diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 46b66cb1b67def..51d9b2432e848f 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,16 +3,22 @@ "isRoot": true, "tools": { "coverlet.console": { - "version": "1.7.0", + "version": "1.7.1", "commands": [ "coverlet" ] }, "dotnet-reportgenerator-globaltool": { - "version": "4.5.2", + "version": "4.5.8", "commands": [ "reportgenerator" ] + }, + "microsoft.dotnet.xharness.cli": { + "version": "1.0.0-prerelease.20271.3", + "commands": [ + "xharness" + ] } } } diff --git a/.editorconfig b/.editorconfig index 6c6dcb40761745..28e3eaba64e83b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -155,6 +155,7 @@ csharp_space_between_square_brackets = false # Analyzers dotnet_code_quality.ca1802.api_surface = private, internal +dotnet_code_quality.CA2208.api_surface = public # C++ Files [*.{cpp,h,in}] @@ -165,6 +166,9 @@ indent_brace_style = Allman [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}] indent_size = 2 +[*.{csproj,vbproj,proj,nativeproj,locproj}] +charset = utf-8 + # Xml build files [*.builds] indent_size = 2 diff --git a/.github/ISSUE_TEMPLATE/01_bug_report.md b/.github/ISSUE_TEMPLATE/01_bug_report.md new file mode 100644 index 00000000000000..ddca1a08888f50 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/01_bug_report.md @@ -0,0 +1,41 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + + + +### Description + + + +### Configuration + + + +### Regression? + + + +### Other information + + diff --git a/.github/ISSUE_TEMPLATE/02_api_proposal.md b/.github/ISSUE_TEMPLATE/02_api_proposal.md new file mode 100644 index 00000000000000..4ba85d6256ab52 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/02_api_proposal.md @@ -0,0 +1,52 @@ +--- +name: API proposal +about: Propose a change to the public API surface +title: '' +labels: api-suggestion +assignees: '' + +--- + +## Background and Motivation + + + +## Proposed API + + + +## Usage Examples + + + +## Alternative Designs + + + +## Risks + + diff --git a/.github/ISSUE_TEMPLATE/03_performance_issue.md b/.github/ISSUE_TEMPLATE/03_performance_issue.md new file mode 100644 index 00000000000000..6da186f0453df1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/03_performance_issue.md @@ -0,0 +1,50 @@ +--- +name: Performance issue +about: Report a performance problem or regression +title: '' +labels: 'tenet-performance' +assignees: '' + +--- + + + +### Description + + + +### Configuration + + + +### Regression? + + + +### Data + + + +### Analysis + + diff --git a/.github/ISSUE_TEMPLATE/04_blank_issue.md b/.github/ISSUE_TEMPLATE/04_blank_issue.md new file mode 100644 index 00000000000000..d1429bfd4c1d90 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/04_blank_issue.md @@ -0,0 +1,8 @@ +--- +name: Blank issue +about: Something that doesn't fit the other categories +title: '' +labels: '' +assignees: '' + +--- diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000000..54d8c5740bad6c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,20 @@ +blank_issues_enabled: true +contact_links: + - name: Issue with ASP.NET Core + url: https://github.com/dotnet/aspnetcore/issues/new/choose + about: Please open issues relating to ASP.NET Core in dotnet/aspnetcore. + - name: Issue with .NET SDK + url: https://github.com/dotnet/sdk/issues/new/choose + about: Please open issues relating to the .NET SDK in dotnet/sdk. + - name: Issue with Entity Framework + url: https://github.com/dotnet/efcore/issues/new/choose + about: Please open issues relating to Entity Framework in dotnet/efcore. + - name: Issue with Roslyn compiler + url: https://github.com/dotnet/roslyn/issues/new/choose + about: Please open issues relating to the Roslyn .NET compiler in dotnet/roslyn. + - name: Issue with Windows Forms + url: https://github.com/dotnet/winforms/issues/new/choose + about: Please open issues relating to Windows Forms in dotnet/winforms. + - name: Issue with WPF + url: https://github.com/dotnet/wpf/issues/new/choose + about: Please open issues relating to WPF in dotnet/wpf. diff --git a/.gitignore b/.gitignore index a9a3cae8e94553..88165cf3073fd2 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,6 @@ linker # ln -s $(pwd)/src/libraries/Common/src src/coreclr/src/System.Private.CoreLib/common src/coreclr/src/System.Private.CoreLib/shared src/coreclr/src/System.Private.CoreLib/common + +# The debug directory should not be ignored +!src/coreclr/src/debug diff --git a/Build.proj b/Build.proj index 0ecff09e8552be..dc4a15ab5f413d 100644 --- a/Build.proj +++ b/Build.proj @@ -5,10 +5,7 @@ Reference the projects for traversal build. Ordering matters here. --> - - - - + - - - - - - - - - - - - - - - - - $(RepoTasksDir) - $(ArtifactsObjDir)runtime.tasks\Debug\build-semaphore.txt - - - - - + + $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'installer.tasks')) $([MSBuild]::NormalizePath('$(InstallerTasksOutputPath)', 'Debug', 'netstandard2.0', 'installer.tasks.dll')) $([MSBuild]::NormalizePath('$(InstallerTasksOutputPath)', 'Debug', 'net46', 'installer.tasks.dll')) - $(ArtifactsObjDir)HostMachineInfo.props $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'docs')) $([MSBuild]::NormalizeDirectory('$(DocsDir)', 'manpages')) $([MSBuild]::NormalizeDirectory('$(LibrariesProjectRoot)', 'System.Private.CoreLib', 'src')) + + $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'AppleAppBuilder', 'Debug', '$(NetCoreAppCurrent)')) + $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'AndroidAppBuilder', 'Debug', '$(NetCoreAppCurrent)')) + $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'WasmAppBuilder', 'Debug', '$(NetCoreAppCurrent)', 'publish')) + $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'MonoAOTCompiler', 'Debug', '$(NetCoreAppCurrent)')) + + $([MSBuild]::NormalizePath('$(AppleAppBuilderDir)', 'AppleAppBuilder.dll')) + $([MSBuild]::NormalizePath('$(AndroidAppBuilderDir)', 'AndroidAppBuilder.dll')) + $([MSBuild]::NormalizePath('$(WasmAppBuilderDir)', 'WasmAppBuilder.dll')) + $([MSBuild]::NormalizePath('$(MonoAOTCompilerDir)', 'MonoAOTCompiler.dll')) + + true - - - false diff --git a/Directory.Build.targets b/Directory.Build.targets index aa09db11f42053..2d72cd0f912847 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -20,10 +20,6 @@ $(MajorVersion).$(MinorVersion) - - $([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(MSBuildProjectName).AssemblyInfo$(DefaultLanguageSourceExtension)')) - - @@ -31,11 +27,4 @@ latest - - - - diff --git a/README.md b/README.md index ee0ac7fcf5ff4e..72e763d3bcceaa 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ For other issues, please use the following repos: ## Useful Links * [.NET Core source index](https://source.dot.net) / [.NET Framework source index](https://referencesource.microsoft.com) -* [API Reference docs](https://docs.microsoft.com/dotnet/api/?view=netcore-3.0) +* [API Reference docs](https://docs.microsoft.com/dotnet/api/?view=netcore-3.1) * [.NET API Catalog](http://apisof.net) (incl. APIs from daily builds and API usage info) * [API docs writing guidelines](https://github.com/dotnet/dotnet-api-docs/wiki) - useful when writing /// comments @@ -55,7 +55,7 @@ For other issues, please use the following repos: There are many .NET related projects on GitHub. - [.NET home repo](https://github.com/Microsoft/dotnet) - links to 100s of .NET projects, from Microsoft and the community. -- [ASP.NET Core home](https://docs.microsoft.com/aspnet/core/?view=aspnetcore-3.0) - the best place to start learning about ASP.NET Core. +- [ASP.NET Core home](https://docs.microsoft.com/aspnet/core/?view=aspnetcore-3.1) - the best place to start learning about ASP.NET Core. This project has adopted the code of conduct defined by the [Contributor Covenant](http://contributor-covenant.org/) to clarify expected behavior in our community. For more information, see the [.NET Foundation Code of Conduct](http://www.dotnetfoundation.org/code-of-conduct). diff --git a/THIRD-PARTY-NOTICES.TXT b/THIRD-PARTY-NOTICES.TXT index 33b2268a7f2faa..707bd024f8f867 100644 --- a/THIRD-PARTY-NOTICES.TXT +++ b/THIRD-PARTY-NOTICES.TXT @@ -820,3 +820,43 @@ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +License notice for DirectX Math Library +--------------------------------------- + +https://github.com/microsoft/DirectXMath/blob/master/LICENSE + + The MIT License (MIT) + +Copyright (c) 2011-2020 Microsoft Corp + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be included in all copies +or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License notice for ldap4net +--------------------------- + +The MIT License (MIT) + +Copyright (c) 2018 Alexander Chermyanin + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/build.cmd b/build.cmd index 615bef6c65b576..76f4d8418947e8 100644 --- a/build.cmd +++ b/build.cmd @@ -4,5 +4,5 @@ setlocal set _args=%* if "%~1"=="-?" set _args=-help -powershell -ExecutionPolicy ByPass -NoProfile -Command "%~dp0eng\build.ps1" %_args% +powershell -ExecutionPolicy ByPass -NoProfile -Command "& '%~dp0eng\build.ps1'" %_args% exit /b %ERRORLEVEL% diff --git a/docs/area-owners.md b/docs/area-owners.md index 4193e6f88632b8..ed99186090f578 100644 --- a/docs/area-owners.md +++ b/docs/area-owners.md @@ -4,8 +4,8 @@ Below table shows the combined area owners on this repository: |-------------|------------------|------------------| | area-AssemblyLoader-coreclr | @jeffschwMSFT @vitek-karas | | | area-CodeGen-coreclr | @BruceForstall @dotnet/jit-contrib | | -| area-CrossGen/NGEN-coreclr | @fadimounir | | -| area-crossgen2-coreclr | @nattress @MichalStrehovsky @trylek @fadimounir | | +| area-CrossGen/NGEN-coreclr | @nattress | | +| area-crossgen2-coreclr | @nattress @trylek @dotnet/crossgen-contrib | | | area-DependencyModel | @eerhardt | Microsoft.Extensions.DependencyModel | | area-Diagnostics-coreclr | @tommcdon | | | area-ExceptionHandling-coreclr | @janvorli | | @@ -30,14 +30,15 @@ Below table shows the combined area owners on this repository: | area-TieredCompilation-coreclr | @kouvel | | | area-Tizen | @alpencolt @gbalykov | | | area-Tracing-coreclr | @sywhang @josalem | | -| area-TypeSystem-coreclr | @davidwrighton @MichalStrehovsky @fadimounir | | +| area-TypeSystem-coreclr | @davidwrighton @MichalStrehovsky @janvorli @mangod9 | | | area-UWP | @nattress | UWP-specific issues including Microsoft.NETCore.UniversalWindowsPlatform and Microsoft.Net.UWPCoreRuntimeSdk | -| area-VM-coreclr | @jeffschwMSFT | | +| area-VM-coreclr | @mangod9 | | | area-AssemblyLoader-mono | @CoffeeFlux | | | area-Codegen-meta-mono | @vargaz | | | area-Codegen-JIT-mono | @SamMonoRT | | | area-Codegen-AOT-mono | @SamMonoRT | | | area-Codegen-Interpreter-mono | @BrzVlad | | +| area-CodeGen-LLVM-mono | @imhameed | | | area-CoreLib-mono | @steveisok | | | area-GC-mono | @BrzVlad | | | area-Build-mono | @akoeplinger | | @@ -47,8 +48,19 @@ Below table shows the combined area owners on this repository: | area-Threading-mono | @lambdageek | | | area-Tracing-mono | @lambdageek | | | area-Performance-mono | @SamMonoRT | | +| ** Extensions namespaces ** | | | +| area-Extensions-Caching | @maryamariyan | | +| area-Extensions-Configuration | @maryamariyan | | +| area-Extensions-DependencyInjection | @maryamariyan | | +| area-Extensions-FileSystem | @maryamariyan | | +| area-Extensions-Hosting | @maryamariyan | | +| area-Extensions-HttpClientFactory | @maryamariyan | | +| area-Extensions-Logging | @maryamariyan | | +| area-Extensions-Options | @maryamariyan | | +| area-Extensions-Primitives | @maryamariyan | | +| area-Microsoft.Extensions | @maryamariyan | | | **System namespaces** | | | -| area-System.Buffers | @tannergooding | | +| area-System.Buffers | @tannergooding @GrabYourPitchforks @pgovind | | | area-System.CodeDom | @buyaa-n @krwq | | | area-System.Collections | @eiriktsarpalis @layomia | Excluded:
  • System.Array -> System.Runtime
| | area-System.ComponentModel | @safern | | @@ -58,12 +70,14 @@ Below table shows the combined area owners on this repository: | area-System.Configuration | @maryamariyan @safern | | | area-System.Console | @carlossanlop @eiriktsarpalis | | | area-System.Data | @ajcvickers @cheenamalhotra @david-engel |
  • Odbc, OleDb - [@saurabh500](https://github.com/saurabh500)
| +| area-System.Data.Odbc | @ajcvickers | | +| area-System.Data.OleDB | @ajcvickers | | | area-System.Data.SqlClient | @cheenamalhotra @david-engel @karinazhou @JRahnama | Archived component - limited churn/contributions (see https://devblogs.microsoft.com/dotnet/introducing-the-new-microsoftdatasqlclient/) | | area-System.Diagnostics | @tommcdon @krwq |
  • System.Diagnostics.EventLog - [@Anipik](https://github.com/Anipik)
| | area-System.Diagnostics.Process | @adamsitnik @eiriktsarpalis | | | area-System.Diagnostics.Tracing | @noahfalk @tommcdon @tarekgh @Anipik | Packages:
  • System.Diagnostics.DiagnosticSource
  • System.Diagnostics.PerformanceCounter - [@Anipik](https://github.com/Anipik)
  • System.Diagnostics.Tracing
  • System.Diagnostics.TraceSource - [@Anipik](https://github.com/Anipik)

| | area-System.DirectoryServices | @tquerec @josephisenhour | | -| area-System.Drawing | @safern | | +| area-System.Drawing | @safern @tannergooding | | | area-System.Dynamic.Runtime | @cston @333fred | Archived component - limited churn/contributions (see [#33170](https://github.com/dotnet/corefx/issues/33170)) | | area-System.Globalization | @safern @tarekgh @krwq | | | area-System.IO | @carlossanlop @jozkee | | diff --git a/docs/coding-guidelines/adding-api-guidelines.md b/docs/coding-guidelines/adding-api-guidelines.md index 1910130c9e7f8a..b9eba22012015f 100644 --- a/docs/coding-guidelines/adding-api-guidelines.md +++ b/docs/coding-guidelines/adding-api-guidelines.md @@ -24,8 +24,8 @@ the implementation without compat concerns in future releases. ### Determine target framework -`netcoreapp5.0` is the target framework version currently under development and the new apis -should be added to `netcoreapp5.0`. [More Information on TargetFrameworks](https://docs.microsoft.com/en-us/dotnet/standard/frameworks) +`net5.0` is the target framework version currently under development and the new apis +should be added to `net5.0`. [More Information on TargetFrameworks](https://docs.microsoft.com/en-us/dotnet/standard/frameworks) ## Making the changes in repo diff --git a/docs/coding-guidelines/api-guidelines/nullability.md b/docs/coding-guidelines/api-guidelines/nullability.md index 4f2e1cb31de02e..997c2b38ac79fa 100644 --- a/docs/coding-guidelines/api-guidelines/nullability.md +++ b/docs/coding-guidelines/api-guidelines/nullability.md @@ -94,6 +94,10 @@ The C# compiler respects a set of attributes that impact its flow analysis. We - **DO** annotate `ref` arguments that guarantee the argument will be non-`null` upon exit (e.g. lazy initialization helpers) with `[NotNull]`. - **DO** annotate properties where a getter will never return `null` but a setter allows `null` as being non-nullable but also `[AllowNull]`. - **DO** annotate properties where a getter may return `null` but a setter throws for `null` as being nullable but also `[DisallowNull]`. +- **DO** add `[NotNullWhen(true)]` to nullable arguments of `Try` methods that will definitively be non-`null` if the method returns `true`. For example, if `Int32.TryParse(string? s)` returns `true`, `s` is known to not be `null`, and so the method should be `public static bool TryParse([NotNullWhen(true)] string? s, out int result)`. +- **DO** add `[NotNullIfNotNull(string)]` if nullable ref argument will be non-`null` upon exit, when an other argument passed evaluated to non-`null`, pass that argument name as string. Example: `public void Exchange([NotNullIfNotNull("value")] ref object? location, object? value);`. +- **DO** add `[return: NotNullIfNotNull(string)]` if a method would not return `null` in case an argument passed evaluated to non-`null`, pass that argument name as string. Example: `[return: NotNullIfNotNull("name")] public string? FormatName(string? name);` +- **DO** add `[MemberNotNull(params string[])]` for a helper method which initializes member field(s), pass the field name. Example: `[MemberNotNull("_buffer")] private void InitializeBuffer()` ## Code Review Guidance diff --git a/docs/coding-guidelines/interop-guidelines.md b/docs/coding-guidelines/interop-guidelines.md index ce0731e20cae11..e6e3a1d32060dc 100644 --- a/docs/coding-guidelines/interop-guidelines.md +++ b/docs/coding-guidelines/interop-guidelines.md @@ -178,7 +178,7 @@ Guidelines for shim C++ API: - If an export point has a 1:1 correspondence to the platform API, then name it after the platform API in PascalCase (e.g. stat -> Stat, fstat -> FStat). - If an export is not 1:1, then spell things out as we typically would in dotnet/runtime code (i.e. don't use abbreviations unless they come from the underlying API. - At first, it seemed that we'd want to use 1:1 names throughout, but it turns out there are many cases where being strictly 1:1 isn't practical. - - In order to reduce the chance of collisions when linking with CoreRT, all exports should have a prefix that corresponds to the Libraries' name, e.g. "SystemNative_" or "CryptoNative_" to make the method name more unique. See https://github.com/dotnet/corefx/issues/4818. + - In order to reduce the chance of collisions when linking with CoreRT, all exports should have a prefix that corresponds to the Libraries' name, e.g. "SystemNative_" or "CryptoNative_" to make the method name more unique. See https://github.com/dotnet/runtime/issues/15854. - Stick to data types which are guaranteed not to vary in size across flavors. - Use int32_t, int64_t, etc. from stdint.h and not int, long, etc. - Use char* for ASCII or UTF-8 strings and uint8_t* for byte buffers. diff --git a/docs/coding-guidelines/project-guidelines.md b/docs/coding-guidelines/project-guidelines.md index 55728730a3c518..f0050a58588096 100644 --- a/docs/coding-guidelines/project-guidelines.md +++ b/docs/coding-guidelines/project-guidelines.md @@ -28,7 +28,7 @@ Below is a list of all the various options we pivot the project builds on: ## Individual build properties The following are the properties associated with each build pivot -- `$(BuildTargetFramework) -> netstandard2.1 | netcoreapp5.0 | net472` +- `$(BuildTargetFramework) -> netstandard2.1 | net5.0 | net472` - `$(TargetOS) -> Windows | Linux | OSX | FreeBSD | [defaults to running OS when empty]` - `$(Configuration) -> Release | [defaults to Debug when empty]` - `$(TargetArchitecture) - x86 | x64 | arm | arm64 | [defaults to x64 when empty]` @@ -82,7 +82,7 @@ When we have a project that has a `netstandard2.0` target framework that means t A full or individual project build is centered around BuildTargetFramework, TargetOS, Configuration and TargetArchitecture. 1. `$(BuildTargetFramework), $(TargetOS), $(Configuration), $(TargetArchitecture)` can individually be passed in to change the default values. -2. If nothing is passed to the build then we will default value of these properties from the environment. Example: `netcoreapp5.0-[TargetOS Running On]-Debug-x64`. +2. If nothing is passed to the build then we will default value of these properties from the environment. Example: `net5.0-[TargetOS Running On]-Debug-x64`. 3. While Building an individual project from the VS, we build the project for all latest netcoreapp target frameworks. We also have `RuntimeOS` which can be passed to customize the specific OS and version needed for native package builds as well as package restoration. If not passed it will default based on the OS you are running on. @@ -97,6 +97,46 @@ When building an individual project the `BuildTargetFramework` and `TargetOS` wi - .NET Framework latest -> `$(NetFrameworkCurrent)-Windows_NT` # Library project guidelines + +## TargetFramework conditions +`TargetFramework` conditions should be avoided in the first PropertyGroup as that causes DesignTimeBuild issues: https://github.com/dotnet/project-system/issues/6143 + +1. Use an equality check if the TargetFramework isn't overloaded with the OS portion. +Example: +``` + + netstandard2.0;netstandard2.1 + +... +``` +2. Use a StartsWith when you want to test for multiple .NETStandard or .NETFramework versions. +Example: +``` + + netstandard2.0;netstandard2.1 + +... +``` +4. Use negations if that makes the conditions easier. +Example: +``` + + netstandard2.0;net461;net472;net5.0 + +... +``` + +## Directory layout + Library projects should use the following directory layout. ``` @@ -121,7 +161,7 @@ The output for the ref project build will be a flat targeting pack folder in the ## src In the src directory for a library there should be only **one** `.csproj` file that contains any information necessary to build the library in various target frameworks. All supported target frameworks should be listed in the `TargetFrameworks` property. -All libraries should use `` for all their project references. That will cause them to be resolved against a targeting pack (i.e. `bin\ref\netcoreapp5.0` or `\bin\ref\netstanard2.0`) based on the project target framework. There should not be any direct project references to other libraries. The only exception to that rule right now is for partial facades which directly reference System.Private.CoreLib and thus need to directly reference other partial facades to avoid type conflicts. +All libraries should use `` for all their project references. That will cause them to be resolved against a targeting pack (i.e. `bin\ref\net5.0` or `\bin\ref\netstanard2.0`) based on the project target framework. There should not be any direct project references to other libraries. The only exception to that rule right now is for partial facades which directly reference System.Private.CoreLib and thus need to directly reference other partial facades to avoid type conflicts.
//**CONSIDER**: just using Reference and use a reference to System.Private.CoreLib as a trigger to turn the other References into a ProjectReference automatically. That will allow us to have consistency where all projects just use Reference. ### src output diff --git a/docs/coding-guidelines/updating-ref-source.md b/docs/coding-guidelines/updating-ref-source.md index d702db01f695fa..6ca0e56cc2629e 100644 --- a/docs/coding-guidelines/updating-ref-source.md +++ b/docs/coding-guidelines/updating-ref-source.md @@ -2,16 +2,16 @@ This document provides the steps you need to take to update the reference assemb ## For most assemblies within libraries -1. Implement the API in the source assembly and [build it](../workflow/building/libraries/README.md#building-individual-libraries). -2. Run the following command (from the src directory) `msbuild /t:GenerateReferenceSource` to update the reference assembly**. +1. Implement the API in the source assembly and [build it](../workflow/building/libraries/README.md#building-individual-libraries). Note that when adding new public types, this might fail with a `TypeMustExist` error. The deadlock can be worked around by disabling the `RunApiCompat` property: `dotnet build /p:RunApiCompat=false`. +2. Run the following command (from the src directory) `msbuild /t:GenerateReferenceAssemblySource` to update the reference assembly**. 3. Navigate to the ref directory and build the reference assembly. 4. Add, build, and run tests. -** **Note:** If you already added the new API to the reference source, re-generating it (after building the source assembly) will update it to be fully qualified and placed in the correct order. This can be done by running the `GenerateReferenceSource` command from the ref directory. +** **Note:** If you already added the new API to the reference source, re-generating it (after building the source assembly) will update it to be fully qualified and placed in the correct order. This can be done by running the `GenerateReferenceAssemblySource` command from the ref directory. ## For System.Runtime These steps can also be applied to some unique assemblies which depend on changes in System.Private.Corelib. (partial facades like System.Memory, for example). -1) Run `dotnet build -c Release /t:GenerateReferenceSource` from the System.Runtime/ref directory. +1) Run `dotnet build -c Release /t:GenerateReferenceAssemblySource` from the System.Runtime/ref directory. 2) Filter out all unrelated changes and extract the changes you care about (ignore certain attributes being removed). Generally, this step is not required for other reference assemblies. diff --git a/docs/design/coreclr/botr/README.md b/docs/design/coreclr/botr/README.md index fde9992daeb9cc..4c6e6cb5b3bf6a 100644 --- a/docs/design/coreclr/botr/README.md +++ b/docs/design/coreclr/botr/README.md @@ -19,7 +19,7 @@ Below is a table of contents. - [Method Descriptor](method-descriptor.md) - [Virtual Stub Dispatch](virtual-stub-dispatch.md) - [Stack Walking](stackwalking.md) -- [Mscorlib and Calling Into the Runtime](mscorlib.md) +- [`System.Private.CoreLib` and calling into the runtime](corelib.md) - [Data Access Component (DAC) Notes](dac-notes.md) - [Profiling](profiling.md) - [Implementing Profilability](profilability.md) diff --git a/docs/design/coreclr/botr/corelib.md b/docs/design/coreclr/botr/corelib.md new file mode 100644 index 00000000000000..9b6f5dbb7f4c22 --- /dev/null +++ b/docs/design/coreclr/botr/corelib.md @@ -0,0 +1,352 @@ +`System.Private.CoreLib` and calling into the runtime +=== + +# Introduction + +`System.Private.CoreLib.dll` is the assembly for defining the core parts of the type system, and a good portion of the Base Class Library in .NET Framework. It was originally named `mscorlib` in .NET Core, though many places in the code and documentation still refer to it as `mscorlib`. This document will endeavour to stick to using `System.Private.CoreLib` or CoreLib. Base data types live in this assembly, and it has a tight coupling with the CLR. Here you will learn exactly how and why CoreLib is special and the basics about calling into the CLR from managed code via QCall and FCall methods. It also discusses calling from within the CLR into managed code. + +## Dependencies + +Since CoreLib defines base data types like `Object`, `Int32`, and `String`, CoreLib cannot depend on other managed assemblies. However, there is a strong dependency between CoreLib and the CLR. Many of the types in CoreLib need to be accessed from native code, so the layout of many managed types is defined both in managed code and in native code inside the CLR. Additionally, some fields may be defined only in Debug, Checked, or Release builds, so typically CoreLib must be compiled separately for each type of build. + +`System.Private.CoreLib.dll` builds separately for 64 bit and 32 bit, and some public constants it exposes differ by bitness. By using these constants, such as `IntPtr.Size`, most libraries above CoreLib should not need to build separately for 32 bit vs. 64 bit. + +## What makes `System.Private.CoreLib` special? + +CoreLib has several unique properties, many of which are due to its tight coupling to the CLR. + +- CoreLib defines the core types necessary to implement the CLR's Virtual Object System, such as the base data types (`Object`, `Int32`, `String`, etc). +- The CLR must load CoreLib on startup to load certain system types. +- Can only have one CoreLib loaded in the process at a time, due to layout issues. Loading multiple CoreLibs would require formalizing a contract of behavior, FCall methods, and datatype layout between CLR and CoreLib, and keeping that contract relatively stable across versions. +- CoreLib's types are used heavily for native interop and managed exceptions should map correctly to native error codes/formats. +- The CLR's multiple JIT compilers may special case a small group of certain methods in CoreLib for performance reasons, both in terms of optimizing away the method (such as `Math.Cos(double)`), or calling a method in peculiar ways (such as `Array.Length`, or some implementation details on `StringBuilder` for getting the current thread). +- CoreLib will need to call into native code, via P/Invoke where appropriate, primarily into the underlying operating system or occasionally a platform adaptation layer. +- CoreLib will require calling into the CLR to expose some CLR-specific functionality, such as triggering a garbage collection, to load classes, or to interact with the type system in a non-trivial way. This requires a bridge between managed code and native, "manually managed" code within the CLR. +- The CLR will need to call into managed code to call managed methods, and to get at certain functionality that is only implemented in managed code. + +# Interface between managed and CLR code + +To reiterate, the needs of managed code in CoreLib include: + +- The ability to access fields of some managed data structures in both managed code and "manually managed" code within the CLR. +- Managed code must be able to call into the CLR. +- The CLR must be able to call managed code. + +To implement these, we need a way for the CLR to specify and optionally verify the layout of a managed object in native code, a managed mechanism for calling into native code, and a native mechanism for calling into managed code. + +The managed mechanism for calling into native code must also support the special managed calling convention used by `String`'s constructors, where the constructor allocates the memory used by the object (instead of the typical convention where the constructor is called after the GC allocates memory). + +The CLR provides a [`mscorlib` binder](https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/binder.cpp) internally, providing a mapping between unmanaged types and fields to managed types and fields. The binder will look up and load classes and allows the calling of managed methods. It also performs simple verification to ensure the correctness of any layout information specified in both managed and native code. The binder ensures that the managed class attempting to load exists in mscorlib, has been loaded, and the field offsets are correct. It also needs the ability to differentiate between method overloads with different signatures. + +# Calling from managed to native code + +Two techniques exist for calling into the CLR from managed code. FCall allows you to call directly into the CLR code, and provides a lot of flexibility in terms of manipulating objects, though it is easy to cause GC holes by not tracking object references correctly. QCall also allows you to call into the CLR via the P/Invoke, but is much harder to accidentally mis-use. FCalls are identified in managed code as extern methods with the [`MethodImplOptions.InternalCall`](https://docs.microsoft.com/dotnet/api/system.runtime.compilerservices.methodimploptions) bit set. QCalls are marked `static extern` methods similar to regular P/Invokes, but are directed toward a library called `"QCall"`. + +There is a small variant of FCall called HCall (for Helper call) for implementing JIT helpers. The HCall is intended for doing things like accessing multi-dimensional array elements, range checks, etc. The only difference between HCall and FCall is that HCall methods won't show up in an exception stack trace. + +### Choosing between FCall, QCall, P/Invoke, and writing in managed code + +First, remember that you should be writing as much as possible in managed code. You avoid a raft of potential GC hole issues, you get a better debugging experience, and the code is often simpler. + +Reasons to write FCalls in the past generally fell into three camps: missing language features, better performance, or implementing unique interactions with the runtime. C# now has almost every useful language feature that you could get from C++, including unsafe code and stack-allocated buffers, and this eliminates the first two reasons for FCalls. We have ported some parts of the CLR that were heavily reliant on FCalls to managed code in the past (such as Reflection, some Encoding, and String operations) and we intend to continue this momentum. + +If the only reason you're defining a FCall method is to call a native method, you should be using P/Invoke to call the method directly. [P/Invoke](https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.dllimportattribute) is the public native method interface and should be doing everything you need in a correct manner. + +If you still need to implement a feature inside the runtime, consider if there is a way to reduce the frequency of transitioning to native code. Can you write the common case in managed and only call into native for some rare corner cases? You're usually best off keeping as much as possible in managed code. + +QCalls are the preferred mechanism going forward. You should only use FCalls when you are "forced" to. This happens when there is common "short path" through the code that is important to optimize. This short path should not be more than a few hundred instructions, cannot allocate GC memory, take locks or throw exceptions (`GC_NOTRIGGER`, `NOTHROWS`). In all other circumstances (and especially when you enter a FCall and then simply erect HelperMethodFrame), you should be using QCall. + +FCalls were specifically designed for short paths of code that must be optimized. They allowed explicit control over when erecting a frame was done. However, it is error prone and not worth the complexity for many APIs. QCalls are essentially P/Invokes into the CLR. In the event the performance of an FCall is required consider creating a QCall and marking it with [`SuppressGCTransitionAttribute`](https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.suppressgctransitionattribute). + +As a result, QCalls give you some advantageous marshaling for `SafeHandle`s automatically – your native method just takes a `HANDLE` type, and can be used without worrying whether someone will free the handle while in that method body. The resulting FCall method would need to use a `SafeHandleHolder` and may need to protect the `SafeHandle`, etc. Leveraging the P/Invoke marshaler can avoid this additional plumbing code. + +## QCall functional behavior + +QCalls are very much like a normal P/Invoke from CoreLib to CLR. Unlike FCalls, QCalls will marshal all arguments as unmanaged types like a normal P/Invoke. QCall also switch to preemptive GC mode like a normal P/Invoke. These two features should make QCalls easier to write reliably compared to FCalls. QCalls are not prone to GC holes and GC starvation bugs that are common with FCalls. + +QCalls perform better than FCalls that erect a `HelperMethodFrame`. The overhead is about 1.4x less compared to FCall w/ `HelperMethodFrame` overhead on x86 and x64. + +The preferred types for QCall arguments are primitive types that are efficiently handled by the P/Invoke marshaler (`INT32`, `LPCWSTR`, `BOOL`). Notice that `BOOL` is the correct boolean flavor for QCall arguments. On the other hand, `CLR_BOOL` is the correct boolean flavor for FCall arguments. + +The pointers to common unmanaged EE structures should be wrapped into handle types. This is to make the managed implementation type safe and avoid falling into unsafe C# everywhere. See AssemblyHandle in [vm\qcall.h][qcall] for an example. + +[qcall]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/qcall.h + +Passing object references in and out of QCalls is done by wrapping a pointer to a local variable in a handle. It is intentionally cumbersome and should be avoided if reasonably possible. See the `StringHandleOnStack` in the example below. Returning objects, especially strings, from QCalls is the only common pattern where passing the raw objects is widely acceptable. (For reasoning on why this set of restrictions helps make QCalls less prone to GC holes, read the ["GC Holes, FCall, and QCall"](#gcholes) section below.) + +### QCall example - managed + +Do not replicate the comments into your actual QCall implementation. This is for illustrative purposes. + +```CSharp +class Foo +{ + // All QCalls should have the following DllImport attribute + [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] + + // QCalls should always be static extern. + private static extern bool BarInternal(int flags, string inString, StringHandleOnStack retString); + + // Many QCalls have a thin managed wrapper around them to perform + // as much work prior to the transition as possible. An example would be + // argument validation which is easier in managed than native code. + public string Bar(int flags) + { + if (flags != 0) + throw new ArgumentException("Invalid flags"); + + string retString = null; + // The strings are returned from QCalls by taking address + // of a local variable using StringHandleOnStack + if (!BarInternal(flags, this.Id, new StringHandleOnStack(ref retString))) + FatalError(); + + return retString; + } +} +``` + +### QCall example - unmanaged + +Do not replicate the comments into your actual QCall implementation. + +The QCall entrypoint has to be registered in tables in [vm\ecalllist.h][ecalllist] using `QCFuncEntry` macro. See ["Registering your QCall or FCall Method"](#register) below. + +[ecalllist]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/ecalllist.h + +```C++ +class FooNative +{ +public: + // All QCalls should be static and tagged with QCALLTYPE + static + BOOL QCALLTYPE BarInternal(int flags, LPCWSTR wszString, QCall::StringHandleOnStack retString); +}; + +BOOL QCALLTYPE FooNative::BarInternal(int flags, LPCWSTR wszString, QCall::StringHandleOnStack retString) +{ + // All QCalls should have QCALL_CONTRACT. + // It is alias for THROWS; GC_TRIGGERS; MODE_PREEMPTIVE. + QCALL_CONTRACT; + + // Optionally, use QCALL_CHECK instead and the expanded form of the contract + // if you want to specify preconditions: + // CONTRACTL { + // QCALL_CHECK; + // PRECONDITION(wszString != NULL); + // } CONTRACTL_END; + + // The only line between QCALL_CONTRACT and BEGIN_QCALL + // should be the return value declaration if there is one. + BOOL retVal = FALSE; + + // The body has to be enclosed in BEGIN_QCALL/END_QCALL macro. + // It is necessary for exception handling. + BEGIN_QCALL; + + // Argument validation would ideally be in managed, but in some cases + // needs to be done in native. If argument validation is done in + // managed asserting in native is warranted. + _ASSERTE(flags != 0); + + // No need to worry about GC moving strings passed into QCall. + // Marshalling pins them for us. + printf("%S\n", wszString); + + // This is the most efficient way to return strings back + // to managed code. No need to use StringBuilder. + retString.Set(L"Hello"); + + // You can not return from inside of BEGIN_QCALL/END_QCALL. + // The return value has to be passed out in helper variable. + retVal = TRUE; + + END_QCALL; + + return retVal; +} +``` + +## FCall functional behavior + +FCalls allow more flexibility in terms of passing object references around, but with higher code complexity and more opportunities to make mistakes. Additionally, FCall methods must either erect a helper method frame along their common code paths, or for any FCall of non-trivial length, explicitly poll for whether a garbage collection must occur. Failing to do so will lead to starvation issues if managed code repeatedly calls the FCall method in a tight loop, because FCalls execute while the thread only allows the GC to run in a cooperative manner. + +FCalls require a lot of boilerplate code, too much to describe here. Refer to [fcall.h][fcall] for details. + +[fcall]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/fcall.h + +### GC holes, FCall, and QCall + +A more complete discussion on GC holes can be found in the [CLR Code Guide](../../../coding-guidelines/clr-code-guide.md). Look for ["Is your code GC-safe?"](../../../coding-guidelines/clr-code-guide.md#2.1). This tailored discussion motivates some of the reasons why FCall and QCall have some of their strange conventions. + +Object references passed as parameters to FCall methods are not GC-protected, meaning that if a GC occurs, those references will point to the old location in memory of an object, not the new location. For this reason, FCalls usually follow the discipline of accepting something like `StringObject*` as their parameter type, then explicitly converting that to a `STRINGREF` before doing operations that may trigger a GC. If you expect to use an object reference later, you must GC protect object references before triggering a GC. + +All GC heap allocations within an FCall method must happen within a helper method frame. If you allocate memory on the GC heap, the GC may collect dead objects and move objects around in unpredictable ways, with some low probability. For this reason, you must manually report any object references in your method to the GC, so that if a garbage collection occurs, your object reference will be updated to refer to the new location in memory. Any pointers into managed objects (like arrays or Strings) within your code will not be updated automatically, and must be re-fetched after any operation that may allocate memory and before your first usage. Reporting a reference can be done via the `GCPROTECT_*` macros or as parameters when erecting a helper method frame. + +Failing to properly report an `OBJECTREF` or to update an interior pointer is commonly referred to as a "GC hole", because the `OBJECTREF` class will do some validation that it points to a valid object every time you dereference it in Debug and Checked builds. When an `OBJECTREF` pointing to an invalid object is dereferenced, an assert will trigger saying something like "Detected an invalid object reference. Possible GC hole?". This assert is unfortunately easy to hit when writing "manually managed" code. + +Note that QCall's programming model is restrictive to sidestep GC holes by forcing you to pass in the address of an object reference on the stack. This guarantees that the object reference is GC protected by the JIT's reporting logic, and that the actual object reference will not move because it is not allocated in the GC heap. QCall is our recommended approach, precisely because it makes GC holes harder to write. + +### FCall epilog walker for x86 + +The managed stack walker needs to be able to find its way from FCalls. It is relative easy on newer platforms that define conventions for stack unwinding as part of the ABI. The stack unwinding conventions are not defined by an ABI for x86. The runtime works around this by implementing an epilog walker. The epilog walker computes the FCall return address and callee save registers by simulating the FCall execution. This imposes limits on what constructs are allowed in the FCall implementation. + +Complex constructs like stack allocated objects with destructors or exception handling in the FCall implementation may confuse the epilog walker. This can lead to GC holes or crashes during stack walking. There is no comprehensive list of what constructs should be avoided to prevent this class of bugs. An FCall implementation that is fine one day may break with the next C++ compiler update. We depend on stress runs and code coverage to find bugs in this area. + +Setting a breakpoint inside an FCall implementation may confuse the epilog walker. It leads to an "Invalid breakpoint in a helpermethod frame epilog" assert inside [vm\i386\gmsx86.cpp](https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/i386/gmsx86.cpp). + +### FCall example – managed + +Here's a real-world example from the `String` class: + +```CSharp +public partial sealed class String +{ + [MethodImpl(MethodImplOptions.InternalCall)] + private extern string? IsInterned(); + + public static string? IsInterned(string str) + { + if (str == null) + { + throw new ArgumentNullException(nameof(str)); + } + + return str.IsInterned(); + } +} +``` + +### FCall example – unmanaged + +The FCall entrypoint has to be registered in tables in [vm\ecalllist.h][ecalllist] using `FCFuncEntry` macro. See ["Registering your QCall or FCall Method"](#register). + +This method is an instance method in managed code, with the "this" parameter passed as the first argument. We use `StringObject*` as the argument type, then copy it into a `STRINGREF` so we get some error checking when we use it. + +```C++ +FCIMPL1(Object*, AppDomainNative::IsStringInterned, StringObject* pStringUNSAFE) +{ + FCALL_CONTRACT; + + STRINGREF refString = ObjectToSTRINGREF(pStringUNSAFE); + STRINGREF* prefRetVal = NULL; + + HELPER_METHOD_FRAME_BEGIN_RET_1(refString); + + if (refString == NULL) + COMPlusThrow(kArgumentNullException, W("ArgumentNull_String")); + + prefRetVal = GetAppDomain()->IsStringInterned(&refString); + + HELPER_METHOD_FRAME_END(); + + if (prefRetVal == NULL) + return NULL; + + return OBJECTREFToObject(*prefRetVal); +} +FCIMPLEND +``` + +## Registering your QCall or FCall method + +The CLR must know the name of your QCall and FCall methods, both in terms of the managed class and method names, as well as which native methods to call. That is done in [ecalllist.h][ecalllist], with two arrays. The first array maps namespace and class names to an array of function elements. That array of function elements then maps individual method names and signatures to function pointers. + +Say we defined an FCall method for `String.IsInterned()`, in the example above. First, we need to ensure that we have an array of function elements for the String class. + +``` C++ +// Note these have to remain sorted by name:namespace pair + ... + FCClassElement("String", "System", gStringFuncs) + ... +``` + +Second, we must then ensure that `gStringFuncs` contains a proper entry for `IsInterned`. Note that if a method name has multiple overloads then we can specify a signature: + +```C++ +FCFuncStart(gStringFuncs) + ... + FCFuncElement("IsInterned", AppDomainNative::IsStringInterned) + ... +FCFuncEnd() +``` + +There is a parallel `QCFuncElement` macro. + +## Naming convention + +FCalls and QCalls should not be publicly exposed. Instead wrap the actual FCall or QCall and provide a API approved name. + +The internal FCall or QCall should use the "Internal" suffix to disambiguate the name of the FCall or QCall from public entry point (e.g. the public entry point does error checking and then calls shared worker function with exactly same signature). This is no different from how you would deal with this situation in pure managed code in BCL. + +# Types with a managed/unmanaged duality + +Certain managed types must have a representation available in both managed and native code. You could ask whether the canonical definition of a type is in managed code or native code within the CLR, but the answer doesn't matter – the key thing is they must both be identical. This will allow the CLR's native code to access fields within a managed object in a fast and efficient manner. There is a more complex way of using essentially the CLR's equivalent of Reflection over `MethodTable`s and `FieldDesc`s to retrieve field values, but this doesn't perform as well as desired and isn't very usable. For commonly used types, it makes sense to declare a data structure in native code and keep the two in sync. + +The CLR provides a binder for this purpose. After you define your managed and native classes, you should provide some clues to the binder to help ensure that the field offsets remain the same to quickly spot when someone accidentally adds a field to only one definition of a type. + +In [mscorlib.h][mscorlib.h], use macros ending in "_U" to describe a type, the name of fields in managed code, and the name of fields in a corresponding native data structure. Additionally, you can specify a list of methods, and reference them by name when you attempt to call them later. + +[mscorlib.h]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/mscorlib.h + +``` C++ +DEFINE_CLASS_U(SAFE_HANDLE, Interop, SafeHandle, SafeHandle) +DEFINE_FIELD(SAFE_HANDLE, HANDLE, handle) +DEFINE_FIELD_U(SAFE_HANDLE, STATE, _state, SafeHandle, m_state) +DEFINE_FIELD_U(SAFE_HANDLE, OWNS_HANDLE, _ownsHandle, SafeHandle, m_ownsHandle) +DEFINE_FIELD_U(SAFE_HANDLE, INITIALIZED, _fullyInitialized, SafeHandle, m_fullyInitialized) +DEFINE_METHOD(SAFE_HANDLE, GET_IS_INVALID, get_IsInvalid, IM_RetBool) +DEFINE_METHOD(SAFE_HANDLE, RELEASE_HANDLE, ReleaseHandle, IM_RetBool) +DEFINE_METHOD(SAFE_HANDLE, DISPOSE, Dispose, IM_RetVoid) +DEFINE_METHOD(SAFE_HANDLE, DISPOSE_BOOL, Dispose, IM_Bool_RetVoid) +``` + +Then, you can use the `REF` template to create a type name like `SAFEHANDLEREF`. All the error checking from `OBJECTREF` is built into the `REF` template, and you can freely dereference this `SAFEHANDLEREF` and use fields off of it in native code. You still must GC protect these references. + +# Calling into managed code from unmanaged code + +Clearly there are places where the CLR must call into managed code from native. For this purpose, we have added a `MethodDescCallSite` class to handle a lot of plumbing for you. Conceptually, all you need to do is find the `MethodDesc*` for the method you want to call, find a managed object for the "this" pointer (if you're calling an instance method), pass in an array of arguments, and deal with the return value. Internally, you'll need to potentially toggle your thread's state to allow the GC to run in preemptive mode, etc. + +Here's a simplified example. Note how this instance uses the binder described in the previous section to call `SafeHandle`'s virtual `ReleaseHandle` method. + +```C++ +void SafeHandle::RunReleaseMethod(SafeHandle* psh) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + } CONTRACTL_END; + + SAFEHANDLEREF sh(psh); + + GCPROTECT_BEGIN(sh); + + MethodDescCallSite releaseHandle(s_pReleaseHandleMethod, METHOD__SAFE_HANDLE__RELEASE_HANDLE, (OBJECTREF*)&sh, TypeHandle(), TRUE); + + ARG_SLOT releaseArgs[] = { ObjToArgSlot(sh) }; + if (!(BOOL)releaseHandle.Call_RetBool(releaseArgs)) { + MDA_TRIGGER_ASSISTANT(ReleaseHandleFailed, ReportViolation)(sh->GetTypeHandle(), sh->m_handle); + } + + GCPROTECT_END(); +} +``` + +# Interactions with other subsystems + +## Debugger + +One limitation of FCalls today is that you cannot easily debug both managed code and FCalls easily in Visual Studio's Interop (or mixed mode) debugging. Setting a breakpoint today in an FCall and debugging with Interop debugging just doesn't work. This most likely won't be fixed. + +# Physical architecture + +When the CLR starts up, CoreLib is loaded by a method called `SystemDomain::LoadBaseSystemClasses()`. Here, the base data types and other similar classes (like `Exception`) are loaded, and appropriate global pointers are set up to refer to CoreLib's types. + +For FCalls, look in [fcall.h][fcall] for infrastructure, and [ecalllist.h][ecalllist] to properly inform the runtime about your FCall method. + +For QCalls, look in [qcall.h][qcall] for associated infrastructure, and [ecalllist.h][ecalllist] to properly inform the runtime about your QCall method. + +More general infrastructure and some native type definitions can be found in [object.h][object.h]. The binder uses `mscorlib.h` to associate managed and native classes. + +[object.h]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/object.h diff --git a/docs/design/coreclr/botr/dac-notes.md b/docs/design/coreclr/botr/dac-notes.md index 1a267484760e9e..43b1714b1d8c90 100644 --- a/docs/design/coreclr/botr/dac-notes.md +++ b/docs/design/coreclr/botr/dac-notes.md @@ -11,13 +11,13 @@ Historically, the CLR debugger has operated in process. A debugger extension, SO Notice that the DAC reads _the memory of the target process_. It's important to realize that the debugger and the debuggee are separate processes with separate address spaces. Thus it is important to make a clear distinction between target memory and host memory. Using a target address in code running in the host process would have completely unpredictable and generally incorrect results. When using the DAC to retrieve memory from the target, it is important to be very careful to use addresses from the correct address space. Furthermore, sometimes the target addresses are sometimes strictly used as data. In this case, it would be just as incorrect to use a host address. For example, to display information about a managed function, we might want to list its starting address and size. Here, it is important to provide the target address. When writing code in the VM that the DAC will run, one needs to correctly choose when to use host and target addresses. -The DAC infrastructure (the macros and templates that control how host or target memory is accessed) supplies certain conventions that distinguish which pointers are host addresses and which are target addresses. When a function is _DACized_ (i.e., use the DAC infrastructure to make the function work out of process), host pointers of type _T _are declared to be of type _T _\*. Target pointers are of type PTR\ __T_. Remember though, that the concept of host versus target is only meaningful for the DAC. In a non-DAC build, we have only a single address space. The host and the target are the same: the CLR. If we declare a local variable of either type _T \* _or of type PTR\_T in a VM function, it will be a "host pointer" When we are executing code in clr.dll (coreclr.dll), there is absolutely no difference between a local variable of type _T \* _and a local variable of type PTR\__ T._ If we execute the function compiled into mscordacwks.dll (msdaccore.dll) from the same source, the variable declared to be of type _T \*_ will be a true host pointer, with the debugger as the host. If you think about it, this is obvious. Nevertheless it can become confusing when we start passing these pointers to other VM functions. When we are DACizing a function (i.e., changing _T \*_ to PTR\__T_, as appropriate), we sometimes need to trace a pointer back to its point of origin to determine whether it should be a host or target type. +The DAC infrastructure (the macros and templates that control how host or target memory is accessed) supplies certain conventions that distinguish which pointers are host addresses and which are target addresses. When a function is _DACized_ (i.e., use the DAC infrastructure to make the function work out of process), host pointers of type `T` are declared to be of type `T *`. Target pointers are of type `PTR_T`. Remember though, that the concept of host versus target is only meaningful for the DAC. In a non-DAC build, we have only a single address space. The host and the target are the same: the CLR. If we declare a local variable of either type `T *` _or of type `PTR_T` in a VM function, it will be a "host pointer". When we are executing code in clr.dll (coreclr.dll), there is absolutely no difference between a local variable of type `T *` and a local variable of type `PTR_T`. If we execute the function compiled into mscordacwks.dll (msdaccore.dll) from the same source, the variable declared to be of type `T *` will be a true host pointer, with the debugger as the host. If you think about it, this is obvious. Nevertheless it can become confusing when we start passing these pointers to other VM functions. When we are DACizing a function (i.e., changing `T *` to `PTR_T`, as appropriate), we sometimes need to trace a pointer back to its point of origin to determine whether it should be a host or target type. -When one has no understanding of the DAC, it's easy to find the use of the DAC infrastructure annoying. The TADDRs and PTR\_this and dac\_casts, etc. seem to clutter the code and make it harder to understand. With just a little work, though, you'll find that these are not really difficult to learn. Keeping host and target addresses explicitly different is really a form of strong typing. The more diligent we are, the easier it becomes to ensure our code is correct. +When one has no understanding of the DAC, it's easy to find the use of the DAC infrastructure annoying. The `TADDR`s and `PTR_this` and `dac_casts`, etc. seem to clutter the code and make it harder to understand. With just a little work, though, you'll find that these are not really difficult to learn. Keeping host and target addresses explicitly different is really a form of strong typing. The more diligent we are, the easier it becomes to ensure our code is correct. Because the DAC potentially operates on a dump, the part of the VM sources we build in clr.dll (msdaccore.dll) must be non-invasive. Specifically, we usually don't want to do anything that would cause writing to the target's address space, nor can we execute any code that might cause an immediate garbage collection. (If we can defer the GC, it may be possible to allocate.) Note that the _host_ state is always mutated (temporaries, stack or local heap values); it is only mutating the _target_ space that is problematic. To enforce this, we do two things: code factoring and conditional compilation. In an ideal world, we would factor the VM code so that we would strictly isolate invasive actions in functions that are separate from non-invasive functions. -Unfortunately, we have a large code base, most of which we wrote without ever thinking about the DAC at all. We have a significant number of functions with "find or create" semantics and many other functions that have some parts that just do inspection and other parts that write to the target. Sometimes we control this with a flag passed into the function. This is common in loader code, for example. To avoid having to complete the immense job of refactoring all the VM code before we can use the DAC, we have a second method to prevent executing invasive code from out of process. We have a defined pre-processor constant, DACCESS\_COMPILE that we use to control what parts of the code we compile into the DAC. We would like to use the DACCESS\_COMPILE constant as little as we can, so when we DACize a new code path, we prefer to refactor whenever possible. Thus, a function that has "find or create" semantics should become two functions: one that tries to find the information and a wrapper that calls this and creates if the find fails. That way, the DAC code path can call the find function directly and avoid the creation. +Unfortunately, we have a large code base, most of which we wrote without ever thinking about the DAC at all. We have a significant number of functions with "find or create" semantics and many other functions that have some parts that just do inspection and other parts that write to the target. Sometimes we control this with a flag passed into the function. This is common in loader code, for example. To avoid having to complete the immense job of refactoring all the VM code before we can use the DAC, we have a second method to prevent executing invasive code from out of process. We have a defined pre-processor constant, `DACCESS_COMPILE` that we use to control what parts of the code we compile into the DAC. We would like to use the `DACCESS_COMPILE` constant as little as we can, so when we DACize a new code path, we prefer to refactor whenever possible. Thus, a function that has "find or create" semantics should become two functions: one that tries to find the information and a wrapper that calls this and creates if the find fails. That way, the DAC code path can call the find function directly and avoid the creation. How does the DAC work? ====================== @@ -27,9 +27,9 @@ As discussed, the DAC works by marshaling the data it needs and running code in Marshaling Principles --------------------- -The DAC maintains a cache of data that it reads. This avoids the overhead of reading the same values repeatedly. Of course, if the target is live, the values will potentially change. We can only assume the cached values are valid as long as the debuggee remains stopped. Once we allow the target to continue execution, we must flush the DAC cache. The DAC will retrieve the values again when the debugger stops the target for further inspection. The entries in the DAC cache are of type DAC\_INSTANCE. This contains (among other data) the target address, the size of the data and space for the marshaled data itself. When the DAC marshals data, it returns the address of the marshaled data part of this entry as the host address. +The DAC maintains a cache of data that it reads. This avoids the overhead of reading the same values repeatedly. Of course, if the target is live, the values will potentially change. We can only assume the cached values are valid as long as the debuggee remains stopped. Once we allow the target to continue execution, we must flush the DAC cache. The DAC will retrieve the values again when the debugger stops the target for further inspection. The entries in the DAC cache are of type `DAC_INSTANCE`. This contains (among other data) the target address, the size of the data and space for the marshaled data itself. When the DAC marshals data, it returns the address of the marshaled data part of this entry as the host address. -When the DAC reads a value from the target, it marshals the value as a chunk of bytes of a given size (determined by its type). By keeping the target address as a field in the cache entries, it maintains a mapping between the target address and the host address (the address in the cache). Between any stop and continue of a debugger session, the DAC will marshal each value requested only once, as long as subsequent accesses use the same type. (If we reference the target address by two different types, the size may be different, so the DAC will create a new cache entry for the new type). If the value is already in the cache, the DAC will be able to look it up by its target address. That means we can correctly compare two host pointers for (in)equality as long as we have accessed both pointers using the same type. This identity of pointers does not hold across type conversions however. Furthermore, we have no guarantee that values marshaled separately will maintain the same spatial relationship in the cache that they do in the target, so it is incorrect to compare two host pointers for less-than or greater-than relationships. Object layout must be identical in host and target, so we can access fields in an object in the cache using the same offsets we use in the target. Remember that any pointer fields in a marshaled object will be target addresses (generally declared as data members of a PTR type). If we need the values at those addresses, the DAC must marshal them to the host before dereferencing them. +When the DAC reads a value from the target, it marshals the value as a chunk of bytes of a given size (determined by its type). By keeping the target address as a field in the cache entries, it maintains a mapping between the target address and the host address (the address in the cache). Between any stop and continue of a debugger session, the DAC will marshal each value requested only once, as long as subsequent accesses use the same type. (If we reference the target address by two different types, the size may be different, so the DAC will create a new cache entry for the new type). If the value is already in the cache, the DAC will be able to look it up by its target address. That means we can correctly compare two host pointers for (in)equality as long as we have accessed both pointers using the same type. This identity of pointers does not hold across type conversions however. Furthermore, we have no guarantee that values marshaled separately will maintain the same spatial relationship in the cache that they do in the target, so it is incorrect to compare two host pointers for less-than or greater-than relationships. Object layout must be identical in host and target, so we can access fields in an object in the cache using the same offsets we use in the target. Remember that any pointer fields in a marshaled object will be target addresses (generally declared as data members of a `PTR` type). If we need the values at those addresses, the DAC must marshal them to the host before dereferencing them. Because we build this dll from the same sources that we use to build mscorwks.dll (coreclr.dll), the mscordacwks.dll (msdaccore.dll) build that the debugger uses must match the mscorwks build exactly. You can see that this is obviously true if you consider that between builds we might add or remove a field from a type we use. The size for the object in mscorwks would then be different from the size in mscordacwks and the DAC could not marshal the object correctly. This has a ramification that's obvious when you think about it, but easy to overlook. We cannot have fields in objects that exist only in DAC builds or only in non-DAC builds. Thus, a declaration such as the following would lead to incorrect behavior. @@ -60,20 +60,20 @@ An example may be helpful in understanding how marshaling works. The common debu ![DAC Overview](images/dac-overview.png) -The debugger in this figure could be Visual Studio, MDbg, WinDbg, etc. The debugger interfaces with the CLR debugger interface (DBI) APIs to get the information it needs. Information that must come from the target goes through the DAC. The debugger implements the data target, which is responsible for implementing a ReadVirtual function to read memory in the target. The dotted line in the diagram represents the process boundary. +The debugger in this figure could be Visual Studio, MDbg, WinDbg, etc. The debugger interfaces with the CLR debugger interface (DBI) APIs to get the information it needs. Information that must come from the target goes through the DAC. The debugger implements the data target, which is responsible for implementing a `ReadVirtual` function to read memory in the target. The dotted line in the diagram represents the process boundary. -Suppose the debugger needs to display the starting address of an ngen'ed method in the managed application that it has gotten from the managed stack. We will assume that the debugger has already gotten an instance of ICorDebugFunction back from the DBI. It will begin by calling the DBI API ICorDebugFunction::GetNativeCode. This calls into the DAC through the DAC/DBI interface function GetNativeCodeInfo, passing in the domain file and metadata token for the function. The following code fragment is a simplification of the actual function, but it illustrates marshaling without introducing extraneous details. +Suppose the debugger needs to display the starting address of an ngen'ed method in the managed application that it has gotten from the managed stack. We will assume that the debugger has already gotten an instance of `ICorDebugFunction` back from the DBI. It will begin by calling the DBI API `ICorDebugFunction::GetNativeCode`. This calls into the DAC through the DAC/DBI interface function `GetNativeCodeInfo`, passing in the domain file and metadata token for the function. The following code fragment is a simplification of the actual function, but it illustrates marshaling without introducing extraneous details. void DacDbiInterfaceImpl::GetNativeCodeInfo(TADDR taddrDomainFile, - mdToken functionToken, - NativeCodeFunctionData \* pCodeInfo) + mdToken functionToken, + NativeCodeFunctionData * pCodeInfo) { ... - DomainFile \* pDomainFile = dac\_cast(taddrDomainFile); - Module \* pModule = pDomainFile->GetCurrentModule(); + DomainFile * pDomainFile = dac_cast(taddrDomainFile); + Module * pModule = pDomainFile->GetCurrentModule(); - MethodDesc\* pMethodDesc = pModule->LookupMethodDef (functionToken); + MethodDesc* pMethodDesc = pModule->LookupMethodDef (functionToken); pCodeInfo->pNativeCodeMethodDescToken = pMethodDesc; // if we are loading a module and trying to bind a previously set breakpoint, we may not have @@ -85,9 +85,9 @@ Suppose the debugger needs to display the starting address of an ngen'ed method } } -The first step is to get the module in which the managed function resides. The taddrDomainFile parameter we pass in represents a target address, but we will need to be able to dereference it here. This means we need the DAC to marshal the value. The dac\_cast operator will construct a new instance of PTR\_DomainFile with a target address equal to the value of domainFileTaddr. When we assign this to pDomainFile, we have an implicit conversion to the host pointer type. This conversion operator is a member of the PTR type and this is where the marshaling occurs. The DAC first searches its cache for the target address. If it doesn't find it, it reads the data from the target for the marshaled DomainFile instance and copies it to the cache. Finally, it returns the host address of the marshaled value. +The first step is to get the module in which the managed function resides. The `taddrDomainFile` parameter we pass in represents a target address, but we will need to be able to dereference it here. This means we need the DAC to marshal the value. The `dac_cast` operator will construct a new instance of `PTR_DomainFile` with a target address equal to the value of `domainFileTaddr`. When we assign this to `pDomainFile`, we have an implicit conversion to the host pointer type. This conversion operator is a member of the `PTR` type and this is where the marshaling occurs. The DAC first searches its cache for the target address. If it doesn't find it, it reads the data from the target for the marshaled `DomainFile` instance and copies it to the cache. Finally, it returns the host address of the marshaled value. -Now we can call GetCurrentModule on this host instance of the DomainFile. This function is a simple accessor that returns DomainFile::m\_pModule. Notice that it returns a Module \*, which will be a host address. The value of m\_pModule is a target address (the DAC will have copied the DomainFile instance as raw bytes). The type for the field is PTR\_Module, however, so when the function returns it, the DAC will automatically marshal it as part of the conversion to Module \*. That means the return value is a host address. Now we have the correct module and a method token, so we have all the information we need to get the MethodDesc. +Now we can call `GetCurrentModule` on this host instance of the `DomainFile`. This function is a simple accessor that returns `DomainFile::m_pModule`. Notice that it returns a `Module *`, which will be a host address. The value of `m_pModule` is a target address (the DAC will have copied the `DomainFile` instance as raw bytes). The type for the field is `PTR_Module`, however, so when the function returns it, the DAC will automatically marshal it as part of the conversion to `Module *`. That means the return value is a host address. Now we have the correct module and a method token, so we have all the information we need to get the `MethodDesc`. Module * DomainFile::GetCurrentModule() { @@ -96,20 +96,19 @@ Now we can call GetCurrentModule on this host instance of the DomainFile. This f return m_pModule; } -In this simplified version of the code, we are assuming that the method token is a method definition. The next step, then, is to call the LookupMethodDef function on the Module instance. +In this simplified version of the code, we are assuming that the method token is a method definition. The next step, then, is to call the `LookupMethodDef` function on the `Module` instance. - inline MethodDesc \*Module::LookupMethodDef(mdMethodDef token) + inline MethodDesc *Module::LookupMethodDef(mdMethodDef token) { - WRAPPER\_CONTRACT; - SUPPORTS\_DAC; + WRAPPER_CONTRACT; + SUPPORTS_DAC; ... - return dac\_cast(GetFromRidMap(&m\_MethodDefToDescMap, - RidFromToken(token))); + return dac_cast(GetFromRidMap(&m_MethodDefToDescMap, RidFromToken(token))); } -This uses the RidMap to lookup the MethodDesc. If you look at the definition for this function, you will see that it returns a TADDR: +This uses the `RidMap` to lookup the `MethodDesc`. If you look at the definition for this function, you will see that it returns a `TADDR`: - TADDR GetFromRidMap(LookupMap \*pMap, DWORD rid) + TADDR GetFromRidMap(LookupMap *pMap, DWORD rid) { ... @@ -118,52 +117,53 @@ This uses the RidMap to lookup the MethodDesc. If you look at the definition for return result; } -This represents a target address, but it's not really a pointer; it's simply a number (although it represents an address). The problem is that LookupMethodDef needs to return the address of a MethodDesc that we can dereference. To accomplish this, the function uses a dac\_cast to PTR\_MethodDesc to convert the TADDR to a PTR\_MethodDesc. You can think of this as the target address space form of a cast from void \* to MethodDesc \*. In fact, this code would be slightly cleander if GetFromRidMap returned a PTR\_VOID (with pointer semantics) instead of a TADDR (with integer semantics). Again, the type conversion implicit in the return statement ensures that the DAC marshals the object (if necessary) and returns the host address of the MethodDesc in the DAC cache. +This represents a target address, but it's not really a pointer; it's simply a number (although it represents an address). The problem is that `LookupMethodDef` needs to return the address of a `MethodDesc` that we can dereference. To accomplish this, the function uses a `dac_cast` to `PTR_MethodDesc` to convert the `TADDR` to a `PTR_MethodDesc`. You can think of this as the target address space form of a cast from `void *` to `MethodDesc *`. In fact, this code would be slightly cleander if `GetFromRidMap` returned a `PTR_VOID` (with pointer semantics) instead of a `TADDR` (with integer semantics). Again, the type conversion implicit in the return statement ensures that the DAC marshals the object (if necessary) and returns the host address of the `MethodDesc` in the DAC cache. -The assignment statement in GetFromRidMap indexes an array to get a particular value. The pMap parameter is the address of a structure field from the MethodDesc. As such, the DAC will have copied the entire field into the cache when it marshaled the MethodDesc instance. Thus, pMap, which is the address of this struct, is a host pointer. Dereferencing it does not involve the DAC at all. The pTable field, however, is a PTR\_TADDR. What this tells us is that pTable is an array of target addresses, but its type indicates that it is a marshaled type. This means that pTable will be a target address as well. We dereference it with the overloaded indexing operator for the PTR type. This will get the target address of the array and compute the target address of the element we want. The last step of indexing marshals the array element back to a host instance in the DAC cache and returns its value. We assign the the element (a TADDR) to the local variable result and return it. +The assignment statement in `GetFromRidMap` indexes an array to get a particular value. The `pMap` parameter is the address of a structure field from the `MethodDesc`. As such, the DAC will have copied the entire field into the cache when it marshaled the `MethodDesc` instance. Thus, `pMap`, which is the address of this struct, is a host pointer. Dereferencing it does not involve the DAC at all. The `pTable` field, however, is a `PTR_TADDR`. What this tells us is that `pTable` is an array of target addresses, but its type indicates that it is a marshaled type. This means that `pTable` will be a target address as well. We dereference it with the overloaded indexing operator for the `PTR` type. This will get the target address of the array and compute the target address of the element we want. The last step of indexing marshals the array element back to a host instance in the DAC cache and returns its value. We assign the the element (a `TADDR`) to the local variable result and return it. -Finally, to get the code address, the DAC/DBI interface function will call MethodDesc::GetNativeCode. This function returns a value of type PCODE. This type is a target address, but one that we cannot dereference (it is just an alias of TADDR) and one that we use specifically to specify a code address. We store this value on the ICorDebugFunction instance and return it to the debugger. +Finally, to get the code address, the DAC/DBI interface function will call `MethodDesc::GetNativeCode`. This function returns a value of type `PCODE`. This type is a target address, but one that we cannot dereference (it is just an alias of `TADDR`) and one that we use specifically to specify a code address. We store this value on the `ICorDebugFunction` instance and return it to the debugger. ### PTR Types -Because the DAC marshals values from the target address space to the host address space, understanding how the DAC handles target pointers is fundamental. We collectively refer to the fundamental types used for marshaling these as "PTR types." You will see that [daccess.h][daccess.h] defines two classes: \_\_TPtrBase, which has several derived types, and \_\_GlobalPtr. We don't use these types directly; we use them only indirectly through a number of macros. Each of these contains a single data member to give us the target address of the value. For \_\_TPtrBase, this is a full address. For \_\_GlobalPtr, it is a relative address, referenced from a DAC global base location. The "T" in \_\_TPtrBase stands for "target". As you can guess, we use types derived from \_\_TPtrBase for pointers that are data members or locals and we use \_\_GlobalPtr for globals and statics. +Because the DAC marshals values from the target address space to the host address space, understanding how the DAC handles target pointers is fundamental. We collectively refer to the fundamental types used for marshaling these as "PTR types." You will see that [daccess.h][daccess.h] defines two classes: `__TPtrBase`, which has several derived types, and `__GlobalPtr`. We don't use these types directly; we use them only indirectly through a number of macros. Each of these contains a single data member to give us the target address of the value. For `__TPtrBase`, this is a full address. For `__GlobalPtr`, it is a relative address, referenced from a DAC global base location. The "T" in `__TPtrBase` stands for "target". As you can guess, we use types derived from `__TPtrBase` for pointers that are data members or locals and we use `__GlobalPtr` for globals and statics. -In practice, we use these types only through macros. The introductory comment in [daccess.h][daccess.h] has examples of the use of all of these. What is interesting about these macros is that they will expand to declare instantiated types from these marshaling templates in DAC builds, but are no-ops in non-DAC builds. For example, the following definition declares PTR\_MethodTable as a type to represent method table pointers (note that the convention is to name these types with a prefix of PTR\_): +In practice, we use these types only through macros. The introductory comment in [daccess.h][daccess.h] has examples of the use of all of these. What is interesting about these macros is that they will expand to declare instantiated types from these marshaling templates in DAC builds, but are no-ops in non-DAC builds. For example, the following definition declares `PTR_MethodTable` as a type to represent method table pointers (note that the convention is to name these types with a prefix of `PTR_`): - typedef DPTR(class MethodTable) PTR\_MethodTable; + typedef DPTR(class MethodTable) PTR_MethodTable; -In a DAC build, the DPTR macro will expand to declare a \_\_DPtr type named PTR\_MethodTable. In a non-DAC build, the macro simply declares PTR\_MethodTable to be MethodTable \*. This implies that the DAC functionality does not result in any behavior change or performance degradation in non-DAC builds. +In a DAC build, the `DPTR` macro will expand to declare a `__DPtr` type named `PTR_MethodTable`. In a non-DAC build, the macro simply declares `PTR_MethodTable` to be `MethodTable *`. This implies that the DAC functionality does not result in any behavior change or performance degradation in non-DAC builds. -Even better, in a DAC build, the DAC will automatically marshal variables, data members, or return values declared to be of type PTR\_MethodTable, as we saw in the example in the last section. The marshaling is completely transparent. The \_\_DPtr type has overloaded operator functions to redefine pointer dereferencing and array indexing, and a conversion operator to cast to the host pointer type. These operations determine whether the requested value is already in the cache, from whence the operators will return them immediately, or whether it is necessary to read from the target and load the value into the cache before returning it. If you are interested in understanding the details, the function responsible for these cache operations is DacInstantiateTypeByAddressHelper. +Even better, in a DAC build, the DAC will automatically marshal variables, data members, or return values declared to be of type `PTR_MethodTable`, as we saw in the example in the last section. The marshaling is completely transparent. The `__DPtr` type has overloaded operator functions to redefine pointer dereferencing and array indexing, and a conversion operator to cast to the host pointer type. These operations determine whether the requested value is already in the cache, from whence the operators will return them immediately, or whether it is necessary to read from the target and load the value into the cache before returning it. If you are interested in understanding the details, the function responsible for these cache operations is `DacInstantiateTypeByAddressHelper`. -PTR types defined with DPTR are the most common in the runtime, but we also have PTR types for global and static pointers, restricted-use arrays, pointers to variable-sized objects, and pointers to classes with virtual functions that we may need to call from mscordacwks.dll (msdaccore.dll). Most of these are rare and you can refer to [daccess.h][daccess.h] to learn more about them if you need them. +`PTR` types defined with `DPTR` are the most common in the runtime, but we also have `PTR` types for global and static pointers, restricted-use arrays, pointers to variable-sized objects, and pointers to classes with virtual functions that we may need to call from mscordacwks.dll (msdaccore.dll). Most of these are rare and you can refer to [daccess.h][daccess.h] to learn more about them if you need them. -The GPTR and VPTR macros are common enough to warrant special mention here. Both the way we use these and their external behavior is quite similar to DPTRs. Again, marshaling is automatic and transparent. The VPTR macro declares a marshaled pointer type for a class with virtual functions. This special macro is necessary because the virtual function table is essentially an implicit extra field. The DAC has to marshal this separately, since the function addresses are all target addresses that the DAC must convert to host addresses. Treating these classes in this way means that the DAC automatically instantiates the correct implementation class, making casts between base and derived types unnecessary. When you declare a VPTR type, you must also list it in vptr\_list.h. \_\_GlobalPtr types provide base functionality to marshal both global variables and static data members through the GPTR, GVAL, SPTR and SVAL macros. The implementation of global variables is almost identical to that of static fields (both use the \_\_GlobalPtr class) and require the addition of an entry in [dacvars.h][dacvars.h]. The comments in daccess.h and dacvars.h provide more details about declaring these types. +The `GPTR` and `VPTR` macros are common enough to warrant special mention here. Both the way we use these and their external behavior is quite similar to `DPTR`s. Again, marshaling is automatic and transparent. The `VPTR` macro declares a marshaled pointer type for a class with virtual functions. This special macro is necessary because the virtual function table is essentially an implicit extra field. The DAC has to marshal this separately, since the function addresses are all target addresses that the DAC must convert to host addresses. Treating these classes in this way means that the DAC automatically instantiates the correct implementation class, making casts between base and derived types unnecessary. When you declare a `VPTR` type, you must also list it in [vptr_list.h][vptr_list.h]. `__GlobalPtr` types provide base functionality to marshal both global variables and static data members through the `GPTR`, `GVAL`, `SPTR` and `SVAL` macros. The implementation of global variables is almost identical to that of static fields (both use the `__GlobalPtr` class) and require the addition of an entry in [dacvars.h][dacvars.h]. The comments in [daccess.h][daccess.h] and [dacvars.h][dacvars.h] provide more details about declaring these types. [dacvars.h]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/inc/dacvars.h +[vptr_list.h]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/inc/vptr_list.h -Global and static values and pointers are interesting because they form the entry points to the target address space (all other uses of the DAC require you to have a target address already). Many of the globals in the runtime are already DACized. It occasionally becomes necessary to make a previously unDACized (or a newly introduced) global available to the DAC. By using the appropriate macros and [dacvars.h][dacvars.h] entry, you enable a post-build step (DacTableGen.exe run by the build in ndp\clr\src\dacupdatedll) to save the address of the global (from clr.pdb) into a table that is embedded into mscordacwks.dll. The DAC uses this table at run-time to determine where to look in the target address space when the code accesses a global. +Global and static values and pointers are interesting because they form the entry points to the target address space (all other uses of the DAC require you to have a target address already). Many of the globals in the runtime are already DACized. It occasionally becomes necessary to make a previously un-DACized (or a newly introduced) global available to the DAC. By using the appropriate macros and [dacvars.h][dacvars.h] entry, you enable a post-build step (DacTableGen.exe run by the build in ndp\clr\src\dacupdatedll) to save the address of the global (from clr.pdb) into a table that is embedded into mscordacwks.dll. The DAC uses this table at run-time to determine where to look in the target address space when the code accesses a global. ### VAL Types -In addition to pointer types, the DAC must also marshal static and global values (as opposed to values referenced by static or global pointers). For this we have a collection of macros ?VAL\_\*. We use GVAL\_\* for global values, and SVAL\_\* for static values. The comment in the [daccess.h][daccess.h] file has a table showing how to use the various forms of these and includes instructions for declaring global and static values (and global and static pointers) that we will use in DACized code. +In addition to pointer types, the DAC must also marshal static and global values (as opposed to values referenced by static or global pointers). For this we have a collection of macros `?VAL_*`. We use `GVAL_*` for global values, and `SVAL_*` for static values. The comment in the [daccess.h][daccess.h] file has a table showing how to use the various forms of these and includes instructions for declaring global and static values (and global and static pointers) that we will use in DACized code. ### Pure Addresses -The TADDR and PCODE types we introduced in the example of DAC operation are pure target addresses. These are actually integer types, rather than pointers. This prevents code in the host from incorrectly dereferencing them. The DAC does not treat them as pointers either. Specifically, because we have no type or size information no dereferencing or marshalling can occur. We use these primarily in two situations: when we are treating a target address as pure data and when we need to do pointer arithmetic with target addresses (although we can also do pointer arithmetic with PTR types). Of course, because TADDRs have no type information for the target locations they specify, when we perform address arithmetic, we need to factor in the size explicitly. +The `TADDR` and `PCODE` types we introduced in the example of DAC operation are pure target addresses. These are actually integer types, rather than pointers. This prevents code in the host from incorrectly dereferencing them. The DAC does not treat them as pointers either. Specifically, because we have no type or size information no dereferencing or marshalling can occur. We use these primarily in two situations: when we are treating a target address as pure data and when we need to do pointer arithmetic with target addresses (although we can also do pointer arithmetic with `PTR` types). Of course, because `TADDR`s have no type information for the target locations they specify, when we perform address arithmetic, we need to factor in the size explicitly. -We also have one special class of PTRs that don't involve marshaling: PTR\_VOID and PTR\_CVOID. These are the target equivalents of void \* and const void \*, respectively. Because TADDRs are simply numbers, they don't have pointer semantics, which means that if we DACize code by converting void \* to TADDR (as was often the case in the past), we often need extra casts and other changes, even in code that does not compile for the DAC. Using PTR\_VOID makes it easier and cleaner to DACize code that uses void \* by preserving the semantics expected for void \*. If we DACize a function that uses PTR\_VOID or PTR\_CVOID, we can't directly marshal data from these addresses, since we have no idea how much data we would need to read. This means we can't dereference them (or even do pointer arithmetic), but this is identical to the semantics of void \*. As is the case for void \*, we generally cast them to a more specific PTR type when we need to use them. We also have a PTR\_BYTE type, which is a standard marshaled target pointer (that supports pointer arithmetic, etc.). In general, when we DACize code, void \* becomes PTR\_VOID and BYTE \* becomes PTR\_BYTE, just as you would expect. [daccess.h][daccess.h] has explanatory comments that provide more details about the use and semantics of the PTR\_VOID type. +We also have one special class of `PTR`s that don't involve marshaling: `PTR_VOID` and `PTR_CVOID`. These are the target equivalents of `void *` and `const void *`, respectively. Because `TADDR`s are simply numbers, they don't have pointer semantics, which means that if we DACize code by converting `void *` to `TADDR` (as was often the case in the past), we often need extra casts and other changes, even in code that does not compile for the DAC. Using `PTR_VOID` makes it easier and cleaner to DACize code that uses `void *` by preserving the semantics expected for `void *`. If we DACize a function that uses `PTR_VOID` or `PTR_CVOID`, we can't directly marshal data from these addresses, since we have no idea how much data we would need to read. This means we can't dereference them (or even do pointer arithmetic), but this is identical to the semantics of `void *`. As is the case for `void *`, we generally cast them to a more specific `PTR` type when we need to use them. We also have a `PTR_BYTE` type, which is a standard marshaled target pointer (that supports pointer arithmetic, etc.). In general, when we DACize code, `void *` becomes `PTR_VOID` and `BYTE *` becomes `PTR_BYTE`, just as you would expect. [daccess.h][daccess.h] has explanatory comments that provide more details about the use and semantics of the `PTR_VOID` type. -Occasionally, legacy code stores a target address in a host pointer type such as void \*. This is always a bug and makes it extremely difficult to reason about the code. It will also break when we support cross-platform, where the pointer types are different sizes). In DAC builds, the void \* type is a host pointer which should never contain a target address. Using PTR\_VOID instead allows us to indicate that a void pointer type is a target address. We are trying to eliminate all such uses, but some are quite pervasive in the code and will take a while to eliminate entirely. +Occasionally, legacy code stores a target address in a host pointer type such as `void *`. This is always a bug and makes it extremely difficult to reason about the code. It will also break when we support cross-platform, where the pointer types are different sizes. In DAC builds, the `void *` type is a host pointer which should never contain a target address. Using `PTR_VOID` instead allows us to indicate that a void pointer type is a target address. We are trying to eliminate all such uses, but some are quite pervasive in the code and will take a while to eliminate entirely. ### Conversions -In earlier CLR versions, we used C-style type casting, macros, and constructors to cast between types. For example, in MethodIterator::Next, we have the following: +In earlier CLR versions, we used C-style type casting, macros, and constructors to cast between types. For example, in `MethodIterator::Next`, we have the following: if (methodCold) { PTR_CORCOMPILE_METHOD_COLD_HEADER methodColdHeader - = PTR_CORCOMPILE_METHOD_COLD_HEADER((TADDR)methodCold); + = PTR_CORCOMPILE_METHOD_COLD_HEADER((TADDR)methodCold); if (((TADDR)methodCode) == PTR_TO_TADDR(methodColdHeader->hotHeader)) { @@ -171,31 +171,31 @@ In earlier CLR versions, we used C-style type casting, macros, and constructors m_pCMH = PTR_CORCOMPILE_METHOD_COLD_HEADER((TADDR)methodCold); ... -Both methodCold and methodCode are declared as BYTE \*, but in fact hold target addresses. In line 4, methodCold is casted to a TADDR and used as the argument to the constructor for PTR\_CORCOMPILE\_METHOD\_COLD\_HEADER. At this point, methodColdHeader is explicitly a target address. In line 6, there is another C-style cast for methodCode. The hotHeader field of methodColdHeader is of type PTR\_CORCOMPILE\_METHOD\_HEADER. The macro PTR\_TO\_TADDR extracts the raw target address from this PTR type and assigns it to methodCode. Finally, in line 9, another instance of type PTR\_CORCOMPILE\_METHOD\_COLD\_HEADER is constructed. Again, methodCold is casted to TADDR to pass to this constructor. +Both methodCold and methodCode are declared as `BYTE *`, but in fact hold target addresses. In line 4, methodCold is casted to a `TADDR` and used as the argument to the constructor for `PTR_CORCOMPILE_METHOD_COLD_HEADER`. At this point, `methodColdHeader` is explicitly a target address. In line 6, there is another C-style cast for `methodCode`. The hotHeader field of `methodColdHeader` is of type `PTR_CORCOMPILE_METHOD_HEADER`. The macro `PTR_TO_TADDR` extracts the raw target address from this `PTR` type and assigns it to `methodCode`. Finally, in line 9, another instance of type `PTR_CORCOMPILE_METHOD_COLD_HEADER` is constructed. Again, `methodCold` is casted to `TADDR` to pass to this constructor. -If this code seems overly complex and confusing to you, that's good. In fact it is. Worse, it provides no protection for the separation of host and target addresses. From the declarations of methodCold and methodCode, there is no particular reason to interpret them as target addresses at all. If these pointers were dereferenced in DAC builds as if they really were host pointers, the process would probably AV. This snippet demonstrates that any arbitrary pointer type (as opposed to a PTR type) can be casted to a TADDR. Given that these two variables always hold target addresses, they should be of type PTR\_BYTE, rather than BYTE \*. +If this code seems overly complex and confusing to you, that's good. In fact it is. Worse, it provides no protection for the separation of host and target addresses. From the declarations of `methodCold` and `methodCode`, there is no particular reason to interpret them as target addresses at all. If these pointers were dereferenced in DAC builds as if they really were host pointers, the process would probably AV. This snippet demonstrates that any arbitrary pointer type (as opposed to a `PTR` type) can be casted to a `TADDR`. Given that these two variables always hold target addresses, they should be of type `PTR_BYTE`, rather than `BYTE *`. -There is also a disciplined means to cast between different PTR types: dac\_cast. The dac\_cast operator is the DAC-aware vesion of the C++ static\_cast operator (which the CLR coding conventions stipulate instead of C-style casts when casting pointer types). The dac\_cast operator will do any of the following things: +There is also a disciplined means to cast between different `PTR` types: `dac_cast`. The `dac_cast` operator is the DAC-aware vesion of the C++ `static_cast` operator (which the CLR coding conventions stipulate instead of C-style casts when casting pointer types). The `dac_cast` operator will do any of the following things: -1. Create a PTR type from a TADDR -2. Convert one PTR type to another -3. Create a PTR from a host instance previously marshaled to the DAC cache -4. Extract the TADDR from a PTR type -5. Get a TADDR from a host instance previously marshaled to the DAC cache +1. Create a `PTR` type from a `TADDR` +2. Convert one `PTR` type to another +3. Create a `PTR` from a host instance previously marshaled to the DAC cache +4. Extract the `TADDR` from a `PTR` type +5. Get a `TADDR` from a host instance previously marshaled to the DAC cache -Now, assuming both methodCold and methodCode are declared to be of type PTR\_BYTE, the code above can be rewritten as follows. +Now, assuming both methodCold and methodCode are declared to be of type `PTR_BYTE`, the code above can be rewritten as follows. if (methodCold) { PTR_CORCOMPILE_METHOD_COLD_HEADER methodColdHeader - = dac_cast(methodCold); + = dac_cast(methodCold); if (methodCode == methodColdHeader->hotHeader) { // Matched the cold code m_pCMH = methodColdHeader; -You might argue that this code still seems complex and confusing, but at least we have significantly reduced the number of casts and constructors. We have also used constructs that maintain the separation between host and target pointers, so we have made the code safer. In particular, dac\_cast will often generate compiler or run-time errors if we try to do the wrong thing. In general, dac\_cast should be used for conversions. +You might argue that this code still seems complex and confusing, but at least we have significantly reduced the number of casts and constructors. We have also used constructs that maintain the separation between host and target pointers, so we have made the code safer. In particular, `dac_cast` will often generate compiler or run-time errors if we try to do the wrong thing. In general, `dac_cast` should be used for conversions. DACizing ======== @@ -203,11 +203,11 @@ DACizing When do you need to DACize? --------------------------- -Whenever you add a new feature, you will need to consider its debuggability needs and DACize the code to support your feature. You must also ensure that any other changes, such as bug fixes or code clean-up, conform to the DAC rules when necessary. Otherwise, the changes will break the debugger or SOS. If you are simply modifying existing code (as opposed to implementing a new feature), you will generally be able to determine that you need to worry about the DAC when a function you modify includes a SUPPORTS\_DAC contract. This contract has a few variants such as SUPPORTS\_DAC\_WRAPPER and LEAF\_DAC\_CONTRACT. You can find comments explaining the differences in [contract.h][contract.h]. If you see a number of DAC-specific types in the function, you should assume the code will run in DAC builds. +Whenever you add a new feature, you will need to consider its debuggability needs and DACize the code to support your feature. You must also ensure that any other changes, such as bug fixes or code clean-up, conform to the DAC rules when necessary. Otherwise, the changes will break the debugger or SOS. If you are simply modifying existing code (as opposed to implementing a new feature), you will generally be able to determine that you need to worry about the DAC when a function you modify includes a `SUPPORTS_DAC` contract. This contract has a few variants such as `SUPPORTS_DAC_WRAPPER` and `LEAF_DAC_CONTRACT`. You can find comments explaining the differences in [contract.h][contract.h]. If you see a number of DAC-specific types in the function, you should assume the code will run in DAC builds. [contract.h]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/inc/contract.h -DACizing ensures that code in the engine will work correctly with the DAC. It is important to use the DAC correctly to marshal values from the target to the host. Target addresses used incorrectly from the host (or vice versa) may reference unmapped addresses. If addresses are mapped, the values will be completely unrelated to the values expected. As a result, DACizing mostly involves ensuring that we use PTR types for all values that the DAC needs to marshal. Another major task is to ensure that we do not allow invasive code to execute in DAC builds. In practice, this means that we must sometimes refactor code or add DACCESS\_COMPILE preprocessor directives. We also want to be sure that we add the appropriate SUPPORTS\_DAC contract. The use of this contract signals to developers that the function works with the DAC. This is important for two reasons: +DACizing ensures that code in the engine will work correctly with the DAC. It is important to use the DAC correctly to marshal values from the target to the host. Target addresses used incorrectly from the host (or vice versa) may reference unmapped addresses. If addresses are mapped, the values will be completely unrelated to the values expected. As a result, DACizing mostly involves ensuring that we use `PTR` types for all values that the DAC needs to marshal. Another major task is to ensure that we do not allow invasive code to execute in DAC builds. In practice, this means that we must sometimes refactor code or add `DACCESS_COMPILE` preprocessor directives. We also want to be sure that we add the appropriate `SUPPORTS_DAC` contract. The use of this contract signals to developers that the function works with the DAC. This is important for two reasons: -1. If we later call it from some other SUPPORTS\_DAC function, we know that it is DAC-safe and we don't need to worry about DACizing it. +1. If we later call it from some other `SUPPORTS_DAC` function, we know that it is DAC-safe and we don't need to worry about DACizing it. 2. If we make modifications to the function, we need to make sure that they are DAC-safe. If we add a call to another function from this one, we also need to ensure that it is DAC-safe or that we only make the call in non-DAC builds. diff --git a/docs/design/coreclr/botr/method-descriptor.md b/docs/design/coreclr/botr/method-descriptor.md index ea5123bdc4b9a8..7d3f24ccf40f1d 100644 --- a/docs/design/coreclr/botr/method-descriptor.md +++ b/docs/design/coreclr/botr/method-descriptor.md @@ -42,7 +42,7 @@ Used for less common IL methods that have generic instantiation or that do not h **FCall** -Internal methods implemented in unmanaged code. These are [methods marked with MethodImplAttribute(MethodImplOptions.InternalCall) attribute](mscorlib.md), delegate constructors and tlbimp constructors. +Internal methods implemented in unmanaged code. These are [methods marked with MethodImplAttribute(MethodImplOptions.InternalCall) attribute](corelib.md), delegate constructors and tlbimp constructors. **NDirect** diff --git a/docs/design/coreclr/botr/mscorlib.md b/docs/design/coreclr/botr/mscorlib.md deleted file mode 100644 index c2d995567f4917..00000000000000 --- a/docs/design/coreclr/botr/mscorlib.md +++ /dev/null @@ -1,355 +0,0 @@ -Mscorlib and Calling Into the Runtime -=== - -Author: Brian Grunkemeyer ([@briangru](https://github.com/briangru)) - 2006 - -# Introduction - -Mscorlib is the assembly for defining the core parts of the type system, and a good portion of the Base Class Library in .NET Framework. It has been renamed to System.Private.CoreLib in .NET Core, though many places in the code and documentation still refer to it as mscorlib. Base data types live in this assembly, and it has a tight coupling with the CLR. Here you will learn exactly how & why mscorlib.dll is special, and the basics about calling into the CLR from managed code via QCall and FCall methods. It also discusses calling from within the CLR into managed code. - -## Dependencies - -Since mscorlib defines base data types like Object, Int32, and String, mscorlib cannot depend on other managed assemblies. However, there is a strong dependency between mscorlib and the CLR. Many of the types in mscorlib need to be accessed from native code, so the layout of many managed types is defined both in managed code and in native code inside the CLR. Additionally, some fields may be defined only in debug or checked builds, so typically mscorlib must be compiled separately for checked vs. retail builds. - -For 64 bit platforms, some constants are also defined at compile time. So a 64 bit mscorlib.dll is slightly different from a 32 bit mscorlib.dll. Due to these constants, such as IntPtr.Size, most libraries above mscorlib should not need to build separately for 32 bit vs. 64 bit. - -## What Makes Mscorlib Special? - -Mscorlib has several unique properties, many of which are due to its tight coupling to the CLR. - -- Mscorlib defines the core types necessary to implement the CLR's Virtual Object System, such as the base data types (Object, Int32, String, etc). -- The CLR must load mscorlib on startup to load certain system types. -- Can only have one mscorlib loaded in the process at a time, due to layout issues. Loading multiple mscorlibs would require formalizing a contract of behavior, FCall methods, and datatype layout between CLR & mscorlib, and keeping that contract relatively stable across versions. -- Mscorlib's types will be used heavily for native interop, and managed exceptions should map correctly to native error codes/formats. -- The CLR's multiple JIT compilers may special case a small group of certain methods in mscorlib for performance reasons, both in terms of optimizing away the method (such as Math.Cos(double)), or calling a method in peculiar ways (such as Array.Length, or some implementation details on StringBuilder for getting the current thread). -- Mscorlib will need to call into native code, via P/Invoke where appropriate, primarily into the underlying operating system or occasionally a platform adaptation layer. -- Mscorlib will require calling into the CLR to expose some CLR-specific functionality, such as triggering a garbage collection, to load classes, or to interact with the type system in a non-trivial way. This requires a bridge between managed code and native, "manually managed" code within the CLR. -- The CLR will need to call into managed code to call managed methods, and to get at certain functionality that is only implemented in managed code. - -# Interface between managed & CLR code - -To reiterate, the needs of managed code in mscorlib include: - -- The ability to access fields of some managed data structures in both managed code and "manually managed" code within the CLR -- Managed code must be able to call into the CLR -- The CLR must be able to call managed code. - -To implement these, we need a way for the CLR to specify and optionally verify the layout of a managed object in native code, a managed mechanism for calling into native code, and a native mechanism for calling into managed code. - -The managed mechanism for calling into native code must also support the special managed calling convention used by String's constructors, where the constructor allocates the memory used by the object (instead of the typical convention where the constructor is called after the GC allocates memory). - -The CLR provides a [mscorlib binder](https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/binder.cpp) internally, providing a mapping between unmanaged types and fields to managed types & fields. The binder will look up & load classes, allow you to call managed methods. It also does some simple verification to ensure the correctness of any layout information specified in both managed & native code. The binder ensures that the managed class you're attempting to use exists in mscorlib, has been loaded, and the field offsets are correct. It also needs the ability to differentiate between method overloads with different signatures. - -# Calling from managed to native code - -We have two techniques for calling into the CLR from managed code. FCall allows you to call directly into the CLR code, and provides a lot of flexibility in terms of manipulating objects, though it is easy to cause GC holes by not tracking object references correctly. QCall allows you to call into the CLR via the P/Invoke, and is much harder to accidentally mis-use than FCall. FCalls are identified in managed code as extern methods with the MethodImplOptions.InternalCall bit set. QCalls are _static_ extern methods that look like regular P/Invokes, but to a library called "QCall". - -There is a small variant of FCall called HCall (for Helper call) for implementing JIT helpers, for doing things like accessing multi-dimensional array elements, range checks, etc. The only difference between HCall and FCall is that HCall methods won't show up in an exception stack trace. - -### Choosing between FCall, QCall, P/Invoke, and writing in managed code - -First, remember that you should be writing as much as possible in managed code. You avoid a raft of potential GC hole issues, you get a good debugging experience, and the code is often simpler. It also is preparation for ongoing refactoring of mscorlib into smaller layered fully [managed libraries](https://github.com/dotnet/runtime/src/libraries). - -Reasons to write FCalls in the past generally fell into three camps: missing language features, better performance, or implementing unique interactions with the runtime. C# now has almost every useful language feature that you could get from C++, including unsafe code & stack-allocated buffers, and this eliminates the first two reasons for FCalls. We have ported some parts of the CLR that were heavily reliant on FCalls to managed code in the past (such as Reflection and some Encoding & String operations), and we want to continue this momentum. We may port our number formatting & String comparison code to managed in the future. - -If the only reason you're defining a FCall method is to call a native Win32 method, you should be using P/Invoke to call Win32 directly. P/Invoke is the public native method interface, and should be doing everything you need in a correct manner. - -If you still need to implement a feature inside the runtime, now consider if there is a way to reduce the frequency of transitioning to native code. Can you write the common case in managed, and only call into native for some rare corner cases? You're usually best off keeping as much as possible in managed code. - -QCalls are the preferred mechanism going forward. You should only use FCalls when you are "forced" to. This happens when there is common "short path" through the code that is important to optimize. This short path should not be more than a few hundred instructions, cannot allocate GC memory, take locks or throw exceptions (GC_NOTRIGGER, NOTHROWS). In all other circumstances (and especially when you enter a FCall and then simply erect HelperMethodFrame), you should be using QCall. - -FCalls were specifically designed for short paths of code that must be optimized. They allowed you to take explicit control over when erecting a frame was done. However it is error prone and is not worth it for many APIs. QCalls are essentially P/Invokes into CLR. - -As a result, QCalls give you some advantageous marshaling for SafeHandles automatically – your native method just takes a HANDLE type, and can use it without worrying whether someone will free the handle while you are in that method body. The resulting FCall method would need to use a SafeHandleHolder, and may need to protect the SafeHandle, etc. Leveraging the P/Invoke marshaler can avoid this additional plumbing code. - -## QCall Functional Behavior - -QCalls are very much like a normal P/Invoke from mscorlib.dll to CLR. Unlike FCalls, QCalls will marshal all arguments as unmanaged types like a normal P/Invoke. QCall also switch to preemptive GC mode like a normal P/Invoke. These two features should make QCalls easier to write reliably compared to FCalls. QCalls are not prone to GC holes and GC starvation bugs that are common with FCalls. - -QCalls perform better than FCalls that erect a HelperMethodFrame. The overhead is about 1.4x less compared to FCall w/ HelperMethodFrame overhead on x86 and x64. - -The preferred types for QCall arguments are primitive types that are efficiently handled by the P/Invoke marshaler (INT32, LPCWSTR, BOOL). Notice that BOOL is the correct boolean flavor for QCall arguments. On the other hand, CLR_BOOL is the correct boolean flavor for FCall arguments. - -The pointers to common unmanaged EE structures should be wrapped into handle types. This is to make the managed implementation type safe and avoid falling into unsafe C# everywhere. See AssemblyHandle in [vm\qcall.h][qcall] for an example. - -[qcall]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/qcall.h - -There is a way to pass a raw object references in and out of QCalls. It is done by wrapping a pointer to a local variable in a handle. It is intentionally cumbersome and should be avoided if reasonably possible. See the StringHandleOnStack in the example below. Returning objects, especially strings, from QCalls is the only common pattern where passing the raw objects is widely acceptable. (For reasoning on why this set of restrictions helps make QCalls less prone to GC holes, read the "GC Holes, FCall, and QCall" section below.) - -### QCall Example - Managed Part - -Do not replicate the comments into your actual QCall implementation. This is for illustrative purposes. - - class Foo - { - // All QCalls should have the following DllImport attribute - [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] - // QCalls should always be static extern. - private static extern bool Bar(int flags, string inString, StringHandleOnStack retString); - - // Many QCalls have a thin managed wrapper around them to expose them to - // the world in more meaningful way. - public string Bar(int flags) - { - string retString = null; - - // The strings are returned from QCalls by taking address - // of a local variable using StringHandleOnStack - if (!Bar(flags, this.Id, new StringHandleOnStack(ref retString))) - FatalError(); - - return retString; - } - } - -### QCall Example - Unmanaged Part - -Do not replicate the comments into your actual QCall implementation. - -The QCall entrypoint has to be registered in tables in [vm\ecalllist.h][ecalllist] using QCFuncEntry macro. See "Registering your QCall or FCall Method" below. - -[ecalllist]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/ecalllist.h - - class FooNative - { - public: - // All QCalls should be static and should be tagged with QCALLTYPE - static - BOOL QCALLTYPE Bar(int flags, LPCWSTR wszString, QCall::StringHandleOnStack retString); - }; - - BOOL QCALLTYPE FooNative::Bar(int flags, LPCWSTR wszString, QCall::StringHandleOnStack retString) - { - // All QCalls should have QCALL_CONTRACT. - // It is alias for THROWS; GC_TRIGGERS; MODE_PREEMPTIVE. - QCALL_CONTRACT; - - // Optionally, use QCALL_CHECK instead and the expanded form of the contract - // if you want to specify preconditions: - // CONTRACTL { - // QCALL_CHECK; - // PRECONDITION(wszString != NULL); - // } CONTRACTL_END; - - // The only line between QCALL_CONTRACT and BEGIN_QCALL - // should be the return value declaration if there is one. - BOOL retVal = FALSE; - - // The body has to be enclosed in BEGIN_QCALL/END_QCALL macro. It is necessary - // to make the exception handling work. - BEGIN_QCALL; - - // Validate arguments if necessary and throw exceptions. - // There is no convention currently on whether the argument validation should be - // done in managed or unmanaged code. - if (flags != 0) - COMPlusThrow(kArgumentException, L"InvalidFlags"); - - // No need to worry about GC moving strings passed into QCall. - // Marshalling pins them for us. - printf("%S", wszString); - - // This is most the efficient way to return strings back - // to managed code. No need to use StringBuilder. - retString.Set(L"Hello"); - - // You can not return from inside of BEGIN_QCALL/END_QCALL. - // The return value has to be passed out in helper variable. - retVal = TRUE; - - END_QCALL; - - return retVal; - } - -## FCall Functional Behavior - -FCalls allow more flexibility in terms of passing object references around, with a higher code complexity and more opportunities to hang yourself. Additionally, FCall methods must either erect a helper method frame along their common code paths, or for any FCall of non-trivial length, explicitly poll for whether a garbage collection must occur. Failing to do so will lead to starvation issues if managed code repeatedly calls the FCall method in a tight loop, because FCalls execute while the thread only allows the GC to run in a cooperative manner. - -FCalls require a lot of glue, too much to describe here. Look at [fcall.h][fcall] for details. - -[fcall]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/fcall.h - -### GC Holes, FCall, and QCall - -A much more complete discussion on GC holes can be found in the [CLR Code Guide](../../../coding-guidelines/clr-code-guide.md). Look for ["Is your code GC-safe?"](../../../coding-guidelines/clr-code-guide.md#2.1). This tailored discussion motivates some of the reasons why FCall and QCall have some of their strange conventions. - -Object references passed as parameters to FCall methods are not GC-protected, meaning that if a GC occurs, those references will point to the old location in memory of an object, not the new location. For this reason, FCalls usually follow the discipline of accepting something like "StringObject*" as their parameter type, then explicitly converting that to a STRINGREF before doing operations that may trigger a GC. You must GC protect object references before triggering a GC, if you expect to be able to use that object reference later. - -All GC heap allocations within an FCall method must happen within a helper method frame. If you allocate memory on the GC's heap, the GC may collect dead objects & move objects around in unpredictable ways, with some low probability. For this reason, you must manually report any object references in your method to the GC, so that if a garbage collection occurs, your object reference will be updated to refer to the new location in memory. Any pointers into managed objects (like arrays or Strings) within your code will not be updated automatically, and must be re-fetched after any operation that may allocate memory and before your first usage. Reporting a reference can be done via the GCPROTECT macros, or as parameters when you erect a helper method frame. - -Failing to properly report an OBJECTREF or to update an interior pointer is commonly referred to as a "GC hole", because the OBJECTREF class will do some validation that it points to a valid object every time you dereference it in checked builds. When an OBJECTREF pointing to an invalid object is dereferenced, you'll get an assert saying something like "Detected an invalid object reference. Possible GC hole?". This assert is unfortunately easy to hit when writing "manually managed" code. - -Note that QCall's programming model is restrictive to sidestep GC holes most of the time, by forcing you to pass in the address of an object reference on the stack. This guarantees that the object reference is GC protected by the JIT's reporting logic, and that the actual object reference will not move because it is not allocated in the GC heap. QCall is our recommended approach, precisely because it makes GC holes harder to write. - -### FCall Epilogue Walker for x86 - -The managed stack walker needs to be able to find its way from FCalls. It is relative easy on newer platforms that define conventions for stack unwinding as part of the ABI. The stack unwinding conventions are not defined by ABI for x86. The runtime works around it by implementing a epilog walker. The epilog walker computes the FCall return address and callee save registers by simulating the FCall execution. This imposes limits on what constructs are allowed in the FCall implementation. - -Complex constructs like stack allocated objects with destructors or exception handling in the FCall implementation may confuse the epilog walker. It leads to GC holes or crashes during stack walking. There is no exact list of what constructs should be avoided to prevent this class of bugs. An FCall implementation that is fine one day may break with the next C++ compiler update. We depend on stress runs & code coverage to find bugs in this area. - -Setting a breakpoint inside an FCall implementation may confuse the epilog walker. It leads to an "Invalid breakpoint in a helpermethod frame epilog" assert inside [vm\i386\gmsx86.cpp](https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/i386/gmsx86.cpp). - -### FCall Example – Managed Part - -Here's a real-world example from the String class: - - public partial sealed class String - { - // Replaces all instances of oldChar with newChar. - [MethodImplAttribute(MethodImplOptions.InternalCall)] - public extern String Replace (char oldChar, char newChar); - } - -### FCall Example – Native Part - -The FCall entrypoint has to be registered in tables in [vm\ecalllist.h][ecalllist] using FCFuncEntry macro. See "Registering your QCall or FCall Method". - -Notice how oldBuffer and newBuffer (interior pointers into String instances) are re-fetched after allocating memory. Also, this method is an instance method in managed code, with the "this" parameter passed as the first argument. We use StringObject* as the argument type, then copy it into a STRINGREF so we get some error checking when we use it. - - FCIMPL3(LPVOID, COMString::Replace, StringObject* thisRefUNSAFE, CLR_CHAR oldChar, CLR_CHAR newChar) - { - FCALL_CONTRACT; - - int length = 0; - int firstFoundIndex = -1; - WCHAR *oldBuffer = NULL; - WCHAR *newBuffer; - - STRINGREF newString = NULL; - STRINGREF thisRef = (STRINGREF)thisRefUNSAFE; - - if (thisRef==NULL) { - FCThrowRes(kNullReferenceException, L"NullReference_This"); - } - - [... Removed some uninteresting code here for illustrative purposes...] - - HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_2(Frame::FRAME_ATTR_RETURNOBJ, newString, thisRef); - - //Get the length and allocate a new String - //We will definitely do an allocation here. - newString = NewString(length); - - //After allocation, thisRef may have moved - oldBuffer = thisRef->GetBuffer(); - - //Get the buffers in both of the Strings. - newBuffer = newString->GetBuffer(); - - //Copy the characters, doing the replacement as we go. - for (int i=0; i template to create a type name like SAFEHANDLEREF. All the error checking from OBJECTREF is built into the REF macro, and you can freely dereference this SAFEHANDLEREF & use fields off of it in native code. You still must GC protect these references. - -# Calling Into Managed Code From Native - -Clearly there are places where the CLR must call into managed code from native. For this purpose, we have added a MethodDescCallSite class to handle a lot of plumbing for you. Conceptually, all you need to do is find the MethodDesc\* for the method you want to call, find a managed object for the "this" pointer (if you're calling an instance method), pass in an array of arguments, and deal with the return value. Internally, you'll need to potentially toggle your thread's state to allow the GC to run in preemptive mode, etc. - -Here's a simplified example. Note how this instance uses the binder described in the previous section to call SafeHandle's virtual ReleaseHandle method. - - void SafeHandle::RunReleaseMethod(SafeHandle* psh) - { - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - SAFEHANDLEREF sh(psh); - - GCPROTECT_BEGIN(sh); - - MethodDescCallSite releaseHandle(s_pReleaseHandleMethod, METHOD__SAFE_HANDLE__RELEASE_HANDLE, (OBJECTREF*)&sh, TypeHandle(), TRUE); - - ARG_SLOT releaseArgs[] = { ObjToArgSlot(sh) }; - if (!(BOOL)releaseHandle.Call_RetBool(releaseArgs)) { - MDA_TRIGGER_ASSISTANT(ReleaseHandleFailed, ReportViolation)(sh->GetTypeHandle(), sh->m_handle); - } - - GCPROTECT_END(); - } - -# Interactions with Other Subsystems - -## Debugger - -One limitation of FCalls today is that you cannot easily debug both managed code and FCalls easily in Visual Studio's Interop (or mixed mode) debugging. Setting a breakpoint today in an FCall and debugging with Interop debugging just doesn't work. This most likely won't be fixed. - -# Physical Architecture - -When the CLR starts up, mscorlib is loaded by a method called LoadBaseSystemClasses. Here, the base data types & other similar classes (like Exception) are loaded, and appropriate global pointers are set up to refer to mscorlib's types. - -For FCalls, look in [fcall.h][fcall] for infrastructure, and [ecalllist.h][ecalllist] to properly inform the runtime about your FCall method. - -For QCalls, look in [qcall.h][qcall] for associated infrastructure, and [ecalllist.h][ecalllist] to properly inform the runtime about your QCall method. - -More general infrastructure and some native type definitions can be found in [object.h][object.h]. The binder uses mscorlib.h to associate managed & native classes. - -[object.h]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/object.h diff --git a/docs/design/coreclr/botr/readytorun-format.md b/docs/design/coreclr/botr/readytorun-format.md index 51fcd1cab56b4c..8db3423dbadfe9 100644 --- a/docs/design/coreclr/botr/readytorun-format.md +++ b/docs/design/coreclr/botr/readytorun-format.md @@ -28,8 +28,9 @@ in the COFF header represent a full copy of the input IL and MSIL metadata it wa **Composite R2R files** currently conform to Windows PE executable file format as the native envelope. Moving forward we plan to gradually add support for platform-native -executable formats (ELF on Linux, MachO on OSX) as the native envelopes. As a natural corollary -there is no global CLI / COR header in the file. The ReadyToRun header structure is pointed to +executable formats (ELF on Linux, MachO on OSX) as the native envelopes. There is a +global CLI / COR header in the file, but it only exists to facilitate pdb generation, and does +not participate in any usages by the CoreCLR runtime. The ReadyToRun header structure is pointed to by the well-known export symbol `RTR_HEADER` and has the `READYTORUN_FLAG_COMPOSITE` flag set. Input MSIL metadata and IL streams can be either embedded in the composite R2R file or left diff --git a/docs/design/coreclr/botr/shared-generics.md b/docs/design/coreclr/botr/shared-generics.md index 690513621da103..6b23563ebf223d 100644 --- a/docs/design/coreclr/botr/shared-generics.md +++ b/docs/design/coreclr/botr/shared-generics.md @@ -12,31 +12,31 @@ Shared generics is a runtime+JIT feature aimed at reducing the amount of code th Consider the following C# code sample: ``` c# -string Func() +string Method() { return typeof(List).ToString(); } ``` -Without shared generics, the code for instantiations like `Func` or `Func` would look identical except for one single instruction: the one that loads the correct TypeHandle of type `List`: +Without shared generics, the code for instantiations like `Method` or `Method` would look identical except for one single instruction: the one that loads the correct TypeHandle of type `List`: ``` asm mov rcx, type handle of List or List call ToString() ret ``` -With shared generics, the canonical code will not have any hard-coded versions of the type handle of List, but instead looks up the exact type handle either through a call to a runtime helper API, or by loading it up from the *generic dictionary* of the instantiation of Func that is executing. The code would look more like the following: +With shared generics, the canonical code will not have any hard-coded versions of the type handle of List, but instead looks up the exact type handle either through a call to a runtime helper API, or by loading it up from the *generic dictionary* of the instantiation of Method that is executing. The code would look more like the following: ``` asm - mov rcx, generic context // MethodDesc of Func or Func + mov rcx, generic context // MethodDesc of Method or Method mov rcx, [rcx + offset of InstantiatedMethodDesc::m_pPerInstInfo] // This is the generic dictionary mov rcx, [rcx + dictionary slot containing type handle of List] call ToString() ret ``` -The generic context in this example is the InstantiatedMethodDesc of `Func` or `Func`. The generic dictionary is a data structure used by shared generic code to fetch instantiation-specific information. It is basically an array where the entries are instantiation-specific type handles, method handles, field handles, method entry points, etc... The "PerInstInfo" fields on MethodTable and InstantiatedMethodDesc structures point at the generic dictionary structure for a generic type and method respectively. +The generic context in this example is the InstantiatedMethodDesc of `Method` or `Method`. The generic dictionary is a data structure used by shared generic code to fetch instantiation-specific information. It is basically an array where the entries are instantiation-specific type handles, method handles, field handles, method entry points, etc... The "PerInstInfo" fields on MethodTable and InstantiatedMethodDesc structures point at the generic dictionary structure for a generic type and method respectively. -In this example, the generic dictionary for Func will contain a slot with the type handle for type List, and the generic dictionary for Func will contain a slot with the type handle for type List. +In this example, the generic dictionary for Method will contain a slot with the type handle for type List, and the generic dictionary for Method will contain a slot with the type handle for type List. This feature is currently only supported for instantiations over reference types because they all have the same size/properties/layout/etc... For instantiations over primitive types or value types, the runtime will generate separate code bodies for each instantiation. @@ -93,9 +93,9 @@ As described earlier, a generic dictionary is an array of multiple slots contain The first N slots in an instantiation of N arguments are always going to be the type handles of the instantiation type arguments (this is kind of an optimization as well). The slots that follow contain instantiation-based information. -For instance, here is an example of the contents of the generic dictionary for our `Func` example: +For instance, here is an example of the contents of the generic dictionary for our `Method` example: -| `Func's dicionary` | +| `Method's dicionary` | |--------------------------| | slot[0]: TypeHandle(`string`) | | slot[1]: Total dictionary size | @@ -116,7 +116,7 @@ When generating shared generic code, the JIT knows which slots to use for the va ### Dictionary Layouts The `DictionaryLayout` structure is what tells the JIT which slot to use when performing a dictionary lookup. This `DictionaryLayout` structure has a couple of important properties: -- It is shared across all compatible instantiations of a certain type of method. In other words, a dictionary layout is associated with the canonical instantiation of a type or a method. For instance, in our example above, `Func` and `Func` are compatible instantiations, each with their own **separate dictionaries**, however they all share the **same dictionary layout**, which is associated with the canonical instantiation `Func<__Canon>`. +- It is shared across all compatible instantiations of a certain type of method. In other words, a dictionary layout is associated with the canonical instantiation of a type or a method. For instance, in our example above, `Method` and `Method` are compatible instantiations, each with their own **separate dictionaries**, however they all share the **same dictionary layout**, which is associated with the canonical instantiation `Method<__Canon>`. - The dictionaries of generic types or methods have the same number of slots as their dictionary layouts. Note: historically before the introduction of the dynamic dictionary expansion feature, the generic dictionaries could be smaller than their layouts, meaning that for certain lookups, we had to use invoke some runtime helper APIs (slow path). When a generic type or method is first created, its dictionary layout contains 'unassigned' slots. Assignments happen as part of code generation, whenever the JIT needs to emit a dictionary lookup sequence. This assignment happens during the calls to the `DictionaryLayout::FindToken(...)` APIs. Once a slot has been assigned, it becomes associated with a certain signature, which describes the kind of value that will go in every instantiated dictionary at that slot index. @@ -160,7 +160,7 @@ The feature is simple in concept: change dictionary layouts from a linked list o - For types, the generic dictionary is part of the `MethodTable` structure, which can't be reallocated (already in use by managed code) - For methods, the generic dictionary is not part of the `MethodDesc` structure, but can still be in use by some generic code. - We can't have multiple MethodTables or MethodDescs for the same type or method anyways, so reallocations are not an option. -- We can't just resize the generic dictionary for a single instantiation. For instance, in our example above, let's say we wanted to expand the dictionary for `Func`. The resizing of the layout would have an impact on the shared canonical code that the JIT generates for `Func<__Canon>`. If we only resized the dictionary of `Func`, the shared generic code would work for that instantiation only, but when we attempt to use it with another instantiation like `Func`, the jitted instructions would no longer match the size of the dictionary structure, and would cause access violations. +- We can't just resize the generic dictionary for a single instantiation. For instance, in our example above, let's say we wanted to expand the dictionary for `Method`. The resizing of the layout would have an impact on the shared canonical code that the JIT generates for `Method<__Canon>`. If we only resized the dictionary of `Method`, the shared generic code would work for that instantiation only, but when we attempt to use it with another instantiation like `Method`, the jitted instructions would no longer match the size of the dictionary structure, and would cause access violations. - The runtime is multi-threaded, which adds to the complexity. The current implementation expands the dictionary layout and the actual dictionaries separately to keep things simple: diff --git a/docs/design/coreclr/jit/ryujit-overview.md b/docs/design/coreclr/jit/ryujit-overview.md index bf0e1540d42287..433043fd27e32e 100644 --- a/docs/design/coreclr/jit/ryujit-overview.md +++ b/docs/design/coreclr/jit/ryujit-overview.md @@ -843,7 +843,7 @@ bad tree and wish to understand how it got corrupted, you can place a conditiona `gtNewNode` to see when it is created, and then a data breakpoint on the field that you believe is corrupted. The trees are connected by line characters (either in ASCII, by default, or in slightly more readable Unicode when -`COMPlus_JitDumpAscii=0` is specified), to make it a bit easier to read. +`COMPlus_JitDumpASCII=0` is specified), to make it a bit easier to read. ## Variable naming diff --git a/docs/design/coreclr/jit/ryujit-tutorial.md b/docs/design/coreclr/jit/ryujit-tutorial.md index 77462044483caa..050c11495b6a88 100644 --- a/docs/design/coreclr/jit/ryujit-tutorial.md +++ b/docs/design/coreclr/jit/ryujit-tutorial.md @@ -5,9 +5,8 @@ ### .NET Runtime - An implementation of the Common Language Infrastructure [ECMA 335] - Supports multiple languages, including C#, F# and VB -- Sources are mostly shared between the "desktop" version and the open-source coreclr implementation: - http://www.github.com/dotnet/runtime/src/coreclr - RyuJIT is the "next generation" just in time compiler for .NET +- Sources are at https://github.com/dotnet/runtime/tree/master/src/coreclr/src/jit #### Notes For context, the .NET runtime has been around since about the turn of the millennium. It is a virtual machine that supports the execution of a number of languages, primarily C#, Visual Basic, and F#. @@ -19,7 +18,6 @@ RyuJIT is the re-architected JIT for .NET. ### Why "RyuJIT"? - Ryujin is a Japanese Sea Dragon -We came up with the code name "RyuJIT" because our original code name had possible issues. We wanted something with "JIT" in the name, and the idea of a dragon came to mind because of the Dragon book that we all know and love. So – we just adapted the name of the Japanese sea dragon, Ryujin. diff --git a/docs/design/coreclr/jit/viewing-jit-dumps.md b/docs/design/coreclr/jit/viewing-jit-dumps.md index a60dd596df9864..3adf613fae85ef 100644 --- a/docs/design/coreclr/jit/viewing-jit-dumps.md +++ b/docs/design/coreclr/jit/viewing-jit-dumps.md @@ -20,7 +20,7 @@ The first thing to do is setup the .NET Core app we want to dump. Here are the s Exe - netcoreapp5.0 + net5.0 win-x64 @@ -58,17 +58,17 @@ The first thing to do is setup the .NET Core app we want to dump. Here are the s } ``` -* After you've finished editing the code, run `dotnet restore` and `dotnet publish -c Release`. This should drop all of the binaries needed to run your app in `bin/Release/netcoreapp5.0//publish`. +* After you've finished editing the code, run `dotnet restore` and `dotnet publish -c Release`. This should drop all of the binaries needed to run your app in `bin/Release/net5.0//publish`. * Overwrite the CLR dlls with the ones you've built locally. If you're a fan of the command line, here are some shell commands for doing this: ```shell # Windows - robocopy /e \artifacts\bin\coreclr\Windows_NT..Release \bin\Release\netcoreapp5.0\\publish > NUL - copy /y \artifacts\bin\coreclr\Windows_NT..Debug\clrjit.dll \bin\Release\netcoreapp5.0\\publish > NUL + robocopy /e \artifacts\bin\coreclr\Windows_NT..Release \bin\Release\net5.0\\publish > NUL + copy /y \artifacts\bin\coreclr\Windows_NT..Debug\clrjit.dll \bin\Release\net5.0\\publish > NUL # Unix - cp -rT /artifacts/bin/coreclr/..Release /bin/Release/netcoreapp5.0//publish - cp /artifacts/bin/coreclr/..Debug/libclrjit.so /bin/Release/netcoreapp5.0//publish + cp -rT /artifacts/bin/coreclr/..Release /bin/Release/net5.0//publish + cp /artifacts/bin/coreclr/..Debug/libclrjit.so /bin/Release/net5.0//publish ``` * Set the configuration knobs you need (see below) and run your published app. The info you want should be dumped to stdout. @@ -98,7 +98,7 @@ The first thing to do is setup the .NET Core app we want to dump. Here are the s ## Setting configuration variables -The behavior of the JIT can be controlled via a number of configuration variables. These are declared in [inc/clrconfigvalues.h](/src/coreclr/src/inc/clrconfigvalues.h). When used as an environment variable, the string name generally has `COMPlus_` prepended. When used as a registry value name, the configuration name is used directly. +The behavior of the JIT can be controlled via a number of configuration variables. These are declared in [inc/clrconfigvalues.h](/src/coreclr/src/inc/clrconfigvalues.h) and [jit/jitconfigvalues.h](/src/coreclr/src/jit/jitconfigvalues.h). When used as an environment variable, the string name generally has `COMPlus_` prepended. When used as a registry value name, the configuration name is used directly. These can be set in one of three ways: @@ -149,6 +149,7 @@ The wildcard character `*` can be used for `` and ``. In Below are some of the most useful `COMPlus` variables. Where {method-list} is specified in the list below, you can supply a space-separated list of either fully-qualified or simple method names (the former is useful when running something that has many methods of the same name), or you can specify `*` to mean all methods. * `COMPlus_JitDump`={method-list} – dump lots of useful information about what the JIT is doing. See [Reading a JitDump](ryujit-overview.md#reading-a-jitdump) for more on how to analyze this data. +* `COMPlus_JitDumpASCII`={1 or 0} - Specifies whether the JIT dump should be ASCII only (Defaults to 1). Disabling this generates more readable expression trees. * `COMPlus_JitDisasm`={method-list} – dump a disassembly listing of each method. * `COMPlus_JitDiffableDasm` – set to 1 to tell the JIT to avoid printing things like pointer values that can change from one invocation to the next, so that the disassembly can be more easily compared. * `COMPlus_JitGCDump`={method-list} – dump the GC information. diff --git a/docs/design/coreclr/profiling/davbr-blog-archive/ELT Hooks - tail calls.md b/docs/design/coreclr/profiling/davbr-blog-archive/ELT Hooks - tail calls.md index f24ce3bc145008..3cca8c9a9c5c17 100644 --- a/docs/design/coreclr/profiling/davbr-blog-archive/ELT Hooks - tail calls.md +++ b/docs/design/coreclr/profiling/davbr-blog-archive/ELT Hooks - tail calls.md @@ -219,7 +219,7 @@ Helper Main ``` -until you get a Leave hook for Helper(). At this point, you need to pop Helper() from your shadow stack, but he's not at the top-- he's buried under all your "deferred pop" frames. So your profiler would need to perform the deferred pops if a frame above OR below them gets popped. Hopefully, the yuckiness of this implementation will scare you straight. But the confusion of presenting crazy stacks to the user is the real reason to abandon Method 2 and go with Method 1. +until you get a Leave hook for Helper(). At this point, you need to pop Helper() from your shadow stack, but he's not at the top-- he's buried under all your "deferred pop" frames. So your profiler would need to perform the deferred pops if a frame above OR below them gets popped. Hopefully, the yuckiness of this implementation will scare you straight. But the confusion of presenting invalid stacks to the user is the real reason to abandon Method 2 and go with Method 1. ### Call tracing diff --git a/docs/design/features/tailcalls-with-helpers.md b/docs/design/features/tailcalls-with-helpers.md index f7156fe6414fd8..316a2a3a008bcb 100644 --- a/docs/design/features/tailcalls-with-helpers.md +++ b/docs/design/features/tailcalls-with-helpers.md @@ -1,460 +1,270 @@ -# The current way of handling tail-calls -## Fast tail calls -These are tail calls that are handled directly by the jitter and no runtime cooperation is needed. They are limited to cases where: -* Return value and call target arguments are all either primitive types, reference types, or valuetypes with a single primitive type or reference type fields -* The aligned size of call target arguments is less or equal to aligned size of caller arguments - -## Tail calls using a helper -Tail calls in cases where we cannot perform the call in a simple way are implemented using a tail call helper. Here is a rough description of how it works: -* For each tail call target, the jitter asks runtime to generate an assembler argument copying routine. This routine reads vararg list of arguments and places the arguments in their proper slots in the CONTEXT or on the stack. Together with the argument copying routine, the runtime also builds a list of offsets of references and byrefs for return value of reference type or structs returned in a hidden return buffer and for structs passed by ref. The gc layout data block is stored at the end of the argument copying thunk. -* At the time of the tail call, the caller generates a vararg list of all arguments of the tail called function and then calls JIT_TailCall runtime function. It passes it the copying routine address, the target address and the vararg list of the arguments. -* The JIT_TailCall then performs the following: - * It calls RtlVirtualUnwind twice to get the context of the caller of the caller of the tail call to simulate the effect of running epilog of the caller of the tail call and also its return. - * It prepares stack space for the callee stack arguments, a helper explicit TailCallFrame and also a CONTEXT structure where the argument registers of the callee, stack pointer and the target function address are set. In case the tail call caller has enough space for the callee arguments and the TailCallFrame in its stack frame, that space is used directly for the callee arguments. Otherwise the stack arguments area is allocated at the top of the stack. This slightly differs in the case the tail call was called from another tail called function - the TailCallFrame already exists and so it is not recreated. The TailCallFrame also keeps a pointer to the list of gc reference offsets of the arguments and structure return buffer members. The stack walker during GC then uses that to ensure proper GC liveness of those references. - * It calls the copying routine to translate the arguments from the vararg list to the just reserved stack area and the context. - * If the stack arguments and TailCaillFrame didn't fit into the caller's stack frame, these data are now moved to the final location - * RtlRestoreContext is used to start executing the callee. - -There are several issues with this approach: -* It is expensive to port to new platforms - * Parsing the vararg list is not possible to do in a portable way on Unix. Unlike on Windows, the list is not stored a linear sequence of the parameter data bytes in memory. va_list on Unix is an opaque data type, some of the parameters can be in registers and some in the memory. - * Generating the copying asm routine needs to be done for each target architecture / platform differently. And it is also very complex, error prone and impossible to do on platforms where code generation at runtime is not allowed. -* It is slower than it has to be - * The parameters are copied possibly twice - once from the vararg list to the stack and then one more time if there was not enough space in the caller's stack frame. - * RtlRestoreContext restores all registers from the CONTEXT structure, not just a subset of them that is really necessary for the functionality, so it results in another unnecessary memory accesses. -* Stack walking over the stack frames of the tail calls requires runtime assistance. - -# The new approach to tail calls using helpers -## Objectives -The new way of handling tail calls using helpers was designed with the following objectives: -* It should be cheap to port to new platforms, architectures and code generators -* It needs to work in both jitted and AOT compiled scenarios -* It should support platforms where runtime code generation is not possible -* The tail calls should be reasonably fast compared to regular calls with the same arguments -* The tail calls should not be slower than existing mechanism on Windows -* No runtime assistance should be necessary for unwinding stack with tail call frames on it -* The stack should be unwindable at any spot during the tail calls to properly support sampling profilers and similar tools. -* Stack walk during GC must be able to always correctly report GC references. -* It should work in all cases except those where a tail call is not allowed as described in the ECMA 335 standard section III.2.4 - -## Requirements -* The code generator needs to be able to compile a tail call to a target as a call to a thunk with the same parameters as the target, but void return, followed by a jump to an assembler helper. - -## Implementation -This section describes the helper functions and data structures that the tail calls use and also describes the tail call sequence step by step. -### Helper functions -The tail calls use the following thunks and helpers: -* StoreArguments - this thunk stores the arguments into a thread local storage together with the address of the corresponding CallTarget thunk and a descriptor of locations and types of managed references in the stored arguments data. This thunk is generated as IL and compiled by the jitter or AOT compiler. There is one such thunk per tail call target. -It has a signature that is compatible with the tailcall target function except for the return type which is void. But it is not the same. It gets the same arguments as the tail call target function, but it would also get "this" pointer and the generic context as explicit arguments if the tail call target requires them. Arguments of generic reference types are passed as "object" so that the StoreArguments doesn't have to be generic. -* CallTarget - this thunk gets the arguments buffer that was filled by the StoreArguments thunk, loads the arguments from the buffer, releases the buffer and calls the target function using calli. The signature used for the calli would ensure that all arguments including the optional hidden return buffer and the generic context are passed in the right registers / stack slots. Generic reference arguments will be specified as "object" in the signature so that the CallTarget doesn't have to be generic. -The CallTarget is also generated as IL and compiled by the jitter or AOT compiler. There is one such thunk per tail call target. This thunk has the same return type as the tailcall target or return "object" if the return type of the tail call target is a generic reference type. -* TailCallHelper - this is an assembler helper that is responsible for restoring stack pointer to the location where it was when the first function in a tail call chain was entered and then jumping to the CallTarget thunk. This helper is common for all tail call targets. -In a context of each tailcall invocation, the TailCallHelper will be handled by the jitter as if it had the same return type as the tail call target. That means that if the tail call target needs a hidden return buffer for returning structs, the pointer to this buffer will be passed to the TailCallHelper the same way as it would be passed to the tail call target. The TailCallHelper would then pass this hidden argument to the CallTarget helper. -There will be two flavors of this helper, based on whether the tail call target needs a hidden return buffer or not: - * TailCallHelper - * TailCallHelper_RetBuf - -### Helper data structures -The tail calls use the following data structures: -* Thread local storage for arguments. It stores the arguments of a tail call for a short period of time between the StoreArguments and CallTarget calls. -* Arguments GC descriptor - descriptor of locations and types of managed references in the arguments. -* TailCallHelperStack - a per thread stack of helper entries that is used to determine whether a tail call is chained or not. Its entries are allocated as local variables in CallTarget thunks. Each entry contains: - * Stack pointer captured right before a call to a tail call target - * ChainCall flag indicating whether the CallTarget thunk should return after the call to the tail call target or whether it should execute its epilog and jump to TailCallHelper instead. The latter is used by the TailCallHelper to remove the stack frame of the CallTarget before making a tail call from a tail called function. - * Pointer to the next entry on the stack. - -### Tail call sequence -* The caller calls the StoreArguments thunk corresponding to the callee to store the pointer to the tail call target function, its arguments, their GC descriptors, optional "this" and generic context arguments and the corresponding CallTarget thunk address in a thread local storage. -* The caller executes its epilog, restoring stack pointer and callee saved registers to their values when the caller was entered. -* The caller jumps to the TailCallHelper. This function performs the following operations: - * Get the topmost TailCallHelperStack entry for the current thread. - * Check if the previous stack frame is a CallTarget thunk frame by comparing the stack pointer value stored in the TailCallHelperStack entry to the current CFA (call frame address). If it matches, it means that the previous stack frame belongs to a CallTarget thunk and so the tail call caller was also tail called. - * If the previous frame was a CallTarget thunk, its stack frame needs to be removed to ensure that the stack will not grow when tail calls are chained. Set ChainCall flag in the TailCallHelperStack entry and return. That returns control to the CallTarget thunk. It checks the ChainCall flag and since it set, it executes its epilog and jumps to the TailCallHelper again. - * If the previous frame was not a CallTarget thunk, get the address of the CallTarget thunk of the tailcall target from the arguments buffer and jump to it. -* The CallTarget thunk function then does the following operation: - * Create local instance of TailCallHelperStack entry and store the current stack pointer value in it. - * Push the entry to the TailCallHelperStack of the current thread. - * Get the arguments buffer from the thread local storage, extract the regular arguments and the optional "this" and generic context arguments and the target function pointer. Release the buffer and call the target function. The frame of the CallTarget thunk ensures that the arguments of the target are GC protected until the target function returns or tail calls to another function. - * Pop the TailCallHelperStack entry from the TailCallHelperStack of the current thread. - * Check the ChainCall flag in the TailCallHelperStack entry. If it is set, run epilog and jump to the TailCallHelper. - * If the ChainCall flag is clear, it means that the last function in the tail call chain has returned. So return the return value of the target function. - -## Work that needs to be done to implement the new tail calls mechanism -### JIT (compiler in the AOT scenario) -* Modify compilation of tail calls with helper so that a tail call is compiled as a call to the StoreArguments thunk followed by the jump to the assembler TailCallHelper. In other words, the -``` -tail. call/callvirt -ret -``` -becomes -``` -call/callvirt -tail. call -ret -``` -### Runtime (compiler in the AOT scenario) -* Add generation of the StoreArguments and CallTarget IL thunks to the runtime (compiler tool chain in at AOT scenario). As a possible optimization, In the AOT scenario, the thunks can be generated by the compiler as native code directly without the intermediate IL. -* For the JIT scenario, add a new method to the JIT to EE interface to get the StoreArguments thunk method handle for a given target method and the TailCallHelper address. - -### Runtime in both scenarios -* Add support for the arguments buffer, which means: - * Add functions to create, release and get the buffer for a thread - * Add support for GC scanning the arguments buffers. -* Implement the TailCallHelper asm helper for all architectures -### Debugging in both scenarios -Ensure that the stepping in a debugger works correctly. In CoreCLR, the TailCallStubManager needs to be updated accordingly. - -## Example code - -```C# -struct S -{ - public S(long p1, long p2, long p3) - { - s1 = p1; s2 = p2; s3 = p3; - } - - public long s1, s2, s3; -} - -struct T -{ - public T(S s) - { - t1 = s.s1; t2 = s.s2; t3 = s.s3 t4 = 4; - } - public long t1, t2, t3, t4; -} - -struct U -{ - public U(T t) - { - u1 = t.t1; u2 = t.t2; u3 = t.t3 u4 = t.t4; u5 = 5; - } - public long u1, u2, u3, u4, u5; -} - -int D(U u) +# Tailcalls via helpers +## Introduction +Tailcall optimization is a transformation typically performed by compilers in +which a call appearing at the very end of a function allows the stack frame of +the caller to be cleaned up before the call is performed. This allows the +execution to use less stack space. For that reason it is an important +optimization for functional languages where recursion is typically the only way +of looping over data structures. Thus, these languages require this +transformation to be performed for correctness to guarantee that stack space +usage does not grow linear in the size of the data structures. + +Since not all languages need this to be done .NET allows languages to request +this optimization to be done on a per-call basis. This is communicated to the +runtime by adding the `tail.` prefix before the call in the CIL bytecode and +marks that the call needs to be performed as a tailcall for correctness. This +prefix is legal only on calls in tail position and also requires certain other +conditions to be met (as described in ECMA-335). + +When .NET sees the `tail.` prefix it has two mechanisms to perform the requested +tailcall: fast tailcalls and helper-based tailcalls. In fast tailcalls the JIT +is able to turn the call into cleanup of the stackframe followed by a jump or +branch instruction in the underlying assembly. However, not all platforms +support this and even on supported platforms it is not generally possible to do +for all callsites. In scenarios where the JIT is not able to do this it falls +back to another helper-based mechanism which allows dispatch of tailcalls more +generally. This mechanism is described in this document. + +## An overview of the mechanism +The helper-based mechanism is designed to be both portable and flexible so that +it can support many forms of tailcalls and so that the mechanism itself can be +supported widely and easily ported to new platforms. To accomplish these goals +the mechanism makes use of IL stubs and as little as possible use of details of +the underlying architecture. These goals are tricky to accomplish for the +general definition of a tailcall which requires unwindining the stack before +performing the call. Instead, the mechanism solves a slightly different problem: +for any arbitrary sequence of tailcalls use constant stack space. + +The idea is the following: at the first tailcall of a sequence let the stack +frame survive but set up a "dispatcher" that will know how to perform future +tailcalls. Otherwise detect that this is not the first tailcall and return to +let the previous dispatcher deal with the tailcall. The hard problems to solve +are then +1. Detecting whether returning will give control to a previous dispatcher. +1. Recording the required information about the tailcall: its arguments and + target. +1. Performing the call once the dispatcher has control. + +It turns out that the first problem is the only problem that requires +architectural details (and thus needs work when ported to new platforms) while +the other two problems can be solved once and for all in the runtime. This is +accomplished by having the runtime generate two IL stubs to do just those +things. When the JIT sees that a tailcall cannot be done using the fast tailcall +mechanism it asks the runtime to create these two IL stubs: one IL stub to +record the arguments and target for the call, and another to extract that +information and perform the call. + +## Storing the args +The first stub will be used to store the arguments. In the scenario where there +is a previous dispatcher control flow will initially return here before the +tail. prefixed call is (semantically) performed. Thus, it will not be legal to +store the arguments on the stack. Instead the arguments are stored in +thread-local storage for this small transitionary period of time. For the first +tailcall it would be legal to store the arguments on the stack but for +simplicity and uniformity this is not done and TLS is always used. Concretely, +for an example like +```csharp +bool IsEven(int x) { - int local; - Console.WriteLine("In C, U = [{0}, {1}, {2}, {3}, {4}", u.u1, u.u2, u.u3, u.u4, u.u5); - return 1; + if (x == 0) + return true; + return /* tail. prefixed */ IsOdd(x - 1); } +``` -int C(T t) +An IL stub will be generated which performs the following: +```csharp +void IL_STUB_StoreTailCallArgs(int x) { - int local; - Console.WriteLine("In C"); - U args = new U(t); - return tailcall D(args); + IntPtr argBuffer = RuntimeHelpers.AllocTailCallArgBuffer(4, null); + *(int*)argBuffer = x; } +``` -int B(S s) +Here a runtime helper is used to allocate an area of space in TLS. Note that +since arguments can be any arbitrary value, including by-refs and object refs, +the GC needs special knowledge of the argument buffer. This is the purpose of +the second argument to the runtime helper: it is a so-called GC descriptor which +describes which slots contain what kind of GC pointers in the argument buffer. +When the runtime generates this IL stub it will also generate the matching GC +descriptor and pass it as the second argument to the runtime helper. For this +simple example, the GC descriptor is trivial and null is passed. + +This case is relatively simple. In other cases the runtime might also require +the generated stub to be passed a function pointer to the target address. This +is for example the case when the tailcall is a `calli` instruction or for +certain tailcalls to generic methods. + +## Calling the target +The second IL stub extracts the arguments and calls the target function. For the +above case a function like the following will be generated: +```csharp +void IL_STUB_CallTailCallTarget(IntPtr argBuffer, IntPtr result, IntPtr* retAddr) { - int local; - Console.WriteLine("In B"); - T args = new T(S); - return tailcall C(args); + int arg1 = *(int*)argBuffer; + RuntimeHelpers.FreeTailCallArgBuffer(); + *retAddr = StubHelpers.NextCallReturnAddress(); + *(bool*)result = IsOdd(arg1); } - -int A() +``` +It matches the function above but also includes a call to +`StubHelpers.NextCallReturnAddress`. This is a JIT intrinsic that represents the +address of where the next call will return to. This is part of how the mechanism +detects that there is a previous dispatcher that should be used, which will be +described in the next section. + +As described above there are cases when the runtime needs to be passed the +target function pointer. In those cases this stub will instead load the function +pointer out of the arg buffer and dispatch to it using a `calli` instruction. + +## The dispatcher +The dispatcher is the last function of the mechanism. Unlike the IL stubs +described in the previous two sections it is general and not specific to any one +callsite. Thus only one dispatcher function needs to exist. However, note that +it is possible for the dispatcher to be simultaneously live multiple times on +the stack. This happens for example when a tailcalled function does a regular +call to a function that then does tailcalls. In that case the dispatcher needs +to be set up again since returning would not return directly back to the +previous dispatcher. + +The mechanism uses some data structures to describe the dispatchers that are +currently live on the stack and to facilitate detection of previous dispatchers. +The dispatchers themselves are described by a linked list of +`PortableTailCallFrame` entries. These entries are in a one-to-one +correspondence with each live instance of the dispatcher in the current stack. +This structure looks like the following: + +```csharp +struct PortableTailCallFrame { - S args = new S(1, 2, 3); - int result = B(args); - Console.WriteLine("Done, result = {0}\n", result); + public PortableTailCallFrame* Prev; + public IntPtr TailCallAwareReturnAddress; + public IntPtr NextCall; } ``` -## Example code execution -This section shows how stack evolves during the execution of the example code above. Execution starts at function A, but the details below start at the interesting point where the first tail call is about to be called. -### B is about to tail call C -``` -* Return address of A -* Callee saved registers and locals of A -* Stack arguments of B -* Return address of B -* Callee saved registers and locals of B -``` -### Arguments of C are stored in the thread local buffer, now we are in the TailCallHelper -The callee saved registers and locals of B are not on the stack anymore -``` -* Return address of A -* Callee saved registers and locals of A -* Stack arguments of B -* Return address of B -``` +Here the `TailCallAwareReturnAddress` is an address that can be used to detect +whether a return would go to that particular dispatcher. `NextCall` is what the +dispatcher uses to perform the next tailcall of a sequence. -### In CallTarget thunk for C, about to call C -The thunk will now extract parameters for C from the thread local storage and call C. -``` -* Return address of A -* Callee saved registers and locals of A -* Stack arguments of B -* Return address of B -* Callee saved registers and locals of CallTarget thunk for C -``` -### C is about to tail call D -``` -* Return address of A -* Callee saved registers and locals of A -* Stack arguments of B -* Return address of B -* Callee saved registers and locals of CallTarget thunk for C -* Stack arguments of C -* Return address of C -* Callee saved registers and locals of C -``` -### Arguments of D are stored in the thread local buffer, now we are in the TailCallHelper -The callee saved registers and locals of C are not on the stack anymore. -But we still have the return address of C, stack arguments of C and callee saved registers and locals of CallTarget thunk for C on the stack. -We need to remove them as well to prevent stack growing. -The TailCallHelper detects that the previous stack frame was the frame of the CallTarget thunk for C and so it sets the ChainCall flag in the topmost TailCallHelperStackEntry and returns to CallTarget thunk for C in order to let it cleanup its stack frame. -``` -* Return address of A -* Callee saved registers and locals of A -* Stack arguments of B -* Return address of B -* Callee saved registers and locals of CallTarget thunk for C -* Stack arguments of C -* Return address of C -``` -### Returned to CallTarget thunk for C with ChainCall flag in the TailCallHelperStackEntry **set** -The thunk checks the ChainCall flag and since it is set, it runs its epilog and then jumps to the TailCallHelper. -``` -* Return address of A -* Callee saved registers and locals of A -* Stack arguments of B -* Return address of B -* Callee saved registers and locals of CallTarget thunk for C -``` -### Back in TailCallHelper -Now the stack is back in the state where we have made the previous tail call. Since the previous stack frame was not a CallTarget thunk frame, we just jump to the CallTarget thunk for D. -``` -* Return address of A -* Callee saved registers and locals of A -* Stack arguments of B -* Return address of B -``` -### In CallTarget thunk for D, about to call D -The thunk will now extract parameters for D from the thread local storage and call D. -``` -* Return address of A -* Callee saved registers and locals of A -* Stack arguments of B -* Return address of B -* Callee saved registers and locals of CallTarget thunk for D -``` -### In D -We are in the last function of the chain, so after it does its work, it returns to its CallTarget thunk. -``` -* Return address of A -* Callee saved registers and locals of A -* Stack arguments of B -* Return address of B -* Callee saved registers and locals of CallTarget thunk for D -* Stack arguments of D -* Return address of D -* Callee saved registers and locals of D -``` -### Returned to CallTarget thunk for D with ChainCall flag in the TailCallHelperStackEntry **clear** -The thunk checks the ChainCall flag and since it is clear, it recognizes we are now returning from the call chain and so it returns the result of the D. -``` -* Return address of A -* Callee saved registers and locals of A -* Stack arguments of B -* Return address of B -* Callee saved registers and locals of CallTarget thunk for D -``` -### Returned to A -We are back in A and we have the return value of the call chain. -``` -* Return address of A -* Callee saved registers and locals of A -``` +The head of this linked list is stored in TLS, along with information about the +currently allocated argument buffer that can be used by GC: -## Example of thunks generated for a simple generic method - -```C# -struct Point +```csharp +struct TailCallTls { - public int x; - public int y; - public int z; + public PortableTailCallFrame* Frame; + public IntPtr ArgBuffer; + public IntPtr ArgBufferGCDesc; + public int ArgBufferSize; } +``` -class Foo +Finally, the dispatcher follows: +```csharp +void DispatchTailCalls(IntPtr callTarget, IntPtr result, IntPtr callersRetAddrSlot) { - public Point Test(int x, T t) where T : class + IntPtr callersRetAddr; + TailCallTls* tls = + RuntimeHelpers.GetTailCallInfo(callersRetAddrSlot, &callersRetAddr); + TailCallFrame* prevDispatcher = tls->Frame; + if (callersRetAddr == prevDispatcher->TailCallAwareReturnAddress) { - Console.WriteLine("T: {0}", typeof(t)); - return new Point(x, x, x); + prevDispatcher->NextCall = callTarget; + return; } -} -``` - -For tail calling the Test function, the IL helpers could look e.g. as follows: - -```IL -.method public static void StoreArgumentsTest(native int target, object thisObj, native int genericContext, int x, object t) cil managed -{ - .maxstack 4 - .locals init ( - [0] native int buffer, - ) - - call native int AllocateArgumentBuffer(56) - stloc.0 - - ldloc.0 - ldc.i8 0x12345678 // pointer to the GC descriptor of the arguments buffer - stind.i - ldloc.0 - sizeof native int - add - stloc.0 - - ldloc.0 - ldftn Point CallTargetTest() - stind.i - ldloc.0 - sizeof native int - add - stloc.0 - - ldloc.0 - ldarg.1 // "thisObj" - stobj object - ldloc.0 - sizeof object - add - stloc.0 - - ldloc.0 - ldarg.2 // "genericContext" - stind.i - ldloc.0 - sizeof native int - add - stloc.0 - - ldloc.0 - ldarg.3 // "x" - stind.i4 - ldloc.0 - sizeof native int - add - stloc.0 - - ldloc.0 - ldarg.4 // "t" - stobj object - ldloc.0 - sizeof object - add - stloc.0 - - ldloc.0 - ldarg.0 // "target" - stind.i - ret -} - -``` - -```IL -.method public static Point CallTargetTest() cil managed -{ - .maxstack 4 - .locals init ( - [0] native int buffer, - [1] valuetype TailCallHelperStackEntry entry, - [2] Point result - ) - - // Initialize the TailCallHelperStackEntry - // chainCall = false - // sp = current sp - - ldloca.s 1 - ldc.i4.0 - stfld bool TailCallHelperStackEntry::chainCall - ldloca.s 1 - call native int GetCurrentSp() - stfld native int TailCallHelperStackEntry::sp - - ldloca.s 1 // TailCallHelperStackEntry - call void PushHelperStackEntry(native int) - - // Prepare arguments for the tail call target - - call native int FetchArgumentBuffer() - sizeof native int - add // skip the pointer to the GC descriptor of the arguments buffer - sizeof native int - add // skip the address of the CallTargetTest in the buffer, it is used by the TailCallHelper only - stloc.0 - - ldloc.0 - ldobj object // this - ldloc.0 - sizeof object - add - stloc.0 - - ldloc.0 - ldind.i // generic context - ldloc.0 - sizeof native int - add - stloc.0 - - ldloc.0 - ldind.i4 // int x - ldloc.0 - sizeof native int - add - stloc.0 - - ldloc.0 - ldobj object // T t - ldloc.0 - sizeof object - add - - ldobj native int // tailcall target - - // The arguments buffer is not needed anymore - call void ReleaseArgumentBuffer() - - .try + PortableTailCallFrame frame; + frame.Prev = prevDispatcher; + try { - calli Point (object, native int, int32, object) // this, generic context, x, t - stloc.2 - leave.s Done + tls->Frame = &frame; + + do + { + frame.NextCall = IntPtr.Zero; + var fptr = (func* void(IntPtr, IntPtr, IntPtr*))callTarget; + fptr(tls->ArgBuffer, result, &frame.TailCallAwareReturnAddress); + callTarget = frame.NextCall; + } while (frame.NextCall != IntPtr.Zero); } finally { - ldloca.s 1 // TailCallHelperStackEntry - call void PopHelperStackEntry(native int) - endfinally + tls->Frame = prevDispatcher; } +} +``` -Done: - ldloc.1 // TailCallHelperStackEntry - ldfld bool TailCallHelperStackEntry::chainCall - brfalse.s NotChained - - // Jump to the TailCallHelper that will call to the next tail call in the chain. - // The stack frame of the current CallTargetTest is reclaimed and epilog executed - // before the TailCallHelper is entered. - tail.call int32 TailCallHelper() - ret +It is first responsible for detecting whether we can return and let a previous +dispatcher perform the tailcall. To do this it needs to obtain the caller's +return address (i.e. an address in the caller's caller). Furthermode, it needs +to obtain information about the linked list of dispatcher frames. Due to return +address hijacking in the VM it is not enough to simply read the return address +directly from the stack -- instead, assistance from the VM is required in the +form of a helper. This helper both returns the TLS information and the correct +return address. + +In the case a return would go back to a dispatcher we simply record the next +call by saving the `callTarget` parameter, a function pointer to a +`CallTailCallTarget` stub. Otherwise a new entry in the linked list is set up +and a loop is entered that starts dispatching tailcalls. + +This loop calls into the `CallTailCallTarget` stubs so it is from these stubs +that we need to store the return address for comparisons in the future. These +stubs will call into the specified user function from the original tailcall +site, and it is if this function does a tailcall that we will need to detect +whether we can use a previous dispatcher. This will be the case when we return +directly to a `CallTailCallTarget` stub which will then return to the +dispatcher. + +## The JIT's transformation +Based on these functions the JIT needs to do a relatively simple transformation +when it sees a tailcall that it cannot dispatch as a fast tailcall. This +transformation is done in the JIT's internal IR, but for familiarity it is +described here in pseudo C#. For a tailcall site like + +```csharp +return /*tail prefixed*/ IsOdd(x - 1); +``` +the JIT requests the runtime to create the two IL stubs described above and +transforms the code into the equivalent of + +```csharp +IL_STUB_StoreTailCallArgs(x - 1); +bool result; +DispatchTailCalls(&IL_STUB_CallTailCallTarget, (IntPtr)&result, _AddressOfReturnAddress()); +return result; +``` -NotChained: - // Now we are returning from a chain of tail calls to the caller of this chain - ldloc.2 - ret -} -``` \ No newline at end of file +Here `_AddressOfReturnAddress()` represents the stack slot containing the return +address. Note that .NET requires that the return address is always stored on the +stack, even on ARM architectures, due to its return address hijacking mechanism. + +In certain cases the target function pointer is also stored. For some targets +this might require the JIT to perform the equivalent of `ldvirtftn` or `ldftn` +to obtain a properly callable function pointer. + +## Debugging +The control flow when helper-based tailcalls are performed is non-standard. +Specifically, there are two possible paths of execution when a tailcall is +performed, depending on whether returning goes to an existing dispatcher. Due to +this the debugger requires special support to give users a good experience when +stepping in code involving heper-based tailcalls. + +The debugger by default ignores IL stubs and implement stepping-in in a way that +makes the above work in both scenarios. It turns out that the only problematic +case is when stepping over tailcalls that are done by returning first. The +debugger uses the same TLS structure as the rest of the mechanism to detect this +case and simulates a step-over by performing a step-out to the nearest user +function instead. + +## Conclusion +.NET implements tail prefixed calls based on two separate mechanisms: a fast +tailcall mechanism, where the JIT just directly jumps to the target function, +and a helper-based tailcall mechanism, where the JIT asks the runtime to +generate IL stubs that are used by a dispatcher to perform the tailcalls. Since +the mechanism is primarily based on these IL stubs the mechanism is portable and +the only architecture specific part is detecting whether there is a previous +dispatcher. However, this part was not hard to implement for ARM and XArch +architectures and it is expected that it will not be significantly harder for +other platforms in the future. diff --git a/docs/design/features/unloadability.md b/docs/design/features/unloadability.md index 54a236cbbe6b5d..4b61b0f8b3ce62 100644 --- a/docs/design/features/unloadability.md +++ b/docs/design/features/unloadability.md @@ -98,8 +98,9 @@ The dashed lines represent indirect links from MethodTables of the objects to th ### First phase of unloading Unloading is initialized by the user code calling `AssemblyLoadContext.Unload` metod or by execution of the `AssemblyLoadContext` finalizer. The following steps are performed to start the unloading process. * The `AssemblyLoadContext` fires the `Unloading` event to allow the user code to perform cleanup if required (e.g. stop threads running inside of the context, remove references and destroy handles, etc.) -* `AssemblyNative::PrepareForAssemblyLoadContextRelease` method is called, which in turn calls `CLRPrivBinderAssemblyLoadContext::PrepareForLoadContextRelease` -* That method changes the handle referring to the `AssemblyLoadContext` to strong to keep the `AssemblyLoadContext` around until the unload is complete. For example, finalizers of types that are loaded into the `AssemblyLoadContext` may need access to the `AssemblyLoadContext`. +* The `AssemblyLoadContext.InitiateUnload` method is called. It creates a strong GC handle referring to the `AssemblyLoadContext` to keep it around until the unload is complete. For example, finalizers of types that are loaded into the `AssemblyLoadContext` may need access to the `AssemblyLoadContext`. +* Then it calls `AssemblyNative::PrepareForAssemblyLoadContextRelease` method with that strong handle as an argument, which in turn calls `CLRPrivBinderAssemblyLoadContext::PrepareForLoadContextRelease` +* That method stores the passed in strong GC handle in `CLRPrivBinderAssemblyLoadContext::m_ptrManagedStrongAssemblyLoadContext`. * Then it decrements refcount of the `AssemblyLoaderAllocator` the `CLRPrivBinderAssemblyLoadContext` points to. * Finally, it destroys the strong handle to the managed `LoaderAllocator`. That allows the `LoaderAllocator` to be collected. ### Second phase of unloading @@ -109,5 +110,5 @@ This phase is initiated after all instances of types from assemblies loaded into * This method decrements reference count of all the `LoaderAllocators` that reference this `LoaderAllocator` and then the reference count of this `LoaderAllocator` itself. * If it was not the last reference, the native `AssemblyLoaderAllocator` must stay alive until there are no references to it, so there is nothing else to be done now. It will be destroyed later in `LoaderAllocator::GCLoaderAllocators` after the last reference goes away. * If we have released the last reference, the `LoaderAllocator::GCLoaderAllocators` is executed. This function finds all collectible LoaderAllocators that are not alive anymore and cleans up all domain assemblies in them. The cleanup removes each `DomainAssembly` from the `AppDomain` and also from the binding cache, it notifies debugger and finally destroys the `DomainAssembly`. -* Strong handle to the managed `AssemblyLoadContext` in each of these LoaderAllocators is now destroyed. That enables these related AssemblyLoadContexts to be collected by GC. -* Finally, these LoaderAllocators are registered for cleanup in the `AppDomain`. Their actual destruction happens on the finalizer thread in `Thread::DoExtraWorkForFinalizer`. When a `LoaderAllocator` is destroyed, the related `CLRPrivBinderAssemblyLoadContext` is destroyed too. +* The strong and long weak handles to the managed `AssemblyLoadContext` in each of these LoaderAllocators are now destroyed. That enables these related `AssemblyLoadContext`s to be collected by GC. +* Finally, these `LoaderAllocator`s are registered for cleanup in the `AppDomain`. Their actual destruction happens on the finalizer thread in `Thread::DoExtraWorkForFinalizer`. When a `LoaderAllocator` is destroyed, the related `CLRPrivBinderAssemblyLoadContext` is destroyed too. diff --git a/docs/design/features/unloadability.svg b/docs/design/features/unloadability.svg index 52f39cdec945da..2b361ebeb2eff2 100644 --- a/docs/design/features/unloadability.svg +++ b/docs/design/features/unloadability.svg @@ -3,7 +3,7 @@ + viewBox="0 0 583.926 544.114" xml:space="preserve" color-interpolation-filters="sRGB" class="st19"> @@ -23,15 +23,14 @@ .st9 {fill:#ffffff;stroke:none;stroke-linecap:butt;stroke-width:7.2} .st10 {fill:#000000;font-family:Calibri;font-size:0.666664em} .st11 {marker-end:url(#mrkr2-52);stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75} - .st12 {fill:#ffffff;stroke:none;stroke-linecap:butt} - .st13 {marker-end:url(#mrkr2-125);stroke:#00b050;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75} - .st14 {fill:#00b050;fill-opacity:1;stroke:#00b050;stroke-opacity:1;stroke-width:0.22935779816514} - .st15 {fill:none;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75} - .st16 {fill:#000000;font-family:Calibri;font-size:1.00001em} - .st17 {stroke:#ffc000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75} - .st18 {fill:#ea700d;font-family:Calibri;font-size:1.00001em} - .st19 {fill:#0070c0;font-family:Calibri;font-size:1.00001em} - .st20 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3} + .st12 {marker-end:url(#mrkr2-125);stroke:#00b050;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75} + .st13 {fill:#00b050;fill-opacity:1;stroke:#00b050;stroke-opacity:1;stroke-width:0.22935779816514} + .st14 {fill:none;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75} + .st15 {fill:#000000;font-family:Calibri;font-size:1.00001em} + .st16 {stroke:#ffc000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75} + .st17 {fill:#ea700d;font-family:Calibri;font-size:1.00001em} + .st18 {fill:#0070c0;font-family:Calibri;font-size:1.00001em} + .st19 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3} ]]> @@ -43,7 +42,7 @@ markerUnits="strokeWidth" overflow="visible"> - @@ -210,7 +209,7 @@ - + Reference Dynamic connector.26 @@ -218,7 +217,7 @@ - + Weak handle Dynamic connector.27 @@ -226,15 +225,15 @@ - + Pointer Dynamic connector.28 Pointer - - + + Pointer Dynamic connector.29 @@ -249,21 +248,21 @@ Pointer - + Pointer Dynamic connector.31 - + - + Dynamic connector.32 - Handle (initially weak, strong during unload) + Long weak handle - + - - Handle (initially weak, strong during unload) + + Long weak handle Dynamic connector.33 Pointer @@ -277,7 +276,7 @@ Strong handle - + Strong handle @@ -285,26 +284,36 @@ ... - - ... + + ... Dynamic connector.36 + 1 246.14 535.15 L391.33 534.92 A3 3 0 1 1 397.33 534.91 L466.33 534.8 A3 3 0 0 1 472.33 534.8 L539.88 534.69" + class="st16"/> Sheet.37 Managed side - - Managed side + + Managed side Sheet.38 Native side - - Native side + + Native side + + Dynamic connector.39 + Strong handle (only during unload) + + + + + Strong handle(only during unload) diff --git a/docs/design/specs/Ecma-335-Augments.md b/docs/design/specs/Ecma-335-Augments.md new file mode 100644 index 00000000000000..1d42a5e4c9094d --- /dev/null +++ b/docs/design/specs/Ecma-335-Augments.md @@ -0,0 +1,368 @@ +# ECMA-335 CLI Specification Addendum + +This is a list of additions and edits to be made in ECMA-335 specifications. It includes both documentation of new runtime features and issues encountered during development. Some of the issues are definite spec errors while others could be reasoned as Microsoft implementation quirks. + +## Signatures + +There is a general philosophical issue whereby the spec defines the +*syntax* of signatures to exclude errors such as: + +* using void outside of return types or pointer element types +* instantiating a generic with a byref type +* having a field of byref type +* etc. + +Another approach is to syntactically treat `VOID`, `TYPEDBYREF`, +`BYREF Type`, `CMOD_OPT Type`, `CMOD_REQ Type` as the other `Type`s +and then deal with the cases like those above as semantic errors in their use. +That is closer to how many implementations work. It is also how type syntax +is defined in the grammar for IL, with many of the semantic errors +deferred to peverify and/or runtime checking rather than being checked +during assembly. + +The spec is also not entirely consistent in its use of the first +approach. Some errors, such as instantiating a generic with an +unmanaged pointer type, are not excluded from the spec's signature +grammars and diagrams. + +Many of the specific issues below arise from the tension between these +two approaches. + +### 1. `(CLASS | VALUETYPE)` cannot be followed by TypeSpec in practice + +In II.23.2.12 and II.23.2.14, it is implied that the token in +`(CLASS | VALUETYPE) TypeDefOrRefOrSpecEncoded` can be a `TypeSpec`, when in +fact it must be a `TypeDef` or `TypeRef`. + +peverify gives the following error: + +``` +[MD]: Error: Signature has token following ELEMENT_TYPE_CLASS +(_VALUETYPE) that is not a TypeDef or TypeRef +``` + +An insightful comment in CLR source code notes that this rule prevents +cycles in signatures, but see #2 below. + +Related issue: + +* https://github.com/dotnet/roslyn/issues/7970 + +#### Proposed specification change + +a) Rename section II.23.2.8 from "TypeDefOrRefOrSpecEncoded" to "TypeDefOrRefEncoded and TypeDefOrRefOrSpecEncoded" + +b) Replace + +> These items are compact ways to store a TypeDef, TypeRef, or TypeSpec token in a Signature (§II.23.2.12). + +with + +> TypeDefOrRefEncoded is a compact representation of either TypeDef or TypeRef token in a Signature (§II.23.2.12). TypeDefOrRefOrSpecEncoded is a compact representation of either TypeDef, TypeRef or TypeSpec token in a Signature. + +Also correct + +> The encoded version of this TypeRef token is made up as follows: + +to + +> The compact representation of a TypeDef, TypeRef or TypeSpec token is made up as follows: + +c) In section II.23.2.12 replace + +```ebnf +Type ::= + ... + CLASS TypeDefOrRefOrSpecEncoded + ... + GENERICINST (CLASS | VALUETYPE) TypeDefOrRefOrSpecEncoded GenArgCount Type* + ... + VALUETYPE TypeDefOrRefOrSpecEncoded + ... +``` + +with + +```ebnf +Type ::= + ... + (CLASS | VALUETYPE) TypeDefOrRefEncoded + GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type+ + ... +``` + +Note also the correction of `Type*` to `Type+`. A generic type instantiation shall have at least one type argument. + +d) In section II.23.2.14 replace + +```ebnf +TypeSpecBlob ::= + ... + GENERICINST (CLASS | VALUETYPE) TypeDefOrRefOrSpecEncoded GenArgCount Type Type* + ... +``` + +with + +```ebnf +TypeSpecBlob ::= + ... + GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type+ + ... +``` + +`Type Type*` is simplified to `Type+`. + +#### Rationale of the proposal + +1. The proposal removes the possibility of representing the same type via two different encodings. This approach is consistent with II.23.2.16: "Short form signatures" where a short form of a primitive type is preferred over the corresponding long form. + +2. Potential TypeSpec recursion is prevented. + +3. PEVerify, the CLR runtime and C# compiler prior to VS 2015 report an error when encountering an encoded TypeSpec in the positions described above. + +### 2. `(CMOD_OPT | CMOD_REQ) ` is permitted in practice + +In II.23.2.7, it is noted that CMOD_OPT or CMOD_REQD is followed +by a TypeRef or TypeDef metadata token, but TypeSpec tokens are +also allowed by ilasm, csc, peverify, and the CLR. + +Note, in particular, that TypeSpecs are used there by C++/CLI to +represent strongly-typed boxing in C++/CLI. e.g. `Nullable^` +in C++/CLI becomes +``[mscorlib]System.ValueType modopt([mscorlib]System.Nullable`1) modopt([mscorlib]System.Runtime.CompilerServices.IsBoxed)`` +in IL. + +This tolerance adds a loophole to the rule above whereby cyclical +signatures are in fact possible, e.g.: + +* `TypeSpec #1: PTR CMOD_OPT I4` + +Such signatures can currently cause crashes in the runtime and various +tools, so if the spec is amended to permit TypeSpecs as modifiers, +then there should be a clarification that cycles are nonetheless not +permitted, and ideally readers would detect such cycles and handle the +error with a suitable message rather than a stack overflow. + +Related issues: + +* https://github.com/dotnet/roslyn/issues/7971 +* https://github.com/dotnet/coreclr/issues/2674 + +#### Proposed specification change + +In section II.23.2.7, replace + +> The CMOD_OPT or CMOD_REQD is followed by a metadata token that indexes a row in the TypeDef + table or the TypeRef table. However, these tokens are encoded and compressed – see §II.23.2.8 +for details + +with + +> The CMOD_OPT or CMOD_REQD is followed by a metadata token that indexes a row in the TypeDef +table, TypeRef table, or TypeSpec table. However, these tokens are encoded and compressed – +see §II.23.2.8 for details. Furthermore, if a row in the TypeSpec table is indicated, +it must not create cycle. + +### 3. Custom modifiers can go in more places than specified + +Most notably, II.23.2.14 and II.23.21.12 (`Type` and `TypeSpec` grammars) +are missing custom modifiers for the element type of `ARRAY` and the +type arguments of `GENERICINST`. + +Also, `LocalVarSig` as specified does not allow modifiers on +`TYPEDBYREF`, and that seems arbitrary since it is allowed on parameter +and return types. + +#### Proposed specification change + +a) In section II.23.2.4 FieldSig, replace the diagram with a production rule: + +```ebnf +FieldSig ::= FIELD Type +``` + +b) In section II.23.2.5 PropertySig, replace the diagram with a production rule: + +```ebnf +PropertySig ::= PROPERTY HASTHIS? ParamCount RetType Param* +``` + +Note that this change also allows properties to have BYREF type. + +c) In section II.23.2.6 LocalVarSig, replace the diagram with production rules: + +```ebnf +LocalVarSig ::= + LOCAL_SIG Count LocalVarType+ + +LocalVarType ::= + Type + CustomMod* Constraint BYREF? Type + CustomMod* BYREF Type + CustomMod* TYPEDBYREF + +``` + +d) In section II.23.2.10 Param, replace the diagram with production rules: + +```ebnf +Param ::= + Type + CustomMod* BYREF Type + CustomMod* TYPEDBYREF +``` + +e) In section II.23.2.11 RetType, replace the diagram with production rules: + +```ebnf +RetType ::= + Type + CustomMod* BYREF Type + CustomMod* TYPEDBYREF + CustomMod* VOID +``` + +f) In section II.23.2.12 Type, add a production rule to the definition of `Type`: + +```ebnf +Type ::= CustomMod* Type + +``` + +g) In sections II.23.2.12 Type and II.23.2.14 TypeSpec replace production rule + +```ebnf +PTR CustomMod* Type +``` + +with + +```ebnf +PTR Type +``` + +and replace production rule + +```ebnf +SZARRAY CustomMod* Type +``` + +with + +```ebnf +SZARRAY Type +``` + +### 4. BYREF can come before custom modifiers + +Everywhere `BYREF` appears in the spec's box and pointer diagrams, it +comes after any custom modifiers, but the C++/CLI declaration `const int&` +is emitted as `BYREF CMOD_OPT IsConst I4`, and a call-site using +`CMOD_OPT IsConst BYREF I4` will not match. + +Under the interpretation that `BYREF` is just a managed pointer type, it +makes sense that there should be parity between `PTR` and `BYREF` with +respect to modifiers. Consider, `const int*` vs. `int* const` in +C++. The former (pointer to constant int) is `PTR CMOD_OPT IsConst I4` +and the latter (constant pointer to int) is `CMOD_OPT IsConst PTR I4`. +The analogy from `const int*` to `const int&` justifies C++'s +encoding of `BYREF` before `CMOD_OPT` in defiance of the spec. + +#### Proposed specification change + +Already addressed by changes in proposal #3 above. + +### 5. TypeSpecs can encode more than specified + +In II.23.2.14, the grammar for a `TypeSpec` blob is a subset of the +`Type` grammar defined in II.23.21.12. However, in practice, it is +possible to have other types than what is listed. + +Most notably, the important use of the `constrained.` IL prefix with +type parameters is not representable as specified since `MVAR` and `VAR` +are excluded from II.23.2.14. + +More obscurely, the constrained. prefix also works with primitives, +e.g: + +``` +constrained. int32 +callvirt instance string [mscorlib]System.Object::ToString() +``` + +which opens the door to `TypeSpec`s with I4, I8, etc. signatures. + +It then follows that the only productions in `Type` that do not make +sense in `TypeSpec` are `(CLASS | VALUETYPE) TypeDefOrRef` since +`TypeDefOrRef` tokens can be used directly and the indirection through +a `TypeSpec` would serve no purpose. + +In the same way as `constrained.`, (assuming #2 is a spec bug and not +an ilasm/peverify/CLR quirk), custom modifiers can beget `TypeSpec`s +beyond what is allowed by II.23.2.14, e.g. `modopt(int32)` creates a +typespec with signature I4. + +Even more obscurely, this gives us a way to use `VOID`, `TYPEDBYREF`, +`CMOD_OPT`, and `CMOD_REQ` at the root of a `TypeSpec`, which are not even +specified as valid at the root of a `Type`: `modopt(int32 modopt(int32))`, +`modopt(void)`, and `modopt(typedref)` all work in +practice. `CMOD_OPT` and `CMOD_REQ` at the root can also be obtained by putting +a modifier on the type used with `constrained.`. + +## Heap sizes + +The ECMA-335-II specification isn't clear on the maximum sizes of #String, #Blob and #GUID heaps. + +#### Proposed specification change + +We propose the limit on #String and #Blob heap size is 2^29 (0.5 GB), that is any index to these heaps fits into 29 bits. + +#### Rationale of the proposal + +1) 2^29 is the maximum value representable by a compressed integer as defined elsewhere in the spec. Currently the metadata don't encode heap indices anywhere using compressed integers. However the Portable PDB specification uses compressed integers for efficient encoding of heap indices. We could extend the definition of compressed integer to cover all 32 bit integers, but it would be simpler if we could leave it as is. + +2) 0.5 GB is a very large heap. Having such a big PE file seems unreasonable and very rare scenario (if it exists at all). + +3) Having 3 spare bits available is very beneficial for the implementation. It allows to represent WinRT projected strings, namespaces, etc. in very efficient way. If we had to represent heap indices with all 32 bits it would bloat various structures and increase memory pressure. PE files over 0.5 GB of size are very rare, but the overhead would affect all compilers and tools working with the metadata reader. + +## Metadata merging + +The mention of metadata merging in § II.10.8 _Global fields and methods_ is a spec bug. The CLI does not merge metadata. Policies of static linkers that merge metadata may vary and do not concern the CLI. + +This text should be deleted, and the _metadata merging_ entry should be removed from the index: + +> ~~The only noticeable difference is in how definitions of this special class +> are treated when multiple modules are combined together, as is done by a class loader. This process is +> known as _metadata merging_.~~ +> +> ~~For an ordinary type, if the metadata merges two definitions of the same type, it simply discards one +> definition on the assumption they are equivalent, and that any anomaly will be discovered when the +> type is used. For the special class that holds global members, however, members are unioned across all +> modules at merge time. If the same name appears to be defined for cross-module use in multiple +> modules then there is an error. In detail:~~ +> +> * ~~If no member of the same kind (field or method), name, and signature exists, then +> add this member to the output class.~~ +> +> * ~~If there are duplicates and no more than one has an accessibility other than +> **compilercontrolled**, then add them all to the output class.~~ +> +> * ~~If there are duplicates and two or more have an accessibility other than +> **compilercontrolled**, an error has occurred.~~ + +## Module Initializer + +All modules may have a module initializer. A module initializer is defined as the type initializer (§ II.10.5.3) of the `` type (§ II.10.8). + +There are no limitations on what code is permitted in a module initializer. Module initializers are permitted to run and call both managed and unmanaged code. + +### Module Initialization Guarantees + +In addition to the guarantees that apply to all type initializers, the CLI shall provide the following guarantees for module initializers: + +1. A module initializer is executed at, or sometime before, first access to any static field or first invocation of any method defined in the module. + +2. A module initializer shall run exactly once for any given module unless explicitly called by user code. + +3. No method other than those called directly or indirectly from the module initializer will be able to access the types, methods, or data in a module before its initializer completes execution. diff --git a/src/libraries/System.Reflection.Metadata/specs/PE-COFF.md b/docs/design/specs/PE-COFF.md similarity index 100% rename from src/libraries/System.Reflection.Metadata/specs/PE-COFF.md rename to docs/design/specs/PE-COFF.md diff --git a/src/libraries/System.Reflection.Metadata/specs/PortablePdb-Metadata.md b/docs/design/specs/PortablePdb-Metadata.md similarity index 100% rename from src/libraries/System.Reflection.Metadata/specs/PortablePdb-Metadata.md rename to docs/design/specs/PortablePdb-Metadata.md diff --git a/docs/pr-guide.md b/docs/pr-guide.md index f55e4e5f1b6b89..9074d699186f39 100644 --- a/docs/pr-guide.md +++ b/docs/pr-guide.md @@ -52,7 +52,7 @@ Validation may fail for several reasons: * Add a comment `/azp run runtime` * Or, click on "re-run all checks" in the GitHub Checks tab * Or, simply close and reopen the PR. -* If you have established that it is an unrelated failure, please ensure we have an active issue for it. See the [unrelated failure](#unrelated-failure) section below. +* If you have established that it is an unrelated failure, please ensure we have an active issue for it. See the [unrelated failure](#what-to-do-if-you-determine-the-failure-is-unrelated) section below. * Whoever merges the PR should be satisfied that the failure is unrelated, is not introduced by the change, and that we are appropriately tracking it. ### Option 3: The state of the master branch HEAD is bad. diff --git a/docs/project/dogfooding.md b/docs/project/dogfooding.md index 8af5db3b995a11..6b564f7ec239c3 100644 --- a/docs/project/dogfooding.md +++ b/docs/project/dogfooding.md @@ -117,8 +117,8 @@ This is the default case for applications - running against an installed .NET ru ```XML Exe - - netcoreapp5.0 + + net5.0 5.0.0-preview.1.20120.5 @@ -140,8 +140,8 @@ make it self-contained by adding a RuntimeIdentifier (RID). ```XML Exe - - netcoreapp5.0 + + net5.0 5.0.0-preview.1.20120.5 @@ -152,7 +152,7 @@ make it self-contained by adding a RuntimeIdentifier (RID). ``` $ dotnet restore $ dotnet publish -$ bin\Debug\netcoreapp5.0\win-x64\publish\App.exe +$ bin\Debug\net5.0\win-x64\publish\App.exe ``` ## More Advanced Scenario - Using your local CoreFx build diff --git a/docs/project/dotnet-standards.md b/docs/project/dotnet-standards.md index 2eb0af2be0bdea..8cdb60da4898db 100644 --- a/docs/project/dotnet-standards.md +++ b/docs/project/dotnet-standards.md @@ -29,6 +29,7 @@ ECMA 335 - CLI - [ECMA 335 Standard Overview](http://www.ecma-international.org/publications/standards/Ecma-335.htm) - [ECMA 335 Standard (PDF)](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf) - [Wikipedia entry on CLI](http://en.wikipedia.org/wiki/Common_Language_Infrastructure) +- [ECMA 335 Addendum](../design/specs/Ecma-335-Augments.md) **ECMA 335 Partitions with added Microsoft Specific Implementation Notes** diff --git a/docs/project/library-servicing.md b/docs/project/library-servicing.md index 52d7f5ac06775c..29934d1606f1f5 100644 --- a/docs/project/library-servicing.md +++ b/docs/project/library-servicing.md @@ -25,7 +25,7 @@ If this library ships both inbox on a platform and in its own library package th ``` - 4.0.3.0 + 4.0.3.0 ``` Where the `AssemblyVersion` is set to the old version before updating. To determine if the library ships inbox you can look at for `InboxOnTargetFramework` item groups or `TreatAsOutOfBox` suppressions in the pkgproj for the library. diff --git a/docs/workflow/README.md b/docs/workflow/README.md index 57c10f7a9d472d..7a17fecd50eff0 100644 --- a/docs/workflow/README.md +++ b/docs/workflow/README.md @@ -10,7 +10,7 @@ The repo can be built for the following platforms, using the provided setup and | x86 | ✔ | | | | | ARM | ✔ | ✔ | | | | ARM64 | ✔ | ✔ | | | -| | [Requirements](requirements/windows-requirements.md) | [Requirements](requirements/linux-requirements.md) | [Requirements](requirements/macos-requirements.md) | +| | [Requirements](requirements/windows-requirements.md) | [Requirements](requirements/linux-requirements.md) | [Requirements](requirements/macos-requirements.md) | [Requirements](requirements/freebsd-requirements.md) Before proceeding further, please click on the link above that matches your machine and ensure you have installed all the prerequisites for the build to work. diff --git a/docs/workflow/building/coreclr/linux-instructions.md b/docs/workflow/building/coreclr/linux-instructions.md index 06977543d9d57b..63280373139927 100644 --- a/docs/workflow/building/coreclr/linux-instructions.md +++ b/docs/workflow/building/coreclr/linux-instructions.md @@ -19,7 +19,7 @@ Please note that when choosing an image choosing the same image as the host os y Once you have chosen an image the build is one command run from the root of the runtime repository: ```sh -docker run --rm -v :/runtime -w /runtime mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-a50a721-20191120200116 ./src/coreclr/build.sh -clang9 +docker run --rm -v :/runtime -w /runtime mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-20200508132555-78cbb55 ./build.sh --subset clr -clang9 ``` Dissecting the command: @@ -30,16 +30,18 @@ Dissecting the command: `-w: /runtime`: set /runtime as working directory for the container -`mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-a50a721-20191120200116`: image name. +`mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-20200508132555-78cbb55`: image name. -`./src/coreclr/build.sh`: command to be run in the container, run the build to coreclr. +`./build.sh`: command to be run in the container, run the build to coreclr. + +`--subset clr`: build the runtime subset (excluding libraries and installers) `-clang9`: argument to use clang 9 for the build, only compiler in the build image. -If you are attempting to cross build for arm/arm64 then use the crossrootfs location to set the ROOTFS_DIR. The command would add `-e ROOTFS_DIR=`. See [Docker Images](#Docker-Images) for the crossrootfs location. In addition you will need to specify `cross`. +If you are attempting to cross build for arm/arm64 then use the crossrootfs location to set the ROOTFS_DIR. The command would add `-e ROOTFS_DIR=`. See [Docker Images](#Docker-Images) for the crossrootfs location. In addition you will need to specify `--cross`. ```sh -docker run --rm -v :/runtime -w /runtime -e ROOTFS_DIR=/crossrootfs/arm64 mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-arm64-cfdd435-20191023143847 ./src/coreclr/build.sh arm64 cross +docker run --rm -v :/runtime -w /runtime -e ROOTFS_DIR=/crossrootfs/arm64 mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-arm64-20200508132638-b2c2436 ./build.sh --arch arm64 --cross --subset clr ``` Note that instructions on building the crossrootfs location can be found at [cross-building.md](cross-building.md). These instructions are suggested only if there are plans to change the rootfs, or the Docker images for arm/arm64 are insufficient for you build. @@ -55,9 +57,9 @@ These instructions might fall stale often enough as we change our images as our | Alpine | x64 | `mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.9-WithNode-0fc54a3-20190918214015` | - | -clang9 | | CentOS 6 (build for RHEL 6) | x64 | `mcr.microsoft.com/dotnet-buildtools/prereqs:centos-6-f39df28-20191023143802` | - | -clang9 | | CentOS 7 (build for RHEL 7) | x64 | `mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7-f39df28-20191023143754` | - | -clang9 | -| Ubuntu 16.04 | arm32(armhf) | `mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-09ec757-20200320131433` | `/crossrootfs/arm` | -clang9 | -| Ubuntu 16.04 | arm64 (arm64v8) | `mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-arm64-cfdd435-20191023143847` | `/crossrootfs/arm64` | -clang9 | -| Alpine | arm64 (arm64v8) | `mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-arm64-alpine-406629a-20191023143847` | `/crossrootfs/arm64` | -clang5.0 | +| Ubuntu 16.04 | arm32(armhf) | `mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-20200413125008-09ec757` | `/crossrootfs/arm` | -clang9 | +| Ubuntu 16.04 | arm64 (arm64v8) | `mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-arm64-20200413125008-cfdd435` | `/crossrootfs/arm64` | -clang9 | +| Alpine | arm64 (arm64v8) | `mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-arm64-alpine-20200413125008-406629a` | `/crossrootfs/arm64` | -clang5.0 | Environment =========== @@ -69,47 +71,7 @@ Minimum RAM required to build is 1GB. The build is known to fail on 512 MB VMs ( Toolchain Setup --------------- -Add Kitware's APT feed to your configuration for a newer version of CMake. See their instructions at . - -Install the following packages for the toolchain: - -- cmake (at least 3.15.5) -- llvm-3.9 -- clang-9 -- libunwind8 -- libunwind8-dev -- gettext -- libicu-dev -- liblttng-ust-dev -- libcurl4-openssl-dev -- libssl-dev -- libkrb5-dev -- libnuma-dev (optional, enables numa support) - -Note: ARM clang has a known issue with CompareExchange -([#15074](https://github.com/dotnet/coreclr/issues/15074)), so for ARM you must -use clang-4.0 or higher. Moreover, when building with clang-5.0, the -following errors occur: - -``` -src/coreclr/src/debug/inc/arm/primitives.h:66:1: error: __declspec attribute 'selectany' is - not supported [-Werror,-Wignored-attributes] -``` - -This is fixed in clang-5.0.2, which can be installed from the apt -repository listed below. - -For other version of Debian/Ubuntu, please visit http://apt.llvm.org/. - -Then install the packages you need: - - ~$ sudo apt-get install cmake llvm-3.9 clang-9 libunwind8 libunwind8-dev gettext libicu-dev liblttng-ust-dev libcurl4-openssl-dev libssl-dev libnuma-dev libkrb5-dev - -You now have all the required components. - -If you are using Fedora, then you will need to install the following packages: - - ~$ sudo dnf install llvm cmake clang lldb-devel libunwind-devel lttng-ust-devel libicu-devel numactl-devel +Follow instructions and install dependencies listed [here](https://github.com/dotnet/runtime/blob/master/docs/workflow/requirements/linux-requirements.md#toolchain-setup). Git Setup --------- diff --git a/docs/workflow/building/coreclr/osx-instructions.md b/docs/workflow/building/coreclr/osx-instructions.md index ddcaeda8eb3c35..b8a168da5186de 100644 --- a/docs/workflow/building/coreclr/osx-instructions.md +++ b/docs/workflow/building/coreclr/osx-instructions.md @@ -23,9 +23,7 @@ git clone https://github.com/dotnet/runtime CMake ----- -CoreCLR has a dependency on CMake for the build. You can download it from [CMake downloads](http://www.cmake.org/download/). - -Alternatively, you can install CMake from [Homebrew](http://brew.sh/). +CoreCLR has a dependency on CMake for the build. You can install it with [Homebrew](https://brew.sh/). ```sh brew install cmake @@ -33,11 +31,10 @@ brew install cmake ICU --- -ICU (International Components for Unicode) is also required to build and run. It can be obtained via [Homebrew](http://brew.sh/). +ICU (International Components for Unicode) is also required to build and run. It can be obtained via [Homebrew](https://brew.sh/). ```sh brew install icu4c -brew link --force icu4c ``` Build the Runtime and System.Private.CoreLib diff --git a/docs/workflow/building/libraries/README.md b/docs/workflow/building/libraries/README.md index 620bd063b52d56..c64f34d7054704 100644 --- a/docs/workflow/building/libraries/README.md +++ b/docs/workflow/building/libraries/README.md @@ -74,7 +74,7 @@ The libraries build has two logical components, the native build which produces The build settings (BuildTargetFramework, TargetOS, Configuration, Architecture) are generally defaulted based on where you are building (i.e. which OS or which architecture) but we have a few shortcuts for the individual properties that can be passed to the build scripts: -- `-framework|-f` identifies the target framework for the build. Possible values include `netcoreapp5.0` (currently the latest .NET Core version) or `net472`. (msbuild property `BuildTargetFramework`) +- `-framework|-f` identifies the target framework for the build. Possible values include `net5.0` (currently the latest .NET version) or `net472`. (msbuild property `BuildTargetFramework`) - `-os` identifies the OS for the build. It defaults to the OS you are running on but possible values include `Windows_NT`, `Unix`, `Linux`, or `OSX`. (msbuild property `TargetOS`) - `-configuration|-c Debug|Release` controls the optimization level the compilers use for the build. It defaults to `Debug`. (msbuild property `Configuration`) - `-arch` identifies the architecture for the build. It defaults to `x64` but possible values include `x64`, `x86`, `arm`, or `arm64`. (msbuild property `TargetArchitecture`) @@ -98,7 +98,7 @@ By default the `build` script only builds the product libraries and none of the - Building for different target frameworks (restore and build are implicit again as no action is passed in) ```bash -./build.sh -subset libs -framework netcoreapp5.0 +./build.sh -subset libs -framework net5.0 ./build.sh -subset libs -framework net472 ``` @@ -205,6 +205,6 @@ If you are working on Windows, and use Visual Studio, you can open individual li ## Running tests -For more details about running tests inside Visual Studio, [go here](../../testing/libraries/testing.md#running-tests-from-visual-studio ) +For more details about running tests inside Visual Studio, [go here](../../testing/visualstudio.md). For more about running tests, read the [running tests](../../testing/libraries/testing.md) document. diff --git a/docs/workflow/building/libraries/code-coverage.md b/docs/workflow/building/libraries/code-coverage.md index 4d20d0e9fae353..d9ab38a2da9d5b 100644 --- a/docs/workflow/building/libraries/code-coverage.md +++ b/docs/workflow/building/libraries/code-coverage.md @@ -28,36 +28,30 @@ An issue need not be addressed in its entirety. We happily accept contributions You can perform code coverage runs for the entire repository locally by adding the `coverage` switch (assuming that source and test assemblies are already built): - build -test -coverage + build libs.tests -test -coverage This runs the tests and generates the full code coverage report. The resulting index.htm file providing the results of the run should be available at: artifacts\coverage\index.htm -You can also build and test with code coverage for a particular test project rather than for the whole repo with the ```/p:Coverage=true``` argument: +You can also build and test with code coverage for a particular test project rather than for the whole repo with the `/p:Coverage=true` property: dotnet build /t:Test /p:Coverage=true -The results for this one library will then show up in the aforementioned index.htm file. For example, to build, test, and get code coverage results for the System.Diagnostics.Debug library, from the root of the repo one can do: - - cd src\System.Diagnostics.Debug\tests\ - dotnet build /t:Test /p:Coverage=true - -And then once the run completes: +The results for this one library will then be available in this index.htm file, where $(OutDir) is the directory where the binaries were generated. $(OutDir)\report\index.htm -**Note:** If you only want to measure the coverage of your local changes (that haven't been pushed to git), run: +For example, to build, test, and get code coverage results for the System.Diagnostics.Debug library, from the root of the repo one can do: - dotnet build /t:Test /p:Coverage=true /p:CoverageSourceLink=false + dotnet build src\System.Diagnostics.Debug\tests /t:Test /p:Coverage=true +And then once the run completes: + + $(OutDir)\report\index.htm ## Code coverage with System.Private.CoreLib code -Some of the libraries for which contracts and tests live in the corefx repo are actually fully or partially implemented in the core runtime library in another repo, e.g. the implementation that backs the System.Runtime contract is in System.Private.CoreLib.dll in either the coreclr or corert repo. Test projects for code that lives, fully or partially, in System.Private.CoreLib, should have the property `TestRuntime` set to `true` in order to obtain proper code coverage reports. +Some of the libraries for which contracts and tests live in libraries are actually fully or partially implemented in the core runtime library, e.g. the implementation that backs the System.Runtime contract is in System.Private.CoreLib.dll. Test projects for code that lives, fully or partially, in System.Private.CoreLib, should have the property `TestRuntime` set to `true` in order to obtain proper code coverage reports. If the test project does not set the property `TestRuntime` to `true` and you want to collect code coverage that includes types in System.Private.CoreLib.dll add `/p:TestRuntime=true` to the coverage build command listed above. - -If you want to get coverage report against a private build of System.Private.CoreLib (// TODO //). - -The build and test projects take care of copying assemblies and PDBs as needed for coverage runs. The resulting code coverage report should now also include details for System.Private.CoreLib. diff --git a/docs/workflow/building/libraries/cross-building.md b/docs/workflow/building/libraries/cross-building.md index 2db7c5887b8392..c7b0fe1fda42f2 100644 --- a/docs/workflow/building/libraries/cross-building.md +++ b/docs/workflow/building/libraries/cross-building.md @@ -85,7 +85,7 @@ You can also build just managed code with: $ ./build.sh --arch arm /p:BuildNative=false -The output is at `artifacts/bin/[BuildSettings]` where `BuildSettings` looks something like `netcoreapp5.0--Debug-`. Ex: `artifacts/bin/netcoreapp5.0-Linux-Debug-x64`. For more details on the build configurations see [project-guidelines](/docs/coding-guidelines/project-guidelines.md) +The output is at `artifacts/bin/[BuildSettings]` where `BuildSettings` looks something like `net5.0--Debug-`. Ex: `artifacts/bin/net5.0-Linux-Debug-x64`. For more details on the build configurations see [project-guidelines](/docs/coding-guidelines/project-guidelines.md) Building corefx for Linux ARM Emulator ======================================= @@ -118,14 +118,14 @@ When building for a new architecture you will need to build the native pieces se Example building for armel ``` src/Native/build-native.sh armel ---> Output goes to artifacts/bin/runtime/netcoreapp5.0-Linux-Debug-armel +--> Output goes to artifacts/bin/runtime/net5.0-Linux-Debug-armel build /p:TargetArchitecture=x64 /p:BuildNative=false ---> Output goes to artifacts/bin/runtime/netcoreapp5.0-Linux-Debug-x64 +--> Output goes to artifacts/bin/runtime/net5.0-Linux-Debug-x64 ``` The reason you need to build the managed portion for x64 is because it depends on runtime packages for the new architecture which don't exist yet so we use another existing architecture such as x64 as a proxy for building the managed binaries. -Similar if you want to try and run tests you will have to copy the managed assemblies from the proxy directory (i.e. `netcoreapp5.0-Linux-Debug-x64`) to the new architecture directory (i.e `netcoreapp5.0-Linux-Debug-armel`) and run code via another host such as corerun because dotnet is at a higher level and most likely doesn't exist for the new architecture yet. +Similar if you want to try and run tests you will have to copy the managed assemblies from the proxy directory (i.e. `net5.0-Linux-Debug-x64`) to the new architecture directory (i.e `net5.0-Linux-Debug-armel`) and run code via another host such as corerun because dotnet is at a higher level and most likely doesn't exist for the new architecture yet. Once all the necessary builds are setup and packages are published the splitting of the build and manual creation of the runtime should no longer be necessary. diff --git a/docs/workflow/building/mono/README.md b/docs/workflow/building/mono/README.md index a7cfa158e03e07..276ae512cedabc 100644 --- a/docs/workflow/building/mono/README.md +++ b/docs/workflow/building/mono/README.md @@ -1,5 +1,15 @@ # Building Mono +## Build Requirements + +| Windows | Linux | macOS | FreeBSD | +| :------: | :------: | :------: | :------: | +| [Requirements](../../requirements/windows-requirements.md) | [Requirements](../../requirements/linux-requirements.md) | [Requirements](../../requirements/macos-requirements.md) | + +Before proceeding further, please click on the link above that matches your machine and ensure you have installed all the prerequisites for the build to work. + +## Concept + To build the Mono runtime, you must first do a complete runtime build (coreclr, libraries, and then mono). At the repo root, simply execute: ```bash diff --git a/docs/workflow/debugging/libraries/debugging-vscode.md b/docs/workflow/debugging/libraries/debugging-vscode.md index a27aa1dcbed577..4b82a4265811b8 100644 --- a/docs/workflow/debugging/libraries/debugging-vscode.md +++ b/docs/workflow/debugging/libraries/debugging-vscode.md @@ -5,7 +5,7 @@ - Open the folder containing the source you want to debug in VS Code - i.e., if you are debugging a test failure in System.Net.Sockets, open `runtime/src/libraries/System.Net.Sockets` - Open the debug window: `ctrl-shift-D` or click on the button on the left - Click the gear button at the top to create a launch configuration, select `.NET Core` from the selection dropdown -- In the `.NET Core Launch (console)` configuration do the following +- In the ".NET Core Launch (console)" `launch.json` configuration file make the following changes: - delete the `preLaunchTask` property - set `program` to the full path to `dotnet` in the artifacts/bin/testhost directory. - something like `artifacts/bin/testhost/netcoreapp-{OS}-{Configuration}-{Architecture}`, plus the full path to your dotnet/runtime directory. @@ -13,5 +13,5 @@ - using the System.Net.Sockets example, it should be something like `artifacts/bin/System.Net.Sockets.Tests/netcoreapp-{OS}-{Configuration}-{Architecture}`, plus the full path to your dotnet/runtime directory. - set `args` to the command line arguments to pass to the test - something like: `[ "exec", "--runtimeconfig", "{TestProjectName}.runtimeconfig.json", "xunit.console.dll", "{TestProjectName}.dll", "-notrait", ... ]`, where TestProjectName would be `System.Net.Sockets.Tests` - - to run a specific test, you can append something like: `[ "method", "System.Net.Sockets.Tests.{ClassName}.{TestMethodName}", ...]` + - to run a specific test, you can append something like: `[ "-method", "System.Net.Sockets.Tests.{ClassName}.{TestMethodName}", ...]` - Set a breakpoint and launch the debugger, inspecting variables and call stacks will now work diff --git a/docs/workflow/requirements/freebsd-requirements.md b/docs/workflow/requirements/freebsd-requirements.md new file mode 100644 index 00000000000000..59b3c64d928f15 --- /dev/null +++ b/docs/workflow/requirements/freebsd-requirements.md @@ -0,0 +1,69 @@ +Requirements to build dotnet/runtime on FreeBSD +===================== + +This guide will walk you through the requirements needed to build dotnet/runtime on FreeBSD. We'll start by showing how to set up your environment from scratch. +Since there is no official build and FreeBSD package, native build on FreeBSD is not trivial. There are generally three options, sorted by ease of use: +- cross-compile on Linux using Docker +- cross-compile on Linux using Toolchain +- build on FreeBSD + + +Environment +=========== + +These instructions were validated for and on FreeBSD 11.3 and 12.1. + +Build using Docker on Linux +--------------------------- + +This is similar to [Linux](linux-requirements.md) instructions. https://github.com/dotnet/dotnet-buildtools-prereqs-docker repro provides images +with all needed prerequisites to build. As the example bellow may become stale, https://github.com/dotnet/versions/blob/master/build-info/docker/image-info.dotnet-dotnet-buildtools-prereqs-docker-master.json offers list of latest Docker tags. + +```sh +TAG=mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-freebsd-11-20200430154008-a84b0d2 +docker run --rm --volume $(pwd):$(pwd) --workdir $(pwd) --env ROOTFS_DIR=/crossrootfs/x64 -ti $TAG ./build.sh -cross -FreeBSD +``` + +Build using Toolchain Setup +--------------------------- +To build FreeBSD images, prerequisites described in [Linux](linux-requirements.md) are needed. Additionally, crossrootfs for FreeBSD needs to be constructed. +In order to successfully build FreeBSD crossrootfs, few more packages needs to be installed. Following example is for Ubuntu 18: +```sh +apt-get install -y libbz2-dev libz-dev liblzma-dev libarchive-dev libbsd-dev +``` +With prerequisites for crossrootfs one can run: +```sh +./eng/common/cross/build-rootfs.sh freebsd11 $(pwd)/rootfs/freebsd +``` +After that, FreeBSD build can be started by running +``` +ROOTFS_DIR=$(pwd)/rootfs/freebsd ./build.sh -cross -os FreeBSD +``` + + +Building on FreeBSD +------------------- + +Building dotnet/runtime depends on several tools to be installed. + +Install the following packages: + +- cmake +- autoconf +- automake +- libtool +- icu +- libunwind +- lttng-ust +- krb5 +- openssl (optional) + +The lines to install all the packages above using package manager. + +```sh +sudo pkg install --yes libunwind icu libinotify lttng-ust krb5 cmake autoconf automake openssl +``` + +Additionally, working dotnet cli with SDK is needed. On other platforms this would be downloaded automatically during build but it is not currently available for FreeBSD. +It needs to be built once on supported platform or obtained via community resources. + diff --git a/docs/workflow/requirements/linux-requirements.md b/docs/workflow/requirements/linux-requirements.md index f7180dcf77e186..6f13897bc64556 100644 --- a/docs/workflow/requirements/linux-requirements.md +++ b/docs/workflow/requirements/linux-requirements.md @@ -86,9 +86,14 @@ Install the following packages for the toolchain: - libssl-dev - libkrb5-dev - libnuma-dev (optional, enables numa support) +- zlib1g-dev -A single line to install all packages above: +The following dependencies are needed if Mono Runtime is enabled (default behavior): - ~$ sudo apt-get install cmake llvm-9 clang-9 autoconf automake libtool build-essential python curl git lldb-6.0 liblldb-6.0-dev libunwind8 libunwind8-dev gettext libicu-dev liblttng-ust-dev libssl-dev libnuma-dev libkrb5-dev +- autoconf +- automake +- libtool + + ~$ sudo apt-get install cmake llvm-9 clang-9 autoconf automake libtool build-essential python curl git lldb-6.0 liblldb-6.0-dev libunwind8 libunwind8-dev gettext libicu-dev liblttng-ust-dev libssl-dev libnuma-dev libkrb5-dev zlib1g-dev autoconf automake libtool You now have all the required components. diff --git a/docs/workflow/requirements/macos-requirements.md b/docs/workflow/requirements/macos-requirements.md index 06d1fb01545d69..4604b87f60f85d 100644 --- a/docs/workflow/requirements/macos-requirements.md +++ b/docs/workflow/requirements/macos-requirements.md @@ -16,54 +16,21 @@ Install Apple Xcode developer tools from the Mac App Store ([link](https://apps. Toolchain Setup --------------- -Building dotnet/runtime depends on several tools to be installed. You can download them individually or use [Homebrew](http://brew.sh) for easier toolchain setup. +Building dotnet/runtime depends on several tools to be installed. You can download them individually or use [Homebrew](https://brew.sh) for easier toolchain setup. Install the following packages: - cmake 3.15.5 or newer - autoconf - automake +- icu4c - libtool +- openssl 1.1 - pkg-config - python3 -- icu4c -The lines to install all the packages above using Homebrew. +You can install all the packages above using Homebrew by running this command in the repository root: ``` -brew install cmake autoconf automake libtool pkg-config python3 icu4c -brew link --force icu4c -``` - -OpenSSL -------- - -To build the libraries on macOS, you must install and configure links for OpenSSL 1.1. - -```sh -brew install openssl - -# You might need to "link" pkg-config: -brew link pkg-config - -# We need to make the runtime libraries discoverable, as well as make -# pkg-config be able to find the headers and current ABI version. -# -# Ensure the paths we will need exist -mkdir -p /usr/local/lib/pkgconfig - -# The rest of these instructions assume a default Homebrew path of -# `/usr/local/opt/`, with `brew --prefix` returning `/usr/local` -# and `brew --prefix openssl` returning `/usr/local/opt/openssl@1.1`. -# In this case, `brew info openssl` shows: -# `openssl@1.1: stable 1.1.1d (bottled) [keg-only]`. - -# Runtime dependencies -ln -s /usr/local/opt/openssl\@1.1/lib/libcrypto.1.1.dylib /usr/local/lib/ -ln -s /usr/local/opt/openssl\@1.1/lib/libssl.1.1.dylib /usr/local/lib/ - -# Compile-time dependencies (for pkg-config) -ln -s /usr/local/opt/openssl\@1.1/lib/pkgconfig/libcrypto.pc /usr/local/lib/pkgconfig/ -ln -s /usr/local/opt/openssl\@1.1/lib/pkgconfig/libssl.pc /usr/local/lib/pkgconfig/ -ln -s /usr/local/opt/openssl\@1.1/lib/pkgconfig/openssl.pc /usr/local/lib/pkgconfig/ +brew bundle --no-lock --file eng/Brewfile ``` diff --git a/docs/workflow/requirements/windows-requirements.md b/docs/workflow/requirements/windows-requirements.md index 51fdbe28943b03..5753ccf266a938 100644 --- a/docs/workflow/requirements/windows-requirements.md +++ b/docs/workflow/requirements/windows-requirements.md @@ -26,19 +26,19 @@ Visual Studio 2019 installation process: - .NET Desktop Development with all default components. - Desktop Development with C++ with all default components. - To build for Arm32 or Arm64, make sure that you have the right architecture specific compilers installed: - - In addition, ensure you install the ARM tools. In the "Individual components" window, in the "Compilers, build tools, and runtimes" section, check the box for "MSVC v142 - VS 2019 C++ ARM build tools (v14.23)". - - Also, ensure you install the ARM64 tools. In the "Individual components" window, in the "Compilers, build tools, and runtimes" section, check the box for "MSVC v142 - VS 2019 C++ ARM64 build tools (v14.23)". + - In addition, ensure you install the ARM tools. In the "Individual components" window, in the "Compilers, build tools, and runtimes" section, check the box for "MSVC v142 - VS 2019 C++ ARM build tools" (v14.23 or newer). + - Also, ensure you install the ARM64 tools. In the "Individual components" window, in the "Compilers, build tools, and runtimes" section, check the box for "MSVC v142 - VS 2019 C++ ARM64 build tools (v14.23 or newer)". - To build the tests, you will need some additional components: - Windows 10 SDK component version 10.0.18362 or newer. This component is installed by default as a part of 'Desktop Development with C++' workload. - - C++/CLI support for v142 build tools (14.23) + - C++/CLI support for v142 build tools (v14.23 or newer) A `.vsconfig` file is included in the root of the dotnet/runtime repository that includes all components needed to build the dotnet/runtime repository. You can [import `.vsconfig` in your Visual Studio installer](https://docs.microsoft.com/en-us/visualstudio/install/import-export-installation-configurations?view=vs-2019#import-a-configuration) to install all necessary components. -The dotnet/runtime repository requires at least Visual Studio 2019 16.3. +The dotnet/runtime repository requires at least Visual Studio 2019 16.6 Preview 2. ## CMake -- Install [CMake](http://www.cmake.org/download) for Windows. +- Install [CMake](https://cmake.org/download) for Windows. - Add its location (e.g. C:\Program Files (x86)\CMake\bin) to the PATH environment variable. The installation script has a check box to do this, but you can do it yourself after the fact following the instructions at [Adding to the Default PATH variable](#adding-to-the-default-path-variable). @@ -67,9 +67,17 @@ The dotnet/runtime repository requires at least Git 2.22.0. ## .NET SDK -While not strictly needed to build or test this repository, having the .NET SDK installed lets you use the dotnet.exe command to run .NET applications in the 'normal' way. +While not strictly needed to build or test this repository, having the .NET SDK installed lets you browse solution files in this repository with Visual Studio and use the dotnet.exe command to run .NET applications in the 'normal' way. We use this in the [Using Your Build](../testing/using-your-build.md) instructions. -Visual Studio should have installed the .NET SDK, but in case it did not you can get it from the [Installing the .NET SDK](https://dotnet.microsoft.com/download) page. +The minimum required version of the SDK is specified in the [global.json file](https://github.com/dotnet/runtime/blob/master/global.json#L3). [You can find the installers and binaries for nightly builds of .NET SDK here](https://github.com/dotnet/installer#installers-and-binaries). + +Alternatively, to avoid modifying your machine state, you can use the repository's locally acquired SDK by passing in the solution to load via the `-vs` switch: + +``` +build.cmd -vs System.Text.RegularExpressions +``` + +This will set the `DOTNET_ROOT` and `PATH` environment variables to point to the locally acquired SDK under `runtime\.dotnet\` and will launch the Visual Studio instance which is registered for the `sln` extension. ## Adding to the default PATH variable diff --git a/docs/workflow/testing/libraries/testing-android.md b/docs/workflow/testing/libraries/testing-android.md new file mode 100644 index 00000000000000..7ac22f84062fa5 --- /dev/null +++ b/docs/workflow/testing/libraries/testing-android.md @@ -0,0 +1,91 @@ +# Testing Libraries on Android + +The following dependencies should be installed in order to be able to run tests: + +- Android NDK +- Android SDK +- OpenJDK +- OpenSSL + +OpenJDK can be installed on Linux (Ubuntu) using `apt-get`: +```bash +sudo apt-get install openjdk-8 unzip +``` + +Android SDK, NDK and OpenSSL can be automatically installed via the following script: +```bash +#!/usr/bin/env bash +set -e + +NDK_VER=r21b +SDK_VER=6200805_latest +SDK_API_LEVEL=29 +SDK_BUILD_TOOLS=29.0.3 +OPENSSL_VER=1.1.1g-alpha-1 + +if [[ "$OSTYPE" == "darwin"* ]]; then + HOST_OS=darwin + HOST_OS_SHORT=mac + BASHRC=~/.zprofile +else + HOST_OS=linux + HOST_OS_SHORT=linux + BASHRC=~/.bashrc +fi + +# download Android NDK +export ANDROID_NDK_ROOT=~/android-ndk-${NDK_VER} +curl https://dl.google.com/android/repository/android-ndk-${NDK_VER}-${HOST_OS}-x86_64.zip -L --output ~/andk.zip +unzip ~/andk.zip -d $(dirname ${ANDROID_NDK_ROOT}) && rm -rf ~/andk.zip + +# download Android SDK, accept licenses and download additional packages such as +# platform-tools, platforms and build-tools +export ANDROID_SDK_ROOT=~/android-sdk +curl https://dl.google.com/android/repository/commandlinetools-${HOST_OS_SHORT}-${SDK_VER}.zip -L --output ~/asdk.zip +unzip ~/asdk.zip -d ${ANDROID_SDK_ROOT} && rm -rf ~/asdk.zip +yes | ${ANDROID_SDK_ROOT}/tools/bin/./sdkmanager --sdk_root=${ANDROID_SDK_ROOT} --licenses +${ANDROID_SDK_ROOT}/tools/bin/./sdkmanager --sdk_root=${ANDROID_SDK_ROOT} "platform-tools" "platforms;android-${SDK_API_LEVEL}" "build-tools;${SDK_BUILD_TOOLS}" + +# We also need to download precompiled binaries and headers for OpenSSL from maven, this step is a temporary hack +# and will be removed once we figure out how to integrate OpenSSL properly as a dependency +export ANDROID_OPENSSL_AAR=~/openssl-android +curl https://maven.google.com/com/android/ndk/thirdparty/openssl/${OPENSSL_VER}/openssl-${OPENSSL_VER}.aar -L --output ~/openssl.zip +unzip ~/openssl.zip -d ${ANDROID_OPENSSL_AAR} && rm -rf ~/openssl.zip +printf "\n\nexport ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}\nexport ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT}\nexport ANDROID_OPENSSL_AAR=${ANDROID_OPENSSL_AAR}\n" >> ${BASHRC} +``` +Save it to a file (e.g. `deps.sh`) and execute using `source` (e.g. `chmod +x deps.sh && source ./deps.sh`) in order to propogate the `ANDROID_NDK_ROOT`, `ANDROID_SDK_ROOT` and `ANDROID_OPENSSL_AAR` environment variables to the current process. + +## Building Libs and Tests for Android + +Now we're ready to build everything for Android: +``` +./build.sh mono+libs -os Android -arch x64 +``` +and even run tests one by one for each library: +``` +./build.sh libs.tests -os Android -arch x64 -test +``` +Make sure an emulator is booted (see `AVD Manager`) or a device is plugged in and unlocked. +`AVD Manager` tool recommends to install `x86` images by default so if you follow that recommendation make sure `-arch x86` was used for the build script. + +### Running individual test suites +The following shows how to run tests for a specific library +``` +./dotnet.sh build /t:Test src/libraries/System.Numerics.Vectors/tests /p:TargetOS=Android /p:TargetArchitecture=x64 +``` + +### Test App Design +Android app is basically a [Java Instrumentation](https://github.com/dotnet/runtime/blob/master/src/mono/msbuild/AndroidAppBuilder/Templates/MonoRunner.java) and a simple Activity that inits the Mono Runtime via JNI. This Mono Runtime starts a simple xunit test +runner called XHarness.TestRunner (see https://github.com/dotnet/xharness) which runs tests for all `*.Tests.dll` libs in the bundle. There is also XHarness.CLI tool with ADB embedded to deploy `*.apk` to a target (device or emulator) and obtain logs once tests are completed. + +### Obtaining the logs +XHarness for Android doesn't talk much and only saves test results to a file. However, you can also subscribe to live logs via the following command: +``` +adb logcat -s "DOTNET" +``` +Or simply open `logcat` window in Android Studio or Visual Stuido. + +### Existing Limitations +- `-os Android` is not supported for Windows yet (`WSL` can be used instead) +- XHarness.CLI is not able to boot emulators yet (so you need to boot via `AVD Manager` or IDE) +- AOT and Interpreter modes are not supported yet \ No newline at end of file diff --git a/docs/workflow/testing/libraries/testing-apple.md b/docs/workflow/testing/libraries/testing-apple.md new file mode 100644 index 00000000000000..3f99570042065b --- /dev/null +++ b/docs/workflow/testing/libraries/testing-apple.md @@ -0,0 +1,32 @@ +# Testing Libraries on iOS and tvOS + +In order to build libraries and tests for iOS or tvOS you need recent version of XCode installed (e.g. 11.3 or higher). + +Build Libraries for iOS: +``` +./build.sh mono+libs -os iOS -arch x64 +``` +Run tests one by one for each test suite on a simulator: +``` +./build.sh libs.tests -os iOS -arch x64 -test +``` +In order to run the tests on a device you need to specify `DevTeamProvisioning` (see [developer.apple.com/account/#/membership](https://developer.apple.com/account/#/membership), scroll down to `Team ID`): +``` +./build.sh libs.tests -os iOS -arch x64 -test /p:DevTeamProvisioning=H1A2B3C4D5 +``` +[AppleAppBuilder](https://github.com/dotnet/runtime/blob/master/src/mono/msbuild/AppleAppBuilder/AppleAppBuilder.cs) generates temp Xcode projects you can manually open and resolve provisioning issues there using native UI and deploy to your devices. + +### Running individual test suites +- The following shows how to run tests for a specific library: +``` +./dotnet.sh build src/libraries/System.Numerics.Vectors/tests /t:Test /p:TargetOS=iOS /p:TargetArchitecture=x64 +``` + +### Test App Design +iOS/tvOS `*.app` (or `*.ipa`) is basically a simple [ObjC app](https://github.com/dotnet/runtime/blob/master/src/mono/msbuild/AppleAppBuilder/Templates/main-console.m) that inits the Mono Runtime. This Mono Runtime starts a simple xunit test +runner called XHarness.TestRunner (see https://github.com/dotnet/xharness) which runs tests for all `*.Tests.dll` libs in the bundle. There is also XHarness.CLI tool to deploy `*.app` and `*.ipa` to a target (device or simulator) and listens for logs via network sockets. + +### Existing Limitations +- Most of the test suites crash on devices due to #35674 +- Simulator uses JIT mode only at the moment (to be extended with FullAOT and Interpreter) +- Interpreter is not enabled yet. diff --git a/docs/workflow/testing/libraries/testing.md b/docs/workflow/testing/libraries/testing.md index a221d849330c64..9ab30e12be41ad 100644 --- a/docs/workflow/testing/libraries/testing.md +++ b/docs/workflow/testing/libraries/testing.md @@ -12,18 +12,18 @@ build.cmd/sh -subset libs.tests - The following builds and runs all tests in release configuration: ``` -build.cmd/sh -subset libs -test -c Release +build.cmd/sh -subset libs.tests -test -c Release ``` - The following example shows how to pass extra msbuild properties to ignore tests ignored in CI: ``` -build.cmd/sh -subset libs -test /p:WithoutCategories=IgnoreForCI +build.cmd/sh -subset libs.tests -test /p:WithoutCategories=IgnoreForCI ``` Unless you specifiy `-testnobuild`, test assemblies are implicitly built when invoking the `Test` action. - The following shows how to only test the libraries without building them ``` -build.cmd/sh -subset libs -test -testnobuild +build.cmd/sh -subset libs.tests -test -testnobuild ``` ## Running tests on the command line @@ -38,7 +38,7 @@ dotnet build /t:Test It is possible to pass parameters to the underlying xunit runner via the `XUnitOptions` parameter, e.g.: ```cmd -dotnet build /t:Test "/p:XUnitOptions=-class Test.ClassUnderTests" +dotnet build /t:Test /p:XUnitOptions="-class Test.ClassUnderTests" ``` There may be multiple projects in some directories so you may need to specify the path to a specific test project to get it to build and run the tests. @@ -59,17 +59,7 @@ dotnet build /t:Test /p:Outerloop=true #### Running tests on a different target framework -Each test project can potentially have multiple target frameworks. There are some tests that might be OS-specific, or might be testing an API that is available only on some target frameworks, so the `TargetFrameworks` property specifies the valid target frameworks. By default we will build and run only the default build target framework which is `netcoreapp5.0`. The rest of the `TargetFrameworks` will need to be built and ran by specifying the `BuildTargetFramework` option, e.g.: +Each test project can potentially have multiple target frameworks. There are some tests that might be OS-specific, or might be testing an API that is available only on some target frameworks, so the `TargetFrameworks` property specifies the valid target frameworks. By default we will build and run only the default build target framework which is `net5.0`. The rest of the `TargetFrameworks` will need to be built and ran by specifying the `BuildTargetFramework` option, e.g.: ```cmd dotnet build src\libraries\System.Runtime\tests\System.Runtime.Tests.csproj /p:BuildTargetFramework=net472 ``` - -## Running tests from Visual Studio - -**Test Explorer** will be able to discover the tests only if the solution is opened with `build -vs` command, e.g.: -```cmd -build -vs System.Net.Http -``` -If running the tests from **Test Explorer** does nothing, it probably tries to use x86 dotnet installation instead of the x64 one. It can be fixed by setting the x64 architecture manually in the test settings. - -It is also possible to execute the tests by simply debugging the test project once it's been built. It will underneath call the same command as `dotnet build /t:Test` does. diff --git a/docs/workflow/testing/visualstudio.md b/docs/workflow/testing/visualstudio.md new file mode 100644 index 00000000000000..c8c20b9cfc7fa3 --- /dev/null +++ b/docs/workflow/testing/visualstudio.md @@ -0,0 +1,16 @@ +# Visual Studio Test Explorer support +For Visual Studio Test Explorer to work in dotnet/runtime, the following test settings need to be enabled: +- Test parameters (like which `dotnet` host to use) are persisted in an auto-generated .runsettings file. For that to work, make sure that the "Auto detect runsettings Files" (`Options -> Test`) option is enabled. +- Make sure that the "Processor Architecture for AnyCPU project" (`Test Explore pane -> Test Explorer toolbar options --> Settings`) value is set to `auto`. + +# Visual Studio F5 Debugging support +dotnet/runtime uses `dotnet test` ([VSTest](https://github.com/Microsoft/vstest)) which spawns child processes during test execution. +Visual Studio by default doesn't automatically debug child processes, therefore preliminary steps need to be done to enable Debugging "F5" support. +Note that these steps aren't necessary for Visual Studio Test Explorer support. +1. Install the [Microsoft Child Process Debugging Power Tool](https://marketplace.visualstudio.com/items?itemName=vsdbgplat.MicrosoftChildProcessDebuggingPowerTool) extension. +2. Go to the child process debug settings (`Debug -> Other Debug Targets -> Child Process Debugging Settings...`), enable the "Enable child process debugging" option and hit save. +3. Go to the project debug settings (`Debug -> $ProjectName Properties`) and enable the "Enable native code debugging" option. + +## References +- https://github.com/dotnet/project-system/issues/6176 tracks enabling the native code debugging functionality for multiple projects without user interaction. +- https://github.com/dotnet/sdk/issues/7419#issuecomment-298261617 explains the necessary steps to install and enable the mentioned extension in more detail. diff --git a/eng/Analyzers.props b/eng/Analyzers.props index 8d2cb20609f2b8..4ed7e3cb9a96d0 100644 --- a/eng/Analyzers.props +++ b/eng/Analyzers.props @@ -6,7 +6,7 @@ - + diff --git a/eng/BeforeTargetFrameworkInference.targets b/eng/BeforeTargetFrameworkInference.targets new file mode 100644 index 00000000000000..92adb5df635380 --- /dev/null +++ b/eng/BeforeTargetFrameworkInference.targets @@ -0,0 +1,23 @@ + + + + <_OriginalTargetFramework>$(TargetFramework) + $(TargetFramework.SubString($([MSBuild]::Add($(TargetFramework.IndexOf('-')), 1)))) + $(TargetFramework.SubString(0, $(TargetFramework.IndexOf('-')))) + + + + $([MSBuild]::NormalizeDirectory('$(RefRootPath)', '$(TargetFramework)')) + + + + + + $([MSBuild]::NormalizeDirectory('$(BaseIntermediateOutputPath)', '$(TargetFramework)-$(TargetFrameworkSuffix)-$(Configuration)')) + $([MSBuild]::NormalizeDirectory('$(BaseIntermediateOutputPath)', '$(TargetFramework)-$(Configuration)')) + + $([MSBuild]::NormalizeDirectory('$(BaseOutputPath)', '$(TargetFramework)-$(TargetFrameworkSuffix)-$(Configuration)')) + $([MSBuild]::NormalizeDirectory('$(BaseOutputPath)', '$(TargetFramework)-$(Configuration)')) + + + diff --git a/eng/Brewfile b/eng/Brewfile new file mode 100644 index 00000000000000..40252a15f30489 --- /dev/null +++ b/eng/Brewfile @@ -0,0 +1,8 @@ +brew "autoconf" +brew "automake" +brew "cmake" +brew "icu4c" +brew "libtool" +brew "openssl@1.1" +brew "pkg-config" +brew "python3" diff --git a/eng/CodeAnalysis.ruleset b/eng/CodeAnalysis.ruleset index cf97025667a2bd..66a6af943a1ef7 100644 --- a/eng/CodeAnalysis.ruleset +++ b/eng/CodeAnalysis.ruleset @@ -4,7 +4,7 @@ - + @@ -106,7 +106,7 @@ - + @@ -210,6 +210,7 @@ + diff --git a/eng/Configurations.props b/eng/Configurations.props index b4417f2205ee70..06ee77bbe8d173 100644 --- a/eng/Configurations.props +++ b/eng/Configurations.props @@ -13,14 +13,23 @@ $([MSBuild]::NormalizeDirectory('$(RepoToolsLocalDir)', 'tasks')) $([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'ibc')) $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'docs')) - $([MSBuild]::NormalizePath('$(ArtifactsDir)', 'tmp', '$(Configuration)', 'RuntimeOS.props')) - 5.0 - .NETCoreApp,Version=v$(NETCoreAppCurrentVersion) - netcoreapp$(NETCoreAppCurrentVersion) + + 5.0 + .NETCoreApp + $(NetCoreAppCurrentIdentifier),Version=v$(NetCoreAppCurrentVersion) + net$(NetCoreAppCurrentVersion) + + $(NetCoreAppCurrent) + Microsoft.NETCore.App + .NET $(NetCoreAppCurrentVersion) + net472 @@ -37,9 +46,13 @@ + $([System.Runtime.InteropServices.RuntimeInformation]::RuntimeIdentifier) + win-$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLowerInvariant) + OSX FreeBSD NetBSD + SunOS Linux Windows_NT $(TargetOS) @@ -47,6 +60,10 @@ $(TargetOS) + + true + + true diff --git a/eng/DiaSymReaderNative.targets b/eng/DiaSymReaderNative.targets new file mode 100644 index 00000000000000..5836a781dfa8f6 --- /dev/null +++ b/eng/DiaSymReaderNative.targets @@ -0,0 +1,35 @@ + + + + + + AnyCPU + + + + + + PreserveNewest + false + false + + + PreserveNewest + false + false + + + + + \ No newline at end of file diff --git a/eng/SignCheckExclusionsFile.txt b/eng/SignCheckExclusionsFile.txt index 2db3b79a9339ec..dc77ca3e4603ca 100644 --- a/eng/SignCheckExclusionsFile.txt +++ b/eng/SignCheckExclusionsFile.txt @@ -7,6 +7,9 @@ ;; and SCD apps. If they are signed, the file that the SDK produces has an invalid signature and ;; can't be signed again. More info at https://github.com/dotnet/core-setup/pull/7549. *apphost.exe;;Template, https://github.com/dotnet/core-setup/pull/7549 +*singlefilehost.exe;;Template, https://github.com/dotnet/core-setup/pull/7549 *comhost.dll;;Template, https://github.com/dotnet/core-setup/pull/7549 *apphosttemplateapphostexe.exe;;Template, https://github.com/dotnet/core-setup/pull/7549 *comhosttemplatecomhostdll.dll;;Template, https://github.com/dotnet/core-setup/pull/7549 +*staticapphosttemplateapphostexe.exe;;Template, https://github.com/dotnet/core-setup/pull/7549 +*dotnet.js;;Workaround, https://github.com/dotnet/core-eng/issues/9933 diff --git a/eng/Signing.props b/eng/Signing.props index 05f2a8bcb39570..463c3602bb7f94 100644 --- a/eng/Signing.props +++ b/eng/Signing.props @@ -24,7 +24,7 @@ - + @@ -71,7 +71,6 @@ - diff --git a/eng/SubsetValidation.targets b/eng/SubsetValidation.targets index 53ea39ccd4959c..3b0acd5c5e1564 100644 --- a/eng/SubsetValidation.targets +++ b/eng/SubsetValidation.targets @@ -6,7 +6,7 @@ on a whole subset, and the dependency on the subset is disregarded automatically when Subset doesn't contain it. - %(InstallerProject.SignPhase): Indicates this project must be built before a certain signing + %(ProjectToBuild.SignPhase): Indicates this project must be built before a certain signing phase. Projects can depend on 'signing/stages/Sign.proj' to wait until all projects that are part of a stage are complete. This allows the build to perform complex container signing that isn't (can't be?) supported by Arcade's single pass, such as MSIs and bundles: diff --git a/eng/Subsets.props b/eng/Subsets.props index d33944f97ddbdb..f7c472357e68c5 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -13,7 +13,7 @@ ./build.sh corehost installer.managed - This builds the CoreHost and also the Managed installer portion (e.g. Microsoft.DotNet.PlatformAbstractions) + This builds the CoreHost and also the Managed installer portion (e.g. Microsoft.NET.HostModel) projects. A space ' ' or '+' are the delimiters between multiple subsets to build. ./build.sh -test installer.tests @@ -38,12 +38,23 @@ clr+mono+libs+installer - mono+libs+installer - mono+libs + mono+libs+installer + - clr.runtime+linuxdac+clr.corelib+clr.nativecorelib+clr.tools+clr.buildtools+clr.packages + <_subset Condition="'$(Subset)' != ''">+$(Subset.ToLowerInvariant())+ + <_subset Condition="'$(Subset)' == ''">+$(DefaultSubsets)+ + + + + Mono + Mono + CoreCLR + + + + clr.runtime+linuxdac+clr.corelib+clr.nativecorelib+clr.tools+clr.packages mono.llvm+ $(DefaultMonoSubsets)mono.runtime+mono.corelib @@ -51,12 +62,10 @@ libs.depprojs+libs.native+libs.ref+libs.src+libs.pretest+libs.packages corehost+installer.managed+installer.depprojs+installer.pkgprojs+bundles+installers+installer.tests - installer.depprojs+installer.pkgprojs + installer.pkgprojs - <_subset Condition="'$(Subset)' != ''">+$(Subset.ToLowerInvariant())+ - <_subset Condition="'$(Subset)' == ''">+$(DefaultSubsets)+ <_subset>$(_subset.Replace('+clr+', '+$(DefaultCoreClrSubsets)+')) <_subset>$(_subset.Replace('+mono+', '+$(DefaultMonoSubsets)+')) <_subset>$(_subset.Replace('+libs+', '+$(DefaultLibrariesSubsets)+')) @@ -66,12 +75,6 @@ <_subset>+$(_subset.Trim('+'))+ - - Mono - Mono - CoreCLR - - @@ -81,7 +84,6 @@ - @@ -102,7 +104,7 @@ - + @@ -113,82 +115,58 @@ - + false false false false - Configuration=$(CoreCLRConfiguration) - - - false - false - false - false - Configuration=$(MonoConfiguration) - - - false - false - false - false - Configuration=$(LibrariesConfiguration) - - - false - true - false - + - - - - - + - + - + - + - + - - - - - + + - + - - + + - + - + @@ -199,65 +177,65 @@ - + - + - + - + - + - + - + - + - - + + - - + + - + - + @@ -267,11 +245,20 @@ - + - + + + + + + + Configuration=$(CoreCLRConfiguration) + Configuration=$(MonoConfiguration) + Configuration=$(LibrariesConfiguration) + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7b7ecd8507195a..0e5212ef380e4f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -6,61 +6,61 @@ - + https://github.com/dotnet/arcade - bce0a98620c1c5a110b2bba9912f3d5929069c6b + 898e51ed5fdcc4871087ac5754ca9056e58e575d - + https://github.com/dotnet/arcade - bce0a98620c1c5a110b2bba9912f3d5929069c6b + 898e51ed5fdcc4871087ac5754ca9056e58e575d - + https://github.com/dotnet/arcade - bce0a98620c1c5a110b2bba9912f3d5929069c6b + 898e51ed5fdcc4871087ac5754ca9056e58e575d - + https://github.com/dotnet/arcade - bce0a98620c1c5a110b2bba9912f3d5929069c6b + 898e51ed5fdcc4871087ac5754ca9056e58e575d - + https://github.com/dotnet/arcade - bce0a98620c1c5a110b2bba9912f3d5929069c6b + 898e51ed5fdcc4871087ac5754ca9056e58e575d - + https://github.com/dotnet/arcade - bce0a98620c1c5a110b2bba9912f3d5929069c6b + 898e51ed5fdcc4871087ac5754ca9056e58e575d - + https://github.com/dotnet/arcade - bce0a98620c1c5a110b2bba9912f3d5929069c6b + 898e51ed5fdcc4871087ac5754ca9056e58e575d - + https://github.com/dotnet/arcade - bce0a98620c1c5a110b2bba9912f3d5929069c6b + 898e51ed5fdcc4871087ac5754ca9056e58e575d - + https://github.com/dotnet/arcade - bce0a98620c1c5a110b2bba9912f3d5929069c6b + 898e51ed5fdcc4871087ac5754ca9056e58e575d - + https://github.com/dotnet/arcade - bce0a98620c1c5a110b2bba9912f3d5929069c6b + 898e51ed5fdcc4871087ac5754ca9056e58e575d - + https://github.com/dotnet/arcade - bce0a98620c1c5a110b2bba9912f3d5929069c6b + 898e51ed5fdcc4871087ac5754ca9056e58e575d - + https://github.com/dotnet/arcade - bce0a98620c1c5a110b2bba9912f3d5929069c6b + 898e51ed5fdcc4871087ac5754ca9056e58e575d - + https://github.com/dotnet/arcade - bce0a98620c1c5a110b2bba9912f3d5929069c6b + 898e51ed5fdcc4871087ac5754ca9056e58e575d - + https://github.com/dotnet/arcade - bce0a98620c1c5a110b2bba9912f3d5929069c6b + 898e51ed5fdcc4871087ac5754ca9056e58e575d https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -82,65 +82,65 @@ https://dev.azure.com/dnceng/internal/_git/dotnet-optimization d0bb63d2ec7060714e63ee4082fac48f2e57f3e2 - + https://github.com/microsoft/vstest - 732a3a37e8d3e1a2522546fca644c7d69be457cf + 8ee627ea54aba31b941e5d45a1a1614b50f7befb - + https://github.com/dotnet/runtime-assets - 3e5b67e9033c00da5e1ce539c0186cbf171b6ce4 + 71b9284907ebc69e5f80b491a51084c75e0ef7d3 - + https://github.com/dotnet/runtime-assets - 3e5b67e9033c00da5e1ce539c0186cbf171b6ce4 + 71b9284907ebc69e5f80b491a51084c75e0ef7d3 - + https://github.com/dotnet/runtime-assets - 3e5b67e9033c00da5e1ce539c0186cbf171b6ce4 + 71b9284907ebc69e5f80b491a51084c75e0ef7d3 - + https://github.com/dotnet/runtime-assets - 3e5b67e9033c00da5e1ce539c0186cbf171b6ce4 + 71b9284907ebc69e5f80b491a51084c75e0ef7d3 - + https://github.com/dotnet/runtime-assets - 3e5b67e9033c00da5e1ce539c0186cbf171b6ce4 + 71b9284907ebc69e5f80b491a51084c75e0ef7d3 - + https://github.com/dotnet/runtime-assets - 3e5b67e9033c00da5e1ce539c0186cbf171b6ce4 + 71b9284907ebc69e5f80b491a51084c75e0ef7d3 - + https://github.com/dotnet/runtime-assets - 3e5b67e9033c00da5e1ce539c0186cbf171b6ce4 + 71b9284907ebc69e5f80b491a51084c75e0ef7d3 - + https://github.com/dotnet/runtime-assets - 3e5b67e9033c00da5e1ce539c0186cbf171b6ce4 + 71b9284907ebc69e5f80b491a51084c75e0ef7d3 - + https://github.com/dotnet/llvm-project - f29b04491741ba1e4c7aa4f0fa039512aad2028f + d179d1b519fb0b3e4a4b3f15ee55920e310c582f - + https://github.com/dotnet/llvm-project - f29b04491741ba1e4c7aa4f0fa039512aad2028f + d179d1b519fb0b3e4a4b3f15ee55920e310c582f - + https://github.com/dotnet/llvm-project - f29b04491741ba1e4c7aa4f0fa039512aad2028f + d179d1b519fb0b3e4a4b3f15ee55920e310c582f - + https://github.com/dotnet/llvm-project - f29b04491741ba1e4c7aa4f0fa039512aad2028f + d179d1b519fb0b3e4a4b3f15ee55920e310c582f - + https://github.com/dotnet/llvm-project - f29b04491741ba1e4c7aa4f0fa039512aad2028f + d179d1b519fb0b3e4a4b3f15ee55920e310c582f - + https://github.com/dotnet/llvm-project - f29b04491741ba1e4c7aa4f0fa039512aad2028f + d179d1b519fb0b3e4a4b3f15ee55920e310c582f https://github.com/dotnet/runtime @@ -166,9 +166,17 @@ https://github.com/dotnet/runtime 0375524a91a47ca4db3ee1be548f74bab7e26e76 - + + https://github.com/dotnet/runtime + 0375524a91a47ca4db3ee1be548f74bab7e26e76 + + https://github.com/mono/linker - 8caef57d1f3bc7a188e5dd26d43a2d34151223f9 + 3481158940a2b7f1114950cc7ba5bd56e0bfc761 + + + https://github.com/dotnet/xharness + 8f6cc04f53cb6759758ffc97c9c8ca3ab4802f7f diff --git a/eng/Versions.props b/eng/Versions.props index 948bdc32af6337..586f105dc54668 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -7,7 +7,7 @@ 0 0 preview - 4 + 6 $(MajorVersion).$(MinorVersion).0.0 @@ -18,15 +18,9 @@ true true false - - 3.6.0-2.20166.2 dotnet $(ContainerName) - - $(MajorVersion).$(MinorVersion) - $(MajorVersion).$(MinorVersion) - netcoreapp$(NETCoreAppFrameworkVersion) - 5.0.0-beta.20201.2 - 5.0.0-beta.20201.2 - 5.0.0-beta.20201.2 - 5.0.0-beta.20201.2 - 5.0.0-beta.20201.2 - 5.0.0-beta.20201.2 - 5.0.0-beta.20201.2 - 2.5.1-beta.20201.2 - 5.0.0-beta.20201.2 - 5.0.0-beta.20201.2 - 5.0.0-beta.20201.2 + 5.0.0-beta.20261.9 + 5.0.0-beta.20261.9 + 5.0.0-beta.20261.9 + 5.0.0-beta.20261.9 + 5.0.0-beta.20261.9 + 5.0.0-beta.20261.9 + 2.5.1-beta.20264.3 + 5.0.0-beta.20261.9 + 5.0.0-beta.20261.9 + 5.0.0-beta.20261.9 5.0.0-preview.4.20202.18 5.0.0-preview.4.20202.18 5.0.0-preview.4.20202.18 - 2.1.0 - 3.0.0 + 3.1.0 5.0.0-preview.4.20202.18 5.0.0-preview.4.20202.18 - 1.0.120601 + 5.0.0-preview.4.20202.18 5.0.0-alpha.1.19563.3 - 5.0.0-beta.20206.1 - 5.0.0-beta.20206.1 - 5.0.0-beta.20206.1 - 5.0.0-beta.20206.1 - 5.0.0-beta.20206.1 - 5.0.0-beta.20206.1 - 5.0.0-beta.20206.1 - 5.0.0-beta.20206.1 + 5.0.0-beta.20258.1 + 5.0.0-beta.20258.1 + 5.0.0-beta.20258.1 + 5.0.0-beta.20258.1 + 5.0.0-beta.20258.1 + 5.0.0-beta.20258.1 + 5.0.0-beta.20258.1 + 5.0.0-beta.20258.1 2.2.0-prerelease.19564.1 @@ -100,6 +92,7 @@ 1.0.5 1.7.0 + 2.0.0-beta1.20253.1 4.8.0 - 16.7.0-preview-20200408-06 + 16.7.0-preview-20200521-01 + 1.0.0-prerelease.20277.1 2.4.1 + 1.2.1 2.0.5 12.0.3 4.12.0 3.1.0-preview-20200129.1 - 5.0.0-preview.3.20210.1 + 5.0.0-preview.3.20276.2 - 6.0.1-alpha.1.20206.1 - 6.0.1-alpha.1.20206.1 - 6.0.1-alpha.1.20206.1 - 6.0.1-alpha.1.20206.1 - 6.0.1-alpha.1.20206.1 - 6.0.1-alpha.1.20206.1 + 9.0.1-alpha.1.20268.2 + 9.0.1-alpha.1.20268.2 + 9.0.1-alpha.1.20268.2 + 9.0.1-alpha.1.20268.2 + 9.0.1-alpha.1.20268.2 + 9.0.1-alpha.1.20268.2 diff --git a/eng/build.ps1 b/eng/build.ps1 index 1298a9ba6a2742..f8f1164bcafc8d 100644 --- a/eng/build.ps1 +++ b/eng/build.ps1 @@ -2,15 +2,16 @@ Param( [switch][Alias('h')]$help, [switch][Alias('t')]$test, - [string[]][Alias('c')]$configuration = @("Debug"), + [ValidateSet("Debug","Release","Checked")][string[]][Alias('c')]$configuration = @("Debug"), [string][Alias('f')]$framework, [string]$vs, - [string]$os, + [string][Alias('v')]$verbosity = "minimal", + [ValidateSet("Windows_NT","Linux","OSX","Browser")][string]$os, [switch]$allconfigurations, [switch]$coverage, [string]$testscope, [switch]$testnobuild, - [string[]][Alias('a')]$arch = @([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant()), + [ValidateSet("x86","x64","arm","arm64","wasm")][string[]][Alias('a')]$arch = @([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant()), [Parameter(Position=0)][string][Alias('s')]$subset, [ValidateSet("Debug","Release","Checked")][string][Alias('rc')]$runtimeConfiguration, [ValidateSet("Debug","Release")][string][Alias('lc')]$librariesConfiguration, @@ -20,9 +21,9 @@ Param( function Get-Help() { Write-Host "Common settings:" Write-Host " -subset Build a subset, print available subsets with -subset help (short: -s)" - Write-Host " -vs Open the solution with VS for Test Explorer support. Path or solution name (ie -vs Microsoft.CSharp)" - Write-Host " -os Build operating system: Windows_NT or Unix" - Write-Host " -arch Build platform: x86, x64, arm or arm64 (short: -a). Pass a comma-separated list to build for multiple architectures." + Write-Host " -vs Open the solution with VS using the locally acquired SDK. Path or solution name (ie -vs Microsoft.CSharp)" + Write-Host " -os Build operating system: Windows_NT, Linux, OSX, or Browser" + Write-Host " -arch Build platform: x86, x64, arm, arm64, or wasm (short: -a). Pass a comma-separated list to build for multiple architectures." Write-Host " -configuration Build configuration: Debug, Release or [CoreCLR]Checked (short: -c). Pass a comma-separated list to build for multiple configurations" Write-Host " -runtimeConfiguration Runtime build configuration: Debug, Release or [CoreCLR]Checked (short: -rc)" Write-Host " -librariesConfiguration Libraries build configuration: Debug or Release (short: -lc)" @@ -43,7 +44,7 @@ function Get-Help() { Write-Host "" Write-Host "Libraries settings:" - Write-Host " -framework Build framework: netcoreapp5.0 or net472 (short: -f)" + Write-Host " -framework Build framework: net5.0 or net472 (short: -f)" Write-Host " -coverage Collect code coverage when testing" Write-Host " -testscope Scope tests, allowed values: innerloop, outerloop, all" Write-Host " -testnobuild Skip building tests when invoking -test" @@ -59,37 +60,32 @@ if ($help -or (($null -ne $properties) -and ($properties.Contains('/help') -or $ exit 0 } -# VS Test Explorer support for libraries if ($vs) { . $PSScriptRoot\common\tools.ps1 - # Microsoft.DotNet.CoreSetup.sln is special - hosting tests are currently meant to run on the - # bootstrapped .NET Core, not on the live-built runtime. - if (([System.IO.Path]::GetFileName($vs) -ieq "Microsoft.DotNet.CoreSetup.sln") -or ($vs -ieq "Microsoft.DotNet.CoreSetup")) { + if (-Not (Test-Path $vs)) { + $solution = $vs + # Search for the solution in libraries + $vs = Split-Path $PSScriptRoot -Parent | Join-Path -ChildPath "src\libraries" | Join-Path -ChildPath $vs | Join-Path -ChildPath "$vs.sln" if (-Not (Test-Path $vs)) { - if (-Not ( $vs.endswith(".sln"))) { - $vs = "$vs.sln" + $vs = $solution + # Search for the solution in installer + if (-Not ($vs.endswith(".sln"))) { + $vs = "$vs.sln" + } + $vs = Split-Path $PSScriptRoot -Parent | Join-Path -ChildPath "src\installer" | Join-Path -ChildPath $vs + if (-Not (Test-Path $vs)) { + Write-Error "Passed in solution cannot be resolved." + exit 1 } - $vs = Join-Path "$PSScriptRoot\..\src\installer" $vs } - - # This tells .NET Core to use the bootstrapped runtime to run the tests - $env:DOTNET_ROOT=InitializeDotNetCli -install:$false } - else { - if (-Not (Test-Path $vs)) { - $vs = Join-Path "$PSScriptRoot\..\src\libraries" $vs | Join-Path -ChildPath "$vs.sln" - } - - $archTestHost = if ($arch) { $arch } else { "x64" } - # This tells .NET Core to use the same dotnet.exe that build scripts use - $env:DOTNET_ROOT="$PSScriptRoot\..\artifacts\bin\testhost\netcoreapp5.0-Windows_NT-$configuration-$archTestHost"; - $env:DEVPATH="$PSScriptRoot\..\artifacts\bin\testhost\net472-Windows_NT-$configuration-$archTestHost"; - } + # This tells .NET Core to use the bootstrapped runtime + $env:DOTNET_ROOT=InitializeDotNetCli -install:$false # This tells MSBuild to load the SDK from the directory of the bootstrapped SDK - $env:DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR=InitializeDotNetCli -install:$false + $env:DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR=$env:DOTNET_ROOT # This tells .NET Core not to go looking for .NET Core in other places $env:DOTNET_MULTILEVEL_LOOKUP=0; @@ -130,6 +126,7 @@ foreach ($argument in $PSBoundParameters.Keys) "os" { $arguments += " /p:TargetOS=$($PSBoundParameters[$argument])" } "allconfigurations" { $arguments += " /p:BuildAllConfigurations=true" } "properties" { $arguments += " " + $properties } + "verbosity" { $arguments += " -$argument " + $($PSBoundParameters[$argument]) } # configuration and arch can be specified multiple times, so they should be no-ops here "configuration" {} "arch" {} @@ -159,4 +156,4 @@ if ($failedBuilds.Count -ne 0) { exit 1 } -exit 0 \ No newline at end of file +exit 0 diff --git a/eng/build.sh b/eng/build.sh index 5b55cabd4ba2af..02c5d278e259d6 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -18,8 +18,8 @@ usage() { echo "Common settings:" echo " --subset Build a subset, print available subsets with -subset help (short: -s)" - echo " --os Build operating system: Windows_NT, Linux, FreeBSD, OSX, tvOS, iOS or Android" - echo " --arch Build platform: x86, x64, arm, armel or arm64" + echo " --os Build operating system: Windows_NT, Linux, FreeBSD, OSX, tvOS, iOS, Android, Browser, NetBSD or SunOS" + echo " --arch Build platform: x86, x64, arm, armel, arm64 or wasm" echo " --configuration Build configuration: Debug, Release or [CoreCLR]Checked (short: -c)" echo " --runtimeConfiguration Runtime build configuration: Debug, Release or [CoreCLR]Checked (short: -rc)" echo " --librariesConfiguration Libraries build configuration: Debug or Release (short: -lc)" @@ -42,7 +42,7 @@ usage() echo "" echo "Libraries settings:" - echo " --framework Build framework: netcoreapp5.0 or net472 (short: -f)" + echo " --framework Build framework: net5.0 or net472 (short: -f)" echo " --coverage Collect code coverage when testing" echo " --testscope Test scope, allowed values: innerloop, outerloop, all" echo " --testnobuild Skip building tests when invoking -test" @@ -107,71 +107,190 @@ while [[ $# > 0 ]]; do usage exit 0 ;; + -subset|-s) - arguments="$arguments /p:Subset=$2" - shift 2 + if [ -z ${2+x} ]; then + arguments="$arguments /p:Subset=help" + shift 1 + else + arguments="$arguments /p:Subset=$2" + shift 2 + fi ;; + -arch) - arch=$2 + if [ -z ${2+x} ]; then + echo "No architecture supplied. See help (--help) for supported architectures." 1>&2 + exit 1 + fi + passedArch="$(echo "$2" | awk '{print tolower($0)}')" + case "$passedArch" in + x64|x86|arm|armel|arm64|wasm) + arch=$passedArch + ;; + *) + echo "Unsupported target architecture '$2'." + echo "The allowed values are x86, x64, arm, armel, arm64, and wasm." + exit 1 + ;; + esac shift 2 ;; + -configuration|-c) - val="$(tr '[:lower:]' '[:upper:]' <<< ${2:0:1})${2:1}" + if [ -z ${2+x} ]; then + echo "No configuration supplied. See help (--help) for supported configurations." 1>&2 + exit 1 + fi + passedConfig="$(echo "$2" | awk '{print tolower($0)}')" + case "$passedConfig" in + debug|release|checked) + val="$(tr '[:lower:]' '[:upper:]' <<< ${passedConfig:0:1})${passedConfig:1}" + ;; + *) + echo "Unsupported target configuration '$2'." + echo "The allowed values are Debug, Release, and Checked." + exit 1 + ;; + esac arguments="$arguments -configuration $val" shift 2 ;; + -framework|-f) + if [ -z ${2+x} ]; then + echo "No framework supplied. See help (--help) for supported frameworks." 1>&2 + exit 1 + fi val="$(echo "$2" | awk '{print tolower($0)}')" arguments="$arguments /p:BuildTargetFramework=$val" shift 2 ;; + -os) - os=$2 - arguments="$arguments /p:TargetOS=$2" + if [ -z ${2+x} ]; then + echo "No target operating system supplied. See help (--help) for supported target operating systems." 1>&2 + exit 1 + fi + passedOS="$(echo "$2" | awk '{print tolower($0)}')" + case "$passedOS" in + windows_nt) + os="Windows_NT" ;; + linux) + os="Linux" ;; + freebsd) + os="FreeBSD" ;; + osx) + os="OSX" ;; + tvos) + os="tvOS" ;; + ios) + os="iOS" ;; + android) + os="Android" ;; + browser) + os="Browser" ;; + sunos) + os="SunOS" ;; + *) + echo "Unsupported target OS '$2'." + echo "The allowed values are Windows_NT, Linux, FreeBSD, OSX, tvOS, iOS, Android, Browser, and SunOS." + exit 1 + ;; + esac + arguments="$arguments /p:TargetOS=$os" shift 2 ;; + -allconfigurations) arguments="$arguments /p:BuildAllConfigurations=true" shift 1 ;; + -testscope) + if [ -z ${2+x} ]; then + echo "No test scope supplied. See help (--help) for supported test scope values." 1>&2 + exit 1 + fi arguments="$arguments /p:TestScope=$2" shift 2 ;; + -testnobuild) - arguments="$arguments /p:TestNoBuild=$2" - shift 2 + arguments="$arguments /p:TestNoBuild=true" + shift 1 ;; + -coverage) arguments="$arguments /p:Coverage=true" shift 1 ;; + -runtimeconfiguration|-rc) - val="$(tr '[:lower:]' '[:upper:]' <<< ${2:0:1})${2:1}" + if [ -z ${2+x} ]; then + echo "No runtime configuration supplied. See help (--help) for supported runtime configurations." 1>&2 + exit 1 + fi + passedRuntimeConf="$(echo "$2" | awk '{print tolower($0)}')" + case "$passedRuntimeConf" in + debug|release|checked) + val="$(tr '[:lower:]' '[:upper:]' <<< ${passedRuntimeConf:0:1})${passedRuntimeConf:1}" + ;; + *) + echo "Unsupported runtime configuration '$2'." + echo "The allowed values are Debug, Release, and Checked." + exit 1 + ;; + esac arguments="$arguments /p:RuntimeConfiguration=$val" shift 2 ;; + -librariesconfiguration|-lc) - arguments="$arguments /p:LibrariesConfiguration=$2" + if [ -z ${2+x} ]; then + echo "No libraries configuration supplied. See help (--help) for supported libraries configurations." 1>&2 + exit 1 + fi + passedLibConf="$(echo "$2" | awk '{print tolower($0)}')" + case "$passedLibConf" in + debug|release) + val="$(tr '[:lower:]' '[:upper:]' <<< ${passedLibConf:0:1})${passedLibConf:1}" + ;; + *) + echo "Unsupported libraries configuration '$2'." + echo "The allowed values are Debug and Release." + exit 1 + ;; + esac + arguments="$arguments /p:LibrariesConfiguration=$val" shift 2 ;; + -cross) crossBuild=1 arguments="$arguments /p:CrossBuild=True" shift 1 ;; + -clang*) arguments="$arguments /p:Compiler=$opt" shift 1 ;; + -cmakeargs) + if [ -z ${2+x} ]; then + echo "No cmake args supplied." 1>&2 + exit 1 + fi cmakeargs="${cmakeargs} ${opt} $2" shift 2 ;; + -gcc*) arguments="$arguments /p:Compiler=$opt" shift 1 ;; + *) extraargs="$extraargs $1" shift 1 diff --git a/eng/codeOptimization.targets b/eng/codeOptimization.targets index 3687c865c90046..6ed7e997487bd6 100644 --- a/eng/codeOptimization.targets +++ b/eng/codeOptimization.targets @@ -9,7 +9,7 @@ IBCMerge optimizations on Mac for now to unblock the offical build. See issue https://github.com/dotnet/runtime/issues/33303 --> - false + false Semi-colon delimited list of sln/proj's to build. Globbing is supported (*.sln)" Write-Host " -ci Set when running on CI server" + Write-Host " -excludeCIBinarylog Don't output binary log (short: -nobl)" Write-Host " -prepareMachine Prepare machine for CI run, clean up processes after build" Write-Host " -warnAsError Sets warnaserror msbuild parameter ('true' or 'false')" Write-Host " -msbuildEngine Msbuild engine to use to run build ('dotnet', 'vs', or unspecified)." @@ -134,7 +136,9 @@ try { } if ($ci) { - $binaryLog = $true + if (-not $excludeCIBinarylog) { + $binaryLog = $true + } $nodeReuse = $false } diff --git a/eng/common/build.sh b/eng/common/build.sh index 36f9aa0462ee17..6d7c5a1f69c200 100755 --- a/eng/common/build.sh +++ b/eng/common/build.sh @@ -32,6 +32,7 @@ usage() echo "Advanced settings:" echo " --projects Project or solution file(s) to build" echo " --ci Set when running on CI server" + echo " --excludeCIBinarylog Don't output binary log (short: -nobl)" echo " --prepareMachine Prepare machine for CI run, clean up processes after build" echo " --nodeReuse Sets nodereuse msbuild parameter ('true' or 'false')" echo " --warnAsError Sets warnaserror msbuild parameter ('true' or 'false')" @@ -68,6 +69,7 @@ clean=false warn_as_error=true node_reuse=true binary_log=false +exclude_ci_binary_log=false pipelines_log=false projects='' @@ -98,6 +100,9 @@ while [[ $# > 0 ]]; do -binarylog|-bl) binary_log=true ;; + -excludeCIBinarylog|-nobl) + exclude_ci_binary_log=true + ;; -pipelineslog|-pl) pipelines_log=true ;; @@ -156,8 +161,10 @@ done if [[ "$ci" == true ]]; then pipelines_log=true - binary_log=true node_reuse=false + if [[ "$exclude_ci_binary_log" == false ]]; then + binary_log=true + fi fi . "$scriptroot/tools.sh" diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh index 2cdd82d30df62e..d780fefb541432 100755 --- a/eng/common/cross/build-rootfs.sh +++ b/eng/common/cross/build-rootfs.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +set -e + usage() { echo "Usage: $0 [BuildArch] [CodeName] [lldbx.y] [--skipunmount] --rootfsdir ]" @@ -15,6 +17,8 @@ __CodeName=xenial __CrossDir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) __InitialDir=$PWD __BuildArch=arm +__AlpineArch=armv7 +__QEMUArch=arm __UbuntuArch=armhf __UbuntuRepo="http://ports.ubuntu.com/" __LLDB_Package="liblldb-3.9-dev" @@ -26,9 +30,10 @@ __UbuntuPackages="build-essential" __AlpinePackages="alpine-base" __AlpinePackages+=" build-base" __AlpinePackages+=" linux-headers" -__AlpinePackagesEdgeTesting=" lldb-dev" -__AlpinePackagesEdgeMain=" llvm9-libs" +__AlpinePackagesEdgeCommunity=" lldb-dev" +__AlpinePackagesEdgeMain=" llvm10-libs" __AlpinePackagesEdgeMain+=" python3" +__AlpinePackagesEdgeMain+=" libedit" # symlinks fixer __UbuntuPackages+=" symlinks" @@ -55,12 +60,11 @@ __AlpinePackages+=" openssl-dev" __AlpinePackages+=" zlib-dev" __FreeBSDBase="12.1-RELEASE" -__FreeBSDPkg="1.10.5" +__FreeBSDPkg="1.12.0" __FreeBSDPackages="libunwind" __FreeBSDPackages+=" icu" __FreeBSDPackages+=" libinotify" __FreeBSDPackages+=" lttng-ust" -__FreeBSDPackages+=" llvm-90" __FreeBSDPackages+=" krb5" __UnprocessedBuildArgs= @@ -78,7 +82,7 @@ while :; do arm) __BuildArch=arm __UbuntuArch=armhf - __AlpineArch=armhf + __AlpineArch=armv7 __QEMUArch=arm ;; arm64) @@ -205,7 +209,7 @@ fi if [ -d "$__RootfsDir" ]; then if [ $__SkipUnmount == 0 ]; then - umount $__RootfsDir/* + umount $__RootfsDir/* || true fi rm -rf $__RootfsDir fi @@ -231,9 +235,9 @@ if [[ "$__CodeName" == "alpine" ]]; then add $__AlpinePackagesEdgeMain $__ApkToolsDir/apk-tools-$__ApkToolsVersion/apk \ - -X http://dl-cdn.alpinelinux.org/alpine/edge/testing \ + -X http://dl-cdn.alpinelinux.org/alpine/edge/community \ -U --allow-untrusted --root $__RootfsDir --arch $__AlpineArch --initdb \ - add $__AlpinePackagesEdgeTesting + add $__AlpinePackagesEdgeCommunity rm -r $__ApkToolsDir elif [[ "$__CodeName" == "freebsd" ]]; then @@ -246,11 +250,13 @@ elif [[ "$__CodeName" == "freebsd" ]]; then # get and build package manager wget -O - https://github.com/freebsd/pkg/archive/${__FreeBSDPkg}.tar.gz | tar -C $__RootfsDir/tmp -zxf - cd $__RootfsDir/tmp/pkg-${__FreeBSDPkg} - ./autogen.sh && ./configure --prefix=$__RootfsDir/host && make install + # needed for install to succeed + mkdir -p $__RootfsDir/host/etc + ./autogen.sh && ./configure --prefix=$__RootfsDir/host && make && make install rm -rf $__RootfsDir/tmp/pkg-${__FreeBSDPkg} # install packages we need. - $__RootfsDir/host/sbin/pkg -r $__RootfsDir -C $__RootfsDir/usr/local/etc/pkg.conf update - $__RootfsDir/host/sbin/pkg -r $__RootfsDir -C $__RootfsDir/usr/local/etc/pkg.conf install --yes $__FreeBSDPackages + INSTALL_AS_USER=$(whoami) $__RootfsDir/host/sbin/pkg -r $__RootfsDir -C $__RootfsDir/usr/local/etc/pkg.conf update + INSTALL_AS_USER=$(whoami) $__RootfsDir/host/sbin/pkg -r $__RootfsDir -C $__RootfsDir/usr/local/etc/pkg.conf install --yes $__FreeBSDPackages elif [[ -n $__CodeName ]]; then qemu-debootstrap --arch $__UbuntuArch $__CodeName $__RootfsDir $__UbuntuRepo cp $__CrossDir/$__BuildArch/sources.list.$__CodeName $__RootfsDir/etc/apt/sources.list @@ -260,7 +266,7 @@ elif [[ -n $__CodeName ]]; then chroot $__RootfsDir symlinks -cr /usr if [ $__SkipUnmount == 0 ]; then - umount $__RootfsDir/* + umount $__RootfsDir/* || true fi if [[ "$__BuildArch" == "arm" && "$__CodeName" == "trusty" ]]; then diff --git a/eng/common/internal/Tools.csproj b/eng/common/internal/Tools.csproj index 1a39a7ef3f67b1..f46d5efe2e32af 100644 --- a/eng/common/internal/Tools.csproj +++ b/eng/common/internal/Tools.csproj @@ -4,6 +4,7 @@ net472 false + false diff --git a/eng/common/native/CommonLibrary.psm1 b/eng/common/native/CommonLibrary.psm1 index 41416862d9132f..d7d1a6510949af 100644 --- a/eng/common/native/CommonLibrary.psm1 +++ b/eng/common/native/CommonLibrary.psm1 @@ -145,9 +145,12 @@ function Get-File { New-Item -path $DownloadDirectory -force -itemType "Directory" | Out-Null } + $TempPath = "$Path.tmp" if (Test-Path -IsValid -Path $Uri) { - Write-Verbose "'$Uri' is a file path, copying file to '$Path'" - Copy-Item -Path $Uri -Destination $Path + Write-Verbose "'$Uri' is a file path, copying temporarily to '$TempPath'" + Copy-Item -Path $Uri -Destination $TempPath + Write-Verbose "Moving temporary file to '$Path'" + Move-Item -Path $TempPath -Destination $Path return $? } else { @@ -157,8 +160,10 @@ function Get-File { while($Attempt -Lt $DownloadRetries) { try { - Invoke-WebRequest -UseBasicParsing -Uri $Uri -OutFile $Path - Write-Verbose "Downloaded to '$Path'" + Invoke-WebRequest -UseBasicParsing -Uri $Uri -OutFile $TempPath + Write-Verbose "Downloaded to temporary location '$TempPath'" + Move-Item -Path $TempPath -Destination $Path + Write-Verbose "Moved temporary file to '$Path'" return $True } catch { @@ -359,16 +364,21 @@ function Expand-Zip { return $False } } - if (-Not (Test-Path $OutputDirectory)) { - New-Item -path $OutputDirectory -Force -itemType "Directory" | Out-Null + + $TempOutputDirectory = Join-Path "$(Split-Path -Parent $OutputDirectory)" "$(Split-Path -Leaf $OutputDirectory).tmp" + if (Test-Path $TempOutputDirectory) { + Remove-Item $TempOutputDirectory -Force -Recurse } + New-Item -Path $TempOutputDirectory -Force -ItemType "Directory" | Out-Null Add-Type -assembly "system.io.compression.filesystem" - [io.compression.zipfile]::ExtractToDirectory("$ZipPath", "$OutputDirectory") + [io.compression.zipfile]::ExtractToDirectory("$ZipPath", "$TempOutputDirectory") if ($? -Eq $False) { Write-Error "Unable to extract '$ZipPath'" return $False } + + Move-Item -Path $TempOutputDirectory -Destination $OutputDirectory } catch { Write-Host $_ diff --git a/eng/common/native/find-native-compiler.sh b/eng/common/native/find-native-compiler.sh new file mode 100644 index 00000000000000..aed19d07d506ff --- /dev/null +++ b/eng/common/native/find-native-compiler.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash +# +# This file locates the native compiler with the given name and version and sets the environment variables to locate it. +# + +source="${BASH_SOURCE[0]}" + +# resolve $SOURCE until the file is no longer a symlink +while [[ -h $source ]]; do + scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" + source="$(readlink "$source")" + + # if $source was a relative symlink, we need to resolve it relative to the path where the + # symlink file was located + [[ $source != /* ]] && source="$scriptroot/$source" +done +scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" + +if [ $# -lt 0 ] +then + echo "Usage..." + echo "find-native-compiler.sh " + echo "Specify the name of compiler (clang or gcc)." + echo "Specify the major version of compiler." + echo "Specify the minor version of compiler." + exit 1 +fi + +. $scriptroot/../pipeline-logging-functions.sh + +compiler="$1" +cxxCompiler="$compiler++" +majorVersion="$2" +minorVersion="$3" + +if [ "$compiler" = "gcc" ]; then cxxCompiler="g++"; fi + +check_version_exists() { + desired_version=-1 + + # Set up the environment to be used for building with the desired compiler. + if command -v "$compiler-$1.$2" > /dev/null; then + desired_version="-$1.$2" + elif command -v "$compiler$1$2" > /dev/null; then + desired_version="$1$2" + elif command -v "$compiler-$1$2" > /dev/null; then + desired_version="-$1$2" + fi + + echo "$desired_version" +} + +if [ -z "$CLR_CC" ]; then + + # Set default versions + if [ -z "$majorVersion" ]; then + # note: gcc (all versions) and clang versions higher than 6 do not have minor version in file name, if it is zero. + if [ "$compiler" = "clang" ]; then versions=( 9 8 7 6.0 5.0 4.0 3.9 3.8 3.7 3.6 3.5 ) + elif [ "$compiler" = "gcc" ]; then versions=( 9 8 7 6 5 4.9 ); fi + + for version in "${versions[@]}"; do + parts=(${version//./ }) + desired_version="$(check_version_exists "${parts[0]}" "${parts[1]}")" + if [ "$desired_version" != "-1" ]; then majorVersion="${parts[0]}"; break; fi + done + + if [ -z "$majorVersion" ]; then + if command -v "$compiler" > /dev/null; then + if [ "$(uname)" != "Darwin" ]; then + Write-PipelineTelemetryError -category "Build" -type "warning" "Specific version of $compiler not found, falling back to use the one in PATH." + fi + export CC="$(command -v "$compiler")" + export CXX="$(command -v "$cxxCompiler")" + else + Write-PipelineTelemetryError -category "Build" "No usable version of $compiler found." + exit 1 + fi + else + if [ "$compiler" = "clang" ] && [ "$majorVersion" -lt 5 ]; then + if [ "$build_arch" = "arm" ] || [ "$build_arch" = "armel" ]; then + if command -v "$compiler" > /dev/null; then + Write-PipelineTelemetryError -category "Build" -type "warning" "Found clang version $majorVersion which is not supported on arm/armel architectures, falling back to use clang from PATH." + export CC="$(command -v "$compiler")" + export CXX="$(command -v "$cxxCompiler")" + else + Write-PipelineTelemetryError -category "Build" "Found clang version $majorVersion which is not supported on arm/armel architectures, and there is no clang in PATH." + exit 1 + fi + fi + fi + fi + else + desired_version="$(check_version_exists "$majorVersion" "$minorVersion")" + if [ "$desired_version" = "-1" ]; then + Write-PipelineTelemetryError -category "Build" "Could not find specific version of $compiler: $majorVersion $minorVersion." + exit 1 + fi + fi + + if [ -z "$CC" ]; then + export CC="$(command -v "$compiler$desired_version")" + export CXX="$(command -v "$cxxCompiler$desired_version")" + if [ -z "$CXX" ]; then export CXX="$(command -v "$cxxCompiler")"; fi + fi +else + if [ ! -f "$CLR_CC" ]; then + Write-PipelineTelemetryError -category "Build" "CLR_CC is set but path '$CLR_CC' does not exist" + exit 1 + fi + export CC="$CLR_CC" + export CXX="$CLR_CXX" +fi + +if [ -z "$CC" ]; then + Write-PipelineTelemetryError -category "Build" "Unable to find $compiler." + exit 1 +fi + +export CCC_CC="$CC" +export CCC_CXX="$CXX" +export SCAN_BUILD_COMMAND="$(command -v "scan-build$desired_version")" diff --git a/eng/common/performance/perfhelixpublish.proj b/eng/common/performance/perfhelixpublish.proj index cf5941e1b64554..1db5e8a84d758b 100644 --- a/eng/common/performance/perfhelixpublish.proj +++ b/eng/common/performance/perfhelixpublish.proj @@ -6,6 +6,7 @@ py -3 %HELIX_CORRELATION_PAYLOAD%\Core_Root\CoreRun.exe %HELIX_CORRELATION_PAYLOAD%\Baseline_Core_Root\CoreRun.exe + $(HelixPreCommands);call %HELIX_CORRELATION_PAYLOAD%\performance\tools\machine-setup.cmd;set PYTHONPATH=%HELIX_WORKITEM_PAYLOAD%\scripts%3B%HELIX_WORKITEM_PAYLOAD% %HELIX_CORRELATION_PAYLOAD%\artifacts\BenchmarkDotNet.Artifacts %HELIX_CORRELATION_PAYLOAD%\artifacts\BenchmarkDotNet.Artifacts_Baseline @@ -40,6 +41,13 @@ $HELIX_WORKITEM_ROOT/testResults.xml + + --corerun %HELIX_CORRELATION_PAYLOAD%\dotnet-mono\shared\Microsoft.NETCore.App\5.0.0\corerun.exe + + + --corerun $(BaseDirectory)/dotnet-mono/shared/Microsoft.NETCore.App/5.0.0/corerun + + --corerun $(CoreRun) diff --git a/eng/common/performance/performance-setup.ps1 b/eng/common/performance/performance-setup.ps1 index 1763a1a97b0e79..31a99e49015f49 100644 --- a/eng/common/performance/performance-setup.ps1 +++ b/eng/common/performance/performance-setup.ps1 @@ -3,7 +3,7 @@ Param( [string] $CoreRootDirectory, [string] $BaselineCoreRootDirectory, [string] $Architecture="x64", - [string] $Framework="netcoreapp5.0", + [string] $Framework="net5.0", [string] $CompilationMode="Tiered", [string] $Repository=$env:BUILD_REPOSITORY_NAME, [string] $Branch=$env:BUILD_SOURCEBRANCH, @@ -12,8 +12,12 @@ Param( [string] $RunCategories="Libraries Runtime", [string] $Csproj="src\benchmarks\micro\MicroBenchmarks.csproj", [string] $Kind="micro", + [switch] $LLVM, + [switch] $MonoInterpreter, + [switch] $MonoAOT, [switch] $Internal, [switch] $Compare, + [string] $MonoDotnet="", [string] $Configurations="CompilationMode=$CompilationMode RunKind=$Kind" ) @@ -31,7 +35,8 @@ $HelixSourcePrefix = "pr" $Queue = "Windows.10.Amd64.ClientRS4.DevEx.15.8.Open" -if ($Framework.StartsWith("netcoreapp")) { +# TODO: Implement a better logic to determine if Framework is .NET Core or >= .NET 5. +if ($Framework.StartsWith("netcoreapp") -or ($Framework -eq "net5.0")) { $Queue = "Windows.10.Amd64.ClientRS5.Open" } @@ -49,6 +54,21 @@ if ($Internal) { $HelixSourcePrefix = "official" } +if($MonoDotnet -ne "") +{ + $Configurations += " LLVM=$LLVM MonoInterpreter=$MonoInterpreter MonoAOT=$MonoAOT" + if($ExtraBenchmarkDotNetArguments -eq "") + { + #FIX ME: We need to block these tests as they don't run on mono for now + $ExtraBenchmarkDotNetArguments = "--exclusion-filter *Perf_Image* *Perf_NamedPipeStream*" + } + else + { + #FIX ME: We need to block these tests as they don't run on mono for now + $ExtraBenchmarkDotNetArguments += " --exclusion-filter *Perf_Image* *Perf_NamedPipeStream*" + } +} + # FIX ME: This is a workaround until we get this from the actual pipeline $CommonSetupArguments="--channel master --queue $Queue --build-number $BuildNumber --build-configs $Configurations --architecture $Architecture" $SetupArguments = "--repository https://github.com/$Repository --branch $Branch --get-perf-hash --commit-sha $CommitSha $CommonSetupArguments" @@ -69,6 +89,13 @@ else { git clone --branch master --depth 1 --quiet https://github.com/dotnet/performance $PerformanceDirectory } +if($MonoDotnet -ne "") +{ + $UsingMono = "true" + $MonoDotnetPath = (Join-Path $PayloadDirectory "dotnet-mono") + Move-Item -Path $MonoDotnet -Destination $MonoDotnetPath +} + if ($UseCoreRun) { $NewCoreRoot = (Join-Path $PayloadDirectory "Core_Root") Move-Item -Path $CoreRootDirectory -Destination $NewCoreRoot @@ -104,6 +131,7 @@ Write-PipelineSetVariable -Name 'UseCoreRun' -Value "$UseCoreRun" -IsMultiJobVar Write-PipelineSetVariable -Name 'UseBaselineCoreRun' -Value "$UseBaselineCoreRun" -IsMultiJobVariable $false Write-PipelineSetVariable -Name 'RunFromPerfRepo' -Value "$RunFromPerformanceRepo" -IsMultiJobVariable $false Write-PipelineSetVariable -Name 'Compare' -Value "$Compare" -IsMultiJobVariable $false +Write-PipelineSetVariable -Name 'MonoDotnet' -Value "$UsingMono" -IsMultiJobVariable $false # Helix Arguments Write-PipelineSetVariable -Name 'Creator' -Value "$Creator" -IsMultiJobVariable $false diff --git a/eng/common/performance/performance-setup.sh b/eng/common/performance/performance-setup.sh index b9eecf94bd01b8..9409e4d85e92e3 100755 --- a/eng/common/performance/performance-setup.sh +++ b/eng/common/performance/performance-setup.sh @@ -4,7 +4,7 @@ source_directory=$BUILD_SOURCESDIRECTORY core_root_directory= baseline_core_root_directory= architecture=x64 -framework=netcoreapp5.0 +framework=net5.0 compilation_mode=tiered repository=$BUILD_REPOSITORY_NAME branch=$BUILD_SOURCEBRANCH @@ -12,13 +12,18 @@ commit_sha=$BUILD_SOURCEVERSION build_number=$BUILD_BUILDNUMBER internal=false compare=false +mono_dotnet= kind="micro" +llvm=false +monointerpreter=false +monoaot=false run_categories="Libraries Runtime" csproj="src\benchmarks\micro\MicroBenchmarks.csproj" configurations="CompliationMode=$compilation_mode RunKind=$kind" run_from_perf_repo=false use_core_run=true use_baseline_core_run=true +using_mono=false while (($# > 0)); do lowerI="$(echo $1 | awk '{print tolower($0)}')" @@ -65,6 +70,7 @@ while (($# > 0)); do ;; --kind) kind=$2 + configurations="CompliationMode=$compilation_mode RunKind=$kind" shift 2 ;; --runcategories) @@ -79,6 +85,22 @@ while (($# > 0)); do internal=true shift 1 ;; + --llvm) + llvm=true + shift 1 + ;; + --monointerpreter) + monointerpreter=true + shift 1 + ;; + --monoaot) + monoaot=true + shift 1 + ;; + --monodotnet) + mono_dotnet=$2 + shift 2 + ;; --compare) compare=true shift 1 @@ -107,6 +129,7 @@ while (($# > 0)); do echo " --kind Related to csproj. The kind of benchmarks that should be run. Defaults to micro" echo " --runcategories Related to csproj. Categories of benchmarks to run. Defaults to \"coreclr corefx\"" echo " --internal If the benchmarks are running as an official job." + echo " --monodotnet Pass the path to the mono dotnet for mono performance testing." echo "" exit 0 ;; @@ -164,6 +187,10 @@ if [[ "$internal" == true ]]; then fi fi +if [[ "$mono_dotnet" != "" ]]; then + configurations="$configurations LLVM=$llvm MonoInterpreter=$monointerpreter MonoAOT=$monoaot" +fi + common_setup_arguments="--channel master --queue $queue --build-number $build_number --build-configs $configurations --architecture $architecture" setup_arguments="--repository https://github.com/$repository --branch $branch --get-perf-hash --commit-sha $commit_sha $common_setup_arguments" @@ -186,6 +213,12 @@ else mv $docs_directory $workitem_directory fi +if [[ "$mono_dotnet" != "" ]]; then + using_mono=true + mono_dotnet_path=$payload_directory/dotnet-mono + mv $mono_dotnet $mono_dotnet_path +fi + if [[ "$use_core_run" = true ]]; then new_core_root=$payload_directory/Core_Root mv $core_root_directory $new_core_root @@ -221,3 +254,4 @@ Write-PipelineSetVariable -name "HelixSourcePrefix" -value "$helix_source_prefix Write-PipelineSetVariable -name "Kind" -value "$kind" -is_multi_job_variable false Write-PipelineSetVariable -name "_BuildConfig" -value "$architecture.$kind.$framework" -is_multi_job_variable false Write-PipelineSetVariable -name "Compare" -value "$compare" -is_multi_job_variable false +Write-PipelineSetVariable -name "MonoDotnet" -value "$using_mono" -is_multi_job_variable false diff --git a/eng/common/post-build/check-channel-consistency.ps1 b/eng/common/post-build/check-channel-consistency.ps1 index 7e6618d64ad9f3..38abc5392dc75c 100644 --- a/eng/common/post-build/check-channel-consistency.ps1 +++ b/eng/common/post-build/check-channel-consistency.ps1 @@ -6,13 +6,18 @@ param( try { . $PSScriptRoot\post-build-utils.ps1 + if ($PromoteToChannels -eq "") { + Write-PipelineTaskError -Type 'warning' -Message "This build won't publish assets as it's not configured to any Maestro channel. If that wasn't intended use Darc to configure a default channel using add-default-channel for this branch or to promote it to a channel using add-build-to-channel. See https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md#assigning-an-individual-build-to-a-channel for more info." + ExitWithExitCode 0 + } + # Check that every channel that Maestro told to promote the build to # is available in YAML $PromoteToChannelsIds = $PromoteToChannels -split "\D" | Where-Object { $_ } foreach ($id in $PromoteToChannelsIds) { if (($id -ne 0) -and ($id -notin $AvailableChannelIds)) { - Write-PipelineTaskError -Type 'warning' -Message "Channel $id is not present in the post-build YAML configuration!" + Write-PipelineTaskError -Message "Channel $id is not present in the post-build YAML configuration! This is an error scenario. Please contact @dnceng." } } diff --git a/eng/common/post-build/symbols-validation.ps1 b/eng/common/post-build/symbols-validation.ps1 index f7cfe986ddd3e4..8e9527113ca083 100644 --- a/eng/common/post-build/symbols-validation.ps1 +++ b/eng/common/post-build/symbols-validation.ps1 @@ -1,7 +1,9 @@ param( [Parameter(Mandatory=$true)][string] $InputPath, # Full path to directory where NuGet packages to be checked are stored [Parameter(Mandatory=$true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation - [Parameter(Mandatory=$true)][string] $DotnetSymbolVersion # Version of dotnet symbol to use + [Parameter(Mandatory=$true)][string] $DotnetSymbolVersion, # Version of dotnet symbol to use + [Parameter(Mandatory=$false)][switch] $ContinueOnError, # If we should keep checking symbols after an error + [Parameter(Mandatory=$false)][switch] $Clean # Clean extracted symbols directory after checking symbols ) function FirstMatchingSymbolDescriptionOrDefault { @@ -80,7 +82,14 @@ function CountMissingSymbols { $ExtractPath = Join-Path -Path $ExtractPath -ChildPath $PackageGuid $SymbolsPath = Join-Path -Path $ExtractPath -ChildPath 'Symbols' - [System.IO.Compression.ZipFile]::ExtractToDirectory($PackagePath, $ExtractPath) + try { + [System.IO.Compression.ZipFile]::ExtractToDirectory($PackagePath, $ExtractPath) + } + catch { + Write-Host "Something went wrong extracting $PackagePath" + Write-Host $_ + return -1 + } Get-ChildItem -Recurse $ExtractPath | Where-Object {$RelevantExtensions -contains $_.Extension} | @@ -115,6 +124,10 @@ function CountMissingSymbols { } } + if ($Clean) { + Remove-Item $ExtractPath -Recurse -Force + } + Pop-Location return $MissingSymbols @@ -125,6 +138,8 @@ function CheckSymbolsAvailable { Remove-Item $ExtractPath -Force -Recurse -ErrorAction SilentlyContinue } + $TotalFailures = 0 + Get-ChildItem "$InputPath\*.nupkg" | ForEach-Object { $FileName = $_.Name @@ -148,11 +163,22 @@ function CheckSymbolsAvailable { if ($Status -ne 0) { Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "Missing symbols for $Status modules in the package $FileName" - ExitWithExitCode $exitCode + + if ($ContinueOnError) { + $TotalFailures++ + } + else { + ExitWithExitCode 1 + } } Write-Host } + + if ($TotalFailures -ne 0) { + Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "Symbols missing for $TotalFailures packages" + ExitWithExitCode 1 + } } function InstallDotnetSymbol { diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1 index 3872af59b97288..f997be4331d224 100644 --- a/eng/common/sdk-task.ps1 +++ b/eng/common/sdk-task.ps1 @@ -57,6 +57,19 @@ try { ExitWithExitCode 1 } + if( $msbuildEngine -eq "vs") { + # Ensure desktop MSBuild is available for sdk tasks. + if( -not ($GlobalJson.tools.PSObject.Properties.Name -contains "vs" )) { + $GlobalJson.tools | Add-Member -Name "vs" -Value (ConvertFrom-Json "{ `"version`": `"16.5`" }") -MemberType NoteProperty + } + if( -not ($GlobalJson.tools.PSObject.Properties.Name -match "xcopy-msbuild" )) { + $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "16.5.0-alpha" -MemberType NoteProperty + } + + $xcopyMSBuildToolsFolder = InitializeXCopyMSBuild $GlobalJson.tools."xcopy-msbuild" -install $true + $global:_MSBuildExe = "$($xcopyMSBuildToolsFolder)\MSBuild\Current\Bin\MSBuild.exe" + } + $taskProject = GetSdkTaskProject $task if (!(Test-Path $taskProject)) { Write-PipelineTelemetryError -Category 'Build' -Message "Unknown task: $task" -ForegroundColor Red diff --git a/eng/common/sdl/extract-artifact-packages.ps1 b/eng/common/sdl/extract-artifact-packages.ps1 index 9e5f3cb43c7e4e..7f28d9c59ec69c 100644 --- a/eng/common/sdl/extract-artifact-packages.ps1 +++ b/eng/common/sdl/extract-artifact-packages.ps1 @@ -63,7 +63,7 @@ try { } } catch { - Write-Host $_.ScriptStackTrace + Write-Host $_ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_ ExitWithExitCode 1 } @@ -74,7 +74,7 @@ try { Measure-Command { ExtractArtifacts } } catch { - Write-Host $_.ScriptStackTrace + Write-Host $_ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_ ExitWithExitCode 1 } diff --git a/eng/common/sdl/init-sdl.ps1 b/eng/common/sdl/init-sdl.ps1 index 1a91bbbc5a9a9c..a68bf0b88ea681 100644 --- a/eng/common/sdl/init-sdl.ps1 +++ b/eng/common/sdl/init-sdl.ps1 @@ -24,7 +24,7 @@ $ProgressPreference = 'SilentlyContinue' # Construct basic auth from AzDO access token; construct URI to the repository's gdn folder stored in that repository; construct location of zip file $encodedPat = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$AzureDevOpsAccessToken")) $escapedRepository = [Uri]::EscapeDataString("/$Repository/$BranchName/.gdn") -$uri = "https://dev.azure.com/dnceng/internal/_apis/git/repositories/sdl-tool-cfg/Items?path=$escapedRepository&versionDescriptor[versionOptions]=0&`$format=zip&api-version=5.0-preview.1" +$uri = "https://dev.azure.com/dnceng/internal/_apis/git/repositories/sdl-tool-cfg/Items?path=$escapedRepository&versionDescriptor[versionOptions]=0&`$format=zip&api-version=5.0" $zipFile = "$WorkingDirectory/gdn.zip" Add-Type -AssemblyName System.IO.Compression.FileSystem diff --git a/eng/common/sdl/packages.config b/eng/common/sdl/packages.config index 256ffbfb93a306..968b39bef5f193 100644 --- a/eng/common/sdl/packages.config +++ b/eng/common/sdl/packages.config @@ -1,4 +1,4 @@ - + diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml index 640f2b04e240f9..c64c4f5686cbfa 100644 --- a/eng/common/templates/job/execute-sdl.yml +++ b/eng/common/templates/job/execute-sdl.yml @@ -6,6 +6,7 @@ parameters: # 'continueOnError', the parameter value is not correctly picked up. # This can also be remedied by the caller (post-build.yml) if it does not use a nested parameter sdlContinueOnError: false # optional: determines whether to continue the build if the step errors; + downloadArtifacts: true # optional: determines if the artifacts should be dowloaded dependsOn: '' # Optional: dependencies of the job artifactNames: '' # Optional: patterns supplied to DownloadBuildArtifacts # Usage: @@ -31,8 +32,20 @@ jobs: steps: - checkout: self clean: true - - ${{ if ne(parameters.artifactNames, '') }}: - - ${{ each artifactName in parameters.artifactNames }}: + - ${{ if ne(parameters.downloadArtifacts, 'false')}}: + - ${{ if ne(parameters.artifactNames, '') }}: + - ${{ each artifactName in parameters.artifactNames }}: + - task: DownloadBuildArtifacts@0 + displayName: Download Build Artifacts + inputs: + buildType: specific + buildVersionToDownload: specific + project: $(AzDOProjectName) + pipeline: $(AzDOPipelineId) + buildId: $(AzDOBuildId) + artifactName: ${{ artifactName }} + downloadPath: $(Build.ArtifactStagingDirectory)\artifacts + - ${{ if eq(parameters.artifactNames, '') }}: - task: DownloadBuildArtifacts@0 displayName: Download Build Artifacts inputs: @@ -41,20 +54,9 @@ jobs: project: $(AzDOProjectName) pipeline: $(AzDOPipelineId) buildId: $(AzDOBuildId) - artifactName: ${{ artifactName }} + downloadType: specific files + itemPattern: "**" downloadPath: $(Build.ArtifactStagingDirectory)\artifacts - - ${{ if eq(parameters.artifactNames, '') }}: - - task: DownloadBuildArtifacts@0 - displayName: Download Build Artifacts - inputs: - buildType: specific - buildVersionToDownload: specific - project: $(AzDOProjectName) - pipeline: $(AzDOPipelineId) - buildId: $(AzDOBuildId) - downloadType: specific files - itemPattern: "**" - downloadPath: $(Build.ArtifactStagingDirectory)\artifacts - powershell: eng/common/sdl/extract-artifact-packages.ps1 -InputPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts @@ -81,7 +83,7 @@ jobs: continueOnError: ${{ parameters.sdlContinueOnError }} - ${{ if eq(parameters.overrideParameters, '') }}: - powershell: eng/common/sdl/execute-all-sdl-tools.ps1 - -GuardianPackageName Microsoft.Guardian.Cli.0.7.2 + -GuardianPackageName Microsoft.Guardian.Cli.win10-x64.0.20.1 -NugetPackageDirectory $(Build.SourcesDirectory)\.packages -AzureDevOpsAccessToken $(dn-bot-dotnet-build-rw-code-rw) ${{ parameters.additionalParameters }} diff --git a/eng/common/templates/job/job.yml b/eng/common/templates/job/job.yml index 536c15c4641c18..fc39647f4b1d0f 100644 --- a/eng/common/templates/job/job.yml +++ b/eng/common/templates/job/job.yml @@ -24,6 +24,7 @@ parameters: enablePublishBuildAssets: false enablePublishTestResults: false enablePublishUsingPipelines: false + useBuildManifest: false mergeTestResults: false testRunTitle: $(AgentOsName)-$(BuildConfiguration)-xunit name: '' @@ -218,3 +219,12 @@ jobs: ArtifactName: AssetManifests continueOnError: ${{ parameters.continueOnError }} condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true')) + + - ${{ if eq(parameters.useBuildManifest, true) }}: + - task: PublishBuildArtifacts@1 + displayName: Publish Build Manifest + inputs: + PathToPublish: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/manifest.props' + PublishLocation: Container + ArtifactName: BuildManifests + continueOnError: ${{ parameters.continueOnError }} diff --git a/eng/common/templates/post-build/channels/generic-internal-channel.yml b/eng/common/templates/post-build/channels/generic-internal-channel.yml index dde27800c3f268..258ba4b7706d96 100644 --- a/eng/common/templates/post-build/channels/generic-internal-channel.yml +++ b/eng/common/templates/post-build/channels/generic-internal-channel.yml @@ -23,7 +23,7 @@ stages: - job: publish_symbols displayName: Symbol Publishing dependsOn: setupMaestroVars - condition: or(contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], format('[{0}]', ${{ parameters.channelId }} )), eq(dependencies.setupMaestroVars.outputs['setReleaseVars.PromoteToMaestroChannelId'], ${{ parameters.channelId }})) + condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} )) variables: - group: DotNet-Symbol-Server-Pats - name: AzDOProjectName @@ -96,7 +96,7 @@ stages: value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] - name: AzDOBuildId value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] - condition: or(contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], format('[{0}]', ${{ parameters.channelId }} )), eq(dependencies.setupMaestroVars.outputs['setReleaseVars.PromoteToMaestroChannelId'], ${{ parameters.channelId }})) + condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} )) pool: vmImage: 'windows-2019' steps: diff --git a/eng/common/templates/post-build/channels/generic-public-channel.yml b/eng/common/templates/post-build/channels/generic-public-channel.yml index 08853ec45e0c1f..bf98d990e88ef7 100644 --- a/eng/common/templates/post-build/channels/generic-public-channel.yml +++ b/eng/common/templates/post-build/channels/generic-public-channel.yml @@ -25,7 +25,7 @@ stages: - job: publish_symbols displayName: Symbol Publishing dependsOn: setupMaestroVars - condition: or(contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], format('[{0}]', ${{ parameters.channelId }} )), eq(dependencies.setupMaestroVars.outputs['setReleaseVars.PromoteToMaestroChannelId'], ${{ parameters.channelId }})) + condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} )) variables: - group: DotNet-Symbol-Server-Pats - name: AzDOProjectName @@ -99,7 +99,7 @@ stages: value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] - name: ArtifactsCategory value: ${{ coalesce(variables._DotNetArtifactsCategory, '.NETCore') }} - condition: or(contains(dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'], format('[{0}]', ${{ parameters.channelId }} )), eq(dependencies.setupMaestroVars.outputs['setReleaseVars.PromoteToMaestroChannelId'], ${{ parameters.channelId }})) + condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} )) pool: vmImage: 'windows-2019' steps: diff --git a/eng/common/templates/post-build/common-variables.yml b/eng/common/templates/post-build/common-variables.yml index 867f37cd875885..c99fd7503767cd 100644 --- a/eng/common/templates/post-build/common-variables.yml +++ b/eng/common/templates/post-build/common-variables.yml @@ -63,7 +63,7 @@ variables: - name: MaestroApiAccessToken value: $(MaestroAccessToken) - name: MaestroApiVersion - value: "2019-01-16" + value: "2020-02-20" - name: SourceLinkCLIVersion value: 3.0.0 diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml index fbab4cb5dce058..b51bc5375ecf0d 100644 --- a/eng/common/templates/post-build/post-build.yml +++ b/eng/common/templates/post-build/post-build.yml @@ -9,12 +9,14 @@ parameters: continueOnError: false params: '' artifactNames: '' + downloadArtifacts: true # These parameters let the user customize the call to sdk-task.ps1 for publishing # symbols & general artifacts as well as for signing validation symbolPublishingAdditionalParameters: '' artifactsPublishingAdditionalParameters: '' signingValidationAdditionalParameters: '' + useBuildManifest: false # Which stages should finish execution before post-build stages start validateDependsOn: @@ -35,10 +37,13 @@ parameters: NETCoreExperimentalChannelId: 562 NetEngServicesIntChannelId: 678 NetEngServicesProdChannelId: 679 - Net5Preview2ChannelId: 738 Net5Preview3ChannelId: 739 + Net5Preview4ChannelId: 856 + Net5Preview5ChannelId: 857 NetCoreSDK313xxChannelId: 759 NetCoreSDK313xxInternalChannelId: 760 + NetCoreSDK314xxChannelId: 921 + NetCoreSDK314xxInternalChannelId: 922 stages: - stage: Validate @@ -53,10 +58,8 @@ stages: displayName: Post-build Checks dependsOn: setupMaestroVars variables: - - name: InitialChannels - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.InitialChannels'] ] - - name: PromoteToMaestroChannelId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.PromoteToMaestroChannelId'] ] + - name: TargetChannels + value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'] ] pool: vmImage: 'windows-2019' steps: @@ -64,8 +67,8 @@ stages: displayName: Maestro Channels Consistency inputs: filePath: $(Build.SourcesDirectory)/eng/common/post-build/check-channel-consistency.ps1 - arguments: -PromoteToChannels "$(InitialChannels)[$(PromoteToMaestroChannelId)]" - -AvailableChannelIds ${{parameters.NetEngLatestChannelId}},${{parameters.NetEngValidationChannelId}},${{parameters.NetDev5ChannelId}},${{parameters.GeneralTestingChannelId}},${{parameters.NETCoreToolingDevChannelId}},${{parameters.NETCoreToolingReleaseChannelId}},${{parameters.NETInternalToolingChannelId}},${{parameters.NETCoreExperimentalChannelId}},${{parameters.NetEngServicesIntChannelId}},${{parameters.NetEngServicesProdChannelId}},${{parameters.Net5Preview2ChannelId}},${{parameters.Net5Preview3ChannelId}},${{parameters.NetCoreSDK313xxChannelId}},${{parameters.NetCoreSDK313xxInternalChannelId}} + arguments: -PromoteToChannels "$(TargetChannels)" + -AvailableChannelIds ${{parameters.NetEngLatestChannelId}},${{parameters.NetEngValidationChannelId}},${{parameters.NetDev5ChannelId}},${{parameters.GeneralTestingChannelId}},${{parameters.NETCoreToolingDevChannelId}},${{parameters.NETCoreToolingReleaseChannelId}},${{parameters.NETInternalToolingChannelId}},${{parameters.NETCoreExperimentalChannelId}},${{parameters.NetEngServicesIntChannelId}},${{parameters.NetEngServicesProdChannelId}},${{parameters.Net5Preview3ChannelId}},${{parameters.Net5Preview4ChannelId}},${{parameters.Net5Preview5ChannelId}},${{parameters.NetCoreSDK313xxChannelId}},${{parameters.NetCoreSDK313xxInternalChannelId}},${{parameters.NetCoreSDK314xxChannelId}},${{parameters.NetCoreSDK314xxInternalChannelId}} - job: displayName: NuGet Validation @@ -113,6 +116,16 @@ stages: pool: vmImage: 'windows-2019' steps: + - ${{ if eq(parameters.useBuildManifest, true) }}: + - task: DownloadBuildArtifacts@0 + displayName: Download build manifest + inputs: + buildType: specific + buildVersionToDownload: specific + project: $(AzDOProjectName) + pipeline: $(AzDOPipelineId) + buildId: $(AzDOBuildId) + artifactName: BuildManifests - task: DownloadBuildArtifacts@0 displayName: Download Package Artifacts inputs: @@ -135,11 +148,13 @@ stages: filePath: eng\common\enable-cross-org-publishing.ps1 arguments: -token $(dn-bot-dnceng-artifact-feeds-rw) + # Signing validation will optionally work with the buildmanifest file which is downloaded from + # Azure DevOps above. - task: PowerShell@2 displayName: Validate inputs: filePath: eng\common\sdk-task.ps1 - arguments: -task SigningValidation -restore -msbuildEngine dotnet + arguments: -task SigningValidation -restore -msbuildEngine vs /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts' /p:SignCheckExclusionsFile='$(Build.SourcesDirectory)/eng/SignCheckExclusionsFile.txt' ${{ parameters.signingValidationAdditionalParameters }} @@ -192,6 +207,7 @@ stages: additionalParameters: ${{ parameters.SDLValidationParameters.params }} continueOnError: ${{ parameters.SDLValidationParameters.continueOnError }} artifactNames: ${{ parameters.SDLValidationParameters.artifactNames }} + downloadArtifacts: ${{ parameters.SDLValidationParameters.downloadArtifacts }} - template: \eng\common\templates\post-build\channels\generic-public-channel.yml parameters: @@ -213,10 +229,10 @@ stages: dependsOn: ${{ parameters.publishDependsOn }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'Net5_Preview2_Publish' - channelName: '.NET 5 Preview 2' - akaMSChannelName: 'net5/preview2' - channelId: ${{ parameters.Net5Preview2ChannelId }} + stageName: 'Net5_Preview3_Publish' + channelName: '.NET 5 Preview 3' + akaMSChannelName: 'net5/preview3' + channelId: ${{ parameters.Net5Preview3ChannelId }} transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-transport/nuget/v3/index.json' shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json' symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-symbols/nuget/v3/index.json' @@ -227,10 +243,24 @@ stages: dependsOn: ${{ parameters.publishDependsOn }} publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} - stageName: 'Net5_Preview3_Publish' - channelName: '.NET 5 Preview 3' - akaMSChannelName: 'net5/preview3' - channelId: ${{ parameters.Net5Preview3ChannelId }} + stageName: 'Net5_Preview4_Publish' + channelName: '.NET 5 Preview 4' + akaMSChannelName: 'net5/preview4' + channelId: ${{ parameters.Net5Preview4ChannelId }} + transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-transport/nuget/v3/index.json' + shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json' + symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-symbols/nuget/v3/index.json' + +- template: \eng\common\templates\post-build\channels\generic-public-channel.yml + parameters: + artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} + dependsOn: ${{ parameters.publishDependsOn }} + publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} + symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} + stageName: 'Net5_Preview5_Publish' + channelName: '.NET 5 Preview 5' + akaMSChannelName: 'net5/preview5' + channelId: ${{ parameters.Net5Preview5ChannelId }} transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-transport/nuget/v3/index.json' shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json' symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-symbols/nuget/v3/index.json' @@ -355,6 +385,32 @@ stages: shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json' symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json' +- template: \eng\common\templates\post-build\channels\generic-public-channel.yml + parameters: + artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} + dependsOn: ${{ parameters.publishDependsOn }} + publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} + symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} + stageName: 'NETCore_SDK_314xx_Publishing' + channelName: '.NET Core SDK 3.1.4xx' + channelId: ${{ parameters.NetCoreSDK314xxChannelId }} + transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-transport/nuget/v3/index.json' + shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1/nuget/v3/index.json' + symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-symbols/nuget/v3/index.json' + +- template: \eng\common\templates\post-build\channels\generic-internal-channel.yml + parameters: + artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} + dependsOn: ${{ parameters.publishDependsOn }} + publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }} + symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }} + stageName: 'NETCore_SDK_314xx_Internal_Publishing' + channelName: '.NET Core SDK 3.1.4xx Internal' + channelId: ${{ parameters.NetCoreSDK314xxInternalChannelId }} + transportFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v3/index.json' + shippingFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v3/index.json' + symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-symbols/nuget/v3/index.json' + - template: \eng\common\templates\post-build\channels\generic-public-channel.yml parameters: artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }} diff --git a/eng/common/templates/post-build/setup-maestro-vars.yml b/eng/common/templates/post-build/setup-maestro-vars.yml index 05e611edb68a2b..b3d29d4498e36a 100644 --- a/eng/common/templates/post-build/setup-maestro-vars.yml +++ b/eng/common/templates/post-build/setup-maestro-vars.yml @@ -5,7 +5,9 @@ jobs: - template: common-variables.yml - name: BuildId value: $[ coalesce(variables.BARBuildId, 0) ] - - name: PromoteToChannelId + - name: PromoteToMaestroChannels + value: $[ coalesce(variables.PromoteToChannelIds, 0) ] + - name: PromoteToMaestroChannel value: $[ coalesce(variables.PromoteToMaestroChannelId, 0) ] pool: vmImage: 'windows-2019' @@ -14,7 +16,7 @@ jobs: - task: DownloadBuildArtifacts@0 displayName: Download Release Configs - condition: eq(variables.PromoteToChannelId, 0) + condition: and(eq(variables.PromoteToMaestroChannels, 0), eq(variables.PromoteToMaestroChannel, 0)) inputs: buildType: current artifactName: ReleaseConfigs @@ -26,20 +28,16 @@ jobs: targetType: inline script: | try { - if ($Env:PromoteToChannelId -eq 0) { + if ($Env:PromoteToMaestroChannels -eq 0 -and $Env:PromoteToMaestroChannel -eq 0) { $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt $BarId = $Content | Select -Index 0 - - $Channels = "" - $Content | Select -Index 1 | ForEach-Object { $Channels += "$_ ," } - + $Channels = $Content | Select -Index 1 $IsStableBuild = $Content | Select -Index 2 $AzureDevOpsProject = $Env:System_TeamProject $AzureDevOpsBuildDefinitionId = $Env:System_DefinitionId $AzureDevOpsBuildId = $Env:Build_BuildId - $PromoteToMaestroChannelId = 0 } else { $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}" @@ -51,25 +49,23 @@ jobs: $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" } $BarId = $Env:BARBuildId - $Channels = 'None' - - #TODO: Fix this once this issue is done: https://github.com/dotnet/arcade/issues/3834 - $IsStableBuild = 'False' + $Channels = $Env:PromoteToMaestroChannels -split "," + $Channels = $Channels -join "][" + $Channels = "[$Channels][$Env:PromoteToMaestroChannel]" + $IsStableBuild = $buildInfo.stable $AzureDevOpsProject = $buildInfo.azureDevOpsProject $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId - $PromoteToMaestroChannelId = $Env:PromoteToMaestroChannelId } Write-Host "##vso[task.setvariable variable=BARBuildId;isOutput=true]$BarId" - Write-Host "##vso[task.setvariable variable=InitialChannels;isOutput=true]$Channels" + Write-Host "##vso[task.setvariable variable=TargetChannels;isOutput=true]$Channels" Write-Host "##vso[task.setvariable variable=IsStableBuild;isOutput=true]$IsStableBuild" Write-Host "##vso[task.setvariable variable=AzDOProjectName;isOutput=true]$AzureDevOpsProject" Write-Host "##vso[task.setvariable variable=AzDOPipelineId;isOutput=true]$AzureDevOpsBuildDefinitionId" Write-Host "##vso[task.setvariable variable=AzDOBuildId;isOutput=true]$AzureDevOpsBuildId" - Write-Host "##vso[task.setvariable variable=PromoteToMaestroChannelId;isOutput=true]$PromoteToMaestroChannelId" } catch { Write-Host $_ diff --git a/eng/common/templates/steps/send-to-helix.yml b/eng/common/templates/steps/send-to-helix.yml index 30becf01ea55a8..5eceb48725dcf5 100644 --- a/eng/common/templates/steps/send-to-helix.yml +++ b/eng/common/templates/steps/send-to-helix.yml @@ -10,7 +10,7 @@ parameters: HelixPostCommands: '' # optional -- commands to run after Helix work item execution WorkItemDirectory: '' # optional -- a payload directory to zip up and send to Helix; requires WorkItemCommand; incompatible with XUnitProjects WorkItemCommand: '' # optional -- a command to execute on the payload; requires WorkItemDirectory; incompatible with XUnitProjects - WorkItemTimeout: '' # optional -- a timeout in seconds for the work item command; requires WorkItemDirectory; incompatible with XUnitProjects + WorkItemTimeout: '' # optional -- a timeout in TimeSpan.Parse-ready value (e.g. 00:02:00) for the work item command; requires WorkItemDirectory; incompatible with XUnitProjects CorrelationPayloadDirectory: '' # optional -- a directory to zip up and send to Helix as a correlation payload XUnitProjects: '' # optional -- semicolon delimited list of XUnitProjects to parse and send to Helix; requires XUnitRuntimeTargetFramework, XUnitPublishTargetFramework, XUnitRunnerVersion, and IncludeDotNetCli=true XUnitWorkItemTimeout: '' # optional -- the workitem timeout in seconds for all workitems created from the xUnit projects specified by XUnitProjects @@ -18,8 +18,8 @@ parameters: XUnitRuntimeTargetFramework: '' # optional -- framework to use for the xUnit console runner XUnitRunnerVersion: '' # optional -- version of the xUnit nuget package you wish to use on Helix; required for XUnitProjects IncludeDotNetCli: false # optional -- true will download a version of the .NET CLI onto the Helix machine as a correlation payload; requires DotNetCliPackageType and DotNetCliVersion - DotNetCliPackageType: '' # optional -- either 'sdk' or 'runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases.json - DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases.json + DotNetCliPackageType: '' # optional -- either 'sdk' or 'runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases-index.json + DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases-index.json EnableXUnitReporter: false # optional -- true enables XUnit result reporting to Mission Control WaitForWorkItemCompletion: true # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is "fire and forget." IsExternal: false # [DEPRECATED] -- doesn't do anything, jobs are external if HelixAccessToken is empty and Creator is set diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 60c1cd89758721..d8dfc5e00498ce 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -7,9 +7,11 @@ # Build configuration. Common values include 'Debug' and 'Release', but the repository may use other names. [string]$configuration = if (Test-Path variable:configuration) { $configuration } else { 'Debug' } +# Set to true to opt out of outputting binary log while running in CI +[bool]$excludeCIBinarylog = if (Test-Path variable:excludeCIBinarylog) { $excludeCIBinarylog } else { $false } + # Set to true to output binary log from msbuild. Note that emitting binary log slows down the build. -# Binary log must be enabled on CI. -[bool]$binaryLog = if (Test-Path variable:binaryLog) { $binaryLog } else { $ci } +[bool]$binaryLog = if (Test-Path variable:binaryLog) { $binaryLog } else { $ci -and !$excludeCIBinarylog } # Set to true to use the pipelines logger which will enable Azure logging output. # https://github.com/Microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md @@ -55,10 +57,8 @@ set-strictmode -version 2.0 $ErrorActionPreference = 'Stop' [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -function Create-Directory([string[]] $path) { - if (!(Test-Path $path)) { - New-Item -path $path -force -itemType 'Directory' | Out-Null - } +function Create-Directory ([string[]] $path) { + New-Item -Path $path -Force -ItemType 'Directory' | Out-Null } function Unzip([string]$zipfile, [string]$outpath) { @@ -488,10 +488,11 @@ function GetNuGetPackageCachePath() { if ($env:NUGET_PACKAGES -eq $null) { # Use local cache on CI to ensure deterministic build, # use global cache in dev builds to avoid cost of downloading packages. + # For directory normalization, see also: https://github.com/NuGet/Home/issues/7968 if ($useGlobalNuGetCache) { - $env:NUGET_PACKAGES = Join-Path $env:UserProfile '.nuget\packages' + $env:NUGET_PACKAGES = Join-Path $env:UserProfile '.nuget\packages\' } else { - $env:NUGET_PACKAGES = Join-Path $RepoRoot '.packages' + $env:NUGET_PACKAGES = Join-Path $RepoRoot '.packages\' } } @@ -546,7 +547,7 @@ function InitializeToolset() { MSBuild-Core $proj $bl /t:__WriteToolsetLocation /clp:ErrorsOnly`;NoSummary /p:__ToolsetLocationOutputFile=$toolsetLocationFile - $path = Get-Content $toolsetLocationFile -TotalCount 1 + $path = Get-Content $toolsetLocationFile -Encoding UTF8 -TotalCount 1 if (!(Test-Path $path)) { throw "Invalid toolset path: $path" } @@ -604,8 +605,8 @@ function MSBuild() { # function MSBuild-Core() { if ($ci) { - if (!$binaryLog) { - Write-PipelineTelemetryError -Category 'Build' -Message 'Binary log must be enabled in CI build.' + if (!$binaryLog -and !$excludeCIBinarylog) { + Write-PipelineTelemetryError -Category 'Build' -Message 'Binary log must be enabled in CI build, or explicitly opted-out from with the -excludeCIBinarylog switch.' ExitWithExitCode 1 } @@ -632,6 +633,8 @@ function MSBuild-Core() { } } + $env:ARCADE_BUILD_TOOL_COMMAND = "$($buildTool.Path) $cmdArgs" + $exitCode = Exec-Process $buildTool.Path $cmdArgs if ($exitCode -ne 0) { diff --git a/eng/common/tools.sh b/eng/common/tools.sh index caae1dbdb273c5..e94fce22ec37ba 100755 --- a/eng/common/tools.sh +++ b/eng/common/tools.sh @@ -18,9 +18,17 @@ fi # Build configuration. Common values include 'Debug' and 'Release', but the repository may use other names. configuration=${configuration:-'Debug'} +# Set to true to opt out of outputting binary log while running in CI +exclude_ci_binary_log=${exclude_ci_binary_log:-false} + +if [[ "$ci" == true && "$exclude_ci_binary_log" == false ]]; then + binary_log_default=true +else + binary_log_default=false +fi + # Set to true to output binary log from msbuild. Note that emitting binary log slows down the build. -# Binary log must be enabled on CI. -binary_log=${binary_log:-$ci} +binary_log=${binary_log:-$binary_log_default} # Turns on machine preparation/clean up code that changes the machine state (e.g. kills build processes). prepare_machine=${prepare_machine:-false} @@ -201,7 +209,14 @@ function InstallDotNet { local runtimeSourceFeedKey='' if [[ -n "${7:-}" ]]; then - decodedFeedKey=`echo $7 | base64 --decode` + # The 'base64' binary on alpine uses '-d' and doesn't support '--decode' + # '-d'. To work around this, do a simple detection and switch the parameter + # accordingly. + decodeArg="--decode" + if base64 --help 2>&1 | grep -q "BusyBox"; then + decodeArg="-d" + fi + decodedFeedKey=`echo $7 | base64 $decodeArg` runtimeSourceFeedKey="--feed-credential $decodedFeedKey" fi @@ -397,8 +412,8 @@ function MSBuild { function MSBuild-Core { if [[ "$ci" == true ]]; then - if [[ "$binary_log" != true ]]; then - Write-PipelineTelemetryError -category 'Build' "Binary log must be enabled in CI build." + if [[ "$binary_log" != true && "$exclude_ci_binary_log" != true ]]; then + Write-PipelineTelemetryError -category 'Build' "Binary log must be enabled in CI build, or explicitly opted-out from with the -noBinaryLog switch." ExitWithExitCode 1 fi @@ -415,11 +430,17 @@ function MSBuild-Core { warnaserror_switch="/warnaserror" fi - "$_InitializeBuildTool" "$_InitializeBuildToolCommand" /m /nologo /clp:Summary /v:$verbosity /nr:$node_reuse $warnaserror_switch /p:TreatWarningsAsErrors=$warn_as_error /p:ContinuousIntegrationBuild=$ci "$@" || { - local exit_code=$? - Write-PipelineTelemetryError -category 'Build' "Build failed (exit code '$exit_code')." - ExitWithExitCode $exit_code + function RunBuildTool { + export ARCADE_BUILD_TOOL_COMMAND="$_InitializeBuildTool $@" + + "$_InitializeBuildTool" "$@" || { + local exit_code=$? + Write-PipelineTaskError "Build failed (exit code '$exit_code')." + ExitWithExitCode $exit_code + } } + + RunBuildTool "$_InitializeBuildToolCommand" /m /nologo /clp:Summary /v:$verbosity /nr:$node_reuse $warnaserror_switch /p:TreatWarningsAsErrors=$warn_as_error /p:ContinuousIntegrationBuild=$ci "$@" } ResolvePath "${BASH_SOURCE[0]}" diff --git a/eng/docker/libraries-sdk-aspnetcore.linux.Dockerfile b/eng/docker/libraries-sdk-aspnetcore.linux.Dockerfile index f352d29cac70c0..422e8e19601558 100644 --- a/eng/docker/libraries-sdk-aspnetcore.linux.Dockerfile +++ b/eng/docker/libraries-sdk-aspnetcore.linux.Dockerfile @@ -14,7 +14,7 @@ RUN ./src/coreclr/build.sh -release -skiptests -clang9 && \ FROM $SDK_BASE_IMAGE as target ARG TESTHOST_LOCATION=/repo/artifacts/bin/testhost -ARG TFM=netcoreapp5.0 +ARG TFM=net5.0 ARG OS=Linux ARG ARCH=x64 ARG CONFIGURATION=Release diff --git a/eng/docker/libraries-sdk-aspnetcore.windows.Dockerfile b/eng/docker/libraries-sdk-aspnetcore.windows.Dockerfile index 59aa7f034f71f0..81c13817d11d91 100644 --- a/eng/docker/libraries-sdk-aspnetcore.windows.Dockerfile +++ b/eng/docker/libraries-sdk-aspnetcore.windows.Dockerfile @@ -4,7 +4,7 @@ ARG SDK_BASE_IMAGE=mcr.microsoft.com/dotnet/core/sdk:3.0.100-nanoserver-1809 FROM $SDK_BASE_IMAGE as target ARG TESTHOST_LOCATION=".\\artifacts\\bin\\testhost" -ARG TFM=netcoreapp5.0 +ARG TFM=net5.0 ARG OS=Windows_NT ARG ARCH=x64 ARG CONFIGURATION=Release diff --git a/eng/docker/libraries-sdk.linux.Dockerfile b/eng/docker/libraries-sdk.linux.Dockerfile index bbfaef49a39d12..8a4abed0b09509 100644 --- a/eng/docker/libraries-sdk.linux.Dockerfile +++ b/eng/docker/libraries-sdk.linux.Dockerfile @@ -13,7 +13,7 @@ RUN ./build.sh -ci -subset clr+libs -runtimeconfiguration release -c $CONFIGURAT FROM $SDK_BASE_IMAGE as target ARG TESTHOST_LOCATION=/repo/artifacts/bin/testhost -ARG TFM=netcoreapp5.0 +ARG TFM=net5.0 ARG OS=Linux ARG ARCH=x64 ARG CONFIGURATION=Release diff --git a/eng/docker/libraries-sdk.windows.Dockerfile b/eng/docker/libraries-sdk.windows.Dockerfile index 5954ae39a0c003..b6393424aad23a 100644 --- a/eng/docker/libraries-sdk.windows.Dockerfile +++ b/eng/docker/libraries-sdk.windows.Dockerfile @@ -4,7 +4,7 @@ ARG SDK_BASE_IMAGE=mcr.microsoft.com/dotnet/core/sdk:3.0.100-nanoserver-1809 FROM $SDK_BASE_IMAGE as target ARG TESTHOST_LOCATION=".\\artifacts\\bin\\testhost" -ARG TFM=netcoreapp5.0 +ARG TFM=net5.0 ARG OS=Windows_NT ARG ARCH=x64 ARG CONFIGURATION=Release diff --git a/eng/empty.csproj b/eng/empty.csproj index 0bd280da02f353..6edde5507fcdaa 100644 --- a/eng/empty.csproj +++ b/eng/empty.csproj @@ -12,4 +12,6 @@ netcoreapp2.0 + + diff --git a/eng/illink.targets b/eng/illink.targets index cecc5c2a5a3699..6ac5e9ac2a1ee0 100644 --- a/eng/illink.targets +++ b/eng/illink.targets @@ -8,8 +8,8 @@ - - $([MSBuild]::NormalizeDirectory('$(PkgILLink_Tasks)', 'tools')) + $([MSBuild]::NormalizeDirectory('$(PkgMicrosoft_NET_ILLink_Tasks)', 'tools')) $(ILLinkTasksDir)netcoreapp3.0/ILLink.Tasks.dll $(ILLinkTasksDir)$(NetFrameworkCurrent)/ILLink.Tasks.dll $(IntermediateOutputPath)$(TargetName)$(TargetExt) @@ -29,6 +29,8 @@ $(IntermediateOutputPath) $(MSBuildProjectDirectory)/ILLinkTrim.xml + + $(MSBuildProjectDirectory)/ILLinkTrim_LibraryBuild.xml true @@ -40,6 +42,10 @@ + + + + @@ -87,7 +93,9 @@ $(ILLinkArgs) -v true - $(ILLinkArgs) --strip-resources false + $(ILLinkArgs) --strip-descriptors false + + $(ILLinkArgs) -x "$(ILLinkTrimXmlLibraryBuild)" $(ILLinkArgs) --skip-unresolved true diff --git a/eng/install-native-dependencies.sh b/eng/install-native-dependencies.sh old mode 100644 new mode 100755 index 9670ae590314cd..00be5a6287289f --- a/eng/install-native-dependencies.sh +++ b/eng/install-native-dependencies.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env sh +#!/usr/bin/env bash if [ "$1" = "Linux" ]; then sudo apt update @@ -9,37 +9,9 @@ if [ "$1" = "Linux" ]; then if [ "$?" != "0" ]; then exit 1; fi -elif [ "$1" = "OSX" ]; then - brew update - brew upgrade - if [ "$?" != "0" ]; then - exit 1; - fi - brew install icu4c openssl autoconf automake libtool pkg-config python3 - if [ "$?" != "0" ]; then - exit 1; - fi - brew link --force icu4c - if [ "$?" != "0" ]; then - exit 1; - fi -elif [ "$1" = "tvOS" ]; then - brew update - brew upgrade - if [ "$?" != "0" ]; then - exit 1; - fi - brew install openssl autoconf automake libtool pkg-config python3 - if [ "$?" != "0" ]; then - exit 1; - fi -elif [ "$1" = "iOS" ]; then - brew update - brew upgrade - if [ "$?" != "0" ]; then - exit 1; - fi - brew install openssl autoconf automake libtool pkg-config python3 +elif [ "$1" = "OSX" ] || [ "$1" = "tvOS" ] || [ "$1" = "iOS" ]; then + engdir=$(dirname "${BASH_SOURCE[0]}") + brew bundle --no-lock --file "${engdir}/Brewfile" if [ "$?" != "0" ]; then exit 1; fi diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets index e01739925eb8ea..42cae8568797aa 100644 --- a/eng/liveBuilds.targets +++ b/eng/liveBuilds.targets @@ -76,11 +76,12 @@ x64 x86 x64 + x64 - - + + $([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)')) @@ -133,18 +134,18 @@ true - - - + - - + + - - - + + + + + - - + + diff --git a/eng/native/build-commons.sh b/eng/native/build-commons.sh index a1a975ce177348..c231a01d429570 100755 --- a/eng/native/build-commons.sh +++ b/eng/native/build-commons.sh @@ -53,10 +53,23 @@ check_prereqs() function version { echo "$@" | awk -F. '{ printf("%d%02d%02d\n", $1,$2,$3); }'; } - local cmake_version="$(cmake --version | awk '/^cmake version [0-9]+\.[0-9]+\.[0-9]+$/ {print $3}')" + local cmake_version="$(cmake --version | awk '/^cmake.* version [0-9]+\.[0-9]+\.[0-9]+$/ {print $3}')" if [[ "$(version "$cmake_version")" -lt "$(version 3.14.2)" ]]; then - echo "Please install CMake 3.14.2 or newer from http://www.cmake.org/download/ or https://apt.kitware.com and ensure it is on your path."; exit 1; + echo "Please install CMake 3.14.2 or newer from https://cmake.org/download/ or https://apt.kitware.com and ensure it is on your path."; exit 1; + fi + + if [[ "$__HostOS" == "OSX" ]]; then + # Check presence of pkg-config on the path + command -v pkg-config 2>/dev/null || { echo >&2 "Please install pkg-config before running this script, see https://github.com/dotnet/runtime/blob/master/docs/workflow/requirements/macos-requirements.md"; exit 1; } + + if ! pkg-config openssl ; then + # We export the proper PKG_CONFIG_PATH where openssl was installed by Homebrew + # It's important to _export_ it since build-commons.sh is sourced by other scripts such as build-native.sh + export PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig + # We try again with the PKG_CONFIG_PATH in place, if pkg-config still can't find OpenSSL, exit with an error, cmake won't find OpenSSL either + pkg-config openssl || { echo >&2 "Please install openssl before running this script, see https://github.com/dotnet/runtime/blob/master/docs/workflow/requirements/macos-requirements.md"; exit 1; } + fi fi if [[ "$__UseNinja" == 1 ]]; then @@ -82,6 +95,7 @@ build_native() buildTool="make" fi + runtimeVersionHeaderFile="$intermediatesDir/../runtime_version.h" if [[ "$__SkipConfigure" == 0 ]]; then # if msbuild is not supported, then set __SkipGenerateVersion to 1 if [[ "$__IsMSBuildOnNETCoreSupported" == 0 ]]; then __SkipGenerateVersion=1; fi @@ -95,7 +109,8 @@ build_native() if [[ "$__SkipGenerateVersion" == 0 ]]; then "$__RepoRootDir/eng/common/msbuild.sh" /clp:nosummary "$__ArcadeScriptArgs" "$__RepoRootDir"/eng/empty.csproj \ /p:NativeVersionFile="$__versionSourceFile" \ - /t:GenerateNativeVersionFile /restore \ + /p:RuntimeVersionFile="$runtimeVersionHeaderFile" \ + /t:GenerateRuntimeVersionFile /restore \ $__CommonMSBuildArgs $__binlogArg $__UnprocessedBuildArgs local exit_code="$?" if [[ "$exit_code" != 0 ]]; then @@ -103,12 +118,24 @@ build_native() exit "$exit_code" fi else - # Generate the dummy version.c, but only if it didn't exist to make sure we don't trigger unnecessary rebuild + # Generate the dummy version.c and runtime_version.h, but only if they didn't exist to make sure we don't trigger unnecessary rebuild __versionSourceLine="static char sccsid[] __attribute__((used)) = \"@(#)No version information produced\";" if [[ -e "$__versionSourceFile" ]]; then read existingVersionSourceLine < "$__versionSourceFile" fi if [[ "$__versionSourceLine" != "$existingVersionSourceLine" ]]; then + cat << EOF > $runtimeVersionHeaderFile +#define RuntimeAssemblyMajorVersion 0 +#define RuntimeAssemblyMinorVersion 0 +#define RuntimeFileMajorVersion 0 +#define RuntimeFileMinorVersion 0 +#define RuntimeFileBuildVersion 0 +#define RuntimeFileRevisionVersion 0 +#define RuntimeProductMajorVersion 0 +#define RuntimeProductMinorVersion 0 +#define RuntimeProductPatchVersion 0 +#define RuntimeProductVersion +EOF echo "$__versionSourceLine" > "$__versionSourceFile" fi fi @@ -382,7 +409,7 @@ done # Get the number of processors available to the scheduler # Other techniques such as `nproc` only get the number of # processors available to a single process. -platform=$(uname) +platform="$(uname)" if [[ "$platform" == "FreeBSD" ]]; then __NumProc=$(sysctl hw.ncpu | awk '{ print $2+1 }') elif [[ "$platform" == "NetBSD" || "$platform" == "SunOS" ]]; then diff --git a/eng/native/configurecompiler.cmake b/eng/native/configurecompiler.cmake index 2937916ced91b2..a6e6ba45808d2c 100644 --- a/eng/native/configurecompiler.cmake +++ b/eng/native/configurecompiler.cmake @@ -183,10 +183,10 @@ elseif(CLR_CMAKE_HOST_FREEBSD) add_compile_options($<$:-Wa,--noexecstack>) add_link_options(LINKER:--build-id=sha1) elseif(CLR_CMAKE_HOST_SUNOS) - set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} /opt/local/include) - set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /opt/local/lib) + add_compile_options($<$:-Wa,--noexecstack>) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector") + add_definitions(-D__EXTENSIONS__) endif() #------------------------------------ @@ -227,15 +227,13 @@ if (CLR_CMAKE_HOST_UNIX) if(CLR_CMAKE_HOST_OSX) message("Detected OSX x86_64") - endif(CLR_CMAKE_HOST_OSX) - - if(CLR_CMAKE_HOST_FREEBSD) + elseif(CLR_CMAKE_HOST_FREEBSD) message("Detected FreeBSD amd64") - endif(CLR_CMAKE_HOST_FREEBSD) - - if(CLR_CMAKE_HOST_NETBSD) + elseif(CLR_CMAKE_HOST_NETBSD) message("Detected NetBSD amd64") - endif(CLR_CMAKE_HOST_NETBSD) + elseif(CLR_CMAKE_HOST_SUNOS) + message("Detected SunOS amd64") + endif(CLR_CMAKE_HOST_OSX) endif(CLR_CMAKE_HOST_UNIX) if (CLR_CMAKE_HOST_WIN32) @@ -367,17 +365,15 @@ if(CLR_CMAKE_TARGET_UNIX) add_definitions(-DDISABLE_CONTRACTS) if(CLR_CMAKE_TARGET_OSX) add_definitions(-DTARGET_OSX) - endif(CLR_CMAKE_TARGET_OSX) - if(CLR_CMAKE_TARGET_FREEBSD) + elseif(CLR_CMAKE_TARGET_FREEBSD) add_definitions(-DTARGET_FREEBSD) - endif(CLR_CMAKE_TARGET_FREEBSD) - if(CLR_CMAKE_TARGET_LINUX) + elseif(CLR_CMAKE_TARGET_LINUX) add_definitions(-DTARGET_LINUX) - endif(CLR_CMAKE_TARGET_LINUX) - if(CLR_CMAKE_TARGET_NETBSD) + elseif(CLR_CMAKE_TARGET_NETBSD) add_definitions(-DTARGET_NETBSD) - endif(CLR_CMAKE_TARGET_NETBSD) - if(CLR_CMAKE_TARGET_ANDROID) + elseif(CLR_CMAKE_TARGET_SUNOS) + add_definitions(-DTARGET_SUNOS) + elseif(CLR_CMAKE_TARGET_ANDROID) add_definitions(-DTARGET_ANDROID) endif() else(CLR_CMAKE_TARGET_UNIX) diff --git a/eng/native/configureplatform.cmake b/eng/native/configureplatform.cmake index 1c5254d84965a8..04fdfaed45a99d 100644 --- a/eng/native/configureplatform.cmake +++ b/eng/native/configureplatform.cmake @@ -88,6 +88,8 @@ if(CLR_CMAKE_HOST_OS STREQUAL iOS) set(CLR_CMAKE_HOST_IOS 1) if(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64") set(CLR_CMAKE_HOST_UNIX_AMD64 1) + elseif(CMAKE_OSX_ARCHITECTURES MATCHES "i386") + set(CLR_CMAKE_HOST_UNIX_X86 1) elseif(CMAKE_OSX_ARCHITECTURES MATCHES "armv7") set(CLR_CMAKE_HOST_UNIX_ARM 1) elseif(CMAKE_OSX_ARCHITECTURES MATCHES "arm64") @@ -168,6 +170,7 @@ endif(CLR_CMAKE_HOST_OS STREQUAL Windows) if(CLR_CMAKE_HOST_OS STREQUAL Emscripten) #set(CLR_CMAKE_HOST_UNIX 1) # TODO: this should be reenabled but it activates a bunch of additional compiler flags in configurecompiler.cmake set(CLR_CMAKE_HOST_UNIX_WASM 1) + set(CLR_CMAKE_HOST_BROWSER 1) endif(CLR_CMAKE_HOST_OS STREQUAL Emscripten) #-------------------------------------------- @@ -315,7 +318,7 @@ endif(CLR_CMAKE_TARGET_OS STREQUAL SunOS) if(CLR_CMAKE_TARGET_OS STREQUAL Emscripten) set(CLR_CMAKE_TARGET_UNIX 1) set(CLR_CMAKE_TARGET_LINUX 1) - set(CLR_CMAKE_TARGET_EMSCRIPTEN 1) + set(CLR_CMAKE_TARGET_BROWSER 1) endif(CLR_CMAKE_TARGET_OS STREQUAL Emscripten) if(CLR_CMAKE_TARGET_UNIX) @@ -357,7 +360,7 @@ else() endif() endif() -if(NOT CLR_CMAKE_TARGET_EMSCRIPTEN) +if(NOT CLR_CMAKE_TARGET_BROWSER) # Skip check_pie_supported call on Android as ld from llvm toolchain with NDK API level 21 # complains about missing linker flag `-no-pie` (while level 28's ld does support this flag, # but since we know that PIE is supported, we can safely skip this redundant check). diff --git a/eng/native/configuretools.cmake b/eng/native/configuretools.cmake index b63ab0f1a66d5a..4fb94531d76987 100644 --- a/eng/native/configuretools.cmake +++ b/eng/native/configuretools.cmake @@ -6,7 +6,7 @@ if (CMAKE_C_COMPILER MATCHES "-?[0-9]+(\.[0-9]+)?$") set(CLR_CMAKE_COMPILER_FILE_NAME_VERSION "${CMAKE_MATCH_0}") endif() -if(NOT WIN32 AND NOT CLR_CMAKE_TARGET_ARCH_WASM) +if(NOT WIN32 AND NOT CLR_CMAKE_TARGET_BROWSER) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") if(APPLE) set(TOOLSET_PREFIX "") diff --git a/eng/native/functions.cmake b/eng/native/functions.cmake index 9a5014917ec61c..49b0064499eb42 100644 --- a/eng/native/functions.cmake +++ b/eng/native/functions.cmake @@ -175,8 +175,8 @@ function(generate_exports_file) add_custom_command( OUTPUT ${outputFilename} - COMMAND ${AWK} -f ${CMAKE_SOURCE_DIR}/${AWK_SCRIPT} ${INPUT_LIST} >${outputFilename} - DEPENDS ${INPUT_LIST} ${CMAKE_SOURCE_DIR}/${AWK_SCRIPT} + COMMAND ${AWK} -f ${CLR_ENG_NATIVE_DIR}/${AWK_SCRIPT} ${INPUT_LIST} >${outputFilename} + DEPENDS ${INPUT_LIST} ${CLR_ENG_NATIVE_DIR}/${AWK_SCRIPT} COMMENT "Generating exports file ${outputFilename}" ) set_source_files_properties(${outputFilename} @@ -196,8 +196,8 @@ function(generate_exports_file_prefix inputFilename outputFilename prefix) add_custom_command( OUTPUT ${outputFilename} - COMMAND ${AWK} -f ${CMAKE_SOURCE_DIR}/${AWK_SCRIPT} ${AWK_VARS} ${inputFilename} >${outputFilename} - DEPENDS ${inputFilename} ${CMAKE_SOURCE_DIR}/${AWK_SCRIPT} + COMMAND ${AWK} -f ${CLR_ENG_NATIVE_DIR}/${AWK_SCRIPT} ${AWK_VARS} ${inputFilename} >${outputFilename} + DEPENDS ${inputFilename} ${CLR_ENG_NATIVE_DIR}/${AWK_SCRIPT} COMMENT "Generating exports file ${outputFilename}" ) set_source_files_properties(${outputFilename} @@ -268,13 +268,20 @@ function(strip_symbols targetName outputFilename) message(FATAL_ERROR "strip not found") endif() + string(TOLOWER "${CMAKE_BUILD_TYPE}" LOWERCASE_CMAKE_BUILD_TYPE) + if (LOWERCASE_CMAKE_BUILD_TYPE STREQUAL release) + set(strip_command ${STRIP} -S ${strip_source_file}) + else () + set(strip_command) + endif () + add_custom_command( TARGET ${targetName} POST_BUILD VERBATIM COMMAND ${DSYMUTIL} --flat --minimize ${strip_source_file} - COMMAND ${STRIP} -S ${strip_source_file} - COMMENT Stripping symbols from ${strip_source_file} into file ${strip_destination_file} + COMMAND ${strip_command} + COMMENT "Stripping symbols from ${strip_source_file} into file ${strip_destination_file}" ) else (CLR_CMAKE_TARGET_OSX OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS) set(strip_destination_file ${strip_source_file}.dbg) @@ -286,7 +293,7 @@ function(strip_symbols targetName outputFilename) COMMAND ${CMAKE_OBJCOPY} --only-keep-debug ${strip_source_file} ${strip_destination_file} COMMAND ${CMAKE_OBJCOPY} --strip-debug ${strip_source_file} COMMAND ${CMAKE_OBJCOPY} --add-gnu-debuglink=${strip_destination_file} ${strip_source_file} - COMMENT Stripping symbols from ${strip_source_file} into file ${strip_destination_file} + COMMENT "Stripping symbols from ${strip_source_file} into file ${strip_destination_file}" ) endif (CLR_CMAKE_TARGET_OSX OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS) @@ -338,7 +345,7 @@ function(install_clr) if (NOT DEFINED CLR_CROSS_COMPONENTS_LIST OR NOT ${INDEX} EQUAL -1) strip_symbols(${targetName} symbol_file) - foreach(destination in ${destinations}) + foreach(destination ${destinations}) # We don't need to install the export libraries for our DLLs # since they won't be directly linked against. install(PROGRAMS $ DESTINATION ${destination}) @@ -415,3 +422,28 @@ endfunction() function(add_executable_clr) _add_executable(${ARGV}) endfunction() + +function(generate_module_index Target ModuleIndexFile) + if(CLR_CMAKE_HOST_WIN32) + set(scriptExt ".cmd") + else() + set(scriptExt ".sh") + endif() + + add_custom_command( + OUTPUT ${ModuleIndexFile} + COMMAND ${CLR_ENG_NATIVE_DIR}/genmoduleindex${scriptExt} $ ${ModuleIndexFile} + DEPENDS ${Target} + COMMENT "Generating ${Target} module index file -> ${ModuleIndexFile}" + ) + + set_source_files_properties( + ${ModuleIndexFile} + PROPERTIES GENERATED TRUE + ) + + add_custom_target( + ${Target}_module_index_header + DEPENDS ${ModuleIndexFile} + ) +endfunction(generate_module_index) diff --git a/src/coreclr/generateexportedsymbols.awk b/eng/native/generateexportedsymbols.awk similarity index 100% rename from src/coreclr/generateexportedsymbols.awk rename to eng/native/generateexportedsymbols.awk diff --git a/src/coreclr/generateversionscript.awk b/eng/native/generateversionscript.awk similarity index 100% rename from src/coreclr/generateversionscript.awk rename to eng/native/generateversionscript.awk diff --git a/eng/native/genmoduleindex.cmd b/eng/native/genmoduleindex.cmd new file mode 100644 index 00000000000000..a6be851461a695 --- /dev/null +++ b/eng/native/genmoduleindex.cmd @@ -0,0 +1,25 @@ +@echo off +REM Generate module index header + +if [%1]==[] goto :Usage +if [%2]==[] goto :Usage + +setlocal +for /f "tokens=1" %%i in ('dumpbin /HEADERS %1 ^| findstr /c:"size of image"') do set imagesize=%%i +REM Pad the extracted size to 8 hex digits +set imagesize=00000000%imagesize% +set imagesize=%imagesize:~-8% + +for /f "tokens=1" %%i in ('dumpbin /HEADERS %1 ^| findstr /c:"time date"') do set timestamp=%%i +REM Pad the extracted time stamp to 8 hex digits +set timestamp=00000000%timestamp% +set timestamp=%timestamp:~-8% + +echo 0x08, 0x%timestamp:~6,2%, 0x%timestamp:~4,2%, 0x%timestamp:~2,2%, 0x%timestamp:~0,2%, 0x%imagesize:~6,2%, 0x%imagesize:~4,2%, 0x%imagesize:~2,2%, 0x%imagesize:~0,2%, > %2 + +endlocal +exit /b 0 + +:Usage +echo Usage: genmoduleindex.cmd ModuleBinaryFile IndexHeaderFile +exit /b 1 diff --git a/eng/native/genmoduleindex.sh b/eng/native/genmoduleindex.sh new file mode 100755 index 00000000000000..77ead1cc8bd86b --- /dev/null +++ b/eng/native/genmoduleindex.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# +# Generate module index header +# +set -euo pipefail + +if [[ "$#" -lt 2 ]]; then + echo "Usage: genmoduleindex.sh ModuleBinaryFile IndexHeaderFile" + exit 1 +fi + +OSName=$(uname -s) + +case "$OSName" in +Darwin) + # Extract the build id and prefix it with its length in bytes + dwarfdump -u $1 | + awk '/UUID:/ { gsub(/\-/,"", $2); printf("%02x", length($2)/2); print $2}' | + # Convert each byte of the id to 0x prefixed constant followed by comma + sed -E s/\(\.\.\)/0x\\1,\ /g > $2 + ;; +*) + # Extract the build id and prefix it with its length in bytes + readelf -n $1 | + awk '/Build ID:/ { printf("%02x", length($3)/2); print $3 }' | + # Convert each byte of the id to 0x prefixed constant followed by comma + sed -E s/\(\.\.\)/0x\\1,\ /g > $2 + ;; +esac diff --git a/eng/native/init-distro-rid.sh b/eng/native/init-distro-rid.sh index 3c875a3e28b96f..22efd8e8b5423f 100644 --- a/eng/native/init-distro-rid.sh +++ b/eng/native/init-distro-rid.sh @@ -137,7 +137,7 @@ initDistroRidGlobal() initNonPortableDistroRid "${targetOs}" "${buildArch}" "${isPortable}" "${rootfsDir}" if [ "$buildArch" = "wasm" ]; then - __DistroRid=WebAssembly-wasm + __DistroRid=browser-wasm export __DistroRid fi @@ -165,6 +165,8 @@ initDistroRidGlobal() distroRid="ios-$buildArch" elif [ "$targetOs" = "Android" ]; then distroRid="android-$buildArch" + elif [ "$targetOs" = "Browser" ]; then + distroRid="browser-$buildArch" elif [ "$targetOs" = "FreeBSD" ]; then distroRid="freebsd-$buildArch" elif [ "$targetOs" = "SunOS" ]; then diff --git a/eng/notSupported.SourceBuild.targets b/eng/notSupported.SourceBuild.targets index afbbdd32de4047..743c4a3ace00bc 100644 --- a/eng/notSupported.SourceBuild.targets +++ b/eng/notSupported.SourceBuild.targets @@ -3,7 +3,11 @@ BeforeTargets="BeforeCompile" Condition="'$(DotNetBuildFromSource)' == 'true' and ('$(GeneratePlatformNotSupportedAssembly)' == 'true' or '$(GeneratePlatformNotSupportedAssemblyMessage)' != '')"> - + + + $(IntermediateOutputPath) + + diff --git a/eng/outerBuild.targets b/eng/outerBuild.targets index dd546d6bd6f6bc..2c529a56aa2f91 100644 --- a/eng/outerBuild.targets +++ b/eng/outerBuild.targets @@ -1,7 +1,7 @@ - + diff --git a/eng/pipelines/common/global-build-job.yml b/eng/pipelines/common/global-build-job.yml index b5140477a7f35d..29071209e79dc1 100644 --- a/eng/pipelines/common/global-build-job.yml +++ b/eng/pipelines/common/global-build-job.yml @@ -25,22 +25,27 @@ jobs: variables: ${{ parameters.variables }} steps: - - ${{ if eq(parameters.osGroup, 'OSX') }}: - - script: | - $(setScriptToEchoAndFailOnNonZero) - brew install pkgconfig icu4c openssl autoconf automake libtool pkg-config python3 - brew link --force icu4c - ln -s /usr/local/opt/openssl/lib/pkgconfig/libcrypto.pc /usr/local/lib/pkgconfig/ - ln -s /usr/local/opt/openssl/lib/pkgconfig/libssl.pc /usr/local/lib/pkgconfig/ - ln -s /usr/local/opt/openssl/lib/pkgconfig/openssl.pc /usr/local/lib/pkgconfig/ + - template: /eng/pipelines/common/clone-checkout-bundle-step.yml + + - ${{ if in(parameters.osGroup, 'OSX', 'iOS', 'tvOS') }}: + - script: $(Build.SourcesDirectory)/eng/install-native-dependencies.sh ${{ parameters.osGroup }} displayName: Install Build Dependencies - - template: /eng/pipelines/common/clone-checkout-bundle-step.yml + - script: | + du -sh $(Build.SourcesDirectory)/* + df -h + displayName: Disk Usage before Build # Build - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -ci -arch ${{ parameters.archType }} ${{ parameters.buildArgs }} displayName: Build product + - ${{ if in(parameters.osGroup, 'OSX', 'iOS','tvOS') }}: + - script: | + du -sh $(Build.SourcesDirectory)/* + df -h + displayName: Disk Usage after Build + - task: PublishBuildArtifacts@1 displayName: Publish Logs inputs: diff --git a/eng/pipelines/common/platform-matrix.yml b/eng/pipelines/common/platform-matrix.yml index fe0765b81050e3..2979349d8beca7 100644 --- a/eng/pipelines/common/platform-matrix.yml +++ b/eng/pipelines/common/platform-matrix.yml @@ -38,7 +38,7 @@ jobs: archType: arm platform: Linux_arm container: - image: ubuntu-16.04-cross-09ec757-20200320131433 + image: ubuntu-16.04-cross-20200413125008-09ec757 registry: mcr jobParameters: runtimeFlavor: ${{ parameters.runtimeFlavor }} @@ -62,7 +62,7 @@ jobs: archType: arm64 platform: Linux_arm64 container: - image: ubuntu-16.04-cross-arm64-cfdd435-20200121150126 + image: ubuntu-16.04-cross-arm64-20200413125008-cfdd435 registry: mcr jobParameters: runtimeFlavor: ${{ parameters.runtimeFlavor }} @@ -119,7 +119,7 @@ jobs: archType: arm64 platform: Linux_musl_arm64 container: - image: ubuntu-16.04-cross-arm64-alpine-406629a-20200127195039 + image: ubuntu-16.04-cross-arm64-alpine-20200413125008-406629a registry: mcr jobParameters: runtimeFlavor: ${{ parameters.runtimeFlavor }} @@ -160,14 +160,14 @@ jobs: # WebAssembly -- ${{ if containsValue(parameters.platforms, 'WebAssembly_wasm') }}: +- ${{ if containsValue(parameters.platforms, 'Browser_wasm') }}: - template: xplat-setup.yml parameters: jobTemplate: ${{ parameters.jobTemplate }} helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }} - osGroup: WebAssembly + osGroup: Browser archType: wasm - platform: WebAssembly_wasm + platform: Browser_wasm container: image: ubuntu-18.04-webassembly-20200409132031-f70ea41 registry: mcr @@ -180,23 +180,25 @@ jobs: ${{ insert }}: ${{ parameters.jobParameters }} # FreeBSD - -# FreeBSD machines are currently offline. Re-enable in the official build when -# the machines are healthy. - -# - template: xplat-setup.yml -# parameters: -# jobTemplate: ${{ parameters.jobTemplate }} -# osGroup: FreeBSD -# archType: x64 -# jobParameters: -# runtimeFlavor: ${{ parameters.runtimeFlavor }} -# buildConfig: ${{ parameters.buildConfig }} -# # There are no FreeBSD helix queues, so we don't run tests at the moment. -# helixQueues: -# asString: '' -# asArray: [] -# ${{ insert }}: ${{ parameters.jobParameters }} +- ${{ if containsValue(parameters.platforms, 'FreeBSD_x64') }}: + - template: xplat-setup.yml + parameters: + jobTemplate: ${{ parameters.jobTemplate }} + helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }} + osGroup: FreeBSD + archType: x64 + platform: FreeBSD_x64 + container: + image: ubuntu-18.04-cross-freebsd-11-20200407092345-a84b0d2 + registry: mcr + jobParameters: + runtimeFlavor: ${{ parameters.runtimeFlavor }} + buildConfig: ${{ parameters.buildConfig }} + helixQueueGroup: ${{ parameters.helixQueueGroup }} + crossrootfsDir: '/crossrootfs/x64' + ${{ if eq(parameters.passPlatforms, true) }}: + platforms: ${{ parameters.platforms }} + ${{ insert }}: ${{ parameters.jobParameters }} # Android x64 @@ -209,7 +211,7 @@ jobs: archType: x64 platform: Android_x64 container: - image: ubuntu-18.04-android-20200401093035-1517ea2 + image: ubuntu-18.04-android-20200422191843-e2c3f83 registry: mcr jobParameters: runtimeFlavor: mono @@ -231,7 +233,7 @@ jobs: archType: x86 platform: Android_x86 container: - image: ubuntu-18.04-android-20200401093035-1517ea2 + image: ubuntu-18.04-android-20200422191843-e2c3f83 registry: mcr jobParameters: runtimeFlavor: mono @@ -253,7 +255,7 @@ jobs: archType: arm platform: Android_arm container: - image: ubuntu-18.04-android-20200401093035-1517ea2 + image: ubuntu-18.04-android-20200422191843-e2c3f83 registry: mcr jobParameters: runtimeFlavor: mono @@ -275,7 +277,7 @@ jobs: archType: arm64 platform: Android_arm64 container: - image: ubuntu-18.04-android-20200401093035-1517ea2 + image: ubuntu-18.04-android-20200422191843-e2c3f83 registry: mcr jobParameters: runtimeFlavor: mono @@ -346,6 +348,26 @@ jobs: managedTestBuildOsGroup: OSX ${{ insert }}: ${{ parameters.jobParameters }} +# iOS x86 + +- ${{ if containsValue(parameters.platforms, 'iOS_x86') }}: + - template: xplat-setup.yml + parameters: + jobTemplate: ${{ parameters.jobTemplate }} + helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }} + osGroup: iOS + archType: x86 + platform: iOS_x86 + jobParameters: + runtimeFlavor: mono + stagedBuild: ${{ parameters.stagedBuild }} + buildConfig: ${{ parameters.buildConfig }} + ${{ if eq(parameters.passPlatforms, true) }}: + platforms: ${{ parameters.platforms }} + helixQueueGroup: ${{ parameters.helixQueueGroup }} + managedTestBuildOsGroup: OSX + ${{ insert }}: ${{ parameters.jobParameters }} + # iOS arm - ${{ if containsValue(parameters.platforms, 'iOS_arm') }}: diff --git a/eng/pipelines/common/templates/runtimes/build-test-job.yml b/eng/pipelines/common/templates/runtimes/build-test-job.yml new file mode 100644 index 00000000000000..6c46cfadeb0c4b --- /dev/null +++ b/eng/pipelines/common/templates/runtimes/build-test-job.yml @@ -0,0 +1,162 @@ +parameters: + buildConfig: '' + archType: '' + osGroup: '' + osSubgroup: '' + container: '' + testGroup: '' + liveRuntimeBuildConfig: '' + + # When set to a non-empty value (Debug / Release), it determines libraries + # build configuration to use for the tests. Setting this property implies + # a dependency of this job on the appropriate libraries build and is used + # to construct the name of the Azure artifact representing libraries build + # to use for building the tests. + liveLibrariesBuildConfig: '' + + displayNameArgs: '' + condition: true + stagedBuild: false + variables: {} + pool: '' + runtimeFlavor: 'coreclr' + runtimeFlavorDisplayName: 'CoreCLR' + runtimeVariant: '' + +### Build managed test components (native components are getting built as part +### of the the product build job). + +### TODO: As of today, build of managed test components requires the product build +### as a prerequisite due to dependency on System.Private.Corelib. After switching +### over to its reference assembly we should be able to remove this dependency and +### run managed test builds in parallel with the product build job. + + +jobs: +- template: /eng/pipelines/${{ parameters.runtimeFlavor }}/templates/xplat-pipeline-job.yml + parameters: + buildConfig: ${{ parameters.buildConfig }} + archType: ${{ parameters.archType }} + osGroup: ${{ parameters.osGroup }} + osSubgroup: ${{ parameters.osSubgroup }} + managedTestBuildOsGroup: ${{ parameters.osGroup }} + managedTestBuildOsSubgroup: ${{ parameters.osSubgroup }} + container: ${{ parameters.container }} + runtimeVariant: ${{ parameters.runtimeVariant }} + testGroup: ${{ parameters.testGroup }} + stagedBuild: ${{ parameters.stagedBuild }} + liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }} + variables: ${{ parameters.variables }} + pool: ${{ parameters.pool }} + + # Test jobs should continue on error for internal builds + ${{ if eq(variables['System.TeamProject'], 'internal') }}: + continueOnError: true + + ${{ if eq(parameters.testGroup, 'innerloop') }}: + name: '${{ parameters.runtimeFlavor }}_common_test_build_p0_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.buildConfig }}' + displayName: '${{ parameters.runtimeFlavorDisplayName }} Common Pri0 Test Build ${{ parameters.osGroup }}${{ parameters.osSubgroup }} ${{ parameters.archType }} ${{ parameters.buildConfig }}' + + ${{ if ne(parameters.testGroup, 'innerloop') }}: + name: '${{ parameters.runtimeFlavor }}_common_test_build_p1_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.buildConfig }}' + displayName: '${{ parameters.runtimeFlavorDisplayName }} Common Pri1 Test Build ${{ parameters.osGroup }}${{ parameters.osSubgroup }} ${{ parameters.archType }} ${{ parameters.buildConfig }}' + + # Since the condition is being altered, merge the default with the additional conditions. + # See https://docs.microsoft.com/azure/devops/pipelines/process/conditions + condition: and(succeeded(), ${{ parameters.condition }}) + + # TODO: Build of managed test components currently depends on the corresponding build job + # because it needs System.Private.Corelib; we should be able to remove this dependency + # by switching over to using reference assembly. + ${{ if ne(parameters.stagedBuild, true) }}: + dependsOn: + - ${{ format('coreclr_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, coalesce(parameters.liveRuntimeBuildConfig, parameters.buildConfig)) }} + - ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}: + - ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveLibrariesBuildConfig) }} + + + ${{ if eq(parameters.testGroup, 'innerloop') }}: + timeoutInMinutes: 90 + + ${{ if ne(parameters.testGroup, 'innerloop') }}: + timeoutInMinutes: 160 + + steps: + + # Install test build dependencies + - ${{ if eq(parameters.osGroup, 'OSX') }}: + - script: $(Build.SourcesDirectory)/eng/install-native-dependencies.sh $(osGroup) + displayName: Install native dependencies + - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + # Necessary to install correct cmake version + - script: $(Build.SourcesDirectory)\eng\common\init-tools-native.cmd -InstallDirectory $(Build.SourcesDirectory)\native-tools -Force + displayName: Install native dependencies + + + # Optionally download live-built libraries + - ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}: + - template: /eng/pipelines/common/download-artifact-step.yml + parameters: + unpackFolder: $(librariesDownloadDir) + cleanUnpackFolder: false + artifactFileName: '$(librariesBuildArtifactName)$(archiveExtension)' + artifactName: '$(librariesBuildArtifactName)' + displayName: 'live-built libraries' + + # We need to explictly download CoreCLR, even if building Mono because the CoreCLR tests depend on it + - template: /eng/pipelines/common/download-artifact-step.yml + parameters: + unpackFolder: $(coreClrProductRootFolderPath) + artifactFileName: '$(coreClrProductArtifactName)$(archiveExtension)' + artifactName: '$(coreClrProductArtifactName)' + displayName: 'CoreCLR product build' + + - ${{ if in(parameters.osGroup, 'OSX', 'iOS','tvOS') }}: + - script: | + du -sh $(Build.SourcesDirectory)/* + df -h + displayName: Disk Usage before Build + + # Build managed test components + - script: $(coreClrRepoRootDir)build-test$(scriptExt) skipnative skipgeneratelayout skiptestwrappers $(buildConfig) $(archType) $(crossArg) $(priorityArg) ci $(librariesOverrideArg) + displayName: Build managed test components + + - ${{ if in(parameters.osGroup, 'OSX', 'iOS','tvOS') }}: + - script: | + du -sh $(Build.SourcesDirectory)/* + df -h + displayName: Disk Usage after Build + + # Zip and publish managed test components + - template: /eng/pipelines/common/upload-artifact-step.yml + parameters: + rootFolder: $(managedTestArtifactRootFolderPath) + includeRootFolder: false + archiveType: $(archiveType) + tarCompression: $(tarCompression) + archiveExtension: $(archiveExtension) + artifactName: $(managedTestArtifactName) + displayName: 'managed test components' + + + # Publish .packages/microsoft.net.sdk.il needed for traversing + # test projects during the copynativeonly command in run test job. + - template: /eng/pipelines/common/upload-artifact-step.yml + parameters: + rootFolder: $(microsoftNetSdkIlFolderPath) + includeRootFolder: false + archiveType: $(archiveType) + tarCompression: $(tarCompression) + archiveExtension: $(archiveExtension) + artifactName: $(microsoftNetSdkIlArtifactName) + displayName: 'Microsoft.NET.Sdk.IL package' + + + # Publish Logs + - task: PublishPipelineArtifact@1 + displayName: Publish Logs + inputs: + targetPath: $(Build.SourcesDirectory)/artifacts/log + artifactName: '${{ parameters.runtimeFlavor }}_Common_Runtime_TestBuildLogs_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)_${{ parameters.testGroup }}' + continueOnError: true + condition: always() diff --git a/eng/pipelines/coreclr/templates/run-test-job.yml b/eng/pipelines/common/templates/runtimes/run-test-job.yml similarity index 81% rename from eng/pipelines/coreclr/templates/run-test-job.yml rename to eng/pipelines/common/templates/runtimes/run-test-job.yml index 4bdb1d38891bf2..a98e8cd1c57cfd 100644 --- a/eng/pipelines/coreclr/templates/run-test-job.yml +++ b/eng/pipelines/common/templates/runtimes/run-test-job.yml @@ -11,6 +11,7 @@ parameters: readyToRun: false liveLibrariesBuildConfig: '' crossgen2: false + compositeBuildMode: false helixQueues: '' # If true, run the corefx tests instead of the coreclr ones corefxTests: false @@ -18,8 +19,11 @@ parameters: stagedBuild: false displayNameArgs: '' runInUnloadableContext: false + runtimeVariant: '' variables: {} pool: '' + runtimeFlavor: 'coreclr' + runtimeFlavorDisplayName: 'CoreCLR' ### Test run job @@ -27,7 +31,7 @@ parameters: ### buildConfig and archType. jobs: -- template: xplat-pipeline-job.yml +- template: /eng/pipelines/${{ parameters.runtimeFlavor }}/templates/xplat-pipeline-job.yml parameters: buildConfig: ${{ parameters.buildConfig }} archType: ${{ parameters.archType }} @@ -42,6 +46,7 @@ jobs: stagedBuild: ${{ parameters.stagedBuild }} liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }} helixType: 'build/tests/' + runtimeVariant: ${{ parameters.runtimeVariant }} pool: ${{ parameters.pool }} condition: ${{ parameters.condition }} @@ -52,22 +57,22 @@ jobs: dependsOn: - ${{ if ne(parameters.corefxTests, true) }}: - ${{ if eq(parameters.testGroup, 'innerloop') }}: - - 'coreclr_test_build_p0_${{ parameters.managedTestBuildOsGroup }}${{ parameters.managedTestBuildOsSubgroup }}_${{ parameters.archType }}_${{parameters.buildConfig }}' + - '${{ parameters.runtimeFlavor }}_common_test_build_p0_${{ parameters.managedTestBuildOsGroup }}${{ parameters.managedTestBuildOsSubgroup }}_${{ parameters.archType }}_${{parameters.buildConfig }}' - ${{ if ne(parameters.testGroup, 'innerloop') }}: - - 'coreclr_test_build_p1_${{ parameters.managedTestBuildOsGroup }}${{ parameters.managedTestBuildOsSubgroup }}_${{ parameters.archType }}_${{parameters.buildConfig }}' + - '${{ parameters.runtimeFlavor }}_common_test_build_p1_${{ parameters.managedTestBuildOsGroup }}${{ parameters.managedTestBuildOsSubgroup }}_${{ parameters.archType }}_${{parameters.buildConfig }}' - ${{ if ne(parameters.stagedBuild, true) }}: - - ${{ format('coreclr_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} + - ${{ format('{0}_{1}_product_build_{2}{3}_{4}_{5}', parameters.runtimeFlavor, parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}: - ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveLibrariesBuildConfig) }} # Compute job name from template parameters ${{ if eq(parameters.testGroup, 'innerloop') }}: - name: 'run_test_p0_${{ parameters.displayNameArgs }}_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.buildConfig }}' - displayName: 'CoreCLR Pri0 Test Run ${{ parameters.displayNameArgs }} ${{ parameters.osGroup }}${{ parameters.osSubgroup }} ${{ parameters.archType }} ${{ parameters.buildConfig }}' + name: 'run_test_p0_${{ parameters.runtimeFlavor }}${{ parameters.runtimeVariant }}_${{ parameters.displayNameArgs }}_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.buildConfig }}' + displayName: '${{ parameters.runtimeFlavorDisplayName }} ${{ parameters.runtimeVariant}} Pri0 Runtime Tests Run ${{ parameters.displayNameArgs }} ${{ parameters.osGroup }}${{ parameters.osSubgroup }} ${{ parameters.archType }} ${{ parameters.buildConfig }}' ${{ if ne(parameters.testGroup, 'innerloop') }}: name: 'run_test_p1_${{ parameters.displayNameArgs }}_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.buildConfig }}' - displayName: 'CoreCLR Pri1 Test Run ${{ parameters.displayNameArgs }} ${{ parameters.osGroup }}${{ parameters.osSubgroup }} ${{ parameters.archType }} ${{ parameters.buildConfig }}' + displayName: '${{ parameters.runtimeFlavorDisplayName }} ${{ parameters.runtimeVariant }} Pri1 Runtime Tests Run ${{ parameters.displayNameArgs }} ${{ parameters.osGroup }}${{ parameters.osSubgroup }} ${{ parameters.archType }} ${{ parameters.buildConfig }}' variables: - name: testhostArg @@ -76,6 +81,13 @@ jobs: - name: testhostArg value: 'buildtesthostonly' + - name: runtimeFlavorArgs + value: '' + + - ${{ if eq(parameters.runtimeFlavor, 'mono') }}: + - name: runtimeFlavorArgs + value: '-excludemonofailures' + - name: crossgenArg value: '' - name: LogNamePrefix @@ -91,6 +103,9 @@ jobs: value: 'crossgen2' - name: LogNamePrefix value: TestRunLogs_R2R_CG2 + - ${{ if eq(parameters.compositeBuildMode, true) }}: + - name: crossgenArg + value: 'composite' # Set job timeouts # @@ -141,6 +156,10 @@ jobs: - name: timeoutPerTestInMinutes value: 90 + - ${{ if eq(parameters.compositeBuildMode, true) }}: + - name: crossgenArg + value: 'composite' + - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - group: DotNet-HelixApi-Access @@ -148,7 +167,7 @@ jobs: # TODO: update these numbers as they were determined long ago ${{ if eq(parameters.testGroup, 'innerloop') }}: - timeoutInMinutes: 150 + timeoutInMinutes: 200 ${{ if in(parameters.testGroup, 'outerloop', 'jit-experimental') }}: timeoutInMinutes: 270 ${{ if in(parameters.testGroup, 'gc-longrunning', 'gc-simulator') }}: @@ -190,6 +209,15 @@ jobs: displayName: 'product build' + - ${{ if eq(parameters.runtimeFlavor, 'mono') }}: + # We need to explictly download CoreCLR for Mono + - template: /eng/pipelines/common/download-artifact-step.yml + parameters: + unpackFolder: $(coreClrProductRootFolderPath) + artifactFileName: '$(coreClrProductArtifactName)$(archiveExtension)' + artifactName: '$(coreClrProductArtifactName)' + displayName: 'CoreCLR product download for Mono' + # Download and unzip the Microsoft.NET.Sdk.IL package needed for traversing # ilproj test projects during copynativeonly. - ${{ if ne(parameters.corefxTests, true) }}: @@ -227,8 +255,8 @@ jobs: displayName: Generate test host - # Generate test wrappers - - script: $(coreClrRepoRootDir)build-test$(scriptExt) buildtestwrappersonly $(crossgenArg) $(buildConfig) $(archType) $(crossArg) $(priorityArg) $(librariesOverrideArg) + # Generate test wrappers. This is the step that examines issues.targets to exclude tests. + - script: $(coreClrRepoRootDir)build-test$(scriptExt) buildtestwrappersonly $(runtimeFlavorArgs) $(crossgenArg) $(buildConfig) $(archType) $(crossArg) $(priorityArg) $(librariesOverrideArg) displayName: Generate test wrappers @@ -237,15 +265,25 @@ jobs: - script: $(coreClrRepoRootDir)build-test$(scriptExt) skipmanaged skipnative $(crossgenArg) $(buildConfig) $(archType) $(crossArg) $(priorityArg) $(librariesOverrideArg) displayName: Crossgen framework assemblies + # Overwrite coreclr runtime binaries with mono ones + - ${{ if eq(parameters.runtimeFlavor, 'mono') }}: + - script: $(_msbuildCommand) + $(Build.SourcesDirectory)/src/mono/mono.proj + /t:PatchCoreClrCoreRoot + /p:Configuration=$(buildConfigUpper) + /p:TargetArchitecture=$(archType) + displayName: "Patch dotnet with mono" # Send tests to Helix - - template: /eng/pipelines/coreclr/templates/send-to-helix-step.yml + - template: /eng/pipelines/common/templates/runtimes/send-to-helix-step.yml parameters: displayName: Send tests to Helix buildConfig: $(buildConfigUpper) archType: ${{ parameters.archType }} osGroup: ${{ parameters.osGroup }} + osSubgroup: ${{ parameters.osSubgroup}} coreClrRepoRoot: $(coreClrRepoRoot) + runtimeFlavorDisplayName: ${{ parameters.runtimeFlavorDisplayName }} ${{ if eq(variables['System.TeamProject'], 'public') }}: creator: $(Build.DefinitionName) @@ -277,6 +315,7 @@ jobs: runCrossGen: ${{ and(eq(parameters.readyToRun, true), ne(parameters.crossgen2, true)) }} runCrossGen2: ${{ and(eq(parameters.readyToRun, true), eq(parameters.crossgen2, true)) }} + compositeBuildMode: ${{ parameters.compositeBuildMode }} runInUnloadableContext: ${{ parameters.runInUnloadableContext }} ${{ if eq(variables['System.TeamProject'], 'internal') }}: @@ -293,7 +332,10 @@ jobs: ${{ if in(parameters.testGroup, 'innerloop', 'outerloop') }}: scenarios: - normal - - no_tiered_compilation + - ${{ if eq(parameters.runtimeFlavor, 'coreclr') }}: + - no_tiered_compilation + - ${{ if eq(parameters.runtimeFlavor, 'mono') }}: + - interpreter ${{ if in(parameters.testGroup, 'jitstress') }}: scenarios: - jitminopts @@ -411,12 +453,13 @@ jobs: - jitguardeddevirtualization - jitehwritethru - jitobjectstackallocation + - jitpgo # Publish Logs - task: PublishPipelineArtifact@1 displayName: Publish Logs inputs: targetPath: $(Build.SourcesDirectory)/artifacts/log - artifactName: '$(LogNamePrefix)_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)_${{ parameters.testGroup }}' + artifactName: '${{ parameters.runtimeFlavor }}_${{ parameters.runtimeVariant }}_$(LogNamePrefix)_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)_${{ parameters.testGroup }}' continueOnError: true condition: always() diff --git a/eng/pipelines/coreclr/templates/send-to-helix-step.yml b/eng/pipelines/common/templates/runtimes/send-to-helix-step.yml similarity index 87% rename from eng/pipelines/coreclr/templates/send-to-helix-step.yml rename to eng/pipelines/common/templates/runtimes/send-to-helix-step.yml index 7209065b570b5e..3602929653dc36 100644 --- a/eng/pipelines/coreclr/templates/send-to-helix-step.yml +++ b/eng/pipelines/common/templates/runtimes/send-to-helix-step.yml @@ -3,6 +3,7 @@ parameters: condition: '' archType: '' osGroup: '' + osSubgroup: '' buildConfig: '' creator: '' publishTestResults: '' @@ -16,11 +17,14 @@ parameters: timeoutPerTestInMinutes: '' runCrossGen: '' runCrossGen2: '' + compositeBuildMode: false helixProjectArguments: '' runInUnloadableContext: '' longRunningGcTests: '' gcSimulatorTests: '' coreClrRepoRoot: '' + runtimeFlavorDisplayName: 'CoreCLR' + runtimeVariant: '' steps: - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: @@ -36,7 +40,7 @@ steps: condition: ${{ parameters.condition }} env: __BuildArch: ${{ parameters.archType }} - __TargetOS: ${{ parameters.osGroup }} + __TargetOS: ${{ parameters.osGroup }}${{ parameters.osSubgroup }} __BuildType: ${{ parameters.buildConfig }} _Creator: ${{ parameters.creator }} _PublishTestResults: ${{ parameters.publishTestResults }} @@ -47,12 +51,15 @@ steps: _HelixType: ${{ parameters.helixType }} _RunCrossGen: ${{ parameters.runCrossGen }} _RunCrossGen2: ${{ parameters.runCrossGen2 }} + _CompositeBuildMode: ${{ parameters.compositeBuildMode }} _RunInUnloadableContext: ${{ parameters.runInUnloadableContext }} _LongRunningGcTests: ${{ parameters.longRunningGcTests }} _GcSimulatorTests: ${{ parameters.gcSimulatorTests }} _Scenarios: ${{ join(',', parameters.scenarios) }} _TimeoutPerTestCollectionInMinutes: ${{ parameters.timeoutPerTestCollectionInMinutes }} _TimeoutPerTestInMinutes: ${{ parameters.timeoutPerTestInMinutes }} + runtimeFlavorDisplayName: ${{ parameters.runtimeFlavorDisplayName }} + _RuntimeVariant: ${{ parameters.runtimeVariant }} ${{ if eq(parameters.publishTestResults, 'true') }}: SYSTEM_ACCESSTOKEN: $(System.AccessToken) # TODO: remove NUGET_PACKAGES once https://github.com/dotnet/arcade/issues/1578 is fixed @@ -75,7 +82,7 @@ steps: condition: ${{ parameters.condition }} env: __BuildArch: ${{ parameters.archType }} - __TargetOS: ${{ parameters.osGroup }} + __TargetOS: ${{ parameters.osGroup }}${{ parameters.osSubgroup }} __BuildType: ${{ parameters.buildConfig }} _Creator: ${{ parameters.creator }} _PublishTestResults: ${{ parameters.publishTestResults }} @@ -86,12 +93,15 @@ steps: _HelixType: ${{ parameters.helixType }} _RunCrossGen: ${{ parameters.runCrossGen }} _RunCrossGen2: ${{ parameters.runCrossGen2 }} + _CompositeBuildMode: ${{ parameters.compositeBuildMode }} _RunInUnloadableContext: ${{ parameters.runInUnloadableContext }} _LongRunningGcTests: ${{ parameters.longRunningGcTests }} _GcSimulatorTests: ${{ parameters.gcSimulatorTests }} _Scenarios: ${{ join(',', parameters.scenarios) }} _TimeoutPerTestCollectionInMinutes: ${{ parameters.timeoutPerTestCollectionInMinutes }} _TimeoutPerTestInMinutes: ${{ parameters.timeoutPerTestInMinutes }} + runtimeFlavorDisplayName: ${{ parameters.runtimeFlavorDisplayName }} + _RuntimeVariant: ${{ parameters.runtimeVariant }} ${{ if eq(parameters.publishTestResults, 'true') }}: SYSTEM_ACCESSTOKEN: $(System.AccessToken) # TODO: remove NUGET_PACKAGES once https://github.com/dotnet/arcade/issues/1578 is fixed diff --git a/eng/pipelines/common/xplat-setup.yml b/eng/pipelines/common/xplat-setup.yml index 4467951602b7e7..54da4233adaff3 100644 --- a/eng/pipelines/common/xplat-setup.yml +++ b/eng/pipelines/common/xplat-setup.yml @@ -11,6 +11,10 @@ parameters: jobs: - template: ${{ coalesce(parameters.helixQueuesTemplate, parameters.jobTemplate) }} parameters: + ${{ if eq(parameters.jobParameters.runtimeFlavor, 'coreclr') }}: + runtimeFlavorDisplayName: 'CoreCLR' + ${{ if eq(parameters.jobParameters.runtimeFlavor, 'mono') }}: + runtimeFlavorDisplayName: 'Mono' variables: # Disable component governance in our CI builds. These builds are not shipping nor # are they a service. Also the component governance jobs issue lots of inconsequential @@ -64,10 +68,6 @@ jobs: - name: ROOTFS_DIR value: ${{ parameters.jobParameters.crossrootfsDir }} - - ${{ if eq(parameters.osGroup, 'Android') }}: - - name: ANDROID_NDK_HOME - value: /usr/local/ndk - - name: runtimeFlavorName ${{ if eq(parameters.jobParameters.runtimeFlavor, 'mono') }}: value: Mono @@ -88,19 +88,15 @@ jobs: ${{ if eq(parameters.jobParameters.pool, '') }}: pool: # Public Linux Build Pool - ${{ if and(eq(parameters.osGroup, 'Linux'), eq(variables['System.TeamProject'], 'public')) }}: + ${{ if and(in(parameters.osGroup, 'Linux', 'FreeBSD'), eq(variables['System.TeamProject'], 'public')) }}: name: NetCorePublic-Pool queue: BuildPool.Ubuntu.1604.Amd64.Open # Official Build Linux Pool - ${{ if and(eq(parameters.osGroup, 'Linux'), ne(variables['System.TeamProject'], 'public')) }}: + ${{ if and(in(parameters.osGroup, 'Linux', 'FreeBSD'), ne(variables['System.TeamProject'], 'public')) }}: name: NetCoreInternal-Pool queue: BuildPool.Ubuntu.1604.Amd64 - # FreeBSD builds only in the internal project - ${{ if and(eq(parameters.osGroup, 'FreeBSD'), ne(variables['System.TeamProject'], 'public')) }}: - name: dnceng-freebsd-internal - # Public OSX Build Pool ${{ if eq(parameters.osGroup, 'OSX') }}: vmImage: 'macOS-10.14' diff --git a/eng/pipelines/coreclr/ci.yml b/eng/pipelines/coreclr/ci.yml index 0249dc33eba230..ec430007258404 100644 --- a/eng/pipelines/coreclr/ci.yml +++ b/eng/pipelines/coreclr/ci.yml @@ -8,6 +8,7 @@ trigger: - '*' - src/libraries/System.Private.CoreLib/* exclude: + - .github/* - docs/* - CODE-OF-CONDUCT.md - CONTRIBUTING.md @@ -94,7 +95,7 @@ jobs: # - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/build-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/build-test-job.yml buildConfig: checked platforms: - Linux_arm @@ -113,7 +114,7 @@ jobs: # - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/run-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml buildConfig: checked platformGroup: all helixQueueGroup: ci @@ -127,7 +128,7 @@ jobs: # - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/run-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml buildConfig: checked platforms: - Linux_arm64 diff --git a/eng/pipelines/coreclr/corefx-jitstress.yml b/eng/pipelines/coreclr/corefx-jitstress.yml index 4ea57cb95ba3d7..07acd4100062a4 100644 --- a/eng/pipelines/coreclr/corefx-jitstress.yml +++ b/eng/pipelines/coreclr/corefx-jitstress.yml @@ -33,7 +33,7 @@ jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/run-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml buildConfig: checked platforms: # TODO: add Windows_NT_arm64, when we have hardware available. Note: platform-matrix.yml needs to enable a Helix queue for this. diff --git a/eng/pipelines/coreclr/corefx-jitstress2-jitstressregs.yml b/eng/pipelines/coreclr/corefx-jitstress2-jitstressregs.yml index df6417a3c080a8..c58f8f575f3831 100644 --- a/eng/pipelines/coreclr/corefx-jitstress2-jitstressregs.yml +++ b/eng/pipelines/coreclr/corefx-jitstress2-jitstressregs.yml @@ -33,7 +33,7 @@ jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/run-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml buildConfig: checked platforms: # TODO: add Windows_NT_arm64, when we have hardware available. Note: platform-matrix.yml needs to enable a Helix queue for this. diff --git a/eng/pipelines/coreclr/corefx-jitstressregs.yml b/eng/pipelines/coreclr/corefx-jitstressregs.yml index a74c2ec0801624..ce064af729f91c 100644 --- a/eng/pipelines/coreclr/corefx-jitstressregs.yml +++ b/eng/pipelines/coreclr/corefx-jitstressregs.yml @@ -33,7 +33,7 @@ jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/run-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml buildConfig: checked platforms: # TODO: add Windows_NT_arm64, when we have hardware available. Note: platform-matrix.yml needs to enable a Helix queue for this. diff --git a/eng/pipelines/coreclr/corefx.yml b/eng/pipelines/coreclr/corefx.yml index c251b0236d3af7..2f70f3f7083031 100644 --- a/eng/pipelines/coreclr/corefx.yml +++ b/eng/pipelines/coreclr/corefx.yml @@ -33,7 +33,7 @@ jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/run-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml buildConfig: checked platforms: # TODO: add Windows_NT_arm64, when we have hardware available. Note: platform-matrix.yml needs to enable a Helix queue for this. diff --git a/eng/pipelines/coreclr/crossgen2-composite.yml b/eng/pipelines/coreclr/crossgen2-composite.yml new file mode 100644 index 00000000000000..0a2e5405878e0d --- /dev/null +++ b/eng/pipelines/coreclr/crossgen2-composite.yml @@ -0,0 +1,56 @@ +trigger: none + +pr: none + +schedules: +- cron: "0 6 * * *" + displayName: Mon through Sun at 10:00 PM (UTC-8:00) + branches: + include: + - master + always: true + +jobs: +# +# Checkout repository +# +- template: /eng/pipelines/common/checkout-job.yml + +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/build-coreclr-and-libraries-job.yml + buildConfig: checked + platforms: + - Linux_x64 + - OSX_x64 + - Windows_NT_x64 + jobParameters: + testGroup: innerloop + +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/templates/runtimes/build-test-job.yml + buildConfig: checked + platforms: + - OSX_x64 + - Windows_NT_x64 + jobParameters: + testGroup: innerloop + liveLibrariesBuildConfig: Release + +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml + helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml + buildConfig: checked + platforms: + - Linux_x64 + - OSX_x64 + - Windows_NT_x64 + jobParameters: + testGroup: innerloop + readyToRun: true + crossgen2: true + compositeBuildMode: true + displayNameArgs: Composite + liveLibrariesBuildConfig: Release diff --git a/eng/pipelines/coreclr/crossgen2-outerloop.yml b/eng/pipelines/coreclr/crossgen2-outerloop.yml index d31a45088687b1..3802f6222f0379 100644 --- a/eng/pipelines/coreclr/crossgen2-outerloop.yml +++ b/eng/pipelines/coreclr/crossgen2-outerloop.yml @@ -29,7 +29,7 @@ jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/build-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/build-test-job.yml buildConfig: checked platforms: - OSX_x64 @@ -40,7 +40,7 @@ jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/run-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml buildConfig: checked platforms: diff --git a/eng/pipelines/coreclr/crossgen2.yml b/eng/pipelines/coreclr/crossgen2.yml index 3d1ea01d4f69d6..ab6ccdf94246b2 100644 --- a/eng/pipelines/coreclr/crossgen2.yml +++ b/eng/pipelines/coreclr/crossgen2.yml @@ -29,7 +29,7 @@ jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/build-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/build-test-job.yml buildConfig: checked platforms: - OSX_x64 @@ -40,7 +40,7 @@ jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/run-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml buildConfig: checked platforms: diff --git a/eng/pipelines/coreclr/gc-longrunning.yml b/eng/pipelines/coreclr/gc-longrunning.yml index 5d3ec8f9e5335b..e706868dc49314 100644 --- a/eng/pipelines/coreclr/gc-longrunning.yml +++ b/eng/pipelines/coreclr/gc-longrunning.yml @@ -30,7 +30,7 @@ jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/build-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/build-test-job.yml buildConfig: release platforms: - Linux_x64 @@ -43,7 +43,7 @@ jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/run-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml buildConfig: release platforms: - Linux_x64 diff --git a/eng/pipelines/coreclr/jitstress-isas-x86.yml b/eng/pipelines/coreclr/jitstress-isas-x86.yml index 52d977d4b7ea46..8c1241a1b371ab 100644 --- a/eng/pipelines/coreclr/jitstress-isas-x86.yml +++ b/eng/pipelines/coreclr/jitstress-isas-x86.yml @@ -30,7 +30,7 @@ jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/build-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/build-test-job.yml buildConfig: checked platforms: - OSX_x64 @@ -42,7 +42,7 @@ jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/run-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml buildConfig: checked platforms: - Linux_x64 diff --git a/eng/pipelines/coreclr/jitstress.yml b/eng/pipelines/coreclr/jitstress.yml index 94ee7eb62c6bb9..04107ea4b05732 100644 --- a/eng/pipelines/coreclr/jitstress.yml +++ b/eng/pipelines/coreclr/jitstress.yml @@ -28,8 +28,7 @@ jobs: - Linux_x64 - Windows_NT_x64 - Windows_NT_x86 - # Currently no Windows arm32 testing. https://github.com/dotnet/runtime/issues/1097 - #- Windows_NT_arm + - Windows_NT_arm - Windows_NT_arm64 jobParameters: testGroup: jitstress @@ -46,8 +45,7 @@ jobs: - Linux_x64 - Windows_NT_x64 - Windows_NT_x86 - # Currently no Windows arm32 testing. https://github.com/dotnet/runtime/issues/1097 - #- Windows_NT_arm + - Windows_NT_arm - Windows_NT_arm64 helixQueueGroup: ci helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml diff --git a/eng/pipelines/coreclr/jitstress2-jitstressregs.yml b/eng/pipelines/coreclr/jitstress2-jitstressregs.yml index 8f196635e89e5b..24953b5ad92196 100644 --- a/eng/pipelines/coreclr/jitstress2-jitstressregs.yml +++ b/eng/pipelines/coreclr/jitstress2-jitstressregs.yml @@ -28,8 +28,7 @@ jobs: - Linux_x64 - Windows_NT_x64 - Windows_NT_x86 - # Currently no Windows arm32 testing. https://github.com/dotnet/runtime/issues/1097 - #- Windows_NT_arm + - Windows_NT_arm - Windows_NT_arm64 jobParameters: testGroup: jitstress2-jitstressregs @@ -46,8 +45,7 @@ jobs: - Linux_x64 - Windows_NT_x64 - Windows_NT_x86 - # Currently no Windows arm32 testing. https://github.com/dotnet/runtime/issues/1097 - #- Windows_NT_arm + - Windows_NT_arm - Windows_NT_arm64 helixQueueGroup: ci helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml diff --git a/eng/pipelines/coreclr/jitstressregs.yml b/eng/pipelines/coreclr/jitstressregs.yml index af6e2faba56891..322458047125b5 100644 --- a/eng/pipelines/coreclr/jitstressregs.yml +++ b/eng/pipelines/coreclr/jitstressregs.yml @@ -28,8 +28,7 @@ jobs: - Linux_x64 - Windows_NT_x64 - Windows_NT_x86 - # Currently no Windows arm32 testing. https://github.com/dotnet/runtime/issues/1097 - #- Windows_NT_arm + - Windows_NT_arm - Windows_NT_arm64 jobParameters: testGroup: jitstressregs @@ -46,8 +45,7 @@ jobs: - Linux_x64 - Windows_NT_x64 - Windows_NT_x86 - # Currently no Windows arm32 testing. https://github.com/dotnet/runtime/issues/1097 - #- Windows_NT_arm + - Windows_NT_arm - Windows_NT_arm64 helixQueueGroup: ci helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml diff --git a/eng/pipelines/coreclr/perf.yml b/eng/pipelines/coreclr/perf.yml index ffa22b8afc7515..d2ed639d434bdc 100644 --- a/eng/pipelines/coreclr/perf.yml +++ b/eng/pipelines/coreclr/perf.yml @@ -8,6 +8,7 @@ trigger: - '*' - src/libraries/System.Private.CoreLib/* exclude: + - .github/* - docs/* - CODE-OF-CONDUCT.md - CONTRIBUTING.md @@ -60,11 +61,32 @@ jobs: - Windows_NT_x86 jobParameters: testGroup: perf - + +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/mono/templates/build-job.yml + runtimeFlavor: mono + buildConfig: release + platforms: + - Linux_x64 + +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/coreclr/templates/perf-job.yml + buildConfig: release + runtimeFlavor: mono + platforms: + - Linux_x64 + jobParameters: + testGroup: perf + liveLibrariesBuildConfig: Release + runtimeType: mono + - template: /eng/pipelines/common/platform-matrix.yml parameters: jobTemplate: /eng/pipelines/coreclr/templates/perf-job.yml buildConfig: release + runtimeFlavor: coreclr platforms: - Linux_x64 - Windows_NT_x64 diff --git a/eng/pipelines/coreclr/r2r.yml b/eng/pipelines/coreclr/r2r.yml index 04ef6d73c06bf2..781e934c6d6e3b 100644 --- a/eng/pipelines/coreclr/r2r.yml +++ b/eng/pipelines/coreclr/r2r.yml @@ -24,6 +24,8 @@ jobs: - Linux_arm - Linux_arm64 - Linux_x64 + - Windows_NT_arm + - Windows_NT_arm64 - Windows_NT_x64 - Windows_NT_x86 jobParameters: @@ -37,6 +39,8 @@ jobs: - Linux_arm - Linux_arm64 - Linux_x64 + - Windows_NT_arm + - Windows_NT_arm64 - Windows_NT_x64 - Windows_NT_x86 helixQueueGroup: ci diff --git a/eng/pipelines/coreclr/release-tests.yml b/eng/pipelines/coreclr/release-tests.yml index 29342df4f6153c..f597bc1623d1a9 100644 --- a/eng/pipelines/coreclr/release-tests.yml +++ b/eng/pipelines/coreclr/release-tests.yml @@ -32,7 +32,7 @@ jobs: # - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/build-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/build-test-job.yml buildConfig: release platformGroup: all jobParameters: @@ -44,7 +44,7 @@ jobs: # - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/run-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml buildConfig: release platformGroup: all helixQueueGroup: ci @@ -58,7 +58,7 @@ jobs: # - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/run-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml buildConfig: release platformGroup: all helixQueueGroup: ci diff --git a/eng/pipelines/coreclr/templates/build-job.yml b/eng/pipelines/coreclr/templates/build-job.yml index b343975a710b53..c23db63f956668 100644 --- a/eng/pipelines/coreclr/templates/build-job.yml +++ b/eng/pipelines/coreclr/templates/build-job.yml @@ -10,6 +10,7 @@ parameters: osSubgroup: '' platform: '' pool: '' + runtimeVariant: '' signBinaries: false stagedBuild: false testGroup: '' @@ -25,6 +26,7 @@ jobs: archType: ${{ parameters.archType }} osGroup: ${{ parameters.osGroup }} osSubgroup: ${{ parameters.osSubgroup }} + runtimeVariant: ${{ parameters.runtimeVariant }} testGroup: ${{ parameters.testGroup }} helixType: 'build/product/' enableMicrobuild: true @@ -37,8 +39,8 @@ jobs: name: ${{ format('coreclr_{0}_product_build_{1}{1}_{3}_{4}', parameters.compilerName, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} displayName: ${{ format('CoreCLR GCC Product Build {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} ${{ if eq(parameters.compilerName, 'clang') }}: - name: ${{ format('coreclr_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - displayName: ${{ format('CoreCLR Product Build {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} + name: ${{ format('coreclr_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} + displayName: ${{ format('CoreCLR {0} Product Build {1}{2} {3} {4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} # Run all steps in the container. # Note that the containers are defined in platform-matrix.yml @@ -66,10 +68,6 @@ jobs: - ${{ if and(ne(parameters.osGroup, 'Windows_NT'), eq(parameters.compilerName, 'clang')) }}: - name: compilerArg value: '-clang9' - # Our FreeBSD doesn't yet detect available clang versions, so pass it explicitly. - - ${{ if eq(parameters.osGroup, 'FreeBSD') }}: - - name: compilerArg - value: '-clang6.0' # Building for x64 MUSL happens on Alpine Linux and we need to use the stable version available there - ${{ if and(eq(parameters.osGroup, 'Linux'), eq(parameters.osSubgroup, '_musl'), eq(parameters.archType, 'x64')) }}: - name: compilerArg @@ -108,7 +106,7 @@ jobs: # and FreeBSD builds use a build agent with dependencies # preinstalled, so we only need this step for OSX and Windows. - ${{ if eq(parameters.osGroup, 'OSX') }}: - - script: sh $(Build.SourcesDirectory)/eng/install-native-dependencies.sh $(osGroup) + - script: $(Build.SourcesDirectory)/eng/install-native-dependencies.sh $(osGroup) displayName: Install native dependencies - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: # Necessary to install python @@ -122,28 +120,36 @@ jobs: - ${{ if and(eq(variables['System.TeamProject'], 'internal'), ne(variables['Build.Reason'], 'PullRequest')) }}: - template: /eng/pipelines/common/restore-internal-tools.yml - # Build CoreCLR tools needed by the native runtime build - - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -subset clr.buildtools $(crossArg) -arch $(archType) -c $(buildConfig) $(officialBuildIdArg) -ci /bl:$(Build.SourcesDirectory)/artifacts/log/clr.buildtools.binlog - displayName: Build CoreCLR Diagnostic Tools + - ${{ if in(parameters.osGroup, 'OSX', 'iOS','tvOS') }}: + - script: | + du -sh $(Build.SourcesDirectory)/* + df -h + displayName: Disk Usage before Build # Build CoreCLR Runtime - ${{ if ne(parameters.osGroup, 'Windows_NT') }}: - - script: $(coreClrRepoRootDir)build-runtime$(scriptExt) $(buildConfig) $(archType) $(crossArg) -ci $(compilerArg) $(officialBuildIdArg) + - script: $(coreClrRepoRootDir)build-runtime$(scriptExt) $(buildConfig) $(archType) $(crossArg) $(osArg) -ci $(compilerArg) $(officialBuildIdArg) displayName: Build CoreCLR Runtime - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: - script: set __TestIntermediateDir=int&&$(coreClrRepoRootDir)build-runtime$(scriptExt) $(buildConfig) $(archType) -ci $(enforcePgoArg) $(officialBuildIdArg) displayName: Build CoreCLR Runtime + - ${{ if in(parameters.osGroup, 'OSX', 'iOS','tvOS') }}: + - script: | + du -sh $(Build.SourcesDirectory)/* + df -h + displayName: Disk Usage after Build + - ${{ if and(eq(parameters.osGroup, 'Windows_NT'), ne(parameters.archType, 'x86')) }}: - script: set __TestIntermediateDir=int&&$(coreClrRepoRootDir)build-runtime$(scriptExt) $(buildConfig) $(archType) -ci -linuxdac $(officialBuildIdArg) displayName: Build Cross OS Linux DAC for Windows # Build CoreCLR Managed Components - - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -subset clr.corelib+clr.nativecorelib+clr.tools+clr.packages $(crossArg) -arch $(archType) -c $(buildConfig) $(officialBuildIdArg) -ci + - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -subset clr.corelib+clr.nativecorelib+clr.tools+clr.packages $(crossArg) -arch $(archType) $(osArg) -c $(buildConfig) $(officialBuildIdArg) -ci displayName: Build managed product components and packages # Build native test components - - script: $(coreClrRepoRootDir)build-test$(scriptExt) skipmanaged $(buildConfig) $(archType) $(crossArg) $(priorityArg) $(compilerArg) skipgeneratelayout + - script: $(coreClrRepoRootDir)build-test$(scriptExt) skipmanaged $(buildConfig) $(archType) $(crossArg) $(osArg) $(priorityArg) $(compilerArg) skipgeneratelayout displayName: Build native test components # Sign on Windows diff --git a/eng/pipelines/coreclr/templates/build-test-job.yml b/eng/pipelines/coreclr/templates/build-test-job.yml deleted file mode 100644 index 75650136520d55..00000000000000 --- a/eng/pipelines/coreclr/templates/build-test-job.yml +++ /dev/null @@ -1,148 +0,0 @@ -parameters: - buildConfig: '' - archType: '' - osGroup: '' - osSubgroup: '' - container: '' - testGroup: '' - - # When set to a non-empty value (Debug / Release), it determines libraries - # build configuration to use for the tests. Setting this property implies - # a dependency of this job on the appropriate libraries build and is used - # to construct the name of the Azure artifact representing libraries build - # to use for building the tests. - liveLibrariesBuildConfig: '' - - displayNameArgs: '' - condition: true - stagedBuild: false - variables: {} - pool: '' - -### Build managed test components (native components are getting built as part -### of the the product build job). - -### TODO: As of today, build of managed test components requires the product build -### as a prerequisite due to dependency on System.Private.Corelib. After switching -### over to its reference assembly we should be able to remove this dependency and -### run managed test builds in parallel with the product build job. - -jobs: -- template: xplat-pipeline-job.yml - parameters: - buildConfig: ${{ parameters.buildConfig }} - archType: ${{ parameters.archType }} - osGroup: ${{ parameters.osGroup }} - osSubgroup: ${{ parameters.osSubgroup }} - managedTestBuildOsGroup: ${{ parameters.osGroup }} - managedTestBuildOsSubgroup: ${{ parameters.osSubgroup }} - container: ${{ parameters.container }} - testGroup: ${{ parameters.testGroup }} - stagedBuild: ${{ parameters.stagedBuild }} - liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }} - variables: ${{ parameters.variables }} - pool: ${{ parameters.pool }} - - # Test jobs should continue on error for internal builds - ${{ if eq(variables['System.TeamProject'], 'internal') }}: - continueOnError: true - - # Compute job name from template parameters - ${{ if eq(parameters.testGroup, 'innerloop') }}: - name: 'coreclr_test_build_p0_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.buildConfig }}' - displayName: 'CoreCLR Pri0 Test Build ${{ parameters.osGroup }}${{ parameters.osSubgroup }} ${{ parameters.archType }} ${{ parameters.buildConfig }}' - - ${{ if ne(parameters.testGroup, 'innerloop') }}: - name: 'coreclr_test_build_p1_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.buildConfig }}' - displayName: 'CoreCLR Pri1 Test Build ${{ parameters.osGroup }}${{ parameters.osSubgroup }} ${{ parameters.archType }} ${{ parameters.buildConfig }}' - - # Since the condition is being altered, merge the default with the additional conditions. - # See https://docs.microsoft.com/azure/devops/pipelines/process/conditions - condition: and(succeeded(), ${{ parameters.condition }}) - - # TODO: Build of managed test components currently depends on the corresponding build job - # because it needs System.Private.Corelib; we should be able to remove this dependency - # by switching over to using reference assembly. - ${{ if ne(parameters.stagedBuild, true) }}: - dependsOn: - - ${{ format('coreclr_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - - ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}: - - ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveLibrariesBuildConfig) }} - - - ${{ if eq(parameters.testGroup, 'innerloop') }}: - timeoutInMinutes: 90 - - ${{ if ne(parameters.testGroup, 'innerloop') }}: - timeoutInMinutes: 160 - - steps: - - # Install test build dependencies - - ${{ if eq(parameters.osGroup, 'OSX') }}: - - script: sh $(Build.SourcesDirectory)/eng/install-native-dependencies.sh $(osGroup) - displayName: Install native dependencies - - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: - # Necessary to install correct cmake version - - script: $(Build.SourcesDirectory)\eng\common\init-tools-native.cmd -InstallDirectory $(Build.SourcesDirectory)\native-tools -Force - displayName: Install native dependencies - - - # Optionally download live-built libraries - - ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}: - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(librariesDownloadDir) - cleanUnpackFolder: false - artifactFileName: '$(librariesBuildArtifactName)$(archiveExtension)' - artifactName: '$(librariesBuildArtifactName)' - displayName: 'live-built libraries' - - - # Download product binaries directory - - template: /eng/pipelines/common/download-artifact-step.yml - parameters: - unpackFolder: $(buildProductRootFolderPath) - artifactFileName: '$(buildProductArtifactName)$(archiveExtension)' - artifactName: '$(buildProductArtifactName)' - displayName: 'product build' - - - # Build managed test components - - script: $(coreClrRepoRootDir)build-test$(scriptExt) skipnative skipgeneratelayout skiptestwrappers $(buildConfig) $(archType) $(crossArg) $(priorityArg) ci $(librariesOverrideArg) - displayName: Build managed test components - - - # Zip and publish managed test components - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(managedTestArtifactRootFolderPath) - includeRootFolder: false - archiveType: $(archiveType) - tarCompression: $(tarCompression) - archiveExtension: $(archiveExtension) - artifactName: $(managedTestArtifactName) - displayName: 'managed test components' - - - # Publish .packages/microsoft.net.sdk.il needed for traversing - # test projects during the copynativeonly command in run test job. - - template: /eng/pipelines/common/upload-artifact-step.yml - parameters: - rootFolder: $(microsoftNetSdkIlFolderPath) - includeRootFolder: false - archiveType: $(archiveType) - tarCompression: $(tarCompression) - archiveExtension: $(archiveExtension) - artifactName: $(microsoftNetSdkIlArtifactName) - displayName: 'Microsoft.NET.Sdk.IL package' - - - # Publish Logs - - task: PublishPipelineArtifact@1 - displayName: Publish Logs - inputs: - targetPath: $(Build.SourcesDirectory)/artifacts/log - artifactName: 'TestBuildLogs_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)_${{ parameters.testGroup }}' - continueOnError: true - condition: always() diff --git a/eng/pipelines/coreclr/templates/crossgen-comparison-job.yml b/eng/pipelines/coreclr/templates/crossgen-comparison-job.yml index cfecf9bbd5c06f..0e537cb6c7e171 100644 --- a/eng/pipelines/coreclr/templates/crossgen-comparison-job.yml +++ b/eng/pipelines/coreclr/templates/crossgen-comparison-job.yml @@ -5,6 +5,7 @@ parameters: osSubgroup: '' container: '' helixQueues: '' + runtimeVariant: '' crossrootfsDir: '' stagedBuild: false variables: {} @@ -30,6 +31,7 @@ jobs: osGroup: ${{ parameters.osGroup }} osSubgroup: ${{ parameters.osSubgroup }} stagedBuild: ${{ parameters.stagedBuild }} + runtimeVariant: ${{ parameters.runtimeVariant }} liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }} helixType: 'test/crossgen-comparison/' pool: ${{ parameters.pool }} @@ -72,7 +74,7 @@ jobs: # Test job depends on the corresponding build job dependsOn: - - ${{ format('coreclr_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} + - ${{ format('coreclr_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}: - ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveLibrariesBuildConfig) }} diff --git a/eng/pipelines/coreclr/templates/helix-queues-setup.yml b/eng/pipelines/coreclr/templates/helix-queues-setup.yml index e35a69e6f7d5b0..5f970ca5367c8c 100644 --- a/eng/pipelines/coreclr/templates/helix-queues-setup.yml +++ b/eng/pipelines/coreclr/templates/helix-queues-setup.yml @@ -7,6 +7,7 @@ parameters: container: '' pool: '' platform: '' + runtimeFlavorDisplayName: '' jobParameters: {} jobs: @@ -18,6 +19,7 @@ jobs: archType: ${{ parameters.archType }} container: ${{ parameters.container }} pool: ${{ parameters.pool }} + runtimeFlavorDisplayName: ${{ parameters.runtimeFlavorDisplayName }} helixQueues: # Linux arm diff --git a/eng/pipelines/coreclr/templates/perf-job.yml b/eng/pipelines/coreclr/templates/perf-job.yml index d71e26001c44c1..003e58f276146d 100644 --- a/eng/pipelines/coreclr/templates/perf-job.yml +++ b/eng/pipelines/coreclr/templates/perf-job.yml @@ -4,9 +4,11 @@ parameters: osGroup: '' osSubgroup: '' container: '' - framework: netcoreapp5.0 # Specify the appropriate framework when running release branches (ie netcoreapp3.0 for release/3.0) + runtimeVariant: '' + framework: net5.0 # Specify the appropriate framework when running release branches (ie netcoreapp3.0 for release/3.0) liveLibrariesBuildConfig: '' variables: {} + runtimeType: 'coreclr' pool: '' ### Perf job @@ -18,24 +20,34 @@ jobs: - template: run-performance-job.yml parameters: # Compute job name from template parameters - jobName: ${{ format('perfbuild_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - displayName: ${{ format('Performance {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} + jobName: ${{ format('perfbuild_{0}{1}_{2}_{3}_{4}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.runtimeType) }} + displayName: ${{ format('Performance {0}{1} {2} {3} {4}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.runtimeType) }} pool: ${{ parameters.pool }} buildConfig: ${{ parameters.buildConfig }} archType: ${{ parameters.archType }} osGroup: ${{ parameters.osGroup }} osSubgroup: ${{ parameters.osSubgroup }} + runtimeVariant: ${{ parameters.runtimeVariant }} liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }} + runtimeType: ${{ parameters.runtimeType }} # Test job depends on the corresponding build job dependsOn: - - ${{ format('coreclr_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} + - ${{ format('coreclr_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}: - ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveLibrariesBuildConfig) }} + - ${{ if eq(parameters.runtimeType, 'mono') }}: + - ${{ format('mono_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} ${{ if eq(parameters.osGroup, 'Windows_NT') }}: - extraSetupParameters: -CoreRootDirectory $(Build.SourcesDirectory)\artifacts\tests\coreclr\${{ parameters.osGroup }}.${{ parameters.archType }}.Release\Tests\Core_Root -Architecture ${{ parameters.archType }} + ${{ if eq(parameters.runtimeType, 'mono') }}: + extraSetupParameters: -Architecture ${{ parameters.archType }} -MonoDotnet $(Build.SourcesDirectory)\.dotnet-mono -Kind micro_mono + ${{ if ne(parameters.runtimeType, 'mono') }}: + extraSetupParameters: -CoreRootDirectory $(Build.SourcesDirectory)\artifacts\tests\coreclr\${{ parameters.osGroup }}.${{ parameters.archType }}.Release\Tests\Core_Root -Architecture ${{ parameters.archType }} ${{ if ne(parameters.osGroup, 'Windows_NT') }}: - extraSetupParameters: --corerootdirectory $(Build.SourcesDirectory)/artifacts/tests/coreclr/${{ parameters.osGroup }}.${{ parameters.archType }}.Release/Tests/Core_Root --architecture ${{ parameters.archType }} + ${{ if eq(parameters.runtimeType, 'mono') }}: + extraSetupParameters: --architecture ${{ parameters.archType }} --monodotnet $(Build.SourcesDirectory)/.dotnet-mono --kind micro_mono + ${{ if ne(parameters.runtimeType, 'mono') }}: + extraSetupParameters: --corerootdirectory $(Build.SourcesDirectory)/artifacts/tests/coreclr/${{ parameters.osGroup }}.${{ parameters.archType }}.Release/Tests/Core_Root --architecture ${{ parameters.archType }} variables: ${{ parameters.variables }} @@ -44,7 +56,6 @@ jobs: steps: # Extra steps that will be passed to the performance template and run before sending the job to helix (all of which is done in the template) - # Optionally download live-built libraries - ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}: - template: /eng/pipelines/common/download-artifact-step.yml @@ -64,7 +75,24 @@ jobs: artifactName: '$(buildProductArtifactName)' displayName: 'product build' + - ${{ if eq(parameters.runtimeType, 'mono') }}: + - template: /eng/pipelines/common/download-artifact-step.yml + parameters: + unpackFolder: $(librariesDownloadDir)/bin/mono/$(osGroup).$(archType).$(buildConfigUpper) + cleanUnpackFolder: false + artifactFileName: 'MonoProduct_${{ parameters.runtimeVariant }}_$(osGroup)_$(archType)_$(buildConfig)$(archiveExtension)' + artifactName: 'MonoProduct_${{ parameters.runtimeVariant }}_$(osGroup)_$(archType)_$(buildConfig)' + displayName: 'Mono runtime' # Create Core_Root - script: $(coreClrRepoRootDir)build-test$(scriptExt) $(buildConfig) $(archType) generatelayoutonly $(librariesOverrideArg) displayName: Create Core_Root + condition: and(succeeded(), ne(variables.runtimeFlavorName, 'Mono')) + + - script: "build.cmd -subset libs.pretest -configuration release -ci -arch $(archType) -testscope innerloop /p:RuntimeArtifactsPath=$(librariesDownloadDir)\\bin\\mono\\$(osGroup).$(archType).$(buildConfigUpper) /p:RuntimeFlavor=mono;xcopy $(Build.SourcesDirectory)\\artifacts\\bin\\testhost\\$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)\\* $(Build.SourcesDirectory)\\.dotnet-mono /E /I /Y;copy $(Build.SourcesDirectory)\\artifacts\\bin\\coreclr\\$(osGroup).$(archType).$(buildConfigUpper)\\corerun.exe $(Build.SourcesDirectory)\\.dotnet-mono\\shared\\Microsoft.NETCore.App\\5.0.0\\corerun.exe" + displayName: "Create mono dotnet (Windows)" + condition: and(and(succeeded(), eq(variables.runtimeFlavorName, 'Mono')), eq(variables.osGroup, 'Windows_NT')) + + - script: "mkdir $(Build.SourcesDirectory)/.dotnet-mono;./build.sh -subset libs.pretest -configuration release -ci -arch $(archType) -testscope innerloop /p:RuntimeArtifactsPath=$(librariesDownloadDir)/bin/mono/$(osGroup).$(archType).$(buildConfigUpper) /p:RuntimeFlavor=mono;cp $(Build.SourcesDirectory)/artifacts/bin/testhost/$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)/* $(Build.SourcesDirectory)/.dotnet-mono -r;cp $(Build.SourcesDirectory)/artifacts/bin/coreclr/$(osGroup).$(archType).$(buildConfigUpper)/corerun $(Build.SourcesDirectory)/.dotnet-mono/shared/Microsoft.NETCore.App/5.0.0/corerun" + displayName: "Create mono dotnet (Linux)" + condition: and(and(succeeded(), eq(variables.runtimeFlavorName, 'Mono')), ne(variables.osGroup, 'Windows_NT')) diff --git a/eng/pipelines/coreclr/templates/run-performance-job.yml b/eng/pipelines/coreclr/templates/run-performance-job.yml index 1e37e86c8a6459..881a498fbd20de 100644 --- a/eng/pipelines/coreclr/templates/run-performance-job.yml +++ b/eng/pipelines/coreclr/templates/run-performance-job.yml @@ -16,6 +16,7 @@ parameters: timeoutInMinutes: 320 # optional -- timeout for the job enableTelemetry: false # optional -- enable for telemetry liveLibrariesBuildConfig: '' # optional -- live-live libraries configuration to use for the run + runtimeType: 'coreclr' jobs: - template: xplat-pipeline-job.yml @@ -103,3 +104,10 @@ jobs: WorkItemTimeout: 4:00 # 4 hours WorkItemDirectory: '$(WorkItemDirectory)' # WorkItemDirectory can not be empty, so we send it some docs to keep it happy CorrelationPayloadDirectory: '$(PayloadDirectory)' # it gets checked out to a folder with shorter path than WorkItemDirectory so we can avoid file name too long exceptions + - task: PublishPipelineArtifact@1 + displayName: Publish Logs + inputs: + targetPath: $(Build.SourcesDirectory)/artifacts/log + artifactName: 'Performance_Run_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)_${{ parameters.runtimeType }}' + continueOnError: true + condition: always() diff --git a/eng/pipelines/coreclr/templates/test-job.yml b/eng/pipelines/coreclr/templates/test-job.yml index e1679923841cb2..9c0cf47dd7f730 100644 --- a/eng/pipelines/coreclr/templates/test-job.yml +++ b/eng/pipelines/coreclr/templates/test-job.yml @@ -27,7 +27,7 @@ parameters: jobs: - ${{ if and(ne(parameters.corefxTests, true), eq(parameters.osSubgroup, parameters.managedTestBuildOsSubgroup), eq(parameters.osGroup, parameters.managedTestBuildOsGroup)) }}: - - template: /eng/pipelines/coreclr/templates/build-test-job.yml + - template: /eng/pipelines/common/templates/runtimes/build-test-job.yml parameters: buildConfig: ${{ parameters.buildConfig }} liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }} @@ -42,7 +42,7 @@ jobs: variables: ${{ parameters.variables }} pool: ${{ parameters.pool }} -- template: /eng/pipelines/coreclr/templates/run-test-job.yml +- template: /eng/pipelines/common/templates/runtimes/run-test-job.yml parameters: buildConfig: ${{ parameters.buildConfig }} liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }} diff --git a/eng/pipelines/coreclr/templates/xplat-pipeline-job.yml b/eng/pipelines/coreclr/templates/xplat-pipeline-job.yml index aad6f7bf69fa40..daa189d88d6da3 100644 --- a/eng/pipelines/coreclr/templates/xplat-pipeline-job.yml +++ b/eng/pipelines/coreclr/templates/xplat-pipeline-job.yml @@ -68,13 +68,21 @@ jobs: - name: binTestsPath value: '$(Build.SourcesDirectory)/artifacts/tests/coreclr' - + + # Build product defines what we are trying to build, either coreclr or mono - name: buildProductArtifactName - value: 'CoreCLRProduct_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)' + value: 'CoreCLRProduct_${{ parameters.runtimeVariant }}_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)' - name: buildProductRootFolderPath value: '$(Build.SourcesDirectory)/artifacts/bin/coreclr/$(osGroup).$(archType).$(buildConfigUpper)' + # We need this because both mono and coreclr build currently depends on CoreClr + - name: coreClrProductArtifactName + value: 'CoreCLRProduct_${{ parameters.runtimeVariant }}_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)' + + - name: coreClrProductRootFolderPath + value: '$(Build.SourcesDirectory)/artifacts/bin/coreclr/$(osGroup).$(archType).$(buildConfigUpper)' + - name: corelibProductArtifactName value: 'CoreLib_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)' @@ -119,4 +127,11 @@ jobs: - ${{ each variable in parameters.variables }}: - ${{insert}}: ${{ variable }} + - name: osArg + value: '' + + - ${{ if eq(parameters.osGroup, 'FreeBSD') }}: + - name: osArg + value: -os FreeBSD + steps: ${{ parameters.steps }} diff --git a/eng/pipelines/evaluate-changed-paths.sh b/eng/pipelines/evaluate-changed-paths.sh index 0df618957245b4..bfc5c857b64fe6 100755 --- a/eng/pipelines/evaluate-changed-paths.sh +++ b/eng/pipelines/evaluate-changed-paths.sh @@ -162,7 +162,7 @@ probePaths() { if [[ "$include_path_string" == "" ]]; then include_path_string=":$_path" else - include_path_string="$exclude_path_string :$_path" + include_path_string="$include_path_string :$_path" fi done diff --git a/eng/pipelines/global-build.yml b/eng/pipelines/global-build.yml index 8006c888ee00c2..ff9600d83fea6f 100644 --- a/eng/pipelines/global-build.yml +++ b/eng/pipelines/global-build.yml @@ -15,6 +15,7 @@ pr: - docs/manpages/* - eng/pipelines/global-build.yml exclude: + - .github/* - docs/* - eng/pipelines/coreclr/*.* - eng/pipelines/libraries/*.* @@ -91,4 +92,17 @@ jobs: jobParameters: testGroup: innerloop nameSuffix: Mono_Libraries - buildArgs: -subset mono+libs /p:RuntimeFlavor=Mono \ No newline at end of file + buildArgs: -subset mono+libs /p:RuntimeFlavor=Mono + +# +# SourceBuild Build +# +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/global-build-job.yml + buildConfig: release + platforms: + - Linux_x64 + jobParameters: + nameSuffix: SourceBuild + buildArgs: /p:DotNetBuildFromSource=true \ No newline at end of file diff --git a/eng/pipelines/installer/installer-matrix.yml b/eng/pipelines/installer/installer-matrix.yml index bb5e6e46f96c43..e9ae06bf267690 100644 --- a/eng/pipelines/installer/installer-matrix.yml +++ b/eng/pipelines/installer/installer-matrix.yml @@ -3,6 +3,7 @@ parameters: platforms: [] jobParameters: [] buildConfig: Release + runtimeVariant: '' jobs: @@ -16,5 +17,6 @@ jobs: platforms: ${{ parameters.platforms }} passPlatforms: true runtimeFlavor: ${{ parameters.runtimeFlavor }} + runtimeVariant: ${{ parameters.runtimeVariant }} jobParameters: ${{ insert }}: ${{ parameters.jobParameters }} diff --git a/eng/pipelines/installer/jobs/base-job.yml b/eng/pipelines/installer/jobs/base-job.yml index 3a6494b0b23df9..8e9c3f1824bb20 100644 --- a/eng/pipelines/installer/jobs/base-job.yml +++ b/eng/pipelines/installer/jobs/base-job.yml @@ -13,6 +13,7 @@ parameters: variables: [] name: '' displayName: '' + runtimeVariant: '' pool: '' packageDistroList: @@ -38,8 +39,8 @@ parameters: platforms: [] jobs: -- job: ${{ format('installer_{0}_{1}', coalesce(parameters.name, parameters.platform), parameters.buildConfig) }} - displayName: ${{ format('Installer Build and Test {0} {1}', coalesce(parameters.name, parameters.platform), parameters.buildConfig) }} +- job: ${{ format('installer_{0}_{1}_{2}_{3}', parameters.runtimeFlavor, parameters.runtimeVariant, coalesce(parameters.name, parameters.platform), parameters.buildConfig) }} + displayName: ${{ format('Installer Build and Test {0} {1} {2} {3}', parameters.runtimeFlavor, parameters.runtimeVariant, coalesce(parameters.name, parameters.platform), parameters.buildConfig) }} condition: and(succeeded(), ${{ parameters.condition }}) pool: ${{ parameters.pool }} @@ -65,13 +66,28 @@ jobs: - name: SkipTests value: ${{ or( not(in(parameters.archType, 'x64', 'x86')), - in(parameters.osGroup, 'iOS', 'tvOS', 'Android'), + eq(parameters.runtimeFlavor, 'mono'), eq(parameters.isOfficialBuild, true), ne(parameters.crossrootfsDir, '')) }} + - name: BuildAction + value: -test + + - ${{ if eq(variables.SkipTests, true) }}: + - name: BuildAction + value: '' + - name: SignType value: test + - ${{ if eq(parameters.runtimeVariant, 'llvmjit') }}: + - name: llvmParameter + value: /p:MonoEnableLLVM=true + + - ${{ if eq(parameters.runtimeVariant, 'llvmaot') }}: + - name: llvmParameter + value: /p:MonoEnableLLVM=true /p:MonoBundleLLVMOptimizer=true + # Set up non-PR build from internal project - ${{ if eq(parameters.isOfficialBuild, true) }}: - name: SignType @@ -80,10 +96,10 @@ jobs: value: /p:OfficialBuildId=$(Build.BuildNumber) - name: buildCommandSourcesDirectory - ${{ if ne(parameters.osGroup, 'Linux') }}: + ${{ if not(in(parameters.osGroup, 'Linux', 'FreeBSD')) }}: value: '$(Build.SourcesDirectory)/' # This job runs within Docker containers, so Build.SourcesDirectory is not accurate. - ${{ if eq(parameters.osGroup, 'Linux') }}: + ${{ if in(parameters.osGroup, 'Linux', 'FreeBSD') }}: value: '/root/runtime/' ### @@ -97,6 +113,8 @@ jobs: /p:TargetArchitecture=${{ parameters.archType }} /p:PortableBuild=true /p:SkipTests=$(SkipTests) + /p:RuntimeFlavor=${{ parameters.runtimeFlavor }} + $(llvmParameter) $(OfficialBuildArg) - name: MsbuildSigningArguments value: >- @@ -107,7 +125,8 @@ jobs: - name: BaseJobBuildCommand value: >- - build.cmd -subset installer -test -ci + build.cmd -subset installer -ci + $(BuildAction) -configuration $(_BuildConfig) $(LiveOverridePathArgs) $(CommonMSBuildArgs) @@ -119,25 +138,30 @@ jobs: value: >- /p:PortableBuild=true /p:SkipTests=$(SkipTests) + /p:RuntimeFlavor=${{ parameters.runtimeFlavor }} + $(llvmParameter) - name: BaseJobBuildCommand value: >- - $(Build.SourcesDirectory)/build.sh -subset installer -test -ci + $(Build.SourcesDirectory)/build.sh -subset installer -ci + $(BuildAction) -configuration $(_BuildConfig) $(LiveOverridePathArgs) $(CommonMSBuildArgs) $(OfficialBuildArg) - - ${{ if in(parameters.osGroup, 'iOS', 'tvOS', 'Android') }}: + - ${{ if in(parameters.osGroup, 'iOS', 'tvOS', 'Android', 'Browser') }}: - name: CommonMSBuildArgs value: >- /p:PortableBuild=true /p:SkipTests=$(SkipTests) + $(llvmParameter) - name: BaseJobBuildCommand value: >- - $(Build.SourcesDirectory)/build.sh -subset installer --ci --test + $(Build.SourcesDirectory)/build.sh -subset installer -ci + $(BuildAction) -configuration $(_BuildConfig) -os ${{ parameters.osGroup }} -arch ${{ parameters.archType }} @@ -146,7 +170,7 @@ jobs: $(CommonMSBuildArgs) $(OfficialBuildArg) - - ${{ if eq(parameters.osGroup, 'Linux') }}: + - ${{ if in(parameters.osGroup, 'Linux', 'FreeBSD') }}: # Preserve the NuGet authentication env vars into the Docker container. # The 'NuGetAuthenticate' build step may have set these. @@ -165,10 +189,6 @@ jobs: -e ROOTFS_DIR=${{ parameters.crossrootfsDir }} ${{ parameters.container }} - - ${{ if eq(parameters.name, 'FreeBSD_x64') }}: - - name: RunArguments - value: export DotNetBootstrapCliTarPath=/dotnet-sdk-freebsd-x64.tar && - - name: BuildScript value: ./build.sh - name: MSBuildScript @@ -183,8 +203,11 @@ jobs: - name: CommonMSBuildArgs value: >- /p:Configuration=$(_BuildConfig) + /p:TargetOS=${{ parameters.osGroup }} /p:TargetArchitecture=${{ parameters.archType }} + /p:RuntimeFlavor=${{ parameters.runtimeFlavor }} $(OfficialBuildArg) + $(llvmParameter) - name: _PortableBuild value: ${{ eq(parameters.osSubgroup, '') }} @@ -199,7 +222,8 @@ jobs: - name: BuildArguments value: >- - -subset installer -test -ci + -subset installer -ci + $(BuildAction) /p:CrossBuild=${{ ne(parameters.crossrootfsDir, '') }} /p:PortableBuild=$(_PortableBuild) /p:SkipTests=$(SkipTests) @@ -281,7 +305,7 @@ jobs: /p:RuntimeArtifactsPath=$(buildCommandSourcesDirectory)$(RuntimeDownloadPath) /p:RuntimeConfiguration=${{ parameters.liveRuntimeBuildConfig }} - name: RuntimeArtifactName - value: $(runtimeFlavorName)Product_$(liveRuntimeLegName) + value: $(runtimeFlavorName)Product_${{ parameters.runtimeVariant }}_$(liveRuntimeLegName) - ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}: - name: liveLibrariesLegName @@ -320,8 +344,9 @@ jobs: - checkout - ${{ parameters.dependsOn }} - ${{ if ne(parameters.liveRuntimeBuildConfig, '') }}: - - ${{ format('{0}_product_build_{1}{2}_{3}_{4}', + - ${{ format('{0}_{1}_product_build_{2}{3}_{4}_{5}', parameters.runtimeFlavor, + parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, @@ -336,7 +361,7 @@ jobs: - libraries_build_allconfigurations_Windows_NT_x64_Release - ${{ if eq(parameters.buildFullPlatformManifest, true) }}: - ${{ each platform in parameters.platforms }}: - - ${{ parameters.runtimeFlavor }}_product_build_${{ platform }}_${{ parameters.liveRuntimeBuildConfig }} + - ${{ parameters.runtimeFlavor }}_${{ parameters.runtimeVariant }}_product_build_${{ platform }}_${{ parameters.liveRuntimeBuildConfig }} - libraries_build_${{ platform }}_${{ parameters.liveLibrariesBuildConfig }} steps: @@ -431,11 +456,26 @@ jobs: displayName: 'Libraries artifacts (AllConfigurations)' cleanUnpackFolder: false + - ${{ if in(parameters.osGroup, 'OSX', 'iOS', 'tvOS') }}: + - script: $(Build.SourcesDirectory)/eng/install-native-dependencies.sh ${{ parameters.osGroup }} + displayName: Install Build Dependencies + + - script: | + du -sh $(Build.SourcesDirectory)/* + df -h + displayName: Disk Usage before Build + - script: $(BaseJobBuildCommand) displayName: Build + - ${{ if in(parameters.osGroup, 'OSX', 'iOS','tvOS') }}: + - script: | + du -sh $(Build.SourcesDirectory)/* + df -h + displayName: Disk Usage after Build + # Only in glibc leg, we produce RPMs and Debs - - ${{ if and(eq(parameters.platform, 'Linux_x64'), eq(parameters.osSubgroup, ''))}}: + - ${{ if and(eq(parameters.runtimeFlavor, 'coreclr'), eq(parameters.platform, 'Linux_x64'), eq(parameters.osSubgroup, ''))}}: - task: CopyFiles@2 displayName: 'Copy built Portable linux-x64 binaries to staging directory' inputs: @@ -448,7 +488,6 @@ jobs: # independent installers on this leg, but we need to do it somewhere.) - template: steps/build-linux-package.yml parameters: - buildTraversalBuildDependencies: true distroRid: ${{ packageBuild.imageRid }} image: ${{ packageBuild.image }} packageStepDescription: Runtime Deps, Runtime, Framework Packs installers @@ -496,6 +535,8 @@ jobs: - template: steps/upload-job-artifacts.yml parameters: name: ${{ coalesce(parameters.name, parameters.platform) }} + runtimeFlavor: ${{ parameters.runtimeFlavor }} + runtimeVariant: ${{ parameters.runtimeVariant }} skipTests: $(SkipTests) isOfficialBuild: ${{ eq(parameters.isOfficialBuild, true) }} diff --git a/eng/pipelines/installer/jobs/steps/build-linux-package.yml b/eng/pipelines/installer/jobs/steps/build-linux-package.yml index e9e342b618c1e8..e0129ccff6317c 100644 --- a/eng/pipelines/installer/jobs/steps/build-linux-package.yml +++ b/eng/pipelines/installer/jobs/steps/build-linux-package.yml @@ -1,5 +1,4 @@ parameters: - buildTraversalBuildDependencies: false distroRid: null image: null outputRidArg: '' @@ -8,18 +7,6 @@ parameters: subsetArg: '' steps: -- ${{ if eq(parameters.buildTraversalBuildDependencies, true) }}: - - script: | - set -x - df -h - $(DockerRunMSBuild) ${{ parameters.image }} $(MSBuildScript) \ - --ci \ - /root/runtime/tools-local/tasks/installer.tasks/installer.tasks.csproj \ - /t:Restore /t:Build /t:CreateHostMachineInfoFile \ - $(CommonMSBuildArgs) \ - /bl:msbuild.${{ parameters.distroRid }}.traversaldependencies.binlog - displayName: ====== Build traversal build dependencies - ${{ parameters.distroRid }} - - script: | set -x df -h @@ -32,5 +19,6 @@ steps: ${{ parameters.packagingArgs }} \ $(CommonMSBuildArgs) \ ${{ parameters.outputRidArg }} \ + $(LiveOverridePathArgs) \ /bl:artifacts/log/$(_BuildConfig)/msbuild.${{ parameters.distroRid }}.installers.binlog displayName: Package ${{ parameters.packageStepDescription }} - ${{ parameters.distroRid }} diff --git a/eng/pipelines/installer/jobs/steps/upload-job-artifacts.yml b/eng/pipelines/installer/jobs/steps/upload-job-artifacts.yml index 05232836e569c5..884ca0177e7f81 100644 --- a/eng/pipelines/installer/jobs/steps/upload-job-artifacts.yml +++ b/eng/pipelines/installer/jobs/steps/upload-job-artifacts.yml @@ -1,6 +1,7 @@ parameters: name: '' - + runtimeFlavor: 'coreclr' + runtimeVariant: '' isOfficialBuild: false steps: @@ -17,7 +18,7 @@ steps: testResultsFiles: '*.xml' searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)' mergeTestResults: true - testRunTitle: Installer-${{ parameters.name }}-$(_BuildConfig) + testRunTitle: Installer-${{ parameters.runtimeFlavor }}-${{ parameters.name }}-$(_BuildConfig) continueOnError: true condition: eq(variables.SkipTests, false) @@ -37,6 +38,6 @@ steps: displayName: Publish BuildLogs inputs: targetPath: '$(Build.StagingDirectory)/BuildLogs' - artifactName: Installer-Logs-${{ parameters.name }}-$(_BuildConfig) + artifactName: Installer-Logs-${{ parameters.runtimeFlavor }}-${{ parameters.runtimeVariant }}-${{ parameters.name }}-$(_BuildConfig) continueOnError: true condition: succeededOrFailed() diff --git a/eng/pipelines/libraries/base-job.yml b/eng/pipelines/libraries/base-job.yml index df6f5e31a73468..b1a801f9657897 100644 --- a/eng/pipelines/libraries/base-job.yml +++ b/eng/pipelines/libraries/base-job.yml @@ -5,8 +5,8 @@ parameters: osSubgroup: '' crossrootfsDir: '' framework: '' - isOfficialBuild: false isOfficialAllConfigurations: false + isSourceBuild: false liveRuntimeBuildConfig: '' runtimeFlavor: 'coreclr' timeoutInMinutes: 150 @@ -54,7 +54,7 @@ jobs: - ${{ if ne(parameters.testScope, '') }}: - _testScopeArg: -testscope ${{ parameters.testScope }} - - ${{ if eq(parameters.osGroup, 'Linux') }}: + - ${{ if in(parameters.osGroup, 'Linux', 'FreeBSD') }}: - _crossBuildPropertyArg: /p:CrossBuild=${{ ne(parameters.crossrootfsDir, '') }} - ${{ if and(eq(parameters.osGroup, 'Linux'), eq(parameters.osSubGroup, '_musl')) }}: @@ -63,20 +63,8 @@ jobs: - ${{ if and(eq(parameters.osGroup, 'Linux'), eq(parameters.osSubGroup, ''), eq(parameters.archType, 'arm')) }}: - _runtimeOSArg: /p:RuntimeOS=ubuntu.16.04 - # force a value for OS when cross-building WebAssembly - - ${{ if eq(parameters.osGroup, 'WebAssembly') }}: - - _runtimeOSArg: -os ${{ parameters.osGroup }} - - # force a value for OS when cross-building tvOS on OSX - - ${{ if eq(parameters.osGroup, 'tvOS') }}: - - _runtimeOSArg: -os ${{ parameters.osGroup }} - - # force a value for OS when cross-building iOS on OSX - - ${{ if eq(parameters.osGroup, 'iOS') }}: - - _runtimeOSArg: -os ${{ parameters.osGroup }} - - # force a value for OS when cross-building Android on Linux - - ${{ if eq(parameters.osGroup, 'Android') }}: + # force a value for OS when cross-building + - ${{ if in(parameters.osGroup, 'Browser', 'iOS', 'tvOS', 'Android', 'FreeBSD') }}: - _runtimeOSArg: -os ${{ parameters.osGroup }} - ${{ if ne(parameters.framework, '') }}: @@ -103,7 +91,7 @@ jobs: - _runtimeConfigurationArg: -rc ${{ parameters.liveRuntimeBuildConfig }} # Download full product dependencies for mono or test - ${{ if or(ne(parameters.runtimeFlavor, 'coreclr'), ne(parameters.testScope, '')) }}: - - _runtimeArtifactName: '$(runtimeFlavorName)Product_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.liveRuntimeBuildConfig }}' + - _runtimeArtifactName: '$(runtimeFlavorName)Product_${{ parameters.runtimeVariant}}_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.liveRuntimeBuildConfig }}' - _runtimeArtifactsPathArg: ' /p:RuntimeArtifactsPath=$(_runtimeDownloadPath)' - _testRunNamePrefixSuffix: $(runtimeFlavorName)_${{ parameters.liveRuntimeBuildConfig }} diff --git a/eng/pipelines/libraries/build-job.yml b/eng/pipelines/libraries/build-job.yml index c541e688803d21..f33f413f457eef 100644 --- a/eng/pipelines/libraries/build-job.yml +++ b/eng/pipelines/libraries/build-job.yml @@ -7,6 +7,7 @@ parameters: framework: '' isOfficialBuild: false isOfficialAllConfigurations: false + runtimeVariant: '' # When set to a non-empty value (Debug / Release), it determines the runtime's # build configuration to use for building libraries and tests. Setting this @@ -43,6 +44,7 @@ jobs: container: ${{ parameters.container }} condition: ${{ parameters.condition }} pool: ${{ parameters.pool }} + runtimeVariant: ${{ parameters.runtimeVariant }} testScope: ${{ parameters.testScope }} name: build displayName: 'Build' @@ -51,13 +53,13 @@ jobs: dependsOn: # Use full product dependency for non-coreclr and test builds - ${{ if or(ne(parameters.runtimeFlavor, 'coreclr'), ne(parameters.testScope, '')) }}: - - ${{ format('{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeFlavor, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveRuntimeBuildConfig) }} + - ${{ format('{0}_{1}_product_build_{2}{3}_{4}_{5}', parameters.runtimeFlavor, parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveRuntimeBuildConfig) }} variables: - _subset: libs - _additionalBuildArguments: '' - ${{ parameters.variables }} - - ${{ if eq(parameters.osGroup, 'WebAssembly') }}: + - ${{ if eq(parameters.osGroup, 'Browser') }}: - EMSDK_PATH: /usr/local/emscripten # for coreclr library builds (when not testing) build corelib as well. - ${{ if and(eq(parameters.runtimeFlavor, 'coreclr'), eq(parameters.testScope, '')) }}: @@ -70,24 +72,30 @@ jobs: - ${{ parameters.variables }} steps: - - ${{ if eq(parameters.osGroup, 'OSX') }}: - - script: | - brew install pkgconfig icu4c openssl - brew link --force icu4c - ln -s /usr/local/opt/openssl/lib/pkgconfig/libcrypto.pc /usr/local/lib/pkgconfig/ - ln -s /usr/local/opt/openssl/lib/pkgconfig/libssl.pc /usr/local/lib/pkgconfig/ - ln -s /usr/local/opt/openssl/lib/pkgconfig/openssl.pc /usr/local/lib/pkgconfig/ - displayName: Install Build Dependencies - - ${{ if eq(parameters.isOfficialBuild, true) }}: - template: /eng/pipelines/common/restore-internal-tools.yml + - ${{ if in(parameters.osGroup, 'OSX', 'iOS', 'tvOS') }}: + - script: $(Build.SourcesDirectory)/eng/install-native-dependencies.sh ${{ parameters.osGroup }} + displayName: Install Build Dependencies + + - script: | + du -sh $(Build.SourcesDirectory)/* + df -h + displayName: Disk Usage before Build + - script: $(_buildScript) -subset $(_subset) $(_buildArguments) $(_additionalBuildArguments) displayName: Restore and Build Product + - ${{ if in(parameters.osGroup, 'OSX', 'iOS','tvOS') }}: + - script: | + du -sh $(Build.SourcesDirectory)/* + df -h + displayName: Disk Usage after Build + - ${{ if eq(parameters.runTests, false) }}: - ${{ if ne(parameters.isOfficialBuild, true) }}: - task: CopyFiles@2 @@ -145,12 +153,6 @@ jobs: targetFolder: $(Build.ArtifactStagingDirectory)/artifacts/packages condition: and(succeeded(), eq(variables['_librariesBuildProducedPackages'], true)) - - task: CopyFiles@2 - displayName: Prepare tmp assets to publish - inputs: - sourceFolder: $(Build.SourcesDirectory)/artifacts/tmp - targetFolder: $(Build.ArtifactStagingDirectory)/artifacts/tmp - - template: /eng/pipelines/common/upload-artifact-step.yml parameters: rootFolder: $(Build.ArtifactStagingDirectory)/artifacts diff --git a/eng/pipelines/libraries/build-test-job.yml b/eng/pipelines/libraries/build-test-job.yml index 82da2388581bf7..0ce715add47c9d 100644 --- a/eng/pipelines/libraries/build-test-job.yml +++ b/eng/pipelines/libraries/build-test-job.yml @@ -7,6 +7,7 @@ parameters: isOfficialBuild: false liveRuntimeBuildConfig: '' runtimeFlavor: 'coreclr' + runtimeVariant: '' timeoutInMinutes: 150 container: '' publishTestArtifacs: true @@ -29,6 +30,7 @@ jobs: liveRuntimeBuildConfig: ${{ parameters.liveRuntimeBuildConfig }} timeoutInMinutes: ${{ parameters.timeoutInMinutes }} container: ${{ parameters.container }} + runtimeVariant: ${{ parameters.runtimeVariant }} pool: ${{ parameters.pool }} testScope: ${{ parameters.testScope }} name: test_build @@ -38,7 +40,7 @@ jobs: - ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} # Libraries Test also depends on Product, now that the libraries build only depends on corelib - ${{ if ne(parameters.liveRuntimeBuildConfig, '') }}: - - ${{ format('{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeFlavor, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveRuntimeBuildConfig) }} + - ${{ format('{0}_{1}_product_build_{2}{3}_{4}_{5}', parameters.runtimeFlavor, parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveRuntimeBuildConfig) }} variables: - librariesTestsArtifactName: ${{ format('libraries_test_assets_{0}_{1}_{2}', parameters.osGroup, parameters.archType, parameters.buildConfig) }} @@ -55,12 +57,24 @@ jobs: unpackFolder: $(Build.SourcesDirectory)/artifacts cleanUnpackFolder: false + - ${{ if in(parameters.osGroup, 'OSX', 'iOS','tvOS') }}: + - script: | + du -sh $(Build.SourcesDirectory)/* + df -h + displayName: Disk Usage before Build + - script: $(_buildScript) -subset libs.pretest+libs.tests $(_buildArguments) $(_archiveTestsParameter) displayName: Restore and Build + - ${{ if in(parameters.osGroup, 'OSX', 'iOS','tvOS') }}: + - script: | + du -sh $(Build.SourcesDirectory)/* + df -h + displayName: Disk Usage after Build + - template: /eng/pipelines/common/upload-artifact-step.yml parameters: rootFolder: $(Build.SourcesDirectory)/artifacts/helix diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml index 10b99697d0b734..7e450f8f4c0d00 100644 --- a/eng/pipelines/libraries/helix-queues-setup.yml +++ b/eng/pipelines/libraries/helix-queues-setup.yml @@ -7,6 +7,7 @@ parameters: container: '' pool: '' platform: '' + runtimeFlavorDisplayName: '' jobParameters: {} jobs: @@ -18,6 +19,7 @@ jobs: archType: ${{ parameters.archType }} container: ${{ parameters.container }} pool: ${{ parameters.pool }} + runtimeFlavorDisplayName: ${{ parameters.runtimeFlavorDisplayName }} helixQueues: # Linux arm @@ -56,8 +58,8 @@ jobs: - Ubuntu.1804.Amd64.Open - SLES.12.Amd64.Open - SLES.15.Amd64.Open - - (Fedora.29.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-29-helix-a12566d-20191210224553 - (Fedora.30.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-30-helix-4f8cef7-20200121150022 + - (Fedora.32.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-32-helix-20200512010618-efb9f14 - (Ubuntu.1910.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-19.10-helix-amd64-cfcfd50-20191030180623 - (Debian.10.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-amd64-bfcd90a-20200121150006 - ${{ if eq(parameters.jobParameters.isFullMatrix, false) }}: @@ -67,7 +69,7 @@ jobs: - Ubuntu.1604.Amd64.Open - Ubuntu.1804.Amd64.Open - SLES.15.Amd64.Open - - (Fedora.29.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-29-helix-a12566d-20191210224553 + - (Fedora.30.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-30-helix-4f8cef7-20200121150022 # OSX x64 - ${{ if eq(parameters.platform, 'OSX_x64') }}: @@ -86,14 +88,16 @@ jobs: # netcoreapp - ${{ if notIn(parameters.jobParameters.framework, 'allConfigurations', 'net472') }}: - ${{ if eq(parameters.jobParameters.isFullMatrix, true) }}: - - Windows.7.Amd64.Open + # Bring back once: https://github.com/dotnet/runtime/issues/35689 is fixed + # - Windows.7.Amd64.Open - Windows.81.Amd64.Open - Windows.10.Amd64.ServerRS5.Open - Windows.10.Amd64.Server19H1.Open - ${{ if ne(parameters.jobParameters.runtimeFlavor, 'mono') }}: - (Windows.Nano.1809.Amd64.Open)windows.10.amd64.serverrs5.open@mcr.microsoft.com/dotnet-buildtools/prereqs:nanoserver-1809-helix-amd64-08e8e40-20200107182504 - ${{ if eq(parameters.jobParameters.isFullMatrix, false) }}: - - Windows.7.Amd64.Open + # Bring back once: https://github.com/dotnet/runtime/issues/35689 is fixed + # - Windows.7.Amd64.Open - Windows.81.Amd64.Open - Windows.10.Amd64.Server19H1.ES.Open - ${{ if ne(parameters.jobParameters.runtimeFlavor, 'mono') }}: @@ -112,22 +116,30 @@ jobs: # netcoreapp - ${{ if notIn(parameters.jobParameters.framework, 'allConfigurations', 'net472') }}: - ${{ if eq(parameters.jobParameters.isFullMatrix, true) }}: - # TODO: Reopen when https://github.com/dotnet/runtime/issues/32231 is fixed - #- Windows.7.Amd64.Open - #- Windows.81.Amd64.Open + - Windows.7.Amd64.Open + # Bring back once: https://github.com/dotnet/runtime/issues/35689 is fixed + # - Windows.81.Amd64.Open - Windows.10.Amd64.ServerRS5.Open - Windows.10.Amd64.Server19H1.Open - ${{ if eq(parameters.jobParameters.isFullMatrix, false) }}: - ${{ if eq(parameters.jobParameters.buildConfig, 'Release') }}: - # TODO: Reopen when https://github.com/dotnet/runtime/issues/32231 is fixed - #- Windows.7.Amd64.Open - #- Windows.81.Amd64.Open - Windows.10.Amd64.Server19H1.ES.Open - ${{ if eq(parameters.jobParameters.buildConfig, 'Debug') }}: + - Windows.7.Amd64.Open + # Bring back once: https://github.com/dotnet/runtime/issues/35689 is fixed + # - Windows.81.Amd64.Open - Windows.10.Amd64.Server19H1.Open # NET472 - ${{ if eq(parameters.jobParameters.framework, 'net472') }}: - Windows.10.Amd64.Client19H1.Open + # Windows_NT arm + - ${{ if eq(parameters.platform, 'Windows_NT_arm') }}: + - Windows.10.Arm64v8.Open + + # Windows_NT arm64 + - ${{ if eq(parameters.platform, 'Windows_NT_arm64') }}: + - Windows.10.Arm64.Open + ${{ insert }}: ${{ parameters.jobParameters }} diff --git a/eng/pipelines/libraries/run-test-job.yml b/eng/pipelines/libraries/run-test-job.yml index 7d982c09e72024..053d7f90044ae1 100644 --- a/eng/pipelines/libraries/run-test-job.yml +++ b/eng/pipelines/libraries/run-test-job.yml @@ -9,6 +9,7 @@ parameters: runtimeFlavor: 'coreclr' timeoutInMinutes: 150 pool: '' + runtimeVariant: '' testScope: '' helixQueues: [] dependsOnTestBuildConfiguration: Debug @@ -27,6 +28,7 @@ jobs: isOfficialBuild: ${{ parameters.isOfficialBuild }} liveRuntimeBuildConfig: ${{ parameters.liveRuntimeBuildConfig }} runtimeFlavor: ${{ parameters.runtimeFlavor }} + runtimeVariant: ${{ parameters.runtimeVariant }} timeoutInMinutes: ${{ parameters.timeoutInMinutes }} container: '' # we just send to helix, no need to use a container. condition: ${{ parameters.condition }} @@ -47,7 +49,7 @@ jobs: - ${{ format('libraries_build_{0}_{1}{2}_{3}_{4}', parameters.framework, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - ${{ format('libraries_test_build_{0}_{1}_{2}_{3}', parameters.framework, parameters.osGroup, parameters.dependsOnTestArchitecture, parameters.dependsOnTestBuildConfiguration) }} - ${{ if ne(parameters.liveRuntimeBuildConfig, '') }}: - - ${{ format('{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeFlavor, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveRuntimeBuildConfig) }} + - ${{ format('{0}_{1}_product_build_{2}{3}_{4}_{5}', parameters.runtimeFlavor, parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveRuntimeBuildConfig) }} variables: - librariesTestsArtifactName: ${{ format('libraries_test_assets_{0}_{1}_{2}', parameters.osGroup, parameters.dependsOnTestArchitecture, parameters.dependsOnTestBuildConfiguration) }} diff --git a/eng/pipelines/libraries/stress/http.yml b/eng/pipelines/libraries/stress/http.yml index 9c34a658bfe0a6..2d7dbb6860b2b4 100644 --- a/eng/pipelines/libraries/stress/http.yml +++ b/eng/pipelines/libraries/stress/http.yml @@ -56,7 +56,7 @@ jobs: steps: - checkout: self clean: true - fetchDepth: 1 + fetchDepth: 5 lfs: false - pwsh: | diff --git a/eng/pipelines/libraries/stress/ssl.yml b/eng/pipelines/libraries/stress/ssl.yml index 11e3f0dba5f234..88e20efce027a1 100644 --- a/eng/pipelines/libraries/stress/ssl.yml +++ b/eng/pipelines/libraries/stress/ssl.yml @@ -57,7 +57,7 @@ jobs: steps: - checkout: self clean: true - fetchDepth: 1 + fetchDepth: 5 lfs: false - pwsh: | diff --git a/eng/pipelines/mono/templates/build-job.yml b/eng/pipelines/mono/templates/build-job.yml index 40f952dac00522..901bab9a0f6609 100644 --- a/eng/pipelines/mono/templates/build-job.yml +++ b/eng/pipelines/mono/templates/build-job.yml @@ -9,7 +9,7 @@ parameters: variables: {} pool: '' condition: true - llvm: false + runtimeVariant: '' isOfficialBuild: false crossrootfsDir: '' @@ -24,20 +24,13 @@ jobs: helixType: 'build/product/' enableMicrobuild: true pool: ${{ parameters.pool }} - llvm: ${{ parameters.llvm }} + runtimeVariant: ${{ parameters.runtimeVariant }} crossrootfsDir: ${{ parameters.crossroofsDir }} condition: ${{ parameters.condition }} # Compute job name from template parameters - ${{ if ne(parameters.llvm, true) }}: - name: ${{ format('mono_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - displayName: ${{ format('Mono Product Build {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - - # if LLVM enabled, set a variable we can consume - ${{ if eq(parameters.llvm, true) }}: - name: ${{ format('mono_llvm_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - displayName: ${{ format('Mono LLVM Product Build {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} - + name: ${{ format('mono_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} + displayName: ${{ format('Mono {0} Product Build {1}{2} {3} {4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }} # Run all steps in the container. # Note that the containers are defined in platform-matrix.yml @@ -74,13 +67,19 @@ jobs: - ${{ if eq(parameters.osGroup, 'Android') }}: - name: osOverride value: -os Android - - ${{ if eq(parameters.osGroup, 'WebAssembly') }}: + - ${{ if eq(parameters.osGroup, 'Browser') }}: - name: EMSDK_PATH value: /usr/local/emscripten - name: archType value: wasm - name: osOverride - value: '-os WebAssembly' + value: '-os Browser' + - ${{ if eq(parameters.runtimeVariant, 'llvmjit') }}: + - name: llvmParameter + value: /p:MonoEnableLLVM=true /p:MonoBundleLLVMOptimizer=false + - ${{ if eq(parameters.runtimeVariant, 'llvmaot') }}: + - name: llvmParameter + value: /p:MonoEnableLLVM=true /p:MonoBundleLLVMOptimizer=true - ${{ parameters.variables }} steps: @@ -90,21 +89,33 @@ jobs: # and FreeBSD builds use a build agent with dependencies # preinstalled, so we only need this step for OSX and Windows. - ${{ if in(parameters.osGroup, 'OSX', 'iOS', 'tvOS') }}: - - script: sh $(Build.SourcesDirectory)/eng/install-native-dependencies.sh $(osGroup) + - script: $(Build.SourcesDirectory)/eng/install-native-dependencies.sh $(osGroup) displayName: Install native dependencies - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: # Necessary to install python - script: $(Build.SourcesDirectory)\eng\common\init-tools-native.cmd -InstallDirectory $(Build.SourcesDirectory)\native-tools -Force displayName: Install native dependencies + - ${{ if in(parameters.osGroup, 'OSX', 'iOS','tvOS') }}: + - script: | + du -sh $(Build.SourcesDirectory)/* + df -h + displayName: Disk Usage before Build + # Build - ${{ if ne(parameters.osGroup, 'Windows_NT') }}: - - script: ./build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci /p:MonoEnableLLVM=${{ parameters.llvm }} + - script: ./build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) $(llvmParameter) displayName: Build product - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: - - script: build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci /p:MonoEnableLLVM=${{ parameters.llvm }} + - script: build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) $(llvmParameter) displayName: Build product + - ${{ if in(parameters.osGroup, 'OSX', 'iOS','tvOS') }}: + - script: | + du -sh $(Build.SourcesDirectory)/* + df -h + displayName: Disk Usage after Build + # Publish product output directory for consumption by tests. - template: /eng/pipelines/common/upload-artifact-step.yml parameters: @@ -117,15 +128,15 @@ jobs: displayName: 'product build' # Build packages - - ${{ if and(ne(parameters.llvm, true), ne(parameters.osGroup, 'Windows_NT')) }}: - - script: ./build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) /p:MonoEnableLLVM=${{ parameters.llvm }} -pack $(OutputRidArg) + - ${{ if ne(parameters.osGroup, 'Windows_NT') }}: + - script: ./build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) $(llvmParameter) -pack $(OutputRidArg) displayName: Build nupkg - - ${{ if and(ne(parameters.llvm, true), eq(parameters.osGroup, 'Windows_NT')) }}: - - script: build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) /p:MonoEnableLLVM=${{ parameters.llvm }} -pack $(OutputRidArg) + - ${{ if eq(parameters.osGroup, 'Windows_NT') }}: + - script: build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) $(llvmParameter) -pack $(OutputRidArg) displayName: Build nupkg # Publish official build - - ${{ if and(ne(parameters.llvm, true), eq(parameters.publishToBlobFeed, 'true')) }}: + - ${{ if eq(parameters.publishToBlobFeed, 'true') }}: - ${{ if ne(parameters.osGroup, 'Windows_NT') }}: - script: $(Build.SourcesDirectory)/eng/common/build.sh --ci --restore --publish --configuration $(_BuildConfig) /p:DotNetPublishUsingPipelines=true /p:DotNetPublishToBlobFeed=true /p:DotNetPublishBlobFeedUrl=$(dotnetfeedUrl) /p:DotNetPublishBlobFeedKey=$(dotnetfeedPAT) /p:Configuration=$(_BuildConfig) /p:TargetArchitecture=$(archType) /p:TargetOS=$(osGroup) /p:OSIdentifier=$(osGroup)$(osSubgroup) /bl:"$(Build.SourcesDirectory)/artifacts/log/publish-pkgs.binlog" --projects $(Build.SourcesDirectory)/eng/empty.csproj displayName: Publish packages to blob feed @@ -148,9 +159,6 @@ jobs: displayName: Publish Logs inputs: targetPath: $(Build.SourcesDirectory)/artifacts/log - ${{ if ne(parameters.llvm, true) }}: - artifactName: 'BuildLogs_Mono_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)' - ${{ if eq(parameters.llvm, true) }}: - artifactName: 'BuildLogs_Mono_LLVM_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)' + artifactName: 'BuildLogs_Mono_${{ parameters.runtimeVariant }}_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)' continueOnError: true condition: always() diff --git a/eng/pipelines/mono/templates/xplat-job.yml b/eng/pipelines/mono/templates/xplat-job.yml index 2cd61dc7e7f3e4..899f36ef85ad81 100644 --- a/eng/pipelines/mono/templates/xplat-job.yml +++ b/eng/pipelines/mono/templates/xplat-job.yml @@ -90,6 +90,12 @@ jobs: - name: osSubgroup value: ${{ parameters.osSubgroup }} + - name: coreClrRepoRoot + value: '$(Build.SourcesDirectory)/src/coreclr' + + - name: coreClrRepoRootDir + value: '$(coreClrRepoRoot)$(dir)' + - ${{ if and(eq(variables['System.TeamProject'], 'internal'), ne(variables['Build.Reason'], 'PullRequest')) }}: - name: _HelixSource value: official/dotnet/runtime/$(Build.SourceBranch) diff --git a/eng/pipelines/mono/templates/xplat-pipeline-job.yml b/eng/pipelines/mono/templates/xplat-pipeline-job.yml index a0d65845203929..0701073c669c61 100644 --- a/eng/pipelines/mono/templates/xplat-pipeline-job.yml +++ b/eng/pipelines/mono/templates/xplat-pipeline-job.yml @@ -9,7 +9,8 @@ parameters: liveLibrariesBuildConfig: '' strategy: '' pool: '' - llvm: false + runtimeVariant: '' + liveRuntimeBuildConfig: 'release' # arcade-specific parameters condition: true @@ -34,7 +35,7 @@ jobs: container: ${{ parameters.container }} strategy: ${{ parameters.strategy }} pool: ${{ parameters.pool }} - llvm: ${{ parameters.llvm }} + runtimeVariant: ${{ parameters.runtimeVariant }} # arcade-specific parameters condition: and(succeeded(), ${{ parameters.condition }}) @@ -46,15 +47,50 @@ jobs: gatherAssetManifests: ${{ parameters.gatherAssetManifests }} variables: + - name: coreClrProductArtifactName + value: 'CoreCLRProduct_${{ parameters.runtimeVariant }}_$(osGroup)$(osSubgroup)_$(archType)_${{ parameters.liveRuntimeBuildConfig }}' + + - name: coreClrProductRootFolderPath + value: '$(Build.SourcesDirectory)/artifacts/bin/coreclr/$(osGroup).$(archType).$(liveRuntimeBuildConfigUpper)' + - name: buildProductArtifactName - ${{ if ne(parameters.llvm, true) }}: - value: 'MonoProduct_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)' - ${{ if eq(parameters.llvm, true) }}: - value: 'MonoProduct_LLVM_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)' + value: 'MonoProduct_${{ parameters.runtimeVariant }}_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)' + + - name: binTestsPath + value: '$(Build.SourcesDirectory)/artifacts/tests/coreclr' - name: buildProductRootFolderPath value: '$(Build.SourcesDirectory)/artifacts/bin/mono/$(osGroup).$(archType).$(buildConfigUpper)' + - name: managedTestArtifactRootFolderPath + value: '$(binTestsPath)/$(osGroup).$(archType).$(buildConfigUpper)' + + - name: managedTestArtifactName + value: 'CoreCLRManagedTestArtifacts_${{ parameters.managedTestBuildOsGroup }}${{ parameters.managedTestBuildOsSubgroup }}_$(archType)_$(buildConfig)' + + - name: microsoftNetSdkIlFolderPath + value: '$(Build.SourcesDirectory)/.packages/microsoft.net.sdk.il' + + - name: microsoftNetSdkIlArtifactName + value: 'MicrosoftNetSdkIlPackage_${{ parameters.managedTestBuildOsGroup }}${{ parameters.managedTestBuildOsSubgroup }}_$(archType)_$(buildConfig)' + + - name: monoRepoRoot + value: '$(Build.SourcesDirectory)/src/mono' + + - name: nativeTestArtifactName + value: 'CoreCLRNativeTestArtifacts_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)' + + - name: nativeTestArtifactRootFolderPath + value: '$(binTestsPath)/obj/$(osGroup).$(archType).$(buildConfigUpper)' + + - name: liveRuntimeBuildConfigUpper + ${{ if eq(parameters.liveRuntimeBuildConfig, 'release') }}: + value: 'Release' + ${{ if eq(parameters.liveRuntimeBuildConfig, 'checked') }}: + value: 'Checked' + ${{ if eq(parameters.liveRuntimeBuildConfig, 'debug') }}: + value: 'Debug' + - librariesBuildArtifactName: '' - librariesOverrideArg: '' - librariesDownloadDir: '' diff --git a/eng/pipelines/official/stages/publish.yml b/eng/pipelines/official/stages/publish.yml index 260931d01cb438..48171955c3709d 100644 --- a/eng/pipelines/official/stages/publish.yml +++ b/eng/pipelines/official/stages/publish.yml @@ -18,8 +18,7 @@ stages: publishUsingPipelines: true dependsOn: PrepareSignedArtifacts pool: - name: NetCoreInternal-Pool - queue: buildpool.windows.10.amd64.vs2017 + vmImage: vs2017-win2016 # Stages-based publishing entry point - template: /eng/common/templates/post-build/post-build.yml diff --git a/eng/pipelines/runtime-official.yml b/eng/pipelines/runtime-official.yml index e2cd3a2d67d962..45715a7bf11832 100644 --- a/eng/pipelines/runtime-official.yml +++ b/eng/pipelines/runtime-official.yml @@ -9,6 +9,7 @@ trigger: - '*' - docs/manpages/* exclude: + - .github/* - docs/* - CODE-OF-CONDUCT.md - CONTRIBUTING.md @@ -76,13 +77,15 @@ stages: - tvOS_x64 - tvOS_arm64 - iOS_x64 - # - iOS_arm # https://github.com/dotnet/runtime/issues/34465 + - iOS_x86 + - iOS_arm - iOS_arm64 - OSX_x64 - Linux_x64 - Linux_arm - Linux_arm64 - Linux_musl_x64 + - Browser_wasm # - Linux_musl_arm64 - Windows_NT_x64 # - Windows_NT_x86 @@ -91,6 +94,49 @@ stages: jobParameters: isOfficialBuild: ${{ variables.isOfficialBuild }} + # + # Build Mono LLVM release + # + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/mono/templates/build-job.yml + runtimeFlavor: mono + buildConfig: release + platforms: + - OSX_x64 + - Linux_x64 + # - Linux_arm + # - Linux_arm64 + # - Linux_musl_x64 + # - Linux_musl_arm64 + # - Windows_NT_x64 + # - Windows_NT_x86 + # - Windows_NT_arm + # - Windows_NT_arm64 + jobParameters: + runtimeVariant: LLVMJIT + isOfficialBuild: ${{ variables.isOfficialBuild }} + + - template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/mono/templates/build-job.yml + runtimeFlavor: mono + buildConfig: release + platforms: + - OSX_x64 + - Linux_x64 + # - Linux_arm + # - Linux_arm64 + # - Linux_musl_x64 + # - Linux_musl_arm64 + # - Windows_NT_x64 + # - Windows_NT_x86 + # - Windows_NT_arm + # - Windows_NT_arm64 + jobParameters: + runtimeVariant: LLVMAOT + isOfficialBuild: ${{ variables.isOfficialBuild }} + # # Build libraries using live CoreLib from CoreCLR # @@ -129,8 +175,10 @@ stages: - tvOS_x64 - tvOS_arm64 - iOS_x64 - # - iOS_arm # https://github.com/dotnet/runtime/issues/34465 + - iOS_x86 + - iOS_arm - iOS_arm64 + - Browser_wasm jobParameters: isOfficialBuild: ${{ variables.isOfficialBuild }} liveRuntimeBuildConfig: release @@ -186,15 +234,50 @@ stages: buildFullPlatformManifest: false runtimeFlavor: mono platforms: + - OSX_x64 + - Linux_x64 - tvOS_x64 - tvOS_arm64 - # - iOS_arm # https://github.com/dotnet/runtime/issues/34465 + - iOS_arm - iOS_arm64 - iOS_x64 + - iOS_x86 - Android_arm - Android_arm64 - Android_x64 - Android_x86 + - Browser_wasm + + # + # Installer Build for platforms using Mono + # + - template: /eng/pipelines/installer/installer-matrix.yml + parameters: + jobParameters: + liveRuntimeBuildConfig: release + liveLibrariesBuildConfig: Release + isOfficialBuild: ${{ variables.isOfficialBuild }} + useOfficialAllConfigurations: false + buildFullPlatformManifest: false + runtimeVariant: LLVMJIT + runtimeFlavor: mono + platforms: + - OSX_x64 + - Linux_x64 + + - template: /eng/pipelines/installer/installer-matrix.yml + parameters: + jobParameters: + liveRuntimeBuildConfig: release + liveLibrariesBuildConfig: Release + isOfficialBuild: ${{ variables.isOfficialBuild }} + useOfficialAllConfigurations: false + buildFullPlatformManifest: false + runtimeVariant: LLVMAOT + runtimeFlavor: mono + platforms: + - OSX_x64 + - Linux_x64 - ${{ if eq(variables.isOfficialBuild, true) }}: - template: /eng/pipelines/official/stages/publish.yml diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index 9a7b6d8ef5ea41..8d69c7586b860d 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -7,6 +7,7 @@ trigger: branches: include: - master + - dev/infrastructure - release/*.* paths: include: @@ -14,6 +15,7 @@ trigger: - docs/manpages/* exclude: - eng/Version.Details.xml + - .github/* - docs/* - CODE-OF-CONDUCT.md - CONTRIBUTING.md @@ -27,6 +29,7 @@ pr: branches: include: - master + - dev/infrastructure - release/*.* paths: include: @@ -34,6 +37,7 @@ pr: - docs/manpages/* exclude: - eng/Version.Details.xml + - .github/* - docs/* - CODE-OF-CONDUCT.md - CONTRIBUTING.md @@ -74,6 +78,8 @@ jobs: - subset: mono include: - src/libraries/System.Private.CoreLib/* + - src/libraries/Native/Unix/System.Globalization.Native/* + - src/libraries/Native/Unix/Common/* exclude: - eng/Version.Details.xml - '*.md' @@ -101,6 +107,10 @@ jobs: - eng/pipelines/coreclr/* - eng/pipelines/mono/* - eng/pipelines/installer/* + - subset: runtimetests + include: + - src/coreclr/tests/* + - src/coreclr/build-test.sh - subset: installer include: - docs/manpages/* @@ -197,6 +207,7 @@ jobs: - Windows_NT_x86 - Windows_NT_arm - Windows_NT_arm64 + - FreeBSD_x64 jobParameters: testGroup: innerloop @@ -238,6 +249,7 @@ jobs: - tvOS_x64 - tvOS_arm64 - iOS_x64 + - iOS_x86 - iOS_arm - iOS_arm64 - OSX_x64 @@ -245,7 +257,7 @@ jobs: - Linux_arm - Linux_arm64 - Linux_musl_x64 - - WebAssembly_wasm + - Browser_wasm # - Linux_musl_arm64 - Windows_NT_x64 # - Windows_NT_x86 @@ -275,14 +287,14 @@ jobs: - tvOS_x64 - tvOS_arm64 - iOS_x64 + - iOS_x86 - iOS_arm - iOS_arm64 - - OSX_x64 - Linux_x64 - Linux_arm - Linux_arm64 - Linux_musl_x64 - - WebAssembly_wasm + - Browser_wasm # - Linux_musl_arm64 - Windows_NT_x64 # - Windows_NT_x86 @@ -295,6 +307,27 @@ jobs: eq(dependencies.checkout.outputs['SetPathVars_mono.containsChange'], true), eq(variables['isFullMatrix'], true)) +# +# Build Mono release +# Only when libraries, mono, or the runtime tests changed +# Currently only these architectures are needed for the runtime tests. +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/mono/templates/build-job.yml + runtimeFlavor: mono + buildConfig: release + platforms: + - OSX_x64 + jobParameters: + condition: >- + or( + eq(dependencies.checkout.outputs['SetPathVars_libraries.containsChange'], true), + eq(dependencies.checkout.outputs['SetPathVars_runtimetests.containsChange'], true), + eq(dependencies.checkout.outputs['SetPathVars_mono.containsChange'], true), + eq(variables['isFullMatrix'], true)) + + + # # Build Mono LLVM debug # Only when libraries or mono changed @@ -316,7 +349,31 @@ jobs: # - Windows_NT_arm # - Windows_NT_arm64 jobParameters: - llvm: true + runtimeVariant: LLVMJIT + condition: >- + or( + eq(dependencies.checkout.outputs['SetPathVars_libraries.containsChange'], true), + eq(dependencies.checkout.outputs['SetPathVars_mono.containsChange'], true), + eq(variables['isFullMatrix'], true)) + +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/mono/templates/build-job.yml + runtimeFlavor: mono + buildConfig: debug + platforms: + - OSX_x64 + - Linux_x64 + # - Linux_arm + # - Linux_arm64 + # - Linux_musl_x64 + # - Linux_musl_arm64 + # - Windows_NT_x64 + # - Windows_NT_x86 + # - Windows_NT_arm + # - Windows_NT_arm64 + jobParameters: + runtimeVariant: LLVMAOT condition: >- or( eq(dependencies.checkout.outputs['SetPathVars_libraries.containsChange'], true), @@ -344,7 +401,31 @@ jobs: # - Windows_NT_arm # - Windows_NT_arm64 jobParameters: - llvm: true + runtimeVariant: LLVMJIT + condition: >- + or( + eq(dependencies.checkout.outputs['SetPathVars_libraries.containsChange'], true), + eq(dependencies.checkout.outputs['SetPathVars_mono.containsChange'], true), + eq(variables['isFullMatrix'], true)) + +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/mono/templates/build-job.yml + runtimeFlavor: mono + buildConfig: release + platforms: + - OSX_x64 + - Linux_x64 + # - Linux_arm + # - Linux_arm64 + # - Linux_musl_x64 + # - Linux_musl_arm64 + # - Windows_NT_x64 + # - Windows_NT_x86 + # - Windows_NT_arm + # - Windows_NT_arm64 + jobParameters: + runtimeVariant: LLVMAOT condition: >- or( eq(dependencies.checkout.outputs['SetPathVars_libraries.containsChange'], true), @@ -380,6 +461,7 @@ jobs: - Linux_x64 - OSX_x64 - Windows_NT_x64 + - FreeBSD_x64 jobParameters: liveRuntimeBuildConfig: release @@ -395,7 +477,7 @@ jobs: - Android_x64 - Android_arm - tvOS_arm64 - # - iOS_arm # https://github.com/dotnet/runtime/issues/34465 + - iOS_arm - iOS_x64 jobParameters: liveRuntimeBuildConfig: release @@ -410,7 +492,8 @@ jobs: - Android_arm64 - tvOS_x64 - iOS_arm64 - - WebAssembly_wasm + - iOS_x86 + - Browser_wasm jobParameters: liveRuntimeBuildConfig: debug @@ -487,26 +570,27 @@ jobs: - template: /eng/pipelines/installer/installer-matrix.yml parameters: - buildConfig: ${{ variables.debugOnPrReleaseOnRolling }} + buildConfig: Release platforms: - OSX_x64 - Linux_x64 - Linux_arm64 - Linux_musl_x64 - Windows_NT_x64 + - FreeBSD_x64 jobParameters: liveRuntimeBuildConfig: release liveLibrariesBuildConfig: ${{ variables.debugOnPrReleaseOnRolling }} - template: /eng/pipelines/installer/installer-matrix.yml parameters: - buildConfig: ${{ variables.debugOnPrReleaseOnRolling }} + buildConfig: Release runtimeFlavor: mono platforms: - Android_x64 - Android_arm - tvOS_arm64 - # - iOS_arm # https://github.com/dotnet/runtime/issues/34465 + - iOS_arm - iOS_x64 jobParameters: liveRuntimeBuildConfig: release @@ -521,7 +605,35 @@ jobs: - Android_arm64 - tvOS_x64 - iOS_arm64 + - iOS_x86 + - OSX_x64 + - Linux_x64 + - Browser_wasm + jobParameters: + liveRuntimeBuildConfig: release + liveLibrariesBuildConfig: ${{ variables.debugOnPrReleaseOnRolling }} + +- template: /eng/pipelines/installer/installer-matrix.yml + parameters: + buildConfig: ${{ variables.debugOnPrReleaseOnRolling }} + runtimeFlavor: mono + platforms: + - OSX_x64 + - Linux_x64 jobParameters: + runtimeVariant: LLVMJIT + liveRuntimeBuildConfig: release + liveLibrariesBuildConfig: ${{ variables.debugOnPrReleaseOnRolling }} + +- template: /eng/pipelines/installer/installer-matrix.yml + parameters: + buildConfig: ${{ variables.debugOnPrReleaseOnRolling }} + runtimeFlavor: mono + platforms: + - OSX_x64 + - Linux_x64 + jobParameters: + runtimeVariant: LLVMAOT liveRuntimeBuildConfig: release liveLibrariesBuildConfig: ${{ variables.debugOnPrReleaseOnRolling }} @@ -573,7 +685,7 @@ jobs: # - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/build-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/build-test-job.yml buildConfig: checked platforms: - Linux_arm @@ -594,7 +706,7 @@ jobs: # - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/build-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/build-test-job.yml buildConfig: checked platforms: - OSX_x64 @@ -615,7 +727,7 @@ jobs: # - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/run-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml buildConfig: checked platforms: - Linux_arm @@ -634,7 +746,7 @@ jobs: - template: /eng/pipelines/common/platform-matrix.yml parameters: - jobTemplate: /eng/pipelines/coreclr/templates/run-test-job.yml + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml buildConfig: checked platforms: - OSX_x64 @@ -651,6 +763,50 @@ jobs: eq(dependencies.checkout.outputs['SetPathVars_coreclr.containsChange'], true), eq(variables['isFullMatrix'], true)) +# +# Mono Test builds with CoreCLR runtime tests using live libraries debug build +# Only when Mono is changed +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/templates/runtimes/build-test-job.yml + buildConfig: release + runtimeFlavor: mono + platforms: + - OSX_x64 + - Linux_arm64 + jobParameters: + testGroup: innerloop + liveLibrariesBuildConfig: ${{ variables.debugOnPrReleaseOnRolling }} + liveRuntimeBuildConfig: release + condition: >- + or( + eq(dependencies.checkout.outputs['SetPathVars_mono.containsChange'], true), + eq(dependencies.checkout.outputs['SetPathVars_runtimetests.containsChange'], true), + eq(variables['isFullMatrix'], true)) + +# +# Mono CoreCLR runtime Test executions using live libraries +# Only when Mono is changed +- template: /eng/pipelines/common/platform-matrix.yml + parameters: + jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml + buildConfig: release + runtimeFlavor: mono + platforms: + - OSX_x64 + - Linux_arm64 + helixQueueGroup: pr + helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml + jobParameters: + testGroup: innerloop + liveLibrariesBuildConfig: ${{ variables.debugOnPrReleaseOnRolling }} + liveRuntimeBuildConfig: release + condition: >- + or( + eq(dependencies.checkout.outputs['SetPathVars_mono.containsChange'], true), + eq(dependencies.checkout.outputs['SetPathVars_runtimetests.containsChange'], true), + eq(variables['isFullMatrix'], true)) + # # Libraries Release Test Execution against a release mono runtime. # Only when libraries or mono changed @@ -689,6 +845,9 @@ jobs: buildConfig: Release platforms: - Windows_NT_x86 + - ${{ if eq(variables['isFullMatrix'], true) }}: + - Windows_NT_arm + - Windows_NT_arm64 helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml jobParameters: isOfficialBuild: false diff --git a/eng/referenceFromRuntime.targets b/eng/referenceFromRuntime.targets index 873e7e5ff40192..34d0eb49199c8c 100644 --- a/eng/referenceFromRuntime.targets +++ b/eng/referenceFromRuntime.targets @@ -1,5 +1,5 @@ - + AddRuntimeProjectReference; $(PrepareProjectReferencesDependsOn); @@ -19,7 +19,7 @@ + Condition="'$(IsTestProject)' != 'true' and '$(IsTestSupportProject)' != 'true' and '@(ReferenceFromRuntime)' != ''"> @@ -65,7 +65,7 @@ <_referencePathFromRuntime Include="@(RuntimeFiles)" Private="false" /> <_referencePathFromRuntime Include="@(_referencePathFromRestoredRuntime)" Private="false" /> - <_referencePathFromRuntime Include="@(ReferenceFromRuntime->'$(RuntimePath)%(Identity).dll')" Condition="'$(IsTestProject)' == 'true'" /> + <_referencePathFromRuntime Include="@(ReferenceFromRuntime->'$(RuntimePath)%(Identity).dll')" Condition="'$(IsTestProject)' == 'true' or '$(IsTestSupportProject)' == 'true'" /> <_referencePathFromRuntimeByFileName Include="@(_referencePathFromRuntime->'%(FileName)')" Condition="'%(_referencePathFromRuntime.Extension)' == '.dll'" > %(Identity) @@ -111,7 +111,7 @@ - + diff --git a/eng/references.targets b/eng/references.targets index 0c104db2bb27bc..efcac7d0515214 100644 --- a/eng/references.targets +++ b/eng/references.targets @@ -21,7 +21,7 @@ - + @@ -36,7 +36,7 @@ - + diff --git a/eng/restore/runtimeprops.targets b/eng/restore/runtimeprops.targets deleted file mode 100644 index 945d0830f8cc90..00000000000000 --- a/eng/restore/runtimeprops.targets +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file diff --git a/eng/run-test.sh b/eng/run-test.sh index abd1d920b1615a..5f14e6f6121bec 100644 --- a/eng/run-test.sh +++ b/eng/run-test.sh @@ -15,12 +15,12 @@ wait_on_pids() usage() { - echo "Runs .NET CoreFX tests on FreeBSD, NetBSD or Linux" + echo "Runs .NET CoreFX tests on FreeBSD, Linux, NetBSD or SunOS" echo "usage: run-test [options]" echo echo "Input sources:" echo " --runtime Location of root of the binaries directory" - echo " containing the FreeBSD, NetBSD or Linux runtime" + echo " containing the FreeBSD, Linux, NetBSD or SunOS runtime" echo " default: /bin/testhost/netcoreapp---" echo " --corefx-tests Location of the root binaries location containing" echo " the tests to run" @@ -29,7 +29,7 @@ usage() echo "Flavor/OS/Architecture options:" echo " --configuration Configuration to run (Debug/Release)" echo " default: Debug" - echo " --os OS to run (FreeBSD, NetBSD or Linux)" + echo " --os OS to run (FreeBSD, Linux, NetBSD or SunOS)" echo " default: detect current OS" echo " --arch Architecture to run (x64, arm, armel, x86, arm64)" echo " default: detect current architecture" @@ -236,34 +236,34 @@ done # Compute paths to the binaries if they haven't already been computed -if [ "$Runtime" == "" ] +if [ -z "$Runtime" ] then Runtime="$ProjectRoot/artifacts/bin/testhost/netcoreapp-$OS-$Configuration-$__Arch" fi -if [ "$CoreFxTests" == "" ] +if [ -z "$CoreFxTests" ] then CoreFxTests="$ProjectRoot/artifacts/bin" fi # Check parameters up front for valid values: -if [ ! "$Configuration" == "Debug" ] && [ ! "$Configuration" == "Release" ] +if [ "$Configuration" != "Debug" ] && [ "$Configuration" != "Release" ] then echo "error: Configuration should be Debug or Release" exit 1 fi -if [ ! "$OS" == "FreeBSD" ] && [ ! "$OS" == "NetBSD" ] && [ ! "$OS" == "Linux" ] +if [ "$OS" != "FreeBSD" ] && [ "$OS" != "Linux" ] && [ "$OS" != "NetBSD" ] && [ "$OS" != "SunOS" ] then - echo "error: OS should be FreeBSD, NetBSD or Linux" + echo "error: OS should be FreeBSD, Linux, NetBSD or Linux" exit 1 fi export CORECLR_SERVER_GC="$serverGC" export PAL_OUTPUTDEBUGSTRING="1" -if [ "$LANG" == "" ] +if [ -z "$LANG" ] then export LANG="en_US.UTF-8" fi @@ -285,7 +285,10 @@ if [ $RunTestSequential -eq 1 ] then maxProcesses=1; else - if [ `uname` = "NetBSD" ] || [ `uname` = "FreeBSD" ]; then + platform="$(uname)" + if [ "$platform" = "FreeBSD" ]; then + maxProcesses=$(sysctl hw.ncpu | awk '{ print $2+1 }') + if [ "$platform" = "NetBSD" ] || [ "$platform" = "SunOS" ] ; then maxProcesses=$(($(getconf NPROCESSORS_ONLN)+1)) else maxProcesses=$(($(getconf _NPROCESSORS_ONLN)+1)) diff --git a/eng/sdl-tsa-vars.config b/eng/sdl-tsa-vars.config new file mode 100644 index 00000000000000..0b4659a0fe4f78 --- /dev/null +++ b/eng/sdl-tsa-vars.config @@ -0,0 +1,11 @@ +-SourceToolsList @("policheck","credscan") +-TsaInstanceURL https://devdiv.visualstudio.com/ +-TsaProjectName DEVDIV +-TsaNotificationEmail runtimerepo-infra@microsoft.com +-TsaCodebaseAdmin REDMOND\danmose +-TsaBugAreaPath "DevDiv\NET Runtime\Reliability\Docs" +-TsaIterationPath DevDiv +-TsaRepositoryName Runtime +-TsaCodebaseName Runtime +-TsaOnboard $True +-TsaPublish $True \ No newline at end of file diff --git a/eng/targetframeworksuffix.props b/eng/targetframeworksuffix.props new file mode 100644 index 00000000000000..f89923d3ab86ce --- /dev/null +++ b/eng/targetframeworksuffix.props @@ -0,0 +1,84 @@ + + + + + true + win + + + + + true + unix + + + + + true + true + linux + + + + + true + true + true + android + + + + + true + true + osx + + + + + true + true + tvos + + + + + true + true + ios + + + + + true + true + freebsd + + + + + true + true + netbsd + + + + + true + true + sunos + + + + + true + true + + + + + true + + + + diff --git a/eng/testing/.runsettings b/eng/testing/.runsettings new file mode 100644 index 00000000000000..fabc0310a7aa51 --- /dev/null +++ b/eng/testing/.runsettings @@ -0,0 +1,53 @@ + + + + + 300000 + + .\TestResults\ + + .\ + + $$MAXCPUCOUNT$$ + + $$TARGETPLATFORM$$ + + $$DISABLEPARALLELIZATION$$ + + $$DISABLEAPPDOMAIN$$ + + $$TESTCASEFILTER$$ + $$DOTNETHOSTPATH$$ + + + $$DEVPATH$$ + + + + + + + + + Minimal + + + + + + + + + $$COVERAGE_INCLUDE$$ + $$COVERAGE_EXCLUDEBYFILE$$ + $$COVERAGE_INCLUDEDIRECTORY$$ + opencover + false + true + false + + + + + + \ No newline at end of file diff --git a/eng/testing/AndroidRunnerTemplate.sh b/eng/testing/AndroidRunnerTemplate.sh new file mode 100644 index 00000000000000..1a683aa348986c --- /dev/null +++ b/eng/testing/AndroidRunnerTemplate.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +EXECUTION_DIR=$(dirname $0) +TEST_NAME=$1 +TARGET_ARCH=$2 + +APK=$EXECUTION_DIR/bin/$TEST_NAME.apk + +# it doesn't support parallel execution yet, so, here is a hand-made semaphore: +LOCKDIR=/tmp/androidtests.lock +while true; do + if mkdir "$LOCKDIR" + then + trap 'rm -rf "$LOCKDIR"' 0 + break + else + sleep 5 + fi +done + +dotnet xharness android test -i="net.dot.MonoRunner" \ + --package-name="net.dot.$TEST_NAME" \ + --app=$APK -o=$EXECUTION_DIR/TestResults -v diff --git a/eng/testing/AppleRunnerTemplate.sh b/eng/testing/AppleRunnerTemplate.sh new file mode 100644 index 00000000000000..c146f7e0364b13 --- /dev/null +++ b/eng/testing/AppleRunnerTemplate.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +EXECUTION_DIR=$(dirname $0) +TEST_NAME=$1 +TARGET_ARCH=$2 +TARGET= +SCHEME_SDK= + +if [ "$TARGET_ARCH" == "arm" ]; then + TARGET=ios-device + SCHEME_SDK=Release-iphoneos +elif [ "$TARGET_ARCH" == "arm64" ]; then + TARGET=ios-device + SCHEME_SDK=Release-iphoneos +elif [ "$TARGET_ARCH" == "x64" ]; then + TARGET=ios-simulator-64 + SCHEME_SDK=Release-iphonesimulator +elif [ "$TARGET_ARCH" == "x86" ]; then + TARGET=ios-simulator-32 + SCHEME_SDK=Release-iphonesimulator +else + echo "Unknown architecture: $TARGET_ARCH" + exit 1 +fi + +# "Release" in SCHEME_SDK is what xcode produces (see "bool Optimized" property in AppleAppBuilderTask) + +APP_BUNDLE=$EXECUTION_DIR/$TEST_NAME/$SCHEME_SDK/$TEST_NAME.app + +# it doesn't support parallel execution yet, so, here is a hand-made semaphore: +LOCKDIR=/tmp/runonsim.lock +while true; do + if mkdir "$LOCKDIR" + then + trap 'rm -rf "$LOCKDIR"' 0 + break + else + sleep 5 + fi +done + +XHARNESS_OUT="$EXECUTION_DIR/xharness-output" + +dotnet xharness ios test --app="$APP_BUNDLE" \ + --targets=$TARGET \ + --output-directory=$XHARNESS_OUT + +_exitCode=$? + +echo "Xharness artifacts: $XHARNESS_OUT" + +exit $_exitCode diff --git a/eng/testing/WasmRunnerTemplate.sh b/eng/testing/WasmRunnerTemplate.sh new file mode 100644 index 00000000000000..2d4b8f95d4f491 --- /dev/null +++ b/eng/testing/WasmRunnerTemplate.sh @@ -0,0 +1,12 @@ +set -ev + +EXECUTION_DIR=$(dirname $0) +TEST_NAME=$1 +TARGET_ARCH=$2 + +echo "Test: $1 Arch: $2" + +cd $EXECUTION_DIR +v8 --expose_wasm runtime.js -- --enable-gc --run WasmTestRunner.dll $TEST_NAME + +exit 0 diff --git a/eng/testing/coverage.props b/eng/testing/coverage.props deleted file mode 100644 index 7af30267a5625a..00000000000000 --- a/eng/testing/coverage.props +++ /dev/null @@ -1,14 +0,0 @@ - - - coverage.xml - 0 - line,branch,method - opencover - true - normal - - $(CoverageOutputPath) - Html - Info - - diff --git a/eng/testing/coverage.targets b/eng/testing/coverage.targets index 3638e3efd7ca6b..6f8ac2648f06e7 100644 --- a/eng/testing/coverage.targets +++ b/eng/testing/coverage.targets @@ -1,44 +1,10 @@ - - - - "$(TargetFileName)" --target "$(RunCommand)" --targetargs "$(RunArguments)" --format "$(CoverageFormat)" --output "$(CoverageOutputPath)" --threshold "$(CoverageThreshold)" --threshold-type "$(CoverageThresholdType)" --verbosity "$(CoverageVerbosity)" - $(RunArguments) --use-source-link - "$(DotNetTool)" tool run coverlet - - - - - $([MSBuild]::NormalizeDirectory('$(OutDir)', 'report')) - $([MSBuild]::NormalizePath('$(CoverageReportDir)', 'index.htm')) - "$(DotNetTool)" tool run reportgenerator "-reports:$(CoverageReportInputPath)" "-targetdir:$(CoverageReportDir.TrimEnd('\/'))" "-reporttypes:$(CoverageReportTypes)" "-verbosity:$(CoverageReportVerbosity)" - - - - - - - + - - --exclude-by-file @(CoverageExcludeFile -> '"%(Identity)"', ' --exclude-by-file ') - $(RunArguments) $(CoverageExcludeByFileFilter) - - - - --include-directory @(CoverageProbePath -> '"$(RunScriptHostDir)%(Identity)"', ' --include-directory ') - $(RunArguments) $(IncludeDirectoriesFilter) - - - - --exclude @(CoverageExclude -> '"%(Identity)"', ' --exclude ') - $(RunArguments) $(CoverageExcludeFilter) - - - + <_ProjectDirectoryUnderSourceDir>$(MSBuildProjectDirectory.SubString($(LibrariesProjectRoot.Length))) $(_ProjectDirectoryUnderSourceDir.SubString(0, $(_ProjectDirectoryUnderSourceDir.IndexOfAny("\\/")))) @@ -48,15 +14,76 @@ CoverageAssemblies can be passed in to the build to gather coverage on additional assemblies. --> - <_CoverageAssemblies Include="$(AssemblyBeingTested)" /> - <_CoverageAssemblies Include="System.Private.CoreLib" Condition="'$(TestRuntime)' == 'true'" /> - <_CoverageAssemblies Include="@(AssembliesBeingTested)" /> - <_CoverageAssemblies Include="$(CoverageAssemblies)" Condition="'$(CoverageAssemblies)' != ''" /> + + + + - - --include @(_CoverageAssemblies -> '"[%(Identity)]*"', ' --include ') - $(RunArguments) $(CoverageFilter) + + @(CoverageInclude -> '[%(Identity)]*', ',') + + + @(CoverageExcludeByFile -> '%(Identity)', ',') + + + + @(CoverageIncludeDirectory -> '$(TestHostRootPath)%(Identity)', ',') + + + + + + + coverage.opencover.xml + $(CoverageOutputPath) + $([MSBuild]::NormalizeDirectory('$(OutDir)', 'report')) + + "$(DotNetTool)" tool run coverlet "$(TargetFileName)" --target "$(RunScriptHost)" --targetargs "$(RunScriptCommand.Replace('"$(RunScriptHost)"', ''))" --format "opencover" --output "$(CoverageOutputPath)" --verbosity "normal" --use-source-link + $(RunScriptCommand) --exclude-by-file @(CoverageExcludeByFile -> '"%(Identity)"', ' --exclude-by-file ') + $(RunScriptCommand) --include-directory @(CoverageIncludeDirectory -> '"$(RunScriptHostDir)%(Identity)"', ' --include-directory ') + $(RunScriptCommand) --include @(CoverageInclude -> '"[%(Identity)]*"', ' --include ') + "$(DotNetTool)" tool run reportgenerator "-reports:$(CoverageReportInputPath)" "-targetdir:$(CoverageReportDir.TrimEnd('\/'))" "-reporttypes:Html" "-verbosity:Info" + + + + + + + + + + + + + + + + %(CoverageOutputFile.Identity) + Html + Info + $([MSBuild]::NormalizeDirectory('$(OutDir)', 'TestResults', 'report')) + "$(DotNetTool)" tool run reportgenerator "-reports:$(CoverageReportInputPath)" "-targetdir:$(CoverageReportDir.TrimEnd('\/'))" "-reporttypes:$(CoverageReportTypes)" "-verbosity:$(CoverageReportVerbosity)" + + + + + + + + + diff --git a/eng/testing/launchSettings.json b/eng/testing/launchSettings.json deleted file mode 100644 index 62d099feb3b7d8..00000000000000 --- a/eng/testing/launchSettings.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "profiles": { - ".NET Core xUnit Console": { - "commandName": "Executable", - "executablePath": "$(TestHostRootPath)dotnet.exe", - "commandLineArgs": "$(RunArguments) -parallel none", - "workingDirectory": "$(RunWorkingDirectory)" - }, - ".NET Framework xUnit Console": { - "commandName": "Executable", - "executablePath": "$(RunWorkingDirectory)$(RunCommand)", - "commandLineArgs": "$(RunArguments) -parallel none", - "workingDirectory": "$(RunWorkingDirectory)", - "environmentVariables": { - "DEVPATH": "$(TestHostRootPath)" - } - } - } -} diff --git a/eng/testing/launchSettings.targets b/eng/testing/launchSettings.targets deleted file mode 100644 index 6caf9475304570..00000000000000 --- a/eng/testing/launchSettings.targets +++ /dev/null @@ -1,22 +0,0 @@ - - - - $(MSBuildThisFileDirectory)launchSettings.json - $([MSBuild]::NormalizePath('$(MSBuildProjectDirectory)', '$(AppDesignerFolder)', 'launchSettings.json')) - GenerateLaunchSettingsFile;$(PrepareForRunDependsOn); - - - - - - - \ No newline at end of file diff --git a/eng/testing/runsettings.targets b/eng/testing/runsettings.targets new file mode 100644 index 00000000000000..10496127b8a90a --- /dev/null +++ b/eng/testing/runsettings.targets @@ -0,0 +1,53 @@ + + + $(MSBuildThisFileDirectory).runsettings + $(ArtifactsObjDir)$(TargetOS)-$(Configuration)-$(TargetArchitecture).runsettings + $(OutDir).runsettings + + false + $(RunSettingsIntermediateOutputFilePath) + $(RunSettingsAppOutputFilePath) + + + $(RunSettingsAppOutputFilePath) + + $(RunSettingsIntermediateOutputFilePath) + + GenerateRunSettingsFile;$(PrepareForRunDependsOn) + + + + <_testFilter Condition="'$(_withCategories)' != ''">$(_withCategories.Replace(';', '&amp;category=')) + <_testFilter Condition="'$(_withoutCategories)' != ''">$(_testFilter)$(_withoutCategories.Replace(';', '&amp;category!=')) + <_testFilter>$(_testFilter.Trim('&amp;')) + + + + + $([System.IO.File]::ReadAllText('$(RunSettingsInputFilePath)')) + $(RunSettingsFileContent.Replace('$$MAXCPUCOUNT$$', '1')) + $(RunSettingsFileContent.Replace('$$MAXCPUCOUNT$$', '0')) + $(RunSettingsFileContent.Replace('$$COVERAGE_INCLUDE$$', '$(CoverageIncludeFilter)') + .Replace('$$COVERAGE_EXCLUDEBYFILE$$', '$(CoverageExcludeByFileFilter)') + .Replace('$$COVERAGE_INCLUDEDIRECTORY$$', '$(CoverageIncludeDirectoryFilter)') + .Replace('$$COVERAGE_ENABLED$$', '$([MSBuild]::ValueOrDefault('$(Coverage)', 'false'))') + .Replace('$$TARGETPLATFORM$$', '$(TargetArchitecture)') + .Replace('$$DISABLEPARALLELIZATION$$', '$([MSBuild]::ValueOrDefault('$(TestDisableParallelization)', 'false'))') + .Replace('$$DISABLEAPPDOMAIN$$', '$([MSBuild]::ValueOrDefault('$(TestDisableAppDomain)', 'false'))') + .Replace('$$TESTCASEFILTER$$', '$(_testFilter)') + .Replace('$$DEVPATH$$', '$(TestHostRootPath)') + .Replace('$$DOTNETHOSTPATH$$', '$(TestHostRootPath)$([System.IO.Path]::GetFileName('$(DotNetTool)'))')) + + + + + + + $(RunSettingsOutputFilePath) + + + diff --git a/eng/testing/runtimeConfiguration.targets b/eng/testing/runtimeConfiguration.targets index fdb81abbb18929..f687adfad40f97 100644 --- a/eng/testing/runtimeConfiguration.targets +++ b/eng/testing/runtimeConfiguration.targets @@ -1,10 +1,10 @@ - $(MSBuildThisFileDirectory)netfx.exe.config + $(MSBuildThisFileDirectory)netfx.exe.config - true + true @@ -19,11 +19,11 @@ Tracking issue: https://github.com/dotnet/sdk/issues/1675 --> diff --git a/eng/testing/tests.mobile.targets b/eng/testing/tests.mobile.targets new file mode 100644 index 00000000000000..3fd1594b73bd55 --- /dev/null +++ b/eng/testing/tests.mobile.targets @@ -0,0 +1,154 @@ + + + + $([MSBuild]::NormalizeDirectory('$(OutDir)', 'AppBundle')) + $([MSBuild]::NormalizePath('$(BundleDir)', '$(RunScriptOutputName)')) + true + + + + + + + + arm64-v8a + armeabi-v7a + x86_64 + x86 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @(MonoAOTCompilerDefaultAotArguments, ';') + @(MonoAOTCompilerDefaultProcessArguments, ';') + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_runnerFilesToPublish Include="$(AndroidTestRunnerDir)*" Condition="'$(TargetOS)' == 'Android'" /> + <_runnerFilesToPublish Include="$(AppleTestRunnerDir)*" Condition="'$(TargetOS)' == 'iOS' or '$(TargetOS)' == 'tvOS'" /> + <_runnerFilesToPublish Include="$(WasmTestRunnerDir)*" Condition="'$(TargetOS)' == 'Browser'" /> + + + + + + + + + + + + + + + + + + + diff --git a/eng/testing/tests.props b/eng/testing/tests.props index dfaabfa18db038..cccce13b1c4546 100644 --- a/eng/testing/tests.props +++ b/eng/testing/tests.props @@ -5,12 +5,33 @@ Build $(TestDependsOn);GenerateRunScript;RunTests + true - - - - + + + <_withCategories Condition="'$(WithCategories)' != ''">;$(WithCategories.Trim(';')) + <_withoutCategories Condition="'$(WithoutCategories)' != ''">;$(WithoutCategories.Trim(';')) + + all + <_withCategories Condition="'$(TestScope)' == 'outerloop'">$(_withCategories);OuterLoop + <_withoutCategories Condition="'$(ArchiveTests)' == 'true'">$(_withoutCategories);IgnoreForCI + <_withoutCategories Condition="'$(TestScope)' == '' or '$(TestScope)' == 'innerloop'">$(_withoutCategories);OuterLoop + <_withoutCategories Condition="!$(_withCategories.Contains('failing'))">$(_withoutCategories);failing + + + + + $(NetCoreAppCurrent)-$(Configuration) + $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'AppleTestRunner', '$(MobileRunnersDirSuffix)')) + $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'AndroidTestRunner', '$(MobileRunnersDirSuffix)')) + $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'WasmTestRunner', '$(MobileRunnersDirSuffix)')) + + $(PackageRID) + true + false + + + + + + - $(RunArguments) %RSP_FILE% - $(RunArguments) $RSP_FILE + $(RunScriptCommand) %RSP_FILE% + $(RunScriptCommand) $RSP_FILE - - $([MSBuild]::Escape('$(RunArguments)')) - - $(RunCommand) $(RunArguments) + + $([MSBuild]::Escape('$(RunScriptCommand)')) @@ -71,42 +75,26 @@ TemplatePath="$(RunScriptInputPath)" OutputPath="$(RunScriptOutputPath)" /> - - - - - - - - - - - true - - - - - + - + "$(RunScriptOutputPath)" --runtime-path "$(TestHostRootPath.TrimEnd('\/'))" $(RunTestsCommand) --rsp-file "$(TestRspFile)" + "$(RunScriptOutputPath)" $(AssemblyName) $(TargetArchitecture) - $(RunWorkingDirectory)$(TestResultsName) + $(OutputPath)$(TestResultsName) One or more tests failed while running tests from '$(TestProjectName)'. $(TestRunErrorMessage) Please check $(TestResultsPath) for details! @@ -114,6 +102,7 @@ + diff --git a/eng/testing/xunit/vstest.props b/eng/testing/xunit/vstest.props deleted file mode 100644 index 0cc370f2761714..00000000000000 --- a/eng/testing/xunit/vstest.props +++ /dev/null @@ -1,16 +0,0 @@ - - - - en - testResults.trx - testResults.html - $(HtmlTestResultsName) - $(MSBuildThisFileDirectory)vstest.xunit.json - - - - - - - - diff --git a/eng/testing/xunit/vstest.targets b/eng/testing/xunit/vstest.targets deleted file mode 100644 index 3a638a442c0998..00000000000000 --- a/eng/testing/xunit/vstest.targets +++ /dev/null @@ -1,36 +0,0 @@ - - - "$(DotNetTool)" - dotnet - test $(TargetFileName) - - - $(RunArguments) --nologo - $(RunArguments) --logger "trx;LogFileName=$(TrxTestResultsName)" - $(RunArguments) --logger "html;LogFileName=$(HtmlTestResultsName)" - $(RunArguments) --framework $(TargetFramework) - $(RunArguments) --platform $(TargetArchitecture) - $(RunArguments) --parallel - $(RunArguments) --blame - - - <_testFilter Condition="'$(_withCategories)' != ''">$(_withCategories.Replace(';', '&category=')) - <_testFilter Condition="'$(_withoutCategories)' != ''">$(_testFilter)$(_withoutCategories.Replace(';', '&category!=')) - - <_testFilter Condition="'$(TargetOS)' == 'Windows_NT'">$(_testFilter.Replace('!=', '^!=')) - <_testFilter>$(_testFilter.Trim('&')) - - <_testFilter Condition="'$(TestFilter)' != ''">$(_testFilter)&$(TestFilter.Replace('!=', '^!=')) - - $(RunArguments) --filter "($(_testFilter))" - - - $(RunArguments) $(XUnitOptions) - - - $(RunSettingsOptions) RunConfiguration.DisableParallelization=true - $(RunSettingsOptions) RunConfiguration.DisableAppDomain=true - $(RunSettingsOptions) RunConfiguration.DotNetHostPath="$(RunScriptHost)" - $(RunArguments) --$(RunSettingsOptions) - - \ No newline at end of file diff --git a/eng/testing/xunit/vstest.xunit.json b/eng/testing/xunit/vstest.xunit.json deleted file mode 100644 index b81a78d00ad56e..00000000000000 --- a/eng/testing/xunit/vstest.xunit.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "diagnosticMessages": false, - "longRunningTestSeconds": 120, - "shadowCopy": false -} \ No newline at end of file diff --git a/eng/testing/xunit/xunit.console.json b/eng/testing/xunit/xunit.console.json deleted file mode 100644 index 5d2ac0433c91fe..00000000000000 --- a/eng/testing/xunit/xunit.console.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "diagnosticMessages": true, - "longRunningTestSeconds": 120, - "shadowCopy": false -} \ No newline at end of file diff --git a/eng/testing/xunit/xunit.console.props b/eng/testing/xunit/xunit.console.props deleted file mode 100644 index ad7ffdb52587fd..00000000000000 --- a/eng/testing/xunit/xunit.console.props +++ /dev/null @@ -1,23 +0,0 @@ - - - true - testResults.xml - $(MSBuildThisFileDirectory)xunit.console.json - - - - - - - - - - - - - - diff --git a/eng/testing/xunit/xunit.console.targets b/eng/testing/xunit/xunit.console.targets index 059eede7dcf42b..2824bd84107806 100644 --- a/eng/testing/xunit/xunit.console.targets +++ b/eng/testing/xunit/xunit.console.targets @@ -1,33 +1,51 @@ - $(TargetFileName) - $(RunArguments) -xml $(TestResultsName) - $(RunArguments) -nologo - $(RunArguments) -nocolor + true + testResults.xml + + + + <_depsFileArgument Condition="'$(GenerateDependencyFile)' == 'true'">--depsfile $(AssemblyName).deps.json + "$(RunScriptHost)" exec --runtimeconfig $(AssemblyName).runtimeconfig.json $(_depsFileArgument) xunit.console.dll + xunit.console.exe + + $(RunScriptCommand) $(TargetFileName) + $(RunScriptCommand) -xml $(TestResultsName) + $(RunScriptCommand) -nologo + $(RunScriptCommand) -nocolor - $(RunArguments) -maxthreads 1 - $(RunArguments) -method $(XUnitMethodName) - $(RunArguments) -class $(XUnitClassName) - $(RunArguments) -verbose - $(RunArguments) -noappdomain + $(RunScriptCommand) -maxthreads 1 + $(RunScriptCommand) -method $(XUnitMethodName) + $(RunScriptCommand) -class $(XUnitClassName) + $(RunScriptCommand) -verbose + $(RunScriptCommand) -noappdomain - $(RunArguments)$(_withCategories.Replace(';', ' -trait category=')) - $(RunArguments)$(_withoutCategories.Replace(';', ' -notrait category=')) + $(RunScriptCommand)$(_withCategories.Replace(';', ' -trait category=')) + $(RunScriptCommand)$(_withoutCategories.Replace(';', ' -notrait category=')) - $(RunArguments) $(XUnitOptions) + $(RunScriptCommand) $(XUnitOptions) + + + + + <_testRunnerConfigSourceFile Include="$(TargetDir)$(TargetName).exe.config" /> - <_testRunnerConfigDestFile Include="$(TargetDir)$(_testRunnerName).config" /> + <_testRunnerConfigDestFile Include="$(TargetDir)xunit.console.exe.config" /> - - - "$(RunScriptHost)" - <_depsFileRunArgument Condition="'$(GenerateDependencyFile)' == 'true'">--depsfile $(AssemblyName).deps.json - exec --runtimeconfig $(AssemblyName).runtimeconfig.json $(_depsFileRunArgument) xunit.console.dll $(RunArguments) - - - - <_testRunnerName>xunit.console.exe - $(_testRunnerName) - - <_xunitConsoleNetCoreExclude Condition="'$(GenerateDependencyFile)' != 'true' and '$(XunitConsoleNetCore21AppPath)' != ''" Include="$([System.IO.Path]::GetDirectoryName('$(XunitConsoleNetCore21AppPath)'))\xunit.console.deps.json" /> diff --git a/eng/testing/xunit/xunit.props b/eng/testing/xunit/xunit.props index 0b6289b9a22669..4032da19347661 100644 --- a/eng/testing/xunit/xunit.props +++ b/eng/testing/xunit/xunit.props @@ -1,6 +1,8 @@ - xunit.console + + en + $(MSBuildThisFileDirectory)xunit.runner.json @@ -11,6 +13,22 @@ - - + + + + + + + + + + + + diff --git a/eng/testing/xunit/xunit.runner.json b/eng/testing/xunit/xunit.runner.json new file mode 100644 index 00000000000000..a879e62a4379e4 --- /dev/null +++ b/eng/testing/xunit/xunit.runner.json @@ -0,0 +1,6 @@ +{ + "diagnosticMessages": true, + "longRunningTestSeconds": 120, + "shadowCopy": false, + "preEnumerateTheories": false +} \ No newline at end of file diff --git a/eng/testing/xunit/xunit.targets b/eng/testing/xunit/xunit.targets index 4583d682cfb705..b14d3b7cbf227c 100644 --- a/eng/testing/xunit/xunit.targets +++ b/eng/testing/xunit/xunit.targets @@ -1,41 +1,18 @@ + - nonwindowstests - nonlinuxtests - nonosxtests - nonfreebsdtests - nonnetbsdtests - - - <_withCategories Condition="'$(WithCategories)' != ''">;$(WithCategories.Trim(';')) - <_withoutCategories Condition="'$(WithoutCategories)' != ''">;$(WithoutCategories.Trim(';')) - - all - <_withCategories Condition="'$(TestScope)' == 'outerloop'">$(_withCategories);OuterLoop - <_withoutCategories Condition="'$(ArchiveTests)' == 'true'">$(_withoutCategories);IgnoreForCI - <_withoutCategories Condition="'$(TestScope)' == '' or '$(TestScope)' == 'innerloop'">$(_withoutCategories);OuterLoop - <_withoutCategories Condition="!$(_withCategories.Contains('failing'))">$(_withoutCategories);failing - - <_targetCategory Condition="'$(TargetsNetCoreApp)' == 'true'">netcoreapp - <_targetCategory Condition="'$(TargetsNetFx)' == 'true'">netfx - - <_withoutCategories>$(_withoutCategories);non$(_targetCategory)tests - <_withoutCategories Condition="'$(TargetOSCategory)' != ''">$(_withoutCategories);$(TargetOSCategory) + $(OutDir) - - - + + $(DotNetTool) + test $(TargetPath) --settings $(OutDir).runsettings + - - - + + $(DevEnvDir)Extensions\TestPlatform\vstest.console.exe + $(TargetPath) --settings:$(OutDir).runsettings + - - + diff --git a/eng/versioning.targets b/eng/versioning.targets index 9c2fc1cf8b3b51..21a442a03f3c0d 100644 --- a/eng/versioning.targets +++ b/eng/versioning.targets @@ -10,7 +10,7 @@ - + @@ -23,7 +23,7 @@ + Condition="'$(IsDotNetFrameworkProductAssembly)' == 'true' and '$(IsTestProject)' != 'true' and '$(IsTestSupportProject)' != 'true'"> @@ -97,4 +97,39 @@ + + + + + $(ArtifactsObjDir)runtime_version.h + + <_RuntimeVersionFileContents> + + + + + + + + + diff --git a/global.json b/global.json index 1c7dd9061e282d..1f55cf7ca46f2f 100644 --- a/global.json +++ b/global.json @@ -1,21 +1,21 @@ { "sdk": { - "version": "5.0.100-preview.4.20202.8", + "version": "5.0.100-preview.5.20251.2", "allowPrerelease": true, "rollForward": "major" }, "tools": { - "dotnet": "5.0.100-preview.4.20202.8" + "dotnet": "5.0.100-preview.5.20251.2" }, "native-tools": { "cmake": "3.14.2", "python3": "3.7.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "5.0.0-beta.20201.2", - "Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20201.2", - "Microsoft.DotNet.Build.Tasks.SharedFramework.Sdk": "5.0.0-beta.20201.2", - "Microsoft.DotNet.Helix.Sdk": "5.0.0-beta.20201.2", + "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "5.0.0-beta.20261.9", + "Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20261.9", + "Microsoft.DotNet.Build.Tasks.SharedFramework.Sdk": "5.0.0-beta.20261.9", + "Microsoft.DotNet.Helix.Sdk": "5.0.0-beta.20261.9", "FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", "Microsoft.NET.Sdk.IL": "5.0.0-preview.4.20202.18", "Microsoft.Build.NoTargets": "1.0.53", diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt index 5fa572c4fcdf9c..efad61086e853d 100644 --- a/src/coreclr/CMakeLists.txt +++ b/src/coreclr/CMakeLists.txt @@ -25,12 +25,6 @@ set(GENERATED_EVENTING_DIR ${CMAKE_CURRENT_BINARY_DIR}/Eventing) set(VERSION_FILE_PATH "${CMAKE_BINARY_DIR}/version.c") set(PAL_REDEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/src/dlls/mscordac/palredefines.S) -if(CLR_CMAKE_HOST_UNIX) - set(CLR_DOTNET_COMMAND ${CLR_REPO_ROOT_DIR}/dotnet.sh) -elseif(CLR_CMAKE_HOST_WIN32) - set(CLR_DOTNET_COMMAND ${CLR_REPO_ROOT_DIR}/dotnet.cmd) -endif(CLR_CMAKE_HOST_UNIX) - # Avoid logging when skipping up-to-date copies set(CMAKE_INSTALL_MESSAGE LAZY) diff --git a/src/coreclr/build-runtime.cmd b/src/coreclr/build-runtime.cmd index 7ba07fedafd874..2c1d7db98ee7a5 100644 --- a/src/coreclr/build-runtime.cmd +++ b/src/coreclr/build-runtime.cmd @@ -81,6 +81,7 @@ set __CommonMSBuildArgs= set __BuildNative=1 set __BuildCrossArchNative=0 set __SkipCrossArchNative=0 +set __SkipGenerateVersion=0 set __RestoreOptData=1 set __CrossArch= set __PgoOptDataPath= @@ -154,6 +155,7 @@ if /i "%1" == "-configureonly" (set __ConfigureOnly=1&set __BuildNative=1& if /i "%1" == "-skipconfigure" (set __SkipConfigure=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "-skipnative" (set __BuildNative=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "-skipcrossarchnative" (set __SkipCrossArchNative=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) +if /i "%1" == "-skipgenerateversion" (set __SkipGenerateVersion=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "-skiprestoreoptdata" (set __RestoreOptData=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "-usenmakemakefiles" (set __NMakeMakefiles=1&set __ConfigureOnly=1&set __BuildNative=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "-pgoinstrument" (set __PgoInstrument=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) @@ -166,6 +168,7 @@ if /i "%1" == "configureonly" (set __ConfigureOnly=1&set __BuildNative=1&s if /i "%1" == "skipconfigure" (set __SkipConfigure=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "skipnative" (set __BuildNative=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "skipcrossarchnative" (set __SkipCrossArchNative=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) +if /i "%1" == "skipgenerateversion" (set __SkipGenerateVersion=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "skiprestoreoptdata" (set __RestoreOptData=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "usenmakemakefiles" (set __NMakeMakefiles=1&set __ConfigureOnly=1&set __BuildNative=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "pgoinstrument" (set __PgoInstrument=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) @@ -317,16 +320,19 @@ REM ============================================================================ @if defined _echo @echo on -echo %__MsgPrefix%Generating native version headers -set "__BinLog=%__LogsDir%\GenerateVersionHeaders_%__TargetOS%__%__BuildArch%__%__BuildType%.binlog" -powershell -NoProfile -ExecutionPolicy ByPass -NoLogo -File "%__RepoRootDir%\eng\common\msbuild.ps1" /clp:nosummary %__ArcadeScriptArgs%^ - %__RepoRootDir%\eng\empty.csproj /p:NativeVersionFile="%__RootBinDir%\obj\coreclr\_version.h"^ - /t:GenerateNativeVersionFile /restore^ - %__CommonMSBuildArgs% %__UnprocessedBuildArgs% /bl:!__BinLog! -if not !errorlevel! == 0 ( - set __exitCode=!errorlevel! - echo %__ErrMsgPrefix%%__MsgPrefix%Error: Failed to generate version headers. - goto ExitWithCode +if %__SkipGenerateVersion% EQU 0 ( + echo %__MsgPrefix%Generating native version headers + set "__BinLog=%__LogsDir%\GenerateVersionHeaders_%__TargetOS%__%__BuildArch%__%__BuildType%.binlog" + powershell -NoProfile -ExecutionPolicy ByPass -NoLogo -File "%__RepoRootDir%\eng\common\msbuild.ps1" /clp:nosummary %__ArcadeScriptArgs%^ + %__RepoRootDir%\eng\empty.csproj /t:GenerateRuntimeVersionFile /restore^ + /p:NativeVersionFile="%__RootBinDir%\obj\coreclr\_version.h"^ + /p:RuntimeVersionFile="%__RootBinDir%\obj\coreclr\runtime_version.h"^ + %__CommonMSBuildArgs% %__UnprocessedBuildArgs% /bl:!__BinLog! + if not !errorlevel! == 0 ( + set __exitCode=!errorlevel! + echo %__ErrMsgPrefix%%__MsgPrefix%Error: Failed to generate version headers. + goto ExitWithCode + ) ) REM ========================================================================================= @@ -690,6 +696,7 @@ echo -skipconfigure: skip CMake ^(default: CMake is run^) echo -skipnative: skip building native components ^(default: native components are built^). echo -skipcrossarchnative: skip building cross-architecture native components ^(default: components are built^). echo -skiprestoreoptdata: skip restoring optimization data used by profile-based optimizations. +echo -skipgenerateversion: skip generating the native version headers. echo -priority=^ : specify a set of test that will be built and run, with priority N. echo portable : build for portable RID. echo. diff --git a/src/coreclr/build-test.cmd b/src/coreclr/build-test.cmd index 6ae3904d022f18..01a41c0a91118a 100644 --- a/src/coreclr/build-test.cmd +++ b/src/coreclr/build-test.cmd @@ -59,6 +59,7 @@ set __RuntimeId= set __TargetsWindows=1 set __DoCrossgen= set __DoCrossgen2= +set __CompositeBuildMode= set __CopyNativeTestBinaries=0 set __CopyNativeProjectsAfterCombinedTestBuild=true set __SkipGenerateLayout=0 @@ -106,6 +107,7 @@ if /i "%1" == "buildagainstpackages" (echo error: Remove /BuildAgainstPackages if /i "%1" == "skiprestorepackages" (set __SkipRestorePackages=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "crossgen" (set __DoCrossgen=1&set __TestBuildMode=crossgen&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "crossgen2" (set __DoCrossgen2=1&set __TestBuildMode=crossgen2&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) +if /i "%1" == "composite" (set __CompositeBuildMode=1&set __DoCrossgen2=1&set __TestBuildMode=crossgen2&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "runtimeid" (set __RuntimeId=%2&set processedArgs=!processedArgs! %1 %2&shift&shift&goto Arg_Loop) if /i "%1" == "targetsNonWindows" (set __TargetsWindows=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "Exclude" (set __Exclude=%2&set processedArgs=!processedArgs! %1 %2&shift&shift&goto Arg_Loop) @@ -115,6 +117,7 @@ if /i "%1" == "targetSpecific" (set "__BuildNeedTargetArg=/p:CLRTestNeedT if /i "%1" == "copynativeonly" (set __CopyNativeTestBinaries=1&set __SkipNative=1&set __CopyNativeProjectsAfterCombinedTestBuild=false&set __SkipCrossgenFramework=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "skipgeneratelayout" (set __SkipGenerateLayout=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "generatelayoutonly" (set __SkipManaged=1&set __SkipNative=1&set __CopyNativeProjectsAfterCombinedTestBuild=false&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) +if /i "%1" == "-excludemonofailures" (set __Mono=1&set processedArgs=!processedArgs!&shift&goto Arg_Loop) if /i "%1" == "--" (set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if [!processedArgs!]==[] ( @@ -154,6 +157,9 @@ set "__BinDir=%__RootBinDir%\bin\coreclr\%__TargetOS%.%__BuildArch%.%__BuildType set "__TestRootDir=%__RootBinDir%\tests\coreclr" set "__TestBinDir=%__TestRootDir%\%__TargetOS%.%__BuildArch%.%__BuildType%" +if not defined XunitTestBinBase set XunitTestBinBase=%__TestBinDir%\ +set "CORE_ROOT=%XunitTestBinBase%\Tests\Core_Root" + REM We have different managed and native intermediate dirs because the managed bits will include REM the configuration information deeper in the intermediates path. REM These variables are used by the msbuild project files. @@ -287,9 +293,6 @@ if "%__SkipRestorePackages%" == "1" goto SkipRestoreProduct echo %__MsgPrefix%Restoring CoreCLR product from packages -if not defined XunitTestBinBase set XunitTestBinBase=%__TestBinDir%\ -set "CORE_ROOT=%XunitTestBinBase%\Tests\Core_Root" - set __BuildLogRootName=Restore_Product set __BuildLog=%__LogsDir%\%__BuildLogRootName%_%__TargetOS%__%__BuildArch%__%__BuildType%.log set __BuildWrn=%__LogsDir%\%__BuildLogRootName%_%__TargetOS%__%__BuildArch%__%__BuildType%.wrn @@ -434,12 +437,8 @@ REM Remove any lock folder used for synchronization from previous runs. powershell -NoProfile "Get-ChildItem -path %__TestBinDir% -Include 'lock' -Recurse -Force | where {$_.Attributes -eq 'Directory'}| Remove-Item -force -Recurse" set CORE_ROOT=%__TestBinDir%\Tests\Core_Root -set CORE_ROOT_STAGE=%__TestBinDir%\Tests\Core_Root_Stage if exist "%CORE_ROOT%" rd /s /q "%CORE_ROOT%" -if exist "%CORE_ROOT_STAGE%" rd /s /q "%CORE_ROOT_STAGE%" md "%CORE_ROOT%" -md "%CORE_ROOT_STAGE%" -xcopy /s "%__BinDir%" "%CORE_ROOT_STAGE%" REM ========================================================================================= REM === @@ -477,8 +476,6 @@ if errorlevel 1 ( exit /b 1 ) -xcopy /s /y /i "%CORE_ROOT_STAGE%" "%CORE_ROOT%" - REM ========================================================================================= REM === REM === Create test wrappers. @@ -502,8 +499,14 @@ set __MsbuildWrn=/flp1:WarningsOnly;LogFile="%__BuildWrn%" set __MsbuildErr=/flp2:ErrorsOnly;LogFile="%__BuildErr%" set __Logging=!__MsbuildLog! !__MsbuildWrn! !__MsbuildErr! +if %%__Mono%%==1 ( + set RuntimeFlavor="mono" +) else ( + set RuntimeFlavor="coreclr" +) + REM Build wrappers using the local SDK's msbuild. As we move to arcade, the other builds should be moved away from run.exe as well. -call "%__RepoRootDir%\dotnet.cmd" msbuild %__ProjectDir%\tests\src\runtest.proj /nodereuse:false /p:BuildWrappers=true /p:TestBuildMode=%__TestBuildMode% !__Logging! %__msbuildArgs% %TargetsWindowsMsbuildArg% %__SkipFXRestoreArg% %__UnprocessedBuildArgs% +call "%__RepoRootDir%\dotnet.cmd" msbuild %__ProjectDir%\tests\src\runtest.proj /nodereuse:false /p:BuildWrappers=true /p:TestBuildMode=%__TestBuildMode% !__Logging! %__msbuildArgs% %TargetsWindowsMsbuildArg% %__SkipFXRestoreArg% %__UnprocessedBuildArgs% /p:RuntimeFlavor=%RuntimeFlavor% if errorlevel 1 ( echo %__ErrMsgPrefix%%__MsgPrefix%Error: XUnit wrapper build failed. Refer to the build log files for details: echo %__BuildLog% @@ -556,8 +559,6 @@ if defined __DoCrossgen2 ( :SkipCrossgen -rd /s /q "%CORE_ROOT_STAGE%" - REM ========================================================================================= REM === REM === All builds complete! @@ -627,18 +628,47 @@ exit /b 1 set __TotalPrecompiled=0 set __FailedToPrecompile=0 set __FailedAssemblies= -for %%F in ("%CORE_ROOT%\System.*.dll";"%CORE_ROOT%\Microsoft.*.dll") do ( +set __CompositeOutputDir=%CORE_ROOT%\composite.out +set __CompositeResponseFile=%__CompositeOutputDir%\framework-r2r.dll.rsp + +if defined __CompositeBuildMode ( + mkdir !__CompositeOutputDir! + echo --composite>>!__CompositeResponseFile! + echo -O>>!__CompositeResponseFile! + echo --out^:%__CompositeOutputDir%\framework-r2r.dll>>!__CompositeResponseFile! +) + +for %%F in ("%CORE_ROOT%\System.*.dll";"%CORE_ROOT%\Microsoft.*.dll";%CORE_ROOT%\netstandard.dll;%CORE_ROOT%\mscorlib.dll) do ( if not "%%~nxF"=="Microsoft.CodeAnalysis.VisualBasic.dll" ( if not "%%~nxF"=="Microsoft.CodeAnalysis.CSharp.dll" ( if not "%%~nxF"=="Microsoft.CodeAnalysis.dll" ( if not "%%~nxF"=="System.Runtime.WindowsRuntime.dll" ( - call :PrecompileAssembly "%%F" %%~nxF __TotalPrecompiled __FailedToPrecompile __FailedAssemblies - echo Processed: !__TotalPrecompiled!, failed !__FailedToPrecompile! + if defined __CompositeBuildMode ( + echo %%F>>!__CompositeResponseFile! + ) else ( + call :PrecompileAssembly "%%F" %%~nxF __TotalPrecompiled __FailedToPrecompile __FailedAssemblies + echo Processed: !__TotalPrecompiled!, failed !__FailedToPrecompile! + ) ))))) ) +if defined __CompositeBuildMode ( + echo Composite response line^: %__CompositeResponseFile% + type "%__CompositeResponseFile%" +) + +if defined __CompositeBuildMode ( + set __CompositeCommandLine="%__RepoRootDir%\dotnet.cmd" + set __CompositeCommandLine=!__CompositeCommandLine! "%CORE_ROOT%\crossgen2\crossgen2.dll" + set __CompositeCommandLine=!__CompositeCommandLine! "@%__CompositeResponseFile%" + echo Building composite R2R framework^: !__CompositeCommandLine! + call !__CompositeCommandLine! + set __FailedToPrecompile=!ERRORLEVEL! + copy /Y "!__CompositeOutputDir!\*.*" "!CORE_ROOT!\" +) + if !__FailedToPrecompile! NEQ 0 ( - echo Failed assemblies: + @echo Failed assemblies: FOR %%G IN (!__FailedAssemblies!) do echo %%G ) @@ -650,13 +680,13 @@ REM Compile the managed assemblies in Core_ROOT before running the tests set AssemblyPath=%1 set AssemblyName=%2 -set __CrossgenExe="%CORE_ROOT%\crossgen.exe" -if /i "%__BuildArch%" == "arm" ( set __CrossgenExe="%CORE_ROOT%\x86\crossgen.exe" ) -if /i "%__BuildArch%" == "arm64" ( set __CrossgenExe="%CORE_ROOT%\x64\crossgen.exe" ) +set __CrossgenExe="%__BinDir%\crossgen.exe" +if /i "%__BuildArch%" == "arm" ( set __CrossgenExe="%__BinDir%\x86\crossgen.exe" ) +if /i "%__BuildArch%" == "arm64" ( set __CrossgenExe="%__BinDir%\x64\crossgen.exe" ) set __CrossgenExe=%__CrossgenExe% if defined __DoCrossgen2 ( - set __CrossgenExe="%CORE_ROOT%\corerun" "%CORE_ROOT%\crossgen2\crossgen2.dll" + set __CrossgenExe="%__RepoRootDir%\dotnet.cmd" "%CORE_ROOT%\crossgen2\crossgen2.dll" ) REM Intentionally avoid using the .dll extension to prevent @@ -666,12 +696,14 @@ set __CrossgenCmd= if defined __DoCrossgen ( set __CrossgenCmd=!__CrossgenExe! /Platform_Assemblies_Paths "!CORE_ROOT!" /in !AssemblyPath! /out !__CrossgenOutputFile! + echo !__CrossgenCmd! + !__CrossgenCmd! ) else ( set __CrossgenCmd=!__CrossgenExe! -r:"!CORE_ROOT!\System.*.dll" -r:"!CORE_ROOT!\Microsoft.*.dll" -r:"!CORE_ROOT!\mscorlib.dll" -r:"!CORE_ROOT!\netstandard.dll" -O --inputbubble --out:!__CrossgenOutputFile! !AssemblyPath! + echo !__CrossgenCmd! + call !__CrossgenCmd! ) -echo %__CrossgenCmd% -%__CrossgenCmd% set /a __exitCode = !errorlevel! set /a "%~3+=1" diff --git a/src/coreclr/build-test.sh b/src/coreclr/build-test.sh index 65110b5ef3b21c..78d294bd83564f 100755 --- a/src/coreclr/build-test.sh +++ b/src/coreclr/build-test.sh @@ -6,9 +6,9 @@ build_test_wrappers() echo "${__MsgPrefix}Creating test wrappers..." if [[ $__Mono -eq 1 ]]; then - export RuntimeFlavor="mono" + __RuntimeFlavor="mono" else - export RuntimeFlavor="coreclr" + __RuntimeFlavor="coreclr" fi __Exclude="${__ProjectDir}/tests/issues.targets" @@ -32,7 +32,7 @@ build_test_wrappers() __MsbuildErr="/fileloggerparameters2:\"ErrorsOnly;LogFile=${__BuildErr}\"" __Logging="$__MsbuildLog $__MsbuildWrn $__MsbuildErr /consoleloggerparameters:$buildVerbosity" - nextCommand="\"${__DotNetCli}\" msbuild \"${__ProjectDir}/tests/src/runtest.proj\" /nodereuse:false /p:BuildWrappers=true /p:TestBuildMode=$__TestBuildMode /p:TargetsWindows=false $__Logging /p:TargetOS=$__TargetOS /p:Configuration=$__BuildType /p:TargetArchitecture=$__BuildArch" + nextCommand="\"${__DotNetCli}\" msbuild \"${__ProjectDir}/tests/src/runtest.proj\" /nodereuse:false /p:BuildWrappers=true /p:TestBuildMode=$__TestBuildMode /p:TargetsWindows=false $__Logging /p:TargetOS=$__TargetOS /p:Configuration=$__BuildType /p:TargetArchitecture=$__BuildArch /p:RuntimeFlavor=$__RuntimeFlavor \"/bl:${__RepoRootDir}/artifacts/log/${__BuildType}/build_test_wrappers_${__RuntimeFlavor}.binlog\"" eval $nextCommand local exitCode="$?" @@ -119,13 +119,10 @@ generate_layout() mkdir -p "$CORE_ROOT" - build_MSBuild_projects "Tests_Overlay_Managed" "${__ProjectDir}/tests/src/runtest.proj" "Creating test overlay" "/t:CreateTestOverlay" - chmod +x "$__BinDir"/corerun chmod +x "$__CrossgenExe" - # Make sure to copy over the pulled down packages - cp -r "$__BinDir"/* "$CORE_ROOT/" > /dev/null + build_MSBuild_projects "Tests_Overlay_Managed" "${__ProjectDir}/tests/src/runtest.proj" "Creating test overlay" "/t:CreateTestOverlay" if [[ "$__TargetOS" != "OSX" ]]; then nextCommand="\"$__TestDir/setup-stress-dependencies.sh\" --arch=$__BuildArch --outputDir=$CORE_ROOT" @@ -183,15 +180,25 @@ precompile_coreroot_fx() local totalPrecompiled=0 local failedToPrecompile=0 + local compositeCommandLine="${__DotNetCli}" + compositeCommandLine+=" $__BinDir/crossgen2/crossgen2.dll" + compositeCommandLine+=" --composite" + compositeCommandLine+=" -O" + compositeCommandLine+=" --out:$outputDir/framework-r2r.dll" declare -a failedAssemblies - filesToPrecompile=$(find -L "$overlayDir" -maxdepth 1 -iname Microsoft.\*.dll -o -iname System.\*.dll -type f) + filesToPrecompile=$(find -L "$overlayDir" -maxdepth 1 -iname Microsoft.\*.dll -o -iname System.\*.dll -o -iname netstandard.dll -o -iname mscorlib.dll -type f) for fileToPrecompile in ${filesToPrecompile}; do local filename="$fileToPrecompile" if is_skip_crossgen_test "$(basename $filename)"; then continue fi + if [[ "$__CompositeBuildMode" != 0 ]]; then + compositeCommandLine+=" $filename" + continue + fi + local commandLine="" if [[ "$__DoCrossgen" != 0 ]]; then @@ -199,7 +206,7 @@ precompile_coreroot_fx() fi if [[ "$__DoCrossgen2" != 0 ]]; then - commandLine="$overlayDir/corerun $overlayDir/crossgen2/crossgen2.dll $crossgen2References -O --inputbubble --out $outputDir/$(basename $filename) $filename" + commandLine="${__DotNetCli} $overlayDir/crossgen2/crossgen2.dll $crossgen2References -O --inputbubble --out $outputDir/$(basename $filename) $filename" fi echo Precompiling "$filename" @@ -224,6 +231,17 @@ precompile_coreroot_fx() echo "Processed: $totalPrecompiled, failed $failedToPrecompile" done + if [[ "$__CompositeBuildMode" != 0 ]]; then + # Compile the entire framework in composite build mode + echo "Compiling composite R2R framework: $compositeCommandLine" + $compositeCommandLine + local exitCode="$?" + if [[ "$exitCode" != 0 ]]; then + echo Unable to precompile composite framework, exit code is "$exitCode". + exit 1 + fi + fi + if [[ "$__DoCrossgen2" != 0 ]]; then # Copy the Crossgen-compiled assemblies back to CORE_ROOT mv -f "$outputDir"/* "$overlayDir"/ @@ -536,6 +554,12 @@ handle_arguments_local() { __TestBuildMode=crossgen2 ;; + composite|-composite) + __CompositeBuildMode=1 + __DoCrossgen2=1 + __TestBuildMode=crossgen2 + ;; + generatetesthostonly|-generatetesthostonly) __GenerateTestHostOnly=1 ;; @@ -603,6 +627,7 @@ __CrossBuild=0 __DistroRid="" __DoCrossgen=0 __DoCrossgen2=0 +__CompositeBuildMode=0 __DotNetCli="$__RepoRootDir/dotnet.sh" __GenerateLayoutOnly= __GenerateTestHostOnly= diff --git a/src/coreclr/build.cmd b/src/coreclr/build.cmd deleted file mode 100644 index a4955fb4c52a35..00000000000000 --- a/src/coreclr/build.cmd +++ /dev/null @@ -1,1017 +0,0 @@ -@if not defined _echo @echo off -setlocal EnableDelayedExpansion EnableExtensions - -:: Define a prefix for most output progress messages that come from this script. That makes -:: it easier to see where these are coming from. Note that there is a trailing space here. -set "__MsgPrefix=BUILD: " - -echo %__MsgPrefix%Starting Build at %TIME% -echo %__MsgPrefix%WARNING: This build script is deprecated and will be deleted soon. Use the root build script to build CoreCLR. If you want to build the CoreCLR runtime without using MSBuild, use the build-native.cmd script. -echo %__MsgPrefix%See https://github.com/dotnet/runtime/issues/32991 for more information. - -set __ThisScriptFull="%~f0" -set __ThisScriptDir="%~dp0" - -call "%__ThisScriptDir%"\setup_vs_tools.cmd -if NOT '%ERRORLEVEL%' == '0' goto ExitWithError - -if defined VS160COMNTOOLS ( - set "__VSToolsRoot=%VS160COMNTOOLS%" - set "__VCToolsRoot=%VS160COMNTOOLS%\..\..\VC\Auxiliary\Build" - set __VSVersion=vs2019 -) else if defined VS150COMNTOOLS ( - set "__VSToolsRoot=%VS150COMNTOOLS%" - set "__VCToolsRoot=%VS150COMNTOOLS%\..\..\VC\Auxiliary\Build" - set __VSVersion=vs2017 -) - -:: Note that the msbuild project files (specifically, dir.proj) will use the following variables, if set: -:: __BuildArch -- default: x64 -:: __BuildType -- default: Debug -:: __TargetOS -- default: Windows_NT -:: __ProjectDir -- default: directory of the dir.props file -:: __RepoRootDir -- default: directory two levels above the dir.props file -:: __SourceDir -- default: %__ProjectDir%\src\ -:: __RootBinDir -- default: %__RepoRootDir%\artifacts\ -:: __BinDir -- default: %__RootBinDir%\%__TargetOS%.%__BuildArch.%__BuildType%\ -:: __IntermediatesDir -:: __PackagesBinDir -- default: %__BinDir%\.nuget -:: -:: Thus, these variables are not simply internal to this script! - -:: Set the default arguments for build -set __BuildArch=x64 -set __BuildType=Debug -set __TargetOS=Windows_NT - -:: Set the various build properties here so that CMake and MSBuild can pick them up -set "__ProjectDir=%~dp0" -:: remove trailing slash -if %__ProjectDir:~-1%==\ set "__ProjectDir=%__ProjectDir:~0,-1%" -set "__RepoRootDir=%__ProjectDir%\..\.." - -set "__ProjectFilesDir=%__ProjectDir%" -set "__SourceDir=%__ProjectDir%\src" -set "__RootBinDir=%__RepoRootDir%\artifacts" - -set __BuildAll= - -set __BuildArchX64=0 -set __BuildArchX86=0 -set __BuildArchArm=0 -set __BuildArchArm64=0 - -set __BuildTypeDebug=0 -set __BuildTypeChecked=0 -set __BuildTypeRelease=0 - -set __PgoInstrument=0 -set __PgoOptimize=1 -set __EnforcePgo=0 -set __IbcTuning= - -REM __PassThroughArgs is a set of things that will be passed through to nested calls to build.cmd -REM when using "all". -set __PassThroughArgs= - -REM __UnprocessedBuildArgs are args that we pass to msbuild (e.g. /p:TargetArchitecture=x64) -set "__args= %*" -set processedArgs= -set __UnprocessedBuildArgs= -set __CommonMSBuildArgs= - -set __BuildCoreLib=1 -set __BuildNative=1 -set __BuildCrossArchNative=0 -set __SkipCrossArchNative=0 -set __BuildTests=1 -set __BuildPackages=1 -set __BuildNativeCoreLib=1 -set __BuildManagedTools=1 -set __RestoreOptData=1 -set __GenerateLayout=0 -set __CrossgenAltJit= -set __SkipRestoreArg=/p:RestoreDuringBuild=true -set __OfficialBuildIdArg= -set __CrossArch= -set __PgoOptDataPath= - -@REM CMD has a nasty habit of eating "=" on the argument list, so passing: -@REM -priority=1 -@REM appears to CMD parsing as "-priority 1". Handle -priority specially to avoid problems, -@REM and allow the "-priority=1" syntax. -set __Priority= - -:Arg_Loop -if "%1" == "" goto ArgsDone - -if /i "%1" == "/?" goto Usage -if /i "%1" == "-?" goto Usage -if /i "%1" == "/h" goto Usage -if /i "%1" == "-h" goto Usage -if /i "%1" == "/help" goto Usage -if /i "%1" == "-help" goto Usage -if /i "%1" == "--help" goto Usage - -if /i "%1" == "-all" (set __BuildAll=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-x64" (set __BuildArchX64=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-x86" (set __BuildArchX86=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-arm" (set __BuildArchArm=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-arm64" (set __BuildArchArm64=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) - -if /i "%1" == "-debug" (set __BuildTypeDebug=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-checked" (set __BuildTypeChecked=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-release" (set __BuildTypeRelease=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) - - -REM TODO these are deprecated remove them eventually -REM don't add more, use the - syntax instead -if /i "%1" == "all" (set __BuildAll=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "x64" (set __BuildArchX64=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "x86" (set __BuildArchX86=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "arm" (set __BuildArchArm=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "arm64" (set __BuildArchArm64=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) - -if /i "%1" == "debug" (set __BuildTypeDebug=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "checked" (set __BuildTypeChecked=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "release" (set __BuildTypeRelease=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) - -if /i "%1" == "-priority" (set __Priority=%2&shift&set processedArgs=!processedArgs! %1=%2&shift&goto Arg_Loop) - -REM Explicitly block -Rebuild. -if /i "%1" == "Rebuild" ( - echo "ERROR: 'Rebuild' is not supported. Please remove it." - goto Usage -) -if /i "%1" == "-Rebuild" ( - echo "ERROR: 'Rebuild' is not supported. Please remove it." - goto Usage -) - - -REM All arguments after this point will be passed through directly to build.cmd on nested invocations -REM using the "all" argument, and must be added to the __PassThroughArgs variable. -if [!__PassThroughArgs!]==[] ( - set __PassThroughArgs=%1 -) else ( - set __PassThroughArgs=%__PassThroughArgs% %1 -) - -if /i "%1" == "-ci" (set __ArcadeScriptArgs="-ci"&set __ErrMsgPrefix=##vso[task.logissue type=error]&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-OfficialBuildId" (set __OfficialBuildIdArg=/p:OfficialBuildId=%2&set __PassThroughArgs=%__PassThroughArgs% %2&set processedArgs=!processedArgs! %1=%2&shift&shift&goto Arg_Loop) - -if /i "%1" == "-alpinedac" (set __BuildCoreLib=0&set __BuildNativeCoreLib=0&set __BuildNative=0&set __BuildCrossArchNative=1&set __CrossArch=x64&set __BuildTests=0&set __BuildPackages=0&set __BuildManagedTools=0&set __TargetOS=alpine&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-linuxdac" (set __BuildCoreLib=0&set __BuildNativeCoreLib=0&set __BuildNative=0&set __BuildCrossArchNative=1&set __CrossArch=x64&set __BuildTests=0&set __BuildPackages=0&set __BuildManagedTools=0&set __TargetOS=Linux&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) - -if /i "%1" == "-freebsdmscorlib" (set __BuildNativeCoreLib=0&set __BuildNative=0&set __BuildTests=0&set __BuildPackages=0&set __BuildManagedTools=0&set __TargetOS=FreeBSD&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-linuxmscorlib" (set __BuildNativeCoreLib=0&set __BuildNative=0&set __BuildTests=0&set __BuildPackages=0&set __BuildManagedTools=0&set __TargetOS=Linux&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-netbsdmscorlib" (set __BuildNativeCoreLib=0&set __BuildNative=0&set __BuildTests=0&set __BuildPackages=0&set __BuildManagedTools=0&set __TargetOS=NetBSD&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-osxmscorlib" (set __BuildNativeCoreLib=0&set __BuildNative=0&set __BuildTests=0&set __BuildPackages=0&set __BuildManagedTools=0&set __TargetOS=OSX&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-windowsmscorlib" (set __BuildNativeCoreLib=0&set __BuildNative=0&set __BuildTests=0&set __BuildPackages=0&set __BuildManagedTools=0&set __TargetOS=Windows_NT&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-nativemscorlib" (set __BuildNativeCoreLib=1&set __BuildCoreLib=0&set __BuildNative=0&set __BuildTests=0&set __BuildPackages=0&set __BuildManagedTools=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-configureonly" (set __ConfigureOnly=1&set __BuildNative=1&set __BuildNativeCoreLib=0&set __BuildCoreLib=0&set __BuildTests=0&set __BuildPackages=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-skipconfigure" (set __SkipConfigure=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-skipmscorlib" (set __BuildCoreLib=0&set __BuildNativeCoreLib=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-skipnative" (set __BuildNative=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-skipcrossarchnative" (set __SkipCrossArchNative=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-skiptests" (set __BuildTests=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-skipbuildpackages" (set __BuildPackages=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-skipmanagedtools" (set __BuildManagedTools=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-skiprestoreoptdata" (set __RestoreOptData=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-generatelayout" (set __GenerateLayout=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-usenmakemakefiles" (set __NMakeMakefiles=1&set __ConfigureOnly=1&set __BuildNative=1&set __BuildNativeCoreLib=0&set __BuildCoreLib=0&set __BuildTests=0&set __BuildPackages=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-pgoinstrument" (set __PgoInstrument=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-enforcepgo" (set __EnforcePgo=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-nopgooptimize" (set __PgoOptimize=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-ibcinstrument" (set __IbcTuning=/Tuning&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "-crossgenaltjit" (set __CrossgenAltJit=%2&set __PassThroughArgs=%__PassThroughArgs% %2&set processedArgs=!processedArgs! %1 %2&shift&shift&goto Arg_Loop) -REM TODO remove these once they are no longer used in buildpipeline -if /i "%1" == "-skiprestore" (set __SkipRestoreArg=/p:RestoreDuringBuild=false&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) - -REM TODO these are deprecated remove them eventually -REM don't add more, use the - syntax instead -if /i "%1" == "freebsdmscorlib" (set __BuildNativeCoreLib=0&set __BuildNative=0&set __BuildTests=0&set __BuildPackages=0&set __BuildManagedTools=0&set __TargetOS=FreeBSD&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "linuxmscorlib" (set __BuildNativeCoreLib=0&set __BuildNative=0&set __BuildTests=0&set __BuildPackages=0&set __BuildManagedTools=0&set __TargetOS=Linux&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "netbsdmscorlib" (set __BuildNativeCoreLib=0&set __BuildNative=0&set __BuildTests=0&set __BuildPackages=0&set __BuildManagedTools=0&set __TargetOS=NetBSD&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "osxmscorlib" (set __BuildNativeCoreLib=0&set __BuildNative=0&set __BuildTests=0&set __BuildPackages=0&set __BuildManagedTools=0&set __TargetOS=OSX&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "windowsmscorlib" (set __BuildNativeCoreLib=0&set __BuildNative=0&set __BuildTests=0&set __BuildPackages=0&set __BuildManagedTools=0&set __TargetOS=Windows_NT&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "nativemscorlib" (set __BuildNativeCoreLib=1&set __BuildCoreLib=0&set __BuildNative=0&set __BuildTests=0&set __BuildPackages=0&set __BuildManagedTools=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "configureonly" (set __ConfigureOnly=1&set __BuildNative=1&set __BuildNativeCoreLib=0&set __BuildCoreLib=0&set __BuildTests=0&set __BuildPackages=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "skipconfigure" (set __SkipConfigure=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "skipmscorlib" (set __BuildCoreLib=0&set __BuildNativeCoreLib=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "skipnative" (set __BuildNative=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "skipcrossarchnative" (set __SkipCrossArchNative=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "skiptests" (set __BuildTests=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "skipbuildpackages" (set __BuildPackages=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "skiprestoreoptdata" (set __RestoreOptData=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "generatelayout" (set __GenerateLayout=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "usenmakemakefiles" (set __NMakeMakefiles=1&set __ConfigureOnly=1&set __BuildNative=1&set __BuildNativeCoreLib=0&set __BuildCoreLib=0&set __BuildTests=0&set __BuildPackages=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "pgoinstrument" (set __PgoInstrument=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "nopgooptimize" (set __PgoOptimize=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "enforcepgo" (set __EnforcePgo=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "ibcinstrument" (set __IbcTuning=/Tuning&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "crossgenaltjit" (set __CrossgenAltJit=%2&set __PassThroughArgs=%__PassThroughArgs% %2set processedArgs=!processedArgs! %1 %2&shift&shift&goto Arg_Loop) -REM TODO remove this once it's no longer used in buildpipeline -if /i "%1" == "--" (set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) - -if [!processedArgs!]==[] ( - set __UnprocessedBuildArgs=%__args% -) else ( - set __UnprocessedBuildArgs=%__args% - for %%t in (!processedArgs!) do ( - set __UnprocessedBuildArgs=!__UnprocessedBuildArgs:*%%t=! - ) -) - -:ArgsDone - -@REM Special handling for -priority=N argument. -if defined __Priority ( - if defined __PassThroughArgs ( - set __PassThroughArgs=%__PassThroughArgs% -priority=%__Priority% - ) else ( - set __PassThroughArgs=-priority=%__Priority% - ) -) - -if defined __BuildAll goto BuildAll - -set /A __TotalSpecifiedBuildArch=__BuildArchX64 + __BuildArchX86 + __BuildArchArm + __BuildArchArm64 -if %__TotalSpecifiedBuildArch% GTR 1 ( - echo Error: more than one build architecture specified, but "all" not specified. - goto Usage -) - -if %__BuildArchX64%==1 set __BuildArch=x64 -if %__BuildArchX86%==1 set __BuildArch=x86 -if %__BuildArchArm%==1 ( - set __BuildArch=arm - set __CrossArch=x86 -) -if %__BuildArchArm64%==1 ( - set __BuildArch=arm64 - set __CrossArch=x64 -) - -set /A __TotalSpecifiedBuildType=__BuildTypeDebug + __BuildTypeChecked + __BuildTypeRelease -if %__TotalSpecifiedBuildType% GTR 1 ( - echo Error: more than one build type specified, but "all" not specified. - goto Usage -) - -if %__BuildTypeDebug%==1 set __BuildType=Debug -if %__BuildTypeChecked%==1 set __BuildType=Checked -if %__BuildTypeRelease%==1 set __BuildType=Release - -set __CommonMSBuildArgs=/p:TargetOS=%__TargetOS% /p:Configuration=%__BuildType% /p:TargetArchitecture=%__BuildArch% !__SkipRestoreArg! !__OfficialBuildIdArg! - -if %__EnforcePgo%==1 ( - if %__BuildArchArm%==1 ( - echo NOTICE: enforcepgo does nothing on arm architecture - ) - if %__BuildArchArm64%==1 ( - echo NOTICE: enforcepgo does nothing on arm64 architecture - ) -) - -REM Determine if this is a cross-arch build. Only do cross-arch build if we're also building native. - -if %__SkipCrossArchNative% EQU 0 ( - if %__BuildNative% EQU 1 ( - if %__BuildCrossArchNative% EQU 0 ( - if /i not "%__BuildArch%"=="x86" ( - REM Make recursive calls to build the cross OS DAC - call :BuildCrossOSDac -linuxdac - if not !errorlevel! == 0 ( - goto ExitWithError - ) - ) - ) - if /i "%__BuildArch%"=="arm64" ( - set __BuildCrossArchNative=1 - ) - if /i "%__BuildArch%"=="arm" ( - set __BuildCrossArchNative=1 - ) - ) -) - -REM Set the remaining variables based upon the determined build configuration - -if %__PgoOptimize%==0 ( - set __RestoreOptData=0 -) - -set "__BinDir=%__RootBinDir%\bin\coreclr\%__TargetOS%.%__BuildArch%.%__BuildType%" -set "__IntermediatesDir=%__RootBinDir%\obj\coreclr\%__TargetOS%.%__BuildArch%.%__BuildType%" -set "__ArtifactsIntermediatesDir=%__RepoRootDir%\artifacts\obj\coreclr\" -if "%__NMakeMakefiles%"=="1" (set "__IntermediatesDir=%__RootBinDir%\nmakeobj\%__TargetOS%.%__BuildArch%.%__BuildType%") -set "__PackagesBinDir=%__BinDir%\.nuget" -set "__CrossComponentBinDir=%__BinDir%" -set "__CrossCompIntermediatesDir=%__IntermediatesDir%\crossgen" -set "__LogsDir=%__RootBinDir%\log\!__BuildType!" -set "__MsbuildDebugLogsDir=%__LogsDir%\MsbuildDebugLogs" - - -if NOT "%__CrossArch%" == "" set __CrossComponentBinDir=%__CrossComponentBinDir%\%__CrossArch% -set "__CrossGenCoreLibLog=%__LogsDir%\CrossgenCoreLib_%__TargetOS%__%__BuildArch%__%__BuildType%.log" -set "__CrossgenExe=%__CrossComponentBinDir%\crossgen.exe" - -REM Generate path to be set for CMAKE_INSTALL_PREFIX to contain forward slash -set "__CMakeBinDir=%__BinDir%" -set "__CMakeBinDir=%__CMakeBinDir:\=/%" - -if not exist "%__BinDir%" md "%__BinDir%" -if not exist "%__IntermediatesDir%" md "%__IntermediatesDir%" -if not exist "%__LogsDir%" md "%__LogsDir%" -if not exist "%__MsbuildDebugLogsDir%" md "%__MsbuildDebugLogsDir%" - -if not exist "%__RootBinDir%\Directory.Build.props" copy %__ProjectDir%\EmptyProps.props %__RootBinDir%\Directory.Build.props -if not exist "%__RootBinDir%\Directory.Build.targets" copy %__ProjectDir%\EmptyProps.props %__RootBinDir%\Directory.Build.targets - -REM Set up the directory for MSBuild debug logs. -set MSBUILDDEBUGPATH=%__MsbuildDebugLogsDir% - -REM It is convenient to have your Nuget search path include the location where the build -REM will place packages. However nuget used during the build will fail if that directory -REM does not exist. Avoid this in at least one case by aggressively creating the directory. -if not exist "%__BinDir%\.nuget\pkg" md "%__BinDir%\.nuget\pkg" - -echo %__MsgPrefix%Commencing CoreCLR product build - -REM Set the remaining variables based upon the determined build configuration - -echo %__MsgPrefix%Checking prerequisites - -set __CMakeNeeded=1 -if %__BuildNative%==0 if %__BuildCrossArchNative%==0 if %__BuildNativeCoreLib%==0 if %__BuildTests%==0 set __CMakeNeeded=0 -if %__CMakeNeeded%==1 ( - REM Eval the output from set-cmake-path.ps1 - for /f "delims=" %%a in ('powershell -NoProfile -ExecutionPolicy ByPass "& ""%__SourceDir%\pal\tools\set-cmake-path.ps1"""') do %%a - echo %__MsgPrefix%Using CMake from !CMakePath! -) - -REM NumberOfCores is an WMI property providing number of physical cores on machine -REM processor(s). It is used to set optimal level of CL parallelism during native build step -if not defined NumberOfCores ( - REM Determine number of physical processor cores available on machine - set TotalNumberOfCores=0 - for /f "tokens=*" %%I in ( - 'wmic cpu get NumberOfCores /value ^| find "=" 2^>NUL' - ) do set %%I & set /a TotalNumberOfCores=TotalNumberOfCores+NumberOfCores - set NumberOfCores=!TotalNumberOfCores! -) -echo %__MsgPrefix%Number of processor cores %NumberOfCores% - -REM ========================================================================================= -REM === -REM === Start the build steps -REM === -REM ========================================================================================= - -@if defined _echo @echo on - -echo %__MsgPrefix%Generating native version headers -set "__BinLog=%__LogsDir%\GenerateVersionHeaders_%__TargetOS%__%__BuildArch%__%__BuildType%.binlog" -powershell -NoProfile -ExecutionPolicy ByPass -NoLogo -File "%__RepoRootDir%\eng\common\msbuild.ps1" /clp:nosummary %__ArcadeScriptArgs%^ - %__RepoRootDir%\eng\empty.csproj /p:NativeVersionFile="%__RootBinDir%\obj\coreclr\_version.h"^ - /t:GenerateNativeVersionFile /restore^ - %__CommonMSBuildArgs% %__UnprocessedBuildArgs% /bl:!__BinLog! -if not !errorlevel! == 0 ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: Failed to generate version headers. - echo !__BinLog! - set __exitCode=!errorlevel! - goto ExitWithCode -) - -REM ========================================================================================= -REM === -REM === Restore optimization profile data -REM === -REM ========================================================================================= - -set OptDataProjectFilePath=%__ProjectDir%\src\.nuget\optdata\optdata.csproj -if %__RestoreOptData% EQU 1 ( - echo %__MsgPrefix%Restoring the OptimizationData Package - set "__BinLog=%__LogsDir%\OptRestore_%__TargetOS%__%__BuildArch%__%__BuildType%.binlog" - - powershell -NoProfile -ExecutionPolicy ByPass -NoLogo -File "%__RepoRootDir%\eng\common\msbuild.ps1" /clp:nosummary %__ArcadeScriptArgs%^ - %OptDataProjectFilePath% /t:Restore^ - %__CommonMSBuildArgs% %__UnprocessedBuildArgs%^ - /nodereuse:false /bl:!__BinLog! - if not !errorlevel! == 0 ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: Failed to restore the optimization data package. - echo !__BinLog! - set __exitCode=!errorlevel! - goto ExitWithCode - ) -) -set __PgoOptDataPath= -if %__PgoOptimize% EQU 1 ( - set PgoDataPackagePathOutputFile="%__IntermediatesDir%\optdatapath.txt" - set "__BinLog=%__LogsDir%\PgoVersionRead_%__TargetOS%__%__BuildArch%__%__BuildType%.binlog" - - REM Parse the optdata package versions out of msbuild so that we can pass them on to CMake - powershell -NoProfile -ExecutionPolicy ByPass -NoLogo -File "%__RepoRootDir%\eng\common\msbuild.ps1" /clp:nosummary %__ArcadeScriptArgs%^ - "%OptDataProjectFilePath%" /t:DumpPgoDataPackagePath %__CommonMSBuildArgs% /bl:!__BinLog! /p:PgoDataPackagePathOutputFile="!PgoDataPackagePathOutputFile!" - - if not !errorlevel! == 0 ( - echo %__ErrMsgPrefix%Failed to get PGO data package path. - echo !__BinLog! - set __exitCode=!errorlevel! - goto ExitWithCode - ) - if not exist "!PgoDataPackagePathOutputFile!" ( - echo %__ErrMsgPrefix%Failed to get PGO data package path. - echo !__BinLog! - goto ExitWithError - ) - - set /p __PgoOptDataPath=<"!PgoDataPackagePathOutputFile!" -) - -REM ========================================================================================= -REM === -REM === Generate source files for eventing -REM === -REM ========================================================================================= - -set __IntermediatesIncDir=%__IntermediatesDir%\src\inc -set __IntermediatesEventingDir=%__ArtifactsIntermediatesDir%\Eventing\%__BuildArch%\%__BuildType% - -REM Find python and set it to the variable PYTHON -set _C=-c "import sys; sys.stdout.write(sys.executable)" -(py -3 %_C% || py -2 %_C% || python3 %_C% || python2 %_C% || python %_C%) > %TEMP%\pythonlocation.txt 2> NUL -set _C= -set /p PYTHON=<%TEMP%\pythonlocation.txt - -if NOT DEFINED PYTHON ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: Could not find a python installation - goto ExitWithError -) - -if %__BuildCoreLib% EQU 1 ( - echo %__MsgPrefix%Laying out dynamically generated EventSource classes - "!PYTHON!" -B -Wall %__SourceDir%\scripts\genRuntimeEventSources.py --man %__SourceDir%\vm\ClrEtwAll.man --intermediate %__IntermediatesEventingDir% || goto ExitWithError -) - -REM ========================================================================================= -REM === -REM === Build Cross-Architecture Native Components (if applicable) -REM === -REM ========================================================================================= - -if %__BuildCrossArchNative% EQU 1 ( - REM Scope environment changes start { - setlocal - - echo %__MsgPrefix%Commencing build of cross architecture native components for %__TargetOS%.%__BuildArch%.%__BuildType% - - REM Set the environment for the cross-arch native build - set __VCBuildArch=x86_amd64 - if /i "%__CrossArch%" == "x86" ( set __VCBuildArch=x86 ) - - echo %__MsgPrefix%Using environment: "%__VCToolsRoot%\vcvarsall.bat" !__VCBuildArch! - call "%__VCToolsRoot%\vcvarsall.bat" !__VCBuildArch! - @if defined _echo @echo on - - if not exist "%__CrossCompIntermediatesDir%" md "%__CrossCompIntermediatesDir%" - if defined __SkipConfigure goto SkipConfigureCrossBuild - - set __CMakeBinDir=%__CrossComponentBinDir% - set "__CMakeBinDir=!__CMakeBinDir:\=/!" - set __ExtraCmakeArgs="-DCLR_CROSS_COMPONENTS_BUILD=1" "-DCLR_CMAKE_TARGET_ARCH=%__BuildArch%" "-DCLR_CMAKE_TARGET_OS=%__TargetOS%" "-DCLR_CMAKE_PGO_INSTRUMENT=%__PgoInstrument%" "-DCLR_CMAKE_OPTDATA_PATH=%__PgoOptDataPath%" "-DCLR_CMAKE_PGO_OPTIMIZE=%__PgoOptimize%" "-DCMAKE_SYSTEM_VERSION=10.0" "-DCLR_ENG_NATIVE_DIR=%__RepoRootDir%/eng/native" "-DCLR_REPO_ROOT_DIR=%__RepoRootDir%" - call "%__SourceDir%\pal\tools\gen-buildsys.cmd" "%__ProjectDir%" "%__CrossCompIntermediatesDir%" %__VSVersion% %__CrossArch% !__ExtraCmakeArgs! - - if not !errorlevel! == 0 ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: failed to generate native component build project! - goto ExitWithError - ) - @if defined _echo @echo on - -:SkipConfigureCrossBuild - if not exist "%__CrossCompIntermediatesDir%\CMakeCache.txt" ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: unable to find generated native component build project! - goto ExitWithError - ) - - if defined __ConfigureOnly goto SkipCrossCompBuild - - set __BuildLogRootName=Cross - set "__BuildLog=%__LogsDir%\!__BuildLogRootName!_%__TargetOS%__%__BuildArch%__%__BuildType%.log" - set "__BuildWrn=%__LogsDir%\!__BuildLogRootName!_%__TargetOS%__%__BuildArch%__%__BuildType%.wrn" - set "__BuildErr=%__LogsDir%\!__BuildLogRootName!_%__TargetOS%__%__BuildArch%__%__BuildType%.err" - set "__BinLog=%__LogsDir%\!__BuildLogRootName!_%__TargetOS%__%__BuildArch%__%__BuildType%.binlog" - set "__MsbuildLog=/flp:Verbosity=normal;LogFile=!__BuildLog!" - set "__MsbuildWrn=/flp1:WarningsOnly;LogFile=!__BuildWrn!" - set "__MsbuildErr=/flp2:ErrorsOnly;LogFile=!__BuildErr!" - set "__MsbuildBinLog=/bl:!__BinLog!" - set "__Logging=!__MsbuildLog! !__MsbuildWrn! !__MsbuildErr! !__MsbuildBinLog!" - - REM We pass the /m flag directly to MSBuild so that we can get both MSBuild and CL parallelism, which is fastest for our builds. - "%CMakePath%" --build %__CrossCompIntermediatesDir% --target install --config %__BuildType% -- /nologo /m !__Logging! - - if not !errorlevel! == 0 ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: cross-arch components build failed. - echo !__BinLog! - set __exitCode=!errorlevel! - goto ExitWithCode - ) - -:SkipCrossCompBuild - REM } Scope environment changes end - endlocal -) - -REM ========================================================================================= -REM === -REM === Build the CLR VM -REM === -REM ========================================================================================= - -if %__BuildNative% EQU 1 ( - REM Scope environment changes start { - setlocal - - echo %__MsgPrefix%Commencing build of native components for %__TargetOS%.%__BuildArch%.%__BuildType% - - REM Set the environment for the native build - set __VCBuildArch=x86_amd64 - if /i "%__BuildArch%" == "x86" ( set __VCBuildArch=x86 ) - if /i "%__BuildArch%" == "arm" ( - set __VCBuildArch=x86_arm - set ___CrossBuildDefine="-DCLR_CMAKE_CROSS_ARCH=1" "-DCLR_CMAKE_CROSS_HOST_ARCH=%__CrossArch%" - ) - if /i "%__BuildArch%" == "arm64" ( - set __VCBuildArch=x86_arm64 - set ___CrossBuildDefine="-DCLR_CMAKE_CROSS_ARCH=1" "-DCLR_CMAKE_CROSS_HOST_ARCH=%__CrossArch%" - ) - - echo %__MsgPrefix%Using environment: "%__VCToolsRoot%\vcvarsall.bat" !__VCBuildArch! - call "%__VCToolsRoot%\vcvarsall.bat" !__VCBuildArch! - @if defined _echo @echo on - - if not defined VSINSTALLDIR ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: VSINSTALLDIR variable not defined. - goto ExitWithError - ) - if not exist "!VSINSTALLDIR!DIA SDK" goto NoDIA - - if defined __SkipConfigure goto SkipConfigure - - echo %__MsgPrefix%Regenerating the Visual Studio solution - - set __ExtraCmakeArgs="-DCMAKE_SYSTEM_VERSION=10.0" !___CrossBuildDefine! "-DCLR_CMAKE_PGO_INSTRUMENT=%__PgoInstrument%" "-DCLR_CMAKE_OPTDATA_PATH=%__PgoOptDataPath%" "-DCLR_CMAKE_PGO_OPTIMIZE=%__PgoOptimize%" "-DCLR_ENG_NATIVE_DIR=%__RepoRootDir%/eng/native" "-DCLR_REPO_ROOT_DIR=%__RepoRootDir%" - call "%__SourceDir%\pal\tools\gen-buildsys.cmd" "%__ProjectDir%" "%__IntermediatesDir%" %__VSVersion% %__BuildArch% !__ExtraCmakeArgs! - if not !errorlevel! == 0 ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: failed to generate native component build project! - goto ExitWithError - ) - - @if defined _echo @echo on - -:SkipConfigure - if not exist "%__IntermediatesDir%\CMakeCache.txt" ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: unable to find generated native component build project! - goto ExitWithError - ) - - if defined __ConfigureOnly goto SkipNativeBuild - - set __BuildLogRootName=CoreCLR - set "__BuildLog=%__LogsDir%\!__BuildLogRootName!_%__TargetOS%__%__BuildArch%__%__BuildType%.log" - set "__BuildWrn=%__LogsDir%\!__BuildLogRootName!_%__TargetOS%__%__BuildArch%__%__BuildType%.wrn" - set "__BuildErr=%__LogsDir%\!__BuildLogRootName!_%__TargetOS%__%__BuildArch%__%__BuildType%.err" - set "__BinLog=%__LogsDir%\!__BuildLogRootName!_%__TargetOS%__%__BuildArch%__%__BuildType%.binlog" - set "__MsbuildLog=/flp:Verbosity=normal;LogFile=!__BuildLog!" - set "__MsbuildWrn=/flp1:WarningsOnly;LogFile=!__BuildWrn!" - set "__MsbuildErr=/flp2:ErrorsOnly;LogFile=!__BuildErr!" - set "__MsbuildBinLog=/bl:!__BinLog!" - set "__Logging=!__MsbuildLog! !__MsbuildWrn! !__MsbuildErr! !__MsbuildBinLog!" - - REM We pass the /m flag directly to MSBuild so that we can get both MSBuild and CL parallelism, which is fastest for our builds. - "%CMakePath%" --build %__IntermediatesDir% --target install --config %__BuildType% -- /nologo /m !__Logging! - - if not !errorlevel! == 0 ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: native component build failed. - echo !__BinLog! - set __exitCode=!errorlevel! - goto ExitWithCode - ) - -:SkipNativeBuild - REM } Scope environment changes end - endlocal -) - -REM ========================================================================================= -REM === -REM === CoreLib and NuGet package build section. -REM === -REM ========================================================================================= - -if %__BuildCoreLib% EQU 1 ( - REM Scope environment changes start { - setlocal - - echo %__MsgPrefix%Commencing build of System.Private.CoreLib for %__TargetOS%.%__BuildArch%.%__BuildType% - rem Explicitly set Platform causes conflicts in CoreLib project files. Clear it to allow building from VS x64 Native Tools Command Prompt - set Platform= - - set __ExtraBuildArgs= - - if "%__BuildManagedTools%" == "1" ( - set __ExtraBuildArgs=!__ExtraBuildArgs! /p:BuildManagedTools=true - ) - - set __BuildLogRootName=System.Private.CoreLib - set "__BuildLog=%__LogsDir%\!__BuildLogRootName!_%__TargetOS%__%__BuildArch%__%__BuildType%.log" - set "__BuildWrn=%__LogsDir%\!__BuildLogRootName!_%__TargetOS%__%__BuildArch%__%__BuildType%.wrn" - set "__BuildErr=%__LogsDir%\!__BuildLogRootName!_%__TargetOS%__%__BuildArch%__%__BuildType%.err" - set "__Binlog=%__LogsDir%\!__BuildLogRootName!_%__TargetOS%__%__BuildArch%__%__BuildType%.binlog" - set "__MsbuildLog=/flp:Verbosity=normal;LogFile=!__BuildLog!" - set "__MsbuildWrn=/flp1:WarningsOnly;LogFile=!__BuildWrn!" - set "__MsbuildErr=/flp2:ErrorsOnly;LogFile=!__BuildErr!" - set "__MsbuildBinLog=/bl:!__Binlog!" - set "__Logging=!__MsbuildLog! !__MsbuildWrn! !__MsbuildErr! !__MsbuildBinLog!" - - powershell -NoProfile -ExecutionPolicy ByPass -NoLogo -File "%__RepoRootDir%\eng\common\msbuild.ps1" /clp:nosummary %__ArcadeScriptArgs%^ - %__ProjectDir%\src\build.proj /t:Restore^ - /nodeReuse:false /p:PortableBuild=true /maxcpucount /p:IncludeRestoreOnlyProjects=true^ - !__Logging! /bl: %__CommonMSBuildArgs% !__ExtraBuildArgs! %__UnprocessedBuildArgs% - if not !errorlevel! == 0 ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: Managed Product assemblies restore failed. Refer to the build log files for details. - echo !__BuildLog! - echo !__BuildWrn! - echo !__BuildErr! - echo !__Binlog! - set __exitCode=!errorlevel! - goto ExitWithCode - ) - - powershell -NoProfile -ExecutionPolicy ByPass -NoLogo -Command "%__RepoRootDir%\eng\common\msbuild.ps1" /clp:nosummary %__ArcadeScriptArgs%^ - %__ProjectDir%\src\build.proj /nodeReuse:false /p:PortableBuild=true /maxcpucount^ - '!__MsbuildLog!' '!__MsbuildWrn!' '!__MsbuildErr!' %__CommonMSBuildArgs% !__ExtraBuildArgs! %__UnprocessedBuildArgs% - if not !errorlevel! == 0 ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: Managed Product assemblies build failed. Refer to the build log files for details. - echo !__BuildLog! - echo !__BuildWrn! - echo !__BuildErr! - echo !__Binlog! - set __exitCode=!errorlevel! - goto ExitWithCode - ) - - if "%__BuildManagedTools%" == "1" ( - echo %__MsgPrefix%Publishing crossgen2... - call %__RepoRootDir%\dotnet.cmd publish --self-contained -r win-%__BuildArch% -c %__BuildType% -o "%__BinDir%\crossgen2" "%__ProjectDir%\src\tools\crossgen2\crossgen2\crossgen2.csproj" /nologo /p:TargetArchitecture=%__BuildArch% - - if not !errorlevel! == 0 ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: Failed to build crossgen2. - echo !__BuildLog! - echo !__BuildWrn! - echo !__BuildErr! - set __exitCode=!errorlevel! - goto ExitWithCode - ) - - copy /Y "%__BinDir%\clrjit.dll" "%__BinDir%\crossgen2\clrjitilc.dll" | find /i /v "file(s) copied" - copy /Y "%__BinDir%\jitinterface.dll" "%__BinDir%\crossgen2\jitinterface.dll" | find /i /v "file(s) copied" - ) - REM } Scope environment changes end - endlocal -) - -REM ========================================================================================= -REM === -REM === Build native System.Private.CoreLib. -REM === -REM ========================================================================================= - -REM Scope environment changes start { -setlocal - -REM Need diasymreader.dll on your path for /CreatePdb -set PATH=%PATH%;%WinDir%\Microsoft.Net\Framework64\V4.0.30319;%WinDir%\Microsoft.Net\Framework\V4.0.30319 - -if %__BuildNativeCoreLib% EQU 1 ( - echo %__MsgPrefix%Generating native image of System.Private.CoreLib for %__TargetOS%.%__BuildArch%.%__BuildType%. Logging to "%__CrossGenCoreLibLog%". - if exist "%__CrossGenCoreLibLog%" del "%__CrossGenCoreLibLog%" - - REM Need VS native tools environment for the **target** arch when running instrumented binaries - if %__PgoInstrument% EQU 1 ( - set __VCExecArch=%__BuildArch% - if /i [%__BuildArch%] == [x64] set __VCExecArch=amd64 - echo %__MsgPrefix%Using environment: "%__VCToolsRoot%\vcvarsall.bat" !__VCExecArch! - call "%__VCToolsRoot%\vcvarsall.bat" !__VCExecArch! - @if defined _echo @echo on - if NOT !errorlevel! == 0 ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: Failed to load native tools environment for !__VCExecArch! - goto ExitWithError - ) - - REM HACK: Workaround for [dotnet/coreclr#13970](https://github.com/dotnet/coreclr/issues/13970) - set __PgoRtPath= - for /f "tokens=*" %%f in ('where pgort*.dll') do ( - if not defined __PgoRtPath set "__PgoRtPath=%%~f" - ) - echo %__MsgPrefix%Copying "!__PgoRtPath!" into "%__BinDir%" - copy /y "!__PgoRtPath!" "%__BinDir%" || ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: copy failed - goto ExitWithError - ) - REM End HACK - ) - - if defined __CrossgenAltJit ( - REM Set altjit flags for the crossgen run. Note that this entire crossgen section is within a setlocal/endlocal scope, - REM so we don't need to save or unset these afterwards. - echo %__MsgPrefix%Setting altjit environment variables for %__CrossgenAltJit%. - echo %__MsgPrefix%Setting altjit environment variables for %__CrossgenAltJit%. >> "%__CrossGenCoreLibLog%" - set COMPlus_AltJit=* - set COMPlus_AltJitNgen=* - set COMPlus_AltJitName=%__CrossgenAltJit% - set COMPlus_AltJitAssertOnNYI=1 - set COMPlus_NoGuiOnAssert=1 - set COMPlus_ContinueOnAssert=0 - ) - - set NEXTCMD="%__CrossgenExe%" /nologo %__IbcTuning% /Platform_Assemblies_Paths "%__BinDir%\IL" /out "%__BinDir%\System.Private.CoreLib.dll" "%__BinDir%\IL\System.Private.CoreLib.dll" - echo %__MsgPrefix%!NEXTCMD! - echo %__MsgPrefix%!NEXTCMD! >> "%__CrossGenCoreLibLog%" - !NEXTCMD! >> "%__CrossGenCoreLibLog%" 2>&1 - if NOT !errorlevel! == 0 ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: CrossGen System.Private.CoreLib build failed. Refer to %__CrossGenCoreLibLog% - REM Put it in the same log, helpful for Jenkins - type %__CrossGenCoreLibLog% - goto ExitWithError - ) - - set NEXTCMD="%__CrossgenExe%" /nologo /Platform_Assemblies_Paths "%__BinDir%" /CreatePdb "%__BinDir%\PDB" "%__BinDir%\System.Private.CoreLib.dll" - echo %__MsgPrefix%!NEXTCMD! - echo %__MsgPrefix%!NEXTCMD! >> "%__CrossGenCoreLibLog%" - !NEXTCMD! >> "%__CrossGenCoreLibLog%" 2>&1 - if NOT !errorlevel! == 0 ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: CrossGen /CreatePdb System.Private.CoreLib build failed. Refer to %__CrossGenCoreLibLog% - REM Put it in the same log, helpful for Jenkins - type %__CrossGenCoreLibLog% - goto ExitWithError - ) -) - -REM } Scope environment changes end -endlocal - -REM ========================================================================================= -REM === -REM === Build packages -REM === -REM ========================================================================================= - -if %__BuildPackages% EQU 1 ( - REM Scope environment changes start { - setlocal - - echo %__MsgPrefix%Building Packages for %__TargetOS%.%__BuildArch%.%__BuildType% - - set __BuildLog="%__LogsDir%\Nuget_%__TargetOS%__%__BuildArch%__%__BuildType%.binlog" - - REM The conditions as to what to build are captured in the builds file. - REM Package build uses the Arcade system and scripts, relying on it to restore required toolsets as part of build - powershell -NoProfile -ExecutionPolicy ByPass -NoLogo -File "%__RepoRootDir%\eng\common\build.ps1"^ - -r -b -projects %__SourceDir%\.nuget\coreclr-packages.proj^ - -verbosity minimal /clp:nosummary /nodeReuse:false /bl:!__BuildLog!^ - /p:PortableBuild=true^ - /p:Platform=%__BuildArch% %__CommonMSBuildArgs% %__UnprocessedBuildArgs% - if not !errorlevel! == 0 ( - echo %__ErrMsgPrefix%%__MsgPrefix%Error: Nuget package generation failed. Refer to the build log file for details. - echo !__BuildLog! - set __exitCode=!errorlevel! - goto ExitWithCode - ) - - REM } Scope environment changes end - endlocal -) - -REM ========================================================================================= -REM === -REM === Test build section -REM === -REM ========================================================================================= - -if %__BuildTests% EQU 1 ( - echo %__MsgPrefix%Commencing build of tests for %__TargetOS%.%__BuildArch%.%__BuildType% - - set __PriorityArg= - if defined __Priority ( - set __PriorityArg=-priority=%__Priority% - ) - set NEXTCMD=call %__ProjectDir%\build-test.cmd %__BuildArch% %__BuildType% !__PriorityArg! %__UnprocessedBuildArgs% - echo %__MsgPrefix%!NEXTCMD! - !NEXTCMD! - - if not !errorlevel! == 0 ( - REM buildtest.cmd has already emitted an error message and mentioned the build log file to examine. - goto ExitWithError - ) -) else if %__GenerateLayout% EQU 1 ( - echo %__MsgPrefix%Generating layout for %__TargetOS%.%__BuildArch%.%__BuildType% - - set NEXTCMD=call %__ProjectDir%\build-test.cmd %__BuildArch% %__BuildType% generatelayoutonly %__UnprocessedBuildArgs% - echo %__MsgPrefix%!NEXTCMD! - !NEXTCMD! - - if not !errorlevel! == 0 ( - REM runtest.cmd has already emitted an error message and mentioned the build log file to examine. - goto ExitWithError - ) -) - -REM ========================================================================================= -REM === -REM === All builds complete! -REM === -REM ========================================================================================= - -echo %__MsgPrefix%Build succeeded. Finished at %TIME% -echo %__MsgPrefix%Product binaries are available at !__BinDir! -exit /b 0 - -REM ========================================================================================= -REM === -REM === Handle the "all" case. -REM === -REM ========================================================================================= - -:BuildAll - -set __BuildArchList= - -set /A __TotalSpecifiedBuildArch=__BuildArchX64 + __BuildArchX86 + __BuildArchArm + __BuildArchArm64 -if %__TotalSpecifiedBuildArch% EQU 0 ( - REM Nothing specified means we want to build all architectures. - set __BuildArchList=x64 x86 arm arm64 -) - -REM Otherwise, add all the specified architectures to the list. - -if %__BuildArchX64%==1 set __BuildArchList=%__BuildArchList% x64 -if %__BuildArchX86%==1 set __BuildArchList=%__BuildArchList% x86 -if %__BuildArchArm%==1 set __BuildArchList=%__BuildArchList% arm -if %__BuildArchArm64%==1 set __BuildArchList=%__BuildArchList% arm64 - -set __BuildTypeList= - -set /A __TotalSpecifiedBuildType=__BuildTypeDebug + __BuildTypeChecked + __BuildTypeRelease -if %__TotalSpecifiedBuildType% EQU 0 ( - REM Nothing specified means we want to build all build types. - set __BuildTypeList=Debug Checked Release -) - -if %__BuildTypeDebug%==1 set __BuildTypeList=%__BuildTypeList% Debug -if %__BuildTypeChecked%==1 set __BuildTypeList=%__BuildTypeList% Checked -if %__BuildTypeRelease%==1 set __BuildTypeList=%__BuildTypeList% Release - -REM Create a temporary file to collect build results. We always build all flavors specified, and -REM report a summary of the results at the end. - -set __AllBuildSuccess=true -set __BuildResultFile=%TEMP%\build-all-summary-%RANDOM%.txt -if exist %__BuildResultFile% del /f /q %__BuildResultFile% - -for %%i in (%__BuildArchList%) do ( - for %%j in (%__BuildTypeList%) do ( - call :BuildOne %%i %%j - ) -) - -if %__AllBuildSuccess%==true ( - echo %__MsgPrefix%All builds succeeded! - exit /b 0 -) else ( - echo %__MsgPrefix%Builds failed: - type %__BuildResultFile% - del /f /q %__BuildResultFile% - goto ExitWithError -) - -REM This code is unreachable, but leaving it nonetheless, just in case things change. -exit /b 99 - -:BuildOne -set __BuildArch=%1 -set __BuildType=%2 -set __NextCmd=call %__ThisScriptFull% %__BuildArch% %__BuildType% %__PassThroughArgs% -echo %__MsgPrefix%Invoking: %__NextCmd% -%__NextCmd% -if not !errorlevel! == 0 ( - echo %__MsgPrefix% %__BuildArch% %__BuildType% %__PassThroughArgs% >> %__BuildResultFile% - set __AllBuildSuccess=false -) - - -echo %__MsgPrefix%WARNING: This build script is deprecated and will be deleted soon. Use the root build script to build CoreCLR. If you want to build the CoreCLR runtime without using MSBuild, use the build-native.cmd script. -echo %__MsgPrefix%See https://github.com/dotnet/runtime/issues/32991 for more information. - -exit /b 0 - -REM ========================================================================================= -REM === -REM === Helper routines -REM === -REM ========================================================================================= - - -REM ========================================================================================= -REM === These two routines are intended for the exit code to propagate to the parent process -REM === Like MSBuild or Powershell. If we directly exit /b 1 from within a if statement in -REM === any of the routines, the exit code is not propagated. -REM ========================================================================================= -:ExitWithError -echo %__MsgPrefix%WARNING: This build script is deprecated and will be deleted soon. Use the root build script to build CoreCLR. If you want to build the CoreCLR runtime without using MSBuild, use the build-native.cmd script. -echo %__MsgPrefix%See https://github.com/dotnet/runtime/issues/32991 for more information. -exit /b 1 - -:ExitWithCode -echo %__MsgPrefix%WARNING: This build script is deprecated and will be deleted soon. Use the root build script to build CoreCLR. If you want to build the CoreCLR runtime without using MSBuild, use the build-native.cmd script. -echo %__MsgPrefix%See https://github.com/dotnet/runtime/issues/32991 for more information. -exit /b !__exitCode! - -:BuildCrossOSDac -setlocal -set __BuildDacOption=%1 -set __NextCmd=call %__ThisScriptFull% %__BuildDacOption% %__BuildArch% %__BuildType% %__PassThroughArgs% -echo %__MsgPrefix%Invoking: %__NextCmd% -%__NextCmd% -if not !errorlevel! == 0 ( - echo %__MsgPrefix% %__BuildDacOption% %__BuildArch% %__BuildType% %__PassThroughArgs% - endlocal - goto ExitWithError -) -endlocal -exit /b 0 - -:Usage -echo. -echo Build the CoreCLR repo. -echo. -echo Usage: -echo build.cmd [option1] [option2] -echo or: -echo build.cmd all [option1] [option2] -echo. -echo All arguments are optional. The options are: -echo. -echo.-? -h -help --help: view this message. -echo -all: Builds all configurations and platforms. -echo Build architecture: one of -x64, -x86, -arm, -arm64 ^(default: -x64^). -echo Build type: one of -Debug, -Checked, -Release ^(default: -Debug^). -echo mscorlib version: one of -freebsdmscorlib, -linuxmscorlib, -netbsdmscorlib, -osxmscorlib, -echo or -windowsmscorlib. If one of these is passed, only System.Private.CoreLib is built, -echo for the specified platform ^(FreeBSD, Linux, NetBSD, OS X or Windows, -echo respectively^). -echo add nativemscorlib to go further and build the native image for designated mscorlib. -echo -nopgooptimize: do not use profile guided optimizations. -echo -enforcepgo: verify after the build that PGO was used for key DLLs, and fail the build if not -echo -pgoinstrument: generate instrumented code for profile guided optimization enabled binaries. -echo -ibcinstrument: generate IBC-tuning-enabled native images when invoking crossgen. -echo -configureonly: skip all builds; only run CMake ^(default: CMake and builds are run^) -echo -alpinedac: Build a linux musl DAC with minimal support for printing exceptions in a dump on a windows host. -echo -linuxdac: Build a linux DAC with minimal support for printing exceptions in a dump on a windows host. - -echo -skipconfigure: skip CMake ^(default: CMake is run^) -echo -skipmscorlib: skip building System.Private.CoreLib ^(default: System.Private.CoreLib is built^). -echo -skipnative: skip building native components ^(default: native components are built^). -echo -skipcrossarchnative: skip building cross-architecture native components ^(default: components are built^). -echo -skiptests: skip building tests ^(default: tests are built^). -echo -skipbuildpackages: skip building nuget packages ^(default: packages are built^). -echo -skipmanagedtools: skip build tools such as R2R dump and RunInContext -echo -skiprestoreoptdata: skip restoring optimization data used by profile-based optimizations. -echo -skiprestore: skip restoring packages ^(default: packages are restored during build^). -echo -disableoss: Disable Open Source Signing for System.Private.CoreLib. -echo -priority=^ : specify a set of test that will be built and run, with priority N. -echo -officialbuildid=^: specify the official build ID to be used by this build. -echo -crossgenaltjit ^: run crossgen using specified altjit ^(used for JIT testing^). -echo portable : build for portable RID. -echo. -echo If "all" is specified, then all build architectures and types are built. If, in addition, -echo one or more build architectures or types is specified, then only those build architectures -echo and types are built. -echo. -echo For example: -echo build -all -echo -- builds all architectures, and all build types per architecture -echo build -all -x86 -echo -- builds all build types for x86 -echo build -all -x64 -x86 -Checked -Release -echo -- builds x64 and x86 architectures, Checked and Release build types for each -exit /b 1 - -:NoDIA -echo Error: DIA SDK is missing at "%VSINSTALLDIR%DIA SDK". ^ -Did you install all the requirements for building on Windows, including the "Desktop Development with C++" workload? ^ -Please see https://github.com/dotnet/runtime/blob/master/docs/workflow/requirements/windows-requirements.md ^ -Another possibility is that you have a parallel installation of Visual Studio and the DIA SDK is there. In this case it ^ -may help to copy its "DIA SDK" folder into "%VSINSTALLDIR%" manually, then try again. -exit /b 1 diff --git a/src/coreclr/build.sh b/src/coreclr/build.sh deleted file mode 100755 index 634bcb7af3106e..00000000000000 --- a/src/coreclr/build.sh +++ /dev/null @@ -1,553 +0,0 @@ -#!/usr/bin/env bash - -# resolve python-version to use -if [[ -z "$PYTHON" ]]; then - if ! PYTHON=$(command -v python3 || command -v python2 || command -v python || command -v py) - then - echo "Unable to locate build-dependency python!" 1>&2 - exit 1 - fi -fi -# validate python-dependency -# useful in case of explicitly set option. -if ! command -v "$PYTHON" > /dev/null -then - echo "Unable to locate build-dependency python ($PYTHON)!" 1>&2 - exit 1 -fi - -export PYTHON - -usage_list=("-crossgenonly: only run native image generation.") -usage_list+=("-disableoss: Disable Open Source Signing for System.Private.CoreLib.") -usage_list+=("-ibcinstrument: generate IBC-tuning-enabled native images when invoking crossgen.") -usage_list+=("-nopgooptimize: do not use profile guided optimizations.") -usage_list+=("-officialbuildid=^: specify the official build ID to be used by this build.") -usage_list+=("-partialngen: build CoreLib as PartialNGen.") -usage_list+=("-pgoinstrument: generate instrumented code for profile guided optimization enabled binaries.") -usage_list+=("-skipcrossgen: skip native image generation.") -usage_list+=("-skipcrossarchnative: Disable Open Source Signing for System.Private.CoreLib.") -usage_list+=("-skipmanagedtools: generate instrumented code for profile guided optimization enabled binaries.") -usage_list+=("-skipmscorlib: generate IBC-tuning-enabled native images when invoking crossgen.") -usage_list+=("-skipnuget: skip NuGet package generation.") -usage_list+=("-skiprestore: specify the official build ID to be used by this build.") -usage_list+=("-skiprestoreoptdata: build CoreLib as PartialNGen.") -usage_list+=("-staticanalyzer: skip native image generation.") - -setup_dirs_local() -{ - setup_dirs - - mkdir -p "$__LogsDir" - mkdir -p "$__MsbuildDebugLogsDir" - - if [[ "$__CrossBuild" == 1 ]]; then - mkdir -p "$__CrossComponentBinDir" - fi -} - -restore_optdata() -{ - local OptDataProjectFilePath="$__ProjectRoot/src/.nuget/optdata/optdata.csproj" - if [[ "$__SkipRestoreOptData" == 0 && "$__IsMSBuildOnNETCoreSupported" == 1 ]]; then - echo "Restoring the OptimizationData package" - "$__RepoRootDir/eng/common/msbuild.sh" /clp:nosummary $__ArcadeScriptArgs \ - $OptDataProjectFilePath /t:Restore /m \ - -bl:"$__LogsDir/OptRestore_$__ConfigTriplet.binlog"\ - $__CommonMSBuildArgs $__UnprocessedBuildArgs \ - /nodereuse:false - local exit_code="$?" - if [[ "$exit_code" != 0 ]]; then - echo "${__ErrMsgPrefix}Failed to restore the optimization data package." - exit "$exit_code" - fi - fi - - if [[ "$__PgoOptimize" == 1 && "$__IsMSBuildOnNETCoreSupported" == 1 ]]; then - # Parse the optdata package versions out of msbuild so that we can pass them on to CMake - - local PgoDataPackagePathOutputFile="${__IntermediatesDir}/optdatapath.txt" - - # Writes into ${PgoDataPackagePathOutputFile} - "$__RepoRootDir/eng/common/msbuild.sh" /clp:nosummary $__ArcadeScriptArgs $OptDataProjectFilePath /t:DumpPgoDataPackagePath\ - ${__CommonMSBuildArgs} /p:PgoDataPackagePathOutputFile=${PgoDataPackagePathOutputFile} \ - -bl:"$__LogsDir/PgoVersionRead_$__ConfigTriplet.binlog" > /dev/null 2>&1 - local exit_code="$?" - if [[ "$exit_code" != 0 || ! -f "${PgoDataPackagePathOutputFile}" ]]; then - echo "${__ErrMsgPrefix}Failed to get PGO data package path." - exit "$exit_code" - fi - - __PgoOptDataPath=$(<"${PgoDataPackagePathOutputFile}") - fi -} - -generate_event_logging_sources() -{ - __OutputEventingDir="$1" - - __PythonWarningFlags="-Wall" - if [[ "$__IgnoreWarnings" == 0 ]]; then - __PythonWarningFlags="$__PythonWarningFlags -Werror" - fi - - echo "Laying out dynamically generated EventSource classes" - "$PYTHON" -B $__PythonWarningFlags "$__ProjectRoot/src/scripts/genRuntimeEventSources.py" --man "$__ProjectRoot/src/vm/ClrEtwAll.man" --intermediate "$__OutputEventingDir" -} - -generate_event_logging() -{ - # Event Logging Infrastructure - if [[ "$__SkipMSCorLib" == 0 ]]; then - generate_event_logging_sources "$__ArtifactsIntermediatesDir/Eventing/$__BuildArch/$__BuildType" - fi -} - -build_cross_architecture_components() -{ - local intermediatesForBuild="$__IntermediatesDir/Host$__CrossArch/crossgen" - local crossArchBinDir="$__BinDir/$__CrossArch" - - mkdir -p "$intermediatesForBuild" - mkdir -p "$crossArchBinDir" - - generate_event_logging_sources "$intermediatesForBuild" "the crossarch build system" - - __SkipCrossArchBuild=1 - # check supported cross-architecture components host(__HostArch)/target(__BuildArch) pair - if [[ ("$__BuildArch" == "arm" || "$__BuildArch" == "armel") && ("$__CrossArch" == "x86" || "$__CrossArch" == "x64") ]]; then - __SkipCrossArchBuild=0 - elif [[ "$__BuildArch" == "arm64" && "$__CrossArch" == "x64" ]]; then - __SkipCrossArchBuild=0 - else - # not supported - return - fi - - __CMakeBinDir="$crossArchBinDir" - CROSSCOMPILE=0 - export __CMakeBinDir CROSSCOMPILE - - __CMakeArgs="-DCLR_CMAKE_TARGET_ARCH=$__BuildArch -DCLR_CROSS_COMPONENTS_BUILD=1 $__CMakeArgs" - build_native "$__CrossArch" "$__ProjectRoot" "$__ProjectRoot" "$intermediatesForBuild" "cross-architecture components" - - CROSSCOMPILE=1 - export CROSSCOMPILE -} - -build_CoreLib_ni() -{ - local __CrossGenExec=$1 - local __CoreLibILDir=$2 - - if [[ "$__PartialNgen" == 1 ]]; then - COMPlus_PartialNGen=1 - export COMPlus_PartialNGen - fi - - if [[ -e "$__CrossGenCoreLibLog" ]]; then - rm "$__CrossGenCoreLibLog" - fi - echo "Generating native image of System.Private.CoreLib.dll for $__TargetOS.$__BuildArch.$__BuildType. Logging to \"$__CrossGenCoreLibLog\"." - echo "$__CrossGenExec /Platform_Assemblies_Paths $__CoreLibILDir $__IbcTuning /out $__BinDir/System.Private.CoreLib.dll $__CoreLibILDir/System.Private.CoreLib.dll" - "$__CrossGenExec" /nologo /Platform_Assemblies_Paths $__CoreLibILDir $__IbcTuning /out $__BinDir/System.Private.CoreLib.dll $__CoreLibILDir/System.Private.CoreLib.dll >> $__CrossGenCoreLibLog 2>&1 - local exit_code="$?" - if [[ "$exit_code" != 0 ]]; then - echo "${__ErrMsgPrefix}Failed to generate native image for System.Private.CoreLib. Refer to $__CrossGenCoreLibLog" - exit "$exit_code" - fi - - if [[ "$__TargetOS" == "Linux" ]]; then - echo "Generating symbol file for System.Private.CoreLib.dll" - echo "$__CrossGenExec /Platform_Assemblies_Paths $__BinDir /CreatePerfMap $__BinDir $__BinDir/System.Private.CoreLib.dll" - "$__CrossGenExec" /nologo /Platform_Assemblies_Paths $__BinDir /CreatePerfMap $__BinDir $__BinDir/System.Private.CoreLib.dll >> $__CrossGenCoreLibLog 2>&1 - local exit_code="$?" - if [[ "$exit_code" != 0 ]]; then - echo "${__ErrMsgPrefix}Failed to generate symbol file for System.Private.CoreLib. Refer to $__CrossGenCoreLibLog" - exit "$exit_code" - fi - fi -} - -build_CoreLib() -{ - if [[ "$__IsMSBuildOnNETCoreSupported" == 0 ]]; then - echo "System.Private.CoreLib.dll build unsupported." - return - fi - - if [[ "$__SkipMSCorLib" == 1 ]]; then - echo "Skipping building System.Private.CoreLib." - return - fi - - echo "Commencing build of managed components for $__TargetOS.$__BuildArch.$__BuildType" - - # Invoke MSBuild - __ExtraBuildArgs="" - - if [[ "$__BuildManagedTools" -eq "1" ]]; then - __ExtraBuildArgs="$__ExtraBuildArgs /p:BuildManagedTools=true" - fi - - "$__RepoRootDir/eng/common/msbuild.sh" /clp:nosummary $__ArcadeScriptArgs \ - $__ProjectDir/src/build.proj /t:Restore \ - /p:PortableBuild=true /maxcpucount /p:IncludeRestoreOnlyProjects=true \ - /flp:Verbosity=normal\;LogFile=$__LogsDir/System.Private.CoreLib_$__ConfigTriplet.log \ - -bl:"$__LogsDir/System.Private.CoreLib_$__ConfigTriplet.binlog" \ - /p:__IntermediatesDir=$__IntermediatesDir /p:__RootBinDir=$__RootBinDir \ - $__CommonMSBuildArgs $__ExtraBuildArgs $__UnprocessedBuildArgs - - local exit_code="$?" - if [[ "$exit_code" != 0 ]]; then - echo "${__ErrMsgPrefix}Failed to restore managed components." - exit "$exit_code" - fi - - "$__RepoRootDir/eng/common/msbuild.sh" /clp:nosummary $__ArcadeScriptArgs \ - $__ProjectDir/src/build.proj \ - /p:PortableBuild=true /maxcpucount \ - /flp:Verbosity=normal\;LogFile=$__LogsDir/System.Private.CoreLib_$__TargetOS__$__BuildArch__$__BuildType.log \ - -bl:"$__LogsDir/System.Private.CoreLib_$__ConfigTriplet.binlog" \ - /p:__IntermediatesDir=$__IntermediatesDir /p:__RootBinDir=$__RootBinDir \ - $__CommonMSBuildArgs $__ExtraBuildArgs $__UnprocessedBuildArgs - - local exit_code="$?" - if [[ "$exit_code" != 0 ]]; then - echo "${__ErrMsgPrefix}Failed to build managed components." - exit "$exit_code" - fi - - if [[ "$__BuildManagedTools" -eq "1" ]]; then - echo "Publishing crossgen2 for $__DistroRid" - "$__RepoRootDir/dotnet.sh" publish --self-contained -r $__DistroRid -c $__BuildType -o "$__BinDir/crossgen2" "$__ProjectRoot/src/tools/crossgen2/crossgen2/crossgen2.csproj" /nologo /p:TargetArchitecture=$__BuildArch - - local exit_code="$?" - if [[ "$exit_code" != 0 ]]; then - echo "${__ErrMsgPrefix}Failed to build crossgen2." - exit "$exit_code" - fi - - if [[ "$__HostOS" == "OSX" ]]; then - cp "$__BinDir/libclrjit.dylib" "$__BinDir/crossgen2/libclrjitilc.dylib" - cp "$__BinDir/libjitinterface.dylib" "$__BinDir/crossgen2/libjitinterface.dylib" - else - cp "$__BinDir/libclrjit.so" "$__BinDir/crossgen2/libclrjitilc.so" - cp "$__BinDir/libjitinterface.so" "$__BinDir/crossgen2/libjitinterface.so" - fi - fi - - local __CoreLibILDir="$__BinDir"/IL - - if [[ "$__SkipCrossgen" == 1 ]]; then - echo "Skipping generating native image" - - if [[ "$__CrossBuild" == 1 ]]; then - # Crossgen not performed, so treat the IL version as the final version - cp "$__CoreLibILDir"/System.Private.CoreLib.dll "$__BinDir"/System.Private.CoreLib.dll - fi - - return - fi - - # The cross build generates a crossgen with the target architecture. - if [[ "$__CrossBuild" == 0 ]]; then - if [[ "$__SkipCoreCLR" == 1 ]]; then - return - fi - - # The architecture of host pc must be same architecture with target. - if [[ "$__HostArch" == "$__BuildArch" ]]; then - build_CoreLib_ni "$__BinDir/crossgen" "$__CoreLibILDir" - elif [[ ( "$__HostArch" == "x64" ) && ( "$__BuildArch" == "x86" ) ]]; then - build_CoreLib_ni "$__BinDir/crossgen" "$__CoreLibILDir" - elif [[ ( "$__HostArch" == "arm64" ) && ( "$__BuildArch" == "arm" ) ]]; then - build_CoreLib_ni "$__BinDir/crossgen" "$__CoreLibILDir" - else - exit 1 - fi - else - if [[ ( "$__CrossArch" == "x86" ) && ( "$__BuildArch" == "arm" ) ]]; then - build_CoreLib_ni "$__CrossComponentBinDir/crossgen" "$__CoreLibILDir" - elif [[ ( "$__CrossArch" == "x64" ) && ( "$__BuildArch" == "arm" ) ]]; then - build_CoreLib_ni "$__CrossComponentBinDir/crossgen" "$__CoreLibILDir" - elif [[ ( "$__HostArch" == "x64" ) && ( "$__BuildArch" == "arm64" ) ]]; then - build_CoreLib_ni "$__CrossComponentBinDir/crossgen" "$__CoreLibILDir" - else - # Crossgen not performed, so treat the IL version as the final version - cp "$__CoreLibILDir"/System.Private.CoreLib.dll "$__BinDir"/System.Private.CoreLib.dll - fi - fi -} - -generate_NugetPackages() -{ - # We can only generate nuget package if we also support building mscorlib as part of this build. - if [[ "$__IsMSBuildOnNETCoreSupported" == 0 ]]; then - echo "Nuget package generation unsupported." - return - fi - - # Since we can build mscorlib for this OS, did we build the native components as well? - if [[ "$__SkipCoreCLR" == 1 && "$__CrossgenOnly" == 0 ]]; then - echo "Unable to generate nuget packages since native components were not built." - return - fi - - echo "Generating nuget packages for $__TargetOS" - echo "DistroRid is $__DistroRid" - echo "ROOTFS_DIR is $ROOTFS_DIR" - # Build the packages - # Package build uses the Arcade system and scripts, relying on it to restore required toolsets as part of build - "$__RepoRootDir"/eng/common/build.sh -r -b -projects "$__SourceDir"/.nuget/coreclr-packages.proj \ - -verbosity minimal -bl:"$__LogsDir/Nuget_$__TargetOS__$__BuildArch__$__BuildType.binlog" \ - /p:PortableBuild=true \ - /p:"__IntermediatesDir=$__IntermediatesDir" /p:"__RootBinDir=$__RootBinDir" /p:"__DoCrossArchBuild=$__CrossBuild" \ - $__CommonMSBuildArgs $__UnprocessedBuildArgs - - local exit_code="$?" - if [[ "$exit_code" != 0 ]]; then - echo "${__ErrMsgPrefix}Failed to generate Nuget packages." - exit "$exit_code" - fi -} - -handle_arguments_local() { - case "$1" in - crossgenonly|-crossgenonly) - __SkipMSCorLib=1 - __SkipCoreCLR=1 - __CrossgenOnly=1 - ;; - - disableoss|-disableoss) - __SignTypeArg="/p:SignType=real" - ;; - - ibcinstrument|-ibcinstrument) - __IbcTuning="/Tuning" - ;; - - ignorewarnings|-ignorewarnings) - __IgnoreWarnings=1 - __CMakeArgs="-DCLR_CMAKE_WARNINGS_ARE_ERRORS=OFF $__CMakeArgs" - ;; - - nopgooptimize|-nopgooptimize) - __PgoOptimize=0 - __SkipRestoreOptData=1 - ;; - - officialbuildid=*|-officialbuildid=*) - __Id=$(echo "$1" | cut -d'=' -f 2) - __OfficialBuildIdArg="/p:OfficialBuildId=$__Id" - ;; - - partialngen|-partialngen) - __PartialNgen=1 - ;; - - pgoinstrument|-pgoinstrument) - __PgoInstrument=1 - ;; - - skipcoreclr|-skipcoreclr) - # Accept "skipcoreclr" for backwards-compatibility. - __SkipCoreCLR=1 - ;; - - skipcrossarchnative|-skipcrossarchnative) - __SkipCrossArchNative=1 - ;; - - skipcrossgen|-skipcrossgen) - __SkipCrossgen=1 - ;; - - skipmanagedtools|-skipmanagedtools) - __BuildManagedTools=0 - ;; - - skipmscorlib|-skipmscorlib) - __SkipMSCorLib=1 - ;; - - skipnuget|-skipnuget|skipbuildpackages|-skipbuildpackages) - __SkipNuget=1 - ;; - - skiprestore|-skiprestore) - __SkipRestoreArg="/p:RestoreDuringBuild=false" - ;; - - staticanalyzer|-staticanalyzer) - __StaticAnalyzer=1 - ;; - - *) - __UnprocessedBuildArgs="$__UnprocessedBuildArgs $1" - ;; - esac -} - -echo "Commencing CoreCLR Repo build" -echo "WARNING: This build script is deprecated and will be deleted soon. Use the root build script to build CoreCLR. If you want to build the CoreCLR runtime without using MSBuild, use the build-native.sh script." -echo "See https://github.com/dotnet/runtime/issues/32991 for more information." - -# Argument types supported by this script: -# -# Build architecture - valid values are: x64, ARM. -# Build Type - valid values are: Debug, Checked, Release -# -# Set the default arguments for build - -# Obtain the location of the bash script to figure out where the root of the repo is. -__ProjectRoot="$(cd "$(dirname "$0")"; pwd -P)" -__RepoRootDir="$(cd "$__ProjectRoot"/../..; pwd -P)" - -__BuildArch= -__BuildType=Debug -__CodeCoverage=0 -__IgnoreWarnings=0 - -# Set the various build properties here so that CMake and MSBuild can pick them up -__BuildManagedTools=1 -__Compiler=clang -__CompilerMajorVersion= -__CompilerMinorVersion= -__CommonMSBuildArgs= -__ConfigureOnly=0 -__CrossBuild=0 -__CrossgenOnly=0 -__DistroRid="" -__IbcOptDataPath="" -__IbcTuning="" -__IsMSBuildOnNETCoreSupported=0 -__MSBCleanBuildArgs= -__OfficialBuildIdArg="" -__PartialNgen=0 -__PgoInstrument=0 -__PgoOptDataPath="" -__PgoOptimize=1 -__PortableBuild=1 -__ProjectDir="$__ProjectRoot" -__RootBinDir="$__RepoRootDir/artifacts" -__SignTypeArg="" -__SkipConfigure=0 -__SkipCoreCLR=0 -__SkipCrossArchNative=0 -__SkipCrossgen=0 -__SkipGenerateVersion=0 -__SkipMSCorLib=0 -__SkipManaged=0 -__SkipNuget=0 -__SkipRestore="" -__SkipRestoreArg="/p:RestoreDuringBuild=true" -__SkipRestoreOptData=0 -__SourceDir="$__ProjectDir/src" -__StaticAnalyzer=0 -__UnprocessedBuildArgs= -__UseNinja=0 -__VerboseBuild=0 -__ValidateCrossArg=1 -__CMakeArgs="" - -source "$__ProjectRoot"/_build-commons.sh - -if [[ "${__BuildArch}" != "${__HostArch}" ]]; then - __CrossBuild=1 -fi - -# Set dependent variables -__LogsDir="$__RootBinDir/log/$__BuildType" -__MsbuildDebugLogsDir="$__LogsDir/MsbuildDebugLogs" -__ConfigTriplet=$__TargetOS__$__BuildArch__$__BuildType - -# Set the remaining variables based upon the determined build configuration -__BinDir="$__RootBinDir/bin/coreclr/$__TargetOS.$__BuildArch.$__BuildType" -__PackagesBinDir="$__BinDir/.nuget" -__IntermediatesDir="$__RootBinDir/obj/coreclr/$__TargetOS.$__BuildArch.$__BuildType" -__ArtifactsIntermediatesDir="$__RepoRootDir/artifacts/obj/coreclr" -export __IntermediatesDir __ArtifactsIntermediatesDir - -__CrossComponentBinDir="$__BinDir" - -__CrossArch="$__HostArch" -if [[ "$__CrossBuild" == 1 ]]; then - __CrossComponentBinDir="$__CrossComponentBinDir/$__CrossArch" -fi -__CrossGenCoreLibLog="$__LogsDir/CrossgenCoreLib_$__ConfigTriplet.log" - -# CI_SPECIFIC - On CI machines, $HOME may not be set. In such a case, create a subfolder and set the variable to set. -# This is needed by CLI to function. -if [[ -z "$HOME" ]]; then - if [[ ! -d "$__ProjectDir/temp_home" ]]; then - mkdir temp_home - fi - HOME="$__ProjectDir"/temp_home - export HOME - echo "HOME not defined; setting it to $HOME" -fi - -# Specify path to be set for CMAKE_INSTALL_PREFIX. -# This is where all built CoreClr libraries will copied to. -__CMakeBinDir="$__BinDir" -export __CMakeBinDir - -# Make the directories necessary for build if they don't exist -setup_dirs_local - -# Set up the directory for MSBuild debug logs. -MSBUILDDEBUGPATH="${__MsbuildDebugLogsDir}" -export MSBUILDDEBUGPATH - -# Check prereqs. -check_prereqs - -# Restore the package containing profile counts for profile-guided optimizations -restore_optdata - -# Generate event logging infrastructure sources -generate_event_logging - -# Build the coreclr (native) components. -__CMakeArgs="-DCLR_CMAKE_PGO_INSTRUMENT=$__PgoInstrument -DCLR_CMAKE_OPTDATA_PATH=$__PgoOptDataPath -DCLR_CMAKE_PGO_OPTIMIZE=$__PgoOptimize -DCLR_REPO_ROOT_DIR=\"$__RepoRootDir\" $__CMakeArgs" - -if [[ "$__SkipConfigure" == 0 && "$__CodeCoverage" == 1 ]]; then - __CMakeArgs="-DCLR_CMAKE_ENABLE_CODE_COVERAGE=1 $__CMakeArgs" -fi - -if [[ "$__SkipCoreCLR" == 1 ]]; then - echo "Skipping CoreCLR component build." -else - build_native "$__BuildArch" "$__ProjectRoot" "$__ProjectRoot" "$__IntermediatesDir" "CoreCLR component" -fi - -# Build cross-architecture components -if [[ "$__SkipCrossArchNative" != 1 ]]; then - if [[ "$__CrossBuild" == 1 ]]; then - build_cross_architecture_components - fi -fi - -# Build System.Private.CoreLib. - -build_CoreLib - -if [[ "$__CrossgenOnly" == 1 ]]; then - build_CoreLib_ni "$__BinDir/crossgen" -fi - -# Generate nuget packages -if [[ "$__SkipNuget" != 1 ]]; then - generate_NugetPackages -fi - - -# Build complete - -echo "Repo successfully built." -echo "Product binaries are available at $__BinDir" -echo "WARNING: This build script is deprecated and will be deleted soon. Use the root build script to build CoreCLR. If you want to build the CoreCLR runtime without using MSBuild, use the build-native.sh script." -echo "See https://github.com/dotnet/runtime/issues/32991 for more information." -exit 0 diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake index ce2bc382a99377..469e0090271094 100644 --- a/src/coreclr/clrdefinitions.cmake +++ b/src/coreclr/clrdefinitions.cmake @@ -105,7 +105,6 @@ endif(CLR_CMAKE_TARGET_WIN32) add_definitions(-DFEATURE_BASICFREEZE) add_definitions(-DFEATURE_CORECLR) add_definitions(-DFEATURE_CORESYSTEM) -add_definitions(-DFEATURE_CORRUPTING_EXCEPTIONS) if(FEATURE_DBGIPC) add_definitions(-DFEATURE_DBGIPC_TRANSPORT_DI) add_definitions(-DFEATURE_DBGIPC_TRANSPORT_VM) @@ -196,6 +195,7 @@ add_compile_definitions($<$>>:F if (CLR_CMAKE_TARGET_ARCH_AMD64) add_compile_definitions($<$>>:FEATURE_ON_STACK_REPLACEMENT>) endif (CLR_CMAKE_TARGET_ARCH_AMD64) +add_compile_definitions($<$>>:FEATURE_PGO>) if (CLR_CMAKE_TARGET_WIN32) add_definitions(-DFEATURE_TYPEEQUIVALENCE) endif(CLR_CMAKE_TARGET_WIN32) diff --git a/src/coreclr/crosscomponents.cmake b/src/coreclr/crosscomponents.cmake index 30d53d585dff58..f8ea417471ca6e 100644 --- a/src/coreclr/crosscomponents.cmake +++ b/src/coreclr/crosscomponents.cmake @@ -14,10 +14,6 @@ endif() if(NOT CLR_CMAKE_HOST_LINUX AND NOT FEATURE_CROSSBITNESS) list (APPEND CLR_CROSS_COMPONENTS_LIST mscordaccore + mscordbi ) - if (CLR_CMAKE_HOST_OS STREQUAL CLR_CMAKE_TARGET_OS) - list (APPEND CLR_CROSS_COMPONENTS_LIST - mscordbi - ) - endif (CLR_CMAKE_HOST_OS STREQUAL CLR_CMAKE_TARGET_OS) endif() diff --git a/src/coreclr/crossgen-corelib.sh b/src/coreclr/crossgen-corelib.sh index 73811315afefa0..8350da0f636b74 100755 --- a/src/coreclr/crossgen-corelib.sh +++ b/src/coreclr/crossgen-corelib.sh @@ -103,6 +103,7 @@ __LogsDir="$__RootBinDir/log/$__BuildType" # Set the remaining variables based upon the determined build configuration __BinDir="$__RootBinDir/bin/coreclr/$__TargetOS.$__BuildArch.$__BuildType" +__IntermediatesDir="$__RootBinDir/obj/coreclr/$__TargetOS.$__BuildArch.$__BuildType" __CrossComponentBinDir="$__BinDir" __CrossArch="$__HostArch" diff --git a/src/coreclr/dir.common.props b/src/coreclr/dir.common.props index e4d212b2aee164..2ff54f14de24a2 100644 --- a/src/coreclr/dir.common.props +++ b/src/coreclr/dir.common.props @@ -55,10 +55,11 @@ true true true + true true true - true + true $(__DistroRid) diff --git a/src/coreclr/run-cppcheck.sh b/src/coreclr/run-cppcheck.sh index c505fd184dedc3..46e51e1e7471fc 100755 --- a/src/coreclr/run-cppcheck.sh +++ b/src/coreclr/run-cppcheck.sh @@ -17,13 +17,13 @@ usage() check_dependencies() { # Check presence of cppcheck on the path - if [ "$RunCppCheck" == true ] + if [ "$RunCppCheck" = "true" ] then hash cppcheck 2>/dev/null || { echo >&2 "Please install cppcheck before running this script"; exit 1; } fi - + # Check presence of sloccount on the path - if [ "$RunSlocCount" == true ] + if [ "$RunSlocCount" = "true" ] then hash sloccount 2>/dev/null || { echo >&2 "Please install sloccount before running this script"; exit 1; } fi @@ -39,9 +39,10 @@ SloccountOutput="sloccount.sc" # Get the number of processors available to the scheduler # Other techniques such as `nproc` only get the number of # processors available to a single process. -if [ `uname` = "FreeBSD" ]; then -NumProc=`sysctl hw.ncpu | awk '{ print $2+1 }'` -elif [ `uname` = "NetBSD" ]; then +platform="$(uname)" +if [ "$platform" = "FreeBSD" ]; then +NumProc=$(sysctl hw.ncpu | awk '{ print $2+1 }') +elif [ "$platform" = "NetBSD" || "$platform" = "SunOS" ]; then NumProc=$(($(getconf NPROCESSORS_ONLN)+1)) else NumProc=$(($(getconf _NPROCESSORS_ONLN)+1)) @@ -80,19 +81,19 @@ do esac done -if [ "$FilesFromArgs" != "" ]; +if [ -n "$FilesFromArgs" ]; then Files=$FilesFromArgs fi -if [ "$CppCheckOutput" == "" ]; +if [ -z "$CppCheckOutput" ]; then echo "Expected: file for cppcheck output" usage exit 1 fi -if [ "$SloccountOutput" == "" ]; +if [ -z "$SloccountOutput" ]; then echo "Expected: file for sloccount output" usage @@ -101,14 +102,14 @@ fi check_dependencies -if [ "$RunCppCheck" == true ] +if [ "$RunCppCheck" = "true" ] then echo "Running cppcheck for files: $Files" cppcheck --enable=all -j $NumProc --xml --xml-version=2 --force $Files 2> $CppCheckOutput CppCheckOutputs="$CppCheckOutput (cppcheck)" fi -if [ "$RunSlocCount" == true ] +if [ "$RunSlocCount" = "true" ] then echo "Running sloccount for files: $Files" sloccount --wide --details $Files > $SloccountOutput diff --git a/src/coreclr/runtime.proj b/src/coreclr/runtime.proj index 02c4c5e205205d..a78af666926bf2 100644 --- a/src/coreclr/runtime.proj +++ b/src/coreclr/runtime.proj @@ -12,9 +12,14 @@ <_CoreClrBuildArg Condition="'$(CrossBuild)' == 'true'" Include="-cross" /> <_CoreClrBuildArg Condition="!$([MSBuild]::IsOsPlatform(Windows))" Include="-os $(TargetOS)" /> - <_CoreClrBuildArg Condition="$([MSBuild]::IsOsPlatform(Windows)) and ('$(TargetArchitecture)' == 'x86' or '$(TargetArchitecture)' == 'x64') and '$(Configuration)' == 'Release'" Include="-enforcepgo" /> + <_CoreClrBuildArg Condition="$([MSBuild]::IsOsPlatform(Windows)) and + ('$(TargetArchitecture)' == 'x86' or '$(TargetArchitecture)' == 'x64') and + '$(Configuration)' == 'Release' and + '$(NoPgoOptimize)' != 'true'" + Include="-enforcepgo" /> <_CoreClrBuildArg Condition="$([MSBuild]::IsOsPlatform(Windows)) and '$(CrossDac)' != ''" Include="-$(CrossDac)dac" /> <_CoreClrBuildArg Condition="'$(OfficialBuildId)' != ''" Include="/p:OfficialBuildId=$(OfficialBuildId)" /> + <_CoreClrBuildArg Condition="'$(NoPgoOptimize)' == 'true'" Include="-nopgooptimize" /> diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py index 1c7f2f22a76f42..8bef741ce7234e 100755 --- a/src/coreclr/scripts/superpmi.py +++ b/src/coreclr/scripts/superpmi.py @@ -533,7 +533,7 @@ def collect(self): if not os.path.isdir(final_mch_dir): os.makedirs(final_mch_dir) else: - default_coreclr_bin_mch_location = os.path.join(coreclr_args.spmi_location, "mch", "{}.{}.{}".format(coreclr_args.host_os, coreclr_args.arch, coreclr_args.build_type)) + default_coreclr_bin_mch_location = os.path.join(self.coreclr_args.spmi_location, "mch", "{}.{}.{}".format(self.coreclr_args.host_os, self.coreclr_args.arch, self.coreclr_args.build_type)) if not os.path.isdir(default_coreclr_bin_mch_location): os.makedirs(default_coreclr_bin_mch_location) self.final_mch_file = os.path.abspath(os.path.join(default_coreclr_bin_mch_location, "{}.{}.{}.mch".format(self.coreclr_args.host_os, self.coreclr_args.arch, self.coreclr_args.build_type))) @@ -588,7 +588,9 @@ def __collect_mc_files__(self): env_copy["SuperPMIShimLogPath"] = self.temp_location env_copy["SuperPMIShimPath"] = self.jit_path env_copy["COMPlus_AltJit"] = "*" + env_copy["COMPlus_AltJitNgen"] = "*" env_copy["COMPlus_AltJitName"] = self.collection_shim_name + env_copy["COMPlus_EnableExtraSuperPmiQueries"] = "1" if self.coreclr_args.use_zapdisable: env_copy["COMPlus_ZapDisable"] = "1" @@ -599,6 +601,7 @@ def __collect_mc_files__(self): print_platform_specific_environment_vars(self.coreclr_args, "SuperPMIShimPath", self.jit_path) print_platform_specific_environment_vars(self.coreclr_args, "COMPlus_AltJit", "*") print_platform_specific_environment_vars(self.coreclr_args, "COMPlus_AltJitName", self.collection_shim_name) + print_platform_specific_environment_vars(self.coreclr_args, "COMPlus_AltJitNgen", "*") print("") if self.collection_command != None: diff --git a/src/coreclr/src/.nuget/Directory.Build.props b/src/coreclr/src/.nuget/Directory.Build.props index e321b384626e0e..2fd932c03b84ee 100644 --- a/src/coreclr/src/.nuget/Directory.Build.props +++ b/src/coreclr/src/.nuget/Directory.Build.props @@ -28,7 +28,7 @@ $(OSRid) - Windows_NT;OSX;Android;Linux;FreeBSD + Windows_NT;OSX;Android;Linux;FreeBSD;NetBSD;SunOS ;$(SupportedPackageOSGroups); + netbsd-$(TargetArchitecture) + + + + + sunos-$(TargetArchitecture) + + sunos-$(TargetArchitecture) + + android.21-$(TargetArchitecture) @@ -159,6 +173,12 @@ + + + + + + x86 diff --git a/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.Common.targets b/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.Common.targets index 0b60d9b5f46bf2..452353b37096b2 100644 --- a/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.Common.targets +++ b/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.Common.targets @@ -9,7 +9,7 @@ Copyright (c) .NET Foundation. All rights reserved. - + diff --git a/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.targets b/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.targets index 299511fa2a8be4..f2c0a3fb649733 100644 --- a/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.targets +++ b/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.targets @@ -7,7 +7,7 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and created a backup copy. Incorrect changes to this file will make it impossible to load or build your projects from the command-line or the IDE. -Copyright (c) .NET Foundation. All rights reserved. +Copyright (c) .NET Foundation. All rights reserved. *********************************************************************************************** --> @@ -24,13 +24,15 @@ Copyright (c) .NET Foundation. All rights reserved. <_OSPlatform Condition="$([MSBuild]::IsOSPlatform('linux'))">linux <_OSPlatform Condition="$([MSBuild]::IsOSPlatform('osx'))">osx <_OSPlatform Condition="$([MSBuild]::IsOSPlatform('freebsd'))">freebsd + <_OSPlatform Condition="$([MSBuild]::IsOSPlatform('netbsd'))">netbsd + <_OSPlatform Condition="$([MSBuild]::IsOSPlatform('sunos'))">sunos <_OSArchitecture>$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture) $(_OSPlatform)-$(_OSArchitecture.ToLower()) 5.0.0 runtime.$(MicrosoftNetCoreIlasmPackageRuntimeId).microsoft.netcore.ilasm runtime.$(MicrosoftNetCoreIlasmPackageRuntimeId).microsoft.netcore.ildasm - + <_IlasmDir Condition="'$(ILAsmToolPath)' != ''">$([MSBuild]::NormalizeDirectory($(ILAsmToolPath))) @@ -68,8 +70,8 @@ Copyright (c) .NET Foundation. All rights reserved. - @@ -122,7 +124,7 @@ Copyright (c) .NET Foundation. All rights reserved. <_KeyFileArgument Condition="'$(KeyOriginatorFile)' != ''">-KEY="$(KeyOriginatorFile)" - <_IlasmSwitches>-QUIET -NOLOGO + <_IlasmSwitches>-QUIET -NOLOGO <_IlasmSwitches Condition="'$(FoldIdenticalMethods)' == 'True'">$(_IlasmSwitches) -FOLD <_IlasmSwitches Condition="'$(SizeOfStackReserve)' != ''">$(_IlasmSwitches) -STACK=$(SizeOfStackReserve) <_IlasmSwitches Condition="'$(DebugType)' == 'Full'">$(_IlasmSwitches) -DEBUG diff --git a/src/coreclr/src/.nuget/optdata/optdata.csproj b/src/coreclr/src/.nuget/optdata/optdata.csproj index d19c3125fe5d3e..14ec28443321b3 100644 --- a/src/coreclr/src/.nuget/optdata/optdata.csproj +++ b/src/coreclr/src/.nuget/optdata/optdata.csproj @@ -6,6 +6,7 @@ True True win7-x64;win7-x86;linux-x64 + true <_TargetOSArchLowercase>$(TargetOS.ToLower())-$(TargetArchitecture.ToLower()) diff --git a/src/coreclr/src/System.Private.CoreLib/CreateRuntimeRootILLinkDescriptorFile.targets b/src/coreclr/src/System.Private.CoreLib/CreateRuntimeRootILLinkDescriptorFile.targets index d06367c480c6f3..a40473eb98ac31 100644 --- a/src/coreclr/src/System.Private.CoreLib/CreateRuntimeRootILLinkDescriptorFile.targets +++ b/src/coreclr/src/System.Private.CoreLib/CreateRuntimeRootILLinkDescriptorFile.targets @@ -11,7 +11,7 @@ <_CortypeFilePath Condition=" '$(_CortypeFilePath)' == '' ">$(MSBuildThisFileDirectory)..\inc\cortypeinfo.h <_RexcepFilePath Condition=" '$(_RexcepFilePath)' == '' ">$(MSBuildThisFileDirectory)..\vm\rexcep.h <_ILLinkTrimXmlFilePath Condition=" '$(_ILLinkTrimXmlFilePath)' == '' ">$(MSBuildThisFileDirectory)ILLinkTrim.xml - <_ILLinkTasksToolsDir>$(PkgILLink_Tasks)/tools + <_ILLinkTasksToolsDir>$(PkgMicrosoft_NET_ILLink_Tasks)/tools <_ILLinkTasksDir>$(_ILLinkTasksToolsDir)/$(NetFrameworkCurrent)/ <_ILLinkTasksDir Condition="'$(MSBuildRuntimeType)' == 'Core'">$(_ILLinkTasksToolsDir)/netcoreapp3.0/ diff --git a/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata b/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata index 141a5c2a73ce0d..e1c58c0c50381a 100644 --- a/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata +++ b/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata @@ -6,5 +6,5 @@ normaliz.dll!NormalizeString user32.dll!GetProcessWindowStation user32.dll!GetUserObjectInformationW - + kernel32.dll!GetGeoInfo \ No newline at end of file diff --git a/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj index e1d9a09182ef60..323d68b052b19e 100644 --- a/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -149,7 +149,6 @@ - @@ -357,12 +356,8 @@ - - Common\Interop\Windows\Interop.BOOL.cs - - @@ -372,7 +367,6 @@ Common\Interop\Windows\OleAut32\Interop.VariantClear.cs - diff --git a/src/coreclr/src/System.Private.CoreLib/Tools/GenUnicodeProp/GenUnicodeProp.csproj b/src/coreclr/src/System.Private.CoreLib/Tools/GenUnicodeProp/GenUnicodeProp.csproj index c40c22dbb8168d..73e115381ce756 100644 --- a/src/coreclr/src/System.Private.CoreLib/Tools/GenUnicodeProp/GenUnicodeProp.csproj +++ b/src/coreclr/src/System.Private.CoreLib/Tools/GenUnicodeProp/GenUnicodeProp.csproj @@ -7,7 +7,7 @@ - + @@ -43,7 +43,6 @@ - diff --git a/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs b/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs index 8f7d8ecd550be9..ffecc9b0d493b0 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs @@ -124,7 +124,7 @@ public static object GetClassFactoryForType(ComActivationContext cxt) if (!Path.IsPathRooted(cxt.AssemblyPath)) { - throw new ArgumentException(); + throw new ArgumentException(null, nameof(cxt)); } Type classType = FindClassType(cxt.ClassId, cxt.AssemblyPath, cxt.AssemblyName, cxt.TypeName); @@ -156,7 +156,7 @@ public static void ClassRegistrationScenarioForType(ComActivationContext cxt, bo if (!Path.IsPathRooted(cxt.AssemblyPath)) { - throw new ArgumentException(); + throw new ArgumentException(null, nameof(cxt)); } Type classType = FindClassType(cxt.ClassId, cxt.AssemblyPath, cxt.AssemblyName, cxt.TypeName); @@ -231,7 +231,7 @@ public static void ClassRegistrationScenarioForType(ComActivationContext cxt, bo /// /// Pointer to a instance [CLSCompliant(false)] - [NativeCallable] + [UnmanagedCallersOnly] public static unsafe int GetClassFactoryForTypeInternal(ComActivationContextInternal* pCxtInt) { ref ComActivationContextInternal cxtInt = ref *pCxtInt; @@ -268,7 +268,7 @@ public static unsafe int GetClassFactoryForTypeInternal(ComActivationContextInte /// /// Pointer to a instance [CLSCompliant(false)] - [NativeCallable] + [UnmanagedCallersOnly] public static unsafe int RegisterClassForTypeInternal(ComActivationContextInternal* pCxtInt) { ref ComActivationContextInternal cxtInt = ref *pCxtInt; @@ -288,7 +288,7 @@ public static unsafe int RegisterClassForTypeInternal(ComActivationContextIntern if (cxtInt.InterfaceId != Guid.Empty || cxtInt.ClassFactoryDest != IntPtr.Zero) { - throw new ArgumentException(); + throw new ArgumentException(null, nameof(pCxtInt)); } try @@ -308,7 +308,7 @@ public static unsafe int RegisterClassForTypeInternal(ComActivationContextIntern /// Internal entry point for unregistering a managed COM server API from native code /// [CLSCompliant(false)] - [NativeCallable] + [UnmanagedCallersOnly] public static unsafe int UnregisterClassForTypeInternal(ComActivationContextInternal* pCxtInt) { ref ComActivationContextInternal cxtInt = ref *pCxtInt; @@ -328,7 +328,7 @@ public static unsafe int UnregisterClassForTypeInternal(ComActivationContextInte if (cxtInt.InterfaceId != Guid.Empty || cxtInt.ClassFactoryDest != IntPtr.Zero) { - throw new ArgumentException(); + throw new ArgumentException(null, nameof(pCxtInt)); } try diff --git a/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComponentActivator.cs b/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComponentActivator.cs index dd8feba56e8262..c571fcf2bf26e4 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComponentActivator.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComponentActivator.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Reflection; using System.Runtime.InteropServices; @@ -47,7 +48,8 @@ private static string MarshalToString(IntPtr arg, string argName) /// Assembly qualified delegate type name /// Extensibility parameter (currently unused) /// Pointer where to store the function pointer result - public static int LoadAssemblyAndGetFunctionPointer(IntPtr assemblyPathNative, + [UnmanagedCallersOnly] + public static unsafe int LoadAssemblyAndGetFunctionPointer(IntPtr assemblyPathNative, IntPtr typeNameNative, IntPtr methodNameNative, IntPtr delegateTypeNative, @@ -56,18 +58,36 @@ public static int LoadAssemblyAndGetFunctionPointer(IntPtr assemblyPathNative, { try { + // Load the assembly and create a resolver callback for types. string assemblyPath = MarshalToString(assemblyPathNative, nameof(assemblyPathNative)); + IsolatedComponentLoadContext alc = GetIsolatedComponentLoadContext(assemblyPath); + Func resolver = name => alc.LoadFromAssemblyName(name); + + // Get the requested type. string typeName = MarshalToString(typeNameNative, nameof(typeNameNative)); + Type type = Type.GetType(typeName, resolver, null, throwOnError: true)!; + + // Get the method name on the type. string methodName = MarshalToString(methodNameNative, nameof(methodNameNative)); - string delegateType; + // Determine the signature of the type. There are 3 possibilities: + // * No delegate type was supplied - use the default (i.e. ComponentEntryPoint). + // * A sentinel value was supplied - the function is marked UnmanagedCallersOnly. This means + // a function pointer can be returned without creating a delegate. + // * A delegate type was supplied - Load the type and create a delegate for that method. + Type? delegateType; if (delegateTypeNative == IntPtr.Zero) { - delegateType = typeof(ComponentEntryPoint).AssemblyQualifiedName!; + delegateType = typeof(ComponentEntryPoint); + } + else if (delegateTypeNative == (IntPtr)(-1)) + { + delegateType = null; } else { - delegateType = MarshalToString(delegateTypeNative, nameof(delegateTypeNative)); + string delegateTypeName = MarshalToString(delegateTypeNative, nameof(delegateTypeNative)); + delegateType = Type.GetType(delegateTypeName, resolver, null, throwOnError: true)!; } if (reserved != IntPtr.Zero) @@ -80,17 +100,35 @@ public static int LoadAssemblyAndGetFunctionPointer(IntPtr assemblyPathNative, throw new ArgumentNullException(nameof(functionHandle)); } - Delegate d = CreateDelegate(assemblyPath, typeName, methodName, delegateType); + IntPtr functionPtr; + if (delegateType == null) + { + // Match search semantics of the CreateDelegate() function below. + BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; + MethodInfo? methodInfo = type.GetMethod(methodName, bindingFlags); + if (methodInfo == null) + throw new MissingMethodException(typeName, methodName); - IntPtr functionPtr = Marshal.GetFunctionPointerForDelegate(d); + // Verify the function is properly marked. + if (null == methodInfo.GetCustomAttribute()) + throw new InvalidOperationException(SR.InvalidOperation_FunctionMissingUnmanagedCallersOnly); - lock (s_delegates) + functionPtr = methodInfo.MethodHandle.GetFunctionPointer(); + } + else { - // Keep a reference to the delegate to prevent it from being garbage collected - s_delegates[functionPtr] = d; + Delegate d = Delegate.CreateDelegate(delegateType, type, methodName)!; + + functionPtr = Marshal.GetFunctionPointerForDelegate(d); + + lock (s_delegates) + { + // Keep a reference to the delegate to prevent it from being garbage collected + s_delegates[functionPtr] = d; + } } - Marshal.WriteIntPtr(functionHandle, functionPtr); + *(IntPtr*)functionHandle = functionPtr; } catch (Exception e) { @@ -100,23 +138,6 @@ public static int LoadAssemblyAndGetFunctionPointer(IntPtr assemblyPathNative, return 0; } - private static Delegate CreateDelegate(string assemblyPath, string typeName, string methodName, string delegateTypeName) - { - // Throws - IsolatedComponentLoadContext alc = GetIsolatedComponentLoadContext(assemblyPath); - - Func resolver = name => alc.LoadFromAssemblyName(name); - - // Throws - Type type = Type.GetType(typeName, resolver, null, throwOnError: true)!; - - // Throws - Type delegateType = Type.GetType(delegateTypeName, resolver, null, throwOnError: true)!; - - // Throws - return Delegate.CreateDelegate(delegateType, type, methodName)!; - } - private static IsolatedComponentLoadContext GetIsolatedComponentLoadContext(string assemblyPath) { IsolatedComponentLoadContext? alc; diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/ArgIterator.cs b/src/coreclr/src/System.Private.CoreLib/src/System/ArgIterator.cs index d32d53ae753b6e..8c7039e557b457 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/ArgIterator.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/ArgIterator.cs @@ -85,7 +85,9 @@ public TypedReference GetNextArg(RuntimeTypeHandle rth) // malicious caller to increment the pointer to an arbitrary // location in memory and read the contents. if (ArgPtr == IntPtr.Zero) +#pragma warning disable CA2208 // Instantiate argument exceptions correctly, the argument not applicable throw new ArgumentNullException(); +#pragma warning restore CA2208 TypedReference result = default; // reference to TypedReference is banned, so have to pass result as pointer diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Array.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Array.CoreCLR.cs index 55ed9f70b082be..75f6aa40ce4d14 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Array.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Array.CoreCLR.cs @@ -9,13 +9,6 @@ using System.Reflection; using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System { // Note that we make a T[] (single-dimensional w/ zero as the lower bound) implement both diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs index 8c7bc784ad8961..5e1d8249e3ddda 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs @@ -7,15 +7,6 @@ using System.Runtime.InteropServices; using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -using nint = System.UInt64; -#else -using nuint = System.UInt32; -using nint = System.UInt32; -#endif - namespace System { public partial class Buffer diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.CoreCLR.cs index bd1ad774bea18b..7d3ab6c6af68d8 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.CoreCLR.cs @@ -33,7 +33,7 @@ private static unsafe extern ulong Enable( internal static extern IntPtr CreateProvider(string providerName, Interop.Advapi32.EtwEnableCallback callbackFunc); [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] - internal static extern unsafe IntPtr DefineEvent(IntPtr provHandle, uint eventID, long keywords, uint eventVersion, uint level, void* pMetadata, uint metadataLength); + internal static extern unsafe IntPtr DefineEvent(IntPtr provHandle, uint eventID, long keywords, uint eventVersion, uint level, void *pMetadata, uint metadataLength); [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] internal static extern IntPtr GetProvider(string providerName); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/StackFrameHelper.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/StackFrameHelper.cs index 20a0c57492d8aa..41b1dd72e01023 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/StackFrameHelper.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/StackFrameHelper.cs @@ -131,7 +131,7 @@ internal void InitializeSourceInfo(int iSkip, bool fNeedFileInfo, Exception? exc object? target = Activator.CreateInstance(symbolsType); // Create an instance delegate for the GetSourceLineInfo method - GetSourceLineInfoDelegate getSourceLineInfo = (GetSourceLineInfoDelegate)symbolsMethodInfo.CreateDelegate(typeof(GetSourceLineInfoDelegate), target); + GetSourceLineInfoDelegate getSourceLineInfo = symbolsMethodInfo.CreateDelegate(target); // We could race with another thread. It doesn't matter if we win or lose, the losing instance will be GC'ed and all threads including this one will // use the winning instance diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/GC.cs b/src/coreclr/src/System.Private.CoreLib/src/System/GC.cs index fc8a9650f63b7e..a44047cc4d8e95 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/GC.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/GC.cs @@ -135,7 +135,7 @@ public static void AddMemoryPressure(long bytesAllocated) if ((4 == IntPtr.Size) && (bytesAllocated > int.MaxValue)) { - throw new ArgumentOutOfRangeException("pressure", + throw new ArgumentOutOfRangeException(nameof(bytesAllocated), SR.ArgumentOutOfRange_MustBeNonNegInt32); } @@ -353,7 +353,7 @@ public static long GetTotalMemory(bool forceFullCollection) } [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] - private static extern IntPtr _RegisterFrozenSegment(IntPtr sectionAddress, IntPtr sectionSize); + private static extern IntPtr _RegisterFrozenSegment(IntPtr sectionAddress, nint sectionSize); [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] private static extern void _UnregisterFrozenSegment(IntPtr segmentHandle); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs deleted file mode 100644 index dccd60c78ce0d5..00000000000000 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace System.Globalization -{ - internal static partial class GlobalizationMode - { - private static bool GetGlobalizationInvariantMode() - { - bool invariantEnabled = GetInvariantSwitchValue(); - if (!invariantEnabled) - { - if (Interop.Globalization.LoadICU() == 0) - { - string message = "Couldn't find a valid ICU package installed on the system. " + - "Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support."; - Environment.FailFast(message); - } - } - return invariantEnabled; - } - } -} diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Windows.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Windows.cs deleted file mode 100644 index f5def09ab96ab4..00000000000000 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Windows.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace System.Globalization -{ - internal static partial class GlobalizationMode - { - private static bool GetGlobalizationInvariantMode() - { - return GetInvariantSwitchValue(); - } - } -} diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.cs deleted file mode 100644 index b216677e1a711b..00000000000000 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace System.Globalization -{ - internal static partial class GlobalizationMode - { - internal static bool Invariant { get; } = GetGlobalizationInvariantMode(); - - // GetInvariantSwitchValue calls CLRConfig first to detect if the switch is defined in the config file. - // if the switch is defined we just use the value of this switch. otherwise, we'll try to get the switch - // value from the environment variable if it is defined. - internal static bool GetInvariantSwitchValue() - { - bool ret = CLRConfig.GetBoolValue("System.Globalization.Invariant", out bool exist); - if (!exist) - { - // Linux doesn't support environment variable names include dots - string? switchValue = Environment.GetEnvironmentVariable("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT"); - if (switchValue != null) - { - ret = bool.IsTrueStringIgnoreCase(switchValue) || switchValue.Equals("1"); - } - } - - return ret; - } - } -} diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs index 2878b89a49cc41..b426926a95e3f8 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/IO/FileLoadException.CoreCLR.cs @@ -29,7 +29,7 @@ internal static string FormatFileLoadExceptionMessage(string? fileName, int hRes else GetMessageForHR(hResult, new StringHandleOnStack(ref message)); - return string.Format(format, fileName, message); + return string.Format(format!, fileName, message); } [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Object.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Object.CoreCLR.cs index 3c7cb5c23982a2..a65358449ee8ca 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Object.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Object.CoreCLR.cs @@ -4,13 +4,6 @@ using System.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System { public partial class Object diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs index c227155ef46645..8ef9d01d3ee707 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Assembly.CoreCLR.cs @@ -62,7 +62,7 @@ internal static RuntimeAssembly GetExecutingAssembly(ref StackCrawlMark stackMar { RuntimeAssembly? retAssembly = null; GetExecutingAssemblyNative(new StackCrawlMarkHandle(ref stackMark), ObjectHandleOnStack.Create(ref retAssembly)); - return retAssembly; + return retAssembly!; } // Get the assembly that the current code is running from. diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs index 2e0acab5590163..1407f8705246e7 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs @@ -21,6 +21,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.SymbolStore; using System.Globalization; using System.IO; @@ -125,7 +126,7 @@ public sealed class AssemblyBuilder : Assembly // This is only valid in the "external" AssemblyBuilder internal AssemblyBuilderData _assemblyData; private readonly InternalAssemblyBuilder _internalAssemblyBuilder; - private ModuleBuilder _manifestModuleBuilder = null!; + private ModuleBuilder _manifestModuleBuilder; // Set to true if the manifest module was returned by code:DefineDynamicModule to the user private bool _isManifestModuleUsedAsDefinedModule; @@ -191,7 +192,7 @@ internal AssemblyBuilder(AssemblyName name, new StackCrawlMarkHandle(ref stackMark), (int)access, ObjectHandleOnStack.Create(ref retAssembly)); - _internalAssemblyBuilder = (InternalAssemblyBuilder)retAssembly; + _internalAssemblyBuilder = (InternalAssemblyBuilder)retAssembly!; _assemblyData = new AssemblyBuilderData(_internalAssemblyBuilder, access); @@ -208,6 +209,7 @@ internal AssemblyBuilder(AssemblyName name, } } + [MemberNotNull(nameof(_manifestModuleBuilder))] private void InitManifestModule() { InternalModuleBuilder modBuilder = (InternalModuleBuilder)GetInMemoryAssemblyModule(GetNativeHandle()); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.cs index 80cb55b796c501..fb6b4c623eab93 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.cs @@ -19,7 +19,7 @@ internal ConstructorBuilder(string name, MethodAttributes attributes, CallingCon m_methodBuilder = new MethodBuilder(name, attributes, callingConvention, null, null, null, parameterTypes, requiredCustomModifiers, optionalCustomModifiers, mod, type); - type.m_listMethods.Add(m_methodBuilder); + type.m_listMethods!.Add(m_methodBuilder); m_methodBuilder.GetMethodSignature().InternalGetSignature(out _); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs index 506c98b28e5e2c..d1e89aaf0c3bf3 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs @@ -14,91 +14,42 @@ ===========================================================*/ using System.Buffers.Binary; +using System.Diagnostics; using System.IO; using System.Text; -using System.Diagnostics; namespace System.Reflection.Emit { public class CustomAttributeBuilder { + internal ConstructorInfo m_con; + private object?[] m_constructorArgs; + private byte[] m_blob; + // public constructor to form the custom attribute with constructor and constructor // parameters. - public CustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs) + public CustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs) : + this(con, constructorArgs, Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty()) { - InitCustomAttributeBuilder(con, constructorArgs, - Array.Empty(), Array.Empty(), - Array.Empty(), Array.Empty()); } // public constructor to form the custom attribute with constructor, constructor // parameters and named properties. - public CustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs, - PropertyInfo[] namedProperties, object?[] propertyValues) + public CustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs, PropertyInfo[] namedProperties, object?[] propertyValues) : + this(con, constructorArgs, namedProperties, propertyValues, Array.Empty(), Array.Empty()) { - InitCustomAttributeBuilder(con, constructorArgs, namedProperties, - propertyValues, Array.Empty(), Array.Empty()); } // public constructor to form the custom attribute with constructor and constructor // parameters. - public CustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs, - FieldInfo[] namedFields, object?[] fieldValues) + public CustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs, FieldInfo[] namedFields, object?[] fieldValues) : + this(con, constructorArgs, Array.Empty(), Array.Empty(), namedFields, fieldValues) { - InitCustomAttributeBuilder(con, constructorArgs, Array.Empty(), - Array.Empty(), namedFields, fieldValues); } // public constructor to form the custom attribute with constructor and constructor // parameters. - public CustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs, - PropertyInfo[] namedProperties, object?[] propertyValues, - FieldInfo[] namedFields, object?[] fieldValues) - { - InitCustomAttributeBuilder(con, constructorArgs, namedProperties, - propertyValues, namedFields, fieldValues); - } - - // Check that a type is suitable for use in a custom attribute. - private bool ValidateType(Type t) - { - if (t.IsPrimitive) - { - return t != typeof(IntPtr) && t != typeof(UIntPtr); - } - if (t == typeof(string) || t == typeof(Type)) - { - return true; - } - if (t.IsEnum) - { - switch (Type.GetTypeCode(Enum.GetUnderlyingType(t))) - { - case TypeCode.SByte: - case TypeCode.Byte: - case TypeCode.Int16: - case TypeCode.UInt16: - case TypeCode.Int32: - case TypeCode.UInt32: - case TypeCode.Int64: - case TypeCode.UInt64: - return true; - default: - return false; - } - } - if (t.IsArray) - { - if (t.GetArrayRank() != 1) - return false; - return ValidateType(t.GetElementType()!); - } - return t == typeof(object); - } - - internal void InitCustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs, - PropertyInfo[] namedProperties, object?[] propertyValues, - FieldInfo[] namedFields, object?[] fieldValues) + public CustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs, PropertyInfo[] namedProperties, object?[] propertyValues, FieldInfo[] namedFields, object?[] fieldValues) { if (con == null) throw new ArgumentNullException(nameof(con)); @@ -289,6 +240,43 @@ internal void InitCustomAttributeBuilder(ConstructorInfo con, object?[] construc m_blob = ((MemoryStream)writer.BaseStream).ToArray(); } + // Check that a type is suitable for use in a custom attribute. + private bool ValidateType(Type t) + { + if (t.IsPrimitive) + { + return t != typeof(IntPtr) && t != typeof(UIntPtr); + } + if (t == typeof(string) || t == typeof(Type)) + { + return true; + } + if (t.IsEnum) + { + switch (Type.GetTypeCode(Enum.GetUnderlyingType(t))) + { + case TypeCode.SByte: + case TypeCode.Byte: + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Int64: + case TypeCode.UInt64: + return true; + default: + return false; + } + } + if (t.IsArray) + { + if (t.GetArrayRank() != 1) + return false; + return ValidateType(t.GetElementType()!); + } + return t == typeof(object); + } + private static void VerifyTypeAndPassedObjectType(Type type, Type passedType, string paramName) { if (type != typeof(object) && Type.GetTypeCode(passedType) != Type.GetTypeCode(type)) @@ -549,9 +537,5 @@ internal void CreateCustomAttribute(ModuleBuilder mod, int tkOwner, int tkAttrib TypeBuilder.DefineCustomAttribute(mod, tkOwner, tkAttrib, m_blob, toDisk, typeof(System.Diagnostics.DebuggableAttribute) == m_con.DeclaringType); } - - internal ConstructorInfo m_con = null!; - internal object?[] m_constructorArgs = null!; - internal byte[] m_blob = null!; } } diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs index a1a85b47d0bf3b..d8e330dd7f98b2 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs @@ -345,7 +345,7 @@ public override void BeginExceptFilterBlock() if (CurrExcStackCount == 0) throw new NotSupportedException(SR.Argument_NotInExceptionBlock); - __ExceptionInfo current = CurrExcStack[CurrExcStackCount - 1]; + __ExceptionInfo current = CurrExcStack![CurrExcStackCount - 1]; Label endLabel = current.GetEndLabel(); Emit(OpCodes.Leave, endLabel); @@ -359,7 +359,7 @@ public override void BeginCatchBlock(Type exceptionType) if (CurrExcStackCount == 0) throw new NotSupportedException(SR.Argument_NotInExceptionBlock); - __ExceptionInfo current = CurrExcStack[CurrExcStackCount - 1]; + __ExceptionInfo current = CurrExcStack![CurrExcStackCount - 1]; RuntimeType? rtType = exceptionType as RuntimeType; @@ -558,7 +558,7 @@ private int GetTokenForSig(byte[] sig) internal class DynamicResolver : Resolver { #region Private Data Members - private __ExceptionInfo[] m_exceptions = null!; + private __ExceptionInfo[]? m_exceptions; private byte[]? m_exceptionHeader; private DynamicMethod m_method; private byte[] m_code; @@ -571,7 +571,7 @@ internal class DynamicResolver : Resolver internal DynamicResolver(DynamicILGenerator ilGenerator) { m_stackSize = ilGenerator.GetMaxStackSize(); - m_exceptions = ilGenerator.GetExceptions()!; + m_exceptions = ilGenerator.GetExceptions(); m_code = ilGenerator.BakeByteArray()!; m_localSignature = ilGenerator.m_localSignature.InternalGetSignatureArray(); m_scope = ilGenerator.m_scope; @@ -586,7 +586,6 @@ internal DynamicResolver(DynamicILInfo dynamicILInfo) m_code = dynamicILInfo.Code; m_localSignature = dynamicILInfo.LocalSignature; m_exceptionHeader = dynamicILInfo.Exceptions; - // m_exceptions = dynamicILInfo.Exceptions; m_scope = dynamicILInfo.DynamicScope; m_method = dynamicILInfo.DynamicMethod; @@ -740,6 +739,8 @@ internal override byte[] GetLocalsSignature() internal override unsafe void GetEHInfo(int excNumber, void* exc) { + Debug.Assert(m_exceptions != null); + CORINFO_EH_CLAUSE* exception = (CORINFO_EH_CLAUSE*)exc; for (int i = 0; i < m_exceptions.Length; i++) { @@ -819,11 +820,13 @@ internal override void ResolveToken(int token, out IntPtr typeHandle, out IntPtr { if (vaMeth.m_dynamicMethod == null) { - methodHandle = vaMeth.m_method.MethodHandle.Value; + methodHandle = vaMeth.m_method!.MethodHandle.Value; typeHandle = vaMeth.m_method.GetDeclaringTypeInternal().GetTypeHandleInternal().Value; } else + { methodHandle = vaMeth.m_dynamicMethod.GetMethodDescriptor().Value; + } return; } @@ -1098,8 +1101,8 @@ internal GenericFieldInfo(RuntimeFieldHandle fieldHandle, RuntimeTypeHandle cont internal sealed class VarArgMethod { - internal RuntimeMethodInfo m_method = null!; - internal DynamicMethod m_dynamicMethod = null!; + internal RuntimeMethodInfo? m_method; + internal DynamicMethod? m_dynamicMethod; internal SignatureHelper m_signature; internal VarArgMethod(DynamicMethod dm, SignatureHelper signature) diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs index 35a708a1f867d0..c8c5468801d72e 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Text; @@ -12,9 +13,9 @@ namespace System.Reflection.Emit { public sealed class DynamicMethod : MethodInfo { - private RuntimeType[] m_parameterTypes = null!; + private RuntimeType[] m_parameterTypes; internal IRuntimeMethodInfo? m_methodHandle; - private RuntimeType m_returnType = null!; + private RuntimeType m_returnType; private DynamicILGenerator? m_ilGenerator; private DynamicILInfo? m_DynamicILInfo; private bool m_fInitLocals; @@ -28,7 +29,7 @@ public sealed class DynamicMethod : MethodInfo // If we allowed use of RTDynamicMethod, the creator of the DynamicMethod would // not be able to bound access to the DynamicMethod. Hence, we need to ensure that // we do not allow direct use of RTDynamicMethod. - private RTDynamicMethod m_dynMethod = null!; + private RTDynamicMethod m_dynMethod; // needed to keep the object alive during jitting // assigned by the DynamicResolver ctor @@ -249,6 +250,9 @@ private static RuntimeModule GetDynamicMethodsModule() return s_anonymouslyHostedDynamicMethodsModule; } + [MemberNotNull(nameof(m_parameterTypes))] + [MemberNotNull(nameof(m_returnType))] + [MemberNotNull(nameof(m_dynMethod))] private void Init(string name, MethodAttributes attributes, CallingConventions callingConvention, diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/EnumBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/EnumBuilder.cs index 4f58098617fdb3..3b0e0350bf9df1 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/EnumBuilder.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/EnumBuilder.cs @@ -91,6 +91,8 @@ public FieldBuilder DefineLiteral(string literalName, object? literalValue) public override Type? BaseType => m_typeBuilder.BaseType; + public override bool IsByRefLike => false; + protected override ConstructorInfo? GetConstructorImpl(BindingFlags bindingAttr, Binder? binder, CallingConventions callConvention, Type[] types, ParameterModifier[]? modifiers) { diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs index 547d160a664262..d0f930e4c763ea 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs @@ -52,6 +52,8 @@ public override bool Equals(object? o) public override Module Module => m_type.Module; + public override bool IsByRefLike => false; + internal int MetadataTokenInternal => m_type.MetadataTokenInternal; #endregion diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.cs index 93c517fb23c5c7..354d470bb982a2 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ILGenerator.cs @@ -40,20 +40,20 @@ internal static T[] EnlargeArray(T[] incoming, int requiredSize) private int m_length; private byte[] m_ILStream; - private int[] m_labelList; + private int[]? m_labelList; private int m_labelCount; - private __FixupData[] m_fixupData; + private __FixupData[]? m_fixupData; private int m_fixupCount; - private int[] m_RelocFixupList; + private int[]? m_RelocFixupList; private int m_RelocFixupCount; private int m_exceptionCount; private int m_currExcStackCount; - private __ExceptionInfo[] m_exceptions; // This is the list of all of the exceptions in this ILStream. - private __ExceptionInfo[] m_currExcStack; // This is the stack of exceptions which we're currently in. + private __ExceptionInfo[]? m_exceptions; // This is the list of all of the exceptions in this ILStream. + private __ExceptionInfo[]? m_currExcStack; // This is the stack of exceptions which we're currently in. internal ScopeTree m_ScopeTree; // this variable tracks all debugging scope information internal LineNumberInfo m_LineNumberInfo; // this variable tracks all line number information @@ -69,7 +69,7 @@ internal static T[] EnlargeArray(T[] incoming, int requiredSize) internal int CurrExcStackCount => m_currExcStackCount; - internal __ExceptionInfo[] CurrExcStack => m_currExcStack; + internal __ExceptionInfo[]? CurrExcStack => m_currExcStack; #endregion @@ -87,29 +87,12 @@ internal ILGenerator(MethodInfo methodBuilder, int size) m_ILStream = new byte[Math.Max(size, DefaultSize)]; - m_length = 0; - - m_labelCount = 0; - m_fixupCount = 0; - m_labelList = null!; - - m_fixupData = null!; - - m_exceptions = null!; - m_exceptionCount = 0; - m_currExcStack = null!; - m_currExcStackCount = 0; - - m_RelocFixupList = null!; - m_RelocFixupCount = 0; - // initialize the scope tree m_ScopeTree = new ScopeTree(); m_LineNumberInfo = new LineNumberInfo(); m_methodBuilder = methodBuilder; // initialize local signature - m_localCount = 0; MethodBuilder? mb = m_methodBuilder as MethodBuilder; m_localSignature = SignatureHelper.GetLocalVarSigHelper(mb?.GetTypeBuilder().Module); } @@ -215,7 +198,7 @@ private SignatureHelper GetMemberRefSignature(CallingConventions call, Type? ret // replacing them with their proper values. for (int i = 0; i < m_fixupCount; i++) { - __FixupData fixupData = m_fixupData[i]; + __FixupData fixupData = m_fixupData![i]; int updateAddr = GetLabelPos(fixupData.m_fixupLabel) - (fixupData.m_fixupPos + fixupData.m_fixupInstSize); // Handle single byte instructions @@ -253,7 +236,7 @@ private SignatureHelper GetMemberRefSignature(CallingConventions call, Type? ret } var temp = new __ExceptionInfo[m_exceptionCount]; - Array.Copy(m_exceptions, temp, m_exceptionCount); + Array.Copy(m_exceptions!, temp, m_exceptionCount); SortExceptions(temp); return temp; } @@ -288,7 +271,7 @@ private int GetLabelPos(Label lbl) int index = lbl.GetLabelValue(); - if (index < 0 || index >= m_labelCount) + if (index < 0 || index >= m_labelCount || m_labelList is null) throw new ArgumentException(SR.Argument_BadLabel); if (m_labelList[index] < 0) @@ -355,7 +338,7 @@ private static void SortExceptions(__ExceptionInfo[] exceptions) } int[] narrowTokens = new int[m_RelocFixupCount]; - Array.Copy(m_RelocFixupList, narrowTokens, m_RelocFixupCount); + Array.Copy(m_RelocFixupList!, narrowTokens, m_RelocFixupCount); return narrowTokens; } #endregion @@ -396,7 +379,90 @@ public virtual void Emit(OpCode opcode, short arg) public virtual void Emit(OpCode opcode, int arg) { - // Puts opcode onto the stream of instructions followed by arg + // Special-case several opcodes that have shorter variants for common values. + if (opcode.Equals(OpCodes.Ldc_I4)) + { + if (arg >= -1 && arg <= 8) + { + opcode = arg switch + { + -1 => OpCodes.Ldc_I4_M1, + 0 => OpCodes.Ldc_I4_0, + 1 => OpCodes.Ldc_I4_1, + 2 => OpCodes.Ldc_I4_2, + 3 => OpCodes.Ldc_I4_3, + 4 => OpCodes.Ldc_I4_4, + 5 => OpCodes.Ldc_I4_5, + 6 => OpCodes.Ldc_I4_6, + 7 => OpCodes.Ldc_I4_7, + _ => OpCodes.Ldc_I4_8, + }; + Emit(opcode); + return; + } + + if (arg >= -128 && arg <= 127) + { + Emit(OpCodes.Ldc_I4_S, (sbyte)arg); + return; + } + } + else if (opcode.Equals(OpCodes.Ldarg)) + { + if ((uint)arg <= 3) + { + Emit(arg switch + { + 0 => OpCodes.Ldarg_0, + 1 => OpCodes.Ldarg_1, + 2 => OpCodes.Ldarg_2, + _ => OpCodes.Ldarg_3, + }); + return; + } + + if ((uint)arg <= byte.MaxValue) + { + Emit(OpCodes.Ldarg_S, (byte)arg); + return; + } + + if ((uint)arg <= ushort.MaxValue) // this will be true except on misuse of the opcode + { + Emit(OpCodes.Ldarg, (short)arg); + return; + } + } + else if (opcode.Equals(OpCodes.Ldarga)) + { + if ((uint)arg <= byte.MaxValue) + { + Emit(OpCodes.Ldarga_S, (byte)arg); + return; + } + + if ((uint)arg <= ushort.MaxValue) // this will be true except on misuse of the opcode + { + Emit(OpCodes.Ldarga, (short)arg); + return; + } + } + else if (opcode.Equals(OpCodes.Starg)) + { + if ((uint)arg <= byte.MaxValue) + { + Emit(OpCodes.Starg_S, (byte)arg); + return; + } + + if ((uint)arg <= ushort.MaxValue) // this will be true except on misuse of the opcode + { + Emit(OpCodes.Starg, (short)arg); + return; + } + } + + // For everything else, put the opcode followed by the arg onto the stream of instructions. EnsureCapacity(7); InternalEmit(opcode); PutInteger4(arg); @@ -881,7 +947,7 @@ public virtual void EndExceptionBlock() } // Pop the current exception block - __ExceptionInfo current = m_currExcStack[m_currExcStackCount - 1]; + __ExceptionInfo current = m_currExcStack![m_currExcStackCount - 1]; m_currExcStack[--m_currExcStackCount] = null!; Label endLabel = current.GetEndLabel(); @@ -905,7 +971,7 @@ public virtual void EndExceptionBlock() // Check if we've already set this label. // The only reason why we might have set this is if we have a finally block. - Label label = m_labelList[endLabel.GetLabelValue()] != -1 + Label label = m_labelList![endLabel.GetLabelValue()] != -1 ? current.m_finallyEndLabel : endLabel; @@ -921,7 +987,7 @@ public virtual void BeginExceptFilterBlock() if (m_currExcStackCount == 0) throw new NotSupportedException(SR.Argument_NotInExceptionBlock); - __ExceptionInfo current = m_currExcStack[m_currExcStackCount - 1]; + __ExceptionInfo current = m_currExcStack![m_currExcStackCount - 1]; Emit(OpCodes.Leave, current.GetEndLabel()); @@ -936,7 +1002,7 @@ public virtual void BeginCatchBlock(Type exceptionType) { throw new NotSupportedException(SR.Argument_NotInExceptionBlock); } - __ExceptionInfo current = m_currExcStack[m_currExcStackCount - 1]; + __ExceptionInfo current = m_currExcStack![m_currExcStackCount - 1]; if (current.GetCurrentState() == __ExceptionInfo.State_Filter) { @@ -967,7 +1033,7 @@ public virtual void BeginFaultBlock() { throw new NotSupportedException(SR.Argument_NotInExceptionBlock); } - __ExceptionInfo current = m_currExcStack[m_currExcStackCount - 1]; + __ExceptionInfo current = m_currExcStack![m_currExcStackCount - 1]; // emit the leave for the clause before this one. Emit(OpCodes.Leave, current.GetEndLabel()); @@ -981,7 +1047,7 @@ public virtual void BeginFinallyBlock() { throw new NotSupportedException(SR.Argument_NotInExceptionBlock); } - __ExceptionInfo current = m_currExcStack[m_currExcStackCount - 1]; + __ExceptionInfo current = m_currExcStack![m_currExcStackCount - 1]; int state = current.GetCurrentState(); Label endLabel = current.GetEndLabel(); int catchEndAddr = 0; @@ -1031,8 +1097,8 @@ public virtual void MarkLabel(Label loc) int labelIndex = loc.GetLabelValue(); - // This should never happen. - if (labelIndex < 0 || labelIndex >= m_labelList.Length) + // This should only happen if a label from another generator is used with this one. + if (m_labelList is null || labelIndex < 0 || labelIndex >= m_labelList.Length) { throw new ArgumentException(SR.Argument_InvalidLabel); } diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs index c5ae82adaeed65..e3c189f910beb3 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs @@ -620,7 +620,7 @@ public MethodToken GetToken() // We need to lock here to prevent a method from being "tokenized" twice. // We don't need to synchronize this with Type.DefineMethod because it only appends newly // constructed MethodBuilders to the end of m_listMethods - lock (m_containingType.m_listMethods) + lock (m_containingType.m_listMethods!) { if (m_tkMethod.Token != 0) { diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/SignatureHelper.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/SignatureHelper.cs index 0808335d3b8de7..a9db943c8ae588 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/SignatureHelper.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/SignatureHelper.cs @@ -2,10 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Text; using System.Buffers.Binary; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +using System.Text; namespace System.Reflection.Emit { @@ -185,7 +186,7 @@ internal static SignatureHelper GetTypeSigToken(Module module, Type type) #endregion #region Private Data Members - private byte[] m_signature = null!; + private byte[] m_signature; private int m_currSig; // index into m_signature buffer for next available byte private int m_sizeLoc; // index into m_signature buffer to put m_argCount (will be NO_SIZE_IN_SIG if no arg count is needed) private ModuleBuilder? m_module; @@ -225,6 +226,7 @@ private SignatureHelper(Module mod, Type type) AddOneArgTypeHelper(type); } + [MemberNotNull(nameof(m_signature))] private void Init(Module? mod) { m_signature = new byte[32]; @@ -238,11 +240,13 @@ private void Init(Module? mod) throw new ArgumentException(SR.NotSupported_MustBeModuleBuilder); } + [MemberNotNull(nameof(m_signature))] private void Init(Module? mod, MdSigCallingConvention callingConvention) { Init(mod, callingConvention, 0); } + [MemberNotNull(nameof(m_signature))] private void Init(Module? mod, MdSigCallingConvention callingConvention, int cGenericParam) { Init(mod); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs index f69d99e02a9ec8..65d61ca28adeec 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs @@ -396,15 +396,15 @@ internal static unsafe void SetConstantValue(ModuleBuilder module, int tk, Type #region Private Data Members private List? m_ca; private TypeToken m_tdType; - private readonly ModuleBuilder m_module = null!; + private readonly ModuleBuilder m_module; private readonly string? m_strName; private readonly string? m_strNameSpace; private string? m_strFullQualName; private Type? m_typeParent; - private List m_typeInterfaces = null!; + private List? m_typeInterfaces; private readonly TypeAttributes m_iAttr; private GenericParameterAttributes m_genParamAttributes; - internal List m_listMethods = null!; + internal List? m_listMethods; internal int m_lastTokenizedMethod; private int m_constructorCount; private readonly int m_iTypeSize; @@ -430,7 +430,7 @@ internal TypeBuilder(ModuleBuilder module) { m_tdType = new TypeToken((int)MetadataTokenType.TypeDef); m_isHiddenGlobalType = true; - m_module = (ModuleBuilder)module; + m_module = module; m_listMethods = new List(); // No token has been created so let's initialize it to -1 // The first time we call MethodBuilder.GetToken this will incremented. @@ -438,8 +438,13 @@ internal TypeBuilder(ModuleBuilder module) } // ctor for generic method parameter - internal TypeBuilder(string szName, int genParamPos, MethodBuilder declMeth) : this(szName, genParamPos) + internal TypeBuilder(string szName, int genParamPos, MethodBuilder declMeth) { + m_strName = szName; + m_genParamPos = genParamPos; + m_bIsGenParam = true; + m_typeInterfaces = new List(); + Debug.Assert(declMeth != null); m_declMeth = declMeth; m_DeclaringType = m_declMeth.GetTypeBuilder(); @@ -447,20 +452,16 @@ internal TypeBuilder(string szName, int genParamPos, MethodBuilder declMeth) : t } // ctor for generic type parameter - private TypeBuilder(string szName, int genParamPos, TypeBuilder declType) : this(szName, genParamPos) - { - Debug.Assert(declType != null); - m_DeclaringType = declType; - m_module = declType.GetModuleBuilder(); - } - - // only for delegating to by other ctors - private TypeBuilder(string szName, int genParamPos) + private TypeBuilder(string szName, int genParamPos, TypeBuilder declType) { m_strName = szName; m_genParamPos = genParamPos; m_bIsGenParam = true; m_typeInterfaces = new List(); + + Debug.Assert(declType != null); + m_DeclaringType = declType; + m_module = declType.GetModuleBuilder(); } internal TypeBuilder( @@ -721,6 +722,8 @@ public override string ToString() public override Module Module => GetModuleBuilder(); + public override bool IsByRefLike => false; + internal int MetadataTokenInternal => m_tdType.Token; #endregion @@ -1293,7 +1296,7 @@ private MethodBuilder DefineMethodNoLock(string name, MethodAttributes attribute } } - m_listMethods.Add(method); + m_listMethods!.Add(method); return method; } @@ -1379,7 +1382,7 @@ private MethodBuilder DefinePInvokeMethodHelper( // and our equals check won't work. _ = method.GetMethodSignature().InternalGetSignature(out _); - if (m_listMethods.Contains(method)) + if (m_listMethods!.Contains(method)) { throw new ArgumentException(SR.Argument_MethodRedefined); } @@ -1952,7 +1955,7 @@ internal void CheckContext(params Type?[]? types) } } - int size = m_listMethods.Count; + int size = m_listMethods!.Count; for (int i = 0; i < size; i++) { @@ -2030,12 +2033,12 @@ internal void CheckContext(params Type?[]? types) m_hasBeenCreated = true; // Terminate the process. - RuntimeType cls = null!; + RuntimeType? cls = null; TermCreateClass(new QCallModule(ref module), m_tdType.Token, ObjectHandleOnStack.Create(ref cls)); if (!m_isHiddenGlobalType) { - m_bakedRuntimeType = cls; + m_bakedRuntimeType = cls!; // if this type is a nested type, we need to invalidate the cached nested runtime type on the nesting type if (m_DeclaringType != null && m_DeclaringType.m_bakedRuntimeType != null) @@ -2103,7 +2106,7 @@ public void AddInterfaceImplementation(Type interfaceType) ModuleBuilder module = m_module; AddInterfaceImpl(new QCallModule(ref module), m_tdType.Token, tkInterface.Token); - m_typeInterfaces.Add(interfaceType); + m_typeInterfaces!.Add(interfaceType); } public TypeToken TypeToken diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/MethodBase.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/MethodBase.CoreCLR.cs index 3c467b743290dd..7ab2a594ab52fb 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/MethodBase.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/MethodBase.CoreCLR.cs @@ -69,7 +69,7 @@ internal object[] CheckArguments(object[] parameters, Binder? binder, // copy the arguments in a different array so we detach from any user changes object[] copyOfParameters = new object[parameters.Length]; - ParameterInfo[] p = null!; + ParameterInfo[]? p = null; for (int i = 0; i < parameters.Length; i++) { object arg = parameters[i]; diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs index 60379a0cf9182e..fd6eeb2bc23cbb 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeAssembly.cs @@ -327,7 +327,7 @@ internal static RuntimeAssembly InternalLoad(AssemblyName assemblyName, throwOnFileNotFound, ObjectHandleOnStack.Create(ref assemblyLoadContext), ObjectHandleOnStack.Create(ref retAssembly)); - return retAssembly; + return retAssembly!; } [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.cs index 77367461e462d3..133f825dbcc063 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.cs @@ -18,11 +18,11 @@ internal sealed class RuntimeConstructorInfo : ConstructorInfo, IRuntimeMethodIn private RuntimeTypeCache m_reflectedTypeCache; private string? m_toString; private ParameterInfo[]? m_parameters; // Created lazily when GetParameters() is called. -#pragma warning disable CA1823, 414 - private object _empty1 = null!; // These empties are used to ensure that RuntimeConstructorInfo and RuntimeMethodInfo are have a layout which is sufficiently similar - private object _empty2 = null!; - private object _empty3 = null!; -#pragma warning restore CA1823, 414 +#pragma warning disable CA1823, 414, 169 + private object? _empty1; // These empties are used to ensure that RuntimeConstructorInfo and RuntimeMethodInfo are have a layout which is sufficiently similar + private object? _empty2; + private object? _empty3; +#pragma warning restore CA1823, 414, 169 private IntPtr m_handle; private MethodAttributes m_methodAttributes; private BindingFlags m_bindingFlags; diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs index 0b24a02472d5ad..2a14dc6b9a188c 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeEventInfo.cs @@ -15,20 +15,16 @@ internal sealed unsafe class RuntimeEventInfo : EventInfo private EventAttributes m_flags; private string? m_name; private void* m_utf8name; - private RuntimeTypeCache m_reflectedTypeCache = null!; + private RuntimeTypeCache m_reflectedTypeCache; private RuntimeMethodInfo? m_addMethod; private RuntimeMethodInfo? m_removeMethod; private RuntimeMethodInfo? m_raiseMethod; private MethodInfo[]? m_otherMethod; - private RuntimeType m_declaringType = null!; + private RuntimeType m_declaringType; private BindingFlags m_bindingFlags; #endregion #region Constructor - internal RuntimeEventInfo() - { - // Used for dummy head node during population - } internal RuntimeEventInfo(int tkEvent, RuntimeType declaredType, RuntimeTypeCache reflectedTypeCache, out bool isPrivate) { Debug.Assert(declaredType != null); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs index 5eb9a5fd3cc209..fc64e1d9713a69 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeFieldInfo.cs @@ -11,15 +11,11 @@ internal abstract class RuntimeFieldInfo : FieldInfo { #region Private Data Members private BindingFlags m_bindingFlags; - protected RuntimeTypeCache m_reflectedTypeCache = null!; - protected RuntimeType m_declaringType = null!; + protected RuntimeTypeCache m_reflectedTypeCache; + protected RuntimeType m_declaringType; #endregion #region Constructor - protected RuntimeFieldInfo() - { - // Used for dummy head node during population - } protected RuntimeFieldInfo(RuntimeTypeCache reflectedTypeCache, RuntimeType declaringType, BindingFlags bindingFlags) { m_bindingFlags = bindingFlags; diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs index c7ad03319ddf3c..f8a0ff0b329cea 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeParameterInfo.cs @@ -113,7 +113,7 @@ internal static ParameterInfo[] GetParameters( #region Private Data Members private int m_tkParamDef; private MetadataImport m_scope; - private Signature m_signature = null!; + private Signature? m_signature; private volatile bool m_nameIsCached = false; private readonly bool m_noMetadata = false; private bool m_noDefaultValue = false; @@ -217,6 +217,8 @@ public override Type ParameterType // only instance of ParameterInfo has ClassImpl, all its subclasses don't if (ClassImpl == null) { + Debug.Assert(m_signature != null); + RuntimeType parameterType; if (PositionImpl == -1) parameterType = m_signature.ReturnType; @@ -481,12 +483,16 @@ private static DateTime GetRawDateTimeConstant(CustomAttributeData attr) public override Type[] GetRequiredCustomModifiers() { - return m_signature.GetCustomModifiers(PositionImpl + 1, true); + return m_signature is null ? + Type.EmptyTypes : + m_signature.GetCustomModifiers(PositionImpl + 1, true); } public override Type[] GetOptionalCustomModifiers() { - return m_signature.GetCustomModifiers(PositionImpl + 1, false); + return m_signature is null ? + Type.EmptyTypes : + m_signature.GetCustomModifiers(PositionImpl + 1, false); } #endregion diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs index 74148dda4ee6f3..15cad526595576 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs @@ -9,13 +9,6 @@ using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System.Runtime.CompilerServices { internal static unsafe class CastHelpers @@ -46,13 +39,13 @@ private struct CastCacheEntry }; [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int KeyToBucket(int[] table, nuint source, nuint target) + private static int KeyToBucket(ref int tableData, nuint source, nuint target) { // upper bits of addresses do not vary much, so to reduce loss due to cancelling out, // we do `rotl(source, ) ^ target` for mixing inputs. // then we use fibonacci hashing to reduce the value to desired size. - int hashShift = HashShift(table); + int hashShift = HashShift(ref tableData); #if TARGET_64BIT ulong hash = (((ulong)source << 32) | ((ulong)source >> 32)) ^ (ulong)target; return (int)((hash * 11400714819323198485ul) >> hashShift); @@ -63,31 +56,31 @@ private static int KeyToBucket(int[] table, nuint source, nuint target) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ref int AuxData(int[] table) + private static ref int TableData(int[] table) { // element 0 is used for embedded aux data return ref MemoryMarshal.GetArrayDataReference(table); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ref CastCacheEntry Element(int[] table, int index) + private static ref CastCacheEntry Element(ref int tableData, int index) { // element 0 is used for embedded aux data, skip it - return ref Unsafe.Add(ref Unsafe.As(ref AuxData(table)), index + 1); + return ref Unsafe.Add(ref Unsafe.As(ref tableData), index + 1); } - // TableMask is "size - 1" - // we need that more often that we need size [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int TableMask(int[] table) + private static int HashShift(ref int tableData) { - return AuxData(table); + return tableData; } + // TableMask is "size - 1" + // we need that more often that we need size [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int HashShift(int[] table) + private static int TableMask(ref int tableData) { - return Unsafe.Add(ref AuxData(table), 1); + return Unsafe.Add(ref tableData, 1); } private enum CastResult @@ -104,57 +97,60 @@ private enum CastResult private static CastResult TryGet(nuint source, nuint target) { const int BUCKET_SIZE = 8; - int[]? table = s_table; - // we use NULL as a sentinel for a rare case when a table could not be allocated - // because we avoid OOMs. - // we could use 0-element table instead, but then we would have to check the size here. - if (table != null) + // table is initialized and updated by native code that guarantees it is not null. + ref int tableData = ref TableData(s_table!); + + int index = KeyToBucket(ref tableData, source, target); + for (int i = 0; i < BUCKET_SIZE;) { - int index = KeyToBucket(table, source, target); - for (int i = 0; i < BUCKET_SIZE;) - { - ref CastCacheEntry pEntry = ref Element(table, index); + ref CastCacheEntry pEntry = ref Element(ref tableData, index); - // must read in this order: version -> entry parts -> version - // if version is odd or changes, the entry is inconsistent and thus ignored - int version = Volatile.Read(ref pEntry._version); - nuint entrySource = pEntry._source; + // must read in this order: version -> [entry parts] -> version + // if version is odd or changes, the entry is inconsistent and thus ignored + int version = Volatile.Read(ref pEntry._version); + nuint entrySource = pEntry._source; - // mask the lower version bit to make it even. - // This way we can check if version is odd or changing in just one compare. - version &= ~1; + // mask the lower version bit to make it even. + // This way we can check if version is odd or changing in just one compare. + version &= ~1; - if (entrySource == source) + if (entrySource == source) + { + nuint entryTargetAndResult = pEntry._targetAndResult; + // target never has its lower bit set. + // a matching entryTargetAndResult would the have same bits, except for the lowest one, which is the result. + entryTargetAndResult ^= target; + if (entryTargetAndResult <= 1) { - nuint entryTargetAndResult = Volatile.Read(ref pEntry._targetAndResult); - // target never has its lower bit set. - // a matching entryTargetAndResult would the have same bits, except for the lowest one, which is the result. - entryTargetAndResult ^= target; - if (entryTargetAndResult <= 1) + // make sure 'version' is loaded after 'source' and 'targetAndResults' + // + // We can either: + // - use acquires for both _source and _targetAndResults or + // - issue a load barrier before reading _version + // benchmarks on available hardware show that use of a read barrier is cheaper. + Interlocked.ReadMemoryBarrier(); + if (version != pEntry._version) { - if (version != pEntry._version) - { - // oh, so close, the entry is in inconsistent state. - // it is either changing or has changed while we were reading. - // treat it as a miss. - break; - } - - return (CastResult)entryTargetAndResult; + // oh, so close, the entry is in inconsistent state. + // it is either changing or has changed while we were reading. + // treat it as a miss. + break; } - } - if (version == 0) - { - // the rest of the bucket is unclaimed, no point to search further - break; + return (CastResult)entryTargetAndResult; } + } - // quadratic reprobe - i++; - index = (index + i) & TableMask(table); + if (version == 0) + { + // the rest of the bucket is unclaimed, no point to search further + break; } + + // quadratic reprobe + i++; + index = (index + i) & TableMask(ref tableData); } return CastResult.MaybeCast; } diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/CrossLoaderAllocatorHashHelpers.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/CrossLoaderAllocatorHashHelpers.cs index 9f45efa3df1c55..89d0773075d8a8 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/CrossLoaderAllocatorHashHelpers.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/CrossLoaderAllocatorHashHelpers.cs @@ -30,7 +30,7 @@ internal class LAHashDependentHashTracker [StructLayout(LayoutKind.Sequential)] internal class LAHashKeyToTrackers { - private object _trackerOrTrackerSet = null!; - private object _laLocalKeyValueStore = null!; + private object? _trackerOrTrackerSet; + private object? _laLocalKeyValueStore; } } diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/GCHeapHash.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/GCHeapHash.cs index 763ab98ceb3ca3..396967048ff0be 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/GCHeapHash.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/GCHeapHash.cs @@ -13,7 +13,7 @@ namespace System.Runtime.CompilerServices [StructLayout(LayoutKind.Sequential)] internal class GCHeapHash { - private Array _data = null!; + private Array? _data; private int _count; private int _deletedCount; } diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs index 63a8fbf6e9c335..6a3418ade5938e 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs @@ -15,7 +15,7 @@ internal unsafe ref struct StringHandleOnStack { private void* _ptr; - internal StringHandleOnStack([NotNull] ref string? s) + internal StringHandleOnStack(ref string? s) { _ptr = Unsafe.AsPointer(ref s); } @@ -31,7 +31,7 @@ private ObjectHandleOnStack(void* pObject) _ptr = pObject; } - internal static ObjectHandleOnStack Create([NotNull] ref T o) where T : class? + internal static ObjectHandleOnStack Create(ref T o) where T : class? { return new ObjectHandleOnStack(Unsafe.AsPointer(ref o)); } diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs index 705e611d7e1645..55d7ee78afc3a0 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs @@ -7,13 +7,6 @@ using System.Runtime.InteropServices; using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System.Runtime.CompilerServices { public static partial class RuntimeHelpers @@ -286,8 +279,22 @@ public static IntPtr AllocateTypeAssociatedMemory(Type type, int size) [DllImport(RuntimeHelpers.QCall)] private static extern IntPtr AllocateTypeAssociatedMemoryInternal(QCallTypeHandle type, uint size); - } + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern IntPtr AllocTailCallArgBuffer(int size, IntPtr gcDesc); + + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void FreeTailCallArgBuffer(); + + [MethodImpl(MethodImplOptions.InternalCall)] + private static unsafe extern TailCallTls* GetTailCallInfo(IntPtr retAddrSlot, IntPtr* retAddr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern long GetILBytesJitted(); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern int GetMethodsJittedCount(); + } // Helper class to assist with unsafe pinning of arbitrary objects. // It's used by VM code. internal class RawData @@ -340,31 +347,31 @@ internal unsafe struct MethodTable | 0x40000000 // enum_flag_ComObject | 0x00400000;// enum_flag_ICastable; - private const int ParentMethodTableOffset = 0x10 + private const int DebugClassNamePtr = // adjust for debug_m_szClassName #if DEBUG - + sizeof(nuint) // adjust for debug_m_szClassName -#endif - ; - #if TARGET_64BIT - private const int ElementTypeOffset = 0x30 + 8 #else - private const int ElementTypeOffset = 0x20 + 4 #endif -#if DEBUG - + sizeof(nuint) // adjust for debug_m_szClassName +#else + 0 #endif - ; + ; + + private const int ParentMethodTableOffset = 0x10 + DebugClassNamePtr; #if TARGET_64BIT - private const int InterfaceMapOffset = 0x38 + private const int ElementTypeOffset = 0x30 + DebugClassNamePtr; #else - private const int InterfaceMapOffset = 0x24 + private const int ElementTypeOffset = 0x20 + DebugClassNamePtr; #endif -#if DEBUG - + sizeof(nuint) // adjust for debug_m_szClassName + +#if TARGET_64BIT + private const int InterfaceMapOffset = 0x38 + DebugClassNamePtr; +#else + private const int InterfaceMapOffset = 0x24 + DebugClassNamePtr; #endif - ; public bool HasComponentSize { @@ -421,4 +428,24 @@ public int MultiDimensionalArrayRank } } } + + // Helper structs used for tail calls via helper. + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct PortableTailCallFrame + { + public PortableTailCallFrame* Prev; + public IntPtr TailCallAwareReturnAddress; + public IntPtr NextCall; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct TailCallTls + { + public PortableTailCallFrame* Frame; + public IntPtr ArgBuffer; + private IntPtr _argBufferSize; + private IntPtr _argBufferGCDesc; + private fixed byte _argBufferInline[64]; + } + } diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs index 0229ac9c0dbc55..6bdd48d7290a90 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs @@ -56,6 +56,16 @@ public enum CreateObjectFlags UniqueInstance = 2, } + /// + /// Internal enumeration used by the runtime to indicate the scenario for which ComWrappers is being used. + /// + internal enum ComWrappersScenario + { + Instance = 0, + TrackerSupportGlobalInstance = 1, + MarshallingGlobalInstance = 2, + } + /// /// Class for managing wrappers of COM IUnknown types. /// @@ -107,9 +117,14 @@ private struct ComInterfaceInstance } /// - /// Globally registered instance of the ComWrappers class. + /// Globally registered instance of the ComWrappers class for reference tracker support. /// - private static ComWrappers? s_globalInstance; + private static ComWrappers? s_globalInstanceForTrackerSupport; + + /// + /// Globally registered instance of the ComWrappers class for marshalling. + /// + private static ComWrappers? s_globalInstanceForMarshalling; /// /// Create a COM representation of the supplied object that can be passed to a non-managed environment. @@ -121,7 +136,7 @@ public IntPtr GetOrCreateComInterfaceForObject(object instance, CreateComInterfa { IntPtr ptr; if (!TryGetOrCreateComInterfaceForObjectInternal(this, instance, flags, out ptr)) - throw new ArgumentException(); + throw new ArgumentException(null, nameof(instance)); return ptr; } @@ -164,10 +179,23 @@ private static bool TryGetOrCreateComInterfaceForObjectInternal(ComWrappers? imp /// protected unsafe abstract ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count); - // Call to execute the abstract instance function - internal static unsafe void* CallComputeVtables(ComWrappers? comWrappersImpl, object obj, CreateComInterfaceFlags flags, out int count) + // Called by the runtime to execute the abstract instance function + internal static unsafe void* CallComputeVtables(ComWrappersScenario scenario, ComWrappers? comWrappersImpl, object obj, CreateComInterfaceFlags flags, out int count) { - ComWrappers? impl = comWrappersImpl ?? s_globalInstance; + ComWrappers? impl = null; + switch (scenario) + { + case ComWrappersScenario.Instance: + impl = comWrappersImpl; + break; + case ComWrappersScenario.TrackerSupportGlobalInstance: + impl = s_globalInstanceForTrackerSupport; + break; + case ComWrappersScenario.MarshallingGlobalInstance: + impl = s_globalInstanceForMarshalling; + break; + } + if (impl is null) { count = -1; @@ -187,7 +215,7 @@ public object GetOrCreateObjectForComInstance(IntPtr externalComObject, CreateOb { object? obj; if (!TryGetOrCreateObjectForComInstanceInternal(this, externalComObject, flags, null, out obj)) - throw new ArgumentNullException(); + throw new ArgumentNullException(nameof(externalComObject)); return obj!; } @@ -203,10 +231,23 @@ public object GetOrCreateObjectForComInstance(IntPtr externalComObject, CreateOb /// protected abstract object? CreateObject(IntPtr externalComObject, CreateObjectFlags flags); - // Call to execute the abstract instance function - internal static object? CallCreateObject(ComWrappers? comWrappersImpl, IntPtr externalComObject, CreateObjectFlags flags) + // Called by the runtime to execute the abstract instance function. + internal static object? CallCreateObject(ComWrappersScenario scenario, ComWrappers? comWrappersImpl, IntPtr externalComObject, CreateObjectFlags flags) { - ComWrappers? impl = comWrappersImpl ?? s_globalInstance; + ComWrappers? impl = null; + switch (scenario) + { + case ComWrappersScenario.Instance: + impl = comWrappersImpl; + break; + case ComWrappersScenario.TrackerSupportGlobalInstance: + impl = s_globalInstanceForTrackerSupport; + break; + case ComWrappersScenario.MarshallingGlobalInstance: + impl = s_globalInstanceForMarshalling; + break; + } + if (impl == null) return null; @@ -230,7 +271,7 @@ public object GetOrRegisterObjectForComInstance(IntPtr externalComObject, Create object? obj; if (!TryGetOrCreateObjectForComInstanceInternal(this, externalComObject, flags, wrapper, out obj)) - throw new ArgumentNullException(); + throw new ArgumentNullException(nameof(externalComObject)); return obj!; } @@ -268,32 +309,69 @@ private static bool TryGetOrCreateObjectForComInstanceInternal(ComWrappers? impl // Call to execute the virtual instance function internal static void CallReleaseObjects(ComWrappers? comWrappersImpl, IEnumerable objects) - => (comWrappersImpl ?? s_globalInstance!).ReleaseObjects(objects); + => (comWrappersImpl ?? s_globalInstanceForTrackerSupport!).ReleaseObjects(objects); /// - /// Register this class's implementation to be used as the single global instance. + /// Register a instance to be used as the global instance for reference tracker support. /// + /// Instance to register /// /// This function can only be called a single time. Subsequent calls to this function will result /// in a being thrown. /// - /// Scenarios where the global instance may be used are: + /// Scenarios where this global instance may be used are: /// * Object tracking via the and flags. - /// * Usage of COM related Marshal APIs. /// - public void RegisterAsGlobalInstance() + public static void RegisterForTrackerSupport(ComWrappers instance) + { + if (instance == null) + throw new ArgumentNullException(nameof(instance)); + + if (null != Interlocked.CompareExchange(ref s_globalInstanceForTrackerSupport, instance, null)) + { + throw new InvalidOperationException(SR.InvalidOperation_ResetGlobalComWrappersInstance); + } + + SetGlobalInstanceRegisteredForTrackerSupport(); + } + + + [DllImport(RuntimeHelpers.QCall)] + [SuppressGCTransition] + private static extern void SetGlobalInstanceRegisteredForTrackerSupport(); + + /// + /// Register a instance to be used as the global instance for marshalling in the runtime. + /// + /// Instance to register + /// + /// This function can only be called a single time. Subsequent calls to this function will result + /// in a being thrown. + /// + /// Scenarios where this global instance may be used are: + /// * Usage of COM-related Marshal APIs + /// * P/Invokes with COM-related types + /// * COM activation + /// + public static void RegisterForMarshalling(ComWrappers instance) { - if (null != Interlocked.CompareExchange(ref s_globalInstance, this, null)) + if (instance == null) + throw new ArgumentNullException(nameof(instance)); + + if (null != Interlocked.CompareExchange(ref s_globalInstanceForMarshalling, instance, null)) { throw new InvalidOperationException(SR.InvalidOperation_ResetGlobalComWrappersInstance); } - SetGlobalInstanceRegistered(); + // Indicate to the runtime that a global instance has been registered for marshalling. + // This allows the native runtime know to call into the managed ComWrappers only if a + // global instance is registered for marshalling. + SetGlobalInstanceRegisteredForMarshalling(); } [DllImport(RuntimeHelpers.QCall)] [SuppressGCTransition] - private static extern void SetGlobalInstanceRegistered(); + private static extern void SetGlobalInstanceRegisteredForMarshalling(); /// /// Get the runtime provided IUnknown implementation. @@ -319,4 +397,4 @@ internal static int CallICustomQueryInterface(object customQueryInterfaceMaybe, return (int)customQueryInterface.GetInterface(ref iid, out ppObject); } } -} \ No newline at end of file +} diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs index f19d63e4034492..d7cd618a076104 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/ConstantSplittableMap.cs @@ -78,9 +78,7 @@ private KeyValuePair[] CreateKeyValueArray(int count, IEnumerator< public TValue Lookup(TKey key) { - bool found = TryGetValue(key, out TValue value); - - if (!found) + if (!TryGetValue(key, out TValue value)) { Debug.Assert(key != null); Exception e = new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key.ToString())); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs index d24a0c9201d93c..bdacad0d07f3ba 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs @@ -28,9 +28,7 @@ private DictionaryToMapAdapter() internal V Lookup(K key) where K : notnull { IDictionary _this = Unsafe.As>(this); - bool keyFound = _this.TryGetValue(key, out V value); - - if (!keyFound) + if (!_this.TryGetValue(key, out V value)) { Debug.Assert(key != null); Exception e = new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key.ToString())); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs index 5ba246996dccb5..81c3a453b17a80 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs @@ -28,9 +28,7 @@ private IReadOnlyDictionaryToIMapViewAdapter() internal V Lookup(K key) where K : notnull { IReadOnlyDictionary _this = Unsafe.As>(this); - bool keyFound = _this.TryGetValue(key, out V value); - - if (!keyFound) + if (!_this.TryGetValue(key, out V value)) { Debug.Assert(key != null); Exception e = new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, key.ToString())); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs index 9027e3bd3598a9..997fa49107dcee 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs @@ -95,6 +95,16 @@ internal Assembly LoadFromInMemoryModule(IntPtr moduleHandle) } #endif + // This method is invoked by the VM to resolve a satellite assembly reference + // after trying assembly resolution via Load override without success. + private static Assembly? ResolveSatelliteAssembly(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName) + { + AssemblyLoadContext context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchManagedAssemblyLoadContext).Target)!; + + // Invoke the ResolveSatelliteAssembly method + return context.ResolveSatelliteAssembly(assemblyName); + } + // This method is invoked by the VM when using the host-provided assembly load context // implementation. private static IntPtr ResolveUnmanagedDll(string unmanagedDllName, IntPtr gchManagedAssemblyLoadContext) @@ -111,6 +121,15 @@ private static IntPtr ResolveUnmanagedDllUsingEvent(string unmanagedDllName, Ass return context.GetResolvedUnmanagedDll(assembly, unmanagedDllName); } + // This method is invoked by the VM to resolve an assembly reference using the Resolving event + // after trying assembly resolution via Load override and TPA load context without success. + private static Assembly? ResolveUsingResolvingEvent(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName) + { + AssemblyLoadContext context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchManagedAssemblyLoadContext).Target)!; + // Invoke the AssemblyResolve event callbacks if wired up + return context.ResolveUsingEvent(assemblyName); + } + [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] private static extern void LoadTypeForWinRTTypeNameInContextInternal(IntPtr ptrNativeAssemblyLoadContext, string typeName, ObjectHandleOnStack loadedType); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeHandles.cs index 5661ce8130ec5d..c95afb2036300c 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -446,10 +446,10 @@ internal static RuntimeType GetTypeByNameUsingCARules(string name, RuntimeModule if (string.IsNullOrEmpty(name)) throw new ArgumentException(null, nameof(name)); - RuntimeType type = null!; + RuntimeType? type = null; GetTypeByNameUsingCARules(name, new QCallModule(ref scope), ObjectHandleOnStack.Create(ref type)); - return type; + return type!; } [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] @@ -457,18 +457,18 @@ internal static RuntimeType GetTypeByNameUsingCARules(string name, RuntimeModule internal RuntimeType[] GetInstantiationInternal() { - RuntimeType[] types = null!; + RuntimeType[]? types = null; RuntimeTypeHandle nativeHandle = GetNativeHandle(); GetInstantiation(new QCallTypeHandle(ref nativeHandle), ObjectHandleOnStack.Create(ref types), Interop.BOOL.TRUE); - return types; + return types!; } internal Type[] GetInstantiationPublic() { - Type[] types = null!; + Type[]? types = null; RuntimeTypeHandle nativeHandle = GetNativeHandle(); GetInstantiation(new QCallTypeHandle(ref nativeHandle), ObjectHandleOnStack.Create(ref types), Interop.BOOL.FALSE); - return types; + return types!; } [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] @@ -481,11 +481,11 @@ internal RuntimeType Instantiate(Type[]? inst) fixed (IntPtr* pInst = instHandles) { - RuntimeType type = null!; + RuntimeType? type = null; RuntimeTypeHandle nativeHandle = GetNativeHandle(); Instantiate(new QCallTypeHandle(ref nativeHandle), pInst, instCount, ObjectHandleOnStack.Create(ref type)); GC.KeepAlive(inst); - return type; + return type!; } } @@ -494,10 +494,10 @@ internal RuntimeType Instantiate(Type[]? inst) internal RuntimeType MakeArray(int rank) { - RuntimeType type = null!; + RuntimeType? type = null; RuntimeTypeHandle nativeHandle = GetNativeHandle(); MakeArray(new QCallTypeHandle(ref nativeHandle), rank, ObjectHandleOnStack.Create(ref type)); - return type; + return type!; } [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] @@ -505,10 +505,10 @@ internal RuntimeType MakeArray(int rank) internal RuntimeType MakeSZArray() { - RuntimeType type = null!; + RuntimeType? type = null; RuntimeTypeHandle nativeHandle = GetNativeHandle(); MakeSZArray(new QCallTypeHandle(ref nativeHandle), ObjectHandleOnStack.Create(ref type)); - return type; + return type!; } [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] @@ -516,10 +516,10 @@ internal RuntimeType MakeSZArray() internal RuntimeType MakeByRef() { - RuntimeType type = null!; + RuntimeType? type = null; RuntimeTypeHandle nativeHandle = GetNativeHandle(); MakeByRef(new QCallTypeHandle(ref nativeHandle), ObjectHandleOnStack.Create(ref type)); - return type; + return type!; } [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] @@ -527,10 +527,10 @@ internal RuntimeType MakeByRef() internal RuntimeType MakePointer() { - RuntimeType type = null!; + RuntimeType? type = null; RuntimeTypeHandle nativeHandle = GetNativeHandle(); MakePointer(new QCallTypeHandle(ref nativeHandle), ObjectHandleOnStack.Create(ref type)); - return type; + return type!; } [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] @@ -665,15 +665,15 @@ public RuntimeMethodInfoStub(IntPtr methodHandleValue, object keepalive) private readonly object m_keepalive; // These unused variables are used to ensure that this class has the same layout as RuntimeMethodInfo -#pragma warning disable CA1823, 414 - private object m_a = null!; - private object m_b = null!; - private object m_c = null!; - private object m_d = null!; - private object m_e = null!; - private object m_f = null!; - private object m_g = null!; -#pragma warning restore CA1823, 414 +#pragma warning disable CA1823, 414, 169 + private object? m_a; + private object? m_b; + private object? m_c; + private object? m_d; + private object? m_e; + private object? m_f; + private object? m_g; +#pragma warning restore CA1823, 414, 169 public RuntimeMethodHandleInternal m_value; @@ -861,25 +861,25 @@ internal static MdUtf8String GetUtf8Name(RuntimeMethodHandleInternal method) internal static RuntimeType[] GetMethodInstantiationInternal(IRuntimeMethodInfo method) { - RuntimeType[] types = null!; + RuntimeType[]? types = null; GetMethodInstantiation(EnsureNonNullMethodInfo(method).Value, ObjectHandleOnStack.Create(ref types), Interop.BOOL.TRUE); GC.KeepAlive(method); - return types; + return types!; } internal static RuntimeType[] GetMethodInstantiationInternal(RuntimeMethodHandleInternal method) { - RuntimeType[] types = null!; + RuntimeType[]? types = null; GetMethodInstantiation(method, ObjectHandleOnStack.Create(ref types), Interop.BOOL.TRUE); - return types; + return types!; } internal static Type[] GetMethodInstantiationPublic(IRuntimeMethodInfo method) { - RuntimeType[] types = null!; + RuntimeType[]? types = null; GetMethodInstantiation(EnsureNonNullMethodInfo(method).Value, ObjectHandleOnStack.Create(ref types), Interop.BOOL.FALSE); GC.KeepAlive(method); - return types; + return types!; } [MethodImpl(MethodImplOptions.InternalCall)] @@ -1000,14 +1000,14 @@ RuntimeFieldHandleInternal Value internal class RuntimeFieldInfoStub : IRuntimeFieldInfo { // These unused variables are used to ensure that this class has the same layout as RuntimeFieldInfo -#pragma warning disable 414 - private object m_keepalive = null!; - private object m_c = null!; - private object m_d = null!; +#pragma warning disable 414, 169 + private object? m_keepalive; + private object? m_c; + private object? m_d; private int m_b; - private object m_e = null!; + private object? m_e; private RuntimeFieldHandleInternal m_fieldHandle; -#pragma warning restore 414 +#pragma warning restore 414, 169 RuntimeFieldHandleInternal IRuntimeFieldInfo.Value => m_fieldHandle; } @@ -1209,11 +1209,11 @@ internal static RuntimeType ResolveTypeHandleInternal(RuntimeModule module, int fixed (IntPtr* typeInstArgs = typeInstantiationContextHandles, methodInstArgs = methodInstantiationContextHandles) { - RuntimeType type = null!; + RuntimeType? type = null; ResolveType(new QCallModule(ref module), typeToken, typeInstArgs, typeInstCount, methodInstArgs, methodInstCount, ObjectHandleOnStack.Create(ref type)); GC.KeepAlive(typeInstantiationContext); GC.KeepAlive(methodInstantiationContext); - return type; + return type!; } } @@ -1288,11 +1288,11 @@ internal static IRuntimeFieldInfo ResolveFieldHandleInternal(RuntimeModule modul fixed (IntPtr* typeInstArgs = typeInstantiationContextHandles, methodInstArgs = methodInstantiationContextHandles) { - IRuntimeFieldInfo field = null!; + IRuntimeFieldInfo? field = null; ResolveField(new QCallModule(ref module), fieldToken, typeInstArgs, typeInstCount, methodInstArgs, methodInstCount, ObjectHandleOnStack.Create(ref field)); GC.KeepAlive(typeInstantiationContext); GC.KeepAlive(methodInstantiationContext); - return field; + return field!; } } @@ -1318,9 +1318,9 @@ internal static bool ContainsPropertyMatchingHash(RuntimeModule module, int prop internal static RuntimeType GetModuleType(RuntimeModule module) { - RuntimeType type = null!; + RuntimeType? type = null; GetModuleType(new QCallModule(ref module), ObjectHandleOnStack.Create(ref type)); - return type; + return type!; } [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] @@ -1375,6 +1375,8 @@ internal enum MdSigCallingConvention : byte #endregion #region FCalls + [MemberNotNull(nameof(m_arguments))] + [MemberNotNull(nameof(m_returnTypeORfieldType))] [MethodImpl(MethodImplOptions.InternalCall)] private extern void GetSignature( void* pCorSig, int cCorSig, @@ -1386,9 +1388,9 @@ private extern void GetSignature( // // Keep the layout in sync with SignatureNative in the VM // - internal RuntimeType[] m_arguments = null!; - internal RuntimeType m_declaringType = null!; // seems not used - internal RuntimeType m_returnTypeORfieldType = null!; + internal RuntimeType[] m_arguments; + internal RuntimeType? m_declaringType; + internal RuntimeType m_returnTypeORfieldType; internal object? m_keepalive; internal void* m_sig; internal int m_managedCallingConventionAndArgIteratorFlags; // lowest byte is CallingConvention, upper 3 bytes are ArgIterator flags diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index 93cfd86bc167b1..38511276255bed 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -244,14 +244,17 @@ internal MethodBase AddMethod(RuntimeType declaringType, RuntimeMethodHandleInte switch (cacheType) { case CacheType.Method: - list = (T[])(object)new RuntimeMethodInfo[1] { - new RuntimeMethodInfo(method, declaringType, m_runtimeTypeCache, methodAttributes, bindingFlags, null) - }; + list = (T[])(object)new RuntimeMethodInfo[1] + { + new RuntimeMethodInfo(method, declaringType, m_runtimeTypeCache, methodAttributes, bindingFlags, null) + }; break; + case CacheType.Constructor: - list = (T[])(object)new RuntimeConstructorInfo[1] { - new RuntimeConstructorInfo(method, declaringType, m_runtimeTypeCache, methodAttributes, bindingFlags) - }; + list = (T[])(object)new RuntimeConstructorInfo[1] + { + new RuntimeConstructorInfo(method, declaringType, m_runtimeTypeCache, methodAttributes, bindingFlags) + }; break; } @@ -2752,7 +2755,7 @@ public override InterfaceMapping GetInterfaceMap(Type ifaceType) protected override PropertyInfo? GetPropertyImpl( string name, BindingFlags bindingAttr, Binder? binder, Type? returnType, Type[]? types, ParameterModifier[]? modifiers) { - if (name == null) throw new ArgumentNullException(); + if (name == null) throw new ArgumentNullException(nameof(name)); ListBuilder candidates = GetPropertyCandidates(name, bindingAttr, types, false); @@ -2788,7 +2791,7 @@ public override InterfaceMapping GetInterfaceMap(Type ifaceType) public override EventInfo? GetEvent(string name, BindingFlags bindingAttr) { - if (name is null) throw new ArgumentNullException(); + if (name is null) throw new ArgumentNullException(nameof(name)); FilterHelper(bindingAttr, ref name, out _, out MemberListType listType); @@ -2851,7 +2854,7 @@ public override InterfaceMapping GetInterfaceMap(Type ifaceType) public override Type? GetInterface(string fullname, bool ignoreCase) { - if (fullname is null) throw new ArgumentNullException(); + if (fullname is null) throw new ArgumentNullException(nameof(fullname)); BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.NonPublic; @@ -2885,7 +2888,7 @@ public override InterfaceMapping GetInterfaceMap(Type ifaceType) public override Type? GetNestedType(string fullname, BindingFlags bindingAttr) { - if (fullname is null) throw new ArgumentNullException(); + if (fullname is null) throw new ArgumentNullException(nameof(fullname)); bindingAttr &= ~BindingFlags.Static; string name, ns; @@ -2913,7 +2916,7 @@ public override InterfaceMapping GetInterfaceMap(Type ifaceType) public override MemberInfo[] GetMember(string name, MemberTypes type, BindingFlags bindingAttr) { - if (name is null) throw new ArgumentNullException(); + if (name is null) throw new ArgumentNullException(nameof(name)); ListBuilder methods = default; ListBuilder constructors = default; @@ -4062,7 +4065,7 @@ internal static Type GetTypeFromCLSIDImpl(Guid clsid, string? server, bool throw // Handle arguments that are passed as ByRef and those // arguments that need to be wrapped. - ParameterModifier[] aParamMod = null!; + ParameterModifier[]? aParamMod = null; if (cArgs > 0) { ParameterModifier paramMod = new ParameterModifier(cArgs); @@ -4087,7 +4090,7 @@ internal static Type GetTypeFromCLSIDImpl(Guid clsid, string? server, bool throw for (int i = 0; i < cArgs; i++) { // Determine if the parameter is ByRef. - if (aParamMod[0][i] && aArgs[i] != null) + if (aParamMod![0][i] && aArgs[i] != null) { Type argType = aArgsTypes[i]; if (!ReferenceEquals(argType, aArgs[i].GetType())) diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/src/System.Private.CoreLib/src/System/StubHelpers.cs index 81c1611be4f56a..51d0138d905d61 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1878,5 +1878,8 @@ internal static void CheckStringLength(uint length) [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void MulticastDebuggerTraceHelper(object o, int count); #endif + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern IntPtr NextCallReturnAddress(); } // class StubHelpers } diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Threading/Interlocked.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Threading/Interlocked.CoreCLR.cs index 33437141e76121..c9153f3cda7539 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Threading/Interlocked.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Threading/Interlocked.CoreCLR.cs @@ -232,6 +232,15 @@ public static long Read(ref long location) => [MethodImpl(MethodImplOptions.InternalCall)] public static extern void MemoryBarrier(); + /// + /// Synchronizes memory access as follows: + /// The processor that executes the current thread cannot reorder instructions in such a way that memory reads before + /// the call to execute after memory accesses that follow the call to . + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void ReadMemoryBarrier(); + [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] private static extern void _MemoryBarrierProcessWide(); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs index c2d72e3915cae7..719576c06d0338 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs @@ -192,6 +192,13 @@ public static partial class ThreadPool // Time in ms for which ThreadPoolWorkQueue.Dispatch keeps executing work items before returning to the OS private const uint DispatchQuantum = 30; + private static bool GetEnableWorkerTracking() + { + bool enableWorkerTracking = false; + InitializeVMTp(ref enableWorkerTracking); + return enableWorkerTracking; + } + internal static bool KeepDispatching(int startTickCount) { // Note: this function may incorrectly return false due to TickCount overflow @@ -260,7 +267,7 @@ private static extern long PendingUnmanagedWorkItemCount get; } - private static RegisteredWaitHandle RegisterWaitForSingleObject( // throws RegisterWaitException + private static RegisteredWaitHandle RegisterWaitForSingleObject( WaitHandle waitObject, WaitOrTimerCallback callBack, object? state, @@ -302,25 +309,6 @@ bool compressStack public static unsafe bool UnsafeQueueNativeOverlapped(NativeOverlapped* overlapped) => PostQueuedCompletionStatus(overlapped); - // The thread pool maintains a per-appdomain managed work queue. - // New thread pool entries are added in the managed queue. - // The VM is responsible for the actual growing/shrinking of - // threads. - private static void EnsureInitialized() - { - if (!ThreadPoolGlobals.threadPoolInitialized) - { - EnsureVMInitializedCore(); // separate out to help with inlining - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void EnsureVMInitializedCore() - { - InitializeVMTp(ref ThreadPoolGlobals.enableWorkerTracking); - ThreadPoolGlobals.threadPoolInitialized = true; - } - // Native methods: [MethodImpl(MethodImplOptions.InternalCall)] @@ -346,7 +334,6 @@ private static void EnsureVMInitializedCore() internal static void NotifyWorkItemProgress() { - EnsureInitialized(); NotifyWorkItemProgressNative(); } diff --git a/src/coreclr/src/ToolBox/SOS/DacTableGen/CMakeLists.txt b/src/coreclr/src/ToolBox/SOS/DacTableGen/CMakeLists.txt index dcd39e346c98e4..e3fc3ed9e3a5e1 100644 --- a/src/coreclr/src/ToolBox/SOS/DacTableGen/CMakeLists.txt +++ b/src/coreclr/src/ToolBox/SOS/DacTableGen/CMakeLists.txt @@ -2,6 +2,19 @@ project(DacTableGen LANGUAGES CSharp) +file(TO_CMAKE_PATH "$ENV{VSInstallDir}\\DIA SDK" DIASDK_DIR) +file(COPY "${DIASDK_DIR}/bin/msdia140.dll" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + +set (DIALib "${CMAKE_CURRENT_BINARY_DIR}/DIALib.dll") +FIND_PROGRAM(TLBIMP tlbimp.exe) +FIND_PROGRAM(MIDL midl.exe) +add_custom_command( + OUTPUT "${DIALib}" + COMMAND ${MIDL} /I "${DIASDK_DIR}/include" "${DIASDK_DIR}/idl/dia2.idl" /tlb "${CMAKE_CURRENT_BINARY_DIR}/dia2.tlb" + COMMAND ${TLBIMP} dia2.tlb /out:"${DIALib}" +) +add_custom_target(gen_dialib DEPENDS "${DIALib}") + set(DACTABLEGEN_SOURCES cvconst.cs diautil.cs @@ -13,6 +26,7 @@ set_directory_properties(PROPERTIES COMPILE_DEFINITIONS "") set(CMAKE_CSharp_FLAGS "/platform:anycpu32bitpreferred") add_executable(dactablegen ${DACTABLEGEN_SOURCES}) +add_dependencies(dactablegen gen_dialib) set_target_properties(dactablegen PROPERTIES VS_DOTNET_REFERENCES "System") -set_target_properties(dactablegen PROPERTIES VS_DOTNET_REFERENCE_DIALib ${CMAKE_CURRENT_SOURCE_DIR}/DIALib.dll) +set_target_properties(dactablegen PROPERTIES VS_DOTNET_REFERENCE_DIALib "${DIALib}") diff --git a/src/coreclr/src/ToolBox/SOS/DacTableGen/DIALib.dll b/src/coreclr/src/ToolBox/SOS/DacTableGen/DIALib.dll deleted file mode 100644 index 06665740dc94db..00000000000000 Binary files a/src/coreclr/src/ToolBox/SOS/DacTableGen/DIALib.dll and /dev/null differ diff --git a/src/coreclr/src/ToolBox/SOS/DacTableGen/diautil.cs b/src/coreclr/src/ToolBox/SOS/DacTableGen/diautil.cs index e5c994329de00d..e9e53494cf7b2d 100644 --- a/src/coreclr/src/ToolBox/SOS/DacTableGen/diautil.cs +++ b/src/coreclr/src/ToolBox/SOS/DacTableGen/diautil.cs @@ -5,7 +5,7 @@ using System; using System.Text; using System.IO; -using Dia; +using DIALib; using System.Runtime.InteropServices; using System.Diagnostics; diff --git a/src/coreclr/src/ToolBox/SOS/DacTableGen/main.cs b/src/coreclr/src/ToolBox/SOS/DacTableGen/main.cs index 0ed7f451d5def4..ab25537d75353a 100644 --- a/src/coreclr/src/ToolBox/SOS/DacTableGen/main.cs +++ b/src/coreclr/src/ToolBox/SOS/DacTableGen/main.cs @@ -8,7 +8,7 @@ using System.Collections.Generic; #if !TARGET_UNIX -using Dia; +using DIALib; using Dia.Util; #endif // !TARGET_UNIX using System.Globalization; diff --git a/src/coreclr/src/ToolBox/superpmi/mcs/verbildump.cpp b/src/coreclr/src/ToolBox/superpmi/mcs/verbildump.cpp index 8b552af3bdf73a..5a41401cc53d79 100644 --- a/src/coreclr/src/ToolBox/superpmi/mcs/verbildump.cpp +++ b/src/coreclr/src/ToolBox/superpmi/mcs/verbildump.cpp @@ -915,12 +915,9 @@ char* DumpAttributeToConsoleBare(DWORD attribute) if (0) ; - ifPrint(CORINFO_FLG_STATIC, s_static) ifPrint(CORINFO_FLG_DONT_INLINE, s_dontInline) - ifPrint(CORINFO_FLG_CONSTRUCTOR, s_constructor) else - { - LogError("unknown attribute %x", attribute); - __debugbreak(); - } + ifPrint(CORINFO_FLG_STATIC, s_static) + ifPrint(CORINFO_FLG_DONT_INLINE, s_dontInline) + ifPrint(CORINFO_FLG_CONSTRUCTOR, s_constructor) return nullptr; #undef ifPrint diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h index d57e7eae48d879..03c722caed8962 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h @@ -880,8 +880,11 @@ CORINFO_METHOD_HANDLE GetDelegateCtor(CORINFO_METHOD_HANDLE methHnd, void MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd); -// return a thunk that will copy the arguments for the given signature. -void* getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags); +bool getTailCallHelpers( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult); bool convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert); diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h index c8aa01e3a6a03e..1922e7d0f5dfad 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h @@ -121,7 +121,7 @@ LWM(GetRelocTypeHint, DWORDLONG, DWORD) LWM(GetSharedCCtorHelper, DWORDLONG, DWORD) LWM(GetStringConfigValue, DWORD, DWORD) LWM(GetSystemVAmd64PassStructInRegisterDescriptor, DWORDLONG, Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor) -LWM(GetTailCallCopyArgsThunk, Agnostic_GetTailCallCopyArgsThunk, DWORDLONG) +LWM(GetTailCallHelpers, Agnostic_GetTailCallHelpers, Agnostic_CORINFO_TAILCALL_HELPERS) LWM(GetThreadTLSIndex, DWORD, DLD) LWM(GetTokenTypeAsHandle, GetTokenTypeAsHandleValue, DWORDLONG) LWM(GetTypeForBox, DWORDLONG, DWORDLONG) diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp index c2c4d8f5e78b83..77603de0a850c6 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp @@ -5940,44 +5940,76 @@ const WCHAR* MethodContext::repAppendClassName(CORINFO_CLASS_HANDLE cls, return name; } -void MethodContext::recGetTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, - CorInfoHelperTailCallSpecialHandling flags, - void* result) +void MethodContext::recGetTailCallHelpers( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult) { - if (GetTailCallCopyArgsThunk == nullptr) - GetTailCallCopyArgsThunk = new LightWeightMap(); + if (GetTailCallHelpers == nullptr) + GetTailCallHelpers = new LightWeightMap(); - Agnostic_GetTailCallCopyArgsThunk key; - ZeroMemory(&key, sizeof(Agnostic_GetTailCallCopyArgsThunk)); // We use the input structs as a key and use memcmp to - // compare.. so we need to zero out padding too - key.Sig = SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INFO(*pSig, GetTailCallCopyArgsThunk); + Agnostic_GetTailCallHelpers key; + ZeroMemory(&key, sizeof(Agnostic_GetTailCallHelpers)); + + key.callToken = SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN(callToken, GetTailCallHelpers); + key.sig = SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INFO(*sig, GetTailCallHelpers); key.flags = (DWORD)flags; - GetTailCallCopyArgsThunk->Add(key, (DWORDLONG)result); - DEBUG_REC(dmpGetTailCallCopyArgsThunk(key, (DWORDLONG)result)); + Agnostic_CORINFO_TAILCALL_HELPERS value; + ZeroMemory(&value, sizeof(Agnostic_CORINFO_TAILCALL_HELPERS)); + + value.result = pResult != nullptr; + if (pResult != nullptr) + { + value.flags = (DWORD)pResult->flags; + value.hStoreArgs = (DWORDLONG)pResult->hStoreArgs; + value.hCallTarget = (DWORDLONG)pResult->hCallTarget; + value.hDispatcher = (DWORDLONG)pResult->hDispatcher; + } + GetTailCallHelpers->Add(key, value); + DEBUG_REC(dmpGetTailCallHelpers(key, value)); } -void MethodContext::dmpGetTailCallCopyArgsThunk(const Agnostic_GetTailCallCopyArgsThunk& key, DWORDLONG value) + +void MethodContext::dmpGetTailCallHelpers(const Agnostic_GetTailCallHelpers& key, const Agnostic_CORINFO_TAILCALL_HELPERS& value) { - printf("GetTailCallCopyArgsThunk key sig%s flg-%08X", - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(key.Sig).c_str(), key.flags); - printf(", value res-%016llX", value); + printf("GetTailCallHelpers key callToken-%s sig-%s flg-%08X", + SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.callToken).c_str(), + SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(key.sig).c_str(), + key.flags); + printf(", value result-%s flg-%08X hStoreArgs-%016llX hCallTarget-%016llX hDispatcher-%016llX", + value.result ? "true" : "false", + value.flags, + value.hStoreArgs, + value.hCallTarget, + value.hDispatcher); } -void* MethodContext::repGetTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) + +bool MethodContext::repGetTailCallHelpers( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult) { - AssertCodeMsg(GetTailCallCopyArgsThunk != nullptr, EXCEPTIONCODE_MC, "Didn't find anything for ..."); + AssertCodeMsg(GetTailCallHelpers != nullptr, EXCEPTIONCODE_MC, "Didn't find anything for ..."); - Agnostic_GetTailCallCopyArgsThunk key; - ZeroMemory(&key, sizeof(Agnostic_GetTailCallCopyArgsThunk)); // We use the input structs as a key and use memcmp to - // compare.. so we need to zero out padding too - key.Sig = SpmiRecordsHelper::RestoreAgnostic_CORINFO_SIG_INFO(*pSig, GetTailCallCopyArgsThunk); + Agnostic_GetTailCallHelpers key; + ZeroMemory(&key, sizeof(Agnostic_GetTailCallHelpers)); + key.callToken = SpmiRecordsHelper::RestoreAgnostic_CORINFO_RESOLVED_TOKEN(callToken, GetTailCallHelpers); + key.sig = SpmiRecordsHelper::RestoreAgnostic_CORINFO_SIG_INFO(*sig, GetTailCallHelpers); key.flags = (DWORD)flags; - AssertCodeMsg(GetTailCallCopyArgsThunk->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Didn't find %016llX", - (DWORDLONG)key.Sig.retTypeClass); - void* result = (void*)GetTailCallCopyArgsThunk->Get(key); - cr->recAddressMap((void*)0x424242, (void*)result, 1); - DEBUG_REP(dmpGetTailCallCopyArgsThunk(key, (DWORDLONG)result)); - return result; + AssertCodeMsg(GetTailCallHelpers->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Could not find matching tail call helper call"); + Agnostic_CORINFO_TAILCALL_HELPERS value = GetTailCallHelpers->Get(key); + if (!value.result) + return false; + + pResult->flags = (CORINFO_TAILCALL_HELPERS_FLAGS)value.flags; + pResult->hStoreArgs = (CORINFO_METHOD_HANDLE)value.hStoreArgs; + pResult->hCallTarget = (CORINFO_METHOD_HANDLE)value.hCallTarget; + pResult->hDispatcher = (CORINFO_METHOD_HANDLE)value.hDispatcher; + DEBUG_REP(dmpGetTailCallHelpers(key, value)); + return true; } void MethodContext::recGetMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod, mdMethodDef result) diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h index 84c2042ee367af..1f34c4569e3358 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h @@ -436,10 +436,19 @@ class MethodContext DWORDLONG ProfilerHandle; DWORD bIndirectedHandles; }; - struct Agnostic_GetTailCallCopyArgsThunk + struct Agnostic_GetTailCallHelpers { - Agnostic_CORINFO_SIG_INFO Sig; - DWORD flags; + Agnostic_CORINFO_RESOLVED_TOKEN callToken; + Agnostic_CORINFO_SIG_INFO sig; + DWORD flags; + }; + struct Agnostic_CORINFO_TAILCALL_HELPERS + { + bool result; + DWORD flags; + DWORDLONG hStoreArgs; + DWORDLONG hCallTarget; + DWORDLONG hDispatcher; }; struct Agnostic_GetArgClass_Value { @@ -1255,9 +1264,17 @@ class MethodContext void dmpAppendClassName(const Agnostic_AppendClassName& key, DWORD value); const WCHAR* repAppendClassName(CORINFO_CLASS_HANDLE cls, BOOL fNamespace, BOOL fFullInst, BOOL fAssembly); - void recGetTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags, void* result); - void dmpGetTailCallCopyArgsThunk(const Agnostic_GetTailCallCopyArgsThunk& key, DWORDLONG value); - void* repGetTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags); + void recGetTailCallHelpers( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult); + void dmpGetTailCallHelpers(const Agnostic_GetTailCallHelpers& key, const Agnostic_CORINFO_TAILCALL_HELPERS& value); + bool repGetTailCallHelpers( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult); void recGetMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod, mdMethodDef result); void dmpGetMethodDefFromMethod(DWORDLONG key, DWORD value); @@ -1320,7 +1337,7 @@ class MethodContext }; // ********************* Please keep this up-to-date to ease adding more *************** -// Highest packet number: 177 +// Highest packet number: 178 // ************************************************************************************* enum mcPackets { @@ -1438,7 +1455,8 @@ enum mcPackets Packet_GetRelocTypeHint = 84, Packet_GetSecurityPrologHelper = 85, // Retired 2/18/2020 Packet_GetSharedCCtorHelper = 86, - Packet_GetTailCallCopyArgsThunk = 87, + Packet_GetTailCallCopyArgsThunk = 87, // Retired 4/27/2020 + Packet_GetTailCallHelpers = 178, // Added 3/18/2020 Packet_GetThreadTLSIndex = 88, Packet_GetTokenTypeAsHandle = 89, Packet_GetTypeForBox = 90, diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 505d46c114cfb6..2da8785f96bc23 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1857,12 +1857,18 @@ void interceptor_ICJI::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd) original_ICorJitInfo->MethodCompileComplete(methHnd); } -// return a thunk that will copy the arguments for the given signature. -void* interceptor_ICJI::getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) -{ - mc->cr->AddCall("getTailCallCopyArgsThunk"); - void* result = original_ICorJitInfo->getTailCallCopyArgsThunk(pSig, flags); - mc->recGetTailCallCopyArgsThunk(pSig, flags, result); +bool interceptor_ICJI::getTailCallHelpers( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult) +{ + mc->cr->AddCall("getTailCallHelpers"); + bool result = original_ICorJitInfo->getTailCallHelpers(callToken, sig, flags, pResult); + if (result) + mc->recGetTailCallHelpers(callToken, sig, flags, pResult); + else + mc->recGetTailCallHelpers(callToken, sig, flags, nullptr); return result; } @@ -2091,4 +2097,4 @@ DWORD interceptor_ICJI::getExpectedTargetArchitecture() void interceptor_ICJI::notifyInstructionSetUsage(CORINFO_InstructionSet instructionSet, bool supported) { original_ICorJitInfo->notifyInstructionSetUsage(instructionSet, supported); -} \ No newline at end of file +} diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp index ad18047e373749..febd952a655fab 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp @@ -1442,11 +1442,14 @@ void interceptor_ICJI::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd) original_ICorJitInfo->MethodCompileComplete(methHnd); } -// return a thunk that will copy the arguments for the given signature. -void* interceptor_ICJI::getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) +bool interceptor_ICJI::getTailCallHelpers( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult) { - mcs->AddCall("getTailCallCopyArgsThunk"); - return original_ICorJitInfo->getTailCallCopyArgsThunk(pSig, flags); + mcs->AddCall("getTailCallHelpers"); + return original_ICorJitInfo->getTailCallHelpers(callToken, sig, flags, pResult); } // Stuff directly on ICorJitInfo @@ -1668,4 +1671,4 @@ void interceptor_ICJI::notifyInstructionSetUsage(CORINFO_InstructionSet instruct { mcs->AddCall("notifyInstructionSetUsage"); original_ICorJitInfo->notifyInstructionSetUsage(instructionSet, supported); -} \ No newline at end of file +} diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp index eab760a30d2926..26141d06068f46 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp @@ -1285,10 +1285,13 @@ void interceptor_ICJI::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd) original_ICorJitInfo->MethodCompileComplete(methHnd); } -// return a thunk that will copy the arguments for the given signature. -void* interceptor_ICJI::getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) +bool interceptor_ICJI::getTailCallHelpers( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult) { - return original_ICorJitInfo->getTailCallCopyArgsThunk(pSig, flags); + return original_ICorJitInfo->getTailCallHelpers(callToken, sig, flags, pResult); } // Stuff directly on ICorJitInfo diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp index 728bd3b2bef8b8..24bc4415e586e0 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp @@ -1540,11 +1540,14 @@ void MyICJI::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd) DebugBreakorAV(118); } -// return a thunk that will copy the arguments for the given signature. -void* MyICJI::getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) +bool MyICJI::getTailCallHelpers( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult) { - jitInstance->mc->cr->AddCall("getTailCallCopyArgsThunk"); - return jitInstance->mc->repGetTailCallCopyArgsThunk(pSig, flags); + jitInstance->mc->cr->AddCall("getTailCallHelpers"); + return jitInstance->mc->repGetTailCallHelpers(callToken, sig, flags, pResult); } bool MyICJI::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fMustConvert) @@ -1575,6 +1578,18 @@ bool MyICJI::runWithErrorTrap(void (*function)(void*), void* param) return RunWithErrorTrap(function, param); } +// Ideally we'd just use the copies of this in standardmacros.h +// however, superpmi is missing various other dependencies as well +static size_t ALIGN_UP_SPMI(size_t val, size_t alignment) +{ + return (val + (alignment - 1)) & ~(alignment - 1); +} + +static void* ALIGN_UP_SPMI(void* val, size_t alignment) +{ + return (void*)ALIGN_UP_SPMI((size_t)val, alignment); +} + // get a block of memory for the code, readonly data, and read-write data void MyICJI::allocMem(ULONG hotCodeSize, /* IN */ ULONG coldCodeSize, /* IN */ @@ -1587,13 +1602,46 @@ void MyICJI::allocMem(ULONG hotCodeSize, /* IN */ ) { jitInstance->mc->cr->AddCall("allocMem"); - // TODO-Cleanup: investigate if we need to check roDataBlock as well. Could hot block size be ever 0? + + // TODO-Cleanup: Could hot block size be ever 0? *hotCodeBlock = jitInstance->mc->cr->allocateMemory(hotCodeSize); + if (coldCodeSize > 0) *coldCodeBlock = jitInstance->mc->cr->allocateMemory(coldCodeSize); else *coldCodeBlock = nullptr; - *roDataBlock = jitInstance->mc->cr->allocateMemory(roDataSize); + + if (roDataSize > 0) + { + size_t roDataAlignment = sizeof(void*); + size_t roDataAlignedSize = static_cast(roDataSize); + + if ((flag & CORJIT_ALLOCMEM_FLG_RODATA_32BYTE_ALIGN) != 0) + { + roDataAlignment = 32; + } + else if ((flag & CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN) != 0) + { + roDataAlignment = 16; + } + else if (roDataSize >= 8) + { + roDataAlignment = 8; + } + + // We need to round the roDataSize up to the alignment size and then + // overallocate by at most alignment - sizeof(void*) to ensure that + // we can offset roDataBlock to be an aligned address and that the + // allocation contains at least the originally requested size after + + roDataAlignedSize = ALIGN_UP_SPMI(roDataAlignedSize, roDataAlignment); + roDataAlignedSize = roDataAlignedSize + (roDataAlignment - sizeof(void*)); + *roDataBlock = jitInstance->mc->cr->allocateMemory(roDataAlignedSize); + *roDataBlock = ALIGN_UP_SPMI(*roDataBlock, roDataAlignment); + } + else + *roDataBlock = nullptr; + jitInstance->mc->cr->recAllocMem(hotCodeSize, coldCodeSize, roDataSize, xcptnsCount, flag, hotCodeBlock, coldCodeBlock, roDataBlock); } diff --git a/src/coreclr/src/binder/assemblybinder.cpp b/src/coreclr/src/binder/assemblybinder.cpp index 784b91260ee75d..362c2b867802f5 100644 --- a/src/coreclr/src/binder/assemblybinder.cpp +++ b/src/coreclr/src/binder/assemblybinder.cpp @@ -14,7 +14,6 @@ #include "assemblybinder.hpp" #include "assemblyname.hpp" - #include "assembly.hpp" #include "applicationcontext.hpp" #include "bindertracing.h" @@ -380,23 +379,36 @@ namespace BINDER_SPACE _ASSERTE(ppSystemAssembly != NULL); - StackSString sCoreLibDir(systemDirectory); ReleaseHolder pSystemAssembly; - if (!sCoreLibDir.EndsWith(DIRECTORY_SEPARATOR_CHAR_W)) - { - sCoreLibDir.Append(DIRECTORY_SEPARATOR_CHAR_W); - } + // At run-time, System.Private.CoreLib.dll is expected to be the NI image. + // System.Private.CoreLib.dll is expected to be found at one of the following locations: + // * Non-single-file app: In systemDirectory, beside coreclr.dll + // * Framework-dependent single-file app: In systemDirectory, beside coreclr.dll + // * Self-contained single-file app: Within the single-file bundle. + // + // CoreLib path (sCoreLib): + // * Absolute path when looking for a file on disk + // * Bundle-relative path when looking within the single-file bundle. + StackSString sCoreLibName(CoreLibName_IL_W); StackSString sCoreLib; + BinderTracing::PathSource pathSource = BinderTracing::PathSource::Bundle; + BundleFileLocation bundleFileLocation = Bundle::ProbeAppBundle(sCoreLibName, /*pathIsBundleRelative */ true); + if (!bundleFileLocation.IsValid()) + { + sCoreLib.Set(systemDirectory); + pathSource = BinderTracing::PathSource::ApplicationAssemblies; + } + CombinePath(sCoreLib, sCoreLibName, sCoreLib); - // At run-time, System.Private.CoreLib.dll is expected to be the NI image. - sCoreLib = sCoreLibDir; - sCoreLib.Append(CoreLibName_IL_W); IF_FAIL_GO(AssemblyBinder::GetAssembly(sCoreLib, TRUE /* fIsInGAC */, fBindToNativeImage, - &pSystemAssembly)); + &pSystemAssembly, + NULL /* szMDAssemblyPath */, + bundleFileLocation)); + BinderTracing::PathProbed(sCoreLib, pathSource, hr); *ppSystemAssembly = pSystemAssembly.Extract(); @@ -406,10 +418,10 @@ namespace BINDER_SPACE /* static */ - HRESULT AssemblyBinder::BindToSystemSatellite(SString &systemDirectory, - SString &simpleName, - SString &cultureName, - Assembly **ppSystemAssembly) + HRESULT AssemblyBinder::BindToSystemSatellite(SString& systemDirectory, + SString& simpleName, + SString& cultureName, + Assembly** ppSystemAssembly) { // Indirect check that binder was initialized. _ASSERTE(g_BinderVariables != NULL); @@ -418,25 +430,43 @@ namespace BINDER_SPACE _ASSERTE(ppSystemAssembly != NULL); - StackSString sMscorlibSatellite(systemDirectory); - ReleaseHolder pSystemAssembly; + // Satellite assembly's relative path + StackSString relativePath; // append culture name if (!cultureName.IsEmpty()) { - CombinePath(sMscorlibSatellite, cultureName, sMscorlibSatellite); + CombinePath(relativePath, cultureName, relativePath); } // append satellite assembly's simple name - CombinePath(sMscorlibSatellite, simpleName, sMscorlibSatellite); + CombinePath(relativePath, simpleName, relativePath); // append extension - sMscorlibSatellite.Append(W(".dll")); + relativePath.Append(W(".dll")); + // Satellite assembly's path: + // * Absolute path when looking for a file on disk + // * Bundle-relative path when looking within the single-file bundle. + StackSString sMscorlibSatellite; + + BinderTracing::PathSource pathSource = BinderTracing::PathSource::Bundle; + BundleFileLocation bundleFileLocation = Bundle::ProbeAppBundle(relativePath, /*pathIsBundleRelative */ true); + if (!bundleFileLocation.IsValid()) + { + sMscorlibSatellite.Set(systemDirectory); + pathSource = BinderTracing::PathSource::ApplicationAssemblies; + } + CombinePath(sMscorlibSatellite, relativePath, sMscorlibSatellite); + + ReleaseHolder pSystemAssembly; IF_FAIL_GO(AssemblyBinder::GetAssembly(sMscorlibSatellite, TRUE /* fIsInGAC */, FALSE /* fExplicitBindToNativeImage */, - &pSystemAssembly)); + &pSystemAssembly, + NULL /* szMDAssemblyPath */, + bundleFileLocation)); + BinderTracing::PathProbed(sMscorlibSatellite, pathSource, hr); *ppSystemAssembly = pSystemAssembly.Extract(); @@ -553,7 +583,9 @@ namespace BINDER_SPACE // specified. Generally only NGEN PDB generation has // this TRUE. fExplicitBindToNativeImage, - &pAssembly)); + &pAssembly, + NULL /* szMDAssemblyPath */, + Bundle::ProbeAppBundle(assemblyPath))); AssemblyName *pAssemblyName; pAssemblyName = pAssembly->GetAssemblyName(); @@ -721,36 +753,75 @@ namespace BINDER_SPACE namespace { - typedef void (*OnPathProbed)(const WCHAR *path, HRESULT hr); - - HRESULT BindSatelliteResourceByProbingPaths( - const StringArrayList *pResourceRoots, - AssemblyName *pRequestedAssemblyName, - BindResult *pBindResult, - OnPathProbed onPathProbed) + HRESULT BindSatelliteResourceFromBundle( + AssemblyName* pRequestedAssemblyName, + SString &relativePath, + BindResult* pBindResult) { HRESULT hr = S_OK; - SString &simpleNameRef = pRequestedAssemblyName->GetSimpleName(); - SString &cultureRef = pRequestedAssemblyName->GetCulture(); + BundleFileLocation bundleFileLocation = Bundle::ProbeAppBundle(relativePath, /* pathIsBundleRelative */ true); + if (!bundleFileLocation.IsValid()) + { + return hr; + } - _ASSERTE(!cultureRef.IsEmpty() && !cultureRef.EqualsCaseInsensitive(g_BinderVariables->cultureNeutral)); + ReleaseHolder pAssembly; + hr = AssemblyBinder::GetAssembly(relativePath, + FALSE /* fIsInGAC */, + FALSE /* fExplicitBindToNativeImage */, + &pAssembly, + NULL, // szMDAssemblyPath + bundleFileLocation); + + BinderTracing::PathProbed(relativePath, BinderTracing::PathSource::Bundle, hr); + + // Missing files are okay and expected when probing + if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) + { + return S_OK; + } + + pBindResult->SetAttemptResult(hr, pAssembly); + if (FAILED(hr)) + return hr; + + AssemblyName* pBoundAssemblyName = pAssembly->GetAssemblyName(); + if (TestCandidateRefMatchesDef(pRequestedAssemblyName, pBoundAssemblyName, false /*tpaListAssembly*/)) + { + pBindResult->SetResult(pAssembly); + hr = S_OK; + } + else + { + hr = FUSION_E_REF_DEF_MISMATCH; + } + + pBindResult->SetAttemptResult(hr, pAssembly); + return hr; + } + + HRESULT BindSatelliteResourceByProbingPaths( + const StringArrayList *pResourceRoots, + AssemblyName *pRequestedAssemblyName, + SString &relativePath, + BindResult *pBindResult, + BinderTracing::PathSource pathSource) + { + HRESULT hr = S_OK; for (UINT i = 0; i < pResourceRoots->GetCount(); i++) { ReleaseHolder pAssembly; SString &wszBindingPath = (*pResourceRoots)[i]; SString fileName(wszBindingPath); - - CombinePath(fileName, cultureRef, fileName); - CombinePath(fileName, simpleNameRef, fileName); - fileName.Append(W(".dll")); + CombinePath(fileName, relativePath, fileName); hr = AssemblyBinder::GetAssembly(fileName, FALSE /* fIsInGAC */, FALSE /* fExplicitBindToNativeImage */, &pAssembly); - onPathProbed(fileName, hr); + BinderTracing::PathProbed(fileName, pathSource, hr); // Missing files are okay and expected when probing if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) @@ -781,6 +852,59 @@ namespace BINDER_SPACE return S_OK; } + HRESULT BindSatelliteResource( + ApplicationContext* pApplicationContext, + AssemblyName* pRequestedAssemblyName, + BindResult* pBindResult) + { + // Satellite resource probing strategy is to look: + // * First within the single-file bundle + // * Then under each of the Platform Resource Roots + // * Then under each of the App Paths. + // + // During each search, if we find a platform resource file with matching file name, but whose ref-def didn't match, + // fall back to application resource lookup to handle case where a user creates resources with the same + // names as platform ones. + + HRESULT hr = S_OK; + SString& simpleNameRef = pRequestedAssemblyName->GetSimpleName(); + SString& cultureRef = pRequestedAssemblyName->GetCulture(); + + _ASSERTE(!cultureRef.IsEmpty() && !cultureRef.EqualsCaseInsensitive(g_BinderVariables->cultureNeutral)); + + ReleaseHolder pAssembly; + SString fileName; + CombinePath(fileName, cultureRef, fileName); + CombinePath(fileName, simpleNameRef, fileName); + fileName.Append(W(".dll")); + + hr = BindSatelliteResourceFromBundle(pRequestedAssemblyName, fileName, pBindResult); + + if (pBindResult->HaveResult() || (FAILED(hr) && hr != FUSION_E_CONFIGURATION_ERROR)) + { + return hr; + } + + hr = BindSatelliteResourceByProbingPaths(pApplicationContext->GetPlatformResourceRoots(), + pRequestedAssemblyName, + fileName, + pBindResult, + BinderTracing::PathSource::PlatformResourceRoots); + + if (pBindResult->HaveResult() || (FAILED(hr) && hr != FUSION_E_CONFIGURATION_ERROR)) + { + return hr; + } + + hr = BindSatelliteResourceByProbingPaths(pApplicationContext->GetAppPaths(), + pRequestedAssemblyName, + fileName, + pBindResult, + BinderTracing::PathSource::AppPaths); + + return hr; + } + HRESULT BindAssemblyByProbingPaths( const StringArrayList *pBindingPaths, AssemblyName *pRequestedAssemblyName, @@ -788,7 +912,6 @@ namespace BINDER_SPACE Assembly **ppAssembly) { SString &simpleName = pRequestedAssemblyName->GetSimpleName(); - BinderTracing::PathSource pathSource = useNativeImages ? BinderTracing::PathSource::AppNativeImagePaths : BinderTracing::PathSource::AppPaths; // Loop through the binding paths looking for a matching assembly for (DWORD i = 0; i < pBindingPaths->GetCount(); i++) @@ -850,6 +973,13 @@ namespace BINDER_SPACE /* * BindByTpaList is the entry-point for the custom binding algorithm in CoreCLR. + * + * The search for assemblies will proceed in the following order: + * + * If this application is a single-file bundle, the meta-data contained in the bundle + * will be probed to find the requested assembly. If the assembly is not found, + * The list of platform assemblies (TPAs) are considered next. + * * Platform assemblies are specified as a list of files. This list is the only set of * assemblies that we will load as platform. They can be specified as IL or NIs. * @@ -875,39 +1005,65 @@ namespace BINDER_SPACE if (!culture.IsEmpty() && !culture.EqualsCaseInsensitive(g_BinderVariables->cultureNeutral)) { - // - // Satellite resource probing strategy is to look under each of the Platform Resource Roots - // followed by App Paths. - // + IF_FAIL_GO(BindSatelliteResource(pApplicationContext, pRequestedAssemblyName, pBindResult)); + } + else + { + ReleaseHolder pTPAAssembly; + SString& simpleName = pRequestedAssemblyName->GetSimpleName(); + + // Is assembly in the bundle? + // Single-file bundle contents take precedence over TPA. + // The list of bundled assemblies is contained in the bundle manifest, and NOT in the TPA. + // Therefore the bundle is first probed using the assembly's simple name. + // If found, the assembly is loaded from the bundle. + if (Bundle::AppIsBundle()) + { + // Search Assembly.ni.dll, then Assembly.dll + // The Assembly.ni.dll paths are rare, and intended for supporting managed C++ R2R assemblies. + SString candidates[] = { W(".ni.dll"), W(".dll") }; - hr = BindSatelliteResourceByProbingPaths(pApplicationContext->GetPlatformResourceRoots(), - pRequestedAssemblyName, - pBindResult, - [](const WCHAR *path, HRESULT res) { BinderTracing::PathProbed(path, BinderTracing::PathSource::PlatformResourceRoots, res); }); + // Loop through the binding paths looking for a matching assembly + for (int i = 0; i < 2; i++) + { + SString assemblyFileName(simpleName); + assemblyFileName.Append(candidates[i]); - // We found a platform resource file with matching file name, but whose ref-def didn't match. Fall - // back to application resource lookup to handle case where a user creates resources with the same - // names as platform ones. - if (hr != FUSION_E_CONFIGURATION_ERROR) - { - IF_FAIL_GO(hr); - } + SString assemblyFilePath(Bundle::AppBundle->BasePath()); + assemblyFilePath.Append(assemblyFileName); - if (!pBindResult->HaveResult()) - { - IF_FAIL_GO(BindSatelliteResourceByProbingPaths(pApplicationContext->GetAppPaths(), - pRequestedAssemblyName, - pBindResult, - [](const WCHAR *path, HRESULT res) { BinderTracing::PathProbed(path, BinderTracing::PathSource::AppPaths, res); })); + BundleFileLocation bundleFileLocation = Bundle::ProbeAppBundle(assemblyFileName, /* pathIsBundleRelative */ true); + if (bundleFileLocation.IsValid()) + { + hr = GetAssembly(assemblyFilePath, + TRUE, // fIsInGAC + FALSE, // fExplicitBindToNativeImage + &pTPAAssembly, + NULL, // szMDAssemblyPath + bundleFileLocation); + + BinderTracing::PathProbed(assemblyFilePath, BinderTracing::PathSource::Bundle, hr); + + if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) + { + // Any other error is fatal + IF_FAIL_GO(hr); + + if (TestCandidateRefMatchesDef(pRequestedAssemblyName, pTPAAssembly->GetAssemblyName(), true /*tpaListAssembly*/)) + { + // We have found the requested assembly match in the bundle with validation of the full-qualified name. + // Bind to it. + pBindResult->SetResult(pTPAAssembly); + GO_WITH_HRESULT(S_OK); + } + } + } + } } - } - else - { + // Is assembly on TPA list? - SString &simpleName = pRequestedAssemblyName->GetSimpleName(); SimpleNameToFileNameMap * tpaMap = pApplicationContext->GetTpaList(); const SimpleNameToFileNameMapEntry *pTpaEntry = tpaMap->LookupPtr(simpleName.GetUnicode()); - ReleaseHolder pTPAAssembly; if (pTpaEntry != nullptr) { if (pTpaEntry->m_wszNIFileName != nullptr) @@ -1020,20 +1176,21 @@ namespace BINDER_SPACE } /* static */ - HRESULT AssemblyBinder::GetAssembly(SString &assemblyPath, - BOOL fIsInGAC, + HRESULT AssemblyBinder::GetAssembly(SString &assemblyPath, + BOOL fIsInGAC, // When binding to the native image, should we // assume assemblyPath explicitly specifies that // NI? (If not, infer the path to the NI // implicitly.) - BOOL fExplicitBindToNativeImage, + BOOL fExplicitBindToNativeImage, - Assembly **ppAssembly, + Assembly **ppAssembly, // If assemblyPath refers to a native image without metadata, // szMDAssemblyPath gives the alternative file to get metadata. - LPCTSTR szMDAssemblyPath) + LPCTSTR szMDAssemblyPath, + BundleFileLocation bundleFileLocation) { HRESULT hr = S_OK; @@ -1053,7 +1210,7 @@ namespace BINDER_SPACE { LPCTSTR szAssemblyPath = const_cast(assemblyPath.GetUnicode()); - hr = BinderAcquirePEImage(szAssemblyPath, &pPEImage, &pNativePEImage, fExplicitBindToNativeImage); + hr = BinderAcquirePEImage(szAssemblyPath, &pPEImage, &pNativePEImage, fExplicitBindToNativeImage, bundleFileLocation); IF_FAIL_GO(hr); // If we found a native image, it might be an MSIL assembly masquerading as an native image @@ -1068,7 +1225,7 @@ namespace BINDER_SPACE BinderReleasePEImage(pPEImage); BinderReleasePEImage(pNativePEImage); - hr = BinderAcquirePEImage(szAssemblyPath, &pPEImage, &pNativePEImage, false); + hr = BinderAcquirePEImage(szAssemblyPath, &pPEImage, &pNativePEImage, false, bundleFileLocation); IF_FAIL_GO(hr); } } @@ -1094,7 +1251,7 @@ namespace BINDER_SPACE } else { - hr = BinderAcquirePEImage(szMDAssemblyPath, &pPEImage, NULL, FALSE); + hr = BinderAcquirePEImage(szMDAssemblyPath, &pPEImage, NULL, FALSE, bundleFileLocation); IF_FAIL_GO(hr); hr = BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, FALSE); diff --git a/src/coreclr/src/binder/clrprivbinderassemblyloadcontext.cpp b/src/coreclr/src/binder/clrprivbinderassemblyloadcontext.cpp index 0881af5c599832..8c1ae4060a6154 100644 --- a/src/coreclr/src/binder/clrprivbinderassemblyloadcontext.cpp +++ b/src/coreclr/src/binder/clrprivbinderassemblyloadcontext.cpp @@ -250,12 +250,11 @@ void CLRPrivBinderAssemblyLoadContext::PrepareForLoadContextRelease(INT_PTR ptrM } CONTRACTL_END; - // Replace the weak handle with a strong handle so that the managed assembly load context stays alive until the + // Add a strong handle so that the managed assembly load context stays alive until the // CLRPrivBinderAssemblyLoadContext::ReleaseLoadContext is called. - OBJECTHANDLE handle = reinterpret_cast(m_ptrManagedAssemblyLoadContext); - OBJECTHANDLE strongHandle = reinterpret_cast(ptrManagedStrongAssemblyLoadContext); - DestroyLongWeakHandle(handle); - m_ptrManagedAssemblyLoadContext = reinterpret_cast(strongHandle); + // We keep the weak handle as well since this method can be running on one thread (e.g. the finalizer one) + // and other thread can be using the weak handle. + m_ptrManagedStrongAssemblyLoadContext = ptrManagedStrongAssemblyLoadContext; _ASSERTE(m_pAssemblyLoaderAllocator != NULL); _ASSERTE(m_loaderAllocatorHandle != NULL); @@ -274,15 +273,19 @@ void CLRPrivBinderAssemblyLoadContext::PrepareForLoadContextRelease(INT_PTR ptrM CLRPrivBinderAssemblyLoadContext::CLRPrivBinderAssemblyLoadContext() { m_pTPABinder = NULL; + m_ptrManagedStrongAssemblyLoadContext = NULL; } void CLRPrivBinderAssemblyLoadContext::ReleaseLoadContext() { VERIFY(m_ptrManagedAssemblyLoadContext != NULL); + VERIFY(m_ptrManagedStrongAssemblyLoadContext != NULL); - // This method is called to release the strong handle on the managed AssemblyLoadContext + // This method is called to release the weak and strong handles on the managed AssemblyLoadContext // once the Unloading event has been fired OBJECTHANDLE handle = reinterpret_cast(m_ptrManagedAssemblyLoadContext); + DestroyLongWeakHandle(handle); + handle = reinterpret_cast(m_ptrManagedStrongAssemblyLoadContext); DestroyHandle(handle); m_ptrManagedAssemblyLoadContext = NULL; } diff --git a/src/coreclr/src/binder/coreclrbindercommon.cpp b/src/coreclr/src/binder/coreclrbindercommon.cpp index afd64cfc4dc582..e415b9067bb34a 100644 --- a/src/coreclr/src/binder/coreclrbindercommon.cpp +++ b/src/coreclr/src/binder/coreclrbindercommon.cpp @@ -7,6 +7,7 @@ #include "assemblybinder.hpp" #include "coreclrbindercommon.h" #include "clrprivbindercoreclr.h" +#include "bundle.h" using namespace BINDER_SPACE; diff --git a/src/coreclr/src/binder/inc/assembly.hpp b/src/coreclr/src/binder/inc/assembly.hpp index 0d5500afb82032..f42cee4e622687 100644 --- a/src/coreclr/src/binder/inc/assembly.hpp +++ b/src/coreclr/src/binder/inc/assembly.hpp @@ -27,15 +27,18 @@ #include "clrprivbinderassemblyloadcontext.h" #endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) -STDAPI BinderAcquirePEImage(LPCTSTR szAssemblyPath, - PEImage **ppPEImage, - PEImage **ppNativeImage, - BOOL fExplicitBindToNativeImage); - -STDAPI BinderAcquireImport(PEImage *pPEImage, - IMDInternalImport **pIMetaDataAssemblyImport, - DWORD *pdwPAFlags, - BOOL bNativeImage); +#include "bundle.h" + +STDAPI BinderAcquirePEImage(LPCTSTR szAssemblyPath, + PEImage **ppPEImage, + PEImage **ppNativeImage, + BOOL fExplicitBindToNativeImage, + BundleFileLocation bundleFileLocation); + +STDAPI BinderAcquireImport(PEImage *pPEImage, + IMDInternalImport **pIMetaDataAssemblyImport, + DWORD *pdwPAFlags, + BOOL bNativeImage); STDAPI BinderHasNativeHeader(PEImage *pPEImage, BOOL *result); diff --git a/src/coreclr/src/binder/inc/assemblybinder.hpp b/src/coreclr/src/binder/inc/assemblybinder.hpp index 1332b671edc2dd..5246676b1a47f3 100644 --- a/src/coreclr/src/binder/inc/assemblybinder.hpp +++ b/src/coreclr/src/binder/inc/assemblybinder.hpp @@ -18,6 +18,7 @@ #include "bindertypes.hpp" #include "bindresult.hpp" #include "coreclrbindercommon.h" +#include "bundle.h" class CLRPrivBinderAssemblyLoadContext; class CLRPrivBinderCoreCLR; @@ -54,7 +55,8 @@ namespace BINDER_SPACE /* in */ BOOL fIsInGAC, /* in */ BOOL fExplicitBindToNativeImage, /* out */ Assembly **ppAssembly, - /* in */ LPCTSTR szMDAssemblyPath = NULL); + /* in */ LPCTSTR szMDAssemblyPath = NULL, + /* in */ BundleFileLocation bundleFileLocation = BundleFileLocation::Invalid()); #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) static HRESULT BindUsingHostAssemblyResolver (/* in */ INT_PTR pManagedAssemblyLoadContextToBindWithin, diff --git a/src/coreclr/src/binder/inc/bindertracing.h b/src/coreclr/src/binder/inc/bindertracing.h index 472197bf5b4e39..6fb5137349e026 100644 --- a/src/coreclr/src/binder/inc/bindertracing.h +++ b/src/coreclr/src/binder/inc/bindertracing.h @@ -180,7 +180,8 @@ namespace BinderTracing AppNativeImagePaths, AppPaths, PlatformResourceRoots, - SatelliteSubdirectory + SatelliteSubdirectory, + Bundle }; void PathProbed(const WCHAR *path, PathSource source, HRESULT hr); diff --git a/src/coreclr/src/binder/inc/clrprivbinderassemblyloadcontext.h b/src/coreclr/src/binder/inc/clrprivbinderassemblyloadcontext.h index 09695b09fc0108..546779e3f435d7 100644 --- a/src/coreclr/src/binder/inc/clrprivbinderassemblyloadcontext.h +++ b/src/coreclr/src/binder/inc/clrprivbinderassemblyloadcontext.h @@ -78,7 +78,13 @@ class CLRPrivBinderAssemblyLoadContext : public AssemblyLoadContext CLRPrivBinderCoreCLR *m_pTPABinder; + // A long weak GC handle to the managed AssemblyLoadContext INT_PTR m_ptrManagedAssemblyLoadContext; + // A strong GC handle to the managed AssemblyLoadContext. This handle is set when the unload of the AssemblyLoadContext is initiated + // to keep the managed AssemblyLoadContext alive until the unload is finished. + // We still keep the weak handle pointing to the same managed AssemblyLoadContext so that native code can use the handle above + // to refer to it during the whole lifetime of the AssemblyLoadContext. + INT_PTR m_ptrManagedStrongAssemblyLoadContext; LoaderAllocator* m_pAssemblyLoaderAllocator; void* m_loaderAllocatorHandle; diff --git a/src/coreclr/src/binder/utils.cpp b/src/coreclr/src/binder/utils.cpp index 27f1d4c6b3f6d9..953da35d8ffa3f 100644 --- a/src/coreclr/src/binder/utils.cpp +++ b/src/coreclr/src/binder/utils.cpp @@ -80,7 +80,7 @@ namespace BINDER_SPACE SString platformPathSeparator(SString::Literal, GetPlatformPathSeparator()); combinedPath.Set(pathA); - if (!combinedPath.EndsWith(platformPathSeparator)) + if (!combinedPath.IsEmpty() && !combinedPath.EndsWith(platformPathSeparator)) { combinedPath.Append(platformPathSeparator); } diff --git a/src/coreclr/src/build.proj b/src/coreclr/src/build.proj deleted file mode 100644 index ad5ff6e63a70a2..00000000000000 --- a/src/coreclr/src/build.proj +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - true - false - - - - - - - - - - - - diff --git a/src/coreclr/src/classlibnative/bcltype/stringnative.h b/src/coreclr/src/classlibnative/bcltype/stringnative.h index 6aea696e41af7f..c8e1fcecc9f352 100644 --- a/src/coreclr/src/classlibnative/bcltype/stringnative.h +++ b/src/coreclr/src/classlibnative/bcltype/stringnative.h @@ -42,10 +42,8 @@ class COMString { public: // - // Search/Query Methods + // Query Methods // - static FCDECL6(INT32, CompareOrdinalEx, StringObject* strA, INT32 indexA, INT32 countA, StringObject* strB, INT32 indexB, INT32 countB); - static FCDECL2(FC_CHAR_RET, GetCharAt, StringObject* pThisRef, INT32 index); static FCDECL1(INT32, Length, StringObject* pThisRef); diff --git a/src/coreclr/src/debug/CMakeLists.txt b/src/coreclr/src/debug/CMakeLists.txt index 03fcc8cc596065..4fd69d9a82adc3 100644 --- a/src/coreclr/src/debug/CMakeLists.txt +++ b/src/coreclr/src/debug/CMakeLists.txt @@ -3,6 +3,9 @@ add_subdirectory(ildbsymlib) add_subdirectory(ee) add_subdirectory(di) add_subdirectory(shim) +if(CLR_CMAKE_HOST_WIN32) + add_subdirectory(createdump) +endif(CLR_CMAKE_HOST_WIN32) if(FEATURE_SINGLE_FILE_DIAGNOSTICS) add_subdirectory(runtimeinfo) endif(FEATURE_SINGLE_FILE_DIAGNOSTICS) diff --git a/src/coreclr/src/debug/createdump/CMakeLists.txt b/src/coreclr/src/debug/createdump/CMakeLists.txt index f642159fb705ba..0915212448e6d8 100644 --- a/src/coreclr/src/debug/createdump/CMakeLists.txt +++ b/src/coreclr/src/debug/createdump/CMakeLists.txt @@ -2,53 +2,77 @@ project(createdump) set(CMAKE_INCLUDE_CURRENT_DIR ON) -include(configure.cmake) - -# Set the RPATH of createdump so that it can find dependencies without needing to set LD_LIBRARY_PATH -# For more information: http://www.cmake.org/Wiki/CMake_RPATH_handling. -if (CORECLR_SET_RPATH) - set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) - if(CLR_CMAKE_HOST_OSX) - set(CMAKE_INSTALL_RPATH "@loader_path") - else() - set(CMAKE_INSTALL_RPATH "\$ORIGIN") - endif(CLR_CMAKE_HOST_OSX) -endif (CORECLR_SET_RPATH) +include_directories(BEFORE ${VM_DIR}) remove_definitions(-DUNICODE) remove_definitions(-D_UNICODE) -include_directories(BEFORE ${VM_DIR}) +if(CLR_CMAKE_HOST_WIN32) + + set(CREATEDUMP_SOURCES + main.cpp + createdumpwindows.cpp + createdump.rc + ) + + _add_executable(createdump + ${CREATEDUMP_SOURCES} + ) + + target_link_libraries(createdump + kernel32.lib + ${STATIC_MT_CRT_LIB} + advapi32.lib + version.lib + dbghelp.lib + ) + +else(CLR_CMAKE_HOST_WIN32) + + include(configure.cmake) + + # Set the RPATH of createdump so that it can find dependencies without needing to set LD_LIBRARY_PATH + # For more information: http://www.cmake.org/Wiki/CMake_RPATH_handling. + if (CORECLR_SET_RPATH) + set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + if(CLR_CMAKE_HOST_OSX) + set(CMAKE_INSTALL_RPATH "@loader_path") + else() + set(CMAKE_INSTALL_RPATH "\$ORIGIN") + endif(CLR_CMAKE_HOST_OSX) + endif (CORECLR_SET_RPATH) + + add_definitions(-DPAL_STDCPP_COMPAT) -add_definitions(-DPAL_STDCPP_COMPAT) + set(CREATEDUMP_SOURCES + createdump.cpp + crashinfo.cpp + threadinfo.cpp + datatarget.cpp + dumpwriter.cpp + ) -set(CREATEDUMP_SOURCES - createdump.cpp - crashinfo.cpp - threadinfo.cpp - datatarget.cpp - dumpwriter.cpp -) + _add_library(createdump_lib + ${CREATEDUMP_SOURCES} + ) -_add_library(createdump_lib - ${CREATEDUMP_SOURCES} -) + _add_executable(createdump + main.cpp + ${PAL_REDEFINES_FILE} + ) -_add_executable(createdump - main.cpp - ${PAL_REDEFINES_FILE} -) + add_dependencies(createdump pal_redefines_file) -add_dependencies(createdump pal_redefines_file) + target_link_libraries(createdump + createdump_lib + corguids + dbgutil + # share the PAL in the dac module + mscordaccore + ) -target_link_libraries(createdump - createdump_lib - corguids - dbgutil - # share the PAL in the dac module - mscordaccore -) + add_dependencies(createdump mscordaccore) -add_dependencies(createdump mscordaccore) +endif(CLR_CMAKE_HOST_WIN32) install_clr(TARGETS createdump ADDITIONAL_DESTINATION sharedFramework) diff --git a/src/coreclr/src/debug/createdump/createdump.cpp b/src/coreclr/src/debug/createdump/createdump.cpp index a4a21f4df3c204..8299054d10b4b0 100644 --- a/src/coreclr/src/debug/createdump/createdump.cpp +++ b/src/coreclr/src/debug/createdump/createdump.cpp @@ -7,37 +7,21 @@ bool g_diagnostics = false; // -// The common create dump code +// The Linux create dump code // bool -CreateDumpCommon(const char* dumpPathTemplate, MINIDUMP_TYPE minidumpType, CrashInfo* crashInfo) +CreateDump(const char* dumpPath, int pid, MINIDUMP_TYPE minidumpType) { + ReleaseHolder dataTarget = new DumpDataTarget(pid); + ReleaseHolder crashInfo = new CrashInfo(pid, dataTarget, false); ReleaseHolder dumpWriter = new DumpWriter(*crashInfo); bool result = false; - ArrayHolder dumpPath = new char[PATH_MAX]; - snprintf(dumpPath, PATH_MAX, dumpPathTemplate, crashInfo->Pid()); - - const char* dumpType = "minidump"; - switch (minidumpType) + // The initialize the data target's ReadVirtual support (opens /proc/$pid/mem) + if (!dataTarget->Initialize(crashInfo)) { - case MiniDumpWithPrivateReadWriteMemory: - dumpType = "minidump with heap"; - break; - - case MiniDumpFilterTriage: - dumpType = "triage minidump"; - break; - - case MiniDumpWithFullMemory: - dumpType = "full dump"; - break; - - default: - break; + goto exit; } - printf("Writing %s to file %s\n", dumpType, (char*)dumpPath); - // Suspend all the threads in the target process and build the list of threads if (!crashInfo->EnumerateAndSuspendThreads()) { @@ -61,13 +45,3 @@ CreateDumpCommon(const char* dumpPathTemplate, MINIDUMP_TYPE minidumpType, Crash crashInfo->ResumeThreads(); return result; } - -// -// Entry point for SOS createdump command -// -bool -CreateDumpForSOS(const char* programPath, const char* dumpPathTemplate, pid_t pid, MINIDUMP_TYPE minidumpType, ICLRDataTarget* dataTarget) -{ - ReleaseHolder crashInfo = new CrashInfo(pid, dataTarget, true); - return CreateDumpCommon(dumpPathTemplate, minidumpType, crashInfo); -} diff --git a/src/coreclr/src/debug/createdump/createdump.h b/src/coreclr/src/debug/createdump/createdump.h index 7627fb6e8611b2..96afcab29199cf 100644 --- a/src/coreclr/src/debug/createdump/createdump.h +++ b/src/coreclr/src/debug/createdump/createdump.h @@ -11,16 +11,22 @@ extern bool g_diagnostics; +#ifdef HOST_UNIX #define TRACE(args...) \ if (g_diagnostics) { \ printf(args); \ } +#else +#define TRACE(args, ...) +#endif +#ifdef HOST_UNIX #include "config.h" +#endif +#include #include #include -#include #include #include #include @@ -34,11 +40,12 @@ extern bool g_diagnostics; #include #include #include -#include typedef int T_CONTEXT; #include #include #include +#ifdef HOST_UNIX +#include #include #include #include @@ -56,13 +63,24 @@ typedef int T_CONTEXT; #include #define __STDC_FORMAT_MACROS #include +#else +#include +#endif #include #include #include #include #include +#ifdef HOST_UNIX #include "datatarget.h" #include "threadinfo.h" #include "memoryregion.h" #include "crashinfo.h" #include "dumpwriter.h" +#endif + +#ifndef MAX_LONGPATH +#define MAX_LONGPATH 1024 +#endif + +bool CreateDump(const char* dumpPathTemplate, int pid, MINIDUMP_TYPE minidumpType); diff --git a/src/coreclr/src/debug/createdump/createdump.rc b/src/coreclr/src/debug/createdump/createdump.rc new file mode 100644 index 00000000000000..f5319668e3395d --- /dev/null +++ b/src/coreclr/src/debug/createdump/createdump.rc @@ -0,0 +1,8 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#define FX_VER_FILEDESCRIPTION_STR "Microsoft .NET Runtime Crash Dump Generator\0" + +#include +#include diff --git a/src/coreclr/src/debug/createdump/createdumpwindows.cpp b/src/coreclr/src/debug/createdump/createdumpwindows.cpp new file mode 100644 index 00000000000000..d806330724eb0a --- /dev/null +++ b/src/coreclr/src/debug/createdump/createdumpwindows.cpp @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "createdump.h" + +bool g_diagnostics = false; + +// +// The Windows create dump code +// +bool +CreateDump(const char* dumpPath, int pid, MINIDUMP_TYPE minidumpType) +{ + HANDLE hFile = INVALID_HANDLE_VALUE; + HANDLE hProcess = NULL; + bool result = false; + + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); + if (hProcess == NULL) + { + fprintf(stderr, "Invalid process id '%d' error %d\n", pid, GetLastError()); + goto exit; + } + + hFile = CreateFileA(dumpPath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "Invalid dump path '%s' error %d\n", dumpPath, GetLastError()); + goto exit; + } + + // Retry the write dump on ERROR_PARTIAL_COPY + for (int i = 0; i < 5; i++) + { + if (MiniDumpWriteDump(hProcess, pid, hFile, minidumpType, NULL, NULL, NULL)) + { + result = true; + break; + } + else + { + int err = GetLastError(); + if (err != HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY)) + { + fprintf(stderr, "Write dump FAILED 0x%08x\n", err); + break; + } + } + } + +exit: + if (hProcess != NULL) + { + CloseHandle(hProcess); + } + + if (hFile != INVALID_HANDLE_VALUE) + { + CloseHandle(hFile); + } + + return result; +} diff --git a/src/coreclr/src/debug/createdump/main.cpp b/src/coreclr/src/debug/createdump/main.cpp index ab853be62fbc97..dab69df6305782 100644 --- a/src/coreclr/src/debug/createdump/main.cpp +++ b/src/coreclr/src/debug/createdump/main.cpp @@ -4,32 +4,48 @@ #include "createdump.h" +#ifdef HOST_WINDOWS +#define DEFAULT_DUMP_PATH "%TEMP%\\" +#define DEFAULT_DUMP_TEMPLATE "dump.%d.dmp" +#else +#define DEFAULT_DUMP_PATH "/tmp/" +#define DEFAULT_DUMP_TEMPLATE "coredump.%d" +#endif + const char* g_help = "createdump [options] pid\n" -"-f, --name - dump path and file name. The pid can be placed in the name with %d. The default is '/tmp/coredump.%d'\n" +"-f, --name - dump path and file name. The pid can be placed in the name with %d. The default is '" DEFAULT_DUMP_PATH DEFAULT_DUMP_TEMPLATE "'\n" "-n, --normal - create minidump.\n" "-h, --withheap - create minidump with heap (default).\n" "-t, --triage - create triage minidump.\n" "-u, --full - create full core dump.\n" "-d, --diag - enable diagnostic messages.\n"; -bool CreateDumpCommon(const char* dumpPathTemplate, MINIDUMP_TYPE minidumpType, CrashInfo* crashInfo); +bool CreateDump(const char* dumpPathTemplate, int pid, MINIDUMP_TYPE minidumpType); // // Main entry point // int __cdecl main(const int argc, const char* argv[]) { - MINIDUMP_TYPE minidumpType = MiniDumpWithPrivateReadWriteMemory; + MINIDUMP_TYPE minidumpType = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory | + MiniDumpWithDataSegs | + MiniDumpWithHandleData | + MiniDumpWithUnloadedModules | + MiniDumpWithFullMemoryInfo | + MiniDumpWithThreadInfo | + MiniDumpWithTokenInformation); const char* dumpPathTemplate = nullptr; - pid_t pid = 0; + int exitCode = 0; + int pid = 0; - int exitCode = PAL_InitializeDLL(); +#ifdef HOST_UNIX + exitCode = PAL_InitializeDLL(); if (exitCode != 0) { fprintf(stderr, "PAL initialization FAILED %d\n", exitCode); return exitCode; } - +#endif // Parse the command line options and target pid argv++; @@ -43,26 +59,40 @@ int __cdecl main(const int argc, const char* argv[]) } else if ((strcmp(*argv, "-n") == 0) || (strcmp(*argv, "--normal") == 0)) { - minidumpType = MiniDumpNormal; + minidumpType = (MINIDUMP_TYPE)(MiniDumpNormal | + MiniDumpWithThreadInfo); } else if ((strcmp(*argv, "-h") == 0) || (strcmp(*argv, "--withheap") == 0)) { - minidumpType = MiniDumpWithPrivateReadWriteMemory; + minidumpType = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory | + MiniDumpWithDataSegs | + MiniDumpWithHandleData | + MiniDumpWithUnloadedModules | + MiniDumpWithFullMemoryInfo | + MiniDumpWithThreadInfo | + MiniDumpWithTokenInformation); } else if ((strcmp(*argv, "-t") == 0) || (strcmp(*argv, "--triage") == 0)) { - minidumpType = MiniDumpFilterTriage; + minidumpType = (MINIDUMP_TYPE)(MiniDumpFilterTriage | + MiniDumpWithThreadInfo); } else if ((strcmp(*argv, "-u") == 0) || (strcmp(*argv, "--full") == 0)) { - minidumpType = MiniDumpWithFullMemory; + minidumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | + MiniDumpWithDataSegs | + MiniDumpWithHandleData | + MiniDumpWithUnloadedModules | + MiniDumpWithFullMemoryInfo | + MiniDumpWithThreadInfo | + MiniDumpWithTokenInformation); } else if ((strcmp(*argv, "-d") == 0) || (strcmp(*argv, "--diag") == 0)) { g_diagnostics = true; } else { - pid = atoll(*argv); + pid = atoi(*argv); } argv++; } @@ -70,15 +100,17 @@ int __cdecl main(const int argc, const char* argv[]) if (pid != 0) { + ArrayHolder tmpPath = new char[MAX_LONGPATH]; + ArrayHolder dumpPath = new char[MAX_LONGPATH]; + if (dumpPathTemplate == nullptr) { - char tmpPath[MAX_LONGPATH]; if (::GetTempPathA(MAX_LONGPATH, tmpPath) == 0) { fprintf(stderr, "GetTempPath failed (0x%08x)", ::GetLastError()); return ::GetLastError(); } - exitCode = strcat_s(tmpPath, MAX_LONGPATH, "coredump.%d"); + exitCode = strcat_s(tmpPath, MAX_LONGPATH, DEFAULT_DUMP_TEMPLATE); if (exitCode != 0) { fprintf(stderr, "strcat_s failed (%d)", exitCode); @@ -86,16 +118,32 @@ int __cdecl main(const int argc, const char* argv[]) } dumpPathTemplate = tmpPath; } - ReleaseHolder dataTarget = new DumpDataTarget(pid); - ReleaseHolder crashInfo = new CrashInfo(pid, dataTarget, false); - // The initialize the data target's ReadVirtual support (opens /proc/$pid/mem) - if (dataTarget->Initialize(crashInfo)) + snprintf(dumpPath, MAX_LONGPATH, dumpPathTemplate, pid); + + const char* dumpType = "minidump"; + switch (minidumpType) { - if (!CreateDumpCommon(dumpPathTemplate, minidumpType, crashInfo)) - { - exitCode = -1; - } + case MiniDumpWithPrivateReadWriteMemory: + dumpType = "minidump with heap"; + break; + + case MiniDumpFilterTriage: + dumpType = "triage minidump"; + break; + + case MiniDumpWithFullMemory: + dumpType = "full dump"; + break; + + default: + break; + } + printf("Writing %s to file %s\n", dumpType, (char*)dumpPath); + + if (CreateDump(dumpPath, pid, minidumpType)) + { + printf("Dump successfully written\n"); } else { @@ -108,6 +156,8 @@ int __cdecl main(const int argc, const char* argv[]) fprintf(stderr, "%s", g_help); exitCode = -1; } +#ifdef HOST_UNIX PAL_TerminateEx(exitCode); +#endif return exitCode; } diff --git a/src/coreclr/src/debug/daccess/CMakeLists.txt b/src/coreclr/src/debug/daccess/CMakeLists.txt index b56c37c623e872..b683d762885b47 100644 --- a/src/coreclr/src/debug/daccess/CMakeLists.txt +++ b/src/coreclr/src/debug/daccess/CMakeLists.txt @@ -5,6 +5,7 @@ include_directories(BEFORE ${VM_DIR}/${ARCH_SOURCES_DIR}) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CLR_DIR}/src/debug/ee) include_directories(${CLR_DIR}/src/gcdump) +include_directories(${CLR_DIR}/src/interop/inc) if(CLR_CMAKE_HOST_UNIX) include_directories(${GENERATED_INCLUDE_DIR}) @@ -41,7 +42,7 @@ target_precompile_header(TARGET daccess HEADER stdafx.h) add_dependencies(daccess eventing_headers) -if(CLR_CMAKE_HOST_OSX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) +if(CLR_CMAKE_HOST_OSX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) add_definitions(-DUSE_DAC_TABLE_RVA) add_custom_command( @@ -63,4 +64,4 @@ if(CLR_CMAKE_HOST_OSX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) ) add_dependencies(daccess dactablerva_header) -endif(CLR_CMAKE_HOST_OSX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) +endif(CLR_CMAKE_HOST_OSX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) diff --git a/src/coreclr/src/debug/daccess/daccess.cpp b/src/coreclr/src/debug/daccess/daccess.cpp index a05d4f09d0d689..444114587c2ab9 100644 --- a/src/coreclr/src/debug/daccess/daccess.cpp +++ b/src/coreclr/src/debug/daccess/daccess.cpp @@ -8252,7 +8252,7 @@ void CALLBACK DacHandleWalker::EnumCallbackSOS(PTR_UNCHECKED_OBJECTREF handle, u if (param->Type == HNDTYPE_DEPENDENT) data.Secondary = GetDependentHandleSecondary(handle.GetAddr()).GetAddr(); #ifdef FEATURE_COMINTEROP - else if (param->Type == HNDTYPE_WEAK_WINRT) + else if (param->Type == HNDTYPE_WEAK_NATIVE_COM) data.Secondary = HndGetHandleExtraInfo(handle.GetAddr()); #endif // FEATURE_COMINTEROP else diff --git a/src/coreclr/src/debug/daccess/dacdbiimpl.cpp b/src/coreclr/src/debug/daccess/dacdbiimpl.cpp index 905698ad4fd71e..e3152652fb5f90 100644 --- a/src/coreclr/src/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/src/debug/daccess/dacdbiimpl.cpp @@ -7491,8 +7491,8 @@ UINT32 DacRefWalker::GetHandleWalkerMask() if ((mHandleMask & CorHandleWeakRefCount) || (mHandleMask & CorHandleStrongRefCount)) result |= (1 << HNDTYPE_REFCOUNTED); - if (mHandleMask & CorHandleWeakWinRT) - result |= (1 << HNDTYPE_WEAK_WINRT); + if (mHandleMask & CorHandleWeakNativeCom) + result |= (1 << HNDTYPE_WEAK_NATIVE_COM); #endif // FEATURE_COMINTEROP if (mHandleMask & CorHandleStrongDependent) @@ -7667,8 +7667,8 @@ void CALLBACK DacHandleWalker::EnumCallbackDac(PTR_UNCHECKED_OBJECTREF handle, u data.i64ExtraData = refCnt; break; - case HNDTYPE_WEAK_WINRT: - data.dwType = (DWORD)CorHandleWeakWinRT; + case HNDTYPE_WEAK_NATIVE_COM: + data.dwType = (DWORD)CorHandleWeakNativeCom; break; #endif diff --git a/src/coreclr/src/debug/daccess/dacimpl.h b/src/coreclr/src/debug/daccess/dacimpl.h index 958adb1fd91787..29183751fb53e9 100644 --- a/src/coreclr/src/debug/daccess/dacimpl.h +++ b/src/coreclr/src/debug/daccess/dacimpl.h @@ -1456,6 +1456,10 @@ class ClrDataAccess PTR_IUnknown DACGetCOMIPFromCCW(PTR_ComCallWrapper pCCW, int vtableIndex); #endif +#ifdef FEATURE_COMWRAPPERS + HRESULT DACTryGetComWrappersObjectFromCCW(CLRDATA_ADDRESS ccwPtr, OBJECTREF* objRef); +#endif + static LONG s_procInit; public: diff --git a/src/coreclr/src/debug/daccess/enummem.cpp b/src/coreclr/src/debug/daccess/enummem.cpp index 6a3feec6cf9f5a..5c5f402b99ad06 100644 --- a/src/coreclr/src/debug/daccess/enummem.cpp +++ b/src/coreclr/src/debug/daccess/enummem.cpp @@ -1298,7 +1298,7 @@ HRESULT ClrDataAccess::EnumMemDumpAllThreadsStack(CLRDataEnumMemoryFlags flags) } -#ifdef FEATURE_COMINTEROP +#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS) //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // WinRT stowed exception holds the (CCW)pointer to a managed exception object. @@ -1431,11 +1431,26 @@ HRESULT ClrDataAccess::DumpStowedExceptionObject(CLRDataEnumMemoryFlags flags, C if (ccwPtr == NULL) return S_OK; + OBJECTREF managedExceptionObject = NULL; + +#ifdef FEATURE_COMINTEROP // dump the managed exception object wrapped in CCW // memory of the CCW object itself is dumped later by DacInstanceManager::DumpAllInstances DacpCCWData ccwData; GetCCWData(ccwPtr, &ccwData); // this call collects some memory implicitly - DumpManagedExcepObject(flags, OBJECTREF(TO_TADDR(ccwData.managedObject))); + managedExceptionObject = OBJECTREF(CLRDATA_ADDRESS_TO_TADDR(ccwData.managedObject)); +#endif +#ifdef FEATURE_COMWRAPPERS + if (managedExceptionObject == NULL) + { + OBJECTREF wrappedObjAddress; + if (DACTryGetComWrappersObjectFromCCW(ccwPtr, &wrappedObjAddress) == S_OK) + { + managedExceptionObject = wrappedObjAddress; + } + } +#endif + DumpManagedExcepObject(flags, managedExceptionObject); // dump memory of the 2nd slot in the CCW's vtable // this is used in DACGetCCWFromAddress to identify if the passed in pointer is a valid CCW. @@ -1450,7 +1465,8 @@ HRESULT ClrDataAccess::DumpStowedExceptionObject(CLRDataEnumMemoryFlags flags, C CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED ( - ReportMem(vTableAddress + sizeof(PBYTE)* TEAR_OFF_SLOT, sizeof(TADDR)); + ReportMem(vTableAddress, sizeof(TADDR)); // Report the QI slot on the vtable for ComWrappers + ReportMem(vTableAddress + sizeof(PBYTE) * TEAR_OFF_SLOT, sizeof(TADDR)); // Report the AddRef slot on the vtable for built-in CCWs ); return S_OK; diff --git a/src/coreclr/src/debug/daccess/request.cpp b/src/coreclr/src/debug/daccess/request.cpp index 2be663ebd77ea9..8fc4896abdcd11 100644 --- a/src/coreclr/src/debug/daccess/request.cpp +++ b/src/coreclr/src/debug/daccess/request.cpp @@ -20,6 +20,8 @@ #include #endif // FEATURE_COMINTEROP +#include + #ifndef TARGET_UNIX // It is unfortunate having to include this header just to get the definition of GenericModeBlock #include @@ -3253,7 +3255,7 @@ HRESULT ClrDataAccess::GetHandleEnum(ISOSHandleEnum **ppHandleEnum) unsigned int types[] = {HNDTYPE_WEAK_SHORT, HNDTYPE_WEAK_LONG, HNDTYPE_STRONG, HNDTYPE_PINNED, HNDTYPE_VARIABLE, HNDTYPE_DEPENDENT, HNDTYPE_ASYNCPINNED, HNDTYPE_SIZEDREF, #ifdef FEATURE_COMINTEROP - HNDTYPE_REFCOUNTED, HNDTYPE_WEAK_WINRT + HNDTYPE_REFCOUNTED, HNDTYPE_WEAK_NATIVE_COM #endif }; @@ -3291,7 +3293,7 @@ HRESULT ClrDataAccess::GetHandleEnumForGC(unsigned int gen, ISOSHandleEnum **ppH unsigned int types[] = {HNDTYPE_WEAK_SHORT, HNDTYPE_WEAK_LONG, HNDTYPE_STRONG, HNDTYPE_PINNED, HNDTYPE_VARIABLE, HNDTYPE_DEPENDENT, HNDTYPE_ASYNCPINNED, HNDTYPE_SIZEDREF, #ifdef FEATURE_COMINTEROP - HNDTYPE_REFCOUNTED, HNDTYPE_WEAK_WINRT + HNDTYPE_REFCOUNTED, HNDTYPE_WEAK_NATIVE_COM #endif }; @@ -4065,6 +4067,76 @@ PTR_IUnknown ClrDataAccess::DACGetCOMIPFromCCW(PTR_ComCallWrapper pCCW, int vtab } #endif +#ifdef FEATURE_COMWRAPPERS +HRESULT ClrDataAccess::DACTryGetComWrappersObjectFromCCW(CLRDATA_ADDRESS ccwPtr, OBJECTREF* objRef) +{ + if (ccwPtr == 0 || objRef == NULL) + return E_INVALIDARG; + + SOSDacEnter(); + + // Read CCWs QI address and compare it to the managed object wrapper's implementation. + ULONG32 bytesRead = 0; + TADDR ccw = CLRDATA_ADDRESS_TO_TADDR(ccwPtr); + TADDR vTableAddress = NULL; + IfFailGo(m_pTarget->ReadVirtual(ccw, (PBYTE)&vTableAddress, sizeof(TADDR), &bytesRead)); + if (bytesRead != sizeof(TADDR) + || vTableAddress == NULL) + { + hr = E_FAIL; + goto ErrExit; + } + + TADDR qiAddress = NULL; + IfFailGo(m_pTarget->ReadVirtual(vTableAddress, (PBYTE)&qiAddress, sizeof(TADDR), &bytesRead)); + if (bytesRead != sizeof(TADDR) + || qiAddress == NULL) + { + hr = E_FAIL; + goto ErrExit; + } + + +#ifdef TARGET_ARM + // clear the THUMB bit on qiAddress before comparing with known vtable entry + qiAddress &= ~THUMB_CODE; +#endif + + if (qiAddress != GetEEFuncEntryPoint(ManagedObjectWrapper_QueryInterface)) + { + hr = E_FAIL; + goto ErrExit; + } + + // Mask the "dispatch pointer" to get a double pointer to the ManagedObjectWrapper + TADDR managedObjectWrapperPtrPtr = ccw & InteropLib::ABI::DispatchThisPtrMask; + + // Return ManagedObjectWrapper as an OBJECTHANDLE. (The OBJECTHANDLE is guaranteed to live at offset 0). + TADDR managedObjectWrapperPtr; + IfFailGo(m_pTarget->ReadVirtual(managedObjectWrapperPtrPtr, (PBYTE)&managedObjectWrapperPtr, sizeof(TADDR), &bytesRead)); + if (bytesRead != sizeof(TADDR)) + { + hr = E_FAIL; + goto ErrExit; + } + + OBJECTHANDLE handle; + IfFailGo(m_pTarget->ReadVirtual(managedObjectWrapperPtr, (PBYTE)&handle, sizeof(OBJECTHANDLE), &bytesRead)); + if (bytesRead != sizeof(OBJECTHANDLE)) + { + hr = E_FAIL; + goto ErrExit; + } + + *objRef = ObjectFromHandle(handle); + + SOSDacLeave(); + + return S_OK; + +ErrExit: return hr; +} +#endif HRESULT ClrDataAccess::GetCCWData(CLRDATA_ADDRESS ccw, struct DacpCCWData *ccwData) { diff --git a/src/coreclr/src/debug/debug-pal/CMakeLists.txt b/src/coreclr/src/debug/debug-pal/CMakeLists.txt index b06e46092caba1..ac1e48fb5fb4d8 100644 --- a/src/coreclr/src/debug/debug-pal/CMakeLists.txt +++ b/src/coreclr/src/debug/debug-pal/CMakeLists.txt @@ -8,11 +8,17 @@ if(CLR_CMAKE_HOST_WIN32) add_definitions(-DWIN32_LEAN_AND_MEAN) include_directories(../../inc) #needed for warning control - set(TWO_WAY_PIPE_SOURCES - win/diagnosticsipc.cpp - win/twowaypipe.cpp - win/processdescriptor.cpp - ) + if(CLR_CMAKE_TARGET_WIN32) + set(TWO_WAY_PIPE_SOURCES + win/diagnosticsipc.cpp + win/twowaypipe.cpp + win/processdescriptor.cpp + ) + else(CLR_CMAKE_TARGET_WIN32) + set(TWO_WAY_PIPE_SOURCES + dummy/twowaypipe.cpp + ) + endif(CLR_CMAKE_TARGET_WIN32) endif(CLR_CMAKE_HOST_WIN32) if(CLR_CMAKE_HOST_UNIX) diff --git a/src/coreclr/src/debug/debug-pal/dummy/twowaypipe.cpp b/src/coreclr/src/debug/debug-pal/dummy/twowaypipe.cpp new file mode 100644 index 00000000000000..ed73fd75cf1731 --- /dev/null +++ b/src/coreclr/src/debug/debug-pal/dummy/twowaypipe.cpp @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include "twowaypipe.h" + +// This file contains a dummy implementation of the simple IPC mechanism - bidirectional named pipe. +// It is used for the cross OS DBI where IPC is not supported. + + +// Creates a server side of the pipe. +// Id is used to create pipes names and uniquely identify the pipe on the machine. +// true - success, false - failure (use GetLastError() for more details) +bool TwoWayPipe::CreateServer(const ProcessDescriptor& pd) +{ + return false; +} + + +// Connects to a previously opened server side of the pipe. +// Id is used to locate the pipe on the machine. +// true - success, false - failure (use GetLastError() for more details) +bool TwoWayPipe::Connect(const ProcessDescriptor& pd) +{ + return false; +} + +// Waits for incoming client connections, assumes GetState() == Created +// true - success, false - failure (use GetLastError() for more details) +bool TwoWayPipe::WaitForConnection() +{ + return false; +} + +// Reads data from pipe. Returns number of bytes read or a negative number in case of an error. +// use GetLastError() for more details +int TwoWayPipe::Read(void *buffer, DWORD bufferSize) +{ + return -1; +} + +// Writes data to pipe. Returns number of bytes written or a negative number in case of an error. +// use GetLastError() for more details +int TwoWayPipe::Write(const void *data, DWORD dataSize) +{ + return -1; +} + +// Disconnect server or client side of the pipe. +// true - success, false - failure (use GetLastError() for more details) +bool TwoWayPipe::Disconnect() +{ + return false; +} + +// Connects to a one sided pipe previously created by CreateOneWayPipe. +// In order to successfully connect id and inbound flag should be the same. +HANDLE TwoWayPipe::OpenOneWayPipe(DWORD id, bool inbound) +{ + return NULL; +} + + +// Creates a one way pipe, id and inboud flag are used for naming. +// Created pipe is supposed to be connected to by OpenOneWayPipe. +HANDLE TwoWayPipe::CreateOneWayPipe(DWORD id, bool inbound) +{ + return NULL; +} + +// Used by debugger side (RS) to cleanup the target (LS) named pipes +// and semaphores when the debugger detects the debuggee process exited. +void TwoWayPipe::CleanupTargetProcess() +{ +} diff --git a/src/coreclr/src/debug/debug-pal/unix/diagnosticsipc.cpp b/src/coreclr/src/debug/debug-pal/unix/diagnosticsipc.cpp index e70f35884f510a..046350317cde15 100644 --- a/src/coreclr/src/debug/debug-pal/unix/diagnosticsipc.cpp +++ b/src/coreclr/src/debug/debug-pal/unix/diagnosticsipc.cpp @@ -12,13 +12,20 @@ #include "diagnosticsipc.h" #include "processdescriptor.h" -IpcStream::DiagnosticsIpc::DiagnosticsIpc(const int serverSocket, sockaddr_un *const pServerAddress) : +#if __GNUC__ + #include +#else + #include +#endif // __GNUC__ + +IpcStream::DiagnosticsIpc::DiagnosticsIpc(const int serverSocket, sockaddr_un *const pServerAddress, ConnectionMode mode) : + mode(mode), _serverSocket(serverSocket), _pServerAddress(new sockaddr_un), - _isClosed(false) + _isClosed(false), + _isListening(false) { _ASSERTE(_pServerAddress != nullptr); - _ASSERTE(_serverSocket != -1); _ASSERTE(pServerAddress != nullptr); if (_pServerAddress == nullptr || pServerAddress == nullptr) @@ -32,24 +39,8 @@ IpcStream::DiagnosticsIpc::~DiagnosticsIpc() delete _pServerAddress; } -IpcStream::DiagnosticsIpc *IpcStream::DiagnosticsIpc::Create(const char *const pIpcName, ErrorCallback callback) +IpcStream::DiagnosticsIpc *IpcStream::DiagnosticsIpc::Create(const char *const pIpcName, ConnectionMode mode, ErrorCallback callback) { -#ifdef __APPLE__ - mode_t prev_mask = umask(~(S_IRUSR | S_IWUSR)); // This will set the default permission bit to 600 -#endif // __APPLE__ - - const int serverSocket = ::socket(AF_UNIX, SOCK_STREAM, 0); - if (serverSocket == -1) - { - if (callback != nullptr) - callback(strerror(errno), errno); -#ifdef __APPLE__ - umask(prev_mask); -#endif // __APPLE__ - _ASSERTE(!"Failed to create diagnostics IPC socket."); - return nullptr; - } - sockaddr_un serverAddress{}; serverAddress.sun_family = AF_UNIX; @@ -71,6 +62,24 @@ IpcStream::DiagnosticsIpc *IpcStream::DiagnosticsIpc::Create(const char *const p "socket"); } + if (mode == ConnectionMode::CLIENT) + return new IpcStream::DiagnosticsIpc(-1, &serverAddress, ConnectionMode::CLIENT); + +#ifdef __APPLE__ + mode_t prev_mask = umask(~(S_IRUSR | S_IWUSR)); // This will set the default permission bit to 600 +#endif // __APPLE__ + + const int serverSocket = ::socket(AF_UNIX, SOCK_STREAM, 0); + if (serverSocket == -1) + { + if (callback != nullptr) + callback(strerror(errno), errno); +#ifdef __APPLE__ + umask(prev_mask); +#endif // __APPLE__ + _ASSERTE(!"Failed to create diagnostics IPC socket."); + return nullptr; + } #ifndef __APPLE__ if (fchmod(serverSocket, S_IRUSR | S_IWUSR) == -1) @@ -99,33 +108,52 @@ IpcStream::DiagnosticsIpc *IpcStream::DiagnosticsIpc::Create(const char *const p return nullptr; } - const int fSuccessfulListen = ::listen(serverSocket, /* backlog */ 255); +#ifdef __APPLE__ + umask(prev_mask); +#endif // __APPLE__ + + return new IpcStream::DiagnosticsIpc(serverSocket, &serverAddress, mode); +} + +bool IpcStream::DiagnosticsIpc::Listen(ErrorCallback callback) +{ + _ASSERTE(mode == ConnectionMode::SERVER); + if (mode != ConnectionMode::SERVER) + { + if (callback != nullptr) + callback("Cannot call Listen on a client connection", -1); + return false; + } + + if (_isListening) + return true; + + const int fSuccessfulListen = ::listen(_serverSocket, /* backlog */ 255); if (fSuccessfulListen == -1) { if (callback != nullptr) callback(strerror(errno), errno); _ASSERTE(fSuccessfulListen != -1); - const int fSuccessUnlink = ::unlink(serverAddress.sun_path); + const int fSuccessUnlink = ::unlink(_pServerAddress->sun_path); _ASSERTE(fSuccessUnlink != -1); - const int fSuccessClose = ::close(serverSocket); + const int fSuccessClose = ::close(_serverSocket); _ASSERTE(fSuccessClose != -1); -#ifdef __APPLE__ - umask(prev_mask); -#endif // __APPLE__ - return nullptr; + return false; + } + else + { + _isListening = true; + return true; } - -#ifdef __APPLE__ - umask(prev_mask); -#endif // __APPLE__ - - return new IpcStream::DiagnosticsIpc(serverSocket, &serverAddress); } -IpcStream *IpcStream::DiagnosticsIpc::Accept(ErrorCallback callback) const +IpcStream *IpcStream::DiagnosticsIpc::Accept(ErrorCallback callback) { + _ASSERTE(mode == ConnectionMode::SERVER); + _ASSERTE(_isListening); + sockaddr_un from; socklen_t fromlen = sizeof(from); const int clientSocket = ::accept(_serverSocket, (sockaddr *)&from, &fromlen); @@ -136,10 +164,117 @@ IpcStream *IpcStream::DiagnosticsIpc::Accept(ErrorCallback callback) const return nullptr; } - return new IpcStream(clientSocket); + return new IpcStream(clientSocket, mode); +} + +IpcStream *IpcStream::DiagnosticsIpc::Connect(ErrorCallback callback) +{ + _ASSERTE(mode == ConnectionMode::CLIENT); + + sockaddr_un clientAddress{}; + clientAddress.sun_family = AF_UNIX; + const int clientSocket = ::socket(AF_UNIX, SOCK_STREAM, 0); + if (clientSocket == -1) + { + if (callback != nullptr) + callback(strerror(errno), errno); + return nullptr; + } + + // We don't expect this to block since this is a Unix Domain Socket. `connect` may block until the + // TCP handshake is complete for TCP/IP sockets, but UDS don't use TCP. `connect` will return even if + // the server hasn't called `accept`. + if (::connect(clientSocket, (struct sockaddr *)_pServerAddress, sizeof(*_pServerAddress)) < 0) + { + if (callback != nullptr) + callback(strerror(errno), errno); + return nullptr; + } + + return new IpcStream(clientSocket, ConnectionMode::CLIENT); } -void IpcStream::DiagnosticsIpc::Close(ErrorCallback callback) +int32_t IpcStream::DiagnosticsIpc::Poll(IpcPollHandle *rgIpcPollHandles, uint32_t nHandles, int32_t timeoutMs, ErrorCallback callback) +{ + // prepare the pollfd structs + pollfd *pollfds = new pollfd[nHandles]; + for (uint32_t i = 0; i < nHandles; i++) + { + rgIpcPollHandles[i].revents = 0; // ignore any values in revents + int fd = -1; + if (rgIpcPollHandles[i].pIpc != nullptr) + { + // SERVER + _ASSERTE(rgIpcPollHandles[i].pIpc->mode == ConnectionMode::SERVER); + fd = rgIpcPollHandles[i].pIpc->_serverSocket; + } + else + { + // CLIENT + _ASSERTE(rgIpcPollHandles[i].pStream != nullptr); + fd = rgIpcPollHandles[i].pStream->_clientSocket; + } + + pollfds[i].fd = fd; + pollfds[i].events = POLLIN; + } + + int retval = poll(pollfds, nHandles, timeoutMs); + + // Check results + if (retval < 0) + { + for (uint32_t i = 0; i < nHandles; i++) + { + if ((pollfds[i].revents & POLLERR) && callback != nullptr) + callback(strerror(errno), errno); + rgIpcPollHandles[i].revents = (uint8_t)PollEvents::ERR; + } + delete[] pollfds; + return -1; + } + else if (retval == 0) + { + // we timed out + delete[] pollfds; + return 0; + } + + for (uint32_t i = 0; i < nHandles; i++) + { + if (pollfds[i].revents != 0) + { + // error check FIRST + if (pollfds[i].revents & POLLHUP) + { + // check for hangup first because a closed socket + // will technically meet the requirements for POLLIN + // i.e., a call to recv/read won't block + rgIpcPollHandles[i].revents = (uint8_t)PollEvents::HANGUP; + delete[] pollfds; + return -1; + } + else if ((pollfds[i].revents & (POLLERR|POLLNVAL))) + { + if (callback != nullptr) + callback("Poll error", (uint32_t)pollfds[i].revents); + rgIpcPollHandles[i].revents = (uint8_t)PollEvents::ERR; + delete[] pollfds; + return -1; + } + else if (pollfds[i].revents & POLLIN) + { + rgIpcPollHandles[i].revents = (uint8_t)PollEvents::SIGNALED; + break; + } + } + } + + delete[] pollfds; + return 1; +} + +void IpcStream::DiagnosticsIpc::Close(bool isShutdown, ErrorCallback callback) { if (_isClosed) return; @@ -147,13 +282,19 @@ void IpcStream::DiagnosticsIpc::Close(ErrorCallback callback) if (_serverSocket != -1) { - if (::close(_serverSocket) == -1) + // only close the socket if not shutting down, let the OS handle it in that case + if (!isShutdown && ::close(_serverSocket) == -1) { if (callback != nullptr) callback(strerror(errno), errno); _ASSERTE(!"Failed to close unix domain socket."); } + // N.B. - it is safe to unlink the unix domain socket file while the server + // is still alive: + // "The usual UNIX close-behind semantics apply; the socket can be unlinked + // at any time and will be finally removed from the file system when the last + // reference to it is closed." - unix(7) man page Unlink(callback); } } @@ -172,6 +313,11 @@ void IpcStream::DiagnosticsIpc::Unlink(ErrorCallback callback) } IpcStream::~IpcStream() +{ + Close(); +} + +void IpcStream::Close(ErrorCallback) { if (_clientSocket != -1) { @@ -179,38 +325,89 @@ IpcStream::~IpcStream() const int fSuccessClose = ::close(_clientSocket); _ASSERTE(fSuccessClose != -1); + _clientSocket = -1; } } -bool IpcStream::Read(void *lpBuffer, const uint32_t nBytesToRead, uint32_t &nBytesRead) const +bool IpcStream::Read(void *lpBuffer, const uint32_t nBytesToRead, uint32_t &nBytesRead, const int32_t timeoutMs) { _ASSERTE(lpBuffer != nullptr); - const ssize_t ssize = ::recv(_clientSocket, lpBuffer, nBytesToRead, 0); - const bool fSuccess = ssize != -1; + if (timeoutMs != InfiniteTimeout) + { + pollfd pfd; + pfd.fd = _clientSocket; + pfd.events = POLLIN; + int retval = poll(&pfd, 1, timeoutMs); + if (retval <= 0 || pfd.revents != POLLIN) + { + // timeout or error + return false; + } + // else fallthrough + } + + uint8_t *lpBufferCursor = (uint8_t*)lpBuffer; + ssize_t currentBytesRead = 0; + ssize_t totalBytesRead = 0; + bool fSuccess = true; + while (fSuccess && nBytesToRead - totalBytesRead > 0) + { + currentBytesRead = ::recv(_clientSocket, lpBufferCursor, nBytesToRead - totalBytesRead, 0); + fSuccess = currentBytesRead != 0; + if (!fSuccess) + break; + totalBytesRead += currentBytesRead; + lpBufferCursor += currentBytesRead; + } if (!fSuccess) { // TODO: Add error handling. } - nBytesRead = static_cast(ssize); + nBytesRead = static_cast(totalBytesRead); return fSuccess; } -bool IpcStream::Write(const void *lpBuffer, const uint32_t nBytesToWrite, uint32_t &nBytesWritten) const +bool IpcStream::Write(const void *lpBuffer, const uint32_t nBytesToWrite, uint32_t &nBytesWritten, const int32_t timeoutMs) { _ASSERTE(lpBuffer != nullptr); - const ssize_t ssize = ::send(_clientSocket, lpBuffer, nBytesToWrite, 0); - const bool fSuccess = ssize != -1; + if (timeoutMs != InfiniteTimeout) + { + pollfd pfd; + pfd.fd = _clientSocket; + pfd.events = POLLOUT; + int retval = poll(&pfd, 1, timeoutMs); + if (retval <= 0 || pfd.revents != POLLOUT) + { + // timeout or error + return false; + } + // else fallthrough + } + + uint8_t *lpBufferCursor = (uint8_t*)lpBuffer; + ssize_t currentBytesWritten = 0; + ssize_t totalBytesWritten = 0; + bool fSuccess = true; + while (fSuccess && nBytesToWrite - totalBytesWritten > 0) + { + currentBytesWritten = ::send(_clientSocket, lpBufferCursor, nBytesToWrite - totalBytesWritten, 0); + fSuccess = currentBytesWritten != -1; + if (!fSuccess) + break; + lpBufferCursor += currentBytesWritten; + totalBytesWritten += currentBytesWritten; + } if (!fSuccess) { // TODO: Add error handling. } - nBytesWritten = static_cast(ssize); + nBytesWritten = static_cast(totalBytesWritten); return fSuccess; } diff --git a/src/coreclr/src/debug/debug-pal/win/diagnosticsipc.cpp b/src/coreclr/src/debug/debug-pal/win/diagnosticsipc.cpp index 36c11857cabe98..f7b41b92fc1e6f 100644 --- a/src/coreclr/src/debug/debug-pal/win/diagnosticsipc.cpp +++ b/src/coreclr/src/debug/debug-pal/win/diagnosticsipc.cpp @@ -7,9 +7,14 @@ #include #include "diagnosticsipc.h" -IpcStream::DiagnosticsIpc::DiagnosticsIpc(const char(&namedPipeName)[MaxNamedPipeNameLength]) +#define _ASSERTE assert + +IpcStream::DiagnosticsIpc::DiagnosticsIpc(const char(&namedPipeName)[MaxNamedPipeNameLength], ConnectionMode mode) : + mode(mode), + _isListening(false) { memcpy(_pNamedPipeName, namedPipeName, sizeof(_pNamedPipeName)); + memset(&_oOverlap, 0, sizeof(OVERLAPPED)); } IpcStream::DiagnosticsIpc::~DiagnosticsIpc() @@ -17,7 +22,7 @@ IpcStream::DiagnosticsIpc::~DiagnosticsIpc() Close(); } -IpcStream::DiagnosticsIpc *IpcStream::DiagnosticsIpc::Create(const char *const pIpcName, ErrorCallback callback) +IpcStream::DiagnosticsIpc *IpcStream::DiagnosticsIpc::Create(const char *const pIpcName, ConnectionMode mode, ErrorCallback callback) { char namedPipeName[MaxNamedPipeNameLength]{}; int nCharactersWritten = -1; @@ -43,20 +48,32 @@ IpcStream::DiagnosticsIpc *IpcStream::DiagnosticsIpc::Create(const char *const p { if (callback != nullptr) callback("Failed to generate the named pipe name", nCharactersWritten); - assert(nCharactersWritten != -1); + _ASSERTE(nCharactersWritten != -1); return nullptr; } - return new IpcStream::DiagnosticsIpc(namedPipeName); + return new IpcStream::DiagnosticsIpc(namedPipeName, mode); } -IpcStream *IpcStream::DiagnosticsIpc::Accept(ErrorCallback callback) const +bool IpcStream::DiagnosticsIpc::Listen(ErrorCallback callback) { + _ASSERTE(mode == ConnectionMode::SERVER); + if (mode != ConnectionMode::SERVER) + { + if (callback != nullptr) + callback("Cannot call Listen on a client connection", -1); + return false; + } + + if (_isListening) + return true; + const uint32_t nInBufferSize = 16 * 1024; const uint32_t nOutBufferSize = 16 * 1024; - HANDLE hPipe = ::CreateNamedPipeA( + _hPipe = ::CreateNamedPipeA( _pNamedPipeName, // pipe name - PIPE_ACCESS_DUPLEX, // read/write access + PIPE_ACCESS_DUPLEX | // read/write access + FILE_FLAG_OVERLAPPED, // async listening PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, // message type pipe, message-read and blocking mode PIPE_UNLIMITED_INSTANCES, // max. instances nOutBufferSize, // output buffer size @@ -64,19 +81,32 @@ IpcStream *IpcStream::DiagnosticsIpc::Accept(ErrorCallback callback) const 0, // default client time-out NULL); // default security attribute - if (hPipe == INVALID_HANDLE_VALUE) + if (_hPipe == INVALID_HANDLE_VALUE) { if (callback != nullptr) callback("Failed to create an instance of a named pipe.", ::GetLastError()); - return nullptr; + return false; } - const BOOL fSuccess = ::ConnectNamedPipe(hPipe, NULL) != 0; + HANDLE hOverlapEvent = CreateEvent(NULL, true, false, NULL); + if (hOverlapEvent == NULL) + { + if (callback != nullptr) + callback("Failed to create overlap event", ::GetLastError()); + ::CloseHandle(_hPipe); + _hPipe = INVALID_HANDLE_VALUE; + return false; + } + _oOverlap.hEvent = hOverlapEvent; + + BOOL fSuccess = ::ConnectNamedPipe(_hPipe, &_oOverlap) != 0; if (!fSuccess) { const DWORD errorCode = ::GetLastError(); switch (errorCode) { + case ERROR_IO_PENDING: + // There was a pending connection that can be waited on (will happen in poll) case ERROR_PIPE_CONNECTED: // Occurs when a client connects before the function is called. // In this case, there is a connection between client and @@ -86,46 +116,333 @@ IpcStream *IpcStream::DiagnosticsIpc::Accept(ErrorCallback callback) const default: if (callback != nullptr) callback("A client process failed to connect.", errorCode); - ::CloseHandle(hPipe); - return nullptr; + ::CloseHandle(_hPipe); + _hPipe = INVALID_HANDLE_VALUE; + ::CloseHandle(_oOverlap.hEvent); + _oOverlap.hEvent = INVALID_HANDLE_VALUE; + return false; + } + } + + _isListening = true; + return true; +} + +IpcStream *IpcStream::DiagnosticsIpc::Accept(ErrorCallback callback) +{ + _ASSERTE(_isListening); + _ASSERTE(mode == ConnectionMode::SERVER); + + DWORD dwDummy = 0; + bool fSuccess = GetOverlappedResult( + _hPipe, // handle + &_oOverlap, // overlapped + &dwDummy, // throw-away dword + true); // wait till event signals + + if (!fSuccess) + { + if (callback != nullptr) + callback("Failed to GetOverlappedResults for NamedPipe server", ::GetLastError()); + return nullptr; + } + + // create new IpcStream using handle and reset the Server object so it can listen again + IpcStream *pStream = new IpcStream(_hPipe, ConnectionMode::SERVER); + + // reset the server + _hPipe = INVALID_HANDLE_VALUE; + _isListening = false; + ::CloseHandle(_oOverlap.hEvent); + memset(&_oOverlap, 0, sizeof(OVERLAPPED)); // clear the overlapped objects state + fSuccess = Listen(callback); + if (!fSuccess) + { + delete pStream; + return nullptr; + } + + return pStream; +} + +IpcStream *IpcStream::DiagnosticsIpc::Connect(ErrorCallback callback) +{ + _ASSERTE(mode == ConnectionMode::CLIENT); + if (mode != ConnectionMode::CLIENT) + { + if (callback != nullptr) + callback("Cannot call connect on a server connection", 0); + return nullptr; + } + + HANDLE hPipe = ::CreateFileA( + _pNamedPipeName, // pipe name + PIPE_ACCESS_DUPLEX, // read/write access + 0, // no sharing + NULL, // default security attributes + OPEN_EXISTING, // opens existing pipe + FILE_FLAG_OVERLAPPED, // Overlapped + NULL); // no template file + + if (hPipe == INVALID_HANDLE_VALUE) + { + if (callback != nullptr) + callback("Failed to connect to named pipe.", ::GetLastError()); + return nullptr; + } + + return new IpcStream(hPipe, mode); +} + +void IpcStream::DiagnosticsIpc::Close(bool isShutdown, ErrorCallback) +{ + // don't attempt cleanup on shutdown and let the OS handle it + if (isShutdown) + return; + + if (_hPipe != INVALID_HANDLE_VALUE) + { + if (mode == DiagnosticsIpc::ConnectionMode::SERVER) + { + const BOOL fSuccessDisconnectNamedPipe = ::DisconnectNamedPipe(_hPipe); + _ASSERTE(fSuccessDisconnectNamedPipe != 0); } + + const BOOL fSuccessCloseHandle = ::CloseHandle(_hPipe); + _ASSERTE(fSuccessCloseHandle != 0); } - return new IpcStream(hPipe); + if (_oOverlap.hEvent != INVALID_HANDLE_VALUE) + { + ::CloseHandle(_oOverlap.hEvent); + } } -void IpcStream::DiagnosticsIpc::Close(ErrorCallback) +IpcStream::IpcStream(HANDLE hPipe, DiagnosticsIpc::ConnectionMode mode) : + _hPipe(hPipe), + _mode(mode) { + memset(&_oOverlap, 0, sizeof(OVERLAPPED)); + _oOverlap.hEvent = CreateEvent(NULL, true, false, NULL); } IpcStream::~IpcStream() +{ + Close(); +} + +void IpcStream::Close(ErrorCallback) { if (_hPipe != INVALID_HANDLE_VALUE) { Flush(); - const BOOL fSuccessDisconnectNamedPipe = ::DisconnectNamedPipe(_hPipe); - assert(fSuccessDisconnectNamedPipe != 0); + if (_mode == DiagnosticsIpc::ConnectionMode::SERVER) + { + const BOOL fSuccessDisconnectNamedPipe = ::DisconnectNamedPipe(_hPipe); + _ASSERTE(fSuccessDisconnectNamedPipe != 0); + } const BOOL fSuccessCloseHandle = ::CloseHandle(_hPipe); - assert(fSuccessCloseHandle != 0); + _ASSERTE(fSuccessCloseHandle != 0); + } + + if (_oOverlap.hEvent != INVALID_HANDLE_VALUE) + { + ::CloseHandle(_oOverlap.hEvent); + } +} + +int32_t IpcStream::DiagnosticsIpc::Poll(IpcPollHandle *rgIpcPollHandles, uint32_t nHandles, int32_t timeoutMs, ErrorCallback callback) +{ + // load up an array of handles + HANDLE *pHandles = new HANDLE[nHandles]; + for (uint32_t i = 0; i < nHandles; i++) + { + rgIpcPollHandles[i].revents = 0; // ignore any inputs on revents + if (rgIpcPollHandles[i].pIpc != nullptr) + { + // SERVER + _ASSERTE(rgIpcPollHandles[i].pIpc->mode == DiagnosticsIpc::ConnectionMode::SERVER); + pHandles[i] = rgIpcPollHandles[i].pIpc->_oOverlap.hEvent; + } + else + { + // CLIENT + bool fSuccess = false; + DWORD dwDummy = 0; + if (!rgIpcPollHandles[i].pStream->_isTestReading) + { + // check for data by doing an asynchronous 0 byte read. + // This will signal if the pipe closes (hangup) or the server + // sends new data + fSuccess = ::ReadFile( + rgIpcPollHandles[i].pStream->_hPipe, // handle + nullptr, // null buffer + 0, // read 0 bytes + &dwDummy, // dummy variable + &rgIpcPollHandles[i].pStream->_oOverlap); // overlap object to use + rgIpcPollHandles[i].pStream->_isTestReading = true; + if (!fSuccess) + { + DWORD error = ::GetLastError(); + switch (error) + { + case ERROR_IO_PENDING: + pHandles[i] = rgIpcPollHandles[i].pStream->_oOverlap.hEvent; + break; + case ERROR_PIPE_NOT_CONNECTED: + // hangup + rgIpcPollHandles[i].revents = (uint8_t)PollEvents::HANGUP; + delete[] pHandles; + return -1; + default: + if (callback != nullptr) + callback("0 byte async read on client connection failed", error); + delete[] pHandles; + return -1; + } + } + } + else + { + pHandles[i] = rgIpcPollHandles[i].pStream->_oOverlap.hEvent; + } + } + } + + // call wait for multiple obj + DWORD dwWait = WaitForMultipleObjects( + nHandles, // count + pHandles, // handles + false, // Don't wait-all + timeoutMs); + + if (dwWait == WAIT_TIMEOUT) + { + // we timed out + delete[] pHandles; + return 0; + } + + if (dwWait == WAIT_FAILED) + { + // we errored + if (callback != nullptr) + callback("WaitForMultipleObjects failed", ::GetLastError()); + delete[] pHandles; + return -1; + } + + // determine which of the streams signaled + DWORD index = dwWait - WAIT_OBJECT_0; + // error check the index + if (index < 0 || index > (nHandles - 1)) + { + // check if we abandoned something + DWORD abandonedIndex = dwWait - WAIT_ABANDONED_0; + if (abandonedIndex > 0 || abandonedIndex < (nHandles - 1)) + { + rgIpcPollHandles[abandonedIndex].revents = (uint8_t)IpcStream::DiagnosticsIpc::PollEvents::HANGUP; + delete[] pHandles; + return -1; + } + else + { + if (callback != nullptr) + callback("WaitForMultipleObjects failed", ::GetLastError()); + delete[] pHandles; + return -1; + } } + + // Set revents depending on what signaled the stream + if (rgIpcPollHandles[index].pIpc == nullptr) + { + // CLIENT + // check if the connection got hung up + DWORD dwDummy = 0; + bool fSuccess = GetOverlappedResult(rgIpcPollHandles[index].pStream->_hPipe, + &rgIpcPollHandles[index].pStream->_oOverlap, + &dwDummy, + true); + rgIpcPollHandles[index].pStream->_isTestReading = false; + if (!fSuccess) + { + DWORD error = ::GetLastError(); + if (error == ERROR_PIPE_NOT_CONNECTED) + rgIpcPollHandles[index].revents = (uint8_t)IpcStream::DiagnosticsIpc::PollEvents::HANGUP; + else + { + if (callback != nullptr) + callback("Client connection error", -1); + rgIpcPollHandles[index].revents = (uint8_t)IpcStream::DiagnosticsIpc::PollEvents::ERR; + delete[] pHandles; + return -1; + } + } + else + { + rgIpcPollHandles[index].revents = (uint8_t)IpcStream::DiagnosticsIpc::PollEvents::SIGNALED; + } + } + else + { + // SERVER + rgIpcPollHandles[index].revents = (uint8_t)IpcStream::DiagnosticsIpc::PollEvents::SIGNALED; + } + + delete[] pHandles; + return 1; } -bool IpcStream::Read(void *lpBuffer, const uint32_t nBytesToRead, uint32_t &nBytesRead) const +bool IpcStream::Read(void *lpBuffer, const uint32_t nBytesToRead, uint32_t &nBytesRead, const int32_t timeoutMs) { - assert(lpBuffer != nullptr); + _ASSERTE(lpBuffer != nullptr); DWORD nNumberOfBytesRead = 0; - const bool fSuccess = ::ReadFile( + LPOVERLAPPED overlap = &_oOverlap; + bool fSuccess = ::ReadFile( _hPipe, // handle to pipe lpBuffer, // buffer to receive data nBytesToRead, // size of buffer &nNumberOfBytesRead, // number of bytes read - NULL) != 0; // not overlapped I/O + overlap) != 0; // overlapped I/O if (!fSuccess) { + if (timeoutMs == InfiniteTimeout) + { + fSuccess = GetOverlappedResult(_hPipe, + overlap, + &nNumberOfBytesRead, + true) != 0; + } + else + { + DWORD dwError = GetLastError(); + if (dwError == ERROR_IO_PENDING) + { + DWORD dwWait = WaitForSingleObject(_oOverlap.hEvent, (DWORD)timeoutMs); + if (dwWait == WAIT_OBJECT_0) + { + // get the result + fSuccess = GetOverlappedResult(_hPipe, + overlap, + &nNumberOfBytesRead, + true) != 0; + } + else + { + // cancel IO and ensure the cancel happened + if (CancelIo(_hPipe)) + { + // check if the async write beat the cancellation + fSuccess = GetOverlappedResult(_hPipe, overlap, &nNumberOfBytesRead, true) != 0; + } + } + } + } // TODO: Add error handling. } @@ -133,20 +450,54 @@ bool IpcStream::Read(void *lpBuffer, const uint32_t nBytesToRead, uint32_t &nByt return fSuccess; } -bool IpcStream::Write(const void *lpBuffer, const uint32_t nBytesToWrite, uint32_t &nBytesWritten) const +bool IpcStream::Write(const void *lpBuffer, const uint32_t nBytesToWrite, uint32_t &nBytesWritten, const int32_t timeoutMs) { - assert(lpBuffer != nullptr); + _ASSERTE(lpBuffer != nullptr); DWORD nNumberOfBytesWritten = 0; - const bool fSuccess = ::WriteFile( + LPOVERLAPPED overlap = &_oOverlap; + bool fSuccess = ::WriteFile( _hPipe, // handle to pipe lpBuffer, // buffer to write from nBytesToWrite, // number of bytes to write &nNumberOfBytesWritten, // number of bytes written - NULL) != 0; // not overlapped I/O + overlap) != 0; // overlapped I/O if (!fSuccess) { + DWORD dwError = GetLastError(); + if (dwError == ERROR_IO_PENDING) + { + if (timeoutMs == InfiniteTimeout) + { + // if we're waiting infinitely, don't bother with extra kernel call + fSuccess = GetOverlappedResult(_hPipe, + overlap, + &nNumberOfBytesWritten, + true) != 0; + } + else + { + DWORD dwWait = WaitForSingleObject(_oOverlap.hEvent, (DWORD)timeoutMs); + if (dwWait == WAIT_OBJECT_0) + { + // get the result + fSuccess = GetOverlappedResult(_hPipe, + overlap, + &nNumberOfBytesWritten, + true) != 0; + } + else + { + // cancel IO and ensure the cancel happened + if (CancelIo(_hPipe)) + { + // check if the async write beat the cancellation + fSuccess = GetOverlappedResult(_hPipe, overlap, &nNumberOfBytesWritten, true) != 0; + } + } + } + } // TODO: Add error handling. } diff --git a/src/coreclr/src/debug/di/cordb.cpp b/src/coreclr/src/debug/di/cordb.cpp index df6679040d1964..71e19a4e4b3931 100644 --- a/src/coreclr/src/debug/di/cordb.cpp +++ b/src/coreclr/src/debug/di/cordb.cpp @@ -28,7 +28,7 @@ #endif //********** Globals. ********************************************************* -#ifndef TARGET_UNIX +#ifndef HOST_UNIX HINSTANCE g_hInst; // Instance handle to this piece of code. #endif @@ -473,40 +473,6 @@ STDAPI GetRequestedRuntimeInfo(LPCWSTR pExe, return E_NOTIMPL; } -//----------------------------------------------------------------------------- -// Replacement for legacy shim API GetCORRequiredVersion(...) used in linked libraries. -// Used in code:TiggerStorage::GetDefaultVersion#CallTo_CLRRuntimeHostInternal_GetImageVersionString. -// -// Notes: -// Mscordbi does not statically link to mscoree.dll. -// This is used in EnC for IMetadataEmit2::GetSaveSize to computer size of header. -// see code:TiggerStorage::GetDefaultVersion. -// -// Implemented by returning the version we're built for. Mscordbi.dll has a tight coupling with -// the CLR version, so this will match exactly the build version we're debugging. -// One potential caveat is that the build version doesn't necessarily match the install string -// (eg. we may install as "v4.0.x86chk" but that's not captured in the build version). But this should -// be internal scenarios only, and shouldn't actually matter here. If it did, we could instead get -// the last components of the directory name the current mscordbi.dll is located in. -// -HRESULT -CLRRuntimeHostInternal_GetImageVersionString( - __out_ecount_part(*pcchBuffer, *pcchBuffer) LPWSTR wszBuffer, - DWORD *pcchBuffer) -{ - // Construct the cannoncial version string we're built as - eg. "v4.0.1234" - const WCHAR k_wszBuiltFor[] = W("v") VER_PRODUCTVERSION_NO_QFE_STR_L; - - // Copy our buffer in - HRESULT hr = HRESULT_FROM_WIN32(wcscpy_s(wszBuffer, *pcchBuffer, k_wszBuiltFor)); - - // Hand out length regardless of success - like GetCORRequiredVersion - *pcchBuffer = _countof(k_wszBuiltFor); - - return hr; -} // CLRRuntimeHostInternal_GetImageVersionString - - #ifdef TARGET_ARM BOOL DbiGetThreadContext(HANDLE hThread, diff --git a/src/coreclr/src/debug/di/module.cpp b/src/coreclr/src/debug/di/module.cpp index bcf11d206540e0..24911bab1b05a1 100644 --- a/src/coreclr/src/debug/di/module.cpp +++ b/src/coreclr/src/debug/di/module.cpp @@ -19,6 +19,7 @@ #include "ildbsymlib.h" #include "pedecoder.h" +#include "stgpool.h" //--------------------------------------------------------------------------------------- // Update an existing metadata importer with a buffer @@ -1993,14 +1994,17 @@ HRESULT CordbModule::CreateClass(mdTypeDef classMetaDataToken, HRESULT hr = m_classes.AddBase(pClass); if (SUCCEEDED(hr)) + { *ppClass = pClass; + if (classMetaDataToken == COR_GLOBAL_PARENT_TOKEN) + { + _ASSERTE( m_pClass == NULL ); //redundant create + m_pClass.Assign(pClass); + } + } else - delete pClass; - - if (classMetaDataToken == COR_GLOBAL_PARENT_TOKEN) { - _ASSERTE( m_pClass == NULL ); //redundant create - m_pClass.Assign(pClass); + delete pClass; } return hr; @@ -5331,6 +5335,3 @@ void CordbNativeCode::LoadNativeInfo() } } // CordbNativeCode::LoadNativeInfo - - - diff --git a/src/coreclr/src/debug/di/process.cpp b/src/coreclr/src/debug/di/process.cpp index 6c45f2c13e9c58..f13e7b9f0eaa1b 100644 --- a/src/coreclr/src/debug/di/process.cpp +++ b/src/coreclr/src/debug/di/process.cpp @@ -8981,10 +8981,10 @@ CordbProcess::GetVersion(COR_VERSION* pVersion) // // Because we require a matching version of mscordbi.dll to debug a certain version of the runtime, // we can just use constants found in this particular mscordbi.dll to determine the version of the left side. - pVersion->dwMajor = CLR_MAJOR_VERSION; - pVersion->dwMinor = CLR_MINOR_VERSION; - pVersion->dwBuild = CLR_BUILD_VERSION; - pVersion->dwSubBuild = CLR_BUILD_VERSION_QFE; + pVersion->dwMajor = RuntimeProductMajorVersion; + pVersion->dwMinor = RuntimeProductMinorVersion; + pVersion->dwBuild = RuntimeProductPatchVersion; + pVersion->dwSubBuild = 0; return S_OK; } @@ -10990,8 +10990,7 @@ void CordbWin32EventThread::ThreadProc() } // Define a holder that calls code:DeleteIPCEventHelper -NEW_WRAPPER_TEMPLATE1(DeleteIPCEventHolderHelper, DeleteIPCEventHelper); -typedef DeleteIPCEventHolderHelper DeleteIPCEventHolder; +using DeleteIPCEventHolder = SpecializedWrapper; //--------------------------------------------------------------------------------------- // diff --git a/src/coreclr/src/debug/ee/amd64/amd64InstrDecode.h b/src/coreclr/src/debug/ee/amd64/amd64InstrDecode.h index 012436129faff0..1a40c26e9799fd 100644 --- a/src/coreclr/src/debug/ee/amd64/amd64InstrDecode.h +++ b/src/coreclr/src/debug/ee/amd64/amd64InstrDecode.h @@ -124,7 +124,7 @@ namespace Amd64InstrDecode // Instruction which change forms based on modrm.reg are encoded in this extension table. // Since there are 8 modrm.reg values, they occur is groups of 8. // Each group is referenced from the other tables below using Extension|(index >> 3). - static InstrForm instrFormExtension[153] + static const InstrForm instrFormExtension[153] { MOnly_M4B, // Primary:0xd90/0 fld None, @@ -280,7 +280,7 @@ namespace Amd64InstrDecode MOnly_M8B, // Secondary:0xc73/7 vmptrst }; - static InstrForm instrFormPrimary[256] + static const InstrForm instrFormPrimary[256] { M1st_M1B, // 0x000 add M1st_WP_M8B_or_M4B_or_M2B, // 0x010 add @@ -540,7 +540,7 @@ namespace Amd64InstrDecode InstrForm(int(Extension)|0x06), // 0xff0 }; - static InstrForm instrForm3DNow[256] + static const InstrForm instrForm3DNow[256] { MOp_M8B_I1B, // 0x000 MOp_M8B_I1B, // 0x010 @@ -800,7 +800,7 @@ namespace Amd64InstrDecode MOp_M8B_I1B, // 0xff0 }; - static InstrForm instrFormSecondary[1024] + static const InstrForm instrFormSecondary[1024] { MOnly_M2B, // 0x000 lldt,ltr,sldt,str,verr,verw MOnly_M2B, // 0x001 lldt,ltr,sldt,str,verr,verw @@ -1828,7 +1828,7 @@ namespace Amd64InstrDecode None, // 0xff3 }; - static InstrForm instrFormF38[1024] + static const InstrForm instrFormF38[1024] { MOp_M8B, // 0x000 pshufb MOp_M16B, // 0x001 pshufb @@ -2856,7 +2856,7 @@ namespace Amd64InstrDecode None, // 0xff3 }; - static InstrForm instrFormF3A[1024] + static const InstrForm instrFormF3A[1024] { None, // 0x000 None, // 0x001 @@ -3884,7 +3884,7 @@ namespace Amd64InstrDecode None, // 0xff3 }; - static InstrForm instrFormVex1[1024] + static const InstrForm instrFormVex1[1024] { None, // 0x000 None, // 0x001 @@ -4912,7 +4912,7 @@ namespace Amd64InstrDecode None, // 0xff3 }; - static InstrForm instrFormVex2[1024] + static const InstrForm instrFormVex2[1024] { None, // 0x000 MOp_L_M32B_or_M16B, // 0x001 vpshufb @@ -5940,7 +5940,7 @@ namespace Amd64InstrDecode None, // 0xff3 }; - static InstrForm instrFormVex3[1024] + static const InstrForm instrFormVex3[1024] { None, // 0x000 MOp_M32B_I1B, // 0x001 vpermq @@ -6968,7 +6968,7 @@ namespace Amd64InstrDecode None, // 0xff3 }; - static InstrForm instrFormXOP8[1024] + static const InstrForm instrFormXOP8[1024] { None, // 0x000 None, // 0x001 @@ -7996,7 +7996,7 @@ namespace Amd64InstrDecode None, // 0xff3 }; - static InstrForm instrFormXOP9[1024] + static const InstrForm instrFormXOP9[1024] { None, // 0x000 None, // 0x001 @@ -9024,7 +9024,7 @@ namespace Amd64InstrDecode None, // 0xff3 }; - static InstrForm instrFormXOPA[1024] + static const InstrForm instrFormXOPA[1024] { None, // 0x000 None, // 0x001 diff --git a/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/Amd64InstructionTableGenerator.cs b/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/Amd64InstructionTableGenerator.cs index d90a1278c80dcb..ed1dc1c87fc712 100644 --- a/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/Amd64InstructionTableGenerator.cs +++ b/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/Amd64InstructionTableGenerator.cs @@ -1,3 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + using System; using System.Collections.Generic; using System.Globalization; @@ -865,7 +869,7 @@ void WriteCode() Console.WriteLine(" // Since there are 8 modrm.reg values, they occur is groups of 8."); Console.WriteLine(" // Each group is referenced from the other tables below using Extension|(index >> 3)."); currentExtension += 8; - Console.WriteLine($" static InstrForm instrFormExtension[{currentExtension + 1}]"); + Console.WriteLine($" static const InstrForm instrFormExtension[{currentExtension + 1}]"); Console.WriteLine(" {"); for (int i = 0; i < currentExtension; i++) { @@ -877,7 +881,7 @@ void WriteCode() Console.WriteLine(" };"); Console.WriteLine(); - Console.WriteLine($" static InstrForm instrFormPrimary[256]"); + Console.WriteLine($" static const InstrForm instrFormPrimary[256]"); Console.WriteLine(" {"); for (int i = 0; i < 4096; i+= 16) { @@ -889,7 +893,7 @@ void WriteCode() Console.WriteLine(" };"); Console.WriteLine(); - Console.WriteLine($" static InstrForm instrForm3DNow[256]"); + Console.WriteLine($" static const InstrForm instrForm3DNow[256]"); Console.WriteLine(" {"); for (int i = 0; i < 4096; i+= 16) { @@ -906,7 +910,7 @@ void WriteCode() foreach((string name, Map map) in mapTuples) { Console.WriteLine(); - Console.WriteLine($" static InstrForm instrForm{name}[1024]"); + Console.WriteLine($" static const InstrForm instrForm{name}[1024]"); Console.WriteLine(" {"); for (int i = 0; i < 4096; i+= 16) { diff --git a/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/Amd64InstructionTableGenerator.csproj b/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/Amd64InstructionTableGenerator.csproj index 6d647bf4e47327..d1eec22ab87e60 100644 --- a/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/Amd64InstructionTableGenerator.csproj +++ b/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/Amd64InstructionTableGenerator.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.2 + netcoreapp3.1 diff --git a/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/README.md b/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/README.md index d7a3172014923f..9f83da3bcaa320 100644 --- a/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/README.md +++ b/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/README.md @@ -30,8 +30,8 @@ and accurately mechanism to implement This function needs to be able to decode an arbitrary `amd64` instruction. The decoder currently must be able to identify: -- Whether the instruction includes a instruction pointer relative memory accesses -- The location of the memory displacement withing the instruction +- Whether the instruction includes an instruction pointer relative memory access +- The location of the memory displacement within the instruction - The instruction length in bytes - The size of the memory operation in bytes @@ -80,7 +80,7 @@ We will iterate through all the necessary set. Many of these combinations will lead to invalid/undefined encodings. This will cause the disassembler to give up and mark the disassemble as bad. -The disassemble will then resume trying to diassemble at the next boundary. +The disassemble will then resume trying to disassemble at the next boundary. To make sure the disassembler attempts to disassemble every instruction, we need to make sure the preceding instruction is always valid and terminates @@ -104,7 +104,7 @@ After the modrm byte, the generated instructions always include a const char* postamble = "0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,\n"; ``` -This meets the padding a consistency needs. +This meets the padding consistency needs. #### Ordering @@ -213,7 +213,7 @@ We continue parsing the first line of each group. #### Ignoring bad encodings -Many encoding are not valid. For `gdb`, these instructions are marked +Many encodings are not valid. For `gdb`, these instructions are marked `(bad)`. We filter and ignore these. #### Parsing the disassambly for each instruction sample @@ -247,7 +247,7 @@ To facilitate identifying sets of instructions, the creates an `opCodeExt`. For the `Primary` map this is simply the encoded opcode from the instruction shifted left by 4 bits. -For the #D Now `NOW3D` map this is simply the encoded immediate from the +For the 3D Now `NOW3D` map this is simply the encoded immediate from the instruction shifted left by 4 bits. For the `Secondary` `F38`, and `F39` maps this is the encoded opcode from @@ -351,10 +351,10 @@ of the disassembler may have disassembly bugs. Using newer disassemblers would mitigate this to some extent. ### Bugs -- Inadequate samples. Are thre other bits which modify instruction -behavior which we missed. +- Inadequate samples. Are there other bits which modify instruction +behavior which we missed? - Parser/Table generator implementation bugs. Does the parser do what it -was intended to do +was intended to do? ## Reasons to regenerate the file diff --git a/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/createOpcodes.cpp b/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/createOpcodes.cpp index a127d0f54ac8ff..de4abb70c07ceb 100644 --- a/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/createOpcodes.cpp +++ b/src/coreclr/src/debug/ee/amd64/gen_amd64InstrDecode/createOpcodes.cpp @@ -1,3 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + #include int main(int argc, char*argv[]) diff --git a/src/coreclr/src/debug/ee/controller.cpp b/src/coreclr/src/debug/ee/controller.cpp index 137fcf774067db..cd7dc03273eac3 100644 --- a/src/coreclr/src/debug/ee/controller.cpp +++ b/src/coreclr/src/debug/ee/controller.cpp @@ -23,6 +23,7 @@ #include "eeconfig.h" #include "../../vm/methoditer.h" +#include "../../vm/tailcallhelp.h" const char *GetTType( TraceType tt); @@ -5644,9 +5645,56 @@ bool DebuggerStepper::TrapStepInHelper( return false; } -FORCEINLINE bool IsTailCall(const BYTE * pTargetIP) +static bool IsTailCallJitHelper(const BYTE * ip) { - return TailCallStubManager::IsTailCallStubHelper(reinterpret_cast(pTargetIP)); + return TailCallStubManager::IsTailCallJitHelper(reinterpret_cast(ip)); +} + +// Check whether a call to an IP will be a tailcall dispatched by first +// returning. When a tailcall cannot be performed just with a jump instruction, +// the code will be doing a regular call to a managed function called the +// tailcall dispatcher. This functions dispatches tailcalls in a special way: if +// there is a previous "tailcall aware" frame, then it will simply record the +// next tailcall to perform and immediately return. Otherwise it will set up +// such a tailcall aware frame and dispatch tailcalls. In the former case the +// control flow will be a little peculiar in that the function will return +// immediately, so we need special handling in the debugger for it. This +// function detects that case to be used for those scenarios. +static bool IsTailCallThatReturns(const BYTE * ip, ControllerStackInfo* info) +{ + MethodDesc* pTailCallDispatcherMD = TailCallHelp::GetTailCallDispatcherMD(); + if (pTailCallDispatcherMD == NULL) + { + return false; + } + + TraceDestination trace; + if (!g_pEEInterface->TraceStub(ip, &trace) || !g_pEEInterface->FollowTrace(&trace)) + { + return false; + } + + MethodDesc* pTargetMD = + trace.GetTraceType() == TRACE_UNJITTED_METHOD + ? trace.GetMethodDesc() + : g_pEEInterface->GetNativeCodeMethodDesc(trace.GetAddress()); + + if (pTargetMD != pTailCallDispatcherMD) + { + return false; + } + + LOG((LF_CORDB, LL_INFO1000, "ITCTR: target %p is the tailcall dispatcher\n", ip)); + + _ASSERTE(info->HasReturnFrame()); + LPVOID retAddr = (LPVOID)GetControlPC(&info->GetReturnFrame().registers); + TailCallTls* tls = GetThread()->GetTailCallTls(); + LPVOID tailCallAwareRetAddr = tls->GetFrame()->TailCallAwareReturnAddress; + + LOG((LF_CORDB,LL_INFO1000, "ITCTR: ret addr is %p, tailcall aware ret addr is %p\n", + retAddr, tailCallAwareRetAddr)); + + return retAddr == tailCallAwareRetAddr; } // bool DebuggerStepper::TrapStep() TrapStep attepts to set a @@ -5864,11 +5912,18 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in) fCallingIntoFunclet = IsAddrWithinMethodIncludingFunclet(ji, info->m_activeFrame.md, walker.GetNextIP()) && ((CORDB_ADDRESS)(SIZE_T)walker.GetNextIP() != ji->m_addrOfCode); #endif - // At this point, we know that the call/branch target is not in the current method. - // So if the current instruction is a jump, this must be a tail call or possibly a jump to the finally. - // So, check if the call/branch target is the JIT helper for handling tail calls if we are not calling - // into the funclet. - if ((fIsJump && !fCallingIntoFunclet) || IsTailCall(walker.GetNextIP())) + // At this point, we know that the call/branch target is not + // in the current method. The possible cases is that this is + // a jump or a tailcall-via-helper. There are two separate + // tailcalling mechanisms: on x86 we use a JIT helper which + // will look like a regular call and which won't return, so + // a step over becomes a step out. On other platforms we use + // a separate mechanism that will perform a tailcall by + // returning to an IL stub first. A step over in this case + // is done by stepping out to the previous user function + // (non IL stub). + if ((fIsJump && !fCallingIntoFunclet) || IsTailCallJitHelper(walker.GetNextIP()) || + IsTailCallThatReturns(walker.GetNextIP(), info)) { // A step-over becomes a step-out for a tail call. if (!in) @@ -6014,7 +6069,7 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in) return true; } - if (IsTailCall(walker.GetNextIP())) + if (IsTailCallJitHelper(walker.GetNextIP()) || IsTailCallThatReturns(walker.GetNextIP(), info)) { if (!in) { @@ -6306,7 +6361,19 @@ void DebuggerStepper::TrapStepOut(ControllerStackInfo *info, bool fForceTraditio } else #endif // FEATURE_MULTICASTSTUB_AS_IL - if (info->m_activeFrame.managed) + if (info->m_activeFrame.md != nullptr && info->m_activeFrame.md->IsILStub() && + info->m_activeFrame.md->AsDynamicMethodDesc()->GetILStubResolver()->GetStubType() == ILStubResolver::TailCallCallTargetStub) + { + // Normally the stack trace would not include IL stubs, but we + // include this specific IL stub so that we can check if a call into + // the tailcall dispatcher will result in any user code being + // executed or will return and allow a previous tailcall dispatcher + // to deal with the tailcall. Thus we just skip that frame here. + LOG((LF_CORDB, LL_INFO10000, + "DS::TSO: CallTailCallTarget frame.\n")); + continue; + } + else if (info->m_activeFrame.managed) { LOG((LF_CORDB, LL_INFO10000, "DS::TSO: return frame is managed.\n")); @@ -6488,7 +6555,6 @@ void DebuggerStepper::TrapStepOut(ControllerStackInfo *info, bool fForceTraditio GetControlPC(&(info->m_activeFrame.registers)), info->GetReturnFrame().fp.GetSPValue())); - AddAndActivateNativePatchForAddress((CORDB_ADDRESS_TYPE *)GetControlPC(&(info->m_activeFrame.registers)), info->GetReturnFrame().fp, FALSE, diff --git a/src/coreclr/src/debug/ee/frameinfo.cpp b/src/coreclr/src/debug/ee/frameinfo.cpp index f718d144cfc5e5..1f043f710aed67 100644 --- a/src/coreclr/src/debug/ee/frameinfo.cpp +++ b/src/coreclr/src/debug/ee/frameinfo.cpp @@ -1559,20 +1559,27 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data) } else #endif // FEATURE_EH_FUNCLETS - // We should ignore IL stubs with no frames in our stackwalking. - // The only exception is dynamic methods. We want to report them when SIS is turned on. + // We ignore most IL stubs with no frames in our stackwalking. As exceptions + // we will always report multicast stubs and the tailcall call target stubs + // since we treat them specially in the debugger. if ((md != NULL) && md->IsILStub() && pCF->IsFrameless()) { + _ASSERTE(md->IsDynamicMethod()); + DynamicMethodDesc* dMD = md->AsDynamicMethodDesc(); #ifdef FEATURE_MULTICASTSTUB_AS_IL - if(md->AsDynamicMethodDesc()->IsMulticastStub()) + use |= dMD->IsMulticastStub(); +#endif + use |= dMD->GetILStubResolver()->GetStubType() == ILStubResolver::TailCallCallTargetStub; + + if (use) { - use = true; d->info.managed = true; d->info.internal = false; } -#endif - // We do nothing here. - LOG((LF_CORDB, LL_INFO100000, "DWSP: Skip frameless IL stub.\n")); + else + { + LOG((LF_CORDB, LL_INFO100000, "DWSP: Skip frameless IL stub.\n")); + } } else // For frames w/o method data, send them as an internal stub frame. diff --git a/src/coreclr/src/debug/ee/rcthread.cpp b/src/coreclr/src/debug/ee/rcthread.cpp index 85186e080034fa..c119dbcc2dda7b 100644 --- a/src/coreclr/src/debug/ee/rcthread.cpp +++ b/src/coreclr/src/debug/ee/rcthread.cpp @@ -241,8 +241,8 @@ HRESULT DebuggerIPCControlBlock::Init( memset( this, 0, sizeof( DebuggerIPCControlBlock) ); // Setup version checking info. - m_verMajor = CLR_BUILD_VERSION; - m_verMinor = CLR_BUILD_VERSION_QFE; + m_verMajor = RuntimeFileBuildVersion; + m_verMinor = RuntimeFileRevisionVersion; #ifdef _DEBUG m_checkedBuild = true; diff --git a/src/coreclr/src/debug/inc/dbgipcevents.h b/src/coreclr/src/debug/inc/dbgipcevents.h index e9c095efb2e110..45c6bf9ad100e6 100644 --- a/src/coreclr/src/debug/inc/dbgipcevents.h +++ b/src/coreclr/src/debug/inc/dbgipcevents.h @@ -21,8 +21,7 @@ // Get version numbers for IPCHeader stamp -#include "ndpversion.h" - +#include "clrversion.h" #include "dbgappdomain.h" #include "./common.h" diff --git a/src/coreclr/src/debug/inc/diagnosticsipc.h b/src/coreclr/src/debug/inc/diagnosticsipc.h index eabea6c3ceaea0..225299c2b8992f 100644 --- a/src/coreclr/src/debug/inc/diagnosticsipc.h +++ b/src/coreclr/src/debug/inc/diagnosticsipc.h @@ -18,24 +18,80 @@ typedef void (*ErrorCallback)(const char *szMessage, uint32_t code); class IpcStream final { public: + static constexpr int32_t InfiniteTimeout = -1; ~IpcStream(); - bool Read(void *lpBuffer, const uint32_t nBytesToRead, uint32_t &nBytesRead) const; - bool Write(const void *lpBuffer, const uint32_t nBytesToWrite, uint32_t &nBytesWritten) const; + bool Read(void *lpBuffer, const uint32_t nBytesToRead, uint32_t &nBytesRead, const int32_t timeoutMs = IpcStream::InfiniteTimeout); + bool Write(const void *lpBuffer, const uint32_t nBytesToWrite, uint32_t &nBytesWritten, const int32_t timeoutMs = IpcStream::InfiniteTimeout); bool Flush() const; + void Close(ErrorCallback callback = nullptr); class DiagnosticsIpc final { public: + enum ConnectionMode + { + CLIENT, + SERVER + }; + + enum class PollEvents : uint8_t + { + TIMEOUT = 0x00, // implies timeout + SIGNALED = 0x01, // ready for use + HANGUP = 0x02, // connection remotely closed + ERR = 0x04 // other error + }; + + // The bookeeping struct used for polling on server and client structs + struct IpcPollHandle + { + // Only one of these will be non-null, treat as a union + DiagnosticsIpc *pIpc; + IpcStream *pStream; + + // contains some set of PollEvents + // will be set by Poll + // Any values here are ignored by Poll + uint8_t revents; + + // a cookie assignable by upstream users for additional bookkeeping + void *pUserData; + }; + + // Poll + // Parameters: + // - IpcPollHandle * rgpIpcPollHandles: Array of IpcPollHandles to poll + // - uint32_t nHandles: The number of handles to poll + // - int32_t timeoutMs: The timeout in milliseconds for the poll (-1 == infinite) + // Returns: + // int32_t: -1 on error, 0 on timeout, >0 on successful poll + // Remarks: + // Check the events returned in revents for each IpcPollHandle to find the signaled handle. + // Signaled DiagnosticsIpcs can call Accept() without blocking. + // Signaled IpcStreams can call Read(...) without blocking. + // The caller is responsible for cleaning up "hung up" connections. + static int32_t Poll(IpcPollHandle *rgIpcPollHandles, uint32_t nHandles, int32_t timeoutMs, ErrorCallback callback = nullptr); + + ConnectionMode mode; + ~DiagnosticsIpc(); - //! Creates an IPC object - static DiagnosticsIpc *Create(const char *const pIpcName, ErrorCallback callback = nullptr); + // Creates an IPC object + static DiagnosticsIpc *Create(const char *const pIpcName, ConnectionMode mode, ErrorCallback callback = nullptr); + + // puts the DiagnosticsIpc into Listening Mode + // Re-entrant safe + bool Listen(ErrorCallback callback = nullptr); + + // produces a connected stream from a server-mode DiagnosticsIpc. Blocks until a connection is available. + IpcStream *Accept(ErrorCallback callback = nullptr); - //! Enables the underlaying IPC implementation to accept connection. - IpcStream *Accept(ErrorCallback callback = nullptr) const; + // Connect to a server and returns a connected stream + IpcStream *Connect(ErrorCallback callback = nullptr); - //! Closes an open IPC. - void Close(ErrorCallback callback = nullptr); + // Closes an open IPC. + // Only attempts minimal cleanup if isShutdown==true, i.e., unlinks Unix Domain Socket on Linux, no-op on Windows + void Close(bool isShutdown = false, ErrorCallback callback = nullptr); private: @@ -44,18 +100,22 @@ class IpcStream final sockaddr_un *const _pServerAddress; bool _isClosed; - DiagnosticsIpc(const int serverSocket, sockaddr_un *const pServerAddress); + DiagnosticsIpc(const int serverSocket, sockaddr_un *const pServerAddress, ConnectionMode mode = ConnectionMode::SERVER); - //! Used to unlink the socket so it can be removed from the filesystem - //! when the last reference to it is closed. + // Used to unlink the socket so it can be removed from the filesystem + // when the last reference to it is closed. void Unlink(ErrorCallback callback = nullptr); #else static const uint32_t MaxNamedPipeNameLength = 256; char _pNamedPipeName[MaxNamedPipeNameLength]; // https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createnamedpipea + HANDLE _hPipe = INVALID_HANDLE_VALUE; + OVERLAPPED _oOverlap = {}; - DiagnosticsIpc(const char(&namedPipeName)[MaxNamedPipeNameLength]); + DiagnosticsIpc(const char(&namedPipeName)[MaxNamedPipeNameLength], ConnectionMode mode = ConnectionMode::SERVER); #endif /* TARGET_UNIX */ + bool _isListening; + DiagnosticsIpc() = delete; DiagnosticsIpc(const DiagnosticsIpc &src) = delete; DiagnosticsIpc(DiagnosticsIpc &&src) = delete; @@ -66,12 +126,17 @@ class IpcStream final private: #ifdef TARGET_UNIX int _clientSocket = -1; - IpcStream(int clientSocket) : _clientSocket(clientSocket) {} + IpcStream(int clientSocket, int serverSocket, DiagnosticsIpc::ConnectionMode mode = DiagnosticsIpc::ConnectionMode::SERVER) + : _clientSocket(clientSocket), _mode(mode) {} #else HANDLE _hPipe = INVALID_HANDLE_VALUE; - IpcStream(HANDLE hPipe) : _hPipe(hPipe) {} + OVERLAPPED _oOverlap = {}; + BOOL _isTestReading = false; // used to check whether we are already doing a 0-byte read to test for data + IpcStream(HANDLE hPipe, DiagnosticsIpc::ConnectionMode mode = DiagnosticsIpc::ConnectionMode::SERVER); #endif /* TARGET_UNIX */ + DiagnosticsIpc::ConnectionMode _mode; + IpcStream() = delete; IpcStream(const IpcStream &src) = delete; IpcStream(IpcStream &&src) = delete; diff --git a/src/coreclr/src/debug/runtimeinfo/CMakeLists.txt b/src/coreclr/src/debug/runtimeinfo/CMakeLists.txt index 96a3d464b13366..99b8f5edd08453 100644 --- a/src/coreclr/src/debug/runtimeinfo/CMakeLists.txt +++ b/src/coreclr/src/debug/runtimeinfo/CMakeLists.txt @@ -6,6 +6,6 @@ set(RUNTIMEINFO_SOURCES add_library_clr(runtimeinfo STATIC ${RUNTIMEINFO_SOURCES}) -add_dependencies(runtimeinfo runtime_module_index_header) -add_dependencies(runtimeinfo dac_module_index_header) -add_dependencies(runtimeinfo dbi_module_index_header) +add_dependencies(runtimeinfo coreclr_module_index_header) +add_dependencies(runtimeinfo mscordaccore_module_index_header) +add_dependencies(runtimeinfo mscordbi_module_index_header) diff --git a/src/coreclr/src/dlls/dbgshim/CMakeLists.txt b/src/coreclr/src/dlls/dbgshim/CMakeLists.txt index b3b326f0bf49da..ef2d0e360782b2 100644 --- a/src/coreclr/src/dlls/dbgshim/CMakeLists.txt +++ b/src/coreclr/src/dlls/dbgshim/CMakeLists.txt @@ -26,14 +26,18 @@ else(CLR_CMAKE_TARGET_WIN32) generate_exports_file(${DEF_SOURCES} ${EXPORTS_FILE}) endif(CLR_CMAKE_TARGET_WIN32) -if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) +if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) # This option is necessary to ensure that the overloaded delete operator defined inside # of the utilcode will be used instead of the standard library delete operator. set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Xlinker -Bsymbolic") # Add linker exports file option - set(EXPORTS_LINKER_OPTION -Wl,--version-script=${EXPORTS_FILE}) -endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) + if(CLR_CMAKE_HOST_SUNOS) + set(EXPORTS_LINKER_OPTION -Wl,-M,${EXPORTS_FILE}) + else(CLR_CMAKE_HOST_SUNOS) + set(EXPORTS_LINKER_OPTION -Wl,--version-script=${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_SUNOS) +endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) if(CLR_CMAKE_HOST_OSX) # Add linker exports file option diff --git a/src/coreclr/src/dlls/dbgshim/dbgshim.rc b/src/coreclr/src/dlls/dbgshim/dbgshim.rc index c1d53acc7d9be5..9e4153871899ee 100644 --- a/src/coreclr/src/dlls/dbgshim/dbgshim.rc +++ b/src/coreclr/src/dlls/dbgshim/dbgshim.rc @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#include "resource.h" - #define FX_VER_FILEDESCRIPTION_STR "Microsoft .NET Runtime Multi-CLR Debugging Helper\0" #include diff --git a/src/coreclr/src/dlls/dbgshim/resource.h b/src/coreclr/src/dlls/dbgshim/resource.h deleted file mode 100644 index 45274bad55e154..00000000000000 --- a/src/coreclr/src/dlls/dbgshim/resource.h +++ /dev/null @@ -1,3 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. diff --git a/src/coreclr/src/dlls/mscordac/CMakeLists.txt b/src/coreclr/src/dlls/mscordac/CMakeLists.txt index e8e9ef167291b6..ddf66b4a0d45b7 100644 --- a/src/coreclr/src/dlls/mscordac/CMakeLists.txt +++ b/src/coreclr/src/dlls/mscordac/CMakeLists.txt @@ -31,9 +31,9 @@ else(CLR_CMAKE_HOST_WIN32) # Add dependency on export file add_custom_target(mscordaccore_exports DEPENDS ${EXPORTS_FILE}) - if(CLR_CMAKE_HOST_OSX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) + if(CLR_CMAKE_HOST_OSX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) generate_exports_file(${DEF_SOURCES} ${EXPORTS_FILE}) - endif(CLR_CMAKE_HOST_OSX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) + endif(CLR_CMAKE_HOST_OSX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) if(CLR_CMAKE_HOST_LINUX) @@ -73,7 +73,7 @@ else(CLR_CMAKE_HOST_WIN32) endif(CLR_CMAKE_HOST_LINUX) endif(CLR_CMAKE_HOST_WIN32) -if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) +if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) # This option is necessary to ensure that the overloaded delete operator defined inside # of the utilcode will be used instead of the standard library delete operator. set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Xlinker -Bsymbolic") @@ -88,8 +88,12 @@ if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) set(END_WHOLE_ARCHIVE -Wl,--no-whole-archive) # Add linker exports file option - set(EXPORTS_LINKER_OPTION -Wl,--version-script=${EXPORTS_FILE}) -endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) + if(CLR_CMAKE_HOST_SUNOS) + set(EXPORTS_LINKER_OPTION -Wl,-M,${EXPORTS_FILE}) + else(CLR_CMAKE_HOST_SUNOS) + set(EXPORTS_LINKER_OPTION -Wl,--version-script=${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_SUNOS) +endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) if(CLR_CMAKE_HOST_OSX) # Add linker exports file option @@ -190,24 +194,7 @@ target_link_libraries(mscordaccore PRIVATE ${COREDAC_LIBRARIES}) # Create the DAC module index header file containing the DAC build id # for xplat and the timestamp/size on Windows. if(FEATURE_SINGLE_FILE_DIAGNOSTICS) - set( - DAC_MODULE_INDEX_FILE - ${GENERATED_INCLUDE_DIR}/dacmoduleindex.h - ) - add_custom_command( - OUTPUT ${DAC_MODULE_INDEX_FILE} - COMMAND ${CLR_DOTNET_COMMAND} ${CMAKE_INSTALL_PREFIX}/GetModuleIndex/GetModuleIndex.dll $ ${DAC_MODULE_INDEX_FILE} - DEPENDS mscordaccore - COMMENT "Generating DAC module index file -> ${DAC_MODULE_INDEX_FILE}" - ) - set_source_files_properties( - ${DAC_MODULE_INDEX_FILE} - PROPERTIES GENERATED TRUE - ) - add_custom_target( - dac_module_index_header - DEPENDS ${DAC_MODULE_INDEX_FILE} - ) + generate_module_index(mscordaccore ${GENERATED_INCLUDE_DIR}/dacmoduleindex.h) endif(FEATURE_SINGLE_FILE_DIAGNOSTICS) # add the install targets diff --git a/src/coreclr/src/dlls/mscordbi/CMakeLists.txt b/src/coreclr/src/dlls/mscordbi/CMakeLists.txt index 3f4568fa75d62f..ffd48ee489aba5 100644 --- a/src/coreclr/src/dlls/mscordbi/CMakeLists.txt +++ b/src/coreclr/src/dlls/mscordbi/CMakeLists.txt @@ -19,7 +19,7 @@ if(CLR_CMAKE_HOST_LINUX) list(APPEND MSCORDBI_SOURCES ${PAL_REDEFINES_FILE}) endif(CLR_CMAKE_HOST_LINUX) -if(CLR_CMAKE_TARGET_WIN32) +if(CLR_CMAKE_HOST_WIN32) add_definitions(-DFX_VER_INTERNALNAME_STR=mscordbi.dll) list(APPEND MSCORDBI_SOURCES @@ -35,20 +35,24 @@ if(CLR_CMAKE_TARGET_WIN32) preprocess_file(${DEF_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/mscordbi.def) list(APPEND MSCORDBI_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/mscordbi.def) -else(CLR_CMAKE_TARGET_WIN32) +else(CLR_CMAKE_HOST_WIN32) set(DEF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/mscordbi_unixexports.src) set(EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/mscordbi.exports) generate_exports_file(${DEF_SOURCES} ${EXPORTS_FILE}) -endif(CLR_CMAKE_TARGET_WIN32) +endif(CLR_CMAKE_HOST_WIN32) -if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) +if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) # This option is necessary to ensure that the overloaded new/delete operators defined inside # of the utilcode will be used instead of the standard library delete operator. set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Xlinker -Bsymbolic") # Add linker exports file option - set(EXPORTS_LINKER_OPTION -Wl,--version-script=${EXPORTS_FILE}) -endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) + if(CLR_CMAKE_HOST_SUNOS) + set(EXPORTS_LINKER_OPTION -Wl,-M,${EXPORTS_FILE}) + else(CLR_CMAKE_HOST_SUNOS) + set(EXPORTS_LINKER_OPTION -Wl,--version-script=${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_SUNOS) +endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) if(CLR_CMAKE_HOST_OSX) # Add linker exports file option @@ -79,9 +83,13 @@ set(COREDBI_LIBRARIES ) if(CLR_CMAKE_HOST_WIN32) + if(CLR_CMAKE_TARGET_WIN32) + set(COREDBI_TARGET_WIN32_LIBRARIES mdwinmd_dbi) + endif(CLR_CMAKE_TARGET_WIN32) + list(APPEND COREDBI_LIBRARIES mdhotdata-staticcrt - mdwinmd_dbi + ${COREDBI_TARGET_WIN32_LIBRARIES} kernel32.lib advapi32.lib ole32.lib @@ -120,24 +128,7 @@ endif(CLR_CMAKE_HOST_WIN32) # Create the DBI module index header file containing the DBI build id # for xplat and the timestamp/size on Windows. if(FEATURE_SINGLE_FILE_DIAGNOSTICS) - set( - DBI_MODULE_INDEX_FILE - ${GENERATED_INCLUDE_DIR}/dbimoduleindex.h - ) - add_custom_command( - OUTPUT ${DBI_MODULE_INDEX_FILE} - COMMAND ${CLR_DOTNET_COMMAND} ${CMAKE_INSTALL_PREFIX}/GetModuleIndex/GetModuleIndex.dll $ ${DBI_MODULE_INDEX_FILE} - DEPENDS mscordbi - COMMENT "Generating DBI module index file -> ${DBI_MODULE_INDEX_FILE}" - ) - set_source_files_properties( - ${DBI_MODULE_INDEX_FILE} - PROPERTIES GENERATED TRUE - ) - add_custom_target( - dbi_module_index_header - DEPENDS ${DBI_MODULE_INDEX_FILE} - ) + generate_module_index(mscordbi ${GENERATED_INCLUDE_DIR}/dbimoduleindex.h) endif(FEATURE_SINGLE_FILE_DIAGNOSTICS) # add the install targets diff --git a/src/coreclr/src/dlls/mscoree/coreclr/CMakeLists.txt b/src/coreclr/src/dlls/mscoree/coreclr/CMakeLists.txt index 777a2869e4f7ce..918fbf27a68488 100644 --- a/src/coreclr/src/dlls/mscoree/coreclr/CMakeLists.txt +++ b/src/coreclr/src/dlls/mscoree/coreclr/CMakeLists.txt @@ -32,7 +32,7 @@ else(CLR_CMAKE_HOST_WIN32) set(EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/coreclr.exports) generate_exports_file(${DEF_SOURCES} ${EXPORTS_FILE}) - if(CLR_CMAKE_TARGET_LINUX OR CLR_CMAKE_TARGET_FREEBSD OR CLR_CMAKE_TARGET_NETBSD) + if(CLR_CMAKE_TARGET_LINUX OR CLR_CMAKE_TARGET_FREEBSD OR CLR_CMAKE_TARGET_NETBSD OR CLR_CMAKE_TARGET_SUNOS) # This option is necessary to ensure that the overloaded delete operator defined inside # of the utilcode will be used instead of the standard library delete operator. add_link_options("LINKER:-Bsymbolic") @@ -46,8 +46,12 @@ else(CLR_CMAKE_HOST_WIN32) set(START_WHOLE_ARCHIVE -Wl,--whole-archive) set(END_WHOLE_ARCHIVE -Wl,--no-whole-archive) - set(EXPORTS_LINKER_OPTION -Wl,--version-script=${EXPORTS_FILE}) - endif(CLR_CMAKE_TARGET_LINUX OR CLR_CMAKE_TARGET_FREEBSD OR CLR_CMAKE_TARGET_NETBSD) + if(CLR_CMAKE_TARGET_SUNOS) + set(EXPORTS_LINKER_OPTION -Wl,-M,${EXPORTS_FILE}) + elseif(CLR_CMAKE_TARGET_SUNOS) + set(EXPORTS_LINKER_OPTION -Wl,--version-script=${EXPORTS_FILE}) + endif(CLR_CMAKE_TARGET_SUNOS) + endif(CLR_CMAKE_TARGET_LINUX OR CLR_CMAKE_TARGET_FREEBSD OR CLR_CMAKE_TARGET_NETBSD OR CLR_CMAKE_TARGET_SUNOS) if(CLR_CMAKE_TARGET_OSX) # These options are used to force every object to be included even if it's unused. @@ -59,7 +63,7 @@ else(CLR_CMAKE_HOST_WIN32) if(CLR_CMAKE_TARGET_ANDROID AND CLR_CMAKE_HOST_ARCH_ARM) set(EXPORTS_LINKER_OPTION "${EXPORTS_LINKER_OPTION} -Wl,--no-warn-shared-textrel") - endif() + endif(CLR_CMAKE_TARGET_ANDROID AND CLR_CMAKE_HOST_ARCH_ARM) endif (CLR_CMAKE_HOST_WIN32) @@ -146,6 +150,10 @@ if(CLR_CMAKE_TARGET_LINUX) tracepointprovider ${END_WHOLE_ARCHIVE} ) +elseif(CLR_CMAKE_TARGET_SUNOS) + list(APPEND CORECLR_LIBRARIES + socket + ) endif(CLR_CMAKE_TARGET_LINUX) if(FEATURE_PERFTRACING) @@ -167,24 +175,7 @@ target_link_libraries(coreclr ${CORECLR_LIBRARIES}) # Create the runtime module index header file containing the coreclr build id # for xplat and the timestamp/size on Windows. if(FEATURE_SINGLE_FILE_DIAGNOSTICS) - set( - RUNTIME_MODULE_INDEX_FILE - ${GENERATED_INCLUDE_DIR}/runtimemoduleindex.h - ) - add_custom_command( - OUTPUT ${RUNTIME_MODULE_INDEX_FILE} - COMMAND ${CLR_DOTNET_COMMAND} ${CMAKE_INSTALL_PREFIX}/GetModuleIndex/GetModuleIndex.dll $ ${RUNTIME_MODULE_INDEX_FILE} - DEPENDS coreclr - COMMENT "Generating runtime module index file -> ${RUNTIME_MODULE_INDEX_FILE}" - ) - set_source_files_properties( - ${RUNTIME_MODULE_INDEX_FILE} - PROPERTIES GENERATED TRUE - ) - add_custom_target( - runtime_module_index_header - DEPENDS ${RUNTIME_MODULE_INDEX_FILE} - ) + generate_module_index(coreclr ${GENERATED_INCLUDE_DIR}/runtimemoduleindex.h) endif(FEATURE_SINGLE_FILE_DIAGNOSTICS) if(CLR_CMAKE_TARGET_WIN32) diff --git a/src/coreclr/src/dlls/mscoree/mscoree.cpp b/src/coreclr/src/dlls/mscoree/mscoree.cpp index d87d9bebc0ca02..2ad1e9d6f284ef 100644 --- a/src/coreclr/src/dlls/mscoree/mscoree.cpp +++ b/src/coreclr/src/dlls/mscoree/mscoree.cpp @@ -16,8 +16,6 @@ #include "metadataexports.h" #include "ex.h" -#include "product_version.h" - #include // Globals @@ -316,21 +314,6 @@ STDAPI ReOpenMetaDataWithMemoryEx( return hr; } -// Replacement for legacy shim API GetCORRequiredVersion(...) used in linked libraries. -// Used in code:TiggerStorage::GetDefaultVersion#CallTo_CLRRuntimeHostInternal_GetImageVersionString. -HRESULT -CLRRuntimeHostInternal_GetImageVersionString( - __out_ecount_opt(*pcchBuffer) LPWSTR wszBuffer, - __inout DWORD *pcchBuffer) -{ - // Simply forward the call to the ICLRRuntimeHostInternal implementation. - STATIC_CONTRACT_WRAPPER; - - HRESULT hr = GetCORVersionInternal(wszBuffer, *pcchBuffer, pcchBuffer); - - return hr; -} // CLRRuntimeHostInternal_GetImageVersionString - STDAPI GetCORSystemDirectoryInternaL(SString& pBuffer) { CONTRACTL { @@ -364,67 +347,6 @@ STDAPI GetCORSystemDirectoryInternaL(SString& pBuffer) return hr; } -// -// Returns version of the runtime (null-terminated). -// -// Arguments: -// pBuffer - [out] Output buffer allocated by caller of size cchBuffer. -// cchBuffer - Size of pBuffer in characters. -// pdwLength - [out] Size of the version string in characters (incl. null-terminator). Will be filled -// even if ERROR_INSUFFICIENT_BUFFER is returned. -// -// Return Value: -// S_OK - Output buffer contains the version string. -// HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) - *pdwLength contains required size of the buffer in -// characters. - -STDAPI GetCORVersionInternal( -__out_ecount_z_opt(cchBuffer) LPWSTR pBuffer, - DWORD cchBuffer, - __out DWORD *pdwLength) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; - PRECONDITION(CheckPointer(pBuffer, NULL_OK)); - PRECONDITION(CheckPointer(pdwLength)); - } CONTRACTL_END; - - HRESULT hr; - BEGIN_ENTRYPOINT_NOTHROW; - - if ((pBuffer != NULL) && (cchBuffer > 0)) - { // Initialize the output for case the function fails - *pBuffer = W('\0'); - } - -#define VERSION_NUMBER_NOSHIM W("v") QUOTE_MACRO_L(CLR_MAJOR_VERSION.CLR_MINOR_VERSION.CLR_BUILD_VERSION) - - DWORD length = (DWORD)(wcslen(VERSION_NUMBER_NOSHIM) + 1); - if (length > cchBuffer) - { - hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); - } - else - { - if (pBuffer == NULL) - { - hr = E_POINTER; - } - else - { - CopyMemory(pBuffer, VERSION_NUMBER_NOSHIM, length * sizeof(WCHAR)); - hr = S_OK; - } - } - *pdwLength = length; - - END_ENTRYPOINT_NOTHROW; - return hr; - -} - static DWORD g_dwSystemDirectory = 0; static WCHAR * g_pSystemDirectory = NULL; diff --git a/src/coreclr/src/dlls/mscoree/unixinterface.cpp b/src/coreclr/src/dlls/mscoree/unixinterface.cpp index 35d7c56c14c8e4..ca4d452a8edaef 100644 --- a/src/coreclr/src/dlls/mscoree/unixinterface.cpp +++ b/src/coreclr/src/dlls/mscoree/unixinterface.cpp @@ -18,6 +18,7 @@ #ifdef FEATURE_GDBJIT #include "../../vm/gdbjithelpers.h" #endif // FEATURE_GDBJIT +#include "bundle.h" #define ASSERTE_ALL_BUILDS(expr) _ASSERTE_ALL_BUILDS(__FILE__, (expr)) @@ -112,7 +113,8 @@ static void ConvertConfigPropertiesToUnicode( const char** propertyValues, int propertyCount, LPCWSTR** propertyKeysWRef, - LPCWSTR** propertyValuesWRef) + LPCWSTR** propertyValuesWRef, + BundleProbe** bundleProbe) { LPCWSTR* propertyKeysW = new (nothrow) LPCWSTR[propertyCount]; ASSERTE_ALL_BUILDS(propertyKeysW != nullptr); @@ -124,17 +126,19 @@ static void ConvertConfigPropertiesToUnicode( { propertyKeysW[propertyIndex] = StringToUnicode(propertyKeys[propertyIndex]); propertyValuesW[propertyIndex] = StringToUnicode(propertyValues[propertyIndex]); + + if (strcmp(propertyKeys[propertyIndex], "BUNDLE_PROBE") == 0) + { + // If this application is a single-file bundle, the bundle-probe callback + // is passed in as the value of "BUNDLE_PROBE" property (encoded as a string). + *bundleProbe = (BundleProbe*)_wcstoui64(propertyValuesW[propertyIndex], nullptr, 0); + } } *propertyKeysWRef = propertyKeysW; *propertyValuesWRef = propertyValuesW; } -#if !defined(FEATURE_MERGE_JIT_AND_ENGINE) -// Reference to the global holding the path to the JIT -extern LPCWSTR g_CLRJITPath; -#endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE) - #ifdef FEATURE_GDBJIT GetInfoForMethodDelegate getInfoForMethodDelegate = NULL; extern "C" int coreclr_create_delegate(void*, unsigned int, const char*, const char*, const char*, void**); @@ -188,21 +192,25 @@ int coreclr_initialize( LPCWSTR* propertyKeysW; LPCWSTR* propertyValuesW; + BundleProbe* bundleProbe = nullptr; + ConvertConfigPropertiesToUnicode( propertyKeys, propertyValues, propertyCount, &propertyKeysW, - &propertyValuesW); + &propertyValuesW, + &bundleProbe); + + if (bundleProbe != nullptr) + { + static Bundle bundle(StringToUnicode(exePath), bundleProbe); + Bundle::AppBundle = &bundle; + } // This will take ownership of propertyKeysWTemp and propertyValuesWTemp Configuration::InitializeConfigurationKnobs(propertyCount, propertyKeysW, propertyValuesW); -#if !defined(FEATURE_MERGE_JIT_AND_ENGINE) - // Fetch the path to JIT binary, if specified - g_CLRJITPath = Configuration::GetKnobStringValue(W("JIT_PATH")); -#endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE) - STARTUP_FLAGS startupFlags; InitializeStartupFlags(&startupFlags); diff --git a/src/coreclr/src/dlls/mscorrc/mscorrc.rc b/src/coreclr/src/dlls/mscorrc/mscorrc.rc index 8a7410ef25b2d5..4573e20be97ae4 100644 --- a/src/coreclr/src/dlls/mscorrc/mscorrc.rc +++ b/src/coreclr/src/dlls/mscorrc/mscorrc.rc @@ -344,7 +344,7 @@ BEGIN IDS_EE_WINRT_NOT_FACTORY_FOR_TYPE "Windows Runtime factory '%1' is not a factory for Windows Runtime type '%2'." IDS_EE_WINRT_INVALID_FACTORY_FOR_TYPE "Windows Runtime type '%1' has a invalid Windows Runtime factory" IDS_EE_CANNOTCAST_NOMARSHAL "The Windows Runtime Object can only be used in the threading context where it was created, because it implements INoMarshal or has MarshalingBehaviorAttribute(MarshalingType.None) set." - IDS_EE_WINRT_WEAKREF_BAD_TYPE "The object resolved by a native IWeakReference has an incompatible type for its managed WeakReference instance.\r\nExpected WeakReference target type: '%1'\r\nNative IWeakReference returned type: '%2'" + IDS_EE_NATIVE_COM_WEAKREF_BAD_TYPE "The object resolved by a native IWeakReference has an incompatible type for its managed WeakReference instance.\r\nExpected WeakReference target type: '%1'\r\nNative IWeakReference returned type: '%2'" #endif // FEATURE_COMINTEROP IDS_EE_INTEROP_CODE_SIZE_COMMENT "Code size" diff --git a/src/coreclr/src/dlls/mscorrc/resource.h b/src/coreclr/src/dlls/mscorrc/resource.h index 342c0570d493bb..4011efb748215d 100644 --- a/src/coreclr/src/dlls/mscorrc/resource.h +++ b/src/coreclr/src/dlls/mscorrc/resource.h @@ -600,7 +600,7 @@ #ifdef FEATURE_COMINTEROP -#define IDS_EE_WINRT_WEAKREF_BAD_TYPE 0x262e +#define IDS_EE_NATIVE_COM_WEAKREF_BAD_TYPE 0x262e #endif // FEATURE_COMINTEROP #define IDS_EE_BADMARSHAL_TYPE_ANSIBSTR 0x262f diff --git a/src/coreclr/src/gc/env/etmdummy.h b/src/coreclr/src/gc/env/etmdummy.h index 7435df7f8137b2..ba4c4cf96a5db3 100644 --- a/src/coreclr/src/gc/env/etmdummy.h +++ b/src/coreclr/src/gc/env/etmdummy.h @@ -164,6 +164,7 @@ #define FireEtwGCMarkWithType(HeapNum, ClrInstanceID, Type, Bytes) 0 #define FireEtwGCJoin_V2(Heap, JoinTime, JoinType, ClrInstanceID, JoinID) 0 #define FireEtwGCPerHeapHistory_V3(ClrInstanceID, FreeListAllocated, FreeListRejected, EndOfSegAllocated, CondemnedAllocated, PinnedAllocated, PinnedAllocatedAdvance, RunningFreeListEfficiency, CondemnReasons0, CondemnReasons1, CompactMechanisms, ExpandMechanisms, HeapIndex, ExtraGen0Commit, Count, Values_Len_, Values) 0 +#define FireEtwGCGlobalHeapHistory_V2(FinalYoungestDesired, NumHeaps, CondemnedGeneration, Gen0ReductionCount, Reason, GlobalMechanisms, ClrInstanceID, PauseMode, MemoryPressure) 0 #define FireEtwGCGlobalHeapHistory_V3(FinalYoungestDesired, NumHeaps, CondemnedGeneration, Gen0ReductionCount, Reason, GlobalMechanisms, ClrInstanceID, PauseMode, MemoryPressure, CondemnReasons0, CondemnReasons1) 0 #define FireEtwDebugIPCEventStart() 0 #define FireEtwDebugIPCEventEnd() 0 diff --git a/src/coreclr/src/gc/env/gcenv.base.h b/src/coreclr/src/gc/env/gcenv.base.h index b8fd0862db96b2..837291f345d49a 100644 --- a/src/coreclr/src/gc/env/gcenv.base.h +++ b/src/coreclr/src/gc/env/gcenv.base.h @@ -12,6 +12,9 @@ #endif // _MSC_VER #if !defined(_MSC_VER) +#ifdef __sun +#include +#endif #define _alloca alloca #endif //_MSC_VER diff --git a/src/coreclr/src/gc/env/gcenv.ee.h b/src/coreclr/src/gc/env/gcenv.ee.h index ab0fe80620ffd9..fa4f2dcd765889 100644 --- a/src/coreclr/src/gc/env/gcenv.ee.h +++ b/src/coreclr/src/gc/env/gcenv.ee.h @@ -73,9 +73,9 @@ class GCToEEInterface static void HandleFatalError(unsigned int exitCode); static bool EagerFinalized(Object* obj); static MethodTable* GetFreeObjectMethodTable(); - static bool GetBooleanConfigValue(const char* key, bool* value); - static bool GetIntConfigValue(const char* key, int64_t* value); - static bool GetStringConfigValue(const char* key, const char** value); + static bool GetBooleanConfigValue(const char* privateKey, const char* publicKey, bool* value); + static bool GetIntConfigValue(const char* privateKey, const char* publicKey, int64_t* value); + static bool GetStringConfigValue(const char* privateKey, const char* publicKey, const char** value); static void FreeStringConfigValue(const char* key); static bool IsGCThread(); static bool WasCurrentThreadCreatedByGC(); diff --git a/src/coreclr/src/gc/env/gcenv.os.h b/src/coreclr/src/gc/env/gcenv.os.h index ae398e5503e3b8..6a6477f3c46504 100644 --- a/src/coreclr/src/gc/env/gcenv.os.h +++ b/src/coreclr/src/gc/env/gcenv.os.h @@ -66,8 +66,9 @@ struct VirtualReserveFlags // are run on process exit, potentially concurrently with other threads that may still be // operating on the static event. To avoid these sorts of unsafety, GCEvent chooses to // not have a destructor at all. The cost of this is leaking a small amount of memory, but -// this is not a problem since a majority of the uses of GCEvent are static. See CoreCLR#11111 -// for more details on the hazards of static destructors. +// this is not a problem since a majority of the uses of GCEvent are static. +// See https://github.com/dotnet/runtime/issues/7919 for more details on the hazards of +// static destructors. class GCEvent { private: class Impl; @@ -433,20 +434,19 @@ class GCToOSInterface // Remarks: // If a process runs with a restricted memory limit, it returns the limit. If there's no limit // specified, it returns amount of actual physical memory. - // - // PERF TODO: Requires more work to not treat the restricted case to be special. - // To be removed before 3.0 ships. static uint64_t GetPhysicalMemoryLimit(bool* is_restricted=NULL); // Get memory status // Parameters: + // restricted_limit - The amount of physical memory in bytes that the current process is being restricted to. If non-zero, it used to calculate + // memory_load and available_physical. If zero, memory_load and available_physical is calculate based on all available memory. // memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory // that is in use (0 indicates no memory use and 100 indicates full memory use). // available_physical - The amount of physical memory currently available, in bytes. // available_page_file - The maximum amount of memory the current process can commit, in bytes. // Remarks: // Any parameter can be null. - static void GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file); + static void GetMemoryStatus(uint64_t restricted_limit, uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file); // Get size of an OS memory page static size_t GetPageSize(); diff --git a/src/coreclr/src/gc/env/volatile.h b/src/coreclr/src/gc/env/volatile.h index c7964e9107d8fe..32b6fca3b6a7c6 100644 --- a/src/coreclr/src/gc/env/volatile.h +++ b/src/coreclr/src/gc/env/volatile.h @@ -67,8 +67,8 @@ #error The Volatile type is currently only defined for Visual C++ and GNU C++ #endif -#if defined(__GNUC__) && !defined(HOST_X86) && !defined(HOST_AMD64) && !defined(HOST_ARM) && !defined(HOST_ARM64) -#error The Volatile type is currently only defined for GCC when targeting x86, AMD64, ARM or ARM64 CPUs +#if defined(__GNUC__) && !defined(HOST_X86) && !defined(HOST_AMD64) && !defined(HOST_ARM) && !defined(HOST_ARM64) && !defined(HOST_WASM) +#error The Volatile type is currently only defined for GCC when targeting x86, AMD64, ARM, ARM64 or Wasm #endif #if defined(__GNUC__) diff --git a/src/coreclr/src/gc/gc.cpp b/src/coreclr/src/gc/gc.cpp index 3e3096e604eae5..3c26bd5b60e2e1 100644 --- a/src/coreclr/src/gc/gc.cpp +++ b/src/coreclr/src/gc/gc.cpp @@ -192,6 +192,25 @@ BOOL is_induced_blocking (gc_reason reason) (reason == reason_lowmemory_host_blocking)); } +gc_oh_num gen_to_oh(int gen) +{ + switch (gen) + { + case soh_gen0: + return gc_oh_num::soh; + case soh_gen1: + return gc_oh_num::soh; + case soh_gen2: + return gc_oh_num::soh; + case loh_generation: + return gc_oh_num::loh; + case poh_generation: + return gc_oh_num::poh; + default: + return gc_oh_num::none; + } +} + #ifndef DACCESS_COMPILE int64_t qpf; size_t start_time; @@ -1866,7 +1885,14 @@ const int max_snoop_level = 128; #define MH_TH_CARD_BUNDLE (180*1024*1024) #endif //CARD_BUNDLE -#define GC_EPHEMERAL_DECOMMIT_TIMEOUT 5000 +// min size to decommit to make the OS call worthwhile +#define MIN_DECOMMIT_SIZE (100*OS_PAGE_SIZE) + +// max size to decommit per millisecond +#define DECOMMIT_SIZE_PER_MILLISECOND (160*1024) + +// time in milliseconds between decommit steps +#define DECOMMIT_TIME_STEP_MILLISECONDS (100) inline size_t align_on_page (size_t add) @@ -2060,7 +2086,6 @@ void qsort1(uint8_t** low, uint8_t** high, unsigned int depth); void* virtual_alloc (size_t size); void* virtual_alloc (size_t size, bool use_large_pages_p); -void virtual_free (void* add, size_t size); /* per heap static initialization */ #if defined(BACKGROUND_GC) && !defined(MULTIPLE_HEAPS) @@ -2112,6 +2137,8 @@ int* gc_heap::g_mark_stack_busy; size_t* gc_heap::g_bpromoted; #endif //BACKGROUND_GC +BOOL gc_heap::gradual_decommit_in_progress_p = FALSE; +size_t gc_heap::max_decommit_step_size = 0; #else //MULTIPLE_HEAPS size_t gc_heap::g_promoted; @@ -2138,12 +2165,12 @@ gc_history_global gc_heap::gc_data_global; size_t gc_heap::gc_last_ephemeral_decommit_time = 0; -size_t gc_heap::gc_gen0_desired_high; - CLRCriticalSection gc_heap::check_commit_cs; size_t gc_heap::current_total_committed = 0; +size_t gc_heap::committed_by_oh[total_oh_count] = {0, 0, 0, 0}; + size_t gc_heap::current_total_committed_bookkeeping = 0; #ifdef SHORT_PLUGS @@ -2175,6 +2202,8 @@ uint32_t gc_heap::m_high_memory_load_th; uint32_t gc_heap::v_high_memory_load_th; +bool gc_heap::is_restricted_physical_mem; + uint64_t gc_heap::total_physical_mem = 0; uint64_t gc_heap::entry_available_physical_mem = 0; @@ -3564,9 +3593,6 @@ heap_segment* seg_mapping_table_segment_of (uint8_t* o) size_t gcard_of ( uint8_t*); -#define memref(i) *(uint8_t**)(i) - -//GC Flags #define GC_MARKED (size_t)0x1 #define slot(i, j) ((uint8_t**)(i))[(j)+1] @@ -3944,7 +3970,7 @@ struct initial_memory_details initial_memory_details memory_details; -BOOL reserve_initial_memory (size_t normal_size, size_t large_size, size_t pinned_size, int num_heaps, bool use_large_pages_p) +BOOL gc_heap::reserve_initial_memory (size_t normal_size, size_t large_size, size_t pinned_size, int num_heaps, bool use_large_pages_p) { BOOL reserve_success = FALSE; @@ -4083,7 +4109,7 @@ BOOL reserve_initial_memory (size_t normal_size, size_t large_size, size_t pinne return reserve_success; } -void destroy_initial_memory() +void gc_heap::destroy_initial_memory() { if (memory_details.initial_memory != NULL) { @@ -4103,7 +4129,7 @@ void destroy_initial_memory() virtual_free (memory_details.initial_pinned_heap[0].memory_base, memory_details.block_count*memory_details.block_size_pinned); - } + } else { assert (memory_details.allocation_pattern == initial_memory_details::EACH_BLOCK); @@ -4130,7 +4156,8 @@ heap_segment* make_initial_segment (int gen, int h_number) { void* mem = memory_details.get_initial_memory (gen, h_number); size_t size = memory_details.get_initial_size (gen); - heap_segment* res = gc_heap::make_heap_segment ((uint8_t*)mem, size , h_number); + gc_oh_num oh = gen_to_oh (gen); + heap_segment* res = gc_heap::make_heap_segment ((uint8_t*)mem, size, oh, h_number); return res; } @@ -4197,14 +4224,6 @@ void* virtual_alloc (size_t size, bool use_large_pages_p) return aligned_mem; } -void virtual_free (void* add, size_t size) -{ - GCToOSInterface::VirtualRelease (add, size); - gc_heap::reserved_memory -= size; - dprintf (2, ("Virtual Free size %Id: [%Ix, %Ix[", - size, (size_t)add, (size_t)((uint8_t*)add+size))); -} - static size_t get_valid_segment_size (BOOL large_seg=FALSE) { size_t seg_size, initial_seg_size; @@ -4378,7 +4397,7 @@ gc_heap::soh_get_segment_to_expand() } } - heap_segment* result = get_segment (size, FALSE); + heap_segment* result = get_segment (size, gc_oh_num::soh); if(result) { @@ -4419,8 +4438,10 @@ gc_heap::soh_get_segment_to_expand() //returns 0 in case of allocation failure heap_segment* -gc_heap::get_segment (size_t size, BOOL loh_p) +gc_heap::get_segment (size_t size, gc_oh_num oh) { + assert(oh != gc_oh_num::none); + BOOL uoh_p = (oh == gc_oh_num::loh) || (oh == gc_oh_num::poh); if (heap_hard_limit) return NULL; @@ -4489,11 +4510,11 @@ gc_heap::get_segment (size_t size, BOOL loh_p) void* mem = virtual_alloc (size); if (!mem) { - fgm_result.set_fgm (fgm_reserve_segment, size, loh_p); + fgm_result.set_fgm (fgm_reserve_segment, size, uoh_p); return 0; } - result = gc_heap::make_heap_segment ((uint8_t*)mem, size, heap_number); + result = gc_heap::make_heap_segment ((uint8_t*)mem, size, oh, heap_number); if (result) { @@ -4517,7 +4538,7 @@ gc_heap::get_segment (size_t size, BOOL loh_p) end = (uint8_t*)g_gc_highest_address; } - if (gc_heap::grow_brick_card_tables (start, end, size, result, __this, loh_p) != 0) + if (gc_heap::grow_brick_card_tables (start, end, size, result, __this, uoh_p) != 0) { virtual_free (mem, size); return 0; @@ -4525,7 +4546,7 @@ gc_heap::get_segment (size_t size, BOOL loh_p) } else { - fgm_result.set_fgm (fgm_commit_segment_beg, SEGMENT_INITIAL_COMMIT, loh_p); + fgm_result.set_fgm (fgm_commit_segment_beg, SEGMENT_INITIAL_COMMIT, uoh_p); virtual_free (mem, size); } @@ -4549,11 +4570,11 @@ gc_heap::get_segment (size_t size, BOOL loh_p) return result; } -void release_segment (heap_segment* sg) +void gc_heap::release_segment (heap_segment* sg) { ptrdiff_t delta = 0; FIRE_EVENT(GCFreeSegment_V1, heap_segment_mem(sg)); - virtual_free (sg, (uint8_t*)heap_segment_reserved (sg)-(uint8_t*)sg); + virtual_free (sg, (uint8_t*)heap_segment_reserved (sg)-(uint8_t*)sg, sg); } heap_segment* gc_heap::get_segment_for_uoh (int gen_number, size_t size @@ -4565,7 +4586,8 @@ heap_segment* gc_heap::get_segment_for_uoh (int gen_number, size_t size #ifndef MULTIPLE_HEAPS gc_heap* hp = 0; #endif //MULTIPLE_HEAPS - heap_segment* res = hp->get_segment (size, TRUE); + gc_oh_num oh = gen_to_oh (gen_number); + heap_segment* res = hp->get_segment (size, oh); if (res != 0) { #ifdef MULTIPLE_HEAPS @@ -5398,7 +5420,12 @@ void gc_heap::gc_thread_function () if (heap_number == 0) { - gc_heap::ee_suspend_event.Wait(INFINITE, FALSE); + uint32_t wait_result = gc_heap::ee_suspend_event.Wait(gradual_decommit_in_progress_p ? DECOMMIT_TIME_STEP_MILLISECONDS : INFINITE, FALSE); + if (wait_result == WAIT_TIMEOUT) + { + gradual_decommit_in_progress_p = decommit_step (); + continue; + } BEGIN_TIMING(suspend_ee_during_log); GCToEEInterface::SuspendEE(SUSPEND_FOR_GC); @@ -5480,6 +5507,12 @@ void gc_heap::gc_thread_function () hp->set_gc_done(); } } + + // check if we should do some decommitting + if (gradual_decommit_in_progress_p) + { + gradual_decommit_in_progress_p = decommit_step (); + } } else { @@ -5524,7 +5557,7 @@ bool gc_heap::virtual_alloc_commit_for_heap (void* addr, size_t size, int h_numb return GCToOSInterface::VirtualCommit(addr, size); } -bool gc_heap::virtual_commit (void* address, size_t size, int h_number, bool* hard_limit_exceeded_p) +bool gc_heap::virtual_commit (void* address, size_t size, gc_oh_num oh, int h_number, bool* hard_limit_exceeded_p) { #ifndef HOST_64BIT assert (heap_hard_limit == 0); @@ -5532,9 +5565,9 @@ bool gc_heap::virtual_commit (void* address, size_t size, int h_number, bool* ha if (heap_hard_limit) { - bool exceeded_p = false; - check_commit_cs.Enter(); + committed_by_oh[oh] += size; + bool exceeded_p = false; if ((current_total_committed + size) > heap_hard_limit) { @@ -5573,6 +5606,8 @@ bool gc_heap::virtual_commit (void* address, size_t size, int h_number, bool* ha if (!commit_succeeded_p && heap_hard_limit) { check_commit_cs.Enter(); + committed_by_oh[oh] -= size; + dprintf (1, ("commit failed, updating %Id to %Id", current_total_committed, (current_total_committed - size))); current_total_committed -= size; @@ -5581,11 +5616,10 @@ bool gc_heap::virtual_commit (void* address, size_t size, int h_number, bool* ha check_commit_cs.Leave(); } - return commit_succeeded_p; } -bool gc_heap::virtual_decommit (void* address, size_t size, int h_number) +bool gc_heap::virtual_decommit (void* address, size_t size, gc_oh_num oh, int h_number) { #ifndef HOST_64BIT assert (heap_hard_limit == 0); @@ -5596,6 +5630,7 @@ bool gc_heap::virtual_decommit (void* address, size_t size, int h_number) if (decommit_succeeded_p && heap_hard_limit) { check_commit_cs.Enter(); + committed_by_oh[oh] -= size; current_total_committed -= size; if (h_number < 0) current_total_committed_bookkeeping -= size; @@ -5605,6 +5640,18 @@ bool gc_heap::virtual_decommit (void* address, size_t size, int h_number) return decommit_succeeded_p; } +void gc_heap::virtual_free (void* add, size_t allocated_size, heap_segment* sg) +{ + assert(!heap_hard_limit); + bool release_succeeded_p = GCToOSInterface::VirtualRelease (add, allocated_size); + if (release_succeeded_p) + { + reserved_memory -= allocated_size; + dprintf (2, ("Virtual Free size %Id: [%Ix, %Ix[", + allocated_size, (size_t)add, (size_t)((uint8_t*)add + allocated_size))); + } +} + class mark { public: @@ -7208,7 +7255,7 @@ uint32_t* gc_heap::make_card_table (uint8_t* start, uint8_t* end) // mark array will be committed separately (per segment). size_t commit_size = alloc_size - ms; - if (!virtual_commit (mem, commit_size)) + if (!virtual_commit (mem, commit_size, gc_oh_num::none)) { dprintf (1, ("Card table commit failed")); GCToOSInterface::VirtualRelease (mem, alloc_size); @@ -7278,7 +7325,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start, size_t size, heap_segment* new_seg, gc_heap* hp, - BOOL loh_p) + BOOL uoh_p) { uint8_t* la = g_gc_lowest_address; uint8_t* ha = g_gc_highest_address; @@ -7403,7 +7450,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start, if (!mem) { - set_fgm_result (fgm_grow_table, alloc_size, loh_p); + set_fgm_result (fgm_grow_table, alloc_size, uoh_p); goto fail; } @@ -7414,10 +7461,10 @@ int gc_heap::grow_brick_card_tables (uint8_t* start, // mark array will be committed separately (per segment). size_t commit_size = alloc_size - ms; - if (!virtual_commit (mem, commit_size)) + if (!virtual_commit (mem, commit_size, gc_oh_num::none)) { dprintf (GC_TABLE_LOG, ("Table commit failed")); - set_fgm_result (fgm_commit_table, commit_size, loh_p); + set_fgm_result (fgm_commit_table, commit_size, uoh_p); goto fail; } } @@ -7484,14 +7531,14 @@ int gc_heap::grow_brick_card_tables (uint8_t* start, if (!commit_new_mark_array_global (new_mark_array)) { dprintf (GC_TABLE_LOG, ("failed to commit portions in the mark array for existing segments")); - set_fgm_result (fgm_commit_table, logging_ma_commit_size, loh_p); + set_fgm_result (fgm_commit_table, logging_ma_commit_size, uoh_p); goto fail; } if (!commit_mark_array_new_seg (hp, new_seg, translated_ct, saved_g_lowest_address)) { dprintf (GC_TABLE_LOG, ("failed to commit mark array for the new seg")); - set_fgm_result (fgm_commit_table, logging_ma_commit_size, loh_p); + set_fgm_result (fgm_commit_table, logging_ma_commit_size, uoh_p); goto fail; } } @@ -7608,7 +7655,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start, if (!commit_mark_array_new_seg (hp, new_seg)) { dprintf (GC_TABLE_LOG, ("failed to commit mark array for the new seg in range")); - set_fgm_result (fgm_commit_table, logging_ma_commit_size, loh_p); + set_fgm_result (fgm_commit_table, logging_ma_commit_size, uoh_p); return -1; } } @@ -9141,11 +9188,12 @@ int gc_heap::object_gennum_plan (uint8_t* o) #pragma optimize("", on) // Go back to command line default optimizations #endif //_MSC_VER && TARGET_X86 -heap_segment* gc_heap::make_heap_segment (uint8_t* new_pages, size_t size, int h_number) +heap_segment* gc_heap::make_heap_segment (uint8_t* new_pages, size_t size, gc_oh_num oh, int h_number) { + assert(oh != gc_oh_num::none); size_t initial_commit = SEGMENT_INITIAL_COMMIT; - if (!virtual_commit (new_pages, initial_commit, h_number)) + if (!virtual_commit (new_pages, initial_commit, oh, h_number)) { return 0; } @@ -9245,22 +9293,40 @@ void gc_heap::decommit_heap_segment_pages (heap_segment* seg, uint8_t* page_start = align_on_page (heap_segment_allocated(seg)); size_t size = heap_segment_committed (seg) - page_start; extra_space = align_on_page (extra_space); - if (size >= max ((extra_space + 2*OS_PAGE_SIZE), 100*OS_PAGE_SIZE)) + if (size >= max ((extra_space + 2*OS_PAGE_SIZE), MIN_DECOMMIT_SIZE)) { page_start += max(extra_space, 32*OS_PAGE_SIZE); - size -= max (extra_space, 32*OS_PAGE_SIZE); + decommit_heap_segment_pages_worker (seg, page_start); + } +} - virtual_decommit (page_start, size, heap_number); - dprintf (3, ("Decommitting heap segment [%Ix, %Ix[(%d)", - (size_t)page_start, - (size_t)(page_start + size), - size)); - heap_segment_committed (seg) = page_start; - if (heap_segment_used (seg) > heap_segment_committed (seg)) +size_t gc_heap::decommit_heap_segment_pages_worker (heap_segment* seg, + uint8_t* new_committed) +{ + assert (!use_large_pages_p); + uint8_t* page_start = align_on_page (new_committed); + size_t size = heap_segment_committed (seg) - page_start; + if (size > 0) + { + bool decommit_succeeded_p = virtual_decommit (page_start, size, heap_segment_oh (seg), heap_number); + if (decommit_succeeded_p) { - heap_segment_used (seg) = heap_segment_committed (seg); + dprintf (3, ("Decommitting heap segment [%Ix, %Ix[(%d)", + (size_t)page_start, + (size_t)(page_start + size), + size)); + heap_segment_committed (seg) = page_start; + if (heap_segment_used (seg) > heap_segment_committed (seg)) + { + heap_segment_used (seg) = heap_segment_committed (seg); + } + } + else + { + dprintf (3, ("Decommitting heap segment failed")); } } + return size; } //decommit all pages except one or 2 @@ -9275,13 +9341,16 @@ void gc_heap::decommit_heap_segment (heap_segment* seg) #endif //BACKGROUND_GC size_t size = heap_segment_committed (seg) - page_start; - virtual_decommit (page_start, size, heap_number); + bool decommit_succeeded_p = virtual_decommit (page_start, size, heap_segment_oh (seg), heap_number); - //re-init the segment object - heap_segment_committed (seg) = page_start; - if (heap_segment_used (seg) > heap_segment_committed (seg)) + if (decommit_succeeded_p) { - heap_segment_used (seg) = heap_segment_committed (seg); + //re-init the segment object + heap_segment_committed (seg) = page_start; + if (heap_segment_used (seg) > heap_segment_committed (seg)) + { + heap_segment_used (seg) = heap_segment_committed (seg); + } } } @@ -10029,6 +10098,14 @@ gc_heap::init_semi_shared() } #endif //MARK_LIST +#ifdef MULTIPLE_HEAPS + // gradual decommit: set size to some reasonable value per time interval + max_decommit_step_size = ((DECOMMIT_SIZE_PER_MILLISECOND * DECOMMIT_TIME_STEP_MILLISECONDS) / n_heaps); + + // but do at least MIN_DECOMMIT_SIZE per step to make the OS call worthwhile + max_decommit_step_size = max (max_decommit_step_size, MIN_DECOMMIT_SIZE); +#endif //MULTIPLE_HEAPS + #ifdef FEATURE_BASICFREEZE seg_table = sorted_table::make_sorted_table(); @@ -10899,7 +10976,7 @@ BOOL gc_heap::grow_heap_segment (heap_segment* seg, uint8_t* high_address, bool* "Growing heap_segment: %Ix high address: %Ix\n", (size_t)seg, (size_t)high_address); - bool ret = virtual_commit (heap_segment_committed (seg), c_size, heap_number, hard_limit_exceeded_p); + bool ret = virtual_commit (heap_segment_committed (seg), c_size, heap_segment_oh (seg), heap_number, hard_limit_exceeded_p); if (ret) { heap_segment_committed (seg) += c_size; @@ -15023,11 +15100,12 @@ size_t gc_heap::get_total_allocated_since_last_gc() // Gets what's allocated on both SOH, LOH, etc that hasn't been collected. size_t gc_heap::get_current_allocated() { - size_t current_alloc = 0; - for (int i = max_generation; i < total_generation_count; i++) + dynamic_data* dd = dynamic_data_of (0); + size_t current_alloc = dd_desired_allocation (dd) - dd_new_allocation (dd); + for (int i = uoh_start_generation; i < total_generation_count; i++) { dynamic_data* dd = dynamic_data_of (i); - current_alloc = dd_desired_allocation (dd) - dd_new_allocation (dd); + current_alloc += dd_desired_allocation (dd) - dd_new_allocation (dd); } return current_alloc; } @@ -16291,9 +16369,9 @@ void gc_heap::gc1() int limit = settings.condemned_generation; if (limit == max_generation) { - limit = total_generation_count; + limit = total_generation_count-1; } - for (int gen = 0; gen < limit; gen++) + for (int gen = 0; gen <= limit; gen++) { size_t total_desired = 0; @@ -16973,7 +17051,9 @@ BOOL gc_heap::expand_soh_with_minimal_gc() return TRUE; } else + { return FALSE; + } } // Only to be done on the thread that calls restart in a join for server GC @@ -17655,22 +17735,21 @@ gc_heap* gc_heap::heap_of_gc (uint8_t* o) } // will find all heap objects (large and small) -uint8_t* gc_heap::find_object (uint8_t* interior, uint8_t* low) +// +// Callers of this method need to guarantee the interior pointer is within the heap range. +// +// If you need it to be stricter, eg if you only want to find an object in ephemeral range, +// you should make sure interior is within that range before calling this method. +uint8_t* gc_heap::find_object (uint8_t* interior) { + assert (interior != 0); + if (!gen0_bricks_cleared) { #ifdef MULTIPLE_HEAPS assert (!"Should have already been done in server GC"); #endif //MULTIPLE_HEAPS - gen0_bricks_cleared = TRUE; - //initialize brick table for gen 0 - for (size_t b = brick_of (generation_allocation_start (generation_of (0))); - b < brick_of (align_on_brick - (heap_segment_allocated (ephemeral_heap_segment))); - b++) - { - set_brick (b, -1); - } + clear_gen0_bricks(); } //indicate that in the future this needs to be done during allocation gen0_must_clear_bricks = FFIND_DECAY; @@ -17701,7 +17780,7 @@ uint8_t* gc_heap::find_object (uint8_t* interior, uint8_t* low) uint8_t* next_o = o + Align (size (o), align_const); assert (next_o > o); if ((o <= interior) && (interior < next_o)) - return o; + return o; o = next_o; } return 0; @@ -17711,7 +17790,7 @@ uint8_t* gc_heap::find_object (uint8_t* interior, uint8_t* low) return 0; } } - else if (interior >= low) + else { heap_segment* seg = find_segment (interior, TRUE); if (seg) @@ -17728,8 +17807,6 @@ uint8_t* gc_heap::find_object (uint8_t* interior, uint8_t* low) else return 0; } - else - return 0; } #ifdef MULTIPLE_HEAPS @@ -17849,15 +17926,6 @@ BOOL gc_heap::background_mark (uint8_t* o, uint8_t* low, uint8_t* high) #endif //BACKGROUND_GC -inline -uint8_t* gc_heap::next_end (heap_segment* seg, uint8_t* f) -{ - if (seg == ephemeral_heap_segment) - return f; - else - return heap_segment_allocated (seg); -} - #define new_start() {if (ppstop <= start) {break;} else {parm = start}} #define ignore_start 0 #define use_start 1 @@ -18725,7 +18793,7 @@ gc_heap::ha_mark_object_simple (uint8_t** po THREAD_NUMBER_DCL) !((ref >= current_obj) && (ref < (current_obj + current_obj_size)))) { gc_heap* hp = gc_heap::heap_of (ref); - current_obj = hp->find_object (ref, hp->lowest_address); + current_obj = hp->find_object (ref); current_obj_size = size (current_obj); internal_root_array[internal_root_array_index] = current_obj; @@ -18784,7 +18852,6 @@ void gc_heap::mark_object (uint8_t* o THREAD_NUMBER_DCL) #ifdef MULTIPLE_HEAPS else if (o) { - //find the heap gc_heap* hp = heap_of (o); assert (hp); if ((o >= hp->gc_low) && (o < hp->gc_high)) @@ -19092,7 +19159,7 @@ void gc_heap::background_promote (Object** ppObject, ScanContext* sc, uint32_t f if (flags & GC_CALL_INTERIOR) { - o = hp->find_object (o, hp->background_saved_lowest_address); + o = hp->find_object (o); if (o == 0) return; } @@ -19193,27 +19260,6 @@ gc_heap::scan_background_roots (promote_func* fn, int hn, ScanContext *pSC) } } -inline -void gc_heap::background_mark_through_object (uint8_t* oo THREAD_NUMBER_DCL) -{ - if (contain_pointers (oo)) - { - size_t total_refs = 0; - size_t s = size (oo); - go_through_object_nostart (method_table(oo), oo, s, po, - { - uint8_t* o = *po; - total_refs++; - background_mark_object (o THREAD_NUMBER_ARG); - } - ); - - dprintf (3,("Background marking through %Ix went through %Id refs", - (size_t)oo, - total_refs)); - } -} - uint8_t* gc_heap::background_seg_end (heap_segment* seg, BOOL concurrent_p) { if (concurrent_p && (seg == saved_overflow_ephemeral_seg)) @@ -19664,7 +19710,7 @@ void gc_heap::get_memory_info (uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) { - GCToOSInterface::GetMemoryStatus(memory_load, available_physical, available_page_file); + GCToOSInterface::GetMemoryStatus(is_restricted_physical_mem ? total_physical_mem : 0, memory_load, available_physical, available_page_file); } void fire_mark_event (int heap_num, int root_type, size_t bytes_marked) @@ -20476,25 +20522,21 @@ void gc_heap::mark_phase (int condemned_gen_number, BOOL mark_only_p) } inline -void gc_heap::pin_object (uint8_t* o, uint8_t** ppObject, uint8_t* low, uint8_t* high) +void gc_heap::pin_object (uint8_t* o, uint8_t** ppObject) { - dprintf (3, ("Pinning %Ix", (size_t)o)); - if ((o >= low) && (o < high)) - { - dprintf(3,("^%Ix^", (size_t)o)); - set_pinned (o); + dprintf (3, ("Pinning %Ix->%Ix", (size_t)ppObject, (size_t)o)); + set_pinned (o); #ifdef FEATURE_EVENT_TRACE - if(EVENT_ENABLED(PinObjectAtGCTime)) - { - fire_etw_pin_object_event(o, ppObject); - } + if(EVENT_ENABLED(PinObjectAtGCTime)) + { + fire_etw_pin_object_event(o, ppObject); + } #endif // FEATURE_EVENT_TRACE #if defined(ENABLE_PERF_COUNTERS) || defined(FEATURE_EVENT_TRACE) - num_pinned_objects++; + num_pinned_objects++; #endif //ENABLE_PERF_COUNTERS || FEATURE_EVENT_TRACE - } } #if defined(ENABLE_PERF_COUNTERS) || defined(FEATURE_EVENT_TRACE) @@ -22224,7 +22266,10 @@ void gc_heap::plan_phase (int condemned_gen_number) { if (x >= end) { - assert (x == end); + if (!use_mark_list) + { + assert (x == end); + } assert (heap_segment_allocated (seg1) == end); heap_segment_allocated (seg1) = plug_end; @@ -24531,8 +24576,6 @@ void gc_heap::relocate_survivors (int condemned_gen_number, size_t end_brick = brick_of (end_address - 1); relocate_args args; - args.low = gc_low; - args.high = gc_high; args.is_shortened = FALSE; args.pinned_plug_entry = 0; args.last_plug = 0; @@ -25826,7 +25869,7 @@ BOOL gc_heap::commit_mark_array_by_range (uint8_t* begin, uint8_t* end, uint32_t size)); #endif //SIMPLE_DPRINTF - if (virtual_commit (commit_start, size)) + if (virtual_commit (commit_start, size, gc_oh_num::none)) { // We can only verify the mark array is cleared from begin to end, the first and the last // page aren't necessarily all cleared 'cause they could be used by other segments or @@ -26050,7 +26093,7 @@ void gc_heap::decommit_mark_array_by_seg (heap_segment* seg) if (decommit_start < decommit_end) { - if (!virtual_decommit (decommit_start, size)) + if (!virtual_decommit (decommit_start, size, gc_oh_num::none)) { dprintf (GC_TABLE_LOG, ("decommit on %Ix for %Id bytes failed", decommit_start, size)); @@ -27100,7 +27143,7 @@ void gc_heap::background_promote_callback (Object** ppObject, ScanContext* sc, if (flags & GC_CALL_INTERIOR) { - o = hp->find_object (o, hp->background_saved_lowest_address); + o = hp->find_object (o); if (o == 0) return; } @@ -31766,56 +31809,133 @@ void gc_heap::trim_youngest_desired_low_memory() void gc_heap::decommit_ephemeral_segment_pages() { - if (settings.concurrent) + if (settings.concurrent || use_large_pages_p) { return; } - size_t slack_space = heap_segment_committed (ephemeral_heap_segment) - heap_segment_allocated (ephemeral_heap_segment); - - dynamic_data* dd = dynamic_data_of (0); - -#ifndef MULTIPLE_HEAPS - size_t extra_space = (g_low_memory_status ? 0 : (512 * 1024)); - size_t decommit_timeout = (g_low_memory_status ? 0 : GC_EPHEMERAL_DECOMMIT_TIMEOUT); - size_t ephemeral_elapsed = dd_time_clock(dd) - gc_last_ephemeral_decommit_time; + dynamic_data* dd0 = dynamic_data_of (0); - if (dd_desired_allocation (dd) > gc_gen0_desired_high) - { - gc_gen0_desired_high = dd_desired_allocation (dd) + extra_space; - } + // this is how much we are going to allocate in gen 0 + ptrdiff_t desired_allocation = dd_desired_allocation (dd0) + loh_size_threshold; - if (ephemeral_elapsed >= decommit_timeout) + // estimate how we are going to need in gen 1 - estimate half the free list space gets used + dynamic_data* dd1 = dynamic_data_of (1); + ptrdiff_t desired_allocation_1 = dd_new_allocation (dd1) - (generation_free_list_space (generation_of (1)) / 2); + if (desired_allocation_1 > 0) { - slack_space = min (slack_space, gc_gen0_desired_high); - - gc_last_ephemeral_decommit_time = dd_time_clock(dd); - gc_gen0_desired_high = 0; + desired_allocation += desired_allocation_1; } -#endif //!MULTIPLE_HEAPS - if (settings.condemned_generation >= (max_generation-1)) - { - size_t new_slack_space = + size_t slack_space = #ifdef HOST_64BIT - max(min(min(soh_segment_size/32, dd_max_size(dd)), (generation_size (max_generation) / 10)), dd_desired_allocation(dd)); + max(min(min(soh_segment_size/32, dd_max_size (dd0)), (generation_size (max_generation) / 10)), (size_t)desired_allocation); #else #ifdef FEATURE_CORECLR - dd_desired_allocation (dd); + desired_allocation; #else - dd_max_size (dd); + dd_max_size (dd0); #endif //FEATURE_CORECLR #endif // HOST_64BIT - slack_space = min (slack_space, new_slack_space); + uint8_t *decommit_target = heap_segment_allocated (ephemeral_heap_segment) + slack_space; + if (decommit_target < heap_segment_decommit_target (ephemeral_heap_segment)) + { + // we used to have a higher target - do exponential smoothing by computing + // essentially decommit_target = 1/3*decommit_target + 2/3*previous_decommit_target + // computation below is slightly different to avoid overflow + ptrdiff_t target_decrease = heap_segment_decommit_target (ephemeral_heap_segment) - decommit_target; + decommit_target += target_decrease * 2 / 3; + } + + heap_segment_decommit_target(ephemeral_heap_segment) = decommit_target; + +#ifdef MULTIPLE_HEAPS + if (decommit_target < heap_segment_committed (ephemeral_heap_segment)) + { + gradual_decommit_in_progress_p = TRUE; } +#ifdef _DEBUG + // these are only for checking against logic errors + ephemeral_heap_segment->saved_committed = heap_segment_committed (ephemeral_heap_segment); + ephemeral_heap_segment->saved_desired_allocation = dd_desired_allocation (dd0); +#endif // _DEBUG +#endif // MULTIPLE_HEAPS + +#ifndef MULTIPLE_HEAPS + // we want to limit the amount of decommit we do per time to indirectly + // limit the amount of time spent in recommit and page faults + size_t ephemeral_elapsed = dd_time_clock (dd0) - gc_last_ephemeral_decommit_time; + gc_last_ephemeral_decommit_time = dd_time_clock (dd0); + + // this is the amount we were planning to decommit + ptrdiff_t decommit_size = heap_segment_committed (ephemeral_heap_segment) - decommit_target; + // we do a max of DECOMMIT_SIZE_PER_MILLISECOND per millisecond of elapsed time since the last GC + // we limit the elapsed time to 10 seconds to avoid spending too much time decommitting + ptrdiff_t max_decommit_size = min (ephemeral_elapsed, (10*1000)) * DECOMMIT_SIZE_PER_MILLISECOND; + decommit_size = min (decommit_size, max_decommit_size); + + slack_space = heap_segment_committed (ephemeral_heap_segment) - heap_segment_allocated (ephemeral_heap_segment) - decommit_size; decommit_heap_segment_pages (ephemeral_heap_segment, slack_space); +#endif // !MULTIPLE_HEAPS gc_history_per_heap* current_gc_data_per_heap = get_gc_data_per_heap(); current_gc_data_per_heap->extra_gen0_committed = heap_segment_committed (ephemeral_heap_segment) - heap_segment_allocated (ephemeral_heap_segment); } +#ifdef MULTIPLE_HEAPS +// return true if we actually decommitted anything +bool gc_heap::decommit_step () +{ + // should never get here for large pages because decommit_ephemeral_segment_pages + // will not do anything if use_large_pages_p is true + assert (!use_large_pages_p); + + size_t decommit_size = 0; + for (int i = 0; i < n_heaps; i++) + { + gc_heap* hp = gc_heap::g_heaps[i]; + decommit_size += hp->decommit_ephemeral_segment_pages_step (); + } + return (decommit_size != 0); +} + +// return the decommitted size +size_t gc_heap::decommit_ephemeral_segment_pages_step () +{ + // we rely on desired allocation not being changed outside of GC + assert (ephemeral_heap_segment->saved_desired_allocation == dd_desired_allocation (dynamic_data_of (0))); + + uint8_t* decommit_target = heap_segment_decommit_target (ephemeral_heap_segment); + size_t EXTRA_SPACE = 2 * OS_PAGE_SIZE; + decommit_target += EXTRA_SPACE; + uint8_t* committed = heap_segment_committed (ephemeral_heap_segment); + if (decommit_target < committed) + { + // we rely on other threads not messing with committed if we are about to trim it down + assert (ephemeral_heap_segment->saved_committed == heap_segment_committed (ephemeral_heap_segment)); + + // how much would we need to decommit to get to decommit_target in one step? + size_t full_decommit_size = (committed - decommit_target); + + // don't do more than max_decommit_step_size per step + size_t decommit_size = min (max_decommit_step_size, full_decommit_size); + + // figure out where the new committed should be + uint8_t* new_committed = (committed - decommit_size); + size_t size = decommit_heap_segment_pages_worker (ephemeral_heap_segment, new_committed); + +#ifdef _DEBUG + ephemeral_heap_segment->saved_committed = committed - size; +#endif // _DEBUG + + return size; + } + return 0; +} +#endif //MULTIPLE_HEAPS + //This is meant to be called by decide_on_compacting. size_t gc_heap::generation_fragmentation (generation* gen, @@ -33391,11 +33511,6 @@ void gc_heap::sweep_uoh_objects (int gen_num) void gc_heap::relocate_in_uoh_objects (int gen_num) { - relocate_args args; - args.low = gc_low; - args.high = gc_high; - args.last_plug = 0; - generation* gen = generation_of (gen_num); heap_segment* seg = heap_segment_rw (generation_start_segment (gen)); @@ -34969,11 +35084,14 @@ HRESULT GCHeap::Initialize() g_num_processors = GCToOSInterface::GetTotalProcessorCount(); assert(g_num_processors != 0); - bool is_restricted; gc_heap::total_physical_mem = (size_t)GCConfig::GetGCTotalPhysicalMemory(); - if (!(gc_heap::total_physical_mem)) + if (gc_heap::total_physical_mem != 0) + { + gc_heap::is_restricted_physical_mem = true; + } + else { - gc_heap::total_physical_mem = GCToOSInterface::GetPhysicalMemoryLimit (&is_restricted); + gc_heap::total_physical_mem = GCToOSInterface::GetPhysicalMemoryLimit (&gc_heap::is_restricted_physical_mem); } #ifdef HOST_64BIT @@ -34992,7 +35110,7 @@ HRESULT GCHeap::Initialize() // running in a container, use this limit for the GC heap. if (!(gc_heap::heap_hard_limit)) { - if (is_restricted) + if (gc_heap::is_restricted_physical_mem) { uint64_t physical_mem_for_gc = gc_heap::total_physical_mem * (uint64_t)75 / (uint64_t)100; gc_heap::heap_hard_limit = (size_t)max ((20 * 1024 * 1024), physical_mem_for_gc); @@ -35392,9 +35510,6 @@ Object * GCHeap::NextObj (Object * object) // returns TRUE if the pointer is in one of the GC heaps. bool GCHeap::IsHeapPointer (void* vpObject, bool small_heap_only) { - // removed STATIC_CONTRACT_CAN_TAKE_LOCK here because find_segment - // no longer calls GCEvent::Wait which eventually takes a lock. - uint8_t* object = (uint8_t*) vpObject; #ifndef FEATURE_BASICFREEZE if (!((object < g_gc_highest_address) && (object >= g_gc_lowest_address))) @@ -35405,7 +35520,6 @@ bool GCHeap::IsHeapPointer (void* vpObject, bool small_heap_only) return !!hs; } -// promote an object void GCHeap::Promote(Object** ppObject, ScanContext* sc, uint32_t flags) { THREAD_NUMBER_FROM_CONTEXT; @@ -35428,19 +35542,19 @@ void GCHeap::Promote(Object** ppObject, ScanContext* sc, uint32_t flags) gc_heap* hp = gc_heap::heap_of (o); + if ((o < hp->gc_low) || (o >= hp->gc_high)) + { + return; + } + dprintf (3, ("Promote %Ix", (size_t)o)); if (flags & GC_CALL_INTERIOR) { - if ((o < hp->gc_low) || (o >= hp->gc_high)) - { - return; - } - if ( (o = hp->find_object (o, hp->gc_low)) == 0) + if ((o = hp->find_object (o)) == 0) { return; } - } #ifdef FEATURE_CONSERVATIVE_GC @@ -35460,17 +35574,14 @@ void GCHeap::Promote(Object** ppObject, ScanContext* sc, uint32_t flags) #endif //_DEBUG if (flags & GC_CALL_PINNED) - hp->pin_object (o, (uint8_t**) ppObject, hp->gc_low, hp->gc_high); + hp->pin_object (o, (uint8_t**) ppObject); #ifdef STRESS_PINNING if ((++n_promote % 20) == 1) - hp->pin_object (o, (uint8_t**) ppObject, hp->gc_low, hp->gc_high); + hp->pin_object (o, (uint8_t**) ppObject); #endif //STRESS_PINNING - if ((o >= hp->gc_low) && (o < hp->gc_high)) - { - hpt->mark_object_simple (&o THREAD_NUMBER_ARG); - } + hpt->mark_object_simple (&o THREAD_NUMBER_ARG); STRESS_LOG_ROOT_PROMOTE(ppObject, o, o ? header(o)->GetMethodTable() : NULL); } @@ -35517,7 +35628,7 @@ void GCHeap::Relocate (Object** ppObject, ScanContext* sc, if (gc_heap::loh_object_p (object)) { - pheader = hp->find_object (object, 0); + pheader = hp->find_object (object); if (pheader == 0) { return; @@ -35910,7 +36021,7 @@ GCHeap::GetContainingObject (void *pInteriorPtr, bool fCollectedGenOnly) if (o >= lowest && o < highest) { - o = hp->find_object (o, lowest); + o = hp->find_object (o); } else { @@ -38151,13 +38262,12 @@ void initGCShadow() #define INVALIDGCVALUE (void*)((size_t)0xcccccccd) - // test to see if 'ptr' was only updated via the write barrier. +// test to see if 'ptr' was only updated via the write barrier. inline void testGCShadow(Object** ptr) { Object** shadow = (Object**) &g_GCShadow[((uint8_t*) ptr - g_gc_lowest_address)]; if (*ptr != 0 && (uint8_t*) shadow < g_GCShadowEnd && *ptr != *shadow) { - // If you get this assertion, someone updated a GC pointer in the heap without // using the write barrier. To find out who, check the value of // dd_collection_count (dynamic_data_of (0)). Also @@ -38180,7 +38290,6 @@ inline void testGCShadow(Object** ptr) // TODO: fixed to detect the race. We've only seen this race from VolatileWritePtr, // TODO: so elect not to fix jithelp.asm at this time. It should be done if we start hitting // TODO: erroneous asserts in here. - if(*shadow!=INVALIDGCVALUE) { #ifdef FEATURE_BASICFREEZE diff --git a/src/coreclr/src/gc/gcconfig.cpp b/src/coreclr/src/gc/gcconfig.cpp index b3a43f105bb8f2..02004e3d475089 100644 --- a/src/coreclr/src/gc/gcconfig.cpp +++ b/src/coreclr/src/gc/gcconfig.cpp @@ -6,23 +6,23 @@ #include "gcenv.h" #include "gc.h" -#define BOOL_CONFIG(name, key, default, unused_doc) \ - bool GCConfig::Get##name() { return s_##name; } \ +#define BOOL_CONFIG(name, unused_private_key, unused_public_key, default, unused_doc) \ + bool GCConfig::Get##name() { return s_##name; } \ bool GCConfig::s_##name = default; -#define INT_CONFIG(name, key, default, unused_doc) \ - int64_t GCConfig::Get##name() { return s_##name; } \ +#define INT_CONFIG(name, unused_private_key, unused_public_key, default, unused_doc) \ + int64_t GCConfig::Get##name() { return s_##name; } \ int64_t GCConfig::s_##name = default; // String configs are not cached because 1) they are rare and // not on hot paths and 2) they involve transfers of ownership // of EE-allocated strings, which is potentially complicated. -#define STRING_CONFIG(name, key, unused_doc) \ - GCConfigStringHolder GCConfig::Get##name() \ - { \ - const char* resultStr = nullptr; \ - GCToEEInterface::GetStringConfigValue(key, &resultStr); \ - return GCConfigStringHolder(resultStr); \ +#define STRING_CONFIG(name, private_key, public_key, unused_doc) \ + GCConfigStringHolder GCConfig::Get##name() \ + { \ + const char* resultStr = nullptr; \ + GCToEEInterface::GetStringConfigValue(private_key, public_key, &resultStr); \ + return GCConfigStringHolder(resultStr); \ } GC_CONFIGURATION_KEYS @@ -33,18 +33,19 @@ GC_CONFIGURATION_KEYS void GCConfig::Initialize() { -#define BOOL_CONFIG(name, key, default, unused_doc) \ - GCToEEInterface::GetBooleanConfigValue(key, &s_##name); +#define BOOL_CONFIG(name, private_key, public_key, default, unused_doc) \ + GCToEEInterface::GetBooleanConfigValue(private_key, public_key, &s_##name); -#define INT_CONFIG(name, key, default, unused_doc) \ - GCToEEInterface::GetIntConfigValue(key, &s_##name); +#define INT_CONFIG(name, private_key, public_key, default, unused_doc) \ + GCToEEInterface::GetIntConfigValue(private_key, public_key, &s_##name); -#define STRING_CONFIG(unused_name, unused_key, unused_doc) +#define STRING_CONFIG(unused_name, unused_private_key, unused_public_key, unused_doc) GC_CONFIGURATION_KEYS #undef BOOL_CONFIG #undef INT_CONFIG +#undef STRING_CONFIG } // Parse an integer index or range of two indices separated by '-'. diff --git a/src/coreclr/src/gc/gcconfig.h b/src/coreclr/src/gc/gcconfig.h index 75893bb50bc86e..f51191c56a1d6c 100644 --- a/src/coreclr/src/gc/gcconfig.h +++ b/src/coreclr/src/gc/gcconfig.h @@ -64,103 +64,81 @@ class GCConfigStringHolder // Each one of these keys produces a method on GCConfig with the name "Get{name}", where {name} // is the first parameter of the *_CONFIG macros below. #define GC_CONFIGURATION_KEYS \ - BOOL_CONFIG(ServerGC, "gcServer", false, "Whether we should be using Server GC") \ - BOOL_CONFIG(ConcurrentGC, "gcConcurrent", true, "Whether we should be using Concurrent GC") \ - BOOL_CONFIG(ConservativeGC, "gcConservative", false, "Enables/Disables conservative GC") \ - BOOL_CONFIG(ForceCompact, "gcForceCompact", false, \ - "When set to true, always do compacting GC") \ - BOOL_CONFIG(RetainVM, "GCRetainVM", false, \ - "When set we put the segments that should be deleted on a standby list (instead of " \ - "releasing them back to the OS) which will be considered to satisfy new segment requests"\ - " (note that the same thing can be specified via API which is the supported way)") \ - BOOL_CONFIG(BreakOnOOM, "GCBreakOnOOM", false, \ - "Does a DebugBreak at the soonest time we detect an OOM") \ - BOOL_CONFIG(NoAffinitize, "GCNoAffinitize", false, \ - "If set, do not affinitize server GC threads") \ - BOOL_CONFIG(LogEnabled, "GCLogEnabled", false, \ - "Specifies if you want to turn on logging in GC") \ - BOOL_CONFIG(ConfigLogEnabled, "GCConfigLogEnabled", false, \ - "Specifies the name of the GC config log file") \ - BOOL_CONFIG(GCNumaAware, "GCNumaAware", true, "Enables numa allocations in the GC") \ - BOOL_CONFIG(GCCpuGroup, "GCCpuGroup", false, "Enables CPU groups in the GC") \ - BOOL_CONFIG(GCLargePages, "GCLargePages", false, "Enables using Large Pages in the GC") \ - INT_CONFIG(HeapVerifyLevel, "HeapVerify", HEAPVERIFY_NONE, \ - "When set verifies the integrity of the managed heap on entry and exit of each GC") \ - INT_CONFIG(LOHCompactionMode, "GCLOHCompact", 0, "Specifies the LOH compaction mode") \ - INT_CONFIG(LOHThreshold, "GCLOHThreshold", LARGE_OBJECT_SIZE, \ - "Specifies the size that will make objects go on LOH") \ - INT_CONFIG(BGCSpinCount, "BGCSpinCount", 140, "Specifies the bgc spin count") \ - INT_CONFIG(BGCSpin, "BGCSpin", 2, "Specifies the bgc spin time") \ - INT_CONFIG(HeapCount, "GCHeapCount", 0, "Specifies the number of server GC heaps") \ - INT_CONFIG(Gen0Size, "GCgen0size", 0, "Specifies the smallest gen0 size") \ - INT_CONFIG(SegmentSize, "GCSegmentSize", 0, "Specifies the managed heap segment size") \ - INT_CONFIG(LatencyMode, "GCLatencyMode", -1, \ - "Specifies the GC latency mode - batch, interactive or low latency (note that the same " \ - "thing can be specified via API which is the supported way") \ - INT_CONFIG(LatencyLevel, "GCLatencyLevel", 1, \ - "Specifies the GC latency level that you want to optimize for. Must be a number from 0" \ - "3. See documentation for more details on each level.") \ - INT_CONFIG(LogFileSize, "GCLogFileSize", 0, "Specifies the GC log file size") \ - INT_CONFIG(CompactRatio, "GCCompactRatio", 0, \ - "Specifies the ratio compacting GCs vs sweeping") \ - INT_CONFIG(GCHeapAffinitizeMask, "GCHeapAffinitizeMask", 0, \ - "Specifies processor mask for Server GC threads") \ - STRING_CONFIG(GCHeapAffinitizeRanges, "GCHeapAffinitizeRanges", \ - "Specifies list of processors for Server GC threads. The format is a comma separated " \ - "list of processor numbers or ranges of processor numbers. On Windows, each entry is " \ - "prefixed by the CPU group number. Example: Unix - 1,3,5,7-9,12, Windows - 0:1,1:7-9") \ - INT_CONFIG(GCHighMemPercent, "GCHighMemPercent", 0, \ - "The percent for GC to consider as high memory") \ - INT_CONFIG(GCProvModeStress, "GCProvModeStress", 0, \ - "Stress the provisional modes") \ - INT_CONFIG(GCGen0MaxBudget, "GCGen0MaxBudget", 0, \ - "Specifies the largest gen0 allocation budget") \ - INT_CONFIG(GCHeapHardLimit, "GCHeapHardLimit", 0, \ - "Specifies a hard limit for the GC heap") \ - INT_CONFIG(GCHeapHardLimitPercent, "GCHeapHardLimitPercent", 0, \ - "Specifies the GC heap usage as a percentage of the total memory") \ - INT_CONFIG(GCTotalPhysicalMemory, "GCTotalPhysicalMemory", 0, \ - "Specifies what the GC should consider to be total physical memory") \ - STRING_CONFIG(LogFile, "GCLogFile", "Specifies the name of the GC log file") \ - STRING_CONFIG(ConfigLogFile, "GCConfigLogFile", \ - "Specifies the name of the GC config log file") \ - INT_CONFIG(BGCFLTuningEnabled, "BGCFLTuningEnabled", 0, "Enables FL tuning") \ - INT_CONFIG(BGCMemGoal, "BGCMemGoal", 75, "Specifies the physical memory load goal") \ - INT_CONFIG(BGCMemGoalSlack, "BGCMemGoalSlack", 10, \ - "Specifies comfort zone of going above goal") \ - INT_CONFIG(BGCFLSweepGoal, "BGCFLSweepGoal", 0, \ - "Specifies the gen2 sweep FL ratio goal") \ - INT_CONFIG(BGCFLSweepGoalLOH, "BGCFLSweepGoalLOH", 0, \ - "Specifies the LOH sweep FL ratio goal") \ - INT_CONFIG(BGCFLkp, "BGCFLkp", 6000, "Specifies kp for above goal tuning") \ - INT_CONFIG(BGCFLki, "BGCFLki", 1000, "Specifies ki for above goal tuning") \ - INT_CONFIG(BGCFLkd, "BGCFLkd", 11, "Specifies kd for above goal tuning") \ - INT_CONFIG(BGCFLff, "BGCFLff", 100, "Specifies ff ratio") \ - INT_CONFIG(BGCFLSmoothFactor, "BGCFLSmoothFactor", 150, "Smoothing over these") \ - INT_CONFIG(BGCFLGradualD, "BGCFLGradualD", 0, \ - "Enable gradual D instead of cutting of at the value") \ - INT_CONFIG(BGCMLkp, "BGCMLkp", 1000, "Specifies kp for ML tuning") \ - INT_CONFIG(BGCMLki, "BGCMLki", 16, "Specifies ki for ML tuning") \ - INT_CONFIG(BGCFLEnableKi, "BGCFLEnableKi", 1, "Enables ki for above goal tuning") \ - INT_CONFIG(BGCFLEnableKd, "BGCFLEnableKd", 0, "Enables kd for above goal tuning") \ - INT_CONFIG(BGCFLEnableSmooth, "BGCFLEnableSmooth", 0, "Enables smoothing") \ - INT_CONFIG(BGCFLEnableTBH, "BGCFLEnableTBH", 0, "Enables TBH") \ - INT_CONFIG(BGCFLEnableFF, "BGCFLEnableFF", 0, "Enables FF") \ - INT_CONFIG(BGCG2RatioStep, "BGCG2RatioStep", 5, "Ratio correction factor for ML loop") + BOOL_CONFIG (ServerGC, "gcServer", NULL, false, "Whether we should be using Server GC") \ + BOOL_CONFIG (ConcurrentGC, "gcConcurrent", NULL, true, "Whether we should be using Concurrent GC") \ + BOOL_CONFIG (ConservativeGC, "gcConservative", NULL, false, "Enables/Disables conservative GC") \ + BOOL_CONFIG (ForceCompact, "gcForceCompact", NULL, false, "When set to true, always do compacting GC") \ + BOOL_CONFIG (RetainVM, "GCRetainVM", NULL, false, "When set we put the segments that should be deleted on a standby list (instead of " \ + "releasing them back to the OS) which will be considered to satisfy new segment requests" \ + " (note that the same thing can be specified via API which is the supported way)") \ + BOOL_CONFIG (BreakOnOOM, "GCBreakOnOOM", NULL, false, "Does a DebugBreak at the soonest time we detect an OOM") \ + BOOL_CONFIG (NoAffinitize, "GCNoAffinitize", "System.GC.NoAffinitize", false, "If set, do not affinitize server GC threads") \ + BOOL_CONFIG (LogEnabled, "GCLogEnabled", NULL, false, "Specifies if you want to turn on logging in GC") \ + BOOL_CONFIG (ConfigLogEnabled, "GCConfigLogEnabled", NULL, false, "Specifies the name of the GC config log file") \ + BOOL_CONFIG (GCNumaAware, "GCNumaAware", NULL, true, "Enables numa allocations in the GC") \ + BOOL_CONFIG (GCCpuGroup, "GCCpuGroup", NULL, false, "Enables CPU groups in the GC") \ + BOOL_CONFIG (GCLargePages, "GCLargePages", "System.GC.LargePages", false, "Enables using Large Pages in the GC") \ + INT_CONFIG (HeapVerifyLevel, "HeapVerify", NULL, HEAPVERIFY_NONE, "When set verifies the integrity of the managed heap on entry and exit of each GC") \ + INT_CONFIG (LOHCompactionMode, "GCLOHCompact", NULL, 0, "Specifies the LOH compaction mode") \ + INT_CONFIG (LOHThreshold, "GCLOHThreshold", NULL, LARGE_OBJECT_SIZE, "Specifies the size that will make objects go on LOH") \ + INT_CONFIG (BGCSpinCount, "BGCSpinCount", NULL, 140, "Specifies the bgc spin count") \ + INT_CONFIG (BGCSpin, "BGCSpin", NULL, 2, "Specifies the bgc spin time") \ + INT_CONFIG (HeapCount, "GCHeapCount", "System.GC.HeapCount", 0, "Specifies the number of server GC heaps") \ + INT_CONFIG (Gen0Size, "GCgen0size", NULL, 0, "Specifies the smallest gen0 size") \ + INT_CONFIG (SegmentSize, "GCSegmentSize", NULL, 0, "Specifies the managed heap segment size") \ + INT_CONFIG (LatencyMode, "GCLatencyMode", NULL, -1, "Specifies the GC latency mode - batch, interactive or low latency (note that the same " \ + "thing can be specified via API which is the supported way") \ + INT_CONFIG (LatencyLevel, "GCLatencyLevel", NULL, 1, "Specifies the GC latency level that you want to optimize for. Must be a number from 0" \ + "3. See documentation for more details on each level.") \ + INT_CONFIG (LogFileSize, "GCLogFileSize", NULL, 0, "Specifies the GC log file size") \ + INT_CONFIG (CompactRatio, "GCCompactRatio", NULL, 0, "Specifies the ratio compacting GCs vs sweeping") \ + INT_CONFIG (GCHeapAffinitizeMask, "GCHeapAffinitizeMask", "System.GC.HeapAffinitizeMask", 0, "Specifies processor mask for Server GC threads") \ + STRING_CONFIG(GCHeapAffinitizeRanges, "GCHeapAffinitizeRanges", NULL, "Specifies list of processors for Server GC threads. The format is a comma separated " \ + "list of processor numbers or ranges of processor numbers. On Windows, each entry is " \ + "prefixed by the CPU group number. Example: Unix - 1,3,5,7-9,12, Windows - 0:1,1:7-9") \ + INT_CONFIG (GCHighMemPercent, "GCHighMemPercent", NULL, 0, "The percent for GC to consider as high memory") \ + INT_CONFIG (GCProvModeStress, "GCProvModeStress", NULL, 0, "Stress the provisional modes") \ + INT_CONFIG (GCGen0MaxBudget, "GCGen0MaxBudget", NULL, 0, "Specifies the largest gen0 allocation budget") \ + INT_CONFIG (GCHeapHardLimit, "GCHeapHardLimit", NULL, 0, "Specifies a hard limit for the GC heap") \ + INT_CONFIG (GCHeapHardLimitPercent, "GCHeapHardLimitPercent", "System.GC.HeapHardLimitPercent", 0, "Specifies the GC heap usage as a percentage of the total memory") \ + INT_CONFIG (GCTotalPhysicalMemory, "GCTotalPhysicalMemory", NULL, 0, "Specifies what the GC should consider to be total physical memory") \ + STRING_CONFIG(LogFile, "GCLogFile", NULL, "Specifies the name of the GC log file") \ + STRING_CONFIG(ConfigLogFile, "GCConfigLogFile", NULL, "Specifies the name of the GC config log file") \ + INT_CONFIG (BGCFLTuningEnabled, "BGCFLTuningEnabled", NULL, 0, "Enables FL tuning") \ + INT_CONFIG (BGCMemGoal, "BGCMemGoal", NULL, 75, "Specifies the physical memory load goal") \ + INT_CONFIG (BGCMemGoalSlack, "BGCMemGoalSlack", NULL, 10, "Specifies comfort zone of going above goal") \ + INT_CONFIG (BGCFLSweepGoal, "BGCFLSweepGoal", NULL, 0, "Specifies the gen2 sweep FL ratio goal") \ + INT_CONFIG (BGCFLSweepGoalLOH, "BGCFLSweepGoalLOH", NULL, 0, "Specifies the LOH sweep FL ratio goal") \ + INT_CONFIG (BGCFLkp, "BGCFLkp", NULL, 6000, "Specifies kp for above goal tuning") \ + INT_CONFIG (BGCFLki, "BGCFLki", NULL, 1000, "Specifies ki for above goal tuning") \ + INT_CONFIG (BGCFLkd, "BGCFLkd", NULL, 11, "Specifies kd for above goal tuning") \ + INT_CONFIG (BGCFLff, "BGCFLff", NULL, 100, "Specifies ff ratio") \ + INT_CONFIG (BGCFLSmoothFactor, "BGCFLSmoothFactor", NULL, 150, "Smoothing over these") \ + INT_CONFIG (BGCFLGradualD, "BGCFLGradualD", NULL, 0, "Enable gradual D instead of cutting of at the value") \ + INT_CONFIG (BGCMLkp, "BGCMLkp", NULL, 1000, "Specifies kp for ML tuning") \ + INT_CONFIG (BGCMLki, "BGCMLki", NULL, 16, "Specifies ki for ML tuning") \ + INT_CONFIG (BGCFLEnableKi, "BGCFLEnableKi", NULL, 1, "Enables ki for above goal tuning") \ + INT_CONFIG (BGCFLEnableKd, "BGCFLEnableKd", NULL, 0, "Enables kd for above goal tuning") \ + INT_CONFIG (BGCFLEnableSmooth, "BGCFLEnableSmooth", NULL, 0, "Enables smoothing") \ + INT_CONFIG (BGCFLEnableTBH, "BGCFLEnableTBH", NULL, 0, "Enables TBH") \ + INT_CONFIG (BGCFLEnableFF, "BGCFLEnableFF", NULL, 0, "Enables FF") \ + INT_CONFIG (BGCG2RatioStep, "BGCG2RatioStep", NULL, 5, "Ratio correction factor for ML loop") // This class is responsible for retreiving configuration information // for how the GC should operate. class GCConfig { -#define BOOL_CONFIG(name, unused_key, unused_default, unused_doc) \ +#define BOOL_CONFIG(name, unused_private_key, unused_public_key, unused_default, unused_doc) \ public: static bool Get##name(); \ private: static bool s_##name; -#define INT_CONFIG(name, unused_key, unused_default, unused_doc) \ +#define INT_CONFIG(name, unused_private_key, unused_public_key, unused_default, unused_doc) \ public: static int64_t Get##name(); \ private: static int64_t s_##name; -#define STRING_CONFIG(name, unused_key, unused_doc) \ +#define STRING_CONFIG(name, unused_private_key, unused_public_key, unused_doc) \ public: static GCConfigStringHolder Get##name(); + GC_CONFIGURATION_KEYS + #undef BOOL_CONFIG #undef INT_CONFIG #undef STRING_CONFIG diff --git a/src/coreclr/src/gc/gcenv.ee.standalone.inl b/src/coreclr/src/gc/gcenv.ee.standalone.inl index 7ed523edd6892a..b91d0c4d5b8915 100644 --- a/src/coreclr/src/gc/gcenv.ee.standalone.inl +++ b/src/coreclr/src/gc/gcenv.ee.standalone.inl @@ -203,22 +203,22 @@ inline MethodTable* GCToEEInterface::GetFreeObjectMethodTable() return g_theGCToCLR->GetFreeObjectMethodTable(); } -inline bool GCToEEInterface::GetBooleanConfigValue(const char* key, bool* value) +inline bool GCToEEInterface::GetBooleanConfigValue(const char* privateKey, const char* publicKey, bool* value) { assert(g_theGCToCLR != nullptr); - return g_theGCToCLR->GetBooleanConfigValue(key, value); + return g_theGCToCLR->GetBooleanConfigValue(privateKey, publicKey, value); } -inline bool GCToEEInterface::GetIntConfigValue(const char* key, int64_t* value) +inline bool GCToEEInterface::GetIntConfigValue(const char* privateKey, const char* publicKey, int64_t* value) { assert(g_theGCToCLR != nullptr); - return g_theGCToCLR->GetIntConfigValue(key, value); + return g_theGCToCLR->GetIntConfigValue(privateKey, publicKey, value); } -inline bool GCToEEInterface::GetStringConfigValue(const char* key, const char** value) +inline bool GCToEEInterface::GetStringConfigValue(const char* privateKey, const char* publicKey, const char** value) { assert(g_theGCToCLR != nullptr); - return g_theGCToCLR->GetStringConfigValue(key, value); + return g_theGCToCLR->GetStringConfigValue(privateKey, publicKey, value); } inline void GCToEEInterface::FreeStringConfigValue(const char* value) diff --git a/src/coreclr/src/gc/gchandletable.cpp b/src/coreclr/src/gc/gchandletable.cpp index b7c4bf26872336..d3f93b457521eb 100644 --- a/src/coreclr/src/gc/gchandletable.cpp +++ b/src/coreclr/src/gc/gchandletable.cpp @@ -168,7 +168,7 @@ Object* GCHandleManager::InterlockedCompareExchangeObjectInHandle(OBJECTHANDLE h HandleType GCHandleManager::HandleFetchType(OBJECTHANDLE handle) { uint32_t type = ::HandleFetchType(handle); - assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_WINRT); + assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_NATIVE_COM); return static_cast(type); } diff --git a/src/coreclr/src/gc/gcinterface.ee.h b/src/coreclr/src/gc/gcinterface.ee.h index 4d8cb61c0a6d28..bc9a0ab162c34d 100644 --- a/src/coreclr/src/gc/gcinterface.ee.h +++ b/src/coreclr/src/gc/gcinterface.ee.h @@ -348,13 +348,13 @@ class IGCToCLR { // pointer is undefined. Otherwise, true is returned and the config key's value is written to // the passed-in pointer. virtual - bool GetBooleanConfigValue(const char* key, bool* value) = 0; + bool GetBooleanConfigValue(const char* privateKey, const char* publicKey, bool* value) = 0; virtual - bool GetIntConfigValue(const char* key, int64_t* value) = 0; + bool GetIntConfigValue(const char* privateKey, const char* publicKey, int64_t* value) = 0; virtual - bool GetStringConfigValue(const char* key, const char** value) = 0; + bool GetStringConfigValue(const char* privateKey, const char* publicKey, const char** value) = 0; virtual void FreeStringConfigValue(const char* value) = 0; diff --git a/src/coreclr/src/gc/gcinterface.h b/src/coreclr/src/gc/gcinterface.h index 122106c2ae273a..e9bef6a502b458 100644 --- a/src/coreclr/src/gc/gcinterface.h +++ b/src/coreclr/src/gc/gcinterface.h @@ -422,18 +422,18 @@ typedef enum HNDTYPE_SIZEDREF = 8, /* - * WINRT WEAK HANDLES + * NATIVE WEAK HANDLES * - * WinRT weak reference handles hold two different types of weak handles to any + * Native weak reference handles hold two different types of weak handles to any * RCW with an underlying COM object that implements IWeakReferenceSource. The * object reference itself is a short weak handle to the RCW. In addition an * IWeakReference* to the underlying COM object is stored, allowing the handle * to create a new RCW if the existing RCW is collected. This ensures that any - * code holding onto a WinRT weak reference can always access an RCW to the + * code holding onto a native weak reference can always access an RCW to the * underlying COM object as long as it has not been released by all of its strong * references. */ - HNDTYPE_WEAK_WINRT = 9 + HNDTYPE_WEAK_NATIVE_COM = 9 } HandleType; typedef enum diff --git a/src/coreclr/src/gc/gcpriv.h b/src/coreclr/src/gc/gcpriv.h index 8b7765d20e3744..ac6e746317889f 100644 --- a/src/coreclr/src/gc/gcpriv.h +++ b/src/coreclr/src/gc/gcpriv.h @@ -223,6 +223,7 @@ const int policy_expand = 2; #define JOIN_LOG (MIN_CUSTOM_LOG_LEVEL + 6) #define SPINLOCK_LOG (MIN_CUSTOM_LOG_LEVEL + 7) #define SNOOP_LOG (MIN_CUSTOM_LOG_LEVEL + 8) +#define COMMIT_ACCOUNTING_LOG (MIN_CUSTOM_LOG_LEVEL + 9) // NOTE! This is for HEAP_BALANCE_INSTRUMENTATION // This particular one is special and needs to be well formatted because we @@ -398,6 +399,17 @@ enum gc_tuning_point tuning_deciding_short_on_seg = 5 }; +enum gc_oh_num +{ + soh = 0, + loh = 1, + poh = 2, + none = 3, + total_oh_count = 4 +}; + +gc_oh_num gen_to_oh (int gen); + #if defined(TRACE_GC) && defined(BACKGROUND_GC) static const char * const str_bgc_state[] = { @@ -1138,6 +1150,7 @@ class gc_heap static heap_segment* make_heap_segment (uint8_t* new_pages, size_t size, + gc_oh_num oh, int h_number); static @@ -1269,6 +1282,11 @@ class gc_heap #endif // FEATURE_BASICFREEZE protected: + PER_HEAP_ISOLATED + BOOL reserve_initial_memory (size_t normal_size, size_t large_size, size_t pinned_size, int num_heaps, bool use_large_pages_p); + + PER_HEAP_ISOLATED + void destroy_initial_memory(); PER_HEAP_ISOLATED void walk_heap (walk_fn fn, void* context, int gen_number, BOOL walk_large_object_heap_p); @@ -1631,7 +1649,9 @@ class gc_heap PER_HEAP heap_segment* soh_get_segment_to_expand(); PER_HEAP - heap_segment* get_segment (size_t size, BOOL loh_p); + heap_segment* get_segment (size_t size, gc_oh_num oh); + PER_HEAP_ISOLATED + void release_segment (heap_segment* sg); PER_HEAP_ISOLATED void seg_mapping_table_add_segment (heap_segment* seg, gc_heap* hp); PER_HEAP_ISOLATED @@ -1651,13 +1671,21 @@ class gc_heap PER_HEAP void decommit_heap_segment_pages (heap_segment* seg, size_t extra_space); PER_HEAP + size_t decommit_ephemeral_segment_pages_step (); + PER_HEAP + size_t decommit_heap_segment_pages_worker (heap_segment* seg, uint8_t *new_committed); + PER_HEAP_ISOLATED + bool decommit_step (); + PER_HEAP void decommit_heap_segment (heap_segment* seg); PER_HEAP_ISOLATED bool virtual_alloc_commit_for_heap (void* addr, size_t size, int h_number); PER_HEAP_ISOLATED - bool virtual_commit (void* address, size_t size, int h_number=-1, bool* hard_limit_exceeded_p=NULL); + bool virtual_commit (void* address, size_t size, gc_oh_num oh, int h_number=-1, bool* hard_limit_exceeded_p=NULL); PER_HEAP_ISOLATED - bool virtual_decommit (void* address, size_t size, int h_number=-1); + bool virtual_decommit (void* address, size_t size, gc_oh_num oh, int h_number=-1); + PER_HEAP_ISOLATED + void virtual_free (void* add, size_t size, heap_segment* sg=NULL); PER_HEAP void clear_gen0_bricks(); #ifdef BACKGROUND_GC @@ -1878,7 +1906,7 @@ class gc_heap size_t& promoted_bytes (int); PER_HEAP - uint8_t* find_object (uint8_t* o, uint8_t* low); + uint8_t* find_object (uint8_t* o); PER_HEAP dynamic_data* dynamic_data_of (int gen_number); @@ -2012,8 +2040,6 @@ class gc_heap PER_HEAP void background_sweep (); PER_HEAP - void background_mark_through_object (uint8_t* oo THREAD_NUMBER_DCL); - PER_HEAP uint8_t* background_seg_end (heap_segment* seg, BOOL concurrent_p); PER_HEAP uint8_t* background_first_overflow (uint8_t* min_add, @@ -2300,8 +2326,6 @@ class gc_heap #endif //BACKGROUND_GC - PER_HEAP - uint8_t* next_end (heap_segment* seg, uint8_t* f); PER_HEAP void mark_through_object (uint8_t* oo, BOOL mark_class_object_p THREAD_NUMBER_DCL); PER_HEAP @@ -2329,7 +2353,7 @@ class gc_heap void mark_phase (int condemned_gen_number, BOOL mark_only_p); PER_HEAP - void pin_object (uint8_t* o, uint8_t** ppObject, uint8_t* low, uint8_t* high); + void pin_object (uint8_t* o, uint8_t** ppObject); #if defined(ENABLE_PERF_COUNTERS) || defined(FEATURE_EVENT_TRACE) PER_HEAP_ISOLATED @@ -2450,8 +2474,6 @@ class gc_heap void check_loh_compact_mode (BOOL all_heaps_compacted_p); #endif //FEATURE_LOH_COMPACTION - PER_HEAP - void decommit_ephemeral_segment_pages (int condemned_gen_number); PER_HEAP void fix_generation_bounds (int condemned_gen_number, generation* consing_gen); @@ -2487,8 +2509,6 @@ class gc_heap struct relocate_args { uint8_t* last_plug; - uint8_t* low; - uint8_t* high; BOOL is_shortened; mark* pinned_plug_entry; }; @@ -3261,9 +3281,6 @@ class gc_heap PER_HEAP_ISOLATED size_t gc_last_ephemeral_decommit_time; - PER_HEAP_ISOLATED - size_t gc_gen0_desired_high; - PER_HEAP size_t gen0_big_free_spaces; @@ -3295,6 +3312,9 @@ class gc_heap PER_HEAP_ISOLATED uint32_t v_high_memory_load_th; + PER_HEAP_ISOLATED + bool is_restricted_physical_mem; + PER_HEAP_ISOLATED uint64_t mem_one_percent; @@ -3369,6 +3389,9 @@ class gc_heap PER_HEAP_ISOLATED size_t current_total_committed; + PER_HEAP_ISOLATED + size_t committed_by_oh[total_oh_count]; + // This is what GC uses for its own bookkeeping. PER_HEAP_ISOLATED size_t current_total_committed_bookkeeping; @@ -3788,6 +3811,14 @@ class gc_heap PER_HEAP_ISOLATED BOOL proceed_with_gc_p; +#ifdef MULTIPLE_HEAPS + PER_HEAP_ISOLATED + BOOL gradual_decommit_in_progress_p; + + PER_HEAP_ISOLATED + size_t max_decommit_step_size; +#endif //MULTIPLE_HEAPS + #define youngest_generation (generation_of (0)) #define large_object_generation (generation_of (loh_generation)) #define pinned_object_generation (generation_of (poh_generation)) @@ -4126,7 +4157,6 @@ class gc_heap #endif //HEAP_ANALYZE - /* ----------------------- global members ----------------------- */ public: PER_HEAP @@ -4702,7 +4732,12 @@ class heap_segment uint8_t* background_allocated; #ifdef MULTIPLE_HEAPS gc_heap* heap; +#ifdef _DEBUG + uint8_t* saved_committed; + size_t saved_desired_allocation; +#endif // _DEBUG #endif //MULTIPLE_HEAPS + uint8_t* decommit_target; uint8_t* plan_allocated; uint8_t* saved_bg_allocated; @@ -4739,6 +4774,11 @@ uint8_t*& heap_segment_committed (heap_segment* inst) return inst->committed; } inline +uint8_t*& heap_segment_decommit_target (heap_segment* inst) +{ + return inst->decommit_target; +} +inline uint8_t*& heap_segment_used (heap_segment* inst) { return inst->used; @@ -4775,6 +4815,22 @@ BOOL heap_segment_uoh_p (heap_segment * inst) return !!(inst->flags & (heap_segment_flags_loh | heap_segment_flags_poh)); } +inline gc_oh_num heap_segment_oh (heap_segment * inst) +{ + if ((inst->flags & heap_segment_flags_loh) != 0) + { + return gc_oh_num::loh; + } + else if ((inst->flags & heap_segment_flags_poh) != 0) + { + return gc_oh_num::poh; + } + else + { + return gc_oh_num::soh; + } +} + #ifdef BACKGROUND_GC inline BOOL heap_segment_decommitted_p (heap_segment * inst) diff --git a/src/coreclr/src/gc/handletable.cpp b/src/coreclr/src/gc/handletable.cpp index 898e843419341b..1b56c74c791cff 100644 --- a/src/coreclr/src/gc/handletable.cpp +++ b/src/coreclr/src/gc/handletable.cpp @@ -409,10 +409,10 @@ void HndDestroyHandleOfUnknownType(HHANDLETABLE hTable, OBJECTHANDLE handle) _ASSERTE(handle); #ifdef FEATURE_COMINTEROP - // If we're being asked to destroy a WinRT weak handle, that will cause a leak + // If we're being asked to destroy a native COM weak handle, that will cause a leak // of the IWeakReference* that it holds in its extra data. Instead of using this - // API use DestroyWinRTWeakHandle instead. - _ASSERTE(HandleFetchType(handle) != HNDTYPE_WEAK_WINRT); + // API use DestroyNativeComWeakHandle instead. + _ASSERTE(HandleFetchType(handle) != HNDTYPE_WEAK_NATIVE_COM); #endif // FEATURE_COMINTEROP // fetch the type and then free normally diff --git a/src/coreclr/src/gc/objecthandle.cpp b/src/coreclr/src/gc/objecthandle.cpp index 4a4f201ca03bd0..e6a5160d7ee543 100644 --- a/src/coreclr/src/gc/objecthandle.cpp +++ b/src/coreclr/src/gc/objecthandle.cpp @@ -426,7 +426,7 @@ void CALLBACK ScanPointerForProfilerAndETW(_UNCHECKED_OBJECTREF *pObjRef, uintpt case HNDTYPE_WEAK_SHORT: case HNDTYPE_WEAK_LONG: #ifdef FEATURE_COMINTEROP - case HNDTYPE_WEAK_WINRT: + case HNDTYPE_WEAK_NATIVE_COM: #endif // FEATURE_COMINTEROP rootFlags |= kEtwGCRootFlagsWeakRef; break; @@ -520,7 +520,7 @@ static const uint32_t s_rgTypeFlags[] = HNDF_EXTRAINFO, // HNDTYPE_DEPENDENT HNDF_NORMAL, // HNDTYPE_ASYNCPINNED HNDF_EXTRAINFO, // HNDTYPE_SIZEDREF - HNDF_EXTRAINFO, // HNDTYPE_WEAK_WINRT + HNDF_EXTRAINFO, // HNDTYPE_WEAK_NATIVE_COM }; int getNumberOfSlots() @@ -1380,7 +1380,7 @@ void Ref_CheckAlive(uint32_t condemned, uint32_t maxgen, uintptr_t lp1) { HNDTYPE_WEAK_SHORT #ifdef FEATURE_COMINTEROP - , HNDTYPE_WEAK_WINRT + , HNDTYPE_WEAK_NATIVE_COM #endif // FEATURE_COMINTEROP }; uint32_t flags = (((ScanContext*) lp1)->concurrent) ? HNDGCF_ASYNC : HNDGCF_NORMAL; @@ -1439,7 +1439,7 @@ void Ref_UpdatePointers(uint32_t condemned, uint32_t maxgen, ScanContext* sc, Re HNDTYPE_REFCOUNTED, #endif // FEATURE_COMINTEROP || FEATURE_REDHAWK #ifdef FEATURE_COMINTEROP - HNDTYPE_WEAK_WINRT, + HNDTYPE_WEAK_NATIVE_COM, #endif // FEATURE_COMINTEROP HNDTYPE_SIZEDREF, }; @@ -1485,7 +1485,7 @@ void Ref_ScanHandlesForProfilerAndETW(uint32_t maxgen, uintptr_t lp1, handle_sca HNDTYPE_REFCOUNTED, #endif // FEATURE_COMINTEROP || FEATURE_REDHAWK #ifdef FEATURE_COMINTEROP - HNDTYPE_WEAK_WINRT, + HNDTYPE_WEAK_NATIVE_COM, #endif // FEATURE_COMINTEROP HNDTYPE_PINNED, // HNDTYPE_VARIABLE, @@ -1631,7 +1631,7 @@ void Ref_AgeHandles(uint32_t condemned, uint32_t maxgen, uintptr_t lp1) HNDTYPE_REFCOUNTED, #endif // FEATURE_COMINTEROP || FEATURE_REDHAWK #ifdef FEATURE_COMINTEROP - HNDTYPE_WEAK_WINRT, + HNDTYPE_WEAK_NATIVE_COM, #endif // FEATURE_COMINTEROP HNDTYPE_ASYNCPINNED, HNDTYPE_SIZEDREF, @@ -1674,7 +1674,7 @@ void Ref_RejuvenateHandles(uint32_t condemned, uint32_t maxgen, uintptr_t lp1) HNDTYPE_REFCOUNTED, #endif // FEATURE_COMINTEROP || FEATURE_REDHAWK #ifdef FEATURE_COMINTEROP - HNDTYPE_WEAK_WINRT, + HNDTYPE_WEAK_NATIVE_COM, #endif // FEATURE_COMINTEROP HNDTYPE_ASYNCPINNED, HNDTYPE_SIZEDREF, @@ -1716,7 +1716,7 @@ void Ref_VerifyHandleTable(uint32_t condemned, uint32_t maxgen, ScanContext* sc) HNDTYPE_REFCOUNTED, #endif // FEATURE_COMINTEROP || FEATURE_REDHAWK #ifdef FEATURE_COMINTEROP - HNDTYPE_WEAK_WINRT, + HNDTYPE_WEAK_NATIVE_COM, #endif // FEATURE_COMINTEROP HNDTYPE_ASYNCPINNED, HNDTYPE_SIZEDREF, diff --git a/src/coreclr/src/gc/sample/gcenv.ee.cpp b/src/coreclr/src/gc/sample/gcenv.ee.cpp index 9dad62e20bf1a1..6f5151ee1534cd 100644 --- a/src/coreclr/src/gc/sample/gcenv.ee.cpp +++ b/src/coreclr/src/gc/sample/gcenv.ee.cpp @@ -275,17 +275,17 @@ bool GCToEEInterface::EagerFinalized(Object* obj) return false; } -bool GCToEEInterface::GetBooleanConfigValue(const char* key, bool* value) +bool GCToEEInterface::GetBooleanConfigValue(const char* privateKey, const char* publicKey, bool* value) { return false; } -bool GCToEEInterface::GetIntConfigValue(const char* key, int64_t* value) +bool GCToEEInterface::GetIntConfigValue(const char* privateKey, const char* publicKey, int64_t* value) { return false; } -bool GCToEEInterface::GetStringConfigValue(const char* key, const char** value) +bool GCToEEInterface::GetStringConfigValue(const char* privateKey, const char* publicKey, const char** value) { return false; } diff --git a/src/coreclr/src/gc/unix/cgroup.cpp b/src/coreclr/src/gc/unix/cgroup.cpp index 5d8ea5320a89f6..9cdc5b14df021c 100644 --- a/src/coreclr/src/gc/unix/cgroup.cpp +++ b/src/coreclr/src/gc/unix/cgroup.cpp @@ -54,6 +54,8 @@ Module Name: #define CGROUP1_CFS_PERIOD_FILENAME "/cpu.cfs_period_us" #define CGROUP2_CPU_MAX_FILENAME "/cpu.max" +extern bool ReadMemoryValueFromFile(const char* filename, uint64_t* val); + class CGroup { // the cgroup version number or 0 to indicate cgroups are not found or not enabled @@ -132,6 +134,10 @@ class CGroup // modes because both of those involve cgroup v1 controllers managing // resources. +#if !HAVE_NON_LEGACY_STATFS + return 0; +#else + struct statfs stats; int result = statfs("/sys/fs/cgroup", &stats); if (result != 0) @@ -145,6 +151,7 @@ class CGroup assert(!"Unexpected file system type for /sys/fs/cgroup"); return 0; } +#endif } static bool IsCGroup1MemorySubsystem(const char *strTok){ @@ -415,52 +422,6 @@ class CGroup return result; } - static bool ReadMemoryValueFromFile(const char* filename, uint64_t* val) - { - bool result = false; - char *line = nullptr; - size_t lineLen = 0; - char* endptr = nullptr; - uint64_t num = 0, l, multiplier; - FILE* file = nullptr; - - if (val == nullptr) - goto done; - - file = fopen(filename, "r"); - if (file == nullptr) - goto done; - - if (getline(&line, &lineLen, file) == -1) - goto done; - - errno = 0; - num = strtoull(line, &endptr, 0); - if (line == endptr || errno != 0) - goto done; - - multiplier = 1; - switch(*endptr) - { - case 'g': - case 'G': multiplier = 1024; - case 'm': - case 'M': multiplier = multiplier*1024; - case 'k': - case 'K': multiplier = multiplier*1024; - } - - *val = num * multiplier; - result = true; - if (*val/multiplier != num) - result = false; - done: - if (file) - fclose(file); - free(line); - return result; - } - static bool GetCGroup1CpuLimit(uint32_t *val) { long long quota; diff --git a/src/coreclr/src/gc/unix/config.gc.h.in b/src/coreclr/src/gc/unix/config.gc.h.in index a1d60d3e1fda2d..ad33f95b6bdc81 100644 --- a/src/coreclr/src/gc/unix/config.gc.h.in +++ b/src/coreclr/src/gc/unix/config.gc.h.in @@ -14,6 +14,7 @@ #cmakedefine01 HAVE_SCHED_GETCPU #cmakedefine01 HAVE_NUMA_H #cmakedefine01 HAVE_VM_ALLOCATE +#cmakedefine01 HAVE_SWAPCTL #cmakedefine01 HAVE_SYSCTLBYNAME #cmakedefine01 HAVE_PTHREAD_CONDATTR_SETCLOCK #cmakedefine01 HAVE_MACH_ABSOLUTE_TIME diff --git a/src/coreclr/src/gc/unix/configure.cmake b/src/coreclr/src/gc/unix/configure.cmake index 9ed93b95b7159d..cc7fb90265d8be 100644 --- a/src/coreclr/src/gc/unix/configure.cmake +++ b/src/coreclr/src/gc/unix/configure.cmake @@ -98,6 +98,7 @@ check_library_exists(${PTHREAD_LIBRARY} pthread_getaffinity_np "" HAVE_PTHREAD_G check_cxx_symbol_exists(_SC_PHYS_PAGES unistd.h HAVE__SC_PHYS_PAGES) check_cxx_symbol_exists(_SC_AVPHYS_PAGES unistd.h HAVE__SC_AVPHYS_PAGES) +check_cxx_symbol_exists(swapctl sys/swap.h HAVE_SWAPCTL) check_function_exists(sysctl HAVE_SYSCTL) check_function_exists(sysinfo HAVE_SYSINFO) check_function_exists(sysconf HAVE_SYSCONF) diff --git a/src/coreclr/src/gc/unix/gcenv.unix.cpp b/src/coreclr/src/gc/unix/gcenv.unix.cpp index 855f2da02a9822..9b78b70f53abbb 100644 --- a/src/coreclr/src/gc/unix/gcenv.unix.cpp +++ b/src/coreclr/src/gc/unix/gcenv.unix.cpp @@ -22,6 +22,10 @@ #include "gcenv.unix.inl" #include "volatile.h" +#if HAVE_SWAPCTL +#include +#endif + #undef min #undef max @@ -731,7 +735,7 @@ bool GCToOSInterface::VirtualReset(void * address, size_t size, bool unlock) #endif { // In case the MADV_FREE is not supported, use MADV_DONTNEED - st = madvise(address, size, MADV_DONTNEED); + st = posix_madvise(address, size, MADV_DONTNEED); } return (st == 0); @@ -768,6 +772,52 @@ bool GCToOSInterface::GetWriteWatch(bool resetState, void* address, size_t size, return false; } +bool ReadMemoryValueFromFile(const char* filename, uint64_t* val) +{ + bool result = false; + char* line = nullptr; + size_t lineLen = 0; + char* endptr = nullptr; + uint64_t num = 0, l, multiplier; + FILE* file = nullptr; + + if (val == nullptr) + goto done; + + file = fopen(filename, "r"); + if (file == nullptr) + goto done; + + if (getline(&line, &lineLen, file) == -1) + goto done; + + errno = 0; + num = strtoull(line, &endptr, 0); + if (line == endptr || errno != 0) + goto done; + + multiplier = 1; + switch (*endptr) + { + case 'g': + case 'G': multiplier = 1024; + case 'm': + case 'M': multiplier = multiplier * 1024; + case 'k': + case 'K': multiplier = multiplier * 1024; + } + + *val = num * multiplier; + result = true; + if (*val / multiplier != num) + result = false; +done: + if (file) + fclose(file); + free(line); + return result; +} + static size_t GetLogicalProcessorCacheSizeFromOS() { size_t cacheSize = 0; @@ -785,6 +835,49 @@ static size_t GetLogicalProcessorCacheSizeFromOS() cacheSize = std::max(cacheSize, ( size_t) sysconf(_SC_LEVEL4_CACHE_SIZE)); #endif +#if defined(HOST_ARM64) + if (cacheSize == 0) + { + size_t size; + + if (ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index0/size", &size)) + cacheSize = std::max(cacheSize, size); + if (ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index1/size", &size)) + cacheSize = std::max(cacheSize, size); + if (ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index2/size", &size)) + cacheSize = std::max(cacheSize, size); + if (ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index3/size", &size)) + cacheSize = std::max(cacheSize, size); + if (ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index4/size", &size)) + cacheSize = std::max(cacheSize, size); + } + + if (cacheSize == 0) + { + // It is currently expected to be missing cache size info + // + // _SC_LEVEL*_*CACHE_SIZE is not yet present. Work is in progress to enable this for arm64 + // + // /sys/devices/system/cpu/cpu*/cache/index*/ is also not yet present in most systems. + // Arm64 patch is in Linux kernel tip. + // + // midr_el1 is available in "/sys/devices/system/cpu/cpu0/regs/identification/midr_el1", + // but without an exhaustive list of ARM64 processors any decode of midr_el1 + // Would likely be incomplete + + // Published information on ARM64 architectures is limited. + // If we use recent high core count chips as a guide for state of the art, we find + // total L3 cache to be 1-2MB/core. As always, there are exceptions. + + // Estimate cache size based on CPU count + // Assume lower core count are lighter weight parts which are likely to have smaller caches + // Assume L3$/CPU grows linearly from 256K to 1.5M/CPU as logicalCPUs grows from 2 to 12 CPUs + DWORD logicalCPUs = g_totalCpuCount; + + cacheSize = logicalCPUs * std::min(1536, std::max(256, (int)logicalCPUs * 128)) * 1024; + } +#endif + #if HAVE_SYSCTLBYNAME if (cacheSize == 0) { @@ -953,7 +1046,7 @@ uint32_t GCToOSInterface::GetCurrentProcessCpuCount() // Return the size of the user-mode portion of the virtual address space of this process. // Return: -// non zero if it has succeeded, 0 if it has failed +// non zero if it has succeeded, (size_t)-1 if not available size_t GCToOSInterface::GetVirtualMemoryLimit() { #ifdef HOST_64BIT @@ -1112,6 +1205,13 @@ uint64_t GetAvailablePageFile() available += avail * pagesize; } } +#elif HAVE_SWAPCTL + struct anoninfo ai; + if (swapctl(SC_AINFO, &ai) != -1) + { + int pagesize = getpagesize(); + available = ai.ani_free * pagesize; + } #elif HAVE_SYSINFO // Linux struct sysinfo info; @@ -1132,11 +1232,13 @@ uint64_t GetAvailablePageFile() // Get memory status // Parameters: +// restricted_limit - The amount of physical memory in bytes that the current process is being restricted to. If non-zero, it used to calculate +// memory_load and available_physical. If zero, memory_load and available_physical is calculate based on all available memory. // memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory // that is in use (0 indicates no memory use and 100 indicates full memory use). // available_physical - The amount of physical memory currently available, in bytes. // available_page_file - The maximum amount of memory the current process can commit, in bytes. -void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) +void GCToOSInterface::GetMemoryStatus(uint64_t restricted_limit, uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) { uint64_t available = 0; uint32_t load = 0; @@ -1144,16 +1246,14 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available if (memory_load != nullptr || available_physical != nullptr) { size_t used; - bool isRestricted; - uint64_t total = GetPhysicalMemoryLimit(&isRestricted); - if (isRestricted) + if (restricted_limit != 0) { // Get the physical memory in use - from it, we can get the physical memory available. // We do this only when we have the total physical memory available. if (GetPhysicalMemoryUsed(&used)) { - available = total > used ? total-used : 0; - load = (uint32_t)(((float)used * 100) / (float)total); + available = restricted_limit > used ? restricted_limit - used : 0; + load = (uint32_t)(((float)used * 100) / (float)restricted_limit); } } else @@ -1162,7 +1262,9 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available if (memory_load != NULL) { - uint32_t load = 0; + bool isRestricted; + uint64_t total = GetPhysicalMemoryLimit(&isRestricted); + if (total > available) { used = total - available; @@ -1180,7 +1282,6 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available if (available_page_file != nullptr) *available_page_file = GetAvailablePageFile(); - } // Get a high precision performance counter diff --git a/src/coreclr/src/gc/windows/gcenv.windows.cpp b/src/coreclr/src/gc/windows/gcenv.windows.cpp index 2aaf7ba19aa5e3..a9504bd4b69adf 100644 --- a/src/coreclr/src/gc/windows/gcenv.windows.cpp +++ b/src/coreclr/src/gc/windows/gcenv.windows.cpp @@ -18,22 +18,12 @@ GCSystemInfo g_SystemInfo; -typedef BOOL (WINAPI *PGET_PROCESS_MEMORY_INFO)(HANDLE handle, PROCESS_MEMORY_COUNTERS* memCounters, uint32_t cb); -static PGET_PROCESS_MEMORY_INFO GCGetProcessMemoryInfo = 0; - static size_t g_RestrictedPhysicalMemoryLimit = (size_t)UINTPTR_MAX; -// For 32-bit processes the virtual address range could be smaller than the amount of physical -// memory on the machine/in the container, we need to restrict by the VM. -static bool g_UseRestrictedVirtualMemory = false; - static bool g_SeLockMemoryPrivilegeAcquired = false; static AffinitySet g_processAffinitySet; -typedef BOOL (WINAPI *PIS_PROCESS_IN_JOB)(HANDLE processHandle, HANDLE jobHandle, BOOL* result); -typedef BOOL (WINAPI *PQUERY_INFORMATION_JOB_OBJECT)(HANDLE jobHandle, JOBOBJECTINFOCLASS jobObjectInfoClass, void* lpJobObjectInfo, DWORD cbJobObjectInfoLength, LPDWORD lpReturnLength); - namespace { static bool g_fEnableGCNumaAware; @@ -297,36 +287,14 @@ static size_t GetRestrictedPhysicalMemoryLimit() uint64_t total_virtual = 0; uint64_t total_physical = 0; BOOL in_job_p = FALSE; - HINSTANCE hinstKernel32 = 0; - - PIS_PROCESS_IN_JOB GCIsProcessInJob = 0; - PQUERY_INFORMATION_JOB_OBJECT GCQueryInformationJobObject = 0; - - hinstKernel32 = LoadLibraryEx(L"kernel32.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); - if (!hinstKernel32) - goto exit; - GCIsProcessInJob = (PIS_PROCESS_IN_JOB)GetProcAddress(hinstKernel32, "IsProcessInJob"); - if (!GCIsProcessInJob) - goto exit; - - if (!GCIsProcessInJob(GetCurrentProcess(), NULL, &in_job_p)) + if (!IsProcessInJob(GetCurrentProcess(), NULL, &in_job_p)) goto exit; if (in_job_p) { - GCGetProcessMemoryInfo = (PGET_PROCESS_MEMORY_INFO)GetProcAddress(hinstKernel32, "K32GetProcessMemoryInfo"); - - if (!GCGetProcessMemoryInfo) - goto exit; - - GCQueryInformationJobObject = (PQUERY_INFORMATION_JOB_OBJECT)GetProcAddress(hinstKernel32, "QueryInformationJobObject"); - - if (!GCQueryInformationJobObject) - goto exit; - JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info; - if (GCQueryInformationJobObject (NULL, JobObjectExtendedLimitInformation, &limit_info, + if (QueryInformationJobObject (NULL, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info), NULL)) { size_t job_memory_limit = (size_t)UINTPTR_MAX; @@ -373,13 +341,6 @@ static size_t GetRestrictedPhysicalMemoryLimit() if (job_physical_memory_limit == (size_t)UINTPTR_MAX) { job_physical_memory_limit = 0; - - if (hinstKernel32 != 0) - { - FreeLibrary(hinstKernel32); - hinstKernel32 = 0; - GCGetProcessMemoryInfo = 0; - } } // Check to see if we are limited by VM. @@ -399,15 +360,8 @@ static size_t GetRestrictedPhysicalMemoryLimit() if (total_virtual < total_physical) { - if (hinstKernel32 != 0) - { - // We can also free the lib here - if we are limited by VM we will not be calling - // GetProcessMemoryInfo. - FreeLibrary(hinstKernel32); - GCGetProcessMemoryInfo = 0; - } - g_UseRestrictedVirtualMemory = true; - job_physical_memory_limit = (size_t)total_virtual; + // Limited by virtual address space + job_physical_memory_limit = 0; } VolatileStore(&g_RestrictedPhysicalMemoryLimit, job_physical_memory_limit); @@ -1044,7 +998,7 @@ uint32_t GCToOSInterface::GetCurrentProcessCpuCount() // Return the size of the user-mode portion of the virtual address space of this process. // Return: -// non zero if it has succeeded, 0 if it has failed +// non zero if it has succeeded, (size_t)-1 if not available size_t GCToOSInterface::GetVirtualMemoryLimit() { MEMORYSTATUSEX memStatus; @@ -1067,7 +1021,7 @@ uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted) size_t restricted_limit = GetRestrictedPhysicalMemoryLimit(); if (restricted_limit != 0) { - if (is_restricted && !g_UseRestrictedVirtualMemory) + if (is_restricted) *is_restricted = true; return restricted_limit; @@ -1081,23 +1035,22 @@ uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted) // Get memory status // Parameters: +// restricted_limit - The amount of physical memory in bytes that the current process is being restricted to. If non-zero, it used to calculate +// memory_load and available_physical. If zero, memory_load and available_physical is calculate based on all available memory. // memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory // that is in use (0 indicates no memory use and 100 indicates full memory use). // available_physical - The amount of physical memory currently available, in bytes. // available_page_file - The maximum amount of memory the current process can commit, in bytes. -void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) +void GCToOSInterface::GetMemoryStatus(uint64_t restricted_limit, uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) { - uint64_t restricted_limit = GetRestrictedPhysicalMemoryLimit(); if (restricted_limit != 0) { size_t workingSetSize; BOOL status = FALSE; - if (!g_UseRestrictedVirtualMemory) - { - PROCESS_MEMORY_COUNTERS pmc; - status = GCGetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); - workingSetSize = pmc.WorkingSetSize; - } + + PROCESS_MEMORY_COUNTERS pmc; + status = GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); + workingSetSize = pmc.WorkingSetSize; if(status) { @@ -1123,9 +1076,10 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available MEMORYSTATUSEX ms; ::GetProcessMemoryLoad(&ms); - if (g_UseRestrictedVirtualMemory) + // For 32-bit processes the virtual address range could be smaller than the amount of physical + // memory on the machine/in the container, we need to restrict by the VM. + if (ms.ullTotalVirtual < ms.ullTotalPhys) { - _ASSERTE (ms.ullTotalVirtual == restricted_limit); if (memory_load != NULL) *memory_load = (uint32_t)((float)(ms.ullTotalVirtual - ms.ullAvailVirtual) * 100.0 / (float)ms.ullTotalVirtual); if (available_physical != NULL) diff --git a/src/coreclr/src/hosts/corerun/corerun.cpp b/src/coreclr/src/hosts/corerun/corerun.cpp index 75c73b68a5ebd4..1643922a3b593f 100644 --- a/src/coreclr/src/hosts/corerun/corerun.cpp +++ b/src/coreclr/src/hosts/corerun/corerun.cpp @@ -767,6 +767,7 @@ bool TryRun(const int argc, const wchar_t* argv[], Logger &log, const bool verbo hr = InitializeHost(log, hostEnvironment, appPath, appNiPath, nativeDllSearchDirs, appLocalWinmetadata, &hostHandle, (unsigned int*)&domainId); if (FAILED(hr)) { + exitCode = hr; return false; } diff --git a/src/coreclr/src/hosts/unixcoreruncommon/config.h.in b/src/coreclr/src/hosts/unixcoreruncommon/config.h.in index 0e457b411c3c8d..8adb7098ef11b8 100644 --- a/src/coreclr/src/hosts/unixcoreruncommon/config.h.in +++ b/src/coreclr/src/hosts/unixcoreruncommon/config.h.in @@ -6,5 +6,6 @@ #define __CONFIG_H__ #cmakedefine01 HAVE_GETAUXVAL +#cmakedefine01 HAVE_DIRENT_D_TYPE #endif // __CONFIG_H__ diff --git a/src/coreclr/src/hosts/unixcoreruncommon/configure.cmake b/src/coreclr/src/hosts/unixcoreruncommon/configure.cmake index ea90cc8a3551c4..61c98113949945 100644 --- a/src/coreclr/src/hosts/unixcoreruncommon/configure.cmake +++ b/src/coreclr/src/hosts/unixcoreruncommon/configure.cmake @@ -1,4 +1,5 @@ check_symbol_exists(getauxval sys/auxv.h HAVE_GETAUXVAL) +check_struct_has_member ("struct dirent" d_type dirent.h HAVE_DIRENT_D_TYPE) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in diff --git a/src/coreclr/src/hosts/unixcoreruncommon/coreruncommon.cpp b/src/coreclr/src/hosts/unixcoreruncommon/coreruncommon.cpp index a2c00b1c3b4ab4..1b6e1fa8204103 100644 --- a/src/coreclr/src/hosts/unixcoreruncommon/coreruncommon.cpp +++ b/src/coreclr/src/hosts/unixcoreruncommon/coreruncommon.cpp @@ -35,6 +35,13 @@ #define SUCCEEDED(Status) ((Status) >= 0) #endif // !SUCCEEDED +#if !HAVE_DIRENT_D_TYPE +#define DT_UNKNOWN 0 +#define DT_DIR 4 +#define DT_REG 8 +#define DT_LNK 10 +#endif + // Name of the environment variable controlling server GC. // If set to 1, server GC is enabled on startup. If 0, server GC is // disabled. Server GC is off by default. @@ -109,6 +116,34 @@ bool GetEntrypointExecutableAbsolutePath(std::string& entrypointExecutable) { result = false; } +#elif defined(__sun) + const char *path; + if ((path = getexecname()) == NULL) + { + result = false; + } + else if (*path != '/') + { + char *cwd; + if ((cwd = getcwd(NULL, PATH_MAX)) == NULL) + { + result = false; + } + else + { + entrypointExecutable + .assign(cwd) + .append("/") + .append(path); + result = true; + free(cwd); + } + } + else + { + entrypointExecutable.assign(path); + result = true; + } #else #if HAVE_GETAUXVAL && defined(AT_EXECFN) @@ -216,8 +251,14 @@ void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) // For all entries in the directory while ((entry = readdir(dir)) != nullptr) { +#if HAVE_DIRENT_D_TYPE + int dirEntryType = entry->d_type; +#else + int dirEntryType = DT_UNKNOWN; +#endif + // We are interested in files only - switch (entry->d_type) + switch (dirEntryType) { case DT_REG: break; diff --git a/src/coreclr/src/ilasm/CMakeLists.txt b/src/coreclr/src/ilasm/CMakeLists.txt index e8f1460f3c414f..94fe6b83d3a414 100644 --- a/src/coreclr/src/ilasm/CMakeLists.txt +++ b/src/coreclr/src/ilasm/CMakeLists.txt @@ -52,7 +52,7 @@ if(CLR_CMAKE_HOST_UNIX) set_source_files_properties( prebuilt/asmparse.cpp PROPERTIES COMPILE_FLAGS "-O0" ) endif(CLR_CMAKE_HOST_UNIX) -if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) +if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) # This option is necessary to ensure that the overloaded delete operator defined inside # of the utilcode will be used instead of the standard library delete operator. set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Xlinker -Bsymbolic") @@ -61,8 +61,7 @@ if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) # ensure proper resolving of circular references between a subset of the libraries. set(START_LIBRARY_GROUP -Wl,--start-group) set(END_LIBRARY_GROUP -Wl,--end-group) -endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) - +endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) _add_executable(ilasm ${ILASM_SOURCES} diff --git a/src/coreclr/src/ilasm/ilasmpch.h b/src/coreclr/src/ilasm/ilasmpch.h index 56e86c21d0c07e..31be491abc8a6a 100644 --- a/src/coreclr/src/ilasm/ilasmpch.h +++ b/src/coreclr/src/ilasm/ilasmpch.h @@ -24,4 +24,7 @@ #include "openum.h" // for CEE_* #include // for vararg macros +#include "mdfileformat.h" +#include "stgpooli.h" + #endif diff --git a/src/coreclr/src/ilasm/main.cpp b/src/coreclr/src/ilasm/main.cpp index 188733f5829cb7..3257323446d77f 100644 --- a/src/coreclr/src/ilasm/main.cpp +++ b/src/coreclr/src/ilasm/main.cpp @@ -9,7 +9,7 @@ #include "ilasmpch.h" #include "asmparse.h" -#include "ndpversion.h" +#include "clrversion.h" #include "shimload.h" #include "strsafe.h" @@ -149,7 +149,7 @@ extern "C" int _cdecl wmain(int argc, __in WCHAR **argv) #pragma warning(pop) #endif { - printf("\nMicrosoft (R) .NET Framework IL Assembler version " VER_FILEVERSION_STR); + printf("\nMicrosoft (R) .NET IL Assembler version " CLR_PRODUCT_VERSION); printf("\n%S\n\n", VER_LEGALCOPYRIGHT_LOGO_STR_L); goto PrintUsageAndExit; @@ -643,7 +643,7 @@ extern "C" int _cdecl wmain(int argc, __in WCHAR **argv) //====================================================================== if(bLogo) { - printf("\nMicrosoft (R) .NET Framework IL Assembler. Version " VER_FILEVERSION_STR); + printf("\nMicrosoft (R) .NET IL Assembler. Version " CLR_PRODUCT_VERSION); printf("\n%S", VER_LEGALCOPYRIGHT_LOGO_STR_L); } diff --git a/src/coreclr/src/ildasm/dasm.cpp b/src/coreclr/src/ildasm/dasm.cpp index 667857ea1b5d54..2a46f33548fefa 100644 --- a/src/coreclr/src/ildasm/dasm.cpp +++ b/src/coreclr/src/ildasm/dasm.cpp @@ -23,7 +23,7 @@ //#define MAX_FILENAME_LENGTH 2048 //moved to dis.h #include -#include +#include // Disable the "initialization of static local vars is no thread safe" error #ifdef _MSC_VER @@ -40,6 +40,9 @@ DECLARE_NATIVE_STRING_RESOURCE_TABLE(NATIVE_STRING_RESOURCE_NAME); #endif +#include "mdfileformat.h" + + struct MIDescriptor { mdToken tkClass; // defining class token @@ -6955,7 +6958,7 @@ void DumpPreamble() else if(g_fDumpRTF) { } - sprintf_s(szString,SZSTRING_SIZE,"// Microsoft (R) .NET Framework IL Disassembler. Version " VER_FILEVERSION_STR); + sprintf_s(szString,SZSTRING_SIZE,"// Microsoft (R) .NET IL Disassembler. Version " CLR_PRODUCT_VERSION); printLine(g_pFile,COMMENT(szString)); if(g_fDumpHTML) { diff --git a/src/coreclr/src/ildasm/dasm_mi.cpp b/src/coreclr/src/ildasm/dasm_mi.cpp index f345b19a28b957..38fee079cfe25a 100644 --- a/src/coreclr/src/ildasm/dasm_mi.cpp +++ b/src/coreclr/src/ildasm/dasm_mi.cpp @@ -4,5 +4,8 @@ #include "ildasmpch.h" +#include "mdfileformat.h" + + #include "../tools/metainfo/mdinfo.cpp" #include "../tools/metainfo/mdobj.cpp" diff --git a/src/coreclr/src/ildasm/exe/CMakeLists.txt b/src/coreclr/src/ildasm/exe/CMakeLists.txt index 7ce367ee048971..87a0fa01f820fb 100644 --- a/src/coreclr/src/ildasm/exe/CMakeLists.txt +++ b/src/coreclr/src/ildasm/exe/CMakeLists.txt @@ -47,7 +47,7 @@ if (CLR_CMAKE_TARGET_WIN32) list(APPEND ILDASM_SOURCES ${ILDASM_HEADERS}) endif(CLR_CMAKE_TARGET_WIN32) -if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) +if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) # This option is necessary to ensure that the overloaded delete operator defined inside # of the utilcode will be used instead of the standard library delete operator. set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Xlinker -Bsymbolic") @@ -56,7 +56,7 @@ if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) # ensure proper resolving of circular references between a subset of the libraries. set(START_LIBRARY_GROUP -Wl,--start-group) set(END_LIBRARY_GROUP -Wl,--end-group) -endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) +endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) _add_executable(ildasm ${ILDASM_SOURCES} diff --git a/src/coreclr/src/ildasm/ildasmpch.h b/src/coreclr/src/ildasm/ildasmpch.h index ff939ede748c5f..071bedbcb2c76a 100644 --- a/src/coreclr/src/ildasm/ildasmpch.h +++ b/src/coreclr/src/ildasm/ildasmpch.h @@ -22,4 +22,8 @@ #include #include +#ifndef Debug_ReportError +#define Debug_ReportError(strMessage) +#endif + #endif diff --git a/src/coreclr/src/ildasm/util.hpp b/src/coreclr/src/ildasm/util.hpp index 8ad5bc4b3bad5c..c5c4c44a55dac3 100644 --- a/src/coreclr/src/ildasm/util.hpp +++ b/src/coreclr/src/ildasm/util.hpp @@ -13,7 +13,6 @@ #if defined(_DEBUG) #include -#undef _ASSERTE // utilcode defines a custom _ASSERTE #endif #include "utilcode.h" diff --git a/src/coreclr/src/ildasm/windasm.cpp b/src/coreclr/src/ildasm/windasm.cpp index 21062b2daf1adb..41a7a67bed2791 100644 --- a/src/coreclr/src/ildasm/windasm.cpp +++ b/src/coreclr/src/ildasm/windasm.cpp @@ -15,7 +15,7 @@ #include "dasmenum.hpp" #include "dis.h" -#include +#include #include "resource.h" #include "new.hpp" @@ -97,7 +97,7 @@ FILE* OpenOutput(__in __nullterminated const char* szFileName); void PrintLogo() { - printf("Microsoft (R) .NET Framework IL Disassembler. Version " VER_FILEVERSION_STR); + printf("Microsoft (R) .NET IL Disassembler. Version " CLR_PRODUCT_VERSION); printf("\n%S\n\n", VER_LEGALCOPYRIGHT_LOGO_STR_L); } diff --git a/src/coreclr/src/inc/CrstTypes.def b/src/coreclr/src/inc/CrstTypes.def index 06f900a79be900..1cd949cbe97ff2 100644 --- a/src/coreclr/src/inc/CrstTypes.def +++ b/src/coreclr/src/inc/CrstTypes.def @@ -283,9 +283,6 @@ Crst GCCover AcquiredBefore LoaderHeap CodeVersioning End -Crst GCMemoryPressure -End - Crst GlobalStrLiteralMap AcquiredBefore HandleTable IbcProfile SyncBlockCache SystemDomainDelayedUnloadList ThreadStore UniqueStack End diff --git a/src/coreclr/src/inc/MSCOREE.IDL b/src/coreclr/src/inc/MSCOREE.IDL index 8a19345f86c163..6c2c5122bc8360 100644 --- a/src/coreclr/src/inc/MSCOREE.IDL +++ b/src/coreclr/src/inc/MSCOREE.IDL @@ -129,61 +129,6 @@ typedef struct _BucketParameters WCHAR pszParams[BucketParamsCount][BucketParamLength]; // Parameter strings. } BucketParameters; - -typedef enum -{ - OPR_ThreadAbort, - OPR_ThreadRudeAbortInNonCriticalRegion, - OPR_ThreadRudeAbortInCriticalRegion, - OPR_AppDomainUnload, - OPR_AppDomainRudeUnload, - OPR_ProcessExit, - OPR_FinalizerRun, - MaxClrOperation - // Do not add anything after this -} EClrOperation; - -typedef enum -{ - FAIL_NonCriticalResource, - FAIL_CriticalResource, - FAIL_FatalRuntime, - FAIL_OrphanedLock, - FAIL_StackOverflow, - // In CoreCLR, we will treat AV specially, based upon the escalation policy. - // Currently only used in CoreCLR. - FAIL_AccessViolation, - FAIL_CodeContract, - MaxClrFailure - // Do not add anything after this -} EClrFailure; - -typedef enum -{ - eRuntimeDeterminedPolicy, // default - eHostDeterminedPolicy, // revert back to Everett behavior, i.e. swallow all exception -} EClrUnhandledException; - -typedef enum -{ - // !!! Please keep these ordered by severity - // !!! If you don't, you need to change EEPolicy::IsValidActionForOperation - // !!! and EEPolicy::IsValidActionForFailure - eNoAction, - eThrowException, - eAbortThread, - eRudeAbortThread, - eUnloadAppDomain, - eRudeUnloadAppDomain, - eExitProcess, - // Look at CorHost2::Stop. For eFastExitProcess, eRudeExitProcess, eDisableRuntime, - // Stop bypasses finalizer run. - eFastExitProcess, - eRudeExitProcess, - MaxPolicyAction -} EPolicyAction; - - //***************************************************************************** // New interface for hosting mscoree //***************************************************************************** diff --git a/src/coreclr/src/inc/appxutil.h b/src/coreclr/src/inc/appxutil.h index c5fce6967eed7c..644d3b9fce04ac 100644 --- a/src/coreclr/src/inc/appxutil.h +++ b/src/coreclr/src/inc/appxutil.h @@ -14,8 +14,6 @@ //--------------------------------------------------------------------------------------------- // Forward declarations -template -class NewArrayHolder; BOOL WinRTSupported(); diff --git a/src/coreclr/src/inc/bundle.h b/src/coreclr/src/inc/bundle.h new file mode 100644 index 00000000000000..00fc186ab9ff0c --- /dev/null +++ b/src/coreclr/src/inc/bundle.h @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/***************************************************************************** + ** ** + ** bundle.h - Information about applications bundled as a single-file ** + ** ** + *****************************************************************************/ + +#ifndef _BUNDLE_H_ +#define _BUNDLE_H_ + +#include + +class Bundle; + +struct BundleFileLocation +{ + INT64 Size; + INT64 Offset; + + BundleFileLocation() + { + LIMITED_METHOD_CONTRACT; + + Size = 0; + Offset = 0; + } + + static BundleFileLocation Invalid() { LIMITED_METHOD_CONTRACT; return BundleFileLocation(); } + + const SString &Path() const; + + bool IsValid() const { LIMITED_METHOD_CONTRACT; return Offset != 0; } +}; + +typedef bool(__stdcall BundleProbe)(LPCWSTR, INT64*, INT64*); + +class Bundle +{ +public: + Bundle(LPCWSTR bundlePath, BundleProbe *probe); + BundleFileLocation Probe(LPCWSTR path, bool pathIsBundleRelative = false) const; + + const SString &Path() const { LIMITED_METHOD_CONTRACT; return m_path; } + const SString &BasePath() const { LIMITED_METHOD_CONTRACT; return m_basePath; } + + static Bundle* AppBundle; // The BundleInfo for the current app, initialized by coreclr_initialize. + static bool AppIsBundle() { LIMITED_METHOD_CONTRACT; return AppBundle != nullptr; } + static BundleFileLocation ProbeAppBundle(LPCWSTR path, bool pathIsBundleRelative = false); + +private: + + SString m_path; // The path to single-file executable + BundleProbe *m_probe; + + SString m_basePath; // The prefix to denote a path within the bundle +}; + +#endif // _BUNDLE_H_ +// EOF ======================================================================= diff --git a/src/coreclr/src/inc/clrconfig.h b/src/coreclr/src/inc/clrconfig.h index 4f0cb11978dd47..42d8a24efd8c2e 100644 --- a/src/coreclr/src/inc/clrconfig.h +++ b/src/coreclr/src/inc/clrconfig.h @@ -46,10 +46,6 @@ class CLRConfig IgnoreHKLM = 0x4, // If set, don't look in HKCU in the registry. IgnoreHKCU = 0x8, - // If set, don't look in any config files - IgnoreConfigFiles = 0x10, - // If set, look in config file(s) before looking in env/registry. - FavorConfigFile = 0x20, // If set, look only in the system config file, ignoring other config files. // (This option does not affect environment variable and registry lookups) ConfigFile_SystemOnly = 0x40, @@ -60,8 +56,6 @@ class CLRConfig // *string* configuration values.) TrimWhiteSpaceFromStringValue = 0x100, - // Legacy REGUTIL-style lookup. - REGUTIL_default = IgnoreConfigFiles, // Legacy EEConfig-style lookup. EEConfig_default = 0, }; diff --git a/src/coreclr/src/inc/clrconfigvalues.h b/src/coreclr/src/inc/clrconfigvalues.h index df0d44af48e927..109c3c83553011 100644 --- a/src/coreclr/src/inc/clrconfigvalues.h +++ b/src/coreclr/src/inc/clrconfigvalues.h @@ -123,104 +123,104 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_JitPitchMaxVal, W("JitPitchMaxVal"), (DWORD)0x /// /// Assembly Loader /// -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_DesignerNamespaceResolutionEnabled, W("designerNamespaceResolution"), FALSE, "Set it to 1 to enable DesignerNamespaceResolve event for WinRT types", CLRConfig::IgnoreEnv | CLRConfig::IgnoreHKLM | CLRConfig::IgnoreHKCU | CLRConfig::FavorConfigFile) -CONFIG_DWORD_INFO_EX(INTERNAL_GetAssemblyIfLoadedIgnoreRidMap, W("GetAssemblyIfLoadedIgnoreRidMap"), 0, "Used to force loader to ignore assemblies cached in the rid-map", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_DesignerNamespaceResolutionEnabled, W("designerNamespaceResolution"), FALSE, "Set it to 1 to enable DesignerNamespaceResolve event for WinRT types", CLRConfig::IgnoreEnv | CLRConfig::IgnoreHKLM | CLRConfig::IgnoreHKCU) +CONFIG_DWORD_INFO_EX(INTERNAL_GetAssemblyIfLoadedIgnoreRidMap, W("GetAssemblyIfLoadedIgnoreRidMap"), 0, "Used to force loader to ignore assemblies cached in the rid-map", CLRConfig::EEConfig_default) /// /// Conditional breakpoints /// -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_BreakOnBadExit, W("BreakOnBadExit"), 0, "", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_BreakOnBadExit, W("BreakOnBadExit"), 0, "", CLRConfig::EEConfig_default) CONFIG_STRING_INFO(INTERNAL_BreakOnClassBuild, W("BreakOnClassBuild"), "Very useful for debugging class layout code.") CONFIG_STRING_INFO(INTERNAL_BreakOnClassLoad, W("BreakOnClassLoad"), "Very useful for debugging class loading code.") CONFIG_STRING_INFO(INTERNAL_BreakOnComToClrNativeInfoInit, W("BreakOnComToClrNativeInfoInit"), "Throws an assert when native information about a COM -> CLR call are about to be gathered.") -CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnDebugBreak, W("BreakOnDebugBreak"), 0, "Allows an assert in debug builds when a user break is hit", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnDILoad, W("BreakOnDILoad"), 0, "Allows an assert when the DI is loaded", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnDumpToken, W("BreakOnDumpToken"), 0xffffffff, "Breaks when using internal logging on a particular token value.", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_BreakOnEELoad, W("BreakOnEELoad"), 0, "", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnDebugBreak, W("BreakOnDebugBreak"), 0, "Allows an assert in debug builds when a user break is hit", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnDILoad, W("BreakOnDILoad"), 0, "Allows an assert when the DI is loaded", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnDumpToken, W("BreakOnDumpToken"), 0xffffffff, "Breaks when using internal logging on a particular token value.", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_BreakOnEELoad, W("BreakOnEELoad"), 0, "", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO(INTERNAL_BreakOnEEShutdown, W("BreakOnEEShutdown"), 0, "") -CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnExceptionInGetThrowable, W("BreakOnExceptionInGetThrowable"), 0, "", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnExceptionInGetThrowable, W("BreakOnExceptionInGetThrowable"), 0, "", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO(INTERNAL_BreakOnFindMethod, W("BreakOnFindMethod"), 0, "Breaks in findMethodInternal when it searches for the specified token.") -CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnFirstPass, W("BreakOnFirstPass"), 0, "", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnHR, W("BreakOnHR"), 0, "Debug.cpp, IfFailxxx use this macro to stop if hr matches ", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnFirstPass, W("BreakOnFirstPass"), 0, "", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnHR, W("BreakOnHR"), 0, "Debug.cpp, IfFailxxx use this macro to stop if hr matches ", CLRConfig::EEConfig_default) CONFIG_STRING_INFO(INTERNAL_BreakOnInstantiation, W("BreakOnInstantiation"), "Very useful for debugging generic class instantiation.") CONFIG_STRING_INFO(INTERNAL_BreakOnInteropStubSetup, W("BreakOnInteropStubSetup"), "Throws an assert when marshaling stub for the given method is about to be built.") -CONFIG_STRING_INFO_EX(INTERNAL_BreakOnInteropVTableBuild, W("BreakOnInteropVTableBuild"), "Specifies a type name for which an assert should be thrown when building interop v-table.", CLRConfig::REGUTIL_default) +CONFIG_STRING_INFO_EX(INTERNAL_BreakOnInteropVTableBuild, W("BreakOnInteropVTableBuild"), "Specifies a type name for which an assert should be thrown when building interop v-table.", CLRConfig::EEConfig_default) CONFIG_STRING_INFO(INTERNAL_BreakOnMethodName, W("BreakOnMethodName"), "Very useful for debugging method override placement code.") -CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnNotify, W("BreakOnNotify"), 0, "", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnRetailAssert, W("BreakOnRetailAssert"), 0, "Used for debugging \"retail\" asserts (fatal errors)", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnSecondPass, W("BreakOnSecondPass"), 0, "", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_BreakOnSO, W("BreakOnSO"), 0, "", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnNotify, W("BreakOnNotify"), 0, "", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnRetailAssert, W("BreakOnRetailAssert"), 0, "Used for debugging \"retail\" asserts (fatal errors)", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnSecondPass, W("BreakOnSecondPass"), 0, "", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_BreakOnSO, W("BreakOnSO"), 0, "", CLRConfig::EEConfig_default) CONFIG_STRING_INFO(INTERNAL_BreakOnStructMarshalSetup, W("BreakOnStructMarshalSetup"), "Throws an assert when field marshalers for the given type with layout are about to be created.") -CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnUEF, W("BreakOnUEF"), 0, "", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnUncaughtException, W("BreakOnUncaughtException"), 0, "", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnUEF, W("BreakOnUEF"), 0, "", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_BreakOnUncaughtException, W("BreakOnUncaughtException"), 0, "", CLRConfig::EEConfig_default) /// /// Debugger /// -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_EnableDiagnostics, W("EnableDiagnostics"), 1, "Allows the debugger, profiler, and EventPipe diagnostics to be disabled", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_D__FCE, W("D::FCE"), 0, "Allows an assert when crawling the managed stack for an exception handler", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakIfLocksUnavailable, W("DbgBreakIfLocksUnavailable"), 0, "Allows an assert when the debugger can't take a lock ", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnErr, W("DbgBreakOnErr"), 0, "Allows an assert when we get a failing hresult", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnMapPatchToDJI, W("DbgBreakOnMapPatchToDJI"), 0, "Allows an assert when mapping a patch to an address", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnRawInt3, W("DbgBreakOnRawInt3"), 0, "Allows an assert for test coverage for debug break or other int3 breaks", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnSendBreakpoint, W("DbgBreakOnSendBreakpoint"), 0, "Allows an assert when sending a breakpoint to the right side", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnSetIP, W("DbgBreakOnSetIP"), 0, "Allows an assert when setting the IP", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgCheckInt3, W("DbgCheckInt3"), 0, "Asserts if the debugger explicitly writes int3 instead of calling SetUnmanagedBreakpoint", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_EnableDiagnostics, W("EnableDiagnostics"), 1, "Allows the debugger, profiler, and EventPipe diagnostics to be disabled", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_D__FCE, W("D::FCE"), 0, "Allows an assert when crawling the managed stack for an exception handler", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakIfLocksUnavailable, W("DbgBreakIfLocksUnavailable"), 0, "Allows an assert when the debugger can't take a lock ", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnErr, W("DbgBreakOnErr"), 0, "Allows an assert when we get a failing hresult", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnMapPatchToDJI, W("DbgBreakOnMapPatchToDJI"), 0, "Allows an assert when mapping a patch to an address", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnRawInt3, W("DbgBreakOnRawInt3"), 0, "Allows an assert for test coverage for debug break or other int3 breaks", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnSendBreakpoint, W("DbgBreakOnSendBreakpoint"), 0, "Allows an assert when sending a breakpoint to the right side", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgBreakOnSetIP, W("DbgBreakOnSetIP"), 0, "Allows an assert when setting the IP", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgCheckInt3, W("DbgCheckInt3"), 0, "Asserts if the debugger explicitly writes int3 instead of calling SetUnmanagedBreakpoint", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_DbgDACAssertOnMismatch, W("DbgDACAssertOnMismatch"), "Allows an assert when the mscordacwks and mscorwks dll versions don't match") -CONFIG_DWORD_INFO_EX(INTERNAL_DbgDACEnableAssert, W("DbgDACEnableAssert"), 0, "Enables extra validity checking in DAC - assumes target isn't corrupt", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_DbgDACSkipVerifyDlls, W("DbgDACSkipVerifyDlls"), 0, "Allows disabling the check to ensure mscordacwks and mscorwks dll versions match", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgDelayHelper, W("DbgDelayHelper"), 0, "Varies the wait in the helper thread startup for testing race between threads", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_DbgDisableDynamicSymsCompat, W("DbgDisableDynamicSymsCompat"), 0, "", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgDisableTargetConsistencyAsserts, W("DbgDisableTargetConsistencyAsserts"), 0, "Allows explicitly testing with corrupt targets", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_DbgEnableMixedModeDebugging, W("DbgEnableMixedModeDebuggingInternalOnly"), 0, "", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgExtraThreads, W("DbgExtraThreads"), 0, "Allows extra unmanaged threads to run and throw debug events for stress testing", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgExtraThreadsCantStop, W("DbgExtraThreadsCantStop"), 0, "Allows extra unmanaged threads in can't stop region to run and throw debug events for stress testing", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgExtraThreadsIB, W("DbgExtraThreadsIB"), 0, "Allows extra in-band unmanaged threads to run and throw debug events for stress testing", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgExtraThreadsOOB, W("DbgExtraThreadsOOB"), 0, "Allows extra out of band unmanaged threads to run and throw debug events for stress testing", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgFaultInHandleIPCEvent, W("DbgFaultInHandleIPCEvent"), 0, "Allows testing the unhandled event filter", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgInjectFEE, W("DbgInjectFEE"), 0, "Allows injecting a fatal execution error for testing Watson", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgLeakCheck, W("DbgLeakCheck"), 0, "Allows checking for leaked Cordb objects", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgNo2ndChance, W("DbgNo2ndChance"), 0, "Allows breaking on (and catching bogus) 2nd chance exceptions", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgNoDebugger, W("DbgNoDebugger"), 0, "Allows breaking if we don't want to lazily initialize the debugger", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DbgNoForceContinue, W("DbgNoForceContinue"), 1, "Used to force a continue on longhorn", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgNoOpenMDByFile, W("DbgNoOpenMDByFile"), 0, "Allows opening MD by memory for perf testing", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgDACEnableAssert, W("DbgDACEnableAssert"), 0, "Enables extra validity checking in DAC - assumes target isn't corrupt", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_DbgDACSkipVerifyDlls, W("DbgDACSkipVerifyDlls"), 0, "Allows disabling the check to ensure mscordacwks and mscorwks dll versions match", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgDelayHelper, W("DbgDelayHelper"), 0, "Varies the wait in the helper thread startup for testing race between threads", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_DbgDisableDynamicSymsCompat, W("DbgDisableDynamicSymsCompat"), 0, "", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgDisableTargetConsistencyAsserts, W("DbgDisableTargetConsistencyAsserts"), 0, "Allows explicitly testing with corrupt targets", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_DbgEnableMixedModeDebugging, W("DbgEnableMixedModeDebuggingInternalOnly"), 0, "", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgExtraThreads, W("DbgExtraThreads"), 0, "Allows extra unmanaged threads to run and throw debug events for stress testing", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgExtraThreadsCantStop, W("DbgExtraThreadsCantStop"), 0, "Allows extra unmanaged threads in can't stop region to run and throw debug events for stress testing", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgExtraThreadsIB, W("DbgExtraThreadsIB"), 0, "Allows extra in-band unmanaged threads to run and throw debug events for stress testing", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgExtraThreadsOOB, W("DbgExtraThreadsOOB"), 0, "Allows extra out of band unmanaged threads to run and throw debug events for stress testing", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgFaultInHandleIPCEvent, W("DbgFaultInHandleIPCEvent"), 0, "Allows testing the unhandled event filter", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgInjectFEE, W("DbgInjectFEE"), 0, "Allows injecting a fatal execution error for testing Watson", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgLeakCheck, W("DbgLeakCheck"), 0, "Allows checking for leaked Cordb objects", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgNo2ndChance, W("DbgNo2ndChance"), 0, "Allows breaking on (and catching bogus) 2nd chance exceptions", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgNoDebugger, W("DbgNoDebugger"), 0, "Allows breaking if we don't want to lazily initialize the debugger", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DbgNoForceContinue, W("DbgNoForceContinue"), 1, "Used to force a continue on longhorn", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgNoOpenMDByFile, W("DbgNoOpenMDByFile"), 0, "Allows opening MD by memory for perf testing", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO(INTERNAL_DbgOOBinFEEE, W("DbgOOBinFEEE"), 0, "Allows forcing oob breakpoints when a fatal error occurs") RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(EXTERNAL_DbgPackShimPath, W("DbgPackShimPath"), "CoreCLR path to dbgshim.dll - we are trying to figure out if we can remove this") -CONFIG_DWORD_INFO_EX(INTERNAL_DbgPingInterop, W("DbgPingInterop"), 0, "Allows checking for deadlocks in interop debugging", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgRace, W("DbgRace"), 0, "Allows pausing for native debug events to get hijicked", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DbgRedirect, W("DbgRedirect"), 0, "Allows for redirecting the event pipeline", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgPingInterop, W("DbgPingInterop"), 0, "Allows checking for deadlocks in interop debugging", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgRace, W("DbgRace"), 0, "Allows pausing for native debug events to get hijicked", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DbgRedirect, W("DbgRedirect"), 0, "Allows for redirecting the event pipeline", CLRConfig::EEConfig_default) RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(EXTERNAL_DbgRedirectApplication, W("DbgRedirectApplication"), "Specifies the auxiliary debugger application to launch.") RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(EXTERNAL_DbgRedirectAttachCmd, W("DbgRedirectAttachCmd"), "Specifies command parameters for attaching the auxiliary debugger.") RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(EXTERNAL_DbgRedirectCommonCmd, W("DbgRedirectCommonCmd"), "Specifies a command line format string for the auxiliary debugger.") RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(EXTERNAL_DbgRedirectCreateCmd, W("DbgRedirectCreateCmd"), "Specifies command parameters when creating the auxiliary debugger.") -CONFIG_DWORD_INFO_EX(INTERNAL_DbgShortcutCanary, W("DbgShortcutCanary"), 0, "Allows a way to force canary to fail to be able to test failure paths", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgSkipMEOnStep, W("DbgSkipMEOnStep"), 0, "Turns off MethodEnter checks", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgSkipVerCheck, W("DbgSkipVerCheck"), 0, "Allows different RS and LS versions (for servicing work)", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgTC, W("DbgTC"), 0, "Allows checking boundary compression for offset mappings", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgTransportFaultInject, W("DbgTransportFaultInject"), 0, "Allows injecting a fault for testing the debug transport", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgShortcutCanary, W("DbgShortcutCanary"), 0, "Allows a way to force canary to fail to be able to test failure paths", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgSkipMEOnStep, W("DbgSkipMEOnStep"), 0, "Turns off MethodEnter checks", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgSkipVerCheck, W("DbgSkipVerCheck"), 0, "Allows different RS and LS versions (for servicing work)", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgTC, W("DbgTC"), 0, "Allows checking boundary compression for offset mappings", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgTransportFaultInject, W("DbgTransportFaultInject"), 0, "Allows injecting a fault for testing the debug transport", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_DbgTransportLog, W("DbgTransportLog"), "Turns on logging for the debug transport") CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_DbgTransportLogClass, W("DbgTransportLogClass"), "Mask to control what is logged in DbgTransportLog") -RETAIL_CONFIG_STRING_INFO_EX(UNSUPPORTED_DbgTransportProxyAddress, W("DbgTransportProxyAddress"), "Allows specifying the transport proxy address", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgTrapOnSkip, W("DbgTrapOnSkip"), 0, "Allows breaking when we skip a breakpoint", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DbgWaitTimeout, W("DbgWaitTimeout"), 1, "Specifies the timeout value for waits", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DbgWFDETimeout, W("DbgWFDETimeout"), 25, "Specifies the timeout value for wait when waiting for a debug event", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_RaiseExceptionOnAssert, W("RaiseExceptionOnAssert"), 0, "Raise a first chance (if set to 1) or second chance (if set to 2) exception on asserts.", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DebugBreakOnAssert, W("DebugBreakOnAssert"), 0, "If DACCESS_COMPILE is defined, break on asserts.", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_DebugBreakOnVerificationFailure, W("DebugBreakOnVerificationFailure"), 0, "Halts the jit on verification failure", CLRConfig::REGUTIL_default) -CONFIG_STRING_INFO_EX(INTERNAL_DebuggerBreakPoint, W("DebuggerBreakPoint"), "Allows counting various debug events", CLRConfig::REGUTIL_default) -CONFIG_STRING_INFO_EX(INTERNAL_DebugVerify, W("DebugVerify"), "Control for tracing in peverify", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_STRING_INFO_EX(UNSUPPORTED_DbgTransportProxyAddress, W("DbgTransportProxyAddress"), "Allows specifying the transport proxy address", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgTrapOnSkip, W("DbgTrapOnSkip"), 0, "Allows breaking when we skip a breakpoint", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgWaitTimeout, W("DbgWaitTimeout"), 1, "Specifies the timeout value for waits", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DbgWFDETimeout, W("DbgWFDETimeout"), 25, "Specifies the timeout value for wait when waiting for a debug event", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_RaiseExceptionOnAssert, W("RaiseExceptionOnAssert"), 0, "Raise a first chance (if set to 1) or second chance (if set to 2) exception on asserts.", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DebugBreakOnAssert, W("DebugBreakOnAssert"), 0, "If DACCESS_COMPILE is defined, break on asserts.", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DebugBreakOnVerificationFailure, W("DebugBreakOnVerificationFailure"), 0, "Halts the jit on verification failure", CLRConfig::EEConfig_default) +CONFIG_STRING_INFO_EX(INTERNAL_DebuggerBreakPoint, W("DebuggerBreakPoint"), "Allows counting various debug events", CLRConfig::EEConfig_default) +CONFIG_STRING_INFO_EX(INTERNAL_DebugVerify, W("DebugVerify"), "Control for tracing in peverify", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO(INTERNAL_EncApplyChanges, W("EncApplyChanges"), 0, "Allows breaking when ApplyEditAndContinue is called") -CONFIG_DWORD_INFO_EX(INTERNAL_EnCBreakOnRemapComplete, W("EnCBreakOnRemapComplete"), 0, "Allows breaking after N RemapCompletes", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_EnCBreakOnRemapOpportunity, W("EnCBreakOnRemapOpportunity"), 0, "Allows breaking after N RemapOpportunities", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_EnCBreakOnRemapComplete, W("EnCBreakOnRemapComplete"), 0, "Allows breaking after N RemapCompletes", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_EnCBreakOnRemapOpportunity, W("EnCBreakOnRemapOpportunity"), 0, "Allows breaking after N RemapOpportunities", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO(INTERNAL_EncDumpApplyChanges, W("EncDumpApplyChanges"), 0, "Allows dumping edits in delta metadata and il files") CONFIG_DWORD_INFO(INTERNAL_EncFixupFieldBreak, W("EncFixupFieldBreak"), 0, "Unlikely that this is used anymore.") CONFIG_DWORD_INFO(INTERNAL_EncJitUpdatedFunction, W("EncJitUpdatedFunction"), 0, "Allows breaking when an updated function is jitted") CONFIG_DWORD_INFO(INTERNAL_EnCResolveField, W("EnCResolveField"), 0, "Allows breaking when computing the address of an EnC-added field") CONFIG_DWORD_INFO(INTERNAL_EncResumeInUpdatedFunction, W("EncResumeInUpdatedFunction"), 0, "Allows breaking when execution resumes in a new EnC version of a function") -CONFIG_DWORD_INFO_EX(INTERNAL_DbgAssertOnDebuggeeDebugBreak, W("DbgAssertOnDebuggeeDebugBreak"), 0, "If non-zero causes the managed-only debugger to assert on unhandled breakpoints in the debuggee", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgAssertOnDebuggeeDebugBreak, W("DbgAssertOnDebuggeeDebugBreak"), 0, "If non-zero causes the managed-only debugger to assert on unhandled breakpoints in the debuggee", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_DbgDontResumeThreadsOnUnhandledException, W("UNSUPPORTED_DbgDontResumeThreadsOnUnhandledException"), 0, "If non-zero, then don't try to unsuspend threads after continuing a 2nd-chance native exception") -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DbgSkipStackCheck, W("DbgSkipStackCheck"), 0, "Skip the stack pointer check during stackwalking", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DbgSkipStackCheck, W("DbgSkipStackCheck"), 0, "Skip the stack pointer check during stackwalking", CLRConfig::EEConfig_default) #ifdef DACCESS_COMPILE CONFIG_DWORD_INFO(INTERNAL_DumpGeneration_IntentionallyCorruptDataFromTarget, W("IntentionallyCorruptDataFromTarget"), 0, "Intentionally fakes bad data retrieved from target to try and break dump generation.") #endif @@ -231,17 +231,17 @@ CONFIG_DWORD_INFO(UNSUPPORTED_Debugging_RequiredVersion, W("UNSUPPORTED_Debuggin RETAIL_CONFIG_DWORD_INFO(INTERNAL_MiniMdBufferCapacity, W("MiniMdBufferCapacity"), 64 * 1024, "The max size of the buffer to store mini metadata information for triage- and mini-dumps.") #endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS -CONFIG_DWORD_INFO_EX(INTERNAL_DbgNativeCodeBpBindsAcrossVersions, W("DbgNativeCodeBpBindsAcrossVersions"), 0, "If non-zero causes native breakpoints at offset 0 to bind in all tiered compilation versions of the given method", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_DbgNativeCodeBpBindsAcrossVersions, W("DbgNativeCodeBpBindsAcrossVersions"), 0, "If non-zero causes native breakpoints at offset 0 to bind in all tiered compilation versions of the given method", CLRConfig::EEConfig_default) /// /// Diagnostics (internal general-purpose) /// CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_ConditionalContracts, W("ConditionalContracts"), "If ENABLE_CONTRACTS_IMPL is defined, sets whether contracts are conditional. (?)") CONFIG_DWORD_INFO(INTERNAL_ConsistencyCheck, W("ConsistencyCheck"), 0, "") -CONFIG_DWORD_INFO_EX(INTERNAL_ContinueOnAssert, W("ContinueOnAssert"), 0, "If set, doesn't break on asserts.", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_disableStackOverflowProbing, W("disableStackOverflowProbing"), 0, "", CLRConfig::FavorConfigFile) +CONFIG_DWORD_INFO_EX(INTERNAL_ContinueOnAssert, W("ContinueOnAssert"), 0, "If set, doesn't break on asserts.", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_disableStackOverflowProbing, W("disableStackOverflowProbing"), 0, "", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_InjectFatalError, W("InjectFatalError"), "") -CONFIG_DWORD_INFO_EX(INTERNAL_InjectFault, W("InjectFault"), 0, "", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_InjectFault, W("InjectFault"), 0, "", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SuppressChecks, W("SuppressChecks"), "") #ifdef FEATURE_EH_FUNCLETS CONFIG_DWORD_INFO(INTERNAL_SuppressLockViolationsOnReentryFromOS, W("SuppressLockViolationsOnReentryFromOS"), 0, "64 bit OOM tests re-enter the CLR via RtlVirtualUnwind. This indicates whether to suppress resulting locking violations.") @@ -251,11 +251,10 @@ CONFIG_DWORD_INFO(INTERNAL_SuppressLockViolationsOnReentryFromOS, W("SuppressLoc /// Exception Handling /// CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_AssertOnFailFast, W("AssertOnFailFast"), "") -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_legacyCorruptedStateExceptionsPolicy, W("legacyCorruptedStateExceptionsPolicy"), 0, "Enabled Pre-V4 CSE behavior", CLRConfig::FavorConfigFile) -CONFIG_DWORD_INFO_EX(INTERNAL_SuppressLostExceptionTypeAssert, W("SuppressLostExceptionTypeAssert"), 0, "", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_FailFastOnCorruptedStateException, W("FailFastOnCorruptedStateException"), 0, "Failfast if a CSE is encountered", CLRConfig::FavorConfigFile) -RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_UseEntryPointFilter, W("UseEntryPointFilter"), 0, "", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_Corhost_Swallow_Uncaught_Exceptions, W("Corhost_Swallow_Uncaught_Exceptions"), 0, "", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_legacyCorruptedStateExceptionsPolicy, W("legacyCorruptedStateExceptionsPolicy"), 0, "Enabled Pre-V4 CSE behavior", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_SuppressLostExceptionTypeAssert, W("SuppressLostExceptionTypeAssert"), 0, "", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_UseEntryPointFilter, W("UseEntryPointFilter"), 0, "", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_Corhost_Swallow_Uncaught_Exceptions, W("Corhost_Swallow_Uncaught_Exceptions"), 0, "", CLRConfig::EEConfig_default) /// /// Garbage collector @@ -271,77 +270,49 @@ RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_gcConservative, W("gcConservative"), 0, "En RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_gcServer, W("gcServer"), 0, "Enables server GC") CONFIG_STRING_INFO(INTERNAL_GcCoverage, W("GcCoverage"), "Specify a method or regular expression of method names to run with GCStress") CONFIG_STRING_INFO(INTERNAL_SkipGCCoverage, W("SkipGcCoverage"), "Specify a list of assembly names to skip with GC Coverage") -RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_gcForceCompact, W("gcForceCompact"), "When set to true, always do compacting GC") -RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCgen0size, W("GCgen0size"), "Specifies the smallest gen0 size") -RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCGen0MaxBudget, W("GCGen0MaxBudget"), "Specifies the largest gen0 allocation budget") RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_StatsUpdatePeriod, W("StatsUpdatePeriod"), 60, "Specifies the interval, in seconds, at which to update the statistics") -RETAIL_CONFIG_STRING_INFO(UNSUPPORTED_SuspendTimeLog, W("SuspendTimeLog"), "Specifies the name of the log file for suspension statistics") -CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_GCLatencyMode, W("GCLatencyMode"), "Specifies the GC latency mode - batch, interactive or low latency (note that the same thing can be specified via API which is the supported way)") -RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCLatencyLevel, W("GCLatencyLevel"), 1, "Specifies the GC latency level that you want to optimize for") -RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCConfigLogEnabled, W("GCConfigLogEnabled"), 0, "Specifies if you want to turn on config logging in GC") -RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCLogEnabled, W("GCLogEnabled"), 0, "Specifies if you want to turn on logging in GC") -RETAIL_CONFIG_STRING_INFO(UNSUPPORTED_GCLogFile, W("GCLogFile"), "Specifies the name of the GC log file") -RETAIL_CONFIG_STRING_INFO(UNSUPPORTED_GCConfigLogFile, W("GCConfigLogFile"), "Specifies the name of the GC config log file") -RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCLogFileSize, W("GCLogFileSize"), 0, "Specifies the GC log file size") -RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCCompactRatio, W("GCCompactRatio"), 0, "Specifies the ratio compacting GCs vs sweeping ") RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_GCPollType, W("GCPollType"), "") RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCRetainVM, W("GCRetainVM"), 0, "When set we put the segments that should be deleted on a standby list (instead of releasing them back to the OS) which will be considered to satisfy new segment requests (note that the same thing can be specified via API which is the supported way)") -RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCSegmentSize, W("GCSegmentSize"), "Specifies the managed heap segment size") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCLOHThreshold, W("GCLOHThreshold"), 0, "Specifies the size that will make objects go on LOH") -RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCLOHCompact, W("GCLOHCompact"), "Specifies the LOH compaction mode") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_gcAllowVeryLargeObjects, W("gcAllowVeryLargeObjects"), 1, "Allow allocation of 2GB+ objects on GC heap") -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_GCStress, W("GCStress"), 0, "Trigger GCs at regular intervals", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_GcStressOnDirectCalls, W("GcStressOnDirectCalls"), 0, "Whether to trigger a GC on direct calls", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_gcTrimCommitOnLowMemory, W("gcTrimCommitOnLowMemory"), "When set we trim the committed space more aggressively for the ephemeral seg. This is used for running many instances of server processes where they want to keep as little memory committed as possible") -RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_BGCSpinCount, W("BGCSpinCount"), 140, "Specifies the bgc spin count") -RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_BGCSpin, W("BGCSpin"), 2, "Specifies the bgc spin time") +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_GCStress, W("GCStress"), 0, "Trigger GCs at regular intervals", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_GcStressOnDirectCalls, W("GcStressOnDirectCalls"), 0, "Whether to trigger a GC on direct calls", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_HeapVerify, W("HeapVerify"), "When set verifies the integrity of the managed heap on entry and exit of each GC") -RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_SetupGcCoverage, W("SetupGcCoverage"), "This doesn't appear to be a config flag", CLRConfig::REGUTIL_default) RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCNumaAware, W("GCNumaAware"), 1, "Specifies if to enable GC NUMA aware") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCCpuGroup, W("GCCpuGroup"), 0, "Specifies if to enable GC to support CPU groups") -RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCHeapCount, W("GCHeapCount"), 0, "") -RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCNoAffinitize, W("GCNoAffinitize"), 0, "") -// this config is only in effect if the process is not running in multiple CPU groups. -RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_GCHeapAffinitizeMask, W("GCHeapAffinitizeMask"), "Specifies processor mask for Server GC threads") -RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCProvModeStress, W("GCProvModeStress"), 0, "Stress the provisional modes") -RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCHighMemPercent, W("GCHighMemPercent"), 0, "Specifies the percent for GC to consider as high memory") RETAIL_CONFIG_STRING_INFO(EXTERNAL_GCName, W("GCName"), "") -RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_GCHeapHardLimit, W("GCHeapHardLimit"), "Specifies the maximum commit size for the GC heap") -RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_GCHeapHardLimitPercent, W("GCHeapHardLimitPercent"), "Specifies the GC heap usage as a percentage of the total memory") -RETAIL_CONFIG_STRING_INFO(EXTERNAL_GCHeapAffinitizeRanges, W("GCHeapAffinitizeRanges"), "Specifies list of processors for Server GC threads. The format is a comma separated list of processor numbers or ranges of processor numbers. Example: 1,3,5,7-9,12") -RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCLargePages, W("GCLargePages"), 0, "Specifies whether large pages should be used when a heap hard limit is set") /// /// IBC /// -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_ConvertIbcData, W("ConvertIbcData"), 1, "Converts between v1 and v2 IBC data", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_ConvertIbcData, W("ConvertIbcData"), 1, "Converts between v1 and v2 IBC data", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_DisableHotCold, W("DisableHotCold"), "Master hot/cold splitting switch in Jit64") -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DisableIBC, W("DisableIBC"), 0, "Disables the use of IBC data", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_UseIBCFile, W("UseIBCFile"), 0, "", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_DisableIBC, W("DisableIBC"), 0, "Disables the use of IBC data", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_UseIBCFile, W("UseIBCFile"), 0, "", CLRConfig::EEConfig_default) /// /// JIT /// RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_JitAlignLoops, W("JitAlignLoops"), "Aligns loop targets to 8 byte boundaries") -CONFIG_DWORD_INFO_EX(INTERNAL_JitBreakEmit, W("JitBreakEmit"), (DWORD)-1, "", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_JitBreakEmit, W("JitBreakEmit"), (DWORD)-1, "", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_JitDebuggable, W("JitDebuggable"), "") #if !defined(DEBUG) && !defined(_DEBUG) #define INTERNAL_JitEnableNoWayAssert_Default 0 #else #define INTERNAL_JitEnableNoWayAssert_Default 1 #endif -RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_JitEnableNoWayAssert, W("JitEnableNoWayAssert"), INTERNAL_JitEnableNoWayAssert_Default, "", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_JitEnableNoWayAssert, W("JitEnableNoWayAssert"), INTERNAL_JitEnableNoWayAssert_Default, "", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_JitFramed, W("JitFramed"), "Forces EBP frames") -CONFIG_DWORD_INFO_EX(INTERNAL_JitGCStress, W("JitGCStress"), 0, "GC stress mode for jit", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_JitGCStress, W("JitGCStress"), 0, "GC stress mode for jit", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO(INTERNAL_JitHeartbeat, W("JitHeartbeat"), 0, "") CONFIG_DWORD_INFO(INTERNAL_JitHelperLogging, W("JitHelperLogging"), 0, "") RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_JITMinOpts, W("JITMinOpts"), "Forces MinOpts") RETAIL_CONFIG_STRING_INFO(EXTERNAL_JitName, W("JitName"), "Primary Jit to use") #if defined(ALLOW_SXS_JIT) -RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_AltJitName, W("AltJitName"), "Alternative Jit to use, will fall back to primary jit.", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_AltJit, W("AltJit"), "Enables AltJit and selectively limits it to the specified methods.", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_AltJitExcludeAssemblies, W("AltJitExcludeAssemblies"), "Do not use AltJit on this semicolon-delimited list of assemblies.", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_AltJitName, W("AltJitName"), "Alternative Jit to use, will fall back to primary jit.", CLRConfig::EEConfig_default) +RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_AltJit, W("AltJit"), "Enables AltJit and selectively limits it to the specified methods.", CLRConfig::EEConfig_default) +RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_AltJitExcludeAssemblies, W("AltJitExcludeAssemblies"), "Do not use AltJit on this semicolon-delimited list of assemblies.", CLRConfig::EEConfig_default) #endif // defined(ALLOW_SXS_JIT) #if defined(FEATURE_STACK_SAMPLING) @@ -352,21 +323,21 @@ RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_StackSamplingNumMethods, W("StackSamplingNu #endif // defined(FEATURE_JIT_SAMPLING) #if defined(ALLOW_SXS_JIT_NGEN) -RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_AltJitNgen, W("AltJitNgen"), "Enables AltJit for NGEN and selectively limits it to the specified methods.", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_AltJitNgen, W("AltJitNgen"), "Enables AltJit for NGEN and selectively limits it to the specified methods.", CLRConfig::EEConfig_default) #endif // defined(ALLOW_SXS_JIT_NGEN) RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitHostMaxSlabCache, W("JitHostMaxSlabCache"), 0x1000000, "Sets jit host max slab cache size, 16MB default") RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_JitOptimizeType, W("JitOptimizeType"), "") -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_JitPrintInlinedMethods, W("JitPrintInlinedMethods"), 0, "", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_JitPrintInlinedMethods, W("JitPrintInlinedMethods"), 0, "", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitTelemetry, W("JitTelemetry"), 1, "If non-zero, gather JIT telemetry data") RETAIL_CONFIG_STRING_INFO(INTERNAL_JitTimeLogFile, W("JitTimeLogFile"), "If set, gather JIT throughput data and write to this file.") RETAIL_CONFIG_STRING_INFO(INTERNAL_JitTimeLogCsv, W("JitTimeLogCsv"), "If set, gather JIT throughput data and write to a CSV file. This mode must be used in internal retail builds.") RETAIL_CONFIG_STRING_INFO(INTERNAL_JitFuncInfoLogFile, W("JitFuncInfoLogFile"), "If set, gather JIT function info and write to this file.") CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_JitVerificationDisable, W("JitVerificationDisable"), "") RETAIL_CONFIG_DWORD_INFO(INTERNAL_JitLockWrite, W("JitLockWrite"), 0, "Force all volatile writes to be 'locked'") -CONFIG_STRING_INFO_EX(INTERNAL_TailCallMax, W("TailCallMax"), "", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_TailCallOpt, W("TailCallOpt"), "", CLRConfig::REGUTIL_default) +CONFIG_STRING_INFO_EX(INTERNAL_TailCallMax, W("TailCallMax"), "", CLRConfig::EEConfig_default) +RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_TailCallOpt, W("TailCallOpt"), "", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TailCallLoopOpt, W("TailCallLoopOpt"), 1, "Convert recursive tail calls to loops") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_Jit_NetFx40PInvokeStackResilience, W("NetFx40_PInvokeStackResilience"), (DWORD)-1, "Makes P/Invoke resilient against mismatched signature and calling convention (significant perf penalty).") @@ -376,10 +347,10 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_AltJitAssertOnNYI, W("AltJitAssertOnNYI"), 0, #else RETAIL_CONFIG_DWORD_INFO(INTERNAL_AltJitAssertOnNYI, W("AltJitAssertOnNYI"), 1, "Controls the AltJit behavior of NYI stuff") #endif -CONFIG_DWORD_INFO_EX(INTERNAL_JitLargeBranches, W("JitLargeBranches"), 0, "Force using the largest conditional branch format", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_JitRegisterFP, W("JitRegisterFP"), 3, "Control FP enregistration", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_JitLargeBranches, W("JitLargeBranches"), 0, "Force using the largest conditional branch format", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_JitRegisterFP, W("JitRegisterFP"), 3, "Control FP enregistration", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(INTERNAL_JitELTHookEnabled, W("JitELTHookEnabled"), 0, "On ARM, setting this will emit Enter/Leave/TailCall callbacks") -RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_JitMemStats, W("JitMemStats"), 0, "Display JIT memory usage statistics", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_JitMemStats, W("JitMemStats"), 0, "Display JIT memory usage statistics", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(INTERNAL_JitVNMapSelBudget, W("JitVNMapSelBudget"), 100, "Max # of MapSelect's considered for a particular top-level invocation.") #if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_ARM64) #define EXTERNAL_FeatureSIMD_Default 1 @@ -391,10 +362,10 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_JitVNMapSelBudget, W("JitVNMapSelBudget"), 100 #else // !(defined(TARGET_AMD64) || defined(TARGET_X86) #define EXTERNAL_JitEnableAVX_Default 0 #endif // !(defined(TARGET_AMD64) || defined(TARGET_X86) -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_FeatureSIMD, W("FeatureSIMD"), EXTERNAL_FeatureSIMD_Default, "Enable SIMD intrinsics recognition in System.Numerics.dll and/or System.Numerics.Vectors.dll", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_FeatureSIMD, W("FeatureSIMD"), EXTERNAL_FeatureSIMD_Default, "Enable SIMD intrinsics recognition in System.Numerics.dll and/or System.Numerics.Vectors.dll", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(INTERNAL_SIMD16ByteOnly, W("SIMD16ByteOnly"), 0, "Limit maximum SIMD vector length to 16 bytes (used by x64_arm64_altjit)") -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_EnableAVX, W("EnableAVX"), EXTERNAL_JitEnableAVX_Default, "Enable AVX instruction set for wide operations as default", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_TrackDynamicMethodDebugInfo, W("TrackDynamicMethodDebugInfo"), 0, "Specifies whether debug info should be generated and tracked for dynamic methods", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_EnableAVX, W("EnableAVX"), EXTERNAL_JitEnableAVX_Default, "Enable AVX instruction set for wide operations as default", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_TrackDynamicMethodDebugInfo, W("TrackDynamicMethodDebugInfo"), 0, "Specifies whether debug info should be generated and tracked for dynamic methods", CLRConfig::EEConfig_default) #ifdef FEATURE_MULTICOREJIT @@ -407,18 +378,18 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_MultiCoreJitProfileWriteDelay, W("MultiCoreJit /// /// Interpreter /// -RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_Interpret, W("Interpret"), "Selectively uses the interpreter to execute the specified methods", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_InterpretExclude, W("InterpretExclude"), "Excludes the specified methods from the set selected by 'Interpret'", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_Interpret, W("Interpret"), "Selectively uses the interpreter to execute the specified methods", CLRConfig::EEConfig_default) +RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_InterpretExclude, W("InterpretExclude"), "Excludes the specified methods from the set selected by 'Interpret'", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterMethHashMin, W("InterpreterMethHashMin"), 0, "Only interpret methods selected by 'Interpret' whose hash is at least this value. or after nth") RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterMethHashMax, W("InterpreterMethHashMax"), UINT32_MAX, "If non-zero, only interpret methods selected by 'Interpret' whose hash is at most this value") RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterStubMin, W("InterpreterStubMin"), 0, "Only interpret methods selected by 'Interpret' whose stub num is at least this value.") RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterStubMax, W("InterpreterStubMax"), UINT32_MAX, "If non-zero, only interpret methods selected by 'Interpret' whose stub number is at most this value.") RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterJITThreshold, W("InterpreterJITThreshold"), 10, "The number of times a method should be interpreted before being JITted") RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterDoLoopMethods, W("InterpreterDoLoopMethods"), 0, "If set, don't check for loops, start by interpreting *all* methods") -RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_InterpreterUseCaching, W("InterpreterUseCaching"), 1, "If non-zero, use the caching mechanism.", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_InterpreterLooseRules, W("InterpreterLooseRules"), 1, "If non-zero, allow ECMA spec violations required by managed C++.", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_InterpreterUseCaching, W("InterpreterUseCaching"), 1, "If non-zero, use the caching mechanism.", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_InterpreterLooseRules, W("InterpreterLooseRules"), 1, "If non-zero, allow ECMA spec violations required by managed C++.", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(INTERNAL_InterpreterPrintPostMortem, W("InterpreterPrintPostMortem"), 0, "Prints summary information about the execution to the console") -RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_InterpreterLogFile, W("InterpreterLogFile"), "If non-null, append interpreter logging to this file, else use stdout", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_InterpreterLogFile, W("InterpreterLogFile"), "If non-null, append interpreter logging to this file, else use stdout", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(INTERNAL_DumpInterpreterStubs, W("DumpInterpreterStubs"), 0, "Prints all interpreter stubs that are created to the console") RETAIL_CONFIG_DWORD_INFO(INTERNAL_TraceInterpreterEntries, W("TraceInterpreterEntries"), 0, "Logs entries to interpreted methods to the console") RETAIL_CONFIG_DWORD_INFO(INTERNAL_TraceInterpreterIL, W("TraceInterpreterIL"), 0, "Logs individual instructions of interpreted methods to the console") @@ -437,7 +408,7 @@ RETAIL_CONFIG_STRING_INFO(INTERNAL_WinMDPath, W("WinMDPath"), "Path for Windows /// /// Loader heap /// -CONFIG_DWORD_INFO_EX(INTERNAL_LoaderHeapCallTracing, W("LoaderHeapCallTracing"), 0, "Loader heap troubleshooting", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_LoaderHeapCallTracing, W("LoaderHeapCallTracing"), 0, "Loader heap troubleshooting", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(INTERNAL_CodeHeapReserveForJumpStubs, W("CodeHeapReserveForJumpStubs"), 1, "Percentage of code heap to reserve for jump stubs") RETAIL_CONFIG_DWORD_INFO(INTERNAL_NGenReserveForJumpStubs, W("NGenReserveForJumpStubs"), 0, "Percentage of ngen image size to reserve for jump stubs") RETAIL_CONFIG_DWORD_INFO(INTERNAL_BreakOnOutOfMemoryWithinRange, W("BreakOnOutOfMemoryWithinRange"), 0, "Break before out of memory within range exception is thrown") @@ -449,7 +420,7 @@ RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogEnable, W("LogEnable"), "Turn RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogFacility, W("LogFacility"), "Specifies a facility mask for CLR log. (See 'loglf.h'; VM interprets string value as hex number.) Also used by stresslog.") RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogFacility2, W("LogFacility2"), "Specifies a facility mask for CLR log. (See 'loglf.h'; VM interprets string value as hex number.) Also used by stresslog.") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_logFatalError, W("logFatalError"), 1, "Specifies whether EventReporter logs fatal errors in the Windows event log.") -CONFIG_STRING_INFO_EX(INTERNAL_LogFile, W("LogFile"), "Specifies a file name for the CLR log.", CLRConfig::REGUTIL_default) +CONFIG_STRING_INFO_EX(INTERNAL_LogFile, W("LogFile"), "Specifies a file name for the CLR log.", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogFileAppend, W("LogFileAppend"), "Specifies whether to append to or replace the CLR log file.") CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogFlushFile, W("LogFlushFile"), "Specifies whether to flush the CLR log file on each write.") RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_LogLevel, W("LogLevel"), "4=10 msgs, 9=1000000, 10=everything") @@ -461,22 +432,22 @@ CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogWithPid, W("LogWithPid"), "Appends p /// /// MetaData /// -CONFIG_DWORD_INFO_EX(INTERNAL_MD_ApplyDeltaBreak, W("MD_ApplyDeltaBreak"), 0, "ASSERT when applying EnC", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_MD_ApplyDeltaBreak, W("MD_ApplyDeltaBreak"), 0, "ASSERT when applying EnC", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_AssertOnBadImageFormat, W("AssertOnBadImageFormat"), "ASSERT when invalid MD read") -RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_MD_DeltaCheck, W("MD_DeltaCheck"), 1, "Some checks of GUID when applying EnC (?)", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_MD_EncDelta, W("MD_EncDelta"), 0, "Forces EnC Delta format in MD (?)", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_MD_ForceNoColDesSharing, W("MD_ForceNoColDesSharing"), 0, "Don't know - the only usage I could find is #if 0 (?)", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_MD_KeepKnownCA, W("MD_KeepKnownCA"), 0, "Something with known CAs (?)", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_MD_MiniMDBreak, W("MD_MiniMDBreak"), 0, "ASSERT when creating CMiniMdRw class", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_MD_PreSaveBreak, W("MD_PreSaveBreak"), 0, "ASSERT when calling CMiniMdRw::PreSave", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_MD_RegMetaBreak, W("MD_RegMetaBreak"), 0, "ASSERT when creating RegMeta class", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_MD_RegMetaDump, W("MD_RegMetaDump"), 0, "Dump MD in 4 functions (?)", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_MD_DeltaCheck, W("MD_DeltaCheck"), 1, "Some checks of GUID when applying EnC (?)", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_MD_EncDelta, W("MD_EncDelta"), 0, "Forces EnC Delta format in MD (?)", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_MD_ForceNoColDesSharing, W("MD_ForceNoColDesSharing"), 0, "Don't know - the only usage I could find is #if 0 (?)", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_MD_KeepKnownCA, W("MD_KeepKnownCA"), 0, "Something with known CAs (?)", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_MD_MiniMDBreak, W("MD_MiniMDBreak"), 0, "ASSERT when creating CMiniMdRw class", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_MD_PreSaveBreak, W("MD_PreSaveBreak"), 0, "ASSERT when calling CMiniMdRw::PreSave", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_MD_RegMetaBreak, W("MD_RegMetaBreak"), 0, "ASSERT when creating RegMeta class", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_MD_RegMetaDump, W("MD_RegMetaDump"), 0, "Dump MD in 4 functions (?)", CLRConfig::EEConfig_default) // MetaData - Desktop-only -CONFIG_DWORD_INFO_EX(INTERNAL_MD_WinMD_Disable, W("MD_WinMD_Disable"), 0, "Never activate the WinMD import adapter", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_MD_WinMD_AssertOnIllegalUsage, W("MD_WinMD_AssertOnIllegalUsage"), 0, "ASSERT if a WinMD import adapter detects a tool incompatibility", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_MD_WinMD_Disable, W("MD_WinMD_Disable"), 0, "Never activate the WinMD import adapter", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_MD_WinMD_AssertOnIllegalUsage, W("MD_WinMD_AssertOnIllegalUsage"), 0, "ASSERT if a WinMD import adapter detects a tool incompatibility", CLRConfig::EEConfig_default) // Metadata - mscordbi only - this flag is only intended to mitigate potential issues in bug fix 458597. -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_MD_PreserveDebuggerMetadataMemory, W("MD_PreserveDebuggerMetadataMemory"), 0, "Save all versions of metadata memory in the debugger when debuggee metadata is updated", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_MD_PreserveDebuggerMetadataMemory, W("MD_PreserveDebuggerMetadataMemory"), 0, "Save all versions of metadata memory in the debugger when debuggee metadata is updated", CLRConfig::EEConfig_default) /// /// Spinning heuristics @@ -498,20 +469,20 @@ CONFIG_DWORD_INFO(INTERNAL_NgenBind_ZapForbid, W("NgenBind_ZapForbid CONFIG_STRING_INFO(INTERNAL_NgenBind_ZapForbidExcludeList, W("NgenBind_ZapForbidExcludeList"), "") CONFIG_STRING_INFO(INTERNAL_NgenBind_ZapForbidList, W("NgenBind_ZapForbidList"), "") -CONFIG_DWORD_INFO_EX(INTERNAL_SymDiffDump, W("SymDiffDump"), 0, "Used to create the map file while binding the assembly. Used by SemanticDiffer", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_SymDiffDump, W("SymDiffDump"), 0, "Used to create the map file while binding the assembly. Used by SemanticDiffer", CLRConfig::EEConfig_default) /// /// NGEN /// -RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_NGen_JitName, W("NGen_JitName"), "", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGenFramed, W("NGenFramed"), (DWORD)-1, "Same as JitFramed, but for ngen", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_NGenOnlyOneMethod, W("NGenOnlyOneMethod"), 0, "", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_NgenOrder, W("NgenOrder"), 0, "", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_partialNGenStress, W("partialNGenStress"), 0, "", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_ZapDoNothing, W("ZapDoNothing"), 0, "", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_NgenForceFailureMask, W("NgenForceFailureMask"), (DWORD)-1, "Bitmask used to control which locations will check and raise the failure (defaults to bits: -1)", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_NgenForceFailureCount, W("NgenForceFailureCount"), 0, "If set to >0 and we have IBC data we will force a failure after we reference an IBC data item times", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_NgenForceFailureKind, W("NgenForceFailureKind"), 1, "If set to 1, We will throw a TypeLoad exception; If set to 2, We will cause an A/V", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_NGen_JitName, W("NGen_JitName"), "", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGenFramed, W("NGenFramed"), (DWORD)-1, "Same as JitFramed, but for ngen", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_NGenOnlyOneMethod, W("NGenOnlyOneMethod"), 0, "", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_NgenOrder, W("NgenOrder"), 0, "", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_partialNGenStress, W("partialNGenStress"), 0, "", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_ZapDoNothing, W("ZapDoNothing"), 0, "", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_NgenForceFailureMask, W("NgenForceFailureMask"), (DWORD)-1, "Bitmask used to control which locations will check and raise the failure (defaults to bits: -1)", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_NgenForceFailureCount, W("NgenForceFailureCount"), 0, "If set to >0 and we have IBC data we will force a failure after we reference an IBC data item times", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_NgenForceFailureKind, W("NgenForceFailureKind"), 1, "If set to 1, We will throw a TypeLoad exception; If set to 2, We will cause an A/V", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_NGenEnableCreatePdb, W("NGenEnableCreatePdb"), 0, "If set to >0 ngen.exe displays help on, recognizes createpdb in the command line") RETAIL_CONFIG_DWORD_INFO(INTERNAL_NGenSimulateDiskFull, W("NGenSimulateDiskFull"), 0, "If set to 1, ngen will throw a Disk full exception in ZapWriter.cpp:Save()") RETAIL_CONFIG_DWORD_INFO(INTERNAL_PartialNGen, W("PartialNGen"), (DWORD)-1, "Generate partial NGen images") @@ -525,17 +496,17 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_CrossGenAssumeInputSigned, W("CrossGenAssumeIn /// /// Profiling API / ETW /// -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_COR_ENABLE_PROFILING, W("COR_ENABLE_PROFILING"), 0, "Flag to indicate whether profiling should be enabled for the currently running process.", CLRConfig::DontPrependCOMPlus_ | CLRConfig::IgnoreConfigFiles) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_COR_ENABLE_PROFILING, W("COR_ENABLE_PROFILING"), 0, "Flag to indicate whether profiling should be enabled for the currently running process.", CLRConfig::DontPrependCOMPlus_) RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_COR_PROFILER, W("COR_PROFILER"), "Specifies GUID of profiler to load into currently running process", CLRConfig::DontPrependCOMPlus_) RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_COR_PROFILER_PATH, W("COR_PROFILER_PATH"), "Specifies the path to the DLL of profiler to load into currently running process", CLRConfig::DontPrependCOMPlus_) RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_COR_PROFILER_PATH_32, W("COR_PROFILER_PATH_32"), "Specifies the path to the DLL of profiler to load into currently running 32 bits process", CLRConfig::DontPrependCOMPlus_) RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_COR_PROFILER_PATH_64, W("COR_PROFILER_PATH_64"), "Specifies the path to the DLL of profiler to load into currently running 64 bits process", CLRConfig::DontPrependCOMPlus_) -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_CORECLR_ENABLE_PROFILING, W("CORECLR_ENABLE_PROFILING"), 0, "CoreCLR only: Flag to indicate whether profiling should be enabled for the currently running process.", CLRConfig::DontPrependCOMPlus_ | CLRConfig::IgnoreConfigFiles) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_CORECLR_ENABLE_PROFILING, W("CORECLR_ENABLE_PROFILING"), 0, "CoreCLR only: Flag to indicate whether profiling should be enabled for the currently running process.", CLRConfig::DontPrependCOMPlus_) RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER, W("CORECLR_PROFILER"), "CoreCLR only: Specifies GUID of profiler to load into currently running process", CLRConfig::DontPrependCOMPlus_) RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER_PATH, W("CORECLR_PROFILER_PATH"), "CoreCLR only: Specifies the path to the DLL of profiler to load into currently running process", CLRConfig::DontPrependCOMPlus_) RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER_PATH_32, W("CORECLR_PROFILER_PATH_32"), "CoreCLR only: Specifies the path to the DLL of profiler to load into currently running 32 process", CLRConfig::DontPrependCOMPlus_) RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CORECLR_PROFILER_PATH_64, W("CORECLR_PROFILER_PATH_64"), "CoreCLR only: Specifies the path to the DLL of profiler to load into currently running 64 process", CLRConfig::DontPrependCOMPlus_) -RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_ProfAPI_ProfilerCompatibilitySetting, W("ProfAPI_ProfilerCompatibilitySetting"), "Specifies the profiler loading policy (the default is not to load a V2 profiler in V4)", CLRConfig::REGUTIL_default | CLRConfig::TrimWhiteSpaceFromStringValue) +RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_ProfAPI_ProfilerCompatibilitySetting, W("ProfAPI_ProfilerCompatibilitySetting"), "Specifies the profiler loading policy (the default is not to load a V2 profiler in V4)", CLRConfig::EEConfig_default | CLRConfig::TrimWhiteSpaceFromStringValue) RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ProfAPI_DetachMinSleepMs, W("ProfAPI_DetachMinSleepMs"), 0, "The minimum time, in milliseconds, the CLR will wait before checking whether a profiler that is in the process of detaching is ready to be unloaded.") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ProfAPI_DetachMaxSleepMs, W("ProfAPI_DetachMaxSleepMs"), 0, "The maximum time, in milliseconds, the CLR will wait before checking whether a profiler that is in the process of detaching is ready to be unloaded.") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ProfAPI_RejitOnAttach, W("ProfApi_RejitOnAttach"), 1, "Enables the ability for profilers to rejit methods on attach.") @@ -547,13 +518,13 @@ CONFIG_DWORD_INFO(INTERNAL_TestOnlyEnableICorProfilerInfo, W("ProfAPI_TestOnlyEn CONFIG_DWORD_INFO(INTERNAL_TestOnlyEnableObjectAllocatedHook, W("TestOnlyEnableObjectAllocatedHook"), 0, "Test-only flag that forces CLR to initialize on startup as if ObjectAllocated callback were requested, to enable post-attach ObjectAllocated functionality.") CONFIG_DWORD_INFO(INTERNAL_TestOnlyEnableSlowELTHooks, W("TestOnlyEnableSlowELTHooks"), 0, "Test-only flag that forces CLR to initialize on startup as if slow-ELT were requested, to enable post-attach ELT functionality.") -RETAIL_CONFIG_STRING_INFO_EX(UNSUPPORTED_ETW_ObjectAllocationEventsPerTypePerSec, W("ETW_ObjectAllocationEventsPerTypePerSec"), "Desired number of GCSampledObjectAllocation ETW events to be logged per type per second. If 0, then the default built in to the implementation for the enabled event (e.g., High, Low), will be used.", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_STRING_INFO_EX(UNSUPPORTED_ETW_ObjectAllocationEventsPerTypePerSec, W("ETW_ObjectAllocationEventsPerTypePerSec"), "Desired number of GCSampledObjectAllocation ETW events to be logged per type per second. If 0, then the default built in to the implementation for the enabled event (e.g., High, Low), will be used.", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_ProfAPI_ValidateNGENInstrumentation, W("ProfAPI_ValidateNGENInstrumentation"), 0, "This flag enables additional validations when using the IMetaDataEmit APIs for NGEN'ed images to ensure only supported edits are made.") #ifdef FEATURE_PERFMAP -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_PerfMapEnabled, W("PerfMapEnabled"), 0, "This flag is used on Linux to enable writing /tmp/perf-$pid.map. It is disabled by default", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_PerfMapJitDumpPath, W("PerfMapJitDumpPath"), "Specifies a path to write the perf jitdump file. Defaults to GetTempPathA()", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_PerfMapIgnoreSignal, W("PerfMapIgnoreSignal"), 0, "When perf map is enabled, this option will configure the specified signal to be accepted and ignored as a marker in the perf logs. It is disabled by default", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_PerfMapEnabled, W("PerfMapEnabled"), 0, "This flag is used on Linux to enable writing /tmp/perf-$pid.map. It is disabled by default", CLRConfig::EEConfig_default) +RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_PerfMapJitDumpPath, W("PerfMapJitDumpPath"), "Specifies a path to write the perf jitdump file. Defaults to GetTempPathA()", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_PerfMapIgnoreSignal, W("PerfMapIgnoreSignal"), 0, "When perf map is enabled, this option will configure the specified signal to be accepted and ignored as a marker in the perf logs. It is disabled by default", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(EXTERNAL_PerfMapShowOptimizationTiers, W("PerfMapShowOptimizationTiers"), 1, "Shows optimization tiers in the perf map for methods, as part of the symbol name. Useful for seeing separate stack frames for different optimization tiers of each method.") RETAIL_CONFIG_STRING_INFO(EXTERNAL_NativeImagePerfMapFormat, W("NativeImagePerfMapFormat"), "Specifies the format of native image perfmap files generated by crossgen. Valid options are RVA or OFFSET.") #endif @@ -563,11 +534,11 @@ RETAIL_CONFIG_STRING_INFO(EXTERNAL_StartupDelayMS, W("StartupDelayMS"), "") /// /// Stress /// -CONFIG_DWORD_INFO_EX(INTERNAL_StressCOMCall, W("StressCOMCall"), 0, "", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_StressCOMCall, W("StressCOMCall"), 0, "", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_StressLog, W("StressLog"), "Turns on the stress log.") RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_ForceEnc, W("ForceEnc"), "Forces Edit and Continue to be on for all eligible modules.") RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_StressLogSize, W("StressLogSize"), "Stress log size in bytes per thread.") -CONFIG_DWORD_INFO_EX(INTERNAL_stressSynchronized, W("stressSynchronized"), 0, "Unknown if or where this is used; unless a test is specifically depending on this, it can be removed.", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_stressSynchronized, W("stressSynchronized"), 0, "Unknown if or where this is used; unless a test is specifically depending on this, it can be removed.", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_StressThreadCount, W("StressThreadCount"), "") /// @@ -648,6 +619,16 @@ CONFIG_DWORD_INFO(INTERNAL_OSR_LowId, W("OSR_LowId"), (DWORD)-1, "Low end of ena CONFIG_DWORD_INFO(INTERNAL_OSR_HighId, W("OSR_HighId"), 10000000, "High end of enabled patchpoint range (inclusive)"); #endif +/// +/// Profile Guided Opts +/// +#ifdef FEATURE_PGO +RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_PGODataPath, W("PGODataPath"), "Read/Write PGO data from/to the indicated file.", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO(INTERNAL_ReadPGOData, W("ReadPGOData"), 0, "Read PGO data") +RETAIL_CONFIG_DWORD_INFO(INTERNAL_WritePGOData, W("WritePGOData"), 0, "Write PGO data") +RETAIL_CONFIG_DWORD_INFO(INTERNAL_TieredPGO, W("TieredPGO"), 0, "Instrument Tier0 code and make counts available to Tier1") +#endif + /// /// Entry point slot backpatch /// @@ -663,32 +644,40 @@ CONFIG_DWORD_INFO(INTERNAL_TypeLoader_InjectInterfaceDuplicates, W("INTERNAL_Typ /// /// Virtual call stubs /// -CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubCollideMonoPct, W("VirtualCallStubCollideMonoPct"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubCollideWritePct, W("VirtualCallStubCollideWritePct"), 100, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubDumpLogCounter, W("VirtualCallStubDumpLogCounter"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubDumpLogIncr, W("VirtualCallStubDumpLogIncr"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_VirtualCallStubLogging, W("VirtualCallStubLogging"), 0, "Worth keeping, but should be moved into \"#ifdef STUB_LOGGING\" blocks. This goes for most (or all) of the stub logging infrastructure.", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubMissCount, W("VirtualCallStubMissCount"), 100, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubResetCacheCounter, W("VirtualCallStubResetCacheCounter"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubResetCacheIncr, W("VirtualCallStubResetCacheIncr"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubCollideMonoPct, W("VirtualCallStubCollideMonoPct"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubCollideWritePct, W("VirtualCallStubCollideWritePct"), 100, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubDumpLogCounter, W("VirtualCallStubDumpLogCounter"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubDumpLogIncr, W("VirtualCallStubDumpLogIncr"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_VirtualCallStubLogging, W("VirtualCallStubLogging"), 0, "Worth keeping, but should be moved into \"#ifdef STUB_LOGGING\" blocks. This goes for most (or all) of the stub logging infrastructure.", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubMissCount, W("VirtualCallStubMissCount"), 100, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubResetCacheCounter, W("VirtualCallStubResetCacheCounter"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_VirtualCallStubResetCacheIncr, W("VirtualCallStubResetCacheIncr"), 0, "Used only when STUB_LOGGING is defined, which by default is not.", CLRConfig::EEConfig_default) /// /// Watson /// RETAIL_CONFIG_DWORD_INFO(INTERNAL_DisableWatsonForManagedExceptions, W("DisableWatsonForManagedExceptions"), 0, "Disable Watson and debugger launching for managed exceptions") +/// +/// Dump generation +/// +RETAIL_CONFIG_DWORD_INFO(INTERNAL_DbgEnableMiniDump, W("DbgEnableMiniDump"), 0, "Enable unhandled exception crash dump generation") +RETAIL_CONFIG_STRING_INFO(INTERNAL_DbgMiniDumpName, W("DbgMiniDumpName"), "Crash dump name") +RETAIL_CONFIG_DWORD_INFO(INTERNAL_DbgMiniDumpType, W("DbgMiniDumpType"), 0, "Crash dump type: 1 normal, 2 withheap, 3 triage, 4 full") +RETAIL_CONFIG_DWORD_INFO(INTERNAL_CreateDumpDiagnostics, W("CreateDumpDiagnostics"), 0, "Enable crash dump generation diagnostic logging") + /// /// Zap /// -RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_ZapBBInstr, W("ZapBBInstr"), "", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_STRING_INFO_EX(INTERNAL_ZapBBInstr, W("ZapBBInstr"), "", CLRConfig::EEConfig_default) RETAIL_CONFIG_STRING_INFO(EXTERNAL_ZapBBInstrDir, W("ZapBBInstrDir"), "") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ZapDisable, W("ZapDisable"), 0, "") -CONFIG_STRING_INFO_EX(INTERNAL_ZapExclude, W("ZapExclude"), "", CLRConfig::REGUTIL_default) -CONFIG_STRING_INFO_EX(INTERNAL_ZapOnly, W("ZapOnly"), "", CLRConfig::REGUTIL_default) +CONFIG_STRING_INFO_EX(INTERNAL_ZapExclude, W("ZapExclude"), "", CLRConfig::EEConfig_default) +CONFIG_STRING_INFO_EX(INTERNAL_ZapOnly, W("ZapOnly"), "", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_ZapRequire, W("ZapRequire"), "") RETAIL_CONFIG_STRING_INFO(EXTERNAL_ZapRequireExcludeList, W("ZapRequireExcludeList"), "") RETAIL_CONFIG_STRING_INFO(EXTERNAL_ZapRequireList, W("ZapRequireList"), "") -RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_ZapSet, W("ZapSet"), "", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_ZapSet, W("ZapSet"), "", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ReadyToRun, W("ReadyToRun"), 1, "Enable/disable use of ReadyToRun native code") // On by default for CoreCLR RETAIL_CONFIG_STRING_INFO(EXTERNAL_ReadyToRunExcludeList, W("ReadyToRunExcludeList"), "List of assemblies that cannot use Ready to Run images") @@ -704,7 +693,7 @@ RETAIL_CONFIG_STRING_INFO(INTERNAL_EventNameFilter, W("EventNameFilter"), "") /// Interop /// CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_ExposeExceptionsInCOM, W("ExposeExceptionsInCOM"), "") -RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_PInvokeInline, W("PInvokeInline"), "", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_PInvokeInline, W("PInvokeInline"), "", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_InteropValidatePinnedObjects, W("InteropValidatePinnedObjects"), 0, "After returning from a managed-to-unmanaged interop call, validate GC heap around objects pinned by IL stubs.") RETAIL_CONFIG_DWORD_INFO(EXTERNAL_InteropLogArguments, W("InteropLogArguments"), 0, "Log all pinned arguments passed to an interop call") RETAIL_CONFIG_STRING_INFO(UNSUPPORTED_LogCCWRefCountChange, W("LogCCWRefCountChange"), "Outputs debug information and calls LogCCWRefCountChange_BREAKPOINT when AddRef or Release is called on a CCW.") @@ -726,7 +715,7 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeProcNumbers, W("EventPipeProcNumbers" // // Diagnostics Server // -RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_DOTNET_DiagnosticsServerAddress, W("DOTNET_DiagnosticsServerAddress"), "The full path including filename for the OS transport (NamedPipe on Windows; Unix Domain Socket on Linux) to be used by the Diagnostics Server", CLRConfig::DontPrependCOMPlus_); +RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_DOTNET_DiagnosticsMonitorAddress, W("DOTNET_DiagnosticsMonitorAddress"), "NamedPipe path without '\\\\.\\pipe\\' on Windows; Full path of Unix Domain Socket on Linux/Unix. Used for Diagnostics Monitoring Agents.", CLRConfig::DontPrependCOMPlus_); // // LTTng @@ -757,38 +746,36 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_GDBJitEmitDebugFrame, W("GDBJitEmitDebugFrame" // // DO NOT ADD ANY MORE CONFIG SWITCHES TO THIS SECTION! // ** -CONFIG_DWORD_INFO_EX(INTERNAL_ActivatePatchSkip, W("ActivatePatchSkip"), 0, "Allows an assert when ActivatePatchSkip is called", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_ActivatePatchSkip, W("ActivatePatchSkip"), 0, "Allows an assert when ActivatePatchSkip is called", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_AlwaysUseMetadataInterfaceMapLayout, W("AlwaysUseMetadataInterfaceMapLayout"), "Used for debugging generic interface map layout.") CONFIG_DWORD_INFO(INTERNAL_AssertOnUnneededThis, W("AssertOnUnneededThis"), 0, "While the ConfigDWORD is unnecessary, the contained ASSERT should be kept. This may result in some work tracking down violating MethodDescCallSites.") -CONFIG_DWORD_INFO_EX(INTERNAL_AssertStacktrace, W("AssertStacktrace"), 1, "", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_clearNativeImageStress, W("clearNativeImageStress"), 0, "", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_AssertStacktrace, W("AssertStacktrace"), 1, "", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_clearNativeImageStress, W("clearNativeImageStress"), 0, "", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_CPUFamily, W("CPUFamily"), "") CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_CPUFeatures, W("CPUFeatures"), "") -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_DisableConfigCache, W("DisableConfigCache"), 0, "Used to disable the \"probabilistic\" config cache, which walks through the appropriate config registry keys on init and probabilistically keeps track of which exist.", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_DisableConfigCache, W("DisableConfigCache"), 0, "Used to disable the \"probabilistic\" config cache, which walks through the appropriate config registry keys on init and probabilistically keeps track of which exist.", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_DisableStackwalkCache, W("DisableStackwalkCache"), "") RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_DoubleArrayToLargeObjectHeap, W("DoubleArrayToLargeObjectHeap"), "Controls double[] placement") CONFIG_STRING_INFO(INTERNAL_DumpOnClassLoad, W("DumpOnClassLoad"), "Dumps information about loaded class to log.") CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_ExpandAllOnLoad, W("ExpandAllOnLoad"), "") CONFIG_STRING_INFO_DIRECT_ACCESS(INTERNAL_ForcedRuntime, W("ForcedRuntime"), "Verify version of CLR loaded") -CONFIG_DWORD_INFO_EX(INTERNAL_ForceRelocs, W("ForceRelocs"), 0, "", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_ForceRelocs, W("ForceRelocs"), 0, "", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_GenerateLongJumpDispatchStubRatio, W("GenerateLongJumpDispatchStubRatio"), "Useful for testing VSD on AMD64") -CONFIG_DWORD_INFO_EX(INTERNAL_HashStack, W("HashStack"), 0, "", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_HashStack, W("HashStack"), 0, "", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO(INTERNAL_HostManagerConfig, W("HostManagerConfig"), (DWORD)-1, "") CONFIG_DWORD_INFO(INTERNAL_HostTestThreadAbort, W("HostTestThreadAbort"), 0, "") RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_IgnoreDllMainReturn, W("IgnoreDllMainReturn"), 0, "Don't check the return value of DllMain if this is set", CLRConfig::ConfigFile_ApplicationFirst) CONFIG_STRING_INFO(INTERNAL_InvokeHalt, W("InvokeHalt"), "Throws an assert when the given method is invoked through reflection.") -RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_legacyNullReferenceExceptionPolicy, W("legacyNullReferenceExceptionPolicy"), "") -RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_legacyUnhandledExceptionPolicy, W("legacyUnhandledExceptionPolicy"), "") CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_MaxStackDepth, W("MaxStackDepth"), "") CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_MaxStubUnwindInfoSegmentSize, W("MaxStubUnwindInfoSegmentSize"), "") CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_MaxThreadRecord, W("MaxThreadRecord"), "") CONFIG_DWORD_INFO(INTERNAL_MessageDebugOut, W("MessageDebugOut"), 0, "") -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_NativeImageRequire, W("NativeImageRequire"), 0, "", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_NestedEhOom, W("NestedEhOom"), 0, "", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_NativeImageRequire, W("NativeImageRequire"), 0, "", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_NestedEhOom, W("NestedEhOom"), 0, "", CLRConfig::EEConfig_default) #define INTERNAL_NoGuiOnAssert_Default 1 -RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_NoGuiOnAssert, W("NoGuiOnAssert"), INTERNAL_NoGuiOnAssert_Default, "", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_NoProcedureSplitting, W("NoProcedureSplitting"), 0, "", CLRConfig::REGUTIL_default) -CONFIG_DWORD_INFO_EX(INTERNAL_NoStringInterning, W("NoStringInterning"), 1, "Disallows string interning. I see no value in it anymore.", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_NoGuiOnAssert, W("NoGuiOnAssert"), INTERNAL_NoGuiOnAssert_Default, "", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_NoProcedureSplitting, W("NoProcedureSplitting"), 0, "", CLRConfig::EEConfig_default) +CONFIG_DWORD_INFO_EX(INTERNAL_NoStringInterning, W("NoStringInterning"), 1, "Disallows string interning. I see no value in it anymore.", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_NotifyBadAppCfg, W("NotifyBadAppCfg"), "Whether to show a message box for bad application config file.") CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_PauseOnLoad, W("PauseOnLoad"), "Stops in SystemDomain::init. I think it can be removed.") CONFIG_DWORD_INFO(INTERNAL_PerfAllocsSizeThreshold, W("PerfAllocsSizeThreshold"), 0x3FFFFFFF, "Log facility LF_GCALLOC logs object allocations. This flag controls which ones also log stacktraces. Predates ClrProfiler.") @@ -798,8 +785,8 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_Prepopulate1, W("Prepopulate1"), 1, "") CONFIG_STRING_INFO(INTERNAL_PrestubGC, W("PrestubGC"), "") CONFIG_STRING_INFO(INTERNAL_PrestubHalt, W("PrestubHalt"), "") RETAIL_CONFIG_STRING_INFO(EXTERNAL_RestrictedGCStressExe, W("RestrictedGCStressExe"), "") -CONFIG_DWORD_INFO_EX(INTERNAL_ReturnSourceTypeForTesting, W("ReturnSourceTypeForTesting"), 0, "Allows returning the (internal only) source type of an IL to Native mapping for debugging purposes", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_RSStressLog, W("RSStressLog"), 0, "Allows turning on logging for RS startup", CLRConfig::REGUTIL_default) +CONFIG_DWORD_INFO_EX(INTERNAL_ReturnSourceTypeForTesting, W("ReturnSourceTypeForTesting"), 0, "Allows returning the (internal only) source type of an IL to Native mapping for debugging purposes", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_RSStressLog, W("RSStressLog"), 0, "Allows turning on logging for RS startup", CLRConfig::EEConfig_default) CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SaveThreadInfo, W("SaveThreadInfo"), "") CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SaveThreadInfoMask, W("SaveThreadInfoMask"), "") CONFIG_DWORD_INFO(INTERNAL_SBDumpOnNewIndex, W("SBDumpOnNewIndex"), 0, "Used for Syncblock debugging. It's been a while since any of those have been used.") @@ -808,11 +795,11 @@ CONFIG_DWORD_INFO(INTERNAL_SBDumpStyle, W("SBDumpStyle"), 0, "Used for Syncblock RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(UNSUPPORTED_ShimDatabaseVersion, W("ShimDatabaseVersion"), "Force using shim database version in registry") RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_SleepOnExit, W("SleepOnExit"), 0, "Used for lrak detection. I'd say deprecated by umdh.") CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_StubLinkerUnwindInfoVerificationOn, W("StubLinkerUnwindInfoVerificationOn"), "") -RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_SuccessExit, W("SuccessExit"), 0, "", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_SuccessExit, W("SuccessExit"), 0, "", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_SymbolReadingPolicy, W("SymbolReadingPolicy"), "Specifies when PDBs may be read") RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TestDataConsistency, W("TestDataConsistency"), FALSE, "Allows ensuring the left side is not holding locks (and may thus be in an inconsistent state) when inspection occurs") -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_ThreadGuardPages, W("ThreadGuardPages"), 0, "", CLRConfig::REGUTIL_default) -RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_Timeline, W("Timeline"), 0, "", CLRConfig::REGUTIL_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_ThreadGuardPages, W("ThreadGuardPages"), 0, "", CLRConfig::EEConfig_default) +RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_Timeline, W("Timeline"), 0, "", CLRConfig::EEConfig_default) RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_TotalStressLogSize, W("TotalStressLogSize"), "Total stress log size in bytes.") #ifdef _DEBUG diff --git a/src/coreclr/src/inc/clrversion.h b/src/coreclr/src/inc/clrversion.h new file mode 100644 index 00000000000000..def05683a1a6c5 --- /dev/null +++ b/src/coreclr/src/inc/clrversion.h @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "runtime_version.h" + +#ifndef QUOTE_MACRO +#define QUOTE_MACRO_HELPER(x) #x +#define QUOTE_MACRO(x) QUOTE_MACRO_HELPER(x) +#endif + +#ifndef QUOTE_MACRO_L +#define QUOTE_MACRO_L_HELPER(x) L###x +#define QUOTE_MACRO_L(x) QUOTE_MACRO_L_HELPER(x) +#endif + +#define CLR_METADATA_VERSION "v4.0.30319" +#define CLR_METADATA_VERSION_L W("v4.0.30319") + +#define CLR_PRODUCT_VERSION QUOTE_MACRO(RuntimeProductVersion) +#define CLR_PRODUCT_VERSION_L QUOTE_MACRO_L(RuntimeProductVersion) + +#define VER_ASSEMBLYVERSION_STR QUOTE_MACRO(RuntimeAssemblyMajorVersion.RuntimeAssemblyMinorVersion.0.0) +#define VER_ASSEMBLYVERSION_STR_L QUOTE_MACRO_L(RuntimeAssemblyMajorVersion.RuntimeAssemblyMinorVersion.0.0) + +#define VER_FILEVERSION_STR QUOTE_MACRO(RuntimeFileMajorVersion.RuntimeFileMinorVersion.RuntimeFileBuildVersion.RuntimeFileRevisionVersion) +#define VER_FILEVERSION_STR_L QUOTE_MACRO_L(RuntimeFileMajorVersion.RuntimeFileMinorVersion.RuntimeFileBuildVersion.RuntimeFileRevisionVersion) + +#define VER_LEGALCOPYRIGHT_LOGO_STR "Copyright (c) Microsoft Corporation. All rights reserved." +#define VER_LEGALCOPYRIGHT_LOGO_STR_L L"Copyright (c) Microsoft Corporation. All rights reserved." diff --git a/src/coreclr/src/inc/configuration.h b/src/coreclr/src/inc/configuration.h index 2980f34d8bd3a6..94f016888f5f89 100644 --- a/src/coreclr/src/inc/configuration.h +++ b/src/coreclr/src/inc/configuration.h @@ -35,7 +35,7 @@ class Configuration // in the traditional way separately if you need to. // // Returns value for name if found in config. - static ULONGLONG GetKnobULONGLONGValue(LPCWSTR name); + static ULONGLONG GetKnobULONGLONGValue(LPCWSTR name, ULONGLONG defaultValue); // Returns (in priority order): // - The value of the ConfigStringInfo if it's set diff --git a/src/coreclr/src/inc/corcompile.h b/src/coreclr/src/inc/corcompile.h index a14a979bd0a265..2973b7a2fa42b6 100644 --- a/src/coreclr/src/inc/corcompile.h +++ b/src/coreclr/src/inc/corcompile.h @@ -1728,8 +1728,8 @@ class ICorCompileInfo // to 1 on the clone. The buffer has to be large enough to hold the stub object and the code virtual HRESULT GetStubClone(void *pStub, BYTE *pBuffer, DWORD dwBufferSize) = 0; - // true if the method has [NativeCallableAttribute] - virtual BOOL IsNativeCallableMethod(CORINFO_METHOD_HANDLE handle) = 0; + // true if the method has [UnmanagedCallersOnlyAttribute] + virtual BOOL IsUnmanagedCallersOnlyMethod(CORINFO_METHOD_HANDLE handle) = 0; virtual BOOL GetIsGeneratingNgenPDB() = 0; virtual void SetIsGeneratingNgenPDB(BOOL fGeneratingNgenPDB) = 0; diff --git a/src/coreclr/src/inc/cordebug.idl b/src/coreclr/src/inc/cordebug.idl index 87e1458cfc91da..be745368f2bb33 100644 --- a/src/coreclr/src/inc/cordebug.idl +++ b/src/coreclr/src/inc/cordebug.idl @@ -2567,7 +2567,8 @@ typedef enum CorGCReferenceType CorHandleStrongDependent = 1<<6, CorHandleStrongAsyncPinned = 1<<7, CorHandleStrongSizedByref = 1<<8, - CorHandleWeakWinRT = 1<<9, + CorHandleWeakNativeCom = 1<<9, + CorHandleWeakWinRT = CorHandleWeakNativeCom, CorReferenceStack = 0x80000001, CorReferenceFinalizer = 80000002, diff --git a/src/coreclr/src/inc/corhlprpriv.h b/src/coreclr/src/inc/corhlprpriv.h index 8fcafd08d93c34..7b9e5f1f885677 100644 --- a/src/coreclr/src/inc/corhlprpriv.h +++ b/src/coreclr/src/inc/corhlprpriv.h @@ -507,6 +507,7 @@ class CQuickArrayList : protected CQuickArray using CQuickArray::AllocNoThrow; using CQuickArray::ReSizeNoThrow; using CQuickArray::MaxSize; + using CQuickArray::Ptr; CQuickArrayList() : m_curSize(0) diff --git a/src/coreclr/src/inc/corinfo.h b/src/coreclr/src/inc/corinfo.h index 635da5887ade4b..2c8c1260b73925 100644 --- a/src/coreclr/src/inc/corinfo.h +++ b/src/coreclr/src/inc/corinfo.h @@ -217,11 +217,11 @@ TODO: Talk about initializing strutures before use #endif #endif -SELECTANY const GUID JITEEVersionIdentifier = { /* 6ae798bf-44bd-4e8a-b8fc-dbe1d1f4029e */ - 0x6ae798bf, - 0x44bd, - 0x4e8a, - {0xb8, 0xfc, 0xdb, 0xe1, 0xd1, 0xf4, 0x02, 0x9e} +SELECTANY const GUID JITEEVersionIdentifier = { /* 8b2226a2-ac30-4f5c-ae5c-926c792ecdb9 */ + 0x8b2226a2, + 0xac30, + 0x4f5c, + { 0xae, 0x5c, 0x92, 0x6c, 0x79, 0x2e, 0xcd, 0xb9 } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -937,6 +937,7 @@ enum CorInfoIntrinsics CORINFO_INTRINSIC_StubHelpers_GetStubContext, CORINFO_INTRINSIC_StubHelpers_GetStubContextAddr, CORINFO_INTRINSIC_StubHelpers_GetNDirectTarget, + CORINFO_INTRINSIC_StubHelpers_NextCallReturnAddress, CORINFO_INTRINSIC_InterlockedAdd32, CORINFO_INTRINSIC_InterlockedAdd64, CORINFO_INTRINSIC_InterlockedXAdd32, @@ -946,6 +947,7 @@ enum CorInfoIntrinsics CORINFO_INTRINSIC_InterlockedCmpXchg32, CORINFO_INTRINSIC_InterlockedCmpXchg64, CORINFO_INTRINSIC_MemoryBarrier, + CORINFO_INTRINSIC_MemoryBarrierLoad, CORINFO_INTRINSIC_GetCurrentManagedThread, CORINFO_INTRINSIC_GetManagedThreadId, CORINFO_INTRINSIC_ByReference_Ctor, @@ -1074,15 +1076,6 @@ enum CorInfoIndirectCallReason CORINFO_INDIRECT_CALL_COUNT }; -// When using CORINFO_HELPER_TAILCALL, the JIT needs to pass certain special -// calling convention/argument passing/handling details to the helper -enum CorInfoHelperTailCallSpecialHandling -{ - CORINFO_TAILCALL_NORMAL = 0x00000000, - CORINFO_TAILCALL_STUB_DISPATCH_ARG = 0x00000001, -}; - - inline bool dontInline(CorInfoInline val) { return(val < 0); } @@ -1612,7 +1605,7 @@ struct CORINFO_CALL_INFO unsigned classFlags; //flags for CORINFO_RESOLVED_TOKEN::hClass - CORINFO_SIG_INFO sig; + CORINFO_SIG_INFO sig; //Verification information unsigned verMethodFlags; // flags for CORINFO_RESOLVED_TOKEN::hMethod @@ -1796,6 +1789,30 @@ struct CORINFO_EE_INFO CORINFO_OS osType; }; +// Flags passed from JIT to runtime. +enum CORINFO_GET_TAILCALL_HELPERS_FLAGS +{ + // The callsite is a callvirt instruction. + CORINFO_TAILCALL_IS_CALLVIRT = 0x00000001, + CORINFO_TAILCALL_THIS_ARG_IS_BYREF = 0x00000002, +}; + +// Flags passed from runtime to JIT. +enum CORINFO_TAILCALL_HELPERS_FLAGS +{ + // The StoreArgs stub needs to be passed the target function pointer as the + // first argument. + CORINFO_TAILCALL_STORE_TARGET = 0x00000001, +}; + +struct CORINFO_TAILCALL_HELPERS +{ + CORINFO_TAILCALL_HELPERS_FLAGS flags; + CORINFO_METHOD_HANDLE hStoreArgs; + CORINFO_METHOD_HANDLE hCallTarget; + CORINFO_METHOD_HANDLE hDispatcher; +}; + // This is used to indicate that a finally has been called // "locally" by the try block enum { LCL_FINALLY_MARK = 0xFC }; // FC = "Finally Call" @@ -3115,11 +3132,20 @@ class ICorDynamicInfo : public ICorStaticInfo CORINFO_METHOD_HANDLE methHnd ) = 0; - // return a thunk that will copy the arguments for the given signature. - virtual void* getTailCallCopyArgsThunk ( - CORINFO_SIG_INFO *pSig, - CorInfoHelperTailCallSpecialHandling flags - ) = 0; + // Obtain tailcall help for the specified call site. + virtual bool getTailCallHelpers( + + // The resolved token for the call. Can be null for calli. + CORINFO_RESOLVED_TOKEN* callToken, + + // The signature at the callsite. + CORINFO_SIG_INFO* sig, + + // Flags for the tailcall site. + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + + // The resulting help. + CORINFO_TAILCALL_HELPERS* pResult) = 0; // Optionally, convert calli to regular method call. This is for PInvoke argument marshalling. virtual bool convertPInvokeCalliToCall( diff --git a/src/coreclr/src/inc/corinfoinstructionset.h b/src/coreclr/src/inc/corinfoinstructionset.h index e689f03d8557d6..8e667bc29b07b1 100644 --- a/src/coreclr/src/inc/corinfoinstructionset.h +++ b/src/coreclr/src/inc/corinfoinstructionset.h @@ -32,58 +32,62 @@ enum CORINFO_InstructionSet InstructionSet_Vector128=12, #endif // TARGET_ARM64 #ifdef TARGET_AMD64 - InstructionSet_SSE=1, - InstructionSet_SSE2=2, - InstructionSet_SSE3=3, - InstructionSet_SSSE3=4, - InstructionSet_SSE41=5, - InstructionSet_SSE42=6, - InstructionSet_AVX=7, - InstructionSet_AVX2=8, - InstructionSet_AES=9, - InstructionSet_BMI1=10, - InstructionSet_BMI2=11, - InstructionSet_FMA=12, - InstructionSet_LZCNT=13, - InstructionSet_PCLMULQDQ=14, - InstructionSet_POPCNT=15, - InstructionSet_Vector128=16, - InstructionSet_Vector256=17, - InstructionSet_BMI1_X64=18, - InstructionSet_BMI2_X64=19, - InstructionSet_LZCNT_X64=20, - InstructionSet_POPCNT_X64=21, - InstructionSet_SSE_X64=22, - InstructionSet_SSE2_X64=23, - InstructionSet_SSE41_X64=24, - InstructionSet_SSE42_X64=25, + InstructionSet_X86Base=1, + InstructionSet_SSE=2, + InstructionSet_SSE2=3, + InstructionSet_SSE3=4, + InstructionSet_SSSE3=5, + InstructionSet_SSE41=6, + InstructionSet_SSE42=7, + InstructionSet_AVX=8, + InstructionSet_AVX2=9, + InstructionSet_AES=10, + InstructionSet_BMI1=11, + InstructionSet_BMI2=12, + InstructionSet_FMA=13, + InstructionSet_LZCNT=14, + InstructionSet_PCLMULQDQ=15, + InstructionSet_POPCNT=16, + InstructionSet_Vector128=17, + InstructionSet_Vector256=18, + InstructionSet_X86Base_X64=19, + InstructionSet_BMI1_X64=20, + InstructionSet_BMI2_X64=21, + InstructionSet_LZCNT_X64=22, + InstructionSet_POPCNT_X64=23, + InstructionSet_SSE_X64=24, + InstructionSet_SSE2_X64=25, + InstructionSet_SSE41_X64=26, + InstructionSet_SSE42_X64=27, #endif // TARGET_AMD64 #ifdef TARGET_X86 - InstructionSet_SSE=1, - InstructionSet_SSE2=2, - InstructionSet_SSE3=3, - InstructionSet_SSSE3=4, - InstructionSet_SSE41=5, - InstructionSet_SSE42=6, - InstructionSet_AVX=7, - InstructionSet_AVX2=8, - InstructionSet_AES=9, - InstructionSet_BMI1=10, - InstructionSet_BMI2=11, - InstructionSet_FMA=12, - InstructionSet_LZCNT=13, - InstructionSet_PCLMULQDQ=14, - InstructionSet_POPCNT=15, - InstructionSet_Vector128=16, - InstructionSet_Vector256=17, - InstructionSet_BMI1_X64=18, - InstructionSet_BMI2_X64=19, - InstructionSet_LZCNT_X64=20, - InstructionSet_POPCNT_X64=21, - InstructionSet_SSE_X64=22, - InstructionSet_SSE2_X64=23, - InstructionSet_SSE41_X64=24, - InstructionSet_SSE42_X64=25, + InstructionSet_X86Base=1, + InstructionSet_SSE=2, + InstructionSet_SSE2=3, + InstructionSet_SSE3=4, + InstructionSet_SSSE3=5, + InstructionSet_SSE41=6, + InstructionSet_SSE42=7, + InstructionSet_AVX=8, + InstructionSet_AVX2=9, + InstructionSet_AES=10, + InstructionSet_BMI1=11, + InstructionSet_BMI2=12, + InstructionSet_FMA=13, + InstructionSet_LZCNT=14, + InstructionSet_PCLMULQDQ=15, + InstructionSet_POPCNT=16, + InstructionSet_Vector128=17, + InstructionSet_Vector256=18, + InstructionSet_X86Base_X64=19, + InstructionSet_BMI1_X64=20, + InstructionSet_BMI2_X64=21, + InstructionSet_LZCNT_X64=22, + InstructionSet_POPCNT_X64=23, + InstructionSet_SSE_X64=24, + InstructionSet_SSE2_X64=25, + InstructionSet_SSE41_X64=26, + InstructionSet_SSE42_X64=27, #endif // TARGET_X86 }; @@ -139,6 +143,8 @@ struct CORINFO_InstructionSetFlags AddInstructionSet(InstructionSet_Crc32_Arm64); #endif // TARGET_ARM64 #ifdef TARGET_AMD64 + if (HasInstructionSet(InstructionSet_X86Base)) + AddInstructionSet(InstructionSet_X86Base_X64); if (HasInstructionSet(InstructionSet_SSE)) AddInstructionSet(InstructionSet_SSE_X64); if (HasInstructionSet(InstructionSet_SSE2)) @@ -204,6 +210,10 @@ inline CORINFO_InstructionSetFlags EnsureInstructionSetFlagsAreValid(CORINFO_Ins resultflags.RemoveInstructionSet(InstructionSet_Sha256); #endif // TARGET_ARM64 #ifdef TARGET_AMD64 + if (resultflags.HasInstructionSet(InstructionSet_X86Base) && !resultflags.HasInstructionSet(InstructionSet_X86Base_X64)) + resultflags.RemoveInstructionSet(InstructionSet_X86Base); + if (resultflags.HasInstructionSet(InstructionSet_X86Base_X64) && !resultflags.HasInstructionSet(InstructionSet_X86Base)) + resultflags.RemoveInstructionSet(InstructionSet_X86Base_X64); if (resultflags.HasInstructionSet(InstructionSet_SSE) && !resultflags.HasInstructionSet(InstructionSet_SSE_X64)) resultflags.RemoveInstructionSet(InstructionSet_SSE); if (resultflags.HasInstructionSet(InstructionSet_SSE_X64) && !resultflags.HasInstructionSet(InstructionSet_SSE)) @@ -236,6 +246,8 @@ inline CORINFO_InstructionSetFlags EnsureInstructionSetFlagsAreValid(CORINFO_Ins resultflags.RemoveInstructionSet(InstructionSet_POPCNT); if (resultflags.HasInstructionSet(InstructionSet_POPCNT_X64) && !resultflags.HasInstructionSet(InstructionSet_POPCNT)) resultflags.RemoveInstructionSet(InstructionSet_POPCNT_X64); + if (resultflags.HasInstructionSet(InstructionSet_SSE) && !resultflags.HasInstructionSet(InstructionSet_X86Base)) + resultflags.RemoveInstructionSet(InstructionSet_SSE); if (resultflags.HasInstructionSet(InstructionSet_SSE2) && !resultflags.HasInstructionSet(InstructionSet_SSE)) resultflags.RemoveInstructionSet(InstructionSet_SSE2); if (resultflags.HasInstructionSet(InstructionSet_SSE3) && !resultflags.HasInstructionSet(InstructionSet_SSE2)) @@ -262,8 +274,12 @@ inline CORINFO_InstructionSetFlags EnsureInstructionSetFlagsAreValid(CORINFO_Ins resultflags.RemoveInstructionSet(InstructionSet_PCLMULQDQ); if (resultflags.HasInstructionSet(InstructionSet_POPCNT) && !resultflags.HasInstructionSet(InstructionSet_SSE42)) resultflags.RemoveInstructionSet(InstructionSet_POPCNT); + if (resultflags.HasInstructionSet(InstructionSet_Vector256) && !resultflags.HasInstructionSet(InstructionSet_AVX)) + resultflags.RemoveInstructionSet(InstructionSet_Vector256); #endif // TARGET_AMD64 #ifdef TARGET_X86 + if (resultflags.HasInstructionSet(InstructionSet_SSE) && !resultflags.HasInstructionSet(InstructionSet_X86Base)) + resultflags.RemoveInstructionSet(InstructionSet_SSE); if (resultflags.HasInstructionSet(InstructionSet_SSE2) && !resultflags.HasInstructionSet(InstructionSet_SSE)) resultflags.RemoveInstructionSet(InstructionSet_SSE2); if (resultflags.HasInstructionSet(InstructionSet_SSE3) && !resultflags.HasInstructionSet(InstructionSet_SSE2)) @@ -290,6 +306,8 @@ inline CORINFO_InstructionSetFlags EnsureInstructionSetFlagsAreValid(CORINFO_Ins resultflags.RemoveInstructionSet(InstructionSet_PCLMULQDQ); if (resultflags.HasInstructionSet(InstructionSet_POPCNT) && !resultflags.HasInstructionSet(InstructionSet_SSE42)) resultflags.RemoveInstructionSet(InstructionSet_POPCNT); + if (resultflags.HasInstructionSet(InstructionSet_Vector256) && !resultflags.HasInstructionSet(InstructionSet_AVX)) + resultflags.RemoveInstructionSet(InstructionSet_Vector256); #endif // TARGET_X86 } while (!oldflags.Equals(resultflags)); @@ -332,6 +350,10 @@ inline const char *InstructionSetToString(CORINFO_InstructionSet instructionSet) return "Vector128"; #endif // TARGET_ARM64 #ifdef TARGET_AMD64 + case InstructionSet_X86Base : + return "X86Base"; + case InstructionSet_X86Base_X64 : + return "X86Base_X64"; case InstructionSet_SSE : return "SSE"; case InstructionSet_SSE_X64 : @@ -384,6 +406,8 @@ inline const char *InstructionSetToString(CORINFO_InstructionSet instructionSet) return "Vector256"; #endif // TARGET_AMD64 #ifdef TARGET_X86 + case InstructionSet_X86Base : + return "X86Base"; case InstructionSet_SSE : return "SSE"; case InstructionSet_SSE2 : @@ -447,6 +471,7 @@ inline CORINFO_InstructionSet InstructionSetFromR2RInstructionSet(ReadyToRunInst case READYTORUN_INSTRUCTION_Atomics: return InstructionSet_Atomics; #endif // TARGET_ARM64 #ifdef TARGET_AMD64 + case READYTORUN_INSTRUCTION_X86Base: return InstructionSet_X86Base; case READYTORUN_INSTRUCTION_Sse: return InstructionSet_SSE; case READYTORUN_INSTRUCTION_Sse2: return InstructionSet_SSE2; case READYTORUN_INSTRUCTION_Sse3: return InstructionSet_SSE3; @@ -464,6 +489,7 @@ inline CORINFO_InstructionSet InstructionSetFromR2RInstructionSet(ReadyToRunInst case READYTORUN_INSTRUCTION_Popcnt: return InstructionSet_POPCNT; #endif // TARGET_AMD64 #ifdef TARGET_X86 + case READYTORUN_INSTRUCTION_X86Base: return InstructionSet_X86Base; case READYTORUN_INSTRUCTION_Sse: return InstructionSet_SSE; case READYTORUN_INSTRUCTION_Sse2: return InstructionSet_SSE2; case READYTORUN_INSTRUCTION_Sse3: return InstructionSet_SSE3; diff --git a/src/coreclr/src/inc/corpriv.h b/src/coreclr/src/inc/corpriv.h index 766fb2916b7639..6b92458ec40f18 100644 --- a/src/coreclr/src/inc/corpriv.h +++ b/src/coreclr/src/inc/corpriv.h @@ -25,9 +25,6 @@ interface IAssemblyName; -// PE images loaded through the runtime. -typedef struct _dummyCOR { BYTE b; } *HCORMODULE; - class UTSemReadWrite; // Helper function to get a pointer to the Dispenser interface. @@ -70,11 +67,6 @@ STDAPI GetAssemblyMDInternalImport( // Return code. REFIID riid, // [IN] The interface desired. IUnknown **ppIUnk); // [OUT] Return interface on success. -HRESULT GetAssemblyMDInternalImportFromImage( - HCORMODULE hImage, //[IN] pointer to module handle to get the metadata from. - REFIID riid, //[IN] The interface desired. - IUnknown **ppIUnk); //[OUT] Return Interface on success. - STDAPI GetAssemblyMDInternalImportByStream( // Return code. IStream *pIStream, // [IN] The IStream for the file UINT64 AssemblyId, // [IN] Unique Id for the assembly @@ -303,60 +295,6 @@ typedef enum CorOpenFlagsInternal #define COR_MODULE_CLASS "" #define COR_WMODULE_CLASS W("") -STDAPI RuntimeOpenImage(LPCWSTR pszFileName, HCORMODULE* hHandle); -STDAPI RuntimeOpenImageInternal(LPCWSTR pszFileName, HCORMODULE* hHandle, - DWORD *pdwLength, MDInternalImportFlags flags, HANDLE hFile = INVALID_HANDLE_VALUE); -STDAPI RuntimeOpenImageByStream(IStream* pIStream, UINT64 AssemblyId, DWORD dwModuleId, - HCORMODULE* hHandle, DWORD *pdwLength, MDInternalImportFlags flags); - -void RuntimeAddRefHandle(HCORMODULE hHandle); -STDAPI RuntimeReleaseHandle(HCORMODULE hHandle); -STDAPI RuntimeGetImageBase(HCORMODULE hHandle, LPVOID* base, BOOL bMapped, COUNT_T* dwSize); -STDAPI RuntimeGetImageKind(HCORMODULE hHandle, DWORD* pdwKind, DWORD* pdwMachine); -STDAPI RuntimeOSHandle(HCORMODULE hHandle, HMODULE* hModule); -STDAPI RuntimeGetAssemblyStrongNameHashForModule(HCORMODULE hModule, - IMetaDataImport *pMDimport, - BYTE *pbSNHash, - DWORD *pcbSNHash); -STDAPI RuntimeGetMDInternalImport(HCORMODULE hHandle, - MDInternalImportFlags flags, - IMDInternalImport** ppMDImport); - -FORCEINLINE -void ReleaseHCorModule(HCORMODULE hModule) -{ - HRESULT hr = RuntimeReleaseHandle(hModule); - _ASSERTE(SUCCEEDED(hr)); -} - -typedef Wrapper, ReleaseHCorModule, (UINT_PTR) NULL> HCORMODULEHolder; - - -// =========================================================================== -// ISNAssemblySignature (similar to IAssemblySignature in V1) -// -// This is a private interface that allows querying of the strong name -// signature. -// This can be used for (strong-named) assemblies added to the GAC as -// a unique identifier. -// - -// {848845BC-0C4A-42e3-8915-DC850112443D} -EXTERN_GUID(IID_ISNAssemblySignature, 0x848845BC, 0x0C4A, 0x42e3, 0x89, 0x15, 0xDC, 0x85, 0x01, 0x12, 0x44, 0x3D); - -#undef INTERFACE -#define INTERFACE ISNAssemblySignature -DECLARE_INTERFACE_(ISNAssemblySignature, IUnknown) -{ - // Returns the strong-name signature if the assembly is strong-name-signed - // Returns the MVID if the assembly is delay-signed. - // Fails if the assembly is not signed at all. - STDMETHOD(GetSNAssemblySignature) ( - BYTE *pbSig, // [IN, OUT] Buffer to write signature - DWORD *pcbSig // [IN, OUT] Size of buffer, bytes written - ) PURE; -}; - //------------------------------------- //--- ICeeGenInternal //------------------------------------- @@ -460,11 +398,6 @@ STDAPI GetCORSystemDirectoryInternal( __out_opt DWORD* pdwLength ); -STDAPI GetCORVersionInternal( - __out_ecount_z_opt(cchBuffer) LPWSTR pBuffer, - DWORD cchBuffer, - __out DWORD *pdwLength); - #endif // _CORPRIV_H_ // EOF ======================================================================= diff --git a/src/coreclr/src/inc/crosscomp.h b/src/coreclr/src/inc/crosscomp.h index 81a85641b8e303..93a164c249240d 100644 --- a/src/coreclr/src/inc/crosscomp.h +++ b/src/coreclr/src/inc/crosscomp.h @@ -392,9 +392,11 @@ typedef struct _T_KNONVOLATILE_CONTEXT_POINTERS { #define DAC_CS_NATIVE_DATA_SIZE 56 #elif defined(TARGET_NETBSD) && defined(TARGET_X86) #define DAC_CS_NATIVE_DATA_SIZE 56 +#elif defined(__sun) && defined(TARGET_AMD64) +#define DAC_CS_NATIVE_DATA_SIZE 48 #else #warning -#error DAC_CS_NATIVE_DATA_SIZE is not defined for this architecture +#error DAC_CS_NATIVE_DATA_SIZE is not defined for this architecture. This should be same value as PAL_CS_NATIVE_DATA_SIZE (aka sizeof(PAL_CS_NATIVE_DATA)). #endif struct T_CRITICAL_SECTION { diff --git a/src/coreclr/src/inc/crsttypes.h b/src/coreclr/src/inc/crsttypes.h index 98d24c2efafcae..dc8e5a94296d27 100644 --- a/src/coreclr/src/inc/crsttypes.h +++ b/src/coreclr/src/inc/crsttypes.h @@ -69,109 +69,108 @@ enum CrstType CrstFuncPtrStubs = 50, CrstFusionAppCtx = 51, CrstGCCover = 52, - CrstGCMemoryPressure = 53, - CrstGlobalStrLiteralMap = 54, - CrstHandleTable = 55, - CrstHostAssemblyMap = 56, - CrstHostAssemblyMapAdd = 57, - CrstIbcProfile = 58, - CrstIJWFixupData = 59, - CrstIJWHash = 60, - CrstILStubGen = 61, - CrstInlineTrackingMap = 62, - CrstInstMethodHashTable = 63, - CrstInterfaceVTableMap = 64, - CrstInterop = 65, - CrstInteropData = 66, - CrstIOThreadpoolWorker = 67, - CrstIsJMCMethod = 68, - CrstISymUnmanagedReader = 69, - CrstJit = 70, - CrstJitGenericHandleCache = 71, - CrstJitInlineTrackingMap = 72, - CrstJitPatchpoint = 73, - CrstJitPerf = 74, - CrstJumpStubCache = 75, - CrstLeafLock = 76, - CrstListLock = 77, - CrstLoaderAllocator = 78, - CrstLoaderAllocatorReferences = 79, - CrstLoaderHeap = 80, - CrstMda = 81, - CrstMetadataTracker = 82, - CrstMethodDescBackpatchInfoTracker = 83, - CrstModIntPairList = 84, - CrstModule = 85, - CrstModuleFixup = 86, - CrstModuleLookupTable = 87, - CrstMulticoreJitHash = 88, - CrstMulticoreJitManager = 89, - CrstMUThunkHash = 90, - CrstNativeBinderInit = 91, - CrstNativeImageCache = 92, - CrstNativeImageEagerFixups = 93, - CrstNls = 94, - CrstNotifyGdb = 95, - CrstObjectList = 96, - CrstOnEventManager = 97, - CrstPatchEntryPoint = 98, - CrstPEImage = 99, - CrstPEImagePDBStream = 100, - CrstPendingTypeLoadEntry = 101, - CrstPinHandle = 102, - CrstPinnedByrefValidation = 103, - CrstProfilerGCRefDataFreeList = 104, - CrstProfilingAPIStatus = 105, - CrstPublisherCertificate = 106, - CrstRCWCache = 107, - CrstRCWCleanupList = 108, - CrstRCWRefCache = 109, - CrstReadyToRunEntryPointToMethodDescMap = 110, - CrstReDacl = 111, - CrstReflection = 112, - CrstReJITGlobalRequest = 113, - CrstRemoting = 114, - CrstRetThunkCache = 115, - CrstRWLock = 116, - CrstSavedExceptionInfo = 117, - CrstSaveModuleProfileData = 118, - CrstSecurityStackwalkCache = 119, - CrstSharedAssemblyCreate = 120, - CrstSigConvert = 121, - CrstSingleUseLock = 122, - CrstSpecialStatics = 123, - CrstSqmManager = 124, - CrstStackSampler = 125, - CrstStressLog = 126, - CrstStrongName = 127, - CrstStubCache = 128, - CrstStubDispatchCache = 129, - CrstStubUnwindInfoHeapSegments = 130, - CrstSyncBlockCache = 131, - CrstSyncHashLock = 132, - CrstSystemBaseDomain = 133, - CrstSystemDomain = 134, - CrstSystemDomainDelayedUnloadList = 135, - CrstThreadIdDispenser = 136, - CrstThreadpoolEventCache = 137, - CrstThreadpoolTimerQueue = 138, - CrstThreadpoolWaitThreads = 139, - CrstThreadpoolWorker = 140, - CrstThreadStaticDataHashTable = 141, - CrstThreadStore = 142, - CrstTieredCompilation = 143, - CrstTPMethodTable = 144, - CrstTypeEquivalenceMap = 145, - CrstTypeIDMap = 146, - CrstUMEntryThunkCache = 147, - CrstUMThunkHash = 148, - CrstUniqueStack = 149, - CrstUnresolvedClassLock = 150, - CrstUnwindInfoTableLock = 151, - CrstVSDIndirectionCellLock = 152, - CrstWinRTFactoryCache = 153, - CrstWrapperTemplate = 154, - kNumberOfCrstTypes = 155 + CrstGlobalStrLiteralMap = 53, + CrstHandleTable = 54, + CrstHostAssemblyMap = 55, + CrstHostAssemblyMapAdd = 56, + CrstIbcProfile = 57, + CrstIJWFixupData = 58, + CrstIJWHash = 59, + CrstILStubGen = 60, + CrstInlineTrackingMap = 61, + CrstInstMethodHashTable = 62, + CrstInterfaceVTableMap = 63, + CrstInterop = 64, + CrstInteropData = 65, + CrstIOThreadpoolWorker = 66, + CrstIsJMCMethod = 67, + CrstISymUnmanagedReader = 68, + CrstJit = 69, + CrstJitGenericHandleCache = 70, + CrstJitInlineTrackingMap = 71, + CrstJitPatchpoint = 72, + CrstJitPerf = 73, + CrstJumpStubCache = 74, + CrstLeafLock = 75, + CrstListLock = 76, + CrstLoaderAllocator = 77, + CrstLoaderAllocatorReferences = 78, + CrstLoaderHeap = 79, + CrstMda = 80, + CrstMetadataTracker = 81, + CrstMethodDescBackpatchInfoTracker = 82, + CrstModIntPairList = 83, + CrstModule = 84, + CrstModuleFixup = 85, + CrstModuleLookupTable = 86, + CrstMulticoreJitHash = 87, + CrstMulticoreJitManager = 88, + CrstMUThunkHash = 89, + CrstNativeBinderInit = 90, + CrstNativeImageCache = 91, + CrstNativeImageEagerFixups = 92, + CrstNls = 93, + CrstNotifyGdb = 94, + CrstObjectList = 95, + CrstOnEventManager = 96, + CrstPatchEntryPoint = 97, + CrstPEImage = 98, + CrstPEImagePDBStream = 99, + CrstPendingTypeLoadEntry = 100, + CrstPinHandle = 101, + CrstPinnedByrefValidation = 102, + CrstProfilerGCRefDataFreeList = 103, + CrstProfilingAPIStatus = 104, + CrstPublisherCertificate = 105, + CrstRCWCache = 106, + CrstRCWCleanupList = 107, + CrstRCWRefCache = 108, + CrstReadyToRunEntryPointToMethodDescMap = 109, + CrstReDacl = 110, + CrstReflection = 111, + CrstReJITGlobalRequest = 112, + CrstRemoting = 113, + CrstRetThunkCache = 114, + CrstRWLock = 115, + CrstSavedExceptionInfo = 116, + CrstSaveModuleProfileData = 117, + CrstSecurityStackwalkCache = 118, + CrstSharedAssemblyCreate = 119, + CrstSigConvert = 120, + CrstSingleUseLock = 121, + CrstSpecialStatics = 122, + CrstSqmManager = 123, + CrstStackSampler = 124, + CrstStressLog = 125, + CrstStrongName = 126, + CrstStubCache = 127, + CrstStubDispatchCache = 128, + CrstStubUnwindInfoHeapSegments = 129, + CrstSyncBlockCache = 130, + CrstSyncHashLock = 131, + CrstSystemBaseDomain = 132, + CrstSystemDomain = 133, + CrstSystemDomainDelayedUnloadList = 134, + CrstThreadIdDispenser = 135, + CrstThreadpoolEventCache = 136, + CrstThreadpoolTimerQueue = 137, + CrstThreadpoolWaitThreads = 138, + CrstThreadpoolWorker = 139, + CrstThreadStaticDataHashTable = 140, + CrstThreadStore = 141, + CrstTieredCompilation = 142, + CrstTPMethodTable = 143, + CrstTypeEquivalenceMap = 144, + CrstTypeIDMap = 145, + CrstUMEntryThunkCache = 146, + CrstUMThunkHash = 147, + CrstUniqueStack = 148, + CrstUnresolvedClassLock = 149, + CrstUnwindInfoTableLock = 150, + CrstVSDIndirectionCellLock = 151, + CrstWinRTFactoryCache = 152, + CrstWrapperTemplate = 153, + kNumberOfCrstTypes = 154 }; #endif // __CRST_TYPES_INCLUDED @@ -235,7 +234,6 @@ int g_rgCrstLevelMap[] = 7, // CrstFuncPtrStubs 5, // CrstFusionAppCtx 11, // CrstGCCover - 0, // CrstGCMemoryPressure 13, // CrstGlobalStrLiteralMap 1, // CrstHandleTable 0, // CrstHostAssemblyMap @@ -395,7 +393,6 @@ LPCSTR g_rgCrstNameMap[] = "CrstFuncPtrStubs", "CrstFusionAppCtx", "CrstGCCover", - "CrstGCMemoryPressure", "CrstGlobalStrLiteralMap", "CrstHandleTable", "CrstHostAssemblyMap", diff --git a/src/coreclr/src/inc/daccess.h b/src/coreclr/src/inc/daccess.h index 2c68abff92c180..f2b37c32db7494 100644 --- a/src/coreclr/src/inc/daccess.h +++ b/src/coreclr/src/inc/daccess.h @@ -629,6 +629,9 @@ typedef struct _DacGlobals ULONG fn__Unknown_AddRefSpecial; ULONG fn__Unknown_AddRefInner; #endif +#ifdef FEATURE_COMWRAPPERS + ULONG fn__ManagedObjectWrapper_QueryInterface; +#endif // Vtable pointer values for all classes that must // be instanted using vtable pointers as the identity. diff --git a/src/coreclr/src/inc/eventtracebase.h b/src/coreclr/src/inc/eventtracebase.h index a02d8f5fbda696..340c7b0a8fc7be 100644 --- a/src/coreclr/src/inc/eventtracebase.h +++ b/src/coreclr/src/inc/eventtracebase.h @@ -109,7 +109,7 @@ enum EtwThreadFlags #if defined(FEATURE_PERFTRACING) #define ETW_INLINE #define ETWOnStartup(StartEventName, EndEventName) -#define ETWFireEvent(EventName) +#define ETWFireEvent(EventName) FireEtw##EventName(GetClrInstanceId()) #define ETW_TRACING_INITIALIZED(RegHandle) (TRUE) #define ETW_EVENT_ENABLED(Context, EventDescriptor) (EventPipeHelper::IsEnabled(Context, EventDescriptor.Level, EventDescriptor.Keyword) || \ diff --git a/src/coreclr/src/inc/ex.h b/src/coreclr/src/inc/ex.h index 21ce9d3d4b0ec7..6d008c6febecf2 100644 --- a/src/coreclr/src/inc/ex.h +++ b/src/coreclr/src/inc/ex.h @@ -278,17 +278,13 @@ class Exception }; #if 1 -template -inline void Exception__Delete(T* pvMemory); -template <> -inline void Exception__Delete(Exception* pvMemory) +inline void Exception__Delete(Exception* pvMemory) { Exception::Delete(pvMemory); } -NEW_WRAPPER_TEMPLATE1(ExceptionHolderTemplate, Exception__Delete<_TYPE>); -typedef ExceptionHolderTemplate ExceptionHolder; +using ExceptionHolder = SpecializedWrapper; #else //------------------------------------------------------------------------------ @@ -710,93 +706,17 @@ class CAutoTryCleanup EX_RETHROW; \ } \ -// Don't use this - use RethrowCorruptingExceptions (see below) instead. #define SwallowAllExceptions ; -////////////////////////////////////////////////////////////////////// -// -// Corrupted State Exception Support -// -///////////////////////////////////////////////////////////////////// - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - -#define CORRUPTING_EXCEPTIONS_ONLY(expr) expr -#define COMMA_CORRUPTING_EXCEPTIONS_ONLY(expr) ,expr - -// EX_END_CATCH has been modified to not swallow Corrupting Exceptions (CE) when one of the -// following arguments are passed to it: -// -// 1) RethrowTerminalExceptions - rethrows both terminal and corrupting exceptions -// 2) RethrowCorruptingExceptions - swallows all exceptions exception corrupting exceptions. This SHOULD BE USED instead of SwallowAllExceptions. -// 3) RethrowTerminalExceptionsEx - same as (1) but rethrow of CE can be controlled via a condition. -// 4) RethrowCorruptingExceptionsEx - same as (2) but rethrow of CE can be controlled via a condition. -// -// By default, if a CE is encountered when one of the above policies are applied, the runtime will -// ensure that the CE propagates up the stack and not get swallowed unless the developer chooses to override the behaviour. -// This can be done by using the "Ex" versions above that take a conditional which evaluates to a BOOL. In such a case, -// the CE will *only* be rethrown if the conditional evalutes to TRUE. For examples, refer to COMToCLRWorker or -// DispatchInfo::InvokeMember implementations. -// -// SET_CE_RETHROW_FLAG_FOR_EX_CATCH macros helps evaluate if the CE is to be rethrown or not. This has been redefined in -// Clrex.h to add the condition of evaluating the throwable as well (which is not available outside the VM folder). -// -// Passing FALSE as the second argument to IsProcessCorruptedStateException implies that SET_CE_RETHROW_FLAG_FOR_EX_CATCH -// will ensure that we dont rethrow SO and allow EX_ENDTRY to SO specific processing. If none is done, then EX_ENDTRY will -// rethrow SO. By that time stack has been reclaimed and thus, throwing SO will be safe. -// -// We also check the global override flag incase it has been set to force pre-V4 beahviour. "0" implies it has not -// been overriden. -#define SET_CE_RETHROW_FLAG_FOR_EX_CATCH(expr) ((((expr) == TRUE) && \ - (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_legacyCorruptedStateExceptionsPolicy) == 0) && \ - IsProcessCorruptedStateException(GetCurrentExceptionCode(), FALSE))) - -// This rethrow policy can be used in EX_END_CATCH to swallow all exceptions except the corrupting ones. -// This macro can be used to rethrow the CE based upon a BOOL condition. -#define RethrowCorruptingExceptionsEx(expr) \ - if (SET_CE_RETHROW_FLAG_FOR_EX_CATCH(expr)) \ - { \ - STATIC_CONTRACT_THROWS_TERMINAL; \ - EX_RETHROW; \ - } - -#define RethrowCorruptingExceptionsExAndHookRethrow(shouldRethrowExpr, aboutToRethrowExpr) \ - if (SET_CE_RETHROW_FLAG_FOR_EX_CATCH(shouldRethrowExpr)) \ - { \ - STATIC_CONTRACT_THROWS_TERMINAL; \ - aboutToRethrowExpr; \ - EX_RETHROW; \ - } - -#else // !FEATURE_CORRUPTING_EXCEPTIONS - -#define CORRUPTING_EXCEPTIONS_ONLY(expr) -#define COMMA_CORRUPTING_EXCEPTIONS_ONLY(expr) - -// When we dont have support for CE, just map it to SwallowAllExceptions -#define RethrowCorruptingExceptionsEx(expr) SwallowAllExceptions -#define RethrowCorruptingExceptionsExAndHookRethrow(shouldRethrowExpr, aboutToRethrowExpr) SwallowAllExceptions -#define SET_CE_RETHROW_FLAG_FOR_EX_CATCH(expr) !TRUE -#endif // FEATURE_CORRUPTING_EXCEPTIONS - -// Map to RethrowCorruptingExceptionsEx so that it does the "right" thing -#define RethrowCorruptingExceptions RethrowCorruptingExceptionsEx(TRUE) - -// This macro can be used to rethrow the CE based upon a BOOL condition. It will continue to rethrow terminal -// exceptions unconditionally. -#define RethrowTerminalExceptionsEx(expr) \ - if (GET_EXCEPTION()->IsTerminal() || \ - SET_CE_RETHROW_FLAG_FOR_EX_CATCH(expr)) \ +// When applied to EX_END_CATCH, this policy will always rethrow Terminal exceptions if they are +// encountered. +#define RethrowTerminalExceptions \ + if (GET_EXCEPTION()->IsTerminal()) \ { \ STATIC_CONTRACT_THROWS_TERMINAL; \ EX_RETHROW; \ } \ - -// When applied to EX_END_CATCH, this policy will always rethrow Terminal and Corrupting exceptions if they are -// encountered. -#define RethrowTerminalExceptions RethrowTerminalExceptionsEx(TRUE) - // Special define to be used in EEStartup that will also check for VM initialization before // commencing on a path that may use the managed thread object. #define RethrowTerminalExceptionsWithInitCheck \ diff --git a/src/coreclr/src/inc/gcrefmap.h b/src/coreclr/src/inc/gcrefmap.h index 5961162582faa9..d2ba660f259ca2 100644 --- a/src/coreclr/src/inc/gcrefmap.h +++ b/src/coreclr/src/inc/gcrefmap.h @@ -100,6 +100,8 @@ class GCRefMapBuilder int posDelta = pos - m_Pos; m_Pos = pos + 1; + _ASSERTE(posDelta >= 0); + if (posDelta != 0) { if (posDelta < 4) diff --git a/src/coreclr/src/inc/holder.h b/src/coreclr/src/inc/holder.h index c1f86b1ee0ff84..a5781d5570ddea 100644 --- a/src/coreclr/src/inc/holder.h +++ b/src/coreclr/src/inc/holder.h @@ -824,84 +824,68 @@ class Wrapper : public BaseWrapper, #define INDEBUG_AND_WINDOWS_FOR_HOLDERS(x) #endif -//--------------------------------------------------------------------------------------- -// -// New template wrapper type macros. These save some effort when specializing -// existing holder templates. (We would rather use a construct like: -// -// template -// typedef Holder<...> NewHolder; -// -// But this construct doesn't exist in C++. These macros ease some of the cruft necessary -// to get similar functionality out of class templates. -//----------------------------------------------------------------------------- +template +class SpecializedWrapper : public Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL> +{ + using BaseT = Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL>; +public: + FORCEINLINE SpecializedWrapper() : BaseT(NULL, FALSE) + { + STATIC_CONTRACT_WRAPPER; + INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) + } + FORCEINLINE SpecializedWrapper(_TYPE* value) : BaseT(value) + { + STATIC_CONTRACT_WRAPPER; + INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) + } + FORCEINLINE SpecializedWrapper(_TYPE* value, BOOL takeOwnership) : BaseT(value, takeOwnership) + { + STATIC_CONTRACT_WRAPPER; + INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) + } + FORCEINLINE ~SpecializedWrapper() + { + } -// Dev10 VC++ has some of the new C++0x language extensions. Of particular interest here: -// rvalue references, which enables differentiation between named (lvalue) and -// temporary (rvalue) object references, enabling move semantics and perfect forwarding. -// See http://msdn.microsoft.com/en-us/library/dd293668.aspx for more information. - -// Enable copy construction and assignment from temporary objects. This permits Wrapper objects -// to be returned from methods, and for move assignment. -#define NEW_WRAPPER_TEMPLATE_RVALREF_METHODS(_NAME) \ - public: \ - FORCEINLINE _NAME(_NAME && other) \ - : BaseT(NULL, FALSE) \ - { \ - STATIC_CONTRACT_WRAPPER; \ - INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \ - *this = std::move(other); \ - } \ - FORCEINLINE _NAME& operator=(_NAME && other) \ - { \ - std::swap(BaseT::m_value, other.BaseT::m_value); \ - std::swap(BaseT::m_acquired, other.BaseT::m_acquired); \ - return *this; \ - } + SpecializedWrapper(SpecializedWrapper const &) = delete; + SpecializedWrapper & operator=(SpecializedWrapper const &) = delete; -#define NEW_WRAPPER_TEMPLATE1(_NAME, _RELEASEF) \ - template \ - class _NAME : public Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL> \ - { \ - typedef Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL> BaseT; \ - public: \ - FORCEINLINE _NAME() : BaseT(NULL, FALSE) \ - { \ - STATIC_CONTRACT_WRAPPER; \ - INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \ - } \ - FORCEINLINE _NAME(_TYPE* value) : BaseT(value) \ - { \ - STATIC_CONTRACT_WRAPPER; \ - INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \ - } \ - FORCEINLINE _NAME(_TYPE* value, BOOL takeOwnership) : BaseT(value, takeOwnership) \ - { \ - STATIC_CONTRACT_WRAPPER; \ - INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \ - } \ - FORCEINLINE ~_NAME() \ - { \ - } \ - FORCEINLINE _NAME& operator=(_TYPE * value) \ - { \ - STATIC_CONTRACT_WRAPPER; \ - BaseT::operator=(value); \ - return *this; \ - } \ - /* Since operator& is overloaded we need a way to get a type safe this pointer. */ \ - FORCEINLINE _NAME* GetAddr() \ - { \ - STATIC_CONTRACT_LEAF; \ - return this; \ - } \ - NEW_WRAPPER_TEMPLATE_RVALREF_METHODS(_NAME) \ - HIDE_GENERATED_METHODS(_NAME) \ - private: \ - /* m_ppValue: Do not use from source code: Only for convenient use from debugger */ \ - /* watch windows - saves five mouseclicks when inspecting holders. */ \ - INDEBUG_AND_WINDOWS_FOR_HOLDERS(_TYPE ** m_pvalue;) \ - }; + FORCEINLINE SpecializedWrapper& operator=(_TYPE * value) + { + STATIC_CONTRACT_WRAPPER; + BaseT::operator=(value); + return *this; + } + + FORCEINLINE SpecializedWrapper(SpecializedWrapper && other) + : BaseT(NULL, FALSE) + { + STATIC_CONTRACT_WRAPPER; + INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) + *this = std::move(other); + } + + FORCEINLINE SpecializedWrapper& operator=(SpecializedWrapper && other) + { + BaseT::m_value = std::move(other.BaseT::m_value); + BaseT::m_acquired = std::move(other.BaseT::m_acquired); + other.BaseT::m_value = nullptr; + other.BaseT::m_acquired = FALSE; + return *this; + } + + /* Since operator& is overloaded we need a way to get a type safe this pointer. */ + FORCEINLINE SpecializedWrapper* GetAddr() + { + STATIC_CONTRACT_LEAF; + return this; + } + private: + /* m_ppValue: Do not use from source code: Only for convenient use from debugger */ + /* watch windows - saves five mouseclicks when inspecting holders. */ + INDEBUG_AND_WINDOWS_FOR_HOLDERS(_TYPE ** m_pvalue;) +}; //----------------------------------------------------------------------------- // NOTE: THIS IS UNSAFE TO USE IN THE VM for interop COM objects!! @@ -930,11 +914,14 @@ FORCEINLINE void DoTheRelease(TYPE *value) } } -NEW_WRAPPER_TEMPLATE1(DoNothingHolder, DoNothing<_TYPE*>); +template +using DoNothingHolder = SpecializedWrapper<_TYPE, DoNothing<_TYPE*>>; -NEW_WRAPPER_TEMPLATE1(ReleaseHolder, DoTheRelease<_TYPE>); +template +using ReleaseHolder = SpecializedWrapper<_TYPE, DoTheRelease<_TYPE>>; -NEW_WRAPPER_TEMPLATE1(NonVMComHolder, DoTheRelease<_TYPE>); +template +using NonVMComHolder = SpecializedWrapper<_TYPE, DoTheRelease<_TYPE>>; //----------------------------------------------------------------------------- @@ -957,7 +944,8 @@ FORCEINLINE void StubRelease(TYPE* value) value->DecRef(); } -NEW_WRAPPER_TEMPLATE1(StubHolder, StubRelease<_TYPE>); +template +using StubHolder = SpecializedWrapper<_TYPE, StubRelease<_TYPE>>; //----------------------------------------------------------------------------- // CoTaskMemHolder : CoTaskMemAlloc allocated memory holder @@ -974,7 +962,8 @@ FORCEINLINE void DeleteCoTaskMem(TYPE *value) CoTaskMemFree(value); } -NEW_WRAPPER_TEMPLATE1(CoTaskMemHolder, DeleteCoTaskMem<_TYPE>); +template +using CoTaskMemHolder = SpecializedWrapper<_TYPE, DeleteCoTaskMem<_TYPE>>; //----------------------------------------------------------------------------- // NewHolder : New'ed memory holder @@ -997,7 +986,8 @@ FORCEINLINE void Delete(TYPE *value) delete value; } -NEW_WRAPPER_TEMPLATE1(NewHolder, Delete<_TYPE>); +template +using NewHolder = SpecializedWrapper<_TYPE, Delete<_TYPE>>; //----------------------------------------------------------------------------- // NewExecutableHolder : New'ed memory holder for executable memory. @@ -1009,7 +999,8 @@ NEW_WRAPPER_TEMPLATE1(NewHolder, Delete<_TYPE>); // IJW template void DeleteExecutable(T *p); -NEW_WRAPPER_TEMPLATE1(NewExecutableHolder, DeleteExecutable<_TYPE>); +template +using NewExecutableHolder = SpecializedWrapper<_TYPE, DeleteExecutable<_TYPE>>; //----------------------------------------------------------------------------- // NewArrayHolder : New []'ed pointer holder @@ -1026,7 +1017,8 @@ FORCEINLINE void DeleteArray(TYPE *value) value = NULL; } -NEW_WRAPPER_TEMPLATE1(NewArrayHolder, DeleteArray<_TYPE>); +template +using NewArrayHolder = SpecializedWrapper<_TYPE, DeleteArray<_TYPE>>; typedef NewArrayHolder AStringHolder; typedef NewArrayHolder WStringHolder; @@ -1113,8 +1105,10 @@ namespace detail } #undef VISIBLE -NEW_WRAPPER_TEMPLATE1(ResetPointerHolder, detail::ZeroMem<_TYPE>::Invoke); -NEW_WRAPPER_TEMPLATE1(FieldNuller, detail::ZeroMem<_TYPE>::Invoke); +template +using ResetPointerHolder = SpecializedWrapper<_TYPE, detail::ZeroMem<_TYPE>::Invoke>; +template +using FieldNuller = SpecializedWrapper<_TYPE, detail::ZeroMem<_TYPE>::Invoke>; //----------------------------------------------------------------------------- // Wrap win32 functions using HANDLE @@ -1157,7 +1151,8 @@ typedef Wrapper, HolderFreeLibrary, NULL> HModuleHol template FORCEINLINE void DoLocalFree(T* pMem) { (LocalFree)((HLOCAL)pMem); } -NEW_WRAPPER_TEMPLATE1(LocalAllocHolder, DoLocalFree<_TYPE>); +template +using LocalAllocHolder = SpecializedWrapper<_TYPE, DoLocalFree<_TYPE>>; inline void BoolSet( _Out_ bool * val ) { *val = true; } inline void BoolUnset( _Out_ bool * val ) { *val = false; } diff --git a/src/coreclr/src/inc/jithelpers.h b/src/coreclr/src/inc/jithelpers.h index 9add356aa90514..608398ac17ef2c 100644 --- a/src/coreclr/src/inc/jithelpers.h +++ b/src/coreclr/src/inc/jithelpers.h @@ -220,11 +220,15 @@ JITHELPER(CORINFO_HELP_PINVOKE_CALLI, GenericPInvokeCalliHelper, CORINFO_HELP_SIG_NO_ALIGN_STUB) +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) JITHELPER(CORINFO_HELP_TAILCALL, JIT_TailCall, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) +#else + JITHELPER(CORINFO_HELP_TAILCALL, NULL, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) +#endif JITHELPER(CORINFO_HELP_GETCURRENTMANAGEDTHREADID, JIT_GetCurrentManagedThreadId, CORINFO_HELP_SIG_REG_ONLY) -#ifdef HOST_64BIT +#ifdef TARGET_64BIT JITHELPER(CORINFO_HELP_INIT_PINVOKE_FRAME, JIT_InitPInvokeFrame, CORINFO_HELP_SIG_REG_ONLY) #else DYNAMICJITHELPER(CORINFO_HELP_INIT_PINVOKE_FRAME, NULL, CORINFO_HELP_SIG_REG_ONLY) diff --git a/src/coreclr/src/md/inc/mdfileformat.h b/src/coreclr/src/inc/mdfileformat.h similarity index 99% rename from src/coreclr/src/md/inc/mdfileformat.h rename to src/coreclr/src/inc/mdfileformat.h index 8d217819aba462..b414b0cc1d3322 100644 --- a/src/coreclr/src/md/inc/mdfileformat.h +++ b/src/coreclr/src/inc/mdfileformat.h @@ -14,6 +14,9 @@ #ifndef __MDFileFormat_h__ #define __MDFileFormat_h__ +#include +#include "utilcode.h" + //***************************************************************************** // The signature ULONG is the first 4 bytes of the file format. The second // signature string starts the header containing the stream list. It is used diff --git a/src/coreclr/src/inc/metadata.h b/src/coreclr/src/inc/metadata.h index b78988102fb619..662a77ea4d9d5f 100644 --- a/src/coreclr/src/inc/metadata.h +++ b/src/coreclr/src/inc/metadata.h @@ -14,9 +14,11 @@ #ifndef _METADATA_H_ #define _METADATA_H_ -#include "../md/inc/metamodelro.h" -#include "../md/inc/liteweightstgdb.h" +#include "ex.h" +class CorProfileData; +class IMetaModelCommon; +class MDInternalRW; class UTSemReadWrite; inline int IsGlobalMethodParentTk(mdTypeDef td) @@ -1123,8 +1125,12 @@ DECLARE_INTERFACE_(IMDInternalEmit, IUnknown) #ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE struct IMDCustomDataSource; - -#include "../md/inc/metamodel.h" +class CMiniMdSchema; +struct CMiniTableDef; +namespace MetaData +{ + class DataBlob; +} // {CC0C8F7A-A00B-493D-80B6-CE0C92491670} EXTERN_GUID(IID_IMDCustomDataSource, 0xcc0c8f7a, 0xa00b, 0x493d, 0x80, 0xb6, 0xce, 0xc, 0x92, 0x49, 0x16, 0x70); @@ -1168,6 +1174,37 @@ struct ICorDebugDataTarget; HRESULT CreateRemoteMDInternalRWSource(TADDR mdInternalRWRemoteAddress, ICorDebugDataTarget* pDataTarget, DWORD defines, DWORD dataStructureVersion, IMDCustomDataSource** ppDataSource); #endif +enum MetaDataReorderingOptions { + NoReordering=0x0, + ReArrangeStringPool=0x1 +}; + +#ifdef FEATURE_PREJIT + +// {0702E333-8D64-4ca7-B564-4AA56B1FCEA3} +EXTERN_GUID(IID_IMetaDataCorProfileData, 0x702e333, 0x8d64, 0x4ca7, 0xb5, 0x64, 0x4a, 0xa5, 0x6b, 0x1f, 0xce, 0xa3 ); + +#undef INTERFACE +#define INTERFACE IMetaDataCorProfileData +DECLARE_INTERFACE_(IMetaDataCorProfileData, IUnknown) +{ + STDMETHOD(SetCorProfileData)( + CorProfileData *pProfileData) PURE; // [IN] Pointer to profile data +}; + +// {2B464817-C0F6-454e-99E7-C352D8384D7B} +EXTERN_GUID(IID_IMDInternalMetadataReorderingOptions, 0x2B464817, 0xC0F6, 0x454e, 0x99, 0xE7, 0xC3, 0x52, 0xD8, 0x38, 0x4D, 0x7B ); + +#undef INTERFACE +#define INTERFACE IMDInternalMetadataReorderingOptions +DECLARE_INTERFACE_(IMDInternalMetadataReorderingOptions, IUnknown) +{ + STDMETHOD(SetMetaDataReorderingOptions)( + MetaDataReorderingOptions options) PURE; // [IN] metadata reordering options +}; + +#endif //FEATURE_PREJIT + #ifdef __HOLDER_H_ void DECLSPEC_NORETURN ThrowHR(HRESULT hr); diff --git a/src/coreclr/src/inc/metamodelpub.h b/src/coreclr/src/inc/metamodelpub.h index 0762598a286307..83cc9c6a32f7a9 100644 --- a/src/coreclr/src/inc/metamodelpub.h +++ b/src/coreclr/src/inc/metamodelpub.h @@ -16,7 +16,8 @@ #endif #include -#include +#include "contract.h" + #ifndef lengthof # define lengthof(x) (sizeof(x)/sizeof((x)[0])) diff --git a/src/coreclr/src/inc/pedecoder.h b/src/coreclr/src/inc/pedecoder.h index ad0e77e532c157..c4f4e92b6b613a 100644 --- a/src/coreclr/src/inc/pedecoder.h +++ b/src/coreclr/src/inc/pedecoder.h @@ -95,6 +95,8 @@ inline CHECK CheckOverflow(RVA value1, COUNT_T value2) #define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x7B79 #elif defined(__NetBSD__) #define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x1993 +#elif defined(__sun) +#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x1992 #else #define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0 #endif diff --git a/src/coreclr/src/inc/readytoruninstructionset.h b/src/coreclr/src/inc/readytoruninstructionset.h index 6e6f2549f90440..77f1cd267672ed 100644 --- a/src/coreclr/src/inc/readytoruninstructionset.h +++ b/src/coreclr/src/inc/readytoruninstructionset.h @@ -32,6 +32,7 @@ enum ReadyToRunInstructionSet READYTORUN_INSTRUCTION_Sha1=19, READYTORUN_INSTRUCTION_Sha256=20, READYTORUN_INSTRUCTION_Atomics=21, + READYTORUN_INSTRUCTION_X86Base=22, }; diff --git a/src/coreclr/src/inc/sstring.h b/src/coreclr/src/inc/sstring.h index a0459174587317..8de0cd3d4277a9 100644 --- a/src/coreclr/src/inc/sstring.h +++ b/src/coreclr/src/inc/sstring.h @@ -45,6 +45,7 @@ #include "utilcode.h" #include "sbuffer.h" +#include "debugmacros.h" // ========================================================================================== // Documentational typedefs: use these to indicate specific representations of 8 bit strings: @@ -808,6 +809,7 @@ template class EMPTY_BASES_DECL InlineSString : public SString { private: + DAC_ALIGNAS(SString) BYTE m_inline[SBUFFER_PADDED_SIZE(MEMSIZE)]; public: @@ -990,6 +992,7 @@ template class EMPTY_BASES_DECL ScratchBuffer : public SString::AbstractScratchBuffer { private: + DAC_ALIGNAS(::SString::AbstractScratchBuffer) BYTE m_inline[MEMSIZE]; public: diff --git a/src/coreclr/src/inc/stgpool.h b/src/coreclr/src/inc/stgpool.h index f86354b1050005..d9a84c360b2a2b 100644 --- a/src/coreclr/src/inc/stgpool.h +++ b/src/coreclr/src/inc/stgpool.h @@ -30,8 +30,6 @@ #include "memoryrange.h" #include "../md/hotdata/hotheap.h" -#include "../md/debug_metadata.h" - //***************************************************************************** // NOTE: // One limitation with the pools, we have no way to removing strings from diff --git a/src/coreclr/src/inc/strongnameholders.h b/src/coreclr/src/inc/strongnameholders.h index ecec99432af1bb..d684e9d3a032ae 100644 --- a/src/coreclr/src/inc/strongnameholders.h +++ b/src/coreclr/src/inc/strongnameholders.h @@ -18,6 +18,7 @@ void VoidStrongNameFreeBuffer(__in T *pBuffer) { StrongNameFreeBuffer(reinterpret_cast(pBuffer)); } -NEW_WRAPPER_TEMPLATE1(StrongNameBufferHolder, VoidStrongNameFreeBuffer<_TYPE>); +template +using StrongNameBufferHolder = SpecializedWrapper<_TYPE, VoidStrongNameFreeBuffer<_TYPE>>; #endif // !__STRONGNAME_HOLDERS_H__ diff --git a/src/coreclr/src/inc/utilcode.h b/src/coreclr/src/inc/utilcode.h index 1721db03dc01f4..15902ef99e9761 100644 --- a/src/coreclr/src/inc/utilcode.h +++ b/src/coreclr/src/inc/utilcode.h @@ -2573,6 +2573,7 @@ template class CHashTableAndData : public CHashTable { public: + DAC_ALIGNAS(CHashTable) ULONG m_iFree; // Index into m_pcEntries[] of next available slot ULONG m_iEntries; // size of m_pcEntries[] @@ -4715,13 +4716,6 @@ BOOL IsIPInModule(HMODULE_TGT hModule, PCODE ip); extern HINSTANCE g_hmodCoreCLR; -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - -// Corrupting Exception limited support for outside the VM folder -BOOL IsProcessCorruptedStateException(DWORD dwExceptionCode, BOOL fCheckForSO = TRUE); - -#endif // FEATURE_CORRUPTING_EXCEPTIONS - namespace UtilCode { // These are type-safe versions of Interlocked[Compare]Exchange diff --git a/src/coreclr/src/inc/volatile.h b/src/coreclr/src/inc/volatile.h index 960e33cc982aa6..6c73dc4c65667b 100644 --- a/src/coreclr/src/inc/volatile.h +++ b/src/coreclr/src/inc/volatile.h @@ -286,6 +286,27 @@ void VolatileStoreWithoutBarrier(T* pt, T val) #endif } +// +// Memory ordering barrier that waits for loads in progress to complete. +// Any effects of loads or stores that appear after, in program order, will "happen after" relative to this. +// Other operations such as computation or instruction prefetch are not affected. +// +// Architectural mapping: +// arm64 : dmb ishld +// arm : dmb ish +// x86/64 : compiler fence +inline +void VolatileLoadBarrier() +{ +#if defined(HOST_ARM64) && defined(__GNUC__) + asm volatile ("dmb ishld" : : : "memory"); +#elif defined(HOST_ARM64) && defined(_MSC_VER) + __dmb(_ARM64_BARRIER_ISHLD); +#else + VOLATILE_MEMORY_BARRIER(); +#endif +} + // // Volatile implements accesses with our volatile semantics over a variable of type T. // Wherever you would have used a "volatile Foo" or, equivalently, "Foo volatile", use Volatile diff --git a/src/coreclr/src/inc/vptr_list.h b/src/coreclr/src/inc/vptr_list.h index 93e978224947d1..f53bbac1edf1e4 100644 --- a/src/coreclr/src/inc/vptr_list.h +++ b/src/coreclr/src/inc/vptr_list.h @@ -39,7 +39,9 @@ VPTR_CLASS(RangeSectionStubManager) VPTR_CLASS(ILStubManager) VPTR_CLASS(InteropDispatchStubManager) VPTR_CLASS(DelegateInvokeStubManager) +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) VPTR_CLASS(TailCallStubManager) +#endif VPTR_CLASS(CallCountingStubManager) VPTR_CLASS(PEFile) VPTR_CLASS(PEAssembly) @@ -93,7 +95,9 @@ VPTR_CLASS(DynamicHelperFrame) #if defined(TARGET_X86) VPTR_CLASS(UMThkCallFrame) #endif +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) VPTR_CLASS(TailCallFrame) +#endif VPTR_CLASS(ExceptionFilterFrame) #ifdef _DEBUG diff --git a/src/coreclr/src/interop/comwrappers.cpp b/src/coreclr/src/interop/comwrappers.cpp index 60d80910a5078b..3fb1b7941ed758 100644 --- a/src/coreclr/src/interop/comwrappers.cpp +++ b/src/coreclr/src/interop/comwrappers.cpp @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. #include "comwrappers.hpp" +#include #include #include // placement new @@ -47,8 +48,8 @@ namespace ABI }; ABI_ASSERT(sizeof(ComInterfaceDispatch) == sizeof(void*)); - const size_t DispatchAlignmentThisPtr = 16; // Should be a power of 2. - const intptr_t DispatchThisPtrMask = ~(DispatchAlignmentThisPtr - 1); + using InteropLib::ABI::DispatchAlignmentThisPtr; + using InteropLib::ABI::DispatchThisPtrMask; ABI_ASSERT(sizeof(void*) < DispatchAlignmentThisPtr); const intptr_t AlignmentThisPtrMaxPadding = DispatchAlignmentThisPtr - sizeof(void*); @@ -179,17 +180,20 @@ namespace ABI } } -namespace +// ManagedObjectWrapper_QueryInterface needs to be visible outside of this compilation unit +// to support the DAC. See code:ClrDataAccess::DACTryGetComWrappersObjectFromCCW for the +// usage in the DAC (look for the GetEEFuncEntryPoint call). +HRESULT STDMETHODCALLTYPE ManagedObjectWrapper_QueryInterface( + _In_ ABI::ComInterfaceDispatch* disp, + /* [in] */ REFIID riid, + /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject) { - HRESULT STDMETHODCALLTYPE ManagedObjectWrapper_QueryInterface( - _In_ ABI::ComInterfaceDispatch* disp, - /* [in] */ REFIID riid, - /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject) - { - ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp); - return wrapper->QueryInterface(riid, ppvObject); - } + ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp); + return wrapper->QueryInterface(riid, ppvObject); +} +namespace +{ ULONG STDMETHODCALLTYPE ManagedObjectWrapper_AddRef(_In_ ABI::ComInterfaceDispatch* disp) { ManagedObjectWrapper* wrapper = ABI::ToManagedObjectWrapper(disp); @@ -310,6 +314,7 @@ void ManagedObjectWrapper::GetIUnknownImpl( *fpRelease = ManagedObjectWrapper_IUnknownImpl.Release; } +// The logic here should match code:ClrDataAccess::DACTryGetComWrappersObjectFromCCW in daccess/request.cpp ManagedObjectWrapper* ManagedObjectWrapper::MapFromIUnknown(_In_ IUnknown* pUnk) { _ASSERTE(pUnk != nullptr); diff --git a/src/coreclr/src/interop/inc/interoplibabi.h b/src/coreclr/src/interop/inc/interoplibabi.h new file mode 100644 index 00000000000000..19a1e0c01e7556 --- /dev/null +++ b/src/coreclr/src/interop/inc/interoplibabi.h @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include + +namespace InteropLib +{ + namespace ABI + { + const size_t DispatchAlignmentThisPtr = 16; // Should be a power of 2. + const intptr_t DispatchThisPtrMask = ~(DispatchAlignmentThisPtr - 1); + } +} diff --git a/src/coreclr/src/jit/CMakeLists.txt b/src/coreclr/src/jit/CMakeLists.txt index 034cdbe38dcd48..a3f0b1aeb2e0d0 100644 --- a/src/coreclr/src/jit/CMakeLists.txt +++ b/src/coreclr/src/jit/CMakeLists.txt @@ -170,6 +170,7 @@ if (CLR_CMAKE_TARGET_WIN32) regset.h sideeffects.h simd.h + simdashwintrinsic.h simdintrinsiclist.h sm.h smallhash.h @@ -204,14 +205,16 @@ if (CLR_CMAKE_TARGET_WIN32) instrsarm.h instrsarm64.h registerarm.h - registerarm64.h) + registerarm64.h + simdashwintrinsiclistarm64.h) elseif (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386) list (APPEND JIT_HEADERS emitfmtsxarch.h emitxarch.h hwintrinsiclistxarch.h hwintrinsic.h - instrsxarch.h) + instrsxarch.h + simdashwintrinsiclistxarch.h) endif () endif(CLR_CMAKE_TARGET_WIN32) @@ -223,6 +226,7 @@ set( JIT_AMD64_SOURCES lowerxarch.cpp lsraxarch.cpp simd.cpp + simdashwintrinsic.cpp simdcodegenxarch.cpp targetamd64.cpp unwindamd64.cpp @@ -249,6 +253,7 @@ set( JIT_I386_SOURCES lowerxarch.cpp lsraxarch.cpp simd.cpp + simdashwintrinsic.cpp simdcodegenxarch.cpp targetx86.cpp unwindx86.cpp @@ -264,6 +269,7 @@ set( JIT_ARM64_SOURCES lsraarmarch.cpp lsraarm64.cpp simd.cpp + simdashwintrinsic.cpp targetarm64.cpp unwindarm.cpp unwindarm64.cpp @@ -312,11 +318,15 @@ else() set(JIT_EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/clrjit.exports) generate_exports_file(${CLRJIT_EXPORTS} ${JIT_EXPORTS_FILE}) - if(CLR_CMAKE_TARGET_LINUX OR CLR_CMAKE_TARGET_FREEBSD OR CLR_CMAKE_TARGET_NETBSD) + if(CLR_CMAKE_TARGET_LINUX OR CLR_CMAKE_TARGET_FREEBSD OR CLR_CMAKE_TARGET_NETBSD OR CLR_CMAKE_TARGET_SUNOS) # This is required to force using our own PAL, not one that we are loaded with. set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Xlinker -Bsymbolic") - set(JIT_EXPORTS_LINKER_OPTION -Wl,--version-script=${JIT_EXPORTS_FILE}) + if(CLR_CMAKE_TARGET_SUNOS) + set(JIT_EXPORTS_LINKER_OPTION -Wl,-M,${JIT_EXPORTS_FILE}) + else(CLR_CMAKE_TARGET_SUNOS) + set(JIT_EXPORTS_LINKER_OPTION -Wl,--version-script=${JIT_EXPORTS_FILE}) + endif(CLR_CMAKE_TARGET_SUNOS) elseif(CLR_CMAKE_TARGET_OSX) set(JIT_EXPORTS_LINKER_OPTION -Wl,-exported_symbols_list,${JIT_EXPORTS_FILE}) endif() diff --git a/src/coreclr/src/jit/ICorJitInfo_API_names.h b/src/coreclr/src/jit/ICorJitInfo_API_names.h index a65c6c79c904db..b2f623ac96fb19 100644 --- a/src/coreclr/src/jit/ICorJitInfo_API_names.h +++ b/src/coreclr/src/jit/ICorJitInfo_API_names.h @@ -151,7 +151,7 @@ DEF_CLR_API(setOverride) DEF_CLR_API(addActiveDependency) DEF_CLR_API(GetDelegateCtor) DEF_CLR_API(MethodCompileComplete) -DEF_CLR_API(getTailCallCopyArgsThunk) +DEF_CLR_API(getTailCallHelpers) DEF_CLR_API(convertPInvokeCalliToCall) DEF_CLR_API(notifyInstructionSetUsage) DEF_CLR_API(getMemoryManager) diff --git a/src/coreclr/src/jit/ICorJitInfo_API_wrapper.hpp b/src/coreclr/src/jit/ICorJitInfo_API_wrapper.hpp index 6e4d016d90c5d7..44e4a3ea1055f1 100644 --- a/src/coreclr/src/jit/ICorJitInfo_API_wrapper.hpp +++ b/src/coreclr/src/jit/ICorJitInfo_API_wrapper.hpp @@ -1476,13 +1476,15 @@ void WrapICorJitInfo::MethodCompileComplete( API_LEAVE(MethodCompileComplete); } -void* WrapICorJitInfo::getTailCallCopyArgsThunk( - CORINFO_SIG_INFO *pSig, - CorInfoHelperTailCallSpecialHandling flags) -{ - API_ENTER(getTailCallCopyArgsThunk); - void *result = wrapHnd->getTailCallCopyArgsThunk(pSig, flags); - API_LEAVE(getTailCallCopyArgsThunk); +void* WrapICorJitInfo::getTailCallHelpers( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult) +{ + API_ENTER(getTailCallHelpers); + void *result = wrapHnd->getTailCallHelpers(callToken, sig, flags, pResult); + API_LEAVE(getTailCallHelpers); return result; } diff --git a/src/coreclr/src/jit/assertionprop.cpp b/src/coreclr/src/jit/assertionprop.cpp index 916921f36cd3f2..031d4867d87cf5 100644 --- a/src/coreclr/src/jit/assertionprop.cpp +++ b/src/coreclr/src/jit/assertionprop.cpp @@ -2108,7 +2108,6 @@ void Compiler::optAssertionGen(GenTree* tree) { // Retrieve the 'this' arg GenTree* thisArg = gtGetThisArg(tree->AsCall()); -#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM) if (thisArg == nullptr) { // For tail calls we lose the this pointer in the argument list but that's OK because a null check @@ -2116,8 +2115,6 @@ void Compiler::optAssertionGen(GenTree* tree) noway_assert(tree->AsCall()->IsTailCall()); break; } -#endif // TARGET_X86 || TARGET_AMD64 || TARGET_ARM - noway_assert(thisArg != nullptr); assertionInfo = optCreateAssertion(thisArg, nullptr, OAK_NOT_EQUAL); } break; @@ -2682,6 +2679,11 @@ GenTree* Compiler::optConstantAssertionProp(AssertionDsc* curAssertion, newTree->ChangeOperConst(GT_CNS_INT); newTree->AsIntCon()->gtIconVal = curAssertion->op2.u1.iconVal; newTree->ClearIconHandleMask(); + if (newTree->TypeIs(TYP_STRUCT)) + { + // LCL_VAR can be init with a GT_CNS_INT, keep its type INT, not STRUCT. + newTree->ChangeType(TYP_INT); + } } // If we're doing an array index address, assume any constant propagated contributes to the index. if (isArrIndex) diff --git a/src/coreclr/src/jit/block.h b/src/coreclr/src/jit/block.h index 5e49bb5c3f366d..6a2c6e86435a7f 100644 --- a/src/coreclr/src/jit/block.h +++ b/src/coreclr/src/jit/block.h @@ -725,7 +725,10 @@ struct BasicBlock : private LIR::Range m_firstNode = tree; } - EntryState* bbEntryState; // verifier tracked state of all entries in stack. + union { + EntryState* bbEntryState; // verifier tracked state of all entries in stack. + flowList* bbLastPred; // last pred list entry + }; #define NO_BASE_TMP UINT_MAX // base# to use when we have none unsigned bbStkTempsIn; // base# for input stack temps diff --git a/src/coreclr/src/jit/codegen.h b/src/coreclr/src/jit/codegen.h index 94201def12d978..d6b53ef475d7a8 100644 --- a/src/coreclr/src/jit/codegen.h +++ b/src/coreclr/src/jit/codegen.h @@ -342,12 +342,12 @@ class CodeGen final : public CodeGenInterface void genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowestCalleeSavedOffset, int spDelta); void genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, int lowestCalleeSavedOffset, int spDelta); - void genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroed); + void genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegModified); #else void genPushCalleeSavedRegisters(); #endif - void genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn); + void genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegModified, regMaskTP maskArgRegsLiveIn); #if defined(TARGET_ARM) @@ -435,18 +435,18 @@ class CodeGen final : public CodeGenInterface void genZeroInitFltRegs(const regMaskTP& initFltRegs, const regMaskTP& initDblRegs, const regNumber& initReg); - regNumber genGetZeroReg(regNumber initReg, bool* pInitRegZeroed); + regNumber genGetZeroReg(regNumber initReg, bool* pInitRegModified); - void genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, bool* pInitRegZeroed); + void genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, bool* pInitRegModified); - void genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed); + void genReportGenericContextArg(regNumber initReg, bool* pInitRegModified); - void genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed); + void genSetGSSecurityCookie(regNumber initReg, bool* pInitRegModified); void genFinalizeFrame(); #ifdef PROFILING_SUPPORTED - void genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed); + void genProfilingEnterCallback(regNumber initReg, bool* pInitRegModified); void genProfilingLeaveCallback(unsigned helper); #endif // PROFILING_SUPPORTED @@ -512,7 +512,7 @@ class CodeGen final : public CodeGenInterface void genFuncletEpilog(); void genCaptureFuncletPrologEpilogInfo(); - void genSetPSPSym(regNumber initReg, bool* pInitRegZeroed); + void genSetPSPSym(regNumber initReg, bool* pInitRegModified); void genUpdateCurrentFunclet(BasicBlock* block); #if defined(TARGET_ARM) @@ -978,7 +978,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void genSIMDIntrinsicInit(GenTreeSIMD* simdNode); void genSIMDIntrinsicInitN(GenTreeSIMD* simdNode); void genSIMDIntrinsicUnOp(GenTreeSIMD* simdNode); - void genSIMDIntrinsicUnOpWithImm(GenTreeSIMD* simdNode); void genSIMDIntrinsicBinOp(GenTreeSIMD* simdNode); void genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode); void genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode); @@ -1028,6 +1027,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void genHWIntrinsic_R_R_R_RM( instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, GenTree* op3); void genBaseIntrinsic(GenTreeHWIntrinsic* node); + void genX86BaseIntrinsic(GenTreeHWIntrinsic* node); void genSSEIntrinsic(GenTreeHWIntrinsic* node); void genSSE2Intrinsic(GenTreeHWIntrinsic* node); void genSSE41Intrinsic(GenTreeHWIntrinsic* node); @@ -1047,6 +1047,59 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX regNumber offsReg, HWIntrinsicSwitchCaseBody emitSwCase); #endif // defined(TARGET_XARCH) + +#ifdef TARGET_ARM64 + class HWIntrinsicImmOpHelper final + { + public: + HWIntrinsicImmOpHelper(CodeGen* codeGen, GenTree* immOp, GenTreeHWIntrinsic* intrin); + + void EmitBegin(); + void EmitCaseEnd(); + + // Returns true after the last call to EmitCaseEnd() (i.e. this signals that code generation is done). + bool Done() const + { + return (immValue > immUpperBound); + } + + // Returns a value of the immediate operand that should be used for a case. + int ImmValue() const + { + return immValue; + } + + private: + // Returns true if immOp is non contained immediate (i.e. the value of the immediate operand is enregistered in + // nonConstImmReg). + bool NonConstImmOp() const + { + return nonConstImmReg != REG_NA; + } + + // Returns true if a non constant immediate operand can be either 0 or 1. + bool TestImmOpZeroOrOne() const + { + assert(NonConstImmOp()); + return (immLowerBound == 0) && (immUpperBound == 1); + } + + emitter* GetEmitter() const + { + return codeGen->GetEmitter(); + } + + CodeGen* const codeGen; + BasicBlock* endLabel; + BasicBlock* nonZeroLabel; + int immValue; + int immLowerBound; + int immUpperBound; + regNumber nonConstImmReg; + regNumber branchTargetReg; + }; +#endif // TARGET_ARM64 + #endif // FEATURE_HW_INTRINSICS #if !defined(TARGET_64BIT) @@ -1060,6 +1113,9 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // Do liveness update for register produced by the current node in codegen after // code has been emitted for it. void genProduceReg(GenTree* tree); + void genSpillLocal(unsigned varNum, var_types type, GenTreeLclVar* lclNode, regNumber regNum); + void genUnspillLocal( + unsigned varNum, var_types type, GenTreeLclVar* lclNode, regNumber regNum, bool reSpill, bool isLastUse); void genUnspillRegIfNeeded(GenTree* tree); regNumber genConsumeReg(GenTree* tree); void genCopyRegIfNeeded(GenTree* tree, regNumber needReg); @@ -1222,10 +1278,13 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void genEHFinallyOrFilterRet(BasicBlock* block); #endif // !FEATURE_EH_FUNCLETS - void genMultiRegCallStoreToLocal(GenTree* treeNode); + void genMultiRegStoreToLocal(GenTree* treeNode); - // Deals with codegen for muti-register struct returns. + // Codegen for multi-register struct returns. bool isStructReturn(GenTree* treeNode); +#ifdef FEATURE_SIMD + void genSIMDSplitReturn(GenTree* src, ReturnTypeDesc* retTypeDesc); +#endif void genStructReturn(GenTree* treeNode); #if defined(TARGET_X86) || defined(TARGET_ARM) @@ -1412,11 +1471,13 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX void instGen_Return(unsigned stkArgSize); -#ifdef TARGET_ARM64 - void instGen_MemoryBarrier(insBarrier barrierType = INS_BARRIER_ISH); -#else - void instGen_MemoryBarrier(); -#endif + enum BarrierKind + { + BARRIER_FULL, // full barrier + BARRIER_LOAD_ONLY, // load barier + }; + + void instGen_MemoryBarrier(BarrierKind barrierKind = BARRIER_FULL); void instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags = INS_FLAGS_DONT_CARE); diff --git a/src/coreclr/src/jit/codegenarm.cpp b/src/coreclr/src/jit/codegenarm.cpp index f4d7f925816ad0..015ac03a68b015 100644 --- a/src/coreclr/src/jit/codegenarm.cpp +++ b/src/coreclr/src/jit/codegenarm.cpp @@ -961,7 +961,7 @@ void CodeGen::genCodeForLclVar(GenTreeLclVar* tree) // If this is a register candidate that has been spilled, genConsumeReg() will // reload it at the point of use. Otherwise, if it's not in a register, we load it here. - if (!isRegCandidate && !(tree->gtFlags & GTF_SPILLED)) + if (!isRegCandidate && !tree->IsMultiReg() && !(tree->gtFlags & GTF_SPILLED)) { const LclVarDsc* varDsc = compiler->lvaGetDesc(tree); var_types type = varDsc->GetRegisterType(tree); @@ -998,13 +998,38 @@ void CodeGen::genCodeForStoreLclFld(GenTreeLclFld* tree) // Ensure that lclVar nodes are typed correctly. assert(!varDsc->lvNormalizeOnStore() || targetType == genActualType(varDsc->TypeGet())); - GenTree* data = tree->gtOp1; - instruction ins = ins_Store(targetType); - emitAttr attr = emitTypeSize(targetType); + GenTree* data = tree->gtOp1; assert(!data->isContained()); genConsumeReg(data); - emit->emitIns_S_R(ins, attr, data->GetRegNum(), varNum, offset); + regNumber dataReg = data->GetRegNum(); + if (tree->IsOffsetMisaligned()) + { + // Arm supports unaligned access only for integer types, + // convert the storing floating data into 1 or 2 integer registers and write them as int. + regNumber addr = tree->ExtractTempReg(); + emit->emitIns_R_S(INS_lea, EA_PTRSIZE, addr, varNum, offset); + if (targetType == TYP_FLOAT) + { + regNumber floatAsInt = tree->GetSingleTempReg(); + emit->emitIns_R_R(INS_vmov_f2i, EA_4BYTE, floatAsInt, dataReg); + emit->emitIns_R_R(INS_str, EA_4BYTE, floatAsInt, addr); + } + else + { + regNumber halfdoubleAsInt1 = tree->ExtractTempReg(); + regNumber halfdoubleAsInt2 = tree->GetSingleTempReg(); + emit->emitIns_R_R_R(INS_vmov_d2i, EA_8BYTE, halfdoubleAsInt1, halfdoubleAsInt2, dataReg); + emit->emitIns_R_R_I(INS_str, EA_4BYTE, halfdoubleAsInt1, addr, 0); + emit->emitIns_R_R_I(INS_str, EA_4BYTE, halfdoubleAsInt1, addr, 4); + } + } + else + { + emitAttr attr = emitTypeSize(targetType); + instruction ins = ins_Store(targetType); + emit->emitIns_S_R(ins, attr, dataReg, varNum, offset); + } // Updating variable liveness after instruction was emitted genUpdateLife(tree); @@ -1025,7 +1050,7 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree) // case is handled separately. if (data->gtSkipReloadOrCopy()->IsMultiRegCall()) { - genMultiRegCallStoreToLocal(tree); + genMultiRegStoreToLocal(tree); } else { @@ -1623,14 +1648,14 @@ void CodeGen::genCodeForMulLong(GenTreeMultiRegOp* node) // genProfilingEnterCallback: Generate the profiling function enter callback. // // Arguments: -// initReg - register to use as scratch register -// pInitRegZeroed - OUT parameter. *pInitRegZeroed set to 'false' if 'initReg' is -// not zero after this call. +// initReg - register to use as scratch register +// pInitRegModified - OUT parameter. *pInitRegModified set to 'true' if and only if +// this call sets 'initReg' to a non-zero value. // // Return Value: // None // -void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed) +void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegModified) { assert(compiler->compGeneratingProlog); @@ -1663,7 +1688,7 @@ void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed) if (initReg == argReg) { - *pInitRegZeroed = false; + *pInitRegModified = true; } } @@ -1793,14 +1818,17 @@ void CodeGen::genProfilingLeaveCallback(unsigned helper) // Arguments: // frameSize - the size of the stack frame being allocated. // initReg - register to use as a scratch register. -// pInitRegZeroed - OUT parameter. *pInitRegZeroed is set to 'false' if and only if +// pInitRegModified - OUT parameter. *pInitRegModified is set to 'true' if and only if // this call sets 'initReg' to a non-zero value. // maskArgRegsLiveIn - incoming argument registers that are currently live. // // Return value: // None // -void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn) +void CodeGen::genAllocLclFrame(unsigned frameSize, + regNumber initReg, + bool* pInitRegModified, + regMaskTP maskArgRegsLiveIn) { assert(compiler->compGeneratingProlog); @@ -1830,7 +1858,7 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni } regSet.verifyRegUsed(initReg); - *pInitRegZeroed = false; // The initReg does not contain zero + *pInitRegModified = true; instGen_Set_Reg_To_Imm(EA_PTRSIZE, initReg, frameSize); compiler->unwindPadding(); @@ -1850,7 +1878,7 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni if ((genRegMask(initReg) & (RBM_STACK_PROBE_HELPER_ARG | RBM_STACK_PROBE_HELPER_CALL_TARGET | RBM_STACK_PROBE_HELPER_TRASH)) != RBM_NONE) { - *pInitRegZeroed = false; + *pInitRegModified = true; } } diff --git a/src/coreclr/src/jit/codegenarm64.cpp b/src/coreclr/src/jit/codegenarm64.cpp index 88799aec62d720..91b5885f174630 100644 --- a/src/coreclr/src/jit/codegenarm64.cpp +++ b/src/coreclr/src/jit/codegenarm64.cpp @@ -1839,7 +1839,7 @@ void CodeGen::genCodeForLclVar(GenTreeLclVar* tree) // If this is a register candidate that has been spilled, genConsumeReg() will // reload it at the point of use. Otherwise, if it's not in a register, we load it here. - if (!isRegCandidate && !(tree->gtFlags & GTF_SPILLED)) + if (!isRegCandidate && !tree->IsMultiReg() && !(tree->gtFlags & GTF_SPILLED)) { // targetType must be a normal scalar type and not a TYP_STRUCT assert(targetType != TYP_STRUCT); @@ -1929,7 +1929,7 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree) // case is handled separately. if (data->gtSkipReloadOrCopy()->IsMultiRegCall()) { - genMultiRegCallStoreToLocal(tree); + genMultiRegStoreToLocal(tree); } else { @@ -1953,17 +1953,31 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree) genConsumeRegs(data); regNumber dataReg = REG_NA; - if (data->isContainedIntOrIImmed()) + if (data->isContained()) { // This is only possible for a zero-init. - assert(data->IsIntegralConst(0)); + assert(data->IsIntegralConst(0) || data->IsSIMDZero()); if (varTypeIsSIMD(targetType)) { - assert(targetType == TYP_SIMD16); - assert(targetReg != REG_NA); - emit->emitIns_R_I(INS_movi, EA_16BYTE, targetReg, 0x00, INS_OPTS_16B); - genProduceReg(tree); + if (targetReg != REG_NA) + { + emit->emitIns_R_I(INS_movi, emitActualTypeSize(targetType), targetReg, 0x00, INS_OPTS_16B); + genProduceReg(tree); + } + else + { + if (targetType == TYP_SIMD16) + { + GetEmitter()->emitIns_S_S_R_R(INS_stp, EA_8BYTE, EA_8BYTE, REG_ZR, REG_ZR, varNum, 0); + } + else + { + assert(targetType == TYP_SIMD8); + GetEmitter()->emitIns_S_R(INS_str, EA_8BYTE, REG_ZR, varNum, 0); + } + genUpdateLife(tree); + } return; } @@ -2371,6 +2385,35 @@ void CodeGen::genCodeForNegNot(GenTree* tree) genProduceReg(tree); } +//------------------------------------------------------------------------ +// genCodeForBswap: Produce code for a GT_BSWAP / GT_BSWAP16 node. +// +// Arguments: +// tree - the node +// +void CodeGen::genCodeForBswap(GenTree* tree) +{ + assert(tree->OperIs(GT_BSWAP, GT_BSWAP16)); + + regNumber targetReg = tree->GetRegNum(); + var_types targetType = tree->TypeGet(); + + GenTree* operand = tree->gtGetOp1(); + assert(operand->isUsedFromReg()); + regNumber operandReg = genConsumeReg(operand); + + if (tree->OperIs(GT_BSWAP16)) + { + inst_RV_RV(INS_rev16, targetReg, operandReg, targetType); + } + else + { + inst_RV_RV(INS_rev, targetReg, operandReg, targetType); + } + + genProduceReg(tree); +} + //------------------------------------------------------------------------ // genCodeForDivMod: Produce code for a GT_DIV/GT_UDIV node. We don't see MOD: // (1) integer MOD is morphed into a sequence of sub, mul, div in fgMorph; @@ -2636,8 +2679,8 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode) if (cpObjNode->gtFlags & GTF_BLK_VOLATILE) { - // issue a INS_BARRIER_ISHLD after a volatile CpObj operation - instGen_MemoryBarrier(INS_BARRIER_ISHLD); + // issue a load barrier after a volatile CpObj operation + instGen_MemoryBarrier(BARRIER_LOAD_ONLY); } // Clear the gcInfo for REG_WRITE_BARRIER_SRC_BYREF and REG_WRITE_BARRIER_DST_BYREF. @@ -2746,7 +2789,7 @@ void CodeGen::genLockedInstructions(GenTreeOp* treeNode) assert(!"Unexpected treeNode->gtOper"); } - instGen_MemoryBarrier(INS_BARRIER_ISH); + instGen_MemoryBarrier(); } else { @@ -2826,7 +2869,7 @@ void CodeGen::genLockedInstructions(GenTreeOp* treeNode) GetEmitter()->emitIns_J_R(INS_cbnz, EA_4BYTE, labelRetry, exResultReg); - instGen_MemoryBarrier(INS_BARRIER_ISH); + instGen_MemoryBarrier(); gcInfo.gcMarkRegSetNpt(addr->gtGetRegMask()); } @@ -2875,7 +2918,7 @@ void CodeGen::genCodeForCmpXchg(GenTreeCmpXchg* treeNode) } GetEmitter()->emitIns_R_R_R(INS_casal, dataSize, targetReg, dataReg, addrReg); - instGen_MemoryBarrier(INS_BARRIER_ISH); + instGen_MemoryBarrier(); } else { @@ -2955,7 +2998,7 @@ void CodeGen::genCodeForCmpXchg(GenTreeCmpXchg* treeNode) genDefineTempLabel(labelCompareFail); - instGen_MemoryBarrier(INS_BARRIER_ISH); + instGen_MemoryBarrier(); gcInfo.gcMarkRegSetNpt(addr->gtGetRegMask()); } @@ -3778,15 +3821,11 @@ void CodeGen::genSIMDIntrinsic(GenTreeSIMD* simdNode) genSIMDIntrinsicInitN(simdNode); break; - case SIMDIntrinsicSqrt: - case SIMDIntrinsicAbs: case SIMDIntrinsicCast: case SIMDIntrinsicConvertToSingle: case SIMDIntrinsicConvertToInt32: case SIMDIntrinsicConvertToDouble: case SIMDIntrinsicConvertToInt64: - case SIMDIntrinsicCeil: - case SIMDIntrinsicFloor: genSIMDIntrinsicUnOp(simdNode); break; @@ -3804,24 +3843,11 @@ void CodeGen::genSIMDIntrinsic(GenTreeSIMD* simdNode) case SIMDIntrinsicMul: case SIMDIntrinsicDiv: case SIMDIntrinsicBitwiseAnd: - case SIMDIntrinsicBitwiseAndNot: case SIMDIntrinsicBitwiseOr: - case SIMDIntrinsicBitwiseXor: - case SIMDIntrinsicMin: - case SIMDIntrinsicMax: case SIMDIntrinsicEqual: - case SIMDIntrinsicLessThan: - case SIMDIntrinsicGreaterThan: - case SIMDIntrinsicLessThanOrEqual: - case SIMDIntrinsicGreaterThanOrEqual: genSIMDIntrinsicBinOp(simdNode); break; - case SIMDIntrinsicOpEquality: - case SIMDIntrinsicOpInEquality: - genSIMDIntrinsicRelOp(simdNode); - break; - case SIMDIntrinsicDotProduct: genSIMDIntrinsicDotProduct(simdNode); break; @@ -3845,10 +3871,6 @@ void CodeGen::genSIMDIntrinsic(GenTreeSIMD* simdNode) genSIMDIntrinsicUpperRestore(simdNode); break; - case SIMDIntrinsicSelect: - NYI("SIMDIntrinsicSelect lowered during import to (a & sel) | (b & ~sel)"); - break; - default: noway_assert(!"Unimplemented SIMD intrinsic."); unreached(); @@ -3906,24 +3928,15 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type { switch (intrinsicId) { - case SIMDIntrinsicAbs: - result = INS_fabs; - break; case SIMDIntrinsicAdd: result = INS_fadd; break; case SIMDIntrinsicBitwiseAnd: result = INS_and; break; - case SIMDIntrinsicBitwiseAndNot: - result = INS_bic; - break; case SIMDIntrinsicBitwiseOr: result = INS_orr; break; - case SIMDIntrinsicBitwiseXor: - result = INS_eor; - break; case SIMDIntrinsicCast: result = INS_mov; break; @@ -3937,24 +3950,6 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type case SIMDIntrinsicEqual: result = INS_fcmeq; break; - case SIMDIntrinsicGreaterThan: - result = INS_fcmgt; - break; - case SIMDIntrinsicGreaterThanOrEqual: - result = INS_fcmge; - break; - case SIMDIntrinsicLessThan: - result = INS_fcmlt; - break; - case SIMDIntrinsicLessThanOrEqual: - result = INS_fcmle; - break; - case SIMDIntrinsicMax: - result = INS_fmax; - break; - case SIMDIntrinsicMin: - result = INS_fmin; - break; case SIMDIntrinsicMul: result = INS_fmul; break; @@ -3963,12 +3958,6 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type // Return lower bytes instruction here result = INS_fcvtn; break; - case SIMDIntrinsicSelect: - result = INS_bsl; - break; - case SIMDIntrinsicSqrt: - result = INS_fsqrt; - break; case SIMDIntrinsicSub: result = INS_fsub; break; @@ -3978,12 +3967,6 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type case SIMDIntrinsicWidenHi: result = INS_fcvtl2; break; - case SIMDIntrinsicCeil: - result = INS_frintp; - break; - case SIMDIntrinsicFloor: - result = INS_frintm; - break; default: assert(!"Unsupported SIMD intrinsic"); unreached(); @@ -3995,25 +3978,15 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type switch (intrinsicId) { - case SIMDIntrinsicAbs: - assert(!isUnsigned); - result = INS_abs; - break; case SIMDIntrinsicAdd: result = INS_add; break; case SIMDIntrinsicBitwiseAnd: result = INS_and; break; - case SIMDIntrinsicBitwiseAndNot: - result = INS_bic; - break; case SIMDIntrinsicBitwiseOr: result = INS_orr; break; - case SIMDIntrinsicBitwiseXor: - result = INS_eor; - break; case SIMDIntrinsicCast: result = INS_mov; break; @@ -4024,26 +3997,6 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type case SIMDIntrinsicEqual: result = INS_cmeq; break; - case SIMDIntrinsicGreaterThan: - result = isUnsigned ? INS_cmhi : INS_cmgt; - break; - case SIMDIntrinsicGreaterThanOrEqual: - result = isUnsigned ? INS_cmhs : INS_cmge; - break; - case SIMDIntrinsicLessThan: - assert(!isUnsigned); - result = INS_cmlt; - break; - case SIMDIntrinsicLessThanOrEqual: - assert(!isUnsigned); - result = INS_cmle; - break; - case SIMDIntrinsicMax: - result = isUnsigned ? INS_umax : INS_smax; - break; - case SIMDIntrinsicMin: - result = isUnsigned ? INS_umin : INS_smin; - break; case SIMDIntrinsicMul: result = INS_mul; break; @@ -4052,9 +4005,6 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type // Return lower bytes instruction here result = INS_xtn; break; - case SIMDIntrinsicSelect: - result = INS_bsl; - break; case SIMDIntrinsicSub: result = INS_sub; break; @@ -4213,13 +4163,11 @@ void CodeGen::genSIMDIntrinsicInitN(GenTreeSIMD* simdNode) // void CodeGen::genSIMDIntrinsicUnOp(GenTreeSIMD* simdNode) { - assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicSqrt || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicCast || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicAbs || + assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicCast || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToSingle || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToInt32 || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToDouble || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToInt64 || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicCeil || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicFloor); + simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToInt64); GenTree* op1 = simdNode->gtGetOp1(); var_types baseType = simdNode->gtSIMDBaseType; @@ -4269,17 +4217,10 @@ void CodeGen::genSIMDIntrinsicWiden(GenTreeSIMD* simdNode) instruction ins = getOpForSIMDIntrinsic(simdNode->gtSIMDIntrinsicID, baseType); - if (varTypeIsFloating(baseType)) - { - GetEmitter()->emitIns_R_R(ins, EA_8BYTE, targetReg, op1Reg); - } - else - { - emitAttr attr = (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicWidenHi) ? EA_16BYTE : EA_8BYTE; - insOpts opt = genGetSimdInsOpt(attr, baseType); + emitAttr attr = (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicWidenHi) ? EA_16BYTE : EA_8BYTE; + insOpts opt = genGetSimdInsOpt(attr, baseType); - GetEmitter()->emitIns_R_R(ins, attr, targetReg, op1Reg, opt); - } + GetEmitter()->emitIns_R_R(ins, attr, targetReg, op1Reg, opt); genProduceReg(simdNode); } @@ -4319,43 +4260,39 @@ void CodeGen::genSIMDIntrinsicNarrow(GenTreeSIMD* simdNode) instruction ins = getOpForSIMDIntrinsic(simdNode->gtSIMDIntrinsicID, baseType); assert((ins == INS_fcvtn) || (ins == INS_xtn)); - if (ins == INS_fcvtn) + instruction ins2 = (ins == INS_fcvtn) ? INS_fcvtn2 : INS_xtn2; + + insOpts opt = INS_OPTS_NONE; + insOpts opt2 = INS_OPTS_NONE; + + // This is not the same as genGetSimdInsOpt() + // Basetype is the soure operand type + // However encoding is based on the destination operand type which is 1/2 the basetype. + switch (baseType) { - GetEmitter()->emitIns_R_R(INS_fcvtn, EA_8BYTE, targetReg, op1Reg); - GetEmitter()->emitIns_R_R(INS_fcvtn2, EA_8BYTE, targetReg, op2Reg); + case TYP_ULONG: + case TYP_LONG: + case TYP_DOUBLE: + opt = INS_OPTS_2S; + opt2 = INS_OPTS_4S; + break; + case TYP_UINT: + case TYP_INT: + opt = INS_OPTS_4H; + opt2 = INS_OPTS_8H; + break; + case TYP_USHORT: + case TYP_SHORT: + opt = INS_OPTS_8B; + opt2 = INS_OPTS_16B; + break; + default: + assert(!"Unsupported narrowing element type"); + unreached(); } - else - { - insOpts opt = INS_OPTS_NONE; - insOpts opt2 = INS_OPTS_NONE; - // This is not the same as genGetSimdInsOpt() - // Basetype is the soure operand type - // However encoding is based on the destination operand type which is 1/2 the basetype. - switch (baseType) - { - case TYP_ULONG: - case TYP_LONG: - opt = INS_OPTS_2S; - opt2 = INS_OPTS_4S; - break; - case TYP_UINT: - case TYP_INT: - opt = INS_OPTS_4H; - opt2 = INS_OPTS_8H; - break; - case TYP_USHORT: - case TYP_SHORT: - opt = INS_OPTS_8B; - opt2 = INS_OPTS_16B; - break; - default: - assert(!"Unsupported narrowing element type"); - unreached(); - } - GetEmitter()->emitIns_R_R(INS_xtn, EA_8BYTE, targetReg, op1Reg, opt); - GetEmitter()->emitIns_R_R(INS_xtn2, EA_16BYTE, targetReg, op2Reg, opt2); - } + GetEmitter()->emitIns_R_R(ins, EA_8BYTE, targetReg, op1Reg, opt); + GetEmitter()->emitIns_R_R(ins2, EA_16BYTE, targetReg, op2Reg, opt2); genProduceReg(simdNode); } @@ -4375,14 +4312,7 @@ void CodeGen::genSIMDIntrinsicBinOp(GenTreeSIMD* simdNode) assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicAdd || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicSub || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicMul || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicDiv || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseAnd || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseAndNot || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseOr || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseXor || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicMin || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicMax || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicEqual || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicLessThan || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicGreaterThan || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicLessThanOrEqual || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicGreaterThanOrEqual); + simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseOr || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicEqual); GenTree* op1 = simdNode->gtGetOp1(); GenTree* op2 = simdNode->gtGetOp2(); @@ -4410,65 +4340,6 @@ void CodeGen::genSIMDIntrinsicBinOp(GenTreeSIMD* simdNode) genProduceReg(simdNode); } -//-------------------------------------------------------------------------------- -// genSIMDIntrinsicRelOp: Generate code for a SIMD Intrinsic relational operater -// == and != -// -// Arguments: -// simdNode - The GT_SIMD node -// -// Return Value: -// None. -// -void CodeGen::genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode) -{ - assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpEquality || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpInEquality); - - GenTree* op1 = simdNode->gtGetOp1(); - GenTree* op2 = simdNode->gtGetOp2(); - var_types baseType = simdNode->gtSIMDBaseType; - regNumber targetReg = simdNode->GetRegNum(); - var_types targetType = simdNode->TypeGet(); - - genConsumeOperands(simdNode); - regNumber op1Reg = op1->GetRegNum(); - regNumber op2Reg = op2->GetRegNum(); - regNumber otherReg = op2Reg; - - instruction ins = getOpForSIMDIntrinsic(SIMDIntrinsicEqual, baseType); - emitAttr attr = (simdNode->gtSIMDSize > 8) ? EA_16BYTE : EA_8BYTE; - insOpts opt = genGetSimdInsOpt(attr, baseType); - - // TODO-ARM64-CQ Contain integer constants where possible - - regNumber tmpFloatReg = simdNode->GetSingleTempReg(RBM_ALLFLOAT); - - GetEmitter()->emitIns_R_R_R(ins, attr, tmpFloatReg, op1Reg, op2Reg, opt); - - if ((simdNode->gtFlags & GTF_SIMD12_OP) != 0) - { - // For 12Byte vectors we must set upper bits to get correct comparison - // We do not assume upper bits are zero. - instGen_Set_Reg_To_Imm(EA_4BYTE, targetReg, -1); - GetEmitter()->emitIns_R_R_I(INS_ins, EA_4BYTE, tmpFloatReg, targetReg, 3); - } - - GetEmitter()->emitIns_R_R(INS_uminv, attr, tmpFloatReg, tmpFloatReg, - (simdNode->gtSIMDSize > 8) ? INS_OPTS_16B : INS_OPTS_8B); - - GetEmitter()->emitIns_R_R_I(INS_mov, EA_1BYTE, targetReg, tmpFloatReg, 0); - - if (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpInEquality) - { - GetEmitter()->emitIns_R_R_I(INS_eor, EA_4BYTE, targetReg, targetReg, 0x1); - } - - GetEmitter()->emitIns_R_R_I(INS_and, EA_4BYTE, targetReg, targetReg, 0x1); - - genProduceReg(simdNode); -} - //-------------------------------------------------------------------------------- // genSIMDIntrinsicDotProduct: Generate code for SIMD Intrinsic Dot Product. // @@ -4990,7 +4861,20 @@ void CodeGen::genStoreLclTypeSIMD12(GenTree* treeNode) } GenTree* op1 = treeNode->AsOp()->gtOp1; - assert(!op1->isContained()); + + if (op1->isContained()) + { + // This is only possible for a zero-init. + assert(op1->IsIntegralConst(0) || op1->IsSIMDZero()); + + // store lower 8 bytes + GetEmitter()->emitIns_S_R(ins_Store(TYP_DOUBLE), EA_8BYTE, REG_ZR, varNum, offs); + + // Store upper 4 bytes + GetEmitter()->emitIns_S_R(ins_Store(TYP_FLOAT), EA_4BYTE, REG_ZR, varNum, offs + 8); + + return; + } regNumber operandReg = genConsumeReg(op1); // Need an addtional integer register to extract upper 4 bytes from data. @@ -5014,14 +4898,14 @@ void CodeGen::genStoreLclTypeSIMD12(GenTree* treeNode) // genProfilingEnterCallback: Generate the profiling function enter callback. // // Arguments: -// initReg - register to use as scratch register -// pInitRegZeroed - OUT parameter. *pInitRegZeroed set to 'false' if 'initReg' is -// not zero after this call. +// initReg - register to use as scratch register +// pInitRegModified - OUT parameter. *pInitRegModified set to 'true' if 'initReg' is +// not zero after this call. // // Return Value: // None // -void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed) +void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegModified) { assert(compiler->compGeneratingProlog); @@ -5049,7 +4933,7 @@ void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed) if ((genRegMask(initReg) & RBM_PROFILER_ENTER_TRASH) != RBM_NONE) { - *pInitRegZeroed = false; + *pInitRegModified = true; } } @@ -5116,16 +5000,12 @@ void CodeGen::genArm64EmitterUnitTests() return; } - if (!compiler->opts.altJit) - { - // No point doing this in a "real" JIT. - return; - } - +#ifdef ALL_ARM64_EMITTER_UNIT_TESTS // Mark the "fake" instructions in the output. printf("*************** In genArm64EmitterUnitTests()\n"); emitter* theEmitter = GetEmitter(); +#endif // ALL_ARM64_EMITTER_UNIT_TESTS #ifdef ALL_ARM64_EMITTER_UNIT_TESTS // We use this: @@ -5409,6 +5289,38 @@ void CodeGen::genArm64EmitterUnitTests() theEmitter->emitIns_R_R(INS_ld4r, EA_8BYTE, REG_V30, REG_R2, INS_OPTS_1D); theEmitter->emitIns_R_R(INS_ld4r, EA_16BYTE, REG_V3, REG_R7, INS_OPTS_2D); + // tbl Vd, {Vt}, Vm + theEmitter->emitIns_R_R_R(INS_tbl, EA_8BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_tbl, EA_16BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_16B); + + // tbx Vd, {Vt}, Vm + theEmitter->emitIns_R_R_R(INS_tbx, EA_8BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_tbx, EA_16BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_16B); + + // tbl Vd, {Vt, Vt2}, Vm + theEmitter->emitIns_R_R_R(INS_tbl_2regs, EA_8BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_tbl_2regs, EA_16BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_16B); + + // tbx Vd, {Vt, Vt2}, Vm + theEmitter->emitIns_R_R_R(INS_tbx_2regs, EA_8BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_tbx_2regs, EA_16BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_16B); + + // tbl Vd, {Vt, Vt2, Vt3}, Vm + theEmitter->emitIns_R_R_R(INS_tbl_3regs, EA_8BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_tbl_3regs, EA_16BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_16B); + + // tbx Vd, {Vt, Vt2, Vt3}, Vm + theEmitter->emitIns_R_R_R(INS_tbx_3regs, EA_8BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_tbx_3regs, EA_16BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_16B); + + // tbl Vd, {Vt, Vt2, Vt3, Vt4}, Vm + theEmitter->emitIns_R_R_R(INS_tbl_4regs, EA_8BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_tbl_4regs, EA_16BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_16B); + + // tbx Vd, {Vt, Vt2, Vt3, Vt4}, Vm + theEmitter->emitIns_R_R_R(INS_tbx_4regs, EA_8BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_tbx_4regs, EA_16BYTE, REG_V0, REG_V1, REG_V6, INS_OPTS_16B); + #endif // ALL_ARM64_EMITTER_UNIT_TESTS #ifdef ALL_ARM64_EMITTER_UNIT_TESTS @@ -6927,7 +6839,6 @@ void CodeGen::genArm64EmitterUnitTests() genDefineTempLabel(genCreateTempLabel()); theEmitter->emitIns_R(INS_br, EA_PTRSIZE, REG_R8); - theEmitter->emitIns_R(INS_blr, EA_PTRSIZE, REG_R9); theEmitter->emitIns_R(INS_ret, EA_PTRSIZE, REG_R8); theEmitter->emitIns_R(INS_ret, EA_PTRSIZE, REG_LR); @@ -7217,6 +7128,12 @@ void CodeGen::genArm64EmitterUnitTests() theEmitter->emitIns_R_R_I(INS_smov, EA_2BYTE, REG_R6, REG_V18, 4); theEmitter->emitIns_R_R_I(INS_smov, EA_1BYTE, REG_R7, REG_V19, 8); + // ext extract vector from pair of vectors + theEmitter->emitIns_R_R_R_I(INS_ext, EA_8BYTE, REG_V0, REG_V1, REG_V2, 3, INS_OPTS_8B); + theEmitter->emitIns_R_R_R_I(INS_ext, EA_8BYTE, REG_V4, REG_V5, REG_V6, 7, INS_OPTS_8B); + theEmitter->emitIns_R_R_R_I(INS_ext, EA_16BYTE, REG_V8, REG_V9, REG_V10, 11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R_I(INS_ext, EA_16BYTE, REG_V12, REG_V13, REG_V14, 15, INS_OPTS_16B); + #endif // ALL_ARM64_EMITTER_UNIT_TESTS #ifdef ALL_ARM64_EMITTER_UNIT_TESTS @@ -7267,6 +7184,10 @@ void CodeGen::genArm64EmitterUnitTests() theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V30, 0xFF000000FF000000); theEmitter->emitIns_R_I(INS_movi, EA_16BYTE, REG_V31, 0x0, INS_OPTS_2D); + // We were not encoding immediate of movi that was int.MaxValue or int.MaxValue / 2. + theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V16, 0x7fffffff, INS_OPTS_2S); + theEmitter->emitIns_R_I(INS_movi, EA_8BYTE, REG_V16, 0x3fffffff, INS_OPTS_2S); + theEmitter->emitIns_R_I(INS_mvni, EA_8BYTE, REG_V0, 0x0022, INS_OPTS_4H); theEmitter->emitIns_R_I(INS_mvni, EA_8BYTE, REG_V1, 0x2200, INS_OPTS_4H); // LSL 8 theEmitter->emitIns_R_I(INS_mvni, EA_16BYTE, REG_V2, 0x0033, INS_OPTS_8H); @@ -7845,19 +7766,54 @@ void CodeGen::genArm64EmitterUnitTests() theEmitter->emitIns_R_R(INS_ursqrte, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_2S); theEmitter->emitIns_R_R(INS_ursqrte, EA_16BYTE, REG_V2, REG_V3, INS_OPTS_4S); - // INS_fcvtl - theEmitter->emitIns_R_R(INS_fcvtl, EA_4BYTE, REG_V0, REG_V1); - - // INS_fcvtl2 - theEmitter->emitIns_R_R(INS_fcvtl2, EA_4BYTE, REG_V0, REG_V1); + // fcvtl{2} vector + theEmitter->emitIns_R_R(INS_fcvtl, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_4H); + theEmitter->emitIns_R_R(INS_fcvtl2, EA_16BYTE, REG_V2, REG_V3, INS_OPTS_8H); + theEmitter->emitIns_R_R(INS_fcvtl, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S); + theEmitter->emitIns_R_R(INS_fcvtl2, EA_16BYTE, REG_V5, REG_V6, INS_OPTS_4S); - // INS_fcvtn - theEmitter->emitIns_R_R(INS_fcvtn, EA_8BYTE, REG_V0, REG_V1); + // fcvtn{2} vector + theEmitter->emitIns_R_R(INS_fcvtn, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_4H); + theEmitter->emitIns_R_R(INS_fcvtn2, EA_16BYTE, REG_V2, REG_V3, INS_OPTS_8H); + theEmitter->emitIns_R_R(INS_fcvtn, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S); + theEmitter->emitIns_R_R(INS_fcvtn2, EA_16BYTE, REG_V5, REG_V6, INS_OPTS_4S); - // INS_fcvtn2 - theEmitter->emitIns_R_R(INS_fcvtn2, EA_8BYTE, REG_V0, REG_V1); #endif +#ifdef ALL_ARM64_EMITTER_UNIT_TESTS + // sadalp vector + theEmitter->emitIns_R_R(INS_sadalp, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_8B); + theEmitter->emitIns_R_R(INS_sadalp, EA_8BYTE, REG_V2, REG_V3, INS_OPTS_4H); + theEmitter->emitIns_R_R(INS_sadalp, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S); + theEmitter->emitIns_R_R(INS_sadalp, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B); + theEmitter->emitIns_R_R(INS_sadalp, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_8H); + theEmitter->emitIns_R_R(INS_sadalp, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S); + + // saddlp vector + theEmitter->emitIns_R_R(INS_saddlp, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_8B); + theEmitter->emitIns_R_R(INS_saddlp, EA_8BYTE, REG_V2, REG_V3, INS_OPTS_4H); + theEmitter->emitIns_R_R(INS_saddlp, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S); + theEmitter->emitIns_R_R(INS_saddlp, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B); + theEmitter->emitIns_R_R(INS_saddlp, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_8H); + theEmitter->emitIns_R_R(INS_saddlp, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S); + + // uadalp vector + theEmitter->emitIns_R_R(INS_uadalp, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_8B); + theEmitter->emitIns_R_R(INS_uadalp, EA_8BYTE, REG_V2, REG_V3, INS_OPTS_4H); + theEmitter->emitIns_R_R(INS_uadalp, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S); + theEmitter->emitIns_R_R(INS_uadalp, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B); + theEmitter->emitIns_R_R(INS_uadalp, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_8H); + theEmitter->emitIns_R_R(INS_uadalp, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S); + + // uaddlp vector + theEmitter->emitIns_R_R(INS_uaddlp, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_8B); + theEmitter->emitIns_R_R(INS_uaddlp, EA_8BYTE, REG_V2, REG_V3, INS_OPTS_4H); + theEmitter->emitIns_R_R(INS_uaddlp, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_2S); + theEmitter->emitIns_R_R(INS_uaddlp, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B); + theEmitter->emitIns_R_R(INS_uaddlp, EA_16BYTE, REG_V8, REG_V9, INS_OPTS_8H); + theEmitter->emitIns_R_R(INS_uaddlp, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S); +#endif // ALL_ARM64_EMITTER_UNIT_TESTS + #ifdef ALL_ARM64_EMITTER_UNIT_TESTS // // R_R floating point round to int, one dest, one source @@ -8061,196 +8017,200 @@ void CodeGen::genArm64EmitterUnitTests() // R_R_I vector operations, one dest, one source reg, one immed // + // Some of the tests cases below might appear redundant since they emit same combinations of instruction x size x + // vector arrangements. However, these are added to verify that the split constant encoding works with both - small + // and large constants. + genDefineTempLabel(genCreateTempLabel()); - // 'sshr' scalar + // sshr scalar theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V0, REG_V1, 1); theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V2, REG_V3, 14); theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V4, REG_V5, 27); theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V6, REG_V7, 40); - theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V8, REG_V9, 63); + theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V8, REG_V9, 64); - // 'sshr' vector + // sshr vector theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); - theEmitter->emitIns_R_R_I(INS_sshr, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_sshr, EA_16BYTE, REG_V2, REG_V3, 8, INS_OPTS_16B); theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); - theEmitter->emitIns_R_R_I(INS_sshr, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_sshr, EA_16BYTE, REG_V6, REG_V7, 16, INS_OPTS_8H); theEmitter->emitIns_R_R_I(INS_sshr, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); - theEmitter->emitIns_R_R_I(INS_sshr, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_sshr, EA_16BYTE, REG_V10, REG_V11, 32, INS_OPTS_4S); theEmitter->emitIns_R_R_I(INS_sshr, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D); - theEmitter->emitIns_R_R_I(INS_sshr, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D); + theEmitter->emitIns_R_R_I(INS_sshr, EA_16BYTE, REG_V14, REG_V15, 64, INS_OPTS_2D); - // 'ssra' scalar + // ssra scalar theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V0, REG_V1, 1); theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V2, REG_V3, 14); theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V4, REG_V5, 27); theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V6, REG_V7, 40); - theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V8, REG_V9, 63); + theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V8, REG_V9, 64); - // 'ssra' vector + // ssra vector theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); - theEmitter->emitIns_R_R_I(INS_ssra, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_ssra, EA_16BYTE, REG_V2, REG_V3, 8, INS_OPTS_16B); theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); - theEmitter->emitIns_R_R_I(INS_ssra, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_ssra, EA_16BYTE, REG_V6, REG_V7, 16, INS_OPTS_8H); theEmitter->emitIns_R_R_I(INS_ssra, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); - theEmitter->emitIns_R_R_I(INS_ssra, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_ssra, EA_16BYTE, REG_V10, REG_V11, 32, INS_OPTS_4S); theEmitter->emitIns_R_R_I(INS_ssra, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D); - theEmitter->emitIns_R_R_I(INS_ssra, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D); + theEmitter->emitIns_R_R_I(INS_ssra, EA_16BYTE, REG_V14, REG_V15, 64, INS_OPTS_2D); - // 'srshr' scalar + // srshr scalar theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V0, REG_V1, 1); theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V2, REG_V3, 14); theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V4, REG_V5, 27); theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V6, REG_V7, 40); - theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V8, REG_V9, 63); + theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V8, REG_V9, 64); - // 'srshr' vector + // srshr vector theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); - theEmitter->emitIns_R_R_I(INS_srshr, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_srshr, EA_16BYTE, REG_V2, REG_V3, 8, INS_OPTS_16B); theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); - theEmitter->emitIns_R_R_I(INS_srshr, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_srshr, EA_16BYTE, REG_V6, REG_V7, 16, INS_OPTS_8H); theEmitter->emitIns_R_R_I(INS_srshr, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); - theEmitter->emitIns_R_R_I(INS_srshr, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_srshr, EA_16BYTE, REG_V10, REG_V11, 32, INS_OPTS_4S); theEmitter->emitIns_R_R_I(INS_srshr, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D); - theEmitter->emitIns_R_R_I(INS_srshr, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D); + theEmitter->emitIns_R_R_I(INS_srshr, EA_16BYTE, REG_V14, REG_V15, 64, INS_OPTS_2D); - // 'srsra' scalar + // srsra scalar theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V0, REG_V1, 1); theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V2, REG_V3, 14); theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V4, REG_V5, 27); theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V6, REG_V7, 40); - theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V8, REG_V9, 63); + theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V8, REG_V9, 64); - // 'srsra' vector + // srsra vector theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); - theEmitter->emitIns_R_R_I(INS_srsra, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_srsra, EA_16BYTE, REG_V2, REG_V3, 8, INS_OPTS_16B); theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); - theEmitter->emitIns_R_R_I(INS_srsra, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_srsra, EA_16BYTE, REG_V6, REG_V7, 16, INS_OPTS_8H); theEmitter->emitIns_R_R_I(INS_srsra, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); - theEmitter->emitIns_R_R_I(INS_srsra, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_srsra, EA_16BYTE, REG_V10, REG_V11, 32, INS_OPTS_4S); theEmitter->emitIns_R_R_I(INS_srsra, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D); - theEmitter->emitIns_R_R_I(INS_srsra, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D); + theEmitter->emitIns_R_R_I(INS_srsra, EA_16BYTE, REG_V14, REG_V15, 64, INS_OPTS_2D); - // 'shl' scalar - theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V0, REG_V1, 1); + // shl scalar + theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V0, REG_V1, 0); theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V2, REG_V3, 14); theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V4, REG_V5, 27); theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V6, REG_V7, 40); theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V8, REG_V9, 63); - // 'shl' vector - theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); + // shl vector + theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V0, REG_V1, 0, INS_OPTS_8B); theEmitter->emitIns_R_R_I(INS_shl, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); - theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V4, REG_V5, 8, INS_OPTS_4H); theEmitter->emitIns_R_R_I(INS_shl, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); - theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_shl, EA_8BYTE, REG_V8, REG_V9, 16, INS_OPTS_2S); theEmitter->emitIns_R_R_I(INS_shl, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); - theEmitter->emitIns_R_R_I(INS_shl, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D); + theEmitter->emitIns_R_R_I(INS_shl, EA_16BYTE, REG_V12, REG_V13, 32, INS_OPTS_2D); theEmitter->emitIns_R_R_I(INS_shl, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D); - // 'ushr' scalar + // ushr scalar theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V0, REG_V1, 1); theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V2, REG_V3, 14); theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V4, REG_V5, 27); theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V6, REG_V7, 40); - theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V8, REG_V9, 63); + theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V8, REG_V9, 64); - // 'ushr' vector + // ushr vector theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); - theEmitter->emitIns_R_R_I(INS_ushr, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_ushr, EA_16BYTE, REG_V2, REG_V3, 8, INS_OPTS_16B); theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); - theEmitter->emitIns_R_R_I(INS_ushr, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_ushr, EA_16BYTE, REG_V6, REG_V7, 16, INS_OPTS_8H); theEmitter->emitIns_R_R_I(INS_ushr, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); - theEmitter->emitIns_R_R_I(INS_ushr, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_ushr, EA_16BYTE, REG_V10, REG_V11, 32, INS_OPTS_4S); theEmitter->emitIns_R_R_I(INS_ushr, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D); - theEmitter->emitIns_R_R_I(INS_ushr, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D); + theEmitter->emitIns_R_R_I(INS_ushr, EA_16BYTE, REG_V14, REG_V15, 64, INS_OPTS_2D); - // 'usra' scalar + // usra scalar theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V0, REG_V1, 1); theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V2, REG_V3, 14); theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V4, REG_V5, 27); theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V6, REG_V7, 40); - theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V8, REG_V9, 63); + theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V8, REG_V9, 64); - // 'usra' vector + // usra vector theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); - theEmitter->emitIns_R_R_I(INS_usra, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_usra, EA_16BYTE, REG_V2, REG_V3, 8, INS_OPTS_16B); theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); - theEmitter->emitIns_R_R_I(INS_usra, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_usra, EA_16BYTE, REG_V6, REG_V7, 16, INS_OPTS_8H); theEmitter->emitIns_R_R_I(INS_usra, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); - theEmitter->emitIns_R_R_I(INS_usra, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_usra, EA_16BYTE, REG_V10, REG_V11, 32, INS_OPTS_4S); theEmitter->emitIns_R_R_I(INS_usra, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D); - theEmitter->emitIns_R_R_I(INS_usra, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D); + theEmitter->emitIns_R_R_I(INS_usra, EA_16BYTE, REG_V14, REG_V15, 64, INS_OPTS_2D); - // 'urshr' scalar + // urshr scalar theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V0, REG_V1, 1); theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V2, REG_V3, 14); theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V4, REG_V5, 27); theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V6, REG_V7, 40); - theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V8, REG_V9, 63); + theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V8, REG_V9, 64); - // 'urshr' vector + // urshr vector theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); - theEmitter->emitIns_R_R_I(INS_urshr, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_urshr, EA_16BYTE, REG_V2, REG_V3, 8, INS_OPTS_16B); theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); - theEmitter->emitIns_R_R_I(INS_urshr, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_urshr, EA_16BYTE, REG_V6, REG_V7, 16, INS_OPTS_8H); theEmitter->emitIns_R_R_I(INS_urshr, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); - theEmitter->emitIns_R_R_I(INS_urshr, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_urshr, EA_16BYTE, REG_V10, REG_V11, 32, INS_OPTS_4S); theEmitter->emitIns_R_R_I(INS_urshr, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D); - theEmitter->emitIns_R_R_I(INS_urshr, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D); + theEmitter->emitIns_R_R_I(INS_urshr, EA_16BYTE, REG_V14, REG_V15, 64, INS_OPTS_2D); - // 'ursra' scalar + // ursra scalar theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V0, REG_V1, 1); theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V2, REG_V3, 14); theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V4, REG_V5, 27); theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V6, REG_V7, 40); - theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V8, REG_V9, 63); + theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V8, REG_V9, 64); - // 'srsra' vector + // ursra vector theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); - theEmitter->emitIns_R_R_I(INS_ursra, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_ursra, EA_16BYTE, REG_V2, REG_V3, 8, INS_OPTS_16B); theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); - theEmitter->emitIns_R_R_I(INS_ursra, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_ursra, EA_16BYTE, REG_V6, REG_V7, 16, INS_OPTS_8H); theEmitter->emitIns_R_R_I(INS_ursra, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); - theEmitter->emitIns_R_R_I(INS_ursra, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_ursra, EA_16BYTE, REG_V10, REG_V11, 32, INS_OPTS_4S); theEmitter->emitIns_R_R_I(INS_ursra, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D); - theEmitter->emitIns_R_R_I(INS_ursra, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D); + theEmitter->emitIns_R_R_I(INS_ursra, EA_16BYTE, REG_V14, REG_V15, 64, INS_OPTS_2D); - // 'sri' scalar + // sri scalar theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V0, REG_V1, 1); theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V2, REG_V3, 14); theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V4, REG_V5, 27); theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V6, REG_V7, 40); - theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V8, REG_V9, 63); + theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V8, REG_V9, 64); - // 'sri' vector + // sri vector theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); - theEmitter->emitIns_R_R_I(INS_sri, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_sri, EA_16BYTE, REG_V2, REG_V3, 8, INS_OPTS_16B); theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); - theEmitter->emitIns_R_R_I(INS_sri, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_sri, EA_16BYTE, REG_V6, REG_V7, 16, INS_OPTS_8H); theEmitter->emitIns_R_R_I(INS_sri, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); - theEmitter->emitIns_R_R_I(INS_sri, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_sri, EA_16BYTE, REG_V10, REG_V11, 32, INS_OPTS_4S); theEmitter->emitIns_R_R_I(INS_sri, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D); - theEmitter->emitIns_R_R_I(INS_sri, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D); + theEmitter->emitIns_R_R_I(INS_sri, EA_16BYTE, REG_V14, REG_V15, 64, INS_OPTS_2D); - // 'sli' scalar - theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V0, REG_V1, 1); + // sli scalar + theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V0, REG_V1, 0); theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V2, REG_V3, 14); theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V4, REG_V5, 27); theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V6, REG_V7, 40); theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V8, REG_V9, 63); - // 'sli' vector - theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); + // sli vector + theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V0, REG_V1, 0, INS_OPTS_8B); theEmitter->emitIns_R_R_I(INS_sli, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); - theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V4, REG_V5, 8, INS_OPTS_4H); theEmitter->emitIns_R_R_I(INS_sli, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); - theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_sli, EA_8BYTE, REG_V8, REG_V9, 16, INS_OPTS_2S); theEmitter->emitIns_R_R_I(INS_sli, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); - theEmitter->emitIns_R_R_I(INS_sli, EA_16BYTE, REG_V12, REG_V13, 33, INS_OPTS_2D); + theEmitter->emitIns_R_R_I(INS_sli, EA_16BYTE, REG_V12, REG_V13, 32, INS_OPTS_2D); theEmitter->emitIns_R_R_I(INS_sli, EA_16BYTE, REG_V14, REG_V15, 63, INS_OPTS_2D); - // 'sshll' vector + // sshll{2} vector theEmitter->emitIns_R_R_I(INS_sshll, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); theEmitter->emitIns_R_R_I(INS_sshll2, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); theEmitter->emitIns_R_R_I(INS_sshll, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); @@ -8258,7 +8218,7 @@ void CodeGen::genArm64EmitterUnitTests() theEmitter->emitIns_R_R_I(INS_sshll, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); theEmitter->emitIns_R_R_I(INS_sshll2, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); - // 'ushll' vector + // ushll{2} vector theEmitter->emitIns_R_R_I(INS_ushll, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); theEmitter->emitIns_R_R_I(INS_ushll2, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); theEmitter->emitIns_R_R_I(INS_ushll, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); @@ -8266,23 +8226,23 @@ void CodeGen::genArm64EmitterUnitTests() theEmitter->emitIns_R_R_I(INS_ushll, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); theEmitter->emitIns_R_R_I(INS_ushll2, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); - // 'shrn' vector + // shrn{2} vector theEmitter->emitIns_R_R_I(INS_shrn, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); - theEmitter->emitIns_R_R_I(INS_shrn2, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_shrn2, EA_16BYTE, REG_V2, REG_V3, 8, INS_OPTS_16B); theEmitter->emitIns_R_R_I(INS_shrn, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); - theEmitter->emitIns_R_R_I(INS_shrn2, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_shrn2, EA_16BYTE, REG_V6, REG_V7, 16, INS_OPTS_8H); theEmitter->emitIns_R_R_I(INS_shrn, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); - theEmitter->emitIns_R_R_I(INS_shrn2, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_shrn2, EA_16BYTE, REG_V10, REG_V11, 32, INS_OPTS_4S); - // 'rshrn' vector + // rshrn{2} vector theEmitter->emitIns_R_R_I(INS_rshrn, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); - theEmitter->emitIns_R_R_I(INS_rshrn2, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_rshrn2, EA_16BYTE, REG_V2, REG_V3, 8, INS_OPTS_16B); theEmitter->emitIns_R_R_I(INS_rshrn, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); - theEmitter->emitIns_R_R_I(INS_rshrn2, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_rshrn2, EA_16BYTE, REG_V6, REG_V7, 16, INS_OPTS_8H); theEmitter->emitIns_R_R_I(INS_rshrn, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); - theEmitter->emitIns_R_R_I(INS_rshrn2, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_rshrn2, EA_16BYTE, REG_V10, REG_V11, 32, INS_OPTS_4S); - // 'sxtl' vector + // sxtl{2} vector theEmitter->emitIns_R_R(INS_sxtl, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_8B); theEmitter->emitIns_R_R(INS_sxtl2, EA_16BYTE, REG_V2, REG_V3, INS_OPTS_16B); theEmitter->emitIns_R_R(INS_sxtl, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_4H); @@ -8290,7 +8250,7 @@ void CodeGen::genArm64EmitterUnitTests() theEmitter->emitIns_R_R(INS_sxtl, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S); theEmitter->emitIns_R_R(INS_sxtl2, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S); - // 'uxtl' vector + // uxtl{2} vector theEmitter->emitIns_R_R(INS_uxtl, EA_8BYTE, REG_V0, REG_V1, INS_OPTS_8B); theEmitter->emitIns_R_R(INS_uxtl2, EA_16BYTE, REG_V2, REG_V3, INS_OPTS_16B); theEmitter->emitIns_R_R(INS_uxtl, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_4H); @@ -8298,6 +8258,195 @@ void CodeGen::genArm64EmitterUnitTests() theEmitter->emitIns_R_R(INS_uxtl, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_2S); theEmitter->emitIns_R_R(INS_uxtl2, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_4S); + // sqrshrn scalar + theEmitter->emitIns_R_R_I(INS_sqrshrn, EA_1BYTE, REG_V0, REG_V1, 1, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqrshrn, EA_1BYTE, REG_V2, REG_V3, 8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqrshrn, EA_2BYTE, REG_V4, REG_V5, 9, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqrshrn, EA_2BYTE, REG_V6, REG_V7, 16, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqrshrn, EA_4BYTE, REG_V8, REG_V9, 17, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqrshrn, EA_4BYTE, REG_V10, REG_V11, 32, INS_OPTS_NONE); + + // sqrshrn{2} vector + theEmitter->emitIns_R_R_I(INS_sqrshrn, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_sqrshrn, EA_8BYTE, REG_V2, REG_V3, 8, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_sqrshrn2, EA_16BYTE, REG_V4, REG_V5, 1, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_sqrshrn2, EA_16BYTE, REG_V6, REG_V7, 8, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_sqrshrn, EA_8BYTE, REG_V8, REG_V9, 9, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_sqrshrn, EA_8BYTE, REG_V10, REG_V11, 16, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_sqrshrn2, EA_16BYTE, REG_V12, REG_V13, 9, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_sqrshrn2, EA_16BYTE, REG_V14, REG_V15, 16, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_sqrshrn, EA_8BYTE, REG_V16, REG_V17, 17, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_sqrshrn, EA_8BYTE, REG_V18, REG_V18, 32, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_sqrshrn2, EA_16BYTE, REG_V20, REG_V21, 17, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_sqrshrn2, EA_16BYTE, REG_V22, REG_V23, 32, INS_OPTS_4S); + + // sqrshrun scalar + theEmitter->emitIns_R_R_I(INS_sqrshrun, EA_1BYTE, REG_V0, REG_V1, 1, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqrshrun, EA_1BYTE, REG_V0, REG_V1, 8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqrshrun, EA_2BYTE, REG_V2, REG_V3, 9, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqrshrun, EA_2BYTE, REG_V2, REG_V3, 16, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqrshrun, EA_4BYTE, REG_V4, REG_V5, 17, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqrshrun, EA_4BYTE, REG_V4, REG_V5, 32, INS_OPTS_NONE); + + // sqrshrun{2} vector + theEmitter->emitIns_R_R_I(INS_sqrshrun, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_sqrshrun, EA_8BYTE, REG_V2, REG_V3, 8, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_sqrshrun2, EA_16BYTE, REG_V4, REG_V5, 1, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_sqrshrun2, EA_16BYTE, REG_V6, REG_V7, 8, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_sqrshrun, EA_8BYTE, REG_V8, REG_V9, 9, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_sqrshrun, EA_8BYTE, REG_V10, REG_V11, 16, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_sqrshrun2, EA_16BYTE, REG_V12, REG_V13, 9, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_sqrshrun2, EA_16BYTE, REG_V14, REG_V15, 16, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_sqrshrun, EA_8BYTE, REG_V16, REG_V17, 17, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_sqrshrun, EA_8BYTE, REG_V18, REG_V18, 32, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_sqrshrun2, EA_16BYTE, REG_V20, REG_V21, 17, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_sqrshrun2, EA_16BYTE, REG_V22, REG_V23, 32, INS_OPTS_4S); + + // sqshl scalar + theEmitter->emitIns_R_R_I(INS_sqshl, EA_1BYTE, REG_V0, REG_V1, 0, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshl, EA_1BYTE, REG_V2, REG_V3, 7, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshl, EA_2BYTE, REG_V4, REG_V5, 8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshl, EA_2BYTE, REG_V6, REG_V7, 15, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshl, EA_4BYTE, REG_V8, REG_V9, 16, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshl, EA_4BYTE, REG_V10, REG_V11, 31, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshl, EA_8BYTE, REG_V12, REG_V13, 32, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshl, EA_8BYTE, REG_V14, REG_V15, 63, INS_OPTS_NONE); + + // sqshl vector + theEmitter->emitIns_R_R_I(INS_sqshl, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_sqshl, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_sqshl, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_sqshl, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_sqshl, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_sqshl, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_sqshl, EA_16BYTE, REG_V12, REG_V13, 63, INS_OPTS_2D); + + // sqshlu scalar + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_1BYTE, REG_V0, REG_V1, 0, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_1BYTE, REG_V2, REG_V3, 7, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_2BYTE, REG_V4, REG_V5, 8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_2BYTE, REG_V6, REG_V7, 15, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_4BYTE, REG_V8, REG_V9, 16, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_4BYTE, REG_V10, REG_V11, 31, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_8BYTE, REG_V12, REG_V13, 32, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_8BYTE, REG_V14, REG_V15, 63, INS_OPTS_NONE); + + // sqshlu vector + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_sqshlu, EA_16BYTE, REG_V12, REG_V13, 63, INS_OPTS_2D); + + // sqshrn scalar + theEmitter->emitIns_R_R_I(INS_sqshrn, EA_1BYTE, REG_V0, REG_V1, 1, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshrn, EA_1BYTE, REG_V2, REG_V3, 8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshrn, EA_2BYTE, REG_V4, REG_V5, 9, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshrn, EA_2BYTE, REG_V6, REG_V7, 16, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshrn, EA_4BYTE, REG_V8, REG_V9, 17, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshrn, EA_4BYTE, REG_V10, REG_V11, 32, INS_OPTS_NONE); + + // sqshrn{2} vector + theEmitter->emitIns_R_R_I(INS_sqshrn, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_sqshrn, EA_8BYTE, REG_V2, REG_V3, 8, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_sqshrn2, EA_16BYTE, REG_V4, REG_V5, 1, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_sqshrn2, EA_16BYTE, REG_V6, REG_V7, 8, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_sqshrn, EA_8BYTE, REG_V8, REG_V9, 9, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_sqshrn, EA_8BYTE, REG_V10, REG_V11, 16, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_sqshrn2, EA_16BYTE, REG_V12, REG_V13, 9, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_sqshrn2, EA_16BYTE, REG_V14, REG_V15, 16, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_sqshrn, EA_8BYTE, REG_V16, REG_V17, 17, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_sqshrn, EA_8BYTE, REG_V18, REG_V18, 32, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_sqshrn2, EA_16BYTE, REG_V20, REG_V21, 17, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_sqshrn2, EA_16BYTE, REG_V22, REG_V23, 32, INS_OPTS_4S); + + // sqshrun scalar + theEmitter->emitIns_R_R_I(INS_sqshrun, EA_1BYTE, REG_V0, REG_V1, 1, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshrun, EA_1BYTE, REG_V2, REG_V3, 8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshrun, EA_2BYTE, REG_V4, REG_V5, 9, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshrun, EA_2BYTE, REG_V6, REG_V7, 16, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshrun, EA_4BYTE, REG_V8, REG_V9, 17, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_sqshrun, EA_4BYTE, REG_V10, REG_V11, 32, INS_OPTS_NONE); + + // sqshrun{2} vector + theEmitter->emitIns_R_R_I(INS_sqshrun, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_sqshrun, EA_8BYTE, REG_V2, REG_V3, 8, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_sqshrun2, EA_16BYTE, REG_V4, REG_V5, 1, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_sqshrun2, EA_16BYTE, REG_V6, REG_V7, 8, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_sqshrun, EA_8BYTE, REG_V8, REG_V9, 9, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_sqshrun, EA_8BYTE, REG_V10, REG_V11, 16, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_sqshrun2, EA_16BYTE, REG_V12, REG_V13, 9, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_sqshrun2, EA_16BYTE, REG_V14, REG_V15, 16, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_sqshrun, EA_8BYTE, REG_V16, REG_V17, 17, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_sqshrun, EA_8BYTE, REG_V18, REG_V18, 32, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_sqshrun2, EA_16BYTE, REG_V20, REG_V21, 17, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_sqshrun2, EA_16BYTE, REG_V22, REG_V23, 32, INS_OPTS_4S); + + // uqrshrn scalar + theEmitter->emitIns_R_R_I(INS_uqrshrn, EA_1BYTE, REG_V0, REG_V1, 1, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqrshrn, EA_1BYTE, REG_V2, REG_V3, 8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqrshrn, EA_2BYTE, REG_V4, REG_V5, 9, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqrshrn, EA_2BYTE, REG_V6, REG_V7, 16, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqrshrn, EA_4BYTE, REG_V8, REG_V9, 17, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqrshrn, EA_4BYTE, REG_V10, REG_V11, 32, INS_OPTS_NONE); + + // uqrshrn{2} vector + theEmitter->emitIns_R_R_I(INS_uqrshrn, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_uqrshrn, EA_8BYTE, REG_V2, REG_V3, 8, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_uqrshrn2, EA_16BYTE, REG_V4, REG_V5, 1, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_uqrshrn2, EA_16BYTE, REG_V6, REG_V7, 8, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_uqrshrn, EA_8BYTE, REG_V8, REG_V9, 9, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_uqrshrn, EA_8BYTE, REG_V10, REG_V11, 16, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_uqrshrn2, EA_16BYTE, REG_V12, REG_V13, 9, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_uqrshrn2, EA_16BYTE, REG_V14, REG_V15, 16, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_uqrshrn, EA_8BYTE, REG_V16, REG_V17, 17, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_uqrshrn, EA_8BYTE, REG_V18, REG_V18, 32, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_uqrshrn2, EA_16BYTE, REG_V20, REG_V21, 17, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_uqrshrn2, EA_16BYTE, REG_V22, REG_V23, 32, INS_OPTS_4S); + + // uqshl scalar + theEmitter->emitIns_R_R_I(INS_uqshl, EA_1BYTE, REG_V0, REG_V1, 0, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqshl, EA_1BYTE, REG_V2, REG_V3, 7, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqshl, EA_2BYTE, REG_V4, REG_V5, 8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqshl, EA_2BYTE, REG_V6, REG_V7, 15, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqshl, EA_4BYTE, REG_V8, REG_V9, 16, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqshl, EA_4BYTE, REG_V10, REG_V11, 31, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqshl, EA_8BYTE, REG_V12, REG_V13, 32, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqshl, EA_8BYTE, REG_V14, REG_V15, 63, INS_OPTS_NONE); + + // uqshl vector + theEmitter->emitIns_R_R_I(INS_uqshl, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_uqshl, EA_16BYTE, REG_V2, REG_V3, 7, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_uqshl, EA_8BYTE, REG_V4, REG_V5, 9, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_uqshl, EA_16BYTE, REG_V6, REG_V7, 15, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_uqshl, EA_8BYTE, REG_V8, REG_V9, 17, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_uqshl, EA_16BYTE, REG_V10, REG_V11, 31, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_uqshl, EA_16BYTE, REG_V12, REG_V13, 63, INS_OPTS_2D); + + // uqshrn scalar + theEmitter->emitIns_R_R_I(INS_uqshrn, EA_1BYTE, REG_V0, REG_V1, 1, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqshrn, EA_1BYTE, REG_V2, REG_V3, 8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqshrn, EA_2BYTE, REG_V4, REG_V5, 9, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqshrn, EA_2BYTE, REG_V6, REG_V7, 16, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqshrn, EA_4BYTE, REG_V8, REG_V9, 17, INS_OPTS_NONE); + theEmitter->emitIns_R_R_I(INS_uqshrn, EA_4BYTE, REG_V10, REG_V11, 32, INS_OPTS_NONE); + + // uqshrn{2} vector + theEmitter->emitIns_R_R_I(INS_uqshrn, EA_8BYTE, REG_V0, REG_V1, 1, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_uqshrn, EA_8BYTE, REG_V2, REG_V3, 8, INS_OPTS_8B); + theEmitter->emitIns_R_R_I(INS_uqshrn2, EA_16BYTE, REG_V4, REG_V5, 1, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_uqshrn2, EA_16BYTE, REG_V6, REG_V7, 8, INS_OPTS_16B); + theEmitter->emitIns_R_R_I(INS_uqshrn, EA_8BYTE, REG_V8, REG_V9, 9, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_uqshrn, EA_8BYTE, REG_V10, REG_V11, 16, INS_OPTS_4H); + theEmitter->emitIns_R_R_I(INS_uqshrn2, EA_16BYTE, REG_V12, REG_V13, 9, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_uqshrn2, EA_16BYTE, REG_V14, REG_V15, 16, INS_OPTS_8H); + theEmitter->emitIns_R_R_I(INS_uqshrn, EA_8BYTE, REG_V16, REG_V17, 17, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_uqshrn, EA_8BYTE, REG_V18, REG_V18, 32, INS_OPTS_2S); + theEmitter->emitIns_R_R_I(INS_uqshrn2, EA_16BYTE, REG_V20, REG_V21, 17, INS_OPTS_4S); + theEmitter->emitIns_R_R_I(INS_uqshrn2, EA_16BYTE, REG_V22, REG_V23, 32, INS_OPTS_4S); + #endif // ALL_ARM64_EMITTER_UNIT_TESTS #ifdef ALL_ARM64_EMITTER_UNIT_TESTS @@ -8610,6 +8759,380 @@ void CodeGen::genArm64EmitterUnitTests() theEmitter->emitIns_R_R_R(INS_zip2, EA_16BYTE, REG_V18, REG_V19, REG_V20, INS_OPTS_2D); #endif // ALL_ARM64_EMITTER_UNIT_TESTS +#ifdef ALL_ARM64_EMITTER_UNIT_TESTS + // srshl scalar + theEmitter->emitIns_R_R_R(INS_srshl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_NONE); + + // srshl vector + theEmitter->emitIns_R_R_R(INS_srshl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_srshl, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_srshl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_srshl, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_srshl, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_srshl, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + theEmitter->emitIns_R_R_R(INS_srshl, EA_16BYTE, REG_V18, REG_V19, REG_V20, INS_OPTS_2D); + + // sshl scalar + theEmitter->emitIns_R_R_R(INS_sshl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_NONE); + + // sshl vector + theEmitter->emitIns_R_R_R(INS_sshl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_sshl, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_sshl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_sshl, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_sshl, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_sshl, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + theEmitter->emitIns_R_R_R(INS_sshl, EA_16BYTE, REG_V18, REG_V19, REG_V20, INS_OPTS_2D); + + // urshl scalar + theEmitter->emitIns_R_R_R(INS_urshl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_NONE); + + // urshl vector + theEmitter->emitIns_R_R_R(INS_urshl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_urshl, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_urshl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_urshl, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_urshl, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_urshl, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + theEmitter->emitIns_R_R_R(INS_urshl, EA_16BYTE, REG_V18, REG_V19, REG_V20, INS_OPTS_2D); + + // ushl scalar + theEmitter->emitIns_R_R_R(INS_ushl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_NONE); + + // ushl vector + theEmitter->emitIns_R_R_R(INS_ushl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_ushl, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_ushl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_ushl, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_ushl, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_ushl, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + theEmitter->emitIns_R_R_R(INS_ushl, EA_16BYTE, REG_V18, REG_V19, REG_V20, INS_OPTS_2D); + + // addhn vector + theEmitter->emitIns_R_R_R(INS_addhn, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_addhn, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_addhn, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // addhn2 vector + theEmitter->emitIns_R_R_R(INS_addhn2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_addhn2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_addhn2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // raddhn vector + theEmitter->emitIns_R_R_R(INS_raddhn, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_raddhn, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_raddhn, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // raddhn2 vector + theEmitter->emitIns_R_R_R(INS_raddhn2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_raddhn2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_raddhn2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // rsubhn vector + theEmitter->emitIns_R_R_R(INS_rsubhn, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_rsubhn, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_rsubhn, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // rsubhn2 vector + theEmitter->emitIns_R_R_R(INS_rsubhn2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_rsubhn2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_rsubhn2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // sabal vector + theEmitter->emitIns_R_R_R(INS_sabal, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_sabal, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_sabal, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // sabal2 vector + theEmitter->emitIns_R_R_R(INS_sabal2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_sabal2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_sabal2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // sabdl vector + theEmitter->emitIns_R_R_R(INS_sabdl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_sabdl, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_sabdl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // sabdl2 vector + theEmitter->emitIns_R_R_R(INS_sabdl2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_sabdl2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_sabdl2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // saddl vector + theEmitter->emitIns_R_R_R(INS_saddl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_saddl, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_saddl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // saddl2 vector + theEmitter->emitIns_R_R_R(INS_saddl2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_saddl2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_saddl2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // saddw vector + theEmitter->emitIns_R_R_R(INS_saddw, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_saddw, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_saddw, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // saddw2 vector + theEmitter->emitIns_R_R_R(INS_saddw2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_saddw2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_saddw2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // shadd vector + theEmitter->emitIns_R_R_R(INS_shadd, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_shadd, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_shadd, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_shadd, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_shadd, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_shadd, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // shsub vector + theEmitter->emitIns_R_R_R(INS_shsub, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_shsub, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_shsub, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_shsub, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_shsub, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_shsub, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // sqadd scalar + theEmitter->emitIns_R_R_R(INS_sqadd, EA_1BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_sqadd, EA_2BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_sqadd, EA_4BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_sqadd, EA_8BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_NONE); + + // sqadd vector + theEmitter->emitIns_R_R_R(INS_sqadd, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_sqadd, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_sqadd, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_sqadd, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_sqadd, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_sqadd, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // sqrshl scalar + theEmitter->emitIns_R_R_R(INS_sqrshl, EA_1BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_sqrshl, EA_2BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_sqrshl, EA_4BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_sqrshl, EA_8BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_NONE); + + // sqrshl vector + theEmitter->emitIns_R_R_R(INS_sqrshl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_sqrshl, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_sqrshl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_sqrshl, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_sqrshl, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_sqrshl, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + theEmitter->emitIns_R_R_R(INS_sqrshl, EA_16BYTE, REG_V18, REG_V19, REG_V20, INS_OPTS_2D); + + // sqshl scalar + theEmitter->emitIns_R_R_R(INS_sqshl, EA_1BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_sqshl, EA_2BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_sqshl, EA_4BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_sqshl, EA_8BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_NONE); + + // sqshl vector + theEmitter->emitIns_R_R_R(INS_sqshl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_sqshl, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_sqshl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_sqshl, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_sqshl, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_sqshl, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + theEmitter->emitIns_R_R_R(INS_sqshl, EA_16BYTE, REG_V18, REG_V19, REG_V20, INS_OPTS_2D); + + // sqsub scalar + theEmitter->emitIns_R_R_R(INS_sqsub, EA_1BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_sqsub, EA_2BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_sqsub, EA_4BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_sqsub, EA_8BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_NONE); + + // sqsub vector + theEmitter->emitIns_R_R_R(INS_sqsub, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_sqsub, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_sqsub, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_sqsub, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_sqsub, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_sqsub, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // srhadd vector + theEmitter->emitIns_R_R_R(INS_srhadd, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_srhadd, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_srhadd, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_srhadd, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_srhadd, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_srhadd, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // ssubl vector + theEmitter->emitIns_R_R_R(INS_ssubl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_ssubl, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_ssubl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // ssubl2 vector + theEmitter->emitIns_R_R_R(INS_ssubl2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_ssubl2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_ssubl2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // ssubw vector + theEmitter->emitIns_R_R_R(INS_ssubw, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_ssubw, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_ssubw, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // ssubw2 vector + theEmitter->emitIns_R_R_R(INS_ssubw2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_ssubw2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_ssubw2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // subhn vector + theEmitter->emitIns_R_R_R(INS_subhn, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_subhn, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_subhn, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // subhn2 vector + theEmitter->emitIns_R_R_R(INS_subhn2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_subhn2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_subhn2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // uabal vector + theEmitter->emitIns_R_R_R(INS_uabal, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_uabal, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_uabal, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // uabal2 vector + theEmitter->emitIns_R_R_R(INS_uabal2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_uabal2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_uabal2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // uabdl vector + theEmitter->emitIns_R_R_R(INS_uabdl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_uabdl, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_uabdl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // uabdl2 vector + theEmitter->emitIns_R_R_R(INS_uabdl2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_uabdl2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_uabdl2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // uaddl vector + theEmitter->emitIns_R_R_R(INS_uaddl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_uaddl, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_uaddl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // uaddl2 vector + theEmitter->emitIns_R_R_R(INS_uaddl2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_uaddl2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_uaddl2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // uaddw vector + theEmitter->emitIns_R_R_R(INS_uaddw, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_uaddw, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_uaddw, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // uaddw2 vector + theEmitter->emitIns_R_R_R(INS_uaddw2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_uaddw2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_uaddw2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // uhadd vector + theEmitter->emitIns_R_R_R(INS_uhadd, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_uhadd, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_uhadd, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_uhadd, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_uhadd, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_uhadd, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // uhsub vector + theEmitter->emitIns_R_R_R(INS_uhsub, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_uhsub, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_uhsub, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_uhsub, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_uhsub, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_uhsub, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // uqadd scalar + theEmitter->emitIns_R_R_R(INS_uqadd, EA_1BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_uqadd, EA_2BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_uqadd, EA_4BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_uqadd, EA_8BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_NONE); + + // uqadd vector + theEmitter->emitIns_R_R_R(INS_uqadd, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_uqadd, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_uqadd, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_uqadd, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_uqadd, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_uqadd, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // uqrshl scalar + theEmitter->emitIns_R_R_R(INS_uqrshl, EA_1BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_uqrshl, EA_2BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_uqrshl, EA_4BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_uqrshl, EA_8BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_NONE); + + // uqrshl vector + theEmitter->emitIns_R_R_R(INS_uqrshl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_uqrshl, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_uqrshl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_uqrshl, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_uqrshl, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_uqrshl, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + theEmitter->emitIns_R_R_R(INS_uqrshl, EA_16BYTE, REG_V18, REG_V19, REG_V20, INS_OPTS_2D); + + // uqshl scalar + theEmitter->emitIns_R_R_R(INS_uqshl, EA_1BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_uqshl, EA_2BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_uqshl, EA_4BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_uqshl, EA_8BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_NONE); + + // uqshl vector + theEmitter->emitIns_R_R_R(INS_uqshl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_uqshl, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_uqshl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_uqshl, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_uqshl, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_uqshl, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + theEmitter->emitIns_R_R_R(INS_uqshl, EA_16BYTE, REG_V18, REG_V19, REG_V20, INS_OPTS_2D); + + // uqsub scalar + theEmitter->emitIns_R_R_R(INS_uqsub, EA_1BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_uqsub, EA_2BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_uqsub, EA_4BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_NONE); + theEmitter->emitIns_R_R_R(INS_uqsub, EA_8BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_NONE); + + // uqsub vector + theEmitter->emitIns_R_R_R(INS_uqsub, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_uqsub, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_uqsub, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_uqsub, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_uqsub, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_uqsub, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // urhadd vector + theEmitter->emitIns_R_R_R(INS_urhadd, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_urhadd, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_urhadd, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + theEmitter->emitIns_R_R_R(INS_urhadd, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_urhadd, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_urhadd, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // usubl vector + theEmitter->emitIns_R_R_R(INS_usubl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_usubl, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_usubl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // usubl2 vector + theEmitter->emitIns_R_R_R(INS_usubl2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_usubl2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_usubl2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // usubw vector + theEmitter->emitIns_R_R_R(INS_usubw, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_usubw, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_usubw, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // usubw2 vector + theEmitter->emitIns_R_R_R(INS_usubw2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_usubw2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_usubw2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); +#endif // ALL_ARM64_EMITTER_UNIT_TESTS + #ifdef ALL_ARM64_EMITTER_UNIT_TESTS // // R_R_R vector multiply @@ -8668,7 +9191,112 @@ void CodeGen::genArm64EmitterUnitTests() theEmitter->emitIns_R_R_R_I(INS_mls, EA_16BYTE, REG_V18, REG_V19, REG_V3, 0, INS_OPTS_8H); theEmitter->emitIns_R_R_R_I(INS_mls, EA_16BYTE, REG_V20, REG_V21, REG_V4, 3, INS_OPTS_8H); theEmitter->emitIns_R_R_R_I(INS_mls, EA_16BYTE, REG_V22, REG_V23, REG_V5, 7, INS_OPTS_8H); +#endif // ALL_ARM64_EMITTER_UNIT_TESTS +#ifdef ALL_ARM64_EMITTER_UNIT_TESTS + // pmull vector + theEmitter->emitIns_R_R_R(INS_pmull, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_pmull, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_1D); + + // pmull2 vector + theEmitter->emitIns_R_R_R(INS_pmull2, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_pmull2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_2D); + + // smlal vector + theEmitter->emitIns_R_R_R(INS_smlal, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_smlal, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_smlal, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // smlal2 vector + theEmitter->emitIns_R_R_R(INS_smlal2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_smlal2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_smlal2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // smlsl vector + theEmitter->emitIns_R_R_R(INS_smlsl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_smlsl, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_smlsl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // smlsl2 vector + theEmitter->emitIns_R_R_R(INS_smlsl2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_smlsl2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_smlsl2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // smull vector + theEmitter->emitIns_R_R_R(INS_smull, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_smull, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_smull, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // smull2 vector + theEmitter->emitIns_R_R_R(INS_smull2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_smull2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_smull2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // umlal vector + theEmitter->emitIns_R_R_R(INS_umlal, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_umlal, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_umlal, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // umlal2 vector + theEmitter->emitIns_R_R_R(INS_umlal2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_umlal2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_umlal2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // umlsl vector + theEmitter->emitIns_R_R_R(INS_umlsl, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_umlsl, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_umlsl, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // umlsl2 vector + theEmitter->emitIns_R_R_R(INS_umlsl2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_umlsl2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_umlsl2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // umull vector + theEmitter->emitIns_R_R_R(INS_umull, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B); + theEmitter->emitIns_R_R_R(INS_umull, EA_8BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_4H); + theEmitter->emitIns_R_R_R(INS_umull, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_2S); + + // umull2 vector + theEmitter->emitIns_R_R_R(INS_umull2, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_16B); + theEmitter->emitIns_R_R_R(INS_umull2, EA_16BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_8H); + theEmitter->emitIns_R_R_R(INS_umull2, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S); + + // smlal vector, by element + theEmitter->emitIns_R_R_R_I(INS_smlal, EA_8BYTE, REG_V0, REG_V1, REG_V2, 3, INS_OPTS_4H); + theEmitter->emitIns_R_R_R_I(INS_smlal, EA_8BYTE, REG_V3, REG_V4, REG_V5, 1, INS_OPTS_2S); + + // smlal2 vector, by element + theEmitter->emitIns_R_R_R_I(INS_smlal2, EA_16BYTE, REG_V6, REG_V7, REG_V8, 7, INS_OPTS_8H); + theEmitter->emitIns_R_R_R_I(INS_smlal2, EA_16BYTE, REG_V9, REG_V10, REG_V11, 3, INS_OPTS_4S); + + // smlsl vector, by element + theEmitter->emitIns_R_R_R_I(INS_smlsl, EA_8BYTE, REG_V0, REG_V1, REG_V2, 3, INS_OPTS_4H); + theEmitter->emitIns_R_R_R_I(INS_smlsl, EA_8BYTE, REG_V3, REG_V4, REG_V5, 1, INS_OPTS_2S); + + // smlsl2 vector, by element + theEmitter->emitIns_R_R_R_I(INS_smlsl2, EA_16BYTE, REG_V6, REG_V7, REG_V8, 7, INS_OPTS_8H); + theEmitter->emitIns_R_R_R_I(INS_smlsl2, EA_16BYTE, REG_V9, REG_V10, REG_V11, 3, INS_OPTS_4S); + + // smull vector, by element + theEmitter->emitIns_R_R_R_I(INS_smull, EA_8BYTE, REG_V0, REG_V1, REG_V2, 3, INS_OPTS_4H); + theEmitter->emitIns_R_R_R_I(INS_smull, EA_8BYTE, REG_V3, REG_V4, REG_V5, 1, INS_OPTS_2S); + + // smull2 vector, by element + theEmitter->emitIns_R_R_R_I(INS_smull2, EA_16BYTE, REG_V6, REG_V7, REG_V8, 7, INS_OPTS_8H); + theEmitter->emitIns_R_R_R_I(INS_smull2, EA_16BYTE, REG_V9, REG_V10, REG_V11, 3, INS_OPTS_4S); + + // umlsl2 vector, by element + theEmitter->emitIns_R_R_R_I(INS_umlsl2, EA_16BYTE, REG_V6, REG_V7, REG_V8, 7, INS_OPTS_8H); + theEmitter->emitIns_R_R_R_I(INS_umlsl2, EA_16BYTE, REG_V9, REG_V10, REG_V11, 3, INS_OPTS_4S); + + // umull vector, by element + theEmitter->emitIns_R_R_R_I(INS_umull, EA_8BYTE, REG_V0, REG_V1, REG_V2, 3, INS_OPTS_4H); + theEmitter->emitIns_R_R_R_I(INS_umull, EA_8BYTE, REG_V3, REG_V4, REG_V5, 1, INS_OPTS_2S); + + // umull2 vector, by element + theEmitter->emitIns_R_R_R_I(INS_umull2, EA_16BYTE, REG_V6, REG_V7, REG_V8, 7, INS_OPTS_8H); + theEmitter->emitIns_R_R_R_I(INS_umull2, EA_16BYTE, REG_V9, REG_V10, REG_V11, 3, INS_OPTS_4S); #endif // ALL_ARM64_EMITTER_UNIT_TESTS #ifdef ALL_ARM64_EMITTER_UNIT_TESTS @@ -8729,7 +9357,9 @@ void CodeGen::genArm64EmitterUnitTests() #endif // ALL_ARM64_EMITTER_UNIT_TESTS +#ifdef ALL_ARM64_EMITTER_UNIT_TESTS printf("*************** End of genArm64EmitterUnitTests()\n"); +#endif // ALL_ARM64_EMITTER_UNIT_TESTS } #endif // defined(DEBUG) @@ -8747,16 +9377,19 @@ void CodeGen::genArm64EmitterUnitTests() // on Windows as well just to be consistent, even though it should not be necessary. // // Arguments: -// frameSize - the size of the stack frame being allocated. -// initReg - register to use as a scratch register. -// pInitRegZeroed - OUT parameter. *pInitRegZeroed is set to 'false' if and only if -// this call sets 'initReg' to a non-zero value. -// maskArgRegsLiveIn - incoming argument registers that are currently live. +// frameSize - the size of the stack frame being allocated. +// initReg - register to use as a scratch register. +// pInitRegModified - OUT parameter. *pInitRegModified is set to 'true' if and only if +// this call sets 'initReg' to a non-zero value. +// maskArgRegsLiveIn - incoming argument registers that are currently live. // // Return value: // None // -void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn) +void CodeGen::genAllocLclFrame(unsigned frameSize, + regNumber initReg, + bool* pInitRegModified, + regMaskTP maskArgRegsLiveIn) { assert(compiler->compGeneratingProlog); @@ -8793,7 +9426,7 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni instGen_Set_Reg_To_Imm(EA_PTRSIZE, initReg, -(ssize_t)probeOffset); GetEmitter()->emitIns_R_R_R(INS_ldr, EA_4BYTE, REG_ZR, REG_SPBASE, initReg); regSet.verifyRegUsed(initReg); - *pInitRegZeroed = false; // The initReg does not contain zero + *pInitRegModified = true; lastTouchDelta -= pageSize; } @@ -8853,7 +9486,7 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni GetEmitter()->emitIns_R_R(INS_cmp, EA_PTRSIZE, rLimit, rOffset); // If equal, we need to probe again GetEmitter()->emitIns_J(INS_bls, NULL, -4); - *pInitRegZeroed = false; // The initReg does not contain zero + *pInitRegModified = true; compiler->unwindPadding(); @@ -8868,7 +9501,7 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni compiler->unwindPadding(); regSet.verifyRegUsed(initReg); - *pInitRegZeroed = false; // The initReg does not contain zero + *pInitRegModified = true; } } diff --git a/src/coreclr/src/jit/codegenarmarch.cpp b/src/coreclr/src/jit/codegenarmarch.cpp index 96deb2f791b2f3..9ca28936f24bf9 100644 --- a/src/coreclr/src/jit/codegenarmarch.cpp +++ b/src/coreclr/src/jit/codegenarmarch.cpp @@ -189,6 +189,13 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) genCodeForNegNot(treeNode); break; +#if defined(TARGET_ARM64) + case GT_BSWAP: + case GT_BSWAP16: + genCodeForBswap(treeNode); + break; +#endif // defined(TARGET_ARM64) + case GT_MOD: case GT_UMOD: case GT_DIV: @@ -391,8 +398,13 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) break; case GT_MEMORYBARRIER: - instGen_MemoryBarrier(); + { + CodeGen::BarrierKind barrierKind = + treeNode->gtFlags & GTF_MEMORYBARRIER_LOAD ? BARRIER_LOAD_ONLY : BARRIER_FULL; + + instGen_MemoryBarrier(barrierKind); break; + } #ifdef TARGET_ARM64 case GT_XCHG: @@ -468,7 +480,11 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) case GT_LABEL: genPendingCallLabel = genCreateTempLabel(); +#if defined(TARGET_ARM) + genMov32RelocatableDisplacement(genPendingCallLabel, targetReg); +#else emit->emitIns_R_L(INS_adr, EA_PTRSIZE, genPendingCallLabel, targetReg); +#endif break; case GT_STORE_OBJ: @@ -546,14 +562,14 @@ void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFla // genSetGSSecurityCookie: Set the "GS" security cookie in the prolog. // // Arguments: -// initReg - register to use as a scratch register -// pInitRegZeroed - OUT parameter. *pInitRegZeroed is set to 'false' if and only if -// this call sets 'initReg' to a non-zero value. +// initReg - register to use as a scratch register +// pInitRegModified - OUT parameter. *pInitRegModified is set to 'true' if and only if +// this call sets 'initReg' to a non-zero value. // // Return Value: // None // -void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed) +void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegModified) { assert(compiler->compGeneratingProlog); @@ -577,7 +593,7 @@ void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed) GetEmitter()->emitIns_S_R(INS_str, EA_PTRSIZE, initReg, compiler->lvaGSSecurityCookie, 0); } - *pInitRegZeroed = false; + *pInitRegModified = true; } //--------------------------------------------------------------------- @@ -1339,7 +1355,7 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode) #endif // FEATURE_ARG_SPLIT //---------------------------------------------------------------------------------- -// genMultiRegCallStoreToLocal: store multi-reg return value of a call node to a local +// genMultiRegStoreToLocal: store multi-reg return value of a call node to a local // // Arguments: // treeNode - Gentree of GT_STORE_LCL_VAR @@ -1348,42 +1364,35 @@ void CodeGen::genPutArgSplit(GenTreePutArgSplit* treeNode) // None // // Assumption: -// The child of store is a multi-reg call node. -// genProduceReg() on treeNode is made by caller of this routine. +// The child of store is a multi-reg node. // -void CodeGen::genMultiRegCallStoreToLocal(GenTree* treeNode) +void CodeGen::genMultiRegStoreToLocal(GenTree* treeNode) { assert(treeNode->OperGet() == GT_STORE_LCL_VAR); - -#if defined(TARGET_ARM) - // Longs are returned in two return registers on Arm32. - // Structs are returned in four registers on ARM32 and HFAs. - assert(varTypeIsLong(treeNode) || varTypeIsStruct(treeNode)); -#elif defined(TARGET_ARM64) - // Structs of size >=9 and <=16 are returned in two return registers on ARM64 and HFAs. - assert(varTypeIsStruct(treeNode)); -#endif // TARGET* + assert(varTypeIsStruct(treeNode) || varTypeIsMultiReg(treeNode)); + GenTree* op1 = treeNode->gtGetOp1(); + GenTree* actualOp1 = op1->gtSkipReloadOrCopy(); + assert(op1->IsMultiRegNode()); + unsigned regCount = actualOp1->GetMultiRegCount(); // Assumption: current implementation requires that a multi-reg // var in 'var = call' is flagged as lvIsMultiRegRet to prevent it from // being promoted. unsigned lclNum = treeNode->AsLclVarCommon()->GetLclNum(); - LclVarDsc* varDsc = &(compiler->lvaTable[lclNum]); - noway_assert(varDsc->lvIsMultiRegRet); - - GenTree* op1 = treeNode->gtGetOp1(); - GenTree* actualOp1 = op1->gtSkipReloadOrCopy(); - GenTreeCall* call = actualOp1->AsCall(); - assert(call->HasMultiRegRetVal()); + LclVarDsc* varDsc = compiler->lvaGetDesc(lclNum); + if (op1->OperIs(GT_CALL)) + { + assert(regCount <= MAX_RET_REG_COUNT); + noway_assert(varDsc->lvIsMultiRegRet); + } genConsumeRegs(op1); - ReturnTypeDesc* pRetTypeDesc = call->GetReturnTypeDesc(); - unsigned regCount = pRetTypeDesc->GetReturnRegCount(); + int offset = 0; - if (treeNode->GetRegNum() != REG_NA) + // Check for the case of an enregistered SIMD type that's returned in multiple registers. + if (varDsc->lvIsRegCandidate() && treeNode->GetRegNum() != REG_NA) { - // Right now the only enregistrable multi-reg return types supported are SIMD types. assert(varTypeIsSIMD(treeNode)); assert(regCount != 0); @@ -1393,8 +1402,8 @@ void CodeGen::genMultiRegCallStoreToLocal(GenTree* treeNode) // Insert pieces in reverse order for (int i = regCount - 1; i >= 0; --i) { - var_types type = pRetTypeDesc->GetReturnRegType(i); - regNumber reg = call->GetRegNumByIdx(i); + var_types type = op1->gtSkipReloadOrCopy()->GetRegTypeByIndex(i); + regNumber reg = op1->GetRegByIndex(i); if (op1->IsCopyOrReload()) { // GT_COPY/GT_RELOAD will have valid reg for those positions @@ -1433,21 +1442,16 @@ void CodeGen::genMultiRegCallStoreToLocal(GenTree* treeNode) } else { - // Stack store - int offset = 0; for (unsigned i = 0; i < regCount; ++i) { - var_types type = pRetTypeDesc->GetReturnRegType(i); - regNumber reg = call->GetRegNumByIdx(i); - if (op1->IsCopyOrReload()) + var_types type = actualOp1->GetRegTypeByIndex(i); + regNumber reg = op1->GetRegByIndex(i); + if (reg == REG_NA) { - // GT_COPY/GT_RELOAD will have valid reg for those positions + // GT_COPY/GT_RELOAD will have valid reg only for those positions // that need to be copied or reloaded. - regNumber reloadReg = op1->AsCopyOrReload()->GetRegNumByIdx(i); - if (reloadReg != REG_NA) - { - reg = reloadReg; - } + assert(op1->IsCopyOrReload()); + reg = actualOp1->GetRegByIndex(i); } assert(reg != REG_NA); @@ -1455,7 +1459,7 @@ void CodeGen::genMultiRegCallStoreToLocal(GenTree* treeNode) offset += genTypeSize(type); } - // Updating variable liveness after instruction was emitted + // Update variable liveness. genUpdateLife(treeNode); varDsc->SetRegNum(REG_STK); } @@ -1775,12 +1779,40 @@ void CodeGen::genCodeForLclFld(GenTreeLclFld* tree) NYI_IF(targetType == TYP_STRUCT, "GT_LCL_FLD: struct load local field not supported"); assert(targetReg != REG_NA); - emitAttr size = emitTypeSize(targetType); unsigned offs = tree->GetLclOffs(); unsigned varNum = tree->GetLclNum(); assert(varNum < compiler->lvaCount); - emit->emitIns_R_S(ins_Load(targetType), emitActualTypeSize(targetType), targetReg, varNum, offs); +#ifdef TARGET_ARM + if (tree->IsOffsetMisaligned()) + { + // Arm supports unaligned access only for integer types, + // load the floating data as 1 or 2 integer registers and convert them to float. + regNumber addr = tree->ExtractTempReg(); + emit->emitIns_R_S(INS_lea, EA_PTRSIZE, addr, varNum, offs); + + if (targetType == TYP_FLOAT) + { + regNumber floatAsInt = tree->GetSingleTempReg(); + emit->emitIns_R_R(INS_ldr, EA_4BYTE, floatAsInt, addr); + emit->emitIns_R_R(INS_vmov_i2f, EA_4BYTE, targetReg, floatAsInt); + } + else + { + regNumber halfdoubleAsInt1 = tree->ExtractTempReg(); + regNumber halfdoubleAsInt2 = tree->GetSingleTempReg(); + emit->emitIns_R_R_I(INS_ldr, EA_4BYTE, halfdoubleAsInt1, addr, 0); + emit->emitIns_R_R_I(INS_ldr, EA_4BYTE, halfdoubleAsInt2, addr, 4); + emit->emitIns_R_R_R(INS_vmov_i2d, EA_8BYTE, targetReg, halfdoubleAsInt1, halfdoubleAsInt2); + } + } + else +#endif // TARGET_ARM + { + emitAttr attr = emitActualTypeSize(targetType); + instruction ins = ins_Load(targetType); + emit->emitIns_R_S(ins, attr, targetReg, varNum, offs); + } genProduceReg(tree); } @@ -1905,11 +1937,9 @@ void CodeGen::genCodeForIndir(GenTreeIndir* tree) if (emitBarrier) { -#ifdef TARGET_ARM64 - instGen_MemoryBarrier(INS_BARRIER_ISHLD); -#else - instGen_MemoryBarrier(); -#endif + // when INS_ldar* could not be used for a volatile load, + // we use an ordinary load followed by a load barrier. + instGen_MemoryBarrier(BARRIER_LOAD_ONLY); } genProduceReg(tree); @@ -1941,13 +1971,8 @@ void CodeGen::genCodeForCpBlkHelper(GenTreeBlk* cpBlkNode) if (cpBlkNode->gtFlags & GTF_BLK_VOLATILE) { -#ifdef TARGET_ARM64 - // issue a INS_BARRIER_ISHLD after a volatile CpBlk operation - instGen_MemoryBarrier(INS_BARRIER_ISHLD); -#else - // issue a full memory barrier after a volatile CpBlk operation - instGen_MemoryBarrier(); -#endif // TARGET_ARM64 + // issue a load barrier after a volatile CpBlk operation + instGen_MemoryBarrier(BARRIER_LOAD_ONLY); } } @@ -2168,6 +2193,7 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node) if (node->IsVolatile()) { + // issue a full memory barrier before a volatile CpBlk operation instGen_MemoryBarrier(); } @@ -2265,11 +2291,8 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node) if (node->IsVolatile()) { -#ifdef TARGET_ARM64 - instGen_MemoryBarrier(INS_BARRIER_ISHLD); -#else - instGen_MemoryBarrier(); -#endif + // issue a load barrier after a volatile CpBlk operation + instGen_MemoryBarrier(BARRIER_LOAD_ONLY); } } @@ -2298,132 +2321,6 @@ void CodeGen::genCodeForInitBlkHelper(GenTreeBlk* initBlkNode) genEmitHelperCall(CORINFO_HELP_MEMSET, 0, EA_UNKNOWN); } -//------------------------------------------------------------------------ -// genRegCopy: Produce code for a GT_COPY node. -// -// Arguments: -// tree - the GT_COPY node -// -// Notes: -// This will copy the register(s) produced by this node's source, to -// the register(s) allocated to this GT_COPY node. -// It has some special handling for these cases: -// - when the source and target registers are in different register files -// (note that this is *not* a conversion). -// - when the source is a lclVar whose home location is being moved to a new -// register (rather than just being copied for temporary use). -// -void CodeGen::genRegCopy(GenTree* treeNode) -{ - assert(treeNode->OperGet() == GT_COPY); - GenTree* op1 = treeNode->AsOp()->gtOp1; - - regNumber sourceReg = genConsumeReg(op1); - - if (op1->IsMultiRegNode()) - { - noway_assert(!op1->IsCopyOrReload()); - unsigned regCount = op1->GetMultiRegCount(); - for (unsigned i = 0; i < regCount; i++) - { - regNumber srcReg = op1->GetRegByIndex(i); - regNumber tgtReg = treeNode->AsCopyOrReload()->GetRegNumByIdx(i); - var_types regType = op1->GetRegTypeByIndex(i); - inst_RV_RV(ins_Copy(regType), tgtReg, srcReg, regType); - } - } - else - { - var_types targetType = treeNode->TypeGet(); - regNumber targetReg = treeNode->GetRegNum(); - assert(targetReg != REG_NA); - assert(targetType != TYP_STRUCT); - - // Check whether this node and the node from which we're copying the value have the same - // register type. - // This can happen if (currently iff) we have a SIMD vector type that fits in an integer - // register, in which case it is passed as an argument, or returned from a call, - // in an integer register and must be copied if it's in a floating point register. - - bool srcFltReg = (varTypeIsFloating(op1) || varTypeIsSIMD(op1)); - bool tgtFltReg = (varTypeIsFloating(treeNode) || varTypeIsSIMD(treeNode)); - if (srcFltReg != tgtFltReg) - { -#ifdef TARGET_ARM64 - inst_RV_RV(INS_fmov, targetReg, sourceReg, targetType); -#else // !TARGET_ARM64 - if (varTypeIsFloating(treeNode)) - { - // GT_COPY from 'int' to 'float' currently can't happen. Maybe if ARM SIMD is implemented - // it will happen, according to the comment above? - NYI_ARM("genRegCopy from 'int' to 'float'"); - } - else - { - assert(varTypeIsFloating(op1)); - - if (op1->TypeGet() == TYP_FLOAT) - { - inst_RV_RV(INS_vmov_f2i, targetReg, genConsumeReg(op1), targetType); - } - else - { - regNumber otherReg = (regNumber)treeNode->AsCopyOrReload()->gtOtherRegs[0]; - assert(otherReg != REG_NA); - inst_RV_RV_RV(INS_vmov_d2i, targetReg, otherReg, genConsumeReg(op1), EA_8BYTE); - } - } -#endif // !TARGET_ARM64 - } - else - { - inst_RV_RV(ins_Copy(targetType), targetReg, sourceReg, targetType); - } - } - - if (op1->IsLocal()) - { - // The lclVar will never be a def. - // If it is a last use, the lclVar will be killed by genConsumeReg(), as usual, and genProduceReg will - // appropriately set the gcInfo for the copied value. - // If not, there are two cases we need to handle: - // - If this is a TEMPORARY copy (indicated by the GTF_VAR_DEATH flag) the variable - // will remain live in its original register. - // genProduceReg() will appropriately set the gcInfo for the copied value, - // and genConsumeReg will reset it. - // - Otherwise, we need to update register info for the lclVar. - - GenTreeLclVarCommon* lcl = op1->AsLclVarCommon(); - assert((lcl->gtFlags & GTF_VAR_DEF) == 0); - - if ((lcl->gtFlags & GTF_VAR_DEATH) == 0 && (treeNode->gtFlags & GTF_VAR_DEATH) == 0) - { - LclVarDsc* varDsc = &compiler->lvaTable[lcl->GetLclNum()]; - - // If we didn't just spill it (in genConsumeReg, above), then update the register info - if (varDsc->GetRegNum() != REG_STK) - { - // The old location is dying - genUpdateRegLife(varDsc, /*isBorn*/ false, /*isDying*/ true DEBUGARG(op1)); - - gcInfo.gcMarkRegSetNpt(genRegMask(op1->GetRegNum())); - - genUpdateVarReg(varDsc, treeNode); - -#ifdef USING_VARIABLE_LIVE_RANGE - // Report the home change for this variable - varLiveKeeper->siUpdateVariableLiveRange(varDsc, lcl->GetLclNum()) -#endif // USING_VARIABLE_LIVE_RANGE - - // The new location is going live - genUpdateRegLife(varDsc, /*isBorn*/ true, /*isDying*/ false DEBUGARG(treeNode)); - } - } - } - - genProduceReg(treeNode); -} - //------------------------------------------------------------------------ // genCallInstruction: Produce code for a GT_CALL node // @@ -2575,9 +2472,9 @@ void CodeGen::genCallInstruction(GenTreeCall* call) } // Determine return value size(s). - ReturnTypeDesc* pRetTypeDesc = call->GetReturnTypeDesc(); - emitAttr retSize = EA_PTRSIZE; - emitAttr secondRetSize = EA_UNKNOWN; + const ReturnTypeDesc* pRetTypeDesc = call->GetReturnTypeDesc(); + emitAttr retSize = EA_PTRSIZE; + emitAttr secondRetSize = EA_UNKNOWN; if (call->HasMultiRegRetVal()) { @@ -2623,6 +2520,27 @@ void CodeGen::genCallInstruction(GenTreeCall* call) INDEBUG_LDISASM_COMMA(sigInfo) nullptr, // addr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize), ilOffset, target->GetRegNum()); } + else if (call->IsR2ROrVirtualStubRelativeIndir()) + { + // Generate a direct call to a non-virtual user defined or helper method + assert(callType == CT_HELPER || callType == CT_USER_FUNC); + assert(((call->IsR2RRelativeIndir()) && (call->gtEntryPoint.accessType == IAT_PVALUE)) || + ((call->IsVirtualStubRelativeIndir()) && (call->gtEntryPoint.accessType == IAT_VALUE))); + assert(call->gtControlExpr == nullptr); + assert(!call->IsTailCall()); + + regNumber tmpReg = call->GetSingleTempReg(); + GetEmitter()->emitIns_R_R(ins_Load(TYP_I_IMPL), emitActualTypeSize(TYP_I_IMPL), tmpReg, REG_R2R_INDIRECT_PARAM); + + // We have now generated code for gtControlExpr evaluating it into `tmpReg`. + // We just need to emit "call tmpReg" in this case. + // + assert(genIsValidIntReg(tmpReg)); + + genEmitCall(emitter::EC_INDIR_R, methHnd, + INDEBUG_LDISASM_COMMA(sigInfo) nullptr, // addr + retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize), ilOffset, tmpReg); + } else { // Generate a direct call to a non-virtual user defined or helper method @@ -2692,7 +2610,6 @@ void CodeGen::genCallInstruction(GenTreeCall* call) // if it was a pinvoke we may have needed to get the address of a label if (genPendingCallLabel) { - assert(call->IsUnmanaged()); genDefineInlineTempLabel(genPendingCallLabel); genPendingCallLabel = nullptr; } @@ -3725,264 +3642,49 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea) genProduceReg(lea); } +#ifdef FEATURE_SIMD //------------------------------------------------------------------------ -// isStructReturn: Returns whether the 'treeNode' is returning a struct. -// -// Arguments: -// treeNode - The tree node to evaluate whether is a struct return. -// -// Return Value: -// Returns true if the 'treeNode" is a GT_RETURN node of type struct. -// Otherwise returns false. -// -bool CodeGen::isStructReturn(GenTree* treeNode) -{ - // This method could be called for 'treeNode' of GT_RET_FILT or GT_RETURN. - // For the GT_RET_FILT, the return is always - // a bool or a void, for the end of a finally block. - noway_assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT); - var_types returnType = treeNode->TypeGet(); - -#ifdef TARGET_ARM64 - return varTypeIsStruct(returnType) && (compiler->info.compRetNativeType == TYP_STRUCT); -#else - return varTypeIsStruct(returnType); -#endif -} - -//------------------------------------------------------------------------ -// genStructReturn: Generates code for returning a struct. +// genSIMDSplitReturn: Generates code for returning a fixed-size SIMD type that lives +// in a single register, but is returned in multiple registers. // // Arguments: -// treeNode - The GT_RETURN tree node. -// -// Return Value: -// None +// src - The source of the return +// retTypeDesc - The return type descriptor. // -// Assumption: -// op1 of GT_RETURN node is either GT_LCL_VAR or multi-reg GT_CALL -void CodeGen::genStructReturn(GenTree* treeNode) +void CodeGen::genSIMDSplitReturn(GenTree* src, ReturnTypeDesc* retTypeDesc) { - assert(treeNode->OperGet() == GT_RETURN); - assert(isStructReturn(treeNode)); - GenTree* op1 = treeNode->gtGetOp1(); - - if (op1->OperGet() == GT_LCL_VAR) - { - GenTreeLclVarCommon* lclVar = op1->AsLclVarCommon(); - LclVarDsc* varDsc = &(compiler->lvaTable[lclVar->GetLclNum()]); - var_types lclType = genActualType(varDsc->TypeGet()); - - assert(varTypeIsStruct(lclType)); - assert(varDsc->lvIsMultiRegRet); - - ReturnTypeDesc retTypeDesc; - unsigned regCount; - - retTypeDesc.InitializeStructReturnType(compiler, varDsc->lvVerTypeInfo.GetClassHandle()); - regCount = retTypeDesc.GetReturnRegCount(); - - assert(regCount >= 2); - - assert(varTypeIsSIMD(lclType) || op1->isContained()); - - if (op1->isContained()) - { - // Copy var on stack into ABI return registers - // TODO: It could be optimized by reducing two float loading to one double - int offset = 0; - for (unsigned i = 0; i < regCount; ++i) - { - var_types type = retTypeDesc.GetReturnRegType(i); - regNumber reg = retTypeDesc.GetABIReturnReg(i); - GetEmitter()->emitIns_R_S(ins_Load(type), emitTypeSize(type), reg, lclVar->GetLclNum(), offset); - offset += genTypeSize(type); - } + assert(varTypeIsSIMD(src)); + assert(src->isUsedFromReg()); + regNumber srcReg = src->GetRegNum(); + + // Treat src register as a homogenous vector with element size equal to the reg size + // Insert pieces in order + unsigned regCount = retTypeDesc->GetReturnRegCount(); + for (unsigned i = 0; i < regCount; ++i) + { + var_types type = retTypeDesc->GetReturnRegType(i); + regNumber reg = retTypeDesc->GetABIReturnReg(i); + if (varTypeIsFloating(type)) + { + // If the register piece is to be passed in a floating point register + // Use a vector mov element instruction + // reg is not a vector, so it is in the first element reg[0] + // mov reg[0], src[i] + // This effectively moves from `src[i]` to `reg[0]`, upper bits of reg remain unchanged + // For the case where src == reg, since we are only writing reg[0], as long as we iterate + // so that src[0] is consumed before writing reg[0], we do not need a temporary. + GetEmitter()->emitIns_R_R_I_I(INS_mov, emitTypeSize(type), reg, srcReg, 0, i); } else { - // Handle SIMD genStructReturn case - NYI_ARM("SIMD genStructReturn"); - -#ifdef TARGET_ARM64 - genConsumeRegs(op1); - regNumber src = op1->GetRegNum(); - - // Treat src register as a homogenous vector with element size equal to the reg size - // Insert pieces in order - for (unsigned i = 0; i < regCount; ++i) - { - var_types type = retTypeDesc.GetReturnRegType(i); - regNumber reg = retTypeDesc.GetABIReturnReg(i); - if (varTypeIsFloating(type)) - { - // If the register piece is to be passed in a floating point register - // Use a vector mov element instruction - // reg is not a vector, so it is in the first element reg[0] - // mov reg[0], src[i] - // This effectively moves from `src[i]` to `reg[0]`, upper bits of reg remain unchanged - // For the case where src == reg, since we are only writing reg[0], as long as we iterate - // so that src[0] is consumed before writing reg[0], we do not need a temporary. - GetEmitter()->emitIns_R_R_I_I(INS_mov, emitTypeSize(type), reg, src, 0, i); - } - else - { - // If the register piece is to be passed in an integer register - // Use a vector mov to general purpose register instruction - // mov reg, src[i] - // This effectively moves from `src[i]` to `reg` - GetEmitter()->emitIns_R_R_I(INS_mov, emitTypeSize(type), reg, src, i); - } - } -#endif // TARGET_ARM64 + // If the register piece is to be passed in an integer register + // Use a vector mov to general purpose register instruction + // mov reg, src[i] + // This effectively moves from `src[i]` to `reg` + GetEmitter()->emitIns_R_R_I(INS_mov, emitTypeSize(type), reg, srcReg, i); } } - else // op1 must be multi-reg GT_CALL - { - assert(op1->IsMultiRegCall() || op1->IsCopyOrReloadOfMultiRegCall()); - - genConsumeRegs(op1); - - GenTree* actualOp1 = op1->gtSkipReloadOrCopy(); - GenTreeCall* call = actualOp1->AsCall(); - - ReturnTypeDesc* pRetTypeDesc; - unsigned regCount; - unsigned matchingCount = 0; - - pRetTypeDesc = call->GetReturnTypeDesc(); - regCount = pRetTypeDesc->GetReturnRegCount(); - - var_types regType[MAX_RET_REG_COUNT]; - regNumber returnReg[MAX_RET_REG_COUNT]; - regNumber allocatedReg[MAX_RET_REG_COUNT]; - regMaskTP srcRegsMask = 0; - regMaskTP dstRegsMask = 0; - bool needToShuffleRegs = false; // Set to true if we have to move any registers - - for (unsigned i = 0; i < regCount; ++i) - { - regType[i] = pRetTypeDesc->GetReturnRegType(i); - returnReg[i] = pRetTypeDesc->GetABIReturnReg(i); - - regNumber reloadReg = REG_NA; - if (op1->IsCopyOrReload()) - { - // GT_COPY/GT_RELOAD will have valid reg for those positions - // that need to be copied or reloaded. - reloadReg = op1->AsCopyOrReload()->GetRegNumByIdx(i); - } - - if (reloadReg != REG_NA) - { - allocatedReg[i] = reloadReg; - } - else - { - allocatedReg[i] = call->GetRegNumByIdx(i); - } - - if (returnReg[i] == allocatedReg[i]) - { - matchingCount++; - } - else // We need to move this value - { - // We want to move the value from allocatedReg[i] into returnReg[i] - // so record these two registers in the src and dst masks - // - srcRegsMask |= genRegMask(allocatedReg[i]); - dstRegsMask |= genRegMask(returnReg[i]); - - needToShuffleRegs = true; - } - } - - if (needToShuffleRegs) - { - assert(matchingCount < regCount); - - unsigned remainingRegCount = regCount - matchingCount; - regMaskTP extraRegMask = treeNode->gtRsvdRegs; - - while (remainingRegCount > 0) - { - // set 'available' to the 'dst' registers that are not currently holding 'src' registers - // - regMaskTP availableMask = dstRegsMask & ~srcRegsMask; - - regMaskTP dstMask; - regNumber srcReg; - regNumber dstReg; - var_types curType = TYP_UNKNOWN; - regNumber freeUpReg = REG_NA; - - if (availableMask == 0) - { - // Circular register dependencies - // So just free up the lowest register in dstRegsMask by moving it to the 'extra' register - - assert(dstRegsMask == srcRegsMask); // this has to be true for us to reach here - assert(extraRegMask != 0); // we require an 'extra' register - assert((extraRegMask & ~dstRegsMask) != 0); // it can't be part of dstRegsMask - - availableMask = extraRegMask & ~dstRegsMask; - - regMaskTP srcMask = genFindLowestBit(srcRegsMask); - freeUpReg = genRegNumFromMask(srcMask); - } - - dstMask = genFindLowestBit(availableMask); - dstReg = genRegNumFromMask(dstMask); - srcReg = REG_NA; - - if (freeUpReg != REG_NA) - { - // We will free up the srcReg by moving it to dstReg which is an extra register - // - srcReg = freeUpReg; - - // Find the 'srcReg' and set 'curType', change allocatedReg[] to dstReg - // and add the new register mask bit to srcRegsMask - // - for (unsigned i = 0; i < regCount; ++i) - { - if (allocatedReg[i] == srcReg) - { - curType = regType[i]; - allocatedReg[i] = dstReg; - srcRegsMask |= genRegMask(dstReg); - } - } - } - else // The normal case - { - // Find the 'srcReg' and set 'curType' - // - for (unsigned i = 0; i < regCount; ++i) - { - if (returnReg[i] == dstReg) - { - srcReg = allocatedReg[i]; - curType = regType[i]; - } - } - // After we perform this move we will have one less registers to setup - remainingRegCount--; - } - assert(curType != TYP_UNKNOWN); - - inst_RV_RV(ins_Copy(curType), dstReg, srcReg, curType); - - // Clear the appropriate bits in srcRegsMask and dstRegsMask - srcRegsMask &= ~genRegMask(srcReg); - dstRegsMask &= ~genRegMask(dstReg); - - } // while (remainingRegCount > 0) - - } // (needToShuffleRegs) - - } // op1 must be multi-reg GT_CALL } +#endif // FEATURE_SIMD #endif // TARGET_ARMARCH diff --git a/src/coreclr/src/jit/codegencommon.cpp b/src/coreclr/src/jit/codegencommon.cpp index c087fbf43bbc20..7f011b56861be9 100644 --- a/src/coreclr/src/jit/codegencommon.cpp +++ b/src/coreclr/src/jit/codegencommon.cpp @@ -3851,7 +3851,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere #endif // !TARGET_64BIT { // If this arg is never on the stack, go to the next one. - if (!regArgTab[argNum].stackArg) + if (!regArgTab[argNum].stackArg && !regArgTab[argNum].writeThru) { continue; } @@ -4596,8 +4596,9 @@ void CodeGen::genCheckUseBlockInit() // double-counting the initialization impact of any locals. bool counted = false; - if (varDsc->lvIsParam) + if (!varDsc->lvIsInReg() && !varDsc->lvOnFrame) { + noway_assert(varDsc->lvRefCnt() == 0); continue; } @@ -4608,43 +4609,10 @@ void CodeGen::genCheckUseBlockInit() continue; } - // Likewise, initialization of the GS cookie is handled specially for OSR. - // Could do this for non-OSR too.. (likewise for the dummy) - if (compiler->opts.IsOSR() && varNum == compiler->lvaGSSecurityCookie) - { - continue; - } - - if (!varDsc->lvIsInReg() && !varDsc->lvOnFrame) - { - noway_assert(varDsc->lvRefCnt() == 0); - continue; - } - - if (varNum == compiler->lvaInlinedPInvokeFrameVar || varNum == compiler->lvaStubArgumentVar) - { - continue; - } - -#if FEATURE_FIXED_OUT_ARGS - if (varNum == compiler->lvaPInvokeFrameRegSaveVar) - { - continue; - } - if (varNum == compiler->lvaOutgoingArgSpaceVar) - { - continue; - } -#endif - -#if defined(FEATURE_EH_FUNCLETS) - // There's no need to force 0-initialization of the PSPSym, it will be - // initialized with a real value in the prolog - if (varNum == compiler->lvaPSPSym) + if (compiler->fgVarIsNeverZeroInitializedInProlog(varNum)) { continue; } -#endif if (compiler->lvaIsFieldOfDependentlyPromotedStruct(varDsc)) { @@ -4654,6 +4622,12 @@ void CodeGen::genCheckUseBlockInit() continue; } + if (varDsc->lvHasExplicitInit) + { + varDsc->lvMustInit = 0; + continue; + } + if (compiler->info.compInitMem || varDsc->HasGCPtr() || varDsc->lvMustInit) { if (varDsc->lvTracked) @@ -4847,7 +4821,7 @@ void CodeGen::genCheckUseBlockInit() */ #if defined(TARGET_ARM64) -void CodeGen::genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroed) +void CodeGen::genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegModified) #else void CodeGen::genPushCalleeSavedRegisters() #endif @@ -5336,7 +5310,8 @@ void CodeGen::genPushCalleeSavedRegisters() JITDUMP(" spAdjustment2=%d\n", spAdjustment2); - genPrologSaveRegPair(REG_FP, REG_LR, alignmentAdjustment2, -spAdjustment2, false, initReg, pInitRegZeroed); + genPrologSaveRegPair(REG_FP, REG_LR, alignmentAdjustment2, -spAdjustment2, false, initReg, + pInitRegModified); offset += spAdjustment2; // Now subtract off the #outsz (or the rest of the #outsz if it was unaligned, and the above "sub" @@ -5356,13 +5331,13 @@ void CodeGen::genPushCalleeSavedRegisters() // We've already established the frame pointer, so no need to report the stack pointer change to unwind // info. - genStackPointerAdjustment(-spAdjustment3, initReg, pInitRegZeroed, /* reportUnwindData */ false); + genStackPointerAdjustment(-spAdjustment3, initReg, pInitRegModified, /* reportUnwindData */ false); offset += spAdjustment3; } else { genPrologSaveRegPair(REG_FP, REG_LR, compiler->lvaOutgoingArgSpaceSize, -remainingFrameSz, false, initReg, - pInitRegZeroed); + pInitRegModified); offset += remainingFrameSz; offsetSpToSavedFp = compiler->lvaOutgoingArgSpaceSize; @@ -5394,7 +5369,7 @@ void CodeGen::genPushCalleeSavedRegisters() JITDUMP(" remainingFrameSz=%d\n", remainingFrameSz); // We've already established the frame pointer, so no need to report the stack pointer change to unwind info. - genStackPointerAdjustment(-remainingFrameSz, initReg, pInitRegZeroed, /* reportUnwindData */ false); + genStackPointerAdjustment(-remainingFrameSz, initReg, pInitRegModified, /* reportUnwindData */ false); offset += remainingFrameSz; } else @@ -6123,17 +6098,17 @@ void CodeGen::genPopCalleeSavedRegisters(bool jmpEpilog) #endif // TARGET* -// We need a register with value zero. Zero the initReg, if necessary, and set *pInitRegZeroed if so. +// We need a register with value zero. Zero the initReg, if necessary, and set *pInitRegModified if so. // Return the register to use. On ARM64, we never touch the initReg, and always just return REG_ZR. -regNumber CodeGen::genGetZeroReg(regNumber initReg, bool* pInitRegZeroed) +regNumber CodeGen::genGetZeroReg(regNumber initReg, bool* pInitRegModified) { #ifdef TARGET_ARM64 return REG_ZR; #else // !TARGET_ARM64 - if (*pInitRegZeroed == false) + if (*pInitRegModified) { instGen_Set_Reg_To_Zero(EA_PTRSIZE, initReg); - *pInitRegZeroed = true; + *pInitRegModified = false; } return initReg; #endif // !TARGET_ARM64 @@ -6143,14 +6118,14 @@ regNumber CodeGen::genGetZeroReg(regNumber initReg, bool* pInitRegZeroed) // genZeroInitFrame: Zero any untracked pointer locals and/or initialize memory for locspace // // Arguments: -// untrLclHi - (Untracked locals High-Offset) The upper bound offset at which the zero init -// code will end initializing memory (not inclusive). -// untrLclLo - (Untracked locals Low-Offset) The lower bound at which the zero init code will -// start zero initializing memory. -// initReg - A scratch register (that gets set to zero on some platforms). -// pInitRegZeroed - Sets a flag that tells the callee whether or not the initReg register got zeroed. +// untrLclHi - (Untracked locals High-Offset) The upper bound offset at which the zero init +// code will end initializing memory (not inclusive). +// untrLclLo - (Untracked locals Low-Offset) The lower bound at which the zero init code will +// start zero initializing memory. +// initReg - A scratch register (that gets set to zero on some platforms). +// pInitRegModified - Sets a flag that tells the callee whether or not the initReg register got zeroed. // -void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, bool* pInitRegZeroed) +void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, bool* pInitRegModified) { assert(compiler->compGeneratingProlog); @@ -6225,8 +6200,8 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, #else // !define(TARGET_ARM) - rAddr = initReg; - *pInitRegZeroed = false; + rAddr = initReg; + *pInitRegModified = true; #endif // !defined(TARGET_ARM) @@ -6267,7 +6242,7 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, // Load immediate into the InitReg register instGen_Set_Reg_To_Imm(EA_PTRSIZE, initReg, (ssize_t)untrLclLo); GetEmitter()->emitIns_R_R_R(INS_add, EA_PTRSIZE, rAddr, genFramePointerReg(), initReg); - *pInitRegZeroed = false; + *pInitRegModified = true; } if (useLoop) @@ -6279,7 +6254,7 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, } #if defined(TARGET_ARM) - rZero1 = genGetZeroReg(initReg, pInitRegZeroed); + rZero1 = genGetZeroReg(initReg, pInitRegModified); instGen_Set_Reg_To_Zero(EA_PTRSIZE, rZero2); target_ssize_t stmImm = (target_ssize_t)(genRegMask(rZero1) | genRegMask(rZero2)); #endif // TARGET_ARM @@ -6368,7 +6343,7 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, #endif if (blkSize < minSimdSize) { - zeroReg = genGetZeroReg(initReg, pInitRegZeroed); + zeroReg = genGetZeroReg(initReg, pInitRegModified); int i = 0; for (; i + REGSIZE_BYTES <= blkSize; i += REGSIZE_BYTES) @@ -6430,7 +6405,7 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, assert(alignmentLoBlkSize < XMM_REGSIZE_BYTES); assert((alignedLclLo - alignmentLoBlkSize) == untrLclLo); - zeroReg = genGetZeroReg(initReg, pInitRegZeroed); + zeroReg = genGetZeroReg(initReg, pInitRegModified); int i = 0; for (; i + REGSIZE_BYTES <= alignmentLoBlkSize; i += REGSIZE_BYTES) @@ -6538,7 +6513,7 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, emit->emitIns_J(INS_jne, nullptr, -5); // initReg will be zero at end of the loop - *pInitRegZeroed = true; + *pInitRegModified = false; } if (untrLclHi != alignedLclHi) @@ -6547,7 +6522,7 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, assert(alignmentHiBlkSize < XMM_REGSIZE_BYTES); assert((alignedLclHi + alignmentHiBlkSize) == untrLclHi); - zeroReg = genGetZeroReg(initReg, pInitRegZeroed); + zeroReg = genGetZeroReg(initReg, pInitRegModified); int i = 0; for (; i + REGSIZE_BYTES <= alignmentHiBlkSize; i += REGSIZE_BYTES) @@ -6614,13 +6589,13 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, if (layout->IsGCPtr(i)) { GetEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, - genGetZeroReg(initReg, pInitRegZeroed), varNum, i * REGSIZE_BYTES); + genGetZeroReg(initReg, pInitRegModified), varNum, i * REGSIZE_BYTES); } } } else { - regNumber zeroReg = genGetZeroReg(initReg, pInitRegZeroed); + regNumber zeroReg = genGetZeroReg(initReg, pInitRegModified); // zero out the whole thing rounded up to a single stack slot size unsigned lclSize = roundUp(compiler->lvaLclSize(varNum), (unsigned)sizeof(int)); @@ -6652,7 +6627,7 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, // printf("initialize untracked spillTmp [EBP-%04X]\n", stkOffs); - inst_ST_RV(ins_Store(TYP_I_IMPL), tempThis, 0, genGetZeroReg(initReg, pInitRegZeroed), TYP_I_IMPL); + inst_ST_RV(ins_Store(TYP_I_IMPL), tempThis, 0, genGetZeroReg(initReg, pInitRegModified), TYP_I_IMPL); } } @@ -6787,7 +6762,7 @@ void CodeGen::genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, * ICodeManager::GetParamTypeArg(). */ -void CodeGen::genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed) +void CodeGen::genReportGenericContextArg(regNumber initReg, bool* pInitRegModified) { // For OSR the original method has set this up for us. if (compiler->opts.IsOSR()) @@ -6852,8 +6827,8 @@ void CodeGen::genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed // We will just use the initReg since it is an available register // and we are probably done using it anyway... - reg = initReg; - *pInitRegZeroed = false; + reg = initReg; + *pInitRegModified = true; // mov reg, [compiler->info.compTypeCtxtArg] GetEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, reg, genFramePointerReg(), varDsc->lvStkOffs); @@ -7568,6 +7543,25 @@ void CodeGen::genFnProlog() bool isInReg = varDsc->lvIsInReg(); bool isInMemory = !isInReg || varDsc->lvLiveInOutOfHndlr; + + // Note that 'lvIsInReg()' will only be accurate for variables that are actually live-in to + // the first block. This will include all possibly-uninitialized locals, whose liveness + // will naturally propagate up to the entry block. However, we also set 'lvMustInit' for + // locals that are live-in to a finally block, and those may not be live-in to the first + // block. For those, we don't want to initialize the register, as it will not actually be + // occupying it on entry. + if (isInReg) + { + if (compiler->lvaEnregEHVars && varDsc->lvLiveInOutOfHndlr) + { + isInReg = VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex); + } + else + { + assert(VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex)); + } + } + if (isInReg) { regMaskTP regMask = genRegMask(varDsc->GetRegNum()); @@ -7678,9 +7672,9 @@ void CodeGen::genFnProlog() /* Choose the register to use for zero initialization */ - regNumber initReg = REG_SCRATCH; // Unless we find a better register below - bool initRegZeroed = false; - regMaskTP excludeMask = intRegState.rsCalleeRegArgMaskLiveIn; + regNumber initReg = REG_SCRATCH; // Unless we find a better register below + bool initRegModified = true; + regMaskTP excludeMask = intRegState.rsCalleeRegArgMaskLiveIn; regMaskTP tempMask; // We should not use the special PINVOKE registers as the initReg @@ -7813,11 +7807,11 @@ void CodeGen::genFnProlog() // been calculated to be one of the callee-saved registers (say, if all the integer argument registers are // in use, and perhaps with other conditions being satisfied). This is ok in other cases, after the callee-saved // registers have been saved. So instead of letting genAllocLclFrame use initReg as a temporary register, - // always use REG_SCRATCH. We don't care if it trashes it, so ignore the initRegZeroed output argument. - bool ignoreInitRegZeroed = false; - genAllocLclFrame(compiler->compLclFrameSize, REG_SCRATCH, &ignoreInitRegZeroed, + // always use REG_SCRATCH. We don't care if it trashes it, so ignore the initRegModified output argument. + bool ignoreInitRegModified = true; + genAllocLclFrame(compiler->compLclFrameSize, REG_SCRATCH, &ignoreInitRegModified, intRegState.rsCalleeRegArgMaskLiveIn); - genPushCalleeSavedRegisters(initReg, &initRegZeroed); + genPushCalleeSavedRegisters(initReg, &initRegModified); #else // !TARGET_ARM64 genPushCalleeSavedRegisters(); #endif // !TARGET_ARM64 @@ -7861,7 +7855,7 @@ void CodeGen::genFnProlog() if (maskStackAlloc == RBM_NONE) { - genAllocLclFrame(compiler->compLclFrameSize, initReg, &initRegZeroed, intRegState.rsCalleeRegArgMaskLiveIn); + genAllocLclFrame(compiler->compLclFrameSize, initReg, &initRegModified, intRegState.rsCalleeRegArgMaskLiveIn); } #endif // !TARGET_ARM64 @@ -7924,11 +7918,11 @@ void CodeGen::genFnProlog() // Zero out the frame as needed // - genZeroInitFrame(untrLclHi, untrLclLo, initReg, &initRegZeroed); + genZeroInitFrame(untrLclHi, untrLclLo, initReg, &initRegModified); #if defined(FEATURE_EH_FUNCLETS) - genSetPSPSym(initReg, &initRegZeroed); + genSetPSPSym(initReg, &initRegModified); #else // !FEATURE_EH_FUNCLETS @@ -7941,10 +7935,10 @@ void CodeGen::genFnProlog() // Zero out the slot for nesting level 0 unsigned firstSlotOffs = filterEndOffsetSlotOffs - TARGET_POINTER_SIZE; - if (!initRegZeroed) + if (initRegModified) { instGen_Set_Reg_To_Zero(EA_PTRSIZE, initReg); - initRegZeroed = true; + initRegModified = false; } GetEmitter()->emitIns_S_R(ins_Store(TYP_I_IMPL), EA_PTRSIZE, initReg, compiler->lvaShadowSPslotsVar, @@ -7953,7 +7947,7 @@ void CodeGen::genFnProlog() #endif // !FEATURE_EH_FUNCLETS - genReportGenericContextArg(initReg, &initRegZeroed); + genReportGenericContextArg(initReg, &initRegModified); #ifdef JIT32_GCENCODER // Initialize the LocalAllocSP slot if there is localloc in the function. @@ -7965,7 +7959,7 @@ void CodeGen::genFnProlog() // Set up the GS security cookie - genSetGSSecurityCookie(initReg, &initRegZeroed); + genSetGSSecurityCookie(initReg, &initRegModified); #ifdef PROFILING_SUPPORTED @@ -7973,7 +7967,7 @@ void CodeGen::genFnProlog() // OSR methods aren't called, so don't have enter hooks. if (!compiler->opts.IsOSR()) { - genProfilingEnterCallback(initReg, &initRegZeroed); + genProfilingEnterCallback(initReg, &initRegModified); } #endif // PROFILING_SUPPORTED @@ -8035,15 +8029,15 @@ void CodeGen::genFnProlog() } else { - xtraReg = REG_SCRATCH; - initRegZeroed = false; + xtraReg = REG_SCRATCH; + initRegModified = true; } genFnPrologCalleeRegArgs(xtraReg, &xtraRegClobbered, regState); if (xtraRegClobbered) { - initRegZeroed = false; + initRegModified = true; } } } @@ -8063,7 +8057,7 @@ void CodeGen::genFnProlog() if (regMask & initRegs) { // Check if we have already zeroed this register - if ((reg == initReg) && initRegZeroed) + if ((reg == initReg) && !initRegModified) { continue; } @@ -8072,7 +8066,7 @@ void CodeGen::genFnProlog() instGen_Set_Reg_To_Zero(EA_PTRSIZE, reg); if (reg == initReg) { - initRegZeroed = true; + initRegModified = false; } } } @@ -8084,17 +8078,17 @@ void CodeGen::genFnProlog() // If initReg is not in initRegs then we will use REG_SCRATCH if ((genRegMask(initReg) & initRegs) == 0) { - initReg = REG_SCRATCH; - initRegZeroed = false; + initReg = REG_SCRATCH; + initRegModified = true; } #ifdef TARGET_ARM // This is needed only for Arm since it can use a zero initialized int register // to initialize vfp registers. - if (!initRegZeroed) + if (initRegModified) { instGen_Set_Reg_To_Zero(EA_PTRSIZE, initReg); - initRegZeroed = true; + initRegModified = false; } #endif // TARGET_ARM @@ -9101,12 +9095,12 @@ void CodeGen::genFuncletProlog(BasicBlock* block) maskArgRegsLiveIn = RBM_R0; } - regNumber initReg = REG_R3; // R3 is never live on entry to a funclet, so it can be trashed - bool initRegZeroed = false; + regNumber initReg = REG_R3; // R3 is never live on entry to a funclet, so it can be trashed + bool initRegModified = true; if (maskStackAlloc == RBM_NONE) { - genAllocLclFrame(genFuncletInfo.fiSpDelta, initReg, &initRegZeroed, maskArgRegsLiveIn); + genAllocLclFrame(genFuncletInfo.fiSpDelta, initReg, &initRegModified, maskArgRegsLiveIn); } // This is the end of the OS-reported prolog for purposes of unwinding @@ -9403,10 +9397,10 @@ void CodeGen::genFuncletProlog(BasicBlock* block) maskArgRegsLiveIn = RBM_ARG_0 | RBM_ARG_2; } - regNumber initReg = REG_EBP; // We already saved EBP, so it can be trashed - bool initRegZeroed = false; + regNumber initReg = REG_EBP; // We already saved EBP, so it can be trashed + bool initRegModified = true; - genAllocLclFrame(genFuncletInfo.fiSpDelta, initReg, &initRegZeroed, maskArgRegsLiveIn); + genAllocLclFrame(genFuncletInfo.fiSpDelta, initReg, &initRegModified, maskArgRegsLiveIn); // Callee saved float registers are copied to stack in their assigned stack slots // after allocating space for them as part of funclet frame. @@ -9745,7 +9739,7 @@ void CodeGen::genCaptureFuncletPrologEpilogInfo() * correctly reported, the PSPSym could be omitted in some cases.) *********************************** */ -void CodeGen::genSetPSPSym(regNumber initReg, bool* pInitRegZeroed) +void CodeGen::genSetPSPSym(regNumber initReg, bool* pInitRegModified) { assert(compiler->compGeneratingProlog); @@ -9791,8 +9785,8 @@ void CodeGen::genSetPSPSym(regNumber initReg, bool* pInitRegZeroed) // We will just use the initReg since it is an available register // and we are probably done using it anyway... - regNumber regTmp = initReg; - *pInitRegZeroed = false; + regNumber regTmp = initReg; + *pInitRegModified = true; GetEmitter()->emitIns_R_R_I(INS_add, EA_PTRSIZE, regTmp, regBase, callerSPOffs); GetEmitter()->emitIns_S_R(INS_str, EA_PTRSIZE, regTmp, compiler->lvaPSPSym, 0); @@ -9803,8 +9797,8 @@ void CodeGen::genSetPSPSym(regNumber initReg, bool* pInitRegZeroed) // We will just use the initReg since it is an available register // and we are probably done using it anyway... - regNumber regTmp = initReg; - *pInitRegZeroed = false; + regNumber regTmp = initReg; + *pInitRegModified = true; GetEmitter()->emitIns_R_R_Imm(INS_add, EA_PTRSIZE, regTmp, REG_SPBASE, SPtoCallerSPdelta); GetEmitter()->emitIns_S_R(INS_str, EA_PTRSIZE, regTmp, compiler->lvaPSPSym, 0); @@ -11534,7 +11528,7 @@ void CodeGen::genReturn(GenTree* treeNode) { if (varTypeIsLong(compiler->info.compRetNativeType)) { - retTypeDesc.InitializeLongReturnType(compiler); + retTypeDesc.InitializeLongReturnType(); } else // we must have a struct return type { @@ -11607,6 +11601,284 @@ void CodeGen::genReturn(GenTree* treeNode) #endif // defined(DEBUG) && defined(TARGET_XARCH) } +//------------------------------------------------------------------------ +// isStructReturn: Returns whether the 'treeNode' is returning a struct. +// +// Arguments: +// treeNode - The tree node to evaluate whether is a struct return. +// +// Return Value: +// Returns true if the 'treeNode" is a GT_RETURN node of type struct. +// Otherwise returns false. +// +bool CodeGen::isStructReturn(GenTree* treeNode) +{ + // This method could be called for 'treeNode' of GT_RET_FILT or GT_RETURN. + // For the GT_RET_FILT, the return is always a bool or a void, for the end of a finally block. + noway_assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT); + if (treeNode->OperGet() != GT_RETURN) + { + return false; + } + +#if defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI) + assert(!varTypeIsStruct(treeNode)); + return false; +#elif defined(TARGET_ARM64) + return varTypeIsStruct(treeNode) && (compiler->info.compRetNativeType == TYP_STRUCT); +#else + return varTypeIsStruct(treeNode); +#endif +} + +//------------------------------------------------------------------------ +// genStructReturn: Generates code for returning a struct. +// +// Arguments: +// treeNode - The GT_RETURN tree node. +// +// Return Value: +// None +// +// Assumption: +// op1 of GT_RETURN node is either GT_LCL_VAR or multi-reg GT_CALL +// +void CodeGen::genStructReturn(GenTree* treeNode) +{ + assert(treeNode->OperGet() == GT_RETURN); + GenTree* op1 = treeNode->gtGetOp1(); + genConsumeRegs(op1); + GenTree* actualOp1 = op1; + if (op1->IsCopyOrReload()) + { + actualOp1 = op1->gtGetOp1(); + } + + ReturnTypeDesc retTypeDesc; + LclVarDsc* varDsc = nullptr; + if (actualOp1->OperIs(GT_LCL_VAR)) + { + varDsc = compiler->lvaGetDesc(actualOp1->AsLclVar()->GetLclNum()); + retTypeDesc.InitializeStructReturnType(compiler, varDsc->lvVerTypeInfo.GetClassHandle()); + } + else + { + assert(actualOp1->OperIs(GT_CALL)); + retTypeDesc = *(actualOp1->AsCall()->GetReturnTypeDesc()); + } + unsigned regCount = retTypeDesc.GetReturnRegCount(); + assert(regCount <= MAX_RET_REG_COUNT); + +#if FEATURE_MULTIREG_RET + if (actualOp1->OperIs(GT_LCL_VAR) && (varTypeIsEnregisterable(op1))) + { + // Right now the only enregisterable structs supported are SIMD vector types. + assert(varTypeIsSIMD(op1)); +#ifdef FEATURE_SIMD + genSIMDSplitReturn(op1, &retTypeDesc); +#endif // FEATURE_SIMD + } + else if (actualOp1->OperIs(GT_LCL_VAR)) + { + GenTreeLclVar* lclNode = actualOp1->AsLclVar(); + LclVarDsc* varDsc = compiler->lvaGetDesc(lclNode->GetLclNum()); + assert(varDsc->lvIsMultiRegRet); + int offset = 0; + for (unsigned i = 0; i < regCount; ++i) + { + var_types type = retTypeDesc.GetReturnRegType(i); + regNumber toReg = retTypeDesc.GetABIReturnReg(i); + GetEmitter()->emitIns_R_S(ins_Load(type), emitTypeSize(type), toReg, lclNode->GetLclNum(), offset); + offset += genTypeSize(type); + } + } + else + { + assert(actualOp1->IsMultiRegCall()); + for (unsigned i = 0; i < regCount; ++i) + { + var_types type = retTypeDesc.GetReturnRegType(i); + regNumber toReg = retTypeDesc.GetABIReturnReg(i); + regNumber fromReg = op1->GetRegByIndex(i); + if (fromReg == REG_NA) + { + assert(op1->IsCopyOrReload()); + fromReg = actualOp1->GetRegByIndex(i); + } + if (fromReg != toReg) + { + inst_RV_RV(ins_Copy(type), toReg, fromReg, type); + } + } + } +#else // !FEATURE_MULTIREG_RET + unreached(); +#endif +} + +//------------------------------------------------------------------------ +// genRegCopy: Produce code for a GT_COPY node. +// +// Arguments: +// tree - the GT_COPY node +// +// Notes: +// This will copy the register(s) produced by this nodes source, to +// the register(s) allocated to this GT_COPY node. +// It has some special handling for these casess: +// - when the source and target registers are in different register files +// (note that this is *not* a conversion). +// - when the source is a lclVar whose home location is being moved to a new +// register (rather than just being copied for temporary use). +// +void CodeGen::genRegCopy(GenTree* treeNode) +{ + assert(treeNode->OperGet() == GT_COPY); + GenTree* op1 = treeNode->AsOp()->gtOp1; + + if (op1->IsMultiRegNode()) + { + // Register allocation assumes that any reload and copy are done in operand order. + // That is, we can have: + // (reg0, reg1) = COPY(V0,V1) where V0 is in reg1 and V1 is in memory + // The register allocation model assumes: + // First, V0 is moved to reg0 (v1 can't be in reg0 because it is still live, which would be a conflict). + // Then, V1 is moved to reg1 + // However, if we call genConsumeRegs on op1, it will do the reload of V1 before we do the copy of V0. + // So we need to handle that case first. + // + // There should never be any circular dependencies, and we will check that here. + + GenTreeCopyOrReload* copyNode = treeNode->AsCopyOrReload(); + // GenTreeCopyOrReload only reports the highest index that has a valid register. + unsigned regCount = copyNode->GetRegCount(); + assert(regCount <= MAX_MULTIREG_COUNT); + + // First set the source registers as busy if they haven't been spilled. + // (Note that this is just for verification that we don't have circular dependencies.) + regMaskTP busyRegs = RBM_NONE; + for (unsigned i = 0; i < regCount; ++i) + { + if ((op1->GetRegSpillFlagByIdx(i) & GTF_SPILLED) == 0) + { + busyRegs |= genRegMask(op1->GetRegByIndex(i)); + } + } + // First do any copies - we'll do the reloads after all the copies are complete. + for (unsigned i = 0; i < regCount; ++i) + { + regNumber sourceReg = op1->GetRegByIndex(i); + regNumber targetReg = copyNode->GetRegNumByIdx(i); + // GenTreeCopyOrReload only reports the highest index that has a valid register. + // However there may be lower indices that have no valid register (i.e. the register + // on the source is still valid at the consumer). + if (targetReg != REG_NA) + { + // We shouldn't specify a no-op move. + regMaskTP targetRegMask = genRegMask(targetReg); + assert(sourceReg != targetReg); + assert((busyRegs & targetRegMask) == 0); + // Clear sourceReg from the busyRegs, and add targetReg. + busyRegs &= ~genRegMask(sourceReg); + busyRegs |= genRegMask(targetReg); + var_types type; + if (op1->IsMultiRegLclVar()) + { + type = op1->AsLclVar()->GetFieldTypeByIndex(compiler, i); + } + else + { + type = op1->GetRegTypeByIndex(i); + } + inst_RV_RV(ins_Copy(type), targetReg, sourceReg, type); + } + } + // Now we can consume op1, which will perform any necessary reloads. + genConsumeReg(op1); + } + else + { + var_types targetType = treeNode->TypeGet(); + regNumber targetReg = treeNode->GetRegNum(); + assert(targetReg != REG_NA); + assert(targetType != TYP_STRUCT); + + // Check whether this node and the node from which we're copying the value have + // different register types. This can happen if (currently iff) we have a SIMD + // vector type that fits in an integer register, in which case it is passed as + // an argument, or returned from a call, in an integer register and must be + // copied if it's in an xmm register. + + bool srcFltReg = (varTypeIsFloating(op1) || varTypeIsSIMD(op1)); + bool tgtFltReg = (varTypeIsFloating(treeNode) || varTypeIsSIMD(treeNode)); + if (srcFltReg != tgtFltReg) + { + instruction ins; + regNumber fpReg; + regNumber intReg; + if (tgtFltReg) + { + ins = ins_CopyIntToFloat(op1->TypeGet(), treeNode->TypeGet()); + fpReg = targetReg; + intReg = op1->GetRegNum(); + } + else + { + ins = ins_CopyFloatToInt(op1->TypeGet(), treeNode->TypeGet()); + intReg = targetReg; + fpReg = op1->GetRegNum(); + } + inst_RV_RV(ins, fpReg, intReg, targetType); + } + else + { + inst_RV_RV(ins_Copy(targetType), targetReg, genConsumeReg(op1), targetType); + } + + if (op1->IsLocal()) + { + // The lclVar will never be a def. + // If it is a last use, the lclVar will be killed by genConsumeReg(), as usual, and genProduceReg will + // appropriately set the gcInfo for the copied value. + // If not, there are two cases we need to handle: + // - If this is a TEMPORARY copy (indicated by the GTF_VAR_DEATH flag) the variable + // will remain live in its original register. + // genProduceReg() will appropriately set the gcInfo for the copied value, + // and genConsumeReg will reset it. + // - Otherwise, we need to update register info for the lclVar. + + GenTreeLclVarCommon* lcl = op1->AsLclVarCommon(); + assert((lcl->gtFlags & GTF_VAR_DEF) == 0); + + if ((lcl->gtFlags & GTF_VAR_DEATH) == 0 && (treeNode->gtFlags & GTF_VAR_DEATH) == 0) + { + LclVarDsc* varDsc = compiler->lvaGetDesc(lcl); + + // If we didn't just spill it (in genConsumeReg, above), then update the register info + if (varDsc->GetRegNum() != REG_STK) + { + // The old location is dying + genUpdateRegLife(varDsc, /*isBorn*/ false, /*isDying*/ true DEBUGARG(op1)); + + gcInfo.gcMarkRegSetNpt(genRegMask(op1->GetRegNum())); + + genUpdateVarReg(varDsc, treeNode); + +#ifdef USING_VARIABLE_LIVE_RANGE + // Report the home change for this variable + varLiveKeeper->siUpdateVariableLiveRange(varDsc, lcl->GetLclNum()); +#endif // USING_VARIABLE_LIVE_RANGE + + // The new location is going live + genUpdateRegLife(varDsc, /*isBorn*/ true, /*isDying*/ false DEBUGARG(treeNode)); + } + } + } + } + + genProduceReg(treeNode); +} + #if defined(DEBUG) && defined(TARGET_XARCH) //------------------------------------------------------------------------ diff --git a/src/coreclr/src/jit/codegenlinear.cpp b/src/coreclr/src/jit/codegenlinear.cpp index e3973ba565119c..b9ed297495f64a 100644 --- a/src/coreclr/src/jit/codegenlinear.cpp +++ b/src/coreclr/src/jit/codegenlinear.cpp @@ -938,6 +938,86 @@ GenTree* sameRegAsDst(GenTree* tree, GenTree*& other /*out*/) } } +//------------------------------------------------------------------------ +// genUnspillLocal: Reload a register candidate local into a register. +// +// Arguments: +// varNum - The variable number of the local to be reloaded (unspilled). +// It may be a local field. +// type - The type of the local. +// lclNode - The node being unspilled. Note that for a multi-reg local, +// the gtLclNum will be that of the parent struct. +// regNum - The register that 'varNum' should be loaded to. +// reSpill - True if it will be immediately spilled after use. +// isLastUse - True if this is a last use of 'varNum'. +// +// Notes: +// The caller must have determined that this local needs to be unspilled. +void CodeGen::genUnspillLocal( + unsigned varNum, var_types type, GenTreeLclVar* lclNode, regNumber regNum, bool reSpill, bool isLastUse) +{ + LclVarDsc* varDsc = compiler->lvaGetDesc(varNum); + inst_set_SV_var(lclNode); + instruction ins = ins_Load(type, compiler->isSIMDTypeLocalAligned(varNum)); + GetEmitter()->emitIns_R_S(ins, emitTypeSize(type), regNum, varNum, 0); + + // TODO-Review: We would like to call: + // genUpdateRegLife(varDsc, /*isBorn*/ true, /*isDying*/ false DEBUGARG(tree)); + // instead of the following code, but this ends up hitting this assert: + // assert((regSet.GetMaskVars() & regMask) == 0); + // due to issues with LSRA resolution moves. + // So, just force it for now. This probably indicates a condition that creates a GC hole! + // + // Extra note: I think we really want to call something like gcInfo.gcUpdateForRegVarMove, + // because the variable is not really going live or dead, but that method is somewhat poorly + // factored because it, in turn, updates rsMaskVars which is part of RegSet not GCInfo. + // TODO-Cleanup: This code exists in other CodeGen*.cpp files, and should be moved to CodeGenCommon.cpp. + + // Don't update the variable's location if we are just re-spilling it again. + + if (!reSpill) + { + varDsc->SetRegNum(regNum); + +#ifdef USING_VARIABLE_LIVE_RANGE + // We want "VariableLiveRange" inclusive on the beginning and exclusive on the ending. + // For that we shouldn't report an update of the variable location if is becoming dead + // on the same native offset. + if (!isLastUse) + { + // Report the home change for this variable + varLiveKeeper->siUpdateVariableLiveRange(varDsc, varNum); + } +#endif // USING_VARIABLE_LIVE_RANGE + + if (!varDsc->lvLiveInOutOfHndlr) + { +#ifdef DEBUG + if (VarSetOps::IsMember(compiler, gcInfo.gcVarPtrSetCur, varDsc->lvVarIndex)) + { + JITDUMP("\t\t\t\t\t\t\tRemoving V%02u from gcVarPtrSetCur\n", varNum); + } +#endif // DEBUG + VarSetOps::RemoveElemD(compiler, gcInfo.gcVarPtrSetCur, varDsc->lvVarIndex); + } + +#ifdef DEBUG + if (compiler->verbose) + { + printf("\t\t\t\t\t\t\tV%02u in reg ", varNum); + varDsc->PrintVarReg(); + printf(" is becoming live "); + compiler->printTreeID(lclNode); + printf("\n"); + } +#endif // DEBUG + + regSet.AddMaskVars(genGetRegMask(varDsc)); + } + + gcInfo.gcMarkRegPtrVal(regNum, type); +} + //------------------------------------------------------------------------ // genUnspillRegIfNeeded: Reload the value into a register, if needed // @@ -968,8 +1048,9 @@ void CodeGen::genUnspillRegIfNeeded(GenTree* tree) // Reset spilled flag, since we are going to load a local variable from its home location. unspillTree->gtFlags &= ~GTF_SPILLED; - GenTreeLclVarCommon* lcl = unspillTree->AsLclVarCommon(); - LclVarDsc* varDsc = &compiler->lvaTable[lcl->GetLclNum()]; + GenTreeLclVar* lcl = unspillTree->AsLclVar(); + LclVarDsc* varDsc = compiler->lvaGetDesc(lcl->GetLclNum()); + var_types spillType = unspillTree->TypeGet(); // TODO-Cleanup: The following code could probably be further merged and cleaned up. #ifdef TARGET_XARCH @@ -985,106 +1066,33 @@ void CodeGen::genUnspillRegIfNeeded(GenTree* tree) // In the normalizeOnLoad case ins_Load will return an appropriate sign- or zero- // extending load. - var_types treeType = unspillTree->TypeGet(); - if (treeType != genActualType(varDsc->lvType) && !varTypeIsGC(treeType) && !varDsc->lvNormalizeOnLoad()) + if (spillType != genActualType(varDsc->lvType) && !varTypeIsGC(spillType) && !varDsc->lvNormalizeOnLoad()) { assert(!varTypeIsGC(varDsc)); - var_types spillType = genActualType(varDsc->lvType); - unspillTree->gtType = spillType; - inst_RV_TT(ins_Load(spillType, compiler->isSIMDTypeLocalAligned(lcl->GetLclNum())), dstReg, - unspillTree); - unspillTree->gtType = treeType; - } - else - { - inst_RV_TT(ins_Load(treeType, compiler->isSIMDTypeLocalAligned(lcl->GetLclNum())), dstReg, unspillTree); + spillType = genActualType(varDsc->lvType); } #elif defined(TARGET_ARM64) var_types targetType = unspillTree->gtType; - if (targetType != genActualType(varDsc->lvType) && !varTypeIsGC(targetType) && !varDsc->lvNormalizeOnLoad()) + if (spillType != genActualType(varDsc->lvType) && !varTypeIsGC(spillType) && !varDsc->lvNormalizeOnLoad()) { assert(!varTypeIsGC(varDsc)); - targetType = genActualType(varDsc->lvType); + spillType = genActualType(varDsc->lvType); } - instruction ins = ins_Load(targetType, compiler->isSIMDTypeLocalAligned(lcl->GetLclNum())); - emitAttr attr = emitActualTypeSize(targetType); - emitter* emit = GetEmitter(); - - // Load local variable from its home location. - inst_RV_TT(ins, dstReg, unspillTree, 0, attr); #elif defined(TARGET_ARM) - var_types targetType = unspillTree->gtType; - instruction ins = ins_Load(targetType, compiler->isSIMDTypeLocalAligned(lcl->GetLclNum())); - emitAttr attr = emitTypeSize(targetType); - - // Load local variable from its home location. - inst_RV_TT(ins, dstReg, unspillTree, 0, attr); +// No normalizing for ARM #else NYI("Unspilling not implemented for this target architecture."); #endif - - // TODO-Review: We would like to call: - // genUpdateRegLife(varDsc, /*isBorn*/ true, /*isDying*/ false DEBUGARG(tree)); - // instead of the following code, but this ends up hitting this assert: - // assert((regSet.GetMaskVars() & regMask) == 0); - // due to issues with LSRA resolution moves. - // So, just force it for now. This probably indicates a condition that creates a GC hole! - // - // Extra note: I think we really want to call something like gcInfo.gcUpdateForRegVarMove, - // because the variable is not really going live or dead, but that method is somewhat poorly - // factored because it, in turn, updates rsMaskVars which is part of RegSet not GCInfo. - // TODO-Cleanup: This code exists in other CodeGen*.cpp files, and should be moved to CodeGenCommon.cpp. - - // Don't update the variable's location if we are just re-spilling it again. - - if ((unspillTree->gtFlags & GTF_SPILL) == 0) - { - genUpdateVarReg(varDsc, tree); - -#ifdef USING_VARIABLE_LIVE_RANGE - // We want "VariableLiveRange" inclusive on the beginbing and exclusive on the ending. - // For that we shouldn't report an update of the variable location if is becoming dead - // on the same native offset. - if ((unspillTree->gtFlags & GTF_VAR_DEATH) == 0) - { - // Report the home change for this variable - varLiveKeeper->siUpdateVariableLiveRange(varDsc, lcl->GetLclNum()); - } -#endif // USING_VARIABLE_LIVE_RANGE - - if (!varDsc->lvLiveInOutOfHndlr) - { -#ifdef DEBUG - if (VarSetOps::IsMember(compiler, gcInfo.gcVarPtrSetCur, varDsc->lvVarIndex)) - { - JITDUMP("\t\t\t\t\t\t\tRemoving V%02u from gcVarPtrSetCur\n", lcl->GetLclNum()); - } -#endif // DEBUG - VarSetOps::RemoveElemD(compiler, gcInfo.gcVarPtrSetCur, varDsc->lvVarIndex); - } - -#ifdef DEBUG - if (compiler->verbose) - { - printf("\t\t\t\t\t\t\tV%02u in reg ", lcl->GetLclNum()); - varDsc->PrintVarReg(); - printf(" is becoming live "); - compiler->printTreeID(unspillTree); - printf("\n"); - } -#endif // DEBUG - - regSet.AddMaskVars(genGetRegMask(varDsc)); - } - - gcInfo.gcMarkRegPtrVal(dstReg, unspillTree->TypeGet()); + bool reSpill = ((unspillTree->gtFlags & GTF_SPILL) != 0); + bool isLastUse = lcl->IsLastUse(0); + genUnspillLocal(lcl->GetLclNum(), spillType, lcl, dstReg, reSpill, isLastUse); } else if (unspillTree->IsMultiRegCall()) { - GenTreeCall* call = unspillTree->AsCall(); - ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); - unsigned regCount = retTypeDesc->GetReturnRegCount(); - GenTreeCopyOrReload* reloadTree = nullptr; + GenTreeCall* call = unspillTree->AsCall(); + const ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); + const unsigned regCount = retTypeDesc->GetReturnRegCount(); + GenTreeCopyOrReload* reloadTree = nullptr; if (tree->OperGet() == GT_RELOAD) { reloadTree = tree->AsCopyOrReload(); @@ -1447,7 +1455,7 @@ void CodeGen::genConsumeRegs(GenTree* tree) #ifdef FEATURE_SIMD // (In)Equality operation that produces bool result, when compared // against Vector zero, marks its Vector Zero operand as contained. - assert(tree->OperIsLeaf() || tree->IsIntegralConstVector(0)); + assert(tree->OperIsLeaf() || tree->IsSIMDZero()); #else assert(tree->OperIsLeaf()); #endif @@ -1849,6 +1857,41 @@ void CodeGen::genConsumeBlockOp(GenTreeBlk* blkNode, regNumber dstReg, regNumber genSetBlockSize(blkNode, sizeReg); } +//------------------------------------------------------------------------- +// genSpillLocal: Generate the actual spill of a local var. +// +// Arguments: +// varNum - The variable number of the local to be spilled. +// It may be a local field. +// type - The type of the local. +// lclNode - The node being spilled. Note that for a multi-reg local, +// the gtLclNum will be that of the parent struct. +// regNum - The register that 'varNum' is currently in. +// +// Return Value: +// None. +// +void CodeGen::genSpillLocal(unsigned varNum, var_types type, GenTreeLclVar* lclNode, regNumber regNum) +{ + LclVarDsc* varDsc = compiler->lvaGetDesc(varNum); + assert(!varDsc->lvNormalizeOnStore() || (type == genActualType(varDsc->TypeGet()))); + + // We have a register candidate local that is marked with GTF_SPILL. + // This flag generally means that we need to spill this local. + // The exception is the case of a use of an EH var use that is being "spilled" + // to the stack, indicated by GTF_SPILL (note that all EH lclVar defs are always + // spilled, i.e. write-thru). + // An EH var use is always valid on the stack (so we don't need to actually spill it), + // but the GTF_SPILL flag records the fact that the register value is going dead. + if (((lclNode->gtFlags & GTF_VAR_DEF) != 0) || !varDsc->lvLiveInOutOfHndlr) + { + // Store local variable to its home location. + // Ensure that lclVar stores are typed correctly. + GetEmitter()->emitIns_S_R(ins_Store(type, compiler->isSIMDTypeLocalAligned(varNum)), emitTypeSize(type), regNum, + varNum, 0); + } +} + //------------------------------------------------------------------------- // genProduceReg: do liveness update for register produced by the current // node in codegen after code has been emitted for it. @@ -1877,24 +1920,8 @@ void CodeGen::genProduceReg(GenTree* tree) if (genIsRegCandidateLocal(tree)) { - unsigned varNum = tree->AsLclVarCommon()->GetLclNum(); - LclVarDsc* varDsc = compiler->lvaGetDesc(varNum); - assert(!varDsc->lvNormalizeOnStore() || (tree->TypeGet() == genActualType(varDsc->TypeGet()))); - - // If we reach here, we have a register candidate local that is marked with GTF_SPILL. - // This flag generally means that we need to spill this local. - // The exception is the case of a use of an EH var use that is being "spilled" - // to the stack, indicated by GTF_SPILL (note that all EH lclVar defs are always - // spilled, i.e. write-thru). - // An EH var use is always valid on the stack (so we don't need to actually spill it), - // but the GTF_SPILL flag records the fact that the register value is going dead. - if (((tree->gtFlags & GTF_VAR_DEF) != 0) || !varDsc->lvLiveInOutOfHndlr) - { - // Store local variable to its home location. - // Ensure that lclVar stores are typed correctly. - inst_TT_RV(ins_Store(tree->gtType, compiler->isSIMDTypeLocalAligned(varNum)), - emitTypeSize(tree->TypeGet()), tree, tree->GetRegNum()); - } + unsigned varNum = tree->AsLclVarCommon()->GetLclNum(); + genSpillLocal(varNum, tree->TypeGet(), tree->AsLclVar(), tree->GetRegNum()); } else { @@ -1904,9 +1931,9 @@ void CodeGen::genProduceReg(GenTree* tree) // know which of its result regs needs to be spilled. if (tree->IsMultiRegCall()) { - GenTreeCall* call = tree->AsCall(); - ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); - unsigned regCount = retTypeDesc->GetReturnRegCount(); + GenTreeCall* call = tree->AsCall(); + const ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); + const unsigned regCount = retTypeDesc->GetReturnRegCount(); for (unsigned i = 0; i < regCount; ++i) { @@ -1983,13 +2010,13 @@ void CodeGen::genProduceReg(GenTree* tree) // the register as live, with a GC pointer, if the variable is dead. if (!genIsRegCandidateLocal(tree) || ((tree->gtFlags & GTF_VAR_DEATH) == 0)) { - // Multi-reg call node will produce more than one register result. - // Mark all the regs produced by call node. + // Multi-reg nodes will produce more than one register result. + // Mark all the regs produced by the node. if (tree->IsMultiRegCall()) { - GenTreeCall* call = tree->AsCall(); - ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); - unsigned regCount = retTypeDesc->GetReturnRegCount(); + const GenTreeCall* call = tree->AsCall(); + const ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); + const unsigned regCount = retTypeDesc->GetReturnRegCount(); for (unsigned i = 0; i < regCount; ++i) { @@ -2006,10 +2033,10 @@ void CodeGen::genProduceReg(GenTree* tree) // A multi-reg GT_COPY node produces those regs to which // copy has taken place. - GenTreeCopyOrReload* copy = tree->AsCopyOrReload(); - GenTreeCall* call = copy->gtGetOp1()->AsCall(); - ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); - unsigned regCount = retTypeDesc->GetReturnRegCount(); + const GenTreeCopyOrReload* copy = tree->AsCopyOrReload(); + const GenTreeCall* call = copy->gtGetOp1()->AsCall(); + const ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); + const unsigned regCount = retTypeDesc->GetReturnRegCount(); for (unsigned i = 0; i < regCount; ++i) { diff --git a/src/coreclr/src/jit/codegenxarch.cpp b/src/coreclr/src/jit/codegenxarch.cpp index 0e041c3061d439..4d8d2fbf9e2172 100644 --- a/src/coreclr/src/jit/codegenxarch.cpp +++ b/src/coreclr/src/jit/codegenxarch.cpp @@ -54,14 +54,14 @@ void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFla // genSetGSSecurityCookie: Set the "GS" security cookie in the prolog. // // Arguments: -// initReg - register to use as a scratch register -// pInitRegZeroed - OUT parameter. *pInitRegZeroed is set to 'false' if and only if -// this call sets 'initReg' to a non-zero value. +// initReg - register to use as a scratch register +// pInitRegModified - OUT parameter. *pInitRegModified is set to 'true' if and only if +// this call sets 'initReg' to a non-zero value. // // Return Value: // None // -void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed) +void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegModified) { assert(compiler->compGeneratingProlog); @@ -85,7 +85,7 @@ void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed) // initReg = #GlobalSecurityCookieVal64; [frame.GSSecurityCookie] = initReg genSetRegToIcon(initReg, compiler->gsGlobalSecurityCookieVal, TYP_I_IMPL); GetEmitter()->emitIns_S_R(INS_mov, EA_PTRSIZE, initReg, compiler->lvaGSSecurityCookie, 0); - *pInitRegZeroed = false; + *pInitRegModified = true; } else #endif @@ -106,7 +106,7 @@ void CodeGen::genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed) GetEmitter()->emitIns_S_R(INS_mov, EA_PTRSIZE, REG_EAX, compiler->lvaGSSecurityCookie, 0); if (initReg == REG_EAX) { - *pInitRegZeroed = false; + *pInitRegModified = true; } } } @@ -137,14 +137,14 @@ void CodeGen::genEmitGSCookieCheck(bool pushReg) ReturnTypeDesc retTypeDesc; if (varTypeIsLong(compiler->info.compRetNativeType)) { - retTypeDesc.InitializeLongReturnType(compiler); + retTypeDesc.InitializeLongReturnType(); } else // we must have a struct return type { retTypeDesc.InitializeStructReturnType(compiler, compiler->info.compMethodInfo->args.retTypeClass); } - unsigned regCount = retTypeDesc.GetReturnRegCount(); + const unsigned regCount = retTypeDesc.GetReturnRegCount(); // Only x86 and x64 Unix ABI allows multi-reg return and // number of result regs should be equal to MAX_RET_REG_COUNT. @@ -212,32 +212,6 @@ void CodeGen::genEmitGSCookieCheck(bool pushReg) regGSCheck = REG_EAX; regMaskGSCheck = RBM_EAX; #else // !TARGET_X86 - // Tail calls from methods that need GS check: We need to preserve registers while - // emitting GS cookie check for a tail prefixed call or a jmp. To emit GS cookie - // check, we might need a register. This won't be an issue for jmp calls for the - // reason mentioned below (see comment starting with "Jmp Calls:"). - // - // The following are the possible solutions in case of tail prefixed calls: - // 1) Use R11 - ignore tail prefix on calls that need to pass a param in R11 when - // present in methods that require GS cookie check. Rest of the tail calls that - // do not require R11 will be honored. - // 2) Internal register - GT_CALL node reserves an internal register and emits GS - // cookie check as part of tail call codegen. GenExitCode() needs to special case - // fast tail calls implemented as epilog+jmp or such tail calls should always get - // dispatched via helper. - // 3) Materialize GS cookie check as a separate node hanging off GT_CALL node in - // right execution order during rationalization. - // - // There are two calls that use R11: VSD and calli pinvokes with cookie param. Tail - // prefix on pinvokes is ignored. That is, options 2 and 3 will allow tail prefixed - // VSD calls from methods that need GS check. - // - // Tail prefixed calls: Right now for Jit64 compat, method requiring GS cookie check - // ignores tail prefix. In future, if we intend to support tail calls from such a method, - // consider one of the options mentioned above. For now adding an assert that we don't - // expect to see a tail call in a method that requires GS check. - noway_assert(!compiler->compTailCallUsed); - // Jmp calls: specify method handle using which JIT queries VM for its entry point // address and hence it can neither be a VSD call nor PInvoke calli with cookie // parameter. Therefore, in case of jmp calls it is safe to use R11. @@ -1150,214 +1124,55 @@ void CodeGen::genCodeForMul(GenTreeOp* treeNode) genProduceReg(treeNode); } +#ifdef FEATURE_SIMD //------------------------------------------------------------------------ -// isStructReturn: Returns whether the 'treeNode' is returning a struct. +// genSIMDSplitReturn: Generates code for returning a fixed-size SIMD type that lives +// in a single register, but is returned in multiple registers. // // Arguments: -// treeNode - The tree node to evaluate whether is a struct return. -// -// Return Value: -// For AMD64 *nix: returns true if the 'treeNode" is a GT_RETURN node, of type struct. -// Otherwise returns false. -// For other platforms always returns false. +// src - The source of the return +// retTypeDesc - The return type descriptor. // -bool CodeGen::isStructReturn(GenTree* treeNode) +void CodeGen::genSIMDSplitReturn(GenTree* src, ReturnTypeDesc* retTypeDesc) { - // This method could be called for 'treeNode' of GT_RET_FILT or GT_RETURN. - // For the GT_RET_FILT, the return is always - // a bool or a void, for the end of a finally block. - noway_assert(treeNode->OperGet() == GT_RETURN || treeNode->OperGet() == GT_RETFILT); - if (treeNode->OperGet() != GT_RETURN) - { - return false; - } + assert(varTypeIsSIMD(src)); + assert(src->isUsedFromReg()); -#ifdef UNIX_AMD64_ABI - return varTypeIsStruct(treeNode); -#else // !UNIX_AMD64_ABI - assert(!varTypeIsStruct(treeNode)); - return false; -#endif // UNIX_AMD64_ABI -} + // This is a case of operand is in a single reg and needs to be + // returned in multiple ABI return registers. + regNumber opReg = src->GetRegNum(); + regNumber reg0 = retTypeDesc->GetABIReturnReg(0); + regNumber reg1 = retTypeDesc->GetABIReturnReg(1); -//------------------------------------------------------------------------ -// genStructReturn: Generates code for returning a struct. -// -// Arguments: -// treeNode - The GT_RETURN tree node. -// -// Return Value: -// None -// -// Assumption: -// op1 of GT_RETURN node is either GT_LCL_VAR or multi-reg GT_CALL -void CodeGen::genStructReturn(GenTree* treeNode) -{ - assert(treeNode->OperGet() == GT_RETURN); - GenTree* op1 = treeNode->gtGetOp1(); - -#ifdef UNIX_AMD64_ABI - if (op1->OperGet() == GT_LCL_VAR) + if (opReg != reg0 && opReg != reg1) { - GenTreeLclVarCommon* lclVar = op1->AsLclVarCommon(); - LclVarDsc* varDsc = &(compiler->lvaTable[lclVar->GetLclNum()]); - assert(varDsc->lvIsMultiRegRet); - - ReturnTypeDesc retTypeDesc; - retTypeDesc.InitializeStructReturnType(compiler, varDsc->lvVerTypeInfo.GetClassHandle()); - unsigned regCount = retTypeDesc.GetReturnRegCount(); - assert(regCount == MAX_RET_REG_COUNT); - - if (varTypeIsEnregisterable(op1)) - { - // Right now the only enregisterable structs supported are SIMD vector types. - assert(varTypeIsSIMD(op1)); - assert(op1->isUsedFromReg()); - - // This is a case of operand is in a single reg and needs to be - // returned in multiple ABI return registers. - regNumber opReg = genConsumeReg(op1); - regNumber reg0 = retTypeDesc.GetABIReturnReg(0); - regNumber reg1 = retTypeDesc.GetABIReturnReg(1); - - if (opReg != reg0 && opReg != reg1) - { - // Operand reg is different from return regs. - // Copy opReg to reg0 and let it to be handled by one of the - // two cases below. - inst_RV_RV(ins_Copy(TYP_DOUBLE), reg0, opReg, TYP_DOUBLE); - opReg = reg0; - } - - if (opReg == reg0) - { - assert(opReg != reg1); - - // reg0 - already has required 8-byte in bit position [63:0]. - // reg1 = opReg. - // swap upper and lower 8-bytes of reg1 so that desired 8-byte is in bit position [63:0]. - inst_RV_RV(ins_Copy(TYP_DOUBLE), reg1, opReg, TYP_DOUBLE); - } - else - { - assert(opReg == reg1); + // Operand reg is different from return regs. + // Copy opReg to reg0 and let it to be handled by one of the + // two cases below. + inst_RV_RV(ins_Copy(TYP_DOUBLE), reg0, opReg, TYP_DOUBLE); + opReg = reg0; + } - // reg0 = opReg. - // swap upper and lower 8-bytes of reg1 so that desired 8-byte is in bit position [63:0]. - inst_RV_RV(ins_Copy(TYP_DOUBLE), reg0, opReg, TYP_DOUBLE); - } - inst_RV_RV_IV(INS_shufpd, EA_16BYTE, reg1, reg1, 0x01); - } - else - { - assert(op1->isUsedFromMemory()); + if (opReg == reg0) + { + assert(opReg != reg1); - // Copy var on stack into ABI return registers - int offset = 0; - for (unsigned i = 0; i < regCount; ++i) - { - var_types type = retTypeDesc.GetReturnRegType(i); - regNumber reg = retTypeDesc.GetABIReturnReg(i); - GetEmitter()->emitIns_R_S(ins_Load(type), emitTypeSize(type), reg, lclVar->GetLclNum(), offset); - offset += genTypeSize(type); - } - } + // reg0 - already has required 8-byte in bit position [63:0]. + // reg1 = opReg. + // swap upper and lower 8-bytes of reg1 so that desired 8-byte is in bit position [63:0]. + inst_RV_RV(ins_Copy(TYP_DOUBLE), reg1, opReg, TYP_DOUBLE); } else { - assert(op1->IsMultiRegCall() || op1->IsCopyOrReloadOfMultiRegCall()); - - genConsumeRegs(op1); - - GenTree* actualOp1 = op1->gtSkipReloadOrCopy(); - GenTreeCall* call = actualOp1->AsCall(); - ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); - unsigned regCount = retTypeDesc->GetReturnRegCount(); - assert(regCount == MAX_RET_REG_COUNT); + assert(opReg == reg1); - // Handle circular dependency between call allocated regs and ABI return regs. - // - // It is possible under LSRA stress that originally allocated regs of call node, - // say rax and rdx, are spilled and reloaded to rdx and rax respectively. But - // GT_RETURN needs to move values as follows: rdx->rax, rax->rdx. Similar kind - // kind of circular dependency could arise between xmm0 and xmm1 return regs. - // Codegen is expected to handle such circular dependency. - // - var_types regType0 = retTypeDesc->GetReturnRegType(0); - regNumber returnReg0 = retTypeDesc->GetABIReturnReg(0); - regNumber allocatedReg0 = call->GetRegNumByIdx(0); - - var_types regType1 = retTypeDesc->GetReturnRegType(1); - regNumber returnReg1 = retTypeDesc->GetABIReturnReg(1); - regNumber allocatedReg1 = call->GetRegNumByIdx(1); - - if (op1->IsCopyOrReload()) - { - // GT_COPY/GT_RELOAD will have valid reg for those positions - // that need to be copied or reloaded. - regNumber reloadReg = op1->AsCopyOrReload()->GetRegNumByIdx(0); - if (reloadReg != REG_NA) - { - allocatedReg0 = reloadReg; - } - - reloadReg = op1->AsCopyOrReload()->GetRegNumByIdx(1); - if (reloadReg != REG_NA) - { - allocatedReg1 = reloadReg; - } - } - - if (allocatedReg0 == returnReg1 && allocatedReg1 == returnReg0) - { - // Circular dependency - swap allocatedReg0 and allocatedReg1 - if (varTypeIsFloating(regType0)) - { - assert(varTypeIsFloating(regType1)); - - // The fastest way to swap two XMM regs is using PXOR - inst_RV_RV(INS_pxor, allocatedReg0, allocatedReg1, TYP_DOUBLE); - inst_RV_RV(INS_pxor, allocatedReg1, allocatedReg0, TYP_DOUBLE); - inst_RV_RV(INS_pxor, allocatedReg0, allocatedReg1, TYP_DOUBLE); - } - else - { - assert(varTypeIsIntegral(regType0)); - assert(varTypeIsIntegral(regType1)); - inst_RV_RV(INS_xchg, allocatedReg1, allocatedReg0, TYP_I_IMPL); - } - } - else if (allocatedReg1 == returnReg0) - { - // Change the order of moves to correctly handle dependency. - if (allocatedReg1 != returnReg1) - { - inst_RV_RV(ins_Copy(regType1), returnReg1, allocatedReg1, regType1); - } - - if (allocatedReg0 != returnReg0) - { - inst_RV_RV(ins_Copy(regType0), returnReg0, allocatedReg0, regType0); - } - } - else - { - // No circular dependency case. - if (allocatedReg0 != returnReg0) - { - inst_RV_RV(ins_Copy(regType0), returnReg0, allocatedReg0, regType0); - } - - if (allocatedReg1 != returnReg1) - { - inst_RV_RV(ins_Copy(regType1), returnReg1, allocatedReg1, regType1); - } - } + // reg0 = opReg. + // swap upper and lower 8-bytes of reg1 so that desired 8-byte is in bit position [63:0]. + inst_RV_RV(ins_Copy(TYP_DOUBLE), reg0, opReg, TYP_DOUBLE); } -#else - unreached(); -#endif + inst_RV_RV_IV(INS_shufpd, EA_16BYTE, reg1, reg1, 0x01); } +#endif // FEATURE_SIMD #if defined(TARGET_X86) @@ -1888,8 +1703,13 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) break; case GT_MEMORYBARRIER: - instGen_MemoryBarrier(); + { + CodeGen::BarrierKind barrierKind = + treeNode->gtFlags & GTF_MEMORYBARRIER_LOAD ? BARRIER_LOAD_ONLY : BARRIER_FULL; + + instGen_MemoryBarrier(barrierKind); break; + } case GT_CMPXCHG: genCodeForCmpXchg(treeNode->AsCmpXchg()); @@ -2030,7 +1850,7 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) } //---------------------------------------------------------------------------------- -// genMultiRegCallStoreToLocal: store multi-reg return value of a call node to a local +// genMultiRegStoreToLocal: store multi-reg return value of a call node to a local // // Arguments: // treeNode - Gentree of GT_STORE_LCL_VAR @@ -2038,45 +1858,52 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) // Return Value: // None // -// Assumption: -// The child of store is a multi-reg call node. -// genProduceReg() on treeNode is made by caller of this routine. +// Assumptions: +// The child of store is a multi-reg node. // -void CodeGen::genMultiRegCallStoreToLocal(GenTree* treeNode) +void CodeGen::genMultiRegStoreToLocal(GenTree* treeNode) { assert(treeNode->OperGet() == GT_STORE_LCL_VAR); + assert(varTypeIsStruct(treeNode) || varTypeIsMultiReg(treeNode)); + GenTree* op1 = treeNode->gtGetOp1(); + GenTree* actualOp1 = op1->gtSkipReloadOrCopy(); + assert(op1->IsMultiRegNode()); + unsigned regCount = actualOp1->GetMultiRegCount(); -#ifdef UNIX_AMD64_ABI - // Structs of size >=9 and <=16 are returned in two return registers on x64 Unix. - assert(varTypeIsStruct(treeNode)); - - // Assumption: current x64 Unix implementation requires that a multi-reg struct + // Assumption: The current implementation requires that a multi-reg // var in 'var = call' is flagged as lvIsMultiRegRet to prevent it from // being struct promoted. - unsigned lclNum = treeNode->AsLclVarCommon()->GetLclNum(); - LclVarDsc* varDsc = &(compiler->lvaTable[lclNum]); - noway_assert(varDsc->lvIsMultiRegRet); - GenTree* op1 = treeNode->gtGetOp1(); - GenTree* actualOp1 = op1->gtSkipReloadOrCopy(); - GenTreeCall* call = actualOp1->AsCall(); - assert(call->HasMultiRegRetVal()); + unsigned lclNum = treeNode->AsLclVarCommon()->GetLclNum(); + LclVarDsc* varDsc = compiler->lvaGetDesc(lclNum); + if (op1->OperIs(GT_CALL)) + { + assert(regCount == MAX_RET_REG_COUNT); + noway_assert(varDsc->lvIsMultiRegRet); + } genConsumeRegs(op1); - ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); - assert(retTypeDesc->GetReturnRegCount() == MAX_RET_REG_COUNT); - unsigned regCount = retTypeDesc->GetReturnRegCount(); +#ifdef UNIX_AMD64_ABI + // Structs of size >=9 and <=16 are returned in two return registers on x64 Unix. - if (treeNode->GetRegNum() != REG_NA) + // Handle the case of a SIMD type returned in 2 registers. + if (varTypeIsSIMD(treeNode) && (treeNode->GetRegNum() != REG_NA)) { // Right now the only enregistrable structs supported are SIMD types. - assert(varTypeIsSIMD(treeNode)); + // They are only returned in 1 or 2 registers - the 1 register case is + // handled as a regular STORE_LCL_VAR. + // This case is always a call (AsCall() will assert if it is not). + GenTreeCall* call = actualOp1->AsCall(); + const ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); + assert(retTypeDesc->GetReturnRegCount() == MAX_RET_REG_COUNT); + + assert(regCount == 2); assert(varTypeIsFloating(retTypeDesc->GetReturnRegType(0))); assert(varTypeIsFloating(retTypeDesc->GetReturnRegType(1))); - // This is a case of two 8-bytes that comprise the operand is in - // two different xmm registers and needs to assembled into a single + // This is a case where the two 8-bytes that comprise the operand are in + // two different xmm registers and need to be assembled into a single // xmm register. regNumber targetReg = treeNode->GetRegNum(); regNumber reg0 = call->GetRegNumByIdx(0); @@ -2132,95 +1959,52 @@ void CodeGen::genMultiRegCallStoreToLocal(GenTree* treeNode) } } else +#endif // UNIX_AMD64_ABI { - // Stack store + // This may be: + // - a call returning multiple registers + // - a HW intrinsic producing two registers to be stored into a TYP_STRUCT + // int offset = 0; for (unsigned i = 0; i < regCount; ++i) { - var_types type = retTypeDesc->GetReturnRegType(i); - regNumber reg = call->GetRegNumByIdx(i); - if (op1->IsCopyOrReload()) + var_types type = actualOp1->GetRegTypeByIndex(i); + regNumber reg = op1->GetRegByIndex(i); + if (reg == REG_NA) { - // GT_COPY/GT_RELOAD will have valid reg for those positions + // GT_COPY/GT_RELOAD will have valid reg only for those positions // that need to be copied or reloaded. - regNumber reloadReg = op1->AsCopyOrReload()->GetRegNumByIdx(i); - if (reloadReg != REG_NA) - { - reg = reloadReg; - } + assert(op1->IsCopyOrReload()); + reg = actualOp1->GetRegByIndex(i); } assert(reg != REG_NA); GetEmitter()->emitIns_S_R(ins_Store(type), emitTypeSize(type), reg, lclNum, offset); offset += genTypeSize(type); } - + // Update variable liveness. + genUpdateLife(treeNode); varDsc->SetRegNum(REG_STK); } -#elif defined(TARGET_X86) - // Longs are returned in two return registers on x86. - assert(varTypeIsLong(treeNode)); - - // Assumption: current x86 implementation requires that a multi-reg long - // var in 'var = call' is flagged as lvIsMultiRegRet to prevent it from - // being promoted. - unsigned lclNum = treeNode->AsLclVarCommon()->GetLclNum(); - LclVarDsc* varDsc = &(compiler->lvaTable[lclNum]); - noway_assert(varDsc->lvIsMultiRegRet); - - GenTree* op1 = treeNode->gtGetOp1(); - GenTree* actualOp1 = op1->gtSkipReloadOrCopy(); - GenTreeCall* call = actualOp1->AsCall(); - assert(call->HasMultiRegRetVal()); - - genConsumeRegs(op1); - - ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); - unsigned regCount = retTypeDesc->GetReturnRegCount(); - assert(regCount == MAX_RET_REG_COUNT); - - // Stack store - int offset = 0; - for (unsigned i = 0; i < regCount; ++i) - { - var_types type = retTypeDesc->GetReturnRegType(i); - regNumber reg = call->GetRegNumByIdx(i); - if (op1->IsCopyOrReload()) - { - // GT_COPY/GT_RELOAD will have valid reg for those positions - // that need to be copied or reloaded. - regNumber reloadReg = op1->AsCopyOrReload()->GetRegNumByIdx(i); - if (reloadReg != REG_NA) - { - reg = reloadReg; - } - } - - assert(reg != REG_NA); - GetEmitter()->emitIns_S_R(ins_Store(type), emitTypeSize(type), reg, lclNum, offset); - offset += genTypeSize(type); - } - - varDsc->SetRegNum(REG_STK); -#else // !UNIX_AMD64_ABI && !TARGET_X86 - assert(!"Unreached"); -#endif // !UNIX_AMD64_ABI && !TARGET_X86 } //------------------------------------------------------------------------ // genAllocLclFrame: Probe the stack and allocate the local stack frame - subtract from SP. // // Arguments: -// frameSize - the size of the stack frame being allocated. -// initReg - register to use as a scratch register. -// pInitRegZeroed - OUT parameter. *pInitRegZeroed is set to 'false' if and only if -// this call sets 'initReg' to a non-zero value. -// maskArgRegsLiveIn - incoming argument registers that are currently live. +// frameSize - the size of the stack frame being allocated. +// initReg - register to use as a scratch register. +// pInitRegModified - OUT parameter. *pInitRegModified is set to 'true' if and only if +// this call sets 'initReg' to a non-zero value. +// maskArgRegsLiveIn - incoming argument registers that are currently live. // // Return value: // None // -void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn) +void CodeGen::genAllocLclFrame(unsigned frameSize, + regNumber initReg, + bool* pInitRegModified, + regMaskTP maskArgRegsLiveIn) { assert(compiler->compGeneratingProlog); @@ -2304,7 +2088,7 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni if (initReg == REG_DEFAULT_HELPER_CALL_TARGET) { - *pInitRegZeroed = false; + *pInitRegModified = true; } static_assert_no_msg((RBM_STACK_PROBE_HELPER_TRASH & RBM_STACK_PROBE_HELPER_ARG) == RBM_NONE); @@ -2314,7 +2098,7 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni if (initReg == REG_STACK_PROBE_HELPER_ARG) { - *pInitRegZeroed = false; + *pInitRegModified = true; } } @@ -4344,16 +4128,32 @@ void CodeGen::genCodeForShift(GenTree* tree) if (shiftBy->isContainedIntOrIImmed()) { - // First, move the operand to the destination register and - // later on perform the shift in-place. - // (LSRA will try to avoid this situation through preferencing.) - if (tree->GetRegNum() != operandReg) + // Optimize "X<<1" to "lea [reg+reg]" or "add reg, reg" + if (tree->OperIs(GT_LSH) && !tree->gtOverflowEx() && !tree->gtSetFlags() && shiftBy->IsIntegralConst(1)) { - inst_RV_RV(INS_mov, tree->GetRegNum(), operandReg, targetType); + emitAttr size = emitTypeSize(tree); + if (tree->GetRegNum() == operandReg) + { + GetEmitter()->emitIns_R_R(INS_add, size, tree->GetRegNum(), operandReg); + } + else + { + GetEmitter()->emitIns_R_ARX(INS_lea, size, tree->GetRegNum(), operandReg, operandReg, 1, 0); + } } + else + { + // First, move the operand to the destination register and + // later on perform the shift in-place. + // (LSRA will try to avoid this situation through preferencing.) + if (tree->GetRegNum() != operandReg) + { + inst_RV_RV(INS_mov, tree->GetRegNum(), operandReg, targetType); + } - int shiftByValue = (int)shiftBy->AsIntConCommon()->IconValue(); - inst_RV_SH(ins, emitTypeSize(tree), tree->GetRegNum(), shiftByValue); + int shiftByValue = (int)shiftBy->AsIntConCommon()->IconValue(); + inst_RV_SH(ins, emitTypeSize(tree), tree->GetRegNum(), shiftByValue); + } } else { @@ -4641,9 +4441,9 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree) // var = call, where call returns a multi-reg return value // case is handled separately. - if (op1->gtSkipReloadOrCopy()->IsMultiRegCall()) + if (op1->gtSkipReloadOrCopy()->IsMultiRegNode()) { - genMultiRegCallStoreToLocal(tree); + genMultiRegStoreToLocal(tree); } else { @@ -4681,17 +4481,6 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree) genStoreLclTypeSIMD12(tree); return; } - - // TODO-CQ: It would be better to simply contain the zero, rather than - // generating zero into a register. - if (varTypeIsSIMD(targetType) && (targetReg != REG_NA) && op1->IsCnsIntOrI()) - { - // This is only possible for a zero-init. - noway_assert(op1->IsIntegralConst(0)); - genSIMDZero(targetType, varDsc->lvBaseType, targetReg); - genProduceReg(tree); - return; - } #endif // FEATURE_SIMD genConsumeRegs(op1); @@ -4890,130 +4679,6 @@ void CodeGen::genCodeForIndir(GenTreeIndir* tree) genProduceReg(tree); } -//------------------------------------------------------------------------ -// genRegCopy: Produce code for a GT_COPY node. -// -// Arguments: -// tree - the GT_COPY node -// -// Notes: -// This will copy the register(s) produced by this nodes source, to -// the register(s) allocated to this GT_COPY node. -// It has some special handling for these casess: -// - when the source and target registers are in different register files -// (note that this is *not* a conversion). -// - when the source is a lclVar whose home location is being moved to a new -// register (rather than just being copied for temporary use). -// -void CodeGen::genRegCopy(GenTree* treeNode) -{ - assert(treeNode->OperGet() == GT_COPY); - GenTree* op1 = treeNode->AsOp()->gtOp1; - - if (op1->IsMultiRegNode()) - { - genConsumeReg(op1); - - GenTreeCopyOrReload* copyTree = treeNode->AsCopyOrReload(); - unsigned regCount = treeNode->GetMultiRegCount(); - - for (unsigned i = 0; i < regCount; ++i) - { - var_types type = op1->GetRegTypeByIndex(i); - regNumber fromReg = op1->GetRegByIndex(i); - regNumber toReg = copyTree->GetRegNumByIdx(i); - - // A Multi-reg GT_COPY node will have a valid reg only for those positions for which a corresponding - // result reg of the multi-reg node needs to be copied. - if (toReg != REG_NA) - { - assert(toReg != fromReg); - inst_RV_RV(ins_Copy(type), toReg, fromReg, type); - } - } - } - else - { - var_types targetType = treeNode->TypeGet(); - regNumber targetReg = treeNode->GetRegNum(); - assert(targetReg != REG_NA); - - // Check whether this node and the node from which we're copying the value have - // different register types. This can happen if (currently iff) we have a SIMD - // vector type that fits in an integer register, in which case it is passed as - // an argument, or returned from a call, in an integer register and must be - // copied if it's in an xmm register. - - bool srcFltReg = (varTypeIsFloating(op1) || varTypeIsSIMD(op1)); - bool tgtFltReg = (varTypeIsFloating(treeNode) || varTypeIsSIMD(treeNode)); - if (srcFltReg != tgtFltReg) - { - instruction ins; - regNumber fpReg; - regNumber intReg; - if (tgtFltReg) - { - ins = ins_CopyIntToFloat(op1->TypeGet(), treeNode->TypeGet()); - fpReg = targetReg; - intReg = op1->GetRegNum(); - } - else - { - ins = ins_CopyFloatToInt(op1->TypeGet(), treeNode->TypeGet()); - intReg = targetReg; - fpReg = op1->GetRegNum(); - } - inst_RV_RV(ins, fpReg, intReg, targetType); - } - else - { - inst_RV_RV(ins_Copy(targetType), targetReg, genConsumeReg(op1), targetType); - } - - if (op1->IsLocal()) - { - // The lclVar will never be a def. - // If it is a last use, the lclVar will be killed by genConsumeReg(), as usual, and genProduceReg will - // appropriately set the gcInfo for the copied value. - // If not, there are two cases we need to handle: - // - If this is a TEMPORARY copy (indicated by the GTF_VAR_DEATH flag) the variable - // will remain live in its original register. - // genProduceReg() will appropriately set the gcInfo for the copied value, - // and genConsumeReg will reset it. - // - Otherwise, we need to update register info for the lclVar. - - GenTreeLclVarCommon* lcl = op1->AsLclVarCommon(); - assert((lcl->gtFlags & GTF_VAR_DEF) == 0); - - if ((lcl->gtFlags & GTF_VAR_DEATH) == 0 && (treeNode->gtFlags & GTF_VAR_DEATH) == 0) - { - LclVarDsc* varDsc = &compiler->lvaTable[lcl->GetLclNum()]; - - // If we didn't just spill it (in genConsumeReg, above), then update the register info - if (varDsc->GetRegNum() != REG_STK) - { - // The old location is dying - genUpdateRegLife(varDsc, /*isBorn*/ false, /*isDying*/ true DEBUGARG(op1)); - - gcInfo.gcMarkRegSetNpt(genRegMask(op1->GetRegNum())); - - genUpdateVarReg(varDsc, treeNode); - -#ifdef USING_VARIABLE_LIVE_RANGE - // Report the home change for this variable - varLiveKeeper->siUpdateVariableLiveRange(varDsc, lcl->GetLclNum()); -#endif // USING_VARIABLE_LIVE_RANGE - - // The new location is going live - genUpdateRegLife(varDsc, /*isBorn*/ true, /*isDying*/ false DEBUGARG(treeNode)); - } - } - } - } - - genProduceReg(treeNode); -} - //------------------------------------------------------------------------ // genCodeForStoreInd: Produce code for a GT_STOREIND node. // @@ -5334,7 +4999,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call) assert(!call->IsVirtual() || call->gtControlExpr || call->gtCallAddr); // Insert a GS check if necessary - if (call->IsTailCallViaHelper()) + if (call->IsTailCallViaJitHelper()) { if (compiler->getNeedsGSSecurityCookie()) { @@ -5506,9 +5171,9 @@ void CodeGen::genCallInstruction(GenTreeCall* call) } // Determine return value size(s). - ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); - emitAttr retSize = EA_PTRSIZE; - emitAttr secondRetSize = EA_UNKNOWN; + const ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); + emitAttr retSize = EA_PTRSIZE; + emitAttr secondRetSize = EA_UNKNOWN; if (call->HasMultiRegRetVal()) { @@ -5555,20 +5220,6 @@ void CodeGen::genCallInstruction(GenTreeCall* call) #if defined(TARGET_X86) bool fCallerPop = call->CallerPop(); -#ifdef UNIX_X86_ABI - if (!call->IsUnmanaged()) - { - CorInfoCallConv callConv = CORINFO_CALLCONV_DEFAULT; - - if ((callType != CT_HELPER) && call->callSig) - { - callConv = call->callSig->callConv; - } - - fCallerPop |= IsCallerPop(callConv); - } -#endif // UNIX_X86_ABI - // If the callee pops the arguments, we pass a positive value as the argSize, and the emitter will // adjust its stack level accordingly. // If the caller needs to explicitly pop its arguments, we must pass a negative value, and then do the @@ -5747,10 +5398,9 @@ void CodeGen::genCallInstruction(GenTreeCall* call) // clang-format on } - // if it was a pinvoke we may have needed to get the address of a label + // if it was a pinvoke or intrinsic we may have needed to get the address of a label if (genPendingCallLabel) { - assert(call->IsUnmanaged()); genDefineInlineTempLabel(genPendingCallLabel); genPendingCallLabel = nullptr; } @@ -5786,7 +5436,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call) if (call->HasMultiRegRetVal()) { assert(retTypeDesc != nullptr); - unsigned regCount = retTypeDesc->GetReturnRegCount(); + const unsigned regCount = retTypeDesc->GetReturnRegCount(); // If regs allocated to call node are different from ABI return // regs in which the call has returned its result, move the result @@ -7211,7 +6861,11 @@ void CodeGen::genSSE2BitwiseOp(GenTree* treeNode) if (*bitMask == nullptr) { assert(cnsAddr != nullptr); - *bitMask = GetEmitter()->emitAnyConst(cnsAddr, genTypeSize(targetType), emitDataAlignment::Preferred); + + UNATIVE_OFFSET cnsSize = genTypeSize(targetType); + UNATIVE_OFFSET cnsAlign = (compiler->compCodeOpt() != Compiler::SMALL_CODE) ? cnsSize : 1; + + *bitMask = GetEmitter()->emitAnyConst(cnsAddr, cnsSize, cnsAlign); } // We need an additional register for bitmask. @@ -8845,9 +8499,9 @@ void CodeGen::genAmd64EmitterUnitTests() // genProfilingEnterCallback: Generate the profiling function enter callback. // // Arguments: -// initReg - register to use as scratch register -// pInitRegZeroed - OUT parameter. *pInitRegZeroed set to 'false' if 'initReg' is -// not zero after this call. +// initReg - register to use as scratch register +// pInitRegModified - OUT parameter. *pInitRegModified set to 'true' if 'initReg' is +// not zero after this call. // // Return Value: // None @@ -8866,7 +8520,7 @@ void CodeGen::genAmd64EmitterUnitTests() // 4. All registers are preserved. // 5. The helper pops the FunctionIDOrClientID argument from the stack. // -void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed) +void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegModified) { assert(compiler->compGeneratingProlog); @@ -9011,14 +8665,14 @@ void CodeGen::genProfilingLeaveCallback(unsigned helper) // genProfilingEnterCallback: Generate the profiling function enter callback. // // Arguments: -// initReg - register to use as scratch register -// pInitRegZeroed - OUT parameter. *pInitRegZeroed set to 'false' if 'initReg' is -// not zero after this call. +// initReg - register to use as scratch register +// pInitRegModified - OUT parameter. *pInitRegModified set to 'true' if 'initReg' is +// not zero after this call. // // Return Value: // None // -void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed) +void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegModified) { assert(compiler->compGeneratingProlog); @@ -9155,7 +8809,7 @@ void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed) // If initReg is one of RBM_CALLEE_TRASH, then it needs to be zero'ed before using. if ((RBM_CALLEE_TRASH & genRegMask(initReg)) != 0) { - *pInitRegZeroed = false; + *pInitRegModified = true; } #else // !defined(UNIX_AMD64_ABI) @@ -9204,7 +8858,7 @@ void CodeGen::genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed) // If initReg is one of RBM_CALLEE_TRASH, then it needs to be zero'ed before using. if ((RBM_CALLEE_TRASH & genRegMask(initReg)) != 0) { - *pInitRegZeroed = false; + *pInitRegModified = true; } #endif // !defined(UNIX_AMD64_ABI) diff --git a/src/coreclr/src/jit/compiler.cpp b/src/coreclr/src/jit/compiler.cpp index a757488847208e..0a9003f51268c8 100644 --- a/src/coreclr/src/jit/compiler.cpp +++ b/src/coreclr/src/jit/compiler.cpp @@ -1825,6 +1825,8 @@ void Compiler::compInit(ArenaAllocator* pAlloc, InlineInfo* inlineInfo) compFloatingPointUsed = false; compUnsafeCastUsed = false; + compSuppressedZeroInit = false; + compNeedsGSSecurityCookie = false; compGSReorderStackLayout = false; @@ -2159,7 +2161,7 @@ const char* Compiler::compLocalVarName(unsigned varNum, unsigned offs) void Compiler::compSetProcessor() { // - // NOTE: This function needs to be kept in sync with EEJitManager::SetCpuInfo() in vm\codemap.cpp + // NOTE: This function needs to be kept in sync with EEJitManager::SetCpuInfo() in vm\codeman.cpp // const JitFlags& jitFlags = *opts.jitFlags; @@ -2193,13 +2195,14 @@ void Compiler::compSetProcessor() #endif // TARGET_X86 + // The VM will set the ISA flags depending on actual hardware support. + // We then select which ISAs to leave enabled based on the JIT config. + // The exception to this is the dummy Vector64/128/256 ISAs, which must be added explicitly. CORINFO_InstructionSetFlags instructionSetFlags = jitFlags.GetInstructionSetFlags(); opts.compSupportsISA = 0; opts.compSupportsISAReported = 0; #ifdef TARGET_XARCH - bool avxSupported = false; - if (JitConfig.EnableHWIntrinsic()) { // Dummy ISAs for simplifying the JIT code @@ -2313,8 +2316,6 @@ void Compiler::compSetProcessor() if (JitConfig.EnableHWIntrinsic()) { // Dummy ISAs for simplifying the JIT code - instructionSetFlags.AddInstructionSet(InstructionSet_ArmBase); - instructionSetFlags.AddInstructionSet(InstructionSet_ArmBase_Arm64); instructionSetFlags.AddInstructionSet(InstructionSet_Vector64); instructionSetFlags.AddInstructionSet(InstructionSet_Vector128); } @@ -2693,6 +2694,11 @@ void Compiler::compInitOptions(JitFlags* jitFlags) opts.compTailCallOpt = true; #endif // FEATURE_TAILCALL_OPT +#if FEATURE_FASTTAILCALL + // By default fast tail calls are enabled. + opts.compFastTailCalls = true; +#endif // FEATURE_FASTTAILCALL + if (compIsForInlining()) { return; @@ -3033,6 +3039,13 @@ void Compiler::compInitOptions(JitFlags* jitFlags) } #endif +#if FEATURE_FASTTAILCALL + if (JitConfig.FastTailCalls() == 0) + { + opts.compFastTailCalls = false; + } +#endif // FEATURE_FASTTAILCALL + opts.compScopeInfo = opts.compDbgInfo; #ifdef LATE_DISASM @@ -4461,9 +4474,16 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags }; DoPhase(this, PHASE_COMPUTE_PREDS, computePredsPhase); - // Run an early flow graph simplification pass + // Now that we have pred lists, do some flow-related optimizations + // if (opts.OptimizationEnabled()) { + // Merge common throw blocks + // + DoPhase(this, PHASE_MERGE_THROWS, &Compiler::fgTailMergeThrows); + + // Run an early flow graph simplification pass + // auto earlyUpdateFlowGraphPhase = [this]() { const bool doTailDup = false; fgUpdateFlowGraph(doTailDup); @@ -4578,9 +4598,6 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags if (opts.OptimizationEnabled()) { - // Merge common throw blocks - // - DoPhase(this, PHASE_MERGE_THROWS, &Compiler::fgTailMergeThrows); // Optimize block order // DoPhase(this, PHASE_OPTIMIZE_LAYOUT, &Compiler::optOptimizeLayout); @@ -4673,6 +4690,8 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags DoPhase(this, PHASE_BUILD_SSA, &Compiler::fgSsaBuild); } + DoPhase(this, PHASE_ZERO_INITS, &Compiler::optRemoveRedundantZeroInits); + if (doEarlyProp) { // Propagate array length and rewrite getType() method call @@ -5876,6 +5895,8 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr, info.compPublishStubParam = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM); + info.compHasNextCallRetAddr = false; + switch (methodInfo->args.getCallConv()) { case CORINFO_CALLCONV_VARARG: @@ -8979,9 +9000,9 @@ void cTreeFlags(Compiler* comp, GenTree* tree) { chars += printf("[CALL_M_FRAME_VAR_DEATH]"); } - if (call->gtCallMoreFlags & GTF_CALL_M_TAILCALL_VIA_HELPER) + if (call->gtCallMoreFlags & GTF_CALL_M_TAILCALL_VIA_JIT_HELPER) { - chars += printf("[CALL_M_TAILCALL_VIA_HELPER]"); + chars += printf("[CALL_M_TAILCALL_VIA_JIT_HELPER]"); } #if FEATURE_TAILCALL_OPT if (call->gtCallMoreFlags & GTF_CALL_M_IMPLICIT_TAILCALL) diff --git a/src/coreclr/src/jit/compiler.h b/src/coreclr/src/jit/compiler.h index 9948bdea3c7b40..c6181d5e194a55 100644 --- a/src/coreclr/src/jit/compiler.h +++ b/src/coreclr/src/jit/compiler.h @@ -61,6 +61,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #include "hwintrinsic.h" #include "simd.h" +#include "simdashwintrinsic.h" // This is only used locally in the JIT to indicate that // a verification block should be inserted @@ -515,6 +516,12 @@ class LclVarDsc unsigned char lvImplicitlyReferenced : 1; // true if there are non-IR references to this local (prolog, epilog, gc, // eh) + unsigned char lvSuppressedZeroInit : 1; // local needs zero init if we transform tail call to loop + + unsigned char lvHasExplicitInit : 1; // The local is explicitly initialized and doesn't need zero initialization in + // the prolog. If the local has gc pointers, there are no gc-safe points + // between the prolog and the explicit initialization. + union { unsigned lvFieldLclStart; // The index of the local var representing the first field in the promoted struct // local. For implicit byref parameters, this gets hijacked between @@ -1735,6 +1742,10 @@ struct fgArgTabEntry #else unsigned int regSize = 1; #endif + + if (numRegs > MAX_ARG_REG_COUNT) + NO_WAY("Multireg argument exceeds the maximum length"); + for (unsigned int regIndex = 1; regIndex < numRegs; regIndex++) { argReg = (regNumber)(argReg + regSize); @@ -2093,6 +2104,8 @@ class Compiler bool shouldUseVerboseSsa(); bool treesBeforeAfterMorph; // If true, print trees before/after morphing (paired by an intra-compilation id: int morphNum; // This counts the the trees that have been morphed, allowing us to label each uniquely. + bool doExtraSuperPmiQueries; + void makeExtraStructQueries(CORINFO_CLASS_HANDLE structHandle, int level); // Make queries recursively 'level' deep. const char* VarNameToStr(VarName name) { @@ -2566,6 +2579,10 @@ class Compiler GenTreeCall* gtNewHelperCallNode(unsigned helper, var_types type, GenTreeCall::Use* args = nullptr); + GenTreeCall* gtNewRuntimeLookupHelperCallNode(CORINFO_RUNTIME_LOOKUP* pRuntimeLookup, + GenTree* ctxTree, + void* compileTimeHandle); + GenTree* gtNewLclvNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs = BAD_IL_OFFSET)); GenTree* gtNewLclLNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs = BAD_IL_OFFSET)); @@ -2607,6 +2624,46 @@ class Compiler NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size); + + GenTreeHWIntrinsic* gtNewSimdAsHWIntrinsicNode(var_types type, + NamedIntrinsic hwIntrinsicID, + var_types baseType, + unsigned size) + { + GenTreeHWIntrinsic* node = gtNewSimdHWIntrinsicNode(type, hwIntrinsicID, baseType, size); + node->gtFlags |= GTF_SIMDASHW_OP; + return node; + } + + GenTreeHWIntrinsic* gtNewSimdAsHWIntrinsicNode( + var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size) + { + GenTreeHWIntrinsic* node = gtNewSimdHWIntrinsicNode(type, op1, hwIntrinsicID, baseType, size); + node->gtFlags |= GTF_SIMDASHW_OP; + return node; + } + + GenTreeHWIntrinsic* gtNewSimdAsHWIntrinsicNode( + var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size) + { + GenTreeHWIntrinsic* node = gtNewSimdHWIntrinsicNode(type, op1, op2, hwIntrinsicID, baseType, size); + node->gtFlags |= GTF_SIMDASHW_OP; + return node; + } + + GenTreeHWIntrinsic* gtNewSimdAsHWIntrinsicNode(var_types type, + GenTree* op1, + GenTree* op2, + GenTree* op3, + NamedIntrinsic hwIntrinsicID, + var_types baseType, + unsigned size) + { + GenTreeHWIntrinsic* node = gtNewSimdHWIntrinsicNode(type, op1, op2, op3, hwIntrinsicID, baseType, size); + node->gtFlags |= GTF_SIMDASHW_OP; + return node; + } + GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID); GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, @@ -2614,7 +2671,6 @@ class Compiler NamedIntrinsic hwIntrinsicID); GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode( var_types type, GenTree* op1, GenTree* op2, GenTree* op3, NamedIntrinsic hwIntrinsicID); - GenTree* gtNewMustThrowException(unsigned helper, var_types type, CORINFO_CLASS_HANDLE clsHnd); CORINFO_CLASS_HANDLE gtGetStructHandleForHWSIMD(var_types simdType, var_types simdBaseType); var_types getBaseTypeFromArgIfNeeded(NamedIntrinsic intrinsic, CORINFO_CLASS_HANDLE clsHnd, @@ -2622,6 +2678,8 @@ class Compiler var_types baseType); #endif // FEATURE_HW_INTRINSICS + GenTree* gtNewMustThrowException(unsigned helper, var_types type, CORINFO_CLASS_HANDLE clsHnd); + GenTreeLclFld* gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset); GenTree* gtNewInlineCandidateReturnExpr(GenTree* inlineCandidate, var_types type); @@ -2645,7 +2703,7 @@ class Compiler fgArgTabEntry* gtArgEntryByLateArgIndex(GenTreeCall* call, unsigned lateArgInx); static GenTree* gtArgNodeByLateArgInx(GenTreeCall* call, unsigned lateArgInx); - GenTree* gtNewAssignNode(GenTree* dst, GenTree* src); + GenTreeOp* gtNewAssignNode(GenTree* dst, GenTree* src); GenTree* gtNewTempAssign(unsigned tmp, GenTree* val, @@ -2852,9 +2910,7 @@ class Compiler // Get the element handle for an array of ref type. CORINFO_CLASS_HANDLE gtGetArrayElementClassHandle(GenTree* array); // Get a class handle from a helper call argument - CORINFO_CLASS_HANDLE gtGetHelperArgClassHandle(GenTree* array, - unsigned* runtimeLookupCount = nullptr, - GenTree** handleTree = nullptr); + CORINFO_CLASS_HANDLE gtGetHelperArgClassHandle(GenTree* array, GenTree** handleTree = nullptr); // Get the class handle for a field CORINFO_CLASS_HANDLE gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldHnd, bool* pIsExact, bool* pIsNonNull); // Check if this tree is a gc static base helper call @@ -3105,6 +3161,10 @@ class Compiler unsigned lvaOutgoingArgSpaceVar; // dummy TYP_LCLBLK var for fixed outgoing argument space PhasedVar lvaOutgoingArgSpaceSize; // size of fixed outgoing argument space #endif // FEATURE_FIXED_OUT_ARGS + // Variable representing the return address. The helper-based tailcall + // mechanism passes the address of the return address to a runtime helper + // where it is used to detect tail-call chains. + unsigned lvaRetAddrVar; #ifdef TARGET_ARM // On architectures whose ABIs allow structs to be passed in registers, struct promotion will sometimes @@ -3127,7 +3187,7 @@ class Compiler #endif // defined(DEBUG) && defined(TARGET_X86) - unsigned lvaGenericsContextUseCount; + bool lvaGenericsContextInUse; bool lvaKeepAliveAndReportThis(); // Synchronized instance method of a reference type, or // CORINFO_GENERICS_CTXT_FROM_THIS? @@ -3455,19 +3515,21 @@ class Compiler assert(varDsc->lvSize() == 16); #endif // defined(TARGET_64BIT) - // We make local variable SIMD12 types 16 bytes instead of just 12. lvSize() - // already does this calculation. However, we also need to prevent mapping types if the var is a - // dependently promoted struct field, which must remain its exact size within its parent struct. - // However, we don't know this until late, so we may have already pretended the field is bigger - // before that. - if ((varDsc->lvSize() == 16) && !lvaIsFieldOfDependentlyPromotedStruct(varDsc)) + // We make local variable SIMD12 types 16 bytes instead of just 12. + // lvSize() will return 16 bytes for SIMD12, even for fields. + // However, we can't do that mapping if the var is a dependently promoted struct field. + // Such a field must remain its exact size within its parent struct unless it is a single + // field *and* it is the only field in a struct of 16 bytes. + if (varDsc->lvSize() != 16) { - return true; + return false; } - else + if (lvaIsFieldOfDependentlyPromotedStruct(varDsc)) { - return false; + LclVarDsc* parentVarDsc = lvaGetDesc(varDsc->lvParentLcl); + return (parentVarDsc->lvFieldCnt == 1) && (parentVarDsc->lvSize() == 16); } + return true; } #endif // defined(FEATURE_SIMD) @@ -3668,6 +3730,10 @@ class Compiler CorInfoIntrinsics intrinsicID, bool tailCall); NamedIntrinsic lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method); + GenTree* impUnsupportedNamedIntrinsic(unsigned helper, + CORINFO_METHOD_HANDLE method, + CORINFO_SIG_INFO* sig, + bool mustExpand); #ifdef FEATURE_HW_INTRINSICS GenTree* impHWIntrinsic(NamedIntrinsic intrinsic, @@ -3675,33 +3741,63 @@ class Compiler CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig, bool mustExpand); - GenTree* impUnsupportedHWIntrinsic(unsigned helper, - CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* sig, - bool mustExpand); + GenTree* impSimdAsHWIntrinsic(NamedIntrinsic intrinsic, + CORINFO_CLASS_HANDLE clsHnd, + CORINFO_METHOD_HANDLE method, + CORINFO_SIG_INFO* sig, + bool mustExpand); protected: bool compSupportsHWIntrinsic(CORINFO_InstructionSet isa); + GenTree* impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, + CORINFO_CLASS_HANDLE clsHnd, + CORINFO_SIG_INFO* sig, + var_types retType, + var_types baseType, + unsigned simdSize); + + GenTree* impSimdAsHWIntrinsicCndSel(CORINFO_CLASS_HANDLE clsHnd, + var_types retType, + var_types baseType, + unsigned simdSize, + GenTree* op1, + GenTree* op2, + GenTree* op3); + GenTree* impSpecialIntrinsic(NamedIntrinsic intrinsic, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* sig); + CORINFO_SIG_INFO* sig, + var_types baseType, + var_types retType, + unsigned simdSize); - GenTree* getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE argClass); + GenTree* getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE argClass, bool expectAddr = false); GenTree* impNonConstFallback(NamedIntrinsic intrinsic, var_types simdType, var_types baseType); - GenTree* addRangeCheckIfNeeded(NamedIntrinsic intrinsic, GenTree* lastOp, bool mustExpand); + GenTree* addRangeCheckIfNeeded( + NamedIntrinsic intrinsic, GenTree* lastOp, bool mustExpand, int immLowerBound, int immUpperBound); #ifdef TARGET_XARCH GenTree* impBaseIntrinsic(NamedIntrinsic intrinsic, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* sig); + CORINFO_SIG_INFO* sig, + var_types baseType, + var_types retType, + unsigned simdSize); GenTree* impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); GenTree* impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); GenTree* impAvxOrAvx2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); GenTree* impBMI1OrBMI2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); + GenTree* impSimdAsHWIntrinsicRelOp(NamedIntrinsic intrinsic, + CORINFO_CLASS_HANDLE clsHnd, + var_types retType, + var_types baseType, + unsigned simdSize, + GenTree* op1, + GenTree* op2); #endif // TARGET_XARCH #endif // FEATURE_HW_INTRINSICS GenTree* impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd, @@ -4561,8 +4657,11 @@ class Compiler unsigned fgSsaPassesCompleted; // Number of times fgSsaBuild has been run. + // Returns "true" if this is a special variable that is never zero initialized in the prolog. + inline bool fgVarIsNeverZeroInitializedInProlog(unsigned varNum); + // Returns "true" if the variable needs explicit zero initialization. - inline bool fgVarNeedsExplicitZeroInit(LclVarDsc* varDsc, bool bbInALoop, bool bbIsReturn); + inline bool fgVarNeedsExplicitZeroInit(unsigned varNum, bool bbInALoop, bool bbIsReturn); // The value numbers for this compilation. ValueNumStore* vnStore; @@ -5442,8 +5541,29 @@ class Compiler private: GenTree* fgMorphField(GenTree* tree, MorphAddrContext* mac); bool fgCanFastTailCall(GenTreeCall* call, const char** failReason); - bool fgCheckStmtAfterTailCall(); - void fgMorphTailCallViaHelper(GenTreeCall* call, void* pfnCopyArgs); +#if FEATURE_FASTTAILCALL + bool fgCallHasMustCopyByrefParameter(GenTreeCall* callee); +#endif + bool fgCheckStmtAfterTailCall(); + GenTree* fgMorphTailCallViaHelpers(GenTreeCall* call, CORINFO_TAILCALL_HELPERS& help); + bool fgCanTailCallViaJitHelper(); + void fgMorphTailCallViaJitHelper(GenTreeCall* call); + GenTree* fgCreateCallDispatcherAndGetResult(GenTreeCall* origCall, + CORINFO_METHOD_HANDLE callTargetStubHnd, + CORINFO_METHOD_HANDLE dispatcherHnd); + GenTree* getMethodPointerTree(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo); + GenTree* getLookupTree(CORINFO_RESOLVED_TOKEN* pResolvedToken, + CORINFO_LOOKUP* pLookup, + unsigned handleFlags, + void* compileTimeHandle); + GenTree* getRuntimeLookupTree(CORINFO_RESOLVED_TOKEN* pResolvedToken, + CORINFO_LOOKUP* pLookup, + void* compileTimeHandle); + GenTree* getVirtMethodPointerTree(GenTree* thisPtr, + CORINFO_RESOLVED_TOKEN* pResolvedToken, + CORINFO_CALL_INFO* pCallInfo); + GenTree* getTokenHandleTree(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool parent); + GenTree* fgMorphPotentialTailCall(GenTreeCall* call); GenTree* fgGetStubAddrArg(GenTreeCall* call); void fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCall* recursiveTailCall); @@ -5753,8 +5873,13 @@ class Compiler // static) written to, and SZ-array element type equivalence classes updated. void optComputeLoopNestSideEffects(unsigned lnum); + // Given a loop number 'lnum' mark it and any nested loops as having 'memoryHavoc' + void optRecordLoopNestsMemoryHavoc(unsigned lnum, MemoryKindSet memoryHavoc); + // Add the side effects of "blk" (which is required to be within a loop) to all loops of which it is a part. - void optComputeLoopSideEffectsOfBlock(BasicBlock* blk); + // Returns false if we encounter a block that is not marked as being inside a loop. + // + bool optComputeLoopSideEffectsOfBlock(BasicBlock* blk); // Hoist the expression "expr" out of loop "lnum". void optPerformHoistExpr(GenTree* expr, unsigned lnum); @@ -5788,6 +5913,8 @@ class Compiler void optUnrollLoops(); // Unrolls loops (needs to have cost info) + void optRemoveRedundantZeroInits(); + protected: // This enumeration describes what is killed by a call. @@ -6054,6 +6181,7 @@ class Compiler bool optLoopContains(unsigned l1, unsigned l2); // Requires "loopInd" to be a valid index into the loop table. + // Updates the loop table by changing loop "loopInd", whose head is required // to be "from", to be "to". Also performs this transformation for any // loop nested in "loopInd" that shares the same head as "loopInd". @@ -6076,6 +6204,9 @@ class Compiler // of "from".) Copies the jump destination from "from" to "to". void optCopyBlkDest(BasicBlock* from, BasicBlock* to); + // Returns true if 'block' is an entry block for any loop in 'optLoopTable' + bool optIsLoopEntry(BasicBlock* block); + // The depth of the loop described by "lnum" (an index into the loop table.) (0 == top level) unsigned optLoopDepth(unsigned lnum) { @@ -7859,9 +7990,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX static bool isRelOpSIMDIntrinsic(SIMDIntrinsicID intrinsicId) { - return (intrinsicId == SIMDIntrinsicEqual || intrinsicId == SIMDIntrinsicLessThan || - intrinsicId == SIMDIntrinsicLessThanOrEqual || intrinsicId == SIMDIntrinsicGreaterThan || - intrinsicId == SIMDIntrinsicGreaterThanOrEqual); + return (intrinsicId == SIMDIntrinsicEqual); } // Returns base type of a TYP_SIMD local. @@ -7965,22 +8094,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // Create a GT_SIMD tree for a Get property of SIMD vector with a fixed index. GenTreeSIMD* impSIMDGetFixed(var_types simdType, var_types baseType, unsigned simdSize, int index); - // Creates a GT_SIMD tree for Select operation - GenTree* impSIMDSelect(CORINFO_CLASS_HANDLE typeHnd, - var_types baseType, - unsigned simdVectorSize, - GenTree* op1, - GenTree* op2, - GenTree* op3); - - // Creates a GT_SIMD tree for Min/Max operation - GenTree* impSIMDMinMax(SIMDIntrinsicID intrinsicId, - CORINFO_CLASS_HANDLE typeHnd, - var_types baseType, - unsigned simdVectorSize, - GenTree* op1, - GenTree* op2); - // Transforms operands and returns the SIMD intrinsic to be applied on // transformed operands to obtain given relop result. SIMDIntrinsicID impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId, @@ -7990,9 +8103,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX GenTree** op1, GenTree** op2); - // Creates a GT_SIMD tree for Abs intrinsic. - GenTree* impSIMDAbs(CORINFO_CLASS_HANDLE typeHnd, var_types baseType, unsigned simdVectorSize, GenTree* op1); - #if defined(TARGET_XARCH) // Transforms operands and returns the SIMD intrinsic to be applied on @@ -8002,26 +8112,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX GenTree** op1, GenTree** op2); - // Transforms operands and returns the SIMD intrinsic to be applied on - // transformed operands to obtain > comparison result. - SIMDIntrinsicID impSIMDLongRelOpGreaterThan(CORINFO_CLASS_HANDLE typeHnd, - unsigned simdVectorSize, - GenTree** op1, - GenTree** op2); - - // Transforms operands and returns the SIMD intrinsic to be applied on - // transformed operands to obtain >= comparison result. - SIMDIntrinsicID impSIMDLongRelOpGreaterThanOrEqual(CORINFO_CLASS_HANDLE typeHnd, - unsigned simdVectorSize, - GenTree** op1, - GenTree** op2); - - // Transforms operands and returns the SIMD intrinsic to be applied on - // transformed operands to obtain >= comparison result in case of int32 - // and small int base type vectors. - SIMDIntrinsicID impSIMDIntegralRelOpGreaterThanOrEqual( - CORINFO_CLASS_HANDLE typeHnd, unsigned simdVectorSize, var_types baseType, GenTree** op1, GenTree** op2); - #endif // defined(TARGET_XARCH) void setLclRelatedToSIMDIntrinsic(GenTree* tree); @@ -8047,7 +8137,25 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // AVX: vector2f, 3f and 4f are all considered sub register SIMD types. bool isSubRegisterSIMDType(GenTreeSIMD* simdNode) { - return (simdNode->gtSIMDSize < getSIMDVectorRegisterByteLength()); + unsigned vectorRegisterByteLength; +#if defined(TARGET_XARCH) + // Calling the getSIMDVectorRegisterByteLength api causes the size of Vector to be recorded + // with the AOT compiler, so that it cannot change from aot compilation time to runtime + // This api does not require such fixing as it merely pertains to the size of the simd type + // relative to the Vector size as used at compile time. (So detecting a vector length of 16 here + // does not preclude the code from being used on a machine with a larger vector length.) + if (getSIMDSupportLevel() < SIMD_AVX2_Supported) + { + vectorRegisterByteLength = 16; + } + else + { + vectorRegisterByteLength = 32; + } +#else + vectorRegisterByteLength = getSIMDVectorRegisterByteLength(); +#endif + return (simdNode->gtSIMDSize < vectorRegisterByteLength); } // Get the type for the hardware SIMD vector. @@ -8145,8 +8253,9 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX return emitTypeSize(TYP_SIMD8); } +public: // Returns the codegen type for a given SIMD size. - var_types getSIMDTypeForSize(unsigned size) + static var_types getSIMDTypeForSize(unsigned size) { var_types simdType = TYP_UNDEF; if (size == 8) @@ -8172,6 +8281,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX return simdType; } +private: unsigned getSIMDInitTempVarNum() { if (lvaSIMDInitTempVarNum == BAD_VAR_NUM) @@ -8415,6 +8525,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX bool compHasBackwardJump; // Does the method (or some inlinee) have a lexically backwards jump? bool compSwitchedToOptimized; // Codegen initially was Tier0 but jit switched to FullOpts bool compSwitchedToMinOpts; // Codegen initially was Tier1/FullOpts but jit switched to MinOpts + bool compSuppressedZeroInit; // There are vars with lvSuppressedZeroInit set // NOTE: These values are only reliable after // the importing is completely finished. @@ -8685,6 +8796,11 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX bool compTailCallLoopOpt; #endif +#if FEATURE_FASTTAILCALL + // Whether fast tail calls are allowed. + bool compFastTailCalls; +#endif // FEATURE_FASTTAILCALL + #if defined(TARGET_ARM64) // Decision about whether to save FP/LR registers with callee-saved registers (see // COMPlus_JitSaveFpLrWithCalleSavedRegisters). @@ -8843,7 +8959,11 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX bool compTailCallStress() { #ifdef DEBUG - return (JitConfig.TailcallStress() != 0 || compStressCompile(STRESS_TAILCALL, 5)); + // Do not stress tailcalls in IL stubs as the runtime creates several IL + // stubs to implement the tailcall mechanism, which would then + // recursively create more IL stubs. + return !opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB) && + (JitConfig.TailcallStress() != 0 || compStressCompile(STRESS_TAILCALL, 5)); #else return false; #endif @@ -8918,12 +9038,13 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // (2) the code is hot/cold split, and we issued less code than we expected // in the cold section (the hot section will always be padded out to compTotalHotCodeSize). - bool compIsStatic : 1; // Is the method static (no 'this' pointer)? - bool compIsVarArgs : 1; // Does the method have varargs parameters? - bool compInitMem : 1; // Is the CORINFO_OPT_INIT_LOCALS bit set in the method info options? - bool compProfilerCallback : 1; // JIT inserted a profiler Enter callback - bool compPublishStubParam : 1; // EAX captured in prolog will be available through an instrinsic - bool compRetBuffDefStack : 1; // The ret buff argument definitely points into the stack. + bool compIsStatic : 1; // Is the method static (no 'this' pointer)? + bool compIsVarArgs : 1; // Does the method have varargs parameters? + bool compInitMem : 1; // Is the CORINFO_OPT_INIT_LOCALS bit set in the method info options? + bool compProfilerCallback : 1; // JIT inserted a profiler Enter callback + bool compPublishStubParam : 1; // EAX captured in prolog will be available through an instrinsic + bool compRetBuffDefStack : 1; // The ret buff argument definitely points into the stack. + bool compHasNextCallRetAddr : 1; // The NextCallReturnAddress intrinsic is used. var_types compRetType; // Return type of the method as declared in IL var_types compRetNativeType; // Normalized return type as per target arch ABI @@ -9019,6 +9140,11 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #endif // !TARGET_AMD64 } + bool compDoOldStructRetyping() + { + return JitConfig.JitDoOldStructRetyping(); + } + // Returns true if the method returns a value in more than one return register // TODO-ARM-Bug: Deal with multi-register genReturnLocaled structs? // TODO-ARM64: Does this apply for ARM64 too? diff --git a/src/coreclr/src/jit/compiler.hpp b/src/coreclr/src/jit/compiler.hpp index a3b3838d48ed58..f3e590a7303a45 100644 --- a/src/coreclr/src/jit/compiler.hpp +++ b/src/coreclr/src/jit/compiler.hpp @@ -702,6 +702,7 @@ inline bool Compiler::VarTypeIsMultiByteAndCanEnreg( if (varTypeIsStruct(type)) { + assert(typeClass != nullptr); size = info.compCompHnd->getClassSize(typeClass); if (forReturn) { @@ -969,9 +970,11 @@ inline GenTree* Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTree // IND(ADDR(IND(x)) == IND(x) if (op1->gtOper == GT_ADDR) { - if (op1->AsOp()->gtOp1->gtOper == GT_IND && (op1->AsOp()->gtOp1->gtFlags & GTF_IND_ARR_INDEX) == 0) + GenTreeUnOp* addr = op1->AsUnOp(); + GenTree* indir = addr->gtGetOp1(); + if (indir->OperIs(GT_IND) && ((indir->gtFlags & GTF_IND_ARR_INDEX) == 0)) { - op1 = op1->AsOp()->gtOp1->AsOp()->gtOp1; + op1 = indir->AsIndir()->Addr(); } } } @@ -982,6 +985,11 @@ inline GenTree* Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTree { return op1->AsOp()->gtOp1; } + else + { + // Addr source can't be CSE-ed. + op1->SetDoNotCSE(); + } } } @@ -1125,6 +1133,28 @@ inline GenTreeCall* Compiler::gtNewHelperCallNode(unsigned helper, var_types typ return result; } +//------------------------------------------------------------------------------ +// gtNewRuntimeLookupHelperCallNode : Helper to create a runtime lookup call helper node. +// +// +// Arguments: +// helper - Call helper +// type - Type of the node +// args - Call args +// +// Return Value: +// New CT_HELPER node + +inline GenTreeCall* Compiler::gtNewRuntimeLookupHelperCallNode(CORINFO_RUNTIME_LOOKUP* pRuntimeLookup, + GenTree* ctxTree, + void* compileTimeHandle) +{ + GenTree* argNode = gtNewIconEmbHndNode(pRuntimeLookup->signature, nullptr, GTF_ICON_TOKEN_HDL, compileTimeHandle); + GenTreeCall::Use* helperArgs = gtNewCallArgs(ctxTree, argNode); + + return gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, helperArgs); +} + //------------------------------------------------------------------------ // gtNewAllocObjNode: A little helper to create an object allocation node. // @@ -1778,8 +1808,11 @@ inline void LclVarDsc::incRefCnts(BasicBlock::weight_t weight, Compiler* comp, R // // Increment counts on the local itself. // - if (lvType != TYP_STRUCT || promotionType != Compiler::PROMOTION_TYPE_INDEPENDENT) + if ((lvType != TYP_STRUCT) || (promotionType != Compiler::PROMOTION_TYPE_INDEPENDENT)) { + // We increment ref counts of this local for primitive types, including structs that have been retyped as their + // only field, as well as for structs whose fields are not independently promoted. + // // Increment lvRefCnt // @@ -1931,9 +1964,9 @@ inline bool Compiler::lvaKeepAliveAndReportThis() if (opts.compDbgCode) return true; - if (lvaGenericsContextUseCount > 0) + if (lvaGenericsContextInUse) { - JITDUMP("Reporting this as generic context: %u refs\n", lvaGenericsContextUseCount); + JITDUMP("Reporting this as generic context\n"); return true; } } @@ -1944,14 +1977,11 @@ inline bool Compiler::lvaKeepAliveAndReportThis() // because collectible types need the generics context when gc-ing. if (genericsContextIsThis) { - const bool isUsed = lvaGenericsContextUseCount > 0; const bool mustKeep = (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_KEEP_ALIVE) != 0; - if (isUsed || mustKeep) + if (lvaGenericsContextInUse || mustKeep) { - JITDUMP("Reporting this as generic context: %u refs%s\n", lvaGenericsContextUseCount, - mustKeep ? ", must keep" : ""); - + JITDUMP("Reporting this as generic context: %s\n", mustKeep ? "must keep" : "referenced"); return true; } } @@ -1979,7 +2009,7 @@ inline bool Compiler::lvaReportParamTypeArg() // Otherwise, if an exact type parameter is needed in the body, report the generics context. // We do this because collectible types needs the generics context when gc-ing. - if (lvaGenericsContextUseCount > 0) + if (lvaGenericsContextInUse) { return true; } @@ -4115,11 +4145,39 @@ inline void Compiler::CLR_API_Leave(API_ICorJitInfo_Names ename) #endif // MEASURE_CLRAPI_CALLS +//------------------------------------------------------------------------------ +// fgVarIsNeverZeroInitializedInProlog : Check whether the variable is never zero initialized in the prolog. +// +// Arguments: +// varNum - local variable number +// +// Returns: +// true if this is a special variable that is never zero initialized in the prolog; +// false otherwise +// + +bool Compiler::fgVarIsNeverZeroInitializedInProlog(unsigned varNum) +{ + LclVarDsc* varDsc = lvaGetDesc(varNum); + bool result = varDsc->lvIsParam || lvaIsOSRLocal(varNum) || (opts.IsOSR() && (varNum == lvaGSSecurityCookie)) || + (varNum == lvaInlinedPInvokeFrameVar) || (varNum == lvaStubArgumentVar) || (varNum == lvaRetAddrVar); + +#if FEATURE_FIXED_OUT_ARGS + result = result || (varNum == lvaPInvokeFrameRegSaveVar) || (varNum == lvaOutgoingArgSpaceVar); +#endif + +#if defined(FEATURE_EH_FUNCLETS) + result = result || (varNum == lvaPSPSym); +#endif + + return result; +} + //------------------------------------------------------------------------------ // fgVarNeedsExplicitZeroInit : Check whether the variable needs an explicit zero initialization. // // Arguments: -// varDsc - local var description +// varNum - local var number // bbInALoop - true if the basic block may be in a loop // bbIsReturn - true if the basic block always returns // @@ -4135,13 +4193,20 @@ inline void Compiler::CLR_API_Leave(API_ICorJitInfo_Names ename) // - compInitMem is set and the variable has a long lifetime or has gc fields. // In these cases we will insert zero-initialization in the prolog if necessary. -bool Compiler::fgVarNeedsExplicitZeroInit(LclVarDsc* varDsc, bool bbInALoop, bool bbIsReturn) +bool Compiler::fgVarNeedsExplicitZeroInit(unsigned varNum, bool bbInALoop, bool bbIsReturn) { + LclVarDsc* varDsc = lvaGetDesc(varNum); + if (bbInALoop && !bbIsReturn) { return true; } + if (fgVarIsNeverZeroInitializedInProlog(varNum)) + { + return true; + } + if (varTypeIsGC(varDsc->lvType)) { return false; diff --git a/src/coreclr/src/jit/compmemkind.h b/src/coreclr/src/jit/compmemkind.h index f680b04987d455..586e5f3ac3ca78 100644 --- a/src/coreclr/src/jit/compmemkind.h +++ b/src/coreclr/src/jit/compmemkind.h @@ -41,7 +41,7 @@ CompMemKindMacro(ArrayInfoMap) CompMemKindMacro(MemoryPhiArg) CompMemKindMacro(CSE) CompMemKindMacro(GC) -CompMemKindMacro(CorSig) +CompMemKindMacro(CorTailCallInfo) CompMemKindMacro(Inlining) CompMemKindMacro(ArrayStack) CompMemKindMacro(DebugInfo) @@ -58,6 +58,7 @@ CompMemKindMacro(VariableLiveRanges) CompMemKindMacro(ClassLayout) CompMemKindMacro(TailMergeThrows) CompMemKindMacro(EarlyProp) +CompMemKindMacro(ZeroInit) //clang-format on #undef CompMemKindMacro diff --git a/src/coreclr/src/jit/compphases.h b/src/coreclr/src/jit/compphases.h index 0cafdc1793e3ca..ccda79c4cfe794 100644 --- a/src/coreclr/src/jit/compphases.h +++ b/src/coreclr/src/jit/compphases.h @@ -55,6 +55,7 @@ CompPhaseNameMacro(PHASE_CREATE_FUNCLETS, "Create EH funclets", CompPhaseNameMacro(PHASE_MERGE_THROWS, "Merge throw blocks", "MRGTHROW", false, -1, false) CompPhaseNameMacro(PHASE_OPTIMIZE_LAYOUT, "Optimize layout", "LAYOUT", false, -1, false) CompPhaseNameMacro(PHASE_COMPUTE_REACHABILITY, "Compute blocks reachability", "BL_REACH", false, -1, false) +CompPhaseNameMacro(PHASE_ZERO_INITS, "Redundant zero Inits", "ZERO-INIT", false, -1, false) CompPhaseNameMacro(PHASE_OPTIMIZE_LOOPS, "Optimize loops", "LOOP-OPT", false, -1, false) CompPhaseNameMacro(PHASE_CLONE_LOOPS, "Clone loops", "LP-CLONE", false, -1, false) CompPhaseNameMacro(PHASE_UNROLL_LOOPS, "Unroll loops", "UNROLL", false, -1, false) diff --git a/src/coreclr/src/jit/decomposelongs.cpp b/src/coreclr/src/jit/decomposelongs.cpp index 77112049271eae..855d60813ca02a 100644 --- a/src/coreclr/src/jit/decomposelongs.cpp +++ b/src/coreclr/src/jit/decomposelongs.cpp @@ -1362,7 +1362,7 @@ GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use) GenTreeCall::Use* argList = m_compiler->gtNewCallArgs(loOp1, hiOp1, shiftByOp); - GenTree* call = m_compiler->gtNewHelperCallNode(helper, TYP_LONG, argList); + GenTreeCall* call = m_compiler->gtNewHelperCallNode(helper, TYP_LONG, argList); call->gtFlags |= shift->gtFlags & GTF_ALL_EFFECT; if (shift->IsUnusedValue()) @@ -1370,11 +1370,7 @@ GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use) call->SetUnusedValue(); } - GenTreeCall* callNode = call->AsCall(); - ReturnTypeDesc* retTypeDesc = callNode->GetReturnTypeDesc(); - retTypeDesc->InitializeLongReturnType(m_compiler); - - call = m_compiler->fgMorphArgs(callNode); + call = m_compiler->fgMorphArgs(call); Range().InsertAfter(shift, LIR::SeqTree(m_compiler, call)); Range().Remove(shift); diff --git a/src/coreclr/src/jit/emit.cpp b/src/coreclr/src/jit/emit.cpp index 9d64888407adfe..2613cd453e61a5 100644 --- a/src/coreclr/src/jit/emit.cpp +++ b/src/coreclr/src/jit/emit.cpp @@ -4622,10 +4622,18 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, } #endif - if (emitConsDsc.align16) + // This restricts the emitConsDsc.alignment to: 1, 2, 4, 8, 16, or 32 bytes + // Alignments greater than 32 would require VM support in ICorJitInfo::allocMem + assert(isPow2(emitConsDsc.alignment) && (emitConsDsc.alignment <= 32)); + + if (emitConsDsc.alignment == 16) { allocMemFlag = static_cast(allocMemFlag | CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN); } + else if (emitConsDsc.alignment == 32) + { + allocMemFlag = static_cast(allocMemFlag | CORJIT_ALLOCMEM_FLG_RODATA_32BYTE_ALIGN); + } #ifdef TARGET_ARM64 // For arm64, we want to allocate JIT data always adjacent to code similar to what native compiler does. @@ -4637,7 +4645,7 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, } UNATIVE_OFFSET roDataAlignmentDelta = 0; - if (emitConsDsc.dsdOffs) + if (emitConsDsc.dsdOffs && (emitConsDsc.alignment == TARGET_POINTER_SIZE)) { UNATIVE_OFFSET roDataAlignment = TARGET_POINTER_SIZE; // 8 Byte align by default. roDataAlignmentDelta = (UNATIVE_OFFSET)ALIGN_UP(emitTotalHotCodeSize, roDataAlignment) - emitTotalHotCodeSize; @@ -5320,49 +5328,54 @@ UNATIVE_OFFSET emitter::emitFindOffset(insGroup* ig, unsigned insNum) * block. */ -UNATIVE_OFFSET emitter::emitDataGenBeg(UNATIVE_OFFSET size, bool align) +UNATIVE_OFFSET emitter::emitDataGenBeg(UNATIVE_OFFSET size, UNATIVE_OFFSET alignment) { unsigned secOffs; dataSection* secDesc; assert(emitDataSecCur == nullptr); - /* The size better not be some kind of an odd thing */ + // The size must not be zero and must be a multiple of 4 bytes + // Additionally, 4 bytes is the minimum alignment that will + // actually be used. That is, if the user requests an alignment + // of 1 or 2, they will get something that is at least 4-byte + // aligned. We allow the others since 4 is at least 1/2 and its + // simpler to allow it than to check and block. + assert((size != 0) && ((size % 4) == 0)); - assert(size && size % sizeof(int) == 0); + // This restricts the alignment to: 1, 2, 4, 8, 16, or 32 bytes + // Alignments greater than 32 would require VM support in ICorJitInfo::allocMem - /* Get hold of the current offset */ + const size_t MaxAlignment = 32; + assert(isPow2(alignment) && (alignment <= MaxAlignment)); + /* Get hold of the current offset */ secOffs = emitConsDsc.dsdOffs; - if (align) + if (alignment > 4) { - // Data can have any size but since alignment is deduced from the size there's no - // way to have a larger data size (e.g. 128) and request 4/8/16 byte alignment. - // 32 bytes (and more) alignment requires VM support (see ICorJitInfo::allocMem). - assert(size <= 16); + // As per the above comment, the minimum alignment is actually 4 + // bytes so we don't need to make any adjustments if the requested + // alignment is 1, 2, or 4. + // + // The maximum requested alignment is tracked and the memory allocator + // will end up ensuring offset 0 is at an address matching that + // alignment. So if the requested alignment is greater than 4, we need + // to pad the space out so the offset is a multiple of the requested. - if (size == 16) - { - emitConsDsc.align16 = true; - } + uint8_t zero[MaxAlignment] = {}; - while ((secOffs % size) != 0) - { - /* Need to skip 4 bytes to honor alignment */ - /* Must allocate a dummy 4 byte integer */ - int zero = 0; - emitDataGenBeg(4, false); - emitDataGenData(0, &zero, 4); - emitDataGenEnd(); + UNATIVE_OFFSET zeroSize = alignment - (secOffs % alignment); + UNATIVE_OFFSET zeroAlign = 4; - /* Get the new secOffs */ - secOffs = emitConsDsc.dsdOffs; - } + emitAnyConst(&zero, zeroSize, zeroAlign); + secOffs = emitConsDsc.dsdOffs; } - /* Advance the current offset */ + assert((secOffs % alignment) == 0); + emitConsDsc.alignment = max(emitConsDsc.alignment, alignment); + /* Advance the current offset */ emitConsDsc.dsdOffs += size; /* Allocate a data section descriptor and add it to the list */ @@ -5450,7 +5463,7 @@ UNATIVE_OFFSET emitter::emitBBTableDataGenBeg(unsigned numEntries, bool relative * Emit the given block of bits into the current data section. */ -void emitter::emitDataGenData(unsigned offs, const void* data, size_t size) +void emitter::emitDataGenData(unsigned offs, const void* data, UNATIVE_OFFSET size) { assert(emitDataSecCur && (emitDataSecCur->dsSize >= offs + size)); @@ -5497,19 +5510,13 @@ void emitter::emitDataGenEnd() * Parameters: * cnsAddr - memory location containing constant value * cnsSize - size of constant in bytes - * dblAlign - whether to double align the data section constant + * cnsAlign - alignment of constant in bytes * * Returns constant number as offset into data section. */ -UNATIVE_OFFSET emitter::emitDataConst(const void* cnsAddr, unsigned cnsSize, bool dblAlign) +UNATIVE_OFFSET emitter::emitDataConst(const void* cnsAddr, UNATIVE_OFFSET cnsSize, UNATIVE_OFFSET cnsAlign) { - // When generating SMALL_CODE, we don't bother with dblAlign - if (dblAlign && (emitComp->compCodeOpt() == Compiler::SMALL_CODE)) - { - dblAlign = false; - } - - UNATIVE_OFFSET cnum = emitDataGenBeg(cnsSize, dblAlign); + UNATIVE_OFFSET cnum = emitDataGenBeg(cnsSize, cnsAlign); emitDataGenData(0, cnsAddr, cnsSize); emitDataGenEnd(); @@ -5521,33 +5528,18 @@ UNATIVE_OFFSET emitter::emitDataConst(const void* cnsAddr, unsigned cnsSize, boo // // Arguments: // cnsAddr - pointer to the data to be placed in the data section -// cnsSize - size of the data -// alignment - indicates how to align the constant +// cnsSize - size of the data in bytes +// cnsAlign - alignment of the data in bytes // // Return Value: // A field handle representing the data offset to access the constant. // -CORINFO_FIELD_HANDLE emitter::emitAnyConst(const void* cnsAddr, unsigned cnsSize, emitDataAlignment alignment) +CORINFO_FIELD_HANDLE emitter::emitAnyConst(const void* cnsAddr, UNATIVE_OFFSET cnsSize, UNATIVE_OFFSET cnsAlign) { - bool align; - - switch (alignment) - { - case emitDataAlignment::None: - align = false; - break; - case emitDataAlignment::Preferred: - align = (emitComp->compCodeOpt() != Compiler::SMALL_CODE); - break; - case emitDataAlignment::Required: - default: - align = true; - break; - } - - UNATIVE_OFFSET cnum = emitDataGenBeg(cnsSize, align); + UNATIVE_OFFSET cnum = emitDataGenBeg(cnsSize, cnsAlign); emitDataGenData(0, cnsAddr, cnsSize); emitDataGenEnd(); + return emitComp->eeFindJitDataOffs(cnum); } @@ -5571,26 +5563,35 @@ CORINFO_FIELD_HANDLE emitter::emitFltOrDblConst(double constValue, emitAttr attr void* cnsAddr; float f; - bool dblAlign; if (attr == EA_4BYTE) { - f = forceCastToFloat(constValue); - cnsAddr = &f; - dblAlign = false; + f = forceCastToFloat(constValue); + cnsAddr = &f; } else { - cnsAddr = &constValue; - dblAlign = true; + cnsAddr = &constValue; } // 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. - UNATIVE_OFFSET cnsSize = (attr == EA_4BYTE) ? 4 : 8; - UNATIVE_OFFSET cnum = emitDataConst(cnsAddr, cnsSize, dblAlign); + UNATIVE_OFFSET cnsSize = (attr == EA_4BYTE) ? 4 : 8; + UNATIVE_OFFSET cnsAlign = cnsSize; + +#ifdef TARGET_XARCH + if (emitComp->compCodeOpt() == Compiler::SMALL_CODE) + { + // Some platforms don't require doubles to be aligned and so + // we can use a smaller alignment to help with smaller code + + cnsAlign = 1; + } +#endif // TARGET_XARCH + + UNATIVE_OFFSET cnum = emitDataConst(cnsAddr, cnsSize, cnsAlign); return emitComp->eeFindJitDataOffs(cnum); } @@ -7517,19 +7518,16 @@ void emitter::emitRecordCallSite(ULONG instrOffset, /* IN */ // lazily obtain it here using the given method handle (we only save the sig // info when we explicitly need it, i.e. for CALLI calls, vararg calls, and // tail calls). + CORINFO_SIG_INFO sigInfo; + if (callSig == nullptr) { assert(methodHandle != nullptr); if (Compiler::eeGetHelperNum(methodHandle) == CORINFO_HELP_UNDEF) { - if (emitScratchSigInfo == nullptr) - { - emitScratchSigInfo = new (emitComp, CMK_CorSig) CORINFO_SIG_INFO; - } - - emitComp->eeGetMethodSig(methodHandle, emitScratchSigInfo); - callSig = emitScratchSigInfo; + emitComp->eeGetMethodSig(methodHandle, &sigInfo); + callSig = &sigInfo; } } diff --git a/src/coreclr/src/jit/emit.h b/src/coreclr/src/jit/emit.h index dda33e19a36bae..cd1616b37eb8c1 100644 --- a/src/coreclr/src/jit/emit.h +++ b/src/coreclr/src/jit/emit.h @@ -200,13 +200,6 @@ class emitLocation unsigned codePos; // the code position within the IG (see emitCurOffset()) }; -enum class emitDataAlignment -{ - None, - Preferred, - Required -}; - /************************************************************************/ /* The following describes an instruction group */ /************************************************************************/ @@ -1222,9 +1215,11 @@ class emitter #define PERFSCORE_THROUGHPUT_ILLEGAL -1024.0f -#define PERFSCORE_THROUGHPUT_4X 0.25f // Fastest - Quad issue -#define PERFSCORE_THROUGHPUT_3X (1.0f / 3.0f) // Faster - Three issue -#define PERFSCORE_THROUGHPUT_2X 0.5f // Faster - Dual issue +#define PERFSCORE_THROUGHPUT_6X (1.0f / 6.0f) // Hextuple issue +#define PERFSCORE_THROUGHPUT_5X 0.20f // Pentuple issue +#define PERFSCORE_THROUGHPUT_4X 0.25f // Quad issue +#define PERFSCORE_THROUGHPUT_3X (1.0f / 3.0f) // Three issue +#define PERFSCORE_THROUGHPUT_2X 0.5f // Dual issue #define PERFSCORE_THROUGHPUT_1C 1.0f // Single Issue @@ -1336,7 +1331,7 @@ class emitter insExecutionCharacteristics getInsExecutionCharacteristics(instrDesc* id); - void emitter::perfScoreUnhandledInstruction(instrDesc* id, insExecutionCharacteristics* result); + void perfScoreUnhandledInstruction(instrDesc* id, insExecutionCharacteristics* result); #endif // defined(DEBUG) || defined(LATE_DISASM) @@ -1683,7 +1678,7 @@ class emitter void emitSetMediumJump(instrDescJmp* id); public: - CORINFO_FIELD_HANDLE emitAnyConst(const void* cnsAddr, unsigned cnsSize, emitDataAlignment alignment); + CORINFO_FIELD_HANDLE emitAnyConst(const void* cnsAddr, UNATIVE_OFFSET cnsSize, UNATIVE_OFFSET cnsAlign); private: CORINFO_FIELD_HANDLE emitFltOrDblConst(double constValue, emitAttr attr); @@ -2178,9 +2173,9 @@ class emitter dataSection* dsdList; dataSection* dsdLast; UNATIVE_OFFSET dsdOffs; - bool align16; + UNATIVE_OFFSET alignment; // in bytes, defaults to 4 - dataSecDsc() : dsdList(nullptr), dsdLast(nullptr), dsdOffs(0), align16(false) + dataSecDsc() : dsdList(nullptr), dsdLast(nullptr), dsdOffs(0), alignment(4) { } }; diff --git a/src/coreclr/src/jit/emitarm64.cpp b/src/coreclr/src/jit/emitarm64.cpp index 876e5cab8d9fa3..7df6edf7ea6c49 100644 --- a/src/coreclr/src/jit/emitarm64.cpp +++ b/src/coreclr/src/jit/emitarm64.cpp @@ -604,20 +604,23 @@ void emitter::emitInsSanityCheck(instrDesc* id) break; case IF_DV_2N: // DV_2N .........iiiiiii ......nnnnnddddd Vd Vn imm (shift - scalar) - assert(id->idOpSize() == EA_8BYTE); + ins = id->idIns(); + datasize = id->idOpSize(); assert(insOptsNone(id->idInsOpt())); assert(isVectorRegister(id->idReg1())); assert(isVectorRegister(id->idReg2())); - assert(isValidImmShift(emitGetInsSC(id), EA_8BYTE)); + assert(isValidVectorShiftAmount(emitGetInsSC(id), datasize, emitInsIsVectorRightShift(ins))); break; case IF_DV_2O: // DV_2O .Q.......iiiiiii ......nnnnnddddd Vd Vn imm (shift - vector) - assert(isValidVectorDatasize(id->idOpSize())); - assert(isValidArrangement(id->idOpSize(), id->idInsOpt())); + ins = id->idIns(); + datasize = id->idOpSize(); + elemsize = optGetElemsize(id->idInsOpt()); + assert(isValidVectorDatasize(datasize)); + assert(isValidArrangement(datasize, id->idInsOpt())); assert(isVectorRegister(id->idReg1())); assert(isVectorRegister(id->idReg2())); - elemsize = optGetElemsize(id->idInsOpt()); - assert(isValidImmShift(emitGetInsSC(id), elemsize)); + assert(isValidVectorShiftAmount(emitGetInsSC(id), elemsize, emitInsIsVectorRightShift(ins))); break; case IF_DV_2B: // DV_2B .Q.........iiiii ......nnnnnddddd Rd Vn[] (umov/smov - to general) @@ -649,12 +652,13 @@ void emitter::emitInsSanityCheck(instrDesc* id) break; case IF_DV_2D: // DV_2D .Q.........iiiii ......nnnnnddddd Vd Vn[] (dup - vector) + ins = id->idIns(); datasize = id->idOpSize(); assert(isValidVectorDatasize(datasize)); assert(isValidArrangement(datasize, id->idInsOpt())); elemsize = optGetElemsize(id->idInsOpt()); index = emitGetInsSC(id); - assert(isValidVectorIndex(datasize, elemsize, index)); + assert((ins == INS_dup) || isValidVectorIndex(datasize, elemsize, index)); assert(isVectorRegister(id->idReg1())); assert(isVectorRegister(id->idReg2())); break; @@ -757,8 +761,6 @@ void emitter::emitInsSanityCheck(instrDesc* id) case IF_DV_2T: // DV_2T .Q......XX...... ......nnnnnddddd Sd Vn (addv, saddlv, smaxv, sminv, uaddlv, // umaxv, uminv) assert(isValidVectorDatasize(id->idOpSize())); - elemsize = optGetElemsize(id->idInsOpt()); - assert((elemsize != EA_8BYTE) && (id->idInsOpt() != INS_OPTS_2S)); // can't use 2D or 1D or 2S assert(isVectorRegister(id->idReg1())); assert(isVectorRegister(id->idReg2())); break; @@ -788,6 +790,7 @@ void emitter::emitInsSanityCheck(instrDesc* id) break; case IF_DV_3AI: // DV_3AI .Q......XXLMmmmm ....H.nnnnnddddd Vd Vn Vm[] (vector by elem) + case IF_DV_3HI: // DV_3HI ........XXLMmmmm ....H.nnnnnddddd Vd Vn Vm[] (smlal{2}, umlal{2} by element) assert(isValidVectorDatasize(id->idOpSize())); assert(isValidArrangement(id->idOpSize(), id->idInsOpt())); assert(isVectorRegister(id->idReg1())); @@ -818,6 +821,22 @@ void emitter::emitInsSanityCheck(instrDesc* id) break; case IF_DV_3C: // DV_3C .Q.........mmmmm ......nnnnnddddd Vd Vn Vm (vector) + switch (id->idIns()) + { + case INS_tbl: + case INS_tbl_2regs: + case INS_tbl_3regs: + case INS_tbl_4regs: + case INS_tbx: + case INS_tbx_2regs: + case INS_tbx_3regs: + case INS_tbx_4regs: + elemsize = optGetElemsize(id->idInsOpt()); + assert(elemsize == EA_1BYTE); + break; + default: + break; + } assert(isValidVectorDatasize(id->idOpSize())); assert(isValidArrangement(id->idOpSize(), id->idInsOpt())); assert(isVectorRegister(id->idReg1())); @@ -843,9 +862,8 @@ void emitter::emitInsSanityCheck(instrDesc* id) assert(isValidVectorIndex(EA_16BYTE, elemsize, emitGetInsSC(id))); break; - case IF_DV_3E: // DV_3E ...........mmmmm ......nnnnnddddd Vd Vn Vm (scalar) + case IF_DV_3E: // DV_3E ........XX.mmmmm ......nnnnnddddd Vd Vn Vm (scalar) assert(insOptsNone(id->idInsOpt())); - assert(id->idOpSize() == EA_8BYTE); assert(isVectorRegister(id->idReg1())); assert(isVectorRegister(id->idReg2())); assert(isVectorRegister(id->idReg3())); @@ -859,6 +877,23 @@ void emitter::emitInsSanityCheck(instrDesc* id) assert(isVectorRegister(id->idReg3())); break; + case IF_DV_3G: // DV_3G .Q.........mmmmm .iiii.nnnnnddddd Vd Vn Vm imm (vector) + assert(isValidVectorDatasize(id->idOpSize())); + assert(isValidArrangement(id->idOpSize(), id->idInsOpt())); + assert(isValidVectorIndex(id->idOpSize(), EA_1BYTE, emitGetInsSC(id))); + assert(isVectorRegister(id->idReg1())); + assert(isVectorRegister(id->idReg2())); + assert(isVectorRegister(id->idReg3())); + break; + + case IF_DV_3H: // DV_3H ........XX.mmmmm ......nnnnnddddd Vd Vn Vm (addhn{2}, raddhn{2}, rsubhn{2}, + // subhn{2}, pmull{2}) + assert(isValidArrangement(id->idOpSize(), id->idInsOpt())); + assert(isVectorRegister(id->idReg1())); + assert(isVectorRegister(id->idReg2())); + assert(isVectorRegister(id->idReg3())); + break; + case IF_DV_4A: // DR_4A .........X.mmmmm .aaaaannnnnddddd Rd Rn Rm Ra (scalar) assert(isValidGeneralDatasize(id->idOpSize())); assert(isVectorRegister(id->idReg1())); @@ -912,7 +947,6 @@ bool emitter::emitInsMayWriteToGCReg(instrDesc* id) case IF_DR_3C: // DR_3C X..........mmmmm xxxsssnnnnnddddd Rd Rn Rm ext(Rm) LSL imm(0-4) case IF_DR_3D: // DR_3D X..........mmmmm cccc..nnnnnddddd Rd Rn Rm cond case IF_DR_3E: // DR_3E X........X.mmmmm ssssssnnnnnddddd Rd Rn Rm imm(0-63) - case IF_DV_3F: // DV_3F ...........mmmmm ......nnnnnddddd Vd Vn Vm (vector) - Vd both source and dest case IF_DR_4A: // DR_4A X..........mmmmm .aaaaannnnnddddd Rd Rn Rm Ra @@ -946,7 +980,13 @@ bool emitter::emitInsMayWriteToGCReg(instrDesc* id) case IF_DV_3C: // DV_3C .Q.........mmmmm ......nnnnnddddd Vd Vn Vm (vector) case IF_DV_3D: // DV_3D .........X.mmmmm ......nnnnnddddd Vd Vn Vm (scalar) case IF_DV_3DI: // DV_3DI .........XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (scalar by elem) - case IF_DV_3E: // DV_3E ...........mmmmm ......nnnnnddddd Vd Vn Vm (scalar) + case IF_DV_3E: // DV_3E ........XX.mmmmm ......nnnnnddddd Vd Vn Vm (scalar) + case IF_DV_3F: // DV_3F .Q......XX.mmmmm ......nnnnnddddd Vd Vn Vm (vector) + case IF_DV_3G: // DV_3G .Q.........mmmmm .iiii.nnnnnddddd Vd Vn Vm imm (vector) + case IF_DV_3H: // DV_3H ........XX.mmmmm ......nnnnnddddd Vd Vn Vm (addhn{2}, raddhn{2}, rsubhn{2}, + // subhn{2}, pmull{2}) + case IF_DV_3HI: // DV_3HI ........XXLMmmmm ....H.nnnnnddddd Vd Vn Vm[] (smlal{2}, smlsl{2}, smull{2}, + // umlal{2}, umlsl{2}, umull{2} vector by elem) case IF_DV_4A: // DV_4A .........X.mmmmm .aaaaannnnnddddd Vd Va Vn Vm (scalar) // Tracked GC pointers cannot be placed into the SIMD registers. return false; @@ -1339,13 +1379,13 @@ emitter::insFormat emitter::emitInsFormat(instruction ins) // clang-format off const static insFormat insFormats[] = { - #define INST1(id, nm, fp, ldst, fmt, e1 ) fmt, - #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) fmt, - #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) fmt, - #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) fmt, - #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) fmt, - #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) fmt, - #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) fmt, + #define INST1(id, nm, info, fmt, e1 ) fmt, + #define INST2(id, nm, info, fmt, e1, e2 ) fmt, + #define INST3(id, nm, info, fmt, e1, e2, e3 ) fmt, + #define INST4(id, nm, info, fmt, e1, e2, e3, e4 ) fmt, + #define INST5(id, nm, info, fmt, e1, e2, e3, e4, e5 ) fmt, + #define INST6(id, nm, info, fmt, e1, e2, e3, e4, e5, e6 ) fmt, + #define INST9(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) fmt, #include "instrs.h" }; // clang-format on @@ -1356,76 +1396,81 @@ emitter::insFormat emitter::emitInsFormat(instruction ins) return insFormats[ins]; } -// INST_FP is 1 -#define LD 2 -#define ST 4 -#define CMP 8 +#define LD 1 +#define ST 2 +#define CMP 4 +#define RSH 8 // clang-format off /*static*/ const BYTE CodeGenInterface::instInfo[] = { - #define INST1(id, nm, fp, ldst, fmt, e1 ) ldst | INST_FP*fp, - #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) ldst | INST_FP*fp, - #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) ldst | INST_FP*fp, - #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) ldst | INST_FP*fp, - #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) ldst | INST_FP*fp, - #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) ldst | INST_FP*fp, - #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) ldst | INST_FP*fp, + #define INST1(id, nm, info, fmt, e1 ) info, + #define INST2(id, nm, info, fmt, e1, e2 ) info, + #define INST3(id, nm, info, fmt, e1, e2, e3 ) info, + #define INST4(id, nm, info, fmt, e1, e2, e3, e4 ) info, + #define INST5(id, nm, info, fmt, e1, e2, e3, e4, e5 ) info, + #define INST6(id, nm, info, fmt, e1, e2, e3, e4, e5, e6 ) info, + #define INST9(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) info, #include "instrs.h" }; // clang-format on -/***************************************************************************** - * - * Returns true if the instruction is some kind of compare or test instruction - */ - +//------------------------------------------------------------------------ +// emitInsIsCompare: Returns true if the instruction is some kind of compare or test instruction. +// bool emitter::emitInsIsCompare(instruction ins) { // We have pseudo ins like lea which are not included in emitInsLdStTab. if (ins < ArrLen(CodeGenInterface::instInfo)) - return (CodeGenInterface::instInfo[ins] & CMP) ? true : false; + return (CodeGenInterface::instInfo[ins] & CMP) != 0; else return false; } -/***************************************************************************** - * - * Returns true if the instruction is some kind of load instruction - */ - +//------------------------------------------------------------------------ +// emitInsIsLoad: Returns true if the instruction is some kind of load instruction. +// bool emitter::emitInsIsLoad(instruction ins) { // We have pseudo ins like lea which are not included in emitInsLdStTab. if (ins < ArrLen(CodeGenInterface::instInfo)) - return (CodeGenInterface::instInfo[ins] & LD) ? true : false; + return (CodeGenInterface::instInfo[ins] & LD) != 0; else return false; } -/***************************************************************************** - * - * Returns true if the instruction is some kind of store instruction - */ +//------------------------------------------------------------------------ +// emitInsIsStore: Returns true if the instruction is some kind of store instruction. +// bool emitter::emitInsIsStore(instruction ins) { // We have pseudo ins like lea which are not included in emitInsLdStTab. if (ins < ArrLen(CodeGenInterface::instInfo)) - return (CodeGenInterface::instInfo[ins] & ST) ? true : false; + return (CodeGenInterface::instInfo[ins] & ST) != 0; else return false; } -/***************************************************************************** - * - * Returns true if the instruction is some kind of load/store instruction - */ - +//------------------------------------------------------------------------ +// emitInsIsLoadOrStore: Returns true if the instruction is some kind of load or store instruction. +// bool emitter::emitInsIsLoadOrStore(instruction ins) { // We have pseudo ins like lea which are not included in emitInsLdStTab. if (ins < ArrLen(CodeGenInterface::instInfo)) - return (CodeGenInterface::instInfo[ins] & (LD | ST)) ? true : false; + return (CodeGenInterface::instInfo[ins] & (LD | ST)) != 0; + else + return false; +} + +//------------------------------------------------------------------------ +// emitInsIsVectorRightShift: Returns true if the instruction is ASIMD right shift. +// +bool emitter::emitInsIsVectorRightShift(instruction ins) +{ + // We have pseudo ins like lea which are not included in emitInsLdStTab. + if (ins < ArrLen(CodeGenInterface::instInfo)) + return (CodeGenInterface::instInfo[ins] & RSH) != 0; else return false; } @@ -1433,6 +1478,7 @@ bool emitter::emitInsIsLoadOrStore(instruction ins) #undef LD #undef ST #undef CMP +#undef RHS /***************************************************************************** * @@ -1444,101 +1490,101 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) // clang-format off const static code_t insCodes1[] = { - #define INST1(id, nm, fp, ldst, fmt, e1 ) e1, - #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) e1, - #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) e1, - #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) e1, - #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) e1, - #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) e1, - #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e1, + #define INST1(id, nm, info, fmt, e1 ) e1, + #define INST2(id, nm, info, fmt, e1, e2 ) e1, + #define INST3(id, nm, info, fmt, e1, e2, e3 ) e1, + #define INST4(id, nm, info, fmt, e1, e2, e3, e4 ) e1, + #define INST5(id, nm, info, fmt, e1, e2, e3, e4, e5 ) e1, + #define INST6(id, nm, info, fmt, e1, e2, e3, e4, e5, e6 ) e1, + #define INST9(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e1, #include "instrs.h" }; const static code_t insCodes2[] = { - #define INST1(id, nm, fp, ldst, fmt, e1 ) - #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) e2, - #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) e2, - #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) e2, - #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) e2, - #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) e2, - #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e2, + #define INST1(id, nm, info, fmt, e1 ) + #define INST2(id, nm, info, fmt, e1, e2 ) e2, + #define INST3(id, nm, info, fmt, e1, e2, e3 ) e2, + #define INST4(id, nm, info, fmt, e1, e2, e3, e4 ) e2, + #define INST5(id, nm, info, fmt, e1, e2, e3, e4, e5 ) e2, + #define INST6(id, nm, info, fmt, e1, e2, e3, e4, e5, e6 ) e2, + #define INST9(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e2, #include "instrs.h" }; const static code_t insCodes3[] = { - #define INST1(id, nm, fp, ldst, fmt, e1 ) - #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) - #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) e3, - #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) e3, - #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) e3, - #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) e3, - #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e3, + #define INST1(id, nm, info, fmt, e1 ) + #define INST2(id, nm, info, fmt, e1, e2 ) + #define INST3(id, nm, info, fmt, e1, e2, e3 ) e3, + #define INST4(id, nm, info, fmt, e1, e2, e3, e4 ) e3, + #define INST5(id, nm, info, fmt, e1, e2, e3, e4, e5 ) e3, + #define INST6(id, nm, info, fmt, e1, e2, e3, e4, e5, e6 ) e3, + #define INST9(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e3, #include "instrs.h" }; const static code_t insCodes4[] = { - #define INST1(id, nm, fp, ldst, fmt, e1 ) - #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) - #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) - #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) e4, - #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) e4, - #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) e4, - #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e4, + #define INST1(id, nm, info, fmt, e1 ) + #define INST2(id, nm, info, fmt, e1, e2 ) + #define INST3(id, nm, info, fmt, e1, e2, e3 ) + #define INST4(id, nm, info, fmt, e1, e2, e3, e4 ) e4, + #define INST5(id, nm, info, fmt, e1, e2, e3, e4, e5 ) e4, + #define INST6(id, nm, info, fmt, e1, e2, e3, e4, e5, e6 ) e4, + #define INST9(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e4, #include "instrs.h" }; const static code_t insCodes5[] = { - #define INST1(id, nm, fp, ldst, fmt, e1 ) - #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) - #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) - #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) - #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) e5, - #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) e5, - #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e5, + #define INST1(id, nm, info, fmt, e1 ) + #define INST2(id, nm, info, fmt, e1, e2 ) + #define INST3(id, nm, info, fmt, e1, e2, e3 ) + #define INST4(id, nm, info, fmt, e1, e2, e3, e4 ) + #define INST5(id, nm, info, fmt, e1, e2, e3, e4, e5 ) e5, + #define INST6(id, nm, info, fmt, e1, e2, e3, e4, e5, e6 ) e5, + #define INST9(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e5, #include "instrs.h" }; const static code_t insCodes6[] = { - #define INST1(id, nm, fp, ldst, fmt, e1 ) - #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) - #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) - #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) - #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) - #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) e6, - #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e6, + #define INST1(id, nm, info, fmt, e1 ) + #define INST2(id, nm, info, fmt, e1, e2 ) + #define INST3(id, nm, info, fmt, e1, e2, e3 ) + #define INST4(id, nm, info, fmt, e1, e2, e3, e4 ) + #define INST5(id, nm, info, fmt, e1, e2, e3, e4, e5 ) + #define INST6(id, nm, info, fmt, e1, e2, e3, e4, e5, e6 ) e6, + #define INST9(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e6, #include "instrs.h" }; const static code_t insCodes7[] = { - #define INST1(id, nm, fp, ldst, fmt, e1 ) - #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) - #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) - #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) - #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) - #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) - #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e7, + #define INST1(id, nm, info, fmt, e1 ) + #define INST2(id, nm, info, fmt, e1, e2 ) + #define INST3(id, nm, info, fmt, e1, e2, e3 ) + #define INST4(id, nm, info, fmt, e1, e2, e3, e4 ) + #define INST5(id, nm, info, fmt, e1, e2, e3, e4, e5 ) + #define INST6(id, nm, info, fmt, e1, e2, e3, e4, e5, e6 ) + #define INST9(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e7, #include "instrs.h" }; const static code_t insCodes8[] = { - #define INST1(id, nm, fp, ldst, fmt, e1 ) - #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) - #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) - #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) - #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) - #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) - #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e8, + #define INST1(id, nm, info, fmt, e1 ) + #define INST2(id, nm, info, fmt, e1, e2 ) + #define INST3(id, nm, info, fmt, e1, e2, e3 ) + #define INST4(id, nm, info, fmt, e1, e2, e3, e4 ) + #define INST5(id, nm, info, fmt, e1, e2, e3, e4, e5 ) + #define INST6(id, nm, info, fmt, e1, e2, e3, e4, e5, e6 ) + #define INST9(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e8, #include "instrs.h" }; const static code_t insCodes9[] = { - #define INST1(id, nm, fp, ldst, fmt, e1 ) - #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) - #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) - #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) - #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) - #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) - #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e9, + #define INST1(id, nm, info, fmt, e1 ) + #define INST2(id, nm, info, fmt, e1, e2 ) + #define INST3(id, nm, info, fmt, e1, e2, e3 ) + #define INST4(id, nm, info, fmt, e1, e2, e3, e4 ) + #define INST5(id, nm, info, fmt, e1, e2, e3, e4, e5 ) + #define INST6(id, nm, info, fmt, e1, e2, e3, e4, e5, e6 ) + #define INST9(id, nm, info, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) e9, #include "instrs.h" }; // clang-format on @@ -1559,6 +1605,7 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) const static insFormat formatEncode4G[4] = {IF_DR_2E, IF_DR_2F, IF_DV_2M, IF_DV_2L}; const static insFormat formatEncode4H[4] = {IF_DV_3E, IF_DV_3A, IF_DV_2L, IF_DV_2M}; const static insFormat formatEncode4I[4] = {IF_DV_3D, IF_DV_3B, IF_DV_2G, IF_DV_2A}; + const static insFormat formatEncode4J[4] = {IF_DV_2N, IF_DV_2O, IF_DV_3E, IF_DV_3A}; const static insFormat formatEncode3A[3] = {IF_DR_3A, IF_DR_3B, IF_DI_2C}; const static insFormat formatEncode3B[3] = {IF_DR_2A, IF_DR_2B, IF_DI_1C}; const static insFormat formatEncode3C[3] = {IF_DR_3A, IF_DR_3B, IF_DV_3C}; @@ -1569,6 +1616,7 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) const static insFormat formatEncode3H[3] = {IF_DR_3A, IF_DV_3A, IF_DV_3AI}; const static insFormat formatEncode3I[3] = {IF_DR_2E, IF_DR_2F, IF_DV_2M}; const static insFormat formatEncode3J[3] = {IF_LS_2D, IF_LS_3F, IF_LS_2E}; + const static insFormat formatEncode3K[3] = {IF_DR_3A, IF_DV_3H, IF_DV_3HI}; const static insFormat formatEncode2A[2] = {IF_DR_2E, IF_DR_2F}; const static insFormat formatEncode2B[2] = {IF_DR_3A, IF_DR_3B}; const static insFormat formatEncode2C[2] = {IF_DR_3A, IF_DI_2D}; @@ -1586,6 +1634,7 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) const static insFormat formatEncode2O[2] = {IF_DV_3E, IF_DV_3A}; const static insFormat formatEncode2P[2] = {IF_DV_2Q, IF_DV_3B}; const static insFormat formatEncode2Q[2] = {IF_DV_2S, IF_DV_3A}; + const static insFormat formatEncode2R[2] = {IF_DV_3H, IF_DV_3HI}; code_t code = BAD_CODE; insFormat insFmt = emitInsFormat(ins); @@ -1759,6 +1808,17 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) } break; + case IF_EN4J: + for (index = 0; index < 4; index++) + { + if (fmt == formatEncode4J[index]) + { + encoding_found = true; + break; + } + } + break; + case IF_EN3A: for (index = 0; index < 3; index++) { @@ -1869,6 +1929,17 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) } break; + case IF_EN3K: + for (index = 0; index < 3; index++) + { + if (fmt == formatEncode3K[index]) + { + encoding_found = true; + break; + } + } + break; + case IF_EN2A: for (index = 0; index < 2; index++) { @@ -2056,91 +2127,27 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) } break; - case IF_BI_0A: - case IF_BI_0B: - case IF_BI_0C: - case IF_BI_1A: - case IF_BI_1B: - case IF_BR_1A: - case IF_BR_1B: - case IF_LS_1A: - case IF_LS_2A: - case IF_LS_2B: - case IF_LS_2C: - case IF_LS_3A: - case IF_LS_3B: - case IF_LS_3C: - case IF_LS_3D: - case IF_LS_3E: - case IF_DI_1A: - case IF_DI_1B: - case IF_DI_1C: - case IF_DI_1D: - case IF_DI_1E: - case IF_DI_1F: - case IF_DI_2A: - case IF_DI_2B: - case IF_DI_2C: - case IF_DI_2D: - case IF_DR_1D: - case IF_DR_2A: - case IF_DR_2B: - case IF_DR_2C: - case IF_DR_2D: - case IF_DR_2E: - case IF_DR_2F: - case IF_DR_2G: - case IF_DR_2H: - case IF_DR_2I: - case IF_DR_3A: - case IF_DR_3B: - case IF_DR_3C: - case IF_DR_3D: - case IF_DR_3E: - case IF_DR_4A: - case IF_DV_1A: - case IF_DV_1B: - case IF_DV_1C: - case IF_DV_2A: - case IF_DV_2B: - case IF_DV_2C: - case IF_DV_2D: - case IF_DV_2E: - case IF_DV_2F: - case IF_DV_2G: - case IF_DV_2H: - case IF_DV_2I: - case IF_DV_2J: - case IF_DV_2K: - case IF_DV_2L: - case IF_DV_2M: - case IF_DV_2N: - case IF_DV_2O: - case IF_DV_2P: - case IF_DV_2R: - case IF_DV_2T: - case IF_DV_2U: - case IF_DV_3A: - case IF_DV_3AI: - case IF_DV_3B: - case IF_DV_3BI: - case IF_DV_3C: - case IF_DV_3D: - case IF_DV_3DI: - case IF_DV_3E: - case IF_DV_3F: - case IF_DV_4A: - case IF_SN_0A: - case IF_SI_0A: - case IF_SI_0B: - - index = 0; - encoding_found = true; + case IF_EN2R: + for (index = 0; index < 2; index++) + { + if (fmt == formatEncode2R[index]) + { + encoding_found = true; + break; + } + } break; default: - - encoding_found = false; + if (fmt == insFmt) + { + encoding_found = true; + index = 0; + } + else + { + encoding_found = false; + } break; } @@ -2879,12 +2886,11 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) * 'size' specifies the size of the result (16 or 32 bits) */ -/*static*/ INT32 emitter::emitDecodeByteShiftedImm(const emitter::byteShiftedImm bsImm, emitAttr size) +/*static*/ UINT32 emitter::emitDecodeByteShiftedImm(const emitter::byteShiftedImm bsImm, emitAttr size) { bool onesShift = (bsImm.immOnes == 1); - unsigned bySh = bsImm.immBY; // Num Bytes to shift 0,1,2,3 - INT32 val = (INT32)bsImm.immVal; // 8-bit immediate - INT32 result = val; + unsigned bySh = bsImm.immBY; // Num Bytes to shift 0,1,2,3 + UINT32 result = (UINT32)bsImm.immVal; // 8-bit immediate if (bySh > 0) { @@ -3244,15 +3250,16 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) } //------------------------------------------------------------------------ -// insGetLoadStoreRegisterListSize: Returns a size of the register list a given instruction operates on. +// insGetRegisterListSize: Returns a size of the register list a given instruction operates on. // // Arguments: -// ins - A Load/Store Vector instruction (e.g. ld1 (2 registers), ld1r, st1). +// ins - An instruction which uses a register list +// (e.g. ld1 (2 registers), ld1r, st1, tbl, tbx). // // Return value: // A number of consecutive SIMD and floating-point registers the instruction loads to/store from. // -/*static*/ unsigned emitter::insGetLoadStoreRegisterListSize(instruction ins) +/*static*/ unsigned emitter::insGetRegisterListSize(instruction ins) { unsigned registerListSize = 0; @@ -3261,6 +3268,8 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) case INS_ld1: case INS_ld1r: case INS_st1: + case INS_tbl: + case INS_tbx: registerListSize = 1; break; @@ -3269,6 +3278,8 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) case INS_ld2r: case INS_st1_2regs: case INS_st2: + case INS_tbl_2regs: + case INS_tbx_2regs: registerListSize = 2; break; @@ -3277,6 +3288,8 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) case INS_ld3r: case INS_st1_3regs: case INS_st3: + case INS_tbl_3regs: + case INS_tbx_3regs: registerListSize = 3; break; @@ -3285,6 +3298,8 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) case INS_ld4r: case INS_st1_4regs: case INS_st4: + case INS_tbl_4regs: + case INS_tbx_4regs: registerListSize = 4; break; @@ -3370,6 +3385,48 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt) } } +// For the given 'srcArrangement' returns the "widen" 'dstArrangement' specifying the destination vector register +// arrangement +// asserts and returns INS_OPTS_NONE if an invalid 'srcArrangement' value is passed +// +/*static*/ insOpts emitter::optWidenDstArrangement(insOpts srcArrangement) +{ + insOpts dstArrangement = INS_OPTS_NONE; + + switch (srcArrangement) + { + case INS_OPTS_8B: + dstArrangement = INS_OPTS_4H; + break; + + case INS_OPTS_16B: + dstArrangement = INS_OPTS_8H; + break; + + case INS_OPTS_4H: + dstArrangement = INS_OPTS_2S; + break; + + case INS_OPTS_8H: + dstArrangement = INS_OPTS_4S; + break; + + case INS_OPTS_2S: + dstArrangement = INS_OPTS_1D; + break; + + case INS_OPTS_4S: + dstArrangement = INS_OPTS_2D; + break; + + default: + assert(!" invalid 'srcArrangement' value"); + break; + } + + return dstArrangement; +} + // For the given 'conversion' returns the 'dstsize' specified by the conversion option /*static*/ emitAttr emitter::optGetDstsize(insOpts conversion) { @@ -4357,15 +4414,21 @@ void emitter::emitIns_R_R( break; case INS_fcvtl: - case INS_fcvtl2: case INS_fcvtn: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(size == EA_8BYTE); + assert((opt == INS_OPTS_4H) || (opt == INS_OPTS_2S)); + fmt = IF_DV_2A; + break; + + case INS_fcvtl2: case INS_fcvtn2: assert(isVectorRegister(reg1)); assert(isVectorRegister(reg2)); - assert(isValidVectorDatasize(size)); - assert(insOptsNone(opt)); - assert(size == EA_8BYTE); // Narrowing from Double or Widening to Double (Half not supported) - fmt = IF_DV_2G; + assert(size == EA_16BYTE); + assert((opt == INS_OPTS_8H) || (opt == INS_OPTS_4S)); + fmt = IF_DV_2A; break; case INS_scvtf: @@ -4608,6 +4671,17 @@ void emitter::emitIns_R_R( fmt = IF_DV_2G; break; + case INS_sadalp: + case INS_saddlp: + case INS_uadalp: + case INS_uaddlp: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isValidArrangement(size, opt)); + assert((opt != INS_OPTS_1D) && (opt != INS_OPTS_2D)); // The encoding size = 11, Q = x is reserved + fmt = IF_DV_2T; + break; + default: unreached(); break; @@ -4750,6 +4824,7 @@ void emitter::emitIns_R_R_I( bool canEncode; bitMaskImm bmi; unsigned registerListSize; + bool isRightShift; case INS_mov: // Check for the 'mov' aliases for the vector registers @@ -4803,19 +4878,21 @@ void emitter::emitIns_R_R_I( fmt = IF_DI_2B; break; - case INS_sshr: - case INS_ssra: + case INS_shl: + case INS_sli: + case INS_sri: case INS_srshr: case INS_srsra: - case INS_shl: - case INS_ushr: - case INS_usra: + case INS_sshr: + case INS_ssra: case INS_urshr: case INS_ursra: - case INS_sri: - case INS_sli: + case INS_ushr: + case INS_usra: assert(isVectorRegister(reg1)); assert(isVectorRegister(reg2)); + isRightShift = emitInsIsVectorRightShift(ins); + if (insOptsAnyArrangement(opt)) { // Vector operation @@ -4823,7 +4900,7 @@ void emitter::emitIns_R_R_I( assert(isValidArrangement(size, opt)); elemsize = optGetElemsize(opt); assert(isValidVectorElemsize(elemsize)); - assert(isValidImmShift(imm, elemsize)); + assert(isValidVectorShiftAmount(imm, elemsize, isRightShift)); assert(opt != INS_OPTS_1D); // Reserved encoding fmt = IF_DV_2O; break; @@ -4833,7 +4910,63 @@ void emitter::emitIns_R_R_I( // Scalar operation assert(insOptsNone(opt)); assert(size == EA_8BYTE); // only supported size - assert(isValidImmShift(imm, size)); + assert(isValidVectorShiftAmount(imm, size, isRightShift)); + fmt = IF_DV_2N; + } + break; + + case INS_sqshl: + case INS_uqshl: + case INS_sqshlu: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + isRightShift = emitInsIsVectorRightShift(ins); + + if (insOptsAnyArrangement(opt)) + { + // Vector operation + assert(isValidArrangement(size, opt)); + assert(opt != INS_OPTS_1D); // The encoding immh = 1xxx, Q = 0 is reserved + elemsize = optGetElemsize(opt); + assert(isValidVectorShiftAmount(imm, elemsize, isRightShift)); + fmt = IF_DV_2O; + } + else + { + // Scalar operation + assert(insOptsNone(opt)); + assert(isValidVectorElemsize(size)); + assert(isValidVectorShiftAmount(imm, size, isRightShift)); + fmt = IF_DV_2N; + } + break; + + case INS_sqrshrn: + case INS_sqrshrun: + case INS_sqshrn: + case INS_sqshrun: + case INS_uqrshrn: + case INS_uqshrn: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + isRightShift = emitInsIsVectorRightShift(ins); + + if (insOptsAnyArrangement(opt)) + { + // Vector operation + assert(isValidArrangement(size, opt)); + assert((opt != INS_OPTS_1D) && (opt != INS_OPTS_2D)); // The encoding immh = 1xxx, Q = x is reserved + elemsize = optGetElemsize(opt); + assert(isValidVectorShiftAmount(imm, elemsize, isRightShift)); + fmt = IF_DV_2O; + } + else + { + // Scalar operation + assert(insOptsNone(opt)); + assert(isValidVectorElemsize(size)); + assert(size != EA_8BYTE); // The encoding immh = 1xxx is reserved + assert(isValidVectorShiftAmount(imm, size, isRightShift)); fmt = IF_DV_2N; } break; @@ -4843,19 +4976,20 @@ void emitter::emitIns_R_R_I( assert(imm == 0); __fallthrough; - case INS_shrn: case INS_rshrn: + case INS_shrn: case INS_sshll: case INS_ushll: assert(isVectorRegister(reg1)); assert(isVectorRegister(reg2)); + isRightShift = emitInsIsVectorRightShift(ins); // Vector operation assert(size == EA_8BYTE); assert(isValidArrangement(size, opt)); elemsize = optGetElemsize(opt); assert(elemsize != EA_8BYTE); // Reserved encodings assert(isValidVectorElemsize(elemsize)); - assert(isValidImmShift(imm, elemsize)); + assert(isValidVectorShiftAmount(imm, elemsize, isRightShift)); fmt = IF_DV_2O; break; @@ -4864,19 +4998,27 @@ void emitter::emitIns_R_R_I( assert(imm == 0); __fallthrough; - case INS_shrn2: case INS_rshrn2: + case INS_shrn2: + case INS_sqrshrn2: + case INS_sqrshrun2: + case INS_sqshrn2: + case INS_sqshrun2: case INS_sshll2: + case INS_uqrshrn2: + case INS_uqshrn2: case INS_ushll2: assert(isVectorRegister(reg1)); assert(isVectorRegister(reg2)); + isRightShift = emitInsIsVectorRightShift(ins); + // Vector operation assert(size == EA_16BYTE); assert(isValidArrangement(size, opt)); elemsize = optGetElemsize(opt); - assert(elemsize != EA_8BYTE); // Reserved encodings + assert(elemsize != EA_8BYTE); // The encoding immh = 1xxx, Q = x is reserved assert(isValidVectorElemsize(elemsize)); - assert(isValidImmShift(imm, elemsize)); + assert(isValidVectorShiftAmount(imm, elemsize, isRightShift)); fmt = IF_DV_2O; break; @@ -4985,12 +5127,17 @@ void emitter::emitIns_R_R_I( { if (insOptsAnyArrangement(opt)) { + // The size and opt were modified to be based on the + // return type but the immediate is based on the operand + // which can be of a larger size. As such, we don't + // assert the index is valid here and instead do it in + // codegen. + // Vector operation assert(isValidVectorDatasize(size)); assert(isValidArrangement(size, opt)); elemsize = optGetElemsize(opt); assert(isValidVectorElemsize(elemsize)); - assert(isValidVectorIndex(size, elemsize, imm)); assert(opt != INS_OPTS_1D); // Reserved encoding fmt = IF_DV_2D; break; @@ -5170,7 +5317,7 @@ void emitter::emitIns_R_R_I( if (insOptsAnyArrangement(opt)) { - registerListSize = insGetLoadStoreRegisterListSize(ins); + registerListSize = insGetRegisterListSize(ins); assert(isValidVectorDatasize(size)); assert(isValidArrangement(size, opt)); assert((size * registerListSize) == imm); @@ -5204,7 +5351,7 @@ void emitter::emitIns_R_R_I( assert(isValidArrangement(size, opt)); elemsize = optGetElemsize(opt); - registerListSize = insGetLoadStoreRegisterListSize(ins); + registerListSize = insGetRegisterListSize(ins); assert((elemsize * registerListSize) == imm); // Load single structure and replicate post-indexed by an immediate @@ -5421,6 +5568,30 @@ void emitter::emitIns_R_R_R( /* Figure out the encoding format of the instruction */ switch (ins) { + case INS_mul: + case INS_smull: + case INS_umull: + if (insOptsAnyArrangement(opt)) + { + // ASIMD instruction + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(isValidArrangement(size, opt)); + assert((opt != INS_OPTS_1D) && (opt != INS_OPTS_2D)); // The encoding size = 11, Q = x is reserved + if (ins == INS_mul) + { + fmt = IF_DV_3A; + } + else + { + fmt = IF_DV_3H; + } + break; + } + // Base instruction + __fallthrough; + case INS_lsl: case INS_lsr: case INS_asr: @@ -5432,10 +5603,8 @@ void emitter::emitIns_R_R_R( case INS_udiv: case INS_sdiv: case INS_mneg: - case INS_smull: case INS_smnegl: case INS_smulh: - case INS_umull: case INS_umnegl: case INS_umulh: case INS_lslv: @@ -5458,44 +5627,11 @@ void emitter::emitIns_R_R_R( fmt = IF_DR_3A; break; - case INS_mul: - if (insOptsNone(opt)) - { - // general register - assert(isValidGeneralDatasize(size)); - assert(isGeneralRegister(reg1)); - assert(isGeneralRegister(reg2)); - assert(isGeneralRegister(reg3)); - fmt = IF_DR_3A; - break; - } - __fallthrough; - - case INS_mla: - case INS_mls: - case INS_pmul: - assert(insOptsAnyArrangement(opt)); - assert(isVectorRegister(reg1)); - assert(isVectorRegister(reg2)); - assert(isVectorRegister(reg3)); - assert(isValidVectorDatasize(size)); - assert(isValidArrangement(size, opt)); - elemsize = optGetElemsize(opt); - if (ins == INS_pmul) - { - assert(elemsize == EA_1BYTE); // only supports 8B or 16B - } - else // INS_mul, INS_mla, INS_mls - { - assert(elemsize != EA_8BYTE); // can't use 2D or 1D - } - fmt = IF_DV_3A; - break; - case INS_add: case INS_sub: if (isVectorRegister(reg1)) { + // ASIMD instruction assert(isVectorRegister(reg2)); assert(isVectorRegister(reg3)); @@ -5516,6 +5652,7 @@ void emitter::emitIns_R_R_R( } break; } + // Base instruction __fallthrough; case INS_adds: @@ -5529,6 +5666,10 @@ void emitter::emitIns_R_R_R( case INS_cmhi: case INS_cmhs: case INS_cmtst: + case INS_srshl: + case INS_sshl: + case INS_urshl: + case INS_ushl: assert(isVectorRegister(reg1)); assert(isVectorRegister(reg2)); assert(isVectorRegister(reg3)); @@ -5536,10 +5677,8 @@ void emitter::emitIns_R_R_R( if (insOptsAnyArrangement(opt)) { // Vector operation - assert(isValidVectorDatasize(size)); assert(isValidArrangement(size, opt)); - elemsize = optGetElemsize(opt); - assert(opt != INS_OPTS_1D); // Reserved encoding + assert(opt != INS_OPTS_1D); // The encoding size = 11, Q = 0 is reserved fmt = IF_DV_3A; } else @@ -5551,6 +5690,34 @@ void emitter::emitIns_R_R_R( } break; + case INS_sqadd: + case INS_sqrshl: + case INS_sqshl: + case INS_sqsub: + case INS_uqadd: + case INS_uqrshl: + case INS_uqshl: + case INS_uqsub: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isVectorRegister(reg3)); + + if (insOptsAnyArrangement(opt)) + { + // Vector operation + assert(isValidArrangement(size, opt)); + assert(opt != INS_OPTS_1D); // The encoding size = 11, Q = 0 is reserved + fmt = IF_DV_3A; + } + else + { + // Scalar operation + assert(insOptsNone(opt)); + assert(isValidVectorElemsize(size)); + fmt = IF_DV_3E; + } + break; + case INS_fcmeq: case INS_fcmge: case INS_fcmgt: @@ -5579,20 +5746,33 @@ void emitter::emitIns_R_R_R( } break; + case INS_mla: + case INS_mls: case INS_saba: case INS_sabd: + case INS_shadd: + case INS_shsub: case INS_smax: case INS_smaxp: case INS_smin: case INS_sminp: + case INS_srhadd: case INS_uaba: case INS_uabd: + case INS_uhadd: + case INS_uhsub: case INS_umax: case INS_umaxp: case INS_umin: case INS_uminp: - assert(elemsize != EA_8BYTE); // can't use 2D or 1D - __fallthrough; + case INS_urhadd: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(isValidArrangement(size, opt)); + assert((opt != INS_OPTS_1D) && (opt != INS_OPTS_2D)); // The encoding size = 11, Q = x is reserved + fmt = IF_DV_3A; + break; case INS_addp: case INS_uzp1: @@ -5604,13 +5784,8 @@ void emitter::emitIns_R_R_R( assert(isVectorRegister(reg1)); assert(isVectorRegister(reg2)); assert(isVectorRegister(reg3)); - assert(insOptsAnyArrangement(opt)); - - // Vector operation - assert(isValidVectorDatasize(size)); assert(isValidArrangement(size, opt)); - elemsize = optGetElemsize(opt); - + assert(opt != INS_OPTS_1D); // The encoding size = 11, Q = 0 is reserved fmt = IF_DV_3A; break; @@ -5634,6 +5809,14 @@ void emitter::emitIns_R_R_R( case INS_eor: case INS_orr: case INS_orn: + case INS_tbl: + case INS_tbl_2regs: + case INS_tbl_3regs: + case INS_tbl_4regs: + case INS_tbx: + case INS_tbx_2regs: + case INS_tbx_3regs: + case INS_tbx_4regs: if (isVectorRegister(reg1)) { assert(isValidVectorDatasize(size)); @@ -5864,6 +6047,109 @@ void emitter::emitIns_R_R_R( fmt = IF_LS_3F; break; + case INS_addhn: + case INS_raddhn: + case INS_rsubhn: + case INS_subhn: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(size == EA_8BYTE); + assert(isValidArrangement(size, opt)); + assert(opt != INS_OPTS_1D); // The encoding size = 11, Q = x is reserved. + fmt = IF_DV_3H; + break; + + case INS_addhn2: + case INS_raddhn2: + case INS_rsubhn2: + case INS_subhn2: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(size == EA_16BYTE); + assert(isValidArrangement(size, opt)); + assert(opt != INS_OPTS_2D); // The encoding size = 11, Q = x is reserved. + fmt = IF_DV_3H; + break; + + case INS_sabal: + case INS_sabdl: + case INS_saddl: + case INS_saddw: + case INS_smlal: + case INS_smlsl: + case INS_ssubl: + case INS_ssubw: + case INS_uabal: + case INS_uabdl: + case INS_uaddl: + case INS_uaddw: + case INS_umlal: + case INS_umlsl: + case INS_usubl: + case INS_usubw: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(size == EA_8BYTE); + assert((opt == INS_OPTS_8B) || (opt == INS_OPTS_4H) || (opt == INS_OPTS_2S)); + fmt = IF_DV_3H; + break; + + case INS_sabal2: + case INS_sabdl2: + case INS_saddl2: + case INS_saddw2: + case INS_smlal2: + case INS_smlsl2: + case INS_ssubl2: + case INS_ssubw2: + case INS_umlal2: + case INS_umlsl2: + case INS_smull2: + case INS_uabal2: + case INS_uabdl2: + case INS_uaddl2: + case INS_uaddw2: + case INS_usubl2: + case INS_umull2: + case INS_usubw2: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(size == EA_16BYTE); + assert((opt == INS_OPTS_16B) || (opt == INS_OPTS_8H) || (opt == INS_OPTS_4S)); + fmt = IF_DV_3H; + break; + + case INS_pmul: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(isValidArrangement(size, opt)); + assert((opt == INS_OPTS_8B) || (opt == INS_OPTS_16B)); + fmt = IF_DV_3A; + break; + + case INS_pmull: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(size == EA_8BYTE); + assert((opt == INS_OPTS_8B) || (opt == INS_OPTS_1D)); + fmt = IF_DV_3H; + break; + + case INS_pmull2: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(size == EA_16BYTE); + assert((opt == INS_OPTS_16B) || (opt == INS_OPTS_2D)); + fmt = IF_DV_3H; + break; + default: unreached(); break; @@ -6058,6 +6344,49 @@ void emitter::emitIns_R_R_R_I(instruction ins, fmt = IF_LS_3G; break; + case INS_ext: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(isValidVectorDatasize(size)); + assert(isValidArrangement(size, opt)); + assert((opt == INS_OPTS_8B) || (opt == INS_OPTS_16B)); + assert(isValidVectorIndex(size, EA_1BYTE, imm)); + fmt = IF_DV_3G; + break; + + case INS_smlal: + case INS_smlsl: + case INS_smull: + case INS_umlal: + case INS_umlsl: + case INS_umull: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(size == EA_8BYTE); + assert((opt == INS_OPTS_4H) || (opt == INS_OPTS_2S)); + elemsize = optGetElemsize(opt); + assert(isValidVectorIndex(EA_16BYTE, elemsize, imm)); + fmt = IF_DV_3HI; + break; + + case INS_smlal2: + case INS_smlsl2: + case INS_smull2: + case INS_umlal2: + case INS_umlsl2: + case INS_umull2: + assert(isVectorRegister(reg1)); + assert(isVectorRegister(reg2)); + assert(isVectorRegister(reg3)); + assert(size == EA_16BYTE); + assert((opt == INS_OPTS_8H) || (opt == INS_OPTS_4S)); + elemsize = optGetElemsize(opt); + assert(isValidVectorIndex(EA_16BYTE, elemsize, imm)); + fmt = IF_DV_3HI; + break; + default: unreached(); break; @@ -6424,7 +6753,7 @@ void emitter::emitIns_R_R_I_I( assert(isValidVectorElemsize(elemsize)); assert(isValidVectorIndex(EA_16BYTE, elemsize, imm1)); - registerListSize = insGetLoadStoreRegisterListSize(ins); + registerListSize = insGetRegisterListSize(ins); assert((elemsize * registerListSize) == (unsigned)imm2); assert(insOptsPostIndex(opt)); @@ -7322,7 +7651,7 @@ void emitter::emitIns_R_C( fmt = IF_LARGELDC; if (isVectorRegister(reg)) { - assert(isValidScalarDatasize(size)); + assert(isValidVectorLSDatasize(size)); // For vector (float/double) register, we should have an integer address reg to // compute long address which consists of page address and page offset. // For integer constant, this is not needed since the dest reg can be used to @@ -7335,6 +7664,7 @@ void emitter::emitIns_R_C( assert(isValidGeneralDatasize(size)); } break; + default: unreached(); } @@ -8527,18 +8857,33 @@ void emitter::emitIns_Call(EmitCallType callType, return bits; } -/***************************************************************************** - * - * Returns the encoding to shift by 'shift' for an Arm64 vector or scalar instruction - */ - -/*static*/ emitter::code_t emitter::insEncodeVectorShift(emitAttr size, ssize_t shift) +// insEncodeVectorShift: Returns the encoding for the SIMD shift (immediate) instructions. +// +// Arguments: +// size - for the scalar variants specifies 'datasize', for the vector variants specifies 'element size'. +// shift - if the shift is positive, the operation is a left shift. Otherwise, it is a right shift. +// +// Returns: +// "immh:immb" field of the instruction that contains encoded shift amount. +// +/*static*/ emitter::code_t emitter::insEncodeVectorShift(emitAttr size, ssize_t shiftAmount) { - assert(shift < getBitWidth(size)); - - code_t imm = (code_t)(getBitWidth(size) + shift); + if (shiftAmount < 0) + { + shiftAmount = -shiftAmount; + // The right shift amount must be in the range 1 to the destination element width in bits. + assert((shiftAmount > 0) && (shiftAmount <= getBitWidth(size))); - return imm << 16; + code_t imm = (code_t)(2 * getBitWidth(size) - shiftAmount); + return imm << 16; + } + else + { + // The left shift amount must in the range 0 to the element width in bits minus 1. + assert(shiftAmount < getBitWidth(size)); + code_t imm = (code_t)(getBitWidth(size) + shiftAmount); + return imm << 16; + } } /***************************************************************************** @@ -10368,9 +10713,25 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) elemsize = optGetElemsize(id->idInsOpt()); code = emitInsCode(ins, fmt); code |= insEncodeVectorsize(id->idOpSize()); // Q - code |= insEncodeFloatElemsize(elemsize); // X - code |= insEncodeReg_Vd(id->idReg1()); // ddddd - code |= insEncodeReg_Vn(id->idReg2()); // nnnnn + if ((ins == INS_fcvtl) || (ins == INS_fcvtl2) || (ins == INS_fcvtn) || (ins == INS_fcvtn2)) + { + // fcvtl{2} and fcvtn{2} encode the element size as + // esize = 16 << UInt(sz) + if (elemsize == EA_4BYTE) + { + code |= 0x00400000; // X + } + else + { + assert(elemsize == EA_2BYTE); + } + } + else + { + code |= insEncodeFloatElemsize(elemsize); // X + } + code |= insEncodeReg_Vd(id->idReg1()); // ddddd + code |= insEncodeReg_Vn(id->idReg2()); // nnnnn dst += emitOutput_Instr(dst, code); break; @@ -10511,11 +10872,12 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) break; case IF_DV_2N: // DV_2N .........iiiiiii ......nnnnnddddd Vd Vn imm (shift - scalar) - imm = emitGetInsSC(id); - code = emitInsCode(ins, fmt); - code |= insEncodeVectorShift(EA_8BYTE, imm); // iiiiiii - code |= insEncodeReg_Vd(id->idReg1()); // ddddd - code |= insEncodeReg_Vn(id->idReg2()); // nnnnn + imm = emitGetInsSC(id); + elemsize = id->idOpSize(); + code = emitInsCode(ins, fmt); + code |= insEncodeVectorShift(elemsize, emitInsIsVectorRightShift(ins) ? -imm : imm); // iiiiiii + code |= insEncodeReg_Vd(id->idReg1()); // ddddd + code |= insEncodeReg_Vn(id->idReg2()); // nnnnn dst += emitOutput_Instr(dst, code); break; @@ -10523,10 +10885,10 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) imm = emitGetInsSC(id); elemsize = optGetElemsize(id->idInsOpt()); code = emitInsCode(ins, fmt); - code |= insEncodeVectorsize(id->idOpSize()); // Q - code |= insEncodeVectorShift(elemsize, imm); // iiiiiii - code |= insEncodeReg_Vd(id->idReg1()); // ddddd - code |= insEncodeReg_Vn(id->idReg2()); // nnnnn + code |= insEncodeVectorsize(id->idOpSize()); // Q + code |= insEncodeVectorShift(elemsize, emitInsIsVectorRightShift(ins) ? -imm : imm); // iiiiiii + code |= insEncodeReg_Vd(id->idReg1()); // ddddd + code |= insEncodeReg_Vn(id->idReg2()); // nnnnn dst += emitOutput_Instr(dst, code); break; @@ -10645,7 +11007,16 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) dst += emitOutput_Instr(dst, code); break; - case IF_DV_3E: // DV_3E ...........mmmmm ......nnnnnddddd Vd Vn Vm (scalar) + case IF_DV_3E: // DV_3E ........XX.mmmmm ......nnnnnddddd Vd Vn Vm (scalar) + code = emitInsCode(ins, fmt); + elemsize = id->idOpSize(); + code |= insEncodeElemsize(elemsize); // XX + code |= insEncodeReg_Vd(id->idReg1()); // ddddd + code |= insEncodeReg_Vn(id->idReg2()); // nnnnn + code |= insEncodeReg_Vm(id->idReg3()); // mmmmm + dst += emitOutput_Instr(dst, code); + break; + case IF_DV_3F: // DV_3F ...........mmmmm ......nnnnnddddd Vd Vn Vm (vector) - source dest regs overlap code = emitInsCode(ins, fmt); code |= insEncodeReg_Vd(id->idReg1()); // ddddd @@ -10654,6 +11025,41 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) dst += emitOutput_Instr(dst, code); break; + case IF_DV_3G: // DV_3G .Q.........mmmmm .iiii.nnnnnddddd Vd Vn Vm imm (vector) + imm = emitGetInsSC(id); + code = emitInsCode(ins, fmt); + code |= insEncodeVectorsize(id->idOpSize()); // Q + code |= insEncodeReg_Vm(id->idReg3()); // mmmmm + code |= ((code_t)imm << 11); // iiii + code |= insEncodeReg_Vn(id->idReg2()); // nnnnn + code |= insEncodeReg_Vd(id->idReg1()); // ddddd + dst += emitOutput_Instr(dst, code); + break; + + case IF_DV_3H: // DV_3H ........XX.mmmmm ......nnnnnddddd Vd Vn Vm (addhn{2}, raddhn{2}, rsubhn{2}, + // subhn{2}, pmull{2}) + code = emitInsCode(ins, fmt); + elemsize = optGetElemsize(id->idInsOpt()); + code |= insEncodeElemsize(elemsize); // XX + code |= insEncodeReg_Vm(id->idReg3()); // mmmmm + code |= insEncodeReg_Vn(id->idReg2()); // nnnnn + code |= insEncodeReg_Vd(id->idReg1()); // ddddd + dst += emitOutput_Instr(dst, code); + break; + + case IF_DV_3HI: // DV_3HI ........XXLMmmmm ....H.nnnnnddddd Vd Vn Vm[] (smlal{2}, umlal{2} by element) + code = emitInsCode(ins, fmt); + imm = emitGetInsSC(id); + elemsize = optGetElemsize(id->idInsOpt()); + assert(isValidVectorIndex(EA_16BYTE, elemsize, imm)); + code |= insEncodeElemsize(elemsize); // XX + code |= insEncodeVectorIndexLMH(elemsize, imm); // LM H + code |= insEncodeReg_Vd(id->idReg1()); // ddddd + code |= insEncodeReg_Vn(id->idReg2()); // nnnnn + code |= insEncodeReg_Vm(id->idReg3()); // mmmmm + dst += emitOutput_Instr(dst, code); + break; + case IF_DV_4A: // DV_4A .........X.mmmmm .aaaaannnnnddddd Vd Va Vn Vm (scalar) code = emitInsCode(ins, fmt); elemsize = id->idOpSize(); @@ -11652,7 +12058,7 @@ void emitter::emitDispIns( case IF_LS_2D: // LS_2D .Q.............. ....ssnnnnnttttt Vt Rn case IF_LS_2E: // LS_2E .Q.............. ....ssnnnnnttttt Vt Rn - registerListSize = insGetLoadStoreRegisterListSize(id->idIns()); + registerListSize = insGetRegisterListSize(id->idIns()); emitDispVectorRegList(id->idReg1(), registerListSize, id->idInsOpt(), true); if (fmt == IF_LS_2D) @@ -11671,7 +12077,7 @@ void emitter::emitDispIns( case IF_LS_2F: // LS_2F .Q.............. xx.Sssnnnnnttttt Vt[] Rn case IF_LS_2G: // LS_2G .Q.............. xx.Sssnnnnnttttt Vt[] Rn - registerListSize = insGetLoadStoreRegisterListSize(id->idIns()); + registerListSize = insGetRegisterListSize(id->idIns()); elemsize = id->idOpSize(); emitDispVectorElemList(id->idReg1(), registerListSize, elemsize, id->idSmallCns(), true); @@ -11735,7 +12141,7 @@ void emitter::emitDispIns( case IF_LS_3F: // LS_3F .Q.........mmmmm ....ssnnnnnttttt Vt Rn Rm case IF_LS_3G: // LS_3G .Q.........mmmmm ...Sssnnnnnttttt Vt[] Rn Rm - registerListSize = insGetLoadStoreRegisterListSize(id->idIns()); + registerListSize = insGetRegisterListSize(id->idIns()); if (fmt == IF_LS_3F) { @@ -11922,8 +12328,19 @@ void emitter::emitDispIns( break; case IF_DR_2H: // DR_2H X........X...... ......nnnnnddddd Rd Rn - emitDispReg(id->idReg1(), size, true); - emitDispReg(id->idReg2(), size, false); + if ((ins == INS_uxtb) || (ins == INS_uxth)) + { + // There is no 64-bit variant of uxtb and uxth + // However, we allow idOpSize() to have EA_8BYTE value for these instruction + emitDispReg(id->idReg1(), EA_4BYTE, true); + emitDispReg(id->idReg2(), EA_4BYTE, false); + } + else + { + emitDispReg(id->idReg1(), size, true); + // sxtb, sxth and sxtb always operate on 32-bit source register + emitDispReg(id->idReg2(), EA_4BYTE, false); + } break; case IF_DR_2I: // DR_2I X..........mmmmm cccc..nnnnn.nzcv Rn Rm nzcv cond @@ -12063,6 +12480,23 @@ void emitter::emitDispIns( break; case IF_DV_2A: // DV_2A .Q.......X...... ......nnnnnddddd Vd Vn (fabs, fcvt - vector) + if ((ins == INS_fcvtl) || (ins == INS_fcvtl2)) + { + emitDispVectorReg(id->idReg1(), optWidenElemsize(id->idInsOpt()), true); + emitDispVectorReg(id->idReg2(), id->idInsOpt(), false); + } + else if ((ins == INS_fcvtn) || (ins == INS_fcvtn2)) + { + emitDispVectorReg(id->idReg1(), id->idInsOpt(), true); + emitDispVectorReg(id->idReg2(), optWidenElemsize(id->idInsOpt()), false); + } + else + { + emitDispVectorReg(id->idReg1(), id->idInsOpt(), true); + emitDispVectorReg(id->idReg2(), id->idInsOpt(), false); + } + break; + case IF_DV_2P: // DV_2P ................ ......nnnnnddddd Vd Vn (aes*, sha1su1) emitDispVectorReg(id->idReg1(), id->idInsOpt(), true); emitDispVectorReg(id->idReg2(), id->idInsOpt(), false); @@ -12203,9 +12637,24 @@ void emitter::emitDispIns( case IF_DV_2S: // DV_2S ........XX...... ......nnnnnddddd Sd Vn (addp - scalar) case IF_DV_2T: // DV_2T .Q......XX...... ......nnnnnddddd Sd Vn (addv, saddlv, smaxv, sminv, uaddlv, // umaxv, uminv) - elemsize = optGetElemsize(id->idInsOpt()); - emitDispReg(id->idReg1(), elemsize, true); - emitDispVectorReg(id->idReg2(), id->idInsOpt(), false); + if ((ins == INS_sadalp) || (ins == INS_saddlp) || (ins == INS_uadalp) || (ins == INS_uaddlp)) + { + emitDispVectorReg(id->idReg1(), optWidenDstArrangement(id->idInsOpt()), true); + emitDispVectorReg(id->idReg2(), id->idInsOpt(), false); + } + else + { + if ((ins == INS_saddlv) || (ins == INS_uaddlv)) + { + elemsize = optGetElemsize(optWidenDstArrangement(id->idInsOpt())); + } + else + { + elemsize = optGetElemsize(id->idInsOpt()); + } + emitDispReg(id->idReg1(), elemsize, true); + emitDispVectorReg(id->idReg2(), id->idInsOpt(), false); + } break; case IF_DV_3A: // DV_3A .Q......XX.mmmmm ......nnnnnddddd Vd Vn Vm (vector) @@ -12217,9 +12666,24 @@ void emitter::emitDispIns( case IF_DV_3C: // DV_3C .Q.........mmmmm ......nnnnnddddd Vd Vn Vm (vector) emitDispVectorReg(id->idReg1(), id->idInsOpt(), true); - if (ins != INS_mov) + switch (ins) { - emitDispVectorReg(id->idReg2(), id->idInsOpt(), true); + case INS_tbl: + case INS_tbl_2regs: + case INS_tbl_3regs: + case INS_tbl_4regs: + case INS_tbx: + case INS_tbx_2regs: + case INS_tbx_3regs: + case INS_tbx_4regs: + registerListSize = insGetRegisterListSize(ins); + emitDispVectorRegList(id->idReg2(), registerListSize, INS_OPTS_16B, true); + break; + case INS_mov: + break; + default: + emitDispVectorReg(id->idReg2(), id->idInsOpt(), true); + break; } emitDispVectorReg(id->idReg3(), id->idInsOpt(), false); break; @@ -12233,7 +12697,7 @@ void emitter::emitDispIns( break; case IF_DV_3D: // DV_3D .........X.mmmmm ......nnnnnddddd Vd Vn Vm (scalar) - case IF_DV_3E: // DV_3E ...........mmmmm ......nnnnnddddd Vd Vn Vm (scalar) + case IF_DV_3E: // DV_3E ........XX.mmmmm ......nnnnnddddd Vd Vn Vm (scalar) emitDispReg(id->idReg1(), size, true); emitDispReg(id->idReg2(), size, true); emitDispReg(id->idReg3(), size, false); @@ -12270,6 +12734,59 @@ void emitter::emitDispIns( emitDispVectorRegIndex(id->idReg3(), elemsize, emitGetInsSC(id), false); break; + case IF_DV_3G: // DV_3G .Q.........mmmmm .iiii.nnnnnddddd Vd Vn Vm imm (vector) + emitDispVectorReg(id->idReg1(), id->idInsOpt(), true); + emitDispVectorReg(id->idReg2(), id->idInsOpt(), true); + emitDispVectorReg(id->idReg3(), id->idInsOpt(), true); + emitDispImm(emitGetInsSC(id), false); + break; + + case IF_DV_3H: // DV_3H ........XX.mmmmm ......nnnnnddddd Vd Vn Vm (addhn{2}, raddhn{2}, rsubhn{2}, + // subhn{2}, pmull{2}) + if ((ins == INS_addhn) || (ins == INS_addhn2) || (ins == INS_raddhn) || (ins == INS_raddhn2) || + (ins == INS_subhn) || (ins == INS_subhn2) || (ins == INS_rsubhn) || (ins == INS_rsubhn2)) + { + // These are "high narrow" instruction i.e. their source registers are "wider" than the destination + // register. + emitDispVectorReg(id->idReg1(), id->idInsOpt(), true); + emitDispVectorReg(id->idReg2(), optWidenElemsize(id->idInsOpt()), true); + emitDispVectorReg(id->idReg3(), optWidenElemsize(id->idInsOpt()), false); + } + else + { + if (((ins == INS_pmull) && (id->idInsOpt() == INS_OPTS_1D)) || + (ins == (INS_pmull2) && (id->idInsOpt() == INS_OPTS_2D))) + { + // PMULL Vd.1Q, Vn.1D, Vm.1D + // PMULL2 Vd.1Q, Vn.2D, Vm.2D + printf("%s.1q, ", emitVectorRegName(id->idReg1())); + } + else + { + emitDispVectorReg(id->idReg1(), optWidenElemsize(id->idInsOpt()), true); + } + + if ((ins == INS_saddw) || (ins == INS_saddw2) || (ins == INS_uaddw) || (ins == INS_uaddw2) || + (ins == INS_ssubw) || (ins == INS_ssubw2) || (ins == INS_usubw) || (ins == INS_usubw2)) + { + emitDispVectorReg(id->idReg2(), optWidenElemsize(id->idInsOpt()), true); + } + else + { + emitDispVectorReg(id->idReg2(), id->idInsOpt(), true); + } + + emitDispVectorReg(id->idReg3(), id->idInsOpt(), false); + } + break; + + case IF_DV_3HI: + emitDispVectorReg(id->idReg1(), optWidenElemsize(id->idInsOpt()), true); + emitDispVectorReg(id->idReg2(), id->idInsOpt(), true); + elemsize = optGetElemsize(id->idInsOpt()); + emitDispVectorRegIndex(id->idReg3(), elemsize, emitGetInsSC(id), false); + break; + case IF_DV_4A: // DV_4A .........X.mmmmm .aaaaannnnnddddd Vd Va Vn Vm (scalar) emitDispReg(id->idReg1(), size, true); emitDispReg(id->idReg2(), size, true); @@ -12361,7 +12878,7 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR if (addr->isContained()) { - assert(addr->OperGet() == GT_LCL_VAR_ADDR || addr->OperGet() == GT_LEA); + assert(addr->OperGet() == GT_CLS_VAR_ADDR || addr->OperGet() == GT_LCL_VAR_ADDR || addr->OperGet() == GT_LEA); int offset = 0; DWORD lsl = 0; @@ -12438,7 +12955,13 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR } else // no Index register { - if (emitIns_valid_imm_for_ldst_offset(offset, emitTypeSize(indir->TypeGet()))) + if (addr->OperGet() == GT_CLS_VAR_ADDR) + { + // Get a temp integer register to compute long address. + regNumber addrReg = indir->GetSingleTempReg(); + emitIns_R_C(ins, attr, dataReg, addrReg, addr->AsClsVar()->gtClsVarHnd, 0); + } + else if (emitIns_valid_imm_for_ldst_offset(offset, emitTypeSize(indir->TypeGet()))) { // Then load/store dataReg from/to [memBase + offset] emitIns_R_R_I(ins, attr, dataReg, memBase->GetRegNum(), offset); @@ -12896,6 +13419,16 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins result.insLatency = PERFSCORE_LATENCY_1C; break; + case INS_smaddl: + case INS_smsubl: + case INS_smnegl: + case INS_umaddl: + case INS_umsubl: + case INS_umnegl: + result.insThroughput = PERFSCORE_THROUGHPUT_2X; + result.insLatency = PERFSCORE_LATENCY_3C; + break; + default: // all other instructions perfScoreUnhandledInstruction(id, &result); @@ -13557,6 +14090,14 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins result.insLatency = PERFSCORE_LATENCY_2C; break; + case INS_fcvtl: + case INS_fcvtl2: + case INS_fcvtn: + case INS_fcvtn2: + result.insThroughput = PERFSCORE_THROUGHPUT_1C; + result.insLatency = PERFSCORE_LATENCY_4C; + break; + default: // all other instructions perfScoreUnhandledInstruction(id, &result); @@ -13609,14 +14150,6 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins result.insLatency = PERFSCORE_LATENCY_2C; break; - case INS_fcvtl: - case INS_fcvtl2: - case INS_fcvtn: - case INS_fcvtn2: - result.insThroughput = PERFSCORE_THROUGHPUT_1C; - result.insLatency = PERFSCORE_LATENCY_4C; - break; - case INS_frecpe: case INS_frecpx: case INS_frsqrte: @@ -13831,9 +14364,48 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins } break; - case IF_DV_3C: // mov,and, bic, eor, mov,mvn, orn, bsl, bit, bif (vector) - result.insThroughput = PERFSCORE_THROUGHPUT_2X; - result.insLatency = PERFSCORE_LATENCY_1C; + case IF_DV_3C: // mov,and, bic, eor, mov,mvn, orn, bsl, bit, bif, + // tbl, tbx (vector) + switch (ins) + { + case INS_tbl: + result.insThroughput = PERFSCORE_THROUGHPUT_2X; + result.insLatency = PERFSCORE_LATENCY_1C; + break; + case INS_tbl_2regs: + result.insThroughput = PERFSCORE_THROUGHPUT_3X; + result.insLatency = PERFSCORE_LATENCY_2C; + break; + case INS_tbl_3regs: + result.insThroughput = PERFSCORE_THROUGHPUT_4X; + result.insLatency = PERFSCORE_LATENCY_3C; + break; + case INS_tbl_4regs: + result.insThroughput = PERFSCORE_THROUGHPUT_3X; + result.insLatency = PERFSCORE_LATENCY_4C; + break; + case INS_tbx: + result.insThroughput = PERFSCORE_THROUGHPUT_3X; + result.insLatency = PERFSCORE_LATENCY_2C; + break; + case INS_tbx_2regs: + result.insThroughput = PERFSCORE_THROUGHPUT_4X; + result.insLatency = PERFSCORE_LATENCY_3C; + break; + case INS_tbx_3regs: + result.insThroughput = PERFSCORE_THROUGHPUT_5X; + result.insLatency = PERFSCORE_LATENCY_4C; + break; + case INS_tbx_4regs: + result.insThroughput = PERFSCORE_THROUGHPUT_6X; + result.insLatency = PERFSCORE_LATENCY_5C; + break; + default: + // All other instructions + result.insThroughput = PERFSCORE_THROUGHPUT_2X; + result.insLatency = PERFSCORE_LATENCY_1C; + break; + } break; case IF_DV_2E: // mov, dup (scalar) @@ -13881,6 +14453,11 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins case INS_cmgt: case INS_cmhi: case INS_cmhs: + case INS_shadd: + case INS_shsub: + case INS_srhadd: + case INS_srshl: + case INS_sshl: case INS_smax: case INS_smaxp: case INS_smin: @@ -13889,6 +14466,11 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins case INS_umaxp: case INS_umin: case INS_uminp: + case INS_uhadd: + case INS_uhsub: + case INS_urhadd: + case INS_urshl: + case INS_ushl: case INS_uzp1: case INS_uzp2: case INS_zip1: @@ -13915,7 +14497,11 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins case INS_cmtst: case INS_pmul: case INS_sabd: + case INS_sqadd: + case INS_sqsub: case INS_uabd: + case INS_uqadd: + case INS_uqsub: result.insThroughput = PERFSCORE_THROUGHPUT_2X; result.insLatency = PERFSCORE_LATENCY_3C; break; @@ -13923,6 +14509,10 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins case INS_mul: case INS_mla: case INS_mls: + case INS_sqshl: + case INS_sqrshl: + case INS_uqrshl: + case INS_uqshl: result.insThroughput = PERFSCORE_THROUGHPUT_2X; result.insLatency = PERFSCORE_LATENCY_4C; break; @@ -13950,6 +14540,11 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins result.insLatency = PERFSCORE_LATENCY_2C; break; + case IF_DV_3G: // ext + result.insThroughput = PERFSCORE_THROUGHPUT_2X; + result.insLatency = PERFSCORE_LATENCY_2C; + break; + case IF_DV_2L: // abs, neg, cmeq, cmge, cmgt, cmle, cmlt (scalar) case IF_DV_2M: // (vector) // abs, neg, mvn, not, cmeq, cmge, cmgt, cmle, cmlt, @@ -14048,9 +14643,52 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins case INS_rshrn: case INS_rshrn2: case INS_srshr: + case INS_sqshrn: + case INS_sqshrn2: + case INS_ssra: case INS_urshr: - result.insThroughput = PERFSCORE_THROUGHPUT_2X; - result.insLatency = PERFSCORE_LATENCY_3C; + case INS_uqshrn: + case INS_uqshrn2: + case INS_usra: + if (id->idOpSize() == EA_16BYTE) + { + result.insThroughput = PERFSCORE_THROUGHPUT_1C; + result.insLatency = PERFSCORE_LATENCY_3C; + } + else + { + result.insThroughput = PERFSCORE_THROUGHPUT_2X; + result.insLatency = PERFSCORE_LATENCY_3C; + } + break; + + case INS_srsra: + case INS_ursra: + result.insThroughput = PERFSCORE_THROUGHPUT_2C; + result.insLatency = PERFSCORE_LATENCY_4C; + break; + + case INS_sqrshrn: + case INS_sqrshrn2: + case INS_sqrshrun: + case INS_sqrshrun2: + case INS_sqshrun: + case INS_sqshrun2: + case INS_sqshl: + case INS_sqshlu: + case INS_uqrshrn: + case INS_uqrshrn2: + case INS_uqshl: + if (id->idOpSize() == EA_16BYTE) + { + result.insThroughput = PERFSCORE_THROUGHPUT_1C; + result.insLatency = PERFSCORE_LATENCY_4C; + } + else + { + result.insThroughput = PERFSCORE_THROUGHPUT_2X; + result.insLatency = PERFSCORE_LATENCY_4C; + } break; default: @@ -14095,6 +14733,90 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins } break; + case IF_DV_3H: // addhn{2}, raddhn{2}, rsubhn{2}, sabal{2}, sabdl{2}, saddl{2}, saddw{2}, ssubl{2}, ssubw{2}, + // pmull{2} + case IF_DV_3HI: // subhn{2}, uabal{2}, uabdl{2}, uaddl{2}, uaddw{2}, usubl{2}, usubw{2} + switch (ins) + { + case INS_addhn: + case INS_addhn2: + case INS_sabdl: + case INS_sabdl2: + case INS_saddl: + case INS_saddl2: + case INS_saddw: + case INS_saddw2: + case INS_ssubl: + case INS_ssubl2: + case INS_ssubw: + case INS_ssubw2: + case INS_subhn: + case INS_subhn2: + case INS_uabdl: + case INS_uabdl2: + case INS_uaddl: + case INS_uaddl2: + case INS_uaddw: + case INS_uaddw2: + case INS_usubl: + case INS_usubl2: + case INS_usubw: + case INS_usubw2: + result.insThroughput = PERFSCORE_THROUGHPUT_1C; + result.insLatency = PERFSCORE_LATENCY_3C; + break; + + case INS_raddhn: + case INS_raddhn2: + case INS_rsubhn: + case INS_rsubhn2: + case INS_sabal: + case INS_sabal2: + case INS_uabal: + case INS_uabal2: + result.insThroughput = PERFSCORE_THROUGHPUT_2C; + result.insLatency = PERFSCORE_LATENCY_4C; + break; + + case INS_smlal: + case INS_smlal2: + case INS_smlsl: + case INS_smlsl2: + case INS_smull: + case INS_smull2: + case INS_umlal: + case INS_umlal2: + case INS_umlsl: + case INS_umlsl2: + case INS_umull: + case INS_umull2: + result.insThroughput = PERFSCORE_THROUGHPUT_1C; + result.insLatency = PERFSCORE_LATENCY_4C; + break; + + case INS_pmull: + case INS_pmull2: + if ((id->idInsOpt() == INS_OPTS_8B) || (id->idInsOpt() == INS_OPTS_16B)) + { + result.insThroughput = PERFSCORE_THROUGHPUT_1C; + result.insLatency = PERFSCORE_LATENCY_3C; + } + else + { + // Crypto polynomial (64x64) multiply long + assert((id->idInsOpt() == INS_OPTS_1D) || (id->idInsOpt() == INS_OPTS_2D)); + result.insThroughput = PERFSCORE_THROUGHPUT_1C; + result.insLatency = PERFSCORE_LATENCY_2C; + } + break; + + default: + // all other instructions + perfScoreUnhandledInstruction(id, &result); + break; + } + break; + case IF_SI_0A: // brk imm16 result.insThroughput = PERFSCORE_THROUGHPUT_1C; result.insLatency = PERFSCORE_LATENCY_1C; @@ -14120,6 +14842,18 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins result.insLatency = PERFSCORE_LATENCY_4C; break; + case INS_sadalp: + case INS_uadalp: + result.insThroughput = PERFSCORE_THROUGHPUT_2C; + result.insLatency = PERFSCORE_LATENCY_4C; + break; + + case INS_saddlp: + case INS_uaddlp: + result.insThroughput = PERFSCORE_THROUGHPUT_2X; + result.insLatency = PERFSCORE_LATENCY_3C; + break; + default: // all other instructions perfScoreUnhandledInstruction(id, &result); diff --git a/src/coreclr/src/jit/emitarm64.h b/src/coreclr/src/jit/emitarm64.h index f6286a6062360a..9c365c005d1fd4 100644 --- a/src/coreclr/src/jit/emitarm64.h +++ b/src/coreclr/src/jit/emitarm64.h @@ -87,6 +87,7 @@ bool emitInsIsCompare(instruction ins); bool emitInsIsLoad(instruction ins); bool emitInsIsStore(instruction ins); bool emitInsIsLoadOrStore(instruction ins); +bool emitInsIsVectorRightShift(instruction ins); emitAttr emitInsTargetRegSize(instrDesc* id); emitAttr emitInsLoadStoreSize(instrDesc* id); @@ -187,7 +188,7 @@ union byteShiftedImm { static emitter::byteShiftedImm emitEncodeByteShiftedImm(INT64 imm, emitAttr size, bool allow_MSL); -static INT32 emitDecodeByteShiftedImm(const emitter::byteShiftedImm bsImm, emitAttr size); +static UINT32 emitDecodeByteShiftedImm(const emitter::byteShiftedImm bsImm, emitAttr size); /************************************************************************ * @@ -300,8 +301,8 @@ static code_t insEncodeVectorIndex2(emitAttr elemsize, ssize_t index2); // Returns the encoding to select 'index' for an Arm64 'mul' elem instruction static code_t insEncodeVectorIndexLMH(emitAttr elemsize, ssize_t index); -// Returns the encoding to shift by 'shift' bits for an Arm64 vector or scalar instruction -static code_t insEncodeVectorShift(emitAttr size, ssize_t shift); +// Returns the encoding for ASIMD Shift instruction. +static code_t insEncodeVectorShift(emitAttr size, ssize_t shiftAmount); // Returns the encoding to select the 1/2/4/8 byte elemsize for an Arm64 vector instruction static code_t insEncodeElemsize(emitAttr size); @@ -438,6 +439,11 @@ static emitAttr optGetElemsize(insOpts arrangement); // For the given 'arrangement' returns the 'widen-arrangement' specified by the vector register arrangement static insOpts optWidenElemsize(insOpts arrangement); +// For the given 'srcArrangement' returns the "widen" 'dstArrangement' specifying the destination vector register +// arrangement +// of Long Pairwise instructions. Note that destination vector elements twice as long as the source vector elements. +static insOpts optWidenDstArrangement(insOpts srcArrangement); + // For the given 'conversion' returns the 'dstsize' specified by the conversion option static emitAttr optGetDstsize(insOpts conversion); @@ -448,9 +454,9 @@ static emitAttr optGetSrcsize(insOpts conversion); // for an element of size 'elemsize' in a vector register of size 'datasize' static bool isValidVectorIndex(emitAttr datasize, emitAttr elemsize, ssize_t index); -// For a given Load/Store Vector instruction 'ins' returns a number of consecutive SIMD registers -// the instruction loads to/store from. -static unsigned insGetLoadStoreRegisterListSize(instruction ins); +// For a given instruction 'ins' which contains a register lists returns a +// number of consecutive SIMD registers the instruction loads to/store from. +static unsigned insGetRegisterListSize(instruction ins); /************************************************************************/ /* Public inline informational methods */ @@ -512,6 +518,13 @@ inline static unsigned isValidImmShift(ssize_t imm, emitAttr size) return (imm >= 0) && (imm < getBitWidth(size)); } +// Returns true if the 'shiftAmount' represents a valid shift for the given 'size'. +inline static unsigned isValidVectorShiftAmount(ssize_t shiftAmount, emitAttr size, bool rightShift) +{ + return (rightShift && (shiftAmount >= 1) && (shiftAmount <= getBitWidth(size))) || + ((shiftAmount >= 0) && (shiftAmount < getBitWidth(size))); +} + inline static bool isValidGeneralDatasize(emitAttr size) { return (size == EA_8BYTE) || (size == EA_4BYTE); diff --git a/src/coreclr/src/jit/emitfmtsarm64.h b/src/coreclr/src/jit/emitfmtsarm64.h index 3717868c6176a9..c39f85d99ae697 100644 --- a/src/coreclr/src/jit/emitfmtsarm64.h +++ b/src/coreclr/src/jit/emitfmtsarm64.h @@ -61,6 +61,7 @@ IF_DEF(EN4F, IS_NONE, NONE) // Instruction has 4 possible encoding types, type F IF_DEF(EN4G, IS_NONE, NONE) // Instruction has 4 possible encoding types, type G IF_DEF(EN4H, IS_NONE, NONE) // Instruction has 4 possible encoding types, type H IF_DEF(EN4I, IS_NONE, NONE) // Instruction has 4 possible encoding types, type I +IF_DEF(EN4J, IS_NONE, NONE) // Instruction has 3 possible encoding types, type J IF_DEF(EN3A, IS_NONE, NONE) // Instruction has 3 possible encoding types, type A IF_DEF(EN3B, IS_NONE, NONE) // Instruction has 3 possible encoding types, type B IF_DEF(EN3C, IS_NONE, NONE) // Instruction has 3 possible encoding types, type C @@ -71,6 +72,7 @@ IF_DEF(EN3G, IS_NONE, NONE) // Instruction has 3 possible encoding types, type G IF_DEF(EN3H, IS_NONE, NONE) // Instruction has 3 possible encoding types, type H IF_DEF(EN3I, IS_NONE, NONE) // Instruction has 3 possible encoding types, type I IF_DEF(EN3J, IS_NONE, NONE) // Instruction has 3 possible encoding types, type J +IF_DEF(EN3K, IS_NONE, NONE) // Instruction has 3 possible encoding types, type K IF_DEF(EN2A, IS_NONE, NONE) // Instruction has 2 possible encoding types, type A IF_DEF(EN2B, IS_NONE, NONE) // Instruction has 2 possible encoding types, type B IF_DEF(EN2C, IS_NONE, NONE) // Instruction has 2 possible encoding types, type C @@ -88,6 +90,7 @@ IF_DEF(EN2N, IS_NONE, NONE) // Instruction has 2 possible encoding types, type N IF_DEF(EN2O, IS_NONE, NONE) // Instruction has 2 possible encoding types, type O IF_DEF(EN2P, IS_NONE, NONE) // Instruction has 2 possible encoding types, type P IF_DEF(EN2Q, IS_NONE, NONE) // Instruction has 2 possible encoding types, type Q +IF_DEF(EN2R, IS_NONE, NONE) // Instruction has 2 possible encoding types, type R ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // @@ -207,17 +210,20 @@ IF_DEF(DV_2S, IS_NONE, NONE) // DV_2S ........XX...... ......nnnnnddddd S IF_DEF(DV_2T, IS_NONE, NONE) // DV_2T .Q......XX...... ......nnnnnddddd Sd Vn (addv, saddlv, smaxv, sminv, uaddlv, umaxv, uminv) IF_DEF(DV_2U, IS_NONE, NONE) // DV_2U ................ ......nnnnnddddd Sd Sn (sha1h) -IF_DEF(DV_3A, IS_NONE, NONE) // DV_3A .Q......XX.mmmmm ......nnnnnddddd Vd Vn Vm (vector) -IF_DEF(DV_3AI, IS_NONE, NONE) // DV_3AI .Q......XXLMmmmm ....H.nnnnnddddd Vd Vn Vm[] (vector by elem) -IF_DEF(DV_3B, IS_NONE, NONE) // DV_3B .Q.......X.mmmmm ......nnnnnddddd Vd Vn Vm (vector) -IF_DEF(DV_3BI, IS_NONE, NONE) // DV_3BI .Q.......XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (vector by elem) -IF_DEF(DV_3C, IS_NONE, NONE) // DV_3C .Q.........mmmmm ......nnnnnddddd Vd Vn Vm (vector) -IF_DEF(DV_3D, IS_NONE, NONE) // DV_3D .........X.mmmmm ......nnnnnddddd Vd Vn Vm (scalar) -IF_DEF(DV_3DI, IS_NONE, NONE) // DV_3DI .........XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (scalar by elem) -IF_DEF(DV_3E, IS_NONE, NONE) // DV_3E ...........mmmmm ......nnnnnddddd Vd Vn Vm (scalar) -IF_DEF(DV_3F, IS_NONE, NONE) // DV_3F ...........mmmmm ......nnnnnddddd Qd Sn Vm (Qd used as both source and destination) - -IF_DEF(DV_4A, IS_NONE, NONE) // DV_4A .........X.mmmmm .aaaaannnnnddddd Vd Vn Vm Va (scalar) +IF_DEF(DV_3A, IS_NONE, NONE) // DV_3A .Q......XX.mmmmm ......nnnnnddddd Vd Vn Vm (vector) +IF_DEF(DV_3AI, IS_NONE, NONE) // DV_3AI .Q......XXLMmmmm ....H.nnnnnddddd Vd Vn Vm[] (vector by elem) +IF_DEF(DV_3B, IS_NONE, NONE) // DV_3B .Q.......X.mmmmm ......nnnnnddddd Vd Vn Vm (vector) +IF_DEF(DV_3BI, IS_NONE, NONE) // DV_3BI .Q.......XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (vector by elem) +IF_DEF(DV_3C, IS_NONE, NONE) // DV_3C .Q.........mmmmm ......nnnnnddddd Vd Vn Vm (vector) +IF_DEF(DV_3D, IS_NONE, NONE) // DV_3D .........X.mmmmm ......nnnnnddddd Vd Vn Vm (scalar) +IF_DEF(DV_3DI, IS_NONE, NONE) // DV_3DI .........XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (scalar by elem) +IF_DEF(DV_3E, IS_NONE, NONE) // DV_3E ........XX.mmmmm ......nnnnnddddd Vd Vn Vm (scalar) +IF_DEF(DV_3F, IS_NONE, NONE) // DV_3F ...........mmmmm ......nnnnnddddd Qd Sn Vm (Qd used as both source and destination) +IF_DEF(DV_3G, IS_NONE, NONE) // DV_3G .Q.........mmmmm .iiii.nnnnnddddd Vd Vn Vm imm (vector) +IF_DEF(DV_3H, IS_NONE, NONE) // DV_3H ........XX.mmmmm ......nnnnnddddd Vd Vn Vm (addhn{2}, raddhn{2}, rsubhn{2}, pmull{2}, smlal{2}, subhn{2}, umlal{2} vector) +IF_DEF(DV_3HI, IS_NONE, NONE) // DV_3HI ........XXLMmmmm ....H.nnnnnddddd Vd Vn Vm[] (smlal{2}, smlsl{2}, smull{2}, umlal{2}, umlsl{2}, umull{2} vector by elem) + +IF_DEF(DV_4A, IS_NONE, NONE) // DV_4A .........X.mmmmm .aaaaannnnnddddd Vd Vn Vm Va (scalar) IF_DEF(SN_0A, IS_NONE, NONE) // SN_0A ................ ................ IF_DEF(SI_0A, IS_NONE, NONE) // SI_0A ...........iiiii iiiiiiiiiii..... imm16 diff --git a/src/coreclr/src/jit/emitpub.h b/src/coreclr/src/jit/emitpub.h index cd28e0355c03ba..e1f5e80b5295bd 100644 --- a/src/coreclr/src/jit/emitpub.h +++ b/src/coreclr/src/jit/emitpub.h @@ -83,17 +83,17 @@ void emitIns_J(instruction ins, BasicBlock* dst, int instrCount = 0); /* Emit initialized data sections */ /************************************************************************/ -UNATIVE_OFFSET emitDataGenBeg(UNATIVE_OFFSET size, bool align); +UNATIVE_OFFSET emitDataGenBeg(UNATIVE_OFFSET size, UNATIVE_OFFSET alignment); UNATIVE_OFFSET emitBBTableDataGenBeg(unsigned numEntries, bool relativeAddr); -void emitDataGenData(unsigned offs, const void* data, size_t size); +void emitDataGenData(unsigned offs, const void* data, UNATIVE_OFFSET size); void emitDataGenData(unsigned offs, BasicBlock* label); void emitDataGenEnd(); -UNATIVE_OFFSET emitDataConst(const void* cnsAddr, unsigned cnsSize, bool dblAlign); +UNATIVE_OFFSET emitDataConst(const void* cnsAddr, UNATIVE_OFFSET cnsSize, UNATIVE_OFFSET cnsAlign); UNATIVE_OFFSET emitDataSize(); diff --git a/src/coreclr/src/jit/emitxarch.cpp b/src/coreclr/src/jit/emitxarch.cpp index 6cf6b4d45f7cd0..0167887f0c9195 100644 --- a/src/coreclr/src/jit/emitxarch.cpp +++ b/src/coreclr/src/jit/emitxarch.cpp @@ -1937,13 +1937,14 @@ inline UNATIVE_OFFSET emitter::emitInsSizeSV(code_t code, int var, int dsp) /* Is this a stack parameter reference? */ - if (emitComp->lvaIsParameter(var) + if ((emitComp->lvaIsParameter(var) #if !defined(TARGET_AMD64) || defined(UNIX_AMD64_ABI) - && !emitComp->lvaIsRegArgument(var) + && !emitComp->lvaIsRegArgument(var) #endif // !TARGET_AMD64 || UNIX_AMD64_ABI - ) + ) || + (static_cast(var) == emitComp->lvaRetAddrVar)) { - /* If no EBP frame, arguments are off of ESP, above temps */ + /* If no EBP frame, arguments and ret addr are off of ESP, above temps */ if (!EBPbased) { @@ -9447,7 +9448,8 @@ BYTE* emitter::emitOutputAM(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc) // Use the large version if this is not a byte. This trick will not // work in case of SSE2 and AVX instructions. - if ((size != EA_1BYTE) && (ins != INS_imul) && !IsSSEInstruction(ins) && !IsAVXInstruction(ins)) + if ((size != EA_1BYTE) && (ins != INS_imul) && (ins != INS_bsf) && (ins != INS_bsr) && !IsSSEInstruction(ins) && + !IsAVXInstruction(ins)) { code++; } @@ -10213,8 +10215,9 @@ BYTE* emitter::emitOutputSV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc) } // Use the large version if this is not a byte - if ((size != EA_1BYTE) && (ins != INS_imul) && (!insIsCMOV(ins)) && !IsSSEInstruction(ins) && - !IsAVXInstruction(ins)) + // TODO-XArch-Cleanup Can the need for the 'w' size bit be encoded in the instruction flags? + if ((size != EA_1BYTE) && (ins != INS_imul) && (ins != INS_bsf) && (ins != INS_bsr) && (!insIsCMOV(ins)) && + !IsSSEInstruction(ins) && !IsAVXInstruction(ins)) { code |= 0x1; } @@ -10762,7 +10765,12 @@ BYTE* emitter::emitOutputCV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc) } // Check that the offset is properly aligned (i.e. the ddd in [ddd]) - assert((emitChkAlign == false) || (ins == INS_lea) || (((size_t)addr & (byteSize - 1)) == 0)); + // When SMALL_CODE is set, we only expect 4-byte alignment, otherwise + // we expect the same alignment as the size of the constant. + + assert((emitChkAlign == false) || (ins == INS_lea) || + ((emitComp->compCodeOpt() == Compiler::SMALL_CODE) && (((size_t)addr & 3) == 0)) || + (((size_t)addr & (byteSize - 1)) == 0)); } else { @@ -11247,7 +11255,8 @@ BYTE* emitter::emitOutputRR(BYTE* dst, instrDesc* id) #endif // TARGET_AMD64 } #ifdef FEATURE_HW_INTRINSICS - else if ((ins == INS_crc32) || (ins == INS_lzcnt) || (ins == INS_popcnt) || (ins == INS_tzcnt)) + else if ((ins == INS_bsf) || (ins == INS_bsr) || (ins == INS_crc32) || (ins == INS_lzcnt) || (ins == INS_popcnt) || + (ins == INS_tzcnt)) { code = insEncodeRMreg(ins, code); if ((ins == INS_crc32) && (size > EA_1BYTE)) @@ -14825,6 +14834,8 @@ emitter::insExecutionCharacteristics emitter::getInsExecutionCharacteristics(ins result.insLatency += PERFSCORE_LATENCY_2C; break; + case INS_bsf: + case INS_bsr: case INS_pextrb: case INS_pextrd: case INS_pextrw: diff --git a/src/coreclr/src/jit/flowgraph.cpp b/src/coreclr/src/jit/flowgraph.cpp index e8229286aaf39e..778962636fb0ab 100644 --- a/src/coreclr/src/jit/flowgraph.cpp +++ b/src/coreclr/src/jit/flowgraph.cpp @@ -271,23 +271,16 @@ void Compiler::fgInstrumentMethod() HRESULT res = info.compCompHnd->allocMethodBlockCounts(countOfBlocks, &profileBlockCountsStart); - Statement* stmt; - if (!SUCCEEDED(res)) { // The E_NOTIMPL status is returned when we are profiling a generic method from a different assembly if (res == E_NOTIMPL) { - // In such cases we still want to add the method entry callback node - - GenTreeCall::Use* args = gtNewCallArgs(gtNewIconEmbMethHndNode(info.compMethodHnd)); - GenTree* call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, args); - - stmt = gtNewStmt(call); + // expected failure... } else { - noway_assert(!"Error: failed to allocate profileBlockCounts"); + noway_assert(!"Error: failed to allocate profileBlockCounts"); return; } } @@ -310,8 +303,8 @@ void Compiler::fgInstrumentMethod() } // Assign the current block's IL offset into the profile data - currentBlockCounts->ILOffset = block->bbCodeOffs; - assert(currentBlockCounts->ExecutionCount == 0); // This value should already be zero-ed out + currentBlockCounts->ILOffset = block->bbCodeOffs; + currentBlockCounts->ExecutionCount = 0; size_t addrOfCurrentExecutionCount = (size_t)¤tBlockCounts->ExecutionCount; @@ -337,50 +330,51 @@ void Compiler::fgInstrumentMethod() // Check that we allocated and initialized the same number of BlockCounts tuples noway_assert(countOfBlocks == 0); - // Add the method entry callback node - - GenTree* arg; + // When prejitting, add the method entry callback node + if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT)) + { + GenTree* arg; #ifdef FEATURE_READYTORUN_COMPILER - if (opts.IsReadyToRun()) - { - mdMethodDef currentMethodToken = info.compCompHnd->getMethodDefFromMethod(info.compMethodHnd); + if (opts.IsReadyToRun()) + { + mdMethodDef currentMethodToken = info.compCompHnd->getMethodDefFromMethod(info.compMethodHnd); - CORINFO_RESOLVED_TOKEN resolvedToken; - resolvedToken.tokenContext = MAKE_METHODCONTEXT(info.compMethodHnd); - resolvedToken.tokenScope = info.compScopeHnd; - resolvedToken.token = currentMethodToken; - resolvedToken.tokenType = CORINFO_TOKENKIND_Method; + CORINFO_RESOLVED_TOKEN resolvedToken; + resolvedToken.tokenContext = MAKE_METHODCONTEXT(info.compMethodHnd); + resolvedToken.tokenScope = info.compScopeHnd; + resolvedToken.token = currentMethodToken; + resolvedToken.tokenType = CORINFO_TOKENKIND_Method; - info.compCompHnd->resolveToken(&resolvedToken); + info.compCompHnd->resolveToken(&resolvedToken); - arg = impTokenToHandle(&resolvedToken); - } - else + arg = impTokenToHandle(&resolvedToken); + } + else #endif - { - arg = gtNewIconEmbMethHndNode(info.compMethodHnd); - } - - GenTreeCall::Use* args = gtNewCallArgs(arg); - GenTree* call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, args); + { + arg = gtNewIconEmbMethHndNode(info.compMethodHnd); + } - // Get the address of the first blocks ExecutionCount - size_t addrOfFirstExecutionCount = (size_t)&profileBlockCountsStart->ExecutionCount; + GenTreeCall::Use* args = gtNewCallArgs(arg); + GenTree* call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, args); - // Read Basic-Block count value - GenTree* valueNode = gtNewIndOfIconHandleNode(TYP_INT, addrOfFirstExecutionCount, GTF_ICON_BBC_PTR, false); + // Get the address of the first blocks ExecutionCount + size_t addrOfFirstExecutionCount = (size_t)&profileBlockCountsStart->ExecutionCount; - // Compare Basic-Block count value against zero - GenTree* relop = gtNewOperNode(GT_NE, TYP_INT, valueNode, gtNewIconNode(0, TYP_INT)); - GenTree* colon = new (this, GT_COLON) GenTreeColon(TYP_VOID, gtNewNothingNode(), call); - GenTree* cond = gtNewQmarkNode(TYP_VOID, relop, colon); - stmt = gtNewStmt(cond); - } + // Read Basic-Block count value + GenTree* valueNode = gtNewIndOfIconHandleNode(TYP_INT, addrOfFirstExecutionCount, GTF_ICON_BBC_PTR, false); - fgEnsureFirstBBisScratch(); + // Compare Basic-Block count value against zero + GenTree* relop = gtNewOperNode(GT_NE, TYP_INT, valueNode, gtNewIconNode(0, TYP_INT)); + GenTree* colon = new (this, GT_COLON) GenTreeColon(TYP_VOID, gtNewNothingNode(), call); + GenTree* cond = gtNewQmarkNode(TYP_VOID, relop, colon); + Statement* stmt = gtNewStmt(cond); - fgInsertStmtAtEnd(fgFirstBB, stmt); + fgEnsureFirstBBisScratch(); + fgInsertStmtAtEnd(fgFirstBB, stmt); + } + } } /***************************************************************************** @@ -1106,28 +1100,59 @@ flowList* Compiler::fgAddRefPred(BasicBlock* block, assert(!fgCheapPredsValid); - flowList* flow; - // Keep the predecessor list in lowest to highest bbNum order. This allows us to discover the loops in // optFindNaturalLoops from innermost to outermost. // + // If we are initializing preds, we rely on the fact that we are adding references in increasing + // order of blockPred->bbNum to avoid searching the list. + // // TODO-Throughput: Inserting an edge for a block in sorted order requires searching every existing edge. // Thus, inserting all the edges for a block is quadratic in the number of edges. We need to either // not bother sorting for debuggable code, or sort in optFindNaturalLoops, or better, make the code in // optFindNaturalLoops not depend on order. This also requires ensuring that nobody else has taken a // dependency on this order. Note also that we don't allow duplicates in the list; we maintain a flDupCount // count of duplication. This also necessitates walking the flow list for every edge we add. - + // + flowList* flow = nullptr; flowList** listp = &block->bbPreds; - while ((*listp != nullptr) && ((*listp)->flBlock->bbNum < blockPred->bbNum)) + + if (initializingPreds) { - listp = &(*listp)->flNext; + // List is sorted order and we're adding references in + // increasing blockPred->bbNum order. The only possible + // dup list entry is the last one. + // + flowList* flowLast = block->bbLastPred; + if (flowLast != nullptr) + { + listp = &flowLast->flNext; + + assert(flowLast->flBlock->bbNum <= blockPred->bbNum); + + if (flowLast->flBlock == blockPred) + { + flow = flowLast; + } + } } + else + { + // References are added randomly, so we have to search. + // + while ((*listp != nullptr) && ((*listp)->flBlock->bbNum < blockPred->bbNum)) + { + listp = &(*listp)->flNext; + } - if ((*listp != nullptr) && ((*listp)->flBlock == blockPred)) + if ((*listp != nullptr) && ((*listp)->flBlock == blockPred)) + { + flow = *listp; + } + } + + if (flow != nullptr) { // The predecessor block already exists in the flow list; simply add to its duplicate count. - flow = *listp; noway_assert(flow->flDupCount > 0); flow->flDupCount++; } @@ -1150,6 +1175,11 @@ flowList* Compiler::fgAddRefPred(BasicBlock* block, flow->flBlock = blockPred; flow->flDupCount = 1; + if (initializingPreds) + { + block->bbLastPred = flow; + } + if (fgHaveValidEdgeWeights) { // We are creating an edge from blockPred to block @@ -2986,6 +3016,9 @@ void Compiler::fgRemoveCheapPred(BasicBlock* block, BasicBlock* blockPred) } } +//------------------------------------------------------------------------ +// fgRemovePreds - remove all pred information from blocks +// void Compiler::fgRemovePreds() { C_ASSERT(offsetof(BasicBlock, bbPreds) == @@ -3001,10 +3034,13 @@ void Compiler::fgRemovePreds() fgCheapPredsValid = false; } -/***************************************************************************** - * - * Function called to compute the bbPreds lists. - */ +//------------------------------------------------------------------------ +// fgComputePreds - compute the bbPreds lists +// +// Notes: +// Resets and then fills in the list of predecessors for each basic +// block. Assumes blocks (via bbNext) are in increasing bbNum order. +// void Compiler::fgComputePreds() { noway_assert(fgFirstBB); @@ -3020,21 +3056,20 @@ void Compiler::fgComputePreds() } #endif // DEBUG - // reset the refs count for each basic block - - for (block = fgFirstBB; block; block = block->bbNext) + // Reset everything pred related + for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) { - block->bbRefs = 0; + block->bbPreds = nullptr; + block->bbLastPred = nullptr; + block->bbRefs = 0; } - /* the first block is always reachable! */ + // the first block is always reachable fgFirstBB->bbRefs = 1; - /* Treat the initial block as a jump target */ + // Treat the initial block as a jump target fgFirstBB->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL; - fgRemovePreds(); - for (block = fgFirstBB; block; block = block->bbNext) { switch (block->bbJumpKind) @@ -3464,8 +3499,12 @@ void Compiler::fgMarkGCPollBlocks() bool blockNeedsPoll = false; switch (block->bbJumpKind) { - case BBJ_COND: case BBJ_ALWAYS: + if (block->isBBCallAlwaysPairTail()) + { + break; + } + case BBJ_COND: blockNeedsPoll = (block->bbJumpDest->bbNum <= block->bbNum); break; @@ -3527,6 +3566,8 @@ void Compiler::fgCreateGCPolls() if (verbose) { printf("*************** In fgCreateGCPolls() for %s\n", info.compFullName); + fgDispBasicBlocks(false); + printf("\n"); } #endif // DEBUG @@ -3792,7 +3833,15 @@ void Compiler::fgCreateGCPolls() { noway_assert(opts.OptimizationEnabled()); fgReorderBlocks(); + fgUpdateChangedFlowGraph(); + } +#ifdef DEBUG + if (verbose) + { + printf("*************** After fgCreateGCPolls()\n"); + fgDispBasicBlocks(true); } +#endif // DEBUG } /***************************************************************************** @@ -3833,19 +3882,21 @@ bool Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block, Statement* assert(containsStmt); } #endif + // Create the GC_CALL node + GenTree* call = gtNewHelperCallNode(CORINFO_HELP_POLL_GC, TYP_VOID); + call = fgMorphCall(call->AsCall()); + gtSetEvalOrder(call); - if (GCPOLL_CALL == pollType) + if (pollType == GCPOLL_CALL) { createdPollBlocks = false; - GenTreeCall* call = gtNewHelperCallNode(CORINFO_HELP_POLL_GC, TYP_VOID); - GenTree* temp = fgMorphCall(call); if (stmt != nullptr) { // The GC_POLL should be inserted relative to the supplied statement. The safer // location for the insertion is prior to the current statement since the supplied // statement could be a GT_JTRUE (see fgNewStmtNearEnd() for more details). - Statement* newStmt = gtNewStmt(temp); + Statement* newStmt = gtNewStmt(call); // Set the GC_POLL statement to have the same IL offset at the subsequent one. newStmt->SetILOffsetX(stmt->GetILOffsetX()); @@ -3854,11 +3905,11 @@ bool Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block, Statement* else if (block->bbJumpKind == BBJ_ALWAYS) { // for BBJ_ALWAYS I don't need to insert it before the condition. Just append it. - fgNewStmtAtEnd(block, temp); + fgNewStmtAtEnd(block, call); } else { - Statement* newStmt = fgNewStmtNearEnd(block, temp); + Statement* newStmt = fgNewStmtNearEnd(block, call); // For DDB156656, we need to associate the GC Poll with the IL offset (and therefore sequence // point) of the tree before which we inserted the poll. One example of when this is a // problem: @@ -3895,8 +3946,9 @@ bool Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block, Statement* } #endif // DEBUG } - else + else // GCPOLL_INLINE { + assert(pollType == GCPOLL_INLINE); createdPollBlocks = true; // if we're doing GCPOLL_INLINE, then: // 1) Create two new blocks: Poll and Bottom. The original block is called Top. @@ -3904,33 +3956,55 @@ bool Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block, Statement* // I want to create: // top -> poll -> bottom (lexically) // so that we jump over poll to get to bottom. - BasicBlock* top = block; - BasicBlock* poll = fgNewBBafter(BBJ_NONE, top, true); - BasicBlock* bottom = fgNewBBafter(top->bbJumpKind, poll, true); - BBjumpKinds oldJumpKind = top->bbJumpKind; + BasicBlock* top = block; + BasicBlock* topFallThrough = nullptr; + unsigned char lpIndexFallThrough = BasicBlock::NOT_IN_LOOP; + + if (top->bbJumpKind == BBJ_COND) + { + topFallThrough = top->bbNext; + lpIndexFallThrough = topFallThrough->bbNatLoopNum; + } + + BasicBlock* poll = fgNewBBafter(BBJ_NONE, top, true); + BasicBlock* bottom = fgNewBBafter(top->bbJumpKind, poll, true); + BBjumpKinds oldJumpKind = top->bbJumpKind; + unsigned char lpIndex = top->bbNatLoopNum; // Update block flags const unsigned __int64 originalFlags = top->bbFlags | BBF_GC_SAFE_POINT; - // Unlike Fei's inliner from puclr, I'm allowed to split loops. - // And we keep a few other flags... + // We are allowed to split loops and we need to keep a few other flags... + // noway_assert((originalFlags & (BBF_SPLIT_NONEXIST & ~(BBF_LOOP_HEAD | BBF_LOOP_CALL0 | BBF_LOOP_CALL1))) == 0); top->bbFlags = originalFlags & (~BBF_SPLIT_LOST | BBF_GC_SAFE_POINT); bottom->bbFlags |= originalFlags & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_GC_SAFE_POINT); bottom->inheritWeight(top); poll->bbFlags |= originalFlags & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_GC_SAFE_POINT); - // 9) Mark Poll as rarely run. + // Mark Poll as rarely run. poll->bbSetRunRarely(); + poll->bbNatLoopNum = lpIndex; // Set the bbNatLoopNum in case we are in a loop + + // Bottom gets all the outgoing edges and inherited flags of Original. + bottom->bbJumpDest = top->bbJumpDest; + bottom->bbNatLoopNum = lpIndex; // Set the bbNatLoopNum in case we are in a loop + if (lpIndex != BasicBlock::NOT_IN_LOOP) + { + // Set the new lpBottom in the natural loop table + optLoopTable[lpIndex].lpBottom = bottom; + } - // 5) Bottom gets all the outgoing edges and inherited flags of Original. - bottom->bbJumpDest = top->bbJumpDest; + if (lpIndexFallThrough != BasicBlock::NOT_IN_LOOP) + { + // Set the new lpHead in the natural loop table + optLoopTable[lpIndexFallThrough].lpHead = bottom; + } - // 2) Add a GC_CALL node to Poll. - GenTreeCall* call = gtNewHelperCallNode(CORINFO_HELP_POLL_GC, TYP_VOID); + // Add the GC_CALL node to Poll. fgNewStmtAtEnd(poll, call); - // 3) Remove the last statement from Top and add it to Bottom. + // Remove the last statement from Top and add it to Bottom. if (oldJumpKind != BBJ_ALWAYS) { // if I'm always jumping to the target, then this is not a condition that needs moving. @@ -3945,9 +4019,15 @@ bool Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block, Statement* // for BBJ_ALWAYS blocks, bottom is an empty block. - // 4) Create a GT_EQ node that checks against g_TrapReturningThreads. True jumps to Bottom, - // false falls through to poll. Add this to the end of Top. Top is now BBJ_COND. Bottom is - // now a jump target + // Create a GT_EQ node that checks against g_TrapReturningThreads. True jumps to Bottom, + // false falls through to poll. Add this to the end of Top. Top is now BBJ_COND. Bottom is + // now a jump target + CLANG_FORMAT_COMMENT_ANCHOR; + +#ifdef ENABLE_FAST_GCPOLL_HELPER + // Prefer the fast gc poll helepr over the double indirection + noway_assert(pAddrOfCaptureThreadGlobal == nullptr); +#endif GenTree* value; // The value of g_TrapReturningThreads if (pAddrOfCaptureThreadGlobal != nullptr) @@ -3974,18 +4054,28 @@ bool Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block, Statement* trapRelop->gtFlags |= GTF_RELOP_JMP_USED | GTF_DONT_CSE; GenTree* trapCheck = gtNewOperNode(GT_JTRUE, TYP_VOID, trapRelop); + gtSetEvalOrder(trapCheck); fgNewStmtAtEnd(top, trapCheck); + +#ifdef DEBUG + if (verbose) + { + printf("Adding trapCheck in " FMT_BB "\n", top->bbNum); + gtDispTree(trapCheck); + } +#endif + top->bbJumpDest = bottom; top->bbJumpKind = BBJ_COND; bottom->bbFlags |= BBF_JMP_TARGET; - // 7) Bottom has Top and Poll as its predecessors. Poll has just Top as a predecessor. + // Bottom has Top and Poll as its predecessors. Poll has just Top as a predecessor. fgAddRefPred(bottom, poll); fgAddRefPred(bottom, top); fgAddRefPred(poll, top); - // 8) Replace Top with Bottom in the predecessor list of all outgoing edges from Bottom (1 for - // jumps, 2 for conditional branches, N for switches). + // Replace Top with Bottom in the predecessor list of all outgoing edges from Bottom + // (1 for unconditional branches, 2 for conditional branches, N for switches). switch (oldJumpKind) { case BBJ_NONE: @@ -4031,6 +4121,9 @@ bool Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block, Statement* gtDispBlockStmts(poll); printf(" bottom block is " FMT_BB "\n", bottom->bbNum); gtDispBlockStmts(bottom); + + printf("\nAfter this change in fgCreateGCPoll the BB graph is:"); + fgDispBasicBlocks(false); } #endif // DEBUG } @@ -5953,7 +6046,14 @@ void Compiler::fgFindBasicBlocks() { // The lifetime of this var might expand multiple BBs. So it is a long lifetime compiler temp. lvaInlineeReturnSpillTemp = lvaGrabTemp(false DEBUGARG("Inline return value spill temp")); - lvaTable[lvaInlineeReturnSpillTemp].lvType = info.compRetNativeType; + if (compDoOldStructRetyping()) + { + lvaTable[lvaInlineeReturnSpillTemp].lvType = info.compRetNativeType; + } + else + { + lvaTable[lvaInlineeReturnSpillTemp].lvType = info.compRetType; + } // If the method returns a ref class, set the class of the spill temp // to the method's return value. We may update this later if it turns @@ -6890,7 +6990,7 @@ PhaseStatus Compiler::fgImport() if ((block->bbFlags & BBF_IMPORTED) != 0) { // Assume if we generate any IR for the block we generate IR for the entire block. - if (!block->isEmpty()) + if (block->firstStmt() != nullptr) { IL_OFFSET beginOffset = block->bbCodeOffs; IL_OFFSET endOffset = block->bbCodeOffsEnd; @@ -7795,18 +7895,26 @@ inline void Compiler::fgMarkLoopHead(BasicBlock* block) return; } -#ifdef DEBUG - if (verbose) - { - printf("no guaranteed callsite exits, marking method as fully interruptible\n"); - } -#endif - // only enable fully interruptible code for if we're hijacking. if (GCPOLL_NONE == opts.compGCPollType) { +#ifdef DEBUG + if (verbose) + { + printf("no guaranteed callsite exits, marking method as fully interruptible\n"); + } +#endif SetInterruptible(true); } + else + { +#ifdef DEBUG + if (verbose) + { + printf("no guaranteed callsite exits, but we are using GC Poll calls\n"); + } +#endif + } } GenTree* Compiler::fgGetCritSectOfStaticMethod() @@ -7833,7 +7941,7 @@ GenTree* Compiler::fgGetCritSectOfStaticMethod() // Collectible types requires that for shared generic code, if we use the generic context paramter // that we report it. (This is a conservative approach, we could detect some cases particularly when the // context parameter is this that we don't need the eager reporting logic.) - lvaGenericsContextUseCount++; + lvaGenericsContextInUse = true; switch (kind.runtimeLookupKind) { @@ -7847,6 +7955,7 @@ GenTree* Compiler::fgGetCritSectOfStaticMethod() { // In this case, the hidden param is the class handle. tree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL); + tree->gtFlags |= GTF_VAR_CONTEXT; break; } @@ -7854,6 +7963,7 @@ GenTree* Compiler::fgGetCritSectOfStaticMethod() { // In this case, the hidden param is the method handle. tree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL); + tree->gtFlags |= GTF_VAR_CONTEXT; // Call helper CORINFO_HELP_GETCLASSFROMMETHODPARAM to get the class handle // from the method handle. tree = gtNewHelperCallNode(CORINFO_HELP_GETCLASSFROMMETHODPARAM, TYP_I_IMPL, gtNewCallArgs(tree)); @@ -8568,7 +8678,18 @@ class MergedReturns if (comp->compMethodReturnsNativeScalarType()) { - returnLocalDsc.lvType = genActualType(comp->info.compRetNativeType); + if (!comp->compDoOldStructRetyping()) + { + returnLocalDsc.lvType = genActualType(comp->info.compRetType); + if (varTypeIsStruct(returnLocalDsc.lvType)) + { + comp->lvaSetStruct(returnLocalNum, comp->info.compMethodInfo->args.retTypeClass, false); + } + } + else + { + returnLocalDsc.lvType = genActualType(comp->info.compRetNativeType); + } } else if (comp->compMethodReturnsRetBufAddr()) { @@ -10145,6 +10266,12 @@ bool Compiler::fgCanCompactBlocks(BasicBlock* block, BasicBlock* bNext) return false; } + // Don't compact away any loop entry blocks that we added in optCanonicalizeLoops + if (optIsLoopEntry(block)) + { + return false; + } + #if defined(TARGET_ARM) // We can't compact a finally target block, as we need to generate special code for such blocks during code // generation @@ -10826,7 +10953,11 @@ void Compiler::fgRemoveConditionalJump(BasicBlock* block) { test->SetRootNode(sideEffList); - fgMorphBlockStmt(block, test DEBUGARG("fgRemoveConditionalJump")); + if (fgStmtListThreaded) + { + gtSetStmtInfo(test); + fgSetStmtSeq(test); + } } } } @@ -11386,10 +11517,12 @@ BasicBlock* Compiler::fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst) { fgAddRefPred(jmpBlk, bSrc, fgGetPredForBlock(bDst, bSrc)); } + // Record the loop number in the new block + jmpBlk->bbNatLoopNum = bSrc->bbNatLoopNum; // When adding a new jmpBlk we will set the bbWeight and bbFlags // - if (fgHaveValidEdgeWeights) + if (fgHaveValidEdgeWeights && fgHaveProfileData()) { noway_assert(fgComputePredsDone); @@ -11408,7 +11541,6 @@ BasicBlock* Compiler::fgConnectFallThrough(BasicBlock* bSrc, BasicBlock* bDst) BasicBlock::weight_t weightDiff = (newEdge->edgeWeightMax() - newEdge->edgeWeightMin()); BasicBlock::weight_t slop = BasicBlock::GetSlopFraction(bSrc, bDst); - // // If the [min/max] values for our edge weight is within the slop factor // then we will set the BBF_PROF_WEIGHT flag for the block @@ -21225,6 +21357,8 @@ void Compiler::fgDebugCheckFlags(GenTree* tree) return; } break; + case GT_ADDR: + assert(!op1->CanCSE()); default: break; @@ -21896,7 +22030,7 @@ unsigned Compiler::fgCheckInlineDepthAndRecursion(InlineInfo* inlineInfo) for (; inlineContext != nullptr; inlineContext = inlineContext->GetParent()) { - + assert(inlineContext->GetCode() != nullptr); depth++; if (inlineContext->GetCode() == candidateCode) @@ -22180,12 +22314,11 @@ void Compiler::fgNoteNonInlineCandidate(Statement* stmt, GenTreeCall* call) */ GenTree* Compiler::fgGetStructAsStructPtr(GenTree* tree) { - noway_assert((tree->gtOper == GT_LCL_VAR) || (tree->gtOper == GT_FIELD) || (tree->gtOper == GT_IND) || - (tree->gtOper == GT_BLK) || (tree->gtOper == GT_OBJ) || tree->OperIsSIMD() || - // tree->gtOper == GT_CALL || cannot get address of call. - // tree->gtOper == GT_MKREFANY || inlining should've been aborted due to mkrefany opcode. - // tree->gtOper == GT_RET_EXPR || cannot happen after fgUpdateInlineReturnExpressionPlaceHolder - (tree->gtOper == GT_COMMA)); + noway_assert(tree->OperIs(GT_LCL_VAR, GT_FIELD, GT_IND, GT_BLK, GT_OBJ, GT_COMMA) || tree->OperIsSIMD() || + tree->OperIsHWIntrinsic()); + // GT_CALL, cannot get address of call. + // GT_MKREFANY, inlining should've been aborted due to mkrefany opcode. + // GT_RET_EXPR, cannot happen after fgUpdateInlineReturnExpressionPlaceHolder switch (tree->OperGet()) { @@ -23647,14 +23780,12 @@ Statement* Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo) // If the local is used check whether we need to insert explicit zero initialization. if (tmpNum != BAD_VAR_NUM) { - if (!fgVarNeedsExplicitZeroInit(lvaGetDesc(tmpNum), bbInALoop, bbIsReturn)) + LclVarDsc* const tmpDsc = lvaGetDesc(tmpNum); + if (!fgVarNeedsExplicitZeroInit(tmpNum, bbInALoop, bbIsReturn)) { -#ifdef DEBUG - if (verbose) - { - printf("\nSkipping zero initialization of V%02u\n", tmpNum); - } -#endif // DEBUG + JITDUMP("\nSuppressing zero-init for V%02u -- expect to zero in prolog\n", tmpNum); + tmpDsc->lvSuppressedZeroInit = 1; + compSuppressedZeroInit = true; continue; } @@ -23720,38 +23851,6 @@ Statement* Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo) void Compiler::fgInlineAppendStatements(InlineInfo* inlineInfo, BasicBlock* block, Statement* stmtAfter) { - // If this inlinee was passed a runtime lookup generic context and - // ignores it, we can decrement the "generic context was used" ref - // count, because we created a new lookup tree and incremented the - // count when we imported the type parameter argument to pass to - // the inlinee. See corresponding logic in impImportCall that - // checks the sig for CORINFO_CALLCONV_PARAMTYPE. - // - // Does this method require a context (type) parameter? - if ((inlineInfo->inlineCandidateInfo->methInfo.args.callConv & CORINFO_CALLCONV_PARAMTYPE) != 0) - { - // Did the computation of that parameter require the - // caller to perform a runtime lookup? - if (inlineInfo->inlineCandidateInfo->exactContextNeedsRuntimeLookup) - { - // Fetch the temp for the generic context as it would - // appear in the inlinee's body. - const unsigned typeCtxtArg = inlineInfo->typeContextArg; - const unsigned tmpNum = inlineInfo->lclTmpNum[typeCtxtArg]; - - // Was it used in the inline body? - if (tmpNum == BAD_VAR_NUM) - { - // No -- so the associated runtime lookup is not needed - // and also no longer provides evidence that the generic - // context should be kept alive. - JITDUMP("Inlinee ignores runtime lookup generics context\n"); - assert(lvaGenericsContextUseCount > 0); - lvaGenericsContextUseCount--; - } - } - } - // Null out any gc ref locals if (!inlineInfo->HasGcRefLocals()) { @@ -25823,6 +25922,10 @@ PhaseStatus Compiler::fgTailMergeThrows() JITDUMP("Method does not have multiple noreturn calls.\n"); return PhaseStatus::MODIFIED_NOTHING; } + else + { + JITDUMP("Scanning the %u candidates\n", optNoReturnCallCount); + } // This transformation requires block pred lists to be built // so that flow can be safely updated. @@ -25888,11 +25991,16 @@ PhaseStatus Compiler::fgTailMergeThrows() continue; } - // For throw helpers the block should have exactly one statement.... - // (this isn't guaranteed, but seems likely) - Statement* stmt = block->firstStmt(); + // We only look at the first statement for throw helper calls. + // Remainder of the block will be dead code. + // + // Throw helper calls could show up later in the block; we + // won't try merging those as we'd need to match up all the + // prior statements or split the block at this point, etc. + // + Statement* const stmt = block->firstStmt(); - if ((stmt == nullptr) || (stmt->GetNextStmt() != nullptr)) + if (stmt == nullptr) { continue; } @@ -25954,13 +26062,14 @@ PhaseStatus Compiler::fgTailMergeThrows() // We walk the map rather than the block list, to save a bit of time. BlockToBlockMap::KeyIterator iter(blockMap.Begin()); BlockToBlockMap::KeyIterator end(blockMap.End()); - int updateCount = 0; + unsigned updateCount = 0; for (; !iter.Equal(end); iter++) { BasicBlock* const nonCanonicalBlock = iter.Get(); BasicBlock* const canonicalBlock = iter.GetValue(); flowList* nextPredEdge = nullptr; + bool updated = false; // Walk pred list of the non canonical block, updating flow to target // the canonical block instead. @@ -25974,14 +26083,14 @@ PhaseStatus Compiler::fgTailMergeThrows() case BBJ_NONE: { fgTailMergeThrowsFallThroughHelper(predBlock, nonCanonicalBlock, canonicalBlock, predEdge); - updateCount++; + updated = true; } break; case BBJ_ALWAYS: { fgTailMergeThrowsJumpToHelper(predBlock, nonCanonicalBlock, canonicalBlock, predEdge); - updateCount++; + updated = true; } break; @@ -25997,7 +26106,7 @@ PhaseStatus Compiler::fgTailMergeThrows() { fgTailMergeThrowsJumpToHelper(predBlock, nonCanonicalBlock, canonicalBlock, predEdge); } - updateCount++; + updated = true; } break; @@ -26005,7 +26114,7 @@ PhaseStatus Compiler::fgTailMergeThrows() { JITDUMP("*** " FMT_BB " now branching to " FMT_BB "\n", predBlock->bbNum, canonicalBlock->bbNum); fgReplaceSwitchJumpTarget(predBlock, canonicalBlock, nonCanonicalBlock); - updateCount++; + updated = true; } break; @@ -26015,6 +26124,11 @@ PhaseStatus Compiler::fgTailMergeThrows() break; } } + + if (updated) + { + updateCount++; + } } if (updateCount == 0) @@ -26022,13 +26136,18 @@ PhaseStatus Compiler::fgTailMergeThrows() return PhaseStatus::MODIFIED_NOTHING; } + // TODO: Update the count of noreturn call sites -- this feeds a heuristic in morph + // to determine if these noreturn calls should be tail called. + // + // Updating the count does not lead to better results, so deferring for now. + // + JITDUMP("Made %u updates\n", updateCount); + assert(updateCount < optNoReturnCallCount); + // If we altered flow, reset fgModified. Given where we sit in the // phase list, flow-dependent side data hasn't been built yet, so // nothing needs invalidation. // - // Note we could invoke a cleanup pass here, but optOptimizeFlow - // seems to be missing some safety checks and doesn't expect to - // see an already cleaned-up flow graph. assert(fgModified); fgModified = false; return PhaseStatus::MODIFIED_EVERYTHING; diff --git a/src/coreclr/src/jit/gentree.cpp b/src/coreclr/src/jit/gentree.cpp index f5b72fc566316a..3ff1403ed021ea 100644 --- a/src/coreclr/src/jit/gentree.cpp +++ b/src/coreclr/src/jit/gentree.cpp @@ -622,15 +622,12 @@ void GenTree::CopyReg(GenTree* from) // bool GenTree::gtHasReg() const { - bool hasReg; + bool hasReg = false; if (IsMultiRegCall()) { - // Have to cast away const-ness because GetReturnTypeDesc() is a non-const method - GenTree* tree = const_cast(this); - GenTreeCall* call = tree->AsCall(); - unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount(); - hasReg = false; + const GenTreeCall* call = AsCall(); + const unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount(); // A Multi-reg call node is said to have regs, if it has // reg assigned to each of its result registers. @@ -645,11 +642,9 @@ bool GenTree::gtHasReg() const } else if (IsCopyOrReloadOfMultiRegCall()) { - GenTree* tree = const_cast(this); - GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload(); - GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall(); - unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount(); - hasReg = false; + const GenTreeCopyOrReload* copyOrReload = AsCopyOrReload(); + const GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall(); + const unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount(); // A Multi-reg copy or reload node is said to have regs, // if it has valid regs in any of the positions. @@ -693,9 +688,7 @@ int GenTree::GetRegisterDstCount() const } else if (IsMultiRegCall()) { - // temporarily cast away const-ness as AsCall() method is not declared const - GenTree* temp = const_cast(this); - return temp->AsCall()->GetReturnTypeDesc()->GetReturnRegCount(); + return AsCall()->GetReturnTypeDesc()->GetReturnRegCount(); } else if (IsCopyOrReload()) { @@ -722,6 +715,14 @@ int GenTree::GetRegisterDstCount() const #endif } #endif + +#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) + if (OperIs(GT_HWINTRINSIC)) + { + assert(TypeGet() == TYP_STRUCT); + return 2; + } +#endif assert(!"Unexpected multi-reg node"); return 0; } @@ -742,9 +743,8 @@ regMaskTP GenTree::gtGetRegMask() const if (IsMultiRegCall()) { // temporarily cast away const-ness as AsCall() method is not declared const - resultMask = genRegMask(GetRegNum()); - GenTree* temp = const_cast(this); - resultMask |= temp->AsCall()->GetOtherRegMask(); + resultMask = genRegMask(GetRegNum()); + resultMask |= AsCall()->GetOtherRegMask(); } else if (IsCopyOrReloadOfMultiRegCall()) { @@ -752,10 +752,9 @@ regMaskTP GenTree::gtGetRegMask() const // positions that need to be copied or reloaded. Hence we need // to consider only those registers for computing reg mask. - GenTree* tree = const_cast(this); - GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload(); - GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall(); - unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount(); + const GenTreeCopyOrReload* copyOrReload = AsCopyOrReload(); + const GenTreeCall* call = copyOrReload->gtGetOp1()->AsCall(); + const unsigned regCount = call->GetReturnTypeDesc()->GetReturnRegCount(); resultMask = RBM_NONE; for (unsigned i = 0; i < regCount; ++i) @@ -770,9 +769,8 @@ regMaskTP GenTree::gtGetRegMask() const #if FEATURE_ARG_SPLIT else if (OperIsPutArgSplit()) { - GenTree* tree = const_cast(this); - GenTreePutArgSplit* splitArg = tree->AsPutArgSplit(); - unsigned regCount = splitArg->gtNumRegs; + const GenTreePutArgSplit* splitArg = AsPutArgSplit(); + const unsigned regCount = splitArg->gtNumRegs; resultMask = RBM_NONE; for (unsigned i = 0; i < regCount; ++i) @@ -1288,6 +1286,15 @@ bool GenTree::Compare(GenTree* op1, GenTree* op2, bool swapOK) return true; } break; + + case GT_CNS_STR: + if ((op1->AsStrCon()->gtSconCPX == op2->AsStrCon()->gtSconCPX) && + (op1->AsStrCon()->gtScpHnd == op2->AsStrCon()->gtScpHnd)) + { + return true; + } + break; + #if 0 // TODO-CQ: Enable this in the future case GT_CNS_LNG: @@ -1450,7 +1457,7 @@ bool GenTree::Compare(GenTree* op1, GenTree* op2, bool swapOK) if ((op1->AsHWIntrinsic()->gtHWIntrinsicId != op2->AsHWIntrinsic()->gtHWIntrinsicId) || (op1->AsHWIntrinsic()->gtSIMDBaseType != op2->AsHWIntrinsic()->gtSIMDBaseType) || (op1->AsHWIntrinsic()->gtSIMDSize != op2->AsHWIntrinsic()->gtSIMDSize) || - (op1->AsHWIntrinsic()->gtIndexBaseType != op2->AsHWIntrinsic()->gtIndexBaseType)) + (op1->AsHWIntrinsic()->GetOtherBaseType() != op2->AsHWIntrinsic()->GetOtherBaseType())) { return false; } @@ -2120,7 +2127,7 @@ unsigned Compiler::gtHashValue(GenTree* tree) hash += tree->AsHWIntrinsic()->gtHWIntrinsicId; hash += tree->AsHWIntrinsic()->gtSIMDBaseType; hash += tree->AsHWIntrinsic()->gtSIMDSize; - hash += tree->AsHWIntrinsic()->gtIndexBaseType; + hash += tree->AsHWIntrinsic()->GetOtherBaseType(); break; #endif // FEATURE_HW_INTRINSICS @@ -5550,6 +5557,47 @@ bool GenTree::OperMayThrow(Compiler* comp) return false; } +//----------------------------------------------------------------------------------- +// GetFieldCount: Return the register count for a multi-reg lclVar. +// +// Arguments: +// compiler - the current Compiler instance. +// +// Return Value: +// Returns the number of registers defined by this node. +// +// Notes: +// This must be a multireg lclVar. +// +unsigned int GenTreeLclVar::GetFieldCount(Compiler* compiler) +{ + assert(IsMultiReg()); + LclVarDsc* varDsc = compiler->lvaGetDesc(GetLclNum()); + return varDsc->lvFieldCnt; +} + +//----------------------------------------------------------------------------------- +// GetFieldTypeByIndex: Get a specific register's type, based on regIndex, that is produced +// by this multi-reg node. +// +// Arguments: +// compiler - the current Compiler instance. +// idx - which register type to return. +// +// Return Value: +// The register type assigned to this index for this node. +// +// Notes: +// This must be a multireg lclVar and 'regIndex' must be a valid index for this node. +// +var_types GenTreeLclVar::GetFieldTypeByIndex(Compiler* compiler, unsigned idx) +{ + assert(IsMultiReg()); + LclVarDsc* varDsc = compiler->lvaGetDesc(GetLclNum()); + LclVarDsc* fieldVarDsc = compiler->lvaGetDesc(varDsc->lvFieldLclStart + idx); + return fieldVarDsc->TypeGet(); +} + #if DEBUGGABLE_GENTREE // static GenTree::VtablePtr GenTree::s_vtablesForOpers[] = {nullptr}; @@ -6058,12 +6106,13 @@ GenTreeCall* Compiler::gtNewCallNode( { node->gtFlags |= (use.GetNode()->gtFlags & GTF_ALL_EFFECT); } - node->gtCallType = callType; - node->gtCallMethHnd = callHnd; - node->gtCallArgs = args; - node->gtCallThisArg = nullptr; - node->fgArgInfo = nullptr; - node->callSig = nullptr; + node->gtCallType = callType; + node->gtCallMethHnd = callHnd; + node->gtCallArgs = args; + node->gtCallThisArg = nullptr; + node->fgArgInfo = nullptr; + INDEBUG(node->callSig = nullptr;) + node->tailCallInfo = nullptr; node->gtRetClsHnd = nullptr; node->gtControlExpr = nullptr; node->gtCallMoreFlags = 0; @@ -6123,21 +6172,14 @@ GenTreeCall* Compiler::gtNewCallNode( // Initialize spill flags of gtOtherRegs node->ClearOtherRegFlags(); -#if defined(TARGET_X86) || defined(TARGET_ARM) - // Initialize the multi-reg long return info if necessary +#if !defined(TARGET_64BIT) if (varTypeIsLong(node)) { - // The return type will remain as the incoming long type - node->gtReturnType = node->gtType; - + assert(node->gtReturnType == node->gtType); // Initialize Return type descriptor of call node - ReturnTypeDesc* retTypeDesc = node->GetReturnTypeDesc(); - retTypeDesc->InitializeLongReturnType(this); - - // must be a long returned in two registers - assert(retTypeDesc->GetReturnRegCount() == 2); + node->InitializeLongReturnType(); } -#endif // defined(TARGET_X86) || defined(TARGET_ARM) +#endif // !defined(TARGET_64BIT) return node; } @@ -6422,7 +6464,7 @@ GenTree* Compiler::gtArgNodeByLateArgInx(GenTreeCall* call, unsigned lateArgInx) * Create a node that will assign 'src' to 'dst'. */ -GenTree* Compiler::gtNewAssignNode(GenTree* dst, GenTree* src) +GenTreeOp* Compiler::gtNewAssignNode(GenTree* dst, GenTree* src) { /* Mark the target as being assigned */ @@ -6439,7 +6481,7 @@ GenTree* Compiler::gtNewAssignNode(GenTree* dst, GenTree* src) /* Create the assignment node */ - GenTree* asg = gtNewOperNode(GT_ASG, dst->TypeGet(), dst, src); + GenTreeOp* asg = gtNewOperNode(GT_ASG, dst->TypeGet(), dst, src)->AsOp(); /* Mark the expression as containing an assignment */ @@ -7430,7 +7472,7 @@ GenTree* Compiler::gtCloneExpr( GenTreeHWIntrinsic(hwintrinsicOp->TypeGet(), hwintrinsicOp->gtGetOp1(), hwintrinsicOp->gtGetOp2IfPresent(), hwintrinsicOp->gtHWIntrinsicId, hwintrinsicOp->gtSIMDBaseType, hwintrinsicOp->gtSIMDSize); - copy->AsHWIntrinsic()->gtIndexBaseType = hwintrinsicOp->gtIndexBaseType; + copy->AsHWIntrinsic()->SetOtherBaseType(hwintrinsicOp->GetOtherBaseType()); } break; #endif @@ -7747,7 +7789,11 @@ GenTreeCall* Compiler::gtCloneExprCallHelper(GenTreeCall* tree, unsigned addFlag // we only really need one physical copy of it. Therefore a shallow pointer copy will suffice. // (Note that this still holds even if the tree we are cloning was created by an inlinee compiler, // because the inlinee still uses the inliner's memory allocator anyway.) - copy->callSig = tree->callSig; + INDEBUG(copy->callSig = tree->callSig;) + + // The tail call info does not change after it is allocated, so for the same reasons as above + // a shallow copy suffices. + copy->tailCallInfo = tree->tailCallInfo; copy->gtCallType = tree->gtCallType; copy->gtReturnType = tree->gtReturnType; @@ -7798,6 +7844,15 @@ GenTreeCall* Compiler::gtCloneExprCallHelper(GenTreeCall* tree, unsigned addFlag copy->CopyOtherRegFlags(tree); + // We keep track of the number of no return calls, so if we've cloned + // one of these, update the tracking. + // + if (tree->IsNoReturn()) + { + assert(copy->IsNoReturn()); + setMethodHasNoReturnCalls(); + } + return copy; } @@ -9874,6 +9929,12 @@ void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, __in __in_z _ --msgLength; break; } + if (tree->gtFlags & GTF_VAR_MULTIREG) + { + printf((tree->gtFlags & GTF_VAR_DEF) ? "M" : "m"); + --msgLength; + break; + } if (tree->gtFlags & GTF_VAR_DEF) { printf("D"); @@ -9892,6 +9953,13 @@ void Compiler::gtDispNode(GenTree* tree, IndentStack* indentStack, __in __in_z _ --msgLength; break; } + if (tree->gtFlags & GTF_VAR_CONTEXT) + { + printf("!"); + --msgLength; + break; + } + goto DASH; case GT_EQ: @@ -10137,39 +10205,49 @@ void Compiler::gtDispRegVal(GenTree* tree) break; } +#if FEATURE_MULTIREG_RET if (tree->IsMultiRegCall()) { - // 0th reg is GettRegNum(), which is already printed above. + // 0th reg is GetRegNum(), which is already printed above. // Print the remaining regs of a multi-reg call node. - GenTreeCall* call = tree->AsCall(); - unsigned regCount = call->GetReturnTypeDesc()->TryGetReturnRegCount(); + const GenTreeCall* call = tree->AsCall(); + const unsigned regCount = call->GetReturnTypeDesc()->TryGetReturnRegCount(); for (unsigned i = 1; i < regCount; ++i) { printf(",%s", compRegVarName(call->GetRegNumByIdx(i))); } } - else if (tree->IsCopyOrReloadOfMultiRegCall()) + else if (tree->IsCopyOrReload()) { - GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload(); - GenTreeCall* call = tree->gtGetOp1()->AsCall(); - unsigned regCount = call->GetReturnTypeDesc()->TryGetReturnRegCount(); - for (unsigned i = 1; i < regCount; ++i) + GenTree* op1 = tree->gtGetOp1(); + const GenTreeCopyOrReload* copyOrReload = tree->AsCopyOrReload(); + unsigned regCount = 0; + if (op1->OperIs(GT_CALL)) { - printf(",%s", compRegVarName(copyOrReload->GetRegNumByIdx(i))); - } - } - -#if FEATURE_MULTIREG_RET - if (tree->IsCopyOrReload()) - { - for (int i = 1; i < MAX_RET_REG_COUNT; i++) - { - regNumber reg = (regNumber)tree->AsCopyOrReload()->GetRegNumByIdx(i); - if (reg == REG_NA) + if (op1->IsMultiRegCall()) { - break; + regCount = op1->AsCall()->GetReturnTypeDesc()->TryGetReturnRegCount(); + // If it hasn't yet been initialized, we'd still like to see the registers printed. + if (regCount == 0) + { + regCount = MAX_RET_REG_COUNT; + } } - printf(",%s", compRegVarName(reg)); + } + else if (op1->IsMultiRegLclVar()) + { + regCount = op1->AsLclVar()->GetFieldCount(this); + } + else if (op1->IsMultiRegNode()) + { + regCount = op1->GetMultiRegCount(); + } + // We will only have valid regs for positions that require copy or reload. + // But we'd like to keep track of where they are so we print all positions. + for (unsigned i = 1; i < regCount; i++) + { + regNumber reg = tree->AsCopyOrReload()->GetRegNumByIdx(i); + printf(",%s", (reg == REG_NA) ? ",NA" : compRegVarName(reg)); } } #endif @@ -10236,6 +10314,10 @@ void Compiler::gtGetLclVarNameInfo(unsigned lclNum, const char** ilKindOut, cons { ilName = "GsCookie"; } + else if (lclNum == lvaRetAddrVar) + { + ilName = "ReturnAddress"; + } #if FEATURE_FIXED_OUT_ARGS else if (lclNum == lvaPInvokeFrameRegSaveVar) { @@ -11285,10 +11367,10 @@ void Compiler::gtDispTree(GenTree* tree, printf(" %s", eeGetFieldName(tree->AsField()->gtFldHnd), 0); } + gtDispCommonEndLine(tree); + if (tree->AsField()->gtFldObj && !topOnly) { - gtDispVN(tree); - printf("\n"); gtDispChild(tree->AsField()->gtFldObj, indentStack, IIArcBottom); } @@ -12421,11 +12503,10 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree) GenTree* op2TunneledHandle = nullptr; CORINFO_CLASS_HANDLE cls1Hnd = NO_CLASS_HANDLE; CORINFO_CLASS_HANDLE cls2Hnd = NO_CLASS_HANDLE; - unsigned runtimeLookupCount = 0; // Try and find class handles from op1 and op2 - cls1Hnd = gtGetHelperArgClassHandle(op1ClassFromHandle, &runtimeLookupCount, &op1TunneledHandle); - cls2Hnd = gtGetHelperArgClassHandle(op2ClassFromHandle, &runtimeLookupCount, &op2TunneledHandle); + cls1Hnd = gtGetHelperArgClassHandle(op1ClassFromHandle, &op1TunneledHandle); + cls2Hnd = gtGetHelperArgClassHandle(op2ClassFromHandle, &op2TunneledHandle); // If we have both class handles, try and resolve the type equality test completely. bool resolveFailed = false; @@ -12444,11 +12525,6 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree) const int compareResult = operatorIsEQ ^ typesAreEqual ? 0 : 1; JITDUMP("Runtime reports comparison is known at jit time: %u\n", compareResult); GenTree* result = gtNewIconNode(compareResult); - - // Any runtime lookups that fed into this compare are - // now dead code, so they no longer require the runtime context. - assert(lvaGenericsContextUseCount >= runtimeLookupCount); - lvaGenericsContextUseCount -= runtimeLookupCount; return result; } else @@ -12611,15 +12687,12 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree) // // Arguments: // tree - tree that passes the handle to the helper -// runtimeLookupCount [optional, in/out] - incremented if tree was a runtime lookup // handleTree [optional, out] - set to the literal operand tree for indirect handles // // Returns: // The compile time class handle if known. // -CORINFO_CLASS_HANDLE Compiler::gtGetHelperArgClassHandle(GenTree* tree, - unsigned* runtimeLookupCount, - GenTree** handleTree) +CORINFO_CLASS_HANDLE Compiler::gtGetHelperArgClassHandle(GenTree* tree, GenTree** handleTree) { CORINFO_CLASS_HANDLE result = NO_CLASS_HANDLE; @@ -12639,11 +12712,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetHelperArgClassHandle(GenTree* tree, else if (tree->OperGet() == GT_RUNTIMELOOKUP) { result = tree->AsRuntimeLookup()->GetClassHandle(); - - if (runtimeLookupCount != nullptr) - { - *runtimeLookupCount = *runtimeLookupCount + 1; - } } // Or something reached indirectly else if (tree->gtOper == GT_IND) @@ -15071,6 +15139,14 @@ GenTree* Compiler::gtNewTempAssign( // and call returns. Lowering and Codegen will handle these. ok = true; } + else if ((dstTyp == TYP_STRUCT) && (valTyp == TYP_INT)) + { + // It could come from `ASG(struct, 0)` that was propagated to `RETURN struct(0)`, + // and now it is merging to a struct again. + assert(!compDoOldStructRetyping()); + assert(tmp == genReturnLocal); + ok = true; + } if (!ok) { @@ -15099,15 +15175,34 @@ GenTree* Compiler::gtNewTempAssign( // struct types. We don't have a convenient way to do that for all SIMD temps, since some // internal trees use SIMD types that are not used by the input IL. In this case, we allow // a null type handle and derive the necessary information about the type from its varType. - CORINFO_CLASS_HANDLE structHnd = gtGetStructHandleIfPresent(val); - if (varTypeIsStruct(varDsc) && ((structHnd != NO_CLASS_HANDLE) || (varTypeIsSIMD(valTyp)))) + CORINFO_CLASS_HANDLE valStructHnd = gtGetStructHandleIfPresent(val); + if (varTypeIsStruct(varDsc) && (valStructHnd == NO_CLASS_HANDLE) && !varTypeIsSIMD(valTyp)) + { + // There are 2 special cases: + // 1. we have lost classHandle from a FIELD node because the parent struct has overlapping fields, + // the field was transformed as IND opr GT_LCL_FLD; + // 2. we are propogating `ASG(struct V01, 0)` to `RETURN(struct V01)`, `CNT_INT` doesn't `structHnd`; + // in these cases, we can use the type of the merge return for the assignment. + assert(val->OperIs(GT_IND, GT_LCL_FLD, GT_CNS_INT)); + assert(!compDoOldStructRetyping()); + assert(tmp == genReturnLocal); + valStructHnd = lvaGetStruct(genReturnLocal); + assert(valStructHnd != NO_CLASS_HANDLE); + } + + if ((valStructHnd != NO_CLASS_HANDLE) && val->IsConstInitVal()) + { + assert(!compDoOldStructRetyping()); + asg = gtNewAssignNode(dest, val); + } + else if (varTypeIsStruct(varDsc) && ((valStructHnd != NO_CLASS_HANDLE) || varTypeIsSIMD(valTyp))) { // The struct value may be be a child of a GT_COMMA. GenTree* valx = val->gtEffectiveVal(/*commaOnly*/ true); - if (structHnd != NO_CLASS_HANDLE) + if (valStructHnd != NO_CLASS_HANDLE) { - lvaSetStruct(tmp, structHnd, false); + lvaSetStruct(tmp, valStructHnd, false); } else { @@ -15115,7 +15210,7 @@ GenTree* Compiler::gtNewTempAssign( } dest->gtFlags |= GTF_DONT_CSE; valx->gtFlags |= GTF_DONT_CSE; - asg = impAssignStruct(dest, val, structHnd, (unsigned)CHECK_SPILL_NONE, pAfterStmt, ilOffset, block); + asg = impAssignStruct(dest, val, valStructHnd, (unsigned)CHECK_SPILL_NONE, pAfterStmt, ilOffset, block); } else { @@ -15123,7 +15218,8 @@ GenTree* Compiler::gtNewTempAssign( // when the ABI calls for returning a struct as a primitive type. // TODO-1stClassStructs: When we stop "lying" about the types for ABI purposes, the // 'genReturnLocal' should be the original struct type. - assert(!varTypeIsStruct(valTyp) || typGetObjLayout(structHnd)->GetSize() == genTypeSize(varDsc)); + assert(!varTypeIsStruct(valTyp) || ((valStructHnd != NO_CLASS_HANDLE) && + (typGetObjLayout(valStructHnd)->GetSize() == genTypeSize(varDsc)))); asg = gtNewAssignNode(dest, val); } @@ -15221,9 +15317,7 @@ GenTree* Compiler::gtNewRefCOMfield(GenTree* objPtr, #if FEATURE_MULTIREG_RET if (varTypeIsStruct(call)) { - // Initialize Return type descriptor of call node. - ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); - retTypeDesc->InitializeStructReturnType(this, structType); + call->InitializeStructReturnType(this, structType); } #endif // FEATURE_MULTIREG_RET @@ -16435,14 +16529,8 @@ bool GenTree::isContained() const else if (OperKind() & GTK_RELOP) { // We have to cast away const-ness since AsOp() method is non-const. - GenTree* childNode = const_cast(this)->AsOp()->gtOp1; - assert((isMarkedContained == false) || childNode->IsSIMDEqualityOrInequality()); - } - - // these either produce a result in register or set flags reg. - else if (IsSIMDEqualityOrInequality()) - { - assert(!isMarkedContained); + const GenTree* childNode = AsOp()->gtGetOp1(); + assert(isMarkedContained == false); } // if it's contained it can't be unused. @@ -17071,7 +17159,7 @@ GenTree* Compiler::gtGetSIMDZero(var_types simdType, var_types baseType, CORINFO // We only return the HWIntrinsicNode if SSE is supported, since it is possible for // the user to disable the SSE HWIntrinsic support via the COMPlus configuration knobs // even though the hardware vector types are still available. - return gtNewSimdHWIntrinsicNode(simdType, NI_Vector128_Zero, baseType, size); + return gtNewSimdHWIntrinsicNode(simdType, NI_Vector128_get_Zero, baseType, size); } return nullptr; case TYP_SIMD32: @@ -17080,7 +17168,7 @@ GenTree* Compiler::gtGetSIMDZero(var_types simdType, var_types baseType, CORINFO // We only return the HWIntrinsicNode if AVX is supported, since it is possible for // the user to disable the AVX HWIntrinsic support via the COMPlus configuration knobs // even though the hardware vector types are still available. - return gtNewSimdHWIntrinsicNode(simdType, NI_Vector256_Zero, baseType, size); + return gtNewSimdHWIntrinsicNode(simdType, NI_Vector256_get_Zero, baseType, size); } return nullptr; default: @@ -17140,6 +17228,12 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree) if (varTypeIsSIMD(tree)) { structHnd = gtGetStructHandleForSIMD(tree->gtType, TYP_FLOAT); +#ifdef FEATURE_HW_INTRINSICS + if (structHnd == NO_CLASS_HANDLE) + { + structHnd = gtGetStructHandleForHWSIMD(tree->gtType, TYP_FLOAT); + } +#endif } #endif break; @@ -17173,28 +17267,28 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree) } else { - GenTree* addr = tree->AsIndir()->Addr(); + GenTree* addr = tree->AsIndir()->Addr(); + FieldSeqNode* fieldSeq = nullptr; if ((addr->OperGet() == GT_ADD) && addr->gtGetOp2()->OperIs(GT_CNS_INT)) { - FieldSeqNode* fieldSeq = addr->gtGetOp2()->AsIntCon()->gtFieldSeq; - - if (fieldSeq != nullptr) - { - while (fieldSeq->m_next != nullptr) - { - fieldSeq = fieldSeq->m_next; - } - if (fieldSeq != FieldSeqStore::NotAField() && !fieldSeq->IsPseudoField()) - { - CORINFO_FIELD_HANDLE fieldHnd = fieldSeq->m_fieldHnd; - CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHnd, &structHnd); - assert(fieldCorType == CORINFO_TYPE_VALUECLASS); - } - } + fieldSeq = addr->gtGetOp2()->AsIntCon()->gtFieldSeq; } - else if (addr->OperGet() == GT_LCL_VAR) + else { - structHnd = gtGetStructHandleIfPresent(addr); + GetZeroOffsetFieldMap()->Lookup(addr, &fieldSeq); + } + if (fieldSeq != nullptr) + { + while (fieldSeq->m_next != nullptr) + { + fieldSeq = fieldSeq->m_next; + } + if (fieldSeq != FieldSeqStore::NotAField() && !fieldSeq->IsPseudoField()) + { + CORINFO_FIELD_HANDLE fieldHnd = fieldSeq->m_fieldHnd; + CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHnd, &structHnd); + assert(fieldCorType == CORINFO_TYPE_VALUECLASS); + } } } } @@ -17206,11 +17300,21 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleIfPresent(GenTree* tree) #endif // FEATURE_SIMD #ifdef FEATURE_HW_INTRINSICS case GT_HWINTRINSIC: - structHnd = gtGetStructHandleForHWSIMD(tree->gtType, tree->AsHWIntrinsic()->gtSIMDBaseType); + if ((tree->gtFlags & GTF_SIMDASHW_OP) != 0) + { + structHnd = gtGetStructHandleForSIMD(tree->gtType, tree->AsHWIntrinsic()->gtSIMDBaseType); + } + else + { + structHnd = gtGetStructHandleForHWSIMD(tree->gtType, tree->AsHWIntrinsic()->gtSIMDBaseType); + } break; #endif break; } + // TODO-1stClassStructs: add a check that `structHnd != NO_CLASS_HANDLE`, + // nowadays it won't work because the right part of an ASG could have struct type without a handle + // (check `fgMorphBlockOperand(isBlkReqd`) and a few other cases. } return structHnd; } @@ -18351,13 +18455,8 @@ bool GenTree::isCommutativeSIMDIntrinsic() case SIMDIntrinsicAdd: case SIMDIntrinsicBitwiseAnd: case SIMDIntrinsicBitwiseOr: - case SIMDIntrinsicBitwiseXor: case SIMDIntrinsicEqual: - case SIMDIntrinsicMax: - case SIMDIntrinsicMin: case SIMDIntrinsicMul: - case SIMDIntrinsicOpEquality: - case SIMDIntrinsicOpInEquality: return true; default: return false; @@ -18549,40 +18648,6 @@ GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode( GenTreeHWIntrinsic(type, gtNewArgList(op1, op2, op3), hwIntrinsicID, TYP_UNKNOWN, 0); } -//--------------------------------------------------------------------------------------- -// gtNewMustThrowException: -// create a throw node (calling into JIT helper) that must be thrown. -// The result would be a comma node: COMMA(jithelperthrow(void), x) where x's type should be specified. -// -// Arguments -// helper - JIT helper ID -// type - return type of the node -// -// Return Value -// pointer to the throw node -// -GenTree* Compiler::gtNewMustThrowException(unsigned helper, var_types type, CORINFO_CLASS_HANDLE clsHnd) -{ - GenTreeCall* node = gtNewHelperCallNode(helper, TYP_VOID); - node->gtCallMoreFlags |= GTF_CALL_M_DOES_NOT_RETURN; - if (type != TYP_VOID) - { - unsigned dummyTemp = lvaGrabTemp(true DEBUGARG("dummy temp of must thrown exception")); - if (type == TYP_STRUCT) - { - lvaSetStruct(dummyTemp, clsHnd, false); - type = lvaTable[dummyTemp].lvType; // struct type is normalized - } - else - { - lvaTable[dummyTemp].lvType = type; - } - GenTree* dummyNode = gtNewLclvNode(dummyTemp, type); - return gtNewOperNode(GT_COMMA, type, node, dummyNode); - } - return node; -} - // Returns true for the HW Instrinsic instructions that have MemoryLoad semantics, false otherwise bool GenTreeHWIntrinsic::OperIsMemoryLoad() const { @@ -18672,6 +18737,40 @@ bool GenTreeHWIntrinsic::OperIsMemoryLoadOrStore() const #endif // FEATURE_HW_INTRINSICS +//--------------------------------------------------------------------------------------- +// gtNewMustThrowException: +// create a throw node (calling into JIT helper) that must be thrown. +// The result would be a comma node: COMMA(jithelperthrow(void), x) where x's type should be specified. +// +// Arguments +// helper - JIT helper ID +// type - return type of the node +// +// Return Value +// pointer to the throw node +// +GenTree* Compiler::gtNewMustThrowException(unsigned helper, var_types type, CORINFO_CLASS_HANDLE clsHnd) +{ + GenTreeCall* node = gtNewHelperCallNode(helper, TYP_VOID); + node->gtCallMoreFlags |= GTF_CALL_M_DOES_NOT_RETURN; + if (type != TYP_VOID) + { + unsigned dummyTemp = lvaGrabTemp(true DEBUGARG("dummy temp of must thrown exception")); + if (type == TYP_STRUCT) + { + lvaSetStruct(dummyTemp, clsHnd, false); + type = lvaTable[dummyTemp].lvType; // struct type is normalized + } + else + { + lvaTable[dummyTemp].lvType = type; + } + GenTree* dummyNode = gtNewLclvNode(dummyTemp, type); + return gtNewOperNode(GT_COMMA, type, node, dummyNode); + } + return node; +} + //--------------------------------------------------------------------------------------- // InitializeStructReturnType: // Initialize the Return Type Descriptor for a method that returns a struct type @@ -18799,16 +18898,10 @@ void ReturnTypeDesc::InitializeStructReturnType(Compiler* comp, CORINFO_CLASS_HA // InitializeLongReturnType: // Initialize the Return Type Descriptor for a method that returns a TYP_LONG // -// Arguments -// comp - Compiler Instance -// -// Return Value -// None -// -void ReturnTypeDesc::InitializeLongReturnType(Compiler* comp) +void ReturnTypeDesc::InitializeLongReturnType() { + assert(!m_inited); #if defined(TARGET_X86) || defined(TARGET_ARM) - // Setups up a ReturnTypeDesc for returning a long using two registers // assert(MAX_RET_REG_COUNT >= 2); @@ -18840,7 +18933,7 @@ void ReturnTypeDesc::InitializeLongReturnType(Compiler* comp) // x86 and ARM return long in multiple registers. // ARM and ARM64 return HFA struct in multiple registers. // -regNumber ReturnTypeDesc::GetABIReturnReg(unsigned idx) +regNumber ReturnTypeDesc::GetABIReturnReg(unsigned idx) const { unsigned count = GetReturnRegCount(); assert(idx < count); @@ -18969,7 +19062,7 @@ regNumber ReturnTypeDesc::GetABIReturnReg(unsigned idx) // of return registers and wants to know the set of return registers. // // static -regMaskTP ReturnTypeDesc::GetABIReturnRegs() +regMaskTP ReturnTypeDesc::GetABIReturnRegs() const { regMaskTP resultMask = RBM_NONE; @@ -19042,3 +19135,20 @@ regNumber GenTree::ExtractTempReg(regMaskTP mask /* = (regMaskTP)-1 */) gtRsvdRegs &= ~tempRegMask; return genRegNumFromMask(tempRegMask); } + +#ifdef TARGET_ARM +//------------------------------------------------------------------------ +// IsOffsetMisaligned: check if the field needs a special handling on arm. +// +// Return Value: +// true if it is a float field with a misaligned offset, false otherwise. +// +bool GenTreeLclFld::IsOffsetMisaligned() const +{ + if (varTypeIsFloating(gtType)) + { + return ((m_lclOffs % emitTypeSize(TYP_FLOAT)) != 0); + } + return false; +} +#endif // TARGET_ARM diff --git a/src/coreclr/src/jit/gentree.h b/src/coreclr/src/jit/gentree.h index ad1e1e10146438..ec0cbee87192e4 100644 --- a/src/coreclr/src/jit/gentree.h +++ b/src/coreclr/src/jit/gentree.h @@ -732,23 +732,24 @@ struct GenTree #define GTF_NOREG_AT_USE 0x00000100 // tree node is in memory at the point of use -#define GTF_SET_FLAGS 0x00000800 // Requires that codegen for this node set the flags. Use gtSetFlags() to check this flag. -#define GTF_USE_FLAGS 0x00001000 // Indicates that this node uses the flags bits. +#define GTF_SET_FLAGS 0x00000200 // Requires that codegen for this node set the flags. Use gtSetFlags() to check this flag. +#define GTF_USE_FLAGS 0x00000400 // Indicates that this node uses the flags bits. -#define GTF_MAKE_CSE 0x00002000 // Hoisted expression: try hard to make this into CSE (see optPerformHoistExpr) -#define GTF_DONT_CSE 0x00004000 // Don't bother CSE'ing this expr -#define GTF_COLON_COND 0x00008000 // This node is conditionally executed (part of ? :) +#define GTF_MAKE_CSE 0x00000800 // Hoisted expression: try hard to make this into CSE (see optPerformHoistExpr) +#define GTF_DONT_CSE 0x00001000 // Don't bother CSE'ing this expr +#define GTF_COLON_COND 0x00002000 // This node is conditionally executed (part of ? :) #define GTF_NODE_MASK (GTF_COLON_COND) -#define GTF_BOOLEAN 0x00040000 // value is known to be 0/1 +#define GTF_BOOLEAN 0x00004000 // value is known to be 0/1 -#define GTF_UNSIGNED 0x00100000 // With GT_CAST: the source operand is an unsigned type +#define GTF_UNSIGNED 0x00008000 // With GT_CAST: the source operand is an unsigned type // With operators: the specified node is an unsigned operator -#define GTF_LATE_ARG 0x00200000 // The specified node is evaluated to a temp in the arg list, and this temp is added to gtCallLateArgs. -#define GTF_SPILL 0x00400000 // Needs to be spilled here + // +#define GTF_LATE_ARG 0x00010000 // The specified node is evaluated to a temp in the arg list, and this temp is added to gtCallLateArgs. +#define GTF_SPILL 0x00020000 // Needs to be spilled here -#define GTF_COMMON_MASK 0x007FFFFF // mask of all the flags above +#define GTF_COMMON_MASK 0x0003FFFF // mask of all the flags above #define GTF_REUSE_REG_VAL 0x00800000 // This is set by the register allocator on nodes whose value already exists in the // register assigned to this node, so the code generator does not have to generate @@ -766,25 +767,38 @@ struct GenTree // NB: GTF_VAR_* and GTF_REG_* share the same namespace of flags. // These flags are also used by GT_LCL_FLD. -#define GTF_VAR_DEF 0x80000000 // GT_LCL_VAR -- this is a definition -#define GTF_VAR_USEASG 0x40000000 // GT_LCL_VAR -- this is a partial definition, a use of the previous definition is implied - // A partial definition usually occurs when a struct field is assigned to (s.f = ...) or - // when a scalar typed variable is assigned to via a narrow store (*((byte*)&i) = ...). -#define GTF_VAR_CAST 0x10000000 // GT_LCL_VAR -- has been explictly cast (variable node may not be type of local) -#define GTF_VAR_ITERATOR 0x08000000 // GT_LCL_VAR -- this is a iterator reference in the loop condition -#define GTF_VAR_CLONED 0x01000000 // GT_LCL_VAR -- this node has been cloned or is a clone - // Relevant for inlining optimizations (see fgInlinePrependStatements) +#define GTF_VAR_DEF 0x80000000 // GT_LCL_VAR -- this is a definition +#define GTF_VAR_USEASG 0x40000000 // GT_LCL_VAR -- this is a partial definition, a use of the previous definition is implied + // A partial definition usually occurs when a struct field is assigned to (s.f = ...) or + // when a scalar typed variable is assigned to via a narrow store (*((byte*)&i) = ...). +// Last-use bits. +// Note that a node marked GTF_VAR_MULTIREG can only be a pure definition of all the fields, or a pure use of all the fields, +// so we don't need the equivalent of GTF_VAR_USEASG. + +#define GTF_VAR_MULTIREG_DEATH0 0x04000000 // GT_LCL_VAR -- The last-use bit for a lclVar (the first register if it is multireg). +#define GTF_VAR_DEATH GTF_VAR_MULTIREG_DEATH0 +#define GTF_VAR_MULTIREG_DEATH1 0x08000000 // GT_LCL_VAR -- The last-use bit for the second register of a multireg lclVar. +#define GTF_VAR_MULTIREG_DEATH2 0x10000000 // GT_LCL_VAR -- The last-use bit for the third register of a multireg lclVar. +#define GTF_VAR_MULTIREG_DEATH3 0x20000000 // GT_LCL_VAR -- The last-use bit for the fourth register of a multireg lclVar. +#define GTF_VAR_DEATH_MASK (GTF_VAR_MULTIREG_DEATH0|GTF_VAR_MULTIREG_DEATH1 | GTF_VAR_MULTIREG_DEATH2 | GTF_VAR_MULTIREG_DEATH3) +// This is the amount we have to shift, plus the regIndex, to get the last use bit we want. +#define MULTIREG_LAST_USE_SHIFT 26 +#define GTF_VAR_MULTIREG 0x02000000 // This is a struct or (on 32-bit platforms) long variable that is used or defined + // to/from a multireg source or destination (e.g. a call arg or return, or an op + // that returns its result in multiple registers such as a long multiply). + +#define GTF_LIVENESS_MASK (GTF_VAR_DEF | GTF_VAR_USEASG | GTF_VAR_DEATH_MASK) + +#define GTF_VAR_CAST 0x01000000 // GT_LCL_VAR -- has been explictly cast (variable node may not be type of local) +#define GTF_VAR_ITERATOR 0x00800000 // GT_LCL_VAR -- this is a iterator reference in the loop condition +#define GTF_VAR_CLONED 0x00400000 // GT_LCL_VAR -- this node has been cloned or is a clone +#define GTF_VAR_CONTEXT 0x00200000 // GT_LCL_VAR -- this node is part of a runtime lookup -// TODO-Cleanup: Currently, GTF_REG_BIRTH is used only by stackfp -// We should consider using it more generally for VAR_BIRTH, instead of -// GTF_VAR_DEF && !GTF_VAR_USEASG -#define GTF_REG_BIRTH 0x04000000 // GT_LCL_VAR, -- enregistered variable born here -#define GTF_VAR_DEATH 0x02000000 // GT_LCL_VAR, -- variable dies here (last use) + // Relevant for inlining optimizations (see fgInlinePrependStatements) #define GTF_VAR_ARR_INDEX 0x00000020 // The variable is part of (the index portion of) an array index expression. // Shares a value with GTF_REVERSE_OPS, which is meaningless for local var. -#define GTF_LIVENESS_MASK (GTF_VAR_DEF | GTF_VAR_USEASG | GTF_REG_BIRTH | GTF_VAR_DEATH) // For additional flags for GT_CALL node see GTF_CALL_M_* @@ -800,6 +814,8 @@ struct GenTree #define GTF_CALL_POP_ARGS 0x04000000 // GT_CALL -- caller pop arguments? #define GTF_CALL_HOISTABLE 0x02000000 // GT_CALL -- call is hoistable +#define GTF_MEMORYBARRIER_LOAD 0x40000000 // GT_MEMORYBARRIER -- Load barrier + #define GTF_NOP_DEATH 0x40000000 // GT_NOP -- operand dies here #define GTF_FLD_VOLATILE 0x40000000 // GT_FIELD/GT_CLS_VAR -- same as GTF_IND_VOLATILE @@ -899,6 +915,9 @@ struct GenTree #define GTF_SIMD12_OP 0x80000000 // GT_SIMD -- Indicates that the operands need to be handled as SIMD12 // even if they have been retyped as SIMD16. +#define GTF_SIMDASHW_OP 0x80000000 // GT_HWINTRINSIC -- Indicates that the structHandle should be gotten from gtGetStructHandleForSIMD + // rarther than from gtGetStructHandleForHWSIMD. + //--------------------------------------------------------------------- // // GenTree flags stored in gtDebugFlags. @@ -1627,11 +1646,10 @@ struct GenTree inline bool IsFPZero(); inline bool IsIntegralConst(ssize_t constVal); inline bool IsIntegralConstVector(ssize_t constVal); + inline bool IsSIMDZero(); inline bool IsBoxedValue(); - inline bool IsSIMDEqualityOrInequality() const; - static bool OperIsList(genTreeOps gtOper) { return gtOper == GT_LIST; @@ -1698,6 +1716,9 @@ struct GenTree // Returns true if it is a call node returning its value in more than one register inline bool IsMultiRegCall() const; + // Returns true if it is a struct lclVar node residing in multiple registers. + inline bool IsMultiRegLclVar() const; + // Returns true if it is a node returning its value in more than one register inline bool IsMultiRegNode() const; @@ -1710,6 +1731,9 @@ struct GenTree // Returns the type of the regIndex'th register defined by a multi-reg node. var_types GetRegTypeByIndex(int regIndex); + // Returns the GTF flag equivalent for the regIndex'th register of a multi-reg node. + unsigned int GetRegSpillFlagByIdx(int regIndex) const; + // Returns true if it is a GT_COPY or GT_RELOAD node inline bool IsCopyOrReload() const; @@ -1941,6 +1965,21 @@ struct GenTree ClearRegOptional(); } + bool CanCSE() const + { + return ((gtFlags & GTF_DONT_CSE) == 0); + } + + void SetDoNotCSE() + { + gtFlags |= GTF_DONT_CSE; + } + + void ClearDoNotCSE() + { + gtFlags &= ~GTF_DONT_CSE; + } + bool IsReverseOp() const { return (gtFlags & GTF_REVERSE_OPS) ? true : false; @@ -3108,12 +3147,195 @@ struct GenTreeLclVarCommon : public GenTreeUnOp #endif }; +//------------------------------------------------------------------------ +// MultiRegSpillFlags +// +// GTF_SPILL or GTF_SPILLED flag on a multi-reg node indicates that one or +// more of its result regs are in that state. The spill flags of each register +// are stored here. We only need 2 bits per returned register, +// so this is treated as a 2-bit array. No architecture needs more than 8 bits. +// +typedef unsigned char MultiRegSpillFlags; +static const unsigned PACKED_GTF_SPILL = 1; +static const unsigned PACKED_GTF_SPILLED = 2; + +//---------------------------------------------------------------------- +// GetMultiRegSpillFlagsByIdx: get spill flag associated with the return register +// specified by its index. +// +// Arguments: +// idx - Position or index of the return register +// +// Return Value: +// Returns GTF_* flags associated with the register. Only GTF_SPILL and GTF_SPILLED are considered. +// +inline unsigned GetMultiRegSpillFlagsByIdx(MultiRegSpillFlags flags, unsigned idx) +{ + static_assert_no_msg(MAX_RET_REG_COUNT * 2 <= sizeof(unsigned char) * BITS_PER_BYTE); + assert(idx < MAX_RET_REG_COUNT); + + unsigned bits = flags >> (idx * 2); // It doesn't matter that we possibly leave other high bits here. + unsigned spillFlags = 0; + if (bits & PACKED_GTF_SPILL) + { + spillFlags |= GTF_SPILL; + } + if (bits & PACKED_GTF_SPILLED) + { + spillFlags |= GTF_SPILLED; + } + return spillFlags; +} + +//---------------------------------------------------------------------- +// SetMultiRegSpillFlagsByIdx: set spill flags for the register specified by its index. +// +// Arguments: +// oldFlags - The current value of the MultiRegSpillFlags for a node. +// flagsToSet - GTF_* flags. Only GTF_SPILL and GTF_SPILLED are allowed. +// Note that these are the flags used on non-multireg nodes, +// and this method adds the appropriate flags to the +// incoming MultiRegSpillFlags and returns it. +// idx - Position or index of the register +// +// Return Value: +// The new value for the node's MultiRegSpillFlags. +// +inline MultiRegSpillFlags SetMultiRegSpillFlagsByIdx(MultiRegSpillFlags oldFlags, unsigned flagsToSet, unsigned idx) +{ + static_assert_no_msg(MAX_RET_REG_COUNT * 2 <= sizeof(unsigned char) * BITS_PER_BYTE); + assert(idx < MAX_RET_REG_COUNT); + + MultiRegSpillFlags newFlags = oldFlags; + unsigned bits = 0; + if (flagsToSet & GTF_SPILL) + { + bits |= PACKED_GTF_SPILL; + } + if (flagsToSet & GTF_SPILLED) + { + bits |= PACKED_GTF_SPILLED; + } + + const unsigned char packedFlags = PACKED_GTF_SPILL | PACKED_GTF_SPILLED; + + // Clear anything that was already there by masking out the bits before 'or'ing in what we want there. + newFlags = (unsigned char)((newFlags & ~(packedFlags << (idx * 2))) | (bits << (idx * 2))); + return newFlags; +} + // gtLclVar -- load/store/addr of local variable struct GenTreeLclVar : public GenTreeLclVarCommon { +private: + regNumberSmall gtOtherReg[MAX_MULTIREG_COUNT - 1]; + MultiRegSpillFlags gtSpillFlags; + unsigned int GetLastUseBit(int regIndex) + { + assert(regIndex < 4); + static_assert_no_msg((1 << MULTIREG_LAST_USE_SHIFT) == GTF_VAR_MULTIREG_DEATH0); + return (1 << (MULTIREG_LAST_USE_SHIFT + regIndex)); + } + +public: INDEBUG(IL_OFFSET gtLclILoffs;) // instr offset of ref (only for JIT dumps) + // Multireg support + bool IsMultiReg() const + { + return ((gtFlags & GTF_VAR_MULTIREG) != 0); + } + void ClearMultiReg() + { + gtFlags &= ~GTF_VAR_MULTIREG; + } + void SetMultiReg() + { + gtFlags |= GTF_VAR_MULTIREG; + ClearOtherRegFlags(); + } + + regNumber GetRegNumByIdx(int regIndex) + { + assert(regIndex < MAX_MULTIREG_COUNT); + return (regIndex == 0) ? GetRegNum() : (regNumber)gtOtherReg[regIndex - 1]; + } + + void SetRegNumByIdx(regNumber reg, int regIndex) + { + assert(regIndex < MAX_MULTIREG_COUNT); + if (regIndex == 0) + { + SetRegNum(reg); + } + else + { + gtOtherReg[regIndex - 1] = regNumberSmall(reg); + } + } + + bool IsLastUse(int regIndex) + { + return (gtFlags & GetLastUseBit(regIndex)) != 0; + } + + bool HasLastUse() + { + return (gtFlags & (GTF_VAR_DEATH_MASK)) != 0; + } + + void SetLastUse(int regIndex) + { + unsigned int bitToSet = gtFlags |= GetLastUseBit(regIndex); + } + + void ClearLastUse(int regIndex) + { + gtFlags &= ~GetLastUseBit(regIndex); + } + + unsigned GetRegSpillFlagByIdx(unsigned idx) const + { + return GetMultiRegSpillFlagsByIdx(gtSpillFlags, idx); + } + + void SetRegSpillFlagByIdx(unsigned flags, unsigned idx) + { + gtSpillFlags = SetMultiRegSpillFlagsByIdx(gtSpillFlags, flags, idx); + } + + unsigned int GetFieldCount(Compiler* compiler); + var_types GetFieldTypeByIndex(Compiler* compiler, unsigned idx); + + //------------------------------------------------------------------- + // clearOtherRegFlags: clear GTF_* flags associated with gtOtherRegs + // + // Arguments: + // None + // + // Return Value: + // None + void ClearOtherRegFlags() + { + gtSpillFlags = 0; + } + + //------------------------------------------------------------------------- + // CopyOtherRegFlags: copy GTF_* flags associated with gtOtherRegs from + // the given LclVar node. + // + // Arguments: + // fromCall - GenTreeLclVar node from which to copy + // + // Return Value: + // None + // + void CopyOtherRegFlags(GenTreeLclVar* from) + { + this->gtSpillFlags = from->gtSpillFlags; + } + GenTreeLclVar(genTreeOps oper, var_types type, unsigned lclNum DEBUGARG(IL_OFFSET ilOffs = BAD_IL_OFFSET) DEBUGARG(bool largeNode = false)) @@ -3165,6 +3387,10 @@ struct GenTreeLclFld : public GenTreeLclVarCommon m_fieldSeq = fieldSeq; } +#ifdef TARGET_ARM + bool IsOffsetMisaligned() const; +#endif // TARGET_ARM + #if DEBUGGABLE_GENTREE GenTreeLclFld() : GenTreeLclVarCommon() { @@ -3378,8 +3604,8 @@ struct ReturnTypeDesc void InitializeStructReturnType(Compiler* comp, CORINFO_CLASS_HANDLE retClsHnd); // Initialize the Return Type Descriptor for a method that returns a TYP_LONG - // Only needed for X86 - void InitializeLongReturnType(Compiler* comp); + // Only needed for X86 and arm32. + void InitializeLongReturnType(); // Reset type descriptor to defaults void Reset() @@ -3458,6 +3684,7 @@ struct ReturnTypeDesc } else { + assert(m_inited); return ((m_regType[0] != TYP_UNKNOWN) && (m_regType[1] != TYP_UNKNOWN)); } } @@ -3473,7 +3700,7 @@ struct ReturnTypeDesc // var_type of the return register specified by its index. // asserts if the index does not have a valid register return type. - var_types GetReturnRegType(unsigned index) + var_types GetReturnRegType(unsigned index) const { var_types result = m_regType[index]; assert(result != TYP_UNKNOWN); @@ -3489,10 +3716,70 @@ struct ReturnTypeDesc } // Get ith ABI return register - regNumber GetABIReturnReg(unsigned idx); + regNumber GetABIReturnReg(unsigned idx) const; // Get reg mask of ABI return registers - regMaskTP GetABIReturnRegs(); + regMaskTP GetABIReturnRegs() const; +}; + +class TailCallSiteInfo +{ + bool m_isCallvirt : 1; + bool m_isCalli : 1; + CORINFO_SIG_INFO m_sig; + CORINFO_RESOLVED_TOKEN m_token; + +public: + // Is the tailcall a callvirt instruction? + bool IsCallvirt() + { + return m_isCallvirt; + } + + // Is the tailcall a calli instruction? + bool IsCalli() + { + return m_isCalli; + } + + // Get the token of the callee + CORINFO_RESOLVED_TOKEN* GetToken() + { + assert(!IsCalli()); + return &m_token; + } + + // Get the signature of the callee + CORINFO_SIG_INFO* GetSig() + { + return &m_sig; + } + + // Mark the tailcall as a calli with the given signature + void SetCalli(CORINFO_SIG_INFO* sig) + { + m_isCallvirt = false; + m_isCalli = true; + m_sig = *sig; + } + + // Mark the tailcall as a callvirt with the given signature and token + void SetCallvirt(CORINFO_SIG_INFO* sig, CORINFO_RESOLVED_TOKEN* token) + { + m_isCallvirt = true; + m_isCalli = false; + m_sig = *sig; + m_token = *token; + } + + // Mark the tailcall as a call with the given signature and token + void SetCall(CORINFO_SIG_INFO* sig, CORINFO_RESOLVED_TOKEN* token) + { + m_isCallvirt = false; + m_isCalli = false; + m_sig = *sig; + m_token = *token; + } }; class fgArgInfo; @@ -3626,14 +3913,16 @@ struct GenTreeCall final : public GenTree regList regArgList; #endif - // TODO-Throughput: Revisit this (this used to be only defined if - // FEATURE_FIXED_OUT_ARGS was enabled, so this makes GenTreeCall 4 bytes bigger on x86). - CORINFO_SIG_INFO* callSig; // Used by tail calls and to register callsites with the EE +#ifdef DEBUG + // Used to register callsites with the EE + CORINFO_SIG_INFO* callSig; +#endif + + TailCallSiteInfo* tailCallInfo; #if FEATURE_MULTIREG_RET // State required to support multi-reg returning call nodes. - // For now it is enabled only for x64 unix. // // TODO-AllArch: enable for all call nodes to unify single-reg and multi-reg returns. ReturnTypeDesc gtReturnTypeDesc; @@ -3642,14 +3931,7 @@ struct GenTreeCall final : public GenTree // The following array holds the other reg numbers of multi-reg return. regNumberSmall gtOtherRegs[MAX_RET_REG_COUNT - 1]; - // GTF_SPILL or GTF_SPILLED flag on a multi-reg call node indicates that one or - // more of its result regs are in that state. The spill flag of each of the - // return register is stored here. We only need 2 bits per returned register, - // so this is treated as a 2-bit array. No architecture needs more than 8 bits. - - static const unsigned PACKED_GTF_SPILL = 1; - static const unsigned PACKED_GTF_SPILLED = 2; - unsigned char gtSpillFlags; + MultiRegSpillFlags gtSpillFlags; #endif // FEATURE_MULTIREG_RET @@ -3662,12 +3944,8 @@ struct GenTreeCall final : public GenTree // Returns // Type descriptor of the value returned by call // - // Note: - // Right now implemented only for x64 unix and yet to be - // implemented for other multi-reg target arch (Arm64/Arm32/x86). - // // TODO-AllArch: enable for all call nodes to unify single-reg and multi-reg returns. - ReturnTypeDesc* GetReturnTypeDesc() + const ReturnTypeDesc* GetReturnTypeDesc() const { #if FEATURE_MULTIREG_RET return >ReturnTypeDesc; @@ -3676,6 +3954,27 @@ struct GenTreeCall final : public GenTree #endif } + void InitializeLongReturnType() + { +#if FEATURE_MULTIREG_RET + gtReturnTypeDesc.InitializeLongReturnType(); +#endif + } + + void InitializeStructReturnType(Compiler* comp, CORINFO_CLASS_HANDLE retClsHnd) + { +#if FEATURE_MULTIREG_RET + gtReturnTypeDesc.InitializeStructReturnType(comp, retClsHnd); +#endif + } + + void ResetReturnType() + { +#if FEATURE_MULTIREG_RET + gtReturnTypeDesc.Reset(); +#endif + } + //--------------------------------------------------------------------------- // GetRegNumByIdx: get ith return register allocated to this call node. // @@ -3772,72 +4071,20 @@ struct GenTreeCall final : public GenTree // Get reg mask of all the valid registers of gtOtherRegs array regMaskTP GetOtherRegMask() const; - //---------------------------------------------------------------------- - // GetRegSpillFlagByIdx: get spill flag associated with the return register - // specified by its index. - // - // Arguments: - // idx - Position or index of the return register - // - // Return Value: - // Returns GTF_* flags associated with the register. Only GTF_SPILL and GTF_SPILLED are considered. - // unsigned GetRegSpillFlagByIdx(unsigned idx) const { - static_assert_no_msg(MAX_RET_REG_COUNT * 2 <= sizeof(unsigned char) * BITS_PER_BYTE); - assert(idx < MAX_RET_REG_COUNT); - #if FEATURE_MULTIREG_RET - unsigned bits = gtSpillFlags >> (idx * 2); // It doesn't matter that we possibly leave other high bits here. - unsigned spillFlags = 0; - if (bits & PACKED_GTF_SPILL) - { - spillFlags |= GTF_SPILL; - } - if (bits & PACKED_GTF_SPILLED) - { - spillFlags |= GTF_SPILLED; - } - return spillFlags; + return GetMultiRegSpillFlagsByIdx(gtSpillFlags, idx); #else assert(!"unreached"); return 0; #endif } - //---------------------------------------------------------------------- - // SetRegSpillFlagByIdx: set spill flags for the return register - // specified by its index. - // - // Arguments: - // flags - GTF_* flags. Only GTF_SPILL and GTF_SPILLED are allowed. - // idx - Position or index of the return register - // - // Return Value: - // None - // void SetRegSpillFlagByIdx(unsigned flags, unsigned idx) { - static_assert_no_msg(MAX_RET_REG_COUNT * 2 <= sizeof(unsigned char) * BITS_PER_BYTE); - assert(idx < MAX_RET_REG_COUNT); - #if FEATURE_MULTIREG_RET - unsigned bits = 0; - if (flags & GTF_SPILL) - { - bits |= PACKED_GTF_SPILL; - } - if (flags & GTF_SPILLED) - { - bits |= PACKED_GTF_SPILLED; - } - - const unsigned char packedFlags = PACKED_GTF_SPILL | PACKED_GTF_SPILLED; - - // Clear anything that was already there by masking out the bits before 'or'ing in what we want there. - gtSpillFlags = (unsigned char)((gtSpillFlags & ~(packedFlags << (idx * 2))) | (bits << (idx * 2))); -#else - unreached(); + gtSpillFlags = SetMultiRegSpillFlagsByIdx(gtSpillFlags, flags, idx); #endif } @@ -3891,7 +4138,7 @@ struct GenTreeCall final : public GenTree #define GTF_CALL_M_NONVIRT_SAME_THIS 0x00000080 // GT_CALL -- callee "this" pointer is // equal to caller this pointer (only for GTF_CALL_NONVIRT) #define GTF_CALL_M_FRAME_VAR_DEATH 0x00000100 // GT_CALL -- the compLvFrameListRoot variable dies here (last use) -#define GTF_CALL_M_TAILCALL_VIA_HELPER 0x00000200 // GT_CALL -- call is a tail call dispatched via tail call JIT helper. +#define GTF_CALL_M_TAILCALL_VIA_JIT_HELPER 0x00000200 // GT_CALL -- call is a tail call dispatched via tail call JIT helper. #if FEATURE_TAILCALL_OPT #define GTF_CALL_M_IMPLICIT_TAILCALL 0x00000400 // GT_CALL -- call is an opportunistic @@ -3955,6 +4202,16 @@ struct GenTreeCall final : public GenTree return (gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0; } + bool IsR2ROrVirtualStubRelativeIndir() + { +#if defined(FEATURE_READYTORUN_COMPILER) && defined(TARGET_ARMARCH) + bool isVirtualStub = (gtFlags & GTF_CALL_VIRT_KIND_MASK) == GTF_CALL_VIRT_STUB; + return ((IsR2RRelativeIndir()) || (isVirtualStub && (IsVirtualStubRelativeIndir()))); +#else + return false; +#endif // FEATURE_READYTORUN_COMPILER && TARGET_ARMARCH + } + bool HasNonStandardAddedArgs(Compiler* compiler) const; int GetNonStandardAddedArgCount(Compiler* compiler) const; @@ -3994,18 +4251,29 @@ struct GenTreeCall final : public GenTree // bool HasMultiRegRetVal() const { -#if defined(TARGET_X86) - return varTypeIsLong(gtType); -#elif FEATURE_MULTIREG_RET && defined(TARGET_ARM) - return varTypeIsLong(gtType) || (varTypeIsStruct(gtType) && !HasRetBufArg()); +#ifdef FEATURE_MULTIREG_RET +#if defined(TARGET_X86) || defined(TARGET_ARM) + if (varTypeIsLong(gtType)) + { + return true; + } #elif defined(FEATURE_HFA) && defined(TARGET_ARM64) // SIMD types are returned in vector regs on ARM64. - return (gtType == TYP_STRUCT) && !HasRetBufArg(); -#elif FEATURE_MULTIREG_RET - return varTypeIsStruct(gtType) && !HasRetBufArg(); -#else + if (varTypeIsSIMD(gtType)) + { + return false; + } +#endif // FEATURE_HFA && TARGET_ARM64 + + if (!varTypeIsStruct(gtType) || HasRetBufArg()) + { + return false; + } + // Now it is a struct that is returned in registers. + return GetReturnTypeDesc()->IsMultiRegRetType(); +#else // !FEATURE_MULTIREG_RET return false; -#endif +#endif // !FEATURE_MULTIREG_RET } // Returns true if VM has flagged this method as CORINFO_FLG_PINVOKE. @@ -4036,15 +4304,26 @@ struct GenTreeCall final : public GenTree return IsTailPrefixedCall() || IsImplicitTailCall(); } - bool IsTailCallViaHelper() const + // Check whether this is a tailcall dispatched via JIT helper. We only use + // this mechanism on x86 as it is faster than our other more general + // tailcall mechanism. + bool IsTailCallViaJitHelper() const { - return IsTailCall() && (gtCallMoreFlags & GTF_CALL_M_TAILCALL_VIA_HELPER); +#ifdef TARGET_X86 + return IsTailCall() && (gtCallMoreFlags & GTF_CALL_M_TAILCALL_VIA_JIT_HELPER); +#else + return false; +#endif } #if FEATURE_FASTTAILCALL bool IsFastTailCall() const { - return IsTailCall() && !(gtCallMoreFlags & GTF_CALL_M_TAILCALL_VIA_HELPER); +#ifdef TARGET_X86 + return IsTailCall() && !(gtCallMoreFlags & GTF_CALL_M_TAILCALL_VIA_JIT_HELPER); +#else + return IsTailCall(); +#endif } #else // !FEATURE_FASTTAILCALL bool IsFastTailCall() const @@ -4291,9 +4570,7 @@ struct GenTreeMultiRegOp : public GenTreeOp // return register is stored here. We only need 2 bits per returned register, // so this is treated as a 2-bit array. No architecture needs more than 8 bits. - static const unsigned PACKED_GTF_SPILL = 1; - static const unsigned PACKED_GTF_SPILLED = 2; - unsigned char gtSpillFlags; + MultiRegSpillFlags gtSpillFlags; GenTreeMultiRegOp(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2) : GenTreeOp(oper, type, op1, op2), gtOtherReg(REG_NA) @@ -4303,11 +4580,7 @@ struct GenTreeMultiRegOp : public GenTreeOp unsigned GetRegCount() const { - if (GetRegNum() == REG_NA || GetRegNum() == REG_STK) - { - return 0; - } - return (gtOtherReg == REG_NA || gtOtherReg == REG_STK) ? 1 : 2; + return (TypeGet() == TYP_LONG) ? 2 : 1; } //--------------------------------------------------------------------------- @@ -4331,63 +4604,16 @@ struct GenTreeMultiRegOp : public GenTreeOp return gtOtherReg; } - //---------------------------------------------------------------------- - // GetRegSpillFlagByIdx: get spill flag associated with the register - // specified by its index. - // - // Arguments: - // idx - Position or index of the register - // - // Return Value: - // Returns GTF_* flags associated with the register. Only GTF_SPILL and GTF_SPILLED are considered. - // unsigned GetRegSpillFlagByIdx(unsigned idx) const { - assert(idx < MAX_REG_ARG); - - unsigned bits = gtSpillFlags >> (idx * 2); // It doesn't matter that we possibly leave other high bits here. - unsigned spillFlags = 0; - if (bits & PACKED_GTF_SPILL) - { - spillFlags |= GTF_SPILL; - } - if (bits & PACKED_GTF_SPILLED) - { - spillFlags |= GTF_SPILLED; - } - - return spillFlags; + return GetMultiRegSpillFlagsByIdx(gtSpillFlags, idx); } - //---------------------------------------------------------------------- - // SetRegSpillFlagByIdx: set spill flags for the register - // specified by its index. - // - // Arguments: - // flags - GTF_* flags. Only GTF_SPILL and GTF_SPILLED are allowed. - // idx - Position or index of the register - // - // Return Value: - // None - // void SetRegSpillFlagByIdx(unsigned flags, unsigned idx) { - assert(idx < MAX_REG_ARG); - - unsigned bits = 0; - if (flags & GTF_SPILL) - { - bits |= PACKED_GTF_SPILL; - } - if (flags & GTF_SPILLED) - { - bits |= PACKED_GTF_SPILLED; - } - - const unsigned char packedFlags = PACKED_GTF_SPILL | PACKED_GTF_SPILLED; - - // Clear anything that was already there by masking out the bits before 'or'ing in what we want there. - gtSpillFlags = (unsigned char)((gtSpillFlags & ~(packedFlags << (idx * 2))) | (bits << (idx * 2))); +#if FEATURE_MULTIREG_RET + gtSpillFlags = SetMultiRegSpillFlagsByIdx(gtSpillFlags, flags, idx); +#endif } //-------------------------------------------------------------------------- @@ -4447,6 +4673,10 @@ struct GenTreeFptrVal : public GenTree GenTreeFptrVal(var_types type, CORINFO_METHOD_HANDLE meth) : GenTree(GT_FTN_ADDR, type), gtFptrMethod(meth) { +#ifdef FEATURE_READYTORUN_COMPILER + gtEntryPoint.addr = nullptr; + gtEntryPoint.accessType = IAT_VALUE; +#endif } #if DEBUGGABLE_GENTREE GenTreeFptrVal() : GenTree() @@ -4501,12 +4731,65 @@ struct GenTreeIntrinsic : public GenTreeOp struct GenTreeJitIntrinsic : public GenTreeOp { - var_types gtSIMDBaseType; // SIMD vector base type - unsigned gtSIMDSize; // SIMD vector size in bytes, use 0 for scalar intrinsics +private: + ClassLayout* m_layout; + + union { + var_types gtOtherBaseType; // For AVX2 Gather* intrinsics + regNumberSmall gtOtherReg; // For intrinsics that return 2 registers + }; + +public: + var_types gtSIMDBaseType; // SIMD vector base type + unsigned char gtSIMDSize; // SIMD vector size in bytes, use 0 for scalar intrinsics + +#if defined(FEATURE_SIMD) + union { + SIMDIntrinsicID gtSIMDIntrinsicID; // operation Id + NamedIntrinsic gtHWIntrinsicId; + }; +#else + NamedIntrinsic gtHWIntrinsicId; +#endif + + ClassLayout* GetLayout() const + { + return m_layout; + } + + void SetLayout(ClassLayout* layout) + { + assert(layout != nullptr); + m_layout = layout; + } + + regNumber GetOtherReg() const + { + return (regNumber)gtOtherReg; + } + void SetOtherReg(regNumber reg) + { + gtOtherReg = (regNumberSmall)reg; + assert(gtOtherReg == reg); + } + + var_types GetOtherBaseType() const + { + return gtOtherBaseType; + } + + void SetOtherBaseType(var_types type) + { + gtOtherBaseType = type; + } GenTreeJitIntrinsic(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2, var_types baseType, unsigned size) - : GenTreeOp(oper, type, op1, op2), gtSIMDBaseType(baseType), gtSIMDSize(size) + : GenTreeOp(oper, type, op1, op2) + , gtSIMDBaseType(baseType) + , gtSIMDSize((unsigned char)size) + , gtHWIntrinsicId(NI_Illegal) { + assert(gtSIMDSize == size); } bool isSIMD() const @@ -4526,17 +4809,18 @@ struct GenTreeJitIntrinsic : public GenTreeOp /* gtSIMD -- SIMD intrinsic (possibly-binary op [NULL op2 is allowed] with additional fields) */ struct GenTreeSIMD : public GenTreeJitIntrinsic { - SIMDIntrinsicID gtSIMDIntrinsicID; // operation Id GenTreeSIMD(var_types type, GenTree* op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size) - : GenTreeJitIntrinsic(GT_SIMD, type, op1, nullptr, baseType, size), gtSIMDIntrinsicID(simdIntrinsicID) + : GenTreeJitIntrinsic(GT_SIMD, type, op1, nullptr, baseType, size) { + gtSIMDIntrinsicID = simdIntrinsicID; } GenTreeSIMD( var_types type, GenTree* op1, GenTree* op2, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size) - : GenTreeJitIntrinsic(GT_SIMD, type, op1, op2, baseType, size), gtSIMDIntrinsicID(simdIntrinsicID) + : GenTreeJitIntrinsic(GT_SIMD, type, op1, op2, baseType, size) { + gtSIMDIntrinsicID = simdIntrinsicID; } bool OperIsMemoryLoad() const; // Returns true for the SIMD Instrinsic instructions that have MemoryLoad semantics, @@ -4553,21 +4837,16 @@ struct GenTreeSIMD : public GenTreeJitIntrinsic #ifdef FEATURE_HW_INTRINSICS struct GenTreeHWIntrinsic : public GenTreeJitIntrinsic { - NamedIntrinsic gtHWIntrinsicId; - var_types gtIndexBaseType; // for AVX2 Gather* intrinsics - GenTreeHWIntrinsic(var_types type, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size) : GenTreeJitIntrinsic(GT_HWINTRINSIC, type, nullptr, nullptr, baseType, size) - , gtHWIntrinsicId(hwIntrinsicID) - , gtIndexBaseType(TYP_UNKNOWN) { + gtHWIntrinsicId = hwIntrinsicID; } GenTreeHWIntrinsic(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size) : GenTreeJitIntrinsic(GT_HWINTRINSIC, type, op1, nullptr, baseType, size) - , gtHWIntrinsicId(hwIntrinsicID) - , gtIndexBaseType(TYP_UNKNOWN) { + gtHWIntrinsicId = hwIntrinsicID; if (OperIsMemoryStore()) { gtFlags |= (GTF_GLOB_REF | GTF_ASG); @@ -4577,9 +4856,8 @@ struct GenTreeHWIntrinsic : public GenTreeJitIntrinsic GenTreeHWIntrinsic( var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size) : GenTreeJitIntrinsic(GT_HWINTRINSIC, type, op1, op2, baseType, size) - , gtHWIntrinsicId(hwIntrinsicID) - , gtIndexBaseType(TYP_UNKNOWN) { + gtHWIntrinsicId = hwIntrinsicID; if (OperIsMemoryStore()) { gtFlags |= (GTF_GLOB_REF | GTF_ASG); @@ -5808,13 +6086,7 @@ struct GenTreePutArgSplit : public GenTreePutArgStk // gtOtherRegs holds the other reg numbers of struct. regNumberSmall gtOtherRegs[MAX_REG_ARG - 1]; - // GTF_SPILL or GTF_SPILLED flag on a multi-reg struct node indicates that one or - // more of its result regs are in that state. The spill flag of each of the - // return register is stored here. We only need 2 bits per register, - // so this is treated as a 2-bit array. - static const unsigned PACKED_GTF_SPILL = 1; - static const unsigned PACKED_GTF_SPILLED = 2; - unsigned char gtSpillFlags; + MultiRegSpillFlags gtSpillFlags; //--------------------------------------------------------------------------- // GetRegNumByIdx: get ith register allocated to this struct argument. @@ -5878,63 +6150,16 @@ struct GenTreePutArgSplit : public GenTreePutArgStk } } - //---------------------------------------------------------------------- - // GetRegSpillFlagByIdx: get spill flag associated with the register - // specified by its index. - // - // Arguments: - // idx - Position or index of the register - // - // Return Value: - // Returns GTF_* flags associated with the register. Only GTF_SPILL and GTF_SPILLED are considered. - // unsigned GetRegSpillFlagByIdx(unsigned idx) const { - assert(idx < MAX_REG_ARG); - - unsigned bits = gtSpillFlags >> (idx * 2); // It doesn't matter that we possibly leave other high bits here. - unsigned spillFlags = 0; - if (bits & PACKED_GTF_SPILL) - { - spillFlags |= GTF_SPILL; - } - if (bits & PACKED_GTF_SPILLED) - { - spillFlags |= GTF_SPILLED; - } - - return spillFlags; + return GetMultiRegSpillFlagsByIdx(gtSpillFlags, idx); } - //---------------------------------------------------------------------- - // SetRegSpillFlagByIdx: set spill flags for the register - // specified by its index. - // - // Arguments: - // flags - GTF_* flags. Only GTF_SPILL and GTF_SPILLED are allowed. - // idx - Position or index of the register - // - // Return Value: - // None - // void SetRegSpillFlagByIdx(unsigned flags, unsigned idx) { - assert(idx < MAX_REG_ARG); - - unsigned bits = 0; - if (flags & GTF_SPILL) - { - bits |= PACKED_GTF_SPILL; - } - if (flags & GTF_SPILLED) - { - bits |= PACKED_GTF_SPILLED; - } - - const unsigned char packedFlags = PACKED_GTF_SPILL | PACKED_GTF_SPILLED; - - // Clear anything that was already there by masking out the bits before 'or'ing in what we want there. - gtSpillFlags = (unsigned char)((gtSpillFlags & ~(packedFlags << (idx * 2))) | (bits << (idx * 2))); +#if FEATURE_MULTIREG_RET + gtSpillFlags = SetMultiRegSpillFlagsByIdx(gtSpillFlags, flags, idx); +#endif } //-------------------------------------------------------------------------- @@ -6582,30 +6807,79 @@ inline bool GenTree::IsIntegralConstVector(ssize_t constVal) assert(gtGetOp2IfPresent() == nullptr); return true; } -#endif +#endif // FEATURE_SIMD - return false; -} +#ifdef FEATURE_HW_INTRINSICS + if (gtOper == GT_HWINTRINSIC) + { + GenTreeHWIntrinsic* node = AsHWIntrinsic(); -inline bool GenTree::IsBoxedValue() -{ - assert(gtOper != GT_BOX || AsBox()->BoxOp() != nullptr); - return (gtOper == GT_BOX) && (gtFlags & GTF_BOX_VALUE); + if (!varTypeIsIntegral(node->gtSIMDBaseType)) + { + // Can't be an integral constant + return false; + } + + GenTree* op1 = gtGetOp1(); + GenTree* op2 = gtGetOp2(); + + NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; + + if (op1 == nullptr) + { + assert(op2 == nullptr); + + if (constVal == 0) + { +#if defined(TARGET_XARCH) + return (intrinsicId == NI_Vector128_get_Zero) || (intrinsicId == NI_Vector256_get_Zero); +#elif defined(TARGET_ARM64) + return (intrinsicId == NI_Vector64_get_Zero) || (intrinsicId == NI_Vector128_get_Zero); +#endif // !TARGET_XARCH && !TARGET_ARM64 + } + } + else if ((op2 == nullptr) && !op1->OperIsList()) + { + if (op1->IsIntegralConst(constVal)) + { +#if defined(TARGET_XARCH) + return (intrinsicId == NI_Vector128_Create) || (intrinsicId == NI_Vector256_Create); +#elif defined(TARGET_ARM64) + return (intrinsicId == NI_Vector64_Create) || (intrinsicId == NI_Vector128_Create); +#endif // !TARGET_XARCH && !TARGET_ARM64 + } + } + } +#endif // FEATURE_HW_INTRINSICS + + return false; } -inline bool GenTree::IsSIMDEqualityOrInequality() const +//------------------------------------------------------------------- +// IsSIMDZero: returns true if this this is a SIMD vector +// with all its elements equal to zero. +// +// Returns: +// True if this represents an integral const SIMD vector. +// +inline bool GenTree::IsSIMDZero() { #ifdef FEATURE_SIMD - if (gtOper == GT_SIMD) + if ((gtOper == GT_SIMD) && (AsSIMD()->gtSIMDIntrinsicID == SIMDIntrinsicInit)) { - SIMDIntrinsicID id = AsSIMD()->gtSIMDIntrinsicID; - return (id == SIMDIntrinsicOpEquality) || (id == SIMDIntrinsicOpInEquality); + return (gtGetOp1()->IsIntegralConst(0) || gtGetOp1()->IsFPZero()); } #endif return false; } +inline bool GenTree::IsBoxedValue() +{ + assert(gtOper != GT_BOX || AsBox()->BoxOp() != nullptr); + return (gtOper == GT_BOX) && (gtFlags & GTF_BOX_VALUE); +} + inline GenTree* GenTree::MoveNext() { assert(OperIsAnyList()); @@ -6821,6 +7095,15 @@ inline bool GenTree::IsMultiRegCall() const return false; } +inline bool GenTree::IsMultiRegLclVar() const +{ + if (OperIs(GT_LCL_VAR, GT_STORE_LCL_VAR)) + { + return AsLclVar()->IsMultiReg(); + } + return false; +} + //----------------------------------------------------------------------------------- // IsMultiRegNode: whether a node returning its value in more than one register // @@ -6862,6 +7145,16 @@ inline bool GenTree::IsMultiRegNode() const return true; } #endif // FEATURE_MULTIREG_RET +#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) + if (OperIs(GT_HWINTRINSIC)) + { + return (TypeGet() == TYP_STRUCT); + } +#endif + if (IsMultiRegLclVar()) + { + return true; + } return false; } //----------------------------------------------------------------------------------- @@ -6873,11 +7166,6 @@ inline bool GenTree::IsMultiRegNode() const // Return Value: // Returns the number of registers defined by this node. // -// Notes: -// All targets that support multi-reg ops of any kind also support multi-reg return -// values for calls. Should that change with a future target, this method will need -// to change accordingly. -// inline unsigned GenTree::GetMultiRegCount() { #if FEATURE_MULTIREG_RET @@ -6905,6 +7193,24 @@ inline unsigned GenTree::GetMultiRegCount() return AsCopyOrReload()->GetRegCount(); } #endif // FEATURE_MULTIREG_RET +#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) + if (OperIs(GT_HWINTRINSIC)) + { + assert(TypeGet() == TYP_STRUCT); + return 2; + } +#endif + if (OperIs(GT_LCL_VAR, GT_STORE_LCL_VAR)) + { + assert((gtFlags & GTF_VAR_MULTIREG) != 0); + // The register count for a multireg lclVar requires looking at the LclVarDsc, + // which requires a Compiler instance. The caller must handle this separately. + // The register count for a multireg lclVar requires looking at the LclVarDsc, + // which requires a Compiler instance. The caller must use the GetFieldCount + // method on GenTreeLclVar. + + assert(!"MultiRegCount for LclVar"); + } assert(!"GetMultiRegCount called with non-multireg node"); return 1; } @@ -6956,6 +7262,17 @@ inline regNumber GenTree::GetRegByIndex(int regIndex) return AsCopyOrReload()->GetRegNumByIdx(regIndex); } #endif // FEATURE_MULTIREG_RET +#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) + if (OperIs(GT_HWINTRINSIC)) + { + assert(regIndex == 1); + return AsHWIntrinsic()->GetOtherReg(); + } +#endif + if (OperIs(GT_LCL_VAR, GT_STORE_LCL_VAR)) + { + return AsLclVar()->GetRegNumByIdx(regIndex); + } assert(!"Invalid regIndex for GetRegFromMultiRegNode"); return REG_NA; @@ -7001,10 +7318,89 @@ inline var_types GenTree::GetRegTypeByIndex(int regIndex) #endif #endif // FEATURE_MULTIREG_RET + +#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) + if (OperIs(GT_HWINTRINSIC)) + { + // At this time, the only multi-reg HW intrinsics all return the type of their + // arguments. If this changes, we will need a way to record or determine this. + assert(TypeGet() == TYP_STRUCT); + return gtGetOp1()->TypeGet(); + } +#endif + if (OperIs(GT_LCL_VAR, GT_STORE_LCL_VAR)) + { + if (TypeGet() == TYP_LONG) + { + return TYP_INT; + } + assert(TypeGet() == TYP_STRUCT); + assert((gtFlags & GTF_VAR_MULTIREG) != 0); + // The register type for a multireg lclVar requires looking at the LclVarDsc, + // which requires a Compiler instance. The caller must use the GetFieldTypeByIndex + // on GenTreeLclVar. + assert(!"GetRegTypeByIndex for LclVar"); + } + assert(!"Invalid node type for GetRegTypeByIndex"); return TYP_UNDEF; } +//----------------------------------------------------------------------------------- +// GetRegSpillFlagByIdx: Get a specific register's spill flags, based on regIndex, +// for this multi-reg node. +// +// Arguments: +// regIndex - which register's spill flags to return +// +// Return Value: +// The spill flags (GTF_SPILL GTF_SPILLED) for this register. +// +// Notes: +// This must be a multireg node and 'regIndex' must be a valid index for this node. +// This method returns the GTF "equivalent" flags based on the packed flags on the multireg node. +// +inline unsigned int GenTree::GetRegSpillFlagByIdx(int regIndex) const +{ +#if FEATURE_MULTIREG_RET + if (IsMultiRegCall()) + { + return AsCall()->AsCall()->GetRegSpillFlagByIdx(regIndex); + } + +#if FEATURE_ARG_SPLIT + if (OperIsPutArgSplit()) + { + return AsPutArgSplit()->GetRegSpillFlagByIdx(regIndex); + } +#endif +#if !defined(TARGET_64BIT) + if (OperIsMultiRegOp()) + { + return AsMultiRegOp()->GetRegSpillFlagByIdx(regIndex); + } +#endif + +#endif // FEATURE_MULTIREG_RET + +#if defined(TARGET_XARCH) && defined(FEATURE_HW_INTRINSICS) + if (OperIs(GT_HWINTRINSIC)) + { + // At this time, the only multi-reg HW intrinsics all return the type of their + // arguments. If this changes, we will need a way to record or determine this. + assert(TypeGet() == TYP_STRUCT); + return gtGetOp1()->TypeGet(); + } +#endif + if (OperIs(GT_LCL_VAR, GT_STORE_LCL_VAR)) + { + return AsLclVar()->GetRegSpillFlagByIdx(regIndex); + } + + assert(!"Invalid node type for GetRegSpillFlagByIdx"); + return TYP_UNDEF; +} + //------------------------------------------------------------------------- // IsCopyOrReload: whether this is a GT_COPY or GT_RELOAD node. // diff --git a/src/coreclr/src/jit/hwintrinsic.cpp b/src/coreclr/src/jit/hwintrinsic.cpp index 65792decbcb6c5..16332b859894b6 100644 --- a/src/coreclr/src/jit/hwintrinsic.cpp +++ b/src/coreclr/src/jit/hwintrinsic.cpp @@ -10,12 +10,12 @@ static const HWIntrinsicInfo hwIntrinsicInfoArray[] = { // clang-format off #if defined(TARGET_XARCH) -#define HARDWARE_INTRINSIC(id, name, isa, ival, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \ - {NI_##id, name, InstructionSet_##isa, ival, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, static_cast(flag)}, +#define HARDWARE_INTRINSIC(isa, name, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \ + {NI_##isa##_##name, #name, InstructionSet_##isa, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, static_cast(flag)}, #include "hwintrinsiclistxarch.h" #elif defined (TARGET_ARM64) -#define HARDWARE_INTRINSIC(isa, name, ival, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \ - {NI_##isa##_##name, #name, InstructionSet_##isa, ival, static_cast(size), numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, static_cast(flag)}, +#define HARDWARE_INTRINSIC(isa, name, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \ + {NI_##isa##_##name, #name, InstructionSet_##isa, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, static_cast(flag)}, #include "hwintrinsiclistarm64.h" #else #error Unsupported platform @@ -59,8 +59,6 @@ var_types Compiler::getBaseTypeFromArgIfNeeded(NamedIntrinsic intrinsic, CORINFO_SIG_INFO* sig, var_types baseType) { - HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsic); - if (HWIntrinsicInfo::BaseTypeFromSecondArg(intrinsic) || HWIntrinsicInfo::BaseTypeFromFirstArg(intrinsic)) { CORINFO_ARG_LIST_HANDLE arg = sig->args; @@ -91,50 +89,6 @@ var_types Compiler::getBaseTypeFromArgIfNeeded(NamedIntrinsic intrinsic, return baseType; } -//------------------------------------------------------------------------ -// impUnsupportedHWIntrinsic: returns a node for an unsupported HWIntrinsic -// -// Arguments: -// helper - JIT helper ID for the exception to be thrown -// method - method handle of the intrinsic function. -// sig - signature of the intrinsic call -// mustExpand - true if the intrinsic must return a GenTree*; otherwise, false -// -// Return Value: -// a gtNewMustThrowException if mustExpand is true; otherwise, nullptr -// -GenTree* Compiler::impUnsupportedHWIntrinsic(unsigned helper, - CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* sig, - bool mustExpand) -{ - // We've hit some error case and may need to return a node for the given error. - // - // When `mustExpand=false`, we are attempting to inline the intrinsic directly into another method. In this - // scenario, we need to return `nullptr` so that a GT_CALL to the intrinsic is emitted instead. This is to - // ensure that everything continues to behave correctly when optimizations are enabled (e.g. things like the - // inliner may expect the node we return to have a certain signature, and the `MustThrowException` node won't - // match that). - // - // When `mustExpand=true`, we are in a GT_CALL to the intrinsic and are attempting to JIT it. This will generally - // be in response to an indirect call (e.g. done via reflection) or in response to an earlier attempt returning - // `nullptr` (under `mustExpand=false`). In that scenario, we are safe to return the `MustThrowException` node. - - if (mustExpand) - { - for (unsigned i = 0; i < sig->numArgs; i++) - { - impPopStack(); - } - - return gtNewMustThrowException(helper, JITtype2varType(sig->retType), sig->retTypeClass); - } - else - { - return nullptr; - } -} - CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleForHWSIMD(var_types simdType, var_types simdBaseType) { if (simdType == TYP_SIMD16) @@ -202,6 +156,8 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleForHWSIMD(var_types simdType, va { case TYP_FLOAT: return m_simdHandleCache->Vector64FloatHandle; + case TYP_DOUBLE: + return m_simdHandleCache->Vector64DoubleHandle; case TYP_INT: return m_simdHandleCache->Vector64IntHandle; case TYP_USHORT: @@ -214,6 +170,10 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleForHWSIMD(var_types simdType, va return m_simdHandleCache->Vector64ByteHandle; case TYP_UINT: return m_simdHandleCache->Vector64UIntHandle; + case TYP_LONG: + return m_simdHandleCache->Vector64LongHandle; + case TYP_ULONG: + return m_simdHandleCache->Vector64ULongHandle; default: assert(!"Didn't find a class handle for simdType"); } @@ -223,7 +183,6 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleForHWSIMD(var_types simdType, va return NO_CLASS_HANDLE; } -#ifdef FEATURE_HW_INTRINSICS //------------------------------------------------------------------------ // vnEncodesResultTypeForHWIntrinsic(NamedIntrinsic hwIntrinsicID): // @@ -284,22 +243,24 @@ CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleForHWSIMD(var_types simdType, va // If we see two (or more) different instructions we need the extra VNF_SimdType arg return (diffInsCount >= 2); } -#endif // FEATURE_HW_INTRINSICS //------------------------------------------------------------------------ // lookupId: Gets the NamedIntrinsic for a given method name and InstructionSet // // Arguments: +// comp -- The compiler +// sig -- The signature of the intrinsic // className -- The name of the class associated with the HWIntrinsic to lookup // methodName -- The name of the method associated with the HWIntrinsic to lookup // enclosingClassName -- The name of the enclosing class of X64 classes // // Return Value: // The NamedIntrinsic associated with methodName and isa -NamedIntrinsic HWIntrinsicInfo::lookupId(Compiler* comp, - const char* className, - const char* methodName, - const char* enclosingClassName) +NamedIntrinsic HWIntrinsicInfo::lookupId(Compiler* comp, + CORINFO_SIG_INFO* sig, + const char* className, + const char* methodName, + const char* enclosingClassName) { // TODO-Throughput: replace sequential search by binary search CORINFO_InstructionSet isa = lookupIsa(className, enclosingClassName); @@ -322,14 +283,23 @@ NamedIntrinsic HWIntrinsicInfo::lookupId(Compiler* comp, for (int i = 0; i < (NI_HW_INTRINSIC_END - NI_HW_INTRINSIC_START - 1); i++) { + const HWIntrinsicInfo& intrinsicInfo = hwIntrinsicInfoArray[i]; + if (isa != hwIntrinsicInfoArray[i].isa) { continue; } - if (strcmp(methodName, hwIntrinsicInfoArray[i].name) == 0) + int numArgs = static_cast(intrinsicInfo.numArgs); + + if ((numArgs != -1) && (sig->numArgs != static_cast(intrinsicInfo.numArgs))) { - return hwIntrinsicInfoArray[i].id; + continue; + } + + if (strcmp(methodName, intrinsicInfo.name) == 0) + { + return intrinsicInfo.id; } } @@ -353,9 +323,11 @@ NamedIntrinsic HWIntrinsicInfo::lookupId(Compiler* comp, // get the SIMD size from the GenTreeHWIntrinsic node. unsigned HWIntrinsicInfo::lookupSimdSize(Compiler* comp, NamedIntrinsic id, CORINFO_SIG_INFO* sig) { - if (HWIntrinsicInfo::HasFixedSimdSize(id)) + unsigned simdSize = 0; + + if (tryLookupSimdSize(id, &simdSize)) { - return lookupSimdSize(id); + return simdSize; } CORINFO_CLASS_HANDLE typeHnd = nullptr; @@ -375,7 +347,6 @@ unsigned HWIntrinsicInfo::lookupSimdSize(Compiler* comp, NamedIntrinsic id, CORI typeHnd = sig->retTypeSigClass; } - unsigned simdSize = 0; var_types baseType = comp->getBaseTypeAndSizeOfSIMDType(typeHnd, &simdSize); assert((simdSize > 0) && (baseType != TYP_UNKNOWN)); return simdSize; @@ -498,26 +469,30 @@ bool HWIntrinsicInfo::isImmOp(NamedIntrinsic id, const GenTree* op) } //------------------------------------------------------------------------ -// // getArgForHWIntrinsic: pop an argument from the stack and validate its type +// getArgForHWIntrinsic: pop an argument from the stack and validate its type // // Arguments: -// argType -- the required type of argument -// argClass -- the class handle of argType +// argType -- the required type of argument +// argClass -- the class handle of argType +// expectAddr -- if true indicates we are expecting type stack entry to be a TYP_BYREF. // // Return Value: // the validated argument // -GenTree* Compiler::getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE argClass) +GenTree* Compiler::getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE argClass, bool expectAddr) { GenTree* arg = nullptr; - if (argType == TYP_STRUCT) + if (varTypeIsStruct(argType)) { - unsigned int argSizeBytes; - var_types base = getBaseTypeAndSizeOfSIMDType(argClass, &argSizeBytes); - argType = getSIMDTypeForSize(argSizeBytes); - assert((argType == TYP_SIMD8) || (argType == TYP_SIMD16) || (argType == TYP_SIMD32)); - arg = impSIMDPopStack(argType); - assert((arg->TypeGet() == TYP_SIMD8) || (arg->TypeGet() == TYP_SIMD16) || (arg->TypeGet() == TYP_SIMD32)); + if (!varTypeIsSIMD(argType)) + { + unsigned int argSizeBytes; + var_types base = getBaseTypeAndSizeOfSIMDType(argClass, &argSizeBytes); + argType = getSIMDTypeForSize(argSizeBytes); + } + assert(varTypeIsSIMD(argType)); + arg = impSIMDPopStack(argType, expectAddr); + assert(varTypeIsSIMD(arg->TypeGet())); } else { @@ -533,15 +508,18 @@ GenTree* Compiler::getArgForHWIntrinsic(var_types argType, CORINFO_CLASS_HANDLE // addRangeCheckIfNeeded: add a GT_HW_INTRINSIC_CHK node for non-full-range imm-intrinsic // // Arguments: -// intrinsic -- intrinsic ID -// immOP -- the last operand of the intrinsic that points to the imm-arg -// mustExpand -- true if the compiler is compiling the fallback(GT_CALL) of this intrinsics +// intrinsic -- intrinsic ID +// immOp -- the immediate operand of the intrinsic +// mustExpand -- true if the compiler is compiling the fallback(GT_CALL) of this intrinsics +// immLowerBound -- lower incl. bound for a value of the immediate operand (for a non-full-range imm-intrinsic) +// immUpperBound -- upper incl. bound for a value of the immediate operand (for a non-full-range imm-intrinsic) // // Return Value: // add a GT_HW_INTRINSIC_CHK node for non-full-range imm-intrinsic, which would throw ArgumentOutOfRangeException // when the imm-argument is not in the valid range // -GenTree* Compiler::addRangeCheckIfNeeded(NamedIntrinsic intrinsic, GenTree* immOp, bool mustExpand) +GenTree* Compiler::addRangeCheckIfNeeded( + NamedIntrinsic intrinsic, GenTree* immOp, bool mustExpand, int immLowerBound, int immUpperBound) { assert(immOp != nullptr); // Full-range imm-intrinsics do not need the range-check @@ -555,19 +533,37 @@ GenTree* Compiler::addRangeCheckIfNeeded(NamedIntrinsic intrinsic, GenTree* immO ) { assert(!immOp->IsCnsIntOrI()); - GenTree* upperBoundNode = gtNewIconNode(HWIntrinsicInfo::lookupImmUpperBound(intrinsic), TYP_INT); - GenTree* index = nullptr; - if ((immOp->gtFlags & GTF_SIDE_EFFECT) != 0) - { - index = fgInsertCommaFormTemp(&immOp); - } - else + assert(varTypeIsUnsigned(immOp)); + + // Bounds check for value of an immediate operand + // (immLowerBound <= immOp) && (immOp <= immUpperBound) + // + // implemented as a single comparison in the form of + // + // if ((immOp - immLowerBound) >= (immUpperBound - immLowerBound + 1)) + // { + // throw new ArgumentOutOfRangeException(); + // } + // + // The value of (immUpperBound - immLowerBound + 1) is denoted as adjustedUpperBound. + + const ssize_t adjustedUpperBound = (ssize_t)immUpperBound - immLowerBound + 1; + GenTree* adjustedUpperBoundNode = gtNewIconNode(adjustedUpperBound, TYP_INT); + + GenTree* immOpDup = nullptr; + + immOp = impCloneExpr(immOp, &immOpDup, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone an immediate operand for immediate value bounds check")); + + if (immLowerBound != 0) { - index = gtCloneExpr(immOp); + immOpDup = gtNewOperNode(GT_SUB, TYP_INT, immOpDup, gtNewIconNode(immLowerBound, TYP_INT)); } + GenTreeBoundsChk* hwIntrinsicChk = new (this, GT_HW_INTRINSIC_CHK) - GenTreeBoundsChk(GT_HW_INTRINSIC_CHK, TYP_VOID, index, upperBoundNode, SCK_RNGCHK_FAIL); + GenTreeBoundsChk(GT_HW_INTRINSIC_CHK, TYP_VOID, immOpDup, adjustedUpperBoundNode, SCK_RNGCHK_FAIL); hwIntrinsicChk->gtThrowKind = SCK_ARG_RNG_EXCPN; + return gtNewOperNode(GT_COMMA, immOp->TypeGet(), hwIntrinsicChk, immOp); } else @@ -610,6 +606,67 @@ static bool impIsTableDrivenHWIntrinsic(NamedIntrinsic intrinsicId, HWIntrinsicC !HWIntrinsicInfo::HasSpecialImport(intrinsicId); } +//------------------------------------------------------------------------ +// isSupportedBaseType +// +// Arguments: +// intrinsicId - HW intrinsic id +// baseType - Base type of the intrinsic. +// +// Return Value: +// returns true if the baseType is supported for given intrinsic. +// +static bool isSupportedBaseType(NamedIntrinsic intrinsic, var_types baseType) +{ + // We don't actually check the intrinsic outside of the false case as we expect + // the exposed managed signatures are either generic and support all types + // or they are explicit and support the type indicated. + if (varTypeIsArithmetic(baseType)) + { + return true; + } + +#ifdef TARGET_XARCH + assert((intrinsic == NI_Vector128_As) || (intrinsic == NI_Vector128_AsByte) || + (intrinsic == NI_Vector128_AsDouble) || (intrinsic == NI_Vector128_AsInt16) || + (intrinsic == NI_Vector128_AsInt32) || (intrinsic == NI_Vector128_AsInt64) || + (intrinsic == NI_Vector128_AsSByte) || (intrinsic == NI_Vector128_AsSingle) || + (intrinsic == NI_Vector128_AsUInt16) || (intrinsic == NI_Vector128_AsUInt32) || + (intrinsic == NI_Vector128_AsUInt64) || (intrinsic == NI_Vector128_get_AllBitsSet) || + (intrinsic == NI_Vector128_get_Count) || (intrinsic == NI_Vector128_get_Zero) || + (intrinsic == NI_Vector128_GetElement) || (intrinsic == NI_Vector128_WithElement) || + (intrinsic == NI_Vector128_ToScalar) || (intrinsic == NI_Vector128_ToVector256) || + (intrinsic == NI_Vector128_ToVector256Unsafe) || (intrinsic == NI_Vector256_As) || + (intrinsic == NI_Vector256_AsByte) || (intrinsic == NI_Vector256_AsDouble) || + (intrinsic == NI_Vector256_AsInt16) || (intrinsic == NI_Vector256_AsInt32) || + (intrinsic == NI_Vector256_AsInt64) || (intrinsic == NI_Vector256_AsSByte) || + (intrinsic == NI_Vector256_AsSingle) || (intrinsic == NI_Vector256_AsUInt16) || + (intrinsic == NI_Vector256_AsUInt32) || (intrinsic == NI_Vector256_AsUInt64) || + (intrinsic == NI_Vector256_get_AllBitsSet) || (intrinsic == NI_Vector256_get_Count) || + (intrinsic == NI_Vector256_get_Zero) || (intrinsic == NI_Vector256_GetElement) || + (intrinsic == NI_Vector256_WithElement) || (intrinsic == NI_Vector256_GetLower) || + (intrinsic == NI_Vector256_ToScalar)); +#else + assert((intrinsic == NI_Vector64_AsByte) || (intrinsic == NI_Vector64_AsInt16) || + (intrinsic == NI_Vector64_AsInt32) || (intrinsic == NI_Vector64_AsSByte) || + (intrinsic == NI_Vector64_AsSingle) || (intrinsic == NI_Vector64_AsUInt16) || + (intrinsic == NI_Vector64_AsUInt32) || (intrinsic == NI_Vector64_get_AllBitsSet) || + (intrinsic == NI_Vector64_get_Count) || (intrinsic == NI_Vector64_get_Zero) || + (intrinsic == NI_Vector64_GetElement) || (intrinsic == NI_Vector64_ToScalar) || + (intrinsic == NI_Vector64_ToVector128) || (intrinsic == NI_Vector64_ToVector128Unsafe) || + (intrinsic == NI_Vector128_As) || (intrinsic == NI_Vector128_AsByte) || + (intrinsic == NI_Vector128_AsDouble) || (intrinsic == NI_Vector128_AsInt16) || + (intrinsic == NI_Vector128_AsInt32) || (intrinsic == NI_Vector128_AsInt64) || + (intrinsic == NI_Vector128_AsSByte) || (intrinsic == NI_Vector128_AsSingle) || + (intrinsic == NI_Vector128_AsUInt16) || (intrinsic == NI_Vector128_AsUInt32) || + (intrinsic == NI_Vector128_AsUInt64) || (intrinsic == NI_Vector128_get_AllBitsSet) || + (intrinsic == NI_Vector128_get_Count) || (intrinsic == NI_Vector128_get_Zero) || + (intrinsic == NI_Vector128_GetElement) || (intrinsic == NI_Vector128_GetLower) || + (intrinsic == NI_Vector128_ToScalar)); +#endif + return false; +} + //------------------------------------------------------------------------ // impHWIntrinsic: Import a hardware intrinsic as a GT_HWINTRINSIC node if possible // @@ -641,32 +698,79 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, baseType = getBaseTypeAndSizeOfSIMDType(sig->retTypeSigClass, &sizeBytes); retType = getSIMDTypeForSize(sizeBytes); assert(sizeBytes != 0); + + // We want to return early here for cases where retType was TYP_STRUCT as per method signature and + // rather than deferring the decision after getting the baseType of arg. + if (!isSupportedBaseType(intrinsic, baseType)) + { + return nullptr; + } + } + + baseType = getBaseTypeFromArgIfNeeded(intrinsic, clsHnd, sig, baseType); + + if (baseType == TYP_UNKNOWN) + { + if (category != HW_Category_Scalar) + { + unsigned int sizeBytes; + baseType = getBaseTypeAndSizeOfSIMDType(clsHnd, &sizeBytes); + assert((category == HW_Category_Special) || (sizeBytes != 0)); + } + else + { + baseType = retType; + } + } + + // Immediately return if the category is other than scalar/special and this is not a supported base type. + if ((category != HW_Category_Special) && (category != HW_Category_Scalar) && + !isSupportedBaseType(intrinsic, baseType)) + { + return nullptr; + } + + unsigned simdSize = HWIntrinsicInfo::lookupSimdSize(this, intrinsic, sig); + + GenTree* immOp = nullptr; + +#ifdef TARGET_ARM64 + if (intrinsic == NI_AdvSimd_Insert) + { + assert(sig->numArgs == 3); + immOp = impStackTop(1).val; + assert(HWIntrinsicInfo::isImmOp(intrinsic, immOp)); + } + else +#endif + if ((sig->numArgs > 0) && HWIntrinsicInfo::isImmOp(intrinsic, impStackTop().val)) + { + // NOTE: The following code assumes that for all intrinsics + // taking an immediate operand, that operand will be last. + immOp = impStackTop().val; } - // NOTE: The following code assumes that for all intrinsics - // taking an immediate operand, that operand will be last. - if (sig->numArgs > 0 && HWIntrinsicInfo::isImmOp(intrinsic, impStackTop().val)) + if (immOp != nullptr) { - GenTree* lastOp = impStackTop().val; - // The imm-HWintrinsics that do not accept all imm8 values may throw - // ArgumentOutOfRangeException when the imm argument is not in the valid range - if (!HWIntrinsicInfo::HasFullRangeImm(intrinsic)) + if (!HWIntrinsicInfo::HasFullRangeImm(intrinsic) && immOp->IsCnsIntOrI()) { - if (!mustExpand && lastOp->IsCnsIntOrI() && - !HWIntrinsicInfo::isInImmRange(intrinsic, (int)lastOp->AsIntCon()->IconValue())) + const int ival = (int)immOp->AsIntCon()->IconValue(); + + if (!HWIntrinsicInfo::isInImmRange(intrinsic, ival, simdSize, baseType)) { + assert(!mustExpand); + // The imm-HWintrinsics that do not accept all imm8 values may throw + // ArgumentOutOfRangeException when the imm argument is not in the valid range return nullptr; } } - - if (!lastOp->IsCnsIntOrI()) + else if (!immOp->IsCnsIntOrI()) { if (HWIntrinsicInfo::NoJmpTableImm(intrinsic)) { return impNonConstFallback(intrinsic, retType, baseType); } - - if (!mustExpand) + else if (!mustExpand) { // When the imm-argument is not a constant and we are not being forced to expand, we need to // return nullptr so a GT_CALL to the intrinsic method is emitted instead. The @@ -687,14 +791,25 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, // table-driven importer of simple intrinsics if (impIsTableDrivenHWIntrinsic(intrinsic, category)) { - baseType = getBaseTypeFromArgIfNeeded(intrinsic, clsHnd, sig, baseType); - unsigned simdSize = HWIntrinsicInfo::lookupSimdSize(this, intrinsic, sig); bool isScalar = category == HW_Category_Scalar; CORINFO_ARG_LIST_HANDLE argList = sig->args; var_types argType = TYP_UNKNOWN; CORINFO_CLASS_HANDLE argClass; + int immLowerBound = 0; + int immUpperBound = 0; + + if (immOp != nullptr) + { +#if defined(TARGET_XARCH) + immUpperBound = HWIntrinsicInfo::lookupImmUpperBound(intrinsic); +#elif defined(TARGET_ARM64) + HWIntrinsicInfo::lookupImmBounds(intrinsic, simdSize, baseType, &immLowerBound, &immUpperBound); +#endif + } + assert(numArgs >= 0); + if (!isScalar && ((HWIntrinsicInfo::lookupIns(intrinsic, baseType) == INS_invalid) || ((simdSize != 8) && (simdSize != 16) && (simdSize != 32)))) { @@ -742,7 +857,7 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg2, &argClass))); op2 = getArgForHWIntrinsic(argType, argClass); - op2 = addRangeCheckIfNeeded(intrinsic, op2, mustExpand); + op2 = addRangeCheckIfNeeded(intrinsic, op2, mustExpand, immLowerBound, immUpperBound); argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, argList, &argClass))); op1 = getArgForHWIntrinsic(argType, argClass); @@ -764,6 +879,13 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, // to the code generator. May encode the overload info in other way. retNode->AsHWIntrinsic()->gtSIMDBaseType = JITtype2varType(corType); } +#ifdef TARGET_ARM64 + if ((intrinsic == NI_AdvSimd_AddWideningUpper) || (intrinsic == NI_AdvSimd_SubtractWideningUpper)) + { + assert(varTypeIsSIMD(op1->TypeGet())); + retNode->AsHWIntrinsic()->SetOtherBaseType(getBaseTypeOfSIMDType(argClass)); + } +#endif break; } @@ -775,8 +897,6 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg3, &argClass))); GenTree* op3 = getArgForHWIntrinsic(argType, argClass); - op3 = addRangeCheckIfNeeded(intrinsic, op3, mustExpand); - argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg2, &argClass))); op2 = getArgForHWIntrinsic(argType, argClass); @@ -785,6 +905,17 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, argList, &argClass))); op1 = getArgForHWIntrinsic(argType, argClass); +#ifdef TARGET_ARM64 + if (intrinsic == NI_AdvSimd_Insert) + { + op2 = addRangeCheckIfNeeded(intrinsic, op2, mustExpand, immLowerBound, immUpperBound); + } + else +#endif + { + op3 = addRangeCheckIfNeeded(intrinsic, op3, mustExpand, immLowerBound, immUpperBound); + } + retNode = isScalar ? gtNewScalarHWIntrinsicNode(retType, op1, op2, op3, intrinsic) : gtNewSimdHWIntrinsicNode(retType, op1, op2, op3, intrinsic, baseType, simdSize); @@ -792,7 +923,7 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, if (intrinsic == NI_AVX2_GatherVector128 || intrinsic == NI_AVX2_GatherVector256) { assert(varTypeIsSIMD(op2->TypeGet())); - retNode->AsHWIntrinsic()->gtIndexBaseType = getBaseTypeOfSIMDType(op2ArgClass); + retNode->AsHWIntrinsic()->SetOtherBaseType(getBaseTypeOfSIMDType(op2ArgClass)); } #endif break; @@ -820,7 +951,7 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, return retNode; } - return impSpecialIntrinsic(intrinsic, clsHnd, method, sig); + return impSpecialIntrinsic(intrinsic, clsHnd, method, sig, baseType, retType, simdSize); } #endif // FEATURE_HW_INTRINSICS diff --git a/src/coreclr/src/jit/hwintrinsic.h b/src/coreclr/src/jit/hwintrinsic.h index 488e77f8278d90..34a92d858e43dc 100644 --- a/src/coreclr/src/jit/hwintrinsic.h +++ b/src/coreclr/src/jit/hwintrinsic.h @@ -55,76 +55,202 @@ enum HWIntrinsicFlag : unsigned int // NoCodeGen // - should be transformed in the compiler front-end, cannot reach CodeGen - HW_Flag_NoCodeGen = 0x8, - - // Unfixed SIMD-size - // - overloaded on multiple vector sizes (SIMD size in the table is unreliable) - HW_Flag_UnfixedSIMDSize = 0x10, + HW_Flag_NoCodeGen = 0x4, // Multi-instruction // - that one intrinsic can generate multiple instructions - HW_Flag_MultiIns = 0x20, - - // NoContainment - // the intrinsic cannot be handled by comtainment, - // all the intrinsic that have explicit memory load/store semantics should have this flag - HW_Flag_NoContainment = 0x40, - - // Copy Upper bits - // some SIMD scalar intrinsics need the semantics of copying upper bits from the source operand - HW_Flag_CopyUpperBits = 0x80, + HW_Flag_MultiIns = 0x8, // Select base type using the first argument type - HW_Flag_BaseTypeFromFirstArg = 0x100, + HW_Flag_BaseTypeFromFirstArg = 0x10, + + // Select base type using the second argument type + HW_Flag_BaseTypeFromSecondArg = 0x20, // Indicates compFloatingPointUsed does not need to be set. - HW_Flag_NoFloatingPointUsed = 0x200, + HW_Flag_NoFloatingPointUsed = 0x40, // Maybe IMM // the intrinsic has either imm or Vector overloads - HW_Flag_MaybeIMM = 0x400, + HW_Flag_MaybeIMM = 0x80, // NoJmpTable IMM // the imm intrinsic does not need jumptable fallback when it gets non-const argument - HW_Flag_NoJmpTableIMM = 0x800, - - // Select base type using the second argument type - HW_Flag_BaseTypeFromSecondArg = 0x1000, + HW_Flag_NoJmpTableIMM = 0x100, // Special codegen // the intrinsics need special rules in CodeGen, // but may be table-driven in the front-end - HW_Flag_SpecialCodeGen = 0x2000, + HW_Flag_SpecialCodeGen = 0x200, + // Special import + // the intrinsics need special rules in importer, + // but may be table-driven in the back-end + HW_Flag_SpecialImport = 0x400, + +// The below is for defining platform-specific flags #if defined(TARGET_XARCH) + // Copy Upper bits + // some SIMD scalar intrinsics need the semantics of copying upper bits from the source operand + HW_Flag_CopyUpperBits = 0x800, + + // Maybe Memory Load/Store + // - some intrinsics may have pointer overloads but without HW_Category_MemoryLoad/HW_Category_MemoryStore + HW_Flag_MaybeMemoryLoad = 0x1000, + HW_Flag_MaybeMemoryStore = 0x2000, + // No Read/Modify/Write Semantics // the intrinsic doesn't have read/modify/write semantics in two/three-operand form. HW_Flag_NoRMWSemantics = 0x4000, + + // NoContainment + // the intrinsic cannot be handled by comtainment, + // all the intrinsic that have explicit memory load/store semantics should have this flag + HW_Flag_NoContainment = 0x8000, + #elif defined(TARGET_ARM64) // The intrinsic has read/modify/write semantics in multiple-operands form. - HW_Flag_HasRMWSemantics = 0x4000, + HW_Flag_HasRMWSemantics = 0x800, + + // The intrinsic supports some sort of containment analysis. + HW_Flag_SupportsContainment = 0x1000, #else #error Unsupported platform #endif +}; - // Special import - // the intrinsics need special rules in importer, - // but may be table-driven in the back-end - HW_Flag_SpecialImport = 0x8000, +#if defined(TARGET_XARCH) +// This mirrors the System.Runtime.Intrinsics.X86.FloatComparisonMode enumeration +enum class FloatComparisonMode : unsigned char +{ + // _CMP_EQ_OQ + OrderedEqualNonSignaling = 0, - // Maybe Memory Load/Store - // - some intrinsics may have pointer overloads but without HW_Category_MemoryLoad/HW_Category_MemoryStore - HW_Flag_MaybeMemoryLoad = 0x10000, - HW_Flag_MaybeMemoryStore = 0x20000, + // _CMP_LT_OS + OrderedLessThanSignaling = 1, + + // _CMP_LE_OS + OrderedLessThanOrEqualSignaling = 2, + + // _CMP_UNORD_Q + UnorderedNonSignaling = 3, + + // _CMP_NEQ_UQ + UnorderedNotEqualNonSignaling = 4, + + // _CMP_NLT_US + UnorderedNotLessThanSignaling = 5, + + // _CMP_NLE_US + UnorderedNotLessThanOrEqualSignaling = 6, + + // _CMP_ORD_Q + OrderedNonSignaling = 7, + + // _CMP_EQ_UQ + UnorderedEqualNonSignaling = 8, + + // _CMP_NGE_US + UnorderedNotGreaterThanOrEqualSignaling = 9, + + // _CMP_NGT_US + UnorderedNotGreaterThanSignaling = 10, + + // _CMP_FALSE_OQ + OrderedFalseNonSignaling = 11, + + // _CMP_NEQ_OQ + OrderedNotEqualNonSignaling = 12, + + // _CMP_GE_OS + OrderedGreaterThanOrEqualSignaling = 13, + + // _CMP_GT_OS + OrderedGreaterThanSignaling = 14, + + // _CMP_TRUE_UQ + UnorderedTrueNonSignaling = 15, + + // _CMP_EQ_OS + OrderedEqualSignaling = 16, + + // _CMP_LT_OQ + OrderedLessThanNonSignaling = 17, + + // _CMP_LE_OQ + OrderedLessThanOrEqualNonSignaling = 18, + + // _CMP_UNORD_S + UnorderedSignaling = 19, + + // _CMP_NEQ_US + UnorderedNotEqualSignaling = 20, + + // _CMP_NLT_UQ + UnorderedNotLessThanNonSignaling = 21, + + // _CMP_NLE_UQ + UnorderedNotLessThanOrEqualNonSignaling = 22, + + // _CMP_ORD_S + OrderedSignaling = 23, + + // _CMP_EQ_US + UnorderedEqualSignaling = 24, + + // _CMP_NGE_UQ + UnorderedNotGreaterThanOrEqualNonSignaling = 25, + + // _CMP_NGT_UQ + UnorderedNotGreaterThanNonSignaling = 26, + + // _CMP_FALSE_OS + OrderedFalseSignaling = 27, + + // _CMP_NEQ_OS + OrderedNotEqualSignaling = 28, + + // _CMP_GE_OQ + OrderedGreaterThanOrEqualNonSignaling = 29, + + // _CMP_GT_OQ + OrderedGreaterThanNonSignaling = 30, + + // _CMP_TRUE_US + UnorderedTrueSignaling = 31, +}; + +enum class FloatRoundingMode : unsigned char +{ + // _MM_FROUND_TO_NEAREST_INT + ToNearestInteger = 0x00, + + // _MM_FROUND_TO_NEG_INF + ToNegativeInfinity = 0x01, + + // _MM_FROUND_TO_POS_INF + ToPositiveInfinity = 0x02, + + // _MM_FROUND_TO_ZERO + ToZero = 0x03, + + // _MM_FROUND_CUR_DIRECTION + CurrentDirection = 0x04, + + // _MM_FROUND_RAISE_EXC + RaiseException = 0x00, + + // _MM_FROUND_NO_EXC + NoException = 0x08, }; +#endif // TARGET_XARCH struct HWIntrinsicInfo { NamedIntrinsic id; const char* name; CORINFO_InstructionSet isa; - int ival; - unsigned simdSize; + int simdSize; int numArgs; instruction ins[10]; HWIntrinsicCategory category; @@ -132,24 +258,34 @@ struct HWIntrinsicInfo static const HWIntrinsicInfo& lookup(NamedIntrinsic id); - static NamedIntrinsic lookupId(Compiler* comp, - const char* className, - const char* methodName, - const char* enclosingClassName); + static NamedIntrinsic lookupId(Compiler* comp, + CORINFO_SIG_INFO* sig, + const char* className, + const char* methodName, + const char* enclosingClassName); static CORINFO_InstructionSet lookupIsa(const char* className, const char* enclosingClassName); static unsigned lookupSimdSize(Compiler* comp, NamedIntrinsic id, CORINFO_SIG_INFO* sig); static int lookupNumArgs(const GenTreeHWIntrinsic* node); static GenTree* lookupLastOp(const GenTreeHWIntrinsic* node); - static int lookupImmUpperBound(NamedIntrinsic id); +#if defined(TARGET_XARCH) + static int lookupImmUpperBound(NamedIntrinsic intrinsic); +#elif defined(TARGET_ARM64) + static void lookupImmBounds( + NamedIntrinsic intrinsic, int simdSize, var_types baseType, int* lowerBound, int* upperBound); +#else +#error Unsupported platform +#endif + + static bool isInImmRange(NamedIntrinsic id, int ival, int simdSize, var_types baseType); static bool isImmOp(NamedIntrinsic id, const GenTree* op); - static bool isInImmRange(NamedIntrinsic id, int ival); static bool isFullyImplementedIsa(CORINFO_InstructionSet isa); static bool isScalarIsa(CORINFO_InstructionSet isa); #ifdef TARGET_XARCH static bool isAVX2GatherIntrinsic(NamedIntrinsic id); + static FloatComparisonMode lookupFloatComparisonModeForSwappedArgs(FloatComparisonMode comparison); #endif // Member lookup @@ -169,14 +305,221 @@ struct HWIntrinsicInfo return lookup(id).isa; } - static int lookupIval(NamedIntrinsic id) +#ifdef TARGET_XARCH + static int lookupIval(NamedIntrinsic id, bool opportunisticallyDependsOnAVX) { - return lookup(id).ival; + switch (id) + { + case NI_SSE_CompareEqual: + case NI_SSE_CompareScalarEqual: + case NI_SSE2_CompareEqual: + case NI_SSE2_CompareScalarEqual: + case NI_AVX_CompareEqual: + { + return static_cast(FloatComparisonMode::OrderedEqualNonSignaling); + } + + case NI_SSE_CompareGreaterThan: + case NI_SSE_CompareScalarGreaterThan: + case NI_SSE2_CompareGreaterThan: + case NI_SSE2_CompareScalarGreaterThan: + case NI_AVX_CompareGreaterThan: + { + if (opportunisticallyDependsOnAVX) + { + return static_cast(FloatComparisonMode::OrderedGreaterThanSignaling); + } + + // CompareGreaterThan is not directly supported in hardware without AVX support. + // We will return the inverted case here and lowering will itself swap the ops + // to ensure the emitted code remains correct. This simplifies the overall logic + // here and for other use cases. + + assert(id != NI_AVX_CompareGreaterThan); + return static_cast(FloatComparisonMode::OrderedLessThanSignaling); + } + + case NI_SSE_CompareLessThan: + case NI_SSE_CompareScalarLessThan: + case NI_SSE2_CompareLessThan: + case NI_SSE2_CompareScalarLessThan: + case NI_AVX_CompareLessThan: + { + return static_cast(FloatComparisonMode::OrderedLessThanSignaling); + } + + case NI_SSE_CompareGreaterThanOrEqual: + case NI_SSE_CompareScalarGreaterThanOrEqual: + case NI_SSE2_CompareGreaterThanOrEqual: + case NI_SSE2_CompareScalarGreaterThanOrEqual: + case NI_AVX_CompareGreaterThanOrEqual: + { + if (opportunisticallyDependsOnAVX) + { + return static_cast(FloatComparisonMode::OrderedGreaterThanOrEqualSignaling); + } + + // CompareGreaterThanOrEqual is not directly supported in hardware without AVX support. + // We will return the inverted case here and lowering will itself swap the ops + // to ensure the emitted code remains correct. This simplifies the overall logic + // here and for other use cases. + + assert(id != NI_AVX_CompareGreaterThanOrEqual); + return static_cast(FloatComparisonMode::OrderedLessThanOrEqualSignaling); + } + + case NI_SSE_CompareLessThanOrEqual: + case NI_SSE_CompareScalarLessThanOrEqual: + case NI_SSE2_CompareLessThanOrEqual: + case NI_SSE2_CompareScalarLessThanOrEqual: + case NI_AVX_CompareLessThanOrEqual: + { + return static_cast(FloatComparisonMode::OrderedLessThanOrEqualSignaling); + } + + case NI_SSE_CompareNotEqual: + case NI_SSE_CompareScalarNotEqual: + case NI_SSE2_CompareNotEqual: + case NI_SSE2_CompareScalarNotEqual: + case NI_AVX_CompareNotEqual: + { + return static_cast(FloatComparisonMode::UnorderedNotEqualNonSignaling); + } + + case NI_SSE_CompareNotGreaterThan: + case NI_SSE_CompareScalarNotGreaterThan: + case NI_SSE2_CompareNotGreaterThan: + case NI_SSE2_CompareScalarNotGreaterThan: + case NI_AVX_CompareNotGreaterThan: + { + if (opportunisticallyDependsOnAVX) + { + return static_cast(FloatComparisonMode::UnorderedNotGreaterThanSignaling); + } + + // CompareNotGreaterThan is not directly supported in hardware without AVX support. + // We will return the inverted case here and lowering will itself swap the ops + // to ensure the emitted code remains correct. This simplifies the overall logic + // here and for other use cases. + + assert(id != NI_AVX_CompareNotGreaterThan); + return static_cast(FloatComparisonMode::UnorderedNotLessThanSignaling); + } + + case NI_SSE_CompareNotLessThan: + case NI_SSE_CompareScalarNotLessThan: + case NI_SSE2_CompareNotLessThan: + case NI_SSE2_CompareScalarNotLessThan: + case NI_AVX_CompareNotLessThan: + { + return static_cast(FloatComparisonMode::UnorderedNotLessThanSignaling); + } + + case NI_SSE_CompareNotGreaterThanOrEqual: + case NI_SSE_CompareScalarNotGreaterThanOrEqual: + case NI_SSE2_CompareNotGreaterThanOrEqual: + case NI_SSE2_CompareScalarNotGreaterThanOrEqual: + case NI_AVX_CompareNotGreaterThanOrEqual: + { + if (opportunisticallyDependsOnAVX) + { + return static_cast(FloatComparisonMode::UnorderedNotGreaterThanOrEqualSignaling); + } + + // CompareNotGreaterThanOrEqual is not directly supported in hardware without AVX support. + // We will return the inverted case here and lowering will itself swap the ops + // to ensure the emitted code remains correct. This simplifies the overall logic + // here and for other use cases. + + assert(id != NI_AVX_CompareNotGreaterThanOrEqual); + return static_cast(FloatComparisonMode::UnorderedNotLessThanOrEqualSignaling); + } + + case NI_SSE_CompareNotLessThanOrEqual: + case NI_SSE_CompareScalarNotLessThanOrEqual: + case NI_SSE2_CompareNotLessThanOrEqual: + case NI_SSE2_CompareScalarNotLessThanOrEqual: + case NI_AVX_CompareNotLessThanOrEqual: + { + return static_cast(FloatComparisonMode::UnorderedNotLessThanOrEqualSignaling); + } + + case NI_SSE_CompareOrdered: + case NI_SSE_CompareScalarOrdered: + case NI_SSE2_CompareOrdered: + case NI_SSE2_CompareScalarOrdered: + case NI_AVX_CompareOrdered: + { + return static_cast(FloatComparisonMode::OrderedNonSignaling); + } + + case NI_SSE_CompareUnordered: + case NI_SSE_CompareScalarUnordered: + case NI_SSE2_CompareUnordered: + case NI_SSE2_CompareScalarUnordered: + case NI_AVX_CompareUnordered: + { + return static_cast(FloatComparisonMode::UnorderedNonSignaling); + } + + case NI_SSE41_Ceiling: + case NI_SSE41_CeilingScalar: + case NI_SSE41_RoundToPositiveInfinity: + case NI_SSE41_RoundToPositiveInfinityScalar: + case NI_AVX_Ceiling: + case NI_AVX_RoundToPositiveInfinity: + { + return static_cast(FloatRoundingMode::ToPositiveInfinity); + } + + case NI_SSE41_Floor: + case NI_SSE41_FloorScalar: + case NI_SSE41_RoundToNegativeInfinity: + case NI_SSE41_RoundToNegativeInfinityScalar: + case NI_AVX_Floor: + case NI_AVX_RoundToNegativeInfinity: + { + return static_cast(FloatRoundingMode::ToNegativeInfinity); + } + + case NI_SSE41_RoundCurrentDirection: + case NI_SSE41_RoundCurrentDirectionScalar: + case NI_AVX_RoundCurrentDirection: + { + return static_cast(FloatRoundingMode::CurrentDirection); + } + + case NI_SSE41_RoundToNearestInteger: + case NI_SSE41_RoundToNearestIntegerScalar: + case NI_AVX_RoundToNearestInteger: + { + return static_cast(FloatRoundingMode::ToNearestInteger); + } + + case NI_SSE41_RoundToZero: + case NI_SSE41_RoundToZeroScalar: + case NI_AVX_RoundToZero: + { + return static_cast(FloatRoundingMode::ToZero); + } + + default: + { + return -1; + } + } } +#endif - static unsigned lookupSimdSize(NamedIntrinsic id) + static bool tryLookupSimdSize(NamedIntrinsic id, unsigned* pSimdSize) { - return lookup(id).simdSize; + bool succeeded = false; + if (lookup(id).simdSize != -1) + { + *pSimdSize = lookup(id).simdSize; + succeeded = true; + } + return succeeded; } static int lookupNumArgs(NamedIntrinsic id) @@ -224,12 +567,6 @@ struct HWIntrinsicInfo return (flags & HW_Flag_NoCodeGen) == 0; } - static bool HasFixedSimdSize(NamedIntrinsic id) - { - HWIntrinsicFlag flags = lookupFlags(id); - return (flags & HW_Flag_UnfixedSIMDSize) == 0; - } - static bool GeneratesMultipleIns(NamedIntrinsic id) { HWIntrinsicFlag flags = lookupFlags(id); @@ -239,13 +576,13 @@ struct HWIntrinsicInfo static bool SupportsContainment(NamedIntrinsic id) { HWIntrinsicFlag flags = lookupFlags(id); +#if defined(TARGET_XARCH) return (flags & HW_Flag_NoContainment) == 0; - } - - static bool CopiesUpperBits(NamedIntrinsic id) - { - HWIntrinsicFlag flags = lookupFlags(id); - return (flags & HW_Flag_CopyUpperBits) != 0; +#elif defined(TARGET_ARM64) + return (flags & HW_Flag_SupportsContainment) != 0; +#else +#error Unsupported platform +#endif } static bool BaseTypeFromFirstArg(NamedIntrinsic id) @@ -266,6 +603,13 @@ struct HWIntrinsicInfo return (flags & HW_Flag_MaybeIMM) != 0; } +#ifdef TARGET_XARCH + static bool CopiesUpperBits(NamedIntrinsic id) + { + HWIntrinsicFlag flags = lookupFlags(id); + return (flags & HW_Flag_CopyUpperBits) != 0; + } + static bool MaybeMemoryLoad(NamedIntrinsic id) { HWIntrinsicFlag flags = lookupFlags(id); @@ -277,6 +621,7 @@ struct HWIntrinsicInfo HWIntrinsicFlag flags = lookupFlags(id); return (flags & HW_Flag_MaybeMemoryStore) != 0; } +#endif static bool NoJmpTableImm(NamedIntrinsic id) { @@ -315,6 +660,104 @@ struct HWIntrinsicInfo } }; +#ifdef TARGET_ARM64 + +struct HWIntrinsic final +{ + HWIntrinsic(const GenTreeHWIntrinsic* node) + : op1(nullptr), op2(nullptr), op3(nullptr), numOperands(0), baseType(TYP_UNDEF) + { + assert(node != nullptr); + + id = node->gtHWIntrinsicId; + category = HWIntrinsicInfo::lookupCategory(id); + + assert(HWIntrinsicInfo::RequiresCodegen(id)); + + InitializeOperands(node); + InitializeBaseType(node); + } + + bool IsTableDriven() const + { + // TODO-Arm64-Cleanup - make more categories to the table-driven framework + bool isTableDrivenCategory = category != HW_Category_Helper; + bool isTableDrivenFlag = !HWIntrinsicInfo::GeneratesMultipleIns(id) && !HWIntrinsicInfo::HasSpecialCodegen(id); + + return isTableDrivenCategory && isTableDrivenFlag; + } + + NamedIntrinsic id; + HWIntrinsicCategory category; + GenTree* op1; + GenTree* op2; + GenTree* op3; + int numOperands; + var_types baseType; + +private: + void InitializeOperands(const GenTreeHWIntrinsic* node) + { + op1 = node->gtGetOp1(); + op2 = node->gtGetOp2(); + + if (op1 == nullptr) + { + numOperands = 0; + } + else if (op1->OperIsList()) + { + assert(op2 == nullptr); + + GenTreeArgList* list = op1->AsArgList(); + op1 = list->Current(); + list = list->Rest(); + op2 = list->Current(); + list = list->Rest(); + op3 = list->Current(); + + assert(list->Rest() == nullptr); + + numOperands = 3; + } + else if (op2 != nullptr) + { + numOperands = 2; + } + else + { + numOperands = 1; + } + } + + void InitializeBaseType(const GenTreeHWIntrinsic* node) + { + baseType = node->gtSIMDBaseType; + + if (baseType == TYP_UNKNOWN) + { + assert(category == HW_Category_Scalar); + + if (HWIntrinsicInfo::BaseTypeFromFirstArg(id)) + { + assert(op1 != nullptr); + baseType = op1->TypeGet(); + } + else if (HWIntrinsicInfo::BaseTypeFromSecondArg(id)) + { + assert(op2 != nullptr); + baseType = op2->TypeGet(); + } + else + { + baseType = node->TypeGet(); + } + } + } +}; + +#endif // TARGET_ARM64 + #endif // FEATURE_HW_INTRINSICS #endif // _HW_INTRINSIC_H_ diff --git a/src/coreclr/src/jit/hwintrinsicarm64.cpp b/src/coreclr/src/jit/hwintrinsicarm64.cpp index 7f494ab96582f5..dc7bbcab49f049 100644 --- a/src/coreclr/src/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/src/jit/hwintrinsicarm64.cpp @@ -114,37 +114,6 @@ CORINFO_InstructionSet HWIntrinsicInfo::lookupIsa(const char* className, const c } } -//------------------------------------------------------------------------ -// lookupImmUpperBound: Gets the upper bound for the imm-value of a given NamedIntrinsic -// -// Arguments: -// id -- The NamedIntrinsic associated with the HWIntrinsic to lookup -// -// Return Value: -// The upper bound for the imm-value of the intrinsic associated with id -// -int HWIntrinsicInfo::lookupImmUpperBound(NamedIntrinsic id) -{ - assert(HWIntrinsicInfo::HasFullRangeImm(id)); - return 255; -} - -//------------------------------------------------------------------------ -// isInImmRange: Check if ival is valid for the intrinsic -// -// Arguments: -// id -- The NamedIntrinsic associated with the HWIntrinsic to lookup -// ival -- the imm value to be checked -// -// Return Value: -// true if ival is valid for the intrinsic -// -bool HWIntrinsicInfo::isInImmRange(NamedIntrinsic id, int ival) -{ - assert(HWIntrinsicInfo::lookupCategory(id) == HW_Category_IMM); - return ival <= lookupImmUpperBound(id) && ival >= 0; -} - //------------------------------------------------------------------------ // isFullyImplementedIsa: Gets a value that indicates whether the InstructionSet is fully implemented // @@ -207,6 +176,138 @@ bool HWIntrinsicInfo::isScalarIsa(CORINFO_InstructionSet isa) } } +//------------------------------------------------------------------------ +// lookupImmBounds: Gets the lower and upper bounds for the imm-value of a given NamedIntrinsic +// +// Arguments: +// intrinsic -- NamedIntrinsic associated with the HWIntrinsic to lookup +// simdType -- vector size +// baseType -- base type of the Vector64/128 +// pImmLowerBound [OUT] - The lower incl. bound for a value of the intrinsic immediate operand +// pImmUpperBound [OUT] - The upper incl. bound for a value of the intrinsic immediate operand +// +void HWIntrinsicInfo::lookupImmBounds( + NamedIntrinsic intrinsic, int simdSize, var_types baseType, int* pImmLowerBound, int* pImmUpperBound) +{ + assert(HWIntrinsicInfo::lookupCategory(intrinsic) == HW_Category_IMM); + + assert(pImmLowerBound != nullptr); + assert(pImmUpperBound != nullptr); + + int immLowerBound = 0; + int immUpperBound = 0; + + if (HWIntrinsicInfo::HasFullRangeImm(intrinsic)) + { + immUpperBound = 255; + } + else + { + switch (intrinsic) + { + case NI_AdvSimd_DuplicateSelectedScalarToVector64: + case NI_AdvSimd_DuplicateSelectedScalarToVector128: + case NI_AdvSimd_Extract: + case NI_AdvSimd_ExtractVector128: + case NI_AdvSimd_ExtractVector64: + case NI_AdvSimd_Insert: + case NI_AdvSimd_Arm64_DuplicateSelectedScalarToVector128: + case NI_Vector64_GetElement: + case NI_Vector128_GetElement: + immUpperBound = Compiler::getSIMDVectorLength(simdSize, baseType) - 1; + break; + + case NI_AdvSimd_ShiftLeftLogical: + case NI_AdvSimd_ShiftLeftLogicalSaturate: + case NI_AdvSimd_ShiftLeftLogicalSaturateScalar: + case NI_AdvSimd_ShiftLeftLogicalSaturateUnsigned: + case NI_AdvSimd_ShiftLeftLogicalSaturateUnsignedScalar: + case NI_AdvSimd_ShiftLeftLogicalScalar: + case NI_AdvSimd_ShiftLeftLogicalWideningLower: + case NI_AdvSimd_ShiftLeftLogicalWideningUpper: + case NI_AdvSimd_Arm64_ShiftLeftLogicalSaturateScalar: + case NI_AdvSimd_Arm64_ShiftLeftLogicalSaturateUnsignedScalar: + // The left shift amount is in the range 0 to the element width in bits minus 1. + immUpperBound = BITS_PER_BYTE * genTypeSize(baseType) - 1; + break; + + case NI_AdvSimd_ShiftRightArithmetic: + case NI_AdvSimd_ShiftRightArithmeticAdd: + case NI_AdvSimd_ShiftRightArithmeticAddScalar: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateUnsignedLower: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateUnsignedUpper: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightArithmeticRounded: + case NI_AdvSimd_ShiftRightArithmeticRoundedAdd: + case NI_AdvSimd_ShiftRightArithmeticRoundedAddScalar: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightArithmeticRoundedScalar: + case NI_AdvSimd_ShiftRightArithmeticScalar: + case NI_AdvSimd_ShiftRightLogical: + case NI_AdvSimd_ShiftRightLogicalAdd: + case NI_AdvSimd_ShiftRightLogicalAddScalar: + case NI_AdvSimd_ShiftRightLogicalNarrowingLower: + case NI_AdvSimd_ShiftRightLogicalNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightLogicalNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightLogicalNarrowingUpper: + case NI_AdvSimd_ShiftRightLogicalRounded: + case NI_AdvSimd_ShiftRightLogicalRoundedAdd: + case NI_AdvSimd_ShiftRightLogicalRoundedAddScalar: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingLower: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingUpper: + case NI_AdvSimd_ShiftRightLogicalRoundedScalar: + case NI_AdvSimd_ShiftRightLogicalScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticNarrowingSaturateScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticNarrowingSaturateUnsignedScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticRoundedNarrowingSaturateScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar: + case NI_AdvSimd_Arm64_ShiftRightLogicalNarrowingSaturateScalar: + case NI_AdvSimd_Arm64_ShiftRightLogicalRoundedNarrowingSaturateScalar: + // The right shift amount, in the range 1 to the element width in bits. + immLowerBound = 1; + immUpperBound = BITS_PER_BYTE * genTypeSize(baseType); + break; + default: + unreached(); + } + } + + assert(immLowerBound <= immUpperBound); + + *pImmLowerBound = immLowerBound; + *pImmUpperBound = immUpperBound; +} + +//------------------------------------------------------------------------ +// isInImmRange: Check if ival is valid for the intrinsic +// +// Arguments: +// id -- the NamedIntrinsic associated with the HWIntrinsic to lookup +// ival -- the imm value to be checked +// simdType -- vector size +// baseType -- base type of the Vector64/128 +// +// Return Value: +// true if ival is valid for the intrinsic +// +bool HWIntrinsicInfo::isInImmRange(NamedIntrinsic id, int ival, int simdSize, var_types baseType) +{ + assert(HWIntrinsicInfo::lookupCategory(id) == HW_Category_IMM); + + int immLowerBound = 0; + int immUpperBound = 0; + + lookupImmBounds(id, simdSize, baseType, &immLowerBound, &immUpperBound); + + return (immLowerBound <= ival) && (ival <= immUpperBound); +} + //------------------------------------------------------------------------ // impNonConstFallback: generate alternate code when the imm-arg is not a compile-time constant // @@ -230,7 +331,9 @@ GenTree* Compiler::impNonConstFallback(NamedIntrinsic intrinsic, var_types simdT // intrinsic -- id of the intrinsic function. // clsHnd -- class handle containing the intrinsic function. // method -- method handle of the intrinsic function. -// sig -- signature of the intrinsic call +// sig -- signature of the intrinsic call. +// baseType -- generic argument of the intrinsic. +// retType -- return type of the intrinsic. // // Return Value: // The GT_HWINTRINSIC node, or nullptr if not a supported intrinsic @@ -238,50 +341,16 @@ GenTree* Compiler::impNonConstFallback(NamedIntrinsic intrinsic, var_types simdT GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* sig) + CORINFO_SIG_INFO* sig, + var_types baseType, + var_types retType, + unsigned simdSize) { HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsic); int numArgs = sig->numArgs; - var_types retType = JITtype2varType(sig->retType); - var_types baseType = TYP_UNKNOWN; - - if ((retType == TYP_STRUCT) && featureSIMD) - { - unsigned int sizeBytes; - baseType = getBaseTypeAndSizeOfSIMDType(sig->retTypeSigClass, &sizeBytes); - retType = getSIMDTypeForSize(sizeBytes); - assert(sizeBytes != 0); - if (!varTypeIsArithmetic(baseType)) - { - assert((intrinsic == NI_Vector64_AsByte) || (intrinsic == NI_Vector128_As)); - return nullptr; - } - } - - baseType = getBaseTypeFromArgIfNeeded(intrinsic, clsHnd, sig, baseType); - - if (baseType == TYP_UNKNOWN) - { - if (category != HW_Category_Scalar) - { - unsigned int sizeBytes; - baseType = getBaseTypeAndSizeOfSIMDType(clsHnd, &sizeBytes); - assert(sizeBytes != 0); - } - else - { - baseType = retType; - } - } - - if (!varTypeIsArithmetic(baseType)) - { - return nullptr; - } - - unsigned simdSize = HWIntrinsicInfo::lookupSimdSize(this, intrinsic, sig); assert(numArgs >= 0); + assert(varTypeIsArithmetic(baseType)); GenTree* retNode = nullptr; GenTree* op1 = nullptr; @@ -325,6 +394,47 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, assert(retNode->gtType == getSIMDTypeForSize(getSIMDTypeSizeInBytes(sig->retTypeSigClass))); break; } + + case NI_Vector64_Create: + case NI_Vector128_Create: + { + // We shouldn't handle this as an intrinsic if the + // respective ISAs have been disabled by the user. + + if (!compExactlyDependsOn(InstructionSet_AdvSimd)) + { + break; + } + + if (sig->numArgs == 1) + { + op1 = impPopStack().val; + retNode = gtNewSimdHWIntrinsicNode(retType, op1, intrinsic, baseType, simdSize); + } + else if (sig->numArgs == 2) + { + op2 = impPopStack().val; + op1 = impPopStack().val; + retNode = gtNewSimdHWIntrinsicNode(retType, op1, op2, intrinsic, baseType, simdSize); + } + else + { + assert(sig->numArgs >= 3); + + GenTreeArgList* tmp = nullptr; + + for (unsigned i = 0; i < sig->numArgs; i++) + { + tmp = gtNewArgList(impPopStack().val); + tmp->gtOp2 = op1; + op1 = tmp; + } + + retNode = gtNewSimdHWIntrinsicNode(retType, op1, intrinsic, baseType, simdSize); + } + break; + } + case NI_Vector64_get_Count: case NI_Vector128_get_Count: { @@ -336,7 +446,17 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, retNode = countNode; break; } + case NI_Vector64_get_Zero: + case NI_Vector64_get_AllBitsSet: + case NI_Vector128_get_Zero: + case NI_Vector128_get_AllBitsSet: + { + assert(!sig->hasThis()); + assert(numArgs == 0); + retNode = gtNewSimdHWIntrinsicNode(retType, intrinsic, baseType, simdSize); + break; + } default: { return nullptr; diff --git a/src/coreclr/src/jit/hwintrinsiccodegenarm64.cpp b/src/coreclr/src/jit/hwintrinsiccodegenarm64.cpp index 61139e2e6ab46a..179c1807e118a1 100644 --- a/src/coreclr/src/jit/hwintrinsiccodegenarm64.cpp +++ b/src/coreclr/src/jit/hwintrinsiccodegenarm64.cpp @@ -9,104 +9,167 @@ #ifdef FEATURE_HW_INTRINSICS -#include "emit.h" #include "codegen.h" -#include "sideeffects.h" -#include "lower.h" -#include "gcinfo.h" -#include "gcinfoencoder.h" -struct HWIntrinsic final +// HWIntrinsicImmOpHelper: constructs the helper class instance. +// This also determines what type of "switch" table is being used (if an immediate operand is not constant) and do +// some preparation work: +// +// a) If an immediate operand can be either 0 or 1, this creates . +// +// b) If an immediate operand can take any value in [0, upperBound), this extract a internal register from an +// intrinsic node. The register will be later used to store computed branch target address. +// +// Arguments: +// codeGen -- an instance of CodeGen class. +// immOp -- an immediate operand of the intrinsic. +// intrin -- a hardware intrinsic tree node. +// +// Note: This class is designed to be used in the following way +// HWIntrinsicImmOpHelper helper(this, immOp, intrin); +// +// for (helper.EmitBegin(); !helper.Done(); helper.EmitCaseEnd()) +// { +// -- emit an instruction for a given value of helper.ImmValue() +// } +// +// This allows to combine logic for cases when immOp->isContainedIntOrIImmed() is either true or false in a form +// of a for-loop. +// +CodeGen::HWIntrinsicImmOpHelper::HWIntrinsicImmOpHelper(CodeGen* codeGen, GenTree* immOp, GenTreeHWIntrinsic* intrin) + : codeGen(codeGen), endLabel(nullptr), nonZeroLabel(nullptr), branchTargetReg(REG_NA) { - HWIntrinsic(const GenTreeHWIntrinsic* node) - : op1(nullptr), op2(nullptr), op3(nullptr), numOperands(0), baseType(TYP_UNDEF) - { - assert(node != nullptr); - - id = node->gtHWIntrinsicId; - category = HWIntrinsicInfo::lookupCategory(id); - - assert(HWIntrinsicInfo::RequiresCodegen(id)); + assert(codeGen != nullptr); + assert(HWIntrinsicInfo::isImmOp(intrin->gtHWIntrinsicId, immOp)); - InitializeOperands(node); - InitializeBaseType(node); - } - - bool IsTableDriven() const + if (immOp->isContainedIntOrIImmed()) { - // TODO-Arm64-Cleanup - make more categories to the table-driven framework - bool isTableDrivenCategory = category != HW_Category_Helper; - bool isTableDrivenFlag = !HWIntrinsicInfo::GeneratesMultipleIns(id) && !HWIntrinsicInfo::HasSpecialCodegen(id); + nonConstImmReg = REG_NA; - return isTableDrivenCategory && isTableDrivenFlag; + immValue = (int)immOp->AsIntCon()->IconValue(); + immLowerBound = immValue; + immUpperBound = immValue; } - - NamedIntrinsic id; - HWIntrinsicCategory category; - GenTree* op1; - GenTree* op2; - GenTree* op3; - int numOperands; - var_types baseType; - -private: - void InitializeOperands(const GenTreeHWIntrinsic* node) + else { - op1 = node->gtGetOp1(); - op2 = node->gtGetOp2(); + HWIntrinsicInfo::lookupImmBounds(intrin->gtHWIntrinsicId, intrin->gtSIMDSize, intrin->gtSIMDBaseType, + &immLowerBound, &immUpperBound); - assert(op1 != nullptr); + nonConstImmReg = immOp->GetRegNum(); + immValue = immLowerBound; - if (op1->OperIsList()) + if (TestImmOpZeroOrOne()) { - assert(op2 == nullptr); + nonZeroLabel = codeGen->genCreateTempLabel(); + } + else + { + // At the moment, this helper supports only intrinsics that correspond to one machine instruction. + // If we ever encounter an intrinsic that is either lowered into multiple instructions or + // the number of instructions that correspond to each case is unknown apriori - we can extend support to + // these by + // using the same approach as in hwintrinsicxarch.cpp - adding an additional indirection level in form of a + // branch table. + assert(!HWIntrinsicInfo::GeneratesMultipleIns(intrin->gtHWIntrinsicId)); + branchTargetReg = intrin->GetSingleTempReg(); + } - GenTreeArgList* list = op1->AsArgList(); - op1 = list->Current(); - list = list->Rest(); - op2 = list->Current(); - list = list->Rest(); - op3 = list->Current(); + endLabel = codeGen->genCreateTempLabel(); + } +} - assert(list->Rest() == nullptr); +//------------------------------------------------------------------------ +// EmitBegin: emits the beginning of a "switch" table, no-op if an immediate operand is constant. +// +// Note: The function is called at the beginning of code generation and emits +// a) If an immediate operand can be either 0 or 1 +// +// cbnz , nonConstImmReg +// +// b) If an immediate operand can take any value in [0, upperBound) range +// +// adr branchTargetReg, +// add branchTargetReg, branchTargetReg, nonConstImmReg, lsl #3 +// br branchTargetReg +// +// When an immediate operand is non constant this also defines right after the emitted code. +// +void CodeGen::HWIntrinsicImmOpHelper::EmitBegin() +{ + if (NonConstImmOp()) + { + BasicBlock* beginLabel = codeGen->genCreateTempLabel(); - numOperands = 3; - } - else if (op2 != nullptr) + if (TestImmOpZeroOrOne()) { - numOperands = 2; + GetEmitter()->emitIns_J_R(INS_cbnz, EA_4BYTE, nonZeroLabel, nonConstImmReg); } else { - numOperands = 1; + // Here we assume that each case consists of one arm64 instruction followed by "b endLabel". + // Since an arm64 instruction is 4 bytes, we branch to AddressOf(beginLabel) + (nonConstImmReg << 3). + GetEmitter()->emitIns_R_L(INS_adr, EA_8BYTE, beginLabel, branchTargetReg); + GetEmitter()->emitIns_R_R_R_I(INS_add, EA_8BYTE, branchTargetReg, branchTargetReg, nonConstImmReg, 3, + INS_OPTS_LSL); + + // If the lower bound is non zero we need to adjust the branch target value by subtracting + // (immLowerBound << 3). + if (immLowerBound != 0) + { + GetEmitter()->emitIns_R_R_I(INS_sub, EA_8BYTE, branchTargetReg, branchTargetReg, + ((ssize_t)immLowerBound << 3)); + } + + GetEmitter()->emitIns_R(INS_br, EA_8BYTE, branchTargetReg); } + + codeGen->genDefineInlineTempLabel(beginLabel); } +} - void InitializeBaseType(const GenTreeHWIntrinsic* node) +//------------------------------------------------------------------------ +// EmitCaseEnd: emits the end of a "case", no-op if an immediate operand is constant. +// +// Note: The function is called at the end of each "case" (i.e. after an instruction has been emitted for a given +// immediate value ImmValue()) +// and emits +// +// b +// +// After the last "case" this defines . +// +// If an immediate operand is either 0 or 1 it also defines after the first "case". +// +void CodeGen::HWIntrinsicImmOpHelper::EmitCaseEnd() +{ + assert(!Done()); + + if (NonConstImmOp()) { - baseType = node->gtSIMDBaseType; + const bool isLastCase = (immValue == immUpperBound); - if (baseType == TYP_UNKNOWN) + if (isLastCase) + { + codeGen->genDefineInlineTempLabel(endLabel); + } + else { - assert(category == HW_Category_Scalar); + GetEmitter()->emitIns_J(INS_b, endLabel); - if (HWIntrinsicInfo::BaseTypeFromFirstArg(id)) + if (TestImmOpZeroOrOne()) { - assert(op1 != nullptr); - baseType = op1->TypeGet(); - } - else if (HWIntrinsicInfo::BaseTypeFromSecondArg(id)) - { - assert(op2 != nullptr); - baseType = op2->TypeGet(); + codeGen->genDefineInlineTempLabel(nonZeroLabel); } else { - baseType = node->TypeGet(); + BasicBlock* tempLabel = codeGen->genCreateTempLabel(); + codeGen->genDefineInlineTempLabel(tempLabel); } } } -}; + + immValue++; +} //------------------------------------------------------------------------ // genHWIntrinsic: Generates the code for a given hardware intrinsic node. @@ -141,6 +204,10 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) op1Reg = intrin.op1->GetRegNum(); break; + case 0: + assert(HWIntrinsicInfo::lookupNumArgs(intrin.id) == 0); + break; + default: unreached(); } @@ -148,13 +215,17 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) emitAttr emitSize; insOpts opt = INS_OPTS_NONE; - if ((intrin.category == HW_Category_SIMDScalar) || (intrin.category == HW_Category_Scalar)) + if (intrin.category == HW_Category_SIMDScalar) + { + emitSize = emitTypeSize(intrin.baseType); + } + else if (intrin.category == HW_Category_Scalar) { emitSize = emitActualTypeSize(intrin.baseType); } else { - emitSize = EA_SIZE(node->gtSIMDSize); + emitSize = emitActualTypeSize(Compiler::getSIMDTypeForSize(node->gtSIMDSize)); opt = genGetSimdInsOpt(emitSize, intrin.baseType); if ((opt == INS_OPTS_1D) && (intrin.category == HW_Category_SimpleSIMD)) @@ -185,7 +256,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) if (targetReg != op1Reg) { - GetEmitter()->emitIns_R_R(INS_mov, emitSize, targetReg, op1Reg); + GetEmitter()->emitIns_R_R(INS_mov, emitTypeSize(node), targetReg, op1Reg); } GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op2Reg, opt); } @@ -202,8 +273,9 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) if (targetReg != op1Reg) { - GetEmitter()->emitIns_R_R(INS_mov, emitSize, targetReg, op1Reg); + GetEmitter()->emitIns_R_R(INS_mov, emitTypeSize(node), targetReg, op1Reg); } + GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op2Reg, op3Reg, opt); break; @@ -214,7 +286,6 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) else { instruction ins = INS_invalid; - switch (intrin.id) { case NI_Crc32_ComputeCrc32: @@ -249,6 +320,61 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) ins = INS_crc32cx; break; + case NI_AdvSimd_AddWideningLower: + assert(varTypeIsIntegral(intrin.baseType)); + if (intrin.op1->TypeGet() == TYP_SIMD8) + { + ins = varTypeIsUnsigned(intrin.baseType) ? INS_uaddl : INS_saddl; + } + else + { + assert(intrin.op1->TypeGet() == TYP_SIMD16); + ins = varTypeIsUnsigned(intrin.baseType) ? INS_uaddw : INS_saddw; + } + break; + + case NI_AdvSimd_SubtractWideningLower: + assert(varTypeIsIntegral(intrin.baseType)); + if (intrin.op1->TypeGet() == TYP_SIMD8) + { + ins = varTypeIsUnsigned(intrin.baseType) ? INS_usubl : INS_ssubl; + } + else + { + assert(intrin.op1->TypeGet() == TYP_SIMD16); + ins = varTypeIsUnsigned(intrin.baseType) ? INS_usubw : INS_ssubw; + } + break; + + case NI_AdvSimd_AddWideningUpper: + assert(varTypeIsIntegral(intrin.baseType)); + if (node->GetOtherBaseType() == intrin.baseType) + { + ins = varTypeIsUnsigned(intrin.baseType) ? INS_uaddl2 : INS_saddl2; + } + else + { + ins = varTypeIsUnsigned(intrin.baseType) ? INS_uaddw2 : INS_saddw2; + } + break; + + case NI_AdvSimd_SubtractWideningUpper: + assert(varTypeIsIntegral(intrin.baseType)); + if (node->GetOtherBaseType() == intrin.baseType) + { + ins = varTypeIsUnsigned(intrin.baseType) ? INS_usubl2 : INS_ssubl2; + } + else + { + ins = varTypeIsUnsigned(intrin.baseType) ? INS_usubw2 : INS_ssubw2; + } + break; + + case NI_Aes_PolynomialMultiplyWideningLower: + ins = INS_pmull; + opt = INS_OPTS_1D; + break; + default: ins = HWIntrinsicInfo::lookupIns(intrin.id, intrin.baseType); break; @@ -286,6 +412,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) case NI_Crc32_ComputeCrc32C: case NI_Crc32_Arm64_ComputeCrc32: case NI_Crc32_Arm64_ComputeCrc32C: + case NI_Aes_PolynomialMultiplyWideningLower: GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op1Reg, op2Reg, opt); break; @@ -319,6 +446,315 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) GetEmitter()->emitIns_R_R(ins, emitSize, op2Reg, op1Reg, opt); break; + case NI_AdvSimd_DuplicateSelectedScalarToVector64: + case NI_AdvSimd_DuplicateSelectedScalarToVector128: + case NI_AdvSimd_Arm64_DuplicateSelectedScalarToVector128: + { + HWIntrinsicImmOpHelper helper(this, intrin.op2, node); + + // Prior to codegen, the emitSize is based on node->gtSIMDSize which + // tracks the size of the first operand and is used to tell if the index + // is in range. However, when actually emitting it needs to be the size + // of the return and the size of the operand is interpreted based on the + // index value. + + assert( + GetEmitter()->isValidVectorIndex(emitSize, GetEmitter()->optGetElemsize(opt), helper.ImmValue())); + + emitSize = emitActualTypeSize(node->gtType); + opt = genGetSimdInsOpt(emitSize, intrin.baseType); + + for (helper.EmitBegin(); !helper.Done(); helper.EmitCaseEnd()) + { + const int elementIndex = helper.ImmValue(); + + assert(opt != INS_OPTS_NONE); + GetEmitter()->emitIns_R_R_I(ins, emitSize, targetReg, op1Reg, elementIndex, opt); + } + + break; + } + + case NI_AdvSimd_Extract: + { + HWIntrinsicImmOpHelper helper(this, intrin.op2, node); + + for (helper.EmitBegin(); !helper.Done(); helper.EmitCaseEnd()) + { + const int elementIndex = helper.ImmValue(); + + GetEmitter()->emitIns_R_R_I(ins, emitTypeSize(intrin.baseType), targetReg, op1Reg, elementIndex, + INS_OPTS_NONE); + } + } + break; + + case NI_AdvSimd_ExtractVector64: + case NI_AdvSimd_ExtractVector128: + { + opt = (intrin.id == NI_AdvSimd_ExtractVector64) ? INS_OPTS_8B : INS_OPTS_16B; + + HWIntrinsicImmOpHelper helper(this, intrin.op3, node); + + for (helper.EmitBegin(); !helper.Done(); helper.EmitCaseEnd()) + { + const int elementIndex = helper.ImmValue(); + const int byteIndex = genTypeSize(intrin.baseType) * elementIndex; + + GetEmitter()->emitIns_R_R_R_I(ins, emitSize, targetReg, op1Reg, op2Reg, byteIndex, opt); + } + } + break; + + case NI_AdvSimd_Insert: + assert(isRMW); + assert(targetReg != op3Reg); + + if (targetReg != op1Reg) + { + GetEmitter()->emitIns_R_R(INS_mov, emitSize, targetReg, op1Reg); + } + + if (intrin.op3->isContainedFltOrDblImmed()) + { + assert(intrin.op2->isContainedIntOrIImmed()); + assert(intrin.op2->AsIntCon()->gtIconVal == 0); + + const double dataValue = intrin.op3->AsDblCon()->gtDconVal; + GetEmitter()->emitIns_R_F(INS_fmov, emitTypeSize(intrin.baseType), targetReg, dataValue, + INS_OPTS_NONE); + } + else + { + HWIntrinsicImmOpHelper helper(this, intrin.op2, node); + + if (varTypeIsFloating(intrin.baseType)) + { + for (helper.EmitBegin(); !helper.Done(); helper.EmitCaseEnd()) + { + const int elementIndex = helper.ImmValue(); + + GetEmitter()->emitIns_R_R_I_I(ins, emitTypeSize(intrin.baseType), targetReg, op3Reg, + elementIndex, 0, INS_OPTS_NONE); + } + } + else + { + for (helper.EmitBegin(); !helper.Done(); helper.EmitCaseEnd()) + { + const int elementIndex = helper.ImmValue(); + + GetEmitter()->emitIns_R_R_I(ins, emitTypeSize(intrin.baseType), targetReg, op3Reg, + elementIndex, INS_OPTS_NONE); + } + } + } + break; + + case NI_Vector64_CreateScalarUnsafe: + case NI_Vector128_CreateScalarUnsafe: + if (intrin.op1->isContainedFltOrDblImmed()) + { + // fmov reg, #imm8 + const double dataValue = intrin.op1->AsDblCon()->gtDconVal; + GetEmitter()->emitIns_R_F(ins, emitTypeSize(intrin.baseType), targetReg, dataValue, INS_OPTS_NONE); + } + else if (varTypeIsFloating(intrin.baseType)) + { + // fmov reg1, reg2 + GetEmitter()->emitIns_R_R(ins, emitTypeSize(intrin.baseType), targetReg, op1Reg, INS_OPTS_NONE); + } + else + { + if (intrin.op1->isContainedIntOrIImmed()) + { + // movi/movni reg, #imm8 + const ssize_t dataValue = intrin.op1->AsIntCon()->gtIconVal; + GetEmitter()->emitIns_R_I(INS_movi, emitSize, targetReg, dataValue, opt); + } + else + { + // ins reg1[0], reg2 + GetEmitter()->emitIns_R_R_I(ins, emitTypeSize(intrin.baseType), targetReg, op1Reg, 0, + INS_OPTS_NONE); + } + } + break; + + case NI_AdvSimd_AddWideningLower: + case NI_AdvSimd_AddWideningUpper: + case NI_AdvSimd_SubtractWideningLower: + case NI_AdvSimd_SubtractWideningUpper: + GetEmitter()->emitIns_R_R_R(ins, emitSize, targetReg, op1Reg, op2Reg, opt); + break; + + // mvni doesn't support the range of element types, so hard code the 'opts' value. + case NI_Vector64_get_Zero: + case NI_Vector64_get_AllBitsSet: + GetEmitter()->emitIns_R_I(ins, emitSize, targetReg, 0, INS_OPTS_2S); + break; + + case NI_Vector128_get_Zero: + case NI_Vector128_get_AllBitsSet: + GetEmitter()->emitIns_R_I(ins, emitSize, targetReg, 0, INS_OPTS_4S); + break; + + case NI_AdvSimd_DuplicateToVector64: + case NI_AdvSimd_DuplicateToVector128: + case NI_AdvSimd_Arm64_DuplicateToVector64: + case NI_AdvSimd_Arm64_DuplicateToVector128: + { + if (varTypeIsFloating(intrin.baseType)) + { + if (intrin.op1->isContainedFltOrDblImmed()) + { + const double dataValue = intrin.op1->AsDblCon()->gtDconVal; + GetEmitter()->emitIns_R_F(INS_fmov, emitSize, targetReg, dataValue, opt); + } + else if (intrin.id == NI_AdvSimd_Arm64_DuplicateToVector64) + { + assert(intrin.baseType == TYP_DOUBLE); + GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op1Reg, opt); + } + else + { + GetEmitter()->emitIns_R_R_I(ins, emitSize, targetReg, op1Reg, 0, opt); + } + } + else if (intrin.op1->isContainedIntOrIImmed()) + { + const ssize_t dataValue = intrin.op1->AsIntCon()->gtIconVal; + GetEmitter()->emitIns_R_I(INS_movi, emitSize, targetReg, dataValue, opt); + } + else + { + GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op1Reg, opt); + } + } + break; + + case NI_Vector64_ToVector128: + GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op1Reg); + break; + + case NI_Vector64_ToVector128Unsafe: + case NI_Vector128_GetLower: + if (op1Reg != targetReg) + { + GetEmitter()->emitIns_R_R(ins, emitSize, targetReg, op1Reg); + } + break; + + case NI_Vector64_GetElement: + case NI_Vector128_GetElement: + case NI_Vector64_ToScalar: + case NI_Vector128_ToScalar: + { + ssize_t indexValue = 0; + if ((intrin.id == NI_Vector64_GetElement) || (intrin.id == NI_Vector128_GetElement)) + { + assert(intrin.op2->IsCnsIntOrI()); + indexValue = intrin.op2->AsIntCon()->gtIconVal; + } + + // no-op if vector is float/double, targetReg == op1Reg and fetching for 0th index. + if ((varTypeIsFloating(intrin.baseType) && (targetReg == op1Reg) && (indexValue == 0))) + { + break; + } + + GetEmitter()->emitIns_R_R_I(ins, emitTypeSize(intrin.baseType), targetReg, op1Reg, indexValue, + INS_OPTS_NONE); + } + break; + + case NI_AdvSimd_ShiftLeftLogicalSaturateScalar: + case NI_AdvSimd_ShiftLeftLogicalSaturateUnsignedScalar: + case NI_AdvSimd_ShiftLeftLogicalScalar: + case NI_AdvSimd_ShiftRightArithmeticRoundedScalar: + case NI_AdvSimd_ShiftRightArithmeticScalar: + case NI_AdvSimd_ShiftRightLogicalRoundedScalar: + case NI_AdvSimd_ShiftRightLogicalScalar: + case NI_AdvSimd_Arm64_ShiftLeftLogicalSaturateScalar: + case NI_AdvSimd_Arm64_ShiftLeftLogicalSaturateUnsignedScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticNarrowingSaturateScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticNarrowingSaturateUnsignedScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticRoundedNarrowingSaturateScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar: + case NI_AdvSimd_Arm64_ShiftRightLogicalNarrowingSaturateScalar: + case NI_AdvSimd_Arm64_ShiftRightLogicalRoundedNarrowingSaturateScalar: + opt = INS_OPTS_NONE; + emitSize = emitTypeSize(intrin.baseType); + __fallthrough; + + case NI_AdvSimd_ShiftLeftLogical: + case NI_AdvSimd_ShiftLeftLogicalSaturate: + case NI_AdvSimd_ShiftLeftLogicalSaturateUnsigned: + case NI_AdvSimd_ShiftLeftLogicalWideningLower: + case NI_AdvSimd_ShiftLeftLogicalWideningUpper: + case NI_AdvSimd_ShiftRightArithmetic: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateUnsignedLower: + case NI_AdvSimd_ShiftRightArithmeticRounded: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower: + case NI_AdvSimd_ShiftRightLogical: + case NI_AdvSimd_ShiftRightLogicalNarrowingLower: + case NI_AdvSimd_ShiftRightLogicalNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightLogicalRounded: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingLower: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingSaturateLower: + { + HWIntrinsicImmOpHelper helper(this, intrin.op2, node); + + for (helper.EmitBegin(); !helper.Done(); helper.EmitCaseEnd()) + { + const int shiftAmount = helper.ImmValue(); + + GetEmitter()->emitIns_R_R_I(ins, emitSize, targetReg, op1Reg, shiftAmount, opt); + } + } + break; + + case NI_AdvSimd_ShiftRightArithmeticAddScalar: + case NI_AdvSimd_ShiftRightArithmeticRoundedAddScalar: + case NI_AdvSimd_ShiftRightLogicalAddScalar: + case NI_AdvSimd_ShiftRightLogicalRoundedAddScalar: + opt = INS_OPTS_NONE; + emitSize = emitTypeSize(intrin.baseType); + __fallthrough; + + case NI_AdvSimd_ShiftRightArithmeticAdd: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateUnsignedUpper: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightArithmeticRoundedAdd: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightLogicalAdd: + case NI_AdvSimd_ShiftRightLogicalNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightLogicalNarrowingUpper: + case NI_AdvSimd_ShiftRightLogicalRoundedAdd: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingUpper: + { + assert(isRMW); + + if (targetReg != op1Reg) + { + GetEmitter()->emitIns_R_R(INS_mov, emitTypeSize(node), targetReg, op1Reg); + } + + HWIntrinsicImmOpHelper helper(this, intrin.op3, node); + + for (helper.EmitBegin(); !helper.Done(); helper.EmitCaseEnd()) + { + const int shiftAmount = helper.ImmValue(); + + GetEmitter()->emitIns_R_R_I(ins, emitSize, targetReg, op2Reg, shiftAmount, opt); + } + } + break; + default: unreached(); } diff --git a/src/coreclr/src/jit/hwintrinsiccodegenxarch.cpp b/src/coreclr/src/jit/hwintrinsiccodegenxarch.cpp index 0f72d43822d7d5..2b6336d2cecd80 100644 --- a/src/coreclr/src/jit/hwintrinsiccodegenxarch.cpp +++ b/src/coreclr/src/jit/hwintrinsiccodegenxarch.cpp @@ -82,9 +82,10 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; CORINFO_InstructionSet isa = HWIntrinsicInfo::lookupIsa(intrinsicId); HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsicId); - int ival = HWIntrinsicInfo::lookupIval(intrinsicId); int numArgs = HWIntrinsicInfo::lookupNumArgs(node); + int ival = HWIntrinsicInfo::lookupIval(intrinsicId, compiler->compOpportunisticallyDependsOn(InstructionSet_AVX)); + assert(HWIntrinsicInfo::RequiresCodegen(intrinsicId)); if (genIsTableDrivenHWIntrinsic(intrinsicId, category)) @@ -102,7 +103,7 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) assert(numArgs >= 0); instruction ins = HWIntrinsicInfo::lookupIns(intrinsicId, baseType); assert(ins != INS_invalid); - emitAttr simdSize = EA_ATTR(node->gtSIMDSize); + emitAttr simdSize = emitActualTypeSize(Compiler::getSIMDTypeForSize(node->gtSIMDSize)); assert(simdSize != 0); switch (numArgs) @@ -254,11 +255,11 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) } else if (node->TypeGet() == TYP_VOID) { - genHWIntrinsic_R_RM(node, ins, EA_ATTR(node->gtSIMDSize), op1Reg, op2); + genHWIntrinsic_R_RM(node, ins, simdSize, op1Reg, op2); } else { - genHWIntrinsic_R_R_RM(node, ins, EA_ATTR(node->gtSIMDSize)); + genHWIntrinsic_R_R_RM(node, ins, simdSize); } break; } @@ -359,6 +360,10 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node) case InstructionSet_Vector256: genBaseIntrinsic(node); break; + case InstructionSet_X86Base: + case InstructionSet_X86Base_X64: + genX86BaseIntrinsic(node); + break; case InstructionSet_SSE: case InstructionSet_SSE_X64: genSSEIntrinsic(node); @@ -546,7 +551,7 @@ void CodeGen::genHWIntrinsic_R_RM_I(GenTreeHWIntrinsic* node, instruction ins, i var_types targetType = node->TypeGet(); regNumber targetReg = node->GetRegNum(); GenTree* op1 = node->gtGetOp1(); - emitAttr simdSize = EA_ATTR(node->gtSIMDSize); + emitAttr simdSize = emitActualTypeSize(Compiler::getSIMDTypeForSize(node->gtSIMDSize)); emitter* emit = GetEmitter(); // TODO-XArch-CQ: Commutative operations can have op1 be contained @@ -628,7 +633,7 @@ void CodeGen::genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins, regNumber targetReg = node->GetRegNum(); GenTree* op1 = node->gtGetOp1(); GenTree* op2 = node->gtGetOp2(); - emitAttr simdSize = EA_ATTR(node->gtSIMDSize); + emitAttr simdSize = emitActualTypeSize(Compiler::getSIMDTypeForSize(node->gtSIMDSize)); emitter* emit = GetEmitter(); // TODO-XArch-CQ: Commutative operations can have op1 be contained @@ -792,7 +797,7 @@ void CodeGen::genHWIntrinsic_R_R_RM_R(GenTreeHWIntrinsic* node, instruction ins) GenTree* op1 = node->gtGetOp1(); GenTree* op2 = node->gtGetOp2(); GenTree* op3 = nullptr; - emitAttr simdSize = EA_ATTR(node->gtSIMDSize); + emitAttr simdSize = emitActualTypeSize(Compiler::getSIMDTypeForSize(node->gtSIMDSize)); emitter* emit = GetEmitter(); assert(op1->OperIsList()); @@ -1146,7 +1151,7 @@ void CodeGen::genBaseIntrinsic(GenTreeHWIntrinsic* node) assert(node->gtGetOp2() == nullptr); emitter* emit = GetEmitter(); - emitAttr attr = EA_ATTR(node->gtSIMDSize); + emitAttr attr = emitActualTypeSize(Compiler::getSIMDTypeForSize(node->gtSIMDSize)); instruction ins = HWIntrinsicInfo::lookupIns(intrinsicId, baseType); switch (intrinsicId) @@ -1231,14 +1236,32 @@ void CodeGen::genBaseIntrinsic(GenTreeHWIntrinsic* node) break; } - case NI_Vector128_Zero: - case NI_Vector256_Zero: + case NI_Vector128_get_Zero: + case NI_Vector256_get_Zero: { assert(op1 == nullptr); emit->emitIns_SIMD_R_R_R(ins, attr, targetReg, targetReg, targetReg); break; } + case NI_Vector128_get_AllBitsSet: + case NI_Vector256_get_AllBitsSet: + { + assert(op1 == nullptr); + if (varTypeIsFloating(baseType) && compiler->compOpportunisticallyDependsOn(InstructionSet_AVX)) + { + // The immediate 8 means Equal (unordered, non-signaling) + // This is not available without VEX prefix. + emit->emitIns_SIMD_R_R_R_I(ins, attr, targetReg, targetReg, targetReg, 8); + } + else + { + assert(varTypeIsIntegral(baseType) || !compiler->compIsaSupportedDebugOnly(InstructionSet_AVX)); + emit->emitIns_SIMD_R_R_R(INS_pcmpeqd, attr, targetReg, targetReg, targetReg); + } + break; + } + default: { unreached(); @@ -1249,6 +1272,40 @@ void CodeGen::genBaseIntrinsic(GenTreeHWIntrinsic* node) genProduceReg(node); } +//------------------------------------------------------------------------ +// genX86BaseIntrinsic: Generates the code for an X86 base hardware intrinsic node +// +// Arguments: +// node - The hardware intrinsic node +// +void CodeGen::genX86BaseIntrinsic(GenTreeHWIntrinsic* node) +{ + NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; + + switch (intrinsicId) + { + case NI_X86Base_BitScanForward: + case NI_X86Base_BitScanReverse: + case NI_X86Base_X64_BitScanForward: + case NI_X86Base_X64_BitScanReverse: + { + GenTree* op1 = node->gtGetOp1(); + regNumber targetReg = node->GetRegNum(); + var_types targetType = node->TypeGet(); + instruction ins = HWIntrinsicInfo::lookupIns(intrinsicId, targetType); + + genConsumeOperands(node); + genHWIntrinsic_R_RM(node, ins, emitTypeSize(targetType), targetReg, op1); + genProduceReg(node); + break; + } + + default: + unreached(); + break; + } +} + //------------------------------------------------------------------------ // genSSEIntrinsic: Generates the code for an SSE hardware intrinsic node // @@ -1352,25 +1409,6 @@ void CodeGen::genSSE2Intrinsic(GenTreeHWIntrinsic* node) switch (intrinsicId) { - // All integer overloads are handled by table codegen - case NI_SSE2_CompareLessThan: - { - assert(op1 != nullptr); - assert(op2 != nullptr); - - assert(baseType == TYP_DOUBLE); - - int ival = HWIntrinsicInfo::lookupIval(intrinsicId); - assert((ival >= 0) && (ival <= 127)); - - instruction ins = HWIntrinsicInfo::lookupIns(intrinsicId, baseType); - op1Reg = op1->GetRegNum(); - op2Reg = op2->GetRegNum(); - emit->emitIns_SIMD_R_R_R_I(ins, emitTypeSize(TYP_SIMD16), targetReg, op1Reg, op2Reg, ival); - - break; - } - case NI_SSE2_X64_ConvertScalarToVector128Double: { assert(baseType == TYP_LONG); @@ -1621,7 +1659,7 @@ void CodeGen::genAvxOrAvx2Intrinsic(GenTreeHWIntrinsic* node) { NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; var_types baseType = node->gtSIMDBaseType; - emitAttr attr = EA_ATTR(node->gtSIMDSize); + emitAttr attr = emitActualTypeSize(Compiler::getSIMDTypeForSize(node->gtSIMDSize)); var_types targetType = node->TypeGet(); instruction ins = HWIntrinsicInfo::lookupIns(intrinsicId, baseType); int numArgs = HWIntrinsicInfo::lookupNumArgs(node); @@ -1731,7 +1769,7 @@ void CodeGen::genAvxOrAvx2Intrinsic(GenTreeHWIntrinsic* node) bool isVector128GatherWithVector256Index = (targetType == TYP_SIMD16) && (indexOp->TypeGet() == TYP_SIMD32); // hwintrinsiclistxarch.h uses Dword index instructions in default - if (varTypeIsLong(node->gtIndexBaseType)) + if (varTypeIsLong(node->GetOtherBaseType())) { switch (ins) { @@ -1934,7 +1972,7 @@ void CodeGen::genFMAIntrinsic(GenTreeHWIntrinsic* node) { NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; var_types baseType = node->gtSIMDBaseType; - emitAttr attr = EA_ATTR(node->gtSIMDSize); + emitAttr attr = emitActualTypeSize(Compiler::getSIMDTypeForSize(node->gtSIMDSize)); instruction ins = HWIntrinsicInfo::lookupIns(intrinsicId, baseType); GenTree* op1 = node->gtGetOp1(); regNumber targetReg = node->GetRegNum(); @@ -1960,16 +1998,7 @@ void CodeGen::genFMAIntrinsic(GenTreeHWIntrinsic* node) // Intrinsics with CopyUpperBits semantics cannot have op1 be contained assert(!copiesUpperBits || !op1->isContained()); - if (op3->isContained() || op3->isUsedFromSpillTemp()) - { - // 213 form: op1 = (op2 * op1) + [op3] - - op1Reg = op1->GetRegNum(); - op2Reg = op2->GetRegNum(); - - isCommutative = !copiesUpperBits; - } - else if (op2->isContained() || op2->isUsedFromSpillTemp()) + if (op2->isContained() || op2->isUsedFromSpillTemp()) { // 132 form: op1 = (op1 * op3) + [op2] @@ -1989,7 +2018,7 @@ void CodeGen::genFMAIntrinsic(GenTreeHWIntrinsic* node) } else { - // 213 form: op1 = (op2 * op1) + op3 + // 213 form: op1 = (op2 * op1) + [op3] op1Reg = op1->GetRegNum(); op2Reg = op2->GetRegNum(); diff --git a/src/coreclr/src/jit/hwintrinsiclistarm64.h b/src/coreclr/src/jit/hwintrinsiclistarm64.h index b314a5e2e4ab9c..be8a0d552da75e 100644 --- a/src/coreclr/src/jit/hwintrinsiclistarm64.h +++ b/src/coreclr/src/jit/hwintrinsiclistarm64.h @@ -12,246 +12,393 @@ #ifdef FEATURE_HW_INTRINSICS // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// ISA Function name ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size Number of arguments Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // Vector64 Intrinsics -HARDWARE_INTRINSIC(Vector64, AsByte, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector64, AsInt16, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector64, AsInt32, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector64, AsSByte, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector64, AsSingle, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector64, AsUInt16, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector64, AsUInt32, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector64, get_Count, -1, 8, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, AsByte, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector64, AsInt16, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector64, AsInt32, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector64, AsSByte, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector64, AsSingle, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector64, AsUInt16, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector64, AsUInt32, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector64, Create, 8, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov, INS_mov, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, CreateScalarUnsafe, 8, 1, {INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_invalid, INS_invalid, INS_fmov, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Vector64, get_AllBitsSet, 8, 0, {INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Vector64, get_Count, 8, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, get_Zero, 8, 0, {INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Vector64, GetElement, 8, 2, {INS_smov, INS_umov, INS_smov, INS_umov, INS_smov, INS_umov, INS_umov, INS_umov, INS_dup, INS_dup}, HW_Category_IMM, HW_Flag_NoJmpTableIMM|HW_Flag_SupportsContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Vector64, op_Equality, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, op_Inequality, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector64, ToScalar, 8, 1, {INS_smov, INS_umov, INS_smov, INS_umov, INS_smov, INS_umov, INS_umov, INS_umov, INS_dup, INS_dup}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector64, ToVector128, 8, 1, {INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Vector64, ToVector128Unsafe, 8, 1, {INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// ISA Function name ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size Number of arguments Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // Vector128 Intrinsics -HARDWARE_INTRINSIC(Vector128, As, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector128, AsByte, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector128, AsDouble, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector128, AsInt16, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector128, AsInt32, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector128, AsInt64, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector128, AsSByte, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector128, AsSingle, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector128, AsUInt16, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector128, AsUInt32, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector128, AsUInt64, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector128, get_Count, -1, 16, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, As, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, AsByte, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, AsDouble, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, AsInt16, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, AsInt32, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, AsInt64, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, AsSByte, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, AsSingle, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, AsUInt16, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, AsUInt32, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, AsUInt64, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, Create, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, CreateScalarUnsafe, 16, 1, {INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_fmov, INS_fmov}, HW_Category_SimpleSIMD, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Vector128, get_AllBitsSet, 16, 0, {INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni, INS_mvni}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Vector128, get_Count, 16, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, get_Zero, 16, 0, {INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi, INS_movi}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Vector128, GetElement, 16, 2, {INS_smov, INS_umov, INS_smov, INS_umov, INS_smov, INS_umov, INS_umov, INS_umov, INS_dup, INS_dup}, HW_Category_IMM, HW_Flag_NoJmpTableIMM|HW_Flag_SupportsContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Vector128, GetLower, 16, 1, {INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Vector128, op_Equality, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, op_Inequality, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, ToScalar, 16, 1, {INS_smov, INS_umov, INS_smov, INS_umov, INS_smov, INS_umov, INS_umov, INS_umov, INS_dup, INS_dup}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// ISA Function name ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size Number of arguments Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // AdvSimd Intrinsics -HARDWARE_INTRINSIC(AdvSimd, Abs, -1, -1, 1, {INS_abs, INS_invalid, INS_abs, INS_invalid, INS_abs, INS_invalid, INS_invalid, INS_invalid, INS_fabs, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AdvSimd, AbsScalar, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fabs, INS_fabs}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd, AbsoluteCompareGreaterThan, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facgt, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, AbsoluteCompareGreaterThanOrEqual, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facge, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, AbsoluteCompareLessThan, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facgt, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd, AbsoluteCompareLessThanOrEqual, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facge, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd, AbsoluteDifference, -1, -1, 2, {INS_sabd, INS_uabd, INS_sabd, INS_uabd, INS_sabd, INS_uabd, INS_invalid, INS_invalid, INS_fabd, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AdvSimd, AbsoluteDifferenceAdd, -1, -1, 3, {INS_saba, INS_uaba, INS_saba, INS_uaba, INS_saba, INS_uaba, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(AdvSimd, Add, -1, -1, 2, {INS_add, INS_add, INS_add, INS_add, INS_add, INS_add, INS_add, INS_add, INS_fadd, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, AddPairwise, -1, 8, 2, {INS_addp, INS_addp, INS_addp, INS_addp, INS_addp, INS_addp, INS_invalid, INS_invalid, INS_faddp, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd, AddScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_add, INS_add, INS_fadd, INS_fadd}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd, And, -1, -1, 2, {INS_and, INS_and, INS_and, INS_and, INS_and, INS_and, INS_and, INS_and, INS_and, INS_and}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd, BitwiseClear, -1, -1, 2, {INS_bic, INS_bic, INS_bic, INS_bic, INS_bic, INS_bic, INS_bic, INS_bic, INS_bic, INS_bic}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, BitwiseSelect, -1, -1, 3, {INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd, CompareEqual, -1, -1, 2, {INS_cmeq, INS_cmeq, INS_cmeq, INS_cmeq, INS_cmeq, INS_cmeq, INS_invalid, INS_invalid, INS_fcmeq, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, CompareGreaterThan, -1, -1, 2, {INS_cmgt, INS_cmhi, INS_cmgt, INS_cmhi, INS_cmgt, INS_cmhi, INS_invalid, INS_invalid, INS_fcmgt, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, CompareGreaterThanOrEqual, -1, -1, 2, {INS_cmge, INS_cmhs, INS_cmge, INS_cmhs, INS_cmge, INS_cmhs, INS_invalid, INS_invalid, INS_fcmge, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, CompareLessThan, -1, -1, 2, {INS_cmgt, INS_cmhi, INS_cmgt, INS_cmhi, INS_cmgt, INS_cmhi, INS_invalid, INS_invalid, INS_fcmgt, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd, CompareLessThanOrEqual, -1, -1, 2, {INS_cmge, INS_cmhs, INS_cmge, INS_cmhs, INS_cmge, INS_cmhs, INS_invalid, INS_invalid, INS_fcmge, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd, CompareTest, -1, -1, 2, {INS_cmtst, INS_cmtst, INS_cmtst, INS_cmtst, INS_cmtst, INS_cmtst, INS_invalid, INS_invalid, INS_cmtst, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, DivideScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fdiv, INS_fdiv}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd, ExtractAndNarrowLow, -1, 8, 1, {INS_xtn, INS_xtn, INS_xtn, INS_xtn, INS_xtn, INS_xtn, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd, ExtractAndNarrowHigh, -1, 16, 2, {INS_xtn2, INS_xtn2, INS_xtn2, INS_xtn2, INS_xtn2, INS_xtn2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(AdvSimd, FusedMultiplyAdd, -1, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmla, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(AdvSimd, FusedMultiplyAddScalar, -1, 8, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmadd, INS_fmadd}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd, FusedMultiplyAddNegatedScalar, -1, 8, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fnmadd, INS_fnmadd}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd, FusedMultiplySubtract, -1, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmls, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(AdvSimd, FusedMultiplySubtractScalar, -1, 8, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmsub, INS_fmsub}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd, FusedMultiplySubtractNegatedScalar, -1, 8, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fnmsub, INS_fnmsub}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd, LeadingSignCount, -1, -1, 1, {INS_cls, INS_invalid, INS_cls, INS_invalid, INS_cls, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, LeadingZeroCount, -1, -1, 1, {INS_clz, INS_clz, INS_clz, INS_clz, INS_clz, INS_clz, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, LoadVector64, -1, 8, 1, {INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AdvSimd, LoadVector128, -1, 16, 1, {INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AdvSimd, Max, -1, -1, 2, {INS_smax, INS_umax, INS_smax, INS_umax, INS_smax, INS_umax, INS_invalid, INS_invalid, INS_fmax, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd, MaxNumber, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxnm, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd, MaxNumberScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxnm, INS_fmaxnm}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd, MaxPairwise, -1, 8, 2, {INS_smaxp, INS_umaxp, INS_smaxp, INS_umaxp, INS_smaxp, INS_umaxp, INS_invalid, INS_invalid, INS_fmaxp, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd, Min, -1, -1, 2, {INS_smin, INS_umin, INS_smin, INS_umin, INS_smin, INS_umin, INS_invalid, INS_invalid, INS_fmin, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd, MinNumber, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminnm, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd, MinNumberScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminnm, INS_fminnm}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd, MinPairwise, -1, 8, 2, {INS_sminp, INS_uminp, INS_sminp, INS_uminp, INS_sminp, INS_uminp, INS_invalid, INS_invalid, INS_fminp, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd, Multiply, -1, -1, 2, {INS_mul, INS_mul, INS_mul, INS_mul, INS_mul, INS_mul, INS_invalid, INS_invalid, INS_fmul, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd, MultiplyScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmul, INS_fmul}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd, MultiplyAdd, -1, -1, 3, {INS_mla, INS_mla, INS_mla, INS_mla, INS_mla, INS_mla, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(AdvSimd, MultiplySubtract, -1, -1, 3, {INS_mls, INS_mls, INS_mls, INS_mls, INS_mls, INS_mls, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(AdvSimd, Negate, -1, -1, 1, {INS_neg, INS_invalid, INS_neg, INS_invalid, INS_neg, INS_invalid, INS_invalid, INS_invalid, INS_fneg, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, NegateScalar, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fneg, INS_fneg}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd, Not, -1, -1, 1, {INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, Or, -1, -1, 2, {INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd, OrNot, -1, -1, 2, {INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, PolynomialMultiply, -1, -1, 2, {INS_pmul, INS_pmul, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd, PopCount, -1, -1, 1, {INS_cnt, INS_cnt, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, ReciprocalEstimate, -1, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_urecpe, INS_invalid, INS_invalid, INS_frecpe, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, ReciprocalSquareRootEstimate, -1, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ursqrte, INS_invalid, INS_invalid, INS_frsqrte, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, ReciprocalSquareRootStep, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrts, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd, ReciprocalStep, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd, SqrtScalar, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fsqrt, INS_fsqrt}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd, Store, -1, -1, 2, {INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1}, HW_Category_MemoryStore, HW_Flag_UnfixedSIMDSize|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(AdvSimd, Subtract, -1, -1, 2, {INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_fsub, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd, SubtractScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sub, INS_sub, INS_fsub, INS_fsub}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd, Xor, -1, -1, 2, {INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, Abs, -1, 1, {INS_abs, INS_invalid, INS_abs, INS_invalid, INS_abs, INS_invalid, INS_invalid, INS_invalid, INS_fabs, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd, AbsScalar, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fabs, INS_fabs}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, AbsoluteCompareGreaterThan, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facgt, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, AbsoluteCompareGreaterThanOrEqual, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facge, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, AbsoluteCompareLessThan, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facgt, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, AbsoluteCompareLessThanOrEqual, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facge, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, AbsoluteDifference, -1, 2, {INS_sabd, INS_uabd, INS_sabd, INS_uabd, INS_sabd, INS_uabd, INS_invalid, INS_invalid, INS_fabd, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd, AbsoluteDifferenceAdd, -1, 3, {INS_saba, INS_uaba, INS_saba, INS_uaba, INS_saba, INS_uaba, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, AbsoluteDifferenceWideningLower, 8, 2, {INS_sabdl, INS_uabdl, INS_sabdl, INS_uabdl, INS_sabdl, INS_uabdl, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd, AbsoluteDifferenceWideningLowerAndAdd, 8, 3, {INS_sabal, INS_uabal, INS_sabal, INS_uabal, INS_sabal, INS_uabal, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AdvSimd, AbsoluteDifferenceWideningUpper, 16, 2, {INS_sabdl2, INS_uabdl2, INS_sabdl2, INS_uabdl2, INS_sabdl2, INS_uabdl2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd, AbsoluteDifferenceWideningUpperAndAdd, 16, 3, {INS_sabal2, INS_uabal2, INS_sabal2, INS_uabal2, INS_sabal2, INS_uabal2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AdvSimd, Add, -1, 2, {INS_add, INS_add, INS_add, INS_add, INS_add, INS_add, INS_add, INS_add, INS_fadd, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, AddHighNarrowingLower, 8, 2, {INS_addhn, INS_addhn, INS_addhn, INS_addhn, INS_addhn, INS_addhn, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, AddHighNarrowingUpper, 16, 3, {INS_addhn2, INS_addhn2, INS_addhn2, INS_addhn2, INS_addhn2, INS_addhn2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, AddPairwise, 8, 2, {INS_addp, INS_addp, INS_addp, INS_addp, INS_addp, INS_addp, INS_invalid, INS_invalid, INS_faddp, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, AddPairwiseWidening, -1, 1, {INS_saddlp, INS_uaddlp, INS_saddlp, INS_uaddlp, INS_saddlp, INS_uaddlp, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd, AddPairwiseWideningAndAdd, -1, 2, {INS_sadalp, INS_uadalp, INS_sadalp, INS_uadalp, INS_sadalp, INS_uadalp, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AdvSimd, AddPairwiseWideningAndAddScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sadalp, INS_uadalp, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AdvSimd, AddPairwiseWideningScalar, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_saddlp, INS_uaddlp, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd, AddRoundedHighNarrowingLower, 8, 2, {INS_raddhn, INS_raddhn, INS_raddhn, INS_raddhn, INS_raddhn, INS_raddhn, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, AddRoundedHighNarrowingUpper, 16, 3, {INS_raddhn2, INS_raddhn2, INS_raddhn2, INS_raddhn2, INS_raddhn2, INS_raddhn2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, AddSaturate, -1, 2, {INS_sqadd, INS_uqadd, INS_sqadd, INS_uqadd, INS_sqadd, INS_uqadd, INS_sqadd, INS_uqadd, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, AddSaturateScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqadd, INS_uqadd, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, AddScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_add, INS_add, INS_fadd, INS_fadd}, HW_Category_SIMDScalar, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, AddWideningLower, 8, 2, {INS_saddl, INS_uaddl, INS_saddl, INS_uaddl, INS_saddl, INS_uaddl, INS_saddw, INS_uaddw, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromSecondArg|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, AddWideningUpper, 16, 2, {INS_saddl2, INS_uaddl2, INS_saddl2, INS_uaddl2, INS_saddl2, INS_uaddl2, INS_saddw2, INS_uaddw2, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromSecondArg|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, And, -1, 2, {INS_and, INS_and, INS_and, INS_and, INS_and, INS_and, INS_and, INS_and, INS_and, INS_and}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, BitwiseClear, -1, 2, {INS_bic, INS_bic, INS_bic, INS_bic, INS_bic, INS_bic, INS_bic, INS_bic, INS_bic, INS_bic}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, BitwiseSelect, -1, 3, {INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl, INS_bsl}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, Ceiling, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frintp, INS_frintp}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, CompareEqual, -1, 2, {INS_cmeq, INS_cmeq, INS_cmeq, INS_cmeq, INS_cmeq, INS_cmeq, INS_invalid, INS_invalid, INS_fcmeq, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, CompareGreaterThan, -1, 2, {INS_cmgt, INS_cmhi, INS_cmgt, INS_cmhi, INS_cmgt, INS_cmhi, INS_invalid, INS_invalid, INS_fcmgt, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, CompareGreaterThanOrEqual, -1, 2, {INS_cmge, INS_cmhs, INS_cmge, INS_cmhs, INS_cmge, INS_cmhs, INS_invalid, INS_invalid, INS_fcmge, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, CompareLessThan, -1, 2, {INS_cmgt, INS_cmhi, INS_cmgt, INS_cmhi, INS_cmgt, INS_cmhi, INS_invalid, INS_invalid, INS_fcmgt, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, CompareLessThanOrEqual, -1, 2, {INS_cmge, INS_cmhs, INS_cmge, INS_cmhs, INS_cmge, INS_cmhs, INS_invalid, INS_invalid, INS_fcmge, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, CompareTest, -1, 2, {INS_cmtst, INS_cmtst, INS_cmtst, INS_cmtst, INS_cmtst, INS_cmtst, INS_invalid, INS_invalid, INS_cmtst, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, DivideScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fdiv, INS_fdiv}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, DuplicateSelectedScalarToVector64, -1, 2, {INS_dup, INS_dup, INS_dup, INS_dup, INS_dup, INS_dup, INS_invalid, INS_invalid, INS_dup, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, DuplicateSelectedScalarToVector128, -1, 2, {INS_dup, INS_dup, INS_dup, INS_dup, INS_dup, INS_dup, INS_invalid, INS_invalid, INS_dup, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, DuplicateToVector64, 8, 1, {INS_dup, INS_dup, INS_dup, INS_dup, INS_dup, INS_dup, INS_invalid, INS_invalid, INS_dup, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, DuplicateToVector128, 16, 1, {INS_dup, INS_dup, INS_dup, INS_dup, INS_dup, INS_dup, INS_invalid, INS_invalid, INS_dup, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, Extract, -1, 2, {INS_smov, INS_umov, INS_smov, INS_umov, INS_smov, INS_umov, INS_umov, INS_umov, INS_dup, INS_dup}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ExtractNarrowingUpper, 16, 2, {INS_xtn2, INS_xtn2, INS_xtn2, INS_xtn2, INS_xtn2, INS_xtn2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ExtractNarrowingLower, 8, 1, {INS_xtn, INS_xtn, INS_xtn, INS_xtn, INS_xtn, INS_xtn, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ExtractVector64, 8, 3, {INS_ext, INS_ext, INS_ext, INS_ext, INS_ext, INS_ext, INS_invalid, INS_invalid, INS_ext, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ExtractVector128, 16, 3, {INS_ext, INS_ext, INS_ext, INS_ext, INS_ext, INS_ext, INS_ext, INS_ext, INS_ext, INS_ext}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, Floor, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frintm, INS_frintm}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, FusedAddHalving, -1, 2, {INS_shadd, INS_uhadd, INS_shadd, INS_uhadd, INS_shadd, INS_uhadd, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, FusedAddRoundedHalving, -1, 2, {INS_srhadd, INS_urhadd, INS_srhadd, INS_urhadd, INS_srhadd, INS_urhadd, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, FusedMultiplyAdd, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmla, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, FusedMultiplyAddScalar, 8, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmadd, INS_fmadd}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, FusedMultiplyAddNegatedScalar, 8, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fnmadd, INS_fnmadd}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, FusedMultiplySubtract, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmls, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, FusedMultiplySubtractScalar, 8, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmsub, INS_fmsub}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, FusedMultiplySubtractNegatedScalar, 8, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fnmsub, INS_fnmsub}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, FusedSubtractHalving, -1, 2, {INS_shsub, INS_uhsub, INS_shsub, INS_uhsub, INS_shsub, INS_uhsub, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, Insert, -1, 3, {INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins, INS_ins}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, LeadingSignCount, -1, 1, {INS_cls, INS_invalid, INS_cls, INS_invalid, INS_cls, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, LeadingZeroCount, -1, 1, {INS_clz, INS_clz, INS_clz, INS_clz, INS_clz, INS_clz, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, LoadVector64, 8, 1, {INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1}, HW_Category_MemoryLoad, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, LoadVector128, 16, 1, {INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1, INS_ld1}, HW_Category_MemoryLoad, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, Max, -1, 2, {INS_smax, INS_umax, INS_smax, INS_umax, INS_smax, INS_umax, INS_invalid, INS_invalid, INS_fmax, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, MaxNumber, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxnm, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, MaxNumberScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxnm, INS_fmaxnm}, HW_Category_SIMDScalar, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, MaxPairwise, 8, 2, {INS_smaxp, INS_umaxp, INS_smaxp, INS_umaxp, INS_smaxp, INS_umaxp, INS_invalid, INS_invalid, INS_fmaxp, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, Min, -1, 2, {INS_smin, INS_umin, INS_smin, INS_umin, INS_smin, INS_umin, INS_invalid, INS_invalid, INS_fmin, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, MinNumber, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminnm, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, MinNumberScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminnm, INS_fminnm}, HW_Category_SIMDScalar, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, MinPairwise, 8, 2, {INS_sminp, INS_uminp, INS_sminp, INS_uminp, INS_sminp, INS_uminp, INS_invalid, INS_invalid, INS_fminp, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, Multiply, -1, 2, {INS_mul, INS_mul, INS_mul, INS_mul, INS_mul, INS_mul, INS_invalid, INS_invalid, INS_fmul, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, MultiplyScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmul, INS_fmul}, HW_Category_SIMDScalar, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, MultiplyAdd, -1, 3, {INS_mla, INS_mla, INS_mla, INS_mla, INS_mla, INS_mla, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, MultiplySubtract, -1, 3, {INS_mls, INS_mls, INS_mls, INS_mls, INS_mls, INS_mls, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, MultiplyWideningLower, 8, 2, {INS_smull, INS_umull, INS_smull, INS_umull, INS_smull, INS_umull, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd, MultiplyWideningLowerAndAdd, 8, 3, {INS_smlal, INS_umlal, INS_smlal, INS_umlal, INS_smlal, INS_umlal, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AdvSimd, MultiplyWideningLowerAndSubtract, 8, 3, {INS_smlsl, INS_umlsl, INS_smlsl, INS_umlsl, INS_smlsl, INS_umlsl, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AdvSimd, MultiplyWideningUpper, 16, 2, {INS_smull2, INS_umull2, INS_smull2, INS_umull2, INS_smull2, INS_umull2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd, MultiplyWideningUpperAndAdd, 16, 3, {INS_smlal2, INS_umlal2, INS_smlal2, INS_umlal2, INS_smlal2, INS_umlal2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AdvSimd, MultiplyWideningUpperAndSubtract, 16, 3, {INS_smlsl2, INS_umlsl2, INS_smlsl2, INS_umlsl2, INS_smlsl2, INS_umlsl2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AdvSimd, Negate, -1, 1, {INS_neg, INS_invalid, INS_neg, INS_invalid, INS_neg, INS_invalid, INS_invalid, INS_invalid, INS_fneg, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, NegateScalar, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fneg, INS_fneg}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, Not, -1, 1, {INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn, INS_mvn}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, Or, -1, 2, {INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr, INS_orr}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, OrNot, -1, 2, {INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn, INS_orn}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, PolynomialMultiply, -1, 2, {INS_pmul, INS_pmul, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, PolynomialMultiplyWideningLower, 8, 2, {INS_pmull, INS_pmull, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd, PolynomialMultiplyWideningUpper, 16, 2, {INS_pmull2, INS_pmull2, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd, PopCount, -1, 1, {INS_cnt, INS_cnt, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ReciprocalEstimate, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_urecpe, INS_invalid, INS_invalid, INS_frecpe, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ReciprocalSquareRootEstimate, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ursqrte, INS_invalid, INS_invalid, INS_frsqrte, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ReciprocalSquareRootStep, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrts, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, ReciprocalStep, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, ShiftArithmetic, -1, 2, {INS_sshl, INS_invalid, INS_sshl, INS_invalid, INS_sshl, INS_invalid, INS_sshl, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftArithmeticRounded, -1, 2, {INS_srshl, INS_invalid, INS_srshl, INS_invalid, INS_srshl, INS_invalid, INS_srshl, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftArithmeticRoundedSaturate, -1, 2, {INS_sqrshl, INS_invalid, INS_sqrshl, INS_invalid, INS_sqrshl, INS_invalid, INS_sqrshl, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftArithmeticRoundedSaturateScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrshl, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftArithmeticRoundedScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_srshl, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftArithmeticSaturate, -1, 2, {INS_sqshl, INS_invalid, INS_sqshl, INS_invalid, INS_sqshl, INS_invalid, INS_sqshl, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftArithmeticSaturateScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqshl, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftArithmeticScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sshl, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftLeftLogical, -1, 2, {INS_shl, INS_shl, INS_shl, INS_shl, INS_shl, INS_shl, INS_shl, INS_shl, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftLeftLogicalSaturate, -1, 2, {INS_sqshl, INS_uqshl, INS_sqshl, INS_uqshl, INS_sqshl, INS_uqshl, INS_sqshl, INS_uqshl, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftLeftLogicalSaturateScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqshl, INS_uqshl, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftLeftLogicalSaturateUnsigned, -1, 2, {INS_sqshlu, INS_invalid, INS_sqshlu, INS_invalid, INS_sqshlu, INS_invalid, INS_sqshlu, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftLeftLogicalSaturateUnsignedScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqshlu, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftLeftLogicalScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_shl, INS_shl, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftLeftLogicalWideningLower, 8, 2, {INS_sshll, INS_ushll, INS_sshll, INS_ushll, INS_sshll, INS_ushll, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftLeftLogicalWideningUpper, 16, 2, {INS_sshll2, INS_ushll2, INS_sshll2, INS_ushll2, INS_sshll2, INS_ushll2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftLogical, -1, 2, {INS_ushl, INS_ushl, INS_ushl, INS_ushl, INS_ushl, INS_ushl, INS_ushl, INS_ushl, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftLogicalRounded, -1, 2, {INS_urshl, INS_urshl, INS_urshl, INS_urshl, INS_urshl, INS_urshl, INS_urshl, INS_urshl, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftLogicalRoundedSaturate, -1, 2, {INS_uqrshl, INS_uqrshl, INS_uqrshl, INS_uqrshl, INS_uqrshl, INS_uqrshl, INS_uqrshl, INS_uqrshl, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftLogicalRoundedSaturateScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_uqrshl, INS_uqrshl, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftLogicalRoundedScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_urshl, INS_urshl, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftLogicalSaturate, -1, 2, {INS_uqshl, INS_uqshl, INS_uqshl, INS_uqshl, INS_uqshl, INS_uqshl, INS_uqshl, INS_uqshl, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftLogicalSaturateScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_uqshl, INS_uqshl, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftLogicalScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ushl, INS_ushl, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmetic, -1, 2, {INS_sshr, INS_invalid, INS_sshr, INS_invalid, INS_sshr, INS_invalid, INS_sshr, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticAdd, -1, 3, {INS_ssra, INS_invalid, INS_ssra, INS_invalid, INS_ssra, INS_invalid, INS_ssra, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticAddScalar, 8, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ssra, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticNarrowingSaturateLower, 8, 2, {INS_sqshrn, INS_invalid, INS_sqshrn, INS_invalid, INS_sqshrn, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticNarrowingSaturateUnsignedLower, 8, 2, {INS_invalid, INS_sqshrun, INS_invalid, INS_sqshrun, INS_invalid, INS_sqshrun, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticNarrowingSaturateUnsignedUpper, 16, 3, {INS_invalid, INS_sqshrun2, INS_invalid, INS_sqshrun2, INS_invalid, INS_sqshrun2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticNarrowingSaturateUpper, 16, 3, {INS_sqshrn2, INS_invalid, INS_sqshrn2, INS_invalid, INS_sqshrn2, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticRounded, -1, 2, {INS_srshr, INS_invalid, INS_srshr, INS_invalid, INS_srshr, INS_invalid, INS_srshr, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticRoundedAdd, -1, 3, {INS_srsra, INS_invalid, INS_srsra, INS_invalid, INS_srsra, INS_invalid, INS_srsra, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticRoundedAddScalar, 8, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_srsra, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticRoundedNarrowingSaturateLower, 8, 2, {INS_sqrshrn, INS_invalid, INS_sqrshrn, INS_invalid, INS_sqrshrn, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower, 8, 2, {INS_invalid, INS_sqrshrun, INS_invalid, INS_sqrshrun, INS_invalid, INS_sqrshrun, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper, 16, 3, {INS_invalid, INS_sqrshrun2, INS_invalid, INS_sqrshrun2, INS_invalid, INS_sqrshrun2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticRoundedNarrowingSaturateUpper, 16, 3, {INS_sqrshrn2, INS_invalid, INS_sqrshrn2, INS_invalid, INS_sqrshrn2, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticRoundedScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_srshr, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightArithmeticScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sshr, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogical, -1, 2, {INS_ushr, INS_ushr, INS_ushr, INS_ushr, INS_ushr, INS_ushr, INS_ushr, INS_ushr, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalAdd, -1, 3, {INS_usra, INS_usra, INS_usra, INS_usra, INS_usra, INS_usra, INS_usra, INS_usra, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalAddScalar, 8, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_usra, INS_usra, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalNarrowingLower, 8, 2, {INS_shrn, INS_shrn, INS_shrn, INS_shrn, INS_shrn, INS_shrn, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalNarrowingSaturateLower, 8, 2, {INS_uqshrn, INS_uqshrn, INS_uqshrn, INS_uqshrn, INS_uqshrn, INS_uqshrn, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalNarrowingSaturateUpper, 16, 3, {INS_uqshrn2, INS_uqshrn2, INS_uqshrn2, INS_uqshrn2, INS_uqshrn2, INS_uqshrn2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalNarrowingUpper, 16, 3, {INS_shrn2, INS_shrn2, INS_shrn2, INS_shrn2, INS_shrn2, INS_shrn2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalRounded, -1, 2, {INS_urshr, INS_urshr, INS_urshr, INS_urshr, INS_urshr, INS_urshr, INS_urshr, INS_urshr, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalRoundedAdd, -1, 3, {INS_ursra, INS_ursra, INS_ursra, INS_ursra, INS_ursra, INS_ursra, INS_ursra, INS_ursra, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalRoundedAddScalar, 8, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ursra, INS_ursra, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalRoundedNarrowingLower, 8, 2, {INS_rshrn, INS_rshrn, INS_rshrn, INS_rshrn, INS_rshrn, INS_rshrn, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalRoundedNarrowingSaturateLower, 8, 2, {INS_uqrshrn, INS_uqrshrn, INS_uqrshrn, INS_uqrshrn, INS_uqrshrn, INS_uqrshrn, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalRoundedNarrowingSaturateUpper, 16, 3, {INS_uqrshrn2, INS_uqrshrn2, INS_uqrshrn2, INS_uqrshrn2, INS_uqrshrn2, INS_uqrshrn2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalRoundedNarrowingUpper, 16, 3, {INS_rshrn2, INS_rshrn2, INS_rshrn2, INS_rshrn2, INS_rshrn2, INS_rshrn2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalRoundedScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_urshr, INS_urshr, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, ShiftRightLogicalScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ushr, INS_ushr, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, SignExtendWideningLower, 8, 1, {INS_sxtl, INS_invalid, INS_sxtl, INS_invalid, INS_sxtl, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd, SignExtendWideningUpper, 16, 1, {INS_sxtl2, INS_invalid, INS_sxtl2, INS_invalid, INS_sxtl2, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd, SqrtScalar, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fsqrt, INS_fsqrt}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, Store, -1, 2, {INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1, INS_st1}, HW_Category_MemoryStore, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AdvSimd, Subtract, -1, 2, {INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_sub, INS_fsub, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, SubtractHighNarrowingLower, 8, 2, {INS_subhn, INS_subhn, INS_subhn, INS_subhn, INS_subhn, INS_subhn, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, SubtractHighNarrowingUpper, 16, 3, {INS_subhn2, INS_subhn2, INS_subhn2, INS_subhn2, INS_subhn2, INS_subhn2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, SubtractRoundedHighNarrowingLower, 8, 2, {INS_rsubhn, INS_rsubhn, INS_rsubhn, INS_rsubhn, INS_rsubhn, INS_rsubhn, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, SubtractRoundedHighNarrowingUpper, 16, 3, {INS_rsubhn2, INS_rsubhn2, INS_rsubhn2, INS_rsubhn2, INS_rsubhn2, INS_rsubhn2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, SubtractSaturate, -1, 2, {INS_sqsub, INS_uqsub, INS_sqsub, INS_uqsub, INS_sqsub, INS_uqsub, INS_sqsub, INS_uqsub, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, SubtractSaturateScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqsub, INS_uqsub, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, SubtractScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sub, INS_sub, INS_fsub, INS_fsub}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, SubtractWideningLower, 8, 2, {INS_ssubl, INS_usubl, INS_ssubl, INS_usubl, INS_ssubl, INS_usubl, INS_ssubw, INS_usubw, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromSecondArg|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, SubtractWideningUpper, 16, 2, {INS_ssubl2, INS_usubl2, INS_ssubl2, INS_usubl2, INS_ssubl2, INS_usubl2, INS_ssubw2, INS_usubw2, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromSecondArg|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd, VectorTableLookup, 8, 2, {INS_tbl, INS_tbl, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd, VectorTableLookupExtension, 8, 3, {INS_tbx, INS_tbx, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd, Xor, -1, 2, {INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor, INS_eor}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd, ZeroExtendWideningLower, 8, 1, {INS_uxtl, INS_uxtl, INS_uxtl, INS_uxtl, INS_uxtl, INS_uxtl, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd, ZeroExtendWideningUpper, 16, 1, {INS_uxtl2, INS_uxtl2, INS_uxtl2, INS_uxtl2, INS_uxtl2, INS_uxtl2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// ISA Function name ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size Number of arguments Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // AdvSimd 64-bit only Intrinsics -HARDWARE_INTRINSIC(AdvSimd_Arm64, Abs, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_abs, INS_invalid, INS_invalid, INS_fabs}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsScalar, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_abs, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareGreaterThan, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facgt}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareGreaterThanOrEqual, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facge}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareGreaterThanOrEqualScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facge, INS_facge}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareGreaterThanScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facgt, INS_facgt}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareLessThan, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facgt}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareLessThanOrEqual, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facge}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareLessThanOrEqualScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facge, INS_facge}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareLessThanScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facgt, INS_facgt}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteDifference, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fabd}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteDifferenceScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fabd, INS_fabd}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, Add, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fadd}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, AddAcross, -1, -1, 1, {INS_addv, INS_addv, INS_addv, INS_addv, INS_addv, INS_addv, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, AddPairwise, -1, 16, 2, {INS_addp, INS_addp, INS_addp, INS_addp, INS_addp, INS_addp, INS_addp, INS_addp, INS_faddp, INS_faddp}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, AddPairwiseScalar, -1, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addp, INS_addp, INS_faddp, INS_faddp}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareEqual, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmeq, INS_cmeq, INS_invalid, INS_fcmeq}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareEqualScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmeq, INS_cmeq, INS_fcmeq, INS_fcmeq}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareGreaterThan, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmgt, INS_cmhi, INS_invalid, INS_fcmgt}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareGreaterThanOrEqual, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmge, INS_cmhs, INS_invalid, INS_fcmge}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareGreaterThanOrEqualScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmge, INS_cmhs, INS_fcmge, INS_fcmge}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareGreaterThanScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmgt, INS_cmhi, INS_fcmgt, INS_fcmgt}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareLessThan, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmgt, INS_cmhi, INS_invalid, INS_fcmgt}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareLessThanOrEqual, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmge, INS_cmhs, INS_invalid, INS_fcmge}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareLessThanOrEqualScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmge, INS_cmhs, INS_fcmge, INS_fcmge}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareLessThanScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmgt, INS_cmhi, INS_fcmgt, INS_fcmgt}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareTest, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmtst, INS_cmtst, INS_invalid, INS_cmtst}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareTestScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmtst, INS_cmtst, INS_invalid, INS_cmtst}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, Divide, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fdiv, INS_fdiv}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, FusedMultiplyAdd, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmla}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(AdvSimd_Arm64, FusedMultiplySubtract, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmls}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(AdvSimd_Arm64, Max, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmax}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxAcross, -1, -1, 1, {INS_smaxv, INS_umaxv, INS_smaxv, INS_umaxv, INS_smaxv, INS_umaxv, INS_invalid, INS_invalid, INS_fmaxv, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxNumber, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxnm}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxNumberAcross, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxnmv, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxNumberPairwise, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxnmp, INS_fmaxnmp}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxNumberPairwiseScalar, -1, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxnmp, INS_fmaxnmp}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxPairwise, -1, 16, 2, {INS_smaxp, INS_umaxp, INS_smaxp, INS_umaxp, INS_smaxp, INS_umaxp, INS_invalid, INS_invalid, INS_fmaxp, INS_fmaxp}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxPairwiseScalar, -1, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxp, INS_fmaxp}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmax, INS_fmax}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, Min, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmin}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MinAcross, -1, -1, 1, {INS_sminv, INS_uminv, INS_sminv, INS_uminv, INS_sminv, INS_uminv, INS_invalid, INS_invalid, INS_fminv, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MinNumber, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminnm}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MinNumberAcross, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminnmv, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MinNumberPairwise, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminnmp, INS_fminnmp}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MinNumberPairwiseScalar, -1, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminnmp, INS_fminnmp}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MinPairwise, -1, 16, 2, {INS_sminp, INS_uminp, INS_sminp, INS_uminp, INS_sminp, INS_uminp, INS_invalid, INS_invalid, INS_fminp, INS_fminp}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MinPairwiseScalar, -1, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminp, INS_fminp}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MinScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmin, INS_fmin}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, Multiply, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmul}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MultiplyExtended, -1, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmulx, INS_fmulx}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, MultiplyExtendedScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmulx, INS_fmulx}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, Negate, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_neg, INS_invalid, INS_invalid, INS_fneg}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, NegateScalar, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_neg, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalEstimate, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecpe}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalEstimateScalar, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecpe, INS_frecpe}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalExponentScalar, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecpx, INS_frecpx}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalSquareRootEstimate, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrte}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalSquareRootEstimateScalar, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrte, INS_frsqrte}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalSquareRootStep, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrts}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalSquareRootStepScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrts, INS_frsqrts}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalStep, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecps}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalStepScalar, -1, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecps, INS_frecps}, HW_Category_SIMDScalar, HW_Flag_NoContainment|HW_Flag_Commutative) -HARDWARE_INTRINSIC(AdvSimd_Arm64, ReverseElementBits, -1, -1, 1, {INS_rbit, INS_rbit, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, Sqrt, -1, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fsqrt, INS_fsqrt}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, Subtract, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fsub}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AdvSimd_Arm64, TransposeEven, -1, -1, 2, {INS_trn1, INS_trn1, INS_trn1, INS_trn1, INS_trn1, INS_trn1, INS_trn1, INS_trn1, INS_trn1, INS_trn1}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, TransposeOdd, -1, -1, 2, {INS_trn2, INS_trn2, INS_trn2, INS_trn2, INS_trn2, INS_trn2, INS_trn2, INS_trn2, INS_trn2, INS_trn2}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, UnzipEven, -1, -1, 2, {INS_uzp1, INS_uzp1, INS_uzp1, INS_uzp1, INS_uzp1, INS_uzp1, INS_uzp1, INS_uzp1, INS_uzp1, INS_uzp1}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, UnzipOdd, -1, -1, 2, {INS_uzp2, INS_uzp2, INS_uzp2, INS_uzp2, INS_uzp2, INS_uzp2, INS_uzp2, INS_uzp2, INS_uzp2, INS_uzp2}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, ZipHigh, -1, -1, 2, {INS_zip2, INS_zip2, INS_zip2, INS_zip2, INS_zip2, INS_zip2, INS_zip2, INS_zip2, INS_zip2, INS_zip2}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AdvSimd_Arm64, ZipLow, -1, -1, 2, {INS_zip1, INS_zip1, INS_zip1, INS_zip1, INS_zip1, INS_zip1, INS_zip1, INS_zip1, INS_zip1, INS_zip1}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize) +HARDWARE_INTRINSIC(AdvSimd_Arm64, Abs, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_abs, INS_invalid, INS_invalid, INS_fabs}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsScalar, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_abs, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facgt}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facge}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareGreaterThanOrEqualScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facge, INS_facge}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareGreaterThanScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facgt, INS_facgt}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareLessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facgt}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facge}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareLessThanOrEqualScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facge, INS_facge}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteCompareLessThanScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_facgt, INS_facgt}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteDifference, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fabd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AbsoluteDifferenceScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fabd, INS_fabd}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, Add, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fadd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AddAcross, -1, 1, {INS_addv, INS_addv, INS_addv, INS_addv, INS_addv, INS_addv, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AddPairwise, 16, 2, {INS_addp, INS_addp, INS_addp, INS_addp, INS_addp, INS_addp, INS_addp, INS_addp, INS_faddp, INS_faddp}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AddPairwiseScalar, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addp, INS_addp, INS_faddp, INS_faddp}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd_Arm64, AddSaturateScalar, 8, 2, {INS_sqadd, INS_uqadd, INS_sqadd, INS_uqadd, INS_sqadd, INS_uqadd, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmeq, INS_cmeq, INS_invalid, INS_fcmeq}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareEqualScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmeq, INS_cmeq, INS_fcmeq, INS_fcmeq}, HW_Category_SIMDScalar, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmgt, INS_cmhi, INS_invalid, INS_fcmgt}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmge, INS_cmhs, INS_invalid, INS_fcmge}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareGreaterThanOrEqualScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmge, INS_cmhs, INS_fcmge, INS_fcmge}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareGreaterThanScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmgt, INS_cmhi, INS_fcmgt, INS_fcmgt}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareLessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmgt, INS_cmhi, INS_invalid, INS_fcmgt}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmge, INS_cmhs, INS_invalid, INS_fcmge}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareLessThanOrEqualScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmge, INS_cmhs, INS_fcmge, INS_fcmge}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareLessThanScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmgt, INS_cmhi, INS_fcmgt, INS_fcmgt}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareTest, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmtst, INS_cmtst, INS_invalid, INS_cmtst}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, CompareTestScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmtst, INS_cmtst, INS_invalid, INS_cmtst}, HW_Category_SIMDScalar, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, Divide, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fdiv, INS_fdiv}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, DuplicateSelectedScalarToVector128, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_dup, INS_dup, INS_invalid, INS_dup}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, DuplicateToVector64, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov, INS_mov, INS_invalid, INS_fmov}, HW_Category_SimpleSIMD, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, DuplicateToVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_dup, INS_dup, INS_invalid, INS_dup}, HW_Category_SimpleSIMD, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, FusedMultiplyAdd, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmla}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd_Arm64, FusedMultiplySubtract, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmls}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd_Arm64, Max, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmax}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxAcross, -1, 1, {INS_smaxv, INS_umaxv, INS_smaxv, INS_umaxv, INS_smaxv, INS_umaxv, INS_invalid, INS_invalid, INS_fmaxv, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxNumber, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxnm}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxNumberAcross, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxnmv, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxNumberPairwise, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxnmp, INS_fmaxnmp}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxNumberPairwiseScalar, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxnmp, INS_fmaxnmp}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxPairwise, 16, 2, {INS_smaxp, INS_umaxp, INS_smaxp, INS_umaxp, INS_smaxp, INS_umaxp, INS_invalid, INS_invalid, INS_fmaxp, INS_fmaxp}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxPairwiseScalar, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmaxp, INS_fmaxp}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MaxScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmax, INS_fmax}, HW_Category_SIMDScalar, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, Min, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmin}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MinAcross, -1, 1, {INS_sminv, INS_uminv, INS_sminv, INS_uminv, INS_sminv, INS_uminv, INS_invalid, INS_invalid, INS_fminv, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MinNumber, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminnm}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MinNumberAcross, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminnmv, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MinNumberPairwise, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminnmp, INS_fminnmp}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MinNumberPairwiseScalar, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminnmp, INS_fminnmp}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MinPairwise, 16, 2, {INS_sminp, INS_uminp, INS_sminp, INS_uminp, INS_sminp, INS_uminp, INS_invalid, INS_invalid, INS_fminp, INS_fminp}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MinPairwiseScalar, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fminp, INS_fminp}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MinScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmin, INS_fmin}, HW_Category_SIMDScalar, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, Multiply, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmul}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MultiplyExtended, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmulx, INS_fmulx}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, MultiplyExtendedScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fmulx, INS_fmulx}, HW_Category_SIMDScalar, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, Negate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_neg, INS_invalid, INS_invalid, INS_fneg}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, NegateScalar, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_neg, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalEstimate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecpe}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalEstimateScalar, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecpe, INS_frecpe}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalExponentScalar, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecpx, INS_frecpx}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalSquareRootEstimate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrte}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalSquareRootEstimateScalar, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrte, INS_frsqrte}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalSquareRootStep, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrts}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalSquareRootStepScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frsqrts, INS_frsqrts}, HW_Category_SIMDScalar, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalStep, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecps}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReciprocalStepScalar, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_frecps, INS_frecps}, HW_Category_SIMDScalar, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ReverseElementBits, -1, 1, {INS_rbit, INS_rbit, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ShiftArithmeticRoundedSaturateScalar, 8, 2, {INS_sqrshl, INS_invalid, INS_sqrshl, INS_invalid, INS_sqrshl, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ShiftArithmeticSaturateScalar, 8, 2, {INS_sqshl, INS_invalid, INS_sqshl, INS_invalid, INS_sqshl, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ShiftLeftLogicalSaturateScalar, 8, 2, {INS_sqshl, INS_uqshl, INS_sqshl, INS_uqshl, INS_sqshl, INS_uqshl, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ShiftLeftLogicalSaturateUnsignedScalar, 8, 2, {INS_sqshlu, INS_invalid, INS_sqshlu, INS_invalid, INS_sqshlu, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ShiftLogicalRoundedSaturateScalar, 8, 2, {INS_uqrshl, INS_uqrshl, INS_uqrshl, INS_uqrshl, INS_uqrshl, INS_uqrshl, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ShiftLogicalSaturateScalar, 8, 2, {INS_uqshl, INS_uqshl, INS_uqshl, INS_uqshl, INS_uqshl, INS_uqshl, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ShiftRightArithmeticNarrowingSaturateScalar, 8, 2, {INS_sqshrn, INS_invalid, INS_sqshrn, INS_invalid, INS_sqshrn, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ShiftRightArithmeticNarrowingSaturateUnsignedScalar, 8, 2, {INS_invalid, INS_sqshrun, INS_invalid, INS_sqshrun, INS_invalid, INS_sqshrun, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ShiftRightArithmeticRoundedNarrowingSaturateScalar, 8, 2, {INS_sqrshrn, INS_invalid, INS_sqrshrn, INS_invalid, INS_sqrshrn, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar, 8, 2, {INS_invalid, INS_sqrshrun, INS_invalid, INS_sqrshrun, INS_invalid, INS_sqrshrun, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ShiftRightLogicalNarrowingSaturateScalar, 8, 2, {INS_uqshrn, INS_uqshrn, INS_uqshrn, INS_uqshrn, INS_uqshrn, INS_uqshrn, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ShiftRightLogicalRoundedNarrowingSaturateScalar, 8, 2, {INS_uqrshrn, INS_uqrshrn, INS_uqrshrn, INS_uqrshrn, INS_uqrshrn, INS_uqrshrn, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(AdvSimd_Arm64, Sqrt, -1, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fsqrt, INS_fsqrt}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, Subtract, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_fsub}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, SubtractSaturateScalar, 8, 2, {INS_sqsub, INS_uqsub, INS_sqsub, INS_uqsub, INS_sqsub, INS_uqsub, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, TransposeEven, -1, 2, {INS_trn1, INS_trn1, INS_trn1, INS_trn1, INS_trn1, INS_trn1, INS_trn1, INS_trn1, INS_trn1, INS_trn1}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, TransposeOdd, -1, 2, {INS_trn2, INS_trn2, INS_trn2, INS_trn2, INS_trn2, INS_trn2, INS_trn2, INS_trn2, INS_trn2, INS_trn2}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, UnzipEven, -1, 2, {INS_uzp1, INS_uzp1, INS_uzp1, INS_uzp1, INS_uzp1, INS_uzp1, INS_uzp1, INS_uzp1, INS_uzp1, INS_uzp1}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, UnzipOdd, -1, 2, {INS_uzp2, INS_uzp2, INS_uzp2, INS_uzp2, INS_uzp2, INS_uzp2, INS_uzp2, INS_uzp2, INS_uzp2, INS_uzp2}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, VectorTableLookup, 16, 2, {INS_tbl, INS_tbl, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, VectorTableLookupExtension, 16, 3, {INS_tbx, INS_tbx, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ZipHigh, -1, 2, {INS_zip2, INS_zip2, INS_zip2, INS_zip2, INS_zip2, INS_zip2, INS_zip2, INS_zip2, INS_zip2, INS_zip2}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AdvSimd_Arm64, ZipLow, -1, 2, {INS_zip1, INS_zip1, INS_zip1, INS_zip1, INS_zip1, INS_zip1, INS_zip1, INS_zip1, INS_zip1, INS_zip1}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// ISA Function name ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size Number of arguments Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // AES Intrinsics -HARDWARE_INTRINSIC(Aes, Decrypt, -1, 16, 2, {INS_invalid, INS_aesd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(Aes, Encrypt, -1, 16, 2, {INS_invalid, INS_aese, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(Aes, InverseMixColumns, -1, 16, 1, {INS_invalid, INS_aesimc, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(Aes, MixColumns, -1, 16, 1, {INS_invalid, INS_aesmc, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(Aes, Decrypt, 16, 2, {INS_invalid, INS_aesd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(Aes, Encrypt, 16, 2, {INS_invalid, INS_aese, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(Aes, InverseMixColumns, 16, 1, {INS_invalid, INS_aesimc, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(Aes, MixColumns, 16, 1, {INS_invalid, INS_aesmc, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(Aes, PolynomialMultiplyWideningLower, 8, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmull, INS_pmull, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Aes, PolynomialMultiplyWideningUpper, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmull2, INS_pmull2, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// ISA Function name ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size Number of arguments Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // Base Intrinsics -HARDWARE_INTRINSIC(ArmBase, LeadingZeroCount, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_clz, INS_clz, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(ArmBase, ReverseElementBits, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rbit, INS_rbit, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(ArmBase, LeadingZeroCount, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_clz, INS_clz, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(ArmBase, ReverseElementBits, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rbit, INS_rbit, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFlag) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// ISA Function name ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size Number of arguments Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // Base 64-bit only Intrinsics -HARDWARE_INTRINSIC(ArmBase_Arm64, LeadingSignCount, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cls, INS_invalid, INS_cls, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(ArmBase_Arm64, LeadingZeroCount, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_clz, INS_clz, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(ArmBase_Arm64, ReverseElementBits, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rbit, INS_rbit, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(ArmBase_Arm64, LeadingSignCount, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cls, INS_invalid, INS_cls, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(ArmBase_Arm64, LeadingZeroCount, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_clz, INS_clz, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(ArmBase_Arm64, ReverseElementBits, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rbit, INS_rbit, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFlag) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// ISA Function name ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size Number of arguments Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // CRC32 Intrinsics -HARDWARE_INTRINSIC(Crc32, ComputeCrc32, -1, 0, 2, {INS_invalid, INS_crc32b, INS_invalid, INS_crc32h, INS_invalid, INS_crc32w, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(Crc32, ComputeCrc32C, -1, 0, 2, {INS_invalid, INS_crc32cb, INS_invalid, INS_crc32ch, INS_invalid, INS_crc32cw, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(Crc32, ComputeCrc32, 0, 2, {INS_invalid, INS_crc32b, INS_invalid, INS_crc32h, INS_invalid, INS_crc32w, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(Crc32, ComputeCrc32C, 0, 2, {INS_invalid, INS_crc32cb, INS_invalid, INS_crc32ch, INS_invalid, INS_crc32cw, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// ISA Function name ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size Number of arguments Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // CRC32 64-bit only Intrinsics -HARDWARE_INTRINSIC(Crc32_Arm64, ComputeCrc32, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_crc32x, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(Crc32_Arm64, ComputeCrc32C, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_crc32cx, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoContainment|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(Crc32_Arm64, ComputeCrc32, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_crc32x, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(Crc32_Arm64, ComputeCrc32C, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_crc32cx, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// ISA Function name ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size Number of arguments Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // SHA1 Intrinsics -HARDWARE_INTRINSIC(Sha1, FixedRotate, -1, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha1h, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(Sha1, HashUpdateChoose, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha1c, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(Sha1, HashUpdateMajority, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha1m, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(Sha1, HashUpdateParity, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha1p, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(Sha1, ScheduleUpdate0, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha1su0, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(Sha1, ScheduleUpdate1, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha1su1, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(Sha1, FixedRotate, 8, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha1h, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(Sha1, HashUpdateChoose, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha1c, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(Sha1, HashUpdateMajority, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha1m, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(Sha1, HashUpdateParity, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha1p, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(Sha1, ScheduleUpdate0, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha1su0, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(Sha1, ScheduleUpdate1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha1su1, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// ISA Function name ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size Number of arguments Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // SHA256 Intrinsics -HARDWARE_INTRINSIC(Sha256, HashUpdate1, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha256h, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(Sha256, HashUpdate2, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha256h2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(Sha256, ScheduleUpdate0, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha256su0, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_HasRMWSemantics) -HARDWARE_INTRINSIC(Sha256, ScheduleUpdate1, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha256su1, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(Sha256, HashUpdate1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha256h, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(Sha256, HashUpdate2, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha256h2, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(Sha256, ScheduleUpdate0, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha256su0, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) +HARDWARE_INTRINSIC(Sha256, ScheduleUpdate1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sha256su1, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_HasRMWSemantics) #endif // FEATURE_HW_INTRINSIC diff --git a/src/coreclr/src/jit/hwintrinsiclistxarch.h b/src/coreclr/src/jit/hwintrinsiclistxarch.h index 70fbdc79e13b65..c6017fb12c44ca 100644 --- a/src/coreclr/src/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/src/jit/hwintrinsiclistxarch.h @@ -23,626 +23,670 @@ 9) Each intrinsic has one or more flags with type of `enum HWIntrinsicFlag` */ // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // Vector128 Intrinsics -HARDWARE_INTRINSIC(Vector128_As, "As", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsByte, "AsByte", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsDouble, "AsDouble", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsInt16, "AsInt16", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsInt32, "AsInt32", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsInt64, "AsInt64", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsSByte, "AsSByte", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsSingle, "AsSingle", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsUInt16, "AsUInt16", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsUInt32, "AsUInt32", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsUInt64, "AsUInt64", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsVector, "AsVector", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsVector2, "AsVector2", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsVector3, "AsVector3", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsVector4, "AsVector4", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_AsVector128, "AsVector128", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_Count, "get_Count", Vector128, -1, 16, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_CreateScalarUnsafe, "CreateScalarUnsafe", Vector128, -1, 16, 1, {INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_movss, INS_movsdsse2}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_GetElement, "GetElement", Vector128, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector128_WithElement, "WithElement", Vector128, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector128_ToScalar, "ToScalar", Vector128, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_movsdsse2}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_ToVector256, "ToVector256", Vector128, -1, 16, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_ToVector256Unsafe, "ToVector256Unsafe", Vector128, -1, 16, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector128_Zero, "get_Zero", Vector128, -1, 16, 0, {INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) - -// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +HARDWARE_INTRINSIC(Vector128, As, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsByte, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsDouble, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsInt16, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsInt32, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsInt64, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsSByte, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsSingle, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsUInt16, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsUInt32, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsUInt64, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsVector, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsVector2, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsVector3, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsVector4, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, AsVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, Create, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, CreateScalarUnsafe, 16, 1, {INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_movss, INS_movsdsse2}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) +// The instruction generated for float/double depends on which ISAs are supported +HARDWARE_INTRINSIC(Vector128, get_AllBitsSet, 16, 0, {INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_cmpps, INS_cmppd}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, get_Count, 16, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, get_Zero, 16, 0, {INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, GetElement, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, op_Equality, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, op_Inequality, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector128, ToScalar, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_movsdsse2}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, ToVector256, 16, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, ToVector256Unsafe, 16, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, WithElement, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) + +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // Vector256 Intrinsics -HARDWARE_INTRINSIC(Vector256_As, "As", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_AsByte, "AsByte", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_AsDouble, "AsDouble", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_AsInt16, "AsInt16", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_AsInt32, "AsInt32", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_AsInt64, "AsInt64", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_AsSByte, "AsSByte", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_AsSingle, "AsSingle", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_AsUInt16, "AsUInt16", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_AsUInt32, "AsUInt32", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_AsUInt64, "AsUInt64", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_AsVector, "AsVector", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_AsVector256, "AsVector256", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_Count, "get_Count", Vector256, -1, 32, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_CreateScalarUnsafe, "CreateScalarUnsafe", Vector256, -1, 32, 1, {INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_movss, INS_movsdsse2}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_GetElement, "GetElement", Vector256, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector256_WithElement, "WithElement", Vector256, -1, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(Vector256_GetLower, "GetLower", Vector256, -1, 32, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_ToScalar, "ToScalar", Vector256, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_movsdsse2}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(Vector256_Zero, "get_Zero", Vector256, -1, 32, 0, {INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) - -// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +HARDWARE_INTRINSIC(Vector256, As, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, AsByte, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, AsDouble, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, AsInt16, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, AsInt32, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, AsInt64, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, AsSByte, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, AsSingle, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, AsUInt16, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, AsUInt32, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, AsUInt64, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, AsVector, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, AsVector256, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +// The instruction generated for float/double depends on which ISAs are supported +HARDWARE_INTRINSIC(Vector256, get_AllBitsSet, 32, 0, {INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqd, INS_cmpps, INS_cmppd}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, get_Count, 32, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, get_Zero, 32, 0, {INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps, INS_xorps}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, Create, 32, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, CreateScalarUnsafe, 32, 1, {INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_mov_i2xmm, INS_movss, INS_movsdsse2}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, GetElement, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector256, GetLower, 32, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, op_Equality, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, op_Inequality, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen) +HARDWARE_INTRINSIC(Vector256, ToScalar, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_movsdsse2}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector256, WithElement, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) + +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** +// X86Base Intrinsics +HARDWARE_INTRINSIC(X86Base, BitScanForward, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsf, INS_bsf, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(X86Base, BitScanReverse, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsr, INS_bsr, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) + +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** +// X86Base 64-bit-only Intrinsics +HARDWARE_INTRINSIC(X86Base_X64, BitScanForward, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsf, INS_bsf, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(X86Base_X64, BitScanReverse, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsr, INS_bsr, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) + +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // SSE Intrinsics -HARDWARE_INTRINSIC(SSE_Add, "Add", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE_AddScalar, "AddScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_And, "And", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_andps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE_AndNot, "AndNot", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_andnps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareEqual, "CompareEqual", SSE, 0, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE_CompareScalarOrderedEqual, "CompareScalarOrderedEqual", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_CompareScalarEqual, "CompareScalarEqual", SSE, 0, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareScalarUnorderedEqual, "CompareScalarUnorderedEqual", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_CompareGreaterThan, "CompareGreaterThan", SSE, 6, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareScalarOrderedGreaterThan, "CompareScalarOrderedGreaterThan", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_CompareScalarGreaterThan, "CompareScalarGreaterThan", SSE, 6, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareScalarUnorderedGreaterThan, "CompareScalarUnorderedGreaterThan", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_CompareGreaterThanOrEqual, "CompareGreaterThanOrEqual", SSE, 5, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareScalarOrderedGreaterThanOrEqual, "CompareScalarOrderedGreaterThanOrEqual", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_CompareScalarGreaterThanOrEqual, "CompareScalarGreaterThanOrEqual", SSE, 5, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareScalarUnorderedGreaterThanOrEqual, "CompareScalarUnorderedGreaterThanOrEqual", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_CompareLessThan, "CompareLessThan", SSE, 1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareScalarOrderedLessThan, "CompareScalarOrderedLessThan", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_CompareScalarLessThan, "CompareScalarLessThan", SSE, 1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareScalarUnorderedLessThan, "CompareScalarUnorderedLessThan", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_CompareLessThanOrEqual, "CompareLessThanOrEqual", SSE, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareScalarOrderedLessThanOrEqual, "CompareScalarOrderedLessThanOrEqual", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_CompareScalarLessThanOrEqual, "CompareScalarLessThanOrEqual", SSE, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareScalarUnorderedLessThanOrEqual, "CompareScalarUnorderedLessThanOrEqual", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_CompareNotEqual, "CompareNotEqual", SSE, 4, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE_CompareScalarOrderedNotEqual, "CompareScalarOrderedNotEqual", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_CompareScalarNotEqual, "CompareScalarNotEqual", SSE, 4, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareScalarUnorderedNotEqual, "CompareScalarUnorderedNotEqual", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_CompareNotGreaterThan, "CompareNotGreaterThan", SSE, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareScalarNotGreaterThan, "CompareScalarNotGreaterThan", SSE, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareNotGreaterThanOrEqual, "CompareNotGreaterThanOrEqual", SSE, 1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareScalarNotGreaterThanOrEqual, "CompareScalarNotGreaterThanOrEqual", SSE, 1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareNotLessThan, "CompareNotLessThan", SSE, 5, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareScalarNotLessThan, "CompareScalarNotLessThan", SSE, 5, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareNotLessThanOrEqual, "CompareNotLessThanOrEqual", SSE, 6, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareScalarNotLessThanOrEqual, "CompareScalarNotLessThanOrEqual", SSE, 6, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareOrdered, "CompareOrdered", SSE, 7, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareScalarOrdered, "CompareScalarOrdered", SSE, 7, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_CompareUnordered, "CompareUnordered", SSE, 3, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_CompareScalarUnordered, "CompareScalarUnordered", SSE, 3, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_ConvertToInt32, "ConvertToInt32", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_ConvertScalarToVector128Single, "ConvertScalarToVector128Single", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsi2ss, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromSecondArg|HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_ConvertToInt32WithTruncation, "ConvertToInt32WithTruncation", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_Divide, "Divide", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_DivideScalar, "DivideScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_LoadAlignedVector128, "LoadAlignedVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movaps, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_LoadHigh, "LoadHigh", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhps, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_LoadLow, "LoadLow", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlps, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_LoadScalarVector128, "LoadScalarVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_LoadVector128, "LoadVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movups, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_Max, "Max", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE_MaxScalar, "MaxScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_Min, "Min", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE_MinScalar, "MinScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_MoveHighToLow, "MoveHighToLow", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhlps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(SSE_MoveLowToHigh, "MoveLowToHigh", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlhps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(SSE_MoveMask, "MoveMask", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movmskps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(SSE_MoveScalar, "MoveScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(SSE_Multiply, "Multiply", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE_MultiplyScalar, "MultiplyScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_Or, "Or", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_orps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE_Prefetch0, "Prefetch0", SSE, -1, 0, 1, {INS_invalid, INS_prefetcht0, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_Prefetch1, "Prefetch1", SSE, -1, 0, 1, {INS_invalid, INS_prefetcht1, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_Prefetch2, "Prefetch2", SSE, -1, 0, 1, {INS_invalid, INS_prefetcht2, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_PrefetchNonTemporal, "PrefetchNonTemporal", SSE, -1, 0, 1, {INS_invalid, INS_prefetchnta, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_Reciprocal, "Reciprocal", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rcpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_ReciprocalScalar, "ReciprocalScalar", SSE, -1, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rcpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_ReciprocalSqrt, "ReciprocalSqrt", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rsqrtps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_ReciprocalSqrtScalar, "ReciprocalSqrtScalar", SSE, -1, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rsqrtss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_Shuffle, "Shuffle", SSE, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_shufps, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE_Sqrt, "Sqrt", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_SqrtScalar, "SqrtScalar", SSE, -1, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_Store, "Store", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movups, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE_StoreAligned, "StoreAligned", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movaps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movntps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE_StoreFence, "StoreFence", SSE, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_StoreHigh, "StoreHigh", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE_StoreLow, "StoreLow", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE_StoreScalar, "StoreScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE_Subtract, "Subtract", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_SubtractScalar, "SubtractScalar", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_UnpackHigh, "UnpackHigh", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_unpckhps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_UnpackLow, "UnpackLow", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_unpcklps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE_Xor, "Xor", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_xorps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) - -// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +HARDWARE_INTRINSIC(SSE, Add, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE, AddScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, And, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_andps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE, AndNot, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_andnps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, CompareEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE, CompareScalarOrderedEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, CompareScalarEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, CompareScalarUnorderedEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, CompareGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, CompareScalarOrderedGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, CompareScalarGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, CompareScalarUnorderedGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, CompareGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, CompareScalarOrderedGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, CompareScalarGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, CompareScalarUnorderedGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, CompareLessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, CompareScalarOrderedLessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, CompareScalarLessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, CompareScalarUnorderedLessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, CompareLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, CompareScalarOrderedLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, CompareScalarLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, CompareScalarUnorderedLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, CompareNotEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE, CompareScalarOrderedNotEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, CompareScalarNotEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, CompareScalarUnorderedNotEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, CompareNotGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, CompareScalarNotGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, CompareNotGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, CompareScalarNotGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, CompareNotLessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, CompareScalarNotLessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, CompareNotLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, CompareScalarNotLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, CompareOrdered, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, CompareScalarOrdered, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, CompareUnordered, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, CompareScalarUnordered, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, ConvertToInt32, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, ConvertScalarToVector128Single, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsi2ss, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromSecondArg|HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, ConvertToInt32WithTruncation, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, Divide, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, DivideScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, LoadAlignedVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movaps, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, LoadHigh, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhps, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, LoadLow, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlps, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, LoadScalarVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, LoadVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movups, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, Max, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE, MaxScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, Min, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE, MinScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, MoveHighToLow, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhlps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE, MoveLowToHigh, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlhps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE, MoveMask, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movmskps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(SSE, MoveScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE, Multiply, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE, MultiplyScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, Or, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_orps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE, Prefetch0, 0, 1, {INS_invalid, INS_prefetcht0, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, Prefetch1, 0, 1, {INS_invalid, INS_prefetcht1, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, Prefetch2, 0, 1, {INS_invalid, INS_prefetcht2, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, PrefetchNonTemporal, 0, 1, {INS_invalid, INS_prefetchnta, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, Reciprocal, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rcpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, ReciprocalScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rcpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, ReciprocalSqrt, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rsqrtps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, ReciprocalSqrtScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rsqrtss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, Shuffle, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_shufps, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE, Sqrt, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, SqrtScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, Store, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movups, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE, StoreAligned, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movaps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE, StoreAlignedNonTemporal, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movntps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE, StoreFence, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, StoreHigh, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE, StoreLow, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlps, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE, StoreScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE, Subtract, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, SubtractScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE, UnpackHigh, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_unpckhps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, UnpackLow, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_unpcklps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE, Xor, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_xorps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) + +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // SSE 64-bit-only Intrinsics -HARDWARE_INTRINSIC(SSE_X64_ConvertToInt64, "ConvertToInt64", SSE_X64, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(SSE_X64_ConvertToInt64WithTruncation, "ConvertToInt64WithTruncation", SSE_X64, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(SSE_X64_ConvertScalarToVector128Single, "ConvertScalarToVector128Single", SSE_X64, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsi2ss, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromSecondArg|HW_Flag_CopyUpperBits|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(SSE_X64, ConvertToInt64, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(SSE_X64, ConvertToInt64WithTruncation, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttss2si, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(SSE_X64, ConvertScalarToVector128Single, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsi2ss, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromSecondArg|HW_Flag_CopyUpperBits|HW_Flag_SpecialCodeGen) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // SSE2 Intrinsics -HARDWARE_INTRINSIC(SSE2_Add, "Add", SSE2, -1, 16, 2, {INS_paddb, INS_paddb, INS_paddw, INS_paddw, INS_paddd, INS_paddd, INS_paddq, INS_paddq, INS_invalid, INS_addpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_AddSaturate, "AddSaturate", SSE2, -1, 16, 2, {INS_paddsb, INS_paddusb, INS_paddsw, INS_paddusw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_AddScalar, "AddScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_And, "And", SSE2, -1, 16, 2, {INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_invalid, INS_andpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_AndNot, "AndNot", SSE2, -1, 16, 2, {INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_invalid, INS_andnpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_Average, "Average", SSE2, -1, 16, 2, {INS_invalid, INS_pavgb, INS_invalid, INS_pavgw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_CompareEqual, "CompareEqual", SSE2, 0, 16, 2, {INS_pcmpeqb, INS_pcmpeqb, INS_pcmpeqw, INS_pcmpeqw, INS_pcmpeqd, INS_pcmpeqd, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_CompareScalarOrderedEqual, "CompareScalarOrderedEqual", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_CompareScalarEqual, "CompareScalarEqual", SSE2, 0, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareScalarUnorderedEqual, "CompareScalarUnorderedEqual", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_CompareGreaterThan, "CompareGreaterThan", SSE2, 6, 16, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_CompareScalarOrderedGreaterThan, "CompareScalarOrderedGreaterThan", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_CompareScalarGreaterThan, "CompareScalarGreaterThan", SSE2, 6, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareScalarUnorderedGreaterThan, "CompareScalarUnorderedGreaterThan", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_CompareGreaterThanOrEqual, "CompareGreaterThanOrEqual", SSE2, 5, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_CompareScalarOrderedGreaterThanOrEqual, "CompareScalarOrderedGreaterThanOrEqual", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_CompareScalarGreaterThanOrEqual, "CompareScalarGreaterThanOrEqual", SSE2, 5, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareScalarUnorderedGreaterThanOrEqual, "CompareScalarUnorderedGreaterThanOrEqual", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_CompareLessThan, "CompareLessThan", SSE2, 1, 16, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_Special, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_CompareScalarOrderedLessThan, "CompareScalarOrderedLessThan", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_CompareScalarLessThan, "CompareScalarLessThan", SSE2, 1, 16, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareScalarUnorderedLessThan, "CompareScalarUnorderedLessThan", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_CompareLessThanOrEqual, "CompareLessThanOrEqual", SSE2, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_CompareScalarOrderedLessThanOrEqual, "CompareScalarOrderedLessThanOrEqual", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_CompareScalarLessThanOrEqual, "CompareScalarLessThanOrEqual", SSE2, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareScalarUnorderedLessThanOrEqual, "CompareScalarUnorderedLessThanOrEqual", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_CompareNotEqual, "CompareNotEqual", SSE2, 4, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_CompareScalarOrderedNotEqual, "CompareScalarOrderedNotEqual", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_MultiIns|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_CompareScalarNotEqual, "CompareScalarNotEqual", SSE2, 4, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareScalarUnorderedNotEqual, "CompareScalarUnorderedNotEqual", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_MultiIns|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_CompareNotGreaterThan, "CompareNotGreaterThan", SSE2, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_CompareScalarNotGreaterThan, "CompareScalarNotGreaterThan", SSE2, 2, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareNotGreaterThanOrEqual, "CompareNotGreaterThanOrEqual", SSE2, 1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_CompareScalarNotGreaterThanOrEqual, "CompareScalarNotGreaterThanOrEqual", SSE2, 1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareNotLessThan, "CompareNotLessThan", SSE2, 5, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_CompareScalarNotLessThan, "CompareScalarNotLessThan", SSE2, 5, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareNotLessThanOrEqual, "CompareNotLessThanOrEqual", SSE2, 6, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_CompareScalarNotLessThanOrEqual, "CompareScalarNotLessThanOrEqual", SSE2, 6, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareOrdered, "CompareOrdered", SSE2, 7, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_CompareScalarOrdered, "CompareScalarOrdered", SSE2, 7, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_CompareUnordered, "CompareUnordered", SSE2, 3, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_CompareScalarUnordered, "CompareScalarUnordered", SSE2, 3, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_ConvertToInt32, "ConvertToInt32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsd2si}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_ConvertToInt32WithTruncation, "ConvertToInt32WithTruncation", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttsd2si}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_ConvertToUInt32, "ConvertToUInt32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_ConvertToVector128Double, "ConvertToVector128Double", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtdq2pd, INS_invalid, INS_invalid, INS_invalid, INS_cvtps2pd, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128Double, "ConvertScalarToVector128Double", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsi2sd, INS_invalid, INS_invalid, INS_invalid, INS_cvtss2sd, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE2_ConvertToVector128Int32, "ConvertToVector128Int32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtps2dq, INS_cvtpd2dq}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128Int32, "ConvertScalarToVector128Int32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_ConvertToVector128Int32WithTruncation, "ConvertToVector128Int32WithTruncation", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttps2dq, INS_cvttpd2dq}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_ConvertToVector128Single, "ConvertToVector128Single", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtdq2ps, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtpd2ps}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128Single, "ConvertScalarToVector128Single", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsd2ss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128UInt32, "ConvertScalarToVector128UInt32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_Divide, "Divide", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_DivideScalar, "DivideScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_Extract, "Extract", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_pextrw, INS_pextrw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_Insert, "Insert", SSE2, -1, 16, 3, {INS_invalid, INS_invalid, INS_pinsrw, INS_pinsrw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE2_LoadAlignedVector128, "LoadAlignedVector128", SSE2, -1, 16, 1, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_invalid, INS_movapd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_LoadFence, "LoadFence", SSE2, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_LoadHigh, "LoadHigh", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhpd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_LoadLow, "LoadLow", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlpd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_LoadScalarVector128, "LoadScalarVector128", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movd, INS_movd, INS_movq, INS_movq, INS_invalid, INS_movsdsse2}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_LoadVector128, "LoadVector128", SSE2, -1, 16, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_invalid, INS_movupd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_MaskMove, "MaskMove", SSE2, -1, 16, 3, {INS_maskmovdqu, INS_maskmovdqu, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE2_Max, "Max", SSE2, -1, 16, 2, {INS_invalid, INS_pmaxub, INS_pmaxsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_MemoryFence, "MemoryFence", SSE2, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_MaxScalar, "MaxScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_Min, "Min", SSE2, -1, 16, 2, {INS_invalid, INS_pminub, INS_pminsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_MinScalar, "MinScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_MoveMask, "MoveMask", SSE2, -1, 16, 1, {INS_pmovmskb, INS_pmovmskb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movmskpd}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(SSE2_MoveScalar, "MoveScalar", SSE2, -1, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movq, INS_movq, INS_invalid, INS_movsdsse2}, HW_Category_SIMDScalar, HW_Flag_NoContainment) -HARDWARE_INTRINSIC(SSE2_Multiply, "Multiply", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmuludq, INS_invalid, INS_mulpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_MultiplyHigh, "MultiplyHigh", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_pmulhw, INS_pmulhuw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_MultiplyAddAdjacent, "MultiplyAddAdjacent", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmaddwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_MultiplyLow, "MultiplyLow", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_pmullw, INS_pmullw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_MultiplyScalar, "MultiplyScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_Or, "Or", SSE2, -1, 16, 2, {INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_invalid, INS_orpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE2_PackSignedSaturate, "PackSignedSaturate", SSE2, -1, 16, 2, {INS_packsswb, INS_invalid, INS_packssdw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_PackUnsignedSaturate, "PackUnsignedSaturate", SSE2, -1, 16, 2, {INS_invalid, INS_packuswb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_SumAbsoluteDifferences, "SumAbsoluteDifferences", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_psadbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_ShiftLeftLogical, "ShiftLeftLogical", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_psllw, INS_psllw, INS_pslld, INS_pslld, INS_psllq, INS_psllq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE2_ShiftLeftLogical128BitLane, "ShiftLeftLogical128BitLane", SSE2, -1, 16, 2, {INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE2_ShiftRightArithmetic, "ShiftRightArithmetic", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_psraw, INS_invalid, INS_psrad, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE2_ShiftRightLogical, "ShiftRightLogical", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_psrlw, INS_psrlw, INS_psrld, INS_psrld, INS_psrlq, INS_psrlq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE2_ShiftRightLogical128BitLane, "ShiftRightLogical128BitLane", SSE2, -1, 16, 2, {INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE2_Shuffle, "Shuffle", SSE2, -1, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pshufd, INS_pshufd, INS_invalid, INS_invalid, INS_invalid, INS_shufpd}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE2_ShuffleHigh, "ShuffleHigh", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_pshufhw, INS_pshufhw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE2_ShuffleLow, "ShuffleLow", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_pshuflw, INS_pshuflw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE2_Sqrt, "Sqrt", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_SqrtScalar, "SqrtScalar", SSE2, -1, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_Store, "Store", SSE2, -1, 16, 2, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_invalid, INS_movupd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE2_StoreAligned, "StoreAligned", SSE2, -1, 16, 2, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_invalid, INS_movapd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE2_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", SSE2, -1, 16, 2, {INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_invalid, INS_movntpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE2_StoreHigh, "StoreHigh", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE2_StoreLow, "StoreLow", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE2_StoreNonTemporal, "StoreNonTemporal", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movnti, INS_movnti, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE2_StoreScalar, "StoreScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movd, INS_movd, INS_movq, INS_movq, INS_invalid, INS_movsdsse2}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE2_Subtract, "Subtract", SSE2, -1, 16, 2, {INS_psubb, INS_psubb, INS_psubw, INS_psubw, INS_psubd, INS_psubd, INS_psubq, INS_psubq, INS_invalid, INS_subpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_SubtractSaturate, "SubtractSaturate", SSE2, -1, 16, 2, {INS_psubsb, INS_psubusb, INS_psubsw, INS_psubusw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_SubtractScalar, "SubtractScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE2_UnpackHigh, "UnpackHigh", SSE2, -1, 16, 2, {INS_punpckhbw, INS_punpckhbw, INS_punpckhwd, INS_punpckhwd, INS_punpckhdq, INS_punpckhdq, INS_punpckhqdq, INS_punpckhqdq, INS_invalid, INS_unpckhpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_UnpackLow, "UnpackLow", SSE2, -1, 16, 2, {INS_punpcklbw, INS_punpcklbw, INS_punpcklwd, INS_punpcklwd, INS_punpckldq, INS_punpckldq, INS_punpcklqdq, INS_punpcklqdq, INS_invalid, INS_unpcklpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE2_Xor, "Xor", SSE2, -1, 16, 2, {INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_invalid, INS_xorpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) - -// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +HARDWARE_INTRINSIC(SSE2, Add, 16, 2, {INS_paddb, INS_paddb, INS_paddw, INS_paddw, INS_paddd, INS_paddd, INS_paddq, INS_paddq, INS_invalid, INS_addpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE2, AddSaturate, 16, 2, {INS_paddsb, INS_paddusb, INS_paddsw, INS_paddusw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE2, AddScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, And, 16, 2, {INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_invalid, INS_andpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE2, AndNot, 16, 2, {INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_invalid, INS_andnpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, Average, 16, 2, {INS_invalid, INS_pavgb, INS_invalid, INS_pavgw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE2, CompareEqual, 16, 2, {INS_pcmpeqb, INS_pcmpeqb, INS_pcmpeqw, INS_pcmpeqw, INS_pcmpeqd, INS_pcmpeqd, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE2, CompareScalarOrderedEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, CompareScalarEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, CompareScalarUnorderedEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, CompareGreaterThan, 16, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, CompareScalarOrderedGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, CompareScalarGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, CompareScalarUnorderedGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, CompareGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, CompareScalarOrderedGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, CompareScalarGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, CompareScalarUnorderedGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, CompareLessThan, 16, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, CompareScalarOrderedLessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, CompareScalarLessThan, 16, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, CompareScalarUnorderedLessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, CompareLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, CompareScalarOrderedLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, CompareScalarLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, CompareScalarUnorderedLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, CompareNotEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE2, CompareScalarOrderedNotEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_MultiIns|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, CompareScalarNotEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, CompareScalarUnorderedNotEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_Commutative|HW_Flag_MultiIns|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, CompareNotGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, CompareScalarNotGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, CompareNotGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, CompareScalarNotGreaterThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, CompareNotLessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, CompareScalarNotLessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, CompareNotLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, CompareScalarNotLessThanOrEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, CompareOrdered, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, CompareScalarOrdered, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, CompareUnordered, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, CompareScalarUnordered, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, ConvertToInt32, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsd2si}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, ConvertToInt32WithTruncation, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttsd2si}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, ConvertToUInt32, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, ConvertToVector128Double, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtdq2pd, INS_invalid, INS_invalid, INS_invalid, INS_cvtps2pd, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, ConvertScalarToVector128Double, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsi2sd, INS_invalid, INS_invalid, INS_invalid, INS_cvtss2sd, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2, ConvertToVector128Int32, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtps2dq, INS_cvtpd2dq}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, ConvertScalarToVector128Int32, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, ConvertToVector128Int32WithTruncation, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttps2dq, INS_cvttpd2dq}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, ConvertToVector128Single, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtdq2ps, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtpd2ps}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, ConvertScalarToVector128Single, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsd2ss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, ConvertScalarToVector128UInt32, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, Divide, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, DivideScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, Extract, 16, 2, {INS_invalid, INS_invalid, INS_pextrw, INS_pextrw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, Insert, 16, 3, {INS_invalid, INS_invalid, INS_pinsrw, INS_pinsrw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE2, LoadAlignedVector128, 16, 1, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_invalid, INS_movapd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, LoadFence, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, LoadHigh, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhpd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, LoadLow, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlpd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, LoadScalarVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movd, INS_movd, INS_movq, INS_movq, INS_invalid, INS_movsdsse2}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, LoadVector128, 16, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_invalid, INS_movupd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, MaskMove, 16, 3, {INS_maskmovdqu, INS_maskmovdqu, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2, Max, 16, 2, {INS_invalid, INS_pmaxub, INS_pmaxsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE2, MemoryFence, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, MaxScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, Min, 16, 2, {INS_invalid, INS_pminub, INS_pminsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE2, MinScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, MoveMask, 16, 1, {INS_pmovmskb, INS_pmovmskb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movmskpd}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(SSE2, MoveScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movq, INS_movq, INS_invalid, INS_movsdsse2}, HW_Category_SIMDScalar, HW_Flag_NoContainment) +HARDWARE_INTRINSIC(SSE2, Multiply, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmuludq, INS_invalid, INS_mulpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE2, MultiplyHigh, 16, 2, {INS_invalid, INS_invalid, INS_pmulhw, INS_pmulhuw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE2, MultiplyAddAdjacent, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmaddwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE2, MultiplyLow, 16, 2, {INS_invalid, INS_invalid, INS_pmullw, INS_pmullw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE2, MultiplyScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, Or, 16, 2, {INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_invalid, INS_orpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE2, PackSignedSaturate, 16, 2, {INS_packsswb, INS_invalid, INS_packssdw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, PackUnsignedSaturate, 16, 2, {INS_invalid, INS_packuswb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, SumAbsoluteDifferences, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_psadbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, ShiftLeftLogical, 16, 2, {INS_invalid, INS_invalid, INS_psllw, INS_psllw, INS_pslld, INS_pslld, INS_psllq, INS_psllq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE2, ShiftLeftLogical128BitLane, 16, 2, {INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE2, ShiftRightArithmetic, 16, 2, {INS_invalid, INS_invalid, INS_psraw, INS_invalid, INS_psrad, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE2, ShiftRightLogical, 16, 2, {INS_invalid, INS_invalid, INS_psrlw, INS_psrlw, INS_psrld, INS_psrld, INS_psrlq, INS_psrlq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE2, ShiftRightLogical128BitLane, 16, 2, {INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE2, Shuffle, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pshufd, INS_pshufd, INS_invalid, INS_invalid, INS_invalid, INS_shufpd}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE2, ShuffleHigh, 16, 2, {INS_invalid, INS_invalid, INS_pshufhw, INS_pshufhw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE2, ShuffleLow, 16, 2, {INS_invalid, INS_invalid, INS_pshuflw, INS_pshuflw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE2, Sqrt, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, SqrtScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, Store, 16, 2, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_invalid, INS_movupd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2, StoreAligned, 16, 2, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_invalid, INS_movapd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2, StoreAlignedNonTemporal, 16, 2, {INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_invalid, INS_movntpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2, StoreHigh, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2, StoreLow, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movlpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2, StoreNonTemporal, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movnti, INS_movnti, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2, StoreScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movd, INS_movd, INS_movq, INS_movq, INS_invalid, INS_movsdsse2}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2, Subtract, 16, 2, {INS_psubb, INS_psubb, INS_psubw, INS_psubw, INS_psubd, INS_psubd, INS_psubq, INS_psubq, INS_invalid, INS_subpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, SubtractSaturate, 16, 2, {INS_psubsb, INS_psubusb, INS_psubsw, INS_psubusw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, SubtractScalar, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE2, UnpackHigh, 16, 2, {INS_punpckhbw, INS_punpckhbw, INS_punpckhwd, INS_punpckhwd, INS_punpckhdq, INS_punpckhdq, INS_punpckhqdq, INS_punpckhqdq, INS_invalid, INS_unpckhpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, UnpackLow, 16, 2, {INS_punpcklbw, INS_punpcklbw, INS_punpcklwd, INS_punpcklwd, INS_punpckldq, INS_punpckldq, INS_punpcklqdq, INS_punpcklqdq, INS_invalid, INS_unpcklpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE2, Xor, 16, 2, {INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_invalid, INS_xorpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) + +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // SSE2 64-bit-only Intrinsics -HARDWARE_INTRINSIC(SSE2_X64_ConvertToInt64, "ConvertToInt64", SSE2_X64, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_cvtsd2si}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_X64_ConvertToInt64WithTruncation, "ConvertToInt64WithTruncation", SSE2_X64, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttsd2si}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_X64_ConvertToUInt64, "ConvertToUInt64", SSE2_X64, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_X64_ConvertScalarToVector128Double, "ConvertScalarToVector128Double", SSE2_X64, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsi2sd, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(SSE2_X64_ConvertScalarToVector128Int64, "ConvertScalarToVector128Int64", SSE2_X64, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(SSE2_X64_ConvertScalarToVector128UInt64, "ConvertScalarToVector128UInt64", SSE2_X64, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen) -HARDWARE_INTRINSIC(SSE2_X64_StoreNonTemporal, "StoreNonTemporal", SSE2_X64, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movnti, INS_movnti, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2_X64, ConvertToInt64, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_cvtsd2si}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_X64, ConvertToInt64WithTruncation, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttsd2si}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_X64, ConvertToUInt64, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_X64, ConvertScalarToVector128Double, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsi2sd, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(SSE2_X64, ConvertScalarToVector128Int64, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(SSE2_X64, ConvertScalarToVector128UInt64, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(SSE2_X64, StoreNonTemporal, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movnti, INS_movnti, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromSecondArg) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // SSE3 Intrinsics -HARDWARE_INTRINSIC(SSE3_AddSubtract, "AddSubtract", SSE3, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addsubps, INS_addsubpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE3_HorizontalAdd, "HorizontalAdd", SSE3, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_haddps, INS_haddpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE3_HorizontalSubtract, "HorizontalSubtract", SSE3, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_hsubps, INS_hsubpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE3_LoadAndDuplicateToVector128, "LoadAndDuplicateToVector128", SSE3, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_lddqu, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movddup}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE3_LoadDquVector128, "LoadDquVector128", SSE3, -1, 16, 1, {INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE3_MoveAndDuplicate, "MoveAndDuplicate", SSE3, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movddup}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE3_MoveHighAndDuplicate, "MoveHighAndDuplicate", SSE3, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movshdup, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE3_MoveLowAndDuplicate, "MoveLowAndDuplicate", SSE3, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movsldup, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE3, AddSubtract, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addsubps, INS_addsubpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE3, HorizontalAdd, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_haddps, INS_haddpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE3, HorizontalSubtract, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_hsubps, INS_hsubpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE3, LoadAndDuplicateToVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_lddqu, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movddup}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE3, LoadDquVector128, 16, 1, {INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE3, MoveAndDuplicate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movddup}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE3, MoveHighAndDuplicate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movshdup, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE3, MoveLowAndDuplicate, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movsldup, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // SSSE3 Intrinsics -HARDWARE_INTRINSIC(SSSE3_Abs, "Abs", SSSE3, -1, 16, 1, {INS_invalid, INS_pabsb, INS_invalid, INS_pabsw, INS_invalid, INS_pabsd, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSSE3_AlignRight, "AlignRight", SSSE3, -1, 16, 3, {INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSSE3_HorizontalAdd, "HorizontalAdd", SSSE3, -1, 16, 2, {INS_invalid, INS_invalid, INS_phaddw, INS_invalid, INS_phaddd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSSE3_HorizontalAddSaturate, "HorizontalAddSaturate", SSSE3, -1, 16, 2, {INS_invalid, INS_invalid, INS_phaddsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSSE3_HorizontalSubtract, "HorizontalSubtract", SSSE3, -1, 16, 2, {INS_invalid, INS_invalid, INS_phsubw, INS_invalid, INS_phsubd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSSE3_HorizontalSubtractSaturate, "HorizontalSubtractSaturate", SSSE3, -1, 16, 2, {INS_invalid, INS_invalid, INS_phsubsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSSE3_MultiplyAddAdjacent, "MultiplyAddAdjacent", SSSE3, -1, 16, 2, {INS_invalid, INS_invalid, INS_pmaddubsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSSE3_MultiplyHighRoundScale, "MultiplyHighRoundScale", SSSE3, -1, 16, 2, {INS_invalid, INS_invalid, INS_pmulhrsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSSE3_Shuffle, "Shuffle", SSSE3, -1, 16, 2, {INS_pshufb, INS_pshufb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSSE3_Sign, "Sign", SSSE3, -1, 16, 2, {INS_psignb, INS_invalid, INS_psignw, INS_invalid, INS_psignd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSSE3, Abs, 16, 1, {INS_pabsb, INS_invalid, INS_pabsw, INS_invalid, INS_pabsd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(SSSE3, AlignRight, 16, 3, {INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSSE3, HorizontalAdd, 16, 2, {INS_invalid, INS_invalid, INS_phaddw, INS_invalid, INS_phaddd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSSE3, HorizontalAddSaturate, 16, 2, {INS_invalid, INS_invalid, INS_phaddsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSSE3, HorizontalSubtract, 16, 2, {INS_invalid, INS_invalid, INS_phsubw, INS_invalid, INS_phsubd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSSE3, HorizontalSubtractSaturate, 16, 2, {INS_invalid, INS_invalid, INS_phsubsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSSE3, MultiplyAddAdjacent, 16, 2, {INS_invalid, INS_invalid, INS_pmaddubsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSSE3, MultiplyHighRoundScale, 16, 2, {INS_invalid, INS_invalid, INS_pmulhrsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSSE3, Shuffle, 16, 2, {INS_pshufb, INS_pshufb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSSE3, Sign, 16, 2, {INS_psignb, INS_invalid, INS_psignw, INS_invalid, INS_psignd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // SSE41 Intrinsics -HARDWARE_INTRINSIC(SSE41_Blend, "Blend", SSE41, -1, 16, 3, {INS_invalid, INS_invalid, INS_pblendw, INS_pblendw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blendps, INS_blendpd}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE41_BlendVariable, "BlendVariable", SSE41, -1, 16, 3, {INS_pblendvb, INS_pblendvb, INS_pblendvb, INS_pblendvb, INS_pblendvb, INS_pblendvb, INS_pblendvb, INS_pblendvb, INS_blendvps, INS_blendvpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE41_Ceiling, "Ceiling", SSE41, 10, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_CeilingScalar, "CeilingScalar", SSE41, 10, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE41_CompareEqual, "CompareEqual", SSE41, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pcmpeqq, INS_pcmpeqq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE41_ConvertToVector128Int16, "ConvertToVector128Int16", SSE41, -1, 16, 1, {INS_pmovsxbw, INS_pmovzxbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_ConvertToVector128Int32, "ConvertToVector128Int32", SSE41, -1, 16, 1, {INS_pmovsxbd, INS_pmovzxbd, INS_pmovsxwd, INS_pmovzxwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_ConvertToVector128Int64, "ConvertToVector128Int64", SSE41, -1, 16, 1, {INS_pmovsxbq, INS_pmovzxbq, INS_pmovsxwq, INS_pmovzxwq, INS_pmovsxdq, INS_pmovzxdq, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_DotProduct, "DotProduct", SSE41, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_dpps, INS_dppd}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE41_Extract, "Extract", SSE41, -1, 16, 2, {INS_pextrb, INS_pextrb, INS_invalid, INS_invalid, INS_pextrd, INS_pextrd, INS_invalid, INS_invalid, INS_extractps, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_BaseTypeFromFirstArg|HW_Flag_MultiIns|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_Floor, "Floor", SSE41, 9, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_FloorScalar, "FloorScalar", SSE41, 9, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE41_Insert, "Insert", SSE41, -1, 16, 3, {INS_pinsrb, INS_pinsrb, INS_invalid, INS_invalid, INS_pinsrd, INS_pinsrd, INS_invalid, INS_invalid, INS_insertps, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE41_LoadAlignedVector128NonTemporal, "LoadAlignedVector128NonTemporal", SSE41, -1, 16, 1, {INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_Max, "Max", SSE41, -1, 16, 2, {INS_pmaxsb, INS_invalid, INS_invalid, INS_pmaxuw, INS_pmaxsd, INS_pmaxud, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE41_Min, "Min", SSE41, -1, 16, 2, {INS_pminsb, INS_invalid, INS_invalid, INS_pminuw, INS_pminsd, INS_pminud, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE41_MinHorizontal, "MinHorizontal", SSE41, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_phminposuw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_MultipleSumAbsoluteDifferences, "MultipleSumAbsoluteDifferences", SSE41, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_mpsadbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(SSE41_Multiply, "Multiply", SSE41, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmuldq, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(SSE41_MultiplyLow, "MultiplyLow", SSE41, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmulld, INS_pmulld, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE41_PackUnsignedSaturate, "PackUnsignedSaturate", SSE41, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_packusdw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE41_RoundCurrentDirection, "RoundCurrentDirection", SSE41, 4, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_RoundCurrentDirectionScalar, "RoundCurrentDirectionScalar", SSE41, 4, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE41_RoundToNearestInteger, "RoundToNearestInteger", SSE41, 8, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_RoundToNearestIntegerScalar, "RoundToNearestIntegerScalar", SSE41, 8, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE41_RoundToNegativeInfinity, "RoundToNegativeInfinity", SSE41, 9, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_RoundToNegativeInfinityScalar, "RoundToNegativeInfinityScalar", SSE41, 9, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE41_RoundToPositiveInfinity, "RoundToPositiveInfinity", SSE41, 10, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_RoundToPositiveInfinityScalar, "RoundToPositiveInfinityScalar", SSE41, 10, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE41_RoundToZero, "RoundToZero", SSE41, 11, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_RoundToZeroScalar, "RoundToZeroScalar", SSE41, 11, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE41_TestC, "TestC", SSE41, -1, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(SSE41_TestNotZAndNotC, "TestNotZAndNotC", SSE41, -1, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(SSE41_TestZ, "TestZ", SSE41, -1, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) - -// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +HARDWARE_INTRINSIC(SSE41, Blend, 16, 3, {INS_invalid, INS_invalid, INS_pblendw, INS_pblendw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blendps, INS_blendpd}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE41, BlendVariable, 16, 3, {INS_pblendvb, INS_pblendvb, INS_pblendvb, INS_pblendvb, INS_pblendvb, INS_pblendvb, INS_pblendvb, INS_pblendvb, INS_blendvps, INS_blendvpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE41, Ceiling, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, CeilingScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE41, CompareEqual, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pcmpeqq, INS_pcmpeqq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE41, ConvertToVector128Int16, 16, 1, {INS_pmovsxbw, INS_pmovzxbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, ConvertToVector128Int32, 16, 1, {INS_pmovsxbd, INS_pmovzxbd, INS_pmovsxwd, INS_pmovzxwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, ConvertToVector128Int64, 16, 1, {INS_pmovsxbq, INS_pmovzxbq, INS_pmovsxwq, INS_pmovzxwq, INS_pmovsxdq, INS_pmovzxdq, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, DotProduct, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_dpps, INS_dppd}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE41, Extract, 16, 2, {INS_pextrb, INS_pextrb, INS_invalid, INS_invalid, INS_pextrd, INS_pextrd, INS_invalid, INS_invalid, INS_extractps, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_BaseTypeFromFirstArg|HW_Flag_MultiIns|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, Floor, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, FloorScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE41, Insert, 16, 3, {INS_pinsrb, INS_pinsrb, INS_invalid, INS_invalid, INS_pinsrd, INS_pinsrd, INS_invalid, INS_invalid, INS_insertps, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE41, LoadAlignedVector128NonTemporal, 16, 1, {INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, Max, 16, 2, {INS_pmaxsb, INS_invalid, INS_invalid, INS_pmaxuw, INS_pmaxsd, INS_pmaxud, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE41, Min, 16, 2, {INS_pminsb, INS_invalid, INS_invalid, INS_pminuw, INS_pminsd, INS_pminud, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE41, MinHorizontal, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_phminposuw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, MultipleSumAbsoluteDifferences, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_mpsadbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE41, Multiply, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmuldq, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(SSE41, MultiplyLow, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmulld, INS_pmulld, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE41, PackUnsignedSaturate, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_packusdw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE41, RoundCurrentDirection, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, RoundCurrentDirectionScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE41, RoundToNearestInteger, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, RoundToNearestIntegerScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE41, RoundToNegativeInfinity, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, RoundToNegativeInfinityScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE41, RoundToPositiveInfinity, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, RoundToPositiveInfinityScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE41, RoundToZero, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, RoundToZeroScalar, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundss, INS_roundsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(SSE41, TestC, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(SSE41, TestNotZAndNotC, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(SSE41, TestZ, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) + +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // SSE41 64-bit-only Intrinsics -HARDWARE_INTRINSIC(SSE41_X64_Extract, "Extract", SSE41_X64, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pextrq, INS_pextrq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_BaseTypeFromFirstArg|HW_Flag_MultiIns|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_X64_Insert, "Insert", SSE41_X64, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pinsrq, INS_pinsrq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(SSE41_X64, Extract, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pextrq, INS_pextrq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_BaseTypeFromFirstArg|HW_Flag_MultiIns|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41_X64, Insert, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pinsrq, INS_pinsrq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // SSE42 Intrinsics -HARDWARE_INTRINSIC(SSE42_Crc32, "Crc32", SSE42, -1, 0, 2, {INS_invalid, INS_crc32, INS_invalid, INS_crc32, INS_invalid, INS_crc32, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed) -HARDWARE_INTRINSIC(SSE42_CompareGreaterThan, "CompareGreaterThan", SSE42, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pcmpgtq, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE42, Crc32, 0, 2, {INS_invalid, INS_crc32, INS_invalid, INS_crc32, INS_invalid, INS_crc32, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed) +HARDWARE_INTRINSIC(SSE42, CompareGreaterThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pcmpgtq, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE42, CompareLessThan, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pcmpgtq, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // SSE42 Intrinsics -HARDWARE_INTRINSIC(SSE42_X64_Crc32, "Crc32", SSE42_X64, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_crc32, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed) +HARDWARE_INTRINSIC(SSE42_X64, Crc32, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_crc32, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // AVX Intrinsics -HARDWARE_INTRINSIC(AVX_Add, "Add", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addps, INS_addpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX_AddSubtract, "AddSubtract", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addsubps, INS_addsubpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_And, "And", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_andps, INS_andpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX_AndNot, "AndNot", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_andnps, INS_andnpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_Blend, "Blend", AVX, -1, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blendps, INS_blendpd}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX_BlendVariable, "BlendVariable", AVX, -1, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vblendvps, INS_vblendvpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_Ceiling, "Ceiling", AVX, 10, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_BroadcastScalarToVector128, "BroadcastScalarToVector128", AVX, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vbroadcastss, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_BroadcastScalarToVector256, "BroadcastScalarToVector256", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vbroadcastss, INS_vbroadcastsd}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_BroadcastVector128ToVector256, "BroadcastVector128ToVector256", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vbroadcastf128, INS_vbroadcastf128}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_Compare, "Compare", AVX, -1, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_IMM, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_CompareScalar, "CompareScalar", AVX, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_cmpsd}, HW_Category_IMM, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(AVX_ConvertToVector128Int32, "ConvertToVector128Int32", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtpd2dq, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_ConvertToVector128Single, "ConvertToVector128Single", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtpd2ps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_ConvertToVector256Int32, "ConvertToVector256Int32", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtps2dq, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_ConvertToVector256Single, "ConvertToVector256Single", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtdq2ps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_ConvertToVector256Double, "ConvertToVector256Double", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtdq2pd, INS_invalid, INS_invalid, INS_invalid, INS_cvtps2pd, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_ConvertToVector128Int32WithTruncation, "ConvertToVector128Int32WithTruncation", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttpd2dq, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_ConvertToVector256Int32WithTruncation, "ConvertToVector256Int32WithTruncation", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttps2dq, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_Divide, "Divide", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divps, INS_divpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_DotProduct, "DotProduct", AVX, -1, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_dpps, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX_DuplicateEvenIndexed, "DuplicateEvenIndexed", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movsldup, INS_movddup}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_DuplicateOddIndexed, "DuplicateOddIndexed", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movshdup, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_ExtractVector128, "ExtractVector128", AVX, -1, 32, 2, {INS_vextractf128, INS_vextractf128, INS_vextractf128, INS_vextractf128, INS_vextractf128, INS_vextractf128, INS_vextractf128, INS_vextractf128, INS_vextractf128, INS_vextractf128}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX_Floor, "Floor", AVX, 9, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_HorizontalAdd, "HorizontalAdd", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_haddps, INS_haddpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_HorizontalSubtract, "HorizontalSubtract", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_hsubps, INS_hsubpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_InsertVector128, "InsertVector128", AVX, -1, 32, 3, {INS_vinsertf128, INS_vinsertf128, INS_vinsertf128, INS_vinsertf128, INS_vinsertf128, INS_vinsertf128, INS_vinsertf128, INS_vinsertf128, INS_vinsertf128, INS_vinsertf128}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX_LoadAlignedVector256, "LoadAlignedVector256", AVX, -1, 32, 1, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movaps, INS_movapd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_LoadDquVector256, "LoadDquVector256", AVX, -1, 32, 1, {INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_LoadVector256, "LoadVector256", AVX, -1, 32, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_Max, "Max", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxps, INS_maxpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX_Min, "Min", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minps, INS_minpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX_MaskLoad, "MaskLoad", AVX, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vmaskmovps, INS_vmaskmovpd}, HW_Category_MemoryLoad, HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AVX_MaskStore, "MaskStore", AVX, -1, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vmaskmovps, INS_vmaskmovpd}, HW_Category_MemoryStore, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(AVX_MoveMask, "MoveMask", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movmskps, INS_movmskpd}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AVX_Multiply, "Multiply", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulps, INS_mulpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX_Or, "Or", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_orps, INS_orpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX_Permute, "Permute", AVX, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpermilps, INS_vpermilpd}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AVX_Permute2x128, "Permute2x128", AVX, -1, 32, 3, {INS_vperm2f128, INS_vperm2f128, INS_vperm2f128, INS_vperm2f128, INS_vperm2f128, INS_vperm2f128, INS_vperm2f128, INS_vperm2f128, INS_vperm2f128, INS_vperm2f128}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX_PermuteVar, "PermuteVar", AVX, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpermilpsvar, INS_vpermilpdvar}, HW_Category_SimpleSIMD, HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AVX_Reciprocal, "Reciprocal", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rcpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_ReciprocalSqrt, "ReciprocalSqrt", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rsqrtps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_RoundCurrentDirection, "RoundCurrentDirection", AVX, 4, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_RoundToNearestInteger, "RoundToNearestInteger", AVX, 8, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_RoundToNegativeInfinity, "RoundToNegativeInfinity", AVX, 9, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_RoundToPositiveInfinity, "RoundToPositiveInfinity", AVX, 10, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_RoundToZero, "RoundToZero", AVX, 11, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_Shuffle, "Shuffle", AVX, -1, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_shufps, INS_shufpd}, HW_Category_IMM, HW_Flag_NoRMWSemantics|HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX_Sqrt, "Sqrt", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtps, INS_sqrtpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_Store, "Store", AVX, -1, 32, 2, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(AVX_StoreAligned, "StoreAligned", AVX, -1, 32, 2, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movaps, INS_movapd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(AVX_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", AVX, -1, 32, 2, {INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntps, INS_movntpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(AVX_Subtract, "Subtract", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subps, INS_subpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_TestC, "TestC", AVX, -1, 0, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_vtestps, INS_vtestpd}, HW_Category_SimpleSIMD, HW_Flag_UnfixedSIMDSize|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AVX_TestNotZAndNotC, "TestNotZAndNotC", AVX, -1, 0, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_vtestps, INS_vtestpd}, HW_Category_SimpleSIMD, HW_Flag_UnfixedSIMDSize|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AVX_TestZ, "TestZ", AVX, -1, 0, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_vtestps, INS_vtestpd}, HW_Category_SimpleSIMD, HW_Flag_UnfixedSIMDSize|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AVX_UnpackHigh, "UnpackHigh", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_unpckhps, INS_unpckhpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_UnpackLow, "UnpackLow", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_unpcklps, INS_unpcklpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX_Xor, "Xor", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_xorps, INS_xorpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) - -// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +HARDWARE_INTRINSIC(AVX, Add, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addps, INS_addpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX, AddSubtract, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_addsubps, INS_addsubpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, And, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_andps, INS_andpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX, AndNot, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_andnps, INS_andnpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, Blend, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blendps, INS_blendpd}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX, BlendVariable, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vblendvps, INS_vblendvpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, Ceiling, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, BroadcastScalarToVector128, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vbroadcastss, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, BroadcastScalarToVector256, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vbroadcastss, INS_vbroadcastsd}, HW_Category_MemoryLoad, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, BroadcastVector128ToVector256, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vbroadcastf128, INS_vbroadcastf128}, HW_Category_MemoryLoad, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, Compare, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_IMM, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, CompareEqual, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX, CompareGreaterThan, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, CompareGreaterThanOrEqual, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, CompareLessThan, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, CompareLessThanOrEqual, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, CompareNotEqual, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX, CompareNotGreaterThan, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, CompareNotGreaterThanOrEqual, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, CompareNotLessThan, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, CompareNotLessThanOrEqual, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, CompareOrdered, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, CompareUnordered, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpps, INS_cmppd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, CompareScalar, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cmpss, INS_cmpsd}, HW_Category_IMM, HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(AVX, ConvertToVector128Int32, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtpd2dq, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, ConvertToVector128Single, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtpd2ps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, ConvertToVector256Int32, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtps2dq, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, ConvertToVector256Single, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtdq2ps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, ConvertToVector256Double, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtdq2pd, INS_invalid, INS_invalid, INS_invalid, INS_cvtps2pd, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, ConvertToVector128Int32WithTruncation, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttpd2dq, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, ConvertToVector256Int32WithTruncation, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvttps2dq, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, Divide, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divps, INS_divpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, DotProduct, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_dpps, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX, DuplicateEvenIndexed, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movsldup, INS_movddup}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, DuplicateOddIndexed, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movshdup, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, ExtractVector128, 32, 2, {INS_vextractf128, INS_vextractf128, INS_vextractf128, INS_vextractf128, INS_vextractf128, INS_vextractf128, INS_vextractf128, INS_vextractf128, INS_vextractf128, INS_vextractf128}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX, Floor, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, HorizontalAdd, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_haddps, INS_haddpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, HorizontalSubtract, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_hsubps, INS_hsubpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, InsertVector128, 32, 3, {INS_vinsertf128, INS_vinsertf128, INS_vinsertf128, INS_vinsertf128, INS_vinsertf128, INS_vinsertf128, INS_vinsertf128, INS_vinsertf128, INS_vinsertf128, INS_vinsertf128}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX, LoadAlignedVector256, 32, 1, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movaps, INS_movapd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, LoadDquVector256, 32, 1, {INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_lddqu, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, LoadVector256, 32, 1, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_MemoryLoad, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, Max, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_maxps, INS_maxpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX, Min, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minps, INS_minpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX, MaskLoad, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vmaskmovps, INS_vmaskmovpd}, HW_Category_MemoryLoad, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, MaskStore, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vmaskmovps, INS_vmaskmovpd}, HW_Category_MemoryStore, HW_Flag_NoContainment|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AVX, MoveMask, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movmskps, INS_movmskpd}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX, Multiply, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulps, INS_mulpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX, Or, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_orps, INS_orpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX, Permute, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpermilps, INS_vpermilpd}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX, Permute2x128, 32, 3, {INS_vperm2f128, INS_vperm2f128, INS_vperm2f128, INS_vperm2f128, INS_vperm2f128, INS_vperm2f128, INS_vperm2f128, INS_vperm2f128, INS_vperm2f128, INS_vperm2f128}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX, PermuteVar, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpermilpsvar, INS_vpermilpdvar}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, Reciprocal, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rcpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, ReciprocalSqrt, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rsqrtps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, RoundCurrentDirection, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, RoundToNearestInteger, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, RoundToNegativeInfinity, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, RoundToPositiveInfinity, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, RoundToZero, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, Shuffle, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_shufps, INS_shufpd}, HW_Category_IMM, HW_Flag_NoRMWSemantics|HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX, Sqrt, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtps, INS_sqrtpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, Store, 32, 2, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AVX, StoreAligned, 32, 2, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movaps, INS_movapd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AVX, StoreAlignedNonTemporal, 32, 2, {INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntps, INS_movntpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AVX, Subtract, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_subps, INS_subpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, TestC, -1, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_vtestps, INS_vtestpd}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX, TestNotZAndNotC, -1, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_vtestps, INS_vtestpd}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX, TestZ, -1, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_vtestps, INS_vtestpd}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX, UnpackHigh, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_unpckhps, INS_unpckhpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, UnpackLow, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_unpcklps, INS_unpcklpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX, Xor, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_xorps, INS_xorpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) + +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // AVX2 Intrinsics -HARDWARE_INTRINSIC(AVX2_Abs, "Abs", AVX2, -1, 32, 1, {INS_pabsb, INS_pabsb, INS_pabsw, INS_pabsw, INS_pabsd, INS_pabsd, INS_paddq, INS_paddq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX2_Add, "Add", AVX2, -1, 32, 2, {INS_paddb, INS_paddb, INS_paddw, INS_paddw, INS_paddd, INS_paddd, INS_paddq, INS_paddq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX2_AddSaturate, "AddSaturate", AVX2, -1, 32, 2, {INS_paddsb, INS_paddusb, INS_paddsw, INS_paddusw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX2_AlignRight, "AlignRight", AVX2, -1, 32, 3, {INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX2_And, "And", AVX2, -1, 32, 2, {INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX2_AndNot, "AndNot", AVX2, -1, 32, 2, {INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_Average, "Average", AVX2, -1, 32, 2, {INS_invalid, INS_pavgb, INS_invalid, INS_pavgw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX2_Blend, "Blend", AVX2, -1, 0, 3, {INS_invalid, INS_invalid, INS_pblendw, INS_pblendw, INS_vpblendd, INS_vpblendd, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_UnfixedSIMDSize|HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX2_BlendVariable, "BlendVariable", AVX2, -1, 32, 3, {INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_BroadcastScalarToVector128, "BroadcastScalarToVector128", AVX2, -1, 16, 1, {INS_vpbroadcastb, INS_vpbroadcastb, INS_vpbroadcastw, INS_vpbroadcastw, INS_vpbroadcastd, INS_vpbroadcastd, INS_vpbroadcastq, INS_vpbroadcastq, INS_vbroadcastss, INS_movddup}, HW_Category_SIMDScalar, HW_Flag_MaybeMemoryLoad) -HARDWARE_INTRINSIC(AVX2_BroadcastScalarToVector256, "BroadcastScalarToVector256", AVX2, -1, 32, 1, {INS_vpbroadcastb, INS_vpbroadcastb, INS_vpbroadcastw, INS_vpbroadcastw, INS_vpbroadcastd, INS_vpbroadcastd, INS_vpbroadcastq, INS_vpbroadcastq, INS_vbroadcastss, INS_vbroadcastsd}, HW_Category_SIMDScalar, HW_Flag_MaybeMemoryLoad) -HARDWARE_INTRINSIC(AVX2_BroadcastVector128ToVector256, "BroadcastVector128ToVector256", AVX2, -1, 32, 1, {INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_CompareEqual, "CompareEqual", AVX2, -1, 32, 2, {INS_pcmpeqb, INS_pcmpeqb, INS_pcmpeqw, INS_pcmpeqw, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqq, INS_pcmpeqq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX2_CompareGreaterThan, "CompareGreaterThan", AVX2, -1, 32, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_pcmpgtq, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_ExtractVector128, "ExtractVector128", AVX2, -1, 32, 2, {INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX2_ConvertToInt32, "ConvertToInt32", AVX2, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX2_ConvertToUInt32, "ConvertToUInt32", AVX2, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX2_ConvertToVector256Int16, "ConvertToVector256Int16", AVX2, -1, 32, 1, {INS_pmovsxbw, INS_pmovzxbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AVX2_ConvertToVector256Int32, "ConvertToVector256Int32", AVX2, -1, 32, 1, {INS_pmovsxbd, INS_pmovzxbd, INS_pmovsxwd, INS_pmovzxwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AVX2_ConvertToVector256Int64, "ConvertToVector256Int64", AVX2, -1, 32, 1, {INS_pmovsxbq, INS_pmovzxbq, INS_pmovsxwq, INS_pmovzxwq, INS_pmovsxdq, INS_pmovzxdq, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AVX2_GatherVector128, "GatherVector128", AVX2, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpgatherdd, INS_vpgatherdd, INS_vpgatherdq, INS_vpgatherdq, INS_vgatherdps, INS_vgatherdpd}, HW_Category_IMM, HW_Flag_SpecialCodeGen|HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AVX2_GatherVector256, "GatherVector256", AVX2, -1, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpgatherdd, INS_vpgatherdd, INS_vpgatherdq, INS_vpgatherdq, INS_vgatherdps, INS_vgatherdpd}, HW_Category_IMM, HW_Flag_MaybeMemoryLoad|HW_Flag_SpecialCodeGen|HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AVX2_GatherMaskVector128, "GatherMaskVector128", AVX2, -1, 16, 5, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpgatherdd, INS_vpgatherdd, INS_vpgatherdq, INS_vpgatherdq, INS_vgatherdps, INS_vgatherdpd}, HW_Category_IMM, HW_Flag_MaybeMemoryLoad|HW_Flag_SpecialCodeGen|HW_Flag_SpecialImport|HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AVX2_GatherMaskVector256, "GatherMaskVector256", AVX2, -1, 32, 5, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpgatherdd, INS_vpgatherdd, INS_vpgatherdq, INS_vpgatherdq, INS_vgatherdps, INS_vgatherdpd}, HW_Category_IMM, HW_Flag_MaybeMemoryLoad|HW_Flag_SpecialCodeGen|HW_Flag_SpecialImport|HW_Flag_NoContainment) -HARDWARE_INTRINSIC(AVX2_HorizontalAdd, "HorizontalAdd", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_phaddw, INS_invalid, INS_phaddd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_HorizontalAddSaturate, "HorizontalAddSaturate", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_phaddsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_HorizontalSubtract, "HorizontalSubtract", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_phsubw, INS_invalid, INS_phsubd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_HorizontalSubtractSaturate, "HorizontalSubtractSaturate", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_phsubsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_InsertVector128, "InsertVector128", AVX2, -1, 32, 3, {INS_vinserti128, INS_vinserti128, INS_vinserti128, INS_vinserti128, INS_vinserti128, INS_vinserti128, INS_vinserti128, INS_vinserti128, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX2_LoadAlignedVector256NonTemporal, "LoadAlignedVector256NonTemporal", AVX2, -1, 32, 1, {INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_MaskLoad, "MaskLoad", AVX2, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpmaskmovd, INS_vpmaskmovd, INS_vpmaskmovq, INS_vpmaskmovq, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AVX2_MaskStore, "MaskStore", AVX2, -1, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpmaskmovd, INS_vpmaskmovd, INS_vpmaskmovq, INS_vpmaskmovq, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoContainment|HW_Flag_UnfixedSIMDSize|HW_Flag_BaseTypeFromSecondArg) -HARDWARE_INTRINSIC(AVX2_Max, "Max", AVX2, -1, 32, 2, {INS_pmaxsb, INS_pmaxub, INS_pmaxsw, INS_pmaxuw, INS_pmaxsd, INS_pmaxud, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX2_Min, "Min", AVX2, -1, 32, 2, {INS_pminsb, INS_pminub, INS_pminsw, INS_pminuw, INS_pminsd, INS_pminud, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX2_MoveMask, "MoveMask", AVX2, -1, 32, 1, {INS_pmovmskb, INS_pmovmskb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) -HARDWARE_INTRINSIC(AVX2_Multiply, "Multiply", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmuldq, INS_pmuludq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX2_MultipleSumAbsoluteDifferences, "MultipleSumAbsoluteDifferences", AVX2, -1, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_mpsadbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX2_MultiplyAddAdjacent, "MultiplyAddAdjacent", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_pmaddubsw, INS_invalid, INS_pmaddwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_MultiplyHigh, "MultiplyHigh", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_pmulhw, INS_pmulhuw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX2_MultiplyHighRoundScale, "MultiplyHighRoundScale", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_pmulhrsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_MultiplyLow, "MultiplyLow", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_pmullw, INS_pmullw, INS_pmulld, INS_pmulld, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX2_Or, "Or", AVX2, -1, 32, 2, {INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) -HARDWARE_INTRINSIC(AVX2_Permute2x128, "Permute2x128", AVX2, -1, 32, 3, {INS_vperm2i128, INS_vperm2i128, INS_vperm2i128, INS_vperm2i128, INS_vperm2i128, INS_vperm2i128, INS_vperm2i128, INS_vperm2i128, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX2_Permute4x64, "Permute4x64", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpermq, INS_vpermq, INS_invalid, INS_vpermpd}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX2_PermuteVar8x32, "PermuteVar8x32", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpermd, INS_vpermd, INS_invalid, INS_invalid, INS_vpermps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport) -HARDWARE_INTRINSIC(AVX2_PackSignedSaturate, "PackSignedSaturate", AVX2, -1, 32, 2, {INS_packsswb, INS_invalid, INS_packssdw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_PackUnsignedSaturate, "PackUnsignedSaturate", AVX2, -1, 32, 2, {INS_invalid, INS_packuswb, INS_invalid, INS_packusdw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_ShiftLeftLogical, "ShiftLeftLogical", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_psllw, INS_psllw, INS_pslld, INS_pslld, INS_psllq, INS_psllq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX2_ShiftLeftLogical128BitLane, "ShiftLeftLogical128BitLane", AVX2, -1, 32, 2, {INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX2_ShiftLeftLogicalVariable, "ShiftLeftLogicalVariable", AVX2, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpsllvd, INS_vpsllvd, INS_vpsllvq, INS_vpsllvq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AVX2_ShiftRightArithmetic, "ShiftRightArithmetic", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_psraw, INS_invalid, INS_psrad, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX2_ShiftRightArithmeticVariable, "ShiftRightArithmeticVariable", AVX2, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpsravd, INS_vpsravd, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AVX2_ShiftRightLogical, "ShiftRightLogical", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_psrlw, INS_psrlw, INS_psrld, INS_psrld, INS_psrlq, INS_psrlq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX2_ShiftRightLogical128BitLane, "ShiftRightLogical128BitLane", AVX2, -1, 32, 2, {INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX2_ShiftRightLogicalVariable, "ShiftRightLogicalVariable", AVX2, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpsrlvd, INS_vpsrlvd, INS_vpsrlvq, INS_vpsrlvq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(AVX2_Shuffle, "Shuffle", AVX2, -1, 32, 2, {INS_pshufb, INS_pshufb, INS_invalid, INS_invalid, INS_pshufd, INS_pshufd, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_MaybeIMM) -HARDWARE_INTRINSIC(AVX2_ShuffleHigh, "ShuffleHigh", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_pshufhw, INS_pshufhw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX2_ShuffleLow, "ShuffleLow", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_pshuflw, INS_pshuflw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) -HARDWARE_INTRINSIC(AVX2_Sign, "Sign", AVX2, -1, 32, 2, {INS_psignb, INS_invalid, INS_psignw, INS_invalid, INS_psignd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_SumAbsoluteDifferences, "SumAbsoluteDifferences", AVX2, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_psadbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_Subtract, "Subtract", AVX2, -1, 32, 2, {INS_psubb, INS_psubb, INS_psubw, INS_psubw, INS_psubd, INS_psubd, INS_psubq, INS_psubq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_SubtractSaturate, "SubtractSaturate", AVX2, -1, 32, 2, {INS_psubsb, INS_psubusb, INS_psubsw, INS_psubusw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_UnpackHigh, "UnpackHigh", AVX2, -1, 32, 2, {INS_punpckhbw, INS_punpckhbw, INS_punpckhwd, INS_punpckhwd, INS_punpckhdq, INS_punpckhdq, INS_punpckhqdq, INS_punpckhqdq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_UnpackLow, "UnpackLow", AVX2, -1, 32, 2, {INS_punpcklbw, INS_punpcklbw, INS_punpcklwd, INS_punpcklwd, INS_punpckldq, INS_punpckldq, INS_punpcklqdq, INS_punpcklqdq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AVX2_Xor, "Xor", AVX2, -1, 32, 2, {INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) - -// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +HARDWARE_INTRINSIC(AVX2, Abs, 32, 1, {INS_pabsb, INS_invalid, INS_pabsw, INS_invalid, INS_pabsd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX2, Add, 32, 2, {INS_paddb, INS_paddb, INS_paddw, INS_paddw, INS_paddd, INS_paddd, INS_paddq, INS_paddq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX2, AddSaturate, 32, 2, {INS_paddsb, INS_paddusb, INS_paddsw, INS_paddusw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX2, AlignRight, 32, 3, {INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_palignr, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2, And, 32, 2, {INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_pand, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX2, AndNot, 32, 2, {INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_pandn, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, Average, 32, 2, {INS_invalid, INS_pavgb, INS_invalid, INS_pavgw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX2, Blend, -1, 3, {INS_invalid, INS_invalid, INS_pblendw, INS_pblendw, INS_vpblendd, INS_vpblendd, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2, BlendVariable, 32, 3, {INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_vpblendvb, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, BroadcastScalarToVector128, 16, 1, {INS_vpbroadcastb, INS_vpbroadcastb, INS_vpbroadcastw, INS_vpbroadcastw, INS_vpbroadcastd, INS_vpbroadcastd, INS_vpbroadcastq, INS_vpbroadcastq, INS_vbroadcastss, INS_movddup}, HW_Category_SIMDScalar, HW_Flag_MaybeMemoryLoad) +HARDWARE_INTRINSIC(AVX2, BroadcastScalarToVector256, 32, 1, {INS_vpbroadcastb, INS_vpbroadcastb, INS_vpbroadcastw, INS_vpbroadcastw, INS_vpbroadcastd, INS_vpbroadcastd, INS_vpbroadcastq, INS_vpbroadcastq, INS_vbroadcastss, INS_vbroadcastsd}, HW_Category_SIMDScalar, HW_Flag_MaybeMemoryLoad) +HARDWARE_INTRINSIC(AVX2, BroadcastVector128ToVector256, 32, 1, {INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_vbroadcasti128, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, CompareEqual, 32, 2, {INS_pcmpeqb, INS_pcmpeqb, INS_pcmpeqw, INS_pcmpeqw, INS_pcmpeqd, INS_pcmpeqd, INS_pcmpeqq, INS_pcmpeqq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX2, CompareGreaterThan, 32, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_pcmpgtq, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, CompareLessThan, 32, 2, {INS_pcmpgtb, INS_invalid, INS_pcmpgtw, INS_invalid, INS_pcmpgtd, INS_invalid, INS_pcmpgtq, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, ExtractVector128, 32, 2, {INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_vextracti128, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2, ConvertToInt32, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX2, ConvertToUInt32, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_xmm2i, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX2, ConvertToVector256Int16, 32, 1, {INS_pmovsxbw, INS_pmovzxbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX2, ConvertToVector256Int32, 32, 1, {INS_pmovsxbd, INS_pmovzxbd, INS_pmovsxwd, INS_pmovzxwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX2, ConvertToVector256Int64, 32, 1, {INS_pmovsxbq, INS_pmovzxbq, INS_pmovsxwq, INS_pmovzxwq, INS_pmovsxdq, INS_pmovzxdq, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX2, GatherVector128, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpgatherdd, INS_vpgatherdd, INS_vpgatherdq, INS_vpgatherdq, INS_vgatherdps, INS_vgatherdpd}, HW_Category_IMM, HW_Flag_MaybeMemoryLoad|HW_Flag_SpecialCodeGen|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(AVX2, GatherVector256, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpgatherdd, INS_vpgatherdd, INS_vpgatherdq, INS_vpgatherdq, INS_vgatherdps, INS_vgatherdpd}, HW_Category_IMM, HW_Flag_MaybeMemoryLoad|HW_Flag_SpecialCodeGen|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(AVX2, GatherMaskVector128, 16, 5, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpgatherdd, INS_vpgatherdd, INS_vpgatherdq, INS_vpgatherdq, INS_vgatherdps, INS_vgatherdpd}, HW_Category_IMM, HW_Flag_MaybeMemoryLoad|HW_Flag_SpecialCodeGen|HW_Flag_SpecialImport|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(AVX2, GatherMaskVector256, 32, 5, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpgatherdd, INS_vpgatherdd, INS_vpgatherdq, INS_vpgatherdq, INS_vgatherdps, INS_vgatherdpd}, HW_Category_IMM, HW_Flag_MaybeMemoryLoad|HW_Flag_SpecialCodeGen|HW_Flag_SpecialImport|HW_Flag_NoContainment) +HARDWARE_INTRINSIC(AVX2, HorizontalAdd, 32, 2, {INS_invalid, INS_invalid, INS_phaddw, INS_invalid, INS_phaddd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, HorizontalAddSaturate, 32, 2, {INS_invalid, INS_invalid, INS_phaddsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, HorizontalSubtract, 32, 2, {INS_invalid, INS_invalid, INS_phsubw, INS_invalid, INS_phsubd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, HorizontalSubtractSaturate, 32, 2, {INS_invalid, INS_invalid, INS_phsubsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, InsertVector128, 32, 3, {INS_vinserti128, INS_vinserti128, INS_vinserti128, INS_vinserti128, INS_vinserti128, INS_vinserti128, INS_vinserti128, INS_vinserti128, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2, LoadAlignedVector256NonTemporal, 32, 1, {INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_movntdqa, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, MaskLoad, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpmaskmovd, INS_vpmaskmovd, INS_vpmaskmovq, INS_vpmaskmovq, INS_invalid, INS_invalid}, HW_Category_MemoryLoad, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, MaskStore, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpmaskmovd, INS_vpmaskmovd, INS_vpmaskmovq, INS_vpmaskmovq, INS_invalid, INS_invalid}, HW_Category_MemoryStore, HW_Flag_NoContainment|HW_Flag_BaseTypeFromSecondArg) +HARDWARE_INTRINSIC(AVX2, Max, 32, 2, {INS_pmaxsb, INS_pmaxub, INS_pmaxsw, INS_pmaxuw, INS_pmaxsd, INS_pmaxud, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX2, Min, 32, 2, {INS_pminsb, INS_pminub, INS_pminsw, INS_pminuw, INS_pminsd, INS_pminud, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX2, MoveMask, 32, 1, {INS_pmovmskb, INS_pmovmskb, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(AVX2, Multiply, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pmuldq, INS_pmuludq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX2, MultipleSumAbsoluteDifferences, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_mpsadbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2, MultiplyAddAdjacent, 32, 2, {INS_invalid, INS_invalid, INS_pmaddubsw, INS_invalid, INS_pmaddwd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, MultiplyHigh, 32, 2, {INS_invalid, INS_invalid, INS_pmulhw, INS_pmulhuw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX2, MultiplyHighRoundScale, 32, 2, {INS_invalid, INS_invalid, INS_pmulhrsw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, MultiplyLow, 32, 2, {INS_invalid, INS_invalid, INS_pmullw, INS_pmullw, INS_pmulld, INS_pmulld, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX2, Or, 32, 2, {INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_por, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX2, Permute2x128, 32, 3, {INS_vperm2i128, INS_vperm2i128, INS_vperm2i128, INS_vperm2i128, INS_vperm2i128, INS_vperm2i128, INS_vperm2i128, INS_vperm2i128, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2, Permute4x64, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpermq, INS_vpermq, INS_invalid, INS_vpermpd}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2, PermuteVar8x32, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpermd, INS_vpermd, INS_invalid, INS_invalid, INS_vpermps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport) +HARDWARE_INTRINSIC(AVX2, PackSignedSaturate, 32, 2, {INS_packsswb, INS_invalid, INS_packssdw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, PackUnsignedSaturate, 32, 2, {INS_invalid, INS_packuswb, INS_invalid, INS_packusdw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, ShiftLeftLogical, 32, 2, {INS_invalid, INS_invalid, INS_psllw, INS_psllw, INS_pslld, INS_pslld, INS_psllq, INS_psllq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2, ShiftLeftLogical128BitLane, 32, 2, {INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_pslldq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2, ShiftLeftLogicalVariable, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpsllvd, INS_vpsllvd, INS_vpsllvq, INS_vpsllvq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, ShiftRightArithmetic, 32, 2, {INS_invalid, INS_invalid, INS_psraw, INS_invalid, INS_psrad, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2, ShiftRightArithmeticVariable, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpsravd, INS_vpsravd, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, ShiftRightLogical, 32, 2, {INS_invalid, INS_invalid, INS_psrlw, INS_psrlw, INS_psrld, INS_psrld, INS_psrlq, INS_psrlq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_MaybeIMM|HW_Flag_NoJmpTableIMM|HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2, ShiftRightLogical128BitLane, 32, 2, {INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_psrldq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2, ShiftRightLogicalVariable, -1, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpsrlvd, INS_vpsrlvd, INS_vpsrlvq, INS_vpsrlvq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, Shuffle, 32, 2, {INS_pshufb, INS_pshufb, INS_invalid, INS_invalid, INS_pshufd, INS_pshufd, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_MaybeIMM) +HARDWARE_INTRINSIC(AVX2, ShuffleHigh, 32, 2, {INS_invalid, INS_invalid, INS_pshufhw, INS_pshufhw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2, ShuffleLow, 32, 2, {INS_invalid, INS_invalid, INS_pshuflw, INS_pshuflw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AVX2, Sign, 32, 2, {INS_psignb, INS_invalid, INS_psignw, INS_invalid, INS_psignd, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, SumAbsoluteDifferences, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_psadbw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, Subtract, 32, 2, {INS_psubb, INS_psubb, INS_psubw, INS_psubw, INS_psubd, INS_psubd, INS_psubq, INS_psubq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, SubtractSaturate, 32, 2, {INS_psubsb, INS_psubusb, INS_psubsw, INS_psubusw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, UnpackHigh, 32, 2, {INS_punpckhbw, INS_punpckhbw, INS_punpckhwd, INS_punpckhwd, INS_punpckhdq, INS_punpckhdq, INS_punpckhqdq, INS_punpckhqdq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, UnpackLow, 32, 2, {INS_punpcklbw, INS_punpcklbw, INS_punpcklwd, INS_punpcklwd, INS_punpckldq, INS_punpckldq, INS_punpcklqdq, INS_punpcklqdq, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AVX2, Xor, 32, 2, {INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_Commutative) + +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // AES Intrinsics -HARDWARE_INTRINSIC(AES_Decrypt, "Decrypt", AES, -1, 16, 2, {INS_invalid, INS_aesdec, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AES_DecryptLast, "DecryptLast", AES, -1, 16, 2, {INS_invalid, INS_aesdeclast, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AES_Encrypt, "Encrypt", AES, -1, 16, 2, {INS_invalid, INS_aesenc, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AES_EncryptLast, "EncryptLast", AES, -1, 16, 2, {INS_invalid, INS_aesenclast, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AES_InverseMixColumns, "InverseMixColumns", AES, -1, 16, 1, {INS_invalid, INS_aesimc, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(AES_KeygenAssist, "KeygenAssist", AES, -1, 16, 2, {INS_invalid, INS_aeskeygenassist,INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(AES, Decrypt, 16, 2, {INS_invalid, INS_aesdec, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AES, DecryptLast, 16, 2, {INS_invalid, INS_aesdeclast, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AES, Encrypt, 16, 2, {INS_invalid, INS_aesenc, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AES, EncryptLast, 16, 2, {INS_invalid, INS_aesenclast, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AES, InverseMixColumns, 16, 1, {INS_invalid, INS_aesimc, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(AES, KeygenAssist, 16, 2, {INS_invalid, INS_aeskeygenassist, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // BMI1 Intrinsics -HARDWARE_INTRINSIC(BMI1_AndNot, "AndNot", BMI1, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_andn, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(BMI1_ExtractLowestSetBit, "ExtractLowestSetBit", BMI1, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blsi, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(BMI1_GetMaskUpToLowestSetBit, "GetMaskUpToLowestSetBit", BMI1, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blsmsk, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(BMI1_ResetLowestSetBit, "ResetLowestSetBit", BMI1, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blsr, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(BMI1_TrailingZeroCount, "TrailingZeroCount", BMI1, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_tzcnt, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns) -HARDWARE_INTRINSIC(BMI1_BitFieldExtract, "BitFieldExtract", BMI1, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bextr, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns|HW_Flag_SpecialImport) +HARDWARE_INTRINSIC(BMI1, AndNot, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_andn, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(BMI1, ExtractLowestSetBit, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blsi, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(BMI1, GetMaskUpToLowestSetBit, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blsmsk, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(BMI1, ResetLowestSetBit, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blsr, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(BMI1, TrailingZeroCount, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_tzcnt, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns) +HARDWARE_INTRINSIC(BMI1, BitFieldExtract, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bextr, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns|HW_Flag_SpecialImport) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // BMI1 Intrinsics -HARDWARE_INTRINSIC(BMI1_X64_AndNot, "AndNot", BMI1_X64, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_andn, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(BMI1_X64_ExtractLowestSetBit, "ExtractLowestSetBit", BMI1_X64, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blsi, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(BMI1_X64_GetMaskUpToLowestSetBit, "GetMaskUpToLowestSetBit", BMI1_X64, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blsmsk, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(BMI1_X64_ResetLowestSetBit, "ResetLowestSetBit", BMI1_X64, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blsr, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(BMI1_X64_TrailingZeroCount, "TrailingZeroCount", BMI1_X64, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_tzcnt, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns) -HARDWARE_INTRINSIC(BMI1_X64_BitFieldExtract, "BitFieldExtract", BMI1_X64, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bextr, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns|HW_Flag_SpecialImport) +HARDWARE_INTRINSIC(BMI1_X64, AndNot, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_andn, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(BMI1_X64, ExtractLowestSetBit, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blsi, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(BMI1_X64, GetMaskUpToLowestSetBit, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blsmsk, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(BMI1_X64, ResetLowestSetBit, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_blsr, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(BMI1_X64, TrailingZeroCount, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_tzcnt, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns) +HARDWARE_INTRINSIC(BMI1_X64, BitFieldExtract, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bextr, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns|HW_Flag_SpecialImport) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // BMI2 Intrinsics -HARDWARE_INTRINSIC(BMI2_ParallelBitDeposit, "ParallelBitDeposit", BMI2, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pdep, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(BMI2_ParallelBitExtract, "ParallelBitExtract", BMI2, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pext, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(BMI2_ZeroHighBits, "ZeroHighBits", BMI2, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bzhi, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_SpecialImport) -HARDWARE_INTRINSIC(BMI2_MultiplyNoFlags, "MultiplyNoFlags", BMI2, -1, 0, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulx, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoContainment|HW_Flag_MaybeMemoryStore|HW_Flag_MultiIns|HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(BMI2, ParallelBitDeposit, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pdep, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(BMI2, ParallelBitExtract, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pext, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(BMI2, ZeroHighBits, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bzhi, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_SpecialImport) +HARDWARE_INTRINSIC(BMI2, MultiplyNoFlags, 0, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulx, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoContainment|HW_Flag_MaybeMemoryStore|HW_Flag_MultiIns|HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // BMI2 Intrinsics -HARDWARE_INTRINSIC(BMI2_X64_ParallelBitDeposit, "ParallelBitDeposit", BMI2_X64, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pdep, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(BMI2_X64_ParallelBitExtract, "ParallelBitExtract", BMI2_X64, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pext, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(BMI2_X64_ZeroHighBits, "ZeroHighBits", BMI2_X64, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bzhi, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_SpecialImport) -HARDWARE_INTRINSIC(BMI2_X64_MultiplyNoFlags, "MultiplyNoFlags", BMI2_X64, -1, 0, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulx, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoContainment|HW_Flag_MaybeMemoryStore|HW_Flag_MultiIns|HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(BMI2_X64, ParallelBitDeposit, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pdep, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(BMI2_X64, ParallelBitExtract, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pext, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(BMI2_X64, ZeroHighBits, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bzhi, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_SpecialImport) +HARDWARE_INTRINSIC(BMI2_X64, MultiplyNoFlags, 0, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulx, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoContainment|HW_Flag_MaybeMemoryStore|HW_Flag_MultiIns|HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // FMA Intrinsics -HARDWARE_INTRINSIC(FMA_MultiplyAdd, "MultiplyAdd", FMA, -1, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfmadd213ps, INS_vfmadd213pd}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(FMA_MultiplyAddNegated, "MultiplyAddNegated", FMA, -1, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfnmadd213ps, INS_vfnmadd213pd}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(FMA_MultiplyAddNegatedScalar, "MultiplyAddNegatedScalar", FMA, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfnmadd213ss, INS_vfnmadd213sd}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen|HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(FMA_MultiplyAddScalar, "MultiplyAddScalar", FMA, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfmadd213ss, INS_vfmadd213sd}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen|HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(FMA_MultiplyAddSubtract, "MultiplyAddSubtract", FMA, -1, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfmaddsub213ps, INS_vfmaddsub213pd}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(FMA_MultiplySubtract, "MultiplySubtract", FMA, -1, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfmsub213ps, INS_vfmsub213pd}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(FMA_MultiplySubtractAdd, "MultiplySubtractAdd", FMA, -1, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfmsubadd213ps, INS_vfmsubadd213pd}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(FMA_MultiplySubtractNegated, "MultiplySubtractNegated", FMA, -1, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfnmsub213ps, INS_vfnmsub213pd}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen|HW_Flag_UnfixedSIMDSize) -HARDWARE_INTRINSIC(FMA_MultiplySubtractScalar, "MultiplySubtractScalar", FMA, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfmsub213ss, INS_vfmsub213sd}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen|HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(FMA_MultiplySubtractNegatedScalar, "MultiplySubtractNegatedScalar", FMA, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfnmsub213ss, INS_vfnmsub213sd}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen|HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(FMA, MultiplyAdd, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfmadd213ps, INS_vfmadd213pd}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(FMA, MultiplyAddNegated, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfnmadd213ps, INS_vfnmadd213pd}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(FMA, MultiplyAddNegatedScalar, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfnmadd213ss, INS_vfnmadd213sd}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen|HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(FMA, MultiplyAddScalar, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfmadd213ss, INS_vfmadd213sd}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen|HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(FMA, MultiplyAddSubtract, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfmaddsub213ps, INS_vfmaddsub213pd}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(FMA, MultiplySubtract, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfmsub213ps, INS_vfmsub213pd}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(FMA, MultiplySubtractAdd, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfmsubadd213ps, INS_vfmsubadd213pd}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(FMA, MultiplySubtractNegated, -1, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfnmsub213ps, INS_vfnmsub213pd}, HW_Category_SimpleSIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(FMA, MultiplySubtractScalar, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfmsub213ss, INS_vfmsub213sd}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen|HW_Flag_CopyUpperBits) +HARDWARE_INTRINSIC(FMA, MultiplySubtractNegatedScalar, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vfnmsub213ss, INS_vfnmsub213sd}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen|HW_Flag_CopyUpperBits) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // LZCNT Intrinsics -HARDWARE_INTRINSIC(LZCNT_LeadingZeroCount, "LeadingZeroCount", LZCNT, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_lzcnt, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns) +HARDWARE_INTRINSIC(LZCNT, LeadingZeroCount, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_lzcnt, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // LZCNT Intrinsics -HARDWARE_INTRINSIC(LZCNT_X64_LeadingZeroCount, "LeadingZeroCount", LZCNT_X64, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_lzcnt, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns) +HARDWARE_INTRINSIC(LZCNT_X64, LeadingZeroCount, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_lzcnt, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // PCLMULQDQ Intrinsics -HARDWARE_INTRINSIC(PCLMULQDQ_CarrylessMultiply, "CarrylessMultiply", PCLMULQDQ, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pclmulqdq, INS_pclmulqdq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) +HARDWARE_INTRINSIC(PCLMULQDQ, CarrylessMultiply, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_pclmulqdq, INS_pclmulqdq, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // POPCNT Intrinsics -HARDWARE_INTRINSIC(POPCNT_PopCount, "PopCount", POPCNT, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_popcnt, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns) +HARDWARE_INTRINSIC(POPCNT, PopCount, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_popcnt, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** -// Intrinsic ID Function name ISA ival SIMD size NumArg instructions Category Flags -// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // POPCNT Intrinsics -HARDWARE_INTRINSIC(POPCNT_X64_PopCount, "PopCount", POPCNT_X64, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_popcnt, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns) +HARDWARE_INTRINSIC(POPCNT_X64, PopCount, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_popcnt, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_MultiIns) +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** +// ISA Function name SIMD size NumArg Instructions Category Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // Special intrinsics that are generated during lowering -HARDWARE_INTRINSIC(SSE_COMISS, "COMISS", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE_UCOMISS, "UCOMISS", SSE, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_COMISD, "COMISD", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_UCOMISD, "UCOMISD", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE41_PTEST, "PTEST", SSE41, -1, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(AVX_PTEST, "PTEST", AVX, -1, 0, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_vtestps, INS_vtestpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, COMISS, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE, UCOMISS, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomiss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, COMISD, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_comisd}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2, UCOMISD, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_ucomisd}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE41, PTEST, 16, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX, PTEST, 0, 2, {INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_ptest, INS_vtestps, INS_vtestpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) #endif // FEATURE_HW_INTRINSIC diff --git a/src/coreclr/src/jit/hwintrinsicxarch.cpp b/src/coreclr/src/jit/hwintrinsicxarch.cpp index c4f3748af47b29..214ce21496f5a7 100644 --- a/src/coreclr/src/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/src/jit/hwintrinsicxarch.cpp @@ -19,6 +19,8 @@ static CORINFO_InstructionSet X64VersionOfIsa(CORINFO_InstructionSet isa) { switch (isa) { + case InstructionSet_X86Base: + return InstructionSet_X86Base_X64; case InstructionSet_SSE: return InstructionSet_SSE_X64; case InstructionSet_SSE2: @@ -134,12 +136,16 @@ static CORINFO_InstructionSet lookupInstructionSet(const char* className) { return InstructionSet_LZCNT; } + else if (strcmp(className, "X86Base") == 0) + { + return InstructionSet_X86Base; + } return InstructionSet_ILLEGAL; } //------------------------------------------------------------------------ -// lookupIsa: Gets the InstructionSet for a given class name and enclsoing class name +// lookupIsa: Gets the InstructionSet for a given class name and enclosing class name // // Arguments: // className -- The name of the class associated with the InstructionSet to lookup @@ -202,13 +208,15 @@ int HWIntrinsicInfo::lookupImmUpperBound(NamedIntrinsic id) // isInImmRange: Check if ival is valid for the intrinsic // // Arguments: -// id -- The NamedIntrinsic associated with the HWIntrinsic to lookup -// ival -- the imm value to be checked +// id -- the NamedIntrinsic associated with the HWIntrinsic to lookup +// ival -- the imm value to be checked +// simdType -- vector size +// baseType -- base type of the Vector64/128 // // Return Value: // true if ival is valid for the intrinsic // -bool HWIntrinsicInfo::isInImmRange(NamedIntrinsic id, int ival) +bool HWIntrinsicInfo::isInImmRange(NamedIntrinsic id, int ival, int simdSize, var_types baseType) { assert(HWIntrinsicInfo::lookupCategory(id) == HW_Category_IMM); @@ -245,6 +253,95 @@ bool HWIntrinsicInfo::isAVX2GatherIntrinsic(NamedIntrinsic id) } } +//------------------------------------------------------------------------ +// lookupFloatComparisonModeForSwappedArgs: Get the floating-point comparison +// mode to use when the operands are swapped. +// +// Arguments: +// comparison -- The comparison mode used for (op1, op2) +// +// Return Value: +// The comparison mode to use for (op2, op1) +// +FloatComparisonMode HWIntrinsicInfo::lookupFloatComparisonModeForSwappedArgs(FloatComparisonMode comparison) +{ + switch (comparison) + { + // These comparison modes are the same even if the operands are swapped + + case FloatComparisonMode::OrderedEqualNonSignaling: + return FloatComparisonMode::OrderedEqualNonSignaling; + case FloatComparisonMode::UnorderedNonSignaling: + return FloatComparisonMode::UnorderedNonSignaling; + case FloatComparisonMode::UnorderedNotEqualNonSignaling: + return FloatComparisonMode::UnorderedNotEqualNonSignaling; + case FloatComparisonMode::OrderedNonSignaling: + return FloatComparisonMode::OrderedNonSignaling; + case FloatComparisonMode::UnorderedEqualNonSignaling: + return FloatComparisonMode::UnorderedEqualNonSignaling; + case FloatComparisonMode::OrderedFalseNonSignaling: + return FloatComparisonMode::OrderedFalseNonSignaling; + case FloatComparisonMode::OrderedNotEqualNonSignaling: + return FloatComparisonMode::OrderedNotEqualNonSignaling; + case FloatComparisonMode::UnorderedTrueNonSignaling: + return FloatComparisonMode::UnorderedTrueNonSignaling; + case FloatComparisonMode::OrderedEqualSignaling: + return FloatComparisonMode::OrderedEqualSignaling; + case FloatComparisonMode::UnorderedSignaling: + return FloatComparisonMode::UnorderedSignaling; + case FloatComparisonMode::UnorderedNotEqualSignaling: + return FloatComparisonMode::UnorderedNotEqualSignaling; + case FloatComparisonMode::OrderedSignaling: + return FloatComparisonMode::OrderedSignaling; + case FloatComparisonMode::UnorderedEqualSignaling: + return FloatComparisonMode::UnorderedEqualSignaling; + case FloatComparisonMode::OrderedFalseSignaling: + return FloatComparisonMode::OrderedFalseSignaling; + case FloatComparisonMode::OrderedNotEqualSignaling: + return FloatComparisonMode::OrderedNotEqualSignaling; + case FloatComparisonMode::UnorderedTrueSignaling: + return FloatComparisonMode::UnorderedTrueSignaling; + + // These comparison modes need a different mode if the operands are swapped + + case FloatComparisonMode::OrderedLessThanSignaling: + return FloatComparisonMode::OrderedGreaterThanSignaling; + case FloatComparisonMode::OrderedLessThanOrEqualSignaling: + return FloatComparisonMode::OrderedGreaterThanOrEqualSignaling; + case FloatComparisonMode::UnorderedNotLessThanSignaling: + return FloatComparisonMode::UnorderedNotGreaterThanSignaling; + case FloatComparisonMode::UnorderedNotLessThanOrEqualSignaling: + return FloatComparisonMode::UnorderedNotGreaterThanOrEqualSignaling; + case FloatComparisonMode::UnorderedNotGreaterThanOrEqualSignaling: + return FloatComparisonMode::UnorderedNotLessThanOrEqualSignaling; + case FloatComparisonMode::UnorderedNotGreaterThanSignaling: + return FloatComparisonMode::UnorderedNotLessThanSignaling; + case FloatComparisonMode::OrderedGreaterThanOrEqualSignaling: + return FloatComparisonMode::OrderedLessThanOrEqualSignaling; + case FloatComparisonMode::OrderedGreaterThanSignaling: + return FloatComparisonMode::OrderedLessThanSignaling; + case FloatComparisonMode::OrderedLessThanNonSignaling: + return FloatComparisonMode::OrderedGreaterThanNonSignaling; + case FloatComparisonMode::OrderedLessThanOrEqualNonSignaling: + return FloatComparisonMode::OrderedGreaterThanOrEqualNonSignaling; + case FloatComparisonMode::UnorderedNotLessThanNonSignaling: + return FloatComparisonMode::UnorderedNotGreaterThanNonSignaling; + case FloatComparisonMode::UnorderedNotLessThanOrEqualNonSignaling: + return FloatComparisonMode::UnorderedNotGreaterThanOrEqualNonSignaling; + case FloatComparisonMode::UnorderedNotGreaterThanOrEqualNonSignaling: + return FloatComparisonMode::UnorderedNotLessThanOrEqualNonSignaling; + case FloatComparisonMode::UnorderedNotGreaterThanNonSignaling: + return FloatComparisonMode::UnorderedNotLessThanNonSignaling; + case FloatComparisonMode::OrderedGreaterThanOrEqualNonSignaling: + return FloatComparisonMode::OrderedLessThanOrEqualNonSignaling; + case FloatComparisonMode::OrderedGreaterThanNonSignaling: + return FloatComparisonMode::OrderedLessThanNonSignaling; + + default: + unreached(); + } +} + //------------------------------------------------------------------------ // isFullyImplementedIsa: Gets a value that indicates whether the InstructionSet is fully implemented // @@ -283,6 +380,8 @@ bool HWIntrinsicInfo::isFullyImplementedIsa(CORINFO_InstructionSet isa) case InstructionSet_SSE42_X64: case InstructionSet_Vector128: case InstructionSet_Vector256: + case InstructionSet_X86Base: + case InstructionSet_X86Base_X64: { return true; } @@ -314,6 +413,8 @@ bool HWIntrinsicInfo::isScalarIsa(CORINFO_InstructionSet isa) case InstructionSet_LZCNT_X64: case InstructionSet_POPCNT: case InstructionSet_POPCNT_X64: + case InstructionSet_X86Base: + case InstructionSet_X86Base_X64: { return true; } @@ -368,22 +469,26 @@ GenTree* Compiler::impNonConstFallback(NamedIntrinsic intrinsic, var_types simdT // intrinsic -- id of the intrinsic function. // clsHnd -- class handle containing the intrinsic function. // method -- method handle of the intrinsic function. -// sig -- signature of the intrinsic call -// +// sig -- signature of the intrinsic call. +// baseType -- generic argument of the intrinsic. +// retType -- return type of the intrinsic. // Return Value: // the expanded intrinsic. // GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* sig) + CORINFO_SIG_INFO* sig, + var_types baseType, + var_types retType, + unsigned simdSize) { // other intrinsics need special importation switch (HWIntrinsicInfo::lookupIsa(intrinsic)) { case InstructionSet_Vector128: case InstructionSet_Vector256: - return impBaseIntrinsic(intrinsic, clsHnd, method, sig); + return impBaseIntrinsic(intrinsic, clsHnd, method, sig, baseType, retType, simdSize); case InstructionSet_SSE: return impSSEIntrinsic(intrinsic, method, sig); case InstructionSet_SSE2: @@ -408,60 +513,29 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // Arguments: // intrinsic -- id of the intrinsic function. // method -- method handle of the intrinsic function. -// sig -- signature of the intrinsic call -// +// sig -- signature of the intrinsic call. +// baseType -- generic argument of the intrinsic. +// retType -- return type of the intrinsic. // Return Value: // the expanded intrinsic. // GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* sig) + CORINFO_SIG_INFO* sig, + var_types baseType, + var_types retType, + unsigned simdSize) { GenTree* retNode = nullptr; GenTree* op1 = nullptr; + GenTree* op2 = nullptr; if (!featureSIMD) { return nullptr; } - unsigned simdSize = 0; - var_types baseType = TYP_UNKNOWN; - var_types retType = JITtype2varType(sig->retType); - - assert(!sig->hasThis()); - - if (HWIntrinsicInfo::BaseTypeFromFirstArg(intrinsic)) - { - baseType = getBaseTypeAndSizeOfSIMDType(info.compCompHnd->getArgClass(sig, sig->args), &simdSize); - - if (retType == TYP_STRUCT) - { - unsigned retSimdSize = 0; - var_types retBasetype = getBaseTypeAndSizeOfSIMDType(sig->retTypeClass, &retSimdSize); - if (!varTypeIsArithmetic(retBasetype)) - { - return nullptr; - } - retType = getSIMDTypeForSize(retSimdSize); - } - } - else if (retType == TYP_STRUCT) - { - baseType = getBaseTypeAndSizeOfSIMDType(sig->retTypeClass, &simdSize); - retType = getSIMDTypeForSize(simdSize); - } - else - { - baseType = getBaseTypeAndSizeOfSIMDType(clsHnd, &simdSize); - } - - if (!varTypeIsArithmetic(baseType)) - { - return nullptr; - } - switch (intrinsic) { case NI_Vector256_As: @@ -516,7 +590,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, if (getSIMDVectorRegisterByteLength() == YMM_REGSIZE_BYTES) { // Vector is TYP_SIMD32, so we should treat this as a call to Vector128.ToVector256 - return impBaseIntrinsic(NI_Vector128_ToVector256, clsHnd, method, sig); + return impBaseIntrinsic(NI_Vector128_ToVector256, clsHnd, method, sig, baseType, retType, simdSize); } assert(getSIMDVectorRegisterByteLength() == XMM_REGSIZE_BYTES); @@ -557,6 +631,11 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, case NI_Vector128_AsVector128: { assert(sig->numArgs == 1); + assert(HWIntrinsicInfo::BaseTypeFromFirstArg(intrinsic)); + + var_types baseTypeOfIntrinsic = + getBaseTypeAndSizeOfSIMDType(info.compCompHnd->getArgClass(sig, sig->args), &simdSize); + assert(baseType == baseTypeOfIntrinsic); switch (getSIMDTypeForSize(simdSize)) { @@ -584,7 +663,7 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, case TYP_SIMD32: { // Vector is TYP_SIMD32, so we should treat this as a call to Vector256.GetLower - return impBaseIntrinsic(NI_Vector256_GetLower, clsHnd, method, sig); + return impBaseIntrinsic(NI_Vector256_GetLower, clsHnd, method, sig, baseType, retType, simdSize); } default: @@ -623,20 +702,20 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, if (intrinsic == NI_Vector256_AsVector) { - return impBaseIntrinsic(NI_Vector256_GetLower, clsHnd, method, sig); + return impBaseIntrinsic(NI_Vector256_GetLower, clsHnd, method, sig, baseType, retType, simdSize); } else { assert(intrinsic == NI_Vector256_AsVector256); - return impBaseIntrinsic(NI_Vector128_ToVector256, clsHnd, method, sig); + return impBaseIntrinsic(NI_Vector128_ToVector256, clsHnd, method, sig, baseType, retType, simdSize); } } break; } - case NI_Vector128_Count: - case NI_Vector256_Count: + case NI_Vector128_get_Count: + case NI_Vector256_get_Count: { assert(sig->numArgs == 0); @@ -646,6 +725,70 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector128_Create: + case NI_Vector256_Create: + { +#if defined(TARGET_X86) + if (varTypeIsLong(baseType)) + { + // TODO-XARCH-CQ: It may be beneficial to emit the movq + // instruction, which takes a 64-bit memory address and + // works on 32-bit x86 systems. + break; + } +#endif // TARGET_X86 + + // We shouldn't handle this as an intrinsic if the + // respective ISAs have been disabled by the user. + + if (intrinsic == NI_Vector256_Create) + { + if (!compExactlyDependsOn(InstructionSet_AVX)) + { + break; + } + } + else if (baseType == TYP_FLOAT) + { + if (!compExactlyDependsOn(InstructionSet_SSE)) + { + break; + } + } + else if (!compExactlyDependsOn(InstructionSet_SSE2)) + { + break; + } + + if (sig->numArgs == 1) + { + op1 = impPopStack().val; + retNode = gtNewSimdHWIntrinsicNode(retType, op1, intrinsic, baseType, simdSize); + } + else if (sig->numArgs == 2) + { + op2 = impPopStack().val; + op1 = impPopStack().val; + retNode = gtNewSimdHWIntrinsicNode(retType, op1, op2, intrinsic, baseType, simdSize); + } + else + { + assert(sig->numArgs >= 3); + + GenTreeArgList* tmp = nullptr; + + for (unsigned i = 0; i < sig->numArgs; i++) + { + tmp = gtNewArgList(impPopStack().val); + tmp->gtOp2 = op1; + op1 = tmp; + } + + retNode = gtNewSimdHWIntrinsicNode(retType, op1, intrinsic, baseType, simdSize); + } + break; + } + case NI_Vector128_CreateScalarUnsafe: { assert(sig->numArgs == 1); @@ -695,7 +838,8 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, break; } - case NI_Vector128_Zero: + case NI_Vector128_get_Zero: + case NI_Vector128_get_AllBitsSet: { assert(sig->numArgs == 0); @@ -740,7 +884,8 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, break; } - case NI_Vector256_Zero: + case NI_Vector256_get_Zero: + case NI_Vector256_get_AllBitsSet: { assert(sig->numArgs == 0); @@ -1173,12 +1318,11 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig) { - GenTree* retNode = nullptr; - GenTree* op1 = nullptr; - GenTree* op2 = nullptr; - GenTree* op3 = nullptr; - GenTree* op4 = nullptr; - int simdSize = HWIntrinsicInfo::lookupSimdSize(this, intrinsic, sig); + GenTree* retNode = nullptr; + GenTree* op1 = nullptr; + GenTree* op2 = nullptr; + int simdSize = HWIntrinsicInfo::lookupSimdSize(this, intrinsic, sig); + var_types baseType = TYP_UNKNOWN; // The Prefetch and StoreFence intrinsics don't take any SIMD operands // and have a simdSize of 0 @@ -1186,6 +1330,40 @@ GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HAND switch (intrinsic) { + case NI_SSE_CompareScalarGreaterThan: + case NI_SSE_CompareScalarGreaterThanOrEqual: + case NI_SSE_CompareScalarNotGreaterThan: + case NI_SSE_CompareScalarNotGreaterThanOrEqual: + { + assert(sig->numArgs == 2); + op2 = impSIMDPopStack(TYP_SIMD16); + op1 = impSIMDPopStack(TYP_SIMD16); + baseType = getBaseTypeOfSIMDType(sig->retTypeSigClass); + assert(baseType == TYP_FLOAT); + + if (compOpportunisticallyDependsOn(InstructionSet_AVX)) + { + // These intrinsics are "special import" because the non-AVX path isn't directly + // hardware supported. Instead, they start with "swapped operands" and we fix that here. + + FloatComparisonMode comparison = + static_cast(HWIntrinsicInfo::lookupIval(intrinsic, true)); + retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, gtNewIconNode(static_cast(comparison)), + NI_AVX_CompareScalar, baseType, simdSize); + } + else + { + GenTree* clonedOp1 = nullptr; + op1 = impCloneExpr(op1, &clonedOp1, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op1 for Sse.CompareScalarGreaterThan")); + + retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, op1, intrinsic, baseType, simdSize); + retNode = + gtNewSimdHWIntrinsicNode(TYP_SIMD16, clonedOp1, retNode, NI_SSE_MoveScalar, baseType, simdSize); + } + break; + } + case NI_SSE_Prefetch0: case NI_SSE_Prefetch1: case NI_SSE_Prefetch2: @@ -1218,7 +1396,7 @@ GenTree* Compiler::impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HAN GenTree* op2 = nullptr; int ival = -1; int simdSize = HWIntrinsicInfo::lookupSimdSize(this, intrinsic, sig); - var_types baseType = TYP_UNKNOWN; + var_types baseType = getBaseTypeOfSIMDType(sig->retTypeSigClass); var_types retType = TYP_UNKNOWN; // The fencing intrinsics don't take any operands and simdSize is 0 @@ -1229,20 +1407,35 @@ GenTree* Compiler::impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HAN switch (intrinsic) { - case NI_SSE2_CompareLessThan: + case NI_SSE2_CompareScalarGreaterThan: + case NI_SSE2_CompareScalarGreaterThanOrEqual: + case NI_SSE2_CompareScalarNotGreaterThan: + case NI_SSE2_CompareScalarNotGreaterThanOrEqual: { assert(sig->numArgs == 2); - op2 = impSIMDPopStack(TYP_SIMD16); - op1 = impSIMDPopStack(TYP_SIMD16); - baseType = getBaseTypeOfSIMDType(sig->retTypeSigClass); - if (baseType == TYP_DOUBLE) + op2 = impSIMDPopStack(TYP_SIMD16); + op1 = impSIMDPopStack(TYP_SIMD16); + assert(baseType == TYP_DOUBLE); + + if (compOpportunisticallyDependsOn(InstructionSet_AVX)) { - retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, intrinsic, baseType, simdSize); + // These intrinsics are "special import" because the non-AVX path isn't directly + // hardware supported. Instead, they start with "swapped operands" and we fix that here. + + FloatComparisonMode comparison = + static_cast(HWIntrinsicInfo::lookupIval(intrinsic, true)); + retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, gtNewIconNode(static_cast(comparison)), + NI_AVX_CompareScalar, baseType, simdSize); } else { + GenTree* clonedOp1 = nullptr; + op1 = impCloneExpr(op1, &clonedOp1, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op1 for Sse2.CompareScalarGreaterThan")); + + retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, op1, intrinsic, baseType, simdSize); retNode = - gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, op1, NI_SSE2_CompareGreaterThan, baseType, simdSize); + gtNewSimdHWIntrinsicNode(TYP_SIMD16, clonedOp1, retNode, NI_SSE2_MoveScalar, baseType, simdSize); } break; } @@ -1335,7 +1528,7 @@ GenTree* Compiler::impAvxOrAvx2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHO GenTree* opList = new (this, GT_LIST) GenTreeArgList(op1, gtNewArgList(op2, op3, op4, op5)); retNode = new (this, GT_HWINTRINSIC) GenTreeHWIntrinsic(retType, opList, intrinsic, baseType, simdSize); - retNode->AsHWIntrinsic()->gtIndexBaseType = indexbaseType; + retNode->AsHWIntrinsic()->SetOtherBaseType(indexbaseType); break; } diff --git a/src/coreclr/src/jit/importer.cpp b/src/coreclr/src/jit/importer.cpp index 76b4dd9a706ab4..d5bf9bf745541d 100644 --- a/src/coreclr/src/jit/importer.cpp +++ b/src/coreclr/src/jit/importer.cpp @@ -1173,8 +1173,8 @@ GenTree* Compiler::impAssignStructPtr(GenTree* destAddr, ilOffset = impCurStmtOffs; } - assert(src->OperIs(GT_LCL_VAR, GT_FIELD, GT_IND, GT_OBJ, GT_CALL, GT_MKREFANY, GT_RET_EXPR, GT_COMMA) || - (src->TypeGet() != TYP_STRUCT && (src->OperIsSimdOrHWintrinsic() || src->OperIs(GT_LCL_FLD)))); + assert(src->OperIs(GT_LCL_VAR, GT_LCL_FLD, GT_FIELD, GT_IND, GT_OBJ, GT_CALL, GT_MKREFANY, GT_RET_EXPR, GT_COMMA) || + (src->TypeGet() != TYP_STRUCT && src->OperIsSimdOrHWintrinsic())); var_types asgType = src->TypeGet(); @@ -1199,8 +1199,11 @@ GenTree* Compiler::impAssignStructPtr(GenTree* destAddr, var_types returnType = (var_types)src->AsCall()->gtReturnType; - // We won't use a return buffer, so change the type of src->gtType to 'returnType' - src->gtType = genActualType(returnType); + if (compDoOldStructRetyping()) + { + // We're not using a return buffer, so if we're retyping we'll change the type of 'src' to 'returnTYpe'. + src->gtType = genActualType(returnType); + } // First we try to change this to "LclVar/LclFld = call" // @@ -1280,17 +1283,25 @@ GenTree* Compiler::impAssignStructPtr(GenTree* destAddr, else { // Case of inline method returning a struct in one or more registers. - // - var_types returnType = (var_types)call->gtReturnType; - // We won't need a return buffer - asgType = returnType; - src->gtType = genActualType(returnType); - call->gtType = src->gtType; + if (compDoOldStructRetyping()) + { + var_types returnType = (var_types)call->gtReturnType; + asgType = returnType; + src->gtType = genActualType(returnType); + call->gtType = src->gtType; + } + else + { + asgType = src->gtType; + } - // !!! The destination could be on stack. !!! - // This flag will let us choose the correct write barrier. - destFlags = GTF_IND_TGTANYWHERE; + if ((destAddr->gtOper != GT_ADDR) || (destAddr->AsOp()->gtOp1->gtOper != GT_LCL_VAR)) + { + // !!! The destination could be on stack. !!! + // This flag will let us choose the correct write barrier. + destFlags = GTF_IND_TGTANYWHERE; + } } } else if (src->OperIsBlk()) @@ -1933,11 +1944,6 @@ GenTree* Compiler::impMethodPointer(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORI { op1->AsFptrVal()->gtEntryPoint = pCallInfo->codePointerLookup.constLookup; } - else - { - op1->AsFptrVal()->gtEntryPoint.addr = nullptr; - op1->AsFptrVal()->gtEntryPoint.accessType = IAT_VALUE; - } #endif break; @@ -1980,12 +1986,13 @@ GenTree* Compiler::getRuntimeContextTree(CORINFO_RUNTIME_LOOKUP_KIND kind) // Collectible types requires that for shared generic code, if we use the generic context parameter // that we report it. (This is a conservative approach, we could detect some cases particularly when the // context parameter is this that we don't need the eager reporting logic.) - lvaGenericsContextUseCount++; + lvaGenericsContextInUse = true; if (kind == CORINFO_LOOKUP_THISOBJ) { // this Object ctxTree = gtNewLclvNode(info.compThisArg, TYP_REF); + ctxTree->gtFlags |= GTF_VAR_CONTEXT; // Vtable pointer of this object ctxTree = gtNewOperNode(GT_IND, TYP_I_IMPL, ctxTree); @@ -1997,6 +2004,7 @@ GenTree* Compiler::getRuntimeContextTree(CORINFO_RUNTIME_LOOKUP_KIND kind) assert(kind == CORINFO_LOOKUP_METHODPARAM || kind == CORINFO_LOOKUP_CLASSPARAM); ctxTree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL); // Exact method descriptor as passed in as last arg + ctxTree->gtFlags |= GTF_VAR_CONTEXT; } return ctxTree; } @@ -2041,11 +2049,7 @@ GenTree* Compiler::impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken gtNewCallArgs(ctxTree), &pLookup->lookupKind); } #endif - GenTree* argNode = - gtNewIconEmbHndNode(pRuntimeLookup->signature, nullptr, GTF_ICON_TOKEN_HDL, compileTimeHandle); - GenTreeCall::Use* helperArgs = gtNewCallArgs(ctxTree, argNode); - - return gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, helperArgs); + return gtNewRuntimeLookupHelperCallNode(pRuntimeLookup, ctxTree, compileTimeHandle); } // Slot pointer @@ -3474,33 +3478,43 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, { ni = lookupNamedIntrinsic(method); -#ifdef FEATURE_HW_INTRINSICS + // We specially support the following on all platforms to allow for dead + // code optimization and to more generally support recursive intrinsics. + if (ni == NI_IsSupported_True) { + assert(sig->numArgs == 0); return gtNewIconNode(true); } if (ni == NI_IsSupported_False) { + assert(sig->numArgs == 0); return gtNewIconNode(false); } if (ni == NI_Throw_PlatformNotSupportedException) { - return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand); + return impUnsupportedNamedIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand); } +#ifdef FEATURE_HW_INTRINSICS if ((ni > NI_HW_INTRINSIC_START) && (ni < NI_HW_INTRINSIC_END)) { GenTree* hwintrinsic = impHWIntrinsic(ni, clsHnd, method, sig, mustExpand); if (mustExpand && (hwintrinsic == nullptr)) { - return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_NOT_IMPLEMENTED, method, sig, mustExpand); + return impUnsupportedNamedIntrinsic(CORINFO_HELP_THROW_NOT_IMPLEMENTED, method, sig, mustExpand); } return hwintrinsic; } + + if ((ni > NI_SIMD_AS_HWINTRINSIC_START) && (ni < NI_SIMD_AS_HWINTRINSIC_END)) + { + return impSimdAsHWIntrinsic(ni, clsHnd, method, sig, mustExpand); + } #endif // FEATURE_HW_INTRINSICS } } @@ -3526,10 +3540,24 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, assert(intrinsicID != CORINFO_INTRINSIC_StubHelpers_GetStubContextAddr); #endif + if (intrinsicID == CORINFO_INTRINSIC_StubHelpers_NextCallReturnAddress) + { + // For now we just avoid inlining anything into these methods since + // this intrinsic is only rarely used. We could do this better if we + // wanted to by trying to match which call is the one we need to get + // the return address of. + info.compHasNextCallRetAddr = true; + return new (this, GT_LABEL) GenTree(GT_LABEL, TYP_I_IMPL); + } + GenTree* retNode = nullptr; // Under debug and minopts, only expand what is required. - if (!mustExpand && opts.OptimizationDisabled()) + // NextCallReturnAddress intrinsic returns the return address of the next call. + // If that call is an intrinsic and is expanded, codegen for NextCallReturnAddress will fail. + // To avoid that we conservatively expand only required intrinsics in methods that call + // the NextCallReturnAddress intrinsic. + if (!mustExpand && (opts.OptimizationDisabled() || info.compHasNextCallRetAddr)) { *pIntrinsicID = CORINFO_INTRINSIC_Illegal; return retNode; @@ -3617,11 +3645,20 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, #endif // defined(TARGET_XARCH) || defined(TARGET_ARM64) case CORINFO_INTRINSIC_MemoryBarrier: + case CORINFO_INTRINSIC_MemoryBarrierLoad: assert(sig->numArgs == 0); op1 = new (this, GT_MEMORYBARRIER) GenTree(GT_MEMORYBARRIER, TYP_VOID); op1->gtFlags |= GTF_GLOB_REF | GTF_ASG; + + // On XARCH `CORINFO_INTRINSIC_MemoryBarrierLoad` fences need not be emitted. + // However, we still need to capture the effect on reordering. + if (intrinsicID == CORINFO_INTRINSIC_MemoryBarrierLoad) + { + op1->gtFlags |= GTF_MEMORYBARRIER_LOAD; + } + retNode = op1; break; @@ -4133,7 +4170,7 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, case NI_System_MathF_FusedMultiplyAdd: { #ifdef TARGET_XARCH - if (compExactlyDependsOn(InstructionSet_FMA)) + if (compExactlyDependsOn(InstructionSet_FMA) && supportSIMDTypes()) { assert(varTypeIsFloating(callType)); @@ -4240,7 +4277,8 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, if (mustExpand && (retNode == nullptr)) { - NO_WAY("JIT must expand the intrinsic!"); + assert(!"Unhandled must expand intrinsic, throwing PlatformNotSupportedException"); + return impUnsupportedNamedIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand); } // Optionally report if this intrinsic is special @@ -4363,7 +4401,7 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) } if (className != nullptr) { - JITDUMP("%s", className); + JITDUMP("%s.", className); } if (methodName != nullptr) { @@ -4431,7 +4469,7 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) } } } -#if defined(TARGET_XARCH) // We currently only support BSWAP on x86 +#if defined(TARGET_XARCH) || defined(TARGET_ARM64) else if (strcmp(namespaceName, "System.Buffers.Binary") == 0) { if ((strcmp(className, "BinaryPrimitives") == 0) && (strcmp(methodName, "ReverseEndianness") == 0)) @@ -4439,7 +4477,7 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) result = NI_System_Buffers_Binary_BinaryPrimitives_ReverseEndianness; } } -#endif // !defined(TARGET_XARCH) +#endif // defined(TARGET_XARCH) || defined(TARGET_ARM64) else if (strcmp(namespaceName, "System.Collections.Generic") == 0) { if ((strcmp(className, "EqualityComparer`1") == 0) && (strcmp(methodName, "get_Default") == 0)) @@ -4448,8 +4486,39 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) } } #ifdef FEATURE_HW_INTRINSICS + else if (strcmp(namespaceName, "System.Numerics") == 0) + { + CORINFO_SIG_INFO sig; + info.compCompHnd->getMethodSig(method, &sig); + + int sizeOfVectorT = getSIMDVectorRegisterByteLength(); + + result = SimdAsHWIntrinsicInfo::lookupId(&sig, className, methodName, enclosingClassName, sizeOfVectorT); + } +#endif // FEATURE_HW_INTRINSICS else if (strncmp(namespaceName, "System.Runtime.Intrinsics", 25) == 0) { + // We go down this path even when FEATURE_HW_INTRINSICS isn't enabled + // so we can specially handle IsSupported and recursive calls. + + // This is required to appropriately handle the intrinsics on platforms + // which don't support them. On such a platform methods like Vector64.Create + // will be seen as `Intrinsic` and `mustExpand` due to having a code path + // which is recursive. When such a path is hit we expect it to be handled by + // the importer and we fire an assert if it wasn't and in previous versions + // of the JIT would fail fast. This was changed to throw a PNSE instead but + // we still assert as most intrinsics should have been recognized/handled. + + // In order to avoid the assert, we specially handle the IsSupported checks + // (to better allow dead-code optimizations) and we explicitly throw a PNSE + // as we know that is the desired behavior for the HWIntrinsics when not + // supported. For cases like Vector64.Create, this is fine because it will + // be behind a relevant IsSupported check and will never be hit and the + // software fallback will be executed instead. + + CLANG_FORMAT_COMMENT_ANCHOR; + +#ifdef FEATURE_HW_INTRINSICS namespaceName += 25; const char* platformNamespaceName; @@ -4463,23 +4532,45 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) if ((namespaceName[0] == '\0') || (strcmp(namespaceName, platformNamespaceName) == 0)) { - result = HWIntrinsicInfo::lookupId(this, className, methodName, enclosingClassName); - } - else if (strcmp(methodName, "get_IsSupported") == 0) - { - return NI_IsSupported_False; + CORINFO_SIG_INFO sig; + info.compCompHnd->getMethodSig(method, &sig); + + result = HWIntrinsicInfo::lookupId(this, &sig, className, methodName, enclosingClassName); } - else +#endif // FEATURE_HW_INTRINSICS + + if (result == NI_Illegal) { - return gtIsRecursiveCall(method) ? NI_Throw_PlatformNotSupportedException : NI_Illegal; + if (strcmp(methodName, "get_IsSupported") == 0) + { + // This allows the relevant code paths to be dropped as dead code even + // on platforms where FEATURE_HW_INTRINSICS is not supported. + + result = NI_IsSupported_False; + } + else if (gtIsRecursiveCall(method)) + { + // For the framework itself, any recursive intrinsics will either be + // only supported on a single platform or will be guarded by a relevant + // IsSupported check so the throw PNSE will be valid or dropped. + + result = NI_Throw_PlatformNotSupportedException; + } } } -#endif // FEATURE_HW_INTRINSICS if (result == NI_Illegal) { JITDUMP("Not recognized\n"); } + else if (result == NI_IsSupported_False) + { + JITDUMP("Unsupported - return false"); + } + else if (result == NI_Throw_PlatformNotSupportedException) + { + JITDUMP("Unsupported - throw PlatformNotSupportedException"); + } else { JITDUMP("Recognized\n"); @@ -4487,6 +4578,50 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) return result; } +//------------------------------------------------------------------------ +// impUnsupportedNamedIntrinsic: Throws an exception for an unsupported named intrinsic +// +// Arguments: +// helper - JIT helper ID for the exception to be thrown +// method - method handle of the intrinsic function. +// sig - signature of the intrinsic call +// mustExpand - true if the intrinsic must return a GenTree*; otherwise, false +// +// Return Value: +// a gtNewMustThrowException if mustExpand is true; otherwise, nullptr +// +GenTree* Compiler::impUnsupportedNamedIntrinsic(unsigned helper, + CORINFO_METHOD_HANDLE method, + CORINFO_SIG_INFO* sig, + bool mustExpand) +{ + // We've hit some error case and may need to return a node for the given error. + // + // When `mustExpand=false`, we are attempting to inline the intrinsic directly into another method. In this + // scenario, we need to return `nullptr` so that a GT_CALL to the intrinsic is emitted instead. This is to + // ensure that everything continues to behave correctly when optimizations are enabled (e.g. things like the + // inliner may expect the node we return to have a certain signature, and the `MustThrowException` node won't + // match that). + // + // When `mustExpand=true`, we are in a GT_CALL to the intrinsic and are attempting to JIT it. This will generally + // be in response to an indirect call (e.g. done via reflection) or in response to an earlier attempt returning + // `nullptr` (under `mustExpand=false`). In that scenario, we are safe to return the `MustThrowException` node. + + if (mustExpand) + { + for (unsigned i = 0; i < sig->numArgs; i++) + { + impPopStack(); + } + + return gtNewMustThrowException(helper, JITtype2varType(sig->retType), sig->retTypeClass); + } + else + { + return nullptr; + } +} + /*****************************************************************************/ GenTree* Compiler::impArrayAccessIntrinsic( @@ -6738,9 +6873,16 @@ void Compiler::impPopArgsForUnmanagedCall(GenTree* call, CORINFO_SIG_INFO* sig) assert(thisPtr->TypeGet() == TYP_I_IMPL || thisPtr->TypeGet() == TYP_BYREF); } - for (GenTreeCall::Use& use : GenTreeCall::UseList(args)) + for (GenTreeCall::Use& argUse : GenTreeCall::UseList(args)) { - call->gtFlags |= use.GetNode()->gtFlags & GTF_GLOB_EFFECT; + // We should not be passing gc typed args to an unmanaged call. + GenTree* arg = argUse.GetNode(); + if (varTypeIsGC(arg->TypeGet())) + { + assert(!"*** invalid IL: gc type passed to unmanaged call"); + } + + call->gtFlags |= arg->gtFlags & GTF_GLOB_EFFECT; } } @@ -7423,14 +7565,6 @@ var_types Compiler::impImportCall(OPCODE opcode, sig = &calliSig; -#ifdef DEBUG - // We cannot lazily obtain the signature of a CALLI call because it has no method - // handle that we can use, so we need to save its full call signature here. - assert(call->AsCall()->callSig == nullptr); - call->AsCall()->callSig = new (this, CMK_CorSig) CORINFO_SIG_INFO; - *call->AsCall()->callSig = calliSig; -#endif // DEBUG - if ((sig->flags & CORINFO_SIGFLAG_FAT_CALL) != 0) { addFatPointerCandidate(call->AsCall()); @@ -7893,11 +8027,9 @@ var_types Compiler::impImportCall(OPCODE opcode, #endif // !FEATURE_VARARG #ifdef UNIX_X86_ABI - if (call->AsCall()->callSig == nullptr) - { - call->AsCall()->callSig = new (this, CMK_CorSig) CORINFO_SIG_INFO; - *call->AsCall()->callSig = *sig; - } + // On Unix x86 we usually use caller-cleaned convention. + if (!call->AsCall()->IsUnmanaged() && IsCallerPop(sig->callConv)) + call->gtFlags |= GTF_CALL_POP_ARGS; #endif // UNIX_X86_ABI if ((sig->callConv & CORINFO_CALLCONV_MASK) == CORINFO_CALLCONV_VARARG || @@ -7935,14 +8067,6 @@ var_types Compiler::impImportCall(OPCODE opcode, #endif eeGetCallSiteSig(pResolvedToken->token, pResolvedToken->tokenScope, pResolvedToken->tokenContext, sig); -#ifdef DEBUG - // We cannot lazily obtain the signature of a vararg call because using its method - // handle will give us only the declared argument list, not the full argument list. - assert(call->AsCall()->callSig == nullptr); - call->AsCall()->callSig = new (this, CMK_CorSig) CORINFO_SIG_INFO; - *call->AsCall()->callSig = *sig; -#endif - // For vararg calls we must be sure to load the return type of the // method actually being called, as well as the return types of the // specified in the vararg signature. With type equivalency, these types @@ -8249,7 +8373,8 @@ var_types Compiler::impImportCall(OPCODE opcode, //------------------------------------------------------------------------- // The "this" pointer - if (!(mflags & CORINFO_FLG_STATIC) && !((opcode == CEE_NEWOBJ) && (newobjThis == nullptr))) + if (((mflags & CORINFO_FLG_STATIC) == 0) && ((sig->callConv & CORINFO_CALLCONV_EXPLICITTHIS) == 0) && + !((opcode == CEE_NEWOBJ) && (newobjThis == nullptr))) { GenTree* obj; @@ -8371,6 +8496,13 @@ var_types Compiler::impImportCall(OPCODE opcode, DONE: +#ifdef DEBUG + // In debug we want to be able to register callsites with the EE. + assert(call->AsCall()->callSig == nullptr); + call->AsCall()->callSig = new (this, CMK_Generic) CORINFO_SIG_INFO; + *call->AsCall()->callSig = *sig; +#endif + // Final importer checks for calls flagged as tail calls. // if (tailCallFlags != 0) @@ -8465,7 +8597,27 @@ var_types Compiler::impImportCall(OPCODE opcode, #endif // FEATURE_TAILCALL_OPT } - // we can't report success just yet... + // This might or might not turn into a tailcall. We do more + // checks in morph. For explicit tailcalls we need more + // information in morph in case it turns out to be a + // helper-based tailcall. + if (isExplicitTailCall) + { + assert(call->AsCall()->tailCallInfo == nullptr); + call->AsCall()->tailCallInfo = new (this, CMK_CorTailCallInfo) TailCallSiteInfo; + switch (opcode) + { + case CEE_CALLI: + call->AsCall()->tailCallInfo->SetCalli(sig); + break; + case CEE_CALLVIRT: + call->AsCall()->tailCallInfo->SetCallvirt(sig, pResolvedToken); + break; + default: + call->AsCall()->tailCallInfo->SetCall(sig, pResolvedToken); + break; + } + } } else { @@ -8532,15 +8684,7 @@ var_types Compiler::impImportCall(OPCODE opcode, // assert(call->gtOper == GT_CALL); - assert(sig != nullptr); - - // Tail calls require us to save the call site's sig info so we can obtain an argument - // copying thunk from the EE later on. - if (call->AsCall()->callSig == nullptr) - { - call->AsCall()->callSig = new (this, CMK_CorSig) CORINFO_SIG_INFO; - *call->AsCall()->callSig = *sig; - } + assert(callInfo != nullptr); if (compIsForInlining() && opcode == CEE_CALLVIRT) { @@ -8838,9 +8982,7 @@ GenTree* Compiler::impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HAN call->gtRetClsHnd = retClsHnd; #if FEATURE_MULTIREG_RET - // Initialize Return type descriptor of call node - ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); - retTypeDesc->InitializeStructReturnType(this, retClsHnd); + call->InitializeStructReturnType(this, retClsHnd); #endif // FEATURE_MULTIREG_RET #ifdef UNIX_AMD64_ABI @@ -8848,55 +8990,57 @@ GenTree* Compiler::impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HAN // Not allowed for FEATURE_CORCLR which is the only SKU available for System V OSs. assert(!call->IsVarargs() && "varargs not allowed for System V OSs."); - // The return type will remain as the incoming struct type unless normalized to a - // single eightbyte return type below. - call->gtReturnType = call->gtType; - - unsigned retRegCount = retTypeDesc->GetReturnRegCount(); - if (retRegCount != 0) + const ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); + const unsigned retRegCount = retTypeDesc->GetReturnRegCount(); + if (retRegCount == 0) + { + // struct not returned in registers i.e returned via hiddden retbuf arg. + call->gtCallMoreFlags |= GTF_CALL_M_RETBUFFARG; + } + else if (retRegCount == 1) { - if (retRegCount == 1) + if (!compDoOldStructRetyping()) + { + return call; + } + // See if the struct size is smaller than the return + // type size... + if (retTypeDesc->IsEnclosingType()) { - // See if the struct size is smaller than the return - // type size... - if (retTypeDesc->IsEnclosingType()) + // If we know for sure this call will remain a call, + // retype and return value via a suitable temp. + if ((!call->CanTailCall()) && (!call->IsInlineCandidate())) { - // If we know for sure this call will remain a call, - // retype and return value via a suitable temp. - if ((!call->CanTailCall()) && (!call->IsInlineCandidate())) - { - call->gtReturnType = retTypeDesc->GetReturnRegType(0); - return impAssignSmallStructTypeToVar(call, retClsHnd); - } + call->gtReturnType = retTypeDesc->GetReturnRegType(0); + return impAssignSmallStructTypeToVar(call, retClsHnd); } else { - // Return type is same size as struct, so we can - // simply retype the call. - call->gtReturnType = retTypeDesc->GetReturnRegType(0); + call->gtReturnType = call->gtType; } } else { - // must be a struct returned in two registers - assert(retRegCount == 2); - - if ((!call->CanTailCall()) && (!call->IsInlineCandidate())) - { - // Force a call returning multi-reg struct to be always of the IR form - // tmp = call - // - // No need to assign a multi-reg struct to a local var if: - // - It is a tail call or - // - The call is marked for in-lining later - return impAssignMultiRegTypeToVar(call, retClsHnd); - } + // Return type is same size as struct, so we can + // simply retype the call. + call->gtReturnType = retTypeDesc->GetReturnRegType(0); } } else { - // struct not returned in registers i.e returned via hiddden retbuf arg. - call->gtCallMoreFlags |= GTF_CALL_M_RETBUFFARG; + // must be a struct returned in two registers + assert(retRegCount == 2); + + if ((!call->CanTailCall()) && (!call->IsInlineCandidate())) + { + // Force a call returning multi-reg struct to be always of the IR form + // tmp = call + // + // No need to assign a multi-reg struct to a local var if: + // - It is a tail call or + // - The call is marked for in-lining later + return impAssignMultiRegTypeToVar(call, retClsHnd); + } } #else // not UNIX_AMD64_ABI @@ -8915,6 +9059,21 @@ GenTree* Compiler::impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HAN } else { + +#if FEATURE_MULTIREG_RET + const ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); + const unsigned retRegCount = retTypeDesc->GetReturnRegCount(); + assert(retRegCount != 0); + if (!compDoOldStructRetyping() && retRegCount == 1) + { + return call; + } +#else // !FEATURE_MULTIREG_RET + if (!compDoOldStructRetyping()) + { + return call; + } +#endif // !FEATURE_MULTIREG_RET assert(returnType != TYP_UNKNOWN); // See if the struct size is smaller than the return @@ -8947,9 +9106,6 @@ GenTree* Compiler::impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HAN } #if FEATURE_MULTIREG_RET - unsigned retRegCount = retTypeDesc->GetReturnRegCount(); - assert(retRegCount != 0); - if (retRegCount >= 2) { if ((!call->CanTailCall()) && (!call->IsInlineCandidate())) @@ -9096,6 +9252,12 @@ GenTree* Compiler::impFixupStructReturnType(GenTree* op, CORINFO_CLASS_HANDLE re #endif // FEATURE_MULTIREG_RET && FEATURE_HFA + if (!compDoOldStructRetyping() && (!op->IsCall() || !op->AsCall()->TreatAsHasRetBufArg(this))) + { + // Don't retype `struct` as a primitive type in `ret` instruction. + return op; + } + REDO_RETURN_NODE: // adjust the type away from struct to integral // and no normalizing @@ -9147,10 +9309,20 @@ GenTree* Compiler::impFixupStructReturnType(GenTree* op, CORINFO_CLASS_HANDLE re // No need to spill anything as we're about to return. impAssignTempGen(tmpNum, op, info.compMethodInfo->args.retTypeClass, (unsigned)CHECK_SPILL_NONE); - // Don't create both a GT_ADDR & GT_OBJ just to undo all of that; instead, - // jump directly to a GT_LCL_FLD. - op = gtNewLclvNode(tmpNum, info.compRetNativeType); - op->ChangeOper(GT_LCL_FLD); + if (compDoOldStructRetyping()) + { + // Don't create both a GT_ADDR & GT_OBJ just to undo all of that; instead, + // jump directly to a GT_LCL_FLD. + op = gtNewLclvNode(tmpNum, info.compRetNativeType); + op->ChangeOper(GT_LCL_FLD); + } + else + { + op = gtNewLclvNode(tmpNum, info.compRetType); + JITDUMP("\nimpFixupStructReturnType: created a pseudo-return buffer for a special helper\n"); + DISPTREE(op); + return op; + } } else { @@ -13710,7 +13882,8 @@ void Compiler::impImportBlockCode(BasicBlock* block) ((block->bbFlags & BBF_BACKWARD_JUMP) != 0); bool bbIsReturn = (block->bbJumpKind == BBJ_RETURN) && (!compIsForInlining() || (impInlineInfo->iciBlock->bbJumpKind == BBJ_RETURN)); - if (fgVarNeedsExplicitZeroInit(lvaGetDesc(lclNum), bbInALoop, bbIsReturn)) + LclVarDsc* const lclDsc = lvaGetDesc(lclNum); + if (fgVarNeedsExplicitZeroInit(lclNum, bbInALoop, bbIsReturn)) { // Append a tree to zero-out the temp newObjThisPtr = gtNewLclvNode(lclNum, lvaTable[lclNum].TypeGet()); @@ -13721,6 +13894,12 @@ void Compiler::impImportBlockCode(BasicBlock* block) false); // not copyBlock impAppendTree(newObjThisPtr, (unsigned)CHECK_SPILL_NONE, impCurStmtOffs); } + else + { + JITDUMP("\nSuppressing zero-init for V%02u -- expect to zero in prolog\n", lclNum); + lclDsc->lvSuppressedZeroInit = 1; + compSuppressedZeroInit = true; + } // Obtain the address of the temp newObjThisPtr = @@ -14231,6 +14410,12 @@ void Compiler::impImportBlockCode(BasicBlock* block) assert(pFldAddr == nullptr); op1 = impImportStaticReadOnlyField(fldAddr, lclTyp); + + // Widen small types since we're propagating the value + // instead of producing an indir. + // + op1->gtType = genActualType(lclTyp); + goto FIELD_DONE; } } @@ -14248,7 +14433,9 @@ void Compiler::impImportBlockCode(BasicBlock* block) case CORINFO_FIELD_INTRINSIC_ZERO: { assert(aflags & CORINFO_ACCESS_GET); - op1 = gtNewIconNode(0, lclTyp); + // Widen to stack type + lclTyp = genActualType(lclTyp); + op1 = gtNewIconNode(0, lclTyp); goto FIELD_DONE; } break; @@ -14267,6 +14454,8 @@ void Compiler::impImportBlockCode(BasicBlock* block) case CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN: { assert(aflags & CORINFO_ACCESS_GET); + // Widen to stack type + lclTyp = genActualType(lclTyp); #if BIGENDIAN op1 = gtNewIconNode(0, lclTyp); #else @@ -15036,10 +15225,19 @@ void Compiler::impImportBlockCode(BasicBlock* block) op1 = gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL, TYP_STRUCT, helperArgs); + CORINFO_CLASS_HANDLE classHandle = impGetTypeHandleClass(); + // The handle struct is returned in register op1->AsCall()->gtReturnType = GetRuntimeHandleUnderlyingType(); + if (!compDoOldStructRetyping()) + { + op1->AsCall()->gtRetClsHnd = classHandle; +#if FEATURE_MULTIREG_RET + op1->AsCall()->InitializeStructReturnType(this, classHandle); +#endif + } - tiRetVal = typeInfo(TI_STRUCT, impGetTypeHandleClass()); + tiRetVal = typeInfo(TI_STRUCT, classHandle); } impPushOnStack(op1, tiRetVal); @@ -15076,8 +15274,16 @@ void Compiler::impImportBlockCode(BasicBlock* block) op1 = gtNewHelperCallNode(helper, TYP_STRUCT, helperArgs); - // The handle struct is returned in register + // The handle struct is returned in register and + // it could be consumed both as `TYP_STRUCT` and `TYP_REF`. op1->AsCall()->gtReturnType = GetRuntimeHandleUnderlyingType(); + if (!compDoOldStructRetyping()) + { +#if FEATURE_MULTIREG_RET + op1->AsCall()->InitializeStructReturnType(this, tokenType); +#endif + op1->AsCall()->gtRetClsHnd = tokenType; + } tiRetVal = verMakeTypeInfo(tokenType); impPushOnStack(op1, tiRetVal); @@ -15254,6 +15460,13 @@ void Compiler::impImportBlockCode(BasicBlock* block) op1 = gtNewHelperCallNode(helper, (var_types)((helper == CORINFO_HELP_UNBOX) ? TYP_BYREF : TYP_STRUCT), gtNewCallArgs(op2, op1)); + if (!compDoOldStructRetyping()) + { + if (op1->gtType == TYP_STRUCT) + { + op1->AsCall()->gtRetClsHnd = resolvedToken.hClass; + } + } } assert(helper == CORINFO_HELP_UNBOX && op1->gtType == TYP_BYREF || // Unbox helper returns a byref. @@ -16172,7 +16385,7 @@ void Compiler::impMarkLclDstNotPromotable(unsigned tmpNum, GenTree* src, CORINFO GenTree* Compiler::impAssignSmallStructTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass) { - unsigned tmpNum = lvaGrabTemp(true DEBUGARG("Return value temp for small struct return.")); + unsigned tmpNum = lvaGrabTemp(true DEBUGARG("Return value temp for small struct return")); impAssignTempGen(tmpNum, op, hClass, (unsigned)CHECK_SPILL_ALL); GenTree* ret = gtNewLclvNode(tmpNum, lvaTable[tmpNum].lvType); return ret; @@ -16192,7 +16405,7 @@ GenTree* Compiler::impAssignSmallStructTypeToVar(GenTree* op, CORINFO_CLASS_HAND GenTree* Compiler::impAssignMultiRegTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass) { - unsigned tmpNum = lvaGrabTemp(true DEBUGARG("Return value temp for multireg return.")); + unsigned tmpNum = lvaGrabTemp(true DEBUGARG("Return value temp for multireg return")); impAssignTempGen(tmpNum, op, hClass, (unsigned)CHECK_SPILL_ALL); GenTree* ret = gtNewLclvNode(tmpNum, lvaTable[tmpNum].lvType); @@ -16430,11 +16643,14 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode) // node type. During morphing, the GT_CALL will get the correct, final, native return type. bool restoreType = false; - if ((op2->OperGet() == GT_CALL) && (info.compRetType == TYP_STRUCT)) + if (compDoOldStructRetyping()) { - noway_assert(op2->TypeGet() == TYP_STRUCT); - op2->gtType = info.compRetNativeType; - restoreType = true; + if ((op2->OperGet() == GT_CALL) && (info.compRetType == TYP_STRUCT)) + { + noway_assert(op2->TypeGet() == TYP_STRUCT); + op2->gtType = info.compRetNativeType; + restoreType = true; + } } impAssignTempGen(lvaInlineeReturnSpillTemp, op2, se.seTypeInfo.GetClassHandle(), @@ -16442,9 +16658,12 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode) GenTree* tmpOp2 = gtNewLclvNode(lvaInlineeReturnSpillTemp, op2->TypeGet()); - if (restoreType) + if (compDoOldStructRetyping()) { - op2->gtType = TYP_STRUCT; // restore it to what it was + if (restoreType) + { + op2->gtType = TYP_STRUCT; // restore it to what it was + } } op2 = tmpOp2; @@ -16671,7 +16890,16 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode) #endif op2 = impFixupStructReturnType(op2, retClsHnd); // return op2 - op1 = gtNewOperNode(GT_RETURN, genActualType(info.compRetNativeType), op2); + var_types returnType; + if (compDoOldStructRetyping()) + { + returnType = info.compRetNativeType; + } + else + { + returnType = info.compRetType; + } + op1 = gtNewOperNode(GT_RETURN, genActualType(returnType), op2); } else { @@ -17384,7 +17612,7 @@ void Compiler::impImportBlockPending(BasicBlock* block) #ifdef DEBUG char buffer[400]; sprintf_s(buffer, sizeof(buffer), - "Block at offset %4.4x to %4.4x in %s entered with different stack depths.\n" + "Block at offset %4.4x to %4.4x in %0.200s entered with different stack depths.\n" "Previous depth was %d, current depth is %d", block->bbCodeOffs, block->bbCodeOffsEnd, info.compFullName, block->bbStkDepth, verCurrentState.esStackDepth); @@ -18596,7 +18824,7 @@ void Compiler::impCheckCanInline(GenTreeCall* call, // // Checks for various inline blocking conditions and makes notes in // the inline info arg table about the properties of the actual. These -// properties are used later by impFetchArg to determine how best to +// properties are used later by impInlineFetchArg to determine how best to // pass the argument into the inlinee. void Compiler::impInlineRecordArgInfo(InlineInfo* pInlineInfo, @@ -19611,6 +19839,13 @@ void Compiler::impMarkInlineCandidateHelper(GenTreeCall* call, return; } + // Don't inline into callers that use the NextCallReturnAddress intrinsic. + if (info.compHasNextCallRetAddr) + { + inlineResult.NoteFatal(InlineObservation::CALLER_USES_NEXT_CALL_RET_ADDR); + return; + } + // Inlining candidate determination needs to honor only IL tail prefix. // Inlining takes precedence over implicit tail call optimization (if the call is not directly recursive). if (call->IsTailPrefixedCall()) diff --git a/src/coreclr/src/jit/inline.cpp b/src/coreclr/src/jit/inline.cpp index fca4fb50d62aef..5223376edce5bc 100644 --- a/src/coreclr/src/jit/inline.cpp +++ b/src/coreclr/src/jit/inline.cpp @@ -1171,6 +1171,7 @@ InlineContext* InlineStrategy::NewRoot() InlineContext* rootContext = new (m_Compiler, CMK_Inlining) InlineContext(this); rootContext->m_ILSize = m_Compiler->info.compILCodeSize; + rootContext->m_Code = m_Compiler->info.compCode; #if defined(DEBUG) || defined(INLINE_DATA) diff --git a/src/coreclr/src/jit/inline.def b/src/coreclr/src/jit/inline.def index b35464e3a2a4cc..886572094c0cfb 100644 --- a/src/coreclr/src/jit/inline.def +++ b/src/coreclr/src/jit/inline.def @@ -22,161 +22,162 @@ // ------ Initial Sentinel ------- -INLINE_OBSERVATION(UNUSED_INITIAL, bool, "unused initial observation", FATAL, CALLEE) +INLINE_OBSERVATION(UNUSED_INITIAL, bool, "unused initial observation", FATAL, CALLEE) // ------ Callee Fatal ------- -INLINE_OBSERVATION(BAD_ARGUMENT_NUMBER, bool, "invalid argument number", FATAL, CALLEE) -INLINE_OBSERVATION(BAD_LOCAL_NUMBER, bool, "invalid local number", FATAL, CALLEE) -INLINE_OBSERVATION(CLASS_INIT_FAILURE, bool, "class init failed", FATAL, CALLEE) -INLINE_OBSERVATION(COMPILATION_ERROR, bool, "compilation error", FATAL, CALLEE) -INLINE_OBSERVATION(EXCEEDS_THRESHOLD, bool, "exceeds profit threshold", FATAL, CALLEE) -INLINE_OBSERVATION(HAS_DELEGATE_INVOKE, bool, "delegate invoke", FATAL, CALLEE) -INLINE_OBSERVATION(HAS_EH, bool, "has exception handling", FATAL, CALLEE) -INLINE_OBSERVATION(HAS_ENDFILTER, bool, "has endfilter", FATAL, CALLEE) -INLINE_OBSERVATION(HAS_ENDFINALLY, bool, "has endfinally", FATAL, CALLEE) -INLINE_OBSERVATION(HAS_LEAVE, bool, "has leave", FATAL, CALLEE) -INLINE_OBSERVATION(HAS_MANAGED_VARARGS, bool, "managed varargs", FATAL, CALLEE) -INLINE_OBSERVATION(HAS_NATIVE_VARARGS, bool, "native varargs", FATAL, CALLEE) -INLINE_OBSERVATION(HAS_NO_BODY, bool, "has no body", FATAL, CALLEE) -INLINE_OBSERVATION(HAS_NULL_FOR_LDELEM, bool, "has null pointer for ldelem", FATAL, CALLEE) -INLINE_OBSERVATION(IS_ARRAY_METHOD, bool, "is array method", FATAL, CALLEE) -INLINE_OBSERVATION(IS_GENERIC_VIRTUAL, bool, "generic virtual", FATAL, CALLEE) -INLINE_OBSERVATION(IS_JIT_NOINLINE, bool, "noinline per JitNoinline", FATAL, CALLEE) -INLINE_OBSERVATION(IS_NOINLINE, bool, "noinline per IL/cached result", FATAL, CALLEE) -INLINE_OBSERVATION(IS_SYNCHRONIZED, bool, "is synchronized", FATAL, CALLEE) -INLINE_OBSERVATION(IS_VM_NOINLINE, bool, "noinline per VM", FATAL, CALLEE) -INLINE_OBSERVATION(LACKS_RETURN, bool, "no return opcode", FATAL, CALLEE) -INLINE_OBSERVATION(LDFLD_NEEDS_HELPER, bool, "ldfld needs helper", FATAL, CALLEE) -INLINE_OBSERVATION(LOCALLOC_TOO_LARGE, bool, "localloc size too large", FATAL, CALLEE) -INLINE_OBSERVATION(LOG_REPLAY_REJECT, bool, "rejected by log replay", FATAL, CALLEE) -INLINE_OBSERVATION(MARKED_AS_SKIPPED, bool, "skipped by complus request", FATAL, CALLEE) -INLINE_OBSERVATION(MAXSTACK_TOO_BIG, bool, "maxstack too big" , FATAL, CALLEE) -INLINE_OBSERVATION(NO_METHOD_INFO, bool, "cannot get method info", FATAL, CALLEE) -INLINE_OBSERVATION(NOT_PROFITABLE_INLINE, bool, "unprofitable inline", FATAL, CALLEE) -INLINE_OBSERVATION(RANDOM_REJECT, bool, "random reject", FATAL, CALLEE) -INLINE_OBSERVATION(STACK_CRAWL_MARK, bool, "uses stack crawl mark", FATAL, CALLEE) -INLINE_OBSERVATION(STFLD_NEEDS_HELPER, bool, "stfld needs helper", FATAL, CALLEE) -INLINE_OBSERVATION(TOO_MANY_ARGUMENTS, bool, "too many arguments", FATAL, CALLEE) -INLINE_OBSERVATION(TOO_MANY_LOCALS, bool, "too many locals", FATAL, CALLEE) -INLINE_OBSERVATION(EXPLICIT_TAIL_PREFIX, bool, "explicit tail prefix in callee",FATAL, CALLEE) +INLINE_OBSERVATION(BAD_ARGUMENT_NUMBER, bool, "invalid argument number", FATAL, CALLEE) +INLINE_OBSERVATION(BAD_LOCAL_NUMBER, bool, "invalid local number", FATAL, CALLEE) +INLINE_OBSERVATION(CLASS_INIT_FAILURE, bool, "class init failed", FATAL, CALLEE) +INLINE_OBSERVATION(COMPILATION_ERROR, bool, "compilation error", FATAL, CALLEE) +INLINE_OBSERVATION(EXCEEDS_THRESHOLD, bool, "exceeds profit threshold", FATAL, CALLEE) +INLINE_OBSERVATION(HAS_DELEGATE_INVOKE, bool, "delegate invoke", FATAL, CALLEE) +INLINE_OBSERVATION(HAS_EH, bool, "has exception handling", FATAL, CALLEE) +INLINE_OBSERVATION(HAS_ENDFILTER, bool, "has endfilter", FATAL, CALLEE) +INLINE_OBSERVATION(HAS_ENDFINALLY, bool, "has endfinally", FATAL, CALLEE) +INLINE_OBSERVATION(HAS_LEAVE, bool, "has leave", FATAL, CALLEE) +INLINE_OBSERVATION(HAS_MANAGED_VARARGS, bool, "managed varargs", FATAL, CALLEE) +INLINE_OBSERVATION(HAS_NATIVE_VARARGS, bool, "native varargs", FATAL, CALLEE) +INLINE_OBSERVATION(HAS_NO_BODY, bool, "has no body", FATAL, CALLEE) +INLINE_OBSERVATION(HAS_NULL_FOR_LDELEM, bool, "has null pointer for ldelem", FATAL, CALLEE) +INLINE_OBSERVATION(IS_ARRAY_METHOD, bool, "is array method", FATAL, CALLEE) +INLINE_OBSERVATION(IS_GENERIC_VIRTUAL, bool, "generic virtual", FATAL, CALLEE) +INLINE_OBSERVATION(IS_JIT_NOINLINE, bool, "noinline per JitNoinline", FATAL, CALLEE) +INLINE_OBSERVATION(IS_NOINLINE, bool, "noinline per IL/cached result", FATAL, CALLEE) +INLINE_OBSERVATION(IS_SYNCHRONIZED, bool, "is synchronized", FATAL, CALLEE) +INLINE_OBSERVATION(IS_VM_NOINLINE, bool, "noinline per VM", FATAL, CALLEE) +INLINE_OBSERVATION(LACKS_RETURN, bool, "no return opcode", FATAL, CALLEE) +INLINE_OBSERVATION(LDFLD_NEEDS_HELPER, bool, "ldfld needs helper", FATAL, CALLEE) +INLINE_OBSERVATION(LOCALLOC_TOO_LARGE, bool, "localloc size too large", FATAL, CALLEE) +INLINE_OBSERVATION(LOG_REPLAY_REJECT, bool, "rejected by log replay", FATAL, CALLEE) +INLINE_OBSERVATION(MARKED_AS_SKIPPED, bool, "skipped by complus request", FATAL, CALLEE) +INLINE_OBSERVATION(MAXSTACK_TOO_BIG, bool, "maxstack too big" , FATAL, CALLEE) +INLINE_OBSERVATION(NO_METHOD_INFO, bool, "cannot get method info", FATAL, CALLEE) +INLINE_OBSERVATION(NOT_PROFITABLE_INLINE, bool, "unprofitable inline", FATAL, CALLEE) +INLINE_OBSERVATION(RANDOM_REJECT, bool, "random reject", FATAL, CALLEE) +INLINE_OBSERVATION(STACK_CRAWL_MARK, bool, "uses stack crawl mark", FATAL, CALLEE) +INLINE_OBSERVATION(STFLD_NEEDS_HELPER, bool, "stfld needs helper", FATAL, CALLEE) +INLINE_OBSERVATION(TOO_MANY_ARGUMENTS, bool, "too many arguments", FATAL, CALLEE) +INLINE_OBSERVATION(TOO_MANY_LOCALS, bool, "too many locals", FATAL, CALLEE) +INLINE_OBSERVATION(EXPLICIT_TAIL_PREFIX, bool, "explicit tail prefix in callee", FATAL, CALLEE) // ------ Callee Performance ------- -INLINE_OBSERVATION(LDFLD_STATIC_VALUECLASS, bool, "ldsfld of value class", PERFORMANCE, CALLEE) -INLINE_OBSERVATION(TOO_MANY_BASIC_BLOCKS, bool, "too many basic blocks", PERFORMANCE, CALLEE) -INLINE_OBSERVATION(TOO_MUCH_IL, bool, "too many il bytes", PERFORMANCE, CALLEE) +INLINE_OBSERVATION(LDFLD_STATIC_VALUECLASS, bool, "ldsfld of value class", PERFORMANCE, CALLEE) +INLINE_OBSERVATION(TOO_MANY_BASIC_BLOCKS, bool, "too many basic blocks", PERFORMANCE, CALLEE) +INLINE_OBSERVATION(TOO_MUCH_IL, bool, "too many il bytes", PERFORMANCE, CALLEE) // ------ Callee Information ------- -INLINE_OBSERVATION(ARG_FEEDS_CONSTANT_TEST, bool, "argument feeds constant test", INFORMATION, CALLEE) -INLINE_OBSERVATION(ARG_FEEDS_TEST, bool, "argument feeds test", INFORMATION, CALLEE) -INLINE_OBSERVATION(ARG_FEEDS_RANGE_CHECK, bool, "argument feeds range check", INFORMATION, CALLEE) -INLINE_OBSERVATION(BEGIN_OPCODE_SCAN, bool, "prepare to look at opcodes", INFORMATION, CALLEE) -INLINE_OBSERVATION(BELOW_ALWAYS_INLINE_SIZE, bool, "below ALWAYS_INLINE size", INFORMATION, CALLEE) -INLINE_OBSERVATION(CLASS_PROMOTABLE, bool, "promotable value class", INFORMATION, CALLEE) -INLINE_OBSERVATION(DOES_NOT_RETURN, bool, "does not return", INFORMATION, CALLEE) -INLINE_OBSERVATION(END_OPCODE_SCAN, bool, "done looking at opcodes", INFORMATION, CALLEE) -INLINE_OBSERVATION(HAS_GC_STRUCT, bool, "has gc field in struct local", INFORMATION, CALLEE) -INLINE_OBSERVATION(HAS_LOCALLOC, bool, "has localloc", INFORMATION, CALLEE) -INLINE_OBSERVATION(HAS_PINNED_LOCALS, bool, "has pinned locals", INFORMATION, CALLEE) -INLINE_OBSERVATION(HAS_SIMD, bool, "has SIMD arg, local, or ret", INFORMATION, CALLEE) -INLINE_OBSERVATION(HAS_SWITCH, bool, "has switch", INFORMATION, CALLEE) -INLINE_OBSERVATION(IL_CODE_SIZE, int, "number of bytes of IL", INFORMATION, CALLEE) -INLINE_OBSERVATION(IS_CLASS_CTOR, bool, "class constructor", INFORMATION, CALLEE) -INLINE_OBSERVATION(IS_DISCRETIONARY_INLINE, bool, "can inline, check heuristics", INFORMATION, CALLEE) -INLINE_OBSERVATION(IS_FORCE_INLINE, bool, "aggressive inline attribute", INFORMATION, CALLEE) -INLINE_OBSERVATION(IS_INSTANCE_CTOR, bool, "instance constructor", INFORMATION, CALLEE) -INLINE_OBSERVATION(IS_PROFITABLE_INLINE, bool, "profitable inline", INFORMATION, CALLEE) -INLINE_OBSERVATION(IS_SIZE_DECREASING_INLINE, bool, "size decreasing inline", INFORMATION, CALLEE) -INLINE_OBSERVATION(LOG_REPLAY_ACCEPT, bool, "accepted by log replay", INFORMATION, CALLEE) -INLINE_OBSERVATION(LOOKS_LIKE_WRAPPER, bool, "thin wrapper around a call", INFORMATION, CALLEE) -INLINE_OBSERVATION(MAXSTACK, int, "maxstack", INFORMATION, CALLEE) -INLINE_OBSERVATION(OPCODE, int, "next opcode in IL stream", INFORMATION, CALLEE) -INLINE_OBSERVATION(OPCODE_NORMED, int, "next opcode in IL stream", INFORMATION, CALLEE) -INLINE_OBSERVATION(NUMBER_OF_ARGUMENTS, int, "number of arguments", INFORMATION, CALLEE) -INLINE_OBSERVATION(NUMBER_OF_BASIC_BLOCKS, int, "number of basic blocks", INFORMATION, CALLEE) -INLINE_OBSERVATION(NUMBER_OF_LOCALS, int, "number of locals", INFORMATION, CALLEE) -INLINE_OBSERVATION(RANDOM_ACCEPT, bool, "random accept", INFORMATION, CALLEE) -INLINE_OBSERVATION(UNSUPPORTED_OPCODE, bool, "unsupported opcode", INFORMATION, CALLEE) +INLINE_OBSERVATION(ARG_FEEDS_CONSTANT_TEST, bool, "argument feeds constant test", INFORMATION, CALLEE) +INLINE_OBSERVATION(ARG_FEEDS_TEST, bool, "argument feeds test", INFORMATION, CALLEE) +INLINE_OBSERVATION(ARG_FEEDS_RANGE_CHECK, bool, "argument feeds range check", INFORMATION, CALLEE) +INLINE_OBSERVATION(BEGIN_OPCODE_SCAN, bool, "prepare to look at opcodes", INFORMATION, CALLEE) +INLINE_OBSERVATION(BELOW_ALWAYS_INLINE_SIZE, bool, "below ALWAYS_INLINE size", INFORMATION, CALLEE) +INLINE_OBSERVATION(CLASS_PROMOTABLE, bool, "promotable value class", INFORMATION, CALLEE) +INLINE_OBSERVATION(DOES_NOT_RETURN, bool, "does not return", INFORMATION, CALLEE) +INLINE_OBSERVATION(END_OPCODE_SCAN, bool, "done looking at opcodes", INFORMATION, CALLEE) +INLINE_OBSERVATION(HAS_GC_STRUCT, bool, "has gc field in struct local", INFORMATION, CALLEE) +INLINE_OBSERVATION(HAS_LOCALLOC, bool, "has localloc", INFORMATION, CALLEE) +INLINE_OBSERVATION(HAS_PINNED_LOCALS, bool, "has pinned locals", INFORMATION, CALLEE) +INLINE_OBSERVATION(HAS_SIMD, bool, "has SIMD arg, local, or ret", INFORMATION, CALLEE) +INLINE_OBSERVATION(HAS_SWITCH, bool, "has switch", INFORMATION, CALLEE) +INLINE_OBSERVATION(IL_CODE_SIZE, int, "number of bytes of IL", INFORMATION, CALLEE) +INLINE_OBSERVATION(IS_CLASS_CTOR, bool, "class constructor", INFORMATION, CALLEE) +INLINE_OBSERVATION(IS_DISCRETIONARY_INLINE, bool, "can inline, check heuristics", INFORMATION, CALLEE) +INLINE_OBSERVATION(IS_FORCE_INLINE, bool, "aggressive inline attribute", INFORMATION, CALLEE) +INLINE_OBSERVATION(IS_INSTANCE_CTOR, bool, "instance constructor", INFORMATION, CALLEE) +INLINE_OBSERVATION(IS_PROFITABLE_INLINE, bool, "profitable inline", INFORMATION, CALLEE) +INLINE_OBSERVATION(IS_SIZE_DECREASING_INLINE, bool, "size decreasing inline", INFORMATION, CALLEE) +INLINE_OBSERVATION(LOG_REPLAY_ACCEPT, bool, "accepted by log replay", INFORMATION, CALLEE) +INLINE_OBSERVATION(LOOKS_LIKE_WRAPPER, bool, "thin wrapper around a call", INFORMATION, CALLEE) +INLINE_OBSERVATION(MAXSTACK, int, "maxstack", INFORMATION, CALLEE) +INLINE_OBSERVATION(OPCODE, int, "next opcode in IL stream", INFORMATION, CALLEE) +INLINE_OBSERVATION(OPCODE_NORMED, int, "next opcode in IL stream", INFORMATION, CALLEE) +INLINE_OBSERVATION(NUMBER_OF_ARGUMENTS, int, "number of arguments", INFORMATION, CALLEE) +INLINE_OBSERVATION(NUMBER_OF_BASIC_BLOCKS, int, "number of basic blocks", INFORMATION, CALLEE) +INLINE_OBSERVATION(NUMBER_OF_LOCALS, int, "number of locals", INFORMATION, CALLEE) +INLINE_OBSERVATION(RANDOM_ACCEPT, bool, "random accept", INFORMATION, CALLEE) +INLINE_OBSERVATION(UNSUPPORTED_OPCODE, bool, "unsupported opcode", INFORMATION, CALLEE) // ------ Caller Correctness ------- -INLINE_OBSERVATION(DEBUG_CODEGEN, bool, "debug codegen", FATAL, CALLER) -INLINE_OBSERVATION(IS_JIT_NOINLINE, bool, "noinline per JitNoInlineRange", FATAL, CALLER) +INLINE_OBSERVATION(DEBUG_CODEGEN, bool, "debug codegen", FATAL, CALLER) +INLINE_OBSERVATION(IS_JIT_NOINLINE, bool, "noinline per JitNoInlineRange", FATAL, CALLER) +INLINE_OBSERVATION(USES_NEXT_CALL_RET_ADDR, bool, "uses NextCallReturnAddress intrinsic", FATAL, CALLER) // ------ Caller Information ------- -INLINE_OBSERVATION(HAS_NEWARRAY, bool, "has newarray", INFORMATION, CALLER) -INLINE_OBSERVATION(HAS_NEWOBJ, bool, "has newobj", INFORMATION, CALLER) +INLINE_OBSERVATION(HAS_NEWARRAY, bool, "has newarray", INFORMATION, CALLER) +INLINE_OBSERVATION(HAS_NEWOBJ, bool, "has newobj", INFORMATION, CALLER) // ------ Call Site Correctness ------- -INLINE_OBSERVATION(ARG_HAS_NULL_THIS, bool, "this pointer argument is null", FATAL, CALLSITE) -INLINE_OBSERVATION(ARG_IS_MKREFANY, bool, "argument is mkrefany", FATAL, CALLSITE) -INLINE_OBSERVATION(ARG_NO_BASH_TO_INT, bool, "argument can't bash to int", FATAL, CALLSITE) -INLINE_OBSERVATION(ARG_NO_BASH_TO_REF, bool, "argument can't bash to ref", FATAL, CALLSITE) -INLINE_OBSERVATION(ARG_TYPES_INCOMPATIBLE, bool, "argument types incompatible", FATAL, CALLSITE) -INLINE_OBSERVATION(CANT_EMBED_PINVOKE_COOKIE, bool, "can't embed pinvoke cookie", FATAL, CALLSITE) -INLINE_OBSERVATION(CANT_EMBED_VARARGS_COOKIE, bool, "can't embed varargs cookie", FATAL, CALLSITE) -INLINE_OBSERVATION(CLASS_INIT_FAILURE_SPEC, bool, "speculative class init failed", FATAL, CALLSITE) -INLINE_OBSERVATION(COMPILATION_ERROR, bool, "compilation error", FATAL, CALLSITE) -INLINE_OBSERVATION(COMPILATION_FAILURE, bool, "failed to compile", FATAL, CALLSITE) -INLINE_OBSERVATION(CROSS_BOUNDARY_CALLI, bool, "cross-boundary calli", FATAL, CALLSITE) -INLINE_OBSERVATION(CROSS_BOUNDARY_SECURITY, bool, "cross-boundary security check", FATAL, CALLSITE) -INLINE_OBSERVATION(EXCEEDS_THRESHOLD, bool, "exceeds profit threshold", FATAL, CALLSITE) -INLINE_OBSERVATION(EXPLICIT_TAIL_PREFIX, bool, "explicit tail prefix", FATAL, CALLSITE) -INLINE_OBSERVATION(GENERIC_DICTIONARY_LOOKUP, bool, "runtime dictionary lookup", FATAL, CALLSITE) -INLINE_OBSERVATION(HAS_CALL_VIA_LDVIRTFTN, bool, "call via ldvirtftn", FATAL, CALLSITE) -INLINE_OBSERVATION(HAS_COMPLEX_HANDLE, bool, "complex handle access", FATAL, CALLSITE) -INLINE_OBSERVATION(HAS_LDSTR_RESTRICTION, bool, "has ldstr VM restriction", FATAL, CALLSITE) -INLINE_OBSERVATION(IMPLICIT_REC_TAIL_CALL, bool, "implicit recursive tail call", FATAL, CALLSITE) -INLINE_OBSERVATION(IS_CALL_TO_HELPER, bool, "target is helper", FATAL, CALLSITE) -INLINE_OBSERVATION(IS_NOT_DIRECT, bool, "target not direct", FATAL, CALLSITE) -INLINE_OBSERVATION(IS_NOT_DIRECT_MANAGED, bool, "target not direct managed", FATAL, CALLSITE) -INLINE_OBSERVATION(IS_RECURSIVE, bool, "recursive", FATAL, CALLSITE) -INLINE_OBSERVATION(IS_TOO_DEEP, bool, "too deep", FATAL, CALLSITE) -INLINE_OBSERVATION(IS_VIRTUAL, bool, "virtual", FATAL, CALLSITE) -INLINE_OBSERVATION(IS_VM_NOINLINE, bool, "noinline per VM", FATAL, CALLSITE) -INLINE_OBSERVATION(IS_WITHIN_CATCH, bool, "within catch region", FATAL, CALLSITE) -INLINE_OBSERVATION(IS_WITHIN_FILTER, bool, "within filter region", FATAL, CALLSITE) -INLINE_OBSERVATION(LDARGA_NOT_LOCAL_VAR, bool, "ldarga not on local var", FATAL, CALLSITE) -INLINE_OBSERVATION(LDFLD_NEEDS_HELPER, bool, "ldfld needs helper", FATAL, CALLSITE) -INLINE_OBSERVATION(LDVIRTFN_ON_NON_VIRTUAL, bool, "ldvirtfn on non-virtual", FATAL, CALLSITE) -INLINE_OBSERVATION(LOCALLOC_IN_LOOP, bool, "within loop, has localloc", FATAL, CALLSITE) -INLINE_OBSERVATION(LOCALLOC_SIZE_UNKNOWN, bool, "localloc size unknown", FATAL, CALLSITE) -INLINE_OBSERVATION(LOG_REPLAY_REJECT, bool, "rejected by log replay", FATAL, CALLSITE) -INLINE_OBSERVATION(NOT_CANDIDATE, bool, "not inline candidate", FATAL, CALLSITE) -INLINE_OBSERVATION(NOT_PROFITABLE_INLINE, bool, "unprofitable inline", FATAL, CALLSITE) -INLINE_OBSERVATION(OVER_BUDGET, bool, "inline exceeds budget", FATAL, CALLSITE) -INLINE_OBSERVATION(OVER_INLINE_LIMIT, bool, "limited by JitInlineLimit", FATAL, CALLSITE) -INLINE_OBSERVATION(PIN_IN_TRY_REGION, bool, "within try region, pinned", FATAL, CALLSITE) -INLINE_OBSERVATION(RANDOM_REJECT, bool, "random reject", FATAL, CALLSITE) -INLINE_OBSERVATION(REQUIRES_SAME_THIS, bool, "requires same this", FATAL, CALLSITE) -INLINE_OBSERVATION(RETURN_TYPE_MISMATCH, bool, "return type mismatch", FATAL, CALLSITE) -INLINE_OBSERVATION(STFLD_NEEDS_HELPER, bool, "stfld needs helper", FATAL, CALLSITE) -INLINE_OBSERVATION(TOO_MANY_LOCALS, bool, "too many locals", FATAL, CALLSITE) -INLINE_OBSERVATION(PINVOKE_EH, bool, "PInvoke call site with EH", FATAL, CALLSITE) +INLINE_OBSERVATION(ARG_HAS_NULL_THIS, bool, "this pointer argument is null", FATAL, CALLSITE) +INLINE_OBSERVATION(ARG_IS_MKREFANY, bool, "argument is mkrefany", FATAL, CALLSITE) +INLINE_OBSERVATION(ARG_NO_BASH_TO_INT, bool, "argument can't bash to int", FATAL, CALLSITE) +INLINE_OBSERVATION(ARG_NO_BASH_TO_REF, bool, "argument can't bash to ref", FATAL, CALLSITE) +INLINE_OBSERVATION(ARG_TYPES_INCOMPATIBLE, bool, "argument types incompatible", FATAL, CALLSITE) +INLINE_OBSERVATION(CANT_EMBED_PINVOKE_COOKIE, bool, "can't embed pinvoke cookie", FATAL, CALLSITE) +INLINE_OBSERVATION(CANT_EMBED_VARARGS_COOKIE, bool, "can't embed varargs cookie", FATAL, CALLSITE) +INLINE_OBSERVATION(CLASS_INIT_FAILURE_SPEC, bool, "speculative class init failed", FATAL, CALLSITE) +INLINE_OBSERVATION(COMPILATION_ERROR, bool, "compilation error", FATAL, CALLSITE) +INLINE_OBSERVATION(COMPILATION_FAILURE, bool, "failed to compile", FATAL, CALLSITE) +INLINE_OBSERVATION(CROSS_BOUNDARY_CALLI, bool, "cross-boundary calli", FATAL, CALLSITE) +INLINE_OBSERVATION(CROSS_BOUNDARY_SECURITY, bool, "cross-boundary security check", FATAL, CALLSITE) +INLINE_OBSERVATION(EXCEEDS_THRESHOLD, bool, "exceeds profit threshold", FATAL, CALLSITE) +INLINE_OBSERVATION(EXPLICIT_TAIL_PREFIX, bool, "explicit tail prefix", FATAL, CALLSITE) +INLINE_OBSERVATION(GENERIC_DICTIONARY_LOOKUP, bool, "runtime dictionary lookup", FATAL, CALLSITE) +INLINE_OBSERVATION(HAS_CALL_VIA_LDVIRTFTN, bool, "call via ldvirtftn", FATAL, CALLSITE) +INLINE_OBSERVATION(HAS_COMPLEX_HANDLE, bool, "complex handle access", FATAL, CALLSITE) +INLINE_OBSERVATION(HAS_LDSTR_RESTRICTION, bool, "has ldstr VM restriction", FATAL, CALLSITE) +INLINE_OBSERVATION(IMPLICIT_REC_TAIL_CALL, bool, "implicit recursive tail call", FATAL, CALLSITE) +INLINE_OBSERVATION(IS_CALL_TO_HELPER, bool, "target is helper", FATAL, CALLSITE) +INLINE_OBSERVATION(IS_NOT_DIRECT, bool, "target not direct", FATAL, CALLSITE) +INLINE_OBSERVATION(IS_NOT_DIRECT_MANAGED, bool, "target not direct managed", FATAL, CALLSITE) +INLINE_OBSERVATION(IS_RECURSIVE, bool, "recursive", FATAL, CALLSITE) +INLINE_OBSERVATION(IS_TOO_DEEP, bool, "too deep", FATAL, CALLSITE) +INLINE_OBSERVATION(IS_VIRTUAL, bool, "virtual", FATAL, CALLSITE) +INLINE_OBSERVATION(IS_VM_NOINLINE, bool, "noinline per VM", FATAL, CALLSITE) +INLINE_OBSERVATION(IS_WITHIN_CATCH, bool, "within catch region", FATAL, CALLSITE) +INLINE_OBSERVATION(IS_WITHIN_FILTER, bool, "within filter region", FATAL, CALLSITE) +INLINE_OBSERVATION(LDARGA_NOT_LOCAL_VAR, bool, "ldarga not on local var", FATAL, CALLSITE) +INLINE_OBSERVATION(LDFLD_NEEDS_HELPER, bool, "ldfld needs helper", FATAL, CALLSITE) +INLINE_OBSERVATION(LDVIRTFN_ON_NON_VIRTUAL, bool, "ldvirtfn on non-virtual", FATAL, CALLSITE) +INLINE_OBSERVATION(LOCALLOC_IN_LOOP, bool, "within loop, has localloc", FATAL, CALLSITE) +INLINE_OBSERVATION(LOCALLOC_SIZE_UNKNOWN, bool, "localloc size unknown", FATAL, CALLSITE) +INLINE_OBSERVATION(LOG_REPLAY_REJECT, bool, "rejected by log replay", FATAL, CALLSITE) +INLINE_OBSERVATION(NOT_CANDIDATE, bool, "not inline candidate", FATAL, CALLSITE) +INLINE_OBSERVATION(NOT_PROFITABLE_INLINE, bool, "unprofitable inline", FATAL, CALLSITE) +INLINE_OBSERVATION(OVER_BUDGET, bool, "inline exceeds budget", FATAL, CALLSITE) +INLINE_OBSERVATION(OVER_INLINE_LIMIT, bool, "limited by JitInlineLimit", FATAL, CALLSITE) +INLINE_OBSERVATION(PIN_IN_TRY_REGION, bool, "within try region, pinned", FATAL, CALLSITE) +INLINE_OBSERVATION(RANDOM_REJECT, bool, "random reject", FATAL, CALLSITE) +INLINE_OBSERVATION(REQUIRES_SAME_THIS, bool, "requires same this", FATAL, CALLSITE) +INLINE_OBSERVATION(RETURN_TYPE_MISMATCH, bool, "return type mismatch", FATAL, CALLSITE) +INLINE_OBSERVATION(STFLD_NEEDS_HELPER, bool, "stfld needs helper", FATAL, CALLSITE) +INLINE_OBSERVATION(TOO_MANY_LOCALS, bool, "too many locals", FATAL, CALLSITE) +INLINE_OBSERVATION(PINVOKE_EH, bool, "PInvoke call site with EH", FATAL, CALLSITE) // ------ Call Site Performance ------- -INLINE_OBSERVATION(RARE_GC_STRUCT, bool, "rarely called, has gc struct", INFORMATION, CALLSITE) +INLINE_OBSERVATION(RARE_GC_STRUCT, bool, "rarely called, has gc struct", INFORMATION, CALLSITE) // ------ Call Site Information ------- -INLINE_OBSERVATION(CONSTANT_ARG_FEEDS_TEST, bool, "constant argument feeds test", INFORMATION, CALLSITE) -INLINE_OBSERVATION(DEPTH, int, "depth", INFORMATION, CALLSITE) -INLINE_OBSERVATION(FREQUENCY, int, "rough call site frequency", INFORMATION, CALLSITE) -INLINE_OBSERVATION(IN_LOOP, bool, "call site is in a loop", INFORMATION, CALLSITE) -INLINE_OBSERVATION(IN_TRY_REGION, bool, "call site is in a try region", INFORMATION, CALLSITE) -INLINE_OBSERVATION(IS_PROFITABLE_INLINE, bool, "profitable inline", INFORMATION, CALLSITE) -INLINE_OBSERVATION(IS_SAME_THIS, bool, "same this as root caller", INFORMATION, CALLSITE) -INLINE_OBSERVATION(IS_SIZE_DECREASING_INLINE, bool, "size decreasing inline", INFORMATION, CALLSITE) -INLINE_OBSERVATION(LOG_REPLAY_ACCEPT, bool, "accepted by log replay", INFORMATION, CALLSITE) -INLINE_OBSERVATION(RANDOM_ACCEPT, bool, "random accept", INFORMATION, CALLSITE) -INLINE_OBSERVATION(WEIGHT, int, "call site frequency", INFORMATION, CALLSITE) +INLINE_OBSERVATION(CONSTANT_ARG_FEEDS_TEST, bool, "constant argument feeds test", INFORMATION, CALLSITE) +INLINE_OBSERVATION(DEPTH, int, "depth", INFORMATION, CALLSITE) +INLINE_OBSERVATION(FREQUENCY, int, "rough call site frequency", INFORMATION, CALLSITE) +INLINE_OBSERVATION(IN_LOOP, bool, "call site is in a loop", INFORMATION, CALLSITE) +INLINE_OBSERVATION(IN_TRY_REGION, bool, "call site is in a try region", INFORMATION, CALLSITE) +INLINE_OBSERVATION(IS_PROFITABLE_INLINE, bool, "profitable inline", INFORMATION, CALLSITE) +INLINE_OBSERVATION(IS_SAME_THIS, bool, "same this as root caller", INFORMATION, CALLSITE) +INLINE_OBSERVATION(IS_SIZE_DECREASING_INLINE, bool, "size decreasing inline", INFORMATION, CALLSITE) +INLINE_OBSERVATION(LOG_REPLAY_ACCEPT, bool, "accepted by log replay", INFORMATION, CALLSITE) +INLINE_OBSERVATION(RANDOM_ACCEPT, bool, "random accept", INFORMATION, CALLSITE) +INLINE_OBSERVATION(WEIGHT, int, "call site frequency", INFORMATION, CALLSITE) // ------ Final Sentinel ------- -INLINE_OBSERVATION(UNUSED_FINAL, bool, "unused final observation", FATAL, CALLEE) +INLINE_OBSERVATION(UNUSED_FINAL, bool, "unused final observation", FATAL, CALLEE) diff --git a/src/coreclr/src/jit/inline.h b/src/coreclr/src/jit/inline.h index 01c523dc9891a8..76011c10028b40 100644 --- a/src/coreclr/src/jit/inline.h +++ b/src/coreclr/src/jit/inline.h @@ -662,7 +662,7 @@ class InlineContext } // Get the code pointer for this context. - BYTE* GetCode() const + const BYTE* GetCode() const { return m_Code; } @@ -731,7 +731,7 @@ class InlineContext InlineContext* m_Parent; // logical caller (parent) InlineContext* m_Child; // first child InlineContext* m_Sibling; // next child of the parent - BYTE* m_Code; // address of IL buffer for the method + const BYTE* m_Code; // address of IL buffer for the method unsigned m_ILSize; // size of IL buffer for the method unsigned m_ImportedILSize; // estimated size of imported IL IL_OFFSETX m_Offset; // call site location within parent diff --git a/src/coreclr/src/jit/instr.cpp b/src/coreclr/src/jit/instr.cpp index 2ee631fceeff82..ec776cbea9a911 100644 --- a/src/coreclr/src/jit/instr.cpp +++ b/src/coreclr/src/jit/instr.cpp @@ -57,13 +57,13 @@ const char* CodeGen::genInsName(instruction ins) #include "instrs.h" #elif defined(TARGET_ARM64) - #define INST1(id, nm, fp, ldst, fmt, e1 ) nm, - #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) nm, - #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) nm, - #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) nm, - #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) nm, - #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) nm, - #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9 ) nm, + #define INST1(id, nm, ldst, fmt, e1 ) nm, + #define INST2(id, nm, ldst, fmt, e1, e2 ) nm, + #define INST3(id, nm, ldst, fmt, e1, e2, e3 ) nm, + #define INST4(id, nm, ldst, fmt, e1, e2, e3, e4 ) nm, + #define INST5(id, nm, ldst, fmt, e1, e2, e3, e4, e5 ) nm, + #define INST6(id, nm, ldst, fmt, e1, e2, e3, e4, e5, e6 ) nm, + #define INST9(id, nm, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9 ) nm, #include "instrs.h" #else @@ -2364,11 +2364,7 @@ void CodeGen::instGen_Return(unsigned stkArgSize) * Note: all MemoryBarriers instructions can be removed by * SET COMPlus_JitNoMemoryBarriers=1 */ -#ifdef TARGET_ARM64 -void CodeGen::instGen_MemoryBarrier(insBarrier barrierType) -#else -void CodeGen::instGen_MemoryBarrier() -#endif +void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind) { #ifdef DEBUG if (JitConfig.JitNoMemoryBarriers() == 1) @@ -2378,12 +2374,19 @@ void CodeGen::instGen_MemoryBarrier() #endif // DEBUG #if defined(TARGET_XARCH) + // only full barrier needs to be emitted on Xarch + if (barrierKind != BARRIER_FULL) + { + return; + } + instGen(INS_lock); GetEmitter()->emitIns_I_AR(INS_or, EA_4BYTE, 0, REG_SPBASE, 0); #elif defined(TARGET_ARM) + // ARM has only full barriers, so all barriers need to be emitted as full. GetEmitter()->emitIns_I(INS_dmb, EA_4BYTE, 0xf); #elif defined(TARGET_ARM64) - GetEmitter()->emitIns_BARR(INS_dmb, barrierType); + GetEmitter()->emitIns_BARR(INS_dmb, barrierKind == BARRIER_LOAD_ONLY ? INS_BARRIER_ISHLD : INS_BARRIER_ISH); #else #error "Unknown TARGET" #endif diff --git a/src/coreclr/src/jit/instr.h b/src/coreclr/src/jit/instr.h index 26ba6eec4ac016..3c0404c6079e95 100644 --- a/src/coreclr/src/jit/instr.h +++ b/src/coreclr/src/jit/instr.h @@ -37,13 +37,13 @@ enum instruction : unsigned INS_lea, // Not a real instruction. It is used for load the address of stack locals #elif defined(TARGET_ARM64) - #define INST1(id, nm, fp, ldst, fmt, e1 ) INS_##id, - #define INST2(id, nm, fp, ldst, fmt, e1, e2 ) INS_##id, - #define INST3(id, nm, fp, ldst, fmt, e1, e2, e3 ) INS_##id, - #define INST4(id, nm, fp, ldst, fmt, e1, e2, e3, e4 ) INS_##id, - #define INST5(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5 ) INS_##id, - #define INST6(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6 ) INS_##id, - #define INST9(id, nm, fp, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) INS_##id, + #define INST1(id, nm, ldst, fmt, e1 ) INS_##id, + #define INST2(id, nm, ldst, fmt, e1, e2 ) INS_##id, + #define INST3(id, nm, ldst, fmt, e1, e2, e3 ) INS_##id, + #define INST4(id, nm, ldst, fmt, e1, e2, e3, e4 ) INS_##id, + #define INST5(id, nm, ldst, fmt, e1, e2, e3, e4, e5 ) INS_##id, + #define INST6(id, nm, ldst, fmt, e1, e2, e3, e4, e5, e6 ) INS_##id, + #define INST9(id, nm, ldst, fmt, e1, e2, e3, e4, e5, e6, e7, e8, e9) INS_##id, #include "instrs.h" INS_lea, // Not a real instruction. It is used for load the address of stack locals diff --git a/src/coreclr/src/jit/instrsarm64.h b/src/coreclr/src/jit/instrsarm64.h index c65ecdf9248043..41d33443c68d3a 100644 --- a/src/coreclr/src/jit/instrsarm64.h +++ b/src/coreclr/src/jit/instrsarm64.h @@ -7,14 +7,17 @@ * * id -- the enum name for the instruction * nm -- textual name (for assembly dipslay) - * fp -- floating point instruction - * ld/st/cmp -- load/store/compare instruction + * info -- miscellaneous instruction info (load/store/compare/ASIMD right shift) * fmt -- encoding format used by this instruction * e1 -- encoding 1 * e2 -- encoding 2 * e3 -- encoding 3 * e4 -- encoding 4 * e5 -- encoding 5 + * e6 -- encoding 6 + * e7 -- encoding 7 + * e8 -- encoding 8 + * e9 -- encoding 9 * ******************************************************************************/ @@ -45,7 +48,7 @@ #endif /*****************************************************************************/ -/* The following is ARM64-specific */ +/* The following is ARM64-specific */ /*****************************************************************************/ // If you're adding a new instruction: @@ -54,10 +57,10 @@ // emitInsMayWriteMultipleRegs in emitArm64.cpp. // clang-format off -INST9(invalid, "INVALID", 0, 0, IF_NONE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE) +INST9(invalid, "INVALID", 0, IF_NONE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE, BAD_CODE) -// enum name FP LD/ST DR_2E DR_2G DI_1B DI_1D DV_3C DV_2B DV_2C DV_2E DV_2F -INST9(mov, "mov", 0, 0, IF_EN9, 0x2A0003E0, 0x11000000, 0x52800000, 0x320003E0, 0x0EA01C00, 0x0E003C00, 0x4E001C00, 0x5E000400, 0x6E000400) +// enum name info DR_2E DR_2G DI_1B DI_1D DV_3C DV_2B DV_2C DV_2E DV_2F +INST9(mov, "mov", 0, IF_EN9, 0x2A0003E0, 0x11000000, 0x52800000, 0x320003E0, 0x0EA01C00, 0x0E003C00, 0x4E001C00, 0x5E000400, 0x6E000400) // mov Rd,Rm DR_2E X0101010000mmmmm 00000011111ddddd 2A00 03E0 // mov Rd,Rn DR_2G X001000100000000 000000nnnnnddddd 1100 0000 mov to/from SP only // mov Rd,imm(i16,hw) DI_1B X10100101hwiiiii iiiiiiiiiiiddddd 5280 0000 imm(i16,hw) @@ -68,8 +71,8 @@ INST9(mov, "mov", 0, 0, IF_EN9, 0x2A0003E0, 0x11000000, 0x52800000, // mov Vd,Vn[] DV_2E 01011110000iiiii 000001nnnnnddddd 5E00 0400 Vd,Vn[] (scalar by elem) // mov Vd[],Vn[] DV_2F 01101110000iiiii 0jjjj1nnnnnddddd 6E00 0400 Vd[],Vn[] (from/to elem) -// enum name FP LD/ST DR_3A DR_3B DR_3C DI_2A DV_3A DV_3E -INST6(add, "add", 0, 0, IF_EN6A, 0x0B000000, 0x0B000000, 0x0B200000, 0x11000000, 0x0E208400, 0x5EE08400) +// enum name info DR_3A DR_3B DR_3C DI_2A DV_3A DV_3E +INST6(add, "add", 0, IF_EN6A, 0x0B000000, 0x0B000000, 0x0B200000, 0x11000000, 0x0E208400, 0x5EE08400) // add Rd,Rn,Rm DR_3A X0001011000mmmmm 000000nnnnnddddd 0B00 0000 Rd,Rn,Rm // add Rd,Rn,(Rm,shk,imm) DR_3B X0001011sh0mmmmm ssssssnnnnnddddd 0B00 0000 Rm {LSL,LSR,ASR} imm(0-63) // add Rd,Rn,(Rm,ext,shl) DR_3C X0001011001mmmmm ooosssnnnnnddddd 0B20 0000 ext(Rm) LSL imm(0-4) @@ -77,7 +80,7 @@ INST6(add, "add", 0, 0, IF_EN6A, 0x0B000000, 0x0B000000, 0x0B200000, // add Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 100001nnnnnddddd 0E20 8400 Vd,Vn,Vm (vector) // add Vd,Vn,Vm DV_3E 01011110111mmmmm 100001nnnnnddddd 5EE0 8400 Vd,Vn,Vm (scalar) -INST6(sub, "sub", 0, 0, IF_EN6A, 0x4B000000, 0x4B000000, 0x4B200000, 0x51000000, 0x2E208400, 0x7EE08400) +INST6(sub, "sub", 0, IF_EN6A, 0x4B000000, 0x4B000000, 0x4B200000, 0x51000000, 0x2E208400, 0x7EE08400) // sub Rd,Rn,Rm DR_3A X1001011000mmmmm 000000nnnnnddddd 4B00 0000 Rd,Rn,Rm // sub Rd,Rn,(Rm,shk,imm) DR_3B X1001011sh0mmmmm ssssssnnnnnddddd 4B00 0000 Rm {LSL,LSR,ASR} imm(0-63) // sub Rd,Rn,(Rm,ext,shl) DR_3C X1001011001mmmmm ooosssnnnnnddddd 4B20 0000 ext(Rm) LSL imm(0-4) @@ -85,1483 +88,1774 @@ INST6(sub, "sub", 0, 0, IF_EN6A, 0x4B000000, 0x4B000000, 0x4B200000, // sub Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 100001nnnnnddddd 2E20 8400 Vd,Vn,Vm (vector) // sub Vd,Vn,Vm DV_3E 01111110111mmmmm 100001nnnnnddddd 7EE0 8400 Vd,Vn,Vm (scalar) -// enum name FP LD/ST LS_2D LS_3F LS_2E LS_2F LS_3G LS_2G -INST6(ld1, "ld1", 0, LD, IF_EN6B, 0x0C407000, 0x0CC07000, 0x0CDF7000, 0x0D400000, 0x0DC00000, 0x0DDF0000) - // C7.2.170 LD1 (multiple structures, one register variant) +// enum name info LS_2D LS_3F LS_2E LS_2F LS_3G LS_2G +INST6(ld1, "ld1", LD, IF_EN6B, 0x0C407000, 0x0CC07000, 0x0CDF7000, 0x0D400000, 0x0DC00000, 0x0DDF0000) + // LD1 (multiple structures, one register variant) // ld1 {Vt},[Xn] LS_2D 0Q00110001000000 0111ssnnnnnttttt 0C40 7000 base register // ld1 {Vt},[Xn],Xm LS_3F 0Q001100110mmmmm 0111ssnnnnnttttt 0CC0 7000 post-indexed by a register // ld1 {Vt},[Xn],#imm LS_2E 0Q00110011011111 0111ssnnnnnttttt 0CDF 7000 post-indexed by an immediate - // C7.2.171 LD1 (single structure) + // LD1 (single structure) // ld1 {Vt}[],[Xn] LS_2F 0Q00110101000000 xx0Sssnnnnnttttt 0D40 0000 base register // ld1 {Vt}[],[Xn],Xm LS_3G 0Q001101110mmmmm xx0Sssnnnnnttttt 0DC0 0000 post-indexed by a register // ld1 {Vt}[],[Xn],#imm LS_2G 0Q00110111011111 xx0Sssnnnnnttttt 0DDF 0000 post-indexed by an immediate -INST6(ld2, "ld2", 0, LD, IF_EN6B, 0x0C408000, 0x0CC08000, 0x0CDF8000, 0x0D600000, 0x0DE00000, 0x0DFF0000) - // C7.2.173 LD2 (multiple structures) +INST6(ld2, "ld2", LD, IF_EN6B, 0x0C408000, 0x0CC08000, 0x0CDF8000, 0x0D600000, 0x0DE00000, 0x0DFF0000) + // LD2 (multiple structures) // ld2 {Vt,Vt2},[Xn] LS_2D 0Q00110001000000 1000ssnnnnnttttt 0C40 8000 base register // ld2 {Vt,Vt2},[Xn],Xm LS_3F 0Q001100110mmmmm 1000ssnnnnnttttt 0CC0 8000 post-indexed by a register // ld2 {Vt,Vt2},[Xn],#imm LS_2E 0Q001100110mmmmm 1000ssnnnnnttttt 0CDF 8000 post-indexed by an immediate - // C7.2.174 LD2 (single structure) + // LD2 (single structure) // ld2 {Vt,Vt2}[],[Xn] LS_2F 0Q00110101100000 xx0Sssnnnnnttttt 0D60 0000 base register // ld2 {Vt,Vt2}[],[Xn],Xm LS_3G 0Q001101111mmmmm xx0Sssnnnnnttttt 0DE0 0000 post-indexed by a register // ld2 {Vt,Vt2}[],[Xn],#imm LS_2G 0Q00110111111111 xx0Sssnnnnnttttt 0DFF 0000 post-indexed by an immediate -INST6(ld3, "ld3", 0, LD, IF_EN6B, 0x0C404000, 0x0CC04000, 0x0CDF4000, 0x0D402000, 0x0DC02000, 0x0DDF2000) - // C7.2.176 LD3 (multiple structures) +INST6(ld3, "ld3", LD, IF_EN6B, 0x0C404000, 0x0CC04000, 0x0CDF4000, 0x0D402000, 0x0DC02000, 0x0DDF2000) + // LD3 (multiple structures) // ld3 {Vt-Vt3},[Xn] LS_2D 0Q00110001000000 0100ssnnnnnttttt 0C40 4000 base register // ld3 {Vt-Vt3},[Xn],Xm LS_3F 0Q001100110mmmmm 0100ssnnnnnttttt 0CC0 4000 post-indexed by a register // ld3 {Vt-Vt3},[Xn],#imm LS_2E 0Q001100110mmmmm 0100ssnnnnnttttt 0CDF 4000 post-indexed by an immediate - // C7.2.177 LD3 (single structure) + // LD3 (single structure) // ld3 {Vt-Vt3}[],[Xn] LS_2F 0Q00110101000000 xx1Sssnnnnnttttt 0D40 2000 base register // ld3 {Vt-Vt3}[],[Xn],Xm LS_3G 0Q001101110mmmmm xx1Sssnnnnnttttt 0DC0 2000 post-indexed by a register // ld3 {Vt-Vt3}[],[Xn],#imm LS_2G 0Q00110111011111 xx1Sssnnnnnttttt 0DDF 2000 post-indexed by an immediate -INST6(ld4, "ld4", 0, LD, IF_EN6B, 0x0C400000, 0x0CC00000, 0x0CDF0000, 0x0D602000, 0x0DE02000, 0x0DFF2000) - // C7.2.179 LD4 (multiple structures) +INST6(ld4, "ld4", LD, IF_EN6B, 0x0C400000, 0x0CC00000, 0x0CDF0000, 0x0D602000, 0x0DE02000, 0x0DFF2000) + // LD4 (multiple structures) // ld4 {Vt-Vt4},[Xn] LS_2D 0Q00110001000000 0000ssnnnnnttttt 0C40 0000 base register // ld4 {Vt-Vt4},[Xn],Xm LS_3F 0Q001100110mmmmm 0000ssnnnnnttttt 0CC0 0000 post-indexed by a register // ld4 {Vt-Vt4},[Xn],#imm LS_2E 0Q00110011011111 0000ssnnnnnttttt 0CDF 0000 post-indexed by an immediate - // C7.2.180 LD4 (single structure) + // LD4 (single structure) // ld4 {Vt-Vt4}[],[Xn] LS_2F 0Q00110101100000 xx1Sssnnnnnttttt 0D60 2000 base register // ld4 {Vt-Vt4}[],[Xn],Xm LS_3G 0Q001101111mmmmm xx1Sssnnnnnttttt 0DE0 2000 post-indexed by a register // ld4 {Vt-Vt4}[],[Xn],#imm LS_2G 0Q00110111111111 xx1Sssnnnnnttttt 0DFF 2000 post-indexed by an immediate -INST6(st1, "st1", 0, LD, IF_EN6B, 0x0C007000, 0x0C807000, 0x0C9F7000, 0x0D000000, 0x0D800000, 0x0D9F0000) - // C7.2.313 ST1 (multiple structures, one register variant) +INST6(st1, "st1", LD, IF_EN6B, 0x0C007000, 0x0C807000, 0x0C9F7000, 0x0D000000, 0x0D800000, 0x0D9F0000) + // ST1 (multiple structures, one register variant) // st1 {Vt},[Xn] LS_2D 0Q00110000000000 0111ssnnnnnttttt 0C00 7000 base register // st1 {Vt},[Xn],Xm LS_3F 0Q001100100mmmmm 0111ssnnnnnttttt 0C80 7000 post-indexed by a register // st1 {Vt},[Xn],#imm LS_2E 0Q00110010011111 0111ssnnnnnttttt 0C9F 7000 post-indexed by an immediate - // C7.2.314 ST1 (single structure) + // ST1 (single structure) // st1 {Vt}[],[Xn] LS_2F 0Q00110100000000 xx0Sssnnnnnttttt 0D00 0000 base register // st1 {Vt}[],[Xn],Xm LS_3G 0Q001101100mmmmm xx0Sssnnnnnttttt 0D80 0000 post-indexed by a register // st1 {Vt}[],[Xn],#imm LS_2G 0Q00110110011111 xx0Sssnnnnnttttt 0D9F 0000 post-indexed by an immediate -INST6(st2, "st2", 0, ST, IF_EN6B, 0x0C008000, 0x0C808000, 0x0C9F8000, 0x0D200000, 0x0DA00000, 0x0DBF0000) - // C7.2.315 ST2 (multiple structures) +INST6(st2, "st2", ST, IF_EN6B, 0x0C008000, 0x0C808000, 0x0C9F8000, 0x0D200000, 0x0DA00000, 0x0DBF0000) + // ST2 (multiple structures) // st2 {Vt,Vt2},[Xn] LS_2D 0Q00110000000000 1000ssnnnnnttttt 0C00 8000 base register // st2 {Vt,Vt2},[Xn],Xm LS_3F 0Q001100100mmmmm 1000ssnnnnnttttt 0C80 8000 post-indexed by a register // st2 {Vt,Vt2},[Xn],#imm LS_2E 0Q00110010011111 1000ssnnnnnttttt 0C9F 8000 post-indexed by an immediate - // C7.2.316 ST2 (single structure) + // ST2 (single structure) // st2 {Vt,Vt2}[],[Xn] LS_2F 0Q00110100100000 xx0Sssnnnnnttttt 0D20 0000 base register // st2 {Vt,Vt2}[],[Xn],Xm LS_3G 0Q001101101mmmmm xx0Sssnnnnnttttt 0DA0 0000 post-indexed by a register // st2 {Vt,Vt2}[],[Xn],#imm LS_2G 0Q00110110111111 xx0Sssnnnnnttttt 0DBF 0000 post-indexed by an immediate -INST6(st3, "st3", 0, ST, IF_EN6B, 0x0C004000, 0x0C804000, 0x0C9F4000, 0x0D002000, 0x0D802000, 0x0D9F2000) - // C7.2.317 ST3 (multiple structures) +INST6(st3, "st3", ST, IF_EN6B, 0x0C004000, 0x0C804000, 0x0C9F4000, 0x0D002000, 0x0D802000, 0x0D9F2000) + // ST3 (multiple structures) // st3 {Vt-Vt3},[Xn] LS_2D 0Q00110000000000 0100ssnnnnnttttt 0C00 4000 base register // st3 {Vt-Vt3},[Xn],Xm LS_3F 0Q001100100mmmmm 0100ssnnnnnttttt 0C80 4000 post-indexed by a register // st3 {Vt-Vt3},[Xn],#imm LS_2E 0Q00110010011111 0100ssnnnnnttttt 0C9F 4000 post-indexed by an immediate - // C7.2.318 ST3 (single structure) + // ST3 (single structure) // st3 {Vt-Vt3}[],[Xn] LS_2F 0Q00110100000000 xx1Sssnnnnnttttt 0D00 2000 base register // st3 {Vt-Vt3}[],[Xn],Xm LS_3G 0Q001101100mmmmm xx1Sssnnnnnttttt 0D80 2000 post-indexed by a register // st3 {Vt-Vt3}[],[Xn],#imm LS_2G 0Q00110110011111 xx1Sssnnnnnttttt 0D9F 2000 post-indexed by an immediate -INST6(st4, "st4", 0, ST, IF_EN6B, 0x0C000000, 0x0C800000, 0x0C9F0000, 0x0D202000, 0x0DA02000, 0x0DBF2000) - // C7.2.319 ST4 (multiple structures) +INST6(st4, "st4", ST, IF_EN6B, 0x0C000000, 0x0C800000, 0x0C9F0000, 0x0D202000, 0x0DA02000, 0x0DBF2000) + // ST4 (multiple structures) // st4 {Vt-Vt4},[Xn] LS_2D 0Q00110000000000 0000ssnnnnnttttt 0C00 0000 base register // st4 {Vt-Vt4},[Xn],Xm LS_3F 0Q001100100mmmmm 0000ssnnnnnttttt 0C80 0000 post-indexed by a register // st4 {Vt-Vt4},[Xn],#imm LS_2E 0Q00110010011111 0000ssnnnnnttttt 0C9F 0000 post-indexed by an immediate - // C7.2.320 ST4 (single structure) + // ST4 (single structure) // st4 {Vt-Vt4}[],[Xn] LS_2F 0Q00110100100000 xx1Sssnnnnnttttt 0D20 2000 base register // st4 {Vt-Vt4}[],[Xn],Xm LS_3G 0Q001101101mmmmm xx1Sssnnnnnttttt 0DA0 2000 post-indexed by a register // st4 {Vt-Vt4}[],[Xn],#imm LS_2G 0Q00110110111111 xx1Sssnnnnnttttt 0DBF 2000 post-indexed by an immediate -// enum name FP LD/ST LS_2A LS_2B LS_2C LS_3A LS_1A -INST5(ldr, "ldr", 0,LD, IF_EN5A, 0xB9400000, 0xB9400000, 0xB8400000, 0xB8600800, 0x18000000) +// enum name info LS_2A LS_2B LS_2C LS_3A LS_1A +INST5(ldr, "ldr", LD, IF_EN5A, 0xB9400000, 0xB9400000, 0xB8400000, 0xB8600800, 0x18000000) // ldr Rt,[Xn] LS_2A 1X11100101000000 000000nnnnnttttt B940 0000 // ldr Rt,[Xn+pimm12] LS_2B 1X11100101iiiiii iiiiiinnnnnttttt B940 0000 imm(0-4095<<{2,3}) // ldr Rt,[Xn+simm9] LS_2C 1X111000010iiiii iiiiPPnnnnnttttt B840 0000 [Xn imm(-256..+255) pre/post/no inc] // ldr Rt,[Xn,(Rm,ext,shl)] LS_3A 1X111000011mmmmm oooS10nnnnnttttt B860 0800 [Xn, ext(Rm) LSL {0,2,3}] // ldr Vt/Rt,[PC+simm19<<2] LS_1A XX011V00iiiiiiii iiiiiiiiiiittttt 1800 0000 [PC +- imm(1MB)] -INST5(ldrsw, "ldrsw", 0,LD, IF_EN5A, 0xB9800000, 0xB9800000, 0xB8800000, 0xB8A00800, 0x98000000) +INST5(ldrsw, "ldrsw", LD, IF_EN5A, 0xB9800000, 0xB9800000, 0xB8800000, 0xB8A00800, 0x98000000) // ldrsw Rt,[Xn] LS_2A 1011100110000000 000000nnnnnttttt B980 0000 // ldrsw Rt,[Xn+pimm12] LS_2B 1011100110iiiiii iiiiiinnnnnttttt B980 0000 imm(0-4095<<2) // ldrsw Rt,[Xn+simm9] LS_2C 10111000100iiiii iiiiPPnnnnnttttt B880 0000 [Xn imm(-256..+255) pre/post/no inc] // ldrsw Rt,[Xn,(Rm,ext,shl)] LS_3A 10111000101mmmmm oooS10nnnnnttttt B8A0 0800 [Xn, ext(Rm) LSL {0,2}] // ldrsw Rt,[PC+simm19<<2] LS_1A 10011000iiiiiiii iiiiiiiiiiittttt 9800 0000 [PC +- imm(1MB)] -// enum name FP LD/ST DV_2G DV_2H DV_2I DV_1A DV_1B -INST5(fmov, "fmov", 0, 0, IF_EN5B, 0x1E204000, 0x1E260000, 0x1E270000, 0x1E201000, 0x0F00F400) +// enum name info DV_2G DV_2H DV_2I DV_1A DV_1B +INST5(fmov, "fmov", 0, IF_EN5B, 0x1E204000, 0x1E260000, 0x1E270000, 0x1E201000, 0x0F00F400) // fmov Vd,Vn DV_2G 000111100X100000 010000nnnnnddddd 1E20 4000 Vd,Vn (scalar) // fmov Rd,Vn DV_2H X00111100X100110 000000nnnnnddddd 1E26 0000 Rd,Vn (scalar, to general) // fmov Vd,Rn DV_2I X00111100X100111 000000nnnnnddddd 1E27 0000 Vd,Rn (scalar, from general) // fmov Vd,immfp DV_1A 000111100X1iiiii iii10000000ddddd 1E20 1000 Vd,immfp (scalar) // fmov Vd,immfp DV_1B 0QX0111100000iii 111101iiiiiddddd 0F00 F400 Vd,immfp (immediate vector) -// enum name FP LD/ST DR_3A DR_3B DI_2C DV_3C DV_1B -INST5(orr, "orr", 0, 0, IF_EN5C, 0x2A000000, 0x2A000000, 0x32000000, 0x0EA01C00, 0x0F001400) +// enum name info DR_3A DR_3B DI_2C DV_3C DV_1B +INST5(orr, "orr", 0, IF_EN5C, 0x2A000000, 0x2A000000, 0x32000000, 0x0EA01C00, 0x0F001400) // orr Rd,Rn,Rm DR_3A X0101010000mmmmm 000000nnnnnddddd 2A00 0000 // orr Rd,Rn,(Rm,shk,imm) DR_3B X0101010sh0mmmmm iiiiiinnnnnddddd 2A00 0000 Rm {LSL,LSR,ASR,ROR} imm(0-63) // orr Rd,Rn,imm(N,r,s) DI_2C X01100100Nrrrrrr ssssssnnnnnddddd 3200 0000 imm(N,r,s) // orr Vd,Vn,Vm DV_3C 0Q001110101mmmmm 000111nnnnnddddd 0EA0 1C00 Vd,Vn,Vm // orr Vd,imm8 DV_1B 0Q00111100000iii ---101iiiiiddddd 0F00 1400 Vd imm8 (immediate vector) -// enum name FP LD/ST LS_2A LS_2B LS_2C LS_3A -INST4(ldrb, "ldrb", 0,LD, IF_EN4A, 0x39400000, 0x39400000, 0x38400000, 0x38600800) +// enum name info LS_2A LS_2B LS_2C LS_3A +INST4(ldrb, "ldrb", LD, IF_EN4A, 0x39400000, 0x39400000, 0x38400000, 0x38600800) // ldrb Rt,[Xn] LS_2A 0011100101000000 000000nnnnnttttt 3940 0000 // ldrb Rt,[Xn+pimm12] LS_2B 0011100101iiiiii iiiiiinnnnnttttt 3940 0000 imm(0-4095) // ldrb Rt,[Xn+simm9] LS_2C 00111000010iiiii iiiiPPnnnnnttttt 3840 0000 [Xn imm(-256..+255) pre/post/no inc] // ldrb Rt,[Xn,(Rm,ext,shl)] LS_3A 00111000011mmmmm oooS10nnnnnttttt 3860 0800 [Xn, ext(Rm)] -INST4(ldrh, "ldrh", 0,LD, IF_EN4A, 0x79400000, 0x79400000, 0x78400000, 0x78600800) +INST4(ldrh, "ldrh", LD, IF_EN4A, 0x79400000, 0x79400000, 0x78400000, 0x78600800) // ldrh Rt,[Xn] LS_2A 0111100101000000 000000nnnnnttttt 7940 0000 // ldrh Rt,[Xn+pimm12] LS_2B 0111100101iiiiii iiiiiinnnnnttttt 7940 0000 imm(0-4095<<1) // ldrh Rt,[Xn+simm9] LS_2C 01111000010iiiii iiiiPPnnnnnttttt 7840 0000 [Xn imm(-256..+255) pre/post/no inc] // ldrh Rt,[Xn,(Rm,ext,shl)] LS_3A 01111000011mmmmm oooS10nnnnnttttt 7860 0800 [Xn, ext(Rm) LSL {0,1}] -INST4(ldrsb, "ldrsb", 0,LD, IF_EN4A, 0x39800000, 0x39800000, 0x38800000, 0x38A00800) +INST4(ldrsb, "ldrsb", LD, IF_EN4A, 0x39800000, 0x39800000, 0x38800000, 0x38A00800) // ldrsb Rt,[Xn] LS_2A 001110011X000000 000000nnnnnttttt 3980 0000 // ldrsb Rt,[Xn+pimm12] LS_2B 001110011Xiiiiii iiiiiinnnnnttttt 3980 0000 imm(0-4095) // ldrsb Rt,[Xn+simm9] LS_2C 001110001X0iiiii iiii01nnnnnttttt 3880 0000 [Xn imm(-256..+255) pre/post/no inc] // ldrsb Rt,[Xn,(Rm,ext,shl)] LS_3A 001110001X1mmmmm oooS10nnnnnttttt 38A0 0800 [Xn, ext(Rm)] -INST4(ldrsh, "ldrsh", 0,LD, IF_EN4A, 0x79800000, 0x79800000, 0x78800000, 0x78A00800) +INST4(ldrsh, "ldrsh", LD, IF_EN4A, 0x79800000, 0x79800000, 0x78800000, 0x78A00800) // ldrsh Rt,[Xn] LS_2A 011110011X000000 000000nnnnnttttt 7980 0000 // ldrsh Rt,[Xn+pimm12] LS_2B 011110011Xiiiiii iiiiiinnnnnttttt 7980 0000 imm(0-4095<<1) // ldrsh Rt,[Xn+simm9] LS_2C 011110001X0iiiii iiiiPPnnnnnttttt 7880 0000 [Xn imm(-256..+255) pre/post/no inc] // ldrsh Rt,[Xn,(Rm,ext,shl)] LS_3A 011110001X1mmmmm oooS10nnnnnttttt 78A0 0800 [Xn, ext(Rm) LSL {0,1}] -INST4(str, "str", 0,ST, IF_EN4A, 0xB9000000, 0xB9000000, 0xB8000000, 0xB8200800) +INST4(str, "str", ST, IF_EN4A, 0xB9000000, 0xB9000000, 0xB8000000, 0xB8200800) // str Rt,[Xn] LS_2A 1X11100100000000 000000nnnnnttttt B900 0000 // str Rt,[Xn+pimm12] LS_2B 1X11100100iiiiii iiiiiinnnnnttttt B900 0000 imm(0-4095<<{2,3}) // str Rt,[Xn+simm9] LS_2C 1X111000000iiiii iiiiPPnnnnnttttt B800 0000 [Xn imm(-256..+255) pre/post/no inc] // str Rt,[Xn,(Rm,ext,shl)] LS_3A 1X111000001mmmmm oooS10nnnnnttttt B820 0800 [Xn, ext(Rm)] -INST4(strb, "strb", 0,ST, IF_EN4A, 0x39000000, 0x39000000, 0x38000000, 0x38200800) +INST4(strb, "strb", ST, IF_EN4A, 0x39000000, 0x39000000, 0x38000000, 0x38200800) // strb Rt,[Xn] LS_2A 0011100100000000 000000nnnnnttttt 3900 0000 // strb Rt,[Xn+pimm12] LS_2B 0011100100iiiiii iiiiiinnnnnttttt 3900 0000 imm(0-4095) // strb Rt,[Xn+simm9] LS_2C 00111000000iiiii iiiiPPnnnnnttttt 3800 0000 [Xn imm(-256..+255) pre/post/no inc] // strb Rt,[Xn,(Rm,ext,shl)] LS_3A 00111000001mmmmm oooS10nnnnnttttt 3820 0800 [Xn, ext(Rm)] -INST4(strh, "strh", 0,ST, IF_EN4A, 0x79000000, 0x79000000, 0x78000000, 0x78200800) +INST4(strh, "strh", ST, IF_EN4A, 0x79000000, 0x79000000, 0x78000000, 0x78200800) // strh Rt,[Xn] LS_2A 0111100100000000 000000nnnnnttttt 7900 0000 // strh Rt,[Xn+pimm12] LS_2B 0111100100iiiiii iiiiiinnnnnttttt 7900 0000 imm(0-4095<<1) // strh Rt,[Xn+simm9] LS_2C 01111000000iiiii iiiiPPnnnnnttttt 7800 0000 [Xn imm(-256..+255) pre/post/no inc] // strh Rt,[Xn,(Rm,ext,shl)] LS_3A 01111000001mmmmm oooS10nnnnnttttt 7820 0800 [Xn, ext(Rm)] -// enum name FP LD/ST DR_3A DR_3B DR_3C DI_2A -INST4(adds, "adds", 0, 0, IF_EN4B, 0x2B000000, 0x2B000000, 0x2B200000, 0x31000000) +// enum name info DR_3A DR_3B DR_3C DI_2A +INST4(adds, "adds", 0, IF_EN4B, 0x2B000000, 0x2B000000, 0x2B200000, 0x31000000) // adds Rd,Rn,Rm DR_3A X0101011000mmmmm 000000nnnnnddddd 2B00 0000 // adds Rd,Rn,(Rm,shk,imm) DR_3B X0101011sh0mmmmm ssssssnnnnnddddd 2B00 0000 Rm {LSL,LSR,ASR} imm(0-63) // adds Rd,Rn,(Rm,ext,shl) DR_3C X0101011001mmmmm ooosssnnnnnddddd 2B20 0000 ext(Rm) LSL imm(0-4) // adds Rd,Rn,i12 DI_2A X0110001shiiiiii iiiiiinnnnnddddd 3100 0000 imm(i12,sh) -INST4(subs, "subs", 0, 0, IF_EN4B, 0x6B000000, 0x6B000000, 0x6B200000, 0x71000000) +INST4(subs, "subs", 0, IF_EN4B, 0x6B000000, 0x6B000000, 0x6B200000, 0x71000000) // subs Rd,Rn,Rm DR_3A X1101011000mmmmm 000000nnnnnddddd 6B00 0000 // subs Rd,Rn,(Rm,shk,imm) DR_3B X1101011sh0mmmmm ssssssnnnnnddddd 6B00 0000 Rm {LSL,LSR,ASR} imm(0-63) // subs Rd,Rn,(Rm,ext,shl) DR_3C X1101011001mmmmm ooosssnnnnnddddd 6B20 0000 ext(Rm) LSL imm(0-4) // subs Rd,Rn,i12 DI_2A X1110001shiiiiii iiiiiinnnnnddddd 7100 0000 imm(i12,sh) -// enum name FP LD/ST DR_2A DR_2B DR_2C DI_1A -INST4(cmp, "cmp", 0,CMP,IF_EN4C, 0x6B00001F, 0x6B00001F, 0x6B20001F, 0x7100001F) +// enum name info DR_2A DR_2B DR_2C DI_1A +INST4(cmp, "cmp", CMP, IF_EN4C, 0x6B00001F, 0x6B00001F, 0x6B20001F, 0x7100001F) // cmp Rn,Rm DR_2A X1101011000mmmmm 000000nnnnn11111 6B00 001F // cmp Rn,(Rm,shk,imm) DR_2B X1101011sh0mmmmm ssssssnnnnn11111 6B00 001F Rm {LSL,LSR,ASR} imm(0-63) // cmp Rn,(Rm,ext,shl) DR_2C X1101011001mmmmm ooosssnnnnn11111 6B20 001F ext(Rm) LSL imm(0-4) // cmp Rn,i12 DI_1A X111000100iiiiii iiiiiinnnnn11111 7100 001F imm(i12,sh) -INST4(cmn, "cmn", 0,CMP,IF_EN4C, 0x2B00001F, 0x2B00001F, 0x2B20001F, 0x3100001F) +INST4(cmn, "cmn", CMP, IF_EN4C, 0x2B00001F, 0x2B00001F, 0x2B20001F, 0x3100001F) // cmn Rn,Rm DR_2A X0101011000mmmmm 000000nnnnn11111 2B00 001F // cmn Rn,(Rm,shk,imm) DR_2B X0101011sh0mmmmm ssssssnnnnn11111 2B00 001F Rm {LSL,LSR,ASR} imm(0-63) // cmn Rn,(Rm,ext,shl) DR_2C X0101011001mmmmm ooosssnnnnn11111 2B20 001F ext(Rm) LSL imm(0-4) // cmn Rn,i12 DI_1A X0110001shiiiiii iiiiiinnnnn11111 3100 001F imm(0-4095) -// enum name FP LD/ST DV_3B DV_3D DV_3BI DV_3DI -INST4(fmul, "fmul", 0, 0, IF_EN4D, 0x2E20DC00, 0x1E200800, 0x0F809000, 0x5F809000) +// enum name info DV_3B DV_3D DV_3BI DV_3DI +INST4(fmul, "fmul", 0, IF_EN4D, 0x2E20DC00, 0x1E200800, 0x0F809000, 0x5F809000) // fmul Vd,Vn,Vm DV_3B 0Q1011100X1mmmmm 110111nnnnnddddd 2E20 DC00 Vd,Vn,Vm (vector) // fmul Vd,Vn,Vm DV_3D 000111100X1mmmmm 000010nnnnnddddd 1E20 0800 Vd,Vn,Vm (scalar) // fmul Vd,Vn,Vm[] DV_3BI 0Q0011111XLmmmmm 1001H0nnnnnddddd 0F80 9000 Vd,Vn,Vm[] (vector by elem) // fmul Vd,Vn,Vm[] DV_3DI 010111111XLmmmmm 1001H0nnnnnddddd 5F80 9000 Vd,Vn,Vm[] (scalar by elem) -INST4(fmulx, "fmulx", 0, 0, IF_EN4D, 0x0E20DC00, 0x5E20DC00, 0x2F809000, 0x7F809000) +INST4(fmulx, "fmulx", 0, IF_EN4D, 0x0E20DC00, 0x5E20DC00, 0x2F809000, 0x7F809000) // fmulx Vd,Vn,Vm DV_3B 0Q0011100X1mmmmm 110111nnnnnddddd 0E20 DC00 Vd,Vn,Vm (vector) // fmulx Vd,Vn,Vm DV_3D 010111100X1mmmmm 110111nnnnnddddd 5E20 DC00 Vd,Vn,Vm (scalar) // fmulx Vd,Vn,Vm[] DV_3BI 0Q1011111XLmmmmm 1001H0nnnnnddddd 2F80 9000 Vd,Vn,Vm[] (vector by elem) // fmulx Vd,Vn,Vm[] DV_3DI 011111111XLmmmmm 1001H0nnnnnddddd 7F80 9000 Vd,Vn,Vm[] (scalar by elem) -// enum name FP LD/ST DR_3A DR_3B DI_2C DV_3C -INST4(and, "and", 0, 0, IF_EN4E, 0x0A000000, 0x0A000000, 0x12000000, 0x0E201C00) +// enum name info DR_3A DR_3B DI_2C DV_3C +INST4(and, "and", 0, IF_EN4E, 0x0A000000, 0x0A000000, 0x12000000, 0x0E201C00) // and Rd,Rn,Rm DR_3A X0001010000mmmmm 000000nnnnnddddd 0A00 0000 // and Rd,Rn,(Rm,shk,imm) DR_3B X0001010sh0mmmmm iiiiiinnnnnddddd 0A00 0000 Rm {LSL,LSR,ASR,ROR} imm(0-63) // and Rd,Rn,imm(N,r,s) DI_2C X00100100Nrrrrrr ssssssnnnnnddddd 1200 0000 imm(N,r,s) // and Vd,Vn,Vm DV_3C 0Q001110001mmmmm 000111nnnnnddddd 0E20 1C00 Vd,Vn,Vm -INST4(eor, "eor", 0, 0, IF_EN4E, 0x4A000000, 0x4A000000, 0x52000000, 0x2E201C00) +INST4(eor, "eor", 0, IF_EN4E, 0x4A000000, 0x4A000000, 0x52000000, 0x2E201C00) // eor Rd,Rn,Rm DR_3A X1001010000mmmmm 000000nnnnnddddd 4A00 0000 // eor Rd,Rn,(Rm,shk,imm) DR_3B X1001010sh0mmmmm iiiiiinnnnnddddd 4A00 0000 Rm {LSL,LSR,ASR,ROR} imm(0-63) // eor Rd,Rn,imm(N,r,s) DI_2C X10100100Nrrrrrr ssssssnnnnnddddd 5200 0000 imm(N,r,s) // eor Vd,Vn,Vm DV_3C 0Q101110001mmmmm 000111nnnnnddddd 2E20 1C00 Vd,Vn,Vm -// enum name FP LD/ST DR_3A DR_3B DV_3C DV_1B -INST4(bic, "bic", 0, 0, IF_EN4F, 0x0A200000, 0x0A200000, 0x0E601C00, 0x2F001400) +// enum name info DR_3A DR_3B DV_3C DV_1B +INST4(bic, "bic", 0, IF_EN4F, 0x0A200000, 0x0A200000, 0x0E601C00, 0x2F001400) // bic Rd,Rn,Rm DR_3A X0001010001mmmmm 000000nnnnnddddd 0A20 0000 // bic Rd,Rn,(Rm,shk,imm) DR_3B X0001010sh1mmmmm iiiiiinnnnnddddd 0A20 0000 Rm {LSL,LSR,ASR,ROR} imm(0-63) // bic Vd,Vn,Vm DV_3C 0Q001110011mmmmm 000111nnnnnddddd 0E60 1C00 Vd,Vn,Vm // bic Vd,imm8 DV_1B 0Q10111100000iii ---101iiiiiddddd 2F00 1400 Vd imm8 (immediate vector) -// enum name FP LD/ST DR_2E DR_2F DV_2M DV_2L -INST4(neg, "neg", 0, 0, IF_EN4G, 0x4B0003E0, 0x4B0003E0, 0x2E20B800, 0x7E20B800) +// enum name info DR_2E DR_2F DV_2M DV_2L +INST4(neg, "neg", 0, IF_EN4G, 0x4B0003E0, 0x4B0003E0, 0x2E20B800, 0x7E20B800) // neg Rd,Rm DR_2E X1001011000mmmmm 00000011111ddddd 4B00 03E0 // neg Rd,(Rm,shk,imm) DR_2F X1001011sh0mmmmm ssssss11111ddddd 4B00 03E0 Rm {LSL,LSR,ASR} imm(0-63) // neg Vd,Vn DV_2M 0Q101110XX100000 101110nnnnnddddd 2E20 B800 Vd,Vn (vector) // neg Vd,Vn DV_2L 01111110XX100000 101110nnnnnddddd 7E20 B800 Vd,Vn (scalar) -// enum name FP LD/ST DV_3E DV_3A DV_2L DV_2M -INST4(cmeq, "cmeq", 0, 0, IF_EN4H, 0x7EE08C00, 0x2E208C00, 0x5E209800, 0x0E209800) +// enum name info DV_3E DV_3A DV_2L DV_2M +INST4(cmeq, "cmeq", 0, IF_EN4H, 0x7EE08C00, 0x2E208C00, 0x5E209800, 0x0E209800) // cmeq Vd,Vn,Vm DV_3E 01111110111mmmmm 100011nnnnnddddd 7EE0 8C00 Vd,Vn,Vm (scalar) // cmeq Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 100011nnnnnddddd 2E20 8C00 Vd,Vn,Vm (vector) // cmeq Vd,Vn DV_2L 01011110XX100000 100110nnnnnddddd 5E20 9800 Vd,Vn (scalar) // cmeq Vd,Vn DV_2M 0Q001110XX100000 100110nnnnnddddd 0E20 9800 Vd,Vn (vector) -INST4(cmge, "cmge", 0, 0, IF_EN4H, 0x5EE03C00, 0x0E203C00, 0x7E208800, 0x2E208800) +INST4(cmge, "cmge", 0, IF_EN4H, 0x5EE03C00, 0x0E203C00, 0x7E208800, 0x2E208800) // cmge Vd,Vn,Vm DV_3E 01011110111mmmmm 001111nnnnnddddd 5EE0 3C00 Vd,Vn,Vm (scalar) // cmge Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 001111nnnnnddddd 0E20 3C00 Vd,Vn,Vm (vector) // cmge Vd,Vn DV_2L 01111110XX100000 100010nnnnnddddd 5E20 8800 Vd,Vn (scalar) // cmge Vd,Vn DV_2M 0Q101110XX100000 100010nnnnnddddd 2E20 8800 Vd,Vn (vector) -INST4(cmgt, "cmgt", 0, 0, IF_EN4H, 0x5EE03400, 0x0E203400, 0x5E208800, 0x0E208800) +INST4(cmgt, "cmgt", 0, IF_EN4H, 0x5EE03400, 0x0E203400, 0x5E208800, 0x0E208800) // cmgt Vd,Vn,Vm DV_3E 01011110111mmmmm 001101nnnnnddddd 5EE0 3400 Vd,Vn,Vm (scalar) // cmgt Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 001101nnnnnddddd 0E20 3400 Vd,Vn,Vm (vector) // cmgt Vd,Vn DV_2L 01011110XX100000 100010nnnnnddddd 5E20 8800 Vd,Vn (scalar) // cmgt Vd,Vn DV_2M 0Q001110XX100000 101110nnnnnddddd 0E20 8800 Vd,Vn (vector) -// enum name FP LD/ST DV_3D DV_3B DV_2G DV_2A -INST4(fcmeq, "fcmeq", 0, 0, IF_EN4I, 0x5E20E400, 0x0E20E400, 0x5EA0D800, 0x0EA0D800) +// enum name info DV_3D DV_3B DV_2G DV_2A +INST4(fcmeq, "fcmeq", 0, IF_EN4I, 0x5E20E400, 0x0E20E400, 0x5EA0D800, 0x0EA0D800) // fcmeq Vd,Vn,Vm DV_3D 010111100X1mmmmm 111001nnnnnddddd 5E20 E400 Vd Vn Vm (scalar) // fcmeq Vd,Vn,Vm DV_3B 0Q0011100X1mmmmm 111001nnnnnddddd 0E20 E400 Vd,Vn,Vm (vector) // fcmeq Vd,Vn DV_2G 010111101X100000 110110nnnnnddddd 5EA0 D800 Vd Vn (scalar) // fcmeq Vd,Vn DV_2A 0Q0011101X100000 110110nnnnnddddd 0EA0 D800 Vd Vn (vector) -INST4(fcmge, "fcmge", 0, 0, IF_EN4I, 0x7E20E400, 0x2E20E400, 0x7EA0C800, 0x2EA0C800) +INST4(fcmge, "fcmge", 0, IF_EN4I, 0x7E20E400, 0x2E20E400, 0x7EA0C800, 0x2EA0C800) // fcmge Vd,Vn,Vm DV_3D 011111100X1mmmmm 111001nnnnnddddd 7E20 E400 Vd Vn Vm (scalar) // fcmge Vd,Vn,Vm DV_3B 0Q1011100X1mmmmm 111001nnnnnddddd 2E20 E400 Vd,Vn,Vm (vector) // fcmge Vd,Vn DV_2G 011111101X100000 110010nnnnnddddd 7EA0 E800 Vd Vn (scalar) // fcmge Vd,Vn DV_2A 0Q1011101X100000 110010nnnnnddddd 2EA0 C800 Vd Vn (vector) -INST4(fcmgt, "fcmgt", 0, 0, IF_EN4I, 0x7EA0E400, 0x2EA0E400, 0x5EA0C800, 0x0EA0C800) +INST4(fcmgt, "fcmgt", 0, IF_EN4I, 0x7EA0E400, 0x2EA0E400, 0x5EA0C800, 0x0EA0C800) // fcmgt Vd,Vn,Vm DV_3D 011111101X1mmmmm 111001nnnnnddddd 7EA0 E400 Vd Vn Vm (scalar) // fcmgt Vd,Vn,Vm DV_3B 0Q1011101X1mmmmm 111001nnnnnddddd 2EA0 E400 Vd,Vn,Vm (vector) // fcmgt Vd,Vn DV_2G 010111101X100000 110010nnnnnddddd 5EA0 E800 Vd Vn (scalar) // fcmgt Vd,Vn DV_2A 0Q0011101X100000 110010nnnnnddddd 0EA0 C800 Vd Vn (vector) -// enum name FP LD/ST DR_3A DR_3B DI_2C -INST3(ands, "ands", 0, 0, IF_EN3A, 0x6A000000, 0x6A000000, 0x72000000) +// enum name info DV_2N DV_2O DV_3E DV_3A +INST4(sqshl, "sqshl", 0, IF_EN4J, 0x5F007400, 0x0F007400, 0x5E204C00, 0x0E204C00) + // sqshl Vd,Vn,imm DV_2N 010111110iiiiiii 011101nnnnnddddd 5F00 7400 Vd Vn imm (left shift - scalar) + // sqshl Vd,Vn,imm DV_2O 0Q0011110iiiiiii 011101nnnnnddddd 0F00 7400 Vd Vn imm (left shift - vector) + // sqshl Vd,Vn,Vm DV_3E 01011110XX1mmmmm 010011nnnnnddddd 5E20 4C00 Vd Vn Vm (scalar) + // sqshl Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 010011nnnnnddddd 0E20 4C00 Vd Vn Vm (vector) + +INST4(uqshl, "uqshl", 0, IF_EN4J, 0x7F007400, 0x2F007400, 0x7E204C00, 0x2E204C00) + // uqshl Vd,Vn,imm DV_2N 011111110iiiiiii 011101nnnnnddddd 7F00 7400 Vd Vn imm (left shift - scalar) + // uqshl Vd,Vn,imm DV_2O 0Q1011110iiiiiii 011101nnnnnddddd 2F00 7400 Vd Vn imm (left shift - vector) + // uqshl Vd,Vn,Vm DV_3E 01111110XX1mmmmm 010011nnnnnddddd 7E20 4C00 Vd Vn Vm (scalar) + // uqshl Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 010011nnnnnddddd 2E20 4C00 Vd Vn Vm (vector) + +// enum name info DR_3A DR_3B DI_2C +INST3(ands, "ands", 0, IF_EN3A, 0x6A000000, 0x6A000000, 0x72000000) // ands Rd,Rn,Rm DR_3A X1101010000mmmmm 000000nnnnnddddd 6A00 0000 // ands Rd,Rn,(Rm,shk,imm) DR_3B X1101010sh0mmmmm iiiiiinnnnnddddd 6A00 0000 Rm {LSL,LSR,ASR,ROR} imm(0-63) // ands Rd,Rn,imm(N,r,s) DI_2C X11100100Nrrrrrr ssssssnnnnnddddd 7200 0000 imm(N,r,s) -// enum name FP LD/ST DR_2A DR_2B DI_1C -INST3(tst, "tst", 0, 0, IF_EN3B, 0x6A00001F, 0x6A00001F, 0x7200001F) +// enum name info DR_2A DR_2B DI_1C +INST3(tst, "tst", 0, IF_EN3B, 0x6A00001F, 0x6A00001F, 0x7200001F) // tst Rn,Rm DR_2A X1101010000mmmmm 000000nnnnn11111 6A00 001F // tst Rn,(Rm,shk,imm) DR_2B X1101010sh0mmmmm iiiiiinnnnn11111 6A00 001F Rm {LSL,LSR,ASR,ROR} imm(0-63) // tst Rn,imm(N,r,s) DI_1C X11100100Nrrrrrr ssssssnnnnn11111 7200 001F imm(N,r,s) -// enum name FP LD/ST DR_3A DR_3B DV_3C -INST3(orn, "orn", 0, 0, IF_EN3C, 0x2A200000, 0x2A200000, 0x0EE01C00) +// enum name info DR_3A DR_3B DV_3C +INST3(orn, "orn", 0, IF_EN3C, 0x2A200000, 0x2A200000, 0x0EE01C00) // orn Rd,Rn,Rm DR_3A X0101010001mmmmm 000000nnnnnddddd 2A20 0000 // orn Rd,Rn,(Rm,shk,imm) DR_3B X0101010sh1mmmmm iiiiiinnnnnddddd 2A20 0000 Rm {LSL,LSR,ASR,ROR} imm(0-63) // orn Vd,Vn,Vm DV_3C 0Q001110111mmmmm 000111nnnnnddddd 0EE0 1C00 Vd,Vn,Vm -// enum name FP LD/ST DV_2C DV_2D DV_2E -INST3(dup, "dup", 0, 0, IF_EN3D, 0x0E000C00, 0x0E000400, 0x5E000400) +// enum name info DV_2C DV_2D DV_2E +INST3(dup, "dup", 0, IF_EN3D, 0x0E000C00, 0x0E000400, 0x5E000400) // dup Vd,Rn DV_2C 0Q001110000iiiii 000011nnnnnddddd 0E00 0C00 Vd,Rn (vector from general) // dup Vd,Vn[] DV_2D 0Q001110000iiiii 000001nnnnnddddd 0E00 0400 Vd,Vn[] (vector by elem) // dup Vd,Vn[] DV_2E 01011110000iiiii 000001nnnnnddddd 5E00 0400 Vd,Vn[] (scalar by elem) -// enum name FP LD/ST DV_3B DV_3BI DV_3DI -INST3(fmla, "fmla", 0, 0, IF_EN3E, 0x0E20CC00, 0x0F801000, 0x5F801000) +// enum name info DV_3B DV_3BI DV_3DI +INST3(fmla, "fmla", 0, IF_EN3E, 0x0E20CC00, 0x0F801000, 0x5F801000) // fmla Vd,Vn,Vm DV_3B 0Q0011100X1mmmmm 110011nnnnnddddd 0E20 CC00 Vd,Vn,Vm (vector) // fmla Vd,Vn,Vm[] DV_3BI 0Q0011111XLmmmmm 0001H0nnnnnddddd 0F80 1000 Vd,Vn,Vm[] (vector by elem) // fmla Vd,Vn,Vm[] DV_3DI 010111111XLmmmmm 0001H0nnnnnddddd 5F80 1000 Vd,Vn,Vm[] (scalar by elem) -INST3(fmls, "fmls", 0, 0, IF_EN3E, 0x0EA0CC00, 0x0F805000, 0x5F805000) +INST3(fmls, "fmls", 0, IF_EN3E, 0x0EA0CC00, 0x0F805000, 0x5F805000) // fmls Vd,Vn,Vm DV_3B 0Q0011101X1mmmmm 110011nnnnnddddd 0EA0 CC00 Vd,Vn,Vm (vector) // fmls Vd,Vn,Vm[] DV_3BI 0Q0011111XLmmmmm 0101H0nnnnnddddd 0F80 5000 Vd,Vn,Vm[] (vector by elem) // fmls Vd,Vn,Vm[] DV_3DI 010111111XLmmmmm 0101H0nnnnnddddd 5F80 5000 Vd,Vn,Vm[] (scalar by elem) -// enum name FP LD/ST DV_2A DV_2G DV_2H -INST3(fcvtas, "fcvtas", 0, 0, IF_EN3F, 0x0E21C800, 0x5E21C800, 0x1E240000) +// enum name info DV_2A DV_2G DV_2H +INST3(fcvtas, "fcvtas", 0, IF_EN3F, 0x0E21C800, 0x5E21C800, 0x1E240000) // fcvtas Vd,Vn DV_2A 0Q0011100X100001 110010nnnnnddddd 0E21 C800 Vd,Vn (vector) // fcvtas Vd,Vn DV_2G 010111100X100001 110010nnnnnddddd 5E21 C800 Vd,Vn (scalar) // fcvtas Rd,Vn DV_2H X00111100X100100 000000nnnnnddddd 1E24 0000 Rd,Vn (scalar, to general) -INST3(fcvtau, "fcvtau", 0, 0, IF_EN3F, 0x2E21C800, 0x7E21C800, 0x1E250000) +INST3(fcvtau, "fcvtau", 0, IF_EN3F, 0x2E21C800, 0x7E21C800, 0x1E250000) // fcvtau Vd,Vn DV_2A 0Q1011100X100001 111010nnnnnddddd 2E21 C800 Vd,Vn (vector) // fcvtau Vd,Vn DV_2G 011111100X100001 111010nnnnnddddd 7E21 C800 Vd,Vn (scalar) // fcvtau Rd,Vn DV_2H X00111100X100101 000000nnnnnddddd 1E25 0000 Rd,Vn (scalar, to general) -INST3(fcvtms, "fcvtms", 0, 0, IF_EN3F, 0x0E21B800, 0x5E21B800, 0x1E300000) +INST3(fcvtms, "fcvtms", 0, IF_EN3F, 0x0E21B800, 0x5E21B800, 0x1E300000) // fcvtms Vd,Vn DV_2A 0Q0011100X100001 101110nnnnnddddd 0E21 B800 Vd,Vn (vector) // fcvtms Vd,Vn DV_2G 010111100X100001 101110nnnnnddddd 5E21 B800 Vd,Vn (scalar) // fcvtms Rd,Vn DV_2H X00111100X110000 000000nnnnnddddd 1E30 0000 Rd,Vn (scalar, to general) -INST3(fcvtmu, "fcvtmu", 0, 0, IF_EN3F, 0x2E21B800, 0x7E21B800, 0x1E310000) +INST3(fcvtmu, "fcvtmu", 0, IF_EN3F, 0x2E21B800, 0x7E21B800, 0x1E310000) // fcvtmu Vd,Vn DV_2A 0Q1011100X100001 101110nnnnnddddd 2E21 B800 Vd,Vn (vector) // fcvtmu Vd,Vn DV_2G 011111100X100001 101110nnnnnddddd 7E21 B800 Vd,Vn (scalar) // fcvtmu Rd,Vn DV_2H X00111100X110001 000000nnnnnddddd 1E31 0000 Rd,Vn (scalar, to general) -INST3(fcvtns, "fcvtns", 0, 0, IF_EN3F, 0x0E21A800, 0x5E21A800, 0x1E200000) +INST3(fcvtns, "fcvtns", 0, IF_EN3F, 0x0E21A800, 0x5E21A800, 0x1E200000) // fcvtns Vd,Vn DV_2A 0Q0011100X100001 101010nnnnnddddd 0E21 A800 Vd,Vn (vector) // fcvtns Vd,Vn DV_2G 010111100X100001 101010nnnnnddddd 5E21 A800 Vd,Vn (scalar) // fcvtns Rd,Vn DV_2H X00111100X100000 000000nnnnnddddd 1E20 0000 Rd,Vn (scalar, to general) -INST3(fcvtnu, "fcvtnu", 0, 0, IF_EN3F, 0x2E21A800, 0x7E21A800, 0x1E210000) +INST3(fcvtnu, "fcvtnu", 0, IF_EN3F, 0x2E21A800, 0x7E21A800, 0x1E210000) // fcvtnu Vd,Vn DV_2A 0Q1011100X100001 101010nnnnnddddd 2E21 A800 Vd,Vn (vector) // fcvtnu Vd,Vn DV_2G 011111100X100001 101010nnnnnddddd 7E21 A800 Vd,Vn (scalar) // fcvtnu Rd,Vn DV_2H X00111100X100001 000000nnnnnddddd 1E21 0000 Rd,Vn (scalar, to general) -INST3(fcvtps, "fcvtps", 0, 0, IF_EN3F, 0x0EA1A800, 0x5EA1A800, 0x1E280000) +INST3(fcvtps, "fcvtps", 0, IF_EN3F, 0x0EA1A800, 0x5EA1A800, 0x1E280000) // fcvtps Vd,Vn DV_2A 0Q0011101X100001 101010nnnnnddddd 0EA1 A800 Vd,Vn (vector) // fcvtps Vd,Vn DV_2G 010111101X100001 101010nnnnnddddd 5EA1 A800 Vd,Vn (scalar) // fcvtps Rd,Vn DV_2H X00111100X101000 000000nnnnnddddd 1E28 0000 Rd,Vn (scalar, to general) -INST3(fcvtpu, "fcvtpu", 0, 0, IF_EN3F, 0x2EA1A800, 0x7EA1A800, 0x1E290000) +INST3(fcvtpu, "fcvtpu", 0, IF_EN3F, 0x2EA1A800, 0x7EA1A800, 0x1E290000) // fcvtpu Vd,Vn DV_2A 0Q1011101X100001 101010nnnnnddddd 2EA1 A800 Vd,Vn (vector) // fcvtpu Vd,Vn DV_2G 011111101X100001 101010nnnnnddddd 7EA1 A800 Vd,Vn (scalar) // fcvtpu Rd,Vn DV_2H X00111100X101001 000000nnnnnddddd 1E29 0000 Rd,Vn (scalar, to general) -INST3(fcvtzs, "fcvtzs", 0, 0, IF_EN3F, 0x0EA1B800, 0x5EA1B800, 0x1E380000) +INST3(fcvtzs, "fcvtzs", 0, IF_EN3F, 0x0EA1B800, 0x5EA1B800, 0x1E380000) // fcvtzs Vd,Vn DV_2A 0Q0011101X100001 101110nnnnnddddd 0EA1 B800 Vd,Vn (vector) // fcvtzs Vd,Vn DV_2G 010111101X100001 101110nnnnnddddd 5EA1 B800 Vd,Vn (scalar) // fcvtzs Rd,Vn DV_2H X00111100X111000 000000nnnnnddddd 1E38 0000 Rd,Vn (scalar, to general) -INST3(fcvtzu, "fcvtzu", 0, 0, IF_EN3F, 0x2EA1B800, 0x7EA1B800, 0x1E390000) +INST3(fcvtzu, "fcvtzu", 0, IF_EN3F, 0x2EA1B800, 0x7EA1B800, 0x1E390000) // fcvtzu Vd,Vn DV_2A 0Q1011101X100001 101110nnnnnddddd 2EA1 B800 Vd,Vn (vector) // fcvtzu Vd,Vn DV_2G 011111101X100001 101110nnnnnddddd 7EA1 B800 Vd,Vn (scalar) // fcvtzu Rd,Vn DV_2H X00111100X111001 000000nnnnnddddd 1E39 0000 Rd,Vn (scalar, to general) -// enum name FP LD/ST DV_2A DV_2G DV_2I -INST3(scvtf, "scvtf", 0, 0, IF_EN3G, 0x0E21D800, 0x5E21D800, 0x1E220000) +// enum name info DV_2A DV_2G DV_2I +INST3(scvtf, "scvtf", 0, IF_EN3G, 0x0E21D800, 0x5E21D800, 0x1E220000) // scvtf Vd,Vn DV_2A 0Q0011100X100001 110110nnnnnddddd 0E21 D800 Vd,Vn (vector) // scvtf Vd,Vn DV_2G 010111100X100001 110110nnnnnddddd 7E21 D800 Vd,Vn (scalar) // scvtf Rd,Vn DV_2I X00111100X100010 000000nnnnnddddd 1E22 0000 Vd,Rn (scalar, from general) -INST3(ucvtf, "ucvtf", 0, 0, IF_EN3G, 0x2E21D800, 0x7E21D800, 0x1E230000) +INST3(ucvtf, "ucvtf", 0, IF_EN3G, 0x2E21D800, 0x7E21D800, 0x1E230000) // ucvtf Vd,Vn DV_2A 0Q1011100X100001 110110nnnnnddddd 2E21 D800 Vd,Vn (vector) // ucvtf Vd,Vn DV_2G 011111100X100001 110110nnnnnddddd 7E21 D800 Vd,Vn (scalar) // ucvtf Rd,Vn DV_2I X00111100X100011 000000nnnnnddddd 1E23 0000 Vd,Rn (scalar, from general) -INST3(mul, "mul", 0, 0, IF_EN3H, 0x1B007C00, 0x0E209C00, 0x0F008000) +INST3(mul, "mul", 0, IF_EN3H, 0x1B007C00, 0x0E209C00, 0x0F008000) // mul Rd,Rn,Rm DR_3A X0011011000mmmmm 011111nnnnnddddd 1B00 7C00 // mul Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 100111nnnnnddddd 0E20 9C00 Vd,Vn,Vm (vector) // mul Vd,Vn,Vm[] DV_3AI 0Q001111XXLMmmmm 1000H0nnnnnddddd 0F00 8000 Vd,Vn,Vm[] (vector by elem) -// enum name FP LD/ST DR_2E DR_2F DV_2M -INST3(mvn, "mvn", 0, 0, IF_EN3I, 0x2A2003E0, 0x2A2003E0, 0x2E205800) +// enum name info DR_2E DR_2F DV_2M +INST3(mvn, "mvn", 0, IF_EN3I, 0x2A2003E0, 0x2A2003E0, 0x2E205800) // mvn Rd,Rm DR_2E X0101010001mmmmm 00000011111ddddd 2A20 03E0 // mvn Rd,(Rm,shk,imm) DR_2F X0101010sh1mmmmm iiiiii11111ddddd 2A20 03E0 Rm {LSL,LSR,ASR} imm(0-63) // mvn Vd,Vn DV_2M 0Q10111000100000 010110nnnnnddddd 2E20 5800 Vd,Vn (vector) -// enum name FP LD/ST LS_2D LS_3F LS_2E -INST3(ld1_2regs,"ld1", 0,LD, IF_EN3J, 0x0C40A000, 0x0CC0A000, 0x0CDFA000) - // C7.2.170 LD1 (multiple structures, two registers variant) +// enum name info LS_2D LS_3F LS_2E +INST3(ld1_2regs, "ld1", LD, IF_EN3J, 0x0C40A000, 0x0CC0A000, 0x0CDFA000) + // LD1 (multiple structures, two registers variant) // ld1 {Vt,Vt2},[Xn] LS_2D 0Q00110001000000 1010ssnnnnnttttt 0C40 A000 base register // ld1 {Vt,Vt2},[Xn],Xm LS_3F 0Q001100110mmmmm 1010ssnnnnnttttt 0CC0 A000 post-indexed by a register // ld1 {Vt,Vt2},[Xn],#imm LS_2E 0Q00110011011111 1010ssnnnnnttttt 0CDF A000 post-indexed by an immediate -INST3(ld1_3regs,"ld1", 0,LD, IF_EN3J, 0x0C406000, 0x0CC06000, 0x0CDF6000) - // C7.2.170 LD1 (multiple structures, three registers variant) +INST3(ld1_3regs, "ld1", LD, IF_EN3J, 0x0C406000, 0x0CC06000, 0x0CDF6000) + // LD1 (multiple structures, three registers variant) // ld1 {Vt-Vt3},[Xn] LS_2D 0Q00110001000000 0110ssnnnnnttttt 0C40 6000 base register // ld1 {Vt-Vt3},[Xn],Xm LS_3F 0Q001100110mmmmm 0110ssnnnnnttttt 0CC0 6000 post-indexed by a register // ld1 {Vt-Vt3},[Xn],#imm LS_2E 0Q00110011011111 0110ssnnnnnttttt 0CDF 6000 post-indexed by an immediate -INST3(ld1_4regs,"ld1", 0,LD, IF_EN3J, 0x0C402000, 0x0CC02000, 0x0CDF2000) - // C7.2.170 LD1 (multiple structures, four registers variant) +INST3(ld1_4regs, "ld1", LD, IF_EN3J, 0x0C402000, 0x0CC02000, 0x0CDF2000) + // LD1 (multiple structures, four registers variant) // ld1 {Vt-Vt4},[Xn] LS_2D 0Q00110001000000 0010ssnnnnnttttt 0C40 2000 base register // ld1 {Vt-Vt4},[Xn],Xm LS_3F 0Q001100110mmmmm 0010ssnnnnnttttt 0CC0 2000 post-indexed by a register // ld1 {Vt-Vt4},[Xn],#imm LS_2E 0Q00110011011111 0010ssnnnnnttttt 0CDF 2000 post-indexed by an immediate -INST3(st1_2regs,"st1", 0,ST, IF_EN3J, 0x0C00A000, 0x0C80A000, 0x0C9FA000) - // C7.2.313 ST1 (multiple structures, two registers variant) +INST3(st1_2regs, "st1", ST, IF_EN3J, 0x0C00A000, 0x0C80A000, 0x0C9FA000) + // ST1 (multiple structures, two registers variant) // st1 {Vt,Vt2},[Xn] LS_2D 0Q00110000000000 1010ssnnnnnttttt 0C00 A000 base register // st1 {Vt,Vt2},[Xn],Xm LS_3F 0Q001100100mmmmm 1010ssnnnnnttttt 0C80 A000 post-indexed by a register // st1 {Vt,Vt2},[Xn],#imm LS_2E 0Q00110010011111 1010ssnnnnnttttt 0C9F A000 post-indexed by an immediate -INST3(st1_3regs,"st1", 0,ST, IF_EN3J, 0x0C006000, 0x0C806000, 0x0C9F6000) - // C7.2.313 ST1 (multiple structures, three registers variant) +INST3(st1_3regs, "st1", ST, IF_EN3J, 0x0C006000, 0x0C806000, 0x0C9F6000) + // ST1 (multiple structures, three registers variant) // st1 {Vt-Vt3},[Xn] LS_2D 0Q00110000000000 0110ssnnnnnttttt 0C00 6000 base register // st1 {Vt-Vt3},[Xn],Xm LS_3F 0Q001100100mmmmm 0110XXnnnnnttttt 0C80 6000 post-indexed by a register // st1 {Vt-Vt3},[Xn],#imm LS_2E 0Q00110010011111 0110XXnnnnnttttt 0C9F 6000 post-indexed by an immediate -INST3(st1_4regs,"st1", 0,ST, IF_EN3J, 0x0C002000, 0x0C802000, 0x0C9F2000) - // C7.2.313 ST1 (multiple structures, four registers variant) +INST3(st1_4regs, "st1", ST, IF_EN3J, 0x0C002000, 0x0C802000, 0x0C9F2000) + // ST1 (multiple structures, four registers variant) // st1 {Vt-Vt4},[Xn] LS_2D 0Q00110000000000 0010XXnnnnnttttt 0C00 2000 base register // st1 {Vt-Vt4},[Xn],Xm LS_3F 0Q001100100mmmmm 0010XXnnnnnttttt 0C80 2000 post-indexed by a register // st1 {Vt-Vt4},[Xn],#imm LS_2E 0Q00110010011111 0010XXnnnnnttttt 0C9F 2000 post-indexed by an immediate -INST3(ld1r, "ld1r", 0,LD, IF_EN3J, 0x0D40C000, 0x0DC0C000, 0x0DDFC000) - // C7.2.172 LD1R +INST3(ld1r, "ld1r", LD, IF_EN3J, 0x0D40C000, 0x0DC0C000, 0x0DDFC000) // ld1r {Vt},[Xn] LS_2D 0Q00110101000000 1100ssnnnnnttttt 0D40 C000 base register // ld1r {Vt},[Xn],Xm LS_3F 0Q001101110mmmmm 1100ssnnnnnttttt 0DC0 C000 post-indexed by a register // ld1r {Vt},[Xn],#1 LS_2E 0Q00110111011111 1100ssnnnnnttttt 0DDF C000 post-indexed by an immediate -INST3(ld2r, "ld2r", 0,LD, IF_EN3J, 0x0D60C000, 0x0DE0C000, 0x0DFFC000) - // C7.2.175 LD2R +INST3(ld2r, "ld2r", LD, IF_EN3J, 0x0D60C000, 0x0DE0C000, 0x0DFFC000) // ld2r {Vt,Vt2},[Xn] LS_2D 0Q00110101100000 1100ssnnnnnttttt 0D60 C000 base register // ld2r {Vt,Vt2},[Xn],Xm LS_3F 0Q001101111mmmmm 1100ssnnnnnttttt 0DE0 C000 post-indexed by a register // ld2r {Vt,Vt2},[Xn],#2 LS_2E 0Q00110111111111 1100ssnnnnnttttt 0DFF C000 post-indexed by an immediate -INST3(ld3r, "ld3r", 0,LD, IF_EN3J, 0x0D40E000, 0x0DC0E000, 0x0DDFE000) - // C7.2.178 LD3R +INST3(ld3r, "ld3r", LD, IF_EN3J, 0x0D40E000, 0x0DC0E000, 0x0DDFE000) // ld3r {Vt-Vt3},[Xn] LS_2D 0Q00110101000000 1110ssnnnnnttttt 0D40 E000 base register // ld3r {Vt-Vt3},[Xn],Xm LS_3F 0Q001101110mmmmm 1110ssnnnnnttttt 0DC0 E000 post-indexed by a register // ld3r {Vt-Vt3},[Xn],#4 LS_2E 0Q00110111011111 1110ssnnnnnttttt 0DDF E000 post-indexed by an immediate -INST3(ld4r, "ld4r", 0,LD, IF_EN3J, 0x0D60E000, 0x0DE0E000, 0x0DFFE000) - // C7.2.181 LD4R +INST3(ld4r, "ld4r", LD, IF_EN3J, 0x0D60E000, 0x0DE0E000, 0x0DFFE000) // ld4r {Vt-Vt4},[Xn] LS_2D 0Q00110101100000 1110ssnnnnnttttt 0D60 E000 base register // ld4r {Vt-Vt4},[Xn],Xm LS_3F 0Q001101111mmmmm 1110ssnnnnnttttt 0DE0 E000 post-indexed by a register // ld4r {Vt-Vt4},[Xn],#8 LS_2E 0Q00110111111111 1110ssnnnnnttttt 0DFF E000 post-indexed by an immediate -// enum name FP LD/ST DR_2E DR_2F -INST2(negs, "negs", 0, 0, IF_EN2A, 0x6B0003E0, 0x6B0003E0) +INST3(smull, "smull", 0, IF_EN3K, 0x9B207C00, 0x0E20C000, 0x0F00A000) + // smull Rd,Rn,Rm DR_3A 10011011001mmmmm 011111nnnnnddddd 9B20 7C00 + // smull Vd,Vn,Vm DV_3H 0000111000100000 1100000000000000 0E20 C000 Vd,Vn,Vm (vector) + // smull Vd,Vn,Vm[] DV_3HI 00001111XXLMmmmm 1010H0nnnnnddddd 0F00 A000 Vd,Vn,Vm[] (vector by elem) + +INST3(umull, "umull", 0, IF_EN3K, 0x9BA07C00, 0x2E20C000, 0x2F00A000) + // umull Rd,Rn,Rm DR_3A 10011011101mmmmm 011111nnnnnddddd 9BA0 7C00 + // umull Vd,Vn,Vm DV_3H 00101110XX1mmmmm 110000nnnnnddddd 2E20 C000 Vd,Vn,Vm (vector) + // umull Vd,Vn,Vm[] DV_3HI 00101111XXLMmmmm 1010H0nnnnnddddd 2F00 A000 Vd,Vn,Vm[] (vector by elem) + +// enum name info DR_2E DR_2F +INST2(negs, "negs", 0, IF_EN2A, 0x6B0003E0, 0x6B0003E0) // negs Rd,Rm DR_2E X1101011000mmmmm 00000011111ddddd 6B00 03E0 // negs Rd,(Rm,shk,imm) DR_2F X1101011sh0mmmmm ssssss11111ddddd 6B00 03E0 Rm {LSL,LSR,ASR} imm(0-63) -// enum name FP LD/ST DR_3A DR_3B -INST2(bics, "bics", 0, 0, IF_EN2B, 0x6A200000, 0x6A200000) +// enum name info DR_3A DR_3B +INST2(bics, "bics", 0, IF_EN2B, 0x6A200000, 0x6A200000) // bics Rd,Rn,Rm DR_3A X1101010001mmmmm 000000nnnnnddddd 6A20 0000 // bics Rd,Rn,(Rm,shk,imm) DR_3B X1101010sh1mmmmm iiiiiinnnnnddddd 6A20 0000 Rm {LSL,LSR,ASR,ROR} imm(0-63) -INST2(eon, "eon", 0, 0, IF_EN2B, 0x4A200000, 0x4A200000) +INST2(eon, "eon", 0, IF_EN2B, 0x4A200000, 0x4A200000) // eon Rd,Rn,Rm DR_3A X1001010001mmmmm 000000nnnnnddddd 4A20 0000 // eon Rd,Rn,(Rm,shk,imm) DR_3B X1001010sh1mmmmm iiiiiinnnnnddddd 4A20 0000 Rm {LSL,LSR,ASR,ROR} imm(0-63) -// enum name FP LD/ST DR_3A DI_2C -INST2(lsl, "lsl", 0, 0, IF_EN2C, 0x1AC02000, 0x53000000) +// enum name info DR_3A DI_2C +INST2(lsl, "lsl", 0, IF_EN2C, 0x1AC02000, 0x53000000) // lsl Rd,Rn,Rm DR_3A X0011010110mmmmm 001000nnnnnddddd 1AC0 2000 // lsl Rd,Rn,imm6 DI_2D X10100110Xrrrrrr ssssssnnnnnddddd 5300 0000 imm(N,r,s) -INST2(lsr, "lsr", 0, 0, IF_EN2C, 0x1AC02400, 0x53000000) +INST2(lsr, "lsr", 0, IF_EN2C, 0x1AC02400, 0x53000000) // lsr Rd,Rn,Rm DR_3A X0011010110mmmmm 001001nnnnnddddd 1AC0 2400 // lsr Rd,Rn,imm6 DI_2D X10100110Xrrrrrr ssssssnnnnnddddd 5300 0000 imm(N,r,s) -INST2(asr, "asr", 0, 0, IF_EN2C, 0x1AC02800, 0x13000000) +INST2(asr, "asr", 0, IF_EN2C, 0x1AC02800, 0x13000000) // asr Rd,Rn,Rm DR_3A X0011010110mmmmm 001010nnnnnddddd 1AC0 2800 // asr Rd,Rn,imm6 DI_2D X00100110Xrrrrrr ssssssnnnnnddddd 1300 0000 imm(N,r,s) -// enum name FP LD/ST DR_3A DI_2B -INST2(ror, "ror", 0, 0, IF_EN2D, 0x1AC02C00, 0x13800000) +// enum name info DR_3A DI_2B +INST2(ror, "ror", 0, IF_EN2D, 0x1AC02C00, 0x13800000) // ror Rd,Rn,Rm DR_3A X0011010110mmmmm 001011nnnnnddddd 1AC0 2C00 // ror Rd,Rn,imm6 DI_2B X00100111X0nnnnn ssssssnnnnnddddd 1380 0000 imm(0-63) -// enum name FP LD/ST LS_3B LS_3C -INST2(ldp, "ldp", 0,LD, IF_EN2E, 0x29400000, 0x28400000) +// enum name info LS_3B LS_3C +INST2(ldp, "ldp", LD, IF_EN2E, 0x29400000, 0x28400000) // ldp Rt,Ra,[Xn] LS_3B X010100101000000 0aaaaannnnnttttt 2940 0000 [Xn imm7] // ldp Rt,Ra,[Xn+simm7] LS_3C X010100PP1iiiiii iaaaaannnnnttttt 2840 0000 [Xn imm7 LSL {} pre/post/no inc] -INST2(ldpsw, "ldpsw", 0,LD, IF_EN2E, 0x69400000, 0x68400000) +INST2(ldpsw, "ldpsw", LD, IF_EN2E, 0x69400000, 0x68400000) // ldpsw Rt,Ra,[Xn] LS_3B 0110100101000000 0aaaaannnnnttttt 6940 0000 [Xn imm7] // ldpsw Rt,Ra,[Xn+simm7] LS_3C 0110100PP1iiiiii iaaaaannnnnttttt 6840 0000 [Xn imm7 LSL {} pre/post/no inc] -INST2(stp, "stp", 0,ST, IF_EN2E, 0x29000000, 0x28000000) +INST2(stp, "stp", ST, IF_EN2E, 0x29000000, 0x28000000) // stp Rt,Ra,[Xn] LS_3B X010100100000000 0aaaaannnnnttttt 2900 0000 [Xn imm7] // stp Rt,Ra,[Xn+simm7] LS_3C X010100PP0iiiiii iaaaaannnnnttttt 2800 0000 [Xn imm7 LSL {} pre/post/no inc] -INST2(ldnp, "ldnp", 0,LD, IF_EN2E, 0x28400000, 0x28400000) +INST2(ldnp, "ldnp", LD, IF_EN2E, 0x28400000, 0x28400000) // ldnp Rt,Ra,[Xn] LS_3B X010100001000000 0aaaaannnnnttttt 2840 0000 [Xn imm7] // ldnp Rt,Ra,[Xn+simm7] LS_3C X010100001iiiiii iaaaaannnnnttttt 2840 0000 [Xn imm7 LSL {}] -INST2(stnp, "stnp", 0,ST, IF_EN2E, 0x28000000, 0x28000000) +INST2(stnp, "stnp", ST, IF_EN2E, 0x28000000, 0x28000000) // stnp Rt,Ra,[Xn] LS_3B X010100000000000 0aaaaannnnnttttt 2800 0000 [Xn imm7] // stnp Rt,Ra,[Xn+simm7] LS_3C X010100000iiiiii iaaaaannnnnttttt 2800 0000 [Xn imm7 LSL {}] -INST2(ccmp, "ccmp", 0,CMP,IF_EN2F, 0x7A400000, 0x7A400800) +INST2(ccmp, "ccmp", CMP, IF_EN2F, 0x7A400000, 0x7A400800) // ccmp Rn,Rm, nzcv,cond DR_2I X1111010010mmmmm cccc00nnnnn0nzcv 7A40 0000 nzcv, cond // ccmp Rn,imm5,nzcv,cond DI_1F X1111010010iiiii cccc10nnnnn0nzcv 7A40 0800 imm5, nzcv, cond -INST2(ccmn, "ccmn", 0,CMP,IF_EN2F, 0x3A400000, 0x3A400800) +INST2(ccmn, "ccmn", CMP, IF_EN2F, 0x3A400000, 0x3A400800) // ccmn Rn,Rm, nzcv,cond DR_2I X0111010010mmmmm cccc00nnnnn0nzcv 3A40 0000 nzcv, cond // ccmn Rn,imm5,nzcv,cond DI_1F X0111010910iiiii cccc10nnnnn0nzcv 3A40 0800 imm5, nzcv, cond -// enum name FP LD/ST DV_2C DV_2F -INST2(ins, "ins", 0, 0, IF_EN2H, 0x4E001C00, 0x6E000400) +// enum name info DV_2C DV_2F +INST2(ins, "ins", 0, IF_EN2H, 0x4E001C00, 0x6E000400) // ins Vd[],Rn DV_2C 01001110000iiiii 000111nnnnnddddd 4E00 1C00 Vd[],Rn (from general) // ins Vd[],Vn[] DV_2F 01101110000iiiii 0jjjj1nnnnnddddd 6E00 0400 Vd[],Vn[] (from/to elem) -// enum name FP LD/ST DV_3B DV_3D -INST2(fadd, "fadd", 0, 0, IF_EN2G, 0x0E20D400, 0x1E202800) +// enum name info DV_3B DV_3D +INST2(fadd, "fadd", 0, IF_EN2G, 0x0E20D400, 0x1E202800) // fadd Vd,Vn,Vm DV_3B 0Q0011100X1mmmmm 110101nnnnnddddd 0E20 D400 Vd,Vn,Vm (vector) // fadd Vd,Vn,Vm DV_3D 000111100X1mmmmm 001010nnnnnddddd 1E20 2800 Vd,Vn,Vm (scalar) -INST2(fsub, "fsub", 0, 0, IF_EN2G, 0x0EA0D400, 0x1E203800) +INST2(fsub, "fsub", 0, IF_EN2G, 0x0EA0D400, 0x1E203800) // fsub Vd,Vn,Vm DV_3B 0Q0011101X1mmmmm 110101nnnnnddddd 0EA0 D400 Vd,Vn,Vm (vector) // fsub Vd,Vn,Vm DV_3D 000111100X1mmmmm 001110nnnnnddddd 1E20 3800 Vd,Vn,Vm (scalar) -INST2(fdiv, "fdiv", 0, 0, IF_EN2G, 0x2E20FC00, 0x1E201800) +INST2(fdiv, "fdiv", 0, IF_EN2G, 0x2E20FC00, 0x1E201800) // fdiv Vd,Vn,Vm DV_3B 0Q1011100X1mmmmm 111111nnnnnddddd 2E20 FC00 Vd,Vn,Vm (vector) // fdiv Vd,Vn,Vm DV_3D 000111100X1mmmmm 000110nnnnnddddd 1E20 1800 Vd,Vn,Vm (scalar) -INST2(fmax, "fmax", 0, 0, IF_EN2G, 0x0E20F400, 0x1E204800) +INST2(fmax, "fmax", 0, IF_EN2G, 0x0E20F400, 0x1E204800) // fmax Vd,Vn,Vm DV_3B 0Q0011100X1mmmmm 111101nnnnnddddd 0E20 F400 Vd,Vn,Vm (vector) // fmax Vd,Vn,Vm DV_3D 000111100X1mmmmm 010010nnnnnddddd 1E20 4800 Vd,Vn,Vm (scalar) -INST2(fmaxnm, "fmaxnm", 0, 0, IF_EN2G, 0x0E20C400, 0x1E206800) +INST2(fmaxnm, "fmaxnm", 0, IF_EN2G, 0x0E20C400, 0x1E206800) // fmaxnm Vd,Vn,Vm DV_3B 0Q0011100X1mmmmm 110001nnnnnddddd 0E20 C400 Vd,Vn,Vm (vector) // fmaxnm Vd,Vn,Vm DV_3D 000111100X1mmmmm 011010nnnnnddddd 1E20 6800 Vd,Vn,Vm (scalar) -INST2(fmin, "fmin", 0, 0, IF_EN2G, 0x0EA0F400, 0x1E205800) +INST2(fmin, "fmin", 0, IF_EN2G, 0x0EA0F400, 0x1E205800) // fmin Vd,Vn,Vm DV_3B 0Q0011101X1mmmmm 111101nnnnnddddd 0EA0 F400 Vd,Vn,Vm (vector) // fmin Vd,Vn,Vm DV_3D 000111100X1mmmmm 010110nnnnnddddd 1E20 5800 Vd,Vn,Vm (scalar) -INST2(fminnm, "fminnm", 0, 0, IF_EN2G, 0x0EA0C400, 0x1E207800) +INST2(fminnm, "fminnm", 0, IF_EN2G, 0x0EA0C400, 0x1E207800) // fminnm Vd,Vn,Vm DV_3B 0Q0011101X1mmmmm 110001nnnnnddddd 0EA0 C400 Vd,Vn,Vm (vector) // fminnm Vd,Vn,Vm DV_3D 000111100X1mmmmm 011110nnnnnddddd 1E20 7800 Vd,Vn,Vm (scalar) -INST2(fabd, "fabd", 0, 0, IF_EN2G, 0x2EA0D400, 0x7EA0D400) +INST2(fabd, "fabd", 0, IF_EN2G, 0x2EA0D400, 0x7EA0D400) // fabd Vd,Vn,Vm DV_3B 0Q1011101X1mmmmm 110101nnnnnddddd 2EA0 D400 Vd,Vn,Vm (vector) // fabd Vd,Vn,Vm DV_3D 011111101X1mmmmm 110101nnnnnddddd 7EA0 D400 Vd,Vn,Vm (scalar) -INST2(facge, "facge", 0, 0, IF_EN2G, 0x2E20EC00, 0x7E20EC00) +INST2(facge, "facge", 0, IF_EN2G, 0x2E20EC00, 0x7E20EC00) // facge Vd,Vn,Vm DV_3B 0Q1011100X1mmmmm 111011nnnnnddddd 2E20 EC00 Vd,Vn,Vm (vector) // facge Vd,Vn,Vm DV_3D 011111100X1mmmmm 111011nnnnnddddd 7E20 EC00 Vd,Vn,Vm (scalar) -INST2(facgt, "facgt", 0, 0, IF_EN2G, 0x2EA0EC00, 0x7EA0EC00) +INST2(facgt, "facgt", 0, IF_EN2G, 0x2EA0EC00, 0x7EA0EC00) // facgt Vd,Vn,Vm DV_3B 0Q1011101X1mmmmm 111011nnnnnddddd 2EA0 EC00 Vd,Vn,Vm (vector) // facgt Vd,Vn,Vm DV_3D 011111101X1mmmmm 111011nnnnnddddd 7EA0 EC00 Vd,Vn,Vm (scalar) -INST2(frecps, "frecps", 0, 0, IF_EN2G, 0x0E20FC00, 0x5E20FC00) - // C7.2.138 FRECPS +INST2(frecps, "frecps", 0, IF_EN2G, 0x0E20FC00, 0x5E20FC00) // frecps Vd,Vn,Vm DV_3B 0Q0011100X1mmmmm 111111nnnnnddddd 0E20 FC00 Vd,Vn,Vm (vector) // frecps Vd,Vn,Vm DV_3D 010111100X1mmmmm 111111nnnnnddddd 5E20 FC00 Vd,Vn,Vm (scalar) -INST2(frsqrts, "frsqrts",0, 0, IF_EN2G, 0x0EA0FC00, 0x5EA0FC00) - // C7.2.163 FRSQRTS +INST2(frsqrts, "frsqrts", 0, IF_EN2G, 0x0EA0FC00, 0x5EA0FC00) // frsqrts Vd,Vn,Vm DV_3B 0Q0011101X1mmmmm 111111nnnnnddddd 0EA0 FC00 Vd,Vn,Vm (vector) // frsqrts Vd,Vn,Vm DV_3D 010111101X1mmmmm 111111nnnnnddddd 5EA0 FC00 Vd,Vn,Vm (scalar) -// enum name FP LD/ST DV_2K DV_1C -INST2(fcmp, "fcmp", 0, 0, IF_EN2I, 0x1E202000, 0x1E202008) +// enum name info DV_2K DV_1C +INST2(fcmp, "fcmp", 0, IF_EN2I, 0x1E202000, 0x1E202008) // fcmp Vn,Vm DV_2K 000111100X1mmmmm 001000nnnnn00000 1E20 2000 Vn Vm // fcmp Vn,#0.0 DV_1C 000111100X100000 001000nnnnn01000 1E20 2008 Vn #0.0 -INST2(fcmpe, "fcmpe", 0, 0, IF_EN2I, 0x1E202010, 0x1E202018) +INST2(fcmpe, "fcmpe", 0, IF_EN2I, 0x1E202010, 0x1E202018) // fcmpe Vn,Vm DV_2K 000111100X1mmmmm 001000nnnnn10000 1E20 2010 Vn Vm // fcmpe Vn,#0.0 DV_1C 000111100X100000 001000nnnnn11000 1E20 2018 Vn #0.0 -// enum name FP LD/ST DV_2A DV_2G -INST2(fabs, "fabs", 0, 0, IF_EN2J, 0x0EA0F800, 0x1E20C000) +// enum name info DV_2A DV_2G +INST2(fabs, "fabs", 0, IF_EN2J, 0x0EA0F800, 0x1E20C000) // fabs Vd,Vn DV_2A 0Q0011101X100000 111110nnnnnddddd 0EA0 F800 Vd,Vn (vector) // fabs Vd,Vn DV_2G 000111100X100000 110000nnnnnddddd 1E20 C000 Vd,Vn (scalar) -INST2(fcmle, "fcmle", 0, 0, IF_EN2J, 0x2EA0D800, 0x7EA0D800) +INST2(fcmle, "fcmle", 0, IF_EN2J, 0x2EA0D800, 0x7EA0D800) // fcmle Vd,Vn DV_2A 0Q1011101X100000 111110nnnnnddddd 2EA0 D800 Vd,Vn (vector) // fcmle Vd,Vn DV_2G 011111101X100000 110110nnnnnddddd 7EA0 D800 Vd,Vn (scalar) -INST2(fcmlt, "fcmlt", 0, 0, IF_EN2J, 0x0EA0E800, 0x5EA0E800) +INST2(fcmlt, "fcmlt", 0, IF_EN2J, 0x0EA0E800, 0x5EA0E800) // fcmlt Vd,Vn DV_2A 0Q0011101X100000 111110nnnnnddddd 0EA0 E800 Vd,Vn (vector) // fcmlt Vd,Vn DV_2G 010111101X100000 111010nnnnnddddd 5EA0 E800 Vd,Vn (scalar) -INST2(fneg, "fneg", 0, 0, IF_EN2J, 0x2EA0F800, 0x1E214000) +INST2(fneg, "fneg", 0, IF_EN2J, 0x2EA0F800, 0x1E214000) // fneg Vd,Vn DV_2A 0Q1011101X100000 111110nnnnnddddd 2EA0 F800 Vd,Vn (vector) // fneg Vd,Vn DV_2G 000111100X100001 010000nnnnnddddd 1E21 4000 Vd,Vn (scalar) -INST2(frecpe, "frecpe", 0, 0, IF_EN2J, 0x0EA1D800, 0x5EA1D800) +INST2(frecpe, "frecpe", 0, IF_EN2J, 0x0EA1D800, 0x5EA1D800) // frecpe Vd,Vn DV_2A 0Q0011101X100001 110110nnnnnddddd 0EA1 D800 Vd,Vn (vector) // frecpe Vd,Vn DV_2G 010111101X100001 110110nnnnnddddd 5EA1 D800 Vd,Vn (scalar) -INST2(frintn, "frintn", 0, 0, IF_EN2J, 0x0E218800, 0x1E244000) +INST2(frintn, "frintn", 0, IF_EN2J, 0x0E218800, 0x1E244000) // frintn Vd,Vn DV_2A 0Q0011100X100001 100010nnnnnddddd 0E21 8800 Vd,Vn (vector) // frintn Vd,Vn DV_2G 000111100X100100 010000nnnnnddddd 1E24 4000 Vd,Vn (scalar) -INST2(frintp, "frintp", 0, 0, IF_EN2J, 0x0EA18800, 0x1E24C000) +INST2(frintp, "frintp", 0, IF_EN2J, 0x0EA18800, 0x1E24C000) // frintp Vd,Vn DV_2A 0Q0011101X100001 100010nnnnnddddd 0EA1 8800 Vd,Vn (vector) // frintp Vd,Vn DV_2G 000111100X100100 110000nnnnnddddd 1E24 C000 Vd,Vn (scalar) -INST2(frintm, "frintm", 0, 0, IF_EN2J, 0x0E219800, 0x1E254000) +INST2(frintm, "frintm", 0, IF_EN2J, 0x0E219800, 0x1E254000) // frintm Vd,Vn DV_2A 0Q0011100X100001 100110nnnnnddddd 0E21 9800 Vd,Vn (vector) // frintm Vd,Vn DV_2G 000111100X100101 010000nnnnnddddd 1E25 4000 Vd,Vn (scalar) -INST2(frintz, "frintz", 0, 0, IF_EN2J, 0x0EA19800, 0x1E25C000) +INST2(frintz, "frintz", 0, IF_EN2J, 0x0EA19800, 0x1E25C000) // frintz Vd,Vn DV_2A 0Q0011101X100001 100110nnnnnddddd 0EA1 9800 Vd,Vn (vector) // frintz Vd,Vn DV_2G 000111100X100101 110000nnnnnddddd 1E25 C000 Vd,Vn (scalar) -INST2(frinta, "frinta", 0, 0, IF_EN2J, 0x2E218800, 0x1E264000) +INST2(frinta, "frinta", 0, IF_EN2J, 0x2E218800, 0x1E264000) // frinta Vd,Vn DV_2A 0Q1011100X100001 100010nnnnnddddd 2E21 8800 Vd,Vn (vector) // frinta Vd,Vn DV_2G 000111100X100110 010000nnnnnddddd 1E26 4000 Vd,Vn (scalar) -INST2(frintx, "frintx", 0, 0, IF_EN2J, 0x2E219800, 0x1E274000) +INST2(frintx, "frintx", 0, IF_EN2J, 0x2E219800, 0x1E274000) // frintx Vd,Vn DV_2A 0Q1011100X100001 100110nnnnnddddd 2E21 9800 Vd,Vn (vector) // frintx Vd,Vn DV_2G 000111100X100111 010000nnnnnddddd 1E27 4000 Vd,Vn (scalar) -INST2(frinti, "frinti", 0, 0, IF_EN2J, 0x2EA19800, 0x1E27C000) +INST2(frinti, "frinti", 0, IF_EN2J, 0x2EA19800, 0x1E27C000) // frinti Vd,Vn DV_2A 0Q1011101X100001 100110nnnnnddddd 2EA1 9800 Vd,Vn (vector) // frinti Vd,Vn DV_2G 000111100X100111 110000nnnnnddddd 1E27 C000 Vd,Vn (scalar) -INST2(frsqrte, "frsqrte",0, 0, IF_EN2J, 0x2EA1D800, 0x7EA1D800) - // C7.2.162 FRSQRTE +INST2(frsqrte, "frsqrte", 0, IF_EN2J, 0x2EA1D800, 0x7EA1D800) // frsqrte Vd,Vn DV_2A 0Q1011101X100001 110110nnnnnddddd 2EA1 D800 Vd,Vn (vector) // frsqrte Vd,Vn DV_2G 011111101X100001 110110nnnnnddddd 7EA1 D800 Vd,Vn (scalar) -INST2(fsqrt, "fsqrt", 0, 0, IF_EN2J, 0x2EA1F800, 0x1E21C000) - // C7.2.164 FSQRT (vector) +INST2(fsqrt, "fsqrt", 0, IF_EN2J, 0x2EA1F800, 0x1E21C000) // fsqrt Vd,Vn DV_2A 0Q1011101X100001 111110nnnnnddddd 2EA1 F800 Vd,Vn (vector) - // C7.2.165 FSQRT (scalar) // fsqrt Vd,Vn DV_2G 000111100X100001 110000nnnnnddddd 1E21 C000 Vd,Vn (scalar) -// enum name FP LD/ST DV_2M DV_2L -INST2(abs, "abs", 0, 0, IF_EN2K, 0x0E20B800, 0x5E20B800) +// enum name info DV_2M DV_2L +INST2(abs, "abs", 0, IF_EN2K, 0x0E20B800, 0x5E20B800) // abs Vd,Vn DV_2M 0Q001110XX100000 101110nnnnnddddd 0E20 B800 Vd,Vn (vector) // abs Vd,Vn DV_2L 01011110XX100000 101110nnnnnddddd 5E20 B800 Vd,Vn (scalar) -INST2(cmle, "cmle", 0, 0, IF_EN2K, 0x2E209800, 0x7E209800) +INST2(cmle, "cmle", 0, IF_EN2K, 0x2E209800, 0x7E209800) // cmle Vd,Vn DV_2M 0Q101110XX100000 100110nnnnnddddd 2E20 9800 Vd,Vn (vector) // cmle Vd,Vn DV_2L 01111110XX100000 100110nnnnnddddd 7E20 9800 Vd,Vn (scalar) -INST2(cmlt, "cmlt", 0, 0, IF_EN2K, 0x0E20A800, 0x5E20A800) +INST2(cmlt, "cmlt", 0, IF_EN2K, 0x0E20A800, 0x5E20A800) // cmlt Vd,Vn DV_2M 0Q101110XX100000 101010nnnnnddddd 0E20 A800 Vd,Vn (vector) // cmlt Vd,Vn DV_2L 01011110XX100000 101010nnnnnddddd 5E20 A800 Vd,Vn (scalar) -// enum name FP LD/ST DR_2G DV_2M -INST2(cls, "cls", 0, 0, IF_EN2L, 0x5AC01400, 0x0E204800) +// enum name info DR_2G DV_2M +INST2(cls, "cls", 0, IF_EN2L, 0x5AC01400, 0x0E204800) // cls Rd,Rm DR_2G X101101011000000 000101nnnnnddddd 5AC0 1400 Rd Rn (general) // cls Vd,Vn DV_2M 0Q00111000100000 010010nnnnnddddd 0E20 4800 Vd,Vn (vector) -INST2(clz, "clz", 0, 0, IF_EN2L, 0x5AC01000, 0x2E204800) +INST2(clz, "clz", 0, IF_EN2L, 0x5AC01000, 0x2E204800) // clz Rd,Rm DR_2G X101101011000000 000100nnnnnddddd 5AC0 1000 Rd Rn (general) // clz Vd,Vn DV_2M 0Q10111000100000 010010nnnnnddddd 2E20 4800 Vd,Vn (vector) -INST2(rbit, "rbit", 0, 0, IF_EN2L, 0x5AC00000, 0x2E605800) +INST2(rbit, "rbit", 0, IF_EN2L, 0x5AC00000, 0x2E605800) // rbit Rd,Rm DR_2G X101101011000000 000000nnnnnddddd 5AC0 0000 Rd Rn (general) // rbit Vd,Vn DV_2M 0Q10111001100000 010110nnnnnddddd 2E60 5800 Vd,Vn (vector) -INST2(rev16, "rev16", 0, 0, IF_EN2L, 0x5AC00400, 0x0E201800) +INST2(rev16, "rev16", 0, IF_EN2L, 0x5AC00400, 0x0E201800) // rev16 Rd,Rm DR_2G X101101011000000 000001nnnnnddddd 5AC0 0400 Rd Rn (general) // rev16 Vd,Vn DV_2M 0Q001110XX100000 000110nnnnnddddd 0E20 1800 Vd,Vn (vector) -INST2(rev32, "rev32", 0, 0, IF_EN2L, 0xDAC00800, 0x2E200800) +INST2(rev32, "rev32", 0, IF_EN2L, 0xDAC00800, 0x2E200800) // rev32 Rd,Rm DR_2G 1101101011000000 000010nnnnnddddd DAC0 0800 Rd Rn (general) // rev32 Vd,Vn DV_2M 0Q101110XX100000 000010nnnnnddddd 2E20 0800 Vd,Vn (vector) -// enum name FP LD/ST DV_3A DV_3AI -INST2(mla, "mla", 0, 0, IF_EN2M, 0x0E209400, 0x2F000000) +// enum name info DV_3A DV_3AI +INST2(mla, "mla", 0, IF_EN2M, 0x0E209400, 0x2F000000) // mla Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 100101nnnnnddddd 0E20 9400 Vd,Vn,Vm (vector) // mla Vd,Vn,Vm[] DV_3AI 0Q101111XXLMmmmm 0000H0nnnnnddddd 2F00 0000 Vd,Vn,Vm[] (vector by elem) -INST2(mls, "mls", 0, 0, IF_EN2M, 0x2E209400, 0x2F004000) +INST2(mls, "mls", 0, IF_EN2M, 0x2E209400, 0x2F004000) // mls Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 100101nnnnnddddd 2E20 9400 Vd,Vn,Vm (vector) // mls Vd,Vn,Vm[] DV_3AI 0Q101111XXLMmmmm 0100H0nnnnnddddd 2F00 4000 Vd,Vn,Vm[] (vector by elem) -// enum name FP LD/ST DV_2N DV_2O -INST2(sshr, "sshr", 0, 0, IF_EN2N, 0x5F000400, 0x0F000400) - // sshr Vd,Vn,imm DV_2N 010111110iiiiiii 000001nnnnnddddd 5F00 0400 Vd Vn imm (shift - scalar) - // sshr Vd,Vn,imm DV_2O 0Q0011110iiiiiii 000001nnnnnddddd 0F00 0400 Vd,Vn imm (shift - vector) +INST2(smlal, "smlal", 0, IF_EN2R, 0x0E208000, 0x0F002000) + // smlal Vd,Vn,Vm DV_3H 00001110XX1mmmmm 100000nnnnnddddd 0E20 8000 Vd,Vn,Vm (vector) + // smlal Vd,Vn,Vm[] DV_3HI 00001111XXLMmmmm 0010H0nnnnnddddd 0F00 2000 Vd,Vn,Vm[] (vector by elem) + +INST2(smlal2, "smlal2", 0, IF_EN2R, 0x4E208000, 0x4F002000) + // smlal2 Vd,Vn,Vm DV_3H 01001110XX1mmmmm 100000nnnnnddddd 4E20 8000 Vd,Vn,Vm (vector) + // smlal2 Vd,Vn,Vm[] DV_3HI 01001111XXLMmmmm 0010H0nnnnnddddd 4F00 2000 Vd,Vn,Vm[] (vector by elem) + +INST2(smlsl, "smlsl", 0, IF_EN2R, 0x0E20A000, 0x0F006000) + // smlsl Vd,Vn,Vm DV_3H 00001110XX1mmmmm 101000nnnnnddddd 0E20 A000 Vd,Vn,Vm (vector) + // smlsl Vd,Vn,Vm[] DV_3HI 00001111XXLMmmmm 0110H0nnnnnddddd 0F00 6000 Vd,Vn,Vm[] (vector by elem) + +INST2(smlsl2, "smlsl2", 0, IF_EN2R, 0x4E20A000, 0x4F006000) + // smlsl2 Vd,Vn,Vm DV_3H 01001110XX1mmmmm 101000nnnnnddddd 4E20 A000 Vd,Vn,Vm (vector) + // smlsl2 Vd,Vn,Vm[] DV_3HI 01001111XXLMmmmm 0110H0nnnnnddddd 4F00 6000 Vd,Vn,Vm[] (vector by elem) + +INST2(smull2, "smull2", 0, IF_EN2R, 0x4E20C000, 0x4F00A000) + // smull2 Vd,Vn,Vm DV_3H 01001110XX1mmmmm 110000nnnnnddddd 4E20 C000 Vd,Vn,Vm (vector) + // smull2 Vd,Vn,Vm[] DV_3HI 01001111XXLMmmmm 1010H0nnnnnddddd 4F00 A000 Vd,Vn,Vm[] (vector by elem) + +INST2(umlal, "umlal", 0, IF_EN2R, 0x2E208000, 0x2F002000) + // umlal Vd,Vn,Vm DV_3H 00101110XX1mmmmm 100000nnnnnddddd 2E20 8000 Vd,Vn,Vm (vector) + // umlal Vd,Vn,Vm[] DV_3HI 00101111XXLMmmmm 0010H0nnnnnddddd 2F00 2000 Vd,Vn,Vm[] (vector by elem) + +INST2(umlal2, "umlal2", 0, IF_EN2R, 0x6E208000, 0x6F002000) + // umlal2 Vd,Vn,Vm DV_3H 01101110XX1mmmmm 100000nnnnnddddd 6E20 8000 Vd,Vn,Vm (vector) + // umlal2 Vd,Vn,Vm[] DV_3HI 01101111XXLMmmmm 0010H0nnnnnddddd 6F00 2000 Vd,Vn,Vm[] (vector by elem) + +INST2(umlsl, "umlsl", 0, IF_EN2R, 0x2E20A000, 0x2F006000) + // umlsl Vd,Vn,Vm DV_3H 00101110XX1mmmmm 101000nnnnnddddd 2E20 A000 Vd,Vn,Vm (vector) + // umlsl Vd,Vn,Vm[] DV_3HI 00101111XXLMmmmm 0110H0nnnnnddddd 2F00 6000 Vd,Vn,Vm[] (vector by elem) + +INST2(umlsl2, "umlsl2", 0, IF_EN2R, 0x6E20A000, 0x6F006000) + // umlsl2 Vd,Vn,Vm DV_3H 01101110XX1mmmmm 101000nnnnnddddd 6E20 A000 Vd,Vn,Vm (vector) + // umlsl2 Vd,Vn,Vm[] DV_3HI 01101111XXLMmmmm 0110H0nnnnnddddd 6F00 6000 Vd,Vn,Vm[] (vector by elem) -INST2(ssra, "ssra", 0, 0, IF_EN2N, 0x5F001400, 0x0F001400) - // ssra Vd,Vn,imm DV_2N 010111110iiiiiii 000101nnnnnddddd 5F00 1400 Vd Vn imm (shift - scalar) - // ssra Vd,Vn,imm DV_2O 0Q0011110iiiiiii 000101nnnnnddddd 0F00 1400 Vd,Vn imm (shift - vector) +INST2(umull2, "umull2", 0, IF_EN2R, 0x6E20C000, 0x6F00A000) + // umull2 Vd,Vn,Vm DV_3H 01101110XX1mmmmm 110000nnnnnddddd 6E20 C000 Vd,Vn,Vm (vector) + // umull2 Vd,Vn,Vm[] DV_3HI 01101111XXLMmmmm 1010H0nnnnnddddd 6F00 A000 Vd,Vn,Vm[] (vector by elem) -INST2(srshr, "srshr", 0, 0, IF_EN2N, 0x5F002400, 0x0F002400) - // srshr Vd,Vn,imm DV_2N 010111110iiiiiii 001001nnnnnddddd 5F00 0400 Vd Vn imm (shift - scalar) - // srshr Vd,Vn,imm DV_2O 0Q0011110iiiiiii 001001nnnnnddddd 0F00 0400 Vd,Vn imm (shift - vector) +// enum name info DV_2N DV_2O +INST2(sshr, "sshr", RSH, IF_EN2N, 0x5F000400, 0x0F000400) + // sshr Vd,Vn,imm DV_2N 010111110iiiiiii 000001nnnnnddddd 5F00 0400 Vd Vn imm (right shift - scalar) + // sshr Vd,Vn,imm DV_2O 0Q0011110iiiiiii 000001nnnnnddddd 0F00 0400 Vd,Vn imm (right shift - vector) -INST2(srsra, "srsra", 0, 0, IF_EN2N, 0x5F003400, 0x0F003400) - // srsra Vd,Vn,imm DV_2N 010111110iiiiiii 001101nnnnnddddd 5F00 1400 Vd Vn imm (shift - scalar) - // srsra Vd,Vn,imm DV_2O 0Q0011110iiiiiii 001101nnnnnddddd 0F00 1400 Vd,Vn imm (shift - vector) +INST2(ssra, "ssra", RSH, IF_EN2N, 0x5F001400, 0x0F001400) + // ssra Vd,Vn,imm DV_2N 010111110iiiiiii 000101nnnnnddddd 5F00 1400 Vd Vn imm (right shift - scalar) + // ssra Vd,Vn,imm DV_2O 0Q0011110iiiiiii 000101nnnnnddddd 0F00 1400 Vd,Vn imm (right shift - vector) -INST2(shl, "shl", 0, 0, IF_EN2N, 0x5F005400, 0x0F005400) - // shl Vd,Vn,imm DV_2N 010111110iiiiiii 010101nnnnnddddd 5F00 5400 Vd Vn imm (shift - scalar) - // shl Vd,Vn,imm DV_2O 0Q0011110iiiiiii 010101nnnnnddddd 0F00 5400 Vd,Vn imm (shift - vector) +INST2(srshr, "srshr", RSH, IF_EN2N, 0x5F002400, 0x0F002400) + // srshr Vd,Vn,imm DV_2N 010111110iiiiiii 001001nnnnnddddd 5F00 0400 Vd Vn imm (right shift - scalar) + // srshr Vd,Vn,imm DV_2O 0Q0011110iiiiiii 001001nnnnnddddd 0F00 0400 Vd,Vn imm (right shift - vector) -INST2(ushr, "ushr", 0, 0, IF_EN2N, 0x7F000400, 0x2F000400) - // ushr Vd,Vn,imm DV_2N 011111110iiiiiii 000001nnnnnddddd 7F00 0400 Vd Vn imm (shift - scalar) - // ushr Vd,Vn,imm DV_2O 0Q1011110iiiiiii 000001nnnnnddddd 2F00 0400 Vd,Vn imm (shift - vector) +INST2(srsra, "srsra", RSH, IF_EN2N, 0x5F003400, 0x0F003400) + // srsra Vd,Vn,imm DV_2N 010111110iiiiiii 001101nnnnnddddd 5F00 1400 Vd Vn imm (right shift - scalar) + // srsra Vd,Vn,imm DV_2O 0Q0011110iiiiiii 001101nnnnnddddd 0F00 1400 Vd,Vn imm (right shift - vector) -INST2(usra, "usra", 0, 0, IF_EN2N, 0x7F001400, 0x2F001400) - // usra Vd,Vn,imm DV_2N 011111110iiiiiii 000101nnnnnddddd 7F00 1400 Vd Vn imm (shift - scalar) - // usra Vd,Vn,imm DV_2O 0Q1011110iiiiiii 000101nnnnnddddd 2F00 1400 Vd,Vn imm (shift - vector) +INST2(shl, "shl", 0, IF_EN2N, 0x5F005400, 0x0F005400) + // shl Vd,Vn,imm DV_2N 010111110iiiiiii 010101nnnnnddddd 5F00 5400 Vd Vn imm (left shift - scalar) + // shl Vd,Vn,imm DV_2O 0Q0011110iiiiiii 010101nnnnnddddd 0F00 5400 Vd,Vn imm (left shift - vector) -INST2(urshr, "urshr", 0, 0, IF_EN2N, 0x7F002400, 0x2F002400) - // urshr Vd,Vn,imm DV_2N 011111110iiiiiii 001001nnnnnddddd 7F00 2400 Vd Vn imm (shift - scalar) - // urshr Vd,Vn,imm DV_2O 0Q1011110iiiiiii 001001nnnnnddddd 2F00 2400 Vd,Vn imm (shift - vector) +INST2(ushr, "ushr", RSH, IF_EN2N, 0x7F000400, 0x2F000400) + // ushr Vd,Vn,imm DV_2N 011111110iiiiiii 000001nnnnnddddd 7F00 0400 Vd Vn imm (right shift - scalar) + // ushr Vd,Vn,imm DV_2O 0Q1011110iiiiiii 000001nnnnnddddd 2F00 0400 Vd,Vn imm (right shift - vector) -INST2(ursra, "ursra", 0, 0, IF_EN2N, 0x7F003400, 0x2F003400) - // ursra Vd,Vn,imm DV_2N 011111110iiiiiii 001101nnnnnddddd 7F00 3400 Vd Vn imm (shift - scalar) - // ursra Vd,Vn,imm DV_2O 0Q1011110iiiiiii 001101nnnnnddddd 2F00 3400 Vd,Vn imm (shift - vector) +INST2(usra, "usra", RSH, IF_EN2N, 0x7F001400, 0x2F001400) + // usra Vd,Vn,imm DV_2N 011111110iiiiiii 000101nnnnnddddd 7F00 1400 Vd Vn imm (right shift - scalar) + // usra Vd,Vn,imm DV_2O 0Q1011110iiiiiii 000101nnnnnddddd 2F00 1400 Vd,Vn imm (right shift - vector) -INST2(sri, "sri", 0, 0, IF_EN2N, 0x7F004400, 0x2F004400) - // sri Vd,Vn,imm DV_2N 011111110iiiiiii 010001nnnnnddddd 7F00 4400 Vd Vn imm (shift - scalar) - // sri Vd,Vn,imm DV_2O 0Q1011110iiiiiii 010001nnnnnddddd 2F00 4400 Vd,Vn imm (shift - vector) +INST2(urshr, "urshr", RSH, IF_EN2N, 0x7F002400, 0x2F002400) + // urshr Vd,Vn,imm DV_2N 011111110iiiiiii 001001nnnnnddddd 7F00 2400 Vd Vn imm (right shift - scalar) + // urshr Vd,Vn,imm DV_2O 0Q1011110iiiiiii 001001nnnnnddddd 2F00 2400 Vd,Vn imm (right shift - vector) -INST2(sli, "sli", 0, 0, IF_EN2N, 0x7F005400, 0x2F005400) - // sli Vd,Vn,imm DV_2N 011111110iiiiiii 010101nnnnnddddd 7F00 5400 Vd Vn imm (shift - scalar) - // sli Vd,Vn,imm DV_2O 0Q1011110iiiiiii 010101nnnnnddddd 2F00 5400 Vd,Vn imm (shift - vector) +INST2(ursra, "ursra", RSH, IF_EN2N, 0x7F003400, 0x2F003400) + // ursra Vd,Vn,imm DV_2N 011111110iiiiiii 001101nnnnnddddd 7F00 3400 Vd Vn imm (right shift - scalar) + // ursra Vd,Vn,imm DV_2O 0Q1011110iiiiiii 001101nnnnnddddd 2F00 3400 Vd,Vn imm (right shift - vector) -// enum name FP LD/ST DV_3E DV_3A -INST2(cmhi, "cmhi", 0, 0, IF_EN2O, 0x7EE03400, 0x2E203400) +INST2(sri, "sri", RSH, IF_EN2N, 0x7F004400, 0x2F004400) + // sri Vd,Vn,imm DV_2N 011111110iiiiiii 010001nnnnnddddd 7F00 4400 Vd Vn imm (right shift - scalar) + // sri Vd,Vn,imm DV_2O 0Q1011110iiiiiii 010001nnnnnddddd 2F00 4400 Vd,Vn imm (right shift - vector) + +INST2(sli, "sli", 0, IF_EN2N, 0x7F005400, 0x2F005400) + // sli Vd,Vn,imm DV_2N 011111110iiiiiii 010101nnnnnddddd 7F00 5400 Vd Vn imm (left shift - scalar) + // sli Vd,Vn,imm DV_2O 0Q1011110iiiiiii 010101nnnnnddddd 2F00 5400 Vd,Vn imm (left shift - vector) + +INST2(sqshlu, "sqshlu", 0, IF_EN2N, 0x7F006400, 0x2F006400) + // sqshlu Vd,Vn,imm DV_2N 011111110iiiiiii 011001nnnnnddddd 7F00 6400 Vd Vn imm (left shift - scalar) + // sqshlu Vd,Vn,imm DV_2O 0Q1011110iiiiiii 011001nnnnnddddd 2F00 6400 Vd Vn imm (left shift - vector) + +INST2(sqrshrn, "sqrshrn", RSH, IF_EN2N, 0x5F009C00, 0x0F009C00) + // sqrshrn Vd,Vn,imm DV_2N 010111110iiiiiii 100111nnnnnddddd 5F00 9C00 Vd Vn imm (right shift - scalar) + // sqrshrn Vd,Vn,imm DV_2O 0Q0011110iiiiiii 100111nnnnnddddd 0F00 9C00 Vd Vn imm (right shift - vector) + +INST2(sqrshrun, "sqrshrun", RSH, IF_EN2N, 0x7F008C00, 0x2F008C00) + // sqrshrun Vd,Vn,imm DV_2N 011111110iiiiiii 100011nnnnnddddd 7F00 8C00 Vd Vn imm (right shift - scalar) + // sqrshrun Vd,Vn,imm DV_2O 0Q1011110iiiiiii 100011nnnnnddddd 2F00 8C00 Vd Vn imm (right shift - vector) + +INST2(sqshrn, "sqshrn", RSH, IF_EN2N, 0x5F009400, 0x0F009400) + // sqshrn Vd,Vn,imm DV_2N 010111110iiiiiii 100101nnnnnddddd 5F00 9400 Vd Vn imm (right shift - scalar) + // sqshrn Vd,Vn,imm DV_2O 0Q0011110iiiiiii 100101nnnnnddddd 0F00 9400 Vd Vn imm (right shift - vector) + +INST2(sqshrun, "sqshrun", RSH, IF_EN2N, 0x7F008400, 0x2F008400) + // sqshrun Vd,Vn,imm DV_2N 011111110iiiiiii 100001nnnnnddddd 7F00 8400 Vd Vn imm (right shift - scalar) + // sqshrun Vd,Vn,imm DV_2O 0Q1011110iiiiiii 100001nnnnnddddd 2F00 8400 Vd Vn imm (right shift - vector) + +INST2(uqrshrn, "uqrshrn", RSH, IF_EN2N, 0x7F009C00, 0x2F009C00) + // uqrshrn Vd,Vn,imm DV_2N 011111110iiiiiii 100111nnnnnddddd 7F00 9C00 Vd Vn imm (right shift - scalar) + // uqrshrn Vd,Vn,imm DV_2O 0Q1011110iiiiiii 100111nnnnnddddd 2F00 9C00 Vd Vn imm (right shift - vector) + +INST2(uqshrn, "uqshrn", RSH, IF_EN2N, 0x7F009400, 0x2F009400) + // usqhrn Vd,Vn,imm DV_2N 011111110iiiiiii 100101nnnnnddddd 7F00 9400 Vd Vn imm (right shift - scalar) + // usqhrn Vd,Vn,imm DV_2O 0Q1011110iiiiiii 100101nnnnnddddd 2F00 9400 Vd Vn imm (right shift - vector) + +// enum name info DV_3E DV_3A +INST2(cmhi, "cmhi", 0, IF_EN2O, 0x7EE03400, 0x2E203400) // cmhi Vd,Vn,Vm DV_3E 01111110111mmmmm 001101nnnnnddddd 7EE0 3400 Vd,Vn,Vm (scalar) // cmhi Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 001101nnnnnddddd 2E20 3400 Vd,Vn,Vm (vector) -INST2(cmhs, "cmhs", 0, 0, IF_EN2O, 0x7EE03C00, 0x2E203C00) +INST2(cmhs, "cmhs", 0, IF_EN2O, 0x7EE03C00, 0x2E203C00) // cmhs Vd,Vn,Vm DV_3E 01111110111mmmmm 001111nnnnnddddd 7EE0 3C00 Vd,Vn,Vm (scalar) // cmhs Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 001111nnnnnddddd 2E20 3C00 Vd,Vn,Vm (vector) -INST2(cmtst, "cmtst", 0, 0, IF_EN2O, 0x5EE08C00, 0x0E208C00) +INST2(cmtst, "cmtst", 0, IF_EN2O, 0x5EE08C00, 0x0E208C00) // cmtst Vd,Vn,Vm DV_3E 01011110111mmmmm 100011nnnnnddddd 5EE0 8C00 Vd,Vn,Vm (scalar) // cmtst Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 100011nnnnnddddd 0E20 8C00 Vd,Vn,Vm (vector) -// enum name FP LD/ST DV_2Q DV_3B -INST2(faddp, "faddp", 0, 0, IF_EN2P, 0x7E30D800, 0x2E20D400) +INST2(sqadd, "sqadd", 0, IF_EN2O, 0x5E200C00, 0x0E200C00) + // sqadd Vd,Vn,Vm DV_3E 01011110XX1mmmmm 000011nnnnnddddd 5E20 0C00 Vd,Vn,Vm (scalar) + // sqadd Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 000011nnnnnddddd 0E20 0C00 Vd,Vn,Vm (vector) + +INST2(sqrshl, "sqrshl", 0, IF_EN2O, 0x5E205C00, 0x0E205C00) + // sqrshl Vd,Vn,Vm DV_3E 01011110XX1mmmmm 010111nnnnnddddd 5E20 5C00 Vd,Vn,Vm (scalar) + // sqrshl Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 010111nnnnnddddd 0E20 5C00 Vd,Vn,Vm (vector) + +INST2(sqsub, "sqsub", 0, IF_EN2O, 0x5E202C00, 0x0E202C00) + // sqsub Vd,Vn,Vm DV_3E 01011110XX1mmmmm 001011nnnnnddddd 5E20 2C00 Vd,Vn,Vm (scalar) + // sqsub Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 001011nnnnnddddd 0E20 2C00 Vd,Vn,Vm (vector) + +INST2(srshl, "srshl", 0, IF_EN2O, 0x5E205400, 0x0E205400) + // srshl Vd,Vn,Vm DV_3E 01011110XX1mmmmm 010101nnnnnddddd 5E20 5400 Vd,Vn,Vm (scalar) + // srshl Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 010101nnnnnddddd 0E20 5400 Vd,Vn,Vm (vector) + +INST2(sshl, "sshl", 0, IF_EN2O, 0x5E204400, 0x0E204400) + // sshl Vd,Vn,Vm DV_3E 01011110XX1mmmmm 010001nnnnnddddd 5E20 4400 Vd,Vn,Vm (scalar) + // sshl Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 010001nnnnnddddd 0E20 4400 Vd,Vn,Vm (vector) + +INST2(uqadd, "uqadd", 0, IF_EN2O, 0x7E200C00, 0x2E200C00) + // uqadd Vd,Vn,Vm DV_3E 01111110XX1mmmmm 000011nnnnnddddd 7E20 0C00 Vd,Vn,Vm (scalar) + // uqadd Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 000011nnnnnddddd 2E20 0C00 Vd,Vn,Vm (vector) + +INST2(uqrshl, "uqrshl", 0, IF_EN2O, 0x7E205C00, 0x2E205C00) + // uqrshl Vd,Vn,Vm DV_3E 01111110XX1mmmmm 010111nnnnnddddd 7E20 5C00 Vd,Vn,Vm (scalar) + // uqrshl Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 010111nnnnnddddd 2E20 5C00 Vd,Vn,Vm (vector) + +INST2(uqsub, "uqsub", 0, IF_EN2O, 0x7E202C00, 0x2E202C00) + // uqsub Vd,Vn,Vm DV_3E 01111110XX1mmmmm 001011nnnnnddddd 7E20 2C00 Vd,Vn,Vm (scalar) + // uqsub Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 001011nnnnnddddd 2E20 2C00 Vd,Vn,Vm (vector) + +INST2(urshl, "urshl", 0, IF_EN2O, 0x7E205400, 0x2E205400) + // urshl Vd,Vn,Vm DV_3E 01111110XX1mmmmm 010101nnnnnddddd 7E20 5400 Vd,Vn,Vm (scalar) + // urshl Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 010101nnnnnddddd 2E20 5400 Vd,Vn,Vm (vector) + +INST2(ushl, "ushl", 0, IF_EN2O, 0x7E204400, 0x2E204400) + // ushl Vd,Vn,Vm DV_3E 01111110XX1mmmmm 010001nnnnnddddd 7E20 4400 Vd,Vn,Vm (scalar) + // ushl Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 010001nnnnnddddd 2E20 4400 Vd,Vn,Vm (vector) + +// enum name info DV_2Q DV_3B +INST2(faddp, "faddp", 0, IF_EN2P, 0x7E30D800, 0x2E20D400) // faddp Vd,Vn DV_2Q 011111100X110000 110110nnnnnddddd 7E30 D800 Vd,Vn (scalar) // faddp Vd,Vn,Vm DV_3B 0Q1011100X1mmmmm 110101nnnnnddddd 2E20 D400 Vd,Vn,Vm (vector) -INST2(fmaxnmp, "fmaxnmp",0, 0, IF_EN2P, 0x7E30C800, 0x2E20C400) +INST2(fmaxnmp, "fmaxnmp", 0, IF_EN2P, 0x7E30C800, 0x2E20C400) // fmaxnmp Vd,Vn DV_2Q 011111100X110000 110010nnnnnddddd 7E30 C800 Vd,Vn (scalar) // fmaxnmp Vd,Vn,Vm DV_3B 0Q1011100X1mmmmm 110001nnnnnddddd 2E20 C400 Vd,Vn,Vm (vector) -INST2(fmaxp, "fmaxp", 0, 0, IF_EN2P, 0x7E30F800, 0x2E20F400) +INST2(fmaxp, "fmaxp", 0, IF_EN2P, 0x7E30F800, 0x2E20F400) // fmaxp Vd,Vn DV_2Q 011111100X110000 111110nnnnnddddd 7E30 F800 Vd,Vn (scalar) // fmaxp Vd,Vn,Vm DV_3B 0Q1011100X1mmmmm 111101nnnnnddddd 2E20 F400 Vd,Vn,Vm (vector) -INST2(fminnmp, "fminnmp",0, 0, IF_EN2P, 0x7EB0C800, 0x2EA0C400) +INST2(fminnmp, "fminnmp", 0, IF_EN2P, 0x7EB0C800, 0x2EA0C400) // fminnmp Vd,Vn DV_2Q 011111101X110000 110010nnnnnddddd 7EB0 C800 Vd,Vn (scalar) // fminnmp Vd,Vn,Vm DV_3B 0Q1011101X1mmmmm 110001nnnnnddddd 2EA0 C400 Vd,Vn,Vm (vector) -INST2(fminp, "fminp", 0, 0, IF_EN2P, 0x7EB0F800, 0x2EA0F400) +INST2(fminp, "fminp", 0, IF_EN2P, 0x7EB0F800, 0x2EA0F400) // fminp Vd,Vn DV_2Q 011111101X110000 111110nnnnnddddd 7EB0 F800 Vd,Vn (scalar) // fminp Vd,Vn,Vm DV_3B 0Q1011101X1mmmmm 111101nnnnnddddd 2EA0 F400 Vd,Vn,Vm (vector) -INST2(addp, "addp", 0, 0, IF_EN2Q, 0x5E31B800, 0x0E20BC00) +INST2(addp, "addp", 0, IF_EN2Q, 0x5E31B800, 0x0E20BC00) // addp Vd,Vn DV_2S 01011110XX110001 101110nnnnnddddd 5E31 B800 Vd,Vn (scalar) // addp Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 101111nnnnnddddd 0E20 BC00 Vd,Vn,Vm (vector) -INST1(ldar, "ldar", 0,LD, IF_LS_2A, 0x88DFFC00) +INST1(ldar, "ldar", LD, IF_LS_2A, 0x88DFFC00) // ldar Rt,[Xn] LS_2A 1X00100011011111 111111nnnnnttttt 88DF FC00 -INST1(ldarb, "ldarb", 0,LD, IF_LS_2A, 0x08DFFC00) +INST1(ldarb, "ldarb", LD, IF_LS_2A, 0x08DFFC00) // ldarb Rt,[Xn] LS_2A 0000100011011111 111111nnnnnttttt 08DF FC00 -INST1(ldarh, "ldarh", 0,LD, IF_LS_2A, 0x48DFFC00) +INST1(ldarh, "ldarh", LD, IF_LS_2A, 0x48DFFC00) // ldarh Rt,[Xn] LS_2A 0100100011011111 111111nnnnnttttt 48DF FC00 -INST1(ldxr, "ldxr", 0,LD, IF_LS_2A, 0x885F7C00) +INST1(ldxr, "ldxr", LD, IF_LS_2A, 0x885F7C00) // ldxr Rt,[Xn] LS_2A 1X00100001011111 011111nnnnnttttt 885F 7C00 -INST1(ldxrb, "ldxrb", 0,LD, IF_LS_2A, 0x085F7C00) +INST1(ldxrb, "ldxrb", LD, IF_LS_2A, 0x085F7C00) // ldxrb Rt,[Xn] LS_2A 0000100001011111 011111nnnnnttttt 085F 7C00 -INST1(ldxrh, "ldxrh", 0,LD, IF_LS_2A, 0x485F7C00) +INST1(ldxrh, "ldxrh", LD, IF_LS_2A, 0x485F7C00) // ldxrh Rt,[Xn] LS_2A 0100100001011111 011111nnnnnttttt 485F 7C00 -INST1(ldaxr, "ldaxr", 0,LD, IF_LS_2A, 0x885FFC00) +INST1(ldaxr, "ldaxr", LD, IF_LS_2A, 0x885FFC00) // ldaxr Rt,[Xn] LS_2A 1X00100001011111 111111nnnnnttttt 885F FC00 -INST1(ldaxrb, "ldaxrb", 0,LD, IF_LS_2A, 0x085FFC00) +INST1(ldaxrb, "ldaxrb", LD, IF_LS_2A, 0x085FFC00) // ldaxrb Rt,[Xn] LS_2A 0000100001011111 111111nnnnnttttt 085F FC00 -INST1(ldaxrh, "ldaxrh", 0,LD, IF_LS_2A, 0x485FFC00) +INST1(ldaxrh, "ldaxrh", LD, IF_LS_2A, 0x485FFC00) // ldaxrh Rt,[Xn] LS_2A 0100100001011111 111111nnnnnttttt 485F FC00 -INST1(ldur, "ldur", 0,LD, IF_LS_2C, 0xB8400000) +INST1(ldur, "ldur", LD, IF_LS_2C, 0xB8400000) // ldur Rt,[Xn+simm9] LS_2C 1X111000010iiiii iiii00nnnnnttttt B840 0000 [Xn imm(-256..+255)] -INST1(ldurb, "ldurb", 0,LD, IF_LS_2C, 0x38400000) +INST1(ldurb, "ldurb", LD, IF_LS_2C, 0x38400000) // ldurb Rt,[Xn+simm9] LS_2C 00111000010iiiii iiii00nnnnnttttt 3840 0000 [Xn imm(-256..+255)] -INST1(ldurh, "ldurh", 0,LD, IF_LS_2C, 0x78400000) +INST1(ldurh, "ldurh", LD, IF_LS_2C, 0x78400000) // ldurh Rt,[Xn+simm9] LS_2C 01111000010iiiii iiii00nnnnnttttt 7840 0000 [Xn imm(-256..+255)] -INST1(ldursb, "ldursb", 0,LD, IF_LS_2C, 0x38800000) +INST1(ldursb, "ldursb", LD, IF_LS_2C, 0x38800000) // ldursb Rt,[Xn+simm9] LS_2C 001110001X0iiiii iiii00nnnnnttttt 3880 0000 [Xn imm(-256..+255)] -INST1(ldursh, "ldursh", 0,LD, IF_LS_2C, 0x78800000) +INST1(ldursh, "ldursh", LD, IF_LS_2C, 0x78800000) // ldursh Rt,[Xn+simm9] LS_2C 011110001X0iiiii iiii00nnnnnttttt 7880 0000 [Xn imm(-256..+255)] -INST1(ldursw, "ldursw", 0,LD, IF_LS_2C, 0xB8800000) +INST1(ldursw, "ldursw", LD, IF_LS_2C, 0xB8800000) // ldursw Rt,[Xn+simm9] LS_2C 10111000100iiiii iiii00nnnnnttttt B880 0000 [Xn imm(-256..+255)] -INST1(stlr, "stlr", 0,ST, IF_LS_2A, 0x889FFC00) +INST1(stlr, "stlr", ST, IF_LS_2A, 0x889FFC00) // stlr Rt,[Xn] LS_2A 1X00100010011111 111111nnnnnttttt 889F FC00 -INST1(stlrb, "stlrb", 0,ST, IF_LS_2A, 0x089FFC00) +INST1(stlrb, "stlrb", ST, IF_LS_2A, 0x089FFC00) // stlrb Rt,[Xn] LS_2A 0000100010011111 111111nnnnnttttt 089F FC00 -INST1(stlrh, "stlrh", 0,ST, IF_LS_2A, 0x489FFC00) +INST1(stlrh, "stlrh", ST, IF_LS_2A, 0x489FFC00) // stlrh Rt,[Xn] LS_2A 0100100010011111 111111nnnnnttttt 489F FC00 -INST1(stxr, "stxr", 0,ST, IF_LS_3D, 0x88007C00) +INST1(stxr, "stxr", ST, IF_LS_3D, 0x88007C00) // stxr Ws, Rt,[Xn] LS_3D 1X001000000sssss 011111nnnnnttttt 8800 7C00 -INST1(stxrb, "stxrb", 0,ST, IF_LS_3D, 0x08007C00) +INST1(stxrb, "stxrb", ST, IF_LS_3D, 0x08007C00) // stxrb Ws, Rt,[Xn] LS_3D 00001000000sssss 011111nnnnnttttt 0800 7C00 -INST1(stxrh, "stxrh", 0,ST, IF_LS_3D, 0x48007C00) +INST1(stxrh, "stxrh", ST, IF_LS_3D, 0x48007C00) // stxrh Ws, Rt,[Xn] LS_3D 01001000000sssss 011111nnnnnttttt 4800 7C00 -INST1(stlxr, "stlxr", 0,ST, IF_LS_3D, 0x8800FC00) +INST1(stlxr, "stlxr", ST, IF_LS_3D, 0x8800FC00) // stlxr Ws, Rt,[Xn] LS_3D 1X001000000sssss 111111nnnnnttttt 8800 FC00 -INST1(stlxrb, "stlxrb", 0,ST, IF_LS_3D, 0x0800FC00) +INST1(stlxrb, "stlxrb", ST, IF_LS_3D, 0x0800FC00) // stlxrb Ws, Rt,[Xn] LS_3D 00001000000sssss 111111nnnnnttttt 0800 FC00 -INST1(stlxrh, "stlxrh", 0,ST, IF_LS_3D, 0x4800FC00) +INST1(stlxrh, "stlxrh", ST, IF_LS_3D, 0x4800FC00) // stlxrh Ws, Rt,[Xn] LS_3D 01001000000sssss 111111nnnnnttttt 4800 FC00 -INST1(stur, "stur", 0,ST, IF_LS_2C, 0xB8000000) +INST1(stur, "stur", ST, IF_LS_2C, 0xB8000000) // stur Rt,[Xn+simm9] LS_2C 1X111000000iiiii iiii00nnnnnttttt B800 0000 [Xn imm(-256..+255)] -INST1(sturb, "sturb", 0,ST, IF_LS_2C, 0x38000000) +INST1(sturb, "sturb", ST, IF_LS_2C, 0x38000000) // sturb Rt,[Xn+simm9] LS_2C 00111000000iiiii iiii00nnnnnttttt 3800 0000 [Xn imm(-256..+255)] -INST1(sturh, "sturh", 0,ST, IF_LS_2C, 0x78000000) +INST1(sturh, "sturh", ST, IF_LS_2C, 0x78000000) // sturh Rt,[Xn+simm9] LS_2C 01111000000iiiii iiii00nnnnnttttt 7800 0000 [Xn imm(-256..+255)] -INST1(casb, "casb", 0, LD|ST, IF_LS_3E, 0x08A07C00) +INST1(casb, "casb", LD|ST, IF_LS_3E, 0x08A07C00) // casb Wm, Wt, [Xn] LS_3E 00001000101mmmmm 011111nnnnnttttt 08A0 7C00 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(casab, "casab", 0, LD|ST, IF_LS_3E, 0x08E07C00) +INST1(casab, "casab", LD|ST, IF_LS_3E, 0x08E07C00) // casab Wm, Wt, [Xn] LS_3E 00001000111mmmmm 011111nnnnnttttt 08E0 7C00 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(casalb, "casalb", 0, LD|ST, IF_LS_3E, 0x08E0FC00) +INST1(casalb, "casalb", LD|ST, IF_LS_3E, 0x08E0FC00) // casalb Wm, Wt, [Xn] LS_3E 00001000111mmmmm 111111nnnnnttttt 08E0 FC00 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(caslb, "caslb", 0, LD|ST, IF_LS_3E, 0x08A0FC00) +INST1(caslb, "caslb", LD|ST, IF_LS_3E, 0x08A0FC00) // caslb Wm, Wt, [Xn] LS_3E 00001000101mmmmm 111111nnnnnttttt 08A0 FC00 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(cash, "cash", 0, LD|ST, IF_LS_3E, 0x48A07C00) +INST1(cash, "cash", LD|ST, IF_LS_3E, 0x48A07C00) // cash Wm, Wt, [Xn] LS_3E 01001000101mmmmm 011111nnnnnttttt 48A0 7C00 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(casah, "casah", 0, LD|ST, IF_LS_3E, 0x48E07C00) +INST1(casah, "casah", LD|ST, IF_LS_3E, 0x48E07C00) // casah Wm, Wt, [Xn] LS_3E 01001000111mmmmm 011111nnnnnttttt 48E0 7C00 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(casalh, "casalh", 0, LD|ST, IF_LS_3E, 0x48E0FC00) +INST1(casalh, "casalh", LD|ST, IF_LS_3E, 0x48E0FC00) // casalh Wm, Wt, [Xn] LS_3E 01001000111mmmmm 111111nnnnnttttt 48E0 FC00 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(caslh, "caslh", 0, LD|ST, IF_LS_3E, 0x48A0FC00) +INST1(caslh, "caslh", LD|ST, IF_LS_3E, 0x48A0FC00) // caslh Wm, Wt, [Xn] LS_3E 01001000101mmmmm 111111nnnnnttttt 48A0 FC00 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(cas, "cas", 0, LD|ST, IF_LS_3E, 0x88A07C00) +INST1(cas, "cas", LD|ST, IF_LS_3E, 0x88A07C00) // cas Rm, Rt, [Xn] LS_3E 1X001000101mmmmm 011111nnnnnttttt 88A0 7C00 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(casa, "casa", 0, LD|ST, IF_LS_3E, 0x88E07C00) +INST1(casa, "casa", LD|ST, IF_LS_3E, 0x88E07C00) // casa Rm, Rt, [Xn] LS_3E 1X001000111mmmmm 011111nnnnnttttt 88E0 7C00 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(casal, "casal", 0, LD|ST, IF_LS_3E, 0x88E0FC00) +INST1(casal, "casal", LD|ST, IF_LS_3E, 0x88E0FC00) // casal Rm, Rt, [Xn] LS_3E 1X001000111mmmmm 111111nnnnnttttt 88E0 FC00 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(casl, "casl", 0, LD|ST, IF_LS_3E, 0x88A0FC00) +INST1(casl, "casl", LD|ST, IF_LS_3E, 0x88A0FC00) // casl Rm, Rt, [Xn] LS_3E 1X001000101mmmmm 111111nnnnnttttt 88A0 FC00 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(ldaddb, "ldaddb", 0, LD|ST, IF_LS_3E, 0x38200000) +INST1(ldaddb, "ldaddb", LD|ST, IF_LS_3E, 0x38200000) // ldaddb Wm, Wt, [Xn] LS_3E 00111000001mmmmm 000000nnnnnttttt 3820 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(ldaddab, "ldaddab", 0, LD|ST, IF_LS_3E, 0x38A00000) +INST1(ldaddab, "ldaddab", LD|ST, IF_LS_3E, 0x38A00000) // ldaddab Wm, Wt, [Xn] LS_3E 00111000101mmmmm 000000nnnnnttttt 38A0 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(ldaddalb,"ldaddalb",0, LD|ST, IF_LS_3E, 0x38E00000) +INST1(ldaddalb, "ldaddalb", LD|ST, IF_LS_3E, 0x38E00000) // ldaddalb Wm, Wt, [Xn] LS_3E 00111000111mmmmm 000000nnnnnttttt 38E0 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(ldaddlb, "ldaddlb", 0, LD|ST, IF_LS_3E, 0x38600000) +INST1(ldaddlb, "ldaddlb", LD|ST, IF_LS_3E, 0x38600000) // ldaddlb Wm, Wt, [Xn] LS_3E 00111000011mmmmm 000000nnnnnttttt 3860 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(ldaddh, "ldaddh", 0, LD|ST, IF_LS_3E, 0x78200000) +INST1(ldaddh, "ldaddh", LD|ST, IF_LS_3E, 0x78200000) // ldaddh Wm, Wt, [Xn] LS_3E 01111000001mmmmm 000000nnnnnttttt 7820 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(ldaddah, "ldaddah", 0, LD|ST, IF_LS_3E, 0x78A00000) +INST1(ldaddah, "ldaddah", LD|ST, IF_LS_3E, 0x78A00000) // ldaddah Wm, Wt, [Xn] LS_3E 01111000101mmmmm 000000nnnnnttttt 78A0 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(ldaddalh,"ldaddalh",0, LD|ST, IF_LS_3E, 0x78E00000) +INST1(ldaddalh, "ldaddalh", LD|ST, IF_LS_3E, 0x78E00000) // ldaddalh Wm, Wt, [Xn] LS_3E 01111000111mmmmm 000000nnnnnttttt 78E0 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(ldaddlh, "ldaddlh", 0, LD|ST, IF_LS_3E, 0x78600000) +INST1(ldaddlh, "ldaddlh", LD|ST, IF_LS_3E, 0x78600000) // ldaddlh Wm, Wt, [Xn] LS_3E 01111000011mmmmm 000000nnnnnttttt 7860 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(ldadd, "ldadd", 0, LD|ST, IF_LS_3E, 0xB8200000) +INST1(ldadd, "ldadd", LD|ST, IF_LS_3E, 0xB8200000) // ldadd Rm, Rt, [Xn] LS_3E 1X111000001mmmmm 000000nnnnnttttt B820 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(ldadda, "ldadda", 0, LD|ST, IF_LS_3E, 0xB8A00000) +INST1(ldadda, "ldadda", LD|ST, IF_LS_3E, 0xB8A00000) // ldadda Rm, Rt, [Xn] LS_3E 1X111000101mmmmm 000000nnnnnttttt B8A0 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(ldaddal, "ldaddal", 0, LD|ST, IF_LS_3E, 0xB8E00000) +INST1(ldaddal, "ldaddal", LD|ST, IF_LS_3E, 0xB8E00000) // ldaddal Rm, Rt, [Xn] LS_3E 1X111000111mmmmm 000000nnnnnttttt B8E0 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(ldaddl, "ldaddl", 0, LD|ST, IF_LS_3E, 0xB8600000) +INST1(ldaddl, "ldaddl", LD|ST, IF_LS_3E, 0xB8600000) // ldaddl Rm, Rt, [Xn] LS_3E 1X111000011mmmmm 000000nnnnnttttt B860 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(staddb, "staddb", 0, ST, IF_LS_3E, 0x38200000) +INST1(staddb, "staddb", ST, IF_LS_3E, 0x38200000) // staddb Wm, [Xn] LS_3E 00111000001mmmmm 000000nnnnnttttt 3820 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(staddlb, "staddlb", 0, ST, IF_LS_3E, 0x38600000) +INST1(staddlb, "staddlb", ST, IF_LS_3E, 0x38600000) // staddlb Wm, [Xn] LS_3E 00111000011mmmmm 000000nnnnnttttt 3860 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(staddh, "staddh", 0, ST, IF_LS_3E, 0x78200000) +INST1(staddh, "staddh", ST, IF_LS_3E, 0x78200000) // staddh Wm, [Xn] LS_3E 01111000001mmmmm 000000nnnnnttttt 7820 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(staddlh, "staddlh", 0, ST, IF_LS_3E, 0x78600000) +INST1(staddlh, "staddlh", ST, IF_LS_3E, 0x78600000) // staddlh Wm, [Xn] LS_3E 01111000011mmmmm 000000nnnnnttttt 7860 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(stadd, "stadd", 0, ST, IF_LS_3E, 0xB8200000) +INST1(stadd, "stadd", ST, IF_LS_3E, 0xB8200000) // stadd Rm, [Xn] LS_3E 1X111000001mmmmm 000000nnnnnttttt B820 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(staddl, "staddl", 0, ST, IF_LS_3E, 0xB8600000) +INST1(staddl, "staddl", ST, IF_LS_3E, 0xB8600000) // staddl Rm, [Xn] LS_3E 1X111000011mmmmm 000000nnnnnttttt B860 0000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(swpb, "swpb", 0, LD|ST, IF_LS_3E, 0x38208000) +INST1(swpb, "swpb", LD|ST, IF_LS_3E, 0x38208000) // swpb Wm, Wt, [Xn] LS_3E 00111000001mmmmm 100000nnnnnttttt 3820 8000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(swpab, "swpab", 0, LD|ST, IF_LS_3E, 0x38A08000) +INST1(swpab, "swpab", LD|ST, IF_LS_3E, 0x38A08000) // swpab Wm, Wt, [Xn] LS_3E 00111000101mmmmm 100000nnnnnttttt 38A0 8000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(swpalb, "swpalb", 0, LD|ST, IF_LS_3E, 0x38E08000) +INST1(swpalb, "swpalb", LD|ST, IF_LS_3E, 0x38E08000) // swpalb Wm, Wt, [Xn] LS_3E 00111000111mmmmm 100000nnnnnttttt 38E0 8000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(swplb, "swplb", 0, LD|ST, IF_LS_3E, 0x38608000) +INST1(swplb, "swplb", LD|ST, IF_LS_3E, 0x38608000) // swplb Wm, Wt, [Xn] LS_3E 00111000011mmmmm 100000nnnnnttttt 3860 8000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(swph, "swph", 0, LD|ST, IF_LS_3E, 0x78208000) +INST1(swph, "swph", LD|ST, IF_LS_3E, 0x78208000) // swph Wm, Wt, [Xn] LS_3E 01111000001mmmmm 100000nnnnnttttt 7820 8000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(swpah, "swpah", 0, LD|ST, IF_LS_3E, 0x78A08000) +INST1(swpah, "swpah", LD|ST, IF_LS_3E, 0x78A08000) // swpah Wm, Wt, [Xn] LS_3E 01111000101mmmmm 100000nnnnnttttt 78A0 8000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(swpalh, "swpalh", 0, LD|ST, IF_LS_3E, 0x78E08000) +INST1(swpalh, "swpalh", LD|ST, IF_LS_3E, 0x78E08000) // swpalh Wm, Wt, [Xn] LS_3E 01111000111mmmmm 100000nnnnnttttt 78E0 8000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(swplh, "swplh", 0, LD|ST, IF_LS_3E, 0x78608000) +INST1(swplh, "swplh", LD|ST, IF_LS_3E, 0x78608000) // swplh Wm, Wt, [Xn] LS_3E 01111000011mmmmm 100000nnnnnttttt 7860 8000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(swp, "swp", 0, LD|ST, IF_LS_3E, 0xB8208000) +INST1(swp, "swp", LD|ST, IF_LS_3E, 0xB8208000) // swp Rm, Rt, [Xn] LS_3E 1X111000001mmmmm 100000nnnnnttttt B820 8000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(swpa, "swpa", 0, LD|ST, IF_LS_3E, 0xB8A08000) +INST1(swpa, "swpa", LD|ST, IF_LS_3E, 0xB8A08000) // swpa Rm, Rt, [Xn] LS_3E 1X111000101mmmmm 100000nnnnnttttt B8A0 8000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(swpal, "swpal", 0, LD|ST, IF_LS_3E, 0xB8E08000) +INST1(swpal, "swpal", LD|ST, IF_LS_3E, 0xB8E08000) // swpal Rm, Rt, [Xn] LS_3E 1X111000111mmmmm 100000nnnnnttttt B8E0 8000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(swpl, "swpl", 0, LD|ST, IF_LS_3E, 0xB8608000) +INST1(swpl, "swpl", LD|ST, IF_LS_3E, 0xB8608000) // swpl Rm, Rt, [Xn] LS_3E 1X111000011mmmmm 100000nnnnnttttt B860 8000 Rm Rt Rn ARMv8.1 LSE Atomics -INST1(adr, "adr", 0, 0, IF_DI_1E, 0x10000000) +INST1(adr, "adr", 0, IF_DI_1E, 0x10000000) // adr Rd, simm21 DI_1E 0ii10000iiiiiiii iiiiiiiiiiiddddd 1000 0000 Rd simm21 -INST1(adrp, "adrp", 0, 0, IF_DI_1E, 0x90000000) +INST1(adrp, "adrp", 0, IF_DI_1E, 0x90000000) // adrp Rd, simm21 DI_1E 1ii10000iiiiiiii iiiiiiiiiiiddddd 9000 0000 Rd simm21 -INST1(b, "b", 0, 0, IF_BI_0A, 0x14000000) +INST1(b, "b", 0, IF_BI_0A, 0x14000000) // b simm26 BI_0A 000101iiiiiiiiii iiiiiiiiiiiiiiii 1400 0000 simm26:00 -INST1(b_tail, "b", 0, 0, IF_BI_0C, 0x14000000) +INST1(b_tail, "b", 0, IF_BI_0C, 0x14000000) // b simm26 BI_0A 000101iiiiiiiiii iiiiiiiiiiiiiiii 1400 0000 simm26:00, same as b representing a tail call of bl. -INST1(bl_local,"bl", 0, 0, IF_BI_0A, 0x94000000) +INST1(bl_local, "bl", 0, IF_BI_0A, 0x94000000) // bl simm26 BI_0A 100101iiiiiiiiii iiiiiiiiiiiiiiii 9400 0000 simm26:00, same as bl, but with a BasicBlock target. -INST1(bl, "bl", 0, 0, IF_BI_0C, 0x94000000) +INST1(bl, "bl", 0, IF_BI_0C, 0x94000000) // bl simm26 BI_0C 100101iiiiiiiiii iiiiiiiiiiiiiiii 9400 0000 simm26:00 -INST1(br, "br", 0, 0, IF_BR_1A, 0xD61F0000) +INST1(br, "br", 0, IF_BR_1A, 0xD61F0000) // br Rn BR_1A 1101011000011111 000000nnnnn00000 D61F 0000, an indirect branch like switch expansion -INST1(br_tail, "br", 0, 0, IF_BR_1B, 0xD61F0000) +INST1(br_tail, "br", 0, IF_BR_1B, 0xD61F0000) // br Rn BR_1B 1101011000011111 000000nnnnn00000 D61F 0000, same as br representing a tail call of blr. Encode target with Reg3. -INST1(blr, "blr", 0, 0, IF_BR_1B, 0xD63F0000) +INST1(blr, "blr", 0, IF_BR_1B, 0xD63F0000) // blr Rn BR_1B 1101011000111111 000000nnnnn00000 D63F 0000, Encode target with Reg3. -INST1(ret, "ret", 0, 0, IF_BR_1A, 0xD65F0000) +INST1(ret, "ret", 0, IF_BR_1A, 0xD65F0000) // ret Rn BR_1A 1101011001011111 000000nnnnn00000 D65F 0000 -INST1(beq, "beq", 0, 0, IF_BI_0B, 0x54000000) +INST1(beq, "beq", 0, IF_BI_0B, 0x54000000) // beq simm19 BI_0B 01010100iiiiiiii iiiiiiiiiii00000 5400 0000 simm19:00 -INST1(bne, "bne", 0, 0, IF_BI_0B, 0x54000001) +INST1(bne, "bne", 0, IF_BI_0B, 0x54000001) // bne simm19 BI_0B 01010100iiiiiiii iiiiiiiiiii00001 5400 0001 simm19:00 -INST1(bhs, "bhs", 0, 0, IF_BI_0B, 0x54000002) +INST1(bhs, "bhs", 0, IF_BI_0B, 0x54000002) // bhs simm19 BI_0B 01010100iiiiiiii iiiiiiiiiii00010 5400 0002 simm19:00 -INST1(blo, "blo", 0, 0, IF_BI_0B, 0x54000003) +INST1(blo, "blo", 0, IF_BI_0B, 0x54000003) // blo simm19 BI_0B 01010100iiiiiiii iiiiiiiiiii00011 5400 0003 simm19:00 -INST1(bmi, "bmi", 0, 0, IF_BI_0B, 0x54000004) +INST1(bmi, "bmi", 0, IF_BI_0B, 0x54000004) // bmi simm19 BI_0B 01010100iiiiiiii iiiiiiiiiii00100 5400 0004 simm19:00 -INST1(bpl, "bpl", 0, 0, IF_BI_0B, 0x54000005) +INST1(bpl, "bpl", 0, IF_BI_0B, 0x54000005) // bpl simm19 BI_0B 01010100iiiiiiii iiiiiiiiiii00101 5400 0005 simm19:00 -INST1(bvs, "bvs", 0, 0, IF_BI_0B, 0x54000006) +INST1(bvs, "bvs", 0, IF_BI_0B, 0x54000006) // bvs simm19 BI_0B 01010100iiiiiiii iiiiiiiiiii00110 5400 0006 simm19:00 -INST1(bvc, "bvc", 0, 0, IF_BI_0B, 0x54000007) +INST1(bvc, "bvc", 0, IF_BI_0B, 0x54000007) // bvc simm19 BI_0B 01010100iiiiiiii iiiiiiiiiii00111 5400 0007 simm19:00 -INST1(bhi, "bhi", 0, 0, IF_BI_0B, 0x54000008) +INST1(bhi, "bhi", 0, IF_BI_0B, 0x54000008) // bhi simm19 BI_0B 01010100iiiiiiii iiiiiiiiiii01000 5400 0008 simm19:00 -INST1(bls, "bls", 0, 0, IF_BI_0B, 0x54000009) +INST1(bls, "bls", 0, IF_BI_0B, 0x54000009) // bls simm19 BI_0B 01010100iiiiiiii iiiiiiiiiii01001 5400 0009 simm19:00 -INST1(bge, "bge", 0, 0, IF_BI_0B, 0x5400000A) +INST1(bge, "bge", 0, IF_BI_0B, 0x5400000A) // bge simm19 BI_0B 01010100iiiiiiii iiiiiiiiiii01010 5400 000A simm19:00 -INST1(blt, "blt", 0, 0, IF_BI_0B, 0x5400000B) +INST1(blt, "blt", 0, IF_BI_0B, 0x5400000B) // blt simm19 BI_0B 01010100iiiiiiii iiiiiiiiiii01011 5400 000B simm19:00 -INST1(bgt, "bgt", 0, 0, IF_BI_0B, 0x5400000C) +INST1(bgt, "bgt", 0, IF_BI_0B, 0x5400000C) // bgt simm19 BI_0B 01010100iiiiiiii iiiiiiiiiii01100 5400 000C simm19:00 -INST1(ble, "ble", 0, 0, IF_BI_0B, 0x5400000D) +INST1(ble, "ble", 0, IF_BI_0B, 0x5400000D) // ble simm19 BI_0B 01010100iiiiiiii iiiiiiiiiii01101 5400 000D simm19:00 -INST1(cbz, "cbz", 0, 0, IF_BI_1A, 0x34000000) +INST1(cbz, "cbz", 0, IF_BI_1A, 0x34000000) // cbz Rt, simm19 BI_1A X0110100iiiiiiii iiiiiiiiiiittttt 3400 0000 Rt simm19:00 -INST1(cbnz, "cbnz", 0, 0, IF_BI_1A, 0x35000000) +INST1(cbnz, "cbnz", 0, IF_BI_1A, 0x35000000) // cbnz Rt, simm19 BI_1A X0110101iiiiiiii iiiiiiiiiiittttt 3500 0000 Rt simm19:00 -INST1(tbz, "tbz", 0, 0, IF_BI_1B, 0x36000000) +INST1(tbz, "tbz", 0, IF_BI_1B, 0x36000000) // tbz Rt, imm6, simm14 BI_1B B0110110bbbbbiii iiiiiiiiiiittttt 3600 0000 Rt imm6, simm14:00 -INST1(tbnz, "tbnz", 0, 0, IF_BI_1B, 0x37000000) +INST1(tbnz, "tbnz", 0, IF_BI_1B, 0x37000000) // tbnz Rt, imm6, simm14 BI_1B B0110111bbbbbiii iiiiiiiiiiittttt 3700 0000 Rt imm6, simm14:00 -INST1(movk, "movk", 0, 0, IF_DI_1B, 0x72800000) +INST1(movk, "movk", 0, IF_DI_1B, 0x72800000) // movk Rd,imm(i16,hw) DI_1B X11100101hwiiiii iiiiiiiiiiiddddd 7280 0000 imm(i16,hw) -INST1(movn, "movn", 0, 0, IF_DI_1B, 0x12800000) +INST1(movn, "movn", 0, IF_DI_1B, 0x12800000) // movn Rd,imm(i16,hw) DI_1B X00100101hwiiiii iiiiiiiiiiiddddd 1280 0000 imm(i16,hw) -INST1(movz, "movz", 0, 0, IF_DI_1B, 0x52800000) +INST1(movz, "movz", 0, IF_DI_1B, 0x52800000) // movz Rd,imm(i16,hw) DI_1B X10100101hwiiiii iiiiiiiiiiiddddd 5280 0000 imm(i16,hw) -INST1(csel, "csel", 0, 0, IF_DR_3D, 0x1A800000) +INST1(csel, "csel", 0, IF_DR_3D, 0x1A800000) // csel Rd,Rn,Rm,cond DR_3D X0011010100mmmmm cccc00nnnnnddddd 1A80 0000 cond -INST1(csinc, "csinc", 0, 0, IF_DR_3D, 0x1A800400) +INST1(csinc, "csinc", 0, IF_DR_3D, 0x1A800400) // csinc Rd,Rn,Rm,cond DR_3D X0011010100mmmmm cccc01nnnnnddddd 1A80 0400 cond -INST1(csinv, "csinv", 0, 0, IF_DR_3D, 0x5A800000) +INST1(csinv, "csinv", 0, IF_DR_3D, 0x5A800000) // csinv Rd,Rn,Rm,cond DR_3D X1011010100mmmmm cccc00nnnnnddddd 5A80 0000 cond -INST1(csneg, "csneg", 0, 0, IF_DR_3D, 0x5A800400) +INST1(csneg, "csneg", 0, IF_DR_3D, 0x5A800400) // csneg Rd,Rn,Rm,cond DR_3D X1011010100mmmmm cccc01nnnnnddddd 5A80 0400 cond -INST1(cinc, "cinc", 0, 0, IF_DR_2D, 0x1A800400) +INST1(cinc, "cinc", 0, IF_DR_2D, 0x1A800400) // cinc Rd,Rn,cond DR_2D X0011010100nnnnn cccc01nnnnnddddd 1A80 0400 cond -INST1(cinv, "cinv", 0, 0, IF_DR_2D, 0x5A800000) +INST1(cinv, "cinv", 0, IF_DR_2D, 0x5A800000) // cinv Rd,Rn,cond DR_2D X1011010100nnnnn cccc00nnnnnddddd 5A80 0000 cond -INST1(cneg, "cneg", 0, 0, IF_DR_2D, 0x5A800400) +INST1(cneg, "cneg", 0, IF_DR_2D, 0x5A800400) // cneg Rd,Rn,cond DR_2D X1011010100nnnnn cccc01nnnnnddddd 5A80 0400 cond -INST1(cset, "cset", 0, 0, IF_DR_1D, 0x1A9F07E0) +INST1(cset, "cset", 0, IF_DR_1D, 0x1A9F07E0) // cset Rd,cond DR_1D X001101010011111 cccc0111111ddddd 1A9F 07E0 Rd cond -INST1(csetm, "csetm", 0, 0, IF_DR_1D, 0x5A9F03E0) +INST1(csetm, "csetm", 0, IF_DR_1D, 0x5A9F03E0) // csetm Rd,cond DR_1D X101101010011111 cccc0011111ddddd 5A9F 03E0 Rd cond -INST1(aese, "aese", 0, 0, IF_DV_2P, 0x4E284800) +INST1(aese, "aese", 0, IF_DV_2P, 0x4E284800) // aese Vd.16B,Vn.16B DV_2P 0100111000101000 010010nnnnnddddd 4E28 4800 Vd.16B Vn.16B (vector) -INST1(aesd, "aesd", 0, 0, IF_DV_2P, 0x4E285800) +INST1(aesd, "aesd", 0, IF_DV_2P, 0x4E285800) // aesd Vd.16B,Vn.16B DV_2P 0100111000101000 010110nnnnnddddd 4E28 5800 Vd.16B Vn.16B (vector) -INST1(aesmc, "aesmc", 0, 0, IF_DV_2P, 0x4E286800) +INST1(aesmc, "aesmc", 0, IF_DV_2P, 0x4E286800) // aesmc Vd.16B,Vn.16B DV_2P 0100111000101000 011010nnnnnddddd 4E28 6800 Vd.16B Vn.16B (vector) -INST1(aesimc, "aesimc", 0, 0, IF_DV_2P, 0x4E287800) +INST1(aesimc, "aesimc", 0, IF_DV_2P, 0x4E287800) // aesimc Vd.16B,Vn.16B DV_2P 0100111000101000 011110nnnnnddddd 4E28 7800 Vd.16B Vn.16B (vector) -INST1(rev, "rev", 0, 0, IF_DR_2G, 0x5AC00800) +INST1(rev, "rev", 0, IF_DR_2G, 0x5AC00800) // rev Rd,Rm DR_2G X101101011000000 00001Xnnnnnddddd 5AC0 0800 Rd Rn -INST1(rev64, "rev64", 0, 0, IF_DV_2M, 0x0E200800) +INST1(rev64, "rev64", 0, IF_DV_2M, 0x0E200800) // rev64 Vd,Vn DV_2M 0Q001110XX100000 000010nnnnnddddd 0E20 0800 Vd,Vn (vector) -INST1(adc, "adc", 0, 0, IF_DR_3A, 0x1A000000) +INST1(adc, "adc", 0, IF_DR_3A, 0x1A000000) // adc Rd,Rn,Rm DR_3A X0011010000mmmmm 000000nnnnnddddd 1A00 0000 -INST1(adcs, "adcs", 0, 0, IF_DR_3A, 0x3A000000) +INST1(adcs, "adcs", 0, IF_DR_3A, 0x3A000000) // adcs Rd,Rn,Rm DR_3A X0111010000mmmmm 000000nnnnnddddd 3A00 0000 -INST1(sbc, "sbc", 0, 0, IF_DR_3A, 0x5A000000) +INST1(sbc, "sbc", 0, IF_DR_3A, 0x5A000000) // sdc Rd,Rn,Rm DR_3A X1011010000mmmmm 000000nnnnnddddd 5A00 0000 -INST1(sbcs, "sbcs", 0, 0, IF_DR_3A, 0x7A000000) +INST1(sbcs, "sbcs", 0, IF_DR_3A, 0x7A000000) // sdcs Rd,Rn,Rm DR_3A X1111010000mmmmm 000000nnnnnddddd 7A00 0000 -INST1(udiv, "udiv", 0, 0, IF_DR_3A, 0x1AC00800) +INST1(udiv, "udiv", 0, IF_DR_3A, 0x1AC00800) // udiv Rd,Rn,Rm DR_3A X0011010110mmmmm 000010nnnnnddddd 1AC0 0800 -INST1(sdiv, "sdiv", 0, 0, IF_DR_3A, 0x1AC00C00) +INST1(sdiv, "sdiv", 0, IF_DR_3A, 0x1AC00C00) // sdiv Rd,Rn,Rm DR_3A X0011010110mmmmm 000011nnnnnddddd 1AC0 0C00 -INST1(mneg, "mneg", 0, 0, IF_DR_3A, 0x1B00FC00) +INST1(mneg, "mneg", 0, IF_DR_3A, 0x1B00FC00) // mneg Rd,Rn,Rm DR_3A X0011011000mmmmm 111111nnnnnddddd 1B00 FC00 -INST1(madd, "madd", 0, 0, IF_DR_4A, 0x1B000000) +INST1(madd, "madd", 0, IF_DR_4A, 0x1B000000) // madd Rd,Rn,Rm,Ra DR_4A X0011011000mmmmm 0aaaaannnnnddddd 1B00 0000 -INST1(msub, "msub", 0, 0, IF_DR_4A, 0x1B008000) +INST1(msub, "msub", 0, IF_DR_4A, 0x1B008000) // msub Rd,Rn,Rm,Ra DR_4A X0011011000mmmmm 1aaaaannnnnddddd 1B00 8000 -INST1(smull, "smull", 0, 0, IF_DR_3A, 0x9B207C00) - // smull Rd,Rn,Rm DR_3A 10011011001mmmmm 011111nnnnnddddd 9B20 7C00 - -INST1(smaddl, "smaddl", 0, 0, IF_DR_4A, 0x9B200000) +INST1(smaddl, "smaddl", 0, IF_DR_4A, 0x9B200000) // smaddl Rd,Rn,Rm,Ra DR_4A 10011011001mmmmm 0aaaaannnnnddddd 9B20 0000 -INST1(smnegl, "smnegl", 0, 0, IF_DR_3A, 0x9B20FC00) +INST1(smnegl, "smnegl", 0, IF_DR_3A, 0x9B20FC00) // smnegl Rd,Rn,Rm DR_3A 10011011001mmmmm 111111nnnnnddddd 9B20 FC00 -INST1(smsubl, "smsubl", 0, 0, IF_DR_4A, 0x9B208000) +INST1(smsubl, "smsubl", 0, IF_DR_4A, 0x9B208000) // smsubl Rd,Rn,Rm,Ra DR_4A 10011011001mmmmm 1aaaaannnnnddddd 9B20 8000 -INST1(smulh, "smulh", 0, 0, IF_DR_3A, 0x9B407C00) +INST1(smulh, "smulh", 0, IF_DR_3A, 0x9B407C00) // smulh Rd,Rn,Rm DR_3A 10011011010mmmmm 011111nnnnnddddd 9B40 7C00 -INST1(umull, "umull", 0, 0, IF_DR_3A, 0x9BA07C00) - // umull Rd,Rn,Rm DR_3A 10011011101mmmmm 011111nnnnnddddd 9BA0 7C00 - -INST1(umaddl, "umaddl", 0, 0, IF_DR_4A, 0x9BA00000) +INST1(umaddl, "umaddl", 0, IF_DR_4A, 0x9BA00000) // umaddl Rd,Rn,Rm,Ra DR_4A 10011011101mmmmm 0aaaaannnnnddddd 9BA0 0000 -INST1(umnegl, "umnegl", 0, 0, IF_DR_3A, 0x9BA0FC00) +INST1(umnegl, "umnegl", 0, IF_DR_3A, 0x9BA0FC00) // umnegl Rd,Rn,Rm DR_3A 10011011101mmmmm 111111nnnnnddddd 9BA0 FC00 -INST1(umsubl, "umsubl", 0, 0, IF_DR_4A, 0x9BA08000) +INST1(umsubl, "umsubl", 0, IF_DR_4A, 0x9BA08000) // umsubl Rd,Rn,Rm,Ra DR_4A 10011011101mmmmm 1aaaaannnnnddddd 9BA0 8000 -INST1(umulh, "umulh", 0, 0, IF_DR_3A, 0x9BC07C00) +INST1(umulh, "umulh", 0, IF_DR_3A, 0x9BC07C00) // umulh Rd,Rn,Rm DR_3A 10011011110mmmmm 011111nnnnnddddd 9BC0 7C00 -INST1(extr, "extr", 0, 0, IF_DR_3E, 0x13800000) +INST1(extr, "extr", 0, IF_DR_3E, 0x13800000) // extr Rd,Rn,Rm,imm6 DR_3E X00100111X0mmmmm ssssssnnnnnddddd 1380 0000 imm(0-63) -INST1(lslv, "lslv", 0, 0, IF_DR_3A, 0x1AC02000) +INST1(lslv, "lslv", 0, IF_DR_3A, 0x1AC02000) // lslv Rd,Rn,Rm DR_3A X0011010110mmmmm 001000nnnnnddddd 1AC0 2000 -INST1(lsrv, "lsrv", 0, 0, IF_DR_3A, 0x1AC02400) +INST1(lsrv, "lsrv", 0, IF_DR_3A, 0x1AC02400) // lsrv Rd,Rn,Rm DR_3A X0011010110mmmmm 001001nnnnnddddd 1AC0 2400 -INST1(asrv, "asrv", 0, 0, IF_DR_3A, 0x1AC02800) +INST1(asrv, "asrv", 0, IF_DR_3A, 0x1AC02800) // asrv Rd,Rn,Rm DR_3A X0011010110mmmmm 001010nnnnnddddd 1AC0 2800 -INST1(rorv, "rorv", 0, 0, IF_DR_3A, 0x1AC02C00) +INST1(rorv, "rorv", 0, IF_DR_3A, 0x1AC02C00) // rorv Rd,Rn,Rm DR_3A X0011010110mmmmm 001011nnnnnddddd 1AC0 2C00 -INST1(crc32b, "crc32b", 0, 0, IF_DR_3A, 0x1AC04000) +INST1(crc32b, "crc32b", 0, IF_DR_3A, 0x1AC04000) // crc32b Rd,Rn,Rm DR_3A 00011010110mmmmm 010000nnnnnddddd 1AC0 4000 -INST1(crc32h, "crc32h", 0, 0, IF_DR_3A, 0x1AC04400) +INST1(crc32h, "crc32h", 0, IF_DR_3A, 0x1AC04400) // crc32h Rd,Rn,Rm DR_3A 00011010110mmmmm 010001nnnnnddddd 1AC0 4400 -INST1(crc32w, "crc32w", 0, 0, IF_DR_3A, 0x1AC04800) +INST1(crc32w, "crc32w", 0, IF_DR_3A, 0x1AC04800) // crc32w Rd,Rn,Rm DR_3A 00011010110mmmmm 010010nnnnnddddd 1AC0 4800 -INST1(crc32x, "crc32x", 0, 0, IF_DR_3A, 0x9AC04C00) +INST1(crc32x, "crc32x", 0, IF_DR_3A, 0x9AC04C00) // crc32x Rd,Rn,Xm DR_3A 10011010110mmmmm 010011nnnnnddddd 9AC0 4C00 -INST1(crc32cb, "crc32cb",0, 0, IF_DR_3A, 0x1AC05000) +INST1(crc32cb, "crc32cb", 0, IF_DR_3A, 0x1AC05000) // crc32cb Rd,Rn,Rm DR_3A 00011010110mmmmm 010100nnnnnddddd 1AC0 5000 -INST1(crc32ch, "crc32ch",0, 0, IF_DR_3A, 0x1AC05400) +INST1(crc32ch, "crc32ch", 0, IF_DR_3A, 0x1AC05400) // crc32ch Rd,Rn,Rm DR_3A 00011010110mmmmm 010101nnnnnddddd 1AC0 5400 -INST1(crc32cw, "crc32cw",0, 0, IF_DR_3A, 0x1AC05800) +INST1(crc32cw, "crc32cw", 0, IF_DR_3A, 0x1AC05800) // crc32cw Rd,Rn,Rm DR_3A 00011010110mmmmm 010110nnnnnddddd 1AC0 5800 -INST1(crc32cx, "crc32cx",0, 0, IF_DR_3A, 0x9AC05C00) +INST1(crc32cx, "crc32cx", 0, IF_DR_3A, 0x9AC05C00) // crc32cx Rd,Rn,Xm DR_3A 10011010110mmmmm 010111nnnnnddddd 9AC0 5C00 -INST1(sha1c, "sha1c", 0, 0, IF_DV_3F, 0x5E000000) +INST1(sha1c, "sha1c", 0, IF_DV_3F, 0x5E000000) // sha1c Qd, Sn Vm.4S DV_3F 01011110000mmmmm 000000nnnnnddddd 5E00 0000 Qd Sn Vm.4S (vector) -INST1(sha1m, "sha1m", 0, 0, IF_DV_3F, 0x5E002000) +INST1(sha1m, "sha1m", 0, IF_DV_3F, 0x5E002000) // sha1m Qd, Sn Vm.4S DV_3F 01011110000mmmmm 001000nnnnnddddd 5E00 0000 Qd Sn Vm.4S (vector) -INST1(sha1p, "sha1p", 0, 0, IF_DV_3F, 0x5E001000) +INST1(sha1p, "sha1p", 0, IF_DV_3F, 0x5E001000) // sha1m Qd, Sn Vm.4S DV_3F 01011110000mmmmm 000100nnnnnddddd 5E00 0000 Qd Sn Vm.4S (vector) -INST1(sha1h, "sha1h", 0, 0, IF_DV_2U, 0x5E280800) +INST1(sha1h, "sha1h", 0, IF_DV_2U, 0x5E280800) // sha1h Sd, Sn DV_2U 0101111000101000 000010nnnnnddddd 5E28 0800 Sn Sn -INST1(sha1su0, "sha1su0", 0, 0, IF_DV_3F, 0x5E003000) - // sha1su0 Vd.4S,Vn.4S,Vm.4S DV_3F 01011110000mmmmm 001100nnnnnddddd 5E00 3000 Vd.4S Vn.4S Vm.4S (vector) +INST1(sha1su0, "sha1su0", 0, IF_DV_3F, 0x5E003000) + // sha1su0 Vd.4S,Vn.4S,Vm.4S DV_3F 01011110000mmmmm 001100nnnnnddddd 5E00 3000 Vd.4S Vn.4S Vm.4S (vector) -INST1(sha1su1, "sha1su1", 0, 0, IF_DV_2P, 0x5E281800) +INST1(sha1su1, "sha1su1", 0, IF_DV_2P, 0x5E281800) // sha1su1 Vd.4S, Vn.4S DV_2P 0101111000101000 000110nnnnnddddd 5E28 1800 Vd.4S Vn.4S (vector) -INST1(sha256h, "sha256h", 0, 0, IF_DV_3F, 0x5E004000) - // sha256h Qd,Qn,Vm.4S DV_3F 01011110000mmmmm 010000nnnnnddddd 5E00 4000 Qd Qn Vm.4S (vector) +INST1(sha256h, "sha256h", 0, IF_DV_3F, 0x5E004000) + // sha256h Qd,Qn,Vm.4S DV_3F 01011110000mmmmm 010000nnnnnddddd 5E00 4000 Qd Qn Vm.4S (vector) + +INST1(sha256h2, "sha256h2", 0, IF_DV_3F, 0x5E005000) + // sha256h Qd,Qn,Vm.4S DV_3F 01011110000mmmmm 010100nnnnnddddd 5E00 5000 Qd Qn Vm.4S (vector) -INST1(sha256h2, "sha256h2", 0, 0, IF_DV_3F, 0x5E005000) - // sha256h Qd,Qn,Vm.4S DV_3F 01011110000mmmmm 010100nnnnnddddd 5E00 5000 Qd Qn Vm.4S (vector) +INST1(sha256su0, "sha256su0", 0, IF_DV_2P, 0x5E282800) + // sha256su0 Vd.4S,Vn.4S DV_2P 0101111000101000 001010nnnnnddddd 5E28 2800 Vd.4S Vn.4S (vector) -INST1(sha256su0, "sha256su0", 0, 0, IF_DV_2P, 0x5E282800) - // sha256su0 Vd.4S,Vn.4S DV_2P 0101111000101000 001010nnnnnddddd 5E28 2800 Vd.4S Vn.4S (vector) +INST1(sha256su1, "sha256su1", 0, IF_DV_3F, 0x5E006000) + // sha256su1 Vd.4S,Vn.4S,Vm.4S DV_3F 01011110000mmmmm 011000nnnnnddddd 5E00 6000 Vd.4S Vn.4S Vm.4S (vector) -INST1(sha256su1, "sha256su1", 0, 0, IF_DV_3F, 0x5E006000) - // sha256su1 Vd.4S,Vn.4S,Vm.4S DV_3F 01011110000mmmmm 011000nnnnnddddd 5E00 6000 Vd.4S Vn.4S Vm.4S (vector) +INST1(ext, "ext", 0, IF_DV_3G, 0x2E000000) + // ext Vd,Vn,Vm,index DV_3G 0Q101110000mmmmm 0iiii0nnnnnddddd 2E00 0000 Vd Vn Vm index (vector) -INST1(sbfm, "sbfm", 0, 0, IF_DI_2D, 0x13000000) +INST1(sbfm, "sbfm", 0, IF_DI_2D, 0x13000000) // sbfm Rd,Rn,imr,ims DI_2D X00100110Nrrrrrr ssssssnnnnnddddd 1300 0000 imr, ims -INST1(bfm, "bfm", 0, 0, IF_DI_2D, 0x33000000) +INST1(bfm, "bfm", 0, IF_DI_2D, 0x33000000) // bfm Rd,Rn,imr,ims DI_2D X01100110Nrrrrrr ssssssnnnnnddddd 3300 0000 imr, ims -INST1(ubfm, "ubfm", 0, 0, IF_DI_2D, 0x53000000) +INST1(ubfm, "ubfm", 0, IF_DI_2D, 0x53000000) // ubfm Rd,Rn,imr,ims DI_2D X10100110Nrrrrrr ssssssnnnnnddddd 5300 0000 imr, ims -INST1(sbfiz, "sbfiz", 0, 0, IF_DI_2D, 0x13000000) +INST1(sbfiz, "sbfiz", 0, IF_DI_2D, 0x13000000) // sbfiz Rd,Rn,lsb,width DI_2D X00100110Nrrrrrr ssssssnnnnnddddd 1300 0000 imr, ims -INST1(bfi, "bfi", 0, 0, IF_DI_2D, 0x33000000) +INST1(bfi, "bfi", 0, IF_DI_2D, 0x33000000) // bfi Rd,Rn,lsb,width DI_2D X01100110Nrrrrrr ssssssnnnnnddddd 3300 0000 imr, ims -INST1(ubfiz, "ubfiz", 0, 0, IF_DI_2D, 0x53000000) +INST1(ubfiz, "ubfiz", 0, IF_DI_2D, 0x53000000) // ubfiz Rd,Rn,lsb,width DI_2D X10100110Nrrrrrr ssssssnnnnnddddd 5300 0000 imr, ims -INST1(sbfx, "sbfx", 0, 0, IF_DI_2D, 0x13000000) +INST1(sbfx, "sbfx", 0, IF_DI_2D, 0x13000000) // sbfx Rd,Rn,lsb,width DI_2D X00100110Nrrrrrr ssssssnnnnnddddd 1300 0000 imr, ims -INST1(bfxil, "bfxil", 0, 0, IF_DI_2D, 0x33000000) +INST1(bfxil, "bfxil", 0, IF_DI_2D, 0x33000000) // bfxil Rd,Rn,lsb,width DI_2D X01100110Nrrrrrr ssssssnnnnnddddd 3300 0000 imr, ims -INST1(ubfx, "ubfx", 0, 0, IF_DI_2D, 0x53000000) +INST1(ubfx, "ubfx", 0, IF_DI_2D, 0x53000000) // ubfx Rd,Rn,lsb,width DI_2D X10100110Nrrrrrr ssssssnnnnnddddd 5300 0000 imr, ims -INST1(sxtb, "sxtb", 0, 0, IF_DR_2H, 0x13001C00) +INST1(sxtb, "sxtb", 0, IF_DR_2H, 0x13001C00) // sxtb Rd,Rn DR_2H X00100110X000000 000111nnnnnddddd 1300 1C00 -INST1(sxth, "sxth", 0, 0, IF_DR_2H, 0x13003C00) +INST1(sxth, "sxth", 0, IF_DR_2H, 0x13003C00) // sxth Rd,Rn DR_2H X00100110X000000 001111nnnnnddddd 1300 3C00 -INST1(sxtw, "sxtw", 0, 0, IF_DR_2H, 0x13007C00) +INST1(sxtw, "sxtw", 0, IF_DR_2H, 0x13007C00) // sxtw Rd,Rn DR_2H X00100110X000000 011111nnnnnddddd 1300 7C00 -INST1(uxtb, "uxtb", 0, 0, IF_DR_2H, 0x53001C00) +INST1(uxtb, "uxtb", 0, IF_DR_2H, 0x53001C00) // uxtb Rd,Rn DR_2H 0101001100000000 000111nnnnnddddd 5300 1C00 -INST1(uxth, "uxth", 0, 0, IF_DR_2H, 0x53003C00) +INST1(uxth, "uxth", 0, IF_DR_2H, 0x53003C00) // uxth Rd,Rn DR_2H 0101001100000000 001111nnnnnddddd 5300 3C00 -INST1(nop, "nop", 0, 0, IF_SN_0A, 0xD503201F) +INST1(nop, "nop", 0, IF_SN_0A, 0xD503201F) // nop SN_0A 1101010100000011 0010000000011111 D503 201F -INST1(bkpt, "bkpt", 0, 0, IF_SN_0A, 0xD43E0000) +INST1(bkpt, "bkpt", 0, IF_SN_0A, 0xD43E0000) // brpt SN_0A 1101010000111110 0000000000000000 D43E 0000 0xF000 -INST1(brk, "brk", 0, 0, IF_SI_0A, 0xD4200000) +INST1(brk, "brk", 0, IF_SI_0A, 0xD4200000) // brk imm16 SI_0A 11010100001iiiii iiiiiiiiiii00000 D420 0000 imm16 -INST1(dsb, "dsb", 0, 0, IF_SI_0B, 0xD503309F) +INST1(dsb, "dsb", 0, IF_SI_0B, 0xD503309F) // dsb barrierKind SI_0B 1101010100000011 0011bbbb10011111 D503 309F imm4 - barrier kind -INST1(dmb, "dmb", 0, 0, IF_SI_0B, 0xD50330BF) +INST1(dmb, "dmb", 0, IF_SI_0B, 0xD50330BF) // dmb barrierKind SI_0B 1101010100000011 0011bbbb10111111 D503 30BF imm4 - barrier kind -INST1(isb, "isb", 0, 0, IF_SI_0B, 0xD50330DF) +INST1(isb, "isb", 0, IF_SI_0B, 0xD50330DF) // isb barrierKind SI_0B 1101010100000011 0011bbbb11011111 D503 30DF imm4 - barrier kind -INST1(umov, "umov", 0, 0, IF_DV_2B, 0x0E003C00) +INST1(umov, "umov", 0, IF_DV_2B, 0x0E003C00) // umov Rd,Vn[] DV_2B 0Q001110000iiiii 001111nnnnnddddd 0E00 3C00 Rd,Vn[] -INST1(smov, "smov", 0, 0, IF_DV_2B, 0x0E002C00) +INST1(smov, "smov", 0, IF_DV_2B, 0x0E002C00) // smov Rd,Vn[] DV_2B 0Q001110000iiiii 001011nnnnnddddd 0E00 3C00 Rd,Vn[] -INST1(movi, "movi", 0, 0, IF_DV_1B, 0x0F000400) +INST1(movi, "movi", 0, IF_DV_1B, 0x0F000400) // movi Vd,imm8 DV_1B 0QX0111100000iii cmod01iiiiiddddd 0F00 0400 Vd imm8 (immediate vector) -INST1(mvni, "mvni", 0, 0, IF_DV_1B, 0x2F000400) +INST1(mvni, "mvni", 0, IF_DV_1B, 0x2F000400) // mvni Vd,imm8 DV_1B 0Q10111100000iii cmod01iiiiiddddd 2F00 0400 Vd imm8 (immediate vector) -INST1(urecpe, "urecpe", 0, 0, IF_DV_2A, 0x0EA1C800) - // C7.2.372 URECPE +INST1(urecpe, "urecpe", 0, IF_DV_2A, 0x0EA1C800) // urecpe Vd,Vn DV_2A 0Q0011101X100001 110010nnnnnddddd 0EA1 C800 Vd,Vn (vector) -INST1(ursqrte, "ursqrte",0, 0, IF_DV_2A, 0x2EA1C800) - // C7.2.376 URSQRTE +INST1(ursqrte, "ursqrte", 0, IF_DV_2A, 0x2EA1C800) // ursqrte Vd,Vn DV_2A 0Q1011101X100001 110010nnnnnddddd 2EA1 C800 Vd,Vn (vector) -INST1(bsl, "bsl", 0, 0, IF_DV_3C, 0x2E601C00) +INST1(bsl, "bsl", 0, IF_DV_3C, 0x2E601C00) // bsl Vd,Vn,Vm DV_3C 0Q101110011mmmmm 000111nnnnnddddd 2E60 1C00 Vd,Vn,Vm -INST1(bit, "bit", 0, 0, IF_DV_3C, 0x2EA01C00) +INST1(bit, "bit", 0, IF_DV_3C, 0x2EA01C00) // bit Vd,Vn,Vm DV_3C 0Q101110101mmmmm 000111nnnnnddddd 2EA0 1C00 Vd,Vn,Vm -INST1(bif, "bif", 0, 0, IF_DV_3C, 0x2EE01C00) +INST1(bif, "bif", 0, IF_DV_3C, 0x2EE01C00) // bif Vd,Vn,Vm DV_3C 0Q101110111mmmmm 000111nnnnnddddd 2EE0 1C00 Vd,Vn,Vm -INST1(addv, "addv", 0, 0, IF_DV_2T, 0x0E31B800) +INST1(addv, "addv", 0, IF_DV_2T, 0x0E31B800) // addv Vd,Vn DV_2T 0Q001110XX110001 101110nnnnnddddd 0E31 B800 Vd,Vn (vector) -INST1(cnt, "cnt", 0, 0, IF_DV_2M, 0x0E205800) +INST1(cnt, "cnt", 0, IF_DV_2M, 0x0E205800) // cnt Vd,Vn DV_2M 0Q00111000100000 010110nnnnnddddd 0E20 5800 Vd,Vn (vector) -INST1(not, "not", 0, 0, IF_DV_2M, 0x2E205800) +INST1(not, "not", 0, IF_DV_2M, 0x2E205800) // not Vd,Vn DV_2M 0Q10111000100000 010110nnnnnddddd 2E20 5800 Vd,Vn (vector) -INST1(saddlv, "saddlv", 0, 0, IF_DV_2T, 0x0E303800) +INST1(saddlv, "saddlv", 0, IF_DV_2T, 0x0E303800) // saddlv Vd,Vn DV_2T 0Q001110XX110000 001110nnnnnddddd 0E30 3800 Vd,Vn (vector) -INST1(smaxv, "smaxv", 0, 0, IF_DV_2T, 0x0E30A800) +INST1(smaxv, "smaxv", 0, IF_DV_2T, 0x0E30A800) // smaxv Vd,Vn DV_2T 0Q001110XX110000 101010nnnnnddddd 0E30 A800 Vd,Vn (vector) -INST1(sminv, "sminv", 0, 0, IF_DV_2T, 0x0E31A800) +INST1(sminv, "sminv", 0, IF_DV_2T, 0x0E31A800) // sminv Vd,Vn DV_2T 0Q001110XX110001 101010nnnnnddddd 0E31 A800 Vd,Vn (vector) -INST1(uaddlv, "uaddlv", 0, 0, IF_DV_2T, 0x2E303800) +INST1(uaddlv, "uaddlv", 0, IF_DV_2T, 0x2E303800) // uaddlv Vd,Vn DV_2T 0Q101110XX110000 001110nnnnnddddd 2E30 3800 Vd,Vn (vector) -INST1(umaxv, "umaxv", 0, 0, IF_DV_2T, 0x2E30A800) +INST1(umaxv, "umaxv", 0, IF_DV_2T, 0x2E30A800) // umaxv Vd,Vn DV_2T 0Q101110XX110000 101010nnnnnddddd 2E30 A800 Vd,Vn (vector) -INST1(uminv, "uminv", 0, 0, IF_DV_2T, 0x2E31A800) +INST1(uminv, "uminv", 0, IF_DV_2T, 0x2E31A800) // uminv Vd,Vn DV_2T 0Q101110XX110001 101010nnnnnddddd 2E31 A800 Vd,Vn (vector) -INST1(fmaxnmv, "fmaxnmv",0, 0, IF_DV_2R, 0x2E30C800) +INST1(fmaxnmv, "fmaxnmv", 0, IF_DV_2R, 0x2E30C800) // fmaxnmv Vd,Vn DV_2R 0Q1011100X110000 110010nnnnnddddd 2E30 C800 Vd,Vn (vector) -INST1(fmaxv, "fmaxv", 0, 0, IF_DV_2R, 0x2E30F800) +INST1(fmaxv, "fmaxv", 0, IF_DV_2R, 0x2E30F800) // fmaxv Vd,Vn DV_2R 0Q1011100X110000 111110nnnnnddddd 2E30 F800 Vd,Vn (vector) -INST1(fminnmv, "fminnmv",0, 0, IF_DV_2R, 0x2EB0C800) +INST1(fminnmv, "fminnmv", 0, IF_DV_2R, 0x2EB0C800) // fminnmv Vd,Vn DV_2R 0Q1011101X110000 110010nnnnnddddd 2EB0 C800 Vd,Vn (vector) -INST1(fminv, "fminv", 0, 0, IF_DV_2R, 0x2EB0F800) +INST1(fminv, "fminv", 0, IF_DV_2R, 0x2EB0F800) // fminv Vd,Vn DV_2R 0Q1011101X110000 111110nnnnnddddd 2EB0 F800 Vd,Vn (vector) -INST1(uzp1, "uzp1", 0, 0, IF_DV_3A, 0x0E001800) +INST1(uzp1, "uzp1", 0, IF_DV_3A, 0x0E001800) // uzp1 Vd,Vn,Vm DV_3A 0Q001110XX0mmmmm 000110nnnnnddddd 0E00 1800 Vd,Vn,Vm (vector) -INST1(uzp2, "uzp2", 0, 0, IF_DV_3A, 0x0E005800) +INST1(uzp2, "uzp2", 0, IF_DV_3A, 0x0E005800) // upz2 Vd,Vn,Vm DV_3A 0Q001110XX0mmmmm 010110nnnnnddddd 0E00 5800 Vd,Vn,Vm (vector) -INST1(zip1, "zip1", 0, 0, IF_DV_3A, 0x0E003800) +INST1(zip1, "zip1", 0, IF_DV_3A, 0x0E003800) // zip1 Vd,Vn,Vm DV_3A 0Q001110XX0mmmmm 011110nnnnnddddd 0E00 3800 Vd,Vn,Vm (vector) -INST1(zip2, "zip2", 0, 0, IF_DV_3A, 0x0E007800) +INST1(zip2, "zip2", 0, IF_DV_3A, 0x0E007800) // zip2 Vd,Vn,Vm DV_3A 0Q001110XX0mmmmm 001110nnnnnddddd 0E00 7800 Vd,Vn,Vm (vector) -INST1(trn1, "trn1", 0, 0, IF_DV_3A, 0x0E002800) +INST1(trn1, "trn1", 0, IF_DV_3A, 0x0E002800) // trn1 Vd,Vn,Vm DV_3A 0Q001110XX0mmmmm 001010nnnnnddddd 0E00 2800 Vd,Vn,Vm (vector) -INST1(trn2, "trn2", 0, 0, IF_DV_3A, 0x0E006800) +INST1(trn2, "trn2", 0, IF_DV_3A, 0x0E006800) // trn2 Vd,Vn,Vm DV_3A 0Q001110XX0mmmmm 011010nnnnnddddd 0E00 6800 Vd,Vn,Vm (vector) -INST1(xtn, "xtn", 0, 0, IF_DV_2M, 0x0E212800) +INST1(xtn, "xtn", 0, IF_DV_2M, 0x0E212800) // xtn Vd,Vn DV_2M 00101110XX110000 001110nnnnnddddd 0E21 2800 Vd,Vn (vector) -INST1(xtn2, "xtn2", 0, 0, IF_DV_2M, 0x4E212800) +INST1(xtn2, "xtn2", 0, IF_DV_2M, 0x4E212800) // xtn2 Vd,Vn DV_2M 01101110XX110000 001110nnnnnddddd 4E21 2800 Vd,Vn (vector) -INST1(fnmul, "fnmul", 0, 0, IF_DV_3D, 0x1E208800) +INST1(fnmul, "fnmul", 0, IF_DV_3D, 0x1E208800) // fnmul Vd,Vn,Vm DV_3D 000111100X1mmmmm 100010nnnnnddddd 1E20 8800 Vd,Vn,Vm (scalar) -INST1(fmadd, "fmadd", 0, 0, IF_DV_4A, 0x1F000000) +INST1(fmadd, "fmadd", 0, IF_DV_4A, 0x1F000000) // fmadd Vd,Va,Vn,Vm DV_4A 000111110X0mmmmm 0aaaaannnnnddddd 1F00 0000 Vd Vn Vm Va (scalar) -INST1(fmsub, "fmsub", 0, 0, IF_DV_4A, 0x1F008000) +INST1(fmsub, "fmsub", 0, IF_DV_4A, 0x1F008000) // fmsub Vd,Va,Vn,Vm DV_4A 000111110X0mmmmm 1aaaaannnnnddddd 1F00 8000 Vd Vn Vm Va (scalar) -INST1(fnmadd, "fnmadd", 0, 0, IF_DV_4A, 0x1F200000) +INST1(fnmadd, "fnmadd", 0, IF_DV_4A, 0x1F200000) // fnmadd Vd,Va,Vn,Vm DV_4A 000111110X1mmmmm 0aaaaannnnnddddd 1F20 0000 Vd Vn Vm Va (scalar) -INST1(fnmsub, "fnmsub", 0, 0, IF_DV_4A, 0x1F208000) +INST1(fnmsub, "fnmsub", 0, IF_DV_4A, 0x1F208000) // fnmsub Vd,Va,Vn,Vm DV_4A 000111110X1mmmmm 1aaaaannnnnddddd 1F20 8000 Vd Vn Vm Va (scalar) -INST1(fcvt, "fcvt", 0, 0, IF_DV_2J, 0x1E224000) +INST1(fcvt, "fcvt", 0, IF_DV_2J, 0x1E224000) // fcvt Vd,Vn DV_2J 00011110SS10001D D10000nnnnnddddd 1E22 4000 Vd,Vn -INST1(pmul, "pmul", 0, 0, IF_DV_3A, 0x2E209C00) +INST1(pmul, "pmul", 0, IF_DV_3A, 0x2E209C00) // pmul Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 100111nnnnnddddd 2E20 9C00 Vd,Vn,Vm (vector) -INST1(saba, "saba", 0, 0, IF_DV_3A, 0x0E207C00) +INST1(saba, "saba", 0, IF_DV_3A, 0x0E207C00) // saba Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 011111nnnnnddddd 0E20 7C00 Vd,Vn,Vm (vector) -INST1(sabd, "sabd", 0, 0, IF_DV_3A, 0x0E207400) +INST1(sabd, "sabd", 0, IF_DV_3A, 0x0E207400) // sabd Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 011101nnnnnddddd 0E20 7400 Vd,Vn,Vm (vector) -INST1(smax, "smax", 0, 0, IF_DV_3A, 0x0E206400) +INST1(smax, "smax", 0, IF_DV_3A, 0x0E206400) // smax Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 011001nnnnnddddd 0E20 6400 Vd,Vn,Vm (vector) -INST1(smaxp, "smaxp", 0, 0, IF_DV_3A, 0x0E20A400) +INST1(smaxp, "smaxp", 0, IF_DV_3A, 0x0E20A400) // smaxp Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 101001nnnnnddddd 0E20 A400 Vd,Vn,Vm (vector) -INST1(smin, "smin", 0, 0, IF_DV_3A, 0x0E206C00) +INST1(smin, "smin", 0, IF_DV_3A, 0x0E206C00) // smax Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 011011nnnnnddddd 0E20 6C00 Vd,Vn,Vm (vector) -INST1(sminp, "sminp", 0, 0, IF_DV_3A, 0x0E20AC00) +INST1(sminp, "sminp", 0, IF_DV_3A, 0x0E20AC00) // smax Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 101011nnnnnddddd 0E20 AC00 Vd,Vn,Vm (vector) -INST1(uaba, "uaba", 0, 0, IF_DV_3A, 0x2E207C00) +INST1(uaba, "uaba", 0, IF_DV_3A, 0x2E207C00) // uaba Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 011111nnnnnddddd 2E20 7C00 Vd,Vn,Vm (vector) -INST1(uabd, "uabd", 0, 0, IF_DV_3A, 0x2E207400) +INST1(uabd, "uabd", 0, IF_DV_3A, 0x2E207400) // uabd Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 011101nnnnnddddd 2E20 7400 Vd,Vn,Vm (vector) -INST1(umax, "umax", 0, 0, IF_DV_3A, 0x2E206400) +INST1(umax, "umax", 0, IF_DV_3A, 0x2E206400) // umax Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 011001nnnnnddddd 2E20 6400 Vd,Vn,Vm (vector) -INST1(umaxp, "umaxp", 0, 0, IF_DV_3A, 0x2E20A400) +INST1(umaxp, "umaxp", 0, IF_DV_3A, 0x2E20A400) // umaxp Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 101001nnnnnddddd 2E20 A400 Vd,Vn,Vm (vector) -INST1(umin, "umin", 0, 0, IF_DV_3A, 0x2E206C00) +INST1(umin, "umin", 0, IF_DV_3A, 0x2E206C00) // umin Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 011011nnnnnddddd 2E20 6C00 Vd,Vn,Vm (vector) -INST1(uminp, "uminp", 0, 0, IF_DV_3A, 0x2E20AC00) +INST1(uminp, "uminp", 0, IF_DV_3A, 0x2E20AC00) // umin Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 101011nnnnnddddd 2E20 AC00 Vd,Vn,Vm (vector) -INST1(fcvtl, "fcvtl", 0, 0, IF_DV_2G, 0x0E217800) - // fcvtl Vd,Vn DV_2G 000011100X100001 011110nnnnnddddd 0E21 7800 Vd,Vn (scalar) +INST1(fcvtl, "fcvtl", 0, IF_DV_2A, 0x0E217800) + // fcvtl Vd,Vn DV_2A 000011100X100001 011110nnnnnddddd 0E21 7800 Vd,Vn (vector) -INST1(fcvtl2, "fcvtl2", 0, 0, IF_DV_2G, 0x4E217800) - // fcvtl2 Vd,Vn DV_2G 040011100X100001 011110nnnnnddddd 4E21 7800 Vd,Vn (scalar) +INST1(fcvtl2, "fcvtl2", 0, IF_DV_2A, 0x4E217800) + // fcvtl2 Vd,Vn DV_2A 040011100X100001 011110nnnnnddddd 4E21 7800 Vd,Vn (vector) -INST1(fcvtn, "fcvtn", 0, 0, IF_DV_2G, 0x0E216800) - // fcvtn Vd,Vn DV_2G 000011100X100001 011010nnnnnddddd 0E21 6800 Vd,Vn (scalar) +INST1(fcvtn, "fcvtn", 0, IF_DV_2A, 0x0E216800) + // fcvtn Vd,Vn DV_2A 000011100X100001 011010nnnnnddddd 0E21 6800 Vd,Vn (vector) -INST1(fcvtn2, "fcvtn2", 0, 0, IF_DV_2G, 0x4E216800) - // fcvtn2 Vd,Vn DV_2G 040011100X100001 011010nnnnnddddd 4E21 6800 Vd,Vn (scalar) +INST1(fcvtn2, "fcvtn2", 0, IF_DV_2A, 0x4E216800) + // fcvtn2 Vd,Vn DV_2A 040011100X100001 011010nnnnnddddd 4E21 6800 Vd,Vn (vector) -INST1(frecpx, "frecpx", 0, 0, IF_DV_2G, 0x5EA1F800) - // C7.2.139 FRECPX +INST1(frecpx, "frecpx", 0, IF_DV_2G, 0x5EA1F800) // frecpx Vd,Vn DV_2G 010111101X100001 111110nnnnnddddd 5EA1 F800 Vd,Vn (scalar) -INST1(shll, "shll", 0, 0, IF_DV_2M, 0x2F00A400) +INST1(addhn, "addhn", 0, IF_DV_3H, 0x0E204000) + // addhn Vd,Vn,Vm DV_3H 00001110XX1mmmmm 010000nnnnnddddd 0E20 4000 Vd,Vn,Vm (vector) + +INST1(addhn2, "addhn2", 0, IF_DV_3H, 0x4E204000) + // addhn2 Vd,Vn,Vm DV_3H 01001110XX1mmmmm 010000nnnnnddddd 4E20 4000 Vd,Vn,Vm (vector) + +INST1(pmull, "pmull", 0, IF_DV_3H, 0x0E20E000) + // pmull Vd,Vn,Vm DV_3H 00001110XX1mmmmm 111000nnnnnddddd 0E20 E000 Vd,Vn,Vm (vector) + +INST1(pmull2, "pmull2", 0, IF_DV_3H, 0x4E20E000) + // pmull2 Vd,Vn,Vm DV_3H 01001110XX1mmmmm 111000nnnnnddddd 4E20 E000 Vd,Vn,Vm (vector) + +INST1(raddhn, "raddhn", 0, IF_DV_3H, 0x2E204000) + // raddhn Vd,Vn,Vm DV_3H 00101110XX1mmmmm 010000nnnnnddddd 2E20 4000 Vd,Vn,Vm (vector) + +INST1(raddhn2, "raddhn2", 0, IF_DV_3H, 0x6E204000) + // raddhn2 Vd,Vn,Vm DV_3H 01101110XX1mmmmm 010000nnnnnddddd 6E20 4000 Vd,Vn,Vm (vector) + +INST1(rsubhn, "rsubhn", 0, IF_DV_3H, 0x2E206000) + // rsubhn Vd,Vn,Vm DV_3H 00101110XX1mmmmm 011000nnnnnddddd 2E20 6000 Vd,Vn,Vm (vector) + +INST1(rsubhn2, "rsubhn2", 0, IF_DV_3H, 0x6E206000) + // rsubhn2 Vd,Vn,Vm DV_3H 01101110XX1mmmmm 011000nnnnnddddd 6E20 6000 Vd,Vn,Vm (vector) + +INST1(sabal, "sabal", 0, IF_DV_3H, 0x0E205000) + // sabal Vd,Vn,Vm DV_3H 00001110XX1mmmmm 010100nnnnnddddd 0E20 5000 Vd,Vn,Vm (vector) + +INST1(sabal2, "sabal2", 0, IF_DV_3H, 0x4E205000) + // sabal2 Vd,Vn,Vm DV_3H 01001110XX1mmmmm 010100nnnnnddddd 4E20 5000 Vd,Vn,Vm (vector) + +INST1(sabdl, "sabdl", 0, IF_DV_3H, 0x0E207000) + // sabdl Vd,Vn,Vm DV_3H 00001110XX1mmmmm 011100nnnnnddddd 0E20 7000 Vd,Vn,Vm (vector) + +INST1(sabdl2, "sabdl2", 0, IF_DV_3H, 0x4E207000) + // sabdl2 Vd,Vn,Vm DV_3H 01001110XX1mmmmm 011100nnnnnddddd 4E20 7000 Vd,Vn,Vm (vector) + +INST1(sadalp, "sadalp", 0, IF_DV_2T, 0x0E206800) + // sadalp Vd,Vn DV_2T 0Q001110XX100000 011010nnnnnddddd 0E20 6800 Vd,Vn (vector) + +INST1(saddl, "saddl", 0, IF_DV_3H, 0x0E200000) + // saddl Vd,Vn,Vm DV_3H 00001110XX1mmmmm 000000nnnnnddddd 0E20 0000 Vd,Vn,Vm (vector) + +INST1(saddl2, "saddl2", 0, IF_DV_3H, 0x4E200000) + // saddl2 Vd,Vn,Vm DV_3H 01001110XX1mmmmm 000000nnnnnddddd 4E20 0000 Vd,Vn,Vm (vector) + +INST1(saddlp, "saddlp", 0, IF_DV_2T, 0x0E202800) + // saddlp Vd,Vn DV_2T 0Q001110XX100000 001010nnnnnddddd 0E20 2800 Vd,Vn (vector) + +INST1(saddw, "saddw", 0, IF_DV_3H, 0x0E201000) + // saddw Vd,Vn,Vm DV_3H 00001110XX1mmmmm 000100nnnnnddddd 0E20 1000 Vd,Vn,Vm (vector) + +INST1(saddw2, "saddw2", 0, IF_DV_3H, 0x4E201000) + // saddw2 Vd,Vn,Vm DV_3H 01001110XX1mmmmm 000100nnnnnddddd 4E20 1000 Vd,Vn,Vm (vector) + +INST1(shadd, "shadd", 0, IF_DV_3A, 0x0E200400) + // shadd Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 000001nnnnnddddd 0E20 0400 Vd,Vn,Vm (vector) + +INST1(shsub, "shsub", 0, IF_DV_3A, 0x0E202400) + // shsub Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 001001nnnnnddddd 0E20 2400 Vd,Vn,Vm (vector) + +INST1(srhadd, "srhadd", 0, IF_DV_3A, 0x0E201400) + // srhadd Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 000101nnnnnddddd 0E20 1400 Vd,Vn,Vm (vector) + +INST1(ssubl, "ssubl", 0, IF_DV_3H, 0x0E202000) + // ssubl Vd,Vn,Vm DV_3H 00001110XX1mmmmm 001000nnnnnddddd 0E20 2000 Vd,Vn,Vm (vector) + +INST1(ssubl2, "ssubl2", 0, IF_DV_3H, 0x4E202000) + // ssubl2 Vd,Vn,Vm DV_3H 01001110XX1mmmmm 001000nnnnnddddd 4E20 2000 Vd,Vn,Vm (vector) + +INST1(ssubw, "ssubw", 0, IF_DV_3H, 0x0E203000) + // ssubw Vd,Vn,Vm DV_3H 00001110XX1mmmmm 001100nnnnnddddd 0E20 3000 Vd,Vn,Vm (vector) + +INST1(ssubw2, "ssubw2", 0, IF_DV_3H, 0x4E203000) + // ssubw2 Vd,Vn,Vm DV_3H 01001110XX1mmmmm 001100nnnnnddddd 4E20 3000 Vd,Vn,Vm (vector) + +INST1(subhn, "subhn", 0, IF_DV_3H, 0x0E206000) + // subhn Vd,Vn,Vm DV_3H 00001110XX1mmmmm 011000nnnnnddddd 0E20 6000 Vd,Vn,Vm (vector) + +INST1(subhn2, "subhn2", 0, IF_DV_3H, 0x4E206000) + // subhn2 Vd,Vn,Vm DV_3H 01001110XX1mmmmm 011000nnnnnddddd 4E20 6000 Vd,Vn,Vm (vector) + +INST1(uabal, "uabal", 0, IF_DV_3H, 0x2E205000) + // uabal Vd,Vn,Vm DV_3H 00101110XX1mmmmm 010100nnnnnddddd 2E20 5000 Vd,Vn,Vm (vector) + +INST1(uabal2, "uabal2", 0, IF_DV_3H, 0x6E205000) + // uabal2 Vd,Vn,Vm DV_3H 01101110XX1mmmmm 010100nnnnnddddd 6E20 5000 Vd,Vn,Vm (vector) + +INST1(uabdl, "uabdl", 0, IF_DV_3H, 0x2E207000) + // uabdl Vd,Vn,Vm DV_3H 00101110XX1mmmmm 011100nnnnnddddd 2E20 7000 Vd,Vn,Vm (vector) + +INST1(uabdl2, "uabdl2", 0, IF_DV_3H, 0x6E207000) + // uabdl2 Vd,Vn,Vm DV_3H 01101110XX1mmmmm 011100nnnnnddddd 6E20 7000 Vd,Vn,Vm (vector) + +INST1(uadalp, "uadalp", 0, IF_DV_2T, 0x2E206800) + // uadalp Vd,Vn DV_2T 0Q101110XX100000 011010nnnnnddddd 2E20 6800 Vd,Vn (vector) + +INST1(uaddl, "uaddl", 0, IF_DV_3H, 0x2E200000) + // uaddl Vd,Vn,Vm DV_3H 00101110XX1mmmmm 000000nnnnnddddd 2E20 0000 Vd,Vn,Vm (vector) + +INST1(uaddl2, "uaddl2", 0, IF_DV_3H, 0x6E200000) + // uaddl2 Vd,Vn,Vm DV_3H 01101110XX1mmmmm 000000nnnnnddddd 6E20 0000 Vd,Vn,Vm (vector) + +INST1(uaddlp, "uaddlp", 0, IF_DV_2T, 0x2E202800) + // uaddlp Vd,Vn DV_2T 0Q101110XX100000 001010nnnnnddddd 2E20 2800 Vd,Vn (vector) + +INST1(uaddw, "uaddw", 0, IF_DV_3H, 0x2E201000) + // uaddw Vd,Vn,Vm DV_3H 00101110XX1mmmmm 000100nnnnnddddd 2E20 1000 Vd,Vn,Vm (vector) + +INST1(uaddw2, "uaddw2", 0, IF_DV_3H, 0x6E201000) + // uaddw2 Vd,Vn,Vm DV_3H 01101110XX1mmmmm 000100nnnnnddddd 6E20 1000 Vd,Vn,Vm (vector) + +INST1(uhadd, "uhadd", 0, IF_DV_3A, 0x2E200400) + // uhadd Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 000001nnnnnddddd 2E20 0400 Vd,Vn,Vm (vector) + +INST1(uhsub, "uhsub", 0, IF_DV_3A, 0x2E202400) + // uhsub Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 001001nnnnnddddd 2E20 2400 Vd,Vn,Vm (vector) + +INST1(urhadd, "urhadd", 0, IF_DV_3A, 0x2E201400) + // urhadd Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 000101nnnnnddddd 2E20 1400 Vd,Vn,Vm (vector) + +INST1(usubl, "usubl", 0, IF_DV_3H, 0x2E202000) + // usubl Vd,Vn,Vm DV_3H 00101110XX1mmmmm 001000nnnnnddddd 2E20 2000 Vd,Vn,Vm (vector) + +INST1(usubl2, "usubl2", 0, IF_DV_3H, 0x6E202000) + // usubl2 Vd,Vn,Vm DV_3H 01101110XX1mmmmm 001000nnnnnddddd 6E20 2000 Vd,Vn,Vm (vector) + +INST1(usubw, "usubw", 0, IF_DV_3H, 0x2E203000) + // usubw Vd,Vn,Vm DV_3H 00101110XX1mmmmm 001100nnnnnddddd 2E20 3000 Vd,Vn,Vm (vector) + +INST1(usubw2, "usubw2", 0, IF_DV_3H, 0x6E203000) + // usubw2 Vd,Vn,Vm DV_3H 01101110XX1mmmmm 001100nnnnnddddd 6E20 3000 Vd,Vn,Vm (vector) + +INST1(shll, "shll", 0, IF_DV_2M, 0x2F00A400) // shll Vd,Vn,imm DV_2M 0Q101110XX100001 001110nnnnnddddd 2E21 3800 Vd,Vn, {8/16/32} -INST1(shll2, "shll2", 0, 0, IF_DV_2M, 0x6F00A400) +INST1(shll2, "shll2", 0, IF_DV_2M, 0x6F00A400) // shll Vd,Vn,imm DV_2M 0Q101110XX100001 001110nnnnnddddd 2E21 3800 Vd,Vn, {8/16/32} -INST1(sshll, "sshll", 0, 0, IF_DV_2O, 0x0F00A400) - // sshll Vd,Vn,imm DV_2O 000011110iiiiiii 101001nnnnnddddd 0F00 A400 Vd,Vn imm (shift - vector) +INST1(sshll, "sshll", 0, IF_DV_2O, 0x0F00A400) + // sshll Vd,Vn,imm DV_2O 000011110iiiiiii 101001nnnnnddddd 0F00 A400 Vd,Vn imm (left shift - vector) + +INST1(sshll2, "sshll2", 0, IF_DV_2O, 0x4F00A400) + // sshll2 Vd,Vn,imm DV_2O 010011110iiiiiii 101001nnnnnddddd 4F00 A400 Vd,Vn imm (left shift - vector) + +INST1(ushll, "ushll", 0, IF_DV_2O, 0x2F00A400) + // ushll Vd,Vn,imm DV_2O 001011110iiiiiii 101001nnnnnddddd 2F00 A400 Vd,Vn imm (left shift - vector) + +INST1(ushll2, "ushll2", 0, IF_DV_2O, 0x6F00A400) + // ushll2 Vd,Vn,imm DV_2O 011011110iiiiiii 101001nnnnnddddd 6F00 A400 Vd,Vn imm (left shift - vector) + +INST1(shrn, "shrn", RSH, IF_DV_2O, 0x0F008400) + // shrn Vd,Vn,imm DV_2O 000011110iiiiiii 100001nnnnnddddd 0F00 8400 Vd,Vn imm (right shift - vector) + +INST1(shrn2, "shrn2", RSH, IF_DV_2O, 0x4F008400) + // shrn2 Vd,Vn,imm DV_2O 010011110iiiiiii 100001nnnnnddddd 4F00 8400 Vd,Vn imm (right shift - vector) + +INST1(rshrn, "rshrn", RSH, IF_DV_2O, 0x0F008C00) + // rshrn Vd,Vn,imm DV_2O 000011110iiiiiii 100011nnnnnddddd 0F00 8C00 Vd,Vn imm (right shift - vector) + +INST1(rshrn2, "rshrn2", RSH, IF_DV_2O, 0x4F008C00) + // rshrn2 Vd,Vn,imm DV_2O 010011110iiiiiii 100011nnnnnddddd 4F00 8C00 Vd,Vn imm (right shift - vector) + +INST1(sqrshrn2, "sqrshrn2", RSH, IF_DV_2O, 0x0F009C00) + // sqrshrn2 Vd,Vn,imm DV_2O 0Q0011110iiiiiii 100111nnnnnddddd 0F00 9C00 Vd Vn imm (right shift - vector) + +INST1(sqrshrun2, "sqrshrun2", RSH, IF_DV_2O, 0x2F008C00) + // sqrshrun2 Vd,Vn,imm DV_2O 0Q1011110iiiiiii 100011nnnnnddddd 2F00 8C00 Vd Vn imm (right shift - vector) + +INST1(sqshrn2, "sqshrn2", RSH, IF_DV_2O, 0x0F009400) + // sqshrn2 Vd,Vn,imm DV_2O 0Q0011110iiiiiii 100101nnnnnddddd 0F00 9400 Vd Vn imm (right shift - vector) + +INST1(sqshrun2, "sqshrun2", RSH, IF_DV_2O, 0x2F008400) + // sqshrun2 Vd,Vn,imm DV_2O 0Q1011110iiiiiii 100001nnnnnddddd 2F00 8400 Vd Vn imm (right shift - vector) + +INST1(uqrshrn2, "uqrshrn2", RSH, IF_DV_2O, 0x2F009C00) + // uqrshrn2 Vd,Vn,imm DV_2O 0Q1011110iiiiiii 100111nnnnnddddd 2F00 9C00 Vd Vn imm (right shift - vector) + +INST1(uqshrn2, "uqshrn2", RSH, IF_DV_2O, 0x2F009400) + // uqshrn2 Vd,Vn,imm DV_2O 0Q1011110iiiiiii 100101nnnnnddddd 2F00 9400 Vd Vn imm (right shift - vector) + +INST1(sxtl, "sxtl", 0, IF_DV_2O, 0x0F00A400) + // sxtl Vd,Vn DV_2O 000011110iiiiiii 101001nnnnnddddd 0F00 A400 Vd,Vn (left shift - vector) + +INST1(sxtl2, "sxtl2", 0, IF_DV_2O, 0x4F00A400) + // sxtl2 Vd,Vn DV_2O 010011110iiiiiii 101001nnnnnddddd 4F00 A400 Vd,Vn (left shift - vector) -INST1(sshll2, "sshll2", 0, 0, IF_DV_2O, 0x4F00A400) - // sshll2 Vd,Vn,imm DV_2O 010011110iiiiiii 101001nnnnnddddd 4F00 A400 Vd,Vn imm (shift - vector) +INST1(uxtl, "uxtl", 0, IF_DV_2O, 0x2F00A400) + // uxtl Vd,Vn DV_2O 001011110iiiiiii 101001nnnnnddddd 2F00 A400 Vd,Vn (left shift - vector) -INST1(ushll, "ushll", 0, 0, IF_DV_2O, 0x2F00A400) - // ushll Vd,Vn,imm DV_2O 001011110iiiiiii 101001nnnnnddddd 2F00 A400 Vd,Vn imm (shift - vector) +INST1(uxtl2, "uxtl2", 0, IF_DV_2O, 0x6F00A400) + // uxtl2 Vd,Vn DV_2O 011011110iiiiiii 101001nnnnnddddd 6F00 A400 Vd,Vn (left shift - vector) -INST1(ushll2, "ushll2", 0, 0, IF_DV_2O, 0x6F00A400) - // ushll2 Vd,Vn,imm DV_2O 011011110iiiiiii 101001nnnnnddddd 6F00 A400 Vd,Vn imm (shift - vector) +INST1(tbl, "tbl", 0, IF_DV_3C, 0x0E000000) + // tbl Vd,{Vn},Vm DV_3C 0Q001110000mmmmm 000000nnnnnddddd 0E00 0000 Vd,Vn,Vm (vector) -INST1(shrn, "shrn", 0, 0, IF_DV_2O, 0x0F008400) - // shrn Vd,Vn,imm DV_2O 000011110iiiiiii 100001nnnnnddddd 0F00 8400 Vd,Vn imm (shift - vector) +INST1(tbl_2regs, "tbl", 0, IF_DV_3C, 0x0E002000) + // tbl Vd,{Vn,Vn+1},Vm DV_3C 0Q001110000mmmmm 001000nnnnnddddd 0E00 2000 Vd,Vn,Vm (vector) -INST1(shrn2, "shrn2", 0, 0, IF_DV_2O, 0x4F008400) - // shrn2 Vd,Vn,imm DV_2O 010011110iiiiiii 100001nnnnnddddd 4F00 8400 Vd,Vn imm (shift - vector) +INST1(tbl_3regs, "tbl", 0, IF_DV_3C, 0x0E004000) + // tbl Vd,{Vn,Vn+1,Vn+2},Vm DV_3C 0Q001110000mmmmm 010000nnnnnddddd 0E00 4000 Vd,Vn,Vm (vector) -INST1(rshrn, "rshrn", 0, 0, IF_DV_2O, 0x0F008C00) - // rshrn Vd,Vn,imm DV_2O 000011110iiiiiii 100011nnnnnddddd 0F00 8C00 Vd,Vn imm (shift - vector) +INST1(tbl_4regs, "tbl", 0, IF_DV_3C, 0x0E006000) + // tbl Vd,{Vn,Vn+1,Vn+2,Vn+3},Vm DV_3C 0Q001110000mmmmm 011000nnnnnddddd 0E00 6000 Vd,Vn,Vm (vector) -INST1(rshrn2, "rshrn2", 0, 0, IF_DV_2O, 0x4F008C00) - // rshrn2 Vd,Vn,imm DV_2O 010011110iiiiiii 100011nnnnnddddd 4F00 8C00 Vd,Vn imm (shift - vector) +INST1(tbx, "tbx", 0, IF_DV_3C, 0x0E001000) + // tbx Vd,{Vn},Vm DV_3C 0Q001110000mmmmm 000100nnnnnddddd 0E00 1000 Vd,Vn,Vm (vector) -INST1(sxtl, "sxtl", 0, 0, IF_DV_2O, 0x0F00A400) - // sxtl Vd,Vn DV_2O 000011110iiiiiii 101001nnnnnddddd 0F00 A400 Vd,Vn (shift - vector) +INST1(tbx_2regs, "tbx", 0, IF_DV_3C, 0x0E003000) + // tbx Vd,{Vn,Vn+1},Vm DV_3C 0Q001110000mmmmm 001100nnnnnddddd 0E00 3000 Vd,Vn,Vm (vector) -INST1(sxtl2, "sxtl2", 0, 0, IF_DV_2O, 0x4F00A400) - // sxtl2 Vd,Vn DV_2O 010011110iiiiiii 101001nnnnnddddd 4F00 A400 Vd,Vn (shift - vector) +INST1(tbx_3regs, "tbx", 0, IF_DV_3C, 0x0E005000) + // tbx Vd,{Vn,Vn+1,Vn+2},Vm DV_3C 0Q001110000mmmmm 010100nnnnnddddd 0E00 5000 Vd,Vn,Vm (vector) -INST1(uxtl, "uxtl", 0, 0, IF_DV_2O, 0x2F00A400) - // uxtl Vd,Vn DV_2O 001011110iiiiiii 101001nnnnnddddd 2F00 A400 Vd,Vn (shift - vector) +INST1(tbx_4regs, "tbx", 0, IF_DV_3C, 0x0E007000) + // tbx Vd,{Vn,Vn+1,Vn+2,Vn+3},Vm DV_3C 0Q001110000mmmmm 011100nnnnnddddd 0E00 7000 Vd,Vn,Vm (vector) -INST1(uxtl2, "uxtl2", 0, 0, IF_DV_2O, 0x6F00A400) - // uxtl2 Vd,Vn DV_2O 011011110iiiiiii 101001nnnnnddddd 6F00 A400 Vd,Vn (shift - vector) // clang-format on /*****************************************************************************/ diff --git a/src/coreclr/src/jit/instrsxarch.h b/src/coreclr/src/jit/instrsxarch.h index 986ce9ab450c13..cbb56aa04c434f 100644 --- a/src/coreclr/src/jit/instrsxarch.h +++ b/src/coreclr/src/jit/instrsxarch.h @@ -87,6 +87,9 @@ INST4(lea, "lea", IUM_WR, BAD_CODE, BAD_CODE, // and the registers need to be reversed to get the correct encoding. INST3(bt, "bt", IUM_RD, 0x0F00A3, BAD_CODE, 0x0F00A3, INS_FLAGS_WritesFlags) +INST3(bsf, "bsf", IUM_WR, BAD_CODE, BAD_CODE, 0x0F00BC, INS_FLAGS_WritesFlags) +INST3(bsr, "bsr", IUM_WR, BAD_CODE, BAD_CODE, 0x0F00BD, INS_FLAGS_WritesFlags) + INST3(movsx, "movsx", IUM_WR, BAD_CODE, BAD_CODE, 0x0F00BE, INS_FLAGS_None) #ifdef TARGET_AMD64 INST3(movsxd, "movsxd", IUM_WR, BAD_CODE, BAD_CODE, 0x4800000063, INS_FLAGS_None) diff --git a/src/coreclr/src/jit/jitconfigvalues.h b/src/coreclr/src/jit/jitconfigvalues.h index 65b92b55ba1338..d531362543ebe0 100644 --- a/src/coreclr/src/jit/jitconfigvalues.h +++ b/src/coreclr/src/jit/jitconfigvalues.h @@ -352,12 +352,19 @@ CONFIG_STRING(JitFuncInfoFile, W("JitFuncInfoLogFile")) // If set, gather JIT fu CONFIG_STRING(JitTimeLogCsv, W("JitTimeLogCsv")) // If set, gather JIT throughput data and write to a CSV file. This // mode must be used in internal retail builds. CONFIG_STRING(TailCallOpt, W("TailCallOpt")) +CONFIG_INTEGER(FastTailCalls, W("FastTailCalls"), 1) // If set, allow fast tail calls; otherwise allow only helper-based + // calls + // for explicit tail calls. CONFIG_INTEGER(JitMeasureNowayAssert, W("JitMeasureNowayAssert"), 0) // Set to 1 to measure noway_assert usage. Only // valid if MEASURE_NOWAY is defined. CONFIG_STRING(JitMeasureNowayAssertFile, W("JitMeasureNowayAssertFile")) // Set to file to write noway_assert usage to a file (if not // set: stdout). Only valid if MEASURE_NOWAY is defined. +#if defined(DEBUG) +CONFIG_INTEGER(EnableExtraSuperPmiQueries, W("EnableExtraSuperPmiQueries"), 0) // Make extra queries to somewhat + // future-proof SuperPmi method contexts. +#endif // DEBUG #if defined(DEBUG) || defined(INLINE_DATA) CONFIG_INTEGER(JitInlineDumpData, W("JitInlineDumpData"), 0) @@ -430,6 +437,14 @@ CONFIG_INTEGER(JitSaveFpLrWithCalleeSavedRegisters, W("JitSaveFpLrWithCalleeSave #endif // defined(TARGET_ARM64) #endif // DEBUG +#if defined(TARGET_ARMARCH) +CONFIG_INTEGER(JitDoOldStructRetyping, W("JitDoOldStructRetyping"), 1) // Allow Jit to retype structs as primitive types + // when possible. +#else +CONFIG_INTEGER(JitDoOldStructRetyping, W("JitDoOldStructRetyping"), 1) // Allow Jit to retype structs as primitive types + // when possible. +#endif + #undef CONFIG_INTEGER #undef CONFIG_STRING #undef CONFIG_METHODSET diff --git a/src/coreclr/src/jit/lclvars.cpp b/src/coreclr/src/jit/lclvars.cpp index 3cd224462f0f41..608b4410cd9421 100644 --- a/src/coreclr/src/jit/lclvars.cpp +++ b/src/coreclr/src/jit/lclvars.cpp @@ -39,7 +39,7 @@ void Compiler::lvaInit() /* We haven't allocated stack variables yet */ lvaRefCountState = RCS_INVALID; - lvaGenericsContextUseCount = 0; + lvaGenericsContextInUse = false; lvaTrackedToVarNumSize = 0; lvaTrackedToVarNum = nullptr; @@ -72,6 +72,7 @@ void Compiler::lvaInit() lvaStubArgumentVar = BAD_VAR_NUM; lvaArg0Var = BAD_VAR_NUM; lvaMonAcquired = BAD_VAR_NUM; + lvaRetAddrVar = BAD_VAR_NUM; lvaInlineeReturnSpillTemp = BAD_VAR_NUM; @@ -624,7 +625,7 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo) // If the argType is a struct, then check if it is an HFA if (varTypeIsStruct(argType)) { - // hfaType is set to float, double or SIMD type if it is an HFA, otherwise TYP_UNDEF. + // hfaType is set to float, double, or SIMD type if it is an HFA, otherwise TYP_UNDEF hfaType = GetHfaType(typeHnd); isHfaArg = varTypeIsValidHfaType(hfaType); } @@ -643,9 +644,9 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo) if (isHfaArg) { - // We have an HFA argument, so from here on out treat the type as a float, double or vector. - // The orginal struct type is available by using origArgType - // We also update the cSlots to be the number of float/double fields in the HFA + // We have an HFA argument, so from here on out treat the type as a float, double, or vector. + // The orginal struct type is available by using origArgType. + // We also update the cSlots to be the number of float/double/vector fields in the HFA. argType = hfaType; varDsc->SetHfaType(hfaType); cSlots = varDsc->lvHfaSlots(); @@ -1970,10 +1971,12 @@ bool Compiler::StructPromotionHelper::ShouldPromoteStructVar(unsigned lclNum) // void Compiler::StructPromotionHelper::SortStructFields() { - assert(!structPromotionInfo.fieldsSorted); - qsort(structPromotionInfo.fields, structPromotionInfo.fieldCnt, sizeof(*structPromotionInfo.fields), - lvaFieldOffsetCmp); - structPromotionInfo.fieldsSorted = true; + if (!structPromotionInfo.fieldsSorted) + { + qsort(structPromotionInfo.fields, structPromotionInfo.fieldCnt, sizeof(*structPromotionInfo.fields), + lvaFieldOffsetCmp); + structPromotionInfo.fieldsSorted = true; + } } //-------------------------------------------------------------------------------------------- @@ -2157,10 +2160,7 @@ void Compiler::StructPromotionHelper::PromoteStructVar(unsigned lclNum) } #endif - if (!structPromotionInfo.fieldsSorted) - { - SortStructFields(); - } + SortStructFields(); for (unsigned index = 0; index < structPromotionInfo.fieldCnt; ++index) { @@ -2614,10 +2614,11 @@ void Compiler::lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool } #endif // FEATURE_SIMD #ifdef FEATURE_HFA - // for structs that are small enough, we check and set lvIsHfa and lvHfaTypeIsFloat + // For structs that are small enough, we check and set HFA element type if (varDsc->lvExactSize <= MAX_PASS_MULTIREG_BYTES) { - var_types hfaType = GetHfaType(typeHnd); // set to float or double if it is an HFA, otherwise TYP_UNDEF + // hfaType is set to float, double or SIMD type if it is an HFA, otherwise TYP_UNDEF + var_types hfaType = GetHfaType(typeHnd); if (varTypeIsValidHfaType(hfaType)) { varDsc->SetHfaType(hfaType); @@ -2670,8 +2671,53 @@ void Compiler::lvaSetStruct(unsigned varNum, CORINFO_CLASS_HANDLE typeHnd, bool compGSReorderStackLayout = true; varDsc->lvIsUnsafeBuffer = true; } +#ifdef DEBUG + if (JitConfig.EnableExtraSuperPmiQueries()) + { + makeExtraStructQueries(typeHnd, 2); + } +#endif // DEBUG } +#ifdef DEBUG +//------------------------------------------------------------------------ +// makeExtraStructQueries: Query the information for the given struct handle. +// +// Arguments: +// structHandle -- The handle for the struct type we're querying. +// level -- How many more levels to recurse. +// +void Compiler::makeExtraStructQueries(CORINFO_CLASS_HANDLE structHandle, int level) +{ + if (level <= 0) + { + return; + } + assert(structHandle != NO_CLASS_HANDLE); + (void)typGetObjLayout(structHandle); + unsigned fieldCnt = info.compCompHnd->getClassNumInstanceFields(structHandle); + impNormStructType(structHandle); +#ifdef TARGET_ARMARCH + GetHfaType(structHandle); +#endif + for (unsigned int i = 0; i < fieldCnt; i++) + { + CORINFO_FIELD_HANDLE fieldHandle = info.compCompHnd->getFieldInClass(structHandle, i); + unsigned fldOffset = info.compCompHnd->getFieldOffset(fieldHandle); + CORINFO_CLASS_HANDLE fieldClassHandle = NO_CLASS_HANDLE; + CorInfoType fieldCorType = info.compCompHnd->getFieldType(fieldHandle, &fieldClassHandle); + var_types fieldVarType = JITtype2varType(fieldCorType); + if (fieldClassHandle != NO_CLASS_HANDLE) + { + if (varTypeIsStruct(fieldVarType)) + { + makeExtraStructQueries(fieldClassHandle, level - 1); + } + } + } +} +#endif // DEBUG + //------------------------------------------------------------------------ // lvaSetStructUsedAsVarArg: update hfa information for vararg struct args // @@ -3606,6 +3652,8 @@ var_types LclVarDsc::lvaArgType() // eligible for assertion prop, single defs, and tracking which blocks // hold uses. // +// Looks for uses of generic context and sets lvaGenericsContextInUse. +// // In checked builds: // // Verifies that local accesses are consistenly typed. @@ -3711,6 +3759,17 @@ void Compiler::lvaMarkLclRefs(GenTree* tree, BasicBlock* block, Statement* stmt, /* This must be a local variable reference */ + // See if this is a generics context use. + if ((tree->gtFlags & GTF_VAR_CONTEXT) != 0) + { + assert(tree->OperIs(GT_LCL_VAR)); + if (!lvaGenericsContextInUse) + { + JITDUMP("-- generic context in use at [%06u]\n", dspTreeID(tree)); + lvaGenericsContextInUse = true; + } + } + assert((tree->gtOper == GT_LCL_VAR) || (tree->gtOper == GT_LCL_FLD)); unsigned lclNum = tree->AsLclVarCommon()->GetLclNum(); @@ -3794,7 +3853,8 @@ void Compiler::lvaMarkLclRefs(GenTree* tree, BasicBlock* block, Statement* stmt, allowStructs || genActualType(varDsc->TypeGet()) == genActualType(tree->gtType) || (tree->gtType == TYP_BYREF && varDsc->TypeGet() == TYP_I_IMPL) || (tree->gtType == TYP_I_IMPL && varDsc->TypeGet() == TYP_BYREF) || (tree->gtFlags & GTF_VAR_CAST) || - varTypeIsFloating(varDsc->TypeGet()) && varTypeIsFloating(tree->gtType)); + (varTypeIsFloating(varDsc) && varTypeIsFloating(tree)) || + (varTypeIsStruct(varDsc) == varTypeIsStruct(tree))); /* Remember the type of the reference */ @@ -4008,24 +4068,26 @@ void Compiler::lvaMarkLocalVars() return; } -#if ASSERTION_PROP - assert(opts.OptimizationEnabled()); - - // Note: optAddCopies() depends on lvaRefBlks, which is set in lvaMarkLocalVars(BasicBlock*), called above. - optAddCopies(); -#endif + const bool reportParamTypeArg = lvaReportParamTypeArg(); + // Update bookkeeping on the generic context. if (lvaKeepAliveAndReportThis()) { - lvaTable[0].lvImplicitlyReferenced = 1; - // This isn't strictly needed as we will make a copy of the param-type-arg - // in the prolog. However, this ensures that the LclVarDsc corresponding to - // info.compTypeCtxtArg is valid. + lvaGetDesc(0u)->lvImplicitlyReferenced = reportParamTypeArg; } else if (lvaReportParamTypeArg()) { - lvaTable[info.compTypeCtxtArg].lvImplicitlyReferenced = 1; + // We should have a context arg. + assert(info.compTypeCtxtArg != BAD_VAR_NUM); + lvaGetDesc(info.compTypeCtxtArg)->lvImplicitlyReferenced = reportParamTypeArg; } + +#if ASSERTION_PROP + assert(opts.OptimizationEnabled()); + + // Note: optAddCopies() depends on lvaRefBlks, which is set in lvaMarkLocalVars(BasicBlock*), called above. + optAddCopies(); +#endif } //------------------------------------------------------------------------ @@ -4045,7 +4107,10 @@ void Compiler::lvaMarkLocalVars() // In fast-jitting modes where we don't ref count locals, this bypasses // actual counting, and makes all locals implicitly referenced on first // compute. It asserts all locals are implicitly referenced on recompute. - +// +// When optimizing we also recompute lvaGenericsContextInUse based +// on specially flagged LCL_VAR appearances. +// void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) { JITDUMP("\n*** lvaComputeRefCounts ***\n"); @@ -4140,6 +4205,11 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) varDsc->lvSingleDef = varDsc->lvIsParam; } + // Remember current state of generic context use, and prepare + // to compute new state. + const bool oldLvaGenericsContextInUse = lvaGenericsContextInUse; + lvaGenericsContextInUse = false; + JITDUMP("\n*** lvaComputeRefCounts -- explicit counts ***\n"); // Second, account for all explicit local variable references @@ -4175,6 +4245,12 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) { varDsc->incRefCnts(weight, this); } + + if ((node->gtFlags & GTF_VAR_CONTEXT) != 0) + { + assert(node->OperIs(GT_LCL_VAR)); + lvaGenericsContextInUse = true; + } break; } @@ -4189,6 +4265,21 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) } } + if (oldLvaGenericsContextInUse && !lvaGenericsContextInUse) + { + // Context was in use but no longer is. This can happen + // if we're able to optimize, so just leave a note. + JITDUMP("\n** Generics context no longer in use\n"); + } + else if (lvaGenericsContextInUse && !oldLvaGenericsContextInUse) + { + // Context was not in use but now is. + // + // Changing from unused->used should never happen; creation of any new IR + // for context use should also be settting lvaGenericsContextInUse. + assert(!"unexpected new use of generics context"); + } + JITDUMP("\n*** lvaComputeRefCounts -- implicit counts ***\n"); // Third, bump ref counts for some implicit prolog references @@ -4949,6 +5040,20 @@ void Compiler::lvaFixVirtualFrameOffsets() } #endif // FEATURE_FIXED_OUT_ARGS + +#ifdef TARGET_ARM64 + // We normally add alignment below the locals between them and the outgoing + // arg space area. When we store fp/lr at the bottom, however, this will be + // below the alignment. So we should not apply the alignment adjustment to + // them. On ARM64 it turns out we always store these at +0 and +8 of the FP, + // so instead of dealing with skipping adjustment just for them we just set + // them here always. + assert(codeGen->isFramePointerUsed()); + if (lvaRetAddrVar != BAD_VAR_NUM) + { + lvaTable[lvaRetAddrVar].lvStkOffs = REGSIZE_BYTES; + } +#endif } #ifdef TARGET_ARM @@ -5664,6 +5769,10 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() #ifdef TARGET_XARCH // On x86/amd64, the return address has already been pushed by the call instruction in the caller. stkOffs -= TARGET_POINTER_SIZE; // return address; + if (lvaRetAddrVar != BAD_VAR_NUM) + { + lvaTable[lvaRetAddrVar].lvStkOffs = stkOffs; + } // If we are an OSR method, we "inherit" the frame of the original method, // and the stack is already double aligned on entry (since the return adddress push @@ -5724,7 +5833,16 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() stkOffs -= (compCalleeRegsPushed - 2) * REGSIZE_BYTES; } -#else // !TARGET_ARM64 +#else // !TARGET_ARM64 +#ifdef TARGET_ARM + // On ARM32 LR is part of the pushed registers and is always stored at the + // top. + if (lvaRetAddrVar != BAD_VAR_NUM) + { + lvaTable[lvaRetAddrVar].lvStkOffs = stkOffs - REGSIZE_BYTES; + } +#endif + stkOffs -= compCalleeRegsPushed * REGSIZE_BYTES; #endif // !TARGET_ARM64 @@ -6085,7 +6203,7 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals() #ifdef JIT32_GCENCODER lclNum == lvaLocAllocSPvar || #endif // JIT32_GCENCODER - false) + lclNum == lvaRetAddrVar) { assert(varDsc->lvStkOffs != BAD_STK_OFFS); continue; diff --git a/src/coreclr/src/jit/lower.cpp b/src/coreclr/src/jit/lower.cpp index 3e79393cce1a20..75d63a18661f7d 100644 --- a/src/coreclr/src/jit/lower.cpp +++ b/src/coreclr/src/jit/lower.cpp @@ -37,7 +37,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // Notes: // If 'childNode' it has any existing sources, they will now be sources for the parent. // -void Lowering::MakeSrcContained(GenTree* parentNode, GenTree* childNode) +void Lowering::MakeSrcContained(GenTree* parentNode, GenTree* childNode) const { assert(!parentNode->OperIsLeaf()); assert(childNode->canBeContained()); @@ -112,8 +112,8 @@ GenTree* Lowering::LowerNode(GenTree* node) switch (node->gtOper) { case GT_IND: - // Leave struct typed indirs alone, they only appear as the source of - // block copy operations and LowerBlockStore will handle those. + // Process struct typed indirs separately, they only appear as the source of + // a block copy operation or a return node. if (node->TypeGet() != TYP_STRUCT) { // TODO-Cleanup: We're passing isContainable = true but ContainCheckIndir rejects @@ -255,6 +255,13 @@ GenTree* Lowering::LowerNode(GenTree* node) case GT_STORE_BLK: case GT_STORE_OBJ: + if (node->AsBlk()->Data()->IsCall()) + { + assert(!comp->compDoOldStructRetyping()); + LowerStoreCallStruct(node->AsBlk()); + break; + } + __fallthrough; case GT_STORE_DYN_BLK: LowerBlockStore(node->AsBlk()); break; @@ -297,64 +304,8 @@ GenTree* Lowering::LowerNode(GenTree* node) __fallthrough; case GT_STORE_LCL_FLD: - { - GenTreeLclVarCommon* const store = node->AsLclVarCommon(); - GenTree* src = store->gtGetOp1(); - if ((varTypeUsesFloatReg(store) != varTypeUsesFloatReg(src)) && !store->IsPhiDefn() && - (src->TypeGet() != TYP_STRUCT)) - { - if (m_lsra->isRegCandidate(comp->lvaGetDesc(store->GetLclNum()))) - { - GenTreeUnOp* bitcast = new (comp, GT_BITCAST) GenTreeOp(GT_BITCAST, store->TypeGet(), src, nullptr); - store->gtOp1 = bitcast; - src = store->gtGetOp1(); - BlockRange().InsertBefore(store, bitcast); - ContainCheckBitCast(bitcast); - } - else - { - // This is an actual store, we'll just retype it. - store->gtType = src->TypeGet(); - } - } - - if ((node->TypeGet() == TYP_STRUCT) && (src->OperGet() != GT_PHI)) - { - LclVarDsc* varDsc = comp->lvaGetDesc(store); -#if FEATURE_MULTIREG_RET - if (src->OperGet() == GT_CALL) - { - assert(src->AsCall()->HasMultiRegRetVal()); - } - else -#endif // FEATURE_MULTIREG_RET - if (!src->OperIs(GT_LCL_VAR) || varDsc->GetLayout()->GetRegisterType() == TYP_UNDEF) - { - GenTreeLclVar* addr = comp->gtNewLclVarAddrNode(store->GetLclNum(), TYP_BYREF); - - addr->gtFlags |= GTF_VAR_DEF; - assert(!addr->IsPartialLclFld(comp)); - addr->gtFlags |= GTF_DONT_CSE; - - // Create the assignment node. - store->ChangeOper(GT_STORE_OBJ); - - store->gtFlags = GTF_ASG | GTF_IND_NONFAULTING | GTF_IND_TGT_NOT_HEAP; -#ifndef JIT32_GCENCODER - store->AsObj()->gtBlkOpGcUnsafe = false; -#endif - store->AsObj()->gtBlkOpKind = GenTreeObj::BlkOpKindInvalid; - store->AsObj()->SetLayout(varDsc->GetLayout()); - store->AsObj()->SetAddr(addr); - store->AsObj()->SetData(src); - BlockRange().InsertBefore(store, addr); - LowerBlockStore(store->AsObj()); - break; - } - } - LowerStoreLoc(node->AsLclVarCommon()); + LowerStoreLocCommon(node->AsLclVarCommon()); break; - } #if defined(TARGET_ARM64) case GT_CMPXCHG: @@ -1331,11 +1282,18 @@ void Lowering::LowerArg(GenTreeCall* call, GenTree** ppArg) LclVarDsc* varDsc = &comp->lvaTable[varNum]; type = varDsc->lvType; } - else if (arg->OperGet() == GT_SIMD) + else if (arg->OperIs(GT_SIMD, GT_HWINTRINSIC)) { - assert((arg->AsSIMD()->gtSIMDSize == 16) || (arg->AsSIMD()->gtSIMDSize == 12)); + GenTreeJitIntrinsic* jitIntrinsic = reinterpret_cast(arg); + + // For HWIntrinsic, there are some intrinsics like ExtractVector128 which have + // a gtType of TYP_SIMD16 but a gtSIMDSize of 32, so we need to include that in + // the assert below. + + assert((jitIntrinsic->gtSIMDSize == 12) || (jitIntrinsic->gtSIMDSize == 16) || + (jitIntrinsic->gtSIMDSize == 32)); - if (arg->AsSIMD()->gtSIMDSize == 12) + if (jitIntrinsic->gtSIMDSize == 12) { type = TYP_SIMD12; } @@ -1616,7 +1574,7 @@ void Lowering::LowerCall(GenTree* node) } } - if (call->IsTailCallViaHelper()) + if (call->IsTailCallViaJitHelper()) { // Either controlExpr or gtCallAddr must contain real call target. if (controlExpr == nullptr) @@ -1626,7 +1584,7 @@ void Lowering::LowerCall(GenTree* node) controlExpr = call->gtCallAddr; } - controlExpr = LowerTailCallViaHelper(call, controlExpr); + controlExpr = LowerTailCallViaJitHelper(call, controlExpr); } if (controlExpr != nullptr) @@ -1637,7 +1595,7 @@ void Lowering::LowerCall(GenTree* node) DISPRANGE(controlExprRange); GenTree* insertionPoint = call; - if (!call->IsTailCallViaHelper()) + if (!call->IsTailCallViaJitHelper()) { // The controlExpr should go before the gtCallCookie and the gtCallAddr, if they exist // @@ -1682,6 +1640,11 @@ void Lowering::LowerCall(GenTree* node) LowerFastTailCall(call); } + if (varTypeIsStruct(call)) + { + LowerCallStruct(call); + } + ContainCheckCallOperands(call); JITDUMP("lowering call (after):\n"); DISPTREERANGE(BlockRange(), call); @@ -1994,10 +1957,9 @@ void Lowering::LowerFastTailCall(GenTreeCall* call) #else // !FEATURE_FASTTAILCALL - // Platform choose not to implement fast tail call mechanism. - // In such a case we should never be reaching this method as - // the expectation is that IsTailCallViaHelper() will always - // be true on such a platform. + // Platform does not implement fast tail call mechanism. This cannot be + // reached because we always choose to do a tailcall via helper on those + // platforms (or no tailcall at all). unreached(); #endif } @@ -2082,16 +2044,11 @@ void Lowering::RehomeArgForFastTailCall(unsigned int lclNum, } //------------------------------------------------------------------------ -// LowerTailCallViaHelper: lower a call via the tailcall helper. Morph -// has already inserted tailcall helper special arguments. This function -// inserts actual data for some placeholders. -// -// For ARM32, AMD64, lower -// tail.call(void* copyRoutine, void* dummyArg, ...) -// as -// Jit_TailCall(void* copyRoutine, void* callTarget, ...) +// LowerTailCallViaJitHelper: lower a call via the tailcall JIT helper. Morph +// has already inserted tailcall helper special arguments. This function inserts +// actual data for some placeholders. This function is only used on x86. // -// For x86, lower +// Lower // tail.call(, int numberOfOldStackArgs, int dummyNumberOfNewStackArgs, int flags, void* dummyArg) // as // JIT_TailCall(, int numberOfOldStackArgsWords, int numberOfNewStackArgsWords, int flags, void* @@ -2107,7 +2064,7 @@ void Lowering::RehomeArgForFastTailCall(unsigned int lclNum, // Return Value: // Returns control expression tree for making a call to helper Jit_TailCall. // -GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree* callTarget) +GenTree* Lowering::LowerTailCallViaJitHelper(GenTreeCall* call, GenTree* callTarget) { // Tail call restrictions i.e. conditions under which tail prefix is ignored. // Most of these checks are already done by importer or fgMorphTailCall(). @@ -2116,12 +2073,8 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree* callTarget assert(!call->IsUnmanaged()); // tail calls to unamanaged methods assert(!comp->compLocallocUsed); // tail call from methods that also do localloc -#ifdef TARGET_AMD64 - assert(!comp->getNeedsGSSecurityCookie()); // jit64 compat: tail calls from methods that need GS check -#endif // TARGET_AMD64 - // We expect to see a call that meets the following conditions - assert(call->IsTailCallViaHelper()); + assert(call->IsTailCallViaJitHelper()); assert(callTarget != nullptr); // The TailCall helper call never returns to the caller and is not GC interruptible. @@ -2152,38 +2105,6 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree* callTarget // The callTarget tree needs to be sequenced. LIR::Range callTargetRange = LIR::SeqTree(comp, callTarget); -#if defined(TARGET_AMD64) || defined(TARGET_ARM) - - // For ARM32 and AMD64, first argument is CopyRoutine and second argument is a place holder node. - fgArgTabEntry* argEntry; - -#ifdef DEBUG - argEntry = comp->gtArgEntryByArgNum(call, 0); - assert(argEntry != nullptr); - assert(argEntry->GetNode()->OperIs(GT_PUTARG_REG)); - GenTree* firstArg = argEntry->GetNode()->AsUnOp()->gtGetOp1(); - assert(firstArg->gtOper == GT_CNS_INT); -#endif - - // Replace second arg by callTarget. - argEntry = comp->gtArgEntryByArgNum(call, 1); - assert(argEntry != nullptr); - assert(argEntry->GetNode()->OperIs(GT_PUTARG_REG)); - GenTree* secondArg = argEntry->GetNode()->AsUnOp()->gtGetOp1(); - - ContainCheckRange(callTargetRange); - BlockRange().InsertAfter(secondArg, std::move(callTargetRange)); - - bool isClosed; - LIR::ReadOnlyRange secondArgRange = BlockRange().GetTreeRange(secondArg, &isClosed); - assert(isClosed); - - BlockRange().Remove(std::move(secondArgRange)); - - argEntry->GetNode()->AsUnOp()->gtOp1 = callTarget; - -#elif defined(TARGET_X86) - // Verify the special args are what we expect, and replace the dummy args with real values. // We need to figure out the size of the outgoing stack arguments, not including the special args. // The number of 4-byte words is passed to the helper for the incoming and outgoing argument sizes. @@ -2237,21 +2158,17 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree* callTarget assert(arg3->gtOper == GT_CNS_INT); #endif // DEBUG -#else - NYI("LowerTailCallViaHelper"); -#endif // TARGET* - // Transform this call node into a call to Jit tail call helper. call->gtCallType = CT_HELPER; call->gtCallMethHnd = comp->eeFindHelper(CORINFO_HELP_TAILCALL); call->gtFlags &= ~GTF_CALL_VIRT_KIND_MASK; // Lower this as if it were a pure helper call. - call->gtCallMoreFlags &= ~(GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_HELPER); + call->gtCallMoreFlags &= ~(GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_JIT_HELPER); GenTree* result = LowerDirectCall(call); // Now add back tail call flags for identifying this node as tail call dispatched via helper. - call->gtCallMoreFlags |= GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_HELPER; + call->gtCallMoreFlags |= GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_JIT_HELPER; #ifdef PROFILING_SUPPORTED // Insert profiler tail call hook if needed. @@ -2262,8 +2179,6 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree* callTarget } #endif // PROFILING_SUPPORTED - assert(call->IsTailCallViaHelper()); - return result; } @@ -3017,14 +2932,55 @@ void Lowering::LowerRet(GenTreeUnOp* ret) JITDUMP("============"); GenTree* op1 = ret->gtGetOp1(); - if ((ret->TypeGet() != TYP_VOID) && (ret->TypeGet() != TYP_STRUCT) && + if ((ret->TypeGet() != TYP_VOID) && !varTypeIsStruct(ret) && (varTypeUsesFloatReg(ret) != varTypeUsesFloatReg(ret->gtGetOp1()))) { + assert(comp->compDoOldStructRetyping()); GenTreeUnOp* bitcast = new (comp, GT_BITCAST) GenTreeOp(GT_BITCAST, ret->TypeGet(), ret->gtGetOp1(), nullptr); ret->gtOp1 = bitcast; BlockRange().InsertBefore(ret, bitcast); ContainCheckBitCast(bitcast); } + else + { +#ifdef DEBUG + if (ret->TypeGet() != TYP_VOID) + { + GenTree* retVal = ret->gtGetOp1(); + if (varTypeIsStruct(ret->TypeGet()) != varTypeIsStruct(retVal->TypeGet())) + { + if (varTypeIsStruct(ret->TypeGet())) + { + assert(!comp->compDoOldStructRetyping()); + bool actualTypesMatch = false; + if (genActualType(comp->info.compRetNativeType) == genActualType(retVal->TypeGet())) + { + // This could happen if we have retyped op1 as a primitive type during struct promotion, + // check `retypedFieldsMap` for details. + actualTypesMatch = true; + } + bool constStructInit = retVal->IsConstInitVal(); + assert(actualTypesMatch || constStructInit); + } + else + { +#ifdef FEATURE_SIMD + assert(comp->compDoOldStructRetyping()); + assert(ret->TypeIs(TYP_DOUBLE)); + assert(retVal->TypeIs(TYP_SIMD8)); +#else // !FEATURE_SIMD + unreached(); +#endif // !FEATURE_SIMD + } + } + } +#endif // DEBUG + if (varTypeIsStruct(ret) && !comp->compMethodReturnsMultiRegRetType()) + { + assert(!comp->compDoOldStructRetyping()); + LowerRetStruct(ret); + } + } // Method doing PInvokes has exactly one return block unless it has tail calls. if (comp->compMethodRequiresPInvokeFrame() && (comp->compCurBB == comp->genReturnBB)) @@ -3034,13 +2990,420 @@ void Lowering::LowerRet(GenTreeUnOp* ret) ContainCheckRet(ret); } +//---------------------------------------------------------------------------------------------- +// LowerStoreLocCommon: platform idependent part of local var or field store lowering. +// +// Arguments: +// lclStore - The store lcl node to lower. +// +void Lowering::LowerStoreLocCommon(GenTreeLclVarCommon* lclStore) +{ + assert(lclStore->OperIs(GT_STORE_LCL_FLD, GT_STORE_LCL_VAR)); + GenTree* src = lclStore->gtGetOp1(); + LclVarDsc* varDsc = comp->lvaGetDesc(lclStore); + if ((varTypeUsesFloatReg(lclStore) != varTypeUsesFloatReg(src)) && !lclStore->IsPhiDefn() && + (src->TypeGet() != TYP_STRUCT)) + { + if (m_lsra->isRegCandidate(varDsc)) + { + GenTreeUnOp* bitcast = new (comp, GT_BITCAST) GenTreeOp(GT_BITCAST, lclStore->TypeGet(), src, nullptr); + lclStore->gtOp1 = bitcast; + src = lclStore->gtGetOp1(); + BlockRange().InsertBefore(lclStore, bitcast); + ContainCheckBitCast(bitcast); + } + else + { + // This is an actual store, we'll just retype it. + lclStore->gtType = src->TypeGet(); + } + } + + if ((lclStore->TypeGet() == TYP_STRUCT) && (src->OperGet() != GT_PHI)) + { + if (src->OperGet() == GT_CALL) + { + GenTreeCall* call = src->AsCall(); + const ClassLayout* layout = varDsc->GetLayout(); + const var_types regType = layout->GetRegisterType(); + +#ifdef DEBUG + const unsigned slotCount = layout->GetSlotCount(); +#if defined(TARGET_XARCH) && !defined(UNIX_AMD64_ABI) + // Windows x64 doesn't have multireg returns, + // x86 uses it only for long return type, not for structs. + assert(!comp->compDoOldStructRetyping()); + assert(slotCount == 1); + assert(regType != TYP_UNDEF); +#else // !TARGET_XARCH || UNIX_AMD64_ABI + if (!varDsc->lvIsHfa()) + { + if (slotCount > 1) + { + assert(call->HasMultiRegRetVal()); + } + else + { + assert(!comp->compDoOldStructRetyping()); + unsigned size = layout->GetSize(); + assert((size <= 8) || (size == 16)); + bool isPowerOf2 = (((size - 1) & size) == 0); + bool isTypeDefined = (regType != TYP_UNDEF); + assert(isPowerOf2 == isTypeDefined); + } + } +#endif // !TARGET_XARCH || UNIX_AMD64_ABI +#endif // DEBUG + +#if !defined(WINDOWS_AMD64_ABI) + if (!call->HasMultiRegRetVal() && (regType == TYP_UNDEF)) + { + // If we have a single return register, + // but we can't retype it as a primitive type, we must spill it. + GenTreeLclVar* spilledCall = SpillStructCallResult(call); + lclStore->gtOp1 = spilledCall; + src = lclStore->gtOp1; + LowerStoreLocCommon(lclStore); + return; + } +#endif // !WINDOWS_AMD64_ABI + } + else if (!src->OperIs(GT_LCL_VAR) || varDsc->GetLayout()->GetRegisterType() == TYP_UNDEF) + { + GenTreeLclVar* addr = comp->gtNewLclVarAddrNode(lclStore->GetLclNum(), TYP_BYREF); + + addr->gtFlags |= GTF_VAR_DEF; + assert(!addr->IsPartialLclFld(comp)); + addr->gtFlags |= GTF_DONT_CSE; + + // Create the assignment node. + lclStore->ChangeOper(GT_STORE_OBJ); + GenTreeBlk* objStore = lclStore->AsObj(); + objStore->gtFlags = GTF_ASG | GTF_IND_NONFAULTING | GTF_IND_TGT_NOT_HEAP; +#ifndef JIT32_GCENCODER + objStore->gtBlkOpGcUnsafe = false; +#endif + objStore->gtBlkOpKind = GenTreeObj::BlkOpKindInvalid; + objStore->SetLayout(varDsc->GetLayout()); + objStore->SetAddr(addr); + objStore->SetData(src); + BlockRange().InsertBefore(objStore, addr); + LowerBlockStore(objStore); + return; + } + } + LowerStoreLoc(lclStore); +} + +//---------------------------------------------------------------------------------------------- +// LowerRetStructLclVar: Lowers a struct return node. +// +// Arguments: +// node - The return node to lower. +// +void Lowering::LowerRetStruct(GenTreeUnOp* ret) +{ + assert(!comp->compMethodReturnsMultiRegRetType()); + assert(!comp->compDoOldStructRetyping()); + assert(ret->OperIs(GT_RETURN)); + assert(varTypeIsStruct(ret)); + + GenTree* retVal = ret->gtGetOp1(); + // Note: small types are returned as INT. + var_types nativeReturnType = genActualType(comp->info.compRetNativeType); + ret->ChangeType(nativeReturnType); + + switch (retVal->OperGet()) + { + case GT_CALL: + assert(retVal->TypeIs(nativeReturnType)); // Type should be changed during call processing. + break; + + case GT_CNS_INT: + assert(retVal->TypeIs(TYP_INT)); + assert(retVal->AsIntCon()->IconValue() == 0); + if (varTypeUsesFloatReg(nativeReturnType)) + { + retVal->ChangeOperConst(GT_CNS_DBL); + retVal->ChangeType(TYP_FLOAT); + retVal->AsDblCon()->gtDconVal = 0; + } + break; + + case GT_OBJ: + retVal->ChangeOper(GT_IND); + __fallthrough; + case GT_IND: + retVal->ChangeType(nativeReturnType); + break; + + case GT_LCL_VAR: + LowerRetStructLclVar(ret); + break; + +#if defined(FEATURE_SIMD) || defined(FEATURE_HW_INTRINSICS) +#ifdef FEATURE_SIMD + case GT_SIMD: +#endif // FEATURE_SIMD +#ifdef FEATURE_HW_INTRINSICS + case GT_HWINTRINSIC: +#endif // FEATURE_HW_INTRINSICS + { + assert(!retVal->TypeIs(TYP_STRUCT)); + if (varTypeUsesFloatReg(ret) != varTypeUsesFloatReg(retVal)) + { + GenTreeUnOp* bitcast = new (comp, GT_BITCAST) GenTreeOp(GT_BITCAST, ret->TypeGet(), retVal, nullptr); + ret->gtOp1 = bitcast; + BlockRange().InsertBefore(ret, bitcast); + ContainCheckBitCast(bitcast); + } + } + break; +#endif // FEATURE_SIMD || FEATURE_HW_INTRINSICS + + case GT_LCL_FLD: + { +#ifdef DEBUG + GenTreeLclFld* lclFld = retVal->AsLclFld(); + unsigned lclNum = lclFld->GetLclNum(); + LclVarDsc* varDsc = comp->lvaGetDesc(lclNum); + assert(varDsc->lvDoNotEnregister); +#endif + retVal->ChangeType(nativeReturnType); + } + break; + + default: + unreached(); + } +} + +//---------------------------------------------------------------------------------------------- +// LowerRetStructLclVar: Lowers a return node with a struct lclVar as a source. +// +// Arguments: +// node - The return node to lower. +// +// Notes: +// - if LclVar is allocated in memory then read it as return type; +// - if LclVar can be enregistered read it as register type and add a bitcast if necessary; +// +void Lowering::LowerRetStructLclVar(GenTreeUnOp* ret) +{ + assert(!comp->compMethodReturnsMultiRegRetType()); + assert(!comp->compDoOldStructRetyping()); + assert(ret->OperIs(GT_RETURN)); + GenTreeLclVarCommon* lclVar = ret->gtGetOp1()->AsLclVar(); + assert(lclVar->OperIs(GT_LCL_VAR)); + unsigned lclNum = lclVar->GetLclNum(); + LclVarDsc* varDsc = comp->lvaGetDesc(lclNum); + +#ifdef DEBUG + if (comp->gtGetStructHandleIfPresent(lclVar) == NO_CLASS_HANDLE) + { + // a promoted struct field was retyped as its only field. + assert(varDsc->lvIsStructField); + } +#endif + if (varDsc->lvPromoted && (comp->lvaGetPromotionType(lclNum) == Compiler::PROMOTION_TYPE_INDEPENDENT)) + { + if (varDsc->lvFieldCnt == 1) + { + // We can replace the struct with its only field and keep the field on a register. + assert(varDsc->lvRefCnt() == 0); + unsigned fieldLclNum = varDsc->lvFieldLclStart; + LclVarDsc* fieldDsc = comp->lvaGetDesc(fieldLclNum); + if (fieldDsc->lvFldOffset == 0) + { + lclVar->SetLclNum(fieldLclNum); + JITDUMP("Replacing an independently promoted local var with its only field for the return %u, %u\n", + lclNum, fieldLclNum); + lclVar->ChangeType(fieldDsc->lvType); + lclNum = fieldLclNum; + varDsc = comp->lvaGetDesc(lclNum); + } + } + else + { + // TODO-1stClassStructs: We can no longer promote or enregister this struct, + // since it is referenced as a whole. + comp->lvaSetVarDoNotEnregister(lclNum DEBUGARG(Compiler::DNER_VMNeedsStackAddr)); + } + } + + if (varDsc->lvDoNotEnregister) + { + lclVar->ChangeOper(GT_LCL_FLD); + lclVar->AsLclFld()->SetLclOffs(0); + lclVar->ChangeType(ret->TypeGet()); + } + else + { + var_types lclVarType = varDsc->GetRegisterType(lclVar); + assert(lclVarType != TYP_UNDEF); + lclVar->ChangeType(lclVarType); + + if (varTypeUsesFloatReg(ret) != varTypeUsesFloatReg(lclVarType)) + { + GenTreeUnOp* bitcast = new (comp, GT_BITCAST) GenTreeOp(GT_BITCAST, ret->TypeGet(), lclVar, nullptr); + ret->gtOp1 = bitcast; + BlockRange().InsertBefore(ret, bitcast); + ContainCheckBitCast(bitcast); + } + } +} + +//---------------------------------------------------------------------------------------------- +// LowerCallStruct: Lowers a call node that returns a stuct. +// +// Arguments: +// call - The call node to lower. +// +// Notes: +// - this handles only single-register returns; +// - it transforms the call's user for `GT_STOREIND`. +// +void Lowering::LowerCallStruct(GenTreeCall* call) +{ + assert(varTypeIsStruct(call)); + if (call->HasMultiRegRetVal()) + { + return; + } + +#ifdef TARGET_ARMARCH + // !compDoOldStructRetyping is not supported on arm yet, + // because of HFA. + assert(comp->compDoOldStructRetyping()); + return; +#else // !TARGET_ARMARCH + + assert(!comp->compDoOldStructRetyping()); + CORINFO_CLASS_HANDLE retClsHnd = call->gtRetClsHnd; + Compiler::structPassingKind howToReturnStruct; + var_types returnType = comp->getReturnTypeForStruct(retClsHnd, &howToReturnStruct); + assert(!varTypeIsStruct(returnType) && returnType != TYP_UNKNOWN); + var_types origType = call->TypeGet(); + call->gtType = genActualType(returnType); + + LIR::Use callUse; + if (BlockRange().TryGetUse(call, &callUse)) + { + GenTree* user = callUse.User(); + switch (user->OperGet()) + { + case GT_RETURN: + case GT_STORE_LCL_VAR: + case GT_STORE_BLK: + case GT_STORE_OBJ: + // Leave as is, the user will handle it. + assert(user->TypeIs(origType)); + break; + + case GT_STOREIND: +#ifdef FEATURE_SIMD + if (user->TypeIs(TYP_SIMD8)) + { + user->ChangeType(returnType); + break; + } +#endif // FEATURE_SIMD + // importer has a separate mechanism to retype calls to helpers, + // keep it for now. + assert(user->TypeIs(TYP_REF)); + assert(call->IsHelperCall()); + assert(returnType == user->TypeGet()); + break; + + default: + unreached(); + } + } +#endif // !TARGET_ARMARCH +} + +//---------------------------------------------------------------------------------------------- +// LowerStoreCallStruct: Lowers a store block where source is a struct typed call. +// +// Arguments: +// store - The store node to lower. +// +// Notes: +// - it spills the call's result if it can be retyped as a primitive type. +// +void Lowering::LowerStoreCallStruct(GenTreeBlk* store) +{ + assert(!comp->compDoOldStructRetyping()); + assert(varTypeIsStruct(store)); + assert(store->Data()->IsCall()); + GenTreeCall* call = store->Data()->AsCall(); + + const ClassLayout* layout = store->GetLayout(); + assert(layout->GetSlotCount() == 1); + const var_types regType = layout->GetRegisterType(); + + unsigned storeSize = store->GetLayout()->GetSize(); + if (regType != TYP_UNDEF) + { + store->ChangeType(regType); + store->SetOper(GT_STOREIND); + LowerStoreIndir(store->AsIndir()); + } + else + { +#if defined(WINDOWS_AMD64_ABI) + // All ABI except Windows x64 supports passing 3 byte structs in registers. + // Other 64 bites ABI-s support passing 5, 6, 7 byte structs. + unreached(); +#else // !WINDOWS_AMD64_ABI + if (store->OperIs(GT_STORE_OBJ)) + { + store->SetOper(GT_STORE_BLK); + } + store->gtBlkOpKind = GenTreeObj::BlkOpKindUnroll; + + GenTreeLclVar* spilledCall = SpillStructCallResult(call); + store->SetData(spilledCall); + LowerBlockStore(store); +#endif // WINDOWS_AMD64_ABI + } +} + +#if !defined(WINDOWS_AMD64_ABI) +//---------------------------------------------------------------------------------------------- +// SpillStructCallResult: Spill call result to memory. +// +// Arguments: +// call - call with 3, 5, 6 or 7 return size that has to be spilled to memory. +// +// Return Value: +// load of the spilled variable. +// +GenTreeLclVar* Lowering::SpillStructCallResult(GenTreeCall* call) const +{ + // TODO-1stClassStructs: we can support this in codegen for `GT_STORE_BLK` without new temps. + const unsigned spillNum = comp->lvaGrabTemp(true DEBUGARG("Return value temp for an odd struct return size")); + CORINFO_CLASS_HANDLE retClsHnd = call->gtRetClsHnd; + comp->lvaSetStruct(spillNum, retClsHnd, false); + GenTreeLclFld* spill = new (comp, GT_STORE_LCL_FLD) GenTreeLclFld(GT_STORE_LCL_FLD, call->gtType, spillNum, 0); + spill->gtOp1 = call; + spill->gtFlags |= GTF_VAR_DEF; + + BlockRange().InsertAfter(call, spill); + ContainCheckStoreLoc(spill); + GenTreeLclVar* loadCallResult = comp->gtNewLclvNode(spillNum, TYP_STRUCT)->AsLclVar(); + BlockRange().InsertAfter(spill, loadCallResult); + return loadCallResult; +} +#endif // !WINDOWS_AMD64_ABI + GenTree* Lowering::LowerDirectCall(GenTreeCall* call) { noway_assert(call->gtCallType == CT_USER_FUNC || call->gtCallType == CT_HELPER); // Don't support tail calling helper methods. // But we might encounter tail calls dispatched via JIT helper appear as a tail call to helper. - noway_assert(!call->IsTailCall() || call->IsTailCallViaHelper() || call->gtCallType == CT_USER_FUNC); + noway_assert(!call->IsTailCall() || call->IsTailCallViaJitHelper() || call->gtCallType == CT_USER_FUNC); // Non-virtual direct/indirect calls: Work out if the address of the // call is known at JIT time. If not it is either an indirect call @@ -3106,8 +3469,11 @@ GenTree* Lowering::LowerDirectCall(GenTreeCall* call) switch (accessType) { case IAT_VALUE: - // Non-virtual direct call to known address - if (!IsCallTargetInRange(addr) || call->IsTailCallViaHelper()) + // Non-virtual direct call to known address. + // For JIT helper based tailcall (only used on x86) the target + // address is passed as an arg to the helper so we want a node for + // it. + if (!IsCallTargetInRange(addr) || call->IsTailCallViaJitHelper()) { result = AddrGen(addr); } @@ -3121,11 +3487,22 @@ GenTree* Lowering::LowerDirectCall(GenTreeCall* call) case IAT_PVALUE: { - // Non-virtual direct calls to addresses accessed by - // a single indirection. - GenTree* cellAddr = AddrGen(addr); - GenTree* indir = Ind(cellAddr); - result = indir; + bool isR2RRelativeIndir = false; +#if defined(FEATURE_READYTORUN_COMPILER) && defined(TARGET_ARMARCH) + // Skip inserting the indirection node to load the address that is already + // computed in REG_R2R_INDIRECT_PARAM as a hidden parameter. Instead during the + // codegen, just load the call target from REG_R2R_INDIRECT_PARAM. + isR2RRelativeIndir = call->IsR2RRelativeIndir(); +#endif // FEATURE_READYTORUN_COMPILER && TARGET_ARMARCH + + if (!isR2RRelativeIndir) + { + // Non-virtual direct calls to addresses accessed by + // a single indirection. + GenTree* cellAddr = AddrGen(addr); + GenTree* indir = Ind(cellAddr); + result = indir; + } break; } @@ -3166,16 +3543,9 @@ GenTree* Lowering::LowerDelegateInvoke(GenTreeCall* call) (CORINFO_FLG_DELEGATE_INVOKE | CORINFO_FLG_FINAL)) == (CORINFO_FLG_DELEGATE_INVOKE | CORINFO_FLG_FINAL)); GenTree* thisArgNode; - if (call->IsTailCallViaHelper()) + if (call->IsTailCallViaJitHelper()) { -#ifdef TARGET_X86 // x86 tailcall via helper follows normal calling convention, but with extra stack args. - const unsigned argNum = 0; -#else // !TARGET_X86 - // In case of helper dispatched tail calls, "thisptr" will be the third arg. - // The first two args are: real call target and addr of args copy routine. - const unsigned argNum = 2; -#endif // !TARGET_X86 - + const unsigned argNum = 0; fgArgTabEntry* thisArgTabEntry = comp->gtArgEntryByArgNum(call, argNum); thisArgNode = thisArgTabEntry->GetNode(); } @@ -3192,8 +3562,7 @@ GenTree* Lowering::LowerDelegateInvoke(GenTreeCall* call) unsigned lclNum; -#ifdef TARGET_X86 - if (call->IsTailCallViaHelper() && originalThisExpr->IsLocal()) + if (call->IsTailCallViaJitHelper() && originalThisExpr->IsLocal()) { // For ordering purposes for the special tailcall arguments on x86, we forced the // 'this' pointer in this case to a local in Compiler::fgMorphTailCall(). @@ -3204,7 +3573,6 @@ GenTree* Lowering::LowerDelegateInvoke(GenTreeCall* call) lclNum = originalThisExpr->AsLclVarCommon()->GetLclNum(); } else -#endif // TARGET_X86 { unsigned delegateInvokeTmp = comp->lvaGrabTemp(true DEBUGARG("delegate invoke call")); @@ -3971,25 +4339,10 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call) { noway_assert(call->gtCallType == CT_USER_FUNC); - // If this is a tail call via helper, thisPtr will be the third argument. - int thisPtrArgNum; - regNumber thisPtrArgReg; - -#ifndef TARGET_X86 // x86 tailcall via helper follows normal calling convention, but with extra stack args. - if (call->IsTailCallViaHelper()) - { - thisPtrArgNum = 2; - thisPtrArgReg = REG_ARG_2; - } - else -#endif // !TARGET_X86 - { - thisPtrArgNum = 0; - thisPtrArgReg = comp->codeGen->genGetThisArgReg(call); - } + regNumber thisPtrArgReg = comp->codeGen->genGetThisArgReg(call); // get a reference to the thisPtr being passed - fgArgTabEntry* argEntry = comp->gtArgEntryByArgNum(call, thisPtrArgNum); + fgArgTabEntry* argEntry = comp->gtArgEntryByArgNum(call, 0); assert(argEntry->GetRegNum() == thisPtrArgReg); assert(argEntry->GetNode()->OperIs(GT_PUTARG_REG)); GenTree* thisPtr = argEntry->GetNode()->AsUnOp()->gtGetOp1(); @@ -4132,24 +4485,6 @@ GenTree* Lowering::LowerVirtualStubCall(GenTreeCall* call) GenTree* result = nullptr; -#ifdef TARGET_64BIT - // Non-tail calls: Jump Stubs are not taken into account by VM for mapping an AV into a NullRef - // exception. Therefore, JIT needs to emit an explicit null check. Note that Jit64 too generates - // an explicit null check. - // - // Tail calls: fgMorphTailCall() materializes null check explicitly and hence no need to emit - // null check. - - // Non-64-bit: No need to null check the this pointer - the dispatch code will deal with this. - // The VM considers exceptions that occur in stubs on 64-bit to be not managed exceptions and - // it would be difficult to change this in a way so that it affects only the right stubs. - - if (!call->IsTailCallViaHelper()) - { - call->gtFlags |= GTF_CALL_NULLCHECK; - } -#endif - // This is code to set up an indirect call to a stub address computed // via dictionary lookup. if (call->gtCallType == CT_INDIRECT) @@ -4188,19 +4523,30 @@ GenTree* Lowering::LowerVirtualStubCall(GenTreeCall* call) // accessed via an indirection. GenTree* addr = AddrGen(stubAddr); -#ifdef TARGET_X86 // On x86, for tailcall via helper, the JIT_TailCall helper takes the stubAddr as // the target address, and we set a flag that it's a VSD call. The helper then // handles any necessary indirection. - if (call->IsTailCallViaHelper()) + if (call->IsTailCallViaJitHelper()) { result = addr; } -#endif // TARGET_X86 - - if (result == nullptr) + else { - result = Ind(addr); + + bool shouldOptimizeVirtualStubCall = false; +#if defined(FEATURE_READYTORUN_COMPILER) && defined(TARGET_ARMARCH) + // Skip inserting the indirection node to load the address that is already + // computed in REG_R2R_INDIRECT_PARAM as a hidden parameter. Instead during the + // codegen, just load the call target from REG_R2R_INDIRECT_PARAM. + // However, for tail calls, the call target is always computed in RBM_FASTTAILCALL_TARGET + // and so do not optimize virtual stub calls for such cases. + shouldOptimizeVirtualStubCall = !call->IsTailCall(); +#endif // FEATURE_READYTORUN_COMPILER && TARGET_ARMARCH + + if (!shouldOptimizeVirtualStubCall) + { + result = Ind(addr); + } } } @@ -5378,6 +5724,7 @@ void Lowering::CheckNode(Compiler* compiler, GenTree* node) #ifdef FEATURE_SIMD case GT_SIMD: + case GT_HWINTRINSIC: assert(node->TypeGet() != TYP_SIMD12); break; #ifdef TARGET_64BIT diff --git a/src/coreclr/src/jit/lower.h b/src/coreclr/src/jit/lower.h index 838b86e74f4c49..0582cfe61e5d67 100644 --- a/src/coreclr/src/jit/lower.h +++ b/src/coreclr/src/jit/lower.h @@ -92,7 +92,7 @@ class Lowering final : public Phase void ContainCheckStoreIndir(GenTreeIndir* indirNode); void ContainCheckMul(GenTreeOp* node); void ContainCheckShiftRotate(GenTreeOp* node); - void ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc); + void ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc) const; void ContainCheckCast(GenTreeCast* node); void ContainCheckCompare(GenTreeOp* node); void ContainCheckBinary(GenTreeOp* node); @@ -132,11 +132,19 @@ class Lowering final : public Phase GenTreeCC* LowerNodeCC(GenTree* node, GenCondition condition); void LowerJmpMethod(GenTree* jmp); void LowerRet(GenTreeUnOp* ret); + void LowerStoreLocCommon(GenTreeLclVarCommon* lclVar); + void LowerRetStruct(GenTreeUnOp* ret); + void LowerRetStructLclVar(GenTreeUnOp* ret); + void LowerCallStruct(GenTreeCall* call); + void LowerStoreCallStruct(GenTreeBlk* store); +#if !defined(WINDOWS_AMD64_ABI) + GenTreeLclVar* SpillStructCallResult(GenTreeCall* call) const; +#endif // WINDOWS_AMD64_ABI GenTree* LowerDelegateInvoke(GenTreeCall* call); GenTree* LowerIndirectNonvirtCall(GenTreeCall* call); GenTree* LowerDirectCall(GenTreeCall* call); GenTree* LowerNonvirtPinvokeCall(GenTreeCall* call); - GenTree* LowerTailCallViaHelper(GenTreeCall* callNode, GenTree* callTarget); + GenTree* LowerTailCallViaJitHelper(GenTreeCall* callNode, GenTree* callTarget); void LowerFastTailCall(GenTreeCall* callNode); void RehomeArgForFastTailCall(unsigned int lclNum, GenTree* insertTempBefore, @@ -310,9 +318,177 @@ class Lowering final : public Phase #ifdef FEATURE_HW_INTRINSICS void LowerHWIntrinsic(GenTreeHWIntrinsic* node); void LowerHWIntrinsicCC(GenTreeHWIntrinsic* node, NamedIntrinsic newIntrinsicId, GenCondition condition); + void LowerHWIntrinsicCmpOp(GenTreeHWIntrinsic* node, genTreeOps cmpOp); + void LowerHWIntrinsicCreate(GenTreeHWIntrinsic* node); void LowerFusedMultiplyAdd(GenTreeHWIntrinsic* node); + +#ifdef TARGET_ARM64 + bool IsValidConstForMovImm(GenTreeHWIntrinsic* node); +#endif // TARGET_ARM64 + + union VectorConstant { + int8_t i8[32]; + uint8_t u8[32]; + int16_t i16[16]; + uint16_t u16[16]; + int32_t i32[8]; + uint32_t u32[8]; + int64_t i64[4]; + uint64_t u64[4]; + float f32[8]; + double f64[4]; + }; + + //---------------------------------------------------------------------------------------------- + // ProcessArgForHWIntrinsicCreate: Processes an argument for the Lowering::LowerHWIntrinsicCreate method + // + // Arguments: + // arg - The argument to process + // argIdx - The index of the argument being processed + // vecCns - The vector constant being constructed + // baseType - The base type of the vector constant + // + // Returns: + // true if arg was a constant; otherwise, false + static bool HandleArgForHWIntrinsicCreate(GenTree* arg, int argIdx, VectorConstant& vecCns, var_types baseType) + { + switch (baseType) + { + case TYP_BYTE: + case TYP_UBYTE: + { + if (arg->IsCnsIntOrI()) + { + vecCns.i8[argIdx] = static_cast(arg->AsIntCon()->gtIconVal); + return true; + } + else + { + // We expect the VectorConstant to have been already zeroed + assert(vecCns.i8[argIdx] == 0); + } + break; + } + + case TYP_SHORT: + case TYP_USHORT: + { + if (arg->IsCnsIntOrI()) + { + vecCns.i16[argIdx] = static_cast(arg->AsIntCon()->gtIconVal); + return true; + } + else + { + // We expect the VectorConstant to have been already zeroed + assert(vecCns.i16[argIdx] == 0); + } + break; + } + + case TYP_INT: + case TYP_UINT: + { + if (arg->IsCnsIntOrI()) + { + vecCns.i32[argIdx] = static_cast(arg->AsIntCon()->gtIconVal); + return true; + } + else + { + // We expect the VectorConstant to have been already zeroed + assert(vecCns.i32[argIdx] == 0); + } + break; + } + + case TYP_LONG: + case TYP_ULONG: + { + if (arg->OperIs(GT_CNS_LNG)) + { + vecCns.i64[argIdx] = static_cast(arg->AsLngCon()->gtLconVal); + return true; + } + else + { + // We expect the VectorConstant to have been already zeroed + assert(vecCns.i64[argIdx] == 0); + } + break; + } + + case TYP_FLOAT: + { + if (arg->IsCnsFltOrDbl()) + { + vecCns.f32[argIdx] = static_cast(arg->AsDblCon()->gtDconVal); + return true; + } + else + { + // We expect the VectorConstant to have been already zeroed + // We check against the i32, rather than f32, to account for -0.0 + assert(vecCns.i32[argIdx] == 0); + } + break; + } + + case TYP_DOUBLE: + { + if (arg->IsCnsFltOrDbl()) + { + vecCns.f64[argIdx] = static_cast(arg->AsDblCon()->gtDconVal); + return true; + } + else + { + // We expect the VectorConstant to have been already zeroed + // We check against the i64, rather than f64, to account for -0.0 + assert(vecCns.i64[argIdx] == 0); + } + break; + } + + default: + { + unreached(); + } + } + + return false; + } #endif // FEATURE_HW_INTRINSICS + //---------------------------------------------------------------------------------------------- + // TryRemoveCastIfPresent: Removes op it is a cast operation and the size of its input is at + // least the size of expectedType + // + // Arguments: + // expectedType - The expected type of the cast operation input if it is to be removed + // op - The tree to remove if it is a cast op whose input is at least the size of expectedType + // + // Returns: + // op if it was not a cast node or if its input is not at least the size of expected type; + // Otherwise, it returns the underlying operation that was being casted + GenTree* TryRemoveCastIfPresent(var_types expectedType, GenTree* op) + { + if (!op->OperIs(GT_CAST)) + { + return op; + } + + GenTree* castOp = op->AsCast()->CastOp(); + + if (genTypeSize(castOp->gtType) >= genTypeSize(expectedType)) + { + BlockRange().Remove(op); + return castOp; + } + + return op; + } + // Utility functions public: static bool IndirsAreEquivalent(GenTree* pTreeA, GenTree* pTreeB); @@ -320,7 +496,7 @@ class Lowering final : public Phase // return true if 'childNode' is an immediate that can be contained // by the 'parentNode' (i.e. folded into an instruction) // for example small enough and non-relocatable - bool IsContainableImmed(GenTree* parentNode, GenTree* childNode); + bool IsContainableImmed(GenTree* parentNode, GenTree* childNode) const; // Return true if 'node' is a containable memory op. bool IsContainableMemoryOp(GenTree* node) @@ -339,7 +515,7 @@ class Lowering final : public Phase bool AreSourcesPossiblyModifiedLocals(GenTree* addr, GenTree* base, GenTree* index); // Makes 'childNode' contained in the 'parentNode' - void MakeSrcContained(GenTree* parentNode, GenTree* childNode); + void MakeSrcContained(GenTree* parentNode, GenTree* childNode) const; // Checks and makes 'childNode' contained in the 'parentNode' bool CheckImmedAndMakeContained(GenTree* parentNode, GenTree* childNode); diff --git a/src/coreclr/src/jit/lowerarmarch.cpp b/src/coreclr/src/jit/lowerarmarch.cpp index 2f3004a43ad933..c3ac6513e9546c 100644 --- a/src/coreclr/src/jit/lowerarmarch.cpp +++ b/src/coreclr/src/jit/lowerarmarch.cpp @@ -52,7 +52,7 @@ bool Lowering::IsCallTargetInRange(void* addr) // TODO-CQ: we can contain a floating point 0.0 constant in a compare instruction // (vcmp on arm, fcmp on arm64). // -bool Lowering::IsContainableImmed(GenTree* parentNode, GenTree* childNode) +bool Lowering::IsContainableImmed(GenTree* parentNode, GenTree* childNode) const { if (!varTypeIsFloating(parentNode->TypeGet())) { @@ -526,8 +526,493 @@ void Lowering::LowerSIMD(GenTreeSIMD* simdNode) // void Lowering::LowerHWIntrinsic(GenTreeHWIntrinsic* node) { + assert(node->TypeGet() != TYP_SIMD32); + + if (node->TypeGet() == TYP_SIMD12) + { + // GT_HWINTRINSIC node requiring to produce TYP_SIMD12 in fact + // produces a TYP_SIMD16 result + node->gtType = TYP_SIMD16; + } + + NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; + + switch (intrinsicId) + { + case NI_Vector64_Create: + case NI_Vector128_Create: + { + // We don't directly support the Vector64.Create or Vector128.Create methods in codegen + // and instead lower them to other intrinsic nodes in LowerHWIntrinsicCreate so we expect + // that the node is modified to either not be a HWIntrinsic node or that it is no longer + // the same intrinsic as when it came in. + + LowerHWIntrinsicCreate(node); + assert(!node->OperIsHWIntrinsic() || (node->gtHWIntrinsicId != intrinsicId)); + LowerNode(node); + return; + } + + case NI_Vector64_op_Equality: + case NI_Vector128_op_Equality: + { + LowerHWIntrinsicCmpOp(node, GT_EQ); + return; + } + + case NI_Vector64_op_Inequality: + case NI_Vector128_op_Inequality: + { + LowerHWIntrinsicCmpOp(node, GT_NE); + return; + } + + default: + break; + } + ContainCheckHWIntrinsic(node); } + +//---------------------------------------------------------------------------------------------- +// Lowering::IsValidConstForMovImm: Determines if the given node can be replaced by a mov/fmov immediate instruction +// +// Arguments: +// node - The hardware intrinsic node. +// +// Returns: +// true if the node can be replaced by a mov/fmov immediate instruction; otherwise, false +// +// IMPORTANT: +// This check may end up modifying node->gtOp1 if it is a cast node that can be removed +bool Lowering::IsValidConstForMovImm(GenTreeHWIntrinsic* node) +{ + assert((node->gtHWIntrinsicId == NI_Vector64_Create) || (node->gtHWIntrinsicId == NI_Vector128_Create) || + (node->gtHWIntrinsicId == NI_Vector64_CreateScalarUnsafe) || + (node->gtHWIntrinsicId == NI_Vector128_CreateScalarUnsafe) || + (node->gtHWIntrinsicId == NI_AdvSimd_DuplicateToVector64) || + (node->gtHWIntrinsicId == NI_AdvSimd_DuplicateToVector128) || + (node->gtHWIntrinsicId == NI_AdvSimd_Arm64_DuplicateToVector64) || + (node->gtHWIntrinsicId == NI_AdvSimd_Arm64_DuplicateToVector128)); + assert(HWIntrinsicInfo::lookupNumArgs(node) == 1); + + GenTree* op1 = node->gtOp1; + GenTree* castOp = nullptr; + + if (varTypeIsIntegral(node->gtSIMDBaseType) && op1->OperIs(GT_CAST)) + { + // We will sometimes get a cast around a constant value (such as for + // certain long constants) which would block the below containment. + // So we will temporarily check what the cast is from instead so we + // can catch those cases as well. + + castOp = op1->AsCast()->CastOp(); + op1 = castOp; + } + + if (op1->IsCnsIntOrI()) + { + const ssize_t dataValue = op1->AsIntCon()->gtIconVal; + + if (comp->GetEmitter()->emitIns_valid_imm_for_movi(dataValue, emitActualTypeSize(node->gtSIMDBaseType))) + { + if (castOp != nullptr) + { + // We found a containable immediate under + // a cast, so remove the cast from the LIR. + + BlockRange().Remove(node->gtOp1); + node->gtOp1 = op1; + } + return true; + } + } + else if (op1->IsCnsFltOrDbl()) + { + assert(varTypeIsFloating(node->gtSIMDBaseType)); + assert(castOp == nullptr); + + const double dataValue = op1->AsDblCon()->gtDconVal; + return comp->GetEmitter()->emitIns_valid_imm_for_fmov(dataValue); + } + + return false; +} + +//---------------------------------------------------------------------------------------------- +// Lowering::LowerHWIntrinsicCmpOp: Lowers a Vector128 or Vector256 comparison intrinsic +// +// Arguments: +// node - The hardware intrinsic node. +// cmpOp - The comparison operation, currently must be GT_EQ or GT_NE +// +void Lowering::LowerHWIntrinsicCmpOp(GenTreeHWIntrinsic* node, genTreeOps cmpOp) +{ + NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; + var_types baseType = node->gtSIMDBaseType; + unsigned simdSize = node->gtSIMDSize; + var_types simdType = Compiler::getSIMDTypeForSize(simdSize); + + assert((intrinsicId == NI_Vector64_op_Equality) || (intrinsicId == NI_Vector64_op_Inequality) || + (intrinsicId == NI_Vector128_op_Equality) || (intrinsicId == NI_Vector128_op_Inequality)); + + assert(varTypeIsSIMD(simdType)); + assert(varTypeIsArithmetic(baseType)); + assert(simdSize != 0); + assert(node->gtType == TYP_BOOL); + assert((cmpOp == GT_EQ) || (cmpOp == GT_NE)); + + // We have the following (with the appropriate simd size and where the intrinsic could be op_Inequality): + // /--* op2 simd + // /--* op1 simd + // node = * HWINTRINSIC simd T op_Equality + + GenTree* op1 = node->gtGetOp1(); + GenTree* op2 = node->gtGetOp2(); + + NamedIntrinsic cmpIntrinsic; + + switch (baseType) + { + case TYP_BYTE: + case TYP_UBYTE: + case TYP_SHORT: + case TYP_USHORT: + case TYP_INT: + case TYP_UINT: + case TYP_FLOAT: + { + cmpIntrinsic = NI_AdvSimd_CompareEqual; + break; + } + + case TYP_LONG: + case TYP_ULONG: + case TYP_DOUBLE: + { + cmpIntrinsic = NI_AdvSimd_Arm64_CompareEqual; + break; + } + + default: + { + unreached(); + } + } + + GenTree* cmp = comp->gtNewSimdHWIntrinsicNode(simdType, op1, op2, cmpIntrinsic, baseType, simdSize); + BlockRange().InsertBefore(node, cmp); + LowerNode(cmp); + + if ((baseType == TYP_FLOAT) && (simdSize == 12)) + { + // For TYP_SIMD12 we don't want the upper bits to participate in the comparison. So, we will insert all ones + // into those bits of the result, "as if" the upper bits are equal. Then if all lower bits are equal, we get the + // expected all-ones result, and will get the expected 0's only where there are non-matching bits. + + GenTree* idxCns = comp->gtNewIconNode(3, TYP_INT); + BlockRange().InsertAfter(cmp, idxCns); + + GenTree* insCns = comp->gtNewIconNode(-1, TYP_INT); + BlockRange().InsertAfter(idxCns, insCns); + + GenTree* tmp = + comp->gtNewSimdAsHWIntrinsicNode(simdType, cmp, idxCns, insCns, NI_AdvSimd_Insert, TYP_INT, simdSize); + BlockRange().InsertAfter(insCns, tmp); + LowerNode(tmp); + + cmp = tmp; + } + + GenTree* msk = comp->gtNewSimdHWIntrinsicNode(simdType, cmp, NI_AdvSimd_Arm64_MinAcross, TYP_UBYTE, simdSize); + BlockRange().InsertAfter(cmp, msk); + LowerNode(msk); + + GenTree* zroCns = comp->gtNewIconNode(0, TYP_INT); + BlockRange().InsertAfter(msk, zroCns); + + GenTree* val = comp->gtNewSimdAsHWIntrinsicNode(TYP_UBYTE, msk, zroCns, NI_AdvSimd_Extract, TYP_UBYTE, simdSize); + BlockRange().InsertAfter(zroCns, val); + LowerNode(val); + + zroCns = comp->gtNewIconNode(0, TYP_INT); + BlockRange().InsertAfter(val, zroCns); + + node->ChangeOper(cmpOp); + + node->gtType = TYP_INT; + node->gtOp1 = val; + node->gtOp2 = zroCns; + + // The CompareEqual will set (condition is true) or clear (condition is false) all bits of the respective element + // The MinAcross then ensures we get either all bits set (all conditions are true) or clear (any condition is false) + // So, we need to invert the condition from the operation since we compare against zero + + GenCondition cmpCnd = (cmpOp == GT_EQ) ? GenCondition::NE : GenCondition::EQ; + GenTree* cc = LowerNodeCC(node, cmpCnd); + + node->gtType = TYP_VOID; + node->ClearUnusedValue(); + + LowerNode(node); +} + +//---------------------------------------------------------------------------------------------- +// Lowering::LowerHWIntrinsicCreate: Lowers a Vector64 or Vector128 Create call +// +// Arguments: +// node - The hardware intrinsic node. +// +void Lowering::LowerHWIntrinsicCreate(GenTreeHWIntrinsic* node) +{ + NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; + var_types simdType = node->gtType; + var_types baseType = node->gtSIMDBaseType; + unsigned simdSize = node->gtSIMDSize; + VectorConstant vecCns = {}; + + if ((simdSize == 8) && (simdType == TYP_DOUBLE)) + { + simdType = TYP_SIMD8; + } + + assert(varTypeIsSIMD(simdType)); + assert(varTypeIsArithmetic(baseType)); + assert(simdSize != 0); + + GenTreeArgList* argList = nullptr; + GenTree* op1 = node->gtGetOp1(); + GenTree* op2 = node->gtGetOp2(); + + // Spare GenTrees to be used for the lowering logic below + // Defined upfront to avoid naming conflicts, etc... + GenTree* idx = nullptr; + GenTree* tmp1 = nullptr; + GenTree* tmp2 = nullptr; + GenTree* tmp3 = nullptr; + + assert(op1 != nullptr); + + unsigned argCnt = 0; + unsigned cnsArgCnt = 0; + + if (op1->OperIsList()) + { + assert(op2 == nullptr); + + for (argList = op1->AsArgList(); argList != nullptr; argList = argList->Rest()) + { + if (HandleArgForHWIntrinsicCreate(argList->Current(), argCnt, vecCns, baseType)) + { + cnsArgCnt += 1; + } + argCnt += 1; + } + } + else + { + if (HandleArgForHWIntrinsicCreate(op1, argCnt, vecCns, baseType)) + { + cnsArgCnt += 1; + } + argCnt += 1; + + if (op2 != nullptr) + { + if (HandleArgForHWIntrinsicCreate(op2, argCnt, vecCns, baseType)) + { + cnsArgCnt += 1; + } + argCnt += 1; + } + else if (cnsArgCnt == 1) + { + // These intrinsics are meant to set the same value to every element + // so we'll just specially handle it here and copy it into the remaining + // indices. + + for (unsigned i = 1; i < simdSize / genTypeSize(baseType); i++) + { + HandleArgForHWIntrinsicCreate(op1, i, vecCns, baseType); + } + } + } + assert((argCnt == 1) || (argCnt == (simdSize / genTypeSize(baseType)))); + + if ((argCnt == cnsArgCnt) && (argCnt == 1)) + { + GenTree* castOp = nullptr; + + if (varTypeIsIntegral(baseType) && op1->OperIs(GT_CAST)) + { + // We will sometimes get a cast around a constant value (such as for + // certain long constants) which would block the below containment. + // So we will temporarily check what the cast is from instead so we + // can catch those cases as well. + + castOp = op1->AsCast()->CastOp(); + op1 = castOp; + } + + if (IsValidConstForMovImm(node)) + { + // Set the cnsArgCnt to zero so we get lowered to a DuplicateToVector + // intrinsic, which will itself mark the node as contained. + cnsArgCnt = 0; + + // Reacquire op1 as the above check may have removed a cast node and + // changed op1. + op1 = node->gtOp1; + } + } + + if (argCnt == cnsArgCnt) + { + if (op1->OperIsList()) + { + for (argList = op1->AsArgList(); argList != nullptr; argList = argList->Rest()) + { + BlockRange().Remove(argList->Current()); + } + } + else + { + BlockRange().Remove(op1); + + if (op2 != nullptr) + { + BlockRange().Remove(op2); + } + } + + assert((simdSize == 8) || (simdSize == 16)); + + UNATIVE_OFFSET cnsSize = simdSize; + UNATIVE_OFFSET cnsAlign = cnsSize; + + CORINFO_FIELD_HANDLE hnd = comp->GetEmitter()->emitAnyConst(&vecCns, cnsSize, cnsAlign); + GenTree* clsVarAddr = new (comp, GT_CLS_VAR_ADDR) GenTreeClsVar(GT_CLS_VAR_ADDR, TYP_I_IMPL, hnd, nullptr); + BlockRange().InsertBefore(node, clsVarAddr); + + node->ChangeOper(GT_IND); + node->gtOp1 = clsVarAddr; + + // TODO-ARM64-CQ: We should be able to modify at least the paths that use Insert to trivially support partial + // vector constants. With this, we can create a constant if say 50% of the inputs are also constant and just + // insert the non-constant values which should still allow some gains. + + return; + } + else if (argCnt == 1) + { + // We have the following (where simd is simd8 or simd16): + // /--* op1 T + // node = * HWINTRINSIC simd T Create + + // We will be constructing the following parts: + // /--* op1 T + // node = * HWINTRINSIC simd T DuplicateToVector + + // This is roughly the following managed code: + // return AdvSimd.Arm64.DuplicateToVector(op1); + + if (varTypeIsLong(baseType) || (baseType == TYP_DOUBLE)) + { + node->gtHWIntrinsicId = + (simdType == TYP_SIMD8) ? NI_AdvSimd_Arm64_DuplicateToVector64 : NI_AdvSimd_Arm64_DuplicateToVector128; + } + else + { + node->gtHWIntrinsicId = + (simdType == TYP_SIMD8) ? NI_AdvSimd_DuplicateToVector64 : NI_AdvSimd_DuplicateToVector128; + } + return; + } + + // We have the following (where simd is simd8 or simd16): + // /--* op1 T + // +--* ... T + // +--* opN T + // node = * HWINTRINSIC simd T Create + + if (op1->OperIsList()) + { + argList = op1->AsArgList(); + op1 = argList->Current(); + argList = argList->Rest(); + } + + // We will be constructing the following parts: + // /--* op1 T + // tmp1 = * HWINTRINSIC simd8 T CreateScalarUnsafe + // ... + + // This is roughly the following managed code: + // var tmp1 = Vector64.CreateScalarUnsafe(op1); + // ... + + NamedIntrinsic createScalarUnsafe = + (simdType == TYP_SIMD8) ? NI_Vector64_CreateScalarUnsafe : NI_Vector128_CreateScalarUnsafe; + + tmp1 = comp->gtNewSimdHWIntrinsicNode(simdType, op1, createScalarUnsafe, baseType, simdSize); + BlockRange().InsertAfter(op1, tmp1); + LowerNode(tmp1); + + unsigned N = 0; + GenTree* opN = nullptr; + + for (N = 1; N < argCnt - 1; N++) + { + // We will be constructing the following parts: + // ... + // idx = CNS_INT int N + // /--* tmp1 simd + // +--* idx int + // +--* opN T + // tmp1 = * HWINTRINSIC simd T Insert + // ... + + // This is roughly the following managed code: + // ... + // tmp1 = AdvSimd.Insert(tmp1, N, opN); + // ... + + opN = argList->Current(); + + idx = comp->gtNewIconNode(N, TYP_INT); + BlockRange().InsertBefore(opN, idx); + + tmp1 = comp->gtNewSimdHWIntrinsicNode(simdType, tmp1, idx, opN, NI_AdvSimd_Insert, baseType, simdSize); + BlockRange().InsertAfter(opN, tmp1); + LowerNode(tmp1); + + argList = argList->Rest(); + } + + assert(N == (argCnt - 1)); + + // We will be constructing the following parts: + // idx = CNS_INT int N + // /--* tmp1 simd + // +--* idx int + // +--* opN T + // node = * HWINTRINSIC simd T Insert + + // This is roughly the following managed code: + // ... + // tmp1 = AdvSimd.Insert(tmp1, N, opN); + // ... + + opN = (argCnt == 2) ? op2 : argList->Current(); + + idx = comp->gtNewIconNode(N, TYP_INT); + BlockRange().InsertBefore(opN, idx); + + node->gtOp1 = comp->gtNewArgList(tmp1, idx, opN); + node->gtOp2 = nullptr; + + node->gtHWIntrinsicId = NI_AdvSimd_Insert; +} #endif // FEATURE_HW_INTRINSICS //------------------------------------------------------------------------ @@ -601,10 +1086,12 @@ void Lowering::ContainCheckIndir(GenTreeIndir* indirNode) } #endif // FEATURE_SIMD - GenTree* addr = indirNode->Addr(); - bool makeContained = true; + GenTree* addr = indirNode->Addr(); + if ((addr->OperGet() == GT_LEA) && IsSafeToContainMem(indirNode, addr)) { + bool makeContained = true; + #ifdef TARGET_ARM // ARM floating-point load/store doesn't support a form similar to integer // ldr Rdst, [Rbase + Roffset] with offset in a register. The only supported @@ -628,12 +1115,23 @@ void Lowering::ContainCheckIndir(GenTreeIndir* indirNode) } } } -#endif +#endif // TARGET_ARM + if (makeContained) { MakeSrcContained(indirNode, addr); } } +#ifdef TARGET_ARM64 + else if (addr->OperGet() == GT_CLS_VAR_ADDR) + { + // These nodes go into an addr mode: + // - GT_CLS_VAR_ADDR turns into a constant. + + // make this contained, it turns into a constant that goes into an addr mode + MakeSrcContained(indirNode, addr); + } +#endif // TARGET_ARM64 } //------------------------------------------------------------------------ @@ -704,7 +1202,7 @@ void Lowering::ContainCheckShiftRotate(GenTreeOp* node) // Arguments: // node - pointer to the node // -void Lowering::ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc) +void Lowering::ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc) const { assert(storeLoc->OperIsLocalStore()); GenTree* op1 = storeLoc->gtGetOp1(); @@ -721,13 +1219,20 @@ void Lowering::ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc) return; } } + + const LclVarDsc* varDsc = comp->lvaGetDesc(storeLoc); + #ifdef FEATURE_SIMD if (varTypeIsSIMD(storeLoc)) { - if (op1->IsIntegralConst(0)) + // If this is a store to memory, we can initialize a zero vector in memory from REG_ZR. + if ((op1->IsIntegralConst(0) || op1->IsSIMDZero()) && varDsc->lvDoNotEnregister) { - // For an InitBlk we want op1 to be contained MakeSrcContained(storeLoc, op1); + if (op1->IsSIMDZero()) + { + MakeSrcContained(op1, op1->gtGetOp1()); + } } return; } @@ -736,8 +1241,7 @@ void Lowering::ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc) // If the source is a containable immediate, make it contained, unless it is // an int-size or larger store of zero to memory, because we can generate smaller code // by zeroing a register and then storing it. - const LclVarDsc* varDsc = comp->lvaGetDesc(storeLoc); - var_types type = varDsc->GetRegisterType(storeLoc); + var_types type = varDsc->GetRegisterType(storeLoc); if (IsContainableImmed(storeLoc, op1) && (!op1->IsIntegralConst(0) || varTypeIsSmall(type))) { MakeSrcContained(storeLoc, op1); @@ -824,11 +1328,6 @@ void Lowering::ContainCheckSIMD(GenTreeSIMD* simdNode) CheckImmedAndMakeContained(simdNode, simdNode->gtGetOp2()); break; - case SIMDIntrinsicOpEquality: - case SIMDIntrinsicOpInEquality: - // TODO-ARM64-CQ Support containing 0 - break; - case SIMDIntrinsicGetItem: { // This implements get_Item method. The sources are: @@ -862,6 +1361,7 @@ void Lowering::ContainCheckSIMD(GenTreeSIMD* simdNode) #endif // FEATURE_SIMD #ifdef FEATURE_HW_INTRINSICS + //---------------------------------------------------------------------------------------------- // ContainCheckHWIntrinsic: Perform containment analysis for a hardware intrinsic node. // @@ -870,20 +1370,123 @@ void Lowering::ContainCheckSIMD(GenTreeSIMD* simdNode) // void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) { - NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; - HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsicId); - int numArgs = HWIntrinsicInfo::lookupNumArgs(node); - var_types baseType = node->gtSIMDBaseType; - - GenTree* op1 = node->gtGetOp1(); - GenTree* op2 = node->gtGetOp2(); - GenTree* op3 = nullptr; + const HWIntrinsic intrin(node); - if (!HWIntrinsicInfo::SupportsContainment(intrinsicId)) + if (!HWIntrinsicInfo::SupportsContainment(intrin.id)) { // Exit early if containment isn't supported return; } + + switch (intrin.id) + { + case NI_AdvSimd_DuplicateSelectedScalarToVector64: + case NI_AdvSimd_DuplicateSelectedScalarToVector128: + case NI_AdvSimd_Extract: + case NI_AdvSimd_ShiftLeftLogical: + case NI_AdvSimd_ShiftLeftLogicalSaturate: + case NI_AdvSimd_ShiftLeftLogicalSaturateScalar: + case NI_AdvSimd_ShiftLeftLogicalSaturateUnsigned: + case NI_AdvSimd_ShiftLeftLogicalSaturateUnsignedScalar: + case NI_AdvSimd_ShiftLeftLogicalScalar: + case NI_AdvSimd_ShiftLeftLogicalWideningLower: + case NI_AdvSimd_ShiftLeftLogicalWideningUpper: + case NI_AdvSimd_ShiftRightArithmetic: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateUnsignedLower: + case NI_AdvSimd_ShiftRightArithmeticRounded: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower: + case NI_AdvSimd_ShiftRightArithmeticRoundedScalar: + case NI_AdvSimd_ShiftRightArithmeticScalar: + case NI_AdvSimd_ShiftRightLogical: + case NI_AdvSimd_ShiftRightLogicalNarrowingLower: + case NI_AdvSimd_ShiftRightLogicalNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightLogicalRounded: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingLower: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightLogicalRoundedScalar: + case NI_AdvSimd_ShiftRightLogicalScalar: + case NI_AdvSimd_Arm64_DuplicateSelectedScalarToVector128: + case NI_AdvSimd_Arm64_ShiftLeftLogicalSaturateScalar: + case NI_AdvSimd_Arm64_ShiftLeftLogicalSaturateUnsignedScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticNarrowingSaturateScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticNarrowingSaturateUnsignedScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticRoundedNarrowingSaturateScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar: + case NI_AdvSimd_Arm64_ShiftRightLogicalNarrowingSaturateScalar: + case NI_AdvSimd_Arm64_ShiftRightLogicalRoundedNarrowingSaturateScalar: + case NI_Vector64_GetElement: + case NI_Vector128_GetElement: + if (intrin.op2->IsCnsIntOrI()) + { + MakeSrcContained(node, intrin.op2); + } + break; + + case NI_AdvSimd_ExtractVector64: + case NI_AdvSimd_ExtractVector128: + case NI_AdvSimd_ShiftRightArithmeticAdd: + case NI_AdvSimd_ShiftRightArithmeticAddScalar: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateUnsignedUpper: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightArithmeticRoundedAdd: + case NI_AdvSimd_ShiftRightArithmeticRoundedAddScalar: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightLogicalAdd: + case NI_AdvSimd_ShiftRightLogicalAddScalar: + case NI_AdvSimd_ShiftRightLogicalNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightLogicalNarrowingUpper: + case NI_AdvSimd_ShiftRightLogicalRoundedAdd: + case NI_AdvSimd_ShiftRightLogicalRoundedAddScalar: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingUpper: + if (intrin.op3->IsCnsIntOrI()) + { + MakeSrcContained(node, intrin.op3); + } + break; + + case NI_AdvSimd_Insert: + if (intrin.op2->IsCnsIntOrI()) + { + MakeSrcContained(node, intrin.op2); + + if ((intrin.op2->AsIntCon()->gtIconVal == 0) && intrin.op3->IsCnsFltOrDbl()) + { + assert(varTypeIsFloating(intrin.baseType)); + + const double dataValue = intrin.op3->AsDblCon()->gtDconVal; + + if (comp->GetEmitter()->emitIns_valid_imm_for_fmov(dataValue)) + { + MakeSrcContained(node, intrin.op3); + } + } + } + break; + + case NI_Vector64_CreateScalarUnsafe: + case NI_Vector128_CreateScalarUnsafe: + case NI_AdvSimd_DuplicateToVector64: + case NI_AdvSimd_DuplicateToVector128: + case NI_AdvSimd_Arm64_DuplicateToVector64: + case NI_AdvSimd_Arm64_DuplicateToVector128: + { + if (IsValidConstForMovImm(node)) + { + // Use node->gtOp1 as the above check may + // have removed a cast node and changed op1 + + MakeSrcContained(node, node->gtOp1); + } + break; + } + + default: + unreached(); + } } #endif // FEATURE_HW_INTRINSICS diff --git a/src/coreclr/src/jit/lowerxarch.cpp b/src/coreclr/src/jit/lowerxarch.cpp index 92e9965f17c818..52a4de5a1c2e4e 100644 --- a/src/coreclr/src/jit/lowerxarch.cpp +++ b/src/coreclr/src/jit/lowerxarch.cpp @@ -712,8 +712,12 @@ void Lowering::LowerSIMD(GenTreeSIMD* simdNode) BlockRange().Remove(list->Current()); } - CORINFO_FIELD_HANDLE hnd = - comp->GetEmitter()->emitAnyConst(constArgValues, sizeof(constArgValues), emitDataAlignment::Required); + assert(sizeof(constArgValues) == 16); + + UNATIVE_OFFSET cnsSize = sizeof(constArgValues); + UNATIVE_OFFSET cnsAlign = (comp->compCodeOpt() != Compiler::SMALL_CODE) ? cnsSize : 1; + + CORINFO_FIELD_HANDLE hnd = comp->GetEmitter()->emitAnyConst(constArgValues, cnsSize, cnsAlign); GenTree* clsVarAddr = new (comp, GT_CLS_VAR_ADDR) GenTreeClsVar(GT_CLS_VAR_ADDR, TYP_I_IMPL, hnd, nullptr); BlockRange().InsertBefore(simdNode, clsVarAddr); simdNode->ChangeOper(GT_IND); @@ -743,14 +747,6 @@ void Lowering::LowerSIMD(GenTreeSIMD* simdNode) // the addr of SIMD vector with the given index. simdNode->gtOp1->gtFlags |= GTF_IND_REQ_ADDR_IN_REG; } - else if (simdNode->IsSIMDEqualityOrInequality()) - { - LowerNodeCC(simdNode, - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpEquality ? GenCondition::EQ : GenCondition::NE); - - simdNode->gtType = TYP_VOID; - simdNode->ClearUnusedValue(); - } #endif ContainCheckSIMD(simdNode); } @@ -920,8 +916,123 @@ void Lowering::LowerFusedMultiplyAdd(GenTreeHWIntrinsic* node) // void Lowering::LowerHWIntrinsic(GenTreeHWIntrinsic* node) { - switch (node->gtHWIntrinsicId) + if (node->TypeGet() == TYP_SIMD12) + { + // GT_HWINTRINSIC node requiring to produce TYP_SIMD12 in fact + // produces a TYP_SIMD16 result + node->gtType = TYP_SIMD16; + } + + NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; + + switch (intrinsicId) { + case NI_Vector128_Create: + case NI_Vector256_Create: + { + // We don't directly support the Vector128.Create or Vector256.Create methods in codegen + // and instead lower them to other intrinsic nodes in LowerHWIntrinsicCreate so we expect + // that the node is modified to either not be a HWIntrinsic node or that it is no longer + // the same intrinsic as when it came in. In the case of Vector256.Create, we may lower + // it into 2x Vector128.Create intrinsics which themselves are also lowered into other + // intrinsics that are not Vector*.Create + + LowerHWIntrinsicCreate(node); + assert(!node->OperIsHWIntrinsic() || (node->gtHWIntrinsicId != intrinsicId)); + LowerNode(node); + return; + } + + case NI_Vector128_op_Equality: + case NI_Vector256_op_Equality: + { + LowerHWIntrinsicCmpOp(node, GT_EQ); + return; + } + + case NI_Vector128_op_Inequality: + case NI_Vector256_op_Inequality: + { + LowerHWIntrinsicCmpOp(node, GT_NE); + return; + } + + case NI_SSE2_Insert: + case NI_SSE41_Insert: + case NI_SSE41_X64_Insert: + { + assert(HWIntrinsicInfo::lookupNumArgs(node) == 3); + + GenTreeArgList* argList = node->gtOp1->AsArgList(); + + // Insert takes either a 32-bit register or a memory operand. + // In either case, only gtSIMDBaseType bits are read and so + // widening or narrowing the operand may be unnecessary and it + // can just be used directly. + + argList->Rest()->gtOp1 = TryRemoveCastIfPresent(node->gtSIMDBaseType, argList->Rest()->gtOp1); + break; + } + + case NI_SSE42_Crc32: + { + assert(HWIntrinsicInfo::lookupNumArgs(node) == 2); + + // Crc32 takes either a bit register or a memory operand. + // In either case, only gtType bits are read and so widening + // or narrowing the operand may be unnecessary and it can + // just be used directly. + + node->gtOp2 = TryRemoveCastIfPresent(node->gtType, node->gtOp2); + break; + } + + case NI_SSE2_CompareGreaterThan: + { + if (node->gtSIMDBaseType != TYP_DOUBLE) + { + assert(varTypeIsIntegral(node->gtSIMDBaseType)); + break; + } + + __fallthrough; + } + + case NI_SSE_CompareGreaterThan: + case NI_SSE_CompareGreaterThanOrEqual: + case NI_SSE_CompareNotGreaterThan: + case NI_SSE_CompareNotGreaterThanOrEqual: + case NI_SSE2_CompareGreaterThanOrEqual: + case NI_SSE2_CompareNotGreaterThan: + case NI_SSE2_CompareNotGreaterThanOrEqual: + { + assert((node->gtSIMDBaseType == TYP_FLOAT) || (node->gtSIMDBaseType == TYP_DOUBLE)); + + if (comp->compOpportunisticallyDependsOn(InstructionSet_AVX)) + { + break; + } + + // pre-AVX doesn't actually support these intrinsics in hardware so we need to swap the operands around + std::swap(node->gtOp1, node->gtOp2); + break; + } + + case NI_SSE2_CompareLessThan: + case NI_SSE42_CompareLessThan: + case NI_AVX2_CompareLessThan: + { + if (node->gtSIMDBaseType == TYP_DOUBLE) + { + break; + } + assert(varTypeIsIntegral(node->gtSIMDBaseType)); + + // this isn't actually supported in hardware so we need to swap the operands around + std::swap(node->gtOp1, node->gtOp2); + break; + } + case NI_SSE_CompareScalarOrderedEqual: LowerHWIntrinsicCC(node, NI_SSE_COMISS, GenCondition::FEQ); break; @@ -1028,6 +1139,1318 @@ void Lowering::LowerHWIntrinsic(GenTreeHWIntrinsic* node) ContainCheckHWIntrinsic(node); } + +//---------------------------------------------------------------------------------------------- +// Lowering::LowerHWIntrinsicCmpOp: Lowers a Vector128 or Vector256 comparison intrinsic +// +// Arguments: +// node - The hardware intrinsic node. +// cmpOp - The comparison operation, currently must be GT_EQ or GT_NE +// +void Lowering::LowerHWIntrinsicCmpOp(GenTreeHWIntrinsic* node, genTreeOps cmpOp) +{ + NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; + var_types baseType = node->gtSIMDBaseType; + unsigned simdSize = node->gtSIMDSize; + var_types simdType = Compiler::getSIMDTypeForSize(simdSize); + + assert((intrinsicId == NI_Vector128_op_Equality) || (intrinsicId == NI_Vector128_op_Inequality) || + (intrinsicId == NI_Vector256_op_Equality) || (intrinsicId == NI_Vector256_op_Inequality)); + + assert(varTypeIsSIMD(simdType)); + assert(varTypeIsArithmetic(baseType)); + assert(simdSize != 0); + assert(node->gtType == TYP_BOOL); + assert((cmpOp == GT_EQ) || (cmpOp == GT_NE)); + + // We have the following (with the appropriate simd size and where the intrinsic could be op_Inequality): + // /--* op2 simd + // /--* op1 simd + // node = * HWINTRINSIC simd T op_Equality + + GenTree* op1 = node->gtGetOp1(); + GenTree* op2 = node->gtGetOp2(); + + GenCondition cmpCnd = (cmpOp == GT_EQ) ? GenCondition::EQ : GenCondition::NE; + + if (op2->IsIntegralConstVector(0) && comp->compOpportunisticallyDependsOn(InstructionSet_SSE41)) + { + // On SSE4.1 or higher we can optimize comparisons against zero to + // just use PTEST. We can't support it for floating-point, however, + // as it has both +0.0 and -0.0 where +0.0 == -0.0 + + node->gtOp1 = op1; + BlockRange().Remove(op2); + + LIR::Use op1Use(BlockRange(), &node->gtOp1, node); + ReplaceWithLclVar(op1Use); + op1 = node->gtOp1; + + op2 = comp->gtClone(op1); + BlockRange().InsertAfter(op1, op2); + node->gtOp2 = op2; + + if (simdSize == 32) + { + node->gtHWIntrinsicId = NI_AVX_TestZ; + LowerHWIntrinsicCC(node, NI_AVX_PTEST, cmpCnd); + } + else + { + node->gtHWIntrinsicId = NI_SSE41_TestZ; + LowerHWIntrinsicCC(node, NI_SSE41_PTEST, cmpCnd); + } + + return; + } + + NamedIntrinsic cmpIntrinsic; + var_types cmpType; + NamedIntrinsic mskIntrinsic; + var_types mskType; + int mskConstant; + + switch (baseType) + { + case TYP_BYTE: + case TYP_UBYTE: + case TYP_SHORT: + case TYP_USHORT: + case TYP_INT: + case TYP_UINT: + { + cmpType = baseType; + mskType = TYP_UBYTE; + + if (simdSize == 32) + { + cmpIntrinsic = NI_AVX2_CompareEqual; + mskIntrinsic = NI_AVX2_MoveMask; + mskConstant = -1; + } + else + { + assert(simdSize == 16); + + cmpIntrinsic = NI_SSE2_CompareEqual; + mskIntrinsic = NI_SSE2_MoveMask; + mskConstant = 0xFFFF; + } + break; + } + + case TYP_LONG: + case TYP_ULONG: + { + mskType = TYP_UBYTE; + + if (simdSize == 32) + { + cmpIntrinsic = NI_AVX2_CompareEqual; + cmpType = baseType; + mskIntrinsic = NI_AVX2_MoveMask; + mskConstant = -1; + } + else + { + assert(simdSize == 16); + + if (comp->compOpportunisticallyDependsOn(InstructionSet_SSE41)) + { + cmpIntrinsic = NI_SSE41_CompareEqual; + cmpType = baseType; + } + else + { + cmpIntrinsic = NI_SSE2_CompareEqual; + cmpType = TYP_UINT; + } + + mskIntrinsic = NI_SSE2_MoveMask; + mskConstant = 0xFFFF; + } + break; + } + + case TYP_FLOAT: + { + cmpType = baseType; + mskType = baseType; + + if (simdSize == 32) + { + cmpIntrinsic = NI_AVX_CompareEqual; + mskIntrinsic = NI_AVX_MoveMask; + mskConstant = 0xFF; + } + else + { + cmpIntrinsic = NI_SSE_CompareEqual; + mskIntrinsic = NI_SSE_MoveMask; + + if (simdSize == 16) + { + mskConstant = 0xF; + } + else if (simdSize == 12) + { + mskConstant = 0x7; + } + else + { + assert(simdSize == 8); + mskConstant = 0x3; + } + } + break; + } + + case TYP_DOUBLE: + { + cmpType = baseType; + mskType = baseType; + + if (simdSize == 32) + { + cmpIntrinsic = NI_AVX_CompareEqual; + mskIntrinsic = NI_AVX_MoveMask; + mskConstant = 0xF; + } + else + { + assert(simdSize == 16); + + cmpIntrinsic = NI_SSE2_CompareEqual; + mskIntrinsic = NI_SSE2_MoveMask; + mskConstant = 0x3; + } + break; + } + + default: + { + unreached(); + } + } + + GenTree* cmp = comp->gtNewSimdHWIntrinsicNode(simdType, op1, op2, cmpIntrinsic, cmpType, simdSize); + BlockRange().InsertBefore(node, cmp); + LowerNode(cmp); + + GenTree* msk = comp->gtNewSimdHWIntrinsicNode(TYP_INT, cmp, mskIntrinsic, mskType, simdSize); + BlockRange().InsertAfter(cmp, msk); + LowerNode(msk); + + GenTree* mskCns = comp->gtNewIconNode(mskConstant, TYP_INT); + BlockRange().InsertAfter(msk, mskCns); + + if ((baseType == TYP_FLOAT) && (simdSize < 16)) + { + // For TYP_SIMD8 and TYP_SIMD12 we need to clear the upper bits and can't assume their value + + GenTree* tmp = comp->gtNewOperNode(GT_AND, TYP_INT, msk, mskCns); + BlockRange().InsertAfter(mskCns, tmp); + LowerNode(msk); + + msk = tmp; + + mskCns = comp->gtNewIconNode(mskConstant, TYP_INT); + BlockRange().InsertAfter(msk, mskCns); + } + + node->ChangeOper(cmpOp); + + node->gtType = TYP_INT; + node->gtOp1 = msk; + node->gtOp2 = mskCns; + + GenTree* cc = LowerNodeCC(node, cmpCnd); + + node->gtType = TYP_VOID; + node->ClearUnusedValue(); + + LowerNode(node); +} + +//---------------------------------------------------------------------------------------------- +// Lowering::LowerHWIntrinsicCreate: Lowers a Vector128 or Vector256 Create call +// +// Arguments: +// node - The hardware intrinsic node. +// +void Lowering::LowerHWIntrinsicCreate(GenTreeHWIntrinsic* node) +{ + NamedIntrinsic intrinsicId = node->gtHWIntrinsicId; + var_types simdType = node->gtType; + var_types baseType = node->gtSIMDBaseType; + unsigned simdSize = node->gtSIMDSize; + VectorConstant vecCns = {}; + + assert(varTypeIsSIMD(simdType)); + assert(varTypeIsArithmetic(baseType)); + assert(simdSize != 0); + + GenTreeArgList* argList = nullptr; + GenTree* op1 = node->gtGetOp1(); + GenTree* op2 = node->gtGetOp2(); + + // Spare GenTrees to be used for the lowering logic below + // Defined upfront to avoid naming conflicts, etc... + GenTree* idx = nullptr; + GenTree* tmp1 = nullptr; + GenTree* tmp2 = nullptr; + GenTree* tmp3 = nullptr; + + assert(op1 != nullptr); + + unsigned argCnt = 0; + unsigned cnsArgCnt = 0; + + if (op1->OperIsList()) + { + assert(op2 == nullptr); + + for (argList = op1->AsArgList(); argList != nullptr; argList = argList->Rest()) + { + if (HandleArgForHWIntrinsicCreate(argList->Current(), argCnt, vecCns, baseType)) + { + cnsArgCnt += 1; + } + argCnt += 1; + } + } + else + { + if (HandleArgForHWIntrinsicCreate(op1, argCnt, vecCns, baseType)) + { + cnsArgCnt += 1; + } + argCnt += 1; + + if (op2 != nullptr) + { + if (HandleArgForHWIntrinsicCreate(op2, argCnt, vecCns, baseType)) + { + cnsArgCnt += 1; + } + argCnt += 1; + } + else if (cnsArgCnt == 1) + { + // These intrinsics are meant to set the same value to every element + // so we'll just specially handle it here and copy it into the remaining + // indices. + + for (unsigned i = 1; i < simdSize / genTypeSize(baseType); i++) + { + HandleArgForHWIntrinsicCreate(op1, i, vecCns, baseType); + } + } + } + assert((argCnt == 1) || (argCnt == (simdSize / genTypeSize(baseType)))); + + if (argCnt == cnsArgCnt) + { + if (op1->OperIsList()) + { + for (argList = op1->AsArgList(); argList != nullptr; argList = argList->Rest()) + { + BlockRange().Remove(argList->Current()); + } + } + else + { + BlockRange().Remove(op1); + + if (op2 != nullptr) + { + BlockRange().Remove(op2); + } + } + + assert((simdSize == 16) || (simdSize == 32)); + + UNATIVE_OFFSET cnsSize = simdSize; + UNATIVE_OFFSET cnsAlign = (comp->compCodeOpt() != Compiler::SMALL_CODE) ? cnsSize : 1; + + CORINFO_FIELD_HANDLE hnd = comp->GetEmitter()->emitAnyConst(&vecCns, cnsSize, cnsAlign); + GenTree* clsVarAddr = new (comp, GT_CLS_VAR_ADDR) GenTreeClsVar(GT_CLS_VAR_ADDR, TYP_I_IMPL, hnd, nullptr); + BlockRange().InsertBefore(node, clsVarAddr); + + node->ChangeOper(GT_IND); + node->gtOp1 = clsVarAddr; + + // TODO-XARCH-CQ: We should be able to modify at least the paths that use Insert to trivially support partial + // vector constants. With this, we can create a constant if say 50% of the inputs are also constant and just + // insert the non-constant values which should still allow some gains. + + return; + } + else if (argCnt == 1) + { + // We have the following (where simd is simd16 or simd32): + // /--* op1 T + // node = * HWINTRINSIC simd T Create + + if (intrinsicId == NI_Vector256_Create) + { + if (comp->compOpportunisticallyDependsOn(InstructionSet_AVX2)) + { + // We will be constructing the following parts: + // /--* op1 T + // tmp1 = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* tmp1 simd16 + // node = * HWINTRINSIC simd32 T BroadcastScalarToVector256 + + // This is roughly the following managed code: + // var tmp1 = Vector128.CreateScalarUnsafe(op1); + // return Avx2.BroadcastScalarToVector256(tmp1); + + tmp1 = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, NI_Vector128_CreateScalarUnsafe, baseType, 16); + BlockRange().InsertAfter(op1, tmp1); + LowerNode(tmp1); + + node->gtOp1 = tmp1; + node->gtOp2 = nullptr; + + node->gtHWIntrinsicId = NI_AVX2_BroadcastScalarToVector256; + return; + } + + assert(comp->compIsaSupportedDebugOnly(InstructionSet_AVX)); + + // We will be constructing the following parts: + // /--* op1 T + // tmp1 = * HWINTRINSIC simd16 T Create + // /--* tmp1 simd16 + // * STORE_LCL_VAR simd16 + // tmp1 = LCL_VAR simd16 + // tmp2 = LCL_VAR simd16 + // /--* tmp2 simd16 + // tmp3 = * HWINTRINSIC simd16 T ToVector256Unsafe + // idx = CNS_INT int 0 + // /--* tmp3 simd32 + // +--* tmp1 simd16 + // +--* idx int + // node = * HWINTRINSIC simd32 T InsertVector128 + + // This is roughly the following managed code: + // var tmp1 = Vector128.Create(op1); + // var tmp2 = tmp1; + // var tmp3 = tmp2.ToVector256Unsafe(); + // return Avx.InsertVector128(tmp3, tmp1, 0x01); + + tmp1 = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, NI_Vector128_Create, baseType, 16); + BlockRange().InsertAfter(op1, tmp1); + LowerNode(tmp1); + + node->gtOp1 = tmp1; + LIR::Use tmp1Use(BlockRange(), &node->gtOp1, node); + ReplaceWithLclVar(tmp1Use); + tmp1 = node->gtOp1; + + tmp2 = comp->gtClone(tmp1); + BlockRange().InsertAfter(tmp1, tmp2); + + tmp3 = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD32, tmp2, NI_Vector128_ToVector256Unsafe, baseType, 16); + BlockRange().InsertAfter(tmp2, tmp3); + LowerNode(tmp3); + + idx = comp->gtNewIconNode(0x01, TYP_INT); + BlockRange().InsertAfter(tmp3, idx); + + node->gtOp1 = comp->gtNewArgList(tmp3, tmp1, idx); + node->gtOp2 = nullptr; + + node->gtHWIntrinsicId = NI_AVX_InsertVector128; + return; + } + + // We will be constructing the following parts: + // /--* op1 T + // tmp1 = * HWINTRINSIC simd16 T CreateScalarUnsafe + // ... + + // This is roughly the following managed code: + // var tmp1 = Vector128.CreateScalarUnsafe(op1); + // ... + + tmp1 = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, NI_Vector128_CreateScalarUnsafe, baseType, 16); + BlockRange().InsertAfter(op1, tmp1); + LowerNode(tmp1); + + if ((baseType != TYP_DOUBLE) && comp->compOpportunisticallyDependsOn(InstructionSet_AVX2)) + { + // We will be constructing the following parts: + // ... + // /--* tmp1 simd16 + // node = * HWINTRINSIC simd16 T BroadcastScalarToVector128 + + // This is roughly the following managed code: + // ... + // return Avx2.BroadcastScalarToVector128(tmp1); + + node->gtOp1 = tmp1; + node->gtOp2 = nullptr; + + node->gtHWIntrinsicId = NI_AVX2_BroadcastScalarToVector128; + return; + } + + switch (baseType) + { + case TYP_BYTE: + case TYP_UBYTE: + { + if (comp->compOpportunisticallyDependsOn(InstructionSet_SSSE3)) + { + // We will be constructing the following parts: + // ... + // tmp2 = HWINTRINSIC simd16 ubyte get_Zero + // /--* tmp1 simd16 + // +--* tmp2 simd16 + // node = * HWINTRINSIC simd16 ubyte Shuffle + + // This is roughly the following managed code: + // ... + // var tmp2 = Vector128.Zero; + // return Ssse3.Shuffle(tmp1, tmp2); + + tmp2 = comp->gtNewSimdHWIntrinsicNode(simdType, NI_Vector128_get_Zero, TYP_UBYTE, simdSize); + BlockRange().InsertAfter(tmp1, tmp2); + LowerNode(tmp2); + + node->gtOp1 = tmp1; + node->gtOp2 = tmp2; + + node->gtHWIntrinsicId = NI_SSSE3_Shuffle; + break; + } + + assert(comp->compIsaSupportedDebugOnly(InstructionSet_SSE2)); + + // We will be constructing the following parts: + // ... + // /--* tmp1 simd16 + // * STORE_LCL_VAR simd16 + // tmp1 = LCL_VAR simd16 + // tmp2 = LCL_VAR simd16 + // /--* tmp1 simd16 + // +--* tmp2 simd16 + // tmp1 = * HWINTRINSIC simd16 ubyte UnpackLow + // ... + + // This is roughly the following managed code: + // ... + // var tmp2 = tmp1; + // tmp1 = Sse2.UnpackLow(tmp1, tmp2); + // ... + + node->gtOp1 = tmp1; + LIR::Use tmp1Use(BlockRange(), &node->gtOp1, node); + ReplaceWithLclVar(tmp1Use); + tmp1 = node->gtOp1; + + tmp2 = comp->gtClone(tmp1); + BlockRange().InsertAfter(tmp1, tmp2); + + tmp1 = comp->gtNewSimdHWIntrinsicNode(simdType, tmp1, tmp2, NI_SSE2_UnpackLow, TYP_UBYTE, simdSize); + BlockRange().InsertAfter(tmp2, tmp1); + LowerNode(tmp1); + + __fallthrough; + } + + case TYP_SHORT: + case TYP_USHORT: + { + // We will be constructing the following parts: + // ... + // /--* tmp1 simd16 + // * STORE_LCL_VAR simd16 + // tmp1 = LCL_VAR simd16 + // tmp2 = LCL_VAR simd16 + // /--* tmp1 simd16 + // +--* tmp2 simd16 + // tmp1 = * HWINTRINSIC simd16 ushort UnpackLow + // ... + + // This is roughly the following managed code: + // ... + // var tmp2 = tmp1; + // tmp1 = Sse2.UnpackLow(tmp1, tmp2); + // ... + + assert(comp->compIsaSupportedDebugOnly(InstructionSet_SSE2)); + + node->gtOp1 = tmp1; + LIR::Use tmp1Use(BlockRange(), &node->gtOp1, node); + ReplaceWithLclVar(tmp1Use); + tmp1 = node->gtOp1; + + tmp2 = comp->gtClone(tmp1); + BlockRange().InsertAfter(tmp1, tmp2); + + tmp1 = comp->gtNewSimdHWIntrinsicNode(simdType, tmp1, tmp2, NI_SSE2_UnpackLow, TYP_USHORT, simdSize); + BlockRange().InsertAfter(tmp2, tmp1); + LowerNode(tmp1); + + __fallthrough; + } + + case TYP_INT: + case TYP_UINT: + { + // We will be constructing the following parts: + // ... + // idx = CNS_INT int 0 + // /--* tmp1 simd16 + // +--* idx int + // node = * HWINTRINSIC simd16 uint Shuffle + + // This is roughly the following managed code: + // ... + // return Sse2.Shuffle(tmp1, 0x00); + + assert(comp->compIsaSupportedDebugOnly(InstructionSet_SSE2)); + + idx = comp->gtNewIconNode(0x00, TYP_INT); + BlockRange().InsertAfter(tmp1, idx); + + node->gtOp1 = tmp1; + node->gtOp2 = idx; + + node->gtHWIntrinsicId = NI_SSE2_Shuffle; + node->gtSIMDBaseType = TYP_UINT; + + break; + } + +#if defined(TARGET_AMD64) + case TYP_LONG: + case TYP_ULONG: + { + // We will be constructing the following parts: + // ... + // /--* tmp1 simd16 + // * STORE_LCL_VAR simd16 + // tmp1 = LCL_VAR simd16 + // tmp2 = LCL_VAR simd16 + // /--* tmp1 simd16 + // +--* tmp2 simd16 + // node = * HWINTRINSIC simd16 ulong UnpackLow + + // This is roughly the following managed code: + // ... + // var tmp2 = tmp1; + // return Sse2.UnpackLow(tmp1, tmp2); + + assert(comp->compIsaSupportedDebugOnly(InstructionSet_SSE2)); + + node->gtOp1 = tmp1; + LIR::Use tmp1Use(BlockRange(), &node->gtOp1, node); + ReplaceWithLclVar(tmp1Use); + tmp1 = node->gtOp1; + + tmp2 = comp->gtClone(tmp1); + BlockRange().InsertAfter(tmp1, tmp2); + + node->gtOp1 = tmp1; + node->gtOp2 = tmp2; + + node->gtHWIntrinsicId = NI_SSE2_UnpackLow; + break; + } +#endif // TARGET_AMD64 + + case TYP_FLOAT: + { + if (comp->compOpportunisticallyDependsOn(InstructionSet_AVX)) + { + // We will be constructing the following parts: + // ... + // idx = CNS_INT int 0 + // /--* tmp1 simd16 + // +--* idx int + // node = * HWINTRINSIC simd16 float Permute + + // This is roughly the following managed code: + // ... + // return Avx.Permute(tmp1, 0x00); + + idx = comp->gtNewIconNode(0x00, TYP_INT); + BlockRange().InsertAfter(tmp1, idx); + + node->gtOp1 = tmp1; + node->gtOp2 = idx; + + node->gtHWIntrinsicId = NI_AVX_Permute; + break; + } + + // We will be constructing the following parts: + // ... + // /--* tmp1 simd16 + // * STORE_LCL_VAR simd16 + // tmp1 = LCL_VAR simd16 + // tmp2 = LCL_VAR simd16 + // idx = CNS_INT int 0 + // /--* tmp1 simd16 + // +--* tmp2 simd16 + // +--* idx int + // node = * HWINTRINSIC simd16 float Shuffle + + // This is roughly the following managed code: + // ... + // var tmp2 = tmp1; + // return Sse.Shuffle(tmp1, tmp2, 0x00); + + assert(comp->compIsaSupportedDebugOnly(InstructionSet_SSE)); + + node->gtOp1 = tmp1; + LIR::Use tmp1Use(BlockRange(), &node->gtOp1, node); + ReplaceWithLclVar(tmp1Use); + tmp1 = node->gtOp1; + + tmp2 = comp->gtClone(tmp1); + BlockRange().InsertAfter(tmp1, tmp2); + + idx = comp->gtNewIconNode(0x00, TYP_INT); + BlockRange().InsertAfter(tmp2, idx); + + node->gtOp1 = comp->gtNewArgList(tmp1, tmp2, idx); + node->gtOp2 = nullptr; + + node->gtHWIntrinsicId = NI_SSE_Shuffle; + break; + } + + case TYP_DOUBLE: + { + if (comp->compOpportunisticallyDependsOn(InstructionSet_SSE3)) + { + // We will be constructing the following parts: + // ... + // /--* tmp1 simd16 + // node = * HWINTRINSIC simd16 double MoveAndDuplicate + + // This is roughly the following managed code: + // ... + // return Sse3.MoveAndDuplicate(tmp1); + + node->gtOp1 = tmp1; + node->gtOp2 = nullptr; + + node->gtHWIntrinsicId = NI_SSE3_MoveAndDuplicate; + break; + } + + assert(comp->compIsaSupportedDebugOnly(InstructionSet_SSE2)); + + // We will be constructing the following parts: + // ... + // /--* tmp1 simd16 + // * STORE_LCL_VAR simd16 + // tmp1 = LCL_VAR simd16 + // tmp2 = LCL_VAR simd16 + // /--* tmp1 simd16 + // +--* tmp2 simd16 + // node = * HWINTRINSIC simd16 float MoveLowToHigh + + // This is roughly the following managed code: + // ... + // var tmp2 = tmp1; + // return Sse.MoveLowToHigh(tmp1, tmp2); + + node->gtOp1 = tmp1; + LIR::Use tmp1Use(BlockRange(), &node->gtOp1, node); + ReplaceWithLclVar(tmp1Use); + tmp1 = node->gtOp1; + + tmp2 = comp->gtClone(tmp1); + BlockRange().InsertAfter(tmp1, tmp2); + + node->gtOp1 = tmp1; + node->gtOp2 = tmp2; + + node->gtHWIntrinsicId = NI_SSE_MoveLowToHigh; + node->gtSIMDBaseType = TYP_FLOAT; + + break; + } + + default: + { + unreached(); + } + } + + return; + } + + // We have the following (where simd is simd16 or simd32): + // /--* op1 T + // +--* ... T + // +--* opN T + // node = * HWINTRINSIC simd T Create + + if (intrinsicId == NI_Vector256_Create) + { + assert(comp->compIsaSupportedDebugOnly(InstructionSet_AVX)); + + // We will be constructing the following parts: + // /--* op1 T + // +--* ... T + // lo = * HWINTRINSIC simd16 T Create + // /--* ... T + // +--* opN T + // hi = * HWINTRINSIC simd16 T Create + // idx = CNS_INT int 1 + // /--* lo simd32 + // +--* hi simd16 + // +--* idx int + // node = * HWINTRINSIC simd32 T InsertVector128 + + // This is roughly the following managed code: + // ... + // var lo = Vector128.Create(op1, ...); + // var hi = Vector128.Create(..., opN); + // return Avx.InsertVector128(lo, hi, 0x01); + + // Each Vector128.Create call gets half the operands. That is: + // lo = Vector128.Create(op1, op2); + // hi = Vector128.Create(op3, op4); + // -or- + // lo = Vector128.Create(op1, ..., op3); + // hi = Vector128.Create(op4, ..., op7); + // -or- + // lo = Vector128.Create(op1, ..., op7); + // hi = Vector128.Create(op8, ..., op15); + // -or- + // lo = Vector128.Create(op1, ..., op15); + // hi = Vector128.Create(op16, ..., op31); + + unsigned halfArgCnt = argCnt / 2; + assert((halfArgCnt * 2) == argCnt); + + argList = op1->AsArgList(); + + for (unsigned i = 0; i < halfArgCnt; i++) + { + op2 = argList; + argList = argList->Rest(); + } + + op2->AsArgList()->gtOp2 = nullptr; + op2 = argList; + + // The above for loop splits the operand count into exactly half. + // Once it exits, op1 will point to op1 and op2 will point to the + // last operand that will be passed to the first Vector128.Create + // We will set its op2 to null, terminating the chain and then + // assign op2 to be argList, which is the first operand that will + // get passed to the second Vector128.Create + + GenTree* lo = nullptr; + GenTree* hi = nullptr; + + if (halfArgCnt == 2) + { + // The Vector256.Create calls that take 4 operands are special + // because the half argument count is 2, which means we can't + // actually use the GT_LIST anymore and need to pass them as + // explicit operands instead. + + argList = op1->AsArgList(); + + tmp1 = argList->Current(); + tmp2 = argList->Rest()->Current(); + + lo = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, tmp1, tmp2, NI_Vector128_Create, baseType, 16); + BlockRange().InsertAfter(tmp2, lo); + LowerNode(lo); + + argList = op2->AsArgList(); + + tmp1 = argList->Current(); + tmp2 = argList->Rest()->Current(); + + hi = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, tmp1, tmp2, NI_Vector128_Create, baseType, 16); + BlockRange().InsertAfter(tmp2, hi); + LowerNode(hi); + } + else + { + // The rest of the Vector256.Create calls take at least 8 operands + // and so the half count is at least 4 and we have to continue + // passing around GT_LIST nodes in op1 with a null op2 + assert(halfArgCnt >= 4); + + tmp1 = op2->AsArgList()->Current(); + + lo = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, NI_Vector128_Create, baseType, 16); + BlockRange().InsertBefore(tmp1, lo); + LowerNode(lo); + + hi = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, NI_Vector128_Create, baseType, 16); + BlockRange().InsertBefore(node, hi); + LowerNode(hi); + } + + idx = comp->gtNewIconNode(0x01, TYP_INT); + BlockRange().InsertAfter(hi, idx); + + node->gtOp1 = comp->gtNewArgList(lo, hi, idx); + node->gtOp2 = nullptr; + + node->gtHWIntrinsicId = NI_AVX_InsertVector128; + return; + } + + if (op1->OperIsList()) + { + argList = op1->AsArgList(); + op1 = argList->Current(); + argList = argList->Rest(); + } + + // We will be constructing the following parts: + // /--* op1 T + // tmp1 = * HWINTRINSIC simd16 T CreateScalarUnsafe + // ... + + // This is roughly the following managed code: + // var tmp1 = Vector128.CreateScalarUnsafe(op1); + // ... + + tmp1 = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, NI_Vector128_CreateScalarUnsafe, baseType, 16); + BlockRange().InsertAfter(op1, tmp1); + LowerNode(tmp1); + + switch (baseType) + { + case TYP_BYTE: + case TYP_UBYTE: + case TYP_SHORT: + case TYP_USHORT: + case TYP_INT: + case TYP_UINT: + { + unsigned N = 0; + GenTree* opN = nullptr; + NamedIntrinsic insIntrinsic = NI_Illegal; + + if ((baseType == TYP_SHORT) || (baseType == TYP_USHORT)) + { + assert(comp->compIsaSupportedDebugOnly(InstructionSet_SSE2)); + insIntrinsic = NI_SSE2_Insert; + } + else if (comp->compOpportunisticallyDependsOn(InstructionSet_SSE41)) + { + insIntrinsic = NI_SSE41_Insert; + } + + if (insIntrinsic != NI_Illegal) + { + for (N = 1; N < argCnt - 1; N++) + { + // We will be constructing the following parts: + // ... + // idx = CNS_INT int N + // /--* tmp1 simd16 + // +--* opN T + // +--* idx int + // tmp1 = * HWINTRINSIC simd16 T Insert + // ... + + // This is roughly the following managed code: + // ... + // tmp1 = Sse?.Insert(tmp1, opN, N); + // ... + + opN = argList->Current(); + + idx = comp->gtNewIconNode(N, TYP_INT); + BlockRange().InsertAfter(opN, idx); + + tmp1 = comp->gtNewSimdHWIntrinsicNode(simdType, tmp1, opN, idx, insIntrinsic, baseType, simdSize); + BlockRange().InsertAfter(idx, tmp1); + LowerNode(tmp1); + + argList = argList->Rest(); + } + + assert(N == (argCnt - 1)); + + // We will be constructing the following parts: + // idx = CNS_INT int N + // /--* tmp1 simd16 + // +--* opN T + // +--* idx int + // node = * HWINTRINSIC simd16 T Insert + + // This is roughly the following managed code: + // ... + // tmp1 = Sse?.Insert(tmp1, opN, N); + // ... + + opN = argList->Current(); + + idx = comp->gtNewIconNode(N, TYP_INT); + BlockRange().InsertAfter(opN, idx); + + node->gtOp1 = comp->gtNewArgList(tmp1, opN, idx); + node->gtOp2 = nullptr; + + node->gtHWIntrinsicId = insIntrinsic; + break; + } + + assert((baseType != TYP_SHORT) && (baseType != TYP_USHORT)); + assert(comp->compIsaSupportedDebugOnly(InstructionSet_SSE2)); + + GenTree* op[16]; + op[0] = tmp1; + + for (N = 1; N < argCnt; N++) + { + opN = argList->Current(); + + op[N] = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, opN, NI_Vector128_CreateScalarUnsafe, baseType, 16); + BlockRange().InsertAfter(opN, op[N]); + LowerNode(op[N]); + + argList = argList->Rest(); + } + assert(argList == nullptr); + + if ((baseType == TYP_BYTE) || (baseType == TYP_UBYTE)) + { + for (N = 0; N < argCnt; N += 4) + { + // We will be constructing the following parts: + // ... + // /--* opN T + // opN = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* opO T + // opO = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* opN simd16 + // +--* opO simd16 + // tmp1 = * HWINTRINSIC simd16 T UnpackLow + // /--* opP T + // opP = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* opQ T + // opQ = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* opP simd16 + // +--* opQ simd16 + // tmp2 = * HWINTRINSIC simd16 T UnpackLow + // /--* tmp1 simd16 + // +--* tmp2 simd16 + // tmp3 = * HWINTRINSIC simd16 T UnpackLow + // ... + + // This is roughly the following managed code: + // ... + // tmp1 = Sse2.UnpackLow(opN, opO); + // tmp2 = Sse2.UnpackLow(opP, opQ); + // tmp3 = Sse2.UnpackLow(tmp1, tmp2); + // ... + + unsigned O = N + 1; + unsigned P = N + 2; + unsigned Q = N + 3; + + tmp1 = + comp->gtNewSimdHWIntrinsicNode(simdType, op[N], op[O], NI_SSE2_UnpackLow, TYP_UBYTE, simdSize); + BlockRange().InsertAfter(op[O], tmp1); + LowerNode(tmp1); + + tmp2 = + comp->gtNewSimdHWIntrinsicNode(simdType, op[P], op[Q], NI_SSE2_UnpackLow, TYP_UBYTE, simdSize); + BlockRange().InsertAfter(op[Q], tmp2); + LowerNode(tmp2); + + tmp3 = + comp->gtNewSimdHWIntrinsicNode(simdType, tmp1, tmp2, NI_SSE2_UnpackLow, TYP_USHORT, simdSize); + BlockRange().InsertAfter(tmp2, tmp3); + LowerNode(tmp3); + + // This caches the result in index 0 through 3, depending on which + // loop iteration this is and allows the rest of the logic to be + // shared with the TYP_INT and TYP_UINT path. + + op[N / 4] = tmp3; + } + } + + // We will be constructing the following parts: + // ... + // /--* opN T + // opN = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* opO T + // opO = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* opN simd16 + // +--* opO simd16 + // tmp1 = * HWINTRINSIC simd16 T UnpackLow + // /--* opP T + // opP = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* opQ T + // opQ = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* opP simd16 + // +--* opQ simd16 + // tmp2 = * HWINTRINSIC simd16 T UnpackLow + // /--* tmp1 simd16 + // +--* tmp2 simd16 + // node = * HWINTRINSIC simd16 T UnpackLow + + // This is roughly the following managed code: + // ... + // tmp1 = Sse2.UnpackLow(opN, opO); + // tmp2 = Sse2.UnpackLow(opP, opQ); + // return Sse2.UnpackLow(tmp1, tmp2); + + tmp1 = comp->gtNewSimdHWIntrinsicNode(simdType, op[0], op[1], NI_SSE2_UnpackLow, TYP_UINT, simdSize); + BlockRange().InsertAfter(op[1], tmp1); + LowerNode(tmp1); + + tmp2 = comp->gtNewSimdHWIntrinsicNode(simdType, op[2], op[3], NI_SSE2_UnpackLow, TYP_UINT, simdSize); + BlockRange().InsertAfter(op[3], tmp2); + LowerNode(tmp2); + + node->gtOp1 = tmp1; + node->gtOp2 = tmp2; + + node->gtHWIntrinsicId = NI_SSE2_UnpackLow; + node->gtSIMDBaseType = TYP_ULONG; + break; + } + +#if defined(TARGET_AMD64) + case TYP_LONG: + case TYP_ULONG: + { + if (comp->compOpportunisticallyDependsOn(InstructionSet_SSE41_X64)) + { + // We will be constructing the following parts: + // ... + // idx = CNS_INT int 1 + // /--* tmp1 simd16 + // +--* op2 T + // +--* idx int + // node = * HWINTRINSIC simd16 T Insert + + // This is roughly the following managed code: + // ... + // return Sse41.X64.Insert(tmp1, op2, 0x01); + + idx = comp->gtNewIconNode(0x01, TYP_INT); + BlockRange().InsertAfter(op2, idx); + + node->gtOp1 = comp->gtNewArgList(tmp1, op2, idx); + node->gtOp2 = nullptr; + + node->gtHWIntrinsicId = NI_SSE41_X64_Insert; + break; + } + + // We will be constructing the following parts: + // ... + // /--* op2 T + // tmp2 = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* tmp1 simd16 + // +--* tmp2 simd16 + // node = * HWINTRINSIC simd16 T UnpackLow + + // This is roughly the following managed code: + // ... + // var tmp2 = Vector128.CreateScalarUnsafe(op2); + // return Sse2.UnpackLow(tmp1, tmp2); + + assert(comp->compIsaSupportedDebugOnly(InstructionSet_SSE2)); + + tmp2 = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, NI_Vector128_CreateScalarUnsafe, baseType, 16); + BlockRange().InsertAfter(op2, tmp2); + LowerNode(tmp2); + + node->gtOp1 = tmp1; + node->gtOp2 = tmp2; + + node->gtHWIntrinsicId = NI_SSE2_UnpackLow; + break; + } +#endif // TARGET_AMD64 + + case TYP_FLOAT: + { + unsigned N = 0; + GenTree* opN = nullptr; + + if (comp->compOpportunisticallyDependsOn(InstructionSet_SSE41)) + { + for (N = 1; N < argCnt - 1; N++) + { + // We will be constructing the following parts: + // ... + // + // /--* opN T + // tmp2 = * HWINTRINSIC simd16 T CreateScalarUnsafe + // idx = CNS_INT int N + // /--* tmp1 simd16 + // +--* opN T + // +--* idx int + // tmp1 = * HWINTRINSIC simd16 T Insert + // ... + + // This is roughly the following managed code: + // ... + // tmp2 = Vector128.CreateScalarUnsafe(opN); + // tmp1 = Sse41.Insert(tmp1, tmp2, N << 4); + // ... + + opN = argList->Current(); + + tmp2 = + comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, opN, NI_Vector128_CreateScalarUnsafe, baseType, 16); + BlockRange().InsertAfter(opN, tmp2); + LowerNode(tmp2); + + idx = comp->gtNewIconNode(N << 4, TYP_INT); + BlockRange().InsertAfter(tmp2, idx); + + tmp1 = + comp->gtNewSimdHWIntrinsicNode(simdType, tmp1, tmp2, idx, NI_SSE41_Insert, baseType, simdSize); + BlockRange().InsertAfter(idx, tmp1); + LowerNode(tmp1); + + argList = argList->Rest(); + } + + // We will be constructing the following parts: + // ... + // + // /--* opN T + // tmp2 = * HWINTRINSIC simd16 T CreateScalarUnsafe + // idx = CNS_INT int N + // /--* tmp1 simd16 + // +--* opN T + // +--* idx int + // node = * HWINTRINSIC simd16 T Insert + + // This is roughly the following managed code: + // ... + // tmp2 = Vector128.CreateScalarUnsafe(opN); + // return Sse41.Insert(tmp1, tmp2, N << 4); + + opN = argList->Current(); + + tmp2 = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, opN, NI_Vector128_CreateScalarUnsafe, baseType, 16); + BlockRange().InsertAfter(opN, tmp2); + LowerNode(tmp2); + + idx = comp->gtNewIconNode((argCnt - 1) << 4, TYP_INT); + BlockRange().InsertAfter(tmp2, idx); + + node->gtOp1 = comp->gtNewArgList(tmp1, tmp2, idx); + node->gtOp2 = nullptr; + + node->gtHWIntrinsicId = NI_SSE41_Insert; + break; + } + + // We will be constructing the following parts: + // ... + // /--* opN T + // opN = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* opO T + // opO = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* opN simd16 + // +--* opO simd16 + // tmp1 = * HWINTRINSIC simd16 T UnpackLow + // /--* opP T + // opP = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* opQ T + // opQ = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* opP simd16 + // +--* opQ simd16 + // tmp2 = * HWINTRINSIC simd16 T UnpackLow + // /--* tmp1 simd16 + // +--* tmp2 simd16 + // node = * HWINTRINSIC simd16 T MoveLowToHigh + + // This is roughly the following managed code: + // ... + // tmp1 = Sse.UnpackLow(opN, opO); + // tmp2 = Sse.UnpackLow(opP, opQ); + // return Sse.MoveLowToHigh(tmp1, tmp2); + + assert(comp->compIsaSupportedDebugOnly(InstructionSet_SSE)); + + GenTree* op[4]; + op[0] = tmp1; + + for (N = 1; N < argCnt; N++) + { + opN = argList->Current(); + + op[N] = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, opN, NI_Vector128_CreateScalarUnsafe, baseType, 16); + BlockRange().InsertAfter(opN, op[N]); + LowerNode(op[N]); + + argList = argList->Rest(); + } + assert(argList == nullptr); + + tmp1 = comp->gtNewSimdHWIntrinsicNode(simdType, op[0], op[1], NI_SSE_UnpackLow, baseType, simdSize); + BlockRange().InsertAfter(op[1], tmp1); + LowerNode(tmp1); + + tmp2 = comp->gtNewSimdHWIntrinsicNode(simdType, op[2], op[3], NI_SSE_UnpackLow, baseType, simdSize); + BlockRange().InsertAfter(op[3], tmp2); + LowerNode(tmp2); + + node->gtOp1 = tmp1; + node->gtOp2 = tmp2; + + node->gtHWIntrinsicId = NI_SSE_MoveLowToHigh; + break; + } + + case TYP_DOUBLE: + { + // We will be constructing the following parts: + // ... + // /--* op2 T + // tmp2 = * HWINTRINSIC simd16 T CreateScalarUnsafe + // /--* tmp1 simd16 + // +--* tmp2 simd16 + // node = * HWINTRINSIC simd16 T MoveLowToHigh + + // This is roughly the following managed code: + // ... + // var tmp2 = Vector128.CreateScalarUnsafe(op2); + // return Sse.MoveLowToHigh(tmp1, tmp2); + + assert(comp->compIsaSupportedDebugOnly(InstructionSet_SSE2)); + + tmp2 = comp->gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, NI_Vector128_CreateScalarUnsafe, baseType, 16); + BlockRange().InsertAfter(op2, tmp2); + LowerNode(tmp2); + + node->gtOp1 = tmp1; + node->gtOp2 = tmp2; + + node->gtHWIntrinsicId = NI_SSE_MoveLowToHigh; + node->gtSIMDBaseType = TYP_FLOAT; + + break; + } + + default: + { + unreached(); + } + } +} #endif // FEATURE_HW_INTRINSICS //---------------------------------------------------------------------------------------------- @@ -1384,7 +2807,7 @@ bool Lowering::IsCallTargetInRange(void* addr) } // return true if the immediate can be folded into an instruction, for example small enough and non-relocatable -bool Lowering::IsContainableImmed(GenTree* parentNode, GenTree* childNode) +bool Lowering::IsContainableImmed(GenTree* parentNode, GenTree* childNode) const { if (!childNode->IsIntCnsFitsInI32()) { @@ -1920,7 +3343,7 @@ void Lowering::ContainCheckShiftRotate(GenTreeOp* node) // Arguments: // node - pointer to the node // -void Lowering::ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc) +void Lowering::ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc) const { assert(storeLoc->OperIsLocalStore()); GenTree* op1 = storeLoc->gtGetOp1(); @@ -1937,14 +3360,22 @@ void Lowering::ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc) return; } } + + const LclVarDsc* varDsc = comp->lvaGetDesc(storeLoc); + #ifdef FEATURE_SIMD if (varTypeIsSIMD(storeLoc)) { - if (op1->IsCnsIntOrI()) + assert(!op1->IsCnsIntOrI()); + if (storeLoc->TypeIs(TYP_SIMD12) && op1->IsSIMDZero() && varDsc->lvDoNotEnregister) { - // For an InitBlk we want op1 to be contained; otherwise we want it to - // be evaluated into an xmm register. + // For a SIMD12 store we can zero from integer registers more easily. MakeSrcContained(storeLoc, op1); + GenTree* constNode = op1->gtGetOp1(); + assert(constNode->OperIsConst()); + constNode->ClearContained(); + constNode->gtType = TYP_INT; + constNode->SetOper(GT_CNS_INT); } return; } @@ -1953,8 +3384,7 @@ void Lowering::ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc) // If the source is a containable immediate, make it contained, unless it is // an int-size or larger store of zero to memory, because we can generate smaller code // by zeroing a register and then storing it. - const LclVarDsc* varDsc = comp->lvaGetDesc(storeLoc); - var_types type = varDsc->GetRegisterType(storeLoc); + var_types type = varDsc->GetRegisterType(storeLoc); if (IsContainableImmed(storeLoc, op1) && (!op1->IsIntegralConst(0) || varTypeIsSmall(type))) { MakeSrcContained(storeLoc, op1); @@ -2493,19 +3923,6 @@ void Lowering::ContainCheckSIMD(GenTreeSIMD* simdNode) CheckImmedAndMakeContained(simdNode, simdNode->gtGetOp2()); break; - case SIMDIntrinsicOpEquality: - case SIMDIntrinsicOpInEquality: - // On SSE4/AVX, we can generate optimal code for (in)equality - // against zero using ptest. We can safely do this optimization - // for integral vectors but not for floating-point for the reason - // that we have +0.0 and -0.0 and +0.0 == -0.0 - op2 = simdNode->gtGetOp2(); - if ((comp->getSIMDSupportLevel() >= SIMD_SSE4_Supported) && op2->IsIntegralConstVector(0)) - { - MakeSrcContained(simdNode, op2); - } - break; - case SIMDIntrinsicGetItem: { // This implements get_Item method. The sources are: @@ -2655,7 +4072,6 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, Ge switch (containingIntrinsicId) { case NI_SSE_Shuffle: - case NI_SSE2_CompareLessThan: case NI_SSE2_ShiftLeftLogical: case NI_SSE2_ShiftRightArithmetic: case NI_SSE2_ShiftRightLogical: @@ -2975,6 +4391,7 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsicId); int numArgs = HWIntrinsicInfo::lookupNumArgs(node); var_types baseType = node->gtSIMDBaseType; + unsigned simdSize = node->gtSIMDSize; GenTree* op1 = node->gtGetOp1(); GenTree* op2 = node->gtGetOp2(); @@ -2993,6 +4410,24 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) return; } + if (HWIntrinsicInfo::lookupCategory(intrinsicId) == HW_Category_IMM) + { + GenTree* lastOp = HWIntrinsicInfo::lookupLastOp(node); + assert(lastOp != nullptr); + + if (HWIntrinsicInfo::isImmOp(intrinsicId, lastOp) && lastOp->IsCnsIntOrI()) + { + MakeSrcContained(node, lastOp); + } + } + + if ((node->gtSIMDSize == 8) || (node->gtSIMDSize == 12)) + { + // TODO-XArch-CQ: Ideally we would key this off of the size containingNode + // expects vs the size node actually is or would be if spilled to the stack + return; + } + // TODO-XArch-CQ: Non-VEX encoded instructions can have both ops contained const bool isCommutative = HWIntrinsicInfo::IsCommutative(intrinsicId); @@ -3270,28 +4705,6 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) break; } - case HW_Category_Special: - { - if (intrinsicId == NI_SSE2_CompareLessThan) - { - bool supportsRegOptional = false; - - if (IsContainableHWIntrinsicOp(node, op2, &supportsRegOptional)) - { - MakeSrcContained(node, op2); - } - else if (supportsRegOptional) - { - op2->SetRegOptional(); - } - } - else - { - unreached(); - } - break; - } - default: { unreached(); @@ -3479,17 +4892,6 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) { unreached(); } - - if (HWIntrinsicInfo::lookupCategory(intrinsicId) == HW_Category_IMM) - { - GenTree* lastOp = HWIntrinsicInfo::lookupLastOp(node); - assert(lastOp != nullptr); - - if (HWIntrinsicInfo::isImmOp(intrinsicId, lastOp) && lastOp->IsCnsIntOrI()) - { - MakeSrcContained(node, lastOp); - } - } } } #endif // FEATURE_HW_INTRINSICS diff --git a/src/coreclr/src/jit/lsra.cpp b/src/coreclr/src/jit/lsra.cpp index c3f647e3561d3b..5101e573892957 100644 --- a/src/coreclr/src/jit/lsra.cpp +++ b/src/coreclr/src/jit/lsra.cpp @@ -1791,6 +1791,8 @@ void LinearScan::identifyCandidates() VarSetOps::AddElemD(compiler, fpMaybeCandidateVars, varDsc->lvVarIndex); } } + JITDUMP(" "); + DBEXEC(VERBOSE, newInt->dump()); } else { @@ -6282,6 +6284,26 @@ void LinearScan::updatePreviousInterval(RegRecord* reg, Interval* interval, Regi #endif } +//----------------------------------------------------------------------------- +// writeLocalReg: Write the register assignment for a GT_LCL_VAR node. +// +// Arguments: +// lclNode - The GT_LCL_VAR node +// varNum - The variable number for the register +// reg - The assigned register +// +// Return Value: +// None +// +void LinearScan::writeLocalReg(GenTreeLclVar* lclNode, unsigned varNum, regNumber reg) +{ + // We don't yet support multireg locals. + assert((lclNode->GetLclNum() == varNum) && !lclNode->IsMultiReg()); + assert(lclNode->GetLclNum() == varNum); + lclNode->SetRegNum(reg); +} + +//----------------------------------------------------------------------------- // LinearScan::resolveLocalRef // Description: // Update the graph for a local reference. @@ -6318,7 +6340,7 @@ void LinearScan::updatePreviousInterval(RegRecord* reg, Interval* interval, Regi // NICE: Consider tracking whether an Interval is always in the same location (register/stack) // in which case it will require no resolution. // -void LinearScan::resolveLocalRef(BasicBlock* block, GenTree* treeNode, RefPosition* currentRefPosition) +void LinearScan::resolveLocalRef(BasicBlock* block, GenTreeLclVar* treeNode, RefPosition* currentRefPosition) { assert((block == nullptr) == (treeNode == nullptr)); assert(enregisterLocalVars); @@ -6339,11 +6361,11 @@ void LinearScan::resolveLocalRef(BasicBlock* block, GenTree* treeNode, RefPositi { if (currentRefPosition->lastUse) { - treeNode->gtFlags |= GTF_VAR_DEATH; + treeNode->SetLastUse(currentRefPosition->getMultiRegIdx()); } else { - treeNode->gtFlags &= ~GTF_VAR_DEATH; + treeNode->ClearLastUse(currentRefPosition->getMultiRegIdx()); } if ((currentRefPosition->registerAssignment != RBM_NONE) && (interval->physReg == REG_NA) && @@ -6354,7 +6376,7 @@ void LinearScan::resolveLocalRef(BasicBlock* block, GenTree* treeNode, RefPositi // during resolution. In this case we're better off making it contained. assert(inVarToRegMaps[curBBNum][varDsc->lvVarIndex] == REG_STK); currentRefPosition->registerAssignment = RBM_NONE; - treeNode->SetRegNum(REG_NA); + writeLocalReg(treeNode->AsLclVar(), interval->varNum, REG_NA); } } @@ -6445,9 +6467,11 @@ void LinearScan::resolveLocalRef(BasicBlock* block, GenTree* treeNode, RefPositi // // Note that varDsc->GetRegNum() is already to REG_STK above. interval->physReg = REG_NA; - treeNode->SetRegNum(REG_NA); + writeLocalReg(treeNode->AsLclVar(), interval->varNum, REG_NA); treeNode->gtFlags &= ~GTF_SPILLED; treeNode->SetContained(); + // We don't support RegOptional for multi-reg localvars. + assert(!treeNode->IsMultiReg()); } else { @@ -6470,7 +6494,7 @@ void LinearScan::resolveLocalRef(BasicBlock* block, GenTree* treeNode, RefPositi interval->physReg = REG_NA; if (treeNode != nullptr) { - treeNode->SetRegNum(REG_NA); + writeLocalReg(treeNode->AsLclVar(), interval->varNum, REG_NA); } } else // Not reload and Not pure-def that's spillAfter @@ -6489,7 +6513,7 @@ void LinearScan::resolveLocalRef(BasicBlock* block, GenTree* treeNode, RefPositi // But for copyReg, the homeReg remains unchanged. assert(treeNode != nullptr); - treeNode->SetRegNum(interval->physReg); + writeLocalReg(treeNode->AsLclVar(), interval->varNum, interval->physReg); if (currentRefPosition->copyReg) { @@ -6755,6 +6779,17 @@ void LinearScan::insertUpperVectorSave(GenTree* tree, GenTreeSIMD* simdNode = new (compiler, GT_SIMD) GenTreeSIMD(LargeVectorSaveType, saveLcl, nullptr, SIMDIntrinsicUpperSave, varDsc->lvBaseType, genTypeSize(varDsc->lvType)); + + if (simdNode->gtSIMDBaseType == TYP_UNDEF) + { + // There are a few scenarios where we can get a LCL_VAR which + // doesn't know the underlying baseType. In that scenario, we + // will just lie and say it is a float. Codegen doesn't actually + // care what the type is but this avoids an assert that would + // otherwise be fired from the more general checks that happen. + simdNode->gtSIMDBaseType = TYP_FLOAT; + } + SetLsraAdded(simdNode); simdNode->SetRegNum(spillReg); if (spillToMem) @@ -6812,6 +6847,16 @@ void LinearScan::insertUpperVectorRestore(GenTree* tree, new (compiler, GT_SIMD) GenTreeSIMD(varDsc->lvType, restoreLcl, nullptr, SIMDIntrinsicUpperRestore, varDsc->lvBaseType, genTypeSize(varDsc->lvType)); + if (simdNode->gtSIMDBaseType == TYP_UNDEF) + { + // There are a few scenarios where we can get a LCL_VAR which + // doesn't know the underlying baseType. In that scenario, we + // will just lie and say it is a float. Codegen doesn't actually + // care what the type is but this avoids an assert that would + // otherwise be fired from the more general checks that happen. + simdNode->gtSIMDBaseType = TYP_FLOAT; + } + regNumber restoreReg = upperVectorInterval->physReg; SetLsraAdded(simdNode); @@ -6988,14 +7033,6 @@ void LinearScan::updateMaxSpill(RefPosition* refPosition) Interval* interval = refPosition->getInterval(); if (!interval->isLocalVar) { - // The tmp allocation logic 'normalizes' types to a small number of - // types that need distinct stack locations from each other. - // Those types are currently gc refs, byrefs, <= 4 byte non-GC items, - // 8-byte non-GC items, and 16-byte or 32-byte SIMD vectors. - // LSRA is agnostic to those choices but needs - // to know what they are here. - var_types typ; - GenTree* treeNode = refPosition->treeNode; if (treeNode == nullptr) { @@ -7004,46 +7041,36 @@ void LinearScan::updateMaxSpill(RefPosition* refPosition) } assert(treeNode != nullptr); - // In case of multi-reg call nodes, we need to use the type - // of the return register given by multiRegIdx of the refposition. - if (treeNode->IsMultiRegCall()) - { - ReturnTypeDesc* retTypeDesc = treeNode->AsCall()->GetReturnTypeDesc(); - typ = retTypeDesc->GetReturnRegType(refPosition->getMultiRegIdx()); - } -#if FEATURE_ARG_SPLIT - else if (treeNode->OperIsPutArgSplit()) - { - typ = treeNode->AsPutArgSplit()->GetRegType(refPosition->getMultiRegIdx()); - } -#if !defined(TARGET_64BIT) - else if (treeNode->OperIsPutArgReg()) + // The tmp allocation logic 'normalizes' types to a small number of + // types that need distinct stack locations from each other. + // Those types are currently gc refs, byrefs, <= 4 byte non-GC items, + // 8-byte non-GC items, and 16-byte or 32-byte SIMD vectors. + // LSRA is agnostic to those choices but needs + // to know what they are here. + var_types type; + if (!treeNode->IsMultiRegNode()) { - // For double arg regs, the type is changed to long since they must be passed via `r0-r3`. - // However when they get spilled, they should be treated as separated int registers. - var_types typNode = treeNode->TypeGet(); - typ = (typNode == TYP_LONG) ? TYP_INT : typNode; + type = getDefType(treeNode); } -#endif // !TARGET_64BIT -#endif // FEATURE_ARG_SPLIT else { - typ = treeNode->TypeGet(); + type = treeNode->GetRegTypeByIndex(refPosition->getMultiRegIdx()); } - typ = RegSet::tmpNormalizeType(typ); + + type = RegSet::tmpNormalizeType(type); if (refPosition->spillAfter && !refPosition->reload) { - currentSpill[typ]++; - if (currentSpill[typ] > maxSpill[typ]) + currentSpill[type]++; + if (currentSpill[type] > maxSpill[type]) { - maxSpill[typ] = currentSpill[typ]; + maxSpill[type] = currentSpill[type]; } } else if (refPosition->reload) { - assert(currentSpill[typ] > 0); - currentSpill[typ]--; + assert(currentSpill[type] > 0); + currentSpill[type]--; } else if (refPosition->RegOptional() && refPosition->assignedReg() == REG_NA) { @@ -7052,10 +7079,10 @@ void LinearScan::updateMaxSpill(RefPosition* refPosition) // memory location. To properly account max spill for typ we // decrement spill count. assert(RefTypeIsUse(refType)); - assert(currentSpill[typ] > 0); - currentSpill[typ]--; + assert(currentSpill[type] > 0); + currentSpill[type]--; } - JITDUMP(" Max spill for %s is %d\n", varTypeName(typ), maxSpill[typ]); + JITDUMP(" Max spill for %s is %d\n", varTypeName(type), maxSpill[type]); } } } @@ -7342,9 +7369,9 @@ void LinearScan::resolveRegisters() { writeRegisters(currentRefPosition, treeNode); - if (treeNode->IsLocal() && currentRefPosition->getInterval()->isLocalVar) + if (treeNode->OperIs(GT_LCL_VAR, GT_STORE_LCL_VAR) && currentRefPosition->getInterval()->isLocalVar) { - resolveLocalRef(block, treeNode, currentRefPosition); + resolveLocalRef(block, treeNode->AsLclVar(), currentRefPosition); } // Mark spill locations on temps @@ -7367,7 +7394,7 @@ void LinearScan::resolveRegisters() treeNode->ResetReuseRegVal(); } - // In case of multi-reg call node, also set spill flag on the + // In case of multi-reg node, also set spill flag on the // register specified by multi-reg index of current RefPosition. // Note that the spill flag on treeNode indicates that one or // more its allocated registers are in that state. @@ -9302,7 +9329,7 @@ void Interval::dump() } if (isStructField) { - printf(" (struct)"); + printf(" (field)"); } if (isPromotedStruct) { @@ -9443,7 +9470,7 @@ void LinearScan::lsraGetOperandString(GenTree* tree, unsigned operandStringLength) { const char* lastUseChar = ""; - if ((tree->gtFlags & GTF_VAR_DEATH) != 0) + if (tree->OperIsScalarLocal() && ((tree->gtFlags & GTF_VAR_DEATH) != 0)) { lastUseChar = "*"; } @@ -9492,7 +9519,7 @@ void LinearScan::lsraGetOperandString(GenTree* tree, void LinearScan::lsraDispNode(GenTree* tree, LsraTupleDumpMode mode, bool hasDest) { Compiler* compiler = JitTls::GetCompiler(); - const unsigned operandStringLength = 16; + const unsigned operandStringLength = 6 * MAX_MULTIREG_COUNT + 1; char operandString[operandStringLength]; const char* emptyDestOperand = " "; char spillChar = ' '; @@ -9632,7 +9659,7 @@ void LinearScan::TupleStyleDump(LsraTupleDumpMode mode) { BasicBlock* block; LsraLocation currentLoc = 1; // 0 is the entry - const unsigned operandStringLength = 16; + const unsigned operandStringLength = 6 * MAX_MULTIREG_COUNT + 1; char operandString[operandStringLength]; // currentRefPosition is not used for LSRA_DUMP_PRE @@ -10796,6 +10823,7 @@ void LinearScan::verifyFinalAllocation() regRecord->assignedInterval = interval; if (VERBOSE) { + dumpEmptyRefPosition(); printf("Move %-4s ", getRegName(regRecord->regNum)); } } diff --git a/src/coreclr/src/jit/lsra.h b/src/coreclr/src/jit/lsra.h index bc077aad9f77bf..7c4056241dacad 100644 --- a/src/coreclr/src/jit/lsra.h +++ b/src/coreclr/src/jit/lsra.h @@ -965,8 +965,8 @@ class LinearScan : public LinearScanInterface #ifdef DEBUG void checkLastUses(BasicBlock* block); - static int ComputeOperandDstCount(GenTree* operand); - static int ComputeAvailableSrcCount(GenTree* node); + int ComputeOperandDstCount(GenTree* operand); + int ComputeAvailableSrcCount(GenTree* node); #endif // DEBUG void setFrameType(); @@ -1090,7 +1090,8 @@ class LinearScan : public LinearScanInterface RefPosition* buildInternalFloatRegisterDefForNode(GenTree* tree, regMaskTP internalCands = RBM_NONE); void buildInternalRegisterUses(); - void resolveLocalRef(BasicBlock* block, GenTree* treeNode, RefPosition* currentRefPosition); + void writeLocalReg(GenTreeLclVar* lclNode, unsigned varNum, regNumber reg); + void resolveLocalRef(BasicBlock* block, GenTreeLclVar* treeNode, RefPosition* currentRefPosition); void insertMove(BasicBlock* block, GenTree* insertionPoint, unsigned lclNum, regNumber inReg, regNumber outReg); @@ -1575,6 +1576,7 @@ class LinearScan : public LinearScanInterface int BuildBlockStore(GenTreeBlk* blkNode); int BuildModDiv(GenTree* tree); int BuildIntrinsic(GenTree* tree); + void BuildStoreLocDef(GenTreeLclVarCommon* storeLoc, LclVarDsc* varDsc, RefPosition* singleUseRef, int index); int BuildStoreLoc(GenTreeLclVarCommon* tree); int BuildIndir(GenTreeIndir* indirTree); int BuildGCWriteBarrier(GenTree* tree); diff --git a/src/coreclr/src/jit/lsraarm.cpp b/src/coreclr/src/jit/lsraarm.cpp index 8891653f749ca7..165ad929fbc05b 100644 --- a/src/coreclr/src/jit/lsraarm.cpp +++ b/src/coreclr/src/jit/lsraarm.cpp @@ -219,7 +219,6 @@ int LinearScan::BuildNode(GenTree* tree) switch (tree->OperGet()) { case GT_LCL_VAR: - case GT_LCL_FLD: { // We handle tracked variables differently from non-tracked ones. If it is tracked, // we will simply add a use of the tracked variable at its parent/consumer. @@ -230,11 +229,34 @@ int LinearScan::BuildNode(GenTree* tree) // is processed, unless this is marked "isLocalDefUse" because it is a stack-based argument // to a call or an orphaned dead node. // - LclVarDsc* const varDsc = &compiler->lvaTable[tree->AsLclVarCommon()->GetLclNum()]; - if (isCandidateVar(varDsc)) + bool isCandidate = compiler->lvaGetDesc(tree->AsLclVar())->lvLRACandidate; + if (tree->IsRegOptional() && !isCandidate) + { + tree->ClearRegOptional(); + tree->SetContained(); + return 0; + } + if (isCandidate) { return 0; } + } + __fallthrough; + + case GT_LCL_FLD: + { + GenTreeLclVarCommon* const lclVar = tree->AsLclVarCommon(); + if (lclVar->OperIs(GT_LCL_FLD) && lclVar->AsLclFld()->IsOffsetMisaligned()) + { + buildInternalIntRegisterDefForNode(lclVar); // to generate address. + buildInternalIntRegisterDefForNode(lclVar); // to move float into an int reg. + if (lclVar->TypeIs(TYP_DOUBLE)) + { + buildInternalIntRegisterDefForNode(lclVar); // to move the second half into an int reg. + } + buildInternalRegisterUses(); + } + srcCount = 0; BuildDef(tree); } diff --git a/src/coreclr/src/jit/lsraarm64.cpp b/src/coreclr/src/jit/lsraarm64.cpp index c7d06eae442556..c7146d6872af02 100644 --- a/src/coreclr/src/jit/lsraarm64.cpp +++ b/src/coreclr/src/jit/lsraarm64.cpp @@ -76,7 +76,6 @@ int LinearScan::BuildNode(GenTree* tree) break; case GT_LCL_VAR: - case GT_LCL_FLD: { // We handle tracked variables differently from non-tracked ones. If it is tracked, // we will simply add a use of the tracked variable at its parent/consumer. @@ -87,11 +86,22 @@ int LinearScan::BuildNode(GenTree* tree) // is processed, unless this is marked "isLocalDefUse" because it is a stack-based argument // to a call or an orphaned dead node. // - LclVarDsc* const varDsc = &compiler->lvaTable[tree->AsLclVarCommon()->GetLclNum()]; - if (isCandidateVar(varDsc)) + bool isCandidate = compiler->lvaGetDesc(tree->AsLclVar())->lvLRACandidate; + if (tree->IsRegOptional() && !isCandidate) + { + tree->ClearRegOptional(); + tree->SetContained(); + return 0; + } + if (isCandidate) { return 0; } + } + __fallthrough; + + case GT_LCL_FLD: + { srcCount = 0; #ifdef FEATURE_SIMD // Need an additional register to read upper 4 bytes of Vector3. @@ -802,16 +812,12 @@ int LinearScan::BuildSIMD(GenTreeSIMD* simdTree) { case SIMDIntrinsicInit: case SIMDIntrinsicCast: - case SIMDIntrinsicSqrt: - case SIMDIntrinsicAbs: case SIMDIntrinsicConvertToSingle: case SIMDIntrinsicConvertToInt32: case SIMDIntrinsicConvertToDouble: case SIMDIntrinsicConvertToInt64: case SIMDIntrinsicWidenLo: case SIMDIntrinsicWidenHi: - case SIMDIntrinsicCeil: - case SIMDIntrinsicFloor: // No special handling required. break; @@ -858,16 +864,8 @@ int LinearScan::BuildSIMD(GenTreeSIMD* simdTree) case SIMDIntrinsicMul: case SIMDIntrinsicDiv: case SIMDIntrinsicBitwiseAnd: - case SIMDIntrinsicBitwiseAndNot: case SIMDIntrinsicBitwiseOr: - case SIMDIntrinsicBitwiseXor: - case SIMDIntrinsicMin: - case SIMDIntrinsicMax: case SIMDIntrinsicEqual: - case SIMDIntrinsicLessThan: - case SIMDIntrinsicGreaterThan: - case SIMDIntrinsicLessThanOrEqual: - case SIMDIntrinsicGreaterThanOrEqual: // No special handling required. break; @@ -916,23 +914,10 @@ int LinearScan::BuildSIMD(GenTreeSIMD* simdTree) // We have an array and an index, which may be contained. break; - case SIMDIntrinsicOpEquality: - case SIMDIntrinsicOpInEquality: - buildInternalFloatRegisterDefForNode(simdTree); - break; - case SIMDIntrinsicDotProduct: buildInternalFloatRegisterDefForNode(simdTree); break; - case SIMDIntrinsicSelect: - // TODO-ARM64-CQ Allow lowering to see SIMDIntrinsicSelect so we can generate BSL VC, VA, VB - // bsl target register must be VC. Reserve a temp in case we need to shuffle things. - // This will require a different approach, as GenTreeSIMD has only two operands. - assert(!"SIMDIntrinsicSelect not yet supported"); - buildInternalFloatRegisterDefForNode(simdTree); - break; - case SIMDIntrinsicInitArrayX: case SIMDIntrinsicInitFixed: case SIMDIntrinsicCopyToArray: @@ -946,7 +931,6 @@ int LinearScan::BuildSIMD(GenTreeSIMD* simdTree) case SIMDIntrinsicGetY: case SIMDIntrinsicGetZ: case SIMDIntrinsicGetW: - case SIMDIntrinsicInstEquals: case SIMDIntrinsicHWAccel: case SIMDIntrinsicWiden: case SIMDIntrinsicInvalid: @@ -982,7 +966,9 @@ int LinearScan::BuildSIMD(GenTreeSIMD* simdTree) #endif // FEATURE_SIMD #ifdef FEATURE_HW_INTRINSICS + #include "hwintrinsic.h" + //------------------------------------------------------------------------ // BuildHWIntrinsic: Set the NodeInfo for a GT_HWINTRINSIC tree. // @@ -994,131 +980,159 @@ int LinearScan::BuildSIMD(GenTreeSIMD* simdTree) // int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) { - NamedIntrinsic intrinsicId = intrinsicTree->gtHWIntrinsicId; - var_types baseType = intrinsicTree->gtSIMDBaseType; - CORINFO_InstructionSet isa = HWIntrinsicInfo::lookupIsa(intrinsicId); - HWIntrinsicCategory category = HWIntrinsicInfo::lookupCategory(intrinsicId); - int numArgs = HWIntrinsicInfo::lookupNumArgs(intrinsicTree); - - GenTree* op1 = intrinsicTree->gtGetOp1(); - GenTree* op2 = intrinsicTree->gtGetOp2(); - GenTree* op3 = nullptr; - GenTree* lastOp = nullptr; + const HWIntrinsic intrin(intrinsicTree); int srcCount = 0; int dstCount = intrinsicTree->IsValue() ? 1 : 0; - if (op1 == nullptr) - { - assert(op2 == nullptr); - assert(numArgs == 0); - } - else - { - if (op1->OperIsList()) - { - assert(op2 == nullptr); - assert(numArgs >= 3); + bool mayNeedBranchTargetReg = false; - GenTreeArgList* argList = op1->AsArgList(); + if ((intrin.category == HW_Category_IMM) && !HWIntrinsicInfo::NoJmpTableImm(intrin.id)) + { + // We may need to allocate an additional general-purpose register when an intrinsic has a non-const immediate + // operand and the intrinsic does not have an alternative non-const fallback form. + // However, for a case when the operand can take only two possible values - zero and one + // the codegen will use cbnz to do conditional branch. - op1 = argList->Current(); - argList = argList->Rest(); + int immLowerBound = 0; + int immUpperBound = 0; - op2 = argList->Current(); - argList = argList->Rest(); + HWIntrinsicInfo::lookupImmBounds(intrin.id, intrinsicTree->gtSIMDSize, intrinsicTree->gtSIMDBaseType, + &immLowerBound, &immUpperBound); + mayNeedBranchTargetReg = (immLowerBound != 0) || (immUpperBound != 1); + } - op3 = argList->Current(); + if (mayNeedBranchTargetReg) + { + bool needBranchTargetReg = false; - while (argList->Rest() != nullptr) - { - argList = argList->Rest(); - } + switch (intrin.id) + { + case NI_AdvSimd_DuplicateSelectedScalarToVector64: + case NI_AdvSimd_DuplicateSelectedScalarToVector128: + case NI_AdvSimd_Extract: + case NI_AdvSimd_Insert: + case NI_AdvSimd_ShiftLeftLogical: + case NI_AdvSimd_ShiftLeftLogicalSaturate: + case NI_AdvSimd_ShiftLeftLogicalSaturateScalar: + case NI_AdvSimd_ShiftLeftLogicalSaturateUnsigned: + case NI_AdvSimd_ShiftLeftLogicalSaturateUnsignedScalar: + case NI_AdvSimd_ShiftLeftLogicalScalar: + case NI_AdvSimd_ShiftLeftLogicalWideningLower: + case NI_AdvSimd_ShiftLeftLogicalWideningUpper: + case NI_AdvSimd_ShiftRightArithmetic: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateUnsignedLower: + case NI_AdvSimd_ShiftRightArithmeticRounded: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower: + case NI_AdvSimd_ShiftRightArithmeticRoundedScalar: + case NI_AdvSimd_ShiftRightArithmeticScalar: + case NI_AdvSimd_ShiftRightLogical: + case NI_AdvSimd_ShiftRightLogicalNarrowingLower: + case NI_AdvSimd_ShiftRightLogicalNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightLogicalRounded: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingLower: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingSaturateLower: + case NI_AdvSimd_ShiftRightLogicalRoundedScalar: + case NI_AdvSimd_ShiftRightLogicalScalar: + case NI_AdvSimd_Arm64_DuplicateSelectedScalarToVector128: + case NI_AdvSimd_Arm64_ShiftLeftLogicalSaturateScalar: + case NI_AdvSimd_Arm64_ShiftLeftLogicalSaturateUnsignedScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticNarrowingSaturateScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticNarrowingSaturateUnsignedScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticRoundedNarrowingSaturateScalar: + case NI_AdvSimd_Arm64_ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar: + case NI_AdvSimd_Arm64_ShiftRightLogicalNarrowingSaturateScalar: + case NI_AdvSimd_Arm64_ShiftRightLogicalRoundedNarrowingSaturateScalar: + needBranchTargetReg = !intrin.op2->isContainedIntOrIImmed(); + break; - lastOp = argList->Current(); - argList = argList->Rest(); + case NI_AdvSimd_ExtractVector64: + case NI_AdvSimd_ExtractVector128: + case NI_AdvSimd_ShiftRightArithmeticAdd: + case NI_AdvSimd_ShiftRightArithmeticAddScalar: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateUnsignedUpper: + case NI_AdvSimd_ShiftRightArithmeticNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightArithmeticRoundedAdd: + case NI_AdvSimd_ShiftRightArithmeticRoundedAddScalar: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper: + case NI_AdvSimd_ShiftRightArithmeticRoundedNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightLogicalAdd: + case NI_AdvSimd_ShiftRightLogicalAddScalar: + case NI_AdvSimd_ShiftRightLogicalNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightLogicalNarrowingUpper: + case NI_AdvSimd_ShiftRightLogicalRoundedAdd: + case NI_AdvSimd_ShiftRightLogicalRoundedAddScalar: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingSaturateUpper: + case NI_AdvSimd_ShiftRightLogicalRoundedNarrowingUpper: + needBranchTargetReg = !intrin.op3->isContainedIntOrIImmed(); + break; - assert(argList == nullptr); + default: + unreached(); } - else if (op2 != nullptr) - { - assert(numArgs == 2); - lastOp = op2; - } - else - { - assert(numArgs == 1); - lastOp = op1; - } - - assert(lastOp != nullptr); - if ((category == HW_Category_IMM) && !HWIntrinsicInfo::NoJmpTableImm(intrinsicId)) + if (needBranchTargetReg) { - if (HWIntrinsicInfo::isImmOp(intrinsicId, lastOp) && !lastOp->isContainedIntOrIImmed()) - { - assert(!lastOp->IsCnsIntOrI()); - - // We need two extra reg when lastOp isn't a constant so - // the offset into the jump table for the fallback path - // can be computed. - buildInternalIntRegisterDefForNode(intrinsicTree); - buildInternalIntRegisterDefForNode(intrinsicTree); - } + buildInternalIntRegisterDefForNode(intrinsicTree); } + } - // Determine whether this is an RMW operation where op2+ must be marked delayFree so that it - // is not allocated the same register as the target. - const bool isRMW = intrinsicTree->isRMWHWIntrinsic(compiler); + // Determine whether this is an RMW operation where op2+ must be marked delayFree so that it + // is not allocated the same register as the target. + const bool isRMW = intrinsicTree->isRMWHWIntrinsic(compiler); - bool tgtPrefOp1 = false; + bool tgtPrefOp1 = false; + if (intrin.op1 != nullptr) + { // If we have an RMW intrinsic, we want to preference op1Reg to the target if // op1 is not contained. if (isRMW) { - tgtPrefOp1 = !op1->isContained(); + tgtPrefOp1 = !intrin.op1->isContained(); } if (intrinsicTree->OperIsMemoryLoadOrStore()) { - srcCount += BuildAddrUses(op1); + srcCount += BuildAddrUses(intrin.op1); } else if (tgtPrefOp1) { - tgtPrefUse = BuildUse(op1); + tgtPrefUse = BuildUse(intrin.op1); srcCount++; } else { - srcCount += BuildOperandUses(op1); + srcCount += BuildOperandUses(intrin.op1); } + } - if (op2 != nullptr) + if (intrin.op2 != nullptr) + { + if (isRMW) { - if (isRMW) - { - srcCount += BuildDelayFreeUses(op2); + srcCount += BuildDelayFreeUses(intrin.op2); - if (op3 != nullptr) - { - srcCount += BuildDelayFreeUses(op3); - } - } - else + if (intrin.op3 != nullptr) { - srcCount += BuildOperandUses(op2); - - if (op3 != nullptr) - { - srcCount += BuildOperandUses(op3); - } + srcCount += BuildDelayFreeUses(intrin.op3); } } + else + { + srcCount += BuildOperandUses(intrin.op2); - buildInternalRegisterUses(); + if (intrin.op3 != nullptr) + { + srcCount += BuildOperandUses(intrin.op3); + } + } } + buildInternalRegisterUses(); + if (dstCount == 1) { BuildDef(intrinsicTree); diff --git a/src/coreclr/src/jit/lsraarmarch.cpp b/src/coreclr/src/jit/lsraarmarch.cpp index fab94aaf112520..bcc987ca62e132 100644 --- a/src/coreclr/src/jit/lsraarmarch.cpp +++ b/src/coreclr/src/jit/lsraarmarch.cpp @@ -74,23 +74,32 @@ int LinearScan::BuildIndir(GenTreeIndir* indirTree) if (addr->isContained()) { - assert(addr->OperGet() == GT_LEA); - GenTreeAddrMode* lea = addr->AsAddrMode(); - index = lea->Index(); - cns = lea->Offset(); - - // On ARM we may need a single internal register - // (when both conditions are true then we still only need a single internal register) - if ((index != nullptr) && (cns != 0)) + if (addr->OperGet() == GT_LEA) { - // ARM does not support both Index and offset so we need an internal register - buildInternalIntRegisterDefForNode(indirTree); + GenTreeAddrMode* lea = addr->AsAddrMode(); + index = lea->Index(); + cns = lea->Offset(); + + // On ARM we may need a single internal register + // (when both conditions are true then we still only need a single internal register) + if ((index != nullptr) && (cns != 0)) + { + // ARM does not support both Index and offset so we need an internal register + buildInternalIntRegisterDefForNode(indirTree); + } + else if (!emitter::emitIns_valid_imm_for_ldst_offset(cns, emitTypeSize(indirTree))) + { + // This offset can't be contained in the ldr/str instruction, so we need an internal register + buildInternalIntRegisterDefForNode(indirTree); + } } - else if (!emitter::emitIns_valid_imm_for_ldst_offset(cns, emitTypeSize(indirTree))) +#ifdef TARGET_ARM64 + else if (addr->OperGet() == GT_CLS_VAR_ADDR) { - // This offset can't be contained in the ldr/str instruction, so we need an internal register + // Reserve int to load constant from memory (IF_LARGELDC) buildInternalIntRegisterDefForNode(indirTree); } +#endif // TARGET_ARM64 } #ifdef FEATURE_SIMD @@ -126,9 +135,9 @@ int LinearScan::BuildIndir(GenTreeIndir* indirTree) // int LinearScan::BuildCall(GenTreeCall* call) { - bool hasMultiRegRetVal = false; - ReturnTypeDesc* retTypeDesc = nullptr; - regMaskTP dstCandidates = RBM_NONE; + bool hasMultiRegRetVal = false; + const ReturnTypeDesc* retTypeDesc = nullptr; + regMaskTP dstCandidates = RBM_NONE; int srcCount = 0; int dstCount = 0; @@ -173,6 +182,10 @@ int LinearScan::BuildCall(GenTreeCall* call) ctrlExprCandidates = RBM_FASTTAILCALL_TARGET; } } + else if (call->IsR2ROrVirtualStubRelativeIndir()) + { + buildInternalIntRegisterDefForNode(call); + } #ifdef TARGET_ARM else { diff --git a/src/coreclr/src/jit/lsrabuild.cpp b/src/coreclr/src/jit/lsrabuild.cpp index a36965ea9a8a5d..c1a5e0b586b40f 100644 --- a/src/coreclr/src/jit/lsrabuild.cpp +++ b/src/coreclr/src/jit/lsrabuild.cpp @@ -1507,8 +1507,7 @@ int LinearScan::ComputeOperandDstCount(GenTree* operand) // Stores and void-typed operands may be encountered when processing call nodes, which contain // pointers to argument setup stores. assert(operand->OperIsStore() || operand->OperIsBlkOp() || operand->OperIsPutArgStk() || - operand->OperIsCompare() || operand->OperIs(GT_CMP) || operand->IsSIMDEqualityOrInequality() || - operand->TypeGet() == TYP_VOID); + operand->OperIsCompare() || operand->OperIs(GT_CMP) || operand->TypeGet() == TYP_VOID); return 0; } } @@ -1815,12 +1814,23 @@ void LinearScan::insertZeroInitRefPositions() Interval* interval = getIntervalForLocalVar(varIndex); if (compiler->info.compInitMem || varTypeIsGC(varDsc->TypeGet())) { - JITDUMP(" creating ZeroInit\n"); - GenTree* firstNode = getNonEmptyBlock(compiler->fgFirstBB)->firstNode(); - RefPosition* pos = newRefPosition(interval, MinLocation, RefTypeZeroInit, firstNode, - allRegs(interval->registerType)); - pos->setRegOptional(true); - varDsc->lvMustInit = true; + if (interval->recentRefPosition == nullptr) + { + JITDUMP(" creating ZeroInit\n"); + GenTree* firstNode = getNonEmptyBlock(compiler->fgFirstBB)->firstNode(); + RefPosition* pos = newRefPosition(interval, MinLocation, RefTypeZeroInit, firstNode, + allRegs(interval->registerType)); + pos->setRegOptional(true); + varDsc->lvMustInit = true; + } + else + { + // We must only generate one entry RefPosition for each Interval. Since this is not + // a parameter, it can't be RefTypeParamDef, so it must be RefTypeZeroInit, which + // we must have generated for the live-in case above. + assert(interval->recentRefPosition->refType == RefTypeZeroInit); + JITDUMP(" already ZeroInited\n"); + } } } } @@ -2688,7 +2698,7 @@ void LinearScan::BuildDefs(GenTree* tree, int dstCount, regMaskTP dstCandidates) { fixedReg = true; } - ReturnTypeDesc* retTypeDesc = nullptr; + const ReturnTypeDesc* retTypeDesc = nullptr; if (tree->IsMultiRegCall()) { retTypeDesc = tree->AsCall()->GetReturnTypeDesc(); @@ -3063,9 +3073,9 @@ int LinearScan::BuildStoreLoc(GenTreeLclVarCommon* storeLoc) assert(storeLoc->OperGet() == GT_STORE_LCL_VAR); // srcCount = number of registers in which the value is returned by call - GenTreeCall* call = op1->AsCall(); - ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); - srcCount = retTypeDesc->GetReturnRegCount(); + const GenTreeCall* call = op1->AsCall(); + const ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); + srcCount = retTypeDesc->GetReturnRegCount(); for (int i = 0; i < srcCount; ++i) { @@ -3102,7 +3112,20 @@ int LinearScan::BuildStoreLoc(GenTreeLclVarCommon* storeLoc) #endif // !TARGET_64BIT else if (op1->isContained()) { - srcCount = 0; +#ifdef TARGET_XARCH + if (varTypeIsSIMD(storeLoc)) + { + // This is the zero-init case, and we need a register to hold the zero. + // (On Arm64 we can just store REG_ZR.) + assert(op1->IsSIMDZero()); + singleUseRef = BuildUse(op1->gtGetOp1()); + srcCount = 1; + } + else +#endif + { + srcCount = 0; + } } else { @@ -3119,9 +3142,21 @@ int LinearScan::BuildStoreLoc(GenTreeLclVarCommon* storeLoc) } // Third, use internal registers. -#ifdef FEATURE_SIMD +#ifdef TARGET_ARM + if (storeLoc->OperIs(GT_STORE_LCL_FLD) && storeLoc->AsLclFld()->IsOffsetMisaligned()) + { + buildInternalIntRegisterDefForNode(storeLoc); // to generate address. + buildInternalIntRegisterDefForNode(storeLoc); // to move float into an int reg. + if (storeLoc->TypeIs(TYP_DOUBLE)) + { + buildInternalIntRegisterDefForNode(storeLoc); // to move the second half into an int reg. + } + } +#endif // TARGET_ARM + +#if defined(FEATURE_SIMD) || defined(TARGET_ARM) buildInternalRegisterUses(); -#endif // FEATURE_SIMD +#endif // FEATURE_SIMD || TARGET_ARM // Fourth, define destination registers. @@ -3248,9 +3283,9 @@ int LinearScan::BuildReturn(GenTree* tree) { noway_assert(op1->IsMultiRegCall()); - ReturnTypeDesc* retTypeDesc = op1->AsCall()->GetReturnTypeDesc(); - int srcCount = retTypeDesc->GetReturnRegCount(); - useCandidates = retTypeDesc->GetABIReturnRegs(); + const ReturnTypeDesc* retTypeDesc = op1->AsCall()->GetReturnTypeDesc(); + const int srcCount = retTypeDesc->GetReturnRegCount(); + useCandidates = retTypeDesc->GetABIReturnRegs(); for (int i = 0; i < srcCount; i++) { BuildUse(op1, useCandidates, i); diff --git a/src/coreclr/src/jit/lsraxarch.cpp b/src/coreclr/src/jit/lsraxarch.cpp index 524de87f521a16..1239ca23c7bbe1 100644 --- a/src/coreclr/src/jit/lsraxarch.cpp +++ b/src/coreclr/src/jit/lsraxarch.cpp @@ -83,26 +83,6 @@ int LinearScan::BuildNode(GenTree* tree) break; case GT_LCL_VAR: - // Because we do containment analysis before we redo dataflow and identify register - // candidates, the containment analysis only uses !lvDoNotEnregister to estimate register - // candidates. - // If there is a lclVar that is estimated to be register candidate but - // is not, if they were marked regOptional they should now be marked contained instead. - // TODO-XArch-CQ: When this is being called while RefPositions are being created, - // use lvLRACandidate here instead. - if (tree->IsRegOptional()) - { - if (!compiler->lvaTable[tree->AsLclVarCommon()->GetLclNum()].lvTracked || - compiler->lvaTable[tree->AsLclVarCommon()->GetLclNum()].lvDoNotEnregister) - { - tree->ClearRegOptional(); - tree->SetContained(); - return 0; - } - } - __fallthrough; - - case GT_LCL_FLD: { // We handle tracked variables differently from non-tracked ones. If it is tracked, // we will simply add a use of the tracked variable at its parent/consumer. @@ -113,11 +93,27 @@ int LinearScan::BuildNode(GenTree* tree) // is processed, unless this is marked "isLocalDefUse" because it is a stack-based argument // to a call or an orphaned dead node. // - LclVarDsc* const varDsc = &compiler->lvaTable[tree->AsLclVarCommon()->GetLclNum()]; - if (isCandidateVar(varDsc)) + // Because we do containment analysis before we redo dataflow and identify register + // candidates, the containment analysis only uses !lvDoNotEnregister to estimate register + // candidates. + // If there is a lclVar that is estimated to be register candidate but + // is not, if they were marked regOptional they should now be marked contained instead. + bool isCandidate = compiler->lvaGetDesc(tree->AsLclVar())->lvLRACandidate; + if (tree->IsRegOptional() && !isCandidate) + { + tree->ClearRegOptional(); + tree->SetContained(); + return 0; + } + if (isCandidate) { return 0; } + } + __fallthrough; + + case GT_LCL_FLD: + { srcCount = 0; #ifdef FEATURE_SIMD // Need an additional register to read upper 4 bytes of Vector3. @@ -1033,11 +1029,11 @@ int LinearScan::BuildShiftRotate(GenTree* tree) // int LinearScan::BuildCall(GenTreeCall* call) { - bool hasMultiRegRetVal = false; - ReturnTypeDesc* retTypeDesc = nullptr; - int srcCount = 0; - int dstCount = 0; - regMaskTP dstCandidates = RBM_NONE; + bool hasMultiRegRetVal = false; + const ReturnTypeDesc* retTypeDesc = nullptr; + int srcCount = 0; + int dstCount = 0; + regMaskTP dstCandidates = RBM_NONE; assert(!call->isContained()); if (call->TypeGet() != TYP_VOID) @@ -1866,21 +1862,17 @@ int LinearScan::BuildIntrinsic(GenTree* tree) // int LinearScan::BuildSIMD(GenTreeSIMD* simdTree) { - // Only SIMDIntrinsicInit can be contained. Other than that, - // only SIMDIntrinsicOpEquality and SIMDIntrinsicOpInEquality can have 0 dstCount. - int dstCount = simdTree->IsValue() ? 1 : 0; + // All intrinsics have a dstCount of 1 + assert(simdTree->IsValue()); + bool buildUses = true; regMaskTP dstCandidates = RBM_NONE; if (simdTree->isContained()) { + // Only SIMDIntrinsicInit can be contained assert(simdTree->gtSIMDIntrinsicID == SIMDIntrinsicInit); } - else if (dstCount != 1) - { - assert((simdTree->gtSIMDIntrinsicID == SIMDIntrinsicOpEquality) || - (simdTree->gtSIMDIntrinsicID == SIMDIntrinsicOpInEquality)); - } SetContainsAVXFlags(simdTree->gtSIMDSize); GenTree* op1 = simdTree->gtGetOp1(); GenTree* op2 = simdTree->gtGetOp2(); @@ -1960,35 +1952,11 @@ int LinearScan::BuildSIMD(GenTreeSIMD* simdTree) noway_assert(varTypeIsFloating(simdTree->gtSIMDBaseType)); break; - case SIMDIntrinsicAbs: - // float/double vectors: This gets implemented as bitwise-And operation - // with a mask and hence should never see here. - // - // Must be a Vector or Vector Vector - assert(simdTree->gtSIMDBaseType == TYP_INT || simdTree->gtSIMDBaseType == TYP_SHORT || - simdTree->gtSIMDBaseType == TYP_BYTE); - assert(compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported); - break; - - case SIMDIntrinsicSqrt: - // SSE2 has no instruction support for sqrt on integer vectors. - noway_assert(varTypeIsFloating(simdTree->gtSIMDBaseType)); - break; - - case SIMDIntrinsicCeil: - case SIMDIntrinsicFloor: - assert(compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported); - break; - case SIMDIntrinsicAdd: case SIMDIntrinsicSub: case SIMDIntrinsicMul: case SIMDIntrinsicBitwiseAnd: - case SIMDIntrinsicBitwiseAndNot: case SIMDIntrinsicBitwiseOr: - case SIMDIntrinsicBitwiseXor: - case SIMDIntrinsicMin: - case SIMDIntrinsicMax: // SSE2 32-bit integer multiplication requires two temp regs if (simdTree->gtSIMDIntrinsicID == SIMDIntrinsicMul && simdTree->gtSIMDBaseType == TYP_INT && compiler->getSIMDSupportLevel() == SIMD_SSE2_Supported) @@ -2001,40 +1969,6 @@ int LinearScan::BuildSIMD(GenTreeSIMD* simdTree) case SIMDIntrinsicEqual: break; - // SSE2 doesn't support < and <= directly on int vectors. - // Instead we need to use > and >= with swapped operands. - case SIMDIntrinsicLessThan: - case SIMDIntrinsicLessThanOrEqual: - noway_assert(!varTypeIsIntegral(simdTree->gtSIMDBaseType)); - break; - - // SIMDIntrinsicEqual is supported only on non-floating point base type vectors. - // SSE2 cmpps/pd doesn't support > and >= directly on float/double vectors. - // Instead we need to use < and <= with swapped operands. - case SIMDIntrinsicGreaterThan: - noway_assert(!varTypeIsFloating(simdTree->gtSIMDBaseType)); - break; - - case SIMDIntrinsicOpEquality: - case SIMDIntrinsicOpInEquality: - if (simdTree->gtGetOp2()->isContained()) - { - // If the second operand is contained then ContainCheckSIMD has determined - // that PTEST can be used. We only need a single source register and no - // internal registers. - } - else - { - // Can't use PTEST so we need 2 source registers, 1 internal SIMD register - // (to hold the result of PCMPEQD or other similar SIMD compare instruction) - // and one internal INT register (to hold the result of PMOVMSKB). - buildInternalIntRegisterDefForNode(simdTree); - buildInternalFloatRegisterDefForNode(simdTree); - } - // These SIMD nodes only set the condition flags. - dstCount = 0; - break; - case SIMDIntrinsicDotProduct: // Float/Double vectors: // For SSE, or AVX with 32-byte vectors, we also need an internal register @@ -2262,14 +2196,7 @@ int LinearScan::BuildSIMD(GenTreeSIMD* simdTree) srcCount = BuildRMWUses(simdTree); } buildInternalRegisterUses(); - if (dstCount == 1) - { - BuildDef(simdTree, dstCandidates); - } - else - { - assert(dstCount == 0); - } + BuildDef(simdTree, dstCandidates); return srcCount; } #endif // FEATURE_SIMD @@ -2458,8 +2385,10 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) assert(isRMW); // SSE4.1 blendv* hardcode the mask vector (op3) in XMM0 - srcCount += BuildOperandUses(op1); - srcCount += BuildDelayFreeUses(op2); + tgtPrefUse = BuildUse(op1); + + srcCount += 1; + srcCount += op2->isContained() ? BuildOperandUses(op2) : BuildDelayFreeUses(op2); srcCount += BuildDelayFreeUses(op3, RBM_XMM0); buildUses = false; @@ -2493,7 +2422,9 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) assert(isRMW); // CRC32 may operate over "byte" but on x86 only RBM_BYTE_REGS can be used as byte registers. - srcCount += BuildOperandUses(op1); + tgtPrefUse = BuildUse(op1); + + srcCount += 1; srcCount += BuildDelayFreeUses(op2, varTypeIsByte(baseType) ? allByteRegs() : RBM_NONE); buildUses = false; @@ -2539,29 +2470,7 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) // Intrinsics with CopyUpperBits semantics cannot have op1 be contained assert(!copiesUpperBits || !op1->isContained()); - if (op3->isContained()) - { - // 213 form: op1 = (op2 * op1) + [op3] - - if (copiesUpperBits) - { - tgtPrefUse = BuildUse(op1); - - srcCount += 1; - srcCount += BuildDelayFreeUses(op2); - } - else - { - // op1 and op2 are commutative, so don't - // set either to be tgtPref or delayFree - - srcCount += BuildOperandUses(op1); - srcCount += BuildOperandUses(op2); - } - - srcCount += BuildOperandUses(op3); - } - else if (op2->isContained()) + if (op2->isContained()) { // 132 form: op1 = (op1 * op3) + [op2] @@ -2583,25 +2492,22 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) } else { - // 213 form: op1 = (op2 * op1) + op3 + // 213 form: op1 = (op2 * op1) + [op3] + + tgtPrefUse = BuildUse(op1); + srcCount += 1; if (copiesUpperBits) { - tgtPrefUse = BuildUse(op1); - - srcCount += 1; srcCount += BuildDelayFreeUses(op2); } else { - // op1 and op2 are commutative, so don't - // set either to be tgtPref or delayFree - - srcCount += BuildOperandUses(op1); - srcCount += BuildOperandUses(op2); + tgtPrefUse2 = BuildUse(op2); + srcCount += 1; } - srcCount += BuildDelayFreeUses(op3); + srcCount += op3->isContained() ? BuildOperandUses(op3) : BuildDelayFreeUses(op3); } buildUses = false; @@ -2612,10 +2518,15 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) case NI_AVX2_GatherVector256: { assert(numArgs == 3); + assert(!isRMW); + // Any pair of the index, mask, or destination registers should be different srcCount += BuildOperandUses(op1); srcCount += BuildDelayFreeUses(op2); + // op3 should always be contained + assert(op3->isContained()); + // get a tmp register for mask that will be cleared by gather instructions buildInternalFloatRegisterDefForNode(intrinsicTree, allSIMDRegs()); setInternalRegsDelayFree = true; @@ -2628,16 +2539,21 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) case NI_AVX2_GatherMaskVector256: { assert(numArgs == 5); + assert(!isRMW); + assert(intrinsicTree->gtGetOp1()->OperIsList()); + + GenTreeArgList* argList = intrinsicTree->gtGetOp1()->AsArgList()->Rest()->Rest()->Rest(); + GenTree* op4 = argList->Current(); + // Any pair of the index, mask, or destination registers should be different srcCount += BuildOperandUses(op1); - srcCount += BuildOperandUses(op2); + srcCount += BuildDelayFreeUses(op2); srcCount += BuildDelayFreeUses(op3); - - assert(intrinsicTree->gtGetOp1()->OperIsList()); - GenTreeArgList* argList = intrinsicTree->gtGetOp1()->AsArgList(); - GenTree* op4 = argList->Rest()->Rest()->Rest()->Current(); srcCount += BuildDelayFreeUses(op4); + // op5 should always be contained + assert(argList->Rest()->Current()->isContained()); + // get a tmp register for mask that will be cleared by gather instructions buildInternalFloatRegisterDefForNode(intrinsicTree, allSIMDRegs()); setInternalRegsDelayFree = true; @@ -2661,6 +2577,11 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) { srcCount += BuildAddrUses(op1); } + else if (isRMW && !op1->isContained()) + { + tgtPrefUse = BuildUse(op1); + srcCount += 1; + } else { srcCount += BuildOperandUses(op1); @@ -2674,7 +2595,30 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) } else if (isRMW) { - srcCount += BuildDelayFreeUses(op2); + if (!op2->isContained() && HWIntrinsicInfo::IsCommutative(intrinsicId)) + { + // When op2 is not contained and we are commutative, we can set op2 + // to also be a tgtPrefUse. Codegen will then swap the operands. + + tgtPrefUse2 = BuildUse(op2); + srcCount += 1; + } + else if (!op2->isContained() || varTypeIsArithmetic(intrinsicTree->TypeGet())) + { + // When op2 is not contained or if we are producing a scalar value + // we need to mark it as delay free because the operand and target + // exist in the same register set. + + srcCount += BuildDelayFreeUses(op2); + } + else + { + // When op2 is contained and we are not producing a scalar value we + // have no concerns of overwriting op2 because they exist in different + // register sets. + + srcCount += BuildOperandUses(op2); + } } else { @@ -2683,7 +2627,7 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) if (op3 != nullptr) { - srcCount += (isRMW) ? BuildDelayFreeUses(op3) : BuildOperandUses(op3); + srcCount += isRMW ? BuildDelayFreeUses(op3) : BuildOperandUses(op3); } } } diff --git a/src/coreclr/src/jit/morph.cpp b/src/coreclr/src/jit/morph.cpp index fac481935312ac..4fcaa51aa61737 100644 --- a/src/coreclr/src/jit/morph.cpp +++ b/src/coreclr/src/jit/morph.cpp @@ -63,38 +63,41 @@ GenTree* Compiler::fgMorphIntoHelperCall(GenTree* tree, int helper, GenTreeCall: // The helper call ought to be semantically equivalent to the original node, so preserve its VN. tree->ChangeOper(GT_CALL, GenTree::PRESERVE_VN); - tree->AsCall()->gtCallType = CT_HELPER; - tree->AsCall()->gtCallMethHnd = eeFindHelper(helper); - tree->AsCall()->gtCallThisArg = nullptr; - tree->AsCall()->gtCallArgs = args; - tree->AsCall()->gtCallLateArgs = nullptr; - tree->AsCall()->fgArgInfo = nullptr; - tree->AsCall()->gtRetClsHnd = nullptr; - tree->AsCall()->gtCallMoreFlags = 0; - tree->AsCall()->gtInlineCandidateInfo = nullptr; - tree->AsCall()->gtControlExpr = nullptr; + GenTreeCall* call = tree->AsCall(); + + call->gtCallType = CT_HELPER; + call->gtCallMethHnd = eeFindHelper(helper); + call->gtCallThisArg = nullptr; + call->gtCallArgs = args; + call->gtCallLateArgs = nullptr; + call->fgArgInfo = nullptr; + call->gtRetClsHnd = nullptr; + call->gtCallMoreFlags = 0; + call->gtInlineCandidateInfo = nullptr; + call->gtControlExpr = nullptr; #if DEBUG // Helper calls are never candidates. - tree->AsCall()->gtInlineObservation = InlineObservation::CALLSITE_IS_CALL_TO_HELPER; + call->gtInlineObservation = InlineObservation::CALLSITE_IS_CALL_TO_HELPER; #endif // DEBUG #ifdef FEATURE_READYTORUN_COMPILER - tree->AsCall()->gtEntryPoint.addr = nullptr; - tree->AsCall()->gtEntryPoint.accessType = IAT_VALUE; + call->gtEntryPoint.addr = nullptr; + call->gtEntryPoint.accessType = IAT_VALUE; #endif +#if FEATURE_MULTIREG_RET + call->ResetReturnType(); + call->ClearOtherRegs(); + call->ClearOtherRegFlags(); #ifndef TARGET_64BIT if (varTypeIsLong(tree)) { - GenTreeCall* callNode = tree->AsCall(); - ReturnTypeDesc* retTypeDesc = callNode->GetReturnTypeDesc(); - retTypeDesc->Reset(); - retTypeDesc->InitializeLongReturnType(this); - callNode->ClearOtherRegs(); + call->InitializeLongReturnType(); } #endif // !TARGET_64BIT +#endif // FEATURE_MULTIREG_RET if (tree->OperMayThrow(this)) { @@ -115,7 +118,7 @@ GenTree* Compiler::fgMorphIntoHelperCall(GenTree* tree, int helper, GenTreeCall: if (morphArgs) { - tree = fgMorphArgs(tree->AsCall()); + tree = fgMorphArgs(call); } return tree; @@ -1947,8 +1950,6 @@ GenTree* Compiler::fgMakeTmpArgNode(fgArgTabEntry* curArgTabEntry) assert(varTypeIsStruct(type)); if (lvaIsMultiregStruct(varDsc, curArgTabEntry->IsVararg())) { - // ToDo-ARM64: Consider using: arg->ChangeOper(GT_LCL_FLD); - // as that is how UNIX_AMD64_ABI works. // We will create a GT_OBJ for the argument below. // This will be passed by value in two registers. assert(addrNode != nullptr); @@ -2640,7 +2641,7 @@ void Compiler::fgInitArgInfo(GenTreeCall* call) if (call->IsVirtualStub()) { - if (!call->IsTailCallViaHelper()) + if (!call->IsTailCallViaJitHelper()) { GenTree* stubAddrArg = fgGetStubAddrArg(call); // And push the stub address onto the list of arguments @@ -2652,7 +2653,7 @@ void Compiler::fgInitArgInfo(GenTreeCall* call) else { // If it is a VSD call getting dispatched via tail call helper, - // fgMorphTailCallViaHelper() would materialize stub addr as an additional + // fgMorphTailCallViaJitHelper() would materialize stub addr as an additional // parameter added to the original arg list and hence no need to // add as a non-standard arg. } @@ -3230,8 +3231,7 @@ void Compiler::fgInitArgInfo(GenTreeCall* call) { isRegArg = (nonStdRegNum != REG_STK); } -#if defined(TARGET_X86) - else if (call->IsTailCallViaHelper()) + else if (call->IsTailCallViaJitHelper()) { // We have already (before calling fgMorphArgs()) appended the 4 special args // required by the x86 tailcall helper. These args are required to go on the @@ -3242,7 +3242,6 @@ void Compiler::fgInitArgInfo(GenTreeCall* call) isRegArg = false; } } -#endif // defined(TARGET_X86) // Now we know if the argument goes in registers or not and how big it is. CLANG_FORMAT_COMMENT_ANCHOR; @@ -3667,31 +3666,21 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call) #else // UNIX_AMD64_ABI // On Unix, structs are always passed by value. // We only need a copy if we have one of the following: - // - We have a lclVar that has been promoted and is passed in registers. // - The sizes don't match for a non-lclVar argument. // - We have a known struct type (e.g. SIMD) that requires multiple registers. - // TODO-Amd64-Unix-CQ: The first case could and should be handled without copies. // TODO-Amd64-Unix-Throughput: We don't need to keep the structDesc in the argEntry if it's not // actually passed in registers. if (argEntry->isPassedInRegisters()) { assert(argEntry->structDesc.passedInRegisters); - if (lclVar != nullptr) - { - if (lvaGetPromotionType(lclVar->AsLclVarCommon()->GetLclNum()) == - PROMOTION_TYPE_INDEPENDENT) - { - copyBlkClass = objClass; - } - } - else if (argObj->OperIs(GT_OBJ)) + if (argObj->OperIs(GT_OBJ)) { if (passingSize != structSize) { copyBlkClass = objClass; } } - else + else if (lclVar == nullptr) { // This should only be the case of a value directly producing a known struct type. assert(argObj->TypeGet() != TYP_STRUCT); @@ -4813,10 +4802,6 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, // * (must not copy) If the call is a tail call, the use is a last use. // We must skip the copy if we have a fast tail call. // - // * (must copy) However the current slow tail call helper always copies - // the tail call args from the current frame, so we must copy - // if the tail call is a slow tail call. - // // * (may not copy) if the call is noreturn, the use is a last use. // We also check for just one reference here as we are not doing // alias analysis of the call's parameters, or checking if the call @@ -4828,7 +4813,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall* call, const bool isTailCallLastUse = call->IsTailCall(); const bool isCallLastUse = (totalAppearances == 1) && !fgMightHaveLoop(); const bool isNoReturnLastUse = (totalAppearances == 1) && call->IsNoReturn(); - if (!call->IsTailCallViaHelper() && (isTailCallLastUse || isCallLastUse || isNoReturnLastUse)) + if (isTailCallLastUse || isCallLastUse || isNoReturnLastUse) { varDsc->setLvRefCnt(0, RCS_EARLY); args->SetNode(lcl); @@ -4986,6 +4971,10 @@ void Compiler::fgAddSkippedRegsInPromotedStructArg(LclVarDsc* varDsc, // void Compiler::fgFixupStructReturn(GenTree* callNode) { + if (!compDoOldStructRetyping()) + { + return; + } assert(varTypeIsStruct(callNode)); GenTreeCall* call = callNode->AsCall(); @@ -5376,7 +5365,12 @@ GenTree* Compiler::fgMorphArrayIndex(GenTree* tree) tree->ChangeOper(GT_IND); GenTreeIndir* const indir = tree->AsIndir(); indir->Addr() = indexAddr; + bool canCSE = indir->CanCSE(); indir->gtFlags = GTF_IND_ARR_INDEX | (indexAddr->gtFlags & GTF_ALL_EFFECT); + if (!canCSE) + { + indir->SetDoNotCSE(); + } #ifdef DEBUG indexAddr->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED; @@ -6666,38 +6660,199 @@ void Compiler::fgMorphCallInlineHelper(GenTreeCall* call, InlineResult* result) bool Compiler::fgCanFastTailCall(GenTreeCall* callee, const char** failReason) { #if FEATURE_FASTTAILCALL + // To reach here means that the return types of the caller and callee are tail call compatible. // In the case of structs that can be returned in a register, compRetNativeType is set to the actual return type. - // - // In an implicit tail call case callSig may not be available but it is guaranteed to be available - // for explicit tail call cases. The reason implicit tail case callSig may not be available is that - // a call node might be marked as an in-line candidate and could fail to be in-lined. In which case - // fgInline() will replace return value place holder with call node using gtCloneExpr() which is - // currently not copying/setting callSig. CLANG_FORMAT_COMMENT_ANCHOR; #ifdef DEBUG if (callee->IsTailPrefixedCall()) { - assert(impTailCallRetTypeCompatible(info.compRetNativeType, info.compMethodInfo->args.retTypeClass, - (var_types)callee->gtReturnType, callee->callSig->retTypeClass)); + var_types retType = (compDoOldStructRetyping() ? info.compRetNativeType : info.compRetType); + assert(impTailCallRetTypeCompatible(retType, info.compMethodInfo->args.retTypeClass, + (var_types)callee->gtReturnType, callee->gtRetClsHnd)); } #endif assert(!callee->AreArgsComplete()); fgInitArgInfo(callee); + fgArgInfo* argInfo = callee->fgArgInfo; - bool hasMustCopyByrefParameter = false; - size_t calleeArgStackSize = 0; - size_t callerArgStackSize = info.compArgStackSize; + size_t calleeArgStackSize = 0; + size_t callerArgStackSize = info.compArgStackSize; for (unsigned index = 0; index < argInfo->ArgCount(); ++index) { fgArgTabEntry* arg = argInfo->GetArgEntry(index, false); calleeArgStackSize += arg->stackSize(); + } + + auto reportFastTailCallDecision = [&](const char* thisFailReason) { + if (failReason != nullptr) + { + *failReason = thisFailReason; + } + +#ifdef DEBUG + if ((JitConfig.JitReportFastTailCallDecisions()) == 1) + { + if (callee->gtCallType != CT_INDIRECT) + { + const char* methodName; + + methodName = eeGetMethodFullName(callee->gtCallMethHnd); + + printf("[Fast tailcall decision]: Caller: %s\n[Fast tailcall decision]: Callee: %s -- Decision: ", + info.compFullName, methodName); + } + else + { + printf("[Fast tailcall decision]: Caller: %s\n[Fast tailcall decision]: Callee: IndirectCall -- " + "Decision: ", + info.compFullName); + } + + if (thisFailReason == nullptr) + { + printf("Will fast tailcall"); + } + else + { + printf("Will not fast tailcall (%s)", thisFailReason); + } + + printf(" (CallerArgStackSize: %d, CalleeArgStackSize: %d)\n\n", callerArgStackSize, calleeArgStackSize); + } + else + { + if (thisFailReason == nullptr) + { + JITDUMP("[Fast tailcall decision]: Will fast tailcall\n"); + } + else + { + JITDUMP("[Fast tailcall decision]: Will not fast tailcall (%s)\n", thisFailReason); + } + } +#endif // DEBUG + }; + + if (!opts.compFastTailCalls) + { + reportFastTailCallDecision("Configuration doesn't allow fast tail calls"); + return false; + } + + // Note on vararg methods: + // If the caller is vararg method, we don't know the number of arguments passed by caller's caller. + // But we can be sure that in-coming arg area of vararg caller would be sufficient to hold its + // fixed args. Therefore, we can allow a vararg method to fast tail call other methods as long as + // out-going area required for callee is bounded by caller's fixed argument space. + // + // Note that callee being a vararg method is not a problem since we can account the params being passed. + // + // We will currently decide to not fast tail call on Windows armarch if the caller or callee is a vararg + // method. This is due to the ABI differences for native vararg methods for these platforms. There is + // work required to shuffle arguments to the correct locations. + CLANG_FORMAT_COMMENT_ANCHOR; + +#if (defined(TARGET_WINDOWS) && defined(TARGET_ARM)) || (defined(TARGET_WINDOWS) && defined(TARGET_ARM64)) + if (info.compIsVarArgs || callee->IsVarargs()) + { + reportFastTailCallDecision("Fast tail calls with varargs not supported on Windows ARM/ARM64"); + return false; + } +#endif // (defined(TARGET_WINDOWS) && defined(TARGET_ARM)) || defined(TARGET_WINDOWS) && defined(TARGET_ARM64)) + + if (compLocallocUsed) + { + reportFastTailCallDecision("Localloc used"); + return false; + } + +#ifdef TARGET_AMD64 + // Needed for Jit64 compat. + // In future, enabling fast tail calls from methods that need GS cookie + // check would require codegen side work to emit GS cookie check before a + // tail call. + if (getNeedsGSSecurityCookie()) + { + reportFastTailCallDecision("GS Security cookie check required"); + return false; + } +#endif + + // If the NextCallReturnAddress intrinsic is used we should do normal calls. + if (info.compHasNextCallRetAddr) + { + reportFastTailCallDecision("Uses NextCallReturnAddress intrinsic"); + return false; + } + + if (callee->HasRetBufArg()) // RetBuf + { + // If callee has RetBuf param, caller too must have it. + // Otherwise go the slow route. + if (info.compRetBuffArg == BAD_VAR_NUM) + { + reportFastTailCallDecision("Callee has RetBuf but caller does not."); + return false; + } + } + + // For a fast tail call the caller will use its incoming arg stack space to place + // arguments, so if the callee requires more arg stack space than is available here + // the fast tail call cannot be performed. This is common to all platforms. + // Note that the GC'ness of on stack args need not match since the arg setup area is marked + // as non-interruptible for fast tail calls. + if (calleeArgStackSize > callerArgStackSize) + { + reportFastTailCallDecision("Not enough incoming arg space"); + return false; + } + + // For Windows some struct parameters are copied on the local frame + // and then passed by reference. We cannot fast tail call in these situation + // as we need to keep our frame around. + if (fgCallHasMustCopyByrefParameter(callee)) + { + reportFastTailCallDecision("Callee has a byref parameter"); + return false; + } + + reportFastTailCallDecision(nullptr); + return true; +#else // FEATURE_FASTTAILCALL + if (failReason) + *failReason = "Fast tailcalls are not supported on this platform"; + return false; +#endif +} + +//------------------------------------------------------------------------ +// fgCallHasMustCopyByrefParameter: Check to see if this call has a byref parameter that +// requires a struct copy in the caller. +// +// Arguments: +// callee - The callee to check +// +// Return Value: +// Returns true or false based on whether this call has a byref parameter that +// requires a struct copy in the caller. + +#if FEATURE_FASTTAILCALL +bool Compiler::fgCallHasMustCopyByrefParameter(GenTreeCall* callee) +{ + fgArgInfo* argInfo = callee->fgArgInfo; + + bool hasMustCopyByrefParameter = false; + + for (unsigned index = 0; index < argInfo->ArgCount(); ++index) + { + fgArgTabEntry* arg = argInfo->GetArgEntry(index, false); if (arg->isStruct) { @@ -6708,7 +6863,7 @@ bool Compiler::fgCanFastTailCall(GenTreeCall* callee, const char** failReason) hasMustCopyByrefParameter = true; // If we're optimizing, we may be able to pass our caller's byref to our callee, - // and so still be able to tail call. + // and so still be able to avoid a struct copy. if (opts.OptimizationEnabled()) { // First, see if this arg is an implicit byref param. @@ -6914,166 +7069,59 @@ bool Compiler::fgCanFastTailCall(GenTreeCall* callee, const char** failReason) if (hasMustCopyByrefParameter) { - // This arg blocks the tail call. No reason to keep scanning the remaining args. + // This arg requires a struct copy. No reason to keep scanning the remaining args. break; } } } } - auto reportFastTailCallDecision = [&](const char* thisFailReason) { - if (failReason != nullptr) - { - *failReason = thisFailReason; - } - -#ifdef DEBUG - if ((JitConfig.JitReportFastTailCallDecisions()) == 1) - { - if (callee->gtCallType != CT_INDIRECT) - { - const char* methodName; - - methodName = eeGetMethodFullName(callee->gtCallMethHnd); + return hasMustCopyByrefParameter; +} +#endif - printf("[Fast tailcall decision]: Caller: %s\n[Fast tailcall decision]: Callee: %s -- Decision: ", - info.compFullName, methodName); - } - else - { - printf("[Fast tailcall decision]: Caller: %s\n[Fast tailcall decision]: Callee: IndirectCall -- " - "Decision: ", - info.compFullName); - } +//------------------------------------------------------------------------ +// fgMorphPotentialTailCall: Attempt to morph a call that the importer has +// identified as a potential tailcall to an actual tailcall and return the +// placeholder node to use in this case. +// +// Arguments: +// call - The call to morph. +// +// Return Value: +// Returns a node to use if the call was morphed into a tailcall. If this +// function returns a node the call is done being morphed and the new node +// should be used. Otherwise the call will have been demoted to a regular call +// and should go through normal morph. +// +// Notes: +// This is called only for calls that the importer has already identified as +// potential tailcalls. It will do profitability and legality checks and +// classify which kind of tailcall we are able to (or should) do, along with +// modifying the trees to perform that kind of tailcall. +// +GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call) +{ + // It should either be an explicit (i.e. tail prefixed) or an implicit tail call + assert(call->IsTailPrefixedCall() ^ call->IsImplicitTailCall()); - if (thisFailReason == nullptr) - { - printf("Will fast tailcall"); - } - else - { - printf("Will not fast tailcall (%s)", thisFailReason); - } + // It cannot be an inline candidate + assert(!call->IsInlineCandidate()); - printf(" (CallerArgStackSize: %d, CalleeArgStackSize: %d)\n\n", callerArgStackSize, calleeArgStackSize); - } - else + auto failTailCall = [&](const char* reason, unsigned lclNum = BAD_VAR_NUM) { +#ifdef DEBUG + if (verbose) { - if (thisFailReason == nullptr) - { - JITDUMP("[Fast tailcall decision]: Will fast tailcall\n"); - } - else + printf("\nRejecting tail call in morph for call "); + printTreeID(call); + printf(": %s", reason); + if (lclNum != BAD_VAR_NUM) { - JITDUMP("[Fast tailcall decision]: Will not fast tailcall (%s)\n", thisFailReason); + printf(" V%02u", lclNum); } + printf("\n"); } -#endif // DEBUG - }; - - // Note on vararg methods: - // If the caller is vararg method, we don't know the number of arguments passed by caller's caller. - // But we can be sure that in-coming arg area of vararg caller would be sufficient to hold its - // fixed args. Therefore, we can allow a vararg method to fast tail call other methods as long as - // out-going area required for callee is bounded by caller's fixed argument space. - // - // Note that callee being a vararg method is not a problem since we can account the params being passed. - // - // We will currently decide to not fast tail call on Windows armarch if the caller or callee is a vararg - // method. This is due to the ABI differences for native vararg methods for these platforms. There is - // work required to shuffle arguments to the correct locations. - CLANG_FORMAT_COMMENT_ANCHOR; - -#if (defined(TARGET_WINDOWS) && defined(TARGET_ARM)) || (defined(TARGET_WINDOWS) && defined(TARGET_ARM64)) - if (info.compIsVarArgs || callee->IsVarargs()) - { - reportFastTailCallDecision("Fast tail calls with varargs not supported on Windows ARM/ARM64"); - return false; - } -#endif // (defined(TARGET_WINDOWS) && defined(TARGET_ARM)) || defined(TARGET_WINDOWS) && defined(TARGET_ARM64)) - - if (callee->HasRetBufArg()) // RetBuf - { - // If callee has RetBuf param, caller too must have it. - // Otherwise go the slow route. - if (info.compRetBuffArg == BAD_VAR_NUM) - { - reportFastTailCallDecision("Callee has RetBuf but caller does not."); - return false; - } - } - - // For Windows some struct parameters are copied on the local frame - // and then passed by reference. We cannot fast tail call in these situation - // as we need to keep our frame around. - if (hasMustCopyByrefParameter) - { - reportFastTailCallDecision("Callee has a byref parameter"); - return false; - } - - // For a fast tail call the caller will use its incoming arg stack space to place - // arguments, so if the callee requires more arg stack space than is available here - // the fast tail call cannot be performed. This is common to all platforms. - // Note that the GC'ness of on stack args need not match since the arg setup area is marked - // as non-interruptible for fast tail calls. - if (calleeArgStackSize > callerArgStackSize) - { - reportFastTailCallDecision("Not enough incoming arg space"); - return false; - } - - reportFastTailCallDecision(nullptr); - return true; -#else // FEATURE_FASTTAILCALL - if (failReason) - *failReason = "Fast tailcalls are not supported on this platform"; - return false; -#endif -} - -//------------------------------------------------------------------------ -// fgMorphPotentialTailCall: Attempt to morph a call that the importer has -// identified as a potential tailcall to an actual tailcall and return the -// placeholder node to use in this case. -// -// Arguments: -// call - The call to morph. -// -// Return Value: -// Returns a node to use if the call was morphed into a tailcall. If this -// function returns a node the call is done being morphed and the new node -// should be used. Otherwise the call will have been demoted to a regular call -// and should go through normal morph. -// -// Notes: -// This is called only for calls that the importer has already identified as -// potential tailcalls. It will do profitability and legality checks and -// classify which kind of tailcall we are able to (or should) do, along with -// modifying the trees to perform that kind of tailcall. -// -GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call) -{ - // It should either be an explicit (i.e. tail prefixed) or an implicit tail call - assert(call->IsTailPrefixedCall() ^ call->IsImplicitTailCall()); - - // It cannot be an inline candidate - assert(!call->IsInlineCandidate()); - - auto failTailCall = [&](const char* reason, unsigned lclNum = BAD_VAR_NUM) { -#ifdef DEBUG - if (verbose) - { - printf("\nRejecting tail call in morph for call "); - printTreeID(call); - printf(": %s", reason); - if (lclNum != BAD_VAR_NUM) - { - printf(" V%02u", lclNum); - } - printf("\n"); - } -#endif +#endif // for non user funcs, we have no handles to report info.compCompHnd->reportTailCallDecision(nullptr, @@ -7093,32 +7141,18 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call) return nullptr; } - if (compLocallocUsed || compLocallocOptimized) - { - failTailCall("Localloc used"); - return nullptr; - } - // Heuristic: regular calls to noreturn methods can sometimes be // merged, so if we have multiple such calls, we defer tail calling. + // + // TODO: re-examine this; now that we're merging before morph we + // don't need to worry about interfering with merges. + // if (call->IsNoReturn() && (optNoReturnCallCount > 1)) { failTailCall("Defer tail calling throw helper; anticipating merge"); return nullptr; } -#ifdef TARGET_AMD64 - // Needed for Jit64 compat. - // In future, enabling tail calls from methods that need GS cookie check - // would require codegen side work to emit GS cookie check before a tail - // call. - if (getNeedsGSSecurityCookie()) - { - failTailCall("GS Security cookie check"); - return nullptr; - } -#endif - #ifdef DEBUG if (opts.compGcChecks && (info.compRetType == TYP_REF)) { @@ -7235,62 +7269,68 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call) const char* failReason = nullptr; bool canFastTailCall = fgCanFastTailCall(call, &failReason); - void* pfnCopyArgs = nullptr; - // Some tailcalls can (or will) only be done as fast tailcalls. + + CORINFO_TAILCALL_HELPERS tailCallHelpers; + bool tailCallViaJitHelper = false; if (!canFastTailCall) { if (call->IsImplicitTailCall()) { + // Implicit or opportunistic tail calls are always dispatched via fast tail call + // mechanism and never via tail call helper for perf. failTailCall(failReason); return nullptr; } - // Call is tail. prefixed and cannot be dispatched as a fast tail call. + assert(call->IsTailPrefixedCall()); + assert(call->tailCallInfo != nullptr); + // We do not currently handle non-standard args except for VSD stubs. if (!call->IsVirtualStub() && call->HasNonStandardAddedArgs(this)) { - // Methods with non-standard args will have indirection cell or cookie param passed - // in callee trash register (e.g. R11). Tail call helper doesn't preserve it before - // tail calling the target method and hence ".tail" prefix on such calls needs to be - // ignored. - // - // Exception to the above rule: although Virtual Stub Dispatch (VSD) calls require - // extra stub param (e.g. in R11 on Amd64), they can still be called via tail call helper. - // This is done by by adding stubAddr as an additional arg before the original list of - // args. For more details see fgMorphTailCallViaHelper() and CreateTailCallCopyArgsThunk() - // in Stublinkerx86.cpp. failTailCall( "Method with non-standard args passed in callee trash register cannot be tail called via helper"); return nullptr; } -#if defined(TARGET_ARM64) || defined(TARGET_UNIX) - // NYI - TAILCALL_RECURSIVE/TAILCALL_HELPER. - // So, bail out if we can't make fast tail call. - failTailCall(failReason); - return nullptr; -#elif !defined(TARGET_X86) - // Ok, now we are _almost_ there. Since this needs helper make sure we - // can get the required copy thunk. - CorInfoHelperTailCallSpecialHandling handling = CORINFO_TAILCALL_NORMAL; - if (call->IsVirtualStub()) + // On x86 we have a faster mechanism than the general one which we use + // in almost all cases. See fgCanTailCallViaJitHelper for more information. + if (fgCanTailCallViaJitHelper()) { - handling = CORINFO_TAILCALL_STUB_DISPATCH_ARG; + tailCallViaJitHelper = true; } - - pfnCopyArgs = info.compCompHnd->getTailCallCopyArgsThunk(call->callSig, handling); - if (pfnCopyArgs == nullptr) + else { - if (info.compMatchedVM) + // Make sure we can get the helpers. We do this last as the runtime + // will likely be required to generate these. + CORINFO_RESOLVED_TOKEN* token = nullptr; + CORINFO_SIG_INFO* sig = call->tailCallInfo->GetSig(); + unsigned flags = 0; + if (!call->tailCallInfo->IsCalli()) { - failTailCall("TailCallCopyArgsThunk not available."); - return nullptr; + token = call->tailCallInfo->GetToken(); + if (call->tailCallInfo->IsCallvirt()) + { + flags |= CORINFO_TAILCALL_IS_CALLVIRT; + } } - // If we don't have a matched VM, we won't get valid results when asking for a thunk. - pfnCopyArgs = UlongToPtr(0xCA11CA11); // "callcall" + if (call->gtCallThisArg != nullptr) + { + var_types thisArgType = call->gtCallThisArg->GetNode()->TypeGet(); + if (thisArgType != TYP_REF) + { + flags |= CORINFO_TAILCALL_THIS_ARG_IS_BYREF; + } + } + + if (!info.compCompHnd->getTailCallHelpers(token, sig, (CORINFO_GET_TAILCALL_HELPERS_FLAGS)flags, + &tailCallHelpers)) + { + failTailCall("Tail call help not available"); + return nullptr; + } } -#endif } // Check if we can make the tailcall a loop. @@ -7330,15 +7370,15 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call) info.compCompHnd->reportTailCallDecision(nullptr, (call->gtCallType == CT_USER_FUNC) ? call->gtCallMethHnd : nullptr, call->IsTailPrefixedCall(), tailCallResult, nullptr); - // Now actually morph the call. compTailCallUsed = true; // This will prevent inlining this call. call->gtCallMoreFlags |= GTF_CALL_M_TAILCALL; - if (!canFastTailCall) + if (tailCallViaJitHelper) { - call->gtCallMoreFlags |= GTF_CALL_M_TAILCALL_VIA_HELPER; + call->gtCallMoreFlags |= GTF_CALL_M_TAILCALL_VIA_JIT_HELPER; } + #if FEATURE_TAILCALL_OPT if (fastTailCallToLoop) { @@ -7354,11 +7394,6 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call) call->gtCallMoreFlags &= ~GTF_CALL_M_IMPLICIT_TAILCALL; #endif - // Store the call type for later to introduce the correct placeholder. - var_types origCallType = call->TypeGet(); - // Avoid potential extra work for the return (for example, vzeroupper) - call->gtType = TYP_VOID; - #ifdef DEBUG if (verbose) { @@ -7391,18 +7426,6 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call) compCurBB->bbJumpKind = BBJ_RETURN; } - // Do some target-specific transformations (before we process the args, etc.) - // This is needed only for tail prefixed calls that cannot be dispatched as - // fast calls. - if (call->IsTailCallViaHelper()) - { - fgMorphTailCallViaHelper(call, pfnCopyArgs); - - // Force re-evaluating the argInfo. fgMorphTailCallViaHelper will modify the - // argument list, invalidating the argInfo. - call->fgArgInfo = nullptr; - } - GenTree* stmtExpr = fgMorphStmt->GetRootNode(); #ifdef DEBUG @@ -7447,314 +7470,733 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call) assert(treeWithCall == call); } #endif - Statement* nextMorphStmt = fgMorphStmt->GetNextStmt(); - JITDUMP("Remove all stmts after the call.\n"); - while (nextMorphStmt != nullptr) + // Store the call type for later to introduce the correct placeholder. + var_types origCallType = call->TypeGet(); + + GenTree* result; + if (!canFastTailCall && !tailCallViaJitHelper) { - Statement* stmtToRemove = nextMorphStmt; - nextMorphStmt = stmtToRemove->GetNextStmt(); - fgRemoveStmt(compCurBB, stmtToRemove); + // For tailcall via CORINFO_TAILCALL_HELPERS we transform into regular + // calls with (to the JIT) regular control flow so we do not need to do + // much special handling. + result = fgMorphTailCallViaHelpers(call, tailCallHelpers); } + else + { + // Otherwise we will transform into something that does not return. For + // fast tailcalls a "jump" and for tailcall via JIT helper a call to a + // JIT helper that does not return. So peel off everything after the + // call. + Statement* nextMorphStmt = fgMorphStmt->GetNextStmt(); + JITDUMP("Remove all stmts after the call.\n"); + while (nextMorphStmt != nullptr) + { + Statement* stmtToRemove = nextMorphStmt; + nextMorphStmt = stmtToRemove->GetNextStmt(); + fgRemoveStmt(compCurBB, stmtToRemove); + } - bool isRootReplaced = false; - GenTree* root = fgMorphStmt->GetRootNode(); + bool isRootReplaced = false; + GenTree* root = fgMorphStmt->GetRootNode(); - if (root != call) - { - JITDUMP("Replace root node [%06d] with [%06d] tail call node.\n", dspTreeID(root), dspTreeID(call)); - isRootReplaced = true; - fgMorphStmt->SetRootNode(call); + if (root != call) + { + JITDUMP("Replace root node [%06d] with [%06d] tail call node.\n", dspTreeID(root), dspTreeID(call)); + isRootReplaced = true; + fgMorphStmt->SetRootNode(call); + } + + // Avoid potential extra work for the return (for example, vzeroupper) + call->gtType = TYP_VOID; + + // Do some target-specific transformations (before we process the args, + // etc.) for the JIT helper case. + if (tailCallViaJitHelper) + { + fgMorphTailCallViaJitHelper(call); + + // Force re-evaluating the argInfo. fgMorphTailCallViaJitHelper will modify the + // argument list, invalidating the argInfo. + call->fgArgInfo = nullptr; + } + + // Tail call via JIT helper: The VM can't use return address hijacking + // if we're not going to return and the helper doesn't have enough info + // to safely poll, so we poll before the tail call, if the block isn't + // already safe. Since tail call via helper is a slow mechanism it + // doen't matter whether we emit GC poll. his is done to be in parity + // with Jit64. Also this avoids GC info size increase if all most all + // methods are expected to be tail calls (e.g. F#). + // + // Note that we can avoid emitting GC-poll if we know that the current + // BB is dominated by a Gc-SafePoint block. But we don't have dominator + // info at this point. One option is to just add a place holder node for + // GC-poll (e.g. GT_GCPOLL) here and remove it in lowering if the block + // is dominated by a GC-SafePoint. For now it not clear whether + // optimizing slow tail calls is worth the effort. As a low cost check, + // we check whether the first and current basic blocks are + // GC-SafePoints. + // + // Fast Tail call as epilog+jmp - No need to insert GC-poll. Instead, + // fgSetBlockOrder() is going to mark the method as fully interruptible + // if the block containing this tail call is reachable without executing + // any call. + if (canFastTailCall || (fgFirstBB->bbFlags & BBF_GC_SAFE_POINT) || (compCurBB->bbFlags & BBF_GC_SAFE_POINT) || + !fgCreateGCPoll(GCPOLL_INLINE, compCurBB)) + { + // We didn't insert a poll block, so we need to morph the call now + // (Normally it will get morphed when we get to the split poll block) + GenTree* temp = fgMorphCall(call); + noway_assert(temp == call); + } + + // Fast tail call: in case of fast tail calls, we need a jmp epilog and + // hence mark it as BBJ_RETURN with BBF_JMP flag set. + noway_assert(compCurBB->bbJumpKind == BBJ_RETURN); + if (canFastTailCall) + { + compCurBB->bbFlags |= BBF_HAS_JMP; + } + else + { + // We call CORINFO_HELP_TAILCALL which does not return, so we will + // not need epilogue. + compCurBB->bbJumpKind = BBJ_THROW; + } + + if (isRootReplaced) + { + // We have replaced the root node of this stmt and deleted the rest, + // but we still have the deleted, dead nodes on the `fgMorph*` stack + // if the root node was an `ASG`, `RET` or `CAST`. + // Return a zero con node to exit morphing of the old trees without asserts + // and forbid POST_ORDER morphing doing something wrong with our call. + var_types callType; + if (varTypeIsStruct(origCallType)) + { + CORINFO_CLASS_HANDLE retClsHnd = call->gtRetClsHnd; + Compiler::structPassingKind howToReturnStruct; + callType = getReturnTypeForStruct(retClsHnd, &howToReturnStruct); + assert((howToReturnStruct != SPK_Unknown) && (howToReturnStruct != SPK_ByReference)); + if (howToReturnStruct == SPK_ByValue) + { + callType = TYP_I_IMPL; + } + else if (howToReturnStruct == SPK_ByValueAsHfa || varTypeIsSIMD(callType)) + { + callType = TYP_FLOAT; + } + assert((callType != TYP_UNKNOWN) && !varTypeIsStruct(callType)); + } + else + { + callType = origCallType; + } + assert((callType != TYP_UNKNOWN) && !varTypeIsStruct(callType)); + callType = genActualType(callType); + + GenTree* zero = gtNewZeroConNode(callType); + result = fgMorphTree(zero); + } + else + { + result = call; + } } - // Tail call via helper: The VM can't use return address hijacking if we're - // not going to return and the helper doesn't have enough info to safely poll, - // so we poll before the tail call, if the block isn't already safe. Since - // tail call via helper is a slow mechanism it doen't matter whether we emit - // GC poll. This is done to be in parity with Jit64. Also this avoids GC info - // size increase if all most all methods are expected to be tail calls (e.g. F#). - // - // Note that we can avoid emitting GC-poll if we know that the current BB is - // dominated by a Gc-SafePoint block. But we don't have dominator info at this - // point. One option is to just add a place holder node for GC-poll (e.g. GT_GCPOLL) - // here and remove it in lowering if the block is dominated by a GC-SafePoint. For - // now it not clear whether optimizing slow tail calls is worth the effort. As a - // low cost check, we check whether the first and current basic blocks are - // GC-SafePoints. - // - // Fast Tail call as epilog+jmp - No need to insert GC-poll. Instead, fgSetBlockOrder() - // is going to mark the method as fully interruptible if the block containing this tail - // call is reachable without executing any call. - if (canFastTailCall || (fgFirstBB->bbFlags & BBF_GC_SAFE_POINT) || (compCurBB->bbFlags & BBF_GC_SAFE_POINT) || - !fgCreateGCPoll(GCPOLL_INLINE, compCurBB)) + return result; +} + +//------------------------------------------------------------------------ +// fgMorphTailCallViaHelpers: Transform the given GT_CALL tree for tailcall code +// generation. +// +// Arguments: +// call - The call to transform +// helpers - The tailcall helpers provided by the runtime. +// +// Return Value: +// Returns the transformed node. +// +// Notes: +// This transforms +// GT_CALL +// {callTarget} +// {this} +// {args} +// into +// GT_COMMA +// GT_CALL StoreArgsStub +// {callTarget} (depending on flags provided by the runtime) +// {this} (as a regular arg) +// {args} +// GT_COMMA +// GT_CALL Dispatcher +// GT_ADDR ReturnAddress +// {CallTargetStub} +// GT_ADDR ReturnValue +// GT_LCL ReturnValue +// whenever the call node returns a value. If the call node does not return a +// value the last comma will not be there. +// +GenTree* Compiler::fgMorphTailCallViaHelpers(GenTreeCall* call, CORINFO_TAILCALL_HELPERS& help) +{ + // R2R requires different handling but we don't support tailcall via + // helpers in R2R yet, so just leave it for now. + // TODO: R2R: TailCallViaHelper + assert(!opts.IsReadyToRun()); + + JITDUMP("fgMorphTailCallViaHelpers (before):\n"); + DISPTREE(call); + + // Don't support tail calling helper methods + assert(call->gtCallType != CT_HELPER); + + // We come this route only for tail prefixed calls that cannot be dispatched as + // fast tail calls + assert(!call->IsImplicitTailCall()); + assert(!fgCanFastTailCall(call, nullptr)); + + // If VSD then get rid of arg to VSD since we turn this into a direct call. + // The extra arg will be the first arg so this needs to be done before we + // handle the retbuf below. + if (call->IsVirtualStub()) { - // We didn't insert a poll block, so we need to morph the call now - // (Normally it will get morphed when we get to the split poll block) - GenTree* temp = fgMorphCall(call); - noway_assert(temp == call); + JITDUMP("This is a VSD\n"); +#if FEATURE_FASTTAILCALL + // fgInitArgInfo has been called from fgCanFastTailCall and it added the stub address + // to the arg list. Remove it now. + call->gtCallArgs = call->gtCallArgs->GetNext(); + // We changed args so recompute info. + call->fgArgInfo = nullptr; +#endif + + call->gtFlags &= ~GTF_CALL_VIRT_STUB; } - // Tail call via helper: we just call CORINFO_HELP_TAILCALL, and it jumps to - // the target. So we don't need an epilog - just like CORINFO_HELP_THROW. - // - // Fast tail call: in case of fast tail calls, we need a jmp epilog and - // hence mark it as BBJ_RETURN with BBF_JMP flag set. - noway_assert(compCurBB->bbJumpKind == BBJ_RETURN); + GenTree* callDispatcherAndGetResult = fgCreateCallDispatcherAndGetResult(call, help.hCallTarget, help.hDispatcher); - if (canFastTailCall) + // Change the call to a call to the StoreArgs stub. + if (call->HasRetBufArg()) { - compCurBB->bbFlags |= BBF_HAS_JMP; + JITDUMP("Removing retbuf"); + call->gtCallArgs = call->gtCallArgs->GetNext(); + call->gtCallMoreFlags &= ~GTF_CALL_M_RETBUFFARG; + + // We changed args so recompute info. + call->fgArgInfo = nullptr; } - else + + // We may need to pass the target, for instance for calli or generic methods + // where we pass instantiating stub. + if ((help.flags & CORINFO_TAILCALL_STORE_TARGET) != 0) { - compCurBB->bbJumpKind = BBJ_THROW; + // If asked to store target and we have a type arg we will store + // instantiating stub, so in that case we should not pass the type arg. + if (call->tailCallInfo->GetSig()->hasTypeArg()) + { + JITDUMP("Removing type arg"); + + assert(call->gtCallArgs != nullptr); + if (Target::g_tgtArgOrder == Target::ARG_ORDER_R2L) + { + // Generic context is first arg + call->gtCallArgs = call->gtCallArgs->GetNext(); + } + else + { + // Generic context is last arg + GenTreeCall::Use** lastArgSlot = &call->gtCallArgs; + while ((*lastArgSlot)->GetNext() != nullptr) + { + lastArgSlot = &(*lastArgSlot)->NextRef(); + } + + *lastArgSlot = nullptr; + } + call->fgArgInfo = nullptr; + } + + JITDUMP("Adding target since VM requested it\n"); + GenTree* target; + if (call->tailCallInfo->IsCalli()) + { + noway_assert(call->gtCallType == CT_INDIRECT && call->gtCallAddr != nullptr); + target = call->gtCallAddr; + } + else + { + CORINFO_CALL_INFO callInfo; + unsigned flags = CORINFO_CALLINFO_LDFTN; + if (call->tailCallInfo->IsCallvirt()) + { + flags |= CORINFO_CALLINFO_CALLVIRT; + } + + eeGetCallInfo(call->tailCallInfo->GetToken(), nullptr, (CORINFO_CALLINFO_FLAGS)flags, &callInfo); + + if (!call->tailCallInfo->IsCallvirt() || + ((callInfo.methodFlags & (CORINFO_FLG_FINAL | CORINFO_FLG_STATIC)) != 0) || + ((callInfo.methodFlags & CORINFO_FLG_VIRTUAL) == 0)) + { + target = getMethodPointerTree(call->tailCallInfo->GetToken(), &callInfo); + } + else + { + assert(call->gtCallThisArg != nullptr); + // TODO: Proper cloning of the this pointer. + target = getVirtMethodPointerTree(gtCloneExpr(call->gtCallThisArg->GetNode()), + call->tailCallInfo->GetToken(), &callInfo); + } + } + + // Insert target as last arg + GenTreeCall::Use** newArgSlot = &call->gtCallArgs; + while (*newArgSlot != nullptr) + { + newArgSlot = &(*newArgSlot)->NextRef(); + } + + *newArgSlot = gtNewCallArgs(target); + + call->fgArgInfo = nullptr; } - if (isRootReplaced) + // Put 'this' in normal param list + if (call->gtCallThisArg != nullptr) { - // We have replaced the root node of this stmt and deleted the rest, - // but we still have the deleted, dead nodes on the `fgMorph*` stack - // if the root node was an `ASG`, `RET` or `CAST`. - // Return a zero con node to exit morphing of the old trees without asserts - // and forbid POST_ORDER morphing doing something wrong with our call. - var_types callType; - if (varTypeIsStruct(origCallType)) + JITDUMP("Moving this pointer into arg list\n"); + GenTree* thisPtr = nullptr; + GenTree* objp = call->gtCallThisArg->GetNode(); + call->gtCallThisArg = nullptr; + + if (call->NeedsNullCheck()) { - CORINFO_CLASS_HANDLE retClsHnd = call->gtRetClsHnd; - Compiler::structPassingKind howToReturnStruct; - callType = getReturnTypeForStruct(retClsHnd, &howToReturnStruct); - assert((howToReturnStruct != SPK_Unknown) && (howToReturnStruct != SPK_ByReference)); - if (howToReturnStruct == SPK_ByValue) + // clone "this" if "this" has no side effects. + if ((objp->gtFlags & GTF_SIDE_EFFECT) == 0) { - callType = TYP_I_IMPL; + thisPtr = gtClone(objp, true); } - else if (howToReturnStruct == SPK_ByValueAsHfa || varTypeIsSIMD(callType)) + + var_types vt = objp->TypeGet(); + if (thisPtr == nullptr) + { + // create a temp if either "this" has side effects or "this" is too complex to clone. + + // tmp = "this" + unsigned lclNum = lvaGrabTemp(true DEBUGARG("tail call thisptr")); + GenTree* asg = gtNewTempAssign(lclNum, objp); + + // COMMA(tmp = "this", deref(tmp)) + GenTree* tmp = gtNewLclvNode(lclNum, vt); + GenTree* nullcheck = gtNewNullCheck(tmp, compCurBB); + asg = gtNewOperNode(GT_COMMA, TYP_VOID, asg, nullcheck); + + // COMMA(COMMA(tmp = "this", deref(tmp)), tmp) + thisPtr = gtNewOperNode(GT_COMMA, vt, asg, gtNewLclvNode(lclNum, vt)); + } + else { - callType = TYP_FLOAT; + // thisPtr = COMMA(deref("this"), "this") + GenTree* nullcheck = gtNewNullCheck(thisPtr, compCurBB); + thisPtr = gtNewOperNode(GT_COMMA, vt, nullcheck, gtClone(objp, true)); } - assert((callType != TYP_UNKNOWN) && !varTypeIsStruct(callType)); + + call->gtFlags &= ~GTF_CALL_NULLCHECK; + } + else + { + thisPtr = objp; + } + + // During rationalization tmp="this" and null check will be materialized + // in the right execution order. + assert(thisPtr != nullptr); + call->gtCallArgs = gtPrependNewCallArg(thisPtr, call->gtCallArgs); + call->fgArgInfo = nullptr; + } + + // This is now a direct call to the store args stub and not a tailcall. + call->gtCallType = CT_USER_FUNC; + call->gtCallMethHnd = help.hStoreArgs; + call->gtFlags &= ~GTF_CALL_VIRT_KIND_MASK; + call->gtCallMoreFlags &= ~(GTF_CALL_M_TAILCALL | GTF_CALL_M_DELEGATE_INV | GTF_CALL_M_WRAPPER_DELEGATE_INV); + + // The store-args stub returns no value. + call->gtRetClsHnd = nullptr; + call->gtType = TYP_VOID; + call->gtReturnType = TYP_VOID; + + GenTree* finalTree = + gtNewOperNode(GT_COMMA, callDispatcherAndGetResult->TypeGet(), call, callDispatcherAndGetResult); + + finalTree = fgMorphTree(finalTree); + + JITDUMP("fgMorphTailCallViaHelpers (after):\n"); + DISPTREE(finalTree); + return finalTree; +} + +//------------------------------------------------------------------------ +// fgCreateCallDispatcherAndGetResult: Given a call +// CALL +// {callTarget} +// {retbuf} +// {this} +// {args} +// create a similarly typed node that calls the tailcall dispatcher and returns +// the result, as in the following: +// COMMA +// CALL TailCallDispatcher +// ADDR ReturnAddress +// &CallTargetFunc +// ADDR RetValue +// RetValue +// If the call has type TYP_VOID, only create the CALL node. +// +// Arguments: +// origCall - the call +// callTargetStubHnd - the handle of the CallTarget function (this is a special +// IL stub created by the runtime) +// dispatcherHnd - the handle of the tailcall dispatcher function +// +// Return Value: +// A node that can be used in place of the original call. +// +GenTree* Compiler::fgCreateCallDispatcherAndGetResult(GenTreeCall* origCall, + CORINFO_METHOD_HANDLE callTargetStubHnd, + CORINFO_METHOD_HANDLE dispatcherHnd) +{ + GenTreeCall* callDispatcherNode = + gtNewCallNode(CT_USER_FUNC, dispatcherHnd, TYP_VOID, nullptr, fgMorphStmt->GetILOffsetX()); + // The dispatcher has signature + // void DispatchTailCalls(void* callersRetAddrSlot, void* callTarget, void* retValue) + + // Add return value arg. + GenTree* retValArg; + GenTree* retVal = nullptr; + unsigned int newRetLcl = BAD_VAR_NUM; + + // Use existing retbuf if there is one. + if (origCall->HasRetBufArg()) + { + JITDUMP("Transferring retbuf\n"); + GenTree* retBufArg = origCall->gtCallArgs->GetNode(); + assert((info.compRetBuffArg != BAD_VAR_NUM) && retBufArg->OperIsLocal() && + (retBufArg->AsLclVarCommon()->GetLclNum() == info.compRetBuffArg)); + + retValArg = retBufArg; + if (origCall->gtType != TYP_VOID) + { + retVal = gtClone(retValArg); + } + } + else if (origCall->gtType != TYP_VOID) + { + JITDUMP("Creating a new temp for the return value\n"); + newRetLcl = lvaGrabTemp(false DEBUGARG("Return value for tail call dispatcher")); + if (varTypeIsStruct(origCall->gtType)) + { + lvaSetStruct(newRetLcl, origCall->gtRetClsHnd, false); } else { - callType = origCallType; + // Since we pass a reference to the return value to the dispatcher + // we need to use the real return type so we can normalize it on + // load when we return it. + lvaTable[newRetLcl].lvType = (var_types)origCall->gtReturnType; + } + + lvaSetVarAddrExposed(newRetLcl); + + retValArg = + gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(newRetLcl, genActualType(lvaTable[newRetLcl].lvType))); + retVal = gtNewLclvNode(newRetLcl, genActualType(lvaTable[newRetLcl].lvType)); + + if (varTypeIsStruct(origCall->gtType)) + { + retVal = impFixupStructReturnType(retVal, origCall->gtRetClsHnd); } - GenTree* zero = gtNewZeroConNode(callType); - return fgMorphTree(zero); } else { - return call; + JITDUMP("No return value so using null pointer as arg\n"); + retValArg = gtNewZeroConNode(TYP_I_IMPL); + } + + callDispatcherNode->gtCallArgs = gtPrependNewCallArg(retValArg, callDispatcherNode->gtCallArgs); + + // Add callTarget + callDispatcherNode->gtCallArgs = + gtPrependNewCallArg(new (this, GT_FTN_ADDR) GenTreeFptrVal(TYP_I_IMPL, callTargetStubHnd), + callDispatcherNode->gtCallArgs); + + // Add the caller's return address slot. + if (lvaRetAddrVar == BAD_VAR_NUM) + { + lvaRetAddrVar = lvaGrabTemp(false DEBUGARG("Return address")); + lvaTable[lvaRetAddrVar].lvType = TYP_I_IMPL; + lvaSetVarAddrExposed(lvaRetAddrVar); + } + + GenTree* retAddrSlot = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaRetAddrVar, TYP_I_IMPL)); + callDispatcherNode->gtCallArgs = gtPrependNewCallArg(retAddrSlot, callDispatcherNode->gtCallArgs); + + if (origCall->gtType == TYP_VOID) + { + return callDispatcherNode; + } + + assert(retVal != nullptr); + GenTree* comma = gtNewOperNode(GT_COMMA, origCall->TypeGet(), callDispatcherNode, retVal); + // The JIT seems to want to CSE this comma and messes up multi-reg ret + // values in the process. Just avoid CSE'ing this tree entirely in that + // case. + if (origCall->HasMultiRegRetVal()) + { + comma->gtFlags |= GTF_DONT_CSE; + } + + return comma; +} + +//------------------------------------------------------------------------ +// getMethodPointerTree: get a method pointer tree +// +// Arguments: +// pResolvedToken - resolved token of the call +// pCallInfo - the call info of the call +// +// Return Value: +// A node representing the method pointer +// +GenTree* Compiler::getMethodPointerTree(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CALL_INFO* pCallInfo) +{ + switch (pCallInfo->kind) + { + case CORINFO_CALL: + return new (this, GT_FTN_ADDR) GenTreeFptrVal(TYP_I_IMPL, pCallInfo->hMethod); + case CORINFO_CALL_CODE_POINTER: + return getLookupTree(pResolvedToken, &pCallInfo->codePointerLookup, GTF_ICON_FTN_ADDR, pCallInfo->hMethod); + default: + noway_assert(!"unknown call kind"); + return nullptr; } } -/***************************************************************************** - * - * Transform the given GT_CALL tree for tail call code generation. - */ -void Compiler::fgMorphTailCallViaHelper(GenTreeCall* call, void* pfnCopyArgs) +//------------------------------------------------------------------------ +// getLookupTree: get a lookup tree +// +// Arguments: +// pResolvedToken - resolved token of the call +// pLookup - the lookup to get the tree for +// handleFlags - flags to set on the result node +// compileTimeHandle - compile-time handle corresponding to the lookup +// +// Return Value: +// A node representing the lookup tree +// +GenTree* Compiler::getLookupTree(CORINFO_RESOLVED_TOKEN* pResolvedToken, + CORINFO_LOOKUP* pLookup, + unsigned handleFlags, + void* compileTimeHandle) { -#if defined(TARGET_UNIX) - noway_assert(!"Slow tail calls not supported on non-Windows platforms."); -#endif - - JITDUMP("fgMorphTailCallViaHelper (before):\n"); - DISPTREE(call); - - // The runtime requires that we perform a null check on the `this` argument before - // tail calling to a virtual dispatch stub. This requirement is a consequence of limitations - // in the runtime's ability to map an AV to a NullReferenceException if - // the AV occurs in a dispatch stub that has unmanaged caller. - if (call->IsVirtualStub()) + if (!pLookup->lookupKind.needsRuntimeLookup) { - call->gtFlags |= GTF_CALL_NULLCHECK; - -#if defined(TARGET_AMD64) - // If we already inited arg info here then we will have added the VSD - // arg on AMD64. So we remove it here as we will handle this case - // specially below. - fgArgInfo* argInfo = call->fgArgInfo; - assert(argInfo != nullptr); + // No runtime lookup is required. + // Access is direct or memory-indirect (of a fixed address) reference - GenTreeCall::Use* vsdArg = nullptr; + CORINFO_GENERIC_HANDLE handle = nullptr; + void* pIndirection = nullptr; + assert(pLookup->constLookup.accessType != IAT_PPVALUE && pLookup->constLookup.accessType != IAT_RELPVALUE); - for (unsigned index = 0; index < argInfo->ArgCount(); ++index) + if (pLookup->constLookup.accessType == IAT_VALUE) { - fgArgTabEntry* arg = argInfo->GetArgEntry(index, false); - if (arg->isNonStandard) - { - // The only supported nonstandard arg for slow tailcalls is - // VSD arg. - assert(vsdArg == nullptr); - vsdArg = arg->use; -#ifndef DEBUG - break; -#endif - } + handle = pLookup->constLookup.handle; } - - assert(vsdArg != nullptr); - // Find the arg in the linked list keeping track of the pointer to it so - // we can unlink it. - GenTreeCall::Use** ptr = &call->gtCallArgs; - while ((*ptr) != vsdArg) + else if (pLookup->constLookup.accessType == IAT_PVALUE) { - ptr = &(*ptr)->NextRef(); + pIndirection = pLookup->constLookup.addr; } - *ptr = vsdArg->GetNext(); -#endif + return gtNewIconEmbHndNode(handle, pIndirection, handleFlags, compileTimeHandle); } -#if defined(TARGET_ARM) - // For the helper-assisted tail calls, we need to push all the arguments - // into a single list, and then add a few extra at the beginning + return getRuntimeLookupTree(pResolvedToken, pLookup, compileTimeHandle); +} - // Check for PInvoke call types that we don't handle in codegen yet. - assert(!call->IsUnmanaged()); - assert(call->IsVirtual() || (call->gtCallType != CT_INDIRECT) || (call->gtCallCookie == NULL)); +//------------------------------------------------------------------------ +// getRuntimeLookupTree: get a tree for a runtime lookup +// +// Arguments: +// pResolvedToken - resolved token of the call +// pLookup - the lookup to get the tree for +// compileTimeHandle - compile-time handle corresponding to the lookup +// +// Return Value: +// A node representing the runtime lookup tree +// +GenTree* Compiler::getRuntimeLookupTree(CORINFO_RESOLVED_TOKEN* pResolvedToken, + CORINFO_LOOKUP* pLookup, + void* compileTimeHandle) +{ + assert(!compIsForInlining()); - // First move the this pointer (if any) onto the regular arg list - GenTree* thisPtr = NULL; - if (call->gtCallThisArg != nullptr) + CORINFO_RUNTIME_LOOKUP* pRuntimeLookup = &pLookup->runtimeLookup; + + // If pRuntimeLookup->indirections is equal to CORINFO_USEHELPER, it specifies that a run-time helper should be + // used; otherwise, it specifies the number of indirections via pRuntimeLookup->offsets array. + if ((pRuntimeLookup->indirections == CORINFO_USEHELPER) || pRuntimeLookup->testForNull || + pRuntimeLookup->testForFixup) { - GenTree* objp = call->gtCallThisArg->GetNode(); - call->gtCallThisArg = nullptr; + // If the first condition is true, runtime lookup tree is available only via the run-time helper function. + // TODO-CQ If the second or third condition is true, we are always using the slow path since we can't + // introduce control flow at this point. See impRuntimeLookupToTree for the logic to avoid calling the helper. + // The long-term solution is to introduce a new node representing a runtime lookup, create instances + // of that node both in the importer and here, and expand the node in lower (introducing control flow if + // necessary). + return gtNewRuntimeLookupHelperCallNode(pRuntimeLookup, + getRuntimeContextTree(pLookup->lookupKind.runtimeLookupKind), + compileTimeHandle); + } - if ((call->gtFlags & GTF_CALL_NULLCHECK) || call->IsVirtualVtable()) + GenTree* result = getRuntimeContextTree(pLookup->lookupKind.runtimeLookupKind); + + ArrayStack stmts(getAllocator(CMK_ArrayStack)); + + auto cloneTree = [&](GenTree** tree DEBUGARG(const char* reason)) { + if (!((*tree)->gtFlags & GTF_GLOB_EFFECT)) { - thisPtr = gtClone(objp, true); - var_types vt = objp->TypeGet(); - if (thisPtr == NULL) - { - // Too complex, so use a temp - unsigned lclNum = lvaGrabTemp(true DEBUGARG("tail call thisptr")); - GenTree* asg = gtNewTempAssign(lclNum, objp); - if (!call->IsVirtualVtable()) - { - // Add an indirection to get the nullcheck - GenTree* tmp = gtNewLclvNode(lclNum, vt); - GenTree* nullcheck = gtNewNullCheck(tmp, compCurBB); - asg = gtNewOperNode(GT_COMMA, TYP_VOID, asg, nullcheck); - } - objp = gtNewOperNode(GT_COMMA, vt, asg, gtNewLclvNode(lclNum, vt)); - thisPtr = gtNewLclvNode(lclNum, vt); - } - else if (!call->IsVirtualVtable()) + GenTree* clone = gtClone(*tree, true); + + if (clone) { - GenTree* nullcheck = gtNewNullCheck(thisPtr, compCurBB); - objp = gtNewOperNode(GT_COMMA, vt, nullcheck, objp); - thisPtr = gtClone(thisPtr, true); + return clone; } - - call->gtFlags &= ~GTF_CALL_NULLCHECK; } - call->gtCallArgs = gtPrependNewCallArg(objp, call->gtCallArgs); - } - - // Add the extra VSD parameter if needed - if (call->IsVirtualStub()) - { - GenTree* stubAddrArg = fgGetStubAddrArg(call); - - // We don't need this arg to be in the normal stub register, so - // clear out the register assignment. - assert(stubAddrArg->GetRegNum() == virtualStubParamInfo->GetReg()); - stubAddrArg->SetRegNum(REG_NA); + unsigned temp = lvaGrabTemp(true DEBUGARG(reason)); + stmts.Push(gtNewTempAssign(temp, *tree)); + *tree = gtNewLclvNode(temp, lvaGetActualType(temp)); + return gtNewLclvNode(temp, lvaGetActualType(temp)); + }; - // And push the stub address onto the list of arguments - call->gtCallArgs = gtPrependNewCallArg(stubAddrArg, call->gtCallArgs); - } - else if (call->IsVirtualVtable()) + // Apply repeated indirections + for (WORD i = 0; i < pRuntimeLookup->indirections; i++) { - noway_assert(thisPtr != NULL); - - GenTree* add = gtNewOperNode(GT_ADD, TYP_I_IMPL, thisPtr, gtNewIconNode(VPTR_OFFS, TYP_I_IMPL)); - GenTree* vtbl = gtNewOperNode(GT_IND, TYP_I_IMPL, add); - vtbl->gtFlags |= GTF_EXCEPT; - - unsigned vtabOffsOfIndirection; - unsigned vtabOffsAfterIndirection; - bool isRelative; - info.compCompHnd->getMethodVTableOffset(call->gtCallMethHnd, &vtabOffsOfIndirection, &vtabOffsAfterIndirection, - &isRelative); + GenTree* preInd = nullptr; + if ((i == 1 && pRuntimeLookup->indirectFirstOffset) || (i == 2 && pRuntimeLookup->indirectSecondOffset)) + { + preInd = cloneTree(&result DEBUGARG("getRuntimeLookupTree indirectOffset")); + } - /* Get the appropriate vtable chunk */ + if (i != 0) + { + result = gtNewOperNode(GT_IND, TYP_I_IMPL, result); + result->gtFlags |= GTF_IND_NONFAULTING; + result->gtFlags |= GTF_IND_INVARIANT; + } - if (vtabOffsOfIndirection != CORINFO_VIRTUALCALL_NO_CHUNK) + if ((i == 1 && pRuntimeLookup->indirectFirstOffset) || (i == 2 && pRuntimeLookup->indirectSecondOffset)) { - add = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, gtNewIconNode(vtabOffsOfIndirection, TYP_I_IMPL)); + result = gtNewOperNode(GT_ADD, TYP_I_IMPL, preInd, result); + } - GenTree* indOffTree = nullptr; + if (pRuntimeLookup->offsets[i] != 0) + { + result = gtNewOperNode(GT_ADD, TYP_I_IMPL, result, gtNewIconNode(pRuntimeLookup->offsets[i], TYP_I_IMPL)); + } + } - if (isRelative) - { - indOffTree = impCloneExpr(add, &add, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL, - nullptr DEBUGARG("virtual table call")); - } + assert(!pRuntimeLookup->testForNull); + if (pRuntimeLookup->indirections > 0) + { + assert(!pRuntimeLookup->testForFixup); + result = gtNewOperNode(GT_IND, TYP_I_IMPL, result); + result->gtFlags |= GTF_IND_NONFAULTING; + } - vtbl = gtNewOperNode(GT_IND, TYP_I_IMPL, add); + // Produces GT_COMMA(stmt1, GT_COMMA(stmt2, ... GT_COMMA(stmtN, result))) - if (isRelative) - { - vtbl = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, indOffTree); - } - } + while (!stmts.Empty()) + { + result = gtNewOperNode(GT_COMMA, TYP_I_IMPL, stmts.Pop(), result); + } - /* Now the appropriate vtable slot */ + DISPTREE(result); + return result; +} - add = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, gtNewIconNode(vtabOffsAfterIndirection, TYP_I_IMPL)); +//------------------------------------------------------------------------ +// getVirtMethodPointerTree: get a tree for a virtual method pointer +// +// Arguments: +// thisPtr - tree representing `this` pointer +// pResolvedToken - pointer to the resolved token of the method +// pCallInfo - pointer to call info +// +// Return Value: +// A node representing the virtual method pointer - GenTree* indOffTree = nullptr; +GenTree* Compiler::getVirtMethodPointerTree(GenTree* thisPtr, + CORINFO_RESOLVED_TOKEN* pResolvedToken, + CORINFO_CALL_INFO* pCallInfo) +{ + GenTree* exactTypeDesc = getTokenHandleTree(pResolvedToken, true); + GenTree* exactMethodDesc = getTokenHandleTree(pResolvedToken, false); - if (isRelative) - { - indOffTree = impCloneExpr(add, &add, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL, - nullptr DEBUGARG("virtual table call 2")); - } + GenTreeCall::Use* helpArgs = gtNewCallArgs(thisPtr, exactTypeDesc, exactMethodDesc); + return gtNewHelperCallNode(CORINFO_HELP_VIRTUAL_FUNC_PTR, TYP_I_IMPL, helpArgs); +} - vtbl = gtNewOperNode(GT_IND, TYP_I_IMPL, add); +//------------------------------------------------------------------------ +// getTokenHandleTree: get a handle tree for a token +// +// Arguments: +// pResolvedToken - token to get a handle for +// parent - whether parent should be imported +// +// Return Value: +// A node representing the virtual method pointer - if (isRelative) - { - vtbl = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, indOffTree); - } +GenTree* Compiler::getTokenHandleTree(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool parent) +{ + CORINFO_GENERICHANDLE_RESULT embedInfo; + info.compCompHnd->embedGenericHandle(pResolvedToken, parent ? TRUE : FALSE, &embedInfo); - // Switch this to a plain indirect call - call->gtFlags &= ~GTF_CALL_VIRT_KIND_MASK; - assert(!call->IsVirtual()); - call->gtCallType = CT_INDIRECT; + GenTree* result = getLookupTree(pResolvedToken, &embedInfo.lookup, gtTokenToIconFlags(pResolvedToken->token), + embedInfo.compileTimeHandle); - call->gtCallAddr = vtbl; - call->gtCallCookie = NULL; - call->gtFlags |= GTF_EXCEPT; + // If we have a result and it requires runtime lookup, wrap it in a runtime lookup node. + if ((result != nullptr) && embedInfo.lookup.lookupKind.needsRuntimeLookup) + { + result = gtNewRuntimeLookup(embedInfo.compileTimeHandle, embedInfo.handleType, result); } - // Now inject a placeholder for the real call target that codegen will generate - GenTree* arg = gtNewIconNode(0, TYP_I_IMPL); - call->gtCallArgs = gtPrependNewCallArg(arg, call->gtCallArgs); - - // Lastly inject the pointer for the copy routine - noway_assert(pfnCopyArgs != nullptr); - arg = gtNewIconHandleNode(ssize_t(pfnCopyArgs), GTF_ICON_FTN_ADDR); - call->gtCallArgs = gtPrependNewCallArg(arg, call->gtCallArgs); + return result; +} - // It is now a varargs tail call - call->gtCallMoreFlags |= GTF_CALL_M_VARARGS | GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_HELPER; - call->gtFlags &= ~GTF_CALL_POP_ARGS; +/***************************************************************************** + * + * Transform the given GT_CALL tree for tail call via JIT helper. + */ +void Compiler::fgMorphTailCallViaJitHelper(GenTreeCall* call) +{ + JITDUMP("fgMorphTailCallViaJitHelper (before):\n"); + DISPTREE(call); -#elif defined(TARGET_XARCH) + // The runtime requires that we perform a null check on the `this` argument before + // tail calling to a virtual dispatch stub. This requirement is a consequence of limitations + // in the runtime's ability to map an AV to a NullReferenceException if + // the AV occurs in a dispatch stub that has unmanaged caller. + if (call->IsVirtualStub()) + { + call->gtFlags |= GTF_CALL_NULLCHECK; + } // For the helper-assisted tail calls, we need to push all the arguments // into a single list, and then add a few extra at the beginning or end. // - // For AMD64, the tailcall helper (JIT_TailCall) is defined as: - // - // JIT_TailCall(void* copyRoutine, void* callTarget, ) - // - // We need to add "copyRoutine" and "callTarget" extra params at the beginning. - // But callTarget is determined by the Lower phase. Therefore, we add a placeholder arg - // for callTarget here which will be replaced later with callTarget in tail call lowering. - // // For x86, the tailcall helper is defined as: // // JIT_TailCall(, int numberOfOldStackArgsWords, int numberOfNewStackArgsWords, int flags, void* @@ -7825,7 +8267,6 @@ void Compiler::fgMorphTailCallViaHelper(GenTreeCall* call, void* pfnCopyArgs) GenTree* objp = call->gtCallThisArg->GetNode(); call->gtCallThisArg = nullptr; -#ifdef TARGET_X86 if ((call->IsDelegateInvoke() || call->IsVirtualVtable()) && !objp->IsLocal()) { // tmp = "this" @@ -7839,7 +8280,6 @@ void Compiler::fgMorphTailCallViaHelper(GenTreeCall* call, void* pfnCopyArgs) objp = thisPtr; } -#endif // TARGET_X86 if (call->NeedsNullCheck()) { @@ -7886,36 +8326,6 @@ void Compiler::fgMorphTailCallViaHelper(GenTreeCall* call, void* pfnCopyArgs) call->gtCallArgs = gtPrependNewCallArg(thisPtr, call->gtCallArgs); } -#if defined(TARGET_AMD64) - - // Add the extra VSD parameter to arg list in case of VSD calls. - // Tail call arg copying thunk will move this extra VSD parameter - // to R11 before tail calling VSD stub. See CreateTailCallCopyArgsThunk() - // in Stublinkerx86.cpp for more details. - if (call->IsVirtualStub()) - { - GenTree* stubAddrArg = fgGetStubAddrArg(call); - - // We don't need this arg to be in the normal stub register, so - // clear out the register assignment. - assert(stubAddrArg->GetRegNum() == virtualStubParamInfo->GetReg()); - stubAddrArg->SetRegNum(REG_NA); - - // And push the stub address onto the list of arguments - call->gtCallArgs = gtPrependNewCallArg(stubAddrArg, call->gtCallArgs); - } - - // Now inject a placeholder for the real call target that Lower phase will generate. - GenTree* arg = gtNewIconNode(0, TYP_I_IMPL); - call->gtCallArgs = gtPrependNewCallArg(arg, call->gtCallArgs); - - // Inject the pointer for the copy routine to be used for struct copying - noway_assert(pfnCopyArgs != nullptr); - arg = gtNewIconHandleNode(ssize_t(pfnCopyArgs), GTF_ICON_FTN_ADDR); - call->gtCallArgs = gtPrependNewCallArg(arg, call->gtCallArgs); - -#else // !TARGET_AMD64 - // Find the end of the argument list. ppArg will point at the last pointer; setting *ppArg will // append to the list. GenTreeCall::Use** ppArg = &call->gtCallArgs; @@ -7949,20 +8359,14 @@ void Compiler::fgMorphTailCallViaHelper(GenTreeCall* call, void* pfnCopyArgs) GenTree* arg0 = gtNewIconNode(7, TYP_I_IMPL); *ppArg = gtNewCallArgs(arg0); -#endif // !TARGET_AMD64 - - // It is now a varargs tail call dispatched via helper. - call->gtCallMoreFlags |= GTF_CALL_M_VARARGS | GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_HELPER; + // It is now a varargs tail call. + call->gtCallMoreFlags |= GTF_CALL_M_VARARGS; call->gtFlags &= ~GTF_CALL_POP_ARGS; -#elif defined(TARGET_ARM64) - NYI_ARM64("Tail calls via stub are unsupported on this platform."); -#endif // TARGET_ARM64 - // The function is responsible for doing explicit null check when it is necessary. assert(!call->NeedsNullCheck()); - JITDUMP("fgMorphTailCallViaHelper (after):\n"); + JITDUMP("fgMorphTailCallViaJitHelper (after):\n"); DISPTREE(call); } @@ -8137,7 +8541,7 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa // but this loop can't include the prolog. Since we don't have liveness information, we insert zero-initialization // for all non-parameter IL locals as well as temp structs with GC fields. // Liveness phase will remove unnecessary initializations. - if (info.compInitMem) + if (info.compInitMem || compSuppressedZeroInit) { unsigned varNum; LclVarDsc* varDsc; @@ -8154,7 +8558,8 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa var_types lclType = varDsc->TypeGet(); bool isUserLocal = (varNum < info.compLocalsCount); bool structWithGCFields = ((lclType == TYP_STRUCT) && varDsc->GetLayout()->HasGCPtr()); - if (isUserLocal || structWithGCFields) + bool hadSuppressedInit = varDsc->lvSuppressedZeroInit; + if ((info.compInitMem && (isUserLocal || structWithGCFields)) || hadSuppressedInit) { GenTree* lcl = gtNewLclvNode(varNum, lclType); GenTree* init = nullptr; @@ -8907,6 +9312,12 @@ GenTree* Compiler::fgMorphOneAsgBlockOp(GenTree* tree) return nullptr; } + if (src->IsCall() || src->OperIsSIMD()) + { + // Can't take ADDR from these nodes, let fgMorphCopyBlock handle it, #11413. + return nullptr; + } + if ((destVarDsc != nullptr) && !varTypeIsStruct(destVarDsc->TypeGet())) { @@ -9253,12 +9664,6 @@ GenTree* Compiler::fgMorphInitBlock(GenTree* tree) tree->AsOp()->gtOp1 = dest; } tree->gtType = dest->TypeGet(); - // (Constant propagation may cause a TYP_STRUCT lclVar to be changed to GT_CNS_INT, and its - // type will be the type of the original lclVar, in which case we will change it to TYP_INT). - if ((src->OperGet() == GT_CNS_INT) && varTypeIsStruct(src)) - { - src->gtType = TYP_INT; - } JITDUMP("\nfgMorphInitBlock:"); GenTree* oneAsgTree = fgMorphOneAsgBlockOp(tree); @@ -9306,7 +9711,9 @@ GenTree* Compiler::fgMorphInitBlock(GenTree* tree) } #endif // LOCAL_ASSERTION_PROP - if (destLclVar->lvPromoted) + // If we have already determined that a promoted TYP_STRUCT lclVar will not be enregistered, + // we are better off doing a block init. + if (destLclVar->lvPromoted && (!destLclVar->lvDoNotEnregister || !destLclNode->TypeIs(TYP_STRUCT))) { GenTree* newTree = fgMorphPromoteLocalInitBlock(destLclNode->AsLclVar(), initVal, blockSize); @@ -9592,7 +9999,10 @@ GenTree* Compiler::fgMorphGetStructAddr(GenTree** pTree, CORINFO_CLASS_HANDLE cl // TODO: Consider using lvaGrabTemp and gtNewTempAssign instead, since we're // not going to use "temp" GenTree* temp = fgInsertCommaFormTemp(pTree, clsHnd); - addr = fgMorphGetStructAddr(pTree, clsHnd, isRValue); + assert(!compDoOldStructRetyping()); + unsigned lclNum = temp->gtEffectiveVal()->AsLclVar()->GetLclNum(); + lvaSetVarDoNotEnregister(lclNum DEBUG_ARG(DNER_VMNeedsStackAddr)); + addr = fgMorphGetStructAddr(pTree, clsHnd, isRValue); break; } } @@ -9614,6 +10024,8 @@ GenTree* Compiler::fgMorphGetStructAddr(GenTree** pTree, CORINFO_CLASS_HANDLE cl GenTree* Compiler::fgMorphBlkNode(GenTree* tree, bool isDest) { + JITDUMP("fgMorphBlkNode for %s tree, before:\n", (isDest ? "dst" : "src")); + DISPTREE(tree); GenTree* handleTree = nullptr; GenTree* addr = nullptr; if (tree->OperIs(GT_COMMA)) @@ -9688,6 +10100,8 @@ GenTree* Compiler::fgMorphBlkNode(GenTree* tree, bool isDest) if (!tree->OperIsBlk()) { + JITDUMP("fgMorphBlkNode after:\n"); + DISPTREE(tree); return tree; } GenTreeBlk* blkNode = tree->AsBlk(); @@ -9706,24 +10120,31 @@ GenTree* Compiler::fgMorphBlkNode(GenTree* tree, bool isDest) } else { - return tree; + JITDUMP("fgMorphBlkNode after, DYN_BLK with zero size can't be morphed:\n"); + DISPTREE(blkNode); + return blkNode; } } else { - return tree; + JITDUMP("fgMorphBlkNode after, DYN_BLK with non-const size can't be morphed:\n"); + DISPTREE(blkNode); + return blkNode; } } - if ((blkNode->TypeGet() != TYP_STRUCT) && (blkNode->Addr()->OperGet() == GT_ADDR) && - (blkNode->Addr()->gtGetOp1()->OperGet() == GT_LCL_VAR)) + GenTree* blkSrc = blkNode->Addr(); + assert(blkSrc != nullptr); + if (!blkNode->TypeIs(TYP_STRUCT) && blkSrc->OperIs(GT_ADDR) && blkSrc->gtGetOp1()->OperIs(GT_LCL_VAR)) { - GenTreeLclVarCommon* lclVarNode = blkNode->Addr()->gtGetOp1()->AsLclVarCommon(); + GenTreeLclVarCommon* lclVarNode = blkSrc->gtGetOp1()->AsLclVarCommon(); if ((genTypeSize(blkNode) != genTypeSize(lclVarNode)) || (!isDest && !varTypeIsStruct(lclVarNode))) { lvaSetVarDoNotEnregister(lclVarNode->GetLclNum() DEBUG_ARG(DNER_VMNeedsStackAddr)); } } + JITDUMP("fgMorphBlkNode after:\n"); + DISPTREE(tree); return tree; } @@ -9793,6 +10214,16 @@ GenTree* Compiler::fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigne { lclNode = effectiveVal->AsLclVarCommon(); } + else if (effectiveVal->IsCall()) + { + needsIndirection = false; +#ifdef DEBUG + GenTreeCall* call = effectiveVal->AsCall(); + assert(call->TypeGet() == TYP_STRUCT); + assert(blockWidth == info.compCompHnd->getClassSize(call->gtRetClsHnd)); +#endif + } + if (lclNode != nullptr) { LclVarDsc* varDsc = &(lvaTable[lclNode->GetLclNum()]); @@ -9881,13 +10312,13 @@ GenTree* Compiler::fgMorphCopyBlock(GenTree* tree) { noway_assert(tree->OperIsCopyBlkOp()); - JITDUMP("\nfgMorphCopyBlock:"); + JITDUMP("fgMorphCopyBlock:\n"); bool isLateArg = (tree->gtFlags & GTF_LATE_ARG) != 0; - GenTree* asg = tree; - GenTree* src = asg->gtGetOp2(); - GenTree* dest = asg->gtGetOp1(); + GenTreeOp* asg = tree->AsOp(); + GenTree* src = asg->gtGetOp2(); + GenTree* dest = asg->gtGetOp1(); #if FEATURE_MULTIREG_RET // If this is a multi-reg return, we will not do any morphing of this node. @@ -9904,16 +10335,22 @@ GenTree* Compiler::fgMorphCopyBlock(GenTree* tree) dest = fgMorphBlkNode(dest, true); if (dest != asg->gtGetOp1()) { - asg->AsOp()->gtOp1 = dest; + asg->gtOp1 = dest; if (dest->IsLocal()) { dest->gtFlags |= GTF_VAR_DEF; } } - asg->gtType = dest->TypeGet(); - src = fgMorphBlkNode(src, false); +#ifdef DEBUG + if (asg->TypeGet() != dest->TypeGet()) + { + JITDUMP("changing type of dest from %-6s to %-6s\n", varTypeName(asg->TypeGet()), varTypeName(dest->TypeGet())); + } +#endif + asg->ChangeType(dest->TypeGet()); + src = fgMorphBlkNode(src, false); - asg->AsOp()->gtOp2 = src; + asg->gtOp2 = src; GenTree* oldTree = tree; GenTree* oneAsgTree = fgMorphOneAsgBlockOp(tree); @@ -10160,15 +10597,30 @@ GenTree* Compiler::fgMorphCopyBlock(GenTree* tree) // Are both dest and src promoted structs? if (destDoFldAsg && srcDoFldAsg) { - // Both structs should be of the same type, or each have a single field of the same type. + // Both structs should be of the same type, or have the same number of fields of the same type. // If not we will use a copy block. - if (lvaTable[destLclNum].lvVerTypeInfo.GetClassHandle() != - lvaTable[srcLclNum].lvVerTypeInfo.GetClassHandle()) + bool misMatchedTypes = false; + if (destLclVar->lvVerTypeInfo.GetClassHandle() != srcLclVar->lvVerTypeInfo.GetClassHandle()) { - unsigned destFieldNum = lvaTable[destLclNum].lvFieldLclStart; - unsigned srcFieldNum = lvaTable[srcLclNum].lvFieldLclStart; - if ((lvaTable[destLclNum].lvFieldCnt != 1) || (lvaTable[srcLclNum].lvFieldCnt != 1) || - (lvaTable[destFieldNum].lvType != lvaTable[srcFieldNum].lvType)) + if (destLclVar->lvFieldCnt != srcLclVar->lvFieldCnt) + { + misMatchedTypes = true; + } + else + { + for (int i = 0; i < destLclVar->lvFieldCnt; i++) + { + LclVarDsc* destFieldVarDsc = lvaGetDesc(destLclVar->lvFieldLclStart + i); + LclVarDsc* srcFieldVarDsc = lvaGetDesc(srcLclVar->lvFieldLclStart + i); + if ((destFieldVarDsc->lvType != srcFieldVarDsc->lvType) || + (destFieldVarDsc->lvFldOffset != srcFieldVarDsc->lvFldOffset)) + { + misMatchedTypes = true; + break; + } + } + } + if (misMatchedTypes) { requiresCopyBlock = true; // Mismatched types, leave as a CopyBlock JITDUMP(" with mismatched types"); @@ -10665,15 +11117,13 @@ GenTree* Compiler::fgMorphCopyBlock(GenTree* tree) { tree->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED; } - - if (verbose) - { - printf("\nfgMorphCopyBlock (after):\n"); - gtDispTree(tree); - } #endif _Done: + + JITDUMP("\nfgMorphCopyBlock (after):\n"); + DISPTREE(tree); + return tree; } @@ -11200,6 +11650,17 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) op2->AsDblCon()->gtDconVal = 1.0 / divisor; } } + + // array.Length is always positive so GT_DIV can be changed to GT_UDIV + // if op2 is a positive cns + if (!optValnumCSE_phase && op1->OperIs(GT_ARR_LENGTH) && op2->IsIntegralConst() && + op2->AsIntCon()->IconValue() >= 2) // for 0 and 1 it doesn't matter if it's UDIV or DIV + { + assert(tree->OperIs(GT_DIV)); + tree->ChangeOper(GT_UDIV); + return fgMorphSmpOp(tree, mac); + } + #ifndef TARGET_64BIT if (typ == TYP_LONG) { @@ -11264,6 +11725,16 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) goto USE_HELPER_FOR_ARITH; } + // array.Length is always positive so GT_DIV can be changed to GT_UDIV + // if op2 is a positive cns + if (!optValnumCSE_phase && op1->OperIs(GT_ARR_LENGTH) && op2->IsIntegralConst() && + op2->AsIntCon()->IconValue() >= 2) // for 0 and 1 it doesn't matter if it's UMOD or MOD + { + assert(tree->OperIs(GT_MOD)); + tree->ChangeOper(GT_UMOD); + return fgMorphSmpOp(tree, mac); + } + // Do not use optimizations (unlike UMOD's idiv optimizing during codegen) for signed mod. // A similar optimization for signed mod will not work for a negative perfectly divisible // HI-word. To make it correct, we would need to divide without the sign and then flip the @@ -11470,6 +11941,31 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) return tree; } + if (tree->TypeIs(TYP_STRUCT) && op1->OperIs(GT_OBJ, GT_BLK)) + { + assert(!compDoOldStructRetyping()); + GenTree* addr = op1->AsBlk()->Addr(); + // if we return `OBJ` or `BLK` from a local var, lcl var has to have a stack address. + if (addr->OperIs(GT_ADDR) && addr->gtGetOp1()->OperIs(GT_LCL_VAR)) + { + GenTreeLclVar* lclVar = addr->gtGetOp1()->AsLclVar(); + assert(!gtIsActiveCSE_Candidate(addr) && !gtIsActiveCSE_Candidate(op1)); + if (gtGetStructHandle(tree) == gtGetStructHandleIfPresent(lclVar)) + { + // Fold *(&x). + tree->AsUnOp()->gtOp1 = op1; + DEBUG_DESTROY_NODE(op1); + DEBUG_DESTROY_NODE(addr); + op1 = lclVar; + } + else + { + // TODO-1stClassStructs: It is not address-taken or block operation, + // but the current IR doesn't allow to express that cast without stack, see #11413. + lvaSetVarDoNotEnregister(lclVar->GetLclNum() DEBUGARG(DNER_BlockOp)); + } + } + } break; case GT_EQ: @@ -12628,6 +13124,30 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) op2 = tree->AsOp()->gtOp2; } + // See if we can fold floating point operations (can regress minopts mode) + if (opts.OptimizationEnabled() && varTypeIsFloating(tree->TypeGet()) && !optValnumCSE_phase) + { + if ((oper == GT_MUL) && !op1->IsCnsFltOrDbl() && op2->IsCnsFltOrDbl()) + { + if (op2->AsDblCon()->gtDconVal == 2.0) + { + // Fold "x*2.0" to "x+x" + op2 = op1->OperIsLeaf() ? gtCloneExpr(op1) : fgMakeMultiUse(&tree->AsOp()->gtOp1); + op1 = tree->AsOp()->gtOp1; + oper = GT_ADD; + tree = gtNewOperNode(oper, tree->TypeGet(), op1, op2); + INDEBUG(tree->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED); + } + else if (op2->AsDblCon()->gtDconVal == 1.0) + { + // Fold "x*1.0" to "x" + DEBUG_DESTROY_NODE(op2); + DEBUG_DESTROY_NODE(tree); + return op1; + } + } + } + /* See if we can fold GT_ADD nodes. */ if (oper == GT_ADD) @@ -12907,7 +13427,9 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) // is a local or clsVar, even if it has been address-exposed. if (op1->OperGet() == GT_ADDR) { - tree->gtFlags |= (op1->gtGetOp1()->gtFlags & GTF_GLOB_REF); + GenTreeUnOp* addr = op1->AsUnOp(); + GenTree* addrOp = addr->gtGetOp1(); + tree->gtFlags |= (addrOp->gtFlags & GTF_GLOB_REF); } break; @@ -13022,6 +13544,22 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) } else if (op1->OperGet() == GT_ADD) { +#ifdef TARGET_ARM + // Check for a misalignment floating point indirection. + if (varTypeIsFloating(typ)) + { + GenTree* addOp2 = op1->AsOp()->gtGetOp2(); + if (addOp2->IsCnsIntOrI()) + { + ssize_t offset = addOp2->AsIntCon()->gtIconVal; + if ((offset % emitTypeSize(TYP_FLOAT)) != 0) + { + tree->gtFlags |= GTF_IND_UNALIGNED; + } + } + } +#endif // TARGET_ARM + /* Try to change *(&lcl + cns) into lcl[cns] to prevent materialization of &lcl */ if (op1->AsOp()->gtOp1->OperGet() == GT_ADDR && op1->AsOp()->gtOp2->OperGet() == GT_CNS_INT && @@ -13071,19 +13609,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) { break; } - -#ifdef TARGET_ARM - // Check for a LclVar TYP_STRUCT with misalignment on a Floating Point field - // - if (varTypeIsFloating(typ)) - { - if ((ival1 % emitTypeSize(typ)) != 0) - { - tree->gtFlags |= GTF_IND_UNALIGNED; - break; - } - } -#endif } // Now we can fold this into a GT_LCL_FLD below // where we check (temp != nullptr) @@ -13384,9 +13909,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) return tree; } - - /* op1 of a GT_ADDR is an l-value. Only r-values can be CSEed */ - op1->gtFlags |= GTF_DONT_CSE; break; case GT_COLON: @@ -15511,49 +16033,42 @@ void Compiler::fgMorphStmts(BasicBlock* block, bool* lnot, bool* loadw) // Has fgMorphStmt been sneakily changed ? - if (stmt->GetRootNode() != oldTree) + if ((stmt->GetRootNode() != oldTree) || (block != compCurBB)) { - /* This must be tailcall. Ignore 'morphedTree' and carry on with - the tail-call node */ - - morphedTree = stmt->GetRootNode(); - noway_assert(compTailCallUsed); - noway_assert((morphedTree->gtOper == GT_CALL) && morphedTree->AsCall()->IsTailCall()); - noway_assert(stmt->GetNextStmt() == nullptr); + if (stmt->GetRootNode() != oldTree) + { + /* This must be tailcall. Ignore 'morphedTree' and carry on with + the tail-call node */ - GenTreeCall* call = morphedTree->AsCall(); - // Could either be - // - a tail call dispatched via helper in which case block will be ending with BBJ_THROW or - // - a fast call made as jmp in which case block will be ending with BBJ_RETURN and marked as containing - // a jmp. - noway_assert((call->IsTailCallViaHelper() && (compCurBB->bbJumpKind == BBJ_THROW)) || - (call->IsFastTailCall() && (compCurBB->bbJumpKind == BBJ_RETURN) && - (compCurBB->bbFlags & BBF_HAS_JMP))); - } - else if ((block != compCurBB) && ((oldTree->gtOper == GT_CALL) && oldTree->AsCall()->IsTailCall())) - { - /* This must be a tail call that caused a GCPoll to get - injected. We haven't actually morphed the call yet - but the flag still got set, clear it here... */ - CLANG_FORMAT_COMMENT_ANCHOR; + morphedTree = stmt->GetRootNode(); + } + else + { + /* This must be a tailcall that caused a GCPoll to get + injected. We haven't actually morphed the call yet + but the flag still got set, clear it here... */ + CLANG_FORMAT_COMMENT_ANCHOR; #ifdef DEBUG - oldTree->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED; + morphedTree->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED; #endif + } noway_assert(compTailCallUsed); - noway_assert((oldTree->gtOper == GT_CALL) && oldTree->AsCall()->IsTailCall()); - noway_assert(stmt->GetNextStmt() == nullptr); - + noway_assert(morphedTree->gtOper == GT_CALL); GenTreeCall* call = morphedTree->AsCall(); - - // Could either be - // - a tail call dispatched via helper in which case block will be ending with BBJ_THROW or - // - a fast call made as jmp in which case block will be ending with BBJ_RETURN and marked as containing - // a jmp. - noway_assert((call->IsTailCallViaHelper() && (compCurBB->bbJumpKind == BBJ_THROW)) || - (call->IsFastTailCall() && (compCurBB->bbJumpKind == BBJ_RETURN) && - (compCurBB->bbFlags & BBF_HAS_JMP))); + // Could be + // - a fast call made as jmp in which case block will be ending with + // BBJ_RETURN (as we need epilog) and marked as containing a jmp. + // - a tailcall dispatched via JIT helper, on x86, in which case + // block will be ending with BBJ_THROW. + // - a tail call dispatched via runtime help (IL stubs), in which + // case there will not be any tailcall and the block will be ending + // with BBJ_RETURN (as normal control flow) + noway_assert((call->IsFastTailCall() && (compCurBB->bbJumpKind == BBJ_RETURN) && + ((compCurBB->bbFlags & BBF_HAS_JMP)) != 0) || + (call->IsTailCallViaJitHelper() && (compCurBB->bbJumpKind == BBJ_THROW)) || + (!call->IsTailCall() && (compCurBB->bbJumpKind == BBJ_RETURN))); } #ifdef DEBUG @@ -15910,10 +16425,6 @@ void Compiler::fgSetOptions() /* Assume we won't need an explicit stack frame if this is allowed */ - // CORINFO_HELP_TAILCALL won't work with localloc because of the restoring of - // the callee-saved registers. - noway_assert(!compTailCallUsed || !compLocallocUsed); - if (compLocallocUsed) { codeGen->setFramePointerRequired(true); @@ -16045,7 +16556,7 @@ GenTree* Compiler::fgInitThisClass() // Collectible types requires that for shared generic code, if we use the generic context paramter // that we report it. (This is a conservative approach, we could detect some cases particularly when the // context parameter is this that we don't need the eager reporting logic.) - lvaGenericsContextUseCount++; + lvaGenericsContextInUse = true; switch (kind.runtimeLookupKind) { @@ -16054,6 +16565,7 @@ GenTree* Compiler::fgInitThisClass() // the hierarchy { GenTree* vtTree = gtNewLclvNode(info.compThisArg, TYP_REF); + vtTree->gtFlags |= GTF_VAR_CONTEXT; // Vtable pointer of this object vtTree = gtNewOperNode(GT_IND, TYP_I_IMPL, vtTree); vtTree->gtFlags |= GTF_EXCEPT; // Null-pointer exception @@ -16065,12 +16577,14 @@ GenTree* Compiler::fgInitThisClass() case CORINFO_LOOKUP_CLASSPARAM: { GenTree* vtTree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL); + vtTree->gtFlags |= GTF_VAR_CONTEXT; return gtNewHelperCallNode(CORINFO_HELP_INITCLASS, TYP_VOID, gtNewCallArgs(vtTree)); } case CORINFO_LOOKUP_METHODPARAM: { GenTree* methHndTree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL); + methHndTree->gtFlags |= GTF_VAR_CONTEXT; return gtNewHelperCallNode(CORINFO_HELP_INITINSTCLASS, TYP_VOID, gtNewCallArgs(gtNewIconNode(0), methHndTree)); } @@ -16831,8 +17345,7 @@ void Compiler::fgMorphStructField(GenTree* tree, GenTree* parent) tree->SetOper(GT_LCL_VAR); tree->AsLclVarCommon()->SetLclNum(fieldLclIndex); tree->gtType = fieldType; - tree->gtFlags &= GTF_NODE_MASK; - tree->gtFlags &= ~GTF_GLOB_REF; + tree->gtFlags &= GTF_NODE_MASK; // Note: that clears all flags except `GTF_COLON_COND`. if (parent->gtOper == GT_ASG) { @@ -16947,7 +17460,8 @@ void Compiler::fgMorphLocalField(GenTree* tree, GenTree* parent) var_types treeType = tree->TypeGet(); var_types fieldType = fldVarDsc->TypeGet(); - if (fldOffset != BAD_VAR_NUM && (genTypeSize(fieldType) == genTypeSize(treeType))) + if (fldOffset != BAD_VAR_NUM && + ((genTypeSize(fieldType) == genTypeSize(treeType)) || (varDsc->lvFieldCnt == 1))) { // There is an existing sub-field we can use. tree->AsLclFld()->SetLclNum(fieldLclIndex); @@ -17676,7 +18190,7 @@ bool Compiler::fgMorphCombineSIMDFieldAssignments(BasicBlock* block, Statement* if (verbose) { printf("\nFound contiguous assignments from a SIMD vector to memory.\n"); - printf("From " FMT_BB ", stmt", block->bbNum); + printf("From " FMT_BB ", stmt ", block->bbNum); printStmtID(stmt); printf(" to stmt"); printStmtID(lastStmt); @@ -17742,13 +18256,16 @@ bool Compiler::fgMorphCombineSIMDFieldAssignments(BasicBlock* block, Statement* #ifdef DEBUG if (verbose) { - printf("\n" FMT_BB " stmt", block->bbNum); + printf("\n" FMT_BB " stmt ", block->bbNum); printStmtID(stmt); printf("(before)\n"); gtDispStmt(stmt); } #endif + assert(!simdStructNode->CanCSE()); + simdStructNode->ClearDoNotCSE(); + tree = gtNewAssignNode(dstNode, simdStructNode); stmt->SetRootNode(tree); @@ -17873,6 +18390,27 @@ bool Compiler::fgCheckStmtAfterTailCall() return nextMorphStmt == nullptr; } +//------------------------------------------------------------------------ +// fgCanTailCallViaJitHelper: check whether we can use the faster tailcall +// JIT helper on x86. +// +// Return Value: +// 'true' if we can; or 'false' if we should use the generic tailcall mechanism. +// +bool Compiler::fgCanTailCallViaJitHelper() +{ +#ifndef TARGET_X86 + // On anything except X86 we have no faster mechanism available. + return false; +#else + // The JIT helper does not properly handle the case where localloc was used. + if (compLocallocUsed) + return false; + + return true; +#endif +} + static const int numberOfTrackedFlags = 5; static const unsigned trackedFlags[numberOfTrackedFlags] = {GTF_ASG, GTF_CALL, GTF_EXCEPT, GTF_GLOB_REF, GTF_ORDER_SIDEEFF}; diff --git a/src/coreclr/src/jit/namedintrinsiclist.h b/src/coreclr/src/jit/namedintrinsiclist.h index f81f5e0dfdb9e8..c9a87d782a62cb 100644 --- a/src/coreclr/src/jit/namedintrinsiclist.h +++ b/src/coreclr/src/jit/namedintrinsiclist.h @@ -22,22 +22,37 @@ enum NamedIntrinsic : unsigned short NI_System_Type_get_IsValueType, NI_System_Type_IsAssignableFrom, -#ifdef FEATURE_HW_INTRINSICS + // These are used by HWIntrinsics but are defined more generally + // to allow dead code optimization and handle the recursion case + NI_IsSupported_True, NI_IsSupported_False, NI_Throw_PlatformNotSupportedException, +#ifdef FEATURE_HW_INTRINSICS NI_HW_INTRINSIC_START, #if defined(TARGET_XARCH) -#define HARDWARE_INTRINSIC(id, name, isa, ival, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \ - NI_##id, +#define HARDWARE_INTRINSIC(isa, name, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \ + NI_##isa##_##name, #include "hwintrinsiclistxarch.h" #elif defined(TARGET_ARM64) -#define HARDWARE_INTRINSIC(isa, name, ival, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \ +#define HARDWARE_INTRINSIC(isa, name, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \ NI_##isa##_##name, #include "hwintrinsiclistarm64.h" #endif // !defined(TARGET_XARCH) && !defined(TARGET_ARM64) NI_HW_INTRINSIC_END, + + NI_SIMD_AS_HWINTRINSIC_START, +#if defined(TARGET_XARCH) +#define SIMD_AS_HWINTRINSIC(classId, id, name, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, flag) \ + NI_##classId##_##id, +#include "simdashwintrinsiclistxarch.h" +#elif defined(TARGET_ARM64) +#define SIMD_AS_HWINTRINSIC(classId, id, name, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, flag) \ + NI_##classId##_##id, +#include "simdashwintrinsiclistarm64.h" +#endif // !defined(TARGET_XARCH) && !defined(TARGET_ARM64) + NI_SIMD_AS_HWINTRINSIC_END, #endif // FEATURE_HW_INTRINSICS }; diff --git a/src/coreclr/src/jit/objectalloc.cpp b/src/coreclr/src/jit/objectalloc.cpp index 5c31ca33ecef61..7be52493cd21e6 100644 --- a/src/coreclr/src/jit/objectalloc.cpp +++ b/src/coreclr/src/jit/objectalloc.cpp @@ -518,9 +518,10 @@ unsigned int ObjectAllocator::MorphAllocObjNodeIntoStackAlloc(GenTreeAllocObj* a comp->lvaSetStruct(lclNum, allocObj->gtAllocObjClsHnd, unsafeValueClsCheck); // Initialize the object memory if necessary. - bool bbInALoop = (block->bbFlags & BBF_BACKWARD_JUMP) != 0; - bool bbIsReturn = block->bbJumpKind == BBJ_RETURN; - if (comp->fgVarNeedsExplicitZeroInit(comp->lvaGetDesc(lclNum), bbInALoop, bbIsReturn)) + bool bbInALoop = (block->bbFlags & BBF_BACKWARD_JUMP) != 0; + bool bbIsReturn = block->bbJumpKind == BBJ_RETURN; + LclVarDsc* const lclDsc = comp->lvaGetDesc(lclNum); + if (comp->fgVarNeedsExplicitZeroInit(lclNum, bbInALoop, bbIsReturn)) { //------------------------------------------------------------------------ // STMTx (IL 0x... ???) @@ -538,6 +539,12 @@ unsigned int ObjectAllocator::MorphAllocObjNodeIntoStackAlloc(GenTreeAllocObj* a comp->fgInsertStmtBefore(block, stmt, newStmt); } + else + { + JITDUMP("\nSuppressing zero-init for V%02u -- expect to zero in prolog\n", lclNum); + lclDsc->lvSuppressedZeroInit = 1; + comp->compSuppressedZeroInit = true; + } //------------------------------------------------------------------------ // STMTx (IL 0x... ???) diff --git a/src/coreclr/src/jit/optimizer.cpp b/src/coreclr/src/jit/optimizer.cpp index e5da29421f6ee6..2fe04e7a8b0606 100644 --- a/src/coreclr/src/jit/optimizer.cpp +++ b/src/coreclr/src/jit/optimizer.cpp @@ -2669,6 +2669,20 @@ void Compiler::optCopyBlkDest(BasicBlock* from, BasicBlock* to) } } +// Returns true if 'block' is an entry block for any loop in 'optLoopTable' +bool Compiler::optIsLoopEntry(BasicBlock* block) +{ + for (unsigned char loopInd = 0; loopInd < optLoopCount; loopInd++) + { + // Traverse the outermost loops as entries into the loop nest; so skip non-outermost. + if (optLoopTable[loopInd].lpEntry == block) + { + return true; + } + } + return false; +} + // Canonicalize the loop nest rooted at parent loop 'loopInd'. // Returns 'true' if the flow graph is modified. bool Compiler::optCanonicalizeLoopNest(unsigned char loopInd) @@ -3785,6 +3799,8 @@ void Compiler::optUnrollLoops() testCopyStmt->SetRootNode(sideEffList); } newBlock->bbJumpKind = BBJ_NONE; + newBlock->bbFlags &= + ~BBF_NEEDS_GCPOLL; // Clear any NEEDS_GCPOLL flag as this block no longer can be a back edge // Exit this loop; we've walked all the blocks. break; @@ -7642,17 +7658,55 @@ void Compiler::optComputeLoopNestSideEffects(unsigned lnum) { assert(optLoopTable[lnum].lpParent == BasicBlock::NOT_IN_LOOP); // Requires: lnum is outermost. BasicBlock* botNext = optLoopTable[lnum].lpBottom->bbNext; + JITDUMP("optComputeLoopSideEffects botNext is " FMT_BB ", lnum is %d\n", botNext->bbNum, lnum); for (BasicBlock* bbInLoop = optLoopTable[lnum].lpFirst; bbInLoop != botNext; bbInLoop = bbInLoop->bbNext) { - optComputeLoopSideEffectsOfBlock(bbInLoop); + if (!optComputeLoopSideEffectsOfBlock(bbInLoop)) + { + // When optComputeLoopSideEffectsOfBlock returns false, we encountered + // a block that was moved into the loop range (by fgReorderBlocks), + // but not marked correctly as being inside the loop. + // We conservatively mark this loop (and any outer loops) + // as having memory havoc side effects. + // + // Record that all loops containing this block have memory havoc effects. + // + optRecordLoopNestsMemoryHavoc(lnum, fullMemoryKindSet); + + // All done, no need to keep visiting more blocks + break; + } } } -void Compiler::optComputeLoopSideEffectsOfBlock(BasicBlock* blk) +void Compiler::optRecordLoopNestsMemoryHavoc(unsigned lnum, MemoryKindSet memoryHavoc) { - unsigned mostNestedLoop = blk->bbNatLoopNum; - assert(mostNestedLoop != BasicBlock::NOT_IN_LOOP); + // We should start out with 'lnum' set to a valid natural loop index + assert(lnum != BasicBlock::NOT_IN_LOOP); + + while (lnum != BasicBlock::NOT_IN_LOOP) + { + for (MemoryKind memoryKind : allMemoryKinds()) + { + if ((memoryHavoc & memoryKindSet(memoryKind)) != 0) + { + optLoopTable[lnum].lpLoopHasMemoryHavoc[memoryKind] = true; + } + } + + // Move lnum to the next outtermost loop that we need to mark + lnum = optLoopTable[lnum].lpParent; + } +} +bool Compiler::optComputeLoopSideEffectsOfBlock(BasicBlock* blk) +{ + unsigned mostNestedLoop = blk->bbNatLoopNum; + JITDUMP("optComputeLoopSideEffectsOfBlock " FMT_BB ", mostNestedLoop %d\n", blk->bbNum, mostNestedLoop); + if (mostNestedLoop == BasicBlock::NOT_IN_LOOP) + { + return false; + } AddVariableLivenessAllContainingLoops(mostNestedLoop, blk); // MemoryKinds for which an in-loop call or store has arbitrary effects. @@ -7905,20 +7959,10 @@ void Compiler::optComputeLoopSideEffectsOfBlock(BasicBlock* blk) if (memoryHavoc != emptyMemoryKindSet) { - // Record that all loops containing this block have memory havoc effects. - unsigned lnum = mostNestedLoop; - while (lnum != BasicBlock::NOT_IN_LOOP) - { - for (MemoryKind memoryKind : allMemoryKinds()) - { - if ((memoryHavoc & memoryKindSet(memoryKind)) != 0) - { - optLoopTable[lnum].lpLoopHasMemoryHavoc[memoryKind] = true; - } - } - lnum = optLoopTable[lnum].lpParent; - } + // Record that all loops containing this block have this kind of memoryHavoc effects. + optRecordLoopNestsMemoryHavoc(mostNestedLoop, memoryHavoc); } + return true; } // Marks the containsCall information to "lnum" and any parent loops. @@ -9145,3 +9189,147 @@ void Compiler::optOptimizeBools() fgDebugCheckBBlist(); #endif } + +typedef JitHashTable, unsigned> LclVarRefCounts; + +//------------------------------------------------------------------------------------------ +// optRemoveRedundantZeroInits: Remove redundant zero intializations. +// +// Notes: +// This phase iterates over basic blocks starting with the first basic block until there is no unique +// basic block successor or until it detects a loop. It keeps track of local nodes it encounters. +// When it gets to an assignment to a local variable or a local field, it checks whether the assignment +// is the first reference to the local (or to the parent of the local field), and, if so, +// it may do one of two optimizations: +// 1. If the following conditions are true: +// the local is untracked, +// the rhs of the assignment is 0, +// the local is guaranteed to be fully initialized in the prolog, +// then the explicit zero initialization is removed. +// 2. If the following conditions are true: +// the assignment is to a local (and not a field), +// the local is not lvLiveInOutOfHndlr or no exceptions can be thrown between the prolog and the assignment, +// either the local has no gc pointers or there are no gc-safe points between the prolog and the assignment, +// then the local with lvHasExplicitInit which tells the codegen not to insert zero initialization for this +// local in the prolog. + +void Compiler::optRemoveRedundantZeroInits() +{ +#ifdef DEBUG + if (verbose) + { + printf("*************** In optRemoveRedundantZeroInits()\n"); + } +#endif // DEBUG + + CompAllocator allocator(getAllocator(CMK_ZeroInit)); + LclVarRefCounts refCounts(allocator); + bool hasGCSafePoint = false; + bool canThrow = false; + + assert(fgStmtListThreaded); + + for (BasicBlock* block = fgFirstBB; (block != nullptr) && ((block->bbFlags & BBF_MARKED) == 0); + block = block->GetUniqueSucc()) + { + block->bbFlags |= BBF_MARKED; + for (Statement* stmt = block->FirstNonPhiDef(); stmt != nullptr;) + { + Statement* next = stmt->GetNextStmt(); + for (GenTree* tree = stmt->GetTreeList(); tree != nullptr; tree = tree->gtNext) + { + if (((tree->gtFlags & GTF_CALL) != 0) && (!tree->IsCall() || !tree->AsCall()->IsSuppressGCTransition())) + { + hasGCSafePoint = true; + } + + if ((tree->gtFlags & GTF_EXCEPT) != 0) + { + canThrow = true; + } + + switch (tree->gtOper) + { + case GT_LCL_VAR: + case GT_LCL_FLD: + case GT_LCL_VAR_ADDR: + case GT_LCL_FLD_ADDR: + { + unsigned lclNum = tree->AsLclVarCommon()->GetLclNum(); + unsigned* pRefCount = refCounts.LookupPointer(lclNum); + if (pRefCount != nullptr) + { + *pRefCount = (*pRefCount) + 1; + } + else + { + refCounts.Set(lclNum, 1); + } + + break; + } + case GT_ASG: + { + GenTreeOp* treeOp = tree->AsOp(); + if (treeOp->gtOp1->OperIs(GT_LCL_VAR, GT_LCL_FLD)) + { + unsigned lclNum = treeOp->gtOp1->AsLclVarCommon()->GetLclNum(); + LclVarDsc* const lclDsc = lvaGetDesc(lclNum); + unsigned* pRefCount = refCounts.LookupPointer(lclNum); + assert(pRefCount != nullptr); + if (*pRefCount == 1) + { + // The local hasn't been referenced before this assignment. + bool removedExplicitZeroInit = false; + if (!lclDsc->lvTracked && treeOp->gtOp2->IsIntegralConst(0)) + { + bool bbInALoop = (block->bbFlags & BBF_BACKWARD_JUMP) != 0; + bool bbIsReturn = block->bbJumpKind == BBJ_RETURN; + + if (!fgVarNeedsExplicitZeroInit(lclNum, bbInALoop, bbIsReturn)) + { + // We are guaranteed to have a zero initialization in the prolog and + // the local hasn't been redefined between the prolog and this explicit + // zero initialization so the assignment can be safely removed. + if (tree == stmt->GetRootNode()) + { + fgRemoveStmt(block, stmt); + removedExplicitZeroInit = true; + *pRefCount = 0; + lclDsc->lvSuppressedZeroInit = 1; + } + } + } + + if (!removedExplicitZeroInit && treeOp->gtOp1->OperIs(GT_LCL_VAR) && + (!canThrow || !lclDsc->lvLiveInOutOfHndlr)) + { + // If compMethodRequiresPInvokeFrame() returns true, lower may later + // insert a call to CORINFO_HELP_INIT_PINVOKE_FRAME which is a gc-safe point. + if (!lclDsc->HasGCPtr() || + (!GetInterruptible() && !hasGCSafePoint && !compMethodRequiresPInvokeFrame())) + { + // The local hasn't been used and won't be reported to the gc between + // the prolog and this explicit intialization. Therefore, it doesn't + // require zero initialization in the prolog. + lclDsc->lvHasExplicitInit = 1; + } + } + } + } + break; + } + default: + break; + } + } + stmt = next; + } + } + + for (BasicBlock* block = fgFirstBB; (block != nullptr) && ((block->bbFlags & BBF_MARKED) != 0); + block = block->GetUniqueSucc()) + { + block->bbFlags &= ~BBF_MARKED; + } +} diff --git a/src/coreclr/src/jit/patchpoint.cpp b/src/coreclr/src/jit/patchpoint.cpp index 7116e780f4cd9b..f19d2a862f1926 100644 --- a/src/coreclr/src/jit/patchpoint.cpp +++ b/src/coreclr/src/jit/patchpoint.cpp @@ -24,20 +24,17 @@ // // * no patchpoints in handler regions // * no patchpoints for localloc methods -// * no patchpoints in try regions (workaround) // * no patchpoints for synchronized methods (workaround) // class PatchpointTransformer { - unsigned ppCounterLclNum; const int HIGH_PROBABILITY = 99; + unsigned ppCounterLclNum; Compiler* compiler; public: - PatchpointTransformer(Compiler* compiler) : compiler(compiler) + PatchpointTransformer(Compiler* compiler) : ppCounterLclNum(BAD_VAR_NUM), compiler(compiler) { - ppCounterLclNum = compiler->lvaGrabTemp(true DEBUGARG("patchpoint counter")); - compiler->lvaTable[ppCounterLclNum].lvType = TYP_INT; } //------------------------------------------------------------------------ @@ -53,11 +50,8 @@ class PatchpointTransformer compiler->fgEnsureFirstBBisScratch(); } - BasicBlock* block = compiler->fgFirstBB; - TransformEntry(block); - int count = 0; - for (block = block->bbNext; block != nullptr; block = block->bbNext) + for (BasicBlock* block = compiler->fgFirstBB->bbNext; block != nullptr; block = block->bbNext) { if (block->bbFlags & BBF_PATCHPOINT) { @@ -119,6 +113,16 @@ class PatchpointTransformer // void TransformBlock(BasicBlock* block) { + // If we haven't allocated the counter temp yet, set it up + if (ppCounterLclNum == BAD_VAR_NUM) + { + ppCounterLclNum = compiler->lvaGrabTemp(true DEBUGARG("patchpoint counter")); + compiler->lvaTable[ppCounterLclNum].lvType = TYP_INT; + + // and initialize in the entry block + TransformEntry(compiler->fgFirstBB); + } + // Capture the IL offset IL_OFFSET ilOffset = block->bbCodeOffs; assert(ilOffset != BAD_IL_OFFSET); diff --git a/src/coreclr/src/jit/rationalize.cpp b/src/coreclr/src/jit/rationalize.cpp index 9f45bede3abbbf..b8f8595b43e064 100644 --- a/src/coreclr/src/jit/rationalize.cpp +++ b/src/coreclr/src/jit/rationalize.cpp @@ -295,7 +295,7 @@ static void RewriteAssignmentIntoStoreLclCore(GenTreeOp* assignment, store->AsLclFld()->SetFieldSeq(var->AsLclFld()->GetFieldSeq()); } - copyFlags(store, var, GTF_LIVENESS_MASK); + copyFlags(store, var, (GTF_LIVENESS_MASK | GTF_VAR_MULTIREG)); store->gtFlags &= ~GTF_REVERSE_OPS; store->gtType = var->TypeGet(); @@ -768,6 +768,40 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, Compiler::Ge break; #endif // FEATURE_SIMD +#ifdef FEATURE_HW_INTRINSICS + case GT_HWINTRINSIC: + { + GenTreeHWIntrinsic* hwIntrinsicNode = node->AsHWIntrinsic(); + + if (!hwIntrinsicNode->isSIMD()) + { + break; + } + + noway_assert(comp->supportSIMDTypes()); + + // TODO-1stClassStructs: This should be handled more generally for enregistered or promoted + // structs that are passed or returned in a different register type than their enregistered + // type(s). + if ((hwIntrinsicNode->gtType == TYP_I_IMPL) && (hwIntrinsicNode->gtSIMDSize == TARGET_POINTER_SIZE)) + { +#ifdef TARGET_ARM64 + // Special case for GetElement/ToScalar because they take Vector64 and return T + // and T can be long or ulong. + if (!(hwIntrinsicNode->gtHWIntrinsicId == NI_Vector64_GetElement || + hwIntrinsicNode->gtHWIntrinsicId == NI_Vector64_ToScalar)) +#endif + { + // This happens when it is consumed by a GT_RET_EXPR. + // It can only be a Vector2f or Vector2i. + assert(genTypeSize(hwIntrinsicNode->gtSIMDBaseType) == 4); + hwIntrinsicNode->gtType = TYP_SIMD8; + } + } + break; + } +#endif // FEATURE_HW_INTRINSICS + default: // These nodes should not be present in HIR. assert(!node->OperIs(GT_CMP, GT_SETCC, GT_JCC, GT_JCMP, GT_LOCKADD)); diff --git a/src/coreclr/src/jit/regalloc.cpp b/src/coreclr/src/jit/regalloc.cpp index 73c2816dc320b6..367eb81877f1f2 100644 --- a/src/coreclr/src/jit/regalloc.cpp +++ b/src/coreclr/src/jit/regalloc.cpp @@ -175,6 +175,7 @@ regNumber Compiler::raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc } else { + assert(!regState->rsIsFloat); unsigned cSlots = argDsc->lvSize() / TARGET_POINTER_SIZE; for (unsigned i = 1; i < cSlots; i++) { @@ -183,7 +184,6 @@ regNumber Compiler::raUpdateRegStateForArg(RegState* regState, LclVarDsc* argDsc { break; } - assert(regState->rsIsFloat == false); regState->rsCalleeRegArgMaskLiveIn |= genRegMask(nextArgReg); } } diff --git a/src/coreclr/src/jit/regset.cpp b/src/coreclr/src/jit/regset.cpp index a550df415c0302..0ebde49eadfb27 100644 --- a/src/coreclr/src/jit/regset.cpp +++ b/src/coreclr/src/jit/regset.cpp @@ -285,18 +285,17 @@ RegSet::SpillDsc* RegSet::rsGetSpillInfo(GenTree* tree, regNumber reg, SpillDsc* // Return Value: // None. // -// Assumption: -// RyuJIT backend specific: in case of multi-reg call nodes, GTF_SPILL -// flag associated with the reg that is being spilled is cleared. The -// caller of this method is expected to clear GTF_SPILL flag on call -// node after all of its registers marked for spilling are spilled. +// Notes: +// For multi-reg nodes, only the spill flag associated with this reg is cleared. +// The spill flag on the node should be cleared by the caller of this method. // void RegSet::rsSpillTree(regNumber reg, GenTree* tree, unsigned regIdx /* =0 */) { assert(tree != nullptr); - GenTreeCall* call = nullptr; - var_types treeType; + GenTreeCall* call = nullptr; + GenTreeLclVar* lcl = nullptr; + var_types treeType; #if defined(TARGET_ARM) GenTreePutArgSplit* splitArg = nullptr; GenTreeMultiRegOp* multiReg = nullptr; @@ -304,9 +303,9 @@ void RegSet::rsSpillTree(regNumber reg, GenTree* tree, unsigned regIdx /* =0 */) if (tree->IsMultiRegCall()) { - call = tree->AsCall(); - ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); - treeType = retTypeDesc->GetReturnRegType(regIdx); + call = tree->AsCall(); + const ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc(); + treeType = retTypeDesc->GetReturnRegType(regIdx); } #ifdef TARGET_ARM else if (tree->OperIsPutArgSplit()) @@ -320,6 +319,12 @@ void RegSet::rsSpillTree(regNumber reg, GenTree* tree, unsigned regIdx /* =0 */) treeType = multiReg->GetRegType(regIdx); } #endif // TARGET_ARM + else if (tree->IsMultiRegLclVar()) + { + GenTreeLclVar* lcl = tree->AsLclVar(); + LclVarDsc* varDsc = m_rsCompiler->lvaGetDesc(lcl->GetLclNum()); + treeType = varDsc->TypeGet(); + } else { treeType = tree->TypeGet(); @@ -345,9 +350,8 @@ void RegSet::rsSpillTree(regNumber reg, GenTree* tree, unsigned regIdx /* =0 */) // vars should be handled elsewhere, and to prevent // spilling twice clear GTF_SPILL flag on tree node. // - // In case of multi-reg call nodes only the spill flag - // associated with the reg is cleared. Spill flag on - // call node should be cleared by the caller of this method. + // In case of multi-reg nodes, only the spill flag associated with this reg is cleared. + // The spill flag on the node should be cleared by the caller of this method. assert((tree->gtFlags & GTF_SPILL) != 0); unsigned regFlags = 0; @@ -371,6 +375,12 @@ void RegSet::rsSpillTree(regNumber reg, GenTree* tree, unsigned regIdx /* =0 */) regFlags &= ~GTF_SPILL; } #endif // TARGET_ARM + else if (lcl != nullptr) + { + regFlags = lcl->GetRegSpillFlagByIdx(regIdx); + assert((regFlags & GTF_SPILL) != 0); + regFlags &= ~GTF_SPILL; + } else { assert(!varTypeIsMultiReg(tree)); @@ -446,6 +456,11 @@ void RegSet::rsSpillTree(regNumber reg, GenTree* tree, unsigned regIdx /* =0 */) multiReg->SetRegSpillFlagByIdx(regFlags, regIdx); } #endif // TARGET_ARM + else if (lcl != nullptr) + { + regFlags |= GTF_SPILLED; + lcl->SetRegSpillFlagByIdx(regFlags, regIdx); + } } #if defined(TARGET_X86) @@ -565,6 +580,13 @@ TempDsc* RegSet::rsUnspillInPlace(GenTree* tree, regNumber oldReg, unsigned regI multiReg->SetRegSpillFlagByIdx(flags, regIdx); } #endif // TARGET_ARM + else if (tree->IsMultiRegLclVar()) + { + GenTreeLclVar* lcl = tree->AsLclVar(); + unsigned flags = lcl->GetRegSpillFlagByIdx(regIdx); + flags &= ~GTF_SPILLED; + lcl->SetRegSpillFlagByIdx(flags, regIdx); + } else { tree->gtFlags &= ~GTF_SPILLED; diff --git a/src/coreclr/src/jit/simd.cpp b/src/coreclr/src/jit/simd.cpp index 9077971e67cf30..3bd38ef537199c 100644 --- a/src/coreclr/src/jit/simd.cpp +++ b/src/coreclr/src/jit/simd.cpp @@ -162,11 +162,13 @@ var_types Compiler::getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, u if (typeHnd == m_simdHandleCache->SIMDFloatHandle) { simdBaseType = TYP_FLOAT; + size = getSIMDVectorRegisterByteLength(); JITDUMP(" Known type SIMD Vector\n"); } else if (typeHnd == m_simdHandleCache->SIMDIntHandle) { simdBaseType = TYP_INT; + size = getSIMDVectorRegisterByteLength(); JITDUMP(" Known type SIMD Vector\n"); } else if (typeHnd == m_simdHandleCache->SIMDVector2Handle) @@ -192,46 +194,55 @@ var_types Compiler::getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, u } else if (typeHnd == m_simdHandleCache->SIMDVectorHandle) { + size = getSIMDVectorRegisterByteLength(); JITDUMP(" Known type Vector\n"); } else if (typeHnd == m_simdHandleCache->SIMDUShortHandle) { simdBaseType = TYP_USHORT; + size = getSIMDVectorRegisterByteLength(); JITDUMP(" Known type SIMD Vector\n"); } else if (typeHnd == m_simdHandleCache->SIMDUByteHandle) { simdBaseType = TYP_UBYTE; + size = getSIMDVectorRegisterByteLength(); JITDUMP(" Known type SIMD Vector\n"); } else if (typeHnd == m_simdHandleCache->SIMDDoubleHandle) { simdBaseType = TYP_DOUBLE; + size = getSIMDVectorRegisterByteLength(); JITDUMP(" Known type SIMD Vector\n"); } else if (typeHnd == m_simdHandleCache->SIMDLongHandle) { simdBaseType = TYP_LONG; + size = getSIMDVectorRegisterByteLength(); JITDUMP(" Known type SIMD Vector\n"); } else if (typeHnd == m_simdHandleCache->SIMDShortHandle) { simdBaseType = TYP_SHORT; + size = getSIMDVectorRegisterByteLength(); JITDUMP(" Known type SIMD Vector\n"); } else if (typeHnd == m_simdHandleCache->SIMDByteHandle) { simdBaseType = TYP_BYTE; + size = getSIMDVectorRegisterByteLength(); JITDUMP(" Known type SIMD Vector\n"); } else if (typeHnd == m_simdHandleCache->SIMDUIntHandle) { simdBaseType = TYP_UINT; + size = getSIMDVectorRegisterByteLength(); JITDUMP(" Known type SIMD Vector\n"); } else if (typeHnd == m_simdHandleCache->SIMDULongHandle) { simdBaseType = TYP_ULONG; + size = getSIMDVectorRegisterByteLength(); JITDUMP(" Known type SIMD Vector\n"); } @@ -253,6 +264,8 @@ var_types Compiler::getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, u { if (wcsncmp(&(className[16]), W("Vector`1["), 9) == 0) { + size = getSIMDVectorRegisterByteLength(); + if (wcsncmp(&(className[25]), W("System.Single"), 13) == 0) { m_simdHandleCache->SIMDFloatHandle = typeHnd; @@ -348,6 +361,7 @@ var_types Compiler::getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, u else if (wcsncmp(&(className[16]), W("Vector"), 6) == 0) { m_simdHandleCache->SIMDVectorHandle = typeHnd; + size = getSIMDVectorRegisterByteLength(); JITDUMP(" Found type Vector\n"); } else @@ -356,18 +370,6 @@ var_types Compiler::getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, u } } } - if (simdBaseType != TYP_UNKNOWN && sizeBytes != nullptr) - { - // If not a fixed size vector then its size is same as SIMD vector - // register length in bytes - if (size == 0) - { - size = getSIMDVectorRegisterByteLength(); - } - - *sizeBytes = size; - setUsesSIMDTypes(true); - } } #ifdef FEATURE_HW_INTRINSICS else if (isIntrinsicType(typeHnd)) @@ -776,18 +778,18 @@ var_types Compiler::getBaseTypeAndSizeOfSIMDType(CORINFO_CLASS_HANDLE typeHnd, u simdBaseType = TYP_UNKNOWN; } #endif // TARGET_XARCH + } +#endif // FEATURE_HW_INTRINSICS - if (sizeBytes != nullptr) - { - *sizeBytes = size; - } + if (sizeBytes != nullptr) + { + *sizeBytes = size; + } - if (simdBaseType != TYP_UNKNOWN) - { - setUsesSIMDTypes(true); - } + if (simdBaseType != TYP_UNKNOWN) + { + setUsesSIMDTypes(true); } -#endif // FEATURE_HW_INTRINSICS return simdBaseType; } @@ -1073,19 +1075,9 @@ const SIMDIntrinsicInfo* Compiler::getSIMDIntrinsicInfo(CORINFO_CLASS_HANDLE* in case SIMDIntrinsicSub: case SIMDIntrinsicMul: case SIMDIntrinsicDiv: - case SIMDIntrinsicSqrt: - case SIMDIntrinsicMin: - case SIMDIntrinsicMax: - case SIMDIntrinsicAbs: case SIMDIntrinsicEqual: - case SIMDIntrinsicLessThan: - case SIMDIntrinsicLessThanOrEqual: - case SIMDIntrinsicGreaterThan: - case SIMDIntrinsicGreaterThanOrEqual: case SIMDIntrinsicBitwiseAnd: - case SIMDIntrinsicBitwiseAndNot: case SIMDIntrinsicBitwiseOr: - case SIMDIntrinsicBitwiseXor: case SIMDIntrinsicDotProduct: case SIMDIntrinsicCast: case SIMDIntrinsicConvertToSingle: @@ -1266,218 +1258,6 @@ SIMDIntrinsicID Compiler::impSIMDLongRelOpEqual(CORINFO_CLASS_HANDLE typeHnd, SIMDIntrinsicShuffleSSE2, TYP_INT, size); return SIMDIntrinsicBitwiseAnd; } - -// impSIMDLongRelOpGreaterThan: transforms operands and returns the SIMD intrinsic to be applied on -// transformed operands to obtain > comparison result. -// -// Arguments: -// typeHnd - type handle of SIMD vector -// size - SIMD vector size -// pOp1 - in-out parameter; first operand -// pOp2 - in-out parameter; second operand -// -// Return Value: -// Modifies in-out params pOp1, pOp2 and returns intrinsic ID to be applied to modified operands -// -SIMDIntrinsicID Compiler::impSIMDLongRelOpGreaterThan(CORINFO_CLASS_HANDLE typeHnd, - unsigned size, - GenTree** pOp1, - GenTree** pOp2) -{ - var_types simdType = (*pOp1)->TypeGet(); - assert(varTypeIsSIMD(simdType) && ((*pOp2)->TypeGet() == simdType)); - - // GreaterThan(v1, v2) where v1 and v2 are vector long. - // Let us consider the case of single long element comparison. - // say L1 = (x1, y1) and L2 = (x2, y2) where x1, y1, x2, and y2 are 32-bit integers that comprise the longs L1 and - // L2. - // - // GreaterThan(L1, L2) can be expressed in terms of > relationship between 32-bit integers that comprise L1 and L2 - // as - // = (x1, y1) > (x2, y2) - // = (x1 > x2) || [(x1 == x2) && (y1 > y2)] - eq (1) - // - // t = (v1 > v2) 32-bit signed comparison - // u = (v1 == v2) 32-bit sized element equality - // v = (v1 > v2) 32-bit unsigned comparison - // - // z = shuffle(t, (3, 3, 1, 1)) - This corresponds to (x1 > x2) in eq(1) above - // t1 = Shuffle(v, (2, 2, 0, 0)) - This corresponds to (y1 > y2) in eq(1) above - // u1 = Shuffle(u, (3, 3, 1, 1)) - This corresponds to (x1 == x2) in eq(1) above - // w = And(t1, u1) - This corresponds to [(x1 == x2) && (y1 > y2)] in eq(1) above - // Result = BitwiseOr(z, w) - - // Since op1 and op2 gets used multiple times, make sure side effects are computed. - GenTree* dupOp1 = nullptr; - GenTree* dupOp2 = nullptr; - GenTree* dupDupOp1 = nullptr; - GenTree* dupDupOp2 = nullptr; - - if (((*pOp1)->gtFlags & GTF_SIDE_EFFECT) != 0) - { - dupOp1 = fgInsertCommaFormTemp(pOp1, typeHnd); - dupDupOp1 = gtNewLclvNode(dupOp1->AsLclVarCommon()->GetLclNum(), simdType); - } - else - { - dupOp1 = gtCloneExpr(*pOp1); - dupDupOp1 = gtCloneExpr(*pOp1); - } - - if (((*pOp2)->gtFlags & GTF_SIDE_EFFECT) != 0) - { - dupOp2 = fgInsertCommaFormTemp(pOp2, typeHnd); - dupDupOp2 = gtNewLclvNode(dupOp2->AsLclVarCommon()->GetLclNum(), simdType); - } - else - { - dupOp2 = gtCloneExpr(*pOp2); - dupDupOp2 = gtCloneExpr(*pOp2); - } - - assert(dupDupOp1 != nullptr && dupDupOp2 != nullptr); - assert(dupOp1 != nullptr && dupOp2 != nullptr); - assert(*pOp1 != nullptr && *pOp2 != nullptr); - - // v1GreaterThanv2Signed - signed 32-bit comparison - GenTree* v1GreaterThanv2Signed = gtNewSIMDNode(simdType, *pOp1, *pOp2, SIMDIntrinsicGreaterThan, TYP_INT, size); - - // v1Equalsv2 - 32-bit equality - GenTree* v1Equalsv2 = gtNewSIMDNode(simdType, dupOp1, dupOp2, SIMDIntrinsicEqual, TYP_INT, size); - - // v1GreaterThanv2Unsigned - unsigned 32-bit comparison - var_types tempBaseType = TYP_UINT; - SIMDIntrinsicID sid = impSIMDRelOp(SIMDIntrinsicGreaterThan, typeHnd, size, &tempBaseType, &dupDupOp1, &dupDupOp2); - GenTree* v1GreaterThanv2Unsigned = gtNewSIMDNode(simdType, dupDupOp1, dupDupOp2, sid, tempBaseType, size); - - GenTree* z = gtNewSIMDNode(simdType, v1GreaterThanv2Signed, gtNewIconNode(SHUFFLE_WWYY, TYP_INT), - SIMDIntrinsicShuffleSSE2, TYP_FLOAT, size); - GenTree* t1 = gtNewSIMDNode(simdType, v1GreaterThanv2Unsigned, gtNewIconNode(SHUFFLE_ZZXX, TYP_INT), - SIMDIntrinsicShuffleSSE2, TYP_FLOAT, size); - GenTree* u1 = gtNewSIMDNode(simdType, v1Equalsv2, gtNewIconNode(SHUFFLE_WWYY, TYP_INT), SIMDIntrinsicShuffleSSE2, - TYP_FLOAT, size); - GenTree* w = gtNewSIMDNode(simdType, u1, t1, SIMDIntrinsicBitwiseAnd, TYP_INT, size); - - *pOp1 = z; - *pOp2 = w; - return SIMDIntrinsicBitwiseOr; -} - -// impSIMDLongRelOpGreaterThanOrEqual: transforms operands and returns the SIMD intrinsic to be applied on -// transformed operands to obtain >= comparison result. -// -// Arguments: -// typeHnd - type handle of SIMD vector -// size - SIMD vector size -// pOp1 - in-out parameter; first operand -// pOp2 - in-out parameter; second operand -// -// Return Value: -// Modifies in-out params pOp1, pOp2 and returns intrinsic ID to be applied to modified operands -// -SIMDIntrinsicID Compiler::impSIMDLongRelOpGreaterThanOrEqual(CORINFO_CLASS_HANDLE typeHnd, - unsigned size, - GenTree** pOp1, - GenTree** pOp2) -{ - var_types simdType = (*pOp1)->TypeGet(); - assert(varTypeIsSIMD(simdType) && ((*pOp2)->TypeGet() == simdType)); - - // expand this to (a == b) | (a > b) - GenTree* dupOp1 = nullptr; - GenTree* dupOp2 = nullptr; - - if (((*pOp1)->gtFlags & GTF_SIDE_EFFECT) != 0) - { - dupOp1 = fgInsertCommaFormTemp(pOp1, typeHnd); - } - else - { - dupOp1 = gtCloneExpr(*pOp1); - } - - if (((*pOp2)->gtFlags & GTF_SIDE_EFFECT) != 0) - { - dupOp2 = fgInsertCommaFormTemp(pOp2, typeHnd); - } - else - { - dupOp2 = gtCloneExpr(*pOp2); - } - - assert(dupOp1 != nullptr && dupOp2 != nullptr); - assert(*pOp1 != nullptr && *pOp2 != nullptr); - - // (a==b) - SIMDIntrinsicID id = impSIMDLongRelOpEqual(typeHnd, size, pOp1, pOp2); - *pOp1 = gtNewSIMDNode(simdType, *pOp1, *pOp2, id, TYP_LONG, size); - - // (a > b) - id = impSIMDLongRelOpGreaterThan(typeHnd, size, &dupOp1, &dupOp2); - *pOp2 = gtNewSIMDNode(simdType, dupOp1, dupOp2, id, TYP_LONG, size); - - return SIMDIntrinsicBitwiseOr; -} - -// impSIMDInt32OrSmallIntRelOpGreaterThanOrEqual: transforms operands and returns the SIMD intrinsic to be applied on -// transformed operands to obtain >= comparison result in case of integer base type vectors -// -// Arguments: -// typeHnd - type handle of SIMD vector -// size - SIMD vector size -// baseType - base type of SIMD vector -// pOp1 - in-out parameter; first operand -// pOp2 - in-out parameter; second operand -// -// Return Value: -// Modifies in-out params pOp1, pOp2 and returns intrinsic ID to be applied to modified operands -// -SIMDIntrinsicID Compiler::impSIMDIntegralRelOpGreaterThanOrEqual( - CORINFO_CLASS_HANDLE typeHnd, unsigned size, var_types baseType, GenTree** pOp1, GenTree** pOp2) -{ - var_types simdType = (*pOp1)->TypeGet(); - assert(varTypeIsSIMD(simdType) && ((*pOp2)->TypeGet() == simdType)); - - // This routine should be used only for integer base type vectors - assert(varTypeIsIntegral(baseType)); - if ((getSIMDSupportLevel() == SIMD_SSE2_Supported) && ((baseType == TYP_LONG) || baseType == TYP_UBYTE)) - { - return impSIMDLongRelOpGreaterThanOrEqual(typeHnd, size, pOp1, pOp2); - } - - // expand this to (a == b) | (a > b) - GenTree* dupOp1 = nullptr; - GenTree* dupOp2 = nullptr; - - if (((*pOp1)->gtFlags & GTF_SIDE_EFFECT) != 0) - { - dupOp1 = fgInsertCommaFormTemp(pOp1, typeHnd); - } - else - { - dupOp1 = gtCloneExpr(*pOp1); - } - - if (((*pOp2)->gtFlags & GTF_SIDE_EFFECT) != 0) - { - dupOp2 = fgInsertCommaFormTemp(pOp2, typeHnd); - } - else - { - dupOp2 = gtCloneExpr(*pOp2); - } - - assert(dupOp1 != nullptr && dupOp2 != nullptr); - assert(*pOp1 != nullptr && *pOp2 != nullptr); - - // (a==b) - *pOp1 = gtNewSIMDNode(simdType, *pOp1, *pOp2, SIMDIntrinsicEqual, baseType, size); - - // (a > b) - *pOp2 = gtNewSIMDNode(simdType, dupOp1, dupOp2, SIMDIntrinsicGreaterThan, baseType, size); - - return SIMDIntrinsicBitwiseOr; -} #endif // TARGET_XARCH // Transforms operands and returns the SIMD intrinsic to be applied on @@ -1512,32 +1292,9 @@ SIMDIntrinsicID Compiler::impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId, if (varTypeIsFloating(baseType)) { - // SSE2/AVX doesn't support > and >= on vector float/double. - // Therefore, we need to use < and <= with swapped operands - if (relOpIntrinsicId == SIMDIntrinsicGreaterThan || relOpIntrinsicId == SIMDIntrinsicGreaterThanOrEqual) - { - GenTree* tmp = *pOp1; - *pOp1 = *pOp2; - *pOp2 = tmp; - - intrinsicID = - (relOpIntrinsicId == SIMDIntrinsicGreaterThan) ? SIMDIntrinsicLessThan : SIMDIntrinsicLessThanOrEqual; - } } else if (varTypeIsIntegral(baseType)) { - // SSE/AVX doesn't support < and <= on integer base type vectors. - // Therefore, we need to use > and >= with swapped operands. - if (intrinsicID == SIMDIntrinsicLessThan || intrinsicID == SIMDIntrinsicLessThanOrEqual) - { - GenTree* tmp = *pOp1; - *pOp1 = *pOp2; - *pOp2 = tmp; - - intrinsicID = (relOpIntrinsicId == SIMDIntrinsicLessThan) ? SIMDIntrinsicGreaterThan - : SIMDIntrinsicGreaterThanOrEqual; - } - if ((getSIMDSupportLevel() == SIMD_SSE2_Supported) && baseType == TYP_LONG) { // There is no direct SSE2 support for comparing TYP_LONG vectors. @@ -1546,28 +1303,13 @@ SIMDIntrinsicID Compiler::impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId, { intrinsicID = impSIMDLongRelOpEqual(typeHnd, size, pOp1, pOp2); } - else if (intrinsicID == SIMDIntrinsicGreaterThan) - { - intrinsicID = impSIMDLongRelOpGreaterThan(typeHnd, size, pOp1, pOp2); - } - else if (intrinsicID == SIMDIntrinsicGreaterThanOrEqual) - { - intrinsicID = impSIMDLongRelOpGreaterThanOrEqual(typeHnd, size, pOp1, pOp2); - } else { unreached(); } } // SSE2 and AVX direct support for signed comparison of int32, int16 and int8 types - else if (!varTypeIsUnsigned(baseType)) - { - if (intrinsicID == SIMDIntrinsicGreaterThanOrEqual) - { - intrinsicID = impSIMDIntegralRelOpGreaterThanOrEqual(typeHnd, size, baseType, pOp1, pOp2); - } - } - else // unsigned + else if (varTypeIsUnsigned(baseType)) { // Vector, Vector, Vector and Vector: // SSE2 supports > for signed comparison. Therefore, to use it for @@ -1642,21 +1384,7 @@ SIMDIntrinsicID Compiler::impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId, return impSIMDRelOp(intrinsicID, typeHnd, size, inOutBaseType, pOp1, pOp2); } } -#elif defined(TARGET_ARM64) - // TODO-ARM64-CQ handle comparisons against zero - - // TARGET_ARM64 doesn't support < and <= on register register comparisons - // Therefore, we need to use > and >= with swapped operands. - if (intrinsicID == SIMDIntrinsicLessThan || intrinsicID == SIMDIntrinsicLessThanOrEqual) - { - GenTree* tmp = *pOp1; - *pOp1 = *pOp2; - *pOp2 = tmp; - - intrinsicID = - (intrinsicID == SIMDIntrinsicLessThan) ? SIMDIntrinsicGreaterThan : SIMDIntrinsicGreaterThanOrEqual; - } -#else // !TARGET_XARCH +#elif !defined(TARGET_ARM64) assert(!"impSIMDRelOp() unimplemented on target arch"); unreached(); #endif // !TARGET_XARCH @@ -1664,411 +1392,6 @@ SIMDIntrinsicID Compiler::impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId, return intrinsicID; } -//------------------------------------------------------------------------- -// impSIMDAbs: creates GT_SIMD node to compute Abs value of a given vector. -// -// Arguments: -// typeHnd - type handle of SIMD vector -// baseType - base type of vector -// size - vector size in bytes -// op1 - operand of Abs intrinsic -// -GenTree* Compiler::impSIMDAbs(CORINFO_CLASS_HANDLE typeHnd, var_types baseType, unsigned size, GenTree* op1) -{ - assert(varTypeIsSIMD(op1)); - - var_types simdType = op1->TypeGet(); - GenTree* retVal = nullptr; - -#ifdef TARGET_XARCH - // When there is no direct support, Abs(v) could be computed - // on integer vectors as follows: - // BitVector = v < vector.Zero - // result = ConditionalSelect(BitVector, vector.Zero - v, v) - - bool useConditionalSelect = false; - if (getSIMDSupportLevel() == SIMD_SSE2_Supported) - { - // SSE2 doesn't support abs on signed integer type vectors. - if (baseType == TYP_LONG || baseType == TYP_INT || baseType == TYP_SHORT || baseType == TYP_BYTE) - { - useConditionalSelect = true; - } - } - else - { - assert(getSIMDSupportLevel() >= SIMD_SSE4_Supported); - if (baseType == TYP_LONG) - { - // SSE4/AVX2 don't support abs on long type vector. - useConditionalSelect = true; - } - } - - if (useConditionalSelect) - { - // This works only on integer vectors not on float/double vectors. - assert(varTypeIsIntegral(baseType)); - - GenTree* op1Assign; - unsigned op1LclNum; - - if (op1->OperGet() == GT_LCL_VAR) - { - op1LclNum = op1->AsLclVarCommon()->GetLclNum(); - op1Assign = nullptr; - } - else - { - op1LclNum = lvaGrabTemp(true DEBUGARG("SIMD Abs op1")); - lvaSetStruct(op1LclNum, typeHnd, false); - op1Assign = gtNewTempAssign(op1LclNum, op1); - op1 = gtNewLclvNode(op1LclNum, op1->TypeGet()); - } - - // Assign Vector.Zero to a temp since it is needed more than once - GenTree* vecZero = gtNewSIMDVectorZero(simdType, baseType, size); - unsigned vecZeroLclNum = lvaGrabTemp(true DEBUGARG("SIMD Abs VecZero")); - lvaSetStruct(vecZeroLclNum, typeHnd, false); - GenTree* vecZeroAssign = gtNewTempAssign(vecZeroLclNum, vecZero); - - // Construct BitVector = v < vector.Zero - GenTree* bitVecOp1 = op1; - GenTree* bitVecOp2 = gtNewLclvNode(vecZeroLclNum, vecZero->TypeGet()); - var_types relOpBaseType = baseType; - SIMDIntrinsicID relOpIntrinsic = - impSIMDRelOp(SIMDIntrinsicLessThan, typeHnd, size, &relOpBaseType, &bitVecOp1, &bitVecOp2); - GenTree* bitVec = gtNewSIMDNode(simdType, bitVecOp1, bitVecOp2, relOpIntrinsic, relOpBaseType, size); - unsigned bitVecLclNum = lvaGrabTemp(true DEBUGARG("SIMD Abs bitVec")); - lvaSetStruct(bitVecLclNum, typeHnd, false); - GenTree* bitVecAssign = gtNewTempAssign(bitVecLclNum, bitVec); - bitVec = gtNewLclvNode(bitVecLclNum, bitVec->TypeGet()); - - // Construct condSelectOp1 = vector.Zero - v - GenTree* subOp1 = gtNewLclvNode(vecZeroLclNum, vecZero->TypeGet()); - GenTree* subOp2 = gtNewLclvNode(op1LclNum, op1->TypeGet()); - GenTree* negVec = gtNewSIMDNode(simdType, subOp1, subOp2, SIMDIntrinsicSub, baseType, size); - - // Construct ConditionalSelect(bitVec, vector.Zero - v, v) - GenTree* vec = gtNewLclvNode(op1LclNum, op1->TypeGet()); - retVal = impSIMDSelect(typeHnd, baseType, size, bitVec, negVec, vec); - - // Prepend bitVec assignment to retVal. - // retVal = (tmp2 = v < tmp1), CondSelect(tmp2, tmp1 - v, v) - retVal = gtNewOperNode(GT_COMMA, simdType, bitVecAssign, retVal); - - // Prepend vecZero assignment to retVal. - // retVal = (tmp1 = vector.Zero), (tmp2 = v < tmp1), CondSelect(tmp2, tmp1 - v, v) - retVal = gtNewOperNode(GT_COMMA, simdType, vecZeroAssign, retVal); - - // If op1 was assigned to a temp, prepend that to retVal. - if (op1Assign != nullptr) - { - // retVal = (v=op1), (tmp1 = vector.Zero), (tmp2 = v < tmp1), CondSelect(tmp2, tmp1 - v, v) - retVal = gtNewOperNode(GT_COMMA, simdType, op1Assign, retVal); - } - } - else if (varTypeIsFloating(baseType)) - { - // Abs(vf) = vf & new SIMDVector(0x7fffffff); - // Abs(vd) = vf & new SIMDVector(0x7fffffffffffffff); - GenTree* bitMask = nullptr; - if (baseType == TYP_FLOAT) - { - float f; - static_assert_no_msg(sizeof(float) == sizeof(int)); - *((int*)&f) = 0x7fffffff; - bitMask = gtNewDconNode(f); - } - else if (baseType == TYP_DOUBLE) - { - double d; - static_assert_no_msg(sizeof(double) == sizeof(__int64)); - *((__int64*)&d) = 0x7fffffffffffffffLL; - bitMask = gtNewDconNode(d); - } - - assert(bitMask != nullptr); - bitMask->gtType = baseType; - GenTree* bitMaskVector = gtNewSIMDNode(simdType, bitMask, SIMDIntrinsicInit, baseType, size); - retVal = gtNewSIMDNode(simdType, op1, bitMaskVector, SIMDIntrinsicBitwiseAnd, baseType, size); - } - else if (baseType == TYP_USHORT || baseType == TYP_UBYTE || baseType == TYP_UINT || baseType == TYP_ULONG) - { - // Abs is a no-op on unsigned integer type vectors - retVal = op1; - } - else - { - assert(getSIMDSupportLevel() >= SIMD_SSE4_Supported); - assert(baseType != TYP_LONG); - - retVal = gtNewSIMDNode(simdType, op1, SIMDIntrinsicAbs, baseType, size); - } -#elif defined(TARGET_ARM64) - if (varTypeIsUnsigned(baseType)) - { - // Abs is a no-op on unsigned integer type vectors - retVal = op1; - } - else - { - retVal = gtNewSIMDNode(simdType, op1, SIMDIntrinsicAbs, baseType, size); - } -#else // !defined(TARGET_XARCH)_ && !defined(TARGET_ARM64) - assert(!"Abs intrinsic on non-xarch target not implemented"); -#endif // !TARGET_XARCH - - return retVal; -} - -// Creates a GT_SIMD tree for Select operation -// -// Arguments: -// typeHnd - type handle of SIMD vector -// baseType - base type of SIMD vector -// size - SIMD vector size -// op1 - first operand = Condition vector vc -// op2 - second operand = va -// op3 - third operand = vb -// -// Return Value: -// Returns GT_SIMD tree that computes Select(vc, va, vb) -// -GenTree* Compiler::impSIMDSelect( - CORINFO_CLASS_HANDLE typeHnd, var_types baseType, unsigned size, GenTree* op1, GenTree* op2, GenTree* op3) -{ - assert(varTypeIsSIMD(op1)); - var_types simdType = op1->TypeGet(); - assert(op2->TypeGet() == simdType); - assert(op3->TypeGet() == simdType); - - // TODO-ARM64-CQ Support generating select instruction for SIMD - - // Select(BitVector vc, va, vb) = (va & vc) | (vb & !vc) - // Select(op1, op2, op3) = (op2 & op1) | (op3 & !op1) - // = SIMDIntrinsicBitwiseOr(SIMDIntrinsicBitwiseAnd(op2, op1), - // SIMDIntrinsicBitwiseAndNot(op3, op1)) - // - // If Op1 has side effect, create an assignment to a temp - GenTree* tmp = op1; - GenTree* asg = nullptr; - if ((op1->gtFlags & GTF_SIDE_EFFECT) != 0) - { - unsigned lclNum = lvaGrabTemp(true DEBUGARG("SIMD Select")); - lvaSetStruct(lclNum, typeHnd, false); - tmp = gtNewLclvNode(lclNum, op1->TypeGet()); - asg = gtNewTempAssign(lclNum, op1); - } - - GenTree* andExpr = gtNewSIMDNode(simdType, op2, tmp, SIMDIntrinsicBitwiseAnd, baseType, size); - GenTree* dupOp1 = gtCloneExpr(tmp); - assert(dupOp1 != nullptr); -#ifdef TARGET_ARM64 - // ARM64 implements SIMDIntrinsicBitwiseAndNot as Left & ~Right - GenTree* andNotExpr = gtNewSIMDNode(simdType, op3, dupOp1, SIMDIntrinsicBitwiseAndNot, baseType, size); -#else - // XARCH implements SIMDIntrinsicBitwiseAndNot as ~Left & Right - GenTree* andNotExpr = gtNewSIMDNode(simdType, dupOp1, op3, SIMDIntrinsicBitwiseAndNot, baseType, size); -#endif - GenTree* simdTree = gtNewSIMDNode(simdType, andExpr, andNotExpr, SIMDIntrinsicBitwiseOr, baseType, size); - - // If asg not null, create a GT_COMMA tree. - if (asg != nullptr) - { - simdTree = gtNewOperNode(GT_COMMA, simdTree->TypeGet(), asg, simdTree); - } - - return simdTree; -} - -// Creates a GT_SIMD tree for Min/Max operation -// -// Arguments: -// IntrinsicId - SIMD intrinsic Id, either Min or Max -// typeHnd - type handle of SIMD vector -// baseType - base type of SIMD vector -// size - SIMD vector size -// op1 - first operand = va -// op2 - second operand = vb -// -// Return Value: -// Returns GT_SIMD tree that computes Max(va, vb) -// -GenTree* Compiler::impSIMDMinMax(SIMDIntrinsicID intrinsicId, - CORINFO_CLASS_HANDLE typeHnd, - var_types baseType, - unsigned size, - GenTree* op1, - GenTree* op2) -{ - assert(intrinsicId == SIMDIntrinsicMin || intrinsicId == SIMDIntrinsicMax); - assert(varTypeIsSIMD(op1)); - var_types simdType = op1->TypeGet(); - assert(op2->TypeGet() == simdType); - -#if defined(TARGET_XARCH) || defined(TARGET_ARM64) - GenTree* simdTree = nullptr; - -#ifdef TARGET_XARCH - // SSE2 has direct support for float/double/signed word/unsigned byte. - // SSE4.1 has direct support for int32/uint32/signed byte/unsigned word. - // For other integer types we compute min/max as follows - // - // int32/uint32 (SSE2) - // int64/uint64 (SSE2&SSE4): - // compResult = (op1 < op2) in case of Min - // (op1 > op2) in case of Max - // Min/Max(op1, op2) = Select(compResult, op1, op2) - // - // unsigned word (SSE2): - // op1 = op1 - 2^15 ; to make it fit within a signed word - // op2 = op2 - 2^15 ; to make it fit within a signed word - // result = SSE2 signed word Min/Max(op1, op2) - // result = result + 2^15 ; readjust it back - // - // signed byte (SSE2): - // op1 = op1 + 2^7 ; to make it unsigned - // op1 = op1 + 2^7 ; to make it unsigned - // result = SSE2 unsigned byte Min/Max(op1, op2) - // result = result - 2^15 ; readjust it back - - if (varTypeIsFloating(baseType) || baseType == TYP_SHORT || baseType == TYP_UBYTE || - (getSIMDSupportLevel() >= SIMD_SSE4_Supported && - (baseType == TYP_BYTE || baseType == TYP_INT || baseType == TYP_UINT || baseType == TYP_USHORT))) - { - // SSE2 or SSE4.1 has direct support - simdTree = gtNewSIMDNode(simdType, op1, op2, intrinsicId, baseType, size); - } - else if (baseType == TYP_USHORT || baseType == TYP_BYTE) - { - assert(getSIMDSupportLevel() == SIMD_SSE2_Supported); - int constVal; - SIMDIntrinsicID operIntrinsic; - SIMDIntrinsicID adjustIntrinsic; - var_types minMaxOperBaseType; - if (baseType == TYP_USHORT) - { - constVal = 0x80008000; - operIntrinsic = SIMDIntrinsicSub; - adjustIntrinsic = SIMDIntrinsicAdd; - minMaxOperBaseType = TYP_SHORT; - } - else - { - assert(baseType == TYP_BYTE); - constVal = 0x80808080; - operIntrinsic = SIMDIntrinsicAdd; - adjustIntrinsic = SIMDIntrinsicSub; - minMaxOperBaseType = TYP_UBYTE; - } - - GenTree* initVal = gtNewIconNode(constVal); - GenTree* constVector = gtNewSIMDNode(simdType, initVal, nullptr, SIMDIntrinsicInit, TYP_INT, size); - - // Assign constVector to a temp, since we intend to use it more than once - // TODO-CQ: We have quite a few such constant vectors constructed during - // the importation of SIMD intrinsics. Make sure that we have a single - // temp per distinct constant per method. - GenTree* tmp = fgInsertCommaFormTemp(&constVector, typeHnd); - - // op1 = op1 - constVector - // op2 = op2 - constVector - op1 = gtNewSIMDNode(simdType, op1, constVector, operIntrinsic, baseType, size); - op2 = gtNewSIMDNode(simdType, op2, tmp, operIntrinsic, baseType, size); - - // compute min/max of op1 and op2 considering them as if minMaxOperBaseType - simdTree = gtNewSIMDNode(simdType, op1, op2, intrinsicId, minMaxOperBaseType, size); - - // re-adjust the value by adding or subtracting constVector - tmp = gtNewLclvNode(tmp->AsLclVarCommon()->GetLclNum(), tmp->TypeGet()); - simdTree = gtNewSIMDNode(simdType, simdTree, tmp, adjustIntrinsic, baseType, size); - } -#elif defined(TARGET_ARM64) - // Arm64 has direct support for all types except int64/uint64 - // For which we compute min/max as follows - // - // int64/uint64 - // compResult = (op1 < op2) in case of Min - // (op1 > op2) in case of Max - // Min/Max(op1, op2) = Select(compResult, op1, op2) - if (baseType != TYP_ULONG && baseType != TYP_LONG) - { - simdTree = gtNewSIMDNode(simdType, op1, op2, intrinsicId, baseType, size); - } -#endif - else - { - GenTree* dupOp1 = nullptr; - GenTree* dupOp2 = nullptr; - GenTree* op1Assign = nullptr; - GenTree* op2Assign = nullptr; - unsigned op1LclNum; - unsigned op2LclNum; - - if ((op1->gtFlags & GTF_SIDE_EFFECT) != 0) - { - op1LclNum = lvaGrabTemp(true DEBUGARG("SIMD Min/Max")); - lvaSetStruct(op1LclNum, typeHnd, false); - dupOp1 = gtNewLclvNode(op1LclNum, op1->TypeGet()); - op1Assign = gtNewTempAssign(op1LclNum, op1); - op1 = gtNewLclvNode(op1LclNum, op1->TypeGet()); - } - else - { - dupOp1 = gtCloneExpr(op1); - } - - if ((op2->gtFlags & GTF_SIDE_EFFECT) != 0) - { - op2LclNum = lvaGrabTemp(true DEBUGARG("SIMD Min/Max")); - lvaSetStruct(op2LclNum, typeHnd, false); - dupOp2 = gtNewLclvNode(op2LclNum, op2->TypeGet()); - op2Assign = gtNewTempAssign(op2LclNum, op2); - op2 = gtNewLclvNode(op2LclNum, op2->TypeGet()); - } - else - { - dupOp2 = gtCloneExpr(op2); - } - - SIMDIntrinsicID relOpIntrinsic = - (intrinsicId == SIMDIntrinsicMin) ? SIMDIntrinsicLessThan : SIMDIntrinsicGreaterThan; - var_types relOpBaseType = baseType; - - // compResult = op1 relOp op2 - // simdTree = Select(compResult, op1, op2); - assert(dupOp1 != nullptr); - assert(dupOp2 != nullptr); - relOpIntrinsic = impSIMDRelOp(relOpIntrinsic, typeHnd, size, &relOpBaseType, &dupOp1, &dupOp2); - GenTree* compResult = gtNewSIMDNode(simdType, dupOp1, dupOp2, relOpIntrinsic, relOpBaseType, size); - unsigned compResultLclNum = lvaGrabTemp(true DEBUGARG("SIMD Min/Max")); - lvaSetStruct(compResultLclNum, typeHnd, false); - GenTree* compResultAssign = gtNewTempAssign(compResultLclNum, compResult); - compResult = gtNewLclvNode(compResultLclNum, compResult->TypeGet()); - simdTree = impSIMDSelect(typeHnd, baseType, size, compResult, op1, op2); - simdTree = gtNewOperNode(GT_COMMA, simdTree->TypeGet(), compResultAssign, simdTree); - - // Now create comma trees if we have created assignments of op1/op2 to temps - if (op2Assign != nullptr) - { - simdTree = gtNewOperNode(GT_COMMA, simdTree->TypeGet(), op2Assign, simdTree); - } - - if (op1Assign != nullptr) - { - simdTree = gtNewOperNode(GT_COMMA, simdTree->TypeGet(), op1Assign, simdTree); - } - } - - assert(simdTree != nullptr); - return simdTree; -#else // !(defined(TARGET_XARCH) || defined(TARGET_ARM64)) - assert(!"impSIMDMinMax() unimplemented on target arch"); - unreached(); -#endif // !(defined(TARGET_XARCH) || defined(TARGET_ARM64)) -} - //------------------------------------------------------------------------ // getOp1ForConstructor: Get the op1 for a constructor call. // @@ -2904,44 +2227,7 @@ GenTree* Compiler::impSIMDIntrinsic(OPCODE opcode, } break; - case SIMDIntrinsicOpEquality: - case SIMDIntrinsicInstEquals: - { - op2 = impSIMDPopStack(simdType); - op1 = impSIMDPopStack(simdType, instMethod); - - assert(op1->TypeGet() == simdType); - assert(op2->TypeGet() == simdType); - - simdTree = gtNewSIMDNode(genActualType(callType), op1, op2, SIMDIntrinsicOpEquality, baseType, size); - if (simdType == TYP_SIMD12) - { - simdTree->gtFlags |= GTF_SIMD12_OP; - } - retVal = simdTree; - } - break; - - case SIMDIntrinsicOpInEquality: - { - // op1 is the first operand - // op2 is the second operand - op2 = impSIMDPopStack(simdType); - op1 = impSIMDPopStack(simdType, instMethod); - simdTree = gtNewSIMDNode(genActualType(callType), op1, op2, SIMDIntrinsicOpInEquality, baseType, size); - if (simdType == TYP_SIMD12) - { - simdTree->gtFlags |= GTF_SIMD12_OP; - } - retVal = simdTree; - } - break; - case SIMDIntrinsicEqual: - case SIMDIntrinsicLessThan: - case SIMDIntrinsicLessThanOrEqual: - case SIMDIntrinsicGreaterThan: - case SIMDIntrinsicGreaterThanOrEqual: { op2 = impSIMDPopStack(simdType); op1 = impSIMDPopStack(simdType, instMethod); @@ -2957,9 +2243,7 @@ GenTree* Compiler::impSIMDIntrinsic(OPCODE opcode, case SIMDIntrinsicMul: case SIMDIntrinsicDiv: case SIMDIntrinsicBitwiseAnd: - case SIMDIntrinsicBitwiseAndNot: case SIMDIntrinsicBitwiseOr: - case SIMDIntrinsicBitwiseXor: { #if defined(DEBUG) // check for the cases where we don't support intrinsics. @@ -3008,48 +2292,11 @@ GenTree* Compiler::impSIMDIntrinsic(OPCODE opcode, op2 = impSIMDPopStack(simdType); op1 = impSIMDPopStack(simdType, instMethod); -#ifdef TARGET_XARCH - if (simdIntrinsicID == SIMDIntrinsicBitwiseAndNot) - { - // XARCH implements SIMDIntrinsicBitwiseAndNot as ~op1 & op2, while the - // software implementation does op1 & ~op2, so we need to swap the operands - - GenTree* tmp = op2; - op2 = op1; - op1 = tmp; - } -#endif // TARGET_XARCH - simdTree = gtNewSIMDNode(simdType, op1, op2, simdIntrinsicID, baseType, size); retVal = simdTree; } break; - case SIMDIntrinsicSelect: - { - // op3 is a SIMD variable that is the second source - // op2 is a SIMD variable that is the first source - // op1 is a SIMD variable which is the bit mask. - op3 = impSIMDPopStack(simdType); - op2 = impSIMDPopStack(simdType); - op1 = impSIMDPopStack(simdType); - - retVal = impSIMDSelect(clsHnd, baseType, size, op1, op2, op3); - } - break; - - case SIMDIntrinsicMin: - case SIMDIntrinsicMax: - { - // op1 is the first operand; if instance method, op1 is "this" arg - // op2 is the second operand - op2 = impSIMDPopStack(simdType); - op1 = impSIMDPopStack(simdType, instMethod); - - retVal = impSIMDMinMax(simdIntrinsicID, clsHnd, baseType, size, op1, op2); - } - break; - case SIMDIntrinsicGetItem: { // op1 is a SIMD variable that is "this" arg @@ -3116,43 +2363,6 @@ GenTree* Compiler::impSIMDIntrinsic(OPCODE opcode, } break; - case SIMDIntrinsicSqrt: - { -#if (defined(TARGET_XARCH) || defined(TARGET_ARM64)) && defined(DEBUG) - // SSE/AVX/ARM64 doesn't support sqrt on integer type vectors and hence - // should never be seen as an intrinsic here. See SIMDIntrinsicList.h - // for supported base types for this intrinsic. - if (!varTypeIsFloating(baseType)) - { - assert(!"Sqrt not supported on integer vectors\n"); - return nullptr; - } -#endif // (defined(TARGET_XARCH) || defined(TARGET_ARM64)) && defined(DEBUG) - - op1 = impSIMDPopStack(simdType); - - retVal = gtNewSIMDNode(genActualType(callType), op1, nullptr, simdIntrinsicID, baseType, size); - } - break; - - case SIMDIntrinsicCeil: - case SIMDIntrinsicFloor: -#if defined(TARGET_XARCH) - // Rounding instructions are only available from SSE4.1. - if (getSIMDSupportLevel() < SIMD_SSE4_Supported) - { - return nullptr; - } -#endif // defined(TARGET_XARCH) - op1 = impSIMDPopStack(simdType); - retVal = gtNewSIMDNode(genActualType(callType), op1, simdIntrinsicID, baseType, size); - break; - - case SIMDIntrinsicAbs: - op1 = impSIMDPopStack(simdType); - retVal = impSIMDAbs(clsHnd, baseType, size, op1); - break; - case SIMDIntrinsicGetW: retVal = impSIMDGetFixed(simdType, baseType, size, 3); break; diff --git a/src/coreclr/src/jit/simdashwintrinsic.cpp b/src/coreclr/src/jit/simdashwintrinsic.cpp new file mode 100644 index 00000000000000..a4f07b0c2dc816 --- /dev/null +++ b/src/coreclr/src/jit/simdashwintrinsic.cpp @@ -0,0 +1,1243 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "jitpch.h" +#include "simdashwintrinsic.h" + +#ifdef FEATURE_HW_INTRINSICS + +static const SimdAsHWIntrinsicInfo simdAsHWIntrinsicInfoArray[] = { +// clang-format off +#if defined(TARGET_XARCH) +#define SIMD_AS_HWINTRINSIC(classId, id, name, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, flag) \ + {NI_##classId##_##id, name, SimdAsHWIntrinsicClassId::classId, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, static_cast(flag)}, +#include "simdashwintrinsiclistxarch.h" +#elif defined(TARGET_ARM64) +#define SIMD_AS_HWINTRINSIC(classId, id, name, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, flag) \ + {NI_##classId##_##id, name, SimdAsHWIntrinsicClassId::classId, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, static_cast(flag)}, +#include "simdashwintrinsiclistarm64.h" +#else +#error Unsupported platform +#endif + // clang-format on +}; + +//------------------------------------------------------------------------ +// lookup: Gets the SimdAsHWIntrinsicInfo associated with a given NamedIntrinsic +// +// Arguments: +// id -- The NamedIntrinsic associated with the SimdAsHWIntrinsic to lookup +// +// Return Value: +// The SimdAsHWIntrinsicInfo associated with id +const SimdAsHWIntrinsicInfo& SimdAsHWIntrinsicInfo::lookup(NamedIntrinsic id) +{ + assert(id != NI_Illegal); + + assert(id > NI_SIMD_AS_HWINTRINSIC_START); + assert(id < NI_SIMD_AS_HWINTRINSIC_END); + + return simdAsHWIntrinsicInfoArray[id - NI_SIMD_AS_HWINTRINSIC_START - 1]; +} + +//------------------------------------------------------------------------ +// lookupId: Gets the NamedIntrinsic for a given method name and InstructionSet +// +// Arguments: +// className -- The name of the class associated with the SimdIntrinsic to lookup +// methodName -- The name of the method associated with the SimdIntrinsic to lookup +// enclosingClassName -- The name of the enclosing class +// sizeOfVectorT -- The size of Vector in bytes +// +// Return Value: +// The NamedIntrinsic associated with methodName and classId +NamedIntrinsic SimdAsHWIntrinsicInfo::lookupId(CORINFO_SIG_INFO* sig, + const char* className, + const char* methodName, + const char* enclosingClassName, + int sizeOfVectorT) +{ + SimdAsHWIntrinsicClassId classId = lookupClassId(className, enclosingClassName, sizeOfVectorT); + + if (classId == SimdAsHWIntrinsicClassId::Unknown) + { + return NI_Illegal; + } + + unsigned numArgs = sig->numArgs; + bool isInstanceMethod = false; + + if (sig->hasThis()) + { + numArgs++; + isInstanceMethod = true; + } + + for (int i = 0; i < (NI_SIMD_AS_HWINTRINSIC_END - NI_SIMD_AS_HWINTRINSIC_START - 1); i++) + { + const SimdAsHWIntrinsicInfo& intrinsicInfo = simdAsHWIntrinsicInfoArray[i]; + + if (classId != intrinsicInfo.classId) + { + continue; + } + + if (numArgs != static_cast(intrinsicInfo.numArgs)) + { + continue; + } + + if (isInstanceMethod != SimdAsHWIntrinsicInfo::IsInstanceMethod(intrinsicInfo.id)) + { + continue; + } + + if (strcmp(methodName, intrinsicInfo.name) != 0) + { + continue; + } + + return intrinsicInfo.id; + } + + return NI_Illegal; +} + +//------------------------------------------------------------------------ +// lookupClassId: Gets the SimdAsHWIntrinsicClassId for a given class name and enclsoing class name +// +// Arguments: +// className -- The name of the class associated with the SimdAsHWIntrinsicClassId to lookup +// enclosingClassName -- The name of the enclosing class +// sizeOfVectorT -- The size of Vector in bytes +// +// Return Value: +// The SimdAsHWIntrinsicClassId associated with className and enclosingClassName +SimdAsHWIntrinsicClassId SimdAsHWIntrinsicInfo::lookupClassId(const char* className, + const char* enclosingClassName, + int sizeOfVectorT) +{ + assert(className != nullptr); + + if ((enclosingClassName != nullptr) || (className[0] != 'V')) + { + return SimdAsHWIntrinsicClassId::Unknown; + } + if (strcmp(className, "Vector2") == 0) + { + return SimdAsHWIntrinsicClassId::Vector2; + } + if (strcmp(className, "Vector3") == 0) + { + return SimdAsHWIntrinsicClassId::Vector3; + } + if (strcmp(className, "Vector4") == 0) + { + return SimdAsHWIntrinsicClassId::Vector4; + } + if ((strcmp(className, "Vector") == 0) || (strcmp(className, "Vector`1") == 0)) + { +#if defined(TARGET_XARCH) + if (sizeOfVectorT == 32) + { + return SimdAsHWIntrinsicClassId::VectorT256; + } +#endif // TARGET_XARCH + + assert(sizeOfVectorT == 16); + return SimdAsHWIntrinsicClassId::VectorT128; + } + + return SimdAsHWIntrinsicClassId::Unknown; +} + +//------------------------------------------------------------------------ +// impSimdAsIntrinsic: Import a SIMD intrinsic as a GT_HWINTRINSIC node if possible +// +// Arguments: +// intrinsic -- id of the intrinsic function. +// clsHnd -- class handle containing the intrinsic function. +// method -- method handle of the intrinsic function. +// sig -- signature of the intrinsic call +// mustExpand -- true if the intrinsic must return a GenTree*; otherwise, false +// +// Return Value: +// The GT_HWINTRINSIC node, or nullptr if not a supported intrinsic +// +GenTree* Compiler::impSimdAsHWIntrinsic(NamedIntrinsic intrinsic, + CORINFO_CLASS_HANDLE clsHnd, + CORINFO_METHOD_HANDLE method, + CORINFO_SIG_INFO* sig, + bool mustExpand) +{ + assert(!mustExpand); + + if (!featureSIMD) + { + // We can't support SIMD intrinsics if the JIT doesn't support the feature + return nullptr; + } + + CORINFO_CLASS_HANDLE argClass = NO_CLASS_HANDLE; + var_types retType = JITtype2varType(sig->retType); + var_types baseType = TYP_UNKNOWN; + var_types simdType = TYP_UNKNOWN; + unsigned simdSize = 0; + unsigned numArgs = sig->numArgs; + bool isInstanceMethod = false; + + // We want to resolve and populate the handle cache for this type even + // if it isn't the basis for anything carried on the node. + baseType = getBaseTypeAndSizeOfSIMDType(clsHnd, &simdSize); + + if (retType == TYP_STRUCT) + { + baseType = getBaseTypeAndSizeOfSIMDType(sig->retTypeSigClass, &simdSize); + retType = getSIMDTypeForSize(simdSize); + } + else if (numArgs != 0) + { + argClass = info.compCompHnd->getArgClass(sig, sig->args); + baseType = getBaseTypeAndSizeOfSIMDType(argClass, &simdSize); + } + + if (sig->hasThis()) + { + assert(SimdAsHWIntrinsicInfo::IsInstanceMethod(intrinsic)); + numArgs++; + + isInstanceMethod = true; + argClass = clsHnd; + } + else if ((clsHnd == m_simdHandleCache->SIMDVectorHandle) && (numArgs != 0)) + { + // We need to fixup the clsHnd in the case we are an intrinsic on Vector + // The first argument will be the appropriate Vector handle to use + clsHnd = info.compCompHnd->getArgClass(sig, sig->args); + + // We also need to adjust the baseType as some methods on Vector return + // a type different than the operation we need to perform. An example + // is LessThan or Equals which takes double but returns long. This is + // unlike the counterparts on Vector which take a return the same type. + baseType = getBaseTypeAndSizeOfSIMDType(clsHnd, &simdSize); + } + + if (!varTypeIsArithmetic(baseType) || (simdSize == 0)) + { + // We get here for a devirtualization of IEquatable`1.Equals + // or if the user tries to use Vector with an unsupported type + return nullptr; + } + + simdType = getSIMDTypeForSize(simdSize); + assert(varTypeIsSIMD(simdType)); + + NamedIntrinsic hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(intrinsic, baseType); + + if ((hwIntrinsic == NI_Illegal) || !varTypeIsSIMD(simdType)) + { + // The baseType isn't supported by the intrinsic + return nullptr; + } + + if (SimdAsHWIntrinsicInfo::IsFloatingPointUsed(intrinsic)) + { + // Set `compFloatingPointUsed` to cover the scenario where an intrinsic + // is operating on SIMD fields, but where no SIMD local vars are in use. + compFloatingPointUsed = true; + } + + if (hwIntrinsic == intrinsic) + { + // The SIMD intrinsic requires special handling outside the normal code path + return impSimdAsHWIntrinsicSpecial(intrinsic, clsHnd, sig, retType, baseType, simdSize); + } + + CORINFO_InstructionSet hwIntrinsicIsa = HWIntrinsicInfo::lookupIsa(hwIntrinsic); + + if (!compOpportunisticallyDependsOn(hwIntrinsicIsa)) + { + // The JIT doesn't support the required ISA + return nullptr; + } + + CORINFO_ARG_LIST_HANDLE argList = sig->args; + var_types argType = TYP_UNKNOWN; + + GenTree* op1 = nullptr; + GenTree* op2 = nullptr; + + switch (numArgs) + { + case 0: + { + assert(!SimdAsHWIntrinsicInfo::NeedsOperandsSwapped(intrinsic)); + return gtNewSimdAsHWIntrinsicNode(retType, hwIntrinsic, baseType, simdSize); + } + + case 1: + { + argType = isInstanceMethod ? simdType + : JITtype2varType(strip(info.compCompHnd->getArgType(sig, argList, &argClass))); + op1 = getArgForHWIntrinsic(argType, argClass, isInstanceMethod); + + assert(!SimdAsHWIntrinsicInfo::NeedsOperandsSwapped(intrinsic)); + return gtNewSimdAsHWIntrinsicNode(retType, op1, hwIntrinsic, baseType, simdSize); + } + + case 2: + { + CORINFO_ARG_LIST_HANDLE arg2 = isInstanceMethod ? argList : info.compCompHnd->getArgNext(argList); + argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg2, &argClass))); + op2 = getArgForHWIntrinsic(argType, argClass); + + argType = isInstanceMethod ? simdType + : JITtype2varType(strip(info.compCompHnd->getArgType(sig, argList, &argClass))); + op1 = getArgForHWIntrinsic(argType, argClass, isInstanceMethod); + + if (SimdAsHWIntrinsicInfo::NeedsOperandsSwapped(intrinsic)) + { + std::swap(op1, op2); + } + + return gtNewSimdAsHWIntrinsicNode(retType, op1, op2, hwIntrinsic, baseType, simdSize); + } + } + + assert(!"Unexpected SimdAsHWIntrinsic"); + return nullptr; +} + +//------------------------------------------------------------------------ +// impSimdAsHWIntrinsicSpecial: Import a SIMD intrinsic as a GT_HWINTRINSIC node if possible +// This method handles cases which cannot be table driven +// +// Arguments: +// intrinsic -- id of the intrinsic function. +// clsHnd -- class handle containing the intrinsic function. +// sig -- signature of the intrinsic call +// retType -- the return type of the intrinsic call +// baseType -- the base type of SIMD type of the intrinsic +// simdSize -- the size of the SIMD type of the intrinsic +// +// Return Value: +// The GT_HWINTRINSIC node, or nullptr if not a supported intrinsic +// +GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, + CORINFO_CLASS_HANDLE clsHnd, + CORINFO_SIG_INFO* sig, + var_types retType, + var_types baseType, + unsigned simdSize) +{ + assert(featureSIMD); + assert(retType != TYP_UNKNOWN); + assert(varTypeIsArithmetic(baseType)); + assert(simdSize != 0); + assert(SimdAsHWIntrinsicInfo::lookupHWIntrinsic(intrinsic, baseType) == intrinsic); + + var_types simdType = getSIMDTypeForSize(simdSize); + assert(varTypeIsSIMD(simdType)); + + CORINFO_ARG_LIST_HANDLE argList = sig->args; + var_types argType = TYP_UNKNOWN; + CORINFO_CLASS_HANDLE argClass = NO_CLASS_HANDLE; + + GenTree* op1 = nullptr; + GenTree* op2 = nullptr; + GenTree* op3 = nullptr; + + SimdAsHWIntrinsicClassId classId = SimdAsHWIntrinsicInfo::lookupClassId(intrinsic); + unsigned numArgs = sig->numArgs; + bool isInstanceMethod = false; + + if (sig->hasThis()) + { + assert(SimdAsHWIntrinsicInfo::IsInstanceMethod(intrinsic)); + numArgs++; + + isInstanceMethod = true; + argClass = clsHnd; + } + +#if defined(TARGET_XARCH) + bool isVectorT256 = (SimdAsHWIntrinsicInfo::lookupClassId(intrinsic) == SimdAsHWIntrinsicClassId::VectorT256); + + if ((baseType != TYP_FLOAT) && !compOpportunisticallyDependsOn(InstructionSet_SSE2)) + { + // Vector, for everything but float, requires at least SSE2 + return nullptr; + } + else if (!compOpportunisticallyDependsOn(InstructionSet_SSE)) + { + // Vector requires at least SSE + return nullptr; + } + + // Vector, when 32-bytes, requires at least AVX2 + assert(!isVectorT256 || compIsaSupportedDebugOnly(InstructionSet_AVX2)); +#endif + + switch (numArgs) + { + case 0: + { + switch (intrinsic) + { +#if defined(TARGET_XARCH) + case NI_VectorT128_get_Count: + case NI_VectorT256_get_Count: + { + GenTreeIntCon* countNode = gtNewIconNode(getSIMDVectorLength(simdSize, baseType), TYP_INT); + countNode->gtFlags |= GTF_ICON_SIMD_COUNT; + return countNode; + } +#elif defined(TARGET_ARM64) + case NI_VectorT128_get_Count: + { + GenTreeIntCon* countNode = gtNewIconNode(getSIMDVectorLength(simdSize, baseType), TYP_INT); + countNode->gtFlags |= GTF_ICON_SIMD_COUNT; + return countNode; + } +#else +#error Unsupported platform +#endif // !TARGET_XARCH && !TARGET_ARM64 + + default: + { + // Some platforms warn about unhandled switch cases + // We handle it more generally via the assert and nullptr return below. + break; + } + } + } + + case 1: + { + bool isOpExplicit = (intrinsic == NI_VectorT128_op_Explicit); + +#if defined(TARGET_XARCH) + isOpExplicit |= (intrinsic == NI_VectorT256_op_Explicit); +#endif + + if (isOpExplicit) + { + // We fold away the cast here, as it only exists to satisfy the + // type system. It is safe to do this here since the op1 type + // and the signature return type are both the same TYP_SIMD. + + op1 = impSIMDPopStack(retType, /* expectAddr: */ false, sig->retTypeClass); + SetOpLclRelatedToSIMDIntrinsic(op1); + assert(op1->gtType == getSIMDTypeForSize(getSIMDTypeSizeInBytes(sig->retTypeSigClass))); + + return op1; + } + + argType = isInstanceMethod ? simdType + : JITtype2varType(strip(info.compCompHnd->getArgType(sig, argList, &argClass))); + op1 = getArgForHWIntrinsic(argType, argClass, isInstanceMethod); + + assert(!SimdAsHWIntrinsicInfo::NeedsOperandsSwapped(intrinsic)); + + switch (intrinsic) + { +#if defined(TARGET_XARCH) + case NI_Vector2_Abs: + case NI_Vector3_Abs: + case NI_Vector4_Abs: + case NI_VectorT128_Abs: + case NI_VectorT256_Abs: + { + if (varTypeIsFloating(baseType)) + { + // Abs(vf) = vf & new SIMDVector(0x7fffffff); + // Abs(vd) = vf & new SIMDVector(0x7fffffffffffffff); + GenTree* bitMask = nullptr; + + if (baseType == TYP_FLOAT) + { + static_assert_no_msg(sizeof(float) == sizeof(int)); + int mask = 0x7fffffff; + bitMask = gtNewDconNode(*((float*)&mask), TYP_FLOAT); + } + else + { + assert(baseType == TYP_DOUBLE); + static_assert_no_msg(sizeof(double) == sizeof(__int64)); + + __int64 mask = 0x7fffffffffffffffLL; + bitMask = gtNewDconNode(*((double*)&mask), TYP_DOUBLE); + } + assert(bitMask != nullptr); + + bitMask = gtNewSIMDNode(retType, bitMask, SIMDIntrinsicInit, baseType, simdSize); + + intrinsic = isVectorT256 ? NI_VectorT256_op_BitwiseAnd : NI_VectorT128_op_BitwiseAnd; + intrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(intrinsic, baseType); + + return gtNewSimdAsHWIntrinsicNode(retType, op1, bitMask, intrinsic, baseType, simdSize); + } + else if (varTypeIsUnsigned(baseType)) + { + return op1; + } + else if ((baseType != TYP_LONG) && compOpportunisticallyDependsOn(InstructionSet_SSSE3)) + { + return gtNewSimdAsHWIntrinsicNode(retType, op1, NI_SSSE3_Abs, baseType, simdSize); + } + else + { + GenTree* tmp; + NamedIntrinsic hwIntrinsic; + + GenTree* op1Dup1; + op1 = impCloneExpr(op1, &op1Dup1, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op1 for Vector.Abs")); + + GenTree* op1Dup2; + op1Dup1 = impCloneExpr(op1Dup1, &op1Dup2, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op1 for Vector.Abs")); + + // op1 = op1 < Zero + tmp = gtNewSIMDVectorZero(retType, baseType, simdSize); + hwIntrinsic = isVectorT256 ? NI_VectorT256_LessThan : NI_VectorT128_LessThan; + op1 = impSimdAsHWIntrinsicRelOp(hwIntrinsic, clsHnd, retType, baseType, simdSize, op1, tmp); + + // tmp = Zero - op1Dup1 + tmp = gtNewSIMDVectorZero(retType, baseType, simdSize); + hwIntrinsic = isVectorT256 ? NI_AVX2_Subtract : NI_SSE2_Subtract; + tmp = gtNewSimdAsHWIntrinsicNode(retType, tmp, op1Dup1, hwIntrinsic, baseType, simdSize); + + // result = ConditionalSelect(op1, tmp, op1Dup2) + return impSimdAsHWIntrinsicCndSel(clsHnd, retType, baseType, simdSize, op1, tmp, op1Dup2); + } + break; + } +#elif defined(TARGET_ARM64) + case NI_VectorT128_Abs: + { + assert(varTypeIsUnsigned(baseType)); + return op1; + } +#else +#error Unsupported platform +#endif // !TARGET_XARCH && !TARGET_ARM64 + + default: + { + // Some platforms warn about unhandled switch cases + // We handle it more generally via the assert and nullptr return below. + break; + } + } + break; + } + + case 2: + { + CORINFO_ARG_LIST_HANDLE arg2 = isInstanceMethod ? argList : info.compCompHnd->getArgNext(argList); + argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg2, &argClass))); + op2 = getArgForHWIntrinsic(argType, argClass); + + argType = isInstanceMethod ? simdType + : JITtype2varType(strip(info.compCompHnd->getArgType(sig, argList, &argClass))); + op1 = getArgForHWIntrinsic(argType, argClass, isInstanceMethod); + + assert(!SimdAsHWIntrinsicInfo::NeedsOperandsSwapped(intrinsic)); + + switch (intrinsic) + { +#if defined(TARGET_XARCH) + case NI_Vector2_op_Division: + case NI_Vector3_op_Division: + { + // Vector2/3 div: since the top-most elements will be zero, we end up + // perfoming 0/0 which is a NAN. Therefore, post division we need to set the + // top-most elements to zero. This is achieved by left logical shift followed + // by right logical shift of the result. + + // These are 16 byte operations, so we subtract from 16 bytes, not the vector register length. + unsigned shiftCount = 16 - simdSize; + assert((shiftCount > 0) && (shiftCount <= 16)); + + // retNode = Sse.Divide(op1, op2); + GenTree* retNode = gtNewSimdAsHWIntrinsicNode(retType, op1, op2, NI_SSE_Divide, baseType, simdSize); + + // retNode = Sse.ShiftLeftLogical128BitLane(retNode.AsInt32(), shiftCount).AsSingle() + retNode = gtNewSimdAsHWIntrinsicNode(retType, retNode, gtNewIconNode(shiftCount, TYP_INT), + NI_SSE2_ShiftLeftLogical128BitLane, TYP_INT, simdSize); + + // retNode = Sse.ShiftRightLogical128BitLane(retNode.AsInt32(), shiftCount).AsSingle() + retNode = gtNewSimdAsHWIntrinsicNode(retType, retNode, gtNewIconNode(shiftCount, TYP_INT), + NI_SSE2_ShiftRightLogical128BitLane, TYP_INT, simdSize); + + return retNode; + } + + case NI_VectorT128_Equals: + case NI_VectorT128_GreaterThan: + case NI_VectorT128_GreaterThanOrEqual: + case NI_VectorT128_LessThan: + case NI_VectorT128_LessThanOrEqual: + case NI_VectorT256_GreaterThan: + case NI_VectorT256_GreaterThanOrEqual: + case NI_VectorT256_LessThan: + case NI_VectorT256_LessThanOrEqual: + { + return impSimdAsHWIntrinsicRelOp(intrinsic, clsHnd, retType, baseType, simdSize, op1, op2); + } + + case NI_VectorT128_Max: + case NI_VectorT128_Min: + case NI_VectorT256_Max: + case NI_VectorT256_Min: + { + if ((baseType == TYP_BYTE) || (baseType == TYP_USHORT)) + { + GenTree* constVal = nullptr; + var_types opType = baseType; + + NamedIntrinsic opIntrinsic; + NamedIntrinsic hwIntrinsic; + + switch (baseType) + { + case TYP_BYTE: + { + constVal = gtNewIconNode(0x80808080, TYP_INT); + opIntrinsic = NI_VectorT128_op_Subtraction; + baseType = TYP_UBYTE; + break; + } + + case TYP_USHORT: + { + constVal = gtNewIconNode(0x80008000, TYP_INT); + opIntrinsic = NI_VectorT128_op_Addition; + baseType = TYP_SHORT; + break; + } + + default: + { + unreached(); + } + } + + GenTree* constVector = + gtNewSIMDNode(retType, constVal, nullptr, SIMDIntrinsicInit, TYP_INT, simdSize); + + GenTree* constVectorDup1; + constVector = impCloneExpr(constVector, &constVectorDup1, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone constVector for Vector.Max/Min")); + + GenTree* constVectorDup2; + constVectorDup1 = + impCloneExpr(constVectorDup1, &constVectorDup2, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone constVector for Vector.Max/Min")); + + hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(opIntrinsic, opType); + + // op1 = op1 - constVector + // -or- + // op1 = op1 + constVector + op1 = gtNewSimdAsHWIntrinsicNode(retType, op1, constVector, hwIntrinsic, opType, simdSize); + + // op2 = op2 - constVectorDup1 + // -or- + // op2 = op2 + constVectorDup1 + op2 = gtNewSimdAsHWIntrinsicNode(retType, op2, constVectorDup1, hwIntrinsic, opType, simdSize); + + // op1 = Max(op1, op2) + // -or- + // op1 = Min(op1, op2) + hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(intrinsic, baseType); + op1 = gtNewSimdAsHWIntrinsicNode(retType, op1, op2, hwIntrinsic, baseType, simdSize); + + // result = op1 + constVectorDup2 + // -or- + // result = op1 - constVectorDup2 + opIntrinsic = (opIntrinsic == NI_VectorT128_op_Subtraction) ? NI_VectorT128_op_Addition + : NI_VectorT128_op_Subtraction; + hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(opIntrinsic, opType); + return gtNewSimdAsHWIntrinsicNode(retType, op1, constVectorDup2, hwIntrinsic, opType, simdSize); + } + + GenTree* op1Dup; + op1 = impCloneExpr(op1, &op1Dup, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op1 for Vector.Max/Min")); + + GenTree* op2Dup; + op2 = impCloneExpr(op2, &op2Dup, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op2 for Vector.Max/Min")); + + if ((intrinsic == NI_VectorT128_Max) || (intrinsic == NI_VectorT256_Max)) + { + intrinsic = isVectorT256 ? NI_VectorT256_GreaterThan : NI_VectorT128_GreaterThan; + } + else + { + intrinsic = isVectorT256 ? NI_VectorT256_LessThan : NI_VectorT128_LessThan; + } + + // op1 = op1 > op2 + // -or- + // op1 = op1 < op2 + op1 = impSimdAsHWIntrinsicRelOp(intrinsic, clsHnd, retType, baseType, simdSize, op1, op2); + + // result = ConditionalSelect(op1, op1Dup, op2Dup) + return impSimdAsHWIntrinsicCndSel(clsHnd, retType, baseType, simdSize, op1, op1Dup, op2Dup); + } + + case NI_VectorT128_op_Multiply: + { + assert(baseType == TYP_INT); + + NamedIntrinsic hwIntrinsic = NI_Illegal; + + if (compOpportunisticallyDependsOn(InstructionSet_SSE41)) + { + hwIntrinsic = NI_SSE41_MultiplyLow; + } + else + { + // op1Dup = op1 + GenTree* op1Dup; + op1 = impCloneExpr(op1, &op1Dup, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op1 for Vector.Multiply")); + + // op2Dup = op2 + GenTree* op2Dup; + op2 = impCloneExpr(op2, &op2Dup, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op2 for Vector.Multiply")); + + // op1 = Sse2.ShiftRightLogical128BitLane(op1, 4) + op1 = gtNewSimdAsHWIntrinsicNode(retType, op1, gtNewIconNode(4, TYP_INT), + NI_SSE2_ShiftRightLogical128BitLane, baseType, simdSize); + + // op2 = Sse2.ShiftRightLogical128BitLane(op1, 4) + op2 = gtNewSimdAsHWIntrinsicNode(retType, op2, gtNewIconNode(4, TYP_INT), + NI_SSE2_ShiftRightLogical128BitLane, baseType, simdSize); + + // op2 = Sse2.Multiply(op2.AsUInt64(), op1.AsUInt64()).AsInt32() + op2 = gtNewSimdAsHWIntrinsicNode(retType, op2, op1, NI_SSE2_Multiply, TYP_ULONG, simdSize); + + // op2 = Sse2.Shuffle(op2, (0, 0, 2, 0)) + op2 = gtNewSimdAsHWIntrinsicNode(retType, op2, gtNewIconNode(SHUFFLE_XXZX, TYP_INT), + NI_SSE2_Shuffle, baseType, simdSize); + + // op1 = Sse2.Multiply(op1Dup.AsUInt64(), op2Dup.AsUInt64()).AsInt32() + op1 = + gtNewSimdAsHWIntrinsicNode(retType, op1Dup, op2Dup, NI_SSE2_Multiply, TYP_ULONG, simdSize); + + // op1 = Sse2.Shuffle(op1, (0, 0, 2, 0)) + op1 = gtNewSimdAsHWIntrinsicNode(retType, op1, gtNewIconNode(SHUFFLE_XXZX, TYP_INT), + NI_SSE2_Shuffle, baseType, simdSize); + + // result = Sse2.UnpackLow(op1, op2) + hwIntrinsic = NI_SSE2_UnpackLow; + } + assert(hwIntrinsic != NI_Illegal); + + return gtNewSimdAsHWIntrinsicNode(retType, op1, op2, hwIntrinsic, baseType, simdSize); + } +#elif defined(TARGET_ARM64) + case NI_VectorT128_Max: + case NI_VectorT128_Min: + { + assert((baseType == TYP_LONG) || (baseType == TYP_ULONG)); + + NamedIntrinsic hwIntrinsic; + + GenTree* op1Dup; + op1 = impCloneExpr(op1, &op1Dup, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op1 for Vector.Max/Min")); + + GenTree* op2Dup; + op2 = impCloneExpr(op2, &op2Dup, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op2 for Vector.Max/Min")); + + intrinsic = (intrinsic == NI_VectorT128_Max) ? NI_VectorT128_GreaterThan : NI_VectorT128_LessThan; + + // op1 = op1 > op2 + // -or- + // op1 = op1 < op2 + hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(intrinsic, baseType); + op1 = gtNewSimdAsHWIntrinsicNode(retType, op1, op2, hwIntrinsic, baseType, simdSize); + + // result = ConditionalSelect(op1, op1Dup, op2Dup) + return impSimdAsHWIntrinsicCndSel(clsHnd, retType, baseType, simdSize, op1, op1Dup, op2Dup); + } +#else +#error Unsupported platform +#endif // !TARGET_XARCH && !TARGET_ARM64 + + default: + { + // Some platforms warn about unhandled switch cases + // We handle it more generally via the assert and nullptr return below. + break; + } + } + break; + } + + case 3: + { + CORINFO_ARG_LIST_HANDLE arg2 = isInstanceMethod ? argList : info.compCompHnd->getArgNext(argList); + CORINFO_ARG_LIST_HANDLE arg3 = info.compCompHnd->getArgNext(arg2); + + argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg3, &argClass))); + op3 = getArgForHWIntrinsic(argType, argClass); + + argType = JITtype2varType(strip(info.compCompHnd->getArgType(sig, arg2, &argClass))); + op2 = getArgForHWIntrinsic(argType, argClass); + + argType = isInstanceMethod ? simdType + : JITtype2varType(strip(info.compCompHnd->getArgType(sig, argList, &argClass))); + op1 = getArgForHWIntrinsic(argType, argClass, isInstanceMethod); + + assert(!SimdAsHWIntrinsicInfo::NeedsOperandsSwapped(intrinsic)); + + switch (intrinsic) + { +#if defined(TARGET_XARCH) + case NI_VectorT128_ConditionalSelect: + case NI_VectorT256_ConditionalSelect: + { + return impSimdAsHWIntrinsicCndSel(clsHnd, retType, baseType, simdSize, op1, op2, op3); + } +#elif defined(TARGET_ARM64) + case NI_VectorT128_ConditionalSelect: + { + return impSimdAsHWIntrinsicCndSel(clsHnd, retType, baseType, simdSize, op1, op2, op3); + } +#else +#error Unsupported platform +#endif // !TARGET_XARCH && !TARGET_ARM64 + + default: + { + // Some platforms warn about unhandled switch cases + // We handle it more generally via the assert and nullptr return below. + break; + } + } + } + } + + assert(!"Unexpected SimdAsHWIntrinsic"); + return nullptr; +} + +//------------------------------------------------------------------------ +// impSimdAsHWIntrinsicCndSel: Import a SIMD conditional select intrinsic +// +// Arguments: +// clsHnd -- class handle containing the intrinsic function. +// retType -- the return type of the intrinsic call +// baseType -- the base type of SIMD type of the intrinsic +// simdSize -- the size of the SIMD type of the intrinsic +// op1 -- the first operand of the intrinsic +// op2 -- the second operand of the intrinsic +// op3 -- the third operand of the intrinsic +// +// Return Value: +// The GT_HWINTRINSIC node representing the conditional select +// +GenTree* Compiler::impSimdAsHWIntrinsicCndSel(CORINFO_CLASS_HANDLE clsHnd, + var_types retType, + var_types baseType, + unsigned simdSize, + GenTree* op1, + GenTree* op2, + GenTree* op3) +{ + assert(featureSIMD); + assert(retType != TYP_UNKNOWN); + assert(varTypeIsArithmetic(baseType)); + assert(simdSize != 0); + assert(varTypeIsSIMD(getSIMDTypeForSize(simdSize))); + assert(op1 != nullptr); + assert(op2 != nullptr); + assert(op3 != nullptr); + +#if defined(TARGET_XARCH) + bool isVectorT256 = (simdSize == 32); + + // Vector for the rel-ops covered here requires at least SSE2 + assert(compIsaSupportedDebugOnly(InstructionSet_SSE2)); + + // Vector, when 32-bytes, requires at least AVX2 + assert(!isVectorT256 || compIsaSupportedDebugOnly(InstructionSet_AVX2)); + + if (compOpportunisticallyDependsOn(InstructionSet_SSE41)) + { + NamedIntrinsic hwIntrinsic = NI_SSE41_BlendVariable; + + if (isVectorT256) + { + hwIntrinsic = varTypeIsIntegral(baseType) ? NI_AVX2_BlendVariable : NI_AVX_BlendVariable; + } + + return gtNewSimdAsHWIntrinsicNode(retType, op3, op2, op1, hwIntrinsic, baseType, simdSize); + } +#endif // TARGET_XARCH + + NamedIntrinsic hwIntrinsic; + + GenTree* op1Dup; + op1 = impCloneExpr(op1, &op1Dup, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op1 for Vector.ConditionalSelect")); + + // op2 = op2 & op1 + hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(NI_VectorT128_op_BitwiseAnd, baseType); + op2 = gtNewSimdAsHWIntrinsicNode(retType, op2, op1, hwIntrinsic, baseType, simdSize); + + // op3 = op3 & ~op1Dup + hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(NI_VectorT128_AndNot, baseType); + + if (SimdAsHWIntrinsicInfo::NeedsOperandsSwapped(NI_VectorT128_AndNot)) + { + std::swap(op3, op1Dup); + } + + op3 = gtNewSimdAsHWIntrinsicNode(retType, op3, op1Dup, hwIntrinsic, baseType, simdSize); + + // result = op2 | op3 + hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(NI_VectorT128_op_BitwiseOr, baseType); + return gtNewSimdAsHWIntrinsicNode(retType, op2, op3, hwIntrinsic, baseType, simdSize); +} + +#if defined(TARGET_XARCH) +//------------------------------------------------------------------------ +// impSimdAsHWIntrinsicRelOp: Import a SIMD relational operator intrinsic +// +// Arguments: +// intrinsic -- id of the intrinsic function. +// clsHnd -- class handle containing the intrinsic function. +// retType -- the return type of the intrinsic call +// baseType -- the base type of SIMD type of the intrinsic +// simdSize -- the size of the SIMD type of the intrinsic +// op1 -- the first operand of the intrinsic +// op2 -- the second operand of the intrinsic +// +// Return Value: +// The GT_HWINTRINSIC node representing the relational operator +// +GenTree* Compiler::impSimdAsHWIntrinsicRelOp(NamedIntrinsic intrinsic, + CORINFO_CLASS_HANDLE clsHnd, + var_types retType, + var_types baseType, + unsigned simdSize, + GenTree* op1, + GenTree* op2) +{ + assert(featureSIMD); + assert(retType != TYP_UNKNOWN); + assert(varTypeIsIntegral(baseType)); + assert(simdSize != 0); + assert(varTypeIsSIMD(getSIMDTypeForSize(simdSize))); + assert(op1 != nullptr); + assert(op2 != nullptr); + assert(!SimdAsHWIntrinsicInfo::IsInstanceMethod(intrinsic)); + + bool isVectorT256 = (SimdAsHWIntrinsicInfo::lookupClassId(intrinsic) == SimdAsHWIntrinsicClassId::VectorT256); + + // Vector for the rel-ops covered here requires at least SSE2 + assert(compIsaSupportedDebugOnly(InstructionSet_SSE2)); + + // Vector, when 32-bytes, requires at least AVX2 + assert(!isVectorT256 || compIsaSupportedDebugOnly(InstructionSet_AVX2)); + + switch (intrinsic) + { + case NI_VectorT128_Equals: + case NI_VectorT256_Equals: + { + // These ones aren't "special", but they are used by the other + // relational operators and so are defined for convenience. + + NamedIntrinsic hwIntrinsic = NI_Illegal; + + if (isVectorT256 || ((baseType != TYP_LONG) && (baseType != TYP_ULONG))) + { + hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(intrinsic, baseType); + assert(hwIntrinsic != intrinsic); + } + else if (compOpportunisticallyDependsOn(InstructionSet_SSE41)) + { + hwIntrinsic = NI_SSE41_CompareEqual; + } + else + { + // There is no direct SSE2 support for comparing TYP_LONG vectors. + // These have to be implemented in terms of TYP_INT vector comparison operations. + // + // tmp = (op1 == op2) i.e. compare for equality as if op1 and op2 are Vector + // op1 = tmp + // op2 = Shuffle(tmp, (2, 3, 0, 1)) + // result = BitwiseAnd(op1, op2) + // + // Shuffle is meant to swap the comparison results of low-32-bits and high 32-bits of + // respective long elements. + + hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(intrinsic, TYP_INT); + assert(hwIntrinsic != intrinsic); + + GenTree* tmp = gtNewSimdAsHWIntrinsicNode(retType, op1, op2, hwIntrinsic, TYP_INT, simdSize); + + tmp = impCloneExpr(tmp, &op1, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone tmp for Vector.Equals")); + + op2 = gtNewSimdAsHWIntrinsicNode(retType, tmp, gtNewIconNode(SHUFFLE_ZWXY, TYP_INT), NI_SSE2_Shuffle, + TYP_INT, simdSize); + + hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(NI_VectorT128_op_BitwiseAnd, baseType); + assert(hwIntrinsic != NI_VectorT128_op_BitwiseAnd); + } + assert(hwIntrinsic != NI_Illegal); + + return gtNewSimdAsHWIntrinsicNode(retType, op1, op2, hwIntrinsic, baseType, simdSize); + } + + case NI_VectorT128_GreaterThanOrEqual: + case NI_VectorT128_LessThanOrEqual: + case NI_VectorT256_GreaterThanOrEqual: + case NI_VectorT256_LessThanOrEqual: + { + // There is no direct support for doing a combined comparison and equality for integral types. + // These have to be implemented by performing both halves and combining their results. + // + // op1Dup = op1 + // op2Dup = op2 + // + // op1 = GreaterThan(op1, op2) + // op2 = Equals(op1Dup, op2Dup) + // + // result = BitwiseOr(op1, op2) + // + // Where the GreaterThan(op1, op2) comparison could also be LessThan(op1, op2) + + GenTree* op1Dup; + op1 = impCloneExpr(op1, &op1Dup, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op1 for Vector.GreaterThanOrEqual/LessThanOrEqual")); + + GenTree* op2Dup; + op2 = impCloneExpr(op2, &op2Dup, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op2 for Vector.GreaterThanOrEqual/LessThanOrEqual")); + + NamedIntrinsic eqIntrinsic = isVectorT256 ? NI_VectorT256_Equals : NI_VectorT128_Equals; + + switch (intrinsic) + { + case NI_VectorT128_GreaterThanOrEqual: + { + intrinsic = NI_VectorT128_GreaterThan; + break; + } + + case NI_VectorT128_LessThanOrEqual: + { + intrinsic = NI_VectorT128_LessThan; + break; + } + + case NI_VectorT256_GreaterThanOrEqual: + { + intrinsic = NI_VectorT256_GreaterThan; + break; + } + + case NI_VectorT256_LessThanOrEqual: + { + intrinsic = NI_VectorT256_LessThan; + break; + } + + default: + { + unreached(); + } + } + + op1 = impSimdAsHWIntrinsicRelOp(eqIntrinsic, clsHnd, retType, baseType, simdSize, op1, op2); + op2 = impSimdAsHWIntrinsicRelOp(intrinsic, clsHnd, retType, baseType, simdSize, op1Dup, op2Dup); + intrinsic = isVectorT256 ? NI_VectorT256_op_BitwiseOr : NI_VectorT128_op_BitwiseOr; + + NamedIntrinsic hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(intrinsic, baseType); + return gtNewSimdAsHWIntrinsicNode(retType, op1, op2, hwIntrinsic, baseType, simdSize); + } + + case NI_VectorT128_GreaterThan: + case NI_VectorT128_LessThan: + case NI_VectorT256_GreaterThan: + case NI_VectorT256_LessThan: + { + NamedIntrinsic hwIntrinsic = NI_Illegal; + + if (varTypeIsUnsigned(baseType)) + { + // Vector, Vector, Vector and Vector: + // Hardware supports > for signed comparison. Therefore, to use it for + // comparing unsigned numbers, we subtract a constant from both the + // operands such that the result fits within the corresponding signed + // type. The resulting signed numbers are compared using signed comparison. + // + // Vector: constant to be subtracted is 2^7 + // Vector constant to be subtracted is 2^15 + // Vector constant to be subtracted is 2^31 + // Vector constant to be subtracted is 2^63 + // + // We need to treat op1 and op2 as signed for comparison purpose after + // the transformation. + + GenTree* constVal = nullptr; + var_types opType = baseType; + + switch (baseType) + { + case TYP_UBYTE: + { + constVal = gtNewIconNode(0x80808080, TYP_INT); + baseType = TYP_BYTE; + break; + } + + case TYP_USHORT: + { + constVal = gtNewIconNode(0x80008000, TYP_INT); + baseType = TYP_SHORT; + break; + } + + case TYP_UINT: + { + constVal = gtNewIconNode(0x80000000, TYP_INT); + baseType = TYP_INT; + break; + } + + case TYP_ULONG: + { + constVal = gtNewLconNode(0x8000000000000000); + baseType = TYP_LONG; + break; + } + + default: + { + unreached(); + } + } + + GenTree* constVector = + gtNewSIMDNode(retType, constVal, nullptr, SIMDIntrinsicInit, constVal->TypeGet(), simdSize); + + GenTree* constVectorDup; + constVector = impCloneExpr(constVector, &constVectorDup, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone constVector for Vector.GreaterThan/LessThan")); + + NamedIntrinsic hwIntrinsic = isVectorT256 ? NI_AVX2_Subtract : NI_SSE2_Subtract; + + // op1 = op1 - constVector + op1 = gtNewSimdAsHWIntrinsicNode(retType, op1, constVector, hwIntrinsic, opType, simdSize); + + // op2 = op2 - constVector + op2 = gtNewSimdAsHWIntrinsicNode(retType, op2, constVectorDup, hwIntrinsic, opType, simdSize); + } + + // This should have been mutated by the above path + assert(varTypeIsIntegral(baseType) && !varTypeIsUnsigned(baseType)); + + if (isVectorT256 || (baseType != TYP_LONG)) + { + hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(intrinsic, baseType); + assert(hwIntrinsic != intrinsic); + } + else if (compOpportunisticallyDependsOn(InstructionSet_SSE42)) + { + hwIntrinsic = + (intrinsic == NI_VectorT128_GreaterThan) ? NI_SSE42_CompareGreaterThan : NI_SSE42_CompareLessThan; + } + else + { + // There is no direct SSE2 support for comparing TYP_LONG vectors. + // These have to be implemented in terms of TYP_INT vector comparison operations. + // + // Let us consider the case of single long element comparison. + // Say op1 = (x1, y1) and op2 = (x2, y2) where x1, y1, x2, and y2 are 32-bit integers that comprise the + // longs op1 and op2. + // + // GreaterThan(op1, op2) can be expressed in terms of > relationship between 32-bit integers that + // comprise op1 and op2 as + // = (x1, y1) > (x2, y2) + // = (x1 > x2) || [(x1 == x2) && (y1 > y2)] - eq (1) + // + // op1Dup1 = op1 + // op1Dup2 = op1Dup1 + // op2Dup1 = op2 + // op2Dup2 = op2Dup1 + // + // t = (op1 > op2) - 32-bit signed comparison + // u = (op1Dup1 == op2Dup1) - 32-bit equality comparison + // v = (op1Dup2 > op2Dup2) - 32-bit unsigned comparison + // + // op1 = Shuffle(t, (3, 3, 1, 1)) - This corresponds to (x1 > x2) in eq(1) above + // v = Shuffle(v, (2, 2, 0, 0)) - This corresponds to (y1 > y2) in eq(1) above + // u = Shuffle(u, (3, 3, 1, 1)) - This corresponds to (x1 == x2) in eq(1) above + // op2 = BitwiseAnd(v, u) - This corresponds to [(x1 == x2) && (y1 > y2)] in eq(1) above + // + // result = BitwiseOr(op1, op2) + + GenTree* op1Dup1; + op1 = impCloneExpr(op1, &op1Dup1, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op1 for Vector.GreaterThan/LessThan")); + + GenTree* op1Dup2; + op1Dup1 = impCloneExpr(op1Dup1, &op1Dup2, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op1 for Vector.GreaterThan/LessThan")); + + GenTree* op2Dup1; + op2 = impCloneExpr(op2, &op2Dup1, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op2 for Vector.GreaterThan/LessThan")); + + GenTree* op2Dup2; + op2Dup1 = impCloneExpr(op2Dup1, &op2Dup2, clsHnd, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("Clone op2 Vector.GreaterThan/LessThan")); + + GenTree* t = impSimdAsHWIntrinsicRelOp(intrinsic, clsHnd, retType, TYP_INT, simdSize, op1, op2); + GenTree* u = impSimdAsHWIntrinsicRelOp(NI_VectorT128_Equals, clsHnd, retType, TYP_INT, simdSize, + op1Dup1, op2Dup1); + GenTree* v = + impSimdAsHWIntrinsicRelOp(intrinsic, clsHnd, retType, TYP_UINT, simdSize, op1Dup2, op2Dup2); + + op1 = gtNewSimdAsHWIntrinsicNode(retType, t, gtNewIconNode(SHUFFLE_WWYY, TYP_INT), NI_SSE2_Shuffle, + TYP_INT, simdSize); + + v = gtNewSimdAsHWIntrinsicNode(retType, v, gtNewIconNode(SHUFFLE_ZZXX, TYP_INT), NI_SSE2_Shuffle, + TYP_INT, simdSize); + u = gtNewSimdAsHWIntrinsicNode(retType, u, gtNewIconNode(SHUFFLE_WWYY, TYP_INT), NI_SSE2_Shuffle, + TYP_INT, simdSize); + + hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(NI_VectorT128_op_BitwiseAnd, baseType); + op2 = gtNewSimdAsHWIntrinsicNode(retType, v, u, hwIntrinsic, baseType, simdSize); + + hwIntrinsic = SimdAsHWIntrinsicInfo::lookupHWIntrinsic(NI_VectorT128_op_BitwiseOr, baseType); + } + assert(hwIntrinsic != NI_Illegal); + + return gtNewSimdAsHWIntrinsicNode(retType, op1, op2, hwIntrinsic, baseType, simdSize); + } + + default: + { + assert(!"Unexpected SimdAsHWIntrinsic"); + return nullptr; + } + } +} +#endif // TARGET_XARCH + +#endif // FEATURE_HW_INTRINSICS diff --git a/src/coreclr/src/jit/simdashwintrinsic.h b/src/coreclr/src/jit/simdashwintrinsic.h new file mode 100644 index 00000000000000..e5d951e38703d1 --- /dev/null +++ b/src/coreclr/src/jit/simdashwintrinsic.h @@ -0,0 +1,130 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#ifndef _SIMD_AS_HWINTRINSIC_H_ +#define _SIMD_AS_HWINTRINSIC_H_ + +enum class SimdAsHWIntrinsicClassId +{ + Unknown, + Vector2, + Vector3, + Vector4, + VectorT128, + VectorT256, +}; + +enum class SimdAsHWIntrinsicFlag : unsigned int +{ + None = 0, + + // Indicates compFloatingPointUsed does not need to be set. + NoFloatingPointUsed = 0x1, + + // Indicates the intrinsic is for an instance method. + InstanceMethod = 0x02, + + // Indicates the operands should be swapped in importation. + NeedsOperandsSwapped = 0x04, +}; + +inline SimdAsHWIntrinsicFlag operator~(SimdAsHWIntrinsicFlag value) +{ + return static_cast(~static_cast(value)); +} + +inline SimdAsHWIntrinsicFlag operator|(SimdAsHWIntrinsicFlag lhs, SimdAsHWIntrinsicFlag rhs) +{ + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +inline SimdAsHWIntrinsicFlag operator&(SimdAsHWIntrinsicFlag lhs, SimdAsHWIntrinsicFlag rhs) +{ + return static_cast(static_cast(lhs) & static_cast(rhs)); +} + +inline SimdAsHWIntrinsicFlag operator^(SimdAsHWIntrinsicFlag lhs, SimdAsHWIntrinsicFlag rhs) +{ + return static_cast(static_cast(lhs) ^ static_cast(rhs)); +} + +struct SimdAsHWIntrinsicInfo +{ + NamedIntrinsic id; + const char* name; + SimdAsHWIntrinsicClassId classId; + int numArgs; + NamedIntrinsic hwIntrinsic[10]; + SimdAsHWIntrinsicFlag flags; + + static const SimdAsHWIntrinsicInfo& lookup(NamedIntrinsic id); + + static NamedIntrinsic lookupId(CORINFO_SIG_INFO* sig, + const char* className, + const char* methodName, + const char* enclosingClassName, + int sizeOfVectorT); + static SimdAsHWIntrinsicClassId lookupClassId(const char* className, + const char* enclosingClassName, + int sizeOfVectorT); + + // Member lookup + + static NamedIntrinsic lookupId(NamedIntrinsic id) + { + return lookup(id).id; + } + + static const char* lookupName(NamedIntrinsic id) + { + return lookup(id).name; + } + + static SimdAsHWIntrinsicClassId lookupClassId(NamedIntrinsic id) + { + return lookup(id).classId; + } + + static int lookupNumArgs(NamedIntrinsic id) + { + return lookup(id).numArgs; + } + + static NamedIntrinsic lookupHWIntrinsic(NamedIntrinsic id, var_types type) + { + if ((type < TYP_BYTE) || (type > TYP_DOUBLE)) + { + assert(!"Unexpected type"); + return NI_Illegal; + } + return lookup(id).hwIntrinsic[type - TYP_BYTE]; + } + + static SimdAsHWIntrinsicFlag lookupFlags(NamedIntrinsic id) + { + return lookup(id).flags; + } + + // Flags lookup + + static bool IsFloatingPointUsed(NamedIntrinsic id) + { + SimdAsHWIntrinsicFlag flags = lookupFlags(id); + return (flags & SimdAsHWIntrinsicFlag::NoFloatingPointUsed) == SimdAsHWIntrinsicFlag::None; + } + + static bool IsInstanceMethod(NamedIntrinsic id) + { + SimdAsHWIntrinsicFlag flags = lookupFlags(id); + return (flags & SimdAsHWIntrinsicFlag::InstanceMethod) == SimdAsHWIntrinsicFlag::InstanceMethod; + } + + static bool NeedsOperandsSwapped(NamedIntrinsic id) + { + SimdAsHWIntrinsicFlag flags = lookupFlags(id); + return (flags & SimdAsHWIntrinsicFlag::NeedsOperandsSwapped) == SimdAsHWIntrinsicFlag::NeedsOperandsSwapped; + } +}; + +#endif // _SIMD_AS_HWINTRINSIC_H_ diff --git a/src/coreclr/src/jit/simdashwintrinsiclistarm64.h b/src/coreclr/src/jit/simdashwintrinsiclistarm64.h new file mode 100644 index 00000000000000..9621486e69657b --- /dev/null +++ b/src/coreclr/src/jit/simdashwintrinsiclistarm64.h @@ -0,0 +1,130 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*****************************************************************************/ +#ifndef SIMD_AS_HWINTRINSIC +#error Define SIMD_AS_HWINTRINSIC before including this file +#endif + +#if defined(SIMD_AS_HWINTRINSIC_ID) || defined(SIMD_AS_HWINTRINSIC_NM) +#error SIMD_AS_HWINTRINSIC_ID and SIMD_AS_HWINTRINSIC_NM should not be defined before including this file +#endif +/*****************************************************************************/ + +// clang-format off + +#ifdef FEATURE_HW_INTRINSICS + +// Defines a SimdAsHWIntrinsic where the name is implicitly taken from the id +#define SIMD_AS_HWINTRINSIC_ID(classId, id, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, flag) \ + SIMD_AS_HWINTRINSIC(classId, id, #id, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, flag) + +// Defines a SimdAsHWIntrinsic where the name is explicit +#define SIMD_AS_HWINTRINSIC_NM(classId, id, name, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, flag) \ + SIMD_AS_HWINTRINSIC(classId, id, name, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, flag) + +/* Note + * Each intrinsic has a unique Intrinsic ID with type of `enum NamedIntrinsic` + * Each intrinsic has a `NumArg` for number of parameters + * Each intrinsic has 10 `NamedIntrinsic` fields that list the HWIntrinsic that should be generated based-on the base type + * NI_Illegal is used to represent an unsupported type + * Using the same Intrinsic ID as the represented entry is used to indicate special handling is required + * Each intrinsic has one or more flags with type of `enum SimdAsHWIntrinsicFlag` +*/ + +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// ISA ID Name NumArg Instructions Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// Vector2 Intrinsics +SIMD_AS_HWINTRINSIC_ID(Vector2, Abs, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Abs, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_NM(Vector2, EqualsInstance, "Equals", 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector64_op_Equality, NI_Illegal}, SimdAsHWIntrinsicFlag::InstanceMethod) +SIMD_AS_HWINTRINSIC_ID(Vector2, get_Zero, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector64_get_Zero, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, Max, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Max, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, Min, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Min, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, op_Addition, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Add, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, op_Division, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Arm64_Divide, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, op_Equality, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector64_op_Equality, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, op_Inequality, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector64_op_Inequality, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, op_Multiply, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Multiply, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, op_Subtraction, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Subtract, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, SquareRoot, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Arm64_Sqrt, NI_Illegal}, SimdAsHWIntrinsicFlag::None) + +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// ISA ID Name NumArg Instructions Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// Vector3 Intrinsics +SIMD_AS_HWINTRINSIC_ID(Vector3, Abs, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Abs, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_NM(Vector3, EqualsInstance, "Equals", 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Equality, NI_Illegal}, SimdAsHWIntrinsicFlag::InstanceMethod) +SIMD_AS_HWINTRINSIC_ID(Vector3, get_Zero, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_get_Zero, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, Max, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Max, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, Min, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Min, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, op_Addition, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Add, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, op_Division, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Arm64_Divide, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, op_Equality, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Equality, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, op_Inequality, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Inequality, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, op_Multiply, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Multiply, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, op_Subtraction, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Subtract, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, SquareRoot, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Arm64_Sqrt, NI_Illegal}, SimdAsHWIntrinsicFlag::None) + +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// ISA ID Name NumArg Instructions Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// Vector4 Intrinsics +SIMD_AS_HWINTRINSIC_ID(Vector4, Abs, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Abs, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_NM(Vector4, EqualsInstance, "Equals", 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Equality, NI_Illegal}, SimdAsHWIntrinsicFlag::InstanceMethod) +SIMD_AS_HWINTRINSIC_ID(Vector4, get_Zero, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_get_Zero, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, Max, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Max, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, Min, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Min, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, op_Addition, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Add, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, op_Division, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Arm64_Divide, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, op_Equality, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Equality, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, op_Inequality, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Inequality, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, op_Multiply, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Multiply, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, op_Subtraction, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Subtract, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, SquareRoot, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Arm64_Sqrt, NI_Illegal}, SimdAsHWIntrinsicFlag::None) + +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// ISA ID Name NumArg Instructions Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// Vector Intrinsics +SIMD_AS_HWINTRINSIC_ID(VectorT128, Abs, 1, {NI_AdvSimd_Abs, NI_VectorT128_Abs, NI_AdvSimd_Abs, NI_VectorT128_Abs, NI_AdvSimd_Abs, NI_VectorT128_Abs, NI_AdvSimd_Arm64_Abs, NI_VectorT128_Abs, NI_AdvSimd_Abs, NI_AdvSimd_Arm64_Abs}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, AndNot, 2, {NI_AdvSimd_BitwiseClear, NI_AdvSimd_BitwiseClear, NI_AdvSimd_BitwiseClear, NI_AdvSimd_BitwiseClear, NI_AdvSimd_BitwiseClear, NI_AdvSimd_BitwiseClear, NI_AdvSimd_BitwiseClear, NI_AdvSimd_BitwiseClear, NI_AdvSimd_BitwiseClear, NI_AdvSimd_BitwiseClear}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, Ceiling, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Ceiling, NI_AdvSimd_Ceiling}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, ConditionalSelect, 3, {NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, Equals, 2, {NI_AdvSimd_CompareEqual, NI_AdvSimd_CompareEqual, NI_AdvSimd_CompareEqual, NI_AdvSimd_CompareEqual, NI_AdvSimd_CompareEqual, NI_AdvSimd_CompareEqual, NI_AdvSimd_Arm64_CompareEqual, NI_AdvSimd_Arm64_CompareEqual, NI_AdvSimd_CompareEqual, NI_AdvSimd_Arm64_CompareEqual}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_NM(VectorT128, EqualsInstance, "Equals", 2, {NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality}, SimdAsHWIntrinsicFlag::InstanceMethod) +SIMD_AS_HWINTRINSIC_ID(VectorT128, Floor, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Floor, NI_AdvSimd_Floor}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, get_AllBitsSet, 0, {NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, get_Count, 0, {NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, get_Zero, 0, {NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, GreaterThan, 2, {NI_AdvSimd_CompareGreaterThan, NI_AdvSimd_CompareGreaterThan, NI_AdvSimd_CompareGreaterThan, NI_AdvSimd_CompareGreaterThan, NI_AdvSimd_CompareGreaterThan, NI_AdvSimd_CompareGreaterThan, NI_AdvSimd_Arm64_CompareGreaterThan, NI_AdvSimd_Arm64_CompareGreaterThan, NI_AdvSimd_CompareGreaterThan, NI_AdvSimd_Arm64_CompareGreaterThan}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, GreaterThanOrEqual, 2, {NI_AdvSimd_CompareGreaterThanOrEqual, NI_AdvSimd_CompareGreaterThanOrEqual, NI_AdvSimd_CompareGreaterThanOrEqual, NI_AdvSimd_CompareGreaterThanOrEqual, NI_AdvSimd_CompareGreaterThanOrEqual, NI_AdvSimd_CompareGreaterThanOrEqual, NI_AdvSimd_Arm64_CompareGreaterThanOrEqual, NI_AdvSimd_Arm64_CompareGreaterThanOrEqual, NI_AdvSimd_CompareGreaterThanOrEqual, NI_AdvSimd_Arm64_CompareGreaterThanOrEqual}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, LessThan, 2, {NI_AdvSimd_CompareLessThan, NI_AdvSimd_CompareLessThan, NI_AdvSimd_CompareLessThan, NI_AdvSimd_CompareLessThan, NI_AdvSimd_CompareLessThan, NI_AdvSimd_CompareLessThan, NI_AdvSimd_Arm64_CompareLessThan, NI_AdvSimd_Arm64_CompareLessThan, NI_AdvSimd_CompareLessThan, NI_AdvSimd_Arm64_CompareLessThan}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, LessThanOrEqual, 2, {NI_AdvSimd_CompareLessThanOrEqual, NI_AdvSimd_CompareLessThanOrEqual, NI_AdvSimd_CompareLessThanOrEqual, NI_AdvSimd_CompareLessThanOrEqual, NI_AdvSimd_CompareLessThanOrEqual, NI_AdvSimd_CompareLessThanOrEqual, NI_AdvSimd_Arm64_CompareLessThanOrEqual, NI_AdvSimd_Arm64_CompareLessThanOrEqual, NI_AdvSimd_CompareLessThanOrEqual, NI_AdvSimd_Arm64_CompareLessThanOrEqual}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, Max, 2, {NI_AdvSimd_Max, NI_AdvSimd_Max, NI_AdvSimd_Max, NI_AdvSimd_Max, NI_AdvSimd_Max, NI_AdvSimd_Max, NI_VectorT128_Max, NI_VectorT128_Max, NI_AdvSimd_Max, NI_AdvSimd_Arm64_Max}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, Min, 2, {NI_AdvSimd_Min, NI_AdvSimd_Min, NI_AdvSimd_Min, NI_AdvSimd_Min, NI_AdvSimd_Min, NI_AdvSimd_Min, NI_VectorT128_Min, NI_VectorT128_Min, NI_AdvSimd_Min, NI_AdvSimd_Arm64_Min}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_Addition, 2, {NI_AdvSimd_Add, NI_AdvSimd_Add, NI_AdvSimd_Add, NI_AdvSimd_Add, NI_AdvSimd_Add, NI_AdvSimd_Add, NI_AdvSimd_Add, NI_AdvSimd_Add, NI_AdvSimd_Add, NI_AdvSimd_Arm64_Add}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_BitwiseAnd, 2, {NI_AdvSimd_And, NI_AdvSimd_And, NI_AdvSimd_And, NI_AdvSimd_And, NI_AdvSimd_And, NI_AdvSimd_And, NI_AdvSimd_And, NI_AdvSimd_And, NI_AdvSimd_And, NI_AdvSimd_And}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_BitwiseOr, 2, {NI_AdvSimd_Or, NI_AdvSimd_Or, NI_AdvSimd_Or, NI_AdvSimd_Or, NI_AdvSimd_Or, NI_AdvSimd_Or, NI_AdvSimd_Or, NI_AdvSimd_Or, NI_AdvSimd_Or, NI_AdvSimd_Or}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_Division, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Arm64_Divide, NI_AdvSimd_Arm64_Divide}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_Equality, 2, {NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_ExclusiveOr, 2, {NI_AdvSimd_Xor, NI_AdvSimd_Xor, NI_AdvSimd_Xor, NI_AdvSimd_Xor, NI_AdvSimd_Xor, NI_AdvSimd_Xor, NI_AdvSimd_Xor, NI_AdvSimd_Xor, NI_AdvSimd_Xor, NI_AdvSimd_Xor}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_Explicit, 1, {NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_Inequality, 2, {NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_Multiply, 2, {NI_AdvSimd_Multiply, NI_AdvSimd_Multiply, NI_AdvSimd_Multiply, NI_AdvSimd_Multiply, NI_AdvSimd_Multiply, NI_AdvSimd_Multiply, NI_Illegal, NI_Illegal, NI_AdvSimd_Multiply, NI_AdvSimd_Arm64_Multiply}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_Subtraction, 2, {NI_AdvSimd_Subtract, NI_AdvSimd_Subtract, NI_AdvSimd_Subtract, NI_AdvSimd_Subtract, NI_AdvSimd_Subtract, NI_AdvSimd_Subtract, NI_AdvSimd_Subtract, NI_AdvSimd_Subtract, NI_AdvSimd_Subtract, NI_AdvSimd_Arm64_Subtract}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, SquareRoot, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AdvSimd_Arm64_Sqrt, NI_AdvSimd_Arm64_Sqrt}, SimdAsHWIntrinsicFlag::None) + +#undef SIMD_AS_HWINTRINSIC_NM +#undef SIMD_AS_HWINTRINSIC_ID + +#endif // FEATURE_HW_INTRINSICS + +#undef SIMD_AS_HWINTRINSIC + +// clang-format on diff --git a/src/coreclr/src/jit/simdashwintrinsiclistxarch.h b/src/coreclr/src/jit/simdashwintrinsiclistxarch.h new file mode 100644 index 00000000000000..d13153db4aad7b --- /dev/null +++ b/src/coreclr/src/jit/simdashwintrinsiclistxarch.h @@ -0,0 +1,163 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*****************************************************************************/ +#ifndef SIMD_AS_HWINTRINSIC +#error Define SIMD_AS_HWINTRINSIC before including this file +#endif + +#if defined(SIMD_AS_HWINTRINSIC_ID) || defined(SIMD_AS_HWINTRINSIC_NM) +#error SIMD_AS_HWINTRINSIC_ID and SIMD_AS_HWINTRINSIC_NM should not be defined before including this file +#endif +/*****************************************************************************/ + +// clang-format off + +#ifdef FEATURE_HW_INTRINSICS + +// Defines a SimdAsHWIntrinsic where the name is implicitly taken from the id +#define SIMD_AS_HWINTRINSIC_ID(classId, id, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, flag) \ + SIMD_AS_HWINTRINSIC(classId, id, #id, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, flag) + +// Defines a SimdAsHWIntrinsic where the name is explicit +#define SIMD_AS_HWINTRINSIC_NM(classId, id, name, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, flag) \ + SIMD_AS_HWINTRINSIC(classId, id, name, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, flag) + +/* Note + * Each intrinsic has a unique Intrinsic ID with type of `enum NamedIntrinsic` + * Each intrinsic has a `NumArg` for number of parameters + * Each intrinsic has 10 `NamedIntrinsic` fields that list the HWIntrinsic that should be generated based-on the base type + * NI_Illegal is used to represent an unsupported type + * Using the same Intrinsic ID as the represented entry is used to indicate special handling is required + * Each intrinsic has one or more flags with type of `enum SimdAsHWIntrinsicFlag` +*/ + +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// ISA ID Name NumArg Instructions Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// Vector2 Intrinsics +SIMD_AS_HWINTRINSIC_ID(Vector2, Abs, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_Abs, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_NM(Vector2, EqualsInstance, "Equals", 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Equality, NI_Illegal}, SimdAsHWIntrinsicFlag::InstanceMethod) +SIMD_AS_HWINTRINSIC_ID(Vector2, get_Zero, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_get_Zero, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, Max, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Max, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, Min, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Min, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, op_Addition, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Add, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, op_Division, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector2_op_Division, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, op_Equality, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Equality, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, op_Inequality, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Inequality, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, op_Multiply, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Multiply, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, op_Subtraction, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Subtract, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector2, SquareRoot, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Sqrt, NI_Illegal}, SimdAsHWIntrinsicFlag::None) + +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// ISA ID Name NumArg Instructions Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// Vector3 Intrinsics +SIMD_AS_HWINTRINSIC_ID(Vector3, Abs, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_Abs, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_NM(Vector3, EqualsInstance, "Equals", 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Equality, NI_Illegal}, SimdAsHWIntrinsicFlag::InstanceMethod) +SIMD_AS_HWINTRINSIC_ID(Vector3, get_Zero, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_get_Zero, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, Max, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Max, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, Min, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Min, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, op_Addition, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Add, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, op_Division, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector3_op_Division, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, op_Equality, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Equality, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, op_Inequality, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Inequality, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, op_Multiply, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Multiply, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, op_Subtraction, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Subtract, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector3, SquareRoot, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Sqrt, NI_Illegal}, SimdAsHWIntrinsicFlag::None) + +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// ISA ID Name NumArg Instructions Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// Vector4 Intrinsics +SIMD_AS_HWINTRINSIC_ID(Vector4, Abs, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector4_Abs, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_NM(Vector4, EqualsInstance, "Equals", 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Equality, NI_Illegal}, SimdAsHWIntrinsicFlag::InstanceMethod) +SIMD_AS_HWINTRINSIC_ID(Vector4, get_Zero, 0, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_get_Zero, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, Max, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Max, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, Min, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Min, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, op_Addition, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Add, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, op_Division, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Divide, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, op_Equality, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Equality, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, op_Inequality, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Vector128_op_Inequality, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, op_Multiply, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Multiply, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, op_Subtraction, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Subtract, NI_Illegal}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(Vector4, SquareRoot, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Sqrt, NI_Illegal}, SimdAsHWIntrinsicFlag::None) + +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// ISA ID Name NumArg Instructions Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// Vector Intrinsics +SIMD_AS_HWINTRINSIC_ID(VectorT128, Abs, 1, {NI_VectorT128_Abs, NI_VectorT128_Abs, NI_VectorT128_Abs, NI_VectorT128_Abs, NI_VectorT128_Abs, NI_VectorT128_Abs, NI_VectorT128_Abs, NI_VectorT128_Abs, NI_VectorT128_Abs, NI_VectorT128_Abs}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, AndNot, 2, {NI_SSE2_AndNot, NI_SSE2_AndNot, NI_SSE2_AndNot, NI_SSE2_AndNot, NI_SSE2_AndNot, NI_SSE2_AndNot, NI_SSE2_AndNot, NI_SSE2_AndNot, NI_SSE_AndNot, NI_SSE2_AndNot}, SimdAsHWIntrinsicFlag::NeedsOperandsSwapped) +SIMD_AS_HWINTRINSIC_ID(VectorT128, Ceiling, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE41_Ceiling, NI_SSE41_Ceiling}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, ConditionalSelect, 3, {NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect, NI_VectorT128_ConditionalSelect}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, Equals, 2, {NI_SSE2_CompareEqual, NI_SSE2_CompareEqual, NI_SSE2_CompareEqual, NI_SSE2_CompareEqual, NI_SSE2_CompareEqual, NI_SSE2_CompareEqual, NI_VectorT128_Equals, NI_VectorT128_Equals, NI_SSE_CompareEqual, NI_SSE2_CompareEqual}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_NM(VectorT128, EqualsInstance, "Equals", 2, {NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality}, SimdAsHWIntrinsicFlag::InstanceMethod) +SIMD_AS_HWINTRINSIC_ID(VectorT128, Floor, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE41_Floor, NI_SSE41_Floor}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, get_AllBitsSet, 0, {NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet, NI_Vector128_get_AllBitsSet}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, get_Count, 0, {NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count, NI_VectorT128_get_Count}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, get_Zero, 0, {NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero, NI_Vector128_get_Zero}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, GreaterThan, 2, {NI_SSE2_CompareGreaterThan, NI_VectorT128_GreaterThan, NI_SSE2_CompareGreaterThan, NI_VectorT128_GreaterThan, NI_SSE2_CompareGreaterThan, NI_VectorT128_GreaterThan, NI_VectorT128_GreaterThan, NI_VectorT128_GreaterThan, NI_SSE_CompareGreaterThan, NI_SSE2_CompareGreaterThan}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, GreaterThanOrEqual, 2, {NI_VectorT128_GreaterThanOrEqual, NI_VectorT128_GreaterThanOrEqual, NI_VectorT128_GreaterThanOrEqual, NI_VectorT128_GreaterThanOrEqual, NI_VectorT128_GreaterThanOrEqual, NI_VectorT128_GreaterThanOrEqual, NI_VectorT128_GreaterThanOrEqual, NI_VectorT128_GreaterThanOrEqual, NI_SSE_CompareGreaterThanOrEqual, NI_SSE2_CompareGreaterThanOrEqual}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, LessThan, 2, {NI_SSE2_CompareLessThan, NI_VectorT128_LessThan, NI_SSE2_CompareLessThan, NI_VectorT128_LessThan, NI_SSE2_CompareLessThan, NI_VectorT128_LessThan, NI_VectorT128_LessThan, NI_VectorT128_LessThan, NI_SSE_CompareLessThan, NI_SSE2_CompareLessThan}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, LessThanOrEqual, 2, {NI_VectorT128_LessThanOrEqual, NI_VectorT128_LessThanOrEqual, NI_VectorT128_LessThanOrEqual, NI_VectorT128_LessThanOrEqual, NI_VectorT128_LessThanOrEqual, NI_VectorT128_LessThanOrEqual, NI_VectorT128_LessThanOrEqual, NI_VectorT128_LessThanOrEqual, NI_SSE_CompareLessThanOrEqual, NI_SSE2_CompareLessThanOrEqual}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, Max, 2, {NI_VectorT128_Max, NI_SSE2_Max, NI_SSE2_Max, NI_VectorT128_Max, NI_VectorT128_Max, NI_VectorT128_Max, NI_VectorT128_Max, NI_VectorT128_Max, NI_SSE_Max, NI_SSE2_Max}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, Min, 2, {NI_VectorT128_Min, NI_SSE2_Min, NI_SSE2_Min, NI_VectorT128_Min, NI_VectorT128_Min, NI_VectorT128_Min, NI_VectorT128_Min, NI_VectorT128_Min, NI_SSE_Min, NI_SSE2_Min}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_Addition, 2, {NI_SSE2_Add, NI_SSE2_Add, NI_SSE2_Add, NI_SSE2_Add, NI_SSE2_Add, NI_SSE2_Add, NI_SSE2_Add, NI_SSE2_Add, NI_SSE_Add, NI_SSE2_Add}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_BitwiseAnd, 2, {NI_SSE2_And, NI_SSE2_And, NI_SSE2_And, NI_SSE2_And, NI_SSE2_And, NI_SSE2_And, NI_SSE2_And, NI_SSE2_And, NI_SSE_And, NI_SSE2_And}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_BitwiseOr, 2, {NI_SSE2_Or, NI_SSE2_Or, NI_SSE2_Or, NI_SSE2_Or, NI_SSE2_Or, NI_SSE2_Or, NI_SSE2_Or, NI_SSE2_Or, NI_SSE_Or, NI_SSE2_Or}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_Division, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Divide, NI_SSE2_Divide}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_Equality, 2, {NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality, NI_Vector128_op_Equality}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_ExclusiveOr, 2, {NI_SSE2_Xor, NI_SSE2_Xor, NI_SSE2_Xor, NI_SSE2_Xor, NI_SSE2_Xor, NI_SSE2_Xor, NI_SSE2_Xor, NI_SSE2_Xor, NI_SSE_Xor, NI_SSE2_Xor}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_Explicit, 1, {NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit, NI_VectorT128_op_Explicit}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_Inequality, 2, {NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality, NI_Vector128_op_Inequality}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_Multiply, 2, {NI_Illegal, NI_Illegal, NI_SSE2_MultiplyLow, NI_Illegal, NI_VectorT128_op_Multiply, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Multiply, NI_SSE2_Multiply}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, op_Subtraction, 2, {NI_SSE2_Subtract, NI_SSE2_Subtract, NI_SSE2_Subtract, NI_SSE2_Subtract, NI_SSE2_Subtract, NI_SSE2_Subtract, NI_SSE2_Subtract, NI_SSE2_Subtract, NI_SSE_Subtract, NI_SSE2_Subtract}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT128, SquareRoot, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_SSE_Sqrt, NI_SSE2_Sqrt}, SimdAsHWIntrinsicFlag::None) + +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// ISA ID Name NumArg Instructions Flags +// {TYP_BYTE, TYP_UBYTE, TYP_SHORT, TYP_USHORT, TYP_INT, TYP_UINT, TYP_LONG, TYP_ULONG, TYP_FLOAT, TYP_DOUBLE} +// ************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* +// Vector Intrinsics +SIMD_AS_HWINTRINSIC_ID(VectorT256, Abs, 1, {NI_AVX2_Abs, NI_VectorT256_Abs, NI_AVX2_Abs, NI_VectorT256_Abs, NI_AVX2_Abs, NI_VectorT256_Abs, NI_VectorT256_Abs, NI_VectorT256_Abs, NI_VectorT256_Abs, NI_VectorT256_Abs}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, AndNot, 2, {NI_AVX2_AndNot, NI_AVX2_AndNot, NI_AVX2_AndNot, NI_AVX2_AndNot, NI_AVX2_AndNot, NI_AVX2_AndNot, NI_AVX2_AndNot, NI_AVX2_AndNot, NI_AVX_AndNot, NI_AVX_AndNot}, SimdAsHWIntrinsicFlag::NeedsOperandsSwapped) +SIMD_AS_HWINTRINSIC_ID(VectorT256, Ceiling, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AVX_Ceiling, NI_AVX_Ceiling}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, ConditionalSelect, 3, {NI_VectorT256_ConditionalSelect, NI_VectorT256_ConditionalSelect, NI_VectorT256_ConditionalSelect, NI_VectorT256_ConditionalSelect, NI_VectorT256_ConditionalSelect, NI_VectorT256_ConditionalSelect, NI_VectorT256_ConditionalSelect, NI_VectorT256_ConditionalSelect, NI_VectorT256_ConditionalSelect, NI_VectorT256_ConditionalSelect}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, Equals, 2, {NI_AVX2_CompareEqual, NI_AVX2_CompareEqual, NI_AVX2_CompareEqual, NI_AVX2_CompareEqual, NI_AVX2_CompareEqual, NI_AVX2_CompareEqual, NI_AVX2_CompareEqual, NI_AVX2_CompareEqual, NI_AVX_CompareEqual, NI_AVX_CompareEqual}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_NM(VectorT256, EqualsInstance, "Equals", 2, {NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality}, SimdAsHWIntrinsicFlag::InstanceMethod) +SIMD_AS_HWINTRINSIC_ID(VectorT256, Floor, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AVX_Floor, NI_AVX_Floor}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, get_AllBitsSet, 0, {NI_Vector256_get_AllBitsSet, NI_Vector256_get_AllBitsSet, NI_Vector256_get_AllBitsSet, NI_Vector256_get_AllBitsSet, NI_Vector256_get_AllBitsSet, NI_Vector256_get_AllBitsSet, NI_Vector256_get_AllBitsSet, NI_Vector256_get_AllBitsSet, NI_Vector256_get_AllBitsSet, NI_Vector256_get_AllBitsSet}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, get_Count, 0, {NI_VectorT256_get_Count, NI_VectorT256_get_Count, NI_VectorT256_get_Count, NI_VectorT256_get_Count, NI_VectorT256_get_Count, NI_VectorT256_get_Count, NI_VectorT256_get_Count, NI_VectorT256_get_Count, NI_VectorT256_get_Count, NI_VectorT256_get_Count}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, get_Zero, 0, {NI_Vector256_get_Zero, NI_Vector256_get_Zero, NI_Vector256_get_Zero, NI_Vector256_get_Zero, NI_Vector256_get_Zero, NI_Vector256_get_Zero, NI_Vector256_get_Zero, NI_Vector256_get_Zero, NI_Vector256_get_Zero, NI_Vector256_get_Zero}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, GreaterThan, 2, {NI_AVX2_CompareGreaterThan, NI_VectorT256_GreaterThan, NI_AVX2_CompareGreaterThan, NI_VectorT256_GreaterThan, NI_AVX2_CompareGreaterThan, NI_VectorT256_GreaterThan, NI_AVX2_CompareGreaterThan, NI_VectorT256_GreaterThan, NI_AVX_CompareGreaterThan, NI_AVX_CompareGreaterThan}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, GreaterThanOrEqual, 2, {NI_VectorT256_GreaterThanOrEqual, NI_VectorT256_GreaterThanOrEqual, NI_VectorT256_GreaterThanOrEqual, NI_VectorT256_GreaterThanOrEqual, NI_VectorT256_GreaterThanOrEqual, NI_VectorT256_GreaterThanOrEqual, NI_VectorT256_GreaterThanOrEqual, NI_VectorT256_GreaterThanOrEqual, NI_AVX_CompareGreaterThanOrEqual, NI_AVX_CompareGreaterThanOrEqual}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, LessThan, 2, {NI_AVX2_CompareLessThan, NI_VectorT256_LessThan, NI_AVX2_CompareLessThan, NI_VectorT256_LessThan, NI_AVX2_CompareLessThan, NI_VectorT256_LessThan, NI_AVX2_CompareLessThan, NI_VectorT256_LessThan, NI_AVX_CompareLessThan, NI_AVX_CompareLessThan}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, LessThanOrEqual, 2, {NI_VectorT256_LessThanOrEqual, NI_VectorT256_LessThanOrEqual, NI_VectorT256_LessThanOrEqual, NI_VectorT256_LessThanOrEqual, NI_VectorT256_LessThanOrEqual, NI_VectorT256_LessThanOrEqual, NI_VectorT256_LessThanOrEqual, NI_VectorT256_LessThanOrEqual, NI_AVX_CompareLessThanOrEqual, NI_AVX_CompareLessThanOrEqual}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, Max, 2, {NI_AVX2_Max, NI_AVX2_Max, NI_AVX2_Max, NI_AVX2_Max, NI_AVX2_Max, NI_AVX2_Max, NI_VectorT256_Max, NI_VectorT256_Max, NI_AVX_Max, NI_AVX_Max}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, Min, 2, {NI_AVX2_Min, NI_AVX2_Min, NI_AVX2_Min, NI_AVX2_Min, NI_AVX2_Min, NI_AVX2_Min, NI_VectorT256_Min, NI_VectorT256_Min, NI_AVX_Min, NI_AVX_Min}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, op_Addition, 2, {NI_AVX2_Add, NI_AVX2_Add, NI_AVX2_Add, NI_AVX2_Add, NI_AVX2_Add, NI_AVX2_Add, NI_AVX2_Add, NI_AVX2_Add, NI_AVX_Add, NI_AVX_Add}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, op_BitwiseAnd, 2, {NI_AVX2_And, NI_AVX2_And, NI_AVX2_And, NI_AVX2_And, NI_AVX2_And, NI_AVX2_And, NI_AVX2_And, NI_AVX2_And, NI_AVX_And, NI_AVX_And}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, op_BitwiseOr, 2, {NI_AVX2_Or, NI_AVX2_Or, NI_AVX2_Or, NI_AVX2_Or, NI_AVX2_Or, NI_AVX2_Or, NI_AVX2_Or, NI_AVX2_Or, NI_AVX_Or, NI_AVX_Or}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, op_Division, 2, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AVX_Divide, NI_AVX_Divide}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, op_Equality, 2, {NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality, NI_Vector256_op_Equality}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, op_ExclusiveOr, 2, {NI_AVX2_Xor, NI_AVX2_Xor, NI_AVX2_Xor, NI_AVX2_Xor, NI_AVX2_Xor, NI_AVX2_Xor, NI_AVX2_Xor, NI_AVX2_Xor, NI_AVX_Xor, NI_AVX_Xor}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, op_Explicit, 1, {NI_VectorT256_op_Explicit, NI_VectorT256_op_Explicit, NI_VectorT256_op_Explicit, NI_VectorT256_op_Explicit, NI_VectorT256_op_Explicit, NI_VectorT256_op_Explicit, NI_VectorT256_op_Explicit, NI_VectorT256_op_Explicit, NI_VectorT256_op_Explicit, NI_VectorT256_op_Explicit}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, op_Inequality, 2, {NI_Vector256_op_Inequality, NI_Vector256_op_Inequality, NI_Vector256_op_Inequality, NI_Vector256_op_Inequality, NI_Vector256_op_Inequality, NI_Vector256_op_Inequality, NI_Vector256_op_Inequality, NI_Vector256_op_Inequality, NI_Vector256_op_Inequality, NI_Vector256_op_Inequality}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, op_Multiply, 2, {NI_Illegal, NI_Illegal, NI_AVX2_MultiplyLow, NI_Illegal, NI_AVX2_MultiplyLow, NI_Illegal, NI_Illegal, NI_Illegal, NI_AVX_Multiply, NI_AVX_Multiply}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, op_Subtraction, 2, {NI_AVX2_Subtract, NI_AVX2_Subtract, NI_AVX2_Subtract, NI_AVX2_Subtract, NI_AVX2_Subtract, NI_AVX2_Subtract, NI_AVX2_Subtract, NI_AVX2_Subtract, NI_AVX_Subtract, NI_AVX_Subtract}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT256, SquareRoot, 1, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_AVX_Sqrt, NI_AVX_Sqrt}, SimdAsHWIntrinsicFlag::None) + +#undef SIMD_AS_HWINTRINSIC_NM +#undef SIMD_AS_HWINTRINSIC_ID + +#endif // FEATURE_HW_INTRINSICS + +#undef SIMD_AS_HWINTRINSIC + +// clang-format on diff --git a/src/coreclr/src/jit/simdcodegenxarch.cpp b/src/coreclr/src/jit/simdcodegenxarch.cpp index 8ca69e35be37ac..e6aa4db08fe54c 100644 --- a/src/coreclr/src/jit/simdcodegenxarch.cpp +++ b/src/coreclr/src/jit/simdcodegenxarch.cpp @@ -130,21 +130,6 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type } break; - case SIMDIntrinsicSqrt: - if (baseType == TYP_FLOAT) - { - result = INS_sqrtps; - } - else if (baseType == TYP_DOUBLE) - { - result = INS_sqrtpd; - } - else - { - unreached(); - } - break; - case SIMDIntrinsicAdd: if (baseType == TYP_FLOAT) { @@ -233,108 +218,6 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type } break; - case SIMDIntrinsicMin: - if (baseType == TYP_FLOAT) - { - result = INS_minps; - } - else if (baseType == TYP_DOUBLE) - { - result = INS_minpd; - } - else if (baseType == TYP_UBYTE) - { - result = INS_pminub; - } - else if (baseType == TYP_SHORT) - { - result = INS_pminsw; - } - else if (compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported) - { - if (baseType == TYP_BYTE) - { - result = INS_pminsb; - } - else if (baseType == TYP_USHORT) - { - result = INS_pminuw; - } - else if (baseType == TYP_INT) - { - result = INS_pminsd; - } - else if (baseType == TYP_UINT) - { - result = INS_pminud; - } - } - else - { - unreached(); - } - break; - - case SIMDIntrinsicMax: - if (baseType == TYP_FLOAT) - { - result = INS_maxps; - } - else if (baseType == TYP_DOUBLE) - { - result = INS_maxpd; - } - else if (baseType == TYP_UBYTE) - { - result = INS_pmaxub; - } - else if (baseType == TYP_SHORT) - { - result = INS_pmaxsw; - } - else if (compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported) - { - if (baseType == TYP_BYTE) - { - result = INS_pmaxsb; - } - else if (baseType == TYP_USHORT) - { - result = INS_pmaxuw; - } - else if (baseType == TYP_INT) - { - result = INS_pmaxsd; - } - else if (baseType == TYP_UINT) - { - result = INS_pmaxud; - } - } - else - { - unreached(); - } - break; - - case SIMDIntrinsicAbs: - if (compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported) - { - if (baseType == TYP_INT) - { - result = INS_pabsd; - } - else if (baseType == TYP_SHORT) - { - result = INS_pabsw; - } - else if (baseType == TYP_BYTE) - { - result = INS_pabsb; - } - } - break; - case SIMDIntrinsicEqual: if (baseType == TYP_FLOAT) { @@ -367,65 +250,6 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type } break; - case SIMDIntrinsicLessThan: - // Packed integers use > with swapped operands - assert(baseType != TYP_INT); - - if (baseType == TYP_FLOAT) - { - result = INS_cmpps; - assert(ival != nullptr); - *ival = 1; - } - else if (baseType == TYP_DOUBLE) - { - result = INS_cmppd; - assert(ival != nullptr); - *ival = 1; - } - break; - - case SIMDIntrinsicLessThanOrEqual: - // Packed integers use (a==b) || ( b > a) in place of a <= b. - assert(baseType != TYP_INT); - - if (baseType == TYP_FLOAT) - { - result = INS_cmpps; - assert(ival != nullptr); - *ival = 2; - } - else if (baseType == TYP_DOUBLE) - { - result = INS_cmppd; - assert(ival != nullptr); - *ival = 2; - } - break; - - case SIMDIntrinsicGreaterThan: - // Packed float/double use < with swapped operands - assert(!varTypeIsFloating(baseType)); - - // SSE2 supports only signed > - if (baseType == TYP_INT) - { - result = INS_pcmpgtd; - } - else if (baseType == TYP_SHORT) - { - result = INS_pcmpgtw; - } - else if (baseType == TYP_BYTE) - { - result = INS_pcmpgtb; - } - else if ((baseType == TYP_LONG) && (compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported)) - { - result = INS_pcmpgtq; - } - break; - case SIMDIntrinsicBitwiseAnd: if (baseType == TYP_FLOAT) { @@ -441,25 +265,6 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type } break; - case SIMDIntrinsicBitwiseAndNot: - if (baseType == TYP_FLOAT) - { - result = INS_andnps; - } - else if (baseType == TYP_DOUBLE) - { - result = INS_andnpd; - } - else if (baseType == TYP_INT) - { - result = INS_pandn; - } - else if (varTypeIsIntegral(baseType)) - { - result = INS_pandn; - } - break; - case SIMDIntrinsicBitwiseOr: if (baseType == TYP_FLOAT) { @@ -475,21 +280,6 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type } break; - case SIMDIntrinsicBitwiseXor: - if (baseType == TYP_FLOAT) - { - result = INS_xorps; - } - else if (baseType == TYP_DOUBLE) - { - result = INS_xorpd; - } - else if (varTypeIsIntegral(baseType)) - { - result = INS_pxor; - } - break; - case SIMDIntrinsicCast: result = INS_movaps; break; @@ -645,26 +435,6 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type result = INS_insertps; break; - case SIMDIntrinsicCeil: - case SIMDIntrinsicFloor: - if (compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported) - { - if (baseType == TYP_FLOAT) - { - result = INS_roundps; - } - else - { - assert(baseType == TYP_DOUBLE); - result = INS_roundpd; - } - - assert(ival != nullptr); - *ival = (intrinsicId == SIMDIntrinsicCeil) ? ROUNDPS_TOWARD_POSITIVE_INFINITY_IMM - : ROUNDPS_TOWARD_NEGATIVE_INFINITY_IMM; - } - break; - default: assert(!"Unsupported SIMD intrinsic"); unreached(); @@ -760,10 +530,10 @@ void CodeGen::genSIMDScalarMove( void CodeGen::genSIMDZero(var_types targetType, var_types baseType, regNumber targetReg) { - // We just use `INS_xorps` instead of `getOpForSIMDIntrinsic(SIMDIntrinsicBitwiseXor, baseType)` - // since `genSIMDZero` is used for both `System.Numerics.Vectors` and HardwareIntrinsics. Modern - // CPUs handle this specially in the renamer and it never hits the execution pipeline, additionally - // `INS_xorps` is always available (when using either the legacy or VEX encoding). + // We just use `INS_xorps` since `genSIMDZero` is used for both `System.Numerics.Vectors` and + // HardwareIntrinsics. Modern CPUs handle this specially in the renamer and it never hits the + // execution pipeline, additionally `INS_xorps` is always available (when using either the + // legacy or VEX encoding). inst_RV_RV(INS_xorps, targetReg, targetReg, targetType, emitActualTypeSize(targetType)); } @@ -1062,8 +832,7 @@ void CodeGen::genSIMDIntrinsicInitN(GenTreeSIMD* simdNode) // void CodeGen::genSIMDIntrinsicUnOp(GenTreeSIMD* simdNode) { - assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicSqrt || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicCast || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicAbs); + assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicCast); GenTree* op1 = simdNode->gtGetOp1(); var_types baseType = simdNode->gtSIMDBaseType; @@ -1080,32 +849,6 @@ void CodeGen::genSIMDIntrinsicUnOp(GenTreeSIMD* simdNode) genProduceReg(simdNode); } -//---------------------------------------------------------------------------------- -// genSIMDIntrinsicUnOpWithImm: Generate code for SIMD Intrinsic unary operations with an imm8, such as Ceil. -// -// Arguments: -// simdNode - The GT_SIMD node -// -// Return Value: -// None. -// -void CodeGen::genSIMDIntrinsicUnOpWithImm(GenTreeSIMD* simdNode) -{ - assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicCeil || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicFloor); - - GenTree* op1 = simdNode->gtGetOp1(); - var_types baseType = simdNode->gtSIMDBaseType; - regNumber targetReg = simdNode->GetRegNum(); - assert(targetReg != REG_NA); - var_types targetType = simdNode->TypeGet(); - - regNumber op1Reg = genConsumeReg(op1); - unsigned ival; - instruction ins = getOpForSIMDIntrinsic(simdNode->gtSIMDIntrinsicID, baseType, &ival); - assert((ival >= 0) && (ival <= 255)); - GetEmitter()->emitIns_R_R_I(ins, emitActualTypeSize(targetType), targetReg, op1Reg, (int8_t)ival); -} - //---------------------------------------------------------------------------------- // genSIMDIntrinsic32BitConvert: Generate code for 32-bit SIMD Convert (int/uint <-> float) // @@ -1627,7 +1370,26 @@ void CodeGen::genSIMDIntrinsicWiden(GenTreeSIMD* simdNode) genSIMDZero(simdType, baseType, tmpReg); if (!varTypeIsUnsigned(baseType)) { - instruction compareIns = getOpForSIMDIntrinsic(SIMDIntrinsicGreaterThan, baseType); + instruction compareIns = INS_invalid; + + if (baseType == TYP_INT) + { + compareIns = INS_pcmpgtd; + } + else if (baseType == TYP_SHORT) + { + compareIns = INS_pcmpgtw; + } + else if (baseType == TYP_BYTE) + { + compareIns = INS_pcmpgtb; + } + else if ((baseType == TYP_LONG) && (compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported)) + { + compareIns = INS_pcmpgtq; + } + + assert(compareIns != INS_invalid); inst_RV_RV(compareIns, tmpReg, targetReg, simdType, emitSize); } inst_RV_RV(widenIns, targetReg, tmpReg, simdType); @@ -1797,10 +1559,7 @@ void CodeGen::genSIMDIntrinsicBinOp(GenTreeSIMD* simdNode) assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicAdd || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicSub || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicMul || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicDiv || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseAnd || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseAndNot || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseOr || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseXor || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicMin || - simdNode->gtSIMDIntrinsicID == SIMDIntrinsicMax); + simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseOr); GenTree* op1 = simdNode->gtGetOp1(); GenTree* op2 = simdNode->gtGetOp2(); @@ -1997,7 +1756,6 @@ void CodeGen::genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode) switch (simdNode->gtSIMDIntrinsicID) { case SIMDIntrinsicEqual: - case SIMDIntrinsicGreaterThan: { assert(targetReg != REG_NA); @@ -2010,12 +1768,6 @@ void CodeGen::genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode) } #endif - // Greater-than: Floating point vectors use "<" with swapped operands - if (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicGreaterThan) - { - assert(!varTypeIsFloating(baseType)); - } - unsigned ival = 0; instruction ins = getOpForSIMDIntrinsic(simdNode->gtSIMDIntrinsicID, baseType, &ival); @@ -2047,124 +1799,6 @@ void CodeGen::genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode) } break; - case SIMDIntrinsicLessThan: - case SIMDIntrinsicLessThanOrEqual: - { - assert(targetReg != REG_NA); - - // Int vectors use ">" and ">=" with swapped operands - assert(varTypeIsFloating(baseType)); - - // Get the instruction opcode for compare operation - unsigned ival; - instruction ins = getOpForSIMDIntrinsic(simdNode->gtSIMDIntrinsicID, baseType, &ival); - - // targetReg = op1reg RelOp op2reg - // Thefore, we can optimize if op1Reg == targetReg - if (op1Reg != targetReg) - { - inst_RV_RV(ins_Copy(targetType), targetReg, op1Reg, targetType, emitActualTypeSize(targetType)); - } - - assert((ival >= 0) && (ival <= 255)); - GetEmitter()->emitIns_R_R_I(ins, emitActualTypeSize(targetType), targetReg, op2Reg, (int8_t)ival); - } - break; - - // (In)Equality that produces bool result instead of a bit vector - case SIMDIntrinsicOpEquality: - case SIMDIntrinsicOpInEquality: - { - // We're only setting condition flags, if a 0/1 value is desired then Lowering should have inserted a SETCC. - assert(targetReg == REG_NA); - - var_types simdType = op1->TypeGet(); - // TODO-1stClassStructs: Temporary to minimize asmDiffs - if (simdType == TYP_DOUBLE) - { - simdType = TYP_SIMD8; - } - - // Here we should consider TYP_SIMD12 operands as if they were TYP_SIMD16 - // since both the operands will be in XMM registers. - if (simdType == TYP_SIMD12) - { - simdType = TYP_SIMD16; - } - - // On SSE4/AVX, we can generate optimal code for (in)equality against zero using ptest. - if (op2->isContained()) - { - assert((compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported) && op2->IsIntegralConstVector(0)); - inst_RV_RV(INS_ptest, op1->GetRegNum(), op1->GetRegNum(), simdType, emitActualTypeSize(simdType)); - } - else - { - // We need one additional SIMD register to store the result of the SIMD compare. - regNumber tmpReg1 = simdNode->GetSingleTempReg(RBM_ALLFLOAT); - - // tmpReg1 = (op1Reg == op2Reg) - // Call this value of tmpReg1 as 'compResult' for further reference below. - regNumber otherReg = op2Reg; - if (tmpReg1 != op2Reg) - { - if (tmpReg1 != op1Reg) - { - inst_RV_RV(ins_Copy(simdType), tmpReg1, op1Reg, simdType, emitActualTypeSize(simdType)); - } - } - else - { - otherReg = op1Reg; - } - - // For all integer types we can use TYP_INT comparison. - unsigned ival = 0; - instruction ins = - getOpForSIMDIntrinsic(SIMDIntrinsicEqual, varTypeIsFloating(baseType) ? baseType : TYP_INT, &ival); - - if (varTypeIsFloating(baseType)) - { - assert((ival >= 0) && (ival <= 255)); - GetEmitter()->emitIns_R_R_I(ins, emitActualTypeSize(simdType), tmpReg1, otherReg, (int8_t)ival); - } - else - { - inst_RV_RV(ins, tmpReg1, otherReg, simdType, emitActualTypeSize(simdType)); - } - - regNumber intReg = simdNode->GetSingleTempReg(RBM_ALLINT); - inst_RV_RV(INS_pmovmskb, intReg, tmpReg1, simdType, emitActualTypeSize(simdType)); - // There's no pmovmskw/pmovmskd/pmovmskq but they're not needed anyway. Vector compare - // instructions produce "all ones"/"all zeroes" components and pmovmskb extracts a - // subset of each component's ones/zeroes. In the end we need to know if the result is - // "all ones" where the number of ones is given by the vector byte size, not by the - // vector component count. So, for AVX registers we need to compare to 0xFFFFFFFF and - // for SSE registers we need to compare to 0x0000FFFF. - // The SIMD12 case is handled specially, because we can't rely on the upper bytes being - // zero, so we must compare only the lower 3 floats (hence the byte mask of 0xFFF). - // Note that -1 is used instead of 0xFFFFFFFF, on x64 emit doesn't correctly recognize - // that 0xFFFFFFFF can be encoded in a single byte and emits the longer 3DFFFFFFFF - // encoding instead of 83F8FF. - ssize_t mask; - if ((simdNode->gtFlags & GTF_SIMD12_OP) != 0) - { - mask = 0x00000FFF; - GetEmitter()->emitIns_R_I(INS_and, EA_4BYTE, intReg, mask); - } - else if (emitActualTypeSize(simdType) == 32) - { - mask = -1; - } - else - { - mask = 0x0000FFFF; - } - GetEmitter()->emitIns_R_I(INS_cmp, EA_4BYTE, intReg, mask); - } - } - break; - default: noway_assert(!"Unimplemented SIMD relational operation."); unreached(); @@ -2973,13 +2607,26 @@ void CodeGen::genStoreLclTypeSIMD12(GenTree* treeNode) offs = treeNode->AsLclFld()->GetLclOffs(); } - GenTree* op1 = treeNode->AsOp()->gtOp1; + regNumber tmpReg = treeNode->GetSingleTempReg(); + GenTree* op1 = treeNode->AsOp()->gtOp1; + if (op1->isContained()) + { + // This is only possible for a zero-init. + assert(op1->IsIntegralConst(0) || op1->IsSIMDZero()); + genSIMDZero(TYP_SIMD16, op1->AsSIMD()->gtSIMDBaseType, tmpReg); + + // store lower 8 bytes + GetEmitter()->emitIns_S_R(ins_Store(TYP_DOUBLE), EA_8BYTE, tmpReg, varNum, offs); + + // Store upper 4 bytes + GetEmitter()->emitIns_S_R(ins_Store(TYP_FLOAT), EA_4BYTE, tmpReg, varNum, offs + 8); + + return; + } + assert(!op1->isContained()); regNumber operandReg = genConsumeReg(op1); - // Need an addtional Xmm register to extract upper 4 bytes from data. - regNumber tmpReg = treeNode->GetSingleTempReg(); - // store lower 8 bytes GetEmitter()->emitIns_S_R(ins_Store(TYP_DOUBLE), EA_8BYTE, operandReg, varNum, offs); @@ -3211,9 +2858,7 @@ void CodeGen::genSIMDIntrinsic(GenTreeSIMD* simdNode) genSIMDIntrinsicInitN(simdNode); break; - case SIMDIntrinsicSqrt: case SIMDIntrinsicCast: - case SIMDIntrinsicAbs: genSIMDIntrinsicUnOp(simdNode); break; @@ -3241,21 +2886,11 @@ void CodeGen::genSIMDIntrinsic(GenTreeSIMD* simdNode) case SIMDIntrinsicMul: case SIMDIntrinsicDiv: case SIMDIntrinsicBitwiseAnd: - case SIMDIntrinsicBitwiseAndNot: case SIMDIntrinsicBitwiseOr: - case SIMDIntrinsicBitwiseXor: - case SIMDIntrinsicMin: - case SIMDIntrinsicMax: genSIMDIntrinsicBinOp(simdNode); break; - case SIMDIntrinsicOpEquality: - case SIMDIntrinsicOpInEquality: case SIMDIntrinsicEqual: - case SIMDIntrinsicLessThan: - case SIMDIntrinsicGreaterThan: - case SIMDIntrinsicLessThanOrEqual: - case SIMDIntrinsicGreaterThanOrEqual: genSIMDIntrinsicRelOp(simdNode); break; @@ -3285,11 +2920,6 @@ void CodeGen::genSIMDIntrinsic(GenTreeSIMD* simdNode) genSIMDIntrinsicUpperRestore(simdNode); break; - case SIMDIntrinsicCeil: - case SIMDIntrinsicFloor: - genSIMDIntrinsicUnOpWithImm(simdNode); - break; - default: noway_assert(!"Unimplemented SIMD intrinsic."); unreached(); diff --git a/src/coreclr/src/jit/simdintrinsiclist.h b/src/coreclr/src/jit/simdintrinsiclist.h index 7b535c0112dc80..813a937fd056b8 100644 --- a/src/coreclr/src/jit/simdintrinsiclist.h +++ b/src/coreclr/src/jit/simdintrinsiclist.h @@ -76,13 +76,6 @@ SIMD_INTRINSIC("set_Y", true, SetY, SIMD_INTRINSIC("set_Z", true, SetZ, "setZ", TYP_VOID, 2, {TYP_BYREF, TYP_UNKNOWN, TYP_UNDEF}, {TYP_FLOAT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) SIMD_INTRINSIC("set_W", true, SetW, "setW", TYP_VOID, 2, {TYP_BYREF, TYP_UNKNOWN, TYP_UNDEF}, {TYP_FLOAT, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) -// Object.Equals() -SIMD_INTRINSIC("Equals", true, InstEquals, "equals", TYP_BOOL, 2, {TYP_BYREF, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) - -// Operator == and != -SIMD_INTRINSIC("op_Equality", false, OpEquality, "==", TYP_BOOL, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) -SIMD_INTRINSIC("op_Inequality", false, OpInEquality, "!=", TYP_BOOL, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) - // Arithmetic Operations SIMD_INTRINSIC("op_Addition", false, Add, "+", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) SIMD_INTRINSIC("op_Subtraction", false, Sub, "-", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) @@ -96,28 +89,12 @@ SIMD_INTRINSIC("op_Multiply", false, Mul, SIMD_INTRINSIC("op_Division", false, Div, "/", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_FLOAT, TYP_DOUBLE, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) -// SquareRoot is recognized as an intrinsic only for float or double vectors -SIMD_INTRINSIC("SquareRoot", false, Sqrt, "sqrt", TYP_STRUCT, 1, {TYP_STRUCT, TYP_UNDEF, TYP_UNDEF}, {TYP_FLOAT, TYP_DOUBLE, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) - -SIMD_INTRINSIC("Ceiling", false, Ceil, "ceil", TYP_STRUCT, 1, {TYP_STRUCT, TYP_UNDEF, TYP_UNDEF}, {TYP_FLOAT, TYP_DOUBLE, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) -SIMD_INTRINSIC("Floor", false, Floor, "floor", TYP_STRUCT, 1, {TYP_STRUCT, TYP_UNDEF, TYP_UNDEF}, {TYP_FLOAT, TYP_DOUBLE, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}) - -SIMD_INTRINSIC("Min", false, Min, "min", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) -SIMD_INTRINSIC("Max", false, Max, "max", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) -SIMD_INTRINSIC("Abs", false, Abs, "abs", TYP_STRUCT, 1, {TYP_STRUCT, TYP_UNDEF, TYP_UNDEF }, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) - // Vector Relational operators SIMD_INTRINSIC("Equals", false, Equal, "eq", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) -SIMD_INTRINSIC("LessThan", false, LessThan, "lt", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) -SIMD_INTRINSIC("LessThanOrEqual", false, LessThanOrEqual, "le", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) -SIMD_INTRINSIC("GreaterThan", false, GreaterThan, "gt", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) -SIMD_INTRINSIC("GreaterThanOrEqual", false, GreaterThanOrEqual, "ge", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) // Bitwise operations SIMD_INTRINSIC("op_BitwiseAnd", false, BitwiseAnd, "&", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) -SIMD_INTRINSIC("AndNot", false, BitwiseAndNot, "&~", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) SIMD_INTRINSIC("op_BitwiseOr", false, BitwiseOr, "|", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) -SIMD_INTRINSIC("op_ExclusiveOr", false, BitwiseXor, "^", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) // Dot Product #if defined(TARGET_XARCH) @@ -128,9 +105,6 @@ SIMD_INTRINSIC("Dot", false, DotProduct, SIMD_INTRINSIC("Dot", false, DotProduct, "Dot", TYP_UNKNOWN, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_UNDEF, TYP_UNDEF}) #endif -// Select -SIMD_INTRINSIC("ConditionalSelect", false, Select, "Select", TYP_STRUCT, 3, {TYP_STRUCT, TYP_STRUCT, TYP_STRUCT}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) - // Cast SIMD_INTRINSIC("op_Explicit", false, Cast, "Cast", TYP_STRUCT, 1, {TYP_STRUCT, TYP_UNDEF, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_USHORT, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG}) diff --git a/src/coreclr/src/jit/ssabuilder.cpp b/src/coreclr/src/jit/ssabuilder.cpp index 53cffb67c9e341..8730a277c6fd6b 100644 --- a/src/coreclr/src/jit/ssabuilder.cpp +++ b/src/coreclr/src/jit/ssabuilder.cpp @@ -1650,6 +1650,10 @@ bool SsaBuilder::IncludeInSsa(unsigned lclNum) // return false; } + else if (varDsc->lvIsStructField && m_pCompiler->lvaGetDesc(varDsc->lvParentLcl)->lvIsMultiRegRet) + { + return false; + } // otherwise this variable is included in SSA return true; } diff --git a/src/coreclr/src/jit/target.h b/src/coreclr/src/jit/target.h index ddfc9b67f80497..6fd88968026c3a 100644 --- a/src/coreclr/src/jit/target.h +++ b/src/coreclr/src/jit/target.h @@ -232,12 +232,15 @@ typedef unsigned char regNumberSmall; #define FEATURE_MULTIREG_ARGS 0 // Support for passing a single argument in more than one register #define FEATURE_MULTIREG_RET 1 // Support for returning a single value in more than one register #define MAX_PASS_SINGLEREG_BYTES 8 // Maximum size of a struct passed in a single register (double). - #define MAX_PASS_MULTIREG_BYTES 0 // No multireg arguments (note this seems wrong as MAX_ARG_REG_COUNT is 2) + #define MAX_PASS_MULTIREG_BYTES 0 // No multireg arguments #define MAX_RET_MULTIREG_BYTES 8 // Maximum size of a struct that could be returned in more than one register - #define MAX_ARG_REG_COUNT 2 // Maximum registers used to pass an argument. + #define MAX_ARG_REG_COUNT 1 // Maximum registers used to pass an argument. #define MAX_RET_REG_COUNT 2 // Maximum registers used to return a value. + #define MAX_MULTIREG_COUNT 2 // Maxiumum number of registers defined by a single instruction (including calls). + // This is also the maximum number of registers for a MultiReg node. + #ifdef FEATURE_USE_ASM_GC_WRITE_BARRIERS #define NOGC_WRITE_BARRIERS 1 // We have specialized WriteBarrier JIT Helpers that DO-NOT trash the // RBM_CALLEE_TRASH registers @@ -518,6 +521,9 @@ typedef unsigned char regNumberSmall; #define MAX_RET_MULTIREG_BYTES 32 // Maximum size of a struct that could be returned in more than one register (Max is two SIMD16s) #define MAX_ARG_REG_COUNT 2 // Maximum registers used to pass a single argument in multiple registers. #define MAX_RET_REG_COUNT 2 // Maximum registers used to return a value. + + #define MAX_MULTIREG_COUNT 2 // Maxiumum number of registers defined by a single instruction (including calls). + // This is also the maximum number of registers for a MultiReg node. #else // !UNIX_AMD64_ABI #define WINDOWS_AMD64_ABI // Uses the Windows ABI for AMD64 #define FEATURE_MULTIREG_ARGS_OR_RET 0 // Support for passing and/or returning single values in more than one register @@ -527,6 +533,11 @@ typedef unsigned char regNumberSmall; #define MAX_RET_MULTIREG_BYTES 0 // No multireg return values #define MAX_ARG_REG_COUNT 1 // Maximum registers used to pass a single argument (no arguments are passed using multiple registers) #define MAX_RET_REG_COUNT 1 // Maximum registers used to return a value. + + #define MAX_MULTIREG_COUNT 2 // Maxiumum number of registers defined by a single instruction (including calls). + // This is also the maximum number of registers for a MultiReg node. + // Note that this must be greater than 1 so that GenTreeLclVar can have an array of + // MAX_MULTIREG_COUNT - 1. #endif // !UNIX_AMD64_ABI #define NOGC_WRITE_BARRIERS 0 // We DO-NOT have specialized WriteBarrier JIT Helpers that DO-NOT trash the RBM_CALLEE_TRASH registers @@ -906,6 +917,9 @@ typedef unsigned char regNumberSmall; #define MAX_ARG_REG_COUNT 4 // Maximum registers used to pass a single argument in multiple registers. (max is 4 floats or doubles using an HFA) #define MAX_RET_REG_COUNT 4 // Maximum registers used to return a value. + #define MAX_MULTIREG_COUNT 4 // Maxiumum number of registers defined by a single instruction (including calls). + // This is also the maximum number of registers for a MultiReg node. + #define NOGC_WRITE_BARRIERS 0 // We DO-NOT have specialized WriteBarrier JIT Helpers that DO-NOT trash the RBM_CALLEE_TRASH registers #define USER_ARGS_COME_LAST 1 #define EMIT_TRACK_STACK_DEPTH 1 // This is something of a workaround. For both ARM and AMD64, the frame size is fixed, so we don't really @@ -1217,6 +1231,9 @@ typedef unsigned char regNumberSmall; #define MAX_ARG_REG_COUNT 4 // Maximum registers used to pass a single argument in multiple registers. (max is 4 128-bit vectors using an HVA) #define MAX_RET_REG_COUNT 4 // Maximum registers used to return a value. + #define MAX_MULTIREG_COUNT 4 // Maxiumum number of registers defined by a single instruction (including calls). + // This is also the maximum number of registers for a MultiReg node. + #define NOGC_WRITE_BARRIERS 1 // We have specialized WriteBarrier JIT Helpers that DO-NOT trash the RBM_CALLEE_TRASH registers #define USER_ARGS_COME_LAST 1 #define EMIT_TRACK_STACK_DEPTH 1 // This is something of a workaround. For both ARM and AMD64, the frame size is fixed, so we don't really diff --git a/src/coreclr/src/jit/treelifeupdater.cpp b/src/coreclr/src/jit/treelifeupdater.cpp index f373e0c89a18e7..d1a574c071fe85 100644 --- a/src/coreclr/src/jit/treelifeupdater.cpp +++ b/src/coreclr/src/jit/treelifeupdater.cpp @@ -74,9 +74,27 @@ void TreeLifeUpdater::UpdateLifeVar(GenTree* tree) } // if it's a partial definition then variable "x" must have had a previous, original, site to be born. - bool isBorn = ((tree->gtFlags & GTF_VAR_DEF) != 0 && (tree->gtFlags & GTF_VAR_USEASG) == 0); - bool isDying = ((tree->gtFlags & GTF_VAR_DEATH) != 0); - bool spill = ((tree->gtFlags & GTF_SPILL) != 0); + bool isBorn; + bool isDying; + bool spill; + bool isMultiRegLocal = lclVarTree->IsMultiRegLclVar(); + if (isMultiRegLocal) + { + assert((tree->gtFlags & GTF_VAR_USEASG) == 0); + isBorn = ((tree->gtFlags & GTF_VAR_DEF) != 0); + // Note that for multireg locals we can have definitions for which some of those are last uses. + // We don't want to add those to the varDeltaSet because otherwise they will be added as newly + // live. + isDying = !isBorn && tree->AsLclVar()->HasLastUse(); + // GTF_SPILL will be set if any registers need to be spilled. + spill = ((tree->gtFlags & GTF_SPILL) != 0); + } + else + { + isBorn = ((lclVarTree->gtFlags & GTF_VAR_DEF) != 0 && (lclVarTree->gtFlags & GTF_VAR_USEASG) == 0); + isDying = ((lclVarTree->gtFlags & GTF_VAR_DEATH) != 0); + spill = ((lclVarTree->gtFlags & GTF_SPILL) != 0); + } // Since all tracked vars are register candidates, but not all are in registers at all times, // we maintain two separate sets of variables - the total set of variables that are either @@ -108,6 +126,10 @@ void TreeLifeUpdater::UpdateLifeVar(GenTree* tree) } } } + else if (ForCodeGen && lclVarTree->IsMultiRegLclVar()) + { + assert(!"MultiRegLclVars not yet supported"); + } else if (varDsc->lvPromoted) { // If hasDeadTrackedFieldVars is true, then, for a LDOBJ(ADDR()), @@ -126,15 +148,17 @@ void TreeLifeUpdater::UpdateLifeVar(GenTree* tree) } } - for (unsigned i = varDsc->lvFieldLclStart; i < varDsc->lvFieldLclStart + varDsc->lvFieldCnt; ++i) + unsigned firstFieldVarNum = varDsc->lvFieldLclStart; + for (unsigned i = 0; i < varDsc->lvFieldCnt; ++i) { - LclVarDsc* fldVarDsc = &(compiler->lvaTable[i]); + LclVarDsc* fldVarDsc = compiler->lvaGetDesc(firstFieldVarNum + i); noway_assert(fldVarDsc->lvIsStructField); if (fldVarDsc->lvTracked) { unsigned fldVarIndex = fldVarDsc->lvVarIndex; - bool isInReg = fldVarDsc->lvIsInReg(); - bool isInMemory = !isInReg || fldVarDsc->lvLiveInOutOfHndlr; + // We should never see enregistered fields in a struct local unless + // IsMultiRegLclVar() returns true, in which case we've handled this above. + assert(!fldVarDsc->lvIsInReg()); noway_assert(fldVarIndex < compiler->lvaTrackedCount); if (!hasDeadTrackedFieldVars) { @@ -143,34 +167,12 @@ void TreeLifeUpdater::UpdateLifeVar(GenTree* tree) { // We repeat this call here and below to avoid the VarSetOps::IsMember // test in this, the common case, where we have no deadTrackedFieldVars. - if (isInReg) - { - if (isBorn) - { - compiler->codeGen->genUpdateVarReg(fldVarDsc, tree); - } - compiler->codeGen->genUpdateRegLife(fldVarDsc, isBorn, isDying DEBUGARG(tree)); - } - if (isInMemory) - { - VarSetOps::AddElemD(compiler, stackVarDeltaSet, fldVarIndex); - } + VarSetOps::AddElemD(compiler, stackVarDeltaSet, fldVarIndex); } } else if (ForCodeGen && VarSetOps::IsMember(compiler, varDeltaSet, fldVarIndex)) { - if (isInReg) - { - if (isBorn) - { - compiler->codeGen->genUpdateVarReg(fldVarDsc, tree); - } - compiler->codeGen->genUpdateRegLife(fldVarDsc, isBorn, isDying DEBUGARG(tree)); - } - if (isInMemory) - { - VarSetOps::AddElemD(compiler, stackVarDeltaSet, fldVarIndex); - } + VarSetOps::AddElemD(compiler, stackVarDeltaSet, fldVarIndex); } } } diff --git a/src/coreclr/src/jit/valuenum.cpp b/src/coreclr/src/jit/valuenum.cpp index f4060cbd533559..2fb9c3ce14e469 100644 --- a/src/coreclr/src/jit/valuenum.cpp +++ b/src/coreclr/src/jit/valuenum.cpp @@ -3612,15 +3612,7 @@ ValueNum ValueNumStore::VNApplySelectorsTypeCheck(ValueNum elem, var_types indTy size_t elemTypSize = (elemTyp == TYP_STRUCT) ? elemStructSize : genTypeSize(elemTyp); size_t indTypeSize = genTypeSize(indType); - if ((indType == TYP_REF) && (varTypeIsStruct(elemTyp))) - { - // indType is TYP_REF and elemTyp is TYP_STRUCT - // - // We have a pointer to a static that is a Boxed Struct - // - return elem; - } - else if (indTypeSize > elemTypSize) + if (indTypeSize > elemTypSize) { // Reading beyong the end of 'elem' diff --git a/src/coreclr/src/jit/valuenumfuncs.h b/src/coreclr/src/jit/valuenumfuncs.h index 9058b300215c5f..c17d18a57faa31 100644 --- a/src/coreclr/src/jit/valuenumfuncs.h +++ b/src/coreclr/src/jit/valuenumfuncs.h @@ -168,13 +168,13 @@ ValueNumFuncDef(SIMD_##id, argCount, false, false, false) // All of the SIMD i #define VNF_SIMD_FIRST VNF_SIMD_None #if defined(TARGET_XARCH) -#define HARDWARE_INTRINSIC(id, name, isa, ival, size, argCount, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \ -ValueNumFuncDef(HWI_##id, argCount, false, false, false) // All of the HARDWARE_INTRINSICS for x86/x64 +#define HARDWARE_INTRINSIC(isa, name, size, argCount, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \ +ValueNumFuncDef(HWI_##isa##_##name, argCount, false, false, false) // All of the HARDWARE_INTRINSICS for x86/x64 #include "hwintrinsiclistxarch.h" #define VNF_HWI_FIRST VNF_HWI_Vector128_As #elif defined (TARGET_ARM64) -#define HARDWARE_INTRINSIC(isa, name, ival, size, argCount, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \ +#define HARDWARE_INTRINSIC(isa, name, size, argCount, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \ ValueNumFuncDef(HWI_##isa##_##name, argCount, false, false, false) // All of the HARDWARE_INTRINSICS for arm64 #include "hwintrinsiclistarm64.h" #define VNF_HWI_FIRST VNF_HWI_Vector64_AsByte diff --git a/src/coreclr/src/jit/vartype.h b/src/coreclr/src/jit/vartype.h index c6177a82707f70..e34ee7e5a8df8f 100644 --- a/src/coreclr/src/jit/vartype.h +++ b/src/coreclr/src/jit/vartype.h @@ -25,10 +25,7 @@ enum var_types : BYTE #define DEF_TP(tn, nm, jitType, verType, sz, sze, asze, st, al, tf, howUsed) TYP_##tn, #include "typelist.h" #undef DEF_TP - - TYP_COUNT, - - TYP_lastIntrins = TYP_DOUBLE + TYP_COUNT }; /***************************************************************************** @@ -116,6 +113,12 @@ inline bool varTypeIsUnsigned(T vt) return ((varTypeClassification[TypeGet(vt)] & (VTF_UNS)) != 0); } +template +inline bool varTypeIsSigned(T vt) +{ + return varTypeIsIntegralOrI(vt) && !varTypeIsUnsigned(vt); +} + // If "vt" is an unsigned integral type, returns the corresponding signed integral type, otherwise // return "vt". inline var_types varTypeUnsignedToSigned(var_types vt) @@ -143,6 +146,32 @@ inline var_types varTypeUnsignedToSigned(var_types vt) } } +// If "vt" is a signed integral type, returns the corresponding unsigned integral type, otherwise +// return "vt". +inline var_types varTypeSignedToUnsigned(var_types vt) +{ + if (varTypeIsSigned(vt)) + { + switch (vt) + { + case TYP_BYTE: + return TYP_UBYTE; + case TYP_SHORT: + return TYP_USHORT; + case TYP_INT: + return TYP_UINT; + case TYP_LONG: + return TYP_ULONG; + default: + unreached(); + } + } + else + { + return vt; + } +} + template inline bool varTypeIsFloating(T vt) { diff --git a/src/coreclr/src/libraries-native/entrypoints.c b/src/coreclr/src/libraries-native/entrypoints.c index 68553e99997af6..c0dc63961b9b4b 100644 --- a/src/coreclr/src/libraries-native/entrypoints.c +++ b/src/coreclr/src/libraries-native/entrypoints.c @@ -51,6 +51,7 @@ FCFuncStart(gPalGlobalizationNative) QCFuncElement("GetTimeZoneDisplayName", GlobalizationNative_GetTimeZoneDisplayName) QCFuncElement("IndexOf", GlobalizationNative_IndexOf) QCFuncElement("IndexOfOrdinalIgnoreCase", GlobalizationNative_IndexOfOrdinalIgnoreCase) + QCFuncElement("InitICUFunctions", GlobalizationNative_InitICUFunctions) QCFuncElement("IsNormalized", GlobalizationNative_IsNormalized) QCFuncElement("IsPredefinedLocale", GlobalizationNative_IsPredefinedLocale) QCFuncElement("LastIndexOf", GlobalizationNative_LastIndexOf) diff --git a/src/coreclr/src/md/compiler/classfactory.cpp b/src/coreclr/src/md/compiler/classfactory.cpp index 52b869e8cba0eb..57558219c570d4 100644 --- a/src/coreclr/src/md/compiler/classfactory.cpp +++ b/src/coreclr/src/md/compiler/classfactory.cpp @@ -24,9 +24,6 @@ #include "mscoree.h" #include "corhost.h" -#include - - //********** Locals. ********************************************************** HINSTANCE GetModuleInst(); diff --git a/src/coreclr/src/md/compiler/stdafx.h b/src/coreclr/src/md/compiler/stdafx.h index c1bff716e5ce1a..a73681d1c1e36e 100644 --- a/src/coreclr/src/md/compiler/stdafx.h +++ b/src/coreclr/src/md/compiler/stdafx.h @@ -19,6 +19,10 @@ #include #include +#include "../hotdata/hotheap.h" +#include +#include + #include "nsutilpriv.h" #include "utsem.h" diff --git a/src/coreclr/src/md/datasource/stdafx.h b/src/coreclr/src/md/datasource/stdafx.h index be8349da7690d7..61c738585e5df2 100644 --- a/src/coreclr/src/md/datasource/stdafx.h +++ b/src/coreclr/src/md/datasource/stdafx.h @@ -19,5 +19,8 @@ #include #include +#include +#include + #endif // __STDAFX_H_ diff --git a/src/coreclr/src/md/enc/CMakeLists.txt b/src/coreclr/src/md/enc/CMakeLists.txt index 7220736b9ca3c9..221bb8cab4557e 100644 --- a/src/coreclr/src/md/enc/CMakeLists.txt +++ b/src/coreclr/src/md/enc/CMakeLists.txt @@ -13,6 +13,7 @@ set(MDRUNTIMERW_SOURCES set(MDRUNTIMERW_HEADERS ../../inc/corhdr.h ../../inc/metadata.h + ../../inc/mdfileformat.h ../../inc/pedecoder.h ../../inc/pedecoder.inl ../../inc/posterror.h @@ -22,7 +23,6 @@ set(MDRUNTIMERW_HEADERS ../compiler/regmeta.h ../hotdata/hotdataformat.h ../inc/liteweightstgdb.h - ../inc/mdfileformat.h ../inc/mdinternalrw.h ../inc/mdlog.h ../inc/metadatahash.h diff --git a/src/coreclr/src/md/enc/stdafx.h b/src/coreclr/src/md/enc/stdafx.h index 7c92404eda7d68..ed91d0b3a6ce56 100644 --- a/src/coreclr/src/md/enc/stdafx.h +++ b/src/coreclr/src/md/enc/stdafx.h @@ -19,6 +19,11 @@ #include #include +#include "../hotdata/hotheap.h" +#include +#include + + #include "mdcommon.h" #include "utsem.h" diff --git a/src/coreclr/src/md/enc/stgtiggerstorage.cpp b/src/coreclr/src/md/enc/stgtiggerstorage.cpp index 699d7f1bf0cdbd..1dd1ed8662e2df 100644 --- a/src/coreclr/src/md/enc/stgtiggerstorage.cpp +++ b/src/coreclr/src/md/enc/stgtiggerstorage.cpp @@ -20,15 +20,7 @@ #include "posterror.h" #include "mdfileformat.h" #include "sstring.h" - -//#CLRRuntimeHostInternal_GetImageVersionString -// External implementation of call to code:ICLRRuntimeHostInternal::GetImageVersionString. -// Implemented in clr.dll and mscordbi.dll. -HRESULT -CLRRuntimeHostInternal_GetImageVersionString( - __out_ecount(*pcchBuffer) - LPWSTR wszBuffer, - DWORD * pcchBuffer); +#include "clrversion.h" TiggerStorage::TiggerStorage() : m_pStgIO(0), @@ -134,42 +126,7 @@ HRESULT TiggerStorage::GetDefaultVersion( LPCSTR *ppVersion) { - static LPSTR g_pDefaultVersion; - - if (g_pDefaultVersion == NULL) - { -#ifndef DACCESS_COMPILE - HRESULT hr; - - WCHAR wszVersion[_MAX_PATH]; - DWORD cchVersion = _MAX_PATH; - //#CallTo_CLRRuntimeHostInternal_GetImageVersionString - IfFailRet(CLRRuntimeHostInternal_GetImageVersionString(wszVersion, &cchVersion)); - - CHAR szVersion[_MAX_PATH]; - DWORD dwSize = WszWideCharToMultiByte(CP_UTF8, 0, wszVersion, -1, szVersion, _MAX_PATH, NULL, NULL); - if (dwSize == 0) - { - _ASSERTE_MSG(FALSE, "WideCharToMultiByte conversion failed"); - szVersion[0] = 0; - dwSize = 1; - } - - NewArrayHolder pVersion = new (nothrow) CHAR[dwSize]; - IfNullRet(pVersion); - - memcpy(pVersion, szVersion, dwSize); - - if (InterlockedCompareExchangeT(&g_pDefaultVersion, pVersion, NULL) == NULL) - { // We won the initialization race - pVersion.SuppressRelease(); - } -#else - DacNotImpl(); -#endif //DACCESS_COMPILE - } - - *ppVersion = g_pDefaultVersion; + *ppVersion = CLR_METADATA_VERSION; return S_OK; } // TiggerStorage::GetDefaultVersion diff --git a/src/coreclr/src/md/hotdata/CMakeLists.txt b/src/coreclr/src/md/hotdata/CMakeLists.txt index fdcf90aabc2acc..c6168d2a4b0c27 100644 --- a/src/coreclr/src/md/hotdata/CMakeLists.txt +++ b/src/coreclr/src/md/hotdata/CMakeLists.txt @@ -40,7 +40,7 @@ add_library_clr(mdhotdata_crossgen ${MDHOTDATA_SOURCES}) set_target_properties(mdhotdata_crossgen PROPERTIES CROSSGEN_COMPONENT TRUE) target_precompile_header(TARGET mdhotdata_crossgen HEADER external.h) -if(CLR_CMAKE_TARGET_WIN32) +if(CLR_CMAKE_HOST_WIN32) add_library_clr(mdhotdata-staticcrt ${MDHOTDATA_SOURCES}) target_precompile_header(TARGET mdhotdata-staticcrt HEADER external.h) -endif(CLR_CMAKE_TARGET_WIN32) +endif(CLR_CMAKE_HOST_WIN32) diff --git a/src/coreclr/src/md/inc/liteweightstgdb.h b/src/coreclr/src/md/inc/liteweightstgdb.h index 2e3ab202e0ff62..05fd5697a70464 100644 --- a/src/coreclr/src/md/inc/liteweightstgdb.h +++ b/src/coreclr/src/md/inc/liteweightstgdb.h @@ -13,6 +13,7 @@ #ifndef __LiteWeightStgdb_h__ #define __LiteWeightStgdb_h__ +#include "metadata.h" #include "metamodelro.h" #include "metamodelrw.h" diff --git a/src/coreclr/src/md/inc/metamodel.h b/src/coreclr/src/md/inc/metamodel.h index 31105c0397cd67..70402a027b704d 100644 --- a/src/coreclr/src/md/inc/metamodel.h +++ b/src/coreclr/src/md/inc/metamodel.h @@ -22,8 +22,6 @@ #include "../datablob.h" #include "../debug_metadata.h" -#undef __unaligned - #define ALLOCATED_MEMORY_MARKER 0xff // Version numbers for metadata format. diff --git a/src/coreclr/src/md/inc/metamodelrw.h b/src/coreclr/src/md/inc/metamodelrw.h index ab1019052d0419..322e280c69b021 100644 --- a/src/coreclr/src/md/inc/metamodelrw.h +++ b/src/coreclr/src/md/inc/metamodelrw.h @@ -204,37 +204,6 @@ class MDInternalRW; class CorProfileData; class UTSemReadWrite; -enum MetaDataReorderingOptions { - NoReordering=0x0, - ReArrangeStringPool=0x1 -}; - -#ifdef FEATURE_PREJIT - -// {0702E333-8D64-4ca7-B564-4AA56B1FCEA3} -EXTERN_GUID(IID_IMetaDataCorProfileData, 0x702e333, 0x8d64, 0x4ca7, 0xb5, 0x64, 0x4a, 0xa5, 0x6b, 0x1f, 0xce, 0xa3 ); - -#undef INTERFACE -#define INTERFACE IMetaDataCorProfileData -DECLARE_INTERFACE_(IMetaDataCorProfileData, IUnknown) -{ - STDMETHOD(SetCorProfileData)( - CorProfileData *pProfileData) PURE; // [IN] Pointer to profile data -}; - -// {2B464817-C0F6-454e-99E7-C352D8384D7B} -EXTERN_GUID(IID_IMDInternalMetadataReorderingOptions, 0x2B464817, 0xC0F6, 0x454e, 0x99, 0xE7, 0xC3, 0x52, 0xD8, 0x38, 0x4D, 0x7B ); - -#undef INTERFACE -#define INTERFACE IMDInternalMetadataReorderingOptions -DECLARE_INTERFACE_(IMDInternalMetadataReorderingOptions, IUnknown) -{ - STDMETHOD(SetMetaDataReorderingOptions)( - MetaDataReorderingOptions options) PURE; // [IN] metadata reordering options -}; - -#endif //FEATURE_PREJIT - template class CLiteWeightStgdb; //***************************************************************************** // Read/Write MiniMd. diff --git a/src/coreclr/src/md/runtime/CMakeLists.txt b/src/coreclr/src/md/runtime/CMakeLists.txt index 6dc193e14a7ddd..109b9f177d6577 100644 --- a/src/coreclr/src/md/runtime/CMakeLists.txt +++ b/src/coreclr/src/md/runtime/CMakeLists.txt @@ -18,6 +18,7 @@ set(MDRUNTIME_HEADERS ../../inc/corhlpr.h ../../inc/corpriv.h ../../inc/mdcommon.h + ../../inc/mdfileformat.h ../../inc/metadatatracker.h ../../inc/pedecoder.h ../../inc/posterror.h @@ -26,7 +27,6 @@ set(MDRUNTIME_HEADERS ../inc/assemblymdinternaldisp.h ../inc/liteweightstgdb.h ../inc/mdcolumndescriptors.h - ../inc/mdfileformat.h ../inc/metamodel.h ../inc/metamodelro.h ../inc/recordpool.h diff --git a/src/coreclr/src/md/runtime/mdinternaldisp.h b/src/coreclr/src/md/runtime/mdinternaldisp.h index 510e87351f3544..530a1419895654 100644 --- a/src/coreclr/src/md/runtime/mdinternaldisp.h +++ b/src/coreclr/src/md/runtime/mdinternaldisp.h @@ -16,7 +16,6 @@ #include "mdinternalro.h" - enum MDFileFormat { MDFormat_ReadOnly = 0, @@ -25,8 +24,6 @@ enum MDFileFormat MDFormat_Invalid = 3 }; - -HRESULT CheckFileFormat(LPVOID pData, ULONG cbData, MDFileFormat *pFormat); STDAPI GetMDInternalInterface( LPVOID pData, // [IN] Buffer with the metadata. ULONG cbData, // [IN] Size of the data in the buffer. @@ -34,11 +31,6 @@ STDAPI GetMDInternalInterface( REFIID riid, // [in] The interface desired. void **ppIUnk); // [out] Return interface on success. -HRESULT GetAssemblyMDInternalImportHelper(HCORMODULE hModule, - REFIID riid, - MDInternalImportFlags flags, - IUnknown **ppIUnk); - #endif //FEATURE_METADATA_INTERNAL_APIS #endif // __MDInternalDispenser__h__ diff --git a/src/coreclr/src/md/runtime/stdafx.h b/src/coreclr/src/md/runtime/stdafx.h index 088ecb1339945a..65decac1fdd54d 100644 --- a/src/coreclr/src/md/runtime/stdafx.h +++ b/src/coreclr/src/md/runtime/stdafx.h @@ -19,6 +19,10 @@ #include #include +#include "../hotdata/hotheap.h" +#include +#include + #include "mdcommon.h" #endif // __STDAFX_H_ diff --git a/src/coreclr/src/md/staticmd/apis.cpp b/src/coreclr/src/md/staticmd/apis.cpp index 21e784a41144d1..a9e66a7fa4e58e 100644 --- a/src/coreclr/src/md/staticmd/apis.cpp +++ b/src/coreclr/src/md/staticmd/apis.cpp @@ -13,7 +13,6 @@ #include "shimload.h" #include "metadataexports.h" #include "ex.h" -#include "product_version.h" // --------------------------------------------------------------------------- // %%Function: MetaDataGetDispenser @@ -126,79 +125,3 @@ STDAPI DLLEXPORT GetMetaDataPublicInterfaceFromInternal( END_ENTRYPOINT_NOTHROW; return hr; } - -// -// Returns version of the runtime (null-terminated). -// -// Arguments: -// pBuffer - [out] Output buffer allocated by caller of size cchBuffer. -// cchBuffer - Size of pBuffer in characters. -// pdwLength - [out] Size of the version string in characters (incl. null-terminator). Will be filled -// even if ERROR_INSUFFICIENT_BUFFER is returned. -// -// Return Value: -// S_OK - Output buffer contains the version string. -// HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) - *pdwLength contains required size of the buffer in -// characters. - -STDAPI GetCORVersionInternal( -__out_ecount_z_opt(cchBuffer) LPWSTR pBuffer, - DWORD cchBuffer, - __out DWORD *pdwLength) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - ENTRY_POINT; - PRECONDITION(CheckPointer(pBuffer, NULL_OK)); - PRECONDITION(CheckPointer(pdwLength)); - } CONTRACTL_END; - - HRESULT hr; - BEGIN_ENTRYPOINT_NOTHROW; - - if ((pBuffer != NULL) && (cchBuffer > 0)) - { // Initialize the output for case the function fails - *pBuffer = W('\0'); - } - -#define VERSION_NUMBER_NOSHIM W("v") QUOTE_MACRO_L(CLR_MAJOR_VERSION.CLR_MINOR_VERSION.CLR_BUILD_VERSION) - - DWORD length = (DWORD)(wcslen(VERSION_NUMBER_NOSHIM) + 1); - if (length > cchBuffer) - { - hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); - } - else - { - if (pBuffer == NULL) - { - hr = E_POINTER; - } - else - { - CopyMemory(pBuffer, VERSION_NUMBER_NOSHIM, length * sizeof(WCHAR)); - hr = S_OK; - } - } - *pdwLength = length; - - END_ENTRYPOINT_NOTHROW; - return hr; - -} - -// Replacement for legacy shim API GetCORRequiredVersion(...) used in linked libraries. -// Used in code:TiggerStorage::GetDefaultVersion#CallTo_CLRRuntimeHostInternal_GetImageVersionString. -HRESULT -CLRRuntimeHostInternal_GetImageVersionString( - __out_ecount_opt(*pcchBuffer) LPWSTR wszBuffer, - __inout DWORD *pcchBuffer) -{ - // Simply forward the call to the ICLRRuntimeHostInternal implementation. - STATIC_CONTRACT_WRAPPER; - - HRESULT hr = GetCORVersionInternal(wszBuffer, *pcchBuffer, pcchBuffer); - - return hr; -} // CLRRuntimeHostInternal_GetImageVersionString diff --git a/src/coreclr/src/md/winmd/adapter.cpp b/src/coreclr/src/md/winmd/adapter.cpp index da7cb9221d487f..61ae4f9bd4e235 100644 --- a/src/coreclr/src/md/winmd/adapter.cpp +++ b/src/coreclr/src/md/winmd/adapter.cpp @@ -5,15 +5,7 @@ #include "sigparser.h" #include "sigbuilder.h" #include "inc/adapter.h" - -//#CLRRuntimeHostInternal_GetImageVersionString -// External implementation of call to code:ICLRRuntimeHostInternal::GetImageVersionString. -// Implemented in clr.dll and mscordbi.dll. -HRESULT -CLRRuntimeHostInternal_GetImageVersionString( - __out_ecount(*pcchBuffer) - LPWSTR wszBuffer, - DWORD * pcchBuffer); +#include "clrversion.h" //---------------------------------------------------------------------------------------------------- // The name prefixes used by WinMD to hide/unhide WinRT and CLR versions of RuntimeClasses. @@ -131,11 +123,7 @@ HRESULT CheckIfWinMDAdapterNeeded(IMDCommon *pRawMDCommon) { pNewAdapter->m_scenario = kWinMDNormal; #ifndef DACCESS_COMPILE - WCHAR wszCorVersion[_MAX_PATH]; - DWORD cchWszCorVersion = _countof(wszCorVersion); - IfFailGo(CLRRuntimeHostInternal_GetImageVersionString (wszCorVersion, &cchWszCorVersion)); - MAKE_UTF8PTR_FROMWIDE_NOTHROW(szCorVersion, wszCorVersion); - IfNullGo(szCorVersion); + LPCSTR szCorVersion = CLR_METADATA_VERSION; size_t nch = strlen(szCorVersion) + 1; pNewAdapter->m_pRedirectedVersionString = new (nothrow) char[nch]; IfNullGo(pNewAdapter->m_pRedirectedVersionString); @@ -1175,10 +1163,10 @@ void WinMDAdapter::GetExtraAssemblyRefProps(FrameworkAssemblyIndex index, { ::memset(pContext, 0, sizeof(AssemblyMetaDataInternal)); - pContext->usMajorVersion = VER_ASSEMBLYMAJORVERSION; - pContext->usMinorVersion = VER_ASSEMBLYMINORVERSION; - pContext->usBuildNumber = VER_ASSEMBLYBUILD; - pContext->usRevisionNumber = VER_ASSEMBLYBUILD_QFE; + pContext->usMajorVersion = 4; + pContext->usMinorVersion = 0; + pContext->usBuildNumber = 0; + pContext->usRevisionNumber = 0; pContext->szLocale = ""; } diff --git a/src/coreclr/src/md/winmd/inc/adapter.h b/src/coreclr/src/md/winmd/inc/adapter.h index fdc13cb863e5bb..ef6306f7aa1246 100644 --- a/src/coreclr/src/md/winmd/inc/adapter.h +++ b/src/coreclr/src/md/winmd/inc/adapter.h @@ -224,17 +224,16 @@ class WinMDAdapter { _ASSERTE(TypeFromToken(mdar) == mdtAssemblyRef); - // The version of the mscorlib should be 4.0.0.0 if (m_assemblyRefMscorlib == mdar) { if (pusMajorVersion != nullptr) - *pusMajorVersion = VER_ASSEMBLYMAJORVERSION; + *pusMajorVersion = 4; if (pusMinorVersion != nullptr) - *pusMinorVersion = VER_ASSEMBLYMINORVERSION; + *pusMinorVersion = 0; if (pusBuildNumber != nullptr) - *pusBuildNumber = VER_ASSEMBLYBUILD; + *pusBuildNumber = 0; if (pusRevisionNumber != nullptr) - *pusRevisionNumber = VER_ASSEMBLYBUILD_QFE; + *pusRevisionNumber = 0; // Under CoreCLR, we replace the ECMA key in the mscorlib assembly ref with the CoreCLR platform public key token if (ppbPublicKeyOrToken != nullptr) @@ -279,13 +278,13 @@ class WinMDAdapter *pszName = GetExtraAssemblyRefName(mdar); if (pusMajorVersion != nullptr) - *pusMajorVersion = VER_ASSEMBLYMAJORVERSION; + *pusMajorVersion = 4; if (pusMinorVersion != nullptr) - *pusMinorVersion = VER_ASSEMBLYMINORVERSION; + *pusMinorVersion = 0; if (pusBuildNumber != nullptr) - *pusBuildNumber = VER_ASSEMBLYBUILD; + *pusBuildNumber = 0; if (pusRevisionNumber != nullptr) - *pusRevisionNumber = VER_ASSEMBLYBUILD_QFE; + *pusRevisionNumber = 0; if (ppbHashValue) *ppbHashValue = NULL; diff --git a/src/coreclr/src/md/winmd/stdafx.h b/src/coreclr/src/md/winmd/stdafx.h index 779c6ac1c4c607..32494eda0a29cf 100644 --- a/src/coreclr/src/md/winmd/stdafx.h +++ b/src/coreclr/src/md/winmd/stdafx.h @@ -19,9 +19,11 @@ #include #include -#include #include "nsutilpriv.h" #include "utsem.h" +#include +#include + #endif // __STDAFX_H_ diff --git a/src/coreclr/src/nativeresources/processrc.awk b/src/coreclr/src/nativeresources/processrc.awk index 4e6ad55c458711..f8eec8d091d928 100644 --- a/src/coreclr/src/nativeresources/processrc.awk +++ b/src/coreclr/src/nativeresources/processrc.awk @@ -51,7 +51,7 @@ BEGIN { var = var + 0; # Extract string content starting with either " or L" - idx = match($0, /L?\"/); + idx = match($0, /L?"/); content = substr($0, idx); # remove the L prefix from strings diff --git a/src/coreclr/src/pal/inc/pal.h b/src/coreclr/src/pal/inc/pal.h index 7926b2982322f2..7ffdc2b7ec3205 100644 --- a/src/coreclr/src/pal/inc/pal.h +++ b/src/coreclr/src/pal/inc/pal.h @@ -47,6 +47,9 @@ Module Name: #include #include #include +#include +#include +#include #endif #ifdef __cplusplus @@ -2365,6 +2368,8 @@ PALIMPORT BOOL PALAPI PAL_VirtualUnwindOutOfProc(CONTEXT *context, KNONVOLATILE_ #define PAL_CS_NATIVE_DATA_SIZE 56 #elif defined(__NetBSD__) && defined(__i386__) #define PAL_CS_NATIVE_DATA_SIZE 56 +#elif defined(__sun) && defined(__x86_64__) +#define PAL_CS_NATIVE_DATA_SIZE 48 #else #warning #error PAL_CS_NATIVE_DATA_SIZE is not defined for this architecture @@ -2541,6 +2546,7 @@ Abstract Parameters: IN hFile - The file to load + IN offset - offset within hFile where the PE "file" is located Return value: A valid base address if successful. @@ -2549,7 +2555,7 @@ Return value: PALIMPORT PVOID PALAPI -PAL_LOADLoadPEFile(HANDLE hFile); +PAL_LOADLoadPEFile(HANDLE hFile, size_t offset); /*++ PAL_LOADUnloadPEFile @@ -3935,7 +3941,11 @@ PALIMPORT int __cdecl memcmp(const void *, const void *, size_t); PALIMPORT void * __cdecl memset(void *, int, size_t); PALIMPORT void * __cdecl memmove(void *, const void *, size_t); PALIMPORT void * __cdecl memchr(const void *, int, size_t); -PALIMPORT long long int __cdecl atoll(const char *) THROW_DECL; +PALIMPORT long long int __cdecl atoll(const char *) +#ifndef __sun +THROW_DECL +#endif +; PALIMPORT size_t __cdecl strlen(const char *); PALIMPORT int __cdecl strcmp(const char*, const char *); PALIMPORT int __cdecl strncmp(const char*, const char *, size_t); @@ -4028,14 +4038,14 @@ PALIMPORT int __cdecl _wtoi(const WCHAR *); #ifdef __cplusplus extern "C++" { -inline WCHAR *PAL_wcschr(WCHAR *_S, WCHAR _C) - {return ((WCHAR *)PAL_wcschr((const WCHAR *)_S, _C)); } -inline WCHAR *PAL_wcsrchr(WCHAR *_S, WCHAR _C) - {return ((WCHAR *)PAL_wcsrchr((const WCHAR *)_S, _C)); } -inline WCHAR *PAL_wcspbrk(WCHAR *_S, const WCHAR *_P) - {return ((WCHAR *)PAL_wcspbrk((const WCHAR *)_S, _P)); } -inline WCHAR *PAL_wcsstr(WCHAR *_S, const WCHAR *_P) - {return ((WCHAR *)PAL_wcsstr((const WCHAR *)_S, _P)); } +inline WCHAR *PAL_wcschr(WCHAR* S, WCHAR C) + {return ((WCHAR *)PAL_wcschr((const WCHAR *)S, C)); } +inline WCHAR *PAL_wcsrchr(WCHAR* S, WCHAR C) + {return ((WCHAR *)PAL_wcsrchr((const WCHAR *)S, C)); } +inline WCHAR *PAL_wcspbrk(WCHAR* S, const WCHAR* P) + {return ((WCHAR *)PAL_wcspbrk((const WCHAR *)S, P)); } +inline WCHAR *PAL_wcsstr(WCHAR* S, const WCHAR* P) + {return ((WCHAR *)PAL_wcsstr((const WCHAR *)S, P)); } } #endif @@ -4107,9 +4117,17 @@ PALIMPORT double __cdecl acosh(double); PALIMPORT double __cdecl asin(double); PALIMPORT double __cdecl asinh(double); PALIMPORT double __cdecl atan(double) THROW_DECL; -PALIMPORT double __cdecl atanh(double) THROW_DECL; +PALIMPORT double __cdecl atanh(double) +#ifndef __sun +THROW_DECL +#endif +; PALIMPORT double __cdecl atan2(double, double); -PALIMPORT double __cdecl cbrt(double) THROW_DECL; +PALIMPORT double __cdecl cbrt(double) +#ifndef __sun +THROW_DECL +#endif +; PALIMPORT double __cdecl ceil(double); PALIMPORT double __cdecl cos(double); PALIMPORT double __cdecl cosh(double); @@ -4138,10 +4156,22 @@ PALIMPORT float __cdecl acosf(float); PALIMPORT float __cdecl acoshf(float); PALIMPORT float __cdecl asinf(float); PALIMPORT float __cdecl asinhf(float); -PALIMPORT float __cdecl atanf(float) THROW_DECL; -PALIMPORT float __cdecl atanhf(float) THROW_DECL; +PALIMPORT float __cdecl atanf(float) +#ifndef __sun +THROW_DECL +#endif +; +PALIMPORT float __cdecl atanhf(float) +#ifndef __sun +THROW_DECL +#endif +; PALIMPORT float __cdecl atan2f(float, float); -PALIMPORT float __cdecl cbrtf(float) THROW_DECL; +PALIMPORT float __cdecl cbrtf(float) +#ifndef __sun +THROW_DECL +#endif +; PALIMPORT float __cdecl ceilf(float); PALIMPORT float __cdecl cosf(float); PALIMPORT float __cdecl coshf(float); diff --git a/src/coreclr/src/pal/prebuilt/inc/asm_version.h b/src/coreclr/src/pal/prebuilt/inc/asm_version.h deleted file mode 100644 index 44e09c0e8e0d20..00000000000000 --- a/src/coreclr/src/pal/prebuilt/inc/asm_version.h +++ /dev/null @@ -1,22 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -#if defined(SILVERLIGHT) -#if defined(FEATURE_CORESYSTEM) -#define asm_rmj 4 -#define asm_rmm 0 -#define asm_rup 0 -#define asm_rpt 0 -#else -#define asm_rmj 5 -#define asm_rmm 0 -#define asm_rup 5 -#define asm_rpt 0 -#endif -#else -#define asm_rmj 4 -#define asm_rmm 0 -#define asm_rup 0 -#define asm_rpt 0 -#endif - diff --git a/src/coreclr/src/pal/prebuilt/inc/buildnumber.h b/src/coreclr/src/pal/prebuilt/inc/buildnumber.h deleted file mode 100644 index 5aee76ab5ed944..00000000000000 --- a/src/coreclr/src/pal/prebuilt/inc/buildnumber.h +++ /dev/null @@ -1,23 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#define BuildNumberMajor 30319 -#define BuildNumberMinor 0 -#define BuildNumberMajor_A "30319" -#define BuildNumberMinor_A "00" -#define BuildNumbers_A "30319.00" -#define BuildNumbers_T TEXT("30319.00") - -#define NDPBuildNumberMajor 30319 -#define NDPBuildNumberMinor 0 -#define NDPBuildNumbers_A "30319.00" -#define NDPBuildNumbers_T TEXT("30319.00") - -#define NDPFileVersionMinor 5 -#define NDPFileVersionBuild 30319 -#define NDPFileVersionRevision 0 - -#define NDPFileVersionMinor_A "5" -#define NDPFileVersionBuild_A "30319" -#define NDPFileVersionRevision_A "00" diff --git a/src/coreclr/src/pal/prebuilt/inc/cordebug.h b/src/coreclr/src/pal/prebuilt/inc/cordebug.h index 96dc9c0eb19260..69c897575113fe 100644 --- a/src/coreclr/src/pal/prebuilt/inc/cordebug.h +++ b/src/coreclr/src/pal/prebuilt/inc/cordebug.h @@ -6376,7 +6376,8 @@ enum CorGCReferenceType CorHandleStrongDependent = ( 1 << 6 ) , CorHandleStrongAsyncPinned = ( 1 << 7 ) , CorHandleStrongSizedByref = ( 1 << 8 ) , - CorHandleWeakWinRT = ( 1 << 9 ) , + CorHandleWeakNativeCom = ( 1 << 9 ) , + CorHandleWeakWinRT = CorHandleWeakNativeCom, CorReferenceStack = 0x80000001, CorReferenceFinalizer = 80000002, CorHandleStrongOnly = 0x1e3, diff --git a/src/coreclr/src/pal/prebuilt/inc/fxver.h b/src/coreclr/src/pal/prebuilt/inc/fxver.h index 95ccbc63352ce0..7e2a3224b8883f 100644 --- a/src/coreclr/src/pal/prebuilt/inc/fxver.h +++ b/src/coreclr/src/pal/prebuilt/inc/fxver.h @@ -2,202 +2,28 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// -// Insert just the #defines in winver.h, so that the -// C# compiler can include this file after macro preprocessing. -// - -#ifdef __cplusplus -#ifndef FXVER_H_ -#define FXVER_H_ -#define INCLUDE_FXVER_H -#endif -#else -#define RC_INVOKED 1 -#define INCLUDE_FXVER_H -#endif - -#ifdef INCLUDE_FXVER_H -#undef INCLUDE_FXVER_H - -#ifndef RC_INVOKED -#define FXVER_H_RC_INVOKED_ENABLED -#define RC_INVOKED 1 -#endif - #include -#ifdef FXVER_H_RC_INVOKED_ENABLED -#undef RC_INVOKED -#undef FXVER_H_RC_INVOKED_ENABLED -#endif - -// -// Include the definitions for rmj, rmm, rup, rpt -// - -#include - -/* - * Product version, name and copyright - */ +#define QUOTE_MACRO_HELPER(x) #x +#define QUOTE_MACRO(x) QUOTE_MACRO_HELPER(x) -#include "fxverstrings.h" +#define VER_PRODUCTNAME_STR L"Microsoft\256 .NET" -/* - * File version, names, description. - */ - -// FX_VER_INTERNALNAME_STR is passed in by the build environment. -#ifndef FX_VER_INTERNALNAME_STR -#define FX_VER_INTERNALNAME_STR UNKNOWN_FILE -#endif #define VER_INTERNALNAME_STR QUOTE_MACRO(FX_VER_INTERNALNAME_STR) #define VER_ORIGINALFILENAME_STR QUOTE_MACRO(FX_VER_INTERNALNAME_STR) -// FX_VER_FILEDESCRIPTION_STR is defined in RC files that include fxver.h - -#ifndef FX_VER_FILEDESCRIPTION_STR -#define FX_VER_FILEDESCRIPTION_STR QUOTE_MACRO(FX_VER_INTERNALNAME_STR) -#endif - #define VER_FILEDESCRIPTION_STR FX_VER_FILEDESCRIPTION_STR -#ifndef FX_VER_FILEVERSION_STR -#define FX_VER_FILEVERSION_STR FX_FILEVERSION_STR -#endif - -#define VER_FILEVERSION_STR FX_VER_FILEVERSION_STR -#define VER_FILEVERSION_STR_L VER_PRODUCTVERSION_STR_L - -#ifndef FX_VER_FILEVERSION -#define FX_VER_FILEVERSION VER_DOTFILEVERSION -#endif - -#define VER_FILEVERSION FX_VER_FILEVERSION - -//URT_VFT passed in by the build environment. -#ifndef FX_VFT -#define FX_VFT VFT_UNKNOWN -#endif - -#define VER_FILETYPE FX_VFT -#define VER_FILESUBTYPE VFT2_UNKNOWN - -/* default is nodebug */ -#if DBG -#define VER_DEBUG VS_FF_DEBUG -#else -#define VER_DEBUG 0 -#endif - -#define VER_PRERELEASE 0 - -#define EXPORT_TAG - -// Not setting the private build flag until -// official builds can be detected from native projects -//#if OFFICIAL_BUILD -#define VER_PRIVATE 0 -//#else -//#define VER_PRIVATE VS_FF_PRIVATEBUILD -//#endif - -#define VER_SPECIALBUILD 0 +#define VER_COMMENTS_STR "Flavor=" QUOTE_MACRO(URTBLDENV_FRIENDLY) #define VER_FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#define VER_FILEFLAGS (VER_PRERELEASE|VER_DEBUG|VER_PRIVATE|VER_SPECIALBUILD) +#define VER_FILEFLAGS VER_DEBUG #define VER_FILEOS VOS__WINDOWS32 -#define VER_COMPANYNAME_STR "Microsoft Corporation" +#define VER_FILETYPE VFT_UNKNOWN +#define VER_FILESUBTYPE VFT2_UNKNOWN -#ifdef VER_LANGNEUTRAL -#define VER_VERSION_UNICODE_LANG "000004B0" /* LANG_NEUTRAL/SUBLANG_NEUTRAL, Unicode CP */ -#define VER_VERSION_ANSI_LANG "000004E4" /* LANG_NEUTRAL/SUBLANG_NEUTRAL, Ansi CP */ -#define VER_VERSION_TRANSLATION 0x0000, 0x04B0 -#else #define VER_VERSION_UNICODE_LANG "040904B0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */ #define VER_VERSION_ANSI_LANG "040904E4" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Ansi CP */ #define VER_VERSION_TRANSLATION 0x0409, 0x04B0 -#endif - -#if defined(CSC_INVOKED) -#define VER_COMMENTS_STR "Flavor=" + QUOTE_MACRO(URTBLDENV_FRIENDLY) -#else -#define VER_COMMENTS_STR "Flavor=" QUOTE_MACRO(URTBLDENV_FRIENDLY) -#endif - -#if defined(__BUILDMACHINE__) -#if defined(__BUILDDATE__) -#define B2(x,y) " (" #x "." #y ")" -#define B1(x,y) B2(x, y) -#define BUILD_MACHINE_TAG B1(__BUILDMACHINE__, __BUILDDATE__) -#else -#define B2(x) " built by: " #x -#define B1(x) B2(x) -#define BUILD_MACHINE_TAG B1(__BUILDMACHINE__) -#endif -#if defined(__BUILDMACHINE_LEN__) -#if __BUILDMACHINE_LEN__ >= 25 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG -#elif __BUILDMACHINE_LEN__ == 24 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 23 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 22 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 21 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 20 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 19 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 18 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 17 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 16 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 15 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 14 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 13 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 12 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 11 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 10 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 9 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 8 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 7 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 6 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 5 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 4 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 3 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 2 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#elif __BUILDMACHINE_LEN__ == 1 -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " " -#else -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG -#endif -#else -#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG -#endif -#else -#define BUILD_MACHINE_TAG -#define BUILD_MACHINE_TAG_PADDED -#endif - -#endif diff --git a/src/coreclr/src/pal/prebuilt/inc/fxver.rc b/src/coreclr/src/pal/prebuilt/inc/fxver.rc index ab037e78de7d38..8f8637ffc9e8fd 100644 --- a/src/coreclr/src/pal/prebuilt/inc/fxver.rc +++ b/src/coreclr/src/pal/prebuilt/inc/fxver.rc @@ -2,35 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -/*---------------------------------------------------------------*/ -/* */ -/* The following section actually creates the version structure. */ -/* They are ignored if we are not being invoked by RC. */ -/* */ -/* ntverp.H must be included before including this file */ -/* */ -/* If VER_LEGALCOPYRIGHT_STR is not defined, it will be */ -/* constructed using VER_LEGALCOPYRIGHT_YEARS, so at least one */ -/* these macros must be defined before including this file. */ -/* */ -/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR, and */ -/* VER_INTERNALNAME_STR must be defined before including this */ -/* file. */ -/* */ -/* If VER_FILEVERSION is not defined, VER_PRODUCTVERSION will be */ -/* used instead. If VER_FILEVERSION_STR is not defined, */ -/* VER_PRODUCTVERSION_STR will be used instead. */ -/* */ -/* If VER_ORIGINALFILENAME_STR is not defined, it is set to */ -/* the value in VER_INTERNALNAME_STR. */ -/* */ -/* If INTL is defined, then this is assumed to be an */ -/* an international build; two string blocks will be created, */ -/* (since all version resources must have English), and the */ -/* second one can be localized */ -/* */ -/*---------------------------------------------------------------*/ - #ifdef _WIN32 #include <_version.h> #endif //_WIN32 @@ -51,44 +22,15 @@ BEGIN BLOCK VER_VERSION_UNICODE_LANG BEGIN VALUE "CompanyName", VER_COMPANYNAME_STR - VALUE "FileDescription", VER_FILEDESCRIPTION_STR EXPORT_TAG - VALUE "FileVersion", VER_FILEVERSION_STR BUILD_MACHINE_TAG_PADDED - VALUE "InternalName", VER_INTERNALNAME_STR - VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR - VALUE "OriginalFilename",VER_ORIGINALFILENAME_STR - VALUE "ProductName", VER_PRODUCTNAME_STR - VALUE "ProductVersion", VER_FILEVERSION_STR -#ifdef VER_OLESELFREGISTER - VALUE "OleSelfRegister", "\0" -#endif - VALUE "Comments", VER_COMMENTS_STR -#ifdef VER_EXTRA_VALUES - VER_EXTRA_VALUES -#endif - - END - - -#ifdef VER_ANSICP /* Some apps are hard coded to look for ANSI CP. */ - BLOCK VER_VERSION_ANSI_LANG - BEGIN - VALUE "CompanyName", VER_COMPANYNAME_STR - VALUE "FileDescription", VER_FILEDESCRIPTION_STR EXPORT_TAG + VALUE "FileDescription", VER_FILEDESCRIPTION_STR VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", VER_INTERNALNAME_STR VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR VALUE "OriginalFilename",VER_ORIGINALFILENAME_STR VALUE "ProductName", VER_PRODUCTNAME_STR VALUE "ProductVersion", VER_FILEVERSION_STR -#ifdef VER_OLESELFREGISTER - VALUE "OleSelfRegister", "\0" -#endif VALUE "Comments", VER_COMMENTS_STR -#ifdef VER_EXTRA_VALUES - VER_EXTRA_VALUES -#endif END -#endif END BLOCK "VarFileInfo" diff --git a/src/coreclr/src/pal/prebuilt/inc/fxverstrings.h b/src/coreclr/src/pal/prebuilt/inc/fxverstrings.h deleted file mode 100644 index efb03af2f52cf0..00000000000000 --- a/src/coreclr/src/pal/prebuilt/inc/fxverstrings.h +++ /dev/null @@ -1,17 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#ifndef VER_PRODUCTNAME_STR - #define VER_PRODUCTNAME_STR L"Microsoft\256 .NET" -#endif - -#ifndef VER_LEGALCOPYRIGHT_STR - #define VER_LEGALCOPYRIGHT_STR "\251 Microsoft Corporation. All rights reserved." - #define VER_LEGALCOPYRIGHT_STR_L L"\251 Microsoft Corporation. All rights reserved." -#endif - -#ifndef VER_LEGALCOPYRIGHT_LOGO_STR - #define VER_LEGALCOPYRIGHT_LOGO_STR "Copyright (c) Microsoft Corporation. All rights reserved." - #define VER_LEGALCOPYRIGHT_LOGO_STR_L L"Copyright (c) Microsoft Corporation. All rights reserved." -#endif diff --git a/src/coreclr/src/pal/prebuilt/inc/mscoree.h b/src/coreclr/src/pal/prebuilt/inc/mscoree.h index 2d83809685411e..4f5c5b81977201 100644 --- a/src/coreclr/src/pal/prebuilt/inc/mscoree.h +++ b/src/coreclr/src/pal/prebuilt/inc/mscoree.h @@ -164,56 +164,6 @@ typedef struct _BucketParameters WCHAR pszParams[ 10 ][ 255 ]; } BucketParameters; -typedef /* [public] */ -enum __MIDL___MIDL_itf_mscoree_0000_0000_0006 - { - OPR_ThreadAbort = 0, - OPR_ThreadRudeAbortInNonCriticalRegion = ( OPR_ThreadAbort + 1 ) , - OPR_ThreadRudeAbortInCriticalRegion = ( OPR_ThreadRudeAbortInNonCriticalRegion + 1 ) , - OPR_AppDomainUnload = ( OPR_ThreadRudeAbortInCriticalRegion + 1 ) , - OPR_AppDomainRudeUnload = ( OPR_AppDomainUnload + 1 ) , - OPR_ProcessExit = ( OPR_AppDomainRudeUnload + 1 ) , - OPR_FinalizerRun = ( OPR_ProcessExit + 1 ) , - MaxClrOperation = ( OPR_FinalizerRun + 1 ) - } EClrOperation; - -typedef /* [public] */ -enum __MIDL___MIDL_itf_mscoree_0000_0000_0007 - { - FAIL_NonCriticalResource = 0, - FAIL_CriticalResource = ( FAIL_NonCriticalResource + 1 ) , - FAIL_FatalRuntime = ( FAIL_CriticalResource + 1 ) , - FAIL_OrphanedLock = ( FAIL_FatalRuntime + 1 ) , - FAIL_StackOverflow = ( FAIL_OrphanedLock + 1 ) , - FAIL_AccessViolation = ( FAIL_StackOverflow + 1 ) , - FAIL_CodeContract = ( FAIL_AccessViolation + 1 ) , - MaxClrFailure = ( FAIL_CodeContract + 1 ) - } EClrFailure; - -typedef /* [public] */ -enum __MIDL___MIDL_itf_mscoree_0000_0000_0008 - { - eRuntimeDeterminedPolicy = 0, - eHostDeterminedPolicy = ( eRuntimeDeterminedPolicy + 1 ) - } EClrUnhandledException; - -typedef /* [public] */ -enum __MIDL___MIDL_itf_mscoree_0000_0000_0009 - { - eNoAction = 0, - eThrowException = ( eNoAction + 1 ) , - eAbortThread = ( eThrowException + 1 ) , - eRudeAbortThread = ( eAbortThread + 1 ) , - eUnloadAppDomain = ( eRudeAbortThread + 1 ) , - eRudeUnloadAppDomain = ( eUnloadAppDomain + 1 ) , - eExitProcess = ( eRudeUnloadAppDomain + 1 ) , - eFastExitProcess = ( eExitProcess + 1 ) , - eRudeExitProcess = ( eFastExitProcess + 1 ) , - MaxPolicyAction = (eRudeExitProcess + 1 ) - } EPolicyAction; - - - extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0000_v0_0_c_ifspec; extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0000_v0_0_s_ifspec; diff --git a/src/coreclr/src/pal/prebuilt/inc/ndpversion.h b/src/coreclr/src/pal/prebuilt/inc/ndpversion.h deleted file mode 100644 index ba6d018266a04b..00000000000000 --- a/src/coreclr/src/pal/prebuilt/inc/ndpversion.h +++ /dev/null @@ -1,4 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -#include diff --git a/src/coreclr/src/pal/prebuilt/inc/ndpversion_generated.h b/src/coreclr/src/pal/prebuilt/inc/ndpversion_generated.h deleted file mode 100644 index 563e3169714f2f..00000000000000 --- a/src/coreclr/src/pal/prebuilt/inc/ndpversion_generated.h +++ /dev/null @@ -1,15 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#if 0 -/**** Generated Based on d:\ProjectK\src\InternalApis\Version\buildnumber.settings.targets -One can't put comments in this file (without the #if) -because this header is preprocessed in non-C++ context (xml, perl, etc.). *****/ -#endif -#define NDPVersionNumberMajor 4 -#define NDPVersionNumberMinor 0 -#define NDPVersionNumberMajor_A "4" -#define NDPVersionNumberMinor_A "00" -#define NDPVersionNumbers_A "4.00" -#include "buildnumber.h" diff --git a/src/coreclr/src/pal/prebuilt/inc/product_version.h b/src/coreclr/src/pal/prebuilt/inc/product_version.h deleted file mode 100644 index a21ee687416afb..00000000000000 --- a/src/coreclr/src/pal/prebuilt/inc/product_version.h +++ /dev/null @@ -1,113 +0,0 @@ - -#if 0 - Version strings for product keys... no comments can be allowed in this - file due to some usage of this in the build process. - // Licensed to the .NET Foundation under one or more agreements. - // The .NET Foundation licenses this file to you under the MIT license. - // See the LICENSE file in the project root for more information. -#endif - -#include -#ifdef USE_CLR20_VERSION -#include -#else -#include -#endif - -#ifdef CLR_MAJOR_VERSION -#undef CLR_MAJOR_VERSION -#endif - -#ifdef CLR_MINOR_VERSION -#undef CLR_MINOR_VERSION -#endif - -#ifdef CLR_BUILD_VERSION -#undef CLR_BUILD_VERSION -#endif - -#ifdef CLR_BUILD_VERSION_QFE -#undef CLR_BUILD_VERSION_QFE -#endif - -#ifdef VER_FILEVERSIONMINOR -#undef VER_FILEVERSIONMINOR -#endif - -#ifdef VER_FILEVERSIONBUILD -#undef VER_FILEVERSIONBUILD -#endif - -#ifdef VER_FILEVERSIONREVISION -#undef VER_FILEVERSIONREVISION -#endif - -#define CLR_MAJOR_VERSION rmj -#define CLR_MINOR_VERSION rmm -#define CLR_BUILD_VERSION rup -#define CLR_BUILD_VERSION_QFE rpt - -#define VER_FILEVERSIONMINOR fvn -#define VER_FILEVERSIONBUILD fvb -#define VER_FILEVERSIONREVISION fvr - -#define VER_ASSEMBLYMAJORVERSION asm_rmj -#define VER_ASSEMBLYMINORVERSION asm_rmm -#define VER_ASSEMBLYBUILD asm_rup -#define VER_ASSEMBLYBUILD_QFE asm_rpt - -#define QUOTE_MACRO_HELPER(x) #x -#define QUOTE_MACRO(x) QUOTE_MACRO_HELPER(x) - -#ifndef QUOTE_MACRO_L -#define QUOTE_MACRO_L_HELPER(x) L###x -#define QUOTE_MACRO_L(x) QUOTE_MACRO_L_HELPER(x) -#endif - -#define CONCAT_MACRO_HELPER(x, y) x ## y -#define CONCAT_MACRO(x, y) CONCAT_MACRO_HELPER(x, y) - -#define VER_PRODUCTVERSION CLR_MAJOR_VERSION,CLR_MINOR_VERSION,CLR_BUILD_VERSION,CLR_BUILD_VERSION_QFE -#define VER_DOTFILEVERSION CLR_MAJOR_VERSION,VER_FILEVERSIONMINOR,VER_FILEVERSIONBUILD,VER_FILEVERSIONREVISION -#define VER_MANAGED_DOTFILEVERSION CLR_MAJOR_VERSION.VER_FILEVERSIONMINOR.VER_FILEVERSIONBUILD.VER_FILEVERSIONREVISION - -#define VER_DOTPRODUCTVERSION CLR_MAJOR_VERSION.CLR_MINOR_VERSION.CLR_BUILD_VERSION.CLR_BUILD_VERSION_QFE -#define VER_DOTPRODUCTMAJORMINOR CLR_MAJOR_VERSION.CLR_MINOR_VERSION -#define VER_DOTPRODUCTVERSIONNOQFE CLR_MAJOR_VERSION.CLR_MINOR_VERSION.CLR_BUILD_VERSION -#define VER_DOTPRODUCTVERSIONZEROQFE CLR_MAJOR_VERSION.CLR_MINOR_VERSION.CLR_BUILD_VERSION.0 -#define VER_DOTASSEMBLYVERSION VER_ASSEMBLYMAJORVERSION.VER_ASSEMBLYMINORVERSION.VER_ASSEMBLYBUILD.VER_ASSEMBLYBUILD_QFE -#define VER_DOTASSEMBLYVERSION3PART VER_ASSEMBLYMAJORVERSION.VER_ASSEMBLYMINORVERSION.VER_ASSEMBLYBUILD - -#define VER_UNDERSCORE_PRODUCTVERSION_STR3 CONCAT_MACRO(_, CLR_BUILD_VERSION) -#define VER_UNDERSCORE_PRODUCTVERSION_STR2 CONCAT_MACRO(CLR_MINOR_VERSION, VER_UNDERSCORE_PRODUCTVERSION_STR3) -#define VER_UNDERSCORE_PRODUCTVERSION_STR1 CONCAT_MACRO(_, VER_UNDERSCORE_PRODUCTVERSION_STR2) -#define VER_UNDERSCORE_PRODUCTVERSION CONCAT_MACRO(CLR_MAJOR_VERSION, VER_UNDERSCORE_PRODUCTVERSION_STR1) - -#define VER_UNDERSCORE_PRODUCTVERSION_STR QUOTE_MACRO(VER_UNDERSCORE_PRODUCTVERSION) -#define VER_UNDERSCORE_PRODUCTVERSION_STR_L QUOTE_MACRO_L(VER_UNDERSCORE_PRODUCTVERSION) - -#define FX_FILEVERSION_STR QUOTE_MACRO(VER_MANAGED_DOTFILEVERSION) -#define VER_PRODUCTVERSION_STR QUOTE_MACRO(VER_DOTPRODUCTVERSION) -#define VER_PRODUCTVERSION_STR_L QUOTE_MACRO_L(VER_DOTPRODUCTVERSION) - -#define VER_PRODUCTMAJORMINOR_STR QUOTE_MACRO(VER_DOTPRODUCTMAJORMINOR) -#define VER_PRODUCTMAJORMINOR_STR_L QUOTE_MACRO_L(VER_DOTPRODUCTMAJORMINOR) - -#define VER_PRODUCTVERSION_NO_QFE_STR QUOTE_MACRO(VER_DOTPRODUCTVERSIONNOQFE) -#define VER_PRODUCTVERSION_NO_QFE_STR_L QUOTE_MACRO_L(VER_DOTPRODUCTVERSIONNOQFE) - -#define VER_PRODUCTVERSION_ZERO_QFE_STR QUOTE_MACRO(VER_DOTPRODUCTVERSIONZEROQFE) -#define VER_PRODUCTVERSION_ZERO_QFE_STR_L QUOTE_MACRO_L(VER_DOTPRODUCTVERSIONZEROQFE) - -#define VER_PRODUCTVERSION_NO_QFE_STR QUOTE_MACRO(VER_DOTPRODUCTVERSIONNOQFE) -#define VER_PRODUCTVERSION_NO_QFE_STR_L QUOTE_MACRO_L(VER_DOTPRODUCTVERSIONNOQFE) - -#define VER_ASSEMBLYVERSION_STR QUOTE_MACRO(VER_DOTASSEMBLYVERSION) -#define VER_ASSEMBLYVERSION_STR_L QUOTE_MACRO_L(VER_DOTASSEMBLYVERSION) - -#define VER_ASSEMBLYVERSION3PART_STR QUOTE_MACRO(VER_DOTASSEMBLYVERSION3PART) -#define VER_ASSEMBLYVERSION3PART_STR_L QUOTE_MACRO_L(VER_DOTASSEMBLYVERSION3PART) - -#define VER_ECMA_PUBLICKEY b77a5c561934e089 -#define ECMA_PUBLICKEY_STR QUOTE_MACRO(VER_ECMA_PUBLICKEY) -#define ECMA_PUBLICKEY_STR_L QUOTE_MACRO_L(VER_ECMA_PUBLICKEY) diff --git a/src/coreclr/src/pal/prebuilt/inc/version.h b/src/coreclr/src/pal/prebuilt/inc/version.h deleted file mode 100644 index a6de92ca95e04f..00000000000000 --- a/src/coreclr/src/pal/prebuilt/inc/version.h +++ /dev/null @@ -1,17 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#include - -#define rmj NDPVersionNumberMajor -#define rmm NDPVersionNumberMinor -#define rup NDPBuildNumberMajor -#define rpt NDPBuildNumberMinor - -#define fvn NDPFileVersionMinor -#define fvb NDPFileVersionBuild -#define fvr NDPFileVersionRevision - -#define szVerName "" -#define szVerUser "" diff --git a/src/coreclr/src/pal/src/CMakeLists.txt b/src/coreclr/src/pal/src/CMakeLists.txt index e7c1629d5b263f..1a393638322856 100644 --- a/src/coreclr/src/pal/src/CMakeLists.txt +++ b/src/coreclr/src/pal/src/CMakeLists.txt @@ -113,7 +113,7 @@ set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -Wl,--no if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") add_compile_options(-Wno-unused-result) -endif() +endif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") set(ARCH_SOURCES arch/${PAL_ARCH_SOURCES_DIR}/context2.S @@ -135,6 +135,10 @@ if(CLR_CMAKE_HOST_ARCH_ARM) endif() endif(CLR_CMAKE_HOST_ARCH_ARM) +if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") + add_compile_options(-Wa,--divide) +endif() + set(SOURCES cruntime/file.cpp cruntime/filecrt.cpp @@ -321,6 +325,13 @@ if(CLR_CMAKE_TARGET_NETBSD) ) endif(CLR_CMAKE_TARGET_NETBSD) +if(CLR_CMAKE_TARGET_SUNOS) + target_link_libraries(coreclrpal + pthread + rt + ) +endif(CLR_CMAKE_TARGET_SUNOS) + if(FEATURE_EVENT_TRACE) add_subdirectory(eventprovider) endif(FEATURE_EVENT_TRACE) diff --git a/src/coreclr/src/pal/src/config.h.in b/src/coreclr/src/pal/src/config.h.in index ddf6ffc5a1a469..8e7e69288bc9e3 100644 --- a/src/coreclr/src/pal/src/config.h.in +++ b/src/coreclr/src/pal/src/config.h.in @@ -23,6 +23,7 @@ #cmakedefine01 HAVE_NUMA_H #cmakedefine01 HAVE_PTHREAD_NP_H #cmakedefine01 HAVE_AUXV_HWCAP_H +#cmakedefine01 HAVE_SYS_PTRACE_H #cmakedefine01 HAVE_KQUEUE #cmakedefine01 HAVE_PTHREAD_SUSPEND @@ -51,12 +52,14 @@ #cmakedefine01 HAVE_TIMEGM #cmakedefine01 HAVE_POLL #cmakedefine01 HAVE_STATVFS +#cmakedefine01 HAVE_NON_LEGACY_STATFS #cmakedefine01 HAVE_THREAD_SELF #cmakedefine01 HAVE__LWP_SELF #cmakedefine01 HAVE_MACH_THREADS #cmakedefine01 HAVE_MACH_EXCEPTIONS #cmakedefine01 HAVE_VM_ALLOCATE #cmakedefine01 HAVE_VM_READ +#cmakedefine01 HAVE_DIRECTIO #cmakedefine01 HAVE_SEMAPHORE_H #cmakedefine01 HAS_SYSV_SEMAPHORES #cmakedefine01 HAS_PTHREAD_MUTEXES @@ -70,6 +73,7 @@ #cmakedefine01 HAVE_PUBLIC_XSTATE_STRUCT #cmakedefine01 HAVE__FPX_SW_BYTES_WITH_XSTATE_BV #cmakedefine01 HAVE_PR_SET_PTRACER +#cmakedefine01 HAVE_SWAPCTL #cmakedefine01 HAVE_STAT_TIMESPEC #cmakedefine01 HAVE_STAT_TIM @@ -85,6 +89,8 @@ #cmakedefine01 HAVE_PTHREAD_RWLOCK_T #cmakedefine01 HAVE_PRWATCH_T #cmakedefine SIZEOF_OFF_T @SIZEOF_OFF_T@ +#cmakedefine01 HAVE_DIRENT_D_TYPE +#cmakedefine01 HAVE_FPREGS_WITH_CW #cmakedefine01 HAVE_YIELD_SYSCALL #cmakedefine01 HAVE_INFTIM @@ -110,7 +116,6 @@ #cmakedefine01 HAVE_MACH_ABSOLUTE_TIME #cmakedefine01 HAVE_CLOCK_THREAD_CPUTIME #cmakedefine01 HAVE_PTHREAD_CONDATTR_SETCLOCK -#cmakedefine01 STATVFS64_PROTOTYPE_BROKEN #cmakedefine01 HAVE_MMAP_DEV_ZERO #cmakedefine01 MMAP_ANON_IGNORES_PROTECTION #cmakedefine01 ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS diff --git a/src/coreclr/src/pal/src/configure.cmake b/src/coreclr/src/pal/src/configure.cmake index 62e5690af32037..b67637b584ba69 100644 --- a/src/coreclr/src/pal/src/configure.cmake +++ b/src/coreclr/src/pal/src/configure.cmake @@ -2,6 +2,7 @@ include(CheckCXXSourceCompiles) include(CheckCXXSourceRuns) include(CheckCXXSymbolExists) include(CheckFunctionExists) +include(CheckPrototypeDefinition) include(CheckIncludeFiles) include(CheckStructHasMember) include(CheckTypeSize) @@ -45,6 +46,7 @@ check_include_files(sys/prctl.h HAVE_PRCTL_H) check_include_files(numa.h HAVE_NUMA_H) check_include_files(pthread_np.h HAVE_PTHREAD_NP_H) check_include_files("sys/auxv.h;asm/hwcap.h" HAVE_AUXV_HWCAP_H) +check_include_files("sys/ptrace.h" HAVE_SYS_PTRACE_H) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_DL_LIBS}) @@ -143,6 +145,8 @@ check_struct_has_member ("ucontext_t" uc_mcontext.gregs[0] ucontext.h HAVE_GREGS check_struct_has_member ("ucontext_t" uc_mcontext.__gregs[0] ucontext.h HAVE___GREGSET_T) check_struct_has_member ("ucontext_t" uc_mcontext.fpregs->__glibc_reserved1[0] ucontext.h HAVE_FPSTATE_GLIBC_RESERVED1) check_struct_has_member ("struct sysinfo" mem_unit "sys/sysinfo.h" HAVE_SYSINFO_WITH_MEM_UNIT) +check_struct_has_member ("struct dirent" d_type dirent.h HAVE_DIRENT_D_TYPE) +check_struct_has_member ("struct _fpchip_state" cw sys/ucontext.h HAVE_FPREGS_WITH_CW) set(CMAKE_EXTRA_INCLUDE_FILES machine/reg.h) check_type_size("struct reg" BSD_REGS_T) @@ -169,6 +173,7 @@ check_cxx_symbol_exists(CHAR_BIT limits.h HAVE_CHAR_BIT) check_cxx_symbol_exists(_DEBUG sys/user.h USER_H_DEFINES_DEBUG) check_cxx_symbol_exists(_SC_PHYS_PAGES unistd.h HAVE__SC_PHYS_PAGES) check_cxx_symbol_exists(_SC_AVPHYS_PAGES unistd.h HAVE__SC_AVPHYS_PAGES) +check_cxx_symbol_exists(swapctl sys/swap.h HAVE_SWAPCTL) check_cxx_source_runs(" #include @@ -729,7 +734,8 @@ check_cxx_source_runs(" #include int main(void) { - if (!isnan(acos(10))) { + volatile double x = 10; + if (!isnan(acos(x))) { exit(1); } exit(0); @@ -741,7 +747,8 @@ check_cxx_source_runs(" #include int main(void) { - if (!isnan(asin(10))) { + volatile double arg = 10; + if (!isnan(asin(arg))) { exit(1); } exit(0); @@ -753,29 +760,37 @@ check_cxx_source_runs(" #include int main(void) { - double infinity = 1.0 / 0.0; - if (pow(1.0, infinity) != 1.0 || pow(1.0, -infinity) != 1.0) { + volatile double base = 1.0; + volatile double infinity = 1.0 / 0.0; + if (pow(base, infinity) != 1.0 || pow(base, -infinity) != 1.0) { exit(1); } - if (pow(-1.0, infinity) != 1.0 || pow(-1.0, -infinity) != 1.0) { + if (pow(-base, infinity) != 1.0 || pow(-base, -infinity) != 1.0) { exit(1); } - if (pow(0.0, infinity) != 0.0) { + + base = 0.0; + if (pow(base, infinity) != 0.0) { exit(1); } - if (pow(0.0, -infinity) != infinity) { + if (pow(base, -infinity) != infinity) { exit(1); } - if (pow(-1.1, infinity) != infinity || pow(1.1, infinity) != infinity) { + + base = 1.1; + if (pow(-base, infinity) != infinity || pow(base, infinity) != infinity) { exit(1); } - if (pow(-1.1, -infinity) != 0.0 || pow(1.1, -infinity) != 0.0) { + if (pow(-base, -infinity) != 0.0 || pow(base, -infinity) != 0.0) { exit(1); } - if (pow(-0.0, -1) != -infinity) { + + base = 0.0; + volatile int iexp = 1; + if (pow(-base, -iexp) != -infinity) { exit(1); } - if (pow(0.0, -1) != infinity) { + if (pow(base, -iexp) != infinity) { exit(1); } exit(0); @@ -788,8 +803,10 @@ check_cxx_source_runs(" int main(int argc, char **argv) { double result; + volatile double base = 3.2e-10; + volatile double exp = 1 - 5e14; - result = pow(-3.2e-10, -5e14 + 1); + result = pow(-base, exp); if (result != -1.0 / 0.0) { exit(1); } @@ -803,8 +820,10 @@ check_cxx_source_runs(" int main(int argc, char **argv) { double result; + volatile double base = 3.5; + volatile double exp = 3e100; - result = pow(-3.5, 3e100); + result = pow(-base, exp); if (result != 1.0 / 0.0) { exit(1); } @@ -819,23 +838,25 @@ check_cxx_source_runs(" int main(void) { double pi = 3.14159265358979323846; double result; + volatile double y = 0.0; + volatile double x = 0.0; - result = atan2(0.0, -0.0); + result = atan2(y, -x); if (fabs(pi - result) > 0.0000001) { exit(1); } - result = atan2(-0.0, -0.0); + result = atan2(-y, -x); if (fabs(-pi - result) > 0.0000001) { exit(1); } - result = atan2 (-0.0, 0.0); + result = atan2 (-y, x); if (result != 0.0 || copysign (1.0, result) > 0) { exit(1); } - result = atan2 (0.0, 0.0); + result = atan2 (y, x); if (result != 0.0 || copysign (1.0, result) < 0) { exit(1); } @@ -895,7 +916,8 @@ check_cxx_source_runs(" #include int main(void) { - if (!isnan(log(-10000))) { + volatile int arg = 10000; + if (!isnan(log(-arg))) { exit(1); } exit(0); @@ -907,7 +929,8 @@ check_cxx_source_runs(" #include int main(void) { - if (!isnan(log10(-10000))) { + volatile int arg = 10000; + if (!isnan(log10(-arg))) { exit(1); } exit(0); @@ -1390,4 +1413,30 @@ else() # Anything else is Linux set(HAVE_SCHED_OTHER_ASSIGNABLE 1) endif(CLR_CMAKE_TARGET_OSX) +check_struct_has_member( + "struct statfs" + f_fstypename + "sys/mount.h" + HAVE_STATFS_FSTYPENAME) + +check_struct_has_member( + "struct statvfs" + f_fstypename + "sys/mount.h" + HAVE_STATVFS_FSTYPENAME) + +# statfs: Find whether this struct exists +if (HAVE_STATFS_FSTYPENAME OR HAVE_STATVFS_FSTYPENAME) + set (STATFS_INCLUDES sys/mount.h) +else () + set (STATFS_INCLUDES sys/statfs.h) +endif () + +check_prototype_definition( + statfs + "int statfs(const char *path, struct statfs *buf)" + 0 + ${STATFS_INCLUDES} + HAVE_NON_LEGACY_STATFS) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) diff --git a/src/coreclr/src/pal/src/exception/machexception.cpp b/src/coreclr/src/pal/src/exception/machexception.cpp index 5bf4218b40c2e5..01130e80978cf1 100644 --- a/src/coreclr/src/pal/src/exception/machexception.cpp +++ b/src/coreclr/src/pal/src/exception/machexception.cpp @@ -41,6 +41,7 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do #include #include #include +#include using namespace CorUnix; @@ -356,17 +357,11 @@ PAL_ERROR CorUnix::CPalThread::DisableMachExceptions() return palError; } -#if !defined(HOST_AMD64) -extern "C" -void PAL_DispatchException(PCONTEXT pContext, PEXCEPTION_RECORD pExRecord, MachExceptionInfo *pMachExceptionInfo) -#else // defined(HOST_AMD64) - // Since HijackFaultingThread pushed the context, exception record and info on the stack, we need to adjust the // signature of PAL_DispatchException such that the corresponding arguments are considered to be on the stack // per GCC64 calling convention rules. Hence, the first 6 dummy arguments (corresponding to RDI, RSI, RDX,RCX, R8, R9). extern "C" void PAL_DispatchException(DWORD64 dwRDI, DWORD64 dwRSI, DWORD64 dwRDX, DWORD64 dwRCX, DWORD64 dwR8, DWORD64 dwR9, PCONTEXT pContext, PEXCEPTION_RECORD pExRecord, MachExceptionInfo *pMachExceptionInfo) -#endif // !defined(HOST_AMD64) { CPalThread *pThread = InternalGetCurrentThread(); @@ -413,10 +408,8 @@ void PAL_DispatchException(DWORD64 dwRDI, DWORD64 dwRSI, DWORD64 dwRDX, DWORD64 } } -#if defined(HOST_X86) || defined(HOST_AMD64) extern "C" void PAL_DispatchExceptionWrapper(); extern "C" int PAL_DispatchExceptionReturnOffset; -#endif // HOST_X86 || HOST_AMD64 /*++ Function : @@ -476,7 +469,6 @@ BuildExceptionRecord( { switch (exceptionInfo.Subcodes[0]) { -#if defined(HOST_X86) || defined(HOST_AMD64) case EXC_I386_DIV: exceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO; break; @@ -489,9 +481,6 @@ BuildExceptionRecord( case EXC_I386_BOUND: exceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED; break; -#else -#error Trap code to exception mapping not defined for this architecture -#endif default: exceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; break; @@ -500,16 +489,11 @@ BuildExceptionRecord( break; case EXC_SOFTWARE: -#if defined(HOST_X86) || defined(HOST_AMD64) exceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; break; -#else -#error Trap code to exception mapping not defined for this architecture -#endif // Trace, breakpoint, etc. Details in subcode field. case EXC_BREAKPOINT: -#if defined(HOST_X86) || defined(HOST_AMD64) if (exceptionInfo.Subcodes[0] == EXC_I386_SGL) { exceptionCode = EXCEPTION_SINGLE_STEP; @@ -518,9 +502,6 @@ BuildExceptionRecord( { exceptionCode = EXCEPTION_BREAKPOINT; } -#else -#error Trap code to exception mapping not defined for this architecture -#endif else { WARN("unexpected subcode %d for EXC_BREAKPOINT", exceptionInfo.Subcodes[0]); @@ -614,17 +595,12 @@ HijackFaultingThread( // Fill in the exception record from the exception info BuildExceptionRecord(exceptionInfo, &exceptionRecord); -#ifdef HOST_X86 - threadContext.ContextFlags = CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS; -#else threadContext.ContextFlags = CONTEXT_FLOATING_POINT; -#endif CONTEXT_GetThreadContextFromThreadState(x86_FLOAT_STATE, (thread_state_t)&exceptionInfo.FloatState, &threadContext); threadContext.ContextFlags |= CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS; CONTEXT_GetThreadContextFromThreadState(x86_THREAD_STATE, (thread_state_t)&exceptionInfo.ThreadState, &threadContext); -#if defined(CORECLR) && (defined(HOST_X86) || defined(HOST_AMD64)) // For CoreCLR we look more deeply at access violations to determine whether they're the result of a stack // overflow. If so we'll terminate the process immediately (the current default policy of the CoreCLR EE). // Otherwise we'll either A/V ourselves trying to set up the SEH exception record and context on the @@ -670,20 +646,15 @@ HijackFaultingThread( // corrupted). Our managed jits always generate code which does this as does MSVC. GCC, however, // does not do this by default. We have to explicitly provide the -fstack-check compiler option // to enable the behavior. -#if (defined(HOST_X86) || defined(HOST_AMD64)) && defined(__APPLE__) + // Assume that AV isn't an SO to begin with. + bool fIsStackOverflow = false; + if (exceptionRecord.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { - // Assume this AV isn't an SO to begin with. - bool fIsStackOverflow = false; - // Calculate the page base addresses for the fault and the faulting thread's SP. int cbPage = getpagesize(); char *pFaultPage = (char*)(exceptionRecord.ExceptionInformation[1] & ~(cbPage - 1)); -#ifdef HOST_X86 - char *pStackTopPage = (char*)(threadContext.Esp & ~(cbPage - 1)); -#elif defined(HOST_AMD64) char *pStackTopPage = (char*)(threadContext.Rsp & ~(cbPage - 1)); -#endif if (pFaultPage == pStackTopPage || pFaultPage == (pStackTopPage - cbPage)) { @@ -698,24 +669,14 @@ HijackFaultingThread( vm_size_t vm_size; vm_region_flavor_t vm_flavor; mach_msg_type_number_t infoCnt; -#ifdef HOST_64BIT vm_region_basic_info_data_64_t info; infoCnt = VM_REGION_BASIC_INFO_COUNT_64; vm_flavor = VM_REGION_BASIC_INFO_64; -#else - vm_region_basic_info_data_t info; - infoCnt = VM_REGION_BASIC_INFO_COUNT; - vm_flavor = VM_REGION_BASIC_INFO; -#endif mach_port_t object_name; vm_address = (vm_address_t)(pFaultPage + cbPage); -#ifdef HOST_64BIT machret = vm_region_64( -#else - machret = vm_region( -#endif mach_task_self(), &vm_address, &vm_size, @@ -723,11 +684,7 @@ HijackFaultingThread( (vm_region_info_t)&info, &infoCnt, &object_name); -#ifdef HOST_X86 - CHECK_MACH("vm_region", machret); -#elif defined(HOST_AMD64) CHECK_MACH("vm_region_64", machret); -#endif // If vm_region updated the address we gave it then that address was not part of a region at all // (and so this cannot be an SO). Otherwise check that the ESP lies in the region returned. @@ -737,7 +694,6 @@ HijackFaultingThread( fIsStackOverflow = true; } -#if defined(HOST_AMD64) if (!fIsStackOverflow) { // Check if we can read pointer sizeD bytes below the target thread's stack pointer. @@ -754,115 +710,53 @@ HijackFaultingThread( fIsStackOverflow = true; } } -#endif // HOST_AMD64 - - if (fIsStackOverflow) - { - // We have a stack overflow. Abort the process immediately. It would be nice to let the VM do this - // but the Windows mechanism (where a stack overflow SEH exception is delivered on the faulting - // thread) will not work most of the time since non-Windows OSs don't keep a reserve stack - // extension allocated for this purpose. - - // TODO: Once our event reporting story is further along we probably want to report something - // here. If our runtime policy for SO ever changes (the most likely candidate being "unload - // appdomain on SO) then we'll have to do something more complex here, probably involving a - // handshake with the runtime in order to report the SO without attempting to extend the faulting - // thread's stack any further. Note that we cannot call most PAL functions from the context of - // this thread since we're not a PAL thread. - - write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1); - abort(); - } } -#else // (HOST_X86 || HOST_AMD64) && __APPLE__ -#error Platform not supported for correct stack overflow handling -#endif // (HOST_X86 || HOST_AMD64) && __APPLE__ -#endif // CORECLR && HOST_X86 -#if defined(HOST_X86) - NONPAL_ASSERTE(exceptionInfo.ThreadState.tsh.flavor == x86_THREAD_STATE32); + NONPAL_ASSERTE(exceptionInfo.ThreadState.tsh.flavor == x86_THREAD_STATE64); // Make a copy of the thread state because the one in exceptionInfo needs to be preserved to restore // the state if the exception is forwarded. - x86_thread_state32_t ts32 = exceptionInfo.ThreadState.uts.ts32; + x86_thread_state64_t ts64 = exceptionInfo.ThreadState.uts.ts64; // If we're in single step mode, disable it since we're going to call PAL_DispatchException if (exceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP) { - ts32.eflags &= ~EFL_TF; + ts64.__rflags &= ~EFL_TF; + } + + if (fIsStackOverflow) + { + exceptionRecord.ExceptionCode = EXCEPTION_STACK_OVERFLOW; } exceptionRecord.ExceptionFlags = EXCEPTION_IS_SIGNAL; exceptionRecord.ExceptionRecord = NULL; - exceptionRecord.ExceptionAddress = (void *)ts32.eip; - - void **FramePointer = (void **)ts32.esp; - - *--FramePointer = (void *)ts32.eip; - - // Construct a stack frame for a pretend activation of the function - // PAL_DispatchExceptionWrapper that serves only to make the stack - // correctly unwindable by the system exception unwinder. - // PAL_DispatchExceptionWrapper has an ebp frame, its local variables - // are the context and exception record, and it has just "called" - // PAL_DispatchException. - *--FramePointer = (void *)ts32.ebp; - ts32.ebp = (unsigned)FramePointer; - - // Put the context on the stack - FramePointer = (void **)((ULONG_PTR)FramePointer - sizeof(CONTEXT)); - // Make sure it's aligned - CONTEXT has 8-byte alignment - FramePointer = (void **)((ULONG_PTR)FramePointer - ((ULONG_PTR)FramePointer % 8)); - CONTEXT *pContext = (CONTEXT *)FramePointer; - *pContext = threadContext; - - // Put the exception record on the stack - FramePointer = (void **)((ULONG_PTR)FramePointer - sizeof(EXCEPTION_RECORD)); - EXCEPTION_RECORD *pExceptionRecord = (EXCEPTION_RECORD *)FramePointer; - *pExceptionRecord = exceptionRecord; - - FramePointer = (void **)((ULONG_PTR)FramePointer - sizeof(MachExceptionInfo)); - MachExceptionInfo *pMachExceptionInfo = (MachExceptionInfo *)FramePointer; - *pMachExceptionInfo = exceptionInfo; - - // Push arguments to PAL_DispatchException - FramePointer = (void **)((ULONG_PTR)FramePointer - 3 * sizeof(void *)); - - // Make sure it's aligned - ABI requires 16-byte alignment - FramePointer = (void **)((ULONG_PTR)FramePointer - ((ULONG_PTR)FramePointer % 16)); - FramePointer[0] = pContext; - FramePointer[1] = pExceptionRecord; - FramePointer[2] = pMachExceptionInfo; - - // Place the return address to right after the fake call in PAL_DispatchExceptionWrapper - FramePointer[-1] = (void *)((ULONG_PTR)PAL_DispatchExceptionWrapper + PAL_DispatchExceptionReturnOffset); + exceptionRecord.ExceptionAddress = (void *)ts64.__rip; - // Make the instruction register point to DispatchException - ts32.eip = (unsigned)PAL_DispatchException; - ts32.esp = (unsigned)&FramePointer[-1]; // skip return address + void **FramePointer; - // Now set the thread state for the faulting thread so that PAL_DispatchException executes next - machret = thread_set_state(thread, x86_THREAD_STATE32, (thread_state_t)&ts32, x86_THREAD_STATE32_COUNT); - CHECK_MACH("thread_set_state(thread)", machret); -#elif defined(HOST_AMD64) - NONPAL_ASSERTE(exceptionInfo.ThreadState.tsh.flavor == x86_THREAD_STATE64); + if (fIsStackOverflow) + { + // Allocate the minimal stack necessary for handling stack overflow + int stackOverflowStackSize = 7 * 4096; + // Align the size to virtual page size and add one virtual page as a stack guard + stackOverflowStackSize = ALIGN_UP(stackOverflowStackSize, GetVirtualPageSize()) + GetVirtualPageSize(); + void* stackOverflowHandlerStack = mmap(NULL, stackOverflowStackSize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - // Make a copy of the thread state because the one in exceptionInfo needs to be preserved to restore - // the state if the exception is forwarded. - x86_thread_state64_t ts64 = exceptionInfo.ThreadState.uts.ts64; + if ((stackOverflowHandlerStack == MAP_FAILED) || mprotect((void*)stackOverflowHandlerStack, GetVirtualPageSize(), PROT_NONE) != 0) + { + // We are out of memory or we've failed to protect the guard page, so resort to just printing a stack overflow message and abort + write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1); + abort(); + } - // If we're in single step mode, disable it since we're going to call PAL_DispatchException - if (exceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP) + FramePointer = (void**)((size_t)stackOverflowHandlerStack + stackOverflowStackSize); + } + else { - ts64.__rflags &= ~EFL_TF; + FramePointer = (void **)ts64.__rsp; } - exceptionRecord.ExceptionFlags = EXCEPTION_IS_SIGNAL; - exceptionRecord.ExceptionRecord = NULL; - exceptionRecord.ExceptionAddress = (void *)ts64.__rip; - - void **FramePointer = (void **)ts64.__rsp; - *--FramePointer = (void *)ts64.__rip; // Construct a stack frame for a pretend activation of the function @@ -909,9 +803,6 @@ HijackFaultingThread( // Now set the thread state for the faulting thread so that PAL_DispatchException executes next machret = thread_set_state(thread, x86_THREAD_STATE64, (thread_state_t)&ts64, x86_THREAD_STATE64_COUNT); CHECK_MACH("thread_set_state(thread)", machret); -#else -#error HijackFaultingThread not defined for this architecture -#endif } /*++ @@ -1224,13 +1115,7 @@ void MachExceptionInfo::RestoreState(mach_port_t thread) { if (Subcodes[0] == EXC_I386_BPT) { -#ifdef HOST_X86 - ThreadState.uts.ts32.eip--; -#elif defined(HOST_AMD64) ThreadState.uts.ts64.__rip--; -#else -#error Platform not supported -#endif } } kern_return_t machret = thread_set_state(thread, x86_THREAD_STATE, (thread_state_t)&ThreadState, x86_THREAD_STATE_COUNT); diff --git a/src/coreclr/src/pal/src/exception/remote-unwind.cpp b/src/coreclr/src/pal/src/exception/remote-unwind.cpp index f1251fd7a0ab44..355905e334736e 100644 --- a/src/coreclr/src/pal/src/exception/remote-unwind.cpp +++ b/src/coreclr/src/pal/src/exception/remote-unwind.cpp @@ -359,10 +359,12 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pip, int nee ehFrameHdrLen = ph.p_memsz; break; +#ifdef PT_ARM_EXIDX case PT_ARM_EXIDX: exidxFrameHdrAddr = loadbias + ph.p_vaddr; exidxFrameHdrLen = ph.p_memsz; break; +#endif } } diff --git a/src/coreclr/src/pal/src/exception/seh.cpp b/src/coreclr/src/pal/src/exception/seh.cpp index e0ebff145b893d..ee022b45fa7ce3 100644 --- a/src/coreclr/src/pal/src/exception/seh.cpp +++ b/src/coreclr/src/pal/src/exception/seh.cpp @@ -264,24 +264,6 @@ SEHProcessException(PAL_SEHException* exception) // or in a jitter helper or it is a debugger breakpoint) if (g_safeExceptionCheckFunction(contextRecord, exceptionRecord)) { - if (exceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) - { - // Check if the failed access has hit a stack guard page. In such case, it - // was a stack probe that detected that there is not enough stack left. - void* stackLimit = CPalThread::GetStackLimit(); - void* stackOverflowBottom = (void*)((size_t)stackLimit - GetVirtualPageSize()); - // On some versions of glibc / platforms the stackLimit is an address of the guard page, on some - // it is right above the guard page. - // So consider SIGSEGV in one page above and below stack limit to be stack overflow. - void* stackOverflowTop = (void*)((size_t)stackLimit + GetVirtualPageSize()); - void* violationAddr = (void*)exceptionRecord->ExceptionInformation[1]; - - if ((violationAddr >= stackOverflowBottom) && (violationAddr < stackOverflowTop)) - { - exceptionRecord->ExceptionCode = EXCEPTION_STACK_OVERFLOW; - } - } - EnsureExceptionRecordsOnHeap(exception); if (g_hardwareExceptionHandler(exception)) { @@ -322,9 +304,7 @@ PAL_ERROR SEHEnable(CPalThread *pthrCurrent) { #if HAVE_MACH_EXCEPTIONS return pthrCurrent->EnableMachExceptions(); -#elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) - // TODO: This needs to be implemented. Cannot put an ASSERT here - // because it will make other parts of PAL fail. +#elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) return NO_ERROR; #else// HAVE_MACH_EXCEPTIONS #error not yet implemented @@ -349,9 +329,7 @@ PAL_ERROR SEHDisable(CPalThread *pthrCurrent) { #if HAVE_MACH_EXCEPTIONS return pthrCurrent->DisableMachExceptions(); - // TODO: This needs to be implemented. Cannot put an ASSERT here - // because it will make other parts of PAL fail. -#elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) +#elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) return NO_ERROR; #else // HAVE_MACH_EXCEPTIONS #error not yet implemented diff --git a/src/coreclr/src/pal/src/exception/signal.cpp b/src/coreclr/src/pal/src/exception/signal.cpp index d6d8256610e5c2..b142bbd82f77b9 100644 --- a/src/coreclr/src/pal/src/exception/signal.cpp +++ b/src/coreclr/src/pal/src/exception/signal.cpp @@ -116,6 +116,10 @@ int g_common_signal_handler_context_locvar_offset = 0; // TOP of special stack for handling stack overflow volatile void* g_stackOverflowHandlerStack = NULL; + +// Flag that is or-ed with SIGSEGV to indicate that the SIGSEGV was a stack overflow +const int StackOverflowFlag = 0x40000000; + #endif // !HAVE_MACH_EXCEPTIONS /* public function definitions ************************************************/ @@ -183,7 +187,11 @@ BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags) int stackOverflowStackSize = ALIGN_UP(sizeof(SignalHandlerWorkerReturnPoint), 16) + 7 * 4096; // Align the size to virtual page size and add one virtual page as a stack guard stackOverflowStackSize = ALIGN_UP(stackOverflowStackSize, GetVirtualPageSize()) + GetVirtualPageSize(); - g_stackOverflowHandlerStack = mmap(NULL, stackOverflowStackSize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_STACK | MAP_PRIVATE, -1, 0); + int flags = MAP_ANONYMOUS | MAP_PRIVATE; +#ifdef MAP_STACK + flags |= MAP_STACK; +#endif + g_stackOverflowHandlerStack = mmap(NULL, stackOverflowStackSize, PROT_READ | PROT_WRITE, flags, -1, 0); if (g_stackOverflowHandlerStack == MAP_FAILED) { return FALSE; @@ -525,7 +533,7 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context) } } - if (SwitchStackAndExecuteHandler(code, siginfo, context, (size_t)handlerStackTop)) + if (SwitchStackAndExecuteHandler(code | StackOverflowFlag, siginfo, context, (size_t)handlerStackTop)) { PROCAbort(); } @@ -534,7 +542,7 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context) { (void)write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1); PROCAbort(); - } + } } // Now that we know the SIGSEGV didn't happen due to a stack overflow, execute the common @@ -837,7 +845,15 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext ucontext = (native_context_t *)sigcontext; g_common_signal_handler_context_locvar_offset = (int)((char*)&signalContextRecord - (char*)__builtin_frame_address(0)); - exceptionRecord.ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext); + if (code == (SIGSEGV | StackOverflowFlag)) + { + exceptionRecord.ExceptionCode = EXCEPTION_STACK_OVERFLOW; + code &= ~StackOverflowFlag; + } + else + { + exceptionRecord.ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext); + } exceptionRecord.ExceptionFlags = EXCEPTION_IS_SIGNAL; exceptionRecord.ExceptionRecord = NULL; exceptionRecord.ExceptionAddress = GetNativeContextPC(ucontext); diff --git a/src/coreclr/src/pal/src/file/file.cpp b/src/coreclr/src/pal/src/file/file.cpp index 20dcfc43326c07..92695fd6315906 100644 --- a/src/coreclr/src/pal/src/file/file.cpp +++ b/src/coreclr/src/pal/src/file/file.cpp @@ -679,6 +679,14 @@ CorUnix::InternalCreateFile( palError = ERROR_INTERNAL_ERROR; goto done; } +#elif HAVE_DIRECTIO + if (-1 == directio(filed, DIRECTIO_ON)) + { + ASSERT("Can't set DIRECTIO_ON; directio() failed. errno is %d (%s)\n", + errno, strerror(errno)); + palError = ERROR_INTERNAL_ERROR; + goto done; + } #else #error Insufficient support for uncached I/O on this platform #endif diff --git a/src/coreclr/src/pal/src/include/pal/context.h b/src/coreclr/src/pal/src/include/pal/context.h index 482ec3471c5cd6..9313fc51653f7e 100644 --- a/src/coreclr/src/pal/src/include/pal/context.h +++ b/src/coreclr/src/pal/src/include/pal/context.h @@ -121,7 +121,11 @@ using asm_sigcontext::_xstate; #define MCREG_Rax(mc) ((mc).gregs[REG_RAX]) #define MCREG_Rip(mc) ((mc).gregs[REG_RIP]) #define MCREG_Rsp(mc) ((mc).gregs[REG_RSP]) +#ifdef REG_CSGSFS #define MCREG_SegCs(mc) (*(WORD*)&((mc).gregs[REG_CSGSFS])) +#else +#define MCREG_SegCs(mc) (*(WORD*)&((mc).gregs[REG_CS])) +#endif #define MCREG_R8(mc) ((mc).gregs[REG_R8]) #define MCREG_R9(mc) ((mc).gregs[REG_R9]) #define MCREG_R10(mc) ((mc).gregs[REG_R10]) @@ -131,20 +135,35 @@ using asm_sigcontext::_xstate; #define MCREG_R14(mc) ((mc).gregs[REG_R14]) #define MCREG_R15(mc) ((mc).gregs[REG_R15]) +#if HAVE_FPREGS_WITH_CW +#define FPREG_Fpstate(uc) (&((uc)->uc_mcontext.fpregs.fp_reg_set.fpchip_state)) + +#define FPREG_Xmm(uc, index) *(M128A*)&(FPREG_Fpstate(uc)->xmm[index]) +#define FPREG_St(uc, index) *(M128A*)&(FPREG_Fpstate(uc)->st[index]) +#define FPREG_ControlWord(uc) (FPREG_Fpstate(uc)->cw) +#define FPREG_StatusWord(uc) (FPREG_Fpstate(uc)->sw) +#define FPREG_MxCsr_Mask(uc) (FPREG_Fpstate(uc)->mxcsr_mask) + +// on SunOS, fctw and __fx_rsvd are uint8_t, whereas on linux ftw is uint16_t, +// so we use split and join technique for these two uint8_t members at call sites. +#define FPREG_TagWord1(uc) (FPREG_Fpstate(uc)->fctw) +#define FPREG_TagWord2(uc) (FPREG_Fpstate(uc)->__fx_rsvd) +#else #define FPREG_Fpstate(uc) ((uc)->uc_mcontext.fpregs) -#define FPREG_Xmm(uc, index) *(M128A*)&(FPREG_Fpstate(uc)->_xmm[index]) +#define FPREG_Xmm(uc, index) *(M128A*)&(FPREG_Fpstate(uc)->_xmm[index]) #define FPREG_St(uc, index) *(M128A*)&(FPREG_Fpstate(uc)->_st[index]) - #define FPREG_ControlWord(uc) (FPREG_Fpstate(uc)->cwd) #define FPREG_StatusWord(uc) (FPREG_Fpstate(uc)->swd) #define FPREG_TagWord(uc) (FPREG_Fpstate(uc)->ftw) +#define FPREG_MxCsr_Mask(uc) (FPREG_Fpstate(uc)->mxcr_mask) +#endif + #define FPREG_ErrorOffset(uc) *(DWORD*)&(FPREG_Fpstate(uc)->rip) #define FPREG_ErrorSelector(uc) *(((WORD*)&(FPREG_Fpstate(uc)->rip)) + 2) #define FPREG_DataOffset(uc) *(DWORD*)&(FPREG_Fpstate(uc)->rdp) #define FPREG_DataSelector(uc) *(((WORD*)&(FPREG_Fpstate(uc)->rdp)) + 2) #define FPREG_MxCsr(uc) (FPREG_Fpstate(uc)->mxcsr) -#define FPREG_MxCsr_Mask(uc) (FPREG_Fpstate(uc)->mxcr_mask) ///////////////////// // Extended state @@ -239,7 +258,11 @@ inline void *FPREG_Xstate_Ymmh(const ucontext_t *uc) #endif // HOST_64BIT +#ifdef REG_EFL #define MCREG_EFlags(mc) ((mc).gregs[REG_EFL]) +#else +#define MCREG_EFlags(mc) ((mc).gregs[EFL]) +#endif #else // HAVE_GREGSET_T diff --git a/src/coreclr/src/pal/src/include/pal/map.hpp b/src/coreclr/src/pal/src/include/pal/map.hpp index eba0d8844bb278..b8c584f83c5268 100644 --- a/src/coreclr/src/pal/src/include/pal/map.hpp +++ b/src/coreclr/src/pal/src/include/pal/map.hpp @@ -79,13 +79,14 @@ extern "C" Parameters: IN hFile - file to map + IN offset - offset within hFile where the PE "file" is located Return value: non-NULL - the base address of the mapped image NULL - error, with last error set. --*/ - void * MAPMapPEFile(HANDLE hFile); + void* MAPMapPEFile(HANDLE hFile, off_t offset); /*++ Function : diff --git a/src/coreclr/src/pal/src/include/pal/module.h b/src/coreclr/src/pal/src/include/pal/module.h index bb409b8fcd4491..6a5e080d499d2b 100644 --- a/src/coreclr/src/pal/src/include/pal/module.h +++ b/src/coreclr/src/pal/src/include/pal/module.h @@ -145,12 +145,13 @@ Abstract Parameters: IN hFile - The file to load + IN offset - offset within hFile where the PE "file" is located Return value: A valid base address if successful. 0 if failure --*/ -void * PAL_LOADLoadPEFile(HANDLE hFile); +void* PAL_LOADLoadPEFile(HANDLE hFile, size_t offset); /*++ PAL_LOADUnloadPEFile diff --git a/src/coreclr/src/pal/src/include/pal/mutex.hpp b/src/coreclr/src/pal/src/include/pal/mutex.hpp index 8aa9a53bdafc22..d5f6cef0095377 100644 --- a/src/coreclr/src/pal/src/include/pal/mutex.hpp +++ b/src/coreclr/src/pal/src/include/pal/mutex.hpp @@ -146,7 +146,6 @@ class NamedMutexProcessData : public SharedMemoryProcessDataBase private: SharedMemoryProcessDataHeader *m_processDataHeader; - NamedMutexSharedData *m_sharedData; SIZE_T m_lockCount; #if !NAMED_MUTEX_USE_PTHREAD_MUTEX HANDLE m_processLockHandle; @@ -154,6 +153,7 @@ class NamedMutexProcessData : public SharedMemoryProcessDataBase #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX CorUnix::CPalThread *m_lockOwnerThread; NamedMutexProcessData *m_nextInThreadOwnedNamedMutexList; + bool m_hasRefFromLockOwnerThread; public: static SharedMemoryProcessDataHeader *CreateOrOpen(LPCSTR name, bool acquireLockIfCreated, bool *createdRef); @@ -169,8 +169,19 @@ class NamedMutexProcessData : public SharedMemoryProcessDataBase int sharedLockFileDescriptor #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX ); + +public: + virtual bool CanClose() const override; + virtual bool HasImplicitRef() const override; + virtual void SetHasImplicitRef(bool value) override; virtual void Close(bool isAbruptShutdown, bool releaseSharedData) override; +public: + bool IsLockOwnedByCurrentThread() const + { + return GetSharedData()->IsLockOwnedByCurrentThread(); + } + private: NamedMutexSharedData *GetSharedData() const; void SetLockOwnerThread(CorUnix::CPalThread *lockOwnerThread); diff --git a/src/coreclr/src/pal/src/include/pal/sharedmemory.h b/src/coreclr/src/pal/src/include/pal/sharedmemory.h index 74e1cd4aedc391..ff64e20b5aa746 100644 --- a/src/coreclr/src/pal/src/include/pal/sharedmemory.h +++ b/src/coreclr/src/pal/src/include/pal/sharedmemory.h @@ -188,9 +188,10 @@ class SharedMemorySharedDataHeader class SharedMemoryProcessDataBase { public: - virtual void Close(bool isAbruptShutdown, bool releaseSharedData) - { - } + virtual bool CanClose() const = 0; + virtual bool HasImplicitRef() const = 0; + virtual void SetHasImplicitRef(bool value) = 0; + virtual void Close(bool isAbruptShutdown, bool releaseSharedData) = 0; virtual ~SharedMemoryProcessDataBase() { diff --git a/src/coreclr/src/pal/src/include/pal/synchobjects.hpp b/src/coreclr/src/pal/src/include/pal/synchobjects.hpp index 66d4710acb24b2..ab51a005bae065 100644 --- a/src/coreclr/src/pal/src/include/pal/synchobjects.hpp +++ b/src/coreclr/src/pal/src/include/pal/synchobjects.hpp @@ -118,7 +118,6 @@ namespace CorUnix Volatile m_lSharedSynchLockCount; LIST_ENTRY m_leOwnedObjsList; - CRITICAL_SECTION m_ownedNamedMutexListLock; NamedMutexProcessData *m_ownedNamedMutexListHead; ThreadNativeWaitData m_tnwdNativeData; @@ -178,6 +177,7 @@ namespace CorUnix void RemoveOwnedNamedMutex(NamedMutexProcessData *processData); NamedMutexProcessData *RemoveFirstOwnedNamedMutex(); bool OwnsNamedMutex(NamedMutexProcessData *processData); + bool OwnsAnyNamedMutex() const; // The following methods provide access to the native wait lock for // those implementations that need a lock to protect the support for diff --git a/src/coreclr/src/pal/src/loader/module.cpp b/src/coreclr/src/pal/src/loader/module.cpp index 8418ef776d4bec..65168978ba743b 100644 --- a/src/coreclr/src/pal/src/loader/module.cpp +++ b/src/coreclr/src/pal/src/loader/module.cpp @@ -752,6 +752,7 @@ PAL_UnregisterModule( Parameters: IN hFile - file to map + IN offset - offset within hFile where the PE "file" is located Return value: non-NULL - the base address of the mapped image @@ -759,11 +760,11 @@ Return value: --*/ PVOID PALAPI -PAL_LOADLoadPEFile(HANDLE hFile) +PAL_LOADLoadPEFile(HANDLE hFile, size_t offset) { - ENTRY("PAL_LOADLoadPEFile (hFile=%p)\n", hFile); + ENTRY("PAL_LOADLoadPEFile (hFile=%p, offset=%zx)\n", hFile, offset); - void * loadedBase = MAPMapPEFile(hFile); + void* loadedBase = MAPMapPEFile(hFile, offset); #ifdef _DEBUG if (loadedBase != nullptr) @@ -775,7 +776,7 @@ PAL_LOADLoadPEFile(HANDLE hFile) { TRACE("Forcing failure of PE file map, and retry\n"); PAL_LOADUnloadPEFile(loadedBase); // unload it - loadedBase = MAPMapPEFile(hFile); // load it again + loadedBase = MAPMapPEFile(hFile, offset); // load it again } free(envVar); @@ -1547,7 +1548,8 @@ static MODSTRUCT *LOADAddModule(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR libraryN { /* found the handle. increment the refcount and return the existing module structure */ - TRACE("Found matching module %p for module name %s\n", module, libraryNameOrPath); + TRACE("Found matching module %p for module name %s\n", module, + (libraryNameOrPath != nullptr) ? libraryNameOrPath : "nullptr"); if (module->refcount != -1) { diff --git a/src/coreclr/src/pal/src/map/map.cpp b/src/coreclr/src/pal/src/map/map.cpp index ddc715b25c994b..90936b19fd9165 100644 --- a/src/coreclr/src/pal/src/map/map.cpp +++ b/src/coreclr/src/pal/src/map/map.cpp @@ -1088,6 +1088,8 @@ CorUnix::InternalMapViewOfFile( CFileMappingImmutableData *pImmutableData = NULL; CFileMappingProcessLocalData *pProcessLocalData = NULL; IDataLock *pProcessLocalDataLock = NULL; + INT64 offset = ((INT64)dwFileOffsetHigh << 32) | (INT64)dwFileOffsetLow; + #if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS PMAPPED_VIEW_LIST pReusedMapping = NULL; #endif @@ -1102,9 +1104,9 @@ CorUnix::InternalMapViewOfFile( goto InternalMapViewOfFileExit; } - if ( 0 != dwFileOffsetHigh || 0 != dwFileOffsetLow ) + if (offset < 0) { - ASSERT( "dwFileOffsetHigh and dwFileOffsetLow are always 0.\n" ); + ASSERT("dwFileOffsetHigh | dwFileOffsetLow should be non-negative.\n"); palError = ERROR_INVALID_PARAMETER; goto InternalMapViewOfFileExit; } @@ -1182,7 +1184,7 @@ CorUnix::InternalMapViewOfFile( PROT_READ|PROT_WRITE, flags, pProcessLocalData->UnixFd, - 0 + offset ); } else @@ -1205,7 +1207,7 @@ CorUnix::InternalMapViewOfFile( prot, flags, pProcessLocalData->UnixFd, - 0 + offset ); #if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS @@ -2210,13 +2212,14 @@ MAPmmapAndRecord( Parameters: IN hFile - file to map + IN offset - offset within hFile where the PE "file" is located Return value: non-NULL - the base address of the mapped image NULL - error, with last error set. --*/ -void * MAPMapPEFile(HANDLE hFile) +void * MAPMapPEFile(HANDLE hFile, off_t offset) { PAL_ERROR palError = 0; IPalObject *pFileObject = NULL; @@ -2231,7 +2234,7 @@ void * MAPMapPEFile(HANDLE hFile) char* envVar; #endif - ENTRY("MAPMapPEFile (hFile=%p)\n", hFile); + ENTRY("MAPMapPEFile (hFile=%p offset=%zx)\n", hFile, offset); //Step 0: Verify values, find internal pal data structures. if (INVALID_HANDLE_VALUE == hFile) @@ -2270,13 +2273,13 @@ void * MAPMapPEFile(HANDLE hFile) //Step 1: Read the PE headers and reserve enough space for the whole image somewhere. IMAGE_DOS_HEADER dosHeader; IMAGE_NT_HEADERS ntHeader; - if (sizeof(dosHeader) != pread(fd, &dosHeader, sizeof(dosHeader), 0)) + if (sizeof(dosHeader) != pread(fd, &dosHeader, sizeof(dosHeader), offset)) { palError = FILEGetLastErrorFromErrno(); ERROR_(LOADER)( "reading dos header failed\n" ); goto done; } - if (sizeof(ntHeader) != pread(fd, &ntHeader, sizeof(ntHeader), dosHeader.e_lfanew)) + if (sizeof(ntHeader) != pread(fd, &ntHeader, sizeof(ntHeader), offset + dosHeader.e_lfanew)) { palError = FILEGetLastErrorFromErrno(); goto done; @@ -2418,7 +2421,7 @@ void * MAPMapPEFile(HANDLE hFile) //first, map the PE header to the first page in the image. Get pointers to the section headers palError = MAPmmapAndRecord(pFileObject, loadedBase, - loadedBase, headerSize, PROT_READ, MAP_FILE|MAP_PRIVATE|MAP_FIXED, fd, 0, + loadedBase, headerSize, PROT_READ, MAP_FILE|MAP_PRIVATE|MAP_FIXED, fd, offset, (void**)&loadedHeader); if (NO_ERROR != palError) { @@ -2511,7 +2514,7 @@ void * MAPMapPEFile(HANDLE hFile) prot, MAP_FILE|MAP_PRIVATE|MAP_FIXED, fd, - currentHeader.PointerToRawData, + offset + currentHeader.PointerToRawData, §ionData); if (NO_ERROR != palError) { @@ -2541,7 +2544,7 @@ void * MAPMapPEFile(HANDLE hFile) palError = MAPRecordMapping(pFileObject, loadedBase, prevSectionEnd, - (char*)imageEnd - (char*)prevSectionEnd, + offset + (char*)imageEnd - (char*)prevSectionEnd, PROT_NONE); if (NO_ERROR != palError) { @@ -2706,7 +2709,7 @@ BOOL MAPMarkSectionAsNotNeeded(LPCVOID lpAddress) if (pView->lpAddress == lpAddress) // this entry is associated with the section { - if (-1 == madvise(pView->lpAddress, pView->NumberOfBytesToMap, MADV_DONTNEED)) + if (-1 == posix_madvise(pView->lpAddress, pView->NumberOfBytesToMap, POSIX_MADV_DONTNEED)) { ERROR_(LOADER)("Unable to mark the section as NotNeeded.\n"); retval = FALSE; diff --git a/src/coreclr/src/pal/src/map/virtual.cpp b/src/coreclr/src/pal/src/map/virtual.cpp index 571273cf40d8bb..3d796d9efc17a2 100644 --- a/src/coreclr/src/pal/src/map/virtual.cpp +++ b/src/coreclr/src/pal/src/map/virtual.cpp @@ -141,7 +141,7 @@ namespace VirtualMemoryLogging LogRecord* curRec = (LogRecord*)&logRecords[i % MaxRecords]; curRec->RecordId = i; - curRec->CurrentThread = (LPVOID)pthread_self(); + curRec->CurrentThread = reinterpret_cast(pthread_self()); curRec->RequestedAddress = requestedAddress; curRec->ReturnedAddress = returnedAddress; curRec->Size = size; @@ -847,7 +847,7 @@ static LPVOID VIRTUALResetMemory( #endif { // In case the MADV_FREE is not supported, use MADV_DONTNEED - st = madvise((LPVOID)StartBoundary, MemSize, MADV_DONTNEED); + st = posix_madvise((LPVOID)StartBoundary, MemSize, POSIX_MADV_DONTNEED); } if (st == 0) @@ -2276,6 +2276,12 @@ void *ExecutableMemoryAllocator::AllocateMemoryWithinRange(const void *beginAddr at which the allocator should start allocating memory from its reserved memory range. --*/ +#ifdef __sun +// The upper limit of the random() function on SunOS derived operating systems is not RAND_MAX, but 2^31-1. +#define OFFSET_RAND_MAX 0x7FFFFFFF +#else +#define OFFSET_RAND_MAX RAND_MAX +#endif int32_t ExecutableMemoryAllocator::GenerateRandomStartOffset() { int32_t pageCount; @@ -2284,7 +2290,7 @@ int32_t ExecutableMemoryAllocator::GenerateRandomStartOffset() // This code is similar to what coreclr runtime does on Windows. // It generates a random number of pages to skip between 0...MaxStartPageOffset. srandom(time(NULL)); - pageCount = (int32_t)(MaxStartPageOffset * (int64_t)random() / RAND_MAX); + pageCount = (int32_t)(MaxStartPageOffset * (int64_t)random() / OFFSET_RAND_MAX); return pageCount * GetVirtualPageSize(); } diff --git a/src/coreclr/src/pal/src/misc/cgroup.cpp b/src/coreclr/src/pal/src/misc/cgroup.cpp index df6d59f0c77568..42a5dd27d2756b 100644 --- a/src/coreclr/src/pal/src/misc/cgroup.cpp +++ b/src/coreclr/src/pal/src/misc/cgroup.cpp @@ -121,8 +121,12 @@ class CGroup // modes because both of those involve cgroup v1 controllers managing // resources. +#if !HAVE_NON_LEGACY_STATFS + return 0; +#else struct statfs stats; int result = statfs("/sys/fs/cgroup", &stats); + if (result != 0) return 0; @@ -134,6 +138,7 @@ class CGroup _ASSERTE(!"Unexpected file system type for /sys/fs/cgroup"); return 0; } +#endif } static bool IsCGroup1MemorySubsystem(const char *strTok){ diff --git a/src/coreclr/src/pal/src/misc/sysinfo.cpp b/src/coreclr/src/pal/src/misc/sysinfo.cpp index 7e9bf4b3b6e6fc..17efa171c28486 100644 --- a/src/coreclr/src/pal/src/misc/sysinfo.cpp +++ b/src/coreclr/src/pal/src/misc/sysinfo.cpp @@ -93,6 +93,10 @@ Revision History: #include +#if HAVE_SWAPCTL +#include +#endif + SET_DEFAULT_DEBUG_CHANNEL(MISC); #ifndef __APPLE__ @@ -221,6 +225,8 @@ GetSystemInfo( lpSystemInfo->lpMaximumApplicationAddress = (PVOID) VM_MAXUSER_ADDRESS; #elif defined(__linux__) lpSystemInfo->lpMaximumApplicationAddress = (PVOID) (1ull << 47); +#elif defined(__sun) + lpSystemInfo->lpMaximumApplicationAddress = (PVOID) 0xfffffd7fffe00000ul; #elif defined(USERLIMIT) lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USERLIMIT; #elif defined(HOST_64BIT) @@ -404,6 +410,14 @@ GlobalMemoryStatusEx( lpBuffer->ullAvailPageFile += (DWORDLONG)avail * pagesize; } } +#elif HAVE_SWAPCTL + struct anoninfo ai; + if (swapctl(SC_AINFO, &ai) != -1) + { + int pagesize = getpagesize(); + lpBuffer->ullTotalPageFile = ai.ani_max * pagesize; + lpBuffer->ullAvailPageFile = ai.ani_free * pagesize; + } #elif HAVE_SYSINFO // Linux struct sysinfo info; diff --git a/src/coreclr/src/pal/src/safecrt/input.inl b/src/coreclr/src/pal/src/safecrt/input.inl index 4045f423ca7b7f..0f578e099ebaec 100644 --- a/src/coreclr/src/pal/src/safecrt/input.inl +++ b/src/coreclr/src/pal/src/safecrt/input.inl @@ -115,6 +115,9 @@ static int __cdecl _whiteout(int *, miniFILE *); #endif /* CPRFLAG */ +#undef _ISDIGIT +#undef _ISXDIGIT + #ifndef _UNICODE #define _ISDIGIT(chr) isdigit((unsigned char)chr) #define _ISXDIGIT(chr) isxdigit((unsigned char)chr) diff --git a/src/coreclr/src/pal/src/safecrt/mbusafecrt_internal.h b/src/coreclr/src/pal/src/safecrt/mbusafecrt_internal.h index 00136ecfe2839f..4f9ee5f6c5af0d 100644 --- a/src/coreclr/src/pal/src/safecrt/mbusafecrt_internal.h +++ b/src/coreclr/src/pal/src/safecrt/mbusafecrt_internal.h @@ -65,6 +65,10 @@ typedef struct miniFILE_struct int _flag; } miniFILE; +#undef _IOWRT +#undef _IOREAD +#undef _IOMYBUF + #define _IOSTRG 1 #define _IOWRT 2 #define _IOREAD 4 diff --git a/src/coreclr/src/pal/src/sharedmemory/sharedmemory.cpp b/src/coreclr/src/pal/src/sharedmemory/sharedmemory.cpp index 619fae0852826f..d61b92c939fd09 100644 --- a/src/coreclr/src/pal/src/sharedmemory/sharedmemory.cpp +++ b/src/coreclr/src/pal/src/sharedmemory/sharedmemory.cpp @@ -878,6 +878,7 @@ void SharedMemoryProcessDataHeader::Close() // nonzero, don't clean up any object or global process-local state. if (m_refCount == 0) { + _ASSERTE(m_data == nullptr || m_data->CanClose()); SharedMemoryManager::RemoveProcessDataHeader(this); } @@ -1015,7 +1016,12 @@ void SharedMemoryProcessDataHeader::IncRefCount() _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired()); _ASSERTE(m_refCount != 0); - ++m_refCount; + if (++m_refCount == 2 && m_data != nullptr && m_data->HasImplicitRef()) + { + // The synchronization object got an explicit ref that will govern its lifetime, remove the implicit ref + --m_refCount; + m_data->SetHasImplicitRef(false); + } } void SharedMemoryProcessDataHeader::DecRefCount() @@ -1023,10 +1029,21 @@ void SharedMemoryProcessDataHeader::DecRefCount() _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired()); _ASSERTE(m_refCount != 0); - if (--m_refCount == 0) + if (--m_refCount != 0) + { + return; + } + + if (m_data != nullptr && !m_data->CanClose()) { - InternalDelete(this); + // Extend the lifetime of the synchronization object. The process data object is responsible for removing this extra ref + // when the synchronization object transitions into a state where it can be closed. + ++m_refCount; + m_data->SetHasImplicitRef(true); + return; } + + InternalDelete(this); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/src/pal/src/shmemory/shmemory.cpp b/src/coreclr/src/pal/src/shmemory/shmemory.cpp index 46d8e160fef24d..9539d10aebec7d 100644 --- a/src/coreclr/src/pal/src/shmemory/shmemory.cpp +++ b/src/coreclr/src/pal/src/shmemory/shmemory.cpp @@ -155,7 +155,7 @@ int SHMLock(void) PALCEnterCriticalSection(&shm_critsec); _ASSERTE((0 == lock_count && 0 == locking_thread) || - (0 < lock_count && (HANDLE)pthread_self() == locking_thread)); + (0 < lock_count && reinterpret_cast(pthread_self()) == locking_thread)); if(lock_count == 0) { @@ -166,7 +166,7 @@ int SHMLock(void) // Store the id of the current thread as the (only) one that is // trying to grab the spinlock from the current process - locking_thread = (HANDLE)pthread_self(); + locking_thread = reinterpret_cast(pthread_self()); my_pid = gPID; @@ -336,7 +336,7 @@ SHMPTR SHMGetInfo(SHM_INFO_ID element) /* verify that this thread holds the SHM lock. No race condition: if the current thread is here, it can't be in SHMLock or SHMUnlock */ - if( (HANDLE)pthread_self() != locking_thread ) + if( reinterpret_cast(pthread_self()) != locking_thread ) { ASSERT("SHMGetInfo called while thread does not hold the SHM lock!\n"); } @@ -374,7 +374,7 @@ BOOL SHMSetInfo(SHM_INFO_ID element, SHMPTR value) /* verify that this thread holds the SHM lock. No race condition: if the current thread is here, it can't be in SHMLock or SHMUnlock */ - if( (HANDLE)pthread_self() != locking_thread ) + if( reinterpret_cast(pthread_self()) != locking_thread ) { ASSERT("SHMGetInfo called while thread does not hold the SHM lock!\n"); } diff --git a/src/coreclr/src/pal/src/synchmgr/synchmanager.cpp b/src/coreclr/src/pal/src/synchmgr/synchmanager.cpp index 9d868c00e09f94..52b8843889d23f 100644 --- a/src/coreclr/src/pal/src/synchmgr/synchmanager.cpp +++ b/src/coreclr/src/pal/src/synchmgr/synchmanager.cpp @@ -568,6 +568,17 @@ namespace CorUnix CThreadSynchronizationInfo * pSynchInfo = &pthrTarget->synchronizationInfo; CPalSynchronizationManager * pSynchManager = GetInstance(); + // The shared memory manager's process lock is acquired before calling into some PAL synchronization primitives that may + // take the PAL synchronization manager's synch lock (acquired below). For example, when using a file lock + // implementation for a named mutex (see NamedMutexProcessData::NamedMutexProcessData()), under the shared memory + // manager's process lock, CreateMutex is called, which acquires the PAL synchronization manager's synch lock. The same + // lock order needs to be maintained here to avoid a deadlock. + bool abandonNamedMutexes = pSynchInfo->OwnsAnyNamedMutex(); + if (abandonNamedMutexes) + { + SharedMemoryManager::AcquireCreationDeletionProcessLock(); + } + // Local lock AcquireLocalSynchLock(pthrCurrent); @@ -610,15 +621,18 @@ namespace CorUnix pSynchManager->m_cacheOwnedObjectsListNodes.Add(pthrCurrent, poolnItem); } - // Abandon owned named mutexes - while (true) + if (abandonNamedMutexes) { - NamedMutexProcessData *processData = pSynchInfo->RemoveFirstOwnedNamedMutex(); - if (processData == nullptr) + // Abandon owned named mutexes + while (true) { - break; + NamedMutexProcessData *processData = pSynchInfo->RemoveFirstOwnedNamedMutex(); + if (processData == nullptr) + { + break; + } + processData->Abandon(); } - processData->Abandon(); } if (pthrTarget != pthrCurrent) @@ -660,6 +674,12 @@ namespace CorUnix } ReleaseLocalSynchLock(pthrCurrent); + + if (abandonNamedMutexes) + { + SharedMemoryManager::ReleaseCreationDeletionProcessLock(); + } + DiscardAllPendingAPCs(pthrCurrent, pthrTarget); return palErr; @@ -4036,7 +4056,6 @@ namespace CorUnix m_ownedNamedMutexListHead(nullptr) { InitializeListHead(&m_leOwnedObjsList); - InitializeCriticalSection(&m_ownedNamedMutexListLock); #ifdef SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING m_lPendingSignalingCount = 0; @@ -4046,7 +4065,6 @@ namespace CorUnix CThreadSynchronizationInfo::~CThreadSynchronizationInfo() { - DeleteCriticalSection(&m_ownedNamedMutexListLock); if (NULL != m_shridWaitAwakened) { free(m_shridWaitAwakened); @@ -4283,20 +4301,21 @@ namespace CorUnix void CThreadSynchronizationInfo::AddOwnedNamedMutex(NamedMutexProcessData *processData) { + _ASSERTE(this == &GetCurrentPalThread()->synchronizationInfo); _ASSERTE(processData != nullptr); + _ASSERTE(processData->IsLockOwnedByCurrentThread()); _ASSERTE(processData->GetNextInThreadOwnedNamedMutexList() == nullptr); - EnterCriticalSection(&m_ownedNamedMutexListLock); processData->SetNextInThreadOwnedNamedMutexList(m_ownedNamedMutexListHead); m_ownedNamedMutexListHead = processData; - LeaveCriticalSection(&m_ownedNamedMutexListLock); } void CThreadSynchronizationInfo::RemoveOwnedNamedMutex(NamedMutexProcessData *processData) { + _ASSERTE(this == &GetCurrentPalThread()->synchronizationInfo); _ASSERTE(processData != nullptr); + _ASSERTE(processData->IsLockOwnedByCurrentThread()); - EnterCriticalSection(&m_ownedNamedMutexListLock); if (m_ownedNamedMutexListHead == processData) { m_ownedNamedMutexListHead = processData->GetNextInThreadOwnedNamedMutexList(); @@ -4321,38 +4340,44 @@ namespace CorUnix } _ASSERTE(found); } - LeaveCriticalSection(&m_ownedNamedMutexListLock); } NamedMutexProcessData *CThreadSynchronizationInfo::RemoveFirstOwnedNamedMutex() { - EnterCriticalSection(&m_ownedNamedMutexListLock); + _ASSERTE(this == &GetCurrentPalThread()->synchronizationInfo); + NamedMutexProcessData *processData = m_ownedNamedMutexListHead; if (processData != nullptr) { + _ASSERTE(processData->IsLockOwnedByCurrentThread()); m_ownedNamedMutexListHead = processData->GetNextInThreadOwnedNamedMutexList(); processData->SetNextInThreadOwnedNamedMutexList(nullptr); } - LeaveCriticalSection(&m_ownedNamedMutexListLock); return processData; } bool CThreadSynchronizationInfo::OwnsNamedMutex(NamedMutexProcessData *processData) { - EnterCriticalSection(&m_ownedNamedMutexListLock); - bool found = false; + _ASSERTE(this == &GetCurrentPalThread()->synchronizationInfo); + for (NamedMutexProcessData *current = m_ownedNamedMutexListHead; current != nullptr; current = current->GetNextInThreadOwnedNamedMutexList()) { + _ASSERTE(current->IsLockOwnedByCurrentThread()); if (current == processData) { - found = true; - break; + return true; } } - LeaveCriticalSection(&m_ownedNamedMutexListLock); - return found; + + return false; + } + + bool CThreadSynchronizationInfo::OwnsAnyNamedMutex() const + { + _ASSERTE(this == &GetCurrentPalThread()->synchronizationInfo); + return m_ownedNamedMutexListHead != nullptr; } #if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING diff --git a/src/coreclr/src/pal/src/synchobj/mutex.cpp b/src/coreclr/src/pal/src/synchobj/mutex.cpp index a4bb340a436a94..d36752a2040576 100644 --- a/src/coreclr/src/pal/src/synchobj/mutex.cpp +++ b/src/coreclr/src/pal/src/synchobj/mutex.cpp @@ -1247,7 +1247,8 @@ NamedMutexProcessData::NamedMutexProcessData( m_sharedLockFileDescriptor(sharedLockFileDescriptor), #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX m_lockOwnerThread(nullptr), - m_nextInThreadOwnedNamedMutexList(nullptr) + m_nextInThreadOwnedNamedMutexList(nullptr), + m_hasRefFromLockOwnerThread(false) { _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired()); _ASSERTE(processDataHeader != nullptr); @@ -1263,6 +1264,39 @@ NamedMutexProcessData::NamedMutexProcessData( #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX } +bool NamedMutexProcessData::CanClose() const +{ + _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired()); + + // When using a pthread robust mutex, the mutex may only be unlocked and destroyed by the thread that owns the lock. When + // using file locks, even though any thread could release that lock, the behavior is kept consistent to the more + // conservative case. If the last handle to the mutex is closed when a different thread owns the lock, the mutex cannot be + // closed. Due to these limitations, the behavior in this corner case is necessarily different from Windows. The caller will + // extend the lifetime of the mutex and will call OnLifetimeExtendedDueToCannotClose() shortly. + return m_lockOwnerThread == nullptr || m_lockOwnerThread == GetCurrentPalThread(); +} + +bool NamedMutexProcessData::HasImplicitRef() const +{ + _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired()); + return m_hasRefFromLockOwnerThread; +} + +void NamedMutexProcessData::SetHasImplicitRef(bool value) +{ + _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired()); + _ASSERTE(m_hasRefFromLockOwnerThread != value); + _ASSERTE(!value || !CanClose()); + + // If value == true: + // The mutex could not be closed and the caller extended the lifetime of the mutex. Record that the lock owner thread + // should release the ref when the lock is released on that thread. + // Else: + // The mutex has an implicit ref and got the first explicit reference from this process. Remove the implicit ref from the + // lock owner thread. + m_hasRefFromLockOwnerThread = value; +} + void NamedMutexProcessData::Close(bool isAbruptShutdown, bool releaseSharedData) { _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired()); @@ -1272,20 +1306,23 @@ void NamedMutexProcessData::Close(bool isAbruptShutdown, bool releaseSharedData) // active references to the mutex. So when shutting down abruptly, don't clean up any object or global process-local state. if (!isAbruptShutdown) { + _ASSERTE(CanClose()); + _ASSERTE(!m_hasRefFromLockOwnerThread); + CPalThread *lockOwnerThread = m_lockOwnerThread; - if (lockOwnerThread != nullptr) + if (lockOwnerThread == GetCurrentPalThread()) { - // The mutex was not released before it was closed. If the lock is owned by the current thread, abandon the mutex. - // In both cases, clean up the owner thread's list of owned mutexes. + // The mutex was not released before the last handle to it from this process was closed on the lock-owning thread. + // Another process may still have a handle to the mutex, but since it appears as though this process would not be + // releasing the mutex, abandon the mutex. The only way for this process to otherwise release the mutex is to open + // another handle to it and release the lock on the same thread, which would be incorrect-looking code. The behavior + // in this corner case is different from Windows. lockOwnerThread->synchronizationInfo.RemoveOwnedNamedMutex(this); - if (lockOwnerThread == GetCurrentPalThread()) - { - Abandon(); - } - else - { - m_lockOwnerThread = nullptr; - } + Abandon(); + } + else + { + _ASSERTE(lockOwnerThread == nullptr); } if (releaseSharedData) @@ -1337,18 +1374,20 @@ NamedMutexSharedData *NamedMutexProcessData::GetSharedData() const void NamedMutexProcessData::SetLockOwnerThread(CorUnix::CPalThread *lockOwnerThread) { _ASSERTE(lockOwnerThread == nullptr || lockOwnerThread == GetCurrentPalThread()); - _ASSERTE(GetSharedData()->IsLockOwnedByCurrentThread()); + _ASSERTE(IsLockOwnedByCurrentThread()); m_lockOwnerThread = lockOwnerThread; } NamedMutexProcessData *NamedMutexProcessData::GetNextInThreadOwnedNamedMutexList() const { + _ASSERTE(IsLockOwnedByCurrentThread()); return m_nextInThreadOwnedNamedMutexList; } void NamedMutexProcessData::SetNextInThreadOwnedNamedMutexList(NamedMutexProcessData *next) { + _ASSERTE(IsLockOwnedByCurrentThread()); m_nextInThreadOwnedNamedMutexList = next; } @@ -1367,7 +1406,7 @@ MutexTryAcquireLockResult NamedMutexProcessData::TryAcquireLock(DWORD timeoutMil // at the appropriate time, see ReleaseLock(). if (m_lockCount != 0) { - _ASSERTE(sharedData->IsLockOwnedByCurrentThread()); // otherwise, this thread would not have acquired the lock + _ASSERTE(IsLockOwnedByCurrentThread()); // otherwise, this thread would not have acquired the lock _ASSERTE(GetCurrentPalThread()->synchronizationInfo.OwnsNamedMutex(this)); if (m_lockCount + 1 < m_lockCount) @@ -1442,7 +1481,7 @@ MutexTryAcquireLockResult NamedMutexProcessData::TryAcquireLock(DWORD timeoutMil // Check if it's a recursive lock attempt if (m_lockCount != 0) { - _ASSERTE(sharedData->IsLockOwnedByCurrentThread()); // otherwise, this thread would not have acquired the process lock + _ASSERTE(IsLockOwnedByCurrentThread()); // otherwise, this thread would not have acquired the process lock _ASSERTE(GetCurrentPalThread()->synchronizationInfo.OwnsNamedMutex(this)); if (m_lockCount + 1 < m_lockCount) @@ -1565,12 +1604,13 @@ MutexTryAcquireLockResult NamedMutexProcessData::TryAcquireLock(DWORD timeoutMil void NamedMutexProcessData::ReleaseLock() { - if (!GetSharedData()->IsLockOwnedByCurrentThread()) + if (!IsLockOwnedByCurrentThread()) { throw SharedMemoryException(static_cast(NamedMutexError::ThreadHasNotAcquiredMutex)); } _ASSERTE(GetCurrentPalThread()->synchronizationInfo.OwnsNamedMutex(this)); + _ASSERTE(!m_hasRefFromLockOwnerThread); _ASSERTE(m_lockCount != 0); --m_lockCount; @@ -1586,23 +1626,31 @@ void NamedMutexProcessData::ReleaseLock() void NamedMutexProcessData::Abandon() { + _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired()); + NamedMutexSharedData *sharedData = GetSharedData(); - _ASSERTE(sharedData->IsLockOwnedByCurrentThread()); + _ASSERTE(IsLockOwnedByCurrentThread()); _ASSERTE(m_lockCount != 0); sharedData->SetIsAbandoned(true); m_lockCount = 0; SetLockOwnerThread(nullptr); ActuallyReleaseLock(); + + if (m_hasRefFromLockOwnerThread) + { + m_hasRefFromLockOwnerThread = false; + m_processDataHeader->DecRefCount(); + } } void NamedMutexProcessData::ActuallyReleaseLock() { - NamedMutexSharedData *sharedData = GetSharedData(); - _ASSERTE(sharedData->IsLockOwnedByCurrentThread()); + _ASSERTE(IsLockOwnedByCurrentThread()); _ASSERTE(!GetCurrentPalThread()->synchronizationInfo.OwnsNamedMutex(this)); _ASSERTE(m_lockCount == 0); + NamedMutexSharedData *sharedData = GetSharedData(); sharedData->ClearLockOwner(); #if NAMED_MUTEX_USE_PTHREAD_MUTEX diff --git a/src/coreclr/src/pal/src/thread/context.cpp b/src/coreclr/src/pal/src/thread/context.cpp index a89bdb2649f0d4..435b04715eda4c 100644 --- a/src/coreclr/src/pal/src/thread/context.cpp +++ b/src/coreclr/src/pal/src/thread/context.cpp @@ -29,7 +29,9 @@ SET_DEFAULT_DEBUG_CHANNEL(THREAD); // some headers have code with asserts, so do #include "pal/utils.h" #include "pal/virtual.h" +#if HAVE_SYS_PTRACE_H #include +#endif #include #include @@ -428,26 +430,33 @@ void CONTEXTToNativeContext(CONST CONTEXT *lpContext, native_context_t *native) } #undef ASSIGN_REG +#if !HAVE_FPREGS_WITH_CW #if HAVE_GREGSET_T || HAVE_GREGSET_T #if HAVE_GREGSET_T if (native->uc_mcontext.fpregs == nullptr) #elif HAVE___GREGSET_T if (native->uc_mcontext.__fpregs == nullptr) -#endif +#endif // HAVE_GREGSET_T { // If the pointer to the floating point state in the native context // is not valid, we can't copy floating point registers regardless of // whether CONTEXT_FLOATING_POINT is set in the CONTEXT's flags. return; } -#endif +#endif // HAVE_GREGSET_T || HAVE_GREGSET_T +#endif // !HAVE_FPREGS_WITH_CW if ((lpContext->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) { #ifdef HOST_AMD64 FPREG_ControlWord(native) = lpContext->FltSave.ControlWord; FPREG_StatusWord(native) = lpContext->FltSave.StatusWord; +#if HAVE_FPREGS_WITH_CW + FPREG_TagWord1(native) = lpContext->FltSave.TagWord >> 8; + FPREG_TagWord2(native) = lpContext->FltSave.TagWord & 0xff; +#else FPREG_TagWord(native) = lpContext->FltSave.TagWord; +#endif FPREG_ErrorOffset(native) = lpContext->FltSave.ErrorOffset; FPREG_ErrorSelector(native) = lpContext->FltSave.ErrorSelector; FPREG_DataOffset(native) = lpContext->FltSave.DataOffset; @@ -537,12 +546,13 @@ void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContex } #undef ASSIGN_REG +#if !HAVE_FPREGS_WITH_CW #if HAVE_GREGSET_T || HAVE___GREGSET_T #if HAVE_GREGSET_T if (native->uc_mcontext.fpregs == nullptr) #elif HAVE___GREGSET_T if (native->uc_mcontext.__fpregs == nullptr) -#endif +#endif // HAVE_GREGSET_T { // Reset the CONTEXT_FLOATING_POINT bit(s) and the CONTEXT_XSTATE bit(s) so it's // clear that the floating point and extended state data in the CONTEXT is not @@ -559,14 +569,19 @@ void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContex // Bail out regardless of whether the caller wanted CONTEXT_FLOATING_POINT or CONTEXT_XSTATE return; } -#endif +#endif // HAVE_GREGSET_T || HAVE___GREGSET_T +#endif // !HAVE_FPREGS_WITH_CW if ((contextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) { #ifdef HOST_AMD64 lpContext->FltSave.ControlWord = FPREG_ControlWord(native); lpContext->FltSave.StatusWord = FPREG_StatusWord(native); +#if HAVE_FPREGS_WITH_CW + lpContext->FltSave.TagWord = ((DWORD)FPREG_TagWord1(native) << 8) | FPREG_TagWord2(native); +#else lpContext->FltSave.TagWord = FPREG_TagWord(native); +#endif lpContext->FltSave.ErrorOffset = FPREG_ErrorOffset(native); lpContext->FltSave.ErrorSelector = FPREG_ErrorSelector(native); lpContext->FltSave.DataOffset = FPREG_DataOffset(native); diff --git a/src/coreclr/src/pal/src/thread/process.cpp b/src/coreclr/src/pal/src/thread/process.cpp index 49c1291adc6d8e..e002f236d47ae1 100644 --- a/src/coreclr/src/pal/src/thread/process.cpp +++ b/src/coreclr/src/pal/src/thread/process.cpp @@ -198,8 +198,11 @@ PathCharString* gSharedFilesPath = nullptr; #define CLR_SEM_MAX_NAMELEN 15 #elif defined(__APPLE__) #define CLR_SEM_MAX_NAMELEN PSEMNAMLEN -#else +#elif defined(NAME_MAX) #define CLR_SEM_MAX_NAMELEN (NAME_MAX - 4) +#else +// On Solaris, MAXNAMLEN is 512, which is higher than MAX_PATH defined by pal.h +#define CLR_SEM_MAX_NAMELEN MAX_PATH #endif static_assert_no_msg(CLR_SEM_MAX_NAMELEN <= MAX_PATH); diff --git a/src/coreclr/src/pal/src/thread/thread.cpp b/src/coreclr/src/pal/src/thread/thread.cpp index 159ef03cf0b605..fa4a6638013531 100644 --- a/src/coreclr/src/pal/src/thread/thread.cpp +++ b/src/coreclr/src/pal/src/thread/thread.cpp @@ -43,6 +43,15 @@ SET_DEFAULT_DEBUG_CHANNEL(THREAD); // some headers have code with asserts, so do #include #include #include +#elif defined(__sun) +#ifndef _KERNEL +#define _KERNEL +#define UNDEF_KERNEL +#endif +#include +#ifdef UNDEF_KERNEL +#undef _KERNEL +#endif #endif #include @@ -1441,7 +1450,11 @@ CorUnix::GetThreadTimesInternal( CPalThread *pThread; CPalThread *pTargetThread; IPalObject *pobjThread = NULL; +#ifdef __sun + int fd; +#else // __sun clockid_t cid; +#endif // __sun pThread = InternalGetCurrentThread(); @@ -1463,7 +1476,6 @@ CorUnix::GetThreadTimesInternal( #if HAVE_PTHREAD_GETCPUCLOCKID if (pthread_getcpuclockid(pTargetThread->GetPThreadSelf(), &cid) != 0) -#endif { ASSERT("Unable to get clock from thread\n", hThread); SetLastError(ERROR_INTERNAL_ERROR); @@ -1479,6 +1491,33 @@ CorUnix::GetThreadTimesInternal( pTargetThread->Unlock(pThread); goto SetTimesToZero; } +#elif defined(__sun) + timestruc_t ts; + int readResult; + char statusFilename[64]; + snprintf(statusFilename, sizeof(statusFilename), "/proc/%d/lwp/%d/lwpstatus", getpid(), pTargetThread->GetLwpId()); + fd = open(statusFilename, O_RDONLY); + if (fd == -1) + { + ASSERT("open(%s) failed; errno is %d (%s)\n", statusFilename, errno, strerror(errno)); + SetLastError(ERROR_INTERNAL_ERROR); + pTargetThread->Unlock(pThread); + goto SetTimesToZero; + } + + lwpstatus_t status; + do + { + readResult = read(fd, &status, sizeof(status)); + } + while ((readResult == -1) && (errno == EINTR)); + + close(fd); + + ts = status.pr_utime; +#else // HAVE_PTHREAD_GETCPUCLOCKID +#error "Don't know how to obtain user cpu time on this platform." +#endif // HAVE_PTHREAD_GETCPUCLOCKID pTargetThread->Unlock(pThread); @@ -1580,7 +1619,7 @@ GetThreadTimes( HRESULT PALAPI -SetThreadDescription( +SetThreadDescription( IN HANDLE hThread, IN PCWSTR lpThreadDescription) { @@ -1641,6 +1680,13 @@ CorUnix::InternalSetThreadDescription( pTargetThread->Lock(pThread); + // Ignore requests to set the main thread name because + // it causes the value returned by Process.ProcessName to change. + if ((pid_t)pTargetThread->GetThreadId() == getpid()) + { + goto InternalSetThreadDescriptionExit; + } + /* translate the wide char lpThreadDescription string to multibyte string */ nameSize = WideCharToMultiByte(CP_ACP, 0, lpThreadDescription, -1, NULL, 0, NULL, NULL); @@ -1673,7 +1719,7 @@ CorUnix::InternalSetThreadDescription( error = pthread_setname_np(pTargetThread->GetPThreadSelf(), nameBuf); - if (error != 0) + if (error != 0) { palError = ERROR_INTERNAL_ERROR; } @@ -2490,7 +2536,11 @@ CPalThread::EnsureSignalAlternateStack() altStackSize += SIGSTKSZ * 4; #endif altStackSize = ALIGN_UP(altStackSize, GetVirtualPageSize()); - void* altStack = mmap(NULL, altStackSize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_STACK | MAP_PRIVATE, -1, 0); + int flags = MAP_ANONYMOUS | MAP_PRIVATE; +#ifdef MAP_STACK + flags |= MAP_STACK; +#endif + void* altStack = mmap(NULL, altStackSize, PROT_READ | PROT_WRITE, flags, -1, 0); if (altStack != MAP_FAILED) { // create a guard page for the alternate stack diff --git a/src/coreclr/src/pal/tests/palsuite/common/palsuite.h b/src/coreclr/src/pal/tests/palsuite/common/palsuite.h index a3ae016aa45563..8cc5018925994d 100644 --- a/src/coreclr/src/pal/tests/palsuite/common/palsuite.h +++ b/src/coreclr/src/pal/tests/palsuite/common/palsuite.h @@ -17,7 +17,10 @@ #ifndef __PALSUITE_H__ #define __PALSUITE_H__ -#include +#ifndef __cplusplus +typedef unsigned short char16_t; +#endif + #include #include #include diff --git a/src/coreclr/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/CMakeLists.txt b/src/coreclr/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/CMakeLists.txt index 353e5784462926..2d2d037ca29c69 100644 --- a/src/coreclr/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/CMakeLists.txt +++ b/src/coreclr/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/CMakeLists.txt @@ -26,6 +26,11 @@ if(CLR_CMAKE_TARGET_OSX) set(EXPORTS_LINKER_OPTION1 -Wl,-exported_symbols_list,${EXPORTS_FILE1}) endif(CLR_CMAKE_TARGET_OSX) +if(CLR_CMAKE_TARGET_SUNOS) + # Add linker exports file option + set(EXPORTS_LINKER_OPTION -Wl,-M,${EXPORTS_FILE}) +endif(CLR_CMAKE_TARGET_SUNOS) + set(DLL1SOURCES dlltest1.cpp) add_library(paltest_pal_sxs_test1_dll1 SHARED ${DLL1SOURCES}) add_custom_target(dlltest1_exports DEPENDS ${EXPORTS_FILE1}) diff --git a/src/coreclr/src/pal/tests/palsuite/threading/NamedMutex/test1/namedmutex.cpp b/src/coreclr/src/pal/tests/palsuite/threading/NamedMutex/test1/namedmutex.cpp index 6635d76a80a074..761bb47b5c6be0 100644 --- a/src/coreclr/src/pal/tests/palsuite/threading/NamedMutex/test1/namedmutex.cpp +++ b/src/coreclr/src/pal/tests/palsuite/threading/NamedMutex/test1/namedmutex.cpp @@ -60,9 +60,12 @@ extern bool WriteHeaderInfo(const char *path, char sharedMemoryType, char versio { \ if (!g_isParent) \ { \ - Trace("Child process: "); \ + Trace("'paltest_namedmutex_test1' child process failed at line %u. Expression: " #expression "\n", __LINE__); \ + } \ + else \ + { \ + Trace("'paltest_namedmutex_test1' failed at line %u. Expression: " #expression "\n", __LINE__); \ } \ - Trace("'paltest_namedmutex_test1' failed at line %u. Expression: " #expression "\n", __LINE__); \ fflush(stdout); \ return false; \ } \ @@ -516,7 +519,7 @@ bool MutualExclusionTests_Parent() TestAssert(WaitForSingleObject(m, static_cast(-1)) == WAIT_OBJECT_0); // lock the mutex with no timeout and release TestAssert(m.Release()); - UninitializeParent(testName, parentEvents); + TestAssert(UninitializeParent(testName, parentEvents)); return true; } @@ -539,7 +542,7 @@ DWORD PALAPI MutualExclusionTests_Child(void *arg = nullptr) TestAssert(m.Release()); // release the lock } - UninitializeChild(childRunningEvent, parentEvents, childEvents); + TestAssert(UninitializeChild(childRunningEvent, parentEvents, childEvents)); return 0; } @@ -622,7 +625,7 @@ bool LifetimeTests_Parent() TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child closes second reference TestAssert(!TestFileExists(BuildGlobalShmFilePath(testName, name, NamePrefix))); - UninitializeParent(testName, parentEvents); + TestAssert(UninitializeParent(testName, parentEvents)); return true; } @@ -653,7 +656,7 @@ DWORD PALAPI LifetimeTests_Child(void *arg = nullptr) TestAssert(YieldToParent(parentEvents, childEvents, ei)); // parent verifies } - UninitializeChild(childRunningEvent, parentEvents, childEvents); + TestAssert(UninitializeChild(childRunningEvent, parentEvents, childEvents)); return 0; } @@ -702,11 +705,11 @@ bool AbandonTests_Parent() TestAssert(parentEvents[1].Release()); // child sleeps for short duration and abandons the mutex TestAssert(WaitForSingleObject(m, FailTimeoutMilliseconds) == WAIT_ABANDONED_0); // attempt to lock and see abandoned mutex - UninitializeParent(testName, parentEvents, false /* releaseParentEvents */); // parent events are released above + TestAssert(UninitializeParent(testName, parentEvents, false /* releaseParentEvents */)); // parent events are released above } // Verify that the mutex lock is owned by this thread, by starting a new thread and trying to lock it - StartThread(AbandonTests_Child_TryLock); + TestAssert(StartThread(AbandonTests_Child_TryLock)); { AutoCloseMutexHandle parentEvents[2], childEvents[2]; TestAssert(InitializeParent(testName, parentEvents, childEvents)); @@ -714,11 +717,11 @@ bool AbandonTests_Parent() TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child tries to lock mutex - UninitializeParent(testName, parentEvents); + TestAssert(UninitializeParent(testName, parentEvents)); } // Verify that the mutex lock is owned by this thread, by starting a new process and trying to lock it - StartProcess("AbandonTests_Child_TryLock"); + TestAssert(StartProcess("AbandonTests_Child_TryLock")); AutoCloseMutexHandle parentEvents[2], childEvents[2]; TestAssert(InitializeParent(testName, parentEvents, childEvents)); int ei = 0; @@ -730,7 +733,7 @@ bool AbandonTests_Parent() TestAssert(WaitForSingleObject(m, FailTimeoutMilliseconds) == WAIT_OBJECT_0); // lock again to see it's not abandoned anymore TestAssert(m.Release()); - UninitializeParent(testName, parentEvents, false /* releaseParentEvents */); // parent events are released above + TestAssert(UninitializeParent(testName, parentEvents)); // Since the child abandons the mutex, and a child process may not release the file lock on the shared memory file before // indicating completion to the parent, make sure to delete the shared memory file by repeatedly opening/closing the mutex @@ -772,7 +775,7 @@ DWORD PALAPI AbandonTests_Child_GracefulExit_Close(void *arg = nullptr) m.Close(); // close mutex without releasing lock } - UninitializeChild(childRunningEvent, parentEvents, childEvents); + TestAssert(UninitializeChild(childRunningEvent, parentEvents, childEvents)); return 0; } @@ -801,7 +804,7 @@ DWORD AbandonTests_Child_GracefulExit_NoClose(void *arg = nullptr) m.Abandon(); // don't close the mutex } - UninitializeChild(childRunningEvent, parentEvents, childEvents); + TestAssert(UninitializeChild(childRunningEvent, parentEvents, childEvents)); return 0; } @@ -830,7 +833,7 @@ DWORD AbandonTests_Child_AbruptExit(void *arg = nullptr) m.Abandon(); // don't close the mutex } - UninitializeChild(childRunningEvent, parentEvents, childEvents); + TestAssert(UninitializeChild(childRunningEvent, parentEvents, childEvents)); } TestAssert(test_kill(currentPid) == 0); // abandon the mutex abruptly @@ -894,7 +897,7 @@ DWORD AbandonTests_Child_FileLocksNotInherited_Child_AbruptExit(void *arg = null m.Close(); // close mutex without releasing lock (root parent expects the mutex to be abandoned) } - UninitializeChild(childRunningEvent, parentEvents, childEvents); + TestAssert(UninitializeChild(childRunningEvent, parentEvents, childEvents)); return 0; } @@ -917,14 +920,12 @@ DWORD PALAPI AbandonTests_Child_TryLock(void *arg) TestAssert(WaitForSingleObject(m, g_expectedTimeoutMilliseconds) == WAIT_TIMEOUT); } - UninitializeChild(childRunningEvent, parentEvents, childEvents); + TestAssert(UninitializeChild(childRunningEvent, parentEvents, childEvents)); return 0; } bool AbandonTests() { - const char *testName = "AbandonTests"; - // Abandon by graceful exit where the lock owner closes the mutex before releasing it, unblocks a waiter TestAssert(StartThread(AbandonTests_Child_GracefulExit_Close)); TestAssert(AbandonTests_Parent()); @@ -945,6 +946,151 @@ bool AbandonTests() return true; } +bool LockAndCloseWithoutThreadExitTests_Parent_CloseOnSameThread() +{ + const char *testName = "LockAndCloseWithoutThreadExitTests"; + + AutoCloseMutexHandle parentEvents[2], childEvents[2]; + TestAssert(InitializeParent(testName, parentEvents, childEvents)); + int ei = 0; + char name[MaxPathSize]; + AutoCloseMutexHandle m; + + TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix)); + TestAssert(m != nullptr); + + TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child locks mutex and closes second reference to mutex on lock-owner thread + TestAssert(WaitForSingleObject(m, 0) == WAIT_TIMEOUT); // attempt to lock and fail + + TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child closes last reference to mutex on lock-owner thread + TestAssert(WaitForSingleObject(m, 0) == WAIT_ABANDONED_0); // attempt to lock and see abandoned mutex + TestAssert(m.Release()); + + TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child exits + TestAssert(TestFileExists(BuildGlobalShmFilePath(testName, name, NamePrefix))); + m.Close(); + TestAssert(!TestFileExists(BuildGlobalShmFilePath(testName, name, NamePrefix))); + + TestAssert(UninitializeParent(testName, parentEvents)); + return true; +} + +DWORD PALAPI LockAndCloseWithoutThreadExitTests_Child_CloseOnSameThread(void *arg = nullptr) +{ + const char *testName = "LockAndCloseWithoutThreadExitTests"; + + TestAssert(test_getpid() != g_parentPid); // this test needs to run in a separate process + + AutoCloseMutexHandle childRunningEvent, parentEvents[2], childEvents[2]; + TestAssert(InitializeChild(testName, childRunningEvent, parentEvents, childEvents)); + int ei = 0; + char name[MaxPathSize]; + + // ... parent waits for child to lock and close second reference to mutex + AutoCloseMutexHandle m(TestOpenMutex(BuildName(testName, name, GlobalPrefix, NamePrefix))); + TestAssert(m != nullptr); + TestAssert(WaitForSingleObject(m, 0) == WAIT_OBJECT_0); + TestAssert(AutoCloseMutexHandle(TestOpenMutex(BuildName(testName, name, GlobalPrefix, NamePrefix))) != nullptr); + TestAssert(YieldToParent(parentEvents, childEvents, ei)); // parent waits for child to close last reference to mutex + + m.Close(); // close mutex on lock-owner thread without releasing lock + TestAssert(YieldToParent(parentEvents, childEvents, ei)); // parent verifies while this thread is still active + + TestAssert(UninitializeChild(childRunningEvent, parentEvents, childEvents)); + return 0; +} + +DWORD PALAPI LockAndCloseWithoutThreadExitTests_ChildThread_CloseMutex(void *arg); + +bool LockAndCloseWithoutThreadExitTests_Parent_CloseOnDifferentThread() +{ + const char *testName = "LockAndCloseWithoutThreadExitTests"; + + AutoCloseMutexHandle parentEvents[2], childEvents[2]; + TestAssert(InitializeParent(testName, parentEvents, childEvents)); + int ei = 0; + char name[MaxPathSize]; + AutoCloseMutexHandle m; + + TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix)); + TestAssert(m != nullptr); + + TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child locks mutex and closes second reference to mutex on lock-owner thread + TestAssert(WaitForSingleObject(m, 0) == WAIT_TIMEOUT); // attempt to lock and fail + + TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child closes last reference to mutex on non-lock-owner thread + TestAssert(WaitForSingleObject(m, 0) == WAIT_TIMEOUT); // attempt to lock and fail + m.Close(); + m = TestOpenMutex(BuildName(testName, name, GlobalPrefix, NamePrefix)); + TestAssert(m != nullptr); // child has implicit reference to mutex + + TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child closes new reference to mutex on lock-owner thread + TestAssert(WaitForSingleObject(m, 0) == WAIT_ABANDONED_0); // attempt to lock and see abandoned mutex + TestAssert(m.Release()); + + TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child exits + TestAssert(TestFileExists(BuildGlobalShmFilePath(testName, name, NamePrefix))); + m.Close(); + TestAssert(!TestFileExists(BuildGlobalShmFilePath(testName, name, NamePrefix))); + + TestAssert(UninitializeParent(testName, parentEvents)); + return true; +} + +DWORD PALAPI LockAndCloseWithoutThreadExitTests_Child_CloseOnDifferentThread(void *arg = nullptr) +{ + const char *testName = "LockAndCloseWithoutThreadExitTests"; + + TestAssert(test_getpid() != g_parentPid); // this test needs to run in a separate process + + AutoCloseMutexHandle childRunningEvent, parentEvents[2], childEvents[2]; + TestAssert(InitializeChild(testName, childRunningEvent, parentEvents, childEvents)); + int ei = 0; + char name[MaxPathSize]; + + // ... parent waits for child to lock and close second reference to mutex + AutoCloseMutexHandle m(TestOpenMutex(BuildName(testName, name, GlobalPrefix, NamePrefix))); + TestAssert(m != nullptr); + TestAssert(WaitForSingleObject(m, 0) == WAIT_OBJECT_0); + TestAssert(AutoCloseMutexHandle(TestOpenMutex(BuildName(testName, name, GlobalPrefix, NamePrefix))) != nullptr); + TestAssert(YieldToParent(parentEvents, childEvents, ei)); // parent waits for child to close last reference to mutex + + // Close the mutex on a thread that is not the lock-owner thread, without releasing the lock + HANDLE closeMutexThread = nullptr; + TestAssert(StartThread(LockAndCloseWithoutThreadExitTests_ChildThread_CloseMutex, (HANDLE)m, &closeMutexThread)); + TestAssert(closeMutexThread != nullptr); + TestAssert(WaitForSingleObject(closeMutexThread, FailTimeoutMilliseconds) == WAIT_OBJECT_0); + TestAssert(CloseHandle(closeMutexThread)); + m.Abandon(); // mutex is already closed, don't close it again + TestAssert(YieldToParent(parentEvents, childEvents, ei)); // parent verifies while this lock-owner thread is still active + + m = TestOpenMutex(BuildName(testName, name, GlobalPrefix, NamePrefix)); + TestAssert(m != nullptr); + m.Close(); // close mutex on lock-owner thread without releasing lock + TestAssert(YieldToParent(parentEvents, childEvents, ei)); // parent verifies while this thread is still active + + TestAssert(UninitializeChild(childRunningEvent, parentEvents, childEvents)); + return 0; +} + +DWORD PALAPI LockAndCloseWithoutThreadExitTests_ChildThread_CloseMutex(void *arg) +{ + TestAssert(arg != nullptr); + AutoCloseMutexHandle((HANDLE)arg).Close(); + return 0; +} + +bool LockAndCloseWithoutThreadExitTests() +{ + TestAssert(StartProcess("LockAndCloseWithoutThreadExitTests_Child_CloseOnSameThread")); + TestAssert(LockAndCloseWithoutThreadExitTests_Parent_CloseOnSameThread()); + + TestAssert(StartProcess("LockAndCloseWithoutThreadExitTests_Child_CloseOnDifferentThread")); + TestAssert(LockAndCloseWithoutThreadExitTests_Parent_CloseOnDifferentThread()); + + return true; +} + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Test harness @@ -954,7 +1100,8 @@ bool (*const (TestList[]))() = HeaderMismatchTests, MutualExclusionTests, LifetimeTests, - AbandonTests + AbandonTests, + LockAndCloseWithoutThreadExitTests }; bool RunTests() @@ -1125,6 +1272,14 @@ int __cdecl main(int argc, char **argv) { AbandonTests_Child_TryLock(); } + else if (test_strcmp(argv[2], "LockAndCloseWithoutThreadExitTests_Child_CloseOnSameThread") == 0) + { + LockAndCloseWithoutThreadExitTests_Child_CloseOnSameThread(); + } + else if (test_strcmp(argv[2], "LockAndCloseWithoutThreadExitTests_Child_CloseOnDifferentThread") == 0) + { + LockAndCloseWithoutThreadExitTests_Child_CloseOnDifferentThread(); + } ExitProcess(PASS); return PASS; } diff --git a/src/coreclr/src/pal/tools/gen-dactable-rva.sh b/src/coreclr/src/pal/tools/gen-dactable-rva.sh index fd4fa76c6eaab4..c1fc13118deb3a 100644 --- a/src/coreclr/src/pal/tools/gen-dactable-rva.sh +++ b/src/coreclr/src/pal/tools/gen-dactable-rva.sh @@ -1 +1 @@ -${NM:-nm} $1 | grep g_dacTable | cut -f 1 -d' ' | head -n 1 | awk '{ print "#define DAC_TABLE_RVA 0x" $1}' > $2 +${NM:-nm} -P -t x $1 | awk -F ' ' '/g_dacTable/ { print "#define DAC_TABLE_RVA 0x" substr("0000000000000000" $3, length($3) + 1); exit }' > $2 diff --git a/src/coreclr/src/pal/tools/set-cmake-path.ps1 b/src/coreclr/src/pal/tools/set-cmake-path.ps1 index f367ad127c3ff7..689c8c5596a555 100644 --- a/src/coreclr/src/pal/tools/set-cmake-path.ps1 +++ b/src/coreclr/src/pal/tools/set-cmake-path.ps1 @@ -33,7 +33,7 @@ function GetCMakeInfo($regKey) function LocateCMake { - $errorMsg = "CMake is a pre-requisite to build this repository but it was not found on the path. Please install CMake from http://www.cmake.org/download/ and ensure it is on your path." + $errorMsg = "CMake is a pre-requisite to build this repository but it was not found on the path. Please install CMake from https://cmake.org/download/ and ensure it is on your path." $inPathPath = (get-command cmake.exe -ErrorAction SilentlyContinue) if ($inPathPath -ne $null) { # Resolve the first version of CMake if multiple commands are found @@ -64,7 +64,7 @@ try { $version = [Version]$(& $cmakePath --version | Select-String -Pattern '\d+\.\d+\.\d+' | %{$_.Matches.Value}) if ($version -lt [Version]"3.14.0") { - Throw "This repository requires CMake 3.14. The newest version of CMake installed is $version. Please install CMake 3.14 or newer from http://www.cmake.org/download/ and ensure it is on your path." + Throw "This repository requires CMake 3.14. The newest version of CMake installed is $version. Please install CMake 3.14 or newer from https://cmake.org/download/ and ensure it is on your path." } [System.Console]::WriteLine("set CMakePath=" + $cmakePath) diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/MethodReadOnlyDataNode.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/MethodReadOnlyDataNode.cs new file mode 100644 index 00000000000000..7c1ae117056b26 --- /dev/null +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/MethodReadOnlyDataNode.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; + +using Internal.Text; +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + public class MethodReadOnlyDataNode : ObjectNode, ISymbolDefinitionNode + { + private MethodDesc _owningMethod; + private ObjectData _data; + + public MethodReadOnlyDataNode(MethodDesc owningMethod) + { + _owningMethod = owningMethod; + } + + public override ObjectNodeSection Section => ObjectNodeSection.ReadOnlyDataSection; + public override bool StaticDependenciesAreComputed => _data != null; + + public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) + { + sb.Append("__readonlydata_" + nameMangler.GetMangledMethodName(_owningMethod)); + } + public int Offset => 0; + public override bool IsShareable => true; + + public void InitializeData(ObjectData data) + { + Debug.Assert(_data == null); + _data = data; + } + + public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) + { + return _data; + } + + protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); + +#if !SUPPORT_JIT + public override int ClassCode => 674507768; + + public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) + { + return comparer.Compare(_owningMethod, ((MethodReadOnlyDataNode)other)._owningMethod); + } +#endif + } +} + diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs index b89b9482403b7c..5a672f953c96ba 100644 --- a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs @@ -39,16 +39,17 @@ public bool IsStandardSection { get { - return this == DataSection || this == ReadOnlyDataSection || this == FoldableReadOnlyDataSection || this == TextSection || this == XDataSection; + return this == DataSection || this == ReadOnlyDataSection || this == FoldableReadOnlyDataSection || this == TextSection || this == XDataSection || this == BssSection; } } public static readonly ObjectNodeSection XDataSection = new ObjectNodeSection("xdata", SectionType.ReadOnly); public static readonly ObjectNodeSection DataSection = new ObjectNodeSection("data", SectionType.Writeable); public static readonly ObjectNodeSection ReadOnlyDataSection = new ObjectNodeSection("rdata", SectionType.ReadOnly); - public static readonly ObjectNodeSection FoldableReadOnlyDataSection = new ObjectNodeSection("rdata$F", SectionType.ReadOnly); + public static readonly ObjectNodeSection FoldableReadOnlyDataSection = new ObjectNodeSection("rdata", SectionType.ReadOnly); public static readonly ObjectNodeSection TextSection = new ObjectNodeSection("text", SectionType.Executable); public static readonly ObjectNodeSection TLSSection = new ObjectNodeSection("TLS", SectionType.Writeable); + public static readonly ObjectNodeSection BssSection = new ObjectNodeSection("bss", SectionType.Writeable); public static readonly ObjectNodeSection ManagedCodeWindowsContentSection = new ObjectNodeSection(".managedcode$I", SectionType.Executable); public static readonly ObjectNodeSection FoldableManagedCodeWindowsContentSection = new ObjectNodeSection(".managedcode$I", SectionType.Executable); public static readonly ObjectNodeSection ManagedCodeUnixContentSection = new ObjectNodeSection("__managedcode", SectionType.Executable); diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Relocation.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Relocation.cs index 13d7358dd65b1c..6c38500d6856e3 100644 --- a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Relocation.cs +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Relocation.cs @@ -329,6 +329,27 @@ public static unsafe long ReadValue(RelocType relocType, void* location) } } + /// + /// Return file relocation type for the given relocation type. If the relocation + /// doesn't require a file-level relocation entry in the .reloc section, 0 is returned + /// corresponding to the IMAGE_REL_BASED_ABSOLUTE no-op relocation record. + /// + /// Relocation type + /// File-level relocation type or 0 (IMAGE_REL_BASED_ABSOLUTE) if none is required + public static RelocType GetFileRelocationType(RelocType relocationType) + { + switch (relocationType) + { + case RelocType.IMAGE_REL_BASED_HIGHLOW: + case RelocType.IMAGE_REL_BASED_DIR64: + case RelocType.IMAGE_REL_BASED_THUMB_MOV32: + return relocationType; + + default: + return RelocType.IMAGE_REL_BASED_ABSOLUTE; + } + } + public override string ToString() { return $"{Target} ({RelocType}, 0x{Offset:X})"; diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/SettableReadOnlyDataBlob.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/SettableReadOnlyDataBlob.cs deleted file mode 100644 index bf7de904bb3518..00000000000000 --- a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/SettableReadOnlyDataBlob.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Diagnostics; - -using Internal.Text; -using Internal.TypeSystem; - -namespace ILCompiler.DependencyAnalysis -{ - public class SettableReadOnlyDataBlob : ObjectNode, ISymbolDefinitionNode - { - private Utf8String _name; - private ObjectNodeSection _section; - private ObjectData _data; - - public SettableReadOnlyDataBlob(Utf8String name, ObjectNodeSection section) - { - _name = name; - _section = section; - } - - public override ObjectNodeSection Section => _section; - public override bool StaticDependenciesAreComputed => _data != null; - - public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) - { - sb.Append(_name); - } - public int Offset => 0; - public override bool IsShareable => true; - - public void InitializeData(ObjectData data) - { - Debug.Assert(_data == null); - _data = data; - } - - public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) - { - return _data; - } - - protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); - -#if !SUPPORT_JIT - public override int ClassCode => 674507768; - - public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) - { - return _name.CompareTo(((SettableReadOnlyDataBlob)other)._name); - } -#endif - } -} - diff --git a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/TargetRegisterMap.cs b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/TargetRegisterMap.cs index 808f8ed03c5836..7d76bf5259b78c 100644 --- a/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/TargetRegisterMap.cs +++ b/src/coreclr/src/tools/Common/Compiler/DependencyAnalysis/Target_X64/TargetRegisterMap.cs @@ -34,6 +34,8 @@ public TargetRegisterMap(TargetOS os) case TargetOS.Linux: case TargetOS.OSX: case TargetOS.FreeBSD: + case TargetOS.SunOS: + case TargetOS.NetBSD: Arg0 = Register.RDI; Arg1 = Register.RSI; Arg2 = Register.RDX; diff --git a/src/coreclr/src/tools/Common/Compiler/HardwareIntrinsicHelpers.cs b/src/coreclr/src/tools/Common/Compiler/HardwareIntrinsicHelpers.cs index 8ec5a7712b9fd6..1481a74e77b900 100644 --- a/src/coreclr/src/tools/Common/Compiler/HardwareIntrinsicHelpers.cs +++ b/src/coreclr/src/tools/Common/Compiler/HardwareIntrinsicHelpers.cs @@ -11,7 +11,7 @@ namespace ILCompiler { - public static class HardwareIntrinsicHelpers + public static partial class HardwareIntrinsicHelpers { /// /// Gets a value indicating whether this is a hardware intrinsic on the platform that we're compiling for. @@ -20,156 +20,5 @@ public static bool IsHardwareIntrinsic(MethodDesc method) { return !string.IsNullOrEmpty(InstructionSetSupport.GetHardwareIntrinsicId(method.Context.Target.Architecture, method.OwningType)); } - -#if !READYTORUN - public static bool IsIsSupportedMethod(MethodDesc method) - { - return method.Name == "get_IsSupported"; - } - - public static MethodIL GetUnsupportedImplementationIL(MethodDesc method) - { - // The implementation of IsSupported for codegen backends that don't support hardware intrinsics - // at all is to return 0. - if (IsIsSupportedMethod(method)) - { - return new ILStubMethodIL(method, - new byte[] { - (byte)ILOpcode.ldc_i4_0, - (byte)ILOpcode.ret - }, - Array.Empty(), null); - } - - // Other methods throw PlatformNotSupportedException - MethodDesc throwPnse = method.Context.GetHelperEntryPoint("ThrowHelpers", "ThrowPlatformNotSupportedException"); - - return new ILStubMethodIL(method, - new byte[] { - (byte)ILOpcode.call, 1, 0, 0, 0, - (byte)ILOpcode.br_s, unchecked((byte)-7), - }, - Array.Empty(), - new object[] { throwPnse }); - } - - /// - /// Generates IL for the IsSupported property that reads this information from a field initialized by the runtime - /// at startup. Returns null for hardware intrinsics whose support level is known at compile time - /// (i.e. they're known to be always supported or always unsupported). - /// - public static MethodIL EmitIsSupportedIL(MethodDesc method, FieldDesc isSupportedField) - { - Debug.Assert(IsIsSupportedMethod(method)); - Debug.Assert(isSupportedField.IsStatic && isSupportedField.FieldType.IsWellKnownType(WellKnownType.Int32)); - - TargetDetails target = method.Context.Target; - MetadataType owningType = (MetadataType)method.OwningType; - - // Check for case of nested "X64" types - if (owningType.Name == "X64") - { - if (target.Architecture != TargetArchitecture.X64) - return null; - - // Un-nest the type so that we can do a name match - owningType = (MetadataType)owningType.ContainingType; - } - - int flag; - if ((target.Architecture == TargetArchitecture.X64 || target.Architecture == TargetArchitecture.X86) - && owningType.Namespace == "System.Runtime.Intrinsics.X86") - { - switch (owningType.Name) - { - case "Aes": - flag = XArchIntrinsicConstants.Aes; - break; - case "Pclmulqdq": - flag = XArchIntrinsicConstants.Pclmulqdq; - break; - case "Sse3": - flag = XArchIntrinsicConstants.Sse3; - break; - case "Ssse3": - flag = XArchIntrinsicConstants.Ssse3; - break; - case "Lzcnt": - flag = XArchIntrinsicConstants.Lzcnt; - break; - // NOTE: this switch is complemented by IsKnownSupportedIntrinsicAtCompileTime - // in the method below. - default: - return null; - } - } - else - { - return null; - } - - var emit = new ILEmitter(); - ILCodeStream codeStream = emit.NewCodeStream(); - - codeStream.Emit(ILOpcode.ldsfld, emit.NewToken(isSupportedField)); - codeStream.EmitLdc(flag); - codeStream.Emit(ILOpcode.and); - codeStream.EmitLdc(0); - codeStream.Emit(ILOpcode.cgt_un); - codeStream.Emit(ILOpcode.ret); - - return emit.Link(method); - } - - /// - /// Gets a value indicating whether the support for a given intrinsic is known at compile time. - /// - public static bool IsKnownSupportedIntrinsicAtCompileTime(MethodDesc method) - { - TargetDetails target = method.Context.Target; - - if (target.Architecture == TargetArchitecture.X64 - || target.Architecture == TargetArchitecture.X86) - { - var owningType = (MetadataType)method.OwningType; - if (owningType.Name == "X64") - { - if (target.Architecture != TargetArchitecture.X64) - return true; - owningType = (MetadataType)owningType.ContainingType; - } - - if (owningType.Namespace != "System.Runtime.Intrinsics.X86") - return true; - - // Sse and Sse2 are baseline required intrinsics. - // RyuJIT also uses Sse41/Sse42 with the general purpose Vector APIs. - // RyuJIT only respects Popcnt if Sse41/Sse42 is also enabled. - // Avx/Avx2/Bmi1/Bmi2 require VEX encoding and RyuJIT currently can't enable them - // without enabling VEX encoding everywhere. We don't support them. - // This list complements EmitIsSupportedIL above. - return owningType.Name == "Sse" || owningType.Name == "Sse2" - || owningType.Name == "Sse41" || owningType.Name == "Sse42" - || owningType.Name == "Popcnt" - || owningType.Name == "Bmi1" || owningType.Name == "Bmi2" - || owningType.Name == "Avx" || owningType.Name == "Avx2"; - } - - return false; - } - - // Keep this enumeration in sync with startup.cpp in the native runtime. - private static class XArchIntrinsicConstants - { - public const int Aes = 0x0001; - public const int Pclmulqdq = 0x0002; - public const int Sse3 = 0x0004; - public const int Ssse3 = 0x0008; - public const int Sse41 = 0x0010; - public const int Sse42 = 0x0020; - public const int Popcnt = 0x0040; - public const int Lzcnt = 0x0080; - } -#endif // !READYTORUN } } diff --git a/src/coreclr/src/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs b/src/coreclr/src/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs index 981eef3b43d028..12ded51464c64d 100644 --- a/src/coreclr/src/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs +++ b/src/coreclr/src/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs @@ -90,12 +90,17 @@ public override bool ComputeContainsGCPointers(DefType type) public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) { - return _fallbackAlgorithm.ComputeValueTypeShapeCharacteristics(type); - } - - public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) - { - return _fallbackAlgorithm.ComputeHomogeneousFloatAggregateElementType(type); + if (type.Context.Target.Architecture == TargetArchitecture.ARM64 && + type.Instantiation[0].IsPrimitiveNumeric) + { + return type.InstanceFieldSize.AsInt switch + { + 8 => ValueTypeShapeCharacteristics.Vector64Aggregate, + 16 => ValueTypeShapeCharacteristics.Vector128Aggregate, + _ => ValueTypeShapeCharacteristics.None + }; + } + return ValueTypeShapeCharacteristics.None; } public static bool IsVectorType(DefType type) diff --git a/src/coreclr/src/tools/Common/Internal/Runtime/ReadyToRunInstructionSet.cs b/src/coreclr/src/tools/Common/Internal/Runtime/ReadyToRunInstructionSet.cs index 0db969fdc9701f..632b7a9d2df5a8 100644 --- a/src/coreclr/src/tools/Common/Internal/Runtime/ReadyToRunInstructionSet.cs +++ b/src/coreclr/src/tools/Common/Internal/Runtime/ReadyToRunInstructionSet.cs @@ -35,6 +35,7 @@ public enum ReadyToRunInstructionSet Sha1=19, Sha256=20, Atomics=21, + X86Base=22, } } diff --git a/src/coreclr/src/tools/Common/Internal/Runtime/ReadyToRunInstructionSetHelper.cs b/src/coreclr/src/tools/Common/Internal/Runtime/ReadyToRunInstructionSetHelper.cs index 97fe00b465bc80..16cf47f43d686f 100644 --- a/src/coreclr/src/tools/Common/Internal/Runtime/ReadyToRunInstructionSetHelper.cs +++ b/src/coreclr/src/tools/Common/Internal/Runtime/ReadyToRunInstructionSetHelper.cs @@ -46,6 +46,8 @@ public static class ReadyToRunInstructionSetHelper { switch (instructionSet) { + case InstructionSet.X64_X86Base: return ReadyToRunInstructionSet.X86Base; + case InstructionSet.X64_X86Base_X64: return ReadyToRunInstructionSet.X86Base; case InstructionSet.X64_SSE: return ReadyToRunInstructionSet.Sse; case InstructionSet.X64_SSE_X64: return ReadyToRunInstructionSet.Sse; case InstructionSet.X64_SSE2: return ReadyToRunInstructionSet.Sse2; @@ -80,6 +82,7 @@ public static class ReadyToRunInstructionSetHelper { switch (instructionSet) { + case InstructionSet.X86_X86Base: return ReadyToRunInstructionSet.X86Base; case InstructionSet.X86_SSE: return ReadyToRunInstructionSet.Sse; case InstructionSet.X86_SSE2: return ReadyToRunInstructionSet.Sse2; case InstructionSet.X86_SSE3: return ReadyToRunInstructionSet.Sse3; diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs index 53cfc0054f888e..6b2869f23967e1 100644 --- a/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs @@ -314,7 +314,7 @@ unsafe partial class CorInfoImpl [UnmanagedFunctionPointerAttribute(default(CallingConvention))] delegate void __MethodCompileComplete(IntPtr _this, IntPtr* ppException, CORINFO_METHOD_STRUCT_* methHnd); [UnmanagedFunctionPointerAttribute(default(CallingConvention))] - delegate void* __getTailCallCopyArgsThunk(IntPtr _this, IntPtr* ppException, CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags); + [return: MarshalAs(UnmanagedType.I1)]delegate bool __getTailCallHelpers(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, ref CORINFO_TAILCALL_HELPERS pResult); [UnmanagedFunctionPointerAttribute(default(CallingConvention))] [return: MarshalAs(UnmanagedType.I1)]delegate bool __convertPInvokeCalliToCall(IntPtr _this, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN pResolvedToken, [MarshalAs(UnmanagedType.I1)]bool mustConvert); [UnmanagedFunctionPointerAttribute(default(CallingConvention))] @@ -2429,17 +2429,17 @@ static void _MethodCompileComplete(IntPtr thisHandle, IntPtr* ppException, CORIN } } - static void* _getTailCallCopyArgsThunk(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) + [return: MarshalAs(UnmanagedType.I1)]static bool _getTailCallHelpers(IntPtr thisHandle, IntPtr* ppException, ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, ref CORINFO_TAILCALL_HELPERS pResult) { var _this = GetThis(thisHandle); try { - return _this.getTailCallCopyArgsThunk(pSig, flags); + return _this.getTailCallHelpers(ref callToken, sig, flags, ref pResult); } catch (Exception ex) { *ppException = _this.AllocException(ex); - return default(void*); + return default(bool); } } @@ -3145,7 +3145,7 @@ static IntPtr GetUnmanagedCallbacks(out Object keepAlive) var d150 = new __MethodCompileComplete(_MethodCompileComplete); callbacks[150] = Marshal.GetFunctionPointerForDelegate(d150); delegates[150] = d150; - var d151 = new __getTailCallCopyArgsThunk(_getTailCallCopyArgsThunk); + var d151 = new __getTailCallHelpers(_getTailCallHelpers); callbacks[151] = Marshal.GetFunctionPointerForDelegate(d151); delegates[151] = d151; var d152 = new __convertPInvokeCalliToCall(_convertPInvokeCalliToCall); diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.Intrinsics.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.Intrinsics.cs index 0c4d552102e81b..30bc7f772362b2 100644 --- a/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.Intrinsics.cs +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.Intrinsics.cs @@ -142,6 +142,7 @@ static IntrinsicHashtable InitializeIntrinsicHashtable() table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StubHelpers_GetStubContext, "GetStubContext", "System.StubHelpers", "StubHelpers"); // interop-specific // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StubHelpers_GetStubContextAddr, "GetStubContextAddr", "System.StubHelpers", "StubHelpers"); // interop-specific // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StubHelpers_GetNDirectTarget, "GetNDirectTarget", "System.StubHelpers", "StubHelpers"); // interop-specific + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_StubHelpers_NextCallReturnAddress, "NextCallReturnAddress", "System.StubHelpers", "StubHelpers"); // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedAdd32, "Add", System.Threading", "Interlocked"); // unused // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedAdd64, "Add", System.Threading", "Interlocked"); // unused table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedXAdd32, "ExchangeAdd", "System.Threading", "Interlocked"); @@ -151,6 +152,7 @@ static IntrinsicHashtable InitializeIntrinsicHashtable() table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedCmpXchg32, "CompareExchange", "System.Threading", "Interlocked"); // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_InterlockedCmpXchg64, "CompareExchange", "System.Threading", "Interlocked"); // ambiguous match table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_MemoryBarrier, "MemoryBarrier", "System.Threading", "Interlocked"); + table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_MemoryBarrierLoad, "LoadBarrier", "System.Threading", "Interlocked"); // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_GetCurrentManagedThread, "GetCurrentThreadNative", "System", "Thread"); // not in .NET Core // table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_GetManagedThreadId, "get_ManagedThreadId", "System", "Thread"); // not in .NET Core table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_ByReference_Ctor, ".ctor", "System", "ByReference`1"); @@ -162,7 +164,7 @@ static IntrinsicHashtable InitializeIntrinsicHashtable() table.Add(CorInfoIntrinsics.CORINFO_INTRINSIC_GetRawHandle, "AllocatorOf", "System", "Activator"); // If this assert fails, make sure to add the new intrinsics to the table above and update the expected count below. - Debug.Assert((int)CorInfoIntrinsics.CORINFO_INTRINSIC_Count == 54); + Debug.Assert((int)CorInfoIntrinsics.CORINFO_INTRINSIC_Count == 56, "Please update intrinsic hash table"); return table; } diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs index 064327ac434719..205304c49a36b9 100644 --- a/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoImpl.cs @@ -18,6 +18,7 @@ using Internal.IL; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using Internal.TypeSystem.Interop; using Internal.CorConstants; using ILCompiler; @@ -59,10 +60,10 @@ private enum ImageFileMachine private ExceptionDispatchInfo _lastException; - [DllImport(JitLibrary, CallingConvention=CallingConvention.StdCall)] // stdcall in CoreCLR! + [DllImport(JitLibrary, CallingConvention = CallingConvention.StdCall)] // stdcall in CoreCLR! private extern static IntPtr jitStartup(IntPtr host); - [DllImport(JitLibrary, CallingConvention=CallingConvention.StdCall)] + [DllImport(JitLibrary, CallingConvention = CallingConvention.StdCall)] private extern static IntPtr getJit(); [DllImport(JitSupportLibrary)] @@ -79,7 +80,7 @@ private static CorInfoImpl GetThis(IntPtr thisHandle) } [DllImport(JitSupportLibrary)] - private extern static CorJitResult JitCompileMethod(out IntPtr exception, + private extern static CorJitResult JitCompileMethod(out IntPtr exception, IntPtr jit, IntPtr thisHandle, IntPtr callbacks, ref CORINFO_METHOD_INFO info, uint flags, out IntPtr nativeEntry, out uint codeSize); @@ -109,8 +110,6 @@ private IntPtr AllocException(Exception ex) [DllImport(JitSupportLibrary)] private extern static char* GetExceptionMessage(IntPtr obj); - private static readonly UnboxingMethodDescFactory _unboxingThunkFactory = new UnboxingMethodDescFactory(); - public static void Startup() { jitStartup(GetJitHost(JitConfigProvider.Instance.UnmanagedInstance)); @@ -291,7 +290,7 @@ private void PublishCode() InstructionSetSupport actualSupport = new InstructionSetSupport(_actualInstructionSetSupported, _actualInstructionSetUnsupported, architecture); var node = _compilation.SymbolNodeFactory.PerMethodInstructionSetSupportFixup(actualSupport); - ((MethodWithGCInfo)_methodCodeNode).Fixups.Add(node); + _methodCodeNode.Fixups.Add(node); } #endif PublishProfileData(); @@ -492,7 +491,7 @@ private void Get_CORINFO_SIG_INFO(MethodDesc method, CORINFO_SIG_INFO* sig, bool if (method.IsArrayAddressMethod()) hasHiddenParameter = true; - + // We only populate sigInst for intrinsic methods because most of the time, // JIT doesn't care what the instantiation is and this is expensive. Instantiation owningTypeInst = method.OwningType.Instantiation; @@ -534,9 +533,9 @@ private void Get_CORINFO_SIG_INFO(MethodSignature signature, CORINFO_SIG_INFO* s sig->args = (CORINFO_ARG_LIST_STRUCT_*)0; // CORINFO_ARG_LIST_STRUCT_ is argument index - sig->sigInst.classInst = null; // Not used by the JIT - sig->sigInst.classInstCount = 0; // Not used by the JIT - sig->sigInst.methInst = null; // Not used by the JIT + sig->sigInst.classInst = null; // Not used by the JIT + sig->sigInst.classInstCount = 0; // Not used by the JIT + sig->sigInst.methInst = null; // Not used by the JIT sig->sigInst.methInstCount = (uint)signature.GenericParameterCount; sig->pSig = (byte*)ObjectToHandle(signature); @@ -606,7 +605,8 @@ private CorInfoType asCorInfoType(TypeDesc type, CORINFO_CLASS_STRUCT_** structT var corInfoType = asCorInfoType(type); *structType = ((corInfoType == CorInfoType.CORINFO_TYPE_CLASS) || (corInfoType == CorInfoType.CORINFO_TYPE_VALUECLASS) || - (corInfoType == CorInfoType.CORINFO_TYPE_BYREF)) ? ObjectToHandle(type) : null; + (corInfoType == CorInfoType.CORINFO_TYPE_BYREF) || + (corInfoType == CorInfoType.CORINFO_TYPE_PTR)) ? ObjectToHandle(type) : null; return corInfoType; } @@ -874,7 +874,7 @@ private void getEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_E { if (impl.OwningType.IsValueType) { - impl = _unboxingThunkFactory.GetUnboxingMethod(impl); + impl = getUnboxingThunk(impl); } return ObjectToHandle(impl); @@ -1010,8 +1010,8 @@ private static object ResolveTokenInScope(MethodIL methodIL, object typeOrMethod private object GetRuntimeDeterminedObjectForToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) { // Since RyuJIT operates on canonical types (as opposed to runtime determined ones), but the - // dependency analysis operates on runtime determined ones, we convert the resolved token - // to the runtime determined form (e.g. Foo<__Canon> becomes Foo). + // dependency analysis operates on runtime determined ones, we convert the resolved token + // to the runtime determined form (e.g. Foo<__Canon> becomes Foo). var methodIL = (MethodIL)HandleToObject((IntPtr)pResolvedToken.tokenScope); var typeOrMethodContext = HandleToObject((IntPtr)pResolvedToken.tokenContext); @@ -1237,7 +1237,7 @@ private CorInfoType asCorInfoType(CORINFO_CLASS_STRUCT_* cls) *namespaceName = null; return null; } - + private CORINFO_CLASS_STRUCT_* getTypeInstantiationArgument(CORINFO_CLASS_STRUCT_* cls, uint index) { TypeDesc type = HandleToObject(cls); @@ -1396,6 +1396,12 @@ private uint getClassSize(CORINFO_CLASS_STRUCT_* cls) { throw new RequiresRuntimeJitException(type); } + + if (NeedsTypeLayoutCheck(type)) + { + ISymbolNode node = _compilation.SymbolNodeFactory.CheckTypeLayout(type); + _methodCodeNode.Fixups.Add(node); + } #endif return (uint)classSize.AsInt; } @@ -1682,9 +1688,9 @@ private CorInfoInitClassResult initClass(CORINFO_FIELD_STRUCT_* field, CORINFO_M else { // This optimization may cause static fields in reference types to be accessed without cctor being triggered - // for NULL "this" object. It does not conform with what the spec says. However, we have been historically + // for NULL "this" object. It does not conform with what the spec says. However, we have been historically // doing it for perf reasons. - if (!typeToInit.IsValueType && ! typeToInit.IsInterface && !typeToInit.IsBeforeFieldInit) + if (!typeToInit.IsValueType && !typeToInit.IsInterface && !typeToInit.IsBeforeFieldInit) { if (typeToInit == typeFromContext(context) || typeToInit == MethodBeingCompiled.OwningType) { @@ -1693,7 +1699,7 @@ private CorInfoInitClassResult initClass(CORINFO_FIELD_STRUCT_* field, CORINFO_M } } - // If we are currently compiling the class constructor for this static field access then we can skip the initClass + // If we are currently compiling the class constructor for this static field access then we can skip the initClass if (MethodBeingCompiled.OwningType == typeToInit && MethodBeingCompiled.IsStaticConstructor) { // The class will be initialized by the time we access the field. @@ -1753,23 +1759,10 @@ private CorInfoType getTypeForPrimitiveNumericClass(CORINFO_CLASS_STRUCT_* cls) { var type = HandleToObject(cls); - switch (type.Category) - { - case TypeFlags.Byte: - case TypeFlags.SByte: - case TypeFlags.UInt16: - case TypeFlags.Int16: - case TypeFlags.UInt32: - case TypeFlags.Int32: - case TypeFlags.UInt64: - case TypeFlags.Int64: - case TypeFlags.Single: - case TypeFlags.Double: - return asCorInfoType(type); + if (type.IsPrimitiveNumeric) + return asCorInfoType(type); - default: - return CorInfoType.CORINFO_TYPE_UNDEF; - } + return CorInfoType.CORINFO_TYPE_UNDEF; } private bool canCast(CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent) @@ -1984,7 +1977,7 @@ private CorInfoType getChildType(CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_ST CorInfoType result = CorInfoType.CORINFO_TYPE_UNDEF; var td = HandleToObject(clsHnd); - if (td.IsArray || td.IsByRef) + if (td.IsArray || td.IsByRef || td.IsPointer) { TypeDesc returnType = ((ParameterizedType)td).ParameterType; result = asCorInfoType(returnType, clsRet); @@ -2008,7 +2001,7 @@ private uint getArrayRank(CORINFO_CLASS_STRUCT_* cls) { var td = HandleToObject(cls) as ArrayType; Debug.Assert(td != null); - return (uint) td.Rank; + return (uint)td.Rank; } private void* getArrayInitializationData(CORINFO_FIELD_STRUCT_* field, uint size) @@ -2198,7 +2191,18 @@ private CorInfoTypeWithMod getArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_ST private CorInfoType getHFAType(CORINFO_CLASS_STRUCT_* hClass) { var type = (DefType)HandleToObject(hClass); - return type.IsHfa ? asCorInfoType(type.HfaElementType) : CorInfoType.CORINFO_TYPE_UNDEF; + + // For 8-byte vectors return CORINFO_TYPE_DOUBLE, which is mapped by JIT to SIMD8. + // For 16-byte vectors return CORINFO_TYPE_VALUECLASS, which is mapped by JIT to SIMD16. + // See MethodTable::GetHFAType and Compiler::GetHfaType. + return (type.ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) switch + { + ValueTypeShapeCharacteristics.Float32Aggregate => CorInfoType.CORINFO_TYPE_FLOAT, + ValueTypeShapeCharacteristics.Float64Aggregate => CorInfoType.CORINFO_TYPE_DOUBLE, + ValueTypeShapeCharacteristics.Vector64Aggregate => CorInfoType.CORINFO_TYPE_DOUBLE, + ValueTypeShapeCharacteristics.Vector128Aggregate => CorInfoType.CORINFO_TYPE_VALUECLASS, + _ => CorInfoType.CORINFO_TYPE_UNDEF + }; } private HRESULT GetErrorHRESULT(_EXCEPTION_POINTERS* pExceptionPointers) @@ -2534,11 +2538,11 @@ private void addActiveDependency(CORINFO_MODULE_STRUCT_* moduleFrom, CORINFO_MOD private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) { throw new NotImplementedException("MethodCompileComplete"); } - private void* getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags) + private bool getTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, ref CORINFO_TAILCALL_HELPERS pResult) { // Slow tailcalls are not supported yet - // https://github.com/dotnet/corert/issues/1683 - return null; + // https://github.com/dotnet/runtime/issues/35423 + throw new NotImplementedException(nameof(getTailCallHelpers)); } private byte[] _code; @@ -2547,7 +2551,7 @@ private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) private byte[] _roData; - private SettableReadOnlyDataBlob _roDataBlob; + private MethodReadOnlyDataNode _roDataBlob; private int _roDataAlignment; private int _numFrameInfos; @@ -2593,8 +2597,7 @@ private void allocMem(uint hotCodeSize, uint coldCodeSize, uint roDataSize, uint _roData = new byte[roDataSize]; - _roDataBlob = _compilation.NodeFactory.SettableReadOnlyDataBlob( - "__readonlydata_" + _compilation.NameMangler.GetMangledMethodName(MethodBeingCompiled)); + _roDataBlob = new MethodReadOnlyDataNode(MethodBeingCompiled); roDataBlock = (void*)GetPin(_roData); } @@ -2619,7 +2622,7 @@ private void allocUnwindInfo(byte* pHotCode, byte* pColdCode, uint startOffset, if (funcKind == CorJitFuncKind.CORJIT_FUNC_ROOT) { - if (this.MethodBeingCompiled.IsNativeCallable) + if (this.MethodBeingCompiled.IsUnmanagedCallersOnly) flags |= FrameInfoFlags.ReversePInvoke; } @@ -2908,15 +2911,31 @@ private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) if (targetArchitecture == TargetArchitecture.ARM && !_compilation.TypeSystemContext.Target.IsWindows) flags.Set(CorJitFlag.CORJIT_FLAG_RELATIVE_CODE_RELOCS); - if (this.MethodBeingCompiled.IsNativeCallable) + if (this.MethodBeingCompiled.IsUnmanagedCallersOnly) { #if READYTORUN if (targetArchitecture == TargetArchitecture.X86) { - throw new RequiresRuntimeJitException("ReadyToRun: Methods with NativeCallableAttribute not implemented"); + throw new RequiresRuntimeJitException("ReadyToRun: Methods with UnmanagedCallersOnlyAttribute not implemented"); } #endif + // Validate UnmanagedCallersOnlyAttribute usage + if (!this.MethodBeingCompiled.Signature.IsStatic) // Must be a static method + { + ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramNonStaticMethod, this.MethodBeingCompiled); + } + + if (this.MethodBeingCompiled.HasInstantiation || this.MethodBeingCompiled.OwningType.HasInstantiation) // No generics involved + { + ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramGenericMethod, this.MethodBeingCompiled); + } + + if (Marshaller.IsMarshallingRequired(this.MethodBeingCompiled.Signature, Array.Empty())) // Only blittable arguments + { + ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramNonBlittableTypes, this.MethodBeingCompiled); + } + flags.Set(CorJitFlag.CORJIT_FLAG_REVERSE_PINVOKE); } diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoInstructionSet.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoInstructionSet.cs index 92e987f3390872..dae2003712ff19 100644 --- a/src/coreclr/src/tools/Common/JitInterface/CorInfoInstructionSet.cs +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoInstructionSet.cs @@ -31,56 +31,60 @@ public enum InstructionSet ARM64_Atomics=10, ARM64_Vector64=11, ARM64_Vector128=12, - X64_SSE=1, - X64_SSE2=2, - X64_SSE3=3, - X64_SSSE3=4, - X64_SSE41=5, - X64_SSE42=6, - X64_AVX=7, - X64_AVX2=8, - X64_AES=9, - X64_BMI1=10, - X64_BMI2=11, - X64_FMA=12, - X64_LZCNT=13, - X64_PCLMULQDQ=14, - X64_POPCNT=15, - X64_Vector128=16, - X64_Vector256=17, - X64_BMI1_X64=18, - X64_BMI2_X64=19, - X64_LZCNT_X64=20, - X64_POPCNT_X64=21, - X64_SSE_X64=22, - X64_SSE2_X64=23, - X64_SSE41_X64=24, - X64_SSE42_X64=25, - X86_SSE=1, - X86_SSE2=2, - X86_SSE3=3, - X86_SSSE3=4, - X86_SSE41=5, - X86_SSE42=6, - X86_AVX=7, - X86_AVX2=8, - X86_AES=9, - X86_BMI1=10, - X86_BMI2=11, - X86_FMA=12, - X86_LZCNT=13, - X86_PCLMULQDQ=14, - X86_POPCNT=15, - X86_Vector128=16, - X86_Vector256=17, - X86_BMI1_X64=18, - X86_BMI2_X64=19, - X86_LZCNT_X64=20, - X86_POPCNT_X64=21, - X86_SSE_X64=22, - X86_SSE2_X64=23, - X86_SSE41_X64=24, - X86_SSE42_X64=25, + X64_X86Base=1, + X64_SSE=2, + X64_SSE2=3, + X64_SSE3=4, + X64_SSSE3=5, + X64_SSE41=6, + X64_SSE42=7, + X64_AVX=8, + X64_AVX2=9, + X64_AES=10, + X64_BMI1=11, + X64_BMI2=12, + X64_FMA=13, + X64_LZCNT=14, + X64_PCLMULQDQ=15, + X64_POPCNT=16, + X64_Vector128=17, + X64_Vector256=18, + X64_X86Base_X64=19, + X64_BMI1_X64=20, + X64_BMI2_X64=21, + X64_LZCNT_X64=22, + X64_POPCNT_X64=23, + X64_SSE_X64=24, + X64_SSE2_X64=25, + X64_SSE41_X64=26, + X64_SSE42_X64=27, + X86_X86Base=1, + X86_SSE=2, + X86_SSE2=3, + X86_SSE3=4, + X86_SSSE3=5, + X86_SSE41=6, + X86_SSE42=7, + X86_AVX=8, + X86_AVX2=9, + X86_AES=10, + X86_BMI1=11, + X86_BMI2=12, + X86_FMA=13, + X86_LZCNT=14, + X86_PCLMULQDQ=15, + X86_POPCNT=16, + X86_Vector128=17, + X86_Vector256=18, + X86_X86Base_X64=19, + X86_BMI1_X64=20, + X86_BMI2_X64=21, + X86_LZCNT_X64=22, + X86_POPCNT_X64=23, + X86_SSE_X64=24, + X86_SSE2_X64=25, + X86_SSE41_X64=26, + X86_SSE42_X64=27, } @@ -186,6 +190,10 @@ public static InstructionSetFlags ExpandInstructionSetByImplicationHelper(Target break; case TargetArchitecture.X64: + if (resultflags.HasInstructionSet(InstructionSet.X64_X86Base)) + resultflags.AddInstructionSet(InstructionSet.X64_X86Base_X64); + if (resultflags.HasInstructionSet(InstructionSet.X64_X86Base_X64)) + resultflags.AddInstructionSet(InstructionSet.X64_X86Base); if (resultflags.HasInstructionSet(InstructionSet.X64_SSE)) resultflags.AddInstructionSet(InstructionSet.X64_SSE_X64); if (resultflags.HasInstructionSet(InstructionSet.X64_SSE_X64)) @@ -218,6 +226,8 @@ public static InstructionSetFlags ExpandInstructionSetByImplicationHelper(Target resultflags.AddInstructionSet(InstructionSet.X64_POPCNT_X64); if (resultflags.HasInstructionSet(InstructionSet.X64_POPCNT_X64)) resultflags.AddInstructionSet(InstructionSet.X64_POPCNT); + if (resultflags.HasInstructionSet(InstructionSet.X64_SSE)) + resultflags.AddInstructionSet(InstructionSet.X64_X86Base); if (resultflags.HasInstructionSet(InstructionSet.X64_SSE2)) resultflags.AddInstructionSet(InstructionSet.X64_SSE); if (resultflags.HasInstructionSet(InstructionSet.X64_SSE3)) @@ -244,9 +254,13 @@ public static InstructionSetFlags ExpandInstructionSetByImplicationHelper(Target resultflags.AddInstructionSet(InstructionSet.X64_SSE2); if (resultflags.HasInstructionSet(InstructionSet.X64_POPCNT)) resultflags.AddInstructionSet(InstructionSet.X64_SSE42); + if (resultflags.HasInstructionSet(InstructionSet.X64_Vector256)) + resultflags.AddInstructionSet(InstructionSet.X64_AVX); break; case TargetArchitecture.X86: + if (resultflags.HasInstructionSet(InstructionSet.X86_SSE)) + resultflags.AddInstructionSet(InstructionSet.X86_X86Base); if (resultflags.HasInstructionSet(InstructionSet.X86_SSE2)) resultflags.AddInstructionSet(InstructionSet.X86_SSE); if (resultflags.HasInstructionSet(InstructionSet.X86_SSE3)) @@ -273,6 +287,8 @@ public static InstructionSetFlags ExpandInstructionSetByImplicationHelper(Target resultflags.AddInstructionSet(InstructionSet.X86_SSE2); if (resultflags.HasInstructionSet(InstructionSet.X86_POPCNT)) resultflags.AddInstructionSet(InstructionSet.X86_SSE42); + if (resultflags.HasInstructionSet(InstructionSet.X86_Vector256)) + resultflags.AddInstructionSet(InstructionSet.X86_AVX); break; } @@ -315,6 +331,8 @@ private static InstructionSetFlags ExpandInstructionSetByReverseImplicationHelpe break; case TargetArchitecture.X64: + if (resultflags.HasInstructionSet(InstructionSet.X64_X86Base_X64)) + resultflags.AddInstructionSet(InstructionSet.X64_X86Base); if (resultflags.HasInstructionSet(InstructionSet.X64_SSE_X64)) resultflags.AddInstructionSet(InstructionSet.X64_SSE); if (resultflags.HasInstructionSet(InstructionSet.X64_SSE2_X64)) @@ -331,6 +349,8 @@ private static InstructionSetFlags ExpandInstructionSetByReverseImplicationHelpe resultflags.AddInstructionSet(InstructionSet.X64_LZCNT); if (resultflags.HasInstructionSet(InstructionSet.X64_POPCNT_X64)) resultflags.AddInstructionSet(InstructionSet.X64_POPCNT); + if (resultflags.HasInstructionSet(InstructionSet.X64_X86Base)) + resultflags.AddInstructionSet(InstructionSet.X64_SSE); if (resultflags.HasInstructionSet(InstructionSet.X64_SSE)) resultflags.AddInstructionSet(InstructionSet.X64_SSE2); if (resultflags.HasInstructionSet(InstructionSet.X64_SSE2)) @@ -357,9 +377,13 @@ private static InstructionSetFlags ExpandInstructionSetByReverseImplicationHelpe resultflags.AddInstructionSet(InstructionSet.X64_PCLMULQDQ); if (resultflags.HasInstructionSet(InstructionSet.X64_SSE42)) resultflags.AddInstructionSet(InstructionSet.X64_POPCNT); + if (resultflags.HasInstructionSet(InstructionSet.X64_AVX)) + resultflags.AddInstructionSet(InstructionSet.X64_Vector256); break; case TargetArchitecture.X86: + if (resultflags.HasInstructionSet(InstructionSet.X86_X86Base)) + resultflags.AddInstructionSet(InstructionSet.X86_SSE); if (resultflags.HasInstructionSet(InstructionSet.X86_SSE)) resultflags.AddInstructionSet(InstructionSet.X86_SSE2); if (resultflags.HasInstructionSet(InstructionSet.X86_SSE2)) @@ -386,6 +410,8 @@ private static InstructionSetFlags ExpandInstructionSetByReverseImplicationHelpe resultflags.AddInstructionSet(InstructionSet.X86_PCLMULQDQ); if (resultflags.HasInstructionSet(InstructionSet.X86_SSE42)) resultflags.AddInstructionSet(InstructionSet.X86_POPCNT); + if (resultflags.HasInstructionSet(InstructionSet.X86_AVX)) + resultflags.AddInstructionSet(InstructionSet.X86_Vector256); break; } @@ -396,12 +422,14 @@ private static InstructionSetFlags ExpandInstructionSetByReverseImplicationHelpe public struct InstructionSetInfo { public readonly string Name; + public readonly string ManagedName; public readonly InstructionSet InstructionSet; public readonly bool Specifiable; - public InstructionSetInfo(string name, InstructionSet instructionSet, bool specifiable) + public InstructionSetInfo(string name, string managedName, InstructionSet instructionSet, bool specifiable) { Name = name; + ManagedName = managedName; InstructionSet = instructionSet; Specifiable = specifiable; } @@ -413,55 +441,57 @@ public static IEnumerable ArchitectureToValidInstructionSets { case TargetArchitecture.ARM64: - yield return new InstructionSetInfo("base", InstructionSet.ARM64_ArmBase, true); - yield return new InstructionSetInfo("neon", InstructionSet.ARM64_AdvSimd, true); - yield return new InstructionSetInfo("aes", InstructionSet.ARM64_Aes, true); - yield return new InstructionSetInfo("crc", InstructionSet.ARM64_Crc32, true); - yield return new InstructionSetInfo("sha1", InstructionSet.ARM64_Sha1, true); - yield return new InstructionSetInfo("sha2", InstructionSet.ARM64_Sha256, true); - yield return new InstructionSetInfo("lse", InstructionSet.ARM64_Atomics, true); - yield return new InstructionSetInfo("Vector64", InstructionSet.ARM64_Vector64, false); - yield return new InstructionSetInfo("Vector128", InstructionSet.ARM64_Vector128, false); + yield return new InstructionSetInfo("base", "ArmBase", InstructionSet.ARM64_ArmBase, true); + yield return new InstructionSetInfo("neon", "AdvSimd", InstructionSet.ARM64_AdvSimd, true); + yield return new InstructionSetInfo("aes", "Aes", InstructionSet.ARM64_Aes, true); + yield return new InstructionSetInfo("crc", "Crc32", InstructionSet.ARM64_Crc32, true); + yield return new InstructionSetInfo("sha1", "Sha1", InstructionSet.ARM64_Sha1, true); + yield return new InstructionSetInfo("sha2", "Sha256", InstructionSet.ARM64_Sha256, true); + yield return new InstructionSetInfo("lse", "", InstructionSet.ARM64_Atomics, true); + yield return new InstructionSetInfo("Vector64", "", InstructionSet.ARM64_Vector64, false); + yield return new InstructionSetInfo("Vector128", "", InstructionSet.ARM64_Vector128, false); break; case TargetArchitecture.X64: - yield return new InstructionSetInfo("sse", InstructionSet.X64_SSE, true); - yield return new InstructionSetInfo("sse2", InstructionSet.X64_SSE2, true); - yield return new InstructionSetInfo("sse3", InstructionSet.X64_SSE3, true); - yield return new InstructionSetInfo("ssse3", InstructionSet.X64_SSSE3, true); - yield return new InstructionSetInfo("sse4.1", InstructionSet.X64_SSE41, true); - yield return new InstructionSetInfo("sse4.2", InstructionSet.X64_SSE42, true); - yield return new InstructionSetInfo("avx", InstructionSet.X64_AVX, true); - yield return new InstructionSetInfo("avx2", InstructionSet.X64_AVX2, true); - yield return new InstructionSetInfo("aes", InstructionSet.X64_AES, true); - yield return new InstructionSetInfo("bmi", InstructionSet.X64_BMI1, true); - yield return new InstructionSetInfo("bmi2", InstructionSet.X64_BMI2, true); - yield return new InstructionSetInfo("fma", InstructionSet.X64_FMA, true); - yield return new InstructionSetInfo("lzcnt", InstructionSet.X64_LZCNT, true); - yield return new InstructionSetInfo("pclmul", InstructionSet.X64_PCLMULQDQ, true); - yield return new InstructionSetInfo("popcnt", InstructionSet.X64_POPCNT, true); - yield return new InstructionSetInfo("Vector128", InstructionSet.X64_Vector128, false); - yield return new InstructionSetInfo("Vector256", InstructionSet.X64_Vector256, false); + yield return new InstructionSetInfo("base", "X86Base", InstructionSet.X64_X86Base, true); + yield return new InstructionSetInfo("sse", "Sse", InstructionSet.X64_SSE, true); + yield return new InstructionSetInfo("sse2", "Sse2", InstructionSet.X64_SSE2, true); + yield return new InstructionSetInfo("sse3", "Sse3", InstructionSet.X64_SSE3, true); + yield return new InstructionSetInfo("ssse3", "Ssse3", InstructionSet.X64_SSSE3, true); + yield return new InstructionSetInfo("sse4.1", "Sse41", InstructionSet.X64_SSE41, true); + yield return new InstructionSetInfo("sse4.2", "Sse42", InstructionSet.X64_SSE42, true); + yield return new InstructionSetInfo("avx", "Avx", InstructionSet.X64_AVX, true); + yield return new InstructionSetInfo("avx2", "Avx2", InstructionSet.X64_AVX2, true); + yield return new InstructionSetInfo("aes", "Aes", InstructionSet.X64_AES, true); + yield return new InstructionSetInfo("bmi", "Bmi1", InstructionSet.X64_BMI1, true); + yield return new InstructionSetInfo("bmi2", "Bmi2", InstructionSet.X64_BMI2, true); + yield return new InstructionSetInfo("fma", "Fma", InstructionSet.X64_FMA, true); + yield return new InstructionSetInfo("lzcnt", "Lzcnt", InstructionSet.X64_LZCNT, true); + yield return new InstructionSetInfo("pclmul", "Pclmulqdq", InstructionSet.X64_PCLMULQDQ, true); + yield return new InstructionSetInfo("popcnt", "Popcnt", InstructionSet.X64_POPCNT, true); + yield return new InstructionSetInfo("Vector128", "", InstructionSet.X64_Vector128, false); + yield return new InstructionSetInfo("Vector256", "", InstructionSet.X64_Vector256, false); break; case TargetArchitecture.X86: - yield return new InstructionSetInfo("sse", InstructionSet.X86_SSE, true); - yield return new InstructionSetInfo("sse2", InstructionSet.X86_SSE2, true); - yield return new InstructionSetInfo("sse3", InstructionSet.X86_SSE3, true); - yield return new InstructionSetInfo("ssse3", InstructionSet.X86_SSSE3, true); - yield return new InstructionSetInfo("sse4.1", InstructionSet.X86_SSE41, true); - yield return new InstructionSetInfo("sse4.2", InstructionSet.X86_SSE42, true); - yield return new InstructionSetInfo("avx", InstructionSet.X86_AVX, true); - yield return new InstructionSetInfo("avx2", InstructionSet.X86_AVX2, true); - yield return new InstructionSetInfo("aes", InstructionSet.X86_AES, true); - yield return new InstructionSetInfo("bmi", InstructionSet.X86_BMI1, true); - yield return new InstructionSetInfo("bmi2", InstructionSet.X86_BMI2, true); - yield return new InstructionSetInfo("fma", InstructionSet.X86_FMA, true); - yield return new InstructionSetInfo("lzcnt", InstructionSet.X86_LZCNT, true); - yield return new InstructionSetInfo("pclmul", InstructionSet.X86_PCLMULQDQ, true); - yield return new InstructionSetInfo("popcnt", InstructionSet.X86_POPCNT, true); - yield return new InstructionSetInfo("Vector128", InstructionSet.X86_Vector128, false); - yield return new InstructionSetInfo("Vector256", InstructionSet.X86_Vector256, false); + yield return new InstructionSetInfo("base", "X86Base", InstructionSet.X86_X86Base, true); + yield return new InstructionSetInfo("sse", "Sse", InstructionSet.X86_SSE, true); + yield return new InstructionSetInfo("sse2", "Sse2", InstructionSet.X86_SSE2, true); + yield return new InstructionSetInfo("sse3", "Sse3", InstructionSet.X86_SSE3, true); + yield return new InstructionSetInfo("ssse3", "Ssse3", InstructionSet.X86_SSSE3, true); + yield return new InstructionSetInfo("sse4.1", "Sse41", InstructionSet.X86_SSE41, true); + yield return new InstructionSetInfo("sse4.2", "Sse42", InstructionSet.X86_SSE42, true); + yield return new InstructionSetInfo("avx", "Avx", InstructionSet.X86_AVX, true); + yield return new InstructionSetInfo("avx2", "Avx2", InstructionSet.X86_AVX2, true); + yield return new InstructionSetInfo("aes", "Aes", InstructionSet.X86_AES, true); + yield return new InstructionSetInfo("bmi", "Bmi1", InstructionSet.X86_BMI1, true); + yield return new InstructionSetInfo("bmi2", "Bmi2", InstructionSet.X86_BMI2, true); + yield return new InstructionSetInfo("fma", "Fma", InstructionSet.X86_FMA, true); + yield return new InstructionSetInfo("lzcnt", "Lzcnt", InstructionSet.X86_LZCNT, true); + yield return new InstructionSetInfo("pclmul", "Pclmulqdq", InstructionSet.X86_PCLMULQDQ, true); + yield return new InstructionSetInfo("popcnt", "Popcnt", InstructionSet.X86_POPCNT, true); + yield return new InstructionSetInfo("Vector128", "", InstructionSet.X86_Vector128, false); + yield return new InstructionSetInfo("Vector256", "", InstructionSet.X86_Vector256, false); break; } @@ -482,6 +512,8 @@ public void Set64BitInstructionSetVariants(TargetArchitecture architecture) break; case TargetArchitecture.X64: + if (HasInstructionSet(InstructionSet.X64_X86Base)) + AddInstructionSet(InstructionSet.X64_X86Base_X64); if (HasInstructionSet(InstructionSet.X64_SSE)) AddInstructionSet(InstructionSet.X64_SSE_X64); if (HasInstructionSet(InstructionSet.X64_SSE2)) diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs index d4d570ffea365d..990c2713de72c9 100644 --- a/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoTypes.cs @@ -453,6 +453,7 @@ public enum CorInfoIntrinsics CORINFO_INTRINSIC_StubHelpers_GetStubContext, CORINFO_INTRINSIC_StubHelpers_GetStubContextAddr, CORINFO_INTRINSIC_StubHelpers_GetNDirectTarget, + CORINFO_INTRINSIC_StubHelpers_NextCallReturnAddress, CORINFO_INTRINSIC_InterlockedAdd32, CORINFO_INTRINSIC_InterlockedAdd64, CORINFO_INTRINSIC_InterlockedXAdd32, @@ -462,6 +463,7 @@ public enum CorInfoIntrinsics CORINFO_INTRINSIC_InterlockedCmpXchg32, CORINFO_INTRINSIC_InterlockedCmpXchg64, CORINFO_INTRINSIC_MemoryBarrier, + CORINFO_INTRINSIC_MemoryBarrierLoad, CORINFO_INTRINSIC_GetCurrentManagedThread, CORINFO_INTRINSIC_GetManagedThreadId, CORINFO_INTRINSIC_ByReference_Ctor, @@ -755,14 +757,6 @@ public unsafe struct DelegateCtorArgs public void* pArg5; } - // When using CORINFO_HELPER_TAILCALL, the JIT needs to pass certain special - // calling convention/argument passing/handling details to the helper - public enum CorInfoHelperTailCallSpecialHandling - { - CORINFO_TAILCALL_NORMAL = 0x00000000, - CORINFO_TAILCALL_STUB_DISPATCH_ARG = 0x00000001, - } - /*****************************************************************************/ // These are flags passed to ICorJitInfo::allocMem // to guide the memory allocation for the code, readonly data, and read-write data @@ -901,6 +895,30 @@ public struct InlinedCallFrameInfo public CORINFO_OS osType; } + // Flags passed from JIT to runtime. + public enum CORINFO_GET_TAILCALL_HELPERS_FLAGS + { + // The callsite is a callvirt instruction. + CORINFO_TAILCALL_IS_CALLVIRT = 0x00000001, + } + + // Flags passed from runtime to JIT. + public enum CORINFO_TAILCALL_HELPERS_FLAGS + { + // The StoreArgs stub needs to be passed the target function pointer as the + // first argument. + CORINFO_TAILCALL_STORE_TARGET = 0x00000001, + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct CORINFO_TAILCALL_HELPERS + { + CORINFO_TAILCALL_HELPERS_FLAGS flags; + CORINFO_METHOD_STRUCT_* hStoreArgs; + CORINFO_METHOD_STRUCT_* hCallTarget; + CORINFO_METHOD_STRUCT_* hDispatcher; + }; + public enum CORINFO_THIS_TRANSFORM { CORINFO_NO_THIS_TRANSFORM, diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt index 0fcfc9b172e2e7..44a9139982108b 100644 --- a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetDesc.txt @@ -18,7 +18,9 @@ ; Definition of X86 instruction sets definearch ,X86 ,32Bit ,X64 +instructionset ,X86 ,X86Base , ,22 ,X86Base ,base instructionset ,X86 ,Sse , ,1 ,SSE ,sse +implication ,X86 ,SSE ,X86Base instructionset ,X86 ,Sse2 , ,2 ,SSE2 ,sse2 implication ,X86 ,SSE2 ,SSE instructionset ,X86 ,Sse3 , ,3 ,SSE3 ,sse3 @@ -48,9 +50,11 @@ instructionset ,X86 ,Popcnt , ,15 ,POPCNT ,popcnt implication ,X86 ,POPCNT ,SSE42 instructionset ,X86 , , , ,Vector128, instructionset ,X86 , , , ,Vector256, +implication ,X86 ,Vector256 ,AVX ; Definition of X64 instruction sets (Define ) definearch ,X64 ,64Bit ,X64 +instructionset64bit,X86 ,X86Base instructionset64bit,X86 ,BMI1 instructionset64bit,X86 ,BMI2 instructionset64bit,X86 ,LZCNT diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetGenerator.cs b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetGenerator.cs index ea4268f6984306..ad5a2108a1c161 100644 --- a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetGenerator.cs +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/InstructionSetGenerator.cs @@ -522,12 +522,14 @@ private static InstructionSetFlags ExpandInstructionSetByReverseImplicationHelpe public struct InstructionSetInfo { public readonly string Name; + public readonly string ManagedName; public readonly InstructionSet InstructionSet; public readonly bool Specifiable; - public InstructionSetInfo(string name, InstructionSet instructionSet, bool specifiable) + public InstructionSetInfo(string name, string managedName, InstructionSet instructionSet, bool specifiable) { Name = name; + ManagedName = managedName; InstructionSet = instructionSet; Specifiable = specifiable; } @@ -548,9 +550,10 @@ public static IEnumerable ArchitectureToValidInstructionSets if (instructionSet.Architecture != architecture) continue; bool instructionSetIsSpecifiable = !String.IsNullOrEmpty(instructionSet.CommandLineName); string name = instructionSet.PublicName; + string managedName = instructionSet.ManagedName; string specifiable = instructionSetIsSpecifiable ? "true" : "false"; string instructionSetString = $"InstructionSet.{architecture}_{instructionSet.JitName}"; - tr.WriteLine($" yield return new InstructionSetInfo(\"{name}\", {instructionSetString}, {specifiable});"); + tr.WriteLine($" yield return new InstructionSetInfo(\"{name}\", \"{managedName}\", {instructionSetString}, {specifiable});"); } tr.WriteLine(" break;"); } diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 74bde2b72eb42d..fd5b9f464452c0 100644 --- a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -91,6 +91,7 @@ CORINFO_SIG_INFO*,,void* CORINFO_RESOLVED_TOKEN*,ref CORINFO_RESOLVED_TOKEN,void* CORINFO_RESOLVED_TOKEN_PTR,CORINFO_RESOLVED_TOKEN*,void* CORINFO_EE_INFO*,ref CORINFO_EE_INFO,void* +CORINFO_TAILCALL_HELPERS*,ref CORINFO_TAILCALL_HELPERS,void* CORINFO_GENERICHANDLE_RESULT*,ref CORINFO_GENERICHANDLE_RESULT,void* CORINFO_METHOD_INFO*,CORINFO_METHOD_INFO*,void* CORINFO_FIELD_INFO*,CORINFO_FIELD_INFO*,void* @@ -110,7 +111,6 @@ ICorJitInfo::BlockCounts**,ref BlockCounts*,void** ; Enums CorInfoClassId,,int -CorInfoHelperTailCallSpecialHandling,,int CorInfoHelpFunc,,int CorInfoInitClassResult,,int CorInfoInlineTypeCheck,,int @@ -127,6 +127,7 @@ InfoAccessType,,int CORINFO_LOOKUP_KIND CORINFO_ACCESS_FLAGS,,int CORINFO_CALLINFO_FLAGS,,int +CORINFO_GET_TAILCALL_HELPERS_FLAGS,,int CorJitAllocMemFlag,,int CorJitFuncKind,,int CorJitResult,,int @@ -312,7 +313,7 @@ FUNCTIONS void addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom, CORINFO_MODULE_HANDLE moduleTo); CORINFO_METHOD_HANDLE GetDelegateCtor(CORINFO_METHOD_HANDLE methHnd, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE targetMethodHnd, DelegateCtorArgs * pCtorData); void MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd); - void* getTailCallCopyArgsThunk (CORINFO_SIG_INFO *pSig, CorInfoHelperTailCallSpecialHandling flags); + bool getTailCallHelpers(CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, CORINFO_TAILCALL_HELPERS* pResult); bool convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool mustConvert); void notifyInstructionSetUsage(CORINFO_InstructionSet instructionSet,bool supportEnabled); void allocMem( ULONG hotCodeSize, ULONG coldCodeSize, ULONG roDataSize, ULONG xcptnsCount, CorJitAllocMemFlag flag, void** hotCodeBlock, void** coldCodeBlock, void** roDataBlock ); diff --git a/src/coreclr/src/tools/Common/JitInterface/UnboxingMethodDesc.cs b/src/coreclr/src/tools/Common/JitInterface/UnboxingMethodDesc.cs index b21a721652fc3e..817e6f31167709 100644 --- a/src/coreclr/src/tools/Common/JitInterface/UnboxingMethodDesc.cs +++ b/src/coreclr/src/tools/Common/JitInterface/UnboxingMethodDesc.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using Internal.TypeSystem; @@ -80,25 +79,6 @@ protected override int CompareToImpl(MethodDesc other, TypeSystemComparer compar #endif } - internal class UnboxingMethodDescFactory : ConcurrentDictionary - { - private Func _factoryDelegate; - private UnboxingMethodDesc CreateUnboxingMethod(MethodDesc method) - { - return new UnboxingMethodDesc(method, this); - } - - public UnboxingMethodDescFactory() - { - _factoryDelegate = CreateUnboxingMethod; - } - - public UnboxingMethodDesc GetUnboxingMethod(MethodDesc method) - { - return GetOrAdd(method, _factoryDelegate); - } - } - internal static class UnboxingMethodDescExtensions { public static bool IsUnboxingThunk(this MethodDesc method) diff --git a/src/coreclr/src/tools/Common/Sorting/ArrayAccessor.cs b/src/coreclr/src/tools/Common/Sorting/ArrayAccessor.cs new file mode 100644 index 00000000000000..376e452b86f9c1 --- /dev/null +++ b/src/coreclr/src/tools/Common/Sorting/ArrayAccessor.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. +// See the LICENSE file in the project root for more information. + +using System; + +namespace ILCompiler.Sorting.Implementation +{ + internal struct ArrayAccessor : ISortableDataStructureAccessor + { + public void Copy(T[] source, int sourceIndex, T[] target, int destIndex, int length) + { + Array.Copy(source, sourceIndex, target, destIndex, length); + } + + public T GetElement(T[] dataStructure, int i) + { + return dataStructure[i]; + } + + public int GetLength(T[] dataStructure) + { + return dataStructure.Length; + } + + public void SetElement(T[] dataStructure, int i, T value) + { + dataStructure[i] = value; + } + + public void SwapElements(T[] dataStructure, int i, int i2) + { + T temp = dataStructure[i]; + dataStructure[i] = dataStructure[i + 1]; + dataStructure[i + 1] = temp; + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/Sorting/ICompareAsEqualAction.cs b/src/coreclr/src/tools/Common/Sorting/ICompareAsEqualAction.cs new file mode 100644 index 00000000000000..8307aac4cc293f --- /dev/null +++ b/src/coreclr/src/tools/Common/Sorting/ICompareAsEqualAction.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. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +namespace ILCompiler +{ + internal interface ICompareAsEqualAction + { + void CompareAsEqual(); + } + + internal struct RequireTotalOrderAssert : ICompareAsEqualAction + { + public void CompareAsEqual() + { + Debug.Assert(false); + } + } + + internal struct AllowDuplicates : ICompareAsEqualAction + { + public void CompareAsEqual() + { + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/Sorting/ISortableDataStructureAccessor.cs b/src/coreclr/src/tools/Common/Sorting/ISortableDataStructureAccessor.cs new file mode 100644 index 00000000000000..8b2d1ba6e80d2a --- /dev/null +++ b/src/coreclr/src/tools/Common/Sorting/ISortableDataStructureAccessor.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ILCompiler +{ + internal interface ISortableDataStructureAccessor + { + T GetElement(TDataStructure dataStructure, int i); + void SetElement(TDataStructure dataStructure, int i, T value); + void SwapElements(TDataStructure dataStructure, int i, int i2); + void Copy(TDataStructure source, int sourceIndex, T[] target, int destIndex, int length); + void Copy(T[] source, int sourceIndex, TDataStructure target, int destIndex, int length); + int GetLength(TDataStructure dataStructure); + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/Sorting/ListAccessor.cs b/src/coreclr/src/tools/Common/Sorting/ListAccessor.cs new file mode 100644 index 00000000000000..75d97de93a8e44 --- /dev/null +++ b/src/coreclr/src/tools/Common/Sorting/ListAccessor.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; + +namespace ILCompiler.Sorting.Implementation +{ + internal struct ListAccessor : ISortableDataStructureAccessor> + { + public void Copy(List source, int sourceIndex, T[] target, int destIndex, int length) + { + source.CopyTo(sourceIndex, target, destIndex, length); + } + + public void Copy(T[] source, int sourceIndex, List target, int destIndex, int length) + { + for (int i = 0; i < length; i++) + { + target[i + destIndex] = source[i + sourceIndex]; + } + } + + public T GetElement(List dataStructure, int i) + { + return dataStructure[i]; + } + + public int GetLength(List dataStructure) + { + return dataStructure.Count; + } + + public void SetElement(List dataStructure, int i, T value) + { + dataStructure[i] = value; + } + + public void SwapElements(List dataStructure, int i, int i2) + { + T temp = dataStructure[i]; + dataStructure[i] = dataStructure[i + 1]; + dataStructure[i + 1] = temp; + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/Sorting/MergeSort.cs b/src/coreclr/src/tools/Common/Sorting/MergeSort.cs new file mode 100644 index 00000000000000..f05d32e8bf89e5 --- /dev/null +++ b/src/coreclr/src/tools/Common/Sorting/MergeSort.cs @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using ILCompiler.Sorting.Implementation; + +namespace ILCompiler +{ + public static class MergeSortApi + { + // Parallel sorting api which will sort in parallel when appropriate + public static void MergeSort(this List listToSort, Comparison comparison) + { + MergeSortCore, ListAccessor, ComparisonWrapper, RequireTotalOrderAssert>.ParallelSortApi(listToSort, new ComparisonWrapper(comparison)); + } + + // Parallel sorting api which will sort in parallel when appropriate + public static void MergeSortAllowDuplicates(this List listToSort, Comparison comparison) + { + MergeSortCore, ListAccessor, ComparisonWrapper, AllowDuplicates>.ParallelSortApi(listToSort, new ComparisonWrapper(comparison)); + } + + // Parallel sorting api which will sort in parallel when appropriate + public static void MergeSort(this List listToSort, IComparer comparer) + { + MergeSortCore, ListAccessor, IComparer, RequireTotalOrderAssert>.ParallelSortApi(listToSort, comparer); + } + + // Parallel sorting api which will sort in parallel when appropriate + public static void MergeSortAllowDuplicates(this List listToSort, IComparer comparer) + { + MergeSortCore, ListAccessor, IComparer, AllowDuplicates>.ParallelSortApi(listToSort, comparer); + } + + // Parallel sorting api which will sort in parallel when appropriate + public static void MergeSort(this T[] arrayToSort, Comparison comparison) + { + MergeSortCore, ComparisonWrapper, RequireTotalOrderAssert>.ParallelSortApi(arrayToSort, new ComparisonWrapper(comparison)); + } + + // Parallel sorting api which will sort in parallel when appropriate + public static void MergeSortAllowDuplicates(this T[] arrayToSort, Comparison comparison) + { + MergeSortCore, ComparisonWrapper, AllowDuplicates>.ParallelSortApi(arrayToSort, new ComparisonWrapper(comparison)); + } + + // Parallel sorting api which will sort in parallel when appropriate + public static void MergeSort(this T[] arrayToSort, IComparer comparer) + { + MergeSortCore, IComparer, RequireTotalOrderAssert>.ParallelSortApi(arrayToSort, comparer); + } + + // Parallel sorting api which will sort in parallel when appropriate + public static void MergeSortAllowDuplicates(this T[] arrayToSort, IComparer comparer) + { + MergeSortCore, IComparer, AllowDuplicates>.ParallelSortApi(arrayToSort, comparer); + } + + + // Internal helper struct used to enable use of Comparison delegates instead of IComparer instances + private struct ComparisonWrapper : IComparer + { + Comparison _comparison; + public ComparisonWrapper(Comparison comparison) + { + _comparison = comparison; + } + int IComparer.Compare(T x, T y) + { + return _comparison(x, y); + } + } + } +} diff --git a/src/coreclr/src/tools/Common/Sorting/MergeSortCore.cs b/src/coreclr/src/tools/Common/Sorting/MergeSortCore.cs new file mode 100644 index 00000000000000..1a204bebb0eec7 --- /dev/null +++ b/src/coreclr/src/tools/Common/Sorting/MergeSortCore.cs @@ -0,0 +1,130 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ILCompiler.Sorting.Implementation +{ + internal static class MergeSortCore + where TDataStructureAccessor:ISortableDataStructureAccessor + where TComparer:IComparer + where TCompareAsEqualAction : ICompareAsEqualAction + { + internal const int ParallelSortThreshold = 4000; // Number empirically measured by compiling + // a large composite binary + + public static void ParallelSortApi(TDataStructure arrayToSort, TComparer comparer) + { + TDataStructureAccessor accessor = default(TDataStructureAccessor); + if (accessor.GetLength(arrayToSort) < ParallelSortThreshold) + { + // If the array is sufficiently small as to not need parallel sorting + // call the sequential algorithm directly, as the parallel api will create + // an unnecessary Task object to wait on + SequentialSort(arrayToSort, 0, accessor.GetLength(arrayToSort), comparer); + } + ParallelSort(arrayToSort, 0, accessor.GetLength(arrayToSort), comparer).Wait(); + } + + // Parallelized merge sort algorithm. Uses Task infrastructure to spread sort across available resources + private static async Task ParallelSort(TDataStructure arrayToSort, int index, int length, TComparer comparer) + { + if (length < ParallelSortThreshold) + { + SequentialSort(arrayToSort, index, length, comparer); + } + else + { + TDataStructureAccessor accessor = default(TDataStructureAccessor); + int halfLen = length / 2; + + TaskCompletionSource rightSortComplete = new System.Threading.Tasks.TaskCompletionSource(); + _ = Task.Run(async () => + { + await ParallelSort(arrayToSort, index + halfLen, length - halfLen, comparer); + rightSortComplete.SetResult(true); + }); + + T[] localCopyOfHalfOfArray = new T[halfLen]; + accessor.Copy(arrayToSort, index, localCopyOfHalfOfArray, 0, halfLen); + await MergeSortCore, TComparer, TCompareAsEqualAction>.ParallelSort(localCopyOfHalfOfArray, 0, halfLen, comparer); + await rightSortComplete.Task; + Merge(localCopyOfHalfOfArray, arrayToSort, index, halfLen, length, comparer); + } + } + + // Normal non-parallel merge sort + // Allocates length/2 in scratch space + private static void SequentialSort(TDataStructure arrayToSort, int index, int length, TComparer comparer) + { + TDataStructureAccessor accessor = default(TDataStructureAccessor); + T[] scratchSpace = new T[accessor.GetLength(arrayToSort) / 2]; + MergeSortHelper(arrayToSort, index, length, comparer, scratchSpace); + } + + // Non-parallel merge sort, used once the region to be sorted is small enough + // scratchSpace must be at least length/2 in size + private static void MergeSortHelper(TDataStructure arrayToSort, int index, int length, TComparer comparer, T[] scratchSpace) + { + if (length <= 1) + { + return; + } + TDataStructureAccessor accessor = default(TDataStructureAccessor); + if (length == 2) + { + if (comparer.Compare(accessor.GetElement(arrayToSort, index), accessor.GetElement(arrayToSort, index + 1)) > 0) + { + accessor.SwapElements(arrayToSort, index, index + 1); + } + return; + } + + int halfLen = length / 2; + MergeSortHelper(arrayToSort, index, halfLen, comparer, scratchSpace); + MergeSortHelper(arrayToSort, index + halfLen, length - halfLen, comparer, scratchSpace); + accessor.Copy(arrayToSort, index, scratchSpace, 0, halfLen); + Merge(scratchSpace, arrayToSort, index, halfLen, length, comparer); + } + + // Shared merge algorithm used in both parallel and sequential variants of the mergesort + private static void Merge(T[] localCopyOfHalfOfArray, TDataStructure arrayToSort, int index, int halfLen, int length, TComparer comparer) + { + TDataStructureAccessor accessor = default(TDataStructureAccessor); + int leftHalfIndex = 0; + int rightHalfIndex = index + halfLen; + int rightHalfEnd = index + length; + for (int i = 0; i < length; i++) + { + if (leftHalfIndex == halfLen) + { + // All of the remaining elements must be from the right half, and thus must already be in position + break; + } + if (rightHalfIndex == rightHalfEnd) + { + // Copy remaining elements from the local copy + accessor.Copy(localCopyOfHalfOfArray, leftHalfIndex, arrayToSort, index + i, length - i); + break; + } + + int comparisonResult = comparer.Compare(localCopyOfHalfOfArray[leftHalfIndex], accessor.GetElement(arrayToSort, rightHalfIndex)); + if (comparisonResult == 0) + { + default(TCompareAsEqualAction).CompareAsEqual(); + } + if (comparisonResult <= 0) + { + accessor.SetElement(arrayToSort, i + index, localCopyOfHalfOfArray[leftHalfIndex++]); + } + else + { + accessor.SetElement(arrayToSort, i + index, accessor.GetElement(arrayToSort, rightHalfIndex++)); + } + } + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/Common/TypeSystem/CodeGen/MethodDelegator.CodeGen.cs b/src/coreclr/src/tools/Common/TypeSystem/CodeGen/MethodDelegator.CodeGen.cs index 7091ea8a955442..afee75c1636168 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/CodeGen/MethodDelegator.CodeGen.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/CodeGen/MethodDelegator.CodeGen.cs @@ -78,11 +78,11 @@ public override bool IsSynchronized } } - public override bool IsNativeCallable + public override bool IsUnmanagedCallersOnly { get { - return _wrappedMethod.IsNativeCallable; + return _wrappedMethod.IsUnmanagedCallersOnly; } } diff --git a/src/coreclr/src/tools/Common/TypeSystem/CodeGen/MethodDesc.CodeGen.cs b/src/coreclr/src/tools/Common/TypeSystem/CodeGen/MethodDesc.CodeGen.cs index 5884f1dcb4caca..b15a81d9c3cb08 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/CodeGen/MethodDesc.CodeGen.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/CodeGen/MethodDesc.CodeGen.cs @@ -122,7 +122,7 @@ public virtual bool IsSynchronized /// Gets a value specifying whether this method is directly callable /// by external unmanaged code. /// - public virtual bool IsNativeCallable + public virtual bool IsUnmanagedCallersOnly { get { @@ -230,11 +230,11 @@ public override bool IsSynchronized } } - public override bool IsNativeCallable + public override bool IsUnmanagedCallersOnly { get { - return _methodDef.IsNativeCallable; + return _methodDef.IsUnmanagedCallersOnly; } } @@ -322,11 +322,11 @@ public override bool IsSynchronized } } - public override bool IsNativeCallable + public override bool IsUnmanagedCallersOnly { get { - return _typicalMethodDef.IsNativeCallable; + return _typicalMethodDef.IsUnmanagedCallersOnly; } } diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs index e1b1beee81928f..cd7f45d7f4ce04 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs @@ -281,10 +281,7 @@ public LayoutInt ThreadGcStaticFieldAlignment } } - /// - /// Gets a value indicating whether the fields of the type satisfy the Homogeneous Float Aggregate classification. - /// - public bool IsHfa + public ValueTypeShapeCharacteristics ValueTypeShapeCharacteristics { get { @@ -292,41 +289,42 @@ public bool IsHfa { ComputeValueTypeShapeCharacteristics(); } - return (_valueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.HomogenousFloatAggregate) != 0; + return _valueTypeShapeCharacteristics; } } - internal ValueTypeShapeCharacteristics ValueTypeShapeCharacteristics + private void ComputeValueTypeShapeCharacteristics() { - get - { - if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics)) - { - ComputeValueTypeShapeCharacteristics(); - } - return _valueTypeShapeCharacteristics; - } + _valueTypeShapeCharacteristics = this.Context.GetLayoutAlgorithmForType(this).ComputeValueTypeShapeCharacteristics(this); + _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics); } /// - /// Get the Homogeneous Float Aggregate element type if this is a HFA type ( is true). + /// Gets a value indicating whether the type is a homogeneous floating-point or short-vector aggregate. /// - public DefType HfaElementType + public bool IsHomogeneousAggregate { get { - // We are not caching this because this is rare and not worth wasting space in DefType. - return this.Context.GetLayoutAlgorithmForType(this).ComputeHomogeneousFloatAggregateElementType(this); + return (ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) != 0; } } - private void ComputeValueTypeShapeCharacteristics() + /// + /// If the type is a homogeneous floating-point or short-vector aggregate, returns its element size. + /// + public int GetHomogeneousAggregateElementSize() { - _valueTypeShapeCharacteristics = this.Context.GetLayoutAlgorithmForType(this).ComputeValueTypeShapeCharacteristics(this); - _fieldLayoutFlags.AddFlags(FieldLayoutFlags.ComputedValueTypeShapeCharacteristics); + return (ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) switch + { + ValueTypeShapeCharacteristics.Float32Aggregate => 4, + ValueTypeShapeCharacteristics.Float64Aggregate => 8, + ValueTypeShapeCharacteristics.Vector64Aggregate => 8, + ValueTypeShapeCharacteristics.Vector128Aggregate => 16, + _ => throw new InvalidOperationException() + }; } - public void ComputeInstanceLayout(InstanceLayoutKind layoutKind) { if (_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeFieldsLayout | FieldLayoutFlags.ComputedInstanceTypeLayout)) diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/ExceptionStringID.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/ExceptionStringID.cs index 9c0ef31e11b994..d510e7933f718a 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Common/ExceptionStringID.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/ExceptionStringID.cs @@ -31,7 +31,7 @@ public enum ExceptionStringID InvalidProgramSpecific, InvalidProgramVararg, InvalidProgramCallVirtFinalize, - InvalidProgramNativeCallable, + InvalidProgramUnmanagedCallersOnly, InvalidProgramCallAbstractMethod, InvalidProgramCallVirtStatic, InvalidProgramNonStaticMethod, diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs index 720c80a65978d9..d43eb0039099da 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs @@ -33,16 +33,10 @@ public abstract class FieldLayoutAlgorithm public abstract bool ComputeContainsGCPointers(DefType type); /// - /// Compute the shape of a valuetype. The shape information is used to control code generation and allocation - /// (such as vectorization, passing the valuetype by value across method calls, or boxing alignment). + /// Compute the shape of a value type. The shape information is used to control code generation and allocation + /// (such as vectorization, passing the value type by value across method calls, or boxing alignment). /// public abstract ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type); - - /// - /// If the type has characteristic, returns - /// the element type of the homogenous float aggregate. This will either be System.Double or System.Float. - /// - public abstract DefType ComputeHomogeneousFloatAggregateElementType(DefType type); } /// @@ -119,8 +113,38 @@ public enum ValueTypeShapeCharacteristics None = 0x00, /// - /// The structure is an aggregate of floating point values of the same type. + /// The type is an aggregate of 32-bit floating-point values. + /// + Float32Aggregate = 0x01, + + /// + /// The type is an aggregate of 64-bit floating-point values. + /// + Float64Aggregate = 0x02, + + /// + /// The type is an aggregate of 64-bit short-vector values. + /// + Vector64Aggregate = 0x04, + + /// + /// The type is an aggregate of 128-bit short-vector values. + /// + Vector128Aggregate = 0x08, + + /// + /// The mask for homogeneous aggregates of floating-point values. + /// + FloatingPointAggregateMask = Float32Aggregate | Float64Aggregate, + + /// + /// The mask for homogeneous aggregates of short-vector values. + /// + ShortVectorAggregateMask = Vector64Aggregate | Vector128Aggregate, + + /// + /// The mask for homogeneous aggregates. /// - HomogenousFloatAggregate = 0x01, + AggregateMask = FloatingPointAggregateMask | ShortVectorAggregateMask, } } diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 8dddf295adc465..4c7c5cfb6c599f 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -830,129 +830,102 @@ public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristi if (!type.IsValueType) return ValueTypeShapeCharacteristics.None; - ValueTypeShapeCharacteristics result = ComputeHomogeneousFloatAggregateCharacteristic(type); + ValueTypeShapeCharacteristics result = ComputeHomogeneousAggregateCharacteristic(type); // TODO: System V AMD64 characteristics (https://github.com/dotnet/corert/issues/158) return result; } - private ValueTypeShapeCharacteristics ComputeHomogeneousFloatAggregateCharacteristic(DefType type) + private ValueTypeShapeCharacteristics ComputeHomogeneousAggregateCharacteristic(DefType type) { + // Use this constant to make the code below more laconic + const ValueTypeShapeCharacteristics NotHA = ValueTypeShapeCharacteristics.None; + Debug.Assert(type.IsValueType); + TargetArchitecture targetArch = type.Context.Target.Architecture; + if ((targetArch != TargetArchitecture.ARM) && (targetArch != TargetArchitecture.ARM64)) + return NotHA; + MetadataType metadataType = (MetadataType)type; - // No HFAs with explicit layout. There may be cases where explicit layout may be still - // eligible for HFA, but it is hard to tell the real intent. Make it simple and just - // unconditionally disable HFAs for explicit layout. + // No HAs with explicit layout. There may be cases where explicit layout may be still + // eligible for HA, but it is hard to tell the real intent. Make it simple and just + // unconditionally disable HAs for explicit layout. if (metadataType.IsExplicitLayout) - return ValueTypeShapeCharacteristics.None; + return NotHA; switch (metadataType.Category) { + // These are the primitive types that constitute a HFA type case TypeFlags.Single: + return ValueTypeShapeCharacteristics.Float32Aggregate; case TypeFlags.Double: - // These are the primitive types that constitute a HFA type. - return ValueTypeShapeCharacteristics.HomogenousFloatAggregate; + return ValueTypeShapeCharacteristics.Float64Aggregate; case TypeFlags.ValueType: - DefType expectedElementType = null; + // Find the common HA element type if any + ValueTypeShapeCharacteristics haResultType = NotHA; foreach (FieldDesc field in metadataType.GetFields()) { if (field.IsStatic) continue; - // If a field isn't a DefType, then this type cannot be an HFA type - // If a field isn't a HFA type, then this type cannot be an HFA type - DefType fieldType = field.FieldType as DefType; - if (fieldType == null || !fieldType.IsHfa) - return ValueTypeShapeCharacteristics.None; + // If a field isn't a DefType, then this type cannot be a HA type + if (!(field.FieldType is DefType fieldType)) + return NotHA; + + // If a field isn't a HA type, then this type cannot be a HA type + ValueTypeShapeCharacteristics haFieldType = fieldType.ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask; + if (haFieldType == NotHA) + return NotHA; - if (expectedElementType == null) + if (haResultType == NotHA) { - // If we hadn't yet figured out what form of HFA this type might be, we've - // now found one case. - expectedElementType = fieldType.HfaElementType; - Debug.Assert(expectedElementType != null); + // If we hadn't yet figured out what form of HA this type might be, we've now found one case + haResultType = haFieldType; } - else if (expectedElementType != fieldType.HfaElementType) + else if (haResultType != haFieldType) { - // If we had already determined the possible HFA type of the current type, but + // If we had already determined the possible HA type of the current type, but // the field we've encountered is not of that type, then the current type cannot - // be an HFA type. - return ValueTypeShapeCharacteristics.None; + // be a HA type. + return NotHA; } } - // No fields means this is not HFA. - if (expectedElementType == null) - return ValueTypeShapeCharacteristics.None; + // If there are no instance fields, this is not a HA type + if (haResultType == NotHA) + return NotHA; - // Types which are indeterminate in field size are not considered to be HFA - if (expectedElementType.InstanceFieldSize.IsIndeterminate) - return ValueTypeShapeCharacteristics.None; + int haElementSize = haResultType switch + { + ValueTypeShapeCharacteristics.Float32Aggregate => 4, + ValueTypeShapeCharacteristics.Float64Aggregate => 8, + ValueTypeShapeCharacteristics.Vector64Aggregate => 8, + ValueTypeShapeCharacteristics.Vector128Aggregate => 16, + _ => throw new ArgumentOutOfRangeException() + }; - // Types which are indeterminate in field size are not considered to be HFA + // Types which are indeterminate in field size are not considered to be HA if (type.InstanceFieldSize.IsIndeterminate) - return ValueTypeShapeCharacteristics.None; + return NotHA; // Note that we check the total size, but do not perform any checks on number of fields: - // - Type of fields can be HFA valuetype itself - // - Managed C++ HFA valuetypes have just one of type float to signal that - // the valuetype is HFA and explicitly specified size - int maxSize = expectedElementType.InstanceFieldSize.AsInt * expectedElementType.Context.Target.MaximumHfaElementCount; + // - Type of fields can be HA valuetype itself. + // - Managed C++ HA valuetypes have just one of type float to signal that + // the valuetype is HA and explicitly specified size. + int maxSize = haElementSize * type.Context.Target.MaxHomogeneousAggregateElementCount; if (type.InstanceFieldSize.AsInt > maxSize) - return ValueTypeShapeCharacteristics.None; + return NotHA; - // All the tests passed. This is an HFA type. - return ValueTypeShapeCharacteristics.HomogenousFloatAggregate; + // All the tests passed. This is a HA type. + return haResultType; } - return ValueTypeShapeCharacteristics.None; - } - - public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) - { - if (!type.IsHfa) - return null; - - if (type.IsWellKnownType(WellKnownType.Double) || type.IsWellKnownType(WellKnownType.Single)) - return type; - - for (; ; ) - { - Debug.Assert(type.IsValueType); - - // All HFA fields have to be of the same HFA type, so we can just return the type of the first field - TypeDesc firstFieldType = null; - foreach (var field in type.GetFields()) - { - if (field.IsStatic) - continue; - - firstFieldType = field.FieldType; - break; - } - Debug.Assert(firstFieldType != null, "Why is IsHfa true on this type?"); - - switch (firstFieldType.Category) - { - case TypeFlags.Single: - case TypeFlags.Double: - return (DefType)firstFieldType; - - case TypeFlags.ValueType: - // Drill into the struct and find the type of its first field - type = (DefType)firstFieldType; - break; - - default: - Debug.Fail("Why is IsHfa true on this type?"); - return null; - } - } + return NotHA; } private struct SizeAndAlignment diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/TargetDetails.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/TargetDetails.cs index 8f910dd00636ee..9337d7670904aa 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Common/TargetDetails.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/TargetDetails.cs @@ -31,6 +31,7 @@ public enum TargetOS OSX, FreeBSD, NetBSD, + SunOS, WebAssembly, } @@ -316,14 +317,15 @@ public bool IsOSX } /// - /// Maximum number of elements in a HFA type. + /// Maximum number of elements in a homogeneous aggregate type. /// - public int MaximumHfaElementCount + public int MaxHomogeneousAggregateElementCount { get { - // There is a hard limit of 4 elements on an HFA type, see + // There is a hard limit of 4 elements on an HFA/HVA type, see // https://devblogs.microsoft.com/cppblog/introducing-vector-calling-convention/ + // and Procedure Call Standard for the Arm 64-bit Architecture. Debug.Assert(Architecture == TargetArchitecture.ARM || Architecture == TargetArchitecture.ARM64 || Architecture == TargetArchitecture.X64 || diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/TypeDesc.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeDesc.cs index d9110d148e1d12..cf266f0c0990f6 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Common/TypeDesc.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/TypeDesc.cs @@ -188,7 +188,7 @@ public bool IsValueType /// /// Gets a value indicating whether this is one of the primitive types (boolean, char, void, - /// a floating point, or an integer type). + /// a floating-point, or an integer type). /// public bool IsPrimitive { @@ -198,6 +198,34 @@ public bool IsPrimitive } } + /// + /// Gets a value indicating whether this is one of the primitive numeric types + /// (a floating-point or an integer type). + /// + public bool IsPrimitiveNumeric + { + get + { + switch (GetTypeFlags(TypeFlags.CategoryMask)) + { + case TypeFlags.SByte: + case TypeFlags.Byte: + case TypeFlags.Int16: + case TypeFlags.UInt16: + case TypeFlags.Int32: + case TypeFlags.UInt32: + case TypeFlags.Int64: + case TypeFlags.UInt64: + case TypeFlags.Single: + case TypeFlags.Double: + return true; + + default: + return false; + } + } + } + /// /// Gets a value indicating whether this is an enum type. /// Access to retrieve the underlying integral type. diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs new file mode 100644 index 00000000000000..4376f9e25d9700 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.Algorithm.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + partial struct GCPointerMap + { + /// + /// Computes the GC pointer map for the instance fields of . + /// + public static GCPointerMap FromInstanceLayout(DefType type) + { + Debug.Assert(type.ContainsGCPointers); + + GCPointerMapBuilder builder = new GCPointerMapBuilder(type.InstanceByteCount.AsInt, type.Context.Target.PointerSize); + FromInstanceLayoutHelper(ref builder, type); + + return builder.ToGCMap(); + } + + private static void FromInstanceLayoutHelper(ref GCPointerMapBuilder builder, DefType type) + { + if (!type.IsValueType && type.HasBaseType) + { + DefType baseType = type.BaseType; + GCPointerMapBuilder baseLayoutBuilder = builder.GetInnerBuilder(0, baseType.InstanceByteCount.AsInt); + FromInstanceLayoutHelper(ref baseLayoutBuilder, baseType); + } + + foreach (FieldDesc field in type.GetFields()) + { + if (field.IsStatic) + continue; + + TypeDesc fieldType = field.FieldType; + if (fieldType.IsGCPointer) + { + builder.MarkGCPointer(field.Offset.AsInt); + } + else if (fieldType.IsValueType) + { + var fieldDefType = (DefType)fieldType; + if (fieldDefType.ContainsGCPointers) + { + GCPointerMapBuilder innerBuilder = + builder.GetInnerBuilder(field.Offset.AsInt, fieldDefType.InstanceByteCount.AsInt); + FromInstanceLayoutHelper(ref innerBuilder, fieldDefType); + } + } + } + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.cs b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.cs new file mode 100644 index 00000000000000..482e502894d179 --- /dev/null +++ b/src/coreclr/src/tools/Common/TypeSystem/Common/Utilities/GCPointerMap.cs @@ -0,0 +1,272 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Text; + +using Debug = System.Diagnostics.Debug; + +namespace Internal.TypeSystem +{ + /// + /// Represents a bitmap of GC pointers within a memory region divided into + /// pointer-sized cells. + /// + public partial struct GCPointerMap : IEquatable, IComparable + { + // Each bit in this array represents a pointer-sized cell. + private uint[] _gcFlags; + + private int _numCells; + + /// + /// Gets a value indicating whether this map is initialized. + /// + public bool IsInitialized + { + get + { + return _gcFlags != null; + } + } + + /// + /// Gets the size (in cells) of the pointer map. + /// + public int Size + { + get + { + return _numCells; + } + } + + /// + /// Gets the number of continuous runs of GC pointers within the map. + /// + public int NumSeries + { + get + { + int numSeries = 0; + for (int i = 0; i < _numCells; i++) + { + if (this[i]) + { + numSeries++; + while (++i < _numCells && this[i]) ; + } + } + return numSeries; + } + } + + /// + /// Returns true if the map is all pointers + /// + public bool IsAllGCPointers + { + get + { + for (int i = 0; i < _numCells; i++) + { + if (!this[i]) + return false; + } + return true; + } + } + + public bool this[int index] + { + get + { + return (_gcFlags[index >> 5] & (1 << (index & 0x1F))) != 0; + } + } + + public GCPointerMap(uint[] gcFlags, int numCells) + { + Debug.Assert(numCells <= gcFlags.Length << 5); + _gcFlags = gcFlags; + _numCells = numCells; + } + + public BitEnumerator GetEnumerator() + { + return new BitEnumerator(_gcFlags, 0, _numCells); + } + + public override bool Equals(object obj) + { + return obj is GCPointerMap && Equals((GCPointerMap)obj); + } + + public bool Equals(GCPointerMap other) + { + if (_numCells != other._numCells) + return false; + + for (int i = 0; i < _gcFlags.Length; i++) + if (_gcFlags[i] != other._gcFlags[i]) + return false; + + return true; + } + + public override int GetHashCode() + { + int hashCode = 0; + for (int i = 0; i < _gcFlags.Length; i++) + hashCode ^= (int)_gcFlags[i]; + return hashCode; + } + + public override string ToString() + { + var sb = new StringBuilder(_numCells); + foreach (var bit in this) + sb.Append(bit ? '1' : '0'); + return sb.ToString(); + } + + public int CompareTo(GCPointerMap other) + { + if (_numCells != other._numCells) + return _numCells - other._numCells; + + for (int i = 0; i < _gcFlags.Length; i++) + { + if (_gcFlags[i] != other._gcFlags[i]) + return (int)(_gcFlags[i] - other._gcFlags[i]); + } + + Debug.Assert(Equals(other)); + return 0; + } + } + + /// + /// Utility class to assist in building . + /// + public struct GCPointerMapBuilder + { + // Each bit in this array represents a pointer-sized cell. + // Bits start at the least significant bit. + private uint[] _gcFlags; + + private int _pointerSize; + + // Both of these are in bytes. + private int _delta; + private int _limit; + + public GCPointerMapBuilder(int numBytes, int pointerSize) + { + // Align the size up. The size of the pointer map is used to infer the statics storage size that has + // to include space for non-GC statics smaller than pointer size. + int numPointerSizedCells = (numBytes + pointerSize - 1) / pointerSize; + + if (numPointerSizedCells > 0) + { + // Given the number of cells, how many Int32's do we need to represent them? + // (It's one bit per cell, but this time we need to round up.) + _gcFlags = new uint[((numPointerSizedCells - 1) >> 5) + 1]; + } + else + { + // Not big enough to fit even a single pointer. + _gcFlags = Array.Empty(); + } + + _pointerSize = pointerSize; + + _delta = 0; + _limit = numBytes; + } + + public void MarkGCPointer(int offset) + { + Debug.Assert(offset >= 0); + + int absoluteOffset = _delta + offset; + + Debug.Assert(absoluteOffset % _pointerSize == 0); + Debug.Assert(absoluteOffset <= (_limit - _pointerSize)); + + int cellIndex = absoluteOffset / _pointerSize; + + _gcFlags[cellIndex >> 5] |= 1u << (cellIndex & 0x1F); + } + + public GCPointerMapBuilder GetInnerBuilder(int offset, int size) + { + Debug.Assert(offset >= 0); + + int absoluteOffset = _delta + offset; + + Debug.Assert(absoluteOffset + size <= _limit); + + return new GCPointerMapBuilder + { + _gcFlags = this._gcFlags, + _pointerSize = this._pointerSize, + _delta = absoluteOffset, + _limit = absoluteOffset + size + }; + } + + public GCPointerMap ToGCMap() + { + Debug.Assert(_delta == 0); + return new GCPointerMap(_gcFlags, (_limit + _pointerSize - 1) / _pointerSize); + } + + public BitEnumerator GetEnumerator() + { + int numCells = (_limit - _delta) / _pointerSize; + int startCell = _delta / _pointerSize; + return new BitEnumerator(_gcFlags, startCell, numCells); + } + + public override string ToString() + { + var sb = new StringBuilder(); + foreach (var bit in this) + sb.Append(bit ? '1' : '0'); + return sb.ToString(); + } + } + + public struct BitEnumerator + { + private uint[] _buffer; + private int _limitBit; + private int _currentBit; + + public BitEnumerator(uint[] buffer, int startBit, int numBits) + { + Debug.Assert(startBit >= 0 && numBits >= 0); + Debug.Assert(startBit + numBits <= buffer.Length << 5); + + _buffer = buffer; + _currentBit = startBit - 1; + _limitBit = startBit + numBits; + } + + public bool Current + { + get + { + return (_buffer[_currentBit >> 5] & (1 << (_currentBit & 0x1F))) != 0; + } + } + + public bool MoveNext() + { + _currentBit++; + return _currentBit < _limitBit; + } + } +} diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.Sorting.cs index b9cfbda2859232..c5e20b5362b957 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.Sorting.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.Sorting.cs @@ -17,12 +17,14 @@ protected internal override int CompareToImpl(MethodDesc other, TypeSystemCompar EcmaModule module = _type.EcmaModule; EcmaModule otherModule = otherMethod._type.EcmaModule; - - int result = module.MetadataReader.GetToken(_handle) - otherModule.MetadataReader.GetToken(otherMethod._handle); + + // Sort by module in preference to by token. This will place methods of the same type near each other + // even when working with several modules + int result = module.CompareTo(otherModule); if (result != 0) return result; - return module.CompareTo(otherModule); + return module.MetadataReader.GetToken(_handle) - otherModule.MetadataReader.GetToken(otherMethod._handle); } } } diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.cs index 6d1aa8a59bc5d2..d4e0fbd9915e5c 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaMethod.cs @@ -30,7 +30,7 @@ private static class MethodFlags public const int AttributeMetadataCache = 0x02000; public const int Intrinsic = 0x04000; - public const int NativeCallable = 0x08000; + public const int UnmanagedCallersOnly = 0x08000; public const int RuntimeExport = 0x10000; }; @@ -197,9 +197,9 @@ private int InitializeMethodFlags(int mask) else if (metadataReader.StringComparer.Equals(namespaceHandle, "System.Runtime.InteropServices")) { - if (metadataReader.StringComparer.Equals(nameHandle, "NativeCallableAttribute")) + if (metadataReader.StringComparer.Equals(nameHandle, "UnmanagedCallersOnlyAttribute")) { - flags |= MethodFlags.NativeCallable; + flags |= MethodFlags.UnmanagedCallersOnly; } } else @@ -334,11 +334,11 @@ public override bool IsSynchronized } } - public override bool IsNativeCallable + public override bool IsUnmanagedCallersOnly { get { - return (GetMethodFlags(MethodFlags.AttributeMetadataCache | MethodFlags.NativeCallable) & MethodFlags.NativeCallable) != 0; + return (GetMethodFlags(MethodFlags.AttributeMetadataCache | MethodFlags.UnmanagedCallersOnly) & MethodFlags.UnmanagedCallersOnly) != 0; } } diff --git a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Sorting.cs index 246f36aa3f02a1..77a3fbe46a7625 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Sorting.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Ecma/EcmaType.Sorting.cs @@ -13,12 +13,14 @@ partial class EcmaType protected internal override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) { + // Sort by module in preference to by token. This will place types from the same module near each other + // even when working with several modules. var otherType = (EcmaType)other; - int result = _module.MetadataReader.GetToken(_handle) - otherType._module.MetadataReader.GetToken(otherType._handle); + int result = _module.CompareTo(otherType._module); if (result != 0) return result; - return _module.CompareTo(otherType._module); + return _module.MetadataReader.GetToken(_handle) - otherType._module.MetadataReader.GetToken(otherType._handle); } } } diff --git a/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs b/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs index 8635957e67085f..ac307a8b2c74f3 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs @@ -158,6 +158,9 @@ internal static TypeDesc GetNativeTypeFromMarshallerKind(TypeDesc type, case MarshallerKind.AsAnyW: return context.GetWellKnownType(WellKnownType.IntPtr); + case MarshallerKind.ComInterface: + return context.GetWellKnownType(WellKnownType.IntPtr); + case MarshallerKind.Unknown: default: throw new NotSupportedException(); @@ -563,6 +566,10 @@ internal static MarshallerKind GetMarshallerKind( else return MarshallerKind.Invalid; } + else if (type.IsInterface) + { + return MarshallerKind.ComInterface; + } else return MarshallerKind.Invalid; } diff --git a/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/Marshaller.cs b/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/Marshaller.cs index db6e71fc11645e..50f9254171ea98 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/Marshaller.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Interop/IL/Marshaller.cs @@ -50,6 +50,7 @@ enum MarshallerKind LayoutClassPtr, AsAnyA, AsAnyW, + ComInterface, Invalid } public enum MarshalDirection @@ -597,9 +598,14 @@ protected void LoadNativeValue(ILCodeStream stream) protected void LoadNativeArg(ILCodeStream stream) { if (IsNativeByRef) + { _nativeHome.LoadAddr(stream); + stream.Emit(ILOpcode.conv_i); + } else + { _nativeHome.LoadValue(stream); + } } protected void LoadNativeAddr(ILCodeStream stream) @@ -904,7 +910,7 @@ protected override void EmitMarshalArgumentManagedToNative() protected override void EmitMarshalArgumentNativeToManaged() { - if (Out) + if (Out && !IsNativeByRef) { base.EmitMarshalArgumentNativeToManaged(); } diff --git a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs index 91c3d9e1f1149b..7006d95dd71f6e 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs @@ -58,13 +58,5 @@ public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristi return canonicalType.ValueTypeShapeCharacteristics; } - - public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) - { - RuntimeDeterminedType runtimeDeterminedType = (RuntimeDeterminedType)type; - DefType canonicalType = runtimeDeterminedType.CanonicalType; - - return canonicalType.HfaElementType; - } } } diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/InstantiatedMethod.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/InstantiatedMethod.Sorting.cs index 17b270780ce797..065c1227213608 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Sorting/InstantiatedMethod.Sorting.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/InstantiatedMethod.Sorting.cs @@ -12,21 +12,27 @@ partial class InstantiatedMethod protected internal override int CompareToImpl(MethodDesc other, TypeSystemComparer comparer) { var otherMethod = (InstantiatedMethod)other; - int result = _instantiation.Length - otherMethod._instantiation.Length; - if (result != 0) - return result; - - result = comparer.Compare(_methodDef, otherMethod._methodDef); - if (result != 0) - return result; - + // Sort by instantiation before sorting by associated method definition + // The goal of this is to keep methods which work with the same types near + // to each other. This is a better heuristic than sorting by method definition + // then by instantiation. + // + // The goal is to sort methods like SomeClass.SomeMethod, + // near SomeOtherClass.SomeOtherMethod + int result = 0; + // Sort instantiations of the same type together for (int i = 0; i < _instantiation.Length; i++) { + if (i >= otherMethod._instantiation.Length) + return 1; result = comparer.Compare(_instantiation[i], otherMethod._instantiation[i]); if (result != 0) - break; + return result; } + if (_instantiation.Length < otherMethod._instantiation.Length) + return -1; + result = comparer.Compare(_methodDef, otherMethod._methodDef); return result; } } diff --git a/src/coreclr/src/tools/Common/TypeSystem/Sorting/InstantiatedType.Sorting.cs b/src/coreclr/src/tools/Common/TypeSystem/Sorting/InstantiatedType.Sorting.cs index f749b4559406a6..b983382f6268c2 100644 --- a/src/coreclr/src/tools/Common/TypeSystem/Sorting/InstantiatedType.Sorting.cs +++ b/src/coreclr/src/tools/Common/TypeSystem/Sorting/InstantiatedType.Sorting.cs @@ -14,20 +14,28 @@ partial class InstantiatedType protected internal override int CompareToImpl(TypeDesc other, TypeSystemComparer comparer) { var otherType = (InstantiatedType)other; + // Sort by instantiation before sorting by associated method definition + // The goal of this is to keep methods which work with the same types near + // to each other. This is a better heuristic than sorting by method definition + // then by instantiation. + // + // The goal is to sort classes like SomeClass, + // near SomeOtherClass - int result = comparer.Compare(_typeDef, otherType._typeDef); - if (result == 0) + int result = 0; + // Sort instantiations of the same type together + for (int i = 0; i < _instantiation.Length; i++) { - Debug.Assert(_instantiation.Length == otherType._instantiation.Length); - for (int i = 0; i < _instantiation.Length; i++) - { - result = comparer.Compare(_instantiation[i], otherType._instantiation[i]); - if (result != 0) - break; - } + if (i >= otherType._instantiation.Length) + return 1; + result = comparer.Compare(_instantiation[i], otherType._instantiation[i]); + if (result != 0) + return result; } + if (_instantiation.Length < otherType._instantiation.Length) + return -1; - return result; + return comparer.Compare(_typeDef, otherType._typeDef); } } } diff --git a/src/coreclr/src/tools/GetModuleIndex/GetModuleIndex.cs b/src/coreclr/src/tools/GetModuleIndex/GetModuleIndex.cs deleted file mode 100644 index 93b9adb6796ef7..00000000000000 --- a/src/coreclr/src/tools/GetModuleIndex/GetModuleIndex.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// -using System; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using Microsoft.FileFormats; -using Microsoft.FileFormats.ELF; -using Microsoft.FileFormats.MachO; -using Microsoft.FileFormats.PE; - -public class GetModuleIndex -{ - public static int Main(string[] args) - { - if (args.Length < 2 || string.IsNullOrEmpty(args[0]) || string.IsNullOrEmpty(args[1])) - { - throw new ArgumentException("Invalid command line arguments"); - } - string moduleFileName = args[0]; - string outputFileName = args[1]; - - using (FileStream stream = File.OpenRead(moduleFileName)) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - var elfFile = new ELFFile(new StreamAddressSpace(stream)); - byte[] buildId = elfFile.BuildID; - if (buildId != null) - { - // First byte is the number of bytes total in the build id - string outputText = string.Format("0x{0:x2}, {1}", buildId.Length, ToHexString(buildId)); - File.WriteAllText(outputFileName, outputText); - } - else - { - throw new BadInputFormatException($"{moduleFileName} does not have a build id"); - } - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var peFile = new PEFile(new StreamAddressSpace(stream)); - // First byte is the number of bytes total in the index - string outputText = string.Format("0x{0:x2}, {1} {2}", 8, ToHexString(peFile.Timestamp), ToHexString(peFile.SizeOfImage)); - File.WriteAllText(outputFileName, outputText); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - var machoFile = new MachOFile(new StreamAddressSpace(stream)); - byte[] uuid = machoFile.Uuid; - if (uuid != null) - { - // First byte is the number of bytes total in the build id - string outputText = string.Format("0x{0:x2}, {1}", uuid.Length, ToHexString(uuid)); - File.WriteAllText(outputFileName, outputText); - } - else - { - throw new BadInputFormatException($"{moduleFileName} does not have a uuid"); - } - } - else - { - throw new PlatformNotSupportedException(RuntimeInformation.OSDescription); - } - } - return 0; - } - - private static string ToHexString(uint value) - { - return ToHexString(BitConverter.GetBytes(value)); - } - - private static string ToHexString(byte[] bytes) - { - return string.Concat(bytes.Select(b => string.Format("0x{0:x2}, ", b))); - } -} diff --git a/src/coreclr/src/tools/GetModuleIndex/GetModuleIndex.csproj b/src/coreclr/src/tools/GetModuleIndex/GetModuleIndex.csproj deleted file mode 100644 index addf68e7c33a15..00000000000000 --- a/src/coreclr/src/tools/GetModuleIndex/GetModuleIndex.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - AnyCpu - Exe - netcoreapp5.0 - false - $(BinDir)/GetModuleIndex - - - - - $(MicrosoftFileFormatsVersion) - - - diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/CommandLineOptions.cs b/src/coreclr/src/tools/ReadyToRun.SuperIlc/CommandLineOptions.cs deleted file mode 100644 index 26b4cc3cc4fbc6..00000000000000 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/CommandLineOptions.cs +++ /dev/null @@ -1,252 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.CommandLine; -using System.CommandLine.Builder; -using System.CommandLine.Invocation; -using System.IO; - -namespace ReadyToRun.SuperIlc -{ - internal static class CommandLineOptions - { - public static CommandLineBuilder Build() - { - var parser = new CommandLineBuilder() - .AddCommand(CompileFolder()) - .AddCommand(CompileSubtree()) - .AddCommand(CompileFramework()) - .AddCommand(CompileNugetPackages()) - .AddCommand(CompileCrossgenRsp()); - - return parser; - - Command CompileFolder() => - new Command("compile-directory", "Compile all assemblies in directory", - new Option[] - { - InputDirectory(), - OutputDirectory(), - CoreRootDirectory(), - Crossgen(), - CrossgenPath(), - NoJit(), - NoCrossgen2(), - Exe(), - NoExe(), - NoEtw(), - NoCleanup(), - Map(), - DegreeOfParallelism(), - Sequential(), - Framework(), - UseFramework(), - Release(), - LargeBubble(), - Composite(), - Crossgen2Parallelism(), - ReferencePath(), - IssuesPath(), - CompilationTimeoutMinutes(), - ExecutionTimeoutMinutes(), - R2RDumpPath(), - MeasurePerf(), - InputFileSearchString(), - }, - handler: CommandHandler.Create(CompileDirectoryCommand.CompileDirectory)); - - Command CompileSubtree() => - new Command("compile-subtree", "Build each directory in a given subtree containing any managed assemblies as a separate app", - new Option[] - { - InputDirectory(), - OutputDirectory(), - CoreRootDirectory(), - Crossgen(), - CrossgenPath(), - NoJit(), - NoCrossgen2(), - Exe(), - NoExe(), - NoEtw(), - NoCleanup(), - Map(), - DegreeOfParallelism(), - Sequential(), - Framework(), - UseFramework(), - Release(), - LargeBubble(), - Composite(), - Crossgen2Parallelism(), - ReferencePath(), - IssuesPath(), - CompilationTimeoutMinutes(), - ExecutionTimeoutMinutes(), - R2RDumpPath(), - GCStress(), - }, - handler: CommandHandler.Create(CompileSubtreeCommand.CompileSubtree)); - - Command CompileFramework() => - new Command("compile-framework", "Compile managed framework assemblies in Core_Root", - new Option[] - { - CoreRootDirectory(), - Crossgen(), - CrossgenPath(), - NoCrossgen2(), - NoCleanup(), - DegreeOfParallelism(), - Sequential(), - Release(), - LargeBubble(), - Composite(), - ReferencePath(), - IssuesPath(), - CompilationTimeoutMinutes(), - R2RDumpPath(), - MeasurePerf(), - InputFileSearchString(), - }, - handler: CommandHandler.Create(CompileFrameworkCommand.CompileFramework)); - - Command CompileNugetPackages() => - new Command("compile-nuget", "Restore a list of Nuget packages into an empty console app, publish, and optimize with Crossgen / CPAOT", - new Option[] - { - R2RDumpPath(), - InputDirectory(), - OutputDirectory(), - PackageList(), - CoreRootDirectory(), - Crossgen(), - NoCleanup(), - DegreeOfParallelism(), - CompilationTimeoutMinutes(), - ExecutionTimeoutMinutes(), - }, - handler: CommandHandler.Create(CompileNugetCommand.CompileNuget)); - - Command CompileCrossgenRsp() => - new Command("compile-crossgen-rsp", "Use existing Crossgen .rsp file(s) to build assemblies, optionally rewriting base paths", - new Option[] - { - InputDirectory(), - CrossgenResponseFile(), - OutputDirectory(), - CoreRootDirectory(), - Crossgen(), - NoCleanup(), - DegreeOfParallelism(), - CompilationTimeoutMinutes(), - RewriteOldPath(), - RewriteNewPath(), - }, - handler: CommandHandler.Create(CompileFromCrossgenRspCommand.CompileFromCrossgenRsp)); - - // Todo: Input / Output directories should be required arguments to the command when they're made available to handlers - // https://github.com/dotnet/command-line-api/issues/297 - Option InputDirectory() => - new Option(new[] { "--input-directory", "-in" }, "Folder containing assemblies to optimize", new Argument().ExistingOnly()); - - Option OutputDirectory() => - new Option(new[] { "--output-directory", "-out" }, "Folder to emit compiled assemblies", new Argument().LegalFilePathsOnly()); - - Option CoreRootDirectory() => - new Option(new[] { "--core-root-directory", "-cr" }, "Location of the CoreCLR CORE_ROOT folder", new Argument().ExistingOnly()); - - Option ReferencePath() => - new Option(new[] { "--reference-path", "-r" }, "Folder containing assemblies to reference during compilation", new Argument() { Arity = ArgumentArity.ZeroOrMore }.ExistingOnly()); - - Option Crossgen() => - new Option(new[] { "--crossgen" }, "Compile the apps using Crossgen in the CORE_ROOT folder", new Argument()); - - Option CrossgenPath() => - new Option(new[] { "--crossgen-path", "-cp" }, "Explicit Crossgen path (useful for cross-targeting)", new Argument().ExistingOnly()); - - Option NoJit() => - new Option(new[] { "--nojit" }, "Don't run tests in JITted mode", new Argument()); - - Option NoCrossgen2() => - new Option(new[] { "--nocrossgen2" }, "Don't run tests in Crossgen2 mode", new Argument()); - - Option Exe() => - new Option(new[] { "--exe" }, "Don't compile tests, just execute them", new Argument()); - - Option NoExe() => - new Option(new[] { "--noexe" }, "Compilation-only mode (don't execute the built apps)", new Argument()); - - Option NoEtw() => - new Option(new[] { "--noetw" }, "Don't capture jitted methods using ETW", new Argument()); - - Option NoCleanup() => - new Option(new[] { "--nocleanup" }, "Don't clean up compilation artifacts after test runs", new Argument()); - - Option Map() => - new Option(new[] { "--map" }, "Generate a map file (Crossgen2)", new Argument()); - - Option DegreeOfParallelism() => - new Option(new[] { "--degree-of-parallelism", "-dop" }, "Override default compilation / execution DOP (default = logical processor count)", new Argument()); - - Option Sequential() => - new Option(new[] { "--sequential" }, "Run tests sequentially", new Argument()); - - Option Framework() => - new Option(new[] { "--framework" }, "Precompile and use native framework", new Argument()); - - Option UseFramework() => - new Option(new[] { "--use-framework" }, "Use native framework (don't precompile, assume previously compiled)", new Argument()); - - Option Release() => - new Option(new[] { "--release" }, "Build the tests in release mode", new Argument()); - - Option LargeBubble() => - new Option(new[] { "--large-bubble" }, "Assume all input files as part of one version bubble", new Argument()); - - Option Composite() => - new Option(new[] { "--composite" }, "Compile tests in composite R2R mode", new Argument()); - - Option Crossgen2Parallelism() => - new Option(new[] { "--crossgen2-parallelism" }, "Max number of threads to use in Crossgen2 (default = logical processor count)", new Argument()); - - Option IssuesPath() => - new Option(new[] { "--issues-path", "-ip" }, "Path to issues.targets", new Argument() { Arity = ArgumentArity.ZeroOrMore }); - - Option CompilationTimeoutMinutes() => - new Option(new[] { "--compilation-timeout-minutes", "-ct" }, "Compilation timeout (minutes)", new Argument()); - - Option ExecutionTimeoutMinutes() => - new Option(new[] { "--execution-timeout-minutes", "-et" }, "Execution timeout (minutes)", new Argument()); - - Option R2RDumpPath() => - new Option(new[] { "--r2r-dump-path", "-r2r" }, "Path to R2RDump.exe/dll", new Argument().ExistingOnly()); - - Option CrossgenResponseFile() => - new Option(new [] { "--crossgen-response-file", "-rsp" }, "Response file to transpose", new Argument().ExistingOnly()); - - Option RewriteOldPath() => - new Option(new [] { "--rewrite-old-path" }, "Path substring to replace", new Argument(){ Arity = ArgumentArity.ZeroOrMore }); - - Option RewriteNewPath() => - new Option(new [] { "--rewrite-new-path" }, "Path substring to use instead", new Argument(){ Arity = ArgumentArity.ZeroOrMore }); - - Option MeasurePerf() => - new Option(new[] { "--measure-perf" }, "Print out compilation time", new Argument()); - - Option InputFileSearchString() => - new Option(new[] { "--input-file-search-string", "-input-file" }, "Search string for input files in the input directory", new Argument()); - - Option GCStress() => - new Option(new[] { "--gcstress" }, "Run tests with the specified GC stress level enabled (the argument value is in hex)", new Argument()); - - // - // compile-nuget specific options - // - Option PackageList() => - new Option(new[] { "--package-list", "-pl" }, "Text file containing a package name on each line", new Argument().ExistingOnly()); - } - } -} diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/ComputeManagedAssemblies.cs b/src/coreclr/src/tools/ReadyToRun.SuperIlc/ComputeManagedAssemblies.cs deleted file mode 100644 index 94dd0783408c8c..00000000000000 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/ComputeManagedAssemblies.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Reflection.Metadata; -using System.Reflection.PortableExecutable; - -class ComputeManagedAssemblies -{ - public static IEnumerable GetManagedAssembliesInFolder(string folder) - { - foreach (string file in Directory.EnumerateFiles(folder)) - { - if (IsManaged(file)) - { - yield return file; - } - } - } - - static ConcurrentDictionary _isManagedCache = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - - public static bool IsManaged(string file) - { - // Only files named *.dll and *.exe are considered as possible assemblies - if (!Path.HasExtension(file) || (Path.GetExtension(file) != ".dll" && Path.GetExtension(file) != ".exe")) - return false; - - bool isManaged; - lock (_isManagedCache) - { - if (_isManagedCache.TryGetValue(file, out isManaged)) - { - return isManaged; - } - } - - try - { - using (FileStream moduleStream = File.OpenRead(file)) - using (var module = new PEReader(moduleStream)) - { - if (module.HasMetadata) - { - MetadataReader moduleMetadataReader = module.GetMetadataReader(); - if (moduleMetadataReader.IsAssembly) - { - string culture = moduleMetadataReader.GetString(moduleMetadataReader.GetAssemblyDefinition().Culture); - - if (culture == "" || culture.Equals("neutral", StringComparison.OrdinalIgnoreCase)) - { - isManaged = true; - } - } - } - } - } - catch (BadImageFormatException) - { - isManaged = false; - } - - _isManagedCache[file] = isManaged; - - return isManaged; - } -} diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/CpaotRunner.cs b/src/coreclr/src/tools/ReadyToRun.SuperIlc/CpaotRunner.cs deleted file mode 100644 index 4f5c220fea32a8..00000000000000 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/CpaotRunner.cs +++ /dev/null @@ -1,129 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; - -namespace ReadyToRun.SuperIlc -{ - /// - /// Compiles assemblies using the Cross-Platform AOT compiler - /// - class CpaotRunner : CompilerRunner - { - public override CompilerIndex Index => CompilerIndex.CPAOT; - - // Crossgen2 runs on top of corerun. - protected override string CompilerRelativePath => ""; - - protected override string CompilerFileName => "corerun".AppendOSExeSuffix(); - - private string Crossgen2Path => Path.Combine(_options.CoreRootDirectory.FullName, "crossgen2", "crossgen2.dll"); - - public CpaotRunner(BuildOptions options, IEnumerable referencePaths) - : base(options, referencePaths) - { - // Set SuperIlc parallelism to a low enough value that ensures that each Crossgen2 invocation gets to use its parallelism - if (options.DegreeOfParallelism == 0) - options.DegreeOfParallelism = 2; - } - - public override ProcessParameters CompilationProcess(string outputFileName, IEnumerable inputAssemblyFileNames) - { - ProcessParameters processParameters = base.CompilationProcess(outputFileName, inputAssemblyFileNames); - processParameters.Arguments = $"{Crossgen2Path} {processParameters.Arguments}"; - return processParameters; - } - - protected override ProcessParameters ExecutionProcess(IEnumerable modules, IEnumerable folders, bool noEtw) - { - ProcessParameters processParameters = base.ExecutionProcess(modules, folders, noEtw); - processParameters.EnvironmentOverrides["COMPLUS_ReadyToRun"] = "1"; - return processParameters; - } - - protected override IEnumerable BuildCommandLineArguments(IEnumerable assemblyFileNames, string outputFileName) - { - // The file to compile - foreach (string inputAssembly in assemblyFileNames) - { - yield return inputAssembly; - } - - // Output - yield return $"-o:{outputFileName}"; - - // Todo: Allow control of some of these - yield return "--targetarch=x64"; - - if (_options.Map) - { - yield return "--map"; - } - - if (_options.Release) - { - yield return "-O"; - } - - if (_options.LargeBubble) - { - yield return "--inputbubble"; - } - - if (_options.Composite) - { - yield return "--composite"; - } - - if (_options.Crossgen2Parallelism != 0) - { - yield return $"--parallelism={_options.Crossgen2Parallelism}"; - } - - string frameworkFolder = ""; - if (_options.Framework || _options.UseFramework) - { - frameworkFolder = GetOutputPath(_options.CoreRootDirectory.FullName); - foreach (string frameworkRef in ResolveReferences(new string[] { frameworkFolder }, 'r')) - { - yield return frameworkRef; - } - } - - StringComparer pathComparer = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal); - HashSet uniqueFolders = new HashSet(pathComparer); - - foreach (string assemblyFileName in assemblyFileNames) - { - uniqueFolders.Add(Path.GetDirectoryName(assemblyFileName)); - } - - uniqueFolders.UnionWith(_referenceFolders); - uniqueFolders.Remove(frameworkFolder); - - foreach (string reference in ResolveReferences(uniqueFolders, _options.Composite ? 'u' : 'r')) - { - yield return reference; - } - } - - private IEnumerable ResolveReferences(IEnumerable folders, char referenceOption) - { - foreach (string referenceFolder in folders) - { - foreach (string reference in ComputeManagedAssemblies.GetManagedAssembliesInFolder(referenceFolder)) - { - string simpleName = Path.GetFileNameWithoutExtension(reference); - if (!FrameworkExclusion.Exclude(simpleName, Index, out string reason)) - { - yield return $"-{referenceOption}:{reference}"; - } - } - } - } - } -} diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Program.cs b/src/coreclr/src/tools/ReadyToRun.SuperIlc/Program.cs deleted file mode 100644 index 6549fe49dd6d3d..00000000000000 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Program.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.CommandLine.Builder; -using System.CommandLine.Invocation; -using System.Threading.Tasks; - -namespace ReadyToRun.SuperIlc -{ - class Program - { - static async Task Main(string[] args) - { - var parser = CommandLineOptions.Build().UseDefaults().Build(); - - return await parser.InvokeAsync(args); - } - } -} diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/ReadyToRun.SuperIlc.csproj b/src/coreclr/src/tools/ReadyToRun.SuperIlc/ReadyToRun.SuperIlc.csproj deleted file mode 100644 index f50925530593b1..00000000000000 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/ReadyToRun.SuperIlc.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - ReadyToRun.SuperIlc - true - Exe - $(NetCoreAppCurrent) - netcoreapp3.0 - 8002,NU1701 - AnyCPU - $(BinDir)\ReadyToRun.SuperIlc - - - - - 16.0.461 - - - 16.0.461 - - - 2.0.38 - - - 0.2.0-alpha.19174.3 - - - 1.6.0 - - - diff --git a/src/coreclr/src/tools/crossgen/CMakeLists.txt b/src/coreclr/src/tools/crossgen/CMakeLists.txt index a8a4629a654206..685ba73c11fe5b 100644 --- a/src/coreclr/src/tools/crossgen/CMakeLists.txt +++ b/src/coreclr/src/tools/crossgen/CMakeLists.txt @@ -30,12 +30,12 @@ if(FEATURE_MERGE_JIT_AND_ENGINE) set(CLRJIT_CROSSGEN clrjit_crossgen) endif(FEATURE_MERGE_JIT_AND_ENGINE) -if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) +if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) # The following linked options can be inserted into the linker libraries list to # ensure proper resolving of circular references between a subset of the libraries. set(START_LIBRARY_GROUP -Wl,--start-group) set(END_LIBRARY_GROUP -Wl,--end-group) -endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) +endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) target_link_libraries(crossgen ${START_LIBRARY_GROUP} # Start group of libraries that have circular references diff --git a/src/coreclr/src/tools/crossgen/crossgen.cpp b/src/coreclr/src/tools/crossgen/crossgen.cpp index 15a3f5510c8436..fafad635d39c3a 100644 --- a/src/coreclr/src/tools/crossgen/crossgen.cpp +++ b/src/coreclr/src/tools/crossgen/crossgen.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include "palclr.h" @@ -93,7 +93,7 @@ void ErrorWin32(DWORD err) void PrintLogoHelper() { Output(W("Microsoft (R) CoreCLR Native Image ")); - Outputf(W("Generator - Version %S\n"), VER_FILEVERSION_STR); + Outputf(W("Generator - Version %S\n"), CLR_PRODUCT_VERSION); Outputf(W("%S\n"), VER_LEGALCOPYRIGHT_LOGO_STR); Output(W("\n")); } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs index c7bba81ab13a9e..ffd9293d79ff31 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs @@ -311,7 +311,7 @@ public override void ComputeMarkedNodes() } while (_markStack.Count != 0); if (_resultSorter != null) - _markedNodes.Sort(_resultSorter); + _markedNodes.MergeSortAllowDuplicates(_resultSorter); _markedNodesFinal = _markedNodes.ToImmutableArray(); _markedNodes = null; diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj b/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj index 5293d4d99ee2f4..1b715742062a0b 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj @@ -13,6 +13,7 @@ the same bits tests expect to see in artifacts/crossgen2. That way we never need to wonder which binaries are up to date and which are stale. --> false + Debug;Release;Checked @@ -38,5 +39,24 @@ + + Sorting\ArrayAccessor.cs + + + Sorting\ICompareAsEqualAction.cs + + + Sorting\ISortableDataStructureAccessor.cs + + + Sorting\ListAccessor.cs + + + Sorting\MergeSort.cs + + + Sorting\MergeSortCore.cs + + diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs index 2da9f2400985cf..8238d9418f9ced 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs @@ -50,9 +50,9 @@ internal class ReadyToRunObjectWriter private readonly IEnumerable _nodes; /// - /// True when the executable generator should output a map file. + /// Set to non-null when the executable generator should output a map file. /// - private readonly bool _generateMapFile; + private readonly MapFileBuilder _mapFileBuilder; #if DEBUG private struct NodeInfo @@ -78,31 +78,22 @@ public ReadyToRunObjectWriter(string objectFilePath, EcmaModule componentModule, _componentModule = componentModule; _nodes = nodes; _nodeFactory = factory; - _generateMapFile = generateMapFile; + + if (generateMapFile) + { + _mapFileBuilder = new MapFileBuilder(); + } } public void EmitPortableExecutable() { bool succeeded = false; - FileStream mapFileStream = null; - TextWriter mapFile = null; - try { - if (_generateMapFile) - { - string mapFileName = Path.ChangeExtension(_objectFilePath, ".map"); - mapFileStream = new FileStream(mapFileName, FileMode.Create, FileAccess.Write); - mapFile = new StreamWriter(mapFileStream); - } - Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); - if (mapFile != null) - mapFile.WriteLine($@"R2R object emission started: {DateTime.Now}"); - PEHeaderBuilder headerBuilder; int timeDateStamp; ISymbolNode r2rHeaderExportSymbol; @@ -159,15 +150,13 @@ public void EmitPortableExecutable() if (node is NativeDebugDirectoryEntryNode nddeNode) { // There should be only one NativeDebugDirectoryEntry. - // This assert will need to be revisited when we implement the composite R2R format, where we'll need to figure - // out how native symbols will be emitted, and verify that the DiaSymReader library is able to consume them. Debug.Assert(nativeDebugDirectoryEntryNode == null); nativeDebugDirectoryEntryNode = nddeNode; } string name = null; - if (mapFile != null) + if (_mapFileBuilder != null) { name = depNode.GetType().ToString(); int firstGeneric = name.IndexOf('['); @@ -182,14 +171,11 @@ public void EmitPortableExecutable() } } - EmitObjectData(r2rPeBuilder, nodeContents, nodeIndex, name, node.Section, mapFile); + EmitObjectData(r2rPeBuilder, nodeContents, nodeIndex, name, node.Section, _mapFileBuilder); } - if (!_nodeFactory.CompilationModuleGroup.IsCompositeBuildMode || _componentModule != null) - { - r2rPeBuilder.SetCorHeader(_nodeFactory.CopiedCorHeaderNode, _nodeFactory.CopiedCorHeaderNode.Size); - r2rPeBuilder.SetDebugDirectory(_nodeFactory.DebugDirectoryNode, _nodeFactory.DebugDirectoryNode.Size); - } + r2rPeBuilder.SetCorHeader(_nodeFactory.CopiedCorHeaderNode, _nodeFactory.CopiedCorHeaderNode.Size); + r2rPeBuilder.SetDebugDirectory(_nodeFactory.DebugDirectoryNode, _nodeFactory.DebugDirectoryNode.Size); if (_nodeFactory.Win32ResourcesNode != null) { @@ -201,6 +187,11 @@ public void EmitPortableExecutable() { r2rPeBuilder.Write(peStream, timeDateStamp); + if (_mapFileBuilder != null) + { + _mapFileBuilder.SetFileSize(peStream.Length); + } + // Compute MD5 hash of the output image and store that in the native DebugDirectory entry using (var md5Hash = MD5.Create()) { @@ -214,25 +205,18 @@ public void EmitPortableExecutable() } } - if (mapFile != null) + if (_mapFileBuilder != null) { - mapFile.WriteLine($@"R2R object emission finished: {DateTime.Now}, {stopwatch.ElapsedMilliseconds} msecs"); - mapFile.Flush(); - mapFileStream.Flush(); + r2rPeBuilder.AddSections(_mapFileBuilder); + + string mapFileName = Path.ChangeExtension(_objectFilePath, ".map"); + _mapFileBuilder.Save(mapFileName); } succeeded = true; } finally { - if (mapFile != null) - { - mapFile.Dispose(); - } - if (mapFileStream != null) - { - mapFileStream.Dispose(); - } if (!succeeded) { // If there was an exception while generating the OBJ file, make sure we don't leave the unfinished @@ -264,7 +248,7 @@ public void EmitPortableExecutable() /// Textual representation of the ObjecData blob in the map file /// Section to emit the blob into /// Map file output stream - private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int nodeIndex, string name, ObjectNodeSection section, TextWriter mapFile) + private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int nodeIndex, string name, ObjectNodeSection section, MapFileBuilder mapFileBuilder) { #if DEBUG for (int symbolIndex = 0; symbolIndex < data.DefinedSymbols.Length; symbolIndex++) @@ -283,7 +267,7 @@ private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int node } #endif - r2rPeBuilder.AddObjectData(data, section, name, mapFile); + r2rPeBuilder.AddObjectData(data, section, name, mapFileBuilder); } public static void EmitObject(string objectFilePath, EcmaModule componentModule, IEnumerable nodes, NodeFactory factory, bool generateMapFile) diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/AllMethodsOnTypeNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/AllMethodsOnTypeNode.cs index 643b35fbfc96e9..7d7e9fd8263638 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/AllMethodsOnTypeNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/AllMethodsOnTypeNode.cs @@ -38,9 +38,10 @@ public override IEnumerable GetStaticDependencies(NodeFacto foreach (MethodDesc method in Type.GetAllMethods()) { - if (!method.IsGenericMethodDefinition && context.CompilationModuleGroup.VersionsWithMethodBody(method)) + if (!method.IsGenericMethodDefinition && + context.CompilationModuleGroup.ContainsMethodBody(method, false)) { - dependencies.Add(context.MethodEntrypoint(method), $"Method on type {Type.ToString()}"); + dependencies.Add(context.CompiledMethodNode(method), $"Method on type {Type.ToString()}"); } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ArrayOfEmbeddedDataNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ArrayOfEmbeddedDataNode.cs index 4287b78b032ce1..7cfec07fa65320 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ArrayOfEmbeddedDataNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ArrayOfEmbeddedDataNode.cs @@ -88,7 +88,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly) builder.RequireInitialPointerAlignment(); if (_sorter != null) - _nestedNodesList.Sort(_sorter); + _nestedNodesList.MergeSort(_sorter); builder.AddSymbol(StartSymbol); diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs index abc90394c1ab07..cc70462c144549 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ArgIterator.cs @@ -85,10 +85,11 @@ public bool RequiresAlign8() } return _type.RequiresAlign8(); } - public bool IsHFA() + + public bool IsHomogeneousAggregate() { - if (_type.Context.Target.Architecture != TargetArchitecture.ARM && - _type.Context.Target.Architecture != TargetArchitecture.ARM64) + TargetArchitecture targetArch = _type.Context.Target.Architecture; + if ((targetArch != TargetArchitecture.ARM) && (targetArch != TargetArchitecture.ARM64)) { return false; } @@ -96,29 +97,21 @@ public bool IsHFA() { return false; } - return _type is DefType defType && defType.IsHfa; + return _type is DefType defType && defType.IsHomogeneousAggregate; } - public CorElementType GetHFAType() + public int GetHomogeneousAggregateElementSize() { - Debug.Assert(IsHFA()); + Debug.Assert(IsHomogeneousAggregate()); switch (_type.Context.Target.Architecture) { case TargetArchitecture.ARM: - if (RequiresAlign8()) - { - return CorElementType.ELEMENT_TYPE_R8; - } - break; + return RequiresAlign8() ? 8 : 4; case TargetArchitecture.ARM64: - if (_type is DefType defType && defType.InstanceFieldAlignment.Equals(new LayoutInt(_type.Context.Target.PointerSize))) - { - return CorElementType.ELEMENT_TYPE_R8; - } - break; + return ((DefType)_type).GetHomogeneousAggregateElementSize(); } - return CorElementType.ELEMENT_TYPE_R4; + throw new InvalidOperationException(); } public CorElementType GetCorElementType() @@ -235,7 +228,6 @@ internal struct ArgLocDesc public int m_idxGenReg; // First general register used (or -1) public short m_cGenReg; // Count of general registers used (or 0) - public bool m_isSinglePrecision; // ARM64 - For determining if HFA is single or double precision public bool m_fRequires64BitAlignment; // ARM - True if the argument should always be aligned (in registers or on the stack public int m_idxStack; // First stack slot used (or -1) @@ -251,7 +243,6 @@ public void Init() m_idxStack = -1; m_cStack = 0; - m_isSinglePrecision = false; m_fRequires64BitAlignment = false; } }; @@ -286,8 +277,8 @@ public void GcMark(CORCOMPILE_GCREFMAP_TOKENS[] frame, int delta, bool interior) frame[_offset + delta] = interior ? CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_INTERIOR : CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_REF; } - // Returns true if the ArgDestination represents an HFA struct - bool IsHFA() + // Returns true if the ArgDestination represents a homogeneous aggregate struct + bool IsHomogeneousAggregate() { return _argLocDescForStructInRegs.HasValue; } @@ -615,18 +606,17 @@ public bool IsArgPassedByRef() { switch (_transitionBlock.Architecture) { - case TargetArchitecture.X64: return _transitionBlock.IsArgPassedByRef(_argSize); case TargetArchitecture.ARM64: if (_argType == CorElementType.ELEMENT_TYPE_VALUETYPE) { Debug.Assert(!_argTypeHandle.IsNull()); - return ((_argSize > _transitionBlock.EnregisteredParamTypeMaxSize) && (!_argTypeHandle.IsHFA() || IsVarArg)); + return ((_argSize > _transitionBlock.EnregisteredParamTypeMaxSize) && (!_argTypeHandle.IsHomogeneousAggregate() || IsVarArg)); } return false; default: - throw new NotImplementedException(_transitionBlock.Architecture.ToString()); + throw new NotImplementedException(); } } else @@ -830,7 +820,7 @@ public int GetNextOffset() break; default: - throw new NotImplementedException(_transitionBlock.Architecture.ToString()); + throw new NotImplementedException(); } _argNum = (_skipFirstArg ? 1 : 0); @@ -849,21 +839,6 @@ public int GetNextOffset() int argSize = TypeHandle.GetElemSize(argType, _argTypeHandle); - bool processingFloatsAsDoublesFromTransitionBlock = false; - if (_transitionBlock.IsARM64) - { - // NOT DESKTOP BEHAVIOR: The S and D registers overlap, and the UniversalTransitionThunk copies D registers to the transition blocks. We'll need - // to work with the D registers here as well. - if (argType == CorElementType.ELEMENT_TYPE_VALUETYPE && _argTypeHandle.IsHFA() && _argTypeHandle.GetHFAType() == CorElementType.ELEMENT_TYPE_R4) - { - if ((argSize / sizeof(float)) + _arm64IdxFPReg <= 8) - { - argSize *= 2; - processingFloatsAsDoublesFromTransitionBlock = true; - } - } - } - _argType = argType; _argSize = argSize; @@ -1069,7 +1044,7 @@ public int GetNextOffset() // Handle HFAs: packed structures of 1-4 floats or doubles that are passed in FP argument // registers if possible. - if (_argTypeHandle.IsHFA()) + if (_argTypeHandle.IsHomogeneousAggregate()) fFloatingPoint = true; break; @@ -1215,19 +1190,26 @@ public int GetNextOffset() case CorElementType.ELEMENT_TYPE_VALUETYPE: { - // Handle HFAs: packed structures of 2-4 floats or doubles that are passed in FP argument - // registers if possible. - if (_argTypeHandle.IsHFA()) + // Handle HAs: packed structures of 1-4 floats, doubles, or short vectors + // that are passed in FP argument registers if possible. + if (_argTypeHandle.IsHomogeneousAggregate()) { - CorElementType type = _argTypeHandle.GetHFAType(); - if (processingFloatsAsDoublesFromTransitionBlock) - cFPRegs = argSize / sizeof(double); - else - cFPRegs = (type == CorElementType.ELEMENT_TYPE_R4) ? (argSize / sizeof(float)) : (argSize / sizeof(double)); + _argLocDescForStructInRegs = new ArgLocDesc(); + _argLocDescForStructInRegs.m_idxFloatReg = _arm64IdxFPReg; + + int haElementSize = _argTypeHandle.GetHomogeneousAggregateElementSize(); + cFPRegs = argSize / haElementSize; + _argLocDescForStructInRegs.m_cFloatReg = cFPRegs; + + // Check if we have enough registers available for the HA passing + if (cFPRegs + _arm64IdxFPReg <= 8) + { + _hasArgLocDescForStructInRegs = true; + } } else { - // Composite greater than 16bytes should be passed by reference + // Composite greater than 16 bytes should be passed by reference if (argSize > _transitionBlock.EnregisteredParamTypeMaxSize) { argSize = _transitionBlock.PointerSize; @@ -1248,7 +1230,8 @@ public int GetNextOffset() { if (cFPRegs + _arm64IdxFPReg <= 8) { - int argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _arm64IdxFPReg * 8; + // Each floating point register in the argument area is 16 bytes. + int argOfsInner = _transitionBlock.OffsetOfFloatArgumentRegisters + _arm64IdxFPReg * 16; _arm64IdxFPReg += cFPRegs; return argOfsInner; } @@ -1259,14 +1242,33 @@ public int GetNextOffset() } else { + // Only x0-x7 are valid argument registers (x8 is always the return buffer) if (_arm64IdxGenReg + cArgSlots <= 8) { + // The entirety of the arg fits in the register slots. int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _arm64IdxGenReg * 8; _arm64IdxGenReg += cArgSlots; return argOfsInner; } + else if (_context.Target.IsWindows && IsVarArg && (_arm64IdxGenReg < 8)) + { + // Address the Windows ARM64 varargs case where an arg is split between regs and stack. + // This can happen in the varargs case because the first 64 bytes of the stack are loaded + // into x0-x7, and any remaining stack arguments are placed normally. + int argOfsInner = _transitionBlock.OffsetOfArgumentRegisters + _arm64IdxGenReg * 8; + + // Increase m_idxStack to account for the space used for the remainder of the arg after + // register slots are filled. + _arm64IdxStack += (_arm64IdxGenReg + cArgSlots - 8); + + // We used up the remaining reg slots. + _arm64IdxGenReg = 8; + + return argOfsInner; + } else { + // Don't use reg slots for this. It will be passed purely on the stack arg space. _arm64IdxGenReg = 8; } } @@ -1277,7 +1279,7 @@ public int GetNextOffset() } default: - throw new NotImplementedException(_transitionBlock.Architecture.ToString()); + throw new NotImplementedException(); } } @@ -1513,17 +1515,13 @@ private void ForceSigWalk() if (_transitionBlock.IsFloatArgumentRegisterOffset(argOffset)) { - // Dividing by 8 as size of each register in FloatArgumentRegisters is 8 bytes. - pLoc.m_idxFloatReg = (argOffset - _transitionBlock.OffsetOfFloatArgumentRegisters) / 8; + // Dividing by 16 as size of each register in FloatArgumentRegisters is 16 bytes. + pLoc.m_idxFloatReg = (argOffset - _transitionBlock.OffsetOfFloatArgumentRegisters) / 16; - if (!_argTypeHandle.IsNull() && _argTypeHandle.IsHFA()) + if (!_argTypeHandle.IsNull() && _argTypeHandle.IsHomogeneousAggregate()) { - CorElementType type = _argTypeHandle.GetHFAType(); - bool isFloatType = (type == CorElementType.ELEMENT_TYPE_R4); - - // DESKTOP BEHAVIOR pLoc->m_cFloatReg = isFloatType ? GetArgSize() / sizeof(float) : GetArgSize() / sizeof(double); - pLoc.m_cFloatReg = GetArgSize() / sizeof(double); - pLoc.m_isSinglePrecision = isFloatType; + int haElementSize = _argTypeHandle.GetHomogeneousAggregateElementSize(); + pLoc.m_cFloatReg = GetArgSize() / haElementSize; } else { @@ -1605,7 +1603,7 @@ private void ForceSigWalk() return null; default: - throw new NotImplementedException(_transitionBlock.Architecture.ToString()); + throw new NotImplementedException(); } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedCorHeaderNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedCorHeaderNode.cs index 5e7a96afa4c716..87772fa7079f76 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedCorHeaderNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedCorHeaderNode.cs @@ -51,7 +51,10 @@ private static DirectoryEntry ReadDirectoryEntry(ref BlobReader reader) public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix); - sb.Append($"__CorHeader_{_module.Assembly.GetName().Name}"); + if (_module != null) + sb.Append($"__CorHeader_{_module.Assembly.GetName().Name}"); + else + sb.Append("__CompositeCorHeader_"); } protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); @@ -62,75 +65,116 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) builder.RequireInitialPointerAlignment(); builder.AddSymbol(this); - BlobReader reader = _module.PEReader.GetEntireImage().GetReader(); - reader.Offset = _module.PEReader.PEHeaders.CorHeaderStartOffset; - - // Header Size - int headerSize = reader.ReadInt32(); - builder.EmitInt(headerSize); - - // Runtime major, minor version - builder.EmitUShort(reader.ReadUInt16()); - builder.EmitUShort(reader.ReadUInt16()); + if (_module != null) + { + BlobReader reader = _module.PEReader.GetEntireImage().GetReader(); + reader.Offset = _module.PEReader.PEHeaders.CorHeaderStartOffset; + + // Header Size + int headerSize = reader.ReadInt32(); + builder.EmitInt(headerSize); + + // Runtime major, minor version + builder.EmitUShort(reader.ReadUInt16()); + builder.EmitUShort(reader.ReadUInt16()); + + // Metadata Directory + ReadDirectoryEntry(ref reader); + var metadataBlob = factory.CopiedMetadataBlob(_module); + builder.EmitReloc(metadataBlob, RelocType.IMAGE_REL_BASED_ADDR32NB); + builder.EmitInt(metadataBlob.Size); + + // Flags + builder.EmitUInt((uint)(((CorFlags)reader.ReadUInt32() & ~CorFlags.ILOnly) | CorFlags.ILLibrary)); + + // Entrypoint + builder.EmitInt(reader.ReadInt32()); + + // Resources Directory + if (ReadDirectoryEntry(ref reader).Size > 0) + { + var managedResources = factory.CopiedManagedResources(_module); + builder.EmitReloc(managedResources, RelocType.IMAGE_REL_BASED_ADDR32NB); + builder.EmitInt(managedResources.Size); + } + else + { + WriteEmptyDirectoryEntry(ref builder); + } + + // Strong Name Signature Directory + if (ReadDirectoryEntry(ref reader).Size > 0) + { + var strongNameSignature = factory.CopiedStrongNameSignature(_module); + builder.EmitReloc(strongNameSignature, RelocType.IMAGE_REL_BASED_ADDR32NB); + builder.EmitInt(strongNameSignature.Size); + } + else + { + WriteEmptyDirectoryEntry(ref builder); + } + + // Code Manager Table Directory + ReadDirectoryEntry(ref reader); + WriteEmptyDirectoryEntry(ref builder); - // Metadata Directory - ReadDirectoryEntry(ref reader); - var metadataBlob = factory.CopiedMetadataBlob(_module); - builder.EmitReloc(metadataBlob, RelocType.IMAGE_REL_BASED_ADDR32NB); - builder.EmitInt(metadataBlob.Size); + // VTable Fixups Directory + ReadDirectoryEntry(ref reader); + WriteEmptyDirectoryEntry(ref builder); - // Flags - builder.EmitUInt((uint)(((CorFlags)reader.ReadUInt32() & ~CorFlags.ILOnly) | CorFlags.ILLibrary)); + // Export Address Table Jumps Directory + ReadDirectoryEntry(ref reader); + WriteEmptyDirectoryEntry(ref builder); - // Entrypoint - builder.EmitInt(reader.ReadInt32()); + // Managed Native (ReadyToRun) Header Directory + ReadDirectoryEntry(ref reader); + builder.EmitReloc(factory.Header, RelocType.IMAGE_REL_BASED_ADDR32NB); + builder.EmitReloc(factory.Header, RelocType.IMAGE_REL_SYMBOL_SIZE); - // Resources Directory - if (ReadDirectoryEntry(ref reader).Size > 0) - { - var managedResources = factory.CopiedManagedResources(_module); - builder.EmitReloc(managedResources, RelocType.IMAGE_REL_BASED_ADDR32NB); - builder.EmitInt(managedResources.Size); + // Did we fully read the header? + Debug.Assert(reader.Offset - headerSize == _module.PEReader.PEHeaders.CorHeaderStartOffset); + Debug.Assert(builder.CountBytes == headerSize); + Debug.Assert(headerSize == Size); } else { - WriteEmptyDirectoryEntry(ref builder); - } + // Generating CORHeader for composite image + // Header Size + builder.EmitInt(Size); - // Strong Name Signature Directory - if (ReadDirectoryEntry(ref reader).Size > 0) - { - var strongNameSignature = factory.CopiedStrongNameSignature(_module); - builder.EmitReloc(strongNameSignature, RelocType.IMAGE_REL_BASED_ADDR32NB); - builder.EmitInt(strongNameSignature.Size); - } - else - { + // Runtime major, minor version + builder.EmitUShort(0); + builder.EmitUShort(0); + + // Metadata Directory + builder.EmitReloc(factory.ManifestMetadataTable, RelocType.IMAGE_REL_BASED_ADDR32NB); + builder.EmitReloc(factory.ManifestMetadataTable, RelocType.IMAGE_REL_SYMBOL_SIZE); + + // Flags + builder.EmitUInt(0); + + // Entrypoint + builder.EmitInt(0); + + // Resources Directory WriteEmptyDirectoryEntry(ref builder); - } - - // Code Manager Table Directory - ReadDirectoryEntry(ref reader); - WriteEmptyDirectoryEntry(ref builder); + // Strong Name Signature Directory + WriteEmptyDirectoryEntry(ref builder); - // VTable Fixups Directory - ReadDirectoryEntry(ref reader); - WriteEmptyDirectoryEntry(ref builder); + // Code Manager Table Directory + WriteEmptyDirectoryEntry(ref builder); - // Export Address Table Jumps Directory - ReadDirectoryEntry(ref reader); - WriteEmptyDirectoryEntry(ref builder); + // VTable Fixups Directory + WriteEmptyDirectoryEntry(ref builder); - // Managed Native (ReadyToRun) Header Directory - ReadDirectoryEntry(ref reader); - builder.EmitReloc(factory.Header, RelocType.IMAGE_REL_BASED_ADDR32NB); - builder.EmitReloc(factory.Header, RelocType.IMAGE_REL_SYMBOL_SIZE); + // Export Address Table Jumps Directory + WriteEmptyDirectoryEntry(ref builder); - // Did we fully read the header? - Debug.Assert(reader.Offset - headerSize == _module.PEReader.PEHeaders.CorHeaderStartOffset); - Debug.Assert(builder.CountBytes == headerSize); - Debug.Assert(headerSize == Size); + // Managed Native (ReadyToRun) Header Directory + builder.EmitReloc(factory.Header, RelocType.IMAGE_REL_BASED_ADDR32NB); + builder.EmitReloc(factory.Header, RelocType.IMAGE_REL_SYMBOL_SIZE); + } return builder.ToObjectData(); } @@ -143,6 +187,17 @@ private void WriteEmptyDirectoryEntry(ref ObjectDataBuilder builder) public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { + if (_module == null) + { + if (((CopiedCorHeaderNode)other)._module == null) + return 0; + return -1; + } + else if (((CopiedCorHeaderNode)other)._module == null) + { + return 1; + } + return _module.CompareTo(((CopiedCorHeaderNode)other)._module); } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedFieldRvaNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedFieldRvaNode.cs index ca3ca21435d0e3..7c5240fbd33cb0 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedFieldRvaNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedFieldRvaNode.cs @@ -60,11 +60,20 @@ private unsafe byte[] GetRvaData(int targetPointerSize) MetadataReader metadataReader = _module.MetadataReader; BlobReader metadataBlob = new BlobReader(_module.PEReader.GetMetadata().Pointer, _module.PEReader.GetMetadata().Length); metadataBlob.Offset = metadataReader.GetTableMetadataOffset(TableIndex.FieldRva); - + bool compressedFieldRef = 6 == metadataReader.GetTableRowSize(TableIndex.FieldRva); + for (int i = 1; i <= metadataReader.GetTableRowCount(TableIndex.FieldRva); i++) { int currentFieldRva = metadataBlob.ReadInt32(); - short currentFieldRid = metadataBlob.ReadInt16(); + int currentFieldRid; + if (compressedFieldRef) + { + currentFieldRid = metadataBlob.ReadInt16(); + } + else + { + currentFieldRid = metadataBlob.ReadInt32(); + } if (currentFieldRva != _rva) continue; diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedMetadataBlobNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedMetadataBlobNode.cs index 4160a9e5e3f3cb..aedf3037cd09a0 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedMetadataBlobNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedMetadataBlobNode.cs @@ -73,7 +73,8 @@ private void WriteFieldRvas(NodeFactory factory, ref ObjectDataBuilder builder, MetadataReader metadataReader = _sourceModule.MetadataReader; var tableIndex = TableIndex.FieldRva; int rowCount = metadataReader.GetTableRowCount(tableIndex); - + bool compressedFieldRef = 6 == metadataReader.GetTableRowSize(TableIndex.FieldRva); + for (int i = 1; i <= rowCount; i++) { Debug.Assert(builder.CountBytes == reader.Offset); @@ -81,13 +82,28 @@ private void WriteFieldRvas(NodeFactory factory, ref ObjectDataBuilder builder, // Rva reader.ReadInt32(); - short fieldToken = reader.ReadInt16(); + int fieldToken; + if (compressedFieldRef) + { + fieldToken = reader.ReadInt16(); + } + else + { + fieldToken = reader.ReadInt32(); + } EntityHandle fieldHandle = MetadataTokens.EntityHandle(TableIndex.Field, fieldToken); EcmaField fieldDesc = (EcmaField)_sourceModule.GetField(fieldHandle); Debug.Assert(fieldDesc.HasRva); builder.EmitReloc(factory.CopiedFieldRva(fieldDesc), RelocType.IMAGE_REL_BASED_ADDR32NB); - builder.EmitShort(fieldToken); + if (compressedFieldRef) + { + builder.EmitUShort((ushort)fieldToken); + } + else + { + builder.EmitUInt((uint)fieldToken); + } } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugDirectoryEntryNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugDirectoryEntryNode.cs index e88b2805d73694..6a691d831c1992 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugDirectoryEntryNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugDirectoryEntryNode.cs @@ -56,14 +56,18 @@ public class NativeDebugDirectoryEntryNode : DebugDirectoryEntryNode public unsafe int Size => RSDSSize; - public NativeDebugDirectoryEntryNode(EcmaModule sourceModule) - : base(sourceModule) - { } + public NativeDebugDirectoryEntryNode(string pdbName) + : base(null) + { + _pdbName = pdbName; + } + + private string _pdbName; public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix); - sb.Append($"__NativeRvaBlob_{_module.Assembly.GetName().Name}"); + sb.Append($"__NativeDebugDirectory_{_pdbName.Replace('.','_')}"); } public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) @@ -99,7 +103,7 @@ public byte[] GenerateRSDSEntryData(byte[] md5Hash) // Age writer.Write(1); - string pdbFileName = _module.Assembly.GetName().Name + ".ni.pdb"; + string pdbFileName = _pdbName; byte[] pdbFileNameBytes = Encoding.UTF8.GetBytes(pdbFileName); writer.Write(pdbFileNameBytes); @@ -107,6 +111,11 @@ public byte[] GenerateRSDSEntryData(byte[] md5Hash) return rsdsEntry.ToArray(); } } + + public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) + { + return _pdbName.CompareTo(((NativeDebugDirectoryEntryNode)other)._pdbName); + } } public class CopiedDebugDirectoryEntryNode : DebugDirectoryEntryNode diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugDirectoryNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugDirectoryNode.cs index 52e49afe79828f..5c1bd729b64ccc 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugDirectoryNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugDirectoryNode.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Immutable; using System.Diagnostics; +using System.IO; using System.Reflection.PortableExecutable; using Internal.Text; using Internal.TypeSystem.Ecma; @@ -25,10 +26,17 @@ public class DebugDirectoryNode : ObjectNode, ISymbolDefinitionNode sizeof(int); // PointerToRawData private EcmaModule _module; + private NativeDebugDirectoryEntryNode _nativeEntry; - public DebugDirectoryNode(EcmaModule sourceModule) + public DebugDirectoryNode(EcmaModule sourceModule, string outputFileName) { _module = sourceModule; + string pdbNameRoot = Path.GetFileNameWithoutExtension(outputFileName); + if (sourceModule != null) + { + pdbNameRoot = sourceModule.Assembly.GetName().Name; + } + _nativeEntry = new NativeDebugDirectoryEntryNode(pdbNameRoot + ".ni.pdb"); } public override ObjectNodeSection Section => ObjectNodeSection.TextSection; @@ -48,13 +56,22 @@ public DebugDirectoryNode(EcmaModule sourceModule) public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix); - sb.Append($"__DebugDirectory_{_module.Assembly.GetName().Name}"); + string directoryName; + if (_module != null) + directoryName = _module.Assembly.GetName().Name; + else + directoryName = "Composite"; + + sb.Append($"__DebugDirectory_{directoryName}"); } protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler); int GetNumDebugDirectoryEntriesInModule() { + if (_module == null) + return 0; + ImmutableArray entries = _module.PEReader.ReadDebugDirectory(); return entries == null ? 0 : entries.Length; } @@ -65,12 +82,15 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) builder.RequireInitialPointerAlignment(); builder.AddSymbol(this); - ImmutableArray entries = _module.PEReader.ReadDebugDirectory(); + ImmutableArray entries = default(ImmutableArray); + if (_module != null) + entries = _module.PEReader.ReadDebugDirectory(); + int numEntries = GetNumDebugDirectoryEntriesInModule(); // First, write the native debug directory entry { - var entry = (NativeDebugDirectoryEntryNode)factory.DebugDirectoryEntry(_module, -1); + var entry = _nativeEntry; builder.EmitUInt(0 /* Characteristics */); if (numEntries > 0) @@ -121,6 +141,17 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { + if (_module == null) + { + if (((DebugDirectoryNode)other)._module == null) + return 0; + return -1; + } + else if (((DebugDirectoryNode)other)._module == null) + { + return 1; + } + return _module.CompareTo(((DebugDirectoryNode)other)._module); } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugInfoTableNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugInfoTableNode.cs index 68f04436441446..31540b3d302ae1 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugInfoTableNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DebugInfoTableNode.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.IO; using Internal.JitInterface; @@ -81,12 +82,14 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) VertexArray vertexArray = new VertexArray(section); section.Place(vertexArray); + Dictionary blobCache = new Dictionary(ByteArrayComparer.Instance); + foreach (MethodWithGCInfo method in factory.EnumerateCompiledMethods()) { MemoryStream methodDebugBlob = new MemoryStream(); - byte[] bounds = CreateBoundsBlobForMethod(method); - byte[] vars = CreateVarBlobForMethod(method); + byte[] bounds = method.DebugLocInfos; + byte[] vars = method.DebugVarInfos; NibbleWriter nibbleWriter = new NibbleWriter(); nibbleWriter.WriteUInt((uint)(bounds?.Length ?? 0)); @@ -105,8 +108,12 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) methodDebugBlob.Write(vars, 0, vars.Length); } - BlobVertex debugBlob = new BlobVertex(methodDebugBlob.ToArray()); - + byte[] debugBlobArrayKey = methodDebugBlob.ToArray(); + if (!blobCache.TryGetValue(debugBlobArrayKey, out BlobVertex debugBlob)) + { + debugBlob = new BlobVertex(methodDebugBlob.ToArray()); + blobCache.Add(debugBlobArrayKey, debugBlob); + } vertexArray.Set(factory.RuntimeFunctionsTable.GetIndex(method), new DebugInfoVertex(debugBlob)); } @@ -122,16 +129,16 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) definedSymbols: new ISymbolDefinitionNode[] { this }); } - private byte[] CreateBoundsBlobForMethod(MethodWithGCInfo method) + public static byte[] CreateBoundsBlobForMethod(OffsetMapping[] offsetMapping) { - if (method.DebugLocInfos == null || method.DebugLocInfos.Length == 0) + if (offsetMapping == null || offsetMapping.Length == 0) return null; NibbleWriter writer = new NibbleWriter(); - writer.WriteUInt((uint)method.DebugLocInfos.Length); + writer.WriteUInt((uint)offsetMapping.Length); uint previousNativeOffset = 0; - foreach (var locInfo in method.DebugLocInfos) + foreach (var locInfo in offsetMapping) { writer.WriteUInt(locInfo.nativeOffset - previousNativeOffset); writer.WriteUInt(locInfo.ilOffset + 3); // Count of items in Internal.JitInterface.MappingTypes to adjust the IL offset by @@ -143,15 +150,15 @@ private byte[] CreateBoundsBlobForMethod(MethodWithGCInfo method) return writer.ToArray(); } - private byte[] CreateVarBlobForMethod(MethodWithGCInfo method) + public static byte[] CreateVarBlobForMethod(NativeVarInfo[] varInfos) { - if (method.DebugVarInfos == null || method.DebugVarInfos.Length == 0) + if (varInfos == null || varInfos.Length == 0) return null; NibbleWriter writer = new NibbleWriter(); - writer.WriteUInt((uint)method.DebugVarInfos.Length); + writer.WriteUInt((uint)varInfos.Length); - foreach (var nativeVarInfo in method.DebugVarInfos) + foreach (var nativeVarInfo in varInfos) { writer.WriteUInt(nativeVarInfo.startOffset); writer.WriteUInt(nativeVarInfo.endOffset - nativeVarInfo.startOffset); diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperImport.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperImport.cs index df834649fdc5fd..d8f6c8f8d2c30e 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperImport.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperImport.cs @@ -27,8 +27,8 @@ public DelayLoadHelperImport( ReadyToRunHelper helper, Signature instanceSignature, bool useVirtualCall = false, - string callSite = null) - : base(importSectionNode, instanceSignature, callSite) + MethodDesc callingMethod = null) + : base(importSectionNode, instanceSignature, callingMethod) { _helper = helper; _useVirtualCall = useVirtualCall; @@ -45,10 +45,10 @@ public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilde sb.Append(_helper.ToString()); sb.Append(") -> "); ImportSignature.AppendMangledName(nameMangler, sb); - if (CallSite != null) + if (CallingMethod != null) { sb.Append(" @ "); - sb.Append(CallSite); + sb.Append(nameMangler.GetMangledMethodName(CallingMethod)); } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs index dbf106844ed7d3..656a68f40c8410 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/DelayLoadHelperMethodImport.cs @@ -30,8 +30,8 @@ public DelayLoadHelperMethodImport( bool useVirtualCall, bool useInstantiatingStub, Signature instanceSignature, - string callSite = null) - : base(factory, importSectionNode, helper, instanceSignature, useVirtualCall, callSite) + MethodDesc callingMethod = null) + : base(factory, importSectionNode, helper, instanceSignature, useVirtualCall, callingMethod) { _method = method; _useInstantiatingStub = useInstantiatingStub; @@ -47,12 +47,11 @@ public override IEnumerable GetStaticDependencies(NodeFacto { // Require compilation of the canonical version for instantiating stubs MethodDesc canonMethod = _method.Method.GetCanonMethodTarget(CanonicalFormKind.Specific); - ISymbolNode canonMethodNode = factory.MethodEntrypoint( - new MethodWithToken(canonMethod, _method.Token, constrainedType: null), - isUnboxingStub: false, - isInstantiatingStub: false, - isPrecodeImportRequired: false); - yield return new DependencyListEntry(canonMethodNode, "Canonical method for instantiating stub"); + if (factory.CompilationModuleGroup.ContainsMethodBody(canonMethod, false)) + { + ISymbolNode canonMethodNode = factory.CompiledMethodNode(canonMethod); + yield return new DependencyListEntry(canonMethodNode, "Canonical method for instantiating stub"); + } } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapBuilder.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapBuilder.cs index 5f2767c51a63b5..cfe405663be222 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapBuilder.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapBuilder.cs @@ -120,20 +120,8 @@ public void GetCallRefMap(MethodDesc method, bool isUnboxingStub) for (uint pos = 0; pos < nStackSlots; pos++) { - int ofs; - - if (_target.Architecture == TargetArchitecture.X86) - { - ofs = (int)(pos < _transitionBlock.NumArgumentRegisters ? - _transitionBlock.OffsetOfArgumentRegisters + _transitionBlock.SizeOfArgumentRegisters - (pos + 1) * _target.PointerSize : - _transitionBlock.OffsetOfArgs + (pos - _transitionBlock.NumArgumentRegisters) * _target.PointerSize); - } - else - { - ofs = (int)(_transitionBlock.OffsetOfFirstGCRefMapSlot + pos * _target.PointerSize); - } - - CORCOMPILE_GCREFMAP_TOKENS token = fakeStack[ofs]; + int offset = _transitionBlock.OffsetFromGCRefMapPos(checked((int)pos)); + CORCOMPILE_GCREFMAP_TOKENS token = fakeStack[offset]; if (token != CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_SKIP) { diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapNode.cs index 1a7c9ccbb3d8ee..8488c2765f14e7 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapNode.cs @@ -60,7 +60,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) definedSymbols: new ISymbolDefinitionNode[] { this }); } - _methods.Sort(new CompilerComparer()); + _methods.MergeSort(new CompilerComparer()); GCRefMapBuilder builder = new GCRefMapBuilder(factory.Target, relocsOnly); builder.Builder.RequireInitialAlignment(4); builder.Builder.AddSymbol(this); diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/HeaderNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/HeaderNode.cs index f157900c9665f9..4f70333c0a4fde 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/HeaderNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/HeaderNode.cs @@ -105,7 +105,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) // Don't bother sorting if we're not emitting the contents if (!relocsOnly) - _items.Sort((x, y) => Comparer.Default.Compare((int)x.Id, (int)y.Id)); + _items.MergeSort((x, y) => Comparer.Default.Compare((int)x.Id, (int)y.Id)); // ReadyToRunHeader.Flags builder.EmitInt((int)_flags); diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/IReadyToRunMethodCodeNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/IReadyToRunMethodCodeNode.cs deleted file mode 100644 index 2241f09659447b..00000000000000 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/IReadyToRunMethodCodeNode.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Internal.JitInterface; -using Internal.TypeSystem; - -namespace ILCompiler.DependencyAnalysis -{ - public interface IReadyToRunMethodCodeNode : IMethodNode, ISymbolDefinitionNode - { - void SetCode(ObjectNode.ObjectData data); - void InitializeFrameInfos(FrameInfo[] frameInfos); - void InitializeGCInfo(byte[] gcInfo); - void InitializeEHInfo(ObjectNode.ObjectData ehInfo); - void InitializeDebugLocInfos(OffsetMapping[] debugLocInfos); - void InitializeDebugVarInfos(NativeVarInfo[] debugVarInfos); - void InitializeDebugEHClauseInfos(DebugEHClauseInfo[] debugEHClauseInfos); - void InitializeInliningInfo(MethodDesc[] inlinedMethods); - } -} diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/Import.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/Import.cs index e276c75fa77185..ebd73a82552bd0 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/Import.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/Import.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using Internal.Text; +using Internal.TypeSystem; namespace ILCompiler.DependencyAnalysis.ReadyToRun { @@ -17,12 +18,12 @@ public class Import : EmbeddedObjectNode, ISymbolDefinitionNode, ISortableSymbol internal readonly SignatureEmbeddedPointerIndirectionNode ImportSignature; - internal readonly string CallSite; + internal readonly MethodDesc CallingMethod; - public Import(ImportSectionNode tableNode, Signature importSignature, string callSite = null) + public Import(ImportSectionNode tableNode, Signature importSignature, MethodDesc callingMethod = null) { Table = tableNode; - CallSite = callSite; + CallingMethod = callingMethod; ImportSignature = new SignatureEmbeddedPointerIndirectionNode(this, importSignature); } @@ -66,7 +67,7 @@ public override IEnumerable GetStaticDependencies(NodeFacto public override int CompareToImpl(ISortableNode other, CompilerComparer comparer) { Import otherNode = (Import)other; - int result = string.Compare(CallSite, otherNode.CallSite); + int result = comparer.Compare(CallingMethod, otherNode.CallingMethod); if (result != 0) return result; diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InliningInfoNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InliningInfoNode.cs index f22b5af57d9095..94718e3b965e76 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InliningInfoNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InliningInfoNode.cs @@ -112,7 +112,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) } List sortedInliners = new List(inlineeWithInliners.Value); - sortedInliners.Sort((a, b) => + sortedInliners.MergeSort((a, b) => { if (a == b) return 0; diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs index b82737e07152e2..7c7911a14cfbd6 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs @@ -12,7 +12,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun { - public class MethodWithGCInfo : ObjectNode, IReadyToRunMethodCodeNode, IMethodBodyNode + public class MethodWithGCInfo : ObjectNode, IMethodBodyNode, ISymbolDefinitionNode { public readonly MethodGCInfoNode GCInfoNode; @@ -22,8 +22,8 @@ public class MethodWithGCInfo : ObjectNode, IReadyToRunMethodCodeNode, IMethodBo private FrameInfo[] _frameInfos; private byte[] _gcInfo; private ObjectData _ehInfo; - private OffsetMapping[] _debugLocInfos; - private NativeVarInfo[] _debugVarInfos; + private byte[] _debugLocInfos; + private byte[] _debugVarInfos; private DebugEHClauseInfo[] _debugEHClauseInfos; private List _fixups; private MethodDesc[] _inlinedMethods; @@ -124,7 +124,7 @@ public byte[] GetFixupBlob(NodeFactory factory) return null; } - fixupCells.Sort(FixupCell.Comparer); + fixupCells.MergeSortAllowDuplicates(FixupCell.Comparer); // Deduplicate fixupCells int j = 0; @@ -268,20 +268,24 @@ public void InitializeEHInfo(ObjectData ehInfo) _ehInfo = ehInfo; } - public OffsetMapping[] DebugLocInfos => _debugLocInfos; - public NativeVarInfo[] DebugVarInfos => _debugVarInfos; + public byte[] DebugLocInfos => _debugLocInfos; + public byte[] DebugVarInfos => _debugVarInfos; public DebugEHClauseInfo[] DebugEHClauseInfos => _debugEHClauseInfos; public void InitializeDebugLocInfos(OffsetMapping[] debugLocInfos) { Debug.Assert(_debugLocInfos == null); - _debugLocInfos = debugLocInfos; + // Process the debug info from JIT format to R2R format immediately as it is large + // and not used in the rest of the process except to emit. + _debugLocInfos = DebugInfoTableNode.CreateBoundsBlobForMethod(debugLocInfos); } public void InitializeDebugVarInfos(NativeVarInfo[] debugVarInfos) { Debug.Assert(_debugVarInfos == null); - _debugVarInfos = debugVarInfos; + // Process the debug info from JIT format to R2R format immediately as it is large + // and not used in the rest of the process except to emit. + _debugVarInfos = DebugInfoTableNode.CreateVarBlobForMethod(debugVarInfos); } public void InitializeDebugEHClauseInfos(DebugEHClauseInfo[] debugEHClauseInfos) @@ -303,5 +307,6 @@ public void InitializeInliningInfo(MethodDesc[] inlinedMethods) public int Offset => 0; public override bool IsShareable => throw new NotImplementedException(); + public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => IsEmpty; } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureEmbeddedPointerIndirectionNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureEmbeddedPointerIndirectionNode.cs index eec93744449fb9..c07b78b10e2fe9 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureEmbeddedPointerIndirectionNode.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/SignatureEmbeddedPointerIndirectionNode.cs @@ -38,10 +38,10 @@ public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilde { sb.Append("SignaturePointer_"); Target.AppendMangledName(nameMangler, sb); - if (_import.CallSite != null) + if (_import.CallingMethod != null) { sb.Append(" @ "); - sb.Append(_import.CallSite); + sb.Append(nameMangler.GetMangledMethodName(_import.CallingMethod)); } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs index 70f7c4a908e3b5..bc8c9d17bacb11 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TransitionBlock.cs @@ -77,7 +77,7 @@ public static TransitionBlock FromTarget(TargetDetails target) public abstract int OffsetOfArgumentRegisters { get; } /// - /// Only overridden on ARM64 to return offset of the X8 register. + /// The offset of the first slot in a GC ref map. Overridden on ARM64 to return the offset of the X8 register. /// public virtual int OffsetOfFirstGCRefMapSlot => OffsetOfArgumentRegisters; @@ -105,11 +105,9 @@ public static TransitionBlock FromTarget(TargetDetails target) /// Recalculate pos in GC ref map to actual offset. This is the default implementation for all architectures /// except for X86 where it's overridden to supply a more complex algorithm. /// - /// - /// public virtual int OffsetFromGCRefMapPos(int pos) { - return OffsetOfArgumentRegisters + pos * PointerSize; + return OffsetOfFirstGCRefMapSlot + pos * PointerSize; } /// @@ -277,12 +275,15 @@ public void ComputeReturnValueTreatment(CorElementType type, TypeHandle thRetTyp { if (descriptor.eightByteClassifications0 == SystemVClassificationType.SystemVClassificationTypeSSE) { + // Structs occupying just one eightbyte are treated as int / double fpReturnSize = sizeof(double); } } else { + // Size of the struct is 16 bytes fpReturnSize = 16; + // The lowest two bits of the size encode the order of the int and SSE fields if (descriptor.eightByteClassifications0 == SystemVClassificationType.SystemVClassificationTypeSSE) { fpReturnSize += 1; @@ -299,28 +300,10 @@ public void ComputeReturnValueTreatment(CorElementType type, TypeHandle thRetTyp } else { - if (thRetType.IsHFA() && !isVarArgMethod) + if (thRetType.IsHomogeneousAggregate() && !isVarArgMethod) { - CorElementType hfaType = thRetType.GetHFAType(); - - switch (Architecture) - { - case TargetArchitecture.ARM: - fpReturnSize = (hfaType == CorElementType.ELEMENT_TYPE_R4) ? - (4 * (uint)sizeof(float)) : - (4 * (uint)sizeof(double)); - break; - - case TargetArchitecture.ARM64: - // DESKTOP BEHAVIOR fpReturnSize = (hfaType == CorElementType.ELEMENT_TYPE_R4) ? (4 * (uint)sizeof(float)) : (4 * (uint)sizeof(double)); - // S and D registers overlap. Since we copy D registers in the UniversalTransitionThunk, we'll - // treat floats like doubles during copying. - fpReturnSize = 4 * (uint)sizeof(double); - break; - - default: - throw new NotImplementedException(); - } + int haElementSize = thRetType.GetHomogeneousAggregateElementSize(); + fpReturnSize = 4 * (uint)haElementSize; break; } @@ -481,8 +464,6 @@ private sealed class Arm64TransitionBlock : TransitionBlock { public static TransitionBlock Instance = new Arm64TransitionBlock(); - private int OffsetOfX8Register => OffsetOfArgumentRegisters - PointerSize; - public override TargetArchitecture Architecture => TargetArchitecture.ARM64; public override int PointerSize => 8; // X0 .. X7 @@ -492,6 +473,7 @@ private sealed class Arm64TransitionBlock : TransitionBlock // Callee-saves, padding, m_x8RetBuffReg, argument registers public override int SizeOfTransitionBlock => SizeOfCalleeSavedRegisters + 2 * PointerSize + SizeOfArgumentRegisters; public override int OffsetOfArgumentRegisters => SizeOfCalleeSavedRegisters + 2 * PointerSize; + private int OffsetOfX8Register => OffsetOfArgumentRegisters - PointerSize; public override int OffsetOfFirstGCRefMapSlot => OffsetOfX8Register; // D0..D7 @@ -505,12 +487,12 @@ public override bool IsArgPassedByRef(TypeHandle th) Debug.Assert(th.IsValueType()); // Composites greater than 16 bytes are passed by reference - return (th.GetSize() > EnregisteredParamTypeMaxSize) && !th.IsHFA(); + return (th.GetSize() > EnregisteredParamTypeMaxSize) && !th.IsHomogeneousAggregate(); } public override int GetRetBuffArgOffset(bool hasThis) => OffsetOfX8Register; - public override bool IsRetBuffPassedAsFirstArg => true; + public override bool IsRetBuffPassedAsFirstArg => false; } - }; + } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs index 3ae821d2dbf77d..9a9184e085d191 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs @@ -3,11 +3,14 @@ // See the LICENSE file in the project root for more information. using System; +using System.Diagnostics; using Internal.Text; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using Internal.TypeSystem.Interop; using Internal.ReadyToRunConstants; +using Internal.CorConstants; namespace ILCompiler.DependencyAnalysis.ReadyToRun { @@ -39,11 +42,114 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) EcmaModule targetModule = factory.SignatureContext.GetTargetModule(_typeDesc); SignatureContext innerContext = dataBuilder.EmitFixup(factory, _fixupKind, targetModule, factory.SignatureContext); dataBuilder.EmitTypeSignature(_typeDesc, innerContext); + + if (_fixupKind == ReadyToRunFixupKind.Check_TypeLayout) + { + EncodeTypeLayout(dataBuilder, _typeDesc); + } } return dataBuilder.ToObjectData(); } + private static void EncodeTypeLayout(ObjectDataSignatureBuilder dataBuilder, TypeDesc type) + { + Debug.Assert(type.IsValueType); + MetadataType defType = (MetadataType)type; + + int pointerSize = type.Context.Target.PointerSize; + int size = defType.InstanceFieldSize.AsInt; + int alignment = GetClassAlignmentRequirement(defType); + ReadyToRunTypeLayoutFlags flags = ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment | ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout; + if (alignment == pointerSize) + { + flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment_Native; + } + + if (!defType.ContainsGCPointers) + { + flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout_Empty; + } + + if (defType.IsHomogeneousAggregate) + { + flags |= ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_HFA; + } + + dataBuilder.EmitUInt((uint)flags); + dataBuilder.EmitUInt((uint)size); + + if (defType.IsHomogeneousAggregate) + { + CorElementType elementType = (defType.ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) switch + { + ValueTypeShapeCharacteristics.Float32Aggregate => CorElementType.ELEMENT_TYPE_R4, + ValueTypeShapeCharacteristics.Float64Aggregate => CorElementType.ELEMENT_TYPE_R8, + ValueTypeShapeCharacteristics.Vector64Aggregate => CorElementType.ELEMENT_TYPE_R8, + // See MethodTable::GetHFAType + ValueTypeShapeCharacteristics.Vector128Aggregate => CorElementType.ELEMENT_TYPE_VALUETYPE, + _ => CorElementType.Invalid + }; + dataBuilder.EmitUInt((uint)elementType); + } + + if (alignment != pointerSize) + { + dataBuilder.EmitUInt((uint)alignment); + } + + if (defType.ContainsGCPointers) + { + // Encode the GC pointer map + GCPointerMap gcMap = GCPointerMap.FromInstanceLayout(defType); + + byte[] encodedGCRefMap = new byte[(size / pointerSize + 7) / 8]; + int bitIndex = 0; + foreach (bool bit in gcMap) + { + if (bit) + { + encodedGCRefMap[bitIndex / 8] |= (byte)(1 << (bitIndex & 7)); + } + + ++bitIndex; + } + + dataBuilder.EmitBytes(encodedGCRefMap); + } + } + + /// + /// Managed implementation of CEEInfo::getClassAlignmentRequirementStatic + /// + private static int GetClassAlignmentRequirement(MetadataType type) + { + int alignment = type.Context.Target.PointerSize; + + if (type.HasLayout()) + { + if (type.IsSequentialLayout || MarshalUtils.IsBlittableType(type)) + { + alignment = type.InstanceFieldAlignment.AsInt; + } + } + + if (type.Context.Target.Architecture == TargetArchitecture.ARM && + alignment < 8 && type.RequiresAlign8()) + { + // If the structure contains 64-bit primitive fields and the platform requires 8-byte alignment for + // such fields then make sure we return at least 8-byte alignment. Note that it's technically possible + // to create unmanaged APIs that take unaligned structures containing such fields and this + // unconditional alignment bump would cause us to get the calling convention wrong on platforms such + // as ARM. If we see such cases in the future we'd need to add another control (such as an alignment + // property for the StructLayout attribute or a marshaling directive attribute for p/invoke arguments) + // that allows more precise control. For now we'll go with the likely scenario. + alignment = 8; + } + + return alignment; + } + public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) { sb.Append(nameMangler.CompilationUnitPrefix); diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs index 9ddbe79cb3a783..eeb590bce993bd 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs @@ -67,22 +67,20 @@ public void SetMarkingComplete() _markingComplete = true; } - public IMethodNode MethodEntrypoint(MethodDesc method) + private NodeCache _localMethodCache; + + public MethodWithGCInfo CompiledMethodNode(MethodDesc method) { - EcmaModule module = ((EcmaMethod)method.GetTypicalMethodDefinition()).Module; - ModuleToken moduleToken = Resolver.GetModuleTokenForMethod(method, throwIfNotFound: true); - return MethodEntrypoint( - new MethodWithToken(method, moduleToken, constrainedType: null), - isUnboxingStub: false, - isInstantiatingStub: false, - isPrecodeImportRequired: false); + Debug.Assert(CompilationModuleGroup.ContainsMethodBody(method, false)); + Debug.Assert(method == method.GetCanonMethodTarget(CanonicalFormKind.Specific)); + return _localMethodCache.GetOrAdd(method); } private NodeCache _allMethodsOnType; public AllMethodsOnTypeNode AllMethodsOnType(TypeDesc type) { - return _allMethodsOnType.GetOrAdd(type); + return _allMethodsOnType.GetOrAdd(type.ConvertToCanonForm(CanonicalFormKind.Specific)); } private NodeCache _genericReadyToRunHelpersFromDict; @@ -99,13 +97,6 @@ public ISymbolNode ReadyToRunHelperFromTypeLookup(ReadyToRunHelperId id, Object return _genericReadyToRunHelpersFromType.GetOrAdd(new ReadyToRunGenericHelperKey(id, target, dictionaryOwner)); } - private NodeCache _readOnlyDataBlobs; - - public SettableReadOnlyDataBlob SettableReadOnlyDataBlob(Utf8String name) - { - return _readOnlyDataBlobs.GetOrAdd(name); - } - private struct ReadyToRunGenericHelperKey : IEquatable { public readonly object Target; @@ -142,11 +133,13 @@ public ModuleAndIntValueKey(int integer, EcmaModule module) Module = module; } - public bool Equals(ModuleAndIntValueKey other) => IntValue == other.IntValue && Module.Equals(other.Module); + public bool Equals(ModuleAndIntValueKey other) => IntValue == other.IntValue && ((Module == null && other.Module == null) || Module.Equals(other.Module)); public override bool Equals(object obj) => obj is ModuleAndIntValueKey && Equals((ModuleAndIntValueKey)obj); public override int GetHashCode() { int hashCode = IntValue * 0x5498341 + 0x832424; + if (Module == null) + return hashCode; return hashCode * 23 + Module.GetHashCode(); } } @@ -214,11 +207,6 @@ private void CreateNodeCaches() (TypeDesc)helperKey.Target)); }); - _readOnlyDataBlobs = new NodeCache(key => - { - return new SettableReadOnlyDataBlob(key, ObjectNodeSection.ReadOnlyDataSection); - }); - _constructedHelpers = new NodeCache(helperId => { return new Import(EagerImports, new ReadyToRunHelperSignature(helperId)); @@ -269,9 +257,6 @@ private void CreateNodeCaches() _debugDirectoryEntries = new NodeCache(key => { - if (key.IntValue < 0) - return new NativeDebugDirectoryEntryNode(key.Module); - else return new CopiedDebugDirectoryEntryNode(key.Module, key.IntValue); }); @@ -365,7 +350,8 @@ private IMethodNode CreateMethodEntrypoint(TypeAndMethod key) bool isUnboxingStub = key.IsUnboxingStub; bool isInstantiatingStub = key.IsInstantiatingStub; bool isPrecodeImportRequired = key.IsPrecodeImportRequired; - if (CompilationModuleGroup.ContainsMethodBody(method.Method, false)) + MethodDesc compilableMethod = method.Method.GetCanonMethodTarget(CanonicalFormKind.Specific); + if (CompilationModuleGroup.ContainsMethodBody(compilableMethod, false)) { if (isPrecodeImportRequired) { @@ -373,7 +359,7 @@ private IMethodNode CreateMethodEntrypoint(TypeAndMethod key) this, ReadyToRunFixupKind.MethodEntry, method, - CreateMethodEntrypointNodeHelper(method), + CompiledMethodNode(compilableMethod), isUnboxingStub, isInstantiatingStub); } @@ -383,7 +369,7 @@ private IMethodNode CreateMethodEntrypoint(TypeAndMethod key) this, ReadyToRunFixupKind.MethodEntry, method, - CreateMethodEntrypointNodeHelper(method), + CompiledMethodNode(compilableMethod), isUnboxingStub, isInstantiatingStub); } @@ -406,15 +392,6 @@ public IMethodNode MethodEntrypoint(MethodWithToken method, bool isUnboxingStub, return _importMethods.GetOrAdd(key); } - private NodeCache _localMethodCache; - - private MethodWithGCInfo CreateMethodEntrypointNodeHelper(MethodWithToken targetMethod) - { - Debug.Assert(CompilationModuleGroup.ContainsMethodBody(targetMethod.Method, false)); - - return _localMethodCache.GetOrAdd(targetMethod.Method); - } - public IEnumerable EnumerateCompiledMethods() { return EnumerateCompiledMethods(null, CompiledMethodCategory.All); @@ -427,7 +404,10 @@ public IEnumerable EnumerateCompiledMethods(EcmaModule moduleT MethodDesc method = methodNode.Method; MethodWithGCInfo methodCodeNode = methodNode as MethodWithGCInfo; #if DEBUG - IMethodNode methodNodeDebug = MethodEntrypoint(method); + EcmaModule module = ((EcmaMethod)method.GetTypicalMethodDefinition()).Module; + ModuleToken moduleToken = Resolver.GetModuleTokenForMethod(method, throwIfNotFound: true); + + IMethodNode methodNodeDebug = MethodEntrypoint(new MethodWithToken(method, moduleToken, constrainedType: null), false, false, false); MethodWithGCInfo methodCodeNodeDebug = methodNodeDebug as MethodWithGCInfo; if (methodCodeNodeDebug == null && methodNodeDebug is LocalMethodImport localMethodImport) { @@ -676,10 +656,7 @@ public void AttachToDependencyGraph(DependencyAnalyzerBase graph) graph.AddRoot(PrecodeImports, "Precode helper imports are always generated"); graph.AddRoot(StringImports, "String imports are always generated"); graph.AddRoot(Header, "ReadyToRunHeader is always generated"); - if (!CompilationModuleGroup.IsCompositeBuildMode) - { - graph.AddRoot(CopiedCorHeaderNode, "MSIL COR header is always generated for single-file R2R files"); - } + graph.AddRoot(CopiedCorHeaderNode, "MSIL COR header is always generated for R2R files"); graph.AddRoot(DebugDirectoryNode, "Debug Directory will always contain at least one entry"); if (Win32ResourcesNode != null) diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs index 1130220fbc94db..aeca8c8da3b244 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunSymbolNodeFactory.cs @@ -107,7 +107,7 @@ private void CreateNodeCaches() _codegenNodeFactory.MethodSignature(ReadyToRunFixupKind.VirtualEntry, cellKey.Method, cellKey.IsUnboxingStub, isInstantiatingStub: false), - cellKey.CallSite); + cellKey.CallingMethod); }); _delegateCtors = new NodeCache(ctorKey => @@ -125,6 +125,14 @@ private void CreateNodeCaches() new DelegateCtorSignature(ctorKey.Type, targetMethodNode, ctorKey.Method.Token)); }); + _checkTypeLayoutCache = new NodeCache(key => + { + return new PrecodeHelperImport( + _codegenNodeFactory, + _codegenNodeFactory.TypeSignature(ReadyToRunFixupKind.Check_TypeLayout, key) + ); + }); + _genericLookupHelpers = new NodeCache(key => { return new DelayLoadHelperImport( @@ -415,9 +423,9 @@ public ISymbolNode FieldBaseOffset(TypeDesc typeDesc) private NodeCache _interfaceDispatchCells = new NodeCache(); - public ISymbolNode InterfaceDispatchCell(MethodWithToken method, bool isUnboxingStub, string callSite) + public ISymbolNode InterfaceDispatchCell(MethodWithToken method, bool isUnboxingStub, MethodDesc callingMethod) { - MethodAndCallSite cellKey = new MethodAndCallSite(method, isUnboxingStub, callSite); + MethodAndCallSite cellKey = new MethodAndCallSite(method, isUnboxingStub, callingMethod); return _interfaceDispatchCells.GetOrAdd(cellKey); } @@ -434,22 +442,29 @@ public ISymbolNode DelegateCtor(TypeDesc delegateType, MethodWithToken method) return _delegateCtors.GetOrAdd(ctorKey); } + private NodeCache _checkTypeLayoutCache; + + public ISymbolNode CheckTypeLayout(TypeDesc type) + { + return _checkTypeLayoutCache.GetOrAdd(type); + } + struct MethodAndCallSite : IEquatable { public readonly MethodWithToken Method; public readonly bool IsUnboxingStub; - public readonly string CallSite; + public readonly MethodDesc CallingMethod; - public MethodAndCallSite(MethodWithToken method, bool isUnboxingStub, string callSite) + public MethodAndCallSite(MethodWithToken method, bool isUnboxingStub, MethodDesc callingMethod) { - CallSite = callSite; IsUnboxingStub = isUnboxingStub; Method = method; + CallingMethod = callingMethod; } public bool Equals(MethodAndCallSite other) { - return CallSite == other.CallSite && Method.Equals(other.Method) && IsUnboxingStub == other.IsUnboxingStub; + return Method.Equals(other.Method) && IsUnboxingStub == other.IsUnboxingStub && CallingMethod == other.CallingMethod; } public override bool Equals(object obj) @@ -459,7 +474,7 @@ public override bool Equals(object obj) public override int GetHashCode() { - return (CallSite != null ? CallSite.GetHashCode() : 0) + return (CallingMethod != null ? unchecked(199 * CallingMethod.GetHashCode()) : 0) ^ unchecked(31 * Method.GetHashCode()) ^ (IsUnboxingStub ? -0x80000000 : 0); } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/NoMethodsCompilationModuleGroup.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/NoMethodsCompilationModuleGroup.cs new file mode 100644 index 00000000000000..cc97f72a952613 --- /dev/null +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/NoMethodsCompilationModuleGroup.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Internal.ReadyToRunConstants; +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace ILCompiler +{ + /// + /// A compilation group that only contains no methods. Used for creating an R2R image without + /// any method compiled into it. Needed for handling inputbubble scenarios where a dependent + /// assembly should not be R2R'd. + /// + public class NoMethodsCompilationModuleGroup : ReadyToRunCompilationModuleGroupBase + { + public NoMethodsCompilationModuleGroup( + TypeSystemContext context, + bool isCompositeBuildMode, + bool isInputBubble, + IEnumerable compilationModuleSet, + IEnumerable versionBubbleModuleSet, + bool compileGenericDependenciesFromVersionBubbleModuleSet) : + base(context, + isCompositeBuildMode, + isInputBubble, + compilationModuleSet, + versionBubbleModuleSet, + compileGenericDependenciesFromVersionBubbleModuleSet) + { + } + + public override bool ContainsMethodBody(MethodDesc method, bool unboxingStub) + { + return false; + } + + public override void ApplyProfilerGuidedCompilationRestriction(ProfileDataManager profileGuidedCompileRestriction) + { + return; + } + + public override ReadyToRunFlags GetReadyToRunFlags() + { + // Partial by definition. + return ReadyToRunFlags.READYTORUN_FLAG_Partial; + } + } +} diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs index 8316a0d92c2752..bd08ba25809dbf 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Reflection.PortableExecutable; using System.Runtime.CompilerServices; @@ -195,8 +196,11 @@ public RootingServiceProvider(NodeFactory factory, RootAdder rootAdder) public void AddCompilationRoot(MethodDesc method, string reason) { MethodDesc canonMethod = method.GetCanonMethodTarget(CanonicalFormKind.Specific); - IMethodNode methodEntryPoint = _factory.MethodEntrypoint(canonMethod); - _rootAdder(methodEntryPoint, reason); + if (_factory.CompilationModuleGroup.ContainsMethodBody(canonMethod, false)) + { + IMethodNode methodEntryPoint = _factory.CompiledMethodNode(canonMethod); + _rootAdder(methodEntryPoint, reason); + } } } } @@ -227,6 +231,7 @@ public sealed class ReadyToRunCodegenCompilation : Compilation private bool _generateMapFile; public ReadyToRunSymbolNodeFactory SymbolNodeFactory { get; } + public ReadyToRunCompilationModuleGroupBase CompilationModuleGroup { get; } internal ReadyToRunCodegenCompilation( DependencyAnalyzerBase dependencyGraph, @@ -256,6 +261,7 @@ internal ReadyToRunCodegenCompilation( SymbolNodeFactory = new ReadyToRunSymbolNodeFactory(nodeFactory); _corInfoImpls = new ConditionalWeakTable(); _inputFiles = inputFiles; + CompilationModuleGroup = (ReadyToRunCompilationModuleGroupBase)nodeFactory.CompilationModuleGroup; // Generate baseline support specification for InstructionSetSupport. This will prevent usage of the generated // code if the runtime environment doesn't support the specified instruction set @@ -296,7 +302,7 @@ private void RewriteComponentFile(string inputFile, string outputFile, string ow EcmaModule inputModule = NodeFactory.TypeSystemContext.GetModuleFromPath(inputFile); CopiedCorHeaderNode copiedCorHeader = new CopiedCorHeaderNode(inputModule); - DebugDirectoryNode debugDirectory = new DebugDirectoryNode(inputModule); + DebugDirectoryNode debugDirectory = new DebugDirectoryNode(inputModule, outputFile); NodeFactory componentFactory = new NodeFactory( _nodeFactory.TypeSystemContext, _nodeFactory.CompilationModuleGroup, @@ -304,7 +310,8 @@ private void RewriteComponentFile(string inputFile, string outputFile, string ow copiedCorHeader, debugDirectory, win32Resources: new Win32Resources.ResourceData(inputModule), - Internal.ReadyToRunConstants.ReadyToRunFlags.READYTORUN_FLAG_Component); + Internal.ReadyToRunConstants.ReadyToRunFlags.READYTORUN_FLAG_Component | + Internal.ReadyToRunConstants.ReadyToRunFlags.READYTORUN_FLAG_NonSharedPInvokeStubs); IComparer> comparer = new SortableDependencyNode.ObjectNodeComparer(new CompilerComparer()); DependencyAnalyzerBase componentGraph = new DependencyAnalyzer, NodeFactory>(componentFactory, comparer); @@ -332,9 +339,86 @@ public override void WriteDependencyLog(string outputFileName) } } - internal bool IsInheritanceChainLayoutFixedInCurrentVersionBubble(TypeDesc type) + public bool IsLayoutFixedInCurrentVersionBubble(TypeDesc type) + { + // Primitive types and enums have fixed layout + if (type.IsPrimitive || type.IsEnum) + { + return true; + } + + if (!(type is MetadataType defType)) + { + // Non metadata backed types have layout defined in all version bubbles + return true; + } + + if (!NodeFactory.CompilationModuleGroup.VersionsWithModule(defType.Module)) + { + if (!type.IsValueType) + { + // Eventually, we may respect the non-versionable attribute for reference types too. For now, we are going + // to play it safe and ignore it. + return false; + } + + // Valuetypes with non-versionable attribute are candidates for fixed layout. Reject the rest. + return type is MetadataType metadataType && metadataType.IsNonVersionable(); + } + + // If the above condition passed, check that all instance fields have fixed layout as well. In particular, + // it is important for generic types with non-versionable layout (e.g. Nullable) + foreach (var field in type.GetFields()) + { + // Only instance fields matter here + if (field.IsStatic) + continue; + + var fieldType = field.FieldType; + if (!fieldType.IsValueType) + continue; + + if (!IsLayoutFixedInCurrentVersionBubble(fieldType)) + { + return false; + } + } + + return true; + } + + public bool IsInheritanceChainLayoutFixedInCurrentVersionBubble(TypeDesc type) { - // TODO: implement + // This method is not expected to be called for value types + Debug.Assert(!type.IsValueType); + + if (type.IsObject) + return true; + + if (!IsLayoutFixedInCurrentVersionBubble(type)) + { + return false; + } + + type = type.BaseType; + + if (type != null) + { + // If there are multiple inexact compilation units in the layout of the type, then the exact offset + // of a derived given field is unknown as there may or may not be alignment inserted between a type and its base + if (CompilationModuleGroup.TypeLayoutCompilationUnits(type).HasMultipleInexactCompilationUnits) + return false; + + while (!type.IsObject && type != null) + { + if (!IsLayoutFixedInCurrentVersionBubble(type)) + { + return false; + } + type = type.BaseType; + } + } + return true; } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs index 72ce7fae981048..a5e388083be3b5 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs @@ -28,13 +28,14 @@ public sealed class ReadyToRunCodegenCompilationBuilder : CompilationBuilder private InstructionSetSupport _instructionSetSupport; private string _jitPath; + private string _outputFile; // These need to provide reasonable defaults so that the user can optionally skip // calling the Use/Configure methods and still get something reasonable back. private KeyValuePair[] _ryujitOptions = Array.Empty>(); private ILProvider _ilProvider = new ReadyToRunILProvider(); - public ReadyToRunCodegenCompilationBuilder(CompilerTypeSystemContext context, CompilationModuleGroup group, IEnumerable inputFiles) + public ReadyToRunCodegenCompilationBuilder(CompilerTypeSystemContext context, ReadyToRunCompilationModuleGroupBase group, IEnumerable inputFiles) : base(context, group, new CoreRTNameMangler()) { _inputFiles = inputFiles; @@ -115,13 +116,20 @@ public ReadyToRunCodegenCompilationBuilder UseInstructionSetSupport(InstructionS return this; } + public ReadyToRunCodegenCompilationBuilder GenerateOutputFile(string outputFile) + { + _outputFile = outputFile; + return this; + } + public override ICompilation ToCompilation() { // TODO: only copy COR headers for single-assembly build and for composite build with embedded MSIL IEnumerable inputModules = _compilationGroup.CompilationModuleSet; - CopiedCorHeaderNode corHeaderNode = (_compilationGroup.IsCompositeBuildMode ? null : new CopiedCorHeaderNode(inputModules.First())); + EcmaModule singleModule = _compilationGroup.IsCompositeBuildMode ? null : inputModules.First(); + CopiedCorHeaderNode corHeaderNode = new CopiedCorHeaderNode(singleModule); // TODO: proper support for multiple input files - DebugDirectoryNode debugDirectoryNode = new DebugDirectoryNode(inputModules.First()); + DebugDirectoryNode debugDirectoryNode = new DebugDirectoryNode(singleModule, _outputFile); // Produce a ResourceData where the IBC PROFILE_DATA entry has been filtered out // TODO: proper support for multiple input files diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilationModuleGroupBase.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilationModuleGroupBase.cs index 7d55bc55e32b47..7524c5089523b5 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilationModuleGroupBase.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilationModuleGroupBase.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using Internal.TypeSystem; @@ -21,9 +22,11 @@ public abstract class ReadyToRunCompilationModuleGroupBase : CompilationModuleGr private readonly bool _compileGenericDependenciesFromVersionBubbleModuleSet; private readonly bool _isCompositeBuildMode; private readonly bool _isInputBubble; - private readonly ConcurrentDictionary _containsTypeLayoutCache = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _layoutCompilationUnits = new ConcurrentDictionary(); private readonly ConcurrentDictionary _versionsWithTypeCache = new ConcurrentDictionary(); private readonly ConcurrentDictionary _versionsWithMethodCache = new ConcurrentDictionary(); + private readonly Dictionary _moduleCompilationUnits = new Dictionary(); + private CompilationUnitIndex _nextCompilationUnit = CompilationUnitIndex.FirstDynamicallyAssigned; public ReadyToRunCompilationModuleGroupBase( TypeSystemContext context, @@ -69,15 +72,160 @@ protected bool CompileVersionBubbleGenericsIntoCurrentModule(MethodDesc method) return true; } - /// - /// If true, the type is fully contained in the current compilation group. - /// - public override bool ContainsTypeLayout(TypeDesc type) + public CompilationUnitSet TypeLayoutCompilationUnits(TypeDesc type) { - return _containsTypeLayoutCache.GetOrAdd(type, ContainsTypeLayoutUncached); + return _layoutCompilationUnits.GetOrAdd(type, TypeLayoutCompilationUnitsUncached); } - private bool ContainsTypeLayoutUncached(TypeDesc type) + private enum CompilationUnitIndex + { + RESERVEDForHasMultipleInexactCompilationUnits = 0, + RESERVEDForHasMultipleCompilationUnits = 1, + First = 2, + Current = 2, + OutsideOfVersionBubble = 3, + FirstDynamicallyAssigned = 4, + } + + // Compilation Unit Index is the compilation unit of a given module. If the compilation unit + // is unknown the module will be given an independent index from other modules, but + // IsCompilationUnitIndexExact will return false for that index. All compilation unit indices + // are >= 2, to allow for 0 and 1 to be sentinel values. + private CompilationUnitIndex ModuleToCompilationUnitIndex(ModuleDesc nonEcmaModule) + { + EcmaModule module = (EcmaModule)nonEcmaModule; + if (IsModuleInCompilationGroup(module)) + return CompilationUnitIndex.Current; + + if (!VersionsWithModule(module)) + return CompilationUnitIndex.OutsideOfVersionBubble; + + // Assemblies within the version bubble, but not compiled as part of this compilation unit are given + // unique seperate compilation units. The practical effect of this is that the compiler can assume that + // types which are entirely defined in one module can be laid out in an optimal fashion, but types + // which are laid out relying on multiple modules cannot have their type layout precisely known as + // it is unknown if the modules are bounding into a single composite image or into individual assemblies. + lock (_moduleCompilationUnits) + { + if (!_moduleCompilationUnits.TryGetValue(module, out CompilationUnitIndex compilationUnit)) + { + compilationUnit = _nextCompilationUnit; + _nextCompilationUnit = (CompilationUnitIndex)(((int)_nextCompilationUnit) + 1); + _moduleCompilationUnits.Add(module, compilationUnit); + } + + return compilationUnit; + } + } + + // Indicate whether or not the compiler can take a hard dependency on the meaning of + // the compilation unit index. + private bool IsCompilationUnitIndexExact(CompilationUnitIndex compilationUnitIndex) + { + // Currently the implementation is only allowed to assume 2 details. + // 1. That any assembly which is compiled with inputbubble set shall have its entire set of dependencies compiled as R2R + // 2. That any assembly which is compiled in the current process may be considered to be part of a single unit. + // + // At some point, the compiler could take new parameters to allow the compiler to know that assemblies not in the current compilation + // unit are to be compiled into composite images or into seperate binaries, and this helper function could return true for these other + // compilation unit shapes. + if (compilationUnitIndex != CompilationUnitIndex.Current) + return false; + else + return true; + } + + public struct CompilationUnitSet + { + private BitArray _bits; + + public CompilationUnitSet(ReadyToRunCompilationModuleGroupBase compilationGroup, ModuleDesc module) + { + CompilationUnitIndex compilationIndex = compilationGroup.ModuleToCompilationUnitIndex(module); + _bits = new BitArray(((int)compilationIndex) + 1); + _bits.Set((int)compilationIndex, true); + } + + public bool HasMultipleInexactCompilationUnits + { + get + { + if (_bits == null) + return false; + + return _bits[(int)CompilationUnitIndex.RESERVEDForHasMultipleInexactCompilationUnits]; + } + } + + public bool HasMultipleCompilationUnits + { + get + { + if (_bits == null) + return false; + + return _bits[(int)CompilationUnitIndex.RESERVEDForHasMultipleCompilationUnits]; + } + } + + public void UnionWith(ReadyToRunCompilationModuleGroupBase compilationGroup, CompilationUnitSet other) + { + if (other._bits == null) + return; + + if (HasMultipleInexactCompilationUnits) + return; + + if (other.HasMultipleInexactCompilationUnits) + { + _bits[(int)CompilationUnitIndex.RESERVEDForHasMultipleCompilationUnits] = true; + _bits[(int)CompilationUnitIndex.RESERVEDForHasMultipleInexactCompilationUnits] = true; + return; + } + + if (other._bits.Length > _bits.Length) + _bits.Length = other._bits.Length; + + if (other._bits.Length < _bits.Length) + { + for (int i = 0; i < other._bits.Length; i++) + { + if (other._bits[i]) + _bits[i] = true; + } + } + else + { + _bits.Or(other._bits); + } + + int inexactCompilationUnitCount = 0; + int compilationUnitCount = 0; + for (int i = (int)CompilationUnitIndex.First; i < _bits.Length; i++) + { + if (_bits[i]) + { + if (!compilationGroup.IsCompilationUnitIndexExact((CompilationUnitIndex)i)) + inexactCompilationUnitCount++; + + compilationUnitCount++; + } + if (compilationUnitCount == 2) + { + // Multiple compilation units found + _bits[(int)CompilationUnitIndex.RESERVEDForHasMultipleCompilationUnits] = true; + } + if (inexactCompilationUnitCount == 2) + { + // Multiple inexact compilation units involved + _bits[(int)CompilationUnitIndex.RESERVEDForHasMultipleInexactCompilationUnits] = true; + break; + } + } + } + } + + private CompilationUnitSet TypeLayoutCompilationUnitsUncached(TypeDesc type) { if (type.IsObject || type.IsPrimitive || @@ -86,17 +234,18 @@ private bool ContainsTypeLayoutUncached(TypeDesc type) type.IsFunctionPointer || type.IsCanonicalDefinitionType(CanonicalFormKind.Any)) { - return true; + return default(CompilationUnitSet); } + var defType = (MetadataType)type; - if (!ContainsType(defType)) - { - return false; - } - if (!defType.IsValueType && !ContainsTypeLayout(defType.BaseType)) + + CompilationUnitSet moduleDependencySet = new CompilationUnitSet(this, defType.Module); + + if ((type.BaseType != null) && !type.BaseType.IsObject && !type.IsValueType) { - return false; + moduleDependencySet.UnionWith(this, TypeLayoutCompilationUnits(type.BaseType)); } + foreach (FieldDesc field in defType.GetFields()) { if (field.IsStatic) @@ -105,13 +254,29 @@ private bool ContainsTypeLayoutUncached(TypeDesc type) TypeDesc fieldType = field.FieldType; if (fieldType.IsValueType && - !ContainsTypeLayout(fieldType)) + !fieldType.IsPrimitive) { - return false; + moduleDependencySet.UnionWith(this, TypeLayoutCompilationUnits((MetadataType)fieldType)); } } - return true; + return moduleDependencySet; + } + + private bool ModuleMatchesCompilationUnitIndex(ModuleDesc module1, ModuleDesc module2) + { + return ModuleToCompilationUnitIndex(module1) == ModuleToCompilationUnitIndex(module2); + } + + public bool NeedsAlignmentBetweenBaseTypeAndDerived(MetadataType baseType, MetadataType derivedType) + { + if (!ModuleMatchesCompilationUnitIndex(derivedType.Module, baseType.Module) || + TypeLayoutCompilationUnits(baseType).HasMultipleCompilationUnits) + { + return true; + } + + return false; } public sealed override bool VersionsWithModule(ModuleDesc module) diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilerContext.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilerContext.cs index 8a443acefbdf54..bbe1274cae3016 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilerContext.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilerContext.cs @@ -67,7 +67,7 @@ public override FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type) } } - public void SetCompilationGroup(CompilationModuleGroup compilationModuleGroup) + public void SetCompilationGroup(ReadyToRunCompilationModuleGroupBase compilationModuleGroup) { _r2rFieldLayoutAlgorithm.SetCompilationGroup(compilationModuleGroup); } @@ -139,11 +139,6 @@ public override bool ComputeContainsGCPointers(DefType type) return false; } - public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) - { - return _fallbackAlgorithm.ComputeHomogeneousFloatAggregateElementType(type); - } - public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind) { DefType similarSpecifiedVector = GetSimilarVector(type); @@ -202,7 +197,15 @@ public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType type, public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type) { - return _fallbackAlgorithm.ComputeValueTypeShapeCharacteristics(type); + if (type.Context.Target.Architecture == TargetArchitecture.ARM64) + { + return type.InstanceFieldSize.AsInt switch + { + 16 => ValueTypeShapeCharacteristics.Vector128Aggregate, + _ => ValueTypeShapeCharacteristics.None + }; + } + return ValueTypeShapeCharacteristics.None; } public static bool IsVectorOfTType(DefType type) diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs index 5079e20cd04560..f19140fde558a3 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs @@ -27,7 +27,7 @@ internal class ReadyToRunMetadataFieldLayoutAlgorithm : MetadataFieldLayoutAlgor /// /// Compilation module group is used to identify which types extend beyond the current version bubble. /// - private CompilationModuleGroup _compilationGroup; + private ReadyToRunCompilationModuleGroupBase _compilationGroup; public ReadyToRunMetadataFieldLayoutAlgorithm() { @@ -38,7 +38,7 @@ public ReadyToRunMetadataFieldLayoutAlgorithm() /// Set up compilation group needed for proper calculation of base class alignment in auto layout. /// /// - public void SetCompilationGroup(CompilationModuleGroup compilationGroup) + public void SetCompilationGroup(ReadyToRunCompilationModuleGroupBase compilationGroup) { _compilationGroup = compilationGroup; } @@ -822,17 +822,9 @@ protected override void AlignBaseOffsetIfNecessary(MetadataType type, ref Layout return; } - if (_compilationGroup.ContainsType(baseType)) + if (!_compilationGroup.NeedsAlignmentBetweenBaseTypeAndDerived(baseType: (MetadataType)baseType, derivedType: type)) { - if (_compilationGroup.ContainsTypeLayout(baseType)) - { - // The type is defined in the module that's currently being compiled and the type layout doesn't depend on other modules - return; - } - } - else if (_compilationGroup.VersionsWithType(baseType)) - { - // The baseType is in the current version bubble, but in a module different from the one that's currently being compiled + // The type is defined in the module that's currently being compiled and the type layout doesn't depend on other modules return; } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunTableManager.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunTableManager.cs index d2ad6b3325a7f2..805d162b049022 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunTableManager.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/ReadyToRunTableManager.cs @@ -110,14 +110,14 @@ public IEnumerable GetCompiledMethods(EcmaModule moduleToEnumerate, foreach (var perModuleData in perModuleDatas) { - perModuleData.MethodsGenerated.Sort(sortHelper); - perModuleData.GenericMethodsGenerated.Sort(sortHelper); + perModuleData.MethodsGenerated.MergeSort(sortHelper); + perModuleData.GenericMethodsGenerated.MergeSort(sortHelper); _completeSortedMethods.AddRange(perModuleData.MethodsGenerated); _completeSortedMethods.AddRange(perModuleData.GenericMethodsGenerated); _completeSortedGenericMethods.AddRange(perModuleData.GenericMethodsGenerated); } - _completeSortedMethods.Sort(sortHelper); - _completeSortedGenericMethods.Sort(sortHelper); + _completeSortedMethods.MergeSort(sortHelper); + _completeSortedGenericMethods.MergeSort(sortHelper); _sortedMethods = true; } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/SystemObjectFieldLayoutAlgorithm.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/SystemObjectFieldLayoutAlgorithm.cs index 769ed2d09bb9b5..8cdacd9e21e5de 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/SystemObjectFieldLayoutAlgorithm.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/SystemObjectFieldLayoutAlgorithm.cs @@ -54,11 +54,5 @@ public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristi { return _fallbackAlgorithm.ComputeValueTypeShapeCharacteristics(type); } - - public override DefType ComputeHomogeneousFloatAggregateElementType(DefType type) - { - return _fallbackAlgorithm.ComputeHomogeneousFloatAggregateElementType(type); - } - } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index acf9bc914dd836..5183fbfc0f6c99 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -3,7 +3,6 @@ Library ILCompiler.ReadyToRun $(NetCoreAppCurrent) - netcoreapp3.0 true READYTORUN;$(DefineConstants) false @@ -15,6 +14,7 @@ the same bits tests expect to see in artifacts/crossgen2. That way we never need to wonder which binaries are up to date and which are stale. --> false + Debug;Release;Checked @@ -62,7 +62,7 @@ - + @@ -94,6 +94,7 @@ + @@ -133,7 +134,6 @@ - @@ -198,9 +198,11 @@ + + diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 50a9dbb2aaa30c..883303110582a7 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -136,11 +136,13 @@ unsafe partial class CorInfoImpl private uint OffsetOfDelegateFirstTarget => (uint)(3 * PointerSize); // Delegate::m_functionPointer private readonly ReadyToRunCodegenCompilation _compilation; - private IReadyToRunMethodCodeNode _methodCodeNode; + private MethodWithGCInfo _methodCodeNode; private OffsetMapping[] _debugLocInfos; private NativeVarInfo[] _debugVarInfos; private ArrayBuilder _inlinedMethods; + private static readonly UnboxingMethodDescFactory s_unboxingThunkFactory = new UnboxingMethodDescFactory(); + public CorInfoImpl(ReadyToRunCodegenCompilation compilation) : this() { @@ -204,7 +206,7 @@ public static bool ShouldSkipCompilation(MethodDesc methodNeedingCode) return false; } - public void CompileMethod(IReadyToRunMethodCodeNode methodCodeNodeNeedingCode) + public void CompileMethod(MethodWithGCInfo methodCodeNodeNeedingCode) { bool codeGotPublished = false; _methodCodeNode = methodCodeNodeNeedingCode; @@ -624,6 +626,8 @@ private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum) case CorInfoHelpFunc.CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL: case CorInfoHelpFunc.CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL: case CorInfoHelpFunc.CORINFO_HELP_GETREFANY: + // For Vector256.Create and similar cases + case CorInfoHelpFunc.CORINFO_HELP_THROW_NOT_IMPLEMENTED: throw new RequiresRuntimeJitException(ftnNum.ToString()); default: @@ -1151,25 +1155,6 @@ private void ceeInfoGetCallInfo( ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramCallVirtStatic, originalMethod); } - if ((flags & CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN) != 0 - && originalMethod.IsNativeCallable) - { - if (!originalMethod.Signature.IsStatic) // Must be a static method - { - ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramNonStaticMethod, originalMethod); - } - - if (originalMethod.HasInstantiation || originalMethod.OwningType.HasInstantiation) // No generics involved - { - ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramGenericMethod, originalMethod); - } - - if (Marshaller.IsMarshallingRequired(originalMethod.Signature, Array.Empty())) // Only blittable arguments - { - ThrowHelper.ThrowInvalidProgramException(ExceptionStringID.InvalidProgramNonBlittableTypes, originalMethod); - } - } - exactType = type; constrainedType = null; @@ -1503,7 +1488,7 @@ private void classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_STRUCT_* cls) private void classMustBeLoadedBeforeCodeIsRun(TypeDesc type) { ISymbolNode node = _compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.TypeHandle, type); - ((MethodWithGCInfo)_methodCodeNode).Fixups.Add(node); + _methodCodeNode.Fixups.Add(node); } private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult) @@ -1532,9 +1517,9 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO out useInstantiatingStub); var targetDetails = _compilation.TypeSystemContext.Target; - if (targetDetails.Architecture == TargetArchitecture.X86 && targetMethod.IsNativeCallable) + if (targetDetails.Architecture == TargetArchitecture.X86 && targetMethod.IsUnmanagedCallersOnly) { - throw new RequiresRuntimeJitException("ReadyToRun: References to methods with NativeCallableAttribute not implemented"); + throw new RequiresRuntimeJitException("ReadyToRun: References to methods with UnmanagedCallersOnlyAttribute not implemented"); } if (pResult->thisTransform == CORINFO_THIS_TRANSFORM.CORINFO_BOX_THIS) @@ -1566,7 +1551,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO _compilation.SymbolNodeFactory.InterfaceDispatchCell( new MethodWithToken(targetMethod, HandleToModuleToken(ref pResolvedToken, targetMethod), constrainedType: null), isUnboxingStub: false, - _compilation.NameMangler.GetMangledMethodName(MethodBeingCompiled).ToString())); + MethodBeingCompiled)); } break; @@ -1884,7 +1869,7 @@ private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool if ((td.IsValueType) && !md.Signature.IsStatic) { - md = _unboxingThunkFactory.GetUnboxingMethod(md); + md = getUnboxingThunk(md); } symbolNode = _compilation.SymbolNodeFactory.CreateReadyToRunHelper( @@ -1907,6 +1892,11 @@ private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool } } + private MethodDesc getUnboxingThunk(MethodDesc method) + { + return s_unboxingThunkFactory.GetUnboxingMethod(method); + } + private CORINFO_METHOD_STRUCT_* embedMethodHandle(CORINFO_METHOD_STRUCT_* handle, ref void* ppIndirection) { // TODO: READYTORUN FUTURE: Handle this case correctly @@ -1914,48 +1904,15 @@ private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool throw new RequiresRuntimeJitException("embedMethodHandle: " + methodDesc.ToString()); } - private bool IsLayoutFixedInCurrentVersionBubble(TypeDesc type) - { - // Primitive types and enums have fixed layout - if (type.IsPrimitive || type.IsEnum) - { - return true; - } - - if (!_compilation.NodeFactory.CompilationModuleGroup.VersionsWithType(type)) - { - if (!type.IsValueType) - { - // Eventually, we may respect the non-versionable attribute for reference types too. For now, we are going - // to play it safe and ignore it. - return false; - } - - // Valuetypes with non-versionable attribute are candidates for fixed layout. Reject the rest. - return type is MetadataType metadataType && metadataType.IsNonVersionable(); - } - - return true; - } - - /// - /// Is field layout of the inheritance chain fixed within the current version bubble? - /// - private bool IsInheritanceChainLayoutFixedInCurrentVersionBubble(TypeDesc type) + private bool NeedsTypeLayoutCheck(TypeDesc type) { - // This method is not expected to be called for value types - Debug.Assert(!type.IsValueType); + if (!type.IsDefType) + return false; - while (!type.IsObject && type != null) - { - if (!IsLayoutFixedInCurrentVersionBubble(type)) - { - return false; - } - type = type.BaseType; - } + if (!type.IsValueType) + return false; - return true; + return !_compilation.IsLayoutFixedInCurrentVersionBubble(type); } private bool HasLayoutMetadata(TypeDesc type) @@ -1991,14 +1948,13 @@ private void EncodeFieldBaseOffset(FieldDesc field, CORINFO_FIELD_INFO* pResult, { // No-op except for instance fields } - else if (!IsLayoutFixedInCurrentVersionBubble(pMT)) + else if (!_compilation.IsLayoutFixedInCurrentVersionBubble(pMT)) { if (pMT.IsValueType) { // ENCODE_CHECK_FIELD_OFFSET - pResult->offset = 0; - pResult->fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_INSTANCE_WITH_BASE; - pResult->fieldLookup = CreateConstLookupToSymbol(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); + _methodCodeNode.Fixups.Add(_compilation.SymbolNodeFactory.CheckFieldOffset(field)); + // No-op other than generating the check field offset fixup } else { @@ -2014,7 +1970,7 @@ private void EncodeFieldBaseOffset(FieldDesc field, CORINFO_FIELD_INFO* pResult, { // ENCODE_NONE } - else if (IsInheritanceChainLayoutFixedInCurrentVersionBubble(pMT.BaseType)) + else if (_compilation.IsInheritanceChainLayoutFixedInCurrentVersionBubble(pMT.BaseType)) { // ENCODE_NONE } @@ -2115,7 +2071,7 @@ private HRESULT allocMethodBlockCounts(uint count, ref BlockCounts* pBlockCounts pBlockCounts = (BlockCounts*)GetPin(_bbCounts = new byte[count * sizeof(BlockCounts)]); if (_profileDataNode == null) { - _profileDataNode = _compilation.NodeFactory.ProfileData((MethodWithGCInfo)_methodCodeNode); + _profileDataNode = _compilation.NodeFactory.ProfileData(_methodCodeNode); } return 0; } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/UnboxingMethodDescFactory.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/UnboxingMethodDescFactory.cs new file mode 100644 index 00000000000000..9763e8862ee9e9 --- /dev/null +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/JitInterface/UnboxingMethodDescFactory.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using Internal.TypeSystem; + +namespace Internal.JitInterface +{ + internal class UnboxingMethodDescFactory : ConcurrentDictionary + { + private Func _factoryDelegate; + private UnboxingMethodDesc CreateUnboxingMethod(MethodDesc method) + { + return new UnboxingMethodDesc(method, this); + } + + public UnboxingMethodDescFactory() + { + _factoryDelegate = CreateUnboxingMethod; + } + + public UnboxingMethodDesc GetUnboxingMethod(MethodDesc method) + { + return GetOrAdd(method, _factoryDelegate); + } + } +} \ No newline at end of file diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/MapFileBuilder.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/MapFileBuilder.cs new file mode 100644 index 00000000000000..dd7b821ba85ee9 --- /dev/null +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/MapFileBuilder.cs @@ -0,0 +1,334 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using ILCompiler.DependencyAnalysis; + +namespace ILCompiler.PEWriter +{ + /// + /// Base class for symbols and nodes in the map file implements common logic + /// for section / offset ordering. + /// + public class MapFileItem + { + public class Comparer : IComparer + { + public readonly static Comparer Instance = new Comparer(); + + public int Compare([AllowNull] MapFileItem x, [AllowNull] MapFileItem y) + { + return (x.SectionIndex != y.SectionIndex ? x.SectionIndex.CompareTo(y.SectionIndex) : x.Offset.CompareTo(y.Offset)); + } + } + + /// + /// Item section index + /// + public readonly int SectionIndex; + + /// + /// Offset relative to section beginning + /// + public readonly int Offset; + + /// + /// Item name + /// + public readonly string Name; + + public MapFileItem(int sectionIndex, int offset, string name) + { + SectionIndex = sectionIndex; + Offset = offset; + Name = name; + } + } + + /// + /// This class represents a single node (contiguous block of data) in the output R2R PE file. + /// + public class MapFileNode : MapFileItem + { + /// + /// Node length (number of bytes). This doesn't include any external alignment + /// applied when concatenating the nodes to form sections. + /// + public readonly int Length; + + /// + /// Number of file-level relocations (.reloc section entries) used by the node. + /// + public int Relocations { get; private set; } + + public MapFileNode(int sectionIndex, int offset, int length, string name) + : base(sectionIndex, offset, name) + { + Length = length; + Relocations = 0; + } + + public void AddRelocation() + { + Relocations++; + } + } + + /// + /// Symbol is a "pointer" into the PE file. Most (but not all) symbols correspond to + /// node beginnings (most nodes have a "start symbol" representing the beginning + /// of the node). + /// + public class MapFileSymbol : MapFileItem + { + public MapFileSymbol(int sectionIndex, int offset, string name) + : base(sectionIndex, offset, name) + { + } + } + + /// + /// Helper class used to collect information to be output into the map file. + /// + public class MapFileBuilder + { + /// + /// Number of first characters of the section name to retain in the symbol & node map. + /// + private const int SectionNameHeadLength = 7; + + /// + /// Statistic information for a single node type. + /// + private class NodeTypeStatistics + { + public readonly string Name; + + public int Count; + public int Length; + + public NodeTypeStatistics(string name) + { + Name = name; + } + + public void AddNode(MapFileNode node) + { + Debug.Assert(Name == node.Name); + Count++; + Length += node.Length; + } + } + + private readonly List _nodes; + private readonly List _symbols; + private readonly List
_sections; + + private readonly Dictionary _relocCounts; + + private long _fileSize; + + public MapFileBuilder() + { + _nodes = new List(); + _symbols = new List(); + _sections = new List
(); + + _relocCounts = new Dictionary(); + } + + public void AddNode(MapFileNode node) + { + _nodes.Add(node); + } + + public void AddRelocation(MapFileNode node, RelocType relocType) + { + node.AddRelocation(); + _relocCounts.TryGetValue(relocType, out int relocTypeCount); + _relocCounts[relocType] = relocTypeCount + 1; + } + + public void AddSymbol(MapFileSymbol symbol) + { + _symbols.Add(symbol); + } + + public void AddSection(Section section) + { + _sections.Add(section); + } + + public void SetFileSize(long fileSize) + { + _fileSize = fileSize; + } + + public void Save(string mapFileName) + { + Console.WriteLine("Emitting map file: {0}", mapFileName); + + _nodes.Sort(MapFileItem.Comparer.Instance); + _symbols.Sort(MapFileItem.Comparer.Instance); + + using (StreamWriter mapWriter = new StreamWriter(mapFileName)) + { + WriteHeader(mapWriter); + WriteNodeTypeStatistics(mapWriter); + WriteRelocTypeStatistics(mapWriter); + WriteSections(mapWriter); + WriteMap(mapWriter); + } + } + + private void WriteHeader(StreamWriter writer) + { + WriteTitle(writer, "Summary Info"); + + writer.WriteLine($"Output file size: {_fileSize,10}"); + writer.WriteLine($"Section count: {_sections.Count,10}"); + writer.WriteLine($"Node count: {_nodes.Count,10}"); + writer.WriteLine($"Symbol count: {_symbols.Count,10}"); + writer.WriteLine($"Relocation count: {_relocCounts.Values.Sum(),10}"); + } + + private void WriteNodeTypeStatistics(StreamWriter writer) + { + List nodeTypeStats = new List(); + Dictionary statsNameIndex = new Dictionary(); + foreach (MapFileNode node in _nodes) + { + if (!statsNameIndex.TryGetValue(node.Name, out int statsIndex)) + { + statsIndex = nodeTypeStats.Count; + nodeTypeStats.Add(new NodeTypeStatistics(node.Name)); + statsNameIndex.Add(node.Name, statsIndex); + } + nodeTypeStats[statsIndex].AddNode(node); + } + nodeTypeStats.Sort((a, b) => b.Length.CompareTo(a.Length)); + + WriteTitle(writer, "Node Type Statistics"); + WriteTitle(writer, " LENGTH | %FILE | AVERAGE | COUNT | NODETYPE"); + foreach (NodeTypeStatistics nodeStats in nodeTypeStats) + { + writer.Write($"{nodeStats.Length,10} | "); + writer.Write($"{(nodeStats.Length * 100.0 / _fileSize),7:F3} | "); + writer.Write($"{(nodeStats.Length / (double)nodeStats.Count),10:F1} | "); + writer.Write($"{nodeStats.Count,6} | "); + writer.WriteLine(nodeStats.Name); + } + } + + private void WriteRelocTypeStatistics(StreamWriter writer) + { + KeyValuePair[] relocTypeCounts = _relocCounts.ToArray(); + Array.Sort(relocTypeCounts, (a, b) => b.Value.CompareTo(a.Value)); + + WriteTitle(writer, "Reloc Type Statistics"); + WriteTitle(writer, " COUNT | RELOC_TYPE"); + foreach (KeyValuePair relocTypeCount in relocTypeCounts) + { + writer.Write($"{relocTypeCount.Value,8} | "); + writer.WriteLine(relocTypeCount.Key.ToString()); + } + + const int NumberOfTopNodesByRelocType = 10; + + WriteTitle(writer, "Top Nodes By Relocation Count"); + WriteTitle(writer, " COUNT | SYMBOL (NODE)"); + + foreach (MapFileNode node in _nodes.Where(node => node.Relocations != 0).OrderByDescending(node => node.Relocations).Take(NumberOfTopNodesByRelocType)) + { + writer.Write($"{node.Relocations,8} | "); + int symbolIndex = _symbols.BinarySearch(new MapFileSymbol(node.SectionIndex, node.Offset, name: null), MapFileItem.Comparer.Instance); + if (symbolIndex >= 0 && symbolIndex < _symbols.Count && MapFileItem.Comparer.Instance.Compare(_symbols[symbolIndex], node) == 0) + { + writer.Write($"{_symbols[symbolIndex].Name}"); + } + writer.WriteLine($" ({node.Name})"); + } + } + + private void WriteSections(StreamWriter writer) + { + WriteTitle(writer, "Section Map"); + WriteTitle(writer, "INDEX | FILEOFFSET | RVA | END_RVA | LENGTH | NAME"); + for (int sectionIndex = 0; sectionIndex < _sections.Count; sectionIndex++) + { + Section section = _sections[sectionIndex]; + writer.Write($"{sectionIndex,5} | "); + writer.Write($"0x{section.FilePosWhenPlaced:X8} | "); + writer.Write($"0x{section.RVAWhenPlaced:X8} | "); + writer.Write($"0x{(section.RVAWhenPlaced + section.Content.Count):X8} | "); + writer.Write($"0x{section.Content.Count:X8} | "); + writer.WriteLine(section.Name); + } + } + + private void WriteMap(StreamWriter writer) + { + WriteTitle(writer, "Node & Symbol Map"); + WriteTitle(writer, "RVA | LENGTH | RELOCS | SECTION | SYMBOL (NODE)"); + + int nodeIndex = 0; + int symbolIndex = 0; + + while (nodeIndex < _nodes.Count || symbolIndex < _symbols.Count) + { + if (nodeIndex >= _nodes.Count || symbolIndex < _symbols.Count && MapFileItem.Comparer.Instance.Compare(_symbols[symbolIndex], _nodes[nodeIndex]) < 0) + { + // No more nodes or next symbol is below next node - emit symbol + MapFileSymbol symbol = _symbols[symbolIndex++]; + Section section = _sections[symbol.SectionIndex]; + writer.Write($"0x{symbol.Offset + section.RVAWhenPlaced:X8} | "); + writer.Write(" | "); + writer.Write(" | "); + writer.Write($"{GetNameHead(section),-SectionNameHeadLength} | "); + writer.WriteLine(symbol.Name); + } + else + { + // Emit node and optionally symbol + MapFileNode node = _nodes[nodeIndex++]; + Section section = _sections[node.SectionIndex]; + + writer.Write($"0x{node.Offset + section.RVAWhenPlaced:X8} | "); + writer.Write($"0x{node.Length:X6} | "); + writer.Write($"{node.Relocations,6} | "); + writer.Write($"{GetNameHead(section),-SectionNameHeadLength} | "); + if (symbolIndex < _symbols.Count && MapFileItem.Comparer.Instance.Compare(node, _symbols[symbolIndex]) == 0) + { + MapFileSymbol symbol = _symbols[symbolIndex++]; + writer.Write($"{symbol.Name}"); + } + writer.WriteLine($" ({node.Name})"); + } + } + } + + private static string GetNameHead(Section section) + { + string sectionNameHead = section.Name; + if (sectionNameHead.Length > SectionNameHeadLength) + { + sectionNameHead = sectionNameHead.Substring(0, SectionNameHeadLength); + } + return sectionNameHead; + } + + private void WriteTitle(StreamWriter writer, string title) + { + writer.WriteLine(); + writer.WriteLine(title); + writer.WriteLine(new string('-', title.Length)); + } + } +} diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs index ac63ae303a1c09..bb648b9af99253 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/R2RPEBuilder.cs @@ -223,8 +223,8 @@ public void SetWin32Resources(ISymbolNode symbol, int resourcesSize) /// Object data to emit /// Target section /// Textual name of the object data for diagnostic purposese - /// Optional map file to output the data item to - public void AddObjectData(ObjectNode.ObjectData objectData, ObjectNodeSection section, string name, TextWriter mapFile) + /// Optional map file builder to output the data item to + public void AddObjectData(ObjectNode.ObjectData objectData, ObjectNodeSection section, string name, MapFileBuilder mapFileBuilder) { if (_written) { @@ -248,7 +248,7 @@ public void AddObjectData(ObjectNode.ObjectData objectData, ObjectNodeSection se throw new NotImplementedException(); } - _sectionBuilder.AddObjectData(objectData, targetSectionIndex, name, mapFile); + _sectionBuilder.AddObjectData(objectData, targetSectionIndex, name, mapFileBuilder); } public int GetSymbolFilePosition(ISymbolNode symbol) @@ -276,6 +276,15 @@ public void Write(Stream outputStream, int timeDateStamp) _written = true; } + /// + /// Fill in map builder section table. + /// + /// Map file builder to set up + public void AddSections(MapFileBuilder mapFileBuilder) + { + _sectionBuilder.AddSections(mapFileBuilder); + } + /// /// PE header constants copied from System.Reflection.Metadata where they are /// sadly mostly internal or private. diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/SectionBuilder.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/SectionBuilder.cs index 904bea5ec0397c..4e6855e985a053 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/SectionBuilder.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/SectionBuilder.cs @@ -4,15 +4,11 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Linq; -using System.Reflection; using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; -using System.Runtime.CompilerServices; using ILCompiler.DependencyAnalysis; @@ -442,8 +438,8 @@ private NameMangler GetNameMangler() /// Block to add /// Section index /// Node name to emit in the map file - /// Optional map file to emit - public void AddObjectData(ObjectNode.ObjectData objectData, int sectionIndex, string name, TextWriter mapFile) + /// Optional map file to emit + public void AddObjectData(ObjectNode.ObjectData objectData, int sectionIndex, string name, MapFileBuilder mapFileBuilder) { Section section = _sections[sectionIndex]; @@ -480,9 +476,21 @@ public void AddObjectData(ObjectNode.ObjectData objectData, int sectionIndex, st } } - if (mapFile != null) + if (mapFileBuilder != null) { - mapFile.WriteLine($@"S{sectionIndex}+0x{alignedOffset:X4}..{(alignedOffset + objectData.Data.Length):X4}: {objectData.Data.Length:X4} * {name}"); + MapFileNode node = new MapFileNode(sectionIndex, alignedOffset, objectData.Data.Length, name); + mapFileBuilder.AddNode(node); + if (objectData.Relocs != null) + { + foreach (Relocation reloc in objectData.Relocs) + { + RelocType fileReloc = Relocation.GetFileRelocationType(reloc.RelocType); + if (fileReloc != RelocType.IMAGE_REL_BASED_ABSOLUTE) + { + mapFileBuilder.AddRelocation(node, fileReloc); + } + } + } } section.Content.WriteBytes(objectData.Data); @@ -491,12 +499,12 @@ public void AddObjectData(ObjectNode.ObjectData objectData, int sectionIndex, st { foreach (ISymbolDefinitionNode symbol in objectData.DefinedSymbols) { - if (mapFile != null) + if (mapFileBuilder != null) { Utf8StringBuilder sb = new Utf8StringBuilder(); symbol.AppendMangledName(GetNameMangler(), sb); int sectionRelativeOffset = alignedOffset + symbol.Offset; - mapFile.WriteLine($@" +0x{sectionRelativeOffset:X4}: {sb.ToString()}"); + mapFileBuilder.AddSymbol(new MapFileSymbol(sectionIndex, sectionRelativeOffset, sb.ToString())); } _symbolMap.Add(symbol, new SymbolTarget( sectionIndex: sectionIndex, @@ -530,6 +538,14 @@ public IEnumerable GetSections() return sectionList; } + public void AddSections(MapFileBuilder mapFileBuilder) + { + foreach (Section section in _sections) + { + mapFileBuilder.AddSection(section); + } + } + /// /// Traverse blocks within a single section and use them to calculate final layout /// of the given section. @@ -613,6 +629,14 @@ private BlobBuilder SerializeRelocationSection(SectionLocation sectionLocation) int baseRVA = 0; List offsetsAndTypes = null; + Section relocSection = FindSection(R2RPEBuilder.RelocSectionName); + if (relocSection != null) + { + relocSection.FilePosWhenPlaced = sectionLocation.PointerToRawData; + relocSection.RVAWhenPlaced = sectionLocation.RelativeVirtualAddress; + builder = relocSection.Content; + } + // Traverse relocations in all sections in their RVA order // By now, all "normal" sections with relocations should already have been laid out foreach (Section section in _sections.OrderBy((sec) => sec.RVAWhenPlaced)) @@ -622,7 +646,7 @@ private BlobBuilder SerializeRelocationSection(SectionLocation sectionLocation) for (int relocIndex = 0; relocIndex < placedObjectData.Relocs.Length; relocIndex++) { RelocType relocType = placedObjectData.Relocs[relocIndex].RelocType; - RelocType fileRelocType = GetFileRelocationType(relocType); + RelocType fileRelocType = Relocation.GetFileRelocationType(relocType); if (fileRelocType != RelocType.IMAGE_REL_BASED_ABSOLUTE) { int relocationRVA = section.RVAWhenPlaced + placedObjectData.Offset + placedObjectData.Relocs[relocIndex].Offset; @@ -681,7 +705,7 @@ private static void FlushRelocationBlock(BlobBuilder builder, int baseRVA, List< /// RVA and file location of the .edata section private BlobBuilder SerializeExportSection(SectionLocation sectionLocation) { - _exportSymbols.Sort((es1, es2) => StringComparer.Ordinal.Compare(es1.Name, es2.Name)); + _exportSymbols.MergeSort((es1, es2) => StringComparer.Ordinal.Compare(es1.Name, es2.Name)); BlobBuilder builder = new BlobBuilder(); @@ -876,26 +900,5 @@ public void RelocateOutputFile( // Flush remaining PE file blocks after the last relocation relocationHelper.CopyRestOfFile(); } - - /// - /// Return file relocation type for the given relocation type. If the relocation - /// doesn't require a file-level relocation entry in the .reloc section, 0 is returned - /// corresponding to the IMAGE_REL_BASED_ABSOLUTE no-op relocation record. - /// - /// Relocation type - /// File-level relocation type or 0 (IMAGE_REL_BASED_ABSOLUTE) if none is required - private static RelocType GetFileRelocationType(RelocType relocationType) - { - switch (relocationType) - { - case RelocType.IMAGE_REL_BASED_HIGHLOW: - case RelocType.IMAGE_REL_BASED_DIR64: - case RelocType.IMAGE_REL_BASED_THUMB_MOV32: - return relocationType; - - default: - return RelocType.IMAGE_REL_BASED_ABSOLUTE; - } - } } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/TargetExtensions.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/TargetExtensions.cs index d4ba4683609c2e..0b943d6233991c 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/TargetExtensions.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ObjectWriter/TargetExtensions.cs @@ -20,6 +20,7 @@ public enum MachineOSOverride : ushort Apple = 0x4644, FreeBSD = 0xADC4, NetBSD = 0x1993, + SunOS = 0x1992, } /// diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/DebugInfo.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/DebugInfo.cs index fe0872c1b39863..f1ce1b87407a6c 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/DebugInfo.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/DebugInfo.cs @@ -134,7 +134,7 @@ private void ParseBounds(byte[] image, int offset) var entry = new DebugInfoBoundsEntry(); previousNativeOffset += reader.ReadUInt(); entry.NativeOffset = previousNativeOffset; - entry.ILOffset = (uint)(reader.ReadUInt() + (int)MappingTypes.MaxMappingValue); + entry.ILOffset = reader.ReadUInt() + (uint)DebugInfoBoundsType.MaxMappingValue; entry.SourceTypes = (SourceTypes)reader.ReadUInt(); _boundsList.Add(entry); } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/DebugInfoTypes.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/DebugInfoTypes.cs index deeec8716dc1e7..f426fa2b54433a 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/DebugInfoTypes.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/DebugInfoTypes.cs @@ -51,11 +51,11 @@ public enum SourceTypes CallInstruction = 0x10 } - public enum MappingTypes : int + public enum DebugInfoBoundsType : uint { - NoMapping = -1, - Prolog = -2, - Epilog = -3, + NoMapping = 0xffffffff, + Prolog = 0xfffffffe, + Epilog = 0xfffffffd, MaxMappingValue = Epilog } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ILCompiler.Reflection.ReadyToRun.csproj b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ILCompiler.Reflection.ReadyToRun.csproj index b3f0bd30acc1b4..f07c29c417b97b 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ILCompiler.Reflection.ReadyToRun.csproj +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ILCompiler.Reflection.ReadyToRun.csproj @@ -17,8 +17,8 @@ - - + + diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs index c59f99cbd1b3c1..ee4290a80ef532 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs @@ -207,11 +207,6 @@ public class ReadyToRunMethod /// public MetadataReader MetadataReader { get; private set; } - /// - /// An unique index for the method - /// - public int Index { get; set; } - /// /// The name of the method /// @@ -288,7 +283,6 @@ public IReadOnlyList Fixups /// public ReadyToRunMethod( ReadyToRunReader readyToRunReader, - int index, MetadataReader metadataReader, EntityHandle methodHandle, int entryPointId, @@ -299,7 +293,6 @@ public ReadyToRunMethod( { _readyToRunReader = readyToRunReader; _fixupOffset = fixupOffset; - Index = index; MethodHandle = methodHandle; EntryPointRuntimeFunctionId = entryPointId; diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs index 3683fe906f9d44..2da57b2b7b538a 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs @@ -31,6 +31,7 @@ public enum OperatingSystem FreeBSD = 0xADC4, Linux = 0x7B79, NetBSD = 0x1993, + SunOS = 0x1992, Windows = 0, Unknown = -1 } @@ -72,6 +73,7 @@ public sealed class ReadyToRunReader private OperatingSystem _operatingSystem; private Machine _machine; private Architecture _architecture; + private int _pointerSize; private bool _composite; private ulong _imageBase; private int _readyToRunHeaderRVA; @@ -96,6 +98,7 @@ public sealed class ReadyToRunReader // ImportSections private List _importSections; private Dictionary _importCellNames; + private Dictionary _importSignatures; // AvailableType private Dictionary> _availableTypes; @@ -174,6 +177,18 @@ public Architecture Architecture } } + /// + /// Size of a pointer on the architecture + /// + public int TargetPointerSize + { + get + { + EnsureHeader(); + return _pointerSize; + } + } + /// /// Return true when the executable is a composite R2R image. /// @@ -295,6 +310,19 @@ public IReadOnlyDictionary ImportCellNames } + /// + /// Map from import cell addresses to their symbolic names. + /// + public IReadOnlyDictionary ImportSignatures + { + get + { + EnsureImportSections(); + return _importSignatures; + } + + } + internal Dictionary RuntimeFunctionToDebugInfo { get @@ -383,14 +411,20 @@ private unsafe void Initialize(MetadataReader metadata) { if ((PEReader.PEHeaders.CorHeader.Flags & CorFlags.ILLibrary) == 0) { - throw new BadImageFormatException("The file is not a ReadyToRun image"); + if (!TryLocateNativeReadyToRunHeader()) + throw new BadImageFormatException("The file is not a ReadyToRun image"); + + Debug.Assert(Composite); } + else + { + _assemblyCache.Add(metadata); - _assemblyCache.Add(metadata); + DirectoryEntry r2rHeaderDirectory = PEReader.PEHeaders.CorHeader.ManagedNativeHeaderDirectory; + _readyToRunHeaderRVA = r2rHeaderDirectory.RelativeVirtualAddress; + Debug.Assert(!Composite); + } - DirectoryEntry r2rHeaderDirectory = PEReader.PEHeaders.CorHeader.ManagedNativeHeaderDirectory; - _readyToRunHeaderRVA = r2rHeaderDirectory.RelativeVirtualAddress; - Debug.Assert(!Composite); } else if (!TryLocateNativeReadyToRunHeader()) { @@ -476,20 +510,24 @@ private unsafe void EnsureHeader() { case Machine.I386: _architecture = Architecture.X86; + _pointerSize = 4; break; case Machine.Amd64: _architecture = Architecture.X64; + _pointerSize = 8; break; case Machine.Arm: case Machine.Thumb: case Machine.ArmThumb2: _architecture = Architecture.Arm; + _pointerSize = 4; break; case Machine.Arm64: _architecture = Architecture.Arm64; + _pointerSize = 8; break; default: @@ -670,7 +708,7 @@ private void ParseMethodDefEntrypointsSection(ReadyToRunSection section, Metadat int runtimeFunctionId; int? fixupOffset; GetRuntimeFunctionIndexFromOffset(offset, out runtimeFunctionId, out fixupOffset); - ReadyToRunMethod method = new ReadyToRunMethod(this, _methods.Count, metadataReader, methodHandle, runtimeFunctionId, owningType: null, constrainedType: null, instanceArgs: null, fixupOffset: fixupOffset); + ReadyToRunMethod method = new ReadyToRunMethod(this, metadataReader, methodHandle, runtimeFunctionId, owningType: null, constrainedType: null, instanceArgs: null, fixupOffset: fixupOffset); if (method.EntryPointRuntimeFunctionId < 0 || method.EntryPointRuntimeFunctionId >= isEntryPoint.Length) { @@ -712,7 +750,7 @@ private void ParseInstanceMethodEntrypoints(bool[] isEntryPoint) if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_OwnerType) != 0) { mdReader = decoder.GetMetadataReaderFromModuleOverride() ?? mdReader; - if (_composite) + if ((_composite) && mdReader == null) { // The only types that don't have module overrides on them in composite images are primitive types within the system module mdReader = GetSystemModuleMetadataReader(); @@ -755,7 +793,6 @@ private void ParseInstanceMethodEntrypoints(bool[] isEntryPoint) GetRuntimeFunctionIndexFromOffset((int)decoder.Offset, out runtimeFunctionId, out fixupOffset); ReadyToRunMethod method = new ReadyToRunMethod( this, - _methods.Count, mdReader, methodHandle, runtimeFunctionId, @@ -928,6 +965,7 @@ private void EnsureImportSections() } _importSections = new List(); _importCellNames = new Dictionary(); + _importSignatures = new Dictionary(); if (!ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.ImportSections, out ReadyToRunSection importSectionsSection)) { return; @@ -980,9 +1018,11 @@ private void EnsureImportSections() long section = NativeReader.ReadInt64(Image, ref sectionOffset); uint sigRva = NativeReader.ReadUInt32(Image, ref signatureOffset); int sigOffset = GetOffset((int)sigRva); - string cellName = MetadataNameFormatter.FormatSignature(_assemblyResolver, this, sigOffset); + ReadyToRunSignature signature; + string cellName = MetadataNameFormatter.FormatSignature(_assemblyResolver, this, sigOffset, out signature); entries.Add(new ReadyToRunImportSection.ImportSectionEntry(entries.Count, entryOffset, entryOffset + rva, section, sigRva, cellName)); _importCellNames.Add(rva + entrySize * i, cellName); + _importSignatures.Add(rva + entrySize * i, signature); } int auxDataRVA = NativeReader.ReadInt32(Image, ref offset); diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs index 8da2119e58fbb3..3804ef60d4326b 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/ReadyToRunSignature.cs @@ -12,6 +12,30 @@ namespace ILCompiler.Reflection.ReadyToRun { + /// + /// This represents all possible signatures that is + /// + public class ReadyToRunSignature + { + } + + /// + /// For now, this means the signature is not parsed yet + /// + public class TodoSignature : ReadyToRunSignature + { + } + + public class MethodDefEntrySignature : ReadyToRunSignature + { + public uint MethodDefToken { get; set; } + } + + public class MethodRefEntrySignature : ReadyToRunSignature + { + public uint MethodRefToken { get; set; } + } + /// /// Helper class for converting metadata tokens into their textual representation. /// @@ -39,11 +63,11 @@ public static string FormatHandle(MetadataReader metadataReader, Handle handle, return formatter.EmitHandleName(handle, namespaceQualified, owningTypeOverride, signaturePrefix); } - public static string FormatSignature(IAssemblyResolver assemblyResolver, ReadyToRunReader r2rReader, int imageOffset) + public static string FormatSignature(IAssemblyResolver assemblyResolver, ReadyToRunReader r2rReader, int imageOffset, out ReadyToRunSignature result) { SignatureDecoder decoder = new SignatureDecoder(assemblyResolver, r2rReader.GetGlobalMetadataReader(), r2rReader, imageOffset); - string result = decoder.ReadR2RSignature(); - return result; + string answer = decoder.ReadR2RSignature(out result); + return answer; } /// @@ -518,13 +542,14 @@ public CorElementType PeekElementType() /// by custom encoding per fixup type. /// /// - public string ReadR2RSignature() + public string ReadR2RSignature(out ReadyToRunSignature result) { + result = null; StringBuilder builder = new StringBuilder(); int startOffset = _offset; try { - ParseSignature(builder); + result = ParseSignature(builder); EmitSignatureBinaryFrom(builder, startOffset); } catch (Exception ex) @@ -634,7 +659,7 @@ private void EmitSignatureBinaryFrom(StringBuilder builder, int startOffset) /// Parse the signature into a given output string builder. /// /// Output signature builder - private void ParseSignature(StringBuilder builder) + private ReadyToRunSignature ParseSignature(StringBuilder builder) { uint fixupType = ReadByte(); EmitInlineSignatureBinaryBytes(builder, 1); @@ -650,8 +675,9 @@ private void ParseSignature(StringBuilder builder) moduleDecoder = new SignatureDecoder(_options, refAsmEcmaReader, _image, _offset, refAsmEcmaReader, _contextReader); } - moduleDecoder.ParseSignature((ReadyToRunFixupKind)fixupType, builder); + ReadyToRunSignature result = moduleDecoder.ParseSignature((ReadyToRunFixupKind)fixupType, builder); _offset = moduleDecoder.Offset; + return result; } /// @@ -659,14 +685,16 @@ private void ParseSignature(StringBuilder builder) /// /// Fixup type to parse /// Output signature builder - private void ParseSignature(ReadyToRunFixupKind fixupType, StringBuilder builder) + private ReadyToRunSignature ParseSignature(ReadyToRunFixupKind fixupType, StringBuilder builder) { + ReadyToRunSignature result = new TodoSignature(); switch (fixupType) { case ReadyToRunFixupKind.ThisObjDictionaryLookup: builder.Append("THISOBJ_DICTIONARY_LOOKUP @ "); ParseType(builder); builder.Append(": "); + // It looks like ReadyToRunSignature is potentially a composite pattern ParseSignature(builder); break; @@ -702,15 +730,17 @@ private void ParseSignature(ReadyToRunFixupKind fixupType, StringBuilder builder break; case ReadyToRunFixupKind.MethodEntry_DefToken: - ParseMethodDefToken(builder, owningTypeOverride: null); + uint methodDefToken = ParseMethodDefToken(builder, owningTypeOverride: null); builder.Append(" (METHOD_ENTRY"); builder.Append(_options.Naked ? ")" : "_DEF_TOKEN)"); + result = new MethodDefEntrySignature { MethodDefToken = methodDefToken }; break; case ReadyToRunFixupKind.MethodEntry_RefToken: - ParseMethodRefToken(builder, owningTypeOverride: null); + uint methodRefToken = ParseMethodRefToken(builder, owningTypeOverride: null); builder.Append(" (METHOD_ENTRY"); builder.Append(_options.Naked ? ")" : "_REF_TOKEN)"); + result = new MethodRefEntrySignature { MethodRefToken = methodRefToken }; break; @@ -831,12 +861,44 @@ private void ParseSignature(ReadyToRunFixupKind fixupType, StringBuilder builder case ReadyToRunFixupKind.Check_TypeLayout: ParseType(builder); + ReadyToRunTypeLayoutFlags layoutFlags = (ReadyToRunTypeLayoutFlags)ReadUInt(); + builder.Append($" Flags {layoutFlags}"); + int actualSize = (int)ReadUInt(); + builder.Append($" Size {actualSize}"); + + if (layoutFlags.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_HFA)) + { + builder.Append($" HFAType {ReadUInt()}"); + } + + if (layoutFlags.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment)) + { + if (!layoutFlags.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_Alignment_Native)) + { + builder.Append($" Align {ReadUInt()}"); + } + } + + if (layoutFlags.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout)) + { + if (!layoutFlags.HasFlag(ReadyToRunTypeLayoutFlags.READYTORUN_LAYOUT_GCLayout_Empty)) + { + int cbGCRefMap = (actualSize / _contextReader.TargetPointerSize + 7) / 8; + builder.Append(" GCLayout "); + for (int i = 0; i < cbGCRefMap; i++) + { + builder.Append(ReadByte().ToString("X")); + } + } + } + builder.Append(" (CHECK_TYPE_LAYOUT)"); break; case ReadyToRunFixupKind.Check_FieldOffset: - builder.Append("CHECK_FIELD_OFFSET"); - // TODO + builder.Append($"{ReadUInt()} "); + ParseField(builder); + builder.Append(" (CHECK_FIELD_OFFSET)"); break; case ReadyToRunFixupKind.Check_InstructionSetSupport: @@ -877,6 +939,7 @@ private void ParseSignature(ReadyToRunFixupKind fixupType, StringBuilder builder builder.Append(string.Format("Unknown fixup type: {0:X2}", fixupType)); break; } + return result; } /// @@ -1203,7 +1266,7 @@ private void ParseMethod(StringBuilder builder) /// Read a methodDef token from the signature and output the corresponding object to the builder. /// /// Output string builder - private void ParseMethodDefToken(StringBuilder builder, string owningTypeOverride) + private uint ParseMethodDefToken(StringBuilder builder, string owningTypeOverride) { StringBuilder signaturePrefixBuilder = new StringBuilder(); uint methodDefToken = ReadUIntAndEmitInlineSignatureBinary(signaturePrefixBuilder) | (uint)CorTokenType.mdtMethodDef; @@ -1213,6 +1276,7 @@ private void ParseMethodDefToken(StringBuilder builder, string owningTypeOverrid namespaceQualified: true, owningTypeOverride: owningTypeOverride, signaturePrefix: signaturePrefixBuilder.ToString())); + return methodDefToken; } /// @@ -1220,7 +1284,7 @@ private void ParseMethodDefToken(StringBuilder builder, string owningTypeOverrid /// /// Output string builder /// Explicit owning type override - private void ParseMethodRefToken(StringBuilder builder, string owningTypeOverride) + private uint ParseMethodRefToken(StringBuilder builder, string owningTypeOverride) { StringBuilder signaturePrefixBuilder = new StringBuilder(); uint methodRefToken = ReadUIntAndEmitInlineSignatureBinary(signaturePrefixBuilder) | (uint)CorTokenType.mdtMemberRef; @@ -1230,6 +1294,7 @@ private void ParseMethodRefToken(StringBuilder builder, string owningTypeOverrid namespaceQualified: false, owningTypeOverride: owningTypeOverride, signaturePrefix: signaturePrefixBuilder.ToString())); + return methodRefToken; } /// @@ -1658,12 +1723,11 @@ private void ParseHelper(StringBuilder builder) /// /// Read a string token from the signature stream and convert it to the actual string. /// - /// private void ParseStringHandle(StringBuilder builder) { uint rid = ReadUIntAndEmitInlineSignatureBinary(builder); UserStringHandle stringHandle = MetadataTokens.UserStringHandle((int)rid); - builder.Append(_metadataReader.GetUserString(stringHandle)); + builder.AppendEscapedString(_metadataReader.GetUserString(stringHandle)); } } } diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/StringExtensions.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/StringExtensions.cs new file mode 100644 index 00000000000000..9cf7ca6655e7d6 --- /dev/null +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/StringExtensions.cs @@ -0,0 +1,112 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Globalization; +using System.Text; + +namespace ILCompiler.Reflection.ReadyToRun +{ + public static class StringBuilderExtensions + { + /// + /// Appends a C# string literal with the given value to the string builder. + /// + /// + /// This method closely follows the logic in + /// method in Roslyn .NET compiler; see its + /// sources for reference. + /// + public static StringBuilder AppendEscapedString(this StringBuilder builder, string value) + { + builder.Append('"'); + + for (int i = 0; i < value.Length; i++) + { + char c = value[i]; + UnicodeCategory category; + + // Fast check for printable ASCII characters + if ((c <= 0x7e) && (c >= 0x20) || !NeedsEscaping(category = CharUnicodeInfo.GetUnicodeCategory(c))) + { + if ((c == '"') || (c == '\\')) + { + builder.Append(@"\"); + } + builder.Append(c); + } + else if (category == UnicodeCategory.Surrogate) + { + // Check for a valid surrogate pair + category = CharUnicodeInfo.GetUnicodeCategory(value, i); + if (category == UnicodeCategory.Surrogate) + { + // Escape an unpaired surrogate + builder.Append(@"\u" + ((int)c).ToString("x4")); + } + else if (NeedsEscaping(category)) + { + // A surrogate pair that needs to be escaped + int codePoint = char.ConvertToUtf32(value, i); + builder.Append(@"\U" + codePoint.ToString("x8")); + i++; // Skip the already-encoded second surrogate of the pair + } + else + { + // Copy a printable surrogate pair + builder.Append(c); + builder.Append(value[++i]); + } + } + else + { + string escaped = c switch + { + '\0' => @"\0", + '\a' => @"\a", + '\b' => @"\b", + '\f' => @"\f", + '\n' => @"\n", + '\r' => @"\r", + '\t' => @"\t", + '\v' => @"\v", + _ => @"\u" + ((int)c).ToString("x4") + }; + builder.Append(escaped); + } + } + + builder.Append('"'); + return builder; + } + + /// + /// Determines whether characters of the given will be represented with escape sequences. + /// + private static bool NeedsEscaping(UnicodeCategory category) + { + switch (category) + { + case UnicodeCategory.LineSeparator: + case UnicodeCategory.ParagraphSeparator: + case UnicodeCategory.Control: + case UnicodeCategory.Surrogate: + case UnicodeCategory.OtherNotAssigned: + return true; + default: + return false; + } + } + } + + public static class StringExtensions + { + /// + /// Returns a C# string literal with the given value. + /// + public static string ToEscapedString(this string value) + { + return new StringBuilder(value.Length + 16).AppendEscapedString(value).ToString(); + } + } +} diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/TransitionBlock.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/TransitionBlock.cs index 6cebfa78494b7c..5cfef643b90e69 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/TransitionBlock.cs +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.Reflection.ReadyToRun/TransitionBlock.cs @@ -49,15 +49,18 @@ public static TransitionBlock FromReader(ReadyToRunReader reader) public abstract int OffsetOfArgumentRegisters { get; } + /// + /// The offset of the first slot in a GC ref map. Overridden on ARM64 to return the offset of the X8 register. + /// + public virtual int OffsetOfFirstGCRefMapSlot => OffsetOfArgumentRegisters; + /// /// Recalculate pos in GC ref map to actual offset. This is the default implementation for all architectures /// except for X86 where it's overridden to supply a more complex algorithm. /// - /// - /// public virtual int OffsetFromGCRefMapPos(int pos) { - return OffsetOfArgumentRegisters + pos * PointerSize; + return OffsetOfFirstGCRefMapSlot + pos * PointerSize; } /// @@ -144,8 +147,8 @@ private sealed class Arm64TransitionBlock : TransitionBlock // Callee-saves, padding, m_x8RetBuffReg, argument registers public override int SizeOfTransitionBlock => SizeOfCalleeSavedRegisters + 2 * PointerSize + SizeOfArgumentRegisters; public override int OffsetOfArgumentRegisters => SizeOfCalleeSavedRegisters + 2 * PointerSize; + private int OffsetOfX8Register => OffsetOfArgumentRegisters - PointerSize; + public override int OffsetOfFirstGCRefMapSlot => OffsetOfX8Register; } } - } - diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj b/src/coreclr/src/tools/crossgen2/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj index 1b4b6f9cd9348d..15af6af32d3341 100644 --- a/src/coreclr/src/tools/crossgen2/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj +++ b/src/coreclr/src/tools/crossgen2/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj @@ -14,16 +14,17 @@ the same bits tests expect to see in artifacts/crossgen2. That way we never need to wonder which binaries are up to date and which are stale. --> false + Debug;Release;Checked 4.3.0 - 1.6.0 + 1.8.1 - 1.0.8 + 1.3.0 @@ -150,6 +151,12 @@ Utilities\CustomAttributeTypeNameParser.cs + + Utilities\GCPointerMap.Algorithm.cs + + + Utilities\GCPointerMap.cs + Utilities\DebugNameFormatter.cs diff --git a/src/coreclr/src/tools/crossgen2/crossgen2.sln b/src/coreclr/src/tools/crossgen2/crossgen2.sln index d5ab286dfddddc..a22da16873e6c2 100644 --- a/src/coreclr/src/tools/crossgen2/crossgen2.sln +++ b/src/coreclr/src/tools/crossgen2/crossgen2.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29123.88 @@ -13,12 +12,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILCompiler.TypeSystem.Ready EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Checked|x64 = Checked|x64 + Checked|x86 = Checked|x86 Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9B928D3E-06AB-45E5-BF79-F374F0AE3B98}.Checked|x64.ActiveCfg = Checked|x64 + {9B928D3E-06AB-45E5-BF79-F374F0AE3B98}.Checked|x64.Build.0 = Checked|x64 + {9B928D3E-06AB-45E5-BF79-F374F0AE3B98}.Checked|x86.ActiveCfg = Checked|x86 + {9B928D3E-06AB-45E5-BF79-F374F0AE3B98}.Checked|x86.Build.0 = Checked|x86 {9B928D3E-06AB-45E5-BF79-F374F0AE3B98}.Debug|x64.ActiveCfg = Debug|x64 {9B928D3E-06AB-45E5-BF79-F374F0AE3B98}.Debug|x64.Build.0 = Debug|x64 {9B928D3E-06AB-45E5-BF79-F374F0AE3B98}.Debug|x86.ActiveCfg = Debug|x86 @@ -27,6 +32,10 @@ Global {9B928D3E-06AB-45E5-BF79-F374F0AE3B98}.Release|x64.Build.0 = Release|x64 {9B928D3E-06AB-45E5-BF79-F374F0AE3B98}.Release|x86.ActiveCfg = Release|x86 {9B928D3E-06AB-45E5-BF79-F374F0AE3B98}.Release|x86.Build.0 = Release|x86 + {FB2D45F2-FA4C-42B2-8E53-3E1F30CF8046}.Checked|x64.ActiveCfg = Checked|x64 + {FB2D45F2-FA4C-42B2-8E53-3E1F30CF8046}.Checked|x64.Build.0 = Checked|x64 + {FB2D45F2-FA4C-42B2-8E53-3E1F30CF8046}.Checked|x86.ActiveCfg = Checked|x86 + {FB2D45F2-FA4C-42B2-8E53-3E1F30CF8046}.Checked|x86.Build.0 = Checked|x86 {FB2D45F2-FA4C-42B2-8E53-3E1F30CF8046}.Debug|x64.ActiveCfg = Debug|x64 {FB2D45F2-FA4C-42B2-8E53-3E1F30CF8046}.Debug|x64.Build.0 = Debug|x64 {FB2D45F2-FA4C-42B2-8E53-3E1F30CF8046}.Debug|x86.ActiveCfg = Debug|x86 @@ -35,6 +44,10 @@ Global {FB2D45F2-FA4C-42B2-8E53-3E1F30CF8046}.Release|x64.Build.0 = Release|x64 {FB2D45F2-FA4C-42B2-8E53-3E1F30CF8046}.Release|x86.ActiveCfg = Release|x86 {FB2D45F2-FA4C-42B2-8E53-3E1F30CF8046}.Release|x86.Build.0 = Release|x86 + {83A832DE-BF4A-44C4-B361-90F5F88B979B}.Checked|x64.ActiveCfg = Checked|x64 + {83A832DE-BF4A-44C4-B361-90F5F88B979B}.Checked|x64.Build.0 = Checked|x64 + {83A832DE-BF4A-44C4-B361-90F5F88B979B}.Checked|x86.ActiveCfg = Checked|x86 + {83A832DE-BF4A-44C4-B361-90F5F88B979B}.Checked|x86.Build.0 = Checked|x86 {83A832DE-BF4A-44C4-B361-90F5F88B979B}.Debug|x64.ActiveCfg = Debug|x64 {83A832DE-BF4A-44C4-B361-90F5F88B979B}.Debug|x64.Build.0 = Debug|x64 {83A832DE-BF4A-44C4-B361-90F5F88B979B}.Debug|x86.ActiveCfg = Debug|x86 @@ -43,6 +56,10 @@ Global {83A832DE-BF4A-44C4-B361-90F5F88B979B}.Release|x64.Build.0 = Release|x64 {83A832DE-BF4A-44C4-B361-90F5F88B979B}.Release|x86.ActiveCfg = Release|x86 {83A832DE-BF4A-44C4-B361-90F5F88B979B}.Release|x86.Build.0 = Release|x86 + {751583CD-E880-49E1-B3E2-8B1990114CAC}.Checked|x64.ActiveCfg = Checked|x64 + {751583CD-E880-49E1-B3E2-8B1990114CAC}.Checked|x64.Build.0 = Checked|x64 + {751583CD-E880-49E1-B3E2-8B1990114CAC}.Checked|x86.ActiveCfg = Checked|x86 + {751583CD-E880-49E1-B3E2-8B1990114CAC}.Checked|x86.Build.0 = Checked|x86 {751583CD-E880-49E1-B3E2-8B1990114CAC}.Debug|x64.ActiveCfg = Debug|x64 {751583CD-E880-49E1-B3E2-8B1990114CAC}.Debug|x64.Build.0 = Debug|x64 {751583CD-E880-49E1-B3E2-8B1990114CAC}.Debug|x86.ActiveCfg = Debug|x86 diff --git a/src/coreclr/src/tools/crossgen2/crossgen2/CommandLineOptions.cs b/src/coreclr/src/tools/crossgen2/crossgen2/CommandLineOptions.cs index 4fa9271d1c20cc..534bec5b6970f9 100644 --- a/src/coreclr/src/tools/crossgen2/crossgen2/CommandLineOptions.cs +++ b/src/coreclr/src/tools/crossgen2/crossgen2/CommandLineOptions.cs @@ -23,6 +23,7 @@ public class CommandLineOptions public bool CompileBubbleGenerics { get; set; } public bool Verbose { get; set; } public bool Composite { get; set; } + public bool CompileNoMethods { get; set; } public FileInfo DgmlLogFileName { get; set; } public bool GenerateFullDgmlLog { get; set; } @@ -100,6 +101,7 @@ public static Command RootCommand() new Option(new[] { "--optimize-time", "--Ot" }, SR.OptimizeSpeedOption), new Option(new[] { "--inputbubble" }, SR.InputBubbleOption), new Option(new[] { "--composite" }, SR.CompositeBuildMode), + new Option(new[] { "--compile-no-methods" }, SR.CompileNoMethodsOption), new Option(new[] { "--tuning" }, SR.TuningImageOption) { Argument = new Argument() diff --git a/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs b/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs index d6f98eb7d905b7..3b52671fc66412 100644 --- a/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs +++ b/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs @@ -400,6 +400,16 @@ private int Run() singleMethod); compilationRoots.Add(new SingleMethodRootProvider(singleMethod)); } + else if (_commandLineOptions.CompileNoMethods) + { + compilationGroup = new NoMethodsCompilationModuleGroup( + typeSystemContext, + _commandLineOptions.Composite, + _commandLineOptions.InputBubble, + inputModules, + versionBubbleModules, + _commandLineOptions.CompileBubbleGenerics); + } else { // Single assembly compilation. @@ -428,9 +438,9 @@ private int Run() else compilationGroup.ApplyProfilerGuidedCompilationRestriction(null); - if (singleMethod == null) + if ((singleMethod == null) && !_commandLineOptions.CompileNoMethods) { - // For non-single-method compilations add compilation roots. + // For normal compilations add compilation roots. foreach (var module in rootingModules) { compilationRoots.Add(new ReadyToRunRootProvider( @@ -466,6 +476,7 @@ private int Run() .UseParallelism(_commandLineOptions.Parallelism) .UseJitPath(_commandLineOptions.JitPath) .UseInstructionSetSupport(instructionSetSupport) + .GenerateOutputFile(_commandLineOptions.OutputFilePath.FullName) .UseILProvider(ilProvider) .UseBackendOptions(_commandLineOptions.CodegenOptions) .UseLogger(logger) diff --git a/src/coreclr/src/tools/crossgen2/crossgen2/Properties/Resources.resx b/src/coreclr/src/tools/crossgen2/crossgen2/Properties/Resources.resx index f809bfa1a8879b..3bd33829741079 100644 --- a/src/coreclr/src/tools/crossgen2/crossgen2/Properties/Resources.resx +++ b/src/coreclr/src/tools/crossgen2/crossgen2/Properties/Resources.resx @@ -138,6 +138,9 @@ True when the entire input forms a version bubble (default = per-assembly bubble) + + True to skip compiling methods into the R2R image (default = false) + Emit a composite R2R image comprising a number of input assemblies diff --git a/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj b/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj index fa2fc646d57b97..b3c21b883c576c 100644 --- a/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj +++ b/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj @@ -4,7 +4,6 @@ true Exe $(NetCoreAppCurrent) - netcoreapp3.0 8002,NU1701 x64;x86 AnyCPU @@ -14,6 +13,7 @@ true false linux-x64;linux-musl-x64;win-x64 + Debug;Release;Checked @@ -35,8 +35,8 @@ - - 0.3.0-alpha.19577.1 + + $(SystemCommandLineVersion) diff --git a/src/coreclr/src/tools/crossgen2/jitinterface/jitinterface.h b/src/coreclr/src/tools/crossgen2/jitinterface/jitinterface.h index 690c3e5a4cd6bc..88144e0bb8455f 100644 --- a/src/coreclr/src/tools/crossgen2/jitinterface/jitinterface.h +++ b/src/coreclr/src/tools/crossgen2/jitinterface/jitinterface.h @@ -161,7 +161,7 @@ struct JitInterfaceCallbacks void (* addActiveDependency)(void * thisHandle, CorInfoException** ppException, void* moduleFrom, void* moduleTo); void* (* GetDelegateCtor)(void * thisHandle, CorInfoException** ppException, void* methHnd, void* clsHnd, void* targetMethodHnd, void* pCtorData); void (* MethodCompileComplete)(void * thisHandle, CorInfoException** ppException, void* methHnd); - void* (* getTailCallCopyArgsThunk)(void * thisHandle, CorInfoException** ppException, void* pSig, int flags); + bool (* getTailCallHelpers)(void * thisHandle, CorInfoException** ppException, void* callToken, void* sig, int flags, void* pResult); bool (* convertPInvokeCalliToCall)(void * thisHandle, CorInfoException** ppException, void* pResolvedToken, bool mustConvert); void (* notifyInstructionSetUsage)(void * thisHandle, CorInfoException** ppException, int instructionSet, bool supportEnabled); void (* allocMem)(void * thisHandle, CorInfoException** ppException, unsigned int hotCodeSize, unsigned int coldCodeSize, unsigned int roDataSize, unsigned int xcptnsCount, int flag, void** hotCodeBlock, void** coldCodeBlock, void** roDataBlock); @@ -1493,10 +1493,10 @@ class JitInterfaceWrapper throw pException; } - virtual void* getTailCallCopyArgsThunk(void* pSig, int flags) + virtual bool getTailCallHelpers(void* callToken, void* sig, int flags, void* pResult) { CorInfoException* pException = nullptr; - void* _ret = _callbacks->getTailCallCopyArgsThunk(_thisHandle, &pException, pSig, flags); + bool _ret = _callbacks->getTailCallHelpers(_thisHandle, &pException, callToken, sig, flags, pResult); if (pException != nullptr) throw pException; return _ret; diff --git a/src/coreclr/src/tools/crossgen2/jitinterface/jitwrapper.cpp b/src/coreclr/src/tools/crossgen2/jitinterface/jitwrapper.cpp index 5f388248f8c111..63fa69eda34f43 100644 --- a/src/coreclr/src/tools/crossgen2/jitinterface/jitwrapper.cpp +++ b/src/coreclr/src/tools/crossgen2/jitinterface/jitwrapper.cpp @@ -27,11 +27,11 @@ class CORJIT_FLAGS uint64_t corJitFlags; }; -static const GUID JITEEVersionIdentifier = { /* 6ae798bf-44bd-4e8a-b8fc-dbe1d1f4029e */ - 0x6ae798bf, - 0x44bd, - 0x4e8a, - {0xb8, 0xfc, 0xdb, 0xe1, 0xd1, 0xf4, 0x02, 0x9e} +static const GUID JITEEVersionIdentifier = { /* 8b2226a2-ac30-4f5c-ae5c-926c792ecdb9 */ + 0x8b2226a2, + 0xac30, + 0x4f5c, + { 0xae, 0x5c, 0x92, 0x6c, 0x79, 0x2e, 0xcd, 0xb9 } }; class Jit @@ -49,7 +49,7 @@ class Jit // The EE asks the JIT for a "version identifier". This represents the version of the JIT/EE interface. // If the JIT doesn't implement the same JIT/EE interface expected by the EE (because the JIT doesn't // return the version identifier that the EE expects), then the EE fails to load the JIT. - // + // virtual void getVersionIdentifier(GUID* versionIdentifier) = 0; // When the EE loads the System.Numerics.Vectors assembly, it asks the JIT what length (in bytes) of @@ -60,8 +60,8 @@ class Jit DLL_EXPORT int JitCompileMethod( CorInfoException **ppException, - Jit * pJit, - void * thisHandle, + Jit * pJit, + void * thisHandle, void ** callbacks, void* methodInfo, unsigned flags, diff --git a/src/coreclr/src/tools/dotnet-pgo/dotnet-pgo.csproj b/src/coreclr/src/tools/dotnet-pgo/dotnet-pgo.csproj index 4563e17b494a9d..aa2f8968c42001 100644 --- a/src/coreclr/src/tools/dotnet-pgo/dotnet-pgo.csproj +++ b/src/coreclr/src/tools/dotnet-pgo/dotnet-pgo.csproj @@ -1,10 +1,9 @@ - + dotnet-pgo Exe $(NetCoreAppCurrent) - netcoreapp3.0 true 8.0 $(BinDir)/dotnet-pgo @@ -15,8 +14,8 @@ - - - + + + diff --git a/src/coreclr/src/tools/metainfo/metainfo.cpp b/src/coreclr/src/tools/metainfo/metainfo.cpp index cfe5e0b7fed6dd..f73de31371f3f4 100644 --- a/src/coreclr/src/tools/metainfo/metainfo.cpp +++ b/src/coreclr/src/tools/metainfo/metainfo.cpp @@ -7,7 +7,6 @@ #include #include #include "mdinfo.h" -#include // Global variables bool g_bSchema = false; @@ -26,7 +25,7 @@ void DisplayArchive(__in_z __in WCHAR* szFile, ULONG DumpFilter, __in_z __in_opt void PrintLogo() { - printf("Microsoft (R) .NET Frameworks Runtime Meta Data Dump Utility Version %s\n", VER_FILEVERSION_STR); + printf("Microsoft (R) .NET Runtime Meta Data Dump Utility Version %s\n", CLR_PRODUCT_VERSION); printf("%S", VER_LEGALCOPYRIGHT_LOGO_STR_L); printf("\n"); }// PrintLogo diff --git a/src/coreclr/src/tools/r2rdump/CommandLineOptions.cs b/src/coreclr/src/tools/r2rdump/CommandLineOptions.cs index 5ddfd1dbeb6b35..6b3f53aa6ce35d 100644 --- a/src/coreclr/src/tools/r2rdump/CommandLineOptions.cs +++ b/src/coreclr/src/tools/r2rdump/CommandLineOptions.cs @@ -12,30 +12,32 @@ internal static class CommandLineOptions public static RootCommand RootCommand() { RootCommand command = new RootCommand(); - command.AddOption(new Option(new[] { "--in", "-i" }, "Input file(s) to dump. Expects them to by ReadyToRun images", new Argument())); - command.AddOption(new Option(new[] { "--out", "-o" }, "Output file path. Dumps everything to the specified file except for help message and exception messages", new Argument())); - command.AddOption(new Option(new[] { "--raw" }, "Dump the raw bytes of each section or runtime function", new Argument())); - command.AddOption(new Option(new[] { "--header" }, "Dump R2R header", new Argument())); - command.AddOption(new Option(new[] { "--disasm", "-d" }, "Show disassembly of methods or runtime functions", new Argument())); - command.AddOption(new Option(new[] { "--naked" }, "Naked dump suppresses most compilation details like placement addresses", new Argument())); - command.AddOption(new Option(new[] { "--hide-offsets", "--ho" }, "Hide offsets in naked disassembly", new Argument())); - command.AddOption(new Option(new[] { "--query", "-q" }, "Query method by exact name, signature, row ID or token", new Argument())); - command.AddOption(new Option(new[] { "--keyword", "-k" }, "Search method by keyword", new Argument())); - command.AddOption(new Option(new[] { "--runtimefunction", "-f" }, "Get one runtime function by id or relative virtual address", new Argument())); - command.AddOption(new Option(new[] { "--section", "-s" }, "Get section by keyword", new Argument())); - command.AddOption(new Option(new[] { "--unwind" }, "Dump unwindInfo", new Argument())); - command.AddOption(new Option(new[] { "--gc" }, "Dump gcInfo and slot table", new Argument())); - command.AddOption(new Option(new[] { "--sectionContents", "--sc" }, "Dump section contents", new Argument())); - command.AddOption(new Option(new[] { "--entrypoints", "-e" }, "Dump list of method / instance entrypoints in the R2R file", new Argument())); - command.AddOption(new Option(new[] { "--normalize", "-n" }, "Normalize dump by sorting the various tables and methods (default = unsorted i.e. file order)", new Argument())); - command.AddOption(new Option(new[] { "--hide-transitions", "--ht" }, "Don't include GC transitions in disassembly output", new Argument())); - command.AddOption(new Option(new[] { "--verbose", "-v" }, "Dump disassembly, unwindInfo, gcInfo and sectionContents", new Argument())); - command.AddOption(new Option(new[] { "--diff" }, "Compare two R2R images", new Argument())); - command.AddOption(new Option(new[] { "--diff-hide-same-disasm" }, "In matching method diff dump, hide functions with identical disassembly", new Argument())); - command.AddOption(new Option(new[] { "--reference", "-r" }, "Explicit reference assembly files", new Argument())); - command.AddOption(new Option(new[] { "--referencePath", "--rp" }, "Search paths for reference assemblies", new Argument())); - command.AddOption(new Option(new[] { "--inlineSignatureBinary", "--isb" }, "Embed binary signature into its textual representation", new Argument())); - command.AddOption(new Option(new[] { "--signatureBinary", "--sb" }, "Append signature binary to its textual representation", new Argument())); + command.AddOption(new Option(new[] { "--in", "-i" }, "Input file(s) to dump. Expects them to by ReadyToRun images")); + command.AddOption(new Option(new[] { "--out", "-o" }, "Output file path. Dumps everything to the specified file except for help message and exception messages")); + command.AddOption(new Option(new[] { "--raw" }, "Dump the raw bytes of each section or runtime function")); + command.AddOption(new Option(new[] { "--header" }, "Dump R2R header")); + command.AddOption(new Option(new[] { "--disasm", "-d" }, "Show disassembly of methods or runtime functions")); + command.AddOption(new Option(new[] { "--naked" }, "Naked dump suppresses most compilation details like placement addresses")); + command.AddOption(new Option(new[] { "--hide-offsets", "--ho" }, "Hide offsets in naked disassembly")); + command.AddOption(new Option(new[] { "--query", "-q" }, "Query method by exact name, signature, row ID or token")); + command.AddOption(new Option(new[] { "--keyword", "-k" }, "Search method by keyword")); + command.AddOption(new Option(new[] { "--runtimefunction", "-f" }, "Get one runtime function by id or relative virtual address")); + command.AddOption(new Option(new[] { "--section", "-s" }, "Get section by keyword")); + command.AddOption(new Option(new[] { "--unwind" }, "Dump unwindInfo")); + command.AddOption(new Option(new[] { "--gc" }, "Dump gcInfo and slot table")); + command.AddOption(new Option(new[] { "--sectionContents", "--sc" }, "Dump section contents")); + command.AddOption(new Option(new[] { "--entrypoints", "-e" }, "Dump list of method / instance entrypoints in the R2R file")); + command.AddOption(new Option(new[] { "--normalize", "-n" }, "Normalize dump by sorting the various tables and methods (default = unsorted i.e. file order)")); + command.AddOption(new Option(new[] { "--hide-transitions", "--ht" }, "Don't include GC transitions in disassembly output")); + command.AddOption(new Option(new[] { "--verbose", "-v" }, "Dump disassembly, unwindInfo, gcInfo and sectionContents")); + command.AddOption(new Option(new[] { "--diff" }, "Compare two R2R images")); + command.AddOption(new Option(new[] { "--diff-hide-same-disasm" }, "In matching method diff dump, hide functions with identical disassembly")); + command.AddOption(new Option(new[] { "--reference", "-r" }, "Explicit reference assembly files")); + command.AddOption(new Option(new[] { "--referencePath", "--rp" }, "Search paths for reference assemblies")); + command.AddOption(new Option(new[] { "--inlineSignatureBinary", "--isb" }, "Embed binary signature into its textual representation")); + command.AddOption(new Option(new[] { "--signatureBinary", "--sb" }, "Append signature binary to its textual representation")); + command.AddOption(new Option(new[] { "--create-pdb" }, "Create PDB")); + command.AddOption(new Option(new[] { "--pdb-path" }, "PDB output path for --createpdb")); return command; } } diff --git a/src/coreclr/src/tools/r2rdump/CoreDisTools.cs b/src/coreclr/src/tools/r2rdump/CoreDisTools.cs index bbaf801ad3cb64..1f41eab41af668 100644 --- a/src/coreclr/src/tools/r2rdump/CoreDisTools.cs +++ b/src/coreclr/src/tools/r2rdump/CoreDisTools.cs @@ -45,7 +45,7 @@ public enum TargetArch public unsafe static int GetInstruction(IntPtr Disasm, RuntimeFunction rtf, int imageOffset, int rtfOffset, byte[] image, out string instr) { - int instrSize = 1; + int instrSize; fixed (byte* p = image) { IntPtr ptr = (IntPtr)(p + imageOffset + rtfOffset); @@ -58,7 +58,7 @@ public unsafe static int GetInstruction(IntPtr Disasm, RuntimeFunction rtf, int public static IntPtr GetDisasm(Machine machine) { - TargetArch target = TargetArch.Target_Host; + TargetArch target; switch (machine) { case Machine.Amd64: @@ -86,6 +86,16 @@ public static IntPtr GetDisasm(Machine machine) /// public class Disassembler : IDisposable { + /// + /// Indentation of instruction mnemonics in naked mode with no offsets. + /// + private const int NakedNoOffsetIndentation = 4; + + /// + /// Indentation of instruction mnemonics in naked mode with offsets. + /// + private const int NakedWithOffsetIndentation = 11; + /// /// R2R reader is used to access architecture info, the PE image data and symbol table. /// @@ -101,6 +111,16 @@ public class Disassembler : IDisposable /// private readonly IntPtr _disasm; + /// + /// Indentation of instruction mnemonics. + /// + public int MnemonicIndentation { get; private set; } + + /// + /// Indentation of instruction mnemonics. + /// + public int OperandsIndentation { get; private set; } + /// /// Store the R2R reader and construct the disassembler for the appropriate architecture. /// @@ -110,6 +130,7 @@ public Disassembler(ReadyToRunReader reader, DumpOptions options) _reader = reader; _options = options; _disasm = CoreDisTools.GetDisasm(_reader.Machine); + SetIndentations(); } /// @@ -124,7 +145,52 @@ public void Dispose() } /// - /// Parse a single instruction and return the RVA of the next instruction. + /// Set indentations for mnemonics and operands. + /// + private void SetIndentations() + { + if (_options.Naked) + { + MnemonicIndentation = _options.HideOffsets ? NakedNoOffsetIndentation : NakedWithOffsetIndentation; + } + else + { + // The length of the byte dump starting with the first hexadecimal digit and ending with the final space + int byteDumpLength = _reader.Machine switch + { + // Most instructions are no longer than 7 bytes. CorDisasm::dumpInstruction always pads byte dumps + // to 7 * 3 characters; see https://github.com/dotnet/llilc/blob/master/lib/CoreDisTools/coredistools.cpp. + Machine.I386 => 7 * 3, + Machine.Amd64 => 7 * 3, + + // Instructions are either 2 or 4 bytes long + Machine.ArmThumb2 => 4 * 3, + + // Instructions are dumped as 4-byte hexadecimal integers + Machine.Arm64 => 4 * 2 + 1, + + _ => throw new NotImplementedException() + }; + + MnemonicIndentation = NakedWithOffsetIndentation + byteDumpLength; + } + + // This leaves 7 characters for the mnemonic + OperandsIndentation = MnemonicIndentation + 8; + } + + /// + /// Append spaces to the string builder to achieve at least the given indentation. + /// + private static void EnsureIndentation(StringBuilder builder, int lineStartIndex, int desiredIndentation) + { + int currentIndentation = builder.Length - lineStartIndex; + int spacesToAppend = Math.Max(desiredIndentation - currentIndentation, 1); + builder.Append(' ', spacesToAppend); + } + + /// + /// Parse and dump a single instruction and return its size in bytes. /// /// Runtime function to parse /// Offset within the PE image byte array @@ -142,47 +208,108 @@ public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, o int instrSize = CoreDisTools.GetInstruction(_disasm, rtf, imageOffset, rtfOffset, _reader.Image, out instruction); CoreDisTools.ClearOutputBuffer(); - instruction = instruction.Replace('\t', ' '); + // CoreDisTools dumps instructions in the following format: + // + // address: bytes [padding] \t mnemonic [\t operands] \n + // + // However, due to an LLVM issue regarding instruction prefixes (https://bugs.llvm.org/show_bug.cgi?id=7709), + // multiple lines may be returned for a single x86/x64 instruction. - if (_options.Naked) + var builder = new StringBuilder(); + int lineNum = 0; + // The start index of the last line in builder + int lineStartIndex = 0; + + // Remove this foreach wrapper and line* variables after the aforementioned LLVM issue is fixed + foreach (string line in instruction.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)) { - StringBuilder nakedInstruction = new StringBuilder(); - foreach (string line in instruction.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)) + int colonIndex = line.IndexOf(':'); + int tab1Index = line.IndexOf('\t'); + + if ((0 < colonIndex) && (colonIndex < tab1Index)) { - int colon = line.IndexOf(':'); - if (colon >= 0) + // First handle the address and the byte dump + if (_options.Naked) { - colon += 2; - while (colon + 3 <= line.Length && - IsXDigit(line[colon]) && - IsXDigit(line[colon + 1]) && - line[colon + 2] == ' ') + if (!_options.HideOffsets) { - colon += 3; + // All lines but the last one must represent single-byte prefixes, so add lineNum to the offset + builder.Append($"{rtf.CodeOffset + rtfOffset + lineNum,8:x4}:"); } - - if (!_options.HideOffsets) + } + else + { + if (_reader.Machine == Machine.Arm64) { - nakedInstruction.Append($"{(rtfOffset + rtf.CodeOffset),8:x4}:"); - nakedInstruction.Append(" "); + // Replace " hh hh hh hh " byte dump with " hhhhhhhh ". + // CoreDisTools should be fixed to dump bytes this way for ARM64. + uint instructionBytes = BitConverter.ToUInt32(_reader.Image, imageOffset + rtfOffset); + builder.Append(line, 0, colonIndex + 1); + builder.Append(' '); + builder.Append(instructionBytes.ToString("x8")); } else { - nakedInstruction.Append(" "); + // Copy the offset and the byte dump + int byteDumpEndIndex = tab1Index; + do + { + byteDumpEndIndex--; + } + while (line[byteDumpEndIndex] == ' '); + builder.Append(line, 0, byteDumpEndIndex + 1); + } + builder.Append(' '); + } + + // Now handle the mnemonic and operands. Ensure proper indentation for the mnemonic. + EnsureIndentation(builder, lineStartIndex, MnemonicIndentation); + + int tab2Index = line.IndexOf('\t', tab1Index + 1); + if (tab2Index >= 0) + { + // Copy everything between the first and the second tabs + builder.Append(line, tab1Index + 1, tab2Index - tab1Index - 1); + // Ensure proper indentation for the operands + EnsureIndentation(builder, lineStartIndex, OperandsIndentation); + int afterTab2Index = tab2Index + 1; + + // Work around an LLVM issue causing an extra space to be output before operands; + // see https://reviews.llvm.org/D35946. + if ((afterTab2Index < line.Length) && + ((line[afterTab2Index] == ' ') || (line[afterTab2Index] == '\t'))) + { + afterTab2Index++; + } + + // Copy everything after the second tab + int savedLength = builder.Length; + builder.Append(line, afterTab2Index, line.Length - afterTab2Index); + // There should be no extra tabs. Should we encounter them, replace them with a single space. + if (line.IndexOf('\t', afterTab2Index) >= 0) + { + builder.Replace('\t', ' ', savedLength, builder.Length - savedLength); } - nakedInstruction.Append(line.Substring(colon).TrimStart()); - nakedInstruction.Append('\n'); } else { - nakedInstruction.Append(' ', 7); - nakedInstruction.Append(line.TrimStart()); - nakedInstruction.Append('\n'); + // Copy everything after the first tab + builder.Append(line, tab1Index + 1, line.Length - tab1Index - 1); } } - instruction = nakedInstruction.ToString(); + else + { + // Should not happen. Just replace tabs with spaces. + builder.Append(line.Replace('\t', ' ')); + } + + builder.Append('\n'); + lineNum++; + lineStartIndex = builder.Length; } + instruction = builder.ToString(); + switch (_reader.Machine) { case Machine.Amd64: @@ -194,7 +321,6 @@ public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, o break; case Machine.ArmThumb2: - case Machine.Thumb: break; case Machine.Arm64: @@ -208,11 +334,6 @@ public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, o return instrSize; } - private static bool IsXDigit(char c) - { - return Char.IsDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); - } - const string RelIPTag = "[rip "; /// diff --git a/src/coreclr/src/tools/r2rdump/Extensions.cs b/src/coreclr/src/tools/r2rdump/Extensions.cs index 911f7dd9f697b4..873435977d2dc0 100644 --- a/src/coreclr/src/tools/r2rdump/Extensions.cs +++ b/src/coreclr/src/tools/r2rdump/Extensions.cs @@ -28,9 +28,23 @@ public static void WriteTo(this DebugInfo theThis, TextWriter writer, DumpOption { writer.Write($"Native Offset: 0x{theThis.BoundsList[i].NativeOffset:X}, "); } - writer.WriteLine($"IL Offset: 0x{theThis.BoundsList[i].ILOffset:X}, Source Types: {theThis.BoundsList[i].SourceTypes}"); + if (theThis.BoundsList[i].ILOffset == (uint)DebugInfoBoundsType.NoMapping) + { + writer.WriteLine($"NoMapping, Source Types: {theThis.BoundsList[i].SourceTypes}"); + } + else if (theThis.BoundsList[i].ILOffset == (uint)DebugInfoBoundsType.Prolog) + { + writer.WriteLine($"Prolog, Source Types: {theThis.BoundsList[i].SourceTypes}"); + } + else if (theThis.BoundsList[i].ILOffset == (uint)DebugInfoBoundsType.Epilog) + { + writer.WriteLine($"Epilog, Source Types: {theThis.BoundsList[i].SourceTypes}"); + } + else + { + writer.WriteLine($"IL Offset: 0x{theThis.BoundsList[i].ILOffset:x4}, Source Types: {theThis.BoundsList[i].SourceTypes}"); + } } - writer.WriteLine(""); if (dumpOptions.Normalize) diff --git a/src/coreclr/src/tools/r2rdump/ISymNGenWriter.cs b/src/coreclr/src/tools/r2rdump/ISymNGenWriter.cs new file mode 100644 index 00000000000000..8a4eb8074fb6f1 --- /dev/null +++ b/src/coreclr/src/tools/r2rdump/ISymNGenWriter.cs @@ -0,0 +1,85 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma warning disable 436 // SuppressUnmanagedCodeSecurityAttribute defined in source and mscorlib + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; + +namespace Microsoft.DiaSymReader +{ + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("D682FD12-43dE-411C-811B-BE8404CEA126"), SuppressUnmanagedCodeSecurity] + internal interface ISymNGenWriter + { + // Add a new public symbol to the NGEN PDB. + void AddSymbol([MarshalAs(UnmanagedType.BStr)] string pSymbol, + ushort iSection, + ulong rva); + + // Adds a new section to the NGEN PDB. + void AddSection(ushort iSection, + OMF flags, + int offset, + int cb); + } + + [Flags] + internal enum OMF : ushort + { + Const_Read = 0x0001, + Const_Write = 0x0002, + Const_Exec = 0x0004, + Const_F32Bit = 0x0008, + Const_ReservedBits1 = 0x00f0, + Const_FSel = 0x0100, + Const_FAbs = 0x0200, + Const_ReservedBits2 = 0x0C00, + Const_FGroup = 0x1000, + Const_ReservedBits3 = 0xE000, + + + StandardText = (Const_FSel|Const_F32Bit|Const_Exec|Const_Read), // 0x10D + SentinelType = (Const_FAbs|Const_F32Bit) // 0x208 + } + + + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("B029E51B-4C55-4fe2-B993-9F7BC1F10DB4"), SuppressUnmanagedCodeSecurity] + internal interface ISymNGenWriter2 : ISymNGenWriter + { + // Add a new public symbol to the NGEN PDB. + new void AddSymbol([MarshalAs(UnmanagedType.BStr)] string pSymbol, + ushort iSection, + ulong rva); + + // Adds a new section to the NGEN PDB. + new void AddSection(ushort iSection, + OMF flags, + int offset, + int cb); + + void OpenModW([MarshalAs(UnmanagedType.LPWStr)] string wszModule, + [MarshalAs(UnmanagedType.LPWStr)] string wszObjFile, + out UIntPtr ppmod); + + void CloseMod(UIntPtr pmod); + + void ModAddSymbols(UIntPtr pmod, [MarshalAs(UnmanagedType.LPArray)] byte[] pbSym, int cb); + + void ModAddSecContribEx( + UIntPtr pmod, + ushort isect, + int off, + int cb, + uint dwCharacteristics, + uint dwDataCrc, + uint dwRelocCrc); + + void QueryPDBNameExW( + [MarshalAs(UnmanagedType.LPWStr)] StringBuilder pdb, + IntPtr cchMax); + } +} diff --git a/src/coreclr/src/tools/r2rdump/PdbWriter.cs b/src/coreclr/src/tools/r2rdump/PdbWriter.cs new file mode 100644 index 00000000000000..bbf6c5f1f1cbef --- /dev/null +++ b/src/coreclr/src/tools/r2rdump/PdbWriter.cs @@ -0,0 +1,394 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection.PortableExecutable; +using System.Runtime.InteropServices; +using System.Text; + +using Microsoft.DiaSymReader; + +namespace ILCompiler.PdbWriter +{ + // NGEN always generates PDBs with public symbols lists (so tools can map IP ranges to + // methods). This bitmask indicates what extra info should be added to the PDB + [Flags] + public enum PDBExtraData + { + None = 0, + // Add string table subsection, files checksum subsection, and lines subsection to + // allow tools to map IP ranges to source lines. + kPDBLines = 0x00000001, + }; + + struct MethodInfo + { + public string AssemblyName; + public uint MethodToken; + public uint HotRVA; + public string Name; + public uint ColdRVA; + } + + interface IModuleData + { + IEnumerable Methods { get; } + } + + public enum SymChecksumType : byte + { + None = 0, // indicates no checksum is available + MD5, + SHA1, + SHA_256, + }; + + class SymDocument : IEquatable + { + public string Name; + public SymChecksumType ChecksumType; + public byte[] Checksum; + + + public override int GetHashCode() + { + return Name.GetHashCode(); + } + + public override bool Equals(object other) + { + if (other is SymDocument documentOther) + { + return Equals(documentOther); + } + + return false; + } + + public bool Equals(SymDocument other) + { + if (Name != other.Name) + return false; + if (ChecksumType != other.ChecksumType) + return false; + if (Checksum.Length != other.Checksum.Length) + return false; + for (int i = 0; i < Checksum.Length; i++) + { + if (Checksum[i] != other.Checksum[i]) + return false; + } + + return true; + } + } + + class PdbWriter + { + string _pdbPath; + PDBExtraData _pdbExtraData; + + string _pdbFilePath; + string _tempSourceDllName; + + List _symDocuments = new List(); + Dictionary _stringTableToOffsetMapping; + Dictionary _documentToChecksumOffsetMapping; + + UIntPtr _pdbMod; + ISymNGenWriter2 _ngenWriter; + + private const string DiaSymReaderModuleName32 = "Microsoft.DiaSymReader.Native.x86.dll"; + private const string DiaSymReaderModuleName64 = "Microsoft.DiaSymReader.Native.amd64.dll"; + + private const string CreateNGenPdbWriterFactoryName = "CreateNGenPdbWriter"; + + [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.SafeDirectories)] + [DllImport(DiaSymReaderModuleName32, EntryPoint = CreateNGenPdbWriterFactoryName, PreserveSig = false)] + private extern static void CreateNGenPdbWriter32([MarshalAs(UnmanagedType.LPWStr)] string ngenImagePath, [MarshalAs(UnmanagedType.LPWStr)] string pdbPath, [MarshalAs(UnmanagedType.IUnknown)] out object ngenPdbWriter); + + [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.SafeDirectories)] + [DllImport(DiaSymReaderModuleName64, EntryPoint = CreateNGenPdbWriterFactoryName, PreserveSig = false)] + private extern static void CreateNGenPdbWriter64([MarshalAs(UnmanagedType.LPWStr)] string ngenImagePath, [MarshalAs(UnmanagedType.LPWStr)] string pdbPath, [MarshalAs(UnmanagedType.IUnknown)] out object ngenPdbWriter); + + private static ISymNGenWriter2 CreateNGenWriter(string ngenImagePath, string pdbPath) + { + object instance; + + if (IntPtr.Size == 4) + { + CreateNGenPdbWriter32(ngenImagePath, pdbPath, out instance); + } + else + { + CreateNGenPdbWriter64(ngenImagePath, pdbPath, out instance); + } + return (ISymNGenWriter2)instance; + } + + public PdbWriter(string pdbPath, PDBExtraData pdbExtraData) + { + SymDocument unknownDocument = new SymDocument(); + unknownDocument.Name = "unknown"; + unknownDocument.ChecksumType = SymChecksumType.None; + unknownDocument.Checksum = Array.Empty(); + + _symDocuments.Add(unknownDocument); + _pdbPath = pdbPath; + _pdbExtraData = pdbExtraData; + } + + public void WritePDBData(string dllPath, IEnumerable methods) + { + bool failed = true; + try + { + try + { + try + { + WritePDBDataHelper(dllPath, methods); + } + finally + { + if ((_ngenWriter != null) && (_pdbMod != UIntPtr.Zero)) + { + _ngenWriter.CloseMod(_pdbMod); + } + } + } + finally + { + if (_ngenWriter != null) + { + Marshal.FinalReleaseComObject(_ngenWriter); + } + } + + failed = false; + } + finally + { + if (_tempSourceDllName != null) + { + try + { + File.Delete(_tempSourceDllName); + } + catch {} + } + + if (failed && (_pdbFilePath != null)) + { + try + { + // If anything fails, do not create a partial pdb file + File.Delete(_pdbFilePath); + } + catch {} + } + } + } + + private void WritePDBDataHelper(string dllPath, IEnumerable methods) + { + // This will try to open the managed PDB if lines info was requested. This is a + // likely failure point, so intentionally do this before creating the NGEN PDB file + // on disk. + bool isILPDBProvided = false; + if (_pdbExtraData.HasFlag(PDBExtraData.kPDBLines)) + { + // line mapping not ported from crossgen yet. + throw new NotImplementedException(); + } + + string originalDllPath = dllPath; + + // Currently DiaSymReader does not work properly generating NGEN PDBS unless + // the DLL whose PDB is being generated ends in .ni.*. Unfortunately, readyToRun + // images do not follow this convention and end up producing bad PDBS. To fix + // this (without changing diasymreader.dll which ships indepdendently of .NET Core) + // we copy the file to somethign with this convention before generating the PDB + // and delete it when we are done. + if (!dllPath.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase) && !dllPath.EndsWith(".ni.exe", StringComparison.OrdinalIgnoreCase)) + { + _tempSourceDllName = Path.Combine(Path.GetDirectoryName(dllPath), Path.GetFileNameWithoutExtension(dllPath) + ".ni" + Path.GetExtension(dllPath)); + File.Copy(dllPath, _tempSourceDllName); + dllPath = _tempSourceDllName; + } + + _ngenWriter = CreateNGenWriter(dllPath, _pdbPath + "\\"); + + { + // PDB file is now created. Get its path and initialize _pdbFilePath so the PDB file + // can be deleted if we don't make it successfully to the end + StringBuilder pdbFilePathBuilder = new StringBuilder(); + pdbFilePathBuilder.Capacity = 1024; + _ngenWriter.QueryPDBNameExW(pdbFilePathBuilder, new IntPtr(pdbFilePathBuilder.Capacity)); + _pdbFilePath = pdbFilePathBuilder.ToString(); + } + + _ngenWriter.OpenModW(originalDllPath, Path.GetFileName(originalDllPath), out _pdbMod); + + WriteStringTable(); + WriteFileChecksums(); + + ushort? iCodeSection = null; + uint rvaOfTextSection = 0; + using (var peReader = new PEReader(new FileStream(dllPath, FileMode.Open), PEStreamOptions.Default)) + { + var sections = peReader.PEHeaders.SectionHeaders; + + for (int i = 0; i < sections.Length; i++) + { + ushort pdbSectionNumber = checked((ushort)(i+1)); + + _ngenWriter.AddSection(pdbSectionNumber, OMF.StandardText, 0, sections[i].SizeOfRawData); + if (sections[i].Name == ".text") + { + iCodeSection = pdbSectionNumber; + rvaOfTextSection = (uint)sections[i].VirtualAddress; + } + _ngenWriter.ModAddSecContribEx(_pdbMod, pdbSectionNumber, 0, sections[i].SizeOfRawData, (uint)sections[i].SectionCharacteristics, 0, 0); + } + } + + // To support lines info, we need a "dummy" section, indexed as 0, for use as a + // sentinel when MSPDB sets up its section contribution table + _ngenWriter.AddSection(0, // Dummy section 0 + OMF.SentinelType, + 0, + unchecked((int)0xFFFFFFFF)); + + foreach (var method in methods) + { + WriteMethodPDBData(iCodeSection.Value, method, Path.GetFileNameWithoutExtension(originalDllPath), rvaOfTextSection, isILPDBProvided); + } + } + + void WriteMethodPDBData(ushort iCodeSection, MethodInfo method, string assemblyName, uint textSectionOffset, bool isILPDBProvided) + { + string nameSuffix = $"{method.Name}$#{(assemblyName != method.AssemblyName ? method.AssemblyName : String.Empty)}#{method.MethodToken.ToString("X")}"; + + _ngenWriter.AddSymbol(nameSuffix, iCodeSection, method.HotRVA - textSectionOffset); + if (method.ColdRVA != 0) + { + _ngenWriter.AddSymbol($"[COLD] {nameSuffix}", iCodeSection, method.ColdRVA); + } + + if (isILPDBProvided) + { + // line mapping not ported from crossgen yet. + throw new NotImplementedException(); + } + } + + private const int CV_SIGNATURE_C13 = 4; + private enum DEBUG_S_SUBSECTION_TYPE { + DEBUG_S_IGNORE = unchecked((int)0x80000000), // if this bit is set in a subsection type then ignore the subsection contents + + DEBUG_S_SYMBOLS = 0xf1, + DEBUG_S_LINES, + DEBUG_S_STRINGTABLE, + DEBUG_S_FILECHKSMS, + DEBUG_S_FRAMEDATA, + DEBUG_S_INLINEELINES, + DEBUG_S_CROSSSCOPEIMPORTS, + DEBUG_S_CROSSSCOPEEXPORTS, + + DEBUG_S_IL_LINES, + DEBUG_S_FUNC_MDTOKEN_MAP, + DEBUG_S_TYPE_MDTOKEN_MAP, + DEBUG_S_MERGED_ASSEMBLYINPUT, + + DEBUG_S_COFF_SYMBOL_RVA, + } + + private void WriteStringTable() + { + _stringTableToOffsetMapping = new Dictionary(); + + MemoryStream stringTableStream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(stringTableStream, Encoding.UTF8); + writer.Write(CV_SIGNATURE_C13); + writer.Write((uint)DEBUG_S_SUBSECTION_TYPE.DEBUG_S_STRINGTABLE); + long sizeOfStringTablePosition = writer.BaseStream.Position; + writer.Write((uint)0); // Size of actual string table. To be filled in later + long startOfStringTableOffset = writer.BaseStream.Position; + foreach (var document in _symDocuments) + { + string str = document.Name; + if (_stringTableToOffsetMapping.ContainsKey(str)) + continue; + + long offset = writer.BaseStream.Position; + _stringTableToOffsetMapping.Add(str, checked((int)(offset - startOfStringTableOffset))); + writer.Write(str.AsSpan()); + writer.Write((byte)0); // Null terminate all strings + } + + // Update string table size + long stringTableSize = writer.BaseStream.Position - startOfStringTableOffset; + writer.BaseStream.Position = sizeOfStringTablePosition; + writer.Write(checked((uint)stringTableSize)); + writer.Flush(); + + // Write string table into pdb file + byte[] stringTableArray = stringTableStream.ToArray(); + _ngenWriter.ModAddSymbols(_pdbMod, stringTableArray, stringTableArray.Length); + } + + private void WriteFileChecksums() + { + _documentToChecksumOffsetMapping = new Dictionary(); + + MemoryStream checksumStream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(checksumStream, Encoding.UTF8); + writer.Write(CV_SIGNATURE_C13); + writer.Write((uint)DEBUG_S_SUBSECTION_TYPE.DEBUG_S_FILECHKSMS); + + long sizeOfChecksumTablePosition = writer.BaseStream.Position; + writer.Write((uint)0); // Size of actual checksum table. To be filled in later + long startOfChecksumTableOffset = writer.BaseStream.Position; + foreach (var document in _symDocuments) + { + long offset = writer.BaseStream.Position; + _documentToChecksumOffsetMapping.Add(document, checked((int)(offset - startOfChecksumTableOffset))); + + SymChecksumType checksumType = document.ChecksumType; + byte[] checksum = document.Checksum; + + if (document.Checksum.Length > 255) + { + // Should never happen, but just in case checksum data is invalid, just put + // no checksum into the NGEN PDB + checksumType = SymChecksumType.None; + checksum = Array.Empty(); + } + writer.Write(_stringTableToOffsetMapping[document.Name]); + writer.Write((byte)checksum.Length); + writer.Write((byte)checksumType); + writer.Write(checksum); + + // Must align to the next 4-byte boundary + while ((writer.BaseStream.Position % 4) != 0) + { + writer.Write((byte)0); + } + } + + // Update checksum table size + long checksumTableSize = writer.BaseStream.Position - startOfChecksumTableOffset; + writer.BaseStream.Position = sizeOfChecksumTablePosition; + writer.Write(checked((uint)checksumTableSize)); + writer.Flush(); + + // Write string table into pdb file + byte[] checksumTableArray = checksumStream.ToArray(); + _ngenWriter.ModAddSymbols(_pdbMod, checksumTableArray, checksumTableArray.Length); + } + } +} diff --git a/src/coreclr/src/tools/r2rdump/R2RDump.cs b/src/coreclr/src/tools/r2rdump/R2RDump.cs index 5e4360db442282..320d41548d9aa7 100644 --- a/src/coreclr/src/tools/r2rdump/R2RDump.cs +++ b/src/coreclr/src/tools/r2rdump/R2RDump.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.CommandLine; using System.CommandLine.Invocation; using System.IO; using System.Linq; @@ -15,6 +16,7 @@ using System.Text; using System.Threading.Tasks; using ILCompiler.Reflection.ReadyToRun; +using ILCompiler.PdbWriter; using Internal.Runtime; @@ -46,6 +48,9 @@ public class DumpOptions : IAssemblyResolver public bool DiffHideSameDisasm { get; set; } public bool IgnoreSensitive { get; set; } + public bool CreatePDB { get; set; } + public string PdbPath { get; set; } + public FileInfo[] Reference { get; set; } public DirectoryInfo[] ReferencePath { get; set; } @@ -199,12 +204,14 @@ class R2RDump { private readonly DumpOptions _options; private readonly Dictionary _selectedSections = new Dictionary(); + private readonly Encoding _encoding; private readonly TextWriter _writer; private Dumper _dumper; private R2RDump(DumpOptions options) { _options = options; + _encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false); if (_options.Verbose) { @@ -216,7 +223,7 @@ private R2RDump(DumpOptions options) if (_options.Out != null) { - _writer = new StreamWriter(_options.Out.FullName, append: false, encoding: new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false)); + _writer = new StreamWriter(_options.Out.FullName, append: false, _encoding); } else { @@ -337,8 +344,9 @@ private void QueryRuntimeFunction(ReadyToRunReader r2r, IEnumerable quer public void Dump(ReadyToRunReader r2r) { _dumper.Begin(); + bool standardDump = !(_options.EntryPoints || _options.CreatePDB); - if (_options.Header || !_options.EntryPoints) + if (_options.Header && standardDump) { _dumper.WriteDivider("R2R Header"); _dumper.DumpHeader(true); @@ -377,7 +385,18 @@ public void Dump(ReadyToRunReader r2r) _dumper.DumpEntryPoints(); } - if (!_options.Header && !_options.EntryPoints) + if (_options.CreatePDB) + { + string pdbPath = _options.PdbPath; + if (String.IsNullOrEmpty(pdbPath)) + { + pdbPath = Path.GetDirectoryName(r2r.Filename); + } + var pdbWriter = new PdbWriter(pdbPath, PDBExtraData.None); + pdbWriter.WritePDBData(r2r.Filename, ProducePdbWriterMethods(r2r)); + } + + if (!_options.Header && standardDump) { _dumper.DumpAllMethods(); } @@ -386,6 +405,21 @@ public void Dump(ReadyToRunReader r2r) _dumper.End(); } + IEnumerable ProducePdbWriterMethods(ReadyToRunReader r2r) + { + foreach (var method in _dumper.NormalizedMethods()) + { + MethodInfo mi = new MethodInfo(); + mi.Name = method.SignatureString; + mi.HotRVA = (uint)method.RuntimeFunctions[0].StartAddress; + mi.MethodToken = (uint)MetadataTokens.GetToken(method.MetadataReader, method.MethodHandle); + mi.AssemblyName = method.MetadataReader.GetString(method.MetadataReader.GetAssemblyDefinition().Name); + mi.ColdRVA = 0; + + yield return mi; + } + } + /// /// Returns true if the name, signature or id of method matches query /// @@ -538,7 +572,7 @@ private int Run() else { string perFileOutput = filename.FullName + ".common-methods.r2r"; - _dumper = new TextDumper(r2r, new StreamWriter(perFileOutput), disassembler, _options); + _dumper = new TextDumper(r2r, new StreamWriter(perFileOutput, append: false, _encoding), disassembler, _options); if (previousDumper != null) { new R2RDiff(previousDumper, _dumper, _writer).Run(); diff --git a/src/coreclr/src/tools/r2rdump/R2RDump.csproj b/src/coreclr/src/tools/r2rdump/R2RDump.csproj index 9210228b4e3d79..95dc287d162bc0 100644 --- a/src/coreclr/src/tools/r2rdump/R2RDump.csproj +++ b/src/coreclr/src/tools/r2rdump/R2RDump.csproj @@ -8,7 +8,6 @@ Open true $(NetCoreAppCurrent) - netcoreapp3.0 false 8002,NU1701 win-x64;win-x86 @@ -16,12 +15,14 @@ AnyCPU;x64 + + 1.0.1-prerelease-00005 - - 0.2.0-alpha.19174.3 + + $(SystemCommandLineVersion) diff --git a/src/coreclr/src/tools/r2rdump/R2RFormat.png b/src/coreclr/src/tools/r2rdump/R2RFormat.png index f989086c61f7fc..60b84b6cdbeea8 100644 Binary files a/src/coreclr/src/tools/r2rdump/R2RFormat.png and b/src/coreclr/src/tools/r2rdump/R2RFormat.png differ diff --git a/src/coreclr/src/tools/r2rdump/TextDumper.cs b/src/coreclr/src/tools/r2rdump/TextDumper.cs index 9b67bad70af765..84ff8cc968685b 100644 --- a/src/coreclr/src/tools/r2rdump/TextDumper.cs +++ b/src/coreclr/src/tools/r2rdump/TextDumper.cs @@ -134,7 +134,7 @@ internal override void DumpEntryPoints() internal override void DumpAllMethods() { WriteDivider("R2R Methods"); - _writer.WriteLine($"{_r2r.Methods.Count} methods"); + _writer.WriteLine($"{_r2r.Methods.Sum(kvp => kvp.Value.Count)} methods"); SkipLine(); foreach (ReadyToRunMethod method in NormalizedMethods()) { @@ -207,10 +207,10 @@ internal override void DumpRuntimeFunction(RuntimeFunction rtf) /// internal override void DumpDisasm(RuntimeFunction rtf, int imageOffset) { - int indent = (_options.Naked ? _options.HideOffsets ? 4 : 11 : 32); - string indentString = new string(' ', indent); - int rtfOffset = 0; + string indentString = new string(' ', _disassembler.MnemonicIndentation); int codeOffset = rtf.CodeOffset; + int rtfOffset = 0; + while (rtfOffset < rtf.Size) { string instr; @@ -450,12 +450,12 @@ internal override void DumpSectionContents(ReadyToRunSection section) break; case ReadyToRunSectionType.OwnerCompositeExecutable: int oceOffset = _r2r.GetOffset(section.RelativeVirtualAddress); - Decoder decoder = Encoding.UTF8.GetDecoder(); - int charLength = decoder.GetCharCount(_r2r.Image, oceOffset, section.Size - 1); // exclude the zero terminator - char[] charArray = new char[charLength]; - decoder.GetChars(_r2r.Image, oceOffset, section.Size, charArray, 0, flush: true); - string ownerCompositeExecutable = new string(charArray); - _writer.WriteLine("Composite executable: {0}", ownerCompositeExecutable); + if (_r2r.Image[oceOffset + section.Size - 1] != 0) + { + R2RDump.WriteWarning("String is not zero-terminated"); + } + string ownerCompositeExecutable = Encoding.UTF8.GetString(_r2r.Image, oceOffset, section.Size - 1); // exclude the zero terminator + _writer.WriteLine("Composite executable: {0}", ownerCompositeExecutable.ToEscapedString()); break; } } diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Buckets.cs b/src/coreclr/src/tools/r2rtest/Buckets.cs similarity index 99% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/Buckets.cs rename to src/coreclr/src/tools/r2rtest/Buckets.cs index 04052349244d87..4b7bcf06f4a849 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Buckets.cs +++ b/src/coreclr/src/tools/r2rtest/Buckets.cs @@ -9,7 +9,7 @@ using System.IO; using System.Linq; -namespace ReadyToRun.SuperIlc +namespace R2RTest { public class Buckets { diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/BuildFolder.cs b/src/coreclr/src/tools/r2rtest/BuildFolder.cs similarity index 99% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/BuildFolder.cs rename to src/coreclr/src/tools/r2rtest/BuildFolder.cs index 319b4c9058fd82..b3b64572a0cee5 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/BuildFolder.cs +++ b/src/coreclr/src/tools/r2rtest/BuildFolder.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Runtime.InteropServices; -namespace ReadyToRun.SuperIlc +namespace R2RTest { public class BuildFolder { diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/BuildFolderSet.cs b/src/coreclr/src/tools/r2rtest/BuildFolderSet.cs similarity index 99% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/BuildFolderSet.cs rename to src/coreclr/src/tools/r2rtest/BuildFolderSet.cs index cf0dd1ddc62f62..7c05f20c5a8aa7 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/BuildFolderSet.cs +++ b/src/coreclr/src/tools/r2rtest/BuildFolderSet.cs @@ -12,7 +12,7 @@ using Microsoft.Diagnostics.Tracing.Parsers; using Microsoft.Diagnostics.Tracing.Parsers.Clr; -namespace ReadyToRun.SuperIlc +namespace R2RTest { public class BuildFolderSet { diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/BuildOptions.cs b/src/coreclr/src/tools/r2rtest/BuildOptions.cs similarity index 97% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/BuildOptions.cs rename to src/coreclr/src/tools/r2rtest/BuildOptions.cs index 70cb2ce7ab12bc..152b6ae04352f6 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/BuildOptions.cs +++ b/src/coreclr/src/tools/r2rtest/BuildOptions.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.IO; -namespace ReadyToRun.SuperIlc +namespace R2RTest { public class BuildOptions { @@ -30,6 +30,7 @@ public class BuildOptions public bool Release { get; set; } public bool LargeBubble { get; set; } public bool Composite { get; set; } + public bool PartialComposite { get; set; } public int Crossgen2Parallelism { get; set; } public int CompilationTimeoutMinutes { get; set; } public int ExecutionTimeoutMinutes { get; set; } @@ -39,6 +40,7 @@ public class BuildOptions public FileInfo CrossgenResponseFile { get; set; } public DirectoryInfo[] RewriteOldPath { get; set; } public DirectoryInfo[] RewriteNewPath { get; set; } + public DirectoryInfo AspNetPath { get; set; } public bool MeasurePerf { get; set; } public string InputFileSearchString { get; set; } public string ConfigurationSuffix => (Release ? "-ret.out" : "-chk.out"); diff --git a/src/coreclr/src/tools/r2rtest/CommandLineOptions.cs b/src/coreclr/src/tools/r2rtest/CommandLineOptions.cs new file mode 100644 index 00000000000000..9575654a57934b --- /dev/null +++ b/src/coreclr/src/tools/r2rtest/CommandLineOptions.cs @@ -0,0 +1,289 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.CommandLine; +using System.CommandLine.Builder; +using System.CommandLine.Invocation; +using System.IO; + +namespace R2RTest +{ + internal static class CommandLineOptions + { + public static CommandLineBuilder Build() + { + var parser = new CommandLineBuilder() + .AddCommand(CompileFolder()) + .AddCommand(CompileSubtree()) + .AddCommand(CompileFramework()) + .AddCommand(CompileNugetPackages()) + .AddCommand(CompileCrossgenRsp()) + .AddCommand(CompileSerp()); + + return parser; + + Command CreateCommand(string name, string description, Option[] options, Func action) + { + Command command = new Command(name, description); + foreach (var option in options) + command.AddOption(option); + command.Handler = CommandHandler.Create(action); + return command; + } + + Command CompileFolder() => + CreateCommand("compile-directory", "Compile all assemblies in directory", + new Option[] + { + InputDirectory(), + OutputDirectory(), + CoreRootDirectory(), + Crossgen(), + CrossgenPath(), + NoJit(), + NoCrossgen2(), + Exe(), + NoExe(), + NoEtw(), + NoCleanup(), + Map(), + DegreeOfParallelism(), + Sequential(), + Framework(), + UseFramework(), + Release(), + LargeBubble(), + Composite(), + Crossgen2Parallelism(), + ReferencePath(), + IssuesPath(), + CompilationTimeoutMinutes(), + ExecutionTimeoutMinutes(), + R2RDumpPath(), + MeasurePerf(), + InputFileSearchString(), + }, + CompileDirectoryCommand.CompileDirectory); + + Command CompileSubtree() => + CreateCommand("compile-subtree", "Build each directory in a given subtree containing any managed assemblies as a separate app", + new Option[] + { + InputDirectory(), + OutputDirectory(), + CoreRootDirectory(), + Crossgen(), + CrossgenPath(), + NoJit(), + NoCrossgen2(), + Exe(), + NoExe(), + NoEtw(), + NoCleanup(), + Map(), + DegreeOfParallelism(), + Sequential(), + Framework(), + UseFramework(), + Release(), + LargeBubble(), + Composite(), + Crossgen2Parallelism(), + ReferencePath(), + IssuesPath(), + CompilationTimeoutMinutes(), + ExecutionTimeoutMinutes(), + R2RDumpPath(), + GCStress(), + }, + CompileSubtreeCommand.CompileSubtree); + + Command CompileFramework() => + CreateCommand("compile-framework", "Compile managed framework assemblies in Core_Root", + new Option[] + { + CoreRootDirectory(), + Crossgen(), + CrossgenPath(), + NoCrossgen2(), + NoCleanup(), + DegreeOfParallelism(), + Sequential(), + Release(), + LargeBubble(), + Composite(), + ReferencePath(), + IssuesPath(), + CompilationTimeoutMinutes(), + R2RDumpPath(), + MeasurePerf(), + InputFileSearchString(), + }, + CompileFrameworkCommand.CompileFramework); + + Command CompileNugetPackages() => + CreateCommand("compile-nuget", "Restore a list of Nuget packages into an empty console app, publish, and optimize with Crossgen / CPAOT", + new Option[] + { + R2RDumpPath(), + InputDirectory(), + OutputDirectory(), + PackageList(), + CoreRootDirectory(), + Crossgen(), + NoCleanup(), + DegreeOfParallelism(), + CompilationTimeoutMinutes(), + ExecutionTimeoutMinutes(), + }, + CompileNugetCommand.CompileNuget); + + Command CompileCrossgenRsp() => + CreateCommand("compile-crossgen-rsp", "Use existing Crossgen .rsp file(s) to build assemblies, optionally rewriting base paths", + new Option[] + { + InputDirectory(), + CrossgenResponseFile(), + OutputDirectory(), + CoreRootDirectory(), + Crossgen(), + NoCleanup(), + DegreeOfParallelism(), + CompilationTimeoutMinutes(), + RewriteOldPath(), + RewriteNewPath(), + }, + CompileFromCrossgenRspCommand.CompileFromCrossgenRsp); + + Command CompileSerp() => + CreateCommand("compile-serp", "Compile existing application", + new Option[] + { + InputDirectory(), + OutputDirectory(), + DegreeOfParallelism(), + CoreRootDirectory(), + AspNetPath(), + Composite(), + PartialComposite(), + }, + CompileSerpCommand.CompileSerpAssemblies); + + // Todo: Input / Output directories should be required arguments to the command when they're made available to handlers + // https://github.com/dotnet/command-line-api/issues/297 + Option InputDirectory() => + new Option(new[] { "--input-directory", "-in" }, "Folder containing assemblies to optimize").ExistingOnly(); + + Option OutputDirectory() => + new Option(new[] { "--output-directory", "-out" }, "Folder to emit compiled assemblies").LegalFilePathsOnly(); + + Option CoreRootDirectory() => + new Option(new[] { "--core-root-directory", "-cr" }, "Location of the CoreCLR CORE_ROOT folder").ExistingOnly(); + + Option ReferencePath() => + new Option(new[] { "--reference-path", "-r" }, "Folder containing assemblies to reference during compilation") + { Argument = new Argument() { Arity = ArgumentArity.ZeroOrMore }.ExistingOnly() }; + + Option Crossgen() => + new Option(new[] { "--crossgen" }, "Compile the apps using Crossgen in the CORE_ROOT folder"); + + Option CrossgenPath() => + new Option(new[] { "--crossgen-path", "-cp" }, "Explicit Crossgen path (useful for cross-targeting)").ExistingOnly(); + + Option NoJit() => + new Option(new[] { "--nojit" }, "Don't run tests in JITted mode"); + + Option NoCrossgen2() => + new Option(new[] { "--nocrossgen2" }, "Don't run tests in Crossgen2 mode"); + + Option Exe() => + new Option(new[] { "--exe" }, "Don't compile tests, just execute them"); + + Option NoExe() => + new Option(new[] { "--noexe" }, "Compilation-only mode (don't execute the built apps)"); + + Option NoEtw() => + new Option(new[] { "--noetw" }, "Don't capture jitted methods using ETW"); + + Option NoCleanup() => + new Option(new[] { "--nocleanup" }, "Don't clean up compilation artifacts after test runs"); + + Option Map() => + new Option(new[] { "--map" }, "Generate a map file (Crossgen2)"); + + Option DegreeOfParallelism() => + new Option(new[] { "--degree-of-parallelism", "-dop" }, "Override default compilation / execution DOP (default = logical processor count)"); + + Option Sequential() => + new Option(new[] { "--sequential" }, "Run tests sequentially"); + + Option Framework() => + new Option(new[] { "--framework" }, "Precompile and use native framework"); + + Option UseFramework() => + new Option(new[] { "--use-framework" }, "Use native framework (don't precompile, assume previously compiled)"); + + Option Release() => + new Option(new[] { "--release" }, "Build the tests in release mode"); + + Option LargeBubble() => + new Option(new[] { "--large-bubble" }, "Assume all input files as part of one version bubble"); + + Option Composite() => + new Option(new[] { "--composite" }, "Compile tests in composite R2R mode"); + + Option Crossgen2Parallelism() => + new Option(new[] { "--crossgen2-parallelism" }, "Max number of threads to use in Crossgen2 (default = logical processor count)"); + + Option IssuesPath() => + new Option(new[] { "--issues-path", "-ip" }, "Path to issues.targets") + { Argument = new Argument() { Arity = ArgumentArity.ZeroOrMore } }; + + Option CompilationTimeoutMinutes() => + new Option(new[] { "--compilation-timeout-minutes", "-ct" }, "Compilation timeout (minutes)"); + + Option ExecutionTimeoutMinutes() => + new Option(new[] { "--execution-timeout-minutes", "-et" }, "Execution timeout (minutes)"); + + Option R2RDumpPath() => + new Option(new[] { "--r2r-dump-path", "-r2r" }, "Path to R2RDump.exe/dll").ExistingOnly();; + + Option CrossgenResponseFile() => + new Option(new [] { "--crossgen-response-file", "-rsp" }, "Response file to transpose").ExistingOnly();; + + Option RewriteOldPath() => + new Option(new[] { "--rewrite-old-path" }, "Path substring to replace") + { Argument = new Argument() { Arity = ArgumentArity.ZeroOrMore } }; + + Option RewriteNewPath() => + new Option(new[] { "--rewrite-new-path" }, "Path substring to use instead") + { Argument = new Argument() { Arity = ArgumentArity.ZeroOrMore } }; + + Option MeasurePerf() => + new Option(new[] { "--measure-perf" }, "Print out compilation time"); + + Option InputFileSearchString() => + new Option(new[] { "--input-file-search-string", "-input-file" }, "Search string for input files in the input directory"); + + Option GCStress() => + new Option(new[] { "--gcstress" }, "Run tests with the specified GC stress level enabled (the argument value is in hex)"); + + // + // compile-nuget specific options + // + Option PackageList() => + new Option(new[] { "--package-list", "-pl" }, "Text file containing a package name on each line").ExistingOnly();; + + // + // compile-serp specific options + // + Option AspNetPath() => + new Option(new[] { "--asp-net-path", "-asp" }, "Path to SERP's ASP.NET Core folder").ExistingOnly(); + + Option PartialComposite() => + new Option(new[] { "--partial-composite", "-pc" }, "Add references to framework and asp.net instead of unrooted inputs"); + } + } +} diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileDirectoryCommand.cs b/src/coreclr/src/tools/r2rtest/Commands/CompileDirectoryCommand.cs similarity index 98% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileDirectoryCommand.cs rename to src/coreclr/src/tools/r2rtest/Commands/CompileDirectoryCommand.cs index e75948bc16eec9..3089bf3f5aa440 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileDirectoryCommand.cs +++ b/src/coreclr/src/tools/r2rtest/Commands/CompileDirectoryCommand.cs @@ -8,7 +8,7 @@ using System.IO; using System.Linq; -namespace ReadyToRun.SuperIlc +namespace R2RTest { class CompileDirectoryCommand { diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileFrameworkCommand.cs b/src/coreclr/src/tools/r2rtest/Commands/CompileFrameworkCommand.cs similarity index 97% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileFrameworkCommand.cs rename to src/coreclr/src/tools/r2rtest/Commands/CompileFrameworkCommand.cs index f52f54a6d6790c..6ab22cfb9766ca 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileFrameworkCommand.cs +++ b/src/coreclr/src/tools/r2rtest/Commands/CompileFrameworkCommand.cs @@ -8,7 +8,7 @@ using System.IO; using System.Linq; -namespace ReadyToRun.SuperIlc +namespace R2RTest { class CompileFrameworkCommand { diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileFromCrossgenRspCommand.cs b/src/coreclr/src/tools/r2rtest/Commands/CompileFromCrossgenRspCommand.cs similarity index 99% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileFromCrossgenRspCommand.cs rename to src/coreclr/src/tools/r2rtest/Commands/CompileFromCrossgenRspCommand.cs index 5c42e3e9aaff67..f759e117917be1 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileFromCrossgenRspCommand.cs +++ b/src/coreclr/src/tools/r2rtest/Commands/CompileFromCrossgenRspCommand.cs @@ -10,7 +10,7 @@ using System.Linq; using System.Text; -namespace ReadyToRun.SuperIlc +namespace R2RTest { class CompileFromCrossgenRspCommand { diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileNugetCommand.cs b/src/coreclr/src/tools/r2rtest/Commands/CompileNugetCommand.cs similarity index 98% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileNugetCommand.cs rename to src/coreclr/src/tools/r2rtest/Commands/CompileNugetCommand.cs index 9efc474dc63ee5..bc5f541898a9d9 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileNugetCommand.cs +++ b/src/coreclr/src/tools/r2rtest/Commands/CompileNugetCommand.cs @@ -8,7 +8,7 @@ using System.IO; using System.Linq; -namespace ReadyToRun.SuperIlc +namespace R2RTest { /// /// Adds a list of Nuget packages to an empty console app, publishes the app, and runs Crossgen / CPAOT @@ -81,7 +81,7 @@ public static int CompileNuget(BuildOptions options) } // This is not a reliable way of building the publish folder - string publishFolder = Path.Combine(appFolder, @"artifacts\Debug\netcoreapp5.0\publish"); + string publishFolder = Path.Combine(appFolder, @"artifacts\Debug\net5.0\publish"); if (!Directory.Exists(publishFolder)) { nugetLog.WriteLine($"Could not find folder {publishFolder} containing the published app."); diff --git a/src/coreclr/src/tools/r2rtest/Commands/CompileSerpCommand.cs b/src/coreclr/src/tools/r2rtest/Commands/CompileSerpCommand.cs new file mode 100644 index 00000000000000..15893256577bc7 --- /dev/null +++ b/src/coreclr/src/tools/r2rtest/Commands/CompileSerpCommand.cs @@ -0,0 +1,204 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; + +namespace R2RTest +{ + class CompileSerpCommand + { + public static int CompileSerpAssemblies(BuildOptions options) + { + if (options.InputDirectory == null) + { + Console.Error.WriteLine("Specify --response-file or --input-directory containing multiple response files."); + return 1; + } + + if (options.CoreRootDirectory == null) + { + Console.Error.WriteLine("--core-root-directory (--cr) is a required argument."); + return 1; + } + + + // This command does not work in the context of an app, just a loose set of rsp files so don't execute anything we compile + options.NoJit = true; + options.NoEtw = true; + + string serpDir = options.InputDirectory.FullName; + if (!File.Exists(Path.Combine(serpDir, "runserp.cmd"))) + { + Console.Error.WriteLine($"Error: InputDirectory must point at a SERP build. Could not find {Path.Combine(serpDir, "runserp.cmd")}"); + return 1; + } + + string whiteListFilePath = Path.Combine(serpDir, "WhitelistDlls.txt"); + if (!File.Exists(whiteListFilePath)) + { + Console.Error.WriteLine($"File {whiteListFilePath} was not found"); + return 1; + } + + if (!File.Exists(Path.Combine(options.AspNetPath.FullName, "Microsoft.AspNetCore.dll"))) + { + Console.Error.WriteLine($"Error: Asp.NET Core path must contain Microsoft.AspNetCore.dll"); + return 1; + } + + string binDir = Path.Combine(serpDir, "bin"); + + // Remove existing native images + foreach (var file in Directory.GetFiles(Path.Combine(serpDir, "App_Data\\Answers\\Services\\Packages"), "*.dll", SearchOption.AllDirectories)) + { + if (file.EndsWith(".ni.dll") || file.EndsWith(".ni.exe")) + { + File.Delete(file); + } + } + + foreach (var file in Directory.GetFiles(binDir, "*.dll", SearchOption.AllDirectories)) + { + if (file.EndsWith(".ni.dll") || file.EndsWith(".ni.exe")) + { + File.Delete(file); + } + } + + // Add all assemblies from the various SERP packages (filtered by ShouldInclude) + List binFiles = Directory.GetFiles(Path.Combine(serpDir, "App_Data\\Answers\\Services\\Packages"), "*.dll", SearchOption.AllDirectories) + .Where((string x) => ShouldInclude(x)) + .ToList(); + + // Add a whitelist of assemblies from bin + foreach (string item in new HashSet(File.ReadAllLines(whiteListFilePath))) + { + binFiles.Add(Path.Combine(binDir, item)); + } + + HashSet referenceAssemblyDirectories = new HashSet(); + foreach (var binFile in binFiles) + { + var directory = Path.GetDirectoryName(binFile); + if (!referenceAssemblyDirectories.Contains(directory)) + referenceAssemblyDirectories.Add(directory); + } + + // TestILC needs a list of all directories containing assemblies that are referenced from crossgen + List referenceAssemblies = new List(); + HashSet simpleNames = new HashSet(StringComparer.OrdinalIgnoreCase); + + // Reference all managed assemblies in /bin and /App_Data/answers/services/packages + foreach (string binFile in ResolveReferences(referenceAssemblyDirectories)) + { + simpleNames.Add(Path.GetFileNameWithoutExtension(binFile)); + referenceAssemblies.Add(binFile); + } + + referenceAssemblies.AddRange(ComputeManagedAssemblies.GetManagedAssembliesInFolderNoSimpleNameDuplicates(simpleNames, options.AspNetPath.FullName, "*.dll")); + + // Add CoreRoot last because it contains various non-framework assemblies that are duplicated in SERP and we want SERP's to be used + referenceAssemblies.AddRange(ComputeManagedAssemblies.GetManagedAssembliesInFolderNoSimpleNameDuplicates(simpleNames, options.CoreRootDirectory.FullName, "System.*.dll")); + referenceAssemblies.AddRange(ComputeManagedAssemblies.GetManagedAssembliesInFolderNoSimpleNameDuplicates(simpleNames, options.CoreRootDirectory.FullName, "Microsoft.*.dll")); + referenceAssemblies.Add(Path.Combine(options.CoreRootDirectory.FullName, "mscorlib.dll")); + referenceAssemblies.Add(Path.Combine(options.CoreRootDirectory.FullName, "netstandard.dll")); + + // + // binFiles is now all the assemblies that we want to compile (either individually or as composite) + // referenceAssemblies is all managed assemblies that are referenceable + // + + // Remove all bin files except serp.dll so they're just referenced (eventually we'll be able to compile all these in a single composite) + foreach (string item in new HashSet(File.ReadAllLines(whiteListFilePath))) + { + if (item == "Serp.dll") + continue; + + binFiles.Remove(Path.Combine(binDir, item)); + } + + List fileCompilations = new List(); + if (options.Composite) + { + string serpDll = Path.Combine(binDir, "Serp.dll"); + var runner = new CpaotRunner(options, referenceAssemblies); + var compilationProcess = new ProcessInfo(new CompilationProcessConstructor(runner, Path.ChangeExtension(serpDll, ".ni.dll"), binFiles)); + fileCompilations.Add(compilationProcess); + } + else + { + var runner = new CpaotRunner(options, referenceAssemblies); + foreach (string assemblyName in binFiles) + { + var compilationProcess = new ProcessInfo(new CompilationProcessConstructor(runner, Path.ChangeExtension(assemblyName, ".ni.dll"), new string[] {assemblyName})); + fileCompilations.Add(compilationProcess); + } + } + + ParallelRunner.Run(fileCompilations, options.DegreeOfParallelism); + + bool success = true; + int compilationFailures = 0; + foreach (var compilationProcess in fileCompilations) + { + if (!compilationProcess.Succeeded) + { + success = false; + compilationFailures++; + + Console.WriteLine($"Failed compiling {compilationProcess.Parameters.OutputFileName}"); + } + } + + Console.WriteLine("Serp Compilation Results"); + Console.WriteLine($"Total compilations: {fileCompilations.Count}"); + Console.WriteLine($"Compilation failures: {compilationFailures}"); + + return success ? 0 : 1; + } + + private static bool ShouldInclude(string file) + { + if (!string.IsNullOrEmpty(file)) + { + if (file.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase) || file.EndsWith(".ni.exe", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + if (file.EndsWith("Shared.Exports.dll", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + if (file.EndsWith(".parallax.dll", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + if (!file.EndsWith("Exports.dll", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + return false; + } + + private static IEnumerable ResolveReferences(IEnumerable folders) + { + foreach (string referenceFolder in folders) + { + foreach (string reference in ComputeManagedAssemblies.GetManagedAssembliesInFolder(referenceFolder)) + { + if (reference.EndsWith(".ni.dll")) + continue; + yield return reference; + } + } + } + } +} diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileSubtreeCommand.cs b/src/coreclr/src/tools/r2rtest/Commands/CompileSubtreeCommand.cs similarity index 99% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileSubtreeCommand.cs rename to src/coreclr/src/tools/r2rtest/Commands/CompileSubtreeCommand.cs index 40297da9b9522e..aac04c62514180 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Commands/CompileSubtreeCommand.cs +++ b/src/coreclr/src/tools/r2rtest/Commands/CompileSubtreeCommand.cs @@ -11,7 +11,7 @@ using System.Threading; using System.Threading.Tasks; -namespace ReadyToRun.SuperIlc +namespace R2RTest { class CompileSubtreeCommand { diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/CompilerRunner.cs b/src/coreclr/src/tools/r2rtest/CompilerRunner.cs similarity index 97% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/CompilerRunner.cs rename to src/coreclr/src/tools/r2rtest/CompilerRunner.cs index bfefd99f2ce25f..1c91757972b120 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/CompilerRunner.cs +++ b/src/coreclr/src/tools/r2rtest/CompilerRunner.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; using System.Text; -namespace ReadyToRun.SuperIlc +namespace R2RTest { public enum CompilerIndex { @@ -83,12 +83,18 @@ public abstract class CompilerRunner public const int R2RDumpTimeoutMilliseconds = 60 * 1000; protected readonly BuildOptions _options; - protected readonly IEnumerable _referenceFolders; - - public CompilerRunner(BuildOptions options, IEnumerable referenceFolders) + protected readonly List _referenceFolders = new List(); + public CompilerRunner(BuildOptions options, IEnumerable references) { _options = options; - _referenceFolders = referenceFolders; + + foreach (var reference in references) + { + if (Directory.Exists(reference)) + { + _referenceFolders.Add(reference); + } + } } public IEnumerable ReferenceFolders => _referenceFolders; diff --git a/src/coreclr/src/tools/r2rtest/ComputeManagedAssemblies.cs b/src/coreclr/src/tools/r2rtest/ComputeManagedAssemblies.cs new file mode 100644 index 00000000000000..e9be5ccb967bd2 --- /dev/null +++ b/src/coreclr/src/tools/r2rtest/ComputeManagedAssemblies.cs @@ -0,0 +1,91 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; + +class ComputeManagedAssemblies +{ + public static IEnumerable GetManagedAssembliesInFolder(string folder, string fileNamePattern = "*.*") + { + foreach (var file in Directory.GetFiles(folder, fileNamePattern, SearchOption.TopDirectoryOnly)) + { + if (IsManaged(file)) + { + yield return file; + } + } + } + + /// + /// Returns a list of assemblies in "folder" whose simple name does not exist in "simpleNames". Each discovered + /// assembly is added to "simpleNames" to build a list without duplicates. When collecting multiple folders of assemblies + /// consider the call order for this function so duplicates are ignored as expected. For exmaple, CORE_ROOT's S.P.CoreLib + /// should normally win. + /// + /// Used to keep track of which simple names were used across multiple invocations of this method + public static IEnumerable GetManagedAssembliesInFolderNoSimpleNameDuplicates(HashSet simpleNames, string folder, string fileNamePattern = "*.*") + { + foreach (var file in GetManagedAssembliesInFolder(folder, fileNamePattern)) + { + var simpleName = Path.GetFileNameWithoutExtension(file); + if (!simpleNames.Contains(simpleName)) + { + yield return file; + simpleNames.Add(simpleName); + } + } + } + + static ConcurrentDictionary _isManagedCache = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + + public static bool IsManaged(string file) + { + // Only files named *.dll and *.exe are considered as possible assemblies + if (!Path.HasExtension(file) || (Path.GetExtension(file) != ".dll" && Path.GetExtension(file) != ".exe")) + return false; + + bool isManaged; + lock (_isManagedCache) + { + if (_isManagedCache.TryGetValue(file, out isManaged)) + { + return isManaged; + } + } + + try + { + using (FileStream moduleStream = File.OpenRead(file)) + using (var module = new PEReader(moduleStream)) + { + if (module.HasMetadata) + { + MetadataReader moduleMetadataReader = module.GetMetadataReader(); + if (moduleMetadataReader.IsAssembly) + { + string culture = moduleMetadataReader.GetString(moduleMetadataReader.GetAssemblyDefinition().Culture); + + if (culture == "" || culture.Equals("neutral", StringComparison.OrdinalIgnoreCase)) + { + isManaged = true; + } + } + } + } + } + catch (BadImageFormatException) + { + isManaged = false; + } + + _isManagedCache[file] = isManaged; + + return isManaged; + } +} diff --git a/src/coreclr/src/tools/r2rtest/CpaotRunner.cs b/src/coreclr/src/tools/r2rtest/CpaotRunner.cs new file mode 100644 index 00000000000000..128b0e20ed6cea --- /dev/null +++ b/src/coreclr/src/tools/r2rtest/CpaotRunner.cs @@ -0,0 +1,160 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; + +namespace R2RTest +{ + /// + /// Compiles assemblies using the Cross-Platform AOT compiler + /// + class CpaotRunner : CompilerRunner + { + public override CompilerIndex Index => CompilerIndex.CPAOT; + + // Crossgen2 runs on top of corerun. + protected override string CompilerRelativePath => ""; + + protected override string CompilerFileName => "corerun".AppendOSExeSuffix(); + protected readonly List _referenceFiles = new List(); + + private string Crossgen2Path => Path.Combine(_options.CoreRootDirectory.FullName, "crossgen2", "crossgen2.dll"); + + public CpaotRunner(BuildOptions options, IEnumerable references) + : base(options, references) + { + // Some scenarios are easier to express when we give Crossgen2 a list of reference assemblies instead of directories, + // so allow an override here. + foreach (var reference in references) + { + if (File.Exists(reference)) + { + if (_referenceFolders.Count > 0) + { + // There's nothing wrong with this per se, but none of our current scenarios need it, so this is + // just a consistency check. + throw new ArgumentException($"A mix of files and directories was found in {references}"); + } + _referenceFiles.Add(reference); + } + } + + // Set R2RTest parallelism to a low enough value that ensures that each Crossgen2 invocation gets to use its parallelism + if (options.DegreeOfParallelism == 0) + options.DegreeOfParallelism = 2; + } + + public override ProcessParameters CompilationProcess(string outputFileName, IEnumerable inputAssemblyFileNames) + { + ProcessParameters processParameters = base.CompilationProcess(outputFileName, inputAssemblyFileNames); + processParameters.Arguments = $"{Crossgen2Path} {processParameters.Arguments}"; + return processParameters; + } + + protected override ProcessParameters ExecutionProcess(IEnumerable modules, IEnumerable folders, bool noEtw) + { + ProcessParameters processParameters = base.ExecutionProcess(modules, folders, noEtw); + processParameters.EnvironmentOverrides["COMPLUS_ReadyToRun"] = "1"; + return processParameters; + } + + protected override IEnumerable BuildCommandLineArguments(IEnumerable assemblyFileNames, string outputFileName) + { + // The file to compile + foreach (string inputAssembly in assemblyFileNames) + { + yield return inputAssembly; + } + + // Output + yield return $"-o:{outputFileName}"; + + // Todo: Allow cross-architecture compilation + //yield return "--targetarch=x64"; + + if (_options.Map) + { + yield return "--map"; + } + + if (_options.Release) + { + yield return "-O"; + } + + if (_options.LargeBubble) + { + yield return "--inputbubble"; + } + + if (_options.Composite) + { + yield return "--composite"; + } + + if (_options.Crossgen2Parallelism != 0) + { + yield return $"--parallelism={_options.Crossgen2Parallelism}"; + } + + string frameworkFolder = ""; + if (_options.Framework || _options.UseFramework) + { + frameworkFolder = GetOutputPath(_options.CoreRootDirectory.FullName); + foreach (string frameworkRef in ResolveReferences(new string[] { frameworkFolder }, 'r')) + { + yield return frameworkRef; + } + } + + if (_referenceFiles.Count == 0) + { + // Use reference folders and find the managed assemblies we want to reference from them. + // This is the standard path when we want to compile folders and compare crossgen1 and crossgen2. + StringComparer pathComparer = PathExtensions.OSPathCaseComparer; + HashSet uniqueFolders = new HashSet(pathComparer); + + foreach (string assemblyFileName in assemblyFileNames) + { + uniqueFolders.Add(Path.GetDirectoryName(assemblyFileName)); + } + + uniqueFolders.UnionWith(_referenceFolders); + uniqueFolders.Remove(frameworkFolder); + + foreach (string reference in ResolveReferences(uniqueFolders, _options.Composite ? 'u' : 'r')) + { + yield return reference; + } + } + else + { + // Use an explicit set of reference assemblies. + // This is useful for crossgen2-specific scenarios since crossgen2 expects a list of files unlike crossgen1 + foreach (var reference in _referenceFiles) + { + yield return (_options.Composite && !_options.PartialComposite ? "-u:" : "-r:") + reference; + } + } + } + + private IEnumerable ResolveReferences(IEnumerable folders, char referenceOption) + { + foreach (string referenceFolder in folders) + { + foreach (string reference in ComputeManagedAssemblies.GetManagedAssembliesInFolder(referenceFolder)) + { + string simpleName = Path.GetFileNameWithoutExtension(reference); + if (!FrameworkExclusion.Exclude(simpleName, Index, out string reason)) + { + yield return $"-{referenceOption}:{reference}"; + } + } + } + } + } +} diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/CrossgenRunner.cs b/src/coreclr/src/tools/r2rtest/CrossgenRunner.cs similarity index 98% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/CrossgenRunner.cs rename to src/coreclr/src/tools/r2rtest/CrossgenRunner.cs index e2e97399aaeb7c..49a31c032b3668 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/CrossgenRunner.cs +++ b/src/coreclr/src/tools/r2rtest/CrossgenRunner.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Text; -namespace ReadyToRun.SuperIlc +namespace R2RTest { /// /// Compiles assemblies using the Cross-Platform AOT compiler diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/DotnetCli.cs b/src/coreclr/src/tools/r2rtest/DotnetCli.cs similarity index 99% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/DotnetCli.cs rename to src/coreclr/src/tools/r2rtest/DotnetCli.cs index 99b8de24748918..cb1134b0cdf9fd 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/DotnetCli.cs +++ b/src/coreclr/src/tools/r2rtest/DotnetCli.cs @@ -9,7 +9,7 @@ using System.Linq; using System.Text; -namespace ReadyToRun.SuperIlc +namespace R2RTest { /// /// Helpers to call dotnet CLI via Process.Start diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/JitRunner.cs b/src/coreclr/src/tools/r2rtest/JitRunner.cs similarity index 98% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/JitRunner.cs rename to src/coreclr/src/tools/r2rtest/JitRunner.cs index 863c506925d92c..69768e38019c66 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/JitRunner.cs +++ b/src/coreclr/src/tools/r2rtest/JitRunner.cs @@ -7,7 +7,7 @@ using System.IO; using System.Linq; -namespace ReadyToRun.SuperIlc +namespace R2RTest { /// /// No-op runner keeping the original IL assemblies to be directly run with full jitting. diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Linux.cs b/src/coreclr/src/tools/r2rtest/Linux.cs similarity index 97% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/Linux.cs rename to src/coreclr/src/tools/r2rtest/Linux.cs index 4eee0c21656cbb..b31b4a9d3725c0 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/Linux.cs +++ b/src/coreclr/src/tools/r2rtest/Linux.cs @@ -8,7 +8,7 @@ using System.IO; using System.Runtime.InteropServices; -namespace ReadyToRun.SuperIlc +namespace R2RTest { internal static class Linux { diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/ParallelRunner.cs b/src/coreclr/src/tools/r2rtest/ParallelRunner.cs similarity index 100% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/ParallelRunner.cs rename to src/coreclr/src/tools/r2rtest/ParallelRunner.cs diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/PathHelpers.cs b/src/coreclr/src/tools/r2rtest/PathHelpers.cs similarity index 98% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/PathHelpers.cs rename to src/coreclr/src/tools/r2rtest/PathHelpers.cs index 8361b3451ec614..87ad279990ae9d 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/PathHelpers.cs +++ b/src/coreclr/src/tools/r2rtest/PathHelpers.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using ReadyToRun.SuperIlc; +using R2RTest; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -288,4 +288,6 @@ public static bool DeleteOutputFolders(string folder, string coreRootFolder, IEn return false; } } + + public static StringComparer OSPathCaseComparer => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal; } diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/PerfEventSourceListener.cs b/src/coreclr/src/tools/r2rtest/PerfEventSourceListener.cs similarity index 100% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/PerfEventSourceListener.cs rename to src/coreclr/src/tools/r2rtest/PerfEventSourceListener.cs diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/ProcessRunner.cs b/src/coreclr/src/tools/r2rtest/ProcessRunner.cs similarity index 100% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/ProcessRunner.cs rename to src/coreclr/src/tools/r2rtest/ProcessRunner.cs diff --git a/src/coreclr/src/tools/r2rtest/Program.cs b/src/coreclr/src/tools/r2rtest/Program.cs new file mode 100644 index 00000000000000..32aaeafc60d3cf --- /dev/null +++ b/src/coreclr/src/tools/r2rtest/Program.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.CommandLine; +using System.CommandLine.Builder; +using System.CommandLine.Parsing; +using System.Threading.Tasks; + +namespace R2RTest +{ + class Program + { + static async Task Main(string[] args) + { + var parser = CommandLineOptions.Build().UseDefaults().Build(); + + return await parser.InvokeAsync(args); + } + } +} diff --git a/src/coreclr/src/tools/r2rtest/R2RTest.csproj b/src/coreclr/src/tools/r2rtest/R2RTest.csproj new file mode 100644 index 00000000000000..06db7cc4f2e9d7 --- /dev/null +++ b/src/coreclr/src/tools/r2rtest/R2RTest.csproj @@ -0,0 +1,29 @@ + + + R2RTest + true + Exe + $(NetCoreAppCurrent) + 8002,NU1701 + AnyCPU + $(BinDir)\R2RTest + + + + + 16.0.461 + + + 16.0.461 + + + 2.0.55 + + + $(SystemCommandLineVersion) + + + 1.8.1 + + + diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/ReadyToRunJittedMethods.cs b/src/coreclr/src/tools/r2rtest/ReadyToRunJittedMethods.cs similarity index 100% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/ReadyToRunJittedMethods.cs rename to src/coreclr/src/tools/r2rtest/ReadyToRunJittedMethods.cs diff --git a/src/coreclr/src/tools/ReadyToRun.SuperIlc/TestExclusion.cs b/src/coreclr/src/tools/r2rtest/TestExclusion.cs similarity index 98% rename from src/coreclr/src/tools/ReadyToRun.SuperIlc/TestExclusion.cs rename to src/coreclr/src/tools/r2rtest/TestExclusion.cs index 81c34704f44986..5fefaee6d90fcf 100644 --- a/src/coreclr/src/tools/ReadyToRun.SuperIlc/TestExclusion.cs +++ b/src/coreclr/src/tools/r2rtest/TestExclusion.cs @@ -11,7 +11,7 @@ using Microsoft.Build.Construction; using Microsoft.Build.Evaluation; -namespace ReadyToRun.SuperIlc +namespace R2RTest { /// /// This class represents a single test exclusion read from the issues.targets file. @@ -163,7 +163,8 @@ public static TestExclusionMap Create(BuildOptions options) Project project = new Project(); project.SetGlobalProperty("XunitTestBinBase", "*"); - project.SetGlobalProperty("BuildArch", "x64"); + project.SetGlobalProperty("TargetArchitecture", "x64"); + project.SetGlobalProperty("RuntimeFlavor", "coreclr"); // TODO: cross-OS CPAOT project.SetGlobalProperty("TargetsWindows", (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "true" : "false")); project.SetGlobalProperty("AltJitArch", "x64"); diff --git a/src/coreclr/src/unwinder/CMakeLists.txt b/src/coreclr/src/unwinder/CMakeLists.txt index 4421ea9f6f649c..8be5f3b21ea6da 100644 --- a/src/coreclr/src/unwinder/CMakeLists.txt +++ b/src/coreclr/src/unwinder/CMakeLists.txt @@ -29,8 +29,3 @@ add_dependencies(unwinder_dac eventing_headers) set_target_properties(unwinder_dac PROPERTIES DAC_COMPONENT TRUE) target_compile_definitions(unwinder_dac PRIVATE FEATURE_NO_HOST) -add_library_clr(unwinder_dac_amd64 ${UNWINDER_SOURCES}) -add_dependencies(unwinder_dac_amd64 eventing_headers) -set_target_properties(unwinder_dac_amd64 PROPERTIES DAC_COMPONENT TRUE) -target_compile_definitions(unwinder_dac_amd64 PRIVATE FEATURE_NO_HOST) - diff --git a/src/coreclr/src/unwinder/stdafx.h b/src/coreclr/src/unwinder/stdafx.h index 27b419b49707dd..5b7d4f8170c106 100644 --- a/src/coreclr/src/unwinder/stdafx.h +++ b/src/coreclr/src/unwinder/stdafx.h @@ -12,6 +12,7 @@ #define USE_COM_CONTEXT_DEF #include + #include #include #ifdef DACCESS_COMPILE diff --git a/src/coreclr/src/utilcode/ccomprc.cpp b/src/coreclr/src/utilcode/ccomprc.cpp index 4e2c9b97a5ed74..797bc7bd49c255 100644 --- a/src/coreclr/src/utilcode/ccomprc.cpp +++ b/src/coreclr/src/utilcode/ccomprc.cpp @@ -5,7 +5,6 @@ #include "stdafx.h" // Standard header. #include // Utility helpers. #include -#include "ndpversion.h" #include "../dlls/mscorrc/resource.h" #ifdef HOST_UNIX diff --git a/src/coreclr/src/utilcode/clrconfig.cpp b/src/coreclr/src/utilcode/clrconfig.cpp index e52afa54713874..fcb43894bccb7f 100644 --- a/src/coreclr/src/utilcode/clrconfig.cpp +++ b/src/coreclr/src/utilcode/clrconfig.cpp @@ -105,34 +105,13 @@ BOOL CLRConfig::IsConfigEnabled(const ConfigDWORDInfo & info) REGUTIL::CORConfigLevel level = GetConfigLevel(info.options); BOOL prependCOMPlus = !CheckLookupOption(info, DontPrependCOMPlus_); - // - // If we aren't favoring config files, we check REGUTIL here. - // - if(CheckLookupOption(info, FavorConfigFile) == FALSE) - { - REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &result, level, prependCOMPlus); - if(result>0) - return TRUE; - LPWSTR result = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPlus, level); - if(result != NULL && result[0] != 0) - { - return TRUE; - } - } - - // - // If we are favoring config files and we don't have a result from EEConfig, we check REGUTIL here. - // - if(CheckLookupOption(info, FavorConfigFile) == TRUE) + REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &result, level, prependCOMPlus); + if(result>0) + return TRUE; + LPWSTR result2 = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPlus, level); + if(result2 != NULL && result2[0] != 0) { - REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &result, level, prependCOMPlus); - if(result>0) - return TRUE; - LPWSTR result = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPlus, level); - if(result != NULL && result[0] != 0) - { - return TRUE; - } + return TRUE; } if(info.defaultValue>0) @@ -178,63 +157,27 @@ DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info, bool acceptExplici REGUTIL::CORConfigLevel level = GetConfigLevel(info.options); BOOL prependCOMPlus = !CheckLookupOption(info, DontPrependCOMPlus_); - // - // If we aren't favoring config files, we check REGUTIL here. - // - if (CheckLookupOption(info, FavorConfigFile) == FALSE) - { - DWORD resultMaybe; - HRESULT hr = REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &resultMaybe, level, prependCOMPlus); + DWORD resultMaybe; + HRESULT hr = REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &resultMaybe, level, prependCOMPlus); - if (!acceptExplicitDefaultFromRegutil) - { - // Ignore the default value even if it's set explicitly. - if (resultMaybe != info.defaultValue) - { - *isDefault = false; - return resultMaybe; - } - } - else + if (!acceptExplicitDefaultFromRegutil) + { + // Ignore the default value even if it's set explicitly. + if (resultMaybe != info.defaultValue) { - // If we are willing to accept the default value when it's set explicitly, - // checking the HRESULT here is sufficient. E_FAIL is returned when the - // default is used. - if (SUCCEEDED(hr)) - { - *isDefault = false; - return resultMaybe; - } + *isDefault = false; + return resultMaybe; } } - - // - // If we are favoring config files and we don't have a result from EEConfig, we check REGUTIL here. - // - if (CheckLookupOption(info, FavorConfigFile) == TRUE) + else { - DWORD resultMaybe; - HRESULT hr = REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &resultMaybe, level, prependCOMPlus); - - if (!acceptExplicitDefaultFromRegutil) - { - // Ignore the default value even if it's set explicitly. - if (resultMaybe != info.defaultValue) - { - *isDefault = false; - return resultMaybe; - } - } - else + // If we are willing to accept the default value when it's set explicitly, + // checking the HRESULT here is sufficient. E_FAIL is returned when the + // default is used. + if (SUCCEEDED(hr)) { - // If we are willing to accept the default value when it's set explicitly, - // checking the HRESULT here is sufficient. E_FAIL is returned when the - // default is used. - if (SUCCEEDED(hr)) - { - *isDefault = false; - return resultMaybe; - } + *isDefault = false; + return resultMaybe; } } @@ -319,22 +262,7 @@ HRESULT CLRConfig::GetConfigValue(const ConfigStringInfo & info, __deref_out_z L REGUTIL::CORConfigLevel level = GetConfigLevel(info.options); BOOL prependCOMPlus = !CheckLookupOption(info, DontPrependCOMPlus_); - // - // If we aren't favoring config files, we check REGUTIL here. - // - if(result == NULL && CheckLookupOption(info, FavorConfigFile) == FALSE) - { - result = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPlus, level); - } - - // - // If we are favoring config files and we don't have a result from EEConfig, we check REGUTIL here. - // - if(result==NULL && - CheckLookupOption(info, FavorConfigFile) == TRUE) - { - result = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPlus, level); - } + result = REGUTIL::GetConfigString_DontUse_(info.name, prependCOMPlus, level); if ((result != NULL) && CheckLookupOption(info, TrimWhiteSpaceFromStringValue)) { diff --git a/src/coreclr/src/utilcode/configuration.cpp b/src/coreclr/src/utilcode/configuration.cpp index eeeead447ef7ed..2cbf8cf3685ed4 100644 --- a/src/coreclr/src/utilcode/configuration.cpp +++ b/src/coreclr/src/utilcode/configuration.cpp @@ -79,7 +79,7 @@ DWORD Configuration::GetKnobDWORDValue(LPCWSTR name, DWORD defaultValue) return defaultValue; } -ULONGLONG Configuration::GetKnobULONGLONGValue(LPCWSTR name) +ULONGLONG Configuration::GetKnobULONGLONGValue(LPCWSTR name, ULONGLONG defaultValue) { LPCWSTR knobValue = GetConfigurationValue(name); if (knobValue != nullptr) @@ -87,7 +87,7 @@ ULONGLONG Configuration::GetKnobULONGLONGValue(LPCWSTR name) return _wcstoui64(knobValue, nullptr, 0); } - return 0; + return defaultValue; } LPCWSTR Configuration::GetKnobStringValue(LPCWSTR name, const CLRConfig::ConfigStringInfo& stringInfo) diff --git a/src/coreclr/src/utilcode/debug.cpp b/src/coreclr/src/utilcode/debug.cpp index 4833b9cf33f622..80ec783644d665 100644 --- a/src/coreclr/src/utilcode/debug.cpp +++ b/src/coreclr/src/utilcode/debug.cpp @@ -23,6 +23,10 @@ extern "C" _CRTIMP int __cdecl _flushall(void); +#ifdef HOST_WINDOWS +void CreateCrashDumpIfEnabled(); +#endif + // Global state counter to implement SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE. Volatile g_DbgSuppressAllocationAsserts = 0; @@ -180,6 +184,9 @@ VOID TerminateOnAssert() STATIC_CONTRACT_DEBUG_ONLY; ShutdownLogging(); +#ifdef HOST_WINDOWS + CreateCrashDumpIfEnabled(); +#endif RaiseFailFastException(NULL, NULL, 0); } @@ -456,10 +463,13 @@ bool _DbgBreakCheck( #endif // For abort, just quit the app. case IDABORT: +#ifdef HOST_WINDOWS + CreateCrashDumpIfEnabled(); +#endif TerminateProcess(GetCurrentProcess(), 1); break; - // Tell caller to break at the correct loction. + // Tell caller to break at the correct location. case IDRETRY: if (IsDebuggerPresent()) { @@ -823,6 +833,9 @@ void DECLSPEC_NORETURN __FreeBuildAssertFail(const char *szFile, int iLine, cons ShutdownLogging(); +#ifdef HOST_WINDOWS + CreateCrashDumpIfEnabled(); +#endif RaiseFailFastException(NULL, NULL, 0); UNREACHABLE(); diff --git a/src/coreclr/src/utilcode/dlwrap.cpp b/src/coreclr/src/utilcode/dlwrap.cpp index abb46740c02f29..edcd33b04c644e 100644 --- a/src/coreclr/src/utilcode/dlwrap.cpp +++ b/src/coreclr/src/utilcode/dlwrap.cpp @@ -11,7 +11,6 @@ #include #include -#include DWORD GetFileVersionInfoSizeW_NoThrow( diff --git a/src/coreclr/src/utilcode/hostimpl.cpp b/src/coreclr/src/utilcode/hostimpl.cpp index 29716ee1b1f759..3e55bcc3cbdf77 100644 --- a/src/coreclr/src/utilcode/hostimpl.cpp +++ b/src/coreclr/src/utilcode/hostimpl.cpp @@ -75,3 +75,9 @@ void GetLastThrownObjectExceptionFromThread(Exception** ppException) { *ppException = NULL; } + +#ifdef HOST_WINDOWS +void CreateCrashDumpIfEnabled() +{ +} +#endif diff --git a/src/coreclr/src/utilcode/util.cpp b/src/coreclr/src/utilcode/util.cpp index c09496df7c4659..8c980df45dea16 100644 --- a/src/coreclr/src/utilcode/util.cpp +++ b/src/coreclr/src/utilcode/util.cpp @@ -19,6 +19,7 @@ #include "cor.h" #include "corinfo.h" #include "volatile.h" +#include "mdfileformat.h" #ifndef DACCESS_COMPILE UINT32 g_nClrInstanceId = 0; @@ -3030,58 +3031,6 @@ lDone: ; return param.fRet; } -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - -// To include definition of EXCEPTION_SOFTSO -#include "corexcep.h" - -// These functions provide limited support for corrupting exceptions -// outside the VM folder. Its limited since we don't have access to the -// throwable. -// -// These functions are also wrapped by the corresponding CEHelper -// methods in excep.cpp. - -// Given an exception code, this method returns a BOOL to indicate if the -// code belongs to a corrupting exception or not. -BOOL IsProcessCorruptedStateException(DWORD dwExceptionCode, BOOL fCheckForSO /*=TRUE*/) -{ - LIMITED_METHOD_CONTRACT; - - // By default, assume its not corrupting - BOOL fIsCorruptedStateException = FALSE; - - if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_legacyCorruptedStateExceptionsPolicy) == 1) - { - return fIsCorruptedStateException; - } - - // If we have been asked not to include SO in the CSE check - // and the code represent SO, then exit now. - if ((fCheckForSO == FALSE) && (dwExceptionCode == STATUS_STACK_OVERFLOW)) - { - return fIsCorruptedStateException; - } - - switch(dwExceptionCode) - { - case STATUS_ACCESS_VIOLATION: - case STATUS_STACK_OVERFLOW: - case EXCEPTION_ILLEGAL_INSTRUCTION: - case EXCEPTION_IN_PAGE_ERROR: - case EXCEPTION_INVALID_DISPOSITION: - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - case EXCEPTION_PRIV_INSTRUCTION: - case STATUS_UNWIND_CONSOLIDATE: - fIsCorruptedStateException = TRUE; - break; - } - - return fIsCorruptedStateException; -} - -#endif // FEATURE_CORRUPTING_EXCEPTIONS - namespace Clr { namespace Util diff --git a/src/coreclr/src/utilcode/utilmessagebox.cpp b/src/coreclr/src/utilcode/utilmessagebox.cpp index 037c70e42ffa7a..993aef537b1555 100644 --- a/src/coreclr/src/utilcode/utilmessagebox.cpp +++ b/src/coreclr/src/utilcode/utilmessagebox.cpp @@ -15,7 +15,7 @@ #include "stdafx.h" // Standard header. #include // Utility helpers. #include -#include "ndpversion.h" +#include "clrversion.h" #include "../dlls/mscorrc/resource.h" #include "ex.h" #if !defined(FEATURE_CORESYSTEM) @@ -203,7 +203,7 @@ int UtilMessageBoxNonLocalizedVA( { StackSString message; - message.Printf(W(".NET Runtime version : %s - "), VER_FILEVERSION_STR_L); + message.Printf(W(".NET Runtime version : %s - "), CLR_PRODUCT_VERSION_L); if (lpTitle) message.Append(lpTitle); if (!formattedMessage.IsEmpty()) diff --git a/src/coreclr/src/utilcode/winfix.cpp b/src/coreclr/src/utilcode/winfix.cpp index b7fad1e79b3534..91d64c60b0917e 100644 --- a/src/coreclr/src/utilcode/winfix.cpp +++ b/src/coreclr/src/utilcode/winfix.cpp @@ -19,7 +19,6 @@ #include "winwrap.h" // Header for macros and functions. #include "utilcode.h" #include "holder.h" -#include "ndpversion.h" #include "pedecoder.h" diff --git a/src/coreclr/src/vm/.vscode/c_cpp_properties.json b/src/coreclr/src/vm/.vscode/c_cpp_properties.json index a4c0ec931c99ac..2a68e99359295e 100644 --- a/src/coreclr/src/vm/.vscode/c_cpp_properties.json +++ b/src/coreclr/src/vm/.vscode/c_cpp_properties.json @@ -53,7 +53,6 @@ "FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION", "FEATURE_CORECLR", "FEATURE_CORESYSTEM", - "FEATURE_CORRUPTING_EXCEPTIONS", "FEATURE_DATABREAKPOINT", "FEATURE_DEFAULT_INTERFACES", "FEATURE_EVENT_TRACE=1", diff --git a/src/coreclr/src/vm/CMakeLists.txt b/src/coreclr/src/vm/CMakeLists.txt index 2ce12c7250b461..dedb57d0414757 100644 --- a/src/coreclr/src/vm/CMakeLists.txt +++ b/src/coreclr/src/vm/CMakeLists.txt @@ -42,6 +42,7 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON assemblyloadcontext.cpp baseassemblyspec.cpp binder.cpp + bundle.cpp castcache.cpp callcounting.cpp ceeload.cpp @@ -106,6 +107,7 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON peimagelayout.cpp perfmap.cpp perfinfo.cpp + pgo.cpp precode.cpp prestub.cpp profilerdiagnosticprotocolhelper.cpp @@ -217,6 +219,7 @@ set(VM_HEADERS_DAC_AND_WKS_COMMON peimagelayout.inl perfmap.h perfinfo.h + pgo.h precode.h rejit.h rejit.inl @@ -364,6 +367,7 @@ set(VM_SOURCES_WKS interoputil.cpp interpreter.cpp invokeutil.cpp + ipcstreamfactory.cpp jithelpers.cpp managedmdimport.cpp marshalnative.cpp @@ -399,6 +403,7 @@ set(VM_SOURCES_WKS syncclean.cpp synch.cpp synchronizationcontextnative.cpp + tailcallhelp.cpp threaddebugblockinginfo.cpp threadsuspend.cpp typeparse.cpp @@ -482,6 +487,7 @@ set(VM_HEADERS_WKS interpreter.h interpreter.hpp invokeutil.h + ipcstreamfactory.h managedmdimport.hpp marshalnative.h methodtablebuilder.h @@ -517,6 +523,7 @@ set(VM_HEADERS_WKS syncclean.hpp synch.h synchronizationcontextnative.h + tailcallhelp.h tieredcompilation.h threaddebugblockinginfo.h threadsuspend.h @@ -782,7 +789,6 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64) ) set(VM_SOURCES_WKS_ARCH - ${ARCH_SOURCES_DIR}/jithelpersamd64.cpp ${ARCH_SOURCES_DIR}/jitinterfaceamd64.cpp ${ARCH_SOURCES_DIR}/profiler.cpp exceptionhandling.cpp @@ -835,7 +841,6 @@ elseif(CLR_CMAKE_TARGET_ARCH_ARM) ) set(VM_SOURCES_WKS_ARCH - ${ARCH_SOURCES_DIR}/jithelpersarm.cpp ${ARCH_SOURCES_DIR}/profiler.cpp exceptionhandling.cpp gcinfodecoder.cpp diff --git a/src/coreclr/src/vm/amd64/JitHelpers_Fast.asm b/src/coreclr/src/vm/amd64/JitHelpers_Fast.asm index 662c2d4509f829..8866399b41dd11 100644 --- a/src/coreclr/src/vm/amd64/JitHelpers_Fast.asm +++ b/src/coreclr/src/vm/amd64/JitHelpers_Fast.asm @@ -389,114 +389,6 @@ endif ret LEAF_END_MARKED JIT_ByRefWriteBarrier, _TEXT - -extern JIT_FailFast:proc -extern s_gsCookie:qword - -OFFSETOF_GSCOOKIE equ 0h -OFFSETOF_FRAME equ OFFSETOF_GSCOOKIE + \ - 8h - -; -; incoming: -; -; rsp -> return address -; : -; -; Stack Layout: -; -; rsp-> callee scratch -; + 8h callee scratch -; +10h callee scratch -; +18h callee scratch -; : -; stack arguments -; : -; r13-> gsCookie -; + 8h __VFN_table -; +10h m_Next -; +18h m_pGCLayout -; +20h m_padding -; +28h m_rdi -; +30h m_rsi -; +38h m_rbx -; +40h m_rbp -; +48h m_r12 -; +50h m_r13 -; +58h m_r14 -; +60h m_r15 -; +68h m_ReturnAddress -; r12 -> // Caller's SP -; -; r14 = GetThread(); -; r15 = GetThread()->GetFrame(); // For restoring/popping the frame -; -NESTED_ENTRY TailCallHelperStub, _TEXT - PUSH_CALLEE_SAVED_REGISTERS - - alloc_stack 48h ; m_padding, m_pGCLayout, m_Next, __VFN_table, gsCookie, outgoing shadow area - - set_frame r13, 20h - END_PROLOGUE - - ; - ; This part is never executed, but we keep it here for reference - ; - int 3 - -if 0 ne 0 - ; Save the caller's SP - mov r12, rsp + ... - - ; - ; fully initialize the TailCallFrame - ; - call TCF_GETMETHODFRAMEVPTR - mov [r13 + OFFSETOF_FRAME], rax - - mov rax, s_gsCookie - mov [r13 + OFFSETOF_GSCOOKIE], rax - - ; - ; link the TailCallFrame - ; - INLINE_GETTHREAD r14 - mov r15, [r14 + OFFSETOF__Thread__m_pFrame] - mov [r13 + OFFSETOF_FRAME + OFFSETOF__Frame__m_Next], r15 - lea r10, [r13 + OFFSETOF_FRAME] - mov [r14 + OFFSETOF__Thread__m_pFrame], r10 -endif - - ; the pretend call would be here - ; with the return address pointing this this real epilog - -PATCH_LABEL JIT_TailCallHelperStub_ReturnAddress - - ; our epilog (which also unlinks the TailCallFrame) - -ifdef _DEBUG - mov rcx, s_gsCookie - cmp [r13 + OFFSETOF_GSCookie], rcx - je GoodGSCookie - call JIT_FailFast -GoodGSCookie: -endif ; _DEBUG - - ; - ; unlink the TailCallFrame - ; - mov [r14 + OFFSETOF__Thread__m_pFrame], r15 - - ; - ; epilog - ; - - lea rsp, [r13 + 28h] - POP_CALLEE_SAVED_REGISTERS - ret - -NESTED_END TailCallHelperStub, _TEXT - ; The following helper will access ("probe") a word on each page of the stack ; starting with the page right beneath rsp down to the one pointed to by r11. ; The procedure is needed to make sure that the "guard" page is pushed down below the allocated stack frame. diff --git a/src/coreclr/src/vm/amd64/cgenamd64.cpp b/src/coreclr/src/vm/amd64/cgenamd64.cpp index 35d00720264c8a..320884a50f46f0 100644 --- a/src/coreclr/src/vm/amd64/cgenamd64.cpp +++ b/src/coreclr/src/vm/amd64/cgenamd64.cpp @@ -77,40 +77,6 @@ void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); } -#ifndef DACCESS_COMPILE - -void TailCallFrame::InitFromContext(T_CONTEXT * pContext) -{ - WRAPPER_NO_CONTRACT; - -#define CALLEE_SAVED_REGISTER(regname) m_calleeSavedRegisters.regname = pContext->regname; - ENUM_CALLEE_SAVED_REGISTERS(); -#undef CALLEE_SAVED_REGISTER - - m_pGCLayout = 0; - m_ReturnAddress = pContext->Rip; -} - -#endif // !DACCESS_COMPILE - -void TailCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) -{ - LIMITED_METHOD_CONTRACT; - - pRD->IsCallerContextValid = FALSE; - pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. - - pRD->pCurrentContext->Rip = m_ReturnAddress; - pRD->pCurrentContext->Rsp = dac_cast(this) + sizeof(*this); - - UpdateRegDisplayFromCalleeSavedRegisters(pRD, &m_calleeSavedRegisters); - ClearRegDisplayArgumentAndScratchRegisters(pRD); - - SyncRegDisplayToCurrentContext(pRD); - - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); -} - void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) { CONTRACTL diff --git a/src/coreclr/src/vm/amd64/excepamd64.cpp b/src/coreclr/src/vm/amd64/excepamd64.cpp index 4fc72827a8307f..bfe2ca6f4da5ec 100644 --- a/src/coreclr/src/vm/amd64/excepamd64.cpp +++ b/src/coreclr/src/vm/amd64/excepamd64.cpp @@ -26,6 +26,7 @@ #include "asmconstants.h" #include "exceptionhandling.h" +#include "virtualcallstub.h" @@ -573,9 +574,52 @@ AdjustContextForVirtualStub( { LIMITED_METHOD_CONTRACT; - // Nothing to adjust + Thread * pThread = GetThread(); - return FALSE; + // We may not have a managed thread object. Example is an AV on the helper thread. + // (perhaps during StubManager::IsStub) + if (pThread == NULL) + { + return FALSE; + } + + PCODE f_IP = GetIP(pContext); + + VirtualCallStubManager::StubKind sk; + VirtualCallStubManager::FindStubManager(f_IP, &sk); + + if (sk == VirtualCallStubManager::SK_DISPATCH) + { + if ((*PTR_DWORD(f_IP) & 0xffffff) != X64_INSTR_CMP_IND_THIS_REG_RAX) // cmp [THIS_REG], rax + { + _ASSERTE(!"AV in DispatchStub at unknown instruction"); + return FALSE; + } + } + else + if (sk == VirtualCallStubManager::SK_RESOLVE) + { + if ((*PTR_DWORD(f_IP) & 0xffffff) != X64_INSTR_MOV_RAX_IND_THIS_REG) // mov rax, [THIS_REG] + { + _ASSERTE(!"AV in ResolveStub at unknown instruction"); + return FALSE; + } + SetSP(pContext, dac_cast(dac_cast(GetSP(pContext)) + sizeof(void*))); // rollback push rdx + } + else + { + return FALSE; + } + + PCODE callsite = *dac_cast(GetSP(pContext)); + if (pExceptionRecord != NULL) + { + pExceptionRecord->ExceptionAddress = (PVOID)callsite; + } + SetIP(pContext, callsite); + SetSP(pContext, dac_cast(dac_cast(GetSP(pContext)) + sizeof(void*))); // Move SP to where it was at the call site + + return TRUE; } #endif diff --git a/src/coreclr/src/vm/amd64/jithelpersamd64.cpp b/src/coreclr/src/vm/amd64/jithelpersamd64.cpp deleted file mode 100644 index 8f0a889fde231e..00000000000000 --- a/src/coreclr/src/vm/amd64/jithelpersamd64.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// =========================================================================== -// File: JITHelpers.CPP -// =========================================================================== - -// This contains JITinterface routines that are specific to the -// AMD64 platform. They are modeled after the X86 specific routines -// found in JIThelp.asm - - -#include "common.h" -#include "jitinterface.h" -#include "eeconfig.h" -#include "excep.h" -#include "ecall.h" -#include "asmconstants.h" - -EXTERN_C void JIT_TailCallHelperStub_ReturnAddress(); - -TailCallFrame * TailCallFrame::GetFrameFromContext(CONTEXT * pContext) -{ - _ASSERTE((void*)::GetIP(pContext) == JIT_TailCallHelperStub_ReturnAddress); - return (TailCallFrame*)(pContext->R13 + sizeof(GSCookie)); -} - -// Assuming pContext is a plain generic call-site, adjust it to look like -// it called into TailCallHelperStub, and is at the point of the call. -TailCallFrame * TailCallFrame::AdjustContextForTailCallHelperStub(CONTEXT * pContext, size_t cbNewArgArea, Thread * pThread) -{ - TailCallFrame * pNewFrame = (TailCallFrame *)(GetSP(pContext) - sizeof(TailCallFrame)); - - // R13 is the frame pointer (for popping the stack) - pContext->R13 = (size_t)pNewFrame - sizeof(GSCookie); - // R12 is the previous stack pointer, so we can determine if a return buffer from the - // immediate caller (and thus being discarded via the tail call), or someplace else - pContext->R12 = GetSP(pContext); - // for the args and pushed return address of the 'call' - SetSP(pContext, (size_t)pNewFrame - (cbNewArgArea + sizeof(void*) + sizeof(GSCookie))); - - // For popping the Frame, store the Thread - pContext->R14 = (DWORD_PTR)pThread; - // And the current head/top - pContext->R15 = (DWORD_PTR)pThread->GetFrame(); // m_Next - - return (TailCallFrame *) pNewFrame; -} diff --git a/src/coreclr/src/vm/amd64/virtualcallstubcpu.hpp b/src/coreclr/src/vm/amd64/virtualcallstubcpu.hpp index 510f60577374a6..c91a85432e4ea0 100644 --- a/src/coreclr/src/vm/amd64/virtualcallstubcpu.hpp +++ b/src/coreclr/src/vm/amd64/virtualcallstubcpu.hpp @@ -23,6 +23,16 @@ #pragma pack(push, 1) // since we are placing code, we want byte packing of the structs +// Codes of the instruction in the stub where the instruction access violation +// is converted to NullReferenceException at the caller site. +#ifdef UNIX_AMD64_ABI +#define X64_INSTR_CMP_IND_THIS_REG_RAX 0x073948 +#define X64_INSTR_MOV_RAX_IND_THIS_REG 0x078b48 +#else // UNIX_AMD64_ABI +#define X64_INSTR_CMP_IND_THIS_REG_RAX 0x013948 +#define X64_INSTR_MOV_RAX_IND_THIS_REG 0x018b48 +#endif // UNIX_AMD64_ABI + #define USES_LOOKUP_STUBS 1 /********************************************************************************************* @@ -594,13 +604,9 @@ void DispatchHolder::InitializeStatic() dispatchInit._entryPoint [0] = 0x48; dispatchInit._entryPoint [1] = 0xB8; dispatchInit._expectedMT = 0xcccccccccccccccc; - dispatchInit.part1 [0] = 0x48; - dispatchInit.part1 [1] = 0x39; -#ifdef UNIX_AMD64_ABI - dispatchInit.part1 [2] = 0x07; // RDI -#else - dispatchInit.part1 [2] = 0x01; // RCX -#endif + dispatchInit.part1 [0] = X64_INSTR_CMP_IND_THIS_REG_RAX & 0xff; + dispatchInit.part1 [1] = (X64_INSTR_CMP_IND_THIS_REG_RAX >> 8) & 0xff; + dispatchInit.part1 [2] = (X64_INSTR_CMP_IND_THIS_REG_RAX >> 16) & 0xff; dispatchInit.nopOp = 0x90; // Short dispatch stub initialization @@ -686,13 +692,9 @@ void ResolveHolder::InitializeStatic() resolveInit._resolveEntryPoint [1] = 0x49; resolveInit._resolveEntryPoint [2] = 0xBA; resolveInit._cacheAddress = 0xcccccccccccccccc; - resolveInit.part1 [ 0] = 0x48; - resolveInit.part1 [ 1] = 0x8B; -#ifdef UNIX_AMD64_ABI - resolveInit.part1 [ 2] = 0x07; // RDI -#else - resolveInit.part1 [ 2] = 0x01; // RCX -#endif + resolveInit.part1 [ 0] = X64_INSTR_MOV_RAX_IND_THIS_REG & 0xff; + resolveInit.part1 [ 1] = (X64_INSTR_MOV_RAX_IND_THIS_REG >> 8) & 0xff; + resolveInit.part1 [ 2] = (X64_INSTR_MOV_RAX_IND_THIS_REG >> 16) & 0xff; resolveInit.part1 [ 3] = 0x48; resolveInit.part1 [ 4] = 0x8B; resolveInit.part1 [ 5] = 0xD0; diff --git a/src/coreclr/src/vm/appdomain.cpp b/src/coreclr/src/vm/appdomain.cpp index 02c34950e0c5c6..2e39d011b49d85 100644 --- a/src/coreclr/src/vm/appdomain.cpp +++ b/src/coreclr/src/vm/appdomain.cpp @@ -1761,38 +1761,33 @@ void SystemDomain::Init() sizeof(MethodDesc), sizeof(FieldDesc), sizeof(Module) - )); + )); #endif // _DEBUG // The base domain is initialized in SystemDomain::Attach() // to allow stub caches to use the memory pool. Do not // initialze it here! -#ifdef FEATURE_PREJIT if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ZapDisable) != 0) g_fAllowNativeImages = false; -#endif m_pSystemFile = NULL; m_pSystemAssembly = NULL; DWORD size = 0; - // Get the install directory so we can find mscorlib hr = GetInternalSystemDirectory(NULL, &size); if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) ThrowHR(hr); // GetInternalSystemDirectory returns a size, including the null! - WCHAR *buffer = m_SystemDirectory.OpenUnicodeBuffer(size-1); + WCHAR* buffer = m_SystemDirectory.OpenUnicodeBuffer(size - 1); IfFailThrow(GetInternalSystemDirectory(buffer, &size)); m_SystemDirectory.CloseBuffer(); m_SystemDirectory.Normalize(); // At this point m_SystemDirectory should already be canonicalized - - m_BaseLibrary.Append(m_SystemDirectory); if (!m_BaseLibrary.EndsWith(DIRECTORY_SEPARATOR_CHAR_W)) { @@ -1827,7 +1822,7 @@ void SystemDomain::Init() #ifdef _DEBUG BOOL fPause = EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_PauseOnLoad, FALSE); - while(fPause) + while (fPause) { ClrSleepEx(20, TRUE); } diff --git a/src/coreclr/src/vm/appdomain.hpp b/src/coreclr/src/vm/appdomain.hpp index 0ca41f064ee5c6..f017b42c73a2a2 100644 --- a/src/coreclr/src/vm/appdomain.hpp +++ b/src/coreclr/src/vm/appdomain.hpp @@ -1110,10 +1110,10 @@ class BaseDomain return ::CreateRefcountedHandle(m_handleStore, object); } - OBJECTHANDLE CreateWinRTWeakHandle(OBJECTREF object, IWeakReference* pWinRTWeakReference) + OBJECTHANDLE CreateNativeComWeakHandle(OBJECTREF object, IWeakReference* pComWeakReference) { WRAPPER_NO_CONTRACT; - return ::CreateWinRTWeakHandle(m_handleStore, object, pWinRTWeakReference); + return ::CreateNativeComWeakHandle(m_handleStore, object, pComWeakReference); } #endif // FEATURE_COMINTEROP diff --git a/src/coreclr/src/vm/arm/asmhelpers.S b/src/coreclr/src/vm/arm/asmhelpers.S index 0bb2dbee981fc9..e7f61937d886a1 100644 --- a/src/coreclr/src/vm/arm/asmhelpers.S +++ b/src/coreclr/src/vm/arm/asmhelpers.S @@ -134,119 +134,6 @@ LOCAL_LABEL(LReturnDone): NESTED_END CallDescrWorkerInternal,_TEXT - -//----------------------------------------------------------------------------- -// This helper routine is where returns for irregular tail calls end up -// so they can dynamically pop their stack arguments. -//----------------------------------------------------------------------------- -// -// Stack Layout (stack grows up, 0 at the top, offsets relative to frame pointer, r7): -// -// sp -> callee stack arguments -// : -// : -// -0Ch gsCookie -// TailCallHelperFrame -> -// -08h __VFN_table -// -04h m_Next -// r7 -> -// +00h m_calleeSavedRgisters.r4 -// +04h .r5 -// +08h .r6 -// +0Ch .r7 -// +10h .r8 -// +14h .r9 -// +18h .r10 -// r11-> -// +1Ch .r11 -// +20h .r14 -or- m_ReturnAddress -// -// r6 -> GetThread() -// r5 -> r6->m_pFrame (old Frame chain head) -// r11 is used to preserve the ETW call stack - - NESTED_ENTRY TailCallHelperStub, _TEXT, NoHandler - // - // This prolog is never executed, but we keep it here for reference - // and for the unwind data it generates - // - - // Spill callee saved registers and return address. - PROLOG_PUSH "{r4-r11,lr}" - - PROLOG_STACK_SAVE_OFFSET r7, #12 - - // - // This is the code that would have to run to setup this frame - // like the C++ helper does before calling RtlRestoreContext - // - // Allocate space for the rest of the frame and GSCookie. - // PROLOG_STACK_ALLOC 0x0C - // - // Set r11 for frame chain - //add r11, r7, 0x1C - // - // Set the vtable for TailCallFrame - //bl TCF_GETMETHODFRAMEVPTR - //str r0, [r7, #-8] - // - // Initialize the GSCookie within the Frame - //ldr r0, =s_gsCookie - //str r0, [r7, #-0x0C] - // - // Link the TailCallFrameinto the Frame chain - // and initialize r5 & r6 for unlinking later - //CALL_GETTHREAD - //mov r6, r0 - //ldr r5, [r6, #Thread__m_pFrame] - //str r5, [r7, #-4] - //sub r0, r7, 8 - //str r0, [r6, #Thread__m_pFrame] - // - // None of the previous stuff is ever executed, - // but we keep it here for reference - // - - // - // Here's the pretend call (make it real so the unwinder - // doesn't think we're in the prolog) - // - bl C_FUNC(TailCallHelperStub) - // - // with the real return address pointing to this real epilog - // -C_FUNC(JIT_TailCallHelperStub_ReturnAddress): -.global C_FUNC(JIT_TailCallHelperStub_ReturnAddress) - - // - // Our epilog (which also unlinks the StubHelperFrame) - // Be careful not to trash the return registers - // - -#ifdef _DEBUG - ldr r3, =s_gsCookie - ldr r3, [r3] - ldr r2, [r7, #-0x0C] - cmp r2, r3 - beq LOCAL_LABEL(GoodGSCookie) - bl C_FUNC(DoJITFailFast) -LOCAL_LABEL(GoodGSCookie): -#endif // _DEBUG - - // - // unlink the TailCallFrame - // - str r5, [r6, #Thread__m_pFrame] - - // - // epilog - // - EPILOG_STACK_RESTORE_OFFSET r7, #12 - EPILOG_POP "{r4-r11,lr}" - bx lr - - NESTED_END TailCallHelperStub, _TEXT - // ------------------------------------------------------------------ // void LazyMachStateCaptureState(struct LazyMachState *pState)// diff --git a/src/coreclr/src/vm/arm/asmhelpers.asm b/src/coreclr/src/vm/arm/asmhelpers.asm index a76f1103c13ac5..26b8619aef3c66 100644 --- a/src/coreclr/src/vm/arm/asmhelpers.asm +++ b/src/coreclr/src/vm/arm/asmhelpers.asm @@ -62,9 +62,6 @@ #endif IMPORT JIT_RareDisableHelperWorker - IMPORT DoJITFailFast - IMPORT s_gsCookie - IMPORT g_TrapReturningThreads ;; Imports for singleDomain statics helpers IMPORT JIT_GetSharedNonGCStaticBase_Helper @@ -193,119 +190,6 @@ LReturnDone NESTED_END - -;;----------------------------------------------------------------------------- -;; This helper routine is where returns for irregular tail calls end up -:: so they can dynamically pop their stack arguments. -;;----------------------------------------------------------------------------- -; -; Stack Layout (stack grows up, 0 at the top, offsets relative to frame pointer, r7): -; -; sp -> callee stack arguments -; : -; : -; -0Ch gsCookie -; TailCallHelperFrame -> -; -08h __VFN_table -; -04h m_Next -; r7 -> -; +00h m_calleeSavedRgisters.r4 -; +04h .r5 -; +08h .r6 -; +0Ch .r7 -; +10h .r8 -; +14h .r9 -; +18h .r10 -; r11-> -; +1Ch .r11 -; +20h .r14 -or- m_ReturnAddress -; -; r6 -> GetThread() -; r5 -> r6->m_pFrame (old Frame chain head) -; r11 is used to preserve the ETW call stack - - NESTED_ENTRY TailCallHelperStub - ; - ; This prolog is never executed, but we keep it here for reference - ; and for the unwind data it generates - ; - - ; Spill callee saved registers and return address. - PROLOG_PUSH {r4-r11,lr} - - PROLOG_STACK_SAVE r7 - - ; - ; This is the code that would have to run to setup this frame - ; like the C++ helper does before calling RtlRestoreContext - ; - ; Allocate space for the rest of the frame and GSCookie. - ; PROLOG_STACK_ALLOC 0x0C - ; - ; Set r11 for frame chain - ;add r11, r7, 0x1C - ; - ; Set the vtable for TailCallFrame - ;bl TCF_GETMETHODFRAMEVPTR - ;str r0, [r7, #-8] - ; - ; Initialize the GSCookie within the Frame - ;ldr r0, =s_gsCookie - ;str r0, [r7, #-0x0C] - ; - ; Link the TailCallFrameinto the Frame chain - ; and initialize r5 & r6 for unlinking later - ;CALL_GETTHREAD - ;mov r6, r0 - ;ldr r5, [r6, #Thread__m_pFrame] - ;str r5, [r7, #-4] - ;sub r0, r7, 8 - ;str r0, [r6, #Thread__m_pFrame] - ; - ; None of the previous stuff is ever executed, - ; but we keep it here for reference - ; - - ; - ; Here's the pretend call (make it real so the unwinder - ; doesn't think we're in the prolog) - ; - bl TailCallHelperStub - ; - ; with the real return address pointing to this real epilog - ; -JIT_TailCallHelperStub_ReturnAddress - EXPORT JIT_TailCallHelperStub_ReturnAddress - - ; - ; Our epilog (which also unlinks the StubHelperFrame) - ; Be careful not to trash the return registers - ; - -#ifdef _DEBUG - ldr r3, =s_gsCookie - ldr r3, [r3] - ldr r2, [r7, #-0x0C] - cmp r2, r3 - beq GoodGSCookie - bl DoJITFailFast -GoodGSCookie -#endif ; _DEBUG - - ; - ; unlink the TailCallFrame - ; - str r5, [r6, #Thread__m_pFrame] - - ; - ; epilog - ; - EPILOG_STACK_RESTORE r7 - EPILOG_POP {r4-r11,lr} - EPILOG_RETURN - - NESTED_END - ; ------------------------------------------------------------------ ; void LazyMachStateCaptureState(struct LazyMachState *pState); diff --git a/src/coreclr/src/vm/arm/cgencpu.h b/src/coreclr/src/vm/arm/cgencpu.h index edd80606ffd3c2..7b23a51c61a564 100644 --- a/src/coreclr/src/vm/arm/cgencpu.h +++ b/src/coreclr/src/vm/arm/cgencpu.h @@ -784,19 +784,6 @@ class StubLinkerCPU : public StubLinker Emit16((WORD)((imm3 << 12) | (dest << 8) | imm8)); } - void ThumbEmitCmpReg(ThumbReg reg1, ThumbReg reg2) - { - if(reg1 < 8 && reg2 <8) - { - Emit16((WORD)(0x4280 | reg2 << 3 | reg1)); - } - else - { - _ASSERTE(reg1 != ThumbReg(15) && reg2 != ThumbReg(15)); - Emit16((WORD)(0x4500 | reg2 << 3 | (reg1 & 0x7) | (reg1 & 0x8 ? 0x80 : 0x0))); - } - } - void ThumbEmitIncrement(ThumbReg dest, unsigned int value) { while (value) @@ -934,25 +921,11 @@ class StubLinkerCPU : public StubLinker } #endif // FEATURE_INTERPRETER - void ThumbEmitCondFlagJump(CodeLabel * target,UINT cond); - - void ThumbEmitCondRegJump(CodeLabel *target, BOOL nonzero, ThumbReg reg); - - void ThumbEmitNearJump(CodeLabel *target); - // Scratches r12. - void ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall); + void ThumbEmitTailCallManagedMethod(MethodDesc *pMD); void EmitShuffleThunk(struct ShuffleEntry *pShuffleEntryArray); VOID EmitComputedInstantiatingMethodStub(MethodDesc* pSharedMD, struct ShuffleEntry *pShuffleEntryArray, void* extraArg); - - static Stub * CreateTailCallCopyArgsThunk(CORINFO_SIG_INFO * pSig, - MethodDesc* pMD, - CorInfoHelperTailCallSpecialHandling flags); - -private: - void ThumbCopyOneTailCallArg(UINT * pnSrcAlign, const ArgLocDesc * pArgLoc, UINT * pcbStackSpace); - void ThumbEmitCallWithGenericInstantiationParameter(MethodDesc *pMD, void *pHiddenArg); }; extern "C" void SinglecastDelegateInvokeStub(); diff --git a/src/coreclr/src/vm/arm/jithelpersarm.cpp b/src/coreclr/src/vm/arm/jithelpersarm.cpp deleted file mode 100644 index 40827dd7127b8a..00000000000000 --- a/src/coreclr/src/vm/arm/jithelpersarm.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// =========================================================================== -// File: JITHelpersARM.CPP -// =========================================================================== - -// This contains JITinterface routines that are specific to the -// ARM platform. They are modeled after the AMD64 specific routines -// found in JIThelpersAMD64.cpp - - -#include "common.h" -#include "jitinterface.h" -#include "eeconfig.h" -#include "excep.h" -#include "ecall.h" -#include "asmconstants.h" - -EXTERN_C void JIT_TailCallHelperStub_ReturnAddress(); - -TailCallFrame * TailCallFrame::GetFrameFromContext(CONTEXT * pContext) -{ - _ASSERTE((void*)::GetIP(pContext) == JIT_TailCallHelperStub_ReturnAddress); - return (TailCallFrame*)(pContext->R7 - offsetof(TailCallFrame, m_calleeSavedRegisters)); -} - -// Assuming pContext is a plain generic call-site, adjust it to look like -// it called into TailCallHelperStub, and is at the point of the call. -TailCallFrame * TailCallFrame::AdjustContextForTailCallHelperStub(CONTEXT * pContext, size_t cbNewArgArea, Thread * pThread) -{ - TailCallFrame * pNewFrame = (TailCallFrame *) (GetSP(pContext) - sizeof(TailCallFrame)); - - // The return addres for the pseudo-call - pContext->Lr = (DWORD_PTR)JIT_TailCallHelperStub_ReturnAddress; - // The R11/ETW chain 'frame' pointer - pContext->R11 = GetSP(pContext) - (2 * sizeof(DWORD)); // LR & R11 - // The unwind data frame pointer - pContext->R7 = pContext->R11 - (7 * sizeof(DWORD)); // r4-R10 non-volatile registers - // for the args and the remainder of the FrameWithCookie - SetSP(pContext, (size_t) pNewFrame - (cbNewArgArea + sizeof(GSCookie))); - - // For popping the Frame, store the Thread - pContext->R6 = (DWORD_PTR)pThread; - // And the current head/top - pContext->R5 = (DWORD_PTR)pThread->GetFrame(); - - return pNewFrame; -} - diff --git a/src/coreclr/src/vm/arm/stubs.cpp b/src/coreclr/src/vm/arm/stubs.cpp index 0a23cc413dd874..caa80afc9831d9 100644 --- a/src/coreclr/src/vm/arm/stubs.cpp +++ b/src/coreclr/src/vm/arm/stubs.cpp @@ -1609,7 +1609,7 @@ VOID StubLinkerCPU::EmitShuffleThunk(ShuffleEntry *pShuffleEntryArray) #ifndef CROSSGEN_COMPILE -void StubLinkerCPU::ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall) +void StubLinkerCPU::ThumbEmitTailCallManagedMethod(MethodDesc *pMD) { bool isRelative = MethodTable::VTableIndir2_t::isRelative && pMD->IsVtableSlot(); @@ -1631,12 +1631,6 @@ void StubLinkerCPU::ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall) if (isRelative) { - if (!fTailcall) - { - // str r4, [sp, 0] - ThumbEmitStoreRegIndirect(ThumbReg(4), thumbRegSp, 0); - } - // mov r4, r12 ThumbEmitMovRegReg(ThumbReg(4), ThumbReg(12)); } @@ -1648,33 +1642,19 @@ void StubLinkerCPU::ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall) { // add r12, r4 ThumbEmitAddReg(ThumbReg(12), ThumbReg(4)); - - if (!fTailcall) - { - // ldr r4, [sp, 0] - ThumbEmitLoadRegIndirect(ThumbReg(4), thumbRegSp, 0); - } } } - if (fTailcall) + if (!isRelative) { - if (!isRelative) - { - // bx r12 - ThumbEmitJumpRegister(ThumbReg(12)); - } - else - { - // Replace LR with R12 on stack: hybrid-tail call, same as for EmitShuffleThunk - // str r12, [sp, 4] - ThumbEmitStoreRegIndirect(ThumbReg(12), thumbRegSp, 4); - } + // bx r12 + ThumbEmitJumpRegister(ThumbReg(12)); } else { - // blx r12 - ThumbEmitCallRegister(ThumbReg(12)); + // Replace LR with R12 on stack: hybrid-tail call, same as for EmitShuffleThunk + // str r12, [sp, 4] + ThumbEmitStoreRegIndirect(ThumbReg(12), thumbRegSp, 4); } } @@ -1745,7 +1725,7 @@ VOID StubLinkerCPU::EmitComputedInstantiatingMethodStub(MethodDesc* pSharedMD, s ThumbEmitProlog(1, 0, FALSE); } - ThumbEmitCallManagedMethod(pSharedMD, true); + ThumbEmitTailCallManagedMethod(pSharedMD); if (isRelative) { @@ -1819,47 +1799,6 @@ void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); } -void TailCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) -{ - pRD->IsCallerContextValid = FALSE; - pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. - - // Next, copy all the callee saved registers - UpdateRegDisplayFromCalleeSavedRegisters(pRD, &m_calleeSavedRegisters); - - // Set ControlPC to be the same as the saved "return address" - // value, which is actually a ControlPC in the frameless method (e.g. - // faulting address incase of AV or TAE). - pRD->pCurrentContext->Pc = m_ReturnAddress; - - // Set the caller SP - pRD->pCurrentContext->Sp = dac_cast(this) + sizeof(*this); - - // Finally, syncup the regdisplay with the context - SyncRegDisplayToCurrentContext(pRD); - - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); -} - -#ifndef DACCESS_COMPILE - -void TailCallFrame::InitFromContext(T_CONTEXT * pContext) -{ - WRAPPER_NO_CONTRACT; - - r4 = pContext->R4; - r5 = pContext->R5; - r6 = pContext->R6; - r7 = pContext->R7; - r8 = pContext->R8; - r9 = pContext->R9; - r10 = pContext->R10; - r11 = pContext->R11; - m_ReturnAddress = pContext->Lr; -} - -#endif // !DACCESS_COMPILE - void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) { LIMITED_METHOD_DAC_CONTRACT; @@ -2104,414 +2043,6 @@ void InitJITHelpers1() #endif // CROSSGEN_COMPILE -void StubLinkerCPU::ThumbEmitNearJump(CodeLabel *target) -{ - WRAPPER_NO_CONTRACT; - EmitLabelRef(target, reinterpret_cast(gThumbNearJump), 0xe); -} - -void StubLinkerCPU::ThumbEmitCondFlagJump(CodeLabel *target, UINT cond) -{ - WRAPPER_NO_CONTRACT; - EmitLabelRef(target, reinterpret_cast(gThumbNearJump), cond); -} - -void StubLinkerCPU::ThumbEmitCondRegJump(CodeLabel *target, BOOL nonzero, ThumbReg reg) -{ - WRAPPER_NO_CONTRACT; - _ASSERTE(reg <= 7); - UINT variation = reg; - if(nonzero) - variation = variation | 0x8; - EmitLabelRef(target, reinterpret_cast(gThumbCondJump), variation); -} - -void StubLinkerCPU::ThumbCopyOneTailCallArg(UINT * pnSrcAlign, const ArgLocDesc * pArgLoc, UINT * pcbStackSpace) -{ - if (pArgLoc->m_fRequires64BitAlignment && (*pnSrcAlign & 1)) { - // ADD R0, #4 - ThumbEmitIncrement(ThumbReg(0), 4); - *pnSrcAlign = 0; - } - - // Integer register arguments - if (pArgLoc->m_cGenReg > 0) { - int iReg = pArgLoc->m_idxGenReg; - int maxReg = iReg + pArgLoc->m_cGenReg; - while (iReg + 2 <= maxReg) { - // LDM r0!, {r4,r5} ; Post incremented loads (2 bytes) - ThumbEmitLoadStoreMultiple(ThumbReg(0), true, ThumbReg(4).Mask() | ThumbReg(5).Mask()); - // STR r4, [R1, #offset of arg reg] ; (2 bytes) - ThumbEmitStoreRegIndirect(ThumbReg(4), ThumbReg(1), offsetof(T_CONTEXT, R0) + (iReg * sizeof(DWORD))); - iReg++; - // STR r5, [R1, #offset of arg reg] ; (2 bytes) - ThumbEmitStoreRegIndirect(ThumbReg(5), ThumbReg(1), offsetof(T_CONTEXT, R0) + (iReg * sizeof(DWORD))); - iReg++; - } - if (iReg < maxReg) { - // LDR r3, [R0], #+4 ; Post incremented load (4 bytes) - ThumbEmitLoadIndirectPostIncrement(ThumbReg(3), ThumbReg(0), 4); - (*pnSrcAlign)++; - - // STR r3, [R1, #offset of arg reg] ; (2 bytes) - ThumbEmitStoreRegIndirect(ThumbReg(3), ThumbReg(1), offsetof(T_CONTEXT, R0) + (iReg * sizeof(DWORD))); - } - } - if (pArgLoc->m_cFloatReg > 0) { - int iReg = pArgLoc->m_idxFloatReg; - int maxReg = iReg + pArgLoc->m_cFloatReg; - while (iReg + 2 <= maxReg) { - // LDM r0!, {r4,r5} ; Post incremented loads (2 bytes) - ThumbEmitLoadStoreMultiple(ThumbReg(0), true, ThumbReg(4).Mask() | ThumbReg(5).Mask()); - // STR r4, [R1, #offset of arg reg] ; (2 bytes) - ThumbEmitStoreRegIndirect(ThumbReg(4), ThumbReg(1), offsetof(T_CONTEXT, S) + (iReg * sizeof(DWORD))); - iReg++; - // STR r5, [R1, #offset of arg reg] ; (2 bytes) - ThumbEmitStoreRegIndirect(ThumbReg(5), ThumbReg(1), offsetof(T_CONTEXT, S) + (iReg * sizeof(DWORD))); - iReg++; - } - if (iReg < maxReg) { - // LDR r3, [R0], #+4 ; Post incremented load (4 bytes) - ThumbEmitLoadIndirectPostIncrement(ThumbReg(3), ThumbReg(0), 4); - (*pnSrcAlign)++; - - // STR r3, [R1, #offset of arg reg] ; (2 bytes) - ThumbEmitStoreRegIndirect(ThumbReg(3), ThumbReg(1), offsetof(T_CONTEXT, S) + (iReg * sizeof(DWORD))); - } - } - - if (pArgLoc->m_cStack > 0) { - // Copy to the stack - // Be careful because this can get big and ugly. - _ASSERTE(*pcbStackSpace <= (pArgLoc->m_idxStack * sizeof(DWORD))); - - // Pad the output - if (*pcbStackSpace < (pArgLoc->m_idxStack * sizeof(DWORD))) - { - const UINT cbPad = ((pArgLoc->m_idxStack * sizeof(DWORD)) - *pcbStackSpace); - _ASSERTE(cbPad == 4); - // ADD R2, #4 - ThumbEmitIncrement(ThumbReg(2), cbPad); - *pcbStackSpace += cbPad; - } - int cStack = pArgLoc->m_cStack; - *pcbStackSpace += (cStack * sizeof(DWORD)); - - // Now start the copying - if (cStack > 8) { - // Loop to copy in 16-byte chunks per loop. - // Sacrifice r3 for the loop counter - ThumbEmitMovConstant(ThumbReg(3), pArgLoc->m_cStack & ~3); - // LoopLabel: - CodeLabel *pLoopLabel = NewCodeLabel(); - EmitLabel(pLoopLabel); - const WORD mask = ThumbReg(4).Mask() | ThumbReg(5).Mask() | ThumbReg(6).Mask() | ThumbReg(7).Mask(); - // LDM r0!, {r4,r5,r6,r7} ; Post incremented loads (2 bytes) - ThumbEmitLoadStoreMultiple(ThumbReg(0), true, mask); - // STM r2!, {r4,r5,r6,r7} ; Post incremented stores (2 bytes) - ThumbEmitLoadStoreMultiple(ThumbReg(2), false, mask); - // SUBS r3, #4 - Emit16((WORD)(0x3800 | (ThumbReg(3) << 8) | 4)); - // BNZ LoopLabel - ThumbEmitCondFlagJump(pLoopLabel, thumbCondNe.cond); - - cStack = cStack % 4; - // Now deal with the tail if any - } - _ASSERTE(cStack <= 8); - - while (cStack > 1) { - _ASSERTE(cStack >= 2); - WORD mask = ThumbReg(4).Mask() | ThumbReg(5).Mask(); - cStack -= 2; - if (cStack > 0) { - mask |= ThumbReg(6).Mask(); - cStack--; - // Instead of copying 4 slots and leaving a single slot remainder - // which would require us to use the bigger opcodes for the tail - // Only copy 3 slots this loop, saving 2 for next time. :) - if (cStack == 1 || cStack > 2) { - mask |= ThumbReg(7).Mask(); - cStack--; - } - else { - // We're reading an odd amount from the stack - (*pnSrcAlign)++; - } - } - - // LDM r0!, {r4,r5,r6,r7} ; Post incremented loads (2 bytes) - ThumbEmitLoadStoreMultiple(ThumbReg(0), true, mask); - // STM r2!, {r4,r5,r6,r7} ; Post incremented stores (2 bytes) - ThumbEmitLoadStoreMultiple(ThumbReg(2), false, mask); - _ASSERTE((cStack == 0) || (cStack >= 2)); - } - if (cStack > 0) { - _ASSERTE(cStack == 1); - // We're reading an odd amount from the stack - (*pnSrcAlign)++; - // LDR r12, [R0], #+4 ; Post incremented load (4 bytes) - ThumbEmitLoadIndirectPostIncrement(ThumbReg(12), ThumbReg(0), 4); - // STR r12, [R2], #+4 ; Post incremented store (4 bytes) - ThumbEmitStoreIndirectPostIncrement(ThumbReg(12), ThumbReg(2), 4); - } - } -} - - -Stub * StubLinkerCPU::CreateTailCallCopyArgsThunk(CORINFO_SIG_INFO * pSig, - MethodDesc* pMD, - CorInfoHelperTailCallSpecialHandling flags) -{ - STANDARD_VM_CONTRACT; - - CPUSTUBLINKER sl; - CPUSTUBLINKER* pSl = &sl; - - // Generates a function that looks like this: - // size_t CopyArguments(va_list args, (R0) - // CONTEXT *pCtx, (R1) - // DWORD *pvStack, (R2) - // size_t cbStack) (R3) - // { - // if (pCtx != NULL) { - // foreach (arg in args) { - // copy into pCtx or pvStack - // } - // } - // return ; - // } - // - - Module * module = GetModule(pSig->scope); - Instantiation classInst((TypeHandle*)pSig->sigInst.classInst, pSig->sigInst.classInstCount); - Instantiation methodInst((TypeHandle*)pSig->sigInst.methInst, pSig->sigInst.methInstCount); - SigTypeContext typeCtxt(classInst, methodInst); - - // The -8 is because R11 points at the pushed {R11, LR} pair, and it is aligned. - // This is the magic distance, between the frame pointer and the Frame. - const UINT cbFrameOffset = (sizeof(FrameWithCookie) - 8); - - bool fNeedExtraRegs = false; - UINT copyEstimate = 0; - { - // Do a quick scan of the arguments looking for ones that will probably need extra registers - // and guestimating the size of the method - if (flags & CORINFO_TAILCALL_STUB_DISPATCH_ARG) - copyEstimate += 6; - - if (pSig->hasThis()) - copyEstimate += 6; - - MetaSig msig(pSig->pSig, pSig->cbSig, module, &typeCtxt); - if (pSig->hasTypeArg()) - msig.SetHasParamTypeArg(); - ArgIterator argPlacer(&msig); - - if (argPlacer.HasRetBuffArg()) { - copyEstimate += 24; - } - - if (pSig->hasTypeArg() || pSig->isVarArg()) - copyEstimate += 6; - - int argOffset; - while ((argOffset = argPlacer.GetNextOffset()) != TransitionBlock::InvalidOffset) - { - ArgLocDesc argLoc; - argPlacer.GetArgLoc(argOffset, &argLoc); - - if (argLoc.m_cStack > 1 || argLoc.m_cGenReg > 1 || argLoc.m_cFloatReg > 1) { - fNeedExtraRegs = true; - } - else { - copyEstimate += 8; - } - } - } - - if (fNeedExtraRegs) { - // Inject a proper prolog - // push {r4-r7,lr} - pSl->ThumbEmitProlog(4, 0, false); - } - - CodeLabel *pNullLabel = pSl->NewCodeLabel(); - - if (!fNeedExtraRegs && copyEstimate < 100) { - // The real range of BCZ is 0-126, but that's hard to estimate that precisely - // and we don't want to do that much work just to save a few bytes - - // BCZ R1, NullLabel - pSl->ThumbEmitCondRegJump(pNullLabel, false, ThumbReg(1)); - } - else { - // CMP R1, 0 ; T1 encoding - pSl->Emit16((WORD)(0x2900)); - - // BEQ NullLabel - pSl->ThumbEmitCondFlagJump(pNullLabel, thumbCondEq.cond); - } - - UINT cbStackSpace = 0; - UINT cbReturnBufferSpace = 0; - UINT nSrcAlign = 0; - - if (flags & CORINFO_TAILCALL_STUB_DISPATCH_ARG) { - // This is set for stub dispatch or 'thisInSecretRegister' - // The JIT placed an extra argument in the list that needs to - // get shoved into R4, and not counted. - // pCtx->R4 = va_arg(args, DWORD); - - // LDR r3, [R0], #+4 ; Post incremented load (4 bytes) - pSl->ThumbEmitLoadIndirectPostIncrement(ThumbReg(3), ThumbReg(0), 4); - // STR r3, [R1, #offset of R4] ; (2 bytes) - pSl->ThumbEmitStoreRegIndirect(ThumbReg(3), ThumbReg(1), offsetof(T_CONTEXT, R4)); - nSrcAlign++; - } - - - MetaSig msig(pSig->pSig, pSig->cbSig, module, &typeCtxt); - if (pSig->hasTypeArg()) - msig.SetHasParamTypeArg(); - ArgIterator argPlacer(&msig); - ArgLocDesc argLoc; - - // First comes the 'this' pointer - if (argPlacer.HasThis()) { - argPlacer.GetThisLoc(&argLoc); - pSl->ThumbCopyOneTailCallArg(&nSrcAlign, &argLoc, &cbStackSpace); - } - - // Next comes the return buffer - if (argPlacer.HasRetBuffArg()) { - // We always reserve space for the return buffer, but we never zero it out, - // and we never report it. Thus the callee shouldn't do RVO and expect - // to be able to read GC pointers from it. - // If the passed in return buffer is already pointing above the frame, - // then we need to pass it along (so it will get passed out). - // Otherwise we assume the caller is returning void, so we just pass in - // dummy space to be overwritten. - - argPlacer.GetRetBuffArgLoc(&argLoc); - _ASSERTE(argLoc.m_cStack == 0); - _ASSERTE(argLoc.m_cFloatReg == 0); - _ASSERTE(argLoc.m_cGenReg == 1); - - // Grab some space from the top of the frame and pass that in as a dummy - // buffer if needed. Align to 8-byte boundary (after taking in account the Frame). - // Do this by adding the Frame size, align, then remove the Frame size... - _ASSERTE((pSig->retType == CORINFO_TYPE_REFANY) || (pSig->retType == CORINFO_TYPE_VALUECLASS)); - TypeHandle th(pSig->retTypeClass); - UINT cbUsed = ((th.GetSize() + cbFrameOffset + 0x7) & ~0x7) - cbFrameOffset; - _ASSERTE(cbUsed >= th.GetSize()); - cbReturnBufferSpace += cbUsed; - - // LDR r3, [R0], #+4 ; Post incremented load (4 bytes) - pSl->ThumbEmitLoadIndirectPostIncrement(ThumbReg(3), ThumbReg(0), 4); - - // LDR r12, [R1, #offset of R11] ; (2 bytes) - pSl->ThumbEmitLoadRegIndirect(ThumbReg(12), ThumbReg(1), offsetof(T_CONTEXT, R11)); - - // CMP r3, r12 ; (2 bytes) - pSl->ThumbEmitCmpReg(ThumbReg(3), ThumbReg(12)); - - CodeLabel *pSkipLabel = pSl->NewCodeLabel(); - // BHI NullLabel ; skip if R3 > R12 unsigned (2 bytes) - pSl->ThumbEmitCondFlagJump(pSkipLabel, thumbCondHi.cond); - - // Also check the lower bound of the stack in case the return buffer is on the GC heap - // and the GC heap is below the stack - // CMP r3, sp ; (2 bytes) - pSl->ThumbEmitCmpReg(ThumbReg(3), thumbRegSp); - // BLO NullLabel ; skip if r3 < sp unsigned (2 bytes) - pSl->ThumbEmitCondFlagJump(pSkipLabel, thumbCondCc.cond); - - // If the caller is expecting us to simulate a return buffer for the callee - // pass that pointer in now, by subtracting from R11 space for the Frame - // and space for the return buffer. - UINT offset = cbUsed + cbFrameOffset; - if (offset < 4096) { - // SUB r3, r12, #offset ; (4 bytes) - pSl->ThumbEmitSub(ThumbReg(3), ThumbReg(12), offset); - } - else { - offset = UINT(-int(offset)); // Silence the @#$%^ warning - // MOVW/MOVT (4-8 bytes) - // ADD r3, r12; (2 bytes) - pSl->ThumbEmitAdd(ThumbReg(3), ThumbReg(12), offset); - } - // SkipLabel: - pSl->EmitLabel(pSkipLabel); - // STR r3, [R1, #offset of arg reg] ; (2 bytes) - pSl->ThumbEmitStoreRegIndirect(ThumbReg(3), ThumbReg(1), offsetof(T_CONTEXT, R0) + (argLoc.m_idxGenReg * sizeof(DWORD))); - - nSrcAlign++; - } - - // Generics Instantiation Parameter - if (pSig->hasTypeArg()) { - argPlacer.GetParamTypeLoc(&argLoc); - pSl->ThumbCopyOneTailCallArg(&nSrcAlign, &argLoc, &cbStackSpace); - } - - // VarArgs Cookie Parameter - if (pSig->isVarArg()) { - argPlacer.GetVASigCookieLoc(&argLoc); - pSl->ThumbCopyOneTailCallArg(&nSrcAlign, &argLoc, &cbStackSpace); - } - - // Now for *all* the 'real' arguments - int argOffset; - while ((argOffset = argPlacer.GetNextOffset()) != TransitionBlock::InvalidOffset) - { - argPlacer.GetArgLoc(argOffset, &argLoc); - - pSl->ThumbCopyOneTailCallArg(&nSrcAlign, &argLoc, &cbStackSpace); - } - - // Now that we are done moving arguments, add back in the stack space we reserved - // for the return buffer. - cbStackSpace += cbReturnBufferSpace; - - // Keep the stack space 8-byte aligned - if ((cbStackSpace + cbFrameOffset) & 7) { - cbStackSpace += 4; - } - _ASSERTE(((cbStackSpace + cbFrameOffset) & 7) == 0); - - CodeLabel *pReturnLabel = pSl->NewCodeLabel(); - // B ReturnLabel: - pSl->ThumbEmitNearJump(pReturnLabel); - - // NullLabel: - pSl->EmitLabel(pNullLabel); - // MOVW/MOVT r0, 0 ; No GCLayout info - pSl->ThumbEmitMovConstant(ThumbReg(0), 0); - // STR r0, [r3] - pSl->ThumbEmitStoreRegIndirect(ThumbReg(0), ThumbReg(3), 0); - - // ReturnLabel: - pSl->EmitLabel(pReturnLabel); - - // MOVW/MOVT r0, #cbStackSpace - pSl->ThumbEmitMovConstant(ThumbReg(0), cbStackSpace); - - if (fNeedExtraRegs) { - // Inject a proper prolog - // pop {r4-r7,pc} - pSl->ThumbEmitEpilog(); - } - else { - // bx lr - pSl->ThumbEmitJumpRegister(thumbRegLr); - } - - LoaderHeap* pHeap = pMD->GetLoaderAllocator()->GetStubHeap(); - return pSl->Link(pHeap); -} - - VOID ResetCurrentContext() { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/src/vm/arm64/stubs.cpp b/src/coreclr/src/vm/arm64/stubs.cpp index 9987da8e79ff72..2c482db470ff7d 100644 --- a/src/coreclr/src/vm/arm64/stubs.cpp +++ b/src/coreclr/src/vm/arm64/stubs.cpp @@ -837,23 +837,6 @@ void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) #endif -#ifndef CROSSGEN_COMPILE - -void TailCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) -{ - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TailCallFrame::UpdateRegDisplay(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); - _ASSERTE(!"ARM64:NYI"); -} - -#ifndef DACCESS_COMPILE -void TailCallFrame::InitFromContext(T_CONTEXT * pContext) -{ - _ASSERTE(!"ARM64:NYI"); -} -#endif // !DACCESS_COMPILE - -#endif // CROSSGEN_COMPILE - void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) { LIMITED_METHOD_DAC_CONTRACT; diff --git a/src/coreclr/src/vm/assemblyloadcontext.h b/src/coreclr/src/vm/assemblyloadcontext.h index 85b4f30d09ac57..dd6d958f1ce2c7 100644 --- a/src/coreclr/src/vm/assemblyloadcontext.h +++ b/src/coreclr/src/vm/assemblyloadcontext.h @@ -6,6 +6,7 @@ #define _ASSEMBLYLOADCONTEXT_H #include "crst.h" +#include class NativeImage; class Module; diff --git a/src/coreclr/src/vm/assemblynative.cpp b/src/coreclr/src/vm/assemblynative.cpp index b9cec28e3c5a27..0cb1dba31c3c48 100644 --- a/src/coreclr/src/vm/assemblynative.cpp +++ b/src/coreclr/src/vm/assemblynative.cpp @@ -239,7 +239,9 @@ void QCALLTYPE AssemblyNative::LoadFromPath(INT_PTR ptrNativeAssemblyLoadContext if (pwzILPath != NULL) { - pILImage = PEImage::OpenImage(pwzILPath); + pILImage = PEImage::OpenImage(pwzILPath, + MDInternalImport_Default, + Bundle::ProbeAppBundle(pwzILPath)); // Need to verify that this is a valid CLR assembly. if (!pILImage->CheckILFormat()) @@ -257,7 +259,9 @@ void QCALLTYPE AssemblyNative::LoadFromPath(INT_PTR ptrNativeAssemblyLoadContext // Form the PEImage for the NI assembly, if specified if (pwzNIPath != NULL) { - pNIImage = PEImage::OpenImage(pwzNIPath, MDInternalImport_TrustedNativeImage); + pNIImage = PEImage::OpenImage(pwzNIPath, + MDInternalImport_TrustedNativeImage, + Bundle::ProbeAppBundle(pwzNIPath)); if (pNIImage->HasReadyToRunHeader()) { diff --git a/src/coreclr/src/vm/bundle.cpp b/src/coreclr/src/vm/bundle.cpp new file mode 100644 index 00000000000000..e0d03155a56a13 --- /dev/null +++ b/src/coreclr/src/vm/bundle.cpp @@ -0,0 +1,93 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// Bundle.cpp +// +// Helpers to access meta-data stored in single-file bundles +// +//***************************************************************************** + +#include "common.h" +#include "bundle.h" +#include +#include +#include + +Bundle *Bundle::AppBundle = nullptr; + +const SString &BundleFileLocation::Path() const +{ + LIMITED_METHOD_CONTRACT; + + // Currently, there is only one bundle -- the bundle for the main App. + // Therefore, obtain the path from the global AppBundle. + // If there is more than one bundle in one application (ex: single file plugins) + // the BundlePath may be stored in the BundleFileLocation structure. + + _ASSERTE(IsValid()); + _ASSERTE(Bundle::AppBundle != nullptr); + + return Bundle::AppBundle->Path(); +} + +Bundle::Bundle(LPCWSTR bundlePath, BundleProbe *probe) +{ + STANDARD_VM_CONTRACT; + + _ASSERTE(probe != nullptr); + + m_path.Set(bundlePath); + m_probe = probe; + + // The bundle-base path is the directory containing the single-file bundle. + // When the Probe() function searches within the bundle, it masks out the basePath from the assembly-path (if found). + + LPCWSTR pos = wcsrchr(bundlePath, DIRECTORY_SEPARATOR_CHAR_W); + _ASSERTE(pos != nullptr); + size_t baseLen = pos - bundlePath + 1; // Include DIRECTORY_SEPARATOR_CHAR_W in m_basePath + m_basePath.Set(bundlePath, (COUNT_T)baseLen); +} + +BundleFileLocation Bundle::Probe(LPCWSTR path, bool pathIsBundleRelative) const +{ + STANDARD_VM_CONTRACT; + + BundleFileLocation loc; + + // Skip over m_base_path, if any. For example: + // Bundle.Probe("lib.dll") => m_probe("lib.dll") + // Bundle.Probe("path/to/exe/lib.dll") => m_probe("lib.dll") + // Bundle.Probe("path/to/exe/and/some/more/lib.dll") => m_probe("and/some/more/lib.dll") + + if (!pathIsBundleRelative) + { + size_t baseLen = m_basePath.GetCount(); + +#ifdef TARGET_UNIX + if (wcsncmp(m_basePath, path, baseLen) == 0) +#else + if (_wcsnicmp(m_basePath, path, baseLen) == 0) +#endif // TARGET_UNIX + { + path += baseLen; // m_basePath includes count for DIRECTORY_SEPARATOR_CHAR_W + } + else + { + // This is not a file within the bundle + return loc; + } + } + + m_probe(path, &loc.Offset, &loc.Size); + + return loc; +} + +BundleFileLocation Bundle::ProbeAppBundle(LPCWSTR path, bool pathIsBundleRelative) +{ + STANDARD_VM_CONTRACT; + + return AppIsBundle() ? AppBundle->Probe(path, pathIsBundleRelative) : BundleFileLocation::Invalid(); +} + diff --git a/src/coreclr/src/vm/callingconvention.h b/src/coreclr/src/vm/callingconvention.h index 8845a3543e7f17..6cd90b4376d154 100644 --- a/src/coreclr/src/vm/callingconvention.h +++ b/src/coreclr/src/vm/callingconvention.h @@ -638,7 +638,7 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE int cSlots = (GetArgSize() + 7)/ 8; - // Composites greater than 16bytes are passed by reference + // Composites greater than 16 bytes are passed by reference if (GetArgType() == ELEMENT_TYPE_VALUETYPE && GetArgSize() > ENREGISTERED_PARAMTYPE_MAXSIZE) { cSlots = 1; @@ -1346,8 +1346,8 @@ int ArgIteratorTemplate::GetNextOffset() case ELEMENT_TYPE_VALUETYPE: { - // Handle HFAs: packed structures of 2-4 floats or doubles that are passed in FP argument - // registers if possible. + // Handle HFAs: packed structures of 1-4 floats, doubles, or short vectors + // that are passed in FP argument registers if possible. if (thValueType.IsHFA()) { CorElementType type = thValueType.GetHFAType(); diff --git a/src/coreclr/src/vm/castcache.cpp b/src/coreclr/src/vm/castcache.cpp index 5465d82ac00138..829d8b331e0127 100644 --- a/src/coreclr/src/vm/castcache.cpp +++ b/src/coreclr/src/vm/castcache.cpp @@ -11,6 +11,7 @@ #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) BASEARRAYREF* CastCache::s_pTableRef = NULL; +OBJECTHANDLE CastCache::s_sentinelTable = NULL; DWORD CastCache::s_lastFlushSize = INITIAL_CACHE_SIZE; BASEARRAYREF CastCache::CreateCastCache(DWORD size) @@ -24,7 +25,7 @@ BASEARRAYREF CastCache::CreateCastCache(DWORD size) CONTRACTL_END; // size must be positive - _ASSERTE(size > 0); + _ASSERTE(size > 1); // size must be a power of two _ASSERTE((size & (size - 1)) == 0); @@ -39,7 +40,7 @@ BASEARRAYREF CastCache::CreateCastCache(DWORD size) EX_CATCH { } - EX_END_CATCH(RethrowCorruptingExceptions) + EX_END_CATCH(RethrowTerminalExceptions) if (!table) { @@ -53,7 +54,7 @@ BASEARRAYREF CastCache::CreateCastCache(DWORD size) EX_CATCH { } - EX_END_CATCH(RethrowCorruptingExceptions) + EX_END_CATCH(RethrowTerminalExceptions) if (!table) { @@ -62,16 +63,17 @@ BASEARRAYREF CastCache::CreateCastCache(DWORD size) } } - TableMask(table) = size - 1; + DWORD* tableData = TableData(table); + TableMask(tableData) = size - 1; // Fibonacci hash reduces the value into desired range by shifting right by the number of leading zeroes in 'size-1' DWORD bitCnt; #if HOST_64BIT BitScanReverse64(&bitCnt, size - 1); - HashShift(table) = (BYTE)(63 - bitCnt); + HashShift(tableData) = (BYTE)(63 - bitCnt); #else BitScanReverse(&bitCnt, size - 1); - HashShift(table) = (BYTE)(31 - bitCnt); + HashShift(tableData) = (BYTE)(31 - bitCnt); #endif return table; @@ -107,10 +109,10 @@ void CastCache::FlushCurrentCache() } CONTRACTL_END; - BASEARRAYREF currentTableRef = *s_pTableRef; - s_lastFlushSize = !currentTableRef ? INITIAL_CACHE_SIZE : CacheElementCount(currentTableRef); + DWORD* tableData = TableData(*s_pTableRef); + s_lastFlushSize = max(INITIAL_CACHE_SIZE, CacheElementCount(tableData)); - *s_pTableRef = NULL; + SetObjectReference((OBJECTREF *)s_pTableRef, ObjectFromHandle(s_sentinelTable)); } void CastCache::Initialize() @@ -127,6 +129,18 @@ void CastCache::Initialize() GCX_COOP(); s_pTableRef = (BASEARRAYREF*)pTableField->GetCurrentStaticAddress(); + + BASEARRAYREF sentinelTable = CreateCastCache(2); + if (!sentinelTable) + { + // no memory for 2 element cache while initializing? + ThrowOutOfMemory(); + } + + s_sentinelTable = CreateGlobalHandle(sentinelTable); + + // initialize to the sentinel value, this should not be null. + SetObjectReference((OBJECTREF *)s_pTableRef, sentinelTable); } TypeHandle::CastResult CastCache::TryGet(TADDR source, TADDR target) @@ -139,58 +153,55 @@ TypeHandle::CastResult CastCache::TryGet(TADDR source, TADDR target) } CONTRACTL_END; - BASEARRAYREF table = *s_pTableRef; + DWORD* tableData = TableData(*s_pTableRef); - // we use NULL as a sentinel for a rare case when a table could not be allocated - // because we avoid OOMs. - // we could use 0-element table instead, but then we would have to check the size here. - if (table != NULL) + DWORD index = KeyToBucket(tableData, source, target); + for (DWORD i = 0; i < BUCKET_SIZE;) { - DWORD index = KeyToBucket(table, source, target); - for (DWORD i = 0; i < BUCKET_SIZE;) - { - CastCacheEntry* pEntry = &Elements(table)[index]; + CastCacheEntry* pEntry = &Elements(tableData)[index]; - // must read in this order: version -> entry parts -> version - // if version is odd or changes, the entry is inconsistent and thus ignored - DWORD version1 = VolatileLoad(&pEntry->version); - TADDR entrySource = pEntry->source; + // must read in this order: version -> [entry parts] -> version + // if version is odd or changes, the entry is inconsistent and thus ignored + DWORD version1 = VolatileLoad(&pEntry->version); + TADDR entrySource = pEntry->source; - // mask the lower version bit to make it even. - // This way we can check if version is odd or changing in just one compare. - version1 &= ~1; + // mask the lower version bit to make it even. + // This way we can check if version is odd or changing in just one compare. + version1 &= ~1; - if (entrySource == source) + if (entrySource == source) + { + TADDR entryTargetAndResult = pEntry->targetAndResult; + // target never has its lower bit set. + // a matching entryTargetAndResult would have the same bits, except for the lowest one, which is the result. + entryTargetAndResult ^= target; + if (entryTargetAndResult <= 1) { - TADDR entryTargetAndResult = VolatileLoad(&pEntry->targetAndResult); - // target never has its lower bit set. - // a matching entryTargetAndResult would have the same bits, except for the lowest one, which is the result. - entryTargetAndResult ^= target; - if (entryTargetAndResult <= 1) + // make sure 'version' is loaded after 'source' and 'targetAndResults' + VolatileLoadBarrier(); + if (version1 != pEntry->version) { - if (version1 != pEntry->version) - { - // oh, so close, the entry is in inconsistent state. - // it is either changing or has changed while we were reading. - // treat it as a miss. - break; - } - - return TypeHandle::CastResult(entryTargetAndResult); + // oh, so close, the entry is in inconsistent state. + // it is either changing or has changed while we were reading. + // treat it as a miss. + break; } - } - if (version1 == 0) - { - // the rest of the bucket is unclaimed, no point to search further - break; + return TypeHandle::CastResult(entryTargetAndResult); } + } - // quadratic reprobe - i++; - index = (index + i) & TableMask(table); + if (version1 == 0) + { + // the rest of the bucket is unclaimed, no point to search further + break; } + + // quadratic reprobe + i++; + index = (index + i) & TableMask(tableData); } + return TypeHandle::MaybeCast; } @@ -205,21 +216,23 @@ void CastCache::TrySet(TADDR source, TADDR target, BOOL result) CONTRACTL_END; DWORD bucket; - BASEARRAYREF table; + DWORD* tableData; do { - table = *s_pTableRef; - if (!table) + tableData = TableData(*s_pTableRef); + if (TableMask(tableData) == 1) { - // we did not allocate a table or flushed it, try replacing, but do not continue looping. + // 2-element table is used as a sentinel. + // we did not allocate a real table yet or have flushed it. + // try replacing the table, but do not insert anything. MaybeReplaceCacheWithLarger(s_lastFlushSize); return; } - bucket = KeyToBucket(table, source, target); + bucket = KeyToBucket(tableData, source, target); DWORD index = bucket; - CastCacheEntry* pEntry = &Elements(table)[index]; + CastCacheEntry* pEntry = &Elements(tableData)[index]; for (DWORD i = 0; i < BUCKET_SIZE;) { @@ -259,28 +272,28 @@ void CastCache::TrySet(TADDR source, TADDR target, BOOL result) // quadratic reprobe i++; index += i; - pEntry = &Elements(table)[index & TableMask(table)]; + pEntry = &Elements(tableData)[index & TableMask(tableData)]; } // bucket is full. - } while (TryGrow(table)); + } while (TryGrow(tableData)); - // reread table after TryGrow. - table = *s_pTableRef; - if (!table) + // reread tableData after TryGrow. + tableData = TableData(*s_pTableRef); + if (TableMask(tableData) == 1) { - // we did not allocate a table. + // do not insert into a sentinel. return; } // pick a victim somewhat randomly within a bucket // NB: ++ is not interlocked. We are ok if we lose counts here. It is just a number that changes. - DWORD victimDistance = VictimCounter(table)++ & (BUCKET_SIZE - 1); + DWORD victimDistance = VictimCounter(tableData)++ & (BUCKET_SIZE - 1); // position the victim in a quadratic reprobe bucket DWORD victim = (victimDistance * victimDistance + victimDistance) / 2; { - CastCacheEntry* pEntry = &Elements(table)[(bucket + victim) & TableMask(table)]; + CastCacheEntry* pEntry = &Elements(tableData)[(bucket + victim) & TableMask(tableData)]; DWORD version = pEntry->version; if ((version & VERSION_NUM_MASK) >= (VERSION_NUM_MASK - 2)) diff --git a/src/coreclr/src/vm/castcache.h b/src/coreclr/src/vm/castcache.h index 18d1564614bee4..28ba4bdcd320ff 100644 --- a/src/coreclr/src/vm/castcache.h +++ b/src/coreclr/src/vm/castcache.h @@ -199,7 +199,12 @@ class CastCache // We pick 8 as the probe limit (hoping for 4 probes on average), but the number can be refined further. static const DWORD BUCKET_SIZE = 8; + // current cache table static BASEARRAYREF* s_pTableRef; + + // sentinel table that never contains elements and used for flushing the old table when we cannot allocate a new one. + static OBJECTHANDLE s_sentinelTable; + static DWORD s_lastFlushSize; FORCEINLINE static TypeHandle::CastResult TryGetFromCache(TADDR source, TADDR target) @@ -236,7 +241,7 @@ class CastCache TrySet(source, target, result); } - FORCEINLINE static bool TryGrow(BASEARRAYREF table) + FORCEINLINE static bool TryGrow(DWORD* tableData) { CONTRACTL { @@ -246,7 +251,7 @@ class CastCache } CONTRACTL_END; - DWORD newSize = CacheElementCount(table) * 2; + DWORD newSize = CacheElementCount(tableData) * 2; if (newSize <= MAXIMUM_CACHE_SIZE) { return MaybeReplaceCacheWithLarger(newSize); @@ -255,22 +260,23 @@ class CastCache return false; } - FORCEINLINE static DWORD KeyToBucket(BASEARRAYREF table, TADDR source, TADDR target) + FORCEINLINE static DWORD KeyToBucket(DWORD* tableData, TADDR source, TADDR target) { // upper bits of addresses do not vary much, so to reduce loss due to cancelling out, // we do `rotl(source, ) ^ target` for mixing inputs. // then we use fibonacci hashing to reduce the value to desired size. + int hashShift = HashShift(tableData); #if HOST_64BIT UINT64 hash = (((UINT64)source << 32) | ((UINT64)source >> 32)) ^ (UINT64)target; - return (DWORD)((hash * 11400714819323198485llu) >> HashShift(table)); + return (DWORD)((hash * 11400714819323198485llu) >> hashShift); #else UINT32 hash = (((UINT32)source << 16) | ((UINT32)source >> 16)) ^ (UINT32)target; - return (DWORD)((hash * 2654435769ul) >> HashShift(table)); + return (DWORD)((hash * 2654435769ul) >> hashShift); #endif } - FORCEINLINE static DWORD* AuxData(BASEARRAYREF table) + FORCEINLINE static DWORD* TableData(BASEARRAYREF table) { LIMITED_METHOD_CONTRACT; @@ -278,37 +284,37 @@ class CastCache return (DWORD*)((BYTE*)OBJECTREFToObject(table) + ARRAYBASE_SIZE); } - FORCEINLINE static CastCacheEntry* Elements(BASEARRAYREF table) + FORCEINLINE static CastCacheEntry* Elements(DWORD* tableData) { LIMITED_METHOD_CONTRACT; // element 0 is used for embedded aux data, skip it - return (CastCacheEntry*)AuxData(table) + 1; + return (CastCacheEntry*)tableData + 1; } - // TableMask is "size - 1" - // we need that more often that we need size - FORCEINLINE static DWORD& TableMask(BASEARRAYREF table) + FORCEINLINE static DWORD& HashShift(DWORD* tableData) { LIMITED_METHOD_CONTRACT; - return *AuxData(table); + return *tableData; } - FORCEINLINE static DWORD& HashShift(BASEARRAYREF table) + // TableMask is "size - 1" + // we need that more often that we need size + FORCEINLINE static DWORD& TableMask(DWORD* tableData) { LIMITED_METHOD_CONTRACT; - return *(AuxData(table) + 1); + return *(tableData + 1); } - FORCEINLINE static DWORD& VictimCounter(BASEARRAYREF table) + FORCEINLINE static DWORD& VictimCounter(DWORD* tableData) { LIMITED_METHOD_CONTRACT; - return *(AuxData(table) + 2); + return *(tableData + 2); } - FORCEINLINE static DWORD CacheElementCount(BASEARRAYREF table) + FORCEINLINE static DWORD CacheElementCount(DWORD* tableData) { LIMITED_METHOD_CONTRACT; - return TableMask(table) + 1; + return TableMask(tableData) + 1; } static BASEARRAYREF CreateCastCache(DWORD size); diff --git a/src/coreclr/src/vm/ceeload.cpp b/src/coreclr/src/vm/ceeload.cpp index dc76c751edc34a..acd979f6cb3cdb 100644 --- a/src/coreclr/src/vm/ceeload.cpp +++ b/src/coreclr/src/vm/ceeload.cpp @@ -99,10 +99,10 @@ BOOL Module::HasNativeOrReadyToRunInlineTrackingMap() { LIMITED_METHOD_DAC_CONTRACT; #ifdef FEATURE_READYTORUN - if (IsReadyToRun() && GetReadyToRunInfo()->GetInlineTrackingMap() != NULL) - { - return TRUE; - } + if (IsReadyToRun() && GetReadyToRunInfo()->GetInlineTrackingMap() != NULL) + { + return TRUE; + } #endif return (m_pPersistentInlineTrackingMapNGen != NULL); } @@ -500,10 +500,9 @@ BOOL Module::IsPersistedObject(void *address) uint32_t Module::GetNativeMetadataAssemblyCount() { - NativeImage *compositeImage = GetCompositeNativeImage(); - if (compositeImage != NULL) + if (m_pNativeImage != NULL) { - return compositeImage->GetComponentAssemblyCount(); + return m_pNativeImage->GetManifestAssemblyCount(); } else { @@ -593,15 +592,25 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName) #endif // FEATURE_COLLECTIBLE_TYPES #ifdef FEATURE_READYTORUN + m_pNativeImage = NULL; if (!HasNativeImage() && !IsResource()) { if ((m_pReadyToRunInfo = ReadyToRunInfo::Initialize(this, pamTracker)) != NULL) { - COUNT_T cMeta = 0; - if (GetFile()->GetOpenedILimage()->GetNativeManifestMetadata(&cMeta) != NULL) + m_pNativeImage = m_pReadyToRunInfo->GetNativeImage(); + if (m_pNativeImage != NULL) + { + m_NativeMetadataAssemblyRefMap = m_pNativeImage->GetManifestMetadataAssemblyRefMap(); + } + else { - // Load the native assembly import - GetNativeAssemblyImport(TRUE /* loadAllowed */); + // For composite images, manifest metadata gets loaded as part of the native image + COUNT_T cMeta = 0; + if (GetFile()->GetOpenedILimage()->GetNativeManifestMetadata(&cMeta) != NULL) + { + // Load the native assembly import + GetNativeAssemblyImport(TRUE /* loadAllowed */); + } } } } @@ -3374,15 +3383,29 @@ BOOL Module::IsInSameVersionBubble(Module *target) return FALSE; } - // Check if the current module's image has native manifest metadata, otherwise the current->GetNativeAssemblyImport() asserts. - COUNT_T cMeta=0; - const void* pMeta = GetFile()->GetOpenedILimage()->GetNativeManifestMetadata(&cMeta); - if (pMeta == NULL) + NativeImage *nativeImage = this->GetCompositeNativeImage(); + IMDInternalImport* pMdImport = NULL; + + if (nativeImage != NULL) { - return FALSE; + if (nativeImage == target->GetCompositeNativeImage()) + { + // Fast path for modules contained within the same native image + return TRUE; + } + pMdImport = nativeImage->GetManifestMetadata(); + } + else + { + // Check if the current module's image has native manifest metadata, otherwise the current->GetNativeAssemblyImport() asserts. + COUNT_T cMeta=0; + const void* pMeta = GetFile()->GetOpenedILimage()->GetNativeManifestMetadata(&cMeta); + if (pMeta == NULL) + { + return FALSE; + } + pMdImport = GetNativeAssemblyImport(); } - - IMDInternalImport* pMdImport = GetNativeAssemblyImport(); LPCUTF8 targetName = target->GetAssembly()->GetSimpleName(); @@ -9605,7 +9628,14 @@ void Module::Fixup(DataImage *image) image->ZeroField(this, offsetof(Module, m_AssemblyRefByNameCount), sizeof(m_AssemblyRefByNameCount)); image->ZeroPointerField(this, offsetof(Module, m_AssemblyRefByNameTable)); - image->ZeroPointerField(this,offsetof(Module, m_NativeMetadataAssemblyRefMap)); +#ifdef FEATURE_READYTORUN + // For composite ready-to-run images, the manifest assembly ref map is stored in the native image + // and shared by all its component images. + if (m_pNativeImage == NULL) +#endif + { + image->ZeroPointerField(this,offsetof(Module, m_NativeMetadataAssemblyRefMap)); + } // // Fixup statics diff --git a/src/coreclr/src/vm/ceeload.h b/src/coreclr/src/vm/ceeload.h index 9c11aa4bb5c055..361937847fd8f1 100644 --- a/src/coreclr/src/vm/ceeload.h +++ b/src/coreclr/src/vm/ceeload.h @@ -1615,6 +1615,7 @@ class Module #ifdef FEATURE_READYTORUN private: PTR_ReadyToRunInfo m_pReadyToRunInfo; + PTR_NativeImage m_pNativeImage; #endif private: @@ -2924,17 +2925,17 @@ class Module #endif } - NativeImage *GetCompositeNativeImage() const +#ifdef FEATURE_READYTORUN + PTR_ReadyToRunInfo GetReadyToRunInfo() const { LIMITED_METHOD_DAC_CONTRACT; - return (m_pReadyToRunInfo != NULL ? m_pReadyToRunInfo->GetNativeImage() : NULL); + return m_pReadyToRunInfo; } -#ifdef FEATURE_READYTORUN - PTR_ReadyToRunInfo GetReadyToRunInfo() const + PTR_NativeImage GetCompositeNativeImage() const { LIMITED_METHOD_DAC_CONTRACT; - return m_pReadyToRunInfo; + return m_pNativeImage; } #endif diff --git a/src/coreclr/src/vm/ceemain.cpp b/src/coreclr/src/vm/ceemain.cpp index 5f7965e0a0abf5..f80dc4601043ba 100644 --- a/src/coreclr/src/vm/ceemain.cpp +++ b/src/coreclr/src/vm/ceemain.cpp @@ -93,14 +93,14 @@ // file:threads.h#SuspendingTheRuntime and file:../../Documentation/botr/threading.md // * Garbage collection - file:gc.cpp#Overview and file:../../Documentation/botr/garbage-collection.md // * code:AppDomain - The managed version of a process. -// * Calling Into the runtime (FCALLs QCalls) file:../../Documentation/botr/mscorlib.md +// * Calling Into the runtime (FCALLs QCalls) file:../../Documentation/botr/corelib.md // * Exceptions - file:../../Documentation/botr/exceptions.md. The most important routine to start // with is code:COMPlusFrameHandler which is the routine that we hook up to get called when an unmanaged // exception happens. // * Assembly Loading file:../../Documentation/botr/type-loader.md // * Profiling file:../../Documentation/botr/profiling.md and file:../../Documentation/botr/profilability.md // * FCALLS QCALLS (calling into the runtime from managed code) -// file:../../Documentation/botr/mscorlib.md +// file:../../Documentation/botr/corelib.md // * Event Tracing for Windows // * file:../inc/eventtrace.h#EventTracing - // * This is the main file dealing with event tracing in CLR @@ -164,6 +164,7 @@ #include "threadsuspend.h" #include "disassembler.h" #include "jithost.h" +#include "pgo.h" #ifndef TARGET_UNIX #include "dwreport.h" @@ -644,6 +645,11 @@ void EEStartupHelper() IfFailGo(EEConfig::Setup()); #ifndef CROSSGEN_COMPILE + +#ifdef HOST_WINDOWS + InitializeCrashDump(); +#endif // HOST_WINDOWS + // Initialize Numa and CPU group information // Need to do this as early as possible. Used by creating object handle // table inside Ref_Initialization() before GC is initialized. @@ -714,6 +720,10 @@ void EEStartupHelper() PerfMap::Initialize(); #endif +#ifdef FEATURE_PGO + PgoManager::Initialize(); +#endif + STRESS_LOG0(LF_STARTUP, LL_ALWAYS, "===================EEStartup Starting==================="); #ifndef CROSSGEN_COMPILE @@ -831,8 +841,6 @@ void EEStartupHelper() VirtualCallStubManager::InitStatic(); - GCInterface::m_MemoryPressureLock.Init(CrstGCMemoryPressure); - #endif // CROSSGEN_COMPILE // Setup the domains. Threads are started in a default domain. @@ -1156,70 +1164,6 @@ void ForceEEShutdown(ShutdownCompleteAction sca) EEPolicy::HandleExitProcess(sca); } -static bool WaitForEndOfShutdown_OneIteration() -{ - CONTRACTL{ - NOTHROW; - GC_NOTRIGGER; - MODE_PREEMPTIVE; - } CONTRACTL_END; - - // We are shutting down. GC triggers does not have any effect now. - CONTRACT_VIOLATION(GCViolation); - - // If someone calls EEShutDown while holding OS loader lock, the thread we created for shutdown - // won't start running. This is a deadlock we can not fix. Instead, we timeout and continue the - // current thread. - DWORD timeout = GetEEPolicy()->GetTimeout(OPR_ProcessExit); - timeout *= 2; - ULONGLONG endTime = CLRGetTickCount64() + timeout; - bool done = false; - - EX_TRY - { - ULONGLONG curTime = CLRGetTickCount64(); - if (curTime > endTime) - { - done = true; - } - else - { -#ifdef PROFILING_SUPPORTED - if (CORProfilerPresent()) - { - // A profiler is loaded, so just wait without timeout. This allows - // profilers to complete potentially lengthy post processing, without the - // CLR killing them off first. The Office team's server memory profiler, - // for example, does a lot of post-processing that can exceed the 80 - // second imit we normally impose here. The risk of waiting without - // timeout is that, if there really is a deadlock, shutdown will hang. - // Since that will only happen if a profiler is loaded, that is a - // reasonable compromise - timeout = INFINITE; - } - else -#endif //PROFILING_SUPPORTED - { - timeout = static_cast(endTime - curTime); - } - DWORD status = g_pEEShutDownEvent->Wait(timeout,TRUE); - if (status == WAIT_OBJECT_0 || status == WAIT_TIMEOUT) - { - done = true; - } - else - { - done = false; - } - } - } - EX_CATCH - { - } - EX_END_CATCH(SwallowAllExceptions); - return done; -} - void WaitForEndOfShutdown() { CONTRACTL{ @@ -1240,7 +1184,7 @@ void WaitForEndOfShutdown() pThread->SetThreadStateNC(Thread::TSNC_BlockedForShutdown); } - while (!WaitForEndOfShutdown_OneIteration()); + for (;;) g_pEEShutDownEvent->Wait(INFINITE, TRUE); } // --------------------------------------------------------------------------- @@ -1374,6 +1318,10 @@ void STDMETHODCALLTYPE EEShutDownHelper(BOOL fIsDllUnloading) PerfMap::Destroy(); #endif +#ifdef FEATURE_PGO + PgoManager::Shutdown(); +#endif + { // If we're doing basic block profiling, we need to write the log files to disk. static BOOL fIBCLoggingDone = FALSE; @@ -1877,8 +1825,6 @@ BOOL STDMETHODCALLTYPE EEDllMain( // TRUE on success, FALSE on error. SetResourceCultureCallbacks(GetThreadUICultureNames, GetThreadUICultureId); - InitEEPolicy(); - break; } diff --git a/src/coreclr/src/vm/cgensys.h b/src/coreclr/src/vm/cgensys.h index 047725ca0f3619..17213af0e7594c 100644 --- a/src/coreclr/src/vm/cgensys.h +++ b/src/coreclr/src/vm/cgensys.h @@ -46,7 +46,7 @@ enum class CallerGCMode { Unknown, Coop, - Preemptive // (e.g. NativeCallableAttribute) + Preemptive // (e.g. UnmanagedCallersOnlyAttribute) }; // Non-CPU-specific helper functions called by the CPU-dependent code diff --git a/src/coreclr/src/vm/class.cpp b/src/coreclr/src/vm/class.cpp index c87c21d1515952..d9357e85b06a9c 100644 --- a/src/coreclr/src/vm/class.cpp +++ b/src/coreclr/src/vm/class.cpp @@ -87,9 +87,6 @@ void EEClass::Destruct(MethodTable * pOwningMT) #ifndef CROSSGEN_COMPILE - // Not expected to be called for array EEClass - _ASSERTE(!pOwningMT->IsArray()); - #ifdef _DEBUG _ASSERTE(!IsDestroyed()); SetDestroyed(); @@ -1198,10 +1195,6 @@ int MethodTable::GetVectorSize() { vectorSize = 16; } - else if (strcmp(className, "Vector256`1") == 0) - { - vectorSize = 32; - } else if (strcmp(className, "Vector64`1") == 0) { vectorSize = 8; @@ -1256,11 +1249,6 @@ CorElementType MethodTable::GetHFAType() { case ELEMENT_TYPE_VALUETYPE: pMT = pFirstField->LookupApproxFieldTypeHandle().GetMethodTable(); - vectorSize = pMT->GetVectorSize(); - if (vectorSize != 0) - { - return (vectorSize == 8) ? ELEMENT_TYPE_R8 : ELEMENT_TYPE_VALUETYPE; - } break; case ELEMENT_TYPE_R4: diff --git a/src/coreclr/src/vm/classnames.h b/src/coreclr/src/vm/classnames.h index f45311f0de4435..8385bf4828afcf 100644 --- a/src/coreclr/src/vm/classnames.h +++ b/src/coreclr/src/vm/classnames.h @@ -25,8 +25,6 @@ #define g_CollectionsGenericReadOnlyCollectionItfName "System.Collections.Generic.IReadOnlyCollection`1" #ifdef FEATURE_COMINTEROP -#define g_ECMAKeyToken "B77A5C561934E089" // The ECMA key used by some framework assemblies: mscorlib, system, etc. -#define g_FXKeyToken "b03f5f7f11d50a3a" // The FX key used by other framework assemblies: System.Web, System.Drawing, etc. #define g_CorelibAsmName "System.Private.CoreLib" #define g_SystemAsmName "System" #define g_SystemRuntimeAsmName "System.Runtime" @@ -152,7 +150,7 @@ #define g_CompilerServicesIntrinsicAttribute "System.Runtime.CompilerServices.IntrinsicAttribute" #define g_UnmanagedFunctionPointerAttribute "System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute" #define g_DefaultDllImportSearchPathsAttribute "System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute" -#define g_NativeCallableAttribute "System.Runtime.InteropServices.NativeCallableAttribute" +#define g_UnmanagedCallersOnlyAttribute "System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute" #define g_FixedBufferAttribute "System.Runtime.CompilerServices.FixedBufferAttribute" #define g_CompilerServicesTypeDependencyAttribute "System.Runtime.CompilerServices.TypeDependencyAttribute" diff --git a/src/coreclr/src/vm/clrex.cpp b/src/coreclr/src/vm/clrex.cpp index 5153f92dc68934..29db69296042d6 100644 --- a/src/coreclr/src/vm/clrex.cpp +++ b/src/coreclr/src/vm/clrex.cpp @@ -927,7 +927,7 @@ void CLRException::HandlerState::SetupCatch(INDEBUG_COMMA(__in_z const char * sz if (exceptionCode == STATUS_STACK_OVERFLOW) { // We have called HandleStackOverflow for soft SO through our vectored exception handler. - EEPolicy::HandleStackOverflow(SOD_UnmanagedFrameHandler, FRAME_TOP); + EEPolicy::HandleStackOverflow(); } } } @@ -990,21 +990,21 @@ struct WinRtHR_to_ExceptionKind_Map enum WinRtOnly_ExceptionKind { #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) kWinRtEx##reKind, #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) -#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) +#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, bHRformessage, ...) #include "rexcep.h" kWinRtExLastException }; #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) static const HRESULT s_##reKind##WinRtOnlyHRs[] = { __VA_ARGS__ }; #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) -#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) +#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, bHRformessage, ...) #include "rexcep.h" static const WinRtHR_to_ExceptionKind_Map gWinRtHR_to_ExceptionKind_Maps[] = { #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) { k##reKind, sizeof(s_##reKind##WinRtOnlyHRs) / sizeof(HRESULT), s_##reKind##WinRtOnlyHRs }, #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) -#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) +#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, bHRformessage, ...) #include "rexcep.h" }; @@ -1018,14 +1018,14 @@ struct ExceptionHRInfo #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) static const HRESULT s_##reKind##HRs[] = { __VA_ARGS__ }; #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) -#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__) +#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__) #include "rexcep.h" static const ExceptionHRInfo gExceptionHRInfos[] = { #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) {sizeof(s_##reKind##HRs) / sizeof(HRESULT), s_##reKind##HRs}, #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) -#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__) +#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__) #include "rexcep.h" }; @@ -1035,7 +1035,7 @@ bool gShouldDisplayHR[] = { #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) bHRformessage, #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) -#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__) +#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__) #include "rexcep.h" }; @@ -2595,7 +2595,7 @@ ArrayReference GetHRESULTsForExceptionKind(RuntimeExceptionKind k return ArrayReference(s_##reKind##HRs); \ break; #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) - #define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__) + #define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__) #include "rexcep.h" default: diff --git a/src/coreclr/src/vm/clrex.h b/src/coreclr/src/vm/clrex.h index 16b32574f5a39f..3a570a5480f26c 100644 --- a/src/coreclr/src/vm/clrex.h +++ b/src/coreclr/src/vm/clrex.h @@ -735,7 +735,7 @@ class EEFileLoadException : public EEException // { // EX_RETHROW() // } -// EX_END_CATCH(RethrowTerminalExceptions or RethrowCorruptingExceptions) +// EX_END_CATCH(RethrowTerminalExceptions) // -------------------------------------------------------------------------------------------------------- // In DAC builds, we don't want to override the normal utilcode exception handling. @@ -746,62 +746,6 @@ class EEFileLoadException : public EEException #define GET_THROWABLE() CLRException::GetThrowableFromException(GET_EXCEPTION()) -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - -// For the VM folder, we redefine SET_CE_RETHROW_FLAG_FOR_EX_CATCH to also check the -// corruption severity when deciding whether to rethrow them or not. -// -// We also check the global override flag incase it has been set to force pre-V4 behaviour. -// -// Doing the checks for "__fCaughtSO" and "__fCaughtNonCxx" will ensure that we check for -// corruption severity only if the last exception was a managed exception that could have been rethrown in the VM. -// When "(__fCaughtSO == FALSE) && (__fCaughtNonCxx == true)" is true, it implies we are dealing with a managed exception -// inside the VM that is represented by the CLRLastThrownObjectException instance (see EX_TRY/EX_CATCH implementation in VM -// folder to see how CLRLastThrownObjectException is used). -// -// This macro also supports the following scenarios: -// -// Scenario 1 -// ---------- -// -// [VM1] -> [VM2] -> -// -// If a managed exception is swallowed by an EX_CATCH in native function VM2, which then returns back -// to native function VM1 that throws, for example, a VM C++ exception, an EX_CATCH(RethrowCorruptingExceptions) -// in VM1 that catches the C++ exception will not rethrow since the last exception was not a managed CSE but -// a C++ exception. -// -// A variation of this is for VM2 to return back in VM1, which calls VM3 that throws a VM C++ exception that -// reaches VM1's EX_CATCH(RethrowCorruptingExceptions). VM1 shouldn't be rethrowing the exception in such a case. -// -// Scenario 2 -// ---------- -// -// [VM1 - RethrowCSE] -> [VM2 - RethrowCSE] -> [VM3 - RethrowCSE] -> -// -// When managed code throws a CSE (e.g. TargetInvocationException flagged as CSE), [VM3] will rethrow it and we will -// enter EX_CATCH in VM2 which is supposed to rethrow it as well. But if the implementation of EX_CATCH in VM2 throws -// another VM C++ exception (e.g. EEFileLoadException) *before* rethrow policy is applied, control will reach EX_CATCH -// in VM1 that *shouldn't* rethrow (even though it has RethrowCSE as the policy) since the last exception was a VM C++ -// exception. -// -// Scenario 3 -// ---------- -// -// This is about VM throwing a managed exception that gets handled either within the VM, with or without CLR's managed code -// exception handler coming into the picture. -// -// This is explained in detail (alongwith relevant changes) in the implementation of RaiseTheException (in excep.cpp). - -#undef SET_CE_RETHROW_FLAG_FOR_EX_CATCH -#define SET_CE_RETHROW_FLAG_FOR_EX_CATCH(expr) (((expr) == TRUE) && \ - (g_pConfig->LegacyCorruptedStateExceptionsPolicy() == false) && \ - (CEHelper::IsProcessCorruptedStateException(GetCurrentExceptionCode(), FALSE) || \ - (!__state.DidCatchCxx() && \ - CEHelper::IsLastActiveExceptionCorrupting(TRUE)))) - -#endif // FEATURE_CORRUPTING_EXCEPTIONS - #undef EX_TRY #define EX_TRY \ EX_TRY_CUSTOM(CLRException::HandlerState, (::GetThreadNULLOk()), CLRLastThrownObjectException) @@ -1002,25 +946,6 @@ LONG CLRNoCatchHandler(EXCEPTION_POINTERS* pExceptionInfo, PVOID pv); } \ } \ -// This macro should be used at the entry points (e.g. COM interop boundaries) -// where CE's are not expected to get swallowed. -#define END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS_EX(fCond) \ - } \ - EX_CATCH \ - { \ - *__phr = GET_EXCEPTION()->GetHR(); \ - } \ - EX_END_CATCH(RethrowCorruptingExceptionsEx(fCond)); \ - } \ - } \ - -// This macro should be used at the entry points (e.g. COM interop boundaries) -// where CE's are not expected to get swallowed. -#define END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS \ - END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS_EX(TRUE) - - - //============================================================================== // --------------------------------------------------------------------------- diff --git a/src/coreclr/src/vm/clsload.cpp b/src/coreclr/src/vm/clsload.cpp index c83da2654994a9..d453eda642e2b7 100644 --- a/src/coreclr/src/vm/clsload.cpp +++ b/src/coreclr/src/vm/clsload.cpp @@ -3955,7 +3955,7 @@ ClassLoader::LoadTypeHandleForTypeKey_Body( } EX_HOOK { - LOG((LF_CLASSLOADER, LL_INFO10, "Caught an exception loading: %x, %0x (Module)\n", pTypeKey->GetTypeToken(), pTypeKey->GetModule())); + LOG((LF_CLASSLOADER, LL_INFO10, "Caught an exception loading: %x, %0x (Module)\n", pTypeKey->IsConstructed() ? pTypeKey->ComputeHash() : pTypeKey->GetTypeToken(), pTypeKey->GetModule())); if (!GetThread()->HasThreadStateNC(Thread::TSNC_LoadsTypeViolation)) { diff --git a/src/coreclr/src/vm/codeman.cpp b/src/coreclr/src/vm/codeman.cpp index 863b54a240f747..a41e19c02b5e8c 100644 --- a/src/coreclr/src/vm/codeman.cpp +++ b/src/coreclr/src/vm/codeman.cpp @@ -1299,6 +1299,8 @@ void EEJitManager::SetCpuInfo() #endif // TARGET_X86 #if defined(TARGET_X86) || defined(TARGET_AMD64) + CPUCompileFlags.Set(InstructionSet_X86Base); + // NOTE: The below checks are based on the information reported by // Intel® 64 and IA-32 Architectures Software Developer’s Manual. Volume 2 // and @@ -1541,14 +1543,6 @@ struct JIT_LOAD_DATA // Here's the global data for JIT load and initialization state. JIT_LOAD_DATA g_JitLoadData; -#if !defined(FEATURE_MERGE_JIT_AND_ENGINE) - -// Global that holds the path to custom JIT location -LPCWSTR g_CLRJITPath = nullptr; - -#endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE) - - // LoadAndInitializeJIT: load the JIT dll into the process, and initialize it (call the UtilCode initialization function, // check the JIT-EE interface GUID, etc.) // @@ -1587,21 +1581,6 @@ static void LoadAndInitializeJIT(LPCWSTR pwzJitName, OUT HINSTANCE* phJit, OUT I extern HINSTANCE g_hThisInst; bool havePath = false; -#if !defined(FEATURE_MERGE_JIT_AND_ENGINE) - if (g_CLRJITPath != nullptr) - { - // If we have been asked to load a specific JIT binary, load from that path. - // The main JIT load will use exactly that name because pwzJitName will have - // been computed as the last component of g_CLRJITPath by ExecutionManager::GetJitName(). - // Non-primary JIT names (such as compatjit or altjit) will be loaded from the - // same directory. - // (Ideally, g_CLRJITPath would just be the JIT path without the filename component, - // but that's not how the JIT_PATH variable was originally defined.) - CoreClrFolderHolder.Set(g_CLRJITPath); - havePath = true; - } - else -#endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE) if (WszGetModuleFileName(g_hThisInst, CoreClrFolderHolder)) { // Load JIT from next to CoreCLR binary @@ -4381,8 +4360,6 @@ BOOL ExecutionManager::IsReadyToRunCode(PCODE currentPC) return FALSE; } -#ifndef DACCESS_COMPILE - #ifndef FEATURE_MERGE_JIT_AND_ENGINE /*********************************************************************/ // This static method returns the name of the jit dll @@ -4391,34 +4368,10 @@ LPCWSTR ExecutionManager::GetJitName() { STANDARD_VM_CONTRACT; - LPCWSTR pwzJitName = NULL; - -#if !defined(CROSSGEN_COMPILE) - if (g_CLRJITPath != nullptr) - { - const WCHAR* p = wcsrchr(g_CLRJITPath, DIRECTORY_SEPARATOR_CHAR_W); - if (p != nullptr) - { - pwzJitName = p + 1; // Return just the filename, not the directory name - } - else - { - pwzJitName = g_CLRJITPath; - } - } -#endif // !defined(CROSSGEN_COMPILE) - - if (NULL == pwzJitName) - { - pwzJitName = MAKEDLLNAME_W(W("clrjit")); - } - - return pwzJitName; + return MAKEDLLNAME_W(W("clrjit")); } #endif // !FEATURE_MERGE_JIT_AND_ENGINE -#endif // #ifndef DACCESS_COMPILE - RangeSection* ExecutionManager::GetRangeSection(TADDR addr) { CONTRACTL { diff --git a/src/coreclr/src/vm/comcallablewrapper.cpp b/src/coreclr/src/vm/comcallablewrapper.cpp index c621eeb74304dd..583d52d1cf38d4 100644 --- a/src/coreclr/src/vm/comcallablewrapper.cpp +++ b/src/coreclr/src/vm/comcallablewrapper.cpp @@ -3678,8 +3678,7 @@ IDispatch* ComCallWrapper::GetIDispatchIP() CorIfaceAttr ifaceType = hndDefItfClass.GetMethodTable()->GetComInterfaceType(); if (IsDispatchBasedItf(ifaceType)) { - RETURN (IDispatch*)GetComIPFromCCW(this, GUID_NULL, hndDefItfClass.GetMethodTable(), - GetComIPFromCCW::SuppressSecurityCheck); + RETURN (IDispatch*)GetComIPFromCCW(this, GUID_NULL, hndDefItfClass.GetMethodTable()); } else { diff --git a/src/coreclr/src/vm/comcallablewrapper.h b/src/coreclr/src/vm/comcallablewrapper.h index 51b6f88d87b868..9ef02ec63e3848 100644 --- a/src/coreclr/src/vm/comcallablewrapper.h +++ b/src/coreclr/src/vm/comcallablewrapper.h @@ -957,8 +957,7 @@ struct GetComIPFromCCW { None = 0, CheckVisibility = 1, - SuppressSecurityCheck = 2, - SuppressCustomizedQueryInterface = 4 + SuppressCustomizedQueryInterface = 2 }; }; diff --git a/src/coreclr/src/vm/comdelegate.cpp b/src/coreclr/src/vm/comdelegate.cpp index 52e55a3eb6caab..e2b45fb108d1dd 100644 --- a/src/coreclr/src/vm/comdelegate.cpp +++ b/src/coreclr/src/vm/comdelegate.cpp @@ -22,10 +22,7 @@ #include "cgensys.h" #include "asmconstants.h" #include "virtualcallstub.h" -#include "callingconvention.h" -#include "customattribute.h" #include "typestring.h" -#include "../md/compiler/custattr.h" #ifdef FEATURE_COMINTEROP #include "comcallablewrapper.h" #endif // FEATURE_COMINTEROP @@ -1133,59 +1130,23 @@ void COMDelegate::BindToMethod(DELEGATEREF *pRefThis, } #if defined(TARGET_X86) -// Marshals a managed method to an unmanaged callback provided the -// managed method is static and it's parameters require no marshalling. -PCODE COMDelegate::ConvertToCallback(MethodDesc* pMD) +// Marshals a managed method to an unmanaged callback. +PCODE COMDelegate::ConvertToUnmanagedCallback(MethodDesc* pMD) { CONTRACTL { THROWS; GC_TRIGGERS; PRECONDITION(pMD != NULL); + PRECONDITION(pMD->HasUnmanagedCallersOnlyAttribute()); INJECT_FAULT(COMPlusThrowOM()); } CONTRACTL_END; - PCODE pCode = NULL; - // Get UMEntryThunk from the thunk cache. UMEntryThunk *pUMEntryThunk = pMD->GetLoaderAllocator()->GetUMEntryThunkCache()->GetUMEntryThunk(pMD); -#if !defined(FEATURE_STUBS_AS_IL) - - // System.Runtime.InteropServices.NativeCallableAttribute - BYTE* pData = NULL; - LONG cData = 0; - CorPinvokeMap callConv = (CorPinvokeMap)0; - - HRESULT hr = pMD->GetCustomAttribute(WellKnownAttribute::NativeCallable, (const VOID **)(&pData), (ULONG *)&cData); - IfFailThrow(hr); - - if (cData > 0) - { - CustomAttributeParser ca(pData, cData); - // NativeCallable has two optional named arguments CallingConvention and EntryPoint. - CaNamedArg namedArgs[2]; - CaTypeCtor caType(SERIALIZATION_TYPE_STRING); - // First, the void constructor. - IfFailThrow(ParseKnownCaArgs(ca, NULL, 0)); - - // Now the optional named properties - namedArgs[0].InitI4FieldEnum("CallingConvention", "System.Runtime.InteropServices.CallingConvention", (ULONG)callConv); - namedArgs[1].Init("EntryPoint", SERIALIZATION_TYPE_STRING, caType); - IfFailThrow(ParseKnownCaNamedArgs(ca, namedArgs, lengthof(namedArgs))); - - callConv = (CorPinvokeMap)(namedArgs[0].val.u4 << 8); - // Let UMThunkMarshalInfo choose the default if calling convension not definied. - if (namedArgs[0].val.type.tag != SERIALIZATION_TYPE_UNDEFINED) - { - UMThunkMarshInfo* pUMThunkMarshalInfo = pUMEntryThunk->GetUMThunkMarshInfo(); - pUMThunkMarshalInfo->SetCallingConvention(callConv); - } -} -#endif // !FEATURE_STUBS_AS_IL - - pCode = (PCODE)pUMEntryThunk->GetCode(); + PCODE pCode = (PCODE)pUMEntryThunk->GetCode(); _ASSERTE(pCode != NULL); return pCode; } @@ -2140,6 +2101,29 @@ FCIMPLEND #endif // CROSSGEN_COMPILE +void COMDelegate::ThrowIfInvalidUnmanagedCallersOnlyUsage(MethodDesc* pMD) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + PRECONDITION(pMD != NULL); + PRECONDITION(pMD->HasUnmanagedCallersOnlyAttribute()); + } + CONTRACTL_END; + + if (!pMD->IsStatic()) + EX_THROW(EEResourceException, (kInvalidProgramException, W("InvalidProgram_NonStaticMethod"))); + + // No generic methods + if (pMD->HasClassOrMethodInstantiation()) + EX_THROW(EEResourceException, (kInvalidProgramException, W("InvalidProgram_GenericMethod"))); + + // Arguments + if (NDirect::MarshalingRequired(pMD, pMD->GetSig(), pMD->GetModule())) + EX_THROW(EEResourceException, (kInvalidProgramException, W("InvalidProgram_NonBlittableTypes"))); +} + BOOL COMDelegate::NeedsWrapperDelegate(MethodDesc* pTargetMD) { LIMITED_METHOD_CONTRACT; @@ -2945,11 +2929,11 @@ MethodDesc* COMDelegate::GetDelegateCtor(TypeHandle delegateType, MethodDesc *pT // associated with the instantiation. BOOL fMaybeCollectibleAndStatic = FALSE; - // Do not allow static methods with [NativeCallableAttribute] to be a delegate target. - // A native callable method is special and allowing it to be delegate target will destabilize the runtime. - if (pTargetMethod->HasNativeCallableAttribute()) + // Do not allow static methods with [UnmanagedCallersOnlyAttribute] to be a delegate target. + // A method marked UnmanagedCallersOnly is special and allowing it to be delegate target will destabilize the runtime. + if (pTargetMethod->HasUnmanagedCallersOnlyAttribute()) { - COMPlusThrow(kNotSupportedException, W("NotSupported_NativeCallableTarget")); + COMPlusThrow(kNotSupportedException, W("NotSupported_UnmanagedCallersOnlyTarget")); } if (isStatic) @@ -3298,44 +3282,7 @@ static void InvokeUnhandledSwallowing(OBJECTREF *pDelegate, EX_TRY { -#if defined(FEATURE_CORRUPTING_EXCEPTIONS) - BOOL fCanMethodHandleException = g_pConfig->LegacyCorruptedStateExceptionsPolicy(); - if (!fCanMethodHandleException) - { - // CSE policy has not been overridden - proceed with our checks. - // - // Notifications for CSE are only delivered if the delegate target follows CSE rules. - // So, get the corruption severity of the active exception that has gone unhandled. - // - // By Default, assume that the active exception is not corrupting. - CorruptionSeverity severity = NotCorrupting; - Thread *pCurThread = GetThread(); - _ASSERTE(pCurThread != NULL); - ThreadExceptionState *pExState = pCurThread->GetExceptionState(); - if (pExState->IsExceptionInProgress()) - { - // If an exception is active, it implies we have a tracker for it. - // Hence, get the corruption severity from the active exception tracker. - severity = pExState->GetCurrentExceptionTracker()->GetCorruptionSeverity(); - _ASSERTE(severity > NotSet); - } - - // Notifications are delivered based upon corruption severity of the exception - fCanMethodHandleException = ExceptionNotifications::CanDelegateBeInvokedForException(pDelegate, severity); - if (!fCanMethodHandleException) - { - LOG((LF_EH, LL_INFO100, "InvokeUnhandledSwallowing: ADUEN Delegate cannot be invoked for corruption severity %d\n", - severity)); - } - } - - if (fCanMethodHandleException) -#endif // defined(FEATURE_CORRUPTING_EXCEPTIONS) - { - // We've already exercised the prestub on this delegate's COMDelegate::GetMethodDesc, - // as part of wiring up a reliable event sink. Deliver the notification. - ExceptionNotifications::DeliverExceptionNotification(UnhandledExceptionHandler, pDelegate, pDomain, pEventArgs); - } + ExceptionNotifications::DeliverExceptionNotification(UnhandledExceptionHandler, pDelegate, pDomain, pEventArgs); } EX_CATCH { diff --git a/src/coreclr/src/vm/comdelegate.h b/src/coreclr/src/vm/comdelegate.h index d11d79f9a830a9..39db2e778003d0 100644 --- a/src/coreclr/src/vm/comdelegate.h +++ b/src/coreclr/src/vm/comdelegate.h @@ -87,7 +87,7 @@ class COMDelegate #if defined(TARGET_X86) // Marshals a managed method to an unmanaged callback. // This is only used on x86. See usage for further details. - static PCODE ConvertToCallback(MethodDesc* pMD); + static PCODE ConvertToUnmanagedCallback(MethodDesc* pMD); #endif // defined(TARGET_X86) // Marshals an unmanaged callback to Delegate @@ -127,6 +127,10 @@ class COMDelegate static BOOL IsTrueMulticastDelegate(OBJECTREF delegate); + // Throw if the method violates any usage restrictions + // for UnmanagedCallersOnlyAttribute. + static void ThrowIfInvalidUnmanagedCallersOnlyUsage(MethodDesc* pMD); + private: static Stub* SetupShuffleThunk(MethodTable * pDelMT, MethodDesc *pTargetMeth); diff --git a/src/coreclr/src/vm/commodule.cpp b/src/coreclr/src/vm/commodule.cpp index 3a546963066756..51160cf2b896ca 100644 --- a/src/coreclr/src/vm/commodule.cpp +++ b/src/coreclr/src/vm/commodule.cpp @@ -888,7 +888,7 @@ HINSTANCE QCALLTYPE COMModule::GetHINSTANCE(QCall::ModuleHandle pModule) BEGIN_QCALL; - // This returns the base address - this will work for either HMODULE or HCORMODULES + // This returns the base address // Other modules should have zero base PEFile *pPEFile = pModule->GetFile(); if (!pPEFile->IsDynamic() && !pPEFile->IsResource()) @@ -1093,4 +1093,3 @@ FCIMPL0(void*, COMPunkSafeHandle::nGetDReleaseTarget) } FCIMPLEND - diff --git a/src/coreclr/src/vm/common.h b/src/coreclr/src/vm/common.h index 0679dd450583d8..7089b7536ebee9 100644 --- a/src/coreclr/src/vm/common.h +++ b/src/coreclr/src/vm/common.h @@ -98,7 +98,6 @@ #define POISONC ((UINT_PTR)((sizeof(int *) == 4)?0xCCCCCCCCL:I64(0xCCCCCCCCCCCCCCCC))) -#include "ndpversion.h" #include "switches.h" #include "holder.h" #include "classnames.h" @@ -286,6 +285,7 @@ namespace Loader #include "log.h" #include "loaderheap.h" #include "fixuppointer.h" +#include "stgpool.h" // src/vm #include "gcenv.interlocked.h" diff --git a/src/coreclr/src/vm/compatibilityswitch.cpp b/src/coreclr/src/vm/compatibilityswitch.cpp index dc10d536223bef..6a4f2cf7f8210b 100644 --- a/src/coreclr/src/vm/compatibilityswitch.cpp +++ b/src/coreclr/src/vm/compatibilityswitch.cpp @@ -30,8 +30,7 @@ FCIMPL2(StringObject*, CompatibilitySwitch::GetValue, StringObject* switchNameUN // only check in windows appcompat DB info.options = CLRConfig::IgnoreEnv | CLRConfig::IgnoreHKLM | - CLRConfig::IgnoreHKCU | - CLRConfig::IgnoreConfigFiles; + CLRConfig::IgnoreHKCU; } else { diff --git a/src/coreclr/src/vm/compile.cpp b/src/coreclr/src/vm/compile.cpp index 399947bad4b775..2d02eb3de51544 100644 --- a/src/coreclr/src/vm/compile.cpp +++ b/src/coreclr/src/vm/compile.cpp @@ -1223,11 +1223,11 @@ BOOL CEEPreloader::CanEmbedFunctionEntryPoint( MethodDesc * pMethod = GetMethod(methodHandle); - // Methods with native callable attribute are special , since - // they are used as LDFTN targets.Native Callable methods + // Methods with UnmanagedCallersOnlyAttribute are special, since + // they are used as LDFTN targets. UnmanagedCallersOnly methods // uses the same code path as reverse pinvoke and embedding them // in an ngen image require saving the reverse pinvoke stubs. - if (pMethod->HasNativeCallableAttribute()) + if (pMethod->HasUnmanagedCallersOnlyAttribute()) return FALSE; return TRUE; @@ -1272,12 +1272,12 @@ BOOL CEEPreloader::DoesMethodNeedRestoringBeforePrestubIsRun( return FALSE; } -BOOL CEECompileInfo::IsNativeCallableMethod(CORINFO_METHOD_HANDLE handle) +BOOL CEECompileInfo::IsUnmanagedCallersOnlyMethod(CORINFO_METHOD_HANDLE handle) { WRAPPER_NO_CONTRACT; MethodDesc * pMethod = GetMethod(handle); - return pMethod->HasNativeCallableAttribute(); + return pMethod->HasUnmanagedCallersOnlyAttribute(); } BOOL CEEPreloader::CanSkipDependencyActivation(CORINFO_METHOD_HANDLE context, diff --git a/src/coreclr/src/vm/compile.h b/src/coreclr/src/vm/compile.h index 36edc7f49b026b..aaa25cf08721d0 100644 --- a/src/coreclr/src/vm/compile.h +++ b/src/coreclr/src/vm/compile.h @@ -288,7 +288,7 @@ class CEECompileInfo : public ICorCompileInfo BOOL IsEmptyString(mdString token, CORINFO_MODULE_HANDLE module); - BOOL IsNativeCallableMethod(CORINFO_METHOD_HANDLE handle); + BOOL IsUnmanagedCallersOnlyMethod(CORINFO_METHOD_HANDLE handle); BOOL IsCachingOfInliningHintsEnabled() { diff --git a/src/coreclr/src/vm/comutilnative.cpp b/src/coreclr/src/vm/comutilnative.cpp index 1f0e257a548865..f66009b7bcb402 100644 --- a/src/coreclr/src/vm/comutilnative.cpp +++ b/src/coreclr/src/vm/comutilnative.cpp @@ -671,17 +671,12 @@ void QCALLTYPE Buffer::MemMove(void *dst, void *src, size_t length) // // GCInterface // - -UINT64 GCInterface::m_ulMemPressure = 0; -UINT64 GCInterface::m_ulThreshold = MIN_GC_MEMORYPRESSURE_THRESHOLD; INT32 GCInterface::m_gc_counts[3] = {0,0,0}; -CrstStatic GCInterface::m_MemoryPressureLock; - -UINT64 GCInterface::m_addPressure[NEW_PRESSURE_COUNT] = {0, 0, 0, 0}; // history of memory pressure additions -UINT64 GCInterface::m_remPressure[NEW_PRESSURE_COUNT] = {0, 0, 0, 0}; // history of memory pressure removals +UINT64 GCInterface::m_addPressure[MEM_PRESSURE_COUNT] = {0, 0, 0, 0}; // history of memory pressure additions +UINT64 GCInterface::m_remPressure[MEM_PRESSURE_COUNT] = {0, 0, 0, 0}; // history of memory pressure removals // incremented after a gen2 GC has been detected, -// (m_iteration % NEW_PRESSURE_COUNT) is used as an index into m_addPressure and m_remPressure +// (m_iteration % MEM_PRESSURE_COUNT) is used as an index into m_addPressure and m_remPressure UINT GCInterface::m_iteration = 0; FCIMPL6(void, GCInterface::GetMemoryInfo, UINT64* highMemLoadThreshold, UINT64* totalAvailableMemoryBytes, UINT64* lastRecordedMemLoadBytes, UINT32* lastRecordedMemLoadPct, size_t* lastRecordedHeapSizeBytes, size_t* lastRecordedFragmentationBytes) @@ -917,7 +912,7 @@ FCIMPL1(int, GCInterface::GetGenerationWR, LPVOID handle) OBJECTREF temp; temp = ObjectFromHandle((OBJECTHANDLE) handle); if (temp == NULL) - COMPlusThrowArgumentNull(W("weak handle")); + COMPlusThrowArgumentNull(W("wo")); iRetVal = (INT32)GCHeapUtilities::GetGCHeap()->WhichGeneration(OBJECTREFToObject(temp)); @@ -1273,79 +1268,11 @@ void QCALLTYPE GCInterface::_AddMemoryPressure(UINT64 bytesAllocated) { QCALL_CONTRACT; - // AddMemoryPressure could cause a GC, so we need a frame BEGIN_QCALL; AddMemoryPressure(bytesAllocated); END_QCALL; } -void GCInterface::AddMemoryPressure(UINT64 bytesAllocated) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - SendEtwAddMemoryPressureEvent(bytesAllocated); - - UINT64 newMemValue = InterlockedAdd(&m_ulMemPressure, bytesAllocated); - - if (newMemValue > m_ulThreshold) - { - INT32 gen_collect = 0; - { - GCX_PREEMP(); - CrstHolder holder(&m_MemoryPressureLock); - - // to avoid collecting too often, take the max threshold of the linear and geometric growth - // heuristics. - UINT64 addMethod; - UINT64 multMethod; - UINT64 bytesAllocatedMax = (UINT64_MAX - m_ulThreshold) / 8; - - if (bytesAllocated >= bytesAllocatedMax) // overflow check - { - addMethod = UINT64_MAX; - } - else - { - addMethod = m_ulThreshold + bytesAllocated * 8; - } - - multMethod = newMemValue + newMemValue / 10; - if (multMethod < newMemValue) // overflow check - { - multMethod = UINT64_MAX; - } - - m_ulThreshold = (addMethod > multMethod) ? addMethod : multMethod; - for (int i = 0; i <= 1; i++) - { - if ((GCHeapUtilities::GetGCHeap()->CollectionCount(i) / RELATIVE_GC_RATIO) > GCHeapUtilities::GetGCHeap()->CollectionCount(i + 1)) - { - gen_collect = i + 1; - break; - } - } - } - - PREFIX_ASSUME(gen_collect <= 2); - - if ((gen_collect == 0) || (m_gc_counts[gen_collect] == GCHeapUtilities::GetGCHeap()->CollectionCount(gen_collect))) - { - GarbageCollectModeAny(gen_collect); - } - - for (int i = 0; i < 3; i++) - { - m_gc_counts [i] = GCHeapUtilities::GetGCHeap()->CollectionCount(i); - } - } -} - #ifdef HOST_64BIT const unsigned MIN_MEMORYPRESSURE_BUDGET = 4 * 1024 * 1024; // 4 MB #else // HOST_64BIT @@ -1371,17 +1298,16 @@ void GCInterface::CheckCollectionCount() m_iteration++; - UINT p = m_iteration % NEW_PRESSURE_COUNT; + UINT p = m_iteration % MEM_PRESSURE_COUNT; m_addPressure[p] = 0; // new pressure will be accumulated here m_remPressure[p] = 0; } } - -// New AddMemoryPressure implementation (used by RCW and the CLRServicesImpl class) +// AddMemoryPressure implementation // -// 1. Less sensitive than the original implementation (start budget 3 MB) +// 1. Start budget - MIN_MEMORYPRESSURE_BUDGET // 2. Focuses more on newly added memory pressure // 3. Budget adjusted by effectiveness of last 3 triggered GC (add / remove ratio, max 10x) // 4. Budget maxed with 30% of current managed GC size @@ -1395,7 +1321,7 @@ void GCInterface::CheckCollectionCount() // and would be calculated based on historic data using standard exponential approximation: // Xnew = UMDeath/UMTotal * 0.5 + Xprev // -void GCInterface::NewAddMemoryPressure(UINT64 bytesAllocated) +void GCInterface::AddMemoryPressure(UINT64 bytesAllocated) { CONTRACTL { @@ -1407,11 +1333,11 @@ void GCInterface::NewAddMemoryPressure(UINT64 bytesAllocated) CheckCollectionCount(); - UINT p = m_iteration % NEW_PRESSURE_COUNT; + UINT p = m_iteration % MEM_PRESSURE_COUNT; UINT64 newMemValue = InterlockedAdd(&m_addPressure[p], bytesAllocated); - static_assert(NEW_PRESSURE_COUNT == 4, "NewAddMemoryPressure contains unrolled loops which depend on NEW_PRESSURE_COUNT"); + static_assert(MEM_PRESSURE_COUNT == 4, "AddMemoryPressure contains unrolled loops which depend on MEM_PRESSURE_COUNT"); UINT64 add = m_addPressure[0] + m_addPressure[1] + m_addPressure[2] + m_addPressure[3] - m_addPressure[p]; UINT64 rem = m_remPressure[0] + m_remPressure[1] + m_remPressure[2] + m_remPressure[3] - m_remPressure[p]; @@ -1425,7 +1351,7 @@ void GCInterface::NewAddMemoryPressure(UINT64 bytesAllocated) { UINT64 budget = MIN_MEMORYPRESSURE_BUDGET; - if (m_iteration >= NEW_PRESSURE_COUNT) // wait until we have enough data points + if (m_iteration >= MEM_PRESSURE_COUNT) // wait until we have enough data points { // Adjust according to effectiveness of GC // Scale budget according to past m_addPressure / m_remPressure ratio @@ -1489,54 +1415,9 @@ void GCInterface::RemoveMemoryPressure(UINT64 bytesAllocated) } CONTRACTL_END; - SendEtwRemoveMemoryPressureEvent(bytesAllocated); - - UINT64 newMemValue = InterlockedSub(&m_ulMemPressure, bytesAllocated); - UINT64 new_th; - UINT64 bytesAllocatedMax = (m_ulThreshold / 4); - UINT64 addMethod; - UINT64 multMethod = (m_ulThreshold - m_ulThreshold / 20); // can never underflow - if (bytesAllocated >= bytesAllocatedMax) // protect against underflow - { - m_ulThreshold = MIN_GC_MEMORYPRESSURE_THRESHOLD; - return; - } - else - { - addMethod = m_ulThreshold - bytesAllocated * 4; - } - - new_th = (addMethod < multMethod) ? addMethod : multMethod; - - if (newMemValue <= new_th) - { - GCX_PREEMP(); - CrstHolder holder(&m_MemoryPressureLock); - if (new_th > MIN_GC_MEMORYPRESSURE_THRESHOLD) - m_ulThreshold = new_th; - else - m_ulThreshold = MIN_GC_MEMORYPRESSURE_THRESHOLD; - - for (int i = 0; i < 3; i++) - { - m_gc_counts [i] = GCHeapUtilities::GetGCHeap()->CollectionCount(i); - } - } -} - -void GCInterface::NewRemoveMemoryPressure(UINT64 bytesAllocated) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - CheckCollectionCount(); - UINT p = m_iteration % NEW_PRESSURE_COUNT; + UINT p = m_iteration % MEM_PRESSURE_COUNT; SendEtwRemoveMemoryPressureEvent(bytesAllocated); @@ -1799,6 +1680,15 @@ FCIMPL0(void, COMInterlocked::FCMemoryBarrier) } FCIMPLEND +FCIMPL0(void, COMInterlocked::FCMemoryBarrierLoad) +{ + FCALL_CONTRACT; + + VolatileLoadBarrier(); + FC_GC_POLL(); +} +FCIMPLEND + #include void QCALLTYPE COMInterlocked::MemoryBarrierProcessWide() diff --git a/src/coreclr/src/vm/comutilnative.h b/src/coreclr/src/vm/comutilnative.h index 4493ec271326f1..a1a18c45afc5ae 100644 --- a/src/coreclr/src/vm/comutilnative.h +++ b/src/coreclr/src/vm/comutilnative.h @@ -74,25 +74,17 @@ class Buffer static void QCALLTYPE Clear(void *dst, size_t length); }; -#define MIN_GC_MEMORYPRESSURE_THRESHOLD 100000 -#define RELATIVE_GC_RATIO 8 - -const UINT NEW_PRESSURE_COUNT = 4; +const UINT MEM_PRESSURE_COUNT = 4; class GCInterface { private: - - static UINT64 m_ulMemPressure; - static UINT64 m_ulThreshold; static INT32 m_gc_counts[3]; - static UINT64 m_addPressure[NEW_PRESSURE_COUNT]; - static UINT64 m_remPressure[NEW_PRESSURE_COUNT]; + static UINT64 m_addPressure[MEM_PRESSURE_COUNT]; + static UINT64 m_remPressure[MEM_PRESSURE_COUNT]; static UINT m_iteration; public: - static CrstStatic m_MemoryPressureLock; - static FORCEINLINE UINT64 InterlockedAdd(UINT64 *pAugend, UINT64 addend); static FORCEINLINE UINT64 InterlockedSub(UINT64 *pMinuend, UINT64 subtrahend); @@ -150,15 +142,12 @@ class GCInterface { static void QCALLTYPE _RemoveMemoryPressure(UINT64 bytesAllocated); - static void RemoveMemoryPressure(UINT64 bytesAllocated); - static void AddMemoryPressure(UINT64 bytesAllocated); NOINLINE static void SendEtwRemoveMemoryPressureEvent(UINT64 bytesAllocated); static void SendEtwAddMemoryPressureEvent(UINT64 bytesAllocated); - // New less sensitive implementation of Add/RemoveMemoryPressure: static void CheckCollectionCount(); - static void NewRemoveMemoryPressure(UINT64 bytesAllocated); - static void NewAddMemoryPressure(UINT64 bytesAllocated); + static void RemoveMemoryPressure(UINT64 bytesAllocated); + static void AddMemoryPressure(UINT64 bytesAllocated); private: // Out-of-line helper to avoid EH prolog/epilog in functions that otherwise don't throw. @@ -184,6 +173,7 @@ class COMInterlocked static FCDECL2_IV(INT64, ExchangeAdd64, INT64 *location, INT64 value); static FCDECL0(void, FCMemoryBarrier); + static FCDECL0(void, FCMemoryBarrierLoad); static void QCALLTYPE MemoryBarrierProcessWide(); }; diff --git a/src/coreclr/src/vm/coreassemblyspec.cpp b/src/coreclr/src/vm/coreassemblyspec.cpp index 99ae244064758b..d2fc56ad064d9b 100644 --- a/src/coreclr/src/vm/coreassemblyspec.cpp +++ b/src/coreclr/src/vm/coreassemblyspec.cpp @@ -19,7 +19,7 @@ #include "domainfile.h" #include "holder.h" #include "../binder/inc/assemblybinder.hpp" - +#include "bundle.h" #include "strongnameinternal.h" #include "strongnameholders.h" @@ -174,10 +174,11 @@ VOID AssemblySpec::Bind(AppDomain *pAppDomain, } -STDAPI BinderAcquirePEImage(LPCWSTR wszAssemblyPath, - PEImage **ppPEImage, - PEImage **ppNativeImage, - BOOL fExplicitBindToNativeImage) +STDAPI BinderAcquirePEImage(LPCWSTR wszAssemblyPath, + PEImage **ppPEImage, + PEImage **ppNativeImage, + BOOL fExplicitBindToNativeImage, + BundleFileLocation bundleFileLocation) { HRESULT hr = S_OK; @@ -187,12 +188,13 @@ STDAPI BinderAcquirePEImage(LPCWSTR wszAssemblyPath, { PEImageHolder pImage = NULL; PEImageHolder pNativeImage = NULL; + AppDomain* pDomain = ::GetAppDomain(); // DEAD ? ? #ifdef FEATURE_PREJIT // fExplicitBindToNativeImage is set on Phone when we bind to a list of native images and have no IL on device for an assembly if (fExplicitBindToNativeImage) { - pNativeImage = PEImage::OpenImage(wszAssemblyPath, MDInternalImport_TrustedNativeImage); + pNativeImage = PEImage::OpenImage(wszAssemblyPath, MDInternalImport_TrustedNativeImage, bundleFileLocation); // Make sure that the IL image can be opened if the native image is not available. hr=pNativeImage->TryOpenFile(); @@ -204,7 +206,7 @@ STDAPI BinderAcquirePEImage(LPCWSTR wszAssemblyPath, else #endif { - pImage = PEImage::OpenImage(wszAssemblyPath, MDInternalImport_Default); + pImage = PEImage::OpenImage(wszAssemblyPath, MDInternalImport_Default, bundleFileLocation); // Make sure that the IL image can be opened if the native image is not available. hr=pImage->TryOpenFile(); diff --git a/src/coreclr/src/vm/corhost.cpp b/src/coreclr/src/vm/corhost.cpp index 6563b6c8474869..15c2bd1c767850 100644 --- a/src/coreclr/src/vm/corhost.cpp +++ b/src/coreclr/src/vm/corhost.cpp @@ -799,13 +799,10 @@ HRESULT CorHost2::CreateDelegate( if (pMD==NULL || !pMD->IsStatic() || pMD->HasClassOrMethodInstantiation()) ThrowHR(COR_E_MISSINGMETHOD); - if (pMD->HasNativeCallableAttribute()) + if (pMD->HasUnmanagedCallersOnlyAttribute()) { - if (NDirect::MarshalingRequired(pMD, pMD->GetSig(), pMD->GetModule())) - ThrowHR(COR_E_INVALIDPROGRAM); - #ifdef TARGET_X86 - *fnPtr = (INT_PTR)COMDelegate::ConvertToCallback(pMD); + *fnPtr = (INT_PTR)COMDelegate::ConvertToUnmanagedCallback(pMD); #else *fnPtr = pMD->GetMultiCallableAddrOfCode(); #endif diff --git a/src/coreclr/src/vm/crossgen/CMakeLists.txt b/src/coreclr/src/vm/crossgen/CMakeLists.txt index 6a42ab503b21f9..b532a9ecdc3cb3 100644 --- a/src/coreclr/src/vm/crossgen/CMakeLists.txt +++ b/src/coreclr/src/vm/crossgen/CMakeLists.txt @@ -6,6 +6,7 @@ set(VM_CROSSGEN_SOURCES ../assemblyspec.cpp ../baseassemblyspec.cpp ../binder.cpp + ../bundle.cpp ../castcache.cpp ../ceeload.cpp ../ceemain.cpp @@ -76,6 +77,7 @@ set(VM_CROSSGEN_SOURCES ../stubcache.cpp ../stubgen.cpp ../stublink.cpp + ../tailcallhelp.cpp ../typectxt.cpp ../typedesc.cpp ../typeequivalencehash.cpp @@ -173,6 +175,7 @@ set(VM_CROSSGEN_HEADERS ../stubgen.h ../stublink.h ../stublink.inl + ../tailcallhelp.h ../typectxt.h ../typedesc.h ../typedesc.inl diff --git a/src/coreclr/src/vm/diagnosticserver.cpp b/src/coreclr/src/vm/diagnosticserver.cpp index 5a80396179ae00..9879c7b1e35dcd 100644 --- a/src/coreclr/src/vm/diagnosticserver.cpp +++ b/src/coreclr/src/vm/diagnosticserver.cpp @@ -4,6 +4,7 @@ #include "common.h" #include "diagnosticserver.h" +#include "ipcstreamfactory.h" #include "eventpipeprotocolhelper.h" #include "dumpdiagnosticprotocolhelper.h" #include "profilerdiagnosticprotocolhelper.h" @@ -19,7 +20,6 @@ #ifdef FEATURE_PERFTRACING -IpcStream::DiagnosticsIpc *DiagnosticServer::s_pIpc = nullptr; Volatile DiagnosticServer::s_shuttingDown(false); DWORD WINAPI DiagnosticServer::DiagnosticsServerThread(LPVOID) @@ -29,11 +29,11 @@ DWORD WINAPI DiagnosticServer::DiagnosticsServerThread(LPVOID) NOTHROW; GC_TRIGGERS; MODE_PREEMPTIVE; - PRECONDITION(s_pIpc != nullptr); + PRECONDITION(IpcStreamFactory::HasActiveConnections()); } CONTRACTL_END; - if (s_pIpc == nullptr) + if (!IpcStreamFactory::HasActiveConnections()) { STRESS_LOG0(LF_DIAGNOSTICS_PORT, LL_ERROR, "Diagnostics IPC listener was undefined\n"); return 1; @@ -47,8 +47,7 @@ DWORD WINAPI DiagnosticServer::DiagnosticsServerThread(LPVOID) { while (!s_shuttingDown) { - // FIXME: Ideally this would be something like a std::shared_ptr - IpcStream *pStream = s_pIpc->Accept(LoggingCallback); + IpcStream *pStream = IpcStreamFactory::GetNextAvailableStream(LoggingCallback); if (pStream == nullptr) continue; @@ -76,11 +75,9 @@ DWORD WINAPI DiagnosticServer::DiagnosticsServerThread(LPVOID) EventPipeProtocolHelper::HandleIpcMessage(message, pStream); break; -#ifdef TARGET_UNIX case DiagnosticsIpc::DiagnosticServerCommandSet::Dump: DumpDiagnosticProtocolHelper::HandleIpcMessage(message, pStream); break; -#endif #ifdef FEATURE_PROFAPI_ATTACH_DETACH case DiagnosticsIpc::DiagnosticServerCommandSet::Profiler: @@ -136,7 +133,7 @@ bool DiagnosticServer::Initialize() }; NewArrayHolder address = nullptr; - CLRConfigStringHolder wAddress = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DOTNET_DiagnosticsServerAddress); + CLRConfigStringHolder wAddress = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DOTNET_DiagnosticsMonitorAddress); int nCharactersWritten = 0; if (wAddress != nullptr) { @@ -147,12 +144,14 @@ bool DiagnosticServer::Initialize() nCharactersWritten = WideCharToMultiByte(CP_UTF8, 0, wAddress, -1, address, nCharactersWritten, NULL, NULL); assert(nCharactersWritten != 0); } + + // Create the client mode connection + fSuccess &= IpcStreamFactory::CreateClient(address, ErrorCallback); } - // TODO: Should we handle/assert that (s_pIpc == nullptr)? - s_pIpc = IpcStream::DiagnosticsIpc::Create(address, ErrorCallback); + fSuccess &= IpcStreamFactory::CreateServer(nullptr, ErrorCallback); - if (s_pIpc != nullptr) + if (IpcStreamFactory::HasActiveConnections()) { #ifdef FEATURE_AUTO_TRACE auto_trace_init(); @@ -163,14 +162,13 @@ bool DiagnosticServer::Initialize() nullptr, // no security attribute 0, // default stack size DiagnosticsServerThread, // thread proc - (LPVOID)s_pIpc, // thread parameter + nullptr, // thread parameter 0, // not suspended &dwThreadId); // returns thread ID if (hServerThread == NULL) { - delete s_pIpc; - s_pIpc = nullptr; + IpcStreamFactory::CloseConnections(); // Failed to create IPC thread. STRESS_LOG1( @@ -215,7 +213,7 @@ bool DiagnosticServer::Shutdown() EX_TRY { - if (s_pIpc != nullptr) + if (IpcStreamFactory::HasActiveConnections()) { auto ErrorCallback = [](const char *szMessage, uint32_t code) { STRESS_LOG2( @@ -225,7 +223,8 @@ bool DiagnosticServer::Shutdown() code, // data1 szMessage); // data2 }; - s_pIpc->Close(ErrorCallback); // This will break the accept waiting for client connection. + + IpcStreamFactory::Shutdown(ErrorCallback); } fSuccess = true; } diff --git a/src/coreclr/src/vm/diagnosticserver.h b/src/coreclr/src/vm/diagnosticserver.h index 393fbda0bd9ae2..a5b8f07f7847b2 100644 --- a/src/coreclr/src/vm/diagnosticserver.h +++ b/src/coreclr/src/vm/diagnosticserver.h @@ -46,7 +46,6 @@ class DiagnosticServer final static DWORD WINAPI DiagnosticsServerThread(LPVOID lpThreadParameter); private: - static IpcStream::DiagnosticsIpc *s_pIpc; static Volatile s_shuttingDown; }; diff --git a/src/coreclr/src/vm/diagnosticsprotocol.h b/src/coreclr/src/vm/diagnosticsprotocol.h index bbc622a6411a3c..e6bd3d4e89a8d3 100644 --- a/src/coreclr/src/vm/diagnosticsprotocol.h +++ b/src/coreclr/src/vm/diagnosticsprotocol.h @@ -103,6 +103,60 @@ namespace DiagnosticsIpc const MagicVersion DotnetIpcMagic_V1 = { "DOTNET_IPC_V1" }; + /** + * ==ADVERTISE PROTOCOL== + * Before standard IPC Protocol communication can occur on a client-mode connection + * the runtime must advertise itself over the connection. ALL SUBSEQUENT COMMUNICATION + * IS STANDARD DIAGNOSTICS IPC PROTOCOL COMMUNICATION. + * + * See spec in: dotnet/diagnostics@documentation/design-docs/ipc-spec.md + * + * The flow for Advertise is a one-way burst of 24 bytes consisting of + * 8 bytes - "ADVR_V1\0" (ASCII chars + null byte) + * 16 bytes - random 128 bit number cookie (little-endian) + * 8 bytes - PID (little-endian) + * 2 bytes - unused 2 byte field for futureproofing + */ + + const uint8_t AdvertiseMagic_V1[8] = "ADVR_V1"; + + const uint32_t AdvertiseSize = 34; + + static GUID AdvertiseCookie_V1 = GUID_NULL; + + inline GUID GetAdvertiseCookie_V1() + { + if (AdvertiseCookie_V1 == GUID_NULL) + { + CoCreateGuid(&AdvertiseCookie_V1); + } + + return AdvertiseCookie_V1; + } + + inline bool SendIpcAdvertise_V1(IpcStream *pStream) + { + uint8_t advertiseBuffer[DiagnosticsIpc::AdvertiseSize]; + GUID cookie = GetAdvertiseCookie_V1(); + uint64_t pid = GetCurrentProcessId(); + + uint64_t *buffer = (uint64_t*)advertiseBuffer; + buffer[0] = *(uint64_t*)AdvertiseMagic_V1; + buffer[1] = (((uint64_t)VAL32(cookie.Data1) << 32) | ((uint64_t)VAL16(cookie.Data2) << 16) | VAL16((uint64_t)cookie.Data3)); + buffer[2] = *(uint64_t*)cookie.Data4; + buffer[3] = VAL64(pid); + + // zero out unused field + ((uint16_t*)advertiseBuffer)[16] = VAL16(0); + + uint32_t nBytesWritten = 0; + if (!pStream->Write(advertiseBuffer, sizeof(advertiseBuffer), nBytesWritten, 100 /* ms */)) + return false; + + _ASSERTE(nBytesWritten == sizeof(advertiseBuffer)); + return nBytesWritten == sizeof(advertiseBuffer); + } + const IpcHeader GenericSuccessHeader = { { DotnetIpcMagic_V1 }, diff --git a/src/coreclr/src/vm/dispatchinfo.cpp b/src/coreclr/src/vm/dispatchinfo.cpp index 8da1151b93c05c..dca9108f1d8532 100644 --- a/src/coreclr/src/vm/dispatchinfo.cpp +++ b/src/coreclr/src/vm/dispatchinfo.cpp @@ -2193,10 +2193,8 @@ HRESULT DispatchInfo::InvokeMember(SimpleComCallWrapper *pSimpleWrap, DISPID id, EX_CATCH { pThrowable = GET_THROWABLE(); - - // RethrowCorruptingExceptionsEx, in EX_END_CATCH below, will ensure that CEs are rethrown. } - EX_END_CATCH(RethrowCorruptingExceptionsEx(!CEHelper::CanIDispatchTargetHandleException())) + EX_END_CATCH(RethrowTerminalExceptions) catchFrame.Pop(); if (pThrowable != NULL) diff --git a/src/coreclr/src/vm/dllimport.cpp b/src/coreclr/src/vm/dllimport.cpp index 0046ed957c3906..99a63ac3f5b11e 100644 --- a/src/coreclr/src/vm/dllimport.cpp +++ b/src/coreclr/src/vm/dllimport.cpp @@ -410,12 +410,14 @@ class ILStubState : public StubState locDescInnerPtr.MakeByRef(); pcsDispatch->SetStubTargetArgType(&locDescInnerPtr, false); pcsDispatch->EmitLDLOCA(dwInnerIInspectableLocalNum); + pcsDispatch->EmitCONV_I(); } // pass pointer to the local to the factory method (last argument) locDescFactoryRetVal.MakeByRef(); pcsDispatch->SetStubTargetArgType(&locDescFactoryRetVal, false); pcsDispatch->EmitLDLOCA(dwFactoryRetValLocalNum); + pcsDispatch->EmitCONV_I(); /* * UNMARSHAL @@ -4795,7 +4797,7 @@ void NDirect::PopulateNDirectMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSi if (callConv == pmCallConvThiscall) ndirectflags |= NDirectMethodDesc::kThisCall; - if (pNMD->GetLoaderModule()->IsSystem() && (strcmp(szLibName, "QCall") == 0 || strcmp(szLibName, "libSystem.Globalization.Native") == 0)) + if (pNMD->GetLoaderModule()->IsSystem() && strcmp(szLibName, "QCall") == 0) { ndirectflags |= NDirectMethodDesc::kIsQCall; } diff --git a/src/coreclr/src/vm/dllimport.h b/src/coreclr/src/vm/dllimport.h index 4b7f011f8fd092..afed587a091b21 100644 --- a/src/coreclr/src/vm/dllimport.h +++ b/src/coreclr/src/vm/dllimport.h @@ -176,16 +176,19 @@ enum ILStubTypes #ifdef FEATURE_ARRAYSTUB_AS_IL ILSTUB_ARRAYOP_GET = 0x80000001, ILSTUB_ARRAYOP_SET = 0x80000002, - ILSTUB_ARRAYOP_ADDRESS = 0x80000004, + ILSTUB_ARRAYOP_ADDRESS = 0x80000003, #endif #ifdef FEATURE_MULTICASTSTUB_AS_IL - ILSTUB_MULTICASTDELEGATE_INVOKE = 0x80000010, + ILSTUB_MULTICASTDELEGATE_INVOKE = 0x80000004, #endif #ifdef FEATURE_INSTANTIATINGSTUB_AS_IL - ILSTUB_UNBOXINGILSTUB = 0x80000020, - ILSTUB_INSTANTIATINGSTUB = 0x80000040, + ILSTUB_UNBOXINGILSTUB = 0x80000005, + ILSTUB_INSTANTIATINGSTUB = 0x80000006, #endif - ILSTUB_WRAPPERDELEGATE_INVOKE = 0x80000080, + ILSTUB_WRAPPERDELEGATE_INVOKE = 0x80000007, + ILSTUB_TAILCALL_STOREARGS = 0x80000008, + ILSTUB_TAILCALL_CALLTARGET = 0x80000009, + ILSTUB_TAILCALL_DISPATCH = 0x8000000A, }; #ifdef FEATURE_COMINTEROP @@ -223,6 +226,9 @@ inline bool SF_IsWrapperDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CON inline bool SF_IsUnboxingILStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_UNBOXINGILSTUB); } inline bool SF_IsInstantiatingStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_INSTANTIATINGSTUB); } #endif +inline bool SF_IsTailCallStoreArgsStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_TAILCALL_STOREARGS); } +inline bool SF_IsTailCallCallTargetStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_TAILCALL_CALLTARGET); } +inline bool SF_IsTailCallDispatcherStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_TAILCALL_DISPATCH); } inline bool SF_IsCOMStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_COM)); } inline bool SF_IsWinRTStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return COM_ONLY(dwStubFlags < NDIRECTSTUB_FL_INVALID && 0 != (dwStubFlags & NDIRECTSTUB_FL_WINRT)); } @@ -247,7 +253,18 @@ inline bool SF_IsSharedStub(DWORD dwStubFlags) return false; } - return !SF_IsFieldGetterStub(dwStubFlags) && !SF_IsFieldSetterStub(dwStubFlags); + if (SF_IsTailCallStoreArgsStub(dwStubFlags) || SF_IsTailCallCallTargetStub(dwStubFlags) || + SF_IsTailCallDispatcherStub(dwStubFlags)) + { + return false; + } + + if (SF_IsFieldGetterStub(dwStubFlags) || SF_IsFieldSetterStub(dwStubFlags)) + { + return false; + } + + return true; } inline bool SF_IsForwardStub (DWORD dwStubFlags) { WRAPPER_NO_CONTRACT; return !SF_IsReverseStub(dwStubFlags); } diff --git a/src/coreclr/src/vm/dllimportcallback.cpp b/src/coreclr/src/vm/dllimportcallback.cpp index 67b660f59ebd8a..9ec4153e651fc3 100644 --- a/src/coreclr/src/vm/dllimportcallback.cpp +++ b/src/coreclr/src/vm/dllimportcallback.cpp @@ -21,6 +21,8 @@ #include "dbginterface.h" #include "stubgen.h" #include "appdomain.inl" +#include "callingconvention.h" +#include "customattribute.h" #ifndef CROSSGEN_COMPILE @@ -612,6 +614,43 @@ VOID UMEntryThunk::CompileUMThunkWorker(UMThunkStubInfo *pInfo, pcpusl->X86EmitNearJump(pEnableRejoin); } +VOID UMThunkMarshInfo::SetUpForUnmanagedCallersOnly() +{ + STANDARD_VM_CONTRACT; + + MethodDesc* pMD = GetMethod(); + _ASSERTE(pMD != NULL && pMD->HasUnmanagedCallersOnlyAttribute()); + + // Validate UnmanagedCallersOnlyAttribute usage + COMDelegate::ThrowIfInvalidUnmanagedCallersOnlyUsage(pMD); + + BYTE* pData = NULL; + LONG cData = 0; + CorPinvokeMap callConv = (CorPinvokeMap)0; + + HRESULT hr = pMD->GetCustomAttribute(WellKnownAttribute::UnmanagedCallersOnly, (const VOID **)(&pData), (ULONG *)&cData); + IfFailThrow(hr); + + _ASSERTE(cData > 0); + + CustomAttributeParser ca(pData, cData); + // UnmanagedCallersOnly has two optional named arguments CallingConvention and EntryPoint. + CaNamedArg namedArgs[2]; + CaTypeCtor caType(SERIALIZATION_TYPE_STRING); + // First, the void constructor. + IfFailThrow(ParseKnownCaArgs(ca, NULL, 0)); + + // Now the optional named properties + namedArgs[0].InitI4FieldEnum("CallingConvention", "System.Runtime.InteropServices.CallingConvention", (ULONG)callConv); + namedArgs[1].Init("EntryPoint", SERIALIZATION_TYPE_STRING, caType); + IfFailThrow(ParseKnownCaNamedArgs(ca, namedArgs, lengthof(namedArgs))); + + callConv = (CorPinvokeMap)(namedArgs[0].val.u4 << 8); + // Let UMThunkMarshalInfo choose the default if calling convension not definied. + if (namedArgs[0].val.type.tag != SERIALIZATION_TYPE_UNDEFINED) + m_callConv = (UINT16)callConv; +} + // Compiles an unmanaged to managed thunk for the given signature. Stub *UMThunkMarshInfo::CompileNExportThunk(LoaderHeap *pLoaderHeap, PInvokeStaticSigInfo* pSigInfo, MetaSig *pMetaSig, BOOL fNoStub) { @@ -721,7 +760,9 @@ Stub *UMThunkMarshInfo::CompileNExportThunk(LoaderHeap *pLoaderHeap, PInvokeStat m_cbActualArgSize = cbActualArgSize; - m_callConv = static_cast(pSigInfo->GetCallConv()); + // This could have been set in the UnmanagedCallersOnly scenario. + if (m_callConv == UINT16_MAX) + m_callConv = static_cast(pSigInfo->GetCallConv()); UMThunkStubInfo stubInfo; memset(&stubInfo, 0, sizeof(stubInfo)); @@ -848,8 +889,9 @@ UMEntryThunk *UMEntryThunkCache::GetUMEntryThunk(MethodDesc *pMD) RETURN pThunk; } -// FailFast if a native callable method invoked directly from managed code. -// UMThunkStub.asm check the mode and call this function to failfast. +// FailFast if a method marked UnmanagedCallersOnlyAttribute is +// invoked directly from managed code. UMThunkStub.asm check the +// mode and call this function to failfast. extern "C" VOID STDCALL ReversePInvokeBadTransition() { STATIC_CONTRACT_THROWS; @@ -857,7 +899,7 @@ extern "C" VOID STDCALL ReversePInvokeBadTransition() // Fail EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE( COR_E_EXECUTIONENGINE, - W("Invalid Program: attempted to call a NativeCallable method from managed code.") + W("Invalid Program: attempted to call a UnmanagedCallersOnly method from managed code.") ); } @@ -1116,6 +1158,7 @@ VOID UMThunkMarshInfo::LoadTimeInit(Signature sig, Module * pModule, MethodDesc m_sig = sig; #if defined(TARGET_X86) && !defined(FEATURE_STUBS_AS_IL) + m_callConv = UINT16_MAX; INDEBUG(m_cbRetPop = 0xcccc;) #endif } @@ -1141,6 +1184,14 @@ VOID UMThunkMarshInfo::RunTimeInit() MethodDesc * pMD = GetMethod(); +#if defined(TARGET_X86) && !defined(FEATURE_STUBS_AS_IL) + if (pMD != NULL + && pMD->HasUnmanagedCallersOnlyAttribute()) + { + SetUpForUnmanagedCallersOnly(); + } +#endif // TARGET_X86 && !FEATURE_STUBS_AS_IL + // Lookup NGened stub - currently we only support ngening of reverse delegate invoke interop stubs if (pMD != NULL && pMD->IsEEImpl()) { diff --git a/src/coreclr/src/vm/dllimportcallback.h b/src/coreclr/src/vm/dllimportcallback.h index 12bc89a167fdc8..b92b8e8784ccd4 100644 --- a/src/coreclr/src/vm/dllimportcallback.h +++ b/src/coreclr/src/vm/dllimportcallback.h @@ -146,26 +146,6 @@ class UMThunkMarshInfo return m_cbRetPop; } - CorPinvokeMap GetCallingConvention() - { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - SUPPORTS_DAC; - PRECONDITION(IsCompletelyInited()); - } - CONTRACTL_END; - - return (CorPinvokeMap)m_callConv; - } - - VOID SetCallingConvention(const CorPinvokeMap callConv) - { - m_callConv = (UINT16)callConv; - } - #else PCODE GetExecStubEntryPoint(); #endif @@ -195,6 +175,9 @@ class UMThunkMarshInfo VOID SetupArguments(char *pSrc, ArgumentRegisters *pArgRegs, char *pDst); #else +private: + VOID SetUpForUnmanagedCallersOnly(); + // Compiles an unmanaged to managed thunk for the given signature. The thunk // will call the stub or, if fNoStub == TRUE, directly the managed target. Stub *CompileNExportThunk(LoaderHeap *pLoaderHeap, PInvokeStaticSigInfo* pSigInfo, MetaSig *pMetaSig, BOOL fNoStub); diff --git a/src/coreclr/src/vm/domainfile.cpp b/src/coreclr/src/vm/domainfile.cpp index ff5621317fc414..ca7a86c869bba4 100644 --- a/src/coreclr/src/vm/domainfile.cpp +++ b/src/coreclr/src/vm/domainfile.cpp @@ -1685,10 +1685,10 @@ void DomainAssembly::GetCurrentVersionInfo(CORCOMPILE_VERSION_INFO *pNativeVersi pNativeVersionInfo->wMachine = IMAGE_FILE_MACHINE_NATIVE_NI; - pNativeVersionInfo->wVersionMajor = CLR_MAJOR_VERSION; - pNativeVersionInfo->wVersionMinor = CLR_MINOR_VERSION; - pNativeVersionInfo->wVersionBuildNumber = CLR_BUILD_VERSION; - pNativeVersionInfo->wVersionPrivateBuildNumber = CLR_BUILD_VERSION_QFE; + pNativeVersionInfo->wVersionMajor = RuntimeFileMajorVersion; + pNativeVersionInfo->wVersionMinor = RuntimeFileMinorVersion; + pNativeVersionInfo->wVersionBuildNumber = RuntimeFileBuildVersion; + pNativeVersionInfo->wVersionPrivateBuildNumber = RuntimeFileRevisionVersion; GetNGenCpuInfo(&pNativeVersionInfo->cpuInfo); diff --git a/src/coreclr/src/vm/dumpdiagnosticprotocolhelper.cpp b/src/coreclr/src/vm/dumpdiagnosticprotocolhelper.cpp index 2596943081b8e4..920691f988d5e1 100644 --- a/src/coreclr/src/vm/dumpdiagnosticprotocolhelper.cpp +++ b/src/coreclr/src/vm/dumpdiagnosticprotocolhelper.cpp @@ -10,8 +10,6 @@ #ifdef FEATURE_PERFTRACING -#ifdef HOST_UNIX - void DumpDiagnosticProtocolHelper::HandleIpcMessage(DiagnosticsIpc::IpcMessage& message, IpcStream* pStream) { CONTRACTL @@ -91,6 +89,7 @@ void DumpDiagnosticProtocolHelper::GenerateCoreDump(DiagnosticsIpc::IpcMessage& return; } +#ifdef HOST_UNIX MAKE_UTF8PTR_FROMWIDE_NOTHROW(szDumpName, payload->dumpName); if (szDumpName != nullptr) { @@ -107,6 +106,14 @@ void DumpDiagnosticProtocolHelper::GenerateCoreDump(DiagnosticsIpc::IpcMessage& delete pStream; return; } +#else + if (!GenerateCrashDump(payload->dumpName, payload->dumpType, payload->diagnostics)) + { + DiagnosticsIpc::IpcMessage::SendErrorMessage(pStream, E_FAIL); + delete pStream; + return; + } +#endif DiagnosticsIpc::IpcMessage successResponse; HRESULT success = S_OK; @@ -115,6 +122,4 @@ void DumpDiagnosticProtocolHelper::GenerateCoreDump(DiagnosticsIpc::IpcMessage& delete pStream; } -#endif // HOST_UNIX - #endif // FEATURE_PERFTRACING diff --git a/src/coreclr/src/vm/dumpdiagnosticprotocolhelper.h b/src/coreclr/src/vm/dumpdiagnosticprotocolhelper.h index af10a5177b05db..bd0055423d6e70 100644 --- a/src/coreclr/src/vm/dumpdiagnosticprotocolhelper.h +++ b/src/coreclr/src/vm/dumpdiagnosticprotocolhelper.h @@ -41,10 +41,8 @@ class DumpDiagnosticProtocolHelper { public: // IPC event handlers. -#ifdef HOST_UNIX static void GenerateCoreDump(DiagnosticsIpc::IpcMessage& message, IpcStream *pStream); // `dotnet-dump collect` static void HandleIpcMessage(DiagnosticsIpc::IpcMessage& message, IpcStream* pStream); -#endif private: const static uint32_t IpcStreamReadBufferSize = 8192; diff --git a/src/coreclr/src/vm/dwbucketmanager.hpp b/src/coreclr/src/vm/dwbucketmanager.hpp index 535adb3eb5d75e..eb7beac884d2f1 100644 --- a/src/coreclr/src/vm/dwbucketmanager.hpp +++ b/src/coreclr/src/vm/dwbucketmanager.hpp @@ -431,7 +431,7 @@ void BaseBucketParamsManager::PopulateBucketParameter(BucketParameterIndex param CONTRACTL { NOTHROW; - GC_NOTRIGGER; + GC_TRIGGERS; MODE_ANY; } CONTRACTL_END; @@ -452,7 +452,7 @@ void BaseBucketParamsManager::GetAppName(__out_ecount(maxLength) WCHAR* targetPa { NOTHROW; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -475,8 +475,8 @@ void BaseBucketParamsManager::GetAppVersion(__out_ecount(maxLength) WCHAR* targe CONTRACTL { NOTHROW; - GC_NOTRIGGER; - MODE_ANY; + GC_TRIGGERS; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -511,7 +511,7 @@ void BaseBucketParamsManager::GetAppTimeStamp(__out_ecount(maxLength) WCHAR* tar { NOTHROW; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -543,7 +543,7 @@ void BaseBucketParamsManager::GetModuleName(__out_ecount(maxLength) WCHAR* targe { NOTHROW; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -632,8 +632,8 @@ void BaseBucketParamsManager::GetModuleVersion(__out_ecount(maxLength) WCHAR* ta CONTRACTL { NOTHROW; - GC_NOTRIGGER; - MODE_ANY; + GC_TRIGGERS; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -689,7 +689,7 @@ void BaseBucketParamsManager::GetModuleTimeStamp(__out_ecount(maxLength) WCHAR* { NOTHROW; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -742,7 +742,7 @@ void BaseBucketParamsManager::GetMethodDef(__out_ecount(maxLength) WCHAR* target { NOTHROW; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -767,7 +767,7 @@ void BaseBucketParamsManager::GetIlOffset(__out_ecount(maxLength) WCHAR* targetP { NOTHROW; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -786,7 +786,7 @@ void BaseBucketParamsManager::GetExceptionName(__out_ecount(maxLength) WCHAR* ta { NOTHROW; GC_NOTRIGGER; - MODE_ANY; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -954,8 +954,8 @@ bool BaseBucketParamsManager::GetFileVersionInfoForModule(Module* pModule, USHOR CONTRACTL { NOTHROW; - GC_NOTRIGGER; - MODE_ANY; + GC_TRIGGERS; + MODE_PREEMPTIVE; PRECONDITION(pModule != NULL); } CONTRACTL_END; @@ -1215,11 +1215,14 @@ void CLR20r3BucketParamsManager::PopulateBucketParameters() CONTRACTL { NOTHROW; - GC_NOTRIGGER; + GC_TRIGGERS; MODE_ANY; } CONTRACTL_END; + // Preempt to let GC suspend + GCX_PREEMP(); + PopulateEventName(g_WerEventTraits[CLR20r3].EventName); // the "+ 1" is to explicitly indicate which fields need to specify space for NULL diff --git a/src/coreclr/src/vm/dwreport.cpp b/src/coreclr/src/vm/dwreport.cpp index 4cc5950f7fc9a6..0b9a2c94382939 100644 --- a/src/coreclr/src/vm/dwreport.cpp +++ b/src/coreclr/src/vm/dwreport.cpp @@ -189,8 +189,8 @@ HRESULT DwGetFileVersionInfo( CONTRACTL { NOTHROW; - GC_NOTRIGGER; - MODE_ANY; + GC_TRIGGERS; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -602,7 +602,7 @@ HRESULT GetManagedBucketParametersForIp( CONTRACTL { NOTHROW; - GC_NOTRIGGER; + GC_TRIGGERS; MODE_ANY; } CONTRACTL_END; @@ -677,7 +677,7 @@ void* GetBucketParametersForManagedException(UINT_PTR ip, TypeOfReportedError to CONTRACTL { NOTHROW; - GC_NOTRIGGER; + GC_TRIGGERS; MODE_ANY; } CONTRACTL_END; diff --git a/src/coreclr/src/vm/ecalllist.h b/src/coreclr/src/vm/ecalllist.h index 78ca688279ca93..243a735c2b2e49 100644 --- a/src/coreclr/src/vm/ecalllist.h +++ b/src/coreclr/src/vm/ecalllist.h @@ -859,6 +859,7 @@ FCFuncStart(gInterlockedFuncs) FCIntrinsicSig("ExchangeAdd", &gsig_SM_RefLong_Long_RetLong, COMInterlocked::ExchangeAdd64, CORINFO_INTRINSIC_InterlockedXAdd64) FCIntrinsic("MemoryBarrier", COMInterlocked::FCMemoryBarrier, CORINFO_INTRINSIC_MemoryBarrier) + FCIntrinsic("ReadMemoryBarrier", COMInterlocked::FCMemoryBarrierLoad, CORINFO_INTRINSIC_MemoryBarrierLoad) QCFuncElement("_MemoryBarrierProcessWide", COMInterlocked::MemoryBarrierProcessWide) FCFuncEnd() @@ -905,6 +906,11 @@ FCFuncStart(gRuntimeHelpers) FCFuncElement("TryEnsureSufficientExecutionStack", ReflectionInvocation::TryEnsureSufficientExecutionStack) FCFuncElement("GetUninitializedObjectInternal", ReflectionSerialization::GetUninitializedObject) QCFuncElement("AllocateTypeAssociatedMemoryInternal", RuntimeTypeHandle::AllocateTypeAssociatedMemory) + FCFuncElement("AllocTailCallArgBuffer", TailCallHelp::AllocTailCallArgBuffer) + FCFuncElement("FreeTailCallArgBuffer", TailCallHelp::FreeTailCallArgBuffer) + FCFuncElement("GetTailCallInfo", TailCallHelp::GetTailCallInfo) + FCFuncElement("GetILBytesJitted", GetJittedBytes) + FCFuncElement("GetMethodsJittedCount", GetJittedMethodsCount) FCFuncEnd() FCFuncStart(gContextSynchronizationFuncs) @@ -981,7 +987,8 @@ FCFuncStart(gComWrappersFuncs) QCFuncElement("GetIUnknownImplInternal", ComWrappersNative::GetIUnknownImpl) QCFuncElement("TryGetOrCreateComInterfaceForObjectInternal", ComWrappersNative::TryGetOrCreateComInterfaceForObject) QCFuncElement("TryGetOrCreateObjectForComInstanceInternal", ComWrappersNative::TryGetOrCreateObjectForComInstance) - QCFuncElement("SetGlobalInstanceRegistered", GlobalComWrappers::SetGlobalInstanceRegistered) + QCFuncElement("SetGlobalInstanceRegisteredForMarshalling", GlobalComWrappersForMarshalling::SetGlobalInstanceRegisteredForMarshalling) + QCFuncElement("SetGlobalInstanceRegisteredForTrackerSupport", GlobalComWrappersForTrackerSupport::SetGlobalInstanceRegisteredForTrackerSupport) FCFuncEnd() #endif // FEATURE_COMWRAPPERS @@ -1040,6 +1047,7 @@ FCFuncStart(gStubHelperFuncs) #ifdef FEATURE_MULTICASTSTUB_AS_IL FCFuncElement("MulticastDebuggerTraceHelper", StubHelpers::MulticastDebuggerTraceHelper) #endif //FEATURE_MULTICASTSTUB_AS_IL + FCIntrinsic("NextCallReturnAddress", StubHelpers::NextCallReturnAddress, CORINFO_INTRINSIC_StubHelpers_NextCallReturnAddress) FCFuncEnd() FCFuncStart(gGCHandleFuncs) diff --git a/src/coreclr/src/vm/eeconfig.cpp b/src/coreclr/src/vm/eeconfig.cpp index 105305881c5f49..bb4266f86fb7f2 100644 --- a/src/coreclr/src/vm/eeconfig.cpp +++ b/src/coreclr/src/vm/eeconfig.cpp @@ -104,23 +104,9 @@ HRESULT EEConfig::Init() #endif fGCBreakOnOOM = false; - iGCgen0size = 0; - iGCSegmentSize = 0; iGCconcurrent = 0; -#ifdef _DEBUG - iGCLatencyMode = -1; -#endif //_DEBUG - iGCForceCompact = 0; iGCHoardVM = 0; - iGCLOHCompactionMode = 0; iGCLOHThreshold = 0; - iGCHeapCount = 0; - iGCNoAffinitize = 0; - iGCAffinityMask = 0; - -#ifdef GCTRIMCOMMIT - iGCTrimCommit = 0; -#endif m_fFreepZapSet = false; @@ -140,14 +126,6 @@ HRESULT EEConfig::Init() fJitMinOpts = false; fPInvokeRestoreEsp = (DWORD)-1; - fLegacyNullReferenceExceptionPolicy = false; - fLegacyUnhandledExceptionPolicy = false; - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // By default, there is not pre-V4 CSE policy - fLegacyCorruptedStateExceptionsPolicy = false; -#endif // FEATURE_CORRUPTING_EXCEPTIONS - fNgenBindOptimizeNonGac = false; fStressLog = false; fProbeForStackOverflow = true; @@ -471,7 +449,6 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_ IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GcCoverage, (LPWSTR*)&pszGcCoverageOnMethod)); pszGcCoverageOnMethod = NarrowWideChar((LPWSTR)pszGcCoverageOnMethod); - iGCLatencyMode = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_GCLatencyMode, iGCLatencyMode); #endif bool gcConcurrentWasForced = false; @@ -562,24 +539,6 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_ #endif //STRESS_HEAP -#ifdef HOST_64BIT - iGCAffinityMask = GetConfigULONGLONG_DontUse_(CLRConfig::EXTERNAL_GCHeapAffinitizeMask, iGCAffinityMask); - if (!iGCAffinityMask) iGCAffinityMask = Configuration::GetKnobULONGLONGValue(W("System.GC.HeapAffinitizeMask")); - if (!iGCSegmentSize) iGCSegmentSize = GetConfigULONGLONG_DontUse_(CLRConfig::UNSUPPORTED_GCSegmentSize, iGCSegmentSize); - if (!iGCgen0size) iGCgen0size = GetConfigULONGLONG_DontUse_(CLRConfig::UNSUPPORTED_GCgen0size, iGCgen0size); -#else - iGCAffinityMask = GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_GCHeapAffinitizeMask, iGCAffinityMask); - if (!iGCAffinityMask) iGCAffinityMask = Configuration::GetKnobDWORDValue(W("System.GC.HeapAffinitizeMask"), 0); - if (!iGCSegmentSize) iGCSegmentSize = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCSegmentSize, iGCSegmentSize); - if (!iGCgen0size) iGCgen0size = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCgen0size, iGCgen0size); -#endif //HOST_64BIT - - const ULONGLONG ullHeapHardLimit = Configuration::GetKnobULONGLONGValue(W("System.GC.HeapHardLimit")); - iGCHeapHardLimit = FitsIn(ullHeapHardLimit) - ? static_cast(ullHeapHardLimit) - : ClrSafeInt::MaxInt(); - iGCHeapHardLimitPercent = Configuration::GetKnobDWORDValue(W("System.GC.HeapHardLimitPercent"), 0); - if (g_IGCHoardVM) iGCHoardVM = g_IGCHoardVM; else @@ -591,15 +550,6 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_ iGCLOHThreshold = max (iGCLOHThreshold, LARGE_OBJECT_SIZE); } - if (!iGCLOHCompactionMode) iGCLOHCompactionMode = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCLOHCompact, iGCLOHCompactionMode); - -#ifdef GCTRIMCOMMIT - if (g_IGCTrimCommit) - iGCTrimCommit = g_IGCTrimCommit; - else - iGCTrimCommit = GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_gcTrimCommitOnLowMemory, iGCTrimCommit); -#endif - #ifdef FEATURE_CONSERVATIVE_GC iGCConservative = (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_gcConservative) != 0); #endif // FEATURE_CONSERVATIVE_GC @@ -637,12 +587,6 @@ fTrackDynamicMethodDebugInfo = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_ IfFailRet(hr); } #endif - - iGCForceCompact = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_gcForceCompact, iGCForceCompact); - iGCNoAffinitize = Configuration::GetKnobBooleanValue(W("System.GC.NoAffinitize"), - CLRConfig::EXTERNAL_GCNoAffinitize); - iGCHeapCount = Configuration::GetKnobDWORDValue(W("System.GC.HeapCount"), CLRConfig::EXTERNAL_GCHeapCount); - fStressLog = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_StressLog, fStressLog) != 0; fForceEnc = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_ForceEnc, fForceEnc) != 0; diff --git a/src/coreclr/src/vm/eeconfig.h b/src/coreclr/src/vm/eeconfig.h index 830cd8e83a26d3..7ed91a49fc9d4e 100644 --- a/src/coreclr/src/vm/eeconfig.h +++ b/src/coreclr/src/vm/eeconfig.h @@ -133,14 +133,6 @@ class EEConfig } } - bool LegacyNullReferenceExceptionPolicy(void) const {LIMITED_METHOD_CONTRACT; return fLegacyNullReferenceExceptionPolicy; } - bool LegacyUnhandledExceptionPolicy(void) const {LIMITED_METHOD_CONTRACT; return fLegacyUnhandledExceptionPolicy; } - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // Returns a bool to indicate if the legacy CSE (pre-v4) behaviour is enabled or not - bool LegacyCorruptedStateExceptionsPolicy(void) const {LIMITED_METHOD_CONTRACT; return fLegacyCorruptedStateExceptionsPolicy; } -#endif // FEATURE_CORRUPTING_EXCEPTIONS - bool InteropValidatePinnedObjects() const { LIMITED_METHOD_CONTRACT; return m_fInteropValidatePinnedObjects; } bool InteropLogArguments() const { LIMITED_METHOD_CONTRACT; return m_fInteropLogArguments; } @@ -399,33 +391,12 @@ class EEConfig GCStressFlags GetGCStressLevel() const { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return GCStressFlags(iGCStress); } #endif - bool IsGCBreakOnOOMEnabled() const {LIMITED_METHOD_CONTRACT; return fGCBreakOnOOM; } - - size_t GetGCgen0size () const {LIMITED_METHOD_CONTRACT; return iGCgen0size; } - void SetGCgen0size (size_t iSize) {LIMITED_METHOD_CONTRACT; iGCgen0size = iSize; } - size_t GetSegmentSize () const {LIMITED_METHOD_CONTRACT; return iGCSegmentSize; } - void SetSegmentSize (size_t iSize) {LIMITED_METHOD_CONTRACT; iGCSegmentSize = iSize; } + bool IsGCBreakOnOOMEnabled() const {LIMITED_METHOD_CONTRACT; return fGCBreakOnOOM; } - int GetGCconcurrent() const {LIMITED_METHOD_CONTRACT; return iGCconcurrent; } - void SetGCconcurrent(int val) {LIMITED_METHOD_CONTRACT; iGCconcurrent = val; } -#ifdef _DEBUG - int GetGCLatencyMode() const {LIMITED_METHOD_CONTRACT; return iGCLatencyMode; } -#endif //_DEBUG - int GetGCForceCompact() const {LIMITED_METHOD_CONTRACT; return iGCForceCompact; } + int GetGCconcurrent() const {LIMITED_METHOD_CONTRACT; return iGCconcurrent; } + void SetGCconcurrent(int val) {LIMITED_METHOD_CONTRACT; iGCconcurrent = val; } int GetGCRetainVM () const {LIMITED_METHOD_CONTRACT; return iGCHoardVM;} DWORD GetGCLOHThreshold() const {LIMITED_METHOD_CONTRACT; return iGCLOHThreshold;} - int GetGCLOHCompactionMode() const {LIMITED_METHOD_CONTRACT; return iGCLOHCompactionMode;} - int GetGCHeapCount() const {LIMITED_METHOD_CONTRACT; return iGCHeapCount;} - int GetGCNoAffinitize () const {LIMITED_METHOD_CONTRACT; return iGCNoAffinitize;} - size_t GetGCAffinityMask() const {LIMITED_METHOD_CONTRACT; return iGCAffinityMask;} - size_t GetGCHeapHardLimit() const {LIMITED_METHOD_CONTRACT; return iGCHeapHardLimit;} - int GetGCHeapHardLimitPercent() const {LIMITED_METHOD_CONTRACT; return iGCHeapHardLimitPercent;} - -#ifdef GCTRIMCOMMIT - - int GetGCTrimCommit() const {LIMITED_METHOD_CONTRACT; return iGCTrimCommit;} - -#endif #ifdef FEATURE_CONSERVATIVE_GC bool GetGCConservative() const {LIMITED_METHOD_CONTRACT; return iGCConservative;} @@ -583,13 +554,6 @@ class EEConfig unsigned fPInvokeRestoreEsp; // -1=Default, 0=Never, Else=Always - bool fLegacyNullReferenceExceptionPolicy; // Old AV's as NullRef behavior - bool fLegacyUnhandledExceptionPolicy; // Old unhandled exception policy (many are swallowed) - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - bool fLegacyCorruptedStateExceptionsPolicy; -#endif // FEATURE_CORRUPTING_EXCEPTIONS - LPUTF8 pszBreakOnClassLoad; // Halt just before loading this class #ifdef TEST_DATA_CONSISTENCY @@ -687,28 +651,9 @@ class EEConfig int iGCStress; #endif -#define DEFAULT_GC_PRN_LVL 3 - size_t iGCgen0size; - size_t iGCSegmentSize; int iGCconcurrent; -#ifdef _DEBUG - int iGCLatencyMode; -#endif //_DEBUG - int iGCForceCompact; int iGCHoardVM; - int iGCLOHCompactionMode; DWORD iGCLOHThreshold; - int iGCHeapCount; - int iGCNoAffinitize; - size_t iGCAffinityMask; - size_t iGCHeapHardLimit; - int iGCHeapHardLimitPercent; - -#ifdef GCTRIMCOMMIT - - int iGCTrimCommit; - -#endif #ifdef FEATURE_CONSERVATIVE_GC bool iGCConservative; diff --git a/src/coreclr/src/vm/eepolicy.cpp b/src/coreclr/src/vm/eepolicy.cpp index bec99146cd6017..b1e85e16030feb 100644 --- a/src/coreclr/src/vm/eepolicy.cpp +++ b/src/coreclr/src/vm/eepolicy.cpp @@ -28,410 +28,6 @@ #include "eventtrace.h" #undef ExitProcess -BYTE g_EEPolicyInstance[sizeof(EEPolicy)]; - -void InitEEPolicy() -{ - WRAPPER_NO_CONTRACT; - new (g_EEPolicyInstance) EEPolicy(); -} - -EEPolicy::EEPolicy () -{ - CONTRACTL - { - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; - - int n; - for (n = 0; n < MaxClrOperation; n++) { - m_Timeout[n] = INFINITE; - m_ActionOnTimeout[n] = eNoAction; - m_DefaultAction[n] = eNoAction; - } - m_Timeout[OPR_ProcessExit] = 40000; - m_ActionOnTimeout[OPR_ProcessExit] = eRudeExitProcess; - m_ActionOnTimeout[OPR_ThreadAbort] = eAbortThread; - m_ActionOnTimeout[OPR_ThreadRudeAbortInNonCriticalRegion] = eRudeAbortThread; - m_ActionOnTimeout[OPR_ThreadRudeAbortInCriticalRegion] = eRudeAbortThread; - - m_DefaultAction[OPR_ThreadAbort] = eAbortThread; - m_DefaultAction[OPR_ThreadRudeAbortInNonCriticalRegion] = eRudeAbortThread; - m_DefaultAction[OPR_ThreadRudeAbortInCriticalRegion] = eRudeAbortThread; - m_DefaultAction[OPR_AppDomainUnload] = eUnloadAppDomain; - m_DefaultAction[OPR_AppDomainRudeUnload] = eRudeUnloadAppDomain; - m_DefaultAction[OPR_ProcessExit] = eExitProcess; - m_DefaultAction[OPR_FinalizerRun] = eNoAction; - - for (n = 0; n < MaxClrFailure; n++) { - m_ActionOnFailure[n] = eNoAction; - } - m_ActionOnFailure[FAIL_CriticalResource] = eThrowException; - m_ActionOnFailure[FAIL_NonCriticalResource] = eThrowException; - m_ActionOnFailure[FAIL_OrphanedLock] = eNoAction; - m_ActionOnFailure[FAIL_FatalRuntime] = eRudeExitProcess; - // For CoreCLR, initialize the default action for AV processing to all - // all kind of code to catch AV exception. If the host wants, they can - // specify a different action for this. - m_ActionOnFailure[FAIL_AccessViolation] = eNoAction; - m_ActionOnFailure[FAIL_StackOverflow] = eRudeExitProcess; - m_ActionOnFailure[FAIL_CodeContract] = eThrowException; - m_unhandledExceptionPolicy = eRuntimeDeterminedPolicy; -} - -BOOL EEPolicy::IsValidActionForOperation(EClrOperation operation, EPolicyAction action) -{ - CONTRACTL - { - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; - - switch (operation) { - case OPR_ThreadAbort: - return action >= eAbortThread && - action < MaxPolicyAction; - case OPR_ThreadRudeAbortInNonCriticalRegion: - case OPR_ThreadRudeAbortInCriticalRegion: - return action >= eRudeAbortThread && action != eUnloadAppDomain && - action < MaxPolicyAction; - case OPR_AppDomainUnload: - return action >= eUnloadAppDomain && - action < MaxPolicyAction; - case OPR_AppDomainRudeUnload: - return action >= eRudeUnloadAppDomain && - action < MaxPolicyAction; - case OPR_ProcessExit: - return action >= eExitProcess && - action < MaxPolicyAction; - case OPR_FinalizerRun: - return action == eNoAction || - (action >= eAbortThread && - action < MaxPolicyAction); - default: - _ASSERT (!"Do not know valid action for this operation"); - break; - } - return FALSE; -} - -BOOL EEPolicy::IsValidActionForTimeout(EClrOperation operation, EPolicyAction action) -{ - CONTRACTL - { - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; - - switch (operation) { - case OPR_ThreadAbort: - return action > eAbortThread && - action < MaxPolicyAction; - case OPR_ThreadRudeAbortInNonCriticalRegion: - case OPR_ThreadRudeAbortInCriticalRegion: - return action > eRudeUnloadAppDomain && - action < MaxPolicyAction; - case OPR_AppDomainUnload: - return action > eUnloadAppDomain && - action < MaxPolicyAction; - case OPR_AppDomainRudeUnload: - return action > eRudeUnloadAppDomain && - action < MaxPolicyAction; - case OPR_ProcessExit: - return action > eExitProcess && - action < MaxPolicyAction; - case OPR_FinalizerRun: - return action == eNoAction || - (action >= eAbortThread && - action < MaxPolicyAction); - default: - _ASSERT (!"Do not know valid action for this operation"); - break; - } - return FALSE; -} - -BOOL EEPolicy::IsValidActionForFailure(EClrFailure failure, EPolicyAction action) -{ - CONTRACTL - { - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; - - switch (failure) { - case FAIL_NonCriticalResource: - return action >= eThrowException && - action < MaxPolicyAction; - case FAIL_CriticalResource: - return action >= eThrowException && - action < MaxPolicyAction; - case FAIL_FatalRuntime: - return action >= eRudeExitProcess && - action < MaxPolicyAction; - case FAIL_OrphanedLock: - return action >= eUnloadAppDomain && - action < MaxPolicyAction; - case FAIL_AccessViolation: - // Allowed actions on failure are: - // - // eNoAction or eRudeExitProcess. - return ((action == eNoAction) || (action == eRudeExitProcess)); - case FAIL_StackOverflow: - return action >= eRudeUnloadAppDomain && - action < MaxPolicyAction; - case FAIL_CodeContract: - return action >= eThrowException && - action <= eExitProcess; - default: - _ASSERTE (!"Do not know valid action for this failure"); - break; - } - - return FALSE; -} - -HRESULT EEPolicy::SetTimeout(EClrOperation operation, DWORD timeout) -{ - CONTRACTL - { - MODE_ANY; - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; - - if (static_cast(operation) < MaxClrOperation) - { - m_Timeout[operation] = timeout; - if (operation == OPR_FinalizerRun && - g_fEEStarted) - { - FastInterlockOr((DWORD*)&g_FinalizerWaiterStatus, FWS_WaitInterrupt); - FinalizerThread::SignalFinalizationDone(FALSE); - } - return S_OK; -} - else - { - return E_INVALIDARG; - } -} - -HRESULT EEPolicy::SetActionOnTimeout(EClrOperation operation, EPolicyAction action) -{ - CONTRACTL - { - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; - - if (static_cast(operation) < MaxClrOperation && - IsValidActionForTimeout(operation, action)) - { - m_ActionOnTimeout[operation] = action; - return S_OK; - } - else - { - return E_INVALIDARG; - } -} - -EPolicyAction EEPolicy::GetFinalAction(EPolicyAction action, Thread *pThread) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(static_cast(action) < MaxPolicyAction); - - if (action < eAbortThread || action > eFastExitProcess) - { - return action; - } - - while(TRUE) - { - // Look at default action. If the default action is more severe, - // use the default action instead. - EPolicyAction defaultAction = action; - switch (action) - { - case eAbortThread: - defaultAction = m_DefaultAction[OPR_ThreadAbort]; - break; - case eRudeAbortThread: - defaultAction = m_DefaultAction[OPR_ThreadRudeAbortInCriticalRegion]; - break; - case eUnloadAppDomain: - defaultAction = m_DefaultAction[OPR_AppDomainUnload]; - break; - case eRudeUnloadAppDomain: - defaultAction = m_DefaultAction[OPR_AppDomainRudeUnload]; - break; - case eExitProcess: - case eFastExitProcess: - defaultAction = m_DefaultAction[OPR_ProcessExit]; - if (defaultAction < action) - { - defaultAction = action; - } - break; - default: - break; - } - _ASSERTE(static_cast(defaultAction) < MaxPolicyAction); - - if (defaultAction == action) - { - return action; - } - - _ASSERTE(defaultAction > action); - action = defaultAction; - } -} - -// Allow setting timeout and action in one call. -// If we decide to have atomical operation on Policy, we can use lock here -// while SetTimeout and SetActionOnTimeout can not. -HRESULT EEPolicy::SetTimeoutAndAction(EClrOperation operation, DWORD timeout, EPolicyAction action) -{ - CONTRACTL - { - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; - - if (static_cast(operation) < MaxClrOperation && - IsValidActionForTimeout(operation, action)) - { - m_ActionOnTimeout[operation] = action; - m_Timeout[operation] = timeout; - if (operation == OPR_FinalizerRun && - g_fEEStarted) - { - FastInterlockOr((DWORD*)&g_FinalizerWaiterStatus, FWS_WaitInterrupt); - FinalizerThread::SignalFinalizationDone(FALSE); - } - return S_OK; - } - else - { - return E_INVALIDARG; - } -} - -HRESULT EEPolicy::SetDefaultAction(EClrOperation operation, EPolicyAction action) -{ - CONTRACTL - { - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; - - if (static_cast(operation) < MaxClrOperation && - IsValidActionForOperation(operation, action)) - { - m_DefaultAction[operation] = action; - return S_OK; - } - else - { - return E_INVALIDARG; - } -} - -HRESULT EEPolicy::SetActionOnFailure(EClrFailure failure, EPolicyAction action) -{ - CONTRACTL - { - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; - - if (static_cast(failure) < MaxClrFailure && - IsValidActionForFailure(failure, action)) - { - m_ActionOnFailure[failure] = action; - return S_OK; - } - else - { - return E_INVALIDARG; - } -} - -EPolicyAction EEPolicy::GetActionOnFailureNoHostNotification(EClrFailure failure) -{ - CONTRACTL - { - MODE_ANY; - GC_NOTRIGGER; - NOTHROW; - }CONTRACTL_END; - - _ASSERTE (failure < MaxClrFailure); - if (failure == FAIL_StackOverflow) - { - return m_ActionOnFailure[failure]; - } - - return GetFinalAction(m_ActionOnFailure[failure], GetThread()); -} - -EPolicyAction EEPolicy::GetActionOnFailure(EClrFailure failure) -{ - CONTRACTL - { - MODE_ANY; - GC_NOTRIGGER; - NOTHROW; - }CONTRACTL_END; - - _ASSERTE(static_cast(failure) < MaxClrFailure); - if (failure == FAIL_StackOverflow) - { - return m_ActionOnFailure[failure]; - } - - EPolicyAction finalAction = GetActionOnFailureNoHostNotification(failure); - return finalAction; -} - - -void EEPolicy::NotifyHostOnTimeout(EClrOperation operation, EPolicyAction action) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - -} - - -void EEPolicy::NotifyHostOnDefaultAction(EClrOperation operation, EPolicyAction action) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - -} - void SafeExitProcess(UINT exitCode, BOOL fAbort = FALSE, ShutdownCompleteAction sca = SCA_ExitProcessWhenShutdownComplete) { STRESS_LOG2(LF_SYNC, LL_INFO10, "SafeExitProcess: exitCode = %d, fAbort = %d\n", exitCode, fAbort); @@ -498,39 +94,17 @@ void SafeExitProcess(UINT exitCode, BOOL fAbort = FALSE, ShutdownCompleteAction // Watson code CONTRACT_VIOLATION(ThrowsViolation); -#ifdef TARGET_UNIX if (fAbort) { - TerminateProcess(GetCurrentProcess(), exitCode); + CrashDumpAndTerminateProcess(exitCode); + } + else + { + ExitProcess(exitCode); } -#endif - - EEPolicy::ExitProcessViaShim(exitCode); } } -// This is a helper to exit the process after coordinating with the shim. It is used by -// SafeExitProcess above, as well as from CorHost2::ExitProcess when we know that we must -// exit the process without doing further work to shutdown this runtime. This first attempts -// to call back to the Shim to shutdown any other runtimes within the process. -// -// IMPORTANT NOTE: exercise extreme caution when adding new calls to this method. It is highly -// likely that you want to call SafeExitProcess, or EEPolicy::HandleExitProcess instead of this. -// This function only exists to factor some common code out of the methods mentioned above. - -//static -void EEPolicy::ExitProcessViaShim(UINT exitCode) -{ - LIMITED_METHOD_CONTRACT; - - // We must call back to the Shim in order to exit the process, as this may be just one - // runtime in a process with many. We need to give the other runtimes a chance to exit - // cleanly. If we can't make the call, or if the call fails for some reason, then we - // simply exit the process here, which is rude to the others, but the best we can do. - - ExitProcess(exitCode); -} - //--------------------------------------------------------------------------------------- // HandleExitProcessHelper is used to shutdown the runtime as specified by the given // action, then to exit the process. Note, however, that the process will not exit if @@ -545,135 +119,16 @@ DWORD g_fFastExitProcess = 0; extern void STDMETHODCALLTYPE EEShutDown(BOOL fIsDllUnloading); -static void HandleExitProcessHelper(EPolicyAction action, UINT exitCode, ShutdownCompleteAction sca) -{ - WRAPPER_NO_CONTRACT; - - switch (action) { - case eFastExitProcess: - g_fFastExitProcess = 1; - case eExitProcess: - if (g_fEEStarted) - { - EEShutDown(FALSE); - } - if (exitCode == 0) - { - exitCode = GetLatchedExitCode(); - } - SafeExitProcess(exitCode, FALSE, sca); - break; - case eRudeExitProcess: - g_fFastExitProcess = 2; - SafeExitProcess(exitCode, TRUE, sca); - break; - default: - _ASSERTE (!"Invalid policy"); - break; - } -} - - -EPolicyAction EEPolicy::DetermineResourceConstraintAction(Thread *pThread) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - EPolicyAction action = GetEEPolicy()->GetActionOnFailure(FAIL_CriticalResource); - - AppDomain *pDomain = GetAppDomain(); - // If it is default domain, we can not unload the appdomain - if (pDomain == SystemDomain::System()->DefaultDomain() && - (action == eUnloadAppDomain || action == eRudeUnloadAppDomain)) - { - action = eThrowException; - } - return action; -} - -void EEPolicy::PerformResourceConstraintAction(Thread *pThread, EPolicyAction action, UINT exitCode, BOOL haveStack) - { - WRAPPER_NO_CONTRACT; - - _ASSERTE(GetAppDomain() != NULL); - - switch (action) { - case eThrowException: - // Caller is going to rethrow. - return; - break; - case eAbortThread: - pThread->UserAbort(Thread::TAR_Thread, TA_Safe, GetEEPolicy()->GetTimeout(OPR_ThreadAbort), Thread::UAC_Normal); - break; - case eRudeAbortThread: - pThread->UserAbort(Thread::TAR_Thread, TA_Rude, GetEEPolicy()->GetTimeout(OPR_ThreadAbort), Thread::UAC_Normal); - break; - case eExitProcess: - case eFastExitProcess: - case eRudeExitProcess: - HandleExitProcessFromEscalation(action, exitCode); - break; - default: - _ASSERTE (!"Invalid policy"); - break; - } -} - -void EEPolicy::HandleOutOfMemory() -{ - WRAPPER_NO_CONTRACT; - - _ASSERTE (g_pOutOfMemoryExceptionClass); - - Thread *pThread = GetThread(); - _ASSERTE (pThread); - - EPolicyAction action = DetermineResourceConstraintAction(pThread); - - // Check if we are executing in the context of a Constrained Execution Region. - if (action != eThrowException && Thread::IsExecutingWithinCer()) - { - // Hitting OOM in a CER region should throw the OOM without regard to the escalation policy - // since the CER author has declared they are hardened against such failures. That's - // the whole point of CERs, to denote regions where code knows exactly how to deal with - // failures in an attempt to minimize the need for rollback or recycling. - return; - } - - PerformResourceConstraintAction(pThread, action, HOST_E_EXITPROCESS_OUTOFMEMORY, TRUE); -} - //--------------------------------------------------------------------------------------- // // EEPolicy::HandleStackOverflow - Handle stack overflow according to policy // -// Arguments: -// detector: -// pLimitFrame: the limit of search for frames in order to decide if in SO tolerant -// // Return Value: // None. // // How is stack overflow handled? -// If stack overflows in non-hosted case, we terminate the process. -// For hosted case with escalation policy -// 1. If stack overflows in managed code, or in VM before switching to SO intolerant region, and the GC mode is Cooperative -// the domain is rudely unloaded, or the process is terminated if the current domain is default domain. -// a. This action is done through BEGIN_SO_TOLERANT_CODE if there is one. -// b. If there is not this macro on the stack, we mark the domain being unload requested, and when the thread -// dies or is recycled, we finish the AD unload. -// 2. If stack overflows in SO tolerant region, but the GC mode is Preemptive, the process is killed in vector handler, or our -// managed exception handler (COMPlusFrameHandler or ProcessCLRException). -// 3. If stack overflows in SO intolerant region, the process is killed as soon as the exception is seen by our vector handler, or -// our managed exception handler. -// -// The process is terminated if there is StackOverflow as all clr code is considered SO Intolerant. -void EEPolicy::HandleStackOverflow(StackOverflowDetector detector, void * pLimitFrame) +// If stack overflows, we terminate the process. +void EEPolicy::HandleStackOverflow() { WRAPPER_NO_CONTRACT; @@ -722,9 +177,11 @@ void EEPolicy::HandleExitProcess(ShutdownCompleteAction sca) STRESS_LOG0(LF_EH, LL_INFO100, "In EEPolicy::HandleExitProcess\n"); - EPolicyAction action = GetEEPolicy()->GetDefaultAction(OPR_ProcessExit, NULL); - GetEEPolicy()->NotifyHostOnDefaultAction(OPR_ProcessExit,action); - HandleExitProcessHelper(action, 0, sca); + if (g_fEEStarted) + { + EEShutDown(FALSE); + } + SafeExitProcess(GetLatchedExitCode(), FALSE, sca); } @@ -1235,7 +692,7 @@ void DECLSPEC_NORETURN EEPolicy::HandleFatalStackOverflow(EXCEPTION_POINTERS *pE (fTreatAsNativeUnhandledException == FALSE)? TypeOfReportedError::UnhandledException: TypeOfReportedError::NativeThreadUnhandledException); } - TerminateProcess(GetCurrentProcess(), COR_E_STACKOVERFLOW); + CrashDumpAndTerminateProcess(COR_E_STACKOVERFLOW); UNREACHABLE(); } @@ -1318,70 +775,10 @@ int NOINLINE EEPolicy::HandleFatalError(UINT exitCode, UINT_PTR address, LPCWSTR g_fFastExitProcess = 2; STRESS_LOG0(LF_CORDB,LL_INFO100, "D::HFE: About to call LogFatalError\n"); - switch (GetEEPolicy()->GetActionOnFailure(FAIL_FatalRuntime)) - { - case eRudeExitProcess: - LogFatalError(exitCode, address, pszMessage, pExceptionInfo, errorSource, argExceptionString); - SafeExitProcess(exitCode, TRUE); - break; - default: - _ASSERTE(!"Invalid action for FAIL_FatalRuntime"); - break; - } + LogFatalError(exitCode, address, pszMessage, pExceptionInfo, errorSource, argExceptionString); + SafeExitProcess(exitCode, TRUE); } UNREACHABLE(); return -1; } - -void EEPolicy::HandleExitProcessFromEscalation(EPolicyAction action, UINT exitCode) -{ - WRAPPER_NO_CONTRACT; - CONTRACT_VIOLATION(GCViolation); - - _ASSERTE (action >= eExitProcess); - // If policy for ExitProcess is not default action, i.e. ExitProcess, we will use it. - // Otherwise overwrite it with passing arg action; - EPolicyAction todo = GetEEPolicy()->GetDefaultAction(OPR_ProcessExit, NULL); - if (todo == eExitProcess) - { - todo = action; - } - GetEEPolicy()->NotifyHostOnDefaultAction(OPR_ProcessExit,todo); - - HandleExitProcessHelper(todo, exitCode, SCA_ExitProcessWhenShutdownComplete); -} - -void EEPolicy::HandleCodeContractFailure(LPCWSTR pMessage, LPCWSTR pCondition, LPCWSTR pInnerExceptionAsString) -{ - WRAPPER_NO_CONTRACT; - - EEPolicy* pPolicy = GetEEPolicy(); - // GetActionOnFailure will notify the host for us. - EPolicyAction action = pPolicy->GetActionOnFailure(FAIL_CodeContract); - Thread* pThread = GetThread(); - - switch(action) { - case eThrowException: - // Let managed code throw a ContractException (it's easier to pass the right parameters to the constructor). - break; - case eAbortThread: - pThread->UserAbort(Thread::TAR_Thread, TA_Safe, GetEEPolicy()->GetTimeout(OPR_ThreadAbort), Thread::UAC_Normal); - break; - case eRudeAbortThread: - pThread->UserAbort(Thread::TAR_Thread, TA_Rude, GetEEPolicy()->GetTimeout(OPR_ThreadAbort), Thread::UAC_Normal); - break; - case eExitProcess: // Merged w/ default case - default: - _ASSERTE(action == eExitProcess); - // Since we have no exception object, make sure - // UE tracker is clean so that RetrieveManagedBucketParameters - // does not take any bucket details. -#ifndef TARGET_UNIX - pThread->GetExceptionState()->GetUEWatsonBucketTracker()->ClearWatsonBucketDetails(); -#endif // !TARGET_UNIX - pPolicy->HandleFatalError(COR_E_CODECONTRACTFAILED, NULL, pMessage); - break; - } -} - diff --git a/src/coreclr/src/vm/eepolicy.h b/src/coreclr/src/vm/eepolicy.h index 67381512e084c7..fa133791770ae7 100644 --- a/src/coreclr/src/vm/eepolicy.h +++ b/src/coreclr/src/vm/eepolicy.h @@ -18,14 +18,6 @@ extern "C" UINT_PTR STDCALL GetCurrentIP(); -enum StackOverflowDetector -{ - SOD_ManagedFrameHandler, - SOD_UnmanagedFrameHandler, - SOD_SOTolerantTransitor, - SOD_SOIntolerantTransitor, -}; - // EEPolicy maintains actions for resource failure and timeout class EEPolicy { @@ -39,84 +31,7 @@ class EEPolicy TA_Rude }; - enum AppDomainUnloadTypes - { - ADU_Safe, - ADU_Rude - }; - - EEPolicy (); - - HRESULT SetTimeout(EClrOperation operation, DWORD timeout); - - DWORD GetTimeout(EClrOperation operation) - { - LIMITED_METHOD_CONTRACT; - _ASSERTE(static_cast(operation) < MaxClrOperation); - return m_Timeout[operation]; - } - - HRESULT SetActionOnTimeout(EClrOperation operation, EPolicyAction action); - EPolicyAction GetActionOnTimeout(EClrOperation operation, Thread *pThread) - { - WRAPPER_NO_CONTRACT; - _ASSERTE(static_cast(operation) < MaxClrOperation); - return GetFinalAction(m_ActionOnTimeout[operation], pThread); - } - - void NotifyHostOnTimeout(EClrOperation operation, EPolicyAction action); - - HRESULT SetTimeoutAndAction(EClrOperation operation, DWORD timeout, EPolicyAction action); - - HRESULT SetDefaultAction(EClrOperation operation, EPolicyAction action); - EPolicyAction GetDefaultAction(EClrOperation operation, Thread *pThread) - { - WRAPPER_NO_CONTRACT; - _ASSERTE(static_cast(operation) < MaxClrOperation); - return GetFinalAction(m_DefaultAction[operation], pThread); - } - - void NotifyHostOnDefaultAction(EClrOperation operation, EPolicyAction action); - - HRESULT SetActionOnFailure(EClrFailure failure, EPolicyAction action); - - // Generally GetActionOnFailure should be used so that a host can get notification. - // But if we have notified host on the same failure, but we need to check escalation again, - // GetActionOnFailureNoHostNotification can be used. - EPolicyAction GetActionOnFailure(EClrFailure failure); - EPolicyAction GetActionOnFailureNoHostNotification(EClrFailure failure); - - // get and set unhandled exception policy - HRESULT SetUnhandledExceptionPolicy(EClrUnhandledException policy) - { - LIMITED_METHOD_CONTRACT; - if (policy != eRuntimeDeterminedPolicy && policy != eHostDeterminedPolicy) - { - return E_INVALIDARG; - } - else - { - m_unhandledExceptionPolicy = policy; - return S_OK; - } - } - EClrUnhandledException GetUnhandledExceptionPolicy() - { - LIMITED_METHOD_CONTRACT; - return m_unhandledExceptionPolicy; - } - - static EPolicyAction DetermineResourceConstraintAction(Thread *pThread); - - static void PerformResourceConstraintAction(Thread *pThread, EPolicyAction action, UINT exitCode, BOOL haveStack); - - static void HandleOutOfMemory(); - - static void HandleStackOverflow(StackOverflowDetector detector, void * pLimitFrame); - - static void HandleSoftStackOverflow(BOOL fSkipDebugger = FALSE); - - static void HandleStackOverflowAfterCatch(); + static void HandleStackOverflow(); static void HandleExitProcess(ShutdownCompleteAction sca = SCA_ExitProcessWhenShutdownComplete); @@ -124,45 +39,10 @@ class EEPolicy static void DECLSPEC_NORETURN HandleFatalStackOverflow(EXCEPTION_POINTERS *pException, BOOL fSkipDebugger = FALSE); - static void HandleExitProcessFromEscalation(EPolicyAction action, UINT exitCode); - - static void HandleCodeContractFailure(LPCWSTR pMessage, LPCWSTR pCondition, LPCWSTR pInnerExceptionAsString); - private: - DWORD m_Timeout[MaxClrOperation]; - EPolicyAction m_ActionOnTimeout[MaxClrOperation]; - EPolicyAction m_DefaultAction[MaxClrOperation]; - EPolicyAction m_ActionOnFailure[MaxClrFailure]; - EClrUnhandledException m_unhandledExceptionPolicy; - - // TODO: Support multiple methods to set policy: hosting, config, managed api. - - // Return BOOL if action is acceptable for operation. - BOOL IsValidActionForOperation(EClrOperation operation, EPolicyAction action); - BOOL IsValidActionForTimeout(EClrOperation operation, EPolicyAction action); - BOOL IsValidActionForFailure(EClrFailure failure, EPolicyAction action); - EPolicyAction GetFinalAction(EPolicyAction action, Thread *pThread); - static void LogFatalError(UINT exitCode, UINT_PTR address, LPCWSTR pMessage, PEXCEPTION_POINTERS pExceptionInfo, LPCWSTR errorSource, LPCWSTR argExceptionString=NULL); - - // IMPORTANT NOTE: only the following two functions should be calling ExitProcessViaShim. - // - CorHost2::ExitProcess - // - SafeExitProcess - friend class CorHost2; - friend void SafeExitProcess(UINT , BOOL , ShutdownCompleteAction); - - static void ExitProcessViaShim(UINT exitCode); }; -void InitEEPolicy(); - -extern BYTE g_EEPolicyInstance[]; - -inline EEPolicy* GetEEPolicy() -{ - return (EEPolicy*)&g_EEPolicyInstance; -} - // // Use EEPOLICY_HANDLE_FATAL_ERROR when you have a situtation where the Runtime's internal state would be // inconsistent if execution were allowed to continue. This will apply the proper host's policy for fatal diff --git a/src/coreclr/src/vm/eetwain.cpp b/src/coreclr/src/vm/eetwain.cpp index 972b7ae7cbe3a8..ffdf79b6afd20d 100644 --- a/src/coreclr/src/vm/eetwain.cpp +++ b/src/coreclr/src/vm/eetwain.cpp @@ -5757,7 +5757,7 @@ bool EECodeManager::GetReturnAddressHijackInfo(GCInfoToken gcInfoToken, ReturnKi if (gcInfoDecoder.GetReversePInvokeFrameStackSlot() != NO_REVERSE_PINVOKE_FRAME) { - // Hijacking of NativeCallable method is not allowed + // Hijacking of UnmanagedCallersOnly method is not allowed return false; } diff --git a/src/coreclr/src/vm/eventpipe.cpp b/src/coreclr/src/vm/eventpipe.cpp index a7b64acc216fb6..3ec4c54d5b5c4e 100644 --- a/src/coreclr/src/vm/eventpipe.cpp +++ b/src/coreclr/src/vm/eventpipe.cpp @@ -434,6 +434,15 @@ void EventPipe::Disable(EventPipeSessionID id) if (s_numberOfSessions > 0) DisableInternal(id, pEventPipeProviderCallbackDataQueue); }); + +#ifdef DEBUG + if ((int)s_numberOfSessions == 0) + { + _ASSERTE(!MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context.EventPipeProvider.IsEnabled); + _ASSERTE(!MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_DOTNET_Context.EventPipeProvider.IsEnabled); + _ASSERTE(!MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context.EventPipeProvider.IsEnabled); + } +#endif } static void LogProcessInformationEvent(EventPipeEventSource &eventSource) diff --git a/src/coreclr/src/vm/eventpipeblock.cpp b/src/coreclr/src/vm/eventpipeblock.cpp index d72715956df7e5..dd8807d3364c29 100644 --- a/src/coreclr/src/vm/eventpipeblock.cpp +++ b/src/coreclr/src/vm/eventpipeblock.cpp @@ -462,6 +462,4 @@ bool EventPipeStackBlock::WriteStack(DWORD stackId, StackContents* pStack) return true; } - - #endif // FEATURE_PERFTRACING diff --git a/src/coreclr/src/vm/eventpipebuffer.cpp b/src/coreclr/src/vm/eventpipebuffer.cpp index eeed5246cd0e81..b1564bb14af38c 100644 --- a/src/coreclr/src/vm/eventpipebuffer.cpp +++ b/src/coreclr/src/vm/eventpipebuffer.cpp @@ -23,8 +23,21 @@ EventPipeBuffer::EventPipeBuffer(unsigned int bufferSize, EventPipeThread* pWrit m_state = EventPipeBufferState::WRITABLE; m_pWriterThread = pWriterThread; m_eventSequenceNumber = eventSequenceNumber; - m_pBuffer = new BYTE[bufferSize]; + // Use ClrVirtualAlloc instead of malloc to allocate buffer to avoid potential internal fragmentation in the native CRT heap. + // (See https://github.com/dotnet/runtime/pull/35924 and https://github.com/microsoft/ApplicationInsights-dotnet/issues/1678 for more details) + // + // This fix does cause a little bit of performance regression (1-2%) in throughput, + // but within acceptable boundaries, while minimizing the risk of the fix to be backported + // to servicing releases. We may come back in the future to reassess this and potentially improve + // the throughput via more performant solution afterwards. + m_pBuffer = (BYTE*)ClrVirtualAlloc(NULL, bufferSize, MEM_COMMIT, PAGE_READWRITE); + + // memset may be unnecessary here because VirtualAlloc with MEM_COMMIT zero-initializes the pages and mmap also zero-initializes + // if MAP_UNINITIALIZED isn't passed (which ClrVirtualAlloc doesn't). If this memset ends up being a perf cost in future investigations + // we may remove this. But for risk mitigation we're leaving it as-is. + // (See https://github.com/dotnet/runtime/pull/35924#discussion_r421282564 for discussion on this) memset(m_pBuffer, 0, bufferSize); + m_pLimit = m_pBuffer + bufferSize; m_pCurrent = GetNextAlignedAddress(m_pBuffer); @@ -47,7 +60,7 @@ EventPipeBuffer::~EventPipeBuffer() } CONTRACTL_END; - delete[] m_pBuffer; + ClrVirtualFree(m_pBuffer, 0, MEM_RELEASE); } bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeSession &session, EventPipeEvent &event, EventPipeEventPayload &payload, LPCGUID pActivityId, LPCGUID pRelatedActivityId, StackContents *pStack) diff --git a/src/coreclr/src/vm/eventpipebuffermanager.cpp b/src/coreclr/src/vm/eventpipebuffermanager.cpp index 4990c1582dd219..f0f5f453943947 100644 --- a/src/coreclr/src/vm/eventpipebuffermanager.cpp +++ b/src/coreclr/src/vm/eventpipebuffermanager.cpp @@ -168,6 +168,9 @@ EventPipeBuffer* EventPipeBufferManager::AllocateBufferForThread(EventPipeThread const unsigned int maxBufferSize = 1024 * 1024; bufferSize = Min(bufferSize, maxBufferSize); + // Make the buffer size fit into with pagesize-aligned block, since ClrVirtualAlloc expects page-aligned sizes to be passed as arguments (see ctor of EventPipeBuffer) + bufferSize = (bufferSize + g_SystemInfo.dwAllocationGranularity - 1) & ~static_cast(g_SystemInfo.dwAllocationGranularity - 1); + // EX_TRY is used here as opposed to new (nothrow) because // the constructor also allocates a private buffer, which // could throw, and cannot be easily checked diff --git a/src/coreclr/src/vm/eventpipeevent.cpp b/src/coreclr/src/vm/eventpipeevent.cpp index e352afb456c3eb..a56ed9429847c9 100644 --- a/src/coreclr/src/vm/eventpipeevent.cpp +++ b/src/coreclr/src/vm/eventpipeevent.cpp @@ -23,7 +23,8 @@ EventPipeEvent::EventPipeEvent( m_level(level), m_needStack(needStack), m_enabledMask(0), - m_pMetadata(nullptr) + m_pMetadata(nullptr), + m_metadataLength(0) { CONTRACTL { diff --git a/src/coreclr/src/vm/eventpipeevent.h b/src/coreclr/src/vm/eventpipeevent.h index f2dfe4ec232ef5..06da70f90f6c3f 100644 --- a/src/coreclr/src/vm/eventpipeevent.h +++ b/src/coreclr/src/vm/eventpipeevent.h @@ -49,7 +49,8 @@ class EventPipeEvent // Only EventPipeProvider can create events. // The provider is responsible for allocating and freeing events. - EventPipeEvent(EventPipeProvider &provider, INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack, BYTE *pMetadata = NULL, unsigned int metadataLength = 0); + EventPipeEvent(EventPipeProvider &provider, INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack, + BYTE *pMetadata = NULL, unsigned int metadataLength = 0); public: ~EventPipeEvent(); diff --git a/src/coreclr/src/vm/eventpipefile.cpp b/src/coreclr/src/vm/eventpipefile.cpp index 6baeaeefa9cf56..5a69f502e724ba 100644 --- a/src/coreclr/src/vm/eventpipefile.cpp +++ b/src/coreclr/src/vm/eventpipefile.cpp @@ -201,10 +201,11 @@ void EventPipeFile::WriteEvent(EventPipeEventInstance &instance, ULONGLONG captu THROWS; GC_NOTRIGGER; MODE_ANY; - PRECONDITION(m_pSerializer != nullptr); } CONTRACTL_END; + if (HasErrors()) return; + #ifdef DEBUG _ASSERTE(instance.GetTimeStamp()->QuadPart >= m_lastSortedTimestamp.QuadPart); if (isSortedEvent) @@ -221,14 +222,15 @@ void EventPipeFile::WriteEvent(EventPipeEventInstance &instance, ULONGLONG captu // Check to see if we've seen this event type before. // If not, then write the event metadata to the event stream first. - unsigned int metadataId = GetMetadataId(*instance.GetEvent()); + EventPipeEvent* pEvent = instance.GetEvent(); + unsigned int metadataId = GetMetadataId(*pEvent); if(metadataId == 0) { metadataId = GenerateMetadataId(); EventPipeEventInstance* pMetadataInstance = EventPipe::BuildEventMetadataEvent(instance, metadataId); - WriteEventToBlock(*pMetadataInstance, 0); // metadataId=0 breaks recursion and represents the metadata event. + WriteEventToBlock(*pMetadataInstance, 0); // metadataId=0 breaks recursion and represents the metadata event. SaveMetadataId(*instance.GetEvent(), metadataId); @@ -247,7 +249,6 @@ void EventPipeFile::WriteSequencePoint(EventPipeSequencePoint* pSequencePoint) GC_NOTRIGGER; MODE_ANY; PRECONDITION(pSequencePoint != nullptr); - PRECONDITION(m_pSerializer != nullptr); } CONTRACTL_END; @@ -259,6 +260,9 @@ void EventPipeFile::WriteSequencePoint(EventPipeSequencePoint* pSequencePoint) Flush(FlushAllBlocks); EventPipeSequencePointBlock sequencePointBlock(pSequencePoint); + + if (HasErrors()) return; + m_pSerializer->WriteObject(&sequencePointBlock); // stack cache resets on sequence points @@ -278,13 +282,14 @@ void EventPipeFile::Flush(FlushFlags flags) NOTHROW; GC_NOTRIGGER; MODE_ANY; - PRECONDITION(m_pSerializer != nullptr); PRECONDITION(m_pMetadataBlock != nullptr); PRECONDITION(m_pStackBlock != nullptr); PRECONDITION(m_pBlock != nullptr); } CONTRACTL_END; + if (HasErrors()) return; + // we write current blocks to the disk, whether they are full or not if ((m_pMetadataBlock->GetBytesWritten() != 0) && ((flags & FlushMetadataBlock) != 0)) { diff --git a/src/coreclr/src/vm/eventpipeprovider.cpp b/src/coreclr/src/vm/eventpipeprovider.cpp index f2d7760b5b32e2..0351ff88438d82 100644 --- a/src/coreclr/src/vm/eventpipeprovider.cpp +++ b/src/coreclr/src/vm/eventpipeprovider.cpp @@ -152,7 +152,8 @@ EventPipeProviderCallbackData EventPipeProvider::UnsetConfiguration( return PrepareCallbackData(m_keywords, m_providerLevel, pFilterData); } -EventPipeEvent *EventPipeProvider::AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, bool needStack, BYTE *pMetadata, unsigned int metadataLength) +EventPipeEvent *EventPipeProvider::AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, bool needStack, + BYTE *pMetadata, unsigned int metadataLength) { CONTRACTL { @@ -172,7 +173,6 @@ EventPipeEvent *EventPipeProvider::AddEvent(unsigned int eventID, INT64 keywords needStack, pMetadata, metadataLength); - // Add it to the list of events. AddEvent(*pEvent); return pEvent; @@ -255,11 +255,14 @@ void EventPipeProvider::AddEvent(EventPipeEvent &event) isEventFilterDescriptorInitialized = true; } + // NOTE: When we call the callback, we pass in enabled (which is either 1 or 0) as the ControlCode. + // If we want to add new ControlCode, we have to make corresponding change in eventtrace.cpp:EtwCallbackCommon + // to address this. See https://github.com/dotnet/runtime/pull/36733 for more discussions on this. if (pCallbackFunction != NULL && !g_fEEShutDown) { (*pCallbackFunction)( NULL, /* providerId */ - enabled, + enabled, /* ControlCode */ (UCHAR)providerLevel, keywords, 0 /* matchAllKeywords */, diff --git a/src/coreclr/src/vm/eventpipeprovider.h b/src/coreclr/src/vm/eventpipeprovider.h index d842f18044bb36..2fe93e969686a8 100644 --- a/src/coreclr/src/vm/eventpipeprovider.h +++ b/src/coreclr/src/vm/eventpipeprovider.h @@ -76,7 +76,8 @@ class EventPipeProvider INT64 ComputeEventEnabledMask(INT64 keywords, EventPipeEventLevel eventLevel) const; // Create a new event. - EventPipeEvent* AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, bool needStack, BYTE *pMetadata = NULL, unsigned int metadataLength = 0); + EventPipeEvent* AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, bool needStack, + BYTE *pMetadata = NULL, unsigned int metadataLength = 0); private: diff --git a/src/coreclr/src/vm/eventreporter.cpp b/src/coreclr/src/vm/eventreporter.cpp index 3fd9cd04d82625..2ff712b1cc9681 100644 --- a/src/coreclr/src/vm/eventreporter.cpp +++ b/src/coreclr/src/vm/eventreporter.cpp @@ -17,13 +17,12 @@ #include "eventreporter.h" #include "typestring.h" #include "debugdebugger.h" +#include "clrversion.h" #include #include "../dlls/mscorrc/resource.h" -#include "getproductversionnumber.h" - //--------------------------------------------------------------------------------------- // // A constructor for EventReporter. The header of the log is generated here. @@ -90,35 +89,12 @@ EventReporter::EventReporter(EventReporterType type) m_Description.Append(ssMessage); } - BOOL fHasVersion = FALSE; - DWORD dwMajorVersion = 0; - DWORD dwMinorVersion = 0; - DWORD dwBuild = 0; - DWORD dwRevision = 0; - EventReporter::GetCoreCLRInstanceProductVersion(&dwMajorVersion, &dwMinorVersion, &dwBuild, &dwRevision); - m_Description.AppendPrintf(W("%lu.%lu.%lu.%lu\n"),dwMajorVersion, dwMinorVersion, dwBuild, dwRevision); - fHasVersion = TRUE; - - if (!fHasVersion) - { - ssMessage.Clear(); - if(!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_UNKNOWN)) - m_Description.Append(W("unknown\n")); - else - { - m_Description.Append(ssMessage); - m_Description.Append(W("\n")); - } - } + m_Description.Append(VER_FILEVERSION_STR_L); + m_Description.Append(W("\n")); - // Log the .NET Version if we can get it - LPCWSTR fxProductVersion = Configuration::GetKnobStringValue(W("FX_PRODUCT_VERSION")); - if (fxProductVersion != nullptr) - { - m_Description.Append(W(".NET Version: ")); - m_Description.Append(fxProductVersion); - m_Description.Append(W("\n")); - } + m_Description.Append(W(".NET Version: ")); + m_Description.Append(CLR_PRODUCT_VERSION_L); + m_Description.Append(W("\n")); ssMessage.Clear(); @@ -723,41 +699,3 @@ void DoReportForUnhandledNativeException(PEXCEPTION_POINTERS pExceptionInfo) reporter.Report(); } } - -// This function will return the product version of CoreCLR -// instance we are executing in. -void EventReporter::GetCoreCLRInstanceProductVersion(DWORD * pdwMajor, DWORD * pdwMinor, DWORD * pdwBuild, DWORD * pdwRevision) -{ - STATIC_CONTRACT_THROWS; - - // Get the instance of the runtime - HMODULE hModRuntime = GetCLRModule(); - _ASSERTE(hModRuntime != NULL); - - // Get the path to the runtime - PathString runtimePath; - DWORD ret = WszGetModuleFileName(hModRuntime, runtimePath); - if (ret != 0) - { - // Got the path - get the file version from the path - SString path; - path.Clear(); - path.Append(runtimePath); - DWORD dwVersionMS = 0; - DWORD dwVersionLS = 0; - GetProductVersionNumber(path, &dwVersionMS, &dwVersionLS); - - // Get the Major.Minor.Build.Revision details from the returned values - *pdwMajor = HIWORD(dwVersionMS); - *pdwMinor = LOWORD(dwVersionMS); - *pdwBuild = HIWORD(dwVersionLS); - *pdwRevision = LOWORD(dwVersionLS); - LOG((LF_CORDB, LL_INFO100, "GetCoreCLRInstanceVersion: Got CoreCLR version: %lu.%lu.%lu.%lu\n", - *pdwMajor, *pdwMinor, *pdwBuild, *pdwRevision)); - } - else - { - // Failed to get the path - LOG((LF_CORDB, LL_INFO100, "GetCoreCLRInstanceVersion: Unable to get CoreCLR version.\n")); - } -} diff --git a/src/coreclr/src/vm/eventreporter.h b/src/coreclr/src/vm/eventreporter.h index 4c4025f2522dac..3bfede0e1e35d9 100644 --- a/src/coreclr/src/vm/eventreporter.h +++ b/src/coreclr/src/vm/eventreporter.h @@ -49,8 +49,6 @@ class EventReporter // Flag to indicate if the buffer is full BOOL fBufferFull; - static void GetCoreCLRInstanceProductVersion(DWORD * pdwMajor, DWORD * pdwMinor, DWORD * pdwBuild, DWORD * pdwRevision); - public: // Construct EventReporter(EventReporterType type); diff --git a/src/coreclr/src/vm/eventtrace.cpp b/src/coreclr/src/vm/eventtrace.cpp index 12f0e1908143f2..026eec448fdaf8 100644 --- a/src/coreclr/src/vm/eventtrace.cpp +++ b/src/coreclr/src/vm/eventtrace.cpp @@ -31,6 +31,7 @@ #include "ex.h" #include "dbginterface.h" #include "finalizerthread.h" +#include "clrversion.h" #define Win32EventWrite EventWrite @@ -973,7 +974,7 @@ HRESULT ETW::GCLog::ForceGCForDiagnostics() #ifndef FEATURE_REDHAWK } EX_CATCH { } - EX_END_CATCH(RethrowCorruptingExceptions); + EX_END_CATCH(RethrowTerminalExceptions); #endif // FEATURE_REDHAWK return hr; @@ -1751,7 +1752,7 @@ int BulkTypeEventLogger::LogSingleType(TypeHandle th) { fSucceeded = FALSE; } - EX_END_CATCH(RethrowCorruptingExceptions); + EX_END_CATCH(RethrowTerminalExceptions); if (!fSucceeded) return -1; @@ -1790,7 +1791,7 @@ int BulkTypeEventLogger::LogSingleType(TypeHandle th) { fSucceeded = FALSE; } - EX_END_CATCH(RethrowCorruptingExceptions); + EX_END_CATCH(RethrowTerminalExceptions); if (!fSucceeded) return -1; } @@ -1810,7 +1811,7 @@ int BulkTypeEventLogger::LogSingleType(TypeHandle th) { fSucceeded = FALSE; } - EX_END_CATCH(RethrowCorruptingExceptions); + EX_END_CATCH(RethrowTerminalExceptions); if (!fSucceeded) return -1; } @@ -1849,7 +1850,7 @@ int BulkTypeEventLogger::LogSingleType(TypeHandle th) { fSucceeded = FALSE; } - EX_END_CATCH(RethrowCorruptingExceptions); + EX_END_CATCH(RethrowTerminalExceptions); if (!fSucceeded) return -1; } @@ -1887,7 +1888,7 @@ int BulkTypeEventLogger::LogSingleType(TypeHandle th) // won't have a name in it. pVal->sName.Clear(); } - EX_END_CATCH(RethrowCorruptingExceptions); + EX_END_CATCH(RethrowTerminalExceptions); // Now that we know the full size of this type's data, see if it fits in our // batch or whether we need to flush @@ -1985,7 +1986,7 @@ void BulkTypeEventLogger::LogTypeAndParameters(ULONGLONG thAsAddr, ETW::TypeSyst { fSucceeded = FALSE; } - EX_END_CATCH(RethrowCorruptingExceptions); + EX_END_CATCH(RethrowTerminalExceptions); if (!fSucceeded) return; @@ -2550,7 +2551,7 @@ VOID ETW::GCLog::SendFinalizeObjectEvent(MethodTable * pMT, Object * pObj) EX_CATCH { } - EX_END_CATCH(RethrowCorruptingExceptions); + EX_END_CATCH(RethrowTerminalExceptions); } } @@ -2976,7 +2977,7 @@ BOOL ETW::TypeSystemLog::AddOrReplaceTypeLoggingInfo(ETW::LoggedTypesFromModule { fSucceeded = FALSE; } - EX_END_CATCH(RethrowCorruptingExceptions); + EX_END_CATCH(RethrowTerminalExceptions); return fSucceeded; } @@ -3383,7 +3384,7 @@ ETW::TypeLoggingInfo ETW::TypeSystemLog::LookupOrCreateTypeLoggingInfo(TypeHandl { fSucceeded = FALSE; } - EX_END_CATCH(RethrowCorruptingExceptions); + EX_END_CATCH(RethrowTerminalExceptions); if (!fSucceeded) { *pfCreatedNew = FALSE; @@ -3421,7 +3422,7 @@ ETW::TypeLoggingInfo ETW::TypeSystemLog::LookupOrCreateTypeLoggingInfo(TypeHandl { fSucceeded = FALSE; } - EX_END_CATCH(RethrowCorruptingExceptions); + EX_END_CATCH(RethrowTerminalExceptions); if (!fSucceeded) { *pfCreatedNew = FALSE; @@ -3517,7 +3518,7 @@ BOOL ETW::TypeSystemLog::AddTypeToGlobalCacheIfNotExists(TypeHandle th, BOOL * p { fSucceeded = FALSE; } - EX_END_CATCH(RethrowCorruptingExceptions); + EX_END_CATCH(RethrowTerminalExceptions); if (!fSucceeded) { *pfCreatedNew = FALSE; @@ -3549,7 +3550,7 @@ BOOL ETW::TypeSystemLog::AddTypeToGlobalCacheIfNotExists(TypeHandle th, BOOL * p { fSucceeded = FALSE; } - EX_END_CATCH(RethrowCorruptingExceptions); + EX_END_CATCH(RethrowTerminalExceptions); if (!fSucceeded) { *pfCreatedNew = FALSE; @@ -4238,9 +4239,6 @@ VOID EtwCallbackCommon( static_assert(GCEventLevel_Information == TRACE_LEVEL_INFORMATION, "GCEventLevel_Information mismatch"); static_assert(GCEventLevel_Verbose == TRACE_LEVEL_VERBOSE, "GCEventLevel_Verbose mismatch"); #endif // !defined(HOST_UNIX) - GCEventKeyword keywords = static_cast(MatchAnyKeyword); - GCEventLevel level = static_cast(Level); - GCHeapUtilities::RecordEventStateChange(bIsPublicTraceHandle, keywords, level); DOTNET_TRACE_CONTEXT * ctxToUpdate; switch(ProviderIndex) @@ -4269,6 +4267,30 @@ VOID EtwCallbackCommon( { ctxToUpdate->EventPipeProvider.Level = Level; ctxToUpdate->EventPipeProvider.EnabledKeywordsBitmask = MatchAnyKeyword; + ctxToUpdate->EventPipeProvider.IsEnabled = ControlCode; + + // For EventPipe, ControlCode can only be either 0 or 1. + _ASSERTE(ControlCode == 0 || ControlCode == 1); + } + + if ( +#if !defined(HOST_UNIX) + (ControlCode == EVENT_CONTROL_CODE_ENABLE_PROVIDER || ControlCode == EVENT_CONTROL_CODE_DISABLE_PROVIDER) && +#endif + (ProviderIndex == DotNETRuntime || ProviderIndex == DotNETRuntimePrivate)) + { +#if !defined(HOST_UNIX) + // On Windows, consolidate level and keywords across event pipe and ETW contexts - + // ETW may still want to see events that event pipe doesn't care about and vice versa + GCEventKeyword keywords = static_cast(ctxToUpdate->EventPipeProvider.EnabledKeywordsBitmask | + ctxToUpdate->EtwProvider->MatchAnyKeyword); + GCEventLevel level = static_cast(max(ctxToUpdate->EventPipeProvider.Level, + ctxToUpdate->EtwProvider->Level)); +#else + GCEventKeyword keywords = static_cast(ctxToUpdate->EventPipeProvider.EnabledKeywordsBitmask); + GCEventLevel level = static_cast(ctxToUpdate->EventPipeProvider.Level); +#endif + GCHeapUtilities::RecordEventStateChange(bIsPublicTraceHandle, keywords, level); } // Special check for the runtime provider's GCHeapCollectKeyword. Profilers @@ -4488,10 +4510,6 @@ extern "C" BOOLEAN bIsRundownTraceHandle = (context->RegistrationHandle==Microsoft_Windows_DotNETRuntimeRundownHandle); - GCEventKeyword keywords = static_cast(MatchAnyKeyword); - GCEventLevel level = static_cast(Level); - GCHeapUtilities::RecordEventStateChange(!!bIsPublicTraceHandle, keywords, level); - // EventPipeEtwCallback contains some GC eventing functionality shared between EventPipe and ETW. // Eventually, we'll want to merge these two codepaths whenever we can. CallbackProviderIndex providerIndex = DotNETRuntime; @@ -4627,7 +4645,6 @@ VOID ETW::ExceptionLog::ExceptionThrown(CrawlFrame *pCf, BOOL bIsReThrownExcept pExInfo = pExState->GetCurrentExceptionTracker(); _ASSERTE(pExInfo != NULL); bIsNestedException = (pExInfo->GetPreviousExceptionTracker() != NULL); - bIsCSE = (pExInfo->GetCorruptionSeverity() == ProcessCorrupting); bIsCLSCompliant = IsException((gc.exceptionObj)->GetMethodTable()) && ((gc.exceptionObj)->GetMethodTable() != MscorlibBinder::GetException(kRuntimeWrappedException)); @@ -4642,7 +4659,6 @@ VOID ETW::ExceptionLog::ExceptionThrown(CrawlFrame *pCf, BOOL bIsReThrownExcept exceptionFlags = ((bHasInnerException ? ETW::ExceptionLog::ExceptionStructs::HasInnerException : 0) | (bIsNestedException ? ETW::ExceptionLog::ExceptionStructs::IsNestedException : 0) | (bIsReThrownException ? ETW::ExceptionLog::ExceptionStructs::IsReThrownException : 0) | - (bIsCSE ? ETW::ExceptionLog::ExceptionStructs::IsCSE : 0) | (bIsCLSCompliant ? ETW::ExceptionLog::ExceptionStructs::IsCLSCompliant : 0)); if (pCf->IsFrameless()) @@ -4934,17 +4950,17 @@ VOID ETW::InfoLog::RuntimeInformation(INT32 type) PathString dllPath; UINT8 Sku = ETW::InfoLog::InfoStructs::CoreCLR; - //version info for clr.dll - USHORT vmMajorVersion = CLR_MAJOR_VERSION; - USHORT vmMinorVersion = CLR_MINOR_VERSION; - USHORT vmBuildVersion = CLR_BUILD_VERSION; - USHORT vmQfeVersion = CLR_BUILD_VERSION_QFE; + //version info for coreclr.dll + USHORT vmMajorVersion = RuntimeFileMajorVersion; + USHORT vmMinorVersion = RuntimeFileMinorVersion; + USHORT vmBuildVersion = RuntimeFileBuildVersion; + USHORT vmRevisionVersion = RuntimeFileRevisionVersion; - //version info for mscorlib.dll - USHORT bclMajorVersion = VER_ASSEMBLYMAJORVERSION; - USHORT bclMinorVersion = VER_ASSEMBLYMINORVERSION; - USHORT bclBuildVersion = VER_ASSEMBLYBUILD; - USHORT bclQfeVersion = VER_ASSEMBLYBUILD_QFE; + //version info for System.Private.CoreLib.dll + USHORT bclMajorVersion = RuntimeProductMajorVersion; + USHORT bclMinorVersion = RuntimeProductMinorVersion; + USHORT bclBuildVersion = RuntimeProductPatchVersion; + USHORT bclRevisionVersion = 0; LPCGUID comGUID=&IID_NULL; @@ -4964,11 +4980,11 @@ VOID ETW::InfoLog::RuntimeInformation(INT32 type) bclMajorVersion, bclMinorVersion, bclBuildVersion, - bclQfeVersion, + bclRevisionVersion, vmMajorVersion, vmMinorVersion, vmBuildVersion, - vmQfeVersion, + vmRevisionVersion, startupFlags, startupMode, lpwszCommandLine, @@ -4982,11 +4998,11 @@ VOID ETW::InfoLog::RuntimeInformation(INT32 type) bclMajorVersion, bclMinorVersion, bclBuildVersion, - bclQfeVersion, + bclRevisionVersion, vmMajorVersion, vmMinorVersion, vmBuildVersion, - vmQfeVersion, + vmRevisionVersion, startupFlags, startupMode, lpwszCommandLine, @@ -6265,7 +6281,7 @@ VOID ETW::MethodLog::SendMethodDetailsEvent(MethodDesc *pMethodDesc) { fSucceeded = FALSE; } - EX_END_CATCH(RethrowCorruptingExceptions); + EX_END_CATCH(RethrowTerminalExceptions); if (!fSucceeded) goto done; @@ -7600,7 +7616,12 @@ bool EventPipeHelper::IsEnabled(DOTNET_TRACE_CONTEXT Context, UCHAR Level, ULONG } CONTRACTL_END - if (Level <= Context.EventPipeProvider.Level || Context.EventPipeProvider.Level == 0) + if (!Context.EventPipeProvider.IsEnabled) + { + return false; + } + + if (Level <= Context.EventPipeProvider.Level) { return (Keyword == (ULONGLONG)0) || (Keyword & Context.EventPipeProvider.EnabledKeywordsBitmask) != 0; } diff --git a/src/coreclr/src/vm/excep.cpp b/src/coreclr/src/vm/excep.cpp index e77851c4497d04..ff2e67489c801e 100644 --- a/src/coreclr/src/vm/excep.cpp +++ b/src/coreclr/src/vm/excep.cpp @@ -121,11 +121,7 @@ typedef struct { PEXCEPTION_REGISTRATION_RECORD GetCurrentSEHRecord(); BOOL IsUnmanagedToManagedSEHHandler(EXCEPTION_REGISTRATION_RECORD*); -VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable, BOOL rethrow -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , CorruptionSeverity severity = NotCorrupting -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); +VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable, BOOL rethrow); //------------------------------------------------------------------------------- // Basically, this asks whether the exception is a managed exception thrown by @@ -2711,85 +2707,6 @@ LONG RaiseExceptionFilter(EXCEPTION_POINTERS* ep, LPVOID pv) return EXCEPTION_CONTINUE_SEARCH; } -//========================================================================== -// Throw an object. -//========================================================================== -VOID DECLSPEC_NORETURN RaiseTheException(OBJECTREF throwable, BOOL rethrow -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , CorruptionSeverity severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ) -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_COOPERATIVE; - - LOG((LF_EH, LL_INFO100, "RealCOMPlusThrow throwing %s\n", - throwable->GetMethodTable()->GetDebugClassName())); - - if (throwable == NULL) - { - _ASSERTE(!"RealCOMPlusThrow(OBJECTREF) called with NULL argument. Somebody forgot to post an exception!"); - EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE); - } - - _ASSERTE(throwable != CLRException::GetPreallocatedStackOverflowException()); - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - if (!g_pConfig->LegacyCorruptedStateExceptionsPolicy()) - { - // This is Scenario 3 described in clrex.h around the definition of SET_CE_RETHROW_FLAG_FOR_EX_CATCH macro. - // - // We are here because the VM is attempting to throw a managed exception. It is posssible this exception - // may not be seen by CLR's exception handler for managed code (e.g. there maybe an EX_CATCH up the stack - // that will swallow or rethrow this exception). In the following scenario: - // - // [VM1 - RethrowCSE] -> [VM2 - RethrowCSE] -> [VM3 - RethrowCSE] -> - // - // When managed code throws a CSE (e.g. TargetInvocationException flagged as CSE), [VM3] will rethrow it and we will - // enter EX_CATCH in VM2 which is supposed to rethrow it as well. Two things can happen: - // - // 1) The implementation of EX_CATCH in VM2 throws a new managed exception *before* rethrow policy is applied and control - // will reach EX_CATCH in VM1, OR - // - // 2) EX_CATCH in VM2 swallows the exception, comes out of the catch block and later throws a new managed exception that - // will be caught by EX_CATCH in VM1. - // - // In either of the cases, rethrow in VM1 should be on the basis of the new managed exception's corruption severity. - // - // To support this scenario, we set corruption severity of the managed exception VM is throwing. If its a rethrow, - // it implies we are rethrowing the last exception that was seen by CLR's managed code exception handler. In such a case, - // we will copy over the corruption severity of that exception. - - // If throwable indicates corrupted state, forcibly set the severity. - if (CEHelper::IsProcessCorruptedStateException(throwable)) - { - severity = ProcessCorrupting; - } - - // No one should have passed us an invalid severity. - _ASSERTE(severity > NotSet); - - if (severity == NotSet) - { - severity = NotCorrupting; - } - - // Update the corruption severity of the exception being thrown by the VM. - GetThread()->GetExceptionState()->SetLastActiveExceptionCorruptionSeverity(severity); - - // Exception's corruption severity should be reused in reraise if this exception leaks out from the VM - // into managed code - CEHelper::MarkLastActiveExceptionCorruptionSeverityForReraiseReuse(); - - LOG((LF_EH, LL_INFO100, "RaiseTheException - Set VM thrown managed exception severity to %d.\n", severity)); - } - -#endif // FEATURE_CORRUPTING_EXCEPTIONS - - RaiseTheExceptionInternalOnly(throwable,rethrow); -} - HRESULT GetHRFromThrowable(OBJECTREF throwable) { STATIC_CONTRACT_THROWS; @@ -2811,7 +2728,6 @@ HRESULT GetHRFromThrowable(OBJECTREF throwable) return hr; } - VOID DECLSPEC_NORETURN RaiseTheExceptionInternalOnly(OBJECTREF throwable, BOOL rethrow, BOOL fForStackOverflow) { STATIC_CONTRACT_THROWS; @@ -2966,11 +2882,8 @@ VOID DECLSPEC_NORETURN RaiseTheExceptionInternalOnly(OBJECTREF throwable, BOOL r // INSTALL_COMPLUS_EXCEPTION_HANDLER has a filter, so must put the call in a separate fcn -static VOID DECLSPEC_NORETURN RealCOMPlusThrowWorker(OBJECTREF throwable, BOOL rethrow -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , CorruptionSeverity severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS -) { +static VOID DECLSPEC_NORETURN RealCOMPlusThrowWorker(OBJECTREF throwable, BOOL rethrow) +{ STATIC_CONTRACT_THROWS; STATIC_CONTRACT_GC_TRIGGERS; STATIC_CONTRACT_MODE_ANY; @@ -2983,23 +2896,24 @@ static VOID DECLSPEC_NORETURN RealCOMPlusThrowWorker(OBJECTREF throwable, BOOL r // TODO: Do we need to install COMPlusFrameHandler here? INSTALL_COMPLUS_EXCEPTION_HANDLER(); - RaiseTheException(throwable, rethrow -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); + if (throwable == NULL) + { + _ASSERTE(!"RealCOMPlusThrow(OBJECTREF) called with NULL argument. Somebody forgot to post an exception!"); + EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE); + } + RaiseTheExceptionInternalOnly(throwable, rethrow); UNINSTALL_COMPLUS_EXCEPTION_HANDLER(); } - -VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable, BOOL rethrow -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , CorruptionSeverity severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS -) { +VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable, BOOL rethrow) +{ STATIC_CONTRACT_THROWS; STATIC_CONTRACT_GC_TRIGGERS; STATIC_CONTRACT_MODE_ANY; + + LOG((LF_EH, LL_INFO100, "RealCOMPlusThrow throwing %s\n", + throwable->GetMethodTable()->GetDebugClassName())); + GCPROTECT_BEGIN(throwable); _ASSERTE(IsException(throwable->GetMethodTable())); @@ -3020,20 +2934,12 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable, BOOL rethrow ExceptionPreserveStackTrace(throwable); } - RealCOMPlusThrowWorker(throwable, rethrow -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); + RealCOMPlusThrowWorker(throwable, rethrow); GCPROTECT_END(); } -VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , CorruptionSeverity severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ) +VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable) { CONTRACTL { @@ -3043,11 +2949,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable } CONTRACTL_END; - RealCOMPlusThrow(throwable, FALSE -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); + RealCOMPlusThrow(throwable, FALSE); } // this function finds the managed callback to get a resource @@ -3273,38 +3175,30 @@ DWORD MapWin32FaultToCOMPlusException(EXCEPTION_RECORD *pExceptionRecord) case STATUS_ACCESS_VIOLATION: { - // We have a config key, InsecurelyTreatAVsAsNullReference, that ensures we always translate to - // NullReferenceException instead of doing the new AV translation logic. - if ((g_pConfig != NULL) && !g_pConfig->LegacyNullReferenceExceptionPolicy()) - { #if defined(FEATURE_HIJACK) && !defined(TARGET_UNIX) - // If we got the exception on a redirect function it means the original exception happened in managed code: - if (Thread::IsAddrOfRedirectFunc(pExceptionRecord->ExceptionAddress)) - return (DWORD) kNullReferenceException; + // If we got the exception on a redirect function it means the original exception happened in managed code: + if (Thread::IsAddrOfRedirectFunc(pExceptionRecord->ExceptionAddress)) + return (DWORD) kNullReferenceException; - if (pExceptionRecord->ExceptionAddress == (LPVOID)GetEEFuncEntryPoint(THROW_CONTROL_FOR_THREAD_FUNCTION)) - { - return (DWORD) kNullReferenceException; - } + if (pExceptionRecord->ExceptionAddress == (LPVOID)GetEEFuncEntryPoint(THROW_CONTROL_FOR_THREAD_FUNCTION)) + { + return (DWORD) kNullReferenceException; + } #endif // FEATURE_HIJACK && !TARGET_UNIX - // If the IP of the AV is not in managed code, then its an AccessViolationException. - if (!ExecutionManager::IsManagedCode((PCODE)pExceptionRecord->ExceptionAddress)) - { - return (DWORD) kAccessViolationException; - } + // If the IP of the AV is not in managed code, then its an AccessViolationException. + if (!ExecutionManager::IsManagedCode((PCODE)pExceptionRecord->ExceptionAddress)) + { + return (DWORD) kAccessViolationException; + } - // If the address accessed is above 64k (Windows) or page size (PAL), then its an AccessViolationException. - // Note: Win9x is a little different... it never gives you the proper address of the read or write that caused - // the fault. It always gives -1, so we can't use it as part of the decision... just give - // NullReferenceException instead. - if (pExceptionRecord->ExceptionInformation[1] >= NULL_AREA_SIZE) - { - return (DWORD) kAccessViolationException; - } + // If the address accessed is above 64k (Windows) or page size (Unix), then its an AccessViolationException. + if (pExceptionRecord->ExceptionInformation[1] >= NULL_AREA_SIZE) + { + return (DWORD) kAccessViolationException; } - return (DWORD) kNullReferenceException; + return (DWORD) kNullReferenceException; } case STATUS_ARRAY_BOUNDS_EXCEEDED: @@ -3718,14 +3612,6 @@ BOOL IsUncatchable(OBJECTREF *pThrowable) if (OBJECTREFToObject(*pThrowable)->GetMethodTable() == g_pExecutionEngineExceptionClass) return TRUE; - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // Corrupting exceptions are also uncatchable - if (CEHelper::IsProcessCorruptedStateException(*pThrowable)) - { - return TRUE; - } -#endif //FEATURE_CORRUPTING_EXCEPTIONS } return FALSE; @@ -4032,9 +3918,12 @@ LONG WatsonLastChance( // EXCEPTION_CONTINUE_SEARCH, _CONTINUE_ GCX_PREEMP(); STRESS_LOG0(LF_CORDB, LL_INFO10, "D::RFFE: About to call RaiseFailFastException\n"); +#ifdef HOST_WINDOWS + CreateCrashDumpIfEnabled(); +#endif RaiseFailFastException(pExceptionInfo == NULL ? NULL : pExceptionInfo->ExceptionRecord, - pExceptionInfo == NULL ? NULL : pExceptionInfo->ContextRecord, - 0); + pExceptionInfo == NULL ? NULL : pExceptionInfo->ContextRecord, + 0); STRESS_LOG0(LF_CORDB, LL_INFO10, "D::RFFE: Return from RaiseFailFastException\n"); } } @@ -4216,6 +4105,161 @@ LONG WatsonLastChance( // EXCEPTION_CONTINUE_SEARCH, _CONTINUE_ UNREACHABLE(); } // LONG WatsonLastChance() +//=========================================================================================== +// +// Windows crash dump (createdump) support +// + +#ifdef HOST_WINDOWS + +// Crash dump generating program arguments if enabled. +LPCWSTR g_createDumpCommandLine = nullptr; + +static void +BuildCreateDumpCommandLine( + SString& commandLine, + LPCWSTR dumpName, + int dumpType, + bool diag) +{ + const char* DumpGeneratorName = "createdump.exe"; + + PathString coreclrPath; + if (WszGetModuleFileName(GetCLRModule(), coreclrPath)) + { + SString::CIterator lastBackslash = coreclrPath.End(); + if (coreclrPath.FindBack(lastBackslash, W('\\'))) + { + commandLine.Set(coreclrPath, coreclrPath.Begin(), lastBackslash + 1); + } + } + + commandLine.AppendPrintf("%s %d", DumpGeneratorName, GetCurrentProcessId()); + + if (dumpName != nullptr) + { + commandLine.AppendPrintf(" --name %S", dumpName); + } + + const char* dumpTypeOption = nullptr; + switch (dumpType) + { + case 1: + dumpTypeOption = "--normal"; + break; + case 2: + dumpTypeOption = "--withheap"; + break; + case 3: + dumpTypeOption = "--triage"; + break; + case 4: + dumpTypeOption = "--full"; + break; + } + + if (dumpTypeOption != nullptr) + { + commandLine.AppendPrintf(" %s", dumpTypeOption); + } + + if (diag) + { + commandLine.AppendPrintf(" --diag"); + } +} + +static bool +LaunchCreateDump(LPCWSTR lpCommandLine) +{ + bool fSuccess = false; + + EX_TRY + { + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = FALSE; + + STARTUPINFO StartupInfo; + memset(&StartupInfo, 0, sizeof(StartupInfo)); + StartupInfo.cb = sizeof(StartupInfo); + + PROCESS_INFORMATION processInformation; + if (WszCreateProcess(NULL, lpCommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &StartupInfo, &processInformation)) + { + WaitForSingleObject(processInformation.hProcess, INFINITE); + fSuccess = true; + } + } + EX_CATCH + { + } + EX_END_CATCH(SwallowAllExceptions); + + return fSuccess; +} + +void +CreateCrashDumpIfEnabled() +{ + // If enabled, launch the create minidump utility and wait until it completes + if (g_createDumpCommandLine != nullptr) + { + LaunchCreateDump(g_createDumpCommandLine); + } +} + +bool +GenerateCrashDump( + LPCWSTR dumpName, + int dumpType, + bool diag) +{ + SString commandLine; + if (dumpType < 1 || dumpType > 4) + { + return false; + } + if (dumpName != nullptr && dumpName[0] == '\0') + { + dumpName = nullptr; + } + BuildCreateDumpCommandLine(commandLine, dumpName, dumpType, diag); + return LaunchCreateDump(commandLine); +} + +void +InitializeCrashDump() +{ + bool enabled = CLRConfig::IsConfigEnabled(CLRConfig::INTERNAL_DbgEnableMiniDump); + if (enabled) + { + LPCWSTR dumpName = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgMiniDumpName); + int dumpType = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DbgMiniDumpType); + bool diag = CLRConfig::IsConfigEnabled(CLRConfig::INTERNAL_CreateDumpDiagnostics); + + SString commandLine; + BuildCreateDumpCommandLine(commandLine, dumpName, dumpType, diag); + g_createDumpCommandLine = commandLine.GetCopyOfUnicodeString(); + } +} + +#endif // HOST_WINDOWS + +//************************************************************************************ +// Create crash dump if enabled and terminate process. Generates crash dumps for both +// Windows and Linux if enabled. For Linux, it happens in TerminateProcess in the PAL. +//************************************************************************************ + +void CrashDumpAndTerminateProcess(UINT exitCode) +{ +#ifdef HOST_WINDOWS + CreateCrashDumpIfEnabled(); +#endif + TerminateProcess(GetCurrentProcess(), exitCode); +} + //--------------------------------------------------------------------------------------- // // This is just a simple helper to do some basic checking to see if an exception is intercepted. @@ -4342,8 +4386,8 @@ LONG UserBreakpointFilter(EXCEPTION_POINTERS* pEP) GetClrInstanceId()); } - // Otherwise, we termintate the process. - TerminateProcess(GetCurrentProcess(), STATUS_BREAKPOINT); + // Otherwise, we terminate the process. + CrashDumpAndTerminateProcess(STATUS_BREAKPOINT); // Shouldn't get here ... return EXCEPTION_CONTINUE_EXECUTION; @@ -4450,12 +4494,6 @@ LONG DefaultCatchNoSwallowFilter(EXCEPTION_POINTERS *ep, PVOID pv) return UserBreakpointFilter(ep); } - // If host policy or config file says "swallow"... - if (SwallowUnhandledExceptions()) - { // ...return EXCEPTION_EXECUTE_HANDLER to swallow the exception. - return EXCEPTION_EXECUTE_HANDLER; - } - // If the exception is of a type that is always swallowed (ThreadAbort, AppDomainUnload)... if (ExceptionIsAlwaysSwallowed(ep)) { // ...return EXCEPTION_EXECUTE_HANDLER to swallow the exception. @@ -4921,12 +4959,6 @@ lDone: ; } PAL_ENDTRY; - //if (param.fIgnore) - //{ - // VC's try/catch ignores breakpoint or single step exceptions. We can not continue running. - // TerminateProcess(GetCurrentProcess(), pExceptionInfo->ExceptionRecord->ExceptionCode); - //} - return param.retval; } // LONG InternalUnhandledExceptionFilter_Worker() @@ -4973,6 +5005,10 @@ LONG InternalUnhandledExceptionFilter( return retval; } +#ifdef HOST_WINDOWS + CreateCrashDumpIfEnabled(); +#endif + BOOL fShouldOurUEFDisplayUI = ShouldOurUEFDisplayUI(pExceptionInfo); // If this is a managed exception thrown by this instance of the CLR, the exception is no one's @@ -5634,7 +5670,7 @@ static LONG ThreadBaseExceptionFilter_Worker(PEXCEPTION_POINTERS pExceptionInfo, #ifdef _DEBUG if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnUncaughtException) && - !(swallowing && (SwallowUnhandledExceptions() || ExceptionIsAlwaysSwallowed(pExceptionInfo))) && + !(swallowing && ExceptionIsAlwaysSwallowed(pExceptionInfo)) && !(location == ClassInitUnhandledException && pThread->IsRudeAbortInitiated())) _ASSERTE(!"BreakOnUnCaughtException"); #endif @@ -5645,28 +5681,20 @@ static LONG ThreadBaseExceptionFilter_Worker(PEXCEPTION_POINTERS pExceptionInfo, if (swallowing) { - // The default handling for versions v1.0 and v1.1 was to swallow unhandled exceptions. - // With v2.0, the default is to let them go unhandled. Hosts & config files can modify the default - // to retain the v1.1 behaviour. - // Should we swallow this exception, or let it continue up and be unhandled? - if (!SwallowUnhandledExceptions()) - { - // No, don't swallow unhandled exceptions... - - // ...except if the exception is of a type that is always swallowed (ThreadAbort, ...) - if (ExceptionIsAlwaysSwallowed(pExceptionInfo)) - { // ...return EXCEPTION_EXECUTE_HANDLER to swallow the exception anyway. - return EXCEPTION_EXECUTE_HANDLER; - } + // No, don't swallow unhandled exceptions... + // ...except if the exception is of a type that is always swallowed (ThreadAbort, ...) + if (ExceptionIsAlwaysSwallowed(pExceptionInfo)) + { // ...return EXCEPTION_EXECUTE_HANDLER to swallow the exception anyway. + return EXCEPTION_EXECUTE_HANDLER; + } - #ifdef _DEBUG - if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnUncaughtException)) - _ASSERTE(!"BreakOnUnCaughtException"); - #endif + #ifdef _DEBUG + if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnUncaughtException)) + _ASSERTE(!"BreakOnUnCaughtException"); + #endif - // ...so, continue search. i.e. let the exception go unhandled. - return EXCEPTION_CONTINUE_SEARCH; - } + // ...so, continue search. i.e. let the exception go unhandled. + return EXCEPTION_CONTINUE_SEARCH; } #ifdef DEBUGGING_SUPPORTED @@ -5715,15 +5743,6 @@ LONG ThreadBaseExceptionSwallowingFilter(PEXCEPTION_POINTERS pExceptionInfo, PVO return ThreadBaseExceptionFilter_Worker(pExceptionInfo, pvParam, /*swallowing=*/true); } -// This was the filter for new managed threads in v1.0 and v1.1. Now used -// for delegate invoke, various things in the thread pool, and the -// class init handler. -LONG ThreadBaseExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo, PVOID pvParam) -{ - return ThreadBaseExceptionFilter_Worker(pExceptionInfo, pvParam, /*swallowing=*/false); -} - - // This is the filter that we install when transitioning an AppDomain at the base of a managed // thread. Nothing interesting will get swallowed after us. So we never decide to continue // the search. Instead, we let it go unhandled and get the Watson report and debugging @@ -6658,7 +6677,6 @@ EXTERN_C void JIT_WriteBarrier_Debug(); EXTERN_C void JIT_WriteBarrier_Debug_End(); #endif -#ifdef VSD_STUB_CAN_THROW_AV //Return TRUE if pContext->Pc is in VirtualStub BOOL IsIPinVirtualStub(PCODE f_IP) { @@ -6689,7 +6707,6 @@ BOOL IsIPinVirtualStub(PCODE f_IP) return FALSE; } } -#endif // VSD_STUB_CAN_THROW_AV // Check if the passed in instruction pointer is in one of the // JIT helper functions. @@ -7979,7 +7996,7 @@ LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo) // // 1) We have a valid Thread object (implies exception on managed thread) // 2) Not a valid Thread object but the IP is in the execution engine (implies native thread within EE faulted) - // 3) The exception occurred in a GC marked location when no thread exists (i.e. reverse P/Invoke with NativeCallableAttribute). + // 3) The exception occurred in a GC marked location when no thread exists (i.e. reverse P/Invoke with UnmanagedCallersOnlyAttribute). if (pThread || fExceptionInEE) { if (!bIsGCMarker) @@ -8430,35 +8447,6 @@ LONG ReflectionInvocationExceptionFilter( } #endif // !TARGET_UNIX - // If the application has opted into triggering a failfast when a CorruptedStateException enters the Reflection system, - // then do the needful. - if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_FailFastOnCorruptedStateException) == 1) - { - // Get the thread and the managed exception object - they must exist at this point - Thread *pCurThread = GetThread(); - _ASSERTE(pCurThread != NULL); - - // Get the thread exception state - ThreadExceptionState * pCurTES = pCurThread->GetExceptionState(); - _ASSERTE(pCurTES != NULL); - - // Get the exception tracker for the current exception -#ifdef FEATURE_EH_FUNCLETS - PTR_ExceptionTracker pEHTracker = pCurTES->GetCurrentExceptionTracker(); -#elif TARGET_X86 - PTR_ExInfo pEHTracker = pCurTES->GetCurrentExceptionTracker(); -#else // !(HOST_64BIT || TARGET_X86) -#error Unsupported platform -#endif // HOST_64BIT - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - if (pEHTracker->GetCorruptionSeverity() == ProcessCorrupting) - { - EEPolicy::HandleFatalError(COR_E_FAILFAST, reinterpret_cast(pExceptionInfo->ExceptionRecord->ExceptionAddress), NULL, pExceptionInfo); - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS - } - return ret; } // LONG ReflectionInvocationExceptionFilter() @@ -8928,7 +8916,7 @@ BOOL SetupWatsonBucketsForEscapingPreallocatedExceptions() CONTRACTL { - GC_NOTRIGGER; + GC_TRIGGERS; MODE_ANY; NOTHROW; PRECONDITION(GetThread() != NULL); @@ -9348,7 +9336,7 @@ PTR_EHWatsonBucketTracker GetWatsonBucketTrackerForPreallocatedException(OBJECTR #ifndef DACCESS_COMPILE CONTRACTL { - GC_NOTRIGGER; + GC_TRIGGERS; MODE_COOPERATIVE; NOTHROW; PRECONDITION(GetThread() != NULL); @@ -10889,7 +10877,7 @@ void EHWatsonBucketTracker::CaptureUnhandledInfoForWatson(TypeOfReportedError to CONTRACTL { NOTHROW; - GC_NOTRIGGER; + GC_TRIGGERS; MODE_ANY; PRECONDITION(IsWatsonEnabled()); } @@ -10973,861 +10961,105 @@ PTR_ExInfo GetEHTrackerForException(OBJECTREF oThrowable, PTR_ExInfo pStartingEH return fFoundTracker ? pEHTracker : NULL; } -#ifdef FEATURE_CORRUPTING_EXCEPTIONS -// ----------------------------------------------------------------------- -// Support for CorruptedState Exceptions -// ----------------------------------------------------------------------- - // Given an exception code, this method returns a BOOL to indicate if the // code belongs to a corrupting exception or not. /* static */ -BOOL CEHelper::IsProcessCorruptedStateException(DWORD dwExceptionCode, BOOL fCheckForSO /*= TRUE*/) +BOOL IsProcessCorruptedStateException(DWORD dwExceptionCode, OBJECTREF throwable) { CONTRACTL { NOTHROW; GC_NOTRIGGER; - MODE_ANY; + MODE_COOPERATIVE; } CONTRACTL_END; - if (g_pConfig->LegacyCorruptedStateExceptionsPolicy()) + switch (dwExceptionCode) { + case STATUS_ACCESS_VIOLATION: + if (throwable != NULL && MscorlibBinder::IsException(throwable->GetMethodTable(), kNullReferenceException)) + return FALSE; + break; + case STATUS_STACK_OVERFLOW: + case EXCEPTION_ILLEGAL_INSTRUCTION: + case EXCEPTION_IN_PAGE_ERROR: + case EXCEPTION_INVALID_DISPOSITION: + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + case EXCEPTION_PRIV_INSTRUCTION: + case STATUS_UNWIND_CONSOLIDATE: + break; + default: return FALSE; } - // Call into the utilcode helper function to check if this - // is a CE or not. - return (::IsProcessCorruptedStateException(dwExceptionCode, fCheckForSO)); + if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_legacyCorruptedStateExceptionsPolicy)) + return FALSE; + + return TRUE; } -// This is used in the VM folder version of "SET_CE_RETHROW_FLAG_FOR_EX_CATCH" (in clrex.h) -// to check if the managed exception caught by EX_END_CATCH is CSE or not. -// -// If you are using it from rethrow boundaries (e.g. SET_CE_RETHROW_FLAG_FOR_EX_CATCH -// macro that is used to automatically rethrow corrupting exceptions), then you may -// want to set the "fMarkForReuseIfCorrupting" to TRUE to enable propagation of the -// corruption severity when the reraised exception is seen by managed code again. -/* static */ -BOOL CEHelper::IsLastActiveExceptionCorrupting(BOOL fMarkForReuseIfCorrupting /* = FALSE */) +#ifndef DACCESS_COMPILE +// This method will deliver the actual exception notification. Its assumed that the caller has done the necessary checks, including +// checking whether the delegate can be invoked for the exception's corruption severity. +void ExceptionNotifications::DeliverExceptionNotification(ExceptionNotificationHandlerType notificationType, OBJECTREF *pDelegate, + OBJECTREF *pAppDomain, OBJECTREF *pEventArgs) { CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(GetThread() != NULL); + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + PRECONDITION(pDelegate != NULL && IsProtectedByGCFrame(pDelegate) && (*pDelegate != NULL)); + PRECONDITION(pEventArgs != NULL && IsProtectedByGCFrame(pEventArgs)); + PRECONDITION(pAppDomain != NULL && IsProtectedByGCFrame(pAppDomain)); } CONTRACTL_END; - if (g_pConfig->LegacyCorruptedStateExceptionsPolicy()) - { - return FALSE; - } - - BOOL fIsCorrupting = FALSE; - ThreadExceptionState *pCurTES = GetThread()->GetExceptionState(); + PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(DELEGATEREF(*pDelegate)->GetMethodPtr()); - // Check the corruption severity - CorruptionSeverity severity = pCurTES->GetLastActiveExceptionCorruptionSeverity(); - fIsCorrupting = (severity == ProcessCorrupting); - if (fIsCorrupting && fMarkForReuseIfCorrupting) - { - // Mark the corruption severity for reuse - CEHelper::MarkLastActiveExceptionCorruptionSeverityForReraiseReuse(); - } + DECLARE_ARGHOLDER_ARRAY(args, 3); - LOG((LF_EH, LL_INFO100, "CEHelper::IsLastActiveExceptionCorrupting - Using corruption severity from TES.\n")); + args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(DELEGATEREF(*pDelegate)->GetTarget()); + args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(*pAppDomain); + args[ARGNUM_2] = OBJECTREF_TO_ARGHOLDER(*pEventArgs); - return fIsCorrupting; + CALL_MANAGED_METHOD_NORET(args); } -// Given a MethodDesc, this method will return a BOOL to indicate if -// the containing assembly was built for PreV4 runtime or not. -/* static */ -BOOL CEHelper::IsMethodInPreV4Assembly(PTR_MethodDesc pMethodDesc) +// To include definition of COMDelegate::GetMethodDesc +#include "comdelegate.h" + +// This method constructs the arguments to be passed to the exception notification event callback +void ExceptionNotifications::GetEventArgsForNotification(ExceptionNotificationHandlerType notificationType, + OBJECTREF *pOutEventArgs, OBJECTREF *pThrowable) { CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(pMethodDesc != NULL); + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + PRECONDITION(notificationType != UnhandledExceptionHandler); + PRECONDITION((pOutEventArgs != NULL) && IsProtectedByGCFrame(pOutEventArgs)); + PRECONDITION(*pOutEventArgs == NULL); + PRECONDITION((pThrowable != NULL) && (*pThrowable != NULL) && IsProtectedByGCFrame(pThrowable)); + PRECONDITION(IsException((*pThrowable)->GetMethodTable())); // We expect a valid exception object } CONTRACTL_END; - // By default, assume that the containing assembly was not - // built for PreV4 runtimes. - BOOL fBuiltForPreV4Runtime = FALSE; - - if (g_pConfig->LegacyCorruptedStateExceptionsPolicy()) - { - return TRUE; - } - - LPCSTR pszVersion = NULL; + MethodTable *pMTEventArgs = NULL; + BinderMethodID idEventArgsCtor = METHOD__FIRSTCHANCE_EVENTARGS__CTOR; - // Retrieve the manifest metadata reference since that contains - // the "built-for" runtime details - IMDInternalImport *pImport = pMethodDesc->GetAssembly()->GetManifestImport(); - if (pImport && SUCCEEDED(pImport->GetVersionString(&pszVersion))) + EX_TRY { - if (pszVersion != NULL) + switch(notificationType) { - // If version begins with "v1.*" or "v2.*", it was built for preV4 runtime - if ((pszVersion[0] == 'v' || pszVersion[0] == 'V') && - IS_DIGIT(pszVersion[1]) && - (pszVersion[2] == '.') ) - { - // Looks like a version. Is it lesser than v4.0 major version where we start using new behavior? - fBuiltForPreV4Runtime = ((DIGIT_TO_INT(pszVersion[1]) != 0) && - (DIGIT_TO_INT(pszVersion[1]) <= HIGHEST_MAJOR_VERSION_OF_PREV4_RUNTIME)); - } - } - } - - return fBuiltForPreV4Runtime; -} - -// Given a MethodDesc and CorruptionSeverity, this method will return a -// BOOL indicating if the method can handle those kinds of CEs or not. -/* static */ -BOOL CEHelper::CanMethodHandleCE(PTR_MethodDesc pMethodDesc, CorruptionSeverity severity, BOOL fCalculateSecurityInfo /*= TRUE*/) -{ - BOOL fCanMethodHandleSeverity = FALSE; - -#ifndef DACCESS_COMPILE - CONTRACTL - { - if (fCalculateSecurityInfo) - { - GC_TRIGGERS; // CEHelper::CanMethodHandleCE will invoke Security::IsMethodCritical that could endup invoking MethodTable::LoadEnclosingMethodTable that is GC_TRIGGERS - } - else - { - // See comment in COMPlusUnwindCallback for details. - GC_NOTRIGGER; - } - // First pass requires THROWS and in 2nd we need to be due to the AppX check below where GetFusionAssemblyName can throw. - THROWS; - MODE_ANY; - PRECONDITION(pMethodDesc != NULL); - } - CONTRACTL_END; - - - if (g_pConfig->LegacyCorruptedStateExceptionsPolicy()) - { - return TRUE; - } - - // Since the method is Security Critical, now check if it is - // attributed to handle the CE or not. - IMDInternalImport *pImport = pMethodDesc->GetMDImport(); - if (pImport != NULL) - { - mdMethodDef methodDef = pMethodDesc->GetMemberDef(); - switch(severity) - { - case ProcessCorrupting: - fCanMethodHandleSeverity = (S_OK == pImport->GetCustomAttributeByName( - methodDef, - HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE, - NULL, - NULL)); - break; - default: - _ASSERTE(!"Unknown Exception Corruption Severity!"); - break; - } - } -#endif // !DACCESS_COMPILE - - return fCanMethodHandleSeverity; -} - -// Given a MethodDesc, this method will return a BOOL to indicate if the method should be examined for exception -// handlers for the specified exception. -// -// This method accounts for both corrupting and non-corrupting exceptions. -/* static */ -BOOL CEHelper::CanMethodHandleException(CorruptionSeverity severity, PTR_MethodDesc pMethodDesc, BOOL fCalculateSecurityInfo /*= TRUE*/) -{ - CONTRACTL - { - // CEHelper::CanMethodHandleCE will invoke Security::IsMethodCritical that could endup invoking MethodTable::LoadEnclosingMethodTable that is GC_TRIGGERS/THROWS - if (fCalculateSecurityInfo) - { - GC_TRIGGERS; - } - else - { - // See comment in COMPlusUnwindCallback for details. - GC_NOTRIGGER; - } - THROWS; - MODE_ANY; - PRECONDITION(pMethodDesc != NULL); - } - CONTRACTL_END; - - // By default, assume that the runtime shouldn't look for exception handlers - // in the method pointed by the MethodDesc - BOOL fLookForExceptionHandlersInMethod = FALSE; - - if (g_pConfig->LegacyCorruptedStateExceptionsPolicy()) - { - return TRUE; - } - - // If we have been asked to use the last active corruption severity (e.g. in cases of Reflection - // or COM interop), then retrieve it. - if (severity == UseLast) - { - LOG((LF_EH, LL_INFO100, "CEHelper::CanMethodHandleException - Using LastActiveExceptionCorruptionSeverity.\n")); - severity = GetThread()->GetExceptionState()->GetLastActiveExceptionCorruptionSeverity(); - } - - LOG((LF_EH, LL_INFO100, "CEHelper::CanMethodHandleException - Processing CorruptionSeverity: %d.\n", severity)); - - if (severity > NotCorrupting) - { - // If the method lies in an assembly built for pre-V4 runtime, allow the runtime - // to look for exception handler for the CE. - BOOL fIsMethodInPreV4Assembly = FALSE; - fIsMethodInPreV4Assembly = CEHelper::IsMethodInPreV4Assembly(pMethodDesc); - - if (!fIsMethodInPreV4Assembly) - { - // Method lies in an assembly built for V4 or later runtime. - LOG((LF_EH, LL_INFO100, "CEHelper::CanMethodHandleException - Method is in an assembly built for V4 or later runtime.\n")); - - // Depending upon the corruption severity of the exception, see if the - // method supports handling that. - LOG((LF_EH, LL_INFO100, "CEHelper::CanMethodHandleException - Exception is corrupting.\n")); - - // Check if the method can handle the severity specified in the exception object. - fLookForExceptionHandlersInMethod = CEHelper::CanMethodHandleCE(pMethodDesc, severity, fCalculateSecurityInfo); - } - else - { - // Method is in a Pre-V4 assembly - allow it to be examined for processing the CE - fLookForExceptionHandlersInMethod = TRUE; - } - } - else - { - // Non-corrupting exceptions can continue to be delivered - fLookForExceptionHandlersInMethod = TRUE; - } - - return fLookForExceptionHandlersInMethod; -} - -// Given a managed exception object, this method will return a BOOL -// indicating if it corresponds to a ProcessCorruptedState exception -// or not. -/* static */ -BOOL CEHelper::IsProcessCorruptedStateException(OBJECTREF oThrowable) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; - PRECONDITION(oThrowable != NULL); - } - CONTRACTL_END; - - if (g_pConfig->LegacyCorruptedStateExceptionsPolicy()) - { - return FALSE; - } - -#ifndef DACCESS_COMPILE - // If the throwable represents preallocated SO, then indicate it as a CSE - if (CLRException::GetPreallocatedStackOverflowException() == oThrowable) - { - return TRUE; - } -#endif // !DACCESS_COMPILE - - // Check if we have an exception tracker for this exception - // and if so, if it represents corrupting exception or not. - // Get the exception tracker for the current exception -#ifdef FEATURE_EH_FUNCLETS - PTR_ExceptionTracker pEHTracker = GetEHTrackerForException(oThrowable, NULL); -#elif TARGET_X86 - PTR_ExInfo pEHTracker = GetEHTrackerForException(oThrowable, NULL); -#else -#error Unsupported platform -#endif - - if (pEHTracker != NULL) - { - // Found the tracker for exception object - check if its CSE or not. - return (pEHTracker->GetCorruptionSeverity() == ProcessCorrupting); - } - - return FALSE; -} - -#ifdef FEATURE_EH_FUNCLETS -void CEHelper::SetupCorruptionSeverityForActiveExceptionInUnwindPass(Thread *pCurThread, PTR_ExceptionTracker pEHTracker, BOOL fIsFirstPass, - DWORD dwExceptionCode) -{ -#ifndef DACCESS_COMPILE - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(!fIsFirstPass); // This method should only be called during an unwind - PRECONDITION(pCurThread != NULL); - } - CONTRACTL_END; - - // - // - // Typically, exception tracker is created for an exception when the OS is in the first pass. - // However, it may be created during the 2nd pass under specific cases. Managed C++ provides - // such a scenario. In the following, stack grows left to right: - // - // CallDescrWorker -> ILStub1 -> -> UMThunkStub -> IL_Stub2 -> - // - // If a CSE exception goes unhandled from managed main, it will reach the OS. The [CRT in?] OS triggers - // unwind that results in invoking the personality routine of UMThunkStub, called UMThunkStubUnwindFrameChainHandler, - // that releases all exception trackers below it. Thus, the tracker for the CSE, which went unhandled, is also - // released. This detail is 64bit specific and the crux of this issue. - // - // Now, it is expected that by the time we are in the unwind pass, the corruption severity would have already been setup in the - // exception tracker and thread exception state (TES) as part of the first pass, and thus, are identical. - // - // However, for the scenario above, when the unwind continues and reaches ILStub1, its personality routine (which is ProcessCLRException) - // is invoked. It attempts to get the exception tracker corresponding to the exception. Since none exists, it creates a brand new one, - // which has the exception corruption severity as NotSet. - // - // During the stack walk, we know (from TES) that the active exception was a CSE, and thus, ILStub1 cannot handle the exception. Prior - // to bailing out, we assert that our data structures are intact by comparing the exception severity in TES with the one in the current - // exception tracker. Since the tracker was recreated, it had the severity as NotSet and this does not match the severity in TES. - // Thus, the assert fires. [This check is performed in ProcessManagedCallFrame.] - // - // To address such a case, if we have created a new exception tracker in the unwind (2nd) pass, then set its - // exception corruption severity to what the TES holds currently. This will maintain the same semantic as the case - // where new tracker is not created (for e.g. the exception was caught in Managed main). - // - // The exception is the scenario of code that uses longjmp to jump to a different context. Longjmp results in a raise - // of a new exception with the longjmp exception code (0x80000026) but with ExceptionFlags set indicating unwind. When this is - // seen by ProcessCLRException (64bit personality routine), it will create a new tracker in the 2nd pass. - // - // Longjmp outside an exceptional path does not interest us, but the one in the exceptional - // path would only happen when a method attributed to handle CSE invokes it. Thus, if the longjmp happened during the 2nd pass of a CSE, - // we want it to proceed (and thus, jump) as expected and not apply the CSE severity to the tracker - this is equivalent to - // a catch block that handles a CSE and then does a "throw new Exception();". The new exception raised is - // non-CSE in nature as well. - // - // http://www.nynaeve.net/?p=105 has a brief description of how exception-safe setjmp/longjmp works. - // - // - if (pEHTracker->GetCorruptionSeverity() == NotSet) - { - // Get the thread exception state - ThreadExceptionState *pCurTES = pCurThread->GetExceptionState(); - - // Set the tracker to have the same corruption severity as the last active severity unless we are dealing - // with LONGJMP - if (dwExceptionCode == STATUS_LONGJUMP) - { - pCurTES->SetLastActiveExceptionCorruptionSeverity(NotCorrupting); - } - - pEHTracker->SetCorruptionSeverity(pCurTES->GetLastActiveExceptionCorruptionSeverity()); - LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveExceptionInUnwindPass - Setup the corruption severity in the second pass.\n")); - } -#endif // !DACCESS_COMPILE -} -#endif // FEATURE_EH_FUNCLETS - -// This method is invoked from the personality routine for managed code and is used to setup the -// corruption severity for the active exception on the thread exception state and the -// exception tracker corresponding to the exception. -/* static */ -void CEHelper::SetupCorruptionSeverityForActiveException(BOOL fIsRethrownException, BOOL fIsNestedException, BOOL fShouldTreatExceptionAsNonCorrupting /* = FALSE */) -{ -#ifndef DACCESS_COMPILE - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - // Get the thread and the managed exception object - they must exist at this point - Thread *pCurThread = GetThread(); - _ASSERTE(pCurThread != NULL); - - OBJECTREF oThrowable = pCurThread->GetThrowable(); - _ASSERTE(oThrowable != NULL); - - // Get the thread exception state - ThreadExceptionState * pCurTES = pCurThread->GetExceptionState(); - _ASSERTE(pCurTES != NULL); - - // Get the exception tracker for the current exception -#ifdef FEATURE_EH_FUNCLETS - PTR_ExceptionTracker pEHTracker = pCurTES->GetCurrentExceptionTracker(); -#elif TARGET_X86 - PTR_ExInfo pEHTracker = pCurTES->GetCurrentExceptionTracker(); -#else // !(HOST_64BIT || TARGET_X86) -#error Unsupported platform -#endif // HOST_64BIT - - _ASSERTE(pEHTracker != NULL); - - // Get the current exception code from the tracker. - PEXCEPTION_RECORD pEHRecord = pCurTES->GetExceptionRecord(); - _ASSERTE(pEHRecord != NULL); - DWORD dwActiveExceptionCode = pEHRecord->ExceptionCode; - - if (pEHTracker->GetCorruptionSeverity() != NotSet) - { - // Since the exception tracker already has the corruption severity set, - // we dont have much to do. Just confirm that our assumptions are correct. - _ASSERTE(pEHTracker->GetCorruptionSeverity() == pCurTES->GetLastActiveExceptionCorruptionSeverity()); - - LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Current tracker already has the corruption severity set.\n")); - return; - } - - // If the exception in question is to be treated as non-corrupting, - // then flag it and exit. - if (fShouldTreatExceptionAsNonCorrupting || g_pConfig->LegacyCorruptedStateExceptionsPolicy()) - { - pEHTracker->SetCorruptionSeverity(NotCorrupting); - LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Exception treated as non-corrupting.\n")); - goto done; - } - - if (!fIsRethrownException && !fIsNestedException) - { - // There should be no previously active exception for this case - _ASSERTE(pEHTracker->GetPreviousExceptionTracker() == NULL); - - CorruptionSeverity severityTES = NotSet; - - if (pCurTES->ShouldLastActiveExceptionCorruptionSeverityBeReused()) - { - // Get the corruption severity from the ThreadExceptionState (TES) for the last active exception - severityTES = pCurTES->GetLastActiveExceptionCorruptionSeverity(); - - // Incase of scenarios like AD transition or Reflection invocation, - // TES would hold corruption severity of the last active exception. To propagate it - // to the current exception, we will apply it to current tracker and only if the applied - // severity is "NotSet", will we proceed to check the current exception for corruption - // severity. - pEHTracker->SetCorruptionSeverity(severityTES); - } - - // Reset TES Corruption Severity - pCurTES->SetLastActiveExceptionCorruptionSeverity(NotSet); - - if (severityTES == NotSet) - { - // Since the last active exception's severity was "NotSet", we will look up the - // exception code and the exception object to see if the exception should be marked - // corrupting. - // - // Since this exception was neither rethrown nor is nested, it implies that we are - // outside an active exception. Thus, even if it contains inner exceptions, we wont have - // corruption severity for them since that information is tracked in EH tracker and - // we wont have an EH tracker for the inner most exception. - - if (CEHelper::IsProcessCorruptedStateException(dwActiveExceptionCode) || - CEHelper::IsProcessCorruptedStateException(oThrowable)) - { - pEHTracker->SetCorruptionSeverity(ProcessCorrupting); - LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Marked non-rethrow/non-nested exception as ProcessCorrupting.\n")); - } - else - { - pEHTracker->SetCorruptionSeverity(NotCorrupting); - LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Marked non-rethrow/non-nested exception as NotCorrupting.\n")); - } - } - else - { - LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Copied the corruption severity to tracker from ThreadExceptionState for non-rethrow/non-nested exception.\n")); - } - } - else - { - // Its either a rethrow or nested exception - -#ifdef FEATURE_EH_FUNCLETS - PTR_ExceptionTracker pOrigEHTracker = NULL; -#elif TARGET_X86 - PTR_ExInfo pOrigEHTracker = NULL; -#else -#error Unsupported platform -#endif - - BOOL fDoWeHaveCorruptionSeverity = FALSE; - - if (fIsRethrownException) - { - // Rethrown exceptions are nested by nature (of our implementation). The - // original EHTracker will exist for the exception - infact, it will be - // the tracker previous to the current one. We will simply copy - // its severity to the current EH tracker representing the rethrow. - pOrigEHTracker = pEHTracker->GetPreviousExceptionTracker(); - _ASSERTE(pOrigEHTracker != NULL); - - // Ideally, we would like have the assert below enabled. But, as may happen under OOM - // stress, this can be false. Here's how it will happen: - // - // An exception is thrown, which is later caught and rethrown in the catch block. Rethrow - // results in calling IL_Rethrow that will call RaiseTheExceptionInternalOnly to actually - // raise the exception. Prior to the raise, we update the last thrown object on the thread - // by calling Thread::SafeSetLastThrownObject which, internally, could have an OOM, resulting - // in "changing" the throwable used to raise the exception to be preallocated OOM object. - // - // When the rethrow happens and CLR's exception handler for managed code sees the exception, - // the exception tracker created for the rethrown exception will contain the reference to - // the last thrown object, which will be the preallocated OOM object. - // - // Thus, though, we came here because of a rethrow, and logically, the throwable should remain - // the same, it neednt be. Simply put, rethrow can result in working with a completely different - // exception object than what was originally thrown. - // - // Hence, the assert cannot be enabled. - // - // Thus, we will use the EH tracker corresponding to the original exception, to get the - // rethrown exception's corruption severity, only when the rethrown throwable is the same - // as the original throwable. Otherwise, we will pretend that we didnt get the original tracker - // and will automatically enter the path below to set the corruption severity based upon the - // rethrown throwable. - - // _ASSERTE(pOrigEHTracker->GetThrowable() == oThrowable); - if (pOrigEHTracker->GetThrowable() != oThrowable) - { - pOrigEHTracker = NULL; - LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Rethrown throwable does not match the original throwable. Corruption severity will be set based upon rethrown throwable.\n")); - } - } - else - { - // Get the corruption severity from the ThreadExceptionState (TES) for the last active exception - CorruptionSeverity severityTES = NotSet; - - if (pCurTES->ShouldLastActiveExceptionCorruptionSeverityBeReused()) - { - severityTES = pCurTES->GetLastActiveExceptionCorruptionSeverity(); - - // Incase of scenarios like AD transition or Reflection invocation, - // TES would hold corruption severity of the last active exception. To propagate it - // to the current exception, we will apply it to current tracker and only if the applied - // severity is "NotSet", will we proceed to check the current exception for corruption - // severity. - pEHTracker->SetCorruptionSeverity(severityTES); - } - - // Reset TES Corruption Severity - pCurTES->SetLastActiveExceptionCorruptionSeverity(NotSet); - - // If the last exception didnt have any corruption severity, proceed to look for it. - if (severityTES == NotSet) - { - // This is a nested exception - check if it has an inner exception(s). If it does, - // find the EH tracker corresponding to the innermost exception and we will copy the - // corruption severity from the original tracker to the current one. - OBJECTREF oInnermostThrowable = ((EXCEPTIONREF)oThrowable)->GetBaseException(); - if (oInnermostThrowable != NULL) - { - // Find the tracker corresponding to the inner most exception, starting from - // the tracker previous to the current one. An EH tracker may not be found if - // the code did the following inside a catch clause: - // - // Exception ex = new Exception("inner exception"); - // throw new Exception("message", ex); - // - // Or, an exception like AV happened in the catch clause. - pOrigEHTracker = GetEHTrackerForException(oInnermostThrowable, pEHTracker->GetPreviousExceptionTracker()); - } - } - else - { - // We have the corruption severity from the TES. Set the flag indicating so. - fDoWeHaveCorruptionSeverity = TRUE; - LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Copied the corruption severity to tracker from ThreadExceptionState for nested exception.\n")); - } - } - - if (!fDoWeHaveCorruptionSeverity) - { - if (pOrigEHTracker != NULL) - { - // Copy the severity from the original EH tracker to the current one - CorruptionSeverity origCorruptionSeverity = pOrigEHTracker->GetCorruptionSeverity(); - _ASSERTE(origCorruptionSeverity != NotSet); - pEHTracker->SetCorruptionSeverity(origCorruptionSeverity); - - LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Copied the corruption severity (%d) from the original EH tracker for rethrown exception.\n", origCorruptionSeverity)); - } - else - { - if (CEHelper::IsProcessCorruptedStateException(dwActiveExceptionCode) || - CEHelper::IsProcessCorruptedStateException(oThrowable)) - { - pEHTracker->SetCorruptionSeverity(ProcessCorrupting); - LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Marked nested exception as ProcessCorrupting.\n")); - } - else - { - pEHTracker->SetCorruptionSeverity(NotCorrupting); - LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Marked nested exception as NotCorrupting.\n")); - } - } - } - } - -done: - // Save the current exception's corruption severity in the ThreadExceptionState (TES) - // for cases when we catch the managed exception in the runtime using EX_CATCH. - // At such a time, all exception trackers get released (due to unwind triggered - // by EX_END_CATCH) and yet we need the corruption severity information for - // scenarios like AD Transition, Reflection invocation, etc. - CorruptionSeverity currentSeverity = pEHTracker->GetCorruptionSeverity(); - - // We should be having a valid corruption severity at this point - _ASSERTE(currentSeverity != NotSet); - - // Save it in the TES - pCurTES->SetLastActiveExceptionCorruptionSeverity(currentSeverity); - LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Copied the corruption severity (%d) to ThreadExceptionState.\n", currentSeverity)); - -#endif // !DACCESS_COMPILE -} - -// CE can be caught in the VM and later reraised again. Examples of such scenarios -// include AD transition, COM interop, Reflection invocation, to name a few. -// In such cases, we want to mark the corruption severity for reuse upon reraise, -// implying that when the VM does a reraise of such an exception, we should use -// the original corruption severity for the new raised exception, instead of creating -// a new one for it. -/* static */ -void CEHelper::MarkLastActiveExceptionCorruptionSeverityForReraiseReuse() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(GetThread() != NULL); - } - CONTRACTL_END; - - // If the last active exception's corruption severity is anything but - // "NotSet", mark it for ReraiseReuse - ThreadExceptionState *pCurTES = GetThread()->GetExceptionState(); - _ASSERTE(pCurTES != NULL); - - CorruptionSeverity severityTES = pCurTES->GetLastActiveExceptionCorruptionSeverity(); - if (severityTES != NotSet) - { - pCurTES->SetLastActiveExceptionCorruptionSeverity((CorruptionSeverity)(severityTES | ReuseForReraise)); - } -} - -// This method will return a BOOL to indicate if the current exception is to be treated as -// non-corrupting. Currently, this returns true for NullReferenceException only. -/* static */ -BOOL CEHelper::ShouldTreatActiveExceptionAsNonCorrupting() -{ - BOOL fShouldTreatAsNonCorrupting = FALSE; - -#ifndef DACCESS_COMPILE - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(GetThread() != NULL); - } - CONTRACTL_END; - - if (g_pConfig->LegacyCorruptedStateExceptionsPolicy()) - { - return TRUE; - } - - DWORD dwActiveExceptionCode = GetThread()->GetExceptionState()->GetExceptionRecord()->ExceptionCode; - if (dwActiveExceptionCode == STATUS_ACCESS_VIOLATION) - { - // NullReference has the same exception code as AV - OBJECTREF oThrowable = NULL; - GCPROTECT_BEGIN(oThrowable); - - // Get the throwable and check if it represents null reference exception - oThrowable = GetThread()->GetThrowable(); - _ASSERTE(oThrowable != NULL); - if (MscorlibBinder::GetException(kNullReferenceException) == oThrowable->GetMethodTable()) - { - fShouldTreatAsNonCorrupting = TRUE; - } - GCPROTECT_END(); - } -#endif // !DACCESS_COMPILE - - return fShouldTreatAsNonCorrupting; -} - -// If we were working in a nested exception scenario, reset the corruption severity to the last -// exception we were processing, based upon its EH tracker. -// -// If none was present, reset it to NotSet. -// -// Note: This method must be called once the exception trackers have been adjusted post catch-block execution. -/* static */ -void CEHelper::ResetLastActiveCorruptionSeverityPostCatchHandler(Thread *pThread) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(pThread != NULL); - } - CONTRACTL_END; - - ThreadExceptionState *pCurTES = pThread->GetExceptionState(); - - // By this time, we would have set the correct exception tracker for the active exception domain, - // if applicable. An example is throwing and catching an exception within a catch block. We will update - // the LastActiveCorruptionSeverity based upon the active exception domain. If we are not in one, we will - // set it to "NotSet". -#ifdef FEATURE_EH_FUNCLETS - PTR_ExceptionTracker pEHTracker = pCurTES->GetCurrentExceptionTracker(); -#elif TARGET_X86 - PTR_ExInfo pEHTracker = pCurTES->GetCurrentExceptionTracker(); -#else -#error Unsupported platform -#endif - - if (pEHTracker) - { - pCurTES->SetLastActiveExceptionCorruptionSeverity(pEHTracker->GetCorruptionSeverity()); - } - else - { - pCurTES->SetLastActiveExceptionCorruptionSeverity(NotSet); - } - - LOG((LF_EH, LL_INFO100, "CEHelper::ResetLastActiveCorruptionSeverityPostCatchHandler - Reset LastActiveException corruption severity to %d.\n", - pCurTES->GetLastActiveExceptionCorruptionSeverity())); -} - -// This method will return a BOOL indicating if the target of IDispatch can handle the specified exception or not. -/* static */ -BOOL CEHelper::CanIDispatchTargetHandleException() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(GetThread() != NULL); - } - CONTRACTL_END; - - // By default, assume that the target of IDispatch cannot handle the exception. - BOOL fCanMethodHandleException = FALSE; - - if (g_pConfig->LegacyCorruptedStateExceptionsPolicy()) - { - return TRUE; - } - - // IDispatch implementation in COM interop works by invoking the actual target via reflection. - // Thus, a COM client could use the V4 runtime to invoke a V2 method. In such a case, a CSE - // could come unhandled at the actual target invoked via reflection. - // - // Reflection invocation would have set a flag for us, indicating if the actual target was - // enabled to handle the CE or not. If it is, then we should allow the COM client to get the - // hresult from the call and not let the exception continue up the stack. - ThreadExceptionState *pCurTES = GetThread()->GetExceptionState(); - fCanMethodHandleException = pCurTES->CanReflectionTargetHandleException(); - - // Reset the flag so that subsequent invocations work as expected. - pCurTES->SetCanReflectionTargetHandleException(FALSE); - - return fCanMethodHandleException; -} - -#endif // FEATURE_CORRUPTING_EXCEPTIONS - -#ifndef DACCESS_COMPILE -// This method will deliver the actual exception notification. Its assumed that the caller has done the necessary checks, including -// checking whether the delegate can be invoked for the exception's corruption severity. -void ExceptionNotifications::DeliverExceptionNotification(ExceptionNotificationHandlerType notificationType, OBJECTREF *pDelegate, - OBJECTREF *pAppDomain, OBJECTREF *pEventArgs) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(pDelegate != NULL && IsProtectedByGCFrame(pDelegate) && (*pDelegate != NULL)); - PRECONDITION(pEventArgs != NULL && IsProtectedByGCFrame(pEventArgs)); - PRECONDITION(pAppDomain != NULL && IsProtectedByGCFrame(pAppDomain)); - } - CONTRACTL_END; - - PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(DELEGATEREF(*pDelegate)->GetMethodPtr()); - - DECLARE_ARGHOLDER_ARRAY(args, 3); - - args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(DELEGATEREF(*pDelegate)->GetTarget()); - args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(*pAppDomain); - args[ARGNUM_2] = OBJECTREF_TO_ARGHOLDER(*pEventArgs); - - CALL_MANAGED_METHOD_NORET(args); -} - -// To include definition of COMDelegate::GetMethodDesc -#include "comdelegate.h" - -// This method constructs the arguments to be passed to the exception notification event callback -void ExceptionNotifications::GetEventArgsForNotification(ExceptionNotificationHandlerType notificationType, - OBJECTREF *pOutEventArgs, OBJECTREF *pThrowable) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(notificationType != UnhandledExceptionHandler); - PRECONDITION((pOutEventArgs != NULL) && IsProtectedByGCFrame(pOutEventArgs)); - PRECONDITION(*pOutEventArgs == NULL); - PRECONDITION((pThrowable != NULL) && (*pThrowable != NULL) && IsProtectedByGCFrame(pThrowable)); - PRECONDITION(IsException((*pThrowable)->GetMethodTable())); // We expect a valid exception object - } - CONTRACTL_END; - - MethodTable *pMTEventArgs = NULL; - BinderMethodID idEventArgsCtor = METHOD__FIRSTCHANCE_EVENTARGS__CTOR; - - EX_TRY - { - switch(notificationType) - { - case FirstChanceExceptionHandler: - pMTEventArgs = MscorlibBinder::GetClass(CLASS__FIRSTCHANCE_EVENTARGS); - idEventArgsCtor = METHOD__FIRSTCHANCE_EVENTARGS__CTOR; - break; - default: - _ASSERTE(!"Invalid Exception Notification Handler!"); - break; + case FirstChanceExceptionHandler: + pMTEventArgs = MscorlibBinder::GetClass(CLASS__FIRSTCHANCE_EVENTARGS); + idEventArgsCtor = METHOD__FIRSTCHANCE_EVENTARGS__CTOR; + break; + default: + _ASSERTE(!"Invalid Exception Notification Handler!"); + break; } // Allocate the instance of the eventargs corresponding to the notification @@ -11860,7 +11092,7 @@ void ExceptionNotifications::GetEventArgsForNotification(ExceptionNotificationHa *pOutEventArgs = NULL; LOG((LF_EH, LL_INFO100, "ExceptionNotifications::GetEventArgsForNotification: Setting event args to NULL due to an exception.\n")); } - EX_END_CATCH(RethrowCorruptingExceptions); // Dont swallow any CSE that may come in from the .ctor. + EX_END_CATCH(RethrowTerminalExceptions); } // This SEH filter will be invoked when an exception escapes out of the exception notification @@ -11871,89 +11103,6 @@ static LONG ExceptionNotificationFilter(PEXCEPTION_POINTERS pExceptionInfo, LPVO return -1; } -#ifdef FEATURE_CORRUPTING_EXCEPTIONS -// This method will return a BOOL indicating if the delegate should be invoked for the exception -// of the specified corruption severity. -BOOL ExceptionNotifications::CanDelegateBeInvokedForException(OBJECTREF *pDelegate, CorruptionSeverity severity) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(pDelegate != NULL && IsProtectedByGCFrame(pDelegate) && (*pDelegate != NULL)); - PRECONDITION(severity > NotSet); - } - CONTRACTL_END; - - // Notifications for CSE are only delivered if the delegate target follows CSE rules. - BOOL fCanMethodHandleException = g_pConfig->LegacyCorruptedStateExceptionsPolicy() ? TRUE:(severity == NotCorrupting); - if (!fCanMethodHandleException) - { - EX_TRY - { - // Get the MethodDesc of the delegate to be invoked - MethodDesc *pMDDelegate = COMDelegate::GetMethodDesc(*pDelegate); - _ASSERTE(pMDDelegate != NULL); - - // Check the callback target and see if it is following CSE rules or not. - fCanMethodHandleException = CEHelper::CanMethodHandleException(severity, pMDDelegate); - } - EX_CATCH - { - // Incase of any exceptions, pretend we cannot handle the exception - fCanMethodHandleException = FALSE; - LOG((LF_EH, LL_INFO100, "ExceptionNotifications::CanDelegateBeInvokedForException: Exception while trying to determine if exception notification can be invoked or not.\n")); - } - EX_END_CATCH(RethrowCorruptingExceptions); // Dont swallow any CSEs. - } - - return fCanMethodHandleException; -} -#endif // FEATURE_CORRUPTING_EXCEPTIONS - -// This method will make the actual delegate invocation for the exception notification to be delivered. If an -// exception escapes out of the notification, our filter in ExceptionNotifications::DeliverNotification will -// address it. -void ExceptionNotifications::InvokeNotificationDelegate(ExceptionNotificationHandlerType notificationType, OBJECTREF *pDelegate, OBJECTREF *pEventArgs, - OBJECTREF *pAppDomain -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , CorruptionSeverity severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(pDelegate != NULL && IsProtectedByGCFrame(pDelegate) && (*pDelegate != NULL)); - PRECONDITION(pEventArgs != NULL && IsProtectedByGCFrame(pEventArgs)); - PRECONDITION(pAppDomain != NULL && IsProtectedByGCFrame(pAppDomain)); -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - PRECONDITION(severity > NotSet); -#endif // FEATURE_CORRUPTING_EXCEPTIONS - // Unhandled Exception Notification is delivered via Unhandled Exception Processing - // mechanism. - PRECONDITION(notificationType != UnhandledExceptionHandler); - } - CONTRACTL_END; - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // Notifications are delivered based upon corruption severity of the exception - if (!ExceptionNotifications::CanDelegateBeInvokedForException(pDelegate, severity)) - { - LOG((LF_EH, LL_INFO100, "ExceptionNotifications::InvokeNotificationDelegate: Delegate cannot be invoked for corruption severity %d\n", - severity)); - return; - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS - - // We've already exercised the prestub on this delegate's COMDelegate::GetMethodDesc, - // as part of wiring up a reliable event sink in the BCL. Deliver the notification. - ExceptionNotifications::DeliverExceptionNotification(notificationType, pDelegate, pAppDomain, pEventArgs); -} - // This method returns a BOOL to indicate if the AppDomain is ready to receive exception notifications or not. BOOL ExceptionNotifications::CanDeliverNotificationToCurrentAppDomain(ExceptionNotificationHandlerType notificationType) { @@ -11983,11 +11132,7 @@ BOOL ExceptionNotifications::CanDeliverNotificationToCurrentAppDomain(ExceptionN // so that if an exception escapes out of the notification callback, we will trigger failfast from // our filter. void ExceptionNotifications::DeliverNotification(ExceptionNotificationHandlerType notificationType, - OBJECTREF *pThrowable -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , CorruptionSeverity severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ) + OBJECTREF *pThrowable) { STATIC_CONTRACT_GC_TRIGGERS; STATIC_CONTRACT_NOTHROW; // NOTHROW because incase of an exception, we will FailFast. @@ -11997,26 +11142,16 @@ void ExceptionNotifications::DeliverNotification(ExceptionNotificationHandlerTyp { ExceptionNotificationHandlerType notificationType; OBJECTREF *pThrowable; -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - CorruptionSeverity severity; -#endif // FEATURE_CORRUPTING_EXCEPTIONS } args; args.notificationType = notificationType; args.pThrowable = pThrowable; -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - args.severity = severity; -#endif // FEATURE_CORRUPTING_EXCEPTIONS PAL_TRY(TryArgs *, pArgs, &args) { // Make the call to the actual method that will invoke the callbacks ExceptionNotifications::DeliverNotificationInternal(pArgs->notificationType, - pArgs->pThrowable -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , pArgs->severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); + pArgs->pThrowable); } PAL_EXCEPT_FILTER(ExceptionNotificationFilter) { @@ -12030,11 +11165,7 @@ void ExceptionNotifications::DeliverNotification(ExceptionNotificationHandlerTyp // This method will deliver the exception notification to the current AppDomain. void ExceptionNotifications::DeliverNotificationInternal(ExceptionNotificationHandlerType notificationType, - OBJECTREF *pThrowable -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , CorruptionSeverity severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ) + OBJECTREF *pThrowable) { CONTRACTL { @@ -12047,9 +11178,6 @@ void ExceptionNotifications::DeliverNotificationInternal(ExceptionNotificationHa PRECONDITION(notificationType != UnhandledExceptionHandler); PRECONDITION((pThrowable != NULL) && (*pThrowable != NULL)); PRECONDITION(ExceptionNotifications::CanDeliverNotificationToCurrentAppDomain(notificationType)); -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - PRECONDITION(severity > NotSet); // Exception corruption severity must be valid at this point. -#endif // FEATURE_CORRUPTING_EXCEPTIONS } CONTRACTL_END; @@ -12116,12 +11244,7 @@ void ExceptionNotifications::DeliverNotificationInternal(ExceptionNotificationHa gc.arrDelegates = (PTRARRAYREF) ((DELEGATEREF)(gc.oNotificationDelegate))->GetInvocationList(); if (gc.arrDelegates == NULL || !gc.arrDelegates->GetMethodTable()->IsArray()) { - ExceptionNotifications::InvokeNotificationDelegate(notificationType, &gc.oNotificationDelegate, &gc.oEventArgs, - &gc.oCurAppDomain -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); + ExceptionNotifications::DeliverExceptionNotification(notificationType, &gc.oNotificationDelegate, &gc.oCurAppDomain, &gc.oEventArgs); } else { @@ -12133,12 +11256,7 @@ void ExceptionNotifications::DeliverNotificationInternal(ExceptionNotificationHa for (UINT_PTR i=0; im_Array[i]; - ExceptionNotifications::InvokeNotificationDelegate(notificationType, &gc.oInnerDelegate, &gc.oEventArgs, - &gc.oCurAppDomain -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); + ExceptionNotifications::DeliverExceptionNotification(notificationType, &gc.oInnerDelegate, &gc.oCurAppDomain, &gc.oEventArgs); } } } @@ -12178,11 +11296,7 @@ void ExceptionNotifications::DeliverFirstChanceNotification() oThrowable = pCurTES->GetThrowable(); _ASSERTE(oThrowable != NULL); - ExceptionNotifications::DeliverNotification(FirstChanceExceptionHandler, &oThrowable -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , pCurTES->GetCurrentExceptionTracker()->GetCorruptionSeverity() -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); + ExceptionNotifications::DeliverNotification(FirstChanceExceptionHandler, &oThrowable); GCPROTECT_END(); } diff --git a/src/coreclr/src/vm/excep.h b/src/coreclr/src/vm/excep.h index 33a616f81aa7d9..661eefe813bb77 100644 --- a/src/coreclr/src/vm/excep.h +++ b/src/coreclr/src/vm/excep.h @@ -22,16 +22,12 @@ class Thread; #include #include "interoputil.h" -#if defined(TARGET_ARM) || defined(TARGET_X86) -#define VSD_STUB_CAN_THROW_AV -#endif // TARGET_ARM || TARGET_X86 - BOOL IsExceptionFromManagedCode(const EXCEPTION_RECORD * pExceptionRecord); -#ifdef VSD_STUB_CAN_THROW_AV BOOL IsIPinVirtualStub(PCODE f_IP); -#endif // VSD_STUB_CAN_THROW_AV bool IsIPInMarkedJitHelper(UINT_PTR uControlPc); +BOOL IsProcessCorruptedStateException(DWORD dwExceptionCode, OBJECTREF throwable); + BOOL AdjustContextForJITHelpers(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pContext); #if defined(FEATURE_HIJACK) && (!defined(TARGET_X86) || defined(TARGET_UNIX)) @@ -42,26 +38,6 @@ bool IsIPInEpilog(PTR_CONTEXT pContextToCheck, EECodeInfo *pCodeInfo, BOOL *pSaf #endif // FEATURE_HIJACK && (!TARGET_X86 || TARGET_UNIX) -//****************************************************************************** -// -// SwallowUnhandledExceptions -// -// Consult the EE policy and the app config to determine if the runtime should "swallow" unhandled exceptions. -// Swallow if: the EEPolicy->UnhandledExceptionPolicy is "eHostDeterminedPolicy" -// or: the app config value LegacyUnhandledExceptionPolicy() is set. -// -// Parameters: -// none -// -// Return value: -// true - the runtime should "swallow" unhandled exceptions -// -inline bool SwallowUnhandledExceptions() -{ - return (eHostDeterminedPolicy == GetEEPolicy()->GetUnhandledExceptionPolicy()) || - g_pConfig->LegacyUnhandledExceptionPolicy(); -} - // Enums // return values of LookForHandler enum LFH { @@ -96,8 +72,6 @@ struct ThrowCallbackType void * pPrevExceptionRecord; #endif - // Is the current exception a longjmp? - CORRUPTING_EXCEPTIONS_ONLY(BOOL m_fIsLongJump;) void Init() { LIMITED_METHOD_CONTRACT; @@ -118,8 +92,6 @@ struct ThrowCallbackType pCurrentExceptionRecord = 0; pPrevExceptionRecord = 0; #endif - // By default, the current exception is not a longjmp - CORRUPTING_EXCEPTIONS_ONLY(m_fIsLongJump = FALSE;) } }; @@ -223,12 +195,20 @@ enum UnhandledExceptionLocation FatalExecutionEngineException }; +#ifdef HOST_WINDOWS +void InitializeCrashDump(); +bool GenerateCrashDump(LPCWSTR dumpName, int dumpType, bool diag); +void CreateCrashDumpIfEnabled(); +#endif + +// Generates crash dumps if enabled for both Windows and Linux +void CrashDumpAndTerminateProcess(UINT exitCode); + struct ThreadBaseExceptionFilterParam { UnhandledExceptionLocation location; }; -LONG ThreadBaseExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo, PVOID pvParam); LONG ThreadBaseExceptionSwallowingFilter(PEXCEPTION_POINTERS pExceptionInfo, PVOID pvParam); LONG ThreadBaseExceptionAppDomainFilter(PEXCEPTION_POINTERS pExceptionInfo, PVOID pvParam); @@ -269,11 +249,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowNonLocalized(RuntimeExceptionKind reKind, // Throw an object. //========================================================================== -VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , CorruptionSeverity severity = NotCorrupting -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); +VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable); //========================================================================== // Throw an undecorated runtime exception. @@ -818,44 +794,6 @@ LONG ReflectionInvocationExceptionFilter( EXCEPTION_POINTERS *pExceptionInfo, // the pExceptionInfo passed to a filter function. PVOID pParam); -#ifdef FEATURE_CORRUPTING_EXCEPTIONS -// ----------------------------------------------------------------------- -// Support for Corrupted State Exceptions -// ----------------------------------------------------------------------- -#ifndef HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE -#define HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE "System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptionsAttribute" -#endif // HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE - -#ifndef HIGHEST_MAJOR_VERSION_OF_PREV4_RUNTIME -#define HIGHEST_MAJOR_VERSION_OF_PREV4_RUNTIME 2 -#endif // HIGHEST_MAJOR_VERSION_OF_PREV4_RUNTIME - -// This helper class contains static method to support working with Corrupted State Exceptions, -// including checking if a method can handle it or not, copy state across throwables, etc. -class CEHelper -{ - BOOL static IsMethodInPreV4Assembly(PTR_MethodDesc pMethodDesc); - BOOL static CanMethodHandleCE(PTR_MethodDesc pMethodDesc, CorruptionSeverity severity, BOOL fCalculateSecurityInfo = TRUE); - -public: - BOOL static CanMethodHandleException(CorruptionSeverity severity, PTR_MethodDesc pMethodDesc, BOOL fCalculateSecurityInfo = TRUE); - BOOL static CanIDispatchTargetHandleException(); - BOOL static IsProcessCorruptedStateException(DWORD dwExceptionCode, BOOL fCheckForSO = TRUE); - BOOL static IsProcessCorruptedStateException(OBJECTREF oThrowable); - BOOL static IsLastActiveExceptionCorrupting(BOOL fMarkForReuseIfCorrupting = FALSE); - BOOL static ShouldTreatActiveExceptionAsNonCorrupting(); - void static MarkLastActiveExceptionCorruptionSeverityForReraiseReuse(); - void static SetupCorruptionSeverityForActiveException(BOOL fIsRethrownException, BOOL fIsNestedException, BOOL fShouldTreatExceptionAsNonCorrupting = FALSE); -#ifdef FEATURE_EH_FUNCLETS - typedef DPTR(class ExceptionTracker) PTR_ExceptionTracker; - void static SetupCorruptionSeverityForActiveExceptionInUnwindPass(Thread *pCurThread, PTR_ExceptionTracker pEHTracker, BOOL fIsFirstPass, - DWORD dwExceptionCode); -#endif // FEATURE_EH_FUNCLETS - void static ResetLastActiveCorruptionSeverityPostCatchHandler(Thread *pThread); -}; - -#endif // FEATURE_CORRUPTING_EXCEPTIONS - #ifndef DACCESS_COMPILE // exception filter invoked for unhandled exceptions on the entry point thread (thread 0) LONG EntryPointFilter(PEXCEPTION_POINTERS pExceptionInfo, PVOID _pData); @@ -878,36 +816,17 @@ class ExceptionNotifications OBJECTREF *pOutEventArgs, OBJECTREF *pThrowable); void static DeliverNotificationInternal(ExceptionNotificationHandlerType notificationType, - OBJECTREF *pThrowable -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , CorruptionSeverity severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); - - void static InvokeNotificationDelegate(ExceptionNotificationHandlerType notificationType, OBJECTREF *pDelegate, OBJECTREF *pEventArgs, - OBJECTREF *pAppDomain -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , CorruptionSeverity severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); + OBJECTREF *pThrowable); public: - BOOL static CanDeliverNotificationToCurrentAppDomain(ExceptionNotificationHandlerType notificationType); + void static DeliverExceptionNotification(ExceptionNotificationHandlerType notificationType, OBJECTREF *pDelegate, OBJECTREF *pEventArgs, + OBJECTREF *pAppDomain); - void static DeliverNotification(ExceptionNotificationHandlerType notificationType, - OBJECTREF *pThrowable -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , CorruptionSeverity severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); + BOOL static CanDeliverNotificationToCurrentAppDomain(ExceptionNotificationHandlerType notificationType); -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - BOOL static CanDelegateBeInvokedForException(OBJECTREF *pDelegate, CorruptionSeverity severity); -#endif // FEATURE_CORRUPTING_EXCEPTIONS + void static DeliverNotification(ExceptionNotificationHandlerType notificationType, OBJECTREF *pThrowable); public: - void static DeliverExceptionNotification(ExceptionNotificationHandlerType notificationType, OBJECTREF *pDelegate, - OBJECTREF *pAppDomain, OBJECTREF *pEventArgs); void static DeliverFirstChanceNotification(); }; diff --git a/src/coreclr/src/vm/exceptionhandling.cpp b/src/coreclr/src/vm/exceptionhandling.cpp index bdf1bda9a6c7ca..c655fe8ded92c2 100644 --- a/src/coreclr/src/vm/exceptionhandling.cpp +++ b/src/coreclr/src/vm/exceptionhandling.cpp @@ -890,7 +890,7 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord // We should be in cooperative mode if we are going to handle the SO. // We track SO state for the thread. - EEPolicy::HandleStackOverflow(SOD_ManagedFrameHandler, (void*)MemoryStackFp); + EEPolicy::HandleStackOverflow(); FastInterlockAnd (&pThread->m_fPreemptiveGCDisabled, 0); return ExceptionContinueSearch; } @@ -1006,23 +1006,13 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord !(dwExceptionFlags & EXCEPTION_UNWINDING), &STState); -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // Only setup the Corruption Severity in the first pass if (!(dwExceptionFlags & EXCEPTION_UNWINDING)) { // Switch to COOP mode GCX_COOP(); - if (pTracker && pTracker->GetThrowable() != NULL) - { - // Setup the state in current exception tracker indicating the corruption severity - // of the active exception. - CEHelper::SetupCorruptionSeverityForActiveException((STState == ExceptionTracker::STS_FirstRethrowFrame), (pTracker->GetPreviousExceptionTracker() != NULL), - CEHelper::ShouldTreatActiveExceptionAsNonCorrupting()); - } - // Failfast if exception indicates corrupted process state - if (pTracker->GetCorruptionSeverity() == ProcessCorrupting) + if (IsProcessCorruptedStateException(pExceptionRecord->ExceptionCode, pTracker->GetThrowable())) { OBJECTREF oThrowable = NULL; SString message; @@ -1045,50 +1035,6 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(pExceptionRecord->ExceptionCode, (LPCWSTR)message); } } -#endif // FEATURE_CORRUPTING_EXCEPTIONS - - { - // Switch to COOP mode since we are going to work - // with throwable - GCX_COOP(); - if (pTracker->GetThrowable() != NULL) - { - BOOL fIsThrownExceptionAV = FALSE; - OBJECTREF oThrowable = NULL; - GCPROTECT_BEGIN(oThrowable); - oThrowable = pTracker->GetThrowable(); - - // Check if we are dealing with AV or not and if we are, - // ensure that this is a real AV and not managed AV exception - if ((pExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) && - (MscorlibBinder::GetException(kAccessViolationException) == oThrowable->GetMethodTable())) - { - // Its an AV - set the flag - fIsThrownExceptionAV = TRUE; - } - - GCPROTECT_END(); - - // Did we get an AV? - if (fIsThrownExceptionAV == TRUE) - { - // Get the escalation policy action for handling AV - EPolicyAction actionAV = GetEEPolicy()->GetActionOnFailure(FAIL_AccessViolation); - - // Valid actions are: eNoAction (default behviour) or eRudeExitProcess - _ASSERTE(((actionAV == eNoAction) || (actionAV == eRudeExitProcess))); - if (actionAV == eRudeExitProcess) - { - LOG((LF_EH, LL_INFO100, "ProcessCLRException: AccessViolation handler found and doing RudeExitProcess due to escalation policy (eRudeExitProcess)\n")); - - // EEPolicy::HandleFatalError will help us RudeExit the process. - // RudeExitProcess due to AV is to prevent a security risk - we are ripping - // at the boundary, without looking for the handlers. - EEPOLICY_HANDLE_FATAL_ERROR(COR_E_SECURITY); - } - } - } - } #ifndef TARGET_UNIX // Watson is on Windows only // Setup bucketing details for nested exceptions (rethrow and non-rethrow) only if we are in the first pass @@ -1266,7 +1212,7 @@ lExit: ; GcInfoDecoder gcInfoDecoder(codeInfo.GetGCInfoToken(), DECODE_REVERSE_PINVOKE_VAR); if (gcInfoDecoder.GetReversePInvokeFrameStackSlot() != NO_REVERSE_PINVOKE_FRAME) { - // Exception is being propagated from a native callable method into its native caller. + // Exception is being propagated from a method marked UnmanagedCallersOnlyAttribute into its native caller. // The explicit frame chain needs to be unwound at this boundary. bool fIsSO = pExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW; CleanUpForSecondPass(pThread, fIsSO, (void*)MemoryStackFp, (void*)MemoryStackFp); @@ -2489,25 +2435,6 @@ CLRUnwindStatus ExceptionTracker::ProcessManagedCallFrame( if (fIsILStub && !fIsFunclet) // only make this callback on the main method body of IL stubs pUserMDForILStub = GetUserMethodForILStub(pThread, sf.SP, pMD, &pILStubFrame); -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - BOOL fCanMethodHandleException = TRUE; - CorruptionSeverity currentSeverity = NotCorrupting; - { - // Switch to COOP mode since we are going to request throwable - GCX_COOP(); - - // We must defer to the MethodDesc of the user method instead of the IL stub - // itself because the user can specify the policy on a per-method basis and - // that won't be reflected via the IL stub's MethodDesc. - MethodDesc * pMDWithCEAttribute = (pUserMDForILStub != NULL) ? pUserMDForILStub : pMD; - - // Check if the exception can be delivered to the method? It will check if the exception - // is a CE or not. If it is, it will check if the method can process it or not. - currentSeverity = pThread->GetExceptionState()->GetCurrentExceptionTracker()->GetCorruptionSeverity(); - fCanMethodHandleException = CEHelper::CanMethodHandleException(currentSeverity, pMDWithCEAttribute); - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS - // Doing rude abort. Skip all non-constrained execution region code. // When rude abort is initiated, we cannot intercept any exceptions. if (pThread->IsRudeAbortInitiated()) @@ -2716,27 +2643,7 @@ CLRUnwindStatus ExceptionTracker::ProcessManagedCallFrame( const METHODTOKEN& MethToken = pcfThisFrame->GetMethodToken(); EH_CLAUSE_ENUMERATOR EnumState; - unsigned EHCount; - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // The method cannot handle the exception (e.g. cannot handle the CE), then simply bail out - // without examining the EH clauses in it. - if (!fCanMethodHandleException) - { - LOG((LF_EH, LL_INFO100, "ProcessManagedCallFrame - CEHelper decided not to look for exception handlers in the method(MD:%p).\n", pMD)); - - // Set the flag to skip this frame since the CE cannot be delivered - _ASSERTE(currentSeverity == ProcessCorrupting); - - // Force EHClause count to be zero - EHCount = 0; - } - else -#endif // FEATURE_CORRUPTING_EXCEPTIONS - { - EHCount = pJitMan->InitializeEHEnumeration(MethToken, &EnumState); - } - + unsigned EHCount = pJitMan->InitializeEHEnumeration(MethToken, &EnumState); if (!fIsFirstPass) { @@ -4004,20 +3911,6 @@ ExceptionTracker* ExceptionTracker::GetOrCreateTracker( } } } - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - if (fCreateNewTracker) - { - // Exception tracker should be in the 2nd pass right now - _ASSERTE(!pTracker->IsInFirstPass()); - - // The corruption severity of a newly created tracker is NotSet - _ASSERTE(pTracker->GetCorruptionSeverity() == NotSet); - - // See comment in CEHelper::SetupCorruptionSeverityForActiveExceptionInUnwindPass for details - CEHelper::SetupCorruptionSeverityForActiveExceptionInUnwindPass(pThread, pTracker, FALSE, pExceptionRecord->ExceptionCode); - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS } _ASSERTE(pTracker->m_pLimitFrame >= pThread->GetFrame()); @@ -4670,13 +4563,13 @@ VOID DECLSPEC_NORETURN UnwindManagedExceptionPass1(PAL_SEHException& ex, CONTEXT if (gcInfoDecoder.GetReversePInvokeFrameStackSlot() != NO_REVERSE_PINVOKE_FRAME) { - // Propagating exception from a method marked by NativeCallable attribute is prohibited on Unix + // Propagating exception from a method marked by UnmanagedCallersOnly attribute is prohibited on Unix if (!GetThread()->HasThreadStateNC(Thread::TSNC_ProcessedUnhandledException)) { LONG disposition = InternalUnhandledExceptionFilter_Worker(&ex.ExceptionPointers); _ASSERTE(disposition == EXCEPTION_CONTINUE_SEARCH); } - TerminateProcess(GetCurrentProcess(), 1); + CrashDumpAndTerminateProcess(1); UNREACHABLE(); } #endif // USE_GC_INFO_DECODER @@ -4684,14 +4577,11 @@ VOID DECLSPEC_NORETURN UnwindManagedExceptionPass1(PAL_SEHException& ex, CONTEXT // Check whether we are crossing managed-to-native boundary while (!ExecutionManager::IsManagedCode(controlPc)) { -#ifdef VSD_STUB_CAN_THROW_AV - if (IsIPinVirtualStub(controlPc)) + if (AdjustContextForVirtualStub(NULL, frameContext)) { - AdjustContextForVirtualStub(NULL, frameContext); controlPc = GetIP(frameContext); break; } -#endif // VSD_STUB_CAN_THROW_AV #ifdef FEATURE_WRITEBARRIER_COPY if (IsIPInWriteBarrierCodeCopy(controlPc)) @@ -4722,7 +4612,7 @@ VOID DECLSPEC_NORETURN UnwindManagedExceptionPass1(PAL_SEHException& ex, CONTEXT LONG disposition = InternalUnhandledExceptionFilter_Worker(&ex.ExceptionPointers); _ASSERTE(disposition == EXCEPTION_CONTINUE_SEARCH); } - TerminateProcess(GetCurrentProcess(), 1); + CrashDumpAndTerminateProcess(1); UNREACHABLE(); } @@ -4822,20 +4712,6 @@ VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHar ThreadExceptionState * pCurTES = pCurThread->GetExceptionState(); _ASSERTE(pCurTES != NULL); - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - ExceptionTracker* pEHTracker = pCurTES->GetCurrentExceptionTracker(); - if (pEHTracker == NULL) - { - CorruptionSeverity severity = NotCorrupting; - if (CEHelper::IsProcessCorruptedStateException(ex.GetExceptionRecord()->ExceptionCode)) - { - severity = ProcessCorrupting; - } - - pCurTES->SetLastActiveExceptionCorruptionSeverity(severity); - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS } throw std::move(ex); @@ -5200,10 +5076,9 @@ BOOL IsSafeToHandleHardwareException(PCONTEXT contextRecord, PEXCEPTION_RECORD e return g_fEEStarted && ( exceptionRecord->ExceptionCode == STATUS_BREAKPOINT || exceptionRecord->ExceptionCode == STATUS_SINGLE_STEP || + exceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW || (IsSafeToCallExecutionManager() && ExecutionManager::IsManagedCode(controlPc)) || -#ifdef VSD_STUB_CAN_THROW_AV IsIPinVirtualStub(controlPc) || // access violation comes from DispatchStub of Interface call -#endif // VSD_STUB_CAN_THROW_AV IsIPInMarkedJitHelper(controlPc)); } @@ -5237,6 +5112,7 @@ BOOL HandleHardwareException(PAL_SEHException* ex) if (ex->GetExceptionRecord()->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { GetThread()->SetExecutingOnAltStack(); + Thread::VirtualUnwindToFirstManagedCallFrame(ex->GetContextRecord()); EEPolicy::HandleFatalStackOverflow(&ex->ExceptionPointers, FALSE); UNREACHABLE(); } @@ -5292,12 +5168,10 @@ BOOL HandleHardwareException(PAL_SEHException* ex) PAL_VirtualUnwind(ex->GetContextRecord(), NULL); ex->GetExceptionRecord()->ExceptionAddress = (PVOID)GetIP(ex->GetContextRecord()); } -#ifdef VSD_STUB_CAN_THROW_AV - else if (IsIPinVirtualStub(controlPc)) + else { AdjustContextForVirtualStub(ex->GetExceptionRecord(), ex->GetContextRecord()); } -#endif // VSD_STUB_CAN_THROW_AV fef.InitAndLink(ex->GetContextRecord()); } diff --git a/src/coreclr/src/vm/exceptionhandling.h b/src/coreclr/src/vm/exceptionhandling.h index 2f56f20340e775..dfdaf49726edcb 100644 --- a/src/coreclr/src/vm/exceptionhandling.h +++ b/src/coreclr/src/vm/exceptionhandling.h @@ -70,11 +70,6 @@ class ExceptionTracker m_WatsonBucketTracker.Init(); #endif // !TARGET_UNIX -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // Initialize the default exception severity to NotCorrupting - m_CorruptionSeverity = NotSet; -#endif // FEATURE_CORRUPTING_EXCEPTIONS - // By default, mark the tracker as not having delivered the first // chance exception notification m_fDeliveredFirstChanceNotification = FALSE; @@ -130,11 +125,6 @@ class ExceptionTracker m_WatsonBucketTracker.Init(); #endif // !TARGET_UNIX -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // Initialize the default exception severity to NotCorrupting - m_CorruptionSeverity = NotSet; -#endif // FEATURE_CORRUPTING_EXCEPTIONS - // By default, mark the tracker as not having delivered the first // chance exception notification m_fDeliveredFirstChanceNotification = FALSE; @@ -586,25 +576,6 @@ class ExceptionTracker } #endif // !TARGET_UNIX -#ifdef FEATURE_CORRUPTING_EXCEPTIONS -private: - CorruptionSeverity m_CorruptionSeverity; -public: - inline CorruptionSeverity GetCorruptionSeverity() - { - LIMITED_METHOD_CONTRACT; - - return (CorruptionSeverity)GET_CORRUPTION_SEVERITY(m_CorruptionSeverity); - } - - inline void SetCorruptionSeverity(CorruptionSeverity severityToSet) - { - LIMITED_METHOD_CONTRACT; - - m_CorruptionSeverity = severityToSet; - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS - private: BOOL m_fDeliveredFirstChanceNotification; diff --git a/src/coreclr/src/vm/exceptmacros.h b/src/coreclr/src/vm/exceptmacros.h index 38c20de0457f91..31fb8c73cdf713 100644 --- a/src/coreclr/src/vm/exceptmacros.h +++ b/src/coreclr/src/vm/exceptmacros.h @@ -246,38 +246,6 @@ LONG WINAPI CLRVectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo); // Actual UEF worker prototype for use by GCUnhandledExceptionFilter. extern LONG InternalUnhandledExceptionFilter_Worker(PEXCEPTION_POINTERS pExceptionInfo); -//========================================================================== -// Installs a handler to unwind exception frames, but not catch the exception -//========================================================================== - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS -// ----------------------------------------------------------------------- -// Support for Corrupted State Exceptions -// ----------------------------------------------------------------------- -// This enumeration defines the corruption severity of an exception and -// whether it should be reused for the next exception thrown or not. -enum CorruptionSeverity -{ - UseLast = 0x0, // When specified, the last active corruption severity from TES should be used - NotSet = 0x1, // Corruption Severity has not been set - this is the default/reset value - NotCorrupting = 0x2, // Indicates exception is not corrupting - ProcessCorrupting = 0x4, // Indicates exception represents process corrupted state - ReuseForReraise = 0x2000 // Indicates that the corruption severity should be reused for the next exception thrown, - // provided its not nested and isnt a rethrow. This flag is used typically for propagation of - // severity across boundaries like Reflection invocation, AD transition etc. -}; - -#define GET_CORRUPTION_SEVERITY(severity) (((severity) & (~ReuseForReraise))) -#define CAN_REUSE_CORRUPTION_SEVERITY(severity) (((severity) & ReuseForReraise) == ReuseForReraise) - -#endif // FEATURE_CORRUPTING_EXCEPTIONS - -VOID DECLSPEC_NORETURN RaiseTheException(OBJECTREF throwable, BOOL rethrow -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , CorruptionSeverity severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS -); - VOID DECLSPEC_NORETURN RaiseTheExceptionInternalOnly(OBJECTREF throwable, BOOL rethrow, BOOL fForStackOverflow = FALSE); #if defined(DACCESS_COMPILE) || defined(CROSSGEN_COMPILE) @@ -326,7 +294,7 @@ VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHar LONG disposition = InternalUnhandledExceptionFilter_Worker(&ex.ExceptionPointers); \ _ASSERTE(disposition == EXCEPTION_CONTINUE_SEARCH); \ } \ - TerminateProcess(GetCurrentProcess(), 1); \ + CrashDumpAndTerminateProcess(1); \ UNREACHABLE(); \ } diff --git a/src/coreclr/src/vm/exinfo.cpp b/src/coreclr/src/vm/exinfo.cpp index 8a9ed80d257f5c..58e353a0160167 100644 --- a/src/coreclr/src/vm/exinfo.cpp +++ b/src/coreclr/src/vm/exinfo.cpp @@ -110,11 +110,6 @@ void ExInfo::Init() DestroyExceptionHandle(); m_hThrowable = NULL; -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // Initialize the default exception severity to NotCorrupting - m_CorruptionSeverity = NotSet; -#endif // FEATURE_CORRUPTING_EXCEPTIONS - // By default, mark the tracker as not having delivered the first // chance exception notification m_fDeliveredFirstChanceNotification = FALSE; diff --git a/src/coreclr/src/vm/exinfo.h b/src/coreclr/src/vm/exinfo.h index 5e57e0ce77ae88..332d2248342abe 100644 --- a/src/coreclr/src/vm/exinfo.h +++ b/src/coreclr/src/vm/exinfo.h @@ -90,25 +90,6 @@ class ExInfo } #endif -#ifdef FEATURE_CORRUPTING_EXCEPTIONS -private: - CorruptionSeverity m_CorruptionSeverity; -public: - inline CorruptionSeverity GetCorruptionSeverity() - { - LIMITED_METHOD_CONTRACT; - - return (CorruptionSeverity)GET_CORRUPTION_SEVERITY(m_CorruptionSeverity); - } - - inline void SetCorruptionSeverity(CorruptionSeverity severityToSet) - { - LIMITED_METHOD_CONTRACT; - - m_CorruptionSeverity = severityToSet; - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS - private: BOOL m_fDeliveredFirstChanceNotification; public: diff --git a/src/coreclr/src/vm/exstate.cpp b/src/coreclr/src/vm/exstate.cpp index c2c2c0adb63f4a..db238df8bafe1b 100644 --- a/src/coreclr/src/vm/exstate.cpp +++ b/src/coreclr/src/vm/exstate.cpp @@ -43,13 +43,6 @@ ThreadExceptionState::ThreadExceptionState() // Init the UE Watson BucketTracker m_UEWatsonBucketTracker.Init(); #endif // !TARGET_UNIX - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // Initialize the default exception severity to NotCorrupting - m_LastActiveExceptionCorruptionSeverity = NotSet; - m_fCanReflectionTargetHandleException = FALSE; -#endif // FEATURE_CORRUPTING_EXCEPTIONS - } ThreadExceptionState::~ThreadExceptionState() diff --git a/src/coreclr/src/vm/exstate.h b/src/coreclr/src/vm/exstate.h index 1ea8790a11dc10..e3971d356b5a7a 100644 --- a/src/coreclr/src/vm/exstate.h +++ b/src/coreclr/src/vm/exstate.h @@ -162,56 +162,6 @@ class ThreadExceptionState } #endif -#ifdef FEATURE_CORRUPTING_EXCEPTIONS -private: - CorruptionSeverity m_LastActiveExceptionCorruptionSeverity; - BOOL m_fCanReflectionTargetHandleException; - -public: - // Returns the corruption severity of the last active exception - inline CorruptionSeverity GetLastActiveExceptionCorruptionSeverity() - { - LIMITED_METHOD_CONTRACT; - - return (CorruptionSeverity)GET_CORRUPTION_SEVERITY(m_LastActiveExceptionCorruptionSeverity); - } - - // Set the corruption severity of the last active exception - inline void SetLastActiveExceptionCorruptionSeverity(CorruptionSeverity severityToSet) - { - LIMITED_METHOD_CONTRACT; - - m_LastActiveExceptionCorruptionSeverity = severityToSet; - } - - // Returns a bool indicating if the last active exception's corruption severity should - // be used when exception is reraised (e.g. Reflection Invocation, AD transition, etc) - inline BOOL ShouldLastActiveExceptionCorruptionSeverityBeReused() - { - LIMITED_METHOD_CONTRACT; - - return CAN_REUSE_CORRUPTION_SEVERITY(m_LastActiveExceptionCorruptionSeverity); - } - - // Returns a BOOL to indicate if reflection target can handle CSE or not. - // This is used in DispatchInfo::CanIDispatchTargetHandleException. - inline BOOL CanReflectionTargetHandleException() - { - LIMITED_METHOD_CONTRACT; - - return m_fCanReflectionTargetHandleException; - } - - // Sets a BOOL indicate if the Reflection invocation target can handle exception or not. - // Used in ReflectionInvocation.cpp. - inline void SetCanReflectionTargetHandleException(BOOL fCanReflectionTargetHandleException) - { - LIMITED_METHOD_CONTRACT; - - m_fCanReflectionTargetHandleException = fCanReflectionTargetHandleException; - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS - private: ThreadExceptionFlag m_flag; diff --git a/src/coreclr/src/vm/finalizerthread.cpp b/src/coreclr/src/vm/finalizerthread.cpp index 678f849dde8504..979f05e1e43b1a 100644 --- a/src/coreclr/src/vm/finalizerthread.cpp +++ b/src/coreclr/src/vm/finalizerthread.cpp @@ -392,11 +392,7 @@ DWORD WINAPI FinalizerThread::FinalizerThreadStart(void *args) if (s_FinalizerThreadOK) { INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP; - -#ifdef _DEBUG // The only purpose of this try/finally is to trigger an assertion - EE_TRY_FOR_FINALLY(void *, unused, NULL) { -#endif GetFinalizerThread()->SetBackground(TRUE); EnsureYieldProcessorNormalizedInitialized(); @@ -421,20 +417,7 @@ DWORD WINAPI FinalizerThread::FinalizerThreadStart(void *args) _ASSERTE(GetFinalizerThread()->PreemptiveGCDisabled()); hEventFinalizerToShutDown->Set(); - -#ifdef _DEBUG // The only purpose of this try/finally is to trigger an assertion } - EE_FINALLY - { - // We can have exception to reach here if policy tells us to - // let exception go on finalizer thread. - // - if (GOT_EXCEPTION() && SwallowUnhandledExceptions()) - _ASSERTE(!"Exception in the finalizer thread!"); - - } - EE_END_FINALLY; -#endif UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP; } diff --git a/src/coreclr/src/vm/frames.h b/src/coreclr/src/vm/frames.h index 1976d7397fe26c..3437030705f18d 100644 --- a/src/coreclr/src/vm/frames.h +++ b/src/coreclr/src/vm/frames.h @@ -108,9 +108,10 @@ // | +-UMThkCallFrame - this frame represents an unmanaged->managed // | transition through N/Direct #endif -// | +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) // +-TailCallFrame - padding for tailcalls // | +#endif // +-ProtectByRefsFrame // | // +-ProtectValueClassFrame @@ -242,7 +243,9 @@ FRAME_TYPE_NAME(DebuggerU2MCatchHandlerFrame) FRAME_TYPE_NAME(UMThkCallFrame) #endif FRAME_TYPE_NAME(InlinedCallFrame) +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) FRAME_TYPE_NAME(TailCallFrame) +#endif FRAME_TYPE_NAME(ExceptionFilterFrame) #if defined(_DEBUG) FRAME_TYPE_NAME(AssumeByrefFromJITStack) @@ -739,11 +742,7 @@ class Frame : public FrameBase friend class StackFrameIterator; friend class TailCallFrame; friend class AppDomain; - friend VOID RealCOMPlusThrow(OBJECTREF -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , CorruptionSeverity severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); + friend VOID RealCOMPlusThrow(OBJECTREF); friend FCDECL0(VOID, JIT_StressGC); #ifdef _DEBUG friend LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo); @@ -2785,7 +2784,7 @@ class UMThkCallFrame : public UnmanagedToManagedFrame }; #endif // TARGET_X86 && !TARGET_UNIX -// Frame for the Reverse PInvoke (i.e. NativeCallableAttribute). +// Frame for the Reverse PInvoke (i.e. UnmanagedCallersOnlyAttribute). struct ReversePInvokeFrame { Thread* currentThread; @@ -3006,8 +3005,8 @@ class InlinedCallFrame : public Frame //bool isLegalManagedCodeCaller(TADDR retAddr); bool isRetAddr(TADDR retAddr, TADDR* whereCalled); +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) //------------------------------------------------------------------------ -#ifdef TARGET_X86 // This frame is used as padding for virtual stub dispatch tailcalls. // When A calls B via virtual stub dispatch, the stub dispatch stub resolves // the target code for B and jumps to it. If A wants to do a tail call, @@ -3024,69 +3023,18 @@ bool isRetAddr(TADDR retAddr, TADDR* whereCalled); // We could eliminate TailCallFrame if we factor the VSD stub to return // the target code address. This is currently not a very important scenario // as tail calls on interface calls are uncommon. -#else -// This frame is used as padding for tailcalls which require more space -// than the caller has in it's incoming argument space. -// To do a tail call from A to B, A calls JIT_TailCall, which unwinds A's frame -// and sets up a TailCallFrame and the arguments. It then jumps to B. -// If B also does a tail call, then we reuse the -// existing TailCallFrame instead of setting up a second one. -// -// This is also used whenever value types that aren't enregisterable are -// passed by value instead of ref. This is currently not a very important -// scenario as tail calls are uncommon. -#endif //------------------------------------------------------------------------ class TailCallFrame : public Frame { VPTR_VTABLE_CLASS(TailCallFrame, Frame) -#if defined(TARGET_X86) TADDR m_CallerAddress; // the address the tailcall was initiated from CalleeSavedRegisters m_regs; // callee saved registers - the stack walk assumes that all non-JIT frames have them TADDR m_ReturnAddress; // the return address of the tailcall -#elif defined(TARGET_AMD64) - TADDR m_pGCLayout; - TADDR m_padding; // code:StubLinkerCPU::CreateTailCallCopyArgsThunk expects the size of TailCallFrame to be 16-byte aligned - CalleeSavedRegisters m_calleeSavedRegisters; - TADDR m_ReturnAddress; -#elif defined(TARGET_ARM) - union { - CalleeSavedRegisters m_calleeSavedRegisters; - // alias saved link register as m_ReturnAddress - struct { - INT32 r4, r5, r6, r7, r8, r9, r10; - INT32 r11; - TADDR m_ReturnAddress; - }; - }; -#else - TADDR m_ReturnAddress; -#endif public: -#ifndef CROSSGEN_COMPILE -#if !defined(TARGET_X86) - -#ifndef DACCESS_COMPILE - TailCallFrame(T_CONTEXT * pContext, Thread * pThread) - { - InitFromContext(pContext); - m_Next = pThread->GetFrame(); - } - - void InitFromContext(T_CONTEXT * pContext); - - // Architecture-specific method to initialize a CONTEXT record as if the first - // part of the TailCallHelperStub had executed - static TailCallFrame * AdjustContextForTailCallHelperStub(_CONTEXT * pContext, size_t cbNewArgArea, Thread * pThread); -#endif - - static TailCallFrame * GetFrameFromContext(CONTEXT * pContext); -#endif // !TARGET_X86 - -#if defined(TARGET_X86) +#ifndef CROSSGEN_COMPILE static TailCallFrame* FindTailCallFrame(Frame* pFrame) { LIMITED_METHOD_CONTRACT; @@ -3101,7 +3049,6 @@ class TailCallFrame : public Frame LIMITED_METHOD_CONTRACT; return m_CallerAddress; } -#endif // TARGET_X86 virtual TADDR GetReturnAddressPtr() { @@ -3117,26 +3064,12 @@ class TailCallFrame : public Frame virtual void UpdateRegDisplay(const PREGDISPLAY pRD); #endif // !CROSSGEN_COMPILE -#ifdef TARGET_AMD64 - void SetGCLayout(TADDR pGCLayout) - { - LIMITED_METHOD_CONTRACT; - m_pGCLayout = pGCLayout; - } - - virtual void GcScanRoots(promote_func *fn, ScanContext* sc); -#else - void SetGCLayout(TADDR pGCLayout) - { - LIMITED_METHOD_CONTRACT; - _ASSERTE(pGCLayout == NULL); - } -#endif private: // Keep as last entry in class DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(TailCallFrame) }; +#endif // TARGET_X86 && !UNIX_X86_ABI //------------------------------------------------------------------------ // ExceptionFilterFrame is a small frame whose only purpose in @@ -3296,10 +3229,6 @@ class FrameWithCookie m_gsCookie(GetProcessGSCookie()), m_frame(pDebuggerEval, returnAddress, showFrame) { WRAPPER_NO_CONTRACT; } #endif // DEBUGGING_SUPPORTED - // TailCallFrame - FrameWithCookie(T_CONTEXT * pContext, Thread *thread) : - m_gsCookie(GetProcessGSCookie()), m_frame(pContext, thread) { WRAPPER_NO_CONTRACT; } - #ifndef DACCESS_COMPILE // GSCookie for HelperMethodFrames is initialized in a common HelperMethodFrame init method diff --git a/src/coreclr/src/vm/frameworkexceptionloader.cpp b/src/coreclr/src/vm/frameworkexceptionloader.cpp index 72024f5d403c58..72b1f9341dad25 100644 --- a/src/coreclr/src/vm/frameworkexceptionloader.cpp +++ b/src/coreclr/src/vm/frameworkexceptionloader.cpp @@ -16,16 +16,14 @@ struct ExceptionLocationData LPCUTF8 Namespace; LPCUTF8 Name; LPCUTF8 AssemblySimpleName; - LPCUTF8 PublicKeyToken; }; static const ExceptionLocationData g_ExceptionLocationData[] = { #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) -#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) { ns, PTR_CSTR((TADDR) # reKind), assemblySimpleName, publicKeyToken }, +#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, bHRformessage, ...) { ns, PTR_CSTR((TADDR) # reKind), assemblySimpleName }, #include "rexcep.h" - {NULL, NULL, NULL, NULL} // On Silverlight, this table may be empty. This dummy entry allows us to compile. }; @@ -39,7 +37,7 @@ MethodTable* FrameworkExceptionLoader::GetException(RuntimeExceptionKind kind) GC_TRIGGERS; PRECONDITION(kind > kLastExceptionInMscorlib); - PRECONDITION(kind - (kLastExceptionInMscorlib + 1) < COUNTOF(g_ExceptionLocationData) - 1); + PRECONDITION(kind - (kLastExceptionInMscorlib + 1) < COUNTOF(g_ExceptionLocationData)); } CONTRACTL_END; @@ -48,7 +46,7 @@ MethodTable* FrameworkExceptionLoader::GetException(RuntimeExceptionKind kind) // Note that some assemblies, like System.Runtime.WindowsRuntime, might not be installed on pre-Windows 8 machines. int index = kind - (kLastExceptionInMscorlib + 1); ExceptionLocationData exData = g_ExceptionLocationData[index]; - _ASSERTE(exData.Name != NULL && exData.AssemblySimpleName != NULL && exData.PublicKeyToken != NULL); // Was the exception defined in mscorlib instead? + _ASSERTE(exData.Name != NULL && exData.AssemblySimpleName != NULL); // Was the exception defined in mscorlib instead? StackSString assemblyQualifiedName; _ASSERTE(exData.Namespace != NULL); // If we need to support stuff in a global namespace, fix this. assemblyQualifiedName.SetUTF8(exData.Namespace); @@ -56,11 +54,6 @@ MethodTable* FrameworkExceptionLoader::GetException(RuntimeExceptionKind kind) assemblyQualifiedName.AppendUTF8(exData.Name); assemblyQualifiedName.AppendUTF8(", "); assemblyQualifiedName.AppendUTF8(exData.AssemblySimpleName); - assemblyQualifiedName.AppendUTF8(", PublicKeyToken="); - assemblyQualifiedName.AppendUTF8(exData.PublicKeyToken); - assemblyQualifiedName.AppendUTF8(", Version="); - assemblyQualifiedName.AppendUTF8(VER_ASSEMBLYVERSION_STR); - assemblyQualifiedName.AppendUTF8(", Culture=neutral"); MethodTable* pMT = NULL; // Loading will either succeed or throw a FileLoadException. Catch & swallow that exception. @@ -95,7 +88,7 @@ void FrameworkExceptionLoader::GetExceptionName(RuntimeExceptionKind kind, SStri MODE_ANY; PRECONDITION(kind > kLastExceptionInMscorlib); - PRECONDITION(kind - (kLastExceptionInMscorlib + 1) < COUNTOF(g_ExceptionLocationData) - 1); + PRECONDITION(kind - (kLastExceptionInMscorlib + 1) < COUNTOF(g_ExceptionLocationData)); } CONTRACTL_END; exceptionName.SetUTF8(g_ExceptionLocationData[kind].Namespace); diff --git a/src/coreclr/src/vm/gccover.cpp b/src/coreclr/src/vm/gccover.cpp index 96cd53ce2c3f05..9a985e6a421829 100644 --- a/src/coreclr/src/vm/gccover.cpp +++ b/src/coreclr/src/vm/gccover.cpp @@ -1403,10 +1403,10 @@ BOOL OnGcCoverageInterrupt(PCONTEXT regs) if (!pThread) { // No thread at the moment so we aren't doing coverage for this function. - // This should only occur for methods with the NativeCallableAttribute, + // This should only occur for methods with the UnmanagedCallersOnlyAttribute, // where the call could be coming from a thread unknown to the CLR and // we haven't created a thread yet - see PreStubWorker_Preemptive(). - _ASSERTE(pMD->HasNativeCallableAttribute()); + _ASSERTE(pMD->HasUnmanagedCallersOnlyAttribute()); RemoveGcCoverageInterrupt(instrPtr, savedInstrPtr); return TRUE; } diff --git a/src/coreclr/src/vm/gcenv.ee.cpp b/src/coreclr/src/vm/gcenv.ee.cpp index 42a07c2cdb4c0f..7bb9fdde70a612 100644 --- a/src/coreclr/src/vm/gcenv.ee.cpp +++ b/src/coreclr/src/vm/gcenv.ee.cpp @@ -11,6 +11,8 @@ * */ +#include "gcrefmap.h" + void GCToEEInterface::SuspendEE(SUSPEND_REASON reason) { WRAPPER_NO_CONTRACT; @@ -154,6 +156,57 @@ static void ScanStackRoots(Thread * pThread, promote_func* fn, ScanContext* sc) } } +static void ScanTailCallArgBufferRoots(Thread* pThread, promote_func* fn, ScanContext* sc) +{ + void* gcDesc; + char* argBuffer = pThread->GetTailCallTls()->GetArgBuffer(&gcDesc); + if (gcDesc == NULL) + return; + + GCRefMapDecoder decoder(static_cast(gcDesc)); + while (!decoder.AtEnd()) + { + int pos = decoder.CurrentPos(); + int token = decoder.ReadToken(); + + PTR_TADDR ppObj = dac_cast(argBuffer + pos * sizeof(TADDR)); + switch (token) + { + case GCREFMAP_SKIP: + break; + case GCREFMAP_REF: + fn(dac_cast(ppObj), sc, CHECK_APP_DOMAIN); + break; + case GCREFMAP_INTERIOR: + PromoteCarefully(fn, dac_cast(ppObj), sc, GC_CALL_INTERIOR); + break; + case GCREFMAP_METHOD_PARAM: + if (sc->promotion) + { +#ifndef DACCESS_COMPILE + MethodDesc *pMDReal = dac_cast(*ppObj); + if (pMDReal != NULL) + GcReportLoaderAllocator(fn, sc, pMDReal->GetLoaderAllocator()); +#endif + } + break; + case GCREFMAP_TYPE_PARAM: + if (sc->promotion) + { +#ifndef DACCESS_COMPILE + MethodTable *pMTReal = dac_cast(*ppObj); + if (pMTReal != NULL) + GcReportLoaderAllocator(fn, sc, pMTReal->GetLoaderAllocator()); +#endif + } + break; + default: + _ASSERTE(!"Unhandled GCREFMAP token in arg buffer GC desc"); + break; + } + } +} + void GCToEEInterface::GcScanRoots(promote_func* fn, int condemned, int max_gen, ScanContext* sc) { STRESS_LOG1(LF_GCROOTS, LL_INFO10, "GCScan: Promotion Phase = %d\n", sc->promotion); @@ -171,6 +224,7 @@ void GCToEEInterface::GcScanRoots(promote_func* fn, int condemned, int max_gen, sc->dwEtwRootKind = kEtwGCRootKindStack; #endif // FEATURE_EVENT_TRACE ScanStackRoots(pThread, fn, sc); + ScanTailCallArgBufferRoots(pThread, fn, sc); #ifdef FEATURE_EVENT_TRACE sc->dwEtwRootKind = kEtwGCRootKindOther; #endif // FEATURE_EVENT_TRACE @@ -496,6 +550,7 @@ void GcScanRootsForProfilerAndETW(promote_func* fn, int condemned, int max_gen, sc->dwEtwRootKind = kEtwGCRootKindStack; #endif // FEATURE_EVENT_TRACE ScanStackRoots(pThread, fn, sc); + ScanTailCallArgBufferRoots(pThread, fn, sc); #ifdef FEATURE_EVENT_TRACE sc->dwEtwRootKind = kEtwGCRootKindOther; #endif // FEATURE_EVENT_TRACE @@ -1023,7 +1078,7 @@ MethodTable* GCToEEInterface::GetFreeObjectMethodTable() // longer than these lengths. const size_t MaxConfigKeyLength = 255; -bool GCToEEInterface::GetBooleanConfigValue(const char* key, bool* value) +bool GCToEEInterface::GetBooleanConfigValue(const char* privateKey, const char* publicKey, bool* value) { CONTRACTL { NOTHROW; @@ -1031,32 +1086,26 @@ bool GCToEEInterface::GetBooleanConfigValue(const char* key, bool* value) } CONTRACTL_END; // these configuration values are given to us via startup flags. - if (strcmp(key, "gcServer") == 0) + if (strcmp(privateKey, "gcServer") == 0) { *value = g_heap_type == GC_HEAP_SVR; return true; } - if (strcmp(key, "gcConcurrent") == 0) + if (strcmp(privateKey, "gcConcurrent") == 0) { *value = !!g_pConfig->GetGCconcurrent(); return true; } - if (strcmp(key, "GCRetainVM") == 0) + if (strcmp(privateKey, "GCRetainVM") == 0) { *value = !!g_pConfig->GetGCRetainVM(); return true; } - if (strcmp(key, "GCLargePages") == 0) - { - *value = Configuration::GetKnobBooleanValue(W("System.GC.LargePages"), CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_GCLargePages)); - return true; - } - WCHAR configKey[MaxConfigKeyLength]; - if (MultiByteToWideChar(CP_ACP, 0, key, -1 /* key is null-terminated */, configKey, MaxConfigKeyLength) == 0) + if (MultiByteToWideChar(CP_ACP, 0, privateKey, -1 /* key is null-terminated */, configKey, MaxConfigKeyLength) == 0) { // whatever this is... it's not something we care about. (It was too long, wasn't unicode, etc.) return false; @@ -1069,49 +1118,38 @@ bool GCToEEInterface::GetBooleanConfigValue(const char* key, bool* value) *value = CLRConfig::GetConfigValue(info) != 0; return true; } + else if (publicKey != NULL) + { + if (MultiByteToWideChar(CP_ACP, 0, publicKey, -1 /* key is null-terminated */, configKey, MaxConfigKeyLength) == 0) + { + // whatever this is... it's not something we care about. (It was too long, wasn't unicode, etc.) + return false; + } + if (Configuration::GetKnobStringValue(configKey) != NULL) + { + *value = Configuration::GetKnobBooleanValue(configKey, false); + return true; + } + } return false; } -bool GCToEEInterface::GetIntConfigValue(const char* key, int64_t* value) +bool GCToEEInterface::GetIntConfigValue(const char* privateKey, const char* publicKey, int64_t* value) { CONTRACTL { NOTHROW; GC_NOTRIGGER; } CONTRACTL_END; - if (strcmp(key, "GCSegmentSize") == 0) - { - *value = g_pConfig->GetSegmentSize(); - return true; - } - - if (strcmp(key, "GCgen0size") == 0) - { - *value = g_pConfig->GetGCgen0size(); - return true; - } - - if (strcmp(key, "GCHeapHardLimit") == 0) - { - *value = g_pConfig->GetGCHeapHardLimit(); - return true; - } - - if (strcmp(key, "GCHeapHardLimitPercent") == 0) - { - *value = g_pConfig->GetGCHeapHardLimitPercent(); - return true; - } - - if (strcmp(key, "GCLOHThreshold") == 0) + if (strcmp(privateKey, "GCLOHThreshold") == 0) { *value = g_pConfig->GetGCLOHThreshold(); return true; } WCHAR configKey[MaxConfigKeyLength]; - if (MultiByteToWideChar(CP_ACP, 0, key, -1 /* key is null-terminated */, configKey, MaxConfigKeyLength) == 0) + if (MultiByteToWideChar(CP_ACP, 0, privateKey, -1 /* key is null-terminated */, configKey, MaxConfigKeyLength) == 0) { // whatever this is... it's not something we care about. (It was too long, wasn't unicode, etc.) return false; @@ -1146,11 +1184,24 @@ bool GCToEEInterface::GetIntConfigValue(const char* key, int64_t* value) CLRConfig::FreeConfigString(out); return true; } + else if (publicKey != NULL) + { + if (MultiByteToWideChar(CP_ACP, 0, publicKey, -1 /* key is null-terminated */, configKey, MaxConfigKeyLength) == 0) + { + // whatever this is... it's not something we care about. (It was too long, wasn't unicode, etc.) + return false; + } + if (Configuration::GetKnobStringValue(configKey) != NULL) + { + *value = Configuration::GetKnobULONGLONGValue(configKey, 0); + return true; + } + } return false; } -bool GCToEEInterface::GetStringConfigValue(const char* key, const char** value) +bool GCToEEInterface::GetStringConfigValue(const char* privateKey, const char* publicKey, const char** value) { CONTRACTL { NOTHROW; @@ -1158,18 +1209,30 @@ bool GCToEEInterface::GetStringConfigValue(const char* key, const char** value) } CONTRACTL_END; WCHAR configKey[MaxConfigKeyLength]; - if (MultiByteToWideChar(CP_ACP, 0, key, -1 /* key is null-terminated */, configKey, MaxConfigKeyLength) == 0) + if (MultiByteToWideChar(CP_ACP, 0, privateKey, -1 /* key is null-terminated */, configKey, MaxConfigKeyLength) == 0) { // whatever this is... it's not something we care about. (It was too long, wasn't unicode, etc.) return false; } CLRConfig::ConfigStringInfo info { configKey, CLRConfig::EEConfig_default }; - LPWSTR out = CLRConfig::GetConfigValue(info); - if (!out) + LPWSTR fromClrConfig = CLRConfig::GetConfigValue(info); + LPCWSTR out = fromClrConfig; + if (out == NULL) { - // config not found - return false; + if (publicKey != NULL) + { + if (MultiByteToWideChar(CP_ACP, 0, publicKey, -1 /* key is null-terminated */, configKey, MaxConfigKeyLength) == 0) + { + // whatever this is... it's not something we care about. (It was too long, wasn't unicode, etc.) + return false; + } + out = Configuration::GetKnobStringValue(configKey); + if (out == NULL) + { + return false; + } + } } int charCount = WideCharToMultiByte(CP_ACP, 0, out, -1 /* out is null-terminated */, NULL, 0, nullptr, nullptr); @@ -1177,7 +1240,10 @@ bool GCToEEInterface::GetStringConfigValue(const char* key, const char** value) { // this should only happen if the config subsystem gives us a string that's not valid // unicode. - CLRConfig::FreeConfigString(out); + if (fromClrConfig) + { + CLRConfig::FreeConfigString(fromClrConfig); + } return false; } @@ -1185,7 +1251,10 @@ bool GCToEEInterface::GetStringConfigValue(const char* key, const char** value) AStringHolder configResult = new (nothrow) char[charCount]; if (!configResult) { - CLRConfig::FreeConfigString(out); + if (fromClrConfig) + { + CLRConfig::FreeConfigString(fromClrConfig); + } return false; } @@ -1195,12 +1264,18 @@ bool GCToEEInterface::GetStringConfigValue(const char* key, const char** value) // this should never happen, the previous call to WideCharToMultiByte that computed the charCount should // have caught all issues. assert(false); - CLRConfig::FreeConfigString(out); + if (fromClrConfig) + { + CLRConfig::FreeConfigString(fromClrConfig); + } return false; } *value = configResult.Extract(); - CLRConfig::FreeConfigString(out); + if (fromClrConfig) + { + CLRConfig::FreeConfigString(fromClrConfig); + } return true; } diff --git a/src/coreclr/src/vm/gcenv.ee.h b/src/coreclr/src/vm/gcenv.ee.h index deec8769053e24..37f9dc9f68c4df 100644 --- a/src/coreclr/src/vm/gcenv.ee.h +++ b/src/coreclr/src/vm/gcenv.ee.h @@ -64,9 +64,9 @@ class GCToEEInterface : public IGCToCLR { void HandleFatalError(unsigned int exitCode); bool EagerFinalized(Object* obj); MethodTable* GetFreeObjectMethodTable(); - bool GetBooleanConfigValue(const char* key, bool* value); - bool GetIntConfigValue(const char* key, int64_t* value); - bool GetStringConfigValue(const char* key, const char** value); + bool GetBooleanConfigValue(const char* privateKey, const char* publicKey, bool* value); + bool GetIntConfigValue(const char* privateKey, const char* publicKey, int64_t* value); + bool GetStringConfigValue(const char* privateKey, const char* publicKey, const char** value); void FreeStringConfigValue(const char* value); bool IsGCThread(); bool WasCurrentThreadCreatedByGC(); diff --git a/src/coreclr/src/vm/gcenv.os.cpp b/src/coreclr/src/vm/gcenv.os.cpp index 6b9e042f04e9b2..e7add3b29e08bb 100644 --- a/src/coreclr/src/vm/gcenv.os.cpp +++ b/src/coreclr/src/vm/gcenv.os.cpp @@ -756,7 +756,7 @@ uint32_t GCToOSInterface::GetCurrentProcessCpuCount() // Return the size of the user-mode portion of the virtual address space of this process. // Return: -// non zero if it has succeeded, 0 if it has failed +// non zero if it has succeeded, (size_t)-1 if not available size_t GCToOSInterface::GetVirtualMemoryLimit() { LIMITED_METHOD_CONTRACT; @@ -771,16 +771,6 @@ static size_t g_RestrictedPhysicalMemoryLimit = (size_t)MAX_PTR; #ifndef TARGET_UNIX -// For 32-bit processes the virtual address range could be smaller than the amount of physical -// memory on the machine/in the container, we need to restrict by the VM. -static bool g_UseRestrictedVirtualMemory = false; - -typedef BOOL (WINAPI *PGET_PROCESS_MEMORY_INFO)(HANDLE handle, PROCESS_MEMORY_COUNTERS* memCounters, uint32_t cb); -static PGET_PROCESS_MEMORY_INFO GCGetProcessMemoryInfo = 0; - -typedef BOOL (WINAPI *PIS_PROCESS_IN_JOB)(HANDLE processHandle, HANDLE jobHandle, BOOL* result); -typedef BOOL (WINAPI *PQUERY_INFORMATION_JOB_OBJECT)(HANDLE jobHandle, JOBOBJECTINFOCLASS jobObjectInfoClass, void* lpJobObjectInfo, DWORD cbJobObjectInfoLength, LPDWORD lpReturnLength); - static size_t GetRestrictedPhysicalMemoryLimit() { LIMITED_METHOD_CONTRACT; @@ -793,34 +783,14 @@ static size_t GetRestrictedPhysicalMemoryLimit() uint64_t total_virtual = 0; uint64_t total_physical = 0; BOOL in_job_p = FALSE; - HINSTANCE hinstKernel32 = 0; - - PIS_PROCESS_IN_JOB GCIsProcessInJob = 0; - PQUERY_INFORMATION_JOB_OBJECT GCQueryInformationJobObject = 0; - - GCIsProcessInJob = &(::IsProcessInJob); - if (!GCIsProcessInJob(GetCurrentProcess(), NULL, &in_job_p)) + if (!IsProcessInJob(GetCurrentProcess(), NULL, &in_job_p)) goto exit; if (in_job_p) { - hinstKernel32 = WszLoadLibrary(L"kernel32.dll"); - if (!hinstKernel32) - goto exit; - - GCGetProcessMemoryInfo = (PGET_PROCESS_MEMORY_INFO)GetProcAddress(hinstKernel32, "K32GetProcessMemoryInfo"); - - if (!GCGetProcessMemoryInfo) - goto exit; - - GCQueryInformationJobObject = &(::QueryInformationJobObject); - - if (!GCQueryInformationJobObject) - goto exit; - JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info; - if (GCQueryInformationJobObject (NULL, JobObjectExtendedLimitInformation, &limit_info, + if (QueryInformationJobObject(NULL, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info), NULL)) { size_t job_memory_limit = (size_t)MAX_PTR; @@ -867,13 +837,6 @@ static size_t GetRestrictedPhysicalMemoryLimit() if (job_physical_memory_limit == (size_t)MAX_PTR) { job_physical_memory_limit = 0; - - if (hinstKernel32 != 0) - { - FreeLibrary(hinstKernel32); - hinstKernel32 = 0; - GCGetProcessMemoryInfo = 0; - } } // Check to see if we are limited by VM. @@ -893,15 +856,8 @@ static size_t GetRestrictedPhysicalMemoryLimit() if (total_virtual < total_physical) { - if (hinstKernel32 != 0) - { - // We can also free the lib here - if we are limited by VM we will not be calling - // GetProcessMemoryInfo. - FreeLibrary(hinstKernel32); - GCGetProcessMemoryInfo = 0; - } - g_UseRestrictedVirtualMemory = true; - job_physical_memory_limit = (size_t)total_virtual; + // Limited by virtual address space + job_physical_memory_limit = 0; } VolatileStore(&g_RestrictedPhysicalMemoryLimit, job_physical_memory_limit); @@ -928,9 +884,6 @@ static size_t GetRestrictedPhysicalMemoryLimit() // Get the physical memory that this process can use. // Return: // non zero if it has succeeded, 0 if it has failed -// -// PERF TODO: Requires more work to not treat the restricted case to be special. -// To be removed before 3.0 ships. uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted) { LIMITED_METHOD_CONTRACT; @@ -941,11 +894,7 @@ uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted) size_t restricted_limit = GetRestrictedPhysicalMemoryLimit(); if (restricted_limit != 0) { - if (is_restricted -#ifndef TARGET_UNIX - && !g_UseRestrictedVirtualMemory -#endif - ) + if (is_restricted) *is_restricted = true; return restricted_limit; @@ -965,26 +914,22 @@ uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted) // available_page_file - The maximum amount of memory the current process can commit, in bytes. // Remarks: // Any parameter can be null. -void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) +void GCToOSInterface::GetMemoryStatus(uint64_t restricted_limit, uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) { LIMITED_METHOD_CONTRACT; - uint64_t restricted_limit = GetRestrictedPhysicalMemoryLimit(); if (restricted_limit != 0) { size_t workingSetSize; BOOL status = FALSE; #ifndef TARGET_UNIX - if (!g_UseRestrictedVirtualMemory) - { - PROCESS_MEMORY_COUNTERS pmc; - status = GCGetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); - workingSetSize = pmc.WorkingSetSize; - } + PROCESS_MEMORY_COUNTERS pmc; + status = GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); + workingSetSize = pmc.WorkingSetSize; #else status = PAL_GetPhysicalMemoryUsed(&workingSetSize); #endif - if(status) + if (status) { if (memory_load) *memory_load = (uint32_t)((float)workingSetSize * 100.0 / (float)restricted_limit); @@ -1009,9 +954,10 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available GetProcessMemoryLoad(&ms); #ifndef TARGET_UNIX - if (g_UseRestrictedVirtualMemory) + // For 32-bit processes the virtual address range could be smaller than the amount of physical + // memory on the machine/in the container, we need to restrict by the VM. + if (ms.ullTotalVirtual < ms.ullTotalPhys) { - _ASSERTE (ms.ullTotalVirtual == restricted_limit); if (memory_load != NULL) *memory_load = (uint32_t)((float)(ms.ullTotalVirtual - ms.ullAvailVirtual) * 100.0 / (float)ms.ullTotalVirtual); if (available_physical != NULL) diff --git a/src/coreclr/src/vm/gchandleutilities.h b/src/coreclr/src/vm/gchandleutilities.h index b875644b853b5c..d90a2f0faef09a 100644 --- a/src/coreclr/src/vm/gchandleutilities.h +++ b/src/coreclr/src/vm/gchandleutilities.h @@ -201,9 +201,9 @@ inline OBJECTHANDLE CreateGlobalRefcountedHandle(OBJECTREF object) // Special handle creation convenience functions #ifdef FEATURE_COMINTEROP -inline OBJECTHANDLE CreateWinRTWeakHandle(IGCHandleStore* store, OBJECTREF object, IWeakReference* pWinRTWeakReference) +inline OBJECTHANDLE CreateNativeComWeakHandle(IGCHandleStore* store, OBJECTREF object, IWeakReference* pComWeakReference) { - OBJECTHANDLE hnd = store->CreateHandleWithExtraInfo(OBJECTREFToObject(object), HNDTYPE_WEAK_WINRT, (void*)pWinRTWeakReference); + OBJECTHANDLE hnd = store->CreateHandleWithExtraInfo(OBJECTREFToObject(object), HNDTYPE_WEAK_NATIVE_COM, (void*)pComWeakReference); if (!hnd) { COMPlusThrowOM(); @@ -363,7 +363,7 @@ inline void DestroyTypedHandle(OBJECTHANDLE handle) } #ifdef FEATURE_COMINTEROP -inline void DestroyWinRTWeakHandle(OBJECTHANDLE handle) +inline void DestroyNativeComWeakHandle(OBJECTHANDLE handle) { CONTRACTL { @@ -375,7 +375,7 @@ inline void DestroyWinRTWeakHandle(OBJECTHANDLE handle) CONTRACTL_END; // Release the WinRT weak reference if we have one. We're assuming that this will not reenter the - // runtime, since if we are pointing at a managed object, we should not be using HNDTYPE_WEAK_WINRT + // runtime, since if we are pointing at a managed object, we should not be using HNDTYPE_WEAK_NATIVE_COM // but rather HNDTYPE_WEAK_SHORT or HNDTYPE_WEAK_LONG. void* pExtraInfo = GCHandleUtilities::GetGCHandleManager()->GetExtraInfoFromHandle(handle); IWeakReference* pWinRTWeakReference = reinterpret_cast(pExtraInfo); @@ -385,7 +385,7 @@ inline void DestroyWinRTWeakHandle(OBJECTHANDLE handle) } DiagHandleDestroyed(handle); - GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_WEAK_WINRT); + GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_WEAK_NATIVE_COM); } #endif diff --git a/src/coreclr/src/vm/gdbjit.cpp b/src/coreclr/src/vm/gdbjit.cpp index 1642c9fbf7d569..8d8e34e6362f42 100644 --- a/src/coreclr/src/vm/gdbjit.cpp +++ b/src/coreclr/src/vm/gdbjit.cpp @@ -1792,16 +1792,6 @@ void VarDebugInfo::DumpDebugInfo(char* ptr, int& offset) offset += len; } -/* static data for symbol strings */ -struct Elf_Symbol { - const char* m_name; - int m_off; - TADDR m_value; - int m_section, m_size; - NewArrayHolder m_symbol_name; - Elf_Symbol() : m_name(nullptr), m_off(0), m_value(0), m_section(0), m_size(0) {} -}; - template static int countFuncs(T &arr, int n) { diff --git a/src/coreclr/src/vm/gdbjit.h b/src/coreclr/src/vm/gdbjit.h index 8d9359c16ca5e4..fa5a4883cb7425 100644 --- a/src/coreclr/src/vm/gdbjit.h +++ b/src/coreclr/src/vm/gdbjit.h @@ -334,7 +334,16 @@ class VarDebugInfo: public DwarfDumpable uintptr_t m_high_pc; }; -struct Elf_Symbol; +/* static data for symbol strings */ +struct Elf_Symbol { + const char* m_name; + int m_off; + TADDR m_value; + int m_section, m_size; + NewArrayHolder m_symbol_name; + Elf_Symbol() : m_name(nullptr), m_off(0), m_value(0), m_section(0), m_size(0) {} +}; + class Elf_Builder; class DebugStringsCU; diff --git a/src/coreclr/src/vm/genmeth.cpp b/src/coreclr/src/vm/genmeth.cpp index 2b1e19aa13de22..1e6ca14ab8de21 100644 --- a/src/coreclr/src/vm/genmeth.cpp +++ b/src/coreclr/src/vm/genmeth.cpp @@ -1676,6 +1676,7 @@ BOOL MethodDesc::SatisfiesMethodConstraints(TypeHandle thParent, BOOL fThrowIfNo //NB: according to the constructor's signature, thParent should be the declaring type, // but the code appears to admit derived types too. SigTypeContext typeContext(this,thParent); + InstantiationContext instContext(&typeContext, NULL); for (DWORD i = 0; i < methodInst.GetNumArgs(); i++) { @@ -1688,7 +1689,8 @@ BOOL MethodDesc::SatisfiesMethodConstraints(TypeHandle thParent, BOOL fThrowIfNo tyvar->LoadConstraints(); //TODO: is this necessary for anything but the typical method? - if (!tyvar->SatisfiesConstraints(&typeContext,thArg)) + // Pass in the InstatiationContext so contraints can be correctly evaluated + if (!tyvar->SatisfiesConstraints(&typeContext,thArg, &instContext)) { if (fThrowIfNotSatisfied) { diff --git a/src/coreclr/src/vm/i386/asmconstants.h b/src/coreclr/src/vm/i386/asmconstants.h index 33bb341078b977..34e2da58f4be55 100644 --- a/src/coreclr/src/vm/i386/asmconstants.h +++ b/src/coreclr/src/vm/i386/asmconstants.h @@ -143,8 +143,10 @@ ASMCONSTANTS_C_ASSERT(LazyMachState_captureEip == offsetof(LazyMachState, captur #define VASigCookie__StubOffset 4 ASMCONSTANTS_C_ASSERT(VASigCookie__StubOffset == offsetof(VASigCookie, pNDirectILStub)) +#ifndef UNIX_X86_ABI #define SIZEOF_TailCallFrame 32 ASMCONSTANTS_C_ASSERT(SIZEOF_TailCallFrame == sizeof(TailCallFrame)) +#endif // !UNIX_X86_ABI #define SIZEOF_GSCookie 4 diff --git a/src/coreclr/src/vm/i386/cgenx86.cpp b/src/coreclr/src/vm/i386/cgenx86.cpp index 3563e8e5d9b23e..887b24e9ad29ed 100644 --- a/src/coreclr/src/vm/i386/cgenx86.cpp +++ b/src/coreclr/src/vm/i386/cgenx86.cpp @@ -838,6 +838,7 @@ void PInvokeCalliFrame::UpdateRegDisplay(const PREGDISPLAY pRD) RETURN; } +#ifndef UNIX_X86_ABI void TailCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) { CONTRACT_VOID @@ -883,6 +884,7 @@ void TailCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) RETURN; } +#endif // !UNIX_X86_ABI #ifdef FEATURE_READYTORUN void DynamicHelperFrame::UpdateRegDisplay(const PREGDISPLAY pRD) diff --git a/src/coreclr/src/vm/i386/excepx86.cpp b/src/coreclr/src/vm/i386/excepx86.cpp index 85f18d97d6972b..a89e7159566926 100644 --- a/src/coreclr/src/vm/i386/excepx86.cpp +++ b/src/coreclr/src/vm/i386/excepx86.cpp @@ -1065,46 +1065,10 @@ CPFH_RealFirstPassHandler( // ExceptionContinueSearch, etc. GCPROTECT_BEGIN(throwable); throwable = pThread->GetThrowable(); -#ifdef FEATURE_CORRUPTING_EXCEPTIONS + if (IsProcessCorruptedStateException(exceptionCode, throwable)) { - // Setup the state in current exception tracker indicating the corruption severity - // of the active exception. - CEHelper::SetupCorruptionSeverityForActiveException(bRethrownException, bNestedException, - CEHelper::ShouldTreatActiveExceptionAsNonCorrupting()); - // Failfast if exception indicates corrupted process state - if (pExInfo->GetCorruptionSeverity() == ProcessCorrupting) - EEPOLICY_HANDLE_FATAL_ERROR(exceptionCode); - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS - - // Check if we are dealing with AV or not and if we are, - // ensure that this is a real AV and not managed AV exception - BOOL fIsThrownExceptionAV = FALSE; - if ((pExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) && - (MscorlibBinder::GetException(kAccessViolationException) == throwable->GetMethodTable())) - { - // Its an AV - set the flag - fIsThrownExceptionAV = TRUE; - } - - // Did we get an AV? - if (fIsThrownExceptionAV == TRUE) - { - // Get the escalation policy action for handling AV - EPolicyAction actionAV = GetEEPolicy()->GetActionOnFailure(FAIL_AccessViolation); - - // Valid actions are: eNoAction (default behviour) or eRudeExitProcess - _ASSERTE(((actionAV == eNoAction) || (actionAV == eRudeExitProcess))); - if (actionAV == eRudeExitProcess) - { - LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: AccessViolation handler found and doing RudeExitProcess due to escalation policy (eRudeExitProcess)\n")); - - // EEPolicy::HandleFatalError will help us RudeExit the process. - // RudeExitProcess due to AV is to prevent a security risk - we are ripping - // at the boundary, without looking for the handlers. - EEPOLICY_HANDLE_FATAL_ERROR(COR_E_SECURITY); - } + EEPOLICY_HANDLE_FATAL_ERROR(exceptionCode); } // If we're out of memory, then we figure there's probably not memory to maintain a stack trace, so we skip it. @@ -1421,10 +1385,6 @@ CPFH_UnwindFrames1(Thread* pThread, EXCEPTION_REGISTRATION_RECORD* pEstablisherF tct.pTopFrame = GetCurrFrame(pEstablisherFrame); // highest frame to search to tct.pBottomFrame = NULL; - // Set the flag indicating if the current exception represents a longjmp. - // See comment in COMPlusUnwindCallback for details. - CORRUPTING_EXCEPTIONS_ONLY(tct.m_fIsLongJump = (exceptionCode == STATUS_LONGJUMP);) - #ifdef _DEBUG tct.pCurrentExceptionRecord = pEstablisherFrame; tct.pPrevExceptionRecord = GetPrevSEHRecord(pEstablisherFrame); @@ -1692,7 +1652,7 @@ EXCEPTION_HANDLER_IMPL(COMPlusFrameHandler) { if (pExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) { - EEPolicy::HandleStackOverflow(SOD_ManagedFrameHandler, (void*)pEstablisherFrame); + EEPolicy::HandleStackOverflow(); // VC's unhandled exception filter plays with stack. It VirtualAlloc's a new stack, and // then launch Watson from the new stack. When Watson asks CLR to save required data, we @@ -2395,20 +2355,6 @@ StackWalkAction COMPlusThrowCallback( // SWA value if (fIsILStub) pUserMDForILStub = GetUserMethodForILStub(pThread, currentSP, pFunc, &pILStubFrame); -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - CorruptionSeverity currentSeverity = pThread->GetExceptionState()->GetCurrentExceptionTracker()->GetCorruptionSeverity(); - { - // We must defer to the MethodDesc of the user method instead of the IL stub - // itself because the user can specify the policy on a per-method basis and - // that won't be reflected via the IL stub's MethodDesc. - MethodDesc * pMDWithCEAttribute = fIsILStub ? pUserMDForILStub : pFunc; - - // Check if the exception can be delivered to the method? It will check if the exception - // is a CE or not. If it is, it will check if the method can process it or not. - fMethodCanHandleException = CEHelper::CanMethodHandleException(currentSeverity, pMDWithCEAttribute); - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS - // Let the profiler know that we are searching for a handler within this function instance if (fGiveDebuggerAndProfilerNotification) EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionEnter(pFunc); @@ -2435,29 +2381,12 @@ StackWalkAction COMPlusThrowCallback( // SWA value ExceptionNotifications::DeliverFirstChanceNotification(); } } + IJitManager* pJitManager = pCf->GetJitManager(); _ASSERTE(pJitManager); - EH_CLAUSE_ENUMERATOR pEnumState; - unsigned EHCount = 0; - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // If exception cannot be handled, then just bail out. We shouldnt examine the EH clauses - // in such a method. - if (!fMethodCanHandleException) - { - LOG((LF_EH, LL_INFO100, "COMPlusThrowCallback - CEHelper decided not to look for exception handlers in the method(MD:%p).\n", pFunc)); - - // Set the flag to skip this frame since the CE cannot be delivered - _ASSERTE(currentSeverity == ProcessCorrupting); - // Ensure EHClause count is zero - EHCount = 0; - } - else -#endif // FEATURE_CORRUPTING_EXCEPTIONS - { - EHCount = pJitManager->InitializeEHEnumeration(pCf->GetMethodToken(), &pEnumState); - } + EH_CLAUSE_ENUMERATOR pEnumState; + unsigned EHCount = pJitManager->InitializeEHEnumeration(pCf->GetMethodToken(), &pEnumState); if (EHCount == 0) { @@ -2737,59 +2666,6 @@ StackWalkAction COMPlusUnwindCallback (CrawlFrame *pCf, ThrowCallbackType *pData TypeHandle thrownType = TypeHandle(); - BOOL fCanMethodHandleException = TRUE; -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // MethodDesc's security information (i.e. whether it is critical or transparent) is calculated lazily. - // If this method's security information was not precalculated, then it would have been in the first pass - // already using Security::IsMethodCritical which could take have taken us down a path which is GC_TRIGGERS. - // - // - // However, this unwind callback (for X86) is GC_NOTRIGGER and at this point the security information would have been - // calculated already. Hence, we wouldnt endup in the GC_TRIGGERS path. Thus, to keep SCAN.EXE (static contract analyzer) happy, - // we will pass a FALSE to the CanMethodHandleException call, indicating we dont need to calculate security information (and thus, - // not go down the GC_TRIGGERS path. - // - // Check if the exception can be delivered to the method? It will check if the exception - // is a CE or not. If it is, it will check if the method can process it or not. - CorruptionSeverity currentSeverity = pThread->GetExceptionState()->GetCurrentExceptionTracker()->GetCorruptionSeverity(); - - // We have to do this check for x86 since, unlike 64bit which will setup a new exception tracker for longjmp, - // x86 only sets up new trackers in the first pass (and longjmp is 2nd pass only exception). Hence, we pass - // this information in the callback structure without affecting any existing exception tracker (incase longjmp was - // a nested exception). - if (pData->m_fIsLongJump) - { - // Longjump is not a CSE. With a CSE in progress, this can be invoked by either: - // - // 1) Managed code (e.g. finally/fault/catch), OR - // 2) By native code - // - // In scenario (1), managed code can invoke it only if it was attributed with HPCSE attribute. Thus, - // longjmp is no different than managed code doing a "throw new Exception();". - // - // In scenario (2), longjmp is no different than any other non-CSE native exception raised. - // - // In both these case, longjmp should be treated as non-CSE. Since x86 does not setup a tracker for - // it (see comment above), we pass this information (of whether the current exception is a longjmp or not) - // to this callback (from UnwindFrames) to setup the correct corruption severity. - // - // http://www.nynaeve.net/?p=105 has a brief description of how exception-safe setjmp/longjmp works. - currentSeverity = NotCorrupting; - } - { - MethodDesc * pFuncWithCEAttribute = pFunc; - Frame * pILStubFrame = NULL; - if (pFunc->IsILStub()) - { - // We must defer to the MethodDesc of the user method instead of the IL stub - // itself because the user can specify the policy on a per-method basis and - // that won't be reflected via the IL stub's MethodDesc. - pFuncWithCEAttribute = GetUserMethodForILStub(pThread, (UINT_PTR)pStack, pFunc, &pILStubFrame); - } - fCanMethodHandleException = CEHelper::CanMethodHandleException(currentSeverity, pFuncWithCEAttribute, FALSE); - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS - #ifdef DEBUGGING_SUPPORTED LOG((LF_EH, LL_INFO1000, "COMPlusUnwindCallback: Intercept %d, pData->pFunc 0x%X, pFunc 0x%X, pData->pStack 0x%X, pStack 0x%X\n", pExInfo->m_ExceptionFlags.DebuggerInterceptInfo(), @@ -2815,24 +2691,7 @@ StackWalkAction COMPlusUnwindCallback (CrawlFrame *pCf, ThrowCallbackType *pData EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionEnter(pFunc); EH_CLAUSE_ENUMERATOR pEnumState; - unsigned EHCount; - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - if (!fCanMethodHandleException) - { - LOG((LF_EH, LL_INFO100, "COMPlusUnwindCallback - CEHelper decided not to look for exception handlers in the method(MD:%p).\n", pFunc)); - - // Set the flag to skip this frame since the CE cannot be delivered - _ASSERTE(currentSeverity == ProcessCorrupting); - - // Force EHClause count to be zero - EHCount = 0; - } - else -#endif // FEATURE_CORRUPTING_EXCEPTIONS - { - EHCount = pJitManager->InitializeEHEnumeration(pCf->GetMethodToken(), &pEnumState); - } + unsigned EHCount = pJitManager->InitializeEHEnumeration(pCf->GetMethodToken(), &pEnumState); if (EHCount == 0) { @@ -3631,7 +3490,6 @@ LONG CLRNoCatchHandler(EXCEPTION_POINTERS* pExceptionInfo, PVOID pv) return EXCEPTION_CONTINUE_SEARCH; #endif // !FEATURE_EH_FUNCLETS } -#endif // !DACCESS_COMPILE // Returns TRUE if caller should resume execution. BOOL @@ -3653,7 +3511,7 @@ AdjustContextForVirtualStub( PCODE f_IP = GetIP(pContext); VirtualCallStubManager::StubKind sk; - /* VirtualCallStubManager *pMgr = */ VirtualCallStubManager::FindStubManager(f_IP, &sk); + VirtualCallStubManager *pMgr = VirtualCallStubManager::FindStubManager(f_IP, &sk); if (sk == VirtualCallStubManager::SK_DISPATCH) { @@ -3679,11 +3537,12 @@ AdjustContextForVirtualStub( return FALSE; } - PCODE callsite = GetAdjustedCallAddress(*dac_cast(GetSP(pContext))); + PCODE callsite = *dac_cast(GetSP(pContext)); if (pExceptionRecord != NULL) { pExceptionRecord->ExceptionAddress = (PVOID)callsite; } + SetIP(pContext, callsite); #if defined(GCCOVER_TOLERATE_SPURIOUS_AV) @@ -3693,7 +3552,35 @@ AdjustContextForVirtualStub( #endif // defined(GCCOVER_TOLERATE_SPURIOUS_AV) // put ESP back to what it was before the call. - SetSP(pContext, dac_cast(dac_cast(GetSP(pContext)) + sizeof(void*))); + TADDR sp = GetSP(pContext) + sizeof(void*); + +#ifndef UNIX_X86_ABI + // set the ESP to what it would be after the call (remove pushed arguments) + + size_t stackArgumentsSize; + if (sk == VirtualCallStubManager::SK_DISPATCH) + { + ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE(); + + DispatchHolder *holder = DispatchHolder::FromDispatchEntry(f_IP); + MethodTable *pMT = (MethodTable*)holder->stub()->expectedMT(); + DispatchToken token(VirtualCallStubManager::GetTokenFromStubQuick(pMgr, f_IP, sk)); + MethodDesc* pMD = VirtualCallStubManager::GetRepresentativeMethodDescFromToken(token, pMT); + stackArgumentsSize = pMD->SizeOfArgStack(); + } + else + { + // Compute the stub entry address from the address of failure (location of dereferencing of "this" pointer) + ResolveHolder *holder = ResolveHolder::FromResolveEntry(f_IP - ResolveStub::offsetOfThisDeref()); + stackArgumentsSize = holder->stub()->stackArgumentsSize(); + } + + sp += stackArgumentsSize; +#endif // UNIX_X86_ABI + + SetSP(pContext, dac_cast(dac_cast(sp))); return TRUE; } + +#endif // !DACCESS_COMPILE diff --git a/src/coreclr/src/vm/i386/jitinterfacex86.cpp b/src/coreclr/src/vm/i386/jitinterfacex86.cpp index 82b36f5b0d4255..72c97096e17c38 100644 --- a/src/coreclr/src/vm/i386/jitinterfacex86.cpp +++ b/src/coreclr/src/vm/i386/jitinterfacex86.cpp @@ -135,8 +135,10 @@ HCIMPL1(Object*, AllocObjectWrapper, MethodTable *pMT) HCIMPLEND /*********************************************************************/ +#ifndef UNIX_X86_ABI extern "C" void* g_TailCallFrameVptr; void* g_TailCallFrameVptr; +#endif // !UNI_X86_ABI #ifdef FEATURE_HIJACK extern "C" void STDCALL JIT_TailCallHelper(Thread * pThread); @@ -1085,8 +1087,10 @@ void InitJITHelpers1() // Leave the patched region writable for StompWriteBarrierEphemeral(), StompWriteBarrierResize() +#ifndef UNIX_X86_ABI // Initialize g_TailCallFrameVptr for JIT_TailCall helper g_TailCallFrameVptr = (void*)TailCallFrame::GetMethodFrameVPtr(); +#endif // !UNIX_X86_ABI } #pragma warning (default : 4731) diff --git a/src/coreclr/src/vm/i386/stublinkerx86.cpp b/src/coreclr/src/vm/i386/stublinkerx86.cpp index eac75f64b93013..5e801b4d704a13 100644 --- a/src/coreclr/src/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/src/vm/i386/stublinkerx86.cpp @@ -5121,726 +5121,6 @@ Thread* __stdcall CreateThreadBlockReturnHr(ComMethodFrame *pFrame) #endif // !DACCESS_COMPILE - -#ifdef TARGET_AMD64 - -// -// TailCallFrame Object Scanning -// -// This handles scanning/promotion of GC objects that were -// protected by the TailCallHelper routine. Note that the objects -// being protected is somewhat dynamic and is dependent upon the -// the callee... -// - -void TailCallFrame::GcScanRoots(promote_func *fn, ScanContext* sc) -{ - WRAPPER_NO_CONTRACT; - - if (m_pGCLayout != NULL) - { - struct FrameOffsetDecoder { - private: - TADDR prevOffset; - TADDR rangeEnd; - BOOL maybeInterior; - BOOL atEnd; - PTR_SBYTE pbOffsets; - - DWORD ReadNumber() { - signed char i; - DWORD offset = 0; - while ((i = *pbOffsets++) >= 0) - { - offset = (offset << 7) | i; - } - offset = (offset << 7) | (i & 0x7F); - return offset; - } - - public: - FrameOffsetDecoder(PTR_GSCookie _base, TADDR offsets) - : prevOffset(dac_cast(_base)), rangeEnd(~0LL), atEnd(FALSE), pbOffsets(dac_cast(offsets)) { maybeInterior = FALSE;} - - bool MoveNext() { - LIMITED_METHOD_CONTRACT; - - if (rangeEnd < prevOffset) - { - prevOffset -= sizeof(void*); - return true; - } - if (atEnd) return false; - DWORD offset = ReadNumber(); - atEnd = (offset & 1); - BOOL range = (offset & 2); - maybeInterior = (offset & 0x80000000); - - offset &= 0x7FFFFFFC; - -#ifdef HOST_64BIT - offset <<= 1; -#endif - offset += sizeof(void*); - _ASSERTE(prevOffset > offset); - prevOffset -= offset; - - if (range) - { - _ASSERTE(!atEnd); - _ASSERTE(!maybeInterior); - DWORD offsetEnd = ReadNumber(); - atEnd = (offsetEnd & 1); - offsetEnd = (offsetEnd & ~1) << 1; - // range encoding starts with a range of 3 (2 is better to encode as - // 2 offsets), so 0 == 2 (the last offset in the range) - offsetEnd += sizeof(void*) * 2; - rangeEnd = prevOffset - offsetEnd; - } - - return true; - } - - BOOL MaybeInterior() const { return maybeInterior; } - - PTR_PTR_Object Current() const { return PTR_PTR_Object(prevOffset); } - - } decoder(GetGSCookiePtr(), m_pGCLayout); - - while (decoder.MoveNext()) - { - PTR_PTR_Object ppRef = decoder.Current(); - - LOG((LF_GC, INFO3, "Tail Call Frame Promoting" FMT_ADDR "to", - DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*ppRef)) )); - if (decoder.MaybeInterior()) - PromoteCarefully(fn, ppRef, sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN); - else - (*fn)(ppRef, sc, 0); - LOG((LF_GC, INFO3, FMT_ADDR "\n", DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*ppRef)) )); - } - } -} - -#ifndef DACCESS_COMPILE -static void EncodeOneGCOffset(CPUSTUBLINKER *pSl, ULONG delta, BOOL maybeInterior, BOOL range, BOOL last) -{ - CONTRACTL - { - THROWS; // From the stublinker - MODE_ANY; - GC_NOTRIGGER; - } - CONTRACTL_END; - - // Everything should be pointer aligned - // but we use a high bit for interior, and the 0 bit to denote the end of the list - // we use the 1 bit to denote a range - _ASSERTE((delta % sizeof(void*)) == 0); - -#if defined(HOST_64BIT) - // For 64-bit, we have 3 bits of alignment, so we allow larger frames - // by shifting and gaining a free high-bit. - ULONG encodedDelta = delta >> 1; -#else - // For 32-bit, we just limit our frame size to <2GB. - ULONG encodedDelta = delta; -#endif - _ASSERTE((encodedDelta & 0x80000003) == 0); - if (last) - { - encodedDelta |= 1; - } - - if (range) - { - encodedDelta |= 2; - } - else if (maybeInterior) - { - _ASSERTE(!range); - encodedDelta |= 0x80000000; - } - - BYTE bytes[5]; - UINT index = 5; - bytes[--index] = (BYTE)((encodedDelta & 0x7F) | 0x80); - encodedDelta >>= 7; - while (encodedDelta > 0) - { - bytes[--index] = (BYTE)(encodedDelta & 0x7F); - encodedDelta >>= 7; - } - pSl->EmitBytes(&bytes[index], 5 - index); -} - -static void EncodeGCOffsets(CPUSTUBLINKER *pSl, /* const */ ULONGARRAY & gcOffsets) -{ - CONTRACTL - { - THROWS; - MODE_ANY; - GC_NOTRIGGER; - } - CONTRACTL_END; - - _ASSERTE(gcOffsets.Count() > 0); - - ULONG prevOffset = 0; - int i = 0; - BOOL last = FALSE; - do { - ULONG offset = gcOffsets[i]; - // Everything should be pointer aligned - // but we use the 0-bit to mean maybeInterior, for byrefs. - _ASSERTE(((offset % sizeof(void*)) == 0) || ((offset % sizeof(void*)) == 1)); - BOOL maybeInterior = (offset & 1); - offset &= ~1; - - // Encode just deltas because they're smaller (and the list should be sorted) - _ASSERTE(offset >= (prevOffset + sizeof(void*))); - ULONG delta = offset - (prevOffset + sizeof(void*)); - if (!maybeInterior && gcOffsets.Count() > i + 2) - { - // Check for a potential range. - // Only do it if we have 3 or more pointers in a row - ULONG rangeOffset = offset; - int j = i + 1; - do { - ULONG nextOffset = gcOffsets[j]; - // interior pointers can't be in ranges - if (nextOffset & 1) - break; - // ranges must be saturated - if (nextOffset != (rangeOffset + sizeof(void*))) - break; - j++; - rangeOffset = nextOffset; - } while(j < gcOffsets.Count()); - - if (j > (i + 2)) - { - EncodeOneGCOffset(pSl, delta, FALSE, TRUE, last); - i = j - 1; - _ASSERTE(rangeOffset >= (offset + (sizeof(void*) * 2))); - delta = rangeOffset - (offset + (sizeof(void*) * 2)); - offset = rangeOffset; - } - } - last = (++i == gcOffsets.Count()); - - - EncodeOneGCOffset(pSl, delta, maybeInterior, FALSE, last); - - prevOffset = offset; - } while (!last); -} - -static void AppendGCLayout(ULONGARRAY &gcLayout, size_t baseOffset, BOOL fIsTypedRef, TypeHandle VMClsHnd) -{ - STANDARD_VM_CONTRACT; - - _ASSERTE((baseOffset % 16) == 0); - _ASSERTE(FitsInU4(baseOffset)); - - if (fIsTypedRef) - { - *gcLayout.AppendThrowing() = (ULONG)(baseOffset | 1); // "| 1" to mark it as an interior pointer - } - else if (!VMClsHnd.IsNativeValueType()) - { - MethodTable* pMT = VMClsHnd.GetMethodTable(); - _ASSERTE(pMT); - _ASSERTE(pMT->IsValueType()); - - BOOL isByRefLike = pMT->IsByRefLike(); - if (isByRefLike) - { - FindByRefPointerOffsetsInByRefLikeObject( - pMT, - 0 /* baseOffset */, - [&](size_t pointerOffset) - { - // 'gcLayout' requires stack offsets relative to the top of the stack to be recorded, such that subtracting - // the offset from the stack top yields the address of the field, given that subtracting 'baseOffset' from - // the stack top yields the address of the first field in this struct. See TailCallFrame::GcScanRoots() for - // how these offsets are used to calculate stack addresses for fields. - _ASSERTE(pointerOffset < baseOffset); - size_t stackOffsetFromTop = baseOffset - pointerOffset; - _ASSERTE(FitsInU4(stackOffsetFromTop)); - - // Offsets in 'gcLayout' are expected to be in increasing order - int gcLayoutInsertIndex = gcLayout.Count(); - _ASSERTE(gcLayoutInsertIndex >= 0); - for (; gcLayoutInsertIndex != 0; --gcLayoutInsertIndex) - { - ULONG prevStackOffsetFromTop = gcLayout[gcLayoutInsertIndex - 1] & ~(ULONG)1; - if (stackOffsetFromTop > prevStackOffsetFromTop) - { - break; - } - if (stackOffsetFromTop == prevStackOffsetFromTop) - { - return; - } - } - - _ASSERTE(gcLayout.Count() == 0 || stackOffsetFromTop > (gcLayout[gcLayout.Count() - 1] & ~(ULONG)1)); - *gcLayout.InsertThrowing(gcLayoutInsertIndex) = (ULONG)(stackOffsetFromTop | 1); // "| 1" to mark it as an interior pointer - }); - } - - // walk the GC descriptors, reporting the correct offsets - if (pMT->ContainsPointers()) - { - // size of instance when unboxed must be adjusted for the syncblock - // index and the VTable pointer. - DWORD size = pMT->GetBaseSize(); - - // we don't include this term in our 'ppstop' calculation below. - _ASSERTE(pMT->GetComponentSize() == 0); - - CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT); - CGCDescSeries* cur = map->GetLowestSeries(); - CGCDescSeries* last = map->GetHighestSeries(); - - _ASSERTE(cur <= last); - do - { - // offset to embedded references in this series must be - // adjusted by the VTable pointer, when in the unboxed state. - size_t adjustOffset = cur->GetSeriesOffset() - sizeof(void *); - - _ASSERTE(baseOffset >= adjustOffset); - size_t start = baseOffset - adjustOffset; - size_t stop = start - (cur->GetSeriesSize() + size); - for (size_t off = stop + sizeof(void*); off <= start; off += sizeof(void*)) - { - _ASSERTE(FitsInU4(off)); - - int gcLayoutInsertIndex = gcLayout.Count(); - _ASSERTE(gcLayoutInsertIndex >= 0); - if (isByRefLike) - { - // Offsets in 'gcLayout' are expected to be in increasing order and for by-ref-like types the by-refs would - // have already been inserted into 'gcLayout' above. Find the appropriate index at which to insert this - // offset. - while (gcLayoutInsertIndex != 0 && off < gcLayout[gcLayoutInsertIndex - 1]) - { - --gcLayoutInsertIndex; - _ASSERTE(off != (gcLayout[gcLayoutInsertIndex] & ~(ULONG)1)); - } - } - - _ASSERTE(gcLayoutInsertIndex == 0 || off > (gcLayout[gcLayoutInsertIndex - 1] & ~(ULONG)1)); - *gcLayout.InsertThrowing(gcLayoutInsertIndex) = (ULONG)off; - } - cur++; - - } while (cur <= last); - } - } -} - -Stub * StubLinkerCPU::CreateTailCallCopyArgsThunk(CORINFO_SIG_INFO * pSig, - MethodDesc* pMD, - CorInfoHelperTailCallSpecialHandling flags) -{ - STANDARD_VM_CONTRACT; - - CPUSTUBLINKER sl; - CPUSTUBLINKER* pSl = &sl; - - // Generates a function that looks like this: - // size_t CopyArguments(va_list args, (RCX) - // CONTEXT *pCtx, (RDX) - // DWORD64 *pvStack, (R8) - // size_t cbStack) (R9) - // { - // if (pCtx != NULL) { - // foreach (arg in args) { - // copy into pCtx or pvStack - // } - // } - // return ; - // } - // - - CodeLabel *pNullLabel = pSl->NewCodeLabel(); - - // test rdx, rdx - pSl->X86EmitR2ROp(0x85, kRDX, kRDX); - - // jz NullLabel - pSl->X86EmitCondJump(pNullLabel, X86CondCode::kJZ); - - UINT nArgSlot = 0; - UINT totalArgs = pSig->totalILArgs() + ((pSig->isVarArg() || pSig->hasTypeArg()) ? 1 : 0); - bool fR10Loaded = false; - UINT cbArg; - static const UINT rgcbArgRegCtxtOffsets[4] = { offsetof(CONTEXT, Rcx), offsetof(CONTEXT, Rdx), - offsetof(CONTEXT, R8), offsetof(CONTEXT, R9) }; - static const UINT rgcbFpArgRegCtxtOffsets[4] = { offsetof(CONTEXT, Xmm0.Low), offsetof(CONTEXT, Xmm1.Low), - offsetof(CONTEXT, Xmm2.Low), offsetof(CONTEXT, Xmm3.Low) }; - - ULONGARRAY gcLayout; - - // On input to the function R9 contains the size of the buffer - // The first time this macro runs, R10 is loaded with the 'top' of the Frame - // and R9 is changed to point to the 'top' of the copy buffer. - // Then both R9 and R10 are decremented by the size of the struct we're copying - // So R10 is the value to put in the argument slot, and R9 is where the data - // should be copied to (or zeroed out in the case of the return buffer). -#define LOAD_STRUCT_OFFSET_IF_NEEDED(cbSize) \ - { \ - _ASSERTE(cbSize > 0); \ - _ASSERTE(FitsInI4(cbSize)); \ - __int32 offset = (__int32)cbSize; \ - if (!fR10Loaded) { \ - /* mov r10, [rdx + offset of RSP] */ \ - pSl->X86EmitIndexRegLoad(kR10, kRDX, offsetof(CONTEXT, Rsp)); \ - /* add an extra 8 because RSP is pointing at the return address */ \ - offset -= 8; \ - /* add r10, r9 */ \ - pSl->X86EmitAddRegReg(kR10, kR9); \ - /* add r9, r8 */ \ - pSl->X86EmitAddRegReg(kR9, kR8); \ - fR10Loaded = true; \ - } \ - /* sub r10, offset */ \ - pSl->X86EmitSubReg(kR10, offset); \ - /* sub r9, cbSize */ \ - pSl->X86EmitSubReg(kR9, cbSize); \ - } - - - if (flags & CORINFO_TAILCALL_STUB_DISPATCH_ARG) { - // This is set for stub dispatch - // The JIT placed an extra argument in the list that needs to - // get shoved into R11, and not counted. - // pCtx->R11 = va_arg(args, DWORD64); - - // mov rax, [rcx] - pSl->X86EmitIndexRegLoad(kRAX, kRCX, 0); - // add rcx, 8 - pSl->X86EmitAddReg(kRCX, 8); - // mov [rdx + offset of R11], rax - pSl->X86EmitIndexRegStore(kRDX, offsetof(CONTEXT, R11), kRAX); - } - - ULONG cbStructOffset = 0; - - // First comes the 'this' pointer - if (pSig->hasThis()) { - // mov rax, [rcx] - pSl->X86EmitIndexRegLoad(kRAX, kRCX, 0); - // add rcx, 8 - pSl->X86EmitAddReg(kRCX, 8); - // mov [rdx + offset of RCX/RDX], rax - pSl->X86EmitIndexRegStore(kRDX, rgcbArgRegCtxtOffsets[nArgSlot++], kRAX); - } - - // Next the return buffer - cbArg = 0; - TypeHandle th(pSig->retTypeClass); - if ((pSig->retType == CORINFO_TYPE_REFANY) || (pSig->retType == CORINFO_TYPE_VALUECLASS)) { - cbArg = th.GetSize(); - } - - if (ArgIterator::IsArgPassedByRef(cbArg)) { - totalArgs++; - - // We always reserve space for the return buffer, and we always zero it out, - // so the GC won't complain, but if it's already pointing above the frame, - // then we need to pass it in (so it will get passed out). - // Otherwise we assume the caller is returning void, so we just pass in - // dummy space to be overwritten. - UINT cbUsed = (cbArg + 0xF) & ~0xF; - LOAD_STRUCT_OFFSET_IF_NEEDED(cbUsed); - // now emit a 'memset(r9, 0, cbUsed)' - { - // xorps xmm0, xmm0 - pSl->X86EmitR2ROp(X86_INSTR_XORPS, kXMM0, kXMM0); - if (cbUsed <= 4 * 16) { - // movaps [r9], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM0, kR9, 0); - if (16 < cbUsed) { - // movaps [r9 + 16], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM0, kR9, 16); - if (32 < cbUsed) { - // movaps [r9 + 32], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM0, kR9, 32); - if (48 < cbUsed) { - // movaps [r9 + 48], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM0, kR9, 48); - } - } - } - } - else { - // a loop (one double-quadword at a time) - pSl->X86EmitZeroOutReg(kR11); - // LoopLabel: - CodeLabel *pLoopLabel = pSl->NewCodeLabel(); - pSl->EmitLabel(pLoopLabel); - // movaps [r9 + r11], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM0, kR9, 0, kR11, 1); - // add r11, 16 - pSl->X86EmitAddReg(kR11, 16); - // cmp r11, cbUsed - pSl->X86EmitCmpRegImm32(kR11, cbUsed); - // jl LoopLabel - pSl->X86EmitCondJump(pLoopLabel, X86CondCode::kJL); - } - } - cbStructOffset += cbUsed; - AppendGCLayout(gcLayout, cbStructOffset, pSig->retType == CORINFO_TYPE_REFANY, th); - - // mov rax, [rcx] - pSl->X86EmitIndexRegLoad(kRAX, kRCX, 0); - // add rcx, 8 - pSl->X86EmitAddReg(kRCX, 8); - // cmp rax, [rdx + offset of R12] - pSl->X86EmitOffsetModRM(0x3B, kRAX, kRDX, offsetof(CONTEXT, R12)); - - CodeLabel *pSkipLabel = pSl->NewCodeLabel(); - // jnb SkipLabel - pSl->X86EmitCondJump(pSkipLabel, X86CondCode::kJNB); - - // Also check the lower bound of the stack in case the return buffer is on the GC heap - // and the GC heap is below the stack - // cmp rax, rsp - pSl->X86EmitR2ROp(0x3B, kRAX, (X86Reg)4 /*kRSP*/); - // jna SkipLabel - pSl->X86EmitCondJump(pSkipLabel, X86CondCode::kJB); - // mov rax, r10 - pSl->X86EmitMovRegReg(kRAX, kR10); - // SkipLabel: - pSl->EmitLabel(pSkipLabel); - // mov [rdx + offset of RCX], rax - pSl->X86EmitIndexRegStore(kRDX, rgcbArgRegCtxtOffsets[nArgSlot++], kRAX); - } - - // VarArgs Cookie *or* Generics Instantiation Parameter - if (pSig->hasTypeArg() || pSig->isVarArg()) { - // mov rax, [rcx] - pSl->X86EmitIndexRegLoad(kRAX, kRCX, 0); - // add rcx, 8 - pSl->X86EmitAddReg(kRCX, 8); - // mov [rdx + offset of RCX/RDX], rax - pSl->X86EmitIndexRegStore(kRDX, rgcbArgRegCtxtOffsets[nArgSlot++], kRAX); - } - - _ASSERTE(nArgSlot <= 4); - - // Now for *all* the 'real' arguments - SigPointer ptr((PCCOR_SIGNATURE)pSig->args); - Module * module = GetModule(pSig->scope); - Instantiation classInst((TypeHandle*)pSig->sigInst.classInst, pSig->sigInst.classInstCount); - Instantiation methodInst((TypeHandle*)pSig->sigInst.methInst, pSig->sigInst.methInstCount); - SigTypeContext typeCtxt(classInst, methodInst); - - for( ;nArgSlot < totalArgs; ptr.SkipExactlyOne()) { - CorElementType et = ptr.PeekElemTypeNormalized(module, &typeCtxt); - if (et == ELEMENT_TYPE_SENTINEL) - continue; - - // mov rax, [rcx] - pSl->X86EmitIndexRegLoad(kRAX, kRCX, 0); - // add rcx, 8 - pSl->X86EmitAddReg(kRCX, 8); - switch (et) { - case ELEMENT_TYPE_INTERNAL: - // TODO - _ASSERTE(!"Shouldn't see ELEMENT_TYPE_INTERNAL"); - break; - case ELEMENT_TYPE_TYPEDBYREF: - case ELEMENT_TYPE_VALUETYPE: - th = ptr.GetTypeHandleThrowing(module, &typeCtxt, ClassLoader::LoadTypes, CLASS_LOAD_UNRESTOREDTYPEKEY); - _ASSERTE(!th.IsNull()); - g_IBCLogger.LogEEClassAndMethodTableAccess(th.GetMethodTable()); - cbArg = (UINT)th.GetSize(); - if (ArgIterator::IsArgPassedByRef(cbArg)) { - UINT cbUsed = (cbArg + 0xF) & ~0xF; - LOAD_STRUCT_OFFSET_IF_NEEDED(cbUsed); - // rax has the source pointer - // r9 has the intermediate copy location - // r10 has the final destination - if (nArgSlot < 4) { - pSl->X86EmitIndexRegStore(kRDX, rgcbArgRegCtxtOffsets[nArgSlot++], kR10); - } - else { - pSl->X86EmitIndexRegStore(kR8, 8 * nArgSlot++, kR10); - } - // now emit a 'memcpy(rax, r9, cbUsed)' - // These structs are supposed to be 16-byte aligned, but - // Reflection puts them on the GC heap, which is only 8-byte - // aligned. It also means we have to be careful about not - // copying too much (because we might cross a page boundary) - UINT cbUsed16 = (cbArg + 7) & ~0xF; - _ASSERTE((cbUsed16 == cbUsed) || ((cbUsed16 + 16) == cbUsed)); - - if (cbArg <= 192) { - // Unrolled version (6 x 16 bytes in parallel) - UINT offset = 0; - while (offset < cbUsed16) { - // movups xmm0, [rax + offset] - pSl->X86EmitOp(X86_INSTR_MOVUPS_R_RM, kXMM0, kRAX, offset); - if (offset + 16 < cbUsed16) { - // movups xmm1, [rax + offset + 16] - pSl->X86EmitOp(X86_INSTR_MOVUPS_R_RM, kXMM1, kRAX, offset + 16); - if (offset + 32 < cbUsed16) { - // movups xmm2, [rax + offset + 32] - pSl->X86EmitOp(X86_INSTR_MOVUPS_R_RM, kXMM2, kRAX, offset + 32); - if (offset + 48 < cbUsed16) { - // movups xmm3, [rax + offset + 48] - pSl->X86EmitOp(X86_INSTR_MOVUPS_R_RM, kXMM3, kRAX, offset + 48); - if (offset + 64 < cbUsed16) { - // movups xmm4, [rax + offset + 64] - pSl->X86EmitOp(X86_INSTR_MOVUPS_R_RM, kXMM4, kRAX, offset + 64); - if (offset + 80 < cbUsed16) { - // movups xmm5, [rax + offset + 80] - pSl->X86EmitOp(X86_INSTR_MOVUPS_R_RM, kXMM5, kRAX, offset + 80); - } - } - } - } - } - // movaps [r9 + offset], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM0, kR9, offset); - offset += 16; - if (offset < cbUsed16) { - // movaps [r9 + 16], xmm1 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM1, kR9, offset); - offset += 16; - if (offset < cbUsed16) { - // movaps [r9 + 32], xmm2 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM2, kR9, offset); - offset += 16; - if (offset < cbUsed16) { - // movaps [r9 + 48], xmm3 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM3, kR9, offset); - offset += 16; - if (offset < cbUsed16) { - // movaps [r9 + 64], xmm4 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM4, kR9, offset); - offset += 16; - if (offset < cbUsed16) { - // movaps [r9 + 80], xmm5 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM5, kR9, offset); - offset += 16; - } - } - } - } - } - } - // Copy the last 8 bytes if needed - if (cbUsed > cbUsed16) { - _ASSERTE(cbUsed16 < cbArg); - // movlps xmm0, [rax + offset] - pSl->X86EmitOp(X86_INSTR_MOVLPS_R_RM, kXMM0, kRAX, offset); - // movlps [r9 + offset], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVLPS_RM_R, kXMM0, kR9, offset); - } - } - else { - // a loop (one double-quadword at a time) - pSl->X86EmitZeroOutReg(kR11); - // LoopLabel: - CodeLabel *pLoopLabel = pSl->NewCodeLabel(); - pSl->EmitLabel(pLoopLabel); - // movups xmm0, [rax + r11] - pSl->X86EmitOp(X86_INSTR_MOVUPS_R_RM, kXMM0, kRAX, 0, kR11, 1); - // movaps [r9 + r11], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVAPS_RM_R, kXMM0, kR9, 0, kR11, 1); - // add r11, 16 - pSl->X86EmitAddReg(kR11, 16); - // cmp r11, cbUsed16 - pSl->X86EmitCmpRegImm32(kR11, cbUsed16); - // jl LoopLabel - pSl->X86EmitCondJump(pLoopLabel, X86CondCode::kJL); - if (cbArg > cbUsed16) { - _ASSERTE(cbUsed16 + 8 >= cbArg); - // movlps xmm0, [rax + r11] - pSl->X86EmitOp(X86_INSTR_MOVLPS_R_RM, kXMM0, kRAX, 0, kR11, 1); - // movlps [r9 + r11], xmm0 - pSl->X86EmitOp(X86_INSTR_MOVLPS_RM_R, kXMM0, kR9, 0, kR11, 1); - } - } - cbStructOffset += cbUsed; - AppendGCLayout(gcLayout, cbStructOffset, et == ELEMENT_TYPE_TYPEDBYREF, th); - break; - } - - // - // Explicit Fall-Through for non-IsArgPassedByRef - // - - default: - if (nArgSlot < 4) { - pSl->X86EmitIndexRegStore(kRDX, rgcbArgRegCtxtOffsets[nArgSlot], kRAX); - if ((et == ELEMENT_TYPE_R4) || (et == ELEMENT_TYPE_R8)) { - pSl->X86EmitIndexRegStore(kRDX, rgcbFpArgRegCtxtOffsets[nArgSlot], kRAX); - } - } - else { - pSl->X86EmitIndexRegStore(kR8, 8 * nArgSlot, kRAX); - } - nArgSlot++; - break; - } - } - -#undef LOAD_STRUCT_OFFSET_IF_NEEDED - - // Keep our 4 shadow slots and even number of slots (to keep 16-byte aligned) - if (nArgSlot < 4) - nArgSlot = 4; - else if (nArgSlot & 1) - nArgSlot++; - - _ASSERTE((cbStructOffset % 16) == 0); - - // xor eax, eax - pSl->X86EmitZeroOutReg(kRAX); - // ret - pSl->X86EmitReturn(0); - - // NullLabel: - pSl->EmitLabel(pNullLabel); - - CodeLabel *pGCLayoutLabel = NULL; - if (gcLayout.Count() == 0) { - // xor eax, eax - pSl->X86EmitZeroOutReg(kRAX); - } - else { - // lea rax, [rip + offset to gclayout] - pGCLayoutLabel = pSl->NewCodeLabel(); - pSl->X86EmitLeaRIP(pGCLayoutLabel, kRAX); - } - // mov [r9], rax - pSl->X86EmitIndexRegStore(kR9, 0, kRAX); - // mov rax, cbStackNeeded - pSl->X86EmitRegLoad(kRAX, cbStructOffset + nArgSlot * 8); - // ret - pSl->X86EmitReturn(0); - - if (gcLayout.Count() > 0) { - // GCLayout: - pSl->EmitLabel(pGCLayoutLabel); - EncodeGCOffsets(pSl, gcLayout); - } - - LoaderHeap* pHeap = pMD->GetLoaderAllocator()->GetStubHeap(); - return pSl->Link(pHeap); -} -#endif // DACCESS_COMPILE - -#endif // TARGET_AMD64 - - #ifdef HAS_FIXUP_PRECODE #ifdef HAS_FIXUP_PRECODE_CHUNKS diff --git a/src/coreclr/src/vm/i386/stublinkerx86.h b/src/coreclr/src/vm/i386/stublinkerx86.h index 32417ba4171096..23ab0c40ca5716 100644 --- a/src/coreclr/src/vm/i386/stublinkerx86.h +++ b/src/coreclr/src/vm/i386/stublinkerx86.h @@ -443,14 +443,6 @@ class StubLinkerCPU : public StubLinker virtual VOID EmitUnwindInfoCheckSubfunction(); #endif -#ifdef TARGET_AMD64 - - static Stub * CreateTailCallCopyArgsThunk(CORINFO_SIG_INFO * pSig, - MethodDesc* pMD, - CorInfoHelperTailCallSpecialHandling flags); - -#endif // TARGET_AMD64 - private: VOID X86EmitSubEspWorker(INT32 imm32); diff --git a/src/coreclr/src/vm/i386/umthunkstub.S b/src/coreclr/src/vm/i386/umthunkstub.S index e40b1917f8dcba..a88fbefcf16802 100644 --- a/src/coreclr/src/vm/i386/umthunkstub.S +++ b/src/coreclr/src/vm/i386/umthunkstub.S @@ -61,7 +61,7 @@ LOCAL_LABEL(HaveThread): mov dword ptr [ebp - UMThunkStub_THREAD_OFFSET], eax - // FailFast if a native callable method is invoked via ldftn and calli. + // FailFast if a method marked UnmanagedCallersOnlyAttribute is invoked via ldftn and calli. cmp dword ptr [eax + Thread_m_fPreemptiveGCDisabled], 1 jz LOCAL_LABEL(InvalidTransition) diff --git a/src/coreclr/src/vm/i386/virtualcallstubcpu.hpp b/src/coreclr/src/vm/i386/virtualcallstubcpu.hpp index 979c96123eecad..f8e4982360287a 100644 --- a/src/coreclr/src/vm/i386/virtualcallstubcpu.hpp +++ b/src/coreclr/src/vm/i386/virtualcallstubcpu.hpp @@ -258,7 +258,7 @@ is important. */ struct ResolveStub { inline PCODE failEntryPoint() { LIMITED_METHOD_CONTRACT; return (PCODE)&_failEntryPoint[0]; } - inline PCODE resolveEntryPoint() { LIMITED_METHOD_CONTRACT; return (PCODE)&_resolveEntryPoint[0]; } + inline PCODE resolveEntryPoint() { LIMITED_METHOD_CONTRACT; return (PCODE)&_resolveEntryPoint; } inline PCODE slowEntryPoint() { LIMITED_METHOD_CONTRACT; return (PCODE)&_slowEntryPoint[0]; } inline INT32* pCounter() { LIMITED_METHOD_CONTRACT; return _pCounter; } @@ -266,6 +266,10 @@ struct ResolveStub inline size_t cacheAddress() { LIMITED_METHOD_CONTRACT; return _cacheAddress; } inline size_t token() { LIMITED_METHOD_CONTRACT; return _token; } inline size_t size() { LIMITED_METHOD_CONTRACT; return sizeof(ResolveStub); } +#ifndef UNIX_X86_ABI + inline static size_t offsetOfThisDeref(){ LIMITED_METHOD_CONTRACT; return offsetof(ResolveStub, part1) - offsetof(ResolveStub, _resolveEntryPoint); } + inline size_t stackArgumentsSize() { LIMITED_METHOD_CONTRACT; return _stackArgumentsSize; } +#endif private: friend struct ResolveHolder; @@ -283,13 +287,13 @@ struct ResolveStub // ResolveStub::_resolveEntryPoint expects: // ecx: object (the "this" pointer) // eax: siteAddrForRegisterIndirect if this is a RegisterIndirect dispatch call - BYTE _resolveEntryPoint[6]; // 50 push eax ;save siteAddrForRegisterIndirect - this may be an indirect call - // 8b 01 mov eax,[ecx] ;get the method table from the "this" pointer. This is the place + BYTE _resolveEntryPoint; // 50 push eax ;save siteAddrForRegisterIndirect - this may be an indirect call + BYTE part1 [11]; // 8b 01 mov eax,[ecx] ;get the method table from the "this" pointer. This is the place // ; where we are going to fault on null this. If you change it, // ; change also AdjustContextForVirtualStub in excep.cpp!!! // 52 push edx // 8b d0 mov edx, eax - BYTE part1 [6]; // c1 e8 0C shr eax,12 ;we are adding upper bits into lower bits of mt + // c1 e8 0C shr eax,12 ;we are adding upper bits into lower bits of mt // 03 c2 add eax,edx // 35 xor eax, UINT32 _hashedToken; // xx xx xx xx hashedToken ;along with pre-hashed token @@ -329,6 +333,9 @@ struct ResolveStub DISPL _backpatcherDispl; // xx xx xx xx backpatcherWorker == BackPatchWorkerAsmStub BYTE part11 [1]; // eb jmp BYTE toResolveStub; // xx resolveStub, i.e. go back to _resolveEntryPoint +#ifndef UNIX_X86_ABI + size_t _stackArgumentsSize; // xx xx xx xx +#endif }; /* ResolveHolders are the containers for ResolveStubs, They provide @@ -343,7 +350,11 @@ struct ResolveHolder void Initialize(PCODE resolveWorkerTarget, PCODE patcherTarget, size_t dispatchToken, UINT32 hashedToken, - void * cacheAddr, INT32 * counterAddr); + void * cacheAddr, INT32 * counterAddr +#ifndef UNIX_X86_ABI + , size_t stackArgumentsSize +#endif + ); ResolveStub* stub() { LIMITED_METHOD_CONTRACT; return &_stub; } @@ -685,11 +696,16 @@ extern "C" void STDCALL JIT_TailCallReturnFromVSD(); PCODE StubCallSite::GetCallerAddress() { LIMITED_METHOD_CONTRACT; + +#ifdef UNIX_X86_ABI + return m_returnAddr; +#else // UNIX_X86_ABI if (m_returnAddr != (PCODE)JIT_TailCallReturnFromVSD) return m_returnAddr; // Find the tailcallframe in the frame chain and get the actual caller from the first TailCallFrame return TailCallFrame::FindTailCallFrame(GetThread()->GetFrame())->GetCallerAddress(); +#endif // UNIX_X86_ABI } #ifdef STUB_LOGGING @@ -839,21 +855,19 @@ void ResolveHolder::InitializeStatic() resolveInit.toPatcher = (offsetof(ResolveStub, patch) - (offsetof(ResolveStub, toPatcher) + 1)) & 0xFF; - resolveInit._resolveEntryPoint [0] = 0x50; - resolveInit._resolveEntryPoint [1] = 0x8b; - resolveInit._resolveEntryPoint [2] = 0x01; - resolveInit._resolveEntryPoint [3] = 0x52; - resolveInit._resolveEntryPoint [4] = 0x8b; - resolveInit._resolveEntryPoint [5] = 0xd0; - static_assert_no_msg(sizeof(resolveInit._resolveEntryPoint) == 6); - - resolveInit.part1 [0] = 0xc1; - resolveInit.part1 [1] = 0xe8; - resolveInit.part1 [2] = CALL_STUB_CACHE_NUM_BITS; - resolveInit.part1 [3] = 0x03; - resolveInit.part1 [4] = 0xc2; - resolveInit.part1 [5] = 0x35; - static_assert_no_msg(sizeof(resolveInit.part1) == 6); + resolveInit._resolveEntryPoint = 0x50; + resolveInit.part1 [0] = 0x8b; + resolveInit.part1 [1] = 0x01; + resolveInit.part1 [2] = 0x52; + resolveInit.part1 [3] = 0x8b; + resolveInit.part1 [4] = 0xd0; + resolveInit.part1 [5] = 0xc1; + resolveInit.part1 [6] = 0xe8; + resolveInit.part1 [7] = CALL_STUB_CACHE_NUM_BITS; + resolveInit.part1 [8] = 0x03; + resolveInit.part1 [9] = 0xc2; + resolveInit.part1 [10] = 0x35; + static_assert_no_msg(sizeof(resolveInit.part1) == 11); resolveInit._hashedToken = 0xcccccccc; resolveInit.part2 [0] = 0x25; @@ -932,7 +946,11 @@ void ResolveHolder::InitializeStatic() void ResolveHolder::Initialize(PCODE resolveWorkerTarget, PCODE patcherTarget, size_t dispatchToken, UINT32 hashedToken, - void * cacheAddr, INT32 * counterAddr) + void * cacheAddr, INT32 * counterAddr +#ifndef UNIX_X86_ABI + , size_t stackArgumentsSize +#endif + ) { _stub = resolveInit; @@ -945,6 +963,9 @@ void ResolveHolder::Initialize(PCODE resolveWorkerTarget, PCODE patcherTarget, _stub._tokenPush = dispatchToken; _stub._resolveWorkerDispl = resolveWorkerTarget - ((PCODE) &_stub._resolveWorkerDispl + sizeof(DISPL)); _stub._backpatcherDispl = patcherTarget - ((PCODE) &_stub._backpatcherDispl + sizeof(DISPL)); +#ifndef UNIX_X86_ABI + _stub._stackArgumentsSize = stackArgumentsSize; +#endif } ResolveHolder* ResolveHolder::FromFailEntry(PCODE failEntry) diff --git a/src/coreclr/src/vm/ilmarshalers.cpp b/src/coreclr/src/vm/ilmarshalers.cpp index 8ec77a0bd28cc8..a84d6ca21d5f89 100644 --- a/src/coreclr/src/vm/ilmarshalers.cpp +++ b/src/coreclr/src/vm/ilmarshalers.cpp @@ -2907,7 +2907,7 @@ MarshalerOverrideStatus ILSafeHandleMarshaler::ArgumentOverride(NDirectStubLinke } // Leave the address of the native handle local as the argument to the native method. - pslILDispatch->EmitLDLOCA(dwNativeHandleLocal); + EmitLoadNativeLocalAddrForByRefDispatch(pslILDispatch, dwNativeHandleLocal); // On the output side we only backpropagate the native handle into the output SafeHandle and the output SafeHandle // to the caller if the native handle actually changed (otherwise we can end up with two SafeHandles wrapping the @@ -3071,7 +3071,7 @@ ILSafeHandleMarshaler::ReturnOverride( pslIL->SetStubTargetArgType(&locDescReturnHandle, false); // extra arg is a byref IntPtr // 5) [byref] pass address of local as last arg - pslILDispatch->EmitLDLOCA(dwReturnNativeHandleLocal); + EmitLoadNativeLocalAddrForByRefDispatch(pslILDispatch, dwReturnNativeHandleLocal); // We will use cleanup stream to avoid leaking the handle on thread abort. psl->EmitSetArgMarshalIndex(pslIL, NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL); @@ -3253,7 +3253,7 @@ MarshalerOverrideStatus ILCriticalHandleMarshaler::ArgumentOverride(NDirectStubL } // Leave the address of the native handle local as the argument to the native method. - pslILDispatch->EmitLDLOCA(dwNativeHandleLocal); + EmitLoadNativeLocalAddrForByRefDispatch(pslILDispatch, dwNativeHandleLocal); if (fin) { @@ -3406,7 +3406,7 @@ ILCriticalHandleMarshaler::ReturnOverride( pslIL->SetStubTargetArgType(&locDescReturnHandle, false); // extra arg is a byref IntPtr // 5) [byref] pass address of local as last arg - pslILDispatch->EmitLDLOCA(dwReturnNativeHandleLocal); + EmitLoadNativeLocalAddrForByRefDispatch(pslILDispatch, dwReturnNativeHandleLocal); // We will use cleanup stream to avoid leaking the handle on thread abort. psl->EmitSetArgMarshalIndex(pslIL, NDirectStubLinker::CLEANUP_INDEX_RETVAL_UNMARSHAL); @@ -3512,7 +3512,7 @@ MarshalerOverrideStatus ILBlittableValueClassWithCopyCtorMarshaler::ArgumentOver pslILDispatch->EmitLDLOC(dwNewValueTypeLocal); // we load the local directly #else pslIL->SetStubTargetArgType(ELEMENT_TYPE_I); // native type is a pointer - pslILDispatch->EmitLDLOCA(dwNewValueTypeLocal); + EmitLoadNativeLocalAddrForByRefDispatch(pslILDispatch, dwNewValueTypeLocal); #endif return OVERRIDDEN; diff --git a/src/coreclr/src/vm/ilmarshalers.h b/src/coreclr/src/vm/ilmarshalers.h index de661be63f8c75..21e1b2db4478d7 100644 --- a/src/coreclr/src/vm/ilmarshalers.h +++ b/src/coreclr/src/vm/ilmarshalers.h @@ -371,6 +371,16 @@ class ILMarshaler return (0 != (dwMarshalFlags & MARSHAL_FLAG_FIELD)); } + static void EmitLoadNativeLocalAddrForByRefDispatch(ILCodeStream* pslILEmit, DWORD local) + { + WRAPPER_NO_CONTRACT; + pslILEmit->EmitLDLOCA(local); + + // Convert the loaded local containing a native address + // into a non-GC type for the byref case. + pslILEmit->EmitCONV_I(); + } + void EmitLoadManagedValue(ILCodeStream* pslILEmit) { WRAPPER_NO_CONTRACT; @@ -395,6 +405,16 @@ class ILMarshaler m_nativeHome.EmitLoadHomeAddr(pslILEmit); } + void EmitLoadNativeHomeAddrForByRefDispatch(ILCodeStream* pslILEmit) + { + WRAPPER_NO_CONTRACT; + EmitLoadNativeHomeAddr(pslILEmit); + + // Convert the loaded value containing a native address + // into a non-GC type for the byref case. + pslILEmit->EmitCONV_I(); + } + void EmitStoreManagedValue(ILCodeStream* pslILEmit) { WRAPPER_NO_CONTRACT; @@ -421,6 +441,7 @@ class ILMarshaler void EmitLogNativeArgument(ILCodeStream* pslILEmit, DWORD dwPinnedLocal) { + WRAPPER_NO_CONTRACT; if (g_pConfig->InteropLogArguments()) { m_pslNDirect->EmitLogNativeArgument(pslILEmit, dwPinnedLocal); @@ -666,7 +687,7 @@ class ILMarshaler { if (IsNativePassedByRef()) { - EmitLoadNativeHomeAddr(pslILEmit); + EmitLoadNativeHomeAddrForByRefDispatch(pslILEmit); } else { @@ -807,7 +828,7 @@ class ILMarshaler if (IsHresultSwap(dwMarshalFlags) || byrefNativeReturn) { EmitReInitNative(m_pcsMarshal); - EmitLoadNativeHomeAddr(pcsDispatch); // load up the byref native type as an extra arg + EmitLoadNativeHomeAddrForByRefDispatch(pcsDispatch); // load up the byref native type as an extra arg } else { diff --git a/src/coreclr/src/vm/ilstubcache.cpp b/src/coreclr/src/vm/ilstubcache.cpp index 86299dfeeef071..0ea66d4fbbbeaa 100644 --- a/src/coreclr/src/vm/ilstubcache.cpp +++ b/src/coreclr/src/vm/ilstubcache.cpp @@ -105,6 +105,8 @@ MethodDesc* ILStubCache::CreateAndLinkNewILStubMethodDesc(LoaderAllocator* pAllo amTracker.SuppressRelease(); + pStubLinker->SetStubMethodDesc(pStubMD); + ILStubResolver *pResolver = pStubMD->AsDynamicMethodDesc()->GetILStubResolver(); pResolver->SetStubMethodDesc(pStubMD); @@ -112,19 +114,20 @@ MethodDesc* ILStubCache::CreateAndLinkNewILStubMethodDesc(LoaderAllocator* pAllo { UINT maxStack; - size_t cbCode; - DWORD cbSig; - BYTE * pbBuffer; - BYTE * pbLocalSig; - - cbCode = pStubLinker->Link(&maxStack); - cbSig = pStubLinker->GetLocalSigSize(); + size_t cbCode = pStubLinker->Link(&maxStack); + DWORD cbSig = pStubLinker->GetLocalSigSize(); COR_ILMETHOD_DECODER * pILHeader = pResolver->AllocGeneratedIL(cbCode, cbSig, maxStack); - pbBuffer = (BYTE *)pILHeader->Code; - pbLocalSig = (BYTE *)pILHeader->LocalVarSig; + BYTE * pbBuffer = (BYTE *)pILHeader->Code; + BYTE * pbLocalSig = (BYTE *)pILHeader->LocalVarSig; _ASSERTE(cbSig == pILHeader->cbLocalVarSig); + size_t numEH = pStubLinker->GetNumEHClauses(); + if (numEH > 0) + { + pStubLinker->WriteEHClauses(pResolver->AllocEHSect(numEH)); + } + pStubLinker->GenerateCode(pbBuffer, cbCode); pStubLinker->GetLocalSig(pbLocalSig, cbSig); @@ -244,6 +247,21 @@ MethodDesc* ILStubCache::CreateNewMethodDesc(LoaderHeap* pCreationHeap, MethodTa } else #endif + if (SF_IsTailCallStoreArgsStub(dwStubFlags)) + { + pMD->GetILStubResolver()->SetStubType(ILStubResolver::TailCallStoreArgsStub); + } + else + if (SF_IsTailCallCallTargetStub(dwStubFlags)) + { + pMD->GetILStubResolver()->SetStubType(ILStubResolver::TailCallCallTargetStub); + } + else + if (SF_IsTailCallDispatcherStub(dwStubFlags)) + { + pMD->GetILStubResolver()->SetStubType(ILStubResolver::TailCallDispatcherStub); + } + else #ifdef FEATURE_COMINTEROP if (SF_IsCOMStub(dwStubFlags)) { @@ -280,7 +298,7 @@ MethodDesc* ILStubCache::CreateNewMethodDesc(LoaderHeap* pCreationHeap, MethodTa { pMD->m_dwExtendedFlags |= DynamicMethodDesc::nomdReverseStub; #if !defined(TARGET_X86) - pMD->m_dwExtendedFlags |= DynamicMethodDesc::nomdNativeCallableStub; + pMD->m_dwExtendedFlags |= DynamicMethodDesc::nomdUnmanagedCallersOnlyStub; #endif pMD->GetILStubResolver()->SetStubType(ILStubResolver::NativeToCLRInteropStub); } @@ -474,10 +492,6 @@ MethodDesc* ILStubCache::GetStubMethodDesc( if (!pMD) { - size_t cbSizeOfBlob = pParams->m_cbSizeOfBlob; - AllocMemHolder pBlobHolder( m_heap->AllocMem(S_SIZE_T(cbSizeOfBlob)) ); - - // // Couldn't find it, let's make a new one. // @@ -501,6 +515,8 @@ MethodDesc* ILStubCache::GetStubMethodDesc( if (SF_IsSharedStub(dwStubFlags)) { + size_t cbSizeOfBlob = pParams->m_cbSizeOfBlob; + AllocMemHolder pBlobHolder( m_heap->AllocMem(S_SIZE_T(cbSizeOfBlob)) ); CrstHolder ch(&m_crst); diff --git a/src/coreclr/src/vm/ilstubresolver.cpp b/src/coreclr/src/vm/ilstubresolver.cpp index 94be0cf9ca2bee..a0d19f1b867c61 100644 --- a/src/coreclr/src/vm/ilstubresolver.cpp +++ b/src/coreclr/src/vm/ilstubresolver.cpp @@ -88,7 +88,10 @@ LPCUTF8 ILStubResolver::GetStubMethodName() case UnboxingILStub: return "IL_STUB_UnboxingStub"; case InstantiatingStub: return "IL_STUB_InstantiatingStub"; #endif - case WrapperDelegateStub: return "IL_STUB_WrapperDelegate_Invoke"; + case WrapperDelegateStub: return "IL_STUB_WrapperDelegate_Invoke"; + case TailCallStoreArgsStub: return "IL_STUB_StoreTailCallArgs"; + case TailCallCallTargetStub: return "IL_STUB_CallTailCallTarget"; + case TailCallDispatcherStub: return "IL_STUB_DispatchTailCalls"; default: UNREACHABLE_MSG("Unknown stub type"); } @@ -195,9 +198,11 @@ ILStubResolver::ResolveSignature( mdToken token) { STANDARD_VM_CONTRACT; - CONSISTENCY_CHECK_MSG(token == TOKEN_ILSTUB_TARGET_SIG, "IL stubs do not support any other signature tokens!"); - return m_pCompileTimeState->m_StubTargetMethodSig; + if (token == TOKEN_ILSTUB_TARGET_SIG) + return m_pCompileTimeState->m_StubTargetMethodSig; + + return m_pCompileTimeState->m_tokenLookupMap.LookupSig(token); } //--------------------------------------------------------------------------------------- @@ -236,14 +241,10 @@ void ILStubResolver::GetEHInfo(unsigned EHnumber, CORINFO_EH_CLAUSE* clause) clause->FilterOffset = ehInfo->GetFilterOffset(); } -bool ILStubResolver::IsNativeToCLRInteropStub() +ILStubResolver::ILStubType ILStubResolver::GetStubType() { - return (m_type == NativeToCLRInteropStub); -} - -bool ILStubResolver::IsCLRToNativeInteropStub() -{ - return (m_type == CLRToNativeInteropStub); + LIMITED_METHOD_CONTRACT; + return m_type; } void ILStubResolver::SetStubType(ILStubType stubType) diff --git a/src/coreclr/src/vm/ilstubresolver.h b/src/coreclr/src/vm/ilstubresolver.h index 8b42a0cd3b3132..3b319197dd669a 100644 --- a/src/coreclr/src/vm/ilstubresolver.h +++ b/src/coreclr/src/vm/ilstubresolver.h @@ -47,8 +47,6 @@ class ILStubResolver : DynamicResolver // ----------------------------------- // ILStubResolver-specific methods // ----------------------------------- - bool IsNativeToCLRInteropStub(); - bool IsCLRToNativeInteropStub(); MethodDesc* GetStubMethodDesc(); MethodDesc* GetStubTargetMethodDesc(); void SetStubTargetMethodDesc(MethodDesc* pStubTargetMD); @@ -75,7 +73,6 @@ class ILStubResolver : DynamicResolver static void StubGenFailed(ILStubResolver* pResolver); -protected: enum ILStubType { Unassigned = 0, @@ -97,8 +94,15 @@ class ILStubResolver : DynamicResolver UnboxingILStub, InstantiatingStub, #endif + TailCallStoreArgsStub, + TailCallCallTargetStub, + TailCallDispatcherStub, }; + ILStubType GetStubType(); + +protected: + enum CompileTimeStatePtrSpecialValues { ILNotYetGenerated = NULL, diff --git a/src/coreclr/src/vm/inlinetracking.cpp b/src/coreclr/src/vm/inlinetracking.cpp index e382b3e6ecfe8c..4f84ff2b6c6528 100644 --- a/src/coreclr/src/vm/inlinetracking.cpp +++ b/src/coreclr/src/vm/inlinetracking.cpp @@ -550,7 +550,7 @@ COUNT_T PersistentInlineTrackingMapR2R::GetInliners(PTR_Module inlineeOwnerMod, CONTRACTL_END; _ASSERTE(inlineeOwnerMod); - _ASSERTE(inliners); + _ASSERTE(inliners != NULL || inlinersSize == 0); if (incompleteData) { @@ -692,8 +692,8 @@ COUNT_T PersistentInlineTrackingMapR2R2::GetInliners(PTR_Module inlineeOwnerMod, streamSize--; if (inlinerModule == nullptr && incompleteData) { - // We can't find module for this inlineeModuleZapIndex, it means it hasn't been loaded yet - // (maybe it never will be), we just report it to the profiler. + // We can't find module for this inlineeModuleZapIndex, it means it hasn't been loaded yet + // (maybe it never will be), we just report it to the profiler. // Profiler might want to try later when more modules are loaded. *incompleteData = TRUE; continue; diff --git a/src/coreclr/src/vm/interopconverter.cpp b/src/coreclr/src/vm/interopconverter.cpp index 44470d7d297b44..00fa3cb6e4e8d8 100644 --- a/src/coreclr/src/vm/interopconverter.cpp +++ b/src/coreclr/src/vm/interopconverter.cpp @@ -28,7 +28,7 @@ namespace _Outptr_ IUnknown** wrapperRaw) { #ifdef FEATURE_COMWRAPPERS - return GlobalComWrappers::TryGetOrCreateComInterfaceForObject(instance, (void**)wrapperRaw); + return GlobalComWrappersForMarshalling::TryGetOrCreateComInterfaceForObject(instance, (void**)wrapperRaw); #else return false; #endif // FEATURE_COMWRAPPERS @@ -40,7 +40,7 @@ namespace _Out_ OBJECTREF *pObjOut) { #ifdef FEATURE_COMWRAPPERS - return GlobalComWrappers::TryGetOrCreateObjectForComInstance(pUnknown, dwFlags, pObjOut); + return GlobalComWrappersForMarshalling::TryGetOrCreateObjectForComInstance(pUnknown, dwFlags, pObjOut); #else return false; #endif // FEATURE_COMWRAPPERS @@ -80,7 +80,7 @@ namespace //-------------------------------------------------------------------------------- // IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, ...) // Convert ObjectRef to a COM IP, based on MethodTable* pMT. -IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, BOOL bSecurityCheck, BOOL bEnableCustomizedQueryInterface) +IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, BOOL bEnableCustomizedQueryInterface) { CONTRACT (IUnknown*) { @@ -104,8 +104,15 @@ IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, BOOL bSecuri if (TryGetComIPFromObjectRefUsingComWrappers(*poref, &pUnk)) { - pUnk.SuppressRelease(); - RETURN pUnk; + GUID iid; + pMT->GetGuid(&iid, /*bGenerateIfNotFound*/ FALSE, /*bClassic*/ FALSE); + + IUnknown* pvObj; + hr = SafeQueryInterface(pUnk, iid, &pvObj); + if (FAILED(hr)) + COMPlusThrowHR(hr); + + RETURN pvObj; } SyncBlock* pBlock = (*poref)->GetSyncBlock(); @@ -119,7 +126,6 @@ IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, BOOL bSecuri CCWHolder pCCWHold = ComCallWrapper::InlineGetWrapper(poref); GetComIPFromCCW::flags flags = GetComIPFromCCW::None; - if (!bSecurityCheck) { flags |= GetComIPFromCCW::SuppressSecurityCheck; } if (!bEnableCustomizedQueryInterface) { flags |= GetComIPFromCCW::SuppressCustomizedQueryInterface; } pUnk = ComCallWrapper::GetComIPFromCCW(pCCWHold, GUID_NULL, pMT, flags); @@ -177,15 +183,20 @@ IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, ComIpType ReqIpType, ComIpType { hr = S_OK; - SafeComHolder pvObj; + IUnknown* pvObj; if (ReqIpType & ComIpType_Dispatch) { - hr = pUnk->QueryInterface(IID_IDispatch, &pvObj); + hr = SafeQueryInterface(pUnk, IID_IDispatch, &pvObj); + pUnk->Release(); } else if (ReqIpType & ComIpType_Inspectable) { - SafeComHolder pvObj; - hr = pUnk->QueryInterface(IID_IInspectable, &pvObj); + hr = SafeQueryInterface(pUnk, IID_IInspectable, &pvObj); + pUnk->Release(); + } + else + { + pvObj = pUnk; } if (FAILED(hr)) @@ -194,7 +205,7 @@ IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, ComIpType ReqIpType, ComIpType if (pFetchedIpType != NULL) *pFetchedIpType = ReqIpType; - RETURN pUnk; + RETURN pvObj; } MethodTable *pMT = (*poref)->GetMethodTable(); @@ -464,12 +475,13 @@ IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, REFIID iid, bool throwIfNoComI if (TryGetComIPFromObjectRefUsingComWrappers(*poref, &pUnk)) { - SafeComHolder pvObj; - hr = pUnk->QueryInterface(iid, &pvObj); + IUnknown* pvObj; + hr = SafeQueryInterface(pUnk, iid, &pvObj); + pUnk->Release(); if (FAILED(hr)) COMPlusThrowHR(hr); - RETURN pUnk; + RETURN pvObj; } MethodTable *pMT = (*poref)->GetMethodTable(); diff --git a/src/coreclr/src/vm/interopconverter.h b/src/coreclr/src/vm/interopconverter.h index ad6b9a0004d135..a41c169b716b50 100644 --- a/src/coreclr/src/vm/interopconverter.h +++ b/src/coreclr/src/vm/interopconverter.h @@ -113,7 +113,7 @@ enum ComIpType //-------------------------------------------------------------------------------- // IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, ...); // Convert ObjectRef to a COM IP, based on MethodTable* pMT. -IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, BOOL bSecurityCheck = TRUE, BOOL bEnableCustomizedQueryInterface = TRUE); +IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, BOOL bEnableCustomizedQueryInterface = TRUE); //-------------------------------------------------------------------------------- diff --git a/src/coreclr/src/vm/interoplibinterface.cpp b/src/coreclr/src/vm/interoplibinterface.cpp index 8bb65c04cac234..9040e8176aff40 100644 --- a/src/coreclr/src/vm/interoplibinterface.cpp +++ b/src/coreclr/src/vm/interoplibinterface.cpp @@ -401,12 +401,23 @@ namespace Volatile ExtObjCxtCache::g_Instance; // Indicator for if a ComWrappers implementation is globally registered - bool g_IsGlobalComWrappersRegistered; + bool g_IsGlobalComWrappersRegisteredForMarshalling; + bool g_IsGlobalComWrappersRegisteredForTrackerSupport; // Defined handle types for the specific object uses. const HandleType InstanceHandleType{ HNDTYPE_STRONG }; + // Scenarios for ComWrappers usage. + // These values should match the managed definition in ComWrappers. + enum class ComWrappersScenario + { + Instance = 0, + TrackerSupportGlobalInstance = 1, + MarshallingGlobalInstance = 2, + }; + void* CallComputeVTables( + _In_ ComWrappersScenario scenario, _In_ OBJECTREF* implPROTECTED, _In_ OBJECTREF* instancePROTECTED, _In_ INT32 flags, @@ -425,17 +436,19 @@ namespace void* vtables = NULL; PREPARE_NONVIRTUAL_CALLSITE(METHOD__COMWRAPPERS__COMPUTE_VTABLES); - DECLARE_ARGHOLDER_ARRAY(args, 4); - args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(*implPROTECTED); - args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(*instancePROTECTED); - args[ARGNUM_2] = DWORD_TO_ARGHOLDER(flags); - args[ARGNUM_3] = PTR_TO_ARGHOLDER(vtableCount); + DECLARE_ARGHOLDER_ARRAY(args, 5); + args[ARGNUM_0] = DWORD_TO_ARGHOLDER(scenario); + args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(*implPROTECTED); + args[ARGNUM_2] = OBJECTREF_TO_ARGHOLDER(*instancePROTECTED); + args[ARGNUM_3] = DWORD_TO_ARGHOLDER(flags); + args[ARGNUM_4] = PTR_TO_ARGHOLDER(vtableCount); CALL_MANAGED_METHOD(vtables, void*, args); return vtables; } - OBJECTREF CallGetObject( + OBJECTREF CallCreateObject( + _In_ ComWrappersScenario scenario, _In_ OBJECTREF* implPROTECTED, _In_ IUnknown* externalComObject, _In_ INT32 flags) @@ -452,11 +465,12 @@ namespace OBJECTREF retObjRef; PREPARE_NONVIRTUAL_CALLSITE(METHOD__COMWRAPPERS__CREATE_OBJECT); - DECLARE_ARGHOLDER_ARRAY(args, 3); - args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(*implPROTECTED); - args[ARGNUM_1] = PTR_TO_ARGHOLDER(externalComObject); - args[ARGNUM_2] = DWORD_TO_ARGHOLDER(flags); - CALL_MANAGED_METHOD(retObjRef, OBJECTREF, args); + DECLARE_ARGHOLDER_ARRAY(args, 4); + args[ARGNUM_0] = DWORD_TO_ARGHOLDER(scenario); + args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(*implPROTECTED); + args[ARGNUM_2] = PTR_TO_ARGHOLDER(externalComObject); + args[ARGNUM_3] = DWORD_TO_ARGHOLDER(flags); + CALL_MANAGED_METHOD_RETREF(retObjRef, OBJECTREF, args); return retObjRef; } @@ -511,6 +525,7 @@ namespace _In_opt_ OBJECTREF impl, _In_ OBJECTREF instance, _In_ CreateComInterfaceFlags flags, + _In_ ComWrappersScenario scenario, _Outptr_ void** wrapperRaw) { CONTRACT(bool) @@ -519,6 +534,7 @@ namespace MODE_COOPERATIVE; PRECONDITION(instance != NULL); PRECONDITION(wrapperRaw != NULL); + PRECONDITION((impl != NULL && scenario == ComWrappersScenario::Instance)|| (impl == NULL && scenario != ComWrappersScenario::Instance)); } CONTRACT_END; @@ -552,7 +568,7 @@ namespace // is taken. However, a key assumption here is that the returned memory will be // idempotent for the same object. DWORD vtableCount; - void* vtables = CallComputeVTables(&gc.implRef, &gc.instRef, flags, &vtableCount); + void* vtables = CallComputeVTables(scenario, &gc.implRef, &gc.instRef, flags, &vtableCount); // Re-query the associated InteropSyncBlockInfo for an existing managed object wrapper. if (!interopInfo->TryGetManagedObjectComWrapper(&wrapperRawMaybe) @@ -621,16 +637,11 @@ namespace RETURN (wrapperRawMaybe != NULL); } - // The unwrap parameter indicates whether or not COM instances that are actually CCWs should - // be unwrapped to the original managed object. - // For implicit usage of ComWrappers (i.e. automatically called by the runtime when there is a global instance), - // CCWs should be unwrapped to allow for round-tripping object -> COM instance -> object. - // For explicit usage of ComWrappers (i.e. directly called via a ComWrappers APIs), CCWs should not be unwrapped. bool TryGetOrCreateObjectForComInstanceInternal( _In_opt_ OBJECTREF impl, _In_ IUnknown* identity, _In_ CreateObjectFlags flags, - _In_ bool unwrap, + _In_ ComWrappersScenario scenario, _In_opt_ OBJECTREF wrapperMaybe, _Out_ OBJECTREF* objRef) { @@ -640,6 +651,7 @@ namespace MODE_COOPERATIVE; PRECONDITION(identity != NULL); PRECONDITION(objRef != NULL); + PRECONDITION((impl != NULL && scenario == ComWrappersScenario::Instance) || (impl == NULL && scenario != ComWrappersScenario::Instance)); } CONTRACT_END; @@ -670,8 +682,10 @@ namespace extObjCxt = cache->Find(identity); // If is no object found in the cache, check if the object COM instance is actually the CCW - // representing a managed object. - if (extObjCxt == NULL && unwrap) + // representing a managed object. For the scenario of marshalling through a global instance, + // COM instances that are actually CCWs should be unwrapped to the original managed object + // to allow for round-tripping object -> COM instance -> object. + if (extObjCxt == NULL && scenario == ComWrappersScenario::MarshallingGlobalInstance) { // If the COM instance is a CCW that is not COM-activated, use the object of that wrapper object. InteropLib::OBJECTHANDLE handleLocal; @@ -717,7 +731,7 @@ namespace // If the wrapper hasn't been set yet, call the implementation to create one. if (gc.objRefMaybe == NULL) { - gc.objRefMaybe = CallGetObject(&gc.implRef, identity, flags); + gc.objRefMaybe = CallCreateObject(scenario, &gc.implRef, identity, flags); } // The object may be null if the specified ComWrapper implementation returns null @@ -830,7 +844,7 @@ namespace InteropLibImports HRESULT hr = S_OK; BEGIN_EXTERNAL_ENTRYPOINT(&hr) { - GCInterface::NewAddMemoryPressure(memoryInBytes); + GCInterface::AddMemoryPressure(memoryInBytes); } END_EXTERNAL_ENTRYPOINT; @@ -849,7 +863,7 @@ namespace InteropLibImports HRESULT hr = S_OK; BEGIN_EXTERNAL_ENTRYPOINT(&hr) { - GCInterface::NewRemoveMemoryPressure(memoryInBytes); + GCInterface::RemoveMemoryPressure(memoryInBytes); } END_EXTERNAL_ENTRYPOINT; @@ -1017,14 +1031,13 @@ namespace InteropLibImports gc.implRef = NULL; // Use the globally registered implementation. gc.wrapperMaybeRef = NULL; // No supplied wrapper here. - bool unwrapIfManagedObjectWrapper = false; // Don't unwrap CCWs // Get wrapper for external object bool success = TryGetOrCreateObjectForComInstanceInternal( gc.implRef, externalComObject, externalObjectFlags, - unwrapIfManagedObjectWrapper, + ComWrappersScenario::TrackerSupportGlobalInstance, gc.wrapperMaybeRef, &gc.objRef); @@ -1036,6 +1049,7 @@ namespace InteropLibImports gc.implRef, gc.objRef, trackerTargetFlags, + ComWrappersScenario::TrackerSupportGlobalInstance, trackerTarget); if (!success) @@ -1220,6 +1234,7 @@ BOOL QCALLTYPE ComWrappersNative::TryGetOrCreateComInterfaceForObject( ObjectToOBJECTREF(*comWrappersImpl.m_ppObject), ObjectToOBJECTREF(*instance.m_ppObject), (CreateComInterfaceFlags)flags, + ComWrappersScenario::Instance, wrapper); } @@ -1256,13 +1271,12 @@ BOOL QCALLTYPE ComWrappersNative::TryGetOrCreateObjectForComInstance( { GCX_COOP(); - bool unwrapIfManagedObjectWrapper = false; // Don't unwrap CCWs OBJECTREF newObj; success = TryGetOrCreateObjectForComInstanceInternal( ObjectToOBJECTREF(*comWrappersImpl.m_ppObject), identity, (CreateObjectFlags)flags, - unwrapIfManagedObjectWrapper, + ComWrappersScenario::Instance, ObjectToOBJECTREF(*wrapperMaybe.m_ppObject), &newObj); @@ -1369,20 +1383,19 @@ void ComWrappersNative::MarkWrapperAsComActivated(_In_ IUnknown* wrapperMaybe) _ASSERTE(SUCCEEDED(hr) || hr == E_INVALIDARG); } -void QCALLTYPE GlobalComWrappers::SetGlobalInstanceRegistered() +void QCALLTYPE GlobalComWrappersForMarshalling::SetGlobalInstanceRegisteredForMarshalling() { - // QCALL contracts are not used here because the managed declaration - // uses the SuppressGCTransition attribute + QCALL_CONTRACT_NO_GC_TRANSITION; - _ASSERTE(!g_IsGlobalComWrappersRegistered); - g_IsGlobalComWrappersRegistered = true; + _ASSERTE(!g_IsGlobalComWrappersRegisteredForMarshalling); + g_IsGlobalComWrappersRegisteredForMarshalling = true; } -bool GlobalComWrappers::TryGetOrCreateComInterfaceForObject( +bool GlobalComWrappersForMarshalling::TryGetOrCreateComInterfaceForObject( _In_ OBJECTREF instance, _Outptr_ void** wrapperRaw) { - if (!g_IsGlobalComWrappersRegistered) + if (!g_IsGlobalComWrappersRegisteredForMarshalling) return false; // Switch to Cooperative mode since object references @@ -1397,18 +1410,28 @@ bool GlobalComWrappers::TryGetOrCreateComInterfaceForObject( NULL, instance, flags, + ComWrappersScenario::MarshallingGlobalInstance, wrapperRaw); } } -bool GlobalComWrappers::TryGetOrCreateObjectForComInstance( +bool GlobalComWrappersForMarshalling::TryGetOrCreateObjectForComInstance( _In_ IUnknown* externalComObject, _In_ INT32 objFromComIPFlags, _Out_ OBJECTREF* objRef) { - if (!g_IsGlobalComWrappersRegistered) + if (!g_IsGlobalComWrappersRegisteredForMarshalling) return false; + // Determine the true identity of the object + SafeComHolder identity; + { + GCX_PREEMP(); + + HRESULT hr = externalComObject->QueryInterface(IID_IUnknown, &identity); + _ASSERTE(hr == S_OK); + } + // Switch to Cooperative mode since object references // are being manipulated. { @@ -1418,21 +1441,120 @@ bool GlobalComWrappers::TryGetOrCreateObjectForComInstance( if ((objFromComIPFlags & ObjFromComIP::UNIQUE_OBJECT) != 0) flags |= CreateObjectFlags::CreateObjectFlags_UniqueInstance; - // For implicit usage of ComWrappers (i.e. automatically called by the runtime when there is a global instance), - // unwrap CCWs to allow for round-tripping object -> COM instance -> object. - bool unwrapIfManagedObjectWrapper = true; - // Passing NULL as the ComWrappers implementation indicates using the globally registered instance return TryGetOrCreateObjectForComInstanceInternal( NULL /*comWrappersImpl*/, - externalComObject, + identity, (CreateObjectFlags)flags, - unwrapIfManagedObjectWrapper, + ComWrappersScenario::MarshallingGlobalInstance, NULL /*wrapperMaybe*/, objRef); } } +void QCALLTYPE GlobalComWrappersForTrackerSupport::SetGlobalInstanceRegisteredForTrackerSupport() +{ + QCALL_CONTRACT_NO_GC_TRANSITION; + + _ASSERTE(!g_IsGlobalComWrappersRegisteredForTrackerSupport); + g_IsGlobalComWrappersRegisteredForTrackerSupport = true; +} + +bool GlobalComWrappersForTrackerSupport::TryGetOrCreateComInterfaceForObject( + _In_ OBJECTREF instance, + _Outptr_ void** wrapperRaw) +{ + CONTRACTL + { + THROWS; + MODE_COOPERATIVE; + } + CONTRACTL_END; + + if (!g_IsGlobalComWrappersRegisteredForTrackerSupport) + return false; + + // Passing NULL as the ComWrappers implementation indicates using the globally registered instance + return TryGetOrCreateComInterfaceForObjectInternal( + NULL, + instance, + CreateComInterfaceFlags::CreateComInterfaceFlags_TrackerSupport, + ComWrappersScenario::TrackerSupportGlobalInstance, + wrapperRaw); +} + +bool GlobalComWrappersForTrackerSupport::TryGetOrCreateObjectForComInstance( + _In_ IUnknown* externalComObject, + _Out_ OBJECTREF* objRef) +{ + CONTRACTL + { + THROWS; + MODE_COOPERATIVE; + } + CONTRACTL_END; + + if (!g_IsGlobalComWrappersRegisteredForTrackerSupport) + return false; + + // Determine the true identity of the object + SafeComHolder identity; + { + GCX_PREEMP(); + + HRESULT hr = externalComObject->QueryInterface(IID_IUnknown, &identity); + _ASSERTE(hr == S_OK); + } + + // Passing NULL as the ComWrappers implementation indicates using the globally registered instance + return TryGetOrCreateObjectForComInstanceInternal( + NULL /*comWrappersImpl*/, + identity, + CreateObjectFlags::CreateObjectFlags_TrackerObject, + ComWrappersScenario::TrackerSupportGlobalInstance, + NULL /*wrapperMaybe*/, + objRef); +} + +IUnknown* ComWrappersNative::GetIdentityForObject(_In_ OBJECTREF* objectPROTECTED, _In_ REFIID riid) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_COOPERATIVE; + PRECONDITION(CheckPointer(objectPROTECTED)); + } + CONTRACTL_END; + + ASSERT_PROTECTED(objectPROTECTED); + + SyncBlock* syncBlock = (*objectPROTECTED)->PassiveGetSyncBlock(); + if (syncBlock == nullptr) + { + return nullptr; + } + + InteropSyncBlockInfo* interopInfo = syncBlock->GetInteropInfoNoCreate(); + if (interopInfo == nullptr) + { + return nullptr; + } + + void* context; + if (interopInfo->TryGetExternalComObjectContext(&context)) + { + IUnknown* identity = reinterpret_cast(reinterpret_cast(context)->Identity); + GCX_PREEMP(); + IUnknown* result; + if (SUCCEEDED(identity->QueryInterface(riid, (void**)&result))) + { + return result; + } + } + return nullptr; +} + #endif // FEATURE_COMWRAPPERS void Interop::OnGCStarted(_In_ int nCondemnedGeneration) diff --git a/src/coreclr/src/vm/interoplibinterface.h b/src/coreclr/src/vm/interoplibinterface.h index 2985412db4b29e..3e5abda54cd6ae 100644 --- a/src/coreclr/src/vm/interoplibinterface.h +++ b/src/coreclr/src/vm/interoplibinterface.h @@ -37,16 +37,20 @@ class ComWrappersNative public: // COM activation static void MarkWrapperAsComActivated(_In_ IUnknown* wrapperMaybe); + +public: // Unwrapping support + static IUnknown* GetIdentityForObject(_In_ OBJECTREF* objectPROTECTED, _In_ REFIID riid); }; -class GlobalComWrappers +class GlobalComWrappersForMarshalling { public: - // Native QCall for the ComWrappers managed type to indicate a global instance is registered - // This should be set if the private static member representing the global instance on ComWrappers is non-null. - static void QCALLTYPE SetGlobalInstanceRegistered(); + // Native QCall for the ComWrappers managed type to indicate a global instance + // is registered for marshalling. This should be set if the private static member + // representing the global instance for marshalling on ComWrappers is non-null. + static void QCALLTYPE SetGlobalInstanceRegisteredForMarshalling(); -public: // Functions operating on a registered global instance +public: // Functions operating on a registered global instance for marshalling static bool TryGetOrCreateComInterfaceForObject( _In_ OBJECTREF instance, _Outptr_ void** wrapperRaw); @@ -57,6 +61,25 @@ class GlobalComWrappers _Out_ OBJECTREF* objRef); }; + +class GlobalComWrappersForTrackerSupport +{ +public: + // Native QCall for the ComWrappers managed type to indicate a global instance + // is registered for tracker support. This should be set if the private static member + // representing the global instance for tracker support on ComWrappers is non-null. + static void QCALLTYPE SetGlobalInstanceRegisteredForTrackerSupport(); + +public: // Functions operating on a registered global instance for tracker support + static bool TryGetOrCreateComInterfaceForObject( + _In_ OBJECTREF instance, + _Outptr_ void** wrapperRaw); + + static bool TryGetOrCreateObjectForComInstance( + _In_ IUnknown* externalComObject, + _Out_ OBJECTREF* objRef); +}; + #endif // FEATURE_COMWRAPPERS class Interop diff --git a/src/coreclr/src/vm/interoputil.cpp b/src/coreclr/src/vm/interoputil.cpp index fc87cf9277d538..4d705a56250ba2 100644 --- a/src/coreclr/src/vm/interoputil.cpp +++ b/src/coreclr/src/vm/interoputil.cpp @@ -288,17 +288,17 @@ static const BinderMethodID s_stubsDisposableToClosable[] = METHOD__IDISPOSABLE_TO_ICLOSABLE_ADAPTER__CLOSE }; -DEFINE_ASM_QUAL_TYPE_NAME(NCCWINRT_ASM_QUAL_TYPE_NAME, g_INotifyCollectionChanged_WinRTName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken); -DEFINE_ASM_QUAL_TYPE_NAME(NCCMA_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedToManagedAdapterName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken); -DEFINE_ASM_QUAL_TYPE_NAME(NCCWA_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedToWinRTAdapterName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken); -DEFINE_ASM_QUAL_TYPE_NAME(NPCWINRT_ASM_QUAL_TYPE_NAME, g_INotifyPropertyChanged_WinRTName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken); -DEFINE_ASM_QUAL_TYPE_NAME(NPCMA_ASM_QUAL_TYPE_NAME, g_NotifyPropertyChangedToManagedAdapterName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken); -DEFINE_ASM_QUAL_TYPE_NAME(NPCWA_ASM_QUAL_TYPE_NAME, g_NotifyPropertyChangedToWinRTAdapterName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken); -DEFINE_ASM_QUAL_TYPE_NAME(CMDWINRT_ASM_QUAL_TYPE_NAME, g_ICommand_WinRTName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken); -DEFINE_ASM_QUAL_TYPE_NAME(CMDMA_ASM_QUAL_TYPE_NAME, g_ICommandToManagedAdapterName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken); -DEFINE_ASM_QUAL_TYPE_NAME(CMDWA_ASM_QUAL_TYPE_NAME, g_ICommandToWinRTAdapterName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken); -DEFINE_ASM_QUAL_TYPE_NAME(NCCEHWINRT_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedEventHandler_WinRT, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken); -DEFINE_ASM_QUAL_TYPE_NAME(PCEHWINRT_ASM_QUAL_TYPE_NAME, g_PropertyChangedEventHandler_WinRT_Name, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken); +DEFINE_ASM_QUAL_TYPE_NAME(NCCWINRT_ASM_QUAL_TYPE_NAME, g_INotifyCollectionChanged_WinRTName, g_SystemRuntimeWindowsRuntimeAsmName); +DEFINE_ASM_QUAL_TYPE_NAME(NCCMA_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedToManagedAdapterName, g_SystemRuntimeWindowsRuntimeAsmName); +DEFINE_ASM_QUAL_TYPE_NAME(NCCWA_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedToWinRTAdapterName, g_SystemRuntimeWindowsRuntimeAsmName); +DEFINE_ASM_QUAL_TYPE_NAME(NPCWINRT_ASM_QUAL_TYPE_NAME, g_INotifyPropertyChanged_WinRTName, g_SystemRuntimeWindowsRuntimeAsmName); +DEFINE_ASM_QUAL_TYPE_NAME(NPCMA_ASM_QUAL_TYPE_NAME, g_NotifyPropertyChangedToManagedAdapterName, g_SystemRuntimeWindowsRuntimeAsmName); +DEFINE_ASM_QUAL_TYPE_NAME(NPCWA_ASM_QUAL_TYPE_NAME, g_NotifyPropertyChangedToWinRTAdapterName, g_SystemRuntimeWindowsRuntimeAsmName); +DEFINE_ASM_QUAL_TYPE_NAME(CMDWINRT_ASM_QUAL_TYPE_NAME, g_ICommand_WinRTName, g_SystemRuntimeWindowsRuntimeAsmName); +DEFINE_ASM_QUAL_TYPE_NAME(CMDMA_ASM_QUAL_TYPE_NAME, g_ICommandToManagedAdapterName, g_SystemRuntimeWindowsRuntimeAsmName); +DEFINE_ASM_QUAL_TYPE_NAME(CMDWA_ASM_QUAL_TYPE_NAME, g_ICommandToWinRTAdapterName, g_SystemRuntimeWindowsRuntimeAsmName); +DEFINE_ASM_QUAL_TYPE_NAME(NCCEHWINRT_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedEventHandler_WinRT, g_SystemRuntimeWindowsRuntimeAsmName); +DEFINE_ASM_QUAL_TYPE_NAME(PCEHWINRT_ASM_QUAL_TYPE_NAME, g_PropertyChangedEventHandler_WinRT_Name, g_SystemRuntimeWindowsRuntimeAsmName); const WinRTInterfaceRedirector::NonMscorlibRedirectedInterfaceInfo WinRTInterfaceRedirector::s_rNonMscorlibInterfaceInfos[3] = { diff --git a/src/coreclr/src/vm/interoputil.h b/src/coreclr/src/vm/interoputil.h index 5072cdbf6c544d..500badaab7dd3f 100644 --- a/src/coreclr/src/vm/interoputil.h +++ b/src/coreclr/src/vm/interoputil.h @@ -479,7 +479,7 @@ class WinRTGuidGenerator IUnknown* MarshalObjectToInterface(OBJECTREF* ppObject, MethodTable* pItfMT, MethodTable* pClassMT, DWORD dwFlags); void UnmarshalObjectFromInterface(OBJECTREF *ppObjectDest, IUnknown **ppUnkSrc, MethodTable *pItfMT, MethodTable *pClassMT, DWORD dwFlags); -#define DEFINE_ASM_QUAL_TYPE_NAME(varname, typename, asmname, version, publickeytoken) static const char varname##[] = { typename##", "##asmname##", Culture=neutral, PublicKeyToken="##publickeytoken##", Version="##version }; +#define DEFINE_ASM_QUAL_TYPE_NAME(varname, typename, asmname) static const char varname##[] = { typename##", "##asmname## }; class ICOMInterfaceMarshalerCallback; void GetNativeWinRTFactoryObject(MethodTable *pMT, Thread *pThread, MethodTable *pFactoryIntfMT, BOOL bNeedUniqueRCW, ICOMInterfaceMarshalerCallback *pCallback, OBJECTREF *prefFactory); diff --git a/src/coreclr/src/vm/ipcstreamfactory.cpp b/src/coreclr/src/vm/ipcstreamfactory.cpp new file mode 100644 index 00000000000000..33d36e93de5baa --- /dev/null +++ b/src/coreclr/src/vm/ipcstreamfactory.cpp @@ -0,0 +1,206 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "common.h" +#include "diagnosticsprotocol.h" +#include "ipcstreamfactory.h" + +#ifdef FEATURE_PERFTRACING + +CQuickArrayList IpcStreamFactory::s_rgpConnectionStates = CQuickArrayList(); +Volatile IpcStreamFactory::s_isShutdown = false; + +bool IpcStreamFactory::ClientConnectionState::GetIpcPollHandle(IpcStream::DiagnosticsIpc::IpcPollHandle *pIpcPollHandle, ErrorCallback callback) +{ + if (_pStream == nullptr) + { + // cache is empty, reconnect, e.g., there was a disconnect + IpcStream *pConnection = _pIpc->Connect(callback); + if (pConnection == nullptr) + { + if (callback != nullptr) + callback("Failed to connect to client connection", -1); + return false; + } + if (!DiagnosticsIpc::SendIpcAdvertise_V1(pConnection)) + { + if (callback != nullptr) + callback("Failed to send advertise message", -1); + delete pConnection; + return false; + } + + _pStream = pConnection; + } + *pIpcPollHandle = { nullptr, _pStream, 0, this }; + return true; +} + +IpcStream *IpcStreamFactory::ClientConnectionState::GetConnectedStream(ErrorCallback callback) +{ + IpcStream *pStream = _pStream; + _pStream = nullptr; + return pStream; +} + +void IpcStreamFactory::ClientConnectionState::Reset(ErrorCallback callback) +{ + delete _pStream; + _pStream = nullptr; +} + +bool IpcStreamFactory::ServerConnectionState::GetIpcPollHandle(IpcStream::DiagnosticsIpc::IpcPollHandle *pIpcPollHandle, ErrorCallback callback) +{ + *pIpcPollHandle = { _pIpc, nullptr, 0, this }; + return true; +} + +IpcStream *IpcStreamFactory::ServerConnectionState::GetConnectedStream(ErrorCallback callback) +{ + return _pIpc->Accept(callback); +} + +// noop for server +void IpcStreamFactory::ServerConnectionState::Reset(ErrorCallback) +{ + return; +} + +bool IpcStreamFactory::CreateServer(const char *const pIpcName, ErrorCallback callback) +{ + IpcStream::DiagnosticsIpc *pIpc = IpcStream::DiagnosticsIpc::Create(pIpcName, IpcStream::DiagnosticsIpc::ConnectionMode::SERVER, callback); + if (pIpc != nullptr) + { + if (pIpc->Listen(callback)) + { + s_rgpConnectionStates.Push(new ServerConnectionState(pIpc)); + return true; + } + else + { + delete pIpc; + return false; + } + } + else + { + return false; + } +} + +bool IpcStreamFactory::CreateClient(const char *const pIpcName, ErrorCallback callback) +{ + IpcStream::DiagnosticsIpc *pIpc = IpcStream::DiagnosticsIpc::Create(pIpcName, IpcStream::DiagnosticsIpc::ConnectionMode::CLIENT, callback); + if (pIpc != nullptr) + { + s_rgpConnectionStates.Push(new ClientConnectionState(pIpc)); + return true; + } + else + { + return false; + } +} + +bool IpcStreamFactory::HasActiveConnections() +{ + return !s_isShutdown && s_rgpConnectionStates.Size() > 0; +} + +void IpcStreamFactory::CloseConnections(ErrorCallback callback) +{ + for (uint32_t i = 0; i < (uint32_t)s_rgpConnectionStates.Size(); i++) + s_rgpConnectionStates[i]->Close(callback); +} + +void IpcStreamFactory::Shutdown(ErrorCallback callback) +{ + if (s_isShutdown) + return; + s_isShutdown = true; + for (uint32_t i = 0; i < (uint32_t)s_rgpConnectionStates.Size(); i++) + s_rgpConnectionStates[i]->Close(true, callback); +} + +// helper function for getting timeout +int32_t IpcStreamFactory::GetNextTimeout(int32_t currentTimeoutMs) +{ + if (currentTimeoutMs == s_pollTimeoutInfinite) + { + return s_pollTimeoutMinMs; + } + else + { + return (currentTimeoutMs >= s_pollTimeoutMaxMs) ? + s_pollTimeoutMaxMs : + (int32_t)((float)currentTimeoutMs * s_pollTimeoutFalloffFactor); + } +} + +IpcStream *IpcStreamFactory::GetNextAvailableStream(ErrorCallback callback) +{ + IpcStream *pStream = nullptr; + CQuickArrayList rgIpcPollHandles; + + int32_t pollTimeoutMs = s_pollTimeoutInfinite; + bool fConnectSuccess = true; + uint32_t nPollAttempts = 0; + + while (pStream == nullptr) + { + fConnectSuccess = true; + for (uint32_t i = 0; i < (uint32_t)s_rgpConnectionStates.Size(); i++) + { + IpcStream::DiagnosticsIpc::IpcPollHandle pollHandle = {}; + if (s_rgpConnectionStates[i]->GetIpcPollHandle(&pollHandle, callback)) + { + rgIpcPollHandles.Push(pollHandle); + } + else + { + fConnectSuccess = false; + } + } + + pollTimeoutMs = fConnectSuccess ? + s_pollTimeoutInfinite : + GetNextTimeout(pollTimeoutMs); + + int32_t retval = IpcStream::DiagnosticsIpc::Poll(rgIpcPollHandles.Ptr(), (uint32_t)rgIpcPollHandles.Size(), pollTimeoutMs, callback); + nPollAttempts++; + STRESS_LOG2(LF_DIAGNOSTICS_PORT, LL_INFO10, "IpcStreamFactory::GetNextAvailableStream - Poll attempt: %d, timeout: %dms.\n", nPollAttempts, pollTimeoutMs); + + if (retval != 0) + { + for (uint32_t i = 0; i < (uint32_t)rgIpcPollHandles.Size(); i++) + { + switch ((IpcStream::DiagnosticsIpc::PollEvents)rgIpcPollHandles[i].revents) + { + case IpcStream::DiagnosticsIpc::PollEvents::HANGUP: + ((ConnectionState*)(rgIpcPollHandles[i].pUserData))->Reset(callback); + STRESS_LOG1(LF_DIAGNOSTICS_PORT, LL_INFO10, "IpcStreamFactory::GetNextAvailableStream - Poll attempt: %d, connection hung up.\n", nPollAttempts); + pollTimeoutMs = s_pollTimeoutMinMs; + break; + case IpcStream::DiagnosticsIpc::PollEvents::SIGNALED: + if (pStream == nullptr) // only use first signaled stream; will get others on subsequent calls + pStream = ((ConnectionState*)(rgIpcPollHandles[i].pUserData))->GetConnectedStream(callback); + break; + case IpcStream::DiagnosticsIpc::PollEvents::ERR: + return nullptr; + default: + // TODO: Error handling + break; + } + } + } + + // clear the view + while (rgIpcPollHandles.Size() > 0) + rgIpcPollHandles.Pop(); + } + + return pStream; +} + +#endif // FEATURE_PERFTRACING \ No newline at end of file diff --git a/src/coreclr/src/vm/ipcstreamfactory.h b/src/coreclr/src/vm/ipcstreamfactory.h new file mode 100644 index 00000000000000..04d92bef846282 --- /dev/null +++ b/src/coreclr/src/vm/ipcstreamfactory.h @@ -0,0 +1,103 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#ifndef __IPC_STREAM_FACTORY_H__ +#define __IPC_STREAM_FACTORY_H__ + +#ifdef FEATURE_PERFTRACING + +#include "diagnosticsipc.h" + +class IpcStreamFactory +{ +public: + struct ConnectionState + { + public: + ConnectionState(IpcStream::DiagnosticsIpc *pIpc) : + _pIpc(pIpc), + _pStream(nullptr) + { } + + // returns a pollable handle and performs any preparation required + // e.g., as a side-effect, will connect and advertise on reverse connections + virtual bool GetIpcPollHandle(IpcStream::DiagnosticsIpc::IpcPollHandle *pIpcPollHandle, ErrorCallback callback = nullptr) = 0; + + // Returns the signaled stream in a usable state + virtual IpcStream *GetConnectedStream(ErrorCallback callback = nullptr) = 0; + + // Resets the connection in the event of a hangup + virtual void Reset(ErrorCallback callback = nullptr) = 0; + + // closes the underlying connections + // only performs minimal cleanup if isShutdown==true + void Close(bool isShutdown = false, ErrorCallback callback = nullptr) + { + if (_pIpc != nullptr) + _pIpc->Close(isShutdown, callback); + if (_pStream != nullptr && !isShutdown) + _pStream->Close(callback); + } + + protected: + IpcStream::DiagnosticsIpc *_pIpc; + IpcStream *_pStream; + }; + + struct ClientConnectionState : public ConnectionState + { + ClientConnectionState(IpcStream::DiagnosticsIpc *pIpc) : ConnectionState(pIpc) { } + + // returns a pollable handle and performs any preparation required + bool GetIpcPollHandle(IpcStream::DiagnosticsIpc::IpcPollHandle *pIpcPollHandle, ErrorCallback callback = nullptr) override; + + // Returns the signaled stream in a usable state + IpcStream *GetConnectedStream(ErrorCallback callback = nullptr) override; + + // Resets the connection in the event of a hangup + void Reset(ErrorCallback callback = nullptr) override; + }; + + struct ServerConnectionState : public ConnectionState + { + ServerConnectionState(IpcStream::DiagnosticsIpc *pIpc) : ConnectionState(pIpc) { } + + // returns a pollable handle and performs any preparation required + bool GetIpcPollHandle(IpcStream::DiagnosticsIpc::IpcPollHandle *pIpcPollHandle, ErrorCallback callback = nullptr) override; + + // Returns the signaled stream in a usable state + IpcStream *GetConnectedStream(ErrorCallback callback = nullptr) override; + + // Resets the connection in the event of a hangup + void Reset(ErrorCallback callback = nullptr) override; + }; + + static bool CreateServer(const char *const pIpcName, ErrorCallback = nullptr); + static bool CreateClient(const char *const pIpcName, ErrorCallback = nullptr); + static IpcStream *GetNextAvailableStream(ErrorCallback = nullptr); + static bool HasActiveConnections(); + static void CloseConnections(ErrorCallback callback = nullptr); + static void Shutdown(ErrorCallback callback = nullptr); +private: + static CQuickArrayList s_rgpConnectionStates; + static Volatile s_isShutdown; + + // Polling timeout semantics + // If client connection is opted in + // and connection succeeds => set timeout to infinite + // and connection fails => set timeout to minimum and scale by falloff factor + // else => set timeout to -1 (infinite) + // + // If an agent closes its socket while we're still connected, + // Poll will return and let us know which connection hung up + static int32_t GetNextTimeout(int32_t currentTimeoutMs); + constexpr static float s_pollTimeoutFalloffFactor = 1.25; + constexpr static int32_t s_pollTimeoutInfinite = -1; + constexpr static int32_t s_pollTimeoutMinMs = 10; + constexpr static int32_t s_pollTimeoutMaxMs = 500; +}; + +#endif // FEATURE_PERFTRACING + +#endif // __IPC_STREAM_FACTORY_H__ \ No newline at end of file diff --git a/src/coreclr/src/vm/jithelpers.cpp b/src/coreclr/src/vm/jithelpers.cpp index 63d61ae4740426..38a6af10e6dfa7 100644 --- a/src/coreclr/src/vm/jithelpers.cpp +++ b/src/coreclr/src/vm/jithelpers.cpp @@ -4185,23 +4185,6 @@ HCIMPL1(void, IL_Throw, Object* obj) } } -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - if (!g_pConfig->LegacyCorruptedStateExceptionsPolicy()) - { - // Within the VM, we could have thrown and caught a managed exception. This is done by - // RaiseTheException that will flag that exception's corruption severity to be used - // incase it leaks out to managed code. - // - // If it does not leak out, but ends up calling into managed code that throws, - // we will come here. In such a case, simply reset the corruption-severity - // since we want the exception being thrown to have its correct severity set - // when CLR's managed code exception handler sets it. - - ThreadExceptionState *pExState = GetThread()->GetExceptionState(); - pExState->SetLastActiveExceptionCorruptionSeverity(NotSet); - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS - RaiseTheExceptionInternalOnly(oref, FALSE); HELPER_METHOD_FRAME_END(); @@ -4538,7 +4521,7 @@ void DoJITFailFast () GetClrInstanceId()); } - TerminateProcess(GetCurrentProcess(), STATUS_STACK_BUFFER_OVERRUN); + CrashDumpAndTerminateProcess(STATUS_STACK_BUFFER_OVERRUN); #endif // !TARGET_UNIX } @@ -5534,265 +5517,6 @@ void InitJITHelpers2() g_pJitGenericHandleCache = tempGenericHandleCache.Extract(); } -#if defined(TARGET_AMD64) || defined(TARGET_ARM) - -NOINLINE void DoCopy(CONTEXT * ctx, void * pvTempStack, size_t cbTempStack, Thread * pThread, Frame * pNewFrame) -{ - // We need to ensure that copying pvTempStack onto our stack will not in - // *ANY* way trash the context record (or our pointer to it) that we need - // in order to restore context - _ASSERTE((DWORD_PTR)&ctx + sizeof(ctx) < (DWORD_PTR)GetSP(ctx)); - - CONTEXT ctx2; - if ((DWORD_PTR)ctx + sizeof(*ctx) > (DWORD_PTR)GetSP(ctx)) - { - // The context record is in danger, copy it down - _ASSERTE((DWORD_PTR)&ctx2 + sizeof(ctx2) < (DWORD_PTR)GetSP(ctx)); - ctx2 = *ctx; - - // Clear any context that we didn't copy... - ctx2.ContextFlags &= CONTEXT_ALL; - ctx = &ctx2; - } - - _ASSERTE((DWORD_PTR)ctx + sizeof(*ctx) <= (DWORD_PTR)GetSP(ctx)); - - // DevDiv 189140 - use memmove because source and dest might overlap. - memmove((void*)GetSP(ctx), pvTempStack, cbTempStack); - - if (pNewFrame != NULL) - { - // Now that the memmove above is complete, pNewFrame is actually pointing at a - // TailCallFrame, and not garbage. So it's safe to add pNewFrame to the Frame - // chain. - _ASSERTE(pThread != NULL); - pThread->SetFrame(pNewFrame); - } - - RtlRestoreContext(ctx, NULL); -} - -// -// Mostly Architecture-agnostic RtlVirtualUnwind-based tail call helper... -// -// Can't use HCIMPL macro because it requires unwind, and this method *NEVER* unwinds. -// - -#define INVOKE_COPY_ARGS_HELPER(helperFunc, arg1, arg2, arg3, arg4) ((pfnCopyArgs)helperFunc)(arg1, arg2, arg3, arg4) -void F_CALL_VA_CONV JIT_TailCall(PCODE copyArgs, PCODE target, ...) -{ - // Can't have a regular contract because we would never pop it - // We only throw a stack overflow if needed, and we can't handle - // a GC because the incoming parameters are totally unprotected. - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_MODE_COOPERATIVE - -#ifndef TARGET_UNIX - - Thread *pThread = GetThread(); - -#ifdef FEATURE_HIJACK - // We can't crawl the stack of a thread that currently has a hijack pending - // (since the hijack routine won't be recognized by any code manager). So we - // undo any hijack, the EE will re-attempt it later. - pThread->UnhijackThread(); -#endif - - ULONG_PTR establisherFrame = 0; - PVOID handlerData = NULL; - CONTEXT ctx; - - // Unwind back to our caller in managed code - static PT_RUNTIME_FUNCTION my_pdata; - static ULONG_PTR my_imagebase; - - ctx.ContextFlags = CONTEXT_ALL; - RtlCaptureContext(&ctx); - - if (!VolatileLoadWithoutBarrier(&my_imagebase)) { - ULONG_PTR imagebase = 0; - my_pdata = RtlLookupFunctionEntry(GetIP(&ctx), &imagebase, NULL); - InterlockedExchangeT(&my_imagebase, imagebase); - } - - RtlVirtualUnwind(UNW_FLAG_NHANDLER, my_imagebase, GetIP(&ctx), my_pdata, &ctx, &handlerData, - &establisherFrame, NULL); - - EECodeInfo codeInfo(GetIP(&ctx)); - - // Now unwind back to our caller's caller - establisherFrame = 0; - RtlVirtualUnwind(UNW_FLAG_NHANDLER, codeInfo.GetModuleBase(), GetIP(&ctx), codeInfo.GetFunctionEntry(), &ctx, &handlerData, - &establisherFrame, NULL); - - va_list args; - - // Compute the space needed for arguments - va_start(args, target); - - ULONG_PTR pGCLayout = 0; - size_t cbArgArea = INVOKE_COPY_ARGS_HELPER(copyArgs, args, NULL, NULL, (size_t)&pGCLayout); - - va_end(args); - - // reset (in case the helper walked them) - va_start(args, target); - - // Fake call frame (if needed) - size_t cbCopyFrame = 0; - bool fCopyDown = false; - BYTE rgFrameBuffer[sizeof(FrameWithCookie)]; - Frame * pNewFrame = NULL; - -#if defined(TARGET_AMD64) -# define STACK_ADJUST_FOR_RETURN_ADDRESS (sizeof(void*)) -# define STACK_ALIGN_MASK (0xF) -#elif defined(TARGET_ARM) -# define STACK_ADJUST_FOR_RETURN_ADDRESS (0) -# define STACK_ALIGN_MASK (0x7) -#else -#error "Unknown tail call architecture" -#endif - - // figure out if we can re-use an existing TailCallHelperStub - // or if we need to create a new one. - if ((void*)GetIP(&ctx) == JIT_TailCallHelperStub_ReturnAddress) { - TailCallFrame * pCurrentFrame = TailCallFrame::GetFrameFromContext(&ctx); - _ASSERTE(pThread->GetFrame() == pCurrentFrame); - // The caller was tail called, so we can re-use that frame - // See if we need to enlarge the ArgArea - // This can potentially enlarge cbArgArea to the size of the - // existing TailCallFrame. - const size_t endOfFrame = (size_t)pCurrentFrame - (size_t)sizeof(GSCookie); - size_t cbOldArgArea = (endOfFrame - GetSP(&ctx)); - if (cbOldArgArea >= cbArgArea) { - cbArgArea = cbOldArgArea; - } - else { - SetSP(&ctx, (endOfFrame - cbArgArea)); - fCopyDown = true; - } - - // Reset the GCLayout - pCurrentFrame->SetGCLayout((TADDR)pGCLayout); - - // We're jumping to the new method, not calling it - // so make room for the return address that the 'call' - // would have pushed. - SetSP(&ctx, GetSP(&ctx) - STACK_ADJUST_FOR_RETURN_ADDRESS); - } - else { - // Create a fake fixed frame as if the new method was called by - // TailCallHelperStub asm stub and did an - // alloca, then called the target method. - cbCopyFrame = sizeof(rgFrameBuffer); - FrameWithCookie * CookieFrame = new (rgFrameBuffer) FrameWithCookie(&ctx, pThread); - TailCallFrame * tailCallFrame = &*CookieFrame; - - tailCallFrame->SetGCLayout((TADDR)pGCLayout); - pNewFrame = TailCallFrame::AdjustContextForTailCallHelperStub(&ctx, cbArgArea, pThread); - fCopyDown = true; - - // Eventually, we'll add pNewFrame to our frame chain, but don't do it yet. It's - // pointing to the place on the stack where the TailCallFrame contents WILL be, - // but aren't there yet. In order to keep the stack walkable by profilers, wait - // until the contents are moved over properly (inside DoCopy), and then add - // pNewFrame onto the frame chain. - } - - // The stack should be properly aligned, modulo the pushed return - // address (at least on x64) - _ASSERTE((GetSP(&ctx) & STACK_ALIGN_MASK) == STACK_ADJUST_FOR_RETURN_ADDRESS); - - // Set the target pointer so we land there when we restore the context - SetIP(&ctx, (PCODE)target); - - // Begin creating the new stack frame and copying arguments - size_t cbTempStack = cbCopyFrame + cbArgArea + STACK_ADJUST_FOR_RETURN_ADDRESS; - - // If we're going to have to overwrite some of our incoming argument slots - // then do a double-copy, first to temporary copy below us on the stack and - // then back up to the real stack. - void * pvTempStack; - if (!fCopyDown && (((ULONG_PTR)args + cbArgArea) < GetSP(&ctx))) { - - // - // After this our stack may no longer be walkable by the debugger!!! - // - - pvTempStack = (void*)GetSP(&ctx); - } - else { - fCopyDown = true; - - // Need to align properly for a return address (if it goes on the stack) - // - // AMD64 ONLY: - // _alloca produces 16-byte aligned buffers, but the return address, - // where our buffer 'starts' is off by 8, so make sure our buffer is - // off by 8. - // - pvTempStack = (BYTE*)_alloca(cbTempStack + STACK_ADJUST_FOR_RETURN_ADDRESS) + STACK_ADJUST_FOR_RETURN_ADDRESS; - } - - _ASSERTE(((size_t)pvTempStack & STACK_ALIGN_MASK) == STACK_ADJUST_FOR_RETURN_ADDRESS); - - // Start creating the new stack (bottom up) - BYTE * pbTempStackFill = (BYTE*)pvTempStack; - // Return address - if (STACK_ADJUST_FOR_RETURN_ADDRESS > 0) { - *((PVOID*)pbTempStackFill) = (PVOID)JIT_TailCallHelperStub_ReturnAddress; // return address - pbTempStackFill += STACK_ADJUST_FOR_RETURN_ADDRESS; - } - - // arguments - INVOKE_COPY_ARGS_HELPER(copyArgs, args, &ctx, (DWORD_PTR*)pbTempStackFill, cbArgArea); - - va_end(args); - - pbTempStackFill += cbArgArea; - - // frame (includes TailCallFrame) - if (cbCopyFrame > 0) { - _ASSERTE(cbCopyFrame == sizeof(rgFrameBuffer)); - memcpy(pbTempStackFill, rgFrameBuffer, cbCopyFrame); - pbTempStackFill += cbCopyFrame; - } - - // If this fires, check the math above, because we copied more than we should have - _ASSERTE((size_t)((pbTempStackFill - (BYTE*)pvTempStack)) == cbTempStack); - - // If this fires, it means we messed up the math and we're about to overwrite - // some of our locals which would be bad because we still need them to call - // RtlRestoreContext and pop the contract... - _ASSERTE(fCopyDown || ((DWORD_PTR)&ctx + sizeof(ctx) < (DWORD_PTR)GetSP(&ctx))); - - if (fCopyDown) { - // We've created a dummy stack below our frame and now we overwrite - // our own real stack. - - // - // After this our stack may no longer be walkable by the debugger!!! - // - - // This does the copy, adds pNewFrame to the frame chain, and calls RtlRestoreContext - DoCopy(&ctx, pvTempStack, cbTempStack, pThread, pNewFrame); - } - - RtlRestoreContext(&ctx, NULL); - -#undef STACK_ADJUST_FOR_RETURN_ADDRESS -#undef STACK_ALIGN_MASK - -#else // !TARGET_UNIX - PORTABILITY_ASSERT("TODO: Implement JIT_TailCall for PAL"); -#endif // !TARGET_UNIX - -} - -#endif // TARGET_AMD64 || TARGET_ARM - //======================================================================== // // JIT HELPERS LOGGING diff --git a/src/coreclr/src/vm/jitinterface.cpp b/src/coreclr/src/vm/jitinterface.cpp index f65cfe29dc1cb2..94f3d1865754d8 100644 --- a/src/coreclr/src/vm/jitinterface.cpp +++ b/src/coreclr/src/vm/jitinterface.cpp @@ -66,6 +66,12 @@ #include "perfmap.h" #endif +#ifdef FEATURE_PGO +#include "pgo.h" +#endif + +#include "tailcallhelp.h" + // The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro // @@ -97,6 +103,27 @@ GARY_IMPL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT); #else // DACCESS_COMPILE +uint64_t g_cbILJitted = 0; +uint32_t g_cMethodsJitted = 0; + +#ifndef CROSSGEN_COMPILE +FCIMPL0(INT64, GetJittedBytes) +{ + FCALL_CONTRACT; + + return g_cbILJitted; +} +FCIMPLEND + +FCIMPL0(INT32, GetJittedMethodsCount) +{ + FCALL_CONTRACT; + + return g_cMethodsJitted; +} +FCIMPLEND +#endif + /*********************************************************************/ inline CORINFO_MODULE_HANDLE GetScopeHandle(MethodDesc* method) @@ -2203,12 +2230,22 @@ unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs) MODE_PREEMPTIVE; } CONTRACTL_END; - unsigned result = 0; + unsigned result; JIT_TO_EE_TRANSITION(); TypeHandle VMClsHnd(clsHnd); + result = getClassGClayoutStatic(VMClsHnd, gcPtrs); + + EE_TO_JIT_TRANSITION(); + + return result; +} + +unsigned CEEInfo::getClassGClayoutStatic(TypeHandle VMClsHnd, BYTE* gcPtrs) +{ + unsigned result = 0; MethodTable* pMT = VMClsHnd.GetMethodTable(); if (VMClsHnd.IsNativeValueType()) @@ -2266,8 +2303,6 @@ unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs) } } - EE_TO_JIT_TRANSITION(); - return result; } @@ -5085,22 +5120,6 @@ void CEEInfo::getCallInfo( EX_THROW(EEMessageException, (kMissingMethodException, IDS_EE_MISSING_METHOD, W("?"))); } - // If this call is for a LDFTN and the target method has the NativeCallableAttribute, - // then validate it adheres to the limitations. - if ((flags & CORINFO_CALLINFO_LDFTN) && pMD->HasNativeCallableAttribute()) - { - if (!pMD->IsStatic()) - EX_THROW(EEResourceException, (kInvalidProgramException, W("InvalidProgram_NonStaticMethod"))); - - // No generic methods - if (pMD->HasClassOrMethodInstantiation()) - EX_THROW(EEResourceException, (kInvalidProgramException, W("InvalidProgram_GenericMethod"))); - - // Arguments - if (NDirect::MarshalingRequired(pMD, pMD->GetSig(), pMD->GetModule())) - EX_THROW(EEResourceException, (kInvalidProgramException, W("InvalidProgram_NonBlittableTypes"))); - } - TypeHandle exactType = TypeHandle(pResolvedToken->hClass); TypeHandle constrainedType; @@ -9213,9 +9232,9 @@ void CEEInfo::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn, // Deferring X86 support until a need is observed or // time permits investigation into all the potential issues. // https://github.com/dotnet/runtime/issues/33582 - if (pMD->HasNativeCallableAttribute()) + if (pMD->HasUnmanagedCallersOnlyAttribute()) { - pResult->addr = (void*)COMDelegate::ConvertToCallback(pMD); + pResult->addr = (void*)COMDelegate::ConvertToUnmanagedCallback(pMD); } else { @@ -11792,8 +11811,6 @@ HRESULT CEEJitInfo::allocMethodBlockCounts ( JIT_TO_EE_TRANSITION(); -#ifdef FEATURE_PREJIT - // We need to know the code size. Typically we can get the code size // from m_ILHeader. For dynamic methods, m_ILHeader will be NULL, so // for that case we need to use DynamicResolver to get the code size. @@ -11811,11 +11828,16 @@ HRESULT CEEJitInfo::allocMethodBlockCounts ( codeSize = m_ILHeader->GetCodeSize(); } +#ifdef FEATURE_PREJIT *pBlockCounts = m_pMethodBeingCompiled->GetLoaderModule()->AllocateMethodBlockCounts(m_pMethodBeingCompiled->GetMemberDef(), count, codeSize); hr = (*pBlockCounts != nullptr) ? S_OK : E_OUTOFMEMORY; #else // FEATURE_PREJIT +#ifdef FEATURE_PGO + hr = PgoManager::allocMethodBlockCounts(m_pMethodBeingCompiled, count, pBlockCounts, codeSize); +#else _ASSERTE(!"allocMethodBlockCounts not implemented on CEEJitInfo!"); hr = E_NOTIMPL; +#endif // !FEATURE_PGO #endif // !FEATURE_PREJIT EE_TO_JIT_TRANSITION(); @@ -11832,9 +11854,55 @@ HRESULT CEEJitInfo::getMethodBlockCounts ( UINT32 * pNumRuns ) { - LIMITED_METHOD_CONTRACT; + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + HRESULT hr = E_FAIL; + *pCount = 0; + *pBlockCounts = NULL; + *pNumRuns = 0; + + JIT_TO_EE_TRANSITION(); + +#ifdef FEATURE_PGO + + // For now, only return the info for the method being jitted. + // Will need to fix this to gain access to pgo data for inlinees. + MethodDesc* pMD = (MethodDesc*)ftnHnd; + + if (pMD == m_pMethodBeingCompiled) + { + unsigned codeSize = 0; + if (pMD->IsDynamicMethod()) + { + unsigned stackSize, ehSize; + CorInfoOptions options; + DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver(); + pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize); + } + else + { + codeSize = m_ILHeader->GetCodeSize(); + } + + hr = PgoManager::getMethodBlockCounts(pMD, codeSize, pCount, pBlockCounts, pNumRuns); + } + else + { + hr = E_NOTIMPL; + } + +#else _ASSERTE(!"getMethodBlockCounts not implemented on CEEJitInfo!"); - return E_NOTIMPL; + hr = E_NOTIMPL; +#endif + + EE_TO_JIT_TRANSITION(); + + return hr; } void CEEJitInfo::allocMem ( @@ -12429,8 +12497,17 @@ CorJitResult CallCompileMethodWithSEHWrapper(EEJitManager *jitMgr, } #if !defined(TARGET_X86) - if (ftn->HasNativeCallableAttribute()) + if (ftn->HasUnmanagedCallersOnlyAttribute()) + { + // If the stub was generated by the runtime, don't validate + // it for UnmanagedCallersOnlyAttribute usage. There are cases + // where the validation doesn't handle all of the cases we can + // permit during stub generation (e.g. Vector2 returns). + if (!ftn->IsILStub()) + COMDelegate::ThrowIfInvalidUnmanagedCallersOnlyUsage(ftn); + flags.Set(CORJIT_FLAGS::CORJIT_FLAG_REVERSE_PINVOKE); + } #endif // !TARGET_X86 return flags; @@ -12548,6 +12625,30 @@ CORJIT_FLAGS GetCompileFlags(MethodDesc * ftn, CORJIT_FLAGS flags, CORINFO_METHO flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO); } +#ifdef FEATURE_PGO + + if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_WritePGOData) > 0) + { + flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBINSTR); + } + else if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TieredPGO) > 0) + && flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_TIER0)) + { + flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBINSTR); + } + + if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ReadPGOData) > 0) + { + flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBOPT); + } + else if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TieredPGO) > 0) + && flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_TIER1)) + { + flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBOPT); + } + +#endif + return flags; } @@ -12582,10 +12683,6 @@ void ThrowExceptionForJit(HRESULT res) } // ******************************************************************** -#ifdef _DEBUG -LONG g_JitCount = 0; -#endif - //#define PERF_TRACK_METHOD_JITTIMES #ifdef TARGET_AMD64 BOOL g_fAllowRel32 = TRUE; @@ -12962,7 +13059,6 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, } #ifdef _DEBUG - FastInterlockIncrement(&g_JitCount); static BOOL fHeartbeat = -1; if (fHeartbeat == -1) @@ -12972,6 +13068,9 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config, printf("."); #endif // _DEBUG + FastInterlockExchangeAddLong((LONG64*)&g_cbILJitted, methodInfo.ILCodeSize); + FastInterlockIncrement((LONG*)&g_cMethodsJitted); + COOPERATIVE_TRANSITION_END(); return ret; } @@ -13726,8 +13825,66 @@ BOOL LoadDynamicInfoEntry(Module *currentModule, return TRUE; } -void* CEEInfo::getTailCallCopyArgsThunk(CORINFO_SIG_INFO *pSig, - CorInfoHelperTailCallSpecialHandling flags) +bool CEEInfo::getTailCallHelpersInternal(CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult) +{ + MethodDesc* pTargetMD = NULL; + + if (callToken != NULL) + { + pTargetMD = (MethodDesc*)callToken->hMethod; + _ASSERTE(pTargetMD != NULL); + + if (pTargetMD->IsWrapperStub()) + { + pTargetMD = pTargetMD->GetWrappedMethodDesc(); + } + + // We currently do not handle generating the proper call to managed + // varargs methods. + if (pTargetMD->IsVarArg()) + { + return false; + } + } + + SigTypeContext typeCtx; + GetTypeContext(&sig->sigInst, &typeCtx); + + MetaSig msig(sig->pSig, sig->cbSig, GetModule(sig->scope), &typeCtx); + + bool isCallvirt = (flags & CORINFO_TAILCALL_IS_CALLVIRT) != 0; + bool isThisArgByRef = (flags & CORINFO_TAILCALL_THIS_ARG_IS_BYREF) != 0; + + MethodDesc* pStoreArgsMD; + MethodDesc* pCallTargetMD; + bool needsTarget; + + TailCallHelp::CreateTailCallHelperStubs( + m_pMethodBeingCompiled, pTargetMD, + msig, isCallvirt, isThisArgByRef, + &pStoreArgsMD, &needsTarget, + &pCallTargetMD); + + unsigned outFlags = 0; + if (needsTarget) + { + outFlags |= CORINFO_TAILCALL_STORE_TARGET; + } + + pResult->flags = (CORINFO_TAILCALL_HELPERS_FLAGS)outFlags; + pResult->hStoreArgs = (CORINFO_METHOD_HANDLE)pStoreArgsMD; + pResult->hCallTarget = (CORINFO_METHOD_HANDLE)pCallTargetMD; + pResult->hDispatcher = (CORINFO_METHOD_HANDLE)TailCallHelp::GetOrCreateTailCallDispatcherMD(); + return true; +} + +bool CEEInfo::getTailCallHelpers(CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult) { CONTRACTL { THROWS; @@ -13735,21 +13892,15 @@ void* CEEInfo::getTailCallCopyArgsThunk(CORINFO_SIG_INFO *pSig, MODE_PREEMPTIVE; } CONTRACTL_END; - void * ftn = NULL; - -#if (defined(TARGET_AMD64) || defined(TARGET_ARM)) && !defined(TARGET_UNIX) + bool success = false; JIT_TO_EE_TRANSITION(); - Stub* pStub = CPUSTUBLINKER::CreateTailCallCopyArgsThunk(pSig, m_pMethodBeingCompiled, flags); - - ftn = (void*)pStub->GetEntryPoint(); + success = getTailCallHelpersInternal(callToken, sig, flags, pResult); EE_TO_JIT_TRANSITION(); -#endif // (TARGET_AMD64 || TARGET_ARM) && !TARGET_UNIX - - return ftn; + return success; } bool CEEInfo::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert) diff --git a/src/coreclr/src/vm/jitinterface.h b/src/coreclr/src/vm/jitinterface.h index b54d024a8dad60..0e52a1eccc5721 100644 --- a/src/coreclr/src/vm/jitinterface.h +++ b/src/coreclr/src/vm/jitinterface.h @@ -221,7 +221,6 @@ EXTERN_C FCDECL_MONHELPER(JITutil_MonSignal, AwareLock* lock); EXTERN_C FCDECL_MONHELPER(JITutil_MonContention, AwareLock* awarelock); EXTERN_C FCDECL2(void, JITutil_MonReliableContention, AwareLock* awarelock, BYTE* pbLockTaken); -// Slow versions to tail call if the fast version fails EXTERN_C FCDECL2(void*, JIT_GetSharedNonGCStaticBase_Helper, DomainLocalModule *pLocalModule, DWORD dwClassDomainID); EXTERN_C FCDECL2(void*, JIT_GetSharedGCStaticBase_Helper, DomainLocalModule *pLocalModule, DWORD dwClassDomainID); @@ -483,6 +482,7 @@ class CEEInfo : public ICorJitInfo BOOL checkMethodModifier(CORINFO_METHOD_HANDLE hMethod, LPCSTR modifier, BOOL fOptional); unsigned getClassGClayout (CORINFO_CLASS_HANDLE cls, BYTE* gcPtrs); /* really GCType* gcPtrs */ + static unsigned getClassGClayoutStatic(TypeHandle th, BYTE* gcPtrs); unsigned getClassNumInstanceFields(CORINFO_CLASS_HANDLE cls); // returns the enregister info for a struct based on type of fields, alignment, etc. @@ -924,8 +924,17 @@ class CEEInfo : public ICorJitInfo void* getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ void ** ppIndirection); /* OUT */ - void* getTailCallCopyArgsThunk(CORINFO_SIG_INFO *pSig, - CorInfoHelperTailCallSpecialHandling flags); + bool getTailCallHelpersInternal( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult); + + bool getTailCallHelpers( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult); bool convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert); @@ -1602,22 +1611,6 @@ GARY_DECL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT); #define SetJitHelperFunction(ftnNum, pFunc) _SetJitHelperFunction(DYNAMIC_##ftnNum, (void*)(pFunc)) void _SetJitHelperFunction(DynamicCorInfoHelpFunc ftnNum, void * pFunc); -// Helper for RtlVirtualUnwind-based tail calls -#if defined(TARGET_AMD64) || defined(TARGET_ARM) - -// The Stub-linker generated assembly routine to copy arguments from the va_list -// into the CONTEXT and the stack. -// -typedef size_t (*pfnCopyArgs)(va_list, _CONTEXT *, DWORD_PTR *, size_t); - -// Forward declaration from Frames.h -class TailCallFrame; - -// The shared stub return location -EXTERN_C void JIT_TailCallHelperStub_ReturnAddress(); - -#endif // TARGET_AMD64 || TARGET_ARM - void *GenFastGetSharedStaticBase(bool bCheckCCtor); #ifdef HAVE_GCCOVER @@ -1691,5 +1684,8 @@ CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags); bool __stdcall TrackAllocationsEnabled(); +FCDECL0(INT64, GetJittedBytes); +FCDECL0(INT32, GetJittedMethodsCount); + #endif // JITINTERFACE_H diff --git a/src/coreclr/src/vm/listlock.h b/src/coreclr/src/vm/listlock.h index 0fdaf6e68c91c6..2b135b19d784bc 100644 --- a/src/coreclr/src/vm/listlock.h +++ b/src/coreclr/src/vm/listlock.h @@ -55,10 +55,6 @@ class ListLockEntryBase HRESULT m_hrResultCode; LOADERHANDLE m_hInitException; PTR_LoaderAllocator m_pLoaderAllocator; -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // Field to maintain the corruption severity of the exception - CorruptionSeverity m_CorruptionSeverity; -#endif // FEATURE_CORRUPTING_EXCEPTIONS ListLockEntryBase(List_t *pList, ELEMENT data, const char *description = NULL) : m_deadlock(description), @@ -72,10 +68,6 @@ class ListLockEntryBase m_hrResultCode(S_FALSE), m_hInitException(NULL), m_pLoaderAllocator(dac_cast(nullptr)) -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , - m_CorruptionSeverity(NotCorrupting) -#endif // FEATURE_CORRUPTING_EXCEPTIONS { WRAPPER_NO_CONTRACT; } diff --git a/src/coreclr/src/vm/marshalnative.cpp b/src/coreclr/src/vm/marshalnative.cpp index 56657944eb8a5e..75c1e514420f15 100644 --- a/src/coreclr/src/vm/marshalnative.cpp +++ b/src/coreclr/src/vm/marshalnative.cpp @@ -558,7 +558,7 @@ FCIMPL2(LPVOID, MarshalNative::GCHandleInternalAlloc, Object *obj, int type) OBJECTREF objRef(obj); - assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_WINRT); + assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_NATIVE_COM); if (CORProfilerTrackGC()) { @@ -923,7 +923,7 @@ FCIMPL4(IUnknown*, MarshalNative::GetComInterfaceForObjectNative, Object* orefUN if (fOnlyInContext && !IsObjectInContext(&oref)) retVal = NULL; else - retVal = GetComIPFromObjectRef(&oref, th.GetMethodTable(), TRUE, bEnableCustomizedQueryInterface); + retVal = GetComIPFromObjectRef(&oref, th.GetMethodTable(), bEnableCustomizedQueryInterface); HELPER_METHOD_FRAME_END(); return retVal; diff --git a/src/coreclr/src/vm/metasig.h b/src/coreclr/src/vm/metasig.h index b35e6fd613852f..30ca8fe868d8a3 100644 --- a/src/coreclr/src/vm/metasig.h +++ b/src/coreclr/src/vm/metasig.h @@ -196,8 +196,8 @@ DEFINE_METASIG_T(SM(PtrTypeName_ArrType_RetVoid, P(g(TYPENAMENATIVE)) a(C(TYPE)) DEFINE_METASIG_T(SM(PtrTypeName_RetVoid, P(g(TYPENAMENATIVE)), v)) DEFINE_METASIG_T(SM(PtrTypeName_Int_RetVoid, P(g(TYPENAMENATIVE)) i, v)) DEFINE_METASIG_T(SM(Exception_IntPtr_RetException, C(EXCEPTION) I, C(EXCEPTION))) -DEFINE_METASIG_T(SM(ComWrappers_Obj_CreateFlags_RefInt_RetPtrVoid, C(COMWRAPPERS) j g(CREATECOMINTERFACEFLAGS) r(i), P(v))) -DEFINE_METASIG_T(SM(ComWrappers_IntPtr_CreateFlags_RetObj, C(COMWRAPPERS) I g(CREATEOBJECTFLAGS), j)) +DEFINE_METASIG_T(SM(Scenario_ComWrappers_Obj_CreateFlags_RefInt_RetPtrVoid, g(COMWRAPPERSSCENARIO) C(COMWRAPPERS) j g(CREATECOMINTERFACEFLAGS) r(i), P(v))) +DEFINE_METASIG_T(SM(Scenario_ComWrappers_IntPtr_CreateFlags_RetObj, g(COMWRAPPERSSCENARIO) C(COMWRAPPERS) I g(CREATEOBJECTFLAGS), j)) DEFINE_METASIG_T(SM(ComWrappers_IEnumerable_RetVoid, C(COMWRAPPERS) C(IENUMERABLE), v)) DEFINE_METASIG_T(SM(Obj_RefGuid_RefIntPtr_RetInt, j r(g(GUID)) r(I), i)) #endif // FEATURE_COMINTEROP @@ -317,6 +317,7 @@ DEFINE_METASIG_T(SM(RetMethodBase, _, C(METHOD_BASE))) DEFINE_METASIG(SM(RetVoid, _, v)) DEFINE_METASIG(SM(Str_IntPtr_Int_RetVoid, s I i, v)) DEFINE_METASIG(SM(Int_RetIntPtr, i, I)) +DEFINE_METASIG(SM(Int_IntPtr_RetIntPtr, i I, I)) DEFINE_METASIG_T(SM(DateTime_RetDbl, g(DATE_TIME), d)) DEFINE_METASIG(SM(Dbl_RetLong, d, l)) diff --git a/src/coreclr/src/vm/method.cpp b/src/coreclr/src/vm/method.cpp index a458fa9d65cd62..690051b905bf84 100644 --- a/src/coreclr/src/vm/method.cpp +++ b/src/coreclr/src/vm/method.cpp @@ -5307,6 +5307,23 @@ FARPROC NDirectMethodDesc::FindEntryPointWithMangling(NATIVE_LIBRARY_HANDLE hMod return pFunc; } + +FARPROC NDirectMethodDesc::FindEntryPointWithSuffix(NATIVE_LIBRARY_HANDLE hMod, PTR_CUTF8 entryPointName, char suffix) const +{ + // Allocate space for a copy of the entry point name. + DWORD entryPointWithSuffixLen = (DWORD)(strlen(entryPointName) + 1); // +1 for charset decorations + int dstbufsize = (int)(sizeof(char) * (entryPointWithSuffixLen + 1)); // +1 for the null terminator + LPSTR entryPointWithSuffix = ((LPSTR)_alloca(dstbufsize)); + + // Copy the name so we can mangle it. + strcpy_s(entryPointWithSuffix, dstbufsize, entryPointName); + entryPointWithSuffix[entryPointWithSuffixLen] = '\0'; // Null terminator + entryPointWithSuffix[entryPointWithSuffixLen - 1] = suffix; // Charset suffix + + // Look for entry point with the suffix based on charset + return FindEntryPointWithMangling(hMod, entryPointWithSuffix); +} + #endif //******************************************************************************* @@ -5332,39 +5349,27 @@ LPVOID NDirectMethodDesc::FindEntryPoint(NATIVE_LIBRARY_HANDLE hMod) const return reinterpret_cast(GetProcAddress(hMod, (LPCSTR)(size_t)((UINT16)ordinal))); } - // Just look for the user-provided name without charset suffixes. - // If it is unicode fcn, we are going - // to need to check for the 'W' API because it takes precedence over the - // unmangled one (on NT some APIs have unmangled ANSI exports). - FARPROC pFunc = FindEntryPointWithMangling(hMod, funcName); - if ((pFunc != NULL && IsNativeAnsi()) || IsNativeNoMangled()) + FARPROC pFunc = NULL; + if (IsNativeNoMangled()) { - return reinterpret_cast(pFunc); + // Look for the user-provided entry point name only + pFunc = FindEntryPointWithMangling(hMod, funcName); } - - DWORD probedEntrypointNameLength = (DWORD)(strlen(funcName) + 1); // +1 for charset decorations - - // Allocate space for a copy of the entry point name. - int dstbufsize = (int)(sizeof(char) * (probedEntrypointNameLength + 1)); // +1 for the null terminator - - LPSTR szProbedEntrypointName = ((LPSTR)_alloca(dstbufsize)); - - // Copy the name so we can mangle it. - strcpy_s(szProbedEntrypointName, dstbufsize, funcName); - szProbedEntrypointName[probedEntrypointNameLength] = '\0'; // Add an extra '\0'. - - if(!IsNativeNoMangled()) + else if (IsNativeAnsi()) { - szProbedEntrypointName[probedEntrypointNameLength - 1] = IsNativeAnsi() ? 'A' : 'W'; - - FARPROC pProbedFunc = FindEntryPointWithMangling(hMod, szProbedEntrypointName); - - if(pProbedFunc != NULL) - { - pFunc = pProbedFunc; - } - - probedEntrypointNameLength++; + // For ANSI, look for the user-provided entry point name first. + // If that does not exist, try the charset suffix. + pFunc = FindEntryPointWithMangling(hMod, funcName); + if (pFunc == NULL) + pFunc = FindEntryPointWithSuffix(hMod, funcName, 'A'); + } + else + { + // For Unicode, look for the entry point name with the charset suffix first. + // The 'W' API takes precedence over the undecorated one. + pFunc = FindEntryPointWithSuffix(hMod, funcName, 'W'); + if (pFunc == NULL) + pFunc = FindEntryPointWithMangling(hMod, funcName); } return reinterpret_cast(pFunc); @@ -5405,7 +5410,7 @@ void NDirectMethodDesc::InitEarlyBoundNDirectTarget() #endif // !CROSSGEN_COMPILE //******************************************************************************* -BOOL MethodDesc::HasNativeCallableAttribute() +BOOL MethodDesc::HasUnmanagedCallersOnlyAttribute() { CONTRACTL { @@ -5417,11 +5422,11 @@ BOOL MethodDesc::HasNativeCallableAttribute() if (IsILStub()) { - return AsDynamicMethodDesc()->IsNativeCallableStub(); + return AsDynamicMethodDesc()->IsUnmanagedCallersOnlyStub(); } HRESULT hr = GetCustomAttribute( - WellKnownAttribute::NativeCallable, + WellKnownAttribute::UnmanagedCallersOnly, nullptr, nullptr); return (hr == S_OK) ? TRUE : FALSE; diff --git a/src/coreclr/src/vm/method.hpp b/src/coreclr/src/vm/method.hpp index 5973cd6d6053fc..ba5f6ae0967783 100644 --- a/src/coreclr/src/vm/method.hpp +++ b/src/coreclr/src/vm/method.hpp @@ -662,7 +662,7 @@ class MethodDesc return GetMethodTable()->IsInterface(); } - BOOL HasNativeCallableAttribute(); + BOOL HasUnmanagedCallersOnlyAttribute(); BOOL ShouldSuppressGCTransition(); #ifdef FEATURE_COMINTEROP @@ -2605,20 +2605,20 @@ class DynamicMethodDesc : public StoredSigMethodDesc nomdILStubAttrs = mdMemberAccessMask | mdStatic, // method attributes (IL stubs) // attributes (except mdStatic and mdMemberAccessMask) have different meaning for IL stubs - // mdMemberAccessMask = 0x0007, - nomdReverseStub = 0x0008, - // mdStatic = 0x0010, - nomdCALLIStub = 0x0020, - nomdDelegateStub = 0x0040, - nomdStructMarshalStub = 0x0080, - nomdUnbreakable = 0x0100, - nomdDelegateCOMStub = 0x0200, // CLR->COM or COM->CLR call via a delegate (WinRT specific) - nomdSignatureNeedsRestore = 0x0400, - nomdStubNeedsCOMStarted = 0x0800, // EnsureComStarted must be called before executing the method - nomdMulticastStub = 0x1000, - nomdUnboxingILStub = 0x2000, - nomdWrapperDelegateStub = 0x4000, - nomdNativeCallableStub = 0x8000, + // mdMemberAccessMask = 0x0007, + nomdReverseStub = 0x0008, + // mdStatic = 0x0010, + nomdCALLIStub = 0x0020, + nomdDelegateStub = 0x0040, + nomdStructMarshalStub = 0x0080, + nomdUnbreakable = 0x0100, + nomdDelegateCOMStub = 0x0200, // CLR->COM or COM->CLR call via a delegate (WinRT specific) + nomdSignatureNeedsRestore = 0x0400, + nomdStubNeedsCOMStarted = 0x0800, // EnsureComStarted must be called before executing the method + nomdMulticastStub = 0x1000, + nomdUnboxingILStub = 0x2000, + nomdWrapperDelegateStub = 0x4000, + nomdUnmanagedCallersOnlyStub = 0x8000, nomdILStub = 0x00010000, nomdLCGMethod = 0x00020000, @@ -2711,7 +2711,7 @@ class DynamicMethodDesc : public StoredSigMethodDesc } bool IsReverseStub() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(IsILStub()); return (0 != (m_dwExtendedFlags & nomdReverseStub)); } - bool IsNativeCallableStub() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(IsILStub()); return (0 != (m_dwExtendedFlags & nomdNativeCallableStub)); } + bool IsUnmanagedCallersOnlyStub() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(IsILStub()); return (0 != (m_dwExtendedFlags & nomdUnmanagedCallersOnlyStub)); } bool IsCALLIStub() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(IsILStub()); return (0 != (m_dwExtendedFlags & nomdCALLIStub)); } bool IsDelegateStub() { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(IsILStub()); return (0 != (m_dwExtendedFlags & nomdDelegateStub)); } bool IsCLRToCOMStub() { LIMITED_METHOD_CONTRACT; _ASSERTE(IsILStub()); return ((0 == (m_dwExtendedFlags & mdStatic)) && !IsReverseStub() && !IsDelegateStub() && !IsStructMarshalStub()); } @@ -3150,6 +3150,7 @@ class NDirectMethodDesc : public MethodDesc #ifdef TARGET_WINDOWS private: FARPROC FindEntryPointWithMangling(NATIVE_LIBRARY_HANDLE mod, PTR_CUTF8 entryPointName) const; + FARPROC FindEntryPointWithSuffix(NATIVE_LIBRARY_HANDLE mod, PTR_CUTF8 entryPointName, char suffix) const; #endif public: diff --git a/src/coreclr/src/vm/methodtable.cpp b/src/coreclr/src/vm/methodtable.cpp index 1706f0c327c4e4..2332f44e983715 100644 --- a/src/coreclr/src/vm/methodtable.cpp +++ b/src/coreclr/src/vm/methodtable.cpp @@ -3123,39 +3123,6 @@ BOOL MethodTable::RunClassInitEx(OBJECTREF *pThrowable) // a subclass of Error *pThrowable = GET_THROWABLE(); _ASSERTE(fRet == FALSE); - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // If active thread state does not have a CorruptionSeverity set for the exception, - // then set one up based upon the current exception code and/or the throwable. - // - // When can we be here and current exception tracker may not have corruption severity set? - // Incase of SO in managed code, SO is never seen by CLR's exception handler for managed code - // and if this happens in cctor, we can end up here without the corruption severity set. - Thread *pThread = GetThread(); - _ASSERTE(pThread != NULL); - ThreadExceptionState *pCurTES = pThread->GetExceptionState(); - _ASSERTE(pCurTES != NULL); - if (pCurTES->GetLastActiveExceptionCorruptionSeverity() == NotSet) - { - if (CEHelper::IsProcessCorruptedStateException(GetCurrentExceptionCode()) || - CEHelper::IsProcessCorruptedStateException(*pThrowable)) - { - // Process Corrupting - pCurTES->SetLastActiveExceptionCorruptionSeverity(ProcessCorrupting); - LOG((LF_EH, LL_INFO100, "MethodTable::RunClassInitEx - Exception treated as ProcessCorrupting.\n")); - } - else - { - // Not Corrupting - pCurTES->SetLastActiveExceptionCorruptionSeverity(NotCorrupting); - LOG((LF_EH, LL_INFO100, "MethodTable::RunClassInitEx - Exception treated as non-corrupting.\n")); - } - } - else - { - LOG((LF_EH, LL_INFO100, "MethodTable::RunClassInitEx - Exception already has corruption severity set.\n")); - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS } EX_END_CATCH(SwallowAllExceptions) @@ -3289,17 +3256,7 @@ void MethodTable::DoRunClassInitThrowing() ((EXCEPTIONREF)(gc.pThrowable))->ClearStackTraceForThrow(); } - // - // Specify the corruption severity to be used to raise this exception in COMPlusThrow below. - // This will ensure that when the exception is seen by the managed code personality routine, - // it will setup the correct corruption severity in the exception tracker. - // - - COMPlusThrow(gc.pThrowable -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , pEntry->m_CorruptionSeverity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); + COMPlusThrow(gc.pThrowable); } description = ".cctor lock"; @@ -3389,21 +3346,7 @@ void MethodTable::DoRunClassInitThrowing() pEntry->m_hrResultCode = E_FAIL; SetClassInitError(); - #ifdef FEATURE_CORRUPTING_EXCEPTIONS - // Save the corruption severity of the exception so that if the type system - // attempts to pick it up from its cache list and throw again, it should - // treat the exception as corrupting, if applicable. - pEntry->m_CorruptionSeverity = pThread->GetExceptionState()->GetLastActiveExceptionCorruptionSeverity(); - - // We should be having a valid corruption severity at this point - _ASSERTE(pEntry->m_CorruptionSeverity != NotSet); - #endif // FEATURE_CORRUPTING_EXCEPTIONS - - COMPlusThrow(gc.pThrowable - #ifdef FEATURE_CORRUPTING_EXCEPTIONS - , pEntry->m_CorruptionSeverity - #endif // FEATURE_CORRUPTING_EXCEPTIONS - ); + COMPlusThrow(gc.pThrowable); } GCPROTECT_END(); @@ -8674,7 +8617,7 @@ MethodDesc *MethodTable::MethodDataInterfaceImpl::GetImplMethodDesc(UINT32 slotN if (implSlotNumber == INVALID_SLOT_NUMBER) { return NULL; } - return m_pImpl->GetImplMethodDesc(MapToImplSlotNumber(slotNumber)); + return m_pImpl->GetImplMethodDesc(implSlotNumber); } //========================================================================================== @@ -8685,7 +8628,7 @@ void MethodTable::MethodDataInterfaceImpl::InvalidateCachedVirtualSlot(UINT32 sl if (implSlotNumber == INVALID_SLOT_NUMBER) { return; } - return m_pImpl->InvalidateCachedVirtualSlot(MapToImplSlotNumber(slotNumber)); + return m_pImpl->InvalidateCachedVirtualSlot(implSlotNumber); } //========================================================================================== diff --git a/src/coreclr/src/vm/methodtablebuilder.cpp b/src/coreclr/src/vm/methodtablebuilder.cpp index 14ccfd4371061d..5f389b12865fce 100644 --- a/src/coreclr/src/vm/methodtablebuilder.cpp +++ b/src/coreclr/src/vm/methodtablebuilder.cpp @@ -11226,6 +11226,21 @@ VOID MethodTableBuilder::CheckForSpecialTypes() } #ifdef FEATURE_READYTORUN + +bool ModulesAreDistributedAsAnIndivisibleUnit(Module* module1, Module* module2) +{ + if (module1 == module2) + return true; + + bool nativeImagesIdentical = false; + if (module1->GetCompositeNativeImage() != NULL) + { + return module1->GetCompositeNativeImage() == module2->GetCompositeNativeImage(); + } + + return false; +} + //******************************************************************************* VOID MethodTableBuilder::CheckLayoutDependsOnOtherModules(MethodTable * pDependencyMT) { @@ -11237,20 +11252,18 @@ VOID MethodTableBuilder::CheckLayoutDependsOnOtherModules(MethodTable * pDepende // // WARNING: Changes in this algorithm are potential ReadyToRun breaking changes !!! // - // Track whether field layout of this type depend on information outside its containing module + // Track whether field layout of this type depend on information outside its containing module and compilation unit // // It is a stronger condition than MethodTable::IsInheritanceChainLayoutFixedInCurrentVersionBubble(). // It has to remain fixed accross versioning changes in the module dependencies. In particular, it does // not take into account NonVersionable attribute. Otherwise, adding NonVersionable attribute to existing // type would be ReadyToRun incompatible change. // - if (pDependencyMT->GetModule() == GetModule()) - { - if (!pDependencyMT->GetClass()->HasLayoutDependsOnOtherModules()) - return; - } + bool modulesDefinedInSameDistributionUnit = ModulesAreDistributedAsAnIndivisibleUnit(pDependencyMT->GetModule(), GetModule()); + bool dependsOnOtherModules = !modulesDefinedInSameDistributionUnit || pDependencyMT->GetClass()->HasLayoutDependsOnOtherModules(); - GetHalfBakedClass()->SetHasLayoutDependsOnOtherModules(); + if (dependsOnOtherModules) + GetHalfBakedClass()->SetHasLayoutDependsOnOtherModules(); } BOOL MethodTableBuilder::NeedsAlignedBaseOffset() @@ -11274,7 +11287,7 @@ BOOL MethodTableBuilder::NeedsAlignedBaseOffset() // Always use the ReadyToRun field layout algorithm if the source IL image was ReadyToRun, independent on // whether ReadyToRun is actually enabled for the module. It is required to allow mixing and matching - // ReadyToRun images with NGen. + // ReadyToRun images with and without input bubble enabled. if (!GetModule()->GetFile()->IsILImageReadyToRun()) { // Always use ReadyToRun field layout algorithm to produce ReadyToRun images @@ -11282,33 +11295,13 @@ BOOL MethodTableBuilder::NeedsAlignedBaseOffset() return FALSE; } - if (pParentMT->GetModule() == GetModule()) - { - if (!pParentMT->GetClass()->HasLayoutDependsOnOtherModules()) - return FALSE; - } - else + if (!ModulesAreDistributedAsAnIndivisibleUnit(GetModule(), pParentMT->GetModule()) || + pParentMT->GetClass()->HasLayoutDependsOnOtherModules()) { -#ifdef FEATURE_READYTORUN_COMPILER - if (IsReadyToRunCompilation()) - { - if (pParentMT->GetModule()->IsInCurrentVersionBubble()) - { - return FALSE; - } - } -#else // FEATURE_READYTORUN_COMPILER - if (GetModule()->GetFile()->IsILImageReadyToRun()) - { - if (GetModule()->IsInSameVersionBubble(pParentMT->GetModule())) - { - return FALSE; - } - } -#endif // FEATURE_READYTORUN_COMPILER + return TRUE; } - return TRUE; + return FALSE; } #endif // FEATURE_READYTORUN diff --git a/src/coreclr/src/vm/mlinfo.cpp b/src/coreclr/src/vm/mlinfo.cpp index d5168426aec502..5765c22fcd9b02 100644 --- a/src/coreclr/src/vm/mlinfo.cpp +++ b/src/coreclr/src/vm/mlinfo.cpp @@ -39,24 +39,22 @@ #ifdef FEATURE_COMINTEROP - DEFINE_ASM_QUAL_TYPE_NAME(ENUMERATOR_TO_ENUM_VARIANT_CM_NAME, g_EnumeratorToEnumClassName, g_CorelibAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken); + DEFINE_ASM_QUAL_TYPE_NAME(ENUMERATOR_TO_ENUM_VARIANT_CM_NAME, g_EnumeratorToEnumClassName, g_CorelibAsmName); static const int ENUMERATOR_TO_ENUM_VARIANT_CM_NAME_LEN = lengthof(ENUMERATOR_TO_ENUM_VARIANT_CM_NAME); static const char ENUMERATOR_TO_ENUM_VARIANT_CM_COOKIE[] = {""}; static const int ENUMERATOR_TO_ENUM_VARIANT_CM_COOKIE_LEN = lengthof(ENUMERATOR_TO_ENUM_VARIANT_CM_COOKIE); - DEFINE_ASM_QUAL_TYPE_NAME(COLOR_TRANSLATOR_ASM_QUAL_TYPE_NAME, g_ColorTranslatorClassName, g_DrawingAsmName, VER_ASSEMBLYVERSION_STR, g_FXKeyToken); - DEFINE_ASM_QUAL_TYPE_NAME(COLOR_ASM_QUAL_TYPE_NAME, g_ColorClassName, g_DrawingAsmName, VER_ASSEMBLYVERSION_STR, g_FXKeyToken); + DEFINE_ASM_QUAL_TYPE_NAME(COLOR_TRANSLATOR_ASM_QUAL_TYPE_NAME, g_ColorTranslatorClassName, g_DrawingAsmName); + DEFINE_ASM_QUAL_TYPE_NAME(COLOR_ASM_QUAL_TYPE_NAME, g_ColorClassName, g_DrawingAsmName); - DEFINE_ASM_QUAL_TYPE_NAME(URI_ASM_QUAL_TYPE_NAME, g_SystemUriClassName, g_SystemRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_FXKeyToken); + DEFINE_ASM_QUAL_TYPE_NAME(URI_ASM_QUAL_TYPE_NAME, g_SystemUriClassName, g_SystemRuntimeAsmName); - DEFINE_ASM_QUAL_TYPE_NAME(NCCEVENTARGS_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedEventArgsName, g_ObjectModelAsmName, VER_ASSEMBLYVERSION_STR, g_FXKeyToken); - DEFINE_ASM_QUAL_TYPE_NAME(NCCEVENTARGS_MARSHALER_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedEventArgsMarshalerName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken); - - - DEFINE_ASM_QUAL_TYPE_NAME(PCEVENTARGS_ASM_QUAL_TYPE_NAME, g_PropertyChangedEventArgsName, g_ObjectModelAsmName, VER_ASSEMBLYVERSION_STR, g_FXKeyToken); - DEFINE_ASM_QUAL_TYPE_NAME(PCEVENTARGS_MARSHALER_ASM_QUAL_TYPE_NAME, g_PropertyChangedEventArgsMarshalerName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken); + DEFINE_ASM_QUAL_TYPE_NAME(NCCEVENTARGS_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedEventArgsName, g_ObjectModelAsmName); + DEFINE_ASM_QUAL_TYPE_NAME(NCCEVENTARGS_MARSHALER_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedEventArgsMarshalerName, g_SystemRuntimeWindowsRuntimeAsmName); + DEFINE_ASM_QUAL_TYPE_NAME(PCEVENTARGS_ASM_QUAL_TYPE_NAME, g_PropertyChangedEventArgsName, g_ObjectModelAsmName); + DEFINE_ASM_QUAL_TYPE_NAME(PCEVENTARGS_MARSHALER_ASM_QUAL_TYPE_NAME, g_PropertyChangedEventArgsMarshalerName, g_SystemRuntimeWindowsRuntimeAsmName); #define OLECOLOR_TO_SYSTEMCOLOR_METH_NAME "FromOle" #define SYSTEMCOLOR_TO_OLECOLOR_METH_NAME "ToOle" diff --git a/src/coreclr/src/vm/mngstdinterfaces.cpp b/src/coreclr/src/vm/mngstdinterfaces.cpp index a7b0fb3549571b..d9dd7e516be8d3 100644 --- a/src/coreclr/src/vm/mngstdinterfaces.cpp +++ b/src/coreclr/src/vm/mngstdinterfaces.cpp @@ -130,16 +130,14 @@ void MngStdItfBase::InitHelper( pUComItfType->GetMethodTable()->CheckRunClassInitThrowing(); // Retrieve the custom marshaler type handle. - SString sstrCMTypeName(SString::Utf8, strCMTypeName); - *pCustomMarshalerType = TypeName::GetTypeFromAsmQualifiedName(sstrCMTypeName.GetUnicode()); + *pCustomMarshalerType = ClassLoader::LoadTypeByNameThrowing(SystemDomain::SystemAssembly(), NULL, strCMTypeName); // Run the for the marshaller. pCustomMarshalerType->GetMethodTable()->EnsureInstanceActive(); pCustomMarshalerType->GetMethodTable()->CheckRunClassInitThrowing(); // Load the managed view. - SString sstrManagedViewName(SString::Utf8, strManagedViewName); - *pManagedViewType = TypeName::GetTypeFromAsmQualifiedName(sstrManagedViewName.GetUnicode()); + *pManagedViewType = ClassLoader::LoadTypeByNameThrowing(SystemDomain::SystemAssembly(), NULL, strManagedViewName); // Run the for the managed view. pManagedViewType->GetMethodTable()->EnsureInstanceActive(); diff --git a/src/coreclr/src/vm/mngstditflist.h b/src/coreclr/src/vm/mngstditflist.h index 85d4b4a34ebae6..f05f28241dac91 100644 --- a/src/coreclr/src/vm/mngstditflist.h +++ b/src/coreclr/src/vm/mngstditflist.h @@ -30,9 +30,6 @@ #define MNGSTDITF_DEFINE_METH3(FriendlyName, MethName, MethSig, FcallDecl) \ MNGSTDITF_DEFINE_METH_IMPL(FriendlyName, MethName##_3, MethName, MethSig, FcallDecl) -#define CUSTOM_MARSHALER_ASM ", System.Private.CoreLib, Version=" VER_ASSEMBLYVERSION_STR ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" - - // @@ -83,7 +80,7 @@ #define MNGSTDITF_IREFLECT_DECL__INVOKEMEMBER FCDECL9(Object*, InvokeMember, Object* refThisUNSAFE, Object* refNameUNSAFE, INT32 enumBindingAttr, Object* refBinderUNSAFE, Object* refTargetUNSAFE, Object* refArgsArrayUNSAFE, Object* refModifiersArrayUNSAFE, Object* refCultureUNSAFE, Object* refNamedParamsArrayUNSAFE) #define MNGSTDITF_IREFLECT_DECL__GET_UNDERLYING_SYSTEM_TYPE FCDECL1(Object*, get_UnderlyingSystemType, Object* refThisUNSAFE) -MNGSTDITF_BEGIN_INTERFACE(StdMngIReflect, g_ReflectionReflectItfName, "System.Runtime.InteropServices.ComTypes.IReflect", g_CMExpandoToDispatchExMarshaler CUSTOM_MARSHALER_ASM, "IReflect", g_CMExpandoViewOfDispatchEx CUSTOM_MARSHALER_ASM, IID_IDispatchEx, TRUE) +MNGSTDITF_BEGIN_INTERFACE(StdMngIReflect, g_ReflectionReflectItfName, "System.Runtime.InteropServices.ComTypes.IReflect", g_CMExpandoToDispatchExMarshaler, "IReflect", g_CMExpandoViewOfDispatchEx, IID_IDispatchEx, TRUE) MNGSTDITF_DEFINE_METH(StdMngIReflect, GetMethod, &gsig_IM_Str_BindingFlags_Binder_ArrType_ArrParameterModifier_RetMethodInfo, MNGSTDITF_IREFLECT_DECL__GETMETHOD) MNGSTDITF_DEFINE_METH2(StdMngIReflect,GetMethod, &gsig_IM_Str_BindingFlags_RetMethodInfo, MNGSTDITF_IREFLECT_DECL__GETMETHOD_2) MNGSTDITF_DEFINE_METH(StdMngIReflect, GetMethods, &gsig_IM_BindingFlags_RetArrMethodInfo, MNGSTDITF_IREFLECT_DECL__GETMETHODS) @@ -108,7 +105,7 @@ MNGSTDITF_END_INTERFACE(StdMngIReflect) #define MNGSTDITF_IEXPANDO_DECL__ADD_METHOD FCDECL3(Object*, AddMethod, Object* refThisUNSAFE, StringObject* refNameUNSAFE, Object* refDelegateUNSAFE) #define MNGSTDITF_IEXPANDO_DECL__REMOVE_MEMBER FCDECL2(void, RemoveMember, Object* refThisUNSAFE, Object* refMemberInfoUNSAFE) -MNGSTDITF_BEGIN_INTERFACE(StdMngIExpando, g_ReflectionExpandoItfName, "System.Runtime.InteropServices.ComTypes.IExpando", g_CMExpandoToDispatchExMarshaler CUSTOM_MARSHALER_ASM, "IExpando", g_CMExpandoViewOfDispatchEx CUSTOM_MARSHALER_ASM, IID_IDispatchEx, TRUE) +MNGSTDITF_BEGIN_INTERFACE(StdMngIExpando, g_ReflectionExpandoItfName, "System.Runtime.InteropServices.ComTypes.IExpando", g_CMExpandoToDispatchExMarshaler, "IExpando", g_CMExpandoViewOfDispatchEx, IID_IDispatchEx, TRUE) MNGSTDITF_DEFINE_METH(StdMngIExpando, AddField, &gsig_IM_Str_RetFieldInfo, MNGSTDITF_IEXPANDO_DECL__ADD_FIELD) MNGSTDITF_DEFINE_METH(StdMngIExpando, AddProperty, &gsig_IM_Str_RetPropertyInfo, MNGSTDITF_IEXPANDO_DECL__ADD_PROPERTY) MNGSTDITF_DEFINE_METH(StdMngIExpando, AddMethod, &gsig_IM_Str_Delegate_RetMethodInfo,MNGSTDITF_IEXPANDO_DECL__ADD_METHOD) @@ -123,7 +120,7 @@ MNGSTDITF_END_INTERFACE(StdMngIExpando) #define MNGSTDITF_IENUMERATOR_DECL__GET_CURRENT FCDECL1(Object*, get_Current, Object* refThisUNSAFE) #define MNGSTDITF_IENUMERATOR_DECL__RESET FCDECL1(void, Reset, Object* refThisUNSAFE) -MNGSTDITF_BEGIN_INTERFACE(StdMngIEnumerator, g_CollectionsEnumeratorClassName, "System.Runtime.InteropServices.ComTypes.IEnumerator", g_EnumeratorToEnumClassName CUSTOM_MARSHALER_ASM, "", "System.Runtime.InteropServices.CustomMarshalers.EnumeratorViewOfEnumVariant" CUSTOM_MARSHALER_ASM, IID_IEnumVARIANT, TRUE) +MNGSTDITF_BEGIN_INTERFACE(StdMngIEnumerator, g_CollectionsEnumeratorClassName, "System.Runtime.InteropServices.ComTypes.IEnumerator", g_EnumeratorToEnumClassName, "", "System.Runtime.InteropServices.CustomMarshalers.EnumeratorViewOfEnumVariant", IID_IEnumVARIANT, TRUE) MNGSTDITF_DEFINE_METH(StdMngIEnumerator, MoveNext, &gsig_IM_RetBool, MNGSTDITF_IENUMERATOR_DECL__MOVE_NEXT) MNGSTDITF_DEFINE_METH(StdMngIEnumerator, get_Current, &gsig_IM_RetObj, MNGSTDITF_IENUMERATOR_DECL__GET_CURRENT) MNGSTDITF_DEFINE_METH(StdMngIEnumerator, Reset, &gsig_IM_RetVoid, MNGSTDITF_IENUMERATOR_DECL__RESET) @@ -135,6 +132,6 @@ MNGSTDITF_END_INTERFACE(StdMngIEnumerator) #define MNGSTDITF_IENUMERABLE_DECL__GETENUMERATOR FCDECL1(Object*, GetEnumerator, Object* refThisUNSAFE) -MNGSTDITF_BEGIN_INTERFACE(StdMngIEnumerable, g_CollectionsEnumerableItfName, "System.Runtime.InteropServices.ComTypes.IEnumerable", "System.Runtime.InteropServices.CustomMarshalers.EnumerableToDispatchMarshaler" CUSTOM_MARSHALER_ASM, "", "System.Runtime.InteropServices.CustomMarshalers.EnumerableViewOfDispatch" CUSTOM_MARSHALER_ASM, IID_IDispatch, FALSE) +MNGSTDITF_BEGIN_INTERFACE(StdMngIEnumerable, g_CollectionsEnumerableItfName, "System.Runtime.InteropServices.ComTypes.IEnumerable", "System.Runtime.InteropServices.CustomMarshalers.EnumerableToDispatchMarshaler", "", "System.Runtime.InteropServices.CustomMarshalers.EnumerableViewOfDispatch", IID_IDispatch, FALSE) MNGSTDITF_DEFINE_METH(StdMngIEnumerable, GetEnumerator, &gsig_IM_RetIEnumerator, MNGSTDITF_IENUMERABLE_DECL__GETENUMERATOR) MNGSTDITF_END_INTERFACE(StdMngIEnumerable) diff --git a/src/coreclr/src/vm/mscorlib.cpp b/src/coreclr/src/vm/mscorlib.cpp index 6cdd5d9e1a9d1e..3c787e04469b6d 100644 --- a/src/coreclr/src/vm/mscorlib.cpp +++ b/src/coreclr/src/vm/mscorlib.cpp @@ -88,6 +88,8 @@ #include "eventpipeinternal.h" #endif //FEATURE_PERFTRACING +#include "tailcallhelp.h" + #endif // CROSSGEN_MSCORLIB @@ -347,7 +349,7 @@ const MscorlibClassDescription c_rgMscorlibClassDescriptions[] = // Include all exception types here that are defined in mscorlib. Omit exceptions defined elsewhere. #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) { ns , # reKind }, #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) - #define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) + #define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, bHRformessage, ...) #include "rexcep.h" }; const USHORT c_nMscorlibClassDescriptions = NumItems(c_rgMscorlibClassDescriptions); diff --git a/src/coreclr/src/vm/mscorlib.h b/src/coreclr/src/vm/mscorlib.h index 67f140a202dafd..7c0258449f0a5e 100644 --- a/src/coreclr/src/vm/mscorlib.h +++ b/src/coreclr/src/vm/mscorlib.h @@ -462,8 +462,9 @@ DEFINE_CLASS(CUSTOMQUERYINTERFACERESULT, Interop, CustomQueryInterface DEFINE_CLASS(COMWRAPPERS, Interop, ComWrappers) DEFINE_CLASS(CREATECOMINTERFACEFLAGS, Interop, CreateComInterfaceFlags) DEFINE_CLASS(CREATEOBJECTFLAGS, Interop, CreateObjectFlags) -DEFINE_METHOD(COMWRAPPERS, COMPUTE_VTABLES, CallComputeVtables, SM_ComWrappers_Obj_CreateFlags_RefInt_RetPtrVoid) -DEFINE_METHOD(COMWRAPPERS, CREATE_OBJECT, CallCreateObject, SM_ComWrappers_IntPtr_CreateFlags_RetObj) +DEFINE_CLASS(COMWRAPPERSSCENARIO, Interop, ComWrappersScenario) +DEFINE_METHOD(COMWRAPPERS, COMPUTE_VTABLES, CallComputeVtables, SM_Scenario_ComWrappers_Obj_CreateFlags_RefInt_RetPtrVoid) +DEFINE_METHOD(COMWRAPPERS, CREATE_OBJECT, CallCreateObject, SM_Scenario_ComWrappers_IntPtr_CreateFlags_RetObj) DEFINE_METHOD(COMWRAPPERS, RELEASE_OBJECTS, CallReleaseObjects, SM_ComWrappers_IEnumerable_RetVoid) DEFINE_METHOD(COMWRAPPERS, CALL_ICUSTOMQUERYINTERFACE, CallICustomQueryInterface, SM_Obj_RefGuid_RefIntPtr_RetInt) #endif //FEATURE_COMINTEROP @@ -727,6 +728,9 @@ DEFINE_METHOD(RUNTIME_HELPERS, GET_RAW_ARRAY_DATA, GetRawArrayData, No DEFINE_METHOD(RUNTIME_HELPERS, GET_UNINITIALIZED_OBJECT, GetUninitializedObject, NoSig) DEFINE_METHOD(RUNTIME_HELPERS, ENUM_EQUALS, EnumEquals, NoSig) DEFINE_METHOD(RUNTIME_HELPERS, ENUM_COMPARE_TO, EnumCompareTo, NoSig) +DEFINE_METHOD(RUNTIME_HELPERS, ALLOC_TAILCALL_ARG_BUFFER, AllocTailCallArgBuffer, SM_Int_IntPtr_RetIntPtr) +DEFINE_METHOD(RUNTIME_HELPERS, GET_TAILCALL_INFO, GetTailCallInfo, NoSig) +DEFINE_METHOD(RUNTIME_HELPERS, FREE_TAILCALL_ARG_BUFFER, FreeTailCallArgBuffer, SM_RetVoid) DEFINE_CLASS(UNSAFE, InternalCompilerServices, Unsafe) DEFINE_METHOD(UNSAFE, AS_POINTER, AsPointer, NoSig) @@ -769,6 +773,31 @@ DEFINE_FIELD(RAW_ARRAY_DATA, PADDING, Padding) #endif DEFINE_FIELD(RAW_ARRAY_DATA, DATA, Data) +DEFINE_CLASS(PORTABLE_TAIL_CALL_FRAME, CompilerServices, PortableTailCallFrame) +DEFINE_FIELD(PORTABLE_TAIL_CALL_FRAME, PREV, Prev) +DEFINE_FIELD(PORTABLE_TAIL_CALL_FRAME, TAILCALL_AWARE_RETURN_ADDRESS, TailCallAwareReturnAddress) +DEFINE_FIELD(PORTABLE_TAIL_CALL_FRAME, NEXT_CALL, NextCall) + +DEFINE_CLASS(TAIL_CALL_TLS, CompilerServices, TailCallTls) +DEFINE_FIELD(TAIL_CALL_TLS, FRAME, Frame) +DEFINE_FIELD(TAIL_CALL_TLS, ARG_BUFFER, ArgBuffer) +DEFINE_FIELD(TAIL_CALL_TLS, ARG_BUFFER_SIZE, _argBufferSize) +DEFINE_FIELD(TAIL_CALL_TLS, ARG_BUFFER_GC_DESC, _argBufferGCDesc) +DEFINE_FIELD(TAIL_CALL_TLS, ARG_BUFFER_INLINE, _argBufferInline) + +DEFINE_CLASS_U(CompilerServices, PortableTailCallFrame, PortableTailCallFrame) +DEFINE_FIELD_U(Prev, PortableTailCallFrame, Prev) +DEFINE_FIELD_U(TailCallAwareReturnAddress, PortableTailCallFrame, TailCallAwareReturnAddress) +DEFINE_FIELD_U(NextCall, PortableTailCallFrame, NextCall) + +DEFINE_CLASS_U(CompilerServices, TailCallTls, TailCallTls) +DEFINE_FIELD_U(Frame, TailCallTls, m_frame) +DEFINE_FIELD_U(ArgBuffer, TailCallTls, m_argBuffer) +DEFINE_FIELD_U(_argBufferSize, TailCallTls, m_argBufferSize) +DEFINE_FIELD_U(_argBufferGCDesc, TailCallTls, m_argBufferGCDesc) +DEFINE_FIELD_U(_argBufferInline, TailCallTls, m_argBufferInline) + + DEFINE_CLASS(RUNTIME_WRAPPED_EXCEPTION, CompilerServices, RuntimeWrappedException) DEFINE_METHOD(RUNTIME_WRAPPED_EXCEPTION, OBJ_CTOR, .ctor, IM_Obj_RetVoid) DEFINE_FIELD(RUNTIME_WRAPPED_EXCEPTION, WRAPPED_EXCEPTION, _wrappedException) @@ -1033,6 +1062,7 @@ DEFINE_METHOD(STUBHELPERS, LOG_PINNED_ARGUMENT, LogPinne #ifdef TARGET_64BIT DEFINE_METHOD(STUBHELPERS, GET_STUB_CONTEXT_ADDR, GetStubContextAddr, SM_RetIntPtr) #endif // TARGET_64BIT +DEFINE_METHOD(STUBHELPERS, NEXT_CALL_RETURN_ADDRESS, NextCallReturnAddress, SM_RetIntPtr) DEFINE_METHOD(STUBHELPERS, SAFE_HANDLE_ADD_REF, SafeHandleAddRef, SM_SafeHandle_RefBool_RetIntPtr) DEFINE_METHOD(STUBHELPERS, SAFE_HANDLE_RELEASE, SafeHandleRelease, SM_SafeHandle_RetVoid) diff --git a/src/coreclr/src/vm/nativeimage.cpp b/src/coreclr/src/vm/nativeimage.cpp index 7cda61993ddb95..e181bfb06446f7 100644 --- a/src/coreclr/src/vm/nativeimage.cpp +++ b/src/coreclr/src/vm/nativeimage.cpp @@ -61,14 +61,24 @@ void NativeImage::Initialize(READYTORUN_HEADER *pHeader, LoaderAllocator *pLoade HENUMInternal assemblyEnum; HRESULT hr = m_pManifestMetadata->EnumAllInit(mdtAssemblyRef, &assemblyEnum); mdAssemblyRef assemblyRef; - int assemblyIndex = 0; + m_manifestAssemblyCount = 0; while (m_pManifestMetadata->EnumNext(&assemblyEnum, &assemblyRef)) { LPCSTR assemblyName; hr = m_pManifestMetadata->GetAssemblyRefProps(assemblyRef, NULL, NULL, &assemblyName, NULL, NULL, NULL, NULL); - m_assemblySimpleNameToIndexMap.Add(AssemblyNameIndex(assemblyName, assemblyIndex)); - assemblyIndex++; + m_assemblySimpleNameToIndexMap.Add(AssemblyNameIndex(assemblyName, m_manifestAssemblyCount)); + m_manifestAssemblyCount++; } + + // When a composite image contributes to a larger version bubble, its manifest assembly + // count may exceed its component assembly count as it may contain references to + // assemblies outside of the composite image that are part of its version bubble. + _ASSERTE(m_manifestAssemblyCount >= m_componentAssemblyCount); + + S_SIZE_T dwAllocSize = S_SIZE_T(sizeof(PTR_Assembly)) * S_SIZE_T(m_manifestAssemblyCount); + + // Note: Memory allocated on loader heap is zero filled + m_pNativeMetadataAssemblyRefMap = (PTR_Assembly*)pamTracker->Track(pLoaderAllocator->GetLowFrequencyHeap()->AllocMem(dwAllocSize)); } NativeImage::~NativeImage() @@ -115,7 +125,7 @@ NativeImage *NativeImage::Open( #endif #ifndef DACCESS_COMPILE -Assembly *NativeImage::LoadComponentAssembly(uint32_t rowid) +Assembly *NativeImage::LoadManifestAssembly(uint32_t rowid) { STANDARD_VM_CONTRACT; diff --git a/src/coreclr/src/vm/nativeimage.h b/src/coreclr/src/vm/nativeimage.h index 2c3f538043bb0e..323a509ecbc83c 100644 --- a/src/coreclr/src/vm/nativeimage.h +++ b/src/coreclr/src/vm/nativeimage.h @@ -62,9 +62,11 @@ class NativeImage ReadyToRunInfo *m_pReadyToRunInfo; IMDInternalImport *m_pManifestMetadata; PEImageLayout *m_pImageLayout; + PTR_Assembly *m_pNativeMetadataAssemblyRefMap; IMAGE_DATA_DIRECTORY *m_pComponentAssemblies; uint32_t m_componentAssemblyCount; + uint32_t m_manifestAssemblyCount; SHash m_assemblySimpleNameToIndexMap; Crst m_eagerFixupsLock; @@ -93,8 +95,10 @@ class NativeImage uint32_t GetComponentAssemblyCount() const { return m_componentAssemblyCount; } ReadyToRunInfo *GetReadyToRunInfo() const { return m_pReadyToRunInfo; } IMDInternalImport *GetManifestMetadata() const { return m_pManifestMetadata; } + uint32_t GetManifestAssemblyCount() const { return m_manifestAssemblyCount; } + PTR_Assembly *GetManifestMetadataAssemblyRefMap() { return m_pNativeMetadataAssemblyRefMap; } - Assembly *LoadComponentAssembly(uint32_t rowid); + Assembly *LoadManifestAssembly(uint32_t rowid); PTR_READYTORUN_CORE_HEADER GetComponentAssemblyHeader(LPCUTF8 assemblySimpleName); diff --git a/src/coreclr/src/vm/object.cpp b/src/coreclr/src/vm/object.cpp index 836911433f1264..06e7bb6c8bf679 100644 --- a/src/coreclr/src/vm/object.cpp +++ b/src/coreclr/src/vm/object.cpp @@ -1872,7 +1872,7 @@ void ThreadBaseObject::SetInternal(Thread *it) // Now the native Thread will only be destroyed after the managed Thread is collected. // Tell the GC that the managed Thread actually represents much more memory. - GCInterface::NewAddMemoryPressure(sizeof(Thread)); + GCInterface::AddMemoryPressure(sizeof(Thread)); } void ThreadBaseObject::ClearInternal() @@ -1881,7 +1881,7 @@ void ThreadBaseObject::ClearInternal() _ASSERTE(m_InternalThread != NULL); m_InternalThread = NULL; - GCInterface::NewRemoveMemoryPressure(sizeof(Thread)); + GCInterface::RemoveMemoryPressure(sizeof(Thread)); } #endif // #ifndef DACCESS_COMPILE diff --git a/src/coreclr/src/vm/pefile.cpp b/src/coreclr/src/vm/pefile.cpp index 74bdbbeb86bc97..ae9c966cb79833 100644 --- a/src/coreclr/src/vm/pefile.cpp +++ b/src/coreclr/src/vm/pefile.cpp @@ -12,7 +12,6 @@ #include "pefile.h" #include "eecontract.h" #include "eeconfig.h" -#include "product_version.h" #include "eventtrace.h" #include "dbginterface.h" #include "peimagelayout.inl" @@ -296,12 +295,15 @@ void PEFile::LoadLibrary(BOOL allowNativeSkip/*=TRUE*/) // if allowNativeSkip==F if (GetILimage()->IsFile()) { #ifdef TARGET_UNIX - if (GetILimage()->IsILOnly()) + bool loadILImage = GetILimage()->IsILOnly(); +#else // TARGET_UNIX + bool loadILImage = GetILimage()->IsILOnly() && GetILimage()->IsInBundle(); +#endif // TARGET_UNIX + if (loadILImage) { GetILimage()->Load(); } else -#endif // TARGET_UNIX { GetILimage()->LoadFromMapped(); } @@ -1122,10 +1124,10 @@ BOOL RuntimeVerifyNativeImageVersion(const CORCOMPILE_VERSION_INFO *info, PEAsse // Check that the EE version numbers are the same. // - if (info->wVersionMajor != CLR_MAJOR_VERSION - || info->wVersionMinor != CLR_MINOR_VERSION - || info->wVersionBuildNumber != CLR_BUILD_VERSION - || info->wVersionPrivateBuildNumber != CLR_BUILD_VERSION_QFE) + if (info->wVersionMajor != RuntimeFileMajorVersion + || info->wVersionMinor != RuntimeFileMinorVersion + || info->wVersionBuildNumber != RuntimeFileBuildVersion + || info->wVersionPrivateBuildNumber != RuntimeFileRevisionVersion) { RuntimeVerifyLog(LL_ERROR, pLogAsm, W("CLR version recorded in native image doesn't match the current CLR.")); return FALSE; diff --git a/src/coreclr/src/vm/peimage.cpp b/src/coreclr/src/vm/peimage.cpp index 7dc580fe8f8d8d..be06ebc837a146 100644 --- a/src/coreclr/src/vm/peimage.cpp +++ b/src/coreclr/src/vm/peimage.cpp @@ -973,7 +973,7 @@ PTR_PEImageLayout PEImage::GetLayoutInternal(DWORD imageLayoutMask,DWORD flags) BOOL bIsFlatLayoutSuitable = ((imageLayoutMask & PEImageLayout::LAYOUT_FLAT) != 0); #if !defined(TARGET_UNIX) - if (bIsMappedLayoutSuitable) + if (!IsInBundle() && bIsMappedLayoutSuitable) { bIsFlatLayoutSuitable = FALSE; } @@ -1183,7 +1183,14 @@ void PEImage::Load() } #ifdef TARGET_UNIX - if (m_pLayouts[IMAGE_FLAT] != NULL + bool canUseLoadedFlat = true; +#else + bool canUseLoadedFlat = IsInBundle(); +#endif // TARGET_UNIX + + + if (canUseLoadedFlat + && m_pLayouts[IMAGE_FLAT] != NULL && m_pLayouts[IMAGE_FLAT]->CheckILOnlyFormat() && !m_pLayouts[IMAGE_FLAT]->HasWriteableSections()) { @@ -1200,7 +1207,6 @@ void PEImage::Load() SetLayout(IMAGE_LOADED, m_pLayouts[IMAGE_FLAT]); } else -#endif // TARGET_UNIX { if(!IsFile()) { @@ -1328,19 +1334,19 @@ HANDLE PEImage::GetFileHandle() { ErrorModeHolder mode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS); - m_hFile=WszCreateFile((LPCWSTR) m_path, - GENERIC_READ, - FILE_SHARE_READ|FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); + m_hFile=WszCreateFile((LPCWSTR) GetPathToLoad(), + GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); } if (m_hFile == INVALID_HANDLE_VALUE) { #if !defined(DACCESS_COMPILE) - EEFileLoadException::Throw(m_path, HRESULT_FROM_WIN32(GetLastError())); + EEFileLoadException::Throw(GetPathToLoad(), HRESULT_FROM_WIN32(GetLastError())); #else // defined(DACCESS_COMPILE) ThrowLastError(); #endif // !defined(DACCESS_COMPILE) @@ -1374,14 +1380,14 @@ HRESULT PEImage::TryOpenFile() if (m_hFile!=INVALID_HANDLE_VALUE) return S_OK; { - ErrorModeHolder mode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS); - m_hFile=WszCreateFile((LPCWSTR) m_path, - GENERIC_READ, - FILE_SHARE_READ|FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); + ErrorModeHolder mode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); + m_hFile=WszCreateFile((LPCWSTR)GetPathToLoad(), + GENERIC_READ, + FILE_SHARE_READ|FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); } if (m_hFile != INVALID_HANDLE_VALUE) return S_OK; diff --git a/src/coreclr/src/vm/peimage.h b/src/coreclr/src/vm/peimage.h index 1edf05d8ec2175..2a9b0b76ac10a7 100644 --- a/src/coreclr/src/vm/peimage.h +++ b/src/coreclr/src/vm/peimage.h @@ -19,6 +19,7 @@ #include "peimagelayout.h" #include "sstring.h" #include "holder.h" +#include class SimpleRWLock; // -------------------------------------------------------------------------------- @@ -102,7 +103,8 @@ class PEImage #endif // !TARGET_UNIX static PTR_PEImage OpenImage( LPCWSTR pPath, - MDInternalImportFlags flags = MDInternalImport_Default); + MDInternalImportFlags flags = MDInternalImport_Default, + BundleFileLocation bundleFileLocation = BundleFileLocation::Invalid()); // clones the image with new flags (this is pretty much about cached / noncached difference) @@ -146,8 +148,13 @@ class PEImage // Accessors const SString &GetPath(); + const SString& GetPathToLoad(); BOOL IsFile(); + BOOL IsInBundle() const; HANDLE GetFileHandle(); + INT64 GetOffset() const; + INT64 GetSize() const; + void SetFileHandle(HANDLE hFile); HRESULT TryOpenFile(); @@ -237,7 +244,7 @@ class PEImage // Private routines // ------------------------------------------------------------ - void Init(LPCWSTR pPath); + void Init(LPCWSTR pPath, BundleFileLocation bundleFileLocation); void Init(IStream* pStream, UINT64 uStreamAsmId, DWORD dwModuleId, BOOL resourceFile); @@ -273,6 +280,10 @@ class PEImage SString m_path; LONG m_refCount; + BundleFileLocation m_bundleFileLocation; // If this image is located within a single-file bundle, + // the location within the bundle. If m_bundleFileLocation is vaild, + // it takes precedence over m_path for loading. + // This variable will have the data of module name. // It is only used by DAC to remap fusion loaded modules back to // disk IL. This really is a workaround. The real fix is for fusion loader diff --git a/src/coreclr/src/vm/peimage.inl b/src/coreclr/src/vm/peimage.inl index 03d8bc229ce05e..eebae16e15f7a5 100644 --- a/src/coreclr/src/vm/peimage.inl +++ b/src/coreclr/src/vm/peimage.inl @@ -33,6 +33,33 @@ inline const SString &PEImage::GetPath() return m_path; } +inline const SString& PEImage::GetPathToLoad() +{ + LIMITED_METHOD_DAC_CONTRACT; + + return IsInBundle() ? m_bundleFileLocation.Path() : m_path; +} + +inline INT64 PEImage::GetOffset() const +{ + LIMITED_METHOD_CONTRACT; + + return m_bundleFileLocation.Offset; +} + +inline BOOL PEImage::IsInBundle() const +{ + LIMITED_METHOD_CONTRACT; + + return m_bundleFileLocation.IsValid(); +} + +inline INT64 PEImage::GetSize() const +{ + LIMITED_METHOD_CONTRACT; + return m_bundleFileLocation.Size; +} + inline void PEImage::SetModuleFileNameHintForDAC() { LIMITED_METHOD_DAC_CONTRACT; @@ -71,7 +98,7 @@ inline BOOL PEImage::IsFile() { WRAPPER_NO_CONTRACT; - return !m_path.IsEmpty(); + return !GetPathToLoad().IsEmpty(); } #ifndef DACCESS_COMPILE @@ -433,7 +460,7 @@ inline CHECK PEImage::CheckFormat() CHECK_OK; } -inline void PEImage::Init(LPCWSTR pPath) +inline void PEImage::Init(LPCWSTR pPath, BundleFileLocation bundleFileLocation) { CONTRACTL { @@ -442,8 +469,10 @@ inline void PEImage::Init(LPCWSTR pPath) MODE_ANY; } CONTRACTL_END; + m_path = pPath; m_path.Normalize(); + m_bundleFileLocation = bundleFileLocation; SetModuleFileNameHintForDAC(); } #ifndef DACCESS_COMPILE @@ -475,14 +504,14 @@ inline PTR_PEImage PEImage::FindByPath(LPCWSTR pPath) } /* static */ -inline PTR_PEImage PEImage::OpenImage(LPCWSTR pPath, MDInternalImportFlags flags /* = MDInternalImport_Default */) +inline PTR_PEImage PEImage::OpenImage(LPCWSTR pPath, MDInternalImportFlags flags /* = MDInternalImport_Default */, BundleFileLocation bundleFileLocation) { BOOL fUseCache = !((flags & MDInternalImport_NoCache) == MDInternalImport_NoCache); if (!fUseCache) { PEImageHolder pImage(new PEImage); - pImage->Init(pPath); + pImage->Init(pPath, bundleFileLocation); return dac_cast(pImage.Extract()); } @@ -504,7 +533,7 @@ inline PTR_PEImage PEImage::OpenImage(LPCWSTR pPath, MDInternalImportFlags flags if (flags & MDInternalImport_TrustedNativeImage) pImage->SetIsTrustedNativeImage(); #endif - pImage->Init(pPath); + pImage->Init(pPath, bundleFileLocation); pImage->AddToHashMap(); return dac_cast(pImage.Extract()); diff --git a/src/coreclr/src/vm/peimagelayout.cpp b/src/coreclr/src/vm/peimagelayout.cpp index 79739716da430d..33032108e7e3e6 100644 --- a/src/coreclr/src/vm/peimagelayout.cpp +++ b/src/coreclr/src/vm/peimagelayout.cpp @@ -40,6 +40,17 @@ PEImageLayout* PEImageLayout::LoadFromFlat(PEImageLayout* pflatimage) return new ConvertedImageLayout(pflatimage); } +PEImageLayout* PEImageLayout::LoadConverted(PEImage* pOwner) +{ + STANDARD_VM_CONTRACT; + + PEImageLayoutHolder pFlat(new FlatImageLayout(pOwner)); + if (!pFlat->CheckFormat()) + ThrowHR(COR_E_BADIMAGEFORMAT); + + return new ConvertedImageLayout(pFlat); +} + PEImageLayout* PEImageLayout::Load(PEImage* pOwner, BOOL bNTSafeLoad, BOOL bThrowOnError) { STANDARD_VM_CONTRACT; @@ -47,6 +58,11 @@ PEImageLayout* PEImageLayout::Load(PEImage* pOwner, BOOL bNTSafeLoad, BOOL bThro #if defined(CROSSGEN_COMPILE) || defined(TARGET_UNIX) return PEImageLayout::Map(pOwner); #else + if (pOwner->IsInBundle()) + { + return PEImageLayout::LoadConverted(pOwner); + } + PEImageLayoutHolder pAlloc(new LoadedImageLayout(pOwner,bNTSafeLoad,bThrowOnError)); if (pAlloc->GetBase()==NULL) return NULL; @@ -83,11 +99,7 @@ PEImageLayout* PEImageLayout::Map(PEImage* pOwner) if (pAlloc->GetBase()==NULL) { //cross-platform or a bad image - PEImageLayoutHolder pFlat(new FlatImageLayout(pOwner)); - if (!pFlat->CheckFormat()) - ThrowHR(COR_E_BADIMAGEFORMAT); - - pAlloc=new ConvertedImageLayout(pFlat); + pAlloc = LoadConverted(pOwner); } else if(!pAlloc->CheckFormat()) @@ -393,8 +405,8 @@ ConvertedImageLayout::ConvertedImageLayout(PEImageLayout* source) m_FileMap.Assign(WszCreateFileMapping(INVALID_HANDLE_VALUE, NULL, - PAGE_READWRITE, 0, - source->GetVirtualSize(), NULL)); + PAGE_READWRITE, 0, + source->GetVirtualSize(), NULL)); if (m_FileMap == NULL) ThrowLastError(); @@ -428,6 +440,8 @@ MappedImageLayout::MappedImageLayout(PEImage* pOwner) m_pOwner=pOwner; HANDLE hFile = pOwner->GetFileHandle(); + INT64 offset = pOwner->GetOffset(); + INT64 size = pOwner->GetSize(); // If mapping was requested, try to do SEC_IMAGE mapping LOG((LF_LOADER, LL_INFO100, "PEImage: Opening OS mapped %S (hFile %p)\n", (LPCWSTR) GetPath(), hFile)); @@ -459,21 +473,24 @@ MappedImageLayout::MappedImageLayout(PEImage* pOwner) ThrowWin32(dwLastError); } -#endif // CROSSGEN_COMPILE +#endif // !CROSSGEN_COMPILE return; } + DWORD offsetLowPart = (DWORD)offset; + DWORD offsetHighPart = (DWORD)(offset >> 32); + #ifdef _DEBUG // Force relocs by occuping the preferred base while the actual mapping is performed CLRMapViewHolder forceRelocs; if (PEDecoder::GetForceRelocs()) { - forceRelocs.Assign(CLRMapViewOfFile(m_FileMap, 0, 0, 0, 0)); + forceRelocs.Assign(CLRMapViewOfFile(m_FileMap, 0, offsetHighPart, offsetLowPart, (SIZE_T)size)); } #endif // _DEBUG - m_FileView.Assign(CLRMapViewOfFile(m_FileMap, 0, 0, 0, 0)); + m_FileView.Assign(CLRMapViewOfFile(m_FileMap, 0, offsetHighPart, offsetLowPart, (SIZE_T)size)); if (m_FileView == NULL) ThrowLastError(); IfFailThrow(Init((void *) m_FileView)); @@ -502,7 +519,7 @@ MappedImageLayout::MappedImageLayout(PEImage* pOwner) } } else -#endif +#endif // CROSSGEN_COMPILE if (!IsNativeMachineFormat() && !IsI386()) { //can't rely on the image @@ -529,7 +546,7 @@ MappedImageLayout::MappedImageLayout(PEImage* pOwner) #else //!TARGET_UNIX #ifndef CROSSGEN_COMPILE - m_LoadedFile = PAL_LOADLoadPEFile(hFile); + m_LoadedFile = PAL_LOADLoadPEFile(hFile, offset); if (m_LoadedFile == NULL) { @@ -612,13 +629,19 @@ FlatImageLayout::FlatImageLayout(PEImage* pOwner) m_pOwner=pOwner; HANDLE hFile = pOwner->GetFileHandle(); + INT64 offset = pOwner->GetOffset(); + INT64 size = pOwner->GetSize(); LOG((LF_LOADER, LL_INFO100, "PEImage: Opening flat %S\n", (LPCWSTR) GetPath())); - COUNT_T size = SafeGetFileSize(hFile, NULL); - if (size == 0xffffffff && GetLastError() != NOERROR) + // If a size is not specified, load the whole file + if (size == 0) { - ThrowLastError(); + size = SafeGetFileSize(hFile, NULL); + if (size == 0xffffffff && GetLastError() != NOERROR) + { + ThrowLastError(); + } } // It's okay if resource files are length zero @@ -628,11 +651,16 @@ FlatImageLayout::FlatImageLayout(PEImage* pOwner) if (m_FileMap == NULL) ThrowLastError(); - m_FileView.Assign(CLRMapViewOfFile(m_FileMap, FILE_MAP_READ, 0, 0, 0)); + //DWORD lowPart = (DWORD)offset; + //DWORD highPart = (DWORD)(offset >> 32); + char *addr = (char*)CLRMapViewOfFile(m_FileMap, FILE_MAP_READ, 0, 0, 0); + addr += offset; + m_FileView.Assign((LPVOID)addr); + if (m_FileView == NULL) ThrowLastError(); } - Init(m_FileView, size); + Init(m_FileView, (COUNT_T)size); } NativeImageLayout::NativeImageLayout(LPCWSTR fullPath) @@ -655,7 +683,7 @@ NativeImageLayout::NativeImageLayout(LPCWSTR fullPath) ThrowLastError(); } - loadedImage = PAL_LOADLoadPEFile(fileHandle); + loadedImage = PAL_LOADLoadPEFile(fileHandle, 0); } #else loadedImage = CLRLoadLibraryEx(fullPath, NULL, GetLoadWithAlteredSearchPathFlag()); diff --git a/src/coreclr/src/vm/peimagelayout.h b/src/coreclr/src/vm/peimagelayout.h index 9ae14c4b74e541..bc846c54d6c748 100644 --- a/src/coreclr/src/vm/peimagelayout.h +++ b/src/coreclr/src/vm/peimagelayout.h @@ -54,6 +54,7 @@ class PEImageLayout : public PEDecoder static PEImageLayout* LoadFromFlat(PEImageLayout* pflatimage); static PEImageLayout* Load(PEImage* pOwner, BOOL bNTSafeLoad, BOOL bThrowOnError = TRUE); static PEImageLayout* LoadFlat(PEImage* pOwner); + static PEImageLayout* LoadConverted(PEImage* pOwner); static PEImageLayout* LoadNative(LPCWSTR fullPath); static PEImageLayout* Map(PEImage* pOwner); #endif diff --git a/src/coreclr/src/vm/pgo.cpp b/src/coreclr/src/vm/pgo.cpp new file mode 100644 index 00000000000000..3d1826b7eba3b9 --- /dev/null +++ b/src/coreclr/src/vm/pgo.cpp @@ -0,0 +1,368 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "common.h" +#include "log.h" +#include "pgo.h" + +#ifdef FEATURE_PGO + +ICorJitInfo::BlockCounts* PgoManager::s_PgoData; +unsigned PgoManager::s_PgoIndex; +const char* const PgoManager::s_FileHeaderString = "*** START PGO Data, max index = %u ***\n"; +const char* const PgoManager::s_FileTrailerString = "*** END PGO Data ***\n"; +const char* const PgoManager::s_MethodHeaderString = "@@@ token 0x%08X hash 0x%08X ilSize 0x%08X records 0x%08X index %u\n"; +const char* const PgoManager::s_RecordString = "ilOffs %u count %u\n"; + +void PgoManager::Initialize() +{ + LIMITED_METHOD_CONTRACT; + + // If any PGO mode is active, allocate the slab + if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ReadPGOData) > 0) || + (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_WritePGOData) > 0) || + (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TieredPGO) > 0)) + { + s_PgoData = new ICorJitInfo::BlockCounts[BUFFER_SIZE]; + s_PgoIndex = 0; + } + + // If we're reading in counts, do that now + ReadPgoData(); +} + +void PgoManager::Shutdown() +{ + WritePgoData(); +} + +void PgoManager::WritePgoData() +{ + if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_WritePGOData) == 0) + { + return; + } + + if (s_PgoData == NULL) + { + return; + } + + CLRConfigStringHolder fileName(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PGODataPath)); + + if (fileName == NULL) + { + return; + } + + FILE* const pgoDataFile = _wfopen(fileName, W("w")); + + if (pgoDataFile == NULL) + { + return; + } + + fprintf(pgoDataFile, s_FileHeaderString, s_PgoIndex); + unsigned index = 0; + const unsigned maxIndex = s_PgoIndex; + + while (index < maxIndex) + { + const Header* const header = (Header*)&s_PgoData[index]; + + if ((header->recordCount < MIN_RECORD_COUNT) || (header->recordCount > MAX_RECORD_COUNT)) + { + fprintf(pgoDataFile, "Unreasonable record count %u at index %u\n", header->recordCount, index); + break; + } + + fprintf(pgoDataFile, s_MethodHeaderString, header->token, header->hash, header->ilSize, header->recordCount, index); + + index += 2; + + ICorJitInfo::BlockCounts* records = &s_PgoData[index]; + unsigned recordCount = header->recordCount - 2; + unsigned lastOffset = 0; + for (unsigned i = 0; i < recordCount; i++) + { + const unsigned thisOffset = records[i].ILOffset; + assert((thisOffset > lastOffset) || (lastOffset == 0)); + lastOffset = thisOffset; + fprintf(pgoDataFile, s_RecordString, records[i].ILOffset, records[i].ExecutionCount); + } + + index += recordCount; + } + + fprintf(pgoDataFile, s_FileTrailerString); + fclose(pgoDataFile); +} + +void PgoManager::ReadPgoData() +{ + // Skip, if we're not reading, or we're writing profile data, or doing tiered pgo + // + if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_WritePGOData) > 0) || + (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TieredPGO) > 0) || + (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ReadPGOData) == 0)) + { + return; + } + + // PGO data slab should already be set up, if not, just bail + // + if (s_PgoData == NULL) + { + return; + } + + CLRConfigStringHolder fileName(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PGODataPath)); + + if (fileName == NULL) + { + return; + } + + FILE* const pgoDataFile = _wfopen(fileName, W("r")); + + if (pgoDataFile == NULL) + { + return; + } + + char buffer[256]; + unsigned maxIndex = 0; + + // Header must be first line + // + if (fgets(buffer, sizeof(buffer), pgoDataFile) == nullptr) + { + return; + } + + if (sscanf_s(buffer, s_FileHeaderString, &maxIndex) != 1) + { + return; + } + + // Sanity check data will fit into the slab + // + if ((maxIndex == 0) || (maxIndex >= MAX_RECORD_COUNT)) + { + return; + } + + // Fill in the data + // + unsigned index = 0; + unsigned methods = 0; + unsigned probes = 0; + + bool failed = false; + while (!failed) + { + if (fgets(buffer, sizeof(buffer), pgoDataFile) == nullptr) + { + break; + } + + // Find the next method entry line + // + unsigned recordCount = 0; + unsigned token = 0; + unsigned hash = 0; + unsigned ilSize = 0; + unsigned rIndex = 0; + + if (sscanf_s(buffer, s_MethodHeaderString, &token, &hash, &ilSize, &recordCount, &rIndex) != 5) + { + continue; + } + + assert(index == rIndex); + methods++; + + // If there's not enough room left, bail + if ((index + recordCount) > maxIndex) + { + failed = true; + break; + } + + Header* const header = (Header*)&s_PgoData[index]; + + header->recordCount = recordCount; + header->token = token; + header->hash = hash; + header->ilSize = ilSize; + + // Sanity check + // + if ((recordCount < MIN_RECORD_COUNT) || (recordCount > MAX_RECORD_COUNT)) + { + failed = true; + break; + } + + index += 2; + + // Read il data + // + for (unsigned i = 0; i < recordCount - 2; i++) + { + if (fgets(buffer, sizeof(buffer), pgoDataFile) == nullptr) + { + failed = true; + break; + } + + if (sscanf_s(buffer, s_RecordString, &s_PgoData[index].ILOffset, &s_PgoData[index].ExecutionCount) != 2) + { + failed = true; + break; + } + + index++; + } + + probes += recordCount - 2; + } + + s_PgoIndex = maxIndex; +} + +HRESULT PgoManager::allocMethodBlockCounts(MethodDesc* pMD, UINT32 count, + ICorJitInfo::BlockCounts** pBlockCounts, unsigned ilSize) +{ + // Initialize our out param + *pBlockCounts = NULL; + + if (s_PgoData == nullptr) + { + return E_NOTIMPL; + } + + unsigned methodIndex = 0; + unsigned recordCount = count + 2; + + // Look for space in the profile buffer for this method. + // Note other jit invocations may be vying for space concurrently. + // + while (true) + { + const unsigned oldIndex = s_PgoIndex; + const unsigned newIndex = oldIndex + recordCount; + + // If there is no room left for this method, + // that's ok, we just won't profile this method. + // + if (newIndex >= BUFFER_SIZE) + { + return E_NOTIMPL; + } + + const unsigned updatedIndex = InterlockedCompareExchangeT(&s_PgoIndex, newIndex, oldIndex); + + if (updatedIndex == oldIndex) + { + // Found space + methodIndex = oldIndex; + break; + } + } + + // Fill in the header + Header* const header = (Header*)&s_PgoData[methodIndex]; + header->recordCount = recordCount; + header->token = pMD->IsDynamicMethod() ? 0 : pMD->GetMemberDef(); + header->hash = pMD->GetStableHash(); + header->ilSize = ilSize; + + // Return pointer to start of count records + *pBlockCounts = &s_PgoData[methodIndex + 2]; + return S_OK; +} + +HRESULT PgoManager::getMethodBlockCounts(MethodDesc* pMD, unsigned ilSize, UINT32* pCount, + ICorJitInfo::BlockCounts** pBlockCounts, UINT32* pNumRuns) +{ + // Initialize our out params + *pCount = 0; + *pBlockCounts = NULL; + *pNumRuns = 0; + + // Bail if there's no profile data. + // + if (s_PgoData == NULL) + { + return E_NOTIMPL; + } + + // See if we can find counts for this method in the profile buffer. + // + const unsigned maxIndex = s_PgoIndex; + const unsigned token = pMD->IsDynamicMethod() ? 0 : pMD->GetMemberDef(); + const unsigned hash = pMD->GetStableHash(); + + + unsigned index = 0; + unsigned methodsChecked = 0; + + while (index < maxIndex) + { + // The first two "records" of each entry are actually header data + // to identify the method. + // + Header* const header = (Header*)&s_PgoData[index]; + + // Sanity check that header data looks reasonable. If not, just + // fail the lookup. + // + if ((header->recordCount < MIN_RECORD_COUNT) || (header->recordCount > MAX_RECORD_COUNT)) + { + break; + } + + // See if the header info matches the current method. + // + if ((header->token == token) && (header->hash == hash) && (header->ilSize == ilSize)) + { + // Yep, found data. + // + *pBlockCounts = &s_PgoData[index + 2]; + *pCount = header->recordCount - 2; + *pNumRuns = 1; + return S_OK; + } + + index += header->recordCount; + methodsChecked++; + } + + return E_NOTIMPL; +} + +#else + +// Stub version for !FEATURE_PGO builds +// +HRESULT PgoManager::allocMethodBlockCounts(MethodDesc* pMD, UINT32 count, + ICorJitInfo::BlockCounts** pBlockCounts, unsigned ilSize) +{ + pBlockCounts = NULL; + return E_NOTIMPL; +} + +// Stub version for !FEATURE_PGO builds +// +HRESULT PgoManager::getMethodBlockCounts(MethodDesc* pMD, unsigned ilSize, UINT32* pCount, + ICorJitInfo::BlockCounts** pBlockCounts, UINT32* pNumRuns) +{ + pBlockCounts = NULL; + pCount = 0; + pNumRuns = 0; + return E_NOTIMPL; +} + +#endif // FEATURE_PGO diff --git a/src/coreclr/src/vm/pgo.h b/src/coreclr/src/vm/pgo.h new file mode 100644 index 00000000000000..acaf74712c8671 --- /dev/null +++ b/src/coreclr/src/vm/pgo.h @@ -0,0 +1,72 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#ifndef PGO_H +#define PGO_H + +// PgoManager handles in-process and out of band profile data for jitted code. +class PgoManager +{ +#ifdef FEATURE_PGO + +public: + + static void Initialize(); + static void Shutdown(); + +#endif // FEATURE_PGO + +public: + + // Allocate a profile block count buffer for a method + static HRESULT allocMethodBlockCounts(MethodDesc* pMD, UINT32 count, + ICorJitInfo::BlockCounts** pBlockCounts, unsigned ilSize); + + // Retreive the profile block count buffer for a method + static HRESULT getMethodBlockCounts(MethodDesc* pMD, unsigned ilSize, UINT32* pCount, + ICorJitInfo::BlockCounts** pBlockCounts, UINT32* pNumRuns); + +#ifdef FEATURE_PGO + +private: + + enum + { + // Number of ICorJitInfo::BlockCount records in the global slab + BUFFER_SIZE = 64 * 1024, + MIN_RECORD_COUNT = 3, + MAX_RECORD_COUNT = BUFFER_SIZE + }; + + struct Header + { + unsigned recordCount; + unsigned token; + unsigned hash; + unsigned ilSize; + }; + +private: + + static void ReadPgoData(); + static void WritePgoData(); + +private: + + // Global slab holding all pgo data + static ICorJitInfo::BlockCounts* s_PgoData; + + // Index of next free entry in the global slab + static unsigned s_PgoIndex; + + // Formatting strings for file input/output + static const char* const s_FileHeaderString; + static const char* const s_FileTrailerString; + static const char* const s_MethodHeaderString; + static const char* const s_RecordString; + +#endif // FEATURE_PGO +}; + +#endif // PGO_H diff --git a/src/coreclr/src/vm/prestub.cpp b/src/coreclr/src/vm/prestub.cpp index cd25aaa0f90e77..c32ca111f19b4b 100644 --- a/src/coreclr/src/vm/prestub.cpp +++ b/src/coreclr/src/vm/prestub.cpp @@ -370,7 +370,7 @@ PCODE MethodDesc::PrepareILBasedCode(PrepareCodeConfig* pConfig) if (stubMethodDesc->IsILStub() && stubMethodDesc->IsPInvokeStub()) { ILStubResolver* pStubResolver = stubMethodDesc->GetILStubResolver(); - if (pStubResolver->IsCLRToNativeInteropStub()) + if (pStubResolver->GetStubType() == ILStubResolver::CLRToNativeInteropStub) { MethodDesc* pTargetMD = stubMethodDesc->GetILStubResolver()->GetStubTargetMethodDesc(); if (pTargetMD != NULL) @@ -443,12 +443,12 @@ PCODE MethodDesc::GetPrecompiledCode(PrepareCodeConfig* pConfig) CallerGCMode callerGcMode = pConfig->GetCallerGCMode(); // If the method is eligible for tiering but is being // called from a Preemptive GC Mode thread or the method - // has the NativeCallableAttribute then the Tiered Compilation + // has the UnmanagedCallersOnlyAttribute then the Tiered Compilation // should be disabled. if (shouldTier && (callerGcMode == CallerGCMode::Preemptive || (callerGcMode == CallerGCMode::Unknown - && HasNativeCallableAttribute()))) + && HasUnmanagedCallersOnlyAttribute()))) { NativeCodeVersion codeVersion = pConfig->GetCodeVersion(); if (codeVersion.IsDefaultVersion()) @@ -1806,14 +1806,14 @@ extern "C" MethodDesc * STDCALL PreStubGetMethodDescForCompactEntryPoint (PCODE //============================================================================= // This function generates the real code when from Preemptive mode. -// It is specifically designed to work with the NativeCallableAttribute. +// It is specifically designed to work with the UnmanagedCallersOnlyAttribute. //============================================================================= static PCODE PreStubWorker_Preemptive( _In_ TransitionBlock* pTransitionBlock, _In_ MethodDesc* pMD, _In_opt_ Thread* currentThread) { - _ASSERTE(pMD->HasNativeCallableAttribute()); + _ASSERTE(pMD->HasUnmanagedCallersOnlyAttribute()); PCODE pbRetVal = NULL; @@ -1835,7 +1835,7 @@ static PCODE PreStubWorker_Preemptive( MAKE_CURRENT_THREAD_AVAILABLE_EX(currentThread); // No GC frame is needed here since there should be no OBJECTREFs involved - // in this call due to NativeCallableAttribute semantics. + // in this call due to UnmanagedCallersOnlyAttribute semantics. INSTALL_MANAGED_EXCEPTION_DISPATCHER; INSTALL_UNWIND_AND_CONTINUE_HANDLER; diff --git a/src/coreclr/src/vm/profilinghelper.cpp b/src/coreclr/src/vm/profilinghelper.cpp index aac5fbb563b278..e5af2fcdfacac0 100644 --- a/src/coreclr/src/vm/profilinghelper.cpp +++ b/src/coreclr/src/vm/profilinghelper.cpp @@ -702,10 +702,10 @@ HRESULT ProfilingAPIUtility::AttemptLoadProfilerForStartup() IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER, &wszClsid)); -#if defined(TARGET_X86) - IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_32, &wszProfilerDLL)); -#elif defined(TARGET_AMD64) +#ifdef TARGET_64BIT IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_64, &wszProfilerDLL)); +#else + IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_32, &wszProfilerDLL)); #endif if(wszProfilerDLL == NULL) { diff --git a/src/coreclr/src/vm/proftoeeinterfaceimpl.cpp b/src/coreclr/src/vm/proftoeeinterfaceimpl.cpp index 4801655c1ce4ce..6f83565ea4a93f 100644 --- a/src/coreclr/src/vm/proftoeeinterfaceimpl.cpp +++ b/src/coreclr/src/vm/proftoeeinterfaceimpl.cpp @@ -9217,30 +9217,44 @@ HRESULT ProfToEEInterfaceImpl::GetRuntimeInformation(USHORT * pClrInstanceId, if (pcchVersionString != NULL) { - HRESULT hr = GetCORVersionInternal(szVersionString, (DWORD)cchVersionString, (DWORD *)pcchVersionString); - if (FAILED(hr)) - return hr; + PCWSTR pczVersionString = CLR_PRODUCT_VERSION_L; + + // Get the module file name + ULONG trueLen = (ULONG)(wcslen(pczVersionString) + 1); + + // Return name of module as required. + if (szVersionString && cchVersionString > 0) + { + ULONG copyLen = trueLen; + + if (copyLen >= cchVersionString) + { + copyLen = cchVersionString - 1; + } + + wcsncpy_s(szVersionString, cchVersionString, pczVersionString, copyLen); + } + + *pcchVersionString = trueLen; } if (pClrInstanceId != NULL) *pClrInstanceId = static_cast(GetClrInstanceId()); if (pRuntimeType != NULL) - { *pRuntimeType = COR_PRF_CORE_CLR; - } if (pMajorVersion != NULL) - *pMajorVersion = CLR_MAJOR_VERSION; + *pMajorVersion = RuntimeProductMajorVersion; if (pMinorVersion != NULL) - *pMinorVersion = CLR_MINOR_VERSION; + *pMinorVersion = RuntimeProductMinorVersion; if (pBuildNumber != NULL) - *pBuildNumber = CLR_BUILD_VERSION; + *pBuildNumber = RuntimeProductPatchVersion; if (pQFEVersion != NULL) - *pQFEVersion = CLR_BUILD_VERSION_QFE; + *pQFEVersion = 0; return S_OK; } diff --git a/src/coreclr/src/vm/qcall.h b/src/coreclr/src/vm/qcall.h index 380a041ca9215b..32ce22f1bec8a0 100644 --- a/src/coreclr/src/vm/qcall.h +++ b/src/coreclr/src/vm/qcall.h @@ -137,7 +137,13 @@ GC_TRIGGERS; \ MODE_PREEMPTIVE; \ +#define QCALL_CHECK_NO_GC_TRANSITION \ + THROWS; \ + GC_TRIGGERS; \ + MODE_COOPERATIVE; \ + #define QCALL_CONTRACT CONTRACTL { QCALL_CHECK; } CONTRACTL_END; +#define QCALL_CONTRACT_NO_GC_TRANSITION CONTRACTL { QCALL_CHECK_NO_GC_TRANSITION; } CONTRACTL_END; // // Scope class for QCall helper methods and types diff --git a/src/coreclr/src/vm/rcwwalker.cpp b/src/coreclr/src/vm/rcwwalker.cpp index 5c94a3ea536909..8c8e5f0d7f6632 100644 --- a/src/coreclr/src/vm/rcwwalker.cpp +++ b/src/coreclr/src/vm/rcwwalker.cpp @@ -150,7 +150,7 @@ STDMETHODIMP CLRServicesImpl::AddMemoryPressure(UINT64 bytesAllocated) HRESULT hr = S_OK; BEGIN_EXTERNAL_ENTRYPOINT(&hr) { - GCInterface::NewAddMemoryPressure(bytesAllocated); + GCInterface::AddMemoryPressure(bytesAllocated); } END_EXTERNAL_ENTRYPOINT; return hr; @@ -168,7 +168,7 @@ STDMETHODIMP CLRServicesImpl::RemoveMemoryPressure(UINT64 bytesAllocated) HRESULT hr = S_OK; BEGIN_EXTERNAL_ENTRYPOINT(&hr) { - GCInterface::NewRemoveMemoryPressure(bytesAllocated); + GCInterface::RemoveMemoryPressure(bytesAllocated); } END_EXTERNAL_ENTRYPOINT; return hr; @@ -570,7 +570,7 @@ void RCWWalker::WalkRCWs() { hr = GET_EXCEPTION()->GetHR(); } - EX_END_CATCH(RethrowCorruptingExceptions) // Make sure we crash on AV (instead of swallowing everything) + EX_END_CATCH(RethrowTerminalExceptions) if (FAILED(hr)) { diff --git a/src/coreclr/src/vm/reflectioninvocation.cpp b/src/coreclr/src/vm/reflectioninvocation.cpp index 2724de4771b1fa..c530786aa38796 100644 --- a/src/coreclr/src/vm/reflectioninvocation.cpp +++ b/src/coreclr/src/vm/reflectioninvocation.cpp @@ -882,15 +882,6 @@ void DECLSPEC_NORETURN ThrowInvokeMethodException(MethodDesc * pMethod, OBJECTRE } #endif // _DEBUG && !TARGET_UNIX -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // Get the corruption severity of the exception that came in through reflection invocation. - CorruptionSeverity severity = GetThread()->GetExceptionState()->GetLastActiveExceptionCorruptionSeverity(); - - // Since we are dealing with an exception, set the flag indicating if the target of Reflection can handle exception or not. - // This flag is used in CEHelper::CanIDispatchTargetHandleException. - GetThread()->GetExceptionState()->SetCanReflectionTargetHandleException(CEHelper::CanMethodHandleException(severity, pMethod)); -#endif // FEATURE_CORRUPTING_EXCEPTIONS - OBJECTREF except = InvokeUtil::CreateTargetExcept(&targetException); #ifndef TARGET_UNIX @@ -944,11 +935,7 @@ void DECLSPEC_NORETURN ThrowInvokeMethodException(MethodDesc * pMethod, OBJECTRE // Since VM is throwing the exception, we set it to use the same corruption severity // that the original exception came in with from reflection invocation. - COMPlusThrow(except -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - , severity -#endif // FEATURE_CORRUPTING_EXCEPTIONS - ); + COMPlusThrow(except); GCPROTECT_END(); } @@ -1254,12 +1241,6 @@ FCIMPL5(Object*, RuntimeMethodHandle::InvokeMethod, ENDFORBIDGC(); } -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // By default, set the flag in TES indicating the reflection target can handle CSE. - // This flag is used in CEHelper::CanIDispatchTargetHandleException. - pThread->GetExceptionState()->SetCanReflectionTargetHandleException(TRUE); -#endif // FEATURE_CORRUPTING_EXCEPTIONS - if (pValueClasses != NULL) { pProtectValueClassFrame = new (_alloca (sizeof (FrameWithCookie))) @@ -2415,9 +2396,8 @@ FCIMPL1(Object *, ReflectionEnum::InternalGetEnumUnderlyingType, ReflectClassBas VALIDATEOBJECT(target); TypeHandle th = target->GetType(); - if (!th.IsEnum()) - FCThrowArgument(NULL, NULL); - + _ASSERTE(th.IsEnum()); + OBJECTREF result = NULL; HELPER_METHOD_FRAME_BEGIN_RET_0(); diff --git a/src/coreclr/src/vm/rejit.cpp b/src/coreclr/src/vm/rejit.cpp index d954b26352600a..b71c5940ec9ec0 100644 --- a/src/coreclr/src/vm/rejit.cpp +++ b/src/coreclr/src/vm/rejit.cpp @@ -418,18 +418,13 @@ COR_IL_MAP* ProfilerFunctionControl::GetInstrumentedMapEntries() return m_rgInstrumentedMapEntries; } -//--------------------------------------------------------------------------------------- -// ReJitManager implementation - -// All the state-changey stuff is kept up here in the !DACCESS_COMPILE block. -// The more read-only inspection-y stuff follows the block. - #ifndef DACCESS_COMPILE NativeImageInliningIterator::NativeImageInliningIterator() : m_pModule(NULL), m_pInlinee(NULL), m_dynamicBuffer(NULL), m_dynamicBufferSize(0), + m_dynamicAvailable(0), m_currentPos(-1) { @@ -462,16 +457,18 @@ HRESULT NativeImageInliningIterator::Reset(Module *pModule, MethodDesc *pInlinee methodsAvailable = m_pModule->GetNativeOrReadyToRunInliners(inlineeModule, mdInlinee, m_dynamicBufferSize, m_dynamicBuffer, &incompleteData); _ASSERTE(methodsAvailable <= m_dynamicBufferSize); } + + m_dynamicAvailable = methodsAvailable; } EX_CATCH_HRESULT(hr); if (FAILED(hr)) { - m_currentPos = -1; + m_currentPos = s_failurePos; } else { - m_currentPos = 0; + m_currentPos = -1; } return hr; @@ -479,18 +476,20 @@ HRESULT NativeImageInliningIterator::Reset(Module *pModule, MethodDesc *pInlinee BOOL NativeImageInliningIterator::Next() { - if (m_currentPos < 0) + if (m_currentPos == s_failurePos) { return FALSE; } m_currentPos++; - return m_currentPos < m_dynamicBufferSize; + return m_currentPos < m_dynamicAvailable; } MethodDesc *NativeImageInliningIterator::GetMethodDesc() { - if (m_currentPos == (COUNT_T)-1 || m_currentPos >= m_dynamicBufferSize) + // this evaluates true when m_currentPos == s_failurePos or m_currentPos == (COUNT_T)-1 + // m_currentPos is an unsigned type + if (m_currentPos >= m_dynamicAvailable) { return NULL; } @@ -501,6 +500,12 @@ MethodDesc *NativeImageInliningIterator::GetMethodDesc() return pModule->LookupMethodDef(mdInliner); } +//--------------------------------------------------------------------------------------- +// ReJitManager implementation + +// All the state-changey stuff is kept up here in the !DACCESS_COMPILE block. +// The more read-only inspection-y stuff follows the block. + //--------------------------------------------------------------------------------------- // // ICorProfilerInfo4::RequestReJIT calls into this method to do most of the @@ -799,7 +804,7 @@ HRESULT ReJitManager::UpdateNativeInlinerActiveILVersions( // Iterate through all modules, for any that are NGEN or R2R need to check if there are inliners there and call // RequestReJIT on them // TODO: is the default domain enough for coreclr? - AppDomain::AssemblyIterator domainAssemblyIterator = SystemDomain::System()->DefaultDomain()->IterateAssembliesEx((AssemblyIterationFlags) (kIncludeLoaded)); + AppDomain::AssemblyIterator domainAssemblyIterator = SystemDomain::System()->DefaultDomain()->IterateAssembliesEx((AssemblyIterationFlags) (kIncludeLoaded | kIncludeExecution)); CollectibleAssemblyHolder pDomainAssembly; NativeImageInliningIterator inlinerIter; while (domainAssemblyIterator.Next(pDomainAssembly.This())) diff --git a/src/coreclr/src/vm/rejit.h b/src/coreclr/src/vm/rejit.h index 6b2ca65eddc00f..4dbcb869319d3b 100644 --- a/src/coreclr/src/vm/rejit.h +++ b/src/coreclr/src/vm/rejit.h @@ -85,9 +85,11 @@ class NativeImageInliningIterator MethodDesc *m_pInlinee; NewArrayHolder m_dynamicBuffer; COUNT_T m_dynamicBufferSize; + COUNT_T m_dynamicAvailable; COUNT_T m_currentPos; const COUNT_T s_bufferSize = 10; + const COUNT_T s_failurePos = -2; }; #endif // DACCESS_COMPILE diff --git a/src/coreclr/src/vm/rexcep.h b/src/coreclr/src/vm/rexcep.h index 8dc54d81530e1a..4801e264593a8b 100644 --- a/src/coreclr/src/vm/rexcep.h +++ b/src/coreclr/src/vm/rexcep.h @@ -319,10 +319,10 @@ DEFINE_EXCEPTION(g_SystemNS, ArgumentNullException, false, E #ifdef FEATURE_COMINTEROP // Jupiter needs some HRESULTs mapped to exceptions in .NET Framework assemblies other than mscorlib. -DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(g_MarkupNS, XamlParseException, "System.Runtime.WindowsRuntime.UI.Xaml", ECMA_PUBLICKEY_STR, false, E_XAMLPARSEFAILED) -DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(g_AutomationNS, ElementNotAvailableException, "System.Runtime.WindowsRuntime.UI.Xaml", ECMA_PUBLICKEY_STR, false, E_ELEMENTNOTAVAILABLE) -DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(g_AutomationNS, ElementNotEnabledException, "System.Runtime.WindowsRuntime.UI.Xaml", ECMA_PUBLICKEY_STR, false, E_ELEMENTNOTENABLED) -DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(g_DirectUINS, LayoutCycleException, "System.Runtime.WindowsRuntime.UI.Xaml", ECMA_PUBLICKEY_STR, false, E_LAYOUTCYCLE) +DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(g_MarkupNS, XamlParseException, "System.Runtime.WindowsRuntime.UI.Xaml", false, E_XAMLPARSEFAILED) +DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(g_AutomationNS, ElementNotAvailableException, "System.Runtime.WindowsRuntime.UI.Xaml", false, E_ELEMENTNOTAVAILABLE) +DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(g_AutomationNS, ElementNotEnabledException, "System.Runtime.WindowsRuntime.UI.Xaml", false, E_ELEMENTNOTENABLED) +DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(g_DirectUINS, LayoutCycleException, "System.Runtime.WindowsRuntime.UI.Xaml", false, E_LAYOUTCYCLE) #endif // FEATURE_COMINTEROP diff --git a/src/coreclr/src/vm/runtimecallablewrapper.cpp b/src/coreclr/src/vm/runtimecallablewrapper.cpp index 61475bf9ba0d5a..d15ae5e6bbb7e3 100644 --- a/src/coreclr/src/vm/runtimecallablewrapper.cpp +++ b/src/coreclr/src/vm/runtimecallablewrapper.cpp @@ -2432,23 +2432,12 @@ void RCW::AddMemoryPressure(GCPressureSize pressureSize) CONTRACTL_END; int pressure = s_rGCPressureTable[pressureSize]; - - if (pressureSize >= GCPressureSize_WinRT_Base) - { - // use the new implementation for WinRT RCWs - GCInterface::NewAddMemoryPressure(pressure); - } - else - { - // use the old implementation for classic COM interop - GCInterface::AddMemoryPressure(pressure); - } + GCInterface::AddMemoryPressure(pressure); // Remember the pressure we set. m_Flags.m_GCPressure = pressureSize; } - void RCW::RemoveMemoryPressure() { CONTRACTL @@ -2464,17 +2453,7 @@ void RCW::RemoveMemoryPressure() return; int pressure = s_rGCPressureTable[m_Flags.m_GCPressure]; - - if (m_Flags.m_GCPressure >= GCPressureSize_WinRT_Base) - { - // use the new implementation for WinRT RCWs - GCInterface::NewRemoveMemoryPressure(pressure); - } - else - { - // use the old implementation for classic COM interop - GCInterface::RemoveMemoryPressure(pressure); - } + GCInterface::RemoveMemoryPressure(pressure); m_Flags.m_GCPressure = GCPressureSize_None; } diff --git a/src/coreclr/src/vm/runtimeexceptionkind.h b/src/coreclr/src/vm/runtimeexceptionkind.h index 6ed92f7ea83112..6a988e4bbd82bf 100644 --- a/src/coreclr/src/vm/runtimeexceptionkind.h +++ b/src/coreclr/src/vm/runtimeexceptionkind.h @@ -13,7 +13,7 @@ enum RuntimeExceptionKind { #define DEFINE_EXCEPTION(ns, reKind, bHRformessage, ...) k##reKind, #define DEFINE_EXCEPTION_HR_WINRT_ONLY(ns, reKind, ...) -#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, publicKeyToken, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__) +#define DEFINE_EXCEPTION_IN_OTHER_FX_ASSEMBLY(ns, reKind, assemblySimpleName, bHRformessage, ...) DEFINE_EXCEPTION(ns, reKind, bHRformessage, __VA_ARGS__) #include "rexcep.h" kLastException }; diff --git a/src/coreclr/src/vm/runtimehandles.cpp b/src/coreclr/src/vm/runtimehandles.cpp index 2b4cad229bb447..82c793bf3f7af5 100644 --- a/src/coreclr/src/vm/runtimehandles.cpp +++ b/src/coreclr/src/vm/runtimehandles.cpp @@ -22,6 +22,7 @@ #include "eeconfig.h" #include "eehash.h" #include "interoputil.h" +#include "comdelegate.h" #include "typedesc.h" #include "virtualcallstub.h" #include "contractimpl.h" @@ -1109,7 +1110,7 @@ PVOID QCALLTYPE RuntimeTypeHandle::GetGCHandle(QCall::TypeHandle pTypeHandle, IN GCX_COOP(); TypeHandle th = pTypeHandle.AsTypeHandle(); - assert(handleType >= HNDTYPE_WEAK_SHORT && handleType <= HNDTYPE_WEAK_WINRT); + assert(handleType >= HNDTYPE_WEAK_SHORT && handleType <= HNDTYPE_WEAK_NATIVE_COM); objHandle = AppDomain::GetCurrentDomain()->CreateTypedHandle(NULL, static_cast(handleType)); th.GetLoaderAllocator()->RegisterHandleForCleanup(objHandle); @@ -1752,11 +1753,29 @@ void * QCALLTYPE RuntimeMethodHandle::GetFunctionPointer(MethodDesc * pMethod) { QCALL_CONTRACT; - void* funcPtr = 0; + void* funcPtr = NULL; BEGIN_QCALL; + // Ensure the method is active so + // the function pointer can be used. + pMethod->EnsureActive(); + +#if defined(TARGET_X86) + // Deferring X86 support until a need is observed or + // time permits investigation into all the potential issues. + // https://github.com/dotnet/runtime/issues/33582 + if (pMethod->HasUnmanagedCallersOnlyAttribute()) + { + funcPtr = (void*)COMDelegate::ConvertToUnmanagedCallback(pMethod); + } + else + { + funcPtr = (void*)pMethod->GetMultiCallableAddrOfCode(); + } +#else funcPtr = (void*)pMethod->GetMultiCallableAddrOfCode(); +#endif END_QCALL; diff --git a/src/coreclr/src/vm/stackwalk.cpp b/src/coreclr/src/vm/stackwalk.cpp index 04a5db378027f1..9310b863322dc1 100644 --- a/src/coreclr/src/vm/stackwalk.cpp +++ b/src/coreclr/src/vm/stackwalk.cpp @@ -727,14 +727,11 @@ UINT_PTR Thread::VirtualUnwindToFirstManagedCallFrame(T_CONTEXT* pContext) uControlPc = VirtualUnwindCallFrame(pContext); #else // !TARGET_UNIX -#ifdef VSD_STUB_CAN_THROW_AV - if (IsIPinVirtualStub(uControlPc)) + if (AdjustContextForVirtualStub(NULL, pContext)) { - AdjustContextForVirtualStub(NULL, pContext); uControlPc = GetIP(pContext); break; } -#endif // VSD_STUB_CAN_THROW_AV BOOL success = PAL_VirtualUnwind(pContext, NULL); if (!success) diff --git a/src/coreclr/src/vm/stdinterfaces.cpp b/src/coreclr/src/vm/stdinterfaces.cpp index 7ca4975c326785..240bdc926bc3ee 100644 --- a/src/coreclr/src/vm/stdinterfaces.cpp +++ b/src/coreclr/src/vm/stdinterfaces.cpp @@ -1502,7 +1502,7 @@ InternalDispatchImpl_Invoke hr = pDispInfo->InvokeMember(pSimpleWrap, dispidMember, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, NULL, puArgErr); } - END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS; // This will ensure that entry points wont swallow CE and continue to let them propagate out. + END_EXTERNAL_ENTRYPOINT; return hr; } diff --git a/src/coreclr/src/vm/stubgen.cpp b/src/coreclr/src/vm/stubgen.cpp index 2586761a181142..5b76beeecd0afc 100644 --- a/src/coreclr/src/vm/stubgen.cpp +++ b/src/coreclr/src/vm/stubgen.cpp @@ -58,7 +58,7 @@ void DumpIL_RemoveFullPath(SString &strTokenFormatting) } } -void DumpIL_FormatToken(TokenLookupMap* pTokenMap, mdToken token, SString &strTokenFormatting, const SString &strStubTargetSig) +void ILStubLinker::DumpIL_FormatToken(mdToken token, SString &strTokenFormatting) { void* pvLookupRetVal = (void*)POISONC; _ASSERTE(strTokenFormatting.IsEmpty()); @@ -67,7 +67,7 @@ void DumpIL_FormatToken(TokenLookupMap* pTokenMap, mdToken token, SString &strTo { if (TypeFromToken(token) == mdtMethodDef) { - MethodDesc* pMD = pTokenMap->LookupMethodDef(token); + MethodDesc* pMD = m_tokenMap.LookupMethodDef(token); pvLookupRetVal = pMD; CONSISTENCY_CHECK(CheckPointer(pMD)); @@ -75,7 +75,7 @@ void DumpIL_FormatToken(TokenLookupMap* pTokenMap, mdToken token, SString &strTo } else if (TypeFromToken(token) == mdtTypeDef) { - TypeHandle typeHnd = pTokenMap->LookupTypeDef(token); + TypeHandle typeHnd = m_tokenMap.LookupTypeDef(token); pvLookupRetVal = typeHnd.AsPtr(); CONSISTENCY_CHECK(!typeHnd.IsNull()); @@ -100,7 +100,7 @@ void DumpIL_FormatToken(TokenLookupMap* pTokenMap, mdToken token, SString &strTo } else if (TypeFromToken(token) == mdtFieldDef) { - FieldDesc* pFD = pTokenMap->LookupFieldDef(token); + FieldDesc* pFD = m_tokenMap.LookupFieldDef(token); pvLookupRetVal = pFD; CONSISTENCY_CHECK(CheckPointer(pFD)); @@ -116,8 +116,29 @@ void DumpIL_FormatToken(TokenLookupMap* pTokenMap, mdToken token, SString &strTo } else if (TypeFromToken(token) == mdtSignature) { - CONSISTENCY_CHECK(token == TOKEN_ILSTUB_TARGET_SIG); - strTokenFormatting.Set(strStubTargetSig); + CQuickBytes qbTargetSigBytes; + PCCOR_SIGNATURE pSig; + DWORD cbSig; + + if (token == TOKEN_ILSTUB_TARGET_SIG) + { + // Build the current target sig into the buffer. + cbSig = GetStubTargetMethodSigSize(); + pSig = (PCCOR_SIGNATURE)qbTargetSigBytes.AllocThrows(cbSig); + + GetStubTargetMethodSig((BYTE*)pSig, cbSig); + } + else + { + SigPointer sig = m_tokenMap.LookupSig(token); + sig.GetSignature(&pSig, &cbSig); + } + + IMDInternalImport * pIMDI = MscorlibBinder::GetModule()->GetMDImport(); + CQuickBytes sigStr; + PrettyPrintSig(pSig, cbSig, "", &sigStr, pIMDI, NULL); + + strTokenFormatting.SetUTF8((LPUTF8)sigStr.Ptr()); } else { @@ -518,34 +539,12 @@ ILStubLinker::LogILInstruction( if (pDumpILStubCode == NULL) strArgument.Printf(W("0x%08x"), pInstruction->uArg); - LPUTF8 pszFormattedStubTargetSig = NULL; - CQuickBytes qbTargetSig; - - if (TOKEN_ILSTUB_TARGET_SIG == pInstruction->uArg) - { - PCCOR_SIGNATURE pTargetSig; - ULONG cTargetSig; - CQuickBytes qbTempTargetSig; - - IMDInternalImport * pIMDI = MscorlibBinder::GetModule()->GetMDImport(); - - cTargetSig = GetStubTargetMethodSigSize(); - pTargetSig = (PCCOR_SIGNATURE)qbTempTargetSig.AllocThrows(cTargetSig); - - GetStubTargetMethodSig((BYTE*)pTargetSig, cTargetSig); - PrettyPrintSig(pTargetSig, cTargetSig, "", &qbTargetSig, pIMDI, NULL); - - pszFormattedStubTargetSig = (LPUTF8)qbTargetSig.Ptr(); - } - // Dump to szTokenNameBuffer if logging, otherwise dump to szArgumentBuffer to avoid an extra space because we are omitting the token _ASSERTE(FitsIn(pInstruction->uArg)); - SString strFormattedStubTargetSig; - strFormattedStubTargetSig.SetUTF8(pszFormattedStubTargetSig); if (pDumpILStubCode == NULL) - DumpIL_FormatToken(&m_tokenMap, static_cast(pInstruction->uArg), strTokenName, strFormattedStubTargetSig); + DumpIL_FormatToken(static_cast(pInstruction->uArg), strTokenName); else - DumpIL_FormatToken(&m_tokenMap, static_cast(pInstruction->uArg), strArgument, strFormattedStubTargetSig); + DumpIL_FormatToken(static_cast(pInstruction->uArg), strArgument); break; } @@ -802,6 +801,8 @@ size_t ILStubLinker::Link(UINT* puMaxStack) while (pCurrentStream) { + _ASSERTE(pCurrentStream->m_buildingEHClauses.GetCount() == 0); + if (pCurrentStream->m_pqbILInstructions) { ILInstruction* pInstrBuffer = (ILInstruction*)pCurrentStream->m_pqbILInstructions->Ptr(); @@ -841,6 +842,56 @@ size_t ILStubLinker::Link(UINT* puMaxStack) return cbCode; } +size_t ILStubLinker::GetNumEHClauses() +{ + size_t result = 0; + for (ILCodeStream* stream = m_pCodeStreamList; stream; stream = stream->m_pNextStream) + { + result += stream->m_finishedEHClauses.GetCount(); + } + + return result; +} + +void ILStubLinker::WriteEHClauses(COR_ILMETHOD_SECT_EH* pSect) +{ + unsigned int clauseIndex = 0; + for (ILCodeStream* stream = m_pCodeStreamList; stream; stream = stream->m_pNextStream) + { + const SArray& clauses = stream->m_finishedEHClauses; + for (COUNT_T i = 0; i < clauses.GetCount(); i++) + { + const ILStubEHClauseBuilder& builder = clauses[i]; + + CorExceptionFlag flags; + switch (builder.kind) + { + case ILStubEHClause::kTypedCatch: flags = COR_ILEXCEPTION_CLAUSE_NONE; break; + case ILStubEHClause::kFinally: flags = COR_ILEXCEPTION_CLAUSE_FINALLY; break; + default: UNREACHABLE_MSG("unexpected EH clause kind"); + } + + size_t tryBegin = builder.tryBeginLabel->GetCodeOffset(); + size_t tryEnd = builder.tryEndLabel->GetCodeOffset(); + size_t handlerBegin = builder.handlerBeginLabel->GetCodeOffset(); + size_t handlerEnd = builder.handlerEndLabel->GetCodeOffset(); + + IMAGE_COR_ILMETHOD_SECT_EH_CLAUSE_FAT& clause = pSect->Fat.Clauses[clauseIndex]; + clause.Flags = flags; + clause.TryOffset = static_cast(tryBegin); + clause.TryLength = static_cast(tryEnd - tryBegin); + clause.HandlerOffset = static_cast(handlerBegin); + clause.HandlerLength = static_cast(handlerEnd - handlerBegin); + clause.ClassToken = builder.typeToken; + + clauseIndex++; + } + } + + pSect->Fat.Kind = CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat; + pSect->Fat.DataSize = COR_ILMETHOD_SECT_EH_FAT::Size(clauseIndex); +} + #ifdef _DEBUG static const PCSTR s_rgOpNames[] = @@ -1005,6 +1056,75 @@ LPCSTR ILCodeStream::GetStreamDescription(ILStubLinker::CodeStreamType streamTyp return lpszDescriptions[streamType]; } +void ILCodeStream::BeginTryBlock() +{ + ILStubEHClauseBuilder& clause = *m_buildingEHClauses.Append(); + memset(&clause, 0, sizeof(ILStubEHClauseBuilder)); + clause.kind = ILStubEHClause::kNone; + clause.tryBeginLabel = NewCodeLabel(); + EmitLabel(clause.tryBeginLabel); +} + +void ILCodeStream::EndTryBlock() +{ + _ASSERTE(m_buildingEHClauses.GetCount() > 0); + ILStubEHClauseBuilder& clause = m_buildingEHClauses[m_buildingEHClauses.GetCount() - 1]; + + _ASSERTE(clause.tryBeginLabel != NULL && clause.tryEndLabel == NULL); + clause.tryEndLabel = NewCodeLabel(); + EmitLabel(clause.tryEndLabel); +} + +void ILCodeStream::BeginHandler(DWORD kind, DWORD typeToken) +{ + _ASSERTE(m_buildingEHClauses.GetCount() > 0); + ILStubEHClauseBuilder& clause = m_buildingEHClauses[m_buildingEHClauses.GetCount() - 1]; + + _ASSERTE(clause.tryBeginLabel != NULL && clause.tryEndLabel != NULL && + clause.handlerBeginLabel == NULL && clause.kind == ILStubEHClause::kNone); + + clause.kind = kind; + clause.typeToken = typeToken; + clause.handlerBeginLabel = NewCodeLabel(); + EmitLabel(clause.handlerBeginLabel); +} + +void ILCodeStream::EndHandler(DWORD kind) +{ + _ASSERTE(m_buildingEHClauses.GetCount() > 0); + ILStubEHClauseBuilder& clause = m_buildingEHClauses[m_buildingEHClauses.GetCount() - 1]; + + _ASSERTE(clause.tryBeginLabel != NULL && clause.tryEndLabel != NULL && + clause.handlerBeginLabel != NULL && clause.handlerEndLabel == NULL && + clause.kind == kind); + + clause.handlerEndLabel = NewCodeLabel(); + EmitLabel(clause.handlerEndLabel); + + m_finishedEHClauses.Append(clause); + m_buildingEHClauses.SetCount(m_buildingEHClauses.GetCount() - 1); +} + +void ILCodeStream::BeginCatchBlock(int token) +{ + BeginHandler(ILStubEHClause::kTypedCatch, static_cast(token)); +} + +void ILCodeStream::EndCatchBlock() +{ + EndHandler(ILStubEHClause::kTypedCatch); +} + +void ILCodeStream::BeginFinallyBlock() +{ + BeginHandler(ILStubEHClause::kFinally, 0); +} + +void ILCodeStream::EndFinallyBlock() +{ + EndHandler(ILStubEHClause::kFinally); +} + void ILCodeStream::EmitADD() { WRAPPER_NO_CONTRACT; @@ -1064,6 +1184,11 @@ void ILCodeStream::EmitBLT(ILCodeLabel* pCodeLabel) WRAPPER_NO_CONTRACT; Emit(CEE_BLT, -2, (UINT_PTR)pCodeLabel); } +void ILCodeStream::EmitBNE_UN(ILCodeLabel* pCodeLabel) +{ + WRAPPER_NO_CONTRACT; + Emit(CEE_BNE_UN, -2, (UINT_PTR)pCodeLabel); +} void ILCodeStream::EmitBR(ILCodeLabel* pCodeLabel) { WRAPPER_NO_CONTRACT; @@ -1089,12 +1214,17 @@ void ILCodeStream::EmitCALL(int token, int numInArgs, int numRetArgs) WRAPPER_NO_CONTRACT; Emit(CEE_CALL, (INT16)(numRetArgs - numInArgs), token); } +void ILCodeStream::EmitCALLVIRT(int token, int numInArgs, int numRetArgs) +{ + WRAPPER_NO_CONTRACT; + Emit(CEE_CALLVIRT, (INT16)(numRetArgs - numInArgs), token); +} void ILCodeStream::EmitCALLI(int token, int numInArgs, int numRetArgs) { WRAPPER_NO_CONTRACT; Emit(CEE_CALLI, (INT16)(numRetArgs - numInArgs - 1), token); } -void ILCodeStream::EmitCEQ () +void ILCodeStream::EmitCEQ() { WRAPPER_NO_CONTRACT; Emit(CEE_CEQ, -1, 0); @@ -1701,6 +1831,21 @@ void ILCodeStream::EmitCALL(BinderMethodID id, int numInArgs, int numRetArgs) STANDARD_VM_CONTRACT; EmitCALL(GetToken(MscorlibBinder::GetMethod(id)), numInArgs, numRetArgs); } +void ILCodeStream::EmitLDFLD(BinderFieldID id) +{ + STANDARD_VM_CONTRACT; + EmitLDFLD(GetToken(MscorlibBinder::GetField(id))); +} +void ILCodeStream::EmitSTFLD(BinderFieldID id) +{ + STANDARD_VM_CONTRACT; + EmitSTFLD(GetToken(MscorlibBinder::GetField(id))); +} +void ILCodeStream::EmitLDFLDA(BinderFieldID id) +{ + STANDARD_VM_CONTRACT; + EmitLDFLDA(GetToken(MscorlibBinder::GetField(id))); +} void ILStubLinker::SetHasThis (bool fHasThis) { @@ -2858,6 +3003,12 @@ int ILStubLinker::GetToken(FieldDesc* pFD) return m_tokenMap.GetToken(pFD); } +int ILStubLinker::GetSigToken(PCCOR_SIGNATURE pSig, DWORD cbSig) +{ + STANDARD_VM_CONTRACT; + return m_tokenMap.GetSigToken(pSig, cbSig); +} + BOOL ILStubLinker::StubHasVoidReturnType() { @@ -2879,6 +3030,11 @@ void ILStubLinker::ClearCode() ClearCodeStreams(); } +void ILStubLinker::SetStubMethodDesc(MethodDesc* pMD) +{ + m_pMD = pMD; +} + // static ILCodeStream* ILStubLinker::FindLastCodeStream(ILCodeStream* pList) { @@ -2938,6 +3094,11 @@ int ILCodeStream::GetToken(FieldDesc* pFD) STANDARD_VM_CONTRACT; return m_pOwner->GetToken(pFD); } +int ILCodeStream::GetSigToken(PCCOR_SIGNATURE pSig, DWORD cbSig) +{ + STANDARD_VM_CONTRACT; + return m_pOwner->GetSigToken(pSig, cbSig); +} DWORD ILCodeStream::NewLocal(CorElementType typ) { diff --git a/src/coreclr/src/vm/stubgen.h b/src/coreclr/src/vm/stubgen.h index 2afcf307dfa80d..a91679648b3466 100644 --- a/src/coreclr/src/vm/stubgen.h +++ b/src/coreclr/src/vm/stubgen.h @@ -300,6 +300,15 @@ class TokenLookupMap size_t size = pSrc->m_qbEntries.Size(); m_qbEntries.AllocThrows(size); memcpy(m_qbEntries.Ptr(), pSrc->m_qbEntries.Ptr(), size); + + m_signatures.Preallocate(pSrc->m_signatures.GetCount()); + for (COUNT_T i = 0; i < pSrc->m_signatures.GetCount(); i++) + { + const CQuickBytesSpecifySize<16>& src = pSrc->m_signatures[i]; + CQuickBytesSpecifySize<16>& dst = *m_signatures.Append(); + dst.AllocThrows(src.Size()); + memcpy(dst.Ptr(), src.Ptr(), src.Size()); + } } TypeHandle LookupTypeDef(mdToken token) @@ -317,6 +326,24 @@ class TokenLookupMap WRAPPER_NO_CONTRACT; return LookupTokenWorker(token); } + SigPointer LookupSig(mdToken token) + { + CONTRACTL + { + THROWS; + MODE_ANY; + GC_NOTRIGGER; + PRECONDITION(RidFromToken(token)-1 < m_signatures.GetCount()); + PRECONDITION(RidFromToken(token) != 0); + PRECONDITION(TypeFromToken(token) == mdtSignature); + } + CONTRACTL_END; + + CQuickBytesSpecifySize<16>& sigData = m_signatures[static_cast(RidFromToken(token)-1)]; + PCCOR_SIGNATURE pSig = (PCCOR_SIGNATURE)sigData.Ptr(); + DWORD cbSig = static_cast(sigData.Size()); + return SigPointer(pSig, cbSig); + } mdToken GetToken(TypeHandle pMT) { @@ -334,6 +361,24 @@ class TokenLookupMap return GetTokenWorker(pFieldDesc); } + mdToken GetSigToken(PCCOR_SIGNATURE pSig, DWORD cbSig) + { + CONTRACTL + { + THROWS; + MODE_ANY; + GC_NOTRIGGER; + PRECONDITION(pSig != NULL); + } + CONTRACTL_END; + + mdToken token = TokenFromRid(m_signatures.GetCount(), mdtSignature)+1; + CQuickBytesSpecifySize<16>& sigData = *m_signatures.Append(); + sigData.AllocThrows(cbSig); + memcpy(sigData.Ptr(), pSig, cbSig); + return token; + } + protected: template HandleType LookupTokenWorker(mdToken token) @@ -376,10 +421,14 @@ class TokenLookupMap return token; } - unsigned int m_nextAvailableRid; - CQuickBytesSpecifySize m_qbEntries; + unsigned int m_nextAvailableRid; + CQuickBytesSpecifySize m_qbEntries; + SArray, FALSE> m_signatures; }; +class ILCodeLabel; +class ILCodeStream; + #ifndef DACCESS_COMPILE struct ILStubEHClause { @@ -393,8 +442,16 @@ struct ILStubEHClause DWORD dwTypeToken; }; -class ILCodeLabel; -class ILCodeStream; +struct ILStubEHClauseBuilder +{ + DWORD kind; + ILCodeLabel* tryBeginLabel; + ILCodeLabel* tryEndLabel; + ILCodeLabel* handlerBeginLabel; + ILCodeLabel* handlerEndLabel; + DWORD typeToken; +}; + //--------------------------------------------------------------------------------------- // class ILStubLinker @@ -411,6 +468,7 @@ class ILStubLinker void GenerateCode(BYTE* pbBuffer, size_t cbBufferSize); void ClearCode(); + void SetStubMethodDesc(MethodDesc *pMD); protected: void DeleteCodeLabels(); @@ -462,6 +520,9 @@ class ILStubLinker size_t Link(UINT* puMaxStack); + size_t GetNumEHClauses(); + // Write out EH clauses. Number of items written out will be GetNumEHCLauses(). + void WriteEHClauses(COR_ILMETHOD_SECT_EH* sect); TokenLookupMap* GetTokenLookupMap() { LIMITED_METHOD_CONTRACT; return &m_tokenMap; } @@ -486,6 +547,7 @@ class ILStubLinker void LogILStub(CORJIT_FLAGS jitFlags, SString *pDumpILStubCode = NULL); protected: + void DumpIL_FormatToken(mdToken token, SString &strTokenFormatting); void LogILStubWorker(ILInstruction* pInstrBuffer, UINT numInstr, size_t* pcbCode, INT* piCurStack, SString *pDumpILStubCode = NULL); void LogILInstruction(size_t curOffset, bool isLabeled, INT iCurStack, ILInstruction* pInstruction, SString *pDumpILStubCode = NULL); @@ -521,6 +583,7 @@ class ILStubLinker int GetToken(MethodTable* pMT); int GetToken(TypeHandle th); int GetToken(FieldDesc* pFD); + int GetSigToken(PCCOR_SIGNATURE pSig, DWORD cbSig); DWORD NewLocal(CorElementType typ = ELEMENT_TYPE_I); DWORD NewLocal(LocalDesc loc); @@ -610,24 +673,35 @@ class ILCodeStream } + void BeginHandler (DWORD kind, DWORD typeToken); + void EndHandler (DWORD kind); public: + void BeginTryBlock (); + void EndTryBlock (); + void BeginCatchBlock(int token); + void EndCatchBlock (); + void BeginFinallyBlock(); + void EndFinallyBlock(); + void EmitADD (); void EmitADD_OVF (); void EmitAND (); void EmitARGLIST (); void EmitBEQ (ILCodeLabel* pCodeLabel); void EmitBGE (ILCodeLabel* pCodeLabel); - void EmitBGE_UN(ILCodeLabel* pCodeLabel); + void EmitBGE_UN (ILCodeLabel* pCodeLabel); void EmitBGT (ILCodeLabel* pCodeLabel); void EmitBLE (ILCodeLabel* pCodeLabel); void EmitBLE_UN (ILCodeLabel* pCodeLabel); void EmitBLT (ILCodeLabel* pCodeLabel); + void EmitBNE_UN (ILCodeLabel* pCodeLabel); void EmitBR (ILCodeLabel* pCodeLabel); void EmitBREAK (); void EmitBRFALSE (ILCodeLabel* pCodeLabel); void EmitBRTRUE (ILCodeLabel* pCodeLabel); void EmitCALL (int token, int numInArgs, int numRetArgs); void EmitCALLI (int token, int numInArgs, int numRetArgs); + void EmitCALLVIRT (int token, int numInArgs, int numRetArgs); void EmitCEQ (); void EmitCGT (); void EmitCGT_UN (); @@ -715,6 +789,9 @@ class ILCodeStream // Overloads to simplify common usage patterns void EmitNEWOBJ (BinderMethodID id, int numInArgs); void EmitCALL (BinderMethodID id, int numInArgs, int numRetArgs); + void EmitLDFLD (BinderFieldID id); + void EmitSTFLD (BinderFieldID id); + void EmitLDFLDA (BinderFieldID id); void EmitLabel(ILCodeLabel* pLabel); void EmitLoadThis (); @@ -733,6 +810,7 @@ class ILCodeStream int GetToken(MethodTable* pMT); int GetToken(TypeHandle th); int GetToken(FieldDesc* pFD); + int GetSigToken(PCCOR_SIGNATURE pSig, DWORD cbSig); DWORD NewLocal(CorElementType typ = ELEMENT_TYPE_I); DWORD NewLocal(LocalDesc loc); @@ -788,11 +866,13 @@ class ILCodeStream typedef CQuickBytesSpecifySize ILCodeStreamBuffer; - ILCodeStream* m_pNextStream; - ILStubLinker* m_pOwner; - ILCodeStreamBuffer* m_pqbILInstructions; - UINT m_uCurInstrIdx; - ILStubLinker::CodeStreamType m_codeStreamType; // Type of the ILCodeStream + ILCodeStream* m_pNextStream; + ILStubLinker* m_pOwner; + ILCodeStreamBuffer* m_pqbILInstructions; + UINT m_uCurInstrIdx; + ILStubLinker::CodeStreamType m_codeStreamType; // Type of the ILCodeStream + SArray m_buildingEHClauses; + SArray m_finishedEHClauses; #ifndef HOST_64BIT const static UINT32 SPECIAL_VALUE_NAN_64_ON_32 = 0xFFFFFFFF; diff --git a/src/coreclr/src/vm/stubhelpers.cpp b/src/coreclr/src/vm/stubhelpers.cpp index ddba024b808623..324597dcc53f34 100644 --- a/src/coreclr/src/vm/stubhelpers.cpp +++ b/src/coreclr/src/vm/stubhelpers.cpp @@ -1748,3 +1748,10 @@ FCIMPL2(void, StubHelpers::MulticastDebuggerTraceHelper, Object* element, INT32 } FCIMPLEND #endif // FEATURE_MULTICASTSTUB_AS_IL + +FCIMPL0(void*, StubHelpers::NextCallReturnAddress) +{ + FCALL_CONTRACT; + UNREACHABLE_MSG("This is a JIT intrinsic!"); +} +FCIMPLEND diff --git a/src/coreclr/src/vm/stubhelpers.h b/src/coreclr/src/vm/stubhelpers.h index 51de39efde0617..cbc1c60bf43275 100644 --- a/src/coreclr/src/vm/stubhelpers.h +++ b/src/coreclr/src/vm/stubhelpers.h @@ -128,6 +128,8 @@ class StubHelpers #ifdef FEATURE_MULTICASTSTUB_AS_IL static FCDECL2(void, MulticastDebuggerTraceHelper, Object*, INT32); #endif + + static FCDECL0(void*, NextCallReturnAddress); }; #endif // __STUBHELPERS_h__ diff --git a/src/coreclr/src/vm/stubmgr.cpp b/src/coreclr/src/vm/stubmgr.cpp index 23dee8851819a0..12cbd4831f5ee8 100644 --- a/src/coreclr/src/vm/stubmgr.cpp +++ b/src/coreclr/src/vm/stubmgr.cpp @@ -1087,7 +1087,7 @@ BOOL PrecodeStubManager::DoTraceStub(PCODE stubStartAddress, // MethodDesc. If, however, this is an IL method, then we are at risk to have another thread backpatch the call // here, so we'd miss if we patched the prestub. Therefore, we go right to the IL method and patch IL offset 0 // by using TRACE_UNJITTED_METHOD. - if (!pMD->IsIL()) + if (!pMD->IsIL() && !pMD->IsILStub()) { trace->InitForStub(GetPreStubEntryPoint()); } @@ -1844,6 +1844,12 @@ BOOL ILStubManager::TraceManager(Thread *thread, trace->InitForUnmanaged(target); } #endif // FEATURE_COMINTEROP + else if (pStubMD->IsStructMarshalStub()) + { + // There's no "target" for struct marshalling stubs + // so we have nowhere to tell the debugger to move the breakpoint. + return FALSE; + } else { // This is either direct forward P/Invoke or a CLR-to-COM call, the argument is MD @@ -2349,6 +2355,8 @@ BOOL DelegateInvokeStubManager::TraceDelegateObject(BYTE* pbDel, TraceDestinatio #endif // DACCESS_COMPILE +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) + #if !defined(DACCESS_COMPILE) // static @@ -2365,7 +2373,7 @@ void TailCallStubManager::Init() StubManager::AddStubManager(new TailCallStubManager()); } -bool TailCallStubManager::IsTailCallStubHelper(PCODE code) +bool TailCallStubManager::IsTailCallJitHelper(PCODE code) { LIMITED_METHOD_CONTRACT; @@ -2381,7 +2389,7 @@ BOOL TailCallStubManager::CheckIsStub_Internal(PCODE stubStartAddress) bool fIsStub = false; #if !defined(DACCESS_COMPILE) - fIsStub = IsTailCallStubHelper(stubStartAddress); + fIsStub = IsTailCallJitHelper(stubStartAddress); #endif // !DACCESS_COMPILE return fIsStub; @@ -2389,10 +2397,8 @@ BOOL TailCallStubManager::CheckIsStub_Internal(PCODE stubStartAddress) #if !defined(DACCESS_COMPILE) -#if defined(TARGET_X86) EXTERN_C void STDCALL JIT_TailCallLeave(); EXTERN_C void STDCALL JIT_TailCallVSDLeave(); -#endif // TARGET_X86 BOOL TailCallStubManager::TraceManager(Thread * pThread, TraceDestination * pTrace, @@ -2400,7 +2406,6 @@ BOOL TailCallStubManager::TraceManager(Thread * pThread, BYTE ** ppRetAddr) { WRAPPER_NO_CONTRACT; -#if defined(TARGET_X86) TADDR esp = GetSP(pContext); TADDR ebp = GetFP(pContext); @@ -2449,27 +2454,6 @@ BOOL TailCallStubManager::TraceManager(Thread * pThread, pTrace->InitForStub((PCODE)*reinterpret_cast(esp)); return TRUE; } - -#elif defined(TARGET_AMD64) || defined(TARGET_ARM) - - _ASSERTE(GetIP(pContext) == GetEEFuncEntryPoint(JIT_TailCall)); - - // The target address is the second argument -#ifdef TARGET_AMD64 - PCODE target = (PCODE)pContext->Rdx; -#else - PCODE target = (PCODE)pContext->R1; -#endif - *ppRetAddr = reinterpret_cast(target); - pTrace->InitForStub(target); - return TRUE; - -#else // !TARGET_X86 && !TARGET_AMD64 && !TARGET_ARM - - _ASSERTE(!"TCSM::TM - TailCallStubManager should not be necessary on this platform"); - return FALSE; - -#endif // TARGET_X86 || TARGET_AMD64 } #endif // !DACCESS_COMPILE @@ -2491,6 +2475,8 @@ BOOL TailCallStubManager::DoTraceStub(PCODE stubStartAddress, TraceDestination * return fResult; } +#endif // TARGET_X86 && !UNIX_X86_ABI + #ifdef DACCESS_COMPILE @@ -2582,6 +2568,7 @@ VirtualCallStubManager::DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags) GetCacheEntryRangeList()->EnumMemoryRegions(flags); } +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) void TailCallStubManager::DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags) { SUPPORTS_DAC; @@ -2589,6 +2576,7 @@ void TailCallStubManager::DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags) DAC_ENUM_VTHIS(); EMEM_OUT(("MEM: %p TailCallStubManager\n", dac_cast(this))); } +#endif #endif // #ifdef DACCESS_COMPILE diff --git a/src/coreclr/src/vm/stubmgr.h b/src/coreclr/src/vm/stubmgr.h index 6958f677da47c1..409bb88cc2b3a0 100644 --- a/src/coreclr/src/vm/stubmgr.h +++ b/src/coreclr/src/vm/stubmgr.h @@ -838,6 +838,7 @@ class DelegateInvokeStubManager : public StubManager #endif }; +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) //--------------------------------------------------------------------------------------- // // This is the stub manager to help the managed debugger step into a tail call. @@ -859,7 +860,7 @@ class TailCallStubManager : public StubManager virtual BOOL TraceManager(Thread * pThread, TraceDestination * pTrace, T_CONTEXT * pContext, BYTE ** ppRetAddr); - static bool IsTailCallStubHelper(PCODE code); + static bool IsTailCallJitHelper(PCODE code); #endif // DACCESS_COMPILE #if defined(_DEBUG) @@ -878,6 +879,20 @@ class TailCallStubManager : public StubManager virtual LPCWSTR GetStubManagerName(PCODE addr) {LIMITED_METHOD_CONTRACT; return W("TailCallStub");} #endif // !DACCESS_COMPILE }; +#else // TARGET_X86 && UNIX_X86_ABI +class TailCallStubManager +{ +public: + static void Init() + { + } + + static bool IsTailCallJitHelper(PCODE code) + { + return false; + } +}; +#endif // TARGET_X86 && UNIX_X86_ABI // // Helpers for common value locations in stubs to make stub managers more portable diff --git a/src/coreclr/src/vm/tailcallhelp.cpp b/src/coreclr/src/vm/tailcallhelp.cpp new file mode 100644 index 00000000000000..4d7b8bca0af72a --- /dev/null +++ b/src/coreclr/src/vm/tailcallhelp.cpp @@ -0,0 +1,888 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "common.h" +#include "corpriv.h" +#include "tailcallhelp.h" +#include "dllimport.h" +#include "formattype.h" +#include "sigformat.h" +#include "gcrefmap.h" +#include "threads.h" + +#ifndef CROSSGEN_COMPILE + +FCIMPL2(void*, TailCallHelp::AllocTailCallArgBuffer, INT32 size, void* gcDesc) +{ + CONTRACTL + { + FCALL_CHECK; + INJECT_FAULT(FCThrow(kOutOfMemoryException);); + } + CONTRACTL_END + + _ASSERTE(size >= 0); + + void* result = GetThread()->GetTailCallTls()->AllocArgBuffer(static_cast(size), gcDesc); + + if (result == NULL) + FCThrow(kOutOfMemoryException); + + return result; +} +FCIMPLEND + +FCIMPL0(void, TailCallHelp::FreeTailCallArgBuffer) +{ + FCALL_CONTRACT; + + GetThread()->GetTailCallTls()->FreeArgBuffer(); +} +FCIMPLEND + +FCIMPL2(void*, TailCallHelp::GetTailCallInfo, void** retAddrSlot, void** retAddr) +{ + FCALL_CONTRACT; + + Thread* thread = GetThread(); + + *retAddr = thread->GetReturnAddress(retAddrSlot); + return thread->GetTailCallTls(); +} +FCIMPLEND + +#endif + +struct ArgBufferValue +{ + TypeHandle TyHnd; + unsigned int Offset; + + ArgBufferValue(TypeHandle tyHnd = TypeHandle(), unsigned int offset = 0) + : TyHnd(tyHnd), Offset(offset) + { + } +}; + +struct ArgBufferLayout +{ + bool HasTargetAddress; + unsigned int TargetAddressOffset; + InlineSArray Values; + unsigned int Size; + + ArgBufferLayout() + : HasTargetAddress(false) + , TargetAddressOffset(0) + , Size(0) + { + } +}; + +struct TailCallInfo +{ + MethodDesc* Caller; + MethodDesc* Callee; + PTR_LoaderAllocator LoaderAllocator; + MetaSig* CallSiteSig; + bool CallSiteIsVirtual; + TypeHandle RetTyHnd; + ArgBufferLayout ArgBufLayout; + bool HasGCDescriptor; + GCRefMapBuilder GCRefMapBuilder; + + TailCallInfo( + MethodDesc* pCallerMD, MethodDesc* pCalleeMD, + PTR_LoaderAllocator pLoaderAllocator, + MetaSig* callSiteSig, bool callSiteIsVirtual, + TypeHandle retTyHnd) + : Caller(pCallerMD) + , Callee(pCalleeMD) + , LoaderAllocator(pLoaderAllocator) + , CallSiteSig(callSiteSig) + , CallSiteIsVirtual(callSiteIsVirtual) + , RetTyHnd(retTyHnd) + , HasGCDescriptor(false) + { + } +}; + +static MethodDesc* s_tailCallDispatcherMD; +MethodDesc* TailCallHelp::GetTailCallDispatcherMD() +{ + LIMITED_METHOD_CONTRACT; + + return s_tailCallDispatcherMD; +} + + +// This creates the dispatcher used to dispatch sequences of tailcalls. In C# +// code it is the following function. Once C# gets function pointer support this +// function can be put in System.Private.CoreLib. +// private static unsafe void DispatchTailCalls( +// IntPtr callersRetAddrSlot, IntPtr callTarget, IntPtr retVal) +// { +// IntPtr callersRetAddr; +// TailCallTls* tls = GetTailCallInfo(callersRetAddrSlot, &callersRetAddr); +// PortableTailCallFrame* prevFrame = tls->Frame; +// if (callersRetAddr == prevFrame->TailCallAwareReturnAddress) +// { +// prevFrame->NextCall = callTarget; +// return; +// } +// +// PortableTailCallFrame newFrame; +// newFrame.Prev = prevFrame; +// +// try +// { +// tls->Frame = &newFrame; +// +// do +// { +// newFrame.NextCall = IntPtr.Zero; +// var fptr = (func* void(IntPtr, IntPtr, void*))callTarget; +// fptr(tls->ArgBuffer, retVal, &newFrame.TailCallAwareReturnAddress); +// callTarget = newFrame.NextCall; +// } while (callTarget != IntPtr.Zero); +// } +// finally +// { +// tls->Frame = prevFrame; +// } +// } +MethodDesc* TailCallHelp::GetOrCreateTailCallDispatcherMD() +{ + STANDARD_VM_CONTRACT; + + if (s_tailCallDispatcherMD != NULL) + return s_tailCallDispatcherMD; + + SigBuilder sigBuilder; + sigBuilder.AppendByte(IMAGE_CEE_CS_CALLCONV_DEFAULT); + + sigBuilder.AppendData(3); + sigBuilder.AppendElementType(ELEMENT_TYPE_VOID); + + sigBuilder.AppendElementType(ELEMENT_TYPE_I); + sigBuilder.AppendElementType(ELEMENT_TYPE_I); + sigBuilder.AppendElementType(ELEMENT_TYPE_I); + + const int ARG_CALLERS_RET_ADDR_SLOT = 0; + const int ARG_CALL_TARGET = 1; + const int ARG_RET_VAL = 2; + + DWORD cbSig; + PCCOR_SIGNATURE pSig = AllocateSignature( + MscorlibBinder::GetModule()->GetLoaderAllocator(), sigBuilder, &cbSig); + + SigTypeContext emptyCtx; + + ILStubLinker sl(MscorlibBinder::GetModule(), + Signature(pSig, cbSig), + &emptyCtx, + NULL, + FALSE, + FALSE); + + ILCodeStream* pCode = sl.NewCodeStream(ILStubLinker::kDispatch); + + DWORD retAddrLcl = pCode->NewLocal(ELEMENT_TYPE_I); + DWORD tlsLcl = pCode->NewLocal(ELEMENT_TYPE_I); + DWORD prevFrameLcl = pCode->NewLocal(ELEMENT_TYPE_I); + TypeHandle frameTyHnd = MscorlibBinder::GetClass(CLASS__PORTABLE_TAIL_CALL_FRAME); + DWORD newFrameEntryLcl = pCode->NewLocal(LocalDesc(frameTyHnd)); + DWORD argsLcl = pCode->NewLocal(ELEMENT_TYPE_I); + ILCodeLabel* noUnwindLbl = pCode->NewCodeLabel(); + ILCodeLabel* loopStart = pCode->NewCodeLabel(); + ILCodeLabel* afterTryFinally = pCode->NewCodeLabel(); + + // tls = RuntimeHelpers.GetTailcallInfo(callersRetAddrSlot, &retAddr); + pCode->EmitLDARG(ARG_CALLERS_RET_ADDR_SLOT); + pCode->EmitLDLOCA(retAddrLcl); + pCode->EmitCALL(METHOD__RUNTIME_HELPERS__GET_TAILCALL_INFO, 2, 1); + pCode->EmitSTLOC(tlsLcl); + + // prevFrame = tls.Frame; + pCode->EmitLDLOC(tlsLcl); + pCode->EmitLDFLD(FIELD__TAIL_CALL_TLS__FRAME); + pCode->EmitSTLOC(prevFrameLcl); + + // if (retAddr != prevFrame.TailCallAwareReturnAddress) goto noUnwindLbl; + pCode->EmitLDLOC(retAddrLcl); + pCode->EmitLDLOC(prevFrameLcl); + pCode->EmitLDFLD(FIELD__PORTABLE_TAIL_CALL_FRAME__TAILCALL_AWARE_RETURN_ADDRESS); + pCode->EmitBNE_UN(noUnwindLbl); + + // prevFrame->NextCall = callTarget; + pCode->EmitLDLOC(prevFrameLcl); + pCode->EmitLDARG(ARG_CALL_TARGET); + pCode->EmitSTFLD(FIELD__PORTABLE_TAIL_CALL_FRAME__NEXT_CALL); + + // return; + pCode->EmitRET(); + + // Ok, we are the "first" dispatcher. + pCode->EmitLabel(noUnwindLbl); + + // newFrameEntry.Prev = prevFrame; + pCode->EmitLDLOCA(newFrameEntryLcl); + pCode->EmitLDLOC(prevFrameLcl); + pCode->EmitSTFLD(FIELD__PORTABLE_TAIL_CALL_FRAME__PREV); + + // try { + pCode->BeginTryBlock(); + + // tls->Frame = &newFrameEntry; + pCode->EmitLDLOC(tlsLcl); + pCode->EmitLDLOCA(newFrameEntryLcl); + pCode->EmitSTFLD(FIELD__TAIL_CALL_TLS__FRAME); + + // do { + pCode->EmitLabel(loopStart); + + // newFrameEntry.NextCall = 0 + pCode->EmitLDLOCA(newFrameEntryLcl); + pCode->EmitLDC(0); + pCode->EmitCONV_I(); + pCode->EmitSTFLD(FIELD__PORTABLE_TAIL_CALL_FRAME__NEXT_CALL); + + SigBuilder calliSig; + calliSig.AppendByte(IMAGE_CEE_CS_CALLCONV_DEFAULT); + calliSig.AppendData(3); + calliSig.AppendElementType(ELEMENT_TYPE_VOID); + calliSig.AppendElementType(ELEMENT_TYPE_I); + calliSig.AppendElementType(ELEMENT_TYPE_I); + calliSig.AppendElementType(ELEMENT_TYPE_I); + + DWORD cbCalliSig; + PCCOR_SIGNATURE pCalliSig = (PCCOR_SIGNATURE)calliSig.GetSignature(&cbCalliSig); + + // callTarget(tls->ArgBuffer, retVal, &newFrameEntry.TailCallAwareReturnAddress) + // arg buffer + pCode->EmitLDLOC(tlsLcl); + pCode->EmitLDFLD(FIELD__TAIL_CALL_TLS__ARG_BUFFER); + + // ret val + pCode->EmitLDARG(ARG_RET_VAL); + + // TailCallAwareReturnAddress + pCode->EmitLDLOCA(newFrameEntryLcl); + pCode->EmitLDFLDA(FIELD__PORTABLE_TAIL_CALL_FRAME__TAILCALL_AWARE_RETURN_ADDRESS); + + // callTarget + pCode->EmitLDARG(ARG_CALL_TARGET); + + pCode->EmitCALLI(pCode->GetSigToken(pCalliSig, cbCalliSig), 2, 0); + + // callTarget = newFrameEntry.NextCall; + pCode->EmitLDLOC(newFrameEntryLcl); + pCode->EmitLDFLD(FIELD__PORTABLE_TAIL_CALL_FRAME__NEXT_CALL); + pCode->EmitSTARG(ARG_CALL_TARGET); + + // } while (callTarget != IntPtr.Zero); + pCode->EmitLDARG(ARG_CALL_TARGET); + pCode->EmitBRTRUE(loopStart); + + // } + pCode->EmitLEAVE(afterTryFinally); + pCode->EndTryBlock(); + + // finally { + pCode->BeginFinallyBlock(); + + // tls->Frame = prevFrame; + pCode->EmitLDLOC(tlsLcl); + pCode->EmitLDLOC(prevFrameLcl); + pCode->EmitSTFLD(FIELD__TAIL_CALL_TLS__FRAME); + + // } + pCode->EmitENDFINALLY(); + pCode->EndFinallyBlock(); + + // afterTryFinally: + pCode->EmitLabel(afterTryFinally); + + // return; + pCode->EmitRET(); + + Module* mscorlib = MscorlibBinder::GetModule(); + MethodDesc* pDispatchTailCallsMD = + ILStubCache::CreateAndLinkNewILStubMethodDesc( + MscorlibBinder::GetModule()->GetLoaderAllocator(), + mscorlib->GetILStubCache()->GetOrCreateStubMethodTable(mscorlib), + ILSTUB_TAILCALL_DISPATCH, + mscorlib, + pSig, cbSig, + &emptyCtx, + &sl); + +#ifdef _DEBUG + LOG((LF_STUBS, LL_INFO1000, "TAILCALLHELP: DispatchTailCalls IL created\n")); + sl.LogILStub(CORJIT_FLAGS()); +#endif + + // We might waste a MethodDesc here if we lose the race, but that is very + // unlikely and since this initialization only happens once not a big deal. + InterlockedCompareExchangeT(&s_tailCallDispatcherMD, pDispatchTailCallsMD, NULL); + return s_tailCallDispatcherMD; +} + +void TailCallHelp::CreateTailCallHelperStubs( + MethodDesc* pCallerMD, MethodDesc* pCalleeMD, + MetaSig& callSiteSig, bool virt, bool thisArgByRef, + MethodDesc** storeArgsStub, bool* storeArgsNeedsTarget, + MethodDesc** callTargetStub) +{ + STANDARD_VM_CONTRACT; + +#ifdef _DEBUG + SigFormat incSig(callSiteSig, NULL); + LOG((LF_STUBS, LL_INFO1000, "TAILCALLHELP: Incoming sig %s\n", incSig.GetCString())); +#endif + + *storeArgsNeedsTarget = pCalleeMD == NULL || pCalleeMD->IsSharedByGenericInstantiations(); + + // The tailcall helper stubs are always allocated together with the caller. + // If we ever wish to share these stubs they should be allocated with the + // callee in most cases. + LoaderAllocator* pLoaderAllocator = pCallerMD->GetLoaderAllocator(); + + TypeHandle retTyHnd = NormalizeSigType(callSiteSig.GetRetTypeHandleThrowing()); + TailCallInfo info(pCallerMD, pCalleeMD, pLoaderAllocator, &callSiteSig, virt, retTyHnd); + + LayOutArgBuffer(callSiteSig, pCalleeMD, *storeArgsNeedsTarget, thisArgByRef, &info.ArgBufLayout); + info.HasGCDescriptor = GenerateGCDescriptor(pCalleeMD, info.ArgBufLayout, &info.GCRefMapBuilder); + + *storeArgsStub = CreateStoreArgsStub(info); + *callTargetStub = CreateCallTargetStub(info); +} + +void TailCallHelp::LayOutArgBuffer( + MetaSig& callSiteSig, MethodDesc* calleeMD, + bool storeTarget, bool thisArgByRef, ArgBufferLayout* layout) +{ + unsigned int offs = 0; + + auto addValue = [&](TypeHandle th) + { + unsigned int alignment = CEEInfo::getClassAlignmentRequirementStatic(th); + offs = AlignUp(offs, alignment); + layout->Values.Append(ArgBufferValue(th, offs)); + offs += th.GetSize(); + }; + + // User args + if (callSiteSig.HasThis() && !callSiteSig.HasExplicitThis()) + { + TypeHandle thisHnd; + + bool thisParamByRef = (calleeMD != NULL) ? calleeMD->GetMethodTable()->IsValueType() : thisArgByRef; + if (thisParamByRef) + { + thisHnd = TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_U1)) + .MakeByRef(); + } + else + { + thisHnd = TypeHandle(g_pObjectClass); + } + + addValue(thisHnd); + } + + callSiteSig.Reset(); + CorElementType ty; + while ((ty = callSiteSig.NextArg()) != ELEMENT_TYPE_END) + { + TypeHandle tyHnd = callSiteSig.GetLastTypeHandleThrowing(); + tyHnd = NormalizeSigType(tyHnd); + addValue(tyHnd); + } + + if (storeTarget) + { + offs = AlignUp(offs, TARGET_POINTER_SIZE); + layout->TargetAddressOffset = offs; + layout->HasTargetAddress = true; + offs += TARGET_POINTER_SIZE; + } + + layout->Size = offs; +} + +// The types we get from a signature can be generic type arguments, but the +// stubs we create are not generic, so this function normalizes types in the +// signature to a compatible more general type. +TypeHandle TailCallHelp::NormalizeSigType(TypeHandle tyHnd) +{ + CorElementType ety = tyHnd.GetSignatureCorElementType(); + if (CorTypeInfo::IsPrimitiveType(ety)) + { + return tyHnd; + } + if (CorTypeInfo::IsObjRef(ety)) + { + return TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_OBJECT)); + } + if (tyHnd.IsPointer() || tyHnd.IsFnPtrType()) + { + return TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_I)); + } + + if (tyHnd.IsByRef()) + { + return TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_U1)) + .MakeByRef(); + } + + _ASSERTE(ety == ELEMENT_TYPE_VALUETYPE && tyHnd.IsValueType()); + // Value type -- retain it to preserve its size + return tyHnd; +} + +bool TailCallHelp::GenerateGCDescriptor( + MethodDesc* pTargetMD, const ArgBufferLayout& layout, GCRefMapBuilder* builder) +{ + auto writeGCType = [&](unsigned int offset, CorInfoGCType type) + { + _ASSERTE(offset % TARGET_POINTER_SIZE == 0); + switch (type) + { + case TYPE_GC_REF: builder->WriteToken(offset / TARGET_POINTER_SIZE, GCREFMAP_REF); break; + case TYPE_GC_BYREF: builder->WriteToken(offset / TARGET_POINTER_SIZE, GCREFMAP_INTERIOR); break; + case TYPE_GC_NONE: break; + default: UNREACHABLE_MSG("Invalid type"); break; + } + }; + + CQuickBytes gcPtrs; + for (COUNT_T i = 0; i < layout.Values.GetCount(); i++) + { + const ArgBufferValue& val = layout.Values[i]; + + TypeHandle tyHnd = val.TyHnd; + if (tyHnd.IsValueType()) + { + if (!tyHnd.GetMethodTable()->ContainsPointers()) + continue; + + unsigned int numSlots = (tyHnd.GetSize() + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE; + BYTE* ptr = static_cast(gcPtrs.AllocThrows(numSlots)); + CEEInfo::getClassGClayoutStatic(tyHnd, ptr); + for (unsigned int i = 0; i < numSlots; i++) + { + writeGCType(val.Offset + i * TARGET_POINTER_SIZE, (CorInfoGCType)ptr[i]); + } + + continue; + } + + CorElementType ety = tyHnd.GetSignatureCorElementType(); + CorInfoGCType gc = CorTypeInfo::GetGCType(ety); + + writeGCType(val.Offset, gc); + } + + builder->Flush(); + + return builder->GetBlobLength() > 0; +} + +MethodDesc* TailCallHelp::CreateStoreArgsStub(TailCallInfo& info) +{ + SigBuilder sigBuilder; + CreateStoreArgsStubSig(info, &sigBuilder); + + DWORD cbSig; + PCCOR_SIGNATURE pSig = AllocateSignature( + info.LoaderAllocator, sigBuilder, &cbSig); + + SigTypeContext emptyCtx; + + ILStubLinker sl(info.Caller->GetModule(), + Signature(pSig, cbSig), + &emptyCtx, + NULL, + FALSE, + FALSE); + + ILCodeStream* pCode = sl.NewCodeStream(ILStubLinker::kDispatch); + + DWORD bufferLcl = pCode->NewLocal(ELEMENT_TYPE_I); + + void* pGcDesc = NULL; + if (info.HasGCDescriptor) + { + DWORD gcDescLen; + PVOID gcDesc = info.GCRefMapBuilder.GetBlob(&gcDescLen); + pGcDesc = AllocateBlob(info.LoaderAllocator, gcDesc, gcDescLen); + } + + pCode->EmitLDC(info.ArgBufLayout.Size); + pCode->EmitLDC(DWORD_PTR(pGcDesc)); + pCode->EmitCONV_I(); + pCode->EmitCALL(METHOD__RUNTIME_HELPERS__ALLOC_TAILCALL_ARG_BUFFER, 2, 1); + pCode->EmitSTLOC(bufferLcl); + + auto emitOffs = [&](UINT offs) + { + pCode->EmitLDLOC(bufferLcl); + if (offs != 0) + { + pCode->EmitLDC(offs); + pCode->EmitADD(); + } + }; + + unsigned int argIndex = 0; + + for (COUNT_T i = 0; i < info.ArgBufLayout.Values.GetCount(); i++) + { + const ArgBufferValue& arg = info.ArgBufLayout.Values[i]; + CorElementType ty = arg.TyHnd.GetSignatureCorElementType(); + + emitOffs(arg.Offset); + pCode->EmitLDARG(argIndex++); + EmitStoreTyHnd(pCode, arg.TyHnd); + } + + if (info.ArgBufLayout.HasTargetAddress) + { + emitOffs(info.ArgBufLayout.TargetAddressOffset); + pCode->EmitLDARG(argIndex++); + pCode->EmitSTIND_I(); + } + + pCode->EmitRET(); + + Module* pLoaderModule = info.Caller->GetLoaderModule(); + MethodDesc* pStoreArgsMD = + ILStubCache::CreateAndLinkNewILStubMethodDesc( + info.LoaderAllocator, + pLoaderModule->GetILStubCache()->GetOrCreateStubMethodTable(pLoaderModule), + ILSTUB_TAILCALL_STOREARGS, + info.Caller->GetModule(), + pSig, cbSig, + &emptyCtx, + &sl); + +#ifdef _DEBUG + LOG((LF_STUBS, LL_INFO1000, "TAILCALLHELP: StoreArgs IL created\n")); + sl.LogILStub(CORJIT_FLAGS()); +#endif + + return pStoreArgsMD; +} + +void TailCallHelp::CreateStoreArgsStubSig( + const TailCallInfo& info, SigBuilder* sig) +{ + // The store-args stub will be different depending on the tailcall site. + // Specifically the following things might be conditionally inserted: + // * Call target address (for calli or generic calls resolved at tailcall site) + // * This pointer (for instance calls) + + sig->AppendByte(IMAGE_CEE_CS_CALLCONV_DEFAULT); + + ULONG paramCount = 0; + paramCount += info.ArgBufLayout.Values.GetCount(); + if (info.ArgBufLayout.HasTargetAddress) + { + paramCount++; + } + + sig->AppendData(paramCount); + + sig->AppendElementType(ELEMENT_TYPE_VOID); + + for (COUNT_T i = 0; i < info.ArgBufLayout.Values.GetCount(); i++) + { + const ArgBufferValue& val = info.ArgBufLayout.Values[i]; + AppendTypeHandle(*sig, val.TyHnd); + } + + if (info.ArgBufLayout.HasTargetAddress) + { + sig->AppendElementType(ELEMENT_TYPE_I); + } + +#ifdef _DEBUG + DWORD cbSig; + PCCOR_SIGNATURE pSig = (PCCOR_SIGNATURE)sig->GetSignature(&cbSig); + SigTypeContext emptyContext; + MetaSig outMsig(pSig, cbSig, info.CallSiteSig->GetModule(), &emptyContext); + SigFormat outSig(outMsig, NULL); + LOG((LF_STUBS, LL_INFO1000, "TAILCALLHELP: StoreArgs sig: %s\n", outSig.GetCString())); +#endif // _DEBUG +} + +MethodDesc* TailCallHelp::CreateCallTargetStub(const TailCallInfo& info) +{ + SigBuilder sigBuilder; + CreateCallTargetStubSig(info, &sigBuilder); + + DWORD cbSig; + PCCOR_SIGNATURE pSig = AllocateSignature(info.LoaderAllocator, sigBuilder, &cbSig); + + SigTypeContext emptyCtx; + + ILStubLinker sl(info.Caller->GetModule(), + Signature(pSig, cbSig), + &emptyCtx, + NULL, + FALSE, + FALSE); + + ILCodeStream* pCode = sl.NewCodeStream(ILStubLinker::kDispatch); + + // void CallTarget(void* argBuffer, void* retVal, void** pTailCallAwareRetAddress) + const int ARG_ARG_BUFFER = 0; + const int ARG_RET_VAL = 1; + const int ARG_PTR_TAILCALL_AWARE_RET_ADDR = 2; + + auto emitOffs = [&](UINT offs) + { + pCode->EmitLDARG(ARG_ARG_BUFFER); + if (offs != 0) + { + pCode->EmitLDC(offs); + pCode->EmitADD(); + } + }; + + StackSArray argLocals; + for (COUNT_T i = 0; i < info.ArgBufLayout.Values.GetCount(); i++) + { + const ArgBufferValue& arg = info.ArgBufLayout.Values[i]; + DWORD argLcl = pCode->NewLocal(LocalDesc(arg.TyHnd)); + argLocals.Append(argLcl); + + // arg = args->Arg_i + emitOffs(arg.Offset); + EmitLoadTyHnd(pCode, arg.TyHnd); + pCode->EmitSTLOC(argLcl); + } + + DWORD targetAddrLcl; + if (info.ArgBufLayout.HasTargetAddress) + { + targetAddrLcl = pCode->NewLocal(ELEMENT_TYPE_I); + + emitOffs(info.ArgBufLayout.TargetAddressOffset); + pCode->EmitLDIND_I(); + pCode->EmitSTLOC(targetAddrLcl); + } + + // RuntimeHelpers.FreeTailCallArgBuffer(); + pCode->EmitCALL(METHOD__RUNTIME_HELPERS__FREE_TAILCALL_ARG_BUFFER, 0, 0); + + // *pTailCallAwareRetAddr = NextCallReturnAddress(); + pCode->EmitLDARG(ARG_PTR_TAILCALL_AWARE_RET_ADDR); + pCode->EmitCALL(METHOD__STUBHELPERS__NEXT_CALL_RETURN_ADDRESS, 0, 1); + pCode->EmitSTIND_I(); + + int numRetVals = info.CallSiteSig->IsReturnTypeVoid() ? 0 : 1; + // Normally there will not be any target and we just emit a normal + // call/callvirt. + if (!info.ArgBufLayout.HasTargetAddress) + { + _ASSERTE(info.Callee != NULL); + // TODO: enable for varargs. We need to fix the TokenLookupMap to build + // the proper MethodRef. + _ASSERTE(!info.CallSiteSig->IsVarArg()); + + for (COUNT_T i = 0; i < argLocals.GetCount(); i++) + { + pCode->EmitLDLOC(argLocals[i]); + } + + if (info.CallSiteIsVirtual) + { + pCode->EmitCALLVIRT( + pCode->GetToken(info.Callee), + static_cast(argLocals.GetCount()), + numRetVals); + } + else + { + pCode->EmitCALL( + pCode->GetToken(info.Callee), + static_cast(argLocals.GetCount()), + numRetVals); + } + } + else + { + // Build the signature for the calli. + SigBuilder calliSig; + + if (info.CallSiteSig->HasThis()) + { + _ASSERTE(info.ArgBufLayout.Values.GetCount() > 0); + + calliSig.AppendByte(IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS); + calliSig.AppendData(info.ArgBufLayout.Values.GetCount() - 1); + } + else + { + calliSig.AppendByte(IMAGE_CEE_CS_CALLCONV_DEFAULT); + calliSig.AppendData(info.ArgBufLayout.Values.GetCount()); + } + + // Return type + AppendTypeHandle(calliSig, info.RetTyHnd); + + COUNT_T firstSigArg = info.CallSiteSig->HasThis() ? 1 : 0; + + for (COUNT_T i = firstSigArg; i < argLocals.GetCount(); i++) + { + const ArgBufferValue& val = info.ArgBufLayout.Values[i]; + AppendTypeHandle(calliSig, val.TyHnd); + } + + DWORD cbCalliSig; + PCCOR_SIGNATURE pCalliSig = (PCCOR_SIGNATURE)calliSig.GetSignature(&cbCalliSig); + + for (COUNT_T i = 0; i < argLocals.GetCount(); i++) + { + pCode->EmitLDLOC(argLocals[i]); + } + + pCode->EmitLDLOC(targetAddrLcl); + + pCode->EmitCALLI( + pCode->GetSigToken(pCalliSig, cbCalliSig), + static_cast(argLocals.GetCount()), + numRetVals); + } + + if (!info.CallSiteSig->IsReturnTypeVoid()) + { + DWORD resultLcl = pCode->NewLocal(LocalDesc(info.RetTyHnd)); + pCode->EmitSTLOC(resultLcl); + + pCode->EmitLDARG(ARG_RET_VAL); + pCode->EmitLDLOC(resultLcl); + EmitStoreTyHnd(pCode, info.RetTyHnd); + } + + pCode->EmitRET(); + + Module* pLoaderModule = info.Caller->GetLoaderModule(); + MethodDesc* pCallTargetMD = + ILStubCache::CreateAndLinkNewILStubMethodDesc( + info.LoaderAllocator, + pLoaderModule->GetILStubCache()->GetOrCreateStubMethodTable(pLoaderModule), + ILSTUB_TAILCALL_CALLTARGET, + info.Caller->GetModule(), + pSig, cbSig, + &emptyCtx, + &sl); + +#ifdef _DEBUG + LOG((LF_STUBS, LL_INFO1000, "TAILCALLHELP: CallTarget IL created\n")); + sl.LogILStub(CORJIT_FLAGS()); +#endif + + return pCallTargetMD; +} + +void TailCallHelp::CreateCallTargetStubSig(const TailCallInfo& info, SigBuilder* sig) +{ + sig->AppendByte(IMAGE_CEE_CS_CALLCONV_DEFAULT); + + // Arg buffer, return value pointer, and pointer to "tail call aware return address" field. + sig->AppendData(3); + + // Returns void + sig->AppendElementType(ELEMENT_TYPE_VOID); + + // Arg buffer + sig->AppendElementType(ELEMENT_TYPE_I); + + // Return value + sig->AppendElementType(ELEMENT_TYPE_I); + + // Pointer to tail call aware return address + sig->AppendElementType(ELEMENT_TYPE_I); + +#ifdef _DEBUG + DWORD cbSig; + PCCOR_SIGNATURE pSig = (PCCOR_SIGNATURE)sig->GetSignature(&cbSig); + SigTypeContext emptyContext; + MetaSig outMsig(pSig, cbSig, info.CallSiteSig->GetModule(), &emptyContext); + SigFormat outSig(outMsig, NULL); + LOG((LF_STUBS, LL_INFO1000, "TAILCALLHELP: CallTarget sig: %s\n", outSig.GetCString())); +#endif // _DEBUG +} + +void TailCallHelp::EmitLoadTyHnd(ILCodeStream* stream, TypeHandle tyHnd) +{ + CorElementType ty = tyHnd.GetSignatureCorElementType(); + if (tyHnd.IsByRef()) + { + // Note: we can use an "untracked" ldind.i here even with byrefs because + // we are loading between two tracked positions. + stream->EmitLDIND_I(); + } + else + { + int token = stream->GetToken(tyHnd); + stream->EmitLDOBJ(token); + } +} + +void TailCallHelp::EmitStoreTyHnd(ILCodeStream* stream, TypeHandle tyHnd) +{ + CorElementType ty = tyHnd.GetSignatureCorElementType(); + if (tyHnd.IsByRef()) + { + // Note: we can use an "untracked" stind.i here even with byrefs because + // we are storing between two tracked positions. + stream->EmitSTIND_I(); + } + else + { + int token = stream->GetToken(tyHnd); + stream->EmitSTOBJ(token); + } +} + +void TailCallHelp::AppendTypeHandle(SigBuilder& builder, TypeHandle th) +{ + if (th.IsByRef()) + { + builder.AppendElementType(ELEMENT_TYPE_BYREF); + th = th.AsTypeDesc()->GetRootTypeParam(); + } + + CorElementType ty = th.GetSignatureCorElementType(); + if (CorTypeInfo::IsPrimitiveType(ty) || + ty == ELEMENT_TYPE_OBJECT || ty == ELEMENT_TYPE_STRING) + { + builder.AppendElementType(ty); + return; + } + + _ASSERTE(ty == ELEMENT_TYPE_VALUETYPE || ty == ELEMENT_TYPE_CLASS); + builder.AppendElementType(ELEMENT_TYPE_INTERNAL); + builder.AppendPointer(th.AsPtr()); +} + +PCCOR_SIGNATURE TailCallHelp::AllocateSignature(LoaderAllocator* pLoaderAlloc, SigBuilder& sig, DWORD* sigLen) +{ + PCCOR_SIGNATURE pBuilderSig = (PCCOR_SIGNATURE)sig.GetSignature(sigLen); + return (PCCOR_SIGNATURE)AllocateBlob(pLoaderAlloc, pBuilderSig, *sigLen); +} + +void* TailCallHelp::AllocateBlob(LoaderAllocator* pLoaderAllocator, const void* blob, size_t blobLen) +{ + AllocMemTracker pamTracker; + PVOID newBlob = pamTracker.Track(pLoaderAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(blobLen))); + memcpy(newBlob, blob, blobLen); + + pamTracker.SuppressRelease(); + return newBlob; +} diff --git a/src/coreclr/src/vm/tailcallhelp.h b/src/coreclr/src/vm/tailcallhelp.h new file mode 100644 index 00000000000000..38a4aae866d0f8 --- /dev/null +++ b/src/coreclr/src/vm/tailcallhelp.h @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#ifndef TAILCALL_HELP_H +#define TAILCALL_HELP_H + +#include "fcall.h" + +struct TailCallInfo; +struct ArgBufferValue; +struct ArgBufferLayout; + +class TailCallHelp +{ +public: + static FCDECL2(void*, AllocTailCallArgBuffer, INT32, void*); + static FCDECL0(void, FreeTailCallArgBuffer); + static FCDECL2(void*, GetTailCallInfo, void**, void**); + + static void CreateTailCallHelperStubs( + MethodDesc* pCallerMD, MethodDesc* pCalleeMD, + MetaSig& callSiteSig, bool virt, bool thisArgByRef, + MethodDesc** storeArgsStub, bool* storeArgsNeedsTarget, + MethodDesc** callTargetStub); + + static MethodDesc* GetOrCreateTailCallDispatcherMD(); + static MethodDesc* GetTailCallDispatcherMD(); +private: + + static void LayOutArgBuffer( + MetaSig& callSiteSig, MethodDesc* calleeMD, + bool storeTarget, bool thisArgByRef, ArgBufferLayout* layout); + static TypeHandle NormalizeSigType(TypeHandle tyHnd); + static bool GenerateGCDescriptor(MethodDesc* pTargetMD, const ArgBufferLayout& values, GCRefMapBuilder* builder); + + static MethodDesc* CreateStoreArgsStub(TailCallInfo& info); + static void CreateStoreArgsStubSig(const TailCallInfo& info, SigBuilder* sig); + + static MethodDesc* CreateCallTargetStub(const TailCallInfo& info); + static void CreateCallTargetStubSig(const TailCallInfo& info, SigBuilder* sig); + + static void EmitLoadTyHnd(ILCodeStream* stream, TypeHandle tyHnd); + static void EmitStoreTyHnd(ILCodeStream* stream, TypeHandle tyHnd); + + static void AppendTypeHandle(SigBuilder& builder, TypeHandle th); + + static PCCOR_SIGNATURE AllocateSignature(LoaderAllocator* alloc, SigBuilder& sig, DWORD* sigLen); + static void* AllocateBlob(LoaderAllocator* alloc, const void* blob, size_t blobLen); +}; + +#endif diff --git a/src/coreclr/src/vm/threads.cpp b/src/coreclr/src/vm/threads.cpp index 2a22f8952bc1ed..324c65d67ce8c4 100644 --- a/src/coreclr/src/vm/threads.cpp +++ b/src/coreclr/src/vm/threads.cpp @@ -54,6 +54,65 @@ #include "eventpipebuffermanager.h" #endif // FEATURE_PERFTRACING +static const PortableTailCallFrame g_sentinelTailCallFrame = { NULL, NULL, NULL }; + +TailCallTls::TailCallTls() + // A new frame will always be allocated before the frame is modified, + // so casting away const is ok here. + : m_frame(const_cast(&g_sentinelTailCallFrame)) + , m_argBuffer(NULL) + , m_argBufferSize(0) + , m_argBufferGCDesc(NULL) +{ +} + +void* TailCallTls::AllocArgBuffer(size_t size, void* gcDesc) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END + + _ASSERTE(m_argBuffer == NULL); + + if (size > sizeof(m_argBufferInline)) + { + m_argBuffer = new (nothrow) char[size]; + if (m_argBuffer == NULL) + return NULL; + } + else + m_argBuffer = m_argBufferInline; + + if (gcDesc != NULL) + { + memset(m_argBuffer, 0, size); + m_argBufferGCDesc = gcDesc; + } + + m_argBufferSize = size; + + return m_argBuffer; +} + +void TailCallTls::FreeArgBuffer() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END + + if (m_argBufferSize > sizeof(m_argBufferInline)) + delete[] m_argBuffer; + + m_argBufferGCDesc = NULL; + m_argBuffer = NULL; +} + #if defined (_DEBUG_IMPL) || defined(_PREFAST_) thread_local int t_ForbidGCLoaderUseCount; #endif @@ -4441,17 +4500,6 @@ void Thread::SyncManagedExceptionState(bool fIsDebuggerThread) // Syncup the LastThrownObject on the managed thread SafeUpdateLastThrownObject(); } - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // Since the catch clause has successfully executed and we are exiting it, reset the corruption severity - // in the ThreadExceptionState for the last active exception. This will ensure that when the next exception - // gets thrown/raised, EH tracker wont pick up an invalid value. - if (!fIsDebuggerThread) - { - CEHelper::ResetLastActiveCorruptionSeverityPostCatchHandler(this); - } -#endif // FEATURE_CORRUPTING_EXCEPTIONS - } void Thread::SetLastThrownObjectHandle(OBJECTHANDLE h) @@ -7337,8 +7385,7 @@ static void ManagedThreadBase_DispatchMiddle(ManagedThreadCallState *pCallState) // For Whidbey, by default only swallow certain exceptions. If reverting back to Everett's // behavior (swallowing all unhandled exception), then swallow all unhandled exception. // - if (SwallowUnhandledExceptions() || - IsExceptionOfType(kThreadAbortException, pException)) + if (IsExceptionOfType(kThreadAbortException, pException)) { // Do nothing to swallow the exception } diff --git a/src/coreclr/src/vm/threads.h b/src/coreclr/src/vm/threads.h index 5b082e03bc35c6..bb38034a6ec136 100644 --- a/src/coreclr/src/vm/threads.h +++ b/src/coreclr/src/vm/threads.h @@ -969,6 +969,35 @@ EXTERN_C void STDCALL OnHijackWorker(HijackArgs * pArgs); class BaseStackGuard; #endif +struct PortableTailCallFrame +{ + PortableTailCallFrame* Prev; + void* TailCallAwareReturnAddress; + void* NextCall; +}; + +class TailCallTls +{ + friend class MscorlibBinder; + + PortableTailCallFrame* m_frame; + char* m_argBuffer; + size_t m_argBufferSize; + void* m_argBufferGCDesc; + char m_argBufferInline[64]; + +public: + TailCallTls(); + void* AllocArgBuffer(size_t size, void* gcDesc); + void FreeArgBuffer(); + char* GetArgBuffer(void** gcDesc) + { + *gcDesc = m_argBufferGCDesc; + return m_argBuffer; + } + const PortableTailCallFrame* GetFrame() { return m_frame; } +}; + // #ThreadClass // // A code:Thread contains all the per-thread information needed by the runtime. You can get at this @@ -4101,6 +4130,23 @@ class Thread // associated with thread statics void DeleteThreadStaticData(); +private: + TailCallTls m_tailCallTls; + +public: + TailCallTls* GetTailCallTls() { return &m_tailCallTls; } + void* GetReturnAddress(void** retAddrSlot) + { +#ifdef FEATURE_HIJACK + if ((m_State & TS_Hijacked) && (retAddrSlot == m_ppvHJRetAddrPtr)) + { + return m_pvHJRetAddr; + } +#endif + + return *retAddrSlot; + } + #ifdef _DEBUG private: // When we create an object, or create an OBJECTREF, or create an Interior Pointer, or enter EE from managed diff --git a/src/coreclr/src/vm/threadsuspend.cpp b/src/coreclr/src/vm/threadsuspend.cpp index 67ffa075ee21d5..82afaf0b658ced 100644 --- a/src/coreclr/src/vm/threadsuspend.cpp +++ b/src/coreclr/src/vm/threadsuspend.cpp @@ -1246,19 +1246,6 @@ Thread::UserAbort(ThreadAbortRequester requester, BOOL fHoldingThreadStoreLock = ThreadStore::HoldingThreadStore(); - // For SafeAbort from FuncEval abort, we do not apply escalation policy. Debugger - // tries SafeAbort first with a short timeout. The thread will return to debugger. - // After some break, the thread is going to do RudeAbort if abort has not finished. - EClrOperation operation; - if (abortType == EEPolicy::TA_Rude) - { - operation = OPR_ThreadRudeAbortInCriticalRegion; - } - else - { - operation = OPR_ThreadAbort; - } - // Debugger func-eval aborts (both rude + normal) don't have any escalation policy. They are invoked // by the debugger and the debugger handles the consequences. // Furthermore, in interop-debugging, threads will be hard-suspened in preemptive mode while we try to abort them. @@ -1269,55 +1256,7 @@ Thread::UserAbort(ThreadAbortRequester requester, BOOL fEscalation = (requester != TAR_FuncEval); if (fEscalation) { - EPolicyAction action = GetEEPolicy()->GetDefaultAction(operation, this); - switch (action) - { - case eAbortThread: - GetEEPolicy()->NotifyHostOnDefaultAction(operation,action); - break; - case eRudeAbortThread: - if (abortType != EEPolicy::TA_Rude) - { - abortType = EEPolicy::TA_Rude; - } - GetEEPolicy()->NotifyHostOnDefaultAction(operation,action); - break; - case eUnloadAppDomain: - case eRudeUnloadAppDomain: - // AD unload does not abort finalizer thread. - if (this != FinalizerThread::GetFinalizerThread()) - { - if (this == GetThread()) - { - Join(INFINITE,TRUE); - } - return S_OK; - } - break; - case eExitProcess: - case eFastExitProcess: - case eRudeExitProcess: - GetEEPolicy()->NotifyHostOnDefaultAction(operation,action); - EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_THREADABORT); - _ASSERTE (!"Should not reach here"); - break; - default: - _ASSERTE (!"unknown policy for thread abort"); - } - - DWORD timeoutFromPolicy; - if (abortType != EEPolicy::TA_Rude) - { - timeoutFromPolicy = GetEEPolicy()->GetTimeout(OPR_ThreadAbort); - } - else - { - timeoutFromPolicy = GetEEPolicy()->GetTimeout(OPR_ThreadRudeAbortInCriticalRegion); - } - if (timeout > timeoutFromPolicy) - { - timeout = timeoutFromPolicy; - } + timeout = INFINITE; } AbortControlHolder AbortController(this); @@ -1398,31 +1337,12 @@ Thread::UserAbort(ThreadAbortRequester requester, if (now_time >= abortEndTime) { - EPolicyAction action1 = eNoAction; - DWORD timeout1 = INFINITE; - if (fEscalation) - { - if (!IsRudeAbort()) - { - action1 = GetEEPolicy()->GetActionOnTimeout(OPR_ThreadAbort, this); - timeout1 = GetEEPolicy()->GetTimeout(OPR_ThreadAbort); - } - else - { - action1 = GetEEPolicy()->GetActionOnTimeout(OPR_ThreadRudeAbortInCriticalRegion, this); - timeout1 = GetEEPolicy()->GetTimeout(OPR_ThreadRudeAbortInCriticalRegion); - } - } - if (action1 == eNoAction) + if (!fEscalation) { // timeout, but no action on timeout. - // Debugger can call this function to about func-eval with a timeout + // Debugger can call this function to abort func-eval with a timeout return HRESULT_FROM_WIN32(ERROR_TIMEOUT); } - if (timeout1 != INFINITE) - { - break; - } } } @@ -1844,68 +1764,11 @@ Thread::UserAbort(ThreadAbortRequester requester, if (IsAbortRequested() && fEscalation) { - EPolicyAction action1; - EClrOperation operation1; - if (!IsRudeAbort()) - { - operation1 = OPR_ThreadAbort; - } - else - { - operation1 = OPR_ThreadRudeAbortInCriticalRegion; - } - action1 = GetEEPolicy()->GetActionOnTimeout(operation1, this); - switch (action1) + if (IsRudeAbort()) { - case eRudeAbortThread: - GetEEPolicy()->NotifyHostOnTimeout(operation1, action1); MarkThreadForAbort(requester, EEPolicy::TA_Rude); SetRudeAbortEndTimeFromEEPolicy(); goto LRetry; - case eUnloadAppDomain: - // AD unload does not abort finalizer thread. - if (this == FinalizerThread::GetFinalizerThread()) - { - GetEEPolicy()->NotifyHostOnTimeout(operation1, action1); - MarkThreadForAbort(requester, EEPolicy::TA_Rude); - SetRudeAbortEndTimeFromEEPolicy(); - goto LRetry; - } - else - { - if (this == GetThread()) - { - Join(INFINITE,TRUE); - } - return S_OK; - } - break; - case eRudeUnloadAppDomain: - // AD unload does not abort finalizer thread. - if (this == FinalizerThread::GetFinalizerThread()) - { - MarkThreadForAbort(requester, EEPolicy::TA_Rude); - SetRudeAbortEndTimeFromEEPolicy(); - goto LRetry; - } - else - { - if (this == GetThread()) - { - Join(INFINITE,TRUE); - } - return S_OK; - } - break; - case eExitProcess: - case eFastExitProcess: - case eRudeExitProcess: - GetEEPolicy()->NotifyHostOnTimeout(operation1, action1); - EEPolicy::HandleExitProcessFromEscalation(action1, HOST_E_EXITPROCESS_TIMEOUT); - _ASSERTE (!"Should not reach here"); - break; - default: - break; } } @@ -1923,20 +1786,7 @@ Thread::UserAbort(ThreadAbortRequester requester, void Thread::SetRudeAbortEndTimeFromEEPolicy() { LIMITED_METHOD_CONTRACT; - - DWORD timeout = GetEEPolicy()->GetTimeout(OPR_ThreadRudeAbortInCriticalRegion); - - ULONGLONG newEndTime; - if (timeout == INFINITE) - { - newEndTime = MAXULONGLONG; - } - else - { - newEndTime = CLRGetTickCount64() + timeout; - } - - SetAbortEndTime(newEndTime, TRUE); + SetAbortEndTime(MAXULONGLONG, TRUE); } ULONGLONG Thread::s_NextSelfAbortEndTime = MAXULONGLONG; @@ -2019,34 +1869,6 @@ void Thread::MarkThreadForAbort(ThreadAbortRequester requester, EEPolicy::Thread return; } - if (requester == TAR_Thread) - { - DWORD timeoutFromPolicy; - if (abortType != EEPolicy::TA_Rude) - { - timeoutFromPolicy = GetEEPolicy()->GetTimeout(OPR_ThreadAbort); - } - else - { - timeoutFromPolicy = GetEEPolicy()->GetTimeout(OPR_ThreadRudeAbortInCriticalRegion); - } - if (timeoutFromPolicy != INFINITE) - { - ULONGLONG endTime = CLRGetTickCount64() + timeoutFromPolicy; - if (abortType != EEPolicy::TA_Rude) - { - if (endTime < m_AbortEndTime) - { - m_AbortEndTime = endTime; - } - } - else if (endTime < m_RudeAbortEndTime) - { - m_RudeAbortEndTime = endTime; - } - } - } - if (abortInfo == (m_AbortInfo & abortInfo)) { // @@ -2563,12 +2385,9 @@ void Thread::HandleThreadAbortTimeout() { WRAPPER_NO_CONTRACT; - EPolicyAction action = eNoAction; - EClrOperation operation = OPR_ThreadRudeAbortInNonCriticalRegion; - if (IsFuncEvalAbort()) { - // There can't be escalation policy for FuncEvalAbort timeout. + // There can't be escalation for FuncEvalAbort timeout. // The debugger should retain control of the policy. For example, if a RudeAbort times out, it's // probably because the debugger had some other thread frozen. When the thread is thawed, things might // be fine, so we don't want to escelate the FuncEvalRudeAbort (which will be swalled by FuncEvalHijackWorker) @@ -2576,40 +2395,10 @@ void Thread::HandleThreadAbortTimeout() return; } - if (!IsRudeAbort()) - { - operation = OPR_ThreadAbort; - } - else + if (IsRudeAbort()) { - operation = OPR_ThreadRudeAbortInCriticalRegion; - } - action = GetEEPolicy()->GetActionOnTimeout(operation, this); - // We only support escalation to rude abort - - EX_TRY { - switch (action) - { - case eRudeAbortThread: - GetEEPolicy()->NotifyHostOnTimeout(operation,action); - MarkThreadForAbort(TAR_Thread, EEPolicy::TA_Rude); - break; - case eExitProcess: - case eFastExitProcess: - case eRudeExitProcess: - GetEEPolicy()->NotifyHostOnTimeout(operation,action); - EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_THREADABORT); - _ASSERTE (!"Should not reach here"); - break; - case eNoAction: - break; - default: - _ASSERTE (!"unknown policy for thread abort"); - } - } - EX_CATCH { + MarkThreadForAbort(TAR_Thread, EEPolicy::TA_Rude); } - EX_END_CATCH(SwallowAllExceptions); } void Thread::HandleThreadAbort () @@ -2680,23 +2469,6 @@ void Thread::PreWorkForThreadAbort() // the abort is favored. But we do need to reset the interrupt bits. FastInterlockAnd((ULONG *) &m_State, ~(TS_Interruptible | TS_Interrupted)); ResetUserInterrupted(); - - if (IsRudeAbort()) { - EPolicyAction action = GetEEPolicy()->GetDefaultAction(OPR_ThreadRudeAbortInCriticalRegion, this); - switch (action) - { - case eExitProcess: - case eFastExitProcess: - case eRudeExitProcess: - { - GetEEPolicy()->NotifyHostOnDefaultAction(OPR_ThreadRudeAbortInCriticalRegion,action); - GetEEPolicy()->HandleExitProcessFromEscalation(action,HOST_E_EXITPROCESS_ADUNLOAD); - } - break; - default: - break; - } - } } #if defined(STRESS_HEAP) && defined(_DEBUG) diff --git a/src/coreclr/src/vm/tieredcompilation.cpp b/src/coreclr/src/vm/tieredcompilation.cpp index e2ff313e8f1f51..90458ec5b7e4d3 100644 --- a/src/coreclr/src/vm/tieredcompilation.cpp +++ b/src/coreclr/src/vm/tieredcompilation.cpp @@ -775,7 +775,7 @@ BOOL TieredCompilationManager::CompileCodeVersion(NativeCodeVersion nativeCodeVe // This is a recompiling request which means the caller was // in COOP mode since the code already ran. - _ASSERTE(!pMethod->HasNativeCallableAttribute()); + _ASSERTE(!pMethod->HasUnmanagedCallersOnlyAttribute()); config->SetCallerGCMode(CallerGCMode::Coop); pCode = pMethod->PrepareCode(config); LOG((LF_TIEREDCOMPILATION, LL_INFO10000, "TieredCompilationManager::CompileCodeVersion Method=0x%pM (%s::%s), code version id=0x%x, code ptr=0x%p\n", diff --git a/src/coreclr/src/vm/vars.cpp b/src/coreclr/src/vm/vars.cpp index 6c72710c50e2d0..9e6cf27a16964d 100644 --- a/src/coreclr/src/vm/vars.cpp +++ b/src/coreclr/src/vm/vars.cpp @@ -172,12 +172,6 @@ int g_IGCconcurrent = 1; int g_IGCHoardVM = 0; -#ifdef GCTRIMCOMMIT - -int g_IGCTrimCommit = 0; - -#endif - // // Global state variable indicating if the EE is in its init phase. // diff --git a/src/coreclr/src/vm/vars.hpp b/src/coreclr/src/vm/vars.hpp index ef9c8dfe8cee55..997c2157bcdae6 100644 --- a/src/coreclr/src/vm/vars.hpp +++ b/src/coreclr/src/vm/vars.hpp @@ -467,10 +467,6 @@ EXTERN HINSTANCE g_pDebuggerDll; EXTERN int g_IGCconcurrent; extern int g_IGCHoardVM; -#ifdef GCTRIMCOMMIT -extern int g_IGCTrimCommit; -#endif - // Returns a BOOL to indicate if the runtime is active or not BOOL IsRuntimeActive(); @@ -694,12 +690,23 @@ struct ModuleIndex typedef DPTR(GSCookie) PTR_GSCookie; +#ifdef _MSC_VER +#define READONLY_ATTR +#else +#ifdef __APPLE__ +#define READONLY_ATTR_ARGS section("__TEXT,__const") +#else +#define READONLY_ATTR_ARGS section(".rodata") +#endif +#define READONLY_ATTR __attribute__((READONLY_ATTR_ARGS)) +#endif + #ifndef DACCESS_COMPILE // const is so that it gets placed in the .text section (which is read-only) // volatile is so that accesses to it do not get optimized away because of the const // -extern "C" RAW_KEYWORD(volatile) const GSCookie s_gsCookie; +extern "C" RAW_KEYWORD(volatile) READONLY_ATTR const GSCookie s_gsCookie; inline GSCookie * GetProcessGSCookiePtr() { return const_cast(&s_gsCookie); } diff --git a/src/coreclr/src/vm/virtualcallstub.cpp b/src/coreclr/src/vm/virtualcallstub.cpp index 580e17d90b157a..a124ed7ac05f5b 100644 --- a/src/coreclr/src/vm/virtualcallstub.cpp +++ b/src/coreclr/src/vm/virtualcallstub.cpp @@ -1912,9 +1912,22 @@ PCODE VirtualCallStubManager::ResolveWorker(StubCallSite* pCallSite, PCODE addrOfResolver = (PCODE)(resolvers->Find(&probeR)); if (addrOfResolver == CALL_STUB_EMPTY_ENTRY) { +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) + MethodDesc* pMD = VirtualCallStubManager::GetRepresentativeMethodDescFromToken(token, objectType); + size_t stackArgumentsSize; + { + ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE(); + stackArgumentsSize = pMD->SizeOfArgStack(); + } +#endif // TARGET_X86 && !UNIX_X86_ABI + pResolveHolder = GenerateResolveStub(pResolverFcn, pBackPatchFcn, - token.To_SIZE_T()); + token.To_SIZE_T() +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) + , stackArgumentsSize +#endif + ); // Add the resolve entrypoint into the cache. //@TODO: Can we store a pointer to the holder rather than the entrypoint? @@ -2848,7 +2861,11 @@ addrOfPatcher is who to call if the fail piece is being called too often by disp */ ResolveHolder *VirtualCallStubManager::GenerateResolveStub(PCODE addrOfResolver, PCODE addrOfPatcher, - size_t dispatchToken) + size_t dispatchToken +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) + , size_t stackArgumentsSize +#endif + ) { CONTRACT (ResolveHolder*) { THROWS; @@ -2912,7 +2929,11 @@ ResolveHolder *VirtualCallStubManager::GenerateResolveStub(PCODE addr holder->Initialize(addrOfResolver, addrOfPatcher, dispatchToken, DispatchCache::HashToken(dispatchToken), - g_resolveCache->GetCacheBaseAddr(), counterAddr); + g_resolveCache->GetCacheBaseAddr(), counterAddr +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) + , stackArgumentsSize +#endif + ); ClrFlushInstructionCache(holder->stub(), holder->stub()->size()); AddToCollectibleVSDRangeList(holder); diff --git a/src/coreclr/src/vm/virtualcallstub.h b/src/coreclr/src/vm/virtualcallstub.h index cca8df3b19d3c4..9f2e2802fc86cf 100644 --- a/src/coreclr/src/vm/virtualcallstub.h +++ b/src/coreclr/src/vm/virtualcallstub.h @@ -510,7 +510,11 @@ class VirtualCallStubManager : public StubManager ResolveHolder *GenerateResolveStub(PCODE addrOfResolver, PCODE addrOfPatcher, - size_t dispatchToken); + size_t dispatchToken +#if defined(TARGET_X86) && !defined(UNIX_X86_ABI) + , size_t stackArgumentsSize +#endif + ); LookupHolder *GenerateLookupStub(PCODE addrOfResolver, size_t dispatchToken); diff --git a/src/coreclr/src/vm/vmholder.h b/src/coreclr/src/vm/vmholder.h index 9c265a1b366d73..003892b07addcf 100644 --- a/src/coreclr/src/vm/vmholder.h +++ b/src/coreclr/src/vm/vmholder.h @@ -18,6 +18,7 @@ inline void DoTheReleaseHost(TYPE *value) } } -NEW_WRAPPER_TEMPLATE1(HostComHolder, DoTheReleaseHost<_TYPE>); +template +using HostComHolder = SpecializedWrapper<_TYPE, DoTheReleaseHost<_TYPE>>; #endif diff --git a/src/coreclr/src/vm/weakreferencenative.cpp b/src/coreclr/src/vm/weakreferencenative.cpp index b1dc825494f35d..2cdb83ce9b81ed 100644 --- a/src/coreclr/src/vm/weakreferencenative.cpp +++ b/src/coreclr/src/vm/weakreferencenative.cpp @@ -16,6 +16,7 @@ #include "typestring.h" #include "typeparse.h" #include "threadsuspend.h" +#include "interoplibinterface.h" //************************************************************************ @@ -34,7 +35,7 @@ const LPVOID specialWeakReferenceHandles[3] = { 0, 0, 0 }; // // A WeakReference instance can hold one of three types of handles - short or long weak handles, -// or a WinRT weak reference handle. The WinRT weak reference handle has the extra capability +// or a native COM weak reference handle. The native COM weak reference handle has the extra capability // of recreating an RCW for a COM object which is still alive even though the previous RCW had // been collected. In order to differentiate this type of handle from the standard weak handles, // the bottom bit is stolen. @@ -50,23 +51,23 @@ const LPVOID specialWeakReferenceHandles[3] = { 0, 0, 0 }; // The following functions are to set, test, and unset that bit before the handle is used. // -// Determine if an object handle is a WinRT weak reference handle -bool IsWinRTWeakReferenceHandle(OBJECTHANDLE handle) +// Determine if an object handle is a native COM weak reference handle +bool IsNativeComWeakReferenceHandle(OBJECTHANDLE handle) { STATIC_CONTRACT_LEAF; return (reinterpret_cast(handle) & 0x1) != 0x0; } -// Mark an object handle as being a WinRT weak reference handle -OBJECTHANDLE SetWinRTWeakReferenceHandle(OBJECTHANDLE handle) +// Mark an object handle as being a native COM weak reference handle +OBJECTHANDLE SetNativeComWeakReferenceHandle(OBJECTHANDLE handle) { STATIC_CONTRACT_LEAF; - _ASSERTE(!IsWinRTWeakReferenceHandle(handle)); + _ASSERTE(!IsNativeComWeakReferenceHandle(handle)); return reinterpret_cast(reinterpret_cast(handle) | 0x1); } -// Get the object handle value even if the object is a WinRT weak reference +// Get the object handle value even if the object is a native COM weak reference OBJECTHANDLE GetHandleValue(OBJECTHANDLE handle) { STATIC_CONTRACT_LEAF; @@ -102,17 +103,17 @@ struct WeakHandleSpinLockHolder #ifdef FEATURE_COMINTEROP -// Get a WinRT weak reference for the object underlying an RCW if applicable. If the incoming object cannot -// use a WinRT weak reference, nullptr is returned. Otherwise, an AddRef-ed IWeakReference* for the COM +// Get a native COM weak reference for the object underlying an RCW if applicable. If the incoming object cannot +// use a native COM weak reference, nullptr is returned. Otherwise, an AddRef-ed IWeakReference* for the COM // object underlying the RCW is returned. // -// In order to qualify to be used with a HNDTYPE_WEAK_WINRT, the incoming object must: +// In order to qualify to be used with a HNDTYPE_WEAK_NATIVE_COM, the incoming object must: // * be an RCW // * respond to a QI for IWeakReferenceSource // * succeed when asked for an IWeakReference* // // Note that *pObject should be GC protected on the way into this method -IWeakReference* GetWinRTWeakReference(OBJECTREF* pObject) +IWeakReference* GetComWeakReference(OBJECTREF* pObject) { CONTRACTL { @@ -132,21 +133,24 @@ IWeakReference* GetWinRTWeakReference(OBJECTREF* pObject) MethodTable* pMT = (*pObject)->GetMethodTable(); - // If the object is not an RCW, then we do not want to use a WinRT weak reference to it - if (!pMT->IsComObjectType()) - { - return nullptr; - } + SafeComHolder pWeakReferenceSource(nullptr); - // If the object is a managed type deriving from a COM type, then we also do not want to use a WinRT + // If the object is not an RCW, then we do not want to use a native COM weak reference to it + // If the object is a managed type deriving from a COM type, then we also do not want to use a native COM // weak reference to it. (Otherwise, we'll wind up resolving IWeakReference-s back into the CLR // when we don't want to have reentrancy). - if (pMT != g_pBaseCOMObject && pMT->IsExtensibleRCW()) + if (pMT->IsComObjectType() + && (pMT == g_pBaseCOMObject || !pMT->IsExtensibleRCW())) { - return nullptr; + pWeakReferenceSource = reinterpret_cast(GetComIPFromObjectRef(pObject, IID_IWeakReferenceSource, false /* throwIfNoComIP */)); + } +#ifdef FEATURE_COMWRAPPERS + else + { + pWeakReferenceSource = reinterpret_cast(ComWrappersNative::GetIdentityForObject(pObject, IID_IWeakReferenceSource)); } +#endif - SafeComHolder pWeakReferenceSource(reinterpret_cast(GetComIPFromObjectRef(pObject, IID_IWeakReferenceSource, false /* throwIfNoComIP */))); if (pWeakReferenceSource == nullptr) { return nullptr; @@ -162,17 +166,17 @@ IWeakReference* GetWinRTWeakReference(OBJECTREF* pObject) return pWeakReference.Extract(); } -// Given an object handle that stores a WinRT weak reference, attempt to create an RCW -// and store it back in the handle, returning the RCW. If the underlying WinRT object +// Given an object handle that stores a native COM weak reference, attempt to create an RCW +// and store it back in the handle, returning the RCW. If the underlying native COM object // is not alive, then the result is NULL. // // In order to create a new RCW, we must: -// * Have an m_handle of HNDTYPE_WEAK_WINRT (ie the bottom bit of m_handle is set) +// * Have an m_handle of HNDTYPE_WEAK_NATIVE_COM (ie the bottom bit of m_handle is set) // * Have stored an IWeakReference* in the handle extra info when setting up the handle -// (see GetWinRTWeakReference) +// (see GetComWeakReference) // * The IWeakReference* must respond to a Resolve request for IID_IInspectable // * -NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, TypeHandle targetType, LPVOID __me) +NOINLINE Object* LoadComWeakReferenceTarget(WEAKREFERENCEREF weakReference, TypeHandle targetType, LPVOID __me) { CONTRACTL { @@ -200,14 +204,14 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty // // Since we're acquiring and releasing the lock multiple times, we need to check the handle state each time we // reacquire the lock to make sure that another thread hasn't reassigned the target of the handle or finalized it - SafeComHolder pWinRTWeakReference = nullptr; + SafeComHolder pComWeakReference = nullptr; { WeakHandleSpinLockHolder handle(AcquireWeakHandleSpinLock(gc.weakReference), &gc.weakReference); GCX_NOTRIGGER(); // Make sure that while we were not holding the spin lock, another thread did not change the target of // this weak reference. Only fetch the IWeakReference* if we still have a valid handle holding a NULL object - // and the handle is still a HNDTYPE_WEAK_WINRT type handle. + // and the handle is still a HNDTYPE_WEAK_NATIVE_COM type handle. if ((handle.Handle != NULL) && !IS_SPECIAL_HANDLE(handle.Handle)) { if (*(Object **)(handle.Handle) != NULL) @@ -217,22 +221,22 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty // weak reference is targeting. gc.target = ObjectToOBJECTREF(*(Object **)(handle.Handle)); } - else if(IsWinRTWeakReferenceHandle(handle.RawHandle)) + else if(IsNativeComWeakReferenceHandle(handle.RawHandle)) { - _ASSERTE(GCHandleUtilities::GetGCHandleManager()->HandleFetchType(handle.Handle) == HNDTYPE_WEAK_WINRT); + _ASSERTE(GCHandleUtilities::GetGCHandleManager()->HandleFetchType(handle.Handle) == HNDTYPE_WEAK_NATIVE_COM); // Retrieve the associated IWeakReference* for this weak reference. Add a reference to it while we release // the spin lock so that another thread doesn't release it out from underneath us. // - // Setting pWinRTWeakReference will claim that it triggers a GC, however that's not true in this case because + // Setting pComWeakReference will claim that it triggers a GC, however that's not true in this case because // it's always set to NULL here and there's nothing for it to release. - _ASSERTE(pWinRTWeakReference.IsNull()); + _ASSERTE(pComWeakReference.IsNull()); CONTRACT_VIOLATION(GCViolation); IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager(); - pWinRTWeakReference = reinterpret_cast(mgr->GetExtraInfoFromHandle(handle.Handle)); - if (!pWinRTWeakReference.IsNull()) + pComWeakReference = reinterpret_cast(mgr->GetExtraInfoFromHandle(handle.Handle)); + if (!pComWeakReference.IsNull()) { - pWinRTWeakReference->AddRef(); + pComWeakReference->AddRef(); } } } @@ -242,16 +246,16 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty // identity of the underlying COM object (assuming that object is still alive). This work is done without holding the // spin lock since it will call out to arbitrary code and as such we need to switch to preemptive mode. SafeComHolder pTargetIdentity = nullptr; - if (pWinRTWeakReference != nullptr) + if (pComWeakReference != nullptr) { _ASSERTE(gc.target == NULL); GCX_PREEMP(); - // Using the IWeakReference*, get ahold of the target WinRT object's IInspectable*. If this resolve fails, then we - // assume that the underlying WinRT object is no longer alive, and thus we cannot create a new RCW for it. + // Using the IWeakReference*, get ahold of the target native COM object's IInspectable*. If this resolve fails, then we + // assume that the underlying native COM object is no longer alive, and thus we cannot create a new RCW for it. SafeComHolderPreemp pTarget = nullptr; - if (SUCCEEDED(pWinRTWeakReference->Resolve(IID_IInspectable, &pTarget))) + if (SUCCEEDED(pComWeakReference->Resolve(IID_IInspectable, &pTarget))) { if (!pTarget.IsNull()) { @@ -264,7 +268,11 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty // If we were able to get an IUnkown identity for the object, then we can find or create an associated RCW for it. if (!pTargetIdentity.IsNull()) { - GetObjectRefFromComIP(&gc.rcw, pTargetIdentity); + // Try the global COM wrappers first before falling back to the built-in system. + if (!GlobalComWrappersForTrackerSupport::TryGetOrCreateObjectForComInstance(pTargetIdentity, &gc.rcw)) + { + GetObjectRefFromComIP(&gc.rcw, pTargetIdentity); + } } // If we were able to get an RCW, then we need to reacquire the spin lock and store the RCW in the handle. Note that @@ -272,7 +280,7 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty // building the RCW. In that case, we will defer to the hadle that the other thread set, and let the RCW die. if (gc.rcw != NULL) { - // Make sure the type we got back from the WinRT object is compatible with the type the managed + // Make sure the type we got back from the native COM object is compatible with the type the managed // weak reference expects. (For instance, in the WeakReference case, the returned type // had better be compatible with T). TypeHandle rcwType(gc.rcw->GetMethodTable()); @@ -284,7 +292,7 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty SString resolvedTypeName; TypeString::AppendType(resolvedTypeName, rcwType, TypeString::FormatNamespace | TypeString::FormatFullInst | TypeString::FormatAssembly); - COMPlusThrow(kInvalidCastException, IDS_EE_WINRT_WEAKREF_BAD_TYPE, weakReferenceTypeName.GetUnicode(), resolvedTypeName.GetUnicode()); + COMPlusThrow(kInvalidCastException, IDS_EE_NATIVE_COM_WEAKREF_BAD_TYPE, weakReferenceTypeName.GetUnicode(), resolvedTypeName.GetUnicode()); } WeakHandleSpinLockHolder handle(AcquireWeakHandleSpinLock(gc.weakReference), &gc.weakReference); @@ -420,12 +428,21 @@ FCIMPL3(void, WeakReferenceNative::Create, WeakReferenceObject * pThisUNSAFE, Ob // Create the handle. #ifdef FEATURE_COMINTEROP - IWeakReference* pRawWinRTWeakReference = GetWinRTWeakReference(&gc.pTarget); - if (pRawWinRTWeakReference != nullptr) + IWeakReference* pRawComWeakReference = nullptr; + if (gc.pTarget != NULL) { - SafeComHolder pWinRTWeakReferenceHolder(pRawWinRTWeakReference); - gc.pThis->m_Handle = SetWinRTWeakReferenceHandle(GetAppDomain()->CreateWinRTWeakHandle(gc.pTarget, pWinRTWeakReferenceHolder)); - pWinRTWeakReferenceHolder.SuppressRelease(); + SyncBlock* pSyncBlock = gc.pTarget->PassiveGetSyncBlock(); + if (pSyncBlock != nullptr && pSyncBlock->GetInteropInfoNoCreate() != nullptr) + { + pRawComWeakReference = GetComWeakReference(&gc.pTarget); + } + } + + if (pRawComWeakReference != nullptr) + { + SafeComHolder pComWeakReferenceHolder(pRawComWeakReference); + gc.pThis->m_Handle = SetNativeComWeakReferenceHandle(GetAppDomain()->CreateNativeComWeakHandle(gc.pTarget, pComWeakReferenceHolder)); + pComWeakReferenceHolder.SuppressRelease(); } else #endif // FEATURE_COMINTEROP @@ -463,12 +480,21 @@ FCIMPL3(void, WeakReferenceOfTNative::Create, WeakReferenceObject * pThisUNSAFE, // Create the handle. #ifdef FEATURE_COMINTEROP - IWeakReference* pRawWinRTWeakReference = GetWinRTWeakReference(&gc.pTarget); - if (pRawWinRTWeakReference != nullptr) + IWeakReference* pRawComWeakReference = nullptr; + if (gc.pTarget != NULL) + { + SyncBlock* pSyncBlock = gc.pTarget->PassiveGetSyncBlock(); + if (pSyncBlock != nullptr && pSyncBlock->GetInteropInfoNoCreate() != nullptr) + { + pRawComWeakReference = GetComWeakReference(&gc.pTarget); + } + } + + if (pRawComWeakReference != nullptr) { - SafeComHolder pWinRTWeakReferenceHolder(pRawWinRTWeakReference); - gc.pThis->m_Handle = SetWinRTWeakReferenceHandle(GetAppDomain()->CreateWinRTWeakHandle(gc.pTarget, pWinRTWeakReferenceHolder)); - pWinRTWeakReferenceHolder.SuppressRelease(); + SafeComHolder pComWeakReferenceHolder(pRawComWeakReference); + gc.pThis->m_Handle = SetNativeComWeakReferenceHandle(GetAppDomain()->CreateNativeComWeakHandle(gc.pTarget, pComWeakReferenceHolder)); + pComWeakReferenceHolder.SuppressRelease(); } else #endif // FEATURE_COMINTEROP @@ -499,7 +525,7 @@ void FinalizeWeakReference(Object * obj) // The suspension state of the runtime must be prevented from changing while in this function in order for this to be safe. OBJECTHANDLE handle = ThreadSuspend::SysIsSuspended() ? pThis->m_Handle.LoadWithoutBarrier() : AcquireWeakHandleSpinLock(pThis); OBJECTHANDLE handleToDestroy = NULL; - bool isWeakWinRTHandle = false; + bool isWeakNativeComHandle = false; // Check for not yet constructed or already finalized handle if ((handle != NULL) && !IS_SPECIAL_HANDLE(handle)) @@ -509,8 +535,8 @@ void FinalizeWeakReference(Object * obj) // Cache the old handle value HandleType handleType = GCHandleUtilities::GetGCHandleManager()->HandleFetchType(handleToDestroy); #ifdef FEATURE_COMINTEROP - _ASSERTE(handleType == HNDTYPE_WEAK_LONG || handleType == HNDTYPE_WEAK_SHORT || handleType == HNDTYPE_WEAK_WINRT); - isWeakWinRTHandle = handleType == HNDTYPE_WEAK_WINRT; + _ASSERTE(handleType == HNDTYPE_WEAK_LONG || handleType == HNDTYPE_WEAK_SHORT || handleType == HNDTYPE_WEAK_NATIVE_COM); + isWeakNativeComHandle = handleType == HNDTYPE_WEAK_NATIVE_COM; #else // !FEATURE_COMINTEROP _ASSERTE(handleType == HNDTYPE_WEAK_LONG || handleType == HNDTYPE_WEAK_SHORT); #endif // FEATURE_COMINTEROP @@ -528,9 +554,9 @@ void FinalizeWeakReference(Object * obj) if (handleToDestroy != NULL) { #ifdef FEATURE_COMINTEROP - if (isWeakWinRTHandle) + if (isWeakNativeComHandle) { - DestroyWinRTWeakHandle(handleToDestroy); + DestroyNativeComWeakHandle(handleToDestroy); } else #endif // FEATURE_COMINTEROP @@ -645,14 +671,14 @@ FCIMPL1(Object *, WeakReferenceNative::GetTarget, WeakReferenceObject * pThisUNS OBJECTREF pTarget = GetWeakReferenceTarget(pThis); #ifdef FEATURE_COMINTEROP - // If we found an object, or we're not a WinRT weak reference, then we're done. Othewrise - // we can try to create a new RCW to the underlying WinRT object if it's still alive. - if (pTarget != NULL || !IsWinRTWeakReferenceHandle(pThis->m_Handle)) + // If we found an object, or we're not a native COM weak reference, then we're done. Othewrise + // we can try to create a new RCW to the underlying native COM object if it's still alive. + if (pTarget != NULL || !IsNativeComWeakReferenceHandle(pThis->m_Handle)) { FC_GC_POLL_AND_RETURN_OBJREF(pTarget); } - FC_INNER_RETURN(Object*, LoadWinRTWeakReferenceTarget(pThis, g_pObjectClass, GetEEFuncEntryPointMacro(WeakReferenceNative::GetTarget))); + FC_INNER_RETURN(Object*, LoadComWeakReferenceTarget(pThis, g_pObjectClass, GetEEFuncEntryPointMacro(WeakReferenceNative::GetTarget))); #else // !FEATURE_COMINTEROP FC_GC_POLL_AND_RETURN_OBJREF(pTarget); #endif // FEATURE_COMINTEROP @@ -673,14 +699,14 @@ FCIMPL1(Object *, WeakReferenceOfTNative::GetTarget, WeakReferenceObject * pThis #ifdef FEATURE_COMINTEROP - // If we found an object, or we're not a WinRT weak reference, then we're done. Othewrise - // we can try to create a new RCW to the underlying WinRT object if it's still alive. - if (pTarget != NULL || !IsWinRTWeakReferenceHandle(pThis->m_Handle)) + // If we found an object, or we're not a native COM weak reference, then we're done. Othewrise + // we can try to create a new RCW to the underlying native COM object if it's still alive. + if (pTarget != NULL || !IsNativeComWeakReferenceHandle(pThis->m_Handle)) { FC_GC_POLL_AND_RETURN_OBJREF(pTarget); } - FC_INNER_RETURN(Object*, LoadWinRTWeakReferenceTarget(pThis, pThis->GetMethodTable()->GetInstantiation()[0], GetEEFuncEntryPointMacro(WeakReferenceOfTNative::GetTarget))); + FC_INNER_RETURN(Object*, LoadComWeakReferenceTarget(pThis, pThis->GetMethodTable()->GetInstantiation()[0], GetEEFuncEntryPointMacro(WeakReferenceOfTNative::GetTarget))); #else // !FEATURE_COMINTEROP FC_GC_POLL_AND_RETURN_OBJREF(pTarget); #endif // FEATURE_COMINTEROP @@ -711,7 +737,7 @@ FCIMPLEND #include -// Slow path helper for setting the target of a weak reference. This code is used if a WinRT weak reference might +// Slow path helper for setting the target of a weak reference. This code is used if a native COM weak reference might // be required. NOINLINE void SetWeakReferenceTarget(WEAKREFERENCEREF weakReference, OBJECTREF target, LPVOID __me) { @@ -721,7 +747,7 @@ NOINLINE void SetWeakReferenceTarget(WEAKREFERENCEREF weakReference, OBJECTREF t HELPER_METHOD_FRAME_BEGIN_ATTRIB_2(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2, target, weakReference); #ifdef FEATURE_COMINTEROP - SafeComHolder pTargetWeakReference(GetWinRTWeakReference(&target)); + SafeComHolder pTargetWeakReference(GetComWeakReference(&target)); #endif // FEATURE_COMINTEROP @@ -735,30 +761,30 @@ NOINLINE void SetWeakReferenceTarget(WEAKREFERENCEREF weakReference, OBJECTREF t // Existing target is a GC object, new target is a GC object: // * Just store the new object in the handle // - // Existing target is WinRT, new target is WinRT: + // Existing target is native COM weak reference, new target is native COM weak reference: // * Release the existing IWeakReference* // * Store the new IWeakReference* // * Store the new object in the handle // - // Existing target is WinRT, new target is GC: + // Existing target is native COM weak reference, new target is GC: // * Release the existing IWeakReference* // * Store null to the IWeakReference* field // * Store the new object in the handle // - // Existing target is GC, new target is WinRT: + // Existing target is GC, new target is native COM weak reference: // * Destroy the existing handle - // * Allocate a new WinRT weak handle for the new target + // * Allocate a new native COM weak handle for the new target // - if (IsWinRTWeakReferenceHandle(handle.RawHandle)) + if (IsNativeComWeakReferenceHandle(handle.RawHandle)) { - // If the existing reference is a WinRT weak reference, we need to release its IWeakReference pointer + // If the existing reference is a native COM weak reference, we need to release its IWeakReference pointer // and update it with the new weak reference pointer. If the incoming object is not an RCW that can // use IWeakReference, then pTargetWeakReference will be null. Therefore, no matter what the incoming // object type is, we can unconditionally store pTargetWeakReference to the object handle's extra data. IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager(); IWeakReference* pExistingWeakReference = reinterpret_cast(mgr->GetExtraInfoFromHandle(handle.Handle)); - mgr->SetExtraInfoForHandle(handle.Handle, HNDTYPE_WEAK_WINRT, reinterpret_cast(pTargetWeakReference.GetValue())); + mgr->SetExtraInfoForHandle(handle.Handle, HNDTYPE_WEAK_NATIVE_COM, reinterpret_cast(pTargetWeakReference.GetValue())); StoreObjectInHandle(handle.Handle, target); if (pExistingWeakReference != nullptr) @@ -768,15 +794,15 @@ NOINLINE void SetWeakReferenceTarget(WEAKREFERENCEREF weakReference, OBJECTREF t } else if (pTargetWeakReference != nullptr) { - // The existing handle is not a WinRT weak reference, but we need to store the new object in - // a WinRT weak reference. Therefore we need to destroy the old handle and create a new WinRT + // The existing handle is not a native COM weak reference, but we need to store the new object in + // a native COM weak reference. Therefore we need to destroy the old handle and create a new native COM // handle. The new handle needs to be allocated first to prevent the weak reference from holding // a destroyed handle if we fail to allocate the new one. - _ASSERTE(!IsWinRTWeakReferenceHandle(handle.RawHandle)); + _ASSERTE(!IsNativeComWeakReferenceHandle(handle.RawHandle)); OBJECTHANDLE previousHandle = handle.RawHandle; - handle.Handle = GetAppDomain()->CreateWinRTWeakHandle(target, pTargetWeakReference); - handle.RawHandle = SetWinRTWeakReferenceHandle(handle.Handle); + handle.Handle = GetAppDomain()->CreateNativeComWeakHandle(target, pTargetWeakReference); + handle.RawHandle = SetNativeComWeakReferenceHandle(handle.Handle); DestroyTypedHandle(previousHandle); } @@ -822,7 +848,7 @@ FCIMPL2(void, WeakReferenceNative::SetTarget, WeakReferenceObject * pThisUNSAFE, // If the existing handle is a GC weak handle and the new target is not an RCW, then // we can avoid setting up a helper method frame and just reset the handle directly. - if (!IsWinRTWeakReferenceHandle(handle)) + if (!IsNativeComWeakReferenceHandle(handle)) { if (pTarget == NULL || !pTarget->GetMethodTable()->IsComObjectType()) { @@ -875,7 +901,7 @@ FCIMPL2(void, WeakReferenceOfTNative::SetTarget, WeakReferenceObject * pThisUNSA // If the existing handle is a GC weak handle and the new target is not an RCW, then // we can avoid setting up a helper method frame and just reset the handle directly. - if (!IsWinRTWeakReferenceHandle(handle)) + if (!IsNativeComWeakReferenceHandle(handle)) { if (pTarget == NULL || !pTarget->GetMethodTable()->IsComObjectType()) { diff --git a/src/coreclr/src/vm/wellknownattributes.h b/src/coreclr/src/vm/wellknownattributes.h index de71eb459f90cf..b3fef4b4fda8c6 100644 --- a/src/coreclr/src/vm/wellknownattributes.h +++ b/src/coreclr/src/vm/wellknownattributes.h @@ -30,7 +30,7 @@ enum class WellKnownAttribute : DWORD IsByRefLike, PrimaryInteropAssembly, ManagedToNativeComInteropStub, - NativeCallable, + UnmanagedCallersOnly, TypeIdentifier, UnmanagedFunctionPointer, ThreadStatic, @@ -89,8 +89,8 @@ inline const char *GetWellKnownAttributeName(WellKnownAttribute attribute) return "System.Runtime.InteropServices.PrimaryInteropAssemblyAttribute"; case WellKnownAttribute::ManagedToNativeComInteropStub: return "System.Runtime.InteropServices.ManagedToNativeComInteropStubAttribute"; - case WellKnownAttribute::NativeCallable: - return "System.Runtime.InteropServices.NativeCallableAttribute"; + case WellKnownAttribute::UnmanagedCallersOnly: + return "System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute"; case WellKnownAttribute::TypeIdentifier: return "System.Runtime.InteropServices.TypeIdentifierAttribute"; case WellKnownAttribute::UnmanagedFunctionPointer: diff --git a/src/coreclr/src/vm/win32threadpool.cpp b/src/coreclr/src/vm/win32threadpool.cpp index 3d5ec4c7f27753..b7106ccd8108a7 100644 --- a/src/coreclr/src/vm/win32threadpool.cpp +++ b/src/coreclr/src/vm/win32threadpool.cpp @@ -2771,14 +2771,7 @@ void ThreadpoolMgr::ProcessWaitCompletion(WaitInfo* waitInfo, if (asyncCallback) ReleaseAsyncCallback(asyncCallback); - if (SwallowUnhandledExceptions()) - { - // Do nothing to swallow the exception - } - else - { - EX_RETHROW; - } + EX_RETHROW; } EX_END_CATCH(SwallowAllExceptions); } @@ -4563,14 +4556,7 @@ void ThreadpoolMgr::TimerThreadFire() EX_CATCH { // Assert on debug builds since a dead timer thread is a fatal error _ASSERTE(FALSE); - if (SwallowUnhandledExceptions()) - { - // Do nothing to swallow the exception - } - else - { - EX_RETHROW; - } + EX_RETHROW; } EX_END_CATCH(SwallowAllExceptions); } diff --git a/src/coreclr/src/vm/wrappers.h b/src/coreclr/src/vm/wrappers.h index b9e40e89979b81..a256cb56ea3b2e 100644 --- a/src/coreclr/src/vm/wrappers.h +++ b/src/coreclr/src/vm/wrappers.h @@ -109,11 +109,13 @@ inline void SafeComReleasePreemp(TYPE *value) SafeReleasePreemp((IUnknown*)value); } -NEW_WRAPPER_TEMPLATE1(SafeComHolder, SafeComRelease<_TYPE>); +template +using SafeComHolder = SpecializedWrapper<_TYPE, SafeComRelease<_TYPE>>; // Use this holder if you're already in preemptive mode for other reasons, // use SafeComHolder otherwise. -NEW_WRAPPER_TEMPLATE1(SafeComHolderPreemp, SafeComReleasePreemp<_TYPE>); +template +using SafeComHolderPreemp = SpecializedWrapper<_TYPE, SafeComReleasePreemp<_TYPE>>; @@ -166,7 +168,8 @@ void DeletePreemp(TYPE *value) delete value; } -NEW_WRAPPER_TEMPLATE1(NewPreempHolder, DeletePreemp<_TYPE>); +template +using NewPreempHolder = SpecializedWrapper<_TYPE, DeletePreemp<_TYPE>>; //----------------------------------------------------------------------------- diff --git a/src/coreclr/src/vm/zapsig.cpp b/src/coreclr/src/vm/zapsig.cpp index e07520cdde2609..515ea2fb4dc1f1 100644 --- a/src/coreclr/src/vm/zapsig.cpp +++ b/src/coreclr/src/vm/zapsig.cpp @@ -650,7 +650,7 @@ Module *ZapSig::DecodeModuleFromIndex(Module *fromModule, { if (nativeImage != NULL) { - pAssembly = nativeImage->LoadComponentAssembly(index); + pAssembly = nativeImage->LoadManifestAssembly(index); } else { @@ -658,6 +658,7 @@ Module *ZapSig::DecodeModuleFromIndex(Module *fromModule, spec.InitializeSpec(TokenFromRid(index, mdtAssemblyRef), fromModule->GetNativeAssemblyImport(), NULL); + spec.SetParentAssembly(fromModule->GetDomainAssembly()); pAssembly = spec.LoadAssembly(FILE_LOADED); } fromModule->SetNativeMetadataAssemblyRefInCache(index, pAssembly); diff --git a/src/coreclr/src/zap/common.h b/src/coreclr/src/zap/common.h index 5f033e54c1e0d5..1b132908aa84a0 100644 --- a/src/coreclr/src/zap/common.h +++ b/src/coreclr/src/zap/common.h @@ -52,7 +52,7 @@ typedef unsigned int TARGET_POINTER_TYPE; #include "guidfromname.h" #include "../dlls/mscorrc/resource.h" #include "zaplog.h" -#include "ndpversion.h" +#include "clrversion.h" #include "loaderheap.h" diff --git a/src/coreclr/src/zap/zapimage.cpp b/src/coreclr/src/zap/zapimage.cpp index 2a2f158f8610f9..258ebcfddf9b8b 100644 --- a/src/coreclr/src/zap/zapimage.cpp +++ b/src/coreclr/src/zap/zapimage.cpp @@ -220,7 +220,7 @@ void ZapImage::InitializeSectionsForReadyToRun() { #define COMPILER_NAME "CoreCLR" - const char * pCompilerIdentifier = COMPILER_NAME " " FX_FILEVERSION_STR " " QUOTE_MACRO(__BUILDMACHINE__); + const char* pCompilerIdentifier = COMPILER_NAME " " VER_FILEVERSION_STR; ZapBlob * pCompilerIdentifierBlob = new (GetHeap()) ZapBlobPtr((PVOID)pCompilerIdentifier, strlen(pCompilerIdentifier) + 1); GetReadyToRunHeader()->RegisterSection(ReadyToRunSectionType::CompilerIdentifier, pCompilerIdentifierBlob); @@ -1361,7 +1361,7 @@ void ZapImage::Open(CORINFO_MODULE_HANDLE hModule, { // Hardwire the metadata version to be the current runtime version so that the ngen image // does not change when the directory runtime is installed in different directory (e.g. v2.0.x86chk vs. v2.0.80826). - BSTRHolder strVersion(SysAllocString(W("v")VER_PRODUCTVERSION_NO_QFE_STR_L)); + BSTRHolder strVersion(SysAllocString(CLR_METADATA_VERSION_L)); VARIANT versionOption; V_VT(&versionOption) = VT_BSTR; V_BSTR(&versionOption) = strVersion; diff --git a/src/coreclr/src/zap/zapimport.cpp b/src/coreclr/src/zap/zapimport.cpp index 599fbcef38bbf2..6c76fa7faca491 100644 --- a/src/coreclr/src/zap/zapimport.cpp +++ b/src/coreclr/src/zap/zapimport.cpp @@ -1249,7 +1249,7 @@ class ZapFunctionEntryImport : public ZapImport if (token != mdTokenNil) { _ASSERTE(TypeFromToken(token) == mdtMethodDef || TypeFromToken(token) == mdtMemberRef); - _ASSERTE(!pTable->GetCompileInfo()->IsNativeCallableMethod(handle)); + _ASSERTE(!pTable->GetCompileInfo()->IsUnmanagedCallersOnlyMethod(handle)); pTable->EncodeModule( (TypeFromToken(token) == mdtMethodDef) ? ENCODE_METHOD_ENTRY_DEF_TOKEN : ENCODE_METHOD_ENTRY_REF_TOKEN, diff --git a/src/coreclr/src/zap/zapinfo.cpp b/src/coreclr/src/zap/zapinfo.cpp index f65ec7c8aaf1ff..1f4f83c0e48e8a 100644 --- a/src/coreclr/src/zap/zapinfo.cpp +++ b/src/coreclr/src/zap/zapinfo.cpp @@ -483,10 +483,10 @@ void ZapInfo::CompileMethod() #endif #ifdef TARGET_X86 - if (GetCompileInfo()->IsNativeCallableMethod(m_currentMethodHandle)) + if (GetCompileInfo()->IsUnmanagedCallersOnlyMethod(m_currentMethodHandle)) { if (m_zapper->m_pOpt->m_verbose) - m_zapper->Warning(W("ReadyToRun: Methods with NativeCallableAttribute not implemented\n")); + m_zapper->Warning(W("ReadyToRun: Methods with UnmanagedCallersOnlyAttribute not implemented\n")); ThrowHR(E_NOTIMPL); } #endif // TARGET_X86 @@ -1717,14 +1717,14 @@ void ZapInfo::embedGenericSignature(CORINFO_LOOKUP * pLookup) } } -void* ZapInfo::getTailCallCopyArgsThunk ( - CORINFO_SIG_INFO *pSig, - CorInfoHelperTailCallSpecialHandling flags) +bool ZapInfo::getTailCallHelpers( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult) { - void * pStub = m_pEEJitInfo->getTailCallCopyArgsThunk(pSig, flags); - if (pStub == NULL) - return NULL; - return m_pImage->GetWrappers()->GetStub(pStub); + ThrowHR(E_NOTIMPL); + return false; } bool ZapInfo::convertPInvokeCalliToCall( @@ -2134,7 +2134,7 @@ DWORD FilterNamedIntrinsicMethodAttribs(ZapInfo* pZapInfo, DWORD attribs, CORINF #if defined(TARGET_X86) || defined(TARGET_AMD64) fIsPlatformHWIntrinsic = strcmp(namespaceName, "System.Runtime.Intrinsics.X86") == 0; -#elif TARGET_ARM64 +#elif defined(TARGET_ARM64) fIsPlatformHWIntrinsic = strcmp(namespaceName, "System.Runtime.Intrinsics.Arm") == 0; #endif @@ -2152,28 +2152,40 @@ DWORD FilterNamedIntrinsicMethodAttribs(ZapInfo* pZapInfo, DWORD attribs, CORINF // answer for the CPU the code is running on. fTreatAsRegularMethodCall = (fIsGetIsSupportedMethod && fIsPlatformHWIntrinsic) || (!fIsPlatformHWIntrinsic && fIsHWIntrinsic); -#if defined(TARGET_X86) || defined(TARGET_AMD64) if (fIsPlatformHWIntrinsic) { // Simplify the comparison logic by grabbing the name of the ISA const char* isaName = (enclosingClassName == nullptr) ? className : enclosingClassName; - if ((strcmp(isaName, "Sse") == 0) || (strcmp(isaName, "Sse2") == 0)) + bool fIsPlatformRequiredISA = false; + bool fIsPlatformSubArchitecture = false; + +#if defined(TARGET_X86) || defined(TARGET_AMD64) + fIsPlatformRequiredISA = (strcmp(isaName, "X86Base") == 0) || (strcmp(isaName, "Sse") == 0) || (strcmp(isaName, "Sse2") == 0); + fIsPlatformSubArchitecture = strcmp(className, "X64") == 0; +#elif defined(TARGET_ARM64) + fIsPlatformRequiredISA = (strcmp(isaName, "ArmBase") == 0) || (strcmp(isaName, "AdvSimd") == 0); + fIsPlatformSubArchitecture = strcmp(className, "Arm64") == 0; +#endif + + if (fIsPlatformRequiredISA) { - if ((enclosingClassName == nullptr) || (strcmp(className, "X64") == 0)) + if ((enclosingClassName == nullptr) || fIsPlatformSubArchitecture) { - // If it's anything related to Sse/Sse2, we can expand unconditionally since this is - // a baseline requirement of CoreCLR. + // If the ISA is required by CoreCLR for the platform, we can expand unconditionally fTreatAsRegularMethodCall = false; } } - else if ((strcmp(className, "Avx") == 0) || (strcmp(className, "Fma") == 0) || (strcmp(className, "Avx2") == 0) || (strcmp(className, "Bmi1") == 0) || (strcmp(className, "Bmi2") == 0)) +#if defined(TARGET_X86) || defined(TARGET_AMD64) + else if ((strcmp(isaName, "Avx") == 0) || (strcmp(isaName, "Fma") == 0) || (strcmp(isaName, "Avx2") == 0) + || (strcmp(isaName, "Bmi1") == 0) || (strcmp(isaName, "Bmi2") == 0) || (strcmp(isaName, "Lzcnt") == 0)) { - if ((enclosingClassName == nullptr) || (strcmp(className, "X64") == 0)) + if ((enclosingClassName == nullptr) || fIsPlatformSubArchitecture) { - // If it is the get_IsSupported method for an ISA which requires the VEX - // encoding we want to expand unconditionally. This will force those code + // If it is the get_IsSupported method for an ISA which is intentionally not enabled + // for crossgen, we want to expand unconditionally. This will force those code // paths to be treated as dead code and dropped from the compilation. + // See Zapper::InitializeCompilerFlags // // For all of the other intrinsics in an ISA which requires the VEX encoding // we need to treat them as regular method calls. This is done because RyuJIT @@ -2182,7 +2194,20 @@ DWORD FilterNamedIntrinsicMethodAttribs(ZapInfo* pZapInfo, DWORD attribs, CORINF fTreatAsRegularMethodCall = !fIsGetIsSupportedMethod; } } +#endif // defined(TARGET_X86) || defined(TARGET_AMD64) +#ifdef TARGET_X86 + else if (fIsPlatformSubArchitecture) + { + // For ISAs not handled explicitly above, the IsSupported check will always + // be treated as a regular method call. If we are evaulating a method in the X64 + // namespace, we know it will never be supported on x86, so we can allow the code + // to be treated as dead. We treat all non-IsSupported methods as regular method + // calls so they throw PNSE if used withoug the IsSupported check. + fTreatAsRegularMethodCall = !fIsGetIsSupportedMethod; + } +#endif // TARGET_X86 } +#if defined(TARGET_X86) || defined(TARGET_AMD64) else if (strcmp(namespaceName, "System") == 0) { if ((strcmp(className, "Math") == 0) || (strcmp(className, "MathF") == 0)) @@ -2286,10 +2311,10 @@ void ZapInfo::getCallInfo(CORINFO_RESOLVED_TOKEN * pResolvedToken, #endif #ifdef TARGET_X86 - if (GetCompileInfo()->IsNativeCallableMethod(pResult->hMethod)) + if (GetCompileInfo()->IsUnmanagedCallersOnlyMethod(pResult->hMethod)) { if (m_zapper->m_pOpt->m_verbose) - m_zapper->Warning(W("ReadyToRun: References to methods with NativeCallableAttribute not implemented\n")); + m_zapper->Warning(W("ReadyToRun: References to methods with UnmanagedCallersOnlyAttribute not implemented\n")); ThrowHR(E_NOTIMPL); } #endif // TARGET_X86 diff --git a/src/coreclr/src/zap/zapinfo.h b/src/coreclr/src/zap/zapinfo.h index 921afd41402e11..6079f3291c6ea3 100644 --- a/src/coreclr/src/zap/zapinfo.h +++ b/src/coreclr/src/zap/zapinfo.h @@ -351,9 +351,11 @@ class ZapInfo void * getHelperFtn (CorInfoHelpFunc ftnNum, void** ppIndirection); - void* getTailCallCopyArgsThunk ( - CORINFO_SIG_INFO *pSig, - CorInfoHelperTailCallSpecialHandling flags); + virtual bool getTailCallHelpers( + CORINFO_RESOLVED_TOKEN* callToken, + CORINFO_SIG_INFO* sig, + CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, + CORINFO_TAILCALL_HELPERS* pResult); bool convertPInvokeCalliToCall( CORINFO_RESOLVED_TOKEN * pResolvedToken, diff --git a/src/coreclr/src/zap/zapper.cpp b/src/coreclr/src/zap/zapper.cpp index 422775a349257f..eb79402333483a 100644 --- a/src/coreclr/src/zap/zapper.cpp +++ b/src/coreclr/src/zap/zapper.cpp @@ -1114,7 +1114,7 @@ IMetaDataAssemblyEmit * Zapper::CreateAssemblyEmitter() // Hardwire the metadata version to be the current runtime version so that the ngen image // does not change when the directory runtime is installed in different directory (e.g. v2.0.x86chk vs. v2.0.80826). - BSTRHolder strVersion(SysAllocString(W("v")VER_PRODUCTVERSION_NO_QFE_STR_L)); + BSTRHolder strVersion(SysAllocString(CLR_METADATA_VERSION_L)); VARIANT versionOption; V_VT(&versionOption) = VT_BSTR; V_BSTR(&versionOption) = strVersion; @@ -1180,10 +1180,11 @@ void Zapper::InitializeCompilerFlags(CORCOMPILE_VERSION_INFO * pVersionInfo) m_pOpt->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_FCOMI); } - // .NET Core requires SSE2. #endif // TARGET_X86 #if defined(TARGET_X86) || defined(TARGET_AMD64) + // .NET Core requires SSE2. + m_pOpt->m_compilerFlags.Set(InstructionSet_X86Base); m_pOpt->m_compilerFlags.Set(InstructionSet_SSE); m_pOpt->m_compilerFlags.Set(InstructionSet_SSE2); #endif @@ -1205,8 +1206,6 @@ void Zapper::InitializeCompilerFlags(CORCOMPILE_VERSION_INFO * pVersionInfo) m_pOpt->m_compilerFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_FEATURE_SIMD); #if defined(TARGET_X86) || defined(TARGET_AMD64) - m_pOpt->m_compilerFlags.Set(InstructionSet_SSE); - m_pOpt->m_compilerFlags.Set(InstructionSet_SSE2); m_pOpt->m_compilerFlags.Set(InstructionSet_AES); m_pOpt->m_compilerFlags.Set(InstructionSet_PCLMULQDQ); m_pOpt->m_compilerFlags.Set(InstructionSet_SSE3); @@ -1214,11 +1213,11 @@ void Zapper::InitializeCompilerFlags(CORCOMPILE_VERSION_INFO * pVersionInfo) m_pOpt->m_compilerFlags.Set(InstructionSet_SSE41); m_pOpt->m_compilerFlags.Set(InstructionSet_SSE42); m_pOpt->m_compilerFlags.Set(InstructionSet_POPCNT); - // Leaving out CORJIT_FLAGS::CORJIT_FLAG_USE_AVX, CORJIT_FLAGS::CORJIT_FLAG_USE_FMA - // CORJIT_FLAGS::CORJIT_FLAG_USE_AVX2, CORJIT_FLAGS::CORJIT_FLAG_USE_BMI1, - // CORJIT_FLAGS::CORJIT_FLAG_USE_BMI2 on purpose - these require VEX encodings + // Leaving out InstructionSet_AVX, InstructionSet_FMA, InstructionSet_AVX2, + // InstructionSet_BMI1, InstructionSet_BMI2 on purpose - these require VEX encodings // and the JIT doesn't support generating code for methods with mixed encodings. - m_pOpt->m_compilerFlags.Set(InstructionSet_LZCNT); + // Also leaving out InstructionSet_LZCNT because BSR from InstructionSet_X86Base + // is used as a fallback in CoreLib and doesn't require an IsSupported check. #endif // defined(TARGET_X86) || defined(TARGET_AMD64) } #endif // defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM64) diff --git a/src/coreclr/tests/dir.common.props b/src/coreclr/tests/dir.common.props index 97f640014d0c5d..d31d607d7e9f03 100644 --- a/src/coreclr/tests/dir.common.props +++ b/src/coreclr/tests/dir.common.props @@ -12,7 +12,7 @@ $(TargetOS).$(TargetArchitecture).$(Configuration) - $(MSBuildThisFileDirectory)src + $(MSBuildThisFileDirectory)src $([MSBuild]::MakeRelative($(TestSrcDir), $(MSBuildProjectDirectory)))\$(MSBuildProjectName)\ - + @@ -27,14 +27,21 @@ PublishTestResults=$(_PublishTestResults); RunCrossGen=$(_RunCrossGen); RunCrossGen2=$(_RunCrossGen2); + CompositeBuildMode=$(_CompositeBuildMode); LongRunningGCTests=$(_LongRunningGCTests); GcSimulatorTests=$(_GcSimulatorTests); RunInUnloadableContext=$(_RunInUnloadableContext); TimeoutPerTestCollectionInMinutes=$(_TimeoutPerTestCollectionInMinutes); - TimeoutPerTestInMinutes=$(_TimeoutPerTestInMinutes) + TimeoutPerTestInMinutes=$(_TimeoutPerTestInMinutes); + RuntimeVariant=$(_RuntimeVariant); + BundledNETCoreAppPackageVersion=$(BundledNETCoreAppPackageVersion); + HelixRuntimeRid=$(HelixRuntimeRid) + + + @@ -57,12 +64,25 @@ + + + win-$(TargetArchitecture) + osx-$(TargetArchitecture) + linux-$(TargetArchitecture) + linux-musl-$(TargetArchitecture) + + $([MSBuild]::NormalizeDirectory($(TestWorkingDir))) $(BinDir)Tests\Core_Root\ $(BinDir)Payloads\ SetStressModes_$(Scenario).cmd SetStressModes_$(Scenario).sh + + true + runtime + $(BundledNETCoreAppPackageVersion) + $(HelixRuntimeRid) @@ -129,8 +149,8 @@ - - + + @@ -174,6 +194,7 @@ false false false + $(RuntimeFlavorDisplayName) R2R R2R-CG2 $(TestRunNamePrefix)$(TargetOS) $(TargetArchitecture) $(Configuration) @ @@ -194,6 +215,7 @@ + @@ -209,6 +231,7 @@ + @@ -219,7 +242,6 @@ - @@ -229,12 +251,10 @@ - %CORE_ROOT%\CoreRun.exe %CORE_ROOT%\xunit.console.dll - $CORE_ROOT/corerun $CORE_ROOT/xunit.console.dll @@ -256,12 +276,13 @@ %(PayloadDirectory) - $(CoreRun) $(XUnitRunnerDll) %(XUnitWrapperDlls) $(XUnitRunnerArgs) - $(CoreRun) $(XUnitRunnerDll) %(XUnitWrapperDlls) $(XUnitRunnerArgs) -trait TestGroup=%(TestGroup) + dotnet $(XUnitRunnerDll) %(XUnitWrapperDlls) $(XUnitRunnerArgs) + dotnet $(XUnitRunnerDll) %(XUnitWrapperDlls) $(XUnitRunnerArgs) -trait TestGroup=%(TestGroup) $([System.TimeSpan]::FromMinutes($(TimeoutPerTestCollectionInMinutes))) + diff --git a/src/coreclr/tests/issues.targets b/src/coreclr/tests/issues.targets index eeba754c3ee3aa..27080bf7a72620 100644 --- a/src/coreclr/tests/issues.targets +++ b/src/coreclr/tests/issues.targets @@ -11,6 +11,16 @@ https://github.com/dotnet/runtime/issues/13703 + + + https://github.com/dotnet/runtime/issues/35798 + + + https://github.com/dotnet/runtime/issues/35798 + + + https://github.com/dotnet/runtime/issues/35798 + @@ -69,8 +79,7 @@ 19441;22020 - - + https://github.com/dotnet/runtime/issues/3893 @@ -106,6 +115,12 @@ https://github.com/dotnet/runtime/issues/3893 + + https://github.com/dotnet/runtime/issues/36850 + + + This test is to verify we are running mono, and therefore only makes sense on mono. + @@ -119,9 +134,6 @@ https://github.com/dotnet/runtime/issues/12216 - - Unix does not support tailcall helper - @@ -129,9 +141,6 @@ https://github.com/dotnet/runtime/issues/12166 - - Unix does not support tailcall helper - @@ -139,9 +148,6 @@ needs triage - - needs triage - needs triage @@ -160,9 +166,6 @@ needs triage - - needs triage - needs triage @@ -241,9 +244,6 @@ times out - - times out - Depends on implicit tailcalls to be performed @@ -282,12 +282,6 @@ https://github.com/dotnet/runtime/issues/13241 - - - Unix arm32 does not support tailcall helper - - - Unix arm32 does not support tailcall helper TraceEvent can't parse unaligned floats on arm32 @@ -332,15 +326,12 @@ needs triage + + https://github.com/dotnet/runtime/issues/36418 + https://github.com/dotnet/runtime/issues/12216 - - arm64 does not support tailcall helper - - - arm64 does not support tailcall helper - https://github.com/dotnet/runtime/issues/13355 @@ -360,9 +351,6 @@ WindowsXamlManager and DesktopWindowXamlSource are supported for apps targeting Windows version 10.0.18226.0 and later. - - https://github.com/dotnet/runtime/issues/13296 - @@ -398,9 +386,6 @@ - - https://github.com/dotnet/runtime/issues/34170 - https://github.com/dotnet/runtime/issues/11360 @@ -611,7 +596,7 @@ https://github.com/dotnet/runtime/issues/9270 - Requires helper-based tailcalls + Condition17::Test1 checks that we tail call via helper when security cookie is needed; on arm64 we fast tail call in this case. https://github.com/dotnet/runtime/issues/31729 @@ -619,57 +604,12 @@ https://github.com/dotnet/runtime/issues/31729 - - https://github.com/dotnet/runtime/issues/7430 - extremely memory/time intensive test - - https://github.com/dotnet/runtime/issues/7430 - - - https://github.com/dotnet/runtime/issues/7430 - - - https://github.com/dotnet/runtime/issues/7430 - - - https://github.com/dotnet/runtime/issues/7430 - - - https://github.com/dotnet/runtime/issues/7430 - - - https://github.com/dotnet/runtime/issues/7430 - - - https://github.com/dotnet/runtime/issues/7430 - - - https://github.com/dotnet/runtime/issues/7430 - - - https://github.com/dotnet/runtime/issues/7430 - - - https://github.com/dotnet/runtime/issues/7430 - - - https://github.com/dotnet/runtime/issues/7430 - - - https://github.com/dotnet/runtime/issues/7430 - https://github.com/dotnet/runtime/issues/9270 - - https://github.com/dotnet/runtime/issues/7430 - - - https://github.com/dotnet/runtime/issues/7430 - needs triage @@ -996,6 +936,18 @@ Not compatible with crossgen2 + + https://github.com/dotnet/runtime/issues/7597 + + + https://github.com/dotnet/runtime/issues/34905 + + + https://github.com/dotnet/runtime/issues/35639 + + + https://github.com/dotnet/runtime/issues/35724 + - + + PlatformDetection.IsPreciseGcSupported false on mono + + + PlatformDetection.IsPreciseGcSupported false on mono + + + needs triage + + needs triage @@ -1070,9 +1031,6 @@ https://github.com/dotnet/runtime/issues/34072 - - https://github.com/dotnet/runtime/issues/34372 - https://github.com/dotnet/runtime/issues/34374 @@ -1082,6 +1040,21 @@ needs triage + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + needs triage @@ -1163,6 +1136,9 @@ needs triage + + needs triage + needs triage @@ -1175,6 +1151,9 @@ needs triage + + needs triage + needs triage @@ -1202,6 +1181,12 @@ needs triage + + needs triage + + + needs triage + needs triage @@ -1232,24 +1217,12 @@ needs triage - - https://github.com/dotnet/runtime/issues/34084 - needs triage needs triage - - https://github.com/dotnet/runtime/issues/34084 - - - https://github.com/dotnet/runtime/issues/34084 - - - https://github.com/dotnet/runtime/issues/34084 - needs triage @@ -1301,36 +1274,9 @@ needs triage - - needs triage - - - needs triage - - - needs triage - - - needs triage - - - needs triage - - - needs triage - - - needs triage - https://github.com/dotnet/runtime/issues/34068 - - needs triage - - - needs triage - https://github.com/dotnet/runtime/issues/34068 @@ -1340,9 +1286,6 @@ https://github.com/dotnet/runtime/issues/34068 - - needs triage - https://github.com/dotnet/runtime/issues/34068 @@ -1415,36 +1358,9 @@ needs triage - - needs triage - - - needs triage - https://github.com/dotnet/runtime/issues/34068 - - https://github.com/dotnet/runtime/issues/34391 - - - https://github.com/dotnet/runtime/issues/34380 - - - https://github.com/dotnet/runtime/issues/34084 - - - https://github.com/dotnet/runtime/issues/34084 - - - https://github.com/dotnet/runtime/issues/34378 - - - https://github.com/dotnet/runtime/issues/34377 - - - https://github.com/dotnet/runtime/issues/34381 - https://github.com/dotnet/runtime/issues/34196 @@ -1454,17 +1370,8 @@ https://github.com/dotnet/runtime/issues/34068 - - https://github.com/dotnet/runtime/issues/34379 - - - needs triage - - - needs triage - - - needs triage + + https://github.com/dotnet/runtime/issues/34068 needs triage @@ -1472,12 +1379,6 @@ needs triage - - https://github.com/dotnet/runtime/issues/34386 - - - https://github.com/dotnet/runtime/issues/34387 - needs triage @@ -1496,19 +1397,10 @@ needs triage - - https://github.com/dotnet/runtime/issues/34084 - - - https://github.com/dotnet/runtime/issues/34084 - https://github.com/dotnet/runtime/issues/34084 - - https://github.com/dotnet/runtime/issues/34382 - - + needs triage @@ -1532,6 +1424,9 @@ needs triage + + needs triage + needs triage @@ -1623,7 +1518,6 @@ needs triage - needs triage needs triage @@ -1643,6 +1537,21 @@ https://github.com/dotnet/runtime/issues/34072 + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + needs triage @@ -1701,11 +1610,9 @@ needs triage - needs triage - needs triage @@ -1886,6 +1793,805 @@ needs triage - + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + + + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + needs triage + + + + + needs triage + + + diff --git a/src/coreclr/tests/runtest.cmd b/src/coreclr/tests/runtest.cmd index bfe2925f2b713e..1d8037063d56cd 100644 --- a/src/coreclr/tests/runtest.cmd +++ b/src/coreclr/tests/runtest.cmd @@ -47,14 +47,14 @@ if /i "%1" == "x64" (set __BuildArch=x64&shi if /i "%1" == "x86" (set __BuildArch=x86&shift&goto Arg_Loop) if /i "%1" == "arm" (set __BuildArch=arm&shift&goto Arg_Loop) if /i "%1" == "arm64" (set __BuildArch=arm64&shift&goto Arg_Loop) - + if /i "%1" == "debug" (set __BuildType=Debug&shift&goto Arg_Loop) if /i "%1" == "release" (set __BuildType=Release&shift&goto Arg_Loop) if /i "%1" == "checked" (set __BuildType=Checked&shift&goto Arg_Loop) - + if /i "%1" == "vs2017" (set __VSVersion=%1&shift&goto Arg_Loop) if /i "%1" == "vs2019" (set __VSVersion=%1&shift&goto Arg_Loop) - + if /i "%1" == "TestEnv" (set __TestEnv=%2&shift&shift&goto Arg_Loop) if /i "%1" == "AgainstPackages" (echo error: Remove /AgainstPackages switch&&echo /b 1) if /i "%1" == "sequential" (set __Sequential=1&shift&goto Arg_Loop) @@ -98,7 +98,7 @@ goto CollectMsbuildArgs set CORE_ROOT=%1 echo %__MsgPrefix%CORE_ROOT is initially set to: "%CORE_ROOT%" -shift +shift :ArgsDone :: Done with argument processing. Check argument values for validity. @@ -177,7 +177,7 @@ if defined RunInUnloadableContext ( set __RuntestPyArgs=%__RuntestPyArgs% --run_in_context ) -set NEXTCMD=python3 "%__ProjectDir%\runtest.py" %__RuntestPyArgs% +set NEXTCMD=python "%__ProjectDir%\runtest.py" %__RuntestPyArgs% echo !NEXTCMD! !NEXTCMD! @@ -188,7 +188,7 @@ exit /b %ERRORLEVEL% :: Note: We've disabled node reuse because it causes file locking issues. :: The issue is that we extend the build with our own targets which :: means that that rebuilding cannot successfully delete the task -:: assembly. +:: assembly. set __msbuildCommonArgs=/nologo /nodeReuse:false %__msbuildExtraArgs% /p:Platform=%__MSBuildBuildArch% if not defined __Sequential ( @@ -315,7 +315,7 @@ if %__exitCode% neq 0 ( echo Unable to precompile %2 exit /b 0 ) - + echo %__MsgPrefix%Successfully precompiled %2 exit /b 0 @@ -456,7 +456,7 @@ REM ============================================================================ :ResolveDependencies set __BuildLogRootName=Tests_GenerateRuntimeLayout -call :msbuild "%__ProjectFilesDir%\src\runtest.proj" /p:GenerateRuntimeLayout=true +call :msbuild "%__ProjectFilesDir%\src\runtest.proj" /p:GenerateRuntimeLayout=true if errorlevel 1 ( echo %__MsgPrefix%Test Dependency Resolution Failed exit /b 1 diff --git a/src/coreclr/tests/runtest.py b/src/coreclr/tests/runtest.py index 68444d5d440890..e5ef2b0528ed1f 100755 --- a/src/coreclr/tests/runtest.py +++ b/src/coreclr/tests/runtest.py @@ -934,6 +934,9 @@ def run_tests(args, print("Setting CORE_ROOT=%s" % args.core_root) os.environ["CORE_ROOT"] = args.core_root + # Set __TestDotNetCmd so tests which need to run dotnet can use the repo-local script on dev boxes + os.environ["__TestDotNetCmd"] = args.dotnetcli_script_path + # Set test env script path if it is set. if test_env_script_path is not None: print("Setting __TestEnv=%s" % test_env_script_path) diff --git a/src/coreclr/tests/scripts/run-corefx-tests.py b/src/coreclr/tests/scripts/run-corefx-tests.py index 1ff22dc52b52c7..2207d55aa17c00 100644 --- a/src/coreclr/tests/scripts/run-corefx-tests.py +++ b/src/coreclr/tests/scripts/run-corefx-tests.py @@ -298,7 +298,7 @@ def main(args): # Gather up some arguments to pass to the different build scripts. - common_config_args = '-configuration Release -framework netcoreapp5.0 -os %s -arch %s' % (clr_os, arch) + common_config_args = '-configuration Release -framework net5.0 -os %s -arch %s' % (clr_os, arch) build_args = '-build -restore' build_test_args = '-buildtests /p:ArchiveTests=true' @@ -339,7 +339,7 @@ def main(args): 'artifacts', 'bin', 'testhost', - 'netcoreapp5.0-%s-%s-%s' % (clr_os, 'Release', arch), + 'net5.0-%s-%s-%s' % (clr_os, 'Release', arch), 'shared', 'Microsoft.NETCore.App') diff --git a/src/coreclr/tests/scripts/run-corefx-tests.sh b/src/coreclr/tests/scripts/run-corefx-tests.sh index 03d186f04c9d5e..39a87d03834d23 100755 --- a/src/coreclr/tests/scripts/run-corefx-tests.sh +++ b/src/coreclr/tests/scripts/run-corefx-tests.sh @@ -16,7 +16,7 @@ usage() echo "Flavor/OS/Architecture options:" echo " --configuration Configuration to run (Debug/Release)" echo " default: Debug" - echo " --os OS to run (FreeBSD, Linux, NetBSD or OSX)" + echo " --os OS to run (FreeBSD, Linux, NetBSD, OSX, SunOS)" echo " default: detect current OS" echo " --arch Architecture to run (x64, arm, armel, x86, arm64)" echo " default: detect current architecture" @@ -37,7 +37,7 @@ usage() echo "Runtime Code Coverage options:" echo " --coreclr-coverage Optional argument to get coreclr code coverage reports" echo " --coreclr-objs Location of root of the object directory" - echo " containing the FreeBSD, Linux, NetBSD or OSX coreclr build" + echo " containing the FreeBSD, Linux, NetBSD, OSX or SunOS coreclr build" echo " default: /bin/obj/.x64. Location of root of the directory" echo " containing the coreclr source files" @@ -81,6 +81,10 @@ case $OSName in OS=NetBSD ;; + SunOS) + OS=SunOS + ;; + *) echo "Unsupported OS $OSName detected, configuring as if for Linux" OS=Linux @@ -342,7 +346,7 @@ run_test() coreclr_code_coverage() { - if [ ! "$OS" == "FreeBSD" ] && [ ! "$OS" == "Linux" ] && [ ! "$OS" == "NetBSD" ] && [ ! "$OS" == "OSX" ] ; then + if [ "$OS" != "FreeBSD" ] && [ "$OS" != "Linux" ] && [ "$OS" != "NetBSD" ] && [ "$OS" != "OSX" ] && [ "$OS" != "SunOS" ] ; then echo "error: Code Coverage not supported on $OS" exit 1 fi @@ -501,9 +505,9 @@ then exit 1 fi -if [ ! "$OS" == "FreeBSD" ] && [ ! "$OS" == "Linux" ] && [ ! "$OS" == "NetBSD" ] && [ ! "$OS" == "OSX" ] +if [ "$OS" != "FreeBSD" ] && [ "$OS" != "Linux" ] && [ "$OS" != "NetBSD" ] && [ "$OS" != "OSX" ] && [ "$OS" != "SunOS" ] then - echo "error: OS should be FreeBSD, Linux, NetBSD or OSX" + echo "error: OS should be FreeBSD, Linux, NetBSD, OSX or SunOS" exit 1 fi diff --git a/src/coreclr/tests/scripts/run-gc-reliability-framework.sh b/src/coreclr/tests/scripts/run-gc-reliability-framework.sh index 8f8886a1bc84dd..c136c1561ec9ca 100755 --- a/src/coreclr/tests/scripts/run-gc-reliability-framework.sh +++ b/src/coreclr/tests/scripts/run-gc-reliability-framework.sh @@ -18,6 +18,9 @@ case $OSName in OS=NetBSD ;; + SunOS) + OS=SunOS + ;; *) echo "Unsupported OS $OSName detected, configuring as if for Linux" OS=Linux diff --git a/src/coreclr/tests/setup-stress-dependencies.sh b/src/coreclr/tests/setup-stress-dependencies.sh index 400a78003f6d53..a81c8fff7b2a75 100755 --- a/src/coreclr/tests/setup-stress-dependencies.sh +++ b/src/coreclr/tests/setup-stress-dependencies.sh @@ -82,7 +82,7 @@ if [ -z "$libInstallDir" ]; then exit_with_error 1 fi -if [ "$__BuildArch" == "arm64" ] || [ "$__BuildArch" == "arm" ]; then +if [ "$__BuildArch" = "arm64" ] || [ "$__BuildArch" = "arm" ]; then echo "No runtime dependencies for arm32/arm64" exit $EXIT_CODE_SUCCESS fi diff --git a/src/coreclr/tests/src/CLRTest.CrossGen.targets b/src/coreclr/tests/src/CLRTest.CrossGen.targets index 258f3078b6f92b..0dcc732202f752 100644 --- a/src/coreclr/tests/src/CLRTest.CrossGen.targets +++ b/src/coreclr/tests/src/CLRTest.CrossGen.targets @@ -22,22 +22,18 @@ WARNING: When setting properties based on their current state (for example: $(BashScriptSnippetGen);GetCrossgenBashScript $(BatchScriptSnippetGen);GetCrossgenBatchScript - - - - - - - - - + - + >$__ResponseFile + echo $PWD/IL/*.dll>>$__ResponseFile + else + echo --inputbubble>>$__ResponseFile + echo $PWD/IL/$(MSBuildProjectName).dll>>$__ResponseFile + echo -r:$PWD/IL/*.dll>>$__ResponseFile + fi + + echo -o:$__OutputFile>>$__ResponseFile + echo -r:$CORE_ROOT/System.*.dll>>$__ResponseFile + echo -r:$CORE_ROOT/Microsoft.*.dll>>$__ResponseFile + echo -r:$CORE_ROOT/mscorlib.dll>>$__ResponseFile + echo --targetarch=x64>>$__ResponseFile + echo -O>>$__ResponseFile + + echo "Response file: $__ResponseFile" + cat $__ResponseFile + echo "Running CrossGen2: $__Command" + $__Command + __cg2ExitCode=$? + if [ $__cg2ExitCode -ne 0 ] + then + echo Crossgen2 failed with exitcode: $__cg2ExitCode + ReleaseLock + exit 1 fi + + ReleaseLock fi ]]> @@ -94,7 +132,7 @@ fi - + >!__ResponseFile! + rem In composite mode, treat all dll's in the test folder as rooting inputs + echo !scriptPath!IL\*.dll>>!__ResponseFile! + ) else ( + echo --inputbubble>>!__ResponseFile! + echo !scriptPath!IL\$(MSBuildProjectName).dll>>!__ResponseFile! + echo -r:!scriptPath!IL\*.dll>>!__ResponseFile! + ) + + echo -o:!__OutputFile!>>!__ResponseFile! + echo --targetarch:x64>>!__ResponseFile! + echo -O>>!__ResponseFile! + echo -r:!CORE_ROOT!\System.*.dll>>!__ResponseFile! + echo -r:!CORE_ROOT!\Microsoft.*.dll>>!__ResponseFile! + echo -r:!CORE_ROOT!\mscorlib.dll>>!__ResponseFile! + echo -r:!CORE_ROOT!\netstandard.dll>>!__ResponseFile! + + echo Response file: !__ResponseFile! + type !__ResponseFile! + + echo "!__Command!" + call !__Command! + set CrossGen2Status=!ERRORLEVEL! + call :ReleaseLock + IF NOT !CrossGen2Status!==0 ( + ECHO Crossgen2 failed with exitcode - !CrossGen2Status! + Exit /b 1 + ) ) ]]> diff --git a/src/coreclr/tests/src/Common/CoreCLRTestLibrary/Utilities.cs b/src/coreclr/tests/src/Common/CoreCLRTestLibrary/Utilities.cs index bc2d55bffb08dd..e596d551a45db8 100644 --- a/src/coreclr/tests/src/Common/CoreCLRTestLibrary/Utilities.cs +++ b/src/coreclr/tests/src/Common/CoreCLRTestLibrary/Utilities.cs @@ -73,6 +73,7 @@ public static bool Verbose // Windows 10 October 2018 Update public static bool IsWindows10Version1809OrGreater => IsWindows && GetWindowsVersion() == 10 && GetWindowsMinorVersion() == 0 && GetWindowsBuildNumber() >= 17763; + public static bool IsWindowsIoTCore { get diff --git a/src/coreclr/tests/src/Common/Directory.Build.targets b/src/coreclr/tests/src/Common/Directory.Build.targets index 29fe3f80396494..65ff6bd2759461 100644 --- a/src/coreclr/tests/src/Common/Directory.Build.targets +++ b/src/coreclr/tests/src/Common/Directory.Build.targets @@ -21,17 +21,74 @@ + %(Identity) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + + + + + + + + True + + + + + + + + + + ubuntu.14.04-$(TargetArchitecture) + + + true + true + ubuntu.14.04-$(TargetArchitecture) + + + + + true + true + ubuntu.14.04-$(TargetArchitecture) + + @@ -109,7 +123,7 @@ - true + true C# IL diff --git a/src/coreclr/tests/src/GC/API/GC/AddMemoryPressureTest.cs b/src/coreclr/tests/src/GC/API/GC/AddMemoryPressureTest.cs deleted file mode 100644 index 52b98eb7f0d216..00000000000000 --- a/src/coreclr/tests/src/GC/API/GC/AddMemoryPressureTest.cs +++ /dev/null @@ -1,210 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/* AddMemoryPressureTest - * - * Tests GC.AddMemoryPressure by passing it values that are too small (<=0) and - * values that are too large (>Int32.MaxValue on 32-bit). - * The stress test doubles the pressure (2xInt32.MaxValue), and verifies - * valid behaviour. - */ - - - - -using System; -using System.Diagnostics; -using System.Security; -using System.Runtime.InteropServices; - -public class Dummy -{ - private long _pressure = 0; - private int _numTimes = 0; - - public Dummy(bool heavy) - { - if (heavy) - { - _pressure = Int32.MaxValue; - _numTimes = 2; - for (int i = 0; i < _numTimes; i++) - GC.AddMemoryPressure(_pressure); - } - } - - ~Dummy() - { - for (int i = 0; i < _numTimes; i++) - GC.RemoveMemoryPressure(_pressure); - } -} - -public class AddMemoryPressureTest -{ - public int TestCount = 0; - - private long[] _negValues = { 0, -1, Int32.MinValue - (long)1, Int64.MinValue / (long)2, Int64.MinValue }; - private long[] _largeValues = { Int32.MaxValue + (long)1, Int64.MaxValue }; - - - private AddMemoryPressureTest() - { - } - - - public bool TooSmallTest() - { - TestCount++; - bool retVal = true; - - foreach (long i in _negValues) - { - try - { - GC.AddMemoryPressure(i); - Console.WriteLine("Failure at TooSmallTest: {0}", i); - retVal = false; - break; - } - catch (ArgumentOutOfRangeException) - { - } - catch (Exception e) - { - Console.WriteLine(e.Message); - Console.WriteLine("Failure at TooSmallTest: {0}", i); - retVal = false; - break; - } - } - - if (retVal) - Console.WriteLine("TooSmallTest Passed"); - return retVal; - } - - - public bool TooLargeTest() - { - TestCount++; - - bool retVal = true; - - foreach (long i in _largeValues) - { - try - { - GC.AddMemoryPressure(i); - // this should not throw exception on 64-bit - if (IntPtr.Size == Marshal.SizeOf(new Int32())) - { - Console.WriteLine("Failure at LargeValueTest: {0}", i); - retVal = false; - break; - } - else - { - GC.RemoveMemoryPressure(i); - } - } - catch (ArgumentOutOfRangeException) - { - // this should not throw exception on 64-bit - if (IntPtr.Size == Marshal.SizeOf(new Int64())) - { - Console.WriteLine("Failure at LargeValueTest: {0}", i); - retVal = false; - break; - } - } - catch (Exception e) - { - Console.WriteLine(e.Message); - retVal = false; - break; - } - } - - if (retVal) - Console.WriteLine("TooLargeTest Passed"); - return retVal; - } - - - public bool StressTest() - { - TestCount++; - - Console.WriteLine("StressTest Started..."); - - int gcCount1 = createDummies(true); - - - int gcCount2 = createDummies(false); - - Console.WriteLine("{0} {1}", gcCount1, gcCount2); - if (gcCount1 > gcCount2) - { - Console.WriteLine("StressTest Passed"); - Console.WriteLine(); - return true; - } - - Console.WriteLine("StressTest Failed"); - - Console.WriteLine(); - return false; - } - - - private int createDummies(bool heavy) - { - int gcCount = GC.CollectionCount(0); - - for (int i = 0; i < 100; i++) - { - Dummy dummy = new Dummy(heavy); - int gen = GC.GetGeneration(dummy); - if (gen != 0) - { - Console.WriteLine("Warning: newly-allocated dummy ended up in gen {0}", gen); - } - } - - return GC.CollectionCount(0) - gcCount; - } - - - public bool RunTest() - { - int passCount = 0; - - if (TooSmallTest()) - passCount++; - - if (TooLargeTest()) - passCount++; - - if (StressTest()) - passCount++; - - return (passCount == TestCount); - } - - - public static int Main() - { - AddMemoryPressureTest test = new AddMemoryPressureTest(); - - if (test.RunTest()) - { - Console.WriteLine("Test Passed"); - return 100; - } - - Console.WriteLine("Test Failed"); - return 1; - } -} diff --git a/src/coreclr/tests/src/GC/API/GC/AddMemoryPressureTest.csproj b/src/coreclr/tests/src/GC/API/GC/AddMemoryPressureTest.csproj deleted file mode 100644 index 108d33023306e6..00000000000000 --- a/src/coreclr/tests/src/GC/API/GC/AddMemoryPressureTest.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - Exe - - - - PdbOnly - true - - - - - diff --git a/src/coreclr/tests/src/GC/API/GC/RemoveMemoryPressureTest.cs b/src/coreclr/tests/src/GC/API/GC/RemoveMemoryPressureTest.cs deleted file mode 100644 index e288efb6f8c07f..00000000000000 --- a/src/coreclr/tests/src/GC/API/GC/RemoveMemoryPressureTest.cs +++ /dev/null @@ -1,132 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/* RemoveMemoryPressureTest - * - * Tests GC.RemoveMemoryPressure by passing it values that are too small (<=0) and - * values that are too large (>Int32.MaxValue on 32-bit). - */ - - -using System; -using System.Diagnostics; -using System.Security; -using System.Runtime.InteropServices; - -public class RemoveMemoryPressureTest -{ - public int TestCount = 0; - - private long[] _negValues = { 0, -1, Int32.MinValue - (long)1, Int64.MinValue / (long)2, Int64.MinValue }; - private long[] _largeValues = { Int32.MaxValue + (long)1, Int64.MaxValue }; - - - private RemoveMemoryPressureTest() - { - } - - - public bool TooSmallTest() - { - TestCount++; - bool retVal = true; - - foreach (long i in _negValues) - { - try - { - GC.RemoveMemoryPressure(i); - Console.WriteLine("Failure at TooSmallTest: {0}", i); - retVal = false; - break; - } - catch (ArgumentOutOfRangeException) - { - } - catch (Exception e) - { - Console.WriteLine(e.Message); - Console.WriteLine("Failure at TooSmallTest: {0}", i); - retVal = false; - break; - } - } - - if (retVal) - Console.WriteLine("TooSmallTest Passed"); - return retVal; - } - - - public bool TooLargeTest() - { - TestCount++; - - bool retVal = true; - - foreach (long i in _largeValues) - { - try - { - GC.RemoveMemoryPressure(i); - // this should throw exception on 32-bit - if (IntPtr.Size == Marshal.SizeOf(new Int32())) - { - Console.WriteLine("Failure at LargeValueTest: {0}", i); - retVal = false; - break; - } - } - catch (ArgumentOutOfRangeException) - { - // this should not throw exception on 64-bit - if (IntPtr.Size == Marshal.SizeOf(new Int64())) - { - Console.WriteLine("Failure at LargeValueTest: {0}", i); - retVal = false; - break; - } - } - catch (Exception e) - { - Console.WriteLine(e.Message); - retVal = false; - break; - } - } - - if (retVal) - Console.WriteLine("TooLargeTest Passed"); - return retVal; - } - - - public bool RunTest() - { - int passCount = 0; - - if (TooSmallTest()) - passCount++; - - if (TooLargeTest()) - passCount++; - - return (passCount == TestCount); - } - - - public static int Main() - { - RemoveMemoryPressureTest test = new RemoveMemoryPressureTest(); - - if (test.RunTest()) - { - Console.WriteLine("Test Passed"); - return 100; - } - - Console.WriteLine("Test Failed"); - return 1; - } -} diff --git a/src/coreclr/tests/src/GC/API/GC/RemoveMemoryPressureTest.csproj b/src/coreclr/tests/src/GC/API/GC/RemoveMemoryPressureTest.csproj deleted file mode 100644 index bb01dcdf950c74..00000000000000 --- a/src/coreclr/tests/src/GC/API/GC/RemoveMemoryPressureTest.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - Exe - - - - PdbOnly - - - - - diff --git a/src/coreclr/tests/src/Interop/CMakeLists.txt b/src/coreclr/tests/src/Interop/CMakeLists.txt index 9fcec4b3319f89..778d9ab3bded8c 100644 --- a/src/coreclr/tests/src/Interop/CMakeLists.txt +++ b/src/coreclr/tests/src/Interop/CMakeLists.txt @@ -35,7 +35,7 @@ add_subdirectory(PInvoke/Generics) add_subdirectory(PInvoke/AsAny) add_subdirectory(PInvoke/SafeHandles) add_subdirectory(PInvoke/Vector2_3_4) -add_subdirectory(NativeCallable) +add_subdirectory(UnmanagedCallersOnly) add_subdirectory(PrimitiveMarshalling/Bool) add_subdirectory(PrimitiveMarshalling/UIntPtr) add_subdirectory(ArrayMarshalling/BoolArray) @@ -79,7 +79,9 @@ if(CLR_CMAKE_TARGET_WIN32) add_subdirectory(COM/NativeClients/Licensing) add_subdirectory(COM/NativeClients/DefaultInterfaces) add_subdirectory(COM/NativeClients/Dispatch) + add_subdirectory(COM/NativeClients/Events) add_subdirectory(COM/ComWrappers/MockReferenceTrackerRuntime) + add_subdirectory(COM/ComWrappers/WeakReference) add_subdirectory(WinRT/NativeComponent) # IJW isn't supported on ARM64 diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/API/ComWrappersTests.csproj b/src/coreclr/tests/src/Interop/COM/ComWrappers/API/ComWrappersTests.csproj index 83acfa1f6fd5eb..df719b7db8cd7e 100644 --- a/src/coreclr/tests/src/Interop/COM/ComWrappers/API/ComWrappersTests.csproj +++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/API/ComWrappersTests.csproj @@ -3,6 +3,8 @@ Exe true + + true true true diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/Common.cs b/src/coreclr/tests/src/Interop/COM/ComWrappers/Common.cs index 2f322018f0f800..0e75049200c9b5 100644 --- a/src/coreclr/tests/src/Interop/COM/ComWrappers/Common.cs +++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/Common.cs @@ -11,6 +11,7 @@ namespace ComWrappersTests.Common // Managed object with native wrapper definition. // [Guid("447BB9ED-DA48-4ABC-8963-5BB5C3E0AA09")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface ITest { void SetValue(int i); diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstance.Marshalling.cs b/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstance.Marshalling.cs new file mode 100644 index 00000000000000..b2315ff4e6eaaa --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstance.Marshalling.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace ComWrappersTests.GlobalInstance +{ + using System; + + using ComWrappersTests.Common; + using TestLibrary; + + partial class Program + { + private static void ValidateNotRegisteredForTrackerSupport() + { + Console.WriteLine($"Running {nameof(ValidateNotRegisteredForTrackerSupport)}..."); + + int hr = MockReferenceTrackerRuntime.Trigger_NotifyEndOfReferenceTrackingOnThread(); + Assert.AreNotEqual(GlobalComWrappers.ReleaseObjectsCallAck, hr); + } + + static int Main(string[] doNotUse) + { + try + { + // The first test registers a global ComWrappers instance for marshalling + // Subsequents tests assume the global instance has already been registered. + ValidateRegisterForMarshalling(); + + ValidateMarshalAPIs(validateUseRegistered: true); + ValidateMarshalAPIs(validateUseRegistered: false); + + ValidatePInvokes(validateUseRegistered: true); + ValidatePInvokes(validateUseRegistered: false); + + ValidateComActivation(validateUseRegistered: true); + ValidateComActivation(validateUseRegistered: false); + + ValidateNotRegisteredForTrackerSupport(); + + // Register a global ComWrappers instance for tracker support + ValidateRegisterForTrackerSupport(); + + ValidateNotifyEndOfReferenceTrackingOnThread(); + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + + return 100; + } + } +} + diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstance.TrackerSupport.cs b/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstance.TrackerSupport.cs new file mode 100644 index 00000000000000..4d4f1c6e93474a --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstance.TrackerSupport.cs @@ -0,0 +1,68 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace ComWrappersTests.GlobalInstance +{ + using System; + using System.Runtime.InteropServices; + + using ComWrappersTests.Common; + using TestLibrary; + + partial class Program + { + private static void ValidateNotRegisteredForMarshalling() + { + Console.WriteLine($"Running {nameof(ValidateNotRegisteredForMarshalling)}..."); + + var testObj = new Test(); + IntPtr comWrapper1 = Marshal.GetIUnknownForObject(testObj); + Assert.IsNull(GlobalComWrappers.Instance.LastComputeVtablesObject, "ComWrappers instance should not have been called"); + + IntPtr trackerObjRaw = MockReferenceTrackerRuntime.CreateTrackerObject(); + object objWrapper = Marshal.GetObjectForIUnknown(trackerObjRaw); + Assert.IsFalse(objWrapper is FakeWrapper, $"ComWrappers instance should not have been called"); + } + + static int Main(string[] doNotUse) + { + try + { + // The first test registers a global ComWrappers instance for tracker support. + // Subsequents tests assume the global instance has already been registered. + ValidateRegisterForTrackerSupport(); + + ValidateNotRegisteredForMarshalling(); + + IntPtr trackerObjRaw = MockReferenceTrackerRuntime.CreateTrackerObject(); + var trackerObj = GlobalComWrappers.Instance.GetOrCreateObjectForComInstance(trackerObjRaw, CreateObjectFlags.TrackerObject); + Marshal.Release(trackerObjRaw); + + ValidateNotifyEndOfReferenceTrackingOnThread(); + + // Register a global ComWrappers instance for marshalling. + ValidateRegisterForMarshalling(); + + ValidateMarshalAPIs(validateUseRegistered: true); + ValidateMarshalAPIs(validateUseRegistered: false); + + ValidatePInvokes(validateUseRegistered: true); + ValidatePInvokes(validateUseRegistered: false); + + ValidateComActivation(validateUseRegistered: true); + ValidateComActivation(validateUseRegistered: false); + + ValidateNotifyEndOfReferenceTrackingOnThread(); + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + + return 100; + } + } +} + diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstance.cs b/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstance.cs new file mode 100644 index 00000000000000..b362bc641b0376 --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstance.cs @@ -0,0 +1,448 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace ComWrappersTests.GlobalInstance +{ + using System; + using System.Collections; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + using ComWrappersTests.Common; + using TestLibrary; + + partial class Program + { + struct MarshalInterface + { + [DllImport(nameof(MockReferenceTrackerRuntime), EntryPoint=nameof(MockReferenceTrackerRuntime.CreateTrackerObject))] + [return: MarshalAs(UnmanagedType.IUnknown)] + extern public static object CreateTrackerObjectAsIUnknown(); + + [DllImport(nameof(MockReferenceTrackerRuntime), EntryPoint=nameof(MockReferenceTrackerRuntime.CreateTrackerObject))] + [return: MarshalAs(UnmanagedType.Interface)] + extern public static FakeWrapper CreateTrackerObjectAsInterface(); + + [DllImport(nameof(MockReferenceTrackerRuntime), EntryPoint = nameof(MockReferenceTrackerRuntime.CreateTrackerObject))] + [return: MarshalAs(UnmanagedType.Interface)] + extern public static Test CreateTrackerObjectWrongType(); + + [DllImport(nameof(MockReferenceTrackerRuntime))] + extern public static int UpdateTestObjectAsIUnknown( + [MarshalAs(UnmanagedType.IUnknown)] object testObj, + int i, + [MarshalAs(UnmanagedType.IUnknown)] out object ret); + + [DllImport(nameof(MockReferenceTrackerRuntime))] + extern public static int UpdateTestObjectAsIDispatch( + [MarshalAs(UnmanagedType.IDispatch)] object testObj, + int i, + [MarshalAs(UnmanagedType.IDispatch)] out object ret); + + [DllImport(nameof(MockReferenceTrackerRuntime))] + extern public static int UpdateTestObjectAsIInspectable( + [MarshalAs(UnmanagedType.IInspectable)] object testObj, + int i, + [MarshalAs(UnmanagedType.IInspectable)] out object ret); + + [DllImport(nameof(MockReferenceTrackerRuntime))] + extern public static int UpdateTestObjectAsInterface( + [MarshalAs(UnmanagedType.Interface)] ITest testObj, + int i, + [Out, MarshalAs(UnmanagedType.Interface)] out ITest ret); + } + + private const string ManagedServerTypeName = "ConsumeNETServerTesting"; + + private const string IID_IDISPATCH = "00020400-0000-0000-C000-000000000046"; + private const string IID_IINSPECTABLE = "AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90"; + class TestEx : Test + { + public readonly Guid[] Interfaces; + public TestEx(params string[] iids) + { + Interfaces = new Guid[iids.Length]; + for (int i = 0; i < iids.Length; i++) + Interfaces[i] = Guid.Parse(iids[i]); + } + } + + class FakeWrapper + { + private delegate int _AddRef(IntPtr This); + private delegate int _Release(IntPtr This); + private struct IUnknownWrapperVtbl + { + public IntPtr QueryInterface; + public _AddRef AddRef; + public _Release Release; + } + + private readonly IntPtr wrappedInstance; + + private readonly IUnknownWrapperVtbl vtable; + + public FakeWrapper(IntPtr instance) + { + this.wrappedInstance = instance; + var inst = Marshal.PtrToStructure(instance); + this.vtable = Marshal.PtrToStructure(inst.Vtbl); + } + + ~FakeWrapper() + { + if (this.wrappedInstance != IntPtr.Zero) + { + this.vtable.Release(this.wrappedInstance); + } + } + } + + class GlobalComWrappers : ComWrappers + { + public static GlobalComWrappers Instance = new GlobalComWrappers(); + + public bool ReturnInvalid { get; set; } + + public object LastComputeVtablesObject { get; private set; } = null; + + protected unsafe override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) + { + LastComputeVtablesObject = obj; + + if (ReturnInvalid) + { + count = -1; + return null; + } + + if (obj is Test) + { + return ComputeVtablesForTestObject((Test)obj, out count); + } + else if (string.Equals(ManagedServerTypeName, obj.GetType().Name)) + { + IntPtr fpQueryInteface = default; + IntPtr fpAddRef = default; + IntPtr fpRelease = default; + ComWrappers.GetIUnknownImpl(out fpQueryInteface, out fpAddRef, out fpRelease); + + var vtbl = new IUnknownVtbl() + { + QueryInterface = fpQueryInteface, + AddRef = fpAddRef, + Release = fpRelease + }; + var vtblRaw = RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(IUnknownVtbl), sizeof(IUnknownVtbl)); + Marshal.StructureToPtr(vtbl, vtblRaw, false); + + // Including interfaces to allow QI, but not actually returning a valid vtable, since it is not needed for the tests here. + var entryRaw = (ComInterfaceEntry*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(IUnknownVtbl), sizeof(ComInterfaceEntry)); + entryRaw[0].IID = typeof(Server.Contract.IConsumeNETServer).GUID; + entryRaw[0].Vtable = vtblRaw; + + count = 1; + return entryRaw; + } + + count = -1; + return null; + } + + protected override object CreateObject(IntPtr externalComObject, CreateObjectFlags flag) + { + if (ReturnInvalid) + return null; + + Guid[] iids = { + typeof(ITrackerObject).GUID, + typeof(ITest).GUID, + typeof(Server.Contract.IDispatchTesting).GUID, + typeof(Server.Contract.IConsumeNETServer).GUID + }; + + for (var i = 0; i < iids.Length; i++) + { + var iid = iids[i]; + IntPtr comObject; + int hr = Marshal.QueryInterface(externalComObject, ref iid, out comObject); + if (hr == 0) + return new FakeWrapper(comObject); + } + + return null; + } + + public const int ReleaseObjectsCallAck = unchecked((int)-1); + + protected override void ReleaseObjects(IEnumerable objects) + { + throw new Exception() { HResult = ReleaseObjectsCallAck }; + } + + private unsafe ComInterfaceEntry* ComputeVtablesForTestObject(Test obj, out int count) + { + IntPtr fpQueryInteface = default; + IntPtr fpAddRef = default; + IntPtr fpRelease = default; + ComWrappers.GetIUnknownImpl(out fpQueryInteface, out fpAddRef, out fpRelease); + + var iUnknownVtbl = new IUnknownVtbl() + { + QueryInterface = fpQueryInteface, + AddRef = fpAddRef, + Release = fpRelease + }; + + var vtbl = new ITestVtbl() + { + IUnknownImpl = iUnknownVtbl, + SetValue = Marshal.GetFunctionPointerForDelegate(ITestVtbl.pSetValue) + }; + var vtblRaw = RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(ITestVtbl), sizeof(ITestVtbl)); + Marshal.StructureToPtr(vtbl, vtblRaw, false); + + int countLocal = obj is TestEx ? ((TestEx)obj).Interfaces.Length + 1 : 1; + var entryRaw = (ComInterfaceEntry*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(ITestVtbl), sizeof(ComInterfaceEntry) * countLocal); + entryRaw[0].IID = typeof(ITest).GUID; + entryRaw[0].Vtable = vtblRaw; + + if (obj is TestEx) + { + var iUnknownVtblRaw = RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(IUnknownVtbl), sizeof(IUnknownVtbl)); + Marshal.StructureToPtr(iUnknownVtbl, iUnknownVtblRaw, false); + + var testEx = (TestEx)obj; + for (int i = 1; i < testEx.Interfaces.Length + 1; i++) + { + // Including interfaces to allow QI, but not actually returning a valid vtable, since it is not needed for the tests here. + entryRaw[i].IID = testEx.Interfaces[i - 1]; + entryRaw[i].Vtable = iUnknownVtblRaw; + } + } + + count = countLocal; + return entryRaw; + } + } + + private static void ValidateRegisterForMarshalling() + { + Console.WriteLine($"Running {nameof(ValidateRegisterForMarshalling)}..."); + + var wrappers1 = GlobalComWrappers.Instance; + ComWrappers.RegisterForMarshalling(wrappers1); + Assert.Throws( + () => + { + ComWrappers.RegisterForMarshalling(wrappers1); + }, "Should not be able to re-register for global ComWrappers"); + + var wrappers2 = new GlobalComWrappers(); + Assert.Throws( + () => + { + ComWrappers.RegisterForMarshalling(wrappers2); + }, "Should not be able to reset for global ComWrappers"); + } + + private static void ValidateRegisterForTrackerSupport() + { + Console.WriteLine($"Running {nameof(ValidateRegisterForTrackerSupport)}..."); + + var wrappers1 = GlobalComWrappers.Instance; + ComWrappers.RegisterForTrackerSupport(wrappers1); + Assert.Throws( + () => + { + ComWrappers.RegisterForTrackerSupport(wrappers1); + }, "Should not be able to re-register for global ComWrappers"); + + var wrappers2 = new GlobalComWrappers(); + Assert.Throws( + () => + { + ComWrappers.RegisterForTrackerSupport(wrappers2); + }, "Should not be able to reset for global ComWrappers"); + } + + private static void ValidateMarshalAPIs(bool validateUseRegistered) + { + string scenario = validateUseRegistered ? "use registered wrapper" : "fall back to runtime"; + Console.WriteLine($"Running {nameof(ValidateMarshalAPIs)}: {scenario}..."); + + GlobalComWrappers registeredWrapper = GlobalComWrappers.Instance; + registeredWrapper.ReturnInvalid = !validateUseRegistered; + + Console.WriteLine($" -- Validate Marshal.GetIUnknownForObject..."); + + var testObj = new Test(); + IntPtr comWrapper1 = Marshal.GetIUnknownForObject(testObj); + Assert.AreNotEqual(IntPtr.Zero, comWrapper1); + Assert.AreEqual(testObj, registeredWrapper.LastComputeVtablesObject, "Registered ComWrappers instance should have been called"); + + IntPtr comWrapper2 = Marshal.GetIUnknownForObject(testObj); + Assert.AreEqual(comWrapper1, comWrapper2); + + Marshal.Release(comWrapper1); + Marshal.Release(comWrapper2); + + Console.WriteLine($" -- Validate Marshal.GetIDispatchForObject..."); + + Assert.Throws(() => Marshal.GetIDispatchForObject(testObj)); + + if (validateUseRegistered) + { + var dispatchObj = new TestEx(IID_IDISPATCH); + IntPtr dispatchWrapper = Marshal.GetIDispatchForObject(dispatchObj); + Assert.AreNotEqual(IntPtr.Zero, dispatchWrapper); + Assert.AreEqual(dispatchObj, registeredWrapper.LastComputeVtablesObject, "Registered ComWrappers instance should have been called"); + + Console.WriteLine($" -- Validate Marshal.GetIDispatchForObject != Marshal.GetIUnknownForObject..."); + IntPtr unknownWrapper = Marshal.GetIUnknownForObject(dispatchObj); + Assert.AreNotEqual(IntPtr.Zero, unknownWrapper); + Assert.AreNotEqual(unknownWrapper, dispatchWrapper); + } + + Console.WriteLine($" -- Validate Marshal.GetObjectForIUnknown..."); + + IntPtr trackerObjRaw = MockReferenceTrackerRuntime.CreateTrackerObject(); + object objWrapper1 = Marshal.GetObjectForIUnknown(trackerObjRaw); + Assert.AreEqual(validateUseRegistered, objWrapper1 is FakeWrapper, $"GetObjectForIUnknown should{(validateUseRegistered ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance"); + object objWrapper2 = Marshal.GetObjectForIUnknown(trackerObjRaw); + Assert.AreEqual(objWrapper1, objWrapper2); + + Console.WriteLine($" -- Validate Marshal.GetUniqueObjectForIUnknown..."); + + object objWrapper3 = Marshal.GetUniqueObjectForIUnknown(trackerObjRaw); + Assert.AreEqual(validateUseRegistered, objWrapper3 is FakeWrapper, $"GetObjectForIUnknown should{(validateUseRegistered ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance"); + + Assert.AreNotEqual(objWrapper1, objWrapper3); + + Marshal.Release(trackerObjRaw); + } + + private static void ValidatePInvokes(bool validateUseRegistered) + { + string scenario = validateUseRegistered ? "use registered wrapper" : "fall back to runtime"; + Console.WriteLine($"Running {nameof(ValidatePInvokes)}: {scenario}..."); + + GlobalComWrappers.Instance.ReturnInvalid = !validateUseRegistered; + + Console.WriteLine($" -- Validate MarshalAs IUnknown..."); + ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsIUnknown, shouldSucceed: validateUseRegistered); + object obj = MarshalInterface.CreateTrackerObjectAsIUnknown(); + Assert.AreEqual(validateUseRegistered, obj is FakeWrapper, $"Should{(validateUseRegistered ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance"); + + if (validateUseRegistered) + { + Console.WriteLine($" -- Validate MarshalAs IDispatch..."); + ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsIDispatch, shouldSucceed: true, new TestEx(IID_IDISPATCH)); + + Console.WriteLine($" -- Validate MarshalAs IInspectable..."); + ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsIInspectable, shouldSucceed: true, new TestEx(IID_IINSPECTABLE)); + } + + Console.WriteLine($" -- Validate MarshalAs Interface..."); + ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsInterface, shouldSucceed: true); + + if (validateUseRegistered) + { + Assert.Throws(() => MarshalInterface.CreateTrackerObjectWrongType()); + + FakeWrapper wrapper = MarshalInterface.CreateTrackerObjectAsInterface(); + Assert.IsNotNull(wrapper, $"Should have returned {nameof(FakeWrapper)} instance"); + } + } + + private delegate int UpdateTestObject(T testObj, int i, out T ret) where T : class; + private static void ValidateInterfaceMarshaler(UpdateTestObject func, bool shouldSucceed, Test testObj = null) where T : class + { + const int E_NOINTERFACE = unchecked((int)0x80004002); + int value = 10; + + if (testObj == null) + testObj = new Test(); + + T retObj; + int hr = func(testObj as T, value, out retObj); + Assert.AreEqual(testObj, GlobalComWrappers.Instance.LastComputeVtablesObject, "Registered ComWrappers instance should have been called"); + if (shouldSucceed) + { + Assert.IsTrue(retObj is Test); + Assert.AreEqual(value, testObj.GetValue()); + Assert.AreEqual(testObj, retObj); + } + else + { + Assert.AreEqual(E_NOINTERFACE, hr); + } + } + + private static void ValidateComActivation(bool validateUseRegistered) + { + string scenario = validateUseRegistered ? "use registered wrapper" : "fall back to runtime"; + Console.WriteLine($"Running {nameof(ValidateComActivation)}: {scenario}..."); + GlobalComWrappers.Instance.ReturnInvalid = !validateUseRegistered; + + Console.WriteLine($" -- Validate native server..."); + ValidateNativeServerActivation(); + + Console.WriteLine($" -- Validate managed server..."); + ValidateManagedServerActivation(); + } + + private static void ValidateNativeServerActivation() + { + bool returnValid = !GlobalComWrappers.Instance.ReturnInvalid; + + Type t= Type.GetTypeFromCLSID(Guid.Parse(Server.Contract.Guids.DispatchTesting)); + var server = Activator.CreateInstance(t); + Assert.AreEqual(returnValid, server is FakeWrapper, $"Should{(returnValid ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance"); + + IntPtr ptr = Marshal.GetIUnknownForObject(server); + var obj = Marshal.GetObjectForIUnknown(ptr); + Assert.AreEqual(server, obj); + } + + private static void ValidateManagedServerActivation() + { + bool returnValid = !GlobalComWrappers.Instance.ReturnInvalid; + + // Initialize CoreShim and hostpolicymock + HostPolicyMock.Initialize(Environment.CurrentDirectory, null); + Environment.SetEnvironmentVariable("CORESHIM_COMACT_ASSEMBLYNAME", "NETServer"); + Environment.SetEnvironmentVariable("CORESHIM_COMACT_TYPENAME", ManagedServerTypeName); + + using (HostPolicyMock.Mock_corehost_resolve_component_dependencies(0, string.Empty, string.Empty, string.Empty)) + { + Type t = Type.GetTypeFromCLSID(Guid.Parse(Server.Contract.Guids.ConsumeNETServerTesting)); + var server = Activator.CreateInstance(t); + Assert.AreEqual(returnValid, server is FakeWrapper, $"Should{(returnValid ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance"); + object serverUnwrapped = GlobalComWrappers.Instance.LastComputeVtablesObject; + Assert.AreEqual(ManagedServerTypeName, serverUnwrapped.GetType().Name); + + IntPtr ptr = Marshal.GetIUnknownForObject(server); + var obj = Marshal.GetObjectForIUnknown(ptr); + Assert.AreEqual(server, obj); + Assert.AreEqual(returnValid, obj is FakeWrapper, $"Should{(returnValid ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance"); + serverUnwrapped.GetType().GetMethod("NotEqualByRCW").Invoke(serverUnwrapped, new object[] { obj }); + } + } + + private static void ValidateNotifyEndOfReferenceTrackingOnThread() + { + Console.WriteLine($"Running {nameof(ValidateNotifyEndOfReferenceTrackingOnThread)}..."); + + // Make global instance return invalid object so that the Exception thrown by + // GlobalComWrappers.ReleaseObjects is marshalled using the built-in system. + GlobalComWrappers.Instance.ReturnInvalid = true; + + // Trigger the thread lifetime end API and verify the callback occurs. + int hr = MockReferenceTrackerRuntime.Trigger_NotifyEndOfReferenceTrackingOnThread(); + Assert.AreEqual(GlobalComWrappers.ReleaseObjectsCallAck, hr); + } + } +} + diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstanceMarshallingTests.csproj b/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstanceMarshallingTests.csproj new file mode 100644 index 00000000000000..c4dbbd85373300 --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstanceMarshallingTests.csproj @@ -0,0 +1,38 @@ + + + Exe + App.manifest + true + true + + BuildOnly + + true + true + + true + true + + + + + + + + + + + + + + false + Content + Always + + + + + PreserveNewest + + + diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstanceTests.csproj b/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstanceTests.csproj deleted file mode 100644 index 1e5e14f330e2ec..00000000000000 --- a/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstanceTests.csproj +++ /dev/null @@ -1,37 +0,0 @@ - - - Exe - App.manifest - true - true - - BuildOnly - - true - true - - true - true - - - - - - - - - - - - - false - Content - Always - - - - - PreserveNewest - - - diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstanceTrackerSupportTests.csproj b/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstanceTrackerSupportTests.csproj new file mode 100644 index 00000000000000..4742bf4b547f3c --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstanceTrackerSupportTests.csproj @@ -0,0 +1,38 @@ + + + Exe + App.manifest + true + true + + BuildOnly + + true + true + + true + true + + + + + + + + + + + + + + false + Content + Always + + + + + PreserveNewest + + + diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/Program.cs b/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/Program.cs deleted file mode 100644 index 168c1230ffbf34..00000000000000 --- a/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/Program.cs +++ /dev/null @@ -1,451 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace ComWrappersTests.GlobalInstance -{ - using System; - using System.Collections; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - - using ComWrappersTests.Common; - using TestLibrary; - - class Program - { - struct MarshalInterface - { - [DllImport(nameof(MockReferenceTrackerRuntime), EntryPoint=nameof(MockReferenceTrackerRuntime.CreateTrackerObject))] - [return: MarshalAs(UnmanagedType.IUnknown)] - extern public static object CreateTrackerObjectAsIUnknown(); - - [DllImport(nameof(MockReferenceTrackerRuntime), EntryPoint=nameof(MockReferenceTrackerRuntime.CreateTrackerObject))] - [return: MarshalAs(UnmanagedType.Interface)] - extern public static FakeWrapper CreateTrackerObjectAsInterface(); - - [DllImport(nameof(MockReferenceTrackerRuntime), EntryPoint = nameof(MockReferenceTrackerRuntime.CreateTrackerObject))] - [return: MarshalAs(UnmanagedType.Interface)] - extern public static Test CreateTrackerObjectWrongType(); - - [DllImport(nameof(MockReferenceTrackerRuntime))] - extern public static int UpdateTestObjectAsIUnknown( - [MarshalAs(UnmanagedType.IUnknown)] object testObj, - int i, - [MarshalAs(UnmanagedType.IUnknown)] out object ret); - - [DllImport(nameof(MockReferenceTrackerRuntime))] - extern public static int UpdateTestObjectAsIDispatch( - [MarshalAs(UnmanagedType.IDispatch)] object testObj, - int i, - [MarshalAs(UnmanagedType.IDispatch)] out object ret); - - [DllImport(nameof(MockReferenceTrackerRuntime))] - extern public static int UpdateTestObjectAsIInspectable( - [MarshalAs(UnmanagedType.IInspectable)] object testObj, - int i, - [MarshalAs(UnmanagedType.IInspectable)] out object ret); - - [DllImport(nameof(MockReferenceTrackerRuntime))] - extern public static int UpdateTestObjectAsInterface( - [MarshalAs(UnmanagedType.Interface)] Test testObj, - int i, - [Out, MarshalAs(UnmanagedType.Interface)] out Test ret); - } - - private const string ManagedServerTypeName = "ConsumeNETServerTesting"; - - private const string IID_IDISPATCH = "00020400-0000-0000-C000-000000000046"; - private const string IID_IINSPECTABLE = "AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90"; - class TestEx : Test - { - public readonly Guid[] Interfaces; - public TestEx(params string[] iids) - { - Interfaces = new Guid[iids.Length]; - for (int i = 0; i < iids.Length; i++) - Interfaces[i] = Guid.Parse(iids[i]); - } - } - - class FakeWrapper - { - private delegate int _AddRef(IntPtr This); - private delegate int _Release(IntPtr This); - private struct IUnknownWrapperVtbl - { - public IntPtr QueryInterface; - public _AddRef AddRef; - public _Release Release; - } - - private readonly IntPtr wrappedInstance; - - private readonly IUnknownWrapperVtbl vtable; - - public FakeWrapper(IntPtr instance) - { - this.wrappedInstance = instance; - var inst = Marshal.PtrToStructure(instance); - this.vtable = Marshal.PtrToStructure(inst.Vtbl); - } - - ~FakeWrapper() - { - if (this.wrappedInstance != IntPtr.Zero) - { - this.vtable.Release(this.wrappedInstance); - } - } - } - - class GlobalComWrappers : ComWrappers - { - public static GlobalComWrappers Instance = new GlobalComWrappers(); - - public bool ReturnInvalid { get; set; } - - public object LastComputeVtablesObject { get; private set; } - - protected unsafe override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) - { - LastComputeVtablesObject = obj; - - if (ReturnInvalid) - { - count = -1; - return null; - } - - if (obj is Test) - { - return ComputeVtablesForTestObject((Test)obj, out count); - } - else if (string.Equals(ManagedServerTypeName, obj.GetType().Name)) - { - IntPtr fpQueryInteface = default; - IntPtr fpAddRef = default; - IntPtr fpRelease = default; - ComWrappers.GetIUnknownImpl(out fpQueryInteface, out fpAddRef, out fpRelease); - - var vtbl = new IUnknownVtbl() - { - QueryInterface = fpQueryInteface, - AddRef = fpAddRef, - Release = fpRelease - }; - var vtblRaw = RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(IUnknownVtbl), sizeof(IUnknownVtbl)); - Marshal.StructureToPtr(vtbl, vtblRaw, false); - - // Including interfaces to allow QI, but not actually returning a valid vtable, since it is not needed for the tests here. - var entryRaw = (ComInterfaceEntry*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(IUnknownVtbl), sizeof(ComInterfaceEntry)); - entryRaw[0].IID = typeof(Server.Contract.IConsumeNETServer).GUID; - entryRaw[0].Vtable = vtblRaw; - - count = 1; - return entryRaw; - } - - count = -1; - return null; - } - - protected override object CreateObject(IntPtr externalComObject, CreateObjectFlags flag) - { - if (ReturnInvalid) - return null; - - Guid[] iids = { - typeof(ITrackerObject).GUID, - typeof(ITest).GUID, - typeof(Server.Contract.IDispatchTesting).GUID, - typeof(Server.Contract.IConsumeNETServer).GUID - }; - - for (var i = 0; i < iids.Length; i++) - { - var iid = iids[i]; - IntPtr comObject; - int hr = Marshal.QueryInterface(externalComObject, ref iid, out comObject); - if (hr == 0) - return new FakeWrapper(comObject); - } - - return null; - } - - public const int ReleaseObjectsCallAck = unchecked((int)-1); - - protected override void ReleaseObjects(IEnumerable objects) - { - throw new Exception() { HResult = ReleaseObjectsCallAck }; - } - - private unsafe ComInterfaceEntry* ComputeVtablesForTestObject(Test obj, out int count) - { - IntPtr fpQueryInteface = default; - IntPtr fpAddRef = default; - IntPtr fpRelease = default; - ComWrappers.GetIUnknownImpl(out fpQueryInteface, out fpAddRef, out fpRelease); - - var iUnknownVtbl = new IUnknownVtbl() - { - QueryInterface = fpQueryInteface, - AddRef = fpAddRef, - Release = fpRelease - }; - - var vtbl = new ITestVtbl() - { - IUnknownImpl = iUnknownVtbl, - SetValue = Marshal.GetFunctionPointerForDelegate(ITestVtbl.pSetValue) - }; - var vtblRaw = RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(ITestVtbl), sizeof(ITestVtbl)); - Marshal.StructureToPtr(vtbl, vtblRaw, false); - - int countLocal = obj is TestEx ? ((TestEx)obj).Interfaces.Length + 1 : 1; - var entryRaw = (ComInterfaceEntry*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(ITestVtbl), sizeof(ComInterfaceEntry) * countLocal); - entryRaw[0].IID = typeof(ITest).GUID; - entryRaw[0].Vtable = vtblRaw; - - if (obj is TestEx) - { - var iUnknownVtblRaw = RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(IUnknownVtbl), sizeof(IUnknownVtbl)); - Marshal.StructureToPtr(iUnknownVtbl, iUnknownVtblRaw, false); - - var testEx = (TestEx)obj; - for (int i = 1; i < testEx.Interfaces.Length + 1; i++) - { - // Including interfaces to allow QI, but not actually returning a valid vtable, since it is not needed for the tests here. - entryRaw[i].IID = testEx.Interfaces[i - 1]; - entryRaw[i].Vtable = iUnknownVtblRaw; - } - } - - count = countLocal; - return entryRaw; - } - } - - private static void ValidateRegisterAsGlobalInstance() - { - Console.WriteLine($"Running {nameof(ValidateRegisterAsGlobalInstance)}..."); - - var wrappers1 = GlobalComWrappers.Instance; - wrappers1.RegisterAsGlobalInstance(); - Assert.Throws( - () => - { - wrappers1.RegisterAsGlobalInstance(); - }, "Should not be able to re-register for global ComWrappers"); - - var wrappers2 = new GlobalComWrappers(); - Assert.Throws( - () => - { - wrappers2.RegisterAsGlobalInstance(); - }, "Should not be able to reset for global ComWrappers"); - } - - private static void ValidateMarshalAPIs(bool validateUseRegistered) - { - string scenario = validateUseRegistered ? "use registered wrapper" : "fall back to runtime"; - Console.WriteLine($"Running {nameof(ValidateMarshalAPIs)}: {scenario}..."); - - GlobalComWrappers registeredWrapper = GlobalComWrappers.Instance; - registeredWrapper.ReturnInvalid = !validateUseRegistered; - - Console.WriteLine($" -- Validate Marshal.GetIUnknownForObject..."); - - var testObj = new Test(); - IntPtr comWrapper1 = Marshal.GetIUnknownForObject(testObj); - Assert.AreNotEqual(IntPtr.Zero, comWrapper1); - Assert.AreEqual(testObj, registeredWrapper.LastComputeVtablesObject, "Registered ComWrappers instance should have been called"); - - IntPtr comWrapper2 = Marshal.GetIUnknownForObject(testObj); - Assert.AreEqual(comWrapper1, comWrapper2); - - Marshal.Release(comWrapper1); - Marshal.Release(comWrapper2); - - Console.WriteLine($" -- Validate Marshal.GetIDispatchForObject..."); - - Assert.Throws(() => Marshal.GetIDispatchForObject(testObj)); - - if (validateUseRegistered) - { - var dispatchObj = new TestEx(IID_IDISPATCH); - IntPtr dispatchWrapper = Marshal.GetIDispatchForObject(dispatchObj); - Assert.AreNotEqual(IntPtr.Zero, dispatchWrapper); - Assert.AreEqual(dispatchObj, registeredWrapper.LastComputeVtablesObject, "Registered ComWrappers instance should have been called"); - } - - Console.WriteLine($" -- Validate Marshal.GetObjectForIUnknown..."); - - IntPtr trackerObjRaw = MockReferenceTrackerRuntime.CreateTrackerObject(); - object objWrapper1 = Marshal.GetObjectForIUnknown(trackerObjRaw); - Assert.AreEqual(validateUseRegistered, objWrapper1 is FakeWrapper, $"GetObjectForIUnknown should{(validateUseRegistered ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance"); - object objWrapper2 = Marshal.GetObjectForIUnknown(trackerObjRaw); - Assert.AreEqual(objWrapper1, objWrapper2); - - Console.WriteLine($" -- Validate Marshal.GetUniqueObjectForIUnknown..."); - - object objWrapper3 = Marshal.GetUniqueObjectForIUnknown(trackerObjRaw); - Assert.AreEqual(validateUseRegistered, objWrapper3 is FakeWrapper, $"GetObjectForIUnknown should{(validateUseRegistered ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance"); - - Assert.AreNotEqual(objWrapper1, objWrapper3); - - Marshal.Release(trackerObjRaw); - } - - private static void ValidatePInvokes(bool validateUseRegistered) - { - string scenario = validateUseRegistered ? "use registered wrapper" : "fall back to runtime"; - Console.WriteLine($"Running {nameof(ValidatePInvokes)}: {scenario}..."); - - GlobalComWrappers.Instance.ReturnInvalid = !validateUseRegistered; - - Console.WriteLine($" -- Validate MarshalAs IUnknown..."); - ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsIUnknown, validateUseRegistered); - object obj = MarshalInterface.CreateTrackerObjectAsIUnknown(); - Assert.AreEqual(validateUseRegistered, obj is FakeWrapper, $"Should{(validateUseRegistered ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance"); - - if (validateUseRegistered) - { - Console.WriteLine($" -- Validate MarshalAs IDispatch..."); - ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsIDispatch, validateUseRegistered, new TestEx(IID_IDISPATCH)); - - Console.WriteLine($" -- Validate MarshalAs IInspectable..."); - ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsIInspectable, validateUseRegistered, new TestEx(IID_IINSPECTABLE)); - } - - Console.WriteLine($" -- Validate MarshalAs Interface..."); - ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsInterface, validateUseRegistered); - - if (validateUseRegistered) - { - Assert.Throws(() => MarshalInterface.CreateTrackerObjectWrongType()); - - FakeWrapper wrapper = MarshalInterface.CreateTrackerObjectAsInterface(); - Assert.IsNotNull(obj, $"Should have returned {nameof(FakeWrapper)} instance"); - } - } - - private delegate int UpdateTestObject(T testObj, int i, out T ret) where T : class; - private static void ValidateInterfaceMarshaler(UpdateTestObject func, bool validateUseRegistered, Test testObj = null) where T : class - { - const int E_NOINTERFACE = unchecked((int)0x80004002); - int value = 10; - - if (testObj == null) - testObj = new Test(); - - T retObj; - int hr = func(testObj as T, value, out retObj); - Assert.AreEqual(testObj, GlobalComWrappers.Instance.LastComputeVtablesObject, "Registered ComWrappers instance should have been called"); - if (validateUseRegistered) - { - Assert.IsTrue(retObj is Test); - Assert.AreEqual(value, testObj.GetValue()); - Assert.AreEqual(testObj, retObj); - } - else - { - Assert.AreEqual(E_NOINTERFACE, hr); - } - } - - private static void ValidateComActivation(bool validateUseRegistered) - { - string scenario = validateUseRegistered ? "use registered wrapper" : "fall back to runtime"; - Console.WriteLine($"Running {nameof(ValidateComActivation)}: {scenario}..."); - GlobalComWrappers.Instance.ReturnInvalid = !validateUseRegistered; - - Console.WriteLine($" -- Validate native server..."); - ValidateNativeServerActivation(); - - Console.WriteLine($" -- Validate managed server..."); - ValidateManagedServerActivation(); - } - - private static void ValidateNativeServerActivation() - { - bool returnValid = !GlobalComWrappers.Instance.ReturnInvalid; - - Type t= Type.GetTypeFromCLSID(Guid.Parse(Server.Contract.Guids.DispatchTesting)); - var server = Activator.CreateInstance(t); - Assert.AreEqual(returnValid, server is FakeWrapper, $"Should{(returnValid ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance"); - - IntPtr ptr = Marshal.GetIUnknownForObject(server); - var obj = Marshal.GetObjectForIUnknown(ptr); - Assert.AreEqual(server, obj); - } - - private static void ValidateManagedServerActivation() - { - bool returnValid = !GlobalComWrappers.Instance.ReturnInvalid; - - // Initialize CoreShim and hostpolicymock - HostPolicyMock.Initialize(Environment.CurrentDirectory, null); - Environment.SetEnvironmentVariable("CORESHIM_COMACT_ASSEMBLYNAME", "NETServer"); - Environment.SetEnvironmentVariable("CORESHIM_COMACT_TYPENAME", ManagedServerTypeName); - - using (HostPolicyMock.Mock_corehost_resolve_component_dependencies(0, string.Empty, string.Empty, string.Empty)) - { - Type t = Type.GetTypeFromCLSID(Guid.Parse(Server.Contract.Guids.ConsumeNETServerTesting)); - var server = Activator.CreateInstance(t); - Assert.AreEqual(returnValid, server is FakeWrapper, $"Should{(returnValid ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance"); - object serverUnwrapped = GlobalComWrappers.Instance.LastComputeVtablesObject; - Assert.AreEqual(ManagedServerTypeName, serverUnwrapped.GetType().Name); - - IntPtr ptr = Marshal.GetIUnknownForObject(server); - var obj = Marshal.GetObjectForIUnknown(ptr); - Assert.AreEqual(server, obj); - Assert.AreEqual(returnValid, obj is FakeWrapper, $"Should{(returnValid ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance"); - serverUnwrapped.GetType().GetMethod("NotEqualByRCW").Invoke(serverUnwrapped, new object[] { obj }); - } - } - - private static void ValidateNotifyEndOfReferenceTrackingOnThread() - { - Console.WriteLine($"Running {nameof(ValidateNotifyEndOfReferenceTrackingOnThread)}..."); - - // Make global instance return invalid object so that the Exception thrown by - // GlobalComWrappers.ReleaseObjects is marshalled using the built-in system. - GlobalComWrappers.Instance.ReturnInvalid = true; - - // Trigger the thread lifetime end API and verify the callback occurs. - int hr = MockReferenceTrackerRuntime.Trigger_NotifyEndOfReferenceTrackingOnThread(); - Assert.AreEqual(GlobalComWrappers.ReleaseObjectsCallAck, hr); - } - - static int Main(string[] doNotUse) - { - try - { - // The first test registereds a global ComWrappers instance - // Subsequents tests assume the global instance has already been registered. - ValidateRegisterAsGlobalInstance(); - - ValidateMarshalAPIs(validateUseRegistered: true); - ValidateMarshalAPIs(validateUseRegistered: false); - - ValidatePInvokes(validateUseRegistered: true); - ValidatePInvokes(validateUseRegistered: false); - - ValidateComActivation(validateUseRegistered: true); - ValidateComActivation(validateUseRegistered: false); - - ValidateNotifyEndOfReferenceTrackingOnThread(); - } - catch (Exception e) - { - Console.WriteLine($"Test Failure: {e}"); - return 101; - } - - return 100; - } - } -} - diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/MockReferenceTrackerRuntime/ReferenceTrackerRuntime.cpp b/src/coreclr/tests/src/Interop/COM/ComWrappers/MockReferenceTrackerRuntime/ReferenceTrackerRuntime.cpp index 867efa01866e42..54cf0bb31f14b6 100644 --- a/src/coreclr/tests/src/Interop/COM/ComWrappers/MockReferenceTrackerRuntime/ReferenceTrackerRuntime.cpp +++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/MockReferenceTrackerRuntime/ReferenceTrackerRuntime.cpp @@ -374,5 +374,10 @@ extern "C" DLL_EXPORT int STDMETHODCALLTYPE UpdateTestObjectAsInterface(ITest *o if (obj == nullptr) return E_POINTER; - return UpdateTestObjectAsIUnknown(obj, i, (IUnknown**)out); + HRESULT hr; + RETURN_IF_FAILED(obj->SetValue(i)); + + obj->AddRef(); + *out = obj; + return S_OK; } diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/CMakeLists.txt b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/CMakeLists.txt new file mode 100644 index 00000000000000..8166db21865745 --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/CMakeLists.txt @@ -0,0 +1,10 @@ +project (WeakReferenceNative) +include_directories( ${INC_PLATFORM_DIR} ) +set(SOURCES WeakReferenceNative.cpp) + +# add the shared library +add_library (WeakReferenceNative SHARED ${SOURCES}) +target_link_libraries(WeakReferenceNative ${LINK_LIBRARIES_ADDITIONAL}) + +# add the install targets +install (TARGETS WeakReferenceNative DESTINATION bin) diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceNative.cpp b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceNative.cpp new file mode 100644 index 00000000000000..5617b117679817 --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceNative.cpp @@ -0,0 +1,124 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include +#include +#include + +namespace +{ + struct WeakReference : public IWeakReference, public UnknownImpl + { + IInspectable* _reference; + std::atomic _strongRefCount; + + WeakReference(IInspectable* reference, ULONG strongRefCount) + : _reference(reference), + _strongRefCount(strongRefCount) + {} + + ULONG AddStrongRef() + { + assert(_strongRefCount > 0); + return (++_strongRefCount); + } + + ULONG ReleaseStrongRef() + { + assert(_strongRefCount > 0); + return --_strongRefCount; + } + + STDMETHOD(Resolve)(REFIID riid, IInspectable** ppvObject) + { + if (_strongRefCount > 0) + { + void* pObject; + HRESULT hr = _reference->QueryInterface(riid, &pObject); + *ppvObject = reinterpret_cast(pObject); + return hr; + } + return E_NOINTERFACE; + } + + STDMETHOD(QueryInterface)( + /* [in] */ REFIID riid, + /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject) + { + return DoQueryInterface(riid, ppvObject, static_cast(this)); + } + + DEFINE_REF_COUNTING() + }; + + struct WeakReferencableObject : public IWeakReferenceSource, public IInspectable, public UnknownImpl + { + ComSmartPtr _weakReference; + STDMETHOD(GetWeakReference)(_COM_Outptr_ IWeakReference** ppWeakReference) + { + if (!_weakReference) + { + ULONG refCount = UnknownImpl::GetRefCount(); + _weakReference = new WeakReference(this, refCount); + } + _weakReference->AddRef(); + *ppWeakReference = _weakReference; + return S_OK; + } + + STDMETHOD(GetRuntimeClassName)(HSTRING* pRuntimeClassName) + { + return E_NOTIMPL; + } + + STDMETHOD(GetIids)( + ULONG *iidCount, + IID **iids) + { + return E_NOTIMPL; + } + + STDMETHOD(GetTrustLevel)(TrustLevel *trustLevel) + { + *trustLevel = FullTrust; + return S_OK; + } + + STDMETHOD(QueryInterface)( + /* [in] */ REFIID riid, + /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject) + { + HRESULT hr = DoQueryInterface(riid, ppvObject, static_cast(this), static_cast(this), static_cast(this)); + if (SUCCEEDED(hr) && _weakReference) + { + _weakReference->AddStrongRef(); + } + return hr; + } + STDMETHOD_(ULONG, AddRef)(void) + { + if (_weakReference) + { + return _weakReference->AddStrongRef(); + } + return UnknownImpl::DoAddRef(); + } + STDMETHOD_(ULONG, Release)(void) + { + if (_weakReference) + { + ULONG c = _weakReference->ReleaseStrongRef(); + if (c == 0) + delete this; + return c; + } + return UnknownImpl::DoRelease(); + } + }; +} +extern "C" DLL_EXPORT WeakReferencableObject* STDMETHODCALLTYPE CreateWeakReferencableObject() +{ + return new WeakReferencableObject(); +} diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.cs b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.cs new file mode 100644 index 00000000000000..f85138f72c1da6 --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.cs @@ -0,0 +1,133 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace ComWrappersTests +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + using TestLibrary; + + static class WeakReferenceNative + { + [DllImport(nameof(WeakReferenceNative))] + public static extern IntPtr CreateWeakReferencableObject(); + } + + public struct VtblPtr + { + public IntPtr Vtbl; + } + + public class WeakReferencableWrapper + { + private struct Vtbl + { + public IntPtr QueryInterface; + public _AddRef AddRef; + public _Release Release; + } + + private delegate int _AddRef(IntPtr This); + private delegate int _Release(IntPtr This); + + private readonly IntPtr instance; + private readonly Vtbl vtable; + + public WeakReferencableWrapper(IntPtr instance) + { + var inst = Marshal.PtrToStructure(instance); + this.vtable = Marshal.PtrToStructure(inst.Vtbl); + this.instance = instance; + } + + ~WeakReferencableWrapper() + { + if (this.instance != IntPtr.Zero) + { + this.vtable.Release(this.instance); + } + } + } + + class Program + { + class TestComWrappers : ComWrappers + { + protected unsafe override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) + { + count = 0; + return null; + } + + protected override object CreateObject(IntPtr externalComObject, CreateObjectFlags flag) + { + Marshal.AddRef(externalComObject); + return new WeakReferencableWrapper(externalComObject); + } + + protected override void ReleaseObjects(IEnumerable objects) + { + } + + public static readonly ComWrappers Instance = new TestComWrappers(); + } + + static void ValidateNativeWeakReference() + { + Console.WriteLine($"Running {nameof(ValidateNativeWeakReference)}..."); + + static (WeakReference, IntPtr) GetWeakReference() + { + var cw = new TestComWrappers(); + + IntPtr objRaw = WeakReferenceNative.CreateWeakReferencableObject(); + + var obj = (WeakReferencableWrapper)cw.GetOrCreateObjectForComInstance(objRaw, CreateObjectFlags.None); + + return (new WeakReference(obj), objRaw); + } + + static bool CheckIfWeakReferenceIsAlive(WeakReference wr) + { + return wr.TryGetTarget(out _); + } + + var (weakRef, nativeRef) = GetWeakReference(); + GC.Collect(); + GC.WaitForPendingFinalizers(); + // A weak reference to an RCW wrapping an IWeakReference should stay alive even after the RCW dies + Assert.IsTrue(CheckIfWeakReferenceIsAlive(weakRef)); + + // Release the last native reference. + Marshal.Release(nativeRef); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + + // After all native references die and the RCW is collected, the weak reference should be dead and stay dead. + Assert.IsFalse(CheckIfWeakReferenceIsAlive(weakRef)); + + } + + static int Main(string[] doNotUse) + { + try + { + ComWrappers.RegisterForTrackerSupport(TestComWrappers.Instance); + ValidateNativeWeakReference(); + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + + return 100; + } + } +} + diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.csproj b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.csproj new file mode 100644 index 00000000000000..edcc33106ebde9 --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.csproj @@ -0,0 +1,24 @@ + + + Exe + + true + + true + true + true + + + + + + + + + + 1 + + + + + diff --git a/src/coreclr/tests/src/Interop/COM/NETClients/Events/Program.cs b/src/coreclr/tests/src/Interop/COM/NETClients/Events/Program.cs index 49359243d978b3..c6cc282a5c6191 100644 --- a/src/coreclr/tests/src/Interop/COM/NETClients/Events/Program.cs +++ b/src/coreclr/tests/src/Interop/COM/NETClients/Events/Program.cs @@ -50,8 +50,6 @@ void OnEventEventHandler(string msg) } } -#pragma warning disable 618 // Must test deprecated features - // The ComAwareEventInfo is used by the compiler when PIAs // containing COM Events are embedded. static void Validate_COMEventViaComAwareEventInfo() @@ -90,8 +88,6 @@ void OnEventEventHandler(string msg) } } -#pragma warning restore 618 // Must test deprecated features - static int Main(string[] doNotUse) { // RegFree COM is not supported on Windows Nano diff --git a/src/coreclr/tests/src/Interop/COM/NETServer/EventTesting.cs b/src/coreclr/tests/src/Interop/COM/NETServer/EventTesting.cs new file mode 100644 index 00000000000000..63757fadef38f4 --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/NETServer/EventTesting.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Globalization; +using System.Text; +using System.Runtime.InteropServices; +using Server.Contract; + +[ComVisible(true)] +[Guid(Server.Contract.Guids.EventTesting)] +[ComSourceInterfaces(typeof(Server.Contract.TestingEvents))] +public class EventTesting : Server.Contract.IEventTesting +{ + public delegate void OnEventHandler(string msg); + public event OnEventHandler OnEvent; + + public void FireEvent() + { + var h = this.OnEvent; + if (h != null) + { + h(nameof(FireEvent)); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tests/src/Interop/COM/NativeClients/DefaultInterfaces.csproj b/src/coreclr/tests/src/Interop/COM/NativeClients/DefaultInterfaces.csproj index 75cd4e855269e9..fbea00a3521e75 100644 --- a/src/coreclr/tests/src/Interop/COM/NativeClients/DefaultInterfaces.csproj +++ b/src/coreclr/tests/src/Interop/COM/NativeClients/DefaultInterfaces.csproj @@ -1,5 +1,6 @@ + Exe true true true diff --git a/src/coreclr/tests/src/Interop/COM/NativeClients/Dispatch.csproj b/src/coreclr/tests/src/Interop/COM/NativeClients/Dispatch.csproj index 1c758d92634fb8..be2377f98ef28b 100644 --- a/src/coreclr/tests/src/Interop/COM/NativeClients/Dispatch.csproj +++ b/src/coreclr/tests/src/Interop/COM/NativeClients/Dispatch.csproj @@ -1,5 +1,6 @@ + Exe true true true diff --git a/src/coreclr/tests/src/Interop/COM/NativeClients/Events.csproj b/src/coreclr/tests/src/Interop/COM/NativeClients/Events.csproj new file mode 100644 index 00000000000000..54575775db6001 --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/NativeClients/Events.csproj @@ -0,0 +1,27 @@ + + + Exe + true + true + true + BuildOnly + true + true + BLOCK_WINDOWS_NANO + + + + + + + + + + + 1 + + + + + + diff --git a/src/coreclr/tests/src/Interop/COM/NativeClients/Events/App.manifest b/src/coreclr/tests/src/Interop/COM/NativeClients/Events/App.manifest new file mode 100644 index 00000000000000..d06a797929997e --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/NativeClients/Events/App.manifest @@ -0,0 +1,17 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/coreclr/tests/src/Interop/COM/NativeClients/Events/CMakeLists.txt b/src/coreclr/tests/src/Interop/COM/NativeClients/Events/CMakeLists.txt new file mode 100644 index 00000000000000..43063bd532d3af --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/NativeClients/Events/CMakeLists.txt @@ -0,0 +1,17 @@ +project (COMClientEvents) +include_directories( ${INC_PLATFORM_DIR} ) +include_directories( "../../ServerContracts" ) +include_directories( "../../NativeServer" ) +set(SOURCES + EventTests.cpp + App.manifest) + +# add the executable +add_executable (COMClientEvents ${SOURCES}) +target_link_libraries(COMClientEvents ${LINK_LIBRARIES_ADDITIONAL}) + +# Copy CoreShim manifest to project output +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/$/CoreShim.X.manifest INPUT ${CMAKE_CURRENT_SOURCE_DIR}/CoreShim.X.manifest) + +# add the install targets +install (TARGETS COMClientEvents DESTINATION bin) diff --git a/src/coreclr/tests/src/Interop/COM/NativeClients/Events/CoreShim.X.manifest b/src/coreclr/tests/src/Interop/COM/NativeClients/Events/CoreShim.X.manifest new file mode 100644 index 00000000000000..e8284bac6e3421 --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/NativeClients/Events/CoreShim.X.manifest @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/src/coreclr/tests/src/Interop/COM/NativeClients/Events/EventTests.cpp b/src/coreclr/tests/src/Interop/COM/NativeClients/Events/EventTests.cpp new file mode 100644 index 00000000000000..ee5212cd155055 --- /dev/null +++ b/src/coreclr/tests/src/Interop/COM/NativeClients/Events/EventTests.cpp @@ -0,0 +1,257 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include +#include + +// COM headers +#include +#include + +#define COM_CLIENT +#include + +#define THROW_IF_FAILED(exp) { hr = exp; if (FAILED(hr)) { ::printf("FAILURE: 0x%08x = %s\n", hr, #exp); throw hr; } } +#define THROW_FAIL_IF_FALSE(exp) { if (!(exp)) { ::printf("FALSE: %s\n", #exp); throw E_FAIL; } } + +#include +#include + +namespace +{ + class EventSink : public UnknownImpl, public TestingEvents + { + std::map _firedEvents; + + public: + void ResetFiredState(_In_ DISPID id) + { + _firedEvents.erase(id); + } + + bool DidFire(_In_ DISPID id, _Out_ std::wstring& message) + { + auto iter = _firedEvents.find(id); + if (iter == std::end(_firedEvents)) + return false; + + message = iter->second; + return true; + } + + public: // IDispatch + virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( + /* [out] */ __RPC__out UINT* pctinfo) + { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE GetTypeInfo( + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ __RPC__deref_out_opt ITypeInfo** ppTInfo) + { + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames( + /* [in] */ __RPC__in REFIID riid, + /* [size_is][in] */ __RPC__in_ecount_full(cNames) LPOLESTR* rgszNames, + /* [range][in] */ __RPC__in_range(0, 16384) UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ __RPC__out_ecount_full(cNames) DISPID* rgDispId) + { + return E_NOTIMPL; + } + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke( + /* [annotation][in] */ + _In_ DISPID dispIdMember, + /* [annotation][in] */ + _In_ REFIID riid, + /* [annotation][in] */ + _In_ LCID lcid, + /* [annotation][in] */ + _In_ WORD wFlags, + /* [annotation][out][in] */ + _In_ DISPPARAMS* pDispParams, + /* [annotation][out] */ + _Out_opt_ VARIANT* pVarResult, + /* [annotation][out] */ + _Out_opt_ EXCEPINFO* pExcepInfo, + /* [annotation][out] */ + _Out_opt_ UINT* puArgErr) + { + // + // Note that arguments are received in reverse order for IDispatch::Invoke() + // + + switch (dispIdMember) + { + case DISPATCHTESTINGEVENTS_DISPID_ONEVENT: + { + return OnFireEventHandler(dispIdMember, pDispParams); + } + } + + return E_NOTIMPL; + } + + private: + HRESULT OnFireEventHandler(_In_ DISPID dispId, _In_ DISPPARAMS* dispParams) + { + if (dispParams == nullptr) + return E_POINTER; + + if (dispParams->cArgs != 1) + return E_INVALIDARG; + + VARIANTARG* msgMaybe = dispParams->rgvarg; + if (msgMaybe->vt != VT_BSTR) + return E_INVALIDARG; + + _firedEvents.insert({ dispId, msgMaybe->bstrVal }); + return S_OK; + } + + public: // IUnknown + STDMETHOD(QueryInterface)( + /* [in] */ REFIID riid, + /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject) + { + return DoQueryInterface(riid, ppvObject, + static_cast(this), + static_cast(this)); + } + + DEFINE_REF_COUNTING(); + }; + + void VerifyAdviseUnadviseFromEvent() + { + HRESULT hr; + + ComSmartPtr et; + THROW_IF_FAILED(::CoCreateInstance(CLSID_EventTesting, nullptr, CLSCTX_INPROC, IID_IEventTesting, (void**)&et)); + + ComSmartPtr cpc; + THROW_IF_FAILED(et->QueryInterface(&cpc)); + + ComSmartPtr cp; + THROW_IF_FAILED(cpc->FindConnectionPoint(IID_TestingEvents, &cp)); + + // Create event sink + ComSmartPtr es; + es.Attach(new EventSink()); + + DWORD cookie; + ComSmartPtr uk; + THROW_IF_FAILED(es->QueryInterface(IID_IUnknown, (void**)&uk)); + THROW_IF_FAILED(cp->Advise(uk, &cookie)); + + // Ensure state is valid. + es->ResetFiredState(DISPATCHTESTINGEVENTS_DISPID_ONEVENT); + + THROW_IF_FAILED(et->FireEvent()); + + // Validate the event fired. + { + std::wstring eventName; + THROW_FAIL_IF_FALSE(es->DidFire(DISPATCHTESTINGEVENTS_DISPID_ONEVENT, eventName)); + THROW_FAIL_IF_FALSE(eventName.compare(L"FireEvent") == 0); + } + + THROW_IF_FAILED(cp->Unadvise(cookie)); + + // Reset state. + es->ResetFiredState(DISPATCHTESTINGEVENTS_DISPID_ONEVENT); + + THROW_IF_FAILED(et->FireEvent()); + + // Validate the event was not fired. + { + std::wstring eventName; + THROW_FAIL_IF_FALSE(!es->DidFire(DISPATCHTESTINGEVENTS_DISPID_ONEVENT, eventName)); + THROW_FAIL_IF_FALSE(eventName.empty()); + } + } + + void VerifyEnumConnectionPoints() + { + HRESULT hr; + + ComSmartPtr et; + THROW_IF_FAILED(::CoCreateInstance(CLSID_EventTesting, nullptr, CLSCTX_INPROC, IID_IEventTesting, (void**)&et)); + + ComSmartPtr cpc; + THROW_IF_FAILED(et->QueryInterface(&cpc)); + + ComSmartPtr ecp; + THROW_IF_FAILED(cpc->EnumConnectionPoints(&ecp)); + + bool foundEventInterface = false; + ULONG fetched; + LPCONNECTIONPOINT ptRaw = nullptr; + while ((hr = ecp->Next(1, &ptRaw, &fetched)) == S_OK) + { + THROW_FAIL_IF_FALSE(fetched == 1); + THROW_FAIL_IF_FALSE(ptRaw != nullptr); + + ComSmartPtr pt; + pt.Attach(ptRaw); + ptRaw = nullptr; + + IID iidMaybe; + THROW_IF_FAILED(pt->GetConnectionInterface(&iidMaybe)); + foundEventInterface = (iidMaybe == IID_TestingEvents); + + // There should only be one event interface + THROW_FAIL_IF_FALSE(foundEventInterface); + } + + THROW_IF_FAILED(hr); + THROW_FAIL_IF_FALSE(foundEventInterface); + } +} + +template +struct ComInit +{ + const HRESULT Result; + + ComInit() + : Result{ ::CoInitializeEx(nullptr, TM) } + { } + + ~ComInit() + { + if (SUCCEEDED(Result)) + ::CoUninitialize(); + } +}; + +using ComMTA = ComInit; + +int __cdecl main() +{ + ComMTA init; + if (FAILED(init.Result)) + return -1; + + try + { + CoreShimComActivation csact{ W("NETServer"), W("EventTesting") }; + + VerifyAdviseUnadviseFromEvent(); + VerifyEnumConnectionPoints(); + } + catch (HRESULT hr) + { + ::printf("Test Failure: 0x%08x\n", hr); + return 101; + } + + return 100; +} diff --git a/src/coreclr/tests/src/Interop/COM/NativeClients/Licensing.csproj b/src/coreclr/tests/src/Interop/COM/NativeClients/Licensing.csproj index 4b94fda93daa92..5d71d37966a2da 100644 --- a/src/coreclr/tests/src/Interop/COM/NativeClients/Licensing.csproj +++ b/src/coreclr/tests/src/Interop/COM/NativeClients/Licensing.csproj @@ -1,5 +1,6 @@ + Exe true true true diff --git a/src/coreclr/tests/src/Interop/COM/NativeClients/Primitives.csproj b/src/coreclr/tests/src/Interop/COM/NativeClients/Primitives.csproj index 0419036b66cfbe..c27fe1402b6c2e 100644 --- a/src/coreclr/tests/src/Interop/COM/NativeClients/Primitives.csproj +++ b/src/coreclr/tests/src/Interop/COM/NativeClients/Primitives.csproj @@ -1,5 +1,6 @@ + Exe true true true diff --git a/src/coreclr/tests/src/Interop/COM/ServerContracts/Server.Events.cs b/src/coreclr/tests/src/Interop/COM/ServerContracts/Server.Events.cs index 16ed578d98a34a..37d598fcf21a71 100644 --- a/src/coreclr/tests/src/Interop/COM/ServerContracts/Server.Events.cs +++ b/src/coreclr/tests/src/Interop/COM/ServerContracts/Server.Events.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#pragma warning disable 618 // Must test deprecated features - namespace Server.Contract { using System; @@ -189,5 +187,3 @@ public void OnEvent(string msg) } } } - -#pragma warning restore 618 // Must test deprecated features diff --git a/src/coreclr/tests/src/Interop/NativeCallable/CMakeLists.txt b/src/coreclr/tests/src/Interop/NativeCallable/CMakeLists.txt deleted file mode 100644 index d428cd0178ce21..00000000000000 --- a/src/coreclr/tests/src/Interop/NativeCallable/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -project (NativeCallableDll) -include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") -set(SOURCES NativeCallableDll.cpp ) - -# add the executable -add_library (NativeCallableDll SHARED ${SOURCES}) -target_link_libraries(NativeCallableDll ${LINK_LIBRARIES_ADDITIONAL}) - -# add the install targets -install (TARGETS NativeCallableDll DESTINATION bin) diff --git a/src/coreclr/tests/src/Interop/NativeCallable/NativeCallableTest.cs b/src/coreclr/tests/src/Interop/NativeCallable/NativeCallableTest.cs deleted file mode 100644 index 121379c3155cdd..00000000000000 --- a/src/coreclr/tests/src/Interop/NativeCallable/NativeCallableTest.cs +++ /dev/null @@ -1,601 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Reflection; -using System.Reflection.Emit; -using System.Runtime.InteropServices; -using System.Threading; -using TestLibrary; - -public class Program -{ - public static class NativeCallableDll - { - [DllImport(nameof(NativeCallableDll))] - public static extern int CallManagedProc(IntPtr callbackProc, int n); - - [DllImport(nameof(NativeCallableDll))] - public static extern int CallManagedProcOnNewThread(IntPtr callbackProc, int n); - - [DllImport(nameof(NativeCallableDll))] - // Returns -1 if exception was throw and caught. - public static extern int CallManagedProcCatchException(IntPtr callbackProc, int n); - } - - private delegate int IntNativeMethodInvoker(); - private delegate void NativeMethodInvoker(); - - public static int Main(string[] args) - { - try - { - TestNativeCallableValid(); - TestNativeCallableValid_OnNewNativeThread(); - TestNativeCallableValid_PrepareMethod(); - NegativeTest_NonStaticMethod(); - NegativeTest_ViaDelegate(); - NegativeTest_NonBlittable(); - NegativeTest_NonInstantiatedGenericArguments(); - NegativeTest_InstantiatedGenericArguments(); - NegativeTest_FromInstantiatedGenericClass(); - TestNativeCallableViaUnmanagedCalli(); - - // Exception handling is only supported on Windows. - if (TestLibrary.Utilities.IsWindows) - { - TestNativeCallableValid_ThrowException(); - TestNativeCallableViaUnmanagedCalli_ThrowException(); - } - - if (args.Length != 0 && args[0].Equals("calli")) - { - NegativeTest_ViaCalli(); - } - } - catch (Exception e) - { - Console.WriteLine($"Test Failure: {e}"); - return 101; - } - - return 100; - } - - [NativeCallable] - public static int ManagedDoubleCallback(int n) - { - return DoubleImpl(n); - } - - private static int DoubleImpl(int n) - { - return 2 * n; - } - - public static void TestNativeCallableValid() - { - Console.WriteLine($"Running {nameof(TestNativeCallableValid)}..."); - - /* - void NativeCallable() - { - .locals init ([0] native int ptr) - IL_0000: nop - IL_0001: ldftn int32 ManagedDoubleCallback(int32) - IL_0007: stloc.0 - - IL_0008: ldloc.0 - IL_0009: ldc.i4 local - IL_000e: call bool NativeCallableDll::CallManagedProc(native int, int) - - IL_0013: ret - } - */ - DynamicMethod testNativeCallable = new DynamicMethod("NativeCallable", typeof(int), null, typeof(Program).Module); - ILGenerator il = testNativeCallable.GetILGenerator(); - il.DeclareLocal(typeof(IntPtr)); - il.Emit(OpCodes.Nop); - - // Get native function pointer of the callback - il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(ManagedDoubleCallback))); - il.Emit(OpCodes.Stloc_0); - il.Emit(OpCodes.Ldloc_0); - - int n = 12345; - il.Emit(OpCodes.Ldc_I4, n); - il.Emit(OpCodes.Call, typeof(NativeCallableDll).GetMethod("CallManagedProc")); - il.Emit(OpCodes.Ret); - var testNativeMethod = (IntNativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(IntNativeMethodInvoker)); - - int expected = DoubleImpl(n); - Assert.AreEqual(expected, testNativeMethod()); - } - - public static void TestNativeCallableValid_OnNewNativeThread() - { - Console.WriteLine($"Running {nameof(TestNativeCallableValid_OnNewNativeThread)}..."); - - /* - void NativeCallableOnNewNativeThread() - { - .locals init ([0] native int ptr) - IL_0000: nop - IL_0001: ldftn int32 ManagedDoubleCallback(int32) - IL_0007: stloc.0 - - IL_0008: ldloc.0 - IL_0009: ldc.i4 local - IL_000e: call bool NativeCallableDll::CallManagedProcOnNewThread(native int, int) - - IL_0013: ret - } - */ - DynamicMethod testNativeCallable = new DynamicMethod("NativeCallableOnNewNativeThread", typeof(int), null, typeof(Program).Module); - ILGenerator il = testNativeCallable.GetILGenerator(); - il.DeclareLocal(typeof(IntPtr)); - il.Emit(OpCodes.Nop); - - // Get native function pointer of the callback - il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(ManagedDoubleCallback))); - il.Emit(OpCodes.Stloc_0); - il.Emit(OpCodes.Ldloc_0); - - int n = 12345; - il.Emit(OpCodes.Ldc_I4, n); - il.Emit(OpCodes.Call, typeof(NativeCallableDll).GetMethod("CallManagedProcOnNewThread")); - il.Emit(OpCodes.Ret); - var testNativeMethod = (IntNativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(IntNativeMethodInvoker)); - - int expected = DoubleImpl(n); - Assert.AreEqual(expected, testNativeMethod()); - } - - [NativeCallable] - public static int ManagedCallback_Prepared(int n) - { - return DoubleImpl(n); - } - - // This test is about the interaction between Tiered Compilation and the NativeCallableAttribute. - public static void TestNativeCallableValid_PrepareMethod() - { - Console.WriteLine($"Running {nameof(TestNativeCallableValid_PrepareMethod)}..."); - - /* - void NativeCallableOnNewNativeThread() - { - .locals init ([0] native int ptr) - IL_0000: nop - IL_0001: ldftn int32 ManagedCallback_Prepared(int32) - IL_0007: stloc.0 - - IL_0008: ldloc.0 - IL_0009: ldc.i4 local - IL_000e: call bool NativeCallableDll::CallManagedProcOnNewThread(native int, int) - - IL_0013: ret - } - */ - DynamicMethod testNativeCallable = new DynamicMethod("NativeCallableValid_PrepareMethod", typeof(int), null, typeof(Program).Module); - ILGenerator il = testNativeCallable.GetILGenerator(); - il.DeclareLocal(typeof(IntPtr)); - il.Emit(OpCodes.Nop); - - // Prepare the managed callback. - var preparedCallback = typeof(Program).GetMethod(nameof(ManagedCallback_Prepared)); - RuntimeHelpers.PrepareMethod(preparedCallback.MethodHandle); - - // Get native function pointer of the callback - il.Emit(OpCodes.Ldftn, preparedCallback); - il.Emit(OpCodes.Stloc_0); - il.Emit(OpCodes.Ldloc_0); - - int n = 12345; - il.Emit(OpCodes.Ldc_I4, n); - il.Emit(OpCodes.Call, typeof(NativeCallableDll).GetMethod("CallManagedProcOnNewThread")); - il.Emit(OpCodes.Ret); - var testNativeMethod = (IntNativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(IntNativeMethodInvoker)); - - // Call enough to attempt to trigger Tiered Compilation from a new thread. - for (int i = 0; i < 100; ++i) - { - testNativeMethod(); - } - } - - private const int CallbackThrowsErrorCode = 27; - - [NativeCallable] - public static int CallbackThrows(int val) - { - throw new Exception() { HResult = CallbackThrowsErrorCode }; - } - - public static void TestNativeCallableValid_ThrowException() - { - Console.WriteLine($"Running {nameof(TestNativeCallableValid_ThrowException)}..."); - - /* - void NativeCallableValid_ThrowException() - { - .locals init ([0] native int ptr) - IL_0000: nop - IL_0001: ldftn int32 CallbackThrows(int32) - IL_0007: stloc.0 - - IL_0008: ldloc.0 - IL_0009: ldc.i4 local - IL_000e: call bool NativeCallableDll::CallManagedProcCatchException(native int, int) - - IL_0013: ret - } - */ - DynamicMethod testNativeCallable = new DynamicMethod("NativeCallableValid_ThrowException", typeof(int), null, typeof(Program).Module); - ILGenerator il = testNativeCallable.GetILGenerator(); - il.DeclareLocal(typeof(IntPtr)); - il.Emit(OpCodes.Nop); - - // Get native function pointer of the callback - il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackThrows))); - il.Emit(OpCodes.Stloc_0); - il.Emit(OpCodes.Ldloc_0); - - int n = 12345; - il.Emit(OpCodes.Ldc_I4, n); - il.Emit(OpCodes.Call, typeof(NativeCallableDll).GetMethod("CallManagedProcCatchException")); - il.Emit(OpCodes.Ret); - var testNativeMethod = (IntNativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(IntNativeMethodInvoker)); - - // Method should have thrown and caught an exception. - Assert.AreEqual(-1, testNativeMethod()); - } - - public static void NegativeTest_ViaDelegate() - { - Console.WriteLine($"Running {nameof(NegativeTest_ViaDelegate)}..."); - - // Try invoking method directly - Assert.Throws(() => { CallAsDelegate(); }); - - // Local function to delay exception thrown during JIT - void CallAsDelegate() - { - Func invoker = ManagedDoubleCallback; - invoker(0); - } - } - - [NativeCallable] - public void CallbackNonStatic() - { - Assert.Fail($"Instance functions with attribute {nameof(NativeCallableAttribute)} are invalid"); - } - - public static void NegativeTest_NonStaticMethod() - { - Console.WriteLine($"Running {nameof(NegativeTest_NonStaticMethod)}..."); - - /* - void TestNativeCallableNonStatic() - { - .locals init ([0] native int ptr) - IL_0000: nop - IL_0001: ldftn void CallbackNonStatic() - IL_0007: stloc.0 - IL_0008: ret - } - */ - DynamicMethod testNativeCallable = new DynamicMethod("TestNativeCallableNonStatic", null, null, typeof(Program).Module); - ILGenerator il = testNativeCallable.GetILGenerator(); - il.DeclareLocal(typeof(IntPtr)); - il.Emit(OpCodes.Nop); - - // Get native function pointer of the callback - il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackNonStatic))); - il.Emit(OpCodes.Stloc_0); - - il.Emit(OpCodes.Ret); - var testNativeMethod = (NativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(NativeMethodInvoker)); - - // Try invoking method - Assert.Throws(() => { testNativeMethod(); }); - } - - [NativeCallable] - public static void CallbackMethodNonBlittable(bool x1) - { - Assert.Fail($"Functions with attribute {nameof(NativeCallableAttribute)} cannot have non-blittable arguments"); - } - - public static void NegativeTest_NonBlittable() - { - Console.WriteLine($"Running {nameof(NegativeTest_NonBlittable)}..."); - - /* - void TestNativeCallableNonBlittable() - { - .locals init ([0] native int ptr) - IL_0000: nop - IL_0001: ldftn void CallbackMethodNonBlittable(bool) - IL_0007: stloc.0 - IL_0008: ret - } - */ - DynamicMethod testNativeCallable = new DynamicMethod("TestNativeCallableNonBlittable", null, null, typeof(Program).Module); - ILGenerator il = testNativeCallable.GetILGenerator(); - il.DeclareLocal(typeof(IntPtr)); - il.Emit(OpCodes.Nop); - - // Get native function pointer of the callback - il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackMethodNonBlittable))); - il.Emit(OpCodes.Stloc_0); - - il.Emit(OpCodes.Ret); - var testNativeMethod = (NativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(NativeMethodInvoker)); - - // Try invoking method - Assert.Throws(() => { testNativeMethod(); }); - } - - [NativeCallable] - public static void CallbackMethodGeneric(T arg) - { - Assert.Fail($"Functions with attribute {nameof(NativeCallableAttribute)} cannot have generic arguments"); - } - - public static void NegativeTest_NonInstantiatedGenericArguments() - { - Console.WriteLine($"Running {nameof(NegativeTest_NonInstantiatedGenericArguments)}..."); - - /* - void TestNativeCallableNonInstGenericArguments() - { - .locals init ([0] native int ptr) - IL_0000: nop - IL_0001: ldftn void CallbackMethodGeneric(T) - IL_0007: stloc.0 - IL_0008: ret - } - */ - DynamicMethod testNativeCallable = new DynamicMethod("TestNativeCallableNonInstGenericArguments", null, null, typeof(Program).Module); - ILGenerator il = testNativeCallable.GetILGenerator(); - il.DeclareLocal(typeof(IntPtr)); - il.Emit(OpCodes.Nop); - - // Get native function pointer of the callback - il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackMethodGeneric))); - il.Emit(OpCodes.Stloc_0); - - il.Emit(OpCodes.Ret); - var testNativeMethod = (NativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(NativeMethodInvoker)); - - // Try invoking method - Assert.Throws(() => { testNativeMethod(); }); - } - - public static void NegativeTest_InstantiatedGenericArguments() - { - Console.WriteLine($"Running {nameof(NegativeTest_InstantiatedGenericArguments)}..."); - - /* - void TestNativeCallableInstGenericArguments() - { - .locals init ([0] native int ptr) - IL_0000: nop - IL_0001: ldftn void CallbackMethodGeneric(int) - IL_0007: stloc.0 - IL_0008: ret - } - */ - DynamicMethod testNativeCallable = new DynamicMethod("TestNativeCallableInstGenericArguments", null, null, typeof(Program).Module); - ILGenerator il = testNativeCallable.GetILGenerator(); - il.DeclareLocal(typeof(IntPtr)); - il.Emit(OpCodes.Nop); - - // Get native function pointer of the instantiated generic callback - il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackMethodGeneric)).MakeGenericMethod(new [] { typeof(int) })); - il.Emit(OpCodes.Stloc_0); - - il.Emit(OpCodes.Ret); - var testNativeMethod = (NativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(NativeMethodInvoker)); - - // Try invoking method - Assert.Throws(() => { testNativeMethod(); }); - } - - public class GenericClass - { - [NativeCallable] - public static void CallbackMethod(int n) - { - Assert.Fail($"Functions with attribute {nameof(NativeCallableAttribute)} within a generic type are invalid"); - } - } - - public static void NegativeTest_FromInstantiatedGenericClass() - { - Console.WriteLine($"Running {nameof(NegativeTest_FromInstantiatedGenericClass)}..."); - - /* - void TestNativeCallableInstGenericType() - { - .locals init ([0] native int ptr) - IL_0000: nop - IL_0001: ldftn void GenericClass::CallbackMethod(int) - IL_0007: stloc.0 - IL_0008: ret - } - */ - DynamicMethod testNativeCallable = new DynamicMethod("TestNativeCallableInstGenericClass", null, null, typeof(Program).Module); - ILGenerator il = testNativeCallable.GetILGenerator(); - il.DeclareLocal(typeof(IntPtr)); - il.Emit(OpCodes.Nop); - - // Get native function pointer of the callback from the instantiated generic class. - il.Emit(OpCodes.Ldftn, typeof(GenericClass).GetMethod(nameof(GenericClass.CallbackMethod))); - il.Emit(OpCodes.Stloc_0); - - il.Emit(OpCodes.Ret); - var testNativeMethod = (NativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(NativeMethodInvoker)); - - // Try invoking method - Assert.Throws(() => { testNativeMethod(); }); - } - - [NativeCallable] - public static void CallbackViaCalli(int val) - { - Assert.Fail($"Functions with attribute {nameof(NativeCallableAttribute)} cannot be called via calli"); - } - - public static void NegativeTest_ViaCalli() - { - Console.WriteLine($"{nameof(NegativeTest_ViaCalli)} function via calli instruction. The CLR _will_ crash."); - - /* - void TestNativeCallableViaCalli() - { - .locals init (native int V_0) - IL_0000: nop - IL_0001: ldftn void CallbackViaCalli(int32) - IL_0007: stloc.0 - - IL_0008: ldc.i4 1234 - IL_000d: ldloc.0 - IL_000e: calli void(int32) - - IL_0013: nop - IL_0014: ret - } - */ - DynamicMethod testNativeCallable = new DynamicMethod("TestNativeCallableViaCalli", null, null, typeof(Program).Module); - ILGenerator il = testNativeCallable.GetILGenerator(); - il.DeclareLocal(typeof(IntPtr)); - il.Emit(OpCodes.Nop); - - // Get native function pointer of the callback - il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackViaCalli))); - il.Emit(OpCodes.Stloc_0); - - il.Emit(OpCodes.Ldc_I4, 1234); - il.Emit(OpCodes.Ldloc_0); - il.EmitCalli(OpCodes.Calli, CallingConventions.Standard, null, new Type[] { typeof(int) }, null); - - il.Emit(OpCodes.Nop); - il.Emit(OpCodes.Ret); - - NativeMethodInvoker testNativeMethod = (NativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(NativeMethodInvoker)); - - // It is not possible to catch the resulting ExecutionEngineException exception. - // To observe the crashing behavior set a breakpoint in the ReversePInvokeBadTransition() function - // located in src/vm/dllimportcallback.cpp. - testNativeMethod(); - } - - [NativeCallable(CallingConvention = CallingConvention.StdCall)] - public static int CallbackViaUnmanagedCalli(int val) - { - return DoubleImpl(val); - } - - public static void TestNativeCallableViaUnmanagedCalli() - { - Console.WriteLine($"Running {nameof(TestNativeCallableViaUnmanagedCalli)}..."); - - /* - void NativeCallableViaCalli() - { - .locals init (native int V_0) - IL_0000: nop - IL_0001: ldftn int CallbackViaUnmanagedCalli(int32) - IL_0007: stloc.0 - - IL_0008: ldc.i4 1234 - IL_000d: ldloc.0 - IL_000e: calli int32 stdcall(int32) - - IL_0014: ret - } - */ - DynamicMethod testNativeCallable = new DynamicMethod("NativeCallableViaUnmanagedCalli", typeof(int), null, typeof(Program).Module); - ILGenerator il = testNativeCallable.GetILGenerator(); - il.DeclareLocal(typeof(IntPtr)); - il.Emit(OpCodes.Nop); - - // Get native function pointer of the callback - il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackViaUnmanagedCalli))); - il.Emit(OpCodes.Stloc_0); - - int n = 1234; - - il.Emit(OpCodes.Ldc_I4, n); - il.Emit(OpCodes.Ldloc_0); - il.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, typeof(int), new Type[] { typeof(int) }); - - il.Emit(OpCodes.Ret); - - IntNativeMethodInvoker testNativeMethod = (IntNativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(IntNativeMethodInvoker)); - - int expected = DoubleImpl(n); - Assert.AreEqual(expected, testNativeMethod()); - } - - [NativeCallable(CallingConvention = CallingConvention.StdCall)] - public static int CallbackViaUnmanagedCalliThrows(int val) - { - throw new Exception() { HResult = CallbackThrowsErrorCode }; - } - - public static void TestNativeCallableViaUnmanagedCalli_ThrowException() - { - Console.WriteLine($"Running {nameof(TestNativeCallableViaUnmanagedCalli_ThrowException)}..."); - - /* - void NativeCallableViaUnmanagedCalli_ThrowException() - { - .locals init (native int V_0) - IL_0000: nop - IL_0001: ldftn int CallbackViaUnmanagedCalliThrows(int32) - IL_0007: stloc.0 - - IL_0008: ldc.i4 1234 - IL_000d: ldloc.0 - IL_000e: calli int32 stdcall(int32) - - IL_0014: ret - } - */ - DynamicMethod testNativeCallable = new DynamicMethod("NativeCallableViaUnmanagedCalli_ThrowException", typeof(int), null, typeof(Program).Module); - ILGenerator il = testNativeCallable.GetILGenerator(); - il.DeclareLocal(typeof(IntPtr)); - il.Emit(OpCodes.Nop); - - // Get native function pointer of the callback - il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackViaUnmanagedCalliThrows))); - il.Emit(OpCodes.Stloc_0); - - int n = 1234; - - il.Emit(OpCodes.Ldc_I4, n); - il.Emit(OpCodes.Ldloc_0); - il.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, typeof(int), new Type[] { typeof(int) }); - - il.Emit(OpCodes.Ret); - - IntNativeMethodInvoker testNativeMethod = (IntNativeMethodInvoker)testNativeCallable.CreateDelegate(typeof(IntNativeMethodInvoker)); - - try - { - testNativeMethod(); - Assert.Fail($"Function {nameof(CallbackViaUnmanagedCalliThrows)} should throw"); - } - catch (Exception e) - { - Assert.AreEqual(CallbackThrowsErrorCode, e.HResult); - } - } -} diff --git a/src/coreclr/tests/src/Interop/NativeCallable/NativeCallableTest.csproj b/src/coreclr/tests/src/Interop/NativeCallable/NativeCallableTest.csproj deleted file mode 100644 index a485b23e3b68ea..00000000000000 --- a/src/coreclr/tests/src/Interop/NativeCallable/NativeCallableTest.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - Exe - 1 - - - - - - - - - - - diff --git a/src/coreclr/tests/src/Interop/PInvoke/Vector2_3_4/Vector2_3_4.cs b/src/coreclr/tests/src/Interop/PInvoke/Vector2_3_4/Vector2_3_4.cs index ab724068b60c4d..5d390bbd5ddbbb 100644 --- a/src/coreclr/tests/src/Interop/PInvoke/Vector2_3_4/Vector2_3_4.cs +++ b/src/coreclr/tests/src/Interop/PInvoke/Vector2_3_4/Vector2_3_4.cs @@ -22,7 +22,7 @@ public static int Main() } catch (System.Exception ex) { - Console.WriteLine(ex.ToString()); + Console.WriteLine(ex); return 101; } return 100; @@ -30,6 +30,7 @@ public static int Main() private static void RunVector2Tests() { + Console.WriteLine($"Running {nameof(RunVector2Tests)}... "); float X = StartingIntValue; float Y = StartingIntValue + 1; float Z = StartingIntValue + 232; @@ -68,9 +69,10 @@ private static void RunVector2Tests() return newVector; })); } - + private static void RunVector3Tests() { + Console.WriteLine($"Running {nameof(RunVector3Tests)}... "); float X = StartingIntValue; float Y = StartingIntValue + 1; float Z = StartingIntValue + 232; @@ -112,6 +114,7 @@ private static void RunVector3Tests() private static void RunVector4Tests() { + Console.WriteLine($"Running {nameof(RunVector4Tests)}... "); float X = StartingIntValue; float Y = StartingIntValue + 1; float Z = StartingIntValue + 232; diff --git a/src/coreclr/tests/src/Interop/UnmanagedCallersOnly/CMakeLists.txt b/src/coreclr/tests/src/Interop/UnmanagedCallersOnly/CMakeLists.txt new file mode 100644 index 00000000000000..d770209f982395 --- /dev/null +++ b/src/coreclr/tests/src/Interop/UnmanagedCallersOnly/CMakeLists.txt @@ -0,0 +1,10 @@ +project (UnmanagedCallersOnlyDll) +include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake") +set(SOURCES UnmanagedCallersOnlyDll.cpp ) + +# add the executable +add_library (UnmanagedCallersOnlyDll SHARED ${SOURCES}) +target_link_libraries(UnmanagedCallersOnlyDll ${LINK_LIBRARIES_ADDITIONAL}) + +# add the install targets +install (TARGETS UnmanagedCallersOnlyDll DESTINATION bin) diff --git a/src/coreclr/tests/src/Interop/NativeCallable/NativeCallableDll.cpp b/src/coreclr/tests/src/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyDll.cpp similarity index 100% rename from src/coreclr/tests/src/Interop/NativeCallable/NativeCallableDll.cpp rename to src/coreclr/tests/src/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyDll.cpp diff --git a/src/coreclr/tests/src/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs b/src/coreclr/tests/src/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs new file mode 100644 index 00000000000000..6c0acc1eab94e5 --- /dev/null +++ b/src/coreclr/tests/src/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.cs @@ -0,0 +1,644 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.InteropServices; +using System.Threading; +using TestLibrary; + +public class Program +{ + public static class UnmanagedCallersOnlyDll + { + [DllImport(nameof(UnmanagedCallersOnlyDll))] + public static extern int CallManagedProc(IntPtr callbackProc, int n); + + [DllImport(nameof(UnmanagedCallersOnlyDll))] + public static extern int CallManagedProcOnNewThread(IntPtr callbackProc, int n); + + [DllImport(nameof(UnmanagedCallersOnlyDll))] + // Returns -1 if exception was throw and caught. + public static extern int CallManagedProcCatchException(IntPtr callbackProc, int n); + } + + private delegate int IntNativeMethodInvoker(); + private delegate void NativeMethodInvoker(); + + public static int Main(string[] args) + { + try + { + TestUnmanagedCallersOnlyValid(); + TestUnmanagedCallersOnlyValid_OnNewNativeThread(); + TestUnmanagedCallersOnlyValid_PrepareMethod(); + NegativeTest_NonStaticMethod(); + NegativeTest_ViaDelegate(); + NegativeTest_NonBlittable(); + NegativeTest_NonInstantiatedGenericArguments(); + NegativeTest_InstantiatedGenericArguments(); + NegativeTest_FromInstantiatedGenericClass(); + TestUnmanagedCallersOnlyViaUnmanagedCalli(); + + // Exception handling is only supported on Windows. + if (TestLibrary.Utilities.IsWindows) + { + TestUnmanagedCallersOnlyValid_ThrowException(); + TestUnmanagedCallersOnlyViaUnmanagedCalli_ThrowException(); + } + + if (args.Length != 0 && args[0].Equals("calli")) + { + NegativeTest_ViaCalli(); + } + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + + return 100; + } + + [UnmanagedCallersOnly] + public static int ManagedDoubleCallback(int n) + { + return DoubleImpl(n); + } + + private static int DoubleImpl(int n) + { + return 2 * n; + } + + public static void TestUnmanagedCallersOnlyValid() + { + Console.WriteLine($"Running {nameof(TestUnmanagedCallersOnlyValid)}..."); + + /* + void UnmanagedCallersOnly() + { + .locals init ([0] native int ptr) + IL_0000: nop + IL_0001: ldftn int32 ManagedDoubleCallback(int32) + IL_0007: stloc.0 + + IL_0008: ldloc.0 + IL_0009: ldc.i4 local + IL_000e: call bool UnmanagedCallersOnlyDll::CallManagedProc(native int, int) + + IL_0013: ret + } + */ + DynamicMethod testUnmanagedCallersOnly = new DynamicMethod("UnmanagedCallersOnly", typeof(int), null, typeof(Program).Module); + ILGenerator il = testUnmanagedCallersOnly.GetILGenerator(); + il.DeclareLocal(typeof(IntPtr)); + il.Emit(OpCodes.Nop); + + // Get native function pointer of the callback + il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(ManagedDoubleCallback))); + il.Emit(OpCodes.Stloc_0); + il.Emit(OpCodes.Ldloc_0); + + int n = 12345; + il.Emit(OpCodes.Ldc_I4, n); + il.Emit(OpCodes.Call, typeof(UnmanagedCallersOnlyDll).GetMethod("CallManagedProc")); + il.Emit(OpCodes.Ret); + var testNativeMethod = (IntNativeMethodInvoker)testUnmanagedCallersOnly.CreateDelegate(typeof(IntNativeMethodInvoker)); + + int expected = DoubleImpl(n); + Assert.AreEqual(expected, testNativeMethod()); + } + + public static void TestUnmanagedCallersOnlyValid_OnNewNativeThread() + { + Console.WriteLine($"Running {nameof(TestUnmanagedCallersOnlyValid_OnNewNativeThread)}..."); + + /* + void UnmanagedCallersOnlyOnNewNativeThread() + { + .locals init ([0] native int ptr) + IL_0000: nop + IL_0001: ldftn int32 ManagedDoubleCallback(int32) + IL_0007: stloc.0 + + IL_0008: ldloc.0 + IL_0009: ldc.i4 local + IL_000e: call bool UnmanagedCallersOnlyDll::CallManagedProcOnNewThread(native int, int) + + IL_0013: ret + } + */ + DynamicMethod testUnmanagedCallersOnly = new DynamicMethod("UnmanagedCallersOnlyOnNewNativeThread", typeof(int), null, typeof(Program).Module); + ILGenerator il = testUnmanagedCallersOnly.GetILGenerator(); + il.DeclareLocal(typeof(IntPtr)); + il.Emit(OpCodes.Nop); + + // Get native function pointer of the callback + il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(ManagedDoubleCallback))); + il.Emit(OpCodes.Stloc_0); + il.Emit(OpCodes.Ldloc_0); + + int n = 12345; + il.Emit(OpCodes.Ldc_I4, n); + il.Emit(OpCodes.Call, typeof(UnmanagedCallersOnlyDll).GetMethod("CallManagedProcOnNewThread")); + il.Emit(OpCodes.Ret); + var testNativeMethod = (IntNativeMethodInvoker)testUnmanagedCallersOnly.CreateDelegate(typeof(IntNativeMethodInvoker)); + + int expected = DoubleImpl(n); + Assert.AreEqual(expected, testNativeMethod()); + } + + [UnmanagedCallersOnly] + public static int ManagedCallback_Prepared(int n) + { + return DoubleImpl(n); + } + + // This test is about the interaction between Tiered Compilation and the UnmanagedCallersOnlyAttribute. + public static void TestUnmanagedCallersOnlyValid_PrepareMethod() + { + Console.WriteLine($"Running {nameof(TestUnmanagedCallersOnlyValid_PrepareMethod)}..."); + + /* + void UnmanagedCallersOnlyOnNewNativeThread() + { + .locals init ([0] native int ptr) + IL_0000: nop + IL_0001: ldftn int32 ManagedCallback_Prepared(int32) + IL_0007: stloc.0 + + IL_0008: ldloc.0 + IL_0009: ldc.i4 local + IL_000e: call bool UnmanagedCallersOnlyDll::CallManagedProcOnNewThread(native int, int) + + IL_0013: ret + } + */ + DynamicMethod testUnmanagedCallersOnly = new DynamicMethod("UnmanagedCallersOnlyValid_PrepareMethod", typeof(int), null, typeof(Program).Module); + ILGenerator il = testUnmanagedCallersOnly.GetILGenerator(); + il.DeclareLocal(typeof(IntPtr)); + il.Emit(OpCodes.Nop); + + // Prepare the managed callback. + var preparedCallback = typeof(Program).GetMethod(nameof(ManagedCallback_Prepared)); + RuntimeHelpers.PrepareMethod(preparedCallback.MethodHandle); + + // Get native function pointer of the callback + il.Emit(OpCodes.Ldftn, preparedCallback); + il.Emit(OpCodes.Stloc_0); + il.Emit(OpCodes.Ldloc_0); + + int n = 12345; + il.Emit(OpCodes.Ldc_I4, n); + il.Emit(OpCodes.Call, typeof(UnmanagedCallersOnlyDll).GetMethod("CallManagedProcOnNewThread")); + il.Emit(OpCodes.Ret); + var testNativeMethod = (IntNativeMethodInvoker)testUnmanagedCallersOnly.CreateDelegate(typeof(IntNativeMethodInvoker)); + + // Call enough to attempt to trigger Tiered Compilation from a new thread. + for (int i = 0; i < 100; ++i) + { + testNativeMethod(); + } + } + + private const int CallbackThrowsErrorCode = 27; + + [UnmanagedCallersOnly] + public static int CallbackThrows(int val) + { + throw new Exception() { HResult = CallbackThrowsErrorCode }; + } + + public static void TestUnmanagedCallersOnlyValid_ThrowException() + { + Console.WriteLine($"Running {nameof(TestUnmanagedCallersOnlyValid_ThrowException)}..."); + + /* + void UnmanagedCallersOnlyValid_ThrowException() + { + .locals init ([0] native int ptr) + IL_0000: nop + IL_0001: ldftn int32 CallbackThrows(int32) + IL_0007: stloc.0 + + IL_0008: ldloc.0 + IL_0009: ldc.i4 local + IL_000e: call bool UnmanagedCallersOnlyDll::CallManagedProcCatchException(native int, int) + + IL_0013: ret + } + */ + DynamicMethod testUnmanagedCallersOnly = new DynamicMethod("UnmanagedCallersOnlyValid_ThrowException", typeof(int), null, typeof(Program).Module); + ILGenerator il = testUnmanagedCallersOnly.GetILGenerator(); + il.DeclareLocal(typeof(IntPtr)); + il.Emit(OpCodes.Nop); + + // Get native function pointer of the callback + il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackThrows))); + il.Emit(OpCodes.Stloc_0); + il.Emit(OpCodes.Ldloc_0); + + int n = 12345; + il.Emit(OpCodes.Ldc_I4, n); + il.Emit(OpCodes.Call, typeof(UnmanagedCallersOnlyDll).GetMethod("CallManagedProcCatchException")); + il.Emit(OpCodes.Ret); + var testNativeMethod = (IntNativeMethodInvoker)testUnmanagedCallersOnly.CreateDelegate(typeof(IntNativeMethodInvoker)); + + // Method should have thrown and caught an exception. + Assert.AreEqual(-1, testNativeMethod()); + } + + public static void NegativeTest_ViaDelegate() + { + Console.WriteLine($"Running {nameof(NegativeTest_ViaDelegate)}..."); + + // Try invoking method directly + Assert.Throws(() => { CallAsDelegate(); }); + + // Local function to delay exception thrown during JIT + void CallAsDelegate() + { + Func invoker = ManagedDoubleCallback; + invoker(0); + } + } + + [UnmanagedCallersOnly] + public int CallbackNonStatic(int val) + { + Assert.Fail($"Instance functions with attribute {nameof(UnmanagedCallersOnlyAttribute)} are invalid"); + return -1; + } + + public static void NegativeTest_NonStaticMethod() + { + Console.WriteLine($"Running {nameof(NegativeTest_NonStaticMethod)}..."); + + /* + void TestUnmanagedCallersOnlyNonStatic() + { + .locals init ([0] native int ptr) + IL_0000: nop + IL_0001: ldftn int CallbackNonStatic(int) + IL_0007: stloc.0 + + IL_0008: ldloc.0 + IL_0009: ldc.i4 local + IL_000e: call bool UnmanagedCallersOnlyDll::CallManagedProc(native int, int) + + IL_0013: ret + } + */ + DynamicMethod testUnmanagedCallersOnly = new DynamicMethod("TestUnmanagedCallersOnlyNonStatic", null, null, typeof(Program).Module); + ILGenerator il = testUnmanagedCallersOnly.GetILGenerator(); + il.DeclareLocal(typeof(IntPtr)); + il.Emit(OpCodes.Nop); + + // Get native function pointer of the callback + il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackNonStatic))); + il.Emit(OpCodes.Stloc_0); + il.Emit(OpCodes.Ldloc_0); + + int n = 12345; + il.Emit(OpCodes.Ldc_I4, n); + il.Emit(OpCodes.Call, typeof(UnmanagedCallersOnlyDll).GetMethod("CallManagedProc")); + il.Emit(OpCodes.Ret); + + var testNativeMethod = (NativeMethodInvoker)testUnmanagedCallersOnly.CreateDelegate(typeof(NativeMethodInvoker)); + + // Try invoking method + Assert.Throws(() => { testNativeMethod(); }); + } + + [UnmanagedCallersOnly] + public static int CallbackMethodNonBlittable(bool x1) + { + Assert.Fail($"Functions with attribute {nameof(UnmanagedCallersOnlyAttribute)} cannot have non-blittable arguments"); + return -1; + } + + public static void NegativeTest_NonBlittable() + { + Console.WriteLine($"Running {nameof(NegativeTest_NonBlittable)}..."); + + /* + void TestUnmanagedCallersOnlyNonBlittable() + { + .locals init ([0] native int ptr) + IL_0000: nop + IL_0001: ldftn int CallbackMethodNonBlittable(bool) + IL_0007: stloc.0 + + IL_0008: ldloc.0 + IL_0009: ldc.i4 local + IL_000e: call bool UnmanagedCallersOnlyDll::CallManagedProc(native int, int) + + IL_0013: ret + } + */ + DynamicMethod testUnmanagedCallersOnly = new DynamicMethod("TestUnmanagedCallersOnlyNonBlittable", null, null, typeof(Program).Module); + ILGenerator il = testUnmanagedCallersOnly.GetILGenerator(); + il.DeclareLocal(typeof(IntPtr)); + il.Emit(OpCodes.Nop); + + // Get native function pointer of the callback + il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackMethodNonBlittable))); + il.Emit(OpCodes.Stloc_0); + il.Emit(OpCodes.Ldloc_0); + + int n = 12345; + il.Emit(OpCodes.Ldc_I4, n); + il.Emit(OpCodes.Call, typeof(UnmanagedCallersOnlyDll).GetMethod("CallManagedProc")); + il.Emit(OpCodes.Ret); + + var testNativeMethod = (NativeMethodInvoker)testUnmanagedCallersOnly.CreateDelegate(typeof(NativeMethodInvoker)); + + // Try invoking method + Assert.Throws(() => { testNativeMethod(); }); + } + + [UnmanagedCallersOnly] + public static int CallbackMethodGeneric(T arg) + { + Assert.Fail($"Functions with attribute {nameof(UnmanagedCallersOnlyAttribute)} cannot have generic arguments"); + return -1; + } + + public static void NegativeTest_NonInstantiatedGenericArguments() + { + Console.WriteLine($"Running {nameof(NegativeTest_NonInstantiatedGenericArguments)}..."); + + /* + void TestUnmanagedCallersOnlyNonInstGenericArguments() + { + .locals init ([0] native int ptr) + IL_0000: nop + IL_0001: ldftn void CallbackMethodGeneric(T) + IL_0007: stloc.0 + IL_0008: ret + } + */ + DynamicMethod testUnmanagedCallersOnly = new DynamicMethod("TestUnmanagedCallersOnlyNonInstGenericArguments", null, null, typeof(Program).Module); + ILGenerator il = testUnmanagedCallersOnly.GetILGenerator(); + il.DeclareLocal(typeof(IntPtr)); + il.Emit(OpCodes.Nop); + + // Get native function pointer of the callback + il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackMethodGeneric))); + il.Emit(OpCodes.Stloc_0); + + il.Emit(OpCodes.Ret); + var testNativeMethod = (NativeMethodInvoker)testUnmanagedCallersOnly.CreateDelegate(typeof(NativeMethodInvoker)); + + // Try invoking method + Assert.Throws(() => { testNativeMethod(); }); + } + + public static void NegativeTest_InstantiatedGenericArguments() + { + Console.WriteLine($"Running {nameof(NegativeTest_InstantiatedGenericArguments)}..."); + + /* + void TestUnmanagedCallersOnlyInstGenericArguments() + { + .locals init ([0] native int ptr) + IL_0000: nop + IL_0001: ldftn void CallbackMethodGeneric(int) + IL_0007: stloc.0 + + IL_0008: ldloc.0 + IL_0009: ldc.i4 local + IL_000e: call bool UnmanagedCallersOnlyDll::CallManagedProc(native int, int) + + IL_0013: ret + } + */ + DynamicMethod testUnmanagedCallersOnly = new DynamicMethod("TestUnmanagedCallersOnlyInstGenericArguments", null, null, typeof(Program).Module); + ILGenerator il = testUnmanagedCallersOnly.GetILGenerator(); + il.DeclareLocal(typeof(IntPtr)); + il.Emit(OpCodes.Nop); + + // Get native function pointer of the instantiated generic callback + il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackMethodGeneric)).MakeGenericMethod(new [] { typeof(int) })); + il.Emit(OpCodes.Stloc_0); + il.Emit(OpCodes.Ldloc_0); + + int n = 12345; + il.Emit(OpCodes.Ldc_I4, n); + il.Emit(OpCodes.Call, typeof(UnmanagedCallersOnlyDll).GetMethod("CallManagedProc")); + il.Emit(OpCodes.Ret); + + var testNativeMethod = (NativeMethodInvoker)testUnmanagedCallersOnly.CreateDelegate(typeof(NativeMethodInvoker)); + + // Try invoking method + Assert.Throws(() => { testNativeMethod(); }); + } + + public class GenericClass + { + [UnmanagedCallersOnly] + public static void CallbackMethod(int n) + { + Assert.Fail($"Functions with attribute {nameof(UnmanagedCallersOnlyAttribute)} within a generic type are invalid"); + } + } + + public static void NegativeTest_FromInstantiatedGenericClass() + { + Console.WriteLine($"Running {nameof(NegativeTest_FromInstantiatedGenericClass)}..."); + + /* + void TestUnmanagedCallersOnlyInstGenericType() + { + .locals init ([0] native int ptr) + IL_0000: nop + IL_0001: ldftn int GenericClass::CallbackMethod(int) + IL_0007: stloc.0 + + IL_0008: ldloc.0 + IL_0009: ldc.i4 local + IL_000e: call bool UnmanagedCallersOnlyDll::CallManagedProc(native int, int) + + IL_0013: ret + } + */ + DynamicMethod testUnmanagedCallersOnly = new DynamicMethod("TestUnmanagedCallersOnlyInstGenericClass", null, null, typeof(Program).Module); + ILGenerator il = testUnmanagedCallersOnly.GetILGenerator(); + il.DeclareLocal(typeof(IntPtr)); + il.Emit(OpCodes.Nop); + + // Get native function pointer of the callback from the instantiated generic class. + il.Emit(OpCodes.Ldftn, typeof(GenericClass).GetMethod(nameof(GenericClass.CallbackMethod))); + il.Emit(OpCodes.Stloc_0); + il.Emit(OpCodes.Ldloc_0); + + int n = 12345; + il.Emit(OpCodes.Ldc_I4, n); + il.Emit(OpCodes.Call, typeof(UnmanagedCallersOnlyDll).GetMethod("CallManagedProc")); + il.Emit(OpCodes.Ret); + + var testNativeMethod = (NativeMethodInvoker)testUnmanagedCallersOnly.CreateDelegate(typeof(NativeMethodInvoker)); + + // Try invoking method + Assert.Throws(() => { testNativeMethod(); }); + } + + [UnmanagedCallersOnly] + public static void CallbackViaCalli(int val) + { + Assert.Fail($"Functions with attribute {nameof(UnmanagedCallersOnlyAttribute)} cannot be called via calli"); + } + + public static void NegativeTest_ViaCalli() + { + Console.WriteLine($"{nameof(NegativeTest_ViaCalli)} function via calli instruction. The CLR _will_ crash."); + + /* + void TestUnmanagedCallersOnlyViaCalli() + { + .locals init (native int V_0) + IL_0000: nop + IL_0001: ldftn void CallbackViaCalli(int32) + IL_0007: stloc.0 + + IL_0008: ldc.i4 1234 + IL_000d: ldloc.0 + IL_000e: calli void(int32) + + IL_0013: nop + IL_0014: ret + } + */ + DynamicMethod testUnmanagedCallersOnly = new DynamicMethod("TestUnmanagedCallersOnlyViaCalli", null, null, typeof(Program).Module); + ILGenerator il = testUnmanagedCallersOnly.GetILGenerator(); + il.DeclareLocal(typeof(IntPtr)); + il.Emit(OpCodes.Nop); + + // Get native function pointer of the callback + il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackViaCalli))); + il.Emit(OpCodes.Stloc_0); + + il.Emit(OpCodes.Ldc_I4, 1234); + il.Emit(OpCodes.Ldloc_0); + il.EmitCalli(OpCodes.Calli, CallingConventions.Standard, null, new Type[] { typeof(int) }, null); + + il.Emit(OpCodes.Nop); + il.Emit(OpCodes.Ret); + + NativeMethodInvoker testNativeMethod = (NativeMethodInvoker)testUnmanagedCallersOnly.CreateDelegate(typeof(NativeMethodInvoker)); + + // It is not possible to catch the resulting ExecutionEngineException exception. + // To observe the crashing behavior set a breakpoint in the ReversePInvokeBadTransition() function + // located in src/vm/dllimportcallback.cpp. + testNativeMethod(); + } + + [UnmanagedCallersOnly(CallingConvention = CallingConvention.StdCall)] + public static int CallbackViaUnmanagedCalli(int val) + { + return DoubleImpl(val); + } + + public static void TestUnmanagedCallersOnlyViaUnmanagedCalli() + { + Console.WriteLine($"Running {nameof(TestUnmanagedCallersOnlyViaUnmanagedCalli)}..."); + + /* + void UnmanagedCallersOnlyViaCalli() + { + .locals init (native int V_0) + IL_0000: nop + IL_0001: ldftn int CallbackViaUnmanagedCalli(int32) + IL_0007: stloc.0 + + IL_0008: ldc.i4 1234 + IL_000d: ldloc.0 + IL_000e: calli int32 stdcall(int32) + + IL_0014: ret + } + */ + DynamicMethod testUnmanagedCallersOnly = new DynamicMethod("UnmanagedCallersOnlyViaUnmanagedCalli", typeof(int), null, typeof(Program).Module); + ILGenerator il = testUnmanagedCallersOnly.GetILGenerator(); + il.DeclareLocal(typeof(IntPtr)); + il.Emit(OpCodes.Nop); + + // Get native function pointer of the callback + il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackViaUnmanagedCalli))); + il.Emit(OpCodes.Stloc_0); + + int n = 1234; + + il.Emit(OpCodes.Ldc_I4, n); + il.Emit(OpCodes.Ldloc_0); + il.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, typeof(int), new Type[] { typeof(int) }); + + il.Emit(OpCodes.Ret); + + IntNativeMethodInvoker testNativeMethod = (IntNativeMethodInvoker)testUnmanagedCallersOnly.CreateDelegate(typeof(IntNativeMethodInvoker)); + + int expected = DoubleImpl(n); + Assert.AreEqual(expected, testNativeMethod()); + } + + [UnmanagedCallersOnly(CallingConvention = CallingConvention.StdCall)] + public static int CallbackViaUnmanagedCalliThrows(int val) + { + throw new Exception() { HResult = CallbackThrowsErrorCode }; + } + + public static void TestUnmanagedCallersOnlyViaUnmanagedCalli_ThrowException() + { + Console.WriteLine($"Running {nameof(TestUnmanagedCallersOnlyViaUnmanagedCalli_ThrowException)}..."); + + /* + void UnmanagedCallersOnlyViaUnmanagedCalli_ThrowException() + { + .locals init (native int V_0) + IL_0000: nop + IL_0001: ldftn int CallbackViaUnmanagedCalliThrows(int32) + IL_0007: stloc.0 + + IL_0008: ldc.i4 1234 + IL_000d: ldloc.0 + IL_000e: calli int32 stdcall(int32) + + IL_0014: ret + } + */ + DynamicMethod testUnmanagedCallersOnly = new DynamicMethod("UnmanagedCallersOnlyViaUnmanagedCalli_ThrowException", typeof(int), null, typeof(Program).Module); + ILGenerator il = testUnmanagedCallersOnly.GetILGenerator(); + il.DeclareLocal(typeof(IntPtr)); + il.Emit(OpCodes.Nop); + + // Get native function pointer of the callback + il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(CallbackViaUnmanagedCalliThrows))); + il.Emit(OpCodes.Stloc_0); + + int n = 1234; + + il.Emit(OpCodes.Ldc_I4, n); + il.Emit(OpCodes.Ldloc_0); + il.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, typeof(int), new Type[] { typeof(int) }); + + il.Emit(OpCodes.Ret); + + IntNativeMethodInvoker testNativeMethod = (IntNativeMethodInvoker)testUnmanagedCallersOnly.CreateDelegate(typeof(IntNativeMethodInvoker)); + + try + { + testNativeMethod(); + Assert.Fail($"Function {nameof(CallbackViaUnmanagedCalliThrows)} should throw"); + } + catch (Exception e) + { + Assert.AreEqual(CallbackThrowsErrorCode, e.HResult); + } + } +} diff --git a/src/coreclr/tests/src/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.csproj b/src/coreclr/tests/src/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.csproj new file mode 100644 index 00000000000000..efd50bf70f9b59 --- /dev/null +++ b/src/coreclr/tests/src/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.csproj @@ -0,0 +1,15 @@ + + + Exe + 1 + + + + + + + + + + + diff --git a/src/coreclr/tests/src/Interop/common/ComHelpers.h b/src/coreclr/tests/src/Interop/common/ComHelpers.h index c90ff7a773a2e0..673f19063647d3 100644 --- a/src/coreclr/tests/src/Interop/common/ComHelpers.h +++ b/src/coreclr/tests/src/Interop/common/ComHelpers.h @@ -105,6 +105,12 @@ class UnknownImpl return c; } +protected: + ULONG GetRefCount() + { + return _refCount; + } + private: std::atomic _refCount = 1; }; diff --git a/src/coreclr/tests/src/JIT/Directed/IL/PInvokeTail/PInvokeTail.il b/src/coreclr/tests/src/JIT/Directed/IL/PInvokeTail/PInvokeTail.il index 4fd1840cde0967..b9eb324067003f 100644 --- a/src/coreclr/tests/src/JIT/Directed/IL/PInvokeTail/PInvokeTail.il +++ b/src/coreclr/tests/src/JIT/Directed/IL/PInvokeTail/PInvokeTail.il @@ -13,7 +13,6 @@ { } - .class public auto ansi Wrapper { .method public static pinvokeimpl("msvcrt.dll" cdecl) int32 puts(int8* A_0) il managed preservesig{ } @@ -28,78 +27,65 @@ } // end of class 'Wrapper' -.method public static int32 ?callputs1@@YAHXZ() il managed +.method public static pinvokeimpl("msvcrt.dll" cdecl) int32 puts(int8* A_0) il managed preservesig{ } + +.method public static int32 callputs1(char&) il managed { - .maxstack 1 + .maxstack 1 - IL_0000: ldstr bytearray(48 65 6C 6C 6F 20 57 6F 72 6C 64 21 00 00 00 00) //ldptr D_00003000 - IL_0005: tail. call int32 puts(int8*) - IL_000a: ret -} // end of global method '?callputs1@@YAHXZ' + ldarg.0 + conv.i + tail. call int32 puts(int8*) + ret +} // end of global method 'callputs1' -.method public static int32 ?callputs2@@YAHXZ() il managed +.method public static int32 callputs2(char&) il managed { - .maxstack 1 + .maxstack 1 - IL_0000: ldstr bytearray(48 65 6C 6C 6F 20 57 6F 72 6C 64 21 00 00 00 00) //" " //ldptr D_00003010 - IL_0005: tail. call int32 Wrapper::puts(int8*) - IL_000a: ret -} // end of global method '?callputs2@@YAHXZ' + ldarg.0 + conv.i + tail. call int32 Wrapper::puts(int8*) + ret +} // end of global method 'callputs2' .method public static int32 main() il managed { - .entrypoint - .maxstack 2 - - IL_0000: call int32 ?callputs1@@YAHXZ() - IL_0005: ldc.i4 0x0 - IL_000a: bge IL_0029 - - IL_000f: call class [mscorlib]System.IO.TextWriter [System.Console]System.Console::get_Out() - IL_0014: ldstr "Puts Failed" //ldptr D_00003020 - IL_0019: //newobj instance void [mscorlib]System.String::.ctor(wchar*) - IL_001e: callvirt instance void [mscorlib]System.IO.TextWriter::WriteLine(string) - IL_0023: ldc.i4 0x1 - IL_0028: ret - - IL_0029: call int32 ?callputs2@@YAHXZ() - IL_002e: ldc.i4 0x0 - IL_0033: bge IL_0052 - - IL_0038: call class [mscorlib]System.IO.TextWriter [System.Console]System.Console::get_Out() - IL_003d: ldstr "wrapper: Puts failed"//ldptr D_00003040 - IL_0042: //newobj instance void [mscorlib]System.String::.ctor(wchar*) - IL_0047: callvirt instance void [mscorlib]System.IO.TextWriter::WriteLine(string) - IL_004c: ldc.i4 0x1 - IL_0051: ret - - IL_0052: call class [mscorlib]System.IO.TextWriter [System.Console]System.Console::get_Out() - IL_0057: ldstr "passed"//ldptr D_00003070 - IL_005c: //newobj instance void [mscorlib]System.String::.ctor(wchar*) - IL_0061: callvirt instance void [mscorlib]System.IO.TextWriter::WriteLine(string) - IL_0066: ldc.i4 0x64 - IL_006b: ret + .entrypoint + .maxstack 4 + .locals init (char& pinned) + + ldstr bytearray(48 65 6C 6C 6F 20 57 6F 72 6C 64 21 00 00 00 00) // "Hello World!" + call instance char& modreq([mscorlib]System.Runtime.InteropServices.InAttribute) [mscorlib]System.String::GetPinnableReference() + stloc.0 + + ldloc.0 + call int32 callputs1(char&) + ldc.i4 0x0 + bge PASS_1 + + call class [mscorlib]System.IO.TextWriter [System.Console]System.Console::get_Out() + ldstr "puts() failed" + callvirt instance void [mscorlib]System.IO.TextWriter::WriteLine(string) + ldc.i4 0x1 + ret + + PASS_1: + ldloc.0 + call int32 callputs2(char&) + ldc.i4 0x0 + bge PASS_2 + + call class [mscorlib]System.IO.TextWriter [System.Console]System.Console::get_Out() + ldstr "puts() failed" + callvirt instance void [mscorlib]System.IO.TextWriter::WriteLine(string) + ldc.i4 0x1 + ret + + PASS_2: + call class [mscorlib]System.IO.TextWriter [System.Console]System.Console::get_Out() + ldstr "Passed" + callvirt instance void [mscorlib]System.IO.TextWriter::WriteLine(string) + ldc.i4 0x64 + ret } // end of global method 'main' - -.method public static int32 _mainMSIL(int32 argc,int8** argv,int8** envp) il managed -{ - .maxstack 1 - - IL_0000: tail. call int32 main() - IL_0005: ret -} // end of global method '_mainMSIL' - -.method public static pinvokeimpl("msvcrt.dll" cdecl) int32 puts(int8* A_0) il managed preservesig{ } -.data D_00003000 = bytearray ( - 48 65 6C 6C 6F 20 57 6F 72 6C 64 21 00 00 00 00) // Hello World!.... -.data D_00003010 = bytearray ( - 48 65 6C 6C 6F 20 57 6F 72 6C 64 21 00 00 00 00) // Hello World!.... -.data D_00003020 = bytearray ( - 70 00 75 00 74 00 73 00 28 00 29 00 20 00 66 00 // p.u.t.s.(.). .f. - 61 00 69 00 6C 00 65 00 64 00 2E 00 00 00 00 00) // a.i.l.e.d....... -.data D_00003040 = bytearray ( - 57 00 72 00 61 00 70 00 70 00 65 00 72 00 3A 00 // W.r.a.p.p.e.r.:. - 3A 00 70 00 75 00 74 00 73 00 28 00 29 00 20 00 // :.p.u.t.s.(.). . - 66 00 61 00 69 00 6C 00 65 00 64 00 2E 00 00 00) // f.a.i.l.e.d..... -.data D_00003070 = bytearray ( - 50 00 61 00 73 00 73 00 65 00 64 00 00 00) // P.a.s.s.e.d... diff --git a/src/coreclr/tests/src/JIT/Directed/StructABI/StructABI.csproj b/src/coreclr/tests/src/JIT/Directed/StructABI/StructABI.csproj index d43bf082a225b5..696b406cf0b98c 100644 --- a/src/coreclr/tests/src/JIT/Directed/StructABI/StructABI.csproj +++ b/src/coreclr/tests/src/JIT/Directed/StructABI/StructABI.csproj @@ -16,7 +16,7 @@ - + diff --git a/src/coreclr/tests/src/JIT/Directed/StructABI/StructWithOverlappingFields.cs b/src/coreclr/tests/src/JIT/Directed/StructABI/StructWithOverlappingFields.cs new file mode 100644 index 00000000000000..d6d9d34ed477a7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/Directed/StructABI/StructWithOverlappingFields.cs @@ -0,0 +1,129 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// This test originally showed incorrect VN for different fields with the same offset. + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Opt_Error +{ + [StructLayout(LayoutKind.Explicit, Pack = 1)] + public class FourByteClass + { + [FieldOffset(0)] + public int val; + [FieldOffset(0)] + public uint uval; + [FieldOffset(0)] + public float fval; + [FieldOffset(0)] + public byte b0; + [FieldOffset(1)] + public byte b1; + [FieldOffset(2)] + public byte b2; + [FieldOffset(3)] + public byte b3; + + public FourByteClass(int val) + { + val = val; + } + } + + [StructLayout(LayoutKind.Explicit, Pack = 1)] + public struct FourByteStruct + { + [FieldOffset(0)] + public int val; + [FieldOffset(0)] + public uint uval; + [FieldOffset(0)] + public float fval; + [FieldOffset(0)] + public byte b0; + [FieldOffset(1)] + public byte b1; + [FieldOffset(2)] + public byte b2; + [FieldOffset(3)] + public byte b3; + + public FourByteStruct(int val) + { + this.val = 0; + uval = 0; + fval = 0; + b0 = 0; + b1 = 0; + b2 = 0; + b3 = 0; + this.val = val; + } + } + + class Program + { + static void TestClass(int initVal) + { + FourByteClass fb = new FourByteClass(initVal); + fb.fval = 0; + fb.b0 = 1; + fb.uval = 2; + + int cseb0_1 = fb.b0 * 5 + 3; + uint cse_uval_1 = fb.uval * 2 - 5 + fb.uval; + int cse_val_1 = fb.val * 7 - 4 + fb.val * 7; + + Console.WriteLine("First result: " + cseb0_1 + ", " + cse_uval_1 + ", " + cse_val_1 + ";"); + Debug.Assert(cseb0_1 == 13); + Debug.Assert(cse_uval_1 == 1); + Debug.Assert(cse_val_1 == 24); + fb.val = 4; + int cseb0_2 = fb.b0 * 5 + 3; + uint cse_uval_2 = fb.uval * 2 - 5 + fb.uval; + int cse_val_2 = fb.val * 7 - 4 + fb.val * 7; + + Console.WriteLine("Second result: " + cseb0_2 + ", " + cse_uval_2 + ", " + cse_val_2 + ";"); + Debug.Assert(cseb0_2 == 23); + Debug.Assert(cse_uval_2 == 7); + Debug.Assert(cse_val_2 == 52); + } + + static void TestStruct(int initVal) + { + FourByteStruct fb = new FourByteStruct(initVal); + fb.fval = 0; + fb.b0 = 1; + fb.uval = 2; + + int cseb0_1 = fb.b0 * 5 + 3; + uint cse_uval_1 = fb.uval * 2 - 5 + fb.uval; + int cse_val_1 = fb.val * 7 - 4 + fb.val * 7; + + Console.WriteLine("First result: " + cseb0_1 + ", " + cse_uval_1 + ", " + cse_val_1 + ";"); + Debug.Assert(cseb0_1 == 13); + Debug.Assert(cse_uval_1 == 1); + Debug.Assert(cse_val_1 == 24); + fb.val = 4; + int cseb0_2 = fb.b0 * 5 + 3; + uint cse_uval_2 = fb.uval * 2 - 5 + fb.uval; + int cse_val_2 = fb.val * 7 - 4 + fb.val * 7; + + Console.WriteLine("Second result: " + cseb0_2 + ", " + cse_uval_2 + ", " + cse_val_2 + ";"); + Debug.Assert(cseb0_2 == 23); + Debug.Assert(cse_uval_2 == 7); + Debug.Assert(cse_val_2 == 52); + } + + static int Main(string[] args) + { + TestClass(2); + TestStruct(2); + return 100; + } + } +} diff --git a/src/coreclr/tests/src/JIT/Directed/StructABI/StructWithOverlappingFields.csproj b/src/coreclr/tests/src/JIT/Directed/StructABI/StructWithOverlappingFields.csproj new file mode 100644 index 00000000000000..40fbb16bdf90f2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/Directed/StructABI/StructWithOverlappingFields.csproj @@ -0,0 +1,13 @@ + + + Exe + 1 + + + PdbOnly + True + + + + + diff --git a/src/coreclr/tests/src/JIT/Directed/StructABI/structreturn.cs b/src/coreclr/tests/src/JIT/Directed/StructABI/structreturn.cs new file mode 100644 index 00000000000000..226818941c806c --- /dev/null +++ b/src/coreclr/tests/src/JIT/Directed/StructABI/structreturn.cs @@ -0,0 +1,1341 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// Test register struct returns and local vars retyping cases. + +using System; +using System.Numerics; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +#region Test struct return optimizations. +class TestStructReturns +{ + struct LessNativeInt + { + public bool a; + public bool b; + } + + struct NativeIntOneField + { + public long a; + } + + struct NativeIntTwoFields + { + public int a; + public int b; + } + + struct NativeIntFloatField + { + public double a; + } + + struct NativeIntMixedFields + { + public int a; + public float b; + } + + static LessNativeInt TestLessNativeIntReturnBlockInit() + { + LessNativeInt a = new LessNativeInt(); + return a; + } + + static LessNativeInt TestLessNativeIntReturnFieldInit() + { + LessNativeInt a; + a.a = false; + a.b = true; + return a; + } + + + static NativeIntOneField TestNativeIntOneFieldReturnBlockInit() + { + NativeIntOneField a = new NativeIntOneField(); + return a; + } + + static NativeIntOneField TestNativeIntOneFieldReturnFieldInit() + { + NativeIntOneField a; + a.a = 100; + return a; + } + + static NativeIntTwoFields TestNativeIntTwoFieldsReturnBlockInit() + { + NativeIntTwoFields a = new NativeIntTwoFields(); + return a; + } + + static NativeIntTwoFields TestNativeIntTwoFieldsReturnFieldInit() + { + NativeIntTwoFields a; + a.a = 100; + a.b = 10; + return a; + } + + static NativeIntFloatField TestNativeIntFloatFieldReturnBlockInit() + { + NativeIntFloatField a = new NativeIntFloatField(); + return a; + } + + static NativeIntFloatField TestNativeIntFloatFieldReturnFieldInit() + { + NativeIntFloatField a; + a.a = 100; + return a; + } + + static NativeIntMixedFields TestNativeIntMixedFieldsReturnBlockInit() + { + NativeIntMixedFields a = new NativeIntMixedFields(); + return a; + } + + static NativeIntMixedFields TestNativeIntMixedFieldsReturnFieldInit() + { + NativeIntMixedFields a; + a.a = 100; + a.b = 10; + return a; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int TestLessNativeIntCall1() + { + int res = 0; + var v = TestLessNativeIntReturnBlockInit(); + if (v.a) + { + res++; + } + if (v.b) + { + res++; + } + if (v.a && v.b) + { + res++; + } + if (!v.a && !v.b) + { + res--; + } + return res; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int TestLessNativeIntCall2() + { + int res = 0; + var v = TestLessNativeIntReturnFieldInit(); + if (v.a) + { + res++; + } + if (v.b) + { + res++; + } + if (v.a && v.b) + { + res++; + } + if (!v.a && !v.b) + { + res--; + } + return res; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int TestNativeIntOneFieldCall1() + { + int res = 0; + var v = TestNativeIntOneFieldReturnBlockInit(); + if (v.a == 0) + { + res++; + } + return res; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int TestNativeIntOneFieldCall2() + { + int res = 0; + var v = TestNativeIntOneFieldReturnFieldInit(); + if (v.a == 0) + { + res++; + } + return res; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int TestNativeIntTwoFieldsCall1() + { + int res = 0; + var v = TestNativeIntTwoFieldsReturnBlockInit(); + if (v.a == 0) + { + res++; + } + if (v.b == 0) + { + res++; + } + return res; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int TestNativeIntTwoFieldsCall2() + { + int res = 0; + var v = TestNativeIntTwoFieldsReturnFieldInit(); + if (v.a == 0) + { + res++; + } + if (v.b == 0) + { + res++; + } + return res; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int TestNativeIntFloatFieldCall1() + { + int res = 0; + var v = TestNativeIntFloatFieldReturnBlockInit(); + if (v.a >= 0) + { + res++; + } + return res; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int TestNativeIntFloatFieldCall2() + { + int res = 0; + var v = TestNativeIntFloatFieldReturnFieldInit(); + if (v.a >= 0) + { + res++; + } + return res; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int TestNativeIntMixedFieldsCall1() + { + int res = 0; + var v = TestNativeIntMixedFieldsReturnBlockInit(); + if (v.a == 0) + { + res++; + } + if (v.b == 0) + { + res++; + } + return res; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static int TestNativeIntMixedFieldsCall2() + { + int res = 0; + var v = TestNativeIntMixedFieldsReturnFieldInit(); + if (v.a == 0) + { + res++; + } + if (v.b == 0) + { + res++; + } + return res; + } + + public static void Test() + { + TestLessNativeIntCall1(); + TestLessNativeIntCall2(); + TestNativeIntOneFieldCall1(); + TestNativeIntOneFieldCall2(); + TestNativeIntTwoFieldsCall1(); + TestNativeIntTwoFieldsCall2(); + TestNativeIntFloatFieldCall1(); + TestNativeIntFloatFieldCall2(); + TestNativeIntMixedFieldsCall1(); + TestNativeIntMixedFieldsCall2(); + } +} +#endregion + +#region Test struct unsafe casts +class TestUnsafeCasts +{ + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromLPrim1() + { + long[] l = new long[1] { 1 }; + ref int r = ref Unsafe.As(ref l[0]); + Debug.Assert(l[0] != 2); + r = 2; + Debug.Assert(l[0] == 2); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromLPrim2() + { + long[] l = new long[1] { 1 }; + ref float r = ref Unsafe.As(ref l[0]); + Debug.Assert(l[0] != 0); + r = 0; + Debug.Assert(l[0] == 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromLPrim3() + { + double[] d = new double[1] { 154345345 }; + ref float r = ref Unsafe.As(ref d[0]); + Debug.Assert(d[0] != 0); + r = 0; + Debug.Assert(d[0] == 154345344); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromLPrim4() + { + double[] d = new double[1] { 154345345 }; + ref int r = ref Unsafe.As(ref d[0]); + Debug.Assert(d[0] != 0); + r = 0; + Debug.Assert(d[0] == 154345344); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromLPrim5() + { + long l = 0x123412341234; + int r = Unsafe.As(ref l); + Debug.Assert(r == 0x12341234); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromLPrim6() + { + long l = 0; + float r = Unsafe.As(ref l); + Debug.Assert(r == 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSPrim1() + { + int[] i = new int[2] { 0x12341234, 0 }; + ref long r = ref Unsafe.As(ref i[0]); + Debug.Assert(r == 0x12341234); + r = 0; + Debug.Assert(i[0] == 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSPrim2() + { + int[] i = new int[2] { 1, 2 }; + ref double r = ref Unsafe.As(ref i[0]); + Debug.Assert(i[0] != 0); + r = 0; + Debug.Assert(i[0] == 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSPrim3() + { + float[] f = new float[2] { 1, 2 }; + ref double r = ref Unsafe.As(ref f[0]); + Debug.Assert(f[0] != 0); + r = 0; + Debug.Assert(f[0] == 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSPrim4() + { + float[] f = new float[2] { 1, 2 }; + ref long r = ref Unsafe.As(ref f[0]); + Debug.Assert(f[0] != 0); + r = 0; + Debug.Assert(f[0] == 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSPrim5() + { + int l = 0x12341234; + long r = Unsafe.As(ref l); + Debug.Assert((uint)(r % (UInt32.MaxValue + 1L)) == 0x12341234); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSPrim6() + { + int l = 5; + double r = Unsafe.As(ref l); + l = Unsafe.As(ref r); + Debug.Assert(l == 5); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSameSizePrim1() + { + float[] f = new float[1] { 1 }; + ref int r = ref Unsafe.As(ref f[0]); + Debug.Assert(f[0] != 0); + r = 0; + Debug.Assert(f[0] == 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSameSizePrim2() + { + int[] i = new int[1] { 1 }; + ref float r = ref Unsafe.As(ref i[0]); + Debug.Assert(i[0] != 0); + r = 0; + Debug.Assert(i[0] == 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSameSizePrim3() + { + short[] f = new short[1] { 1 }; + ref ushort r = ref Unsafe.As(ref f[0]); + Debug.Assert(f[0] != 0); + r = 0; + Debug.Assert(f[0] == 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSameSizePrim4() + { + int[] i = new int[1] { 1 }; + ref uint r = ref Unsafe.As(ref i[0]); + Debug.Assert(i[0] != 0); + r = 0; + Debug.Assert(i[0] == 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSameSizePrim5() + { + double l = 0x12341234; + long r = Unsafe.As(ref l); + Debug.Assert(r == 0x41b2341234000000); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSameSizePrim6() + { + float l = 0x12341234; + int r = Unsafe.As(ref l); + Debug.Assert(r == 0x4d91a092); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSameSizePrim7() + { + long l = 0; + double r = Unsafe.As(ref l); + Debug.Assert(r == 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSameSizePrim8() + { + int l = 0; + float r = Unsafe.As(ref l); + Debug.Assert(r == 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSameSizePrim9() + { + short l = 100; + ushort r = Unsafe.As(ref l); + Debug.Assert(r == 100); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromLargePrim() + { + PrimFromLPrim1(); + PrimFromLPrim2(); + PrimFromLPrim3(); + PrimFromLPrim4(); + PrimFromLPrim5(); + PrimFromLPrim6(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSmallPrim() + { + PrimFromSPrim1(); + PrimFromSPrim2(); + PrimFromSPrim3(); + PrimFromSPrim4(); + PrimFromSPrim5(); + PrimFromSPrim6(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void PrimFromSameSizePrim() + { + PrimFromSameSizePrim1(); + PrimFromSameSizePrim2(); + PrimFromSameSizePrim3(); + PrimFromSameSizePrim4(); + PrimFromSameSizePrim5(); + PrimFromSameSizePrim6(); + PrimFromSameSizePrim7(); + PrimFromSameSizePrim8(); + PrimFromSameSizePrim9(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static void TestPrimitiveCasts() + { + PrimFromLargePrim(); + PrimFromSmallPrim(); + PrimFromSameSizePrim(); + } + + struct smallStruct + { + public bool a; + public bool b; + } + + struct nativeStruct + { + public IntPtr a; + } + + struct largeStruct + { + public int a; + public long b; + public double c; + public bool d; + public float e; + } + + struct eightByteStruct + { + public long a; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe void PrimFromSStruct() + { + smallStruct[] s = new smallStruct[2]; + s[0].a = true; + s[0].b = false; + int v = Unsafe.As(ref s[0]); + Debug.Assert(v != 0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe void PrimFromLStruct() + { + largeStruct s; + s.a = 1; + s.b = 2; + s.c = 3.0; + s.d = false; + s.e = 1; + int v = Unsafe.As(ref s); + Debug.Assert(v == 1); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe void PrimFromStruct() + { + nativeStruct s; + s.a = new IntPtr(100); + long v = Unsafe.As(ref s); + s = Unsafe.As(ref v); + Debug.Assert(s.a.ToInt32() == 100); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe void StructFromSPrim() + { + byte[] v = new byte[8] { 1, 0, 0, 0, 0, 0, 0, 0 }; + smallStruct s = Unsafe.As(ref v[0]); + Debug.Assert(s.a == true && s.b == false); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe void StructFromLPrim() + { + int v = 0b1; + smallStruct s = Unsafe.As(ref v); + Debug.Assert(s.a == true && s.b == false); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe void StructFromPrim() + { + long v = 100; + nativeStruct s = Unsafe.As(ref v); + Debug.Assert(s.a.ToInt32() == 100); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe void StructFromSStruct1() + { + smallStruct[] smallS = new smallStruct[4]; + smallS[0].a = true; + smallS[0].b = false; + eightByteStruct largeS = Unsafe.As(ref smallS[0]); + Debug.Assert((uint)(largeS.a % (UInt32.MaxValue + 1L)) == 1); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe void StructFromSStruct2() + { + smallStruct[] smallS = new smallStruct[8]; + smallS[0].a = true; + smallS[0].b = false; + largeStruct largeS = Unsafe.As(ref smallS[0]); + Debug.Assert((uint)(largeS.a % (UInt32.MaxValue + 1L)) == 1); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe void StructFromSStruct3() + { + eightByteStruct[] smallS = new eightByteStruct[2]; + smallS[0].a = 1000; + largeStruct largeS = Unsafe.As(ref smallS[0]); + Debug.Assert(largeS.a == 1000); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe void StructFromLStruct1() + { + eightByteStruct largeS; + largeS.a = 1; + smallStruct smallS = Unsafe.As(ref largeS); + Debug.Assert(smallS.a == true && smallS.b == false); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe void StructFromLStruct2() + { + largeStruct largeS; + largeS.a = 1; + largeS.b = 2; + largeS.c = 3.0; + largeS.d = false; + largeS.e = 1; + smallStruct smallS = Unsafe.As(ref largeS); + Debug.Assert(smallS.a == true && smallS.b == false); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe void StructFromLStruct3() + { + largeStruct largeS; + largeS.a = 3; + largeS.b = 2; + largeS.c = 3.0; + largeS.d = false; + largeS.e = 1; + eightByteStruct smallS = Unsafe.As(ref largeS); + Debug.Assert(smallS.a == 3); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static unsafe void StructFromStruct() + { + eightByteStruct s1; + s1.a = 3; + eightByteStruct s2 = Unsafe.As(ref s1); + Debug.Assert(s2.a == 3); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void TestStructCasts() + { + PrimFromSStruct(); + PrimFromLStruct(); + PrimFromStruct(); + + StructFromSPrim(); + StructFromLPrim(); + StructFromPrim(); + + StructFromSStruct1(); + StructFromSStruct2(); + StructFromSStruct3(); + + StructFromLStruct1(); + StructFromLStruct2(); + StructFromLStruct3(); + + StructFromStruct(); + } + + #region for the tests below we are expecting only one move instruction to be generated for each. + [MethodImpl(MethodImplOptions.NoInlining)] + static long ReturnAsLong(eightByteStruct a) + { + return Unsafe.As(ref a); + } + + + [MethodImpl(MethodImplOptions.NoInlining)] + static eightByteStruct ReturnAsEightByteStructFromLong(long a) + { + return Unsafe.As(ref a); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static double ReturnAsDouble(eightByteStruct a) + { + return Unsafe.As(ref a); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static eightByteStruct ReturnAsEightByteStructFromDouble(double a) + { + return Unsafe.As(ref a); + } + + struct eightByteStructOverDouble + { + public double a; + } + + static long ReturnAsLong(eightByteStructOverDouble a) + { + return Unsafe.As(ref a); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static eightByteStructOverDouble ReturnAsEightByteStructOverDoubleFromLong(long a) + { + return Unsafe.As(ref a); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static double ReturnAsDouble(eightByteStructOverDouble a) + { + return Unsafe.As(ref a); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static eightByteStructOverDouble ReturnAsEightByteStructOverDoubleFromDouble(double a) + { + return Unsafe.As(ref a); + } + + #endregion + + [MethodImpl(MethodImplOptions.NoInlining)] + static void TestCastSameSize() + { + eightByteStruct e; + e.a = 32; + long l = ReturnAsLong(e); + Debug.Assert(l == 32); + e = ReturnAsEightByteStructFromLong(l); + Debug.Assert(e.a == 32); + double d = ReturnAsDouble(e); + e = ReturnAsEightByteStructFromDouble(d); + Debug.Assert(e.a == 32); + + eightByteStructOverDouble ed; + ed = ReturnAsEightByteStructOverDoubleFromLong(l); + l = ReturnAsLong(ed); + Debug.Assert(l == 32); + d = ReturnAsDouble(ed); + ed = ReturnAsEightByteStructOverDoubleFromDouble(d); + l = ReturnAsLong(ed); + Debug.Assert(e.a == 32); + } + + struct StructWithVectorField + { + public int a; + public Vector b; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void TestSIMDInit() + { + Vector localVector = new Vector(); + StructWithVectorField structWithVectorField; + structWithVectorField.a = 0; + structWithVectorField.b = new Vector(); + } + + + [MethodImpl(MethodImplOptions.NoInlining)] + static void TestWhatShouldBeOptimized() + { + TestCastSameSize(); + TestSIMDInit(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static void Test() + { + TestPrimitiveCasts(); + TestStructCasts(); + TestWhatShouldBeOptimized(); + } +} + +#endregion + +#region Test merge return blocks +class TestMergeReturnBlocks +{ + struct ReturnStruct + { + public float a; + + [MethodImpl(MethodImplOptions.NoInlining)] + public ReturnStruct(int a) + { + this.a = a; + } + } + + static ReturnStruct TestConstPropogation(int a) + { + if (a == 0) + { + ReturnStruct s = new ReturnStruct(); // ASG(a, 0); + return s; + } + else if (a == 1) + { + ReturnStruct s = new ReturnStruct(1); + return s; + } + else if (a == 2) + { + ReturnStruct s; + s.a = 2; + return s; + } + else if (a == 3) + { + ReturnStruct s = new ReturnStruct(3); + ReturnStruct s2 = s; + ReturnStruct s3 = s2; + return s3; + } + return new ReturnStruct(4); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void TestConstPropogation() + { + TestConstPropogation(5); + } + + + [StructLayout(LayoutKind.Explicit, Pack = 1)] + struct StructWithOverlaps + { + [FieldOffset(0)] + public int val; + [FieldOffset(0)] + public ReturnStruct s; + + [MethodImpl(MethodImplOptions.NoInlining)] + public StructWithOverlaps(int v) + { + val = 0; + s.a = v; + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static ReturnStruct TestNoFieldSeqPropogation(int a) + { + StructWithOverlaps s = new StructWithOverlaps(); + if (a == 0) + { + return new ReturnStruct(); + } + else if (a == 1) + { + return s.s; + } + else if (a == 2) + { + StructWithOverlaps s2 = new StructWithOverlaps(2); + return s2.s; + } + else if (a == 3) + { + StructWithOverlaps s3 = new StructWithOverlaps(3); + return s3.s; + } + else + { + StructWithOverlaps s4 = new StructWithOverlaps(4); + return s4.s; + } + + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void TestNoFieldSeqPropogation() + { + TestNoFieldSeqPropogation(5); + } + + + public static void Test() + { + TestConstPropogation(); + TestNoFieldSeqPropogation(); + } +} +#endregion + +class TestHFA +{ + [MethodImpl(MethodImplOptions.NoInlining)] + static float ReturnFloat() + { + return 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static double ReturnDouble() + { + return 1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector2 ReturnVector2() + { + return new Vector2(1); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector3 ReturnVector3() + { + return new Vector3(1); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector4 ReturnVector4() + { + return new Vector4(1); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector4 ReturnVector4UsingCall() + { + return ReturnVector4(); + } + + struct FloatWrapper + { + public float f; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static FloatWrapper ReturnFloatWrapper() + { + return new FloatWrapper(); + } + + struct DoubleWrapper + { + public double f; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static DoubleWrapper ReturnDoubleWrapper() + { + return new DoubleWrapper(); + } + + struct Floats2Wrapper + { + public float f1; + public float f2; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Floats2Wrapper ReturnFloats2Wrapper() + { + return new Floats2Wrapper(); + } + + struct Doubles2Wrapper + { + public double f1; + public double f2; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Doubles2Wrapper ReturnDoubles2Wrapper() + { + return new Doubles2Wrapper(); + } + struct Floats3Wrapper + { + public float f1; + public float f2; + public float f3; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Floats3Wrapper ReturnFloats3Wrapper() + { + return new Floats3Wrapper(); + } + + struct Doubles3Wrapper + { + public double f1; + public double f2; + public double f3; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Doubles3Wrapper ReturnDoubles3Wrapper() + { + return new Doubles3Wrapper(); + } + + struct Floats4Wrapper + { + public float f1; + public float f2; + public float f3; + public float f4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Floats4Wrapper ReturnFloats4Wrapper() + { + return new Floats4Wrapper(); + } + + struct Doubles4Wrapper + { + public double f1; + public double f2; + public double f3; + public double f4; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Doubles4Wrapper ReturnDoubles4Wrapper() + { + return new Doubles4Wrapper(); + } + + struct Vector2Wrapper + { + Vector2 f1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector2Wrapper ReturnVector2Wrapper() + { + return new Vector2Wrapper(); + } + + struct Vector3Wrapper + { + Vector3 f1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector3Wrapper ReturnVector3Wrapper() + { + return new Vector3Wrapper(); + } + + struct Vector4Wrapper + { + Vector4 f1; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector4Wrapper ReturnVector4Wrapper() + { + return new Vector4Wrapper(); + } + + struct Vector2x2Wrapper + { + Vector2 f1; + Vector2 f2; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Vector2x2Wrapper ReturnVector2x2Wrapper() + { + return new Vector2x2Wrapper(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static void Test() + { + ReturnFloat(); + ReturnDouble(); + ReturnVector2(); + ReturnVector3(); + ReturnVector4(); + ReturnVector4UsingCall(); + ReturnFloatWrapper(); + ReturnDoubleWrapper(); + ReturnFloats2Wrapper(); + ReturnDoubles2Wrapper(); + ReturnFloats3Wrapper(); + ReturnDoubles3Wrapper(); + ReturnFloats4Wrapper(); + ReturnDoubles4Wrapper(); + ReturnVector2Wrapper(); + ReturnVector3Wrapper(); + ReturnVector4Wrapper(); + ReturnVector2x2Wrapper(); + } +} + +class TestNon2PowerStructs +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct Byte3Struct + { + public byte f1; + public byte f2; + public byte f3; + + [MethodImpl(MethodImplOptions.NoInlining)] + public Byte3Struct(int v) + { + f1 = 1; + f2 = 2; + f3 = 3; + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct Byte5Struct + { + public byte f1; + public byte f2; + public byte f3; + public byte f4; + public byte f5; + + [MethodImpl(MethodImplOptions.NoInlining)] + public Byte5Struct(int v) + { + f1 = 4; + f2 = 5; + f3 = 6; + f4 = 7; + f5 = 8; + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct Byte6Struct + { + public byte f1; + public byte f2; + public byte f3; + public byte f4; + public byte f5; + public byte f6; + + [MethodImpl(MethodImplOptions.NoInlining)] + public Byte6Struct(int v) + { + f1 = 9; + f2 = 10; + f3 = 11; + f4 = 12; + f5 = 13; + f6 = 14; + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct Byte7Struct + { + public byte f1; + public byte f2; + public byte f3; + public byte f4; + public byte f5; + public byte f6; + public byte f7; + + [MethodImpl(MethodImplOptions.NoInlining)] + public Byte7Struct(int v) + { + f1 = 15; + f2 = 16; + f3 = 17; + f4 = 18; + f5 = 19; + f6 = 20; + f7 = 21; + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct CompositeOfOddStructs + { + public Byte3Struct a; + public Byte5Struct b; + public Byte6Struct c; + public Byte7Struct d; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Byte3Struct Return3() + { + return new Byte3Struct(0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Byte5Struct Return5() + { + return new Byte5Struct(0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Byte6Struct Return6() + { + return new Byte6Struct(0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static Byte7Struct Return7() + { + return new Byte7Struct(0); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static CompositeOfOddStructs CreateComposite() + { + CompositeOfOddStructs c = new CompositeOfOddStructs(); + c.a = Return3(); + c.b = Return5(); + c.c = Return6(); + c.d = Return7(); + return c; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static void TestComposite() + { + var c = CreateComposite(); + Debug.Assert(c.a.f1 == 1); + Debug.Assert(c.a.f2 == 2); + Debug.Assert(c.a.f3 == 3); + Debug.Assert(c.b.f1 == 4); + Debug.Assert(c.b.f2 == 5); + Debug.Assert(c.b.f3 == 6); + Debug.Assert(c.b.f4 == 7); + Debug.Assert(c.b.f5 == 8); + Debug.Assert(c.c.f1 == 9); + Debug.Assert(c.c.f2 == 10); + Debug.Assert(c.c.f3 == 11); + Debug.Assert(c.c.f4 == 12); + Debug.Assert(c.c.f5 == 13); + Debug.Assert(c.c.f6 == 14); + Debug.Assert(c.d.f1 == 15); + Debug.Assert(c.d.f2 == 16); + Debug.Assert(c.d.f3 == 17); + Debug.Assert(c.d.f4 == 18); + Debug.Assert(c.d.f5 == 19); + Debug.Assert(c.d.f6 == 20); + Debug.Assert(c.d.f7 == 21); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static byte TestLocals(int v) + { + var a = Return3(); + var a1 = a; + a1.f1 = 0; + var b = Return5(); + var c = Return6(); + var d = Return7(); + if (v == 0) + { + return a.f1; + } + else if (v == 1) + { + return b.f1; + } + else if (v == 3) + { + return c.f1; + } + else if (v == 4) + { + return d.f1; + } + else + { + return a1.f1; + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static void Test() + { + TestComposite(); + TestLocals(0); + } +} + +class TestStructs +{ + public static int Main() + { + TestStructReturns.Test(); + TestUnsafeCasts.Test(); + TestMergeReturnBlocks.Test(); + TestHFA.Test(); + TestNon2PowerStructs.Test(); + return 100; + } +} diff --git a/src/coreclr/tests/src/JIT/Directed/StructABI/structreturn.csproj b/src/coreclr/tests/src/JIT/Directed/StructABI/structreturn.csproj new file mode 100644 index 00000000000000..d9516b03e4a5d9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/Directed/StructABI/structreturn.csproj @@ -0,0 +1,14 @@ + + + Exe + 1 + + + PdbOnly + True + True + + + + + diff --git a/src/coreclr/tests/src/JIT/Directed/pinning/object-pin/Object-Pin.il b/src/coreclr/tests/src/JIT/Directed/pinning/object-pin/Object-Pin.il index 6b4ab09bc545da..b3a54f21cfe1c1 100644 --- a/src/coreclr/tests/src/JIT/Directed/pinning/object-pin/Object-Pin.il +++ b/src/coreclr/tests/src/JIT/Directed/pinning/object-pin/Object-Pin.il @@ -140,6 +140,7 @@ FAILURE3: stloc.1 ldloc 1 + conv.i call int32 Pin1_Test::Ret_Ptr(void*) stloc 3 @@ -148,6 +149,7 @@ FAILURE3: stloc.2 ldloc 2 + conv.i call int32 Pin1_Test::Ret_Ptr(void*) stloc 4 @@ -158,6 +160,7 @@ FAILURE3: call void [mscorlib]System.GC::Collect() ldloc 1 + conv.i call int32 Pin1_Test::Ret_Ptr(void*) ldloc 3 conv.i @@ -165,6 +168,7 @@ FAILURE3: SOFT2: ldloc 2 + conv.i call int32 Pin1_Test::Ret_Ptr(void*) ldloc 4 conv.i @@ -202,6 +206,7 @@ AA_3: stloc.1 ldloc 1 + conv.i call int32 Pin1_Test::Ret_Ptr(void*) stloc 3 @@ -210,6 +215,7 @@ AA_3: stloc.2 ldloc 2 + conv.i call int32 Pin1_Test::Ret_Ptr(void*) stloc 4 @@ -220,6 +226,7 @@ AA_3: call void [mscorlib]System.GC::Collect() ldloc 1 + conv.i call int32 Pin1_Test::Ret_Ptr(void*) ldloc 3 conv.i @@ -227,6 +234,7 @@ AA_3: SOFT4: ldloc 2 + conv.i call int32 Pin1_Test::Ret_Ptr(void*) ldloc 4 conv.i @@ -263,6 +271,7 @@ AA_3: stloc.1 ldloc 1 + conv.i call int32 Pin1_Test::Ret_Ptr(void*) stloc 3 @@ -271,6 +280,7 @@ AA_3: stloc.2 ldloc 2 + conv.i call int32 Pin1_Test::Ret_Ptr(void*) stloc 4 @@ -285,7 +295,8 @@ AA_3: ldloc 5 stfld int32 Consume::yucko - ldloc 2 + ldloc 2 + conv.i ldflda int32 Consume::yucko ldc.i4 66 call void Pin1_Test::Set_Val(void*,int32) @@ -301,7 +312,8 @@ Yippie1: ldloc 5 stfld int32 Consume::yucko - ldloc 2 + ldloc 2 + conv.i ldflda int32 Consume::yucko ldc.i4 88 call void Pin1_Test::Set_Val(void*,int32) @@ -314,6 +326,7 @@ Yippie1: Yippie2: call void [mscorlib]System.GC::Collect() ldloc 1 + conv.i call int32 Pin1_Test::Ret_Ptr(void*) ldloc 3 conv.i @@ -321,6 +334,7 @@ Yippie2: SOFT5: ldloc 2 + conv.i call int32 Pin1_Test::Ret_Ptr(void*) ldloc 4 conv.i diff --git a/src/coreclr/tests/src/JIT/Directed/tailcall/more_tailcalls.cs b/src/coreclr/tests/src/JIT/Directed/tailcall/more_tailcalls.cs index eb14de91b067df..28da70839e7cc9 100644 --- a/src/coreclr/tests/src/JIT/Directed/tailcall/more_tailcalls.cs +++ b/src/coreclr/tests/src/JIT/Directed/tailcall/more_tailcalls.cs @@ -16,6 +16,9 @@ struct S16 { public long A, B; public override string ToString() => $"{A}, {B}"; + + [MethodImpl(MethodImplOptions.NoInlining)] + public string InstanceMethod() => "Instance method"; } struct S32 { @@ -38,6 +41,7 @@ struct SGC2 public int D; public override string ToString() => $"{A}, ({B}), {C}, {D}"; } + class HeapInt { public int Value; @@ -51,7 +55,9 @@ internal class Program private static readonly IntPtr s_calcStaticCalliOther; private static readonly IntPtr s_calcStaticCalliRetbuf; private static readonly IntPtr s_calcStaticCalliRetbufOther; - + private static readonly IntPtr s_emptyCalliOther; + private static readonly IntPtr s_instanceMethodOnValueType; + static Program() { IL.Emit.Ldftn(new MethodRef(typeof(Program), nameof(CalcStaticCalli))); @@ -62,11 +68,17 @@ static Program() IL.Pop(out IntPtr calcStaticCalliRetbuf); IL.Emit.Ldftn(new MethodRef(typeof(Program), nameof(CalcStaticCalliRetbufOther))); IL.Pop(out IntPtr calcStaticCalliRetbufOther); + IL.Emit.Ldftn(new MethodRef(typeof(Program), nameof(EmptyCalliOther))); + IL.Pop(out IntPtr emptyCalliOther); + IL.Emit.Ldftn(new MethodRef(typeof(S16), nameof(S16.InstanceMethod))); + IL.Pop(out IntPtr instanceMethodOnValueType); s_calcStaticCalli = calcStaticCalli; s_calcStaticCalliOther = calcStaticCalliOther; s_calcStaticCalliRetbuf = calcStaticCalliRetbuf; s_calcStaticCalliRetbufOther = calcStaticCalliRetbufOther; + s_emptyCalliOther = emptyCalliOther; + s_instanceMethodOnValueType = instanceMethodOnValueType; } private static int Main() @@ -77,7 +89,7 @@ private static int Main() int x = numCalcIters; S32 s = default; int expected = 0; - + while (x != 0) { if (x % 2 == 0) @@ -115,6 +127,8 @@ void TestCalc(Func f, T expected, string name) GenInstance g = new GenInstance(); IGenInterface ig = new GenInterfaceImpl(); IGenInterface ig2 = new GenInterfaceImpl(); + GenAbstractImpl ga1 = new GenAbstractImpl(); + GenAbstractImpl ga2 = new GenAbstractImpl(); long expectedI8 = (long)(((ulong)(uint)expected << 32) | (uint)expected); S16 expectedS16 = new S16 { A = expected, B = expected, }; @@ -137,6 +151,9 @@ void TestCalc(Func f, T expected, string name) TestCalc(CalcStaticCalliRetbuf, expectedS32, "Static calli retbuf"); TestCalc(new Instance().CalcInstanceCalli, expected, "Instance calli"); TestCalc(new Instance().CalcInstanceCalliRetbuf, expectedS32, "Instance calli retbuf"); + Test(() => EmptyCalli(), "Empty calli", "Static calli without args"); + Test(() => ValueTypeInstanceMethodCalli(), "Instance method", "calli to an instance method on a value type"); + Test(() => ValueTypeExplicitThisInstanceMethodCalli(), "Instance method", "calli to an instance method on a value type with explicit this"); Test(() => { var v = new InstanceValueType(); v.CountUp(countUpIters); return v.Count; }, countUpIters, "Value type instance call"); Test(() => new Instance().GC("2", 3, "4", 5, "6", "7", "8", 9, ref ten), "2 3 4 5 6 7 8 9 10", "Instance with GC"); Test(() => CountUpHeap(countUpIters, new HeapInt(0)), countUpIters, "Count up with heap int"); @@ -154,10 +171,18 @@ void TestCalc(Func f, T expected, string name) "System.String System.Int32 System.Object System.String a 5 b c", "Instance generic 4"); Test(() => g.VirtForward("a", 5, "b", "c"), "System.String System.Int32 System.Object System.String a 5 b c", "Virtual instance generic 4"); - Test(() => GenInterfaceForward("a", 5, "c", "d", ig), + Test(() => GenInterfaceForwardF("a", 5, "c", "d", ig), "System.String System.Int32 System.String System.Object a 5 c d", "Interface generic 4"); + Test(() => GenInterfaceForwardG("a", 5, ig), + "System.String System.Int32 a 5", "Interface generic forward G"); Test(() => GenInterfaceForwardNone("a", "b", 5, "d", ig2), "System.String System.Object System.Int32 System.Object a b 5 d", "Interface generic 0"); + Test(() => GenInterfaceForward2("a", "b", ig2), + "System.String System.Object a b", "Interface generic without generics on method"); + Test(() => GenAbstractFString(ga1), "System.String System.Object", "Abstract generic with generic on method 1"); + Test(() => GenAbstractFInt(ga2), "System.Int32 System.Object", "Abstract generic with generic on method 2"); + Test(() => GenAbstractGString(ga1), "System.String", "Abstract generic without generic on method 1"); + Test(() => GenAbstractGInt(ga2), "System.Int32", "Abstract generic without generic on method 2"); if (result) Console.WriteLine("All tailcall-via-help succeeded"); @@ -357,6 +382,55 @@ private static int CalcStaticCalliOther(int x, S32 large, int acc) return IL.Return(); } + [MethodImpl(MethodImplOptions.NoInlining)] + private static string EmptyCalli() + { + // Force helper-based tailcall out of this function by stackallocing + Span values = stackalloc int[Environment.TickCount < 0 ? 30 : 40]; + + IL.Push(s_emptyCalliOther); + IL.Emit.Tail(); + IL.Emit.Calli(new StandAloneMethodSig(CallingConventions.Standard, typeof(string))); + return IL.Return(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static string ValueTypeInstanceMethodCalli() + { + // Force helper-based tailcall out of this function by stackallocing + Span values = stackalloc int[Environment.TickCount < 0 ? 30 : 40]; + + S16 s16 = new S16(); + + IL.Push(ref s16); + IL.Push(s_instanceMethodOnValueType); + IL.Emit.Tail(); + IL.Emit.Calli(new StandAloneMethodSig(CallingConventions.Standard | CallingConventions.HasThis, typeof(string))); + return IL.Return(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static string ValueTypeExplicitThisInstanceMethodCalli() + { + // Force helper-based tailcall out of this function by stackallocing + Span values = stackalloc int[Environment.TickCount < 0 ? 30 : 40]; + + S16 s16 = new S16(); + + IL.Push(ref s16); + IL.Push(s_instanceMethodOnValueType); + IL.Emit.Tail(); + IL.Emit.Calli(new StandAloneMethodSig(CallingConventions.Standard | CallingConventions.HasThis | CallingConventions.ExplicitThis, + typeof(string), typeof(S16).MakeByRefType())); + return IL.Return(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static string EmptyCalliOther() + { + return "Empty calli"; + } + [MethodImpl(MethodImplOptions.NoInlining)] private static S32 CalcStaticCalliRetbuf(int x, int acc) { @@ -527,7 +601,7 @@ private static string GenName2(S32 s, T1 a, T2 b) => $"{typeof(T1).FullName} {typeof(T2).FullName} {a} {b}"; [MethodImpl(MethodImplOptions.NoInlining)] - private static string GenInterfaceForward(T1 a, T2 b, T3 c, T4 d, IGenInterface igen) + private static string GenInterfaceForwardF(T1 a, T2 b, T3 c, T4 d, IGenInterface igen) { IL.Push(igen); IL.Push(new S32()); @@ -540,6 +614,18 @@ private static string GenInterfaceForward(T1 a, T2 b, T3 c, T4 d return IL.Return(); } + [MethodImpl(MethodImplOptions.NoInlining)] + private static string GenInterfaceForwardG(T1 a, T2 b, IGenInterface igen) + { + IL.Push(igen); + IL.Push(new S32()); + IL.Push(a); + IL.Push(b); + IL.Emit.Tail(); + IL.Emit.Callvirt(new MethodRef(typeof(IGenInterface), nameof(IGenInterface.G))); + return IL.Return(); + } + [MethodImpl(MethodImplOptions.NoInlining)] private static string GenInterfaceForwardNone(string a, object b, int c, object d, IGenInterface igen) { @@ -553,6 +639,54 @@ private static string GenInterfaceForwardNone(string a, object b, int c, object IL.Emit.Callvirt(new MethodRef(typeof(IGenInterface), nameof(IGenInterface.F)).MakeGenericMethod(typeof(int), typeof(object))); return IL.Return(); } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static string GenInterfaceForward2(string a, object b, IGenInterface igen) + { + IL.Push(igen); + IL.Push(new S32()); + IL.Push(a); + IL.Push(b); + IL.Emit.Tail(); + IL.Emit.Callvirt(new MethodRef(typeof(IGenInterface), nameof(IGenInterface.G))); + return IL.Return(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static string GenAbstractFString(GenAbstract ga) + { + IL.Push(ga); + IL.Emit.Tail(); + IL.Emit.Callvirt(new MethodRef(typeof(GenAbstract), nameof(GenAbstract.F)).MakeGenericMethod(typeof(object))); + return IL.Return(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static string GenAbstractGString(GenAbstract ga) + { + IL.Push(ga); + IL.Emit.Tail(); + IL.Emit.Callvirt(new MethodRef(typeof(GenAbstract), nameof(GenAbstract.G))); + return IL.Return(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static string GenAbstractFInt(GenAbstract ga) + { + IL.Push(ga); + IL.Emit.Tail(); + IL.Emit.Callvirt(new MethodRef(typeof(GenAbstract), nameof(GenAbstract.F)).MakeGenericMethod(typeof(object))); + return IL.Return(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static string GenAbstractGInt(GenAbstract ga) + { + IL.Push(ga); + IL.Emit.Tail(); + IL.Emit.Callvirt(new MethodRef(typeof(GenAbstract), nameof(GenAbstract.G))); + return IL.Return(); + } } class Instance @@ -992,11 +1126,30 @@ public virtual string Virt(S32 s, T1 a, T2 b, T3 c, T4 d) interface IGenInterface { - public string F(S32 s, T1 a, T2 b, T3 c, T4 d); + string F(S32 s, T1 a, T2 b, T3 c, T4 d); + string G(S32 s, T1 a, T2 b); } class GenInterfaceImpl : IGenInterface { public string F(S32 s, T1 a, T2 b, T3 c, T4 d) => $"{typeof(T1).FullName} {typeof(T2).FullName} {typeof(T3).FullName} {typeof(T4).FullName} {a} {b} {c} {d}"; + + public string G(S32 s, T1 a, T2 b) + => $"{typeof(T1).FullName} {typeof(T2).FullName} {a} {b}"; +} + +abstract class GenAbstract +{ + public abstract string F(); + public abstract string G(); +} + +class GenAbstractImpl : GenAbstract +{ + public override string F() + => $"{typeof(T1).FullName} {typeof(T2).FullName}"; + + public override string G() + => $"{typeof(T1).FullName}"; } diff --git a/src/coreclr/tests/src/JIT/Directed/tailcall/more_tailcalls.il b/src/coreclr/tests/src/JIT/Directed/tailcall/more_tailcalls.il index 299eb82b59f610..49c34a022deb63 100644 --- a/src/coreclr/tests/src/JIT/Directed/tailcall/more_tailcalls.il +++ b/src/coreclr/tests/src/JIT/Directed/tailcall/more_tailcalls.il @@ -4,21 +4,22 @@ // See more_tailcalls.cs for the source of this IL. + // Metadata version: v4.0.30319 .assembly extern System.Runtime { .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....: - .ver 4:2:1:0 + .ver 4:2:2:0 } .assembly extern System.Runtime.Extensions { .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....: - .ver 4:2:1:0 + .ver 4:2:2:0 } .assembly extern System.Console { .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....: - .ver 4:1:1:0 + .ver 4:1:2:0 } .assembly example1 { @@ -30,7 +31,7 @@ // .custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 ) .custom instance void [System.Runtime]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 18 2E 4E 45 54 43 6F 72 65 41 70 70 2C 56 // ....NETCoreApp,V - 65 72 73 69 6F 6E 3D 76 33 2E 30 01 00 54 0E 14 // ersion=v3.0..T.. + 65 72 73 69 6F 6E 3D 76 33 2E 31 01 00 54 0E 14 // ersion=v3.1..T.. 46 72 61 6D 65 77 6F 72 6B 44 69 73 70 6C 61 79 // FrameworkDisplay 4E 61 6D 65 00 ) // Name. .custom instance void [System.Runtime]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 08 65 78 61 6D 70 6C 65 31 00 00 ) // ...example1.. @@ -40,19 +41,19 @@ .custom instance void [System.Runtime]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 08 65 78 61 6D 70 6C 65 31 00 00 ) // ...example1.. .custom instance void [System.Runtime]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 08 65 78 61 6D 70 6C 65 31 00 00 ) // ...example1.. .permissionset reqmin - = {class 'System.Security.Permissions.SecurityPermissionAttribute, System.Runtime.Extensions, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' = {property bool 'SkipVerification' = bool(true)}} + = {class 'System.Security.Permissions.SecurityPermissionAttribute, System.Runtime.Extensions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' = {property bool 'SkipVerification' = bool(true)}} .hash algorithm 0x00008004 .ver 1:0:0:0 } .module example1.dll -// MVID: {d297947d-0d42-4f5f-a026-33cccfd04656} +// MVID: {E5213016-898B-454A-941D-D8C885B9972D} .custom instance void [System.Runtime]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .imagebase 0x00400000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x00007F4743A10000 +// Image base: 0x052D0000 // =============== CLASS MEMBERS DECLARATION =================== @@ -80,6 +81,15 @@ IL_0020: ret } // end of method S16::ToString + .method public hidebysig instance string + InstanceMethod() cil managed noinlining + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: ldstr "Instance method" + IL_0005: ret + } // end of method S16::InstanceMethod + } // end of class S16 .class private sequential ansi sealed beforefieldinit S32 @@ -251,7 +261,7 @@ .class private auto ansi Program extends [System.Runtime]System.Object { - .class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass5_0' + .class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass7_0' extends [System.Runtime]System.Object { .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) @@ -260,6 +270,8 @@ .field public class GenInstance`2 g .field public class IGenInterface`2 ig .field public class IGenInterface`2 ig2 + .field public class GenAbstractImpl`1 ga1 + .field public class GenAbstractImpl`1 ga2 .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { @@ -268,7 +280,7 @@ IL_0000: ldarg.0 IL_0001: call instance void [System.Runtime]System.Object::.ctor() IL_0006: ret - } // end of method '<>c__DisplayClass5_0'::.ctor + } // end of method '<>c__DisplayClass7_0'::.ctor .method assembly hidebysig instance void '
g__Test|0'(class [System.Runtime]System.Func`1 f, @@ -319,9 +331,9 @@ object) IL_0061: ldarg.0 IL_0062: ldc.i4.0 - IL_0063: stfld bool Program/'<>c__DisplayClass5_0'::result + IL_0063: stfld bool Program/'<>c__DisplayClass7_0'::result IL_0068: ret - } // end of method '<>c__DisplayClass5_0'::'
g__Test|0' + } // end of method '<>c__DisplayClass7_0'::'
g__Test|0' .method assembly hidebysig instance void '
g__TestCalc|1'(class [System.Runtime]System.Func`3 f, @@ -330,27 +342,27 @@ { // Code size 34 (0x22) .maxstack 4 - .locals init (class Program/'<>c__DisplayClass5_1`1' V_0) - IL_0000: newobj instance void class Program/'<>c__DisplayClass5_1`1'::.ctor() + .locals init (class Program/'<>c__DisplayClass7_1`1' V_0) + IL_0000: newobj instance void class Program/'<>c__DisplayClass7_1`1'::.ctor() IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: ldarg.1 - IL_0008: stfld class [System.Runtime]System.Func`3 class Program/'<>c__DisplayClass5_1`1'::f + IL_0008: stfld class [System.Runtime]System.Func`3 class Program/'<>c__DisplayClass7_1`1'::f IL_000d: ldarg.0 IL_000e: ldloc.0 - IL_000f: ldftn instance !0 class Program/'<>c__DisplayClass5_1`1'::'
b__20'() + IL_000f: ldftn instance !0 class Program/'<>c__DisplayClass7_1`1'::'
b__29'() IL_0015: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) IL_001a: ldarg.2 IL_001b: ldarg.3 - IL_001c: call instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_001c: call instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) IL_0021: ret - } // end of method '<>c__DisplayClass5_0'::'
g__TestCalc|1' + } // end of method '<>c__DisplayClass7_0'::'
g__TestCalc|1' .method assembly hidebysig instance string - '
b__4'() cil managed + '
b__7'() cil managed { // Code size 51 (0x33) .maxstack 10 @@ -365,7 +377,7 @@ IL_0020: ldstr "8" IL_0025: ldc.i4.s 9 IL_0027: ldarg.0 - IL_0028: ldflda int32 Program/'<>c__DisplayClass5_0'::ten + IL_0028: ldflda int32 Program/'<>c__DisplayClass7_0'::ten IL_002d: call instance string Instance::GC(object, int32, object, @@ -376,15 +388,15 @@ int32, int32&) IL_0032: ret - } // end of method '<>c__DisplayClass5_0'::'
b__4' + } // end of method '<>c__DisplayClass7_0'::'
b__7' .method assembly hidebysig instance string - '
b__16'() cil managed + '
b__19'() cil managed { // Code size 28 (0x1c) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld class GenInstance`2 Program/'<>c__DisplayClass5_0'::g + IL_0001: ldfld class GenInstance`2 Program/'<>c__DisplayClass7_0'::g IL_0006: ldstr "a" IL_000b: ldc.i4.5 IL_000c: ldstr "b" @@ -394,15 +406,15 @@ !!0, !!1) IL_001b: ret - } // end of method '<>c__DisplayClass5_0'::'
b__16' + } // end of method '<>c__DisplayClass7_0'::'
b__19' .method assembly hidebysig instance string - '
b__17'() cil managed + '
b__20'() cil managed { // Code size 28 (0x1c) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld class GenInstance`2 Program/'<>c__DisplayClass5_0'::g + IL_0001: ldfld class GenInstance`2 Program/'<>c__DisplayClass7_0'::g IL_0006: ldstr "a" IL_000b: ldc.i4.5 IL_000c: ldstr "b" @@ -412,10 +424,10 @@ !!0, !!1) IL_001b: ret - } // end of method '<>c__DisplayClass5_0'::'
b__17' + } // end of method '<>c__DisplayClass7_0'::'
b__20' .method assembly hidebysig instance string - '
b__18'() cil managed + '
b__21'() cil managed { // Code size 28 (0x1c) .maxstack 8 @@ -424,17 +436,32 @@ IL_0006: ldstr "c" IL_000b: ldstr "d" IL_0010: ldarg.0 - IL_0011: ldfld class IGenInterface`2 Program/'<>c__DisplayClass5_0'::ig - IL_0016: call string Program::GenInterfaceForward(!!0, - !!1, - !!2, - !!3, - class IGenInterface`2) + IL_0011: ldfld class IGenInterface`2 Program/'<>c__DisplayClass7_0'::ig + IL_0016: call string Program::GenInterfaceForwardF(!!0, + !!1, + !!2, + !!3, + class IGenInterface`2) IL_001b: ret - } // end of method '<>c__DisplayClass5_0'::'
b__18' + } // end of method '<>c__DisplayClass7_0'::'
b__21' .method assembly hidebysig instance string - '
b__19'() cil managed + '
b__22'() cil managed + { + // Code size 18 (0x12) + .maxstack 8 + IL_0000: ldstr "a" + IL_0005: ldc.i4.5 + IL_0006: ldarg.0 + IL_0007: ldfld class IGenInterface`2 Program/'<>c__DisplayClass7_0'::ig + IL_000c: call string Program::GenInterfaceForwardG(!!0, + !!1, + class IGenInterface`2) + IL_0011: ret + } // end of method '<>c__DisplayClass7_0'::'
b__22' + + .method assembly hidebysig instance string + '
b__23'() cil managed { // Code size 28 (0x1c) .maxstack 8 @@ -443,18 +470,77 @@ IL_000a: ldc.i4.5 IL_000b: ldstr "d" IL_0010: ldarg.0 - IL_0011: ldfld class IGenInterface`2 Program/'<>c__DisplayClass5_0'::ig2 + IL_0011: ldfld class IGenInterface`2 Program/'<>c__DisplayClass7_0'::ig2 IL_0016: call string Program::GenInterfaceForwardNone(string, object, int32, object, class IGenInterface`2) IL_001b: ret - } // end of method '<>c__DisplayClass5_0'::'
b__19' + } // end of method '<>c__DisplayClass7_0'::'
b__23' + + .method assembly hidebysig instance string + '
b__24'() cil managed + { + // Code size 22 (0x16) + .maxstack 8 + IL_0000: ldstr "a" + IL_0005: ldstr "b" + IL_000a: ldarg.0 + IL_000b: ldfld class IGenInterface`2 Program/'<>c__DisplayClass7_0'::ig2 + IL_0010: call string Program::GenInterfaceForward2(string, + object, + class IGenInterface`2) + IL_0015: ret + } // end of method '<>c__DisplayClass7_0'::'
b__24' - } // end of class '<>c__DisplayClass5_0' + .method assembly hidebysig instance string + '
b__25'() cil managed + { + // Code size 12 (0xc) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld class GenAbstractImpl`1 Program/'<>c__DisplayClass7_0'::ga1 + IL_0006: call string Program::GenAbstractFString(class GenAbstract`1) + IL_000b: ret + } // end of method '<>c__DisplayClass7_0'::'
b__25' - .class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass5_1`1' + .method assembly hidebysig instance string + '
b__26'() cil managed + { + // Code size 12 (0xc) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld class GenAbstractImpl`1 Program/'<>c__DisplayClass7_0'::ga2 + IL_0006: call string Program::GenAbstractFInt(class GenAbstract`1) + IL_000b: ret + } // end of method '<>c__DisplayClass7_0'::'
b__26' + + .method assembly hidebysig instance string + '
b__27'() cil managed + { + // Code size 12 (0xc) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld class GenAbstractImpl`1 Program/'<>c__DisplayClass7_0'::ga1 + IL_0006: call string Program::GenAbstractGString(class GenAbstract`1) + IL_000b: ret + } // end of method '<>c__DisplayClass7_0'::'
b__27' + + .method assembly hidebysig instance string + '
b__28'() cil managed + { + // Code size 12 (0xc) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld class GenAbstractImpl`1 Program/'<>c__DisplayClass7_0'::ga2 + IL_0006: call string Program::GenAbstractGInt(class GenAbstract`1) + IL_000b: ret + } // end of method '<>c__DisplayClass7_0'::'
b__28' + + } // end of class '<>c__DisplayClass7_0' + + .class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass7_1`1' extends [System.Runtime]System.Object { .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) @@ -467,42 +553,45 @@ IL_0000: ldarg.0 IL_0001: call instance void [System.Runtime]System.Object::.ctor() IL_0006: ret - } // end of method '<>c__DisplayClass5_1`1'::.ctor + } // end of method '<>c__DisplayClass7_1`1'::.ctor .method assembly hidebysig instance !T - '
b__20'() cil managed + '
b__29'() cil managed { // Code size 18 (0x12) .maxstack 8 IL_0000: ldarg.0 - IL_0001: ldfld class [System.Runtime]System.Func`3 class Program/'<>c__DisplayClass5_1`1'::f + IL_0001: ldfld class [System.Runtime]System.Func`3 class Program/'<>c__DisplayClass7_1`1'::f IL_0006: ldc.i4 0xf4240 IL_000b: ldc.i4.0 IL_000c: callvirt instance !2 class [System.Runtime]System.Func`3::Invoke(!0, !1) IL_0011: ret - } // end of method '<>c__DisplayClass5_1`1'::'
b__20' + } // end of method '<>c__DisplayClass7_1`1'::'
b__29' - } // end of class '<>c__DisplayClass5_1`1' + } // end of class '<>c__DisplayClass7_1`1' .class auto ansi serializable sealed nested private beforefieldinit '<>c' extends [System.Runtime]System.Object { .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .field public static initonly class Program/'<>c' '<>9' - .field public static class [System.Runtime]System.Func`3 '<>9__5_2' - .field public static class [System.Runtime]System.Func`1 '<>9__5_3' - .field public static class [System.Runtime]System.Func`1 '<>9__5_5' - .field public static class [System.Runtime]System.Func`1 '<>9__5_6' - .field public static class [System.Runtime]System.Func`1 '<>9__5_7' - .field public static class [System.Runtime]System.Func`1 '<>9__5_8' - .field public static class [System.Runtime]System.Func`1 '<>9__5_9' - .field public static class [System.Runtime]System.Func`1 '<>9__5_10' - .field public static class [System.Runtime]System.Func`1 '<>9__5_11' - .field public static class [System.Runtime]System.Func`1 '<>9__5_12' - .field public static class [System.Runtime]System.Func`1 '<>9__5_13' - .field public static class [System.Runtime]System.Func`1 '<>9__5_14' - .field public static class [System.Runtime]System.Func`1 '<>9__5_15' + .field public static class [System.Runtime]System.Func`3 '<>9__7_2' + .field public static class [System.Runtime]System.Func`1 '<>9__7_3' + .field public static class [System.Runtime]System.Func`1 '<>9__7_4' + .field public static class [System.Runtime]System.Func`1 '<>9__7_5' + .field public static class [System.Runtime]System.Func`1 '<>9__7_6' + .field public static class [System.Runtime]System.Func`1 '<>9__7_8' + .field public static class [System.Runtime]System.Func`1 '<>9__7_9' + .field public static class [System.Runtime]System.Func`1 '<>9__7_10' + .field public static class [System.Runtime]System.Func`1 '<>9__7_11' + .field public static class [System.Runtime]System.Func`1 '<>9__7_12' + .field public static class [System.Runtime]System.Func`1 '<>9__7_13' + .field public static class [System.Runtime]System.Func`1 '<>9__7_14' + .field public static class [System.Runtime]System.Func`1 '<>9__7_15' + .field public static class [System.Runtime]System.Func`1 '<>9__7_16' + .field public static class [System.Runtime]System.Func`1 '<>9__7_17' + .field public static class [System.Runtime]System.Func`1 '<>9__7_18' .method private hidebysig specialname rtspecialname static void .cctor() cil managed { @@ -524,7 +613,7 @@ } // end of method '<>c'::.ctor .method assembly hidebysig instance int32 - '
b__5_2'(int32 x, + '
b__7_2'(int32 x, int32 s) cil managed { // Code size 13 (0xd) @@ -535,10 +624,37 @@ int32) IL_0007: ldsfld int32 Program::s_result IL_000c: ret - } // end of method '<>c'::'
b__5_2' + } // end of method '<>c'::'
b__7_2' + + .method assembly hidebysig instance string + '
b__7_3'() cil managed + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: call string Program::EmptyCalli() + IL_0005: ret + } // end of method '<>c'::'
b__7_3' + + .method assembly hidebysig instance string + '
b__7_4'() cil managed + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: call string Program::ValueTypeInstanceMethodCalli() + IL_0005: ret + } // end of method '<>c'::'
b__7_4' + + .method assembly hidebysig instance string + '
b__7_5'() cil managed + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: call string Program::ValueTypeExplicitThisInstanceMethodCalli() + IL_0005: ret + } // end of method '<>c'::'
b__7_5' .method assembly hidebysig instance int32 - '
b__5_3'() cil managed + '
b__7_6'() cil managed { // Code size 27 (0x1b) .maxstack 2 @@ -551,10 +667,10 @@ IL_0014: ldloc.0 IL_0015: ldfld int32 InstanceValueType::Count IL_001a: ret - } // end of method '<>c'::'
b__5_3' + } // end of method '<>c'::'
b__7_6' .method assembly hidebysig instance int32 - '
b__5_5'() cil managed + '
b__7_8'() cil managed { // Code size 17 (0x11) .maxstack 8 @@ -564,10 +680,10 @@ IL_000b: call int32 Program::CountUpHeap(int32, class HeapInt) IL_0010: ret - } // end of method '<>c'::'
b__5_5' + } // end of method '<>c'::'
b__7_8' .method assembly hidebysig instance int32 - '
b__5_6'() cil managed + '
b__7_9'() cil managed { // Code size 28 (0x1c) .maxstack 3 @@ -585,40 +701,40 @@ IL_0019: ldc.i4.0 IL_001a: ldelem.i4 IL_001b: ret - } // end of method '<>c'::'
b__5_6' + } // end of method '<>c'::'
b__7_9' .method assembly hidebysig instance string - '
b__5_7'() cil managed + '
b__7_10'() cil managed { // Code size 11 (0xb) .maxstack 8 IL_0000: ldstr "hello" IL_0005: call string Program::GenName1Forward(!!0) IL_000a: ret - } // end of method '<>c'::'
b__5_7' + } // end of method '<>c'::'
b__7_10' .method assembly hidebysig instance string - '
b__5_8'() cil managed + '
b__7_11'() cil managed { // Code size 11 (0xb) .maxstack 8 IL_0000: ldstr "hello" IL_0005: call string Program::GenName1Forward(!!0) IL_000a: ret - } // end of method '<>c'::'
b__5_8' + } // end of method '<>c'::'
b__7_11' .method assembly hidebysig instance string - '
b__5_9'() cil managed + '
b__7_12'() cil managed { // Code size 7 (0x7) .maxstack 8 IL_0000: ldc.i4.5 IL_0001: call string Program::GenName1Forward(!!0) IL_0006: ret - } // end of method '<>c'::'
b__5_9' + } // end of method '<>c'::'
b__7_12' .method assembly hidebysig instance string - '
b__5_10'() cil managed + '
b__7_13'() cil managed { // Code size 16 (0x10) .maxstack 8 @@ -627,10 +743,10 @@ IL_000a: call string Program::GenName2ForwardBoth(!!0, !!1) IL_000f: ret - } // end of method '<>c'::'
b__5_10' + } // end of method '<>c'::'
b__7_13' .method assembly hidebysig instance string - '
b__5_11'() cil managed + '
b__7_14'() cil managed { // Code size 12 (0xc) .maxstack 8 @@ -639,10 +755,10 @@ IL_0006: call string Program::GenName2ForwardBoth(!!0, !!1) IL_000b: ret - } // end of method '<>c'::'
b__5_11' + } // end of method '<>c'::'
b__7_14' .method assembly hidebysig instance string - '
b__5_12'() cil managed + '
b__7_15'() cil managed { // Code size 16 (0x10) .maxstack 8 @@ -651,10 +767,10 @@ IL_000a: call string Program::GenName2ForwardOne(!!0, string) IL_000f: ret - } // end of method '<>c'::'
b__5_12' + } // end of method '<>c'::'
b__7_15' .method assembly hidebysig instance string - '
b__5_13'() cil managed + '
b__7_16'() cil managed { // Code size 16 (0x10) .maxstack 8 @@ -663,10 +779,10 @@ IL_000a: call string Program::GenName2ForwardOne(!!0, string) IL_000f: ret - } // end of method '<>c'::'
b__5_13' + } // end of method '<>c'::'
b__7_16' .method assembly hidebysig instance string - '
b__5_14'() cil managed + '
b__7_17'() cil managed { // Code size 12 (0xc) .maxstack 8 @@ -675,10 +791,10 @@ IL_0006: call string Program::GenName2ForwardOne(!!0, string) IL_000b: ret - } // end of method '<>c'::'
b__5_14' + } // end of method '<>c'::'
b__7_17' .method assembly hidebysig instance string - '
b__5_15'() cil managed + '
b__7_18'() cil managed { // Code size 16 (0x10) .maxstack 8 @@ -687,7 +803,7 @@ IL_000a: call string Program::GenName2ForwardNone(object, string) IL_000f: ret - } // end of method '<>c'::'
b__5_15' + } // end of method '<>c'::'
b__7_18' } // end of class '<>c' @@ -695,16 +811,20 @@ .field private static initonly native int s_calcStaticCalliOther .field private static initonly native int s_calcStaticCalliRetbuf .field private static initonly native int s_calcStaticCalliRetbufOther + .field private static initonly native int s_emptyCalliOther + .field private static initonly native int s_instanceMethodOnValueType .field static assembly int32 s_result .method private hidebysig specialname rtspecialname static void .cctor() cil managed { - // Code size 53 (0x35) + // Code size 83 (0x53) .maxstack 1 .locals init (native int V_0, native int V_1, native int V_2, - native int V_3) + native int V_3, + native int V_4, + native int V_5) IL_0000: ldftn int32 Program::CalcStaticCalli(int32, int32) IL_0006: stloc.0 @@ -719,24 +839,32 @@ valuetype S32, int32) IL_001b: stloc.3 - IL_001c: ldloc.0 - IL_001d: stsfld native int Program::s_calcStaticCalli - IL_0022: ldloc.1 - IL_0023: stsfld native int Program::s_calcStaticCalliOther - IL_0028: ldloc.2 - IL_0029: stsfld native int Program::s_calcStaticCalliRetbuf - IL_002e: ldloc.3 - IL_002f: stsfld native int Program::s_calcStaticCalliRetbufOther - IL_0034: ret + IL_001c: ldftn string Program::EmptyCalliOther() + IL_0022: stloc.s V_4 + IL_0024: ldftn instance string S16::InstanceMethod() + IL_002a: stloc.s V_5 + IL_002c: ldloc.0 + IL_002d: stsfld native int Program::s_calcStaticCalli + IL_0032: ldloc.1 + IL_0033: stsfld native int Program::s_calcStaticCalliOther + IL_0038: ldloc.2 + IL_0039: stsfld native int Program::s_calcStaticCalliRetbuf + IL_003e: ldloc.3 + IL_003f: stsfld native int Program::s_calcStaticCalliRetbufOther + IL_0044: ldloc.s V_4 + IL_0046: stsfld native int Program::s_emptyCalliOther + IL_004b: ldloc.s V_5 + IL_004d: stsfld native int Program::s_instanceMethodOnValueType + IL_0052: ret } // end of method Program::.cctor .method private hidebysig static int32 Main() cil managed { .entrypoint - // Code size 1402 (0x57a) + // Code size 1733 (0x6c5) .maxstack 4 - .locals init (class Program/'<>c__DisplayClass5_0' V_0, + .locals init (class Program/'<>c__DisplayClass7_0' V_0, int32 V_1, valuetype S32 V_2, int32 V_3, @@ -747,7 +875,7 @@ valuetype S32 V_8, valuetype S16 V_9, valuetype S32 V_10) - IL_0000: newobj instance void Program/'<>c__DisplayClass5_0'::.ctor() + IL_0000: newobj instance void Program/'<>c__DisplayClass7_0'::.ctor() IL_0005: stloc.0 IL_0006: ldc.i4 0xf4240 IL_000b: stloc.1 @@ -775,7 +903,7 @@ IL_0033: ldloc.0 IL_0034: ldc.i4.1 - IL_0035: stfld bool Program/'<>c__DisplayClass5_0'::result + IL_0035: stfld bool Program/'<>c__DisplayClass7_0'::result IL_003a: newobj instance void ClassImpl::.ctor() IL_003f: stloc.s V_4 IL_0041: ldloc.s V_4 @@ -788,521 +916,639 @@ IL_0055: callvirt instance void InterfaceImpl::set_Other(class IInterface) IL_005a: ldloc.0 IL_005b: newobj instance void class GenInstance`2::.ctor() - IL_0060: stfld class GenInstance`2 Program/'<>c__DisplayClass5_0'::g + IL_0060: stfld class GenInstance`2 Program/'<>c__DisplayClass7_0'::g IL_0065: ldloc.0 IL_0066: newobj instance void class GenInterfaceImpl`2::.ctor() - IL_006b: stfld class IGenInterface`2 Program/'<>c__DisplayClass5_0'::ig + IL_006b: stfld class IGenInterface`2 Program/'<>c__DisplayClass7_0'::ig IL_0070: ldloc.0 IL_0071: newobj instance void class GenInterfaceImpl`2::.ctor() - IL_0076: stfld class IGenInterface`2 Program/'<>c__DisplayClass5_0'::ig2 - IL_007b: ldloc.3 - IL_007c: conv.u8 - IL_007d: ldc.i4.s 32 - IL_007f: shl - IL_0080: ldloc.3 - IL_0081: conv.u8 - IL_0082: or - IL_0083: stloc.s V_6 - IL_0085: ldloca.s V_9 - IL_0087: initobj S16 - IL_008d: ldloca.s V_9 - IL_008f: ldloc.3 - IL_0090: conv.i8 - IL_0091: stfld int64 S16::A - IL_0096: ldloca.s V_9 - IL_0098: ldloc.3 - IL_0099: conv.i8 - IL_009a: stfld int64 S16::B - IL_009f: ldloc.s V_9 - IL_00a1: stloc.s V_7 - IL_00a3: ldloca.s V_10 - IL_00a5: initobj S32 - IL_00ab: ldloca.s V_10 - IL_00ad: ldloc.3 - IL_00ae: conv.i8 - IL_00af: stfld int64 S32::A - IL_00b4: ldloca.s V_10 - IL_00b6: ldloc.3 - IL_00b7: conv.i8 - IL_00b8: stfld int64 S32::B - IL_00bd: ldloca.s V_10 - IL_00bf: ldloc.3 - IL_00c0: conv.i8 - IL_00c1: stfld int64 S32::C - IL_00c6: ldloca.s V_10 - IL_00c8: ldloc.3 - IL_00c9: conv.i8 - IL_00ca: stfld int64 S32::D - IL_00cf: ldloc.s V_10 - IL_00d1: stloc.s V_8 - IL_00d3: ldloc.0 - IL_00d4: ldc.i4.s 10 - IL_00d6: stfld int32 Program/'<>c__DisplayClass5_0'::ten - IL_00db: ldloc.0 - IL_00dc: ldnull - IL_00dd: ldftn int32 Program::CalcStatic(int32, + IL_0076: stfld class IGenInterface`2 Program/'<>c__DisplayClass7_0'::ig2 + IL_007b: ldloc.0 + IL_007c: newobj instance void class GenAbstractImpl`1::.ctor() + IL_0081: stfld class GenAbstractImpl`1 Program/'<>c__DisplayClass7_0'::ga1 + IL_0086: ldloc.0 + IL_0087: newobj instance void class GenAbstractImpl`1::.ctor() + IL_008c: stfld class GenAbstractImpl`1 Program/'<>c__DisplayClass7_0'::ga2 + IL_0091: ldloc.3 + IL_0092: conv.u8 + IL_0093: ldc.i4.s 32 + IL_0095: shl + IL_0096: ldloc.3 + IL_0097: conv.u8 + IL_0098: or + IL_0099: stloc.s V_6 + IL_009b: ldloca.s V_9 + IL_009d: initobj S16 + IL_00a3: ldloca.s V_9 + IL_00a5: ldloc.3 + IL_00a6: conv.i8 + IL_00a7: stfld int64 S16::A + IL_00ac: ldloca.s V_9 + IL_00ae: ldloc.3 + IL_00af: conv.i8 + IL_00b0: stfld int64 S16::B + IL_00b5: ldloc.s V_9 + IL_00b7: stloc.s V_7 + IL_00b9: ldloca.s V_10 + IL_00bb: initobj S32 + IL_00c1: ldloca.s V_10 + IL_00c3: ldloc.3 + IL_00c4: conv.i8 + IL_00c5: stfld int64 S32::A + IL_00ca: ldloca.s V_10 + IL_00cc: ldloc.3 + IL_00cd: conv.i8 + IL_00ce: stfld int64 S32::B + IL_00d3: ldloca.s V_10 + IL_00d5: ldloc.3 + IL_00d6: conv.i8 + IL_00d7: stfld int64 S32::C + IL_00dc: ldloca.s V_10 + IL_00de: ldloc.3 + IL_00df: conv.i8 + IL_00e0: stfld int64 S32::D + IL_00e5: ldloc.s V_10 + IL_00e7: stloc.s V_8 + IL_00e9: ldloc.0 + IL_00ea: ldc.i4.s 10 + IL_00ec: stfld int32 Program/'<>c__DisplayClass7_0'::ten + IL_00f1: ldloc.0 + IL_00f2: ldnull + IL_00f3: ldftn int32 Program::CalcStatic(int32, int32) - IL_00e3: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_00f9: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_00e8: ldloc.3 - IL_00e9: ldstr "Static non-generic" - IL_00ee: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_00fe: ldloc.3 + IL_00ff: ldstr "Static non-generic" + IL_0104: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_00f3: ldloc.0 - IL_00f4: ldnull - IL_00f5: ldftn uint8 Program::CalcStaticSmall(int32, + IL_0109: ldloc.0 + IL_010a: ldnull + IL_010b: ldftn uint8 Program::CalcStaticSmall(int32, int32) - IL_00fb: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_0111: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_0100: ldloc.3 - IL_0101: conv.u1 - IL_0102: ldstr "Static non-generic small" - IL_0107: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_0116: ldloc.3 + IL_0117: conv.u1 + IL_0118: ldstr "Static non-generic small" + IL_011d: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_010c: ldloc.0 - IL_010d: ldnull - IL_010e: ldftn valuetype S32 Program::CalcStaticRetbuf(int32, + IL_0122: ldloc.0 + IL_0123: ldnull + IL_0124: ldftn valuetype S32 Program::CalcStaticRetbuf(int32, int32) - IL_0114: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_012a: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_0119: ldloc.s V_8 - IL_011b: ldstr "Static non-generic retbuf" - IL_0120: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_012f: ldloc.s V_8 + IL_0131: ldstr "Static non-generic retbuf" + IL_0136: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_0125: ldloc.0 - IL_0126: ldnull - IL_0127: ldftn int64 Program::CalcStaticLong(int32, + IL_013b: ldloc.0 + IL_013c: ldnull + IL_013d: ldftn int64 Program::CalcStaticLong(int32, int32) - IL_012d: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_0143: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_0132: ldloc.s V_6 - IL_0134: ldstr "Static non-generic long" - IL_0139: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_0148: ldloc.s V_6 + IL_014a: ldstr "Static non-generic long" + IL_014f: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_013e: ldloc.0 - IL_013f: ldnull - IL_0140: ldftn valuetype S16 Program::CalcStaticS16(int32, + IL_0154: ldloc.0 + IL_0155: ldnull + IL_0156: ldftn valuetype S16 Program::CalcStaticS16(int32, int32) - IL_0146: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_015c: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_014b: ldloc.s V_7 - IL_014d: ldstr "Static non-generic S16" - IL_0152: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_0161: ldloc.s V_7 + IL_0163: ldstr "Static non-generic S16" + IL_0168: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_0157: ldloc.0 - IL_0158: ldsfld class [System.Runtime]System.Func`3 Program/'<>c'::'<>9__5_2' - IL_015d: dup - IL_015e: brtrue.s IL_0177 - - IL_0160: pop - IL_0161: ldsfld class Program/'<>c' Program/'<>c'::'<>9' - IL_0166: ldftn instance int32 Program/'<>c'::'
b__5_2'(int32, + IL_016d: ldloc.0 + IL_016e: ldsfld class [System.Runtime]System.Func`3 Program/'<>c'::'<>9__7_2' + IL_0173: dup + IL_0174: brtrue.s IL_018d + + IL_0176: pop + IL_0177: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_017c: ldftn instance int32 Program/'<>c'::'
b__7_2'(int32, int32) - IL_016c: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_0182: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_0171: dup - IL_0172: stsfld class [System.Runtime]System.Func`3 Program/'<>c'::'<>9__5_2' - IL_0177: ldloc.3 - IL_0178: ldstr "Static void" - IL_017d: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_0187: dup + IL_0188: stsfld class [System.Runtime]System.Func`3 Program/'<>c'::'<>9__7_2' + IL_018d: ldloc.3 + IL_018e: ldstr "Static void" + IL_0193: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_0182: ldloc.0 - IL_0183: newobj instance void Instance::.ctor() - IL_0188: ldftn instance int32 Instance::CalcInstance(int32, + IL_0198: ldloc.0 + IL_0199: newobj instance void Instance::.ctor() + IL_019e: ldftn instance int32 Instance::CalcInstance(int32, int32) - IL_018e: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_01a4: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_0193: ldloc.3 - IL_0194: ldstr "Instance non-generic" - IL_0199: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_01a9: ldloc.3 + IL_01aa: ldstr "Instance non-generic" + IL_01af: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_019e: ldloc.0 - IL_019f: newobj instance void Instance::.ctor() - IL_01a4: ldftn instance valuetype S32 Instance::CalcInstanceRetbuf(int32, + IL_01b4: ldloc.0 + IL_01b5: newobj instance void Instance::.ctor() + IL_01ba: ldftn instance valuetype S32 Instance::CalcInstanceRetbuf(int32, int32) - IL_01aa: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_01c0: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_01af: ldloc.s V_8 - IL_01b1: ldstr "Instance non-generic retbuf" - IL_01b6: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_01c5: ldloc.s V_8 + IL_01c7: ldstr "Instance non-generic retbuf" + IL_01cc: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_01bb: ldloc.0 - IL_01bc: ldloc.s V_4 - IL_01be: dup - IL_01bf: ldvirtftn instance int32 BaseClass::CalcAbstract(int32, + IL_01d1: ldloc.0 + IL_01d2: ldloc.s V_4 + IL_01d4: dup + IL_01d5: ldvirtftn instance int32 BaseClass::CalcAbstract(int32, int32) - IL_01c5: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_01db: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_01ca: ldloc.3 - IL_01cb: ldstr "Abstract class non-generic" - IL_01d0: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_01e0: ldloc.3 + IL_01e1: ldstr "Abstract class non-generic" + IL_01e6: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_01d5: ldloc.0 - IL_01d6: ldloc.s V_4 - IL_01d8: dup - IL_01d9: ldvirtftn instance valuetype S32 BaseClass::CalcAbstractRetbuf(int32, + IL_01eb: ldloc.0 + IL_01ec: ldloc.s V_4 + IL_01ee: dup + IL_01ef: ldvirtftn instance valuetype S32 BaseClass::CalcAbstractRetbuf(int32, int32) - IL_01df: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_01f5: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_01e4: ldloc.s V_8 - IL_01e6: ldstr "Abstract class non-generic retbuf" - IL_01eb: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_01fa: ldloc.s V_8 + IL_01fc: ldstr "Abstract class non-generic retbuf" + IL_0201: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_01f0: ldloc.0 - IL_01f1: ldloc.s V_5 - IL_01f3: dup - IL_01f4: ldvirtftn instance int32 InterfaceImpl::CalcInterface(int32, + IL_0206: ldloc.0 + IL_0207: ldloc.s V_5 + IL_0209: dup + IL_020a: ldvirtftn instance int32 InterfaceImpl::CalcInterface(int32, int32) - IL_01fa: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_0210: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_01ff: ldloc.3 - IL_0200: ldstr "Interface non-generic" - IL_0205: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_0215: ldloc.3 + IL_0216: ldstr "Interface non-generic" + IL_021b: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_020a: ldloc.0 - IL_020b: ldloc.s V_5 - IL_020d: dup - IL_020e: ldvirtftn instance valuetype S32 InterfaceImpl::CalcInterfaceRetbuf(int32, + IL_0220: ldloc.0 + IL_0221: ldloc.s V_5 + IL_0223: dup + IL_0224: ldvirtftn instance valuetype S32 InterfaceImpl::CalcInterfaceRetbuf(int32, int32) - IL_0214: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_022a: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_0219: ldloc.s V_8 - IL_021b: ldstr "Interface non-generic retbuf" - IL_0220: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_022f: ldloc.s V_8 + IL_0231: ldstr "Interface non-generic retbuf" + IL_0236: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_0225: ldloc.0 - IL_0226: ldnull - IL_0227: ldftn int32 Program::CalcStaticCalli(int32, + IL_023b: ldloc.0 + IL_023c: ldnull + IL_023d: ldftn int32 Program::CalcStaticCalli(int32, int32) - IL_022d: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_0243: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_0232: ldloc.3 - IL_0233: ldstr "Static calli" - IL_0238: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_0248: ldloc.3 + IL_0249: ldstr "Static calli" + IL_024e: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_023d: ldloc.0 - IL_023e: ldnull - IL_023f: ldftn valuetype S32 Program::CalcStaticCalliRetbuf(int32, + IL_0253: ldloc.0 + IL_0254: ldnull + IL_0255: ldftn valuetype S32 Program::CalcStaticCalliRetbuf(int32, int32) - IL_0245: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_025b: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_024a: ldloc.s V_8 - IL_024c: ldstr "Static calli retbuf" - IL_0251: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_0260: ldloc.s V_8 + IL_0262: ldstr "Static calli retbuf" + IL_0267: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_0256: ldloc.0 - IL_0257: newobj instance void Instance::.ctor() - IL_025c: ldftn instance int32 Instance::CalcInstanceCalli(int32, + IL_026c: ldloc.0 + IL_026d: newobj instance void Instance::.ctor() + IL_0272: ldftn instance int32 Instance::CalcInstanceCalli(int32, int32) - IL_0262: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_0278: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_0267: ldloc.3 - IL_0268: ldstr "Instance calli" - IL_026d: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_027d: ldloc.3 + IL_027e: ldstr "Instance calli" + IL_0283: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_0272: ldloc.0 - IL_0273: newobj instance void Instance::.ctor() - IL_0278: ldftn instance valuetype S32 Instance::CalcInstanceCalliRetbuf(int32, + IL_0288: ldloc.0 + IL_0289: newobj instance void Instance::.ctor() + IL_028e: ldftn instance valuetype S32 Instance::CalcInstanceCalliRetbuf(int32, int32) - IL_027e: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, + IL_0294: newobj instance void class [System.Runtime]System.Func`3::.ctor(object, native int) - IL_0283: ldloc.s V_8 - IL_0285: ldstr "Instance calli retbuf" - IL_028a: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, + IL_0299: ldloc.s V_8 + IL_029b: ldstr "Instance calli retbuf" + IL_02a0: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__TestCalc|1'(class [System.Runtime]System.Func`3, !!0, string) - IL_028f: ldloc.0 - IL_0290: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_3' - IL_0295: dup - IL_0296: brtrue.s IL_02af - - IL_0298: pop - IL_0299: ldsfld class Program/'<>c' Program/'<>c'::'<>9' - IL_029e: ldftn instance int32 Program/'<>c'::'
b__5_3'() - IL_02a4: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_02a5: ldloc.0 + IL_02a6: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_3' + IL_02ab: dup + IL_02ac: brtrue.s IL_02c5 + + IL_02ae: pop + IL_02af: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_02b4: ldftn instance string Program/'<>c'::'
b__7_3'() + IL_02ba: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + native int) + IL_02bf: dup + IL_02c0: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_3' + IL_02c5: ldstr "Empty calli" + IL_02ca: ldstr "Static calli without args" + IL_02cf: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + !!0, + string) + IL_02d4: ldloc.0 + IL_02d5: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_4' + IL_02da: dup + IL_02db: brtrue.s IL_02f4 + + IL_02dd: pop + IL_02de: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_02e3: ldftn instance string Program/'<>c'::'
b__7_4'() + IL_02e9: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + native int) + IL_02ee: dup + IL_02ef: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_4' + IL_02f4: ldstr "Instance method" + IL_02f9: ldstr "calli to an instance method on a value type" + IL_02fe: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + !!0, + string) + IL_0303: ldloc.0 + IL_0304: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_5' + IL_0309: dup + IL_030a: brtrue.s IL_0323 + + IL_030c: pop + IL_030d: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_0312: ldftn instance string Program/'<>c'::'
b__7_5'() + IL_0318: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + native int) + IL_031d: dup + IL_031e: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_5' + IL_0323: ldstr "Instance method" + IL_0328: ldstr "calli to an instance method on a value type with e" + + "xplicit this" + IL_032d: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + !!0, + string) + IL_0332: ldloc.0 + IL_0333: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_6' + IL_0338: dup + IL_0339: brtrue.s IL_0352 + + IL_033b: pop + IL_033c: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_0341: ldftn instance int32 Program/'<>c'::'
b__7_6'() + IL_0347: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_02a9: dup - IL_02aa: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_3' - IL_02af: ldc.i4 0xf4240 - IL_02b4: ldstr "Value type instance call" - IL_02b9: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_034c: dup + IL_034d: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_6' + IL_0352: ldc.i4 0xf4240 + IL_0357: ldstr "Value type instance call" + IL_035c: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_02be: ldloc.0 - IL_02bf: ldloc.0 - IL_02c0: ldftn instance string Program/'<>c__DisplayClass5_0'::'
b__4'() - IL_02c6: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_0361: ldloc.0 + IL_0362: ldloc.0 + IL_0363: ldftn instance string Program/'<>c__DisplayClass7_0'::'
b__7'() + IL_0369: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_02cb: ldstr "2 3 4 5 6 7 8 9 10" - IL_02d0: ldstr "Instance with GC" - IL_02d5: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_036e: ldstr "2 3 4 5 6 7 8 9 10" + IL_0373: ldstr "Instance with GC" + IL_0378: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_02da: ldloc.0 - IL_02db: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_5' - IL_02e0: dup - IL_02e1: brtrue.s IL_02fa - - IL_02e3: pop - IL_02e4: ldsfld class Program/'<>c' Program/'<>c'::'<>9' - IL_02e9: ldftn instance int32 Program/'<>c'::'
b__5_5'() - IL_02ef: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_037d: ldloc.0 + IL_037e: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_8' + IL_0383: dup + IL_0384: brtrue.s IL_039d + + IL_0386: pop + IL_0387: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_038c: ldftn instance int32 Program/'<>c'::'
b__7_8'() + IL_0392: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_02f4: dup - IL_02f5: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_5' - IL_02fa: ldc.i4 0xf4240 - IL_02ff: ldstr "Count up with heap int" - IL_0304: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_0397: dup + IL_0398: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_8' + IL_039d: ldc.i4 0xf4240 + IL_03a2: ldstr "Count up with heap int" + IL_03a7: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_0309: ldloc.0 - IL_030a: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_6' - IL_030f: dup - IL_0310: brtrue.s IL_0329 - - IL_0312: pop - IL_0313: ldsfld class Program/'<>c' Program/'<>c'::'<>9' - IL_0318: ldftn instance int32 Program/'<>c'::'
b__5_6'() - IL_031e: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_03ac: ldloc.0 + IL_03ad: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_9' + IL_03b2: dup + IL_03b3: brtrue.s IL_03cc + + IL_03b5: pop + IL_03b6: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_03bb: ldftn instance int32 Program/'<>c'::'
b__7_9'() + IL_03c1: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_0323: dup - IL_0324: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_6' - IL_0329: ldc.i4 0xf4240 - IL_032e: ldstr "Count up with byref to heap" - IL_0333: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_03c6: dup + IL_03c7: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_9' + IL_03cc: ldc.i4 0xf4240 + IL_03d1: ldstr "Count up with byref to heap" + IL_03d6: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_0338: ldloc.0 - IL_0339: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_7' - IL_033e: dup - IL_033f: brtrue.s IL_0358 - - IL_0341: pop - IL_0342: ldsfld class Program/'<>c' Program/'<>c'::'<>9' - IL_0347: ldftn instance string Program/'<>c'::'
b__5_7'() - IL_034d: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_03db: ldloc.0 + IL_03dc: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_10' + IL_03e1: dup + IL_03e2: brtrue.s IL_03fb + + IL_03e4: pop + IL_03e5: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_03ea: ldftn instance string Program/'<>c'::'
b__7_10'() + IL_03f0: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_0352: dup - IL_0353: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_7' - IL_0358: ldstr "System.String hello" - IL_035d: ldstr "Static generic string" - IL_0362: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_03f5: dup + IL_03f6: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_10' + IL_03fb: ldstr "System.String hello" + IL_0400: ldstr "Static generic string" + IL_0405: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_0367: ldloc.0 - IL_0368: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_8' - IL_036d: dup - IL_036e: brtrue.s IL_0387 - - IL_0370: pop - IL_0371: ldsfld class Program/'<>c' Program/'<>c'::'<>9' - IL_0376: ldftn instance string Program/'<>c'::'
b__5_8'() - IL_037c: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_040a: ldloc.0 + IL_040b: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_11' + IL_0410: dup + IL_0411: brtrue.s IL_042a + + IL_0413: pop + IL_0414: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_0419: ldftn instance string Program/'<>c'::'
b__7_11'() + IL_041f: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_0381: dup - IL_0382: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_8' - IL_0387: ldstr "System.Object hello" - IL_038c: ldstr "Static generic object" - IL_0391: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_0424: dup + IL_0425: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_11' + IL_042a: ldstr "System.Object hello" + IL_042f: ldstr "Static generic object" + IL_0434: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_0396: ldloc.0 - IL_0397: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_9' - IL_039c: dup - IL_039d: brtrue.s IL_03b6 - - IL_039f: pop - IL_03a0: ldsfld class Program/'<>c' Program/'<>c'::'<>9' - IL_03a5: ldftn instance string Program/'<>c'::'
b__5_9'() - IL_03ab: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_0439: ldloc.0 + IL_043a: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_12' + IL_043f: dup + IL_0440: brtrue.s IL_0459 + + IL_0442: pop + IL_0443: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_0448: ldftn instance string Program/'<>c'::'
b__7_12'() + IL_044e: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_03b0: dup - IL_03b1: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_9' - IL_03b6: ldstr "System.Int32 5" - IL_03bb: ldstr "Static generic int" - IL_03c0: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_0453: dup + IL_0454: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_12' + IL_0459: ldstr "System.Int32 5" + IL_045e: ldstr "Static generic int" + IL_0463: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_03c5: ldloc.0 - IL_03c6: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_10' - IL_03cb: dup - IL_03cc: brtrue.s IL_03e5 - - IL_03ce: pop - IL_03cf: ldsfld class Program/'<>c' Program/'<>c'::'<>9' - IL_03d4: ldftn instance string Program/'<>c'::'
b__5_10'() - IL_03da: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_0468: ldloc.0 + IL_0469: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_13' + IL_046e: dup + IL_046f: brtrue.s IL_0488 + + IL_0471: pop + IL_0472: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_0477: ldftn instance string Program/'<>c'::'
b__7_13'() + IL_047d: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_03df: dup - IL_03e0: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_10' - IL_03e5: ldstr "System.String System.Object hello hello2" - IL_03ea: ldstr "Static generic 2 string object" - IL_03ef: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_0482: dup + IL_0483: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_13' + IL_0488: ldstr "System.String System.Object hello hello2" + IL_048d: ldstr "Static generic 2 string object" + IL_0492: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_03f4: ldloc.0 - IL_03f5: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_11' - IL_03fa: dup - IL_03fb: brtrue.s IL_0414 - - IL_03fd: pop - IL_03fe: ldsfld class Program/'<>c' Program/'<>c'::'<>9' - IL_0403: ldftn instance string Program/'<>c'::'
b__5_11'() - IL_0409: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_0497: ldloc.0 + IL_0498: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_14' + IL_049d: dup + IL_049e: brtrue.s IL_04b7 + + IL_04a0: pop + IL_04a1: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_04a6: ldftn instance string Program/'<>c'::'
b__7_14'() + IL_04ac: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_040e: dup - IL_040f: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_11' - IL_0414: ldstr "System.String System.Int32 hello 5" - IL_0419: ldstr "Static generic 2 string int" - IL_041e: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_04b1: dup + IL_04b2: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_14' + IL_04b7: ldstr "System.String System.Int32 hello 5" + IL_04bc: ldstr "Static generic 2 string int" + IL_04c1: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_0423: ldloc.0 - IL_0424: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_12' - IL_0429: dup - IL_042a: brtrue.s IL_0443 - - IL_042c: pop - IL_042d: ldsfld class Program/'<>c' Program/'<>c'::'<>9' - IL_0432: ldftn instance string Program/'<>c'::'
b__5_12'() - IL_0438: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_04c6: ldloc.0 + IL_04c7: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_15' + IL_04cc: dup + IL_04cd: brtrue.s IL_04e6 + + IL_04cf: pop + IL_04d0: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_04d5: ldftn instance string Program/'<>c'::'
b__7_15'() + IL_04db: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_043d: dup - IL_043e: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_12' - IL_0443: ldstr "System.String System.String hello hello2" - IL_0448: ldstr "Static generic 1 string" - IL_044d: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_04e0: dup + IL_04e1: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_15' + IL_04e6: ldstr "System.String System.String hello hello2" + IL_04eb: ldstr "Static generic 1 string" + IL_04f0: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_0452: ldloc.0 - IL_0453: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_13' - IL_0458: dup - IL_0459: brtrue.s IL_0472 - - IL_045b: pop - IL_045c: ldsfld class Program/'<>c' Program/'<>c'::'<>9' - IL_0461: ldftn instance string Program/'<>c'::'
b__5_13'() - IL_0467: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_04f5: ldloc.0 + IL_04f6: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_16' + IL_04fb: dup + IL_04fc: brtrue.s IL_0515 + + IL_04fe: pop + IL_04ff: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_0504: ldftn instance string Program/'<>c'::'
b__7_16'() + IL_050a: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_046c: dup - IL_046d: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_13' - IL_0472: ldstr "System.Object System.String hello hello2" - IL_0477: ldstr "Static generic 1 object" - IL_047c: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_050f: dup + IL_0510: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_16' + IL_0515: ldstr "System.Object System.String hello hello2" + IL_051a: ldstr "Static generic 1 object" + IL_051f: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_0481: ldloc.0 - IL_0482: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_14' - IL_0487: dup - IL_0488: brtrue.s IL_04a1 - - IL_048a: pop - IL_048b: ldsfld class Program/'<>c' Program/'<>c'::'<>9' - IL_0490: ldftn instance string Program/'<>c'::'
b__5_14'() - IL_0496: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_0524: ldloc.0 + IL_0525: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_17' + IL_052a: dup + IL_052b: brtrue.s IL_0544 + + IL_052d: pop + IL_052e: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_0533: ldftn instance string Program/'<>c'::'
b__7_17'() + IL_0539: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_049b: dup - IL_049c: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_14' - IL_04a1: ldstr "System.Int32 System.String 5 hello2" - IL_04a6: ldstr "Static generic 1 int" - IL_04ab: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_053e: dup + IL_053f: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_17' + IL_0544: ldstr "System.Int32 System.String 5 hello2" + IL_0549: ldstr "Static generic 1 int" + IL_054e: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_04b0: ldloc.0 - IL_04b1: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_15' - IL_04b6: dup - IL_04b7: brtrue.s IL_04d0 - - IL_04b9: pop - IL_04ba: ldsfld class Program/'<>c' Program/'<>c'::'<>9' - IL_04bf: ldftn instance string Program/'<>c'::'
b__5_15'() - IL_04c5: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_0553: ldloc.0 + IL_0554: ldsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_18' + IL_0559: dup + IL_055a: brtrue.s IL_0573 + + IL_055c: pop + IL_055d: ldsfld class Program/'<>c' Program/'<>c'::'<>9' + IL_0562: ldftn instance string Program/'<>c'::'
b__7_18'() + IL_0568: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_04ca: dup - IL_04cb: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__5_15' - IL_04d0: ldstr "System.Object System.String hello hello2" - IL_04d5: ldstr "Static generic 0" - IL_04da: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_056d: dup + IL_056e: stsfld class [System.Runtime]System.Func`1 Program/'<>c'::'<>9__7_18' + IL_0573: ldstr "System.Object System.String hello hello2" + IL_0578: ldstr "Static generic 0" + IL_057d: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_04df: ldloc.0 - IL_04e0: ldloc.0 - IL_04e1: ldftn instance string Program/'<>c__DisplayClass5_0'::'
b__16'() - IL_04e7: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_0582: ldloc.0 + IL_0583: ldloc.0 + IL_0584: ldftn instance string Program/'<>c__DisplayClass7_0'::'
b__19'() + IL_058a: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_04ec: ldstr "System.String System.Int32 System.Object System.St" + IL_058f: ldstr "System.String System.Int32 System.Object System.St" + "ring a 5 b c" - IL_04f1: ldstr "Instance generic 4" - IL_04f6: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_0594: ldstr "Instance generic 4" + IL_0599: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_04fb: ldloc.0 - IL_04fc: ldloc.0 - IL_04fd: ldftn instance string Program/'<>c__DisplayClass5_0'::'
b__17'() - IL_0503: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_059e: ldloc.0 + IL_059f: ldloc.0 + IL_05a0: ldftn instance string Program/'<>c__DisplayClass7_0'::'
b__20'() + IL_05a6: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_0508: ldstr "System.String System.Int32 System.Object System.St" + IL_05ab: ldstr "System.String System.Int32 System.Object System.St" + "ring a 5 b c" - IL_050d: ldstr "Virtual instance generic 4" - IL_0512: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_05b0: ldstr "Virtual instance generic 4" + IL_05b5: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_0517: ldloc.0 - IL_0518: ldloc.0 - IL_0519: ldftn instance string Program/'<>c__DisplayClass5_0'::'
b__18'() - IL_051f: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_05ba: ldloc.0 + IL_05bb: ldloc.0 + IL_05bc: ldftn instance string Program/'<>c__DisplayClass7_0'::'
b__21'() + IL_05c2: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_0524: ldstr "System.String System.Int32 System.String System.Ob" + IL_05c7: ldstr "System.String System.Int32 System.String System.Ob" + "ject a 5 c d" - IL_0529: ldstr "Interface generic 4" - IL_052e: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_05cc: ldstr "Interface generic 4" + IL_05d1: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_0533: ldloc.0 - IL_0534: ldloc.0 - IL_0535: ldftn instance string Program/'<>c__DisplayClass5_0'::'
b__19'() - IL_053b: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + IL_05d6: ldloc.0 + IL_05d7: ldloc.0 + IL_05d8: ldftn instance string Program/'<>c__DisplayClass7_0'::'
b__22'() + IL_05de: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, native int) - IL_0540: ldstr "System.String System.Object System.Int32 System.Ob" + IL_05e3: ldstr "System.String System.Int32 a 5" + IL_05e8: ldstr "Interface generic forward G" + IL_05ed: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + !!0, + string) + IL_05f2: ldloc.0 + IL_05f3: ldloc.0 + IL_05f4: ldftn instance string Program/'<>c__DisplayClass7_0'::'
b__23'() + IL_05fa: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + native int) + IL_05ff: ldstr "System.String System.Object System.Int32 System.Ob" + "ject a b 5 d" - IL_0545: ldstr "Interface generic 0" - IL_054a: callvirt instance void Program/'<>c__DisplayClass5_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + IL_0604: ldstr "Interface generic 0" + IL_0609: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + !!0, + string) + IL_060e: ldloc.0 + IL_060f: ldloc.0 + IL_0610: ldftn instance string Program/'<>c__DisplayClass7_0'::'
b__24'() + IL_0616: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + native int) + IL_061b: ldstr "System.String System.Object a b" + IL_0620: ldstr "Interface generic without generics on method" + IL_0625: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + !!0, + string) + IL_062a: ldloc.0 + IL_062b: ldloc.0 + IL_062c: ldftn instance string Program/'<>c__DisplayClass7_0'::'
b__25'() + IL_0632: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + native int) + IL_0637: ldstr "System.String System.Object" + IL_063c: ldstr "Abstract generic with generic on method 1" + IL_0641: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + !!0, + string) + IL_0646: ldloc.0 + IL_0647: ldloc.0 + IL_0648: ldftn instance string Program/'<>c__DisplayClass7_0'::'
b__26'() + IL_064e: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + native int) + IL_0653: ldstr "System.Int32 System.Object" + IL_0658: ldstr "Abstract generic with generic on method 2" + IL_065d: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, !!0, string) - IL_054f: ldloc.0 - IL_0550: ldfld bool Program/'<>c__DisplayClass5_0'::result - IL_0555: brfalse.s IL_0563 + IL_0662: ldloc.0 + IL_0663: ldloc.0 + IL_0664: ldftn instance string Program/'<>c__DisplayClass7_0'::'
b__27'() + IL_066a: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + native int) + IL_066f: ldstr "System.String" + IL_0674: ldstr "Abstract generic without generic on method 1" + IL_0679: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + !!0, + string) + IL_067e: ldloc.0 + IL_067f: ldloc.0 + IL_0680: ldftn instance string Program/'<>c__DisplayClass7_0'::'
b__28'() + IL_0686: newobj instance void class [System.Runtime]System.Func`1::.ctor(object, + native int) + IL_068b: ldstr "System.Int32" + IL_0690: ldstr "Abstract generic without generic on method 2" + IL_0695: callvirt instance void Program/'<>c__DisplayClass7_0'::'
g__Test|0'(class [System.Runtime]System.Func`1, + !!0, + string) + IL_069a: ldloc.0 + IL_069b: ldfld bool Program/'<>c__DisplayClass7_0'::result + IL_06a0: brfalse.s IL_06ae - IL_0557: ldstr "All tailcall-via-help succeeded" - IL_055c: call void [System.Console]System.Console::WriteLine(string) - IL_0561: br.s IL_056d + IL_06a2: ldstr "All tailcall-via-help succeeded" + IL_06a7: call void [System.Console]System.Console::WriteLine(string) + IL_06ac: br.s IL_06b8 - IL_0563: ldstr "One or more failures in tailcall-via-help test" - IL_0568: call void [System.Console]System.Console::WriteLine(string) - IL_056d: ldloc.0 - IL_056e: ldfld bool Program/'<>c__DisplayClass5_0'::result - IL_0573: brtrue.s IL_0577 + IL_06ae: ldstr "One or more failures in tailcall-via-help test" + IL_06b3: call void [System.Console]System.Console::WriteLine(string) + IL_06b8: ldloc.0 + IL_06b9: ldfld bool Program/'<>c__DisplayClass7_0'::result + IL_06be: brtrue.s IL_06c2 - IL_0575: ldc.i4.1 - IL_0576: ret + IL_06c0: ldc.i4.1 + IL_06c1: ret - IL_0577: ldc.i4.s 100 - IL_0579: ret + IL_06c2: ldc.i4.s 100 + IL_06c4: ret } // end of method Program::Main .method public hidebysig static void Calc(int32& x, @@ -1772,6 +2018,113 @@ IL_0019: ret } // end of method Program::CalcStaticCalliOther + .method private hidebysig static string + EmptyCalli() cil managed noinlining + { + // Code size 41 (0x29) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: call int32 [System.Runtime.Extensions]System.Environment::get_TickCount() + IL_0005: ldc.i4.0 + IL_0006: blt.s IL_000c + + IL_0008: ldc.i4.s 40 + IL_000a: br.s IL_000e + + IL_000c: ldc.i4.s 30 + IL_000e: stloc.0 + IL_000f: ldloc.0 + IL_0010: conv.u + IL_0011: ldc.i4.4 + IL_0012: mul.ovf.un + IL_0013: localloc + IL_0015: ldloc.0 + IL_0016: newobj instance void valuetype [System.Runtime]System.Span`1::.ctor(void*, + int32) + IL_001b: pop + IL_001c: ldsfld native int Program::s_emptyCalliOther + IL_0021: tail. + IL_0023: calli string() + IL_0028: ret + } // end of method Program::EmptyCalli + + .method private hidebysig static string + ValueTypeInstanceMethodCalli() cil managed noinlining + { + // Code size 51 (0x33) + .maxstack 2 + .locals init (valuetype S16 V_0, + int32 V_1) + IL_0000: call int32 [System.Runtime.Extensions]System.Environment::get_TickCount() + IL_0005: ldc.i4.0 + IL_0006: blt.s IL_000c + + IL_0008: ldc.i4.s 40 + IL_000a: br.s IL_000e + + IL_000c: ldc.i4.s 30 + IL_000e: stloc.1 + IL_000f: ldloc.1 + IL_0010: conv.u + IL_0011: ldc.i4.4 + IL_0012: mul.ovf.un + IL_0013: localloc + IL_0015: ldloc.1 + IL_0016: newobj instance void valuetype [System.Runtime]System.Span`1::.ctor(void*, + int32) + IL_001b: pop + IL_001c: ldloca.s V_0 + IL_001e: initobj S16 + IL_0024: ldloca.s V_0 + IL_0026: ldsfld native int Program::s_instanceMethodOnValueType + IL_002b: tail. + IL_002d: calli instance string() + IL_0032: ret + } // end of method Program::ValueTypeInstanceMethodCalli + + .method private hidebysig static string + ValueTypeExplicitThisInstanceMethodCalli() cil managed noinlining + { + // Code size 51 (0x33) + .maxstack 2 + .locals init (valuetype S16 V_0, + int32 V_1) + IL_0000: call int32 [System.Runtime.Extensions]System.Environment::get_TickCount() + IL_0005: ldc.i4.0 + IL_0006: blt.s IL_000c + + IL_0008: ldc.i4.s 40 + IL_000a: br.s IL_000e + + IL_000c: ldc.i4.s 30 + IL_000e: stloc.1 + IL_000f: ldloc.1 + IL_0010: conv.u + IL_0011: ldc.i4.4 + IL_0012: mul.ovf.un + IL_0013: localloc + IL_0015: ldloc.1 + IL_0016: newobj instance void valuetype [System.Runtime]System.Span`1::.ctor(void*, + int32) + IL_001b: pop + IL_001c: ldloca.s V_0 + IL_001e: initobj S16 + IL_0024: ldloca.s V_0 + IL_0026: ldsfld native int Program::s_instanceMethodOnValueType + IL_002b: tail. + IL_002d: calli explicit instance string(valuetype S16&) + IL_0032: ret + } // end of method Program::ValueTypeExplicitThisInstanceMethodCalli + + .method private hidebysig static string + EmptyCalliOther() cil managed noinlining + { + // Code size 6 (0x6) + .maxstack 8 + IL_0000: ldstr "Empty calli" + IL_0005: ret + } // end of method Program::EmptyCalliOther + .method private hidebysig static valuetype S32 CalcStaticCalliRetbuf(int32 x, int32 acc) cil managed noinlining @@ -2140,11 +2493,11 @@ } // end of method Program::GenName2 .method private hidebysig static string - GenInterfaceForward(!!T1 a, - !!T2 b, - !!T3 c, - !!T4 d, - class IGenInterface`2 igen) cil managed noinlining + GenInterfaceForwardF(!!T1 a, + !!T2 b, + !!T3 c, + !!T4 d, + class IGenInterface`2 igen) cil managed noinlining { // Code size 23 (0x17) .maxstack 6 @@ -2164,7 +2517,28 @@ !!0, !!1) IL_0016: ret - } // end of method Program::GenInterfaceForward + } // end of method Program::GenInterfaceForwardF + + .method private hidebysig static string + GenInterfaceForwardG(!!T1 a, + !!T2 b, + class IGenInterface`2 igen) cil managed noinlining + { + // Code size 20 (0x14) + .maxstack 4 + .locals init (valuetype S32 V_0) + IL_0000: ldarg.2 + IL_0001: ldloca.s V_0 + IL_0003: initobj S32 + IL_0009: ldloc.0 + IL_000a: ldarg.0 + IL_000b: ldarg.1 + IL_000c: tail. + IL_000e: callvirt instance string class IGenInterface`2::G(valuetype S32, + !0, + !1) + IL_0013: ret + } // end of method Program::GenInterfaceForwardG .method private hidebysig static string GenInterfaceForwardNone(string a, @@ -2193,6 +2567,71 @@ IL_0016: ret } // end of method Program::GenInterfaceForwardNone + .method private hidebysig static string + GenInterfaceForward2(string a, + object b, + class IGenInterface`2 igen) cil managed noinlining + { + // Code size 20 (0x14) + .maxstack 4 + .locals init (valuetype S32 V_0) + IL_0000: ldarg.2 + IL_0001: ldloca.s V_0 + IL_0003: initobj S32 + IL_0009: ldloc.0 + IL_000a: ldarg.0 + IL_000b: ldarg.1 + IL_000c: tail. + IL_000e: callvirt instance string class IGenInterface`2::G(valuetype S32, + !0, + !1) + IL_0013: ret + } // end of method Program::GenInterfaceForward2 + + .method private hidebysig static string + GenAbstractFString(class GenAbstract`1 ga) cil managed noinlining + { + // Code size 9 (0x9) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: tail. + IL_0003: callvirt instance string class GenAbstract`1::F() + IL_0008: ret + } // end of method Program::GenAbstractFString + + .method private hidebysig static string + GenAbstractGString(class GenAbstract`1 ga) cil managed noinlining + { + // Code size 9 (0x9) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: tail. + IL_0003: callvirt instance string class GenAbstract`1::G() + IL_0008: ret + } // end of method Program::GenAbstractGString + + .method private hidebysig static string + GenAbstractFInt(class GenAbstract`1 ga) cil managed noinlining + { + // Code size 9 (0x9) + .maxstack 1 + IL_0000: ldarg.0 + IL_0001: tail. + IL_0003: callvirt instance string class GenAbstract`1::F() + IL_0008: ret + } // end of method Program::GenAbstractFInt + + .method private hidebysig static string + GenAbstractGInt(class GenAbstract`1 ga) cil managed noinlining + { + // Code size 9 (0x9) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: tail. + IL_0003: callvirt instance string class GenAbstract`1::G() + IL_0008: ret + } // end of method Program::GenAbstractGInt + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { @@ -3403,6 +3842,13 @@ { } // end of method IGenInterface`2::F + .method public hidebysig newslot abstract virtual + instance string G(valuetype S32 s, + !T1 a, + !T2 b) cil managed + { + } // end of method IGenInterface`2::G + } // end of class IGenInterface`2 .class private auto ansi beforefieldinit GenInterfaceImpl`2 @@ -3470,6 +3916,43 @@ IL_007e: ret } // end of method GenInterfaceImpl`2::F + .method public hidebysig newslot virtual final + instance string G(valuetype S32 s, + !T1 a, + !T2 b) cil managed + { + // Code size 71 (0x47) + .maxstack 5 + IL_0000: ldstr "{0} {1} {2} {3}" + IL_0005: ldc.i4.4 + IL_0006: newarr [System.Runtime]System.Object + IL_000b: dup + IL_000c: ldc.i4.0 + IL_000d: ldtoken !T1 + IL_0012: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle) + IL_0017: callvirt instance string [System.Runtime]System.Type::get_FullName() + IL_001c: stelem.ref + IL_001d: dup + IL_001e: ldc.i4.1 + IL_001f: ldtoken !T2 + IL_0024: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle) + IL_0029: callvirt instance string [System.Runtime]System.Type::get_FullName() + IL_002e: stelem.ref + IL_002f: dup + IL_0030: ldc.i4.2 + IL_0031: ldarg.2 + IL_0032: box !T1 + IL_0037: stelem.ref + IL_0038: dup + IL_0039: ldc.i4.3 + IL_003a: ldarg.3 + IL_003b: box !T2 + IL_0040: stelem.ref + IL_0041: call string [System.Runtime]System.String::Format(string, + object[]) + IL_0046: ret + } // end of method GenInterfaceImpl`2::G + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { @@ -3482,6 +3965,88 @@ } // end of class GenInterfaceImpl`2 +.class private abstract auto ansi beforefieldinit GenAbstract`1 + extends [System.Runtime]System.Object +{ + .method public hidebysig newslot abstract virtual + instance string F() cil managed + { + } // end of method GenAbstract`1::F + + .method public hidebysig newslot abstract virtual + instance string G() cil managed + { + } // end of method GenAbstract`1::G + + .method family hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [System.Runtime]System.Object::.ctor() + IL_0006: ret + } // end of method GenAbstract`1::.ctor + +} // end of class GenAbstract`1 + +.class private auto ansi beforefieldinit GenAbstractImpl`1 + extends class GenAbstract`1 +{ + .method public hidebysig virtual instance string + F() cil managed + { + // Code size 41 (0x29) + .maxstack 8 + IL_0000: ldtoken !T1 + IL_0005: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle) + IL_000a: callvirt instance string [System.Runtime]System.Type::get_FullName() + IL_000f: ldstr " " + IL_0014: ldtoken !!T2 + IL_0019: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle) + IL_001e: callvirt instance string [System.Runtime]System.Type::get_FullName() + IL_0023: call string [System.Runtime]System.String::Concat(string, + string, + string) + IL_0028: ret + } // end of method GenAbstractImpl`1::F + + .method public hidebysig virtual instance string + G() cil managed + { + // Code size 25 (0x19) + .maxstack 8 + IL_0000: ldtoken !T1 + IL_0005: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle) + IL_000a: callvirt instance string [System.Runtime]System.Type::get_FullName() + IL_000f: dup + IL_0010: brtrue.s IL_0018 + + IL_0012: pop + IL_0013: ldstr "" + IL_0018: ret + } // end of method GenAbstractImpl`1::G + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void class GenAbstract`1::.ctor() + IL_0006: ret + } // end of method GenAbstractImpl`1::.ctor + +} // end of class GenAbstractImpl`1 + +.class private auto ansi example1_Fody.ProcessedByFody + extends [System.Runtime]System.Object +{ + .field static assembly literal string FodyVersion = "6.1.1.0" + .field static assembly literal string InlineIL = "1.4.0.0" +} // end of class example1_Fody.ProcessedByFody + + // ============================================================= // *********** DISASSEMBLY COMPLETE *********************** diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.Byte.cs new file mode 100644 index 00000000000000..fdc7c08a356aec --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.Byte.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturateScalar_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturateScalar_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturateScalar_Vector64_Byte testClass) + { + var result = AdvSimd.Arm64.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturateScalar_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturateScalar_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturateScalar_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_Byte(); + var result = AdvSimd.Arm64.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.AddSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.AddSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.Int16.cs new file mode 100644 index 00000000000000..29edf93f04ef08 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.Int16.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturateScalar_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int16 testClass) + { + var result = AdvSimd.Arm64.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int16(); + var result = AdvSimd.Arm64.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.AddSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.AddSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.Int32.cs new file mode 100644 index 00000000000000..0a4f5f43a8a537 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.Int32.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturateScalar_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int32 testClass) + { + var result = AdvSimd.Arm64.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int32(); + var result = AdvSimd.Arm64.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.AddSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.AddSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.SByte.cs new file mode 100644 index 00000000000000..e11e5911d63147 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.SByte.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturateScalar_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturateScalar_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturateScalar_Vector64_SByte testClass) + { + var result = AdvSimd.Arm64.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturateScalar_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturateScalar_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturateScalar_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_SByte(); + var result = AdvSimd.Arm64.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.AddSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.AddSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.UInt16.cs new file mode 100644 index 00000000000000..8dd609e0ee05a1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.UInt16.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturateScalar_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt16 testClass) + { + var result = AdvSimd.Arm64.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt16(); + var result = AdvSimd.Arm64.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.AddSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.AddSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.UInt32.cs new file mode 100644 index 00000000000000..83a655104303f3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AddSaturateScalar.Vector64.UInt32.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturateScalar_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt32 testClass) + { + var result = AdvSimd.Arm64.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.AddSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt32(); + var result = AdvSimd.Arm64.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.AddSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.AddSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.AddSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_r.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_r.csproj index 98bcab7a7c5bc4..ce448a4678881f 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_r.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_r.csproj @@ -51,6 +51,12 @@ + + + + + + @@ -95,6 +101,15 @@ + + + + + + + + + @@ -186,10 +201,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -224,6 +296,10 @@ + + + + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_ro.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_ro.csproj index 0a58c29ec9ddea..89c0b557619494 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_ro.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_ro.csproj @@ -51,6 +51,12 @@ + + + + + + @@ -95,6 +101,15 @@ + + + + + + + + + @@ -186,10 +201,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -224,6 +296,10 @@ + + + + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.Double.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.Double.1.cs new file mode 100644 index 00000000000000..b169f5ce0e6b13 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.Double.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V128_Double_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray, Double[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1 testClass) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Double*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly byte Imm = 1; + + private static Double[] _data = new Double[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Double*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Double*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Double*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Double*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1(); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Double*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Double*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Double*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.Int64.1.cs new file mode 100644 index 00000000000000..aa7692084ecd1f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.Int64.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V128_Int64_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1 testClass) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1(); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.UInt64.1.cs new file mode 100644 index 00000000000000..c958bf8e36de1b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.UInt64.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V128_UInt64_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1 testClass) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1(); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Double.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Double.31.cs new file mode 100644 index 00000000000000..25a9c6fb883a31 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Double.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_Double_31() + { + var test = new ImmOpTest__DuplicateToVector128_Double_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector128_Double_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector128_Double_31() + { + Succeeded = true; + + _dataTable = new DataTable(new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.Arm64.DuplicateToVector128( + (Double)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateToVector128), new Type[] { typeof(Double) }) + .Invoke(null, new object[] { + (Double)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + Double[] outArray = new Double[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateToVector128)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Double.cs new file mode 100644 index 00000000000000..f500029f5dafec --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Double.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_Double() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector128_Double(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector128_Double + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Double _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetDouble(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector128_Double testClass) + { + var result = AdvSimd.Arm64.DuplicateToVector128(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double _data; + + private static Double _clsVar; + + private Double _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector128_Double() + { + _clsVar = TestLibrary.Generator.GetDouble(); + } + + public DuplicateUnaryOpTest__DuplicateToVector128_Double() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetDouble(); + _data = TestLibrary.Generator.GetDouble(); + + _dataTable = new DataTable(new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.DuplicateToVector128( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateToVector128), new Type[] { typeof(Double) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.DuplicateToVector128( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.Arm64.DuplicateToVector128(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector128_Double(); + var result = AdvSimd.Arm64.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.DuplicateToVector128(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Double data, void* result, [CallerMemberName] string method = "") + { + Double[] outArray = new Double[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(Double data, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateToVector128)}(Double): DuplicateToVector128 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Int64.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Int64.31.cs new file mode 100644 index 00000000000000..cc3b5e8168d0ce --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Int64.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_Int64_31() + { + var test = new ImmOpTest__DuplicateToVector128_Int64_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector128_Int64_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector128_Int64_31() + { + Succeeded = true; + + _dataTable = new DataTable(new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.Arm64.DuplicateToVector128( + (Int64)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateToVector128), new Type[] { typeof(Int64) }) + .Invoke(null, new object[] { + (Int64)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + Int64[] outArray = new Int64[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateToVector128)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Int64.cs new file mode 100644 index 00000000000000..11dd759214131c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Int64.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_Int64() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector128_Int64 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Int64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetInt64(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector128_Int64 testClass) + { + var result = AdvSimd.Arm64.DuplicateToVector128(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64 _data; + + private static Int64 _clsVar; + + private Int64 _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector128_Int64() + { + _clsVar = TestLibrary.Generator.GetInt64(); + } + + public DuplicateUnaryOpTest__DuplicateToVector128_Int64() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetInt64(); + _data = TestLibrary.Generator.GetInt64(); + + _dataTable = new DataTable(new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.DuplicateToVector128( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateToVector128), new Type[] { typeof(Int64) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.DuplicateToVector128( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.Arm64.DuplicateToVector128(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector128_Int64(); + var result = AdvSimd.Arm64.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.DuplicateToVector128(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Int64 data, void* result, [CallerMemberName] string method = "") + { + Int64[] outArray = new Int64[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(Int64 data, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateToVector128)}(Int64): DuplicateToVector128 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.UInt64.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.UInt64.31.cs new file mode 100644 index 00000000000000..d1ebd0dd1ae65d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.UInt64.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_UInt64_31() + { + var test = new ImmOpTest__DuplicateToVector128_UInt64_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector128_UInt64_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector128_UInt64_31() + { + Succeeded = true; + + _dataTable = new DataTable(new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.Arm64.DuplicateToVector128( + (UInt64)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateToVector128), new Type[] { typeof(UInt64) }) + .Invoke(null, new object[] { + (UInt64)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + UInt64[] outArray = new UInt64[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateToVector128)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.UInt64.cs new file mode 100644 index 00000000000000..58788479dbfd7b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.UInt64.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_UInt64() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector128_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector128_UInt64 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public UInt64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetUInt64(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector128_UInt64 testClass) + { + var result = AdvSimd.Arm64.DuplicateToVector128(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64 _data; + + private static UInt64 _clsVar; + + private UInt64 _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector128_UInt64() + { + _clsVar = TestLibrary.Generator.GetUInt64(); + } + + public DuplicateUnaryOpTest__DuplicateToVector128_UInt64() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetUInt64(); + _data = TestLibrary.Generator.GetUInt64(); + + _dataTable = new DataTable(new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.DuplicateToVector128( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateToVector128), new Type[] { typeof(UInt64) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.DuplicateToVector128( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.Arm64.DuplicateToVector128(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector128_UInt64(); + var result = AdvSimd.Arm64.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.DuplicateToVector128(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(UInt64 data, void* result, [CallerMemberName] string method = "") + { + UInt64[] outArray = new UInt64[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(UInt64 data, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateToVector128)}(UInt64): DuplicateToVector128 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64.cs index 405efb58d4dd95..b77756ecac2d5b 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64.cs +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64.cs @@ -55,6 +55,12 @@ static Program() ["AddPairwiseScalar.Vector128.Double"] = AddPairwiseScalar_Vector128_Double, ["AddPairwiseScalar.Vector128.Int64"] = AddPairwiseScalar_Vector128_Int64, ["AddPairwiseScalar.Vector128.UInt64"] = AddPairwiseScalar_Vector128_UInt64, + ["AddSaturateScalar.Vector64.Byte"] = AddSaturateScalar_Vector64_Byte, + ["AddSaturateScalar.Vector64.Int16"] = AddSaturateScalar_Vector64_Int16, + ["AddSaturateScalar.Vector64.Int32"] = AddSaturateScalar_Vector64_Int32, + ["AddSaturateScalar.Vector64.SByte"] = AddSaturateScalar_Vector64_SByte, + ["AddSaturateScalar.Vector64.UInt16"] = AddSaturateScalar_Vector64_UInt16, + ["AddSaturateScalar.Vector64.UInt32"] = AddSaturateScalar_Vector64_UInt32, ["CompareEqual.Vector128.Double"] = CompareEqual_Vector128_Double, ["CompareEqual.Vector128.Int64"] = CompareEqual_Vector128_Int64, ["CompareEqual.Vector128.UInt64"] = CompareEqual_Vector128_UInt64, @@ -99,6 +105,15 @@ static Program() ["Divide.Vector64.Single"] = Divide_Vector64_Single, ["Divide.Vector128.Double"] = Divide_Vector128_Double, ["Divide.Vector128.Single"] = Divide_Vector128_Single, + ["DuplicateSelectedScalarToVector128.V128.Double.1"] = DuplicateSelectedScalarToVector128_V128_Double_1, + ["DuplicateSelectedScalarToVector128.V128.Int64.1"] = DuplicateSelectedScalarToVector128_V128_Int64_1, + ["DuplicateSelectedScalarToVector128.V128.UInt64.1"] = DuplicateSelectedScalarToVector128_V128_UInt64_1, + ["DuplicateToVector128.Double"] = DuplicateToVector128_Double, + ["DuplicateToVector128.Double.31"] = DuplicateToVector128_Double_31, + ["DuplicateToVector128.Int64"] = DuplicateToVector128_Int64, + ["DuplicateToVector128.Int64.31"] = DuplicateToVector128_Int64_31, + ["DuplicateToVector128.UInt64"] = DuplicateToVector128_UInt64, + ["DuplicateToVector128.UInt64.31"] = DuplicateToVector128_UInt64_31, ["FusedMultiplyAdd.Vector128.Double"] = FusedMultiplyAdd_Vector128_Double, ["FusedMultiplySubtract.Vector128.Double"] = FusedMultiplySubtract_Vector128_Double, ["Max.Vector128.Double"] = Max_Vector128_Double, @@ -190,10 +205,67 @@ static Program() ["ReverseElementBits.Vector128.SByte"] = ReverseElementBits_Vector128_SByte, ["ReverseElementBits.Vector64.Byte"] = ReverseElementBits_Vector64_Byte, ["ReverseElementBits.Vector64.SByte"] = ReverseElementBits_Vector64_SByte, + ["ShiftArithmeticRoundedSaturateScalar.Vector64.Int16"] = ShiftArithmeticRoundedSaturateScalar_Vector64_Int16, + ["ShiftArithmeticRoundedSaturateScalar.Vector64.Int32"] = ShiftArithmeticRoundedSaturateScalar_Vector64_Int32, + ["ShiftArithmeticRoundedSaturateScalar.Vector64.SByte"] = ShiftArithmeticRoundedSaturateScalar_Vector64_SByte, + ["ShiftArithmeticSaturateScalar.Vector64.Int16"] = ShiftArithmeticSaturateScalar_Vector64_Int16, + ["ShiftArithmeticSaturateScalar.Vector64.Int32"] = ShiftArithmeticSaturateScalar_Vector64_Int32, + ["ShiftArithmeticSaturateScalar.Vector64.SByte"] = ShiftArithmeticSaturateScalar_Vector64_SByte, + ["ShiftLeftLogicalSaturateScalar.Vector64.Byte.7"] = ShiftLeftLogicalSaturateScalar_Vector64_Byte_7, + ["ShiftLeftLogicalSaturateScalar.Vector64.Int16.15"] = ShiftLeftLogicalSaturateScalar_Vector64_Int16_15, + ["ShiftLeftLogicalSaturateScalar.Vector64.Int32.31"] = ShiftLeftLogicalSaturateScalar_Vector64_Int32_31, + ["ShiftLeftLogicalSaturateScalar.Vector64.SByte.1"] = ShiftLeftLogicalSaturateScalar_Vector64_SByte_1, + ["ShiftLeftLogicalSaturateScalar.Vector64.UInt16.1"] = ShiftLeftLogicalSaturateScalar_Vector64_UInt16_1, + ["ShiftLeftLogicalSaturateScalar.Vector64.UInt32.1"] = ShiftLeftLogicalSaturateScalar_Vector64_UInt32_1, + ["ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int16.5"] = ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int16_5, + ["ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int32.7"] = ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int32_7, + ["ShiftLeftLogicalSaturateUnsignedScalar.Vector64.SByte.3"] = ShiftLeftLogicalSaturateUnsignedScalar_Vector64_SByte_3, + ["ShiftLogicalRoundedSaturateScalar.Vector64.Byte"] = ShiftLogicalRoundedSaturateScalar_Vector64_Byte, + ["ShiftLogicalRoundedSaturateScalar.Vector64.Int16"] = ShiftLogicalRoundedSaturateScalar_Vector64_Int16, + ["ShiftLogicalRoundedSaturateScalar.Vector64.Int32"] = ShiftLogicalRoundedSaturateScalar_Vector64_Int32, + ["ShiftLogicalRoundedSaturateScalar.Vector64.SByte"] = ShiftLogicalRoundedSaturateScalar_Vector64_SByte, + ["ShiftLogicalRoundedSaturateScalar.Vector64.UInt16"] = ShiftLogicalRoundedSaturateScalar_Vector64_UInt16, + ["ShiftLogicalRoundedSaturateScalar.Vector64.UInt32"] = ShiftLogicalRoundedSaturateScalar_Vector64_UInt32, + ["ShiftLogicalSaturateScalar.Vector64.Byte"] = ShiftLogicalSaturateScalar_Vector64_Byte, + ["ShiftLogicalSaturateScalar.Vector64.Int16"] = ShiftLogicalSaturateScalar_Vector64_Int16, + ["ShiftLogicalSaturateScalar.Vector64.Int32"] = ShiftLogicalSaturateScalar_Vector64_Int32, + ["ShiftLogicalSaturateScalar.Vector64.SByte"] = ShiftLogicalSaturateScalar_Vector64_SByte, + ["ShiftLogicalSaturateScalar.Vector64.UInt16"] = ShiftLogicalSaturateScalar_Vector64_UInt16, + ["ShiftLogicalSaturateScalar.Vector64.UInt32"] = ShiftLogicalSaturateScalar_Vector64_UInt32, + ["ShiftRightArithmeticNarrowingSaturateScalar.Vector64.Int16.16"] = ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int16_16, + ["ShiftRightArithmeticNarrowingSaturateScalar.Vector64.Int32.32"] = ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int32_32, + ["ShiftRightArithmeticNarrowingSaturateScalar.Vector64.SByte.8"] = ShiftRightArithmeticNarrowingSaturateScalar_Vector64_SByte_8, + ["ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.Byte.3"] = ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_Byte_3, + ["ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.UInt16.5"] = ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt16_5, + ["ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.UInt32.7"] = ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt32_7, + ["ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.Int16.32"] = ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int16_32, + ["ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.Int32.64"] = ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int32_64, + ["ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.SByte.16"] = ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_SByte_16, + ["ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.Byte.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_Byte_1, + ["ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.UInt16.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt16_1, + ["ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.UInt32.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt32_1, + ["ShiftRightLogicalNarrowingSaturateScalar.Vector64.Byte.5"] = ShiftRightLogicalNarrowingSaturateScalar_Vector64_Byte_5, + ["ShiftRightLogicalNarrowingSaturateScalar.Vector64.Int16.7"] = ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int16_7, + ["ShiftRightLogicalNarrowingSaturateScalar.Vector64.Int32.11"] = ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int32_11, + ["ShiftRightLogicalNarrowingSaturateScalar.Vector64.SByte.3"] = ShiftRightLogicalNarrowingSaturateScalar_Vector64_SByte_3, + ["ShiftRightLogicalNarrowingSaturateScalar.Vector64.UInt16.5"] = ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt16_5, + ["ShiftRightLogicalNarrowingSaturateScalar.Vector64.UInt32.7"] = ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt32_7, + ["ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Byte.1"] = ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Byte_1, + ["ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Int16.1"] = ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int16_1, + ["ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Int32.1"] = ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int32_1, + ["ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.SByte.1"] = ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_SByte_1, + ["ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.UInt16.1"] = ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt16_1, + ["ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.UInt32.1"] = ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt32_1, ["Sqrt.Vector64.Single"] = Sqrt_Vector64_Single, ["Sqrt.Vector128.Double"] = Sqrt_Vector128_Double, ["Sqrt.Vector128.Single"] = Sqrt_Vector128_Single, ["Subtract.Vector128.Double"] = Subtract_Vector128_Double, + ["SubtractSaturateScalar.Vector64.Byte"] = SubtractSaturateScalar_Vector64_Byte, + ["SubtractSaturateScalar.Vector64.Int16"] = SubtractSaturateScalar_Vector64_Int16, + ["SubtractSaturateScalar.Vector64.Int32"] = SubtractSaturateScalar_Vector64_Int32, + ["SubtractSaturateScalar.Vector64.SByte"] = SubtractSaturateScalar_Vector64_SByte, + ["SubtractSaturateScalar.Vector64.UInt16"] = SubtractSaturateScalar_Vector64_UInt16, + ["SubtractSaturateScalar.Vector64.UInt32"] = SubtractSaturateScalar_Vector64_UInt32, ["TransposeEven.Vector64.Byte"] = TransposeEven_Vector64_Byte, ["TransposeEven.Vector64.Int16"] = TransposeEven_Vector64_Int16, ["TransposeEven.Vector64.Int32"] = TransposeEven_Vector64_Int32, @@ -228,6 +300,10 @@ static Program() ["TransposeOdd.Vector128.UInt16"] = TransposeOdd_Vector128_UInt16, ["TransposeOdd.Vector128.UInt32"] = TransposeOdd_Vector128_UInt32, ["TransposeOdd.Vector128.UInt64"] = TransposeOdd_Vector128_UInt64, + ["VectorTableLookup.Vector128.Byte"] = VectorTableLookup_Vector128_Byte, + ["VectorTableLookup.Vector128.SByte"] = VectorTableLookup_Vector128_SByte, + ["VectorTableLookupExtension.Vector128.Byte"] = VectorTableLookupExtension_Vector128_Byte, + ["VectorTableLookupExtension.Vector128.SByte"] = VectorTableLookupExtension_Vector128_SByte, ["UnzipEven.Vector64.Byte"] = UnzipEven_Vector64_Byte, ["UnzipEven.Vector64.Int16"] = UnzipEven_Vector64_Int16, ["UnzipEven.Vector64.Int32"] = UnzipEven_Vector64_Int32, diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticRoundedSaturateScalar.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticRoundedSaturateScalar.Vector64.Int16.cs new file mode 100644 index 00000000000000..e51ebd01974e73 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticRoundedSaturateScalar.Vector64.Int16.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRoundedSaturateScalar_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int16 testClass) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int16(); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftArithmeticRoundedSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticRoundedSaturateScalar.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticRoundedSaturateScalar.Vector64.Int32.cs new file mode 100644 index 00000000000000..9f6ad9c149212a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticRoundedSaturateScalar.Vector64.Int32.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRoundedSaturateScalar_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int32 testClass) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int32(); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftArithmeticRoundedSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticRoundedSaturateScalar.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticRoundedSaturateScalar.Vector64.SByte.cs new file mode 100644 index 00000000000000..39f57a814afe8f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticRoundedSaturateScalar.Vector64.SByte.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRoundedSaturateScalar_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_SByte testClass) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_SByte(); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftArithmeticRoundedSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticSaturateScalar.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticSaturateScalar.Vector64.Int16.cs new file mode 100644 index 00000000000000..d81b16d685d5fe --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticSaturateScalar.Vector64.Int16.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticSaturateScalar_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int16 testClass) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftArithmeticSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftArithmeticSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int16(); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftArithmeticSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftArithmeticSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticSaturateScalar.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticSaturateScalar.Vector64.Int32.cs new file mode 100644 index 00000000000000..3d7ce320d0d361 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticSaturateScalar.Vector64.Int32.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticSaturateScalar_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int32 testClass) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftArithmeticSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftArithmeticSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int32(); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftArithmeticSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftArithmeticSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticSaturateScalar.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticSaturateScalar.Vector64.SByte.cs new file mode 100644 index 00000000000000..1d9646ea270efb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticSaturateScalar.Vector64.SByte.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticSaturateScalar_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_SByte testClass) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftArithmeticSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftArithmeticSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_SByte(); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftArithmeticSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftArithmeticSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.Byte.7.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.Byte.7.cs new file mode 100644 index 00000000000000..9898c2ed2f7a67 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.Byte.7.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateScalar_Vector64_Byte_7() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Byte_7(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Byte_7 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Byte_7 testClass) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(_fld, 7); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Byte_7 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld)), + 7 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 7; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Byte_7() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Byte_7() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + _clsVar, + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pClsVar)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Byte_7(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Byte_7(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(_fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Byte*)(&test._fld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar)}(Vector64, 7): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.Int16.15.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.Int16.15.cs new file mode 100644 index 00000000000000..0dfb9d9d160bc1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.Int16.15.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateScalar_Vector64_Int16_15() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int16_15(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int16_15 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int16_15 testClass) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(_fld, 15); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int16_15 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 15 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 15; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int16_15() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int16_15() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)15 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)15 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + _clsVar, + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(firstOp, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(firstOp, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int16_15(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(test._fld, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int16_15(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(_fld, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(test._fld, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar)}(Vector64, 15): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.Int32.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.Int32.31.cs new file mode 100644 index 00000000000000..27a1c7f270356b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.Int32.31.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateScalar_Vector64_Int32_31() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int32_31(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int32_31 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int32_31 testClass) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(_fld, 31); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int32_31 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 31 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 31; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int32_31() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int32_31() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + _clsVar, + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(firstOp, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(firstOp, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int32_31(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(test._fld, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int32_31(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(_fld, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(test._fld, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar)}(Vector64, 31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..0f49096fe10e99 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.SByte.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateScalar_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_SByte_1 testClass) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_SByte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_SByte_1(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_SByte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..200e3b5ad23b0e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.UInt16.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateScalar_Vector64_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt16_1(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..bff709b139225b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateScalar.Vector64.UInt32.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateScalar_Vector64_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt32_1(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateScalar)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int16.5.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int16.5.cs new file mode 100644 index 00000000000000..552b63a5892a39 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int16.5.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int16_5() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int16_5(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int16_5 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int16_5 testClass) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(_fld, 5); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int16_5 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 5 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 5; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int16_5() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int16_5() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)5 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)5 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + _clsVar, + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(firstOp, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(firstOp, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int16_5(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(test._fld, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int16_5(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(_fld, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(test._fld, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar)}(Vector64, 5): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int32.7.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int32.7.cs new file mode 100644 index 00000000000000..187916162c85f6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int32.7.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int32_7() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int32_7(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int32_7 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int32_7 testClass) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(_fld, 7); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int32_7 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 7 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 7; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int32_7() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int32_7() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + _clsVar, + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int32_7(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int32_7(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(_fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar)}(Vector64, 7): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateUnsignedScalar.Vector64.SByte.3.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateUnsignedScalar.Vector64.SByte.3.cs new file mode 100644 index 00000000000000..a8d31f1d364ea1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLeftLogicalSaturateUnsignedScalar.Vector64.SByte.3.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateUnsignedScalar_Vector64_SByte_3() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_SByte_3(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_SByte_3 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_SByte_3 testClass) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(_fld, 3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_SByte_3 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((SByte*)(pFld)), + 3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 3; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_SByte_3() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_SByte_3() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + (byte)3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + _clsVar, + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((SByte*)(pClsVar)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(firstOp, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(firstOp, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_SByte_3(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(test._fld, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_SByte_3(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((SByte*)(pFld)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(_fld, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((SByte*)(pFld)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar(test._fld, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((SByte*)(&test._fld)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLeftLogicalSaturateUnsignedScalar)}(Vector64, 3): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.Byte.cs new file mode 100644 index 00000000000000..ad9f8e72d368c9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.Byte.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturateScalar_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, SByte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Byte testClass) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Byte(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, SByte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.Int16.cs new file mode 100644 index 00000000000000..20143758c29f94 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.Int16.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturateScalar_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int16 testClass) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int16(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.Int32.cs new file mode 100644 index 00000000000000..92071ffef73eab --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.Int32.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturateScalar_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int32 testClass) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int32(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.SByte.cs new file mode 100644 index 00000000000000..e8511d443045c5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.SByte.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturateScalar_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_SByte testClass) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_SByte(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.UInt16.cs new file mode 100644 index 00000000000000..0663f9fddee978 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.UInt16.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturateScalar_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Int16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt16 testClass) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt16(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Int16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.UInt32.cs new file mode 100644 index 00000000000000..12b7c1f1b565a9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalRoundedSaturateScalar.Vector64.UInt32.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturateScalar_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, Int32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt32 testClass) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt32(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, Int32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLogicalRoundedSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.Byte.cs new file mode 100644 index 00000000000000..cfa1bcea9697a9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.Byte.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturateScalar_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, SByte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Byte testClass) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Byte(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, SByte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.Int16.cs new file mode 100644 index 00000000000000..db01153ab41594 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.Int16.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturateScalar_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int16 testClass) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int16(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.Int32.cs new file mode 100644 index 00000000000000..6ffcf55329a5d5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.Int32.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturateScalar_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int32 testClass) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int32(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.SByte.cs new file mode 100644 index 00000000000000..2e618dfaec8d41 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.SByte.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturateScalar_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_SByte testClass) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_SByte(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.UInt16.cs new file mode 100644 index 00000000000000..d0a505b457d592 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.UInt16.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturateScalar_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Int16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt16 testClass) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt16(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Int16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.UInt32.cs new file mode 100644 index 00000000000000..1c64baf6e8d1ef --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftLogicalSaturateScalar.Vector64.UInt32.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturateScalar_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, Int32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt32 testClass) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt32(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, Int32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftLogicalSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateScalar.Vector64.Int16.16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateScalar.Vector64.Int16.16.cs new file mode 100644 index 00000000000000..5eb798d3681675 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateScalar.Vector64.Int16.16.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int16_16() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int16_16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int16_16 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int16_16 testClass) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(_fld, 16); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int16_16 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 16 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 16; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int16_16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int16_16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 16 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 16 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)16 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)16 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + _clsVar, + 16 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 16 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(firstOp, 16); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(firstOp, 16); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int16_16(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(test._fld, 16); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int16_16(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 16 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(_fld, 16); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 16 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(test._fld, 16); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 16 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar)}(Vector64, 16): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateScalar.Vector64.Int32.32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateScalar.Vector64.Int32.32.cs new file mode 100644 index 00000000000000..5d8f85004073a7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateScalar.Vector64.Int32.32.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int32_32() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int32_32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int32_32 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int32_32 testClass) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(_fld, 32); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int32_32 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 32 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 32; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int32_32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int32_32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 32 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + 32 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)32 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + (byte)32 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + _clsVar, + 32 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar)), + 32 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(firstOp, 32); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(firstOp, 32); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int32_32(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(test._fld, 32); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int32_32(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 32 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(_fld, 32); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 32 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(test._fld, 32); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld)), + 32 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar)}(Vector64, 32): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateScalar.Vector64.SByte.8.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateScalar.Vector64.SByte.8.cs new file mode 100644 index 00000000000000..daab20f1b12de2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateScalar.Vector64.SByte.8.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateScalar_Vector64_SByte_8() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_SByte_8(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_SByte_8 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_SByte_8 testClass) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(_fld, 8); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_SByte_8 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 8 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 8; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_SByte_8() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_SByte_8() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + _clsVar, + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(firstOp, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(firstOp, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_SByte_8(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(test._fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateScalar_Vector64_SByte_8(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(_fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar(test._fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateScalar)}(Vector64, 8): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.Byte.3.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.Byte.3.cs new file mode 100644 index 00000000000000..9f5359e2680958 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.Byte.3.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_Byte_3() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_Byte_3(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_Byte_3 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_Byte_3 testClass) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(_fld, 3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_Byte_3 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 3; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_Byte_3() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_Byte_3() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + _clsVar, + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(firstOp, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(firstOp, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_Byte_3(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(test._fld, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_Byte_3(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(_fld, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(test._fld, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticNarrowingSaturateUnsigned(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar)}(Vector64, 3): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.UInt16.5.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.UInt16.5.cs new file mode 100644 index 00000000000000..434cea9dcaf7ca --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.UInt16.5.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt16_5() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt16_5(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt16_5 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt16_5 testClass) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(_fld, 5); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt16_5 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 5 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 5; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt16_5() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt16_5() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)5 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)5 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + _clsVar, + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(firstOp, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(firstOp, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt16_5(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(test._fld, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt16_5(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(_fld, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(test._fld, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticNarrowingSaturateUnsigned(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar)}(Vector64, 5): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.UInt32.7.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.UInt32.7.cs new file mode 100644 index 00000000000000..86c7c041a9525d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.UInt32.7.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt32_7() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt32_7(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt32_7 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt32_7 testClass) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(_fld, 7); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt32_7 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 7 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 7; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt32_7() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt32_7() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + _clsVar, + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt32_7(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt32_7(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(_fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticNarrowingSaturateUnsigned(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightArithmeticNarrowingSaturateUnsignedScalar)}(Vector64, 7): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.Int16.32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.Int16.32.cs new file mode 100644 index 00000000000000..98b04fbbce92a3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.Int16.32.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int16_32() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int16_32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int16_32 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int16_32 testClass) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(_fld, 16); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int16_32 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 16 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 16; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int16_32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int16_32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 16 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 16 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)16 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)16 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + _clsVar, + 16 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 16 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(firstOp, 16); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(firstOp, 16); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int16_32(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(test._fld, 16); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int16_32(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 16 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(_fld, 16); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 16 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(test._fld, 16); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 16 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar)}(Vector64, 16): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.Int32.64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.Int32.64.cs new file mode 100644 index 00000000000000..bf7f10cda4efbb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.Int32.64.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int32_64() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int32_64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int32_64 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int32_64 testClass) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(_fld, 32); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int32_64 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 32 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 32; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int32_64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int32_64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 32 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + 32 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)32 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + (byte)32 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + _clsVar, + 32 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar)), + 32 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(firstOp, 32); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(firstOp, 32); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int32_64(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(test._fld, 32); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int32_64(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 32 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(_fld, 32); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 32 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(test._fld, 32); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld)), + 32 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar)}(Vector64, 32): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.SByte.16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.SByte.16.cs new file mode 100644 index 00000000000000..837dda2f3dad6a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.SByte.16.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_SByte_16() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_SByte_16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_SByte_16 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_SByte_16 testClass) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(_fld, 8); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_SByte_16 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 8 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 8; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_SByte_16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_SByte_16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + _clsVar, + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(firstOp, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(firstOp, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_SByte_16(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(test._fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_SByte_16(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(_fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar(test._fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateScalar)}(Vector64, 8): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..2a46e7220c7347 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.Byte.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_Byte_1 testClass) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(_fld, 7); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_Byte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 7 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 7; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + _clsVar, + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_Byte_1(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_Byte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(_fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar)}(Vector64, 7): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..20d8e9468a0863 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.UInt16.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(_fld, 15); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 15 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 15; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)15 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)15 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + _clsVar, + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(firstOp, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(firstOp, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt16_1(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(test._fld, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(_fld, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(test._fld, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar)}(Vector64, 15): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..a8d369928b0b3a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.UInt32.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(_fld, 31); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 31 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 31; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + (byte)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + _clsVar, + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(firstOp, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(firstOp, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt32_1(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(test._fld, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(_fld, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(test._fld, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar)}(Vector64, 31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.Byte.5.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.Byte.5.cs new file mode 100644 index 00000000000000..d93c5c41e333cd --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.Byte.5.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateScalar_Vector64_Byte_5() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Byte_5(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Byte_5 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Byte_5 testClass) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(_fld, 7); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Byte_5 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 7 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 7; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Byte_5() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Byte_5() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + _clsVar, + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pClsVar)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Byte_5(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Byte_5(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(_fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(&test._fld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar)}(Vector64, 7): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.Int16.7.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.Int16.7.cs new file mode 100644 index 00000000000000..bbed7640cf2335 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.Int16.7.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int16_7() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int16_7(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int16_7 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int16_7 testClass) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(_fld, 15); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int16_7 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 15 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 15; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int16_7() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int16_7() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)15 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)15 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + _clsVar, + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(firstOp, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(firstOp, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int16_7(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(test._fld, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int16_7(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(_fld, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(test._fld, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar)}(Vector64, 15): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.Int32.11.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.Int32.11.cs new file mode 100644 index 00000000000000..f723d24d6e8a62 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.Int32.11.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int32_11() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int32_11(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int32_11 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int32_11 testClass) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(_fld, 31); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int32_11 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 31 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 31; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int32_11() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int32_11() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + (byte)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + _clsVar, + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(firstOp, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(firstOp, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int32_11(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(test._fld, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int32_11(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(_fld, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(test._fld, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar)}(Vector64, 31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.SByte.3.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.SByte.3.cs new file mode 100644 index 00000000000000..26b8eef08c9812 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.SByte.3.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateScalar_Vector64_SByte_3() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_SByte_3(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_SByte_3 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_SByte_3 testClass) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(_fld, 7); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_SByte_3 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 7 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 7; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_SByte_3() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_SByte_3() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + _clsVar, + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_SByte_3(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_SByte_3(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(_fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar)}(Vector64, 7): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.UInt16.5.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.UInt16.5.cs new file mode 100644 index 00000000000000..e0f63f4958e094 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.UInt16.5.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt16_5() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt16_5(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt16_5 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt16_5 testClass) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(_fld, 15); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt16_5 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 15 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 15; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt16_5() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt16_5() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)15 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + (byte)15 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + _clsVar, + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pClsVar)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(firstOp, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(firstOp, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt16_5(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(test._fld, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt16_5(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(_fld, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(test._fld, 15); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(&test._fld)), + 15 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar)}(Vector64, 15): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.UInt32.7.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.UInt32.7.cs new file mode 100644 index 00000000000000..7aad4513eee3ba --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalNarrowingSaturateScalar.Vector64.UInt32.7.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt32_7() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt32_7(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt32_7 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt32_7 testClass) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(_fld, 31); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt32_7 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 31 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 31; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt32_7() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt32_7() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)), + (byte)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + _clsVar, + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pClsVar)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(firstOp, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(firstOp, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt32_7(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(test._fld, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt32_7(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(_fld, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar(test._fld, 31); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(&test._fld)), + 31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightLogicalNarrowingSaturateScalar)}(Vector64, 31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..d20fc959a862ef --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Byte.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Byte_1 testClass) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(_fld, 3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Byte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 3; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + (byte)3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + _clsVar, + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pClsVar)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(firstOp, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(firstOp, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Byte_1(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(test._fld, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Byte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(_fld, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(test._fld, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(&test._fld)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar)}(Vector64, 3): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..3d6e9e01ea4a92 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Int16.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int16_1 testClass) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(_fld, 5); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 5 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 5; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)5 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)5 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + _clsVar, + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(firstOp, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(firstOp, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int16_1(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(test._fld, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(_fld, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(test._fld, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar)}(Vector64, 5): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..c888b3177953ce --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Int32.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int32_1 testClass) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(_fld, 7); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 7 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 7; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + _clsVar, + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int32_1(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(_fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar)}(Vector64, 7): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..d2b9d589556667 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.SByte.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_SByte_1 testClass) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(_fld, 3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_SByte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 3; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + _clsVar, + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(firstOp, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(firstOp, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_SByte_1(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(test._fld, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_SByte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(_fld, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(test._fld, 3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar)}(Vector64, 3): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..ed3f2d6b724399 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.UInt16.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(_fld, 5); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 5 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 5; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)5 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + (byte)5 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + _clsVar, + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pClsVar)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(firstOp, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(firstOp, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt16_1(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(test._fld, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(_fld, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(test._fld, 5); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(&test._fld)), + 5 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar)}(Vector64, 5): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..6c650928ce4851 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.UInt32.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(_fld, 7); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 7 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 7; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)), + (byte)7 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + _clsVar, + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pClsVar)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(firstOp, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt32_1(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(_fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar(test._fld, 7); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(&test._fld)), + 7 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.ShiftRightLogicalRoundedNarrowingSaturateScalar)}(Vector64, 7): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.Byte.cs new file mode 100644 index 00000000000000..fd2b8c3e6ed294 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.Byte.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturateScalar_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Byte testClass) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Byte(); + var result = AdvSimd.Arm64.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.SubtractSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.SubtractSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.Int16.cs new file mode 100644 index 00000000000000..90c8d0cffbbe38 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.Int16.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturateScalar_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int16 testClass) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int16(); + var result = AdvSimd.Arm64.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.SubtractSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.SubtractSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.Int32.cs new file mode 100644 index 00000000000000..bd93a25e5587fc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.Int32.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturateScalar_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int32 testClass) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int32(); + var result = AdvSimd.Arm64.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.SubtractSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.SubtractSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.SByte.cs new file mode 100644 index 00000000000000..3d0b36c61d52f2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.SByte.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturateScalar_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_SByte testClass) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_SByte(); + var result = AdvSimd.Arm64.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.SubtractSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.SubtractSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.UInt16.cs new file mode 100644 index 00000000000000..4d802807373a46 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.UInt16.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturateScalar_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt16 testClass) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt16(); + var result = AdvSimd.Arm64.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.SubtractSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.SubtractSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.UInt32.cs new file mode 100644 index 00000000000000..a8efbd50048042 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/SubtractSaturateScalar.Vector64.UInt32.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturateScalar_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt32 testClass) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt32(); + var result = AdvSimd.Arm64.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.SubtractSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.SubtractSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/VectorTableLookup.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/VectorTableLookup.Vector128.Byte.cs new file mode 100644 index 00000000000000..5b3950a6b285e7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/VectorTableLookup.Vector128.Byte.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void VectorTableLookup_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__VectorTableLookup_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__VectorTableLookup_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__VectorTableLookup_Vector128_Byte testClass) + { + var result = AdvSimd.Arm64.VectorTableLookup(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__VectorTableLookup_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.VectorTableLookup( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__VectorTableLookup_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__VectorTableLookup_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.VectorTableLookup( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.VectorTableLookup( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.VectorTableLookup), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.VectorTableLookup), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.VectorTableLookup( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.VectorTableLookup( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.VectorTableLookup(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.VectorTableLookup(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__VectorTableLookup_Vector128_Byte(); + var result = AdvSimd.Arm64.VectorTableLookup(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__VectorTableLookup_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.VectorTableLookup( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.VectorTableLookup(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.VectorTableLookup( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.VectorTableLookup(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.VectorTableLookup( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.TableVectorLookup(0, right, left) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (Helpers.TableVectorLookup(i, right, left) != result[i]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.VectorTableLookup)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/VectorTableLookup.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/VectorTableLookup.Vector128.SByte.cs new file mode 100644 index 00000000000000..e032ce9fa82c8f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/VectorTableLookup.Vector128.SByte.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void VectorTableLookup_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__VectorTableLookup_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__VectorTableLookup_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__VectorTableLookup_Vector128_SByte testClass) + { + var result = AdvSimd.Arm64.VectorTableLookup(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__VectorTableLookup_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.VectorTableLookup( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__VectorTableLookup_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__VectorTableLookup_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.VectorTableLookup( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.VectorTableLookup( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.VectorTableLookup), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.VectorTableLookup), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.VectorTableLookup( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.Arm64.VectorTableLookup( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.Arm64.VectorTableLookup(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.Arm64.VectorTableLookup(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__VectorTableLookup_Vector128_SByte(); + var result = AdvSimd.Arm64.VectorTableLookup(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__VectorTableLookup_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.Arm64.VectorTableLookup( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.VectorTableLookup(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.Arm64.VectorTableLookup( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.VectorTableLookup(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.VectorTableLookup( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.TableVectorLookup(0, right, left) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (Helpers.TableVectorLookup(i, right, left) != result[i]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.VectorTableLookup)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/VectorTableLookupExtension.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/VectorTableLookupExtension.Vector128.Byte.cs new file mode 100644 index 00000000000000..b37d91641f84e1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/VectorTableLookupExtension.Vector128.Byte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void VectorTableLookupExtension_Vector128_Byte() + { + var test = new SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] inArray3, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_Byte testClass) + { + var result = AdvSimd.Arm64.VectorTableLookupExtension(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.Arm64.VectorTableLookupExtension( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + private static Byte[] _data3 = new Byte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + _dataTable = new DataTable(_data1, _data2, _data3, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.VectorTableLookupExtension( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.VectorTableLookupExtension( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.VectorTableLookupExtension), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.VectorTableLookupExtension), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.VectorTableLookupExtension( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Arm64.VectorTableLookupExtension( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)), + AdvSimd.LoadVector128((Byte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.Arm64.VectorTableLookupExtension(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.Arm64.VectorTableLookupExtension(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_Byte(); + var result = AdvSimd.Arm64.VectorTableLookupExtension(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.Arm64.VectorTableLookupExtension( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.VectorTableLookupExtension(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.Arm64.VectorTableLookupExtension( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.VectorTableLookupExtension(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.VectorTableLookupExtension( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)), + AdvSimd.LoadVector128((Byte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] secondOp, Byte[] thirdOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.TableVectorExtension(i, firstOp, thirdOp, secondOp) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.VectorTableLookupExtension)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/VectorTableLookupExtension.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/VectorTableLookupExtension.Vector128.SByte.cs new file mode 100644 index 00000000000000..a246269498eec4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/VectorTableLookupExtension.Vector128.SByte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void VectorTableLookupExtension_Vector128_SByte() + { + var test = new SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] inArray3, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_SByte testClass) + { + var result = AdvSimd.Arm64.VectorTableLookupExtension(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.Arm64.VectorTableLookupExtension( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + private static SByte[] _data3 = new SByte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + _dataTable = new DataTable(_data1, _data2, _data3, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.Arm64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Arm64.VectorTableLookupExtension( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Arm64.VectorTableLookupExtension( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.VectorTableLookupExtension), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.VectorTableLookupExtension), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Arm64.VectorTableLookupExtension( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Arm64.VectorTableLookupExtension( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)), + AdvSimd.LoadVector128((SByte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.Arm64.VectorTableLookupExtension(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.Arm64.VectorTableLookupExtension(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_SByte(); + var result = AdvSimd.Arm64.VectorTableLookupExtension(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__VectorTableLookupExtension_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.Arm64.VectorTableLookupExtension( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Arm64.VectorTableLookupExtension(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.Arm64.VectorTableLookupExtension( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.VectorTableLookupExtension(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Arm64.VectorTableLookupExtension( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)), + AdvSimd.LoadVector128((SByte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] thirdOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.TableVectorExtension(i, firstOp, thirdOp, secondOp) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.VectorTableLookupExtension)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.Byte.cs new file mode 100644 index 00000000000000..5b9fad07da26f8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningLower_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Byte testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Byte(); + var result = AdvSimd.AbsoluteDifferenceWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.Int16.cs new file mode 100644 index 00000000000000..f66ea6698bf407 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningLower_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int16 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int16(); + var result = AdvSimd.AbsoluteDifferenceWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.Int32.cs new file mode 100644 index 00000000000000..5909d3a22ab969 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningLower_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int32 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int32(); + var result = AdvSimd.AbsoluteDifferenceWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.SByte.cs new file mode 100644 index 00000000000000..49eec993f89c52 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningLower_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_SByte testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_SByte(); + var result = AdvSimd.AbsoluteDifferenceWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.UInt16.cs new file mode 100644 index 00000000000000..d9c35fa50d2d73 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningLower_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt16 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt16(); + var result = AdvSimd.AbsoluteDifferenceWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.UInt32.cs new file mode 100644 index 00000000000000..5d6625edeb8e88 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLower.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningLower_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt32 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt32(); + var result = AdvSimd.AbsoluteDifferenceWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningLower_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLower( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.Byte.cs new file mode 100644 index 00000000000000..d6dfff83e69b20 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.Byte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningLowerAndAdd_Vector64_Byte() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Byte[] inArray2, Byte[] inArray3, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Byte testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + private static Byte[] _data3 = new Byte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)), + AdvSimd.LoadVector64((Byte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Byte(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)), + AdvSimd.LoadVector64((Byte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Byte[] secondOp, Byte[] thirdOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.Int16.cs new file mode 100644 index 00000000000000..efd2c2a058969a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.Int16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int16() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int16[] inArray2, Int16[] inArray3, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int16 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)), + AdvSimd.LoadVector64((Int16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + private static Int16[] _data3 = new Int16[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)), + AdvSimd.LoadVector64((Int16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int16(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)), + AdvSimd.LoadVector64((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)), + AdvSimd.LoadVector64((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)), + AdvSimd.LoadVector64((Int16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] secondOp, Int16[] thirdOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.Int32.cs new file mode 100644 index 00000000000000..fb82b96afd1866 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.Int32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int32() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int32[] inArray2, Int32[] inArray3, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int32 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)), + AdvSimd.LoadVector64((Int32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + private static Int32[] _data3 = new Int32[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)), + AdvSimd.LoadVector64((Int32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int32(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)), + AdvSimd.LoadVector64((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)), + AdvSimd.LoadVector64((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)), + AdvSimd.LoadVector64((Int32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] secondOp, Int32[] thirdOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.SByte.cs new file mode 100644 index 00000000000000..e2a82746cb4297 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.SByte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningLowerAndAdd_Vector64_SByte() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, SByte[] inArray2, SByte[] inArray3, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_SByte testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + private static SByte[] _data3 = new SByte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)), + AdvSimd.LoadVector64((SByte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_SByte(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)), + AdvSimd.LoadVector64((SByte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] secondOp, SByte[] thirdOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.UInt16.cs new file mode 100644 index 00000000000000..287ec521291bbb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.UInt16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt16() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt16[] inArray2, UInt16[] inArray3, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt16 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)), + AdvSimd.LoadVector64((UInt16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + private static UInt16[] _data3 = new UInt16[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)), + AdvSimd.LoadVector64((UInt16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt16(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)), + AdvSimd.LoadVector64((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)), + AdvSimd.LoadVector64((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)), + AdvSimd.LoadVector64((UInt16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt16[] secondOp, UInt16[] thirdOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.UInt32.cs new file mode 100644 index 00000000000000..a1972d03882544 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningLowerAndAdd.Vector64.UInt32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt32() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt32[] inArray2, UInt32[] inArray3, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt32 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)), + AdvSimd.LoadVector64((UInt32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + private static UInt32[] _data3 = new UInt32[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)), + AdvSimd.LoadVector64((UInt32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt32(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)), + AdvSimd.LoadVector64((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)), + AdvSimd.LoadVector64((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)), + AdvSimd.LoadVector64((UInt32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt32[] secondOp, UInt32[] thirdOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningLowerAndAdd)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.Byte.cs new file mode 100644 index 00000000000000..67e72a7924d663 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningUpper_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Byte testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Byte(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.Int16.cs new file mode 100644 index 00000000000000..0f2eced9cad4df --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningUpper_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int16 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int16(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.Int32.cs new file mode 100644 index 00000000000000..fbbe970edc63bf --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningUpper_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int32 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int32(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.SByte.cs new file mode 100644 index 00000000000000..e859dd59ecca7a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningUpper_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_SByte testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_SByte(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.UInt16.cs new file mode 100644 index 00000000000000..ee5002aa8e85c8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningUpper_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt16 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt16(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.UInt32.cs new file mode 100644 index 00000000000000..c512db5dfae1e4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpper.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningUpper_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt32 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt32(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AbsoluteDifferenceWideningUpper_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpper( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.Byte.cs new file mode 100644 index 00000000000000..ca4a12acaf201c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.Byte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningUpperAndAdd_Vector128_Byte() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Byte[] inArray2, Byte[] inArray3, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Byte testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + private static Byte[] _data3 = new Byte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)), + AdvSimd.LoadVector128((Byte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Byte(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)), + AdvSimd.LoadVector128((Byte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Byte[] secondOp, Byte[] thirdOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.Int16.cs new file mode 100644 index 00000000000000..7271fb1be9b23f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.Int16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int16() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int16[] inArray2, Int16[] inArray3, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int16 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + private static Int16[] _data3 = new Int16[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)), + AdvSimd.LoadVector128((Int16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int16(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)), + AdvSimd.LoadVector128((Int16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] secondOp, Int16[] thirdOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.Int32.cs new file mode 100644 index 00000000000000..c2e720aebad7c2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.Int32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int32() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int32[] inArray2, Int32[] inArray3, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int32 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + private static Int32[] _data3 = new Int32[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)), + AdvSimd.LoadVector128((Int32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int32(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)), + AdvSimd.LoadVector128((Int32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] secondOp, Int32[] thirdOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.SByte.cs new file mode 100644 index 00000000000000..d99e0d17a3cc3b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.SByte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningUpperAndAdd_Vector128_SByte() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, SByte[] inArray2, SByte[] inArray3, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_SByte testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + private static SByte[] _data3 = new SByte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)), + AdvSimd.LoadVector128((SByte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_SByte(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)), + AdvSimd.LoadVector128((SByte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] secondOp, SByte[] thirdOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.UInt16.cs new file mode 100644 index 00000000000000..a0fbec6d2d6df6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.UInt16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt16() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt16[] inArray2, UInt16[] inArray3, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt16 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + private static UInt16[] _data3 = new UInt16[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)), + AdvSimd.LoadVector128((UInt16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt16(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)), + AdvSimd.LoadVector128((UInt16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt16[] secondOp, UInt16[] thirdOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.UInt32.cs new file mode 100644 index 00000000000000..81d40736138ca3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AbsoluteDifferenceWideningUpperAndAdd.Vector128.UInt32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt32() + { + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt32[] inArray2, UInt32[] inArray3, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt32 testClass) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + private static UInt32[] _data3 = new UInt32[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)), + AdvSimd.LoadVector128((UInt32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt32(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AbsoluteDifferenceWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)), + AdvSimd.LoadVector128((UInt32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt32[] secondOp, UInt32[] thirdOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AbsoluteDifferenceWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AbsoluteDifferenceWideningUpperAndAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.Byte.cs new file mode 100644 index 00000000000000..5468c6e2326db1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddHighNarrowingLower_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Byte testClass) + { + var result = AdvSimd.AddHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Byte(); + var result = AdvSimd.AddHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.Int16.cs new file mode 100644 index 00000000000000..aef7a1a9f85ee4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddHighNarrowingLower_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int16 testClass) + { + var result = AdvSimd.AddHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int16(); + var result = AdvSimd.AddHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.Int32.cs new file mode 100644 index 00000000000000..c8bed51ae70bba --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddHighNarrowingLower_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int32 testClass) + { + var result = AdvSimd.AddHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int32(); + var result = AdvSimd.AddHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.SByte.cs new file mode 100644 index 00000000000000..024712d6f9545a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddHighNarrowingLower_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_SByte testClass) + { + var result = AdvSimd.AddHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_SByte(); + var result = AdvSimd.AddHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.UInt16.cs new file mode 100644 index 00000000000000..6d9318b1f6931d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddHighNarrowingLower_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt16 testClass) + { + var result = AdvSimd.AddHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt16(); + var result = AdvSimd.AddHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.UInt32.cs new file mode 100644 index 00000000000000..bb587e95effa57 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingLower.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddHighNarrowingLower_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt32 testClass) + { + var result = AdvSimd.AddHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((UInt64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt32(); + var result = AdvSimd.AddHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddHighNarrowingLower_Vector64_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((UInt64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.Byte.cs new file mode 100644 index 00000000000000..400ff583a4a95b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.Byte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddHighNarrowingUpper_Vector128_Byte() + { + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, UInt16[] inArray2, UInt16[] inArray3, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Byte testClass) + { + var result = AdvSimd.AddHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + private static UInt16[] _data3 = new UInt16[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)), + AdvSimd.LoadVector128((UInt16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AddHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AddHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Byte(); + var result = AdvSimd.AddHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)), + AdvSimd.LoadVector128((UInt16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] secondOp, UInt16[] thirdOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.Int16.cs new file mode 100644 index 00000000000000..1ed95b9057f432 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.Int16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddHighNarrowingUpper_Vector128_Int16() + { + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] inArray2, Int32[] inArray3, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int16 testClass) + { + var result = AdvSimd.AddHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + private static Int32[] _data3 = new Int32[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)), + AdvSimd.LoadVector128((Int32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AddHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AddHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int16(); + var result = AdvSimd.AddHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)), + AdvSimd.LoadVector128((Int32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] secondOp, Int32[] thirdOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.Int32.cs new file mode 100644 index 00000000000000..ba16eab980ede3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.Int32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddHighNarrowingUpper_Vector128_Int32() + { + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] inArray2, Int64[] inArray3, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int32 testClass) + { + var result = AdvSimd.AddHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)), + AdvSimd.LoadVector128((Int64*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + private static Int64[] _data3 = new Int64[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)), + AdvSimd.LoadVector128((Int64*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AddHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AddHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int32(); + var result = AdvSimd.AddHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)), + AdvSimd.LoadVector128((Int64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)), + AdvSimd.LoadVector128((Int64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)), + AdvSimd.LoadVector128((Int64*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] inArray3 = new Int64[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] inArray3 = new Int64[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] secondOp, Int64[] thirdOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.SByte.cs new file mode 100644 index 00000000000000..93fcc6036ab161 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.SByte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddHighNarrowingUpper_Vector128_SByte() + { + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] inArray2, Int16[] inArray3, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_SByte testClass) + { + var result = AdvSimd.AddHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + private static Int16[] _data3 = new Int16[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)), + AdvSimd.LoadVector128((Int16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AddHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AddHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_SByte(); + var result = AdvSimd.AddHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)), + AdvSimd.LoadVector128((Int16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] secondOp, Int16[] thirdOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.UInt16.cs new file mode 100644 index 00000000000000..2ab6d94fdcb955 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.UInt16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddHighNarrowingUpper_Vector128_UInt16() + { + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt32[] inArray2, UInt32[] inArray3, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt16 testClass) + { + var result = AdvSimd.AddHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + private static UInt32[] _data3 = new UInt32[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)), + AdvSimd.LoadVector128((UInt32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AddHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AddHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt16(); + var result = AdvSimd.AddHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)), + AdvSimd.LoadVector128((UInt32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] secondOp, UInt32[] thirdOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.UInt32.cs new file mode 100644 index 00000000000000..c09986aa721254 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddHighNarrowingUpper.Vector128.UInt32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddHighNarrowingUpper_Vector128_UInt32() + { + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt64[] inArray2, UInt64[] inArray3, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt32 testClass) + { + var result = AdvSimd.AddHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)), + AdvSimd.LoadVector128((UInt64*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + private static UInt64[] _data3 = new UInt64[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt64*)(pClsVar2)), + AdvSimd.LoadVector128((UInt64*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AddHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AddHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt32(); + var result = AdvSimd.AddHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AddHighNarrowingUpper_Vector128_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)), + AdvSimd.LoadVector128((UInt64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)), + AdvSimd.LoadVector128((UInt64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt64*)(&test._fld2)), + AdvSimd.LoadVector128((UInt64*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] inArray3 = new UInt64[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] inArray3 = new UInt64[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] secondOp, UInt64[] thirdOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.Byte.cs new file mode 100644 index 00000000000000..141e07de47c80a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.Byte.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWidening_Vector128_Byte() + { + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Byte testClass) + { + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Byte*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWidening( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWidening( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Byte*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Byte(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Byte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Byte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Byte*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWidening(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWidening)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.Int16.cs new file mode 100644 index 00000000000000..155939ed5affb4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.Int16.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWidening_Vector128_Int16() + { + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int16 testClass) + { + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Int16*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWidening( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWidening( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Int16*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int16(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Int16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Int16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Int16*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWidening(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWidening)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.Int32.cs new file mode 100644 index 00000000000000..ba4979388400aa --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.Int32.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWidening_Vector128_Int32() + { + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int32 testClass) + { + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Int32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWidening( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWidening( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Int32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int32(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Int32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Int32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((Int32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWidening(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWidening)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.SByte.cs new file mode 100644 index 00000000000000..c4b70f746ed6e8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.SByte.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWidening_Vector128_SByte() + { + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__AddPairwiseWidening_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__AddPairwiseWidening_Vector128_SByte testClass) + { + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__AddPairwiseWidening_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((SByte*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__AddPairwiseWidening_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__AddPairwiseWidening_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWidening( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWidening( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((SByte*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_SByte(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((SByte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((SByte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((SByte*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWidening(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWidening)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.UInt16.cs new file mode 100644 index 00000000000000..e7d899afce0766 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.UInt16.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWidening_Vector128_UInt16() + { + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt16 testClass) + { + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((UInt16*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWidening( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWidening( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt16(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((UInt16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((UInt16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWidening(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWidening)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.UInt32.cs new file mode 100644 index 00000000000000..732ecd5d82d228 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector128.UInt32.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWidening_Vector128_UInt32() + { + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt32 testClass) + { + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWidening( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWidening( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt32(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWidening(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWidening)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector64.Byte.cs new file mode 100644 index 00000000000000..89600207ea1dba --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector64.Byte.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWidening_Vector64_Byte() + { + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Byte testClass) + { + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((Byte*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWidening( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWidening( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((Byte*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Byte(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((Byte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((Byte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((Byte*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWidening(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWidening)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector64.Int16.cs new file mode 100644 index 00000000000000..1a7510a8aea179 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector64.Int16.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWidening_Vector64_Int16() + { + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Int16 testClass) + { + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((Int16*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWidening( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWidening( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((Int16*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Int16(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((Int16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((Int16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((Int16*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWidening(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWidening)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector64.SByte.cs new file mode 100644 index 00000000000000..4fb35679a08acd --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector64.SByte.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWidening_Vector64_SByte() + { + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__AddPairwiseWidening_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__AddPairwiseWidening_Vector64_SByte testClass) + { + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__AddPairwiseWidening_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((SByte*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__AddPairwiseWidening_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__AddPairwiseWidening_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWidening( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWidening( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((SByte*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector64_SByte(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((SByte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((SByte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((SByte*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWidening(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWidening)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector64.UInt16.cs new file mode 100644 index 00000000000000..22bdecd3461225 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWidening.Vector64.UInt16.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWidening_Vector64_UInt16() + { + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__AddPairwiseWidening_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__AddPairwiseWidening_Vector64_UInt16 testClass) + { + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__AddPairwiseWidening_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((UInt16*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__AddPairwiseWidening_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__AddPairwiseWidening_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWidening( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWidening), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWidening( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.AddPairwiseWidening(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector64_UInt16(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__AddPairwiseWidening_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((UInt16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWidening(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((UInt16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWidening( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWidening(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWidening)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.Byte.cs new file mode 100644 index 00000000000000..0ebfccbf9c47bb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWideningAndAdd_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Byte testClass) + { + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Byte(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWideningAndAdd)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.Int16.cs new file mode 100644 index 00000000000000..ae0c9d99691cd8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWideningAndAdd_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int16[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int16 testClass) + { + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int16(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWideningAndAdd)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.Int32.cs new file mode 100644 index 00000000000000..4415e86a551006 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWideningAndAdd_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int32[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int32 testClass) + { + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int32(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int32[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWideningAndAdd)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.SByte.cs new file mode 100644 index 00000000000000..0d3773ef2a8b1f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWideningAndAdd_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, SByte[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_SByte testClass) + { + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_SByte(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, SByte[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWideningAndAdd)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.UInt16.cs new file mode 100644 index 00000000000000..d4c737f4bf5032 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWideningAndAdd_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt16 testClass) + { + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt16(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWideningAndAdd)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.UInt32.cs new file mode 100644 index 00000000000000..70206da369902d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWideningAndAdd_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt32 testClass) + { + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt32(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWideningAndAdd)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector64.Byte.cs new file mode 100644 index 00000000000000..9706320540b674 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWideningAndAdd_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Byte testClass) + { + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Byte(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWideningAndAdd)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector64.Int16.cs new file mode 100644 index 00000000000000..0f29b61ced5fb0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWideningAndAdd_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int16[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Int16 testClass) + { + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Int16(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWideningAndAdd)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector64.SByte.cs new file mode 100644 index 00000000000000..018296b06da40d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWideningAndAdd_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, SByte[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_SByte testClass) + { + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_SByte(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, SByte[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWideningAndAdd)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector64.UInt16.cs new file mode 100644 index 00000000000000..35e1ebffe9124a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAdd.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWideningAndAdd_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_UInt16 testClass) + { + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAdd), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddPairwiseWideningAndAdd(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_UInt16(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAdd_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAdd(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAdd( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWideningAndAdd)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAddScalar.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAddScalar.Vector64.Int32.cs new file mode 100644 index 00000000000000..72de8d70534380 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAddScalar.Vector64.Int32.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWideningAndAddScalar_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int32[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_Int32 testClass) + { + var result = AdvSimd.AddPairwiseWideningAndAddScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAddScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAddScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddPairwiseWideningAndAddScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddPairwiseWideningAndAddScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_Int32(); + var result = AdvSimd.AddPairwiseWideningAndAddScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAddScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAddScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int32[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.AddPairwiseWideningAndAdd(left, right, 0) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWideningAndAddScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAddScalar.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAddScalar.Vector64.UInt32.cs new file mode 100644 index 00000000000000..24b865accea4b4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningAndAddScalar.Vector64.UInt32.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWideningAndAddScalar_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_UInt32 testClass) + { + var result = AdvSimd.AddPairwiseWideningAndAddScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAddScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningAndAddScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + AdvSimd.LoadVector64((UInt64*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddPairwiseWideningAndAddScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddPairwiseWideningAndAddScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_UInt32(); + var result = AdvSimd.AddPairwiseWideningAndAddScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddPairwiseWideningAndAddScalar_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWideningAndAddScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAddScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningAndAddScalar( + AdvSimd.LoadVector64((UInt64*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.AddPairwiseWideningAndAdd(left, right, 0) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWideningAndAddScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningScalar.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningScalar.Vector64.Int32.cs new file mode 100644 index 00000000000000..f28841309e88bb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningScalar.Vector64.Int32.cs @@ -0,0 +1,496 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWideningScalar_Vector64_Int32() + { + var test = new SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_Int32 testClass) + { + var result = AdvSimd.AddPairwiseWideningScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWideningScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWideningScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWideningScalar( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWideningScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.AddPairwiseWideningScalar( + AdvSimd.LoadVector64((Int32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.AddPairwiseWideningScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.AddPairwiseWideningScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_Int32(); + var result = AdvSimd.AddPairwiseWideningScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.AddPairwiseWideningScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWideningScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWideningScalar( + AdvSimd.LoadVector64((Int32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningScalar( + AdvSimd.LoadVector64((Int32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.AddPairwiseWidening(firstOp, 0) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWideningScalar)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningScalar.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningScalar.Vector64.UInt32.cs new file mode 100644 index 00000000000000..7a6218108a0dc2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddPairwiseWideningScalar.Vector64.UInt32.cs @@ -0,0 +1,496 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddPairwiseWideningScalar_Vector64_UInt32() + { + var test = new SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_UInt32 testClass) + { + var result = AdvSimd.AddPairwiseWideningScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWideningScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddPairwiseWideningScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddPairwiseWideningScalar( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddPairwiseWideningScalar), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddPairwiseWideningScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.AddPairwiseWideningScalar( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.AddPairwiseWideningScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.AddPairwiseWideningScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_UInt32(); + var result = AdvSimd.AddPairwiseWideningScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__AddPairwiseWideningScalar_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.AddPairwiseWideningScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddPairwiseWideningScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.AddPairwiseWideningScalar( + AdvSimd.LoadVector64((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddPairwiseWideningScalar( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.AddPairwiseWidening(firstOp, 0) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddPairwiseWideningScalar)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.Byte.cs new file mode 100644 index 00000000000000..1724511cd47f66 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddRoundedHighNarrowingLower_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Byte testClass) + { + var result = AdvSimd.AddRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Byte(); + var result = AdvSimd.AddRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddRoundedHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddRoundedHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.Int16.cs new file mode 100644 index 00000000000000..21fc2ac668e355 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddRoundedHighNarrowingLower_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int16 testClass) + { + var result = AdvSimd.AddRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int16(); + var result = AdvSimd.AddRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddRoundedHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddRoundedHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.Int32.cs new file mode 100644 index 00000000000000..8812d14278392c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddRoundedHighNarrowingLower_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int32 testClass) + { + var result = AdvSimd.AddRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int32(); + var result = AdvSimd.AddRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddRoundedHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddRoundedHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.SByte.cs new file mode 100644 index 00000000000000..0d3355f2bb4462 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddRoundedHighNarrowingLower_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_SByte testClass) + { + var result = AdvSimd.AddRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_SByte(); + var result = AdvSimd.AddRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddRoundedHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddRoundedHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.UInt16.cs new file mode 100644 index 00000000000000..09a517e5484656 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddRoundedHighNarrowingLower_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt16 testClass) + { + var result = AdvSimd.AddRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt16(); + var result = AdvSimd.AddRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddRoundedHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddRoundedHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.UInt32.cs new file mode 100644 index 00000000000000..bd51ff2b4af552 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingLower.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddRoundedHighNarrowingLower_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt32 testClass) + { + var result = AdvSimd.AddRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((UInt64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt32(); + var result = AdvSimd.AddRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddRoundedHighNarrowingLower_Vector64_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((UInt64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddRoundedHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddRoundedHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.Byte.cs new file mode 100644 index 00000000000000..f62db16fae2edb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.Byte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddRoundedHighNarrowingUpper_Vector128_Byte() + { + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, UInt16[] inArray2, UInt16[] inArray3, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Byte testClass) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + private static UInt16[] _data3 = new UInt16[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)), + AdvSimd.LoadVector128((UInt16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AddRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AddRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Byte(); + var result = AdvSimd.AddRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)), + AdvSimd.LoadVector128((UInt16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] secondOp, UInt16[] thirdOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddRoundedHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.Int16.cs new file mode 100644 index 00000000000000..b2e8e80e0de3d0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.Int16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddRoundedHighNarrowingUpper_Vector128_Int16() + { + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] inArray2, Int32[] inArray3, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int16 testClass) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + private static Int32[] _data3 = new Int32[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)), + AdvSimd.LoadVector128((Int32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AddRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AddRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int16(); + var result = AdvSimd.AddRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)), + AdvSimd.LoadVector128((Int32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] secondOp, Int32[] thirdOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddRoundedHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.Int32.cs new file mode 100644 index 00000000000000..f73507f28f3ea9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.Int32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddRoundedHighNarrowingUpper_Vector128_Int32() + { + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] inArray2, Int64[] inArray3, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int32 testClass) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)), + AdvSimd.LoadVector128((Int64*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + private static Int64[] _data3 = new Int64[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)), + AdvSimd.LoadVector128((Int64*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AddRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AddRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int32(); + var result = AdvSimd.AddRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)), + AdvSimd.LoadVector128((Int64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)), + AdvSimd.LoadVector128((Int64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)), + AdvSimd.LoadVector128((Int64*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] inArray3 = new Int64[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] inArray3 = new Int64[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] secondOp, Int64[] thirdOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddRoundedHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.SByte.cs new file mode 100644 index 00000000000000..b12db4a90614b7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.SByte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddRoundedHighNarrowingUpper_Vector128_SByte() + { + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] inArray2, Int16[] inArray3, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_SByte testClass) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + private static Int16[] _data3 = new Int16[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)), + AdvSimd.LoadVector128((Int16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AddRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AddRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_SByte(); + var result = AdvSimd.AddRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)), + AdvSimd.LoadVector128((Int16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] secondOp, Int16[] thirdOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddRoundedHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.UInt16.cs new file mode 100644 index 00000000000000..0e96972f6db9c6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.UInt16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddRoundedHighNarrowingUpper_Vector128_UInt16() + { + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt32[] inArray2, UInt32[] inArray3, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt16 testClass) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + private static UInt32[] _data3 = new UInt32[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)), + AdvSimd.LoadVector128((UInt32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AddRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AddRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt16(); + var result = AdvSimd.AddRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)), + AdvSimd.LoadVector128((UInt32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] secondOp, UInt32[] thirdOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddRoundedHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.UInt32.cs new file mode 100644 index 00000000000000..03f2f544b43232 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddRoundedHighNarrowingUpper.Vector128.UInt32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddRoundedHighNarrowingUpper_Vector128_UInt32() + { + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt64[] inArray2, UInt64[] inArray3, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt32 testClass) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)), + AdvSimd.LoadVector128((UInt64*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + private static UInt64[] _data3 = new UInt64[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt64*)(pClsVar2)), + AdvSimd.LoadVector128((UInt64*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.AddRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.AddRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt32(); + var result = AdvSimd.AddRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__AddRoundedHighNarrowingUpper_Vector128_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)), + AdvSimd.LoadVector128((UInt64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)), + AdvSimd.LoadVector128((UInt64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt64*)(&test._fld2)), + AdvSimd.LoadVector128((UInt64*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] inArray3 = new UInt64[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] inArray3 = new UInt64[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] secondOp, UInt64[] thirdOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddRoundedHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.Byte.cs new file mode 100644 index 00000000000000..ad022425957867 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturate_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturate_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturate_Vector128_Byte testClass) + { + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturate_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturate_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturate_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_Byte(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.Int16.cs new file mode 100644 index 00000000000000..ebf2a2fa545b2b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturate_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturate_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturate_Vector128_Int16 testClass) + { + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturate_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturate_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturate_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_Int16(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.Int32.cs new file mode 100644 index 00000000000000..965a3a86213680 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturate_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturate_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturate_Vector128_Int32 testClass) + { + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturate_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturate_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturate_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_Int32(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.Int64.cs new file mode 100644 index 00000000000000..00bc234ca5da30 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.Int64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturate_Vector128_Int64() + { + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturate_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturate_Vector128_Int64 testClass) + { + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturate_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturate_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturate_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_Int64(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.SByte.cs new file mode 100644 index 00000000000000..d46682cd23789f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturate_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturate_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturate_Vector128_SByte testClass) + { + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturate_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturate_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturate_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_SByte(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.UInt16.cs new file mode 100644 index 00000000000000..52a934e9cabc7e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturate_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturate_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturate_Vector128_UInt16 testClass) + { + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturate_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturate_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturate_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_UInt16(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.UInt32.cs new file mode 100644 index 00000000000000..ea14479308f8a5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturate_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturate_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturate_Vector128_UInt32 testClass) + { + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturate_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturate_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturate_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_UInt32(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.UInt64.cs new file mode 100644 index 00000000000000..d4a60ae1edb9a8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector128.UInt64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturate_Vector128_UInt64() + { + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturate_Vector128_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturate_Vector128_UInt64 testClass) + { + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturate_Vector128_UInt64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturate_Vector128_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturate_Vector128_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((UInt64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_UInt64(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector128_UInt64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((UInt64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.Byte.cs new file mode 100644 index 00000000000000..a46cb529fa69e8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturate_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturate_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturate_Vector64_Byte testClass) + { + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturate_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturate_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturate_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_Byte(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.Int16.cs new file mode 100644 index 00000000000000..fc1e0e1f889883 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturate_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturate_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturate_Vector64_Int16 testClass) + { + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturate_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturate_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturate_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_Int16(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.Int32.cs new file mode 100644 index 00000000000000..1a1d3640ce5e64 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturate_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturate_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturate_Vector64_Int32 testClass) + { + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturate_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturate_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturate_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_Int32(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.SByte.cs new file mode 100644 index 00000000000000..a86e4ce7966ff6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturate_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturate_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturate_Vector64_SByte testClass) + { + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturate_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturate_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturate_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_SByte(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.UInt16.cs new file mode 100644 index 00000000000000..b950c219ffef1a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturate_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturate_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturate_Vector64_UInt16 testClass) + { + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturate_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturate_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturate_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_UInt16(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.UInt32.cs new file mode 100644 index 00000000000000..90a44250f9be51 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturate.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturate_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturate_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturate_Vector64_UInt32 testClass) + { + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturate_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturate_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturate_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_UInt32(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturate_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturate( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturateScalar.Vector64.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturateScalar.Vector64.Int64.cs new file mode 100644 index 00000000000000..444245ffeffdfe --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturateScalar.Vector64.Int64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturateScalar_Vector64_Int64() + { + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int64 testClass) + { + var result = AdvSimd.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturateScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int64(); + var result = AdvSimd.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_Int64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturateScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.AddSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturateScalar.Vector64.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturateScalar.Vector64.UInt64.cs new file mode 100644 index 00000000000000..5dc50d09e021e8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddSaturateScalar.Vector64.UInt64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddSaturateScalar_Vector64_UInt64() + { + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt64 testClass) + { + var result = AdvSimd.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pClsVar1)), + AdvSimd.LoadVector64((UInt64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt64(); + var result = AdvSimd.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddSaturateScalar_Vector64_UInt64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(&test._fld1)), + AdvSimd.LoadVector64((UInt64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.AddSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.Int16.cs new file mode 100644 index 00000000000000..99bae1a0c3d2c7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningLower_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningLower_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, SByte[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningLower_Vector128_Int16 testClass) + { + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningLower_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + + private Vector128 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningLower_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningLower_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_Int16(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, SByte[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningLower)}(Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.Int32.cs new file mode 100644 index 00000000000000..726bb621058f86 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningLower_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningLower_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int16[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningLower_Vector128_Int32 testClass) + { + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningLower_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + + private Vector128 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningLower_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningLower_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_Int32(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningLower)}(Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.Int64.cs new file mode 100644 index 00000000000000..78e816841f8b1e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.Int64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningLower_Vector128_Int64() + { + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningLower_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int32[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningLower_Vector128_Int64 testClass) + { + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningLower_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + + private Vector128 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningLower_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningLower_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_Int64(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int32[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningLower)}(Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.UInt16.cs new file mode 100644 index 00000000000000..abda7b3195aafa --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningLower_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningLower_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningLower_Vector128_UInt16 testClass) + { + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningLower_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + + private Vector128 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningLower_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningLower_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_UInt16(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningLower)}(Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.UInt32.cs new file mode 100644 index 00000000000000..93ef1eb038f42e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningLower_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningLower_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningLower_Vector128_UInt32 testClass) + { + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningLower_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + + private Vector128 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningLower_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningLower_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_UInt32(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningLower)}(Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.UInt64.cs new file mode 100644 index 00000000000000..6c31f6adbe8772 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector128.UInt64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningLower_Vector128_UInt64() + { + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningLower_Vector128_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningLower_Vector128_UInt64 testClass) + { + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningLower_Vector128_UInt64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + + private Vector128 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningLower_Vector128_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningLower_Vector128_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_UInt64(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector128_UInt64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningLower)}(Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.Byte.cs new file mode 100644 index 00000000000000..89d3bca73decdd --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningLower_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningLower_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningLower_Vector64_Byte testClass) + { + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningLower_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningLower_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningLower_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_Byte(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.Int16.cs new file mode 100644 index 00000000000000..7cbd8df92fd63b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningLower_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningLower_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningLower_Vector64_Int16 testClass) + { + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningLower_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningLower_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningLower_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_Int16(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.Int32.cs new file mode 100644 index 00000000000000..9fd5eeeb1d1785 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningLower_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningLower_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningLower_Vector64_Int32 testClass) + { + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningLower_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningLower_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningLower_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_Int32(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.SByte.cs new file mode 100644 index 00000000000000..eb75b77696725f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningLower_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningLower_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningLower_Vector64_SByte testClass) + { + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningLower_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningLower_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningLower_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_SByte(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.UInt16.cs new file mode 100644 index 00000000000000..f37ab0b7436b04 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningLower_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningLower_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningLower_Vector64_UInt16 testClass) + { + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningLower_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningLower_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningLower_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_UInt16(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.UInt32.cs new file mode 100644 index 00000000000000..a47b538dd8f983 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningLower.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningLower_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningLower_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningLower_Vector64_UInt32 testClass) + { + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningLower_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningLower_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningLower_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_UInt32(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningLower_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningLower( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Byte.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Byte.Vector128.Byte.cs new file mode 100644 index 00000000000000..181148d9da6762 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Byte.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningUpper_Vector128_Byte_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Byte_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningUpper_Vector128_Byte_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningUpper_Vector128_Byte_Vector128_Byte testClass) + { + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningUpper_Vector128_Byte_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningUpper_Vector128_Byte_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningUpper_Vector128_Byte_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Byte_Vector128_Byte(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Byte_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int16.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int16.Vector128.Int16.cs new file mode 100644 index 00000000000000..2ebc9c72874ef9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int16.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningUpper_Vector128_Int16_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_Int16 testClass) + { + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_Int16(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int16.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int16.Vector128.SByte.cs new file mode 100644 index 00000000000000..57e3326dcc45c5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int16.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningUpper_Vector128_Int16_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, SByte[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_SByte testClass) + { + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_SByte(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int16_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, SByte[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int32.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int32.Vector128.Int16.cs new file mode 100644 index 00000000000000..352b46a7676770 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int32.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningUpper_Vector128_Int32_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int16[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int16 testClass) + { + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int16(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int32.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int32.Vector128.Int32.cs new file mode 100644 index 00000000000000..f186612cb0d071 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int32.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningUpper_Vector128_Int32_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int32 testClass) + { + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int32(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int32_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int64.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int64.Vector128.Int32.cs new file mode 100644 index 00000000000000..ec5ba4a50d52a6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.Int64.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningUpper_Vector128_Int64_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int64_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningUpper_Vector128_Int64_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int32[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningUpper_Vector128_Int64_Vector128_Int32 testClass) + { + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningUpper_Vector128_Int64_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningUpper_Vector128_Int64_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningUpper_Vector128_Int64_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int64_Vector128_Int32(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_Int64_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int32[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.SByte.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.SByte.Vector128.SByte.cs new file mode 100644 index 00000000000000..4f708b1a13d283 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.SByte.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningUpper_Vector128_SByte_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_SByte_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningUpper_Vector128_SByte_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningUpper_Vector128_SByte_Vector128_SByte testClass) + { + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningUpper_Vector128_SByte_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningUpper_Vector128_SByte_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningUpper_Vector128_SByte_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_SByte_Vector128_SByte(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_SByte_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt16.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt16.Vector128.Byte.cs new file mode 100644 index 00000000000000..5978d753898b59 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt16.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningUpper_Vector128_UInt16_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_Byte testClass) + { + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_Byte(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt16.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt16.Vector128.UInt16.cs new file mode 100644 index 00000000000000..2296069f889b7d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt16.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningUpper_Vector128_UInt16_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_UInt16 testClass) + { + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_UInt16(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt16_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt32.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt32.Vector128.UInt16.cs new file mode 100644 index 00000000000000..f3da480e964b02 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt32.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningUpper_Vector128_UInt32_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt16 testClass) + { + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt16(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt32.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt32.Vector128.UInt32.cs new file mode 100644 index 00000000000000..ea2721392e969f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt32.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningUpper_Vector128_UInt32_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt32 testClass) + { + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt32(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt32_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt64.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt64.Vector128.UInt32.cs new file mode 100644 index 00000000000000..a885a9f3bcc210 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AddWideningUpper.Vector128.UInt64.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void AddWideningUpper_Vector128_UInt64_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt64_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt64_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt64_Vector128_UInt32 testClass) + { + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt64_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt64_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt64_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.AddWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.AddWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.AddWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.AddWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt64_Vector128_UInt32(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__AddWideningUpper_Vector128_UInt64_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.AddWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.AddWideningUpper( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.AddWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.AddWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_r.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_r.csproj index 49b47f9827b3da..7f2d981717c87d 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_r.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_r.csproj @@ -52,6 +52,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -68,6 +92,18 @@ + + + + + + + + + + + + @@ -75,10 +111,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -225,18 +337,132 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -249,6 +475,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -377,6 +632,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -451,6 +742,10 @@ + + + + @@ -467,6 +762,327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -505,10 +1121,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -529,6 +1213,18 @@ + + + + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_ro.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_ro.csproj index 6421f8af23e988..a6abd34f4f1ea6 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_ro.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/AdvSimd_ro.csproj @@ -52,6 +52,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -68,6 +92,18 @@ + + + + + + + + + + + + @@ -75,10 +111,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -225,18 +337,132 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -249,6 +475,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -377,6 +632,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -451,6 +742,10 @@ + + + + @@ -467,6 +762,327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -505,10 +1121,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -529,6 +1213,18 @@ + + + + + + + + + + + + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.Byte.8.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.Byte.8.cs new file mode 100644 index 00000000000000..cf9cd8e290cebe --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.Byte.8.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V128_Byte_8() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Byte_8(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Byte_8 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Byte_8 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 8); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Byte_8 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Byte*)(pFld)), + 8 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 8; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Byte_8() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Byte_8() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)), + (byte)8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + _clsVar, + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Byte*)(pClsVar)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Byte_8(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Byte_8(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Byte*)(pFld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Byte*)(pFld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Byte*)(&test._fld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[8]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[8]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector128)}(Vector128, 8): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.Int16.4.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.Int16.4.cs new file mode 100644 index 00000000000000..a1fa2b1b9b09ed --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.Int16.4.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V128_Int16_4() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int16_4(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int16_4 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int16_4 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 4); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int16_4 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int16*)(pFld)), + 4 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 4; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int16_4() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int16_4() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)4 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)4 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + _clsVar, + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int16_4(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int16_4(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int16*)(pFld)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int16*)(pFld)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[4]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[4]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector128)}(Vector128, 4): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.Int32.2.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.Int32.2.cs new file mode 100644 index 00000000000000..60a88d0d8dcd8f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.Int32.2.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V128_Int32_2() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int32_2(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int32_2 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int32_2 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int32_2 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int32*)(pFld)), + 2 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 2; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int32_2() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int32_2() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + _clsVar, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int32_2(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int32_2(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int32*)(pFld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int32*)(pFld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[2]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[2]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector128)}(Vector128, 2): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.SByte.8.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.SByte.8.cs new file mode 100644 index 00000000000000..a57c8b9184bf35 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.SByte.8.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V128_SByte_8() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_SByte_8(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_SByte_8 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_SByte_8 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 8); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_SByte_8 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((SByte*)(pFld)), + 8 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 8; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_SByte_8() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_SByte_8() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + (byte)8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + _clsVar, + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((SByte*)(pClsVar)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_SByte_8(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_SByte_8(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((SByte*)(pFld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((SByte*)(pFld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((SByte*)(&test._fld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[8]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[8]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector128)}(Vector128, 8): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.Single.2.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.Single.2.cs new file mode 100644 index 00000000000000..e6378b48f8972a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.Single.2.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V128_Single_2() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Single_2(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Single_2 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray, Single[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Single_2 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Single_2 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Single*)(pFld)), + 2 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly byte Imm = 2; + + private static Single[] _data = new Single[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Single_2() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Single_2() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Single*)(_dataTable.inArrayPtr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Single*)(_dataTable.inArrayPtr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + _clsVar, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Single*)(pClsVar)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Single*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Single_2(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Single_2(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Single*)(pFld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Single*)(pFld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((Single*)(&test._fld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[2]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[2]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector128)}(Vector128, 2): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.UInt16.4.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.UInt16.4.cs new file mode 100644 index 00000000000000..e88f362ef45ba5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.UInt16.4.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V128_UInt16_4() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt16_4(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt16_4 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt16_4 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 4); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt16_4 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 4 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 4; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt16_4() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt16_4() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)4 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + (byte)4 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + _clsVar, + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt16*)(pClsVar)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt16_4(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt16_4(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt16*)(&test._fld)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[4]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[4]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector128)}(Vector128, 4): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.UInt32.2.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.UInt32.2.cs new file mode 100644 index 00000000000000..b41fc8315838c1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V128.UInt32.2.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V128_UInt32_2() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt32_2(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt32_2 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt32_2 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt32_2 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 2 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 2; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt32_2() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt32_2() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + _clsVar, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt32*)(pClsVar)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt32_2(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt32_2(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector128((UInt32*)(&test._fld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[2]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[2]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector128)}(Vector128, 2): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.Byte.1.cs new file mode 100644 index 00000000000000..bf906543afbc0b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.Byte.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V64_Byte_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Byte_1 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Byte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Byte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Byte_1(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Byte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Byte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector128)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.Int16.1.cs new file mode 100644 index 00000000000000..0719e0b733efd8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.Int16.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V64_Int16_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int16_1 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int16_1(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector128)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.Int32.1.cs new file mode 100644 index 00000000000000..1ec386a4d26697 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.Int32.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V64_Int32_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int32_1 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int32_1(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Int32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector128)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.SByte.1.cs new file mode 100644 index 00000000000000..6f4e005cd56fb3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.SByte.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V64_SByte_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_SByte_1 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_SByte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_SByte_1(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_SByte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector128)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.Single.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.Single.1.cs new file mode 100644 index 00000000000000..f4868930b7b4ee --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.Single.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V64_Single_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Single_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Single_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray, Single[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Single_1 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Single_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Single*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly byte Imm = 1; + + private static Single[] _data = new Single[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Single_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Single_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Single*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Single*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Single*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Single_1(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_Single_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Single*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Single*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((Single*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector128)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.UInt16.1.cs new file mode 100644 index 00000000000000..e961e091b660cc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.UInt16.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V64_UInt16_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt16_1 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt16_1(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector128)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.UInt32.1.cs new file mode 100644 index 00000000000000..b68310f9d6225a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector128.V64.UInt32.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector128_V64_UInt32_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt32_1 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector128(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt32_1(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V64_UInt32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector128(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector128( + AdvSimd.LoadVector64((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector128)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.Byte.8.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.Byte.8.cs new file mode 100644 index 00000000000000..fecce603592ffa --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.Byte.8.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector64_V128_Byte_8() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Byte_8(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Byte_8 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Byte_8 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 8); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Byte_8 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Byte*)(pFld)), + 8 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 8; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Byte_8() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Byte_8() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + Unsafe.Read>(_dataTable.inArrayPtr), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)), + (byte)8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + _clsVar, + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Byte*)(pClsVar)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Byte_8(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Byte_8(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Byte*)(pFld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Byte*)(pFld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Byte*)(&test._fld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[8]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[8]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector64)}(Vector128, 8): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.Int16.4.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.Int16.4.cs new file mode 100644 index 00000000000000..3215c5acbba28c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.Int16.4.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector64_V128_Int16_4() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int16_4(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int16_4 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int16_4 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 4); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int16_4 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Int16*)(pFld)), + 4 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 4; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int16_4() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int16_4() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + Unsafe.Read>(_dataTable.inArrayPtr), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)4 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)4 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + _clsVar, + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int16_4(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int16_4(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Int16*)(pFld)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Int16*)(pFld)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[4]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[4]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector64)}(Vector128, 4): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.Int32.2.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.Int32.2.cs new file mode 100644 index 00000000000000..07b58d8aee7424 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.Int32.2.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector64_V128_Int32_2() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int32_2(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int32_2 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int32_2 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int32_2 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Int32*)(pFld)), + 2 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 2; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int32_2() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int32_2() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + Unsafe.Read>(_dataTable.inArrayPtr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + _clsVar, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int32_2(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Int32_2(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Int32*)(pFld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Int32*)(pFld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[2]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[2]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector64)}(Vector128, 2): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.SByte.8.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.SByte.8.cs new file mode 100644 index 00000000000000..0e795bdf5716ea --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.SByte.8.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector64_V128_SByte_8() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_SByte_8(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_SByte_8 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_SByte_8 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 8); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_SByte_8 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((SByte*)(pFld)), + 8 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 8; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_SByte_8() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_SByte_8() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + Unsafe.Read>(_dataTable.inArrayPtr), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + (byte)8 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + _clsVar, + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((SByte*)(pClsVar)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_SByte_8(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_SByte_8(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((SByte*)(pFld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((SByte*)(pFld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 8); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((SByte*)(&test._fld)), + 8 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[8]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[8]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector64)}(Vector128, 8): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.Single.2.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.Single.2.cs new file mode 100644 index 00000000000000..aab9d496e1439c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.Single.2.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector64_V128_Single_2() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Single_2(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Single_2 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray, Single[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Single_2 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Single_2 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Single*)(pFld)), + 2 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly byte Imm = 2; + + private static Single[] _data = new Single[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Single_2() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Single_2() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + Unsafe.Read>(_dataTable.inArrayPtr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Single*)(_dataTable.inArrayPtr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Single*)(_dataTable.inArrayPtr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + _clsVar, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Single*)(pClsVar)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Single*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Single_2(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_Single_2(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Single*)(pFld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Single*)(pFld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((Single*)(&test._fld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[2]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[2]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector64)}(Vector128, 2): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.UInt16.4.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.UInt16.4.cs new file mode 100644 index 00000000000000..afa70cf115708e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.UInt16.4.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector64_V128_UInt16_4() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt16_4(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt16_4 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt16_4 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 4); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt16_4 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 4 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 4; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt16_4() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt16_4() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + Unsafe.Read>(_dataTable.inArrayPtr), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)4 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + (byte)4 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + _clsVar, + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((UInt16*)(pClsVar)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt16_4(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt16_4(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 4); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((UInt16*)(&test._fld)), + 4 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[4]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[4]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector64)}(Vector128, 4): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.UInt32.2.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.UInt32.2.cs new file mode 100644 index 00000000000000..c6c51495eb00f2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V128.UInt32.2.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector64_V128_UInt32_2() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt32_2(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt32_2 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt32_2 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt32_2 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 2 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 2; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt32_2() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt32_2() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + Unsafe.Read>(_dataTable.inArrayPtr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + _clsVar, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((UInt32*)(pClsVar)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt32_2(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V128_UInt32_2(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector128((UInt32*)(&test._fld)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[2]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[2]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector64)}(Vector128, 2): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.Byte.1.cs new file mode 100644 index 00000000000000..e3cfeffb5da8a7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.Byte.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector64_V64_Byte_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Byte_1 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Byte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Byte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Byte_1(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Byte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Byte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector64)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.Int16.1.cs new file mode 100644 index 00000000000000..3d41d9be238ef6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.Int16.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector64_V64_Int16_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int16_1 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int16_1(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector64)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.Int32.1.cs new file mode 100644 index 00000000000000..711584eb3964ea --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.Int32.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector64_V64_Int32_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int32_1 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int32_1(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Int32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector64)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.SByte.1.cs new file mode 100644 index 00000000000000..7d8c97b4f785bf --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.SByte.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector64_V64_SByte_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_SByte_1 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_SByte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_SByte_1(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_SByte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector64)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.Single.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.Single.1.cs new file mode 100644 index 00000000000000..4afa6ce2cddf68 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.Single.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector64_V64_Single_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Single_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Single_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray, Single[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Single_1 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Single_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Single*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly byte Imm = 1; + + private static Single[] _data = new Single[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Single_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Single_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Single*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Single*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Single*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Single_1(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_Single_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Single*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Single*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((Single*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector64)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.UInt16.1.cs new file mode 100644 index 00000000000000..3323e524af933f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.UInt16.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector64_V64_UInt16_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt16_1 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt16_1(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector64)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.UInt32.1.cs new file mode 100644 index 00000000000000..cbbca5b59655d8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateSelectedScalarToVector64.V64.UInt32.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateSelectedScalarToVector64_V64_UInt32_1() + { + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt32_1 testClass) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateSelectedScalarToVector64), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.DuplicateSelectedScalarToVector64(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt32_1(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector64_V64_UInt32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateSelectedScalarToVector64(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateSelectedScalarToVector64( + AdvSimd.LoadVector64((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != firstOp[1]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != firstOp[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateSelectedScalarToVector64)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Byte.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Byte.31.cs new file mode 100644 index 00000000000000..aa12893fa2fb7c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Byte.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_Byte_31() + { + var test = new ImmOpTest__DuplicateToVector128_Byte_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector128_Byte_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector128_Byte_31() + { + Succeeded = true; + + _dataTable = new DataTable(new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.DuplicateToVector128( + (Byte)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector128), new Type[] { typeof(Byte) }) + .Invoke(null, new object[] { + (Byte)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + Byte[] outArray = new Byte[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector128)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Byte.cs new file mode 100644 index 00000000000000..5c60e82afd1e26 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Byte.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_Byte() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector128_Byte + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Byte _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetByte(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector128_Byte testClass) + { + var result = AdvSimd.DuplicateToVector128(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte _data; + + private static Byte _clsVar; + + private Byte _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector128_Byte() + { + _clsVar = TestLibrary.Generator.GetByte(); + } + + public DuplicateUnaryOpTest__DuplicateToVector128_Byte() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetByte(); + _data = TestLibrary.Generator.GetByte(); + + _dataTable = new DataTable(new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateToVector128( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector128), new Type[] { typeof(Byte) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateToVector128( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.DuplicateToVector128(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector128_Byte(); + var result = AdvSimd.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateToVector128(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Byte data, void* result, [CallerMemberName] string method = "") + { + Byte[] outArray = new Byte[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(Byte data, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector128)}(Byte): DuplicateToVector128 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Int16.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Int16.31.cs new file mode 100644 index 00000000000000..7173c618131eac --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Int16.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_Int16_31() + { + var test = new ImmOpTest__DuplicateToVector128_Int16_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector128_Int16_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector128_Int16_31() + { + Succeeded = true; + + _dataTable = new DataTable(new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.DuplicateToVector128( + (Int16)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector128), new Type[] { typeof(Int16) }) + .Invoke(null, new object[] { + (Int16)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + Int16[] outArray = new Int16[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector128)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Int16.cs new file mode 100644 index 00000000000000..510d61858ff057 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Int16.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_Int16() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector128_Int16 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Int16 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetInt16(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector128_Int16 testClass) + { + var result = AdvSimd.DuplicateToVector128(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16 _data; + + private static Int16 _clsVar; + + private Int16 _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector128_Int16() + { + _clsVar = TestLibrary.Generator.GetInt16(); + } + + public DuplicateUnaryOpTest__DuplicateToVector128_Int16() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetInt16(); + _data = TestLibrary.Generator.GetInt16(); + + _dataTable = new DataTable(new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateToVector128( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector128), new Type[] { typeof(Int16) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateToVector128( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.DuplicateToVector128(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector128_Int16(); + var result = AdvSimd.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateToVector128(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Int16 data, void* result, [CallerMemberName] string method = "") + { + Int16[] outArray = new Int16[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(Int16 data, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector128)}(Int16): DuplicateToVector128 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Int32.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Int32.31.cs new file mode 100644 index 00000000000000..b12495ff11aeda --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Int32.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_Int32_31() + { + var test = new ImmOpTest__DuplicateToVector128_Int32_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector128_Int32_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector128_Int32_31() + { + Succeeded = true; + + _dataTable = new DataTable(new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.DuplicateToVector128( + (Int32)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector128), new Type[] { typeof(Int32) }) + .Invoke(null, new object[] { + (Int32)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + Int32[] outArray = new Int32[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector128)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Int32.cs new file mode 100644 index 00000000000000..77967e2777f32f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Int32.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_Int32() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector128_Int32 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Int32 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetInt32(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector128_Int32 testClass) + { + var result = AdvSimd.DuplicateToVector128(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32 _data; + + private static Int32 _clsVar; + + private Int32 _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector128_Int32() + { + _clsVar = TestLibrary.Generator.GetInt32(); + } + + public DuplicateUnaryOpTest__DuplicateToVector128_Int32() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetInt32(); + _data = TestLibrary.Generator.GetInt32(); + + _dataTable = new DataTable(new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateToVector128( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector128), new Type[] { typeof(Int32) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateToVector128( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.DuplicateToVector128(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector128_Int32(); + var result = AdvSimd.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateToVector128(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Int32 data, void* result, [CallerMemberName] string method = "") + { + Int32[] outArray = new Int32[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(Int32 data, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector128)}(Int32): DuplicateToVector128 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.SByte.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.SByte.31.cs new file mode 100644 index 00000000000000..824cd8968dd8c9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.SByte.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_SByte_31() + { + var test = new ImmOpTest__DuplicateToVector128_SByte_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector128_SByte_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector128_SByte_31() + { + Succeeded = true; + + _dataTable = new DataTable(new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.DuplicateToVector128( + (SByte)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector128), new Type[] { typeof(SByte) }) + .Invoke(null, new object[] { + (SByte)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + SByte[] outArray = new SByte[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector128)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.SByte.cs new file mode 100644 index 00000000000000..183ad0bc2041c1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.SByte.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_SByte() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector128_SByte + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public SByte _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetSByte(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector128_SByte testClass) + { + var result = AdvSimd.DuplicateToVector128(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte _data; + + private static SByte _clsVar; + + private SByte _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector128_SByte() + { + _clsVar = TestLibrary.Generator.GetSByte(); + } + + public DuplicateUnaryOpTest__DuplicateToVector128_SByte() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetSByte(); + _data = TestLibrary.Generator.GetSByte(); + + _dataTable = new DataTable(new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateToVector128( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector128), new Type[] { typeof(SByte) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateToVector128( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.DuplicateToVector128(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector128_SByte(); + var result = AdvSimd.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateToVector128(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(SByte data, void* result, [CallerMemberName] string method = "") + { + SByte[] outArray = new SByte[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(SByte data, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector128)}(SByte): DuplicateToVector128 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Single.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Single.31.cs new file mode 100644 index 00000000000000..9685545397d5d4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Single.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_Single_31() + { + var test = new ImmOpTest__DuplicateToVector128_Single_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector128_Single_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector128_Single_31() + { + Succeeded = true; + + _dataTable = new DataTable(new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.DuplicateToVector128( + (Single)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector128), new Type[] { typeof(Single) }) + .Invoke(null, new object[] { + (Single)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + Single[] outArray = new Single[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector128)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Single.cs new file mode 100644 index 00000000000000..caad761f6f97d3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.Single.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_Single() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector128_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector128_Single + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Single _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetSingle(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector128_Single testClass) + { + var result = AdvSimd.DuplicateToVector128(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single _data; + + private static Single _clsVar; + + private Single _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector128_Single() + { + _clsVar = TestLibrary.Generator.GetSingle(); + } + + public DuplicateUnaryOpTest__DuplicateToVector128_Single() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetSingle(); + _data = TestLibrary.Generator.GetSingle(); + + _dataTable = new DataTable(new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateToVector128( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector128), new Type[] { typeof(Single) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateToVector128( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.DuplicateToVector128(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector128_Single(); + var result = AdvSimd.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateToVector128(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Single data, void* result, [CallerMemberName] string method = "") + { + Single[] outArray = new Single[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(Single data, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector128)}(Single): DuplicateToVector128 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.UInt16.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.UInt16.31.cs new file mode 100644 index 00000000000000..2bfa725584af99 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.UInt16.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_UInt16_31() + { + var test = new ImmOpTest__DuplicateToVector128_UInt16_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector128_UInt16_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector128_UInt16_31() + { + Succeeded = true; + + _dataTable = new DataTable(new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.DuplicateToVector128( + (UInt16)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector128), new Type[] { typeof(UInt16) }) + .Invoke(null, new object[] { + (UInt16)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + UInt16[] outArray = new UInt16[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector128)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.UInt16.cs new file mode 100644 index 00000000000000..5f4e3097fc90a8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.UInt16.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_UInt16() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector128_UInt16 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public UInt16 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetUInt16(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector128_UInt16 testClass) + { + var result = AdvSimd.DuplicateToVector128(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16 _data; + + private static UInt16 _clsVar; + + private UInt16 _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector128_UInt16() + { + _clsVar = TestLibrary.Generator.GetUInt16(); + } + + public DuplicateUnaryOpTest__DuplicateToVector128_UInt16() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetUInt16(); + _data = TestLibrary.Generator.GetUInt16(); + + _dataTable = new DataTable(new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateToVector128( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector128), new Type[] { typeof(UInt16) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateToVector128( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.DuplicateToVector128(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector128_UInt16(); + var result = AdvSimd.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateToVector128(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(UInt16 data, void* result, [CallerMemberName] string method = "") + { + UInt16[] outArray = new UInt16[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(UInt16 data, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector128)}(UInt16): DuplicateToVector128 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.UInt32.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.UInt32.31.cs new file mode 100644 index 00000000000000..c3ade1c04fd546 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.UInt32.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_UInt32_31() + { + var test = new ImmOpTest__DuplicateToVector128_UInt32_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector128_UInt32_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector128_UInt32_31() + { + Succeeded = true; + + _dataTable = new DataTable(new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.DuplicateToVector128( + (UInt32)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector128), new Type[] { typeof(UInt32) }) + .Invoke(null, new object[] { + (UInt32)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + UInt32[] outArray = new UInt32[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector128)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.UInt32.cs new file mode 100644 index 00000000000000..2d58f8f2e3fcb1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector128.UInt32.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector128_UInt32() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector128_UInt32 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public UInt32 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetUInt32(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector128_UInt32 testClass) + { + var result = AdvSimd.DuplicateToVector128(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32 _data; + + private static UInt32 _clsVar; + + private UInt32 _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector128_UInt32() + { + _clsVar = TestLibrary.Generator.GetUInt32(); + } + + public DuplicateUnaryOpTest__DuplicateToVector128_UInt32() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetUInt32(); + _data = TestLibrary.Generator.GetUInt32(); + + _dataTable = new DataTable(new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateToVector128( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector128), new Type[] { typeof(UInt32) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateToVector128( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.DuplicateToVector128(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector128_UInt32(); + var result = AdvSimd.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateToVector128(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateToVector128(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(UInt32 data, void* result, [CallerMemberName] string method = "") + { + UInt32[] outArray = new UInt32[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(UInt32 data, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector128)}(UInt32): DuplicateToVector128 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Byte.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Byte.31.cs new file mode 100644 index 00000000000000..44c3abb84eb068 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Byte.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector64_Byte_31() + { + var test = new ImmOpTest__DuplicateToVector64_Byte_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector64_Byte_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector64_Byte_31() + { + Succeeded = true; + + _dataTable = new DataTable(new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.DuplicateToVector64( + (Byte)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector64), new Type[] { typeof(Byte) }) + .Invoke(null, new object[] { + (Byte)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + Byte[] outArray = new Byte[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector64)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Byte.cs new file mode 100644 index 00000000000000..c519918584cce8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Byte.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector64_Byte() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector64_Byte + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Byte _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetByte(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector64_Byte testClass) + { + var result = AdvSimd.DuplicateToVector64(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte _data; + + private static Byte _clsVar; + + private Byte _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector64_Byte() + { + _clsVar = TestLibrary.Generator.GetByte(); + } + + public DuplicateUnaryOpTest__DuplicateToVector64_Byte() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetByte(); + _data = TestLibrary.Generator.GetByte(); + + _dataTable = new DataTable(new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateToVector64( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector64), new Type[] { typeof(Byte) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateToVector64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.DuplicateToVector64(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector64_Byte(); + var result = AdvSimd.DuplicateToVector64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateToVector64(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateToVector64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Byte data, void* result, [CallerMemberName] string method = "") + { + Byte[] outArray = new Byte[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(Byte data, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector64)}(Byte): DuplicateToVector64 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Int16.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Int16.31.cs new file mode 100644 index 00000000000000..7a84cc8afac977 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Int16.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector64_Int16_31() + { + var test = new ImmOpTest__DuplicateToVector64_Int16_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector64_Int16_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector64_Int16_31() + { + Succeeded = true; + + _dataTable = new DataTable(new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.DuplicateToVector64( + (Int16)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector64), new Type[] { typeof(Int16) }) + .Invoke(null, new object[] { + (Int16)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + Int16[] outArray = new Int16[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector64)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Int16.cs new file mode 100644 index 00000000000000..c5e95a8ee07f1e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Int16.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector64_Int16() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector64_Int16 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Int16 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetInt16(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector64_Int16 testClass) + { + var result = AdvSimd.DuplicateToVector64(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16 _data; + + private static Int16 _clsVar; + + private Int16 _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector64_Int16() + { + _clsVar = TestLibrary.Generator.GetInt16(); + } + + public DuplicateUnaryOpTest__DuplicateToVector64_Int16() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetInt16(); + _data = TestLibrary.Generator.GetInt16(); + + _dataTable = new DataTable(new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateToVector64( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector64), new Type[] { typeof(Int16) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateToVector64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.DuplicateToVector64(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector64_Int16(); + var result = AdvSimd.DuplicateToVector64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateToVector64(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateToVector64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Int16 data, void* result, [CallerMemberName] string method = "") + { + Int16[] outArray = new Int16[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(Int16 data, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector64)}(Int16): DuplicateToVector64 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Int32.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Int32.31.cs new file mode 100644 index 00000000000000..beb6d1b62ac6b7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Int32.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector64_Int32_31() + { + var test = new ImmOpTest__DuplicateToVector64_Int32_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector64_Int32_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector64_Int32_31() + { + Succeeded = true; + + _dataTable = new DataTable(new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.DuplicateToVector64( + (Int32)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector64), new Type[] { typeof(Int32) }) + .Invoke(null, new object[] { + (Int32)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + Int32[] outArray = new Int32[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector64)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Int32.cs new file mode 100644 index 00000000000000..40450592088994 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Int32.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector64_Int32() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector64_Int32 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Int32 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetInt32(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector64_Int32 testClass) + { + var result = AdvSimd.DuplicateToVector64(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32 _data; + + private static Int32 _clsVar; + + private Int32 _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector64_Int32() + { + _clsVar = TestLibrary.Generator.GetInt32(); + } + + public DuplicateUnaryOpTest__DuplicateToVector64_Int32() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetInt32(); + _data = TestLibrary.Generator.GetInt32(); + + _dataTable = new DataTable(new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateToVector64( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector64), new Type[] { typeof(Int32) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateToVector64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.DuplicateToVector64(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector64_Int32(); + var result = AdvSimd.DuplicateToVector64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateToVector64(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateToVector64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Int32 data, void* result, [CallerMemberName] string method = "") + { + Int32[] outArray = new Int32[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(Int32 data, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector64)}(Int32): DuplicateToVector64 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.SByte.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.SByte.31.cs new file mode 100644 index 00000000000000..1d0a5e7dcac31e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.SByte.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector64_SByte_31() + { + var test = new ImmOpTest__DuplicateToVector64_SByte_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector64_SByte_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector64_SByte_31() + { + Succeeded = true; + + _dataTable = new DataTable(new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.DuplicateToVector64( + (SByte)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector64), new Type[] { typeof(SByte) }) + .Invoke(null, new object[] { + (SByte)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + SByte[] outArray = new SByte[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector64)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.SByte.cs new file mode 100644 index 00000000000000..98f2458c5a9cd5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.SByte.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector64_SByte() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector64_SByte + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public SByte _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetSByte(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector64_SByte testClass) + { + var result = AdvSimd.DuplicateToVector64(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte _data; + + private static SByte _clsVar; + + private SByte _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector64_SByte() + { + _clsVar = TestLibrary.Generator.GetSByte(); + } + + public DuplicateUnaryOpTest__DuplicateToVector64_SByte() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetSByte(); + _data = TestLibrary.Generator.GetSByte(); + + _dataTable = new DataTable(new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateToVector64( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector64), new Type[] { typeof(SByte) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateToVector64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.DuplicateToVector64(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector64_SByte(); + var result = AdvSimd.DuplicateToVector64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateToVector64(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateToVector64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(SByte data, void* result, [CallerMemberName] string method = "") + { + SByte[] outArray = new SByte[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(SByte data, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector64)}(SByte): DuplicateToVector64 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Single.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Single.31.cs new file mode 100644 index 00000000000000..cbfbf0c11ee5ac --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Single.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector64_Single_31() + { + var test = new ImmOpTest__DuplicateToVector64_Single_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector64_Single_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector64_Single_31() + { + Succeeded = true; + + _dataTable = new DataTable(new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.DuplicateToVector64( + (Single)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector64), new Type[] { typeof(Single) }) + .Invoke(null, new object[] { + (Single)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + Single[] outArray = new Single[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector64)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Single.cs new file mode 100644 index 00000000000000..44bd66c4948543 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.Single.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector64_Single() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector64_Single(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector64_Single + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Single _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetSingle(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector64_Single testClass) + { + var result = AdvSimd.DuplicateToVector64(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single _data; + + private static Single _clsVar; + + private Single _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector64_Single() + { + _clsVar = TestLibrary.Generator.GetSingle(); + } + + public DuplicateUnaryOpTest__DuplicateToVector64_Single() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetSingle(); + _data = TestLibrary.Generator.GetSingle(); + + _dataTable = new DataTable(new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateToVector64( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector64), new Type[] { typeof(Single) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateToVector64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.DuplicateToVector64(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector64_Single(); + var result = AdvSimd.DuplicateToVector64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateToVector64(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateToVector64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Single data, void* result, [CallerMemberName] string method = "") + { + Single[] outArray = new Single[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(Single data, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector64)}(Single): DuplicateToVector64 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.UInt16.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.UInt16.31.cs new file mode 100644 index 00000000000000..cf0b6de370ba59 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.UInt16.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector64_UInt16_31() + { + var test = new ImmOpTest__DuplicateToVector64_UInt16_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector64_UInt16_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector64_UInt16_31() + { + Succeeded = true; + + _dataTable = new DataTable(new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.DuplicateToVector64( + (UInt16)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector64), new Type[] { typeof(UInt16) }) + .Invoke(null, new object[] { + (UInt16)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + UInt16[] outArray = new UInt16[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector64)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.UInt16.cs new file mode 100644 index 00000000000000..e533f462f74662 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.UInt16.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector64_UInt16() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector64_UInt16 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public UInt16 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetUInt16(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector64_UInt16 testClass) + { + var result = AdvSimd.DuplicateToVector64(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16 _data; + + private static UInt16 _clsVar; + + private UInt16 _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector64_UInt16() + { + _clsVar = TestLibrary.Generator.GetUInt16(); + } + + public DuplicateUnaryOpTest__DuplicateToVector64_UInt16() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetUInt16(); + _data = TestLibrary.Generator.GetUInt16(); + + _dataTable = new DataTable(new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateToVector64( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector64), new Type[] { typeof(UInt16) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateToVector64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.DuplicateToVector64(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector64_UInt16(); + var result = AdvSimd.DuplicateToVector64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateToVector64(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateToVector64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(UInt16 data, void* result, [CallerMemberName] string method = "") + { + UInt16[] outArray = new UInt16[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(UInt16 data, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector64)}(UInt16): DuplicateToVector64 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.UInt32.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.UInt32.31.cs new file mode 100644 index 00000000000000..5e4d079535d7a6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.UInt32.31.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector64_UInt32_31() + { + var test = new ImmOpTest__DuplicateToVector64_UInt32_31(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmOpTest__DuplicateToVector64_UInt32_31 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private DataTable _dataTable; + + public ImmOpTest__DuplicateToVector64_UInt32_31() + { + Succeeded = true; + + _dataTable = new DataTable(new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = AdvSimd.DuplicateToVector64( + (UInt32)31 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector64), new Type[] { typeof(UInt32) }) + .Invoke(null, new object[] { + (UInt32)31 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + UInt32[] outArray = new UInt32[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(outArray, method); + } + + private void ValidateResult(UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != 31) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 31) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector64)}(31): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.UInt32.cs new file mode 100644 index 00000000000000..402384cf4b01c8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/DuplicateToVector64.UInt32.cs @@ -0,0 +1,300 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void DuplicateToVector64_UInt32() + { + var test = new DuplicateUnaryOpTest__DuplicateToVector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector64_UInt32 + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public UInt32 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = TestLibrary.Generator.GetUInt32(); + return testStruct; + } + + public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector64_UInt32 testClass) + { + var result = AdvSimd.DuplicateToVector64(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32 _data; + + private static UInt32 _clsVar; + + private UInt32 _fld; + + private DataTable _dataTable; + + static DuplicateUnaryOpTest__DuplicateToVector64_UInt32() + { + _clsVar = TestLibrary.Generator.GetUInt32(); + } + + public DuplicateUnaryOpTest__DuplicateToVector64_UInt32() + { + Succeeded = true; + + _fld = TestLibrary.Generator.GetUInt32(); + _data = TestLibrary.Generator.GetUInt32(); + + _dataTable = new DataTable(new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.DuplicateToVector64( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.DuplicateToVector64), new Type[] { typeof(UInt32) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.DuplicateToVector64( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data)); + var result = AdvSimd.DuplicateToVector64(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new DuplicateUnaryOpTest__DuplicateToVector64_UInt32(); + var result = AdvSimd.DuplicateToVector64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.DuplicateToVector64(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.DuplicateToVector64(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(UInt32 data, void* result, [CallerMemberName] string method = "") + { + UInt32[] outArray = new UInt32[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult(UInt32 data, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (result[0] != data) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != data) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.DuplicateToVector64)}(UInt32): DuplicateToVector64 failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..c73e03247a540c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Byte.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector128_Byte_1() + { + var test = new ExtractTest__Extract_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(Byte[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector128_Byte_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector128_Byte_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Byte*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static readonly byte ElementIndex = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Byte)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Byte)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Byte*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector128_Byte_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector128_Byte_1(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Byte*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Byte*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((Byte*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Byte result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, Byte result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(Byte[] firstOp, Byte result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (firstOp[ElementIndex] != result) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Double.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Double.1.cs new file mode 100644 index 00000000000000..e156320e9911ee --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Double.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector128_Double_1() + { + var test = new ExtractTest__Extract_Vector128_Double_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector128_Double_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(Double[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector128_Double_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector128_Double_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Double*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static readonly byte ElementIndex = 1; + + private static Double[] _data1 = new Double[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector128_Double_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector128_Double_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Double)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Double)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Double*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector128_Double_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector128_Double_1(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Double*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Double*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((Double*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Double result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, Double result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(Double[] firstOp, Double result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.DoubleToInt64Bits(firstOp[ElementIndex]) != BitConverter.DoubleToInt64Bits(result)) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..4a71ca0345a548 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Int16.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector128_Int16_1() + { + var test = new ExtractTest__Extract_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(Int16[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector128_Int16_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector128_Int16_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Int16*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static readonly byte ElementIndex = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Int16)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Int16)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Int16*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector128_Int16_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector128_Int16_1(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Int16*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Int16*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((Int16*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Int16 result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, Int16 result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(Int16[] firstOp, Int16 result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (firstOp[ElementIndex] != result) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..5628f4be82dfed --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Int32.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector128_Int32_1() + { + var test = new ExtractTest__Extract_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(Int32[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector128_Int32_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector128_Int32_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Int32*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static readonly byte ElementIndex = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Int32)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Int32)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Int32*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector128_Int32_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector128_Int32_1(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Int32*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Int32*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((Int32*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Int32 result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, Int32 result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(Int32[] firstOp, Int32 result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (firstOp[ElementIndex] != result) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Int64.1.cs new file mode 100644 index 00000000000000..49097baabe4c27 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Int64.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector128_Int64_1() + { + var test = new ExtractTest__Extract_Vector128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector128_Int64_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(Int64[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector128_Int64_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector128_Int64_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Int64*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static readonly byte ElementIndex = 1; + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Int64)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Int64)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Int64*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector128_Int64_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector128_Int64_1(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Int64*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Int64*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((Int64*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Int64 result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, Int64 result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(Int64[] firstOp, Int64 result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (firstOp[ElementIndex] != result) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..3d98ada72588c4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.SByte.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector128_SByte_1() + { + var test = new ExtractTest__Extract_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(SByte[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector128_SByte_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector128_SByte_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((SByte*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static readonly byte ElementIndex = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (SByte)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (SByte)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((SByte*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector128_SByte_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector128_SByte_1(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((SByte*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((SByte*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((SByte*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, SByte result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, SByte result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(SByte[] firstOp, SByte result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (firstOp[ElementIndex] != result) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Single.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Single.1.cs new file mode 100644 index 00000000000000..ab39d135250ef9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.Single.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector128_Single_1() + { + var test = new ExtractTest__Extract_Vector128_Single_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector128_Single_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(Single[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector128_Single_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector128_Single_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Single*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static readonly byte ElementIndex = 1; + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector128_Single_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector128_Single_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Single)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Single)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Single*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector128_Single_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector128_Single_1(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Single*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((Single*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((Single*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Single result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, Single result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(Single[] firstOp, Single result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.SingleToInt32Bits(firstOp[ElementIndex]) != BitConverter.SingleToInt32Bits(result)) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..8a9b7c55e72298 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.UInt16.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector128_UInt16_1() + { + var test = new ExtractTest__Extract_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector128_UInt16_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((UInt16*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static readonly byte ElementIndex = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (UInt16)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (UInt16)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((UInt16*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector128_UInt16_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector128_UInt16_1(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((UInt16*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((UInt16*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((UInt16*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, UInt16 result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, UInt16 result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16 result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (firstOp[ElementIndex] != result) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..d09b8e74f139b2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.UInt32.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector128_UInt32_1() + { + var test = new ExtractTest__Extract_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector128_UInt32_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((UInt32*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static readonly byte ElementIndex = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (UInt32)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (UInt32)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((UInt32*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector128_UInt32_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector128_UInt32_1(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((UInt32*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((UInt32*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((UInt32*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, UInt32 result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, UInt32 result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32 result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (firstOp[ElementIndex] != result) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.UInt64.1.cs new file mode 100644 index 00000000000000..f501f0fbb79275 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector128.UInt64.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector128_UInt64_1() + { + var test = new ExtractTest__Extract_Vector128_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector128_UInt64_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector128_UInt64_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector128_UInt64_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((UInt64*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static readonly byte ElementIndex = 1; + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector128_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector128_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (UInt64)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (UInt64)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((UInt64*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector128_UInt64_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector128_UInt64_1(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((UInt64*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector128((UInt64*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector128((UInt64*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, UInt64 result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, UInt64 result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64 result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (firstOp[ElementIndex] != result) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..e82b1fe35014aa --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.Byte.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector64_Byte_1() + { + var test = new ExtractTest__Extract_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(Byte[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector64_Byte_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector64_Byte_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Byte*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static readonly byte ElementIndex = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Byte)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Byte)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Byte*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector64_Byte_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector64_Byte_1(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Byte*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Byte*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector64((Byte*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Byte result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, Byte result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(Byte[] firstOp, Byte result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (firstOp[ElementIndex] != result) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..19ade2aced0805 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.Int16.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector64_Int16_1() + { + var test = new ExtractTest__Extract_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(Int16[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector64_Int16_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector64_Int16_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Int16*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static readonly byte ElementIndex = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Int16)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Int16)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Int16*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector64_Int16_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector64_Int16_1(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Int16*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Int16*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector64((Int16*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Int16 result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, Int16 result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(Int16[] firstOp, Int16 result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (firstOp[ElementIndex] != result) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..5491ce3c30e79c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.Int32.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector64_Int32_1() + { + var test = new ExtractTest__Extract_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(Int32[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector64_Int32_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector64_Int32_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Int32*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static readonly byte ElementIndex = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Int32)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Int32)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Int32*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector64_Int32_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector64_Int32_1(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Int32*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Int32*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector64((Int32*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Int32 result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, Int32 result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(Int32[] firstOp, Int32 result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (firstOp[ElementIndex] != result) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..26ded3956e6ee3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.SByte.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector64_SByte_1() + { + var test = new ExtractTest__Extract_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(SByte[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector64_SByte_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector64_SByte_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((SByte*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static readonly byte ElementIndex = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (SByte)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (SByte)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((SByte*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector64_SByte_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector64_SByte_1(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((SByte*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((SByte*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector64((SByte*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, SByte result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, SByte result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(SByte[] firstOp, SByte result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (firstOp[ElementIndex] != result) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.Single.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.Single.1.cs new file mode 100644 index 00000000000000..d8259eed0a687c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.Single.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector64_Single_1() + { + var test = new ExtractTest__Extract_Vector64_Single_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector64_Single_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(Single[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector64_Single_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector64_Single_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Single*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static readonly byte ElementIndex = 1; + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector64_Single_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector64_Single_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Single)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (Single)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Single*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector64_Single_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector64_Single_1(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Single*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((Single*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector64((Single*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Single result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, Single result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(Single[] firstOp, Single result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.SingleToInt32Bits(firstOp[ElementIndex]) != BitConverter.SingleToInt32Bits(result)) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..ccd69dd151fa7a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.UInt16.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector64_UInt16_1() + { + var test = new ExtractTest__Extract_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector64_UInt16_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((UInt16*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static readonly byte ElementIndex = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (UInt16)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (UInt16)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((UInt16*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector64_UInt16_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector64_UInt16_1(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((UInt16*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((UInt16*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector64((UInt16*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, UInt16 result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, UInt16 result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16 result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (firstOp[ElementIndex] != result) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..30a7e4a952e2cc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Extract.Vector64.UInt32.1.cs @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Extract_Vector64_UInt32_1() + { + var test = new ExtractTest__Extract_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__Extract_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__Extract_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.Extract(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__Extract_Vector64_UInt32_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((UInt32*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static readonly byte ElementIndex = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static ExtractTest__Extract_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractTest__Extract_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Extract( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Extract( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (UInt32)result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Extract), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, (UInt32)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Extract(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((UInt32*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.Extract(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__Extract_Vector64_UInt32_1(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__Extract_Vector64_UInt32_1(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((UInt32*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Extract(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.Extract(AdvSimd.LoadVector64((UInt32*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Extract( + AdvSimd.LoadVector64((UInt32*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, UInt32 result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, UInt32 result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32 result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (firstOp[ElementIndex] != result) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Extract)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.Int16.cs deleted file mode 100644 index 7443842e0e9701..00000000000000 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.Int16.cs +++ /dev/null @@ -1,537 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/****************************************************************************** - * This file is auto-generated from a template file by the GenerateTests.csx * - * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * - * changes, please update the corresponding template and run according to the * - * directions listed in the file. * - ******************************************************************************/ - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; - -namespace JIT.HardwareIntrinsics.Arm -{ - public static partial class Program - { - private static void ExtractAndNarrowHigh_Vector128_Int16() - { - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int16(); - - if (test.IsSupported) - { - // Validates basic functionality works, using Unsafe.Read - test.RunBasicScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates basic functionality works, using Load - test.RunBasicScenario_Load(); - } - - // Validates calling via reflection works, using Unsafe.Read - test.RunReflectionScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates calling via reflection works, using Load - test.RunReflectionScenario_Load(); - } - - // Validates passing a static member works - test.RunClsVarScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing a static member works, using pinning and Load - test.RunClsVarScenario_Load(); - } - - // Validates passing a local works, using Unsafe.Read - test.RunLclVarScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates passing a local works, using Load - test.RunLclVarScenario_Load(); - } - - // Validates passing the field of a local class works - test.RunClassLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local class works, using pinning and Load - test.RunClassLclFldScenario_Load(); - } - - // Validates passing an instance member of a class works - test.RunClassFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a class works, using pinning and Load - test.RunClassFldScenario_Load(); - } - - // Validates passing the field of a local struct works - test.RunStructLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local struct works, using pinning and Load - test.RunStructLclFldScenario_Load(); - } - - // Validates passing an instance member of a struct works - test.RunStructFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a struct works, using pinning and Load - test.RunStructFldScenario_Load(); - } - } - else - { - // Validates we throw on unsupported hardware - test.RunUnsupportedScenario(); - } - - if (!test.Succeeded) - { - throw new Exception("One or more scenarios did not complete as expected."); - } - } - } - - public sealed unsafe class SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int16 - { - private struct DataTable - { - private byte[] inArray1; - private byte[] inArray2; - private byte[] outArray; - - private GCHandle inHandle1; - private GCHandle inHandle2; - private GCHandle outHandle; - - private ulong alignment; - - public DataTable(SByte[] inArray1, Int16[] inArray2, SByte[] outArray, int alignment) - { - int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); - int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); - int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); - if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) - { - throw new ArgumentException("Invalid value of alignment"); - } - - this.inArray1 = new byte[alignment * 2]; - this.inArray2 = new byte[alignment * 2]; - this.outArray = new byte[alignment * 2]; - - this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); - this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); - this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); - - this.alignment = (ulong)alignment; - - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); - } - - public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); - public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); - public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); - - public void Dispose() - { - inHandle1.Free(); - inHandle2.Free(); - outHandle.Free(); - } - - private static unsafe void* Align(byte* buffer, ulong expectedAlignment) - { - return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); - } - } - - private struct TestStruct - { - public Vector64 _fld1; - public Vector128 _fld2; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - - return testStruct; - } - - public void RunStructFldScenario(SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int16 testClass) - { - var result = AdvSimd.ExtractAndNarrowHigh(_fld1, _fld2); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); - } - - public void RunStructFldScenario_Load(SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int16 testClass) - { - fixed (Vector64* pFld1 = &_fld1) - fixed (Vector128* pFld2 = &_fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((SByte*)(pFld1)), - AdvSimd.LoadVector128((Int16*)(pFld2)) - ); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); - } - } - } - - private static readonly int LargestVectorSize = 16; - - private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); - private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); - private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); - - private static SByte[] _data1 = new SByte[Op1ElementCount]; - private static Int16[] _data2 = new Int16[Op2ElementCount]; - - private static Vector64 _clsVar1; - private static Vector128 _clsVar2; - - private Vector64 _fld1; - private Vector128 _fld2; - - private DataTable _dataTable; - - static SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int16() - { - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - } - - public SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int16() - { - Succeeded = true; - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } - _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); - } - - public bool IsSupported => AdvSimd.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = AdvSimd.ExtractAndNarrowHigh( - Unsafe.Read>(_dataTable.inArray1Ptr), - Unsafe.Read>(_dataTable.inArray2Ptr) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunBasicScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); - - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), - AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowHigh), new Type[] { typeof(Vector64), typeof(Vector128) }) - .Invoke(null, new object[] { - Unsafe.Read>(_dataTable.inArray1Ptr), - Unsafe.Read>(_dataTable.inArray2Ptr) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowHigh), new Type[] { typeof(Vector64), typeof(Vector128) }) - .Invoke(null, new object[] { - AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), - AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = AdvSimd.ExtractAndNarrowHigh( - _clsVar1, - _clsVar2 - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); - - fixed (Vector64* pClsVar1 = &_clsVar1) - fixed (Vector128* pClsVar2 = &_clsVar2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((SByte*)(pClsVar1)), - AdvSimd.LoadVector128((Int16*)(pClsVar2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); - } - } - - public void RunLclVarScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); - - var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); - var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); - var result = AdvSimd.ExtractAndNarrowHigh(op1, op2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, op2, _dataTable.outArrayPtr); - } - - public void RunLclVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); - - var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); - var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); - var result = AdvSimd.ExtractAndNarrowHigh(op1, op2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, op2, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int16(); - var result = AdvSimd.ExtractAndNarrowHigh(test._fld1, test._fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); - - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int16(); - - fixed (Vector64* pFld1 = &test._fld1) - fixed (Vector128* pFld2 = &test._fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((SByte*)(pFld1)), - AdvSimd.LoadVector128((Int16*)(pFld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = AdvSimd.ExtractAndNarrowHigh(_fld1, _fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); - } - - public void RunClassFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); - - fixed (Vector64* pFld1 = &_fld1) - fixed (Vector128* pFld2 = &_fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((SByte*)(pFld1)), - AdvSimd.LoadVector128((Int16*)(pFld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); - } - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowHigh(test._fld1, test._fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunStructLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((SByte*)(&test._fld1)), - AdvSimd.LoadVector128((Int16*)(&test._fld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunStructFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); - - var test = TestStruct.Create(); - test.RunStructFldScenario(this); - } - - public void RunStructFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); - - var test = TestStruct.Create(); - test.RunStructFldScenario_Load(this); - } - - public void RunUnsupportedScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); - - bool succeeded = false; - - try - { - RunBasicScenario_UnsafeRead(); - } - catch (PlatformNotSupportedException) - { - succeeded = true; - } - - if (!succeeded) - { - Succeeded = false; - } - } - - private void ValidateResult(Vector64 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") - { - SByte[] inArray1 = new SByte[Op1ElementCount]; - Int16[] inArray2 = new Int16[Op2ElementCount]; - SByte[] outArray = new SByte[RetElementCount]; - - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, inArray2, outArray, method); - } - - private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") - { - SByte[] inArray1 = new SByte[Op1ElementCount]; - Int16[] inArray2 = new Int16[Op2ElementCount]; - SByte[] outArray = new SByte[RetElementCount]; - - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, inArray2, outArray, method); - } - - private void ValidateResult(SByte[] left, Int16[] right, SByte[] result, [CallerMemberName] string method = "") - { - bool succeeded = true; - - if (Helpers.ExtractAndNarrowHigh(0, left, right, result)) - { - succeeded = false; - } - else - { - for (var i = 1; i < RetElementCount; i++) - { - if (Helpers.ExtractAndNarrowHigh(i, left, right, result)) - { - succeeded = false; - break; - } - } - } - - if (!succeeded) - { - TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractAndNarrowHigh)}(Vector64, Vector128): {method} failed:"); - TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); - TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); - TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.Int32.cs deleted file mode 100644 index 87d362dd9f5d30..00000000000000 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.Int32.cs +++ /dev/null @@ -1,537 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/****************************************************************************** - * This file is auto-generated from a template file by the GenerateTests.csx * - * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * - * changes, please update the corresponding template and run according to the * - * directions listed in the file. * - ******************************************************************************/ - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; - -namespace JIT.HardwareIntrinsics.Arm -{ - public static partial class Program - { - private static void ExtractAndNarrowHigh_Vector128_Int32() - { - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int32(); - - if (test.IsSupported) - { - // Validates basic functionality works, using Unsafe.Read - test.RunBasicScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates basic functionality works, using Load - test.RunBasicScenario_Load(); - } - - // Validates calling via reflection works, using Unsafe.Read - test.RunReflectionScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates calling via reflection works, using Load - test.RunReflectionScenario_Load(); - } - - // Validates passing a static member works - test.RunClsVarScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing a static member works, using pinning and Load - test.RunClsVarScenario_Load(); - } - - // Validates passing a local works, using Unsafe.Read - test.RunLclVarScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates passing a local works, using Load - test.RunLclVarScenario_Load(); - } - - // Validates passing the field of a local class works - test.RunClassLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local class works, using pinning and Load - test.RunClassLclFldScenario_Load(); - } - - // Validates passing an instance member of a class works - test.RunClassFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a class works, using pinning and Load - test.RunClassFldScenario_Load(); - } - - // Validates passing the field of a local struct works - test.RunStructLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local struct works, using pinning and Load - test.RunStructLclFldScenario_Load(); - } - - // Validates passing an instance member of a struct works - test.RunStructFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a struct works, using pinning and Load - test.RunStructFldScenario_Load(); - } - } - else - { - // Validates we throw on unsupported hardware - test.RunUnsupportedScenario(); - } - - if (!test.Succeeded) - { - throw new Exception("One or more scenarios did not complete as expected."); - } - } - } - - public sealed unsafe class SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int32 - { - private struct DataTable - { - private byte[] inArray1; - private byte[] inArray2; - private byte[] outArray; - - private GCHandle inHandle1; - private GCHandle inHandle2; - private GCHandle outHandle; - - private ulong alignment; - - public DataTable(Int16[] inArray1, Int32[] inArray2, Int16[] outArray, int alignment) - { - int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); - int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); - int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); - if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) - { - throw new ArgumentException("Invalid value of alignment"); - } - - this.inArray1 = new byte[alignment * 2]; - this.inArray2 = new byte[alignment * 2]; - this.outArray = new byte[alignment * 2]; - - this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); - this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); - this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); - - this.alignment = (ulong)alignment; - - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); - } - - public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); - public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); - public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); - - public void Dispose() - { - inHandle1.Free(); - inHandle2.Free(); - outHandle.Free(); - } - - private static unsafe void* Align(byte* buffer, ulong expectedAlignment) - { - return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); - } - } - - private struct TestStruct - { - public Vector64 _fld1; - public Vector128 _fld2; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - - return testStruct; - } - - public void RunStructFldScenario(SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int32 testClass) - { - var result = AdvSimd.ExtractAndNarrowHigh(_fld1, _fld2); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); - } - - public void RunStructFldScenario_Load(SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int32 testClass) - { - fixed (Vector64* pFld1 = &_fld1) - fixed (Vector128* pFld2 = &_fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Int16*)(pFld1)), - AdvSimd.LoadVector128((Int32*)(pFld2)) - ); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); - } - } - } - - private static readonly int LargestVectorSize = 16; - - private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); - private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); - private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); - - private static Int16[] _data1 = new Int16[Op1ElementCount]; - private static Int32[] _data2 = new Int32[Op2ElementCount]; - - private static Vector64 _clsVar1; - private static Vector128 _clsVar2; - - private Vector64 _fld1; - private Vector128 _fld2; - - private DataTable _dataTable; - - static SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int32() - { - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - } - - public SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int32() - { - Succeeded = true; - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } - _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); - } - - public bool IsSupported => AdvSimd.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = AdvSimd.ExtractAndNarrowHigh( - Unsafe.Read>(_dataTable.inArray1Ptr), - Unsafe.Read>(_dataTable.inArray2Ptr) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunBasicScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); - - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), - AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowHigh), new Type[] { typeof(Vector64), typeof(Vector128) }) - .Invoke(null, new object[] { - Unsafe.Read>(_dataTable.inArray1Ptr), - Unsafe.Read>(_dataTable.inArray2Ptr) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowHigh), new Type[] { typeof(Vector64), typeof(Vector128) }) - .Invoke(null, new object[] { - AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), - AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = AdvSimd.ExtractAndNarrowHigh( - _clsVar1, - _clsVar2 - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); - - fixed (Vector64* pClsVar1 = &_clsVar1) - fixed (Vector128* pClsVar2 = &_clsVar2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Int16*)(pClsVar1)), - AdvSimd.LoadVector128((Int32*)(pClsVar2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); - } - } - - public void RunLclVarScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); - - var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); - var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); - var result = AdvSimd.ExtractAndNarrowHigh(op1, op2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, op2, _dataTable.outArrayPtr); - } - - public void RunLclVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); - - var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); - var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); - var result = AdvSimd.ExtractAndNarrowHigh(op1, op2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, op2, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int32(); - var result = AdvSimd.ExtractAndNarrowHigh(test._fld1, test._fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); - - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int32(); - - fixed (Vector64* pFld1 = &test._fld1) - fixed (Vector128* pFld2 = &test._fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Int16*)(pFld1)), - AdvSimd.LoadVector128((Int32*)(pFld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = AdvSimd.ExtractAndNarrowHigh(_fld1, _fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); - } - - public void RunClassFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); - - fixed (Vector64* pFld1 = &_fld1) - fixed (Vector128* pFld2 = &_fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Int16*)(pFld1)), - AdvSimd.LoadVector128((Int32*)(pFld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); - } - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowHigh(test._fld1, test._fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunStructLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Int16*)(&test._fld1)), - AdvSimd.LoadVector128((Int32*)(&test._fld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunStructFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); - - var test = TestStruct.Create(); - test.RunStructFldScenario(this); - } - - public void RunStructFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); - - var test = TestStruct.Create(); - test.RunStructFldScenario_Load(this); - } - - public void RunUnsupportedScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); - - bool succeeded = false; - - try - { - RunBasicScenario_UnsafeRead(); - } - catch (PlatformNotSupportedException) - { - succeeded = true; - } - - if (!succeeded) - { - Succeeded = false; - } - } - - private void ValidateResult(Vector64 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") - { - Int16[] inArray1 = new Int16[Op1ElementCount]; - Int32[] inArray2 = new Int32[Op2ElementCount]; - Int16[] outArray = new Int16[RetElementCount]; - - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, inArray2, outArray, method); - } - - private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") - { - Int16[] inArray1 = new Int16[Op1ElementCount]; - Int32[] inArray2 = new Int32[Op2ElementCount]; - Int16[] outArray = new Int16[RetElementCount]; - - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, inArray2, outArray, method); - } - - private void ValidateResult(Int16[] left, Int32[] right, Int16[] result, [CallerMemberName] string method = "") - { - bool succeeded = true; - - if (Helpers.ExtractAndNarrowHigh(0, left, right, result)) - { - succeeded = false; - } - else - { - for (var i = 1; i < RetElementCount; i++) - { - if (Helpers.ExtractAndNarrowHigh(i, left, right, result)) - { - succeeded = false; - break; - } - } - } - - if (!succeeded) - { - TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractAndNarrowHigh)}(Vector64, Vector128): {method} failed:"); - TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); - TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); - TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.Int64.cs deleted file mode 100644 index a8cf88a417fc4f..00000000000000 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.Int64.cs +++ /dev/null @@ -1,537 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/****************************************************************************** - * This file is auto-generated from a template file by the GenerateTests.csx * - * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * - * changes, please update the corresponding template and run according to the * - * directions listed in the file. * - ******************************************************************************/ - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; - -namespace JIT.HardwareIntrinsics.Arm -{ - public static partial class Program - { - private static void ExtractAndNarrowHigh_Vector128_Int64() - { - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int64(); - - if (test.IsSupported) - { - // Validates basic functionality works, using Unsafe.Read - test.RunBasicScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates basic functionality works, using Load - test.RunBasicScenario_Load(); - } - - // Validates calling via reflection works, using Unsafe.Read - test.RunReflectionScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates calling via reflection works, using Load - test.RunReflectionScenario_Load(); - } - - // Validates passing a static member works - test.RunClsVarScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing a static member works, using pinning and Load - test.RunClsVarScenario_Load(); - } - - // Validates passing a local works, using Unsafe.Read - test.RunLclVarScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates passing a local works, using Load - test.RunLclVarScenario_Load(); - } - - // Validates passing the field of a local class works - test.RunClassLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local class works, using pinning and Load - test.RunClassLclFldScenario_Load(); - } - - // Validates passing an instance member of a class works - test.RunClassFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a class works, using pinning and Load - test.RunClassFldScenario_Load(); - } - - // Validates passing the field of a local struct works - test.RunStructLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local struct works, using pinning and Load - test.RunStructLclFldScenario_Load(); - } - - // Validates passing an instance member of a struct works - test.RunStructFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a struct works, using pinning and Load - test.RunStructFldScenario_Load(); - } - } - else - { - // Validates we throw on unsupported hardware - test.RunUnsupportedScenario(); - } - - if (!test.Succeeded) - { - throw new Exception("One or more scenarios did not complete as expected."); - } - } - } - - public sealed unsafe class SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int64 - { - private struct DataTable - { - private byte[] inArray1; - private byte[] inArray2; - private byte[] outArray; - - private GCHandle inHandle1; - private GCHandle inHandle2; - private GCHandle outHandle; - - private ulong alignment; - - public DataTable(Int32[] inArray1, Int64[] inArray2, Int32[] outArray, int alignment) - { - int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); - int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); - int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); - if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) - { - throw new ArgumentException("Invalid value of alignment"); - } - - this.inArray1 = new byte[alignment * 2]; - this.inArray2 = new byte[alignment * 2]; - this.outArray = new byte[alignment * 2]; - - this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); - this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); - this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); - - this.alignment = (ulong)alignment; - - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); - } - - public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); - public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); - public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); - - public void Dispose() - { - inHandle1.Free(); - inHandle2.Free(); - outHandle.Free(); - } - - private static unsafe void* Align(byte* buffer, ulong expectedAlignment) - { - return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); - } - } - - private struct TestStruct - { - public Vector64 _fld1; - public Vector128 _fld2; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - - return testStruct; - } - - public void RunStructFldScenario(SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int64 testClass) - { - var result = AdvSimd.ExtractAndNarrowHigh(_fld1, _fld2); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); - } - - public void RunStructFldScenario_Load(SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int64 testClass) - { - fixed (Vector64* pFld1 = &_fld1) - fixed (Vector128* pFld2 = &_fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Int32*)(pFld1)), - AdvSimd.LoadVector128((Int64*)(pFld2)) - ); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); - } - } - } - - private static readonly int LargestVectorSize = 16; - - private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); - private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); - private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); - - private static Int32[] _data1 = new Int32[Op1ElementCount]; - private static Int64[] _data2 = new Int64[Op2ElementCount]; - - private static Vector64 _clsVar1; - private static Vector128 _clsVar2; - - private Vector64 _fld1; - private Vector128 _fld2; - - private DataTable _dataTable; - - static SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int64() - { - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - } - - public SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int64() - { - Succeeded = true; - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } - _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); - } - - public bool IsSupported => AdvSimd.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = AdvSimd.ExtractAndNarrowHigh( - Unsafe.Read>(_dataTable.inArray1Ptr), - Unsafe.Read>(_dataTable.inArray2Ptr) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunBasicScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); - - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), - AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowHigh), new Type[] { typeof(Vector64), typeof(Vector128) }) - .Invoke(null, new object[] { - Unsafe.Read>(_dataTable.inArray1Ptr), - Unsafe.Read>(_dataTable.inArray2Ptr) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowHigh), new Type[] { typeof(Vector64), typeof(Vector128) }) - .Invoke(null, new object[] { - AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), - AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = AdvSimd.ExtractAndNarrowHigh( - _clsVar1, - _clsVar2 - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); - - fixed (Vector64* pClsVar1 = &_clsVar1) - fixed (Vector128* pClsVar2 = &_clsVar2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Int32*)(pClsVar1)), - AdvSimd.LoadVector128((Int64*)(pClsVar2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); - } - } - - public void RunLclVarScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); - - var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); - var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); - var result = AdvSimd.ExtractAndNarrowHigh(op1, op2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, op2, _dataTable.outArrayPtr); - } - - public void RunLclVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); - - var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); - var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); - var result = AdvSimd.ExtractAndNarrowHigh(op1, op2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, op2, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int64(); - var result = AdvSimd.ExtractAndNarrowHigh(test._fld1, test._fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); - - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_Int64(); - - fixed (Vector64* pFld1 = &test._fld1) - fixed (Vector128* pFld2 = &test._fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Int32*)(pFld1)), - AdvSimd.LoadVector128((Int64*)(pFld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = AdvSimd.ExtractAndNarrowHigh(_fld1, _fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); - } - - public void RunClassFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); - - fixed (Vector64* pFld1 = &_fld1) - fixed (Vector128* pFld2 = &_fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Int32*)(pFld1)), - AdvSimd.LoadVector128((Int64*)(pFld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); - } - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowHigh(test._fld1, test._fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunStructLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Int32*)(&test._fld1)), - AdvSimd.LoadVector128((Int64*)(&test._fld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunStructFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); - - var test = TestStruct.Create(); - test.RunStructFldScenario(this); - } - - public void RunStructFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); - - var test = TestStruct.Create(); - test.RunStructFldScenario_Load(this); - } - - public void RunUnsupportedScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); - - bool succeeded = false; - - try - { - RunBasicScenario_UnsafeRead(); - } - catch (PlatformNotSupportedException) - { - succeeded = true; - } - - if (!succeeded) - { - Succeeded = false; - } - } - - private void ValidateResult(Vector64 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") - { - Int32[] inArray1 = new Int32[Op1ElementCount]; - Int64[] inArray2 = new Int64[Op2ElementCount]; - Int32[] outArray = new Int32[RetElementCount]; - - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, inArray2, outArray, method); - } - - private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") - { - Int32[] inArray1 = new Int32[Op1ElementCount]; - Int64[] inArray2 = new Int64[Op2ElementCount]; - Int32[] outArray = new Int32[RetElementCount]; - - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, inArray2, outArray, method); - } - - private void ValidateResult(Int32[] left, Int64[] right, Int32[] result, [CallerMemberName] string method = "") - { - bool succeeded = true; - - if (Helpers.ExtractAndNarrowHigh(0, left, right, result)) - { - succeeded = false; - } - else - { - for (var i = 1; i < RetElementCount; i++) - { - if (Helpers.ExtractAndNarrowHigh(i, left, right, result)) - { - succeeded = false; - break; - } - } - } - - if (!succeeded) - { - TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractAndNarrowHigh)}(Vector64, Vector128): {method} failed:"); - TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); - TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); - TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.UInt16.cs deleted file mode 100644 index e8a9d0f6127b4e..00000000000000 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.UInt16.cs +++ /dev/null @@ -1,537 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/****************************************************************************** - * This file is auto-generated from a template file by the GenerateTests.csx * - * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * - * changes, please update the corresponding template and run according to the * - * directions listed in the file. * - ******************************************************************************/ - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; - -namespace JIT.HardwareIntrinsics.Arm -{ - public static partial class Program - { - private static void ExtractAndNarrowHigh_Vector128_UInt16() - { - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt16(); - - if (test.IsSupported) - { - // Validates basic functionality works, using Unsafe.Read - test.RunBasicScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates basic functionality works, using Load - test.RunBasicScenario_Load(); - } - - // Validates calling via reflection works, using Unsafe.Read - test.RunReflectionScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates calling via reflection works, using Load - test.RunReflectionScenario_Load(); - } - - // Validates passing a static member works - test.RunClsVarScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing a static member works, using pinning and Load - test.RunClsVarScenario_Load(); - } - - // Validates passing a local works, using Unsafe.Read - test.RunLclVarScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates passing a local works, using Load - test.RunLclVarScenario_Load(); - } - - // Validates passing the field of a local class works - test.RunClassLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local class works, using pinning and Load - test.RunClassLclFldScenario_Load(); - } - - // Validates passing an instance member of a class works - test.RunClassFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a class works, using pinning and Load - test.RunClassFldScenario_Load(); - } - - // Validates passing the field of a local struct works - test.RunStructLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local struct works, using pinning and Load - test.RunStructLclFldScenario_Load(); - } - - // Validates passing an instance member of a struct works - test.RunStructFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a struct works, using pinning and Load - test.RunStructFldScenario_Load(); - } - } - else - { - // Validates we throw on unsupported hardware - test.RunUnsupportedScenario(); - } - - if (!test.Succeeded) - { - throw new Exception("One or more scenarios did not complete as expected."); - } - } - } - - public sealed unsafe class SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt16 - { - private struct DataTable - { - private byte[] inArray1; - private byte[] inArray2; - private byte[] outArray; - - private GCHandle inHandle1; - private GCHandle inHandle2; - private GCHandle outHandle; - - private ulong alignment; - - public DataTable(Byte[] inArray1, UInt16[] inArray2, Byte[] outArray, int alignment) - { - int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); - int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); - int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); - if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) - { - throw new ArgumentException("Invalid value of alignment"); - } - - this.inArray1 = new byte[alignment * 2]; - this.inArray2 = new byte[alignment * 2]; - this.outArray = new byte[alignment * 2]; - - this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); - this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); - this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); - - this.alignment = (ulong)alignment; - - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); - } - - public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); - public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); - public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); - - public void Dispose() - { - inHandle1.Free(); - inHandle2.Free(); - outHandle.Free(); - } - - private static unsafe void* Align(byte* buffer, ulong expectedAlignment) - { - return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); - } - } - - private struct TestStruct - { - public Vector64 _fld1; - public Vector128 _fld2; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - - return testStruct; - } - - public void RunStructFldScenario(SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt16 testClass) - { - var result = AdvSimd.ExtractAndNarrowHigh(_fld1, _fld2); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); - } - - public void RunStructFldScenario_Load(SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt16 testClass) - { - fixed (Vector64* pFld1 = &_fld1) - fixed (Vector128* pFld2 = &_fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Byte*)(pFld1)), - AdvSimd.LoadVector128((UInt16*)(pFld2)) - ); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); - } - } - } - - private static readonly int LargestVectorSize = 16; - - private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); - private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); - private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); - - private static Byte[] _data1 = new Byte[Op1ElementCount]; - private static UInt16[] _data2 = new UInt16[Op2ElementCount]; - - private static Vector64 _clsVar1; - private static Vector128 _clsVar2; - - private Vector64 _fld1; - private Vector128 _fld2; - - private DataTable _dataTable; - - static SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt16() - { - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - } - - public SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt16() - { - Succeeded = true; - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } - _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); - } - - public bool IsSupported => AdvSimd.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = AdvSimd.ExtractAndNarrowHigh( - Unsafe.Read>(_dataTable.inArray1Ptr), - Unsafe.Read>(_dataTable.inArray2Ptr) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunBasicScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); - - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), - AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowHigh), new Type[] { typeof(Vector64), typeof(Vector128) }) - .Invoke(null, new object[] { - Unsafe.Read>(_dataTable.inArray1Ptr), - Unsafe.Read>(_dataTable.inArray2Ptr) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowHigh), new Type[] { typeof(Vector64), typeof(Vector128) }) - .Invoke(null, new object[] { - AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), - AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = AdvSimd.ExtractAndNarrowHigh( - _clsVar1, - _clsVar2 - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); - - fixed (Vector64* pClsVar1 = &_clsVar1) - fixed (Vector128* pClsVar2 = &_clsVar2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Byte*)(pClsVar1)), - AdvSimd.LoadVector128((UInt16*)(pClsVar2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); - } - } - - public void RunLclVarScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); - - var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); - var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); - var result = AdvSimd.ExtractAndNarrowHigh(op1, op2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, op2, _dataTable.outArrayPtr); - } - - public void RunLclVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); - - var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); - var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); - var result = AdvSimd.ExtractAndNarrowHigh(op1, op2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, op2, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt16(); - var result = AdvSimd.ExtractAndNarrowHigh(test._fld1, test._fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); - - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt16(); - - fixed (Vector64* pFld1 = &test._fld1) - fixed (Vector128* pFld2 = &test._fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Byte*)(pFld1)), - AdvSimd.LoadVector128((UInt16*)(pFld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = AdvSimd.ExtractAndNarrowHigh(_fld1, _fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); - } - - public void RunClassFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); - - fixed (Vector64* pFld1 = &_fld1) - fixed (Vector128* pFld2 = &_fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Byte*)(pFld1)), - AdvSimd.LoadVector128((UInt16*)(pFld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); - } - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowHigh(test._fld1, test._fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunStructLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((Byte*)(&test._fld1)), - AdvSimd.LoadVector128((UInt16*)(&test._fld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunStructFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); - - var test = TestStruct.Create(); - test.RunStructFldScenario(this); - } - - public void RunStructFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); - - var test = TestStruct.Create(); - test.RunStructFldScenario_Load(this); - } - - public void RunUnsupportedScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); - - bool succeeded = false; - - try - { - RunBasicScenario_UnsafeRead(); - } - catch (PlatformNotSupportedException) - { - succeeded = true; - } - - if (!succeeded) - { - Succeeded = false; - } - } - - private void ValidateResult(Vector64 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") - { - Byte[] inArray1 = new Byte[Op1ElementCount]; - UInt16[] inArray2 = new UInt16[Op2ElementCount]; - Byte[] outArray = new Byte[RetElementCount]; - - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, inArray2, outArray, method); - } - - private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") - { - Byte[] inArray1 = new Byte[Op1ElementCount]; - UInt16[] inArray2 = new UInt16[Op2ElementCount]; - Byte[] outArray = new Byte[RetElementCount]; - - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, inArray2, outArray, method); - } - - private void ValidateResult(Byte[] left, UInt16[] right, Byte[] result, [CallerMemberName] string method = "") - { - bool succeeded = true; - - if (Helpers.ExtractAndNarrowHigh(0, left, right, result)) - { - succeeded = false; - } - else - { - for (var i = 1; i < RetElementCount; i++) - { - if (Helpers.ExtractAndNarrowHigh(i, left, right, result)) - { - succeeded = false; - break; - } - } - } - - if (!succeeded) - { - TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractAndNarrowHigh)}(Vector64, Vector128): {method} failed:"); - TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); - TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); - TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.UInt32.cs deleted file mode 100644 index b82668cbb447e4..00000000000000 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.UInt32.cs +++ /dev/null @@ -1,537 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/****************************************************************************** - * This file is auto-generated from a template file by the GenerateTests.csx * - * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * - * changes, please update the corresponding template and run according to the * - * directions listed in the file. * - ******************************************************************************/ - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; - -namespace JIT.HardwareIntrinsics.Arm -{ - public static partial class Program - { - private static void ExtractAndNarrowHigh_Vector128_UInt32() - { - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt32(); - - if (test.IsSupported) - { - // Validates basic functionality works, using Unsafe.Read - test.RunBasicScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates basic functionality works, using Load - test.RunBasicScenario_Load(); - } - - // Validates calling via reflection works, using Unsafe.Read - test.RunReflectionScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates calling via reflection works, using Load - test.RunReflectionScenario_Load(); - } - - // Validates passing a static member works - test.RunClsVarScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing a static member works, using pinning and Load - test.RunClsVarScenario_Load(); - } - - // Validates passing a local works, using Unsafe.Read - test.RunLclVarScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates passing a local works, using Load - test.RunLclVarScenario_Load(); - } - - // Validates passing the field of a local class works - test.RunClassLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local class works, using pinning and Load - test.RunClassLclFldScenario_Load(); - } - - // Validates passing an instance member of a class works - test.RunClassFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a class works, using pinning and Load - test.RunClassFldScenario_Load(); - } - - // Validates passing the field of a local struct works - test.RunStructLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local struct works, using pinning and Load - test.RunStructLclFldScenario_Load(); - } - - // Validates passing an instance member of a struct works - test.RunStructFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a struct works, using pinning and Load - test.RunStructFldScenario_Load(); - } - } - else - { - // Validates we throw on unsupported hardware - test.RunUnsupportedScenario(); - } - - if (!test.Succeeded) - { - throw new Exception("One or more scenarios did not complete as expected."); - } - } - } - - public sealed unsafe class SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt32 - { - private struct DataTable - { - private byte[] inArray1; - private byte[] inArray2; - private byte[] outArray; - - private GCHandle inHandle1; - private GCHandle inHandle2; - private GCHandle outHandle; - - private ulong alignment; - - public DataTable(UInt16[] inArray1, UInt32[] inArray2, UInt16[] outArray, int alignment) - { - int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); - int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); - int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); - if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) - { - throw new ArgumentException("Invalid value of alignment"); - } - - this.inArray1 = new byte[alignment * 2]; - this.inArray2 = new byte[alignment * 2]; - this.outArray = new byte[alignment * 2]; - - this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); - this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); - this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); - - this.alignment = (ulong)alignment; - - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); - } - - public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); - public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); - public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); - - public void Dispose() - { - inHandle1.Free(); - inHandle2.Free(); - outHandle.Free(); - } - - private static unsafe void* Align(byte* buffer, ulong expectedAlignment) - { - return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); - } - } - - private struct TestStruct - { - public Vector64 _fld1; - public Vector128 _fld2; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - - return testStruct; - } - - public void RunStructFldScenario(SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt32 testClass) - { - var result = AdvSimd.ExtractAndNarrowHigh(_fld1, _fld2); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); - } - - public void RunStructFldScenario_Load(SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt32 testClass) - { - fixed (Vector64* pFld1 = &_fld1) - fixed (Vector128* pFld2 = &_fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((UInt16*)(pFld1)), - AdvSimd.LoadVector128((UInt32*)(pFld2)) - ); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); - } - } - } - - private static readonly int LargestVectorSize = 16; - - private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); - private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); - private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); - - private static UInt16[] _data1 = new UInt16[Op1ElementCount]; - private static UInt32[] _data2 = new UInt32[Op2ElementCount]; - - private static Vector64 _clsVar1; - private static Vector128 _clsVar2; - - private Vector64 _fld1; - private Vector128 _fld2; - - private DataTable _dataTable; - - static SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt32() - { - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - } - - public SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt32() - { - Succeeded = true; - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } - _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); - } - - public bool IsSupported => AdvSimd.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = AdvSimd.ExtractAndNarrowHigh( - Unsafe.Read>(_dataTable.inArray1Ptr), - Unsafe.Read>(_dataTable.inArray2Ptr) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunBasicScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); - - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), - AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowHigh), new Type[] { typeof(Vector64), typeof(Vector128) }) - .Invoke(null, new object[] { - Unsafe.Read>(_dataTable.inArray1Ptr), - Unsafe.Read>(_dataTable.inArray2Ptr) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowHigh), new Type[] { typeof(Vector64), typeof(Vector128) }) - .Invoke(null, new object[] { - AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), - AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = AdvSimd.ExtractAndNarrowHigh( - _clsVar1, - _clsVar2 - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); - - fixed (Vector64* pClsVar1 = &_clsVar1) - fixed (Vector128* pClsVar2 = &_clsVar2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((UInt16*)(pClsVar1)), - AdvSimd.LoadVector128((UInt32*)(pClsVar2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); - } - } - - public void RunLclVarScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); - - var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); - var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); - var result = AdvSimd.ExtractAndNarrowHigh(op1, op2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, op2, _dataTable.outArrayPtr); - } - - public void RunLclVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); - - var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); - var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); - var result = AdvSimd.ExtractAndNarrowHigh(op1, op2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, op2, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt32(); - var result = AdvSimd.ExtractAndNarrowHigh(test._fld1, test._fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); - - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt32(); - - fixed (Vector64* pFld1 = &test._fld1) - fixed (Vector128* pFld2 = &test._fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((UInt16*)(pFld1)), - AdvSimd.LoadVector128((UInt32*)(pFld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = AdvSimd.ExtractAndNarrowHigh(_fld1, _fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); - } - - public void RunClassFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); - - fixed (Vector64* pFld1 = &_fld1) - fixed (Vector128* pFld2 = &_fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((UInt16*)(pFld1)), - AdvSimd.LoadVector128((UInt32*)(pFld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); - } - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowHigh(test._fld1, test._fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunStructLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((UInt16*)(&test._fld1)), - AdvSimd.LoadVector128((UInt32*)(&test._fld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunStructFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); - - var test = TestStruct.Create(); - test.RunStructFldScenario(this); - } - - public void RunStructFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); - - var test = TestStruct.Create(); - test.RunStructFldScenario_Load(this); - } - - public void RunUnsupportedScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); - - bool succeeded = false; - - try - { - RunBasicScenario_UnsafeRead(); - } - catch (PlatformNotSupportedException) - { - succeeded = true; - } - - if (!succeeded) - { - Succeeded = false; - } - } - - private void ValidateResult(Vector64 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") - { - UInt16[] inArray1 = new UInt16[Op1ElementCount]; - UInt32[] inArray2 = new UInt32[Op2ElementCount]; - UInt16[] outArray = new UInt16[RetElementCount]; - - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, inArray2, outArray, method); - } - - private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") - { - UInt16[] inArray1 = new UInt16[Op1ElementCount]; - UInt32[] inArray2 = new UInt32[Op2ElementCount]; - UInt16[] outArray = new UInt16[RetElementCount]; - - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, inArray2, outArray, method); - } - - private void ValidateResult(UInt16[] left, UInt32[] right, UInt16[] result, [CallerMemberName] string method = "") - { - bool succeeded = true; - - if (Helpers.ExtractAndNarrowHigh(0, left, right, result)) - { - succeeded = false; - } - else - { - for (var i = 1; i < RetElementCount; i++) - { - if (Helpers.ExtractAndNarrowHigh(i, left, right, result)) - { - succeeded = false; - break; - } - } - } - - if (!succeeded) - { - TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractAndNarrowHigh)}(Vector64, Vector128): {method} failed:"); - TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); - TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); - TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.UInt64.cs deleted file mode 100644 index 08834020a778f6..00000000000000 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowHigh.Vector128.UInt64.cs +++ /dev/null @@ -1,537 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/****************************************************************************** - * This file is auto-generated from a template file by the GenerateTests.csx * - * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * - * changes, please update the corresponding template and run according to the * - * directions listed in the file. * - ******************************************************************************/ - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; - -namespace JIT.HardwareIntrinsics.Arm -{ - public static partial class Program - { - private static void ExtractAndNarrowHigh_Vector128_UInt64() - { - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt64(); - - if (test.IsSupported) - { - // Validates basic functionality works, using Unsafe.Read - test.RunBasicScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates basic functionality works, using Load - test.RunBasicScenario_Load(); - } - - // Validates calling via reflection works, using Unsafe.Read - test.RunReflectionScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates calling via reflection works, using Load - test.RunReflectionScenario_Load(); - } - - // Validates passing a static member works - test.RunClsVarScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing a static member works, using pinning and Load - test.RunClsVarScenario_Load(); - } - - // Validates passing a local works, using Unsafe.Read - test.RunLclVarScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates passing a local works, using Load - test.RunLclVarScenario_Load(); - } - - // Validates passing the field of a local class works - test.RunClassLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local class works, using pinning and Load - test.RunClassLclFldScenario_Load(); - } - - // Validates passing an instance member of a class works - test.RunClassFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a class works, using pinning and Load - test.RunClassFldScenario_Load(); - } - - // Validates passing the field of a local struct works - test.RunStructLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local struct works, using pinning and Load - test.RunStructLclFldScenario_Load(); - } - - // Validates passing an instance member of a struct works - test.RunStructFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a struct works, using pinning and Load - test.RunStructFldScenario_Load(); - } - } - else - { - // Validates we throw on unsupported hardware - test.RunUnsupportedScenario(); - } - - if (!test.Succeeded) - { - throw new Exception("One or more scenarios did not complete as expected."); - } - } - } - - public sealed unsafe class SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt64 - { - private struct DataTable - { - private byte[] inArray1; - private byte[] inArray2; - private byte[] outArray; - - private GCHandle inHandle1; - private GCHandle inHandle2; - private GCHandle outHandle; - - private ulong alignment; - - public DataTable(UInt32[] inArray1, UInt64[] inArray2, UInt32[] outArray, int alignment) - { - int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); - int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); - int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); - if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) - { - throw new ArgumentException("Invalid value of alignment"); - } - - this.inArray1 = new byte[alignment * 2]; - this.inArray2 = new byte[alignment * 2]; - this.outArray = new byte[alignment * 2]; - - this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); - this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); - this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); - - this.alignment = (ulong)alignment; - - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); - } - - public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); - public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); - public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); - - public void Dispose() - { - inHandle1.Free(); - inHandle2.Free(); - outHandle.Free(); - } - - private static unsafe void* Align(byte* buffer, ulong expectedAlignment) - { - return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); - } - } - - private struct TestStruct - { - public Vector64 _fld1; - public Vector128 _fld2; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - - return testStruct; - } - - public void RunStructFldScenario(SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt64 testClass) - { - var result = AdvSimd.ExtractAndNarrowHigh(_fld1, _fld2); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); - } - - public void RunStructFldScenario_Load(SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt64 testClass) - { - fixed (Vector64* pFld1 = &_fld1) - fixed (Vector128* pFld2 = &_fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((UInt32*)(pFld1)), - AdvSimd.LoadVector128((UInt64*)(pFld2)) - ); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); - } - } - } - - private static readonly int LargestVectorSize = 16; - - private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); - private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); - private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); - - private static UInt32[] _data1 = new UInt32[Op1ElementCount]; - private static UInt64[] _data2 = new UInt64[Op2ElementCount]; - - private static Vector64 _clsVar1; - private static Vector128 _clsVar2; - - private Vector64 _fld1; - private Vector128 _fld2; - - private DataTable _dataTable; - - static SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt64() - { - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - } - - public SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt64() - { - Succeeded = true; - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } - for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } - _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); - } - - public bool IsSupported => AdvSimd.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = AdvSimd.ExtractAndNarrowHigh( - Unsafe.Read>(_dataTable.inArray1Ptr), - Unsafe.Read>(_dataTable.inArray2Ptr) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunBasicScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); - - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), - AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowHigh), new Type[] { typeof(Vector64), typeof(Vector128) }) - .Invoke(null, new object[] { - Unsafe.Read>(_dataTable.inArray1Ptr), - Unsafe.Read>(_dataTable.inArray2Ptr) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowHigh), new Type[] { typeof(Vector64), typeof(Vector128) }) - .Invoke(null, new object[] { - AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), - AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = AdvSimd.ExtractAndNarrowHigh( - _clsVar1, - _clsVar2 - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); - - fixed (Vector64* pClsVar1 = &_clsVar1) - fixed (Vector128* pClsVar2 = &_clsVar2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((UInt32*)(pClsVar1)), - AdvSimd.LoadVector128((UInt64*)(pClsVar2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); - } - } - - public void RunLclVarScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); - - var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); - var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); - var result = AdvSimd.ExtractAndNarrowHigh(op1, op2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, op2, _dataTable.outArrayPtr); - } - - public void RunLclVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); - - var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); - var op2 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); - var result = AdvSimd.ExtractAndNarrowHigh(op1, op2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, op2, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt64(); - var result = AdvSimd.ExtractAndNarrowHigh(test._fld1, test._fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); - - var test = new SimpleBinaryOpTest__ExtractAndNarrowHigh_Vector128_UInt64(); - - fixed (Vector64* pFld1 = &test._fld1) - fixed (Vector128* pFld2 = &test._fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((UInt32*)(pFld1)), - AdvSimd.LoadVector128((UInt64*)(pFld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = AdvSimd.ExtractAndNarrowHigh(_fld1, _fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); - } - - public void RunClassFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); - - fixed (Vector64* pFld1 = &_fld1) - fixed (Vector128* pFld2 = &_fld2) - { - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((UInt32*)(pFld1)), - AdvSimd.LoadVector128((UInt64*)(pFld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); - } - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowHigh(test._fld1, test._fld2); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunStructLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowHigh( - AdvSimd.LoadVector64((UInt32*)(&test._fld1)), - AdvSimd.LoadVector128((UInt64*)(&test._fld2)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); - } - - public void RunStructFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); - - var test = TestStruct.Create(); - test.RunStructFldScenario(this); - } - - public void RunStructFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); - - var test = TestStruct.Create(); - test.RunStructFldScenario_Load(this); - } - - public void RunUnsupportedScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); - - bool succeeded = false; - - try - { - RunBasicScenario_UnsafeRead(); - } - catch (PlatformNotSupportedException) - { - succeeded = true; - } - - if (!succeeded) - { - Succeeded = false; - } - } - - private void ValidateResult(Vector64 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") - { - UInt32[] inArray1 = new UInt32[Op1ElementCount]; - UInt64[] inArray2 = new UInt64[Op2ElementCount]; - UInt32[] outArray = new UInt32[RetElementCount]; - - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, inArray2, outArray, method); - } - - private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") - { - UInt32[] inArray1 = new UInt32[Op1ElementCount]; - UInt64[] inArray2 = new UInt64[Op2ElementCount]; - UInt32[] outArray = new UInt32[RetElementCount]; - - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, inArray2, outArray, method); - } - - private void ValidateResult(UInt32[] left, UInt64[] right, UInt32[] result, [CallerMemberName] string method = "") - { - bool succeeded = true; - - if (Helpers.ExtractAndNarrowHigh(0, left, right, result)) - { - succeeded = false; - } - else - { - for (var i = 1; i < RetElementCount; i++) - { - if (Helpers.ExtractAndNarrowHigh(i, left, right, result)) - { - succeeded = false; - break; - } - } - } - - if (!succeeded) - { - TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractAndNarrowHigh)}(Vector64, Vector128): {method} failed:"); - TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); - TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); - TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.Int16.cs deleted file mode 100644 index 86ebd70207fda5..00000000000000 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.Int16.cs +++ /dev/null @@ -1,489 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/****************************************************************************** - * This file is auto-generated from a template file by the GenerateTests.csx * - * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * - * changes, please update the corresponding template and run according to the * - * directions listed in the file. * - ******************************************************************************/ - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; - -namespace JIT.HardwareIntrinsics.Arm -{ - public static partial class Program - { - private static void ExtractAndNarrowLow_Vector128_Int16() - { - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int16(); - - if (test.IsSupported) - { - // Validates basic functionality works, using Unsafe.Read - test.RunBasicScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates basic functionality works, using Load - test.RunBasicScenario_Load(); - } - - // Validates calling via reflection works, using Unsafe.Read - test.RunReflectionScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates calling via reflection works, using Load - test.RunReflectionScenario_Load(); - } - - // Validates passing a static member works - test.RunClsVarScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing a static member works, using pinning and Load - test.RunClsVarScenario_Load(); - } - - // Validates passing a local works, using Unsafe.Read - test.RunLclVarScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates passing a local works, using Load - test.RunLclVarScenario_Load(); - } - - // Validates passing the field of a local class works - test.RunClassLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local class works, using pinning and Load - test.RunClassLclFldScenario_Load(); - } - - // Validates passing an instance member of a class works - test.RunClassFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a class works, using pinning and Load - test.RunClassFldScenario_Load(); - } - - // Validates passing the field of a local struct works - test.RunStructLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local struct works, using pinning and Load - test.RunStructLclFldScenario_Load(); - } - - // Validates passing an instance member of a struct works - test.RunStructFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a struct works, using pinning and Load - test.RunStructFldScenario_Load(); - } - } - else - { - // Validates we throw on unsupported hardware - test.RunUnsupportedScenario(); - } - - if (!test.Succeeded) - { - throw new Exception("One or more scenarios did not complete as expected."); - } - } - } - - public sealed unsafe class SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int16 - { - private struct DataTable - { - private byte[] inArray1; - private byte[] outArray; - - private GCHandle inHandle1; - private GCHandle outHandle; - - private ulong alignment; - - public DataTable(Int16[] inArray1, SByte[] outArray, int alignment) - { - int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); - int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); - if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) - { - throw new ArgumentException("Invalid value of alignment"); - } - - this.inArray1 = new byte[alignment * 2]; - this.outArray = new byte[alignment * 2]; - - this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); - this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); - - this.alignment = (ulong)alignment; - - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); - } - - public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); - public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); - - public void Dispose() - { - inHandle1.Free(); - outHandle.Free(); - } - - private static unsafe void* Align(byte* buffer, ulong expectedAlignment) - { - return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); - } - } - - private struct TestStruct - { - public Vector128 _fld1; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - - return testStruct; - } - - public void RunStructFldScenario(SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int16 testClass) - { - var result = AdvSimd.ExtractAndNarrowLow(_fld1); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); - } - - public void RunStructFldScenario_Load(SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int16 testClass) - { - fixed (Vector128* pFld1 = &_fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int16*)(pFld1)) - ); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); - } - } - } - - private static readonly int LargestVectorSize = 16; - - private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); - private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); - - private static Int16[] _data1 = new Int16[Op1ElementCount]; - - private static Vector128 _clsVar1; - - private Vector128 _fld1; - - private DataTable _dataTable; - - static SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int16() - { - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - } - - public SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int16() - { - Succeeded = true; - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } - _dataTable = new DataTable(_data1, new SByte[RetElementCount], LargestVectorSize); - } - - public bool IsSupported => AdvSimd.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = AdvSimd.ExtractAndNarrowLow( - Unsafe.Read>(_dataTable.inArray1Ptr) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunBasicScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); - - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowLow), new Type[] { typeof(Vector128) }) - .Invoke(null, new object[] { - Unsafe.Read>(_dataTable.inArray1Ptr) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowLow), new Type[] { typeof(Vector128) }) - .Invoke(null, new object[] { - AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = AdvSimd.ExtractAndNarrowLow( - _clsVar1 - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); - - fixed (Vector128* pClsVar1 = &_clsVar1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int16*)(pClsVar1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _dataTable.outArrayPtr); - } - } - - public void RunLclVarScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); - - var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); - var result = AdvSimd.ExtractAndNarrowLow(op1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, _dataTable.outArrayPtr); - } - - public void RunLclVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); - - var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); - var result = AdvSimd.ExtractAndNarrowLow(op1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int16(); - var result = AdvSimd.ExtractAndNarrowLow(test._fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); - - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int16(); - - fixed (Vector128* pFld1 = &test._fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int16*)(pFld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = AdvSimd.ExtractAndNarrowLow(_fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _dataTable.outArrayPtr); - } - - public void RunClassFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); - - fixed (Vector128* pFld1 = &_fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int16*)(pFld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _dataTable.outArrayPtr); - } - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowLow(test._fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunStructLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int16*)(&test._fld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunStructFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); - - var test = TestStruct.Create(); - test.RunStructFldScenario(this); - } - - public void RunStructFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); - - var test = TestStruct.Create(); - test.RunStructFldScenario_Load(this); - } - - public void RunUnsupportedScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); - - bool succeeded = false; - - try - { - RunBasicScenario_UnsafeRead(); - } - catch (PlatformNotSupportedException) - { - succeeded = true; - } - - if (!succeeded) - { - Succeeded = false; - } - } - - private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") - { - Int16[] inArray1 = new Int16[Op1ElementCount]; - SByte[] outArray = new SByte[RetElementCount]; - - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, outArray, method); - } - - private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") - { - Int16[] inArray1 = new Int16[Op1ElementCount]; - SByte[] outArray = new SByte[RetElementCount]; - - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, outArray, method); - } - - private void ValidateResult(Int16[] firstOp, SByte[] result, [CallerMemberName] string method = "") - { - bool succeeded = true; - - for (var i = 0; i < RetElementCount; i++) - { - if (((SByte)firstOp[i]) != result[i]) - { - succeeded = false; - break; - } - } - - if (!succeeded) - { - TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractAndNarrowLow)}(Vector128): {method} failed:"); - TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); - TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.Int32.cs deleted file mode 100644 index b7184d0e1edfcf..00000000000000 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.Int32.cs +++ /dev/null @@ -1,489 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/****************************************************************************** - * This file is auto-generated from a template file by the GenerateTests.csx * - * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * - * changes, please update the corresponding template and run according to the * - * directions listed in the file. * - ******************************************************************************/ - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; - -namespace JIT.HardwareIntrinsics.Arm -{ - public static partial class Program - { - private static void ExtractAndNarrowLow_Vector128_Int32() - { - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int32(); - - if (test.IsSupported) - { - // Validates basic functionality works, using Unsafe.Read - test.RunBasicScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates basic functionality works, using Load - test.RunBasicScenario_Load(); - } - - // Validates calling via reflection works, using Unsafe.Read - test.RunReflectionScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates calling via reflection works, using Load - test.RunReflectionScenario_Load(); - } - - // Validates passing a static member works - test.RunClsVarScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing a static member works, using pinning and Load - test.RunClsVarScenario_Load(); - } - - // Validates passing a local works, using Unsafe.Read - test.RunLclVarScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates passing a local works, using Load - test.RunLclVarScenario_Load(); - } - - // Validates passing the field of a local class works - test.RunClassLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local class works, using pinning and Load - test.RunClassLclFldScenario_Load(); - } - - // Validates passing an instance member of a class works - test.RunClassFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a class works, using pinning and Load - test.RunClassFldScenario_Load(); - } - - // Validates passing the field of a local struct works - test.RunStructLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local struct works, using pinning and Load - test.RunStructLclFldScenario_Load(); - } - - // Validates passing an instance member of a struct works - test.RunStructFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a struct works, using pinning and Load - test.RunStructFldScenario_Load(); - } - } - else - { - // Validates we throw on unsupported hardware - test.RunUnsupportedScenario(); - } - - if (!test.Succeeded) - { - throw new Exception("One or more scenarios did not complete as expected."); - } - } - } - - public sealed unsafe class SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int32 - { - private struct DataTable - { - private byte[] inArray1; - private byte[] outArray; - - private GCHandle inHandle1; - private GCHandle outHandle; - - private ulong alignment; - - public DataTable(Int32[] inArray1, Int16[] outArray, int alignment) - { - int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); - int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); - if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) - { - throw new ArgumentException("Invalid value of alignment"); - } - - this.inArray1 = new byte[alignment * 2]; - this.outArray = new byte[alignment * 2]; - - this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); - this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); - - this.alignment = (ulong)alignment; - - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); - } - - public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); - public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); - - public void Dispose() - { - inHandle1.Free(); - outHandle.Free(); - } - - private static unsafe void* Align(byte* buffer, ulong expectedAlignment) - { - return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); - } - } - - private struct TestStruct - { - public Vector128 _fld1; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - - return testStruct; - } - - public void RunStructFldScenario(SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int32 testClass) - { - var result = AdvSimd.ExtractAndNarrowLow(_fld1); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); - } - - public void RunStructFldScenario_Load(SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int32 testClass) - { - fixed (Vector128* pFld1 = &_fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int32*)(pFld1)) - ); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); - } - } - } - - private static readonly int LargestVectorSize = 16; - - private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); - private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); - - private static Int32[] _data1 = new Int32[Op1ElementCount]; - - private static Vector128 _clsVar1; - - private Vector128 _fld1; - - private DataTable _dataTable; - - static SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int32() - { - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - } - - public SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int32() - { - Succeeded = true; - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } - _dataTable = new DataTable(_data1, new Int16[RetElementCount], LargestVectorSize); - } - - public bool IsSupported => AdvSimd.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = AdvSimd.ExtractAndNarrowLow( - Unsafe.Read>(_dataTable.inArray1Ptr) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunBasicScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); - - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowLow), new Type[] { typeof(Vector128) }) - .Invoke(null, new object[] { - Unsafe.Read>(_dataTable.inArray1Ptr) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowLow), new Type[] { typeof(Vector128) }) - .Invoke(null, new object[] { - AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = AdvSimd.ExtractAndNarrowLow( - _clsVar1 - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); - - fixed (Vector128* pClsVar1 = &_clsVar1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int32*)(pClsVar1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _dataTable.outArrayPtr); - } - } - - public void RunLclVarScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); - - var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); - var result = AdvSimd.ExtractAndNarrowLow(op1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, _dataTable.outArrayPtr); - } - - public void RunLclVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); - - var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); - var result = AdvSimd.ExtractAndNarrowLow(op1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int32(); - var result = AdvSimd.ExtractAndNarrowLow(test._fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); - - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int32(); - - fixed (Vector128* pFld1 = &test._fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int32*)(pFld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = AdvSimd.ExtractAndNarrowLow(_fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _dataTable.outArrayPtr); - } - - public void RunClassFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); - - fixed (Vector128* pFld1 = &_fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int32*)(pFld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _dataTable.outArrayPtr); - } - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowLow(test._fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunStructLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int32*)(&test._fld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunStructFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); - - var test = TestStruct.Create(); - test.RunStructFldScenario(this); - } - - public void RunStructFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); - - var test = TestStruct.Create(); - test.RunStructFldScenario_Load(this); - } - - public void RunUnsupportedScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); - - bool succeeded = false; - - try - { - RunBasicScenario_UnsafeRead(); - } - catch (PlatformNotSupportedException) - { - succeeded = true; - } - - if (!succeeded) - { - Succeeded = false; - } - } - - private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") - { - Int32[] inArray1 = new Int32[Op1ElementCount]; - Int16[] outArray = new Int16[RetElementCount]; - - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, outArray, method); - } - - private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") - { - Int32[] inArray1 = new Int32[Op1ElementCount]; - Int16[] outArray = new Int16[RetElementCount]; - - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, outArray, method); - } - - private void ValidateResult(Int32[] firstOp, Int16[] result, [CallerMemberName] string method = "") - { - bool succeeded = true; - - for (var i = 0; i < RetElementCount; i++) - { - if (((Int16)firstOp[i]) != result[i]) - { - succeeded = false; - break; - } - } - - if (!succeeded) - { - TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractAndNarrowLow)}(Vector128): {method} failed:"); - TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); - TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.Int64.cs deleted file mode 100644 index 3e74619f8c4a22..00000000000000 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.Int64.cs +++ /dev/null @@ -1,489 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/****************************************************************************** - * This file is auto-generated from a template file by the GenerateTests.csx * - * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * - * changes, please update the corresponding template and run according to the * - * directions listed in the file. * - ******************************************************************************/ - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; - -namespace JIT.HardwareIntrinsics.Arm -{ - public static partial class Program - { - private static void ExtractAndNarrowLow_Vector128_Int64() - { - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int64(); - - if (test.IsSupported) - { - // Validates basic functionality works, using Unsafe.Read - test.RunBasicScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates basic functionality works, using Load - test.RunBasicScenario_Load(); - } - - // Validates calling via reflection works, using Unsafe.Read - test.RunReflectionScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates calling via reflection works, using Load - test.RunReflectionScenario_Load(); - } - - // Validates passing a static member works - test.RunClsVarScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing a static member works, using pinning and Load - test.RunClsVarScenario_Load(); - } - - // Validates passing a local works, using Unsafe.Read - test.RunLclVarScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates passing a local works, using Load - test.RunLclVarScenario_Load(); - } - - // Validates passing the field of a local class works - test.RunClassLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local class works, using pinning and Load - test.RunClassLclFldScenario_Load(); - } - - // Validates passing an instance member of a class works - test.RunClassFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a class works, using pinning and Load - test.RunClassFldScenario_Load(); - } - - // Validates passing the field of a local struct works - test.RunStructLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local struct works, using pinning and Load - test.RunStructLclFldScenario_Load(); - } - - // Validates passing an instance member of a struct works - test.RunStructFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a struct works, using pinning and Load - test.RunStructFldScenario_Load(); - } - } - else - { - // Validates we throw on unsupported hardware - test.RunUnsupportedScenario(); - } - - if (!test.Succeeded) - { - throw new Exception("One or more scenarios did not complete as expected."); - } - } - } - - public sealed unsafe class SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int64 - { - private struct DataTable - { - private byte[] inArray1; - private byte[] outArray; - - private GCHandle inHandle1; - private GCHandle outHandle; - - private ulong alignment; - - public DataTable(Int64[] inArray1, Int32[] outArray, int alignment) - { - int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); - int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); - if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) - { - throw new ArgumentException("Invalid value of alignment"); - } - - this.inArray1 = new byte[alignment * 2]; - this.outArray = new byte[alignment * 2]; - - this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); - this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); - - this.alignment = (ulong)alignment; - - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); - } - - public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); - public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); - - public void Dispose() - { - inHandle1.Free(); - outHandle.Free(); - } - - private static unsafe void* Align(byte* buffer, ulong expectedAlignment) - { - return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); - } - } - - private struct TestStruct - { - public Vector128 _fld1; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - - return testStruct; - } - - public void RunStructFldScenario(SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int64 testClass) - { - var result = AdvSimd.ExtractAndNarrowLow(_fld1); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); - } - - public void RunStructFldScenario_Load(SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int64 testClass) - { - fixed (Vector128* pFld1 = &_fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int64*)(pFld1)) - ); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); - } - } - } - - private static readonly int LargestVectorSize = 16; - - private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); - private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); - - private static Int64[] _data1 = new Int64[Op1ElementCount]; - - private static Vector128 _clsVar1; - - private Vector128 _fld1; - - private DataTable _dataTable; - - static SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int64() - { - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - } - - public SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int64() - { - Succeeded = true; - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } - _dataTable = new DataTable(_data1, new Int32[RetElementCount], LargestVectorSize); - } - - public bool IsSupported => AdvSimd.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = AdvSimd.ExtractAndNarrowLow( - Unsafe.Read>(_dataTable.inArray1Ptr) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunBasicScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); - - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowLow), new Type[] { typeof(Vector128) }) - .Invoke(null, new object[] { - Unsafe.Read>(_dataTable.inArray1Ptr) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowLow), new Type[] { typeof(Vector128) }) - .Invoke(null, new object[] { - AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = AdvSimd.ExtractAndNarrowLow( - _clsVar1 - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); - - fixed (Vector128* pClsVar1 = &_clsVar1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int64*)(pClsVar1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _dataTable.outArrayPtr); - } - } - - public void RunLclVarScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); - - var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); - var result = AdvSimd.ExtractAndNarrowLow(op1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, _dataTable.outArrayPtr); - } - - public void RunLclVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); - - var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); - var result = AdvSimd.ExtractAndNarrowLow(op1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int64(); - var result = AdvSimd.ExtractAndNarrowLow(test._fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); - - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_Int64(); - - fixed (Vector128* pFld1 = &test._fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int64*)(pFld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = AdvSimd.ExtractAndNarrowLow(_fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _dataTable.outArrayPtr); - } - - public void RunClassFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); - - fixed (Vector128* pFld1 = &_fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int64*)(pFld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _dataTable.outArrayPtr); - } - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowLow(test._fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunStructLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((Int64*)(&test._fld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunStructFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); - - var test = TestStruct.Create(); - test.RunStructFldScenario(this); - } - - public void RunStructFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); - - var test = TestStruct.Create(); - test.RunStructFldScenario_Load(this); - } - - public void RunUnsupportedScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); - - bool succeeded = false; - - try - { - RunBasicScenario_UnsafeRead(); - } - catch (PlatformNotSupportedException) - { - succeeded = true; - } - - if (!succeeded) - { - Succeeded = false; - } - } - - private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") - { - Int64[] inArray1 = new Int64[Op1ElementCount]; - Int32[] outArray = new Int32[RetElementCount]; - - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, outArray, method); - } - - private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") - { - Int64[] inArray1 = new Int64[Op1ElementCount]; - Int32[] outArray = new Int32[RetElementCount]; - - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, outArray, method); - } - - private void ValidateResult(Int64[] firstOp, Int32[] result, [CallerMemberName] string method = "") - { - bool succeeded = true; - - for (var i = 0; i < RetElementCount; i++) - { - if (((Int32)firstOp[i]) != result[i]) - { - succeeded = false; - break; - } - } - - if (!succeeded) - { - TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractAndNarrowLow)}(Vector128): {method} failed:"); - TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); - TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.UInt16.cs deleted file mode 100644 index b57d6294cbd883..00000000000000 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.UInt16.cs +++ /dev/null @@ -1,489 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/****************************************************************************** - * This file is auto-generated from a template file by the GenerateTests.csx * - * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * - * changes, please update the corresponding template and run according to the * - * directions listed in the file. * - ******************************************************************************/ - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; - -namespace JIT.HardwareIntrinsics.Arm -{ - public static partial class Program - { - private static void ExtractAndNarrowLow_Vector128_UInt16() - { - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt16(); - - if (test.IsSupported) - { - // Validates basic functionality works, using Unsafe.Read - test.RunBasicScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates basic functionality works, using Load - test.RunBasicScenario_Load(); - } - - // Validates calling via reflection works, using Unsafe.Read - test.RunReflectionScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates calling via reflection works, using Load - test.RunReflectionScenario_Load(); - } - - // Validates passing a static member works - test.RunClsVarScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing a static member works, using pinning and Load - test.RunClsVarScenario_Load(); - } - - // Validates passing a local works, using Unsafe.Read - test.RunLclVarScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates passing a local works, using Load - test.RunLclVarScenario_Load(); - } - - // Validates passing the field of a local class works - test.RunClassLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local class works, using pinning and Load - test.RunClassLclFldScenario_Load(); - } - - // Validates passing an instance member of a class works - test.RunClassFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a class works, using pinning and Load - test.RunClassFldScenario_Load(); - } - - // Validates passing the field of a local struct works - test.RunStructLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local struct works, using pinning and Load - test.RunStructLclFldScenario_Load(); - } - - // Validates passing an instance member of a struct works - test.RunStructFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a struct works, using pinning and Load - test.RunStructFldScenario_Load(); - } - } - else - { - // Validates we throw on unsupported hardware - test.RunUnsupportedScenario(); - } - - if (!test.Succeeded) - { - throw new Exception("One or more scenarios did not complete as expected."); - } - } - } - - public sealed unsafe class SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt16 - { - private struct DataTable - { - private byte[] inArray1; - private byte[] outArray; - - private GCHandle inHandle1; - private GCHandle outHandle; - - private ulong alignment; - - public DataTable(UInt16[] inArray1, Byte[] outArray, int alignment) - { - int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); - int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); - if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) - { - throw new ArgumentException("Invalid value of alignment"); - } - - this.inArray1 = new byte[alignment * 2]; - this.outArray = new byte[alignment * 2]; - - this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); - this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); - - this.alignment = (ulong)alignment; - - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); - } - - public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); - public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); - - public void Dispose() - { - inHandle1.Free(); - outHandle.Free(); - } - - private static unsafe void* Align(byte* buffer, ulong expectedAlignment) - { - return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); - } - } - - private struct TestStruct - { - public Vector128 _fld1; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - - return testStruct; - } - - public void RunStructFldScenario(SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt16 testClass) - { - var result = AdvSimd.ExtractAndNarrowLow(_fld1); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); - } - - public void RunStructFldScenario_Load(SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt16 testClass) - { - fixed (Vector128* pFld1 = &_fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt16*)(pFld1)) - ); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); - } - } - } - - private static readonly int LargestVectorSize = 16; - - private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); - private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); - - private static UInt16[] _data1 = new UInt16[Op1ElementCount]; - - private static Vector128 _clsVar1; - - private Vector128 _fld1; - - private DataTable _dataTable; - - static SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt16() - { - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - } - - public SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt16() - { - Succeeded = true; - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } - _dataTable = new DataTable(_data1, new Byte[RetElementCount], LargestVectorSize); - } - - public bool IsSupported => AdvSimd.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = AdvSimd.ExtractAndNarrowLow( - Unsafe.Read>(_dataTable.inArray1Ptr) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunBasicScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); - - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowLow), new Type[] { typeof(Vector128) }) - .Invoke(null, new object[] { - Unsafe.Read>(_dataTable.inArray1Ptr) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowLow), new Type[] { typeof(Vector128) }) - .Invoke(null, new object[] { - AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = AdvSimd.ExtractAndNarrowLow( - _clsVar1 - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); - - fixed (Vector128* pClsVar1 = &_clsVar1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt16*)(pClsVar1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _dataTable.outArrayPtr); - } - } - - public void RunLclVarScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); - - var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); - var result = AdvSimd.ExtractAndNarrowLow(op1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, _dataTable.outArrayPtr); - } - - public void RunLclVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); - - var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); - var result = AdvSimd.ExtractAndNarrowLow(op1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt16(); - var result = AdvSimd.ExtractAndNarrowLow(test._fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); - - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt16(); - - fixed (Vector128* pFld1 = &test._fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt16*)(pFld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = AdvSimd.ExtractAndNarrowLow(_fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _dataTable.outArrayPtr); - } - - public void RunClassFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); - - fixed (Vector128* pFld1 = &_fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt16*)(pFld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _dataTable.outArrayPtr); - } - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowLow(test._fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunStructLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt16*)(&test._fld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunStructFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); - - var test = TestStruct.Create(); - test.RunStructFldScenario(this); - } - - public void RunStructFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); - - var test = TestStruct.Create(); - test.RunStructFldScenario_Load(this); - } - - public void RunUnsupportedScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); - - bool succeeded = false; - - try - { - RunBasicScenario_UnsafeRead(); - } - catch (PlatformNotSupportedException) - { - succeeded = true; - } - - if (!succeeded) - { - Succeeded = false; - } - } - - private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") - { - UInt16[] inArray1 = new UInt16[Op1ElementCount]; - Byte[] outArray = new Byte[RetElementCount]; - - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, outArray, method); - } - - private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") - { - UInt16[] inArray1 = new UInt16[Op1ElementCount]; - Byte[] outArray = new Byte[RetElementCount]; - - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, outArray, method); - } - - private void ValidateResult(UInt16[] firstOp, Byte[] result, [CallerMemberName] string method = "") - { - bool succeeded = true; - - for (var i = 0; i < RetElementCount; i++) - { - if (((Byte)firstOp[i]) != result[i]) - { - succeeded = false; - break; - } - } - - if (!succeeded) - { - TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractAndNarrowLow)}(Vector128): {method} failed:"); - TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); - TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.UInt32.cs deleted file mode 100644 index a5cce409add8c5..00000000000000 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.UInt32.cs +++ /dev/null @@ -1,489 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/****************************************************************************** - * This file is auto-generated from a template file by the GenerateTests.csx * - * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * - * changes, please update the corresponding template and run according to the * - * directions listed in the file. * - ******************************************************************************/ - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; - -namespace JIT.HardwareIntrinsics.Arm -{ - public static partial class Program - { - private static void ExtractAndNarrowLow_Vector128_UInt32() - { - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt32(); - - if (test.IsSupported) - { - // Validates basic functionality works, using Unsafe.Read - test.RunBasicScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates basic functionality works, using Load - test.RunBasicScenario_Load(); - } - - // Validates calling via reflection works, using Unsafe.Read - test.RunReflectionScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates calling via reflection works, using Load - test.RunReflectionScenario_Load(); - } - - // Validates passing a static member works - test.RunClsVarScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing a static member works, using pinning and Load - test.RunClsVarScenario_Load(); - } - - // Validates passing a local works, using Unsafe.Read - test.RunLclVarScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates passing a local works, using Load - test.RunLclVarScenario_Load(); - } - - // Validates passing the field of a local class works - test.RunClassLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local class works, using pinning and Load - test.RunClassLclFldScenario_Load(); - } - - // Validates passing an instance member of a class works - test.RunClassFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a class works, using pinning and Load - test.RunClassFldScenario_Load(); - } - - // Validates passing the field of a local struct works - test.RunStructLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local struct works, using pinning and Load - test.RunStructLclFldScenario_Load(); - } - - // Validates passing an instance member of a struct works - test.RunStructFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a struct works, using pinning and Load - test.RunStructFldScenario_Load(); - } - } - else - { - // Validates we throw on unsupported hardware - test.RunUnsupportedScenario(); - } - - if (!test.Succeeded) - { - throw new Exception("One or more scenarios did not complete as expected."); - } - } - } - - public sealed unsafe class SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt32 - { - private struct DataTable - { - private byte[] inArray1; - private byte[] outArray; - - private GCHandle inHandle1; - private GCHandle outHandle; - - private ulong alignment; - - public DataTable(UInt32[] inArray1, UInt16[] outArray, int alignment) - { - int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); - int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); - if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) - { - throw new ArgumentException("Invalid value of alignment"); - } - - this.inArray1 = new byte[alignment * 2]; - this.outArray = new byte[alignment * 2]; - - this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); - this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); - - this.alignment = (ulong)alignment; - - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); - } - - public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); - public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); - - public void Dispose() - { - inHandle1.Free(); - outHandle.Free(); - } - - private static unsafe void* Align(byte* buffer, ulong expectedAlignment) - { - return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); - } - } - - private struct TestStruct - { - public Vector128 _fld1; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - - return testStruct; - } - - public void RunStructFldScenario(SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt32 testClass) - { - var result = AdvSimd.ExtractAndNarrowLow(_fld1); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); - } - - public void RunStructFldScenario_Load(SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt32 testClass) - { - fixed (Vector128* pFld1 = &_fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt32*)(pFld1)) - ); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); - } - } - } - - private static readonly int LargestVectorSize = 16; - - private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); - private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); - - private static UInt32[] _data1 = new UInt32[Op1ElementCount]; - - private static Vector128 _clsVar1; - - private Vector128 _fld1; - - private DataTable _dataTable; - - static SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt32() - { - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - } - - public SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt32() - { - Succeeded = true; - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } - _dataTable = new DataTable(_data1, new UInt16[RetElementCount], LargestVectorSize); - } - - public bool IsSupported => AdvSimd.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = AdvSimd.ExtractAndNarrowLow( - Unsafe.Read>(_dataTable.inArray1Ptr) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunBasicScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); - - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowLow), new Type[] { typeof(Vector128) }) - .Invoke(null, new object[] { - Unsafe.Read>(_dataTable.inArray1Ptr) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowLow), new Type[] { typeof(Vector128) }) - .Invoke(null, new object[] { - AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = AdvSimd.ExtractAndNarrowLow( - _clsVar1 - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); - - fixed (Vector128* pClsVar1 = &_clsVar1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt32*)(pClsVar1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _dataTable.outArrayPtr); - } - } - - public void RunLclVarScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); - - var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); - var result = AdvSimd.ExtractAndNarrowLow(op1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, _dataTable.outArrayPtr); - } - - public void RunLclVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); - - var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); - var result = AdvSimd.ExtractAndNarrowLow(op1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt32(); - var result = AdvSimd.ExtractAndNarrowLow(test._fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); - - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt32(); - - fixed (Vector128* pFld1 = &test._fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt32*)(pFld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = AdvSimd.ExtractAndNarrowLow(_fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _dataTable.outArrayPtr); - } - - public void RunClassFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); - - fixed (Vector128* pFld1 = &_fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt32*)(pFld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _dataTable.outArrayPtr); - } - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowLow(test._fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunStructLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt32*)(&test._fld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunStructFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); - - var test = TestStruct.Create(); - test.RunStructFldScenario(this); - } - - public void RunStructFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); - - var test = TestStruct.Create(); - test.RunStructFldScenario_Load(this); - } - - public void RunUnsupportedScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); - - bool succeeded = false; - - try - { - RunBasicScenario_UnsafeRead(); - } - catch (PlatformNotSupportedException) - { - succeeded = true; - } - - if (!succeeded) - { - Succeeded = false; - } - } - - private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") - { - UInt32[] inArray1 = new UInt32[Op1ElementCount]; - UInt16[] outArray = new UInt16[RetElementCount]; - - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, outArray, method); - } - - private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") - { - UInt32[] inArray1 = new UInt32[Op1ElementCount]; - UInt16[] outArray = new UInt16[RetElementCount]; - - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, outArray, method); - } - - private void ValidateResult(UInt32[] firstOp, UInt16[] result, [CallerMemberName] string method = "") - { - bool succeeded = true; - - for (var i = 0; i < RetElementCount; i++) - { - if (((UInt16)firstOp[i]) != result[i]) - { - succeeded = false; - break; - } - } - - if (!succeeded) - { - TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractAndNarrowLow)}(Vector128): {method} failed:"); - TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); - TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.UInt64.cs deleted file mode 100644 index 8ff6d29b34c78a..00000000000000 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractAndNarrowLow.Vector128.UInt64.cs +++ /dev/null @@ -1,489 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/****************************************************************************** - * This file is auto-generated from a template file by the GenerateTests.csx * - * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * - * changes, please update the corresponding template and run according to the * - * directions listed in the file. * - ******************************************************************************/ - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; - -namespace JIT.HardwareIntrinsics.Arm -{ - public static partial class Program - { - private static void ExtractAndNarrowLow_Vector128_UInt64() - { - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt64(); - - if (test.IsSupported) - { - // Validates basic functionality works, using Unsafe.Read - test.RunBasicScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates basic functionality works, using Load - test.RunBasicScenario_Load(); - } - - // Validates calling via reflection works, using Unsafe.Read - test.RunReflectionScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates calling via reflection works, using Load - test.RunReflectionScenario_Load(); - } - - // Validates passing a static member works - test.RunClsVarScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing a static member works, using pinning and Load - test.RunClsVarScenario_Load(); - } - - // Validates passing a local works, using Unsafe.Read - test.RunLclVarScenario_UnsafeRead(); - - if (AdvSimd.IsSupported) - { - // Validates passing a local works, using Load - test.RunLclVarScenario_Load(); - } - - // Validates passing the field of a local class works - test.RunClassLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local class works, using pinning and Load - test.RunClassLclFldScenario_Load(); - } - - // Validates passing an instance member of a class works - test.RunClassFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a class works, using pinning and Load - test.RunClassFldScenario_Load(); - } - - // Validates passing the field of a local struct works - test.RunStructLclFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing the field of a local struct works, using pinning and Load - test.RunStructLclFldScenario_Load(); - } - - // Validates passing an instance member of a struct works - test.RunStructFldScenario(); - - if (AdvSimd.IsSupported) - { - // Validates passing an instance member of a struct works, using pinning and Load - test.RunStructFldScenario_Load(); - } - } - else - { - // Validates we throw on unsupported hardware - test.RunUnsupportedScenario(); - } - - if (!test.Succeeded) - { - throw new Exception("One or more scenarios did not complete as expected."); - } - } - } - - public sealed unsafe class SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt64 - { - private struct DataTable - { - private byte[] inArray1; - private byte[] outArray; - - private GCHandle inHandle1; - private GCHandle outHandle; - - private ulong alignment; - - public DataTable(UInt64[] inArray1, UInt32[] outArray, int alignment) - { - int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); - int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); - if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) - { - throw new ArgumentException("Invalid value of alignment"); - } - - this.inArray1 = new byte[alignment * 2]; - this.outArray = new byte[alignment * 2]; - - this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); - this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); - - this.alignment = (ulong)alignment; - - Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); - } - - public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); - public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); - - public void Dispose() - { - inHandle1.Free(); - outHandle.Free(); - } - - private static unsafe void* Align(byte* buffer, ulong expectedAlignment) - { - return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); - } - } - - private struct TestStruct - { - public Vector128 _fld1; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - - return testStruct; - } - - public void RunStructFldScenario(SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt64 testClass) - { - var result = AdvSimd.ExtractAndNarrowLow(_fld1); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); - } - - public void RunStructFldScenario_Load(SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt64 testClass) - { - fixed (Vector128* pFld1 = &_fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt64*)(pFld1)) - ); - - Unsafe.Write(testClass._dataTable.outArrayPtr, result); - testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); - } - } - } - - private static readonly int LargestVectorSize = 16; - - private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); - private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); - - private static UInt64[] _data1 = new UInt64[Op1ElementCount]; - - private static Vector128 _clsVar1; - - private Vector128 _fld1; - - private DataTable _dataTable; - - static SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt64() - { - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - } - - public SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt64() - { - Succeeded = true; - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } - Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); - - for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } - _dataTable = new DataTable(_data1, new UInt32[RetElementCount], LargestVectorSize); - } - - public bool IsSupported => AdvSimd.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = AdvSimd.ExtractAndNarrowLow( - Unsafe.Read>(_dataTable.inArray1Ptr) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunBasicScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); - - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowLow), new Type[] { typeof(Vector128) }) - .Invoke(null, new object[] { - Unsafe.Read>(_dataTable.inArray1Ptr) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunReflectionScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); - - var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractAndNarrowLow), new Type[] { typeof(Vector128) }) - .Invoke(null, new object[] { - AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)) - }); - - Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); - ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = AdvSimd.ExtractAndNarrowLow( - _clsVar1 - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _dataTable.outArrayPtr); - } - - public void RunClsVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); - - fixed (Vector128* pClsVar1 = &_clsVar1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt64*)(pClsVar1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _dataTable.outArrayPtr); - } - } - - public void RunLclVarScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); - - var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); - var result = AdvSimd.ExtractAndNarrowLow(op1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, _dataTable.outArrayPtr); - } - - public void RunLclVarScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); - - var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); - var result = AdvSimd.ExtractAndNarrowLow(op1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(op1, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt64(); - var result = AdvSimd.ExtractAndNarrowLow(test._fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunClassLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); - - var test = new SimpleUnaryOpTest__ExtractAndNarrowLow_Vector128_UInt64(); - - fixed (Vector128* pFld1 = &test._fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt64*)(pFld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = AdvSimd.ExtractAndNarrowLow(_fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _dataTable.outArrayPtr); - } - - public void RunClassFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); - - fixed (Vector128* pFld1 = &_fld1) - { - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt64*)(pFld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _dataTable.outArrayPtr); - } - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowLow(test._fld1); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunStructLclFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); - - var test = TestStruct.Create(); - var result = AdvSimd.ExtractAndNarrowLow( - AdvSimd.LoadVector128((UInt64*)(&test._fld1)) - ); - - Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, _dataTable.outArrayPtr); - } - - public void RunStructFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); - - var test = TestStruct.Create(); - test.RunStructFldScenario(this); - } - - public void RunStructFldScenario_Load() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); - - var test = TestStruct.Create(); - test.RunStructFldScenario_Load(this); - } - - public void RunUnsupportedScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); - - bool succeeded = false; - - try - { - RunBasicScenario_UnsafeRead(); - } - catch (PlatformNotSupportedException) - { - succeeded = true; - } - - if (!succeeded) - { - Succeeded = false; - } - } - - private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") - { - UInt64[] inArray1 = new UInt64[Op1ElementCount]; - UInt32[] outArray = new UInt32[RetElementCount]; - - Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, outArray, method); - } - - private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") - { - UInt64[] inArray1 = new UInt64[Op1ElementCount]; - UInt32[] outArray = new UInt32[RetElementCount]; - - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); - - ValidateResult(inArray1, outArray, method); - } - - private void ValidateResult(UInt64[] firstOp, UInt32[] result, [CallerMemberName] string method = "") - { - bool succeeded = true; - - for (var i = 0; i < RetElementCount; i++) - { - if (((UInt32)firstOp[i]) != result[i]) - { - succeeded = false; - break; - } - } - - if (!succeeded) - { - TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractAndNarrowLow)}(Vector128): {method} failed:"); - TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); - TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.Int16.cs new file mode 100644 index 00000000000000..c6bc0bca5bec58 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.Int16.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractNarrowingLower_Vector128_Int16() + { + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int16 testClass) + { + var result = AdvSimd.ExtractNarrowingLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingLower), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingLower), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractNarrowingLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ExtractNarrowingLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ExtractNarrowingLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int16(); + var result = AdvSimd.ExtractNarrowingLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractNarrowingLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int16*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractNarrowing(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractNarrowingLower)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.Int32.cs new file mode 100644 index 00000000000000..5f7391b3d1655d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.Int32.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractNarrowingLower_Vector128_Int32() + { + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int32 testClass) + { + var result = AdvSimd.ExtractNarrowingLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingLower), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingLower), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractNarrowingLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ExtractNarrowingLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ExtractNarrowingLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int32(); + var result = AdvSimd.ExtractNarrowingLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractNarrowingLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractNarrowing(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractNarrowingLower)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.Int64.cs new file mode 100644 index 00000000000000..b409826445084f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.Int64.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractNarrowingLower_Vector128_Int64() + { + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int64 testClass) + { + var result = AdvSimd.ExtractNarrowingLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingLower), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingLower), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractNarrowingLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ExtractNarrowingLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ExtractNarrowingLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int64(); + var result = AdvSimd.ExtractNarrowingLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractNarrowingLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((Int64*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractNarrowing(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractNarrowingLower)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.UInt16.cs new file mode 100644 index 00000000000000..5c739b97a99412 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.UInt16.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractNarrowingLower_Vector128_UInt16() + { + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt16 testClass) + { + var result = AdvSimd.ExtractNarrowingLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingLower), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingLower), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractNarrowingLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ExtractNarrowingLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ExtractNarrowingLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt16(); + var result = AdvSimd.ExtractNarrowingLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractNarrowingLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractNarrowing(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractNarrowingLower)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.UInt32.cs new file mode 100644 index 00000000000000..8630a333377e47 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.UInt32.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractNarrowingLower_Vector128_UInt32() + { + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt32 testClass) + { + var result = AdvSimd.ExtractNarrowingLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingLower), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingLower), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractNarrowingLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ExtractNarrowingLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ExtractNarrowingLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt32(); + var result = AdvSimd.ExtractNarrowingLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractNarrowingLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractNarrowing(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractNarrowingLower)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.UInt64.cs new file mode 100644 index 00000000000000..84abecc879988c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingLower.Vector128.UInt64.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractNarrowingLower_Vector128_UInt64() + { + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt64 testClass) + { + var result = AdvSimd.ExtractNarrowingLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingLower), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingLower), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractNarrowingLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ExtractNarrowingLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ExtractNarrowingLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt64(); + var result = AdvSimd.ExtractNarrowingLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ExtractNarrowingLower_Vector128_UInt64(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractNarrowingLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractNarrowing(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractNarrowingLower)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.Int16.cs new file mode 100644 index 00000000000000..cc960def9015c3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractNarrowingUpper_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int16 testClass) + { + var result = AdvSimd.ExtractNarrowingUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractNarrowingUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractNarrowingUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractNarrowingUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int16(); + var result = AdvSimd.ExtractNarrowingUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractNarrowingUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, Int16[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractNarrowingUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractNarrowingUpper)}(Vector64, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.Int32.cs new file mode 100644 index 00000000000000..a2add3e2859695 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractNarrowingUpper_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int32 testClass) + { + var result = AdvSimd.ExtractNarrowingUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractNarrowingUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractNarrowingUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractNarrowingUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int32(); + var result = AdvSimd.ExtractNarrowingUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractNarrowingUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int32[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractNarrowingUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractNarrowingUpper)}(Vector64, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.Int64.cs new file mode 100644 index 00000000000000..b5316d0d700de1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.Int64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractNarrowingUpper_Vector128_Int64() + { + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int64 testClass) + { + var result = AdvSimd.ExtractNarrowingUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractNarrowingUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractNarrowingUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractNarrowingUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int64(); + var result = AdvSimd.ExtractNarrowingUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_Int64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractNarrowingUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int64[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractNarrowingUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractNarrowingUpper)}(Vector64, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.UInt16.cs new file mode 100644 index 00000000000000..6d0facc3ea7be6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractNarrowingUpper_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, UInt16[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt16 testClass) + { + var result = AdvSimd.ExtractNarrowingUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractNarrowingUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractNarrowingUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractNarrowingUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt16(); + var result = AdvSimd.ExtractNarrowingUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractNarrowingUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, UInt16[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractNarrowingUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractNarrowingUpper)}(Vector64, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.UInt32.cs new file mode 100644 index 00000000000000..85e46e6aaa8ab6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractNarrowingUpper_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt32[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt32 testClass) + { + var result = AdvSimd.ExtractNarrowingUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractNarrowingUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractNarrowingUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractNarrowingUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt32(); + var result = AdvSimd.ExtractNarrowingUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractNarrowingUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt32[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractNarrowingUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractNarrowingUpper)}(Vector64, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.UInt64.cs new file mode 100644 index 00000000000000..e1606c139aa8b9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractNarrowingUpper.Vector128.UInt64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractNarrowingUpper_Vector128_UInt64() + { + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt64[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt64 testClass) + { + var result = AdvSimd.ExtractNarrowingUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractNarrowingUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractNarrowingUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractNarrowingUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt64(); + var result = AdvSimd.ExtractNarrowingUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ExtractNarrowingUpper_Vector128_UInt64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractNarrowingUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt64[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractNarrowingUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractNarrowingUpper)}(Vector64, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Byte.1.cs new file mode 100644 index 00000000000000..9796b77b586452 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Byte.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector128_Byte_1() + { + var test = new ExtractVectorTest__ExtractVector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector128_Byte_1 testClass) + { + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector128_Byte_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Byte*)pFld1), + AdvSimd.LoadVector128((Byte*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte ElementIndex = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector128( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector128( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector128_Byte_1(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector128_Byte_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Byte*)pFld1), + AdvSimd.LoadVector128((Byte*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Byte*)pFld1), + AdvSimd.LoadVector128((Byte*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] secondOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector128)}(Vector128, Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Double.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Double.1.cs new file mode 100644 index 00000000000000..f6af47e4779a7d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Double.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector128_Double_1() + { + var test = new ExtractVectorTest__ExtractVector128_Double_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector128_Double_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] inArray2, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector128_Double_1 testClass) + { + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector128_Double_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Double*)pFld1), + AdvSimd.LoadVector128((Double*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly byte ElementIndex = 1; + + private static Double[] _data1 = new Double[Op1ElementCount]; + private static Double[] _data2 = new Double[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector128_Double_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector128_Double_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, _data2, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector128( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Double*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Double*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector128( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Double*)(pClsVar1)), + AdvSimd.LoadVector128((Double*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Double*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector128_Double_1(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector128_Double_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Double*)pFld1), + AdvSimd.LoadVector128((Double*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Double*)pFld1), + AdvSimd.LoadVector128((Double*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Double*)(&test._fld1)), + AdvSimd.LoadVector128((Double*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] secondOp, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i)) != BitConverter.DoubleToInt64Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector128)}(Vector128, Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Int16.1.cs new file mode 100644 index 00000000000000..53da831c078573 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Int16.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector128_Int16_1() + { + var test = new ExtractVectorTest__ExtractVector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector128_Int16_1 testClass) + { + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector128_Int16_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int16*)pFld1), + AdvSimd.LoadVector128((Int16*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte ElementIndex = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector128( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector128( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector128_Int16_1(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector128_Int16_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int16*)pFld1), + AdvSimd.LoadVector128((Int16*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int16*)pFld1), + AdvSimd.LoadVector128((Int16*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector128)}(Vector128, Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Int32.1.cs new file mode 100644 index 00000000000000..d5c90412f4a5e9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Int32.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector128_Int32_1() + { + var test = new ExtractVectorTest__ExtractVector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector128_Int32_1 testClass) + { + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector128_Int32_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int32*)pFld1), + AdvSimd.LoadVector128((Int32*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte ElementIndex = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector128( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector128( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector128_Int32_1(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector128_Int32_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int32*)pFld1), + AdvSimd.LoadVector128((Int32*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int32*)pFld1), + AdvSimd.LoadVector128((Int32*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector128)}(Vector128, Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Int64.1.cs new file mode 100644 index 00000000000000..25a5c038150a6d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Int64.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector128_Int64_1() + { + var test = new ExtractVectorTest__ExtractVector128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector128_Int64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector128_Int64_1 testClass) + { + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector128_Int64_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int64*)pFld1), + AdvSimd.LoadVector128((Int64*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte ElementIndex = 1; + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector128( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector128( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector128_Int64_1(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector128_Int64_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int64*)pFld1), + AdvSimd.LoadVector128((Int64*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int64*)pFld1), + AdvSimd.LoadVector128((Int64*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] secondOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector128)}(Vector128, Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.SByte.1.cs new file mode 100644 index 00000000000000..0ac735f5ae66c6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.SByte.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector128_SByte_1() + { + var test = new ExtractVectorTest__ExtractVector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector128_SByte_1 testClass) + { + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector128_SByte_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((SByte*)pFld1), + AdvSimd.LoadVector128((SByte*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte ElementIndex = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector128( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector128( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector128_SByte_1(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector128_SByte_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((SByte*)pFld1), + AdvSimd.LoadVector128((SByte*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((SByte*)pFld1), + AdvSimd.LoadVector128((SByte*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector128)}(Vector128, Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Single.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Single.1.cs new file mode 100644 index 00000000000000..8a497dd8eb3d69 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.Single.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector128_Single_1() + { + var test = new ExtractVectorTest__ExtractVector128_Single_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector128_Single_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] inArray2, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector128_Single_1 testClass) + { + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector128_Single_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Single*)pFld1), + AdvSimd.LoadVector128((Single*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly byte ElementIndex = 1; + + private static Single[] _data1 = new Single[Op1ElementCount]; + private static Single[] _data2 = new Single[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector128_Single_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector128_Single_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, _data2, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector128( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Single*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Single*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector128( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Single*)(pClsVar1)), + AdvSimd.LoadVector128((Single*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector128_Single_1(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector128_Single_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Single*)pFld1), + AdvSimd.LoadVector128((Single*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Single*)pFld1), + AdvSimd.LoadVector128((Single*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((Single*)(&test._fld1)), + AdvSimd.LoadVector128((Single*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] secondOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i)) != BitConverter.SingleToInt32Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector128)}(Vector128, Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.UInt16.1.cs new file mode 100644 index 00000000000000..ca5c15cb5acaf1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.UInt16.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector128_UInt16_1() + { + var test = new ExtractVectorTest__ExtractVector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector128_UInt16_1 testClass) + { + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector128_UInt16_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt16*)pFld1), + AdvSimd.LoadVector128((UInt16*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte ElementIndex = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector128( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector128( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector128_UInt16_1(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector128_UInt16_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt16*)pFld1), + AdvSimd.LoadVector128((UInt16*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt16*)pFld1), + AdvSimd.LoadVector128((UInt16*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] secondOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector128)}(Vector128, Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.UInt32.1.cs new file mode 100644 index 00000000000000..d211563e47fb29 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.UInt32.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector128_UInt32_1() + { + var test = new ExtractVectorTest__ExtractVector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector128_UInt32_1 testClass) + { + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector128_UInt32_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt32*)pFld1), + AdvSimd.LoadVector128((UInt32*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte ElementIndex = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector128( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector128( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector128_UInt32_1(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector128_UInt32_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt32*)pFld1), + AdvSimd.LoadVector128((UInt32*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt32*)pFld1), + AdvSimd.LoadVector128((UInt32*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] secondOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector128)}(Vector128, Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.UInt64.1.cs new file mode 100644 index 00000000000000..9cdaca196e2c6e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector128.UInt64.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector128_UInt64_1() + { + var test = new ExtractVectorTest__ExtractVector128_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector128_UInt64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector128_UInt64_1 testClass) + { + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector128_UInt64_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt64*)pFld1), + AdvSimd.LoadVector128((UInt64*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte ElementIndex = 1; + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector128_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector128_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector128( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector128), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector128( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((UInt64*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector128(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector128_UInt64_1(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector128_UInt64_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt64*)pFld1), + AdvSimd.LoadVector128((UInt64*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector128(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt64*)pFld1), + AdvSimd.LoadVector128((UInt64*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector128( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((UInt64*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] secondOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector128)}(Vector128, Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.Byte.1.cs new file mode 100644 index 00000000000000..e76d228d4625a1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.Byte.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector64_Byte_1() + { + var test = new ExtractVectorTest__ExtractVector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector64_Byte_1 testClass) + { + var result = AdvSimd.ExtractVector64(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector64_Byte_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Byte*)pFld1), + AdvSimd.LoadVector64((Byte*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte ElementIndex = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector64( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector64), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector64), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector64( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector64(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector64(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector64_Byte_1(); + var result = AdvSimd.ExtractVector64(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector64_Byte_1(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Byte*)pFld1), + AdvSimd.LoadVector64((Byte*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector64(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Byte*)pFld1), + AdvSimd.LoadVector64((Byte*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector64(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] secondOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector64)}(Vector64, Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.Int16.1.cs new file mode 100644 index 00000000000000..0ce99717cec789 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.Int16.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector64_Int16_1() + { + var test = new ExtractVectorTest__ExtractVector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector64_Int16_1 testClass) + { + var result = AdvSimd.ExtractVector64(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector64_Int16_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Int16*)pFld1), + AdvSimd.LoadVector64((Int16*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte ElementIndex = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector64( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector64), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector64), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector64( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector64(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector64(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector64_Int16_1(); + var result = AdvSimd.ExtractVector64(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector64_Int16_1(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Int16*)pFld1), + AdvSimd.LoadVector64((Int16*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector64(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Int16*)pFld1), + AdvSimd.LoadVector64((Int16*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector64(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector64)}(Vector64, Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.Int32.1.cs new file mode 100644 index 00000000000000..7b453dc0db7b4b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.Int32.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector64_Int32_1() + { + var test = new ExtractVectorTest__ExtractVector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector64_Int32_1 testClass) + { + var result = AdvSimd.ExtractVector64(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector64_Int32_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Int32*)pFld1), + AdvSimd.LoadVector64((Int32*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte ElementIndex = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector64( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector64), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector64), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector64( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector64(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector64(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector64_Int32_1(); + var result = AdvSimd.ExtractVector64(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector64_Int32_1(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Int32*)pFld1), + AdvSimd.LoadVector64((Int32*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector64(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Int32*)pFld1), + AdvSimd.LoadVector64((Int32*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector64(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector64)}(Vector64, Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.SByte.1.cs new file mode 100644 index 00000000000000..4d9747eefab0d6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.SByte.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector64_SByte_1() + { + var test = new ExtractVectorTest__ExtractVector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector64_SByte_1 testClass) + { + var result = AdvSimd.ExtractVector64(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector64_SByte_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((SByte*)pFld1), + AdvSimd.LoadVector64((SByte*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte ElementIndex = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector64( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector64), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector64), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector64( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector64(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector64(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector64_SByte_1(); + var result = AdvSimd.ExtractVector64(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector64_SByte_1(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((SByte*)pFld1), + AdvSimd.LoadVector64((SByte*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector64(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((SByte*)pFld1), + AdvSimd.LoadVector64((SByte*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector64(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector64)}(Vector64, Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.Single.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.Single.1.cs new file mode 100644 index 00000000000000..a866ed19914688 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.Single.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector64_Single_1() + { + var test = new ExtractVectorTest__ExtractVector64_Single_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector64_Single_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] inArray2, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector64_Single_1 testClass) + { + var result = AdvSimd.ExtractVector64(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector64_Single_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Single*)pFld1), + AdvSimd.LoadVector64((Single*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly byte ElementIndex = 1; + + private static Single[] _data1 = new Single[Op1ElementCount]; + private static Single[] _data2 = new Single[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector64_Single_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector64_Single_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, _data2, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector64( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector64), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector64), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector64( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Single*)(pClsVar1)), + AdvSimd.LoadVector64((Single*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector64(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector64(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector64_Single_1(); + var result = AdvSimd.ExtractVector64(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector64_Single_1(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Single*)pFld1), + AdvSimd.LoadVector64((Single*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector64(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Single*)pFld1), + AdvSimd.LoadVector64((Single*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector64(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((Single*)(&test._fld1)), + AdvSimd.LoadVector64((Single*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] secondOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i)) != BitConverter.SingleToInt32Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector64)}(Vector64, Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.UInt16.1.cs new file mode 100644 index 00000000000000..ed6599ccae3601 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.UInt16.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector64_UInt16_1() + { + var test = new ExtractVectorTest__ExtractVector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector64_UInt16_1 testClass) + { + var result = AdvSimd.ExtractVector64(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector64_UInt16_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((UInt16*)pFld1), + AdvSimd.LoadVector64((UInt16*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte ElementIndex = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector64( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector64), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector64), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector64( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector64(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector64(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector64_UInt16_1(); + var result = AdvSimd.ExtractVector64(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector64_UInt16_1(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((UInt16*)pFld1), + AdvSimd.LoadVector64((UInt16*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector64(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((UInt16*)pFld1), + AdvSimd.LoadVector64((UInt16*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector64(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] secondOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector64)}(Vector64, Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.UInt32.1.cs new file mode 100644 index 00000000000000..434f8bfd4db526 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ExtractVector64.UInt32.1.cs @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ExtractVector64_UInt32_1() + { + var test = new ExtractVectorTest__ExtractVector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__ExtractVector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__ExtractVector64_UInt32_1 testClass) + { + var result = AdvSimd.ExtractVector64(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__ExtractVector64_UInt32_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((UInt32*)pFld1), + AdvSimd.LoadVector64((UInt32*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte ElementIndex = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__ExtractVector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ExtractVectorTest__ExtractVector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ExtractVector64( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector64), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ExtractVector64), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ExtractVector64( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ExtractVector64(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ExtractVector64(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__ExtractVector64_UInt32_1(); + var result = AdvSimd.ExtractVector64(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__ExtractVector64_UInt32_1(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((UInt32*)pFld1), + AdvSimd.LoadVector64((UInt32*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ExtractVector64(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((UInt32*)pFld1), + AdvSimd.LoadVector64((UInt32*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector64(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ExtractVector64( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] secondOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ExtractVector64)}(Vector64, Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.Byte.cs new file mode 100644 index 00000000000000..60c698595c8952 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddHalving_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddHalving_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddHalving_Vector128_Byte testClass) + { + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddHalving_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddHalving_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddHalving_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_Byte(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.Int16.cs new file mode 100644 index 00000000000000..28387e4eeb0468 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddHalving_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddHalving_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddHalving_Vector128_Int16 testClass) + { + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddHalving_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddHalving_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddHalving_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_Int16(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.Int32.cs new file mode 100644 index 00000000000000..d2e61a79f1c6dd --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddHalving_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddHalving_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddHalving_Vector128_Int32 testClass) + { + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddHalving_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddHalving_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddHalving_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_Int32(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.SByte.cs new file mode 100644 index 00000000000000..b9c18f8e424a1e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddHalving_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddHalving_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddHalving_Vector128_SByte testClass) + { + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddHalving_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddHalving_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddHalving_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_SByte(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.UInt16.cs new file mode 100644 index 00000000000000..19fcebeb37b225 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddHalving_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt16 testClass) + { + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt16(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.UInt32.cs new file mode 100644 index 00000000000000..2cdbda6f865bac --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddHalving_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt32 testClass) + { + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt32(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.Byte.cs new file mode 100644 index 00000000000000..69435318da637e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddHalving_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddHalving_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddHalving_Vector64_Byte testClass) + { + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddHalving_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddHalving_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddHalving_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_Byte(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.Int16.cs new file mode 100644 index 00000000000000..4689d711f34a9d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddHalving_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddHalving_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddHalving_Vector64_Int16 testClass) + { + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddHalving_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddHalving_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddHalving_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_Int16(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.Int32.cs new file mode 100644 index 00000000000000..5c261b083e596e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddHalving_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddHalving_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddHalving_Vector64_Int32 testClass) + { + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddHalving_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddHalving_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddHalving_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_Int32(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.SByte.cs new file mode 100644 index 00000000000000..bf7c7187a24ffc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddHalving_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddHalving_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddHalving_Vector64_SByte testClass) + { + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddHalving_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddHalving_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddHalving_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_SByte(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.UInt16.cs new file mode 100644 index 00000000000000..9fb445a2b1d80b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddHalving_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt16 testClass) + { + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt16(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.UInt32.cs new file mode 100644 index 00000000000000..49e70065a547a5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddHalving.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddHalving_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt32 testClass) + { + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt32(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddHalving_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddHalving( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.Byte.cs new file mode 100644 index 00000000000000..87e73d45b4fee0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddRoundedHalving_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Byte testClass) + { + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddRoundedHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddRoundedHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Byte(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddRoundedHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.Int16.cs new file mode 100644 index 00000000000000..2d2bd1e311e195 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddRoundedHalving_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int16 testClass) + { + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddRoundedHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddRoundedHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int16(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddRoundedHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.Int32.cs new file mode 100644 index 00000000000000..318badd836ef57 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddRoundedHalving_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int32 testClass) + { + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddRoundedHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddRoundedHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int32(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddRoundedHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.SByte.cs new file mode 100644 index 00000000000000..f50e45d78ea993 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddRoundedHalving_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_SByte testClass) + { + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddRoundedHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddRoundedHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_SByte(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddRoundedHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.UInt16.cs new file mode 100644 index 00000000000000..21387f41bb4b34 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddRoundedHalving_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt16 testClass) + { + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddRoundedHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddRoundedHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt16(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddRoundedHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.UInt32.cs new file mode 100644 index 00000000000000..79d2bb8244162a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddRoundedHalving_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt32 testClass) + { + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddRoundedHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddRoundedHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt32(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddRoundedHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.Byte.cs new file mode 100644 index 00000000000000..90588a80822e21 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddRoundedHalving_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Byte testClass) + { + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddRoundedHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddRoundedHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Byte(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddRoundedHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.Int16.cs new file mode 100644 index 00000000000000..d5a9410c892e70 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddRoundedHalving_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int16 testClass) + { + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddRoundedHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddRoundedHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int16(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddRoundedHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.Int32.cs new file mode 100644 index 00000000000000..c425c548c433c6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddRoundedHalving_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int32 testClass) + { + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddRoundedHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddRoundedHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int32(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddRoundedHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.SByte.cs new file mode 100644 index 00000000000000..6f064458098cb2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddRoundedHalving_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_SByte testClass) + { + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddRoundedHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddRoundedHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_SByte(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddRoundedHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.UInt16.cs new file mode 100644 index 00000000000000..55e5f39e3fdce4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddRoundedHalving_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt16 testClass) + { + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddRoundedHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddRoundedHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt16(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddRoundedHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.UInt32.cs new file mode 100644 index 00000000000000..0d08da210d6f21 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedAddRoundedHalving.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedAddRoundedHalving_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt32 testClass) + { + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedAddRoundedHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedAddRoundedHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedAddRoundedHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedAddRoundedHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt32(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedAddRoundedHalving_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedAddRoundedHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedAddRoundedHalving( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedAddRoundedHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.Byte.cs new file mode 100644 index 00000000000000..16fb3b31ab298e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedSubtractHalving_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Byte testClass) + { + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedSubtractHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedSubtractHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Byte(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedSubtractHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.Int16.cs new file mode 100644 index 00000000000000..030bcf09b2c5d6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedSubtractHalving_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int16 testClass) + { + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedSubtractHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedSubtractHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int16(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedSubtractHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.Int32.cs new file mode 100644 index 00000000000000..d200aeaafd3079 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedSubtractHalving_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int32 testClass) + { + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedSubtractHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedSubtractHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int32(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedSubtractHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.SByte.cs new file mode 100644 index 00000000000000..f7481d24193563 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedSubtractHalving_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedSubtractHalving_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedSubtractHalving_Vector128_SByte testClass) + { + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedSubtractHalving_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedSubtractHalving_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedSubtractHalving_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedSubtractHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedSubtractHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_SByte(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedSubtractHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.UInt16.cs new file mode 100644 index 00000000000000..e2ea87715a92df --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedSubtractHalving_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt16 testClass) + { + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedSubtractHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedSubtractHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt16(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedSubtractHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.UInt32.cs new file mode 100644 index 00000000000000..540e4558387983 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedSubtractHalving_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt32 testClass) + { + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedSubtractHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedSubtractHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt32(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedSubtractHalving)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.Byte.cs new file mode 100644 index 00000000000000..eb6876245caf8b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedSubtractHalving_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Byte testClass) + { + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedSubtractHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedSubtractHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Byte(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedSubtractHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.Int16.cs new file mode 100644 index 00000000000000..bf207e4a96ccda --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedSubtractHalving_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int16 testClass) + { + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedSubtractHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedSubtractHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int16(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedSubtractHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.Int32.cs new file mode 100644 index 00000000000000..f70c2ccf47ac6b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedSubtractHalving_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int32 testClass) + { + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedSubtractHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedSubtractHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int32(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedSubtractHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.SByte.cs new file mode 100644 index 00000000000000..dc8cf4b67eebb0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedSubtractHalving_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedSubtractHalving_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedSubtractHalving_Vector64_SByte testClass) + { + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedSubtractHalving_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedSubtractHalving_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedSubtractHalving_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedSubtractHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedSubtractHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_SByte(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedSubtractHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.UInt16.cs new file mode 100644 index 00000000000000..ee1e69079bbef2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedSubtractHalving_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt16 testClass) + { + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedSubtractHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedSubtractHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt16(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedSubtractHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.UInt32.cs new file mode 100644 index 00000000000000..c319f5af6930cc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/FusedSubtractHalving.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void FusedSubtractHalving_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt32 testClass) + { + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.FusedSubtractHalving( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.FusedSubtractHalving), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.FusedSubtractHalving( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.FusedSubtractHalving(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt32(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__FusedSubtractHalving_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.FusedSubtractHalving(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.FusedSubtractHalving( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.FusedSubtractHalving)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..35e461b4e2426c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Byte.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector128_Byte_1() + { + var test = new InsertTest__Insert_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Byte _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetByte(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector128_Byte_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector128_Byte_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Byte* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Byte*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte ElementIndex = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar1; + private static Byte _clsVar3; + + private Vector128 _fld1; + private Byte _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetByte(); + } + + public InsertTest__Insert_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetByte(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + Byte op3 = TestLibrary.Generator.GetByte(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(Byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + Byte op3 = TestLibrary.Generator.GetByte(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(Byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Byte* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Byte*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetByte(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetByte(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector128_Byte_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector128_Byte_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Byte* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Byte*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Byte* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Byte*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Byte op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, Byte op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte thirdOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector128, 1, Byte): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Double.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Double.1.cs new file mode 100644 index 00000000000000..fdca1845169cfe --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Double.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector128_Double_1() + { + var test = new InsertTest__Insert_Vector128_Double_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector128_Double_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Double _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetDouble(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector128_Double_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector128_Double_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Double* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Double*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly byte ElementIndex = 1; + + private static Double[] _data1 = new Double[Op1ElementCount]; + + private static Vector128 _clsVar1; + private static Double _clsVar3; + + private Vector128 _fld1; + private Double _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector128_Double_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetDouble(); + } + + public InsertTest__Insert_Vector128_Double_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetDouble(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, new Double[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + Double op3 = TestLibrary.Generator.GetDouble(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(Double) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + Double op3 = TestLibrary.Generator.GetDouble(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(Double) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Double* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Double*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetDouble(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetDouble(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector128_Double_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector128_Double_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Double* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Double*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Double* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Double*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Double*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Double op3, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, Double op3, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double thirdOp, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(Helpers.Insert(firstOp, ElementIndex, thirdOp, i)) != BitConverter.DoubleToInt64Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector128, 1, Double): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..16b9fb3351ac7a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Int16.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector128_Int16_1() + { + var test = new InsertTest__Insert_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Int16 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetInt16(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector128_Int16_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector128_Int16_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Int16* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int16*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte ElementIndex = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar1; + private static Int16 _clsVar3; + + private Vector128 _fld1; + private Int16 _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetInt16(); + } + + public InsertTest__Insert_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetInt16(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + Int16 op3 = TestLibrary.Generator.GetInt16(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(Int16) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + Int16 op3 = TestLibrary.Generator.GetInt16(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(Int16) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Int16* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int16*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetInt16(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetInt16(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector128_Int16_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector128_Int16_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Int16* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int16*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Int16* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int16*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Int16 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, Int16 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16 thirdOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector128, 1, Int16): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..7115656a771b72 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Int32.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector128_Int32_1() + { + var test = new InsertTest__Insert_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Int32 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetInt32(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector128_Int32_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector128_Int32_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Int32* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int32*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte ElementIndex = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar1; + private static Int32 _clsVar3; + + private Vector128 _fld1; + private Int32 _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetInt32(); + } + + public InsertTest__Insert_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetInt32(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + Int32 op3 = TestLibrary.Generator.GetInt32(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(Int32) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + Int32 op3 = TestLibrary.Generator.GetInt32(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(Int32) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Int32* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int32*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetInt32(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetInt32(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector128_Int32_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector128_Int32_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Int32* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int32*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Int32* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int32*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Int32 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, Int32 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32 thirdOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector128, 1, Int32): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Int64.1.cs new file mode 100644 index 00000000000000..a8310e380a619d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Int64.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector128_Int64_1() + { + var test = new InsertTest__Insert_Vector128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector128_Int64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Int64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetInt64(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector128_Int64_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector128_Int64_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Int64* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int64*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte ElementIndex = 1; + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar1; + private static Int64 _clsVar3; + + private Vector128 _fld1; + private Int64 _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetInt64(); + } + + public InsertTest__Insert_Vector128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetInt64(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + Int64 op3 = TestLibrary.Generator.GetInt64(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(Int64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + Int64 op3 = TestLibrary.Generator.GetInt64(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(Int64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Int64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int64*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetInt64(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetInt64(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector128_Int64_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector128_Int64_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Int64* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int64*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Int64* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int64*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Int64 op3, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, Int64 op3, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64 thirdOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector128, 1, Int64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..04ffbd843b6688 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.SByte.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector128_SByte_1() + { + var test = new InsertTest__Insert_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public SByte _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetSByte(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector128_SByte_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector128_SByte_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (SByte* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((SByte*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte ElementIndex = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar1; + private static SByte _clsVar3; + + private Vector128 _fld1; + private SByte _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetSByte(); + } + + public InsertTest__Insert_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetSByte(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + SByte op3 = TestLibrary.Generator.GetSByte(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(SByte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + SByte op3 = TestLibrary.Generator.GetSByte(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(SByte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (SByte* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((SByte*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetSByte(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetSByte(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector128_SByte_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector128_SByte_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (SByte* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((SByte*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (SByte* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((SByte*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, SByte op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, SByte op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte thirdOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector128, 1, SByte): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Single.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Single.1.cs new file mode 100644 index 00000000000000..0bcef9e62ff040 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.Single.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector128_Single_1() + { + var test = new InsertTest__Insert_Vector128_Single_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector128_Single_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Single _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetSingle(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector128_Single_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector128_Single_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Single* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Single*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly byte ElementIndex = 1; + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector128 _clsVar1; + private static Single _clsVar3; + + private Vector128 _fld1; + private Single _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector128_Single_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetSingle(); + } + + public InsertTest__Insert_Vector128_Single_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetSingle(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + Single op3 = TestLibrary.Generator.GetSingle(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(Single) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + Single op3 = TestLibrary.Generator.GetSingle(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(Single) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Single* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Single*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetSingle(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetSingle(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector128_Single_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector128_Single_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Single* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Single*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Single* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Single*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((Single*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Single op3, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, Single op3, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single thirdOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(Helpers.Insert(firstOp, ElementIndex, thirdOp, i)) != BitConverter.SingleToInt32Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector128, 1, Single): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..f07306c62f479d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.UInt16.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector128_UInt16_1() + { + var test = new InsertTest__Insert_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public UInt16 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetUInt16(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector128_UInt16_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (UInt16* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt16*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte ElementIndex = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar1; + private static UInt16 _clsVar3; + + private Vector128 _fld1; + private UInt16 _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetUInt16(); + } + + public InsertTest__Insert_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetUInt16(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + UInt16 op3 = TestLibrary.Generator.GetUInt16(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(UInt16) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + UInt16 op3 = TestLibrary.Generator.GetUInt16(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(UInt16) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (UInt16* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt16*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetUInt16(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetUInt16(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector128_UInt16_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector128_UInt16_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (UInt16* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt16*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (UInt16* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt16*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, UInt16 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, UInt16 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16 thirdOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector128, 1, UInt16): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..1b96c206bfda28 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.UInt32.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector128_UInt32_1() + { + var test = new InsertTest__Insert_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public UInt32 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetUInt32(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector128_UInt32_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (UInt32* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt32*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte ElementIndex = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar1; + private static UInt32 _clsVar3; + + private Vector128 _fld1; + private UInt32 _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetUInt32(); + } + + public InsertTest__Insert_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetUInt32(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + UInt32 op3 = TestLibrary.Generator.GetUInt32(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(UInt32) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + UInt32 op3 = TestLibrary.Generator.GetUInt32(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(UInt32) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (UInt32* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt32*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetUInt32(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetUInt32(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector128_UInt32_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector128_UInt32_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (UInt32* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt32*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (UInt32* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt32*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, UInt32 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, UInt32 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32 thirdOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector128, 1, UInt32): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.UInt64.1.cs new file mode 100644 index 00000000000000..84ef829072ad37 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector128.UInt64.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector128_UInt64_1() + { + var test = new InsertTest__Insert_Vector128_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector128_UInt64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public UInt64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetUInt64(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector128_UInt64_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector128_UInt64_1 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (UInt64* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt64*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte ElementIndex = 1; + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + + private static Vector128 _clsVar1; + private static UInt64 _clsVar3; + + private Vector128 _fld1; + private UInt64 _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector128_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetUInt64(); + } + + public InsertTest__Insert_Vector128_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetUInt64(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + UInt64 op3 = TestLibrary.Generator.GetUInt64(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(UInt64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + UInt64 op3 = TestLibrary.Generator.GetUInt64(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector128), typeof(byte), typeof(UInt64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (UInt64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt64*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetUInt64(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetUInt64(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector128_UInt64_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector128_UInt64_1(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (UInt64* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt64*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (UInt64* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt64*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, UInt64 op3, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, UInt64 op3, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64 thirdOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector128, 1, UInt64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..9b707f7db3bcc6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.Byte.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector64_Byte_1() + { + var test = new InsertTest__Insert_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Byte _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetByte(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector64_Byte_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector64_Byte_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Byte* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Byte*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte ElementIndex = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + + private static Vector64 _clsVar1; + private static Byte _clsVar3; + + private Vector64 _fld1; + private Byte _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetByte(); + } + + public InsertTest__Insert_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetByte(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + Byte op3 = TestLibrary.Generator.GetByte(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector64), typeof(byte), typeof(Byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + Byte op3 = TestLibrary.Generator.GetByte(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector64), typeof(byte), typeof(Byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Byte* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Byte*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetByte(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetByte(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector64_Byte_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector64_Byte_1(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Byte* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Byte*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Byte* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Byte*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Byte op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, Byte op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte thirdOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector64, 1, Byte): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..8894ba1c73d6a5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.Int16.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector64_Int16_1() + { + var test = new InsertTest__Insert_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Int16 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetInt16(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector64_Int16_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector64_Int16_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Int16* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Int16*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte ElementIndex = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar1; + private static Int16 _clsVar3; + + private Vector64 _fld1; + private Int16 _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetInt16(); + } + + public InsertTest__Insert_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetInt16(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + Int16 op3 = TestLibrary.Generator.GetInt16(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector64), typeof(byte), typeof(Int16) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + Int16 op3 = TestLibrary.Generator.GetInt16(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector64), typeof(byte), typeof(Int16) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Int16* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Int16*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetInt16(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetInt16(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector64_Int16_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector64_Int16_1(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Int16* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Int16*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Int16* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Int16*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Int16 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, Int16 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16 thirdOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector64, 1, Int16): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..ed8cf4cdf60eb0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.Int32.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector64_Int32_1() + { + var test = new InsertTest__Insert_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Int32 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetInt32(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector64_Int32_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector64_Int32_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Int32* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Int32*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte ElementIndex = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar1; + private static Int32 _clsVar3; + + private Vector64 _fld1; + private Int32 _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetInt32(); + } + + public InsertTest__Insert_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetInt32(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + Int32 op3 = TestLibrary.Generator.GetInt32(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector64), typeof(byte), typeof(Int32) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + Int32 op3 = TestLibrary.Generator.GetInt32(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector64), typeof(byte), typeof(Int32) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Int32* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Int32*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetInt32(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetInt32(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector64_Int32_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector64_Int32_1(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Int32* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Int32*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Int32* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Int32*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Int32 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, Int32 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32 thirdOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector64, 1, Int32): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..c34d56d0266a12 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.SByte.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector64_SByte_1() + { + var test = new InsertTest__Insert_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public SByte _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetSByte(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector64_SByte_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector64_SByte_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (SByte* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((SByte*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte ElementIndex = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar1; + private static SByte _clsVar3; + + private Vector64 _fld1; + private SByte _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetSByte(); + } + + public InsertTest__Insert_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetSByte(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + SByte op3 = TestLibrary.Generator.GetSByte(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector64), typeof(byte), typeof(SByte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + SByte op3 = TestLibrary.Generator.GetSByte(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector64), typeof(byte), typeof(SByte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (SByte* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((SByte*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetSByte(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetSByte(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector64_SByte_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector64_SByte_1(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (SByte* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((SByte*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (SByte* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((SByte*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, SByte op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, SByte op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte thirdOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector64, 1, SByte): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.Single.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.Single.1.cs new file mode 100644 index 00000000000000..60a2bb0358e562 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.Single.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector64_Single_1() + { + var test = new InsertTest__Insert_Vector64_Single_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector64_Single_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Single _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetSingle(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector64_Single_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector64_Single_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Single* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Single*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly byte ElementIndex = 1; + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector64 _clsVar1; + private static Single _clsVar3; + + private Vector64 _fld1; + private Single _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector64_Single_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetSingle(); + } + + public InsertTest__Insert_Vector64_Single_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetSingle(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, new Single[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + Single op3 = TestLibrary.Generator.GetSingle(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector64), typeof(byte), typeof(Single) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + Single op3 = TestLibrary.Generator.GetSingle(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector64), typeof(byte), typeof(Single) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Single* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Single*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetSingle(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Single*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetSingle(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector64_Single_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector64_Single_1(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Single* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Single*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Single* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Single*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((Single*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Single op3, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, Single op3, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single thirdOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(Helpers.Insert(firstOp, ElementIndex, thirdOp, i)) != BitConverter.SingleToInt32Bits(result[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector64, 1, Single): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..ecf47b34650bae --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.UInt16.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector64_UInt16_1() + { + var test = new InsertTest__Insert_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public UInt16 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetUInt16(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector64_UInt16_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (UInt16* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((UInt16*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte ElementIndex = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar1; + private static UInt16 _clsVar3; + + private Vector64 _fld1; + private UInt16 _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetUInt16(); + } + + public InsertTest__Insert_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetUInt16(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + UInt16 op3 = TestLibrary.Generator.GetUInt16(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector64), typeof(byte), typeof(UInt16) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + UInt16 op3 = TestLibrary.Generator.GetUInt16(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector64), typeof(byte), typeof(UInt16) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (UInt16* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((UInt16*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetUInt16(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetUInt16(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector64_UInt16_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector64_UInt16_1(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (UInt16* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((UInt16*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (UInt16* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((UInt16*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, UInt16 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, UInt16 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16 thirdOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector64, 1, UInt16): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..3b69c7ab6490dc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Insert.Vector64.UInt32.1.cs @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void Insert_Vector64_UInt32_1() + { + var test = new InsertTest__Insert_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__Insert_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public UInt32 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + testStruct._fld3 = TestLibrary.Generator.GetUInt32(); + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__Insert_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__Insert_Vector64_UInt32_1 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (UInt32* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((UInt32*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte ElementIndex = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar1; + private static UInt32 _clsVar3; + + private Vector64 _fld1; + private UInt32 _fld3; + + private DataTable _dataTable; + + static InsertTest__Insert_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _clsVar3 = TestLibrary.Generator.GetUInt32(); + } + + public InsertTest__Insert_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + _fld3 = TestLibrary.Generator.GetUInt32(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.Insert( + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + UInt32 op3 = TestLibrary.Generator.GetUInt32(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector64), typeof(byte), typeof(UInt32) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + UInt32 op3 = TestLibrary.Generator.GetUInt32(); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.Insert), new Type[] { typeof(Vector64), typeof(byte), typeof(UInt32) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.Insert( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (UInt32* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((UInt32*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op3 = TestLibrary.Generator.GetUInt32(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op3 = TestLibrary.Generator.GetUInt32(); + + var result = AdvSimd.Insert(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__Insert_Vector64_UInt32_1(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__Insert_Vector64_UInt32_1(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (UInt32* pFld3 = &test._fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((UInt32*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.Insert(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (UInt32* pFld3 = &_fld3) + { + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((UInt32*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.Insert( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, UInt32 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, UInt32 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32 thirdOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.Insert)}(Vector64, 1, UInt32): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.Byte.cs new file mode 100644 index 00000000000000..15f093c5b5f1ae --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLower_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Byte testClass) + { + var result = AdvSimd.MultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.MultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.MultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Byte(); + var result = AdvSimd.MultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.Int16.cs new file mode 100644 index 00000000000000..d7b049c35fa6ad --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLower_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int16 testClass) + { + var result = AdvSimd.MultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.MultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.MultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int16(); + var result = AdvSimd.MultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.Int32.cs new file mode 100644 index 00000000000000..924abe3e5fc107 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLower_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int32 testClass) + { + var result = AdvSimd.MultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.MultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.MultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int32(); + var result = AdvSimd.MultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.SByte.cs new file mode 100644 index 00000000000000..41e204947a70db --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLower_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__MultiplyWideningLower_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyWideningLower_Vector64_SByte testClass) + { + var result = AdvSimd.MultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyWideningLower_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyWideningLower_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyWideningLower_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.MultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.MultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_SByte(); + var result = AdvSimd.MultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.UInt16.cs new file mode 100644 index 00000000000000..b937a0e871dfda --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLower_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt16 testClass) + { + var result = AdvSimd.MultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.MultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.MultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt16(); + var result = AdvSimd.MultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.UInt32.cs new file mode 100644 index 00000000000000..63b80db60eea4a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLower.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLower_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt32 testClass) + { + var result = AdvSimd.MultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.MultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.MultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt32(); + var result = AdvSimd.MultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyWideningLower_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLower( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.Byte.cs new file mode 100644 index 00000000000000..7df014bf6ad058 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.Byte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLowerAndAdd_Vector64_Byte() + { + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Byte[] inArray2, Byte[] inArray3, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Byte testClass) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + private static Byte[] _data3 = new Byte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)), + AdvSimd.LoadVector64((Byte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Byte(); + var result = AdvSimd.MultiplyWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)), + AdvSimd.LoadVector64((Byte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Byte[] secondOp, Byte[] thirdOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLowerAndAdd)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.Int16.cs new file mode 100644 index 00000000000000..a29a5adb80f792 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.Int16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLowerAndAdd_Vector64_Int16() + { + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int16[] inArray2, Int16[] inArray3, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int16 testClass) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)), + AdvSimd.LoadVector64((Int16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + private static Int16[] _data3 = new Int16[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)), + AdvSimd.LoadVector64((Int16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int16(); + var result = AdvSimd.MultiplyWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)), + AdvSimd.LoadVector64((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)), + AdvSimd.LoadVector64((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)), + AdvSimd.LoadVector64((Int16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] secondOp, Int16[] thirdOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLowerAndAdd)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.Int32.cs new file mode 100644 index 00000000000000..09f2f2d7ea3a49 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.Int32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLowerAndAdd_Vector64_Int32() + { + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int32[] inArray2, Int32[] inArray3, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int32 testClass) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)), + AdvSimd.LoadVector64((Int32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + private static Int32[] _data3 = new Int32[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)), + AdvSimd.LoadVector64((Int32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int32(); + var result = AdvSimd.MultiplyWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)), + AdvSimd.LoadVector64((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)), + AdvSimd.LoadVector64((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)), + AdvSimd.LoadVector64((Int32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] secondOp, Int32[] thirdOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLowerAndAdd)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.SByte.cs new file mode 100644 index 00000000000000..101d3822cf1b5e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.SByte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLowerAndAdd_Vector64_SByte() + { + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, SByte[] inArray2, SByte[] inArray3, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_SByte testClass) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + private static SByte[] _data3 = new SByte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)), + AdvSimd.LoadVector64((SByte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_SByte(); + var result = AdvSimd.MultiplyWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)), + AdvSimd.LoadVector64((SByte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] secondOp, SByte[] thirdOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLowerAndAdd)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.UInt16.cs new file mode 100644 index 00000000000000..fb166b4758ad69 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.UInt16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLowerAndAdd_Vector64_UInt16() + { + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt16[] inArray2, UInt16[] inArray3, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt16 testClass) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)), + AdvSimd.LoadVector64((UInt16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + private static UInt16[] _data3 = new UInt16[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)), + AdvSimd.LoadVector64((UInt16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt16(); + var result = AdvSimd.MultiplyWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)), + AdvSimd.LoadVector64((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)), + AdvSimd.LoadVector64((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)), + AdvSimd.LoadVector64((UInt16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt16[] secondOp, UInt16[] thirdOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLowerAndAdd)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.UInt32.cs new file mode 100644 index 00000000000000..d1cfd59dcef567 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndAdd.Vector64.UInt32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLowerAndAdd_Vector64_UInt32() + { + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt32[] inArray2, UInt32[] inArray3, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt32 testClass) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)), + AdvSimd.LoadVector64((UInt32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + private static UInt32[] _data3 = new UInt32[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndAdd), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)), + AdvSimd.LoadVector64((UInt32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningLowerAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt32(); + var result = AdvSimd.MultiplyWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndAdd_Vector64_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)), + AdvSimd.LoadVector64((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)), + AdvSimd.LoadVector64((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndAdd( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)), + AdvSimd.LoadVector64((UInt32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt32[] secondOp, UInt32[] thirdOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLowerAndAdd)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.Byte.cs new file mode 100644 index 00000000000000..48f180312307d6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.Byte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLowerAndSubtract_Vector64_Byte() + { + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Byte[] inArray2, Byte[] inArray3, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Byte testClass) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + private static Byte[] _data3 = new Byte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndSubtract), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndSubtract), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)), + AdvSimd.LoadVector64((Byte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Byte(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)), + AdvSimd.LoadVector64((Byte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Byte[] secondOp, Byte[] thirdOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningAndSubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLowerAndSubtract)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.Int16.cs new file mode 100644 index 00000000000000..39abb5db2b7d77 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.Int16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLowerAndSubtract_Vector64_Int16() + { + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int16[] inArray2, Int16[] inArray3, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int16 testClass) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)), + AdvSimd.LoadVector64((Int16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + private static Int16[] _data3 = new Int16[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndSubtract), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndSubtract), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)), + AdvSimd.LoadVector64((Int16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int16(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)), + AdvSimd.LoadVector64((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)), + AdvSimd.LoadVector64((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)), + AdvSimd.LoadVector64((Int16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] secondOp, Int16[] thirdOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningAndSubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLowerAndSubtract)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.Int32.cs new file mode 100644 index 00000000000000..5f64dbe7444593 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.Int32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLowerAndSubtract_Vector64_Int32() + { + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int32[] inArray2, Int32[] inArray3, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int32 testClass) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)), + AdvSimd.LoadVector64((Int32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + private static Int32[] _data3 = new Int32[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndSubtract), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndSubtract), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)), + AdvSimd.LoadVector64((Int32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int32(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)), + AdvSimd.LoadVector64((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)), + AdvSimd.LoadVector64((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)), + AdvSimd.LoadVector64((Int32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] secondOp, Int32[] thirdOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningAndSubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLowerAndSubtract)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.SByte.cs new file mode 100644 index 00000000000000..f47cee8d183b8f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.SByte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLowerAndSubtract_Vector64_SByte() + { + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, SByte[] inArray2, SByte[] inArray3, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_SByte testClass) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + private static SByte[] _data3 = new SByte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndSubtract), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndSubtract), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)), + AdvSimd.LoadVector64((SByte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_SByte(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)), + AdvSimd.LoadVector64((SByte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] secondOp, SByte[] thirdOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningAndSubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLowerAndSubtract)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.UInt16.cs new file mode 100644 index 00000000000000..5db92d8f850eff --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.UInt16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLowerAndSubtract_Vector64_UInt16() + { + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt16[] inArray2, UInt16[] inArray3, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt16 testClass) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)), + AdvSimd.LoadVector64((UInt16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + private static UInt16[] _data3 = new UInt16[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndSubtract), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndSubtract), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)), + AdvSimd.LoadVector64((UInt16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt16(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)), + AdvSimd.LoadVector64((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)), + AdvSimd.LoadVector64((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)), + AdvSimd.LoadVector64((UInt16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt16[] secondOp, UInt16[] thirdOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningAndSubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLowerAndSubtract)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.UInt32.cs new file mode 100644 index 00000000000000..d8fac1e2e0ea96 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningLowerAndSubtract.Vector64.UInt32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningLowerAndSubtract_Vector64_UInt32() + { + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt32[] inArray2, UInt32[] inArray3, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt32 testClass) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)), + AdvSimd.LoadVector64((UInt32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + private static UInt32[] _data3 = new UInt32[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + private static Vector64 _clsVar3; + + private Vector128 _fld1; + private Vector64 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndSubtract), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningLowerAndSubtract), new Type[] { typeof(Vector128), typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)), + AdvSimd.LoadVector64((UInt32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt32(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningLowerAndSubtract_Vector64_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)), + AdvSimd.LoadVector64((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningLowerAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)), + AdvSimd.LoadVector64((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningLowerAndSubtract( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)), + AdvSimd.LoadVector64((UInt32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt32[] secondOp, UInt32[] thirdOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningAndSubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningLowerAndSubtract)}(Vector128, Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.Byte.cs new file mode 100644 index 00000000000000..f523c7daa33dac --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpper_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Byte testClass) + { + var result = AdvSimd.MultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.MultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.MultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Byte(); + var result = AdvSimd.MultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.Int16.cs new file mode 100644 index 00000000000000..0a3b266d231d37 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpper_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int16 testClass) + { + var result = AdvSimd.MultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.MultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.MultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int16(); + var result = AdvSimd.MultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.Int32.cs new file mode 100644 index 00000000000000..f93fad0bd22050 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpper_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int32 testClass) + { + var result = AdvSimd.MultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.MultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.MultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int32(); + var result = AdvSimd.MultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.SByte.cs new file mode 100644 index 00000000000000..46e891e017358f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpper_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_SByte testClass) + { + var result = AdvSimd.MultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.MultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.MultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_SByte(); + var result = AdvSimd.MultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.UInt16.cs new file mode 100644 index 00000000000000..0a5eb815f5a339 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpper_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt16 testClass) + { + var result = AdvSimd.MultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.MultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.MultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt16(); + var result = AdvSimd.MultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.UInt32.cs new file mode 100644 index 00000000000000..23ac8e27c1aae1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpper.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpper_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt32 testClass) + { + var result = AdvSimd.MultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.MultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.MultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt32(); + var result = AdvSimd.MultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__MultiplyWideningUpper_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpper( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.Byte.cs new file mode 100644 index 00000000000000..f3cddbf469b654 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.Byte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpperAndAdd_Vector128_Byte() + { + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Byte[] inArray2, Byte[] inArray3, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Byte testClass) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + private static Byte[] _data3 = new Byte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)), + AdvSimd.LoadVector128((Byte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Byte(); + var result = AdvSimd.MultiplyWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)), + AdvSimd.LoadVector128((Byte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Byte[] secondOp, Byte[] thirdOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpperAndAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.Int16.cs new file mode 100644 index 00000000000000..dde967955dd6c6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.Int16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpperAndAdd_Vector128_Int16() + { + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int16[] inArray2, Int16[] inArray3, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int16 testClass) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + private static Int16[] _data3 = new Int16[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)), + AdvSimd.LoadVector128((Int16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int16(); + var result = AdvSimd.MultiplyWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)), + AdvSimd.LoadVector128((Int16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] secondOp, Int16[] thirdOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpperAndAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.Int32.cs new file mode 100644 index 00000000000000..bf7587683a4313 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.Int32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpperAndAdd_Vector128_Int32() + { + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int32[] inArray2, Int32[] inArray3, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int32 testClass) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + private static Int32[] _data3 = new Int32[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)), + AdvSimd.LoadVector128((Int32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int32(); + var result = AdvSimd.MultiplyWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)), + AdvSimd.LoadVector128((Int32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] secondOp, Int32[] thirdOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpperAndAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.SByte.cs new file mode 100644 index 00000000000000..97c8f7e0a0a7b2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.SByte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpperAndAdd_Vector128_SByte() + { + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, SByte[] inArray2, SByte[] inArray3, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_SByte testClass) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + private static SByte[] _data3 = new SByte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)), + AdvSimd.LoadVector128((SByte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_SByte(); + var result = AdvSimd.MultiplyWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)), + AdvSimd.LoadVector128((SByte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] secondOp, SByte[] thirdOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpperAndAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.UInt16.cs new file mode 100644 index 00000000000000..38bc45e4b4328b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.UInt16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpperAndAdd_Vector128_UInt16() + { + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt16[] inArray2, UInt16[] inArray3, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt16 testClass) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + private static UInt16[] _data3 = new UInt16[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)), + AdvSimd.LoadVector128((UInt16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt16(); + var result = AdvSimd.MultiplyWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)), + AdvSimd.LoadVector128((UInt16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt16[] secondOp, UInt16[] thirdOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpperAndAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.UInt32.cs new file mode 100644 index 00000000000000..c4d55cd27b72c8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndAdd.Vector128.UInt32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpperAndAdd_Vector128_UInt32() + { + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt32[] inArray2, UInt32[] inArray3, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt32 testClass) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + private static UInt32[] _data3 = new UInt32[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)), + AdvSimd.LoadVector128((UInt32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningUpperAndAdd(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt32(); + var result = AdvSimd.MultiplyWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndAdd_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndAdd(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndAdd(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndAdd( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)), + AdvSimd.LoadVector128((UInt32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt32[] secondOp, UInt32[] thirdOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpperAndAdd)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.Byte.cs new file mode 100644 index 00000000000000..9818a6f129fe40 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.Byte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpperAndSubtract_Vector128_Byte() + { + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Byte[] inArray2, Byte[] inArray3, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Byte testClass) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + private static Byte[] _data3 = new Byte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndSubtract), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndSubtract), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)), + AdvSimd.LoadVector128((Byte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Byte(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector128((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)), + AdvSimd.LoadVector128((Byte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Byte[] secondOp, Byte[] thirdOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpperAndSubtract(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpperAndSubtract)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.Int16.cs new file mode 100644 index 00000000000000..acc3e3b19a10ce --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.Int16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpperAndSubtract_Vector128_Int16() + { + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int16[] inArray2, Int16[] inArray3, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int16 testClass) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + private static Int16[] _data3 = new Int16[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndSubtract), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndSubtract), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)), + AdvSimd.LoadVector128((Int16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int16(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)), + AdvSimd.LoadVector128((Int16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] secondOp, Int16[] thirdOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpperAndSubtract(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpperAndSubtract)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.Int32.cs new file mode 100644 index 00000000000000..e75df206398e2e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.Int32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpperAndSubtract_Vector128_Int32() + { + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int32[] inArray2, Int32[] inArray3, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int32 testClass) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + private static Int32[] _data3 = new Int32[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndSubtract), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndSubtract), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)), + AdvSimd.LoadVector128((Int32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int32(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)), + AdvSimd.LoadVector128((Int32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] secondOp, Int32[] thirdOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpperAndSubtract(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpperAndSubtract)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.SByte.cs new file mode 100644 index 00000000000000..1ebcf198bde631 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.SByte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpperAndSubtract_Vector128_SByte() + { + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, SByte[] inArray2, SByte[] inArray3, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_SByte testClass) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + private static SByte[] _data3 = new SByte[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndSubtract), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndSubtract), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)), + AdvSimd.LoadVector128((SByte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_SByte(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector128((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)), + AdvSimd.LoadVector128((SByte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] secondOp, SByte[] thirdOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpperAndSubtract(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpperAndSubtract)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.UInt16.cs new file mode 100644 index 00000000000000..1f4a236171ae79 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.UInt16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpperAndSubtract_Vector128_UInt16() + { + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt16[] inArray2, UInt16[] inArray3, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt16 testClass) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + private static UInt16[] _data3 = new UInt16[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndSubtract), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndSubtract), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)), + AdvSimd.LoadVector128((UInt16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt16(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)), + AdvSimd.LoadVector128((UInt16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt16[] secondOp, UInt16[] thirdOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpperAndSubtract(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpperAndSubtract)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.UInt32.cs new file mode 100644 index 00000000000000..1dbf101a589cfb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/MultiplyWideningUpperAndSubtract.Vector128.UInt32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void MultiplyWideningUpperAndSubtract_Vector128_UInt32() + { + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt32[] inArray2, UInt32[] inArray3, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt32 testClass) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + private static UInt32[] _data3 = new UInt32[Op3ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector128 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndSubtract), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.MultiplyWideningUpperAndSubtract), new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)), + AdvSimd.LoadVector128((UInt32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt32(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__MultiplyWideningUpperAndSubtract_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.MultiplyWideningUpperAndSubtract(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.MultiplyWideningUpperAndSubtract( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)), + AdvSimd.LoadVector128((UInt32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt32[] secondOp, UInt32[] thirdOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.MultiplyWideningUpperAndSubtract(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.MultiplyWideningUpperAndSubtract)}(Vector128, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiplyWideningLower.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiplyWideningLower.Vector64.Byte.cs new file mode 100644 index 00000000000000..729db2ea0559d5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiplyWideningLower.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void PolynomialMultiplyWideningLower_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Byte testClass) + { + var result = AdvSimd.PolynomialMultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.PolynomialMultiplyWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.PolynomialMultiplyWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.PolynomialMultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.PolynomialMultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Byte(); + var result = AdvSimd.PolynomialMultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.PolynomialMultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.PolynomialMultiplyWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.PolynomialMultiplyWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiplyWideningLower.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiplyWideningLower.Vector64.SByte.cs new file mode 100644 index 00000000000000..995f417e47501f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiplyWideningLower.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void PolynomialMultiplyWideningLower_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_SByte testClass) + { + var result = AdvSimd.PolynomialMultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.PolynomialMultiplyWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.PolynomialMultiplyWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.PolynomialMultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.PolynomialMultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_SByte(); + var result = AdvSimd.PolynomialMultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.PolynomialMultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.PolynomialMultiplyWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.PolynomialMultiplyWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiplyWideningUpper.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiplyWideningUpper.Vector128.Byte.cs new file mode 100644 index 00000000000000..dfd07f4ab3260b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiplyWideningUpper.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void PolynomialMultiplyWideningUpper_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Byte testClass) + { + var result = AdvSimd.PolynomialMultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.PolynomialMultiplyWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.PolynomialMultiplyWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.PolynomialMultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.PolynomialMultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Byte(); + var result = AdvSimd.PolynomialMultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.PolynomialMultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.PolynomialMultiplyWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.PolynomialMultiplyWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiplyWideningUpper.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiplyWideningUpper.Vector128.SByte.cs new file mode 100644 index 00000000000000..32780778dbdd0d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/PolynomialMultiplyWideningUpper.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void PolynomialMultiplyWideningUpper_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_SByte testClass) + { + var result = AdvSimd.PolynomialMultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.PolynomialMultiplyWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.PolynomialMultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.PolynomialMultiplyWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.PolynomialMultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.PolynomialMultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_SByte(); + var result = AdvSimd.PolynomialMultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.PolynomialMultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.PolynomialMultiplyWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.PolynomialMultiplyWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Program.AdvSimd.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Program.AdvSimd.cs index 2d48b0a90cefd6..636a26238b5648 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Program.AdvSimd.cs +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/Program.AdvSimd.cs @@ -56,6 +56,30 @@ static Program() ["AbsoluteDifferenceAdd.Vector128.SByte"] = AbsoluteDifferenceAdd_Vector128_SByte, ["AbsoluteDifferenceAdd.Vector128.UInt16"] = AbsoluteDifferenceAdd_Vector128_UInt16, ["AbsoluteDifferenceAdd.Vector128.UInt32"] = AbsoluteDifferenceAdd_Vector128_UInt32, + ["AbsoluteDifferenceWideningLower.Vector64.Byte"] = AbsoluteDifferenceWideningLower_Vector64_Byte, + ["AbsoluteDifferenceWideningLower.Vector64.Int16"] = AbsoluteDifferenceWideningLower_Vector64_Int16, + ["AbsoluteDifferenceWideningLower.Vector64.Int32"] = AbsoluteDifferenceWideningLower_Vector64_Int32, + ["AbsoluteDifferenceWideningLower.Vector64.SByte"] = AbsoluteDifferenceWideningLower_Vector64_SByte, + ["AbsoluteDifferenceWideningLower.Vector64.UInt16"] = AbsoluteDifferenceWideningLower_Vector64_UInt16, + ["AbsoluteDifferenceWideningLower.Vector64.UInt32"] = AbsoluteDifferenceWideningLower_Vector64_UInt32, + ["AbsoluteDifferenceWideningLowerAndAdd.Vector64.Byte"] = AbsoluteDifferenceWideningLowerAndAdd_Vector64_Byte, + ["AbsoluteDifferenceWideningLowerAndAdd.Vector64.Int16"] = AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int16, + ["AbsoluteDifferenceWideningLowerAndAdd.Vector64.Int32"] = AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int32, + ["AbsoluteDifferenceWideningLowerAndAdd.Vector64.SByte"] = AbsoluteDifferenceWideningLowerAndAdd_Vector64_SByte, + ["AbsoluteDifferenceWideningLowerAndAdd.Vector64.UInt16"] = AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt16, + ["AbsoluteDifferenceWideningLowerAndAdd.Vector64.UInt32"] = AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt32, + ["AbsoluteDifferenceWideningUpper.Vector128.Byte"] = AbsoluteDifferenceWideningUpper_Vector128_Byte, + ["AbsoluteDifferenceWideningUpper.Vector128.Int16"] = AbsoluteDifferenceWideningUpper_Vector128_Int16, + ["AbsoluteDifferenceWideningUpper.Vector128.Int32"] = AbsoluteDifferenceWideningUpper_Vector128_Int32, + ["AbsoluteDifferenceWideningUpper.Vector128.SByte"] = AbsoluteDifferenceWideningUpper_Vector128_SByte, + ["AbsoluteDifferenceWideningUpper.Vector128.UInt16"] = AbsoluteDifferenceWideningUpper_Vector128_UInt16, + ["AbsoluteDifferenceWideningUpper.Vector128.UInt32"] = AbsoluteDifferenceWideningUpper_Vector128_UInt32, + ["AbsoluteDifferenceWideningUpperAndAdd.Vector128.Byte"] = AbsoluteDifferenceWideningUpperAndAdd_Vector128_Byte, + ["AbsoluteDifferenceWideningUpperAndAdd.Vector128.Int16"] = AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int16, + ["AbsoluteDifferenceWideningUpperAndAdd.Vector128.Int32"] = AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int32, + ["AbsoluteDifferenceWideningUpperAndAdd.Vector128.SByte"] = AbsoluteDifferenceWideningUpperAndAdd_Vector128_SByte, + ["AbsoluteDifferenceWideningUpperAndAdd.Vector128.UInt16"] = AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt16, + ["AbsoluteDifferenceWideningUpperAndAdd.Vector128.UInt32"] = AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt32, ["Add.Vector64.Byte"] = Add_Vector64_Byte, ["Add.Vector64.Int16"] = Add_Vector64_Int16, ["Add.Vector64.Int32"] = Add_Vector64_Int32, @@ -72,6 +96,18 @@ static Program() ["Add.Vector128.UInt16"] = Add_Vector128_UInt16, ["Add.Vector128.UInt32"] = Add_Vector128_UInt32, ["Add.Vector128.UInt64"] = Add_Vector128_UInt64, + ["AddHighNarrowingLower.Vector64.Byte"] = AddHighNarrowingLower_Vector64_Byte, + ["AddHighNarrowingLower.Vector64.Int16"] = AddHighNarrowingLower_Vector64_Int16, + ["AddHighNarrowingLower.Vector64.Int32"] = AddHighNarrowingLower_Vector64_Int32, + ["AddHighNarrowingLower.Vector64.SByte"] = AddHighNarrowingLower_Vector64_SByte, + ["AddHighNarrowingLower.Vector64.UInt16"] = AddHighNarrowingLower_Vector64_UInt16, + ["AddHighNarrowingLower.Vector64.UInt32"] = AddHighNarrowingLower_Vector64_UInt32, + ["AddHighNarrowingUpper.Vector128.Byte"] = AddHighNarrowingUpper_Vector128_Byte, + ["AddHighNarrowingUpper.Vector128.Int16"] = AddHighNarrowingUpper_Vector128_Int16, + ["AddHighNarrowingUpper.Vector128.Int32"] = AddHighNarrowingUpper_Vector128_Int32, + ["AddHighNarrowingUpper.Vector128.SByte"] = AddHighNarrowingUpper_Vector128_SByte, + ["AddHighNarrowingUpper.Vector128.UInt16"] = AddHighNarrowingUpper_Vector128_UInt16, + ["AddHighNarrowingUpper.Vector128.UInt32"] = AddHighNarrowingUpper_Vector128_UInt32, ["AddPairwise.Vector64.Byte"] = AddPairwise_Vector64_Byte, ["AddPairwise.Vector64.Int16"] = AddPairwise_Vector64_Int16, ["AddPairwise.Vector64.Int32"] = AddPairwise_Vector64_Int32, @@ -79,10 +115,86 @@ static Program() ["AddPairwise.Vector64.Single"] = AddPairwise_Vector64_Single, ["AddPairwise.Vector64.UInt16"] = AddPairwise_Vector64_UInt16, ["AddPairwise.Vector64.UInt32"] = AddPairwise_Vector64_UInt32, + ["AddPairwiseWidening.Vector64.Byte"] = AddPairwiseWidening_Vector64_Byte, + ["AddPairwiseWidening.Vector64.Int16"] = AddPairwiseWidening_Vector64_Int16, + ["AddPairwiseWidening.Vector64.SByte"] = AddPairwiseWidening_Vector64_SByte, + ["AddPairwiseWidening.Vector64.UInt16"] = AddPairwiseWidening_Vector64_UInt16, + ["AddPairwiseWidening.Vector128.Byte"] = AddPairwiseWidening_Vector128_Byte, + ["AddPairwiseWidening.Vector128.Int16"] = AddPairwiseWidening_Vector128_Int16, + ["AddPairwiseWidening.Vector128.Int32"] = AddPairwiseWidening_Vector128_Int32, + ["AddPairwiseWidening.Vector128.SByte"] = AddPairwiseWidening_Vector128_SByte, + ["AddPairwiseWidening.Vector128.UInt16"] = AddPairwiseWidening_Vector128_UInt16, + ["AddPairwiseWidening.Vector128.UInt32"] = AddPairwiseWidening_Vector128_UInt32, + ["AddPairwiseWideningAndAdd.Vector64.Byte"] = AddPairwiseWideningAndAdd_Vector64_Byte, + ["AddPairwiseWideningAndAdd.Vector64.Int16"] = AddPairwiseWideningAndAdd_Vector64_Int16, + ["AddPairwiseWideningAndAdd.Vector64.SByte"] = AddPairwiseWideningAndAdd_Vector64_SByte, + ["AddPairwiseWideningAndAdd.Vector64.UInt16"] = AddPairwiseWideningAndAdd_Vector64_UInt16, + ["AddPairwiseWideningAndAdd.Vector128.Byte"] = AddPairwiseWideningAndAdd_Vector128_Byte, + ["AddPairwiseWideningAndAdd.Vector128.Int16"] = AddPairwiseWideningAndAdd_Vector128_Int16, + ["AddPairwiseWideningAndAdd.Vector128.Int32"] = AddPairwiseWideningAndAdd_Vector128_Int32, + ["AddPairwiseWideningAndAdd.Vector128.SByte"] = AddPairwiseWideningAndAdd_Vector128_SByte, + ["AddPairwiseWideningAndAdd.Vector128.UInt16"] = AddPairwiseWideningAndAdd_Vector128_UInt16, + ["AddPairwiseWideningAndAdd.Vector128.UInt32"] = AddPairwiseWideningAndAdd_Vector128_UInt32, + ["AddPairwiseWideningAndAddScalar.Vector64.Int32"] = AddPairwiseWideningAndAddScalar_Vector64_Int32, + ["AddPairwiseWideningAndAddScalar.Vector64.UInt32"] = AddPairwiseWideningAndAddScalar_Vector64_UInt32, + ["AddPairwiseWideningScalar.Vector64.Int32"] = AddPairwiseWideningScalar_Vector64_Int32, + ["AddPairwiseWideningScalar.Vector64.UInt32"] = AddPairwiseWideningScalar_Vector64_UInt32, + ["AddRoundedHighNarrowingLower.Vector64.Byte"] = AddRoundedHighNarrowingLower_Vector64_Byte, + ["AddRoundedHighNarrowingLower.Vector64.Int16"] = AddRoundedHighNarrowingLower_Vector64_Int16, + ["AddRoundedHighNarrowingLower.Vector64.Int32"] = AddRoundedHighNarrowingLower_Vector64_Int32, + ["AddRoundedHighNarrowingLower.Vector64.SByte"] = AddRoundedHighNarrowingLower_Vector64_SByte, + ["AddRoundedHighNarrowingLower.Vector64.UInt16"] = AddRoundedHighNarrowingLower_Vector64_UInt16, + ["AddRoundedHighNarrowingLower.Vector64.UInt32"] = AddRoundedHighNarrowingLower_Vector64_UInt32, + ["AddRoundedHighNarrowingUpper.Vector128.Byte"] = AddRoundedHighNarrowingUpper_Vector128_Byte, + ["AddRoundedHighNarrowingUpper.Vector128.Int16"] = AddRoundedHighNarrowingUpper_Vector128_Int16, + ["AddRoundedHighNarrowingUpper.Vector128.Int32"] = AddRoundedHighNarrowingUpper_Vector128_Int32, + ["AddRoundedHighNarrowingUpper.Vector128.SByte"] = AddRoundedHighNarrowingUpper_Vector128_SByte, + ["AddRoundedHighNarrowingUpper.Vector128.UInt16"] = AddRoundedHighNarrowingUpper_Vector128_UInt16, + ["AddRoundedHighNarrowingUpper.Vector128.UInt32"] = AddRoundedHighNarrowingUpper_Vector128_UInt32, + ["AddSaturate.Vector64.Byte"] = AddSaturate_Vector64_Byte, + ["AddSaturate.Vector64.Int16"] = AddSaturate_Vector64_Int16, + ["AddSaturate.Vector64.Int32"] = AddSaturate_Vector64_Int32, + ["AddSaturate.Vector64.SByte"] = AddSaturate_Vector64_SByte, + ["AddSaturate.Vector64.UInt16"] = AddSaturate_Vector64_UInt16, + ["AddSaturate.Vector64.UInt32"] = AddSaturate_Vector64_UInt32, + ["AddSaturate.Vector128.Byte"] = AddSaturate_Vector128_Byte, + ["AddSaturate.Vector128.Int16"] = AddSaturate_Vector128_Int16, + ["AddSaturate.Vector128.Int32"] = AddSaturate_Vector128_Int32, + ["AddSaturate.Vector128.Int64"] = AddSaturate_Vector128_Int64, + ["AddSaturate.Vector128.SByte"] = AddSaturate_Vector128_SByte, + ["AddSaturate.Vector128.UInt16"] = AddSaturate_Vector128_UInt16, + ["AddSaturate.Vector128.UInt32"] = AddSaturate_Vector128_UInt32, + ["AddSaturate.Vector128.UInt64"] = AddSaturate_Vector128_UInt64, + ["AddSaturateScalar.Vector64.Int64"] = AddSaturateScalar_Vector64_Int64, + ["AddSaturateScalar.Vector64.UInt64"] = AddSaturateScalar_Vector64_UInt64, ["AddScalar.Vector64.Double"] = AddScalar_Vector64_Double, ["AddScalar.Vector64.Int64"] = AddScalar_Vector64_Int64, ["AddScalar.Vector64.Single"] = AddScalar_Vector64_Single, ["AddScalar.Vector64.UInt64"] = AddScalar_Vector64_UInt64, + ["AddWideningLower.Vector64.Byte"] = AddWideningLower_Vector64_Byte, + ["AddWideningLower.Vector64.Int16"] = AddWideningLower_Vector64_Int16, + ["AddWideningLower.Vector64.Int32"] = AddWideningLower_Vector64_Int32, + ["AddWideningLower.Vector64.SByte"] = AddWideningLower_Vector64_SByte, + ["AddWideningLower.Vector64.UInt16"] = AddWideningLower_Vector64_UInt16, + ["AddWideningLower.Vector64.UInt32"] = AddWideningLower_Vector64_UInt32, + ["AddWideningLower.Vector128.Int16"] = AddWideningLower_Vector128_Int16, + ["AddWideningLower.Vector128.Int32"] = AddWideningLower_Vector128_Int32, + ["AddWideningLower.Vector128.Int64"] = AddWideningLower_Vector128_Int64, + ["AddWideningLower.Vector128.UInt16"] = AddWideningLower_Vector128_UInt16, + ["AddWideningLower.Vector128.UInt32"] = AddWideningLower_Vector128_UInt32, + ["AddWideningLower.Vector128.UInt64"] = AddWideningLower_Vector128_UInt64, + ["AddWideningUpper.Vector128.Byte.Vector128.Byte"] = AddWideningUpper_Vector128_Byte_Vector128_Byte, + ["AddWideningUpper.Vector128.Int16.Vector128.Int16"] = AddWideningUpper_Vector128_Int16_Vector128_Int16, + ["AddWideningUpper.Vector128.Int16.Vector128.SByte"] = AddWideningUpper_Vector128_Int16_Vector128_SByte, + ["AddWideningUpper.Vector128.Int32.Vector128.Int16"] = AddWideningUpper_Vector128_Int32_Vector128_Int16, + ["AddWideningUpper.Vector128.Int32.Vector128.Int32"] = AddWideningUpper_Vector128_Int32_Vector128_Int32, + ["AddWideningUpper.Vector128.Int64.Vector128.Int32"] = AddWideningUpper_Vector128_Int64_Vector128_Int32, + ["AddWideningUpper.Vector128.SByte.Vector128.SByte"] = AddWideningUpper_Vector128_SByte_Vector128_SByte, + ["AddWideningUpper.Vector128.UInt16.Vector128.Byte"] = AddWideningUpper_Vector128_UInt16_Vector128_Byte, + ["AddWideningUpper.Vector128.UInt16.Vector128.UInt16"] = AddWideningUpper_Vector128_UInt16_Vector128_UInt16, + ["AddWideningUpper.Vector128.UInt32.Vector128.UInt16"] = AddWideningUpper_Vector128_UInt32_Vector128_UInt16, + ["AddWideningUpper.Vector128.UInt32.Vector128.UInt32"] = AddWideningUpper_Vector128_UInt32_Vector128_UInt32, + ["AddWideningUpper.Vector128.UInt64.Vector128.UInt32"] = AddWideningUpper_Vector128_UInt64_Vector128_UInt32, ["And.Vector64.Byte"] = And_Vector64_Byte, ["And.Vector64.Double"] = And_Vector64_Double, ["And.Vector64.Int16"] = And_Vector64_Int16, @@ -229,18 +341,132 @@ static Program() ["CompareTest.Vector128.UInt32"] = CompareTest_Vector128_UInt32, ["DivideScalar.Vector64.Double"] = DivideScalar_Vector64_Double, ["DivideScalar.Vector64.Single"] = DivideScalar_Vector64_Single, - ["ExtractAndNarrowLow.Vector128.Int16"] = ExtractAndNarrowLow_Vector128_Int16, - ["ExtractAndNarrowLow.Vector128.Int32"] = ExtractAndNarrowLow_Vector128_Int32, - ["ExtractAndNarrowLow.Vector128.Int64"] = ExtractAndNarrowLow_Vector128_Int64, - ["ExtractAndNarrowLow.Vector128.UInt16"] = ExtractAndNarrowLow_Vector128_UInt16, - ["ExtractAndNarrowLow.Vector128.UInt32"] = ExtractAndNarrowLow_Vector128_UInt32, - ["ExtractAndNarrowLow.Vector128.UInt64"] = ExtractAndNarrowLow_Vector128_UInt64, - ["ExtractAndNarrowHigh.Vector128.Int16"] = ExtractAndNarrowHigh_Vector128_Int16, - ["ExtractAndNarrowHigh.Vector128.Int32"] = ExtractAndNarrowHigh_Vector128_Int32, - ["ExtractAndNarrowHigh.Vector128.Int64"] = ExtractAndNarrowHigh_Vector128_Int64, - ["ExtractAndNarrowHigh.Vector128.UInt16"] = ExtractAndNarrowHigh_Vector128_UInt16, - ["ExtractAndNarrowHigh.Vector128.UInt32"] = ExtractAndNarrowHigh_Vector128_UInt32, - ["ExtractAndNarrowHigh.Vector128.UInt64"] = ExtractAndNarrowHigh_Vector128_UInt64, + ["DuplicateSelectedScalarToVector64.V64.Byte.1"] = DuplicateSelectedScalarToVector64_V64_Byte_1, + ["DuplicateSelectedScalarToVector64.V64.Int16.1"] = DuplicateSelectedScalarToVector64_V64_Int16_1, + ["DuplicateSelectedScalarToVector64.V64.Int32.1"] = DuplicateSelectedScalarToVector64_V64_Int32_1, + ["DuplicateSelectedScalarToVector64.V64.SByte.1"] = DuplicateSelectedScalarToVector64_V64_SByte_1, + ["DuplicateSelectedScalarToVector64.V64.Single.1"] = DuplicateSelectedScalarToVector64_V64_Single_1, + ["DuplicateSelectedScalarToVector64.V64.UInt16.1"] = DuplicateSelectedScalarToVector64_V64_UInt16_1, + ["DuplicateSelectedScalarToVector64.V64.UInt32.1"] = DuplicateSelectedScalarToVector64_V64_UInt32_1, + ["DuplicateSelectedScalarToVector64.V128.Byte.8"] = DuplicateSelectedScalarToVector64_V128_Byte_8, + ["DuplicateSelectedScalarToVector64.V128.Int16.4"] = DuplicateSelectedScalarToVector64_V128_Int16_4, + ["DuplicateSelectedScalarToVector64.V128.Int32.2"] = DuplicateSelectedScalarToVector64_V128_Int32_2, + ["DuplicateSelectedScalarToVector64.V128.SByte.8"] = DuplicateSelectedScalarToVector64_V128_SByte_8, + ["DuplicateSelectedScalarToVector64.V128.Single.2"] = DuplicateSelectedScalarToVector64_V128_Single_2, + ["DuplicateSelectedScalarToVector64.V128.UInt16.4"] = DuplicateSelectedScalarToVector64_V128_UInt16_4, + ["DuplicateSelectedScalarToVector64.V128.UInt32.2"] = DuplicateSelectedScalarToVector64_V128_UInt32_2, + ["DuplicateSelectedScalarToVector128.V64.Byte.1"] = DuplicateSelectedScalarToVector128_V64_Byte_1, + ["DuplicateSelectedScalarToVector128.V64.Int16.1"] = DuplicateSelectedScalarToVector128_V64_Int16_1, + ["DuplicateSelectedScalarToVector128.V64.Int32.1"] = DuplicateSelectedScalarToVector128_V64_Int32_1, + ["DuplicateSelectedScalarToVector128.V64.SByte.1"] = DuplicateSelectedScalarToVector128_V64_SByte_1, + ["DuplicateSelectedScalarToVector128.V64.Single.1"] = DuplicateSelectedScalarToVector128_V64_Single_1, + ["DuplicateSelectedScalarToVector128.V64.UInt16.1"] = DuplicateSelectedScalarToVector128_V64_UInt16_1, + ["DuplicateSelectedScalarToVector128.V64.UInt32.1"] = DuplicateSelectedScalarToVector128_V64_UInt32_1, + ["DuplicateSelectedScalarToVector128.V128.Byte.8"] = DuplicateSelectedScalarToVector128_V128_Byte_8, + ["DuplicateSelectedScalarToVector128.V128.Int16.4"] = DuplicateSelectedScalarToVector128_V128_Int16_4, + ["DuplicateSelectedScalarToVector128.V128.Int32.2"] = DuplicateSelectedScalarToVector128_V128_Int32_2, + ["DuplicateSelectedScalarToVector128.V128.SByte.8"] = DuplicateSelectedScalarToVector128_V128_SByte_8, + ["DuplicateSelectedScalarToVector128.V128.Single.2"] = DuplicateSelectedScalarToVector128_V128_Single_2, + ["DuplicateSelectedScalarToVector128.V128.UInt16.4"] = DuplicateSelectedScalarToVector128_V128_UInt16_4, + ["DuplicateSelectedScalarToVector128.V128.UInt32.2"] = DuplicateSelectedScalarToVector128_V128_UInt32_2, + ["DuplicateToVector64.Byte"] = DuplicateToVector64_Byte, + ["DuplicateToVector64.Byte.31"] = DuplicateToVector64_Byte_31, + ["DuplicateToVector64.Int16"] = DuplicateToVector64_Int16, + ["DuplicateToVector64.Int16.31"] = DuplicateToVector64_Int16_31, + ["DuplicateToVector64.Int32"] = DuplicateToVector64_Int32, + ["DuplicateToVector64.Int32.31"] = DuplicateToVector64_Int32_31, + ["DuplicateToVector64.SByte"] = DuplicateToVector64_SByte, + ["DuplicateToVector64.SByte.31"] = DuplicateToVector64_SByte_31, + ["DuplicateToVector64.Single"] = DuplicateToVector64_Single, + ["DuplicateToVector64.Single.31"] = DuplicateToVector64_Single_31, + ["DuplicateToVector64.UInt16"] = DuplicateToVector64_UInt16, + ["DuplicateToVector64.UInt16.31"] = DuplicateToVector64_UInt16_31, + ["DuplicateToVector64.UInt32"] = DuplicateToVector64_UInt32, + ["DuplicateToVector64.UInt32.31"] = DuplicateToVector64_UInt32_31, + ["DuplicateToVector128.Byte"] = DuplicateToVector128_Byte, + ["DuplicateToVector128.Byte.31"] = DuplicateToVector128_Byte_31, + ["DuplicateToVector128.Int16"] = DuplicateToVector128_Int16, + ["DuplicateToVector128.Int16.31"] = DuplicateToVector128_Int16_31, + ["DuplicateToVector128.Int32"] = DuplicateToVector128_Int32, + ["DuplicateToVector128.Int32.31"] = DuplicateToVector128_Int32_31, + ["DuplicateToVector128.SByte"] = DuplicateToVector128_SByte, + ["DuplicateToVector128.SByte.31"] = DuplicateToVector128_SByte_31, + ["DuplicateToVector128.Single"] = DuplicateToVector128_Single, + ["DuplicateToVector128.Single.31"] = DuplicateToVector128_Single_31, + ["DuplicateToVector128.UInt16"] = DuplicateToVector128_UInt16, + ["DuplicateToVector128.UInt16.31"] = DuplicateToVector128_UInt16_31, + ["DuplicateToVector128.UInt32"] = DuplicateToVector128_UInt32, + ["DuplicateToVector128.UInt32.31"] = DuplicateToVector128_UInt32_31, + ["Extract.Vector64.Byte.1"] = Extract_Vector64_Byte_1, + ["Extract.Vector64.Int16.1"] = Extract_Vector64_Int16_1, + ["Extract.Vector64.Int32.1"] = Extract_Vector64_Int32_1, + ["Extract.Vector64.SByte.1"] = Extract_Vector64_SByte_1, + ["Extract.Vector64.Single.1"] = Extract_Vector64_Single_1, + ["Extract.Vector64.UInt16.1"] = Extract_Vector64_UInt16_1, + ["Extract.Vector64.UInt32.1"] = Extract_Vector64_UInt32_1, + ["Extract.Vector128.Byte.1"] = Extract_Vector128_Byte_1, + ["Extract.Vector128.Double.1"] = Extract_Vector128_Double_1, + ["Extract.Vector128.Int16.1"] = Extract_Vector128_Int16_1, + ["Extract.Vector128.Int32.1"] = Extract_Vector128_Int32_1, + ["Extract.Vector128.Int64.1"] = Extract_Vector128_Int64_1, + ["Extract.Vector128.SByte.1"] = Extract_Vector128_SByte_1, + ["Extract.Vector128.Single.1"] = Extract_Vector128_Single_1, + ["Extract.Vector128.UInt16.1"] = Extract_Vector128_UInt16_1, + ["Extract.Vector128.UInt32.1"] = Extract_Vector128_UInt32_1, + ["Extract.Vector128.UInt64.1"] = Extract_Vector128_UInt64_1, + ["ExtractNarrowingUpper.Vector128.Int16"] = ExtractNarrowingUpper_Vector128_Int16, + ["ExtractNarrowingUpper.Vector128.Int32"] = ExtractNarrowingUpper_Vector128_Int32, + ["ExtractNarrowingUpper.Vector128.Int64"] = ExtractNarrowingUpper_Vector128_Int64, + ["ExtractNarrowingUpper.Vector128.UInt16"] = ExtractNarrowingUpper_Vector128_UInt16, + ["ExtractNarrowingUpper.Vector128.UInt32"] = ExtractNarrowingUpper_Vector128_UInt32, + ["ExtractNarrowingUpper.Vector128.UInt64"] = ExtractNarrowingUpper_Vector128_UInt64, + ["ExtractNarrowingLower.Vector128.Int16"] = ExtractNarrowingLower_Vector128_Int16, + ["ExtractNarrowingLower.Vector128.Int32"] = ExtractNarrowingLower_Vector128_Int32, + ["ExtractNarrowingLower.Vector128.Int64"] = ExtractNarrowingLower_Vector128_Int64, + ["ExtractNarrowingLower.Vector128.UInt16"] = ExtractNarrowingLower_Vector128_UInt16, + ["ExtractNarrowingLower.Vector128.UInt32"] = ExtractNarrowingLower_Vector128_UInt32, + ["ExtractNarrowingLower.Vector128.UInt64"] = ExtractNarrowingLower_Vector128_UInt64, + ["ExtractVector64.Byte.1"] = ExtractVector64_Byte_1, + ["ExtractVector64.Int16.1"] = ExtractVector64_Int16_1, + ["ExtractVector64.Int32.1"] = ExtractVector64_Int32_1, + ["ExtractVector64.SByte.1"] = ExtractVector64_SByte_1, + ["ExtractVector64.Single.1"] = ExtractVector64_Single_1, + ["ExtractVector64.UInt16.1"] = ExtractVector64_UInt16_1, + ["ExtractVector64.UInt32.1"] = ExtractVector64_UInt32_1, + ["ExtractVector128.Byte.1"] = ExtractVector128_Byte_1, + ["ExtractVector128.Double.1"] = ExtractVector128_Double_1, + ["ExtractVector128.Int16.1"] = ExtractVector128_Int16_1, + ["ExtractVector128.Int32.1"] = ExtractVector128_Int32_1, + ["ExtractVector128.Int64.1"] = ExtractVector128_Int64_1, + ["ExtractVector128.SByte.1"] = ExtractVector128_SByte_1, + ["ExtractVector128.Single.1"] = ExtractVector128_Single_1, + ["ExtractVector128.UInt16.1"] = ExtractVector128_UInt16_1, + ["ExtractVector128.UInt32.1"] = ExtractVector128_UInt32_1, + ["ExtractVector128.UInt64.1"] = ExtractVector128_UInt64_1, + ["FusedAddHalving.Vector64.Byte"] = FusedAddHalving_Vector64_Byte, + ["FusedAddHalving.Vector64.Int16"] = FusedAddHalving_Vector64_Int16, + ["FusedAddHalving.Vector64.Int32"] = FusedAddHalving_Vector64_Int32, + ["FusedAddHalving.Vector64.SByte"] = FusedAddHalving_Vector64_SByte, + ["FusedAddHalving.Vector64.UInt16"] = FusedAddHalving_Vector64_UInt16, + ["FusedAddHalving.Vector64.UInt32"] = FusedAddHalving_Vector64_UInt32, + ["FusedAddHalving.Vector128.Byte"] = FusedAddHalving_Vector128_Byte, + ["FusedAddHalving.Vector128.Int16"] = FusedAddHalving_Vector128_Int16, + ["FusedAddHalving.Vector128.Int32"] = FusedAddHalving_Vector128_Int32, + ["FusedAddHalving.Vector128.SByte"] = FusedAddHalving_Vector128_SByte, + ["FusedAddHalving.Vector128.UInt16"] = FusedAddHalving_Vector128_UInt16, + ["FusedAddHalving.Vector128.UInt32"] = FusedAddHalving_Vector128_UInt32, + ["FusedAddRoundedHalving.Vector64.Byte"] = FusedAddRoundedHalving_Vector64_Byte, + ["FusedAddRoundedHalving.Vector64.Int16"] = FusedAddRoundedHalving_Vector64_Int16, + ["FusedAddRoundedHalving.Vector64.Int32"] = FusedAddRoundedHalving_Vector64_Int32, + ["FusedAddRoundedHalving.Vector64.SByte"] = FusedAddRoundedHalving_Vector64_SByte, + ["FusedAddRoundedHalving.Vector64.UInt16"] = FusedAddRoundedHalving_Vector64_UInt16, + ["FusedAddRoundedHalving.Vector64.UInt32"] = FusedAddRoundedHalving_Vector64_UInt32, + ["FusedAddRoundedHalving.Vector128.Byte"] = FusedAddRoundedHalving_Vector128_Byte, + ["FusedAddRoundedHalving.Vector128.Int16"] = FusedAddRoundedHalving_Vector128_Int16, + ["FusedAddRoundedHalving.Vector128.Int32"] = FusedAddRoundedHalving_Vector128_Int32, + ["FusedAddRoundedHalving.Vector128.SByte"] = FusedAddRoundedHalving_Vector128_SByte, + ["FusedAddRoundedHalving.Vector128.UInt16"] = FusedAddRoundedHalving_Vector128_UInt16, + ["FusedAddRoundedHalving.Vector128.UInt32"] = FusedAddRoundedHalving_Vector128_UInt32, ["FusedMultiplyAdd.Vector64.Single"] = FusedMultiplyAdd_Vector64_Single, ["FusedMultiplyAdd.Vector128.Single"] = FusedMultiplyAdd_Vector128_Single, ["FusedMultiplyAddScalar.Vector64.Double"] = FusedMultiplyAddScalar_Vector64_Double, @@ -253,6 +479,35 @@ static Program() ["FusedMultiplySubtractScalar.Vector64.Single"] = FusedMultiplySubtractScalar_Vector64_Single, ["FusedMultiplySubtractNegatedScalar.Vector64.Double"] = FusedMultiplySubtractNegatedScalar_Vector64_Double, ["FusedMultiplySubtractNegatedScalar.Vector64.Single"] = FusedMultiplySubtractNegatedScalar_Vector64_Single, + ["FusedSubtractHalving.Vector64.Byte"] = FusedSubtractHalving_Vector64_Byte, + ["FusedSubtractHalving.Vector64.Int16"] = FusedSubtractHalving_Vector64_Int16, + ["FusedSubtractHalving.Vector64.Int32"] = FusedSubtractHalving_Vector64_Int32, + ["FusedSubtractHalving.Vector64.SByte"] = FusedSubtractHalving_Vector64_SByte, + ["FusedSubtractHalving.Vector64.UInt16"] = FusedSubtractHalving_Vector64_UInt16, + ["FusedSubtractHalving.Vector64.UInt32"] = FusedSubtractHalving_Vector64_UInt32, + ["FusedSubtractHalving.Vector128.Byte"] = FusedSubtractHalving_Vector128_Byte, + ["FusedSubtractHalving.Vector128.Int16"] = FusedSubtractHalving_Vector128_Int16, + ["FusedSubtractHalving.Vector128.Int32"] = FusedSubtractHalving_Vector128_Int32, + ["FusedSubtractHalving.Vector128.SByte"] = FusedSubtractHalving_Vector128_SByte, + ["FusedSubtractHalving.Vector128.UInt16"] = FusedSubtractHalving_Vector128_UInt16, + ["FusedSubtractHalving.Vector128.UInt32"] = FusedSubtractHalving_Vector128_UInt32, + ["Insert.Vector64.Byte.1"] = Insert_Vector64_Byte_1, + ["Insert.Vector64.Int16.1"] = Insert_Vector64_Int16_1, + ["Insert.Vector64.Int32.1"] = Insert_Vector64_Int32_1, + ["Insert.Vector64.SByte.1"] = Insert_Vector64_SByte_1, + ["Insert.Vector64.Single.1"] = Insert_Vector64_Single_1, + ["Insert.Vector64.UInt16.1"] = Insert_Vector64_UInt16_1, + ["Insert.Vector64.UInt32.1"] = Insert_Vector64_UInt32_1, + ["Insert.Vector128.Byte.1"] = Insert_Vector128_Byte_1, + ["Insert.Vector128.Double.1"] = Insert_Vector128_Double_1, + ["Insert.Vector128.Int16.1"] = Insert_Vector128_Int16_1, + ["Insert.Vector128.Int32.1"] = Insert_Vector128_Int32_1, + ["Insert.Vector128.Int64.1"] = Insert_Vector128_Int64_1, + ["Insert.Vector128.SByte.1"] = Insert_Vector128_SByte_1, + ["Insert.Vector128.Single.1"] = Insert_Vector128_Single_1, + ["Insert.Vector128.UInt16.1"] = Insert_Vector128_UInt16_1, + ["Insert.Vector128.UInt32.1"] = Insert_Vector128_UInt32_1, + ["Insert.Vector128.UInt64.1"] = Insert_Vector128_UInt64_1, ["LeadingSignCount.Vector64.Int16"] = LeadingSignCount_Vector64_Int16, ["LeadingSignCount.Vector64.Int32"] = LeadingSignCount_Vector64_Int32, ["LeadingSignCount.Vector64.SByte"] = LeadingSignCount_Vector64_SByte, @@ -381,6 +636,42 @@ static Program() ["MultiplySubtract.Vector128.SByte"] = MultiplySubtract_Vector128_SByte, ["MultiplySubtract.Vector128.UInt16"] = MultiplySubtract_Vector128_UInt16, ["MultiplySubtract.Vector128.UInt32"] = MultiplySubtract_Vector128_UInt32, + ["MultiplyWideningLower.Vector64.Byte"] = MultiplyWideningLower_Vector64_Byte, + ["MultiplyWideningLower.Vector64.Int16"] = MultiplyWideningLower_Vector64_Int16, + ["MultiplyWideningLower.Vector64.Int32"] = MultiplyWideningLower_Vector64_Int32, + ["MultiplyWideningLower.Vector64.SByte"] = MultiplyWideningLower_Vector64_SByte, + ["MultiplyWideningLower.Vector64.UInt16"] = MultiplyWideningLower_Vector64_UInt16, + ["MultiplyWideningLower.Vector64.UInt32"] = MultiplyWideningLower_Vector64_UInt32, + ["MultiplyWideningLowerAndAdd.Vector64.Byte"] = MultiplyWideningLowerAndAdd_Vector64_Byte, + ["MultiplyWideningLowerAndAdd.Vector64.Int16"] = MultiplyWideningLowerAndAdd_Vector64_Int16, + ["MultiplyWideningLowerAndAdd.Vector64.Int32"] = MultiplyWideningLowerAndAdd_Vector64_Int32, + ["MultiplyWideningLowerAndAdd.Vector64.SByte"] = MultiplyWideningLowerAndAdd_Vector64_SByte, + ["MultiplyWideningLowerAndAdd.Vector64.UInt16"] = MultiplyWideningLowerAndAdd_Vector64_UInt16, + ["MultiplyWideningLowerAndAdd.Vector64.UInt32"] = MultiplyWideningLowerAndAdd_Vector64_UInt32, + ["MultiplyWideningLowerAndSubtract.Vector64.Byte"] = MultiplyWideningLowerAndSubtract_Vector64_Byte, + ["MultiplyWideningLowerAndSubtract.Vector64.Int16"] = MultiplyWideningLowerAndSubtract_Vector64_Int16, + ["MultiplyWideningLowerAndSubtract.Vector64.Int32"] = MultiplyWideningLowerAndSubtract_Vector64_Int32, + ["MultiplyWideningLowerAndSubtract.Vector64.SByte"] = MultiplyWideningLowerAndSubtract_Vector64_SByte, + ["MultiplyWideningLowerAndSubtract.Vector64.UInt16"] = MultiplyWideningLowerAndSubtract_Vector64_UInt16, + ["MultiplyWideningLowerAndSubtract.Vector64.UInt32"] = MultiplyWideningLowerAndSubtract_Vector64_UInt32, + ["MultiplyWideningUpper.Vector128.Byte"] = MultiplyWideningUpper_Vector128_Byte, + ["MultiplyWideningUpper.Vector128.Int16"] = MultiplyWideningUpper_Vector128_Int16, + ["MultiplyWideningUpper.Vector128.Int32"] = MultiplyWideningUpper_Vector128_Int32, + ["MultiplyWideningUpper.Vector128.SByte"] = MultiplyWideningUpper_Vector128_SByte, + ["MultiplyWideningUpper.Vector128.UInt16"] = MultiplyWideningUpper_Vector128_UInt16, + ["MultiplyWideningUpper.Vector128.UInt32"] = MultiplyWideningUpper_Vector128_UInt32, + ["MultiplyWideningUpperAndAdd.Vector128.Byte"] = MultiplyWideningUpperAndAdd_Vector128_Byte, + ["MultiplyWideningUpperAndAdd.Vector128.Int16"] = MultiplyWideningUpperAndAdd_Vector128_Int16, + ["MultiplyWideningUpperAndAdd.Vector128.Int32"] = MultiplyWideningUpperAndAdd_Vector128_Int32, + ["MultiplyWideningUpperAndAdd.Vector128.SByte"] = MultiplyWideningUpperAndAdd_Vector128_SByte, + ["MultiplyWideningUpperAndAdd.Vector128.UInt16"] = MultiplyWideningUpperAndAdd_Vector128_UInt16, + ["MultiplyWideningUpperAndAdd.Vector128.UInt32"] = MultiplyWideningUpperAndAdd_Vector128_UInt32, + ["MultiplyWideningUpperAndSubtract.Vector128.Byte"] = MultiplyWideningUpperAndSubtract_Vector128_Byte, + ["MultiplyWideningUpperAndSubtract.Vector128.Int16"] = MultiplyWideningUpperAndSubtract_Vector128_Int16, + ["MultiplyWideningUpperAndSubtract.Vector128.Int32"] = MultiplyWideningUpperAndSubtract_Vector128_Int32, + ["MultiplyWideningUpperAndSubtract.Vector128.SByte"] = MultiplyWideningUpperAndSubtract_Vector128_SByte, + ["MultiplyWideningUpperAndSubtract.Vector128.UInt16"] = MultiplyWideningUpperAndSubtract_Vector128_UInt16, + ["MultiplyWideningUpperAndSubtract.Vector128.UInt32"] = MultiplyWideningUpperAndSubtract_Vector128_UInt32, ["Negate.Vector64.Int16"] = Negate_Vector64_Int16, ["Negate.Vector64.Int32"] = Negate_Vector64_Int32, ["Negate.Vector64.SByte"] = Negate_Vector64_SByte, @@ -455,6 +746,10 @@ static Program() ["PolynomialMultiply.Vector64.SByte"] = PolynomialMultiply_Vector64_SByte, ["PolynomialMultiply.Vector128.Byte"] = PolynomialMultiply_Vector128_Byte, ["PolynomialMultiply.Vector128.SByte"] = PolynomialMultiply_Vector128_SByte, + ["PolynomialMultiplyWideningLower.Vector64.Byte"] = PolynomialMultiplyWideningLower_Vector64_Byte, + ["PolynomialMultiplyWideningLower.Vector64.SByte"] = PolynomialMultiplyWideningLower_Vector64_SByte, + ["PolynomialMultiplyWideningUpper.Vector128.Byte"] = PolynomialMultiplyWideningUpper_Vector128_Byte, + ["PolynomialMultiplyWideningUpper.Vector128.SByte"] = PolynomialMultiplyWideningUpper_Vector128_SByte, ["PopCount.Vector64.Byte"] = PopCount_Vector64_Byte, ["PopCount.Vector64.SByte"] = PopCount_Vector64_SByte, ["PopCount.Vector128.Byte"] = PopCount_Vector128_Byte, @@ -471,6 +766,327 @@ static Program() ["ReciprocalSquareRootStep.Vector128.Single"] = ReciprocalSquareRootStep_Vector128_Single, ["ReciprocalStep.Vector64.Single"] = ReciprocalStep_Vector64_Single, ["ReciprocalStep.Vector128.Single"] = ReciprocalStep_Vector128_Single, + ["ShiftArithmetic.Vector64.Int16"] = ShiftArithmetic_Vector64_Int16, + ["ShiftArithmetic.Vector64.Int32"] = ShiftArithmetic_Vector64_Int32, + ["ShiftArithmetic.Vector64.SByte"] = ShiftArithmetic_Vector64_SByte, + ["ShiftArithmetic.Vector128.Int16"] = ShiftArithmetic_Vector128_Int16, + ["ShiftArithmetic.Vector128.Int32"] = ShiftArithmetic_Vector128_Int32, + ["ShiftArithmetic.Vector128.Int64"] = ShiftArithmetic_Vector128_Int64, + ["ShiftArithmetic.Vector128.SByte"] = ShiftArithmetic_Vector128_SByte, + ["ShiftArithmeticRounded.Vector64.Int16"] = ShiftArithmeticRounded_Vector64_Int16, + ["ShiftArithmeticRounded.Vector64.Int32"] = ShiftArithmeticRounded_Vector64_Int32, + ["ShiftArithmeticRounded.Vector64.SByte"] = ShiftArithmeticRounded_Vector64_SByte, + ["ShiftArithmeticRounded.Vector128.Int16"] = ShiftArithmeticRounded_Vector128_Int16, + ["ShiftArithmeticRounded.Vector128.Int32"] = ShiftArithmeticRounded_Vector128_Int32, + ["ShiftArithmeticRounded.Vector128.Int64"] = ShiftArithmeticRounded_Vector128_Int64, + ["ShiftArithmeticRounded.Vector128.SByte"] = ShiftArithmeticRounded_Vector128_SByte, + ["ShiftArithmeticRoundedSaturate.Vector64.Int16"] = ShiftArithmeticRoundedSaturate_Vector64_Int16, + ["ShiftArithmeticRoundedSaturate.Vector64.Int32"] = ShiftArithmeticRoundedSaturate_Vector64_Int32, + ["ShiftArithmeticRoundedSaturate.Vector64.SByte"] = ShiftArithmeticRoundedSaturate_Vector64_SByte, + ["ShiftArithmeticRoundedSaturate.Vector128.Int16"] = ShiftArithmeticRoundedSaturate_Vector128_Int16, + ["ShiftArithmeticRoundedSaturate.Vector128.Int32"] = ShiftArithmeticRoundedSaturate_Vector128_Int32, + ["ShiftArithmeticRoundedSaturate.Vector128.Int64"] = ShiftArithmeticRoundedSaturate_Vector128_Int64, + ["ShiftArithmeticRoundedSaturate.Vector128.SByte"] = ShiftArithmeticRoundedSaturate_Vector128_SByte, + ["ShiftArithmeticRoundedSaturateScalar.Vector64.Int64"] = ShiftArithmeticRoundedSaturateScalar_Vector64_Int64, + ["ShiftArithmeticRoundedScalar.Vector64.Int64"] = ShiftArithmeticRoundedScalar_Vector64_Int64, + ["ShiftArithmeticSaturate.Vector64.Int16"] = ShiftArithmeticSaturate_Vector64_Int16, + ["ShiftArithmeticSaturate.Vector64.Int32"] = ShiftArithmeticSaturate_Vector64_Int32, + ["ShiftArithmeticSaturate.Vector64.SByte"] = ShiftArithmeticSaturate_Vector64_SByte, + ["ShiftArithmeticSaturate.Vector128.Int16"] = ShiftArithmeticSaturate_Vector128_Int16, + ["ShiftArithmeticSaturate.Vector128.Int32"] = ShiftArithmeticSaturate_Vector128_Int32, + ["ShiftArithmeticSaturate.Vector128.Int64"] = ShiftArithmeticSaturate_Vector128_Int64, + ["ShiftArithmeticSaturate.Vector128.SByte"] = ShiftArithmeticSaturate_Vector128_SByte, + ["ShiftArithmeticSaturateScalar.Vector64.Int64"] = ShiftArithmeticSaturateScalar_Vector64_Int64, + ["ShiftArithmeticScalar.Vector64.Int64"] = ShiftArithmeticScalar_Vector64_Int64, + ["ShiftLeftLogical.Vector64.Byte.1"] = ShiftLeftLogical_Vector64_Byte_1, + ["ShiftLeftLogical.Vector64.Int16.1"] = ShiftLeftLogical_Vector64_Int16_1, + ["ShiftLeftLogical.Vector64.Int32.1"] = ShiftLeftLogical_Vector64_Int32_1, + ["ShiftLeftLogical.Vector64.SByte.1"] = ShiftLeftLogical_Vector64_SByte_1, + ["ShiftLeftLogical.Vector64.UInt16.1"] = ShiftLeftLogical_Vector64_UInt16_1, + ["ShiftLeftLogical.Vector64.UInt32.1"] = ShiftLeftLogical_Vector64_UInt32_1, + ["ShiftLeftLogical.Vector128.Byte.1"] = ShiftLeftLogical_Vector128_Byte_1, + ["ShiftLeftLogical.Vector128.Int16.1"] = ShiftLeftLogical_Vector128_Int16_1, + ["ShiftLeftLogical.Vector128.Int64.1"] = ShiftLeftLogical_Vector128_Int64_1, + ["ShiftLeftLogical.Vector128.SByte.1"] = ShiftLeftLogical_Vector128_SByte_1, + ["ShiftLeftLogical.Vector128.UInt16.1"] = ShiftLeftLogical_Vector128_UInt16_1, + ["ShiftLeftLogical.Vector128.UInt32.1"] = ShiftLeftLogical_Vector128_UInt32_1, + ["ShiftLeftLogical.Vector128.UInt64.1"] = ShiftLeftLogical_Vector128_UInt64_1, + ["ShiftLeftLogicalSaturate.Vector64.Byte.1"] = ShiftLeftLogicalSaturate_Vector64_Byte_1, + ["ShiftLeftLogicalSaturate.Vector64.Int16.1"] = ShiftLeftLogicalSaturate_Vector64_Int16_1, + ["ShiftLeftLogicalSaturate.Vector64.Int32.1"] = ShiftLeftLogicalSaturate_Vector64_Int32_1, + ["ShiftLeftLogicalSaturate.Vector64.SByte.1"] = ShiftLeftLogicalSaturate_Vector64_SByte_1, + ["ShiftLeftLogicalSaturate.Vector64.UInt16.1"] = ShiftLeftLogicalSaturate_Vector64_UInt16_1, + ["ShiftLeftLogicalSaturate.Vector64.UInt32.1"] = ShiftLeftLogicalSaturate_Vector64_UInt32_1, + ["ShiftLeftLogicalSaturate.Vector128.Byte.1"] = ShiftLeftLogicalSaturate_Vector128_Byte_1, + ["ShiftLeftLogicalSaturate.Vector128.Int16.1"] = ShiftLeftLogicalSaturate_Vector128_Int16_1, + ["ShiftLeftLogicalSaturate.Vector128.Int32.1"] = ShiftLeftLogicalSaturate_Vector128_Int32_1, + ["ShiftLeftLogicalSaturate.Vector128.Int64.1"] = ShiftLeftLogicalSaturate_Vector128_Int64_1, + ["ShiftLeftLogicalSaturate.Vector128.SByte.1"] = ShiftLeftLogicalSaturate_Vector128_SByte_1, + ["ShiftLeftLogicalSaturate.Vector128.UInt16.1"] = ShiftLeftLogicalSaturate_Vector128_UInt16_1, + ["ShiftLeftLogicalSaturate.Vector128.UInt32.1"] = ShiftLeftLogicalSaturate_Vector128_UInt32_1, + ["ShiftLeftLogicalSaturate.Vector128.UInt64.1"] = ShiftLeftLogicalSaturate_Vector128_UInt64_1, + ["ShiftLeftLogicalSaturateScalar.Vector64.Int64.1"] = ShiftLeftLogicalSaturateScalar_Vector64_Int64_1, + ["ShiftLeftLogicalSaturateScalar.Vector64.UInt64.1"] = ShiftLeftLogicalSaturateScalar_Vector64_UInt64_1, + ["ShiftLeftLogicalSaturateUnsigned.Vector64.Int16.1"] = ShiftLeftLogicalSaturateUnsigned_Vector64_Int16_1, + ["ShiftLeftLogicalSaturateUnsigned.Vector64.Int32.1"] = ShiftLeftLogicalSaturateUnsigned_Vector64_Int32_1, + ["ShiftLeftLogicalSaturateUnsigned.Vector64.SByte.1"] = ShiftLeftLogicalSaturateUnsigned_Vector64_SByte_1, + ["ShiftLeftLogicalSaturateUnsigned.Vector128.Int16.1"] = ShiftLeftLogicalSaturateUnsigned_Vector128_Int16_1, + ["ShiftLeftLogicalSaturateUnsigned.Vector128.Int32.1"] = ShiftLeftLogicalSaturateUnsigned_Vector128_Int32_1, + ["ShiftLeftLogicalSaturateUnsigned.Vector128.Int64.1"] = ShiftLeftLogicalSaturateUnsigned_Vector128_Int64_1, + ["ShiftLeftLogicalSaturateUnsigned.Vector128.SByte.1"] = ShiftLeftLogicalSaturateUnsigned_Vector128_SByte_1, + ["ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int64.1"] = ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int64_1, + ["ShiftLeftLogicalScalar.Vector64.Int64.1"] = ShiftLeftLogicalScalar_Vector64_Int64_1, + ["ShiftLeftLogicalScalar.Vector64.UInt64.1"] = ShiftLeftLogicalScalar_Vector64_UInt64_1, + ["ShiftLeftLogicalWideningLower.Vector64.Byte.1"] = ShiftLeftLogicalWideningLower_Vector64_Byte_1, + ["ShiftLeftLogicalWideningLower.Vector64.Int16.1"] = ShiftLeftLogicalWideningLower_Vector64_Int16_1, + ["ShiftLeftLogicalWideningLower.Vector64.Int32.1"] = ShiftLeftLogicalWideningLower_Vector64_Int32_1, + ["ShiftLeftLogicalWideningLower.Vector64.SByte.1"] = ShiftLeftLogicalWideningLower_Vector64_SByte_1, + ["ShiftLeftLogicalWideningLower.Vector64.UInt16.1"] = ShiftLeftLogicalWideningLower_Vector64_UInt16_1, + ["ShiftLeftLogicalWideningLower.Vector64.UInt32.1"] = ShiftLeftLogicalWideningLower_Vector64_UInt32_1, + ["ShiftLeftLogicalWideningUpper.Vector128.Byte.1"] = ShiftLeftLogicalWideningUpper_Vector128_Byte_1, + ["ShiftLeftLogicalWideningUpper.Vector128.Int16.1"] = ShiftLeftLogicalWideningUpper_Vector128_Int16_1, + ["ShiftLeftLogicalWideningUpper.Vector128.Int32.1"] = ShiftLeftLogicalWideningUpper_Vector128_Int32_1, + ["ShiftLeftLogicalWideningUpper.Vector128.SByte.1"] = ShiftLeftLogicalWideningUpper_Vector128_SByte_1, + ["ShiftLeftLogicalWideningUpper.Vector128.UInt16.1"] = ShiftLeftLogicalWideningUpper_Vector128_UInt16_1, + ["ShiftLeftLogicalWideningUpper.Vector128.UInt32.1"] = ShiftLeftLogicalWideningUpper_Vector128_UInt32_1, + ["ShiftLogical.Vector64.Byte"] = ShiftLogical_Vector64_Byte, + ["ShiftLogical.Vector64.Int16"] = ShiftLogical_Vector64_Int16, + ["ShiftLogical.Vector64.Int32"] = ShiftLogical_Vector64_Int32, + ["ShiftLogical.Vector64.SByte"] = ShiftLogical_Vector64_SByte, + ["ShiftLogical.Vector64.UInt16"] = ShiftLogical_Vector64_UInt16, + ["ShiftLogical.Vector64.UInt32"] = ShiftLogical_Vector64_UInt32, + ["ShiftLogical.Vector128.Byte"] = ShiftLogical_Vector128_Byte, + ["ShiftLogical.Vector128.Int16"] = ShiftLogical_Vector128_Int16, + ["ShiftLogical.Vector128.Int32"] = ShiftLogical_Vector128_Int32, + ["ShiftLogical.Vector128.Int64"] = ShiftLogical_Vector128_Int64, + ["ShiftLogical.Vector128.SByte"] = ShiftLogical_Vector128_SByte, + ["ShiftLogical.Vector128.UInt16"] = ShiftLogical_Vector128_UInt16, + ["ShiftLogical.Vector128.UInt32"] = ShiftLogical_Vector128_UInt32, + ["ShiftLogical.Vector128.UInt64"] = ShiftLogical_Vector128_UInt64, + ["ShiftLogicalRounded.Vector64.Byte"] = ShiftLogicalRounded_Vector64_Byte, + ["ShiftLogicalRounded.Vector64.Int16"] = ShiftLogicalRounded_Vector64_Int16, + ["ShiftLogicalRounded.Vector64.Int32"] = ShiftLogicalRounded_Vector64_Int32, + ["ShiftLogicalRounded.Vector64.SByte"] = ShiftLogicalRounded_Vector64_SByte, + ["ShiftLogicalRounded.Vector64.UInt16"] = ShiftLogicalRounded_Vector64_UInt16, + ["ShiftLogicalRounded.Vector64.UInt32"] = ShiftLogicalRounded_Vector64_UInt32, + ["ShiftLogicalRounded.Vector128.Byte"] = ShiftLogicalRounded_Vector128_Byte, + ["ShiftLogicalRounded.Vector128.Int16"] = ShiftLogicalRounded_Vector128_Int16, + ["ShiftLogicalRounded.Vector128.Int32"] = ShiftLogicalRounded_Vector128_Int32, + ["ShiftLogicalRounded.Vector128.Int64"] = ShiftLogicalRounded_Vector128_Int64, + ["ShiftLogicalRounded.Vector128.SByte"] = ShiftLogicalRounded_Vector128_SByte, + ["ShiftLogicalRounded.Vector128.UInt16"] = ShiftLogicalRounded_Vector128_UInt16, + ["ShiftLogicalRounded.Vector128.UInt32"] = ShiftLogicalRounded_Vector128_UInt32, + ["ShiftLogicalRounded.Vector128.UInt64"] = ShiftLogicalRounded_Vector128_UInt64, + ["ShiftLogicalRoundedSaturate.Vector64.Byte"] = ShiftLogicalRoundedSaturate_Vector64_Byte, + ["ShiftLogicalRoundedSaturate.Vector64.Int16"] = ShiftLogicalRoundedSaturate_Vector64_Int16, + ["ShiftLogicalRoundedSaturate.Vector64.Int32"] = ShiftLogicalRoundedSaturate_Vector64_Int32, + ["ShiftLogicalRoundedSaturate.Vector64.SByte"] = ShiftLogicalRoundedSaturate_Vector64_SByte, + ["ShiftLogicalRoundedSaturate.Vector64.UInt16"] = ShiftLogicalRoundedSaturate_Vector64_UInt16, + ["ShiftLogicalRoundedSaturate.Vector64.UInt32"] = ShiftLogicalRoundedSaturate_Vector64_UInt32, + ["ShiftLogicalRoundedSaturate.Vector128.Byte"] = ShiftLogicalRoundedSaturate_Vector128_Byte, + ["ShiftLogicalRoundedSaturate.Vector128.Int16"] = ShiftLogicalRoundedSaturate_Vector128_Int16, + ["ShiftLogicalRoundedSaturate.Vector128.Int32"] = ShiftLogicalRoundedSaturate_Vector128_Int32, + ["ShiftLogicalRoundedSaturate.Vector128.Int64"] = ShiftLogicalRoundedSaturate_Vector128_Int64, + ["ShiftLogicalRoundedSaturate.Vector128.SByte"] = ShiftLogicalRoundedSaturate_Vector128_SByte, + ["ShiftLogicalRoundedSaturate.Vector128.UInt16"] = ShiftLogicalRoundedSaturate_Vector128_UInt16, + ["ShiftLogicalRoundedSaturate.Vector128.UInt32"] = ShiftLogicalRoundedSaturate_Vector128_UInt32, + ["ShiftLogicalRoundedSaturate.Vector128.UInt64"] = ShiftLogicalRoundedSaturate_Vector128_UInt64, + ["ShiftLogicalRoundedSaturateScalar.Vector64.Int64"] = ShiftLogicalRoundedSaturateScalar_Vector64_Int64, + ["ShiftLogicalRoundedSaturateScalar.Vector64.UInt64"] = ShiftLogicalRoundedSaturateScalar_Vector64_UInt64, + ["ShiftLogicalRoundedScalar.Vector64.Int64"] = ShiftLogicalRoundedScalar_Vector64_Int64, + ["ShiftLogicalRoundedScalar.Vector64.UInt64"] = ShiftLogicalRoundedScalar_Vector64_UInt64, + ["ShiftLogicalSaturate.Vector64.Byte"] = ShiftLogicalSaturate_Vector64_Byte, + ["ShiftLogicalSaturate.Vector64.Int16"] = ShiftLogicalSaturate_Vector64_Int16, + ["ShiftLogicalSaturate.Vector64.Int32"] = ShiftLogicalSaturate_Vector64_Int32, + ["ShiftLogicalSaturate.Vector64.SByte"] = ShiftLogicalSaturate_Vector64_SByte, + ["ShiftLogicalSaturate.Vector64.UInt16"] = ShiftLogicalSaturate_Vector64_UInt16, + ["ShiftLogicalSaturate.Vector64.UInt32"] = ShiftLogicalSaturate_Vector64_UInt32, + ["ShiftLogicalSaturate.Vector128.Byte"] = ShiftLogicalSaturate_Vector128_Byte, + ["ShiftLogicalSaturate.Vector128.Int16"] = ShiftLogicalSaturate_Vector128_Int16, + ["ShiftLogicalSaturate.Vector128.Int32"] = ShiftLogicalSaturate_Vector128_Int32, + ["ShiftLogicalSaturate.Vector128.Int64"] = ShiftLogicalSaturate_Vector128_Int64, + ["ShiftLogicalSaturate.Vector128.SByte"] = ShiftLogicalSaturate_Vector128_SByte, + ["ShiftLogicalSaturate.Vector128.UInt16"] = ShiftLogicalSaturate_Vector128_UInt16, + ["ShiftLogicalSaturate.Vector128.UInt32"] = ShiftLogicalSaturate_Vector128_UInt32, + ["ShiftLogicalSaturate.Vector128.UInt64"] = ShiftLogicalSaturate_Vector128_UInt64, + ["ShiftLogicalSaturateScalar.Vector64.Int64"] = ShiftLogicalSaturateScalar_Vector64_Int64, + ["ShiftLogicalSaturateScalar.Vector64.UInt64"] = ShiftLogicalSaturateScalar_Vector64_UInt64, + ["ShiftLogicalScalar.Vector64.Int64"] = ShiftLogicalScalar_Vector64_Int64, + ["ShiftLogicalScalar.Vector64.UInt64"] = ShiftLogicalScalar_Vector64_UInt64, + ["ShiftRightArithmetic.Vector64.Int16.1"] = ShiftRightArithmetic_Vector64_Int16_1, + ["ShiftRightArithmetic.Vector64.Int32.1"] = ShiftRightArithmetic_Vector64_Int32_1, + ["ShiftRightArithmetic.Vector64.SByte.1"] = ShiftRightArithmetic_Vector64_SByte_1, + ["ShiftRightArithmetic.Vector128.Int16.1"] = ShiftRightArithmetic_Vector128_Int16_1, + ["ShiftRightArithmetic.Vector128.Int32.1"] = ShiftRightArithmetic_Vector128_Int32_1, + ["ShiftRightArithmetic.Vector128.Int64.1"] = ShiftRightArithmetic_Vector128_Int64_1, + ["ShiftRightArithmetic.Vector128.SByte.1"] = ShiftRightArithmetic_Vector128_SByte_1, + ["ShiftRightArithmeticAdd.Vector64.Int16.1"] = ShiftRightArithmeticAdd_Vector64_Int16_1, + ["ShiftRightArithmeticAdd.Vector64.Int32.1"] = ShiftRightArithmeticAdd_Vector64_Int32_1, + ["ShiftRightArithmeticAdd.Vector64.SByte.1"] = ShiftRightArithmeticAdd_Vector64_SByte_1, + ["ShiftRightArithmeticAdd.Vector128.Int16.1"] = ShiftRightArithmeticAdd_Vector128_Int16_1, + ["ShiftRightArithmeticAdd.Vector128.Int32.1"] = ShiftRightArithmeticAdd_Vector128_Int32_1, + ["ShiftRightArithmeticAdd.Vector128.Int64.1"] = ShiftRightArithmeticAdd_Vector128_Int64_1, + ["ShiftRightArithmeticAdd.Vector128.SByte.1"] = ShiftRightArithmeticAdd_Vector128_SByte_1, + ["ShiftRightArithmeticAddScalar.Vector64.Int64.1"] = ShiftRightArithmeticAddScalar_Vector64_Int64_1, + ["ShiftRightArithmeticNarrowingSaturateLower.Vector64.Int16.1"] = ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int16_1, + ["ShiftRightArithmeticNarrowingSaturateLower.Vector64.Int32.1"] = ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int32_1, + ["ShiftRightArithmeticNarrowingSaturateLower.Vector64.SByte.1"] = ShiftRightArithmeticNarrowingSaturateLower_Vector64_SByte_1, + ["ShiftRightArithmeticNarrowingSaturateUnsignedLower.Vector64.Byte.1"] = ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_Byte_1, + ["ShiftRightArithmeticNarrowingSaturateUnsignedLower.Vector64.UInt16.1"] = ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt16_1, + ["ShiftRightArithmeticNarrowingSaturateUnsignedLower.Vector64.UInt32.1"] = ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt32_1, + ["ShiftRightArithmeticNarrowingSaturateUnsignedUpper.Vector128.Byte.1"] = ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_Byte_1, + ["ShiftRightArithmeticNarrowingSaturateUnsignedUpper.Vector128.UInt16.1"] = ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt16_1, + ["ShiftRightArithmeticNarrowingSaturateUnsignedUpper.Vector128.UInt32.1"] = ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt32_1, + ["ShiftRightArithmeticNarrowingSaturateUpper.Vector128.Int16.1"] = ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int16_1, + ["ShiftRightArithmeticNarrowingSaturateUpper.Vector128.Int32.1"] = ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int32_1, + ["ShiftRightArithmeticNarrowingSaturateUpper.Vector128.SByte.1"] = ShiftRightArithmeticNarrowingSaturateUpper_Vector128_SByte_1, + ["ShiftRightArithmeticRounded.Vector64.Int16.1"] = ShiftRightArithmeticRounded_Vector64_Int16_1, + ["ShiftRightArithmeticRounded.Vector64.Int32.1"] = ShiftRightArithmeticRounded_Vector64_Int32_1, + ["ShiftRightArithmeticRounded.Vector64.SByte.1"] = ShiftRightArithmeticRounded_Vector64_SByte_1, + ["ShiftRightArithmeticRounded.Vector128.Int16.1"] = ShiftRightArithmeticRounded_Vector128_Int16_1, + ["ShiftRightArithmeticRounded.Vector128.Int32.1"] = ShiftRightArithmeticRounded_Vector128_Int32_1, + ["ShiftRightArithmeticRounded.Vector128.Int64.1"] = ShiftRightArithmeticRounded_Vector128_Int64_1, + ["ShiftRightArithmeticRounded.Vector128.SByte.1"] = ShiftRightArithmeticRounded_Vector128_SByte_1, + ["ShiftRightArithmeticRoundedAdd.Vector64.Int16.1"] = ShiftRightArithmeticRoundedAdd_Vector64_Int16_1, + ["ShiftRightArithmeticRoundedAdd.Vector64.Int32.1"] = ShiftRightArithmeticRoundedAdd_Vector64_Int32_1, + ["ShiftRightArithmeticRoundedAdd.Vector64.SByte.1"] = ShiftRightArithmeticRoundedAdd_Vector64_SByte_1, + ["ShiftRightArithmeticRoundedAdd.Vector128.Int16.1"] = ShiftRightArithmeticRoundedAdd_Vector128_Int16_1, + ["ShiftRightArithmeticRoundedAdd.Vector128.Int32.1"] = ShiftRightArithmeticRoundedAdd_Vector128_Int32_1, + ["ShiftRightArithmeticRoundedAdd.Vector128.Int64.1"] = ShiftRightArithmeticRoundedAdd_Vector128_Int64_1, + ["ShiftRightArithmeticRoundedAdd.Vector128.SByte.1"] = ShiftRightArithmeticRoundedAdd_Vector128_SByte_1, + ["ShiftRightArithmeticRoundedAddScalar.Vector64.Int64.1"] = ShiftRightArithmeticRoundedAddScalar_Vector64_Int64_1, + ["ShiftRightArithmeticRoundedNarrowingSaturateLower.Vector64.Int16.1"] = ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int16_1, + ["ShiftRightArithmeticRoundedNarrowingSaturateLower.Vector64.Int32.1"] = ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int32_1, + ["ShiftRightArithmeticRoundedNarrowingSaturateLower.Vector64.SByte.1"] = ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_SByte_1, + ["ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower.Vector64.Byte.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_Byte_1, + ["ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower.Vector64.UInt16.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt16_1, + ["ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower.Vector64.UInt32.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt32_1, + ["ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper.Vector128.Byte.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_Byte_1, + ["ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper.Vector128.UInt16.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt16_1, + ["ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper.Vector128.UInt32.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt32_1, + ["ShiftRightArithmeticRoundedNarrowingSaturateUpper.Vector128.Int16.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int16_1, + ["ShiftRightArithmeticRoundedNarrowingSaturateUpper.Vector128.Int32.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int32_1, + ["ShiftRightArithmeticRoundedNarrowingSaturateUpper.Vector128.SByte.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_SByte_1, + ["ShiftRightArithmeticRoundedScalar.Vector64.Int64.1"] = ShiftRightArithmeticRoundedScalar_Vector64_Int64_1, + ["ShiftRightArithmeticScalar.Vector64.Int64.1"] = ShiftRightArithmeticScalar_Vector64_Int64_1, + ["ShiftRightLogical.Vector64.Byte.1"] = ShiftRightLogical_Vector64_Byte_1, + ["ShiftRightLogical.Vector64.Int16.1"] = ShiftRightLogical_Vector64_Int16_1, + ["ShiftRightLogical.Vector64.Int32.1"] = ShiftRightLogical_Vector64_Int32_1, + ["ShiftRightLogical.Vector64.SByte.1"] = ShiftRightLogical_Vector64_SByte_1, + ["ShiftRightLogical.Vector64.UInt16.1"] = ShiftRightLogical_Vector64_UInt16_1, + ["ShiftRightLogical.Vector64.UInt32.1"] = ShiftRightLogical_Vector64_UInt32_1, + ["ShiftRightLogical.Vector128.Byte.1"] = ShiftRightLogical_Vector128_Byte_1, + ["ShiftRightLogical.Vector128.Int16.1"] = ShiftRightLogical_Vector128_Int16_1, + ["ShiftRightLogical.Vector128.Int32.1"] = ShiftRightLogical_Vector128_Int32_1, + ["ShiftRightLogical.Vector128.Int64.1"] = ShiftRightLogical_Vector128_Int64_1, + ["ShiftRightLogical.Vector128.SByte.1"] = ShiftRightLogical_Vector128_SByte_1, + ["ShiftRightLogical.Vector128.UInt16.1"] = ShiftRightLogical_Vector128_UInt16_1, + ["ShiftRightLogical.Vector128.UInt32.1"] = ShiftRightLogical_Vector128_UInt32_1, + ["ShiftRightLogical.Vector128.UInt64.1"] = ShiftRightLogical_Vector128_UInt64_1, + ["ShiftRightLogicalAdd.Vector64.Byte.1"] = ShiftRightLogicalAdd_Vector64_Byte_1, + ["ShiftRightLogicalAdd.Vector64.Int16.1"] = ShiftRightLogicalAdd_Vector64_Int16_1, + ["ShiftRightLogicalAdd.Vector64.Int32.1"] = ShiftRightLogicalAdd_Vector64_Int32_1, + ["ShiftRightLogicalAdd.Vector64.SByte.1"] = ShiftRightLogicalAdd_Vector64_SByte_1, + ["ShiftRightLogicalAdd.Vector64.UInt16.1"] = ShiftRightLogicalAdd_Vector64_UInt16_1, + ["ShiftRightLogicalAdd.Vector64.UInt32.1"] = ShiftRightLogicalAdd_Vector64_UInt32_1, + ["ShiftRightLogicalAdd.Vector128.Byte.1"] = ShiftRightLogicalAdd_Vector128_Byte_1, + ["ShiftRightLogicalAdd.Vector128.Int16.1"] = ShiftRightLogicalAdd_Vector128_Int16_1, + ["ShiftRightLogicalAdd.Vector128.Int32.1"] = ShiftRightLogicalAdd_Vector128_Int32_1, + ["ShiftRightLogicalAdd.Vector128.Int64.1"] = ShiftRightLogicalAdd_Vector128_Int64_1, + ["ShiftRightLogicalAdd.Vector128.SByte.1"] = ShiftRightLogicalAdd_Vector128_SByte_1, + ["ShiftRightLogicalAdd.Vector128.UInt16.1"] = ShiftRightLogicalAdd_Vector128_UInt16_1, + ["ShiftRightLogicalAdd.Vector128.UInt32.1"] = ShiftRightLogicalAdd_Vector128_UInt32_1, + ["ShiftRightLogicalAdd.Vector128.UInt64.1"] = ShiftRightLogicalAdd_Vector128_UInt64_1, + ["ShiftRightLogicalAddScalar.Vector64.Int64.1"] = ShiftRightLogicalAddScalar_Vector64_Int64_1, + ["ShiftRightLogicalAddScalar.Vector64.UInt64.1"] = ShiftRightLogicalAddScalar_Vector64_UInt64_1, + ["ShiftRightLogicalNarrowingLower.Vector64.Byte.1"] = ShiftRightLogicalNarrowingLower_Vector64_Byte_1, + ["ShiftRightLogicalNarrowingLower.Vector64.Int16.1"] = ShiftRightLogicalNarrowingLower_Vector64_Int16_1, + ["ShiftRightLogicalNarrowingLower.Vector64.Int32.1"] = ShiftRightLogicalNarrowingLower_Vector64_Int32_1, + ["ShiftRightLogicalNarrowingLower.Vector64.SByte.1"] = ShiftRightLogicalNarrowingLower_Vector64_SByte_1, + ["ShiftRightLogicalNarrowingLower.Vector64.UInt16.1"] = ShiftRightLogicalNarrowingLower_Vector64_UInt16_1, + ["ShiftRightLogicalNarrowingLower.Vector64.UInt32.1"] = ShiftRightLogicalNarrowingLower_Vector64_UInt32_1, + ["ShiftRightLogicalNarrowingSaturateLower.Vector64.Byte.1"] = ShiftRightLogicalNarrowingSaturateLower_Vector64_Byte_1, + ["ShiftRightLogicalNarrowingSaturateLower.Vector64.Int16.1"] = ShiftRightLogicalNarrowingSaturateLower_Vector64_Int16_1, + ["ShiftRightLogicalNarrowingSaturateLower.Vector64.Int32.1"] = ShiftRightLogicalNarrowingSaturateLower_Vector64_Int32_1, + ["ShiftRightLogicalNarrowingSaturateLower.Vector64.SByte.1"] = ShiftRightLogicalNarrowingSaturateLower_Vector64_SByte_1, + ["ShiftRightLogicalNarrowingSaturateLower.Vector64.UInt16.1"] = ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt16_1, + ["ShiftRightLogicalNarrowingSaturateLower.Vector64.UInt32.1"] = ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt32_1, + ["ShiftRightLogicalNarrowingSaturateUpper.Vector128.Byte.1"] = ShiftRightLogicalNarrowingSaturateUpper_Vector128_Byte_1, + ["ShiftRightLogicalNarrowingSaturateUpper.Vector128.Int16.1"] = ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int16_1, + ["ShiftRightLogicalNarrowingSaturateUpper.Vector128.Int32.1"] = ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int32_1, + ["ShiftRightLogicalNarrowingSaturateUpper.Vector128.SByte.1"] = ShiftRightLogicalNarrowingSaturateUpper_Vector128_SByte_1, + ["ShiftRightLogicalNarrowingSaturateUpper.Vector128.UInt16.1"] = ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt16_1, + ["ShiftRightLogicalNarrowingSaturateUpper.Vector128.UInt32.1"] = ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt32_1, + ["ShiftRightLogicalNarrowingUpper.Vector128.Byte.1"] = ShiftRightLogicalNarrowingUpper_Vector128_Byte_1, + ["ShiftRightLogicalNarrowingUpper.Vector128.Int16.1"] = ShiftRightLogicalNarrowingUpper_Vector128_Int16_1, + ["ShiftRightLogicalNarrowingUpper.Vector128.Int32.1"] = ShiftRightLogicalNarrowingUpper_Vector128_Int32_1, + ["ShiftRightLogicalNarrowingUpper.Vector128.SByte.1"] = ShiftRightLogicalNarrowingUpper_Vector128_SByte_1, + ["ShiftRightLogicalNarrowingUpper.Vector128.UInt16.1"] = ShiftRightLogicalNarrowingUpper_Vector128_UInt16_1, + ["ShiftRightLogicalNarrowingUpper.Vector128.UInt32.1"] = ShiftRightLogicalNarrowingUpper_Vector128_UInt32_1, + ["ShiftRightLogicalRounded.Vector64.Byte.1"] = ShiftRightLogicalRounded_Vector64_Byte_1, + ["ShiftRightLogicalRounded.Vector64.Int16.1"] = ShiftRightLogicalRounded_Vector64_Int16_1, + ["ShiftRightLogicalRounded.Vector64.Int32.1"] = ShiftRightLogicalRounded_Vector64_Int32_1, + ["ShiftRightLogicalRounded.Vector64.SByte.1"] = ShiftRightLogicalRounded_Vector64_SByte_1, + ["ShiftRightLogicalRounded.Vector64.UInt16.1"] = ShiftRightLogicalRounded_Vector64_UInt16_1, + ["ShiftRightLogicalRounded.Vector64.UInt32.1"] = ShiftRightLogicalRounded_Vector64_UInt32_1, + ["ShiftRightLogicalRounded.Vector128.Byte.1"] = ShiftRightLogicalRounded_Vector128_Byte_1, + ["ShiftRightLogicalRounded.Vector128.Int16.1"] = ShiftRightLogicalRounded_Vector128_Int16_1, + ["ShiftRightLogicalRounded.Vector128.Int32.1"] = ShiftRightLogicalRounded_Vector128_Int32_1, + ["ShiftRightLogicalRounded.Vector128.Int64.1"] = ShiftRightLogicalRounded_Vector128_Int64_1, + ["ShiftRightLogicalRounded.Vector128.SByte.1"] = ShiftRightLogicalRounded_Vector128_SByte_1, + ["ShiftRightLogicalRounded.Vector128.UInt16.1"] = ShiftRightLogicalRounded_Vector128_UInt16_1, + ["ShiftRightLogicalRounded.Vector128.UInt32.1"] = ShiftRightLogicalRounded_Vector128_UInt32_1, + ["ShiftRightLogicalRounded.Vector128.UInt64.1"] = ShiftRightLogicalRounded_Vector128_UInt64_1, + ["ShiftRightLogicalRoundedAdd.Vector64.Byte.1"] = ShiftRightLogicalRoundedAdd_Vector64_Byte_1, + ["ShiftRightLogicalRoundedAdd.Vector64.Int16.1"] = ShiftRightLogicalRoundedAdd_Vector64_Int16_1, + ["ShiftRightLogicalRoundedAdd.Vector64.Int32.1"] = ShiftRightLogicalRoundedAdd_Vector64_Int32_1, + ["ShiftRightLogicalRoundedAdd.Vector64.SByte.1"] = ShiftRightLogicalRoundedAdd_Vector64_SByte_1, + ["ShiftRightLogicalRoundedAdd.Vector64.UInt16.1"] = ShiftRightLogicalRoundedAdd_Vector64_UInt16_1, + ["ShiftRightLogicalRoundedAdd.Vector64.UInt32.1"] = ShiftRightLogicalRoundedAdd_Vector64_UInt32_1, + ["ShiftRightLogicalRoundedAdd.Vector128.Byte.1"] = ShiftRightLogicalRoundedAdd_Vector128_Byte_1, + ["ShiftRightLogicalRoundedAdd.Vector128.Int16.1"] = ShiftRightLogicalRoundedAdd_Vector128_Int16_1, + ["ShiftRightLogicalRoundedAdd.Vector128.Int32.1"] = ShiftRightLogicalRoundedAdd_Vector128_Int32_1, + ["ShiftRightLogicalRoundedAdd.Vector128.Int64.1"] = ShiftRightLogicalRoundedAdd_Vector128_Int64_1, + ["ShiftRightLogicalRoundedAdd.Vector128.SByte.1"] = ShiftRightLogicalRoundedAdd_Vector128_SByte_1, + ["ShiftRightLogicalRoundedAdd.Vector128.UInt16.1"] = ShiftRightLogicalRoundedAdd_Vector128_UInt16_1, + ["ShiftRightLogicalRoundedAdd.Vector128.UInt32.1"] = ShiftRightLogicalRoundedAdd_Vector128_UInt32_1, + ["ShiftRightLogicalRoundedAdd.Vector128.UInt64.1"] = ShiftRightLogicalRoundedAdd_Vector128_UInt64_1, + ["ShiftRightLogicalRoundedAddScalar.Vector64.Int64.1"] = ShiftRightLogicalRoundedAddScalar_Vector64_Int64_1, + ["ShiftRightLogicalRoundedAddScalar.Vector64.UInt64.1"] = ShiftRightLogicalRoundedAddScalar_Vector64_UInt64_1, + ["ShiftRightLogicalRoundedNarrowingLower.Vector64.Byte.1"] = ShiftRightLogicalRoundedNarrowingLower_Vector64_Byte_1, + ["ShiftRightLogicalRoundedNarrowingLower.Vector64.Int16.1"] = ShiftRightLogicalRoundedNarrowingLower_Vector64_Int16_1, + ["ShiftRightLogicalRoundedNarrowingLower.Vector64.Int32.1"] = ShiftRightLogicalRoundedNarrowingLower_Vector64_Int32_1, + ["ShiftRightLogicalRoundedNarrowingLower.Vector64.SByte.1"] = ShiftRightLogicalRoundedNarrowingLower_Vector64_SByte_1, + ["ShiftRightLogicalRoundedNarrowingLower.Vector64.UInt16.1"] = ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt16_1, + ["ShiftRightLogicalRoundedNarrowingLower.Vector64.UInt32.1"] = ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt32_1, + ["ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.Byte.1"] = ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Byte_1, + ["ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.Int16.1"] = ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int16_1, + ["ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.Int32.1"] = ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int32_1, + ["ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.SByte.1"] = ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_SByte_1, + ["ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.UInt16.1"] = ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt16_1, + ["ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.UInt32.1"] = ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt32_1, + ["ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.Byte.1"] = ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Byte_1, + ["ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.Int16.1"] = ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int16_1, + ["ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.Int32.1"] = ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int32_1, + ["ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.SByte.1"] = ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_SByte_1, + ["ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.UInt16.1"] = ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt16_1, + ["ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.UInt32.1"] = ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt32_1, + ["ShiftRightLogicalRoundedNarrowingUpper.Vector128.Byte.1"] = ShiftRightLogicalRoundedNarrowingUpper_Vector128_Byte_1, + ["ShiftRightLogicalRoundedNarrowingUpper.Vector128.Int16.1"] = ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int16_1, + ["ShiftRightLogicalRoundedNarrowingUpper.Vector128.Int32.1"] = ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int32_1, + ["ShiftRightLogicalRoundedNarrowingUpper.Vector128.SByte.1"] = ShiftRightLogicalRoundedNarrowingUpper_Vector128_SByte_1, + ["ShiftRightLogicalRoundedNarrowingUpper.Vector128.UInt16.1"] = ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt16_1, + ["ShiftRightLogicalRoundedNarrowingUpper.Vector128.UInt32.1"] = ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt32_1, + ["ShiftRightLogicalRoundedScalar.Vector64.Int64.1"] = ShiftRightLogicalRoundedScalar_Vector64_Int64_1, + ["ShiftRightLogicalRoundedScalar.Vector64.UInt64.1"] = ShiftRightLogicalRoundedScalar_Vector64_UInt64_1, + ["ShiftRightLogicalScalar.Vector64.Int64.1"] = ShiftRightLogicalScalar_Vector64_Int64_1, + ["ShiftRightLogicalScalar.Vector64.UInt64.1"] = ShiftRightLogicalScalar_Vector64_UInt64_1, + ["SignExtendWideningLower.Vector64.Int16"] = SignExtendWideningLower_Vector64_Int16, + ["SignExtendWideningLower.Vector64.Int32"] = SignExtendWideningLower_Vector64_Int32, + ["SignExtendWideningLower.Vector64.SByte"] = SignExtendWideningLower_Vector64_SByte, + ["SignExtendWideningUpper.Vector128.Int16"] = SignExtendWideningUpper_Vector128_Int16, + ["SignExtendWideningUpper.Vector128.Int32"] = SignExtendWideningUpper_Vector128_Int32, + ["SignExtendWideningUpper.Vector128.SByte"] = SignExtendWideningUpper_Vector128_SByte, ["SqrtScalar.Vector64.Double"] = SqrtScalar_Vector64_Double, ["SqrtScalar.Vector64.Single"] = SqrtScalar_Vector64_Single, ["Store.Vector64.Byte"] = Store_Vector64_Byte, @@ -509,10 +1125,78 @@ static Program() ["Subtract.Vector128.UInt16"] = Subtract_Vector128_UInt16, ["Subtract.Vector128.UInt32"] = Subtract_Vector128_UInt32, ["Subtract.Vector128.UInt64"] = Subtract_Vector128_UInt64, + ["SubtractHighNarrowingLower.Vector64.Byte"] = SubtractHighNarrowingLower_Vector64_Byte, + ["SubtractHighNarrowingLower.Vector64.Int16"] = SubtractHighNarrowingLower_Vector64_Int16, + ["SubtractHighNarrowingLower.Vector64.Int32"] = SubtractHighNarrowingLower_Vector64_Int32, + ["SubtractHighNarrowingLower.Vector64.SByte"] = SubtractHighNarrowingLower_Vector64_SByte, + ["SubtractHighNarrowingLower.Vector64.UInt16"] = SubtractHighNarrowingLower_Vector64_UInt16, + ["SubtractHighNarrowingLower.Vector64.UInt32"] = SubtractHighNarrowingLower_Vector64_UInt32, + ["SubtractHighNarrowingUpper.Vector128.Byte"] = SubtractHighNarrowingUpper_Vector128_Byte, + ["SubtractHighNarrowingUpper.Vector128.Int16"] = SubtractHighNarrowingUpper_Vector128_Int16, + ["SubtractHighNarrowingUpper.Vector128.Int32"] = SubtractHighNarrowingUpper_Vector128_Int32, + ["SubtractHighNarrowingUpper.Vector128.SByte"] = SubtractHighNarrowingUpper_Vector128_SByte, + ["SubtractHighNarrowingUpper.Vector128.UInt16"] = SubtractHighNarrowingUpper_Vector128_UInt16, + ["SubtractHighNarrowingUpper.Vector128.UInt32"] = SubtractHighNarrowingUpper_Vector128_UInt32, + ["SubtractRoundedHighNarrowingLower.Vector64.Byte"] = SubtractRoundedHighNarrowingLower_Vector64_Byte, + ["SubtractRoundedHighNarrowingLower.Vector64.Int16"] = SubtractRoundedHighNarrowingLower_Vector64_Int16, + ["SubtractRoundedHighNarrowingLower.Vector64.Int32"] = SubtractRoundedHighNarrowingLower_Vector64_Int32, + ["SubtractRoundedHighNarrowingLower.Vector64.SByte"] = SubtractRoundedHighNarrowingLower_Vector64_SByte, + ["SubtractRoundedHighNarrowingLower.Vector64.UInt16"] = SubtractRoundedHighNarrowingLower_Vector64_UInt16, + ["SubtractRoundedHighNarrowingLower.Vector64.UInt32"] = SubtractRoundedHighNarrowingLower_Vector64_UInt32, + ["SubtractRoundedHighNarrowingUpper.Vector128.Byte"] = SubtractRoundedHighNarrowingUpper_Vector128_Byte, + ["SubtractRoundedHighNarrowingUpper.Vector128.Int16"] = SubtractRoundedHighNarrowingUpper_Vector128_Int16, + ["SubtractRoundedHighNarrowingUpper.Vector128.Int32"] = SubtractRoundedHighNarrowingUpper_Vector128_Int32, + ["SubtractRoundedHighNarrowingUpper.Vector128.SByte"] = SubtractRoundedHighNarrowingUpper_Vector128_SByte, + ["SubtractRoundedHighNarrowingUpper.Vector128.UInt16"] = SubtractRoundedHighNarrowingUpper_Vector128_UInt16, + ["SubtractRoundedHighNarrowingUpper.Vector128.UInt32"] = SubtractRoundedHighNarrowingUpper_Vector128_UInt32, + ["SubtractSaturate.Vector64.Byte"] = SubtractSaturate_Vector64_Byte, + ["SubtractSaturate.Vector64.Int16"] = SubtractSaturate_Vector64_Int16, + ["SubtractSaturate.Vector64.Int32"] = SubtractSaturate_Vector64_Int32, + ["SubtractSaturate.Vector64.SByte"] = SubtractSaturate_Vector64_SByte, + ["SubtractSaturate.Vector64.UInt16"] = SubtractSaturate_Vector64_UInt16, + ["SubtractSaturate.Vector64.UInt32"] = SubtractSaturate_Vector64_UInt32, + ["SubtractSaturate.Vector128.Byte"] = SubtractSaturate_Vector128_Byte, + ["SubtractSaturate.Vector128.Int16"] = SubtractSaturate_Vector128_Int16, + ["SubtractSaturate.Vector128.Int32"] = SubtractSaturate_Vector128_Int32, + ["SubtractSaturate.Vector128.Int64"] = SubtractSaturate_Vector128_Int64, + ["SubtractSaturate.Vector128.SByte"] = SubtractSaturate_Vector128_SByte, + ["SubtractSaturate.Vector128.UInt16"] = SubtractSaturate_Vector128_UInt16, + ["SubtractSaturate.Vector128.UInt32"] = SubtractSaturate_Vector128_UInt32, + ["SubtractSaturate.Vector128.UInt64"] = SubtractSaturate_Vector128_UInt64, + ["SubtractSaturateScalar.Vector64.Int64"] = SubtractSaturateScalar_Vector64_Int64, + ["SubtractSaturateScalar.Vector64.UInt64"] = SubtractSaturateScalar_Vector64_UInt64, ["SubtractScalar.Vector64.Double"] = SubtractScalar_Vector64_Double, ["SubtractScalar.Vector64.Int64"] = SubtractScalar_Vector64_Int64, ["SubtractScalar.Vector64.Single"] = SubtractScalar_Vector64_Single, ["SubtractScalar.Vector64.UInt64"] = SubtractScalar_Vector64_UInt64, + ["SubtractWideningLower.Vector64.Byte"] = SubtractWideningLower_Vector64_Byte, + ["SubtractWideningLower.Vector64.Int16"] = SubtractWideningLower_Vector64_Int16, + ["SubtractWideningLower.Vector64.Int32"] = SubtractWideningLower_Vector64_Int32, + ["SubtractWideningLower.Vector64.SByte"] = SubtractWideningLower_Vector64_SByte, + ["SubtractWideningLower.Vector64.UInt16"] = SubtractWideningLower_Vector64_UInt16, + ["SubtractWideningLower.Vector64.UInt32"] = SubtractWideningLower_Vector64_UInt32, + ["SubtractWideningLower.Vector128.Int16"] = SubtractWideningLower_Vector128_Int16, + ["SubtractWideningLower.Vector128.Int32"] = SubtractWideningLower_Vector128_Int32, + ["SubtractWideningLower.Vector128.Int64"] = SubtractWideningLower_Vector128_Int64, + ["SubtractWideningLower.Vector128.UInt16"] = SubtractWideningLower_Vector128_UInt16, + ["SubtractWideningLower.Vector128.UInt32"] = SubtractWideningLower_Vector128_UInt32, + ["SubtractWideningLower.Vector128.UInt64"] = SubtractWideningLower_Vector128_UInt64, + ["SubtractWideningUpper.Vector128.Byte.Vector128.Byte"] = SubtractWideningUpper_Vector128_Byte_Vector128_Byte, + ["SubtractWideningUpper.Vector128.Int16.Vector128.Int16"] = SubtractWideningUpper_Vector128_Int16_Vector128_Int16, + ["SubtractWideningUpper.Vector128.Int16.Vector128.SByte"] = SubtractWideningUpper_Vector128_Int16_Vector128_SByte, + ["SubtractWideningUpper.Vector128.Int32.Vector128.Int16"] = SubtractWideningUpper_Vector128_Int32_Vector128_Int16, + ["SubtractWideningUpper.Vector128.Int32.Vector128.Int32"] = SubtractWideningUpper_Vector128_Int32_Vector128_Int32, + ["SubtractWideningUpper.Vector128.Int64.Vector128.Int32"] = SubtractWideningUpper_Vector128_Int64_Vector128_Int32, + ["SubtractWideningUpper.Vector128.SByte.Vector128.SByte"] = SubtractWideningUpper_Vector128_SByte_Vector128_SByte, + ["SubtractWideningUpper.Vector128.UInt16.Vector128.Byte"] = SubtractWideningUpper_Vector128_UInt16_Vector128_Byte, + ["SubtractWideningUpper.Vector128.UInt16.Vector128.UInt16"] = SubtractWideningUpper_Vector128_UInt16_Vector128_UInt16, + ["SubtractWideningUpper.Vector128.UInt32.Vector128.UInt16"] = SubtractWideningUpper_Vector128_UInt32_Vector128_UInt16, + ["SubtractWideningUpper.Vector128.UInt32.Vector128.UInt32"] = SubtractWideningUpper_Vector128_UInt32_Vector128_UInt32, + ["SubtractWideningUpper.Vector128.UInt64.Vector128.UInt32"] = SubtractWideningUpper_Vector128_UInt64_Vector128_UInt32, + ["VectorTableLookup.Vector64.Byte"] = VectorTableLookup_Vector64_Byte, + ["VectorTableLookup.Vector64.SByte"] = VectorTableLookup_Vector64_SByte, + ["VectorTableLookupExtension.Vector64.Byte"] = VectorTableLookupExtension_Vector64_Byte, + ["VectorTableLookupExtension.Vector64.SByte"] = VectorTableLookupExtension_Vector64_SByte, ["Xor.Vector64.Byte"] = Xor_Vector64_Byte, ["Xor.Vector64.Double"] = Xor_Vector64_Double, ["Xor.Vector64.Int16"] = Xor_Vector64_Int16, @@ -533,6 +1217,18 @@ static Program() ["Xor.Vector128.UInt16"] = Xor_Vector128_UInt16, ["Xor.Vector128.UInt32"] = Xor_Vector128_UInt32, ["Xor.Vector128.UInt64"] = Xor_Vector128_UInt64, + ["ZeroExtendWideningLower.Vector64.Byte"] = ZeroExtendWideningLower_Vector64_Byte, + ["ZeroExtendWideningLower.Vector64.Int16"] = ZeroExtendWideningLower_Vector64_Int16, + ["ZeroExtendWideningLower.Vector64.Int32"] = ZeroExtendWideningLower_Vector64_Int32, + ["ZeroExtendWideningLower.Vector64.SByte"] = ZeroExtendWideningLower_Vector64_SByte, + ["ZeroExtendWideningLower.Vector64.UInt16"] = ZeroExtendWideningLower_Vector64_UInt16, + ["ZeroExtendWideningLower.Vector64.UInt32"] = ZeroExtendWideningLower_Vector64_UInt32, + ["ZeroExtendWideningUpper.Vector128.Byte"] = ZeroExtendWideningUpper_Vector128_Byte, + ["ZeroExtendWideningUpper.Vector128.Int16"] = ZeroExtendWideningUpper_Vector128_Int16, + ["ZeroExtendWideningUpper.Vector128.Int32"] = ZeroExtendWideningUpper_Vector128_Int32, + ["ZeroExtendWideningUpper.Vector128.SByte"] = ZeroExtendWideningUpper_Vector128_SByte, + ["ZeroExtendWideningUpper.Vector128.UInt16"] = ZeroExtendWideningUpper_Vector128_UInt16, + ["ZeroExtendWideningUpper.Vector128.UInt32"] = ZeroExtendWideningUpper_Vector128_UInt32, }; } } diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector128.Int16.cs new file mode 100644 index 00000000000000..004afafdffc15a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmetic_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int16 testClass) + { + var result = AdvSimd.ShiftArithmetic(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmetic( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmetic), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmetic), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmetic( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmetic(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmetic(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int16(); + var result = AdvSimd.ShiftArithmetic(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmetic(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmetic(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmetic(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmetic)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector128.Int32.cs new file mode 100644 index 00000000000000..bd0527517d4f8f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmetic_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int32 testClass) + { + var result = AdvSimd.ShiftArithmetic(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmetic( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmetic), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmetic), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmetic( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmetic(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmetic(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int32(); + var result = AdvSimd.ShiftArithmetic(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmetic(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmetic(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmetic(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmetic)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector128.Int64.cs new file mode 100644 index 00000000000000..dc31a6897a2761 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector128.Int64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmetic_Vector128_Int64() + { + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int64 testClass) + { + var result = AdvSimd.ShiftArithmetic(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmetic( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmetic), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmetic), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmetic( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmetic(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmetic(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int64(); + var result = AdvSimd.ShiftArithmetic(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmetic(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmetic(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmetic(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmetic)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector128.SByte.cs new file mode 100644 index 00000000000000..abdadf2096690a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmetic_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmetic_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmetic_Vector128_SByte testClass) + { + var result = AdvSimd.ShiftArithmetic(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmetic_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmetic_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmetic_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmetic( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmetic), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmetic), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmetic( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmetic(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmetic(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector128_SByte(); + var result = AdvSimd.ShiftArithmetic(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmetic(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmetic(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmetic(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmetic)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector64.Int16.cs new file mode 100644 index 00000000000000..6147ff324bc47b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmetic_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int16 testClass) + { + var result = AdvSimd.ShiftArithmetic(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmetic( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmetic), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmetic), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmetic( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmetic(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmetic(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int16(); + var result = AdvSimd.ShiftArithmetic(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmetic(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmetic(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmetic(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmetic)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector64.Int32.cs new file mode 100644 index 00000000000000..cea92f720d580e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmetic_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int32 testClass) + { + var result = AdvSimd.ShiftArithmetic(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmetic( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmetic), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmetic), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmetic( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmetic(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmetic(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int32(); + var result = AdvSimd.ShiftArithmetic(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmetic(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmetic(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmetic(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmetic)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector64.SByte.cs new file mode 100644 index 00000000000000..1df2baab309ebc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmetic.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmetic_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmetic_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmetic_Vector64_SByte testClass) + { + var result = AdvSimd.ShiftArithmetic(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmetic_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmetic_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmetic_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmetic( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmetic), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmetic), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmetic( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmetic(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmetic(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector64_SByte(); + var result = AdvSimd.ShiftArithmetic(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmetic_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmetic(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmetic(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmetic( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmetic(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmetic)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector128.Int16.cs new file mode 100644 index 00000000000000..65a0afda9b07b4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRounded_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int16 testClass) + { + var result = AdvSimd.ShiftArithmeticRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int16(); + var result = AdvSimd.ShiftArithmeticRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRounded)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector128.Int32.cs new file mode 100644 index 00000000000000..d43861ceb6b583 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRounded_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int32 testClass) + { + var result = AdvSimd.ShiftArithmeticRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int32(); + var result = AdvSimd.ShiftArithmeticRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRounded)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector128.Int64.cs new file mode 100644 index 00000000000000..eb08ad535f566d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector128.Int64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRounded_Vector128_Int64() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int64 testClass) + { + var result = AdvSimd.ShiftArithmeticRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int64(); + var result = AdvSimd.ShiftArithmeticRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRounded)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector128.SByte.cs new file mode 100644 index 00000000000000..36b2d0e36c32cb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRounded_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_SByte testClass) + { + var result = AdvSimd.ShiftArithmeticRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_SByte(); + var result = AdvSimd.ShiftArithmeticRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRounded)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector64.Int16.cs new file mode 100644 index 00000000000000..56e2a394bddd84 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRounded_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int16 testClass) + { + var result = AdvSimd.ShiftArithmeticRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int16(); + var result = AdvSimd.ShiftArithmeticRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRounded)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector64.Int32.cs new file mode 100644 index 00000000000000..ecbf0dbac1d0cf --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRounded_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int32 testClass) + { + var result = AdvSimd.ShiftArithmeticRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int32(); + var result = AdvSimd.ShiftArithmeticRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRounded)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector64.SByte.cs new file mode 100644 index 00000000000000..a0a72ba9bfa880 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRounded.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRounded_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_SByte testClass) + { + var result = AdvSimd.ShiftArithmeticRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_SByte(); + var result = AdvSimd.ShiftArithmeticRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRounded_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRounded( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRounded)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector128.Int16.cs new file mode 100644 index 00000000000000..7e2820aa003a31 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRoundedSaturate_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int16 testClass) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int16(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRoundedSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector128.Int32.cs new file mode 100644 index 00000000000000..a70c32f1d90019 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRoundedSaturate_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int32 testClass) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int32(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRoundedSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector128.Int64.cs new file mode 100644 index 00000000000000..0ca521fe3930e3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector128.Int64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRoundedSaturate_Vector128_Int64() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int64 testClass) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int64(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRoundedSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector128.SByte.cs new file mode 100644 index 00000000000000..92663ab176402a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRoundedSaturate_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_SByte testClass) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_SByte(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRoundedSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector64.Int16.cs new file mode 100644 index 00000000000000..7854dc8a00c6ce --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRoundedSaturate_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int16 testClass) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int16(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRoundedSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector64.Int32.cs new file mode 100644 index 00000000000000..d416c680f6f19c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRoundedSaturate_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int32 testClass) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int32(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRoundedSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector64.SByte.cs new file mode 100644 index 00000000000000..ee0cf1385a1827 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturate.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRoundedSaturate_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_SByte testClass) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_SByte(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturate_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturate( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRoundedSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturateScalar.Vector64.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturateScalar.Vector64.Int64.cs new file mode 100644 index 00000000000000..82a478c05dc1e2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedSaturateScalar.Vector64.Int64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRoundedSaturateScalar_Vector64_Int64() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int64 testClass) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int64(); + var result = AdvSimd.ShiftArithmeticRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedSaturateScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftArithmeticRoundedSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRoundedSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedScalar.Vector64.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedScalar.Vector64.Int64.cs new file mode 100644 index 00000000000000..236e5058b4d5d2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticRoundedScalar.Vector64.Int64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticRoundedScalar_Vector64_Int64() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedScalar_Vector64_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRoundedScalar_Vector64_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRoundedScalar_Vector64_Int64 testClass) + { + var result = AdvSimd.ShiftArithmeticRoundedScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRoundedScalar_Vector64_Int64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticRoundedScalar_Vector64_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticRoundedScalar_Vector64_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticRoundedScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticRoundedScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticRoundedScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticRoundedScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticRoundedScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedScalar_Vector64_Int64(); + var result = AdvSimd.ShiftArithmeticRoundedScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedScalar_Vector64_Int64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticRoundedScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticRoundedScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftArithmeticRounded(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticRoundedScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector128.Int16.cs new file mode 100644 index 00000000000000..f69865da373081 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticSaturate_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int16 testClass) + { + var result = AdvSimd.ShiftArithmeticSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int16(); + var result = AdvSimd.ShiftArithmeticSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector128.Int32.cs new file mode 100644 index 00000000000000..c4b65ac67dec9c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticSaturate_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int32 testClass) + { + var result = AdvSimd.ShiftArithmeticSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int32(); + var result = AdvSimd.ShiftArithmeticSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector128.Int64.cs new file mode 100644 index 00000000000000..fa25da45593621 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector128.Int64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticSaturate_Vector128_Int64() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int64 testClass) + { + var result = AdvSimd.ShiftArithmeticSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int64(); + var result = AdvSimd.ShiftArithmeticSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector128.SByte.cs new file mode 100644 index 00000000000000..335a55256c5645 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticSaturate_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_SByte testClass) + { + var result = AdvSimd.ShiftArithmeticSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_SByte(); + var result = AdvSimd.ShiftArithmeticSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector64.Int16.cs new file mode 100644 index 00000000000000..1c0120331f3755 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticSaturate_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int16 testClass) + { + var result = AdvSimd.ShiftArithmeticSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int16(); + var result = AdvSimd.ShiftArithmeticSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector64.Int32.cs new file mode 100644 index 00000000000000..67b0e4dc96e611 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticSaturate_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int32 testClass) + { + var result = AdvSimd.ShiftArithmeticSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int32(); + var result = AdvSimd.ShiftArithmeticSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector64.SByte.cs new file mode 100644 index 00000000000000..89a0732b5fcc72 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturate.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticSaturate_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_SByte testClass) + { + var result = AdvSimd.ShiftArithmeticSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_SByte(); + var result = AdvSimd.ShiftArithmeticSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturate_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturate( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftArithmeticSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturateScalar.Vector64.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturateScalar.Vector64.Int64.cs new file mode 100644 index 00000000000000..f11399812c4b8b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticSaturateScalar.Vector64.Int64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticSaturateScalar_Vector64_Int64() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int64 testClass) + { + var result = AdvSimd.ShiftArithmeticSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int64(); + var result = AdvSimd.ShiftArithmeticSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticSaturateScalar_Vector64_Int64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticSaturateScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftArithmeticSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticScalar.Vector64.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticScalar.Vector64.Int64.cs new file mode 100644 index 00000000000000..ee58a039ccf2b9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftArithmeticScalar.Vector64.Int64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftArithmeticScalar_Vector64_Int64() + { + var test = new SimpleBinaryOpTest__ShiftArithmeticScalar_Vector64_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticScalar_Vector64_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticScalar_Vector64_Int64 testClass) + { + var result = AdvSimd.ShiftArithmeticScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticScalar_Vector64_Int64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftArithmeticScalar_Vector64_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftArithmeticScalar_Vector64_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftArithmeticScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftArithmeticScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftArithmeticScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftArithmeticScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftArithmeticScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftArithmeticScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftArithmeticScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticScalar_Vector64_Int64(); + var result = AdvSimd.ShiftArithmeticScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftArithmeticScalar_Vector64_Int64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftArithmeticScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftArithmeticScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftArithmeticScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftArithmeticScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftArithmetic(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftArithmeticScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..e5876543df026f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogical_Vector128_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogical_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogical_Vector128_Byte_1 testClass) + { + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogical_Vector128_Byte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogical_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogical_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Byte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_Byte_1(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_Byte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Byte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..0acbde27310562 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogical_Vector128_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int16_1(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.Int64.1.cs new file mode 100644 index 00000000000000..f659c72a356040 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.Int64.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogical_Vector128_Int64_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int64_1 testClass) + { + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int64_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int64_1(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_Int64_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..79af663f324f7c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogical_Vector128_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogical_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogical_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogical_Vector128_SByte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogical_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogical_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_SByte_1(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_SByte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..9dd8e898963310 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogical_Vector128_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt16_1(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..aef06f03ac89c8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogical_Vector128_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt32_1(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.UInt64.1.cs new file mode 100644 index 00000000000000..74d56e3d66a6be --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector128.UInt64.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogical_Vector128_UInt64_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt64_1 testClass) + { + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt64_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt64_1(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector128_UInt64_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector128((UInt64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..92ee7ffad1543e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogical_Vector64_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogical_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogical_Vector64_Byte_1 testClass) + { + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogical_Vector64_Byte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogical_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogical_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Byte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_Byte_1(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_Byte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Byte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogical)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..9fa76a108cffb6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogical_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int16_1(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogical)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..5deca2aa3ad4f0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogical_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int32_1(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_Int32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogical)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..3c21bf6fe260f7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogical_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogical_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogical_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogical_Vector64_SByte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogical_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogical_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_SByte_1(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_SByte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogical)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..b6307bfc7f5885 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogical_Vector64_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt16_1(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogical)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..d7e57acc1492c6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogical.Vector64.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogical_Vector64_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt32_1(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogical_Vector64_UInt32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogical( + AdvSimd.LoadVector64((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogical)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..90999ea1642aa6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturate_Vector128_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Byte_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Byte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Byte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Byte_1(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Byte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Byte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturate)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..6877a73fd6d1fb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturate_Vector128_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int16_1(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturate)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..4a76316e39da5e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturate_Vector128_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int32_1(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturate)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.Int64.1.cs new file mode 100644 index 00000000000000..37dde498561c8b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.Int64.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturate_Vector128_Int64_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int64_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int64_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int64_1(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_Int64_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturate)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..9eff7dae8b86e9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturate_Vector128_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_SByte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_SByte_1(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_SByte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturate)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..d0a7cceed73cc1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturate_Vector128_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt16_1(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturate)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..7461e8b421132b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturate_Vector128_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt32_1(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturate)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.UInt64.1.cs new file mode 100644 index 00000000000000..b7135ce6866ff1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector128.UInt64.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturate_Vector128_UInt64_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt64_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt64_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt64_1(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector128_UInt64_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector128((UInt64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturate)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..19f6adbc90cd71 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturate_Vector64_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Byte_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Byte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Byte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Byte_1(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Byte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Byte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturate)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..1f2f914a462eae --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturate_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int16_1(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturate)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..9a7e8a89f35d83 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturate_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int32_1(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_Int32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturate)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..3515faa2d8fc3a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturate_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_SByte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_SByte_1(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_SByte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturate)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..0a0471355a6096 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturate_Vector64_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt16_1(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturate)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..2a74644f94f7f4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturate.Vector64.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturate_Vector64_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturate), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturate(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt32_1(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturate_Vector64_UInt32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturate(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturate( + AdvSimd.LoadVector64((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturate)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateScalar.Vector64.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateScalar.Vector64.Int64.1.cs new file mode 100644 index 00000000000000..6794c900892195 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateScalar.Vector64.Int64.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateScalar_Vector64_Int64_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int64_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturateScalar(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int64_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturateScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturateScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int64_1(); + var result = AdvSimd.ShiftLeftLogicalSaturateScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_Int64_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateScalar(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturateScalar)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateScalar.Vector64.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateScalar.Vector64.UInt64.1.cs new file mode 100644 index 00000000000000..46ea94dcdfcc06 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateScalar.Vector64.UInt64.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateScalar_Vector64_UInt64_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt64_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturateScalar(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt64_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturateScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturateScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt64_1(); + var result = AdvSimd.ShiftLeftLogicalSaturateScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateScalar_Vector64_UInt64_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateScalar(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturateScalar)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..6085e1bd991560 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector128.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateUnsigned_Vector128_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int16_1(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..f9bb48efc64ec2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector128.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateUnsigned_Vector128_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int32_1(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector128.Int64.1.cs new file mode 100644 index 00000000000000..53e118e13ebdb0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector128.Int64.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateUnsigned_Vector128_Int64_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, UInt64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int64_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int64_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int64_1(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_Int64_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..ced25f2be3b850 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector128.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateUnsigned_Vector128_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_SByte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_SByte_1(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector128_SByte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector128((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..0ec38fe4678cdc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector64.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateUnsigned_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int16_1(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..04170dcc9b7938 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector64.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateUnsigned_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int32_1(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_Int32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..f2eae9c2e7907a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsigned.Vector64.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateUnsigned_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_SByte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_SByte_1(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsigned_Vector64_SByte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsigned( + AdvSimd.LoadVector64((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturateUnsigned)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int64.1.cs new file mode 100644 index 00000000000000..805b233f85b792 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int64.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int64_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, UInt64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int64_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int64_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int64_1(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int64_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalSaturateUnsignedScalar)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalScalar.Vector64.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalScalar.Vector64.Int64.1.cs new file mode 100644 index 00000000000000..40358c81ec1d64 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalScalar.Vector64.Int64.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalScalar_Vector64_Int64_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_Int64_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalScalar(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_Int64_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalScalar( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_Int64_1(); + var result = AdvSimd.ShiftLeftLogicalScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_Int64_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalScalar(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLeftLogical(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalScalar)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalScalar.Vector64.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalScalar.Vector64.UInt64.1.cs new file mode 100644 index 00000000000000..a9c5ebabd12810 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalScalar.Vector64.UInt64.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalScalar_Vector64_UInt64_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_UInt64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_UInt64_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalScalar(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_UInt64_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalScalar( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_UInt64_1(); + var result = AdvSimd.ShiftLeftLogicalScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalScalar_Vector64_UInt64_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalScalar(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLeftLogical(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalScalar)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..6643b012f5c27e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalWideningLower_Vector64_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Byte_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Byte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningLower), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningLower), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Byte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalWideningLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalWideningLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Byte_1(); + var result = AdvSimd.ShiftLeftLogicalWideningLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Byte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Byte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalWidening(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalWideningLower)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..18b90d66f0c210 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalWideningLower_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningLower), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningLower), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalWideningLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalWideningLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int16_1(); + var result = AdvSimd.ShiftLeftLogicalWideningLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalWidening(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalWideningLower)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..b78654de09858a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalWideningLower_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningLower), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningLower), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalWideningLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalWideningLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int32_1(); + var result = AdvSimd.ShiftLeftLogicalWideningLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_Int32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalWidening(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalWideningLower)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..ceaf877d20326a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalWideningLower_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_SByte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningLower), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningLower), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalWideningLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalWideningLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_SByte_1(); + var result = AdvSimd.ShiftLeftLogicalWideningLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_SByte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalWidening(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalWideningLower)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..9dcf79fc9bbc6f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalWideningLower_Vector64_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningLower), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningLower), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalWideningLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalWideningLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt16_1(); + var result = AdvSimd.ShiftLeftLogicalWideningLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalWidening(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalWideningLower)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..e53f3be0c9154a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningLower.Vector64.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalWideningLower_Vector64_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningLower), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningLower), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalWideningLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalWideningLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt32_1(); + var result = AdvSimd.ShiftLeftLogicalWideningLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningLower_Vector64_UInt32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningLower( + AdvSimd.LoadVector64((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalWidening(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalWideningLower)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..19009e19bca800 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalWideningUpper_Vector128_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Byte_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Byte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningUpper), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningUpper), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Byte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Byte_1(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Byte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Byte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalWideningUpper(firstOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalWideningUpper)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..1c8ced42418e7a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalWideningUpper_Vector128_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningUpper), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningUpper), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int16_1(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalWideningUpper(firstOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalWideningUpper)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..5482ea148d99f9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalWideningUpper_Vector128_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningUpper), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningUpper), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int32_1(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_Int32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalWideningUpper(firstOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalWideningUpper)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..a5158ce7397da3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalWideningUpper_Vector128_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_SByte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningUpper), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningUpper), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_SByte_1(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_SByte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalWideningUpper(firstOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalWideningUpper)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..ce2a730d027f9e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalWideningUpper_Vector128_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningUpper), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningUpper), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt16_1(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalWideningUpper(firstOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalWideningUpper)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..4802406e32717e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLeftLogicalWideningUpper.Vector128.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLeftLogicalWideningUpper_Vector128_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningUpper), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLeftLogicalWideningUpper), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt32_1(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftLeftLogicalWideningUpper_Vector128_UInt32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLeftLogicalWideningUpper(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLeftLogicalWideningUpper( + AdvSimd.LoadVector128((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLeftLogicalWideningUpper(firstOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLeftLogicalWideningUpper)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.Byte.cs new file mode 100644 index 00000000000000..b5f1ee0ac9a93b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogical_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogical_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, SByte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogical_Vector128_Byte testClass) + { + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogical_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogical_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogical_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogical( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogical( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_Byte(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, SByte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogical(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogical)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.Int16.cs new file mode 100644 index 00000000000000..61e1428538a9c5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogical_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogical_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogical_Vector128_Int16 testClass) + { + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogical_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogical_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogical_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogical( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogical( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_Int16(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogical(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogical)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.Int32.cs new file mode 100644 index 00000000000000..c9e06a69bd9449 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogical_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogical_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogical_Vector128_Int32 testClass) + { + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogical_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogical_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogical_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogical( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogical( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_Int32(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogical(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogical)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.Int64.cs new file mode 100644 index 00000000000000..9279375a741a09 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.Int64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogical_Vector128_Int64() + { + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogical_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogical_Vector128_Int64 testClass) + { + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogical_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogical_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogical_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogical( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogical( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_Int64(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogical(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogical)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.SByte.cs new file mode 100644 index 00000000000000..9fffdc8224b94f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogical_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogical_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogical_Vector128_SByte testClass) + { + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogical_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogical_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogical_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogical( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogical( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_SByte(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogical(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogical)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.UInt16.cs new file mode 100644 index 00000000000000..f9d47ca6c3e8c9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogical_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogical_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Int16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogical_Vector128_UInt16 testClass) + { + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogical_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogical_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogical_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogical( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogical( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_UInt16(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Int16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogical(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogical)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.UInt32.cs new file mode 100644 index 00000000000000..1477f27f0237e4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogical_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogical_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, Int32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogical_Vector128_UInt32 testClass) + { + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogical_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogical_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogical_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogical( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogical( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_UInt32(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, Int32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogical(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogical)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.UInt64.cs new file mode 100644 index 00000000000000..878e05f57d89d0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector128.UInt64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogical_Vector128_UInt64() + { + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogical_Vector128_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, Int64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogical_Vector128_UInt64 testClass) + { + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogical_Vector128_UInt64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogical_Vector128_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogical_Vector128_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogical( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogical( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_UInt64(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector128_UInt64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, Int64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogical(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogical)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.Byte.cs new file mode 100644 index 00000000000000..0d0247d2927e9b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogical_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogical_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, SByte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogical_Vector64_Byte testClass) + { + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogical_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogical_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogical_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogical( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogical( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_Byte(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, SByte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogical(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogical)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.Int16.cs new file mode 100644 index 00000000000000..cf370b6685b02f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogical_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogical_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogical_Vector64_Int16 testClass) + { + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogical_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogical_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogical_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogical( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogical( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_Int16(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogical(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogical)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.Int32.cs new file mode 100644 index 00000000000000..74e76ebb9a32b1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogical_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogical_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogical_Vector64_Int32 testClass) + { + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogical_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogical_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogical_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogical( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogical( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_Int32(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogical(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogical)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.SByte.cs new file mode 100644 index 00000000000000..28171de391d20f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogical_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogical_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogical_Vector64_SByte testClass) + { + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogical_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogical_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogical_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogical( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogical( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_SByte(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogical(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogical)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.UInt16.cs new file mode 100644 index 00000000000000..a12a7e6f2e1e9b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogical_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogical_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Int16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogical_Vector64_UInt16 testClass) + { + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogical_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogical_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogical_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogical( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogical( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_UInt16(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Int16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogical(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogical)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.UInt32.cs new file mode 100644 index 00000000000000..da032eca839609 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogical.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogical_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogical_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, Int32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogical_Vector64_UInt32 testClass) + { + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogical_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogical_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogical_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogical( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogical), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogical( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogical(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_UInt32(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogical_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogical(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogical( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, Int32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogical(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogical)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.Byte.cs new file mode 100644 index 00000000000000..a2b01f27e9c26e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRounded_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, SByte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Byte testClass) + { + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Byte(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, SByte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRounded)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.Int16.cs new file mode 100644 index 00000000000000..22ab6260990192 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRounded_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int16 testClass) + { + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int16(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRounded)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.Int32.cs new file mode 100644 index 00000000000000..ee5505da9a8944 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRounded_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int32 testClass) + { + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int32(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRounded)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.Int64.cs new file mode 100644 index 00000000000000..1993f0d372b660 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.Int64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRounded_Vector128_Int64() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int64 testClass) + { + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int64(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRounded)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.SByte.cs new file mode 100644 index 00000000000000..a345dd531ceac2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRounded_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_SByte testClass) + { + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_SByte(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRounded)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.UInt16.cs new file mode 100644 index 00000000000000..78d1aeb0268a34 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRounded_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Int16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt16 testClass) + { + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt16(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Int16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRounded)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.UInt32.cs new file mode 100644 index 00000000000000..62764e33365c83 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRounded_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, Int32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt32 testClass) + { + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt32(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, Int32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRounded)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.UInt64.cs new file mode 100644 index 00000000000000..29dfe41903e7ca --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector128.UInt64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRounded_Vector128_UInt64() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, Int64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt64 testClass) + { + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt64(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector128_UInt64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, Int64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRounded)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.Byte.cs new file mode 100644 index 00000000000000..6900a082bf0e57 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRounded_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, SByte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Byte testClass) + { + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Byte(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, SByte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRounded)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.Int16.cs new file mode 100644 index 00000000000000..69ee56fceeaa14 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRounded_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int16 testClass) + { + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int16(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRounded)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.Int32.cs new file mode 100644 index 00000000000000..5e2541004b9aa2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRounded_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int32 testClass) + { + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int32(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRounded)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.SByte.cs new file mode 100644 index 00000000000000..94df562d5b2ed9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRounded_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_SByte testClass) + { + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_SByte(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRounded)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.UInt16.cs new file mode 100644 index 00000000000000..4c192beb8bd318 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRounded_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Int16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt16 testClass) + { + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt16(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Int16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRounded)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.UInt32.cs new file mode 100644 index 00000000000000..69dac65171824e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRounded.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRounded_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, Int32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt32 testClass) + { + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRounded( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRounded), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRounded( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRounded(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt32(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRounded_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRounded(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRounded( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, Int32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRounded)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.Byte.cs new file mode 100644 index 00000000000000..2cd0b999b78d49 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturate_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, SByte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Byte testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Byte(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, SByte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.Int16.cs new file mode 100644 index 00000000000000..f30b6ec4362a5d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturate_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int16 testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int16(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.Int32.cs new file mode 100644 index 00000000000000..7e2955eeed17cd --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturate_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int32 testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int32(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.Int64.cs new file mode 100644 index 00000000000000..6d998963744c61 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.Int64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturate_Vector128_Int64() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int64 testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int64(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.SByte.cs new file mode 100644 index 00000000000000..e40d14267f6567 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturate_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_SByte testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_SByte(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.UInt16.cs new file mode 100644 index 00000000000000..8229fd275f561d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturate_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Int16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt16 testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt16(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Int16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.UInt32.cs new file mode 100644 index 00000000000000..7521227343c5f4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturate_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, Int32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt32 testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt32(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, Int32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.UInt64.cs new file mode 100644 index 00000000000000..ec46a3264433f9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector128.UInt64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturate_Vector128_UInt64() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, Int64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt64 testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt64(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector128_UInt64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, Int64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.Byte.cs new file mode 100644 index 00000000000000..efb2d9b2233a02 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturate_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, SByte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Byte testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Byte(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, SByte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.Int16.cs new file mode 100644 index 00000000000000..200aad4b36ba9b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturate_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int16 testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int16(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.Int32.cs new file mode 100644 index 00000000000000..6774c82376837b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturate_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int32 testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int32(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.SByte.cs new file mode 100644 index 00000000000000..ea82600c3c1468 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturate_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_SByte testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_SByte(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.UInt16.cs new file mode 100644 index 00000000000000..c88b0d3b534b7f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturate_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Int16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt16 testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt16(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Int16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.UInt32.cs new file mode 100644 index 00000000000000..051dd2eb1ef1e5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturate.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturate_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, Int32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt32 testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt32(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturate_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturate( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, Int32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturateScalar.Vector64.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturateScalar.Vector64.Int64.cs new file mode 100644 index 00000000000000..bc197aa8ba5342 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturateScalar.Vector64.Int64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturateScalar_Vector64_Int64() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int64 testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int64(); + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_Int64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturateScalar.Vector64.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturateScalar.Vector64.UInt64.cs new file mode 100644 index 00000000000000..b4ac5ec3e07f9f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedSaturateScalar.Vector64.UInt64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedSaturateScalar_Vector64_UInt64() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, Int64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt64 testClass) + { + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt64(); + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedSaturateScalar_Vector64_UInt64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, Int64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedScalar.Vector64.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedScalar.Vector64.Int64.cs new file mode 100644 index 00000000000000..64738a692c27dc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedScalar.Vector64.Int64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedScalar_Vector64_Int64() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_Int64 testClass) + { + var result = AdvSimd.ShiftLogicalRoundedScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_Int64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_Int64(); + var result = AdvSimd.ShiftLogicalRoundedScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_Int64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalRounded(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedScalar.Vector64.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedScalar.Vector64.UInt64.cs new file mode 100644 index 00000000000000..2730747125f705 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalRoundedScalar.Vector64.UInt64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalRoundedScalar_Vector64_UInt64() + { + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, Int64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_UInt64 testClass) + { + var result = AdvSimd.ShiftLogicalRoundedScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_UInt64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalRoundedScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalRoundedScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalRoundedScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalRoundedScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalRoundedScalar( + AdvSimd.LoadVector64((UInt64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalRoundedScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalRoundedScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_UInt64(); + var result = AdvSimd.ShiftLogicalRoundedScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalRoundedScalar_Vector64_UInt64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalRoundedScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalRoundedScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalRoundedScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalRoundedScalar( + AdvSimd.LoadVector64((UInt64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, Int64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalRounded(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalRoundedScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.Byte.cs new file mode 100644 index 00000000000000..4ebbb7b4b57dc7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturate_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, SByte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Byte testClass) + { + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Byte(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, SByte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.Int16.cs new file mode 100644 index 00000000000000..d58b5729da45c4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturate_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int16 testClass) + { + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int16(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.Int32.cs new file mode 100644 index 00000000000000..7343fdb20232d2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturate_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int32 testClass) + { + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int32(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.Int64.cs new file mode 100644 index 00000000000000..a5e0dd7d875cb6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.Int64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturate_Vector128_Int64() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int64 testClass) + { + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int64(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.SByte.cs new file mode 100644 index 00000000000000..b6943048c61756 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturate_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_SByte testClass) + { + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_SByte(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.UInt16.cs new file mode 100644 index 00000000000000..b3e37eea5b4f60 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturate_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Int16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt16 testClass) + { + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt16(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Int16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.UInt32.cs new file mode 100644 index 00000000000000..1ed51fb67edc0c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturate_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, Int32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt32 testClass) + { + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt32(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, Int32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.UInt64.cs new file mode 100644 index 00000000000000..1c43ef1a55ebae --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector128.UInt64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturate_Vector128_UInt64() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, Int64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt64 testClass) + { + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt64(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector128_UInt64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, Int64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.Byte.cs new file mode 100644 index 00000000000000..e44da8d4c8a598 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturate_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, SByte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Byte testClass) + { + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Byte(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, SByte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.Int16.cs new file mode 100644 index 00000000000000..00e63b170038c0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturate_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int16 testClass) + { + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int16(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.Int32.cs new file mode 100644 index 00000000000000..699d531bccd708 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturate_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int32 testClass) + { + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int32(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.SByte.cs new file mode 100644 index 00000000000000..0001fd5a0afdfe --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturate_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_SByte testClass) + { + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_SByte(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.UInt16.cs new file mode 100644 index 00000000000000..c58411177c5fbf --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturate_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Int16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt16 testClass) + { + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt16(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Int16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.UInt32.cs new file mode 100644 index 00000000000000..91e08ee0248066 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturate.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturate_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, Int32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt32 testClass) + { + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt32(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturate_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturate( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, Int32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturateScalar.Vector64.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturateScalar.Vector64.Int64.cs new file mode 100644 index 00000000000000..4d9371ef77e555 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturateScalar.Vector64.Int64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturateScalar_Vector64_Int64() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int64 testClass) + { + var result = AdvSimd.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int64(); + var result = AdvSimd.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_Int64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturateScalar.Vector64.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturateScalar.Vector64.UInt64.cs new file mode 100644 index 00000000000000..337a8d3e6c3e4d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalSaturateScalar.Vector64.UInt64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalSaturateScalar_Vector64_UInt64() + { + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, Int64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt64 testClass) + { + var result = AdvSimd.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt64(); + var result = AdvSimd.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalSaturateScalar_Vector64_UInt64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, Int64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalScalar.Vector64.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalScalar.Vector64.Int64.cs new file mode 100644 index 00000000000000..558309f83f7d7d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalScalar.Vector64.Int64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalScalar_Vector64_Int64() + { + var test = new SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_Int64 testClass) + { + var result = AdvSimd.ShiftLogicalScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_Int64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_Int64(); + var result = AdvSimd.ShiftLogicalScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_Int64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogical(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalScalar.Vector64.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalScalar.Vector64.UInt64.cs new file mode 100644 index 00000000000000..32852fe910875d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftLogicalScalar.Vector64.UInt64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftLogicalScalar_Vector64_UInt64() + { + var test = new SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, Int64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_UInt64 testClass) + { + var result = AdvSimd.ShiftLogicalScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_UInt64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftLogicalScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftLogicalScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftLogicalScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.ShiftLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftLogicalScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftLogicalScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_UInt64(); + var result = AdvSimd.ShiftLogicalScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__ShiftLogicalScalar_Vector64_UInt64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.ShiftLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftLogicalScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.ShiftLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, Int64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftLogical(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftLogicalScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..4e3319ae8f00fd --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector128.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmetic_Vector128_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmetic(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmetic( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmetic), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmetic), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmetic( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmetic(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmetic(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int16_1(); + var result = AdvSimd.ShiftRightArithmetic(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmetic(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmetic(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmetic(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmetic)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..fe035aa7fccdda --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector128.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmetic_Vector128_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmetic(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmetic( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmetic), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmetic), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmetic( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmetic(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmetic(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int32_1(); + var result = AdvSimd.ShiftRightArithmetic(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmetic(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmetic(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmetic(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmetic)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector128.Int64.1.cs new file mode 100644 index 00000000000000..26f054d9c91a2b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector128.Int64.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmetic_Vector128_Int64_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightArithmetic(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int64_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmetic( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmetic), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmetic), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmetic( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmetic(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmetic(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int64_1(); + var result = AdvSimd.ShiftRightArithmetic(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector128_Int64_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmetic(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmetic(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmetic(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmetic)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..da629e612199eb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector128.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmetic_Vector128_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmetic_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmetic_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmetic(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmetic_Vector128_SByte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmetic_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmetic_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmetic( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmetic), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmetic), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmetic( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmetic(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmetic(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector128_SByte_1(); + var result = AdvSimd.ShiftRightArithmetic(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector128_SByte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmetic(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmetic(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector128((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmetic(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmetic)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..a320af6aca1f40 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector64.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmetic_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmetic(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmetic( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmetic), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmetic), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmetic( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmetic(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmetic(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int16_1(); + var result = AdvSimd.ShiftRightArithmetic(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmetic(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmetic(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmetic(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmetic)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..dd54b73ec1fa53 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector64.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmetic_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmetic(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmetic( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmetic), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmetic), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmetic( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmetic(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmetic(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int32_1(); + var result = AdvSimd.ShiftRightArithmetic(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector64_Int32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmetic(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmetic(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmetic(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmetic)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..679ec212fd4a0c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmetic.Vector64.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmetic_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmetic_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmetic_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmetic(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmetic_Vector64_SByte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmetic_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmetic_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmetic( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmetic), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmetic), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmetic( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmetic(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmetic(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector64_SByte_1(); + var result = AdvSimd.ShiftRightArithmetic(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmetic_Vector64_SByte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmetic(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmetic(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmetic( + AdvSimd.LoadVector64((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmetic(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmetic)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..f6cfec500ddd56 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector128.Int16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticAdd_Vector128_Int16_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int16_1(); + var result = AdvSimd.ShiftRightArithmeticAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..a649bbe23ad9f6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector128.Int32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticAdd_Vector128_Int32_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int32_1(); + var result = AdvSimd.ShiftRightArithmeticAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector128.Int64.1.cs new file mode 100644 index 00000000000000..59d05eb5e6f1a0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector128.Int64.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticAdd_Vector128_Int64_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_Int64_1(); + var result = AdvSimd.ShiftRightArithmeticAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] secondOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..647925c244f7e6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector128.SByte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticAdd_Vector128_SByte_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector128_SByte_1(); + var result = AdvSimd.ShiftRightArithmeticAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..1c3c5188783bd7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector64.Int16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticAdd_Vector64_Int16_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_Int16_1(); + var result = AdvSimd.ShiftRightArithmeticAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..6b88a50c83c9eb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector64.Int32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticAdd_Vector64_Int32_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_Int32_1(); + var result = AdvSimd.ShiftRightArithmeticAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..a965bf1f6fcb34 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAdd.Vector64.SByte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticAdd_Vector64_SByte_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticAdd_Vector64_SByte_1(); + var result = AdvSimd.ShiftRightArithmeticAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAddScalar.Vector64.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAddScalar.Vector64.Int64.1.cs new file mode 100644 index 00000000000000..20967cdf7a39e3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticAddScalar.Vector64.Int64.1.cs @@ -0,0 +1,423 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticAddScalar_Vector64_Int64_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticAddScalar_Vector64_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticAddScalar_Vector64_Int64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticAddScalar_Vector64_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticAddScalar(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticAddScalar_Vector64_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticAddScalar_Vector64_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticAddScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticAddScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAddScalar), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticAddScalar), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticAddScalar( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticAddScalar(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticAddScalar(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticAddScalar_Vector64_Int64_1(); + var result = AdvSimd.ShiftRightArithmeticAddScalar(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticAddScalar(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticAddScalar(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] secondOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticAdd(firstOp[0], secondOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticAddScalar)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateLower.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateLower.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..2413bc6b2ba11e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateLower.Vector64.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int16_1(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateLower.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateLower.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..7eef60a65ab6cb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateLower.Vector64.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int32_1(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateLower.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateLower.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..f0e6ad42ea5082 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateLower.Vector64.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateLower_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_SByte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_SByte_1(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateLower_Vector64_SByte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedLower.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedLower.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..2fb415b1ae3120 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedLower.Vector64.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_Byte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_Byte_1(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_Byte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticNarrowingSaturateUnsigned(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedLower.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedLower.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..25f65d74f48468 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedLower.Vector64.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt16_1(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticNarrowingSaturateUnsigned(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedLower.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedLower.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..b13144c8dd51d0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedLower.Vector64.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt32_1(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticNarrowingSaturateUnsigned(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedUpper.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedUpper.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..693d0330e69868 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedUpper.Vector128.Byte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_Byte_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Int16[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_Byte_1(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Int16[] secondOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedUpper.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedUpper.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..a11c4073481c4e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedUpper.Vector128.UInt16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt16_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Int32[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt16_1(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Int32[] secondOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedUpper.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedUpper.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..12b9fe456195d8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUnsignedUpper.Vector128.UInt32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt32_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, Int64[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt32_1(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, Int64[] secondOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUnsignedUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUpper.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUpper.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..effa7d9d61c46b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUpper.Vector128.Int16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int16_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int16_1(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUpper.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUpper.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..ce6c7ed79fdd78 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUpper.Vector128.Int32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int32_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int32_1(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUpper.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUpper.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..0679af81a644ee --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticNarrowingSaturateUpper.Vector128.SByte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticNarrowingSaturateUpper_Vector128_SByte_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticNarrowingSaturateUpper_Vector128_SByte_1(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..89555ea94254d6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector128.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRounded_Vector128_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int16_1(); + var result = AdvSimd.ShiftRightArithmeticRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRounded)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..217904fb6db4b3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector128.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRounded_Vector128_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int32_1(); + var result = AdvSimd.ShiftRightArithmeticRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRounded)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector128.Int64.1.cs new file mode 100644 index 00000000000000..e4bd6b739214b5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector128.Int64.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRounded_Vector128_Int64_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int64_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int64_1(); + var result = AdvSimd.ShiftRightArithmeticRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_Int64_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRounded)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..d3efbc420189b4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector128.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRounded_Vector128_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_SByte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_SByte_1(); + var result = AdvSimd.ShiftRightArithmeticRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector128_SByte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector128((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRounded)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..9dba14a59013ae --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector64.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRounded_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int16_1(); + var result = AdvSimd.ShiftRightArithmeticRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRounded)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..fdd6d7d9dc639b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector64.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRounded_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int32_1(); + var result = AdvSimd.ShiftRightArithmeticRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_Int32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRounded)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..8b2536f5443fd6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRounded.Vector64.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRounded_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_SByte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_SByte_1(); + var result = AdvSimd.ShiftRightArithmeticRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRounded_Vector64_SByte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRounded( + AdvSimd.LoadVector64((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRounded)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..f914cf3643e280 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector128.Int16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedAdd_Vector128_Int16_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int16_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..350750d9813092 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector128.Int32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedAdd_Vector128_Int32_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int32_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector128.Int64.1.cs new file mode 100644 index 00000000000000..16f6b29e7c9e81 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector128.Int64.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedAdd_Vector128_Int64_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_Int64_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] secondOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..8dd2c523ddae2b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector128.SByte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedAdd_Vector128_SByte_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector128_SByte_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..8a5a35b900b6c9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector64.Int16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedAdd_Vector64_Int16_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_Int16_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..cb541c555c5744 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector64.Int32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedAdd_Vector64_Int32_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_Int32_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..7b56cc89de3c5b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAdd.Vector64.SByte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedAdd_Vector64_SByte_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAdd_Vector64_SByte_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAddScalar.Vector64.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAddScalar.Vector64.Int64.1.cs new file mode 100644 index 00000000000000..fab88648a9b2e6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedAddScalar.Vector64.Int64.1.cs @@ -0,0 +1,423 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedAddScalar_Vector64_Int64_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAddScalar_Vector64_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticRoundedAddScalar_Vector64_Int64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticRoundedAddScalar_Vector64_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedAddScalar(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticRoundedAddScalar_Vector64_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticRoundedAddScalar_Vector64_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAddScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAddScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAddScalar), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedAddScalar), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAddScalar( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticRoundedAddScalar(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticRoundedAddScalar(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedAddScalar_Vector64_Int64_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedAddScalar(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedAddScalar(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedAddScalar(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] secondOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticRoundedAdd(firstOp[0], secondOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedAddScalar)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateLower.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateLower.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..d348c65cedd45a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateLower.Vector64.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int16_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateLower.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateLower.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..50550ce9104c13 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateLower.Vector64.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int32_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateLower.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateLower.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..f2466add877724 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateLower.Vector64.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_SByte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_SByte_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_SByte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..cc8565df8d2090 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower.Vector64.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_Byte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_Byte_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_Byte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..d5f79e43412fed --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower.Vector64.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt16_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..67dbbf7cb4db90 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower.Vector64.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt32_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..b78b53582fda71 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper.Vector128.Byte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_Byte_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Int16[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_Byte_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Int16[] secondOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..426b85cab078ba --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper.Vector128.UInt16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt16_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Int32[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt16_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Int32[] secondOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..bab5e30db1bd38 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper.Vector128.UInt32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt32_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, Int64[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt32_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, Int64[] secondOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUpper.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUpper.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..43a8740b116b00 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUpper.Vector128.Int16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int16_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int16_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUpper.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUpper.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..3b1ee352ffcb1c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUpper.Vector128.Int32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int32_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int32_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUpper.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUpper.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..4e185da5d4181f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedNarrowingSaturateUpper.Vector128.SByte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_SByte_1() + { + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_SByte_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedScalar.Vector64.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedScalar.Vector64.Int64.1.cs new file mode 100644 index 00000000000000..d4c91308c44845 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticRoundedScalar.Vector64.Int64.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticRoundedScalar_Vector64_Int64_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedScalar_Vector64_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticRoundedScalar_Vector64_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticRoundedScalar_Vector64_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticRoundedScalar(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticRoundedScalar_Vector64_Int64_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticRoundedScalar_Vector64_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticRoundedScalar_Vector64_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticRoundedScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticRoundedScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticRoundedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedScalar( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticRoundedScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticRoundedScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedScalar_Vector64_Int64_1(); + var result = AdvSimd.ShiftRightArithmeticRoundedScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticRoundedScalar_Vector64_Int64_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticRoundedScalar(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticRoundedScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmeticRounded(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticRoundedScalar)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticScalar.Vector64.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticScalar.Vector64.Int64.1.cs new file mode 100644 index 00000000000000..0bad044604de1f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightArithmeticScalar.Vector64.Int64.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightArithmeticScalar_Vector64_Int64_1() + { + var test = new ImmUnaryOpTest__ShiftRightArithmeticScalar_Vector64_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightArithmeticScalar_Vector64_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightArithmeticScalar_Vector64_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightArithmeticScalar(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightArithmeticScalar_Vector64_Int64_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightArithmeticScalar_Vector64_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightArithmeticScalar_Vector64_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightArithmeticScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightArithmeticScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightArithmeticScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightArithmeticScalar( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightArithmeticScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightArithmeticScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightArithmeticScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticScalar_Vector64_Int64_1(); + var result = AdvSimd.ShiftRightArithmeticScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightArithmeticScalar_Vector64_Int64_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightArithmeticScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightArithmeticScalar(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightArithmeticScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightArithmeticScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightArithmetic(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightArithmeticScalar)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..23729809ef4eaa --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogical_Vector128_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogical_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogical_Vector128_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogical_Vector128_Byte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogical_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogical_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Byte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_Byte_1(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_Byte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Byte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..2f0d94b5684b4b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogical_Vector128_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogical_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogical_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogical_Vector128_Int16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogical_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogical_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_Int16_1(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_Int16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..4e46a2a8f38f37 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogical_Vector128_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogical_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogical_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogical_Vector128_Int32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogical_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogical_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_Int32_1(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_Int32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.Int64.1.cs new file mode 100644 index 00000000000000..ccf01b612b3c84 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.Int64.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogical_Vector128_Int64_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogical_Vector128_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogical_Vector128_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogical_Vector128_Int64_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogical_Vector128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogical_Vector128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_Int64_1(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_Int64_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..72d2dff64eeebc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogical_Vector128_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogical_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogical_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogical_Vector128_SByte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogical_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogical_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_SByte_1(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_SByte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..8aa45d8f47147b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogical_Vector128_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt16_1(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..9bf9e8fec17900 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogical_Vector128_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt32_1(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.UInt64.1.cs new file mode 100644 index 00000000000000..446fa4cf0889a3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector128.UInt64.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogical_Vector128_UInt64_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt64_1 testClass) + { + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt64_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt64_1(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector128_UInt64_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector128((UInt64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogical)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..ade6a58e16b823 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogical_Vector64_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogical_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogical_Vector64_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogical_Vector64_Byte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogical_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogical_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Byte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_Byte_1(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_Byte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Byte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogical)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..c6d9f765d82061 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogical_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogical_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogical_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogical_Vector64_Int16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogical_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogical_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_Int16_1(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_Int16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogical)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..cb700766e8946d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogical_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogical_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogical_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogical_Vector64_Int32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogical_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogical_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_Int32_1(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_Int32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogical)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..764ca4d3e6312c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogical_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogical_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogical_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogical_Vector64_SByte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogical_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogical_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_SByte_1(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_SByte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogical)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..8fad7e0be90707 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogical_Vector64_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt16_1(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogical)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..e979a7d7ce6e9a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogical.Vector64.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogical_Vector64_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogical( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogical), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogical( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogical(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt32_1(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogical_Vector64_UInt32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogical(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogical( + AdvSimd.LoadVector64((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogical)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..d5acb54a342d13 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.Byte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAdd_Vector128_Byte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAdd( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Byte_1(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] secondOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..1478fae32d8815 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.Int16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAdd_Vector128_Int16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAdd( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int16_1(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..f0194aafc6ef88 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.Int32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAdd_Vector128_Int32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAdd( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int32_1(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.Int64.1.cs new file mode 100644 index 00000000000000..806d40762d425c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.Int64.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAdd_Vector128_Int64_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAdd( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_Int64_1(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] secondOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..f63edb600924ed --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.SByte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAdd_Vector128_SByte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAdd( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_SByte_1(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..26aa47a7e2dc7f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.UInt16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAdd_Vector128_UInt16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAdd( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt16_1(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] secondOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..8dc3c3e367d11d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.UInt32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAdd_Vector128_UInt32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAdd( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt32_1(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] secondOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.UInt64.1.cs new file mode 100644 index 00000000000000..96703c835b70c6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector128.UInt64.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAdd_Vector128_UInt64_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt64_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAdd( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector128_UInt64_1(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] secondOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..6ebb0db2d3e094 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.Byte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAdd_Vector64_Byte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAdd( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Byte_1(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] secondOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..b0629b1e843d80 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.Int16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAdd_Vector64_Int16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAdd( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Int16_1(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..bc9794e0587278 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.Int32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAdd_Vector64_Int32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAdd( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_Int32_1(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..9e0306dd55dcd5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.SByte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAdd_Vector64_SByte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAdd( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_SByte_1(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..5e8f29029f7aa0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.UInt16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAdd_Vector64_UInt16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAdd( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_UInt16_1(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] secondOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..daeee69415c294 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAdd.Vector64.UInt32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAdd_Vector64_UInt32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAdd( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAdd_Vector64_UInt32_1(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] secondOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAddScalar.Vector64.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAddScalar.Vector64.Int64.1.cs new file mode 100644 index 00000000000000..f626835fc6c808 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAddScalar.Vector64.Int64.1.cs @@ -0,0 +1,423 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAddScalar_Vector64_Int64_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAddScalar_Vector64_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAddScalar_Vector64_Int64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAddScalar_Vector64_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAddScalar(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAddScalar_Vector64_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAddScalar_Vector64_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAddScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAddScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAddScalar), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAddScalar), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAddScalar( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAddScalar(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAddScalar(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAddScalar_Vector64_Int64_1(); + var result = AdvSimd.ShiftRightLogicalAddScalar(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAddScalar(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAddScalar(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] secondOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalAdd(firstOp[0], secondOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAddScalar)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAddScalar.Vector64.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAddScalar.Vector64.UInt64.1.cs new file mode 100644 index 00000000000000..d03bd9052dd669 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalAddScalar.Vector64.UInt64.1.cs @@ -0,0 +1,423 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalAddScalar_Vector64_UInt64_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalAddScalar_Vector64_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalAddScalar_Vector64_UInt64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalAddScalar_Vector64_UInt64_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalAddScalar(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalAddScalar_Vector64_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalAddScalar_Vector64_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalAddScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalAddScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAddScalar), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalAddScalar), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalAddScalar( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalAddScalar(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalAddScalar(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalAddScalar_Vector64_UInt64_1(); + var result = AdvSimd.ShiftRightLogicalAddScalar(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalAddScalar(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalAddScalar(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] secondOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalAdd(firstOp[0], secondOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalAddScalar)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..16fad752e05f44 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingLower_Vector64_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Byte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Byte_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Byte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowing(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..34b14eb6cd3b33 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingLower_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int16_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowing(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..852862ee7d409f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingLower_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int32_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_Int32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowing(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..57bb8893ca5062 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingLower_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_SByte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_SByte_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_SByte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowing(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..4508eb9a005a60 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingLower_Vector64_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt16_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowing(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..7a94c47c21f058 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingLower.Vector64.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingLower_Vector64_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt32_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingLower_Vector64_UInt32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowing(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..7f5dc434b8685e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateLower_Vector64_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Byte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Byte_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Byte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..aae58ce73f2a45 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateLower_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int16_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..a8068ef4cad654 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateLower_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int32_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_Int32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..64e843030bc481 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateLower_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_SByte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_SByte_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_SByte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..3b5795724645b5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt16_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..eeb668d918b3d6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateLower.Vector64.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt32_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..635790706e2136 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.Byte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateUpper_Vector128_Byte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, UInt16[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Byte_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] secondOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..d711d91384e153 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.Int16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int16_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..fb3922be3813c1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.Int32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int32_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..c961d2f62cbcf8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.SByte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateUpper_Vector128_SByte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_SByte_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..9be98e796867bf --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.UInt16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt32[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt16_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] secondOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..4d002a582247e4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingSaturateUpper.Vector128.UInt32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt64[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt32_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] secondOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..da2d8dc456c45a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.Byte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingUpper_Vector128_Byte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, UInt16[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Byte_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] secondOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..74e1b9423981ab --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.Int16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingUpper_Vector128_Int16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Int16_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..84d216eabb4143 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.Int32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingUpper_Vector128_Int32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_Int32_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..e4733c2473bc8b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.SByte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingUpper_Vector128_SByte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_SByte_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..96c09e59c8f877 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.UInt16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingUpper_Vector128_UInt16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt32[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_UInt16_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] secondOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..7242b26c4f1b21 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalNarrowingUpper.Vector128.UInt32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalNarrowingUpper_Vector128_UInt32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt64[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalNarrowingUpper_Vector128_UInt32_1(); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] secondOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalNarrowingUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..a05c067ffb0619 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRounded_Vector128_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Byte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Byte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Byte_1(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Byte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Byte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRounded)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..31f296e8222b73 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRounded_Vector128_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int16_1(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRounded)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..38a7d2ce38d11a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRounded_Vector128_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int32_1(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRounded)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.Int64.1.cs new file mode 100644 index 00000000000000..e90d9eb023e3aa --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.Int64.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRounded_Vector128_Int64_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int64_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int64_1(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_Int64_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRounded)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..2634b2403d7673 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRounded_Vector128_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_SByte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_SByte_1(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_SByte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRounded)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..6dae0d74e01fba --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRounded_Vector128_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt16_1(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRounded)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..c3cf5d1549f42f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRounded_Vector128_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt32_1(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRounded)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.UInt64.1.cs new file mode 100644 index 00000000000000..c82471766d7cc9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector128.UInt64.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRounded_Vector128_UInt64_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt64_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt64_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt64_1(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector128_UInt64_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector128((UInt64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRounded)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..c58b5475c78267 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRounded_Vector64_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Byte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Byte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Byte_1(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Byte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Byte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Byte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRounded)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..2cdf79c7a1f0f8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRounded_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int16_1(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRounded)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..2acebaf78c5670 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRounded_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int32_1(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_Int32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRounded)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..70c35c236dc332 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRounded_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_SByte_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((SByte*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_SByte_1(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_SByte_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((SByte*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((SByte*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRounded)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..4dce61b5e85985 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRounded_Vector64_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt16_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt16_1(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt16_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRounded)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..49a59f1782dade --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRounded.Vector64.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRounded_Vector64_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt32_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRounded( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRounded), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRounded(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt32_1(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRounded_Vector64_UInt32_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRounded(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRounded( + AdvSimd.LoadVector64((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRounded)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..5ae6329b39111a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.Byte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAdd_Vector128_Byte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Byte_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] secondOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..f235a22a9c4966 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.Int16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAdd_Vector128_Int16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int16_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..9e450700e34f0c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.Int32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAdd_Vector128_Int32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int32_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.Int64.1.cs new file mode 100644 index 00000000000000..51c1822310817c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.Int64.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAdd_Vector128_Int64_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_Int64_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] secondOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..16df705fe083fa --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.SByte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAdd_Vector128_SByte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_SByte_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..6a96d773637e73 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.UInt16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAdd_Vector128_UInt16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt16_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] secondOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..89c7ff5e8a109a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.UInt32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAdd_Vector128_UInt32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt32_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] secondOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.UInt64.1.cs new file mode 100644 index 00000000000000..1c72cd0d481e20 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector128.UInt64.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAdd_Vector128_UInt64_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt64_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector128_UInt64_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] secondOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAdd)}(Vector128.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..0a86b96dcfe614 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.Byte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAdd_Vector64_Byte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Byte_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] secondOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..e576757b44c44f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.Int16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAdd_Vector64_Int16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Int16_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..6549868f8e13ef --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.Int32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAdd_Vector64_Int32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_Int32_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..7d835b05b6d39f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.SByte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAdd_Vector64_SByte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_SByte_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..dedaac14dda3e6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.UInt16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAdd_Vector64_UInt16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_UInt16_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] secondOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..01774f2655abc3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAdd.Vector64.UInt32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAdd_Vector64_UInt32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAdd), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAdd_Vector64_UInt32_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAdd(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAdd(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] secondOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAdd)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAddScalar.Vector64.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAddScalar.Vector64.Int64.1.cs new file mode 100644 index 00000000000000..a9594721634359 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAddScalar.Vector64.Int64.1.cs @@ -0,0 +1,423 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAddScalar_Vector64_Int64_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAddScalar_Vector64_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAddScalar_Vector64_Int64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAddScalar_Vector64_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAddScalar_Vector64_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAddScalar_Vector64_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAddScalar), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAddScalar), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAddScalar_Vector64_Int64_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] secondOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[0], secondOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAddScalar)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAddScalar.Vector64.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAddScalar.Vector64.UInt64.1.cs new file mode 100644 index 00000000000000..5211283aa4848c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedAddScalar.Vector64.UInt64.1.cs @@ -0,0 +1,423 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedAddScalar_Vector64_UInt64_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAddScalar_Vector64_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedAddScalar_Vector64_UInt64_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedAddScalar_Vector64_UInt64_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedAddScalar_Vector64_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedAddScalar_Vector64_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAddScalar), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedAddScalar), new Type[] { typeof(Vector64), typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedAddScalar_Vector64_UInt64_1(); + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedAddScalar(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector64 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] secondOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalRoundedAdd(firstOp[0], secondOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedAddScalar)}(Vector64.1, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..9d870d5e424ed2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingLower_Vector64_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Byte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Byte_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Byte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowing(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..5f25720d78acb0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingLower_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int16_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowing(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..d11de0aeaa62f0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingLower_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int32_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_Int32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowing(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..2548dc60a827cc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingLower_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_SByte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_SByte_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_SByte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowing(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..2d1123813c1f87 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt16_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowing(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..d872562d59d865 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingLower.Vector64.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt32_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowing(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.Byte.1.cs new file mode 100644 index 00000000000000..3d52447cf9a049 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.Byte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Byte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Byte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray, Byte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Byte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Byte_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Byte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.Int16.1.cs new file mode 100644 index 00000000000000..ee9b1741fa829c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.Int16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray, Int16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int16_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.Int32.1.cs new file mode 100644 index 00000000000000..9baab4e0f49505 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.Int32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int32_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.SByte.1.cs new file mode 100644 index 00000000000000..c4e1483ad181df --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.SByte.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_SByte_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_SByte_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray, SByte[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_SByte_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_SByte_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_SByte_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((Int16*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.UInt16.1.cs new file mode 100644 index 00000000000000..435f4db3c6932b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.UInt16.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt16_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt16_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray, UInt16[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt16_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt32*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt16_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt16_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt32*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt32*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.UInt32.1.cs new file mode 100644 index 00000000000000..55728404f1147e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateLower.Vector64.UInt32.1.cs @@ -0,0 +1,500 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt32_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt32_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt32[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt32_1 testClass) + { + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector128 _clsVar; + + private Vector128 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower), new Type[] { typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt32_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt32_1(); + + fixed (Vector128* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower( + AdvSimd.LoadVector128((UInt64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateLower)}(Vector128, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..01298deaf16abd --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.Byte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Byte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, UInt16[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Byte_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] secondOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..e3224aaedb0251 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.Int16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int16_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..c8855546345e25 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.Int32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int32_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..6fd123737b4c1e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.SByte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_SByte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_SByte_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..4a500aac8380d3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.UInt16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt32[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt16_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] secondOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..572bf22ff08349 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingSaturateUpper.Vector128.UInt32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt64[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt32_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] secondOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingSaturateUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.Byte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.Byte.1.cs new file mode 100644 index 00000000000000..ab9fd0abfbf3d8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.Byte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingUpper_Vector128_Byte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Byte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Byte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, UInt16[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Byte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly byte Imm = 1; + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Byte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Byte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Byte_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] secondOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.Int16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.Int16.1.cs new file mode 100644 index 00000000000000..790ad2d1fb5f75 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.Int16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly byte Imm = 1; + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int16_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] secondOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.Int32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.Int32.1.cs new file mode 100644 index 00000000000000..d1da09400aa096 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.Int32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly byte Imm = 1; + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int32_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] secondOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.SByte.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.SByte.1.cs new file mode 100644 index 00000000000000..c909836b973bf2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.SByte.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingUpper_Vector128_SByte_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_SByte_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_SByte_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_SByte_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly byte Imm = 1; + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_SByte_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_SByte_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_SByte_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] secondOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.UInt16.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.UInt16.1.cs new file mode 100644 index 00000000000000..aebf41292401d6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.UInt16.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt16_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt16_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt16_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt32[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt16_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly byte Imm = 1; + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt16_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt16_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt16_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] secondOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.UInt32.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.UInt32.1.cs new file mode 100644 index 00000000000000..17296820b88b82 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedNarrowingUpper.Vector128.UInt32.1.cs @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt32_1() + { + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt32_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt32_1 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt64[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt32_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly byte Imm = 1; + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + + private Vector64 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt32_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt32_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var secondOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt32_1(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedNarrowingUpper(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, Vector128 secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] secondOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedNarrowingUpper)}(Vector64.1, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedScalar.Vector64.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedScalar.Vector64.Int64.1.cs new file mode 100644 index 00000000000000..927ae9381968be --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedScalar.Vector64.Int64.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedScalar_Vector64_Int64_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedScalar(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_Int64_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRoundedScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRoundedScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_Int64_1(); + var result = AdvSimd.ShiftRightLogicalRoundedScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_Int64_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedScalar(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalRounded(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedScalar)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedScalar.Vector64.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedScalar.Vector64.UInt64.1.cs new file mode 100644 index 00000000000000..ea06b0df0464da --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalRoundedScalar.Vector64.UInt64.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalRoundedScalar_Vector64_UInt64_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_UInt64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_UInt64_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalRoundedScalar(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_UInt64_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalRoundedScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + AdvSimd.LoadVector64((UInt64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalRoundedScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalRoundedScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_UInt64_1(); + var result = AdvSimd.ShiftRightLogicalRoundedScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalRoundedScalar_Vector64_UInt64_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalRoundedScalar(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalRoundedScalar( + AdvSimd.LoadVector64((UInt64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogicalRounded(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalRoundedScalar)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalScalar.Vector64.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalScalar.Vector64.Int64.1.cs new file mode 100644 index 00000000000000..033371510253ad --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalScalar.Vector64.Int64.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalScalar_Vector64_Int64_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_Int64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_Int64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray, Int64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_Int64_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalScalar(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_Int64_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly byte Imm = 1; + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_Int64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_Int64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalScalar( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((Int64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_Int64_1(); + var result = AdvSimd.ShiftRightLogicalScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_Int64_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalScalar(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalScalar( + AdvSimd.LoadVector64((Int64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogical(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalScalar)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalScalar.Vector64.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalScalar.Vector64.UInt64.1.cs new file mode 100644 index 00000000000000..1a5d9712e937b8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ShiftRightLogicalScalar.Vector64.UInt64.1.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ShiftRightLogicalScalar_Vector64_UInt64_1() + { + var test = new ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_UInt64_1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_UInt64_1 + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray, UInt64[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_UInt64_1 testClass) + { + var result = AdvSimd.ShiftRightLogicalScalar(_fld, 1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_UInt64_1 testClass) + { + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly byte Imm = 1; + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector64 _clsVar; + + private Vector64 _fld; + + private DataTable _dataTable; + + static ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_UInt64_1() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + } + + public ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_UInt64_1() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ShiftRightLogicalScalar( + Unsafe.Read>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ShiftRightLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ShiftRightLogicalScalar), new Type[] { typeof(Vector64), typeof(byte) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ShiftRightLogicalScalar( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar = &_clsVar) + { + var result = AdvSimd.ShiftRightLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(pClsVar)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read>(_dataTable.inArrayPtr); + var result = AdvSimd.ShiftRightLogicalScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArrayPtr)); + var result = AdvSimd.ShiftRightLogicalScalar(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_UInt64_1(); + var result = AdvSimd.ShiftRightLogicalScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ImmUnaryOpTest__ShiftRightLogicalScalar_Vector64_UInt64_1(); + + fixed (Vector64* pFld = &test._fld) + { + var result = AdvSimd.ShiftRightLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ShiftRightLogicalScalar(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld = &_fld) + { + var result = AdvSimd.ShiftRightLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(pFld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalScalar(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ShiftRightLogicalScalar( + AdvSimd.LoadVector64((UInt64*)(&test._fld)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.ShiftRightLogical(firstOp[0], Imm) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ShiftRightLogicalScalar)}(Vector64, 1): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningLower.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningLower.Vector64.Int16.cs new file mode 100644 index 00000000000000..56f22324ee1d6b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningLower.Vector64.Int16.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SignExtendWideningLower_Vector64_Int16() + { + var test = new SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int16 testClass) + { + var result = AdvSimd.SignExtendWideningLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SignExtendWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SignExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SignExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SignExtendWideningLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((Int16*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.SignExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.SignExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int16(); + var result = AdvSimd.SignExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SignExtendWideningLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SignExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((Int16*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SignExtendWidening(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SignExtendWideningLower)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningLower.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningLower.Vector64.Int32.cs new file mode 100644 index 00000000000000..2a4f37f3de22c4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningLower.Vector64.Int32.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SignExtendWideningLower_Vector64_Int32() + { + var test = new SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int32 testClass) + { + var result = AdvSimd.SignExtendWideningLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SignExtendWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SignExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SignExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SignExtendWideningLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((Int32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.SignExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.SignExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int32(); + var result = AdvSimd.SignExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__SignExtendWideningLower_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SignExtendWideningLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SignExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((Int32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SignExtendWidening(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SignExtendWideningLower)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningLower.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningLower.Vector64.SByte.cs new file mode 100644 index 00000000000000..6e3505931d333f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningLower.Vector64.SByte.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SignExtendWideningLower_Vector64_SByte() + { + var test = new SimpleUnaryOpTest__SignExtendWideningLower_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__SignExtendWideningLower_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__SignExtendWideningLower_Vector64_SByte testClass) + { + var result = AdvSimd.SignExtendWideningLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__SignExtendWideningLower_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__SignExtendWideningLower_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__SignExtendWideningLower_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SignExtendWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SignExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SignExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SignExtendWideningLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((SByte*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.SignExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.SignExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__SignExtendWideningLower_Vector64_SByte(); + var result = AdvSimd.SignExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__SignExtendWideningLower_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SignExtendWideningLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SignExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SignExtendWideningLower( + AdvSimd.LoadVector64((SByte*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SignExtendWidening(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SignExtendWideningLower)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningUpper.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningUpper.Vector128.Int16.cs new file mode 100644 index 00000000000000..ecfa8a20c99bac --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningUpper.Vector128.Int16.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SignExtendWideningUpper_Vector128_Int16() + { + var test = new SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int16 testClass) + { + var result = AdvSimd.SignExtendWideningUpper(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SignExtendWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SignExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SignExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SignExtendWideningUpper( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((Int16*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.SignExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.SignExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int16(); + var result = AdvSimd.SignExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SignExtendWideningUpper(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SignExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((Int16*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SignExtendWideningUpper(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SignExtendWideningUpper)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningUpper.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningUpper.Vector128.Int32.cs new file mode 100644 index 00000000000000..67de15d90c51b3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningUpper.Vector128.Int32.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SignExtendWideningUpper_Vector128_Int32() + { + var test = new SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int32 testClass) + { + var result = AdvSimd.SignExtendWideningUpper(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SignExtendWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SignExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SignExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SignExtendWideningUpper( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((Int32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.SignExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.SignExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int32(); + var result = AdvSimd.SignExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SignExtendWideningUpper(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SignExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((Int32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SignExtendWideningUpper(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SignExtendWideningUpper)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningUpper.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningUpper.Vector128.SByte.cs new file mode 100644 index 00000000000000..7089ef21d2818f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SignExtendWideningUpper.Vector128.SByte.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SignExtendWideningUpper_Vector128_SByte() + { + var test = new SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_SByte testClass) + { + var result = AdvSimd.SignExtendWideningUpper(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SignExtendWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SignExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SignExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SignExtendWideningUpper( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((SByte*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.SignExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.SignExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_SByte(); + var result = AdvSimd.SignExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__SignExtendWideningUpper_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SignExtendWideningUpper(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SignExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SignExtendWideningUpper( + AdvSimd.LoadVector128((SByte*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SignExtendWideningUpper(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SignExtendWideningUpper)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.Byte.cs new file mode 100644 index 00000000000000..7c14bab8bceda4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractHighNarrowingLower_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Byte testClass) + { + var result = AdvSimd.SubtractHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Byte(); + var result = AdvSimd.SubtractHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.Int16.cs new file mode 100644 index 00000000000000..35a46432526308 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractHighNarrowingLower_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int16 testClass) + { + var result = AdvSimd.SubtractHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int16(); + var result = AdvSimd.SubtractHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.Int32.cs new file mode 100644 index 00000000000000..b724f5789340ad --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractHighNarrowingLower_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int32 testClass) + { + var result = AdvSimd.SubtractHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int32(); + var result = AdvSimd.SubtractHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.SByte.cs new file mode 100644 index 00000000000000..bec44ddbbe0cc7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractHighNarrowingLower_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_SByte testClass) + { + var result = AdvSimd.SubtractHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_SByte(); + var result = AdvSimd.SubtractHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.UInt16.cs new file mode 100644 index 00000000000000..cf9fcc96c1a4c1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractHighNarrowingLower_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt16 testClass) + { + var result = AdvSimd.SubtractHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt16(); + var result = AdvSimd.SubtractHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.UInt32.cs new file mode 100644 index 00000000000000..e1ae11ce888609 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingLower.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractHighNarrowingLower_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt32 testClass) + { + var result = AdvSimd.SubtractHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((UInt64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt32(); + var result = AdvSimd.SubtractHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractHighNarrowingLower_Vector64_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((UInt64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.Byte.cs new file mode 100644 index 00000000000000..abd79e02847227 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.Byte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractHighNarrowingUpper_Vector128_Byte() + { + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, UInt16[] inArray2, UInt16[] inArray3, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Byte testClass) + { + var result = AdvSimd.SubtractHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + private static UInt16[] _data3 = new UInt16[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)), + AdvSimd.LoadVector128((UInt16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.SubtractHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.SubtractHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Byte(); + var result = AdvSimd.SubtractHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)), + AdvSimd.LoadVector128((UInt16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] secondOp, UInt16[] thirdOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.Int16.cs new file mode 100644 index 00000000000000..35c625d971cf1c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.Int16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractHighNarrowingUpper_Vector128_Int16() + { + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] inArray2, Int32[] inArray3, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int16 testClass) + { + var result = AdvSimd.SubtractHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + private static Int32[] _data3 = new Int32[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)), + AdvSimd.LoadVector128((Int32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.SubtractHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.SubtractHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int16(); + var result = AdvSimd.SubtractHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)), + AdvSimd.LoadVector128((Int32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] secondOp, Int32[] thirdOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.Int32.cs new file mode 100644 index 00000000000000..d31f07ce3f91ff --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.Int32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractHighNarrowingUpper_Vector128_Int32() + { + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] inArray2, Int64[] inArray3, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int32 testClass) + { + var result = AdvSimd.SubtractHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)), + AdvSimd.LoadVector128((Int64*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + private static Int64[] _data3 = new Int64[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)), + AdvSimd.LoadVector128((Int64*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.SubtractHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.SubtractHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int32(); + var result = AdvSimd.SubtractHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)), + AdvSimd.LoadVector128((Int64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)), + AdvSimd.LoadVector128((Int64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)), + AdvSimd.LoadVector128((Int64*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] inArray3 = new Int64[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] inArray3 = new Int64[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] secondOp, Int64[] thirdOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.SByte.cs new file mode 100644 index 00000000000000..c1f3e06e1e84b1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.SByte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractHighNarrowingUpper_Vector128_SByte() + { + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] inArray2, Int16[] inArray3, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_SByte testClass) + { + var result = AdvSimd.SubtractHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + private static Int16[] _data3 = new Int16[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)), + AdvSimd.LoadVector128((Int16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.SubtractHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.SubtractHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_SByte(); + var result = AdvSimd.SubtractHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)), + AdvSimd.LoadVector128((Int16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] secondOp, Int16[] thirdOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.UInt16.cs new file mode 100644 index 00000000000000..2ce1511a3bcc5e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.UInt16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractHighNarrowingUpper_Vector128_UInt16() + { + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt32[] inArray2, UInt32[] inArray3, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt16 testClass) + { + var result = AdvSimd.SubtractHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + private static UInt32[] _data3 = new UInt32[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)), + AdvSimd.LoadVector128((UInt32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.SubtractHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.SubtractHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt16(); + var result = AdvSimd.SubtractHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)), + AdvSimd.LoadVector128((UInt32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] secondOp, UInt32[] thirdOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.UInt32.cs new file mode 100644 index 00000000000000..bb378397a87588 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractHighNarrowingUpper.Vector128.UInt32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractHighNarrowingUpper_Vector128_UInt32() + { + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt64[] inArray2, UInt64[] inArray3, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt32 testClass) + { + var result = AdvSimd.SubtractHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)), + AdvSimd.LoadVector128((UInt64*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + private static UInt64[] _data3 = new UInt64[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt64*)(pClsVar2)), + AdvSimd.LoadVector128((UInt64*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.SubtractHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.SubtractHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt32(); + var result = AdvSimd.SubtractHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__SubtractHighNarrowingUpper_Vector128_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)), + AdvSimd.LoadVector128((UInt64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)), + AdvSimd.LoadVector128((UInt64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt64*)(&test._fld2)), + AdvSimd.LoadVector128((UInt64*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] inArray3 = new UInt64[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] inArray3 = new UInt64[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] secondOp, UInt64[] thirdOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.Byte.cs new file mode 100644 index 00000000000000..4eac8fc9b11c06 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractRoundedHighNarrowingLower_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Byte testClass) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Byte(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractRoundedHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractRoundedHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.Int16.cs new file mode 100644 index 00000000000000..a538bca9192be0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractRoundedHighNarrowingLower_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int16 testClass) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int16(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractRoundedHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractRoundedHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.Int32.cs new file mode 100644 index 00000000000000..e2c23aad0121d6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractRoundedHighNarrowingLower_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int32 testClass) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int32(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractRoundedHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractRoundedHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.SByte.cs new file mode 100644 index 00000000000000..e1c53772276b89 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractRoundedHighNarrowingLower_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_SByte testClass) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_SByte(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractRoundedHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractRoundedHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.UInt16.cs new file mode 100644 index 00000000000000..d83de1959b87fc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractRoundedHighNarrowingLower_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt16 testClass) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt16(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractRoundedHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractRoundedHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.UInt32.cs new file mode 100644 index 00000000000000..ea17396a4306f2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingLower.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractRoundedHighNarrowingLower_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt32 testClass) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingLower), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((UInt64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt32(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractRoundedHighNarrowingLower_Vector64_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingLower( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((UInt64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractRoundedHighNarrowing(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractRoundedHighNarrowingLower)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.Byte.cs new file mode 100644 index 00000000000000..2dd7c3918c6e05 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.Byte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractRoundedHighNarrowingUpper_Vector128_Byte() + { + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, UInt16[] inArray2, UInt16[] inArray3, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Byte testClass) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + private static UInt16[] _data3 = new UInt16[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)), + AdvSimd.LoadVector128((UInt16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Byte(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)), + AdvSimd.LoadVector128((UInt16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)), + AdvSimd.LoadVector128((UInt16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] inArray3 = new UInt16[Op3ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] secondOp, UInt16[] thirdOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractRoundedHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.Int16.cs new file mode 100644 index 00000000000000..73b854f868af50 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.Int16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractRoundedHighNarrowingUpper_Vector128_Int16() + { + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] inArray2, Int32[] inArray3, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int16 testClass) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + private static Int32[] _data3 = new Int32[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)), + AdvSimd.LoadVector128((Int32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int16(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)), + AdvSimd.LoadVector128((Int32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)), + AdvSimd.LoadVector128((Int32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] inArray3 = new Int32[Op3ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] secondOp, Int32[] thirdOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractRoundedHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.Int32.cs new file mode 100644 index 00000000000000..4ab22c7a31f63c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.Int32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractRoundedHighNarrowingUpper_Vector128_Int32() + { + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] inArray2, Int64[] inArray3, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int32 testClass) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)), + AdvSimd.LoadVector128((Int64*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + private static Int64[] _data3 = new Int64[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, _data3, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)), + AdvSimd.LoadVector128((Int64*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int32(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)), + AdvSimd.LoadVector128((Int64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)), + AdvSimd.LoadVector128((Int64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)), + AdvSimd.LoadVector128((Int64*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] inArray3 = new Int64[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] inArray3 = new Int64[Op3ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] secondOp, Int64[] thirdOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractRoundedHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.SByte.cs new file mode 100644 index 00000000000000..e2ecb71bfc0681 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.SByte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractRoundedHighNarrowingUpper_Vector128_SByte() + { + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] inArray2, Int16[] inArray3, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_SByte testClass) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + private static Int16[] _data3 = new Int16[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, _data3, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)), + AdvSimd.LoadVector128((Int16*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_SByte(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)), + AdvSimd.LoadVector128((Int16*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)), + AdvSimd.LoadVector128((Int16*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] inArray3 = new Int16[Op3ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] secondOp, Int16[] thirdOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractRoundedHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.UInt16.cs new file mode 100644 index 00000000000000..3080f3c0002dd4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.UInt16.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractRoundedHighNarrowingUpper_Vector128_UInt16() + { + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt32[] inArray2, UInt32[] inArray3, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt16 testClass) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + private static UInt32[] _data3 = new UInt32[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)), + AdvSimd.LoadVector128((UInt32*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt16(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)), + AdvSimd.LoadVector128((UInt32*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)), + AdvSimd.LoadVector128((UInt32*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] inArray3 = new UInt32[Op3ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] secondOp, UInt32[] thirdOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractRoundedHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.UInt32.cs new file mode 100644 index 00000000000000..da9245113a1400 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractRoundedHighNarrowingUpper.Vector128.UInt32.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractRoundedHighNarrowingUpper_Vector128_UInt32() + { + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt64[] inArray2, UInt64[] inArray3, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector128 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt32 testClass) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)), + AdvSimd.LoadVector128((UInt64*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + private static UInt64[] _data3 = new UInt64[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector128 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector128 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, _data3, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractRoundedHighNarrowingUpper), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector128* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt64*)(pClsVar2)), + AdvSimd.LoadVector128((UInt64*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt32(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__SubtractRoundedHighNarrowingUpper_Vector128_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector128* pFld3 = &test._fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)), + AdvSimd.LoadVector128((UInt64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector128* pFld3 = &_fld3) + { + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)), + AdvSimd.LoadVector128((UInt64*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractRoundedHighNarrowingUpper( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt64*)(&test._fld2)), + AdvSimd.LoadVector128((UInt64*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector128 op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] inArray3 = new UInt64[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] inArray3 = new UInt64[Op3ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] secondOp, UInt64[] thirdOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractRoundedHighNarrowingUpper)}(Vector64, Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.Byte.cs new file mode 100644 index 00000000000000..819b65668fba10 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturate_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturate_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturate_Vector128_Byte testClass) + { + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturate_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturate_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturate_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_Byte(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.Int16.cs new file mode 100644 index 00000000000000..6d8786a176389d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturate_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturate_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturate_Vector128_Int16 testClass) + { + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturate_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturate_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturate_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_Int16(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.Int32.cs new file mode 100644 index 00000000000000..0a43f7e90c6b51 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturate_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturate_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturate_Vector128_Int32 testClass) + { + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturate_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturate_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturate_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_Int32(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.Int64.cs new file mode 100644 index 00000000000000..1ff680d197cab5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.Int64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturate_Vector128_Int64() + { + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturate_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturate_Vector128_Int64 testClass) + { + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturate_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturate_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturate_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_Int64(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.SByte.cs new file mode 100644 index 00000000000000..5d2df7b14f857d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturate_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturate_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturate_Vector128_SByte testClass) + { + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturate_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturate_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturate_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_SByte(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.UInt16.cs new file mode 100644 index 00000000000000..63e80da412ae20 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturate_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt16 testClass) + { + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt16(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.UInt32.cs new file mode 100644 index 00000000000000..0c16dd46bfeee5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturate_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt32 testClass) + { + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt32(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.UInt64.cs new file mode 100644 index 00000000000000..88d4c684f5caa7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector128.UInt64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturate_Vector128_UInt64() + { + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt64 testClass) + { + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((UInt64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt64(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector128_UInt64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((UInt64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturate)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.Byte.cs new file mode 100644 index 00000000000000..c8ffac25c8fcba --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturate_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturate_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturate_Vector64_Byte testClass) + { + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturate_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturate_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturate_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_Byte(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.Int16.cs new file mode 100644 index 00000000000000..2dd3e419c377fd --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturate_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturate_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturate_Vector64_Int16 testClass) + { + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturate_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturate_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturate_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_Int16(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.Int32.cs new file mode 100644 index 00000000000000..3aa1c633dc0395 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturate_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturate_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturate_Vector64_Int32 testClass) + { + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturate_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturate_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturate_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_Int32(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.SByte.cs new file mode 100644 index 00000000000000..b374004e5af24f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturate_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturate_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturate_Vector64_SByte testClass) + { + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturate_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturate_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturate_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_SByte(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.UInt16.cs new file mode 100644 index 00000000000000..b714d73d802d87 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturate_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt16 testClass) + { + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt16(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.UInt32.cs new file mode 100644 index 00000000000000..363584061cc15e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturate.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturate_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt32 testClass) + { + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturate( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturate), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturate( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturate(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt32(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturate_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturate(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturate( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractSaturate(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturate)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturateScalar.Vector64.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturateScalar.Vector64.Int64.cs new file mode 100644 index 00000000000000..e17066792a4f26 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturateScalar.Vector64.Int64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturateScalar_Vector64_Int64() + { + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int64 testClass) + { + var result = AdvSimd.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int64(); + var result = AdvSimd.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_Int64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturateScalar( + AdvSimd.LoadVector64((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.SubtractSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturateScalar.Vector64.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturateScalar.Vector64.UInt64.cs new file mode 100644 index 00000000000000..0966536405c5cb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractSaturateScalar.Vector64.UInt64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractSaturateScalar_Vector64_UInt64() + { + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt64 testClass) + { + var result = AdvSimd.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 8; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractSaturateScalar( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractSaturateScalar), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractSaturateScalar( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pClsVar1)), + AdvSimd.LoadVector64((UInt64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractSaturateScalar(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt64(); + var result = AdvSimd.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractSaturateScalar_Vector64_UInt64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractSaturateScalar(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturateScalar(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractSaturateScalar( + AdvSimd.LoadVector64((UInt64*)(&test._fld1)), + AdvSimd.LoadVector64((UInt64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.SubtractSaturate(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != 0) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractSaturateScalar)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.Int16.cs new file mode 100644 index 00000000000000..794b10b5ca6f97 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningLower_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, SByte[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int16 testClass) + { + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + + private Vector128 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int16(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, SByte[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningLower)}(Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.Int32.cs new file mode 100644 index 00000000000000..b5c3050bbcb015 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningLower_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int16[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int32 testClass) + { + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + + private Vector128 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int32(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningLower)}(Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.Int64.cs new file mode 100644 index 00000000000000..c123ae92690cfc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.Int64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningLower_Vector128_Int64() + { + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int32[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int64 testClass) + { + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + + private Vector128 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int64(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int32[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningLower)}(Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.UInt16.cs new file mode 100644 index 00000000000000..d62598f8399207 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningLower_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt16 testClass) + { + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + + private Vector128 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt16(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningLower)}(Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.UInt32.cs new file mode 100644 index 00000000000000..6221af60ce7f60 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningLower_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt32 testClass) + { + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + + private Vector128 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt32(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningLower)}(Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.UInt64.cs new file mode 100644 index 00000000000000..3ac30ed6e4e6eb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector128.UInt64.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningLower_Vector128_UInt64() + { + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt64 testClass) + { + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + + private Vector128 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt64(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector128_UInt64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningLower)}(Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.Byte.cs new file mode 100644 index 00000000000000..0d70572f26881b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningLower_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningLower_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningLower_Vector64_Byte testClass) + { + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningLower_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningLower_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningLower_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_Byte(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.Int16.cs new file mode 100644 index 00000000000000..a6e98b282033d0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningLower_Vector64_Int16() + { + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int16 testClass) + { + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Int16*)(pClsVar1)), + AdvSimd.LoadVector64((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int16(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)), + AdvSimd.LoadVector64((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Int16*)(&test._fld1)), + AdvSimd.LoadVector64((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.Int32.cs new file mode 100644 index 00000000000000..39e6436c58e6c4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningLower_Vector64_Int32() + { + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int32 testClass) + { + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Int32*)(pClsVar1)), + AdvSimd.LoadVector64((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int32(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)), + AdvSimd.LoadVector64((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((Int32*)(&test._fld1)), + AdvSimd.LoadVector64((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.SByte.cs new file mode 100644 index 00000000000000..e9b18e40694fee --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningLower_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningLower_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningLower_Vector64_SByte testClass) + { + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningLower_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningLower_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningLower_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_SByte(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.UInt16.cs new file mode 100644 index 00000000000000..dd69d4d47116da --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningLower_Vector64_UInt16() + { + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt16 testClass) + { + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)), + AdvSimd.LoadVector64((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt16(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)), + AdvSimd.LoadVector64((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)), + AdvSimd.LoadVector64((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.UInt32.cs new file mode 100644 index 00000000000000..0f539eec3828eb --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningLower.Vector64.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningLower_Vector64_UInt32() + { + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt32 testClass) + { + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)), + AdvSimd.LoadVector64((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt32(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningLower_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)), + AdvSimd.LoadVector64((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningLower( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)), + AdvSimd.LoadVector64((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWidening(left[i], right[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Byte.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Byte.Vector128.Byte.cs new file mode 100644 index 00000000000000..3e07314e77cb67 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Byte.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningUpper_Vector128_Byte_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Byte_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Byte_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Byte_Vector128_Byte testClass) + { + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Byte_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Byte_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Byte_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Byte_Vector128_Byte(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Byte_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int16.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int16.Vector128.Int16.cs new file mode 100644 index 00000000000000..630a578f00cd6c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int16.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningUpper_Vector128_Int16_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int16[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_Int16 testClass) + { + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_Int16(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int16.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int16.Vector128.SByte.cs new file mode 100644 index 00000000000000..af9e086fd290b1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int16.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningUpper_Vector128_Int16_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, SByte[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_SByte testClass) + { + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int16*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_SByte(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int16_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int16*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, SByte[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int32.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int32.Vector128.Int16.cs new file mode 100644 index 00000000000000..09c9ae171d13c1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int32.Vector128.Int16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningUpper_Vector128_Int32_Vector128_Int16() + { + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int16[] inArray2, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int16 testClass) + { + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int16(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int32.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int32.Vector128.Int32.cs new file mode 100644 index 00000000000000..85fc88e4bd5768 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int32.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningUpper_Vector128_Int32_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int32[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int32 testClass) + { + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int32*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int32(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int32_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int32*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int64.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int64.Vector128.Int32.cs new file mode 100644 index 00000000000000..139c47e29cb785 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.Int64.Vector128.Int32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningUpper_Vector128_Int64_Vector128_Int32() + { + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int64_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int64_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int32[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int64_Vector128_Int32 testClass) + { + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int64_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int32[] _data2 = new Int32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int64_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int64_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int64_Vector128_Int32(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_Int64_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int32[] inArray2 = new Int32[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int32[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.SByte.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.SByte.Vector128.SByte.cs new file mode 100644 index 00000000000000..3317e501e142c4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.SByte.Vector128.SByte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningUpper_Vector128_SByte_Vector128_SByte() + { + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_SByte_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningUpper_Vector128_SByte_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_SByte_Vector128_SByte testClass) + { + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_SByte_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningUpper_Vector128_SByte_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningUpper_Vector128_SByte_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, _data2, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_SByte_Vector128_SByte(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_SByte_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt16.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt16.Vector128.Byte.cs new file mode 100644 index 00000000000000..1601acf83ea114 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt16.Vector128.Byte.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningUpper_Vector128_UInt16_Vector128_Byte() + { + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, Byte[] inArray2, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_Byte testClass) + { + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_Byte(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt16.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt16.Vector128.UInt16.cs new file mode 100644 index 00000000000000..8e1fce4ed222ff --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt16.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningUpper_Vector128_UInt16_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_UInt16 testClass) + { + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_UInt16(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt16_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt32.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt32.Vector128.UInt16.cs new file mode 100644 index 00000000000000..eb2599152351ad --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt32.Vector128.UInt16.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningUpper_Vector128_UInt32_Vector128_UInt16() + { + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt16[] inArray2, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt16 testClass) + { + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt16[] _data2 = new UInt16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt16*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt16(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt16*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt16*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt16[] inArray2 = new UInt16[Op2ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt16[] right, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt32.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt32.Vector128.UInt32.cs new file mode 100644 index 00000000000000..c41cb5a219b4fa --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt32.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningUpper_Vector128_UInt32_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt32 testClass) + { + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt32(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt32_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt64.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt64.Vector128.UInt32.cs new file mode 100644 index 00000000000000..655c9f2846a48f --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/SubtractWideningUpper.Vector128.UInt64.Vector128.UInt32.cs @@ -0,0 +1,530 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void SubtractWideningUpper_Vector128_UInt64_Vector128_UInt32() + { + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt64_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt64_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt32[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt64_Vector128_UInt32 testClass) + { + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt64_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt32[] _data2 = new UInt32[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt64_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt64_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.SubtractWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.SubtractWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.SubtractWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((UInt32*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.SubtractWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt64_Vector128_UInt32(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__SubtractWideningUpper_Vector128_UInt64_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.SubtractWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt32*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.SubtractWideningUpper( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((UInt32*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt32[] inArray2 = new UInt32[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt32[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.SubtractWideningUpper(left, right, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.SubtractWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/VectorTableLookup.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/VectorTableLookup.Vector64.Byte.cs new file mode 100644 index 00000000000000..d2b76cb956cf4c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/VectorTableLookup.Vector64.Byte.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void VectorTableLookup_Vector64_Byte() + { + var test = new SimpleBinaryOpTest__VectorTableLookup_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__VectorTableLookup_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__VectorTableLookup_Vector64_Byte testClass) + { + var result = AdvSimd.VectorTableLookup(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__VectorTableLookup_Vector64_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.VectorTableLookup( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + + private Vector128 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__VectorTableLookup_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__VectorTableLookup_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + _dataTable = new DataTable(_data1, _data2, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.VectorTableLookup( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.VectorTableLookup( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.VectorTableLookup), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.VectorTableLookup), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.VectorTableLookup( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.VectorTableLookup( + AdvSimd.LoadVector128((Byte*)(pClsVar1)), + AdvSimd.LoadVector64((Byte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.VectorTableLookup(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.VectorTableLookup(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__VectorTableLookup_Vector64_Byte(); + var result = AdvSimd.VectorTableLookup(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__VectorTableLookup_Vector64_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.VectorTableLookup( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.VectorTableLookup(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.VectorTableLookup( + AdvSimd.LoadVector128((Byte*)(pFld1)), + AdvSimd.LoadVector64((Byte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.VectorTableLookup(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.VectorTableLookup( + AdvSimd.LoadVector128((Byte*)(&test._fld1)), + AdvSimd.LoadVector64((Byte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.TableVectorLookup(0, right, left) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (Helpers.TableVectorLookup(i, right, left) != result[i]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.VectorTableLookup)}(Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/VectorTableLookup.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/VectorTableLookup.Vector64.SByte.cs new file mode 100644 index 00000000000000..1abebfead04c5c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/VectorTableLookup.Vector64.SByte.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void VectorTableLookup_Vector64_SByte() + { + var test = new SimpleBinaryOpTest__VectorTableLookup_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__VectorTableLookup_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__VectorTableLookup_Vector64_SByte testClass) + { + var result = AdvSimd.VectorTableLookup(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__VectorTableLookup_Vector64_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.VectorTableLookup( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector64 _clsVar2; + + private Vector128 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__VectorTableLookup_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__VectorTableLookup_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + _dataTable = new DataTable(_data1, _data2, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.VectorTableLookup( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.VectorTableLookup( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.VectorTableLookup), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.VectorTableLookup), new Type[] { typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.VectorTableLookup( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = AdvSimd.VectorTableLookup( + AdvSimd.LoadVector128((SByte*)(pClsVar1)), + AdvSimd.LoadVector64((SByte*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = AdvSimd.VectorTableLookup(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray2Ptr)); + var result = AdvSimd.VectorTableLookup(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__VectorTableLookup_Vector64_SByte(); + var result = AdvSimd.VectorTableLookup(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__VectorTableLookup_Vector64_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = AdvSimd.VectorTableLookup( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.VectorTableLookup(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = AdvSimd.VectorTableLookup( + AdvSimd.LoadVector128((SByte*)(pFld1)), + AdvSimd.LoadVector64((SByte*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.VectorTableLookup(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.VectorTableLookup( + AdvSimd.LoadVector128((SByte*)(&test._fld1)), + AdvSimd.LoadVector64((SByte*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.TableVectorLookup(0, right, left) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (Helpers.TableVectorLookup(i, right, left) != result[i]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.VectorTableLookup)}(Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/VectorTableLookupExtension.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/VectorTableLookupExtension.Vector64.Byte.cs new file mode 100644 index 00000000000000..eff0d429839f46 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/VectorTableLookupExtension.Vector64.Byte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void VectorTableLookupExtension_Vector64_Byte() + { + var test = new SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, Byte[] inArray2, Byte[] inArray3, Byte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_Byte testClass) + { + var result = AdvSimd.VectorTableLookupExtension(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.VectorTableLookupExtension( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + private static Byte[] _data3 = new Byte[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector64 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (Byte)(TestLibrary.Generator.GetByte() % 20); } + _dataTable = new DataTable(_data1, _data2, _data3, new Byte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.VectorTableLookupExtension( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.VectorTableLookupExtension( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.VectorTableLookupExtension), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.VectorTableLookupExtension), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.VectorTableLookupExtension( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.VectorTableLookupExtension( + AdvSimd.LoadVector64((Byte*)(pClsVar1)), + AdvSimd.LoadVector128((Byte*)(pClsVar2)), + AdvSimd.LoadVector64((Byte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.VectorTableLookupExtension(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.VectorTableLookupExtension(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_Byte(); + var result = AdvSimd.VectorTableLookupExtension(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.VectorTableLookupExtension( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.VectorTableLookupExtension(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.VectorTableLookupExtension( + AdvSimd.LoadVector64((Byte*)(pFld1)), + AdvSimd.LoadVector128((Byte*)(pFld2)), + AdvSimd.LoadVector64((Byte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.VectorTableLookupExtension(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.VectorTableLookupExtension( + AdvSimd.LoadVector64((Byte*)(&test._fld1)), + AdvSimd.LoadVector128((Byte*)(&test._fld2)), + AdvSimd.LoadVector64((Byte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + Byte[] inArray3 = new Byte[Op3ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] secondOp, Byte[] thirdOp, Byte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.TableVectorExtension(i, firstOp, thirdOp, secondOp) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.VectorTableLookupExtension)}(Vector64, Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/VectorTableLookupExtension.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/VectorTableLookupExtension.Vector64.SByte.cs new file mode 100644 index 00000000000000..7dc979fbadbbf6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/VectorTableLookupExtension.Vector64.SByte.cs @@ -0,0 +1,571 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void VectorTableLookupExtension_Vector64_SByte() + { + var test = new SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] inArray3; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle inHandle3; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, SByte[] inArray2, SByte[] inArray3, SByte[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfinArray3 = inArray3.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfinArray3 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.inArray3 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray3Ptr), ref Unsafe.As(ref inArray3[0]), (uint)sizeOfinArray3); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + inHandle3.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector128 _fld2; + public Vector64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_SByte testClass) + { + var result = AdvSimd.VectorTableLookupExtension(_fld1, _fld2, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.VectorTableLookupExtension( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int Op3ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + private static SByte[] _data2 = new SByte[Op2ElementCount]; + private static SByte[] _data3 = new SByte[Op3ElementCount]; + + private static Vector64 _clsVar1; + private static Vector128 _clsVar2; + private static Vector64 _clsVar3; + + private Vector64 _fld1; + private Vector128 _fld2; + private Vector64 _fld3; + + private DataTable _dataTable; + + static SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld3), ref Unsafe.As(ref _data3[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetSByte(); } + for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (SByte)(TestLibrary.Generator.GetSByte() % 20); } + _dataTable = new DataTable(_data1, _data2, _data3, new SByte[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.VectorTableLookupExtension( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.VectorTableLookupExtension( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.VectorTableLookupExtension), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr), + Unsafe.Read>(_dataTable.inArray3Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.VectorTableLookupExtension), new Type[] { typeof(Vector64), typeof(Vector128), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)), + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector64)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.VectorTableLookupExtension( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + fixed (Vector64* pClsVar3 = &_clsVar3) + { + var result = AdvSimd.VectorTableLookupExtension( + AdvSimd.LoadVector64((SByte*)(pClsVar1)), + AdvSimd.LoadVector128((SByte*)(pClsVar2)), + AdvSimd.LoadVector64((SByte*)(pClsVar3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var op3 = Unsafe.Read>(_dataTable.inArray3Ptr); + var result = AdvSimd.VectorTableLookupExtension(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray2Ptr)); + var op3 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray3Ptr)); + var result = AdvSimd.VectorTableLookupExtension(op1, op2, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_SByte(); + var result = AdvSimd.VectorTableLookupExtension(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleTernaryOpTest__VectorTableLookupExtension_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + fixed (Vector64* pFld3 = &test._fld3) + { + var result = AdvSimd.VectorTableLookupExtension( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.VectorTableLookupExtension(_fld1, _fld2, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + fixed (Vector64* pFld3 = &_fld3) + { + var result = AdvSimd.VectorTableLookupExtension( + AdvSimd.LoadVector64((SByte*)(pFld1)), + AdvSimd.LoadVector128((SByte*)(pFld2)), + AdvSimd.LoadVector64((SByte*)(pFld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.VectorTableLookupExtension(test._fld1, test._fld2, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.VectorTableLookupExtension( + AdvSimd.LoadVector64((SByte*)(&test._fld1)), + AdvSimd.LoadVector128((SByte*)(&test._fld2)), + AdvSimd.LoadVector64((SByte*)(&test._fld3)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector128 op2, Vector64 op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray3[0]), op3); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* op3, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + SByte[] inArray2 = new SByte[Op2ElementCount]; + SByte[] inArray3 = new SByte[Op3ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray3[0]), ref Unsafe.AsRef(op3), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, inArray3, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] secondOp, SByte[] thirdOp, SByte[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.TableVectorExtension(i, firstOp, thirdOp, secondOp) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.VectorTableLookupExtension)}(Vector64, Vector128, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.Byte.cs new file mode 100644 index 00000000000000..0519407fbbd5e2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.Byte.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ZeroExtendWideningLower_Vector64_Byte() + { + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Byte testClass) + { + var result = AdvSimd.ZeroExtendWideningLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Byte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ZeroExtendWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ZeroExtendWideningLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Byte*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ZeroExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Byte*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ZeroExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Byte(); + var result = AdvSimd.ZeroExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Byte(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ZeroExtendWideningLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Byte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Byte*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ZeroExtendWidening(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ZeroExtendWideningLower)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.Int16.cs new file mode 100644 index 00000000000000..3a58cbf2e89bae --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.Int16.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ZeroExtendWideningLower_Vector64_Int16() + { + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int16 testClass) + { + var result = AdvSimd.ZeroExtendWideningLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ZeroExtendWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ZeroExtendWideningLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Int16*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ZeroExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ZeroExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int16(); + var result = AdvSimd.ZeroExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int16(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ZeroExtendWideningLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Int16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Int16*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ZeroExtendWidening(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ZeroExtendWideningLower)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.Int32.cs new file mode 100644 index 00000000000000..05205c7fbb4497 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.Int32.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ZeroExtendWideningLower_Vector64_Int32() + { + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int32 testClass) + { + var result = AdvSimd.ZeroExtendWideningLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ZeroExtendWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ZeroExtendWideningLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Int32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ZeroExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ZeroExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int32(); + var result = AdvSimd.ZeroExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_Int32(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ZeroExtendWideningLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Int32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((Int32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ZeroExtendWidening(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ZeroExtendWideningLower)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.SByte.cs new file mode 100644 index 00000000000000..9701cdda6d48ca --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.SByte.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ZeroExtendWideningLower_Vector64_SByte() + { + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_SByte testClass) + { + var result = AdvSimd.ZeroExtendWideningLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_SByte testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ZeroExtendWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ZeroExtendWideningLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((SByte*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ZeroExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((SByte*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ZeroExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_SByte(); + var result = AdvSimd.ZeroExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_SByte(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ZeroExtendWideningLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((SByte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((SByte*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ZeroExtendWidening(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ZeroExtendWideningLower)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.UInt16.cs new file mode 100644 index 00000000000000..94696f369d89d1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.UInt16.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ZeroExtendWideningLower_Vector64_UInt16() + { + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt16 testClass) + { + var result = AdvSimd.ZeroExtendWideningLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt16 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ZeroExtendWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ZeroExtendWideningLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((UInt16*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ZeroExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ZeroExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt16(); + var result = AdvSimd.ZeroExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt16(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ZeroExtendWideningLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((UInt16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((UInt16*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ZeroExtendWidening(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ZeroExtendWideningLower)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.UInt32.cs new file mode 100644 index 00000000000000..d2a4a895d52655 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningLower.Vector64.UInt32.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ZeroExtendWideningLower_Vector64_UInt32() + { + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt32 testClass) + { + var result = AdvSimd.ZeroExtendWideningLower(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt32 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector64 _clsVar1; + + private Vector64 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ZeroExtendWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningLower), new Type[] { typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ZeroExtendWideningLower( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((UInt32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ZeroExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ZeroExtendWideningLower(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt32(); + var result = AdvSimd.ZeroExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningLower_Vector64_UInt32(); + + fixed (Vector64* pFld1 = &test._fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ZeroExtendWideningLower(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningLower(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningLower( + AdvSimd.LoadVector64((UInt32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ZeroExtendWidening(firstOp[i]) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ZeroExtendWideningLower)}(Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.Byte.cs new file mode 100644 index 00000000000000..07f995be11a611 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.Byte.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ZeroExtendWideningUpper_Vector128_Byte() + { + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Byte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Byte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Byte[] inArray1, UInt16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Byte testClass) + { + var result = AdvSimd.ZeroExtendWideningUpper(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Byte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Byte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Byte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new DataTable(_data1, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ZeroExtendWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ZeroExtendWideningUpper( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Byte*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ZeroExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ZeroExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Byte(); + var result = AdvSimd.ZeroExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Byte(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ZeroExtendWideningUpper(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Byte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Byte*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ZeroExtendWideningUpper(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ZeroExtendWideningUpper)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.Int16.cs new file mode 100644 index 00000000000000..1feb2f0e436085 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.Int16.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ZeroExtendWideningUpper_Vector128_Int16() + { + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int16[] inArray1, Int32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int16 testClass) + { + var result = AdvSimd.ZeroExtendWideningUpper(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new DataTable(_data1, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ZeroExtendWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ZeroExtendWideningUpper( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Int16*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ZeroExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ZeroExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int16(); + var result = AdvSimd.ZeroExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int16(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ZeroExtendWideningUpper(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Int16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Int16*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ZeroExtendWideningUpper(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ZeroExtendWideningUpper)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.Int32.cs new file mode 100644 index 00000000000000..b007617f701f5a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.Int32.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ZeroExtendWideningUpper_Vector128_Int32() + { + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int32[] inArray1, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int32 testClass) + { + var result = AdvSimd.ZeroExtendWideningUpper(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int32[] _data1 = new Int32[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); } + _dataTable = new DataTable(_data1, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ZeroExtendWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ZeroExtendWideningUpper( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Int32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ZeroExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ZeroExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int32(); + var result = AdvSimd.ZeroExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_Int32(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ZeroExtendWideningUpper(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Int32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((Int32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ZeroExtendWideningUpper(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ZeroExtendWideningUpper)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.SByte.cs new file mode 100644 index 00000000000000..dfa0e9e90e0cc0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.SByte.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ZeroExtendWideningUpper_Vector128_SByte() + { + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_SByte(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_SByte + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(SByte[] inArray1, Int16[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_SByte testClass) + { + var result = AdvSimd.ZeroExtendWideningUpper(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_SByte testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + private static SByte[] _data1 = new SByte[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_SByte() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_SByte() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSByte(); } + _dataTable = new DataTable(_data1, new Int16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ZeroExtendWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ZeroExtendWideningUpper( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((SByte*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ZeroExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((SByte*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ZeroExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_SByte(); + var result = AdvSimd.ZeroExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_SByte(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ZeroExtendWideningUpper(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((SByte*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((SByte*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ZeroExtendWideningUpper(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ZeroExtendWideningUpper)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.UInt16.cs new file mode 100644 index 00000000000000..0d471011a7b7b4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.UInt16.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ZeroExtendWideningUpper_Vector128_UInt16() + { + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt16 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt16[] inArray1, UInt32[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt16 testClass) + { + var result = AdvSimd.ZeroExtendWideningUpper(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt16 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + private static UInt16[] _data1 = new UInt16[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); } + _dataTable = new DataTable(_data1, new UInt32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ZeroExtendWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ZeroExtendWideningUpper( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ZeroExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ZeroExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt16(); + var result = AdvSimd.ZeroExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt16(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ZeroExtendWideningUpper(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((UInt16*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((UInt16*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ZeroExtendWideningUpper(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ZeroExtendWideningUpper)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.UInt32.cs new file mode 100644 index 00000000000000..c35161443743dc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd/ZeroExtendWideningUpper.Vector128.UInt32.cs @@ -0,0 +1,489 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void ZeroExtendWideningUpper_Vector128_UInt32() + { + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt32 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt32[] inArray1, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt32 testClass) + { + var result = AdvSimd.ZeroExtendWideningUpper(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt32 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt32[] _data1 = new UInt32[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); } + _dataTable = new DataTable(_data1, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => AdvSimd.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = AdvSimd.ZeroExtendWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(AdvSimd).GetMethod(nameof(AdvSimd.ZeroExtendWideningUpper), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = AdvSimd.ZeroExtendWideningUpper( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = AdvSimd.ZeroExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)); + var result = AdvSimd.ZeroExtendWideningUpper(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt32(); + var result = AdvSimd.ZeroExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__ZeroExtendWideningUpper_Vector128_UInt32(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = AdvSimd.ZeroExtendWideningUpper(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((UInt32*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningUpper(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = AdvSimd.ZeroExtendWideningUpper( + AdvSimd.LoadVector128((UInt32*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if (Helpers.ZeroExtendWideningUpper(firstOp, i) != result[i]) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd)}.{nameof(AdvSimd.ZeroExtendWideningUpper)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/Aes_r.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/Aes_r.csproj index 0742b17dadfe67..ee55253dbbb239 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/Aes_r.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/Aes_r.csproj @@ -12,6 +12,10 @@ + + + + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/Aes_ro.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/Aes_ro.csproj index e4b915cd4e3f79..509b345bdc5ca5 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/Aes_ro.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/Aes_ro.csproj @@ -12,6 +12,10 @@ + + + + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/PolynomialMultiplyWideningLower.Vector64.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/PolynomialMultiplyWideningLower.Vector64.Int64.cs new file mode 100644 index 00000000000000..3cba2406b3af3c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/PolynomialMultiplyWideningLower.Vector64.Int64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void PolynomialMultiplyWideningLower_Vector64_Int64() + { + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Int64 testClass) + { + var result = Aes.PolynomialMultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Int64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = Aes.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Aes.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = Aes.PolynomialMultiplyWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = Aes.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Aes).GetMethod(nameof(Aes.PolynomialMultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(Aes).GetMethod(nameof(Aes.PolynomialMultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Aes.PolynomialMultiplyWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = Aes.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((Int64*)(pClsVar1)), + AdvSimd.LoadVector64((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Aes.PolynomialMultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((Int64*)(_dataTable.inArray2Ptr)); + var result = Aes.PolynomialMultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Int64(); + var result = Aes.PolynomialMultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_Int64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = Aes.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Aes.PolynomialMultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = Aes.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((Int64*)(pFld1)), + AdvSimd.LoadVector64((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Aes.PolynomialMultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = Aes.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((Int64*)(&test._fld1)), + AdvSimd.LoadVector64((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.PolynomialMultiplyWideningLo64(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (Helpers.PolynomialMultiplyWideningHi64(left[0], right[0]) != result[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Aes)}.{nameof(Aes.PolynomialMultiplyWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/PolynomialMultiplyWideningLower.Vector64.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/PolynomialMultiplyWideningLower.Vector64.UInt64.cs new file mode 100644 index 00000000000000..9941f644a2dc23 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/PolynomialMultiplyWideningLower.Vector64.UInt64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void PolynomialMultiplyWideningLower_Vector64_UInt64() + { + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector64 _fld1; + public Vector64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_UInt64 testClass) + { + var result = Aes.PolynomialMultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_UInt64 testClass) + { + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = Aes.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector64 _clsVar1; + private static Vector64 _clsVar2; + + private Vector64 _fld1; + private Vector64 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Aes.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = Aes.PolynomialMultiplyWideningLower( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = Aes.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Aes).GetMethod(nameof(Aes.PolynomialMultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(Aes).GetMethod(nameof(Aes.PolynomialMultiplyWideningLower), new Type[] { typeof(Vector64), typeof(Vector64) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Aes.PolynomialMultiplyWideningLower( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector64* pClsVar1 = &_clsVar1) + fixed (Vector64* pClsVar2 = &_clsVar2) + { + var result = Aes.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((UInt64*)(pClsVar1)), + AdvSimd.LoadVector64((UInt64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Aes.PolynomialMultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector64((UInt64*)(_dataTable.inArray2Ptr)); + var result = Aes.PolynomialMultiplyWideningLower(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_UInt64(); + var result = Aes.PolynomialMultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningLower_Vector64_UInt64(); + + fixed (Vector64* pFld1 = &test._fld1) + fixed (Vector64* pFld2 = &test._fld2) + { + var result = Aes.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Aes.PolynomialMultiplyWideningLower(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector64* pFld1 = &_fld1) + fixed (Vector64* pFld2 = &_fld2) + { + var result = Aes.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((UInt64*)(pFld1)), + AdvSimd.LoadVector64((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Aes.PolynomialMultiplyWideningLower(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = Aes.PolynomialMultiplyWideningLower( + AdvSimd.LoadVector64((UInt64*)(&test._fld1)), + AdvSimd.LoadVector64((UInt64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector64 op1, Vector64 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.PolynomialMultiplyWideningLo64(left[0], right[0]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (Helpers.PolynomialMultiplyWideningHi64(left[0], right[0]) != result[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Aes)}.{nameof(Aes.PolynomialMultiplyWideningLower)}(Vector64, Vector64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/PolynomialMultiplyWideningUpper.Vector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/PolynomialMultiplyWideningUpper.Vector128.Int64.cs new file mode 100644 index 00000000000000..72791aa51283dc --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/PolynomialMultiplyWideningUpper.Vector128.Int64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void PolynomialMultiplyWideningUpper_Vector128_Int64() + { + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Int64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Int64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Int64[] inArray1, Int64[] inArray2, Int64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Int64 testClass) + { + var result = Aes.PolynomialMultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Int64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = Aes.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + private static Int64[] _data1 = new Int64[Op1ElementCount]; + private static Int64[] _data2 = new Int64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Int64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Int64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); } + _dataTable = new DataTable(_data1, _data2, new Int64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Aes.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = Aes.PolynomialMultiplyWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = Aes.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Aes).GetMethod(nameof(Aes.PolynomialMultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(Aes).GetMethod(nameof(Aes.PolynomialMultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Aes.PolynomialMultiplyWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = Aes.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((Int64*)(pClsVar1)), + AdvSimd.LoadVector128((Int64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Aes.PolynomialMultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((Int64*)(_dataTable.inArray2Ptr)); + var result = Aes.PolynomialMultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Int64(); + var result = Aes.PolynomialMultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_Int64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = Aes.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Aes.PolynomialMultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = Aes.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((Int64*)(pFld1)), + AdvSimd.LoadVector128((Int64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Aes.PolynomialMultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = Aes.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((Int64*)(&test._fld1)), + AdvSimd.LoadVector128((Int64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[Op1ElementCount]; + Int64[] inArray2 = new Int64[Op2ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.PolynomialMultiplyWideningLo64(left[1], right[1]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (Helpers.PolynomialMultiplyWideningHi64(left[1], right[1]) != result[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Aes)}.{nameof(Aes.PolynomialMultiplyWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/PolynomialMultiplyWideningUpper.Vector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/PolynomialMultiplyWideningUpper.Vector128.UInt64.cs new file mode 100644 index 00000000000000..bb4064cfa115e6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/PolynomialMultiplyWideningUpper.Vector128.UInt64.cs @@ -0,0 +1,537 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void PolynomialMultiplyWideningUpper_Vector128_UInt64() + { + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_UInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (AdvSimd.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (AdvSimd.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_UInt64 + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(UInt64[] inArray1, UInt64[] inArray2, UInt64[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_UInt64 testClass) + { + var result = Aes.PolynomialMultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_UInt64 testClass) + { + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = Aes.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[Op1ElementCount]; + private static UInt64[] _data2 = new UInt64[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private DataTable _dataTable; + + static SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_UInt64() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_UInt64() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); } + _dataTable = new DataTable(_data1, _data2, new UInt64[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Aes.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = Aes.PolynomialMultiplyWideningUpper( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = Aes.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Aes).GetMethod(nameof(Aes.PolynomialMultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(Aes).GetMethod(nameof(Aes.PolynomialMultiplyWideningUpper), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)), + AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Aes.PolynomialMultiplyWideningUpper( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + fixed (Vector128* pClsVar2 = &_clsVar2) + { + var result = Aes.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((UInt64*)(pClsVar1)), + AdvSimd.LoadVector128((UInt64*)(pClsVar2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Aes.PolynomialMultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)); + var op2 = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)); + var result = Aes.PolynomialMultiplyWideningUpper(op1, op2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_UInt64(); + var result = Aes.PolynomialMultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleBinaryOpTest__PolynomialMultiplyWideningUpper_Vector128_UInt64(); + + fixed (Vector128* pFld1 = &test._fld1) + fixed (Vector128* pFld2 = &test._fld2) + { + var result = Aes.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Aes.PolynomialMultiplyWideningUpper(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + fixed (Vector128* pFld2 = &_fld2) + { + var result = Aes.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((UInt64*)(pFld1)), + AdvSimd.LoadVector128((UInt64*)(pFld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Aes.PolynomialMultiplyWideningUpper(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = Aes.PolynomialMultiplyWideningUpper( + AdvSimd.LoadVector128((UInt64*)(&test._fld1)), + AdvSimd.LoadVector128((UInt64*)(&test._fld2)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, Vector128 op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[Op1ElementCount]; + UInt64[] inArray2 = new UInt64[Op2ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (Helpers.PolynomialMultiplyWideningLo64(left[1], right[1]) != result[0]) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (Helpers.PolynomialMultiplyWideningHi64(left[1], right[1]) != result[1]) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Aes)}.{nameof(Aes.PolynomialMultiplyWideningUpper)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/Program.Aes.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/Program.Aes.cs index fd0188702e40fa..96b49b50943e34 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/Program.Aes.cs +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Aes/Program.Aes.cs @@ -16,6 +16,10 @@ static Program() ["Encrypt.Vector128.Byte"] = Encrypt_Vector128_Byte, ["InverseMixColumns.Vector128.Byte"] = InverseMixColumns_Vector128_Byte, ["MixColumns.Vector128.Byte"] = MixColumns_Vector128_Byte, + ["PolynomialMultiplyWideningLower.Vector64.Int64"] = PolynomialMultiplyWideningLower_Vector64_Int64, + ["PolynomialMultiplyWideningLower.Vector64.UInt64"] = PolynomialMultiplyWideningLower_Vector64_UInt64, + ["PolynomialMultiplyWideningUpper.Vector128.Int64"] = PolynomialMultiplyWideningUpper_Vector128_Int64, + ["PolynomialMultiplyWideningUpper.Vector128.UInt64"] = PolynomialMultiplyWideningUpper_Vector128_UInt64, }; } } diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/ExtractTest.template b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/ExtractTest.template new file mode 100644 index 00000000000000..f366fa1368ac85 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/ExtractTest.template @@ -0,0 +1,452 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void {TestName}() + { + var test = new ExtractTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractTest__{TestName} + { + private struct DataTable + { + private byte[] inArray1; + + private GCHandle inHandle1; + + private ulong alignment; + + public DataTable({Op1BaseType}[] inArray1, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public {Op1VectorType}<{Op1BaseType}> _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractTest__{TestName} testClass) + { + var result = {Isa}.{Method}(_fld1, ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + + public void RunStructFldScenario_Load(ExtractTest__{TestName} testClass) + { + fixed ({Op1VectorType}<{Op1BaseType}>* pFld1 = &_fld1) + { + var result = {Isa}.{Method}({LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)pFld1), ElementIndex); + + testClass.ValidateResult(_fld1, result); + } + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); + + private static readonly byte ElementIndex = {ElementIndex}; + + private static {Op1BaseType}[] _data1 = new {Op1BaseType}[Op1ElementCount]; + + private static {Op1VectorType}<{Op1BaseType}> _clsVar1; + + private {Op1VectorType}<{Op1BaseType}> _fld1; + + private DataTable _dataTable; + + static ExtractTest__{TestName}() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _clsVar1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + } + + public ExtractTest__{TestName}() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + _dataTable = new DataTable(_data1, LargestVectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = {Isa}.{Method}( + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)), + ElementIndex + ); + + ValidateResult(_dataTable.inArray1Ptr, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, ({Op1BaseType})result); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof(byte) }) + .Invoke(null, new object[] { + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)), + ElementIndex + }); + + ValidateResult(_dataTable.inArray1Ptr, ({Op1BaseType})result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = {Isa}.{Method}(_clsVar1, ElementIndex); + + ValidateResult(_clsVar1, result); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed ({Op1VectorType}<{Op1BaseType}>* pClsVar1 = &_clsVar1) + { + var result = {Isa}.{Method}({LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)pClsVar1), ElementIndex); + + ValidateResult(_clsVar1, result); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr); + var result = {Isa}.{Method}(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)); + var result = {Isa}.{Method}(op1, ElementIndex); + + ValidateResult(op1, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractTest__{TestName}(); + var result = {Isa}.{Method}(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractTest__{TestName}(); + + fixed ({Op1VectorType}<{Op1BaseType}>* pFld1 = &test._fld1) + { + var result = {Isa}.{Method}({LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(pFld1)), ElementIndex); + + ValidateResult(test._fld1, result); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = {Isa}.{Method}(_fld1, ElementIndex); + + ValidateResult(_fld1, result); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed ({Op1VectorType}<{Op1BaseType}>* pFld1 = &_fld1) + { + var result = {Isa}.{Method}({LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(pFld1)), ElementIndex); + + ValidateResult(_fld1, result); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}(test._fld1, ElementIndex); + + ValidateResult(test._fld1, result); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)&test._fld1), + ElementIndex + ); + + ValidateResult(test._fld1, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult({Op1VectorType}<{Op1BaseType}> op1, {Op1BaseType} result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), op1); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult(void* op1, {Op1BaseType} result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + + ValidateResult(inArray1, result, method); + } + + private void ValidateResult({Op1BaseType}[] firstOp, {Op1BaseType} result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if ({ValidateResult}) + { + succeeded = false; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}({Op1VectorType}<{Op1BaseType}>, {ElementIndex}): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/ExtractVectorTest.template b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/ExtractVectorTest.template new file mode 100644 index 00000000000000..2042f1e7fb7d61 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/ExtractVectorTest.template @@ -0,0 +1,541 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void {TestName}() + { + var test = new ExtractVectorTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ExtractVectorTest__{TestName} + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable({Op1BaseType}[] inArray1, {Op2BaseType}[] inArray2, {RetBaseType}[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf<{Op2BaseType}>(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public {Op1VectorType}<{Op1BaseType}> _fld1; + public {Op2VectorType}<{Op2BaseType}> _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref testStruct._fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + + return testStruct; + } + + public void RunStructFldScenario(ExtractVectorTest__{TestName} testClass) + { + var result = {Isa}.{Method}(_fld1, _fld2, ElementIndex); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(ExtractVectorTest__{TestName} testClass) + { + fixed ({Op1VectorType}<{Op1BaseType}>* pFld1 = &_fld1) + fixed ({Op2VectorType}<{Op2BaseType}>* pFld2 = &_fld2) + { + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)pFld1), + {LoadIsa}.Load{Op2VectorType}(({Op2BaseType}*)pFld2), + ElementIndex + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); + private static readonly int Op2ElementCount = Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>() / sizeof({Op2BaseType}); + private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + private static readonly byte ElementIndex = {ElementIndex}; + + private static {Op1BaseType}[] _data1 = new {Op1BaseType}[Op1ElementCount]; + private static {Op2BaseType}[] _data2 = new {Op2BaseType}[Op2ElementCount]; + + private static {Op1VectorType}<{Op1BaseType}> _clsVar1; + private static {Op2VectorType}<{Op2BaseType}> _clsVar2; + + private {Op1VectorType}<{Op1BaseType}> _fld1; + private {Op2VectorType}<{Op2BaseType}> _fld2; + + private DataTable _dataTable; + + static ExtractVectorTest__{TestName}() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _clsVar1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref _clsVar2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + } + + public ExtractVectorTest__{TestName}() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref _fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + _dataTable = new DataTable(_data1, _data2, new {RetBaseType}[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = {Isa}.{Method}( + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)), + {LoadIsa}.Load{Op2VectorType}(({Op2BaseType}*)(_dataTable.inArray2Ptr)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof({Op2VectorType}<{Op2BaseType}>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof({Op2VectorType}<{Op2BaseType}>), typeof(byte) }) + .Invoke(null, new object[] { + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)), + {LoadIsa}.Load{Op2VectorType}(({Op2BaseType}*)(_dataTable.inArray2Ptr)), + ElementIndex + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = {Isa}.{Method}( + _clsVar1, + _clsVar2, + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed ({Op1VectorType}<{Op1BaseType}>* pClsVar1 = &_clsVar1) + fixed ({Op2VectorType}<{Op2BaseType}>* pClsVar2 = &_clsVar2) + { + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(pClsVar1)), + {LoadIsa}.Load{Op2VectorType}(({Op2BaseType}*)(pClsVar2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr); + var op2 = Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr); + var result = {Isa}.{Method}(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)); + var op2 = {LoadIsa}.Load{Op2VectorType}(({Op2BaseType}*)(_dataTable.inArray2Ptr)); + var result = {Isa}.{Method}(op1, op2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ExtractVectorTest__{TestName}(); + var result = {Isa}.{Method}(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new ExtractVectorTest__{TestName}(); + + fixed ({Op1VectorType}<{Op1BaseType}>* pFld1 = &test._fld1) + fixed ({Op2VectorType}<{Op2BaseType}>* pFld2 = &test._fld2) + { + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)pFld1), + {LoadIsa}.Load{Op2VectorType}(({Op2BaseType}*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = {Isa}.{Method}(_fld1, _fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed ({Op1VectorType}<{Op1BaseType}>* pFld1 = &_fld1) + fixed ({Op2VectorType}<{Op2BaseType}>* pFld2 = &_fld2) + { + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)pFld1), + {LoadIsa}.Load{Op2VectorType}(({Op2BaseType}*)pFld2), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}(test._fld1, test._fld2, ElementIndex); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(&test._fld1)), + {LoadIsa}.Load{Op2VectorType}(({Op2BaseType}*)(&test._fld2)), + ElementIndex + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult({Op1VectorType}<{Op1BaseType}> op1, {Op2VectorType}<{Op2BaseType}> op2, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), op1); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), op2); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* op1, void* op2, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), ref Unsafe.AsRef(op2), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult({Op1BaseType}[] firstOp, {Op2BaseType}[] secondOp, {RetBaseType}[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if ({ValidateIterResult}) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>, {Op2VectorType}<{Op2BaseType}>, {ElementIndex}): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($"secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx index 99570944cd3041..50bc84cdbb5225 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/GenerateTests.csx @@ -86,6 +86,12 @@ private const string SecureHashOpTest_ValidationLogic = @"{RetBaseType}[] expect private static readonly (string templateFileName, string outputTemplateName, Dictionary templateData)[] Templates = new[] { + ("_UnaryOpScalarTestTemplate.template", "DuplicateTest.template", new Dictionary { ["TemplateName"] = "Duplicate", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }), + ("_ImmUnaryOpTestTemplate.template", "ImmUnOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }), + ("_ImmUnaryOpTestTemplate.template", "VecImmUnOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }), + ("_ImmOpTestTemplate.template", "ImmOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }), + ("_ImmBinaryOpTestTemplate.template", "ImmBinOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }), + ("_ImmBinaryOpTestTemplate.template", "VecImmBinOpTest.template", new Dictionary { ["TemplateName"] = "Imm", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }), ("_BinaryOpTestTemplate.template", "SimpleBinOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }), ("_TernaryOpTestTemplate.template", "VecTernOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleVecOpTest_ValidationLogic }), ("_UnaryOpTestTemplate.template", "SimpleUnOpTest.template", new Dictionary { ["TemplateName"] = "Simple", ["TemplateValidationLogic"] = SimpleOpTest_ValidationLogic }), @@ -97,880 +103,1655 @@ private static readonly (string templateFileName, string outputTemplateName, Dic ("_UnaryOpTestTemplate.template", "SecureHashUnOpTest.template", new Dictionary { ["TemplateName"] = "SecureHash", ["TemplateValidationLogic"] = SecureHashOpTest_ValidationLogic }), ("_BinaryOpTestTemplate.template", "SecureHashBinOpTest.template", new Dictionary { ["TemplateName"] = "SecureHash", ["TemplateValidationLogic"] = SecureHashOpTest_ValidationLogic }), ("_TernaryOpTestTemplate.template", "SecureHashTernOpTest.template", new Dictionary { ["TemplateName"] = "SecureHash", ["TemplateValidationLogic"] = SecureHashOpTest_ValidationLogic }) - }; private static readonly (string templateFileName, Dictionary templateData)[] AdvSimdInputs = new [] { - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "(short)-TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "(sbyte)-TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "-TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Abs(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "(short)-TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "(sbyte)-TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "-TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Abs(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AbsScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "-TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Abs(firstOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AbsScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Abs(firstOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThan_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareGreaterThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThan_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareGreaterThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThanOrEqual_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareGreaterThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThanOrEqual_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareGreaterThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThan_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareLessThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThan_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareLessThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThanOrEqual_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareLessThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThanOrEqual_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareLessThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteDifference(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteDifference(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Add(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Add(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AddPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Add(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddScalar_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.Add(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Add(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddScalar_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.Add(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.And(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.And(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.And(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.And(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.BitwiseClear(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.BitwiseClear(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.BitwiseClear(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.BitwiseClear(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareGreaterThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareGreaterThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareGreaterThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareGreaterThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareLessThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareLessThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareLessThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareLessThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareTest(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareTest(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "DivideScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DivideScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Divide(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "DivideScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DivideScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Divide(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ExtractAndNarrowLow_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractAndNarrowLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "((SByte)firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ExtractAndNarrowLow_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractAndNarrowLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "((Int16)firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ExtractAndNarrowLow_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractAndNarrowLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "((Int32)firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ExtractAndNarrowLow_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractAndNarrowLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "((Byte)firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ExtractAndNarrowLow_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractAndNarrowLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "((UInt16)firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ExtractAndNarrowLow_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractAndNarrowLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "((UInt32)firstOp[i]) != result[i]"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ExtractAndNarrowHigh_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractAndNarrowHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "Helpers.ExtractAndNarrowHigh(0, left, right, result)", ["ValidateRemainingResults"] = "Helpers.ExtractAndNarrowHigh(i, left, right, result)"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ExtractAndNarrowHigh_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractAndNarrowHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateFirstResult"] = "Helpers.ExtractAndNarrowHigh(0, left, right, result)", ["ValidateRemainingResults"] = "Helpers.ExtractAndNarrowHigh(i, left, right, result)"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ExtractAndNarrowHigh_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractAndNarrowHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.ExtractAndNarrowHigh(0, left, right, result)", ["ValidateRemainingResults"] = "Helpers.ExtractAndNarrowHigh(i, left, right, result)"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ExtractAndNarrowHigh_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractAndNarrowHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateFirstResult"] = "Helpers.ExtractAndNarrowHigh(0, left, right, result)", ["ValidateRemainingResults"] = "Helpers.ExtractAndNarrowHigh(i, left, right, result)"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ExtractAndNarrowHigh_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractAndNarrowHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateFirstResult"] = "Helpers.ExtractAndNarrowHigh(0, left, right, result)", ["ValidateRemainingResults"] = "Helpers.ExtractAndNarrowHigh(i, left, right, result)"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ExtractAndNarrowHigh_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractAndNarrowHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.ExtractAndNarrowHigh(0, left, right, result)", ["ValidateRemainingResults"] = "Helpers.ExtractAndNarrowHigh(i, left, right, result)"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplyAdd_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplyAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplyAdd(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplyAdd_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplyAdd(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplyAddScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplyAddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FusedMultiplyAdd(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplyAddScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplyAddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplyAdd(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplyAddNegatedScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplyAddNegatedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FusedMultiplyAddNegated(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplyAddNegatedScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplyAddNegatedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplyAddNegated(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplySubtract_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplySubtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplySubtract(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplySubtract_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplySubtract(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplySubtractScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplySubtractScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FusedMultiplySubtract(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplySubtractScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplySubtractScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplySubtract(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplySubtractNegatedScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplySubtractNegatedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FusedMultiplySubtractNegated(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplySubtractNegatedScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplySubtractNegatedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplySubtractNegated(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingSignCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CountLeadingSignBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingSignCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CountLeadingSignBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingSignCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CountLeadingSignBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingSignCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CountLeadingSignBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingSignCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CountLeadingSignBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingSignCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CountLeadingSignBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_Byte", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_Double", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_Int16", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_Int32", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_Int64", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_SByte", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_Single", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_UInt16", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_UInt32", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_UInt64", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_Byte", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_Double", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_Int16", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_Int32", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_Int64", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_SByte", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_Single", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_UInt16", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_UInt32", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_UInt64", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Max(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Max(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumber_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumber", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxNumber(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumber_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumber", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxNumber(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumberScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MaxNumber(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumberScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxNumber(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Min(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Min(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinNumber_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumber", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinNumber(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinNumber_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumber", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinNumber(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MinNumberScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MinNumber(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MinNumberScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinNumber(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Multiply(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Multiply(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Multiply(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Multiply(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Negate(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Negate(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "NegateScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "NegateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Negate(firstOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "NegateScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "NegateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Negate(firstOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Not(firstOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Not(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Not(firstOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Not(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Or(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Or(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Or(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Or(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.OrNot(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.OrNot(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.OrNot(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.OrNot(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiply_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiply(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiply_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiply(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiply_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiply(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiply_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiply(left[i], right[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "PopCount_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PopCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.BitCount(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "PopCount_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PopCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitCount(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "PopCount_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PopCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.BitCount(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "PopCount_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PopCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitCount(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(result[i]) != 0x409e8000"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.UnsignedRecipEstimate(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(result[i]) != 0x409e8000"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.UnsignedRecipEstimate(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(result[i]) != 0x400e8000"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.UnsignedRSqrtEstimate(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(result[i]) != 0x400e8000"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.UnsignedRSqrtEstimate(firstOp[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStep_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStep", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRSqrtStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStep_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStep", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRSqrtStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStep_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStep", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRecipStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStep_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStep", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRecipStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "SqrtScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SqrtScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Sqrt(firstOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "SqrtScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SqrtScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Sqrt(firstOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Subtract(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Subtract(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Subtract(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractScalar_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.Subtract(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Subtract(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractScalar_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.Subtract(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Xor(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Xor(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Xor(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Xor(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "(short)-TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "(sbyte)-TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "-TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Abs(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "(short)-TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "(sbyte)-TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "-TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Abs(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AbsScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "-TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Abs(firstOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AbsScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Abs(firstOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThan_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareGreaterThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThan_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareGreaterThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThanOrEqual_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareGreaterThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThanOrEqual_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareGreaterThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThan_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareLessThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThan_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareLessThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThanOrEqual_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareLessThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThanOrEqual_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareLessThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteDifference(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteDifference(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifference(left[i], right[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceAdd_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningLower_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningLower_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningLower_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningLower_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningLower_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningLower_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWidening(left[i], right[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningLowerAndAdd_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningLowerAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningLowerAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningLowerAndAdd_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningLowerAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningLowerAndAdd_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningLowerAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningLowerAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningLowerAndAdd_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningLowerAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningUpper_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningUpper_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningUpper_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningUpper_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningUpper_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningUpper_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningUpper(left, right, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningUpperAndAdd_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningUpperAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningUpperAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningUpperAndAdd_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningUpperAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningUpperAndAdd_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningUpperAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningUpperAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceWideningUpperAndAdd_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceWideningUpperAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AbsoluteDifferenceWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Add(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Add(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Add(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddHighNarrowingLower_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddHighNarrowingLower_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddHighNarrowingLower_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.AddHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddHighNarrowingLower_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddHighNarrowingLower_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddHighNarrowingLower_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.AddHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AddHighNarrowingUpper_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AddHighNarrowingUpper_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AddHighNarrowingUpper_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.AddHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AddHighNarrowingUpper_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AddHighNarrowingUpper_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AddHighNarrowingUpper_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.AddHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AddPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWidening_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWidening", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AddPairwiseWidening(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWidening_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWidening", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddPairwiseWidening(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWidening_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWidening", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AddPairwiseWidening(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWidening_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWidening", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddPairwiseWidening(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWidening_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWidening", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AddPairwiseWidening(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWidening_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWidening", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddPairwiseWidening(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWidening_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWidening", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddPairwiseWidening(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWidening_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWidening", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AddPairwiseWidening(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWidening_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWidening", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddPairwiseWidening(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWidening_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWidening", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddPairwiseWidening(firstOp, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWideningAndAdd_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWideningAndAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWideningAndAdd_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWideningAndAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWideningAndAdd_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWideningAndAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWideningAndAdd_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWideningAndAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWideningAndAdd_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWideningAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWideningAndAdd_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWideningAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWideningAndAdd_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWideningAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWideningAndAdd_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWideningAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWideningAndAdd_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWideningAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWideningAndAdd_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWideningAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddPairwiseWideningAndAdd(left, right, i) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWideningAndAddScalar_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWideningAndAddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateFirstResult"] = "Helpers.AddPairwiseWideningAndAdd(left, right, 0) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWideningAndAddScalar_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWideningAndAddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateFirstResult"] = "Helpers.AddPairwiseWideningAndAdd(left, right, 0) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWideningScalar_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWideningScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateFirstResult"] = "Helpers.AddPairwiseWidening(firstOp, 0) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseWideningScalar_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseWideningScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateFirstResult"] = "Helpers.AddPairwiseWidening(firstOp, 0) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddRoundedHighNarrowingLower_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddRoundedHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddRoundedHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddRoundedHighNarrowingLower_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddRoundedHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddRoundedHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddRoundedHighNarrowingLower_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddRoundedHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.AddRoundedHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddRoundedHighNarrowingLower_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddRoundedHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddRoundedHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddRoundedHighNarrowingLower_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddRoundedHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddRoundedHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddRoundedHighNarrowingLower_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddRoundedHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.AddRoundedHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AddRoundedHighNarrowingUpper_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddRoundedHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AddRoundedHighNarrowingUpper_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddRoundedHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AddRoundedHighNarrowingUpper_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddRoundedHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.AddRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AddRoundedHighNarrowingUpper_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddRoundedHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AddRoundedHighNarrowingUpper_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddRoundedHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "AddRoundedHighNarrowingUpper_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddRoundedHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.AddRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturate_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AddSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturate_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturate_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturate_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AddSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturate_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturate_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturate_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AddSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturate_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturate_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturate_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.AddSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturate_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AddSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturate_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturate_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturate_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.AddSaturate(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturateScalar_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.AddSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturateScalar_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.AddSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Add(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddScalar_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.Add(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Add(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddScalar_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.Add(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningLower_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AddWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningLower_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningLower_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningLower_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AddWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningLower_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningLower_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningLower_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AddWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningLower_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningLower_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningLower_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AddWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningLower_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningLower_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningUpper_Vector128_Byte_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AddWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningUpper_Vector128_Int16_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningUpper_Vector128_Int16_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AddWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningUpper_Vector128_Int32_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningUpper_Vector128_Int32_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningUpper_Vector128_Int64_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningUpper_Vector128_SByte_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AddWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningUpper_Vector128_UInt16_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AddWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningUpper_Vector128_UInt16_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningUpper_Vector128_UInt32_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningUpper_Vector128_UInt32_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddWideningUpper_Vector128_UInt64_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.And(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.And(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.And(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.And(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "And_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "And", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.And(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.BitwiseClear(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.BitwiseClear(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.BitwiseClear(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.BitwiseClear(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "BitwiseClear_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseClear", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.BitwiseClear(left[i], right[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "BitwiseSelect_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "BitwiseSelect", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.BitwiseSelect(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareGreaterThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareGreaterThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareGreaterThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareGreaterThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareLessThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareLessThan(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareLessThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareLessThanOrEqual(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareTest(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareTest(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "DivideScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DivideScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Divide(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "DivideScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DivideScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Divide(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector64_V64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector64_V64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector64_V64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector64_V64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector64_V64_Single_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector64_V64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector64_V64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector64_V128_Byte_8", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "8", ["ValidateFirstResult"] = "result[0] != firstOp[8]", ["ValidateRemainingResults"] = "result[i] != firstOp[8]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector64_V128_Int16_4", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "4", ["ValidateFirstResult"] = "result[0] != firstOp[4]", ["ValidateRemainingResults"] = "result[i] != firstOp[4]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector64_V128_Int32_2", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "2", ["ValidateFirstResult"] = "result[0] != firstOp[2]", ["ValidateRemainingResults"] = "result[i] != firstOp[2]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector64_V128_SByte_8", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "8", ["ValidateFirstResult"] = "result[0] != firstOp[8]", ["ValidateRemainingResults"] = "result[i] != firstOp[8]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector64_V128_Single_2", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["Imm"] = "2", ["ValidateFirstResult"] = "result[0] != firstOp[2]", ["ValidateRemainingResults"] = "result[i] != firstOp[2]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector64_V128_UInt16_4", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "4", ["ValidateFirstResult"] = "result[0] != firstOp[4]", ["ValidateRemainingResults"] = "result[i] != firstOp[4]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector64_V128_UInt32_2", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "2", ["ValidateFirstResult"] = "result[0] != firstOp[2]", ["ValidateRemainingResults"] = "result[i] != firstOp[2]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V64_Single_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V128_Byte_8", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "8", ["ValidateFirstResult"] = "result[0] != firstOp[8]", ["ValidateRemainingResults"] = "result[i] != firstOp[8]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V128_Int16_4", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "4", ["ValidateFirstResult"] = "result[0] != firstOp[4]", ["ValidateRemainingResults"] = "result[i] != firstOp[4]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V128_Int32_2", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "2", ["ValidateFirstResult"] = "result[0] != firstOp[2]", ["ValidateRemainingResults"] = "result[i] != firstOp[2]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V128_SByte_8", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "8", ["ValidateFirstResult"] = "result[0] != firstOp[8]", ["ValidateRemainingResults"] = "result[i] != firstOp[8]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V128_Single_2", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["Imm"] = "2", ["ValidateFirstResult"] = "result[0] != firstOp[2]", ["ValidateRemainingResults"] = "result[i] != firstOp[2]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V128_UInt16_4", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "4", ["ValidateFirstResult"] = "result[0] != firstOp[4]", ["ValidateRemainingResults"] = "result[i] != firstOp[4]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V128_UInt32_2", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "2", ["ValidateFirstResult"] = "result[0] != firstOp[2]", ["ValidateRemainingResults"] = "result[i] != firstOp[2]" }), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector64_Byte_31", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector64_Int16_31", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector64_Int32_31", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector64_SByte_31", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector64_Single_31", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector64_UInt16_31", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector64_UInt32_31", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_Byte_31", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_Int16_31", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_Int32_31", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_SByte_31", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_Single_31", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_UInt16_31", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_UInt32_31", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ElementIndex"] = "1", ["ValidateResult"] = "firstOp[ElementIndex] != result"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ElementIndex"] = "1", ["ValidateResult"] = "firstOp[ElementIndex] != result"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ElementIndex"] = "1", ["ValidateResult"] = "firstOp[ElementIndex] != result"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ElementIndex"] = "1", ["ValidateResult"] = "firstOp[ElementIndex] != result"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector64_Single_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ElementIndex"] = "1", ["ValidateResult"] = "BitConverter.SingleToInt32Bits(firstOp[ElementIndex]) != BitConverter.SingleToInt32Bits(result)"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ElementIndex"] = "1", ["ValidateResult"] = "firstOp[ElementIndex] != result"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ElementIndex"] = "1", ["ValidateResult"] = "firstOp[ElementIndex] != result"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ElementIndex"] = "1", ["ValidateResult"] = "firstOp[ElementIndex] != result"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector128_Double_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ElementIndex"] = "1", ["ValidateResult"] = "BitConverter.DoubleToInt64Bits(firstOp[ElementIndex]) != BitConverter.DoubleToInt64Bits(result)"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ElementIndex"] = "1", ["ValidateResult"] = "firstOp[ElementIndex] != result"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ElementIndex"] = "1", ["ValidateResult"] = "firstOp[ElementIndex] != result"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector128_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ElementIndex"] = "1", ["ValidateResult"] = "firstOp[ElementIndex] != result"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ElementIndex"] = "1", ["ValidateResult"] = "firstOp[ElementIndex] != result"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector128_Single_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ElementIndex"] = "1", ["ValidateResult"] = "BitConverter.SingleToInt32Bits(firstOp[ElementIndex]) != BitConverter.SingleToInt32Bits(result)"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ElementIndex"] = "1", ["ValidateResult"] = "firstOp[ElementIndex] != result"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ElementIndex"] = "1", ["ValidateResult"] = "firstOp[ElementIndex] != result"}), + ("ExtractTest.template", new Dictionary { ["TestName"] = "Extract_Vector128_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Extract", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ElementIndex"] = "1", ["ValidateResult"] = "firstOp[ElementIndex] != result"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ExtractNarrowingUpper_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ExtractNarrowingUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ExtractNarrowingUpper_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ExtractNarrowingUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ExtractNarrowingUpper_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.ExtractNarrowingUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ExtractNarrowingUpper_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.ExtractNarrowingUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ExtractNarrowingUpper_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.ExtractNarrowingUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ExtractNarrowingUpper_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.ExtractNarrowingUpper(left, right, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ExtractNarrowingLower_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ExtractNarrowing(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ExtractNarrowingLower_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ExtractNarrowing(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ExtractNarrowingLower_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.ExtractNarrowing(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ExtractNarrowingLower_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.ExtractNarrowing(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ExtractNarrowingLower_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.ExtractNarrowing(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ExtractNarrowingLower_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.ExtractNarrowing(firstOp[i]) != result[i]"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector64_Single_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i)) != BitConverter.SingleToInt32Bits(result[i])"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector128_Double_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i)) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector128_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector128_Single_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i)) != BitConverter.SingleToInt32Bits(result[i])"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]"}), + ("ExtractVectorTest.template", new Dictionary { ["TestName"] = "ExtractVector128_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ExtractVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ElementIndex"] = "1", ["ValidateIterResult"] = "Helpers.ExtractVector(firstOp, secondOp, ElementIndex, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddHalving_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.FusedAddHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddHalving_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.FusedAddHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddHalving_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.FusedAddHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddHalving_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.FusedAddHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddHalving_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.FusedAddHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddHalving_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.FusedAddHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddHalving_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.FusedAddHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddHalving_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.FusedAddHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddHalving_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.FusedAddHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddHalving_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.FusedAddHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddHalving_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.FusedAddHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddHalving_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.FusedAddHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddRoundedHalving_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddRoundedHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddRoundedHalving_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddRoundedHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddRoundedHalving_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddRoundedHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddRoundedHalving_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddRoundedHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddRoundedHalving_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddRoundedHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddRoundedHalving_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddRoundedHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddRoundedHalving_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddRoundedHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddRoundedHalving_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddRoundedHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddRoundedHalving_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddRoundedHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddRoundedHalving_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddRoundedHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddRoundedHalving_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddRoundedHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedAddRoundedHalving_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedAddRoundedHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.FusedAddRoundedHalving(left[i], right[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplyAdd_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplyAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplyAdd(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplyAdd_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplyAdd(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplyAddScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplyAddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FusedMultiplyAdd(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplyAddScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplyAddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplyAdd(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplyAddNegatedScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplyAddNegatedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FusedMultiplyAddNegated(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplyAddNegatedScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplyAddNegatedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplyAddNegated(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplySubtract_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplySubtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplySubtract(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplySubtract_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplySubtract(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplySubtractScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplySubtractScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FusedMultiplySubtract(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplySubtractScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplySubtractScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplySubtract(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplySubtractNegatedScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplySubtractNegatedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FusedMultiplySubtractNegated(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplySubtractNegatedScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplySubtractNegatedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.FusedMultiplySubtractNegated(firstOp[0], secondOp[0], thirdOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedSubtractHalving_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedSubtractHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedSubtractHalving_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedSubtractHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedSubtractHalving_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedSubtractHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedSubtractHalving_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedSubtractHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedSubtractHalving_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedSubtractHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedSubtractHalving_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedSubtractHalving", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedSubtractHalving_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedSubtractHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedSubtractHalving_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedSubtractHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedSubtractHalving_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedSubtractHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedSubtractHalving_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedSubtractHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedSubtractHalving_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedSubtractHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "FusedSubtractHalving_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedSubtractHalving", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.FusedSubtractHalving(left[i], right[i]) != result[i]"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector64_Single_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Insert(firstOp, ElementIndex, thirdOp, i)) != BitConverter.SingleToInt32Bits(result[i])"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector128_Double_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Insert(firstOp, ElementIndex, thirdOp, i)) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector128_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector128_Single_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Insert(firstOp, ElementIndex, thirdOp, i)) != BitConverter.SingleToInt32Bits(result[i])"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]"}), + ("InsertTest.template", new Dictionary { ["TestName"] = "Insert_Vector128_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Insert", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ElementIndex"] = "1", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Insert(firstOp, ElementIndex, thirdOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingSignCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CountLeadingSignBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingSignCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CountLeadingSignBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingSignCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CountLeadingSignBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingSignCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CountLeadingSignBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingSignCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CountLeadingSignBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingSignCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CountLeadingSignBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "LeadingZeroCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.CountLeadingZeroBits(firstOp[i]) != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_Byte", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_Double", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_Int16", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_Int32", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_Int64", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_SByte", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_Single", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_UInt16", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_UInt32", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector64_UInt64", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector64", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_Byte", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_Double", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_Int16", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_Int32", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_Int64", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_SByte", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_Single", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_UInt16", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_UInt32", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("LoadUnOpTest.template", new Dictionary { ["TestName"] = "LoadVector128_UInt64", ["Isa"] = "AdvSimd", ["Method"] = "LoadVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Max(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Max(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Max(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumber_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumber", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxNumber(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumber_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumber", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxNumber(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumberScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MaxNumber(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumberScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxNumber(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Min(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Min(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Min(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinNumber_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumber", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinNumber(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinNumber_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumber", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinNumber(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MinNumberScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MinNumber(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MinNumberScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinNumber(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Multiply(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Multiply(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Multiply(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Multiply(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Multiply(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyAdd_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MultiplyAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplySubtract_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MultiplySubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLower_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MultiplyWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLower_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MultiplyWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLower_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MultiplyWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLower_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MultiplyWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLower_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MultiplyWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLower_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MultiplyWidening(left[i], right[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLowerAndAdd_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLowerAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MultiplyWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLowerAndAdd_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLowerAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MultiplyWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLowerAndAdd_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLowerAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MultiplyWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLowerAndAdd_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLowerAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MultiplyWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLowerAndAdd_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLowerAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MultiplyWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLowerAndAdd_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLowerAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MultiplyWideningAndAdd(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLowerAndSubtract_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLowerAndSubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MultiplyWideningAndSubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLowerAndSubtract_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLowerAndSubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MultiplyWideningAndSubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLowerAndSubtract_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLowerAndSubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MultiplyWideningAndSubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLowerAndSubtract_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLowerAndSubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MultiplyWideningAndSubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLowerAndSubtract_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLowerAndSubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MultiplyWideningAndSubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningLowerAndSubtract_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningLowerAndSubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MultiplyWideningAndSubtract(firstOp[i], secondOp[i], thirdOp[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpper_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpper_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpper_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpper_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpper_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpper_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpper(left, right, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpperAndAdd_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpperAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpperAndAdd_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpperAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpperAndAdd_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpperAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpperAndAdd_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpperAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpperAndAdd_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpperAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpperAndAdd_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpperAndAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpperAndAdd(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpperAndSubtract_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpperAndSubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpperAndSubtract(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpperAndSubtract_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpperAndSubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpperAndSubtract(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpperAndSubtract_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpperAndSubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpperAndSubtract(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpperAndSubtract_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpperAndSubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpperAndSubtract(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpperAndSubtract_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpperAndSubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpperAndSubtract(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "MultiplyWideningUpperAndSubtract_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyWideningUpperAndSubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MultiplyWideningUpperAndSubtract(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Negate(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Negate(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "NegateScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "NegateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Negate(firstOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "NegateScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "NegateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Negate(firstOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Not(firstOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Not(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Not(firstOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Not(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Not_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Not", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Not(firstOp[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Or(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Or(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Or(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Or(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Or_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Or(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.OrNot(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.OrNot(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.OrNot(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.OrNot(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "OrNot_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "OrNot", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.OrNot(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiply_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiply_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiply", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiply_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiply_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiply(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiplyWideningLower_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiplyWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiplyWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiplyWideningLower_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiplyWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiplyWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiplyWideningUpper_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiplyWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiplyWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiplyWideningUpper_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiplyWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.PolynomialMultiplyWideningUpper(left, right, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "PopCount_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PopCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.BitCount(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "PopCount_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PopCount", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitCount(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "PopCount_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PopCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.BitCount(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "PopCount_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "PopCount", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.BitCount(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(result[i]) != 0x409e8000"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.UnsignedRecipEstimate(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(result[i]) != 0x409e8000"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.UnsignedRecipEstimate(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(result[i]) != 0x400e8000"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.UnsignedRSqrtEstimate(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(result[i]) != 0x400e8000"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.UnsignedRSqrtEstimate(firstOp[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStep_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStep", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRSqrtStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStep_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStep", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRSqrtStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStep_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStep", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRecipStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStep_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStep", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRecipStepFused(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmetic_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmetic", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftArithmetic(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmetic_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmetic", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftArithmetic(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmetic_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmetic", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftArithmetic(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmetic_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmetic", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftArithmetic(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmetic_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmetic", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftArithmetic(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmetic_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmetic", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.ShiftArithmetic(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmetic_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmetic", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftArithmetic(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRounded_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRounded_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRounded_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRounded_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRounded_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRounded_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRounded_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRoundedSaturate_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRoundedSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRoundedSaturate_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRoundedSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRoundedSaturate_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRoundedSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRoundedSaturate_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRoundedSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRoundedSaturate_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRoundedSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRoundedSaturate_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRoundedSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRoundedSaturate_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRoundedSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticRoundedSaturate(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRoundedSaturateScalar_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRoundedSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.ShiftArithmeticRoundedSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRoundedScalar_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRoundedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.ShiftArithmeticRounded(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticSaturate_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticSaturate_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticSaturate_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticSaturate_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticSaturate_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticSaturate_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticSaturate_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftArithmeticSaturate(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticSaturateScalar_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.ShiftArithmeticSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticScalar_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.ShiftArithmetic(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogical_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogical_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogical_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogical_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogical_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogical_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogical_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogical_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogical_Vector128_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogical_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogical_Vector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogical_Vector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogical_Vector128_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturate_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturate_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturate_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturate_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturate_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturate_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturate_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturate_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturate_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturate_Vector128_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturate_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturate_Vector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturate_Vector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturate_Vector128_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[i], Imm) != result[i]"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateScalar_Vector64_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateScalar_Vector64_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateUnsigned_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateUnsigned", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateUnsigned_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateUnsigned", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateUnsigned_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateUnsigned", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateUnsigned_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateUnsigned", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateUnsigned_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateUnsigned", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateUnsigned_Vector128_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateUnsigned", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateUnsigned_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateUnsigned", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[i], Imm) != result[i]"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateUnsignedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalScalar_Vector64_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftLeftLogical(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalScalar_Vector64_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftLeftLogical(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalWideningLower_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalWidening(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalWideningLower_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalWidening(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalWideningLower_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalWidening(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalWideningLower_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalWidening(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalWideningLower_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalWidening(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalWideningLower_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalWidening(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalWideningUpper_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalWideningUpper(firstOp, Imm, i) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalWideningUpper_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalWideningUpper(firstOp, Imm, i) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalWideningUpper_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalWideningUpper(firstOp, Imm, i) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalWideningUpper_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalWideningUpper(firstOp, Imm, i) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalWideningUpper_Vector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalWideningUpper(firstOp, Imm, i) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalWideningUpper_Vector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftLeftLogicalWideningUpper(firstOp, Imm, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogical_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogical(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogical_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogical(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogical_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogical(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogical_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogical(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogical_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogical(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogical_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogical(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogical_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogical(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogical_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogical(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogical_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogical(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogical_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.ShiftLogical(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogical_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogical(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogical_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogical(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogical_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogical(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogical_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.ShiftLogical(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRounded_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRounded_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRounded_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRounded_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRounded_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRounded_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRounded_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRounded_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRounded_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRounded_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRounded_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRounded_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRounded_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRounded_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRounded(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturate_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturate_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturate_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturate_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturate_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturate_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturate_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturate_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturate_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturate_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturate_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturate_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturate_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturate_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturateScalar_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturateScalar_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedScalar_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalRounded(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedScalar_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalRounded(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturate_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturate_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturate_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturate_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturate_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturate_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturate_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturate_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturate_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturate_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturate_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturate_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturate_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturate_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.ShiftLogicalSaturate(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturateScalar_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturateScalar_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalScalar_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.ShiftLogical(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalScalar_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.ShiftLogical(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmetic_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmetic", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmetic(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmetic_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmetic", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmetic(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmetic_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmetic", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmetic(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmetic_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmetic", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmetic(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmetic_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmetic", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmetic(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmetic_Vector128_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmetic", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmetic(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmetic_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmetic", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmetic(firstOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticAdd_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticAdd_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticAdd_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticAdd_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticAdd_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticAdd_Vector128_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticAdd_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("ImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticAddScalar_Vector64_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticAddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticAdd(firstOp[0], secondOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateLower_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateLower_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateUnsignedLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturateUnsigned(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateUnsignedLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturateUnsigned(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateUnsignedLower_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateUnsignedLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturateUnsigned(firstOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateUnsignedUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateUnsignedUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateUnsignedUpper_Vector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateUnsignedUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturateUnsignedUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateUpper_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateUpper_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRounded_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRounded_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRounded_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRounded_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRounded_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRounded_Vector128_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRounded_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedAdd_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedAdd_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedAdd_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedAdd_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedAdd_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedAdd_Vector128_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedAdd_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("ImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedAddScalar_Vector64_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedAddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticRoundedAdd(firstOp[0], secondOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateLower_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(firstOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt16_1",["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper_Vector128_UInt32_1",["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateUpper_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedScalar_Vector64_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticRounded(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticScalar_Vector64_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmetic(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogical_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogical_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogical_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogical_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogical_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogical_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogical", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogical_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogical_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogical_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogical_Vector128_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogical_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogical_Vector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogical_Vector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogical_Vector128_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogical", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogical(firstOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAdd_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAdd_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAdd_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAdd_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAdd_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAdd_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAdd_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAdd_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAdd_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAdd_Vector128_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAdd_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAdd_Vector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAdd_Vector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAdd_Vector128_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("ImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAddScalar_Vector64_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[0], secondOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalAddScalar_Vector64_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalAddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalAdd(firstOp[0], secondOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingLower_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowing(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingLower_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowing(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingLower_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowing(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingLower_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowing(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingLower_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowing(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingLower_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowing(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateLower_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateLower_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateLower_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateLower_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateLower_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateUpper_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateUpper_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateUpper_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateUpper_Vector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingUpper_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingUpper_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingUpper_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingUpper_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingUpper_Vector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingUpper_Vector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRounded_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRounded_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRounded_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRounded_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRounded_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRounded_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRounded", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRounded_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRounded_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRounded_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRounded_Vector128_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRounded_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRounded_Vector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRounded_Vector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRounded_Vector128_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRounded", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAdd_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAdd_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAdd_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAdd_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAdd_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAdd_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAdd_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAdd_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAdd_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAdd_Vector128_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAdd_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAdd_Vector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAdd_Vector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAdd_Vector128_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[i], secondOp[i], Imm) != result[i]"}), + ("ImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAddScalar_Vector64_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[0], secondOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedAddScalar_Vector64_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedAddScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalRoundedAdd(firstOp[0], secondOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingLower_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowing(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingLower_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowing(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingLower_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowing(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingLower_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowing(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowing(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingLower_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowing(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateLower_Vector64_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[i], Imm) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateUpper_Vector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturateUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingUpper_Vector128_Byte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingUpper_Vector128_Int32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingUpper_Vector128_SByte_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt16_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("VecImmBinOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingUpper_Vector128_UInt32_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateIterResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingUpper(firstOp, secondOp, Imm, i) != result[i]"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedScalar_Vector64_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedScalar_Vector64_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalRounded(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalScalar_Vector64_Int64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftRightLogical(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalScalar_Vector64_UInt64_1", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftRightLogical(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "SignExtendWideningLower_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SignExtendWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.SignExtendWidening(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "SignExtendWideningLower_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SignExtendWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.SignExtendWidening(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "SignExtendWideningLower_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SignExtendWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.SignExtendWidening(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "SignExtendWideningUpper_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SignExtendWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.SignExtendWideningUpper(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "SignExtendWideningUpper_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SignExtendWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.SignExtendWideningUpper(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "SignExtendWideningUpper_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SignExtendWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.SignExtendWideningUpper(firstOp, i) != result[i]"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "SqrtScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SqrtScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Sqrt(firstOp[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "SqrtScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SqrtScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Sqrt(firstOp[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(firstOp[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(firstOp[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("StoreUnOpTest.template", new Dictionary { ["TestName"] = "Store_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Store", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "firstOp[i] != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Subtract(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Subtract(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Subtract(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractHighNarrowingLower_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.SubtractHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractHighNarrowingLower_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.SubtractHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractHighNarrowingLower_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.SubtractHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractHighNarrowingLower_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.SubtractHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractHighNarrowingLower_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.SubtractHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractHighNarrowingLower_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.SubtractHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "SubtractHighNarrowingUpper_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.SubtractHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "SubtractHighNarrowingUpper_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.SubtractHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "SubtractHighNarrowingUpper_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.SubtractHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "SubtractHighNarrowingUpper_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.SubtractHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "SubtractHighNarrowingUpper_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.SubtractHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "SubtractHighNarrowingUpper_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.SubtractHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractRoundedHighNarrowingLower_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractRoundedHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.SubtractRoundedHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractRoundedHighNarrowingLower_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractRoundedHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.SubtractRoundedHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractRoundedHighNarrowingLower_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractRoundedHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.SubtractRoundedHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractRoundedHighNarrowingLower_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractRoundedHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.SubtractRoundedHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractRoundedHighNarrowingLower_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractRoundedHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.SubtractRoundedHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractRoundedHighNarrowingLower_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractRoundedHighNarrowingLower", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.SubtractRoundedHighNarrowing(left[i], right[i]) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "SubtractRoundedHighNarrowingUpper_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractRoundedHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.SubtractRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "SubtractRoundedHighNarrowingUpper_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractRoundedHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.SubtractRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "SubtractRoundedHighNarrowingUpper_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractRoundedHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.SubtractRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "SubtractRoundedHighNarrowingUpper_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractRoundedHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp3"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.SubtractRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "SubtractRoundedHighNarrowingUpper_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractRoundedHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.SubtractRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "SubtractRoundedHighNarrowingUpper_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractRoundedHighNarrowingUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp3"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.SubtractRoundedHighNarrowingUpper(firstOp, secondOp, thirdOp, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturate_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.SubtractSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturate_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.SubtractSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturate_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.SubtractSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturate_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.SubtractSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturate_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.SubtractSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturate_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.SubtractSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturate_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.SubtractSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturate_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.SubtractSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturate_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.SubtractSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturate_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.SubtractSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturate_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.SubtractSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturate_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.SubtractSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturate_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.SubtractSaturate(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturate_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.SubtractSaturate(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturateScalar_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.SubtractSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturateScalar_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.SubtractSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractScalar_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Subtract(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractScalar_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.Subtract(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractScalar_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Subtract(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractScalar_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.Subtract(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningLower_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.SubtractWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningLower_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.SubtractWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningLower_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.SubtractWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningLower_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.SubtractWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningLower_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.SubtractWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningLower_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.SubtractWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningLower_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.SubtractWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningLower_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.SubtractWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningLower_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.SubtractWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningLower_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.SubtractWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningLower_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.SubtractWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningLower_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.SubtractWidening(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningUpper_Vector128_Byte_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.SubtractWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningUpper_Vector128_Int16_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.SubtractWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningUpper_Vector128_Int16_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.SubtractWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningUpper_Vector128_Int32_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.SubtractWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningUpper_Vector128_Int32_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.SubtractWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningUpper_Vector128_Int64_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.SubtractWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningUpper_Vector128_SByte_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.SubtractWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningUpper_Vector128_UInt16_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.SubtractWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningUpper_Vector128_UInt16_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.SubtractWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningUpper_Vector128_UInt32_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.SubtractWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningUpper_Vector128_UInt32_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.SubtractWideningUpper(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "SubtractWideningUpper_Vector128_UInt64_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.SubtractWideningUpper(left, right, i) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "VectorTableLookup_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "VectorTableLookup", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "(Byte)(TestLibrary.Generator.GetByte() % 20)", ["ValidateFirstResult"] = "Helpers.TableVectorLookup(0, right, left) != result[0]", ["ValidateRemainingResults"] = "Helpers.TableVectorLookup(i, right, left) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "VectorTableLookup_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "VectorTableLookup", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "(SByte)(TestLibrary.Generator.GetSByte() % 20)", ["ValidateFirstResult"] = "Helpers.TableVectorLookup(0, right, left) != result[0]", ["ValidateRemainingResults"] = "Helpers.TableVectorLookup(i, right, left) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "VectorTableLookupExtension_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "VectorTableLookupExtension", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "(Byte)(TestLibrary.Generator.GetByte() % 20)", ["ValidateIterResult"] = "Helpers.TableVectorExtension(i, firstOp, thirdOp, secondOp) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "VectorTableLookupExtension_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "VectorTableLookupExtension", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector64", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "(SByte)(TestLibrary.Generator.GetSByte() % 20)", ["ValidateIterResult"] = "Helpers.TableVectorExtension(i, firstOp, thirdOp, secondOp) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Xor(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Xor(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector64_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_Double", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Xor(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_Int64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_Single", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Xor(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Xor_Vector128_UInt64", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "Xor", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.Xor(left[i], right[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ZeroExtendWideningLower_Vector64_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZeroExtendWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.ZeroExtendWidening(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ZeroExtendWideningLower_Vector64_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZeroExtendWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ZeroExtendWidening(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ZeroExtendWideningLower_Vector64_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZeroExtendWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ZeroExtendWidening(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ZeroExtendWideningLower_Vector64_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZeroExtendWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ZeroExtendWidening(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ZeroExtendWideningLower_Vector64_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZeroExtendWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.ZeroExtendWidening(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ZeroExtendWideningLower_Vector64_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZeroExtendWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.ZeroExtendWidening(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ZeroExtendWideningUpper_Vector128_Byte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZeroExtendWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.ZeroExtendWideningUpper(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ZeroExtendWideningUpper_Vector128_Int16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZeroExtendWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.ZeroExtendWideningUpper(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ZeroExtendWideningUpper_Vector128_Int32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZeroExtendWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.ZeroExtendWideningUpper(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ZeroExtendWideningUpper_Vector128_SByte", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZeroExtendWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ZeroExtendWideningUpper(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ZeroExtendWideningUpper_Vector128_UInt16", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZeroExtendWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.ZeroExtendWideningUpper(firstOp, i) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ZeroExtendWideningUpper_Vector128_UInt32", ["Isa"] = "AdvSimd", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZeroExtendWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.ZeroExtendWideningUpper(firstOp, i) != result[i]"}) }; private static readonly (string templateFileName, Dictionary templateData)[] AdvSimd_Arm64Inputs = new [] { - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "-TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Abs(firstOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "-TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AbsScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "-TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.Abs(firstOp[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThan_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareGreaterThan(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThanScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareGreaterThan(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThanScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareGreaterThan(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThanOrEqual_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareGreaterThanOrEqual(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThanOrEqualScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareGreaterThanOrEqual(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThanOrEqualScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareGreaterThanOrEqual(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThan_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareLessThan(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThanScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareLessThan(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThanScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareLessThan(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThanOrEqual_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareLessThanOrEqual(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThanOrEqualScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareLessThanOrEqual(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThanOrEqualScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareLessThanOrEqual(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteDifference(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteDifference(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteDifference(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Add(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AddPairwise(left, right, i)) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AddPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.AddPairwise(firstOp, 0)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseScalar_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AddPairwise(firstOp, 0)) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseScalar_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.AddPairwise(firstOp, 0) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseScalar_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.AddPairwise(firstOp, 0) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareEqual(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqualScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareEqual(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqualScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.CompareEqual(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqualScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareEqual(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqualScalar_Vector64_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.CompareEqual(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareGreaterThan(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareGreaterThan(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.CompareGreaterThan(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareGreaterThan(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanScalar_Vector64_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.CompareGreaterThan(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareGreaterThanOrEqual(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqualScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareGreaterThanOrEqual(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqualScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.CompareGreaterThanOrEqual(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqualScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareGreaterThanOrEqual(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqualScalar_Vector64_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.CompareGreaterThanOrEqual(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareLessThan(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareLessThan(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.CompareLessThan(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareLessThan(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanScalar_Vector64_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.CompareLessThan(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareLessThanOrEqual(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqualScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareLessThanOrEqual(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqualScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.CompareLessThanOrEqual(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqualScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareLessThanOrEqual(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqualScalar_Vector64_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.CompareLessThanOrEqual(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareTest(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareTestScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTestScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareTest(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareTestScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTestScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.CompareTest(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareTestScalar_Vector64_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTestScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.CompareTest(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Divide_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Divide", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Divide(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Divide_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Divide", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Divide(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Divide_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Divide", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Divide(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplyAdd_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FusedMultiplyAdd(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplySubtract_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FusedMultiplySubtract(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Max(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateReduceOpResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxAcross(firstOp)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumber_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumber", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MaxNumber(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxNumberAcross_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateReduceOpResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxNumberAcross(firstOp)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumberPairwise_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxNumberPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumberPairwise_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MaxNumberPairwise(left, right, i)) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumberPairwise_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxNumberPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MaxNumberPairwiseScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxNumberPairwise(firstOp, 0)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MaxNumberPairwiseScalar_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MaxNumberPairwise(firstOp, 0)) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MaxPairwise(left, right, i)) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MaxPairwiseScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxPairwise(firstOp, 0)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MaxPairwiseScalar_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MaxPairwise(firstOp, 0)) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MaxScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Max(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MaxScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Max(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Min(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateReduceOpResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinAcross(firstOp)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinNumber_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumber", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MinNumber(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinNumberAcross_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateReduceOpResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinNumberAcross(firstOp)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinNumberPairwise_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinNumberPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinNumberPairwise_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MinNumberPairwise(left, right, i)) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinNumberPairwise_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinNumberPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MinNumberPairwiseScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinNumberPairwise(firstOp, 0)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MinNumberPairwiseScalar_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MinNumberPairwise(firstOp, 0)) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MinPairwise(left, right, i)) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MinPairwiseScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinPairwise(firstOp, 0)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MinPairwiseScalar_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MinPairwise(firstOp, 0)) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MinScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Min(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MinScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Min(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Multiply(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtended_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtended", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MultiplyExtended(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtended_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtended", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MultiplyExtended(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtended_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtended", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MultiplyExtended(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtendedScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtendedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MultiplyExtended(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtendedScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtendedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MultiplyExtended(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Negate(firstOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "NegateScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "NegateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.Negate(firstOp[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0x4013d00000000000"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimateScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != 0x4013d00000000000", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimateScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != 0x409e8000", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalExponentScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalExponentScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != 0x4030000000000000", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalExponentScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalExponentScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != 0x41800000", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateIterResult"] = " BitConverter.DoubleToInt64Bits(result[i]) != 0x4001d00000000000"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimateScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != 0x4001d00000000000", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimateScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != 0x400e8000", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStep_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStep", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FPRSqrtStepFused(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStepScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStepScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FPRSqrtStepFused(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStepScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStepScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRSqrtStepFused(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStep_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStep", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FPRecipStepFused(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStepScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStepScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FPRecipStepFused(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), - ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStepScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStepScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRecipStepFused(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReverseElementBits", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.ReverseElementBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReverseElementBits", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ReverseElementBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReverseElementBits", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.ReverseElementBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReverseElementBits", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ReverseElementBits(firstOp[i]) != result[i]"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sqrt_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Sqrt", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Sqrt(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sqrt_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Sqrt", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Sqrt(firstOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sqrt_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Sqrt", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Sqrt(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Subtract(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), - ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "-TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Abs(firstOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Abs_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Abs", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "-TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Abs(firstOp[i]) != result[i]"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AbsScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "-TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.Abs(firstOp[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThan_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareGreaterThan(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThanScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareGreaterThan(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThanScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareGreaterThan(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThanOrEqual_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareGreaterThanOrEqual(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThanOrEqualScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareGreaterThanOrEqual(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareGreaterThanOrEqualScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareGreaterThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareGreaterThanOrEqual(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThan_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareLessThan(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThanScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareLessThan(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThanScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareLessThan(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThanOrEqual_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareLessThanOrEqual(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThanOrEqualScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteCompareLessThanOrEqual(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteCompareLessThanOrEqualScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteCompareLessThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteCompareLessThanOrEqual(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifference_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifference", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteDifference(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AbsoluteDifference(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AbsoluteDifferenceScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AbsoluteDifferenceScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.AbsoluteDifference(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Add_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Add", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Add(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "AddAcross_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateReduceOpResult"] = "Helpers.AddAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AddPairwise(left, right, i)) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.AddPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "AddPairwise_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.AddPairwise(left, right, i) != result[i]"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.AddPairwise(firstOp, 0)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseScalar_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.AddPairwise(firstOp, 0)) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseScalar_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.AddPairwise(firstOp, 0) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "AddPairwiseScalar_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.AddPairwise(firstOp, 0) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturateScalar_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateFirstResult"] = "Helpers.AddSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturateScalar_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "Helpers.AddSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturateScalar_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateFirstResult"] = "Helpers.AddSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturateScalar_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateFirstResult"] = "Helpers.AddSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturateScalar_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateFirstResult"] = "Helpers.AddSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "AddSaturateScalar_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "AddSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateFirstResult"] = "Helpers.AddSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareEqual(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqual_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.CompareEqual(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqualScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareEqual(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqualScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.CompareEqual(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqualScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareEqual(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareEqualScalar_Vector64_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.CompareEqual(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareGreaterThan(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThan_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.CompareGreaterThan(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareGreaterThan(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.CompareGreaterThan(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareGreaterThan(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanScalar_Vector64_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.CompareGreaterThan(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareGreaterThanOrEqual(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqual_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.CompareGreaterThanOrEqual(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqualScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareGreaterThanOrEqual(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqualScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.CompareGreaterThanOrEqual(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqualScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareGreaterThanOrEqual(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareGreaterThanOrEqualScalar_Vector64_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareGreaterThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.CompareGreaterThanOrEqual(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareLessThan(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThan_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThan", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.CompareLessThan(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareLessThan(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.CompareLessThan(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareLessThan(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanScalar_Vector64_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.CompareLessThan(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareLessThanOrEqual(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqual_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqual", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.CompareLessThanOrEqual(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqualScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareLessThanOrEqual(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqualScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.CompareLessThanOrEqual(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqualScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.CompareLessThanOrEqual(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareLessThanOrEqualScalar_Vector64_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareLessThanOrEqualScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.CompareLessThanOrEqual(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareTest(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "CompareTest_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTest", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateIterResult"] = "Helpers.CompareTest(left[i], right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareTestScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTestScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.CompareTest(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareTestScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTestScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.CompareTest(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "CompareTestScalar_Vector64_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "CompareTestScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.CompareTest(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Divide_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Divide", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Divide(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Divide_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Divide", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Divide(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Divide_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Divide", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Divide(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V128_Double_1", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V128_Int64_1", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "DuplicateSelectedScalarToVector128_V128_UInt64_1", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateSelectedScalarToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "1", ["ValidateFirstResult"] = "result[0] != firstOp[1]", ["ValidateRemainingResults"] = "result[i] != firstOp[1]" }), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_Double_31", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_Int64_31", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("DuplicateTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "result[0] != data", ["ValidateRemainingResults"] = "result[i] != data"}), + ("ImmOpTest.template", new Dictionary { ["TestName"] = "DuplicateToVector128_UInt64_31", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "DuplicateToVector128", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["Imm"] = "31", ["ValidateFirstResult"] = "result[0] != 31", ["ValidateRemainingResults"] = "result[i] != 31"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplyAdd_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplyAdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FusedMultiplyAdd(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "FusedMultiplySubtract_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "FusedMultiplySubtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp3"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FusedMultiplySubtract(firstOp[i], secondOp[i], thirdOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Max_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Max", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Max(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateReduceOpResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxAcross(firstOp)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxAcross_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateReduceOpResult"] = "Helpers.MaxAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumber_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumber", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MaxNumber(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MaxNumberAcross_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateReduceOpResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxNumberAcross(firstOp)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumberPairwise_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxNumberPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumberPairwise_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MaxNumberPairwise(left, right, i)) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxNumberPairwise_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxNumberPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MaxNumberPairwiseScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxNumberPairwise(firstOp, 0)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MaxNumberPairwiseScalar_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxNumberPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MaxNumberPairwise(firstOp, 0)) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MaxPairwise(left, right, i)) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MaxPairwise_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MaxPairwise(left, right, i) != result[i]"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MaxPairwiseScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MaxPairwise(firstOp, 0)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MaxPairwiseScalar_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MaxPairwise(firstOp, 0)) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MaxScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Max(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MaxScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MaxScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Max(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Min_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Min", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Min(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateReduceOpResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinAcross(firstOp)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinAcross_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateReduceOpResult"] = "Helpers.MinAcross(firstOp) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinNumber_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumber", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MinNumber(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecReduceUnOpTest.template", new Dictionary { ["TestName"] = "MinNumberAcross_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberAcross", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateReduceOpResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinNumberAcross(firstOp)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinNumberPairwise_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberPairwise", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinNumberPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinNumberPairwise_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MinNumberPairwise(left, right, i)) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinNumberPairwise_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinNumberPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MinNumberPairwiseScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinNumberPairwise(firstOp, 0)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MinNumberPairwiseScalar_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinNumberPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MinNumberPairwise(firstOp, 0)) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MinPairwise(left, right, i)) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinPairwise(left, right, i)) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MinPairwise_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwise", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateIterResult"] = "Helpers.MinPairwise(left, right, i) != result[i]"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MinPairwiseScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MinPairwise(firstOp, 0)) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "MinPairwiseScalar_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinPairwiseScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MinPairwise(firstOp, 0)) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MinScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Min(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MinScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MinScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.Min(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Multiply_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Multiply(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtended_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtended", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MultiplyExtended(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtended_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtended", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MultiplyExtended(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtended_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtended", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.MultiplyExtended(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtendedScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtendedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.MultiplyExtended(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "MultiplyExtendedScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "MultiplyExtendedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.MultiplyExtended(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Negate(firstOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Negate_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Negate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateIterResult"] = "Helpers.Negate(firstOp[i]) != result[i]"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "NegateScalar_Vector64_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "NegateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.Negate(firstOp[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimate_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0x4013d00000000000"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimateScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != 0x4013d00000000000", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalEstimateScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalEstimateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != 0x409e8000", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalExponentScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalExponentScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != 0x4030000000000000", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalExponentScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalExponentScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != 0x41800000", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimate_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateIterResult"] = " BitConverter.DoubleToInt64Bits(result[i]) != 0x4001d00000000000"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimateScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int64BitsToDouble(0x3fc9db3dab555868)", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != 0x4001d00000000000", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleUnOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootEstimateScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootEstimateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "BitConverter.Int32BitsToSingle(0x3e4ed9ed)", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != 0x400e8000", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStep_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStep", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FPRSqrtStepFused(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStepScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStepScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FPRSqrtStepFused(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalSquareRootStepScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalSquareRootStepScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRSqrtStepFused(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStep_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStep", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FPRecipStepFused(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStepScalar_Vector64_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStepScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Helpers.FPRecipStepFused(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ReciprocalStepScalar_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReciprocalStepScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(Helpers.FPRecipStepFused(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != 0"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReverseElementBits", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.ReverseElementBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReverseElementBits", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ReverseElementBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReverseElementBits", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["ValidateIterResult"] = "Helpers.ReverseElementBits(firstOp[i]) != result[i]"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ReverseElementBits", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["ValidateIterResult"] = "Helpers.ReverseElementBits(firstOp[i]) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRoundedSaturateScalar_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRoundedSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "Helpers.ShiftArithmeticRoundedSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRoundedSaturateScalar_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRoundedSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateFirstResult"] = "Helpers.ShiftArithmeticRoundedSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticRoundedSaturateScalar_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticRoundedSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateFirstResult"] = "Helpers.ShiftArithmeticRoundedSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticSaturateScalar_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "Helpers.ShiftArithmeticSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticSaturateScalar_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateFirstResult"] = "Helpers.ShiftArithmeticSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftArithmeticSaturateScalar_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftArithmeticSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateFirstResult"] = "Helpers.ShiftArithmeticSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateScalar_Vector64_Byte_7", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["Imm"] = "7", ["ValidateFirstResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateScalar_Vector64_Int16_15", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "15", ["ValidateFirstResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateScalar_Vector64_Int32_31", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "31", ["ValidateFirstResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateScalar_Vector64_SByte_1", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateScalar_Vector64_UInt16_1", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateScalar_Vector64_UInt32_1", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "1", ["ValidateFirstResult"] = "Helpers.ShiftLeftLogicalSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int16_5", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateUnsignedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "5", ["ValidateFirstResult"] = "Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int32_7", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateUnsignedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "7", ["ValidateFirstResult"] = "Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftLeftLogicalSaturateUnsignedScalar_Vector64_SByte_3", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLeftLogicalSaturateUnsignedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["Imm"] = "3", ["ValidateFirstResult"] = "Helpers.ShiftLeftLogicalSaturateUnsigned(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturateScalar_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturateScalar_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturateScalar_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturateScalar_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturateScalar_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalRoundedSaturateScalar_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalRoundedSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalRoundedSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturateScalar_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturateScalar_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturateScalar_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturateScalar_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturateScalar_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "ShiftLogicalSaturateScalar_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftLogicalSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateFirstResult"] = "Helpers.ShiftLogicalSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int16_16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "16", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int32_32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "32", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateScalar_Vector64_SByte_8", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "8", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_Byte_3", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateUnsignedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "3", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturateUnsigned(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt16_5", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateUnsignedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "5", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturateUnsigned(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt32_7", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticNarrowingSaturateUnsignedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "7", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticNarrowingSaturateUnsigned(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int16_32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "16", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int32_64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "32", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_SByte_16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "8", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_Byte_1", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "7", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt16_1",["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "15", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt32_1",["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "31", ["ValidateFirstResult"] = "Helpers.ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateScalar_Vector64_Byte_5", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "7", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int16_7", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "15", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int32_11", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "31", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateScalar_Vector64_SByte_3", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "7", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt16_5", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "15", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt32_7", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "31", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Byte_1", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["Imm"] = "3", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int16_1", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["Imm"] = "5", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int32_1", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["Imm"] = "7", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_SByte_1", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["Imm"] = "3", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt16_1", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["Imm"] = "5", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("ImmUnOpTest.template", new Dictionary { ["TestName"] = "ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt32_1", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ShiftRightLogicalRoundedNarrowingSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["Imm"] = "7", ["ValidateFirstResult"] = "Helpers.ShiftRightLogicalRoundedNarrowingSaturate(firstOp[0], Imm) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sqrt_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Sqrt", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Sqrt(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sqrt_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Sqrt", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Sqrt(firstOp[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleVecOpTest.template", new Dictionary { ["TestName"] = "Sqrt_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Sqrt", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateIterResult"] = "BitConverter.SingleToInt32Bits(Helpers.Sqrt(firstOp[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("VecBinOpTest.template", new Dictionary { ["TestName"] = "Subtract_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "Subtract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateIterResult"] = "BitConverter.DoubleToInt64Bits(Helpers.Subtract(left[i], right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturateScalar_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateFirstResult"] = "Helpers.SubtractSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturateScalar_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "Helpers.SubtractSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturateScalar_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateFirstResult"] = "Helpers.SubtractSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturateScalar_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateFirstResult"] = "Helpers.SubtractSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturateScalar_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateFirstResult"] = "Helpers.SubtractSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "SubtractSaturateScalar_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "SubtractSaturateScalar", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateFirstResult"] = "Helpers.SubtractSaturate(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "result[i] != 0"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeEven_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[index] != left[i] || result[++index] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "TransposeOdd_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "TransposeOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[index] != left[i+1] || result[++index] != right[i+1]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "VectorTableLookup_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "VectorTableLookup", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "(Byte)(TestLibrary.Generator.GetByte() % 20)", ["ValidateFirstResult"] = "Helpers.TableVectorLookup(0, right, left) != result[0]", ["ValidateRemainingResults"] = "Helpers.TableVectorLookup(i, right, left) != result[i]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "VectorTableLookup_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "VectorTableLookup", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "(SByte)(TestLibrary.Generator.GetSByte() % 20)", ["ValidateFirstResult"] = "Helpers.TableVectorLookup(0, right, left) != result[0]", ["ValidateRemainingResults"] = "Helpers.TableVectorLookup(i, right, left) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "VectorTableLookupExtension_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "VectorTableLookupExtension", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["NextValueOp3"] = "(Byte)(TestLibrary.Generator.GetByte() % 20)", ["ValidateIterResult"] = "Helpers.TableVectorExtension(i, firstOp, thirdOp, secondOp) != result[i]"}), + ("VecTernOpTest.template", new Dictionary { ["TestName"] = "VectorTableLookupExtension_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "VectorTableLookupExtension", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp3"] = "(SByte)(TestLibrary.Generator.GetSByte() % 20)", ["ValidateIterResult"] = "Helpers.TableVectorExtension(i, firstOp, thirdOp, secondOp) != result[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipEven_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipEven", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[index] != left[i] || result[index + half] != right[i]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "UnzipOdd_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "UnzipOdd", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[index] != left[i+1] || result[index + half] != right[i+1]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipHigh_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[i] != left[index+half] || result[i+1] != right[index+half]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector64_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector64_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector64_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector64_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector64_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector64_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector64_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_Byte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_Double", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_Int16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_Int32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt32()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_Int64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_SByte", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "SByte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "SByte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "SByte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetSByte()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_Single", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_UInt16", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_UInt32", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), + ("VecPairBinOpTest.template", new Dictionary { ["TestName"] = "ZipLow_Vector128_UInt64", ["Isa"] = "AdvSimd.Arm64", ["LoadIsa"] = "AdvSimd", ["Method"] = "ZipLow", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateEntry"] = "result[i] != left[index] || result[i+1] != right[index]"}), }; private static readonly (string templateFileName, Dictionary templateData)[] AesInputs = new [] { - ("AesBinOpTest.template", new Dictionary { ["TestName"] = "Decrypt_Vector128_Byte", ["Isa"] = "Aes", ["LoadIsa"] = "AdvSimd", ["Method"] = "Decrypt", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["InputSize"] = "16", ["Input"] = "{0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88}", ["KeySize"] = "16", ["Key"] = "{0xFF, 0xDD, 0xBB, 0x99, 0x77, 0x55, 0x33, 0x11, 0xEE, 0xCC, 0xAA, 0x88, 0x66, 0x44, 0x22, 0x00}", ["ExpectedRetSize"] = "16", ["ExpectedRet"] = "{0x7C, 0x99, 0x02, 0x7C, 0x7C, 0x7C, 0xFE, 0x86, 0xE3, 0x7C, 0x7C, 0x97, 0xC9, 0x94, 0x7C, 0x7C}"}), - ("AesBinOpTest.template", new Dictionary { ["TestName"] = "Encrypt_Vector128_Byte", ["Isa"] = "Aes", ["LoadIsa"] = "AdvSimd", ["Method"] = "Encrypt", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["InputSize"] = "16", ["Input"] = "{0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88}", ["KeySize"] = "16", ["Key"] = "{0xFF, 0xDD, 0xBB, 0x99, 0x77, 0x55, 0x33, 0x11, 0xEE, 0xCC, 0xAA, 0x88, 0x66, 0x44, 0x22, 0x00}", ["ExpectedRetSize"] = "16", ["ExpectedRet"] = "{0xCA, 0xCA, 0xF5, 0xC4, 0xCA, 0x93, 0xEA, 0xCA, 0x82, 0x28, 0xCA, 0xCA, 0xC1, 0xCA, 0xCA, 0x1B}"}), - ("AesUnOpTest.template", new Dictionary { ["TestName"] = "InverseMixColumns_Vector128_Byte", ["Isa"] = "Aes", ["LoadIsa"] = "AdvSimd", ["Method"] = "InverseMixColumns", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["InputSize"] = "16", ["Input"] = "{0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88}", ["ExpectedRetSize"] = "16", ["ExpectedRet"] = "{0xA0, 0x0A, 0xE4, 0x4E, 0x28, 0x82, 0x6C, 0xC6, 0x55, 0x00, 0x77, 0x22, 0x11, 0x44, 0x33, 0x66}"}), - ("AesUnOpTest.template", new Dictionary { ["TestName"] = "MixColumns_Vector128_Byte", ["Isa"] = "Aes", ["LoadIsa"] = "AdvSimd", ["Method"] = "MixColumns", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["InputSize"] = "16", ["Input"] = "{0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88}", ["ExpectedRetSize"] = "16", ["ExpectedRet"] = "{0xAB, 0x01, 0xEF, 0x45, 0x23, 0x89, 0x67, 0xCD, 0xDD, 0x88, 0xFF, 0xAA, 0x99, 0xCC, 0xBB, 0xEE}"}), + ("AesBinOpTest.template", new Dictionary { ["TestName"] = "Decrypt_Vector128_Byte", ["Isa"] = "Aes", ["LoadIsa"] = "AdvSimd", ["Method"] = "Decrypt", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["InputSize"] = "16", ["Input"] = "{0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88}", ["KeySize"] = "16", ["Key"] = "{0xFF, 0xDD, 0xBB, 0x99, 0x77, 0x55, 0x33, 0x11, 0xEE, 0xCC, 0xAA, 0x88, 0x66, 0x44, 0x22, 0x00}", ["ExpectedRetSize"] = "16", ["ExpectedRet"] = "{0x7C, 0x99, 0x02, 0x7C, 0x7C, 0x7C, 0xFE, 0x86, 0xE3, 0x7C, 0x7C, 0x97, 0xC9, 0x94, 0x7C, 0x7C}"}), + ("AesBinOpTest.template", new Dictionary { ["TestName"] = "Encrypt_Vector128_Byte", ["Isa"] = "Aes", ["LoadIsa"] = "AdvSimd", ["Method"] = "Encrypt", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["InputSize"] = "16", ["Input"] = "{0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88}", ["KeySize"] = "16", ["Key"] = "{0xFF, 0xDD, 0xBB, 0x99, 0x77, 0x55, 0x33, 0x11, 0xEE, 0xCC, 0xAA, 0x88, 0x66, 0x44, 0x22, 0x00}", ["ExpectedRetSize"] = "16", ["ExpectedRet"] = "{0xCA, 0xCA, 0xF5, 0xC4, 0xCA, 0x93, 0xEA, 0xCA, 0x82, 0x28, 0xCA, 0xCA, 0xC1, 0xCA, 0xCA, 0x1B}"}), + ("AesUnOpTest.template", new Dictionary { ["TestName"] = "InverseMixColumns_Vector128_Byte", ["Isa"] = "Aes", ["LoadIsa"] = "AdvSimd", ["Method"] = "InverseMixColumns", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["InputSize"] = "16", ["Input"] = "{0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88}", ["ExpectedRetSize"] = "16", ["ExpectedRet"] = "{0xA0, 0x0A, 0xE4, 0x4E, 0x28, 0x82, 0x6C, 0xC6, 0x55, 0x00, 0x77, 0x22, 0x11, 0x44, 0x33, 0x66}"}), + ("AesUnOpTest.template", new Dictionary { ["TestName"] = "MixColumns_Vector128_Byte", ["Isa"] = "Aes", ["LoadIsa"] = "AdvSimd", ["Method"] = "MixColumns", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["InputSize"] = "16", ["Input"] = "{0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88}", ["ExpectedRetSize"] = "16", ["ExpectedRet"] = "{0xAB, 0x01, 0xEF, 0x45, 0x23, 0x89, 0x67, 0xCD, 0xDD, 0x88, 0xFF, 0xAA, 0x99, 0xCC, 0xBB, 0xEE}"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiplyWideningLower_Vector64_Int64", ["Isa"] = "Aes", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiplyWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.PolynomialMultiplyWideningLo64(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "Helpers.PolynomialMultiplyWideningHi64(left[0], right[0]) != result[1]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiplyWideningLower_Vector64_UInt64", ["Isa"] = "Aes", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiplyWideningLower", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.PolynomialMultiplyWideningLo64(left[0], right[0]) != result[0]", ["ValidateRemainingResults"] = "Helpers.PolynomialMultiplyWideningHi64(left[0], right[0]) != result[1]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiplyWideningUpper_Vector128_Int64", ["Isa"] = "Aes", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiplyWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "Helpers.PolynomialMultiplyWideningLo64(left[1], right[1]) != result[0]", ["ValidateRemainingResults"] = "Helpers.PolynomialMultiplyWideningHi64(left[1], right[1]) != result[1]"}), + ("SimpleBinOpTest.template", new Dictionary { ["TestName"] = "PolynomialMultiplyWideningUpper_Vector128_UInt64", ["Isa"] = "Aes", ["LoadIsa"] = "AdvSimd", ["Method"] = "PolynomialMultiplyWideningUpper", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "Helpers.PolynomialMultiplyWideningLo64(left[1], right[1]) != result[0]", ["ValidateRemainingResults"] = "Helpers.PolynomialMultiplyWideningHi64(left[1], right[1]) != result[1]"}) }; private static readonly (string templateFileName, Dictionary templateData)[] ArmBaseInputs = new [] { - ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Int32", ["Isa"] = "ArmBase", ["Method"] = "LeadingZeroCount", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "Int32", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateResult"] = "int expectedResult = 0; for (int index = 31; (((uint)data >> index) & 1) == 0; index--) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), - ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_UInt32", ["Isa"] = "ArmBase", ["Method"] = "LeadingZeroCount", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = "int expectedResult = 0; for (int index = 31; ((data >> index) & 1) == 0; index--) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), - ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Int32", ["Isa"] = "ArmBase", ["Method"] = "ReverseElementBits", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "Int32", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateResult"] = "isUnexpectedResult = Helpers.ReverseElementBits(data) != result;" }), - ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_UInt32", ["Isa"] = "ArmBase", ["Method"] = "ReverseElementBits", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = "isUnexpectedResult = Helpers.ReverseElementBits(data) != result;" }), + ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Int32", ["Isa"] = "ArmBase", ["Method"] = "LeadingZeroCount", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "Int32", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateResult"] = "int expectedResult = 0; for (int index = 31; (((uint)data >> index) & 1) == 0; index--) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), + ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_UInt32", ["Isa"] = "ArmBase", ["Method"] = "LeadingZeroCount", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = "int expectedResult = 0; for (int index = 31; ((data >> index) & 1) == 0; index--) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), + ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Int32", ["Isa"] = "ArmBase", ["Method"] = "ReverseElementBits", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "Int32", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateResult"] = "isUnexpectedResult = Helpers.ReverseElementBits(data) != result;" }), + ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_UInt32", ["Isa"] = "ArmBase", ["Method"] = "ReverseElementBits", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = "isUnexpectedResult = Helpers.ReverseElementBits(data) != result;" }), }; private static readonly (string templateFileName, Dictionary templateData)[] ArmBase_Arm64Inputs = new [] { - ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Int32", ["Isa"] = "ArmBase.Arm64", ["Method"] = "LeadingSignCount", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "Int32", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateResult"] = "int expectedResult = 0; for (int index = 30; (((uint)data >> index) & 1) == (((uint)data >> 31) & 1); index--) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), - ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Int64", ["Isa"] = "ArmBase.Arm64", ["Method"] = "LeadingSignCount", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "Int64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateResult"] = "int expectedResult = 0; for (int index = 62; (((ulong)data >> index) & 1) == (((ulong)data >> 63) & 1); index--) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), - ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Int64", ["Isa"] = "ArmBase.Arm64", ["Method"] = "LeadingZeroCount", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "Int64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateResult"] = "int expectedResult = 0; for (int index = 63; (((ulong)data >> index) & 1) == 0; index--) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), - ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_UInt64", ["Isa"] = "ArmBase.Arm64", ["Method"] = "LeadingZeroCount", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = "int expectedResult = 0; for (int index = 63; ((data >> index) & 1) == 0; index--) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), - ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Int64", ["Isa"] = "ArmBase.Arm64", ["Method"] = "ReverseElementBits", ["RetBaseType"] = "Int64", ["Op1BaseType"] = "Int64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateResult"] = "isUnexpectedResult = Helpers.ReverseElementBits(data) != result;" }), - ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_UInt64", ["Isa"] = "ArmBase.Arm64", ["Method"] = "ReverseElementBits", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = "isUnexpectedResult = Helpers.ReverseElementBits(data) != result;" }), + ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Int32", ["Isa"] = "ArmBase.Arm64", ["Method"] = "LeadingSignCount", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "Int32", ["NextValueOp1"] = "TestLibrary.Generator.GetInt32()", ["ValidateResult"] = "int expectedResult = 0; for (int index = 30; (((uint)data >> index) & 1) == (((uint)data >> 31) & 1); index--) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), + ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "LeadingSignCount_Int64", ["Isa"] = "ArmBase.Arm64", ["Method"] = "LeadingSignCount", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "Int64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateResult"] = "int expectedResult = 0; for (int index = 62; (((ulong)data >> index) & 1) == (((ulong)data >> 63) & 1); index--) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), + ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_Int64", ["Isa"] = "ArmBase.Arm64", ["Method"] = "LeadingZeroCount", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "Int64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateResult"] = "int expectedResult = 0; for (int index = 63; (((ulong)data >> index) & 1) == 0; index--) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), + ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "LeadingZeroCount_UInt64", ["Isa"] = "ArmBase.Arm64", ["Method"] = "LeadingZeroCount", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = "int expectedResult = 0; for (int index = 63; ((data >> index) & 1) == 0; index--) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), + ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_Int64", ["Isa"] = "ArmBase.Arm64", ["Method"] = "ReverseElementBits", ["RetBaseType"] = "Int64", ["Op1BaseType"] = "Int64", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateResult"] = "isUnexpectedResult = Helpers.ReverseElementBits(data) != result;" }), + ("ScalarUnOpTest.template", new Dictionary { ["TestName"] = "ReverseElementBits_UInt64", ["Isa"] = "ArmBase.Arm64", ["Method"] = "ReverseElementBits", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = "isUnexpectedResult = Helpers.ReverseElementBits(data) != result;" }), }; private static readonly (string templateFileName, Dictionary templateData)[] Crc32Inputs = new [] { - ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32_Byte", ["Isa"] = "Crc32", ["Method"] = "ComputeCrc32", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Byte", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x20", ["ValidateResult"] = "uint expectedResult = 0x169330BA; isUnexpectedResult = (expectedResult != result);" }), - ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32_UInt16", ["Isa"] = "Crc32", ["Method"] = "ComputeCrc32", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt16", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x2019", ["ValidateResult"] = "uint expectedResult = 0x1E4864D0; isUnexpectedResult = (expectedResult != result);" }), - ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32_UInt32", ["Isa"] = "Crc32", ["Method"] = "ComputeCrc32", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x20191113", ["ValidateResult"] = "uint expectedResult = 0x219D9805; isUnexpectedResult = (expectedResult != result);" }), - ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32C_Byte", ["Isa"] = "Crc32", ["Method"] = "ComputeCrc32C", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Byte", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x20", ["ValidateResult"] = "uint expectedResult = 0x8D3F2270; isUnexpectedResult = (expectedResult != result);" }), - ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32C_UInt16", ["Isa"] = "Crc32", ["Method"] = "ComputeCrc32C", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt16", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x2019", ["ValidateResult"] = "uint expectedResult = 0x9F50ACBD; isUnexpectedResult = (expectedResult != result);" }), - ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32C_UInt32", ["Isa"] = "Crc32", ["Method"] = "ComputeCrc32C", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x20191113", ["ValidateResult"] = "uint expectedResult = 0x78F34758; isUnexpectedResult = (expectedResult != result);" }), + ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32_Byte", ["Isa"] = "Crc32", ["Method"] = "ComputeCrc32", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Byte", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x20", ["ValidateResult"] = "uint expectedResult = 0x169330BA; isUnexpectedResult = (expectedResult != result);" }), + ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32_UInt16", ["Isa"] = "Crc32", ["Method"] = "ComputeCrc32", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt16", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x2019", ["ValidateResult"] = "uint expectedResult = 0x1E4864D0; isUnexpectedResult = (expectedResult != result);" }), + ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32_UInt32", ["Isa"] = "Crc32", ["Method"] = "ComputeCrc32", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x20191113", ["ValidateResult"] = "uint expectedResult = 0x219D9805; isUnexpectedResult = (expectedResult != result);" }), + ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32C_Byte", ["Isa"] = "Crc32", ["Method"] = "ComputeCrc32C", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Byte", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x20", ["ValidateResult"] = "uint expectedResult = 0x8D3F2270; isUnexpectedResult = (expectedResult != result);" }), + ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32C_UInt16", ["Isa"] = "Crc32", ["Method"] = "ComputeCrc32C", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt16", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x2019", ["ValidateResult"] = "uint expectedResult = 0x9F50ACBD; isUnexpectedResult = (expectedResult != result);" }), + ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32C_UInt32", ["Isa"] = "Crc32", ["Method"] = "ComputeCrc32C", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x20191113", ["ValidateResult"] = "uint expectedResult = 0x78F34758; isUnexpectedResult = (expectedResult != result);" }), }; private static readonly (string templateFileName, Dictionary templateData)[] Crc32_Arm64Inputs = new [] { - ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32_UInt64", ["Isa"] = "Crc32.Arm64", ["Method"] = "ComputeCrc32", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt64", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x20191113110219UL", ["ValidateResult"] = "uint expectedResult = 0xEFAAAB74; isUnexpectedResult = (expectedResult != result);" }), - ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32C_UInt64", ["Isa"] = "Crc32.Arm64", ["Method"] = "ComputeCrc32C", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt64", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x20191113110219UL", ["ValidateResult"] = "uint expectedResult = 0x6295C71A; isUnexpectedResult = (expectedResult != result);" }), + ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32_UInt64", ["Isa"] = "Crc32.Arm64", ["Method"] = "ComputeCrc32", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt64", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x20191113110219UL", ["ValidateResult"] = "uint expectedResult = 0xEFAAAB74; isUnexpectedResult = (expectedResult != result);" }), + ("ScalarBinOpTest.template", new Dictionary { ["TestName"] = "ComputeCrc32C_UInt64", ["Isa"] = "Crc32.Arm64", ["Method"] = "ComputeCrc32C", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt64", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "0x20191113110219UL", ["ValidateResult"] = "uint expectedResult = 0x6295C71A; isUnexpectedResult = (expectedResult != result);" }), }; private static readonly (string templateFileName, Dictionary templateData)[] Sha1Inputs = new [] { - ("SecureHashUnOpTest.template", new Dictionary { ["TestName"] = "FixedRotate_Vector64_UInt32", ["Isa"] = "Sha1", ["LoadIsa"] = "AdvSimd", ["Method"] = "FixedRotate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "0x00112233", ["ExpectedResult"] = "{0xC004488C, 0x0, 0x0, 0x0}"}), - ("SecureHashTernOpTest.template",new Dictionary { ["TestName"] = "HashUpdateChoose_Vector128_UInt32", ["Isa"] = "Sha1", ["LoadIsa"] = "AdvSimd", ["Method"] = "HashUpdateChoose", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["NextValueOp3"] = "0x8899AABB", ["ExpectedResult"] = "{0x27A38C6D, 0xEFEFCA67, 0xDB4E8169, 0x73C91E71}"}), - ("SecureHashTernOpTest.template",new Dictionary { ["TestName"] = "HashUpdateMajority_Vector128_UInt32", ["Isa"] = "Sha1", ["LoadIsa"] = "AdvSimd", ["Method"] = "HashUpdateMajority", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["NextValueOp3"] = "0x8899AABB", ["ExpectedResult"] = "{0xEC691B1D, 0xF21410C7, 0x9B52C9F6, 0x73C91E71}"}), - ("SecureHashTernOpTest.template",new Dictionary { ["TestName"] = "HashUpdateParity_Vector128_UInt32", ["Isa"] = "Sha1", ["LoadIsa"] = "AdvSimd", ["Method"] = "HashUpdateParity", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["NextValueOp3"] = "0x8899AABB", ["ExpectedResult"] = "{0xDAB2AF34, 0xFF990D18, 0xCB4F938C, 0x73C91E71}"}), - ("SecureHashTernOpTest.template",new Dictionary { ["TestName"] = "ScheduleUpdate0_Vector128_UInt32", ["Isa"] = "Sha1", ["LoadIsa"] = "AdvSimd", ["Method"] = "ScheduleUpdate0", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["NextValueOp3"] = "0x8899AABB", ["ExpectedResult"] = "{0x8899AABB, 0x8899AABB, 0xCCDDEEFF, 0xCCDDEEFF}"}), - ("SecureHashBinOpTest.template", new Dictionary { ["TestName"] = "ScheduleUpdate1_Vector128_UInt32", ["Isa"] = "Sha1", ["LoadIsa"] = "AdvSimd", ["Method"] = "ScheduleUpdate1", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["ExpectedResult"] = "{0x88888888, 0x88888888, 0x88888888, 0x11335577}"}), + ("SecureHashUnOpTest.template", new Dictionary { ["TestName"] = "FixedRotate_Vector64_UInt32", ["Isa"] = "Sha1", ["LoadIsa"] = "AdvSimd", ["Method"] = "FixedRotate", ["RetVectorType"] = "Vector64", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector64", ["Op1BaseType"] = "UInt32", ["LargestVectorSize"] = "8", ["NextValueOp1"] = "0x00112233", ["ExpectedResult"] = "{0xC004488C, 0x0, 0x0, 0x0}"}), + ("SecureHashTernOpTest.template",new Dictionary { ["TestName"] = "HashUpdateChoose_Vector128_UInt32", ["Isa"] = "Sha1", ["LoadIsa"] = "AdvSimd", ["Method"] = "HashUpdateChoose", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["NextValueOp3"] = "0x8899AABB", ["ExpectedResult"] = "{0x27A38C6D, 0xEFEFCA67, 0xDB4E8169, 0x73C91E71}"}), + ("SecureHashTernOpTest.template",new Dictionary { ["TestName"] = "HashUpdateMajority_Vector128_UInt32", ["Isa"] = "Sha1", ["LoadIsa"] = "AdvSimd", ["Method"] = "HashUpdateMajority", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["NextValueOp3"] = "0x8899AABB", ["ExpectedResult"] = "{0xEC691B1D, 0xF21410C7, 0x9B52C9F6, 0x73C91E71}"}), + ("SecureHashTernOpTest.template",new Dictionary { ["TestName"] = "HashUpdateParity_Vector128_UInt32", ["Isa"] = "Sha1", ["LoadIsa"] = "AdvSimd", ["Method"] = "HashUpdateParity", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector64", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["NextValueOp3"] = "0x8899AABB", ["ExpectedResult"] = "{0xDAB2AF34, 0xFF990D18, 0xCB4F938C, 0x73C91E71}"}), + ("SecureHashTernOpTest.template",new Dictionary { ["TestName"] = "ScheduleUpdate0_Vector128_UInt32", ["Isa"] = "Sha1", ["LoadIsa"] = "AdvSimd", ["Method"] = "ScheduleUpdate0", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["NextValueOp3"] = "0x8899AABB", ["ExpectedResult"] = "{0x8899AABB, 0x8899AABB, 0xCCDDEEFF, 0xCCDDEEFF}"}), + ("SecureHashBinOpTest.template", new Dictionary { ["TestName"] = "ScheduleUpdate1_Vector128_UInt32", ["Isa"] = "Sha1", ["LoadIsa"] = "AdvSimd", ["Method"] = "ScheduleUpdate1", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["ExpectedResult"] = "{0x88888888, 0x88888888, 0x88888888, 0x11335577}"}), }; private static readonly (string templateFileName, Dictionary templateData)[] Sha256Inputs = new [] { - ("SecureHashTernOpTest.template",new Dictionary { ["TestName"] = "HashUpdate1_Vector128_UInt32", ["Isa"] = "Sha256", ["LoadIsa"] = "AdvSimd", ["Method"] = "HashUpdate1", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["NextValueOp3"] = "0x8899AABB", ["ExpectedResult"] = "{0x3D22118E, 0x987CA5FB, 0x54F4E477, 0xDFB50278}"}), - ("SecureHashTernOpTest.template",new Dictionary { ["TestName"] = "HashUpdate2_Vector128_UInt32", ["Isa"] = "Sha256", ["LoadIsa"] = "AdvSimd", ["Method"] = "HashUpdate2", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["NextValueOp3"] = "0x8899AABB", ["ExpectedResult"] = "{0xFFD38634, 0x2A33F83F, 0x55A1BE45, 0x5002B4C4}"}), - ("SecureHashBinOpTest.template", new Dictionary { ["TestName"] = "ScheduleUpdate0_Vector128_UInt32", ["Isa"] = "Sha256", ["LoadIsa"] = "AdvSimd", ["Method"] = "ScheduleUpdate0", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["ExpectedResult"] = "{0x2E9FE839, 0x2E9FE839, 0x2E9FE839, 0xBFB0F94A}"}), - ("SecureHashTernOpTest.template",new Dictionary { ["TestName"] = "ScheduleUpdate1_Vector128_UInt32", ["Isa"] = "Sha256", ["LoadIsa"] = "AdvSimd", ["Method"] = "ScheduleUpdate1", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["NextValueOp3"] = "0x8899AABB", ["ExpectedResult"] = "{0x248F1BDF, 0x248F1BDF, 0xB303DDBA, 0xF74821FE}"}), + ("SecureHashTernOpTest.template",new Dictionary { ["TestName"] = "HashUpdate1_Vector128_UInt32", ["Isa"] = "Sha256", ["LoadIsa"] = "AdvSimd", ["Method"] = "HashUpdate1", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["NextValueOp3"] = "0x8899AABB", ["ExpectedResult"] = "{0x3D22118E, 0x987CA5FB, 0x54F4E477, 0xDFB50278}"}), + ("SecureHashTernOpTest.template",new Dictionary { ["TestName"] = "HashUpdate2_Vector128_UInt32", ["Isa"] = "Sha256", ["LoadIsa"] = "AdvSimd", ["Method"] = "HashUpdate2", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["NextValueOp3"] = "0x8899AABB", ["ExpectedResult"] = "{0xFFD38634, 0x2A33F83F, 0x55A1BE45, 0x5002B4C4}"}), + ("SecureHashBinOpTest.template", new Dictionary { ["TestName"] = "ScheduleUpdate0_Vector128_UInt32", ["Isa"] = "Sha256", ["LoadIsa"] = "AdvSimd", ["Method"] = "ScheduleUpdate0", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["ExpectedResult"] = "{0x2E9FE839, 0x2E9FE839, 0x2E9FE839, 0xBFB0F94A}"}), + ("SecureHashTernOpTest.template",new Dictionary { ["TestName"] = "ScheduleUpdate1_Vector128_UInt32", ["Isa"] = "Sha256", ["LoadIsa"] = "AdvSimd", ["Method"] = "ScheduleUpdate1", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt32", ["Op3VectorType"] = "Vector128", ["Op3BaseType"] = "UInt32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "0x00112233", ["NextValueOp2"] = "0x44556677", ["NextValueOp3"] = "0x8899AABB", ["ExpectedResult"] = "{0x248F1BDF, 0x248F1BDF, 0xB303DDBA, 0xF74821FE}"}), }; private static void ProcessInputs(string groupName, (string templateFileName, Dictionary templateData)[] inputs) diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs index 3ddeb0424c2c66..9dede7c81433f5 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.cs @@ -8,6 +8,7 @@ // "%DevEnvDir%\TextTransform.exe" .\Helpers.tt using System; +using System.Linq; namespace JIT.HardwareIntrinsics.Arm { @@ -1433,6 +1434,2194 @@ public static float CompareTest(float left, float right) public static uint AbsoluteDifferenceAdd(uint op1, uint op2, uint op3) => (uint)(op1 + AbsoluteDifference(op2, op3)); + public static ushort AbsoluteDifferenceWidening(sbyte op1, sbyte op2) => op1 < op2 ? (ushort)(op2 - op1) : (ushort)(op1 - op2); + + public static ushort AbsoluteDifferenceWideningUpper(sbyte[] op1, sbyte[] op2, int i) => AbsoluteDifferenceWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static short AbsoluteDifferenceWideningAndAdd(short op1, sbyte op2, sbyte op3) => (short)(op1 + (short)AbsoluteDifferenceWidening(op2, op3)); + + public static short AbsoluteDifferenceWideningUpperAndAdd(short[] op1, sbyte[] op2, sbyte[] op3, int i) => AbsoluteDifferenceWideningAndAdd(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static short AddPairwiseWidening(sbyte[] op1, int i) => AddWidening(op1[2 * i], op1[2 * i + 1]); + + public static short AddPairwiseWideningAndAdd(short[] op1, sbyte[] op2, int i) => (short)(op1[i] + AddWidening(op2[2 * i], op2[2 * i + 1])); + + private static sbyte HighNarrowing(short op1, bool round) + { + ushort roundConst = 0; + if (round) + { + roundConst = (ushort)1 << (8 * sizeof(sbyte) - 1); + } + return (sbyte)(((ushort)op1 + roundConst) >> (8 * sizeof(sbyte))); + } + + public static sbyte AddHighNarrowing(short op1, short op2) => HighNarrowing((short)(op1 + op2), round: false); + + public static sbyte AddHighNarrowingUpper(sbyte[] op1, short[] op2, short[] op3, int i) => i < op1.Length ? op1[i] : AddHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static sbyte AddRoundedHighNarrowing(short op1, short op2) => HighNarrowing((short)(op1 + op2), round: true); + + public static short AddRoundedHighNarrowingUpper(sbyte[] op1, short[] op2, short[] op3, int i) => i < op1.Length ? op1[i] : AddRoundedHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static short AddWidening(sbyte op1, sbyte op2) => (short)((short)op1 + (short)op2); + + public static short AddWidening(short op1, sbyte op2) => (short)(op1 + op2); + + public static short AddWideningUpper(sbyte[] op1, sbyte[] op2, int i) => AddWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static short AddWideningUpper(short[] op1, sbyte[] op2, int i) => AddWidening(op1[i], op2[i + op2.Length / 2]); + + public static sbyte ExtractNarrowing(short op1) => (sbyte)op1; + + public static sbyte ExtractNarrowingUpper(sbyte[] op1, short[] op2, int i) => i < op1.Length ? op1[i] : ExtractNarrowing(op2[i - op1.Length]); + + public static sbyte FusedAddHalving(sbyte op1, sbyte op2) => (sbyte)((ushort)((short)op1 + (short)op2) >> 1); + + public static sbyte FusedAddRoundedHalving(sbyte op1, sbyte op2) => (sbyte)((ushort)((short)op1 + (short)op2 + 1) >> 1); + + public static sbyte FusedSubtractHalving(sbyte op1, sbyte op2) => (sbyte)((ushort)((short)op1 - (short)op2) >> 1); + + public static short MultiplyWidening(sbyte op1, sbyte op2) => (short)((short)op1 * (short)op2); + + public static short MultiplyWideningAndAdd(short op1, sbyte op2, sbyte op3) => (short)(op1 + MultiplyWidening(op2, op3)); + + public static short MultiplyWideningAndSubtract(short op1, sbyte op2, sbyte op3) => (short)(op1 - MultiplyWidening(op2, op3)); + + public static short MultiplyWideningUpper(sbyte[] op1, sbyte[] op2, int i) => MultiplyWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static short MultiplyWideningUpperAndAdd(short[] op1, sbyte[] op2, sbyte[] op3, int i) => MultiplyWideningAndAdd(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static short MultiplyWideningUpperAndSubtract(short[] op1, sbyte[] op2, sbyte[] op3, int i) => MultiplyWideningAndSubtract(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static sbyte SubtractHighNarrowing(short op1, short op2) => HighNarrowing((short)(op1 - op2), round: false); + + public static short SubtractHighNarrowingUpper(sbyte[] op1, short[] op2, short[] op3, int i) => i < op1.Length ? op1[i] : SubtractHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static sbyte SubtractRoundedHighNarrowing(short op1, short op2) => HighNarrowing((short)(op1 - op2), round: true); + + public static short SubtractRoundedHighNarrowingUpper(sbyte[] op1, short[] op2, short[] op3, int i) => i < op1.Length ? op1[i] : SubtractRoundedHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static short SubtractWidening(sbyte op1, sbyte op2) => (short)((short)op1 - (short)op2); + + public static short SubtractWidening(short op1, sbyte op2) => (short)(op1 - op2); + + public static short SubtractWideningUpper(sbyte[] op1, sbyte[] op2, int i) => SubtractWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static short SubtractWideningUpper(short[] op1, sbyte[] op2, int i) => SubtractWidening(op1[i], op2[i + op2.Length / 2]); + + public static short ZeroExtendWidening(sbyte op1) => (short)(ushort)op1; + + public static short ZeroExtendWideningUpper(sbyte[] op1, int i) => ZeroExtendWidening(op1[i + op1.Length / 2]); + + public static uint AbsoluteDifferenceWidening(short op1, short op2) => op1 < op2 ? (uint)(op2 - op1) : (uint)(op1 - op2); + + public static uint AbsoluteDifferenceWideningUpper(short[] op1, short[] op2, int i) => AbsoluteDifferenceWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static int AbsoluteDifferenceWideningAndAdd(int op1, short op2, short op3) => (int)(op1 + (int)AbsoluteDifferenceWidening(op2, op3)); + + public static int AbsoluteDifferenceWideningUpperAndAdd(int[] op1, short[] op2, short[] op3, int i) => AbsoluteDifferenceWideningAndAdd(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static int AddPairwiseWidening(short[] op1, int i) => AddWidening(op1[2 * i], op1[2 * i + 1]); + + public static int AddPairwiseWideningAndAdd(int[] op1, short[] op2, int i) => (int)(op1[i] + AddWidening(op2[2 * i], op2[2 * i + 1])); + + private static short HighNarrowing(int op1, bool round) + { + uint roundConst = 0; + if (round) + { + roundConst = (uint)1 << (8 * sizeof(short) - 1); + } + return (short)(((uint)op1 + roundConst) >> (8 * sizeof(short))); + } + + public static short AddHighNarrowing(int op1, int op2) => HighNarrowing((int)(op1 + op2), round: false); + + public static short AddHighNarrowingUpper(short[] op1, int[] op2, int[] op3, int i) => i < op1.Length ? op1[i] : AddHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static short AddRoundedHighNarrowing(int op1, int op2) => HighNarrowing((int)(op1 + op2), round: true); + + public static int AddRoundedHighNarrowingUpper(short[] op1, int[] op2, int[] op3, int i) => i < op1.Length ? op1[i] : AddRoundedHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static int AddWidening(short op1, short op2) => (int)((int)op1 + (int)op2); + + public static int AddWidening(int op1, short op2) => (int)(op1 + op2); + + public static int AddWideningUpper(short[] op1, short[] op2, int i) => AddWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static int AddWideningUpper(int[] op1, short[] op2, int i) => AddWidening(op1[i], op2[i + op2.Length / 2]); + + public static short ExtractNarrowing(int op1) => (short)op1; + + public static short ExtractNarrowingUpper(short[] op1, int[] op2, int i) => i < op1.Length ? op1[i] : ExtractNarrowing(op2[i - op1.Length]); + + public static short FusedAddHalving(short op1, short op2) => (short)((uint)((int)op1 + (int)op2) >> 1); + + public static short FusedAddRoundedHalving(short op1, short op2) => (short)((uint)((int)op1 + (int)op2 + 1) >> 1); + + public static short FusedSubtractHalving(short op1, short op2) => (short)((uint)((int)op1 - (int)op2) >> 1); + + public static int MultiplyWidening(short op1, short op2) => (int)((int)op1 * (int)op2); + + public static int MultiplyWideningAndAdd(int op1, short op2, short op3) => (int)(op1 + MultiplyWidening(op2, op3)); + + public static int MultiplyWideningAndSubtract(int op1, short op2, short op3) => (int)(op1 - MultiplyWidening(op2, op3)); + + public static int MultiplyWideningUpper(short[] op1, short[] op2, int i) => MultiplyWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static int MultiplyWideningUpperAndAdd(int[] op1, short[] op2, short[] op3, int i) => MultiplyWideningAndAdd(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static int MultiplyWideningUpperAndSubtract(int[] op1, short[] op2, short[] op3, int i) => MultiplyWideningAndSubtract(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static short SubtractHighNarrowing(int op1, int op2) => HighNarrowing((int)(op1 - op2), round: false); + + public static int SubtractHighNarrowingUpper(short[] op1, int[] op2, int[] op3, int i) => i < op1.Length ? op1[i] : SubtractHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static short SubtractRoundedHighNarrowing(int op1, int op2) => HighNarrowing((int)(op1 - op2), round: true); + + public static int SubtractRoundedHighNarrowingUpper(short[] op1, int[] op2, int[] op3, int i) => i < op1.Length ? op1[i] : SubtractRoundedHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static int SubtractWidening(short op1, short op2) => (int)((int)op1 - (int)op2); + + public static int SubtractWidening(int op1, short op2) => (int)(op1 - op2); + + public static int SubtractWideningUpper(short[] op1, short[] op2, int i) => SubtractWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static int SubtractWideningUpper(int[] op1, short[] op2, int i) => SubtractWidening(op1[i], op2[i + op2.Length / 2]); + + public static int ZeroExtendWidening(short op1) => (int)(uint)op1; + + public static int ZeroExtendWideningUpper(short[] op1, int i) => ZeroExtendWidening(op1[i + op1.Length / 2]); + + public static ulong AbsoluteDifferenceWidening(int op1, int op2) => op1 < op2 ? (ulong)(op2 - op1) : (ulong)(op1 - op2); + + public static ulong AbsoluteDifferenceWideningUpper(int[] op1, int[] op2, int i) => AbsoluteDifferenceWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static long AbsoluteDifferenceWideningAndAdd(long op1, int op2, int op3) => (long)(op1 + (long)AbsoluteDifferenceWidening(op2, op3)); + + public static long AbsoluteDifferenceWideningUpperAndAdd(long[] op1, int[] op2, int[] op3, int i) => AbsoluteDifferenceWideningAndAdd(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static long AddPairwiseWidening(int[] op1, int i) => AddWidening(op1[2 * i], op1[2 * i + 1]); + + public static long AddPairwiseWideningAndAdd(long[] op1, int[] op2, int i) => (long)(op1[i] + AddWidening(op2[2 * i], op2[2 * i + 1])); + + private static int HighNarrowing(long op1, bool round) + { + ulong roundConst = 0; + if (round) + { + roundConst = (ulong)1 << (8 * sizeof(int) - 1); + } + return (int)(((ulong)op1 + roundConst) >> (8 * sizeof(int))); + } + + public static int AddHighNarrowing(long op1, long op2) => HighNarrowing((long)(op1 + op2), round: false); + + public static int AddHighNarrowingUpper(int[] op1, long[] op2, long[] op3, int i) => i < op1.Length ? op1[i] : AddHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static int AddRoundedHighNarrowing(long op1, long op2) => HighNarrowing((long)(op1 + op2), round: true); + + public static long AddRoundedHighNarrowingUpper(int[] op1, long[] op2, long[] op3, int i) => i < op1.Length ? op1[i] : AddRoundedHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static long AddWidening(int op1, int op2) => (long)((long)op1 + (long)op2); + + public static long AddWidening(long op1, int op2) => (long)(op1 + op2); + + public static long AddWideningUpper(int[] op1, int[] op2, int i) => AddWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static long AddWideningUpper(long[] op1, int[] op2, int i) => AddWidening(op1[i], op2[i + op2.Length / 2]); + + public static int ExtractNarrowing(long op1) => (int)op1; + + public static int ExtractNarrowingUpper(int[] op1, long[] op2, int i) => i < op1.Length ? op1[i] : ExtractNarrowing(op2[i - op1.Length]); + + public static int FusedAddHalving(int op1, int op2) => (int)((ulong)((long)op1 + (long)op2) >> 1); + + public static int FusedAddRoundedHalving(int op1, int op2) => (int)((ulong)((long)op1 + (long)op2 + 1) >> 1); + + public static int FusedSubtractHalving(int op1, int op2) => (int)((ulong)((long)op1 - (long)op2) >> 1); + + public static long MultiplyWidening(int op1, int op2) => (long)((long)op1 * (long)op2); + + public static long MultiplyWideningAndAdd(long op1, int op2, int op3) => (long)(op1 + MultiplyWidening(op2, op3)); + + public static long MultiplyWideningAndSubtract(long op1, int op2, int op3) => (long)(op1 - MultiplyWidening(op2, op3)); + + public static long MultiplyWideningUpper(int[] op1, int[] op2, int i) => MultiplyWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static long MultiplyWideningUpperAndAdd(long[] op1, int[] op2, int[] op3, int i) => MultiplyWideningAndAdd(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static long MultiplyWideningUpperAndSubtract(long[] op1, int[] op2, int[] op3, int i) => MultiplyWideningAndSubtract(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static int SubtractHighNarrowing(long op1, long op2) => HighNarrowing((long)(op1 - op2), round: false); + + public static long SubtractHighNarrowingUpper(int[] op1, long[] op2, long[] op3, int i) => i < op1.Length ? op1[i] : SubtractHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static int SubtractRoundedHighNarrowing(long op1, long op2) => HighNarrowing((long)(op1 - op2), round: true); + + public static long SubtractRoundedHighNarrowingUpper(int[] op1, long[] op2, long[] op3, int i) => i < op1.Length ? op1[i] : SubtractRoundedHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static long SubtractWidening(int op1, int op2) => (long)((long)op1 - (long)op2); + + public static long SubtractWidening(long op1, int op2) => (long)(op1 - op2); + + public static long SubtractWideningUpper(int[] op1, int[] op2, int i) => SubtractWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static long SubtractWideningUpper(long[] op1, int[] op2, int i) => SubtractWidening(op1[i], op2[i + op2.Length / 2]); + + public static long ZeroExtendWidening(int op1) => (long)(ulong)op1; + + public static long ZeroExtendWideningUpper(int[] op1, int i) => ZeroExtendWidening(op1[i + op1.Length / 2]); + + public static ushort AbsoluteDifferenceWidening(byte op1, byte op2) => op1 < op2 ? (ushort)(op2 - op1) : (ushort)(op1 - op2); + + public static ushort AbsoluteDifferenceWideningUpper(byte[] op1, byte[] op2, int i) => AbsoluteDifferenceWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static ushort AbsoluteDifferenceWideningAndAdd(ushort op1, byte op2, byte op3) => (ushort)(op1 + (ushort)AbsoluteDifferenceWidening(op2, op3)); + + public static ushort AbsoluteDifferenceWideningUpperAndAdd(ushort[] op1, byte[] op2, byte[] op3, int i) => AbsoluteDifferenceWideningAndAdd(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static ushort AddPairwiseWidening(byte[] op1, int i) => AddWidening(op1[2 * i], op1[2 * i + 1]); + + public static ushort AddPairwiseWideningAndAdd(ushort[] op1, byte[] op2, int i) => (ushort)(op1[i] + AddWidening(op2[2 * i], op2[2 * i + 1])); + + private static byte HighNarrowing(ushort op1, bool round) + { + ushort roundConst = 0; + if (round) + { + roundConst = (ushort)1 << (8 * sizeof(byte) - 1); + } + return (byte)(((ushort)op1 + roundConst) >> (8 * sizeof(byte))); + } + + public static byte AddHighNarrowing(ushort op1, ushort op2) => HighNarrowing((ushort)(op1 + op2), round: false); + + public static byte AddHighNarrowingUpper(byte[] op1, ushort[] op2, ushort[] op3, int i) => i < op1.Length ? op1[i] : AddHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static byte AddRoundedHighNarrowing(ushort op1, ushort op2) => HighNarrowing((ushort)(op1 + op2), round: true); + + public static ushort AddRoundedHighNarrowingUpper(byte[] op1, ushort[] op2, ushort[] op3, int i) => i < op1.Length ? op1[i] : AddRoundedHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static ushort AddWidening(byte op1, byte op2) => (ushort)((ushort)op1 + (ushort)op2); + + public static ushort AddWidening(ushort op1, byte op2) => (ushort)(op1 + op2); + + public static ushort AddWideningUpper(byte[] op1, byte[] op2, int i) => AddWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static ushort AddWideningUpper(ushort[] op1, byte[] op2, int i) => AddWidening(op1[i], op2[i + op2.Length / 2]); + + public static byte ExtractNarrowing(ushort op1) => (byte)op1; + + public static byte ExtractNarrowingUpper(byte[] op1, ushort[] op2, int i) => i < op1.Length ? op1[i] : ExtractNarrowing(op2[i - op1.Length]); + + public static byte FusedAddHalving(byte op1, byte op2) => (byte)((ushort)((ushort)op1 + (ushort)op2) >> 1); + + public static byte FusedAddRoundedHalving(byte op1, byte op2) => (byte)((ushort)((ushort)op1 + (ushort)op2 + 1) >> 1); + + public static byte FusedSubtractHalving(byte op1, byte op2) => (byte)((ushort)((ushort)op1 - (ushort)op2) >> 1); + + public static ushort MultiplyWidening(byte op1, byte op2) => (ushort)((ushort)op1 * (ushort)op2); + + public static ushort MultiplyWideningAndAdd(ushort op1, byte op2, byte op3) => (ushort)(op1 + MultiplyWidening(op2, op3)); + + public static ushort MultiplyWideningAndSubtract(ushort op1, byte op2, byte op3) => (ushort)(op1 - MultiplyWidening(op2, op3)); + + public static ushort MultiplyWideningUpper(byte[] op1, byte[] op2, int i) => MultiplyWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static ushort MultiplyWideningUpperAndAdd(ushort[] op1, byte[] op2, byte[] op3, int i) => MultiplyWideningAndAdd(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static ushort MultiplyWideningUpperAndSubtract(ushort[] op1, byte[] op2, byte[] op3, int i) => MultiplyWideningAndSubtract(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static byte SubtractHighNarrowing(ushort op1, ushort op2) => HighNarrowing((ushort)(op1 - op2), round: false); + + public static ushort SubtractHighNarrowingUpper(byte[] op1, ushort[] op2, ushort[] op3, int i) => i < op1.Length ? op1[i] : SubtractHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static byte SubtractRoundedHighNarrowing(ushort op1, ushort op2) => HighNarrowing((ushort)(op1 - op2), round: true); + + public static ushort SubtractRoundedHighNarrowingUpper(byte[] op1, ushort[] op2, ushort[] op3, int i) => i < op1.Length ? op1[i] : SubtractRoundedHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static ushort SubtractWidening(byte op1, byte op2) => (ushort)((ushort)op1 - (ushort)op2); + + public static ushort SubtractWidening(ushort op1, byte op2) => (ushort)(op1 - op2); + + public static ushort SubtractWideningUpper(byte[] op1, byte[] op2, int i) => SubtractWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static ushort SubtractWideningUpper(ushort[] op1, byte[] op2, int i) => SubtractWidening(op1[i], op2[i + op2.Length / 2]); + + public static ushort ZeroExtendWidening(byte op1) => (ushort)(ushort)op1; + + public static ushort ZeroExtendWideningUpper(byte[] op1, int i) => ZeroExtendWidening(op1[i + op1.Length / 2]); + + public static uint AbsoluteDifferenceWidening(ushort op1, ushort op2) => op1 < op2 ? (uint)(op2 - op1) : (uint)(op1 - op2); + + public static uint AbsoluteDifferenceWideningUpper(ushort[] op1, ushort[] op2, int i) => AbsoluteDifferenceWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static uint AbsoluteDifferenceWideningAndAdd(uint op1, ushort op2, ushort op3) => (uint)(op1 + (uint)AbsoluteDifferenceWidening(op2, op3)); + + public static uint AbsoluteDifferenceWideningUpperAndAdd(uint[] op1, ushort[] op2, ushort[] op3, int i) => AbsoluteDifferenceWideningAndAdd(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static uint AddPairwiseWidening(ushort[] op1, int i) => AddWidening(op1[2 * i], op1[2 * i + 1]); + + public static uint AddPairwiseWideningAndAdd(uint[] op1, ushort[] op2, int i) => (uint)(op1[i] + AddWidening(op2[2 * i], op2[2 * i + 1])); + + private static ushort HighNarrowing(uint op1, bool round) + { + uint roundConst = 0; + if (round) + { + roundConst = (uint)1 << (8 * sizeof(ushort) - 1); + } + return (ushort)(((uint)op1 + roundConst) >> (8 * sizeof(ushort))); + } + + public static ushort AddHighNarrowing(uint op1, uint op2) => HighNarrowing((uint)(op1 + op2), round: false); + + public static ushort AddHighNarrowingUpper(ushort[] op1, uint[] op2, uint[] op3, int i) => i < op1.Length ? op1[i] : AddHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static ushort AddRoundedHighNarrowing(uint op1, uint op2) => HighNarrowing((uint)(op1 + op2), round: true); + + public static uint AddRoundedHighNarrowingUpper(ushort[] op1, uint[] op2, uint[] op3, int i) => i < op1.Length ? op1[i] : AddRoundedHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static uint AddWidening(ushort op1, ushort op2) => (uint)((uint)op1 + (uint)op2); + + public static uint AddWidening(uint op1, ushort op2) => (uint)(op1 + op2); + + public static uint AddWideningUpper(ushort[] op1, ushort[] op2, int i) => AddWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static uint AddWideningUpper(uint[] op1, ushort[] op2, int i) => AddWidening(op1[i], op2[i + op2.Length / 2]); + + public static ushort ExtractNarrowing(uint op1) => (ushort)op1; + + public static ushort ExtractNarrowingUpper(ushort[] op1, uint[] op2, int i) => i < op1.Length ? op1[i] : ExtractNarrowing(op2[i - op1.Length]); + + public static ushort FusedAddHalving(ushort op1, ushort op2) => (ushort)((uint)((uint)op1 + (uint)op2) >> 1); + + public static ushort FusedAddRoundedHalving(ushort op1, ushort op2) => (ushort)((uint)((uint)op1 + (uint)op2 + 1) >> 1); + + public static ushort FusedSubtractHalving(ushort op1, ushort op2) => (ushort)((uint)((uint)op1 - (uint)op2) >> 1); + + public static uint MultiplyWidening(ushort op1, ushort op2) => (uint)((uint)op1 * (uint)op2); + + public static uint MultiplyWideningAndAdd(uint op1, ushort op2, ushort op3) => (uint)(op1 + MultiplyWidening(op2, op3)); + + public static uint MultiplyWideningAndSubtract(uint op1, ushort op2, ushort op3) => (uint)(op1 - MultiplyWidening(op2, op3)); + + public static uint MultiplyWideningUpper(ushort[] op1, ushort[] op2, int i) => MultiplyWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static uint MultiplyWideningUpperAndAdd(uint[] op1, ushort[] op2, ushort[] op3, int i) => MultiplyWideningAndAdd(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static uint MultiplyWideningUpperAndSubtract(uint[] op1, ushort[] op2, ushort[] op3, int i) => MultiplyWideningAndSubtract(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static ushort SubtractHighNarrowing(uint op1, uint op2) => HighNarrowing((uint)(op1 - op2), round: false); + + public static uint SubtractHighNarrowingUpper(ushort[] op1, uint[] op2, uint[] op3, int i) => i < op1.Length ? op1[i] : SubtractHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static ushort SubtractRoundedHighNarrowing(uint op1, uint op2) => HighNarrowing((uint)(op1 - op2), round: true); + + public static uint SubtractRoundedHighNarrowingUpper(ushort[] op1, uint[] op2, uint[] op3, int i) => i < op1.Length ? op1[i] : SubtractRoundedHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static uint SubtractWidening(ushort op1, ushort op2) => (uint)((uint)op1 - (uint)op2); + + public static uint SubtractWidening(uint op1, ushort op2) => (uint)(op1 - op2); + + public static uint SubtractWideningUpper(ushort[] op1, ushort[] op2, int i) => SubtractWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static uint SubtractWideningUpper(uint[] op1, ushort[] op2, int i) => SubtractWidening(op1[i], op2[i + op2.Length / 2]); + + public static uint ZeroExtendWidening(ushort op1) => (uint)(uint)op1; + + public static uint ZeroExtendWideningUpper(ushort[] op1, int i) => ZeroExtendWidening(op1[i + op1.Length / 2]); + + public static ulong AbsoluteDifferenceWidening(uint op1, uint op2) => op1 < op2 ? (ulong)(op2 - op1) : (ulong)(op1 - op2); + + public static ulong AbsoluteDifferenceWideningUpper(uint[] op1, uint[] op2, int i) => AbsoluteDifferenceWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static ulong AbsoluteDifferenceWideningAndAdd(ulong op1, uint op2, uint op3) => (ulong)(op1 + (ulong)AbsoluteDifferenceWidening(op2, op3)); + + public static ulong AbsoluteDifferenceWideningUpperAndAdd(ulong[] op1, uint[] op2, uint[] op3, int i) => AbsoluteDifferenceWideningAndAdd(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static ulong AddPairwiseWidening(uint[] op1, int i) => AddWidening(op1[2 * i], op1[2 * i + 1]); + + public static ulong AddPairwiseWideningAndAdd(ulong[] op1, uint[] op2, int i) => (ulong)(op1[i] + AddWidening(op2[2 * i], op2[2 * i + 1])); + + private static uint HighNarrowing(ulong op1, bool round) + { + ulong roundConst = 0; + if (round) + { + roundConst = (ulong)1 << (8 * sizeof(uint) - 1); + } + return (uint)(((ulong)op1 + roundConst) >> (8 * sizeof(uint))); + } + + public static uint AddHighNarrowing(ulong op1, ulong op2) => HighNarrowing((ulong)(op1 + op2), round: false); + + public static uint AddHighNarrowingUpper(uint[] op1, ulong[] op2, ulong[] op3, int i) => i < op1.Length ? op1[i] : AddHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static uint AddRoundedHighNarrowing(ulong op1, ulong op2) => HighNarrowing((ulong)(op1 + op2), round: true); + + public static ulong AddRoundedHighNarrowingUpper(uint[] op1, ulong[] op2, ulong[] op3, int i) => i < op1.Length ? op1[i] : AddRoundedHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static ulong AddWidening(uint op1, uint op2) => (ulong)((ulong)op1 + (ulong)op2); + + public static ulong AddWidening(ulong op1, uint op2) => (ulong)(op1 + op2); + + public static ulong AddWideningUpper(uint[] op1, uint[] op2, int i) => AddWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static ulong AddWideningUpper(ulong[] op1, uint[] op2, int i) => AddWidening(op1[i], op2[i + op2.Length / 2]); + + public static uint ExtractNarrowing(ulong op1) => (uint)op1; + + public static uint ExtractNarrowingUpper(uint[] op1, ulong[] op2, int i) => i < op1.Length ? op1[i] : ExtractNarrowing(op2[i - op1.Length]); + + public static uint FusedAddHalving(uint op1, uint op2) => (uint)((ulong)((ulong)op1 + (ulong)op2) >> 1); + + public static uint FusedAddRoundedHalving(uint op1, uint op2) => (uint)((ulong)((ulong)op1 + (ulong)op2 + 1) >> 1); + + public static uint FusedSubtractHalving(uint op1, uint op2) => (uint)((ulong)((ulong)op1 - (ulong)op2) >> 1); + + public static ulong MultiplyWidening(uint op1, uint op2) => (ulong)((ulong)op1 * (ulong)op2); + + public static ulong MultiplyWideningAndAdd(ulong op1, uint op2, uint op3) => (ulong)(op1 + MultiplyWidening(op2, op3)); + + public static ulong MultiplyWideningAndSubtract(ulong op1, uint op2, uint op3) => (ulong)(op1 - MultiplyWidening(op2, op3)); + + public static ulong MultiplyWideningUpper(uint[] op1, uint[] op2, int i) => MultiplyWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static ulong MultiplyWideningUpperAndAdd(ulong[] op1, uint[] op2, uint[] op3, int i) => MultiplyWideningAndAdd(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static ulong MultiplyWideningUpperAndSubtract(ulong[] op1, uint[] op2, uint[] op3, int i) => MultiplyWideningAndSubtract(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static uint SubtractHighNarrowing(ulong op1, ulong op2) => HighNarrowing((ulong)(op1 - op2), round: false); + + public static ulong SubtractHighNarrowingUpper(uint[] op1, ulong[] op2, ulong[] op3, int i) => i < op1.Length ? op1[i] : SubtractHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static uint SubtractRoundedHighNarrowing(ulong op1, ulong op2) => HighNarrowing((ulong)(op1 - op2), round: true); + + public static ulong SubtractRoundedHighNarrowingUpper(uint[] op1, ulong[] op2, ulong[] op3, int i) => i < op1.Length ? op1[i] : SubtractRoundedHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static ulong SubtractWidening(uint op1, uint op2) => (ulong)((ulong)op1 - (ulong)op2); + + public static ulong SubtractWidening(ulong op1, uint op2) => (ulong)(op1 - op2); + + public static ulong SubtractWideningUpper(uint[] op1, uint[] op2, int i) => SubtractWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static ulong SubtractWideningUpper(ulong[] op1, uint[] op2, int i) => SubtractWidening(op1[i], op2[i + op2.Length / 2]); + + public static ulong ZeroExtendWidening(uint op1) => (ulong)(ulong)op1; + + public static ulong ZeroExtendWideningUpper(uint[] op1, int i) => ZeroExtendWidening(op1[i + op1.Length / 2]); + + private static bool SignedSatQ(short val, out sbyte result) + { + bool saturated = false; + + if (val > sbyte.MaxValue) + { + result = sbyte.MaxValue; + saturated = true; + } + else if (val < sbyte.MinValue) + { + result = sbyte.MinValue; + saturated = true; + } + else + { + result = (sbyte)val; + } + + return saturated; + } + + private static bool SignedSatQ(short val, out byte result) + { + bool saturated = false; + + if (val > byte.MaxValue) + { + result = byte.MaxValue; + saturated = true; + } + else if (val < 0) + { + result = 0; + saturated = true; + } + else + { + result = (byte)val; + } + + return saturated; + } + + private static bool UnsignedSatQ(short val, out sbyte result) + { + byte res; + + bool saturated = UnsignedSatQ((ushort)val, out res); + + result = (sbyte)res; + return saturated; + } + + private static bool UnsignedSatQ(ushort val, out byte result) + { + bool saturated = false; + + if (val > byte.MaxValue) + { + result = byte.MaxValue; + saturated = true; + } + else if (val < 0) + { + result = 0; + saturated = true; + } + else + { + result = (byte)val; + } + + return saturated; + } + + public static short ShiftLeftLogicalWidening(sbyte op1, byte op2) => UnsignedShift((short)op1, (short)op2); + + public static ushort ShiftLeftLogicalWidening(byte op1, byte op2) => UnsignedShift((ushort)op1, (short)op2); + + public static short ShiftLeftLogicalWideningUpper(sbyte[] op1, byte op2, int i) => ShiftLeftLogicalWidening(op1[i + op1.Length / 2], op2); + + public static ushort ShiftLeftLogicalWideningUpper(byte[] op1, byte op2, int i) => ShiftLeftLogicalWidening(op1[i + op1.Length / 2], op2); + + public static sbyte ShiftRightArithmeticRoundedNarrowingSaturate(short op1, byte op2) + { + sbyte result; + + SignedSatQ(SignedShift(op1, (short)(-op2), rounding: true), out result); + + return result; + } + + public static byte ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(short op1, byte op2) + { + byte result; + + SignedSatQ(SignedShift(op1, (short)(-op2), rounding: true), out result); + + return result; + } + + public static byte ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(byte[] op1, short[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (byte)ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(op2[i - op1.Length], op3); + + public static sbyte ShiftRightArithmeticRoundedNarrowingSaturateUpper(sbyte[] op1, short[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (sbyte)ShiftRightArithmeticRoundedNarrowingSaturate(op2[i - op1.Length], op3); + + public static sbyte ShiftRightArithmeticNarrowingSaturate(short op1, byte op2) + { + sbyte result; + + SignedSatQ(SignedShift(op1, (short)(-op2)), out result); + + return result; + } + + public static byte ShiftRightArithmeticNarrowingSaturateUnsigned(short op1, byte op2) + { + byte result; + + SignedSatQ(SignedShift(op1, (short)(-op2)), out result); + + return result; + } + + public static byte ShiftRightArithmeticNarrowingSaturateUnsignedUpper(byte[] op1, short[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (byte)ShiftRightArithmeticNarrowingSaturateUnsigned(op2[i - op1.Length], op3); + + public static sbyte ShiftRightArithmeticNarrowingSaturateUpper(sbyte[] op1, short[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (sbyte)ShiftRightArithmeticNarrowingSaturate(op2[i - op1.Length], op3); + + public static sbyte ShiftRightLogicalNarrowing(short op1, byte op2) => (sbyte)UnsignedShift(op1, (short)(-op2)); + + public static byte ShiftRightLogicalNarrowing(ushort op1, byte op2) => (byte)UnsignedShift(op1, (short)(-op2)); + + public static sbyte ShiftRightLogicalRoundedNarrowing(short op1, byte op2) => (sbyte)UnsignedShift(op1, (short)(-op2), rounding: true); + + public static byte ShiftRightLogicalRoundedNarrowing(ushort op1, byte op2) => (byte)UnsignedShift(op1, (short)(-op2), rounding: true); + + public static sbyte ShiftRightLogicalRoundedNarrowingUpper(sbyte[] op1, short[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (sbyte)ShiftRightLogicalRoundedNarrowing(op2[i - op1.Length], op3); + + public static byte ShiftRightLogicalRoundedNarrowingUpper(byte[] op1, ushort[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (byte)ShiftRightLogicalRoundedNarrowing(op2[i - op1.Length], op3); + + public static sbyte ShiftRightLogicalRoundedNarrowingSaturate(short op1, byte op2) + { + sbyte result; + + UnsignedSatQ(UnsignedShift(op1, (short)(-op2), rounding: true), out result); + + return result; + } + + public static byte ShiftRightLogicalRoundedNarrowingSaturate(ushort op1, byte op2) + { + byte result; + + UnsignedSatQ(UnsignedShift(op1, (short)(-op2), rounding: true), out result); + + return result; + } + + public static sbyte ShiftRightLogicalRoundedNarrowingSaturateUpper(sbyte[] op1, short[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (sbyte)ShiftRightLogicalRoundedNarrowingSaturate(op2[i - op1.Length], op3); + + public static byte ShiftRightLogicalRoundedNarrowingSaturateUpper(byte[] op1, ushort[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (byte)ShiftRightLogicalRoundedNarrowingSaturate(op2[i - op1.Length], op3); + + public static sbyte ShiftRightLogicalNarrowingUpper(sbyte[] op1, short[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (sbyte)ShiftRightLogicalNarrowing(op2[i - op1.Length], op3); + + public static byte ShiftRightLogicalNarrowingUpper(byte[] op1, ushort[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (byte)ShiftRightLogicalNarrowing(op2[i - op1.Length], op3); + + public static sbyte ShiftRightLogicalNarrowingSaturate(short op1, byte op2) + { + sbyte result; + + UnsignedSatQ(UnsignedShift(op1, (short)(-op2)), out result); + + return result; + } + + public static byte ShiftRightLogicalNarrowingSaturate(ushort op1, byte op2) + { + byte result; + + UnsignedSatQ(UnsignedShift(op1, (short)(-op2)), out result); + + return result; + } + + public static sbyte ShiftRightLogicalNarrowingSaturateUpper(sbyte[] op1, short[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (sbyte)ShiftRightLogicalNarrowingSaturate(op2[i - op1.Length], op3); + + public static byte ShiftRightLogicalNarrowingSaturateUpper(byte[] op1, ushort[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (byte)ShiftRightLogicalNarrowingSaturate(op2[i - op1.Length], op3); + + public static short SignExtendWidening(sbyte op1) => op1; + + public static short SignExtendWideningUpper(sbyte[] op1, int i) => SignExtendWidening(op1[i + op1.Length / 2]); + + private static bool SignedSatQ(int val, out short result) + { + bool saturated = false; + + if (val > short.MaxValue) + { + result = short.MaxValue; + saturated = true; + } + else if (val < short.MinValue) + { + result = short.MinValue; + saturated = true; + } + else + { + result = (short)val; + } + + return saturated; + } + + private static bool SignedSatQ(int val, out ushort result) + { + bool saturated = false; + + if (val > ushort.MaxValue) + { + result = ushort.MaxValue; + saturated = true; + } + else if (val < 0) + { + result = 0; + saturated = true; + } + else + { + result = (ushort)val; + } + + return saturated; + } + + private static bool UnsignedSatQ(int val, out short result) + { + ushort res; + + bool saturated = UnsignedSatQ((uint)val, out res); + + result = (short)res; + return saturated; + } + + private static bool UnsignedSatQ(uint val, out ushort result) + { + bool saturated = false; + + if (val > ushort.MaxValue) + { + result = ushort.MaxValue; + saturated = true; + } + else if (val < 0) + { + result = 0; + saturated = true; + } + else + { + result = (ushort)val; + } + + return saturated; + } + + public static int ShiftLeftLogicalWidening(short op1, byte op2) => UnsignedShift((int)op1, (int)op2); + + public static uint ShiftLeftLogicalWidening(ushort op1, byte op2) => UnsignedShift((uint)op1, (int)op2); + + public static int ShiftLeftLogicalWideningUpper(short[] op1, byte op2, int i) => ShiftLeftLogicalWidening(op1[i + op1.Length / 2], op2); + + public static uint ShiftLeftLogicalWideningUpper(ushort[] op1, byte op2, int i) => ShiftLeftLogicalWidening(op1[i + op1.Length / 2], op2); + + public static short ShiftRightArithmeticRoundedNarrowingSaturate(int op1, byte op2) + { + short result; + + SignedSatQ(SignedShift(op1, (int)(-op2), rounding: true), out result); + + return result; + } + + public static ushort ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(int op1, byte op2) + { + ushort result; + + SignedSatQ(SignedShift(op1, (int)(-op2), rounding: true), out result); + + return result; + } + + public static ushort ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(ushort[] op1, int[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (ushort)ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(op2[i - op1.Length], op3); + + public static short ShiftRightArithmeticRoundedNarrowingSaturateUpper(short[] op1, int[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (short)ShiftRightArithmeticRoundedNarrowingSaturate(op2[i - op1.Length], op3); + + public static short ShiftRightArithmeticNarrowingSaturate(int op1, byte op2) + { + short result; + + SignedSatQ(SignedShift(op1, (int)(-op2)), out result); + + return result; + } + + public static ushort ShiftRightArithmeticNarrowingSaturateUnsigned(int op1, byte op2) + { + ushort result; + + SignedSatQ(SignedShift(op1, (int)(-op2)), out result); + + return result; + } + + public static ushort ShiftRightArithmeticNarrowingSaturateUnsignedUpper(ushort[] op1, int[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (ushort)ShiftRightArithmeticNarrowingSaturateUnsigned(op2[i - op1.Length], op3); + + public static short ShiftRightArithmeticNarrowingSaturateUpper(short[] op1, int[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (short)ShiftRightArithmeticNarrowingSaturate(op2[i - op1.Length], op3); + + public static short ShiftRightLogicalNarrowing(int op1, byte op2) => (short)UnsignedShift(op1, (int)(-op2)); + + public static ushort ShiftRightLogicalNarrowing(uint op1, byte op2) => (ushort)UnsignedShift(op1, (int)(-op2)); + + public static short ShiftRightLogicalRoundedNarrowing(int op1, byte op2) => (short)UnsignedShift(op1, (int)(-op2), rounding: true); + + public static ushort ShiftRightLogicalRoundedNarrowing(uint op1, byte op2) => (ushort)UnsignedShift(op1, (int)(-op2), rounding: true); + + public static short ShiftRightLogicalRoundedNarrowingUpper(short[] op1, int[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (short)ShiftRightLogicalRoundedNarrowing(op2[i - op1.Length], op3); + + public static ushort ShiftRightLogicalRoundedNarrowingUpper(ushort[] op1, uint[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (ushort)ShiftRightLogicalRoundedNarrowing(op2[i - op1.Length], op3); + + public static short ShiftRightLogicalRoundedNarrowingSaturate(int op1, byte op2) + { + short result; + + UnsignedSatQ(UnsignedShift(op1, (int)(-op2), rounding: true), out result); + + return result; + } + + public static ushort ShiftRightLogicalRoundedNarrowingSaturate(uint op1, byte op2) + { + ushort result; + + UnsignedSatQ(UnsignedShift(op1, (int)(-op2), rounding: true), out result); + + return result; + } + + public static short ShiftRightLogicalRoundedNarrowingSaturateUpper(short[] op1, int[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (short)ShiftRightLogicalRoundedNarrowingSaturate(op2[i - op1.Length], op3); + + public static ushort ShiftRightLogicalRoundedNarrowingSaturateUpper(ushort[] op1, uint[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (ushort)ShiftRightLogicalRoundedNarrowingSaturate(op2[i - op1.Length], op3); + + public static short ShiftRightLogicalNarrowingUpper(short[] op1, int[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (short)ShiftRightLogicalNarrowing(op2[i - op1.Length], op3); + + public static ushort ShiftRightLogicalNarrowingUpper(ushort[] op1, uint[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (ushort)ShiftRightLogicalNarrowing(op2[i - op1.Length], op3); + + public static short ShiftRightLogicalNarrowingSaturate(int op1, byte op2) + { + short result; + + UnsignedSatQ(UnsignedShift(op1, (int)(-op2)), out result); + + return result; + } + + public static ushort ShiftRightLogicalNarrowingSaturate(uint op1, byte op2) + { + ushort result; + + UnsignedSatQ(UnsignedShift(op1, (int)(-op2)), out result); + + return result; + } + + public static short ShiftRightLogicalNarrowingSaturateUpper(short[] op1, int[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (short)ShiftRightLogicalNarrowingSaturate(op2[i - op1.Length], op3); + + public static ushort ShiftRightLogicalNarrowingSaturateUpper(ushort[] op1, uint[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (ushort)ShiftRightLogicalNarrowingSaturate(op2[i - op1.Length], op3); + + public static int SignExtendWidening(short op1) => op1; + + public static int SignExtendWideningUpper(short[] op1, int i) => SignExtendWidening(op1[i + op1.Length / 2]); + + private static bool SignedSatQ(long val, out int result) + { + bool saturated = false; + + if (val > int.MaxValue) + { + result = int.MaxValue; + saturated = true; + } + else if (val < int.MinValue) + { + result = int.MinValue; + saturated = true; + } + else + { + result = (int)val; + } + + return saturated; + } + + private static bool SignedSatQ(long val, out uint result) + { + bool saturated = false; + + if (val > uint.MaxValue) + { + result = uint.MaxValue; + saturated = true; + } + else if (val < 0) + { + result = 0; + saturated = true; + } + else + { + result = (uint)val; + } + + return saturated; + } + + private static bool UnsignedSatQ(long val, out int result) + { + uint res; + + bool saturated = UnsignedSatQ((ulong)val, out res); + + result = (int)res; + return saturated; + } + + private static bool UnsignedSatQ(ulong val, out uint result) + { + bool saturated = false; + + if (val > uint.MaxValue) + { + result = uint.MaxValue; + saturated = true; + } + else if (val < 0) + { + result = 0; + saturated = true; + } + else + { + result = (uint)val; + } + + return saturated; + } + + public static long ShiftLeftLogicalWidening(int op1, byte op2) => UnsignedShift((long)op1, (long)op2); + + public static ulong ShiftLeftLogicalWidening(uint op1, byte op2) => UnsignedShift((ulong)op1, (long)op2); + + public static long ShiftLeftLogicalWideningUpper(int[] op1, byte op2, int i) => ShiftLeftLogicalWidening(op1[i + op1.Length / 2], op2); + + public static ulong ShiftLeftLogicalWideningUpper(uint[] op1, byte op2, int i) => ShiftLeftLogicalWidening(op1[i + op1.Length / 2], op2); + + public static int ShiftRightArithmeticRoundedNarrowingSaturate(long op1, byte op2) + { + int result; + + SignedSatQ(SignedShift(op1, (long)(-op2), rounding: true), out result); + + return result; + } + + public static uint ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(long op1, byte op2) + { + uint result; + + SignedSatQ(SignedShift(op1, (long)(-op2), rounding: true), out result); + + return result; + } + + public static uint ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(uint[] op1, long[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (uint)ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(op2[i - op1.Length], op3); + + public static int ShiftRightArithmeticRoundedNarrowingSaturateUpper(int[] op1, long[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (int)ShiftRightArithmeticRoundedNarrowingSaturate(op2[i - op1.Length], op3); + + public static int ShiftRightArithmeticNarrowingSaturate(long op1, byte op2) + { + int result; + + SignedSatQ(SignedShift(op1, (long)(-op2)), out result); + + return result; + } + + public static uint ShiftRightArithmeticNarrowingSaturateUnsigned(long op1, byte op2) + { + uint result; + + SignedSatQ(SignedShift(op1, (long)(-op2)), out result); + + return result; + } + + public static uint ShiftRightArithmeticNarrowingSaturateUnsignedUpper(uint[] op1, long[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (uint)ShiftRightArithmeticNarrowingSaturateUnsigned(op2[i - op1.Length], op3); + + public static int ShiftRightArithmeticNarrowingSaturateUpper(int[] op1, long[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (int)ShiftRightArithmeticNarrowingSaturate(op2[i - op1.Length], op3); + + public static int ShiftRightLogicalNarrowing(long op1, byte op2) => (int)UnsignedShift(op1, (long)(-op2)); + + public static uint ShiftRightLogicalNarrowing(ulong op1, byte op2) => (uint)UnsignedShift(op1, (long)(-op2)); + + public static int ShiftRightLogicalRoundedNarrowing(long op1, byte op2) => (int)UnsignedShift(op1, (long)(-op2), rounding: true); + + public static uint ShiftRightLogicalRoundedNarrowing(ulong op1, byte op2) => (uint)UnsignedShift(op1, (long)(-op2), rounding: true); + + public static int ShiftRightLogicalRoundedNarrowingUpper(int[] op1, long[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (int)ShiftRightLogicalRoundedNarrowing(op2[i - op1.Length], op3); + + public static uint ShiftRightLogicalRoundedNarrowingUpper(uint[] op1, ulong[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (uint)ShiftRightLogicalRoundedNarrowing(op2[i - op1.Length], op3); + + public static int ShiftRightLogicalRoundedNarrowingSaturate(long op1, byte op2) + { + int result; + + UnsignedSatQ(UnsignedShift(op1, (long)(-op2), rounding: true), out result); + + return result; + } + + public static uint ShiftRightLogicalRoundedNarrowingSaturate(ulong op1, byte op2) + { + uint result; + + UnsignedSatQ(UnsignedShift(op1, (long)(-op2), rounding: true), out result); + + return result; + } + + public static int ShiftRightLogicalRoundedNarrowingSaturateUpper(int[] op1, long[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (int)ShiftRightLogicalRoundedNarrowingSaturate(op2[i - op1.Length], op3); + + public static uint ShiftRightLogicalRoundedNarrowingSaturateUpper(uint[] op1, ulong[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (uint)ShiftRightLogicalRoundedNarrowingSaturate(op2[i - op1.Length], op3); + + public static int ShiftRightLogicalNarrowingUpper(int[] op1, long[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (int)ShiftRightLogicalNarrowing(op2[i - op1.Length], op3); + + public static uint ShiftRightLogicalNarrowingUpper(uint[] op1, ulong[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (uint)ShiftRightLogicalNarrowing(op2[i - op1.Length], op3); + + public static int ShiftRightLogicalNarrowingSaturate(long op1, byte op2) + { + int result; + + UnsignedSatQ(UnsignedShift(op1, (long)(-op2)), out result); + + return result; + } + + public static uint ShiftRightLogicalNarrowingSaturate(ulong op1, byte op2) + { + uint result; + + UnsignedSatQ(UnsignedShift(op1, (long)(-op2)), out result); + + return result; + } + + public static int ShiftRightLogicalNarrowingSaturateUpper(int[] op1, long[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (int)ShiftRightLogicalNarrowingSaturate(op2[i - op1.Length], op3); + + public static uint ShiftRightLogicalNarrowingSaturateUpper(uint[] op1, ulong[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (uint)ShiftRightLogicalNarrowingSaturate(op2[i - op1.Length], op3); + + public static long SignExtendWidening(int op1) => op1; + + public static long SignExtendWideningUpper(int[] op1, int i) => SignExtendWidening(op1[i + op1.Length / 2]); + + public static sbyte ShiftArithmetic(sbyte op1, sbyte op2) => SignedShift(op1, op2); + + public static sbyte ShiftArithmeticRounded(sbyte op1, sbyte op2) => SignedShift(op1, op2, rounding: true); + + public static sbyte ShiftArithmeticSaturate(sbyte op1, sbyte op2) => SignedShift(op1, op2, saturating: true); + + public static sbyte ShiftArithmeticRoundedSaturate(sbyte op1, sbyte op2) => SignedShift(op1, op2, rounding: true, saturating: true); + + private static sbyte SignedShift(sbyte op1, sbyte op2, bool rounding = false, bool saturating = false) + { + int shift = (sbyte)(op2 & 0xFF); + + sbyte rndCns = 0; + + if (rounding) + { + bool ovf; + + (rndCns, ovf) = ShiftOvf((sbyte)1, -shift-1); + + if (ovf) + { + return 0; + } + } + + sbyte result; + + bool addOvf; + + (result, addOvf) = AddOvf(op1, rndCns); + + if (addOvf) + { + result = (sbyte)ShiftOvf((byte)result, shift).val; + } + else + { + bool shiftOvf; + + (result, shiftOvf) = ShiftOvf(result, shift); + + if (saturating) + { + if (shiftOvf) + { + result = sbyte.MaxValue; + } + } + } + + return result; + } + + public static sbyte ShiftLeftLogical(sbyte op1, byte op2) => UnsignedShift(op1, (sbyte)op2); + + public static byte ShiftLeftLogical(byte op1, byte op2) => UnsignedShift(op1, (sbyte)op2); + + public static sbyte ShiftLeftLogicalSaturate(sbyte op1, byte op2) => SignedShift(op1, (sbyte)op2, saturating: true); + + public static byte ShiftLeftLogicalSaturate(byte op1, byte op2) => UnsignedShift(op1, (sbyte)op2, saturating: true); + + public static byte ShiftLeftLogicalSaturateUnsigned(sbyte op1, byte op2) => (byte)UnsignedShift(op1, (sbyte)op2, saturating: true); + + public static sbyte ShiftLogical(sbyte op1, sbyte op2) => UnsignedShift(op1, op2); + + public static byte ShiftLogical(byte op1, sbyte op2) => UnsignedShift(op1, op2); + + public static byte ShiftLogicalRounded(byte op1, sbyte op2) => UnsignedShift(op1, op2, rounding: true); + + public static sbyte ShiftLogicalRounded(sbyte op1, sbyte op2) => UnsignedShift(op1, op2, rounding: true); + + public static byte ShiftLogicalRoundedSaturate(byte op1, sbyte op2) => UnsignedShift(op1, op2, rounding: true, saturating: true); + + public static sbyte ShiftLogicalRoundedSaturate(sbyte op1, sbyte op2) => UnsignedShift(op1, op2, rounding: true, saturating: true); + + public static sbyte ShiftLogicalSaturate(sbyte op1, sbyte op2) => UnsignedShift(op1, op2, saturating: true); + + public static byte ShiftLogicalSaturate(byte op1, sbyte op2) => UnsignedShift(op1, op2, saturating: true); + + public static sbyte ShiftRightArithmetic(sbyte op1, byte op2) => SignedShift(op1, (sbyte)(-op2)); + + public static sbyte ShiftRightArithmeticAdd(sbyte op1, sbyte op2, byte op3) => (sbyte)(op1 + ShiftRightArithmetic(op2, op3)); + + public static sbyte ShiftRightArithmeticRounded(sbyte op1, byte op2) => SignedShift(op1, (sbyte)(-op2), rounding: true); + + public static sbyte ShiftRightArithmeticRoundedAdd(sbyte op1, sbyte op2, byte op3) => (sbyte)(op1 + ShiftRightArithmeticRounded(op2, op3)); + + public static sbyte ShiftRightLogical(sbyte op1, byte op2) => UnsignedShift(op1, (sbyte)(-op2)); + + public static byte ShiftRightLogical(byte op1, byte op2) => UnsignedShift(op1, (sbyte)(-op2)); + + public static sbyte ShiftRightLogicalAdd(sbyte op1, sbyte op2, byte op3) => (sbyte)(op1 + ShiftRightLogical(op2, op3)); + + public static byte ShiftRightLogicalAdd(byte op1, byte op2, byte op3) => (byte)(op1 + ShiftRightLogical(op2, op3)); + + public static sbyte ShiftRightLogicalRounded(sbyte op1, byte op2) => UnsignedShift(op1, (sbyte)(-op2), rounding: true); + + public static byte ShiftRightLogicalRounded(byte op1, byte op2) => UnsignedShift(op1, (sbyte)(-op2), rounding: true); + + public static sbyte ShiftRightLogicalRoundedAdd(sbyte op1, sbyte op2, byte op3) => (sbyte)(op1 + ShiftRightLogicalRounded(op2, op3)); + + public static byte ShiftRightLogicalRoundedAdd(byte op1, byte op2, byte op3) => (byte)(op1 + ShiftRightLogicalRounded(op2, op3)); + + private static byte UnsignedShift(byte op1, sbyte op2, bool rounding = false, bool saturating = false) + { + int shift = (sbyte)(op2 & 0xFF); + + byte rndCns = 0; + + if (rounding) + { + bool ovf; + + (rndCns, ovf) = ShiftOvf((byte)1, -shift-1); + + if (ovf) + { + return 0; + } + } + + (byte result, bool addOvf) = AddOvf(op1, rndCns); + + bool shiftOvf; + + (result, shiftOvf) = ShiftOvf(result, shift); + + if (addOvf) + { + byte shiftedCarry = ShiftOvf((byte)1, 8 * sizeof(byte) + shift).val; + result = (byte)(result | shiftedCarry); + } + + if (saturating) + { + if (shiftOvf) + { + result = byte.MaxValue; + } + } + + return result; + } + + private static sbyte UnsignedShift(sbyte op1, sbyte op2, bool rounding = false, bool saturating = false) => (sbyte)UnsignedShift((byte)op1, op2, rounding, saturating); + + private static (sbyte val, bool ovf) AddOvf(sbyte op1, sbyte op2) + { + sbyte result = (sbyte)(op1 + op2); + + bool ovf = false; + + if ((op1 > 0) && (op2 > 0)) + { + ovf = (result < 0); + } + else if ((op1 < 0) && (op2 < 0)) + { + ovf = (result > 0); + } + + return (result, ovf); + } + + private static (byte val, bool ovf) AddOvf(byte op1, byte op2) + { + byte result = (byte)(op1 + op2); + + bool ovf = (result < op1); + + return (result, ovf); + } + + private static (sbyte val, bool ovf) SubtractOvf(sbyte op1, sbyte op2) + { + sbyte result = (sbyte)(op1 - op2); + + bool ovf = false; + + if ((op1 > 0) && (op2 < 0)) + { + ovf = (result < 0); + } + else if ((op1 < 0) && (op2 > 0)) + { + ovf = (result > 0); + } + + return (result, ovf); + } + + private static (byte val, bool ovf) SubtractOvf(byte op1, byte op2) + { + byte result = (byte)(op1 - op2); + + bool ovf = (op1 < op2); + + return (result, ovf); + } + + public static sbyte AddSaturate(sbyte op1, sbyte op2) + { + var (result, ovf) = AddOvf(op1, op2); + return ovf ? (result > 0 ? sbyte.MinValue : sbyte.MaxValue) : result; + } + + public static byte AddSaturate(byte op1, byte op2) + { + var (result, ovf) = AddOvf(op1, op2); + return ovf ? byte.MaxValue : result; + } + + public static sbyte SubtractSaturate(sbyte op1, sbyte op2) + { + var (result, ovf) = SubtractOvf(op1, op2); + return ovf ? (result > 0 ? sbyte.MinValue : sbyte.MaxValue) : result; + } + + public static byte SubtractSaturate(byte op1, byte op2) + { + var (result, ovf) = SubtractOvf(op1, op2); + return ovf ? byte.MinValue : result; + } + + public static short ShiftArithmetic(short op1, short op2) => SignedShift(op1, op2); + + public static short ShiftArithmeticRounded(short op1, short op2) => SignedShift(op1, op2, rounding: true); + + public static short ShiftArithmeticSaturate(short op1, short op2) => SignedShift(op1, op2, saturating: true); + + public static short ShiftArithmeticRoundedSaturate(short op1, short op2) => SignedShift(op1, op2, rounding: true, saturating: true); + + private static short SignedShift(short op1, short op2, bool rounding = false, bool saturating = false) + { + int shift = (sbyte)(op2 & 0xFF); + + short rndCns = 0; + + if (rounding) + { + bool ovf; + + (rndCns, ovf) = ShiftOvf((short)1, -shift-1); + + if (ovf) + { + return 0; + } + } + + short result; + + bool addOvf; + + (result, addOvf) = AddOvf(op1, rndCns); + + if (addOvf) + { + result = (short)ShiftOvf((ushort)result, shift).val; + } + else + { + bool shiftOvf; + + (result, shiftOvf) = ShiftOvf(result, shift); + + if (saturating) + { + if (shiftOvf) + { + result = short.MaxValue; + } + } + } + + return result; + } + + public static short ShiftLeftLogical(short op1, byte op2) => UnsignedShift(op1, (short)op2); + + public static ushort ShiftLeftLogical(ushort op1, byte op2) => UnsignedShift(op1, (short)op2); + + public static short ShiftLeftLogicalSaturate(short op1, byte op2) => SignedShift(op1, (short)op2, saturating: true); + + public static ushort ShiftLeftLogicalSaturate(ushort op1, byte op2) => UnsignedShift(op1, (short)op2, saturating: true); + + public static ushort ShiftLeftLogicalSaturateUnsigned(short op1, byte op2) => (ushort)UnsignedShift(op1, (short)op2, saturating: true); + + public static short ShiftLogical(short op1, short op2) => UnsignedShift(op1, op2); + + public static ushort ShiftLogical(ushort op1, short op2) => UnsignedShift(op1, op2); + + public static ushort ShiftLogicalRounded(ushort op1, short op2) => UnsignedShift(op1, op2, rounding: true); + + public static short ShiftLogicalRounded(short op1, short op2) => UnsignedShift(op1, op2, rounding: true); + + public static ushort ShiftLogicalRoundedSaturate(ushort op1, short op2) => UnsignedShift(op1, op2, rounding: true, saturating: true); + + public static short ShiftLogicalRoundedSaturate(short op1, short op2) => UnsignedShift(op1, op2, rounding: true, saturating: true); + + public static short ShiftLogicalSaturate(short op1, short op2) => UnsignedShift(op1, op2, saturating: true); + + public static ushort ShiftLogicalSaturate(ushort op1, short op2) => UnsignedShift(op1, op2, saturating: true); + + public static short ShiftRightArithmetic(short op1, byte op2) => SignedShift(op1, (short)(-op2)); + + public static short ShiftRightArithmeticAdd(short op1, short op2, byte op3) => (short)(op1 + ShiftRightArithmetic(op2, op3)); + + public static short ShiftRightArithmeticRounded(short op1, byte op2) => SignedShift(op1, (short)(-op2), rounding: true); + + public static short ShiftRightArithmeticRoundedAdd(short op1, short op2, byte op3) => (short)(op1 + ShiftRightArithmeticRounded(op2, op3)); + + public static short ShiftRightLogical(short op1, byte op2) => UnsignedShift(op1, (short)(-op2)); + + public static ushort ShiftRightLogical(ushort op1, byte op2) => UnsignedShift(op1, (short)(-op2)); + + public static short ShiftRightLogicalAdd(short op1, short op2, byte op3) => (short)(op1 + ShiftRightLogical(op2, op3)); + + public static ushort ShiftRightLogicalAdd(ushort op1, ushort op2, byte op3) => (ushort)(op1 + ShiftRightLogical(op2, op3)); + + public static short ShiftRightLogicalRounded(short op1, byte op2) => UnsignedShift(op1, (short)(-op2), rounding: true); + + public static ushort ShiftRightLogicalRounded(ushort op1, byte op2) => UnsignedShift(op1, (short)(-op2), rounding: true); + + public static short ShiftRightLogicalRoundedAdd(short op1, short op2, byte op3) => (short)(op1 + ShiftRightLogicalRounded(op2, op3)); + + public static ushort ShiftRightLogicalRoundedAdd(ushort op1, ushort op2, byte op3) => (ushort)(op1 + ShiftRightLogicalRounded(op2, op3)); + + private static ushort UnsignedShift(ushort op1, short op2, bool rounding = false, bool saturating = false) + { + int shift = (sbyte)(op2 & 0xFF); + + ushort rndCns = 0; + + if (rounding) + { + bool ovf; + + (rndCns, ovf) = ShiftOvf((ushort)1, -shift-1); + + if (ovf) + { + return 0; + } + } + + (ushort result, bool addOvf) = AddOvf(op1, rndCns); + + bool shiftOvf; + + (result, shiftOvf) = ShiftOvf(result, shift); + + if (addOvf) + { + ushort shiftedCarry = ShiftOvf((ushort)1, 8 * sizeof(ushort) + shift).val; + result = (ushort)(result | shiftedCarry); + } + + if (saturating) + { + if (shiftOvf) + { + result = ushort.MaxValue; + } + } + + return result; + } + + private static short UnsignedShift(short op1, short op2, bool rounding = false, bool saturating = false) => (short)UnsignedShift((ushort)op1, op2, rounding, saturating); + + private static (short val, bool ovf) AddOvf(short op1, short op2) + { + short result = (short)(op1 + op2); + + bool ovf = false; + + if ((op1 > 0) && (op2 > 0)) + { + ovf = (result < 0); + } + else if ((op1 < 0) && (op2 < 0)) + { + ovf = (result > 0); + } + + return (result, ovf); + } + + private static (ushort val, bool ovf) AddOvf(ushort op1, ushort op2) + { + ushort result = (ushort)(op1 + op2); + + bool ovf = (result < op1); + + return (result, ovf); + } + + private static (short val, bool ovf) SubtractOvf(short op1, short op2) + { + short result = (short)(op1 - op2); + + bool ovf = false; + + if ((op1 > 0) && (op2 < 0)) + { + ovf = (result < 0); + } + else if ((op1 < 0) && (op2 > 0)) + { + ovf = (result > 0); + } + + return (result, ovf); + } + + private static (ushort val, bool ovf) SubtractOvf(ushort op1, ushort op2) + { + ushort result = (ushort)(op1 - op2); + + bool ovf = (op1 < op2); + + return (result, ovf); + } + + public static short AddSaturate(short op1, short op2) + { + var (result, ovf) = AddOvf(op1, op2); + return ovf ? (result > 0 ? short.MinValue : short.MaxValue) : result; + } + + public static ushort AddSaturate(ushort op1, ushort op2) + { + var (result, ovf) = AddOvf(op1, op2); + return ovf ? ushort.MaxValue : result; + } + + public static short SubtractSaturate(short op1, short op2) + { + var (result, ovf) = SubtractOvf(op1, op2); + return ovf ? (result > 0 ? short.MinValue : short.MaxValue) : result; + } + + public static ushort SubtractSaturate(ushort op1, ushort op2) + { + var (result, ovf) = SubtractOvf(op1, op2); + return ovf ? ushort.MinValue : result; + } + + public static int ShiftArithmetic(int op1, int op2) => SignedShift(op1, op2); + + public static int ShiftArithmeticRounded(int op1, int op2) => SignedShift(op1, op2, rounding: true); + + public static int ShiftArithmeticSaturate(int op1, int op2) => SignedShift(op1, op2, saturating: true); + + public static int ShiftArithmeticRoundedSaturate(int op1, int op2) => SignedShift(op1, op2, rounding: true, saturating: true); + + private static int SignedShift(int op1, int op2, bool rounding = false, bool saturating = false) + { + int shift = (sbyte)(op2 & 0xFF); + + int rndCns = 0; + + if (rounding) + { + bool ovf; + + (rndCns, ovf) = ShiftOvf((int)1, -shift-1); + + if (ovf) + { + return 0; + } + } + + int result; + + bool addOvf; + + (result, addOvf) = AddOvf(op1, rndCns); + + if (addOvf) + { + result = (int)ShiftOvf((uint)result, shift).val; + } + else + { + bool shiftOvf; + + (result, shiftOvf) = ShiftOvf(result, shift); + + if (saturating) + { + if (shiftOvf) + { + result = int.MaxValue; + } + } + } + + return result; + } + + public static int ShiftLeftLogical(int op1, byte op2) => UnsignedShift(op1, (int)op2); + + public static uint ShiftLeftLogical(uint op1, byte op2) => UnsignedShift(op1, (int)op2); + + public static int ShiftLeftLogicalSaturate(int op1, byte op2) => SignedShift(op1, (int)op2, saturating: true); + + public static uint ShiftLeftLogicalSaturate(uint op1, byte op2) => UnsignedShift(op1, (int)op2, saturating: true); + + public static uint ShiftLeftLogicalSaturateUnsigned(int op1, byte op2) => (uint)UnsignedShift(op1, (int)op2, saturating: true); + + public static int ShiftLogical(int op1, int op2) => UnsignedShift(op1, op2); + + public static uint ShiftLogical(uint op1, int op2) => UnsignedShift(op1, op2); + + public static uint ShiftLogicalRounded(uint op1, int op2) => UnsignedShift(op1, op2, rounding: true); + + public static int ShiftLogicalRounded(int op1, int op2) => UnsignedShift(op1, op2, rounding: true); + + public static uint ShiftLogicalRoundedSaturate(uint op1, int op2) => UnsignedShift(op1, op2, rounding: true, saturating: true); + + public static int ShiftLogicalRoundedSaturate(int op1, int op2) => UnsignedShift(op1, op2, rounding: true, saturating: true); + + public static int ShiftLogicalSaturate(int op1, int op2) => UnsignedShift(op1, op2, saturating: true); + + public static uint ShiftLogicalSaturate(uint op1, int op2) => UnsignedShift(op1, op2, saturating: true); + + public static int ShiftRightArithmetic(int op1, byte op2) => SignedShift(op1, (int)(-op2)); + + public static int ShiftRightArithmeticAdd(int op1, int op2, byte op3) => (int)(op1 + ShiftRightArithmetic(op2, op3)); + + public static int ShiftRightArithmeticRounded(int op1, byte op2) => SignedShift(op1, (int)(-op2), rounding: true); + + public static int ShiftRightArithmeticRoundedAdd(int op1, int op2, byte op3) => (int)(op1 + ShiftRightArithmeticRounded(op2, op3)); + + public static int ShiftRightLogical(int op1, byte op2) => UnsignedShift(op1, (int)(-op2)); + + public static uint ShiftRightLogical(uint op1, byte op2) => UnsignedShift(op1, (int)(-op2)); + + public static int ShiftRightLogicalAdd(int op1, int op2, byte op3) => (int)(op1 + ShiftRightLogical(op2, op3)); + + public static uint ShiftRightLogicalAdd(uint op1, uint op2, byte op3) => (uint)(op1 + ShiftRightLogical(op2, op3)); + + public static int ShiftRightLogicalRounded(int op1, byte op2) => UnsignedShift(op1, (int)(-op2), rounding: true); + + public static uint ShiftRightLogicalRounded(uint op1, byte op2) => UnsignedShift(op1, (int)(-op2), rounding: true); + + public static int ShiftRightLogicalRoundedAdd(int op1, int op2, byte op3) => (int)(op1 + ShiftRightLogicalRounded(op2, op3)); + + public static uint ShiftRightLogicalRoundedAdd(uint op1, uint op2, byte op3) => (uint)(op1 + ShiftRightLogicalRounded(op2, op3)); + + private static uint UnsignedShift(uint op1, int op2, bool rounding = false, bool saturating = false) + { + int shift = (sbyte)(op2 & 0xFF); + + uint rndCns = 0; + + if (rounding) + { + bool ovf; + + (rndCns, ovf) = ShiftOvf((uint)1, -shift-1); + + if (ovf) + { + return 0; + } + } + + (uint result, bool addOvf) = AddOvf(op1, rndCns); + + bool shiftOvf; + + (result, shiftOvf) = ShiftOvf(result, shift); + + if (addOvf) + { + uint shiftedCarry = ShiftOvf((uint)1, 8 * sizeof(uint) + shift).val; + result = (uint)(result | shiftedCarry); + } + + if (saturating) + { + if (shiftOvf) + { + result = uint.MaxValue; + } + } + + return result; + } + + private static int UnsignedShift(int op1, int op2, bool rounding = false, bool saturating = false) => (int)UnsignedShift((uint)op1, op2, rounding, saturating); + + private static (int val, bool ovf) AddOvf(int op1, int op2) + { + int result = (int)(op1 + op2); + + bool ovf = false; + + if ((op1 > 0) && (op2 > 0)) + { + ovf = (result < 0); + } + else if ((op1 < 0) && (op2 < 0)) + { + ovf = (result > 0); + } + + return (result, ovf); + } + + private static (uint val, bool ovf) AddOvf(uint op1, uint op2) + { + uint result = (uint)(op1 + op2); + + bool ovf = (result < op1); + + return (result, ovf); + } + + private static (int val, bool ovf) SubtractOvf(int op1, int op2) + { + int result = (int)(op1 - op2); + + bool ovf = false; + + if ((op1 > 0) && (op2 < 0)) + { + ovf = (result < 0); + } + else if ((op1 < 0) && (op2 > 0)) + { + ovf = (result > 0); + } + + return (result, ovf); + } + + private static (uint val, bool ovf) SubtractOvf(uint op1, uint op2) + { + uint result = (uint)(op1 - op2); + + bool ovf = (op1 < op2); + + return (result, ovf); + } + + public static int AddSaturate(int op1, int op2) + { + var (result, ovf) = AddOvf(op1, op2); + return ovf ? (result > 0 ? int.MinValue : int.MaxValue) : result; + } + + public static uint AddSaturate(uint op1, uint op2) + { + var (result, ovf) = AddOvf(op1, op2); + return ovf ? uint.MaxValue : result; + } + + public static int SubtractSaturate(int op1, int op2) + { + var (result, ovf) = SubtractOvf(op1, op2); + return ovf ? (result > 0 ? int.MinValue : int.MaxValue) : result; + } + + public static uint SubtractSaturate(uint op1, uint op2) + { + var (result, ovf) = SubtractOvf(op1, op2); + return ovf ? uint.MinValue : result; + } + + public static long ShiftArithmetic(long op1, long op2) => SignedShift(op1, op2); + + public static long ShiftArithmeticRounded(long op1, long op2) => SignedShift(op1, op2, rounding: true); + + public static long ShiftArithmeticSaturate(long op1, long op2) => SignedShift(op1, op2, saturating: true); + + public static long ShiftArithmeticRoundedSaturate(long op1, long op2) => SignedShift(op1, op2, rounding: true, saturating: true); + + private static long SignedShift(long op1, long op2, bool rounding = false, bool saturating = false) + { + int shift = (sbyte)(op2 & 0xFF); + + long rndCns = 0; + + if (rounding) + { + bool ovf; + + (rndCns, ovf) = ShiftOvf((long)1, -shift-1); + + if (ovf) + { + return 0; + } + } + + long result; + + bool addOvf; + + (result, addOvf) = AddOvf(op1, rndCns); + + if (addOvf) + { + result = (long)ShiftOvf((ulong)result, shift).val; + } + else + { + bool shiftOvf; + + (result, shiftOvf) = ShiftOvf(result, shift); + + if (saturating) + { + if (shiftOvf) + { + result = long.MaxValue; + } + } + } + + return result; + } + + public static long ShiftLeftLogical(long op1, byte op2) => UnsignedShift(op1, (long)op2); + + public static ulong ShiftLeftLogical(ulong op1, byte op2) => UnsignedShift(op1, (long)op2); + + public static long ShiftLeftLogicalSaturate(long op1, byte op2) => SignedShift(op1, (long)op2, saturating: true); + + public static ulong ShiftLeftLogicalSaturate(ulong op1, byte op2) => UnsignedShift(op1, (long)op2, saturating: true); + + public static ulong ShiftLeftLogicalSaturateUnsigned(long op1, byte op2) => (ulong)UnsignedShift(op1, (long)op2, saturating: true); + + public static long ShiftLogical(long op1, long op2) => UnsignedShift(op1, op2); + + public static ulong ShiftLogical(ulong op1, long op2) => UnsignedShift(op1, op2); + + public static ulong ShiftLogicalRounded(ulong op1, long op2) => UnsignedShift(op1, op2, rounding: true); + + public static long ShiftLogicalRounded(long op1, long op2) => UnsignedShift(op1, op2, rounding: true); + + public static ulong ShiftLogicalRoundedSaturate(ulong op1, long op2) => UnsignedShift(op1, op2, rounding: true, saturating: true); + + public static long ShiftLogicalRoundedSaturate(long op1, long op2) => UnsignedShift(op1, op2, rounding: true, saturating: true); + + public static long ShiftLogicalSaturate(long op1, long op2) => UnsignedShift(op1, op2, saturating: true); + + public static ulong ShiftLogicalSaturate(ulong op1, long op2) => UnsignedShift(op1, op2, saturating: true); + + public static long ShiftRightArithmetic(long op1, byte op2) => SignedShift(op1, (long)(-op2)); + + public static long ShiftRightArithmeticAdd(long op1, long op2, byte op3) => (long)(op1 + ShiftRightArithmetic(op2, op3)); + + public static long ShiftRightArithmeticRounded(long op1, byte op2) => SignedShift(op1, (long)(-op2), rounding: true); + + public static long ShiftRightArithmeticRoundedAdd(long op1, long op2, byte op3) => (long)(op1 + ShiftRightArithmeticRounded(op2, op3)); + + public static long ShiftRightLogical(long op1, byte op2) => UnsignedShift(op1, (long)(-op2)); + + public static ulong ShiftRightLogical(ulong op1, byte op2) => UnsignedShift(op1, (long)(-op2)); + + public static long ShiftRightLogicalAdd(long op1, long op2, byte op3) => (long)(op1 + ShiftRightLogical(op2, op3)); + + public static ulong ShiftRightLogicalAdd(ulong op1, ulong op2, byte op3) => (ulong)(op1 + ShiftRightLogical(op2, op3)); + + public static long ShiftRightLogicalRounded(long op1, byte op2) => UnsignedShift(op1, (long)(-op2), rounding: true); + + public static ulong ShiftRightLogicalRounded(ulong op1, byte op2) => UnsignedShift(op1, (long)(-op2), rounding: true); + + public static long ShiftRightLogicalRoundedAdd(long op1, long op2, byte op3) => (long)(op1 + ShiftRightLogicalRounded(op2, op3)); + + public static ulong ShiftRightLogicalRoundedAdd(ulong op1, ulong op2, byte op3) => (ulong)(op1 + ShiftRightLogicalRounded(op2, op3)); + + private static ulong UnsignedShift(ulong op1, long op2, bool rounding = false, bool saturating = false) + { + int shift = (sbyte)(op2 & 0xFF); + + ulong rndCns = 0; + + if (rounding) + { + bool ovf; + + (rndCns, ovf) = ShiftOvf((ulong)1, -shift-1); + + if (ovf) + { + return 0; + } + } + + (ulong result, bool addOvf) = AddOvf(op1, rndCns); + + bool shiftOvf; + + (result, shiftOvf) = ShiftOvf(result, shift); + + if (addOvf) + { + ulong shiftedCarry = ShiftOvf((ulong)1, 8 * sizeof(ulong) + shift).val; + result = (ulong)(result | shiftedCarry); + } + + if (saturating) + { + if (shiftOvf) + { + result = ulong.MaxValue; + } + } + + return result; + } + + private static long UnsignedShift(long op1, long op2, bool rounding = false, bool saturating = false) => (long)UnsignedShift((ulong)op1, op2, rounding, saturating); + + private static (long val, bool ovf) AddOvf(long op1, long op2) + { + long result = (long)(op1 + op2); + + bool ovf = false; + + if ((op1 > 0) && (op2 > 0)) + { + ovf = (result < 0); + } + else if ((op1 < 0) && (op2 < 0)) + { + ovf = (result > 0); + } + + return (result, ovf); + } + + private static (ulong val, bool ovf) AddOvf(ulong op1, ulong op2) + { + ulong result = (ulong)(op1 + op2); + + bool ovf = (result < op1); + + return (result, ovf); + } + + private static (long val, bool ovf) SubtractOvf(long op1, long op2) + { + long result = (long)(op1 - op2); + + bool ovf = false; + + if ((op1 > 0) && (op2 < 0)) + { + ovf = (result < 0); + } + else if ((op1 < 0) && (op2 > 0)) + { + ovf = (result > 0); + } + + return (result, ovf); + } + + private static (ulong val, bool ovf) SubtractOvf(ulong op1, ulong op2) + { + ulong result = (ulong)(op1 - op2); + + bool ovf = (op1 < op2); + + return (result, ovf); + } + + public static long AddSaturate(long op1, long op2) + { + var (result, ovf) = AddOvf(op1, op2); + return ovf ? (result > 0 ? long.MinValue : long.MaxValue) : result; + } + + public static ulong AddSaturate(ulong op1, ulong op2) + { + var (result, ovf) = AddOvf(op1, op2); + return ovf ? ulong.MaxValue : result; + } + + public static long SubtractSaturate(long op1, long op2) + { + var (result, ovf) = SubtractOvf(op1, op2); + return ovf ? (result > 0 ? long.MinValue : long.MaxValue) : result; + } + + public static ulong SubtractSaturate(ulong op1, ulong op2) + { + var (result, ovf) = SubtractOvf(op1, op2); + return ovf ? ulong.MinValue : result; + } + + + private static (sbyte val, bool ovf) ShiftOvf(sbyte value, int shift) + { + sbyte result = value; + + bool ovf = false; + sbyte msb = 1; + msb = (sbyte)(msb << (8 * sizeof(sbyte) - 1)); + + for (int i = 0; i < shift; i++) + { + ovf = ovf || ((result & msb) != 0); + result <<= 1; + } + + for (int i = 0; i > shift; i--) + { + result >>= 1; + } + + if ((value > 0) && (result < 0)) + { + ovf = true; + } + + return (result, ovf); + } + + + + private static (byte val, bool ovf) ShiftOvf(byte value, int shift) + { + byte result = value; + + bool ovf = false; + byte msb = 1; + msb = (byte)(msb << (8 * sizeof(byte) - 1)); + + for (int i = 0; i < shift; i++) + { + ovf = ovf || ((result & msb) != 0); + result <<= 1; + } + + for (int i = 0; i > shift; i--) + { + result >>= 1; + } + + if ((value > 0) && (result < 0)) + { + ovf = true; + } + + return (result, ovf); + } + + + + private static (short val, bool ovf) ShiftOvf(short value, int shift) + { + short result = value; + + bool ovf = false; + short msb = 1; + msb = (short)(msb << (8 * sizeof(short) - 1)); + + for (int i = 0; i < shift; i++) + { + ovf = ovf || ((result & msb) != 0); + result <<= 1; + } + + for (int i = 0; i > shift; i--) + { + result >>= 1; + } + + if ((value > 0) && (result < 0)) + { + ovf = true; + } + + return (result, ovf); + } + + + + private static (ushort val, bool ovf) ShiftOvf(ushort value, int shift) + { + ushort result = value; + + bool ovf = false; + ushort msb = 1; + msb = (ushort)(msb << (8 * sizeof(ushort) - 1)); + + for (int i = 0; i < shift; i++) + { + ovf = ovf || ((result & msb) != 0); + result <<= 1; + } + + for (int i = 0; i > shift; i--) + { + result >>= 1; + } + + if ((value > 0) && (result < 0)) + { + ovf = true; + } + + return (result, ovf); + } + + + + private static (int val, bool ovf) ShiftOvf(int value, int shift) + { + int result = value; + + bool ovf = false; + int msb = 1; + msb = (int)(msb << (8 * sizeof(int) - 1)); + + for (int i = 0; i < shift; i++) + { + ovf = ovf || ((result & msb) != 0); + result <<= 1; + } + + for (int i = 0; i > shift; i--) + { + result >>= 1; + } + + if ((value > 0) && (result < 0)) + { + ovf = true; + } + + return (result, ovf); + } + + + + private static (uint val, bool ovf) ShiftOvf(uint value, int shift) + { + uint result = value; + + bool ovf = false; + uint msb = 1; + msb = (uint)(msb << (8 * sizeof(uint) - 1)); + + for (int i = 0; i < shift; i++) + { + ovf = ovf || ((result & msb) != 0); + result <<= 1; + } + + for (int i = 0; i > shift; i--) + { + result >>= 1; + } + + if ((value > 0) && (result < 0)) + { + ovf = true; + } + + return (result, ovf); + } + + + + private static (long val, bool ovf) ShiftOvf(long value, int shift) + { + long result = value; + + bool ovf = false; + long msb = 1; + msb = (long)(msb << (8 * sizeof(long) - 1)); + + for (int i = 0; i < shift; i++) + { + ovf = ovf || ((result & msb) != 0); + result <<= 1; + } + + for (int i = 0; i > shift; i--) + { + result >>= 1; + } + + if ((value > 0) && (result < 0)) + { + ovf = true; + } + + return (result, ovf); + } + + + + private static (ulong val, bool ovf) ShiftOvf(ulong value, int shift) + { + ulong result = value; + + bool ovf = false; + ulong msb = 1; + msb = (ulong)(msb << (8 * sizeof(ulong) - 1)); + + for (int i = 0; i < shift; i++) + { + ovf = ovf || ((result & msb) != 0); + result <<= 1; + } + + for (int i = 0; i > shift; i--) + { + result >>= 1; + } + + if ((value > 0) && (result < 0)) + { + ovf = true; + } + + return (result, ovf); + } + + public static float AbsoluteDifference(float op1, float op2) => MathF.Abs(op1 - op2); public static float FusedMultiplyAdd(float op1, float op2, float op3) => MathF.FusedMultiplyAdd(op2, op3, op1); @@ -2261,93 +4450,211 @@ private static double Reduce(Func reduceOp, double[] op1 public static float MinNumberAcross(float[] op1) => Reduce(MinNumber, op1); - private static ulong PolynomialMult(sbyte op1, sbyte op2) + private struct poly128_t { - ulong result = 0; - ulong extendedOp2 = (ulong)op2; + public ulong lo; + public ulong hi; - for (int i = 0; i < 8 * sizeof(sbyte); i++) + public static poly128_t operator ^(poly128_t op1, poly128_t op2) + { + op1.lo ^= op2.lo; + op1.hi ^= op2.hi; + + return op1; + } + + public static poly128_t operator <<(poly128_t val, int shiftAmount) { - if ((op1 & (1 << i)) != 0) + for (int i = 0; i < shiftAmount; i++) { - result ^= (extendedOp2 << i); + val.hi <<= 1; + + if ((val.lo & 0x8000000000000000U) != 0) + { + val.hi |= 1; + } + + val.lo <<= 1; } + + return val; } - return result; + public static implicit operator poly128_t(ulong lo) + { + poly128_t result = new poly128_t(); + result.lo = lo; + return result; + } + + public static explicit operator poly128_t(long lo) + { + poly128_t result = new poly128_t(); + result.lo = (ulong)lo; + return result; + } } - public static sbyte PolynomialMultiply(sbyte op1, sbyte op2) => (sbyte)PolynomialMult(op1, op2); - private static ulong PolynomialMult(byte op1, byte op2) + private static ushort PolynomialMult(byte op1, byte op2) { - ulong result = 0; - ulong extendedOp2 = (ulong)op2; + ushort result = default(ushort); + ushort extendedOp2 = (ushort)op2; for (int i = 0; i < 8 * sizeof(byte); i++) { - if ((op1 & (1 << i)) != 0) + if ((op1 & ((byte)1 << i)) != 0) { - result ^= (extendedOp2 << i); + result = (ushort)(result ^ (extendedOp2 << i)); } } return result; } - public static byte PolynomialMultiply(byte op1, byte op2) => (byte)PolynomialMult(op1, op2); - public static bool ExtractAndNarrowHigh(int i, sbyte[] left, - short[] right, - sbyte[] result) + private static short PolynomialMult(sbyte op1, sbyte op2) { - if (i < left.Length) - return left[i] != result[i]; - else - return (sbyte)right[i - left.Length] != result[i]; + short result = default(short); + short extendedOp2 = (short)op2; + + for (int i = 0; i < 8 * sizeof(sbyte); i++) + { + if ((op1 & ((sbyte)1 << i)) != 0) + { + result = (short)(result ^ (extendedOp2 << i)); + } + } + + return result; } - public static bool ExtractAndNarrowHigh(int i, short[] left, - int[] right, - short[] result) + + private static poly128_t PolynomialMult(ulong op1, ulong op2) { - if (i < left.Length) - return left[i] != result[i]; - else - return (short)right[i - left.Length] != result[i]; + poly128_t result = default(poly128_t); + poly128_t extendedOp2 = (poly128_t)op2; + + for (int i = 0; i < 8 * sizeof(ulong); i++) + { + if ((op1 & ((ulong)1 << i)) != 0) + { + result = (poly128_t)(result ^ (extendedOp2 << i)); + } + } + + return result; } - public static bool ExtractAndNarrowHigh(int i, int[] left, - long[] right, - int[] result) + + private static poly128_t PolynomialMult(long op1, long op2) { - if (i < left.Length) - return left[i] != result[i]; - else - return (int)right[i - left.Length] != result[i]; + poly128_t result = default(poly128_t); + poly128_t extendedOp2 = (poly128_t)op2; + + for (int i = 0; i < 8 * sizeof(long); i++) + { + if ((op1 & ((long)1 << i)) != 0) + { + result = (poly128_t)(result ^ (extendedOp2 << i)); + } + } + + return result; + } + + public static byte PolynomialMultiply(byte op1, byte op2) => (byte)PolynomialMult(op1, op2); + + public static ushort PolynomialMultiplyWidening(byte op1, byte op2) => PolynomialMult(op1, op2); + + public static ushort PolynomialMultiplyWideningUpper(byte[] op1, byte[] op2, int i) => PolynomialMultiplyWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static sbyte PolynomialMultiply(sbyte op1, sbyte op2) => (sbyte)PolynomialMult(op1, op2); + + public static short PolynomialMultiplyWidening(sbyte op1, sbyte op2) => PolynomialMult(op1, op2); + + public static short PolynomialMultiplyWideningUpper(sbyte[] op1, sbyte[] op2, int i) => PolynomialMultiplyWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static ulong PolynomialMultiplyWideningLo64(ulong op1, ulong op2) => PolynomialMult(op1, op2).lo; + + public static long PolynomialMultiplyWideningLo64(long op1, long op2) => (long)PolynomialMult(op1, op2).lo; + + public static ulong PolynomialMultiplyWideningHi64(ulong op1, ulong op2) => PolynomialMult(op1, op2).hi; + + public static long PolynomialMultiplyWideningHi64(long op1, long op2) => (long)PolynomialMult(op1, op2).hi; + + public static sbyte ExtractVector(sbyte[] op1, sbyte[] op2, int op3, int i) => (op3 + i < op1.Length) ? op1[op3 + i] : op2[op3 + i - op1.Length]; + + public static sbyte Insert(sbyte[] op1, int op2, sbyte op3, int i) => (op2 != i) ? op1[i] : op3; + + public static byte ExtractVector(byte[] op1, byte[] op2, int op3, int i) => (op3 + i < op1.Length) ? op1[op3 + i] : op2[op3 + i - op1.Length]; + + public static byte Insert(byte[] op1, int op2, byte op3, int i) => (op2 != i) ? op1[i] : op3; + + public static short ExtractVector(short[] op1, short[] op2, int op3, int i) => (op3 + i < op1.Length) ? op1[op3 + i] : op2[op3 + i - op1.Length]; + + public static short Insert(short[] op1, int op2, short op3, int i) => (op2 != i) ? op1[i] : op3; + + public static ushort ExtractVector(ushort[] op1, ushort[] op2, int op3, int i) => (op3 + i < op1.Length) ? op1[op3 + i] : op2[op3 + i - op1.Length]; + + public static ushort Insert(ushort[] op1, int op2, ushort op3, int i) => (op2 != i) ? op1[i] : op3; + + public static int ExtractVector(int[] op1, int[] op2, int op3, int i) => (op3 + i < op1.Length) ? op1[op3 + i] : op2[op3 + i - op1.Length]; + + public static int Insert(int[] op1, int op2, int op3, int i) => (op2 != i) ? op1[i] : op3; + + public static uint ExtractVector(uint[] op1, uint[] op2, int op3, int i) => (op3 + i < op1.Length) ? op1[op3 + i] : op2[op3 + i - op1.Length]; + + public static uint Insert(uint[] op1, int op2, uint op3, int i) => (op2 != i) ? op1[i] : op3; + + public static long ExtractVector(long[] op1, long[] op2, int op3, int i) => (op3 + i < op1.Length) ? op1[op3 + i] : op2[op3 + i - op1.Length]; + + public static long Insert(long[] op1, int op2, long op3, int i) => (op2 != i) ? op1[i] : op3; + + public static ulong ExtractVector(ulong[] op1, ulong[] op2, int op3, int i) => (op3 + i < op1.Length) ? op1[op3 + i] : op2[op3 + i - op1.Length]; + + public static ulong Insert(ulong[] op1, int op2, ulong op3, int i) => (op2 != i) ? op1[i] : op3; + + public static float ExtractVector(float[] op1, float[] op2, int op3, int i) => (op3 + i < op1.Length) ? op1[op3 + i] : op2[op3 + i - op1.Length]; + + public static float Insert(float[] op1, int op2, float op3, int i) => (op2 != i) ? op1[i] : op3; + + public static double ExtractVector(double[] op1, double[] op2, int op3, int i) => (op3 + i < op1.Length) ? op1[op3 + i] : op2[op3 + i - op1.Length]; + + public static double Insert(double[] op1, int op2, double op3, int i) => (op2 != i) ? op1[i] : op3; + + public static sbyte TableVectorExtension(int i, sbyte[] defaultValues, sbyte[] indices, params sbyte[][] table) + { + sbyte[] fullTable = table.SelectMany(x => x).ToArray(); + int index = indices[i]; + + if (index < 0 || index >= fullTable.Length) + return defaultValues[i]; + + return fullTable[index]; } - public static bool ExtractAndNarrowHigh(int i, byte[] left, - ushort[] right, - byte[] result) + + public static sbyte TableVectorLookup(int i, sbyte[] indices, params sbyte[][] table) { - if (i < left.Length) - return left[i] != result[i]; - else - return (byte)right[i - left.Length] != result[i]; + sbyte[] zeros = new sbyte[indices.Length]; + Array.Fill(zeros, 0, 0, indices.Length); + + return TableVectorExtension(i, zeros, indices, table); } - public static bool ExtractAndNarrowHigh(int i, ushort[] left, - uint[] right, - ushort[] result) + public static byte TableVectorExtension(int i, byte[] defaultValues, byte[] indices, params byte[][] table) { - if (i < left.Length) - return left[i] != result[i]; - else - return (ushort)right[i - left.Length] != result[i]; + byte[] fullTable = table.SelectMany(x => x).ToArray(); + int index = indices[i]; + + if (index < 0 || index >= fullTable.Length) + return defaultValues[i]; + + return fullTable[index]; } - public static bool ExtractAndNarrowHigh(int i, uint[] left, - ulong[] right, - uint[] result) + + public static byte TableVectorLookup(int i, byte[] indices, params byte[][] table) { - if (i < left.Length) - return left[i] != result[i]; - else - return (uint)right[i - left.Length] != result[i]; + byte[] zeros = new byte[indices.Length]; + Array.Fill(zeros, 0, 0, indices.Length); + + return TableVectorExtension(i, zeros, indices, table); } + } } diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.tt b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.tt index cc1d225742155f..9c50cda89e5921 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.tt +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/Helpers.tt @@ -10,6 +10,7 @@ // "%DevEnvDir%\TextTransform.exe" .\Helpers.tt using System; +using System.Linq; namespace JIT.HardwareIntrinsics.Arm { @@ -320,6 +321,566 @@ namespace JIT.HardwareIntrinsics.Arm public static <#= type.name #> AbsoluteDifferenceAdd(<#= type.name #> op1, <#= type.name #> op2, <#= type.name #> op3) => (<#= type.name #>)(op1 + AbsoluteDifference(op2, op3)); +<# + } + + foreach (var type in new[] { (name: "sbyte", wideUnsigned: "ushort", wide: "short"), + (name: "short", wideUnsigned: "uint", wide: "int"), + (name: "int", wideUnsigned: "ulong", wide: "long"), + (name: "byte", wideUnsigned: "ushort", wide: "ushort"), + (name: "ushort", wideUnsigned: "uint", wide: "uint"), + (name: "uint", wideUnsigned: "ulong", wide: "ulong") }) + { +#> + public static <#= type.wideUnsigned #> AbsoluteDifferenceWidening(<#= type.name #> op1, <#= type.name #> op2) => op1 < op2 ? (<#= type.wideUnsigned #>)(op2 - op1) : (<#= type.wideUnsigned #>)(op1 - op2); + + public static <#= type.wideUnsigned #> AbsoluteDifferenceWideningUpper(<#= type.name #>[] op1, <#= type.name #>[] op2, int i) => AbsoluteDifferenceWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static <#= type.wide #> AbsoluteDifferenceWideningAndAdd(<#= type.wide #> op1, <#= type.name #> op2, <#= type.name #> op3) => (<#= type.wide #>)(op1 + (<#= type.wide #>)AbsoluteDifferenceWidening(op2, op3)); + + public static <#= type.wide #> AbsoluteDifferenceWideningUpperAndAdd(<#= type.wide #>[] op1, <#= type.name #>[] op2, <#= type.name #>[] op3, int i) => AbsoluteDifferenceWideningAndAdd(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static <#= type.wide #> AddPairwiseWidening(<#= type.name #>[] op1, int i) => AddWidening(op1[2 * i], op1[2 * i + 1]); + + public static <#= type.wide #> AddPairwiseWideningAndAdd(<#= type.wide #>[] op1, <#= type.name #>[] op2, int i) => (<#= type.wide #>)(op1[i] + AddWidening(op2[2 * i], op2[2 * i + 1])); + + private static <#= type.name #> HighNarrowing(<#= type.wide #> op1, bool round) + { + <#= type.wideUnsigned #> roundConst = 0; + if (round) + { + roundConst = (<#= type.wideUnsigned #>)1 << (8 * sizeof(<#= type.name #>) - 1); + } + return (<#= type.name #>)(((<#= type.wideUnsigned #>)op1 + roundConst) >> (8 * sizeof(<#= type.name #>))); + } + + public static <#= type.name #> AddHighNarrowing(<#= type.wide #> op1, <#= type.wide #> op2) => HighNarrowing((<#= type.wide #>)(op1 + op2), round: false); + + public static <#= type.name #> AddHighNarrowingUpper(<#= type.name #>[] op1, <#= type.wide #>[] op2, <#= type.wide #>[] op3, int i) => i < op1.Length ? op1[i] : AddHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static <#= type.name #> AddRoundedHighNarrowing(<#= type.wide #> op1, <#= type.wide #> op2) => HighNarrowing((<#= type.wide #>)(op1 + op2), round: true); + + public static <#= type.wide #> AddRoundedHighNarrowingUpper(<#= type.name #>[] op1, <#= type.wide #>[] op2, <#= type.wide #>[] op3, int i) => i < op1.Length ? op1[i] : AddRoundedHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static <#= type.wide #> AddWidening(<#= type.name #> op1, <#= type.name #> op2) => (<#= type.wide #>)((<#= type.wide #>)op1 + (<#= type.wide #>)op2); + + public static <#= type.wide #> AddWidening(<#= type.wide #> op1, <#= type.name #> op2) => (<#= type.wide #>)(op1 + op2); + + public static <#= type.wide #> AddWideningUpper(<#= type.name #>[] op1, <#= type.name #>[] op2, int i) => AddWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static <#= type.wide #> AddWideningUpper(<#= type.wide #>[] op1, <#= type.name #>[] op2, int i) => AddWidening(op1[i], op2[i + op2.Length / 2]); + + public static <#= type.name #> ExtractNarrowing(<#= type.wide #> op1) => (<#= type.name #>)op1; + + public static <#= type.name #> ExtractNarrowingUpper(<#= type.name #>[] op1, <#= type.wide #>[] op2, int i) => i < op1.Length ? op1[i] : ExtractNarrowing(op2[i - op1.Length]); + + public static <#= type.name #> FusedAddHalving(<#= type.name #> op1, <#= type.name #> op2) => (<#= type.name #>)((<#= type.wideUnsigned #>)((<#= type.wide #>)op1 + (<#= type.wide #>)op2) >> 1); + + public static <#= type.name #> FusedAddRoundedHalving(<#= type.name #> op1, <#= type.name #> op2) => (<#= type.name #>)((<#= type.wideUnsigned #>)((<#= type.wide #>)op1 + (<#= type.wide #>)op2 + 1) >> 1); + + public static <#= type.name #> FusedSubtractHalving(<#= type.name #> op1, <#= type.name #> op2) => (<#= type.name #>)((<#= type.wideUnsigned #>)((<#= type.wide #>)op1 - (<#= type.wide #>)op2) >> 1); + + public static <#= type.wide #> MultiplyWidening(<#= type.name #> op1, <#= type.name #> op2) => (<#= type.wide #>)((<#= type.wide #>)op1 * (<#= type.wide #>)op2); + + public static <#= type.wide #> MultiplyWideningAndAdd(<#= type.wide #> op1, <#= type.name #> op2, <#= type.name #> op3) => (<#= type.wide #>)(op1 + MultiplyWidening(op2, op3)); + + public static <#= type.wide #> MultiplyWideningAndSubtract(<#= type.wide #> op1, <#= type.name #> op2, <#= type.name #> op3) => (<#= type.wide #>)(op1 - MultiplyWidening(op2, op3)); + + public static <#= type.wide #> MultiplyWideningUpper(<#= type.name #>[] op1, <#= type.name #>[] op2, int i) => MultiplyWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static <#= type.wide #> MultiplyWideningUpperAndAdd(<#= type.wide #>[] op1, <#= type.name #>[] op2, <#= type.name #>[] op3, int i) => MultiplyWideningAndAdd(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static <#= type.wide #> MultiplyWideningUpperAndSubtract(<#= type.wide #>[] op1, <#= type.name #>[] op2, <#= type.name #>[] op3, int i) => MultiplyWideningAndSubtract(op1[i], op2[i + op2.Length / 2], op3[i + op3.Length / 2]); + + public static <#= type.name #> SubtractHighNarrowing(<#= type.wide #> op1, <#= type.wide #> op2) => HighNarrowing((<#= type.wide #>)(op1 - op2), round: false); + + public static <#= type.wide #> SubtractHighNarrowingUpper(<#= type.name #>[] op1, <#= type.wide #>[] op2, <#= type.wide #>[] op3, int i) => i < op1.Length ? op1[i] : SubtractHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static <#= type.name #> SubtractRoundedHighNarrowing(<#= type.wide #> op1, <#= type.wide #> op2) => HighNarrowing((<#= type.wide #>)(op1 - op2), round: true); + + public static <#= type.wide #> SubtractRoundedHighNarrowingUpper(<#= type.name #>[] op1, <#= type.wide #>[] op2, <#= type.wide #>[] op3, int i) => i < op1.Length ? op1[i] : SubtractRoundedHighNarrowing(op2[i - op1.Length], op3[i - op1.Length]); + + public static <#= type.wide #> SubtractWidening(<#= type.name #> op1, <#= type.name #> op2) => (<#= type.wide #>)((<#= type.wide #>)op1 - (<#= type.wide #>)op2); + + public static <#= type.wide #> SubtractWidening(<#= type.wide #> op1, <#= type.name #> op2) => (<#= type.wide #>)(op1 - op2); + + public static <#= type.wide #> SubtractWideningUpper(<#= type.name #>[] op1, <#= type.name #>[] op2, int i) => SubtractWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + + public static <#= type.wide #> SubtractWideningUpper(<#= type.wide #>[] op1, <#= type.name #>[] op2, int i) => SubtractWidening(op1[i], op2[i + op2.Length / 2]); + + public static <#= type.wide #> ZeroExtendWidening(<#= type.name #> op1) => (<#= type.wide #>)(<#= type.wideUnsigned #>)op1; + + public static <#= type.wide #> ZeroExtendWideningUpper(<#= type.name #>[] op1, int i) => ZeroExtendWidening(op1[i + op1.Length / 2]); + +<# + } + + foreach (var type in new[] { (name: "sbyte", unsigned: "byte", wide: "short", wideUnsigned: "ushort"), + (name: "short", unsigned: "ushort", wide: "int", wideUnsigned: "uint"), + (name: "int", unsigned: "uint", wide: "long", wideUnsigned: "ulong") }) + { +#> + private static bool SignedSatQ(<#= type.wide #> val, out <#= type.name #> result) + { + bool saturated = false; + + if (val > <#= type.name #>.MaxValue) + { + result = <#= type.name #>.MaxValue; + saturated = true; + } + else if (val < <#= type.name #>.MinValue) + { + result = <#= type.name #>.MinValue; + saturated = true; + } + else + { + result = (<#= type.name #>)val; + } + + return saturated; + } + + private static bool SignedSatQ(<#= type.wide #> val, out <#= type.unsigned #> result) + { + bool saturated = false; + + if (val > <#= type.unsigned #>.MaxValue) + { + result = <#= type.unsigned #>.MaxValue; + saturated = true; + } + else if (val < 0) + { + result = 0; + saturated = true; + } + else + { + result = (<#= type.unsigned #>)val; + } + + return saturated; + } + + private static bool UnsignedSatQ(<#= type.wide #> val, out <#= type.name #> result) + { + <#= type.unsigned #> res; + + bool saturated = UnsignedSatQ((<#= type.wideUnsigned #>)val, out res); + + result = (<#= type.name #>)res; + return saturated; + } + + private static bool UnsignedSatQ(<#= type.wideUnsigned #> val, out <#= type.unsigned #> result) + { + bool saturated = false; + + if (val > <#= type.unsigned #>.MaxValue) + { + result = <#= type.unsigned #>.MaxValue; + saturated = true; + } + else if (val < 0) + { + result = 0; + saturated = true; + } + else + { + result = (<#= type.unsigned #>)val; + } + + return saturated; + } + + public static <#= type.wide #> ShiftLeftLogicalWidening(<#= type.name #> op1, byte op2) => UnsignedShift((<#= type.wide #>)op1, (<#= type.wide #>)op2); + + public static <#= type.wideUnsigned #> ShiftLeftLogicalWidening(<#= type.unsigned #> op1, byte op2) => UnsignedShift((<#= type.wideUnsigned #>)op1, (<#= type.wide #>)op2); + + public static <#= type.wide #> ShiftLeftLogicalWideningUpper(<#= type.name #>[] op1, byte op2, int i) => ShiftLeftLogicalWidening(op1[i + op1.Length / 2], op2); + + public static <#= type.wideUnsigned #> ShiftLeftLogicalWideningUpper(<#= type.unsigned #>[] op1, byte op2, int i) => ShiftLeftLogicalWidening(op1[i + op1.Length / 2], op2); + + public static <#= type.name #> ShiftRightArithmeticRoundedNarrowingSaturate(<#= type.wide #> op1, byte op2) + { + <#= type.name #> result; + + SignedSatQ(SignedShift(op1, (<#= type.wide #>)(-op2), rounding: true), out result); + + return result; + } + + public static <#= type.unsigned #> ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(<#= type.wide #> op1, byte op2) + { + <#= type.unsigned #> result; + + SignedSatQ(SignedShift(op1, (<#= type.wide #>)(-op2), rounding: true), out result); + + return result; + } + + public static <#= type.unsigned #> ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(<#= type.unsigned #>[] op1, <#= type.wide #>[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (<#= type.unsigned #>)ShiftRightArithmeticRoundedNarrowingSaturateUnsigned(op2[i - op1.Length], op3); + + public static <#= type.name #> ShiftRightArithmeticRoundedNarrowingSaturateUpper(<#= type.name #>[] op1, <#= type.wide #>[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (<#= type.name #>)ShiftRightArithmeticRoundedNarrowingSaturate(op2[i - op1.Length], op3); + + public static <#= type.name #> ShiftRightArithmeticNarrowingSaturate(<#= type.wide #> op1, byte op2) + { + <#= type.name #> result; + + SignedSatQ(SignedShift(op1, (<#= type.wide #>)(-op2)), out result); + + return result; + } + + public static <#= type.unsigned #> ShiftRightArithmeticNarrowingSaturateUnsigned(<#= type.wide #> op1, byte op2) + { + <#= type.unsigned #> result; + + SignedSatQ(SignedShift(op1, (<#= type.wide #>)(-op2)), out result); + + return result; + } + + public static <#= type.unsigned #> ShiftRightArithmeticNarrowingSaturateUnsignedUpper(<#= type.unsigned #>[] op1, <#= type.wide #>[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (<#= type.unsigned #>)ShiftRightArithmeticNarrowingSaturateUnsigned(op2[i - op1.Length], op3); + + public static <#= type.name #> ShiftRightArithmeticNarrowingSaturateUpper(<#= type.name #>[] op1, <#= type.wide #>[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (<#= type.name #>)ShiftRightArithmeticNarrowingSaturate(op2[i - op1.Length], op3); + + public static <#= type.name #> ShiftRightLogicalNarrowing(<#= type.wide #> op1, byte op2) => (<#= type.name #>)UnsignedShift(op1, (<#= type.wide #>)(-op2)); + + public static <#= type.unsigned #> ShiftRightLogicalNarrowing(<#= type.wideUnsigned #> op1, byte op2) => (<#= type.unsigned #>)UnsignedShift(op1, (<#= type.wide #>)(-op2)); + + public static <#= type.name #> ShiftRightLogicalRoundedNarrowing(<#= type.wide #> op1, byte op2) => (<#= type.name #>)UnsignedShift(op1, (<#= type.wide #>)(-op2), rounding: true); + + public static <#= type.unsigned #> ShiftRightLogicalRoundedNarrowing(<#= type.wideUnsigned #> op1, byte op2) => (<#= type.unsigned #>)UnsignedShift(op1, (<#= type.wide #>)(-op2), rounding: true); + + public static <#= type.name #> ShiftRightLogicalRoundedNarrowingUpper(<#= type.name #>[] op1, <#= type.wide #>[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (<#= type.name #>)ShiftRightLogicalRoundedNarrowing(op2[i - op1.Length], op3); + + public static <#= type.unsigned #> ShiftRightLogicalRoundedNarrowingUpper(<#= type.unsigned #>[] op1, <#= type.wideUnsigned #>[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (<#= type.unsigned #>)ShiftRightLogicalRoundedNarrowing(op2[i - op1.Length], op3); + + public static <#= type.name #> ShiftRightLogicalRoundedNarrowingSaturate(<#= type.wide #> op1, byte op2) + { + <#= type.name #> result; + + UnsignedSatQ(UnsignedShift(op1, (<#= type.wide #>)(-op2), rounding: true), out result); + + return result; + } + + public static <#= type.unsigned #> ShiftRightLogicalRoundedNarrowingSaturate(<#= type.wideUnsigned #> op1, byte op2) + { + <#= type.unsigned #> result; + + UnsignedSatQ(UnsignedShift(op1, (<#= type.wide #>)(-op2), rounding: true), out result); + + return result; + } + + public static <#= type.name #> ShiftRightLogicalRoundedNarrowingSaturateUpper(<#= type.name #>[] op1, <#= type.wide #>[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (<#= type.name #>)ShiftRightLogicalRoundedNarrowingSaturate(op2[i - op1.Length], op3); + + public static <#= type.unsigned #> ShiftRightLogicalRoundedNarrowingSaturateUpper(<#= type.unsigned #>[] op1, <#= type.wideUnsigned #>[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (<#= type.unsigned #>)ShiftRightLogicalRoundedNarrowingSaturate(op2[i - op1.Length], op3); + + public static <#= type.name #> ShiftRightLogicalNarrowingUpper(<#= type.name #>[] op1, <#= type.wide #>[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (<#= type.name #>)ShiftRightLogicalNarrowing(op2[i - op1.Length], op3); + + public static <#= type.unsigned #> ShiftRightLogicalNarrowingUpper(<#= type.unsigned #>[] op1, <#= type.wideUnsigned #>[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (<#= type.unsigned #>)ShiftRightLogicalNarrowing(op2[i - op1.Length], op3); + + public static <#= type.name #> ShiftRightLogicalNarrowingSaturate(<#= type.wide #> op1, byte op2) + { + <#= type.name #> result; + + UnsignedSatQ(UnsignedShift(op1, (<#= type.wide #>)(-op2)), out result); + + return result; + } + + public static <#= type.unsigned #> ShiftRightLogicalNarrowingSaturate(<#= type.wideUnsigned #> op1, byte op2) + { + <#= type.unsigned #> result; + + UnsignedSatQ(UnsignedShift(op1, (<#= type.wide #>)(-op2)), out result); + + return result; + } + + public static <#= type.name #> ShiftRightLogicalNarrowingSaturateUpper(<#= type.name #>[] op1, <#= type.wide #>[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (<#= type.name #>)ShiftRightLogicalNarrowingSaturate(op2[i - op1.Length], op3); + + public static <#= type.unsigned #> ShiftRightLogicalNarrowingSaturateUpper(<#= type.unsigned #>[] op1, <#= type.wideUnsigned #>[] op2, byte op3, int i) => i < op1.Length ? op1[i] : (<#= type.unsigned #>)ShiftRightLogicalNarrowingSaturate(op2[i - op1.Length], op3); + + public static <#= type.wide #> SignExtendWidening(<#= type.name #> op1) => op1; + + public static <#= type.wide #> SignExtendWideningUpper(<#= type.name #>[] op1, int i) => SignExtendWidening(op1[i + op1.Length / 2]); + +<# + } + + foreach (var type in new[] { (name: "sbyte", unsigned: "byte"), + (name: "short", unsigned: "ushort"), + (name: "int", unsigned: "uint"), + (name: "long", unsigned: "ulong") }) + { +#> + public static <#= type.name #> ShiftArithmetic(<#= type.name #> op1, <#= type.name #> op2) => SignedShift(op1, op2); + + public static <#= type.name #> ShiftArithmeticRounded(<#= type.name #> op1, <#= type.name #> op2) => SignedShift(op1, op2, rounding: true); + + public static <#= type.name #> ShiftArithmeticSaturate(<#= type.name #> op1, <#= type.name #> op2) => SignedShift(op1, op2, saturating: true); + + public static <#= type.name #> ShiftArithmeticRoundedSaturate(<#= type.name #> op1, <#= type.name #> op2) => SignedShift(op1, op2, rounding: true, saturating: true); + + private static <#= type.name #> SignedShift(<#= type.name #> op1, <#= type.name #> op2, bool rounding = false, bool saturating = false) + { + int shift = (sbyte)(op2 & 0xFF); + + <#= type.name #> rndCns = 0; + + if (rounding) + { + bool ovf; + + (rndCns, ovf) = ShiftOvf((<#= type.name #>)1, -shift-1); + + if (ovf) + { + return 0; + } + } + + <#= type.name #> result; + + bool addOvf; + + (result, addOvf) = AddOvf(op1, rndCns); + + if (addOvf) + { + result = (<#= type.name #>)ShiftOvf((<#= type.unsigned #>)result, shift).val; + } + else + { + bool shiftOvf; + + (result, shiftOvf) = ShiftOvf(result, shift); + + if (saturating) + { + if (shiftOvf) + { + result = <#= type.name #>.MaxValue; + } + } + } + + return result; + } + + public static <#= type.name #> ShiftLeftLogical(<#= type.name #> op1, byte op2) => UnsignedShift(op1, (<#= type.name #>)op2); + + public static <#= type.unsigned #> ShiftLeftLogical(<#= type.unsigned #> op1, byte op2) => UnsignedShift(op1, (<#= type.name #>)op2); + + public static <#= type.name #> ShiftLeftLogicalSaturate(<#= type.name #> op1, byte op2) => SignedShift(op1, (<#= type.name #>)op2, saturating: true); + + public static <#= type.unsigned #> ShiftLeftLogicalSaturate(<#= type.unsigned #> op1, byte op2) => UnsignedShift(op1, (<#= type.name #>)op2, saturating: true); + + public static <#= type.unsigned #> ShiftLeftLogicalSaturateUnsigned(<#= type.name #> op1, byte op2) => (<#= type.unsigned #>)UnsignedShift(op1, (<#= type.name #>)op2, saturating: true); + + public static <#= type.name #> ShiftLogical(<#= type.name #> op1, <#= type.name #> op2) => UnsignedShift(op1, op2); + + public static <#= type.unsigned #> ShiftLogical(<#= type.unsigned #> op1, <#= type.name #> op2) => UnsignedShift(op1, op2); + + public static <#= type.unsigned #> ShiftLogicalRounded(<#= type.unsigned #> op1, <#= type.name #> op2) => UnsignedShift(op1, op2, rounding: true); + + public static <#= type.name #> ShiftLogicalRounded(<#= type.name #> op1, <#= type.name #> op2) => UnsignedShift(op1, op2, rounding: true); + + public static <#= type.unsigned #> ShiftLogicalRoundedSaturate(<#= type.unsigned #> op1, <#= type.name #> op2) => UnsignedShift(op1, op2, rounding: true, saturating: true); + + public static <#= type.name #> ShiftLogicalRoundedSaturate(<#= type.name #> op1, <#= type.name #> op2) => UnsignedShift(op1, op2, rounding: true, saturating: true); + + public static <#= type.name #> ShiftLogicalSaturate(<#= type.name #> op1, <#= type.name #> op2) => UnsignedShift(op1, op2, saturating: true); + + public static <#= type.unsigned #> ShiftLogicalSaturate(<#= type.unsigned #> op1, <#= type.name #> op2) => UnsignedShift(op1, op2, saturating: true); + + public static <#= type.name #> ShiftRightArithmetic(<#= type.name #> op1, byte op2) => SignedShift(op1, (<#= type.name #>)(-op2)); + + public static <#= type.name #> ShiftRightArithmeticAdd(<#= type.name #> op1, <#= type.name #> op2, byte op3) => (<#= type.name #>)(op1 + ShiftRightArithmetic(op2, op3)); + + public static <#= type.name #> ShiftRightArithmeticRounded(<#= type.name #> op1, byte op2) => SignedShift(op1, (<#= type.name #>)(-op2), rounding: true); + + public static <#= type.name #> ShiftRightArithmeticRoundedAdd(<#= type.name #> op1, <#= type.name #> op2, byte op3) => (<#= type.name #>)(op1 + ShiftRightArithmeticRounded(op2, op3)); + + public static <#= type.name #> ShiftRightLogical(<#= type.name #> op1, byte op2) => UnsignedShift(op1, (<#= type.name #>)(-op2)); + + public static <#= type.unsigned #> ShiftRightLogical(<#= type.unsigned #> op1, byte op2) => UnsignedShift(op1, (<#= type.name #>)(-op2)); + + public static <#= type.name #> ShiftRightLogicalAdd(<#= type.name #> op1, <#= type.name #> op2, byte op3) => (<#= type.name #>)(op1 + ShiftRightLogical(op2, op3)); + + public static <#= type.unsigned #> ShiftRightLogicalAdd(<#= type.unsigned #> op1, <#= type.unsigned #> op2, byte op3) => (<#= type.unsigned #>)(op1 + ShiftRightLogical(op2, op3)); + + public static <#= type.name #> ShiftRightLogicalRounded(<#= type.name #> op1, byte op2) => UnsignedShift(op1, (<#= type.name #>)(-op2), rounding: true); + + public static <#= type.unsigned #> ShiftRightLogicalRounded(<#= type.unsigned #> op1, byte op2) => UnsignedShift(op1, (<#= type.name #>)(-op2), rounding: true); + + public static <#= type.name #> ShiftRightLogicalRoundedAdd(<#= type.name #> op1, <#= type.name #> op2, byte op3) => (<#= type.name #>)(op1 + ShiftRightLogicalRounded(op2, op3)); + + public static <#= type.unsigned #> ShiftRightLogicalRoundedAdd(<#= type.unsigned #> op1, <#= type.unsigned #> op2, byte op3) => (<#= type.unsigned #>)(op1 + ShiftRightLogicalRounded(op2, op3)); + + private static <#= type.unsigned #> UnsignedShift(<#= type.unsigned #> op1, <#= type.name #> op2, bool rounding = false, bool saturating = false) + { + int shift = (sbyte)(op2 & 0xFF); + + <#= type.unsigned #> rndCns = 0; + + if (rounding) + { + bool ovf; + + (rndCns, ovf) = ShiftOvf((<#= type.unsigned #>)1, -shift-1); + + if (ovf) + { + return 0; + } + } + + (<#= type.unsigned #> result, bool addOvf) = AddOvf(op1, rndCns); + + bool shiftOvf; + + (result, shiftOvf) = ShiftOvf(result, shift); + + if (addOvf) + { + <#= type.unsigned #> shiftedCarry = ShiftOvf((<#= type.unsigned #>)1, 8 * sizeof(<#= type.unsigned #>) + shift).val; + result = (<#= type.unsigned #>)(result | shiftedCarry); + } + + if (saturating) + { + if (shiftOvf) + { + result = <#= type.unsigned #>.MaxValue; + } + } + + return result; + } + + private static <#= type.name #> UnsignedShift(<#= type.name #> op1, <#= type.name #> op2, bool rounding = false, bool saturating = false) => (<#= type.name #>)UnsignedShift((<#= type.unsigned #>)op1, op2, rounding, saturating); + + private static (<#= type.name #> val, bool ovf) AddOvf(<#= type.name #> op1, <#= type.name #> op2) + { + <#= type.name #> result = (<#= type.name #>)(op1 + op2); + + bool ovf = false; + + if ((op1 > 0) && (op2 > 0)) + { + ovf = (result < 0); + } + else if ((op1 < 0) && (op2 < 0)) + { + ovf = (result > 0); + } + + return (result, ovf); + } + + private static (<#= type.unsigned #> val, bool ovf) AddOvf(<#= type.unsigned #> op1, <#= type.unsigned #> op2) + { + <#= type.unsigned #> result = (<#= type.unsigned #>)(op1 + op2); + + bool ovf = (result < op1); + + return (result, ovf); + } + + private static (<#= type.name #> val, bool ovf) SubtractOvf(<#= type.name #> op1, <#= type.name #> op2) + { + <#= type.name #> result = (<#= type.name #>)(op1 - op2); + + bool ovf = false; + + if ((op1 > 0) && (op2 < 0)) + { + ovf = (result < 0); + } + else if ((op1 < 0) && (op2 > 0)) + { + ovf = (result > 0); + } + + return (result, ovf); + } + + private static (<#= type.unsigned #> val, bool ovf) SubtractOvf(<#= type.unsigned #> op1, <#= type.unsigned #> op2) + { + <#= type.unsigned #> result = (<#= type.unsigned #>)(op1 - op2); + + bool ovf = (op1 < op2); + + return (result, ovf); + } + + public static <#= type.name #> AddSaturate(<#= type.name #> op1, <#= type.name #> op2) + { + var (result, ovf) = AddOvf(op1, op2); + return ovf ? (result > 0 ? <#= type.name #>.MinValue : <#= type.name #>.MaxValue) : result; + } + + public static <#= type.unsigned #> AddSaturate(<#= type.unsigned #> op1, <#= type.unsigned #> op2) + { + var (result, ovf) = AddOvf(op1, op2); + return ovf ? <#= type.unsigned #>.MaxValue : result; + } + + public static <#= type.name #> SubtractSaturate(<#= type.name #> op1, <#= type.name #> op2) + { + var (result, ovf) = SubtractOvf(op1, op2); + return ovf ? (result > 0 ? <#= type.name #>.MinValue : <#= type.name #>.MaxValue) : result; + } + + public static <#= type.unsigned #> SubtractSaturate(<#= type.unsigned #> op1, <#= type.unsigned #> op2) + { + var (result, ovf) = SubtractOvf(op1, op2); + return ovf ? <#= type.unsigned #>.MinValue : result; + } + +<# + } + + foreach (string typeName in new string[] { "sbyte", "byte", "short", "ushort", "int", "uint", "long", "ulong" }) + { +#> + + private static (<#= typeName #> val, bool ovf) ShiftOvf(<#= typeName #> value, int shift) + { + <#= typeName #> result = value; + + bool ovf = false; + <#= typeName #> msb = 1; + msb = (<#= typeName #>)(msb << (8 * sizeof(<#= typeName #>) - 1)); + + for (int i = 0; i < shift; i++) + { + ovf = ovf || ((result & msb) != 0); + result <<= 1; + } + + for (int i = 0; i > shift; i--) + { + result >>= 1; + } + + if ((value > 0) && (result < 0)) + { + ovf = true; + } + + return (result, ovf); + } + + <# } @@ -553,49 +1114,134 @@ namespace JIT.HardwareIntrinsics.Arm public static float MinNumberAcross(float[] op1) => Reduce(MinNumber, op1); + private struct poly128_t + { + public ulong lo; + public ulong hi; + + public static poly128_t operator ^(poly128_t op1, poly128_t op2) + { + op1.lo ^= op2.lo; + op1.hi ^= op2.hi; + + return op1; + } + + public static poly128_t operator <<(poly128_t val, int shiftAmount) + { + for (int i = 0; i < shiftAmount; i++) + { + val.hi <<= 1; + + if ((val.lo & 0x8000000000000000U) != 0) + { + val.hi |= 1; + } + + val.lo <<= 1; + } + + return val; + } + + public static implicit operator poly128_t(ulong lo) + { + poly128_t result = new poly128_t(); + result.lo = lo; + return result; + } + + public static explicit operator poly128_t(long lo) + { + poly128_t result = new poly128_t(); + result.lo = (ulong)lo; + return result; + } + } + <# - foreach (string typeName in new string[] { "sbyte", "byte" }) + foreach (var type in new[] { (name: "byte", wide: "ushort"), + (name: "sbyte", wide: "short"), + (name: "ulong", wide: "poly128_t"), + (name: "long", wide: "poly128_t") }) { #> - private static ulong PolynomialMult(<#= typeName #> op1, <#= typeName #> op2) + private static <#= type.wide #> PolynomialMult(<#= type.name #> op1, <#= type.name #> op2) { - ulong result = 0; - ulong extendedOp2 = (ulong)op2; + <#= type.wide #> result = default(<#= type.wide #>); + <#= type.wide #> extendedOp2 = (<#= type.wide #>)op2; - for (int i = 0; i < 8 * sizeof(<#= typeName #>); i++) + for (int i = 0; i < 8 * sizeof(<#= type.name #>); i++) { - if ((op1 & (1 << i)) != 0) + if ((op1 & ((<#= type.name #>)1 << i)) != 0) { - result ^= (extendedOp2 << i); + result = (<#= type.wide #>)(result ^ (extendedOp2 << i)); } } return result; } - public static <#= typeName #> PolynomialMultiply(<#= typeName #> op1, <#= typeName #> op2) => (<#= typeName #>)PolynomialMult(op1, op2); <# } - foreach (var type in new[] { (small: "sbyte", wide: "short"), - (small: "short", wide: "int"), - (small: "int", wide: "long"), - (small: "byte", wide: "ushort"), - (small: "ushort", wide: "uint"), - (small: "uint", wide: "ulong") }) + foreach (var type in new[] { (name: "byte", wide: "ushort"), + (name: "sbyte", wide: "short") }) { + #> - public static bool ExtractAndNarrowHigh(int i, <#= type.small #>[] left, - <#= type.wide #>[] right, - <#= type.small #>[] result) + public static <#= type.name #> PolynomialMultiply(<#= type.name #> op1, <#= type.name #> op2) => (<#= type.name #>)PolynomialMult(op1, op2); + + public static <#= type.wide #> PolynomialMultiplyWidening(<#= type.name #> op1, <#= type.name #> op2) => PolynomialMult(op1, op2); + + public static <#= type.wide #> PolynomialMultiplyWideningUpper(<#= type.name #>[] op1, <#= type.name #>[] op2, int i) => PolynomialMultiplyWidening(op1[i + op1.Length / 2], op2[i + op2.Length / 2]); + +<# + } +#> + public static ulong PolynomialMultiplyWideningLo64(ulong op1, ulong op2) => PolynomialMult(op1, op2).lo; + + public static long PolynomialMultiplyWideningLo64(long op1, long op2) => (long)PolynomialMult(op1, op2).lo; + + public static ulong PolynomialMultiplyWideningHi64(ulong op1, ulong op2) => PolynomialMult(op1, op2).hi; + + public static long PolynomialMultiplyWideningHi64(long op1, long op2) => (long)PolynomialMult(op1, op2).hi; + +<# + foreach (string typeName in new string[] { "sbyte", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "double" }) { - if (i < left.Length) - return left[i] != result[i]; - else - return (<#= type.small #>)right[i - left.Length] != result[i]; +#> + public static <#= typeName #> ExtractVector(<#= typeName #>[] op1, <#= typeName #>[] op2, int op3, int i) => (op3 + i < op1.Length) ? op1[op3 + i] : op2[op3 + i - op1.Length]; + + public static <#= typeName #> Insert(<#= typeName #>[] op1, int op2, <#= typeName #> op3, int i) => (op2 != i) ? op1[i] : op3; + +<# + } + + foreach (string typeName in new string[] { "sbyte", "byte" }) + { +#> + public static <#= typeName #> TableVectorExtension(int i, <#= typeName #>[] defaultValues, <#= typeName #>[] indices, params <#= typeName #>[][] table) + { + <#= typeName #>[] fullTable = table.SelectMany(x => x).ToArray(); + int index = indices[i]; + + if (index < 0 || index >= fullTable.Length) + return defaultValues[i]; + + return fullTable[index]; + } + + public static <#= typeName #> TableVectorLookup(int i, <#= typeName #>[] indices, params <#= typeName #>[][] table) + { + <#= typeName #>[] zeros = new <#= typeName #>[indices.Length]; + Array.Fill<<#= typeName #>>(zeros, 0, 0, indices.Length); + + return TableVectorExtension(i, zeros, indices, table); } <# } #> + } } diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/InsertTest.template b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/InsertTest.template new file mode 100644 index 00000000000000..7ca74920f0a32d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/InsertTest.template @@ -0,0 +1,532 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void {TestName}() + { + var test = new InsertTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class InsertTest__{TestName} + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable({Op1BaseType}[] inArray1, {RetBaseType}[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public {Op1VectorType}<{Op1BaseType}> _fld1; + public {Op1BaseType} _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + + testStruct._fld3 = {NextValueOp3}; + + return testStruct; + } + + public void RunStructFldScenario(InsertTest__{TestName} testClass) + { + var result = {Isa}.{Method}(_fld1, ElementIndex, _fld3); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(InsertTest__{TestName} testClass) + { + fixed ({Op1VectorType}<{Op1BaseType}>* pFld1 = &_fld1) + fixed ({Op1BaseType}* pFld3 = &_fld3) + { + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld3, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); + private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + private static readonly byte ElementIndex = {ElementIndex}; + + private static {Op1BaseType}[] _data1 = new {Op1BaseType}[Op1ElementCount]; + + private static {Op1VectorType}<{Op1BaseType}> _clsVar1; + private static {Op1BaseType} _clsVar3; + + private {Op1VectorType}<{Op1BaseType}> _fld1; + private {Op1BaseType} _fld3; + + private DataTable _dataTable; + + static InsertTest__{TestName}() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _clsVar1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + + _clsVar3 = {NextValueOp3}; + } + + public InsertTest__{TestName}() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + + _fld3 = {NextValueOp3}; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + _dataTable = new DataTable(_data1, new {RetBaseType}[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = {Isa}.{Method}( + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)), + ElementIndex, + _fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _fld3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + {Op1BaseType} op3 = {NextValueOp3}; + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof(byte), typeof({Op1BaseType}) }) + .Invoke(null, new object[] { + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + {Op1BaseType} op3 = {NextValueOp3}; + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof(byte), typeof({Op1BaseType}) }) + .Invoke(null, new object[] { + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)), + ElementIndex, + op3 + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, op3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = {Isa}.{Method}( + _clsVar1, + ElementIndex, + _clsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed ({Op1VectorType}<{Op1BaseType}>* pClsVar1 = &_clsVar1) + fixed ({Op1BaseType}* pClsVar3 = &_clsVar3) + { + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)pClsVar1), + ElementIndex, + *pClsVar3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar3, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr); + var op3 = {NextValueOp3}; + + var result = {Isa}.{Method}(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)); + var op3 = {NextValueOp3}; + + var result = {Isa}.{Method}(op1, ElementIndex, op3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, op3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new InsertTest__{TestName}(); + var result = {Isa}.{Method}(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new InsertTest__{TestName}(); + + fixed ({Op1VectorType}<{Op1BaseType}>* pFld1 = &test._fld1) + fixed ({Op1BaseType}* pFld3 = &test._fld3) + { + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = {Isa}.{Method}(_fld1, ElementIndex, _fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed ({Op1VectorType}<{Op1BaseType}>* pFld1 = &_fld1) + fixed ({Op1BaseType}* pFld3 = &_fld3) + { + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)pFld1), + ElementIndex, + *pFld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld3, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}(test._fld1, ElementIndex, test._fld3); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(&test._fld1)), + ElementIndex, + test._fld3 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld3, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult({Op1VectorType}<{Op1BaseType}> op1, {Op1BaseType} op3, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult(void* op1, {Op1BaseType} op3, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, op3, outArray, method); + } + + private void ValidateResult({Op1BaseType}[] firstOp, {Op1BaseType} thirdOp, {RetBaseType}[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + for (var i = 0; i < RetElementCount; i++) + { + if ({ValidateIterResult}) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>, {ElementIndex}, {Op1BaseType}): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" thirdOp: {thirdOp}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/_ImmBinaryOpTestTemplate.template b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/_ImmBinaryOpTestTemplate.template new file mode 100644 index 00000000000000..be123b5522add5 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/_ImmBinaryOpTestTemplate.template @@ -0,0 +1,409 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void {TestName}() + { + var test = new ImmBinaryOpTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ImmBinaryOpTest__{TestName} + { + private struct DataTable + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable({Op1BaseType}[] inArray1, {Op2BaseType}[] inArray2, {RetBaseType}[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf<{Op1BaseType}>(); + int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf<{Op2BaseType}>(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.inArray2 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), (uint)sizeOfinArray1); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), (uint)sizeOfinArray2); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public {Op1VectorType}<{Op1BaseType}> _fld1; + public {Op2VectorType}<{Op2BaseType}> _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref testStruct._fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + + return testStruct; + } + + public void RunStructFldScenario(ImmBinaryOpTest__{TestName} testClass) + { + var result = {Isa}.{Method}(_fld1, _fld2, {Imm}); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); + private static readonly int Op2ElementCount = Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>() / sizeof({Op2BaseType}); + private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + private static readonly byte Imm = {Imm}; + + private static {Op1BaseType}[] _data1 = new {Op1BaseType}[Op1ElementCount]; + private static {Op2BaseType}[] _data2 = new {Op2BaseType}[Op2ElementCount]; + + private static {Op1VectorType}<{Op1BaseType}> _clsVar1; + private static {Op2VectorType}<{Op2BaseType}> _clsVar2; + + private {Op1VectorType}<{Op1BaseType}> _fld1; + private {Op2VectorType}<{Op2BaseType}> _fld2; + + private DataTable _dataTable; + + static ImmBinaryOpTest__{TestName}() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _clsVar1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref _clsVar2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + } + + public ImmBinaryOpTest__{TestName}() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref _fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + _dataTable = new DataTable(_data1, _data2, new {RetBaseType}[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = {Isa}.{Method}( + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr), + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)), + {LoadIsa}.Load{Op2VectorType}(({Op2BaseType}*)(_dataTable.inArray2Ptr)), + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof({Op2VectorType}<{Op2BaseType}>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr), + (byte){Imm} + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof({Op2VectorType}<{Op2BaseType}>), typeof(byte) }) + .Invoke(null, new object[] { + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)), + {LoadIsa}.Load{Op2VectorType}(({Op2BaseType}*)(_dataTable.inArray2Ptr)), + (byte){Imm} + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = {Isa}.{Method}( + _clsVar1, + _clsVar2, + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr); + var secondOp = Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr); + var result = {Isa}.{Method}(firstOp, secondOp, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)); + var secondOp = {LoadIsa}.Load{Op2VectorType}(({Op2BaseType}*)(_dataTable.inArray2Ptr)); + var result = {Isa}.{Method}(firstOp, secondOp, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, secondOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ImmBinaryOpTest__{TestName}(); + var result = {Isa}.{Method}(test._fld1, test._fld2, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = {Isa}.{Method}(_fld1, _fld2, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}(test._fld1, test._fld2, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult({Op1VectorType}<{Op1BaseType}> firstOp, {Op2VectorType}<{Op2BaseType}> secondOp, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), firstOp); + Unsafe.WriteUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), secondOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* firstOp, void* secondOp, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), ref Unsafe.AsRef(secondOp), (uint)Unsafe.SizeOf<{Op2VectorType}<{Op2BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult({Op1BaseType}[] firstOp, {Op2BaseType}[] secondOp, {RetBaseType}[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + {TemplateValidationLogic} + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>.{Imm}, {Op2VectorType}<{Op2BaseType}>): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/_ImmOpTestTemplate.template b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/_ImmOpTestTemplate.template new file mode 100644 index 00000000000000..77a6503ac0c0f1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/_ImmOpTestTemplate.template @@ -0,0 +1,171 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void {TestName}() + { + var test = new {TemplateName}OpTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class {TemplateName}OpTest__{TestName} + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable({RetBaseType}[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + + private DataTable _dataTable; + + public {TemplateName}OpTest__{TestName}() + { + Succeeded = true; + + _dataTable = new DataTable(new {RetBaseType}[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + var result = {Isa}.{Method}( + ({Op1BaseType}){Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1BaseType}) }) + .Invoke(null, new object[] { + ({Op1BaseType}){Imm} + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(void* result, [CallerMemberName] string method = "") + { + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + ValidateResult(outArray, method); + } + + private void ValidateResult({RetBaseType}[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + {TemplateValidationLogic} + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Imm}): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/_ImmUnaryOpTestTemplate.template b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/_ImmUnaryOpTestTemplate.template new file mode 100644 index 00000000000000..a670c6e795d26a --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/_ImmUnaryOpTestTemplate.template @@ -0,0 +1,493 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void {TestName}() + { + var test = new {TemplateName}UnaryOpTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class {TemplateName}UnaryOpTest__{TestName} + { + private struct DataTable + { + private byte[] inArray; + private byte[] outArray; + + private GCHandle inHandle; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable({Op1BaseType}[] inArray, {RetBaseType}[] outArray, int alignment) + { + int sizeOfinArray = inArray.Length * Unsafe.SizeOf<{Op1BaseType}>(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As<{Op1BaseType}, byte>(ref inArray[0]), (uint)sizeOfinArray); + } + + public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public {Op1VectorType}<{Op1BaseType}> _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref testStruct._fld), ref Unsafe.As<{Op1BaseType}, byte>(ref _data[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + + return testStruct; + } + + public void RunStructFldScenario({TemplateName}UnaryOpTest__{TestName} testClass) + { + var result = {Isa}.{Method}(_fld, {Imm}); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load({TemplateName}UnaryOpTest__{TestName} testClass) + { + fixed ({Op1VectorType}<{Op1BaseType}>* pFld = &_fld) + { + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(pFld)), + {Imm} + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int Op1ElementCount = Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>() / sizeof({Op1BaseType}); + private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + private static readonly byte Imm = {Imm}; + + private static {Op1BaseType}[] _data = new {Op1BaseType}[Op1ElementCount]; + + private static {Op1VectorType}<{Op1BaseType}> _clsVar; + + private {Op1VectorType}<{Op1BaseType}> _fld; + + private DataTable _dataTable; + + static {TemplateName}UnaryOpTest__{TestName}() + { + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _clsVar), ref Unsafe.As<{Op1BaseType}, byte>(ref _data[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + } + + public {TemplateName}UnaryOpTest__{TestName}() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld), ref Unsafe.As<{Op1BaseType}, byte>(ref _data[0]), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = {NextValueOp1}; } + _dataTable = new DataTable(_data, new {RetBaseType}[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = {Isa}.{Method}( + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArrayPtr), + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArrayPtr)), + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArrayPtr), + (byte){Imm} + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof(byte) }) + .Invoke(null, new object[] { + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArrayPtr)), + (byte){Imm} + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = {Isa}.{Method}( + _clsVar, + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed ({Op1VectorType}<{Op1BaseType}>* pClsVar = &_clsVar) + { + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(pClsVar)), + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var firstOp = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArrayPtr); + var result = {Isa}.{Method}(firstOp, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var firstOp = {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArrayPtr)); + var result = {Isa}.{Method}(firstOp, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new {TemplateName}UnaryOpTest__{TestName}(); + var result = {Isa}.{Method}(test._fld, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new {TemplateName}UnaryOpTest__{TestName}(); + + fixed ({Op1VectorType}<{Op1BaseType}>* pFld = &test._fld) + { + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(pFld)), + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = {Isa}.{Method}(_fld, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed ({Op1VectorType}<{Op1BaseType}>* pFld = &_fld) + { + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(pFld)), + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}(test._fld, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(&test._fld)), + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult({Op1VectorType}<{Op1BaseType}> firstOp, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray = new {Op1BaseType}[Op1ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray = new {Op1BaseType}[Op1ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf<{Op1VectorType}<{Op1BaseType}>>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult({Op1BaseType}[] firstOp, {RetBaseType}[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + {TemplateValidationLogic} + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>, {Imm}): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/_UnaryOpScalarTestTemplate.template b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/_UnaryOpScalarTestTemplate.template new file mode 100644 index 00000000000000..b80651df1c8e3c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/Shared/_UnaryOpScalarTestTemplate.template @@ -0,0 +1,286 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; + +namespace JIT.HardwareIntrinsics.Arm +{ + public static partial class Program + { + private static void {TestName}() + { + var test = new {TemplateName}UnaryOpTest__{TestName}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class {TemplateName}UnaryOpTest__{TestName} + { + private struct DataTable + { + private byte[] outArray; + + private GCHandle outHandle; + + private ulong alignment; + + public DataTable({RetBaseType}[] outArray, int alignment) + { + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf<{RetBaseType}>(); + if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.outArray = new byte[alignment * 2]; + + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + } + + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public {Op1BaseType} _fld; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + testStruct._fld = {NextValueOp1}; + return testStruct; + } + + public void RunStructFldScenario({TemplateName}UnaryOpTest__{TestName} testClass) + { + var result = {Isa}.{Method}(_fld); + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int RetElementCount = Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>() / sizeof({RetBaseType}); + + private static {Op1BaseType} _data; + + private static {Op1BaseType} _clsVar; + + private {Op1BaseType} _fld; + + private DataTable _dataTable; + + static {TemplateName}UnaryOpTest__{TestName}() + { + _clsVar = {NextValueOp1}; + } + + public {TemplateName}UnaryOpTest__{TestName}() + { + Succeeded = true; + + _fld = {NextValueOp1}; + _data = {NextValueOp1}; + + _dataTable = new DataTable(new {RetBaseType}[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = {Isa}.{Method}( + Unsafe.ReadUnaligned<{Op1BaseType}>(ref Unsafe.As<{Op1BaseType}, byte>(ref _data)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1BaseType}) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned<{Op1BaseType}>(ref Unsafe.As<{Op1BaseType}, byte>(ref _data)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_data, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = {Isa}.{Method}( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data = Unsafe.ReadUnaligned<{Op1BaseType}>(ref Unsafe.As<{Op1BaseType}, byte>(ref _data)); + var result = {Isa}.{Method}(data); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(data, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new {TemplateName}UnaryOpTest__{TestName}(); + var result = {Isa}.{Method}(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = {Isa}.{Method}(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult({Op1BaseType} data, void* result, [CallerMemberName] string method = "") + { + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf<{RetVectorType}<{RetBaseType}>>()); + ValidateResult(data, outArray, method); + } + + private void ValidateResult({Op1BaseType} data, {RetBaseType}[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + {TemplateValidationLogic} + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1BaseType}): {Method} failed:"); + TestLibrary.TestFramework.LogInformation($" data: {data}"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/NotSupported_r.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/NotSupported_r.csproj index 3b3af6e21a358f..2e1ffa2dcc1c7d 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/NotSupported_r.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/NotSupported_r.csproj @@ -8,139 +8,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/NotSupported_ro.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/NotSupported_ro.csproj index 87ee4e09b85d82..91f1f64aec297a 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/NotSupported_ro.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/NotSupported_ro.csproj @@ -8,139 +8,7 @@ True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/Program.NotSupported.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/Program.NotSupported.cs index 8c6ac230471a83..f38e804f14ce2c 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/Program.NotSupported.cs +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/Program.NotSupported.cs @@ -13,6 +13,7 @@ static Program() { TestList = new Dictionary() { ["Vector64Zero"] = Vector64Zero, + ["Vector64AllBitsSet"] = Vector64AllBitsSet, ["Vector64BooleanAsGeneric_Boolean"] = Vector64BooleanAsGeneric_Boolean, ["Vector64ByteAsGeneric_Boolean"] = Vector64ByteAsGeneric_Boolean, ["Vector64DoubleAsGeneric_Boolean"] = Vector64DoubleAsGeneric_Boolean, @@ -55,6 +56,7 @@ static Program() ["Vector64ToVector128Unsafe"] = Vector64ToVector128Unsafe, ["Vector64ToString"] = Vector64ToString, ["Vector128Zero"] = Vector128Zero, + ["Vector128AllBitsSet"] = Vector128AllBitsSet, ["Vector128BooleanAsGeneric_Boolean"] = Vector128BooleanAsGeneric_Boolean, ["Vector128ByteAsGeneric_Boolean"] = Vector128ByteAsGeneric_Boolean, ["Vector128DoubleAsGeneric_Boolean"] = Vector128DoubleAsGeneric_Boolean, @@ -101,6 +103,7 @@ static Program() ["Vector128ToVector256Unsafe"] = Vector128ToVector256Unsafe, ["Vector128ToString"] = Vector128ToString, ["Vector256Zero"] = Vector256Zero, + ["Vector256AllBitsSet"] = Vector256AllBitsSet, ["Vector256BooleanAsGeneric_Boolean"] = Vector256BooleanAsGeneric_Boolean, ["Vector256ByteAsGeneric_Boolean"] = Vector256ByteAsGeneric_Boolean, ["Vector256DoubleAsGeneric_Boolean"] = Vector256DoubleAsGeneric_Boolean, diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/Vector128AllBitsSet.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/Vector128AllBitsSet.cs new file mode 100644 index 00000000000000..5c8d18bfdecc3d --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/Vector128AllBitsSet.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void Vector128AllBitsSet() + { + bool succeeded = false; + + try + { + Vector128 result = Vector128.AllBitsSet; + } + catch (NotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector128AllBitsSet: RunNotSupportedScenario failed to throw NotSupportedException."); + TestLibrary.TestFramework.LogInformation(string.Empty); + + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/Vector256AllBitsSet.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/Vector256AllBitsSet.cs new file mode 100644 index 00000000000000..62a00dc431d08b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/Vector256AllBitsSet.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void Vector256AllBitsSet() + { + bool succeeded = false; + + try + { + Vector256 result = Vector256.AllBitsSet; + } + catch (NotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector256AllBitsSet: RunNotSupportedScenario failed to throw NotSupportedException."); + TestLibrary.TestFramework.LogInformation(string.Empty); + + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/Vector64AllBitsSet.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/Vector64AllBitsSet.cs new file mode 100644 index 00000000000000..c9faf62832bf06 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/NotSupported/Vector64AllBitsSet.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void Vector64AllBitsSet() + { + bool succeeded = false; + + try + { + Vector64 result = Vector64.AllBitsSet; + } + catch (NotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector64AllBitsSet: RunNotSupportedScenario failed to throw NotSupportedException."); + TestLibrary.TestFramework.LogInformation(string.Empty); + + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Shared/GenerateTests.csx b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Shared/GenerateTests.csx index 13a54c590e16b0..a2ba1d07e299fd 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Shared/GenerateTests.csx +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Shared/GenerateTests.csx @@ -67,6 +67,17 @@ private static readonly (string templateFileName, Dictionary tem ("VectorZeroTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "Zero", ["VectorType"] = "Vector64", ["BaseType"] = "UInt16", ["LargestVectorSize"] = "8" }), ("VectorZeroTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "Zero", ["VectorType"] = "Vector64", ["BaseType"] = "UInt32", ["LargestVectorSize"] = "8" }), ("VectorZeroTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "Zero", ["VectorType"] = "Vector64", ["BaseType"] = "UInt64", ["LargestVectorSize"] = "8" }), + + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector64", ["BaseType"] = "Byte", ["LargestVectorSize"] = "8" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector64", ["BaseType"] = "Double", ["LargestVectorSize"] = "8" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector64", ["BaseType"] = "Int16", ["LargestVectorSize"] = "8" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector64", ["BaseType"] = "Int32", ["LargestVectorSize"] = "8" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector64", ["BaseType"] = "Int64", ["LargestVectorSize"] = "8" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector64", ["BaseType"] = "SByte", ["LargestVectorSize"] = "8" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector64", ["BaseType"] = "Single", ["LargestVectorSize"] = "8" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector64", ["BaseType"] = "UInt16", ["LargestVectorSize"] = "8" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector64", ["BaseType"] = "UInt32", ["LargestVectorSize"] = "8" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector64", ["BaseType"] = "UInt64", ["LargestVectorSize"] = "8" }), ("VectorAsTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "As", ["VectorType"] = "Vector64", ["BaseType"] = "Byte", ["LargestVectorSize"] = "8", ["NextValueOp"] = "TestLibrary.Generator.GetByte()" }), ("VectorAsTest.template", new Dictionary { ["Isa"] = "Vector64_1", ["Method"] = "As", ["VectorType"] = "Vector64", ["BaseType"] = "Double", ["LargestVectorSize"] = "8", ["NextValueOp"] = "TestLibrary.Generator.GetDouble()" }), @@ -200,6 +211,17 @@ private static readonly (string templateFileName, Dictionary tem ("VectorZeroTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "Zero", ["VectorType"] = "Vector128", ["BaseType"] = "UInt32", ["LargestVectorSize"] = "16" }), ("VectorZeroTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "Zero", ["VectorType"] = "Vector128", ["BaseType"] = "UInt64", ["LargestVectorSize"] = "16" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector128", ["BaseType"] = "Byte", ["LargestVectorSize"] = "16" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector128", ["BaseType"] = "Double", ["LargestVectorSize"] = "16" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector128", ["BaseType"] = "Int16", ["LargestVectorSize"] = "16" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector128", ["BaseType"] = "Int32", ["LargestVectorSize"] = "16" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector128", ["BaseType"] = "Int64", ["LargestVectorSize"] = "16" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector128", ["BaseType"] = "SByte", ["LargestVectorSize"] = "16" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector128", ["BaseType"] = "Single", ["LargestVectorSize"] = "16" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector128", ["BaseType"] = "UInt16", ["LargestVectorSize"] = "16" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector128", ["BaseType"] = "UInt32", ["LargestVectorSize"] = "16" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector128", ["BaseType"] = "UInt64", ["LargestVectorSize"] = "16" }), + ("VectorAsTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "As", ["VectorType"] = "Vector128", ["BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp"] = "(byte)TestLibrary.Generator.GetByte()" }), ("VectorAsTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "As", ["VectorType"] = "Vector128", ["BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp"] = "(double)TestLibrary.Generator.GetDouble()" }), ("VectorAsTest.template", new Dictionary { ["Isa"] = "Vector128_1", ["Method"] = "As", ["VectorType"] = "Vector128", ["BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp"] = "(short)TestLibrary.Generator.GetInt16()" }), @@ -368,6 +390,18 @@ private static readonly (string templateFileName, Dictionary tem ("VectorZeroTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "Zero", ["VectorType"] = "Vector256", ["BaseType"] = "UInt32", ["LargestVectorSize"] = "32" }), ("VectorZeroTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "Zero", ["VectorType"] = "Vector256", ["BaseType"] = "UInt64", ["LargestVectorSize"] = "32" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector256", ["BaseType"] = "Byte", ["LargestVectorSize"] = "32" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector256", ["BaseType"] = "Double", ["LargestVectorSize"] = "32" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector256", ["BaseType"] = "Int16", ["LargestVectorSize"] = "32" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector256", ["BaseType"] = "Int32", ["LargestVectorSize"] = "32" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector256", ["BaseType"] = "Int64", ["LargestVectorSize"] = "32" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector256", ["BaseType"] = "SByte", ["LargestVectorSize"] = "32" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector256", ["BaseType"] = "Single", ["LargestVectorSize"] = "32" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector256", ["BaseType"] = "UInt16", ["LargestVectorSize"] = "32" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector256", ["BaseType"] = "UInt32", ["LargestVectorSize"] = "32" }), + ("VectorAllBitsSetTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "AllBitsSet", ["VectorType"] = "Vector256", ["BaseType"] = "UInt64", ["LargestVectorSize"] = "32" }), + + ("VectorAsTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "As", ["VectorType"] = "Vector256", ["BaseType"] = "Byte", ["LargestVectorSize"] = "32", ["NextValueOp"] = "(byte)TestLibrary.Generator.GetByte()" }), ("VectorAsTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "As", ["VectorType"] = "Vector256", ["BaseType"] = "Double", ["LargestVectorSize"] = "32", ["NextValueOp"] = "(double)TestLibrary.Generator.GetDouble()" }), ("VectorAsTest.template", new Dictionary { ["Isa"] = "Vector256_1", ["Method"] = "As", ["VectorType"] = "Vector256", ["BaseType"] = "Int16", ["LargestVectorSize"] = "32", ["NextValueOp"] = "(short)TestLibrary.Generator.GetInt16()" }), @@ -465,6 +499,7 @@ private static readonly (string templateFileName, Dictionary tem private static readonly (string templateFileName, Dictionary templateData)[] NotSupportedInputs = new [] { ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector64Zero", ["TargetType"] = "Vector64", ["Source"] = "Vector64", ["Method"] = "Zero" }), + ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector64AllBitsSet", ["TargetType"] = "Vector64", ["Source"] = "Vector64", ["Method"] = "AllBitsSet" }), ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector64BooleanAsGeneric_Boolean", ["TargetType"] = "Vector64", ["Source"] = "default(Vector64)", ["Method"] = "As()" }), ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector64ByteAsGeneric_Boolean", ["TargetType"] = "Vector64", ["Source"] = "default(Vector64)", ["Method"] = "As()" }), ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector64DoubleAsGeneric_Boolean", ["TargetType"] = "Vector64", ["Source"] = "default(Vector64)", ["Method"] = "As()" }), @@ -508,6 +543,7 @@ private static readonly (string templateFileName, Dictionary tem ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector64ToString", ["TargetType"] = "string", ["Source"] = "default(Vector64)", ["Method"] = "ToString()" }), ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector128Zero", ["TargetType"] = "Vector128", ["Source"] = "Vector128", ["Method"] = "Zero" }), + ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector128AllBitsSet", ["TargetType"] = "Vector128", ["Source"] = "Vector128", ["Method"] = "AllBitsSet" }), ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector128BooleanAsGeneric_Boolean", ["TargetType"] = "Vector128", ["Source"] = "default(Vector128)", ["Method"] = "As()" }), ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector128ByteAsGeneric_Boolean", ["TargetType"] = "Vector128", ["Source"] = "default(Vector128)", ["Method"] = "As()" }), ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector128DoubleAsGeneric_Boolean", ["TargetType"] = "Vector128", ["Source"] = "default(Vector128)", ["Method"] = "As()" }), @@ -555,6 +591,7 @@ private static readonly (string templateFileName, Dictionary tem ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector128ToString", ["TargetType"] = "string", ["Source"] = "default(Vector128)", ["Method"] = "ToString()" }), ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector256Zero", ["TargetType"] = "Vector256", ["Source"] = "Vector256", ["Method"] = "Zero" }), + ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector256AllBitsSet", ["TargetType"] = "Vector256", ["Source"] = "Vector256", ["Method"] = "AllBitsSet" }), ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector256BooleanAsGeneric_Boolean", ["TargetType"] = "Vector256", ["Source"] = "default(Vector256)", ["Method"] = "As()" }), ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector256ByteAsGeneric_Boolean", ["TargetType"] = "Vector256", ["Source"] = "default(Vector256)", ["Method"] = "As()" }), ("VectorNotSupportedTest.template", new Dictionary { ["Isa"] = "NotSupported", ["Name"] = "Vector256DoubleAsGeneric_Boolean", ["TargetType"] = "Vector256", ["Source"] = "default(Vector256)", ["Method"] = "As()" }), diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Shared/VectorAllBitsSetTest.template b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Shared/VectorAllBitsSetTest.template new file mode 100644 index 00000000000000..bec615964a3f63 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Shared/VectorAllBitsSetTest.template @@ -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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void {Method}{BaseType}() + { + var test = new VectorAllBitsSet__{Method}{BaseType}(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__{Method}{BaseType} + { + private static readonly int LargestVectorSize = {LargestVectorSize}; + + private static readonly int ElementCount = Unsafe.SizeOf<{VectorType}<{BaseType}>>() / sizeof({BaseType}); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + {VectorType}<{BaseType}> result = {VectorType}<{BaseType}>.{Method}; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof({VectorType}<{BaseType}>) + .GetProperty(nameof({VectorType}<{BaseType}>.{Method}), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult(({VectorType}<{BaseType}>)(result)); + } + + private void ValidateResult({VectorType}<{BaseType}> result, [CallerMemberName] string method = "") + { + {BaseType}[] resultElements = new {BaseType}[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As<{BaseType}, byte>(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult({BaseType}[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{VectorType}.{Method}({BaseType}): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet({BaseType} value) + { + for (int i = 0; i < sizeof({BaseType}); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128/Vector128_r.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128/Vector128_r.csproj index 1e8b5fa85f4f1d..2e1ffa2dcc1c7d 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128/Vector128_r.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128/Vector128_r.csproj @@ -8,57 +8,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128/Vector128_ro.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128/Vector128_ro.csproj index a7f139d7665829..91f1f64aec297a 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128/Vector128_ro.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128/Vector128_ro.csproj @@ -8,57 +8,7 @@ True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Byte.cs new file mode 100644 index 00000000000000..8bd51234ad9d56 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Byte.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetByte() + { + var test = new VectorAllBitsSet__AllBitsSetByte(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetByte + { + private static readonly int LargestVectorSize = 16; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector128 result = Vector128.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector128) + .GetProperty(nameof(Vector128.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector128)(result)); + } + + private void ValidateResult(Vector128 result, [CallerMemberName] string method = "") + { + Byte[] resultElements = new Byte[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Byte[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector128.AllBitsSet(Byte): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Byte value) + { + for (int i = 0; i < sizeof(Byte); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Double.cs new file mode 100644 index 00000000000000..b28d53fb6d0a74 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Double.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetDouble() + { + var test = new VectorAllBitsSet__AllBitsSetDouble(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetDouble + { + private static readonly int LargestVectorSize = 16; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Double); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector128 result = Vector128.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector128) + .GetProperty(nameof(Vector128.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector128)(result)); + } + + private void ValidateResult(Vector128 result, [CallerMemberName] string method = "") + { + Double[] resultElements = new Double[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Double[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector128.AllBitsSet(Double): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Double value) + { + for (int i = 0; i < sizeof(Double); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Int16.cs new file mode 100644 index 00000000000000..9b7b179028d870 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Int16.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetInt16() + { + var test = new VectorAllBitsSet__AllBitsSetInt16(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetInt16 + { + private static readonly int LargestVectorSize = 16; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector128 result = Vector128.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector128) + .GetProperty(nameof(Vector128.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector128)(result)); + } + + private void ValidateResult(Vector128 result, [CallerMemberName] string method = "") + { + Int16[] resultElements = new Int16[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Int16[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector128.AllBitsSet(Int16): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Int16 value) + { + for (int i = 0; i < sizeof(Int16); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Int32.cs new file mode 100644 index 00000000000000..6dad97c8c67dc1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Int32.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetInt32() + { + var test = new VectorAllBitsSet__AllBitsSetInt32(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetInt32 + { + private static readonly int LargestVectorSize = 16; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector128 result = Vector128.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector128) + .GetProperty(nameof(Vector128.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector128)(result)); + } + + private void ValidateResult(Vector128 result, [CallerMemberName] string method = "") + { + Int32[] resultElements = new Int32[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Int32[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector128.AllBitsSet(Int32): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Int32 value) + { + for (int i = 0; i < sizeof(Int32); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Int64.cs new file mode 100644 index 00000000000000..dfcb4ab79c0cd7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Int64.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetInt64() + { + var test = new VectorAllBitsSet__AllBitsSetInt64(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetInt64 + { + private static readonly int LargestVectorSize = 16; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector128 result = Vector128.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector128) + .GetProperty(nameof(Vector128.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector128)(result)); + } + + private void ValidateResult(Vector128 result, [CallerMemberName] string method = "") + { + Int64[] resultElements = new Int64[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Int64[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector128.AllBitsSet(Int64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Int64 value) + { + for (int i = 0; i < sizeof(Int64); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.SByte.cs new file mode 100644 index 00000000000000..46d21652e711ef --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.SByte.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetSByte() + { + var test = new VectorAllBitsSet__AllBitsSetSByte(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetSByte + { + private static readonly int LargestVectorSize = 16; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector128 result = Vector128.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector128) + .GetProperty(nameof(Vector128.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector128)(result)); + } + + private void ValidateResult(Vector128 result, [CallerMemberName] string method = "") + { + SByte[] resultElements = new SByte[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(SByte[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector128.AllBitsSet(SByte): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(SByte value) + { + for (int i = 0; i < sizeof(SByte); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Single.cs new file mode 100644 index 00000000000000..878eb567aed588 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.Single.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetSingle() + { + var test = new VectorAllBitsSet__AllBitsSetSingle(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetSingle + { + private static readonly int LargestVectorSize = 16; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Single); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector128 result = Vector128.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector128) + .GetProperty(nameof(Vector128.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector128)(result)); + } + + private void ValidateResult(Vector128 result, [CallerMemberName] string method = "") + { + Single[] resultElements = new Single[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Single[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector128.AllBitsSet(Single): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Single value) + { + for (int i = 0; i < sizeof(Single); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.UInt16.cs new file mode 100644 index 00000000000000..8f7f241dc7cd00 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.UInt16.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetUInt16() + { + var test = new VectorAllBitsSet__AllBitsSetUInt16(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetUInt16 + { + private static readonly int LargestVectorSize = 16; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector128 result = Vector128.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector128) + .GetProperty(nameof(Vector128.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector128)(result)); + } + + private void ValidateResult(Vector128 result, [CallerMemberName] string method = "") + { + UInt16[] resultElements = new UInt16[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(UInt16[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector128.AllBitsSet(UInt16): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(UInt16 value) + { + for (int i = 0; i < sizeof(UInt16); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.UInt32.cs new file mode 100644 index 00000000000000..2521ad706e8a32 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.UInt32.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetUInt32() + { + var test = new VectorAllBitsSet__AllBitsSetUInt32(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetUInt32 + { + private static readonly int LargestVectorSize = 16; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector128 result = Vector128.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector128) + .GetProperty(nameof(Vector128.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector128)(result)); + } + + private void ValidateResult(Vector128 result, [CallerMemberName] string method = "") + { + UInt32[] resultElements = new UInt32[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(UInt32[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector128.AllBitsSet(UInt32): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(UInt32 value) + { + for (int i = 0; i < sizeof(UInt32); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.UInt64.cs new file mode 100644 index 00000000000000..51bc27c467d2d9 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/AllBitsSet.UInt64.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetUInt64() + { + var test = new VectorAllBitsSet__AllBitsSetUInt64(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetUInt64 + { + private static readonly int LargestVectorSize = 16; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector128 result = Vector128.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector128) + .GetProperty(nameof(Vector128.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector128)(result)); + } + + private void ValidateResult(Vector128 result, [CallerMemberName] string method = "") + { + UInt64[] resultElements = new UInt64[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(UInt64[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector128.AllBitsSet(UInt64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(UInt64 value) + { + for (int i = 0; i < sizeof(UInt64); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/Program.Vector128_1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/Program.Vector128_1.cs index d20b224b907ad1..af99bb7d724e50 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/Program.Vector128_1.cs +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/Program.Vector128_1.cs @@ -22,6 +22,16 @@ static Program() ["Zero.UInt16"] = ZeroUInt16, ["Zero.UInt32"] = ZeroUInt32, ["Zero.UInt64"] = ZeroUInt64, + ["AllBitsSet.Byte"] = AllBitsSetByte, + ["AllBitsSet.Double"] = AllBitsSetDouble, + ["AllBitsSet.Int16"] = AllBitsSetInt16, + ["AllBitsSet.Int32"] = AllBitsSetInt32, + ["AllBitsSet.Int64"] = AllBitsSetInt64, + ["AllBitsSet.SByte"] = AllBitsSetSByte, + ["AllBitsSet.Single"] = AllBitsSetSingle, + ["AllBitsSet.UInt16"] = AllBitsSetUInt16, + ["AllBitsSet.UInt32"] = AllBitsSetUInt32, + ["AllBitsSet.UInt64"] = AllBitsSetUInt64, ["As.Byte"] = AsByte, ["As.Double"] = AsDouble, ["As.Int16"] = AsInt16, diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/Vector128_1_r.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/Vector128_1_r.csproj index 461789ad508458..2e1ffa2dcc1c7d 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/Vector128_1_r.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/Vector128_1_r.csproj @@ -8,107 +8,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/Vector128_1_ro.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/Vector128_1_ro.csproj index 3a91a6f202fb03..91f1f64aec297a 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/Vector128_1_ro.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector128_1/Vector128_1_ro.csproj @@ -8,107 +8,7 @@ True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256/Vector256_r.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256/Vector256_r.csproj index 86537dc64fc4b7..2e1ffa2dcc1c7d 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256/Vector256_r.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256/Vector256_r.csproj @@ -8,57 +8,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256/Vector256_ro.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256/Vector256_ro.csproj index be1e05b5eb2b84..91f1f64aec297a 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256/Vector256_ro.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256/Vector256_ro.csproj @@ -8,57 +8,7 @@ True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Byte.cs new file mode 100644 index 00000000000000..99bc1de7180fe7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Byte.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetByte() + { + var test = new VectorAllBitsSet__AllBitsSetByte(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetByte + { + private static readonly int LargestVectorSize = 32; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector256 result = Vector256.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector256) + .GetProperty(nameof(Vector256.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector256)(result)); + } + + private void ValidateResult(Vector256 result, [CallerMemberName] string method = "") + { + Byte[] resultElements = new Byte[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Byte[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector256.AllBitsSet(Byte): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Byte value) + { + for (int i = 0; i < sizeof(Byte); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Double.cs new file mode 100644 index 00000000000000..5e78af82bafd9b --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Double.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetDouble() + { + var test = new VectorAllBitsSet__AllBitsSetDouble(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetDouble + { + private static readonly int LargestVectorSize = 32; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Double); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector256 result = Vector256.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector256) + .GetProperty(nameof(Vector256.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector256)(result)); + } + + private void ValidateResult(Vector256 result, [CallerMemberName] string method = "") + { + Double[] resultElements = new Double[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Double[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector256.AllBitsSet(Double): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Double value) + { + for (int i = 0; i < sizeof(Double); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Int16.cs new file mode 100644 index 00000000000000..d93610a498fba7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Int16.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetInt16() + { + var test = new VectorAllBitsSet__AllBitsSetInt16(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetInt16 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector256 result = Vector256.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector256) + .GetProperty(nameof(Vector256.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector256)(result)); + } + + private void ValidateResult(Vector256 result, [CallerMemberName] string method = "") + { + Int16[] resultElements = new Int16[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Int16[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector256.AllBitsSet(Int16): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Int16 value) + { + for (int i = 0; i < sizeof(Int16); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Int32.cs new file mode 100644 index 00000000000000..94e49c8b52f5cd --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Int32.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetInt32() + { + var test = new VectorAllBitsSet__AllBitsSetInt32(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetInt32 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector256 result = Vector256.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector256) + .GetProperty(nameof(Vector256.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector256)(result)); + } + + private void ValidateResult(Vector256 result, [CallerMemberName] string method = "") + { + Int32[] resultElements = new Int32[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Int32[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector256.AllBitsSet(Int32): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Int32 value) + { + for (int i = 0; i < sizeof(Int32); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Int64.cs new file mode 100644 index 00000000000000..0944ccec721ee0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Int64.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetInt64() + { + var test = new VectorAllBitsSet__AllBitsSetInt64(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetInt64 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector256 result = Vector256.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector256) + .GetProperty(nameof(Vector256.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector256)(result)); + } + + private void ValidateResult(Vector256 result, [CallerMemberName] string method = "") + { + Int64[] resultElements = new Int64[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Int64[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector256.AllBitsSet(Int64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Int64 value) + { + for (int i = 0; i < sizeof(Int64); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.SByte.cs new file mode 100644 index 00000000000000..f8f114672d23c7 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.SByte.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetSByte() + { + var test = new VectorAllBitsSet__AllBitsSetSByte(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetSByte + { + private static readonly int LargestVectorSize = 32; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector256 result = Vector256.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector256) + .GetProperty(nameof(Vector256.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector256)(result)); + } + + private void ValidateResult(Vector256 result, [CallerMemberName] string method = "") + { + SByte[] resultElements = new SByte[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(SByte[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector256.AllBitsSet(SByte): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(SByte value) + { + for (int i = 0; i < sizeof(SByte); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Single.cs new file mode 100644 index 00000000000000..80c2b76e3f49cd --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.Single.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetSingle() + { + var test = new VectorAllBitsSet__AllBitsSetSingle(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetSingle + { + private static readonly int LargestVectorSize = 32; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Single); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector256 result = Vector256.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector256) + .GetProperty(nameof(Vector256.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector256)(result)); + } + + private void ValidateResult(Vector256 result, [CallerMemberName] string method = "") + { + Single[] resultElements = new Single[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Single[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector256.AllBitsSet(Single): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Single value) + { + for (int i = 0; i < sizeof(Single); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.UInt16.cs new file mode 100644 index 00000000000000..ba940f7f7ce966 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.UInt16.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetUInt16() + { + var test = new VectorAllBitsSet__AllBitsSetUInt16(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetUInt16 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector256 result = Vector256.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector256) + .GetProperty(nameof(Vector256.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector256)(result)); + } + + private void ValidateResult(Vector256 result, [CallerMemberName] string method = "") + { + UInt16[] resultElements = new UInt16[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(UInt16[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector256.AllBitsSet(UInt16): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(UInt16 value) + { + for (int i = 0; i < sizeof(UInt16); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.UInt32.cs new file mode 100644 index 00000000000000..6047163ca4b879 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.UInt32.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetUInt32() + { + var test = new VectorAllBitsSet__AllBitsSetUInt32(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetUInt32 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector256 result = Vector256.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector256) + .GetProperty(nameof(Vector256.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector256)(result)); + } + + private void ValidateResult(Vector256 result, [CallerMemberName] string method = "") + { + UInt32[] resultElements = new UInt32[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(UInt32[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector256.AllBitsSet(UInt32): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(UInt32 value) + { + for (int i = 0; i < sizeof(UInt32); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.UInt64.cs new file mode 100644 index 00000000000000..a12fa33213cd73 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/AllBitsSet.UInt64.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetUInt64() + { + var test = new VectorAllBitsSet__AllBitsSetUInt64(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetUInt64 + { + private static readonly int LargestVectorSize = 32; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector256 result = Vector256.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector256) + .GetProperty(nameof(Vector256.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector256)(result)); + } + + private void ValidateResult(Vector256 result, [CallerMemberName] string method = "") + { + UInt64[] resultElements = new UInt64[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(UInt64[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector256.AllBitsSet(UInt64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(UInt64 value) + { + for (int i = 0; i < sizeof(UInt64); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/Program.Vector256_1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/Program.Vector256_1.cs index 7db1c54f570364..a202c3e2737417 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/Program.Vector256_1.cs +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/Program.Vector256_1.cs @@ -22,6 +22,16 @@ static Program() ["Zero.UInt16"] = ZeroUInt16, ["Zero.UInt32"] = ZeroUInt32, ["Zero.UInt64"] = ZeroUInt64, + ["AllBitsSet.Byte"] = AllBitsSetByte, + ["AllBitsSet.Double"] = AllBitsSetDouble, + ["AllBitsSet.Int16"] = AllBitsSetInt16, + ["AllBitsSet.Int32"] = AllBitsSetInt32, + ["AllBitsSet.Int64"] = AllBitsSetInt64, + ["AllBitsSet.SByte"] = AllBitsSetSByte, + ["AllBitsSet.Single"] = AllBitsSetSingle, + ["AllBitsSet.UInt16"] = AllBitsSetUInt16, + ["AllBitsSet.UInt32"] = AllBitsSetUInt32, + ["AllBitsSet.UInt64"] = AllBitsSetUInt64, ["As.Byte"] = AsByte, ["As.Double"] = AsDouble, ["As.Int16"] = AsInt16, diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_r.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_r.csproj index d7e666de89b2fa..2e1ffa2dcc1c7d 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_r.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_r.csproj @@ -8,104 +8,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_ro.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_ro.csproj index d166ec99965a13..91f1f64aec297a 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_ro.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector256_1/Vector256_1_ro.csproj @@ -8,104 +8,7 @@ True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64/Vector64_r.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64/Vector64_r.csproj index 8de9d553944439..2e1ffa2dcc1c7d 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64/Vector64_r.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64/Vector64_r.csproj @@ -8,38 +8,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64/Vector64_ro.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64/Vector64_ro.csproj index dd4c92628574c1..91f1f64aec297a 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64/Vector64_ro.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64/Vector64_ro.csproj @@ -8,38 +8,7 @@ True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Byte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Byte.cs new file mode 100644 index 00000000000000..f42603a2833319 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Byte.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetByte() + { + var test = new VectorAllBitsSet__AllBitsSetByte(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetByte + { + private static readonly int LargestVectorSize = 8; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector64 result = Vector64.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector64) + .GetProperty(nameof(Vector64.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector64)(result)); + } + + private void ValidateResult(Vector64 result, [CallerMemberName] string method = "") + { + Byte[] resultElements = new Byte[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Byte[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector64.AllBitsSet(Byte): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Byte value) + { + for (int i = 0; i < sizeof(Byte); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Double.cs new file mode 100644 index 00000000000000..277ed8ae4e3035 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Double.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetDouble() + { + var test = new VectorAllBitsSet__AllBitsSetDouble(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetDouble + { + private static readonly int LargestVectorSize = 8; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Double); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector64 result = Vector64.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector64) + .GetProperty(nameof(Vector64.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector64)(result)); + } + + private void ValidateResult(Vector64 result, [CallerMemberName] string method = "") + { + Double[] resultElements = new Double[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Double[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector64.AllBitsSet(Double): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Double value) + { + for (int i = 0; i < sizeof(Double); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Int16.cs new file mode 100644 index 00000000000000..79ea21863d4786 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Int16.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetInt16() + { + var test = new VectorAllBitsSet__AllBitsSetInt16(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetInt16 + { + private static readonly int LargestVectorSize = 8; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector64 result = Vector64.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector64) + .GetProperty(nameof(Vector64.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector64)(result)); + } + + private void ValidateResult(Vector64 result, [CallerMemberName] string method = "") + { + Int16[] resultElements = new Int16[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Int16[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector64.AllBitsSet(Int16): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Int16 value) + { + for (int i = 0; i < sizeof(Int16); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Int32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Int32.cs new file mode 100644 index 00000000000000..5b78caf0995740 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Int32.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetInt32() + { + var test = new VectorAllBitsSet__AllBitsSetInt32(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetInt32 + { + private static readonly int LargestVectorSize = 8; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector64 result = Vector64.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector64) + .GetProperty(nameof(Vector64.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector64)(result)); + } + + private void ValidateResult(Vector64 result, [CallerMemberName] string method = "") + { + Int32[] resultElements = new Int32[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Int32[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector64.AllBitsSet(Int32): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Int32 value) + { + for (int i = 0; i < sizeof(Int32); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Int64.cs new file mode 100644 index 00000000000000..35e95209da89ba --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Int64.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetInt64() + { + var test = new VectorAllBitsSet__AllBitsSetInt64(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetInt64 + { + private static readonly int LargestVectorSize = 8; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Int64); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector64 result = Vector64.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector64) + .GetProperty(nameof(Vector64.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector64)(result)); + } + + private void ValidateResult(Vector64 result, [CallerMemberName] string method = "") + { + Int64[] resultElements = new Int64[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Int64[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector64.AllBitsSet(Int64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Int64 value) + { + for (int i = 0; i < sizeof(Int64); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.SByte.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.SByte.cs new file mode 100644 index 00000000000000..4f72699c809ba3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.SByte.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetSByte() + { + var test = new VectorAllBitsSet__AllBitsSetSByte(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetSByte + { + private static readonly int LargestVectorSize = 8; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(SByte); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector64 result = Vector64.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector64) + .GetProperty(nameof(Vector64.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector64)(result)); + } + + private void ValidateResult(Vector64 result, [CallerMemberName] string method = "") + { + SByte[] resultElements = new SByte[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(SByte[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector64.AllBitsSet(SByte): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(SByte value) + { + for (int i = 0; i < sizeof(SByte); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Single.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Single.cs new file mode 100644 index 00000000000000..cdcc116ea7abaa --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.Single.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetSingle() + { + var test = new VectorAllBitsSet__AllBitsSetSingle(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetSingle + { + private static readonly int LargestVectorSize = 8; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(Single); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector64 result = Vector64.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector64) + .GetProperty(nameof(Vector64.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector64)(result)); + } + + private void ValidateResult(Vector64 result, [CallerMemberName] string method = "") + { + Single[] resultElements = new Single[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(Single[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector64.AllBitsSet(Single): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(Single value) + { + for (int i = 0; i < sizeof(Single); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.UInt16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.UInt16.cs new file mode 100644 index 00000000000000..f4b75d11852bc2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.UInt16.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetUInt16() + { + var test = new VectorAllBitsSet__AllBitsSetUInt16(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetUInt16 + { + private static readonly int LargestVectorSize = 8; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector64 result = Vector64.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector64) + .GetProperty(nameof(Vector64.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector64)(result)); + } + + private void ValidateResult(Vector64 result, [CallerMemberName] string method = "") + { + UInt16[] resultElements = new UInt16[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(UInt16[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector64.AllBitsSet(UInt16): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(UInt16 value) + { + for (int i = 0; i < sizeof(UInt16); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.UInt32.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.UInt32.cs new file mode 100644 index 00000000000000..831b97164f0f8e --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.UInt32.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetUInt32() + { + var test = new VectorAllBitsSet__AllBitsSetUInt32(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetUInt32 + { + private static readonly int LargestVectorSize = 8; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(UInt32); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector64 result = Vector64.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector64) + .GetProperty(nameof(Vector64.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector64)(result)); + } + + private void ValidateResult(Vector64 result, [CallerMemberName] string method = "") + { + UInt32[] resultElements = new UInt32[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(UInt32[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector64.AllBitsSet(UInt32): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(UInt32 value) + { + for (int i = 0; i < sizeof(UInt32); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.UInt64.cs new file mode 100644 index 00000000000000..8e65308fc6249c --- /dev/null +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/AllBitsSet.UInt64.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. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\General\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace JIT.HardwareIntrinsics.General +{ + public static partial class Program + { + private static void AllBitsSetUInt64() + { + var test = new VectorAllBitsSet__AllBitsSetUInt64(); + + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class VectorAllBitsSet__AllBitsSetUInt64 + { + private static readonly int LargestVectorSize = 8; + + private static readonly int ElementCount = Unsafe.SizeOf>() / sizeof(UInt64); + + public bool Succeeded { get; set; } = true; + + public void RunBasicScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario)); + + Vector64 result = Vector64.AllBitsSet; + + ValidateResult(result); + } + + public void RunReflectionScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario)); + + object result = typeof(Vector64) + .GetProperty(nameof(Vector64.AllBitsSet), new Type[] { }) + .GetGetMethod() + .Invoke(null, new object[] { }); + + ValidateResult((Vector64)(result)); + } + + private void ValidateResult(Vector64 result, [CallerMemberName] string method = "") + { + UInt64[] resultElements = new UInt64[ElementCount]; + Unsafe.WriteUnaligned(ref Unsafe.As(ref resultElements[0]), result); + ValidateResult(resultElements, method); + } + + private unsafe void ValidateResult(UInt64[] resultElements, [CallerMemberName] string method = "") + { + bool succeeded = true; + for (var i = 0; i < ElementCount; i++) + { + if (!HasAllBitsSet(resultElements[i])) + { + succeeded = false; + break; + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"Vector64.AllBitsSet(UInt64): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", resultElements)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + + private unsafe bool HasAllBitsSet(UInt64 value) + { + for (int i = 0; i < sizeof(UInt64); i++) + { + if (((byte*)&value)[i] != 0xFF) + return false; + } + return true; + } + } +} diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/Program.Vector64_1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/Program.Vector64_1.cs index 3d51ad45a79f82..1c3be92568d624 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/Program.Vector64_1.cs +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/Program.Vector64_1.cs @@ -22,6 +22,16 @@ static Program() ["Zero.UInt16"] = ZeroUInt16, ["Zero.UInt32"] = ZeroUInt32, ["Zero.UInt64"] = ZeroUInt64, + ["AllBitsSet.Byte"] = AllBitsSetByte, + ["AllBitsSet.Double"] = AllBitsSetDouble, + ["AllBitsSet.Int16"] = AllBitsSetInt16, + ["AllBitsSet.Int32"] = AllBitsSetInt32, + ["AllBitsSet.Int64"] = AllBitsSetInt64, + ["AllBitsSet.SByte"] = AllBitsSetSByte, + ["AllBitsSet.Single"] = AllBitsSetSingle, + ["AllBitsSet.UInt16"] = AllBitsSetUInt16, + ["AllBitsSet.UInt32"] = AllBitsSetUInt32, + ["AllBitsSet.UInt64"] = AllBitsSetUInt64, ["As.Byte"] = AsByte, ["As.Double"] = AsDouble, ["As.Int16"] = AsInt16, diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_r.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_r.csproj index 9d02971f9182ce..2e1ffa2dcc1c7d 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_r.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_r.csproj @@ -8,74 +8,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_ro.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_ro.csproj index e4c9baccd0690d..91f1f64aec297a 100644 --- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_ro.csproj +++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/General/Vector64_1/Vector64_1_ro.csproj @@ -8,74 +8,7 @@ True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_byte_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_byte_1_d.csproj index 00a9758fc35e38..f2216b8bd6092a 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_byte_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_byte_1_d.csproj @@ -2,9 +2,6 @@ Exe false - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_byte_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_byte_1_r.csproj index a4c77690480182..c149c151b5c547 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_byte_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_byte_1_r.csproj @@ -2,9 +2,6 @@ Exe false - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_double_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_double_1_d.csproj index 3e99875cccb1e9..4dc52ce2925dca 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_double_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_double_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_double_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_double_1_r.csproj index a0e1ea32630282..157c372fd76a6d 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_double_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_double_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_float_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_float_1_d.csproj index 4c072cd34f3a36..78d1b2a423d6cb 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_float_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_float_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_float_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_float_1_r.csproj index a02915306db0f2..4a8a5773f7865d 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_float_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_float_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_byte_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_byte_1_d.csproj index b85e722dff5d9f..9c841bcb73d91b 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_byte_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_byte_1_d.csproj @@ -2,9 +2,6 @@ Exe false - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_byte_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_byte_1_r.csproj index 40dad66e00b76d..2c5d37892128ef 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_byte_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_byte_1_r.csproj @@ -2,9 +2,6 @@ Exe false - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_double_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_double_1_d.csproj index a242c72f68d3c6..e3f973ca175f5f 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_double_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_double_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_double_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_double_1_r.csproj index 992e33bc070ae4..494df919876580 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_double_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_double_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_float_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_float_1_d.csproj index 82442aa69fd240..b87141e5f4b9d6 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_float_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_float_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_float_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_float_1_r.csproj index 57274e21cb6895..50fcd2da06e3fa 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_float_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_float_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_int_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_int_1_d.csproj index da8e4b2458424a..7536c064f59cfe 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_int_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_int_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_int_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_int_1_r.csproj index d0cfdbff3202ae..a3421a3f304306 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_int_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_int_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_long_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_long_1_d.csproj index 366b242f6e0747..af191f5d15612b 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_long_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_long_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_long_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_long_1_r.csproj index d49c40afb3b224..6aa132a20056f9 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_long_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_long_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_obj_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_obj_1_d.csproj index 62b6027406fc4f..a60467e59c01ed 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_obj_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_obj_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_obj_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_obj_1_r.csproj index 2cdaed45afb25f..22a8ec7831d327 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_obj_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_obj_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_short_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_short_1_d.csproj index 2e9180c9dc8d6d..6cddb2d7dbd6b5 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_short_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_short_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_short_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_short_1_r.csproj index 4ec2597140b16a..b3801faba1bbe8 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_short_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_short_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_val_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_val_1_d.csproj index e9605395d3e1ae..da162fa50bab2b 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_val_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_val_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_val_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_val_1_r.csproj index 3267e366ec509f..297eeb6a1f3978 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_val_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_gc_val_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_int_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_int_1_d.csproj index c3b9c3a574ceb8..7ffc472e569c4d 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_int_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_int_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_int_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_int_1_r.csproj index 08feaa0c4c4e74..e3d3915f923885 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_int_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_int_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_long_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_long_1_d.csproj index 4b7ff7cd62135f..c1e338546c38db 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_long_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_long_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_long_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_long_1_r.csproj index dab4f7c0716237..423c6ea955f0e5 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_long_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_long_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_obj_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_obj_1_d.csproj index c2cdb1b222ad62..48d17ac932950d 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_obj_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_obj_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_obj_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_obj_1_r.csproj index 260e90ce53e8b9..94ff5b8c24f463 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_obj_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_obj_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_short_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_short_1_d.csproj index 972d86cd4bb58e..d027f859516533 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_short_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_short_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_short_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_short_1_r.csproj index 7fd550281d1155..823f1977448f20 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_short_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_short_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_val_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_val_1_d.csproj index f55328301d7d2c..c29594ad20c118 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_val_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_val_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_val_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_val_1_r.csproj index 45f03a5a24ae23..44e6dbba75afa6 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_val_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/expl_val_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_byte_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_byte_1_d.csproj index ec44de88e5196b..fdc7faeccb2dcb 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_byte_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_byte_1_d.csproj @@ -2,9 +2,6 @@ Exe false - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_byte_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_byte_1_r.csproj index df000494948e67..1ed263036d9366 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_byte_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_byte_1_r.csproj @@ -2,9 +2,6 @@ Exe false - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_double_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_double_1_d.csproj index 2f264e5474da63..48847433fe0ebf 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_double_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_double_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_double_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_double_1_r.csproj index 47ff1d66f3c2b4..f4e0a1042f7de2 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_double_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_double_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_float_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_float_1_d.csproj index c780df50874afd..00b704d3df4821 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_float_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_float_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_float_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_float_1_r.csproj index 97f9d0eca5487f..bf72f4caf898df 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_float_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_float_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_byte_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_byte_1_d.csproj index 961d5c3dc4ebff..3dfa967010b2c5 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_byte_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_byte_1_d.csproj @@ -2,9 +2,6 @@ Exe false - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_byte_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_byte_1_r.csproj index 1b505a43ab909e..798cf142092237 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_byte_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_byte_1_r.csproj @@ -2,9 +2,6 @@ Exe false - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_double_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_double_1_d.csproj index 4a366faac6784b..738c9058446417 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_double_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_double_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_double_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_double_1_r.csproj index 00e3585f50d1fa..34cf8d575ec154 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_double_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_double_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_float_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_float_1_d.csproj index 1404d07d4f8c88..2bfbf2bcbe54cf 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_float_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_float_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_float_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_float_1_r.csproj index ad55edeb4c8f33..59596e1e5b8fe6 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_float_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_float_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_int_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_int_1_d.csproj index 81d4b521c63a0e..119d5ac67cc0ed 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_int_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_int_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_int_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_int_1_r.csproj index 61f4d6dbceb76e..424e85e6fd68f4 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_int_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_int_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_long_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_long_1_d.csproj index 4489395a530add..44c06cb4dcd4e5 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_long_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_long_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_long_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_long_1_r.csproj index f8c6882992fc7f..1f0ed4e41cf987 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_long_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_long_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_obj_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_obj_1_d.csproj index 9d9fa929e84b62..1c786400a2abdb 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_obj_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_obj_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_obj_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_obj_1_r.csproj index b5bb76db86df14..107f809cc5aa38 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_obj_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_obj_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_short_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_short_1_d.csproj index 73ff4e590c063c..bee32ef6114192 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_short_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_short_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_short_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_short_1_r.csproj index f4c91f1cfa944d..faef95ea11b348 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_short_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_short_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_val_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_val_1_d.csproj index b2d0d900e16914..10d4215aadbb0e 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_val_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_val_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_val_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_val_1_r.csproj index 9cba141b0f5b3d..fe059309806e63 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_val_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_gc_val_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_int_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_int_1_d.csproj index 6e152621e3f683..032b3ae97810d6 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_int_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_int_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_int_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_int_1_r.csproj index dc8fee05595ae8..cf0bfc623be93b 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_int_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_int_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_long_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_long_1_d.csproj index cfd0b1f6f48a6c..66c4e68a8ff889 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_long_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_long_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_long_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_long_1_r.csproj index a7a69d1b94c94c..f774c2706b232f 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_long_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_long_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_obj_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_obj_1_d.csproj index 37b33e4c6ea19e..ce30b1e6d080ab 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_obj_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_obj_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_obj_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_obj_1_r.csproj index d36f36388082c7..45abb4441b40aa 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_obj_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_obj_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_short_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_short_1_d.csproj index 968148084456ad..3f864de893ca50 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_short_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_short_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_short_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_short_1_r.csproj index de99e6e63c6d47..5ff52f4657858e 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_short_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_short_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_val_1_d.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_val_1_d.csproj index eba374260f0273..fb058166293aa6 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_val_1_d.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_val_1_d.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_val_1_r.csproj b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_val_1_r.csproj index 3688ee9d61f402..74ec71f49bba9e 100644 --- a/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_val_1_r.csproj +++ b/src/coreclr/tests/src/JIT/Methodical/explicit/coverage/seq_val_1_r.csproj @@ -3,9 +3,6 @@ Exe false 1 - - true - true True diff --git a/src/coreclr/tests/src/JIT/Methodical/tailcall_v4/hijacking.il b/src/coreclr/tests/src/JIT/Methodical/tailcall_v4/hijacking.il index fd79227742ddb4..e92e27dfcf6422 100644 --- a/src/coreclr/tests/src/JIT/Methodical/tailcall_v4/hijacking.il +++ b/src/coreclr/tests/src/JIT/Methodical/tailcall_v4/hijacking.il @@ -50,9 +50,9 @@ .class private sequential ansi sealed beforefieldinit ForceHelper extends [System.Runtime]System.ValueType { - .field public valuetype ForceHelper* me + .field public valuetype ForceHelper* me1 + .field public valuetype ForceHelper* me2 .field public int64 counter - .field public int64 extraField } // end of class ForceHelper .class private auto ansi beforefieldinit Repro @@ -91,12 +91,12 @@ IL_002e: ldarga.s h IL_0030: conv.u IL_0031: ldarga.s h - IL_0033: ldfld valuetype ForceHelper* ForceHelper::me + IL_0033: ldfld valuetype ForceHelper* ForceHelper::me1 IL_0038: beq.s IL_0073 IL_003a: ldarga.s h IL_003c: ldfld int64 ForceHelper::counter - IL_0041: ldc.i4.1 + IL_0041: ldc.i4.3 IL_0042: conv.i8 IL_0043: ble.s IL_0069 @@ -119,7 +119,7 @@ IL_0069: ldarga.s h IL_006b: ldarga.s h IL_006d: conv.u - IL_006e: stfld valuetype ForceHelper* ForceHelper::me + IL_006e: stfld valuetype ForceHelper* ForceHelper::me1 IL_0073: ldarg.0 IL_0074: ldarg.1 IL_0075: ldarg.1 @@ -156,12 +156,12 @@ IL_002e: ldarga.s h IL_0030: conv.u IL_0031: ldarga.s h - IL_0033: ldfld valuetype ForceHelper* ForceHelper::me + IL_0033: ldfld valuetype ForceHelper* ForceHelper::me2 IL_0038: beq.s IL_0073 IL_003a: ldarga.s h IL_003c: ldfld int64 ForceHelper::counter - IL_0041: ldc.i4.1 + IL_0041: ldc.i4.3 IL_0042: conv.i8 IL_0043: ble.s IL_0069 @@ -184,7 +184,7 @@ IL_0069: ldarga.s h IL_006b: ldarga.s h IL_006d: conv.u - IL_006e: stfld valuetype ForceHelper* ForceHelper::me + IL_006e: stfld valuetype ForceHelper* ForceHelper::me2 IL_0073: ldarg.0 IL_0074: ldarg.1 IL_0075: tail. call instance void Repro::TailHelper1(valuetype ForceHelper) diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_35384/GitHub_35384.il b/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_35384/GitHub_35384.il new file mode 100644 index 00000000000000..46b1e97fb84e3a --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_35384/GitHub_35384.il @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// This tests a calli with explicit this in the signature + +.assembly extern System.Runtime {} +.assembly GitHub_35384 {} + +.class private sequential ansi sealed beforefieldinit Struct + extends [System.Runtime]System.ValueType +{ + .field public int32 a + + .method public hidebysig instance string + InstanceMethod() cil managed noinlining + { + .maxstack 1 + ldstr "Instance method" + ret + } // end of method Struct::InstanceMethod + +} // end of class Struct + +.class public auto beforefieldinit Program + extends [System.Runtime]System.Object +{ + .method private hidebysig static string + ValueTypeExplicitThisInstanceMethodCalli() cil managed noinlining + { + .maxstack 2 + .locals init (valuetype Struct V_0) + ldloca.s V_0 + initobj Struct + ldloca.s V_0 + ldftn instance string Struct::InstanceMethod() + calli explicit instance string(valuetype Struct&) + ret + } // end of method Program::ValueTypeExplicitThisInstanceMethodCalli + + .method private hidebysig static int32 Main() cil managed + { + .entrypoint + .maxstack 1 + call string Program::ValueTypeExplicitThisInstanceMethodCalli() + pop + ldc.i4 100 + ret + } // end of method Program::Main +} // end of class Program diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_35384/GitHub_35384.ilproj b/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_35384/GitHub_35384.ilproj new file mode 100644 index 00000000000000..e7c67cc80e8533 --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_35384/GitHub_35384.ilproj @@ -0,0 +1,12 @@ + + + Exe + + + None + True + + + + + diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_35821/GitHub_35821.il b/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_35821/GitHub_35821.il new file mode 100644 index 00000000000000..fb248164872af6 --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_35821/GitHub_35821.il @@ -0,0 +1,92 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// Metadata version: v4.0.30319 +.assembly extern System.Runtime +{ + .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....: + .ver 5:0:0:0 +} +.assembly extern System.Runtime.Intrinsics +{ + .publickeytoken = (CC 7B 13 FF CD 2D DD 51 ) // .{...-.Q + .ver 5:0:0:0 +} +.assembly projs { } +.module projs.dll +// MVID: {379016DB-73C2-41D4-9E5F-5B727BC70E2C} +.custom instance void [System.Runtime]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) +.imagebase 0x00400000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY +// Image base: 0x00000293F3DD0000 + + +// =============== CLASS MEMBERS DECLARATION =================== +// This bug was found when passing Vector64 to a method such that +// the vector is on the evaluation stack. C# sometimes assign it the vector64 +// to local variable before passing it to method. In such cases, the bug +// doesn't repro. +.class public auto ansi sealed beforefieldinit projs.GitHub_35821 + extends [System.Runtime]System.Object +{ + .method private hidebysig static int32 + Main(string[] args) cil managed + { + .entrypoint + // Code size 48 (0x30) + .maxstack 8 + IL_0000: ldc.i4.s 23 + IL_0002: conv.i8 + IL_0003: call valuetype [System.Runtime.Intrinsics]System.Runtime.Intrinsics.Vector64`1 [System.Runtime.Intrinsics]System.Runtime.Intrinsics.Vector64::Create(uint64) + IL_0008: call void projs.GitHub_35821::Test1(valuetype [System.Runtime.Intrinsics]System.Runtime.Intrinsics.Vector64`1) + IL_000d: ldc.i4.s 23 + IL_000f: conv.i8 + IL_0010: call valuetype [System.Runtime.Intrinsics]System.Runtime.Intrinsics.Vector64`1 [System.Runtime.Intrinsics]System.Runtime.Intrinsics.Vector64::Create(int64) + IL_0015: call void projs.GitHub_35821::Test2(valuetype [System.Runtime.Intrinsics]System.Runtime.Intrinsics.Vector64`1) + IL_001a: ldc.r8 23. + IL_0023: call valuetype [System.Runtime.Intrinsics]System.Runtime.Intrinsics.Vector64`1 [System.Runtime.Intrinsics]System.Runtime.Intrinsics.Vector64::Create(float64) + IL_0028: call void projs.GitHub_35821::Test3(valuetype [System.Runtime.Intrinsics]System.Runtime.Intrinsics.Vector64`1) + IL_002d: ldc.i4.s 100 + IL_002f: ret + } // end of method GitHub_35821::Main + + .method public hidebysig static void Test1(valuetype [System.Runtime.Intrinsics]System.Runtime.Intrinsics.Vector64`1 data) cil managed noinlining + { + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method GitHub_35821::Test1 + + .method public hidebysig static void Test2(valuetype [System.Runtime.Intrinsics]System.Runtime.Intrinsics.Vector64`1 data) cil managed noinlining + { + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method GitHub_35821::Test2 + + .method public hidebysig static void Test3(valuetype [System.Runtime.Intrinsics]System.Runtime.Intrinsics.Vector64`1 data) cil managed noinlining + { + // Code size 1 (0x1) + .maxstack 8 + IL_0000: ret + } // end of method GitHub_35821::Test3 + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [System.Runtime]System.Object::.ctor() + IL_0006: ret + } // end of method GitHub_35821::.ctor + +} // end of class projs.GitHub_35821 + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_35821/GitHub_35821.ilproj b/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_35821/GitHub_35821.ilproj new file mode 100644 index 00000000000000..e7c67cc80e8533 --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_35821/GitHub_35821.ilproj @@ -0,0 +1,12 @@ + + + Exe + + + None + True + + + + + diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_36905/GitHub_36905.cs b/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_36905/GitHub_36905.cs new file mode 100644 index 00000000000000..eb28530e54270b --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_36905/GitHub_36905.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +public class GitHub_36905 +{ + public static int Main() + { + bool success = true; + + Vector3 a = new Vector3(1.0f, 2.0f, 3.0f); + Vector3 b = new Vector3(1.0f, 2.0f, 3.0f); + + success &= ValidateResult(a == b, expected: true); + success &= ValidateResult(a != b, expected: false); + + Vector3 c = new Vector3(1.0f, 2.0f, 3.0f); + Vector3 d = new Vector3(10.0f, 2.0f, 3.0f); + + success &= ValidateResult(c == d, expected: false); + success &= ValidateResult(c != d, expected: true); + + return success ? 100 : 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static bool ValidateResult(bool actual, bool expected) + { + return actual == expected; + } +} diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_36905/GitHub_36905.csproj b/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_36905/GitHub_36905.csproj new file mode 100644 index 00000000000000..19781e26c20d81 --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_36905/GitHub_36905.csproj @@ -0,0 +1,10 @@ + + + Exe + + True + + + + + diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_33529/Runtime_33529.il b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_33529/Runtime_33529.il new file mode 100644 index 00000000000000..8a77e5078f91b1 --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_33529/Runtime_33529.il @@ -0,0 +1,173 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +.assembly extern mscorlib {} +.assembly Runtime_33529 {} + +// Test case where the jit finds a tail call to loop opportunity after +// suppressing zero initialization for a struct. + +// S is too large to enregister and has gc fields + +.class public sequential ansi sealed beforefieldinit S + extends [mscorlib]System.ValueType +{ + .field public static int32 s_i0 + .field public int32 x + .field public int32 a + .field public int32 i0 + .field public int32 i1 + .field public string s + .method public hidebysig specialname rtspecialname + instance void .ctor(int32 _x, + int32 _a) cil managed + { + // Code size 46 (0x2e) + .maxstack 8 + + // Modify S.ctor to read from i0 before initializing it + + ldarg.0 + ldfld int32 S::i0 + + IL_0001: stsfld int32 S::s_i0 + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld int32 S::x + IL_000d: ldarg.0 + IL_000e: ldarg.2 + IL_000f: stfld int32 S::a + IL_0014: ldarg.0 + IL_0015: ldc.i4.3 + IL_0016: stfld int32 S::i0 + IL_001b: ldarg.0 + IL_001c: ldc.i4.4 + IL_001d: stfld int32 S::i1 + IL_0022: ldarg.0 + IL_0023: ldstr "a string" + IL_0028: stfld string S::s + IL_002d: ret + } // end of method S::.ctor + +} // end of class S + +.class private auto ansi beforefieldinit X + extends [mscorlib]System.Object +{ + .method public hidebysig static int32 F(int32 x, + int32 a) cil managed + { + // Code size 18 (0x12) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: brtrue.s IL_0005 + + IL_0003: ldarg.1 + IL_0004: ret + + IL_0005: ldarg.0 + IL_0006: ldarg.1 + + // This newobj will require a jit temp; the jit will suppress + // zero init assuming prolog zeroing will suffice. + + IL_0007: newobj instance void S::.ctor(int32,int32) + + // Inlining G will introduce a recursive tail call to F which + // the jit will optimize into a loop + + IL_000c: call int32 X::G(valuetype S) + IL_0011: ret + } // end of method X::F + + .method public hidebysig static int32 G(valuetype S s) cil managed + { + // Code size 27 (0x1b) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldfld int32 S::x + IL_0006: ldc.i4.1 + IL_0007: sub + IL_0008: ldarg.0 + IL_0009: ldfld int32 S::a + IL_000e: ldarg.0 + IL_000f: ldfld int32 S::x + IL_0014: mul + IL_0015: call int32 X::F(int32, + int32) + IL_001a: ret + } // end of method X::G + + .method public hidebysig static int32 H(int32 x) cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.1 + IL_0002: call int32 X::F(int32, + int32) + IL_0007: ret + } // end of method X::H + + .method public hidebysig static int32 Main() cil managed + { + .entrypoint + // Code size 78 (0x4e) + .maxstack 4 + .locals init ([0] int32 r) + IL_0000: ldc.i4.6 + IL_0001: call int32 X::H(int32) + IL_0006: stloc.0 + IL_0007: ldsfld int32 S::s_i0 + IL_000c: brtrue.s IL_0018 + + IL_000e: ldloc.0 + IL_000f: ldc.i4 0x2d0 + IL_0014: ceq + IL_0016: br.s IL_0019 + + IL_0018: ldc.i4.0 + IL_0019: dup + IL_001a: brfalse.s IL_0028 + + IL_001c: ldstr "Pass" + IL_0021: call void [mscorlib]System.Console::WriteLine(string) + IL_0026: br.s IL_0047 + + IL_0028: ldstr "Fail, expected S.s_i0 == 0, got {0}, expected r ==" + + " 720, got {1}" + IL_002d: ldsfld int32 S::s_i0 + IL_0032: box [mscorlib]System.Int32 + IL_0037: ldloc.0 + IL_0038: box [mscorlib]System.Int32 + IL_003d: call string [mscorlib]System.String::Format(string, + object, + object) + IL_0042: call void [mscorlib]System.Console::WriteLine(string) + IL_0047: brtrue.s IL_004b + + IL_0049: ldc.i4.m1 + IL_004a: ret + + IL_004b: ldc.i4.s 100 + IL_004d: ret + } // end of method X::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method X::.ctor + +} // end of class X + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** +// WARNING: Created Win32 resource file ixs.res diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_33529/Runtime_33529.ilproj b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_33529/Runtime_33529.ilproj new file mode 100644 index 00000000000000..e7c67cc80e8533 --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_33529/Runtime_33529.ilproj @@ -0,0 +1,12 @@ + + + Exe + + + None + True + + + + + diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_33884/Runtime_33884.cs b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_33884/Runtime_33884.cs new file mode 100644 index 00000000000000..f2576c7b413efb --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_33884/Runtime_33884.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// The test showed CSE issues with struct return retyping. + +using System; +using System.Runtime.CompilerServices; + +struct RefWrapper +{ + public Object a; // a ref field +} + +class TestStructs +{ + static RefWrapper[] arr; + + public static RefWrapper GetElement() // 8 byte size return will be retyped as a ref. + { + return arr[0]; + } + + public static int Main() + { + RefWrapper a = new RefWrapper(); + arr = new RefWrapper[1]; + arr[0] = a; + + RefWrapper e = GetElement(); // force struct retyping to ref. + arr[0] = e; // a struct typed copy. + return 100; + } +} diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_33884/Runtime_33884.csproj b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_33884/Runtime_33884.csproj new file mode 100644 index 00000000000000..1100f420532dc8 --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_33884/Runtime_33884.csproj @@ -0,0 +1,10 @@ + + + Exe + None + True + + + + + diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_34170/Runtime_34170.cs b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_34170/Runtime_34170.cs new file mode 100644 index 00000000000000..5b22d91b0df38f --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_34170/Runtime_34170.cs @@ -0,0 +1,102 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[StructLayout(LayoutKind.Explicit)] +internal struct FloatNonAlignedFieldWithSmallOffset +{ + [FieldOffset(1)] + public float field; + + public FloatNonAlignedFieldWithSmallOffset(float a) + { + field = a; + } +} + +[StructLayout(LayoutKind.Explicit)] +internal struct FloatNonAlignedFieldWithLargeOffset +{ + [FieldOffset(1021)] + public float field; + + public FloatNonAlignedFieldWithLargeOffset(float a) + { + field = a; + } +} + +[StructLayout(LayoutKind.Explicit)] +internal struct DoubleNonAlignedFieldWithSmallOffset +{ + [FieldOffset(1)] + public double field; + + public DoubleNonAlignedFieldWithSmallOffset(float a) + { + field = a; + } +} + +[StructLayout(LayoutKind.Explicit)] +internal struct DoubleNonAlignedFieldWithLargeOffset +{ + [FieldOffset(1021)] + public double field; + + public DoubleNonAlignedFieldWithLargeOffset(float a) + { + field = a; + } +} + +struct SimpleStruct +{ + // the field is aligned inside SimpleStruct. + public float field; +} + +[StructLayout(LayoutKind.Explicit)] +internal struct StructNonAlignedField +{ + // SimpleStruct is unaligned, so the result offset to its float field is unaligned. + [FieldOffset(1)] + public SimpleStruct field; + + public StructNonAlignedField(float a) + { + field.field = a; + } +} + +class Test +{ + private static unsafe int Main() + { + + var a = new FloatNonAlignedFieldWithSmallOffset(1); + Debug.Assert(a.field == 1); + Console.WriteLine(a.field); + var b = new FloatNonAlignedFieldWithLargeOffset(1); + Debug.Assert(b.field == 1); + Console.WriteLine(b.field); + + var c = new DoubleNonAlignedFieldWithSmallOffset(1); + Debug.Assert(c.field == 1); + Console.WriteLine(c.field); + var d = new DoubleNonAlignedFieldWithLargeOffset(1); + Debug.Assert(d.field == 1); + Console.WriteLine(d.field); + + var e = new StructNonAlignedField(1); + Debug.Assert(e.field.field == 1); + Console.WriteLine(e.field.field); + + return 100; + } +} diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_34170/Runtime_34170.csproj b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_34170/Runtime_34170.csproj new file mode 100644 index 00000000000000..5d49e8d49736fa --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_34170/Runtime_34170.csproj @@ -0,0 +1,13 @@ + + + Exe + + + + True + True + + + + + diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_36468/Runtime_36468.cs b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_36468/Runtime_36468.cs new file mode 100644 index 00000000000000..4624bc4def35fc --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_36468/Runtime_36468.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +class C0 +{ + public sbyte F4; +} + +#pragma warning disable 0649 + +struct S1 +{ + public C0 F0; + public bool F8; + public int F9; +} + +public class Runtime_36468 +{ + static S1 s_3; + public static int Main() + { + int result = -1; + try + { + M0(); + } + catch (NullReferenceException) + { + result = 100; + } + + return result; + } + + static void M0() + { + ulong var0 = 0; + try + { + if (M2(ref s_3, s_3)) + { + var0 -= 0; + } + } + finally + { + int var1 = s_3.F9; + } + } + + static bool M2(ref S1 arg0, S1 arg1) + { + sbyte var0 = arg1.F0.F4--; + return arg0.F8; + } +} diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_36468/Runtime_36468.csproj b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_36468/Runtime_36468.csproj new file mode 100644 index 00000000000000..5d49e8d49736fa --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_36468/Runtime_36468.csproj @@ -0,0 +1,13 @@ + + + Exe + + + + True + True + + + + + diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_36584/Runtime_36584.cs b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_36584/Runtime_36584.cs new file mode 100644 index 00000000000000..bdc98c0cedf2ef --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_36584/Runtime_36584.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +// Finally cloning creates new throw merge candidates that +// need to be properly counted. + +class Runtime_36584 +{ + static int x; + + static void ThrowHelper() + { + throw new Exception(); + } + + public static int Main() + { + x = 100; + + if (x != 100) + { + ThrowHelper(); + } + + if (x != 100) + { + ThrowHelper(); + } + + if (x != 100) + { + try + { + x++; + } + // This finally will be cloned + finally + { + if (x != 100) + { + ThrowHelper(); + } + + if (x != 100) + { + ThrowHelper(); + } + } + } + + return x; + } +} diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_36584/Runtime_36584.csproj b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_36584/Runtime_36584.csproj new file mode 100644 index 00000000000000..5d49e8d49736fa --- /dev/null +++ b/src/coreclr/tests/src/JIT/Regression/JitBlue/Runtime_36584/Runtime_36584.csproj @@ -0,0 +1,13 @@ + + + Exe + + + + True + True + + + + + diff --git a/src/coreclr/tests/src/JIT/Regression/VS-ia64-JIT/V2.0-RTM/b539509/b539509.csproj b/src/coreclr/tests/src/JIT/Regression/VS-ia64-JIT/V2.0-RTM/b539509/b539509.csproj index 9dc98caff81a80..e14cd1193bd967 100644 --- a/src/coreclr/tests/src/JIT/Regression/VS-ia64-JIT/V2.0-RTM/b539509/b539509.csproj +++ b/src/coreclr/tests/src/JIT/Regression/VS-ia64-JIT/V2.0-RTM/b539509/b539509.csproj @@ -4,6 +4,7 @@ PdbOnly + True diff --git a/src/coreclr/tests/src/JIT/SIMD/SimpleSIMDProgram.cs b/src/coreclr/tests/src/JIT/SIMD/SimpleSIMDProgram.cs new file mode 100644 index 00000000000000..11c1cd0faff274 --- /dev/null +++ b/src/coreclr/tests/src/JIT/SIMD/SimpleSIMDProgram.cs @@ -0,0 +1,533 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; +using System.Numerics; + +namespace SIMDDebugTest +{ + class Program + { + static int Main(string[] args) + { + Vector4Test.RunTests(); + Vector3Test.RunTests(); + Vector2Test.RunTests(); + FuncEvalTest.RunTests(); + return 100; + } + + class Vector4Test + { + public static int RunTests() + { + AddTest.RunTests(); + SubTest.RunTests(); + MulTest.RunTests(); + DivTest.RunTests(); + return 0; + } + public class AddTest + { + public static int RunTests() + { + Vector4 A = new Vector4(2); + Vector4 B = new Vector4(1); + Vector4 C = A + B; + Vector4 D = VectorAdd(A, B); + Vector4 E = VectorAdd(ref A, ref B); + Vector4 F = VectorAdd(ref A, B); + return 0; + } + + public static Vector4 VectorAdd(Vector4 v1, Vector4 v2) + { + Vector4 v3 = v1 + v2; + return v3; + } + + public static Vector4 VectorAdd(ref Vector4 v1, ref Vector4 v2) + { + Vector4 v3 = v1 + v2; + return v3; + } + + public static Vector4 VectorAdd(ref Vector4 v1, Vector4 v2) + { + Vector4 v3 = v1 + v2; + return v3; + } + + } + + public class SubTest + { + public static int RunTests() + { + Vector4 A = new Vector4(3); + Vector4 B = new Vector4(2); + Vector4 C = A - B; + Vector4 D = VectorSub(A, B); + Vector4 E = VectorSub(ref A, ref B); + Vector4 F = VectorSub(ref A, B); + return 0; + } + public static Vector4 VectorSub(Vector4 v1, Vector4 v2) + { + Vector4 v3 = v1 - v2; + return v3; + } + public static Vector4 VectorSub(ref Vector4 v1, ref Vector4 v2) + { + Vector4 v3 = v1 - v2; + return v3; + } + + public static Vector4 VectorSub(ref Vector4 v1, Vector4 v2) + { + Vector4 v3 = v1 - v2; + return v3; + } + } + + public class MulTest + { + public static int RunTests() + { + Vector4 A = new Vector4(2); + Vector4 B = new Vector4(3); + Vector4 C = A * B; + Vector4 D = VectorMul(A, B); + Vector4 E = VectorMul(ref A, ref B); + Vector4 F = VectorMul(ref A, B); + Vector4 G = VectorMul(A, 2f); + Vector4 H = VectorMul(ref A, 2f); + return 0; + } + + public static Vector4 VectorMul(Vector4 v1, Vector4 v2) + { + Vector4 v3 = v1 * v2; + return v3; + } + + public static Vector4 VectorMul(ref Vector4 v1, ref Vector4 v2) + { + Vector4 v3 = v1 * v2; + return v3; + } + + public static Vector4 VectorMul(ref Vector4 v1, Vector4 v2) + { + Vector4 v3 = v1 * v2; + return v3; + } + + public static Vector4 VectorMul(Vector4 v1, float v) + { + Vector4 v2 = v1 * v; + return v2; + } + + public static Vector4 VectorMul(ref Vector4 v1, float v) + { + Vector4 v2 = v1 * v; + return v2; + } + + } + + public class DivTest + { + public static int RunTests() + { + Vector4 A = new Vector4(2); + Vector4 B = new Vector4(3); + Vector4 C = A / B; + Vector4 D = VectorDiv(A, B); + Vector4 E = VectorDiv(ref A, ref B); + Vector4 F = VectorDiv(ref A, B); + Vector4 G = VectorDiv(A, 3f); + Vector4 H = VectorDiv(ref A, 3f); + return 0; + } + + public static Vector4 VectorDiv(Vector4 v1, Vector4 v2) + { + Vector4 v3 = v1 / v2; + return v3; + } + + public static Vector4 VectorDiv(ref Vector4 v1, ref Vector4 v2) + { + Vector4 v3 = v1 / v2; + return v3; + } + + public static Vector4 VectorDiv(ref Vector4 v1, Vector4 v2) + { + Vector4 v3 = v1 / v2; + return v3; + } + + public static Vector4 VectorDiv(Vector4 v1, float v) + { + Vector4 v2 = v1 / v; + return v2; + } + + public static Vector4 VectorDiv(ref Vector4 v1, float v) + { + Vector4 v2 = v1 / v; + return v2; + } + } + } + + class Vector3Test + { + public static int RunTests() + { + AddTest.RunTests(); + SubTest.RunTests(); + MulTest.RunTests(); + DivTest.RunTests(); + return 0; + } + public class AddTest + { + public static int RunTests() + { + Vector3 A = new Vector3(2); + Vector3 B = new Vector3(1); + Vector3 C = A + B; + Vector3 D = VectorAdd(A, B); + Vector3 E = VectorAdd(ref A, ref B); + Vector3 F = VectorAdd(ref A, B); + return 0; + } + + public static Vector3 VectorAdd(Vector3 v1, Vector3 v2) + { + Vector3 v3 = v1 + v2; + return v3; + } + + public static Vector3 VectorAdd(ref Vector3 v1, ref Vector3 v2) + { + Vector3 v3 = v1 + v2; + return v3; + } + + public static Vector3 VectorAdd(ref Vector3 v1, Vector3 v2) + { + Vector3 v3 = v1 + v2; + return v3; + } + } + + public class SubTest + { + public static int RunTests() + { + Vector3 A = new Vector3(3); + Vector3 B = new Vector3(2); + Vector3 C = A - B; + Vector3 D = VectorSub(A, B); + Vector3 E = VectorSub(ref A, ref B); + Vector3 F = VectorSub(ref A, B); + return 0; + } + public static Vector3 VectorSub(Vector3 v1, Vector3 v2) + { + Vector3 v3 = v1 - v2; + return v3; + } + public static Vector3 VectorSub(ref Vector3 v1, ref Vector3 v2) + { + Vector3 v3 = v1 - v2; + return v3; + } + + public static Vector3 VectorSub(ref Vector3 v1, Vector3 v2) + { + Vector3 v3 = v1 - v2; + return v3; + } + } + public class MulTest + { + public static int RunTests() + { + Vector3 A = new Vector3(2); + Vector3 B = new Vector3(3); + Vector3 C = A * B; + Vector3 D = VectorMul(A, B); + Vector3 E = VectorMul(ref A, ref B); + Vector3 F = VectorMul(ref A, B); + Vector3 G = VectorMul(A, 2f); + Vector3 H = VectorMul(ref A, 2f); + return 0; + } + + public static Vector3 VectorMul(Vector3 v1, Vector3 v2) + { + Vector3 v3 = v1 * v2; + return v3; + } + + public static Vector3 VectorMul(ref Vector3 v1, ref Vector3 v2) + { + Vector3 v3 = v1 * v2; + return v3; + } + + public static Vector3 VectorMul(ref Vector3 v1, Vector3 v2) + { + Vector3 v3 = v1 * v2; + return v3; + } + + public static Vector3 VectorMul(Vector3 v1, float v) + { + Vector3 v2 = v1 * v; + return v2; + } + + public static Vector3 VectorMul(ref Vector3 v1, float v) + { + Vector3 v2 = v1 * v; + return v2; + } + + } + + public class DivTest + { + public static int RunTests() + { + Vector3 A = new Vector3(2); + Vector3 B = new Vector3(3); + Vector3 C = A / B; + Vector3 D = VectorDiv(A, B); + Vector3 E = VectorDiv(ref A, ref B); + Vector3 F = VectorDiv(ref A, B); + Vector3 G = VectorDiv(A, 3f); + Vector3 H = VectorDiv(ref A, 3f); + return 0; + } + + public static Vector3 VectorDiv(Vector3 v1, Vector3 v2) + { + Vector3 v3 = v1 / v2; + return v3; + } + + public static Vector3 VectorDiv(ref Vector3 v1, ref Vector3 v2) + { + Vector3 v3 = v1 / v2; + return v3; + } + + public static Vector3 VectorDiv(ref Vector3 v1, Vector3 v2) + { + Vector3 v3 = v1 / v2; + return v3; + } + + public static Vector3 VectorDiv(Vector3 v1, float v) + { + Vector3 v2 = v1 / v; + return v2; + } + + public static Vector3 VectorDiv(ref Vector3 v1, float v) + { + Vector3 v2 = v1 / v; + return v2; + } + } + } + + class Vector2Test + { + public static int RunTests() + { + AddTest.RunTests(); + SubTest.RunTests(); + MulTest.RunTests(); + DivTest.RunTests(); + return 0; + } + public class AddTest + { + public static int RunTests() + { + Vector2 A = new Vector2(2); + Vector2 B = new Vector2(1); + Vector2 C = A + B; + Vector2 D = VectorAdd(A, B); + Vector2 E = VectorAdd(ref A, ref B); + Vector2 F = VectorAdd(ref A, B); + return 0; + } + + public static Vector2 VectorAdd(Vector2 v1, Vector2 v2) + { + Vector2 v3 = v1 + v2; + return v3; + } + + public static Vector2 VectorAdd(ref Vector2 v1, ref Vector2 v2) + { + Vector2 v3 = v1 + v2; + return v3; + } + + public static Vector2 VectorAdd(ref Vector2 v1, Vector2 v2) + { + Vector2 v3 = v1 + v2; + return v3; + } + } + + public class SubTest + { + public static int RunTests() + { + Vector2 A = new Vector2(3); + Vector2 B = new Vector2(2); + Vector2 C = A - B; + Vector2 D = VectorSub(A, B); + Vector2 E = VectorSub(ref A, ref B); + Vector2 F = VectorSub(ref A, B); + return 0; + } + + public static Vector2 VectorSub(Vector2 v1, Vector2 v2) + { + Vector2 v3 = v1 - v2; + return v3; + } + + public static Vector2 VectorSub(ref Vector2 v1, ref Vector2 v2) + { + Vector2 v3 = v1 - v2; + return v3; + } + + public static Vector2 VectorSub(ref Vector2 v1, Vector2 v2) + { + Vector2 v3 = v1 - v2; + return v3; + } + } + + public class MulTest + { + public static int RunTests() + { + Vector2 A = new Vector2(2); + Vector2 B = new Vector2(3); + Vector2 C = A * B; + Vector2 D = VectorMul(A, B); + Vector2 E = VectorMul(ref A, ref B); + Vector2 F = VectorMul(ref A, B); + Vector2 G = VectorMul(A, 2f); + Vector2 H = VectorMul(ref A, 2f); + return 0; + } + + public static Vector2 VectorMul(Vector2 v1, Vector2 v2) + { + Vector2 v3 = v1 * v2; + return v3; + } + + public static Vector2 VectorMul(ref Vector2 v1, ref Vector2 v2) + { + Vector2 v3 = v1 * v2; + return v3; + } + + public static Vector2 VectorMul(ref Vector2 v1, Vector2 v2) + { + Vector2 v3 = v1 * v2; + return v3; + } + + public static Vector2 VectorMul(Vector2 v1, float v) + { + Vector2 v2 = v1 * v; + return v2; + } + + public static Vector2 VectorMul(ref Vector2 v1, float v) + { + Vector2 v2 = v1 * v; + return v2; + } + + } + + public class DivTest + { + public static int RunTests() + { + Vector2 A = new Vector2(2); + Vector2 B = new Vector2(3); + Vector2 C = A / B; + Vector2 D = VectorDiv(A, B); + Vector2 E = VectorDiv(ref A, ref B); + Vector2 F = VectorDiv(ref A, B); + Vector2 G = VectorDiv(A, 3f); + Vector2 H = VectorDiv(ref A, 3f); + return 0; + } + + public static Vector2 VectorDiv(Vector2 v1, Vector2 v2) + { + Vector2 v3 = v1 / v2; + return v3; + } + + public static Vector2 VectorDiv(ref Vector2 v1, ref Vector2 v2) + { + Vector2 v3 = v1 / v2; + return v3; + } + + public static Vector2 VectorDiv(ref Vector2 v1, Vector2 v2) + { + Vector2 v3 = v1 / v2; + return v3; + } + + public static Vector2 VectorDiv(Vector2 v1, float v) + { + Vector2 v2 = v1 / v; + return v2; + } + + public static Vector2 VectorDiv(ref Vector2 v1, float v) + { + Vector2 v2 = v1 / v; + return v2; + } + } + } + + class FuncEvalTest + { + public static void RunTests() + { + Vector4 v4a = new Vector4(2f); + Vector4 v4b = new Vector4(3f); + Vector3 v3a = new Vector3(2f); + Vector3 v3b = new Vector3(3f); + Vector2 v2a = new Vector2(2f); + Vector2 v2b = new Vector2(3f); + } + } + } +} \ No newline at end of file diff --git a/src/coreclr/tests/src/JIT/SIMD/SimpleSIMDProgram.csproj b/src/coreclr/tests/src/JIT/SIMD/SimpleSIMDProgram.csproj new file mode 100644 index 00000000000000..0177f3a4439eca --- /dev/null +++ b/src/coreclr/tests/src/JIT/SIMD/SimpleSIMDProgram.csproj @@ -0,0 +1,12 @@ + + + Exe + + + None + + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/InstructionCombining/ArrayLengthArithmetic.cs b/src/coreclr/tests/src/JIT/opt/InstructionCombining/ArrayLengthArithmetic.cs new file mode 100644 index 00000000000000..4ac6ef069a3dd4 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/InstructionCombining/ArrayLengthArithmetic.cs @@ -0,0 +1,143 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; + +public class ArrayLengthArithmeticTests +{ + private static int returnCode = 100; + + public static int Main(string[] args) + { + for (int arrayLength = 0; arrayLength < 100; arrayLength++) + { + var array = new int[arrayLength]; + + if (arrayLength == 0) + { + Expect(() => ArrayLengthDiv_cns0(array)); + Expect(() => ArrayLengthDiv_var0(array)); + Expect(() => ArrayLengthMod_cns0(array)); + Expect(() => ArrayLengthMod_var0(array)); + } + + // Array.Length / cns == Array.Length / ToVar(cns) + CompareResults(ArrayLengthDiv_cns1(array), ArrayLengthDiv_var1(array)); + CompareResults(ArrayLengthDiv_cns2(array), ArrayLengthDiv_var2(array)); + CompareResults(ArrayLengthDiv_cns3(array), ArrayLengthDiv_var3(array)); + CompareResults(ArrayLengthDiv_cns4(array), ArrayLengthDiv_var4(array)); + CompareResults(ArrayLengthDiv_cns5(array), ArrayLengthDiv_var5(array)); + CompareResults(ArrayLengthDiv_cns8(array), ArrayLengthDiv_var8(array)); + CompareResults(ArrayLengthDiv_cns10(array), ArrayLengthDiv_var10(array)); + CompareResults(ArrayLengthDiv_cnsMaxValuen1(array), ArrayLengthDiv_varMaxValuen1(array)); + CompareResults(ArrayLengthDiv_cnsMaxValue(array), ArrayLengthDiv_varMaxValue(array)); + CompareResults(ArrayLengthDiv_cnsn1(array), ArrayLengthDiv_varn1(array)); + CompareResults(ArrayLengthDiv_cnsn2(array), ArrayLengthDiv_varn2(array)); + CompareResults(ArrayLengthDiv_cnsMinValue(array), ArrayLengthDiv_varMinValue(array)); + + // Array.Length % cns == Array.Length % ToVar(cns) + CompareResults(ArrayLengthMod_cns1(array), ArrayLengthMod_var1(array)); + CompareResults(ArrayLengthMod_cns2(array), ArrayLengthMod_var2(array)); + CompareResults(ArrayLengthMod_cns3(array), ArrayLengthMod_var3(array)); + CompareResults(ArrayLengthMod_cns4(array), ArrayLengthMod_var4(array)); + CompareResults(ArrayLengthMod_cns5(array), ArrayLengthMod_var5(array)); + CompareResults(ArrayLengthMod_cns8(array), ArrayLengthMod_var8(array)); + CompareResults(ArrayLengthMod_cns10(array), ArrayLengthMod_var10(array)); + CompareResults(ArrayLengthMod_cnsMaxValuen1(array), ArrayLengthMod_varMaxValuen1(array)); + CompareResults(ArrayLengthMod_cnsMaxValue(array), ArrayLengthMod_varMaxValue(array)); + CompareResults(ArrayLengthMod_cnsn1(array), ArrayLengthMod_varn1(array)); + CompareResults(ArrayLengthMod_cnsn2(array), ArrayLengthMod_varn2(array)); + CompareResults(ArrayLengthMod_cnsMinValue(array), ArrayLengthMod_varMinValue(array)); + } + + return returnCode; + } + + // Array.Length / cns + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_cns0(int[] array) => array.Length / 0; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_cns1(int[] array) => array.Length / 1; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_cns2(int[] array) => array.Length / 2; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_cns3(int[] array) => array.Length / 3; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_cns4(int[] array) => array.Length / 4; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_cns5(int[] array) => array.Length / 5; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_cns8(int[] array) => array.Length / 8; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_cns10(int[] array) => array.Length / 10; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_cnsMaxValuen1(int[] array) => array.Length / (int.MaxValue - 1); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_cnsMaxValue(int[] array) => array.Length / int.MaxValue; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_cnsn1(int[] array) => array.Length / -1; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_cnsn2(int[] array) => array.Length / -2; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_cnsMinValue(int[] array) => array.Length / int.MinValue; + + // Array.Length / variable + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_var0(int[] array) => array.Length / ToVar(0); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_var1(int[] array) => array.Length / ToVar(1); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_var2(int[] array) => array.Length / ToVar(2); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_var3(int[] array) => array.Length / ToVar(3); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_var4(int[] array) => array.Length / ToVar(4); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_var5(int[] array) => array.Length / ToVar(5); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_var8(int[] array) => array.Length / ToVar(8); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_var10(int[] array) => array.Length / ToVar(10); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_varMaxValuen1(int[] array) => array.Length / ToVar(int.MaxValue - 1); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_varMaxValue(int[] array) => array.Length / ToVar(int.MaxValue); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_varn1(int[] array) => array.Length / ToVar(-1); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_varn2(int[] array) => array.Length / ToVar(-2); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthDiv_varMinValue(int[] array) => array.Length / ToVar(int.MinValue); + + // Array.Length % cns + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_cns0(int[] array) => array.Length % 0; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_cns1(int[] array) => array.Length % 1; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_cns2(int[] array) => array.Length % 2; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_cns3(int[] array) => array.Length % 3; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_cns4(int[] array) => array.Length % 4; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_cns5(int[] array) => array.Length % 5; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_cns8(int[] array) => array.Length % 8; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_cns10(int[] array) => array.Length % 10; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_cnsMaxValuen1(int[] array) => array.Length % (int.MaxValue - 1); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_cnsMaxValue(int[] array) => array.Length % int.MaxValue; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_cnsn1(int[] array) => array.Length % -1; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_cnsn2(int[] array) => array.Length % -2; + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_cnsMinValue(int[] array) => array.Length % int.MinValue; + + // Array.Length % variable + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_var0(int[] array) => array.Length % ToVar(0); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_var1(int[] array) => array.Length % ToVar(1); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_var2(int[] array) => array.Length % ToVar(2); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_var3(int[] array) => array.Length % ToVar(3); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_var4(int[] array) => array.Length % ToVar(4); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_var5(int[] array) => array.Length % ToVar(5); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_var8(int[] array) => array.Length % ToVar(8); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_var10(int[] array) => array.Length % ToVar(10); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_varMaxValuen1(int[] array) => array.Length % ToVar(int.MaxValue - 1); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_varMaxValue(int[] array) => array.Length % ToVar(int.MaxValue); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_varn1(int[] array) => array.Length % ToVar(-1); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_varn2(int[] array) => array.Length % ToVar(-2); + [MethodImpl(MethodImplOptions.NoInlining)] private static int ArrayLengthMod_varMinValue(int[] array) => array.Length % ToVar(int.MinValue); + + private static void Expect(Action action, [CallerLineNumber] int line = 0) where T : Exception + { + try + { + action(); + } + catch (T) + { + return; + } + Console.WriteLine($"{typeof(T).Name} was expected, L{line}"); + returnCode++; + } + + private static void CompareResults(int a, int b, [CallerLineNumber] int line = 0) + { + if (a != b) + { + Console.WriteLine($"{a} != {b}, L{line}"); + returnCode++; + } + } + + // cns to var + [MethodImpl(MethodImplOptions.NoInlining)] private static T ToVar(T t) => t; +} \ No newline at end of file diff --git a/src/coreclr/tests/src/JIT/opt/InstructionCombining/ArrayLengthArithmetic.csproj b/src/coreclr/tests/src/JIT/opt/InstructionCombining/ArrayLengthArithmetic.csproj new file mode 100644 index 00000000000000..10e5a51b6a3381 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/InstructionCombining/ArrayLengthArithmetic.csproj @@ -0,0 +1,12 @@ + + + Exe + + + None + True + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/InstructionCombining/MulToAdd.cs b/src/coreclr/tests/src/JIT/opt/InstructionCombining/MulToAdd.cs new file mode 100644 index 00000000000000..756d4e840360d2 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/InstructionCombining/MulToAdd.cs @@ -0,0 +1,133 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Linq; +using System.Runtime.CompilerServices; + +// Test "X * 2" to "X + X" + +public class Program +{ + private static int resultCode = 100; + + public static int Main(string[] args) + { + float[] testValues = + { + 0, 0.01f, 1.333f, 1/3.0f, 0.5f, 1, 2, 3, 4, + MathF.PI, MathF.E, + float.MinValue, float.MaxValue, + int.MaxValue, long.MaxValue, + int.MinValue, long.MinValue, + float.NegativeInfinity, + float.PositiveInfinity, + float.NaN, + }; + + testValues = testValues.Concat(testValues.Select(v => -v)).ToArray(); + + foreach (float testValue in testValues) + { + var tf = new TestFloats(); + + // Case 1: argument + AssertEquals(tf.TestArg(testValue), tf.TestArg_var(testValue)); + + // Case 2: ref argument + float t1 = testValue, t2 = testValue; + tf.TestArgRef(ref t1); + tf.TestArgRef_var(ref t2); + AssertEquals(t1, t2); + + // Case 3: out argument + tf.TestArgOut(t1, out t1); + tf.TestArgOut_var(t2, out t2); + AssertEquals(t1, t2); + + // Case 4: field + tf.TestField(); + tf.TestField_var(); + AssertEquals(tf.field1, tf.field2); + + // Case 5: call + AssertEquals(tf.TestCall(), tf.TestCall_var()); + AssertEquals(tf.field1, tf.field2); + } + + return resultCode; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void AssertEquals(float expected, float actual) + { + int expectedBits = BitConverter.SingleToInt32Bits(expected); + int actualBits = BitConverter.SingleToInt32Bits(actual); + if (expectedBits != actualBits) + { + resultCode++; + Console.WriteLine($"AssertEquals: {expected} != {actual}"); + } + } +} + +public class TestFloats +{ + [MethodImpl(MethodImplOptions.NoInlining)] + public static T Var(T t) => t; + + + // Case 1: argument + + [MethodImpl(MethodImplOptions.NoInlining)] + public float TestArg(float x) => x * 2; + + [MethodImpl(MethodImplOptions.NoInlining)] + public float TestArg_var(float x) => x * Var(2); + + + // Case 2: ref argument + + [MethodImpl(MethodImplOptions.NoInlining)] + public void TestArgRef(ref float x) => x *= 2; + + [MethodImpl(MethodImplOptions.NoInlining)] + public void TestArgRef_var(ref float x) => x *= Var(2); + + + // Case 3: out argument + + [MethodImpl(MethodImplOptions.NoInlining)] + public void TestArgOut(float x, out float y) => y = x * 2; + + [MethodImpl(MethodImplOptions.NoInlining)] + public void TestArgOut_var(float x, out float y) => y = x * Var(2); + + + // Case 4: field + + public float field1 = 3.14f; + [MethodImpl(MethodImplOptions.NoInlining)] + public void TestField() => field1 *= 2; + + public float field2 = 3.14f; + [MethodImpl(MethodImplOptions.NoInlining)] + public void TestField_var() => field2 *= Var(2); + + + // Case 5: Call + + [MethodImpl(MethodImplOptions.NoInlining)] + public float Call1() => field1++; // with side-effect + + [MethodImpl(MethodImplOptions.NoInlining)] + public float Call2() => field2++; // with side-effect + + + [MethodImpl(MethodImplOptions.NoInlining)] + public float TestCall() => Call1() * 2; + + [MethodImpl(MethodImplOptions.NoInlining)] + public float TestCall_var() => Call2() * Var(2); +} diff --git a/src/coreclr/tests/src/JIT/opt/InstructionCombining/MulToAdd.csproj b/src/coreclr/tests/src/JIT/opt/InstructionCombining/MulToAdd.csproj new file mode 100644 index 00000000000000..0e728157f743f3 --- /dev/null +++ b/src/coreclr/tests/src/JIT/opt/InstructionCombining/MulToAdd.csproj @@ -0,0 +1,12 @@ + + + Exe + + + None + True + + + + + diff --git a/src/coreclr/tests/src/JIT/opt/Tailcall/TailcallVerifyWithPrefix.il b/src/coreclr/tests/src/JIT/opt/Tailcall/TailcallVerifyWithPrefix.il index 07b7670b15a243..2f27936a85f168 100644 --- a/src/coreclr/tests/src/JIT/opt/Tailcall/TailcallVerifyWithPrefix.il +++ b/src/coreclr/tests/src/JIT/opt/Tailcall/TailcallVerifyWithPrefix.il @@ -1465,33 +1465,6 @@ IL_0067: ldloc.s '<>g__initLocal0' IL_0069: ldstr "Condition5.Test7" IL_006e: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) - IL_0073: ldloc.s '<>g__initLocal0' - IL_0075: ldstr "Condition6.Test1" - IL_007a: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) - IL_007f: ldloc.s '<>g__initLocal0' - IL_0081: ldstr "Condition6.Test2" - IL_0086: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) - IL_008b: ldloc.s '<>g__initLocal0' - IL_008d: ldstr "Condition6.Test3" - IL_0092: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) - IL_0097: ldloc.s '<>g__initLocal0' - IL_0099: ldstr "Condition6.Test4" - IL_009e: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) - IL_00a3: ldloc.s '<>g__initLocal0' - IL_00a5: ldstr "Condition6.Test5" - IL_00aa: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) - IL_00af: ldloc.s '<>g__initLocal0' - IL_00b1: ldstr "Condition7.Test1" - IL_00b6: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) - IL_00bb: ldloc.s '<>g__initLocal0' - IL_00bd: ldstr "Condition7.Test2" - IL_00c2: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) - IL_00c7: ldloc.s '<>g__initLocal0' - IL_00c9: ldstr "Condition7.Test3" - IL_00ce: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) - IL_00d3: ldloc.s '<>g__initLocal0' - IL_00d5: ldstr "Condition7.Test4" - IL_00da: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) IL_00f7: ldloc.s '<>g__initLocal0' IL_00f9: ldstr "Condition9.Test1" IL_00fe: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) @@ -1987,136 +1960,10 @@ IL_028a: ldloc.0 IL_028b: call bool [mscorlib]System.String::op_Equality(string, string) - IL_0290: brfalse.s IL_029c + IL_0290: brfalse.s IL_041c IL_0292: call int32 TailcallVerify.Condition5::Test9() IL_0297: call void TailcallVerify.Program::set_Result(int32) - IL_029c: ldloc.1 - IL_029d: ldstr "Condition6.Test1" - IL_02a2: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_02a7: brtrue.s IL_02b2 - - IL_02a9: ldloc.1 - IL_02aa: ldloc.0 - IL_02ab: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_02b0: brfalse.s IL_02bc - - IL_02b2: call int32 TailcallVerify.Condition6::Test1() - IL_02b7: call void TailcallVerify.Program::set_Result(int32) - IL_02bc: ldloc.1 - IL_02bd: ldstr "Condition6.Test2" - IL_02c2: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_02c7: brtrue.s IL_02d2 - - IL_02c9: ldloc.1 - IL_02ca: ldloc.0 - IL_02cb: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_02d0: brfalse.s IL_02dc - - IL_02d2: call int32 TailcallVerify.Condition6::Test2() - IL_02d7: call void TailcallVerify.Program::set_Result(int32) - IL_02dc: ldloc.1 - IL_02dd: ldstr "Condition6.Test3" - IL_02e2: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_02e7: brtrue.s IL_02f2 - - IL_02e9: ldloc.1 - IL_02ea: ldloc.0 - IL_02eb: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_02f0: brfalse.s IL_02fc - - IL_02f2: call int32 TailcallVerify.Condition6::Test3() - IL_02f7: call void TailcallVerify.Program::set_Result(int32) - IL_02fc: ldloc.1 - IL_02fd: ldstr "Condition6.Test4" - IL_0302: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_0307: brtrue.s IL_0312 - - IL_0309: ldloc.1 - IL_030a: ldloc.0 - IL_030b: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_0310: brfalse.s IL_031c - - IL_0312: call int32 TailcallVerify.Condition6::Test4() - IL_0317: call void TailcallVerify.Program::set_Result(int32) - IL_031c: ldloc.1 - IL_031d: ldstr "Condition6.Test5" - IL_0322: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_0327: brtrue.s IL_0332 - - IL_0329: ldloc.1 - IL_032a: ldloc.0 - IL_032b: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_0330: brfalse.s IL_033c - - IL_0332: call int32 TailcallVerify.Condition6::Test5() - IL_0337: call void TailcallVerify.Program::set_Result(int32) - IL_033c: ldloc.1 - IL_033d: ldstr "Condition7.Test1" - IL_0342: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_0347: brtrue.s IL_0352 - - IL_0349: ldloc.1 - IL_034a: ldloc.0 - IL_034b: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_0350: brfalse.s IL_035c - - IL_0352: call int32 TailcallVerify.Condition7::Test1() - IL_0357: call void TailcallVerify.Program::set_Result(int32) - IL_035c: ldloc.1 - IL_035d: ldstr "Condition7.Test2" - IL_0362: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_0367: brtrue.s IL_0372 - - IL_0369: ldloc.1 - IL_036a: ldloc.0 - IL_036b: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_0370: brfalse.s IL_037c - - IL_0372: call int32 TailcallVerify.Condition7::Test2() - IL_0377: call void TailcallVerify.Program::set_Result(int32) - IL_037c: ldloc.1 - IL_037d: ldstr "Condition7.Test3" - IL_0382: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_0387: brtrue.s IL_0392 - - IL_0389: ldloc.1 - IL_038a: ldloc.0 - IL_038b: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_0390: brfalse.s IL_039c - - IL_0392: call int32 TailcallVerify.Condition7::Test3() - IL_0397: call void TailcallVerify.Program::set_Result(int32) - IL_039c: ldloc.1 - IL_039d: ldstr "Condition7.Test4" - IL_03a2: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_03a7: brtrue.s IL_03b2 - - IL_03a9: ldloc.1 - IL_03aa: ldloc.0 - IL_03ab: call bool [mscorlib]System.String::op_Equality(string, - string) - IL_03b0: brfalse.s IL_041c - - IL_03b2: call int32 TailcallVerify.Condition7::Test4() - IL_03b7: call void TailcallVerify.Program::set_Result(int32) IL_041c: ldloc.1 IL_041d: ldstr "Condition9.Test1" IL_0422: call bool [mscorlib]System.String::op_Equality(string, @@ -2449,33 +2296,6 @@ ldstr "Condition5.Test9" call int32 TailcallVerify.Program::Run(string) pop - ldstr "Condition6.Test1" - call int32 TailcallVerify.Program::Run(string) - pop - ldstr "Condition6.Test2" - call int32 TailcallVerify.Program::Run(string) - pop - ldstr "Condition6.Test3" - call int32 TailcallVerify.Program::Run(string) - pop - ldstr "Condition6.Test4" - call int32 TailcallVerify.Program::Run(string) - pop - ldstr "Condition6.Test5" - call int32 TailcallVerify.Program::Run(string) - pop - ldstr "Condition7.Test1" - call int32 TailcallVerify.Program::Run(string) - pop - ldstr "Condition7.Test2" - call int32 TailcallVerify.Program::Run(string) - pop - ldstr "Condition7.Test3" - call int32 TailcallVerify.Program::Run(string) - pop - ldstr "Condition7.Test4" - call int32 TailcallVerify.Program::Run(string) - pop ldstr "Condition9.Test1" call int32 TailcallVerify.Program::Run(string) pop @@ -4035,78 +3855,79 @@ } // end of class TailcallVerify.Condition10 -.class private auto ansi beforefieldinit TailcallVerify.Condition7 +.class private auto ansi beforefieldinit TailcallVerify.Condition20 extends [mscorlib]System.Object { - .field private static int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) zero .field private static int32 Result .method public hidebysig static int32 Test1() cil managed nooptimization { - // Code size 153 (0x99) + // Code size 158 (0x9e) .maxstack 3 .locals init ([0] class [mscorlib]System.Exception e) - IL_0000: ldstr "Executing Condition7.Test1 - Caller: Arguments: No" - + "ne - ReturnType: void; Callee: Arguments: 10 x Int32 - ReturnType: void" + IL_0000: ldstr "Executing Condition20.Test1 - Caller: Arguments: i" + + "nt - ReturnType: void; Callee: the same as Caller (called again)" IL_0005: call void [System.Console]System.Console::WriteLine(string) IL_000a: ldc.i4.s 100 - IL_000c: stsfld int32 TailcallVerify.Condition7::Result + IL_000c: stsfld int32 TailcallVerify.Condition20::Result .try { - IL_0011: call void TailcallVerify.Condition7::Caller1() - IL_0016: leave.s IL_006f + IL_0011: ldc.i4 0xc8 + IL_0016: call void TailcallVerify.Condition20::Caller1(int32) + IL_001b: leave.s IL_0074 } // end .try catch [mscorlib]System.Exception { - IL_0018: stloc.0 - IL_0019: ldloc.0 - IL_001a: isinst [mscorlib]System.DivideByZeroException - IL_001f: brtrue.s IL_002a + IL_001d: stloc.0 + IL_001e: ldloc.0 + IL_001f: isinst [mscorlib]System.DivideByZeroException + IL_0024: brtrue.s IL_002f - IL_0021: ldc.i4.s 101 - IL_0023: stsfld int32 TailcallVerify.Condition7::Result - IL_0028: rethrow - IL_002a: ldloc.0 - IL_002b: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_0030: ldstr "Caller" - IL_0035: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_003a: ldc.i4.m1 - IL_003b: beq.s IL_006d + IL_0026: ldc.i4.s 101 + IL_0028: stsfld int32 TailcallVerify.Condition20::Result + IL_002d: rethrow + IL_002f: ldloc.0 + IL_0030: callvirt instance string [mscorlib]System.Exception::get_StackTrace() + IL_0035: ldstr "Caller" + IL_003a: callvirt instance int32 [mscorlib]System.String::IndexOf(string) + IL_003f: ldc.i4.m1 + IL_0040: bne.un.s IL_0072 - IL_003d: ldstr "FAILED: Found the word 'Caller' in the stacktrace." - IL_0042: call void [System.Console]System.Console::WriteLine(string) - IL_0047: ldstr "------------------------------------------------" - IL_004c: call void [System.Console]System.Console::WriteLine(string) - IL_0051: call void [System.Console]System.Console::WriteLine() - IL_0056: ldloc.0 - IL_0057: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_005c: call void [System.Console]System.Console::WriteLine(string) - IL_0061: call void [System.Console]System.Console::WriteLine() - IL_0066: ldc.i4.s 101 - IL_0068: stsfld int32 TailcallVerify.Condition7::Result - IL_006d: leave.s IL_006f + IL_0042: ldstr "FAILED: Did not find the word 'Caller' in the stac" + + "ktrace." + IL_0047: call void [System.Console]System.Console::WriteLine(string) + IL_004c: ldstr "------------------------------------------------" + IL_0051: call void [System.Console]System.Console::WriteLine(string) + IL_0056: call void [System.Console]System.Console::WriteLine() + IL_005b: ldloc.0 + IL_005c: callvirt instance string [mscorlib]System.Exception::get_StackTrace() + IL_0061: call void [System.Console]System.Console::WriteLine(string) + IL_0066: call void [System.Console]System.Console::WriteLine() + IL_006b: ldc.i4.s 101 + IL_006d: stsfld int32 TailcallVerify.Condition20::Result + IL_0072: leave.s IL_0074 } // end handler - IL_006f: ldstr "Execution finished - Test " - IL_0074: ldsfld int32 TailcallVerify.Condition7::Result - IL_0079: ldc.i4.s 100 - IL_007b: beq.s IL_0084 + IL_0074: ldstr "Execution finished - Test " + IL_0079: ldsfld int32 TailcallVerify.Condition20::Result + IL_007e: ldc.i4.s 100 + IL_0080: beq.s IL_0089 - IL_007d: ldstr "FAILED" - IL_0082: br.s IL_0089 + IL_0082: ldstr "FAILED" + IL_0087: br.s IL_008e - IL_0084: ldstr "PASSED" - IL_0089: call string [mscorlib]System.String::Concat(string, + IL_0089: ldstr "PASSED" + IL_008e: call string [mscorlib]System.String::Concat(string, string) - IL_008e: call void [System.Console]System.Console::WriteLine(string) - IL_0093: ldsfld int32 TailcallVerify.Condition7::Result - IL_0098: ret - } // end of method Condition7::Test1 + IL_0093: call void [System.Console]System.Console::WriteLine(string) + IL_0098: ldsfld int32 TailcallVerify.Condition20::Result + IL_009d: ret + } // end of method Condition20::Test1 - .method private hidebysig static void Caller1() cil managed + .method private hidebysig static void Caller1(int32 i) cil managed noinlining { - // Code size 63 (0x3f) - .maxstack 10 + // Code size 60 (0x3c) + .maxstack 8 IL_0000: ldc.i4.0 IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() @@ -4119,762 +3940,32 @@ IL_001d: ldstr "Failed, Method was inlined..." IL_0022: call void [System.Console]System.Console::WriteLine(string) IL_0027: ldc.i4.s 101 - IL_0029: stsfld int32 TailcallVerify.Condition7::Result - IL_002e: ldc.i4.0 - IL_002f: ldc.i4.1 - IL_0030: ldc.i4.2 - IL_0031: ldc.i4.3 - IL_0032: ldc.i4.4 - IL_0033: ldc.i4.5 - IL_0034: ldc.i4.6 - IL_0035: ldc.i4.7 - IL_0036: ldc.i4.8 - IL_0037: ldc.i4.s 9 - IL_0039: tail. call void TailcallVerify.Condition7::Callee1(int32, - int32, - int32, - int32, - int32, - int32, - int32, - int32, - int32, - int32) - IL_003e: ret - } // end of method Condition7::Caller1 - - .method private hidebysig static void Callee1(int32 i1, - int32 i2, - int32 i3, - int32 i4, - int32 i5, - int32 i6, - int32 i7, - int32 i8, - int32 i9, - int32 i10) cil managed noinlining - { - // Code size 11 (0xb) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: volatile. - IL_0003: ldsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition7::zero - IL_0008: div - IL_0009: pop - IL_000a: ret - } // end of method Condition7::Callee1 - - .method public hidebysig static int32 Test2() cil managed nooptimization - { - // Code size 153 (0x99) - .maxstack 3 - .locals init ([0] class [mscorlib]System.Exception e) - IL_0000: ldstr "Executing Condition7.Test2 - Caller: Arguments: No" - + "ne - ReturnType: void; Callee: Arguments: i32,i64,mb3,i16,u8,f64,f32,mb" - + "5 - ReturnType: void" - IL_0005: call void [System.Console]System.Console::WriteLine(string) - IL_000a: ldc.i4.s 100 - IL_000c: stsfld int32 TailcallVerify.Condition7::Result - .try - { - IL_0011: call void TailcallVerify.Condition7::Caller2() - IL_0016: leave.s IL_006f - - } // end .try - catch [mscorlib]System.Exception - { - IL_0018: stloc.0 - IL_0019: ldloc.0 - IL_001a: isinst [mscorlib]System.DivideByZeroException - IL_001f: brtrue.s IL_002a - - IL_0021: ldc.i4.s 101 - IL_0023: stsfld int32 TailcallVerify.Condition7::Result - IL_0028: rethrow - IL_002a: ldloc.0 - IL_002b: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_0030: ldstr "Caller" - IL_0035: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_003a: ldc.i4.m1 - IL_003b: beq.s IL_006d - - IL_003d: ldstr "FAILED: Found the word 'Caller' in the stacktrace." - IL_0042: call void [System.Console]System.Console::WriteLine(string) - IL_0047: ldstr "------------------------------------------------" - IL_004c: call void [System.Console]System.Console::WriteLine(string) - IL_0051: call void [System.Console]System.Console::WriteLine() - IL_0056: ldloc.0 - IL_0057: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_005c: call void [System.Console]System.Console::WriteLine(string) - IL_0061: call void [System.Console]System.Console::WriteLine() - IL_0066: ldc.i4.s 101 - IL_0068: stsfld int32 TailcallVerify.Condition7::Result - IL_006d: leave.s IL_006f - - } // end handler - IL_006f: ldstr "Execution finished - Test " - IL_0074: ldsfld int32 TailcallVerify.Condition7::Result - IL_0079: ldc.i4.s 100 - IL_007b: beq.s IL_0084 - - IL_007d: ldstr "FAILED" - IL_0082: br.s IL_0089 - - IL_0084: ldstr "PASSED" - IL_0089: call string [mscorlib]System.String::Concat(string, - string) - IL_008e: call void [System.Console]System.Console::WriteLine(string) - IL_0093: ldsfld int32 TailcallVerify.Condition7::Result - IL_0098: ret - } // end of method Condition7::Test2 + IL_0029: stsfld int32 TailcallVerify.Condition20::Result + IL_002e: ldc.i4.s 10 + IL_0030: ldarg.0 + IL_0031: div + IL_0032: pop + IL_0033: ldarg.0 + IL_0034: ldc.i4.1 + IL_0035: sub + IL_0036: call void TailcallVerify.Condition20::Caller1(int32) + IL_003b: ret + } // end of method Condition20::Caller1 - .method private hidebysig static void Caller2() cil managed + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed { - // Code size 174 (0xae) + // Code size 7 (0x7) .maxstack 8 - .locals init ([0] valuetype TailcallVerify.ValueType3Bytes v3, - [1] valuetype TailcallVerify.ValueType5Bytes v5, - [2] valuetype TailcallVerify.ValueType3Bytes '<>g__initLocal0', - [3] valuetype TailcallVerify.ValueType5Bytes '<>g__initLocal1', - [4] valuetype TailcallVerify.ValueType3Bytes CS$0$0000, - [5] valuetype TailcallVerify.ValueType5Bytes CS$0$0001) - IL_0000: ldc.i4.0 - IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) - IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() - IL_000b: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() - IL_0010: ldstr "Caller" - IL_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_001a: ldc.i4.m1 - IL_001b: bne.un.s IL_002e - - IL_001d: ldstr "Failed, Method was inlined..." - IL_0022: call void [System.Console]System.Console::WriteLine(string) - IL_0027: ldc.i4.s 101 - IL_0029: stsfld int32 TailcallVerify.Condition7::Result - IL_002e: ldloca.s CS$0$0000 - IL_0030: initobj TailcallVerify.ValueType3Bytes - IL_0036: ldloc.s CS$0$0000 - IL_0038: stloc.2 - IL_0039: ldloca.s '<>g__initLocal0' - IL_003b: ldc.i4.0 - IL_003c: stfld uint8 TailcallVerify.ValueType3Bytes::i1 - IL_0041: ldloca.s '<>g__initLocal0' - IL_0043: ldc.i4 0x7fff - IL_0048: stfld int16 TailcallVerify.ValueType3Bytes::i2 - IL_004d: ldloc.2 - IL_004e: stloc.0 - IL_004f: ldloca.s CS$0$0001 - IL_0051: initobj TailcallVerify.ValueType5Bytes - IL_0057: ldloc.s CS$0$0001 - IL_0059: stloc.3 - IL_005a: ldloca.s '<>g__initLocal1' - IL_005c: ldc.i4 0xff - IL_0061: stfld uint8 TailcallVerify.ValueType5Bytes::i1 - IL_0066: ldloca.s '<>g__initLocal1' - IL_0068: ldc.i4 0xffff8000 - IL_006d: stfld int16 TailcallVerify.ValueType5Bytes::i2 - IL_0072: ldloca.s '<>g__initLocal1' - IL_0074: ldc.i4 0x7fff - IL_0079: stfld int16 TailcallVerify.ValueType5Bytes::i3 - IL_007e: ldloc.3 - IL_007f: stloc.1 - IL_0080: ldc.i4 0x80000000 - IL_0085: ldc.i8 0x7fffffffffffffff - IL_008e: ldloc.0 - IL_008f: ldc.i4 0xffff8000 - IL_0094: ldc.i4 0xff - IL_0099: ldc.r8 -1.7976931348623157e+308 - IL_00a2: ldc.r4 3.4028235e+038 - IL_00a7: ldloc.1 - IL_00a8: tail. call void TailcallVerify.Condition7::Callee2(int32, - int64, - valuetype TailcallVerify.ValueType3Bytes, - int16, - uint8, - float64, - float32, - valuetype TailcallVerify.ValueType5Bytes) - IL_00ad: ret - } // end of method Condition7::Caller2 - - .method private hidebysig static void Callee2(int32 i1, - int64 i2, - valuetype TailcallVerify.ValueType3Bytes v3, - int16 i4, - uint8 b5, - float64 d6, - float32 f7, - valuetype TailcallVerify.ValueType5Bytes v8) cil managed noinlining - { - // Code size 308 (0x134) - .maxstack 4 - .locals init ([0] object[] CS$0$0000) IL_0000: ldarg.0 - IL_0001: ldc.i4 0x80000000 - IL_0006: bne.un.s IL_007f - - IL_0008: ldarg.1 - IL_0009: ldc.i8 0x7fffffffffffffff - IL_0012: bne.un.s IL_007f - - IL_0014: ldarga.s v3 - IL_0016: ldfld uint8 TailcallVerify.ValueType3Bytes::i1 - IL_001b: brtrue.s IL_007f - - IL_001d: ldarga.s v3 - IL_001f: ldfld int16 TailcallVerify.ValueType3Bytes::i2 - IL_0024: ldc.i4 0x7fff - IL_0029: bne.un.s IL_007f - - IL_002b: ldarg.3 - IL_002c: ldc.i4 0xffff8000 - IL_0031: bne.un.s IL_007f - - IL_0033: ldarg.s b5 - IL_0035: ldc.i4 0xff - IL_003a: bne.un.s IL_007f - - IL_003c: ldarg.s d6 - IL_003e: ldc.r8 -1.7976931348623157e+308 - IL_0047: bne.un.s IL_007f - - IL_0049: ldarg.s f7 - IL_004b: ldc.r4 3.4028235e+038 - IL_0050: bne.un.s IL_007f - - IL_0052: ldarga.s v8 - IL_0054: ldfld uint8 TailcallVerify.ValueType5Bytes::i1 - IL_0059: ldc.i4 0xff - IL_005e: bne.un.s IL_007f - - IL_0060: ldarga.s v8 - IL_0062: ldfld int16 TailcallVerify.ValueType5Bytes::i2 - IL_0067: ldc.i4 0xffff8000 - IL_006c: bne.un.s IL_007f - - IL_006e: ldarga.s v8 - IL_0070: ldfld int16 TailcallVerify.ValueType5Bytes::i3 - IL_0075: ldc.i4 0x7fff - IL_007a: beq IL_0129 - - IL_007f: ldc.i4.s 101 - IL_0081: stsfld int32 TailcallVerify.Condition7::Result - IL_0086: ldstr "FAILED: Passed in arguments are invalid." - IL_008b: call void [System.Console]System.Console::WriteLine(string) - IL_0090: ldstr "i1:{0} != Int32.MinValue || i2:{1} != Int64.MaxVal" - + "ue || v3.i1:{2} != byte.MinValue || v3.i2:{3} != short.MaxValue || i4:{" - + "4} != Int16.MinValue || b5:{5} != byte.MaxValue || d6:{6} != double.Min" - + "Value || f7:{7} != float.MaxValue || v8.i1:{8} != byte.MaxValue || v8.i" - + "2:{9} != short.MinValue || v8.i3:{10} != short.MaxValue" - IL_0095: ldc.i4.s 11 - IL_0097: newarr [mscorlib]System.Object - IL_009c: stloc.0 - IL_009d: ldloc.0 - IL_009e: ldc.i4.0 - IL_009f: ldarg.0 - IL_00a0: box [mscorlib]System.Int32 - IL_00a5: stelem.ref - IL_00a6: ldloc.0 - IL_00a7: ldc.i4.1 - IL_00a8: ldarg.1 - IL_00a9: box [mscorlib]System.Int64 - IL_00ae: stelem.ref - IL_00af: ldloc.0 - IL_00b0: ldc.i4.2 - IL_00b1: ldarga.s v3 - IL_00b3: ldfld uint8 TailcallVerify.ValueType3Bytes::i1 - IL_00b8: box [mscorlib]System.Byte - IL_00bd: stelem.ref - IL_00be: ldloc.0 - IL_00bf: ldc.i4.3 - IL_00c0: ldarga.s v3 - IL_00c2: ldfld int16 TailcallVerify.ValueType3Bytes::i2 - IL_00c7: box [mscorlib]System.Int16 - IL_00cc: stelem.ref - IL_00cd: ldloc.0 - IL_00ce: ldc.i4.4 - IL_00cf: ldarg.3 - IL_00d0: box [mscorlib]System.Int16 - IL_00d5: stelem.ref - IL_00d6: ldloc.0 - IL_00d7: ldc.i4.5 - IL_00d8: ldarg.s b5 - IL_00da: box [mscorlib]System.Byte - IL_00df: stelem.ref - IL_00e0: ldloc.0 - IL_00e1: ldc.i4.6 - IL_00e2: ldarg.s d6 - IL_00e4: box [mscorlib]System.Double - IL_00e9: stelem.ref - IL_00ea: ldloc.0 - IL_00eb: ldc.i4.7 - IL_00ec: ldarg.s f7 - IL_00ee: box [mscorlib]System.Single - IL_00f3: stelem.ref - IL_00f4: ldloc.0 - IL_00f5: ldc.i4.8 - IL_00f6: ldarga.s v8 - IL_00f8: ldfld uint8 TailcallVerify.ValueType5Bytes::i1 - IL_00fd: box [mscorlib]System.Byte - IL_0102: stelem.ref - IL_0103: ldloc.0 - IL_0104: ldc.i4.s 9 - IL_0106: ldarga.s v8 - IL_0108: ldfld int16 TailcallVerify.ValueType5Bytes::i2 - IL_010d: box [mscorlib]System.Int16 - IL_0112: stelem.ref - IL_0113: ldloc.0 - IL_0114: ldc.i4.s 10 - IL_0116: ldarga.s v8 - IL_0118: ldfld int16 TailcallVerify.ValueType5Bytes::i3 - IL_011d: box [mscorlib]System.Int16 - IL_0122: stelem.ref - IL_0123: ldloc.0 - IL_0124: call void [System.Console]System.Console::Write(string) - callvirt instance string [mscorlib]System.Object::ToString() - call void [System.Console]System.Console::WriteLine(string) - - IL_0129: ldc.i4.1 - IL_012a: volatile. - IL_012c: ldsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition7::zero - IL_0131: div - IL_0132: pop - IL_0133: ret - } // end of method Condition7::Callee2 - - .method public hidebysig static int32 Test3() cil managed nooptimization - { - // Code size 193 (0xc1) - .maxstack 6 - .locals init ([0] class [mscorlib]System.Exception e, - [1] valuetype TailcallVerify.ValueType3Bytes CS$0$0000, - [2] valuetype TailcallVerify.ValueType5Bytes CS$0$0001, - [3] valuetype TailcallVerify.ValueTypeSingleInt64 CS$0$0002, - [4] valuetype TailcallVerify.ValueType3Bytes CS$0$0003, - [5] valuetype TailcallVerify.ValueType5Bytes CS$0$0004, - [6] valuetype TailcallVerify.ValueType3Bytes CS$0$0005) - IL_0000: ldstr "Executing Condition7.Test3 - Caller: Arguments: mb" - + "3,mb5,mb8,mb3,mb5,mb3 - ReturnType: void; Callee: Arguments: mb3,mb5,mb" - + "8,mb3,mb5,mb3 - ReturnType: void" - IL_0005: call void [System.Console]System.Console::WriteLine(string) - IL_000a: ldc.i4.s 100 - IL_000c: stsfld int32 TailcallVerify.Condition7::Result - .try - { - IL_0011: ldloca.s CS$0$0000 - IL_0013: initobj TailcallVerify.ValueType3Bytes - IL_0019: ldloc.1 - IL_001a: ldloca.s CS$0$0001 - IL_001c: initobj TailcallVerify.ValueType5Bytes - IL_0022: ldloc.2 - IL_0023: ldloca.s CS$0$0002 - IL_0025: initobj TailcallVerify.ValueTypeSingleInt64 - IL_002b: ldloc.3 - IL_002c: ldloca.s CS$0$0003 - IL_002e: initobj TailcallVerify.ValueType3Bytes - IL_0034: ldloc.s CS$0$0003 - IL_0036: ldloca.s CS$0$0004 - IL_0038: initobj TailcallVerify.ValueType5Bytes - IL_003e: ldloc.s CS$0$0004 - IL_0040: ldloca.s CS$0$0005 - IL_0042: initobj TailcallVerify.ValueType3Bytes - IL_0048: ldloc.s CS$0$0005 - IL_004a: call void TailcallVerify.Condition7::Caller3(valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes, - valuetype TailcallVerify.ValueTypeSingleInt64, - valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes, - valuetype TailcallVerify.ValueType3Bytes) - IL_004f: leave.s IL_0097 - - } // end .try - catch [mscorlib]System.Exception - { - IL_0051: stloc.0 - IL_0052: ldloc.0 - IL_0053: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_0058: ldstr "Caller" - IL_005d: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_0062: ldc.i4.m1 - IL_0063: beq.s IL_0095 - - IL_0065: ldstr "FAILED: Found the word 'Caller' in the stacktrace." - IL_006a: call void [System.Console]System.Console::WriteLine(string) - IL_006f: ldstr "------------------------------------------------" - IL_0074: call void [System.Console]System.Console::WriteLine(string) - IL_0079: call void [System.Console]System.Console::WriteLine() - IL_007e: ldloc.0 - IL_007f: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_0084: call void [System.Console]System.Console::WriteLine(string) - IL_0089: call void [System.Console]System.Console::WriteLine() - IL_008e: ldc.i4.s 101 - IL_0090: stsfld int32 TailcallVerify.Condition7::Result - IL_0095: leave.s IL_0097 - - } // end handler - IL_0097: ldstr "Execution finished - Test " - IL_009c: ldsfld int32 TailcallVerify.Condition7::Result - IL_00a1: ldc.i4.s 100 - IL_00a3: beq.s IL_00ac - - IL_00a5: ldstr "FAILED" - IL_00aa: br.s IL_00b1 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Condition20::.ctor - IL_00ac: ldstr "PASSED" - IL_00b1: call string [mscorlib]System.String::Concat(string, - string) - IL_00b6: call void [System.Console]System.Console::WriteLine(string) - IL_00bb: ldsfld int32 TailcallVerify.Condition7::Result - IL_00c0: ret - } // end of method Condition7::Test3 - - .method private hidebysig static void Caller3(valuetype TailcallVerify.ValueType3Bytes v1, - valuetype TailcallVerify.ValueType5Bytes v2, - valuetype TailcallVerify.ValueTypeSingleInt64 v3, - valuetype TailcallVerify.ValueType3Bytes v4, - valuetype TailcallVerify.ValueType5Bytes v5, - valuetype TailcallVerify.ValueType3Bytes v6) cil managed + .method private hidebysig specialname rtspecialname static + void .cctor() cil managed { - // Code size 60 (0x3c) - .maxstack 8 - IL_0000: ldc.i4.0 - IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) - IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() - IL_000b: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() - IL_0010: ldstr "Caller" - IL_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_001a: ldc.i4.m1 - IL_001b: bne.un.s IL_002e - - IL_001d: ldstr "Failed, Method was inlined..." - IL_0022: call void [System.Console]System.Console::WriteLine(string) - IL_0027: ldc.i4.s 101 - IL_0029: stsfld int32 TailcallVerify.Condition7::Result - IL_002e: ldarg.0 - IL_002f: ldarg.1 - IL_0030: ldarg.2 - IL_0031: ldarg.3 - IL_0032: ldarg.s v5 - IL_0034: ldarg.s v6 - IL_0036: tail. call void TailcallVerify.Condition7::Callee3(valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes, - valuetype TailcallVerify.ValueTypeSingleInt64, - valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes, - valuetype TailcallVerify.ValueType3Bytes) - IL_003b: ret - } // end of method Condition7::Caller3 - - .method private hidebysig static void Callee3(valuetype TailcallVerify.ValueType3Bytes v1, - valuetype TailcallVerify.ValueType5Bytes v2, - valuetype TailcallVerify.ValueTypeSingleInt64 v3, - valuetype TailcallVerify.ValueType3Bytes v4, - valuetype TailcallVerify.ValueType5Bytes v5, - valuetype TailcallVerify.ValueType3Bytes v6) cil managed noinlining - { - // Code size 18 (0x12) - .maxstack 8 - IL_0000: ldarga.s v1 - IL_0002: ldc.i4.1 - IL_0003: volatile. - IL_0005: ldsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition7::zero - IL_000a: div - IL_000b: conv.i2 - IL_000c: stfld int16 TailcallVerify.ValueType3Bytes::i2 - IL_0011: ret - } // end of method Condition7::Callee3 - - .method public hidebysig static int32 Test4() cil managed nooptimization - { - // Code size 193 (0xc1) - .maxstack 6 - .locals init ([0] class [mscorlib]System.Exception e, - [1] valuetype TailcallVerify.ValueType3Bytes CS$0$0000, - [2] valuetype TailcallVerify.ValueType5Bytes CS$0$0001, - [3] valuetype TailcallVerify.ValueTypeSingleInt64 CS$0$0002, - [4] valuetype TailcallVerify.ValueType3Bytes CS$0$0003, - [5] valuetype TailcallVerify.ValueType5Bytes CS$0$0004, - [6] valuetype TailcallVerify.ValueType3Bytes CS$0$0005) - IL_0000: ldstr "Executing Condition7.Test4 - Caller: Arguments: mb" - + "3,mb5,mb8,mb3,mb5,mb3 - ReturnType: void; Callee: Arguments: mb3,mb5,mb" - + "8,mb3,mb5,mb3 - ReturnType: void" - IL_0005: call void [System.Console]System.Console::WriteLine(string) - IL_000a: ldc.i4.s 100 - IL_000c: stsfld int32 TailcallVerify.Condition7::Result - .try - { - IL_0011: ldloca.s CS$0$0000 - IL_0013: initobj TailcallVerify.ValueType3Bytes - IL_0019: ldloc.1 - IL_001a: ldloca.s CS$0$0001 - IL_001c: initobj TailcallVerify.ValueType5Bytes - IL_0022: ldloc.2 - IL_0023: ldloca.s CS$0$0002 - IL_0025: initobj TailcallVerify.ValueTypeSingleInt64 - IL_002b: ldloc.3 - IL_002c: ldloca.s CS$0$0003 - IL_002e: initobj TailcallVerify.ValueType3Bytes - IL_0034: ldloc.s CS$0$0003 - IL_0036: ldloca.s CS$0$0004 - IL_0038: initobj TailcallVerify.ValueType5Bytes - IL_003e: ldloc.s CS$0$0004 - IL_0040: ldloca.s CS$0$0005 - IL_0042: initobj TailcallVerify.ValueType3Bytes - IL_0048: ldloc.s CS$0$0005 - IL_004a: call void TailcallVerify.Condition7::Caller4(valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes, - valuetype TailcallVerify.ValueTypeSingleInt64, - valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes, - valuetype TailcallVerify.ValueType3Bytes) - IL_004f: leave.s IL_0097 - - } // end .try - catch [mscorlib]System.Exception - { - IL_0051: stloc.0 - IL_0052: ldloc.0 - IL_0053: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_0058: ldstr "Caller" - IL_005d: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_0062: ldc.i4.m1 - IL_0063: beq.s IL_0095 - - IL_0065: ldstr "FAILED: Found the word 'Caller' in the stacktrace." - IL_006a: call void [System.Console]System.Console::WriteLine(string) - IL_006f: ldstr "------------------------------------------------" - IL_0074: call void [System.Console]System.Console::WriteLine(string) - IL_0079: call void [System.Console]System.Console::WriteLine() - IL_007e: ldloc.0 - IL_007f: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_0084: call void [System.Console]System.Console::WriteLine(string) - IL_0089: call void [System.Console]System.Console::WriteLine() - IL_008e: ldc.i4.s 101 - IL_0090: stsfld int32 TailcallVerify.Condition7::Result - IL_0095: leave.s IL_0097 - - } // end handler - IL_0097: ldstr "Execution finished - Test " - IL_009c: ldsfld int32 TailcallVerify.Condition7::Result - IL_00a1: ldc.i4.s 100 - IL_00a3: beq.s IL_00ac - - IL_00a5: ldstr "FAILED" - IL_00aa: br.s IL_00b1 - - IL_00ac: ldstr "PASSED" - IL_00b1: call string [mscorlib]System.String::Concat(string, - string) - IL_00b6: call void [System.Console]System.Console::WriteLine(string) - IL_00bb: ldsfld int32 TailcallVerify.Condition7::Result - IL_00c0: ret - } // end of method Condition7::Test4 - - .method private hidebysig static void Caller4(valuetype TailcallVerify.ValueType3Bytes v1, - valuetype TailcallVerify.ValueType5Bytes v2, - valuetype TailcallVerify.ValueTypeSingleInt64 v3, - valuetype TailcallVerify.ValueType3Bytes v4, - valuetype TailcallVerify.ValueType5Bytes v5, - valuetype TailcallVerify.ValueType3Bytes v6) cil managed - { - // Code size 81 (0x51) - .maxstack 7 - .locals init ([0] int32[] a) - IL_0000: ldc.i4.0 - IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) - IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() - IL_000b: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() - IL_0010: ldstr "Caller" - IL_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_001a: ldc.i4.m1 - IL_001b: bne.un.s IL_002e - - IL_001d: ldstr "Failed, Method was inlined..." - IL_0022: call void [System.Console]System.Console::WriteLine(string) - IL_0027: ldc.i4.s 101 - IL_0029: stsfld int32 TailcallVerify.Condition7::Result - IL_002e: ldc.i4.5 - IL_002f: newarr [mscorlib]System.Int32 - IL_0034: dup - IL_0035: ldtoken field valuetype '{D1242658-CA16-4D11-A740-6635F112F4B5}'/'__StaticArrayInitTypeSize=20' '{D1242658-CA16-4D11-A740-6635F112F4B5}'::'$$method0x6000076-1' - IL_003a: call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, - valuetype [mscorlib]System.RuntimeFieldHandle) - IL_003f: stloc.0 - IL_0040: ldarg.0 - IL_0041: ldarg.1 - IL_0042: ldarg.2 - IL_0043: ldarg.3 - IL_0044: ldarg.s v5 - IL_0046: ldarg.s v6 - IL_0048: ldloc.0 - IL_0049: ldlen - IL_004a: conv.i4 - IL_004b: tail. call void TailcallVerify.Condition7::Callee4(valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes, - valuetype TailcallVerify.ValueTypeSingleInt64, - valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes, - valuetype TailcallVerify.ValueType3Bytes, - int32) - IL_0050: ret - } // end of method Condition7::Caller4 - - .method private hidebysig static void Callee4(valuetype TailcallVerify.ValueType3Bytes v1, - valuetype TailcallVerify.ValueType5Bytes v2, - valuetype TailcallVerify.ValueTypeSingleInt64 v3, - valuetype TailcallVerify.ValueType3Bytes v4, - valuetype TailcallVerify.ValueType5Bytes v5, - valuetype TailcallVerify.ValueType3Bytes v6, - int32 i7) cil managed noinlining - { - // Code size 18 (0x12) - .maxstack 8 - IL_0000: ldarga.s v1 - IL_0002: ldc.i4.1 - IL_0003: volatile. - IL_0005: ldsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition7::zero - IL_000a: div - IL_000b: conv.i2 - IL_000c: stfld int16 TailcallVerify.ValueType3Bytes::i2 - IL_0011: ret - } // end of method Condition7::Callee4 - - .method public hidebysig specialname rtspecialname - instance void .ctor() cil managed - { - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: ret - } // end of method Condition7::.ctor - - .method private hidebysig specialname rtspecialname static - void .cctor() cil managed - { - // Code size 16 (0x10) - .maxstack 8 - IL_0000: ldc.i4.0 - IL_0001: volatile. - IL_0003: stsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition7::zero - IL_0008: ldc.i4.s 100 - IL_000a: stsfld int32 TailcallVerify.Condition7::Result - IL_000f: ret - } // end of method Condition7::.cctor - -} // end of class TailcallVerify.Condition7 - -.class private auto ansi beforefieldinit TailcallVerify.Condition20 - extends [mscorlib]System.Object -{ - .field private static int32 Result - .method public hidebysig static int32 Test1() cil managed nooptimization - { - // Code size 158 (0x9e) - .maxstack 3 - .locals init ([0] class [mscorlib]System.Exception e) - IL_0000: ldstr "Executing Condition20.Test1 - Caller: Arguments: i" - + "nt - ReturnType: void; Callee: the same as Caller (called again)" - IL_0005: call void [System.Console]System.Console::WriteLine(string) - IL_000a: ldc.i4.s 100 - IL_000c: stsfld int32 TailcallVerify.Condition20::Result - .try - { - IL_0011: ldc.i4 0xc8 - IL_0016: call void TailcallVerify.Condition20::Caller1(int32) - IL_001b: leave.s IL_0074 - - } // end .try - catch [mscorlib]System.Exception - { - IL_001d: stloc.0 - IL_001e: ldloc.0 - IL_001f: isinst [mscorlib]System.DivideByZeroException - IL_0024: brtrue.s IL_002f - - IL_0026: ldc.i4.s 101 - IL_0028: stsfld int32 TailcallVerify.Condition20::Result - IL_002d: rethrow - IL_002f: ldloc.0 - IL_0030: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_0035: ldstr "Caller" - IL_003a: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_003f: ldc.i4.m1 - IL_0040: bne.un.s IL_0072 - - IL_0042: ldstr "FAILED: Did not find the word 'Caller' in the stac" - + "ktrace." - IL_0047: call void [System.Console]System.Console::WriteLine(string) - IL_004c: ldstr "------------------------------------------------" - IL_0051: call void [System.Console]System.Console::WriteLine(string) - IL_0056: call void [System.Console]System.Console::WriteLine() - IL_005b: ldloc.0 - IL_005c: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_0061: call void [System.Console]System.Console::WriteLine(string) - IL_0066: call void [System.Console]System.Console::WriteLine() - IL_006b: ldc.i4.s 101 - IL_006d: stsfld int32 TailcallVerify.Condition20::Result - IL_0072: leave.s IL_0074 - - } // end handler - IL_0074: ldstr "Execution finished - Test " - IL_0079: ldsfld int32 TailcallVerify.Condition20::Result - IL_007e: ldc.i4.s 100 - IL_0080: beq.s IL_0089 - - IL_0082: ldstr "FAILED" - IL_0087: br.s IL_008e - - IL_0089: ldstr "PASSED" - IL_008e: call string [mscorlib]System.String::Concat(string, - string) - IL_0093: call void [System.Console]System.Console::WriteLine(string) - IL_0098: ldsfld int32 TailcallVerify.Condition20::Result - IL_009d: ret - } // end of method Condition20::Test1 - - .method private hidebysig static void Caller1(int32 i) cil managed noinlining - { - // Code size 60 (0x3c) - .maxstack 8 - IL_0000: ldc.i4.0 - IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) - IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() - IL_000b: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() - IL_0010: ldstr "Caller" - IL_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_001a: ldc.i4.m1 - IL_001b: bne.un.s IL_002e - - IL_001d: ldstr "Failed, Method was inlined..." - IL_0022: call void [System.Console]System.Console::WriteLine(string) - IL_0027: ldc.i4.s 101 - IL_0029: stsfld int32 TailcallVerify.Condition20::Result - IL_002e: ldc.i4.s 10 - IL_0030: ldarg.0 - IL_0031: div - IL_0032: pop - IL_0033: ldarg.0 - IL_0034: ldc.i4.1 - IL_0035: sub - IL_0036: call void TailcallVerify.Condition20::Caller1(int32) - IL_003b: ret - } // end of method Condition20::Caller1 - - .method public hidebysig specialname rtspecialname - instance void .ctor() cil managed - { - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: ret - } // end of method Condition20::.ctor - - .method private hidebysig specialname rtspecialname static - void .cctor() cil managed - { - // Code size 8 (0x8) + // Code size 8 (0x8) .maxstack 8 IL_0000: ldc.i4.s 100 IL_0002: stsfld int32 TailcallVerify.Condition20::Result @@ -4883,606 +3974,6 @@ } // end of class TailcallVerify.Condition20 -.class private auto ansi beforefieldinit TailcallVerify.Condition6 - extends [mscorlib]System.Object -{ - .field private static int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) zero - .field private static int32 Result - .method public hidebysig static int32 Test1() cil managed nooptimization - { - // Code size 136 (0x88) - .maxstack 3 - .locals init ([0] class [mscorlib]System.Exception e) - IL_0000: ldstr "Executing Condition6.Test1 - Caller: Arguments: No" - + "ne - ReturnType: void; Callee: Arguments: 3 byte struct - ReturnType: v" - + "oid" - IL_0005: call void [System.Console]System.Console::WriteLine(string) - IL_000a: ldc.i4.s 100 - IL_000c: stsfld int32 TailcallVerify.Condition6::Result - .try - { - IL_0011: call void TailcallVerify.Condition6::Caller1() - IL_0016: leave.s IL_005e - - } // end .try - catch [mscorlib]System.Exception - { - IL_0018: stloc.0 - IL_0019: ldloc.0 - IL_001a: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_001f: ldstr "Caller" - IL_0024: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_0029: ldc.i4.m1 - IL_002a: beq.s IL_005c - - IL_002c: ldstr "FAILED: Found the word 'Caller' in the stacktrace." - IL_0031: call void [System.Console]System.Console::WriteLine(string) - IL_0036: ldstr "------------------------------------------------" - IL_003b: call void [System.Console]System.Console::WriteLine(string) - IL_0040: call void [System.Console]System.Console::WriteLine() - IL_0045: ldloc.0 - IL_0046: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_004b: call void [System.Console]System.Console::WriteLine(string) - IL_0050: call void [System.Console]System.Console::WriteLine() - IL_0055: ldc.i4.s 101 - IL_0057: stsfld int32 TailcallVerify.Condition6::Result - IL_005c: leave.s IL_005e - - } // end handler - IL_005e: ldstr "Execution finished - Test " - IL_0063: ldsfld int32 TailcallVerify.Condition6::Result - IL_0068: ldc.i4.s 100 - IL_006a: beq.s IL_0073 - - IL_006c: ldstr "FAILED" - IL_0071: br.s IL_0078 - - IL_0073: ldstr "PASSED" - IL_0078: call string [mscorlib]System.String::Concat(string, - string) - IL_007d: call void [System.Console]System.Console::WriteLine(string) - IL_0082: ldsfld int32 TailcallVerify.Condition6::Result - IL_0087: ret - } // end of method Condition6::Test1 - - .method private hidebysig static void Caller1() cil managed - { - // Code size 70 (0x46) - .maxstack 2 - .locals init ([0] valuetype TailcallVerify.ValueType3Bytes CS$0$0000, - [1] valuetype TailcallVerify.ValueType5Bytes CS$0$0001) - IL_0000: ldc.i4.0 - IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) - IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() - IL_000b: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() - IL_0010: ldstr "Caller" - IL_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_001a: ldc.i4.m1 - IL_001b: bne.un.s IL_002e - - IL_001d: ldstr "Failed, Method was inlined..." - IL_0022: call void [System.Console]System.Console::WriteLine(string) - IL_0027: ldc.i4.s 101 - IL_0029: stsfld int32 TailcallVerify.Condition6::Result - IL_002e: ldloca.s CS$0$0000 - IL_0030: initobj TailcallVerify.ValueType3Bytes - IL_0036: ldloc.0 - IL_0037: ldloca.s CS$0$0001 - IL_0039: initobj TailcallVerify.ValueType5Bytes - IL_003f: ldloc.1 - IL_0040: tail. call void TailcallVerify.Condition6::Callee1(valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes) - IL_0045: ret - } // end of method Condition6::Caller1 - - .method private hidebysig static void Callee1(valuetype TailcallVerify.ValueType3Bytes v, - valuetype TailcallVerify.ValueType5Bytes v5) cil managed noinlining - { - // Code size 18 (0x12) - .maxstack 8 - IL_0000: ldarga.s v - IL_0002: ldc.i4.1 - IL_0003: volatile. - IL_0005: ldsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition6::zero - IL_000a: div - IL_000b: conv.i2 - IL_000c: stfld int16 TailcallVerify.ValueType3Bytes::i2 - IL_0011: ret - } // end of method Condition6::Callee1 - - .method public hidebysig static int32 Test2() cil managed nooptimization - { - // Code size 136 (0x88) - .maxstack 3 - .locals init ([0] class [mscorlib]System.Exception e) - IL_0000: ldstr "Executing Condition6.Test2 - Caller: Arguments: No" - + "ne - ReturnType: void; Callee: Arguments: 3 byte struct - ReturnType: v" - + "oid" - IL_0005: call void [System.Console]System.Console::WriteLine(string) - IL_000a: ldc.i4.s 100 - IL_000c: stsfld int32 TailcallVerify.Condition6::Result - .try - { - IL_0011: call void TailcallVerify.Condition6::Caller2() - IL_0016: leave.s IL_005e - - } // end .try - catch [mscorlib]System.Exception - { - IL_0018: stloc.0 - IL_0019: ldloc.0 - IL_001a: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_001f: ldstr "Caller" - IL_0024: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_0029: ldc.i4.m1 - IL_002a: beq.s IL_005c - - IL_002c: ldstr "FAILED: Found the word 'Caller' in the stacktrace." - IL_0031: call void [System.Console]System.Console::WriteLine(string) - IL_0036: ldstr "------------------------------------------------" - IL_003b: call void [System.Console]System.Console::WriteLine(string) - IL_0040: call void [System.Console]System.Console::WriteLine() - IL_0045: ldloc.0 - IL_0046: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_004b: call void [System.Console]System.Console::WriteLine(string) - IL_0050: call void [System.Console]System.Console::WriteLine() - IL_0055: ldc.i4.s 101 - IL_0057: stsfld int32 TailcallVerify.Condition6::Result - IL_005c: leave.s IL_005e - - } // end handler - IL_005e: ldstr "Execution finished - Test " - IL_0063: ldsfld int32 TailcallVerify.Condition6::Result - IL_0068: ldc.i4.s 100 - IL_006a: beq.s IL_0073 - - IL_006c: ldstr "FAILED" - IL_0071: br.s IL_0078 - - IL_0073: ldstr "PASSED" - IL_0078: call string [mscorlib]System.String::Concat(string, - string) - IL_007d: call void [System.Console]System.Console::WriteLine(string) - IL_0082: ldsfld int32 TailcallVerify.Condition6::Result - IL_0087: ret - } // end of method Condition6::Test2 - - .method private hidebysig static void Caller2() cil managed - { - // Code size 79 (0x4f) - .maxstack 3 - .locals init ([0] valuetype TailcallVerify.ValueType3Bytes CS$0$0000, - [1] valuetype TailcallVerify.ValueType5Bytes CS$0$0001, - [2] valuetype TailcallVerify.ValueTypeSingleInt64 CS$0$0002) - IL_0000: ldc.i4.0 - IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) - IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() - IL_000b: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() - IL_0010: ldstr "Caller" - IL_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_001a: ldc.i4.m1 - IL_001b: bne.un.s IL_002e - - IL_001d: ldstr "Failed, Method was inlined..." - IL_0022: call void [System.Console]System.Console::WriteLine(string) - IL_0027: ldc.i4.s 101 - IL_0029: stsfld int32 TailcallVerify.Condition6::Result - IL_002e: ldloca.s CS$0$0000 - IL_0030: initobj TailcallVerify.ValueType3Bytes - IL_0036: ldloc.0 - IL_0037: ldloca.s CS$0$0001 - IL_0039: initobj TailcallVerify.ValueType5Bytes - IL_003f: ldloc.1 - IL_0040: ldloca.s CS$0$0002 - IL_0042: initobj TailcallVerify.ValueTypeSingleInt64 - IL_0048: ldloc.2 - IL_0049: tail. call void TailcallVerify.Condition6::Callee2(valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes, - valuetype TailcallVerify.ValueTypeSingleInt64) - IL_004e: ret - } // end of method Condition6::Caller2 - - .method private hidebysig static void Callee2(valuetype TailcallVerify.ValueType3Bytes v1, - valuetype TailcallVerify.ValueType5Bytes v2, - valuetype TailcallVerify.ValueTypeSingleInt64 v3) cil managed noinlining - { - // Code size 18 (0x12) - .maxstack 8 - IL_0000: ldarga.s v1 - IL_0002: ldc.i4.1 - IL_0003: volatile. - IL_0005: ldsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition6::zero - IL_000a: div - IL_000b: conv.i2 - IL_000c: stfld int16 TailcallVerify.ValueType3Bytes::i2 - IL_0011: ret - } // end of method Condition6::Callee2 - - .method public hidebysig static int32 Test3() cil managed nooptimization - { - // Code size 136 (0x88) - .maxstack 3 - .locals init ([0] class [mscorlib]System.Exception e) - IL_0000: ldstr "Executing Condition6.Test3 - Caller: Arguments: No" - + "ne - ReturnType: void; Callee: Arguments: 3 byte struct - ReturnType: v" - + "oid" - IL_0005: call void [System.Console]System.Console::WriteLine(string) - IL_000a: ldc.i4.s 100 - IL_000c: stsfld int32 TailcallVerify.Condition6::Result - .try - { - IL_0011: call void TailcallVerify.Condition6::Caller3() - IL_0016: leave.s IL_005e - - } // end .try - catch [mscorlib]System.Exception - { - IL_0018: stloc.0 - IL_0019: ldloc.0 - IL_001a: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_001f: ldstr "Caller" - IL_0024: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_0029: ldc.i4.m1 - IL_002a: beq.s IL_005c - - IL_002c: ldstr "FAILED: Found the word 'Caller' in the stacktrace." - IL_0031: call void [System.Console]System.Console::WriteLine(string) - IL_0036: ldstr "------------------------------------------------" - IL_003b: call void [System.Console]System.Console::WriteLine(string) - IL_0040: call void [System.Console]System.Console::WriteLine() - IL_0045: ldloc.0 - IL_0046: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_004b: call void [System.Console]System.Console::WriteLine(string) - IL_0050: call void [System.Console]System.Console::WriteLine() - IL_0055: ldc.i4.s 101 - IL_0057: stsfld int32 TailcallVerify.Condition6::Result - IL_005c: leave.s IL_005e - - } // end handler - IL_005e: ldstr "Execution finished - Test " - IL_0063: ldsfld int32 TailcallVerify.Condition6::Result - IL_0068: ldc.i4.s 100 - IL_006a: beq.s IL_0073 - - IL_006c: ldstr "FAILED" - IL_0071: br.s IL_0078 - - IL_0073: ldstr "PASSED" - IL_0078: call string [mscorlib]System.String::Concat(string, - string) - IL_007d: call void [System.Console]System.Console::WriteLine(string) - IL_0082: ldsfld int32 TailcallVerify.Condition6::Result - IL_0087: ret - } // end of method Condition6::Test3 - - .method private hidebysig static void Caller3() cil managed - { - // Code size 88 (0x58) - .maxstack 4 - .locals init ([0] valuetype TailcallVerify.ValueType3Bytes CS$0$0000, - [1] valuetype TailcallVerify.ValueType5Bytes CS$0$0001, - [2] valuetype TailcallVerify.ValueTypeSingleInt64 CS$0$0002, - [3] valuetype TailcallVerify.ValueType3Bytes CS$0$0003) - IL_0000: ldc.i4.0 - IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) - IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() - IL_000b: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() - IL_0010: ldstr "Caller" - IL_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_001a: ldc.i4.m1 - IL_001b: bne.un.s IL_002e - - IL_001d: ldstr "Failed, Method was inlined..." - IL_0022: call void [System.Console]System.Console::WriteLine(string) - IL_0027: ldc.i4.s 101 - IL_0029: stsfld int32 TailcallVerify.Condition6::Result - IL_002e: ldloca.s CS$0$0000 - IL_0030: initobj TailcallVerify.ValueType3Bytes - IL_0036: ldloc.0 - IL_0037: ldloca.s CS$0$0001 - IL_0039: initobj TailcallVerify.ValueType5Bytes - IL_003f: ldloc.1 - IL_0040: ldloca.s CS$0$0002 - IL_0042: initobj TailcallVerify.ValueTypeSingleInt64 - IL_0048: ldloc.2 - IL_0049: ldloca.s CS$0$0003 - IL_004b: initobj TailcallVerify.ValueType3Bytes - IL_0051: ldloc.3 - IL_0052: tail. call void TailcallVerify.Condition6::Callee3(valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes, - valuetype TailcallVerify.ValueTypeSingleInt64, - valuetype TailcallVerify.ValueType3Bytes) - IL_0057: ret - } // end of method Condition6::Caller3 - - .method private hidebysig static void Callee3(valuetype TailcallVerify.ValueType3Bytes v1, - valuetype TailcallVerify.ValueType5Bytes v2, - valuetype TailcallVerify.ValueTypeSingleInt64 v3, - valuetype TailcallVerify.ValueType3Bytes v4) cil managed noinlining - { - // Code size 18 (0x12) - .maxstack 8 - IL_0000: ldarga.s v1 - IL_0002: ldc.i4.1 - IL_0003: volatile. - IL_0005: ldsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition6::zero - IL_000a: div - IL_000b: conv.i2 - IL_000c: stfld int16 TailcallVerify.ValueType3Bytes::i2 - IL_0011: ret - } // end of method Condition6::Callee3 - - .method public hidebysig static int32 Test4() cil managed nooptimization - { - // Code size 136 (0x88) - .maxstack 3 - .locals init ([0] class [mscorlib]System.Exception e) - IL_0000: ldstr "Executing Condition6.Test4 - Caller: Arguments: No" - + "ne - ReturnType: void; Callee: Arguments: 3 byte struct - ReturnType: v" - + "oid" - IL_0005: call void [System.Console]System.Console::WriteLine(string) - IL_000a: ldc.i4.s 100 - IL_000c: stsfld int32 TailcallVerify.Condition6::Result - .try - { - IL_0011: call void TailcallVerify.Condition6::Caller4() - IL_0016: leave.s IL_005e - - } // end .try - catch [mscorlib]System.Exception - { - IL_0018: stloc.0 - IL_0019: ldloc.0 - IL_001a: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_001f: ldstr "Caller" - IL_0024: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_0029: ldc.i4.m1 - IL_002a: beq.s IL_005c - - IL_002c: ldstr "FAILED: Found the word 'Caller' in the stacktrace." - IL_0031: call void [System.Console]System.Console::WriteLine(string) - IL_0036: ldstr "------------------------------------------------" - IL_003b: call void [System.Console]System.Console::WriteLine(string) - IL_0040: call void [System.Console]System.Console::WriteLine() - IL_0045: ldloc.0 - IL_0046: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_004b: call void [System.Console]System.Console::WriteLine(string) - IL_0050: call void [System.Console]System.Console::WriteLine() - IL_0055: ldc.i4.s 101 - IL_0057: stsfld int32 TailcallVerify.Condition6::Result - IL_005c: leave.s IL_005e - - } // end handler - IL_005e: ldstr "Execution finished - Test " - IL_0063: ldsfld int32 TailcallVerify.Condition6::Result - IL_0068: ldc.i4.s 100 - IL_006a: beq.s IL_0073 - - IL_006c: ldstr "FAILED" - IL_0071: br.s IL_0078 - - IL_0073: ldstr "PASSED" - IL_0078: call string [mscorlib]System.String::Concat(string, - string) - IL_007d: call void [System.Console]System.Console::WriteLine(string) - IL_0082: ldsfld int32 TailcallVerify.Condition6::Result - IL_0087: ret - } // end of method Condition6::Test4 - - .method private hidebysig static void Caller4() cil managed - { - // Code size 98 (0x62) - .maxstack 5 - .locals init ([0] valuetype TailcallVerify.ValueType3Bytes CS$0$0000, - [1] valuetype TailcallVerify.ValueType5Bytes CS$0$0001, - [2] valuetype TailcallVerify.ValueTypeSingleInt64 CS$0$0002, - [3] valuetype TailcallVerify.ValueType3Bytes CS$0$0003, - [4] valuetype TailcallVerify.ValueType5Bytes CS$0$0004) - IL_0000: ldc.i4.0 - IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) - IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() - IL_000b: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() - IL_0010: ldstr "Caller" - IL_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_001a: ldc.i4.m1 - IL_001b: bne.un.s IL_002e - - IL_001d: ldstr "Failed, Method was inlined..." - IL_0022: call void [System.Console]System.Console::WriteLine(string) - IL_0027: ldc.i4.s 101 - IL_0029: stsfld int32 TailcallVerify.Condition6::Result - IL_002e: ldloca.s CS$0$0000 - IL_0030: initobj TailcallVerify.ValueType3Bytes - IL_0036: ldloc.0 - IL_0037: ldloca.s CS$0$0001 - IL_0039: initobj TailcallVerify.ValueType5Bytes - IL_003f: ldloc.1 - IL_0040: ldloca.s CS$0$0002 - IL_0042: initobj TailcallVerify.ValueTypeSingleInt64 - IL_0048: ldloc.2 - IL_0049: ldloca.s CS$0$0003 - IL_004b: initobj TailcallVerify.ValueType3Bytes - IL_0051: ldloc.3 - IL_0052: ldloca.s CS$0$0004 - IL_0054: initobj TailcallVerify.ValueType5Bytes - IL_005a: ldloc.s CS$0$0004 - IL_005c: tail. call void TailcallVerify.Condition6::Callee4(valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes, - valuetype TailcallVerify.ValueTypeSingleInt64, - valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes) - IL_0061: ret - } // end of method Condition6::Caller4 - - .method private hidebysig static void Callee4(valuetype TailcallVerify.ValueType3Bytes v1, - valuetype TailcallVerify.ValueType5Bytes v2, - valuetype TailcallVerify.ValueTypeSingleInt64 v3, - valuetype TailcallVerify.ValueType3Bytes v4, - valuetype TailcallVerify.ValueType5Bytes v5) cil managed noinlining - { - // Code size 18 (0x12) - .maxstack 8 - IL_0000: ldarga.s v1 - IL_0002: ldc.i4.1 - IL_0003: volatile. - IL_0005: ldsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition6::zero - IL_000a: div - IL_000b: conv.i2 - IL_000c: stfld int16 TailcallVerify.ValueType3Bytes::i2 - IL_0011: ret - } // end of method Condition6::Callee4 - - .method public hidebysig static int32 Test5() cil managed nooptimization - { - // Code size 136 (0x88) - .maxstack 3 - .locals init ([0] class [mscorlib]System.Exception e) - IL_0000: ldstr "Executing Condition6.Test5 - Caller: Arguments: No" - + "ne - ReturnType: void; Callee: Arguments: 3 byte struct - ReturnType: v" - + "oid" - IL_0005: call void [System.Console]System.Console::WriteLine(string) - IL_000a: ldc.i4.s 100 - IL_000c: stsfld int32 TailcallVerify.Condition6::Result - .try - { - IL_0011: call void TailcallVerify.Condition6::Caller5() - IL_0016: leave.s IL_005e - - } // end .try - catch [mscorlib]System.Exception - { - IL_0018: stloc.0 - IL_0019: ldloc.0 - IL_001a: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_001f: ldstr "Caller" - IL_0024: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_0029: ldc.i4.m1 - IL_002a: beq.s IL_005c - - IL_002c: ldstr "FAILED: Found the word 'Caller' in the stacktrace." - IL_0031: call void [System.Console]System.Console::WriteLine(string) - IL_0036: ldstr "------------------------------------------------" - IL_003b: call void [System.Console]System.Console::WriteLine(string) - IL_0040: call void [System.Console]System.Console::WriteLine() - IL_0045: ldloc.0 - IL_0046: callvirt instance string [mscorlib]System.Exception::get_StackTrace() - IL_004b: call void [System.Console]System.Console::WriteLine(string) - IL_0050: call void [System.Console]System.Console::WriteLine() - IL_0055: ldc.i4.s 101 - IL_0057: stsfld int32 TailcallVerify.Condition6::Result - IL_005c: leave.s IL_005e - - } // end handler - IL_005e: ldstr "Execution finished - Test " - IL_0063: ldsfld int32 TailcallVerify.Condition6::Result - IL_0068: ldc.i4.s 100 - IL_006a: beq.s IL_0073 - - IL_006c: ldstr "FAILED" - IL_0071: br.s IL_0078 - - IL_0073: ldstr "PASSED" - IL_0078: call string [mscorlib]System.String::Concat(string, - string) - IL_007d: call void [System.Console]System.Console::WriteLine(string) - IL_0082: ldsfld int32 TailcallVerify.Condition6::Result - IL_0087: ret - } // end of method Condition6::Test5 - - .method private hidebysig static void Caller5() cil managed - { - // Code size 108 (0x6c) - .maxstack 6 - .locals init ([0] valuetype TailcallVerify.ValueType3Bytes CS$0$0000, - [1] valuetype TailcallVerify.ValueType5Bytes CS$0$0001, - [2] valuetype TailcallVerify.ValueTypeSingleInt64 CS$0$0002, - [3] valuetype TailcallVerify.ValueType3Bytes CS$0$0003, - [4] valuetype TailcallVerify.ValueType5Bytes CS$0$0004, - [5] valuetype TailcallVerify.ValueType3Bytes CS$0$0005) - IL_0000: ldc.i4.0 - IL_0001: newobj instance void [mscorlib]System.Diagnostics.StackFrame::.ctor(bool) - IL_0006: callvirt instance class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Diagnostics.StackFrame::GetMethod() - IL_000b: callvirt instance string [mscorlib]System.Reflection.MemberInfo::get_Name() - IL_0010: ldstr "Caller" - IL_0015: callvirt instance int32 [mscorlib]System.String::IndexOf(string) - IL_001a: ldc.i4.m1 - IL_001b: bne.un.s IL_002e - - IL_001d: ldstr "Failed, Method was inlined..." - IL_0022: call void [System.Console]System.Console::WriteLine(string) - IL_0027: ldc.i4.s 101 - IL_0029: stsfld int32 TailcallVerify.Condition6::Result - IL_002e: ldloca.s CS$0$0000 - IL_0030: initobj TailcallVerify.ValueType3Bytes - IL_0036: ldloc.0 - IL_0037: ldloca.s CS$0$0001 - IL_0039: initobj TailcallVerify.ValueType5Bytes - IL_003f: ldloc.1 - IL_0040: ldloca.s CS$0$0002 - IL_0042: initobj TailcallVerify.ValueTypeSingleInt64 - IL_0048: ldloc.2 - IL_0049: ldloca.s CS$0$0003 - IL_004b: initobj TailcallVerify.ValueType3Bytes - IL_0051: ldloc.3 - IL_0052: ldloca.s CS$0$0004 - IL_0054: initobj TailcallVerify.ValueType5Bytes - IL_005a: ldloc.s CS$0$0004 - IL_005c: ldloca.s CS$0$0005 - IL_005e: initobj TailcallVerify.ValueType3Bytes - IL_0064: ldloc.s CS$0$0005 - IL_0066: tail. call void TailcallVerify.Condition6::Callee5(valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes, - valuetype TailcallVerify.ValueTypeSingleInt64, - valuetype TailcallVerify.ValueType3Bytes, - valuetype TailcallVerify.ValueType5Bytes, - valuetype TailcallVerify.ValueType3Bytes) - IL_006b: ret - } // end of method Condition6::Caller5 - - .method private hidebysig static void Callee5(valuetype TailcallVerify.ValueType3Bytes v1, - valuetype TailcallVerify.ValueType5Bytes v2, - valuetype TailcallVerify.ValueTypeSingleInt64 v3, - valuetype TailcallVerify.ValueType3Bytes v4, - valuetype TailcallVerify.ValueType5Bytes v5, - valuetype TailcallVerify.ValueType3Bytes v6) cil managed noinlining - { - // Code size 18 (0x12) - .maxstack 8 - IL_0000: ldarga.s v1 - IL_0002: ldc.i4.1 - IL_0003: volatile. - IL_0005: ldsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition6::zero - IL_000a: div - IL_000b: conv.i2 - IL_000c: stfld int16 TailcallVerify.ValueType3Bytes::i2 - IL_0011: ret - } // end of method Condition6::Callee5 - - .method public hidebysig specialname rtspecialname - instance void .ctor() cil managed - { - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: ret - } // end of method Condition6::.ctor - - .method private hidebysig specialname rtspecialname static - void .cctor() cil managed - { - // Code size 16 (0x10) - .maxstack 8 - IL_0000: ldc.i4.0 - IL_0001: volatile. - IL_0003: stsfld int32 modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) TailcallVerify.Condition6::zero - IL_0008: ldc.i4.s 100 - IL_000a: stsfld int32 TailcallVerify.Condition6::Result - IL_000f: ret - } // end of method Condition6::.cctor - -} // end of class TailcallVerify.Condition6 - .class private auto ansi beforefieldinit TailcallVerify.Condition5 extends [mscorlib]System.Object { @@ -7071,7 +5562,7 @@ call void [System.Console]System.Console::WriteLine(string) br.s IL_AFTER - IL_UNIX: ldstr "Hello" + IL_UNIX: ldstr "Hello\n" call void TailcallVerify.UnixInterop::printf(string) IL_AFTER: ldc.i4.1 volatile. @@ -7178,7 +5669,7 @@ tail. call void TailcallVerify.Win32Interop::Callee(int32) ret - IL_UNIX: ldstr "Hello" + IL_UNIX: ldstr "Hello\n" tail. call void TailcallVerify.UnixInterop::Callee(string) ret } // end of method Condition19::Caller2 diff --git a/src/coreclr/tests/src/Loader/binding/tracing/BinderTracingTest.Basic.csproj b/src/coreclr/tests/src/Loader/binding/tracing/BinderTracingTest.Basic.csproj index c5b8d00433f919..df0b34b275e4e6 100644 --- a/src/coreclr/tests/src/Loader/binding/tracing/BinderTracingTest.Basic.csproj +++ b/src/coreclr/tests/src/Loader/binding/tracing/BinderTracingTest.Basic.csproj @@ -1,4 +1,8 @@ + + + true + diff --git a/src/coreclr/tests/src/Loader/binding/tracing/BinderTracingTest.ResolutionFlow.csproj b/src/coreclr/tests/src/Loader/binding/tracing/BinderTracingTest.ResolutionFlow.csproj index fe21150615f05f..3bc5ed34377a24 100644 --- a/src/coreclr/tests/src/Loader/binding/tracing/BinderTracingTest.ResolutionFlow.csproj +++ b/src/coreclr/tests/src/Loader/binding/tracing/BinderTracingTest.ResolutionFlow.csproj @@ -1,4 +1,8 @@ + + + true + diff --git a/src/coreclr/tests/src/Regressions/assemblyref/assem.cs b/src/coreclr/tests/src/Regressions/assemblyref/assem.cs deleted file mode 100644 index 771dd7d38e32fc..00000000000000 --- a/src/coreclr/tests/src/Regressions/assemblyref/assem.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; - - -public class A -{ - public int method1() - { - return 100; - } -} diff --git a/src/coreclr/tests/src/Regressions/assemblyref/assem.csproj b/src/coreclr/tests/src/Regressions/assemblyref/assem.csproj deleted file mode 100644 index 6970a369968965..00000000000000 --- a/src/coreclr/tests/src/Regressions/assemblyref/assem.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - library - SharedLibrary - - - - - diff --git a/src/coreclr/tests/src/Regressions/assemblyref/test.cs b/src/coreclr/tests/src/Regressions/assemblyref/test.cs deleted file mode 100644 index c24e1ad565bebb..00000000000000 --- a/src/coreclr/tests/src/Regressions/assemblyref/test.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -// regression test for CoreCLR #433 -using System; - -public class Test -{ - public static int Main() - { - try - { - A obj = new A(); - - if (obj.method1() == 100) - { - Console.WriteLine("PASS"); - return 100; - } - else - { - Console.WriteLine("FAIL"); - return 101; - } - } - catch (Exception e) - { - Console.WriteLine("Caught unexpected exception: " + e); - return 102; - } - } -} diff --git a/src/coreclr/tests/src/Regressions/assemblyref/test.csproj b/src/coreclr/tests/src/Regressions/assemblyref/test.csproj deleted file mode 100644 index fc75b801b98945..00000000000000 --- a/src/coreclr/tests/src/Regressions/assemblyref/test.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - Exe - 1 - - - - - - - {946AE2D9-F656-4771-81DB-6D02EEEEFFCB} - assem - - - diff --git a/src/coreclr/tests/src/Regressions/common/AboveStackLimit.cs b/src/coreclr/tests/src/Regressions/common/AboveStackLimit.cs deleted file mode 100644 index ef8507a84c361b..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/AboveStackLimit.cs +++ /dev/null @@ -1,16234 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; - -class Test{ - public static int Main(){ - int retVal; - - TestLibrary.TestFramework.BeginTestCase("Jitting a large method"); - - TestLibrary.TestFramework.BeginScenario("Jitting ~8099 arguments"); - - try{ - Method( -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31, -32, -33, -34, -35, -36, -37, -38, -39, -40, -41, -42, -43, -44, -45, -46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -57, -58, -59, -60, -61, -62, -63, -64, -65, -66, -67, -68, -69, -70, -71, -72, -73, -74, -75, -76, -77, -78, -79, -80, -81, -82, -83, -84, -85, -86, -87, -88, -89, -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, -100, -101, -102, -103, -104, -105, -106, -107, -108, -109, -110, -111, -112, -113, -114, -115, -116, -117, -118, -119, -120, -121, -122, -123, -124, -125, -126, -127, -128, -129, -130, -131, -132, -133, -134, -135, -136, -137, -138, -139, -140, -141, -142, -143, -144, -145, -146, -147, -148, -149, -150, -151, -152, -153, -154, -155, -156, -157, -158, -159, -160, -161, -162, -163, -164, -165, -166, -167, -168, -169, -170, -171, -172, -173, -174, -175, -176, -177, -178, -179, -180, -181, -182, -183, -184, -185, -186, -187, -188, -189, -190, -191, -192, -193, -194, -195, -196, -197, -198, -199, -200, -201, -202, -203, -204, -205, -206, -207, -208, -209, -210, -211, -212, -213, -214, -215, -216, -217, -218, -219, -220, -221, -222, -223, -224, -225, -226, -227, -228, -229, -230, -231, -232, -233, -234, -235, -236, -237, -238, -239, -240, -241, -242, -243, -244, -245, -246, -247, -248, -249, -250, -251, -252, -253, -254, -255, -256, -257, -258, -259, -260, -261, -262, -263, -264, -265, -266, -267, -268, -269, -270, -271, -272, -273, -274, -275, -276, -277, -278, -279, -280, -281, -282, -283, -284, -285, -286, -287, -288, -289, -290, -291, -292, -293, -294, -295, -296, -297, -298, -299, -300, -301, -302, -303, -304, -305, -306, -307, -308, -309, -310, -311, -312, -313, -314, -315, -316, -317, -318, -319, -320, -321, -322, -323, -324, -325, -326, -327, -328, -329, -330, -331, -332, -333, -334, -335, -336, -337, -338, -339, -340, -341, -342, -343, -344, -345, -346, -347, -348, -349, -350, -351, -352, -353, -354, -355, -356, -357, -358, -359, -360, -361, -362, -363, -364, -365, -366, -367, -368, -369, -370, -371, -372, -373, -374, -375, -376, -377, -378, -379, -380, -381, -382, -383, -384, -385, -386, -387, -388, -389, -390, -391, -392, -393, -394, -395, -396, -397, -398, -399, -400, -401, -402, -403, -404, -405, -406, -407, -408, -409, -410, -411, -412, -413, -414, -415, -416, -417, -418, -419, -420, -421, -422, -423, -424, -425, -426, -427, -428, -429, -430, -431, -432, -433, -434, -435, -436, -437, -438, -439, -440, -441, -442, -443, -444, -445, -446, -447, -448, -449, -450, -451, -452, -453, -454, -455, -456, -457, -458, -459, -460, -461, -462, -463, -464, -465, -466, -467, -468, -469, -470, -471, -472, -473, -474, -475, -476, -477, -478, -479, -480, -481, -482, -483, -484, -485, -486, -487, -488, -489, -490, -491, -492, -493, -494, -495, -496, -497, -498, -499, -500, -501, -502, -503, -504, -505, -506, -507, -508, -509, -510, -511, -512, -513, -514, -515, -516, -517, -518, -519, -520, -521, -522, -523, -524, -525, -526, -527, -528, -529, -530, -531, -532, -533, -534, -535, -536, -537, -538, -539, -540, -541, -542, -543, -544, -545, -546, -547, -548, -549, -550, -551, -552, -553, -554, -555, -556, -557, -558, -559, -560, -561, -562, -563, -564, -565, -566, -567, -568, -569, -570, -571, -572, -573, -574, -575, -576, -577, -578, -579, -580, -581, -582, -583, -584, -585, -586, -587, -588, -589, -590, -591, -592, -593, -594, -595, -596, -597, -598, -599, -600, -601, -602, -603, -604, -605, -606, -607, -608, -609, -610, -611, -612, -613, -614, -615, -616, -617, -618, -619, -620, -621, -622, -623, -624, -625, -626, -627, -628, -629, -630, -631, -632, -633, -634, -635, -636, -637, -638, -639, -640, -641, -642, -643, -644, -645, -646, -647, -648, -649, -650, -651, -652, -653, -654, -655, -656, -657, -658, -659, -660, -661, -662, -663, -664, -665, -666, -667, -668, -669, -670, -671, -672, -673, -674, -675, -676, -677, -678, -679, -680, -681, -682, -683, -684, -685, -686, -687, -688, -689, -690, -691, -692, -693, -694, -695, -696, -697, -698, -699, -700, -701, -702, -703, -704, -705, -706, -707, -708, -709, -710, -711, -712, -713, -714, -715, -716, -717, -718, -719, -720, -721, -722, -723, -724, -725, -726, -727, -728, -729, -730, -731, -732, -733, -734, -735, -736, -737, -738, -739, -740, -741, -742, -743, -744, -745, -746, -747, -748, -749, -750, -751, -752, -753, -754, -755, -756, -757, -758, -759, -760, -761, -762, -763, -764, -765, -766, -767, -768, -769, -770, -771, -772, -773, -774, -775, -776, -777, -778, -779, -780, -781, -782, -783, -784, -785, -786, -787, -788, -789, -790, -791, -792, -793, -794, -795, -796, -797, -798, -799, -800, -801, -802, -803, -804, -805, -806, -807, -808, -809, -810, -811, -812, -813, -814, -815, -816, -817, -818, -819, -820, -821, -822, -823, -824, -825, -826, -827, -828, -829, -830, -831, -832, -833, -834, -835, -836, -837, -838, -839, -840, -841, -842, -843, -844, -845, -846, -847, -848, -849, -850, -851, -852, -853, -854, -855, -856, -857, -858, -859, -860, -861, -862, -863, -864, -865, -866, -867, -868, -869, -870, -871, -872, -873, -874, -875, -876, -877, -878, -879, -880, -881, -882, -883, -884, -885, -886, -887, -888, -889, -890, -891, -892, -893, -894, -895, -896, -897, -898, -899, -900, -901, -902, -903, -904, -905, -906, -907, -908, -909, -910, -911, -912, -913, -914, -915, -916, -917, -918, -919, -920, -921, -922, -923, -924, -925, -926, -927, -928, -929, -930, -931, -932, -933, -934, -935, -936, -937, -938, -939, -940, -941, -942, -943, -944, -945, -946, -947, -948, -949, -950, -951, -952, -953, -954, -955, -956, -957, -958, -959, -960, -961, -962, -963, -964, -965, -966, -967, -968, -969, -970, -971, -972, -973, -974, -975, -976, -977, -978, -979, -980, -981, -982, -983, -984, -985, -986, -987, -988, -989, -990, -991, -992, -993, -994, -995, -996, -997, -998, -999, -1000, -1001, -1002, -1003, -1004, -1005, -1006, -1007, -1008, -1009, -1010, -1011, -1012, -1013, -1014, -1015, -1016, -1017, -1018, -1019, -1020, -1021, -1022, -1023, -1024, -1025, -1026, -1027, -1028, -1029, -1030, -1031, -1032, -1033, -1034, -1035, -1036, -1037, -1038, -1039, -1040, -1041, -1042, -1043, -1044, -1045, -1046, -1047, -1048, -1049, -1050, -1051, -1052, -1053, -1054, -1055, -1056, -1057, -1058, -1059, -1060, -1061, -1062, -1063, -1064, -1065, -1066, -1067, -1068, -1069, -1070, -1071, -1072, -1073, -1074, -1075, -1076, -1077, -1078, -1079, -1080, -1081, -1082, -1083, -1084, -1085, -1086, -1087, -1088, -1089, -1090, -1091, -1092, -1093, -1094, -1095, -1096, -1097, -1098, -1099, -1100, -1101, -1102, -1103, -1104, -1105, -1106, -1107, -1108, -1109, -1110, -1111, -1112, -1113, -1114, -1115, -1116, -1117, -1118, -1119, -1120, -1121, -1122, -1123, -1124, -1125, -1126, -1127, -1128, -1129, -1130, -1131, -1132, -1133, -1134, -1135, -1136, -1137, -1138, -1139, -1140, -1141, -1142, -1143, -1144, -1145, -1146, -1147, -1148, -1149, -1150, -1151, -1152, -1153, -1154, -1155, -1156, -1157, -1158, -1159, -1160, -1161, -1162, -1163, -1164, -1165, -1166, -1167, -1168, -1169, -1170, -1171, -1172, -1173, -1174, -1175, -1176, -1177, -1178, -1179, -1180, -1181, -1182, -1183, -1184, -1185, -1186, -1187, -1188, -1189, -1190, -1191, -1192, -1193, -1194, -1195, -1196, -1197, -1198, -1199, -1200, -1201, -1202, -1203, -1204, -1205, -1206, -1207, -1208, -1209, -1210, -1211, -1212, -1213, -1214, -1215, -1216, -1217, -1218, -1219, -1220, -1221, -1222, -1223, -1224, -1225, -1226, -1227, -1228, -1229, -1230, -1231, -1232, -1233, -1234, -1235, -1236, -1237, -1238, -1239, -1240, -1241, -1242, -1243, -1244, -1245, -1246, -1247, -1248, -1249, -1250, -1251, -1252, -1253, -1254, -1255, -1256, -1257, -1258, -1259, -1260, -1261, -1262, -1263, -1264, -1265, -1266, -1267, -1268, -1269, -1270, -1271, -1272, -1273, -1274, -1275, -1276, -1277, -1278, -1279, -1280, -1281, -1282, -1283, -1284, -1285, -1286, -1287, -1288, -1289, -1290, -1291, -1292, -1293, -1294, -1295, -1296, -1297, -1298, -1299, -1300, -1301, -1302, -1303, -1304, -1305, -1306, -1307, -1308, -1309, -1310, -1311, -1312, -1313, -1314, -1315, -1316, -1317, -1318, -1319, -1320, -1321, -1322, -1323, -1324, -1325, -1326, -1327, -1328, -1329, -1330, -1331, -1332, -1333, -1334, -1335, -1336, -1337, -1338, -1339, -1340, -1341, -1342, -1343, -1344, -1345, -1346, -1347, -1348, -1349, -1350, -1351, -1352, -1353, -1354, -1355, -1356, -1357, -1358, -1359, -1360, -1361, -1362, -1363, -1364, -1365, -1366, -1367, -1368, -1369, -1370, -1371, -1372, -1373, -1374, -1375, -1376, -1377, -1378, -1379, -1380, -1381, -1382, -1383, -1384, -1385, -1386, -1387, -1388, -1389, -1390, -1391, -1392, -1393, -1394, -1395, -1396, -1397, -1398, -1399, -1400, -1401, -1402, -1403, -1404, -1405, -1406, -1407, -1408, -1409, -1410, -1411, -1412, -1413, -1414, -1415, -1416, -1417, -1418, -1419, -1420, -1421, -1422, -1423, -1424, -1425, -1426, -1427, -1428, -1429, -1430, -1431, -1432, -1433, -1434, -1435, -1436, -1437, -1438, -1439, -1440, -1441, -1442, -1443, -1444, -1445, -1446, -1447, -1448, -1449, -1450, -1451, -1452, -1453, -1454, -1455, -1456, -1457, -1458, -1459, -1460, -1461, -1462, -1463, -1464, -1465, -1466, -1467, -1468, -1469, -1470, -1471, -1472, -1473, -1474, -1475, -1476, -1477, -1478, -1479, -1480, -1481, -1482, -1483, -1484, -1485, -1486, -1487, -1488, -1489, -1490, -1491, -1492, -1493, -1494, -1495, -1496, -1497, -1498, -1499, -1500, -1501, -1502, -1503, -1504, -1505, -1506, -1507, -1508, -1509, -1510, -1511, -1512, -1513, -1514, -1515, -1516, -1517, -1518, -1519, -1520, -1521, -1522, -1523, -1524, -1525, -1526, -1527, -1528, -1529, -1530, -1531, -1532, -1533, -1534, -1535, -1536, -1537, -1538, -1539, -1540, -1541, -1542, -1543, -1544, -1545, -1546, -1547, -1548, -1549, -1550, -1551, -1552, -1553, -1554, -1555, -1556, -1557, -1558, -1559, -1560, -1561, -1562, -1563, -1564, -1565, -1566, -1567, -1568, -1569, -1570, -1571, -1572, -1573, -1574, -1575, -1576, -1577, -1578, -1579, -1580, -1581, -1582, -1583, -1584, -1585, -1586, -1587, -1588, -1589, -1590, -1591, -1592, -1593, -1594, -1595, -1596, -1597, -1598, -1599, -1600, -1601, -1602, -1603, -1604, -1605, -1606, -1607, -1608, -1609, -1610, -1611, -1612, -1613, -1614, -1615, -1616, -1617, -1618, -1619, -1620, -1621, -1622, -1623, -1624, -1625, -1626, -1627, -1628, -1629, -1630, -1631, -1632, -1633, -1634, -1635, -1636, -1637, -1638, -1639, -1640, -1641, -1642, -1643, -1644, -1645, -1646, -1647, -1648, -1649, -1650, -1651, -1652, -1653, -1654, -1655, -1656, -1657, -1658, -1659, -1660, -1661, -1662, -1663, -1664, -1665, -1666, -1667, -1668, -1669, -1670, -1671, -1672, -1673, -1674, -1675, -1676, -1677, -1678, -1679, -1680, -1681, -1682, -1683, -1684, -1685, -1686, -1687, -1688, -1689, -1690, -1691, -1692, -1693, -1694, -1695, -1696, -1697, -1698, -1699, -1700, -1701, -1702, -1703, -1704, -1705, -1706, -1707, -1708, -1709, -1710, -1711, -1712, -1713, -1714, -1715, -1716, -1717, -1718, -1719, -1720, -1721, -1722, -1723, -1724, -1725, -1726, -1727, -1728, -1729, -1730, -1731, -1732, -1733, -1734, -1735, -1736, -1737, -1738, -1739, -1740, -1741, -1742, -1743, -1744, -1745, -1746, -1747, -1748, -1749, -1750, -1751, -1752, -1753, -1754, -1755, -1756, -1757, -1758, -1759, -1760, -1761, -1762, -1763, -1764, -1765, -1766, -1767, -1768, -1769, -1770, -1771, -1772, -1773, -1774, -1775, -1776, -1777, -1778, -1779, -1780, -1781, -1782, -1783, -1784, -1785, -1786, -1787, -1788, -1789, -1790, -1791, -1792, -1793, -1794, -1795, -1796, -1797, -1798, -1799, -1800, -1801, -1802, -1803, -1804, -1805, -1806, -1807, -1808, -1809, -1810, -1811, -1812, -1813, -1814, -1815, -1816, -1817, -1818, -1819, -1820, -1821, -1822, -1823, -1824, -1825, -1826, -1827, -1828, -1829, -1830, -1831, -1832, -1833, -1834, -1835, -1836, -1837, -1838, -1839, -1840, -1841, -1842, -1843, -1844, -1845, -1846, -1847, -1848, -1849, -1850, -1851, -1852, -1853, -1854, -1855, -1856, -1857, -1858, -1859, -1860, -1861, -1862, -1863, -1864, -1865, -1866, -1867, -1868, -1869, -1870, -1871, -1872, -1873, -1874, -1875, -1876, -1877, -1878, -1879, -1880, -1881, -1882, -1883, -1884, -1885, -1886, -1887, -1888, -1889, -1890, -1891, -1892, -1893, -1894, -1895, -1896, -1897, -1898, -1899, -1900, -1901, -1902, -1903, -1904, -1905, -1906, -1907, -1908, -1909, -1910, -1911, -1912, -1913, -1914, -1915, -1916, -1917, -1918, -1919, -1920, -1921, -1922, -1923, -1924, -1925, -1926, -1927, -1928, -1929, -1930, -1931, -1932, -1933, -1934, -1935, -1936, -1937, -1938, -1939, -1940, -1941, -1942, -1943, -1944, -1945, -1946, -1947, -1948, -1949, -1950, -1951, -1952, -1953, -1954, -1955, -1956, -1957, -1958, -1959, -1960, -1961, -1962, -1963, -1964, -1965, -1966, -1967, -1968, -1969, -1970, -1971, -1972, -1973, -1974, -1975, -1976, -1977, -1978, -1979, -1980, -1981, -1982, -1983, -1984, -1985, -1986, -1987, -1988, -1989, -1990, -1991, -1992, -1993, -1994, -1995, -1996, -1997, -1998, -1999, -2000, -2001, -2002, -2003, -2004, -2005, -2006, -2007, -2008, -2009, -2010, -2011, -2012, -2013, -2014, -2015, -2016, -2017, -2018, -2019, -2020, -2021, -2022, -2023, -2024, -2025, -2026, -2027, -2028, -2029, -2030, -2031, -2032, -2033, -2034, -2035, -2036, -2037, -2038, -2039, -2040, -2041, -2042, -2043, -2044, -2045, -2046, -2047, -2048, -2049, -2050, -2051, -2052, -2053, -2054, -2055, -2056, -2057, -2058, -2059, -2060, -2061, -2062, -2063, -2064, -2065, -2066, -2067, -2068, -2069, -2070, -2071, -2072, -2073, -2074, -2075, -2076, -2077, -2078, -2079, -2080, -2081, -2082, -2083, -2084, -2085, -2086, -2087, -2088, -2089, -2090, -2091, -2092, -2093, -2094, -2095, -2096, -2097, -2098, -2099, -2100, -2101, -2102, -2103, -2104, -2105, -2106, -2107, -2108, -2109, -2110, -2111, -2112, -2113, -2114, -2115, -2116, -2117, -2118, -2119, -2120, -2121, -2122, -2123, -2124, -2125, -2126, -2127, -2128, -2129, -2130, -2131, -2132, -2133, -2134, -2135, -2136, -2137, -2138, -2139, -2140, -2141, -2142, -2143, -2144, -2145, -2146, -2147, -2148, -2149, -2150, -2151, -2152, -2153, -2154, -2155, -2156, -2157, -2158, -2159, -2160, -2161, -2162, -2163, -2164, -2165, -2166, -2167, -2168, -2169, -2170, -2171, -2172, -2173, -2174, -2175, -2176, -2177, -2178, -2179, -2180, -2181, -2182, -2183, -2184, -2185, -2186, -2187, -2188, -2189, -2190, -2191, -2192, -2193, -2194, -2195, -2196, -2197, -2198, -2199, -2200, -2201, -2202, -2203, -2204, -2205, -2206, -2207, -2208, -2209, -2210, -2211, -2212, -2213, -2214, -2215, -2216, -2217, -2218, -2219, -2220, -2221, -2222, -2223, -2224, -2225, -2226, -2227, -2228, -2229, -2230, -2231, -2232, -2233, -2234, -2235, -2236, -2237, -2238, -2239, -2240, -2241, -2242, -2243, -2244, -2245, -2246, -2247, -2248, -2249, -2250, -2251, -2252, -2253, -2254, -2255, -2256, -2257, -2258, -2259, -2260, -2261, -2262, -2263, -2264, -2265, -2266, -2267, -2268, -2269, -2270, -2271, -2272, -2273, -2274, -2275, -2276, -2277, -2278, -2279, -2280, -2281, -2282, -2283, -2284, -2285, -2286, -2287, -2288, -2289, -2290, -2291, -2292, -2293, -2294, -2295, -2296, -2297, -2298, -2299, -2300, -2301, -2302, -2303, -2304, -2305, -2306, -2307, -2308, -2309, -2310, -2311, -2312, -2313, -2314, -2315, -2316, -2317, -2318, -2319, -2320, -2321, -2322, -2323, -2324, -2325, -2326, -2327, -2328, -2329, -2330, -2331, -2332, -2333, -2334, -2335, -2336, -2337, -2338, -2339, -2340, -2341, -2342, -2343, -2344, -2345, -2346, -2347, -2348, -2349, -2350, -2351, -2352, -2353, -2354, -2355, -2356, -2357, -2358, -2359, -2360, -2361, -2362, -2363, -2364, -2365, -2366, -2367, -2368, -2369, -2370, -2371, -2372, -2373, -2374, -2375, -2376, -2377, -2378, -2379, -2380, -2381, -2382, -2383, -2384, -2385, -2386, -2387, -2388, -2389, -2390, -2391, -2392, -2393, -2394, -2395, -2396, -2397, -2398, -2399, -2400, -2401, -2402, -2403, -2404, -2405, -2406, -2407, -2408, -2409, -2410, -2411, -2412, -2413, -2414, -2415, -2416, -2417, -2418, -2419, -2420, -2421, -2422, -2423, -2424, -2425, -2426, -2427, -2428, -2429, -2430, -2431, -2432, -2433, -2434, -2435, -2436, -2437, -2438, -2439, -2440, -2441, -2442, -2443, -2444, -2445, -2446, -2447, -2448, -2449, -2450, -2451, -2452, -2453, -2454, -2455, -2456, -2457, -2458, -2459, -2460, -2461, -2462, -2463, -2464, -2465, -2466, -2467, -2468, -2469, -2470, -2471, -2472, -2473, -2474, -2475, -2476, -2477, -2478, -2479, -2480, -2481, -2482, -2483, -2484, -2485, -2486, -2487, -2488, -2489, -2490, -2491, -2492, -2493, -2494, -2495, -2496, -2497, -2498, -2499, -2500, -2501, -2502, -2503, -2504, -2505, -2506, -2507, -2508, -2509, -2510, -2511, -2512, -2513, -2514, -2515, -2516, -2517, -2518, -2519, -2520, -2521, -2522, -2523, -2524, -2525, -2526, -2527, -2528, -2529, -2530, -2531, -2532, -2533, -2534, -2535, -2536, -2537, -2538, -2539, -2540, -2541, -2542, -2543, -2544, -2545, -2546, -2547, -2548, -2549, -2550, -2551, -2552, -2553, -2554, -2555, -2556, -2557, -2558, -2559, -2560, -2561, -2562, -2563, -2564, -2565, -2566, -2567, -2568, -2569, -2570, -2571, -2572, -2573, -2574, -2575, -2576, -2577, -2578, -2579, -2580, -2581, -2582, -2583, -2584, -2585, -2586, -2587, -2588, -2589, -2590, -2591, -2592, -2593, -2594, -2595, -2596, -2597, -2598, -2599, -2600, -2601, -2602, -2603, -2604, -2605, -2606, -2607, -2608, -2609, -2610, -2611, -2612, -2613, -2614, -2615, -2616, -2617, -2618, -2619, -2620, -2621, -2622, -2623, -2624, -2625, -2626, -2627, -2628, -2629, -2630, -2631, -2632, -2633, -2634, -2635, -2636, -2637, -2638, -2639, -2640, -2641, -2642, -2643, -2644, -2645, -2646, -2647, -2648, -2649, -2650, -2651, -2652, -2653, -2654, -2655, -2656, -2657, -2658, -2659, -2660, -2661, -2662, -2663, -2664, -2665, -2666, -2667, -2668, -2669, -2670, -2671, -2672, -2673, -2674, -2675, -2676, -2677, -2678, -2679, -2680, -2681, -2682, -2683, -2684, -2685, -2686, -2687, -2688, -2689, -2690, -2691, -2692, -2693, -2694, -2695, -2696, -2697, -2698, -2699, -2700, -2701, -2702, -2703, -2704, -2705, -2706, -2707, -2708, -2709, -2710, -2711, -2712, -2713, -2714, -2715, -2716, -2717, -2718, -2719, -2720, -2721, -2722, -2723, -2724, -2725, -2726, -2727, -2728, -2729, -2730, -2731, -2732, -2733, -2734, -2735, -2736, -2737, -2738, -2739, -2740, -2741, -2742, -2743, -2744, -2745, -2746, -2747, -2748, -2749, -2750, -2751, -2752, -2753, -2754, -2755, -2756, -2757, -2758, -2759, -2760, -2761, -2762, -2763, -2764, -2765, -2766, -2767, -2768, -2769, -2770, -2771, -2772, -2773, -2774, -2775, -2776, -2777, -2778, -2779, -2780, -2781, -2782, -2783, -2784, -2785, -2786, -2787, -2788, -2789, -2790, -2791, -2792, -2793, -2794, -2795, -2796, -2797, -2798, -2799, -2800, -2801, -2802, -2803, -2804, -2805, -2806, -2807, -2808, -2809, -2810, -2811, -2812, -2813, -2814, -2815, -2816, -2817, -2818, -2819, -2820, -2821, -2822, -2823, -2824, -2825, -2826, -2827, -2828, -2829, -2830, -2831, -2832, -2833, -2834, -2835, -2836, -2837, -2838, -2839, -2840, -2841, -2842, -2843, -2844, -2845, -2846, -2847, -2848, -2849, -2850, -2851, -2852, -2853, -2854, -2855, -2856, -2857, -2858, -2859, -2860, -2861, -2862, -2863, -2864, -2865, -2866, -2867, -2868, -2869, -2870, -2871, -2872, -2873, -2874, -2875, -2876, -2877, -2878, -2879, -2880, -2881, -2882, -2883, -2884, -2885, -2886, -2887, -2888, -2889, -2890, -2891, -2892, -2893, -2894, -2895, -2896, -2897, -2898, -2899, -2900, -2901, -2902, -2903, -2904, -2905, -2906, -2907, -2908, -2909, -2910, -2911, -2912, -2913, -2914, -2915, -2916, -2917, -2918, -2919, -2920, -2921, -2922, -2923, -2924, -2925, -2926, -2927, -2928, -2929, -2930, -2931, -2932, -2933, -2934, -2935, -2936, -2937, -2938, -2939, -2940, -2941, -2942, -2943, -2944, -2945, -2946, -2947, -2948, -2949, -2950, -2951, -2952, -2953, -2954, -2955, -2956, -2957, -2958, -2959, -2960, -2961, -2962, -2963, -2964, -2965, -2966, -2967, -2968, -2969, -2970, -2971, -2972, -2973, -2974, -2975, -2976, -2977, -2978, -2979, -2980, -2981, -2982, -2983, -2984, -2985, -2986, -2987, -2988, -2989, -2990, -2991, -2992, -2993, -2994, -2995, -2996, -2997, -2998, -2999, -3000, -3001, -3002, -3003, -3004, -3005, -3006, -3007, -3008, -3009, -3010, -3011, -3012, -3013, -3014, -3015, -3016, -3017, -3018, -3019, -3020, -3021, -3022, -3023, -3024, -3025, -3026, -3027, -3028, -3029, -3030, -3031, -3032, -3033, -3034, -3035, -3036, -3037, -3038, -3039, -3040, -3041, -3042, -3043, -3044, -3045, -3046, -3047, -3048, -3049, -3050, -3051, -3052, -3053, -3054, -3055, -3056, -3057, -3058, -3059, -3060, -3061, -3062, -3063, -3064, -3065, -3066, -3067, -3068, -3069, -3070, -3071, -3072, -3073, -3074, -3075, -3076, -3077, -3078, -3079, -3080, -3081, -3082, -3083, -3084, -3085, -3086, -3087, -3088, -3089, -3090, -3091, -3092, -3093, -3094, -3095, -3096, -3097, -3098, -3099, -3100, -3101, -3102, -3103, -3104, -3105, -3106, -3107, -3108, -3109, -3110, -3111, -3112, -3113, -3114, -3115, -3116, -3117, -3118, -3119, -3120, -3121, -3122, -3123, -3124, -3125, -3126, -3127, -3128, -3129, -3130, -3131, -3132, -3133, -3134, -3135, -3136, -3137, -3138, -3139, -3140, -3141, -3142, -3143, -3144, -3145, -3146, -3147, -3148, -3149, -3150, -3151, -3152, -3153, -3154, -3155, -3156, -3157, -3158, -3159, -3160, -3161, -3162, -3163, -3164, -3165, -3166, -3167, -3168, -3169, -3170, -3171, -3172, -3173, -3174, -3175, -3176, -3177, -3178, -3179, -3180, -3181, -3182, -3183, -3184, -3185, -3186, -3187, -3188, -3189, -3190, -3191, -3192, -3193, -3194, -3195, -3196, -3197, -3198, -3199, -3200, -3201, -3202, -3203, -3204, -3205, -3206, -3207, -3208, -3209, -3210, -3211, -3212, -3213, -3214, -3215, -3216, -3217, -3218, -3219, -3220, -3221, -3222, -3223, -3224, -3225, -3226, -3227, -3228, -3229, -3230, -3231, -3232, -3233, -3234, -3235, -3236, -3237, -3238, -3239, -3240, -3241, -3242, -3243, -3244, -3245, -3246, -3247, -3248, -3249, -3250, -3251, -3252, -3253, -3254, -3255, -3256, -3257, -3258, -3259, -3260, -3261, -3262, -3263, -3264, -3265, -3266, -3267, -3268, -3269, -3270, -3271, -3272, -3273, -3274, -3275, -3276, -3277, -3278, -3279, -3280, -3281, -3282, -3283, -3284, -3285, -3286, -3287, -3288, -3289, -3290, -3291, -3292, -3293, -3294, -3295, -3296, -3297, -3298, -3299, -3300, -3301, -3302, -3303, -3304, -3305, -3306, -3307, -3308, -3309, -3310, -3311, -3312, -3313, -3314, -3315, -3316, -3317, -3318, -3319, -3320, -3321, -3322, -3323, -3324, -3325, -3326, -3327, -3328, -3329, -3330, -3331, -3332, -3333, -3334, -3335, -3336, -3337, -3338, -3339, -3340, -3341, -3342, -3343, -3344, -3345, -3346, -3347, -3348, -3349, -3350, -3351, -3352, -3353, -3354, -3355, -3356, -3357, -3358, -3359, -3360, -3361, -3362, -3363, -3364, -3365, -3366, -3367, -3368, -3369, -3370, -3371, -3372, -3373, -3374, -3375, -3376, -3377, -3378, -3379, -3380, -3381, -3382, -3383, -3384, -3385, -3386, -3387, -3388, -3389, -3390, -3391, -3392, -3393, -3394, -3395, -3396, -3397, -3398, -3399, -3400, -3401, -3402, -3403, -3404, -3405, -3406, -3407, -3408, -3409, -3410, -3411, -3412, -3413, -3414, -3415, -3416, -3417, -3418, -3419, -3420, -3421, -3422, -3423, -3424, -3425, -3426, -3427, -3428, -3429, -3430, -3431, -3432, -3433, -3434, -3435, -3436, -3437, -3438, -3439, -3440, -3441, -3442, -3443, -3444, -3445, -3446, -3447, -3448, -3449, -3450, -3451, -3452, -3453, -3454, -3455, -3456, -3457, -3458, -3459, -3460, -3461, -3462, -3463, -3464, -3465, -3466, -3467, -3468, -3469, -3470, -3471, -3472, -3473, -3474, -3475, -3476, -3477, -3478, -3479, -3480, -3481, -3482, -3483, -3484, -3485, -3486, -3487, -3488, -3489, -3490, -3491, -3492, -3493, -3494, -3495, -3496, -3497, -3498, -3499, -3500, -3501, -3502, -3503, -3504, -3505, -3506, -3507, -3508, -3509, -3510, -3511, -3512, -3513, -3514, -3515, -3516, -3517, -3518, -3519, -3520, -3521, -3522, -3523, -3524, -3525, -3526, -3527, -3528, -3529, -3530, -3531, -3532, -3533, -3534, -3535, -3536, -3537, -3538, -3539, -3540, -3541, -3542, -3543, -3544, -3545, -3546, -3547, -3548, -3549, -3550, -3551, -3552, -3553, -3554, -3555, -3556, -3557, -3558, -3559, -3560, -3561, -3562, -3563, -3564, -3565, -3566, -3567, -3568, -3569, -3570, -3571, -3572, -3573, -3574, -3575, -3576, -3577, -3578, -3579, -3580, -3581, -3582, -3583, -3584, -3585, -3586, -3587, -3588, -3589, -3590, -3591, -3592, -3593, -3594, -3595, -3596, -3597, -3598, -3599, -3600, -3601, -3602, -3603, -3604, -3605, -3606, -3607, -3608, -3609, -3610, -3611, -3612, -3613, -3614, -3615, -3616, -3617, -3618, -3619, -3620, -3621, -3622, -3623, -3624, -3625, -3626, -3627, -3628, -3629, -3630, -3631, -3632, -3633, -3634, -3635, -3636, -3637, -3638, -3639, -3640, -3641, -3642, -3643, -3644, -3645, -3646, -3647, -3648, -3649, -3650, -3651, -3652, -3653, -3654, -3655, -3656, -3657, -3658, -3659, -3660, -3661, -3662, -3663, -3664, -3665, -3666, -3667, -3668, -3669, -3670, -3671, -3672, -3673, -3674, -3675, -3676, -3677, -3678, -3679, -3680, -3681, -3682, -3683, -3684, -3685, -3686, -3687, -3688, -3689, -3690, -3691, -3692, -3693, -3694, -3695, -3696, -3697, -3698, -3699, -3700, -3701, -3702, -3703, -3704, -3705, -3706, -3707, -3708, -3709, -3710, -3711, -3712, -3713, -3714, -3715, -3716, -3717, -3718, -3719, -3720, -3721, -3722, -3723, -3724, -3725, -3726, -3727, -3728, -3729, -3730, -3731, -3732, -3733, -3734, -3735, -3736, -3737, -3738, -3739, -3740, -3741, -3742, -3743, -3744, -3745, -3746, -3747, -3748, -3749, -3750, -3751, -3752, -3753, -3754, -3755, -3756, -3757, -3758, -3759, -3760, -3761, -3762, -3763, -3764, -3765, -3766, -3767, -3768, -3769, -3770, -3771, -3772, -3773, -3774, -3775, -3776, -3777, -3778, -3779, -3780, -3781, -3782, -3783, -3784, -3785, -3786, -3787, -3788, -3789, -3790, -3791, -3792, -3793, -3794, -3795, -3796, -3797, -3798, -3799, -3800, -3801, -3802, -3803, -3804, -3805, -3806, -3807, -3808, -3809, -3810, -3811, -3812, -3813, -3814, -3815, -3816, -3817, -3818, -3819, -3820, -3821, -3822, -3823, -3824, -3825, -3826, -3827, -3828, -3829, -3830, -3831, -3832, -3833, -3834, -3835, -3836, -3837, -3838, -3839, -3840, -3841, -3842, -3843, -3844, -3845, -3846, -3847, -3848, -3849, -3850, -3851, -3852, -3853, -3854, -3855, -3856, -3857, -3858, -3859, -3860, -3861, -3862, -3863, -3864, -3865, -3866, -3867, -3868, -3869, -3870, -3871, -3872, -3873, -3874, -3875, -3876, -3877, -3878, -3879, -3880, -3881, -3882, -3883, -3884, -3885, -3886, -3887, -3888, -3889, -3890, -3891, -3892, -3893, -3894, -3895, -3896, -3897, -3898, -3899, -3900, -3901, -3902, -3903, -3904, -3905, -3906, -3907, -3908, -3909, -3910, -3911, -3912, -3913, -3914, -3915, -3916, -3917, -3918, -3919, -3920, -3921, -3922, -3923, -3924, -3925, -3926, -3927, -3928, -3929, -3930, -3931, -3932, -3933, -3934, -3935, -3936, -3937, -3938, -3939, -3940, -3941, -3942, -3943, -3944, -3945, -3946, -3947, -3948, -3949, -3950, -3951, -3952, -3953, -3954, -3955, -3956, -3957, -3958, -3959, -3960, -3961, -3962, -3963, -3964, -3965, -3966, -3967, -3968, -3969, -3970, -3971, -3972, -3973, -3974, -3975, -3976, -3977, -3978, -3979, -3980, -3981, -3982, -3983, -3984, -3985, -3986, -3987, -3988, -3989, -3990, -3991, -3992, -3993, -3994, -3995, -3996, -3997, -3998, -3999, -4000, -4001, -4002, -4003, -4004, -4005, -4006, -4007, -4008, -4009, -4010, -4011, -4012, -4013, -4014, -4015, -4016, -4017, -4018, -4019, -4020, -4021, -4022, -4023, -4024, -4025, -4026, -4027, -4028, -4029, -4030, -4031, -4032, -4033, -4034, -4035, -4036, -4037, -4038, -4039, -4040, -4041, -4042, -4043, -4044, -4045, -4046, -4047, -4048, -4049, -4050, -4051, -4052, -4053, -4054, -4055, -4056, -4057, -4058, -4059, -4060, -4061, -4062, -4063, -4064, -4065, -4066, -4067, -4068, -4069, -4070, -4071, -4072, -4073, -4074, -4075, -4076, -4077, -4078, -4079, -4080, -4081, -4082, -4083, -4084, -4085, -4086, -4087, -4088, -4089, -4090, -4091, -4092, -4093, -4094, -4095, -4096, -4097, -4098, -4099, -4100, -4101, -4102, -4103, -4104, -4105, -4106, -4107, -4108, -4109, -4110, -4111, -4112, -4113, -4114, -4115, -4116, -4117, -4118, -4119, -4120, -4121, -4122, -4123, -4124, -4125, -4126, -4127, -4128, -4129, -4130, -4131, -4132, -4133, -4134, -4135, -4136, -4137, -4138, -4139, -4140, -4141, -4142, -4143, -4144, -4145, -4146, -4147, -4148, -4149, -4150, -4151, -4152, -4153, -4154, -4155, -4156, -4157, -4158, -4159, -4160, -4161, -4162, -4163, -4164, -4165, -4166, -4167, -4168, -4169, -4170, -4171, -4172, -4173, -4174, -4175, -4176, -4177, -4178, -4179, -4180, -4181, -4182, -4183, -4184, -4185, -4186, -4187, -4188, -4189, -4190, -4191, -4192, -4193, -4194, -4195, -4196, -4197, -4198, -4199, -4200, -4201, -4202, -4203, -4204, -4205, -4206, -4207, -4208, -4209, -4210, -4211, -4212, -4213, -4214, -4215, -4216, -4217, -4218, -4219, -4220, -4221, -4222, -4223, -4224, -4225, -4226, -4227, -4228, -4229, -4230, -4231, -4232, -4233, -4234, -4235, -4236, -4237, -4238, -4239, -4240, -4241, -4242, -4243, -4244, -4245, -4246, -4247, -4248, -4249, -4250, -4251, -4252, -4253, -4254, -4255, -4256, -4257, -4258, -4259, -4260, -4261, -4262, -4263, -4264, -4265, -4266, -4267, -4268, -4269, -4270, -4271, -4272, -4273, -4274, -4275, -4276, -4277, -4278, -4279, -4280, -4281, -4282, -4283, -4284, -4285, -4286, -4287, -4288, -4289, -4290, -4291, -4292, -4293, -4294, -4295, -4296, -4297, -4298, -4299, -4300, -4301, -4302, -4303, -4304, -4305, -4306, -4307, -4308, -4309, -4310, -4311, -4312, -4313, -4314, -4315, -4316, -4317, -4318, -4319, -4320, -4321, -4322, -4323, -4324, -4325, -4326, -4327, -4328, -4329, -4330, -4331, -4332, -4333, -4334, -4335, -4336, -4337, -4338, -4339, -4340, -4341, -4342, -4343, -4344, -4345, -4346, -4347, -4348, -4349, -4350, -4351, -4352, -4353, -4354, -4355, -4356, -4357, -4358, -4359, -4360, -4361, -4362, -4363, -4364, -4365, -4366, -4367, -4368, -4369, -4370, -4371, -4372, -4373, -4374, -4375, -4376, -4377, -4378, -4379, -4380, -4381, -4382, -4383, -4384, -4385, -4386, -4387, -4388, -4389, -4390, -4391, -4392, -4393, -4394, -4395, -4396, -4397, -4398, -4399, -4400, -4401, -4402, -4403, -4404, -4405, -4406, -4407, -4408, -4409, -4410, -4411, -4412, -4413, -4414, -4415, -4416, -4417, -4418, -4419, -4420, -4421, -4422, -4423, -4424, -4425, -4426, -4427, -4428, -4429, -4430, -4431, -4432, -4433, -4434, -4435, -4436, -4437, -4438, -4439, -4440, -4441, -4442, -4443, -4444, -4445, -4446, -4447, -4448, -4449, -4450, -4451, -4452, -4453, -4454, -4455, -4456, -4457, -4458, -4459, -4460, -4461, -4462, -4463, -4464, -4465, -4466, -4467, -4468, -4469, -4470, -4471, -4472, -4473, -4474, -4475, -4476, -4477, -4478, -4479, -4480, -4481, -4482, -4483, -4484, -4485, -4486, -4487, -4488, -4489, -4490, -4491, -4492, -4493, -4494, -4495, -4496, -4497, -4498, -4499, -4500, -4501, -4502, -4503, -4504, -4505, -4506, -4507, -4508, -4509, -4510, -4511, -4512, -4513, -4514, -4515, -4516, -4517, -4518, -4519, -4520, -4521, -4522, -4523, -4524, -4525, -4526, -4527, -4528, -4529, -4530, -4531, -4532, -4533, -4534, -4535, -4536, -4537, -4538, -4539, -4540, -4541, -4542, -4543, -4544, -4545, -4546, -4547, -4548, -4549, -4550, -4551, -4552, -4553, -4554, -4555, -4556, -4557, -4558, -4559, -4560, -4561, -4562, -4563, -4564, -4565, -4566, -4567, -4568, -4569, -4570, -4571, -4572, -4573, -4574, -4575, -4576, -4577, -4578, -4579, -4580, -4581, -4582, -4583, -4584, -4585, -4586, -4587, -4588, -4589, -4590, -4591, -4592, -4593, -4594, -4595, -4596, -4597, -4598, -4599, -4600, -4601, -4602, -4603, -4604, -4605, -4606, -4607, -4608, -4609, -4610, -4611, -4612, -4613, -4614, -4615, -4616, -4617, -4618, -4619, -4620, -4621, -4622, -4623, -4624, -4625, -4626, -4627, -4628, -4629, -4630, -4631, -4632, -4633, -4634, -4635, -4636, -4637, -4638, -4639, -4640, -4641, -4642, -4643, -4644, -4645, -4646, -4647, -4648, -4649, -4650, -4651, -4652, -4653, -4654, -4655, -4656, -4657, -4658, -4659, -4660, -4661, -4662, -4663, -4664, -4665, -4666, -4667, -4668, -4669, -4670, -4671, -4672, -4673, -4674, -4675, -4676, -4677, -4678, -4679, -4680, -4681, -4682, -4683, -4684, -4685, -4686, -4687, -4688, -4689, -4690, -4691, -4692, -4693, -4694, -4695, -4696, -4697, -4698, -4699, -4700, -4701, -4702, -4703, -4704, -4705, -4706, -4707, -4708, -4709, -4710, -4711, -4712, -4713, -4714, -4715, -4716, -4717, -4718, -4719, -4720, -4721, -4722, -4723, -4724, -4725, -4726, -4727, -4728, -4729, -4730, -4731, -4732, -4733, -4734, -4735, -4736, -4737, -4738, -4739, -4740, -4741, -4742, -4743, -4744, -4745, -4746, -4747, -4748, -4749, -4750, -4751, -4752, -4753, -4754, -4755, -4756, -4757, -4758, -4759, -4760, -4761, -4762, -4763, -4764, -4765, -4766, -4767, -4768, -4769, -4770, -4771, -4772, -4773, -4774, -4775, -4776, -4777, -4778, -4779, -4780, -4781, -4782, -4783, -4784, -4785, -4786, -4787, -4788, -4789, -4790, -4791, -4792, -4793, -4794, -4795, -4796, -4797, -4798, -4799, -4800, -4801, -4802, -4803, -4804, -4805, -4806, -4807, -4808, -4809, -4810, -4811, -4812, -4813, -4814, -4815, -4816, -4817, -4818, -4819, -4820, -4821, -4822, -4823, -4824, -4825, -4826, -4827, -4828, -4829, -4830, -4831, -4832, -4833, -4834, -4835, -4836, -4837, -4838, -4839, -4840, -4841, -4842, -4843, -4844, -4845, -4846, -4847, -4848, -4849, -4850, -4851, -4852, -4853, -4854, -4855, -4856, -4857, -4858, -4859, -4860, -4861, -4862, -4863, -4864, -4865, -4866, -4867, -4868, -4869, -4870, -4871, -4872, -4873, -4874, -4875, -4876, -4877, -4878, -4879, -4880, -4881, -4882, -4883, -4884, -4885, -4886, -4887, -4888, -4889, -4890, -4891, -4892, -4893, -4894, -4895, -4896, -4897, -4898, -4899, -4900, -4901, -4902, -4903, -4904, -4905, -4906, -4907, -4908, -4909, -4910, -4911, -4912, -4913, -4914, -4915, -4916, -4917, -4918, -4919, -4920, -4921, -4922, -4923, -4924, -4925, -4926, -4927, -4928, -4929, -4930, -4931, -4932, -4933, -4934, -4935, -4936, -4937, -4938, -4939, -4940, -4941, -4942, -4943, -4944, -4945, -4946, -4947, -4948, -4949, -4950, -4951, -4952, -4953, -4954, -4955, -4956, -4957, -4958, -4959, -4960, -4961, -4962, -4963, -4964, -4965, -4966, -4967, -4968, -4969, -4970, -4971, -4972, -4973, -4974, -4975, -4976, -4977, -4978, -4979, -4980, -4981, -4982, -4983, -4984, -4985, -4986, -4987, -4988, -4989, -4990, -4991, -4992, -4993, -4994, -4995, -4996, -4997, -4998, -4999, -5000, -5001, -5002, -5003, -5004, -5005, -5006, -5007, -5008, -5009, -5010, -5011, -5012, -5013, -5014, -5015, -5016, -5017, -5018, -5019, -5020, -5021, -5022, -5023, -5024, -5025, -5026, -5027, -5028, -5029, -5030, -5031, -5032, -5033, -5034, -5035, -5036, -5037, -5038, -5039, -5040, -5041, -5042, -5043, -5044, -5045, -5046, -5047, -5048, -5049, -5050, -5051, -5052, -5053, -5054, -5055, -5056, -5057, -5058, -5059, -5060, -5061, -5062, -5063, -5064, -5065, -5066, -5067, -5068, -5069, -5070, -5071, -5072, -5073, -5074, -5075, -5076, -5077, -5078, -5079, -5080, -5081, -5082, -5083, -5084, -5085, -5086, -5087, -5088, -5089, -5090, -5091, -5092, -5093, -5094, -5095, -5096, -5097, -5098, -5099, -5100, -5101, -5102, -5103, -5104, -5105, -5106, -5107, -5108, -5109, -5110, -5111, -5112, -5113, -5114, -5115, -5116, -5117, -5118, -5119, -5120, -5121, -5122, -5123, -5124, -5125, -5126, -5127, -5128, -5129, -5130, -5131, -5132, -5133, -5134, -5135, -5136, -5137, -5138, -5139, -5140, -5141, -5142, -5143, -5144, -5145, -5146, -5147, -5148, -5149, -5150, -5151, -5152, -5153, -5154, -5155, -5156, -5157, -5158, -5159, -5160, -5161, -5162, -5163, -5164, -5165, -5166, -5167, -5168, -5169, -5170, -5171, -5172, -5173, -5174, -5175, -5176, -5177, -5178, -5179, -5180, -5181, -5182, -5183, -5184, -5185, -5186, -5187, -5188, -5189, -5190, -5191, -5192, -5193, -5194, -5195, -5196, -5197, -5198, -5199, -5200, -5201, -5202, -5203, -5204, -5205, -5206, -5207, -5208, -5209, -5210, -5211, -5212, -5213, -5214, -5215, -5216, -5217, -5218, -5219, -5220, -5221, -5222, -5223, -5224, -5225, -5226, -5227, -5228, -5229, -5230, -5231, -5232, -5233, -5234, -5235, -5236, -5237, -5238, -5239, -5240, -5241, -5242, -5243, -5244, -5245, -5246, -5247, -5248, -5249, -5250, -5251, -5252, -5253, -5254, -5255, -5256, -5257, -5258, -5259, -5260, -5261, -5262, -5263, -5264, -5265, -5266, -5267, -5268, -5269, -5270, -5271, -5272, -5273, -5274, -5275, -5276, -5277, -5278, -5279, -5280, -5281, -5282, -5283, -5284, -5285, -5286, -5287, -5288, -5289, -5290, -5291, -5292, -5293, -5294, -5295, -5296, -5297, -5298, -5299, -5300, -5301, -5302, -5303, -5304, -5305, -5306, -5307, -5308, -5309, -5310, -5311, -5312, -5313, -5314, -5315, -5316, -5317, -5318, -5319, -5320, -5321, -5322, -5323, -5324, -5325, -5326, -5327, -5328, -5329, -5330, -5331, -5332, -5333, -5334, -5335, -5336, -5337, -5338, -5339, -5340, -5341, -5342, -5343, -5344, -5345, -5346, -5347, -5348, -5349, -5350, -5351, -5352, -5353, -5354, -5355, -5356, -5357, -5358, -5359, -5360, -5361, -5362, -5363, -5364, -5365, -5366, -5367, -5368, -5369, -5370, -5371, -5372, -5373, -5374, -5375, -5376, -5377, -5378, -5379, -5380, -5381, -5382, -5383, -5384, -5385, -5386, -5387, -5388, -5389, -5390, -5391, -5392, -5393, -5394, -5395, -5396, -5397, -5398, -5399, -5400, -5401, -5402, -5403, -5404, -5405, -5406, -5407, -5408, -5409, -5410, -5411, -5412, -5413, -5414, -5415, -5416, -5417, -5418, -5419, -5420, -5421, -5422, -5423, -5424, -5425, -5426, -5427, -5428, -5429, -5430, -5431, -5432, -5433, -5434, -5435, -5436, -5437, -5438, -5439, -5440, -5441, -5442, -5443, -5444, -5445, -5446, -5447, -5448, -5449, -5450, -5451, -5452, -5453, -5454, -5455, -5456, -5457, -5458, -5459, -5460, -5461, -5462, -5463, -5464, -5465, -5466, -5467, -5468, -5469, -5470, -5471, -5472, -5473, -5474, -5475, -5476, -5477, -5478, -5479, -5480, -5481, -5482, -5483, -5484, -5485, -5486, -5487, -5488, -5489, -5490, -5491, -5492, -5493, -5494, -5495, -5496, -5497, -5498, -5499, -5500, -5501, -5502, -5503, -5504, -5505, -5506, -5507, -5508, -5509, -5510, -5511, -5512, -5513, -5514, -5515, -5516, -5517, -5518, -5519, -5520, -5521, -5522, -5523, -5524, -5525, -5526, -5527, -5528, -5529, -5530, -5531, -5532, -5533, -5534, -5535, -5536, -5537, -5538, -5539, -5540, -5541, -5542, -5543, -5544, -5545, -5546, -5547, -5548, -5549, -5550, -5551, -5552, -5553, -5554, -5555, -5556, -5557, -5558, -5559, -5560, -5561, -5562, -5563, -5564, -5565, -5566, -5567, -5568, -5569, -5570, -5571, -5572, -5573, -5574, -5575, -5576, -5577, -5578, -5579, -5580, -5581, -5582, -5583, -5584, -5585, -5586, -5587, -5588, -5589, -5590, -5591, -5592, -5593, -5594, -5595, -5596, -5597, -5598, -5599, -5600, -5601, -5602, -5603, -5604, -5605, -5606, -5607, -5608, -5609, -5610, -5611, -5612, -5613, -5614, -5615, -5616, -5617, -5618, -5619, -5620, -5621, -5622, -5623, -5624, -5625, -5626, -5627, -5628, -5629, -5630, -5631, -5632, -5633, -5634, -5635, -5636, -5637, -5638, -5639, -5640, -5641, -5642, -5643, -5644, -5645, -5646, -5647, -5648, -5649, -5650, -5651, -5652, -5653, -5654, -5655, -5656, -5657, -5658, -5659, -5660, -5661, -5662, -5663, -5664, -5665, -5666, -5667, -5668, -5669, -5670, -5671, -5672, -5673, -5674, -5675, -5676, -5677, -5678, -5679, -5680, -5681, -5682, -5683, -5684, -5685, -5686, -5687, -5688, -5689, -5690, -5691, -5692, -5693, -5694, -5695, -5696, -5697, -5698, -5699, -5700, -5701, -5702, -5703, -5704, -5705, -5706, -5707, -5708, -5709, -5710, -5711, -5712, -5713, -5714, -5715, -5716, -5717, -5718, -5719, -5720, -5721, -5722, -5723, -5724, -5725, -5726, -5727, -5728, -5729, -5730, -5731, -5732, -5733, -5734, -5735, -5736, -5737, -5738, -5739, -5740, -5741, -5742, -5743, -5744, -5745, -5746, -5747, -5748, -5749, -5750, -5751, -5752, -5753, -5754, -5755, -5756, -5757, -5758, -5759, -5760, -5761, -5762, -5763, -5764, -5765, -5766, -5767, -5768, -5769, -5770, -5771, -5772, -5773, -5774, -5775, -5776, -5777, -5778, -5779, -5780, -5781, -5782, -5783, -5784, -5785, -5786, -5787, -5788, -5789, -5790, -5791, -5792, -5793, -5794, -5795, -5796, -5797, -5798, -5799, -5800, -5801, -5802, -5803, -5804, -5805, -5806, -5807, -5808, -5809, -5810, -5811, -5812, -5813, -5814, -5815, -5816, -5817, -5818, -5819, -5820, -5821, -5822, -5823, -5824, -5825, -5826, -5827, -5828, -5829, -5830, -5831, -5832, -5833, -5834, -5835, -5836, -5837, -5838, -5839, -5840, -5841, -5842, -5843, -5844, -5845, -5846, -5847, -5848, -5849, -5850, -5851, -5852, -5853, -5854, -5855, -5856, -5857, -5858, -5859, -5860, -5861, -5862, -5863, -5864, -5865, -5866, -5867, -5868, -5869, -5870, -5871, -5872, -5873, -5874, -5875, -5876, -5877, -5878, -5879, -5880, -5881, -5882, -5883, -5884, -5885, -5886, -5887, -5888, -5889, -5890, -5891, -5892, -5893, -5894, -5895, -5896, -5897, -5898, -5899, -5900, -5901, -5902, -5903, -5904, -5905, -5906, -5907, -5908, -5909, -5910, -5911, -5912, -5913, -5914, -5915, -5916, -5917, -5918, -5919, -5920, -5921, -5922, -5923, -5924, -5925, -5926, -5927, -5928, -5929, -5930, -5931, -5932, -5933, -5934, -5935, -5936, -5937, -5938, -5939, -5940, -5941, -5942, -5943, -5944, -5945, -5946, -5947, -5948, -5949, -5950, -5951, -5952, -5953, -5954, -5955, -5956, -5957, -5958, -5959, -5960, -5961, -5962, -5963, -5964, -5965, -5966, -5967, -5968, -5969, -5970, -5971, -5972, -5973, -5974, -5975, -5976, -5977, -5978, -5979, -5980, -5981, -5982, -5983, -5984, -5985, -5986, -5987, -5988, -5989, -5990, -5991, -5992, -5993, -5994, -5995, -5996, -5997, -5998, -5999, -6000, -6001, -6002, -6003, -6004, -6005, -6006, -6007, -6008, -6009, -6010, -6011, -6012, -6013, -6014, -6015, -6016, -6017, -6018, -6019, -6020, -6021, -6022, -6023, -6024, -6025, -6026, -6027, -6028, -6029, -6030, -6031, -6032, -6033, -6034, -6035, -6036, -6037, -6038, -6039, -6040, -6041, -6042, -6043, -6044, -6045, -6046, -6047, -6048, -6049, -6050, -6051, -6052, -6053, -6054, -6055, -6056, -6057, -6058, -6059, -6060, -6061, -6062, -6063, -6064, -6065, -6066, -6067, -6068, -6069, -6070, -6071, -6072, -6073, -6074, -6075, -6076, -6077, -6078, -6079, -6080, -6081, -6082, -6083, -6084, -6085, -6086, -6087, -6088, -6089, -6090, -6091, -6092, -6093, -6094, -6095, -6096, -6097, -6098, -6099, -6100, -6101, -6102, -6103, -6104, -6105, -6106, -6107, -6108, -6109, -6110, -6111, -6112, -6113, -6114, -6115, -6116, -6117, -6118, -6119, -6120, -6121, -6122, -6123, -6124, -6125, -6126, -6127, -6128, -6129, -6130, -6131, -6132, -6133, -6134, -6135, -6136, -6137, -6138, -6139, -6140, -6141, -6142, -6143, -6144, -6145, -6146, -6147, -6148, -6149, -6150, -6151, -6152, -6153, -6154, -6155, -6156, -6157, -6158, -6159, -6160, -6161, -6162, -6163, -6164, -6165, -6166, -6167, -6168, -6169, -6170, -6171, -6172, -6173, -6174, -6175, -6176, -6177, -6178, -6179, -6180, -6181, -6182, -6183, -6184, -6185, -6186, -6187, -6188, -6189, -6190, -6191, -6192, -6193, -6194, -6195, -6196, -6197, -6198, -6199, -6200, -6201, -6202, -6203, -6204, -6205, -6206, -6207, -6208, -6209, -6210, -6211, -6212, -6213, -6214, -6215, -6216, -6217, -6218, -6219, -6220, -6221, -6222, -6223, -6224, -6225, -6226, -6227, -6228, -6229, -6230, -6231, -6232, -6233, -6234, -6235, -6236, -6237, -6238, -6239, -6240, -6241, -6242, -6243, -6244, -6245, -6246, -6247, -6248, -6249, -6250, -6251, -6252, -6253, -6254, -6255, -6256, -6257, -6258, -6259, -6260, -6261, -6262, -6263, -6264, -6265, -6266, -6267, -6268, -6269, -6270, -6271, -6272, -6273, -6274, -6275, -6276, -6277, -6278, -6279, -6280, -6281, -6282, -6283, -6284, -6285, -6286, -6287, -6288, -6289, -6290, -6291, -6292, -6293, -6294, -6295, -6296, -6297, -6298, -6299, -6300, -6301, -6302, -6303, -6304, -6305, -6306, -6307, -6308, -6309, -6310, -6311, -6312, -6313, -6314, -6315, -6316, -6317, -6318, -6319, -6320, -6321, -6322, -6323, -6324, -6325, -6326, -6327, -6328, -6329, -6330, -6331, -6332, -6333, -6334, -6335, -6336, -6337, -6338, -6339, -6340, -6341, -6342, -6343, -6344, -6345, -6346, -6347, -6348, -6349, -6350, -6351, -6352, -6353, -6354, -6355, -6356, -6357, -6358, -6359, -6360, -6361, -6362, -6363, -6364, -6365, -6366, -6367, -6368, -6369, -6370, -6371, -6372, -6373, -6374, -6375, -6376, -6377, -6378, -6379, -6380, -6381, -6382, -6383, -6384, -6385, -6386, -6387, -6388, -6389, -6390, -6391, -6392, -6393, -6394, -6395, -6396, -6397, -6398, -6399, -6400, -6401, -6402, -6403, -6404, -6405, -6406, -6407, -6408, -6409, -6410, -6411, -6412, -6413, -6414, -6415, -6416, -6417, -6418, -6419, -6420, -6421, -6422, -6423, -6424, -6425, -6426, -6427, -6428, -6429, -6430, -6431, -6432, -6433, -6434, -6435, -6436, -6437, -6438, -6439, -6440, -6441, -6442, -6443, -6444, -6445, -6446, -6447, -6448, -6449, -6450, -6451, -6452, -6453, -6454, -6455, -6456, -6457, -6458, -6459, -6460, -6461, -6462, -6463, -6464, -6465, -6466, -6467, -6468, -6469, -6470, -6471, -6472, -6473, -6474, -6475, -6476, -6477, -6478, -6479, -6480, -6481, -6482, -6483, -6484, -6485, -6486, -6487, -6488, -6489, -6490, -6491, -6492, -6493, -6494, -6495, -6496, -6497, -6498, -6499, -6500, -6501, -6502, -6503, -6504, -6505, -6506, -6507, -6508, -6509, -6510, -6511, -6512, -6513, -6514, -6515, -6516, -6517, -6518, -6519, -6520, -6521, -6522, -6523, -6524, -6525, -6526, -6527, -6528, -6529, -6530, -6531, -6532, -6533, -6534, -6535, -6536, -6537, -6538, -6539, -6540, -6541, -6542, -6543, -6544, -6545, -6546, -6547, -6548, -6549, -6550, -6551, -6552, -6553, -6554, -6555, -6556, -6557, -6558, -6559, -6560, -6561, -6562, -6563, -6564, -6565, -6566, -6567, -6568, -6569, -6570, -6571, -6572, -6573, -6574, -6575, -6576, -6577, -6578, -6579, -6580, -6581, -6582, -6583, -6584, -6585, -6586, -6587, -6588, -6589, -6590, -6591, -6592, -6593, -6594, -6595, -6596, -6597, -6598, -6599, -6600, -6601, -6602, -6603, -6604, -6605, -6606, -6607, -6608, -6609, -6610, -6611, -6612, -6613, -6614, -6615, -6616, -6617, -6618, -6619, -6620, -6621, -6622, -6623, -6624, -6625, -6626, -6627, -6628, -6629, -6630, -6631, -6632, -6633, -6634, -6635, -6636, -6637, -6638, -6639, -6640, -6641, -6642, -6643, -6644, -6645, -6646, -6647, -6648, -6649, -6650, -6651, -6652, -6653, -6654, -6655, -6656, -6657, -6658, -6659, -6660, -6661, -6662, -6663, -6664, -6665, -6666, -6667, -6668, -6669, -6670, -6671, -6672, -6673, -6674, -6675, -6676, -6677, -6678, -6679, -6680, -6681, -6682, -6683, -6684, -6685, -6686, -6687, -6688, -6689, -6690, -6691, -6692, -6693, -6694, -6695, -6696, -6697, -6698, -6699, -6700, -6701, -6702, -6703, -6704, -6705, -6706, -6707, -6708, -6709, -6710, -6711, -6712, -6713, -6714, -6715, -6716, -6717, -6718, -6719, -6720, -6721, -6722, -6723, -6724, -6725, -6726, -6727, -6728, -6729, -6730, -6731, -6732, -6733, -6734, -6735, -6736, -6737, -6738, -6739, -6740, -6741, -6742, -6743, -6744, -6745, -6746, -6747, -6748, -6749, -6750, -6751, -6752, -6753, -6754, -6755, -6756, -6757, -6758, -6759, -6760, -6761, -6762, -6763, -6764, -6765, -6766, -6767, -6768, -6769, -6770, -6771, -6772, -6773, -6774, -6775, -6776, -6777, -6778, -6779, -6780, -6781, -6782, -6783, -6784, -6785, -6786, -6787, -6788, -6789, -6790, -6791, -6792, -6793, -6794, -6795, -6796, -6797, -6798, -6799, -6800, -6801, -6802, -6803, -6804, -6805, -6806, -6807, -6808, -6809, -6810, -6811, -6812, -6813, -6814, -6815, -6816, -6817, -6818, -6819, -6820, -6821, -6822, -6823, -6824, -6825, -6826, -6827, -6828, -6829, -6830, -6831, -6832, -6833, -6834, -6835, -6836, -6837, -6838, -6839, -6840, -6841, -6842, -6843, -6844, -6845, -6846, -6847, -6848, -6849, -6850, -6851, -6852, -6853, -6854, -6855, -6856, -6857, -6858, -6859, -6860, -6861, -6862, -6863, -6864, -6865, -6866, -6867, -6868, -6869, -6870, -6871, -6872, -6873, -6874, -6875, -6876, -6877, -6878, -6879, -6880, -6881, -6882, -6883, -6884, -6885, -6886, -6887, -6888, -6889, -6890, -6891, -6892, -6893, -6894, -6895, -6896, -6897, -6898, -6899, -6900, -6901, -6902, -6903, -6904, -6905, -6906, -6907, -6908, -6909, -6910, -6911, -6912, -6913, -6914, -6915, -6916, -6917, -6918, -6919, -6920, -6921, -6922, -6923, -6924, -6925, -6926, -6927, -6928, -6929, -6930, -6931, -6932, -6933, -6934, -6935, -6936, -6937, -6938, -6939, -6940, -6941, -6942, -6943, -6944, -6945, -6946, -6947, -6948, -6949, -6950, -6951, -6952, -6953, -6954, -6955, -6956, -6957, -6958, -6959, -6960, -6961, -6962, -6963, -6964, -6965, -6966, -6967, -6968, -6969, -6970, -6971, -6972, -6973, -6974, -6975, -6976, -6977, -6978, -6979, -6980, -6981, -6982, -6983, -6984, -6985, -6986, -6987, -6988, -6989, -6990, -6991, -6992, -6993, -6994, -6995, -6996, -6997, -6998, -6999, -7000, -7001, -7002, -7003, -7004, -7005, -7006, -7007, -7008, -7009, -7010, -7011, -7012, -7013, -7014, -7015, -7016, -7017, -7018, -7019, -7020, -7021, -7022, -7023, -7024, -7025, -7026, -7027, -7028, -7029, -7030, -7031, -7032, -7033, -7034, -7035, -7036, -7037, -7038, -7039, -7040, -7041, -7042, -7043, -7044, -7045, -7046, -7047, -7048, -7049, -7050, -7051, -7052, -7053, -7054, -7055, -7056, -7057, -7058, -7059, -7060, -7061, -7062, -7063, -7064, -7065, -7066, -7067, -7068, -7069, -7070, -7071, -7072, -7073, -7074, -7075, -7076, -7077, -7078, -7079, -7080, -7081, -7082, -7083, -7084, -7085, -7086, -7087, -7088, -7089, -7090, -7091, -7092, -7093, -7094, -7095, -7096, -7097, -7098, -7099, -7100, -7101, -7102, -7103, -7104, -7105, -7106, -7107, -7108, -7109, -7110, -7111, -7112, -7113, -7114, -7115, -7116, -7117, -7118, -7119, -7120, -7121, -7122, -7123, -7124, -7125, -7126, -7127, -7128, -7129, -7130, -7131, -7132, -7133, -7134, -7135, -7136, -7137, -7138, -7139, -7140, -7141, -7142, -7143, -7144, -7145, -7146, -7147, -7148, -7149, -7150, -7151, -7152, -7153, -7154, -7155, -7156, -7157, -7158, -7159, -7160, -7161, -7162, -7163, -7164, -7165, -7166, -7167, -7168, -7169, -7170, -7171, -7172, -7173, -7174, -7175, -7176, -7177, -7178, -7179, -7180, -7181, -7182, -7183, -7184, -7185, -7186, -7187, -7188, -7189, -7190, -7191, -7192, -7193, -7194, -7195, -7196, -7197, -7198, -7199, -7200, -7201, -7202, -7203, -7204, -7205, -7206, -7207, -7208, -7209, -7210, -7211, -7212, -7213, -7214, -7215, -7216, -7217, -7218, -7219, -7220, -7221, -7222, -7223, -7224, -7225, -7226, -7227, -7228, -7229, -7230, -7231, -7232, -7233, -7234, -7235, -7236, -7237, -7238, -7239, -7240, -7241, -7242, -7243, -7244, -7245, -7246, -7247, -7248, -7249, -7250, -7251, -7252, -7253, -7254, -7255, -7256, -7257, -7258, -7259, -7260, -7261, -7262, -7263, -7264, -7265, -7266, -7267, -7268, -7269, -7270, -7271, -7272, -7273, -7274, -7275, -7276, -7277, -7278, -7279, -7280, -7281, -7282, -7283, -7284, -7285, -7286, -7287, -7288, -7289, -7290, -7291, -7292, -7293, -7294, -7295, -7296, -7297, -7298, -7299, -7300, -7301, -7302, -7303, -7304, -7305, -7306, -7307, -7308, -7309, -7310, -7311, -7312, -7313, -7314, -7315, -7316, -7317, -7318, -7319, -7320, -7321, -7322, -7323, -7324, -7325, -7326, -7327, -7328, -7329, -7330, -7331, -7332, -7333, -7334, -7335, -7336, -7337, -7338, -7339, -7340, -7341, -7342, -7343, -7344, -7345, -7346, -7347, -7348, -7349, -7350, -7351, -7352, -7353, -7354, -7355, -7356, -7357, -7358, -7359, -7360, -7361, -7362, -7363, -7364, -7365, -7366, -7367, -7368, -7369, -7370, -7371, -7372, -7373, -7374, -7375, -7376, -7377, -7378, -7379, -7380, -7381, -7382, -7383, -7384, -7385, -7386, -7387, -7388, -7389, -7390, -7391, -7392, -7393, -7394, -7395, -7396, -7397, -7398, -7399, -7400, -7401, -7402, -7403, -7404, -7405, -7406, -7407, -7408, -7409, -7410, -7411, -7412, -7413, -7414, -7415, -7416, -7417, -7418, -7419, -7420, -7421, -7422, -7423, -7424, -7425, -7426, -7427, -7428, -7429, -7430, -7431, -7432, -7433, -7434, -7435, -7436, -7437, -7438, -7439, -7440, -7441, -7442, -7443, -7444, -7445, -7446, -7447, -7448, -7449, -7450, -7451, -7452, -7453, -7454, -7455, -7456, -7457, -7458, -7459, -7460, -7461, -7462, -7463, -7464, -7465, -7466, -7467, -7468, -7469, -7470, -7471, -7472, -7473, -7474, -7475, -7476, -7477, -7478, -7479, -7480, -7481, -7482, -7483, -7484, -7485, -7486, -7487, -7488, -7489, -7490, -7491, -7492, -7493, -7494, -7495, -7496, -7497, -7498, -7499, -7500, -7501, -7502, -7503, -7504, -7505, -7506, -7507, -7508, -7509, -7510, -7511, -7512, -7513, -7514, -7515, -7516, -7517, -7518, -7519, -7520, -7521, -7522, -7523, -7524, -7525, -7526, -7527, -7528, -7529, -7530, -7531, -7532, -7533, -7534, -7535, -7536, -7537, -7538, -7539, -7540, -7541, -7542, -7543, -7544, -7545, -7546, -7547, -7548, -7549, -7550, -7551, -7552, -7553, -7554, -7555, -7556, -7557, -7558, -7559, -7560, -7561, -7562, -7563, -7564, -7565, -7566, -7567, -7568, -7569, -7570, -7571, -7572, -7573, -7574, -7575, -7576, -7577, -7578, -7579, -7580, -7581, -7582, -7583, -7584, -7585, -7586, -7587, -7588, -7589, -7590, -7591, -7592, -7593, -7594, -7595, -7596, -7597, -7598, -7599, -7600, -7601, -7602, -7603, -7604, -7605, -7606, -7607, -7608, -7609, -7610, -7611, -7612, -7613, -7614, -7615, -7616, -7617, -7618, -7619, -7620, -7621, -7622, -7623, -7624, -7625, -7626, -7627, -7628, -7629, -7630, -7631, -7632, -7633, -7634, -7635, -7636, -7637, -7638, -7639, -7640, -7641, -7642, -7643, -7644, -7645, -7646, -7647, -7648, -7649, -7650, -7651, -7652, -7653, -7654, -7655, -7656, -7657, -7658, -7659, -7660, -7661, -7662, -7663, -7664, -7665, -7666, -7667, -7668, -7669, -7670, -7671, -7672, -7673, -7674, -7675, -7676, -7677, -7678, -7679, -7680, -7681, -7682, -7683, -7684, -7685, -7686, -7687, -7688, -7689, -7690, -7691, -7692, -7693, -7694, -7695, -7696, -7697, -7698, -7699, -7700, -7701, -7702, -7703, -7704, -7705, -7706, -7707, -7708, -7709, -7710, -7711, -7712, -7713, -7714, -7715, -7716, -7717, -7718, -7719, -7720, -7721, -7722, -7723, -7724, -7725, -7726, -7727, -7728, -7729, -7730, -7731, -7732, -7733, -7734, -7735, -7736, -7737, -7738, -7739, -7740, -7741, -7742, -7743, -7744, -7745, -7746, -7747, -7748, -7749, -7750, -7751, -7752, -7753, -7754, -7755, -7756, -7757, -7758, -7759, -7760, -7761, -7762, -7763, -7764, -7765, -7766, -7767, -7768, -7769, -7770, -7771, -7772, -7773, -7774, -7775, -7776, -7777, -7778, -7779, -7780, -7781, -7782, -7783, -7784, -7785, -7786, -7787, -7788, -7789, -7790, -7791, -7792, -7793, -7794, -7795, -7796, -7797, -7798, -7799, -7800, -7801, -7802, -7803, -7804, -7805, -7806, -7807, -7808, -7809, -7810, -7811, -7812, -7813, -7814, -7815, -7816, -7817, -7818, -7819, -7820, -7821, -7822, -7823, -7824, -7825, -7826, -7827, -7828, -7829, -7830, -7831, -7832, -7833, -7834, -7835, -7836, -7837, -7838, -7839, -7840, -7841, -7842, -7843, -7844, -7845, -7846, -7847, -7848, -7849, -7850, -7851, -7852, -7853, -7854, -7855, -7856, -7857, -7858, -7859, -7860, -7861, -7862, -7863, -7864, -7865, -7866, -7867, -7868, -7869, -7870, -7871, -7872, -7873, -7874, -7875, -7876, -7877, -7878, -7879, -7880, -7881, -7882, -7883, -7884, -7885, -7886, -7887, -7888, -7889, -7890, -7891, -7892, -7893, -7894, -7895, -7896, -7897, -7898, -7899, -7900, -7901, -7902, -7903, -7904, -7905, -7906, -7907, -7908, -7909, -7910, -7911, -7912, -7913, -7914, -7915, -7916, -7917, -7918, -7919, -7920, -7921, -7922, -7923, -7924, -7925, -7926, -7927, -7928, -7929, -7930, -7931, -7932, -7933, -7934, -7935, -7936, -7937, -7938, -7939, -7940, -7941, -7942, -7943, -7944, -7945, -7946, -7947, -7948, -7949, -7950, -7951, -7952, -7953, -7954, -7955, -7956, -7957, -7958, -7959, -7960, -7961, -7962, -7963, -7964, -7965, -7966, -7967, -7968, -7969, -7970, -7971, -7972, -7973, -7974, -7975, -7976, -7977, -7978, -7979, -7980, -7981, -7982, -7983, -7984, -7985, -7986, -7987, -7988, -7989, -7990, -7991, -7992, -7993, -7994, -7995, -7996, -7997, -7998, -7999, -8000, -8001, -8002, -8003, -8004, -8005, -8006, -8007, -8008, -8009, -8010, -8011, -8012, -8013, -8014, -8015, -8016, -8017, -8018, -8019, -8020, -8021, -8022, -8023, -8024, -8025, -8026, -8027, -8028, -8029, -8030, -8031, -8032, -8033, -8034, -8035, -8036, -8037, -8038, -8039, -8040, -8041, -8042, -8043, -8044, -8045, -8046, -8047, -8048, -8049, -8050, -8051, -8052, -8053, -8054, -8055, -8056, -8057, -8058, -8059, -8060, -8061, -8062, -8063, -8064, -8065, -8066, -8067, -8068, -8069, -8070, -8071, -8072, -8073, -8074, -8075, -8076, -8077, -8078, -8079, -8080, -8081, -8082, -8083, -8084, -8085, -8086, -8087, -8088, -8089, -8090, -8091, -8092, -8093, -8094, -8095, -8096, -8097, -8098 -); - TestLibrary.TestFramework.LogInformation("Method JITTed and ran"); - - retVal = 100; - }catch(Exception e){ - TestLibrary.TestFramework.LogError("000", "Unexpected exception: " + e); - retVal = 0; - } - - TestLibrary.TestFramework.LogInformation("Done"); - TestLibrary.TestFramework.EndTestCase(); - return retVal; - } - - public static int Method( -long arg0, -long arg1, -long arg2, -long arg3, -long arg4, -long arg5, -long arg6, -long arg7, -long arg8, -long arg9, -long arg10, -long arg11, -long arg12, -long arg13, -long arg14, -long arg15, -long arg16, -long arg17, -long arg18, -long arg19, -long arg20, -long arg21, -long arg22, -long arg23, -long arg24, -long arg25, -long arg26, -long arg27, -long arg28, -long arg29, -long arg30, -long arg31, -long arg32, -long arg33, -long arg34, -long arg35, -long arg36, -long arg37, -long arg38, -long arg39, -long arg40, -long arg41, -long arg42, -long arg43, -long arg44, -long arg45, -long arg46, -long arg47, -long arg48, -long arg49, -long arg50, -long arg51, -long arg52, -long arg53, -long arg54, -long arg55, -long arg56, -long arg57, -long arg58, -long arg59, -long arg60, -long arg61, -long arg62, -long arg63, -long arg64, -long arg65, -long arg66, -long arg67, -long arg68, -long arg69, -long arg70, -long arg71, -long arg72, -long arg73, -long arg74, -long arg75, -long arg76, -long arg77, -long arg78, -long arg79, -long arg80, -long arg81, -long arg82, -long arg83, -long arg84, -long arg85, -long arg86, -long arg87, -long arg88, -long arg89, -long arg90, -long arg91, -long arg92, -long arg93, -long arg94, -long arg95, -long arg96, -long arg97, -long arg98, -long arg99, -long arg100, -long arg101, -long arg102, -long arg103, -long arg104, -long arg105, -long arg106, -long arg107, -long arg108, -long arg109, -long arg110, -long arg111, -long arg112, -long arg113, -long arg114, -long arg115, -long arg116, -long arg117, -long arg118, -long arg119, -long arg120, -long arg121, -long arg122, -long arg123, -long arg124, -long arg125, -long arg126, -long arg127, -long arg128, -long arg129, -long arg130, -long arg131, -long arg132, -long arg133, -long arg134, -long arg135, -long arg136, -long arg137, -long arg138, -long arg139, -long arg140, -long arg141, -long arg142, -long arg143, -long arg144, -long arg145, -long arg146, -long arg147, -long arg148, -long arg149, -long arg150, -long arg151, -long arg152, -long arg153, -long arg154, -long arg155, -long arg156, -long arg157, -long arg158, -long arg159, -long arg160, -long arg161, -long arg162, -long arg163, -long arg164, -long arg165, -long arg166, -long arg167, -long arg168, -long arg169, -long arg170, -long arg171, -long arg172, -long arg173, -long arg174, -long arg175, -long arg176, -long arg177, -long arg178, -long arg179, -long arg180, -long arg181, -long arg182, -long arg183, -long arg184, -long arg185, -long arg186, -long arg187, -long arg188, -long arg189, -long arg190, -long arg191, -long arg192, -long arg193, -long arg194, -long arg195, -long arg196, -long arg197, -long arg198, -long arg199, -long arg200, -long arg201, -long arg202, -long arg203, -long arg204, -long arg205, -long arg206, -long arg207, -long arg208, -long arg209, -long arg210, -long arg211, -long arg212, -long arg213, -long arg214, -long arg215, -long arg216, -long arg217, -long arg218, -long arg219, -long arg220, -long arg221, -long arg222, -long arg223, -long arg224, -long arg225, -long arg226, -long arg227, -long arg228, -long arg229, -long arg230, -long arg231, -long arg232, -long arg233, -long arg234, -long arg235, -long arg236, -long arg237, -long arg238, -long arg239, -long arg240, -long arg241, -long arg242, -long arg243, -long arg244, -long arg245, -long arg246, -long arg247, -long arg248, -long arg249, -long arg250, -long arg251, -long arg252, -long arg253, -long arg254, -long arg255, -long arg256, -long arg257, -long arg258, -long arg259, -long arg260, -long arg261, -long arg262, -long arg263, -long arg264, -long arg265, -long arg266, -long arg267, -long arg268, -long arg269, -long arg270, -long arg271, -long arg272, -long arg273, -long arg274, -long arg275, -long arg276, -long arg277, -long arg278, -long arg279, -long arg280, -long arg281, -long arg282, -long arg283, -long arg284, -long arg285, -long arg286, -long arg287, -long arg288, -long arg289, -long arg290, -long arg291, -long arg292, -long arg293, -long arg294, -long arg295, -long arg296, -long arg297, -long arg298, -long arg299, -long arg300, -long arg301, -long arg302, -long arg303, -long arg304, -long arg305, -long arg306, -long arg307, -long arg308, -long arg309, -long arg310, -long arg311, -long arg312, -long arg313, -long arg314, -long arg315, -long arg316, -long arg317, -long arg318, -long arg319, -long arg320, -long arg321, -long arg322, -long arg323, -long arg324, -long arg325, -long arg326, -long arg327, -long arg328, -long arg329, -long arg330, -long arg331, -long arg332, -long arg333, -long arg334, -long arg335, -long arg336, -long arg337, -long arg338, -long arg339, -long arg340, -long arg341, -long arg342, -long arg343, -long arg344, -long arg345, -long arg346, -long arg347, -long arg348, -long arg349, -long arg350, -long arg351, -long arg352, -long arg353, -long arg354, -long arg355, -long arg356, -long arg357, -long arg358, -long arg359, -long arg360, -long arg361, -long arg362, -long arg363, -long arg364, -long arg365, -long arg366, -long arg367, -long arg368, -long arg369, -long arg370, -long arg371, -long arg372, -long arg373, -long arg374, -long arg375, -long arg376, -long arg377, -long arg378, -long arg379, -long arg380, -long arg381, -long arg382, -long arg383, -long arg384, -long arg385, -long arg386, -long arg387, -long arg388, -long arg389, -long arg390, -long arg391, -long arg392, -long arg393, -long arg394, -long arg395, -long arg396, -long arg397, -long arg398, -long arg399, -long arg400, -long arg401, -long arg402, -long arg403, -long arg404, -long arg405, -long arg406, -long arg407, -long arg408, -long arg409, -long arg410, -long arg411, -long arg412, -long arg413, -long arg414, -long arg415, -long arg416, -long arg417, -long arg418, -long arg419, -long arg420, -long arg421, -long arg422, -long arg423, -long arg424, -long arg425, -long arg426, -long arg427, -long arg428, -long arg429, -long arg430, -long arg431, -long arg432, -long arg433, -long arg434, -long arg435, -long arg436, -long arg437, -long arg438, -long arg439, -long arg440, -long arg441, -long arg442, -long arg443, -long arg444, -long arg445, -long arg446, -long arg447, -long arg448, -long arg449, -long arg450, -long arg451, -long arg452, -long arg453, -long arg454, -long arg455, -long arg456, -long arg457, -long arg458, -long arg459, -long arg460, -long arg461, -long arg462, -long arg463, -long arg464, -long arg465, -long arg466, -long arg467, -long arg468, -long arg469, -long arg470, -long arg471, -long arg472, -long arg473, -long arg474, -long arg475, -long arg476, -long arg477, -long arg478, -long arg479, -long arg480, -long arg481, -long arg482, -long arg483, -long arg484, -long arg485, -long arg486, -long arg487, -long arg488, -long arg489, -long arg490, -long arg491, -long arg492, -long arg493, -long arg494, -long arg495, -long arg496, -long arg497, -long arg498, -long arg499, -long arg500, -long arg501, -long arg502, -long arg503, -long arg504, -long arg505, -long arg506, -long arg507, -long arg508, -long arg509, -long arg510, -long arg511, -long arg512, -long arg513, -long arg514, -long arg515, -long arg516, -long arg517, -long arg518, -long arg519, -long arg520, -long arg521, -long arg522, -long arg523, -long arg524, -long arg525, -long arg526, -long arg527, -long arg528, -long arg529, -long arg530, -long arg531, -long arg532, -long arg533, -long arg534, -long arg535, -long arg536, -long arg537, -long arg538, -long arg539, -long arg540, -long arg541, -long arg542, -long arg543, -long arg544, -long arg545, -long arg546, -long arg547, -long arg548, -long arg549, -long arg550, -long arg551, -long arg552, -long arg553, -long arg554, -long arg555, -long arg556, -long arg557, -long arg558, -long arg559, -long arg560, -long arg561, -long arg562, -long arg563, -long arg564, -long arg565, -long arg566, -long arg567, -long arg568, -long arg569, -long arg570, -long arg571, -long arg572, -long arg573, -long arg574, -long arg575, -long arg576, -long arg577, -long arg578, -long arg579, -long arg580, -long arg581, -long arg582, -long arg583, -long arg584, -long arg585, -long arg586, -long arg587, -long arg588, -long arg589, -long arg590, -long arg591, -long arg592, -long arg593, -long arg594, -long arg595, -long arg596, -long arg597, -long arg598, -long arg599, -long arg600, -long arg601, -long arg602, -long arg603, -long arg604, -long arg605, -long arg606, -long arg607, -long arg608, -long arg609, -long arg610, -long arg611, -long arg612, -long arg613, -long arg614, -long arg615, -long arg616, -long arg617, -long arg618, -long arg619, -long arg620, -long arg621, -long arg622, -long arg623, -long arg624, -long arg625, -long arg626, -long arg627, -long arg628, -long arg629, -long arg630, -long arg631, -long arg632, -long arg633, -long arg634, -long arg635, -long arg636, -long arg637, -long arg638, -long arg639, -long arg640, -long arg641, -long arg642, -long arg643, -long arg644, -long arg645, -long arg646, -long arg647, -long arg648, -long arg649, -long arg650, -long arg651, -long arg652, -long arg653, -long arg654, -long arg655, -long arg656, -long arg657, -long arg658, -long arg659, -long arg660, -long arg661, -long arg662, -long arg663, -long arg664, -long arg665, -long arg666, -long arg667, -long arg668, -long arg669, -long arg670, -long arg671, -long arg672, -long arg673, -long arg674, -long arg675, -long arg676, -long arg677, -long arg678, -long arg679, -long arg680, -long arg681, -long arg682, -long arg683, -long arg684, -long arg685, -long arg686, -long arg687, -long arg688, -long arg689, -long arg690, -long arg691, -long arg692, -long arg693, -long arg694, -long arg695, -long arg696, -long arg697, -long arg698, -long arg699, -long arg700, -long arg701, -long arg702, -long arg703, -long arg704, -long arg705, -long arg706, -long arg707, -long arg708, -long arg709, -long arg710, -long arg711, -long arg712, -long arg713, -long arg714, -long arg715, -long arg716, -long arg717, -long arg718, -long arg719, -long arg720, -long arg721, -long arg722, -long arg723, -long arg724, -long arg725, -long arg726, -long arg727, -long arg728, -long arg729, -long arg730, -long arg731, -long arg732, -long arg733, -long arg734, -long arg735, -long arg736, -long arg737, -long arg738, -long arg739, -long arg740, -long arg741, -long arg742, -long arg743, -long arg744, -long arg745, -long arg746, -long arg747, -long arg748, -long arg749, -long arg750, -long arg751, -long arg752, -long arg753, -long arg754, -long arg755, -long arg756, -long arg757, -long arg758, -long arg759, -long arg760, -long arg761, -long arg762, -long arg763, -long arg764, -long arg765, -long arg766, -long arg767, -long arg768, -long arg769, -long arg770, -long arg771, -long arg772, -long arg773, -long arg774, -long arg775, -long arg776, -long arg777, -long arg778, -long arg779, -long arg780, -long arg781, -long arg782, -long arg783, -long arg784, -long arg785, -long arg786, -long arg787, -long arg788, -long arg789, -long arg790, -long arg791, -long arg792, -long arg793, -long arg794, -long arg795, -long arg796, -long arg797, -long arg798, -long arg799, -long arg800, -long arg801, -long arg802, -long arg803, -long arg804, -long arg805, -long arg806, -long arg807, -long arg808, -long arg809, -long arg810, -long arg811, -long arg812, -long arg813, -long arg814, -long arg815, -long arg816, -long arg817, -long arg818, -long arg819, -long arg820, -long arg821, -long arg822, -long arg823, -long arg824, -long arg825, -long arg826, -long arg827, -long arg828, -long arg829, -long arg830, -long arg831, -long arg832, -long arg833, -long arg834, -long arg835, -long arg836, -long arg837, -long arg838, -long arg839, -long arg840, -long arg841, -long arg842, -long arg843, -long arg844, -long arg845, -long arg846, -long arg847, -long arg848, -long arg849, -long arg850, -long arg851, -long arg852, -long arg853, -long arg854, -long arg855, -long arg856, -long arg857, -long arg858, -long arg859, -long arg860, -long arg861, -long arg862, -long arg863, -long arg864, -long arg865, -long arg866, -long arg867, -long arg868, -long arg869, -long arg870, -long arg871, -long arg872, -long arg873, -long arg874, -long arg875, -long arg876, -long arg877, -long arg878, -long arg879, -long arg880, -long arg881, -long arg882, -long arg883, -long arg884, -long arg885, -long arg886, -long arg887, -long arg888, -long arg889, -long arg890, -long arg891, -long arg892, -long arg893, -long arg894, -long arg895, -long arg896, -long arg897, -long arg898, -long arg899, -long arg900, -long arg901, -long arg902, -long arg903, -long arg904, -long arg905, -long arg906, -long arg907, -long arg908, -long arg909, -long arg910, -long arg911, -long arg912, -long arg913, -long arg914, -long arg915, -long arg916, -long arg917, -long arg918, -long arg919, -long arg920, -long arg921, -long arg922, -long arg923, -long arg924, -long arg925, -long arg926, -long arg927, -long arg928, -long arg929, -long arg930, -long arg931, -long arg932, -long arg933, -long arg934, -long arg935, -long arg936, -long arg937, -long arg938, -long arg939, -long arg940, -long arg941, -long arg942, -long arg943, -long arg944, -long arg945, -long arg946, -long arg947, -long arg948, -long arg949, -long arg950, -long arg951, -long arg952, -long arg953, -long arg954, -long arg955, -long arg956, -long arg957, -long arg958, -long arg959, -long arg960, -long arg961, -long arg962, -long arg963, -long arg964, -long arg965, -long arg966, -long arg967, -long arg968, -long arg969, -long arg970, -long arg971, -long arg972, -long arg973, -long arg974, -long arg975, -long arg976, -long arg977, -long arg978, -long arg979, -long arg980, -long arg981, -long arg982, -long arg983, -long arg984, -long arg985, -long arg986, -long arg987, -long arg988, -long arg989, -long arg990, -long arg991, -long arg992, -long arg993, -long arg994, -long arg995, -long arg996, -long arg997, -long arg998, -long arg999, -long arg1000, -long arg1001, -long arg1002, -long arg1003, -long arg1004, -long arg1005, -long arg1006, -long arg1007, -long arg1008, -long arg1009, -long arg1010, -long arg1011, -long arg1012, -long arg1013, -long arg1014, -long arg1015, -long arg1016, -long arg1017, -long arg1018, -long arg1019, -long arg1020, -long arg1021, -long arg1022, -long arg1023, -long arg1024, -long arg1025, -long arg1026, -long arg1027, -long arg1028, -long arg1029, -long arg1030, -long arg1031, -long arg1032, -long arg1033, -long arg1034, -long arg1035, -long arg1036, -long arg1037, -long arg1038, -long arg1039, -long arg1040, -long arg1041, -long arg1042, -long arg1043, -long arg1044, -long arg1045, -long arg1046, -long arg1047, -long arg1048, -long arg1049, -long arg1050, -long arg1051, -long arg1052, -long arg1053, -long arg1054, -long arg1055, -long arg1056, -long arg1057, -long arg1058, -long arg1059, -long arg1060, -long arg1061, -long arg1062, -long arg1063, -long arg1064, -long arg1065, -long arg1066, -long arg1067, -long arg1068, -long arg1069, -long arg1070, -long arg1071, -long arg1072, -long arg1073, -long arg1074, -long arg1075, -long arg1076, -long arg1077, -long arg1078, -long arg1079, -long arg1080, -long arg1081, -long arg1082, -long arg1083, -long arg1084, -long arg1085, -long arg1086, -long arg1087, -long arg1088, -long arg1089, -long arg1090, -long arg1091, -long arg1092, -long arg1093, -long arg1094, -long arg1095, -long arg1096, -long arg1097, -long arg1098, -long arg1099, -long arg1100, -long arg1101, -long arg1102, -long arg1103, -long arg1104, -long arg1105, -long arg1106, -long arg1107, -long arg1108, -long arg1109, -long arg1110, -long arg1111, -long arg1112, -long arg1113, -long arg1114, -long arg1115, -long arg1116, -long arg1117, -long arg1118, -long arg1119, -long arg1120, -long arg1121, -long arg1122, -long arg1123, -long arg1124, -long arg1125, -long arg1126, -long arg1127, -long arg1128, -long arg1129, -long arg1130, -long arg1131, -long arg1132, -long arg1133, -long arg1134, -long arg1135, -long arg1136, -long arg1137, -long arg1138, -long arg1139, -long arg1140, -long arg1141, -long arg1142, -long arg1143, -long arg1144, -long arg1145, -long arg1146, -long arg1147, -long arg1148, -long arg1149, -long arg1150, -long arg1151, -long arg1152, -long arg1153, -long arg1154, -long arg1155, -long arg1156, -long arg1157, -long arg1158, -long arg1159, -long arg1160, -long arg1161, -long arg1162, -long arg1163, -long arg1164, -long arg1165, -long arg1166, -long arg1167, -long arg1168, -long arg1169, -long arg1170, -long arg1171, -long arg1172, -long arg1173, -long arg1174, -long arg1175, -long arg1176, -long arg1177, -long arg1178, -long arg1179, -long arg1180, -long arg1181, -long arg1182, -long arg1183, -long arg1184, -long arg1185, -long arg1186, -long arg1187, -long arg1188, -long arg1189, -long arg1190, -long arg1191, -long arg1192, -long arg1193, -long arg1194, -long arg1195, -long arg1196, -long arg1197, -long arg1198, -long arg1199, -long arg1200, -long arg1201, -long arg1202, -long arg1203, -long arg1204, -long arg1205, -long arg1206, -long arg1207, -long arg1208, -long arg1209, -long arg1210, -long arg1211, -long arg1212, -long arg1213, -long arg1214, -long arg1215, -long arg1216, -long arg1217, -long arg1218, -long arg1219, -long arg1220, -long arg1221, -long arg1222, -long arg1223, -long arg1224, -long arg1225, -long arg1226, -long arg1227, -long arg1228, -long arg1229, -long arg1230, -long arg1231, -long arg1232, -long arg1233, -long arg1234, -long arg1235, -long arg1236, -long arg1237, -long arg1238, -long arg1239, -long arg1240, -long arg1241, -long arg1242, -long arg1243, -long arg1244, -long arg1245, -long arg1246, -long arg1247, -long arg1248, -long arg1249, -long arg1250, -long arg1251, -long arg1252, -long arg1253, -long arg1254, -long arg1255, -long arg1256, -long arg1257, -long arg1258, -long arg1259, -long arg1260, -long arg1261, -long arg1262, -long arg1263, -long arg1264, -long arg1265, -long arg1266, -long arg1267, -long arg1268, -long arg1269, -long arg1270, -long arg1271, -long arg1272, -long arg1273, -long arg1274, -long arg1275, -long arg1276, -long arg1277, -long arg1278, -long arg1279, -long arg1280, -long arg1281, -long arg1282, -long arg1283, -long arg1284, -long arg1285, -long arg1286, -long arg1287, -long arg1288, -long arg1289, -long arg1290, -long arg1291, -long arg1292, -long arg1293, -long arg1294, -long arg1295, -long arg1296, -long arg1297, -long arg1298, -long arg1299, -long arg1300, -long arg1301, -long arg1302, -long arg1303, -long arg1304, -long arg1305, -long arg1306, -long arg1307, -long arg1308, -long arg1309, -long arg1310, -long arg1311, -long arg1312, -long arg1313, -long arg1314, -long arg1315, -long arg1316, -long arg1317, -long arg1318, -long arg1319, -long arg1320, -long arg1321, -long arg1322, -long arg1323, -long arg1324, -long arg1325, -long arg1326, -long arg1327, -long arg1328, -long arg1329, -long arg1330, -long arg1331, -long arg1332, -long arg1333, -long arg1334, -long arg1335, -long arg1336, -long arg1337, -long arg1338, -long arg1339, -long arg1340, -long arg1341, -long arg1342, -long arg1343, -long arg1344, -long arg1345, -long arg1346, -long arg1347, -long arg1348, -long arg1349, -long arg1350, -long arg1351, -long arg1352, -long arg1353, -long arg1354, -long arg1355, -long arg1356, -long arg1357, -long arg1358, -long arg1359, -long arg1360, -long arg1361, -long arg1362, -long arg1363, -long arg1364, -long arg1365, -long arg1366, -long arg1367, -long arg1368, -long arg1369, -long arg1370, -long arg1371, -long arg1372, -long arg1373, -long arg1374, -long arg1375, -long arg1376, -long arg1377, -long arg1378, -long arg1379, -long arg1380, -long arg1381, -long arg1382, -long arg1383, -long arg1384, -long arg1385, -long arg1386, -long arg1387, -long arg1388, -long arg1389, -long arg1390, -long arg1391, -long arg1392, -long arg1393, -long arg1394, -long arg1395, -long arg1396, -long arg1397, -long arg1398, -long arg1399, -long arg1400, -long arg1401, -long arg1402, -long arg1403, -long arg1404, -long arg1405, -long arg1406, -long arg1407, -long arg1408, -long arg1409, -long arg1410, -long arg1411, -long arg1412, -long arg1413, -long arg1414, -long arg1415, -long arg1416, -long arg1417, -long arg1418, -long arg1419, -long arg1420, -long arg1421, -long arg1422, -long arg1423, -long arg1424, -long arg1425, -long arg1426, -long arg1427, -long arg1428, -long arg1429, -long arg1430, -long arg1431, -long arg1432, -long arg1433, -long arg1434, -long arg1435, -long arg1436, -long arg1437, -long arg1438, -long arg1439, -long arg1440, -long arg1441, -long arg1442, -long arg1443, -long arg1444, -long arg1445, -long arg1446, -long arg1447, -long arg1448, -long arg1449, -long arg1450, -long arg1451, -long arg1452, -long arg1453, -long arg1454, -long arg1455, -long arg1456, -long arg1457, -long arg1458, -long arg1459, -long arg1460, -long arg1461, -long arg1462, -long arg1463, -long arg1464, -long arg1465, -long arg1466, -long arg1467, -long arg1468, -long arg1469, -long arg1470, -long arg1471, -long arg1472, -long arg1473, -long arg1474, -long arg1475, -long arg1476, -long arg1477, -long arg1478, -long arg1479, -long arg1480, -long arg1481, -long arg1482, -long arg1483, -long arg1484, -long arg1485, -long arg1486, -long arg1487, -long arg1488, -long arg1489, -long arg1490, -long arg1491, -long arg1492, -long arg1493, -long arg1494, -long arg1495, -long arg1496, -long arg1497, -long arg1498, -long arg1499, -long arg1500, -long arg1501, -long arg1502, -long arg1503, -long arg1504, -long arg1505, -long arg1506, -long arg1507, -long arg1508, -long arg1509, -long arg1510, -long arg1511, -long arg1512, -long arg1513, -long arg1514, -long arg1515, -long arg1516, -long arg1517, -long arg1518, -long arg1519, -long arg1520, -long arg1521, -long arg1522, -long arg1523, -long arg1524, -long arg1525, -long arg1526, -long arg1527, -long arg1528, -long arg1529, -long arg1530, -long arg1531, -long arg1532, -long arg1533, -long arg1534, -long arg1535, -long arg1536, -long arg1537, -long arg1538, -long arg1539, -long arg1540, -long arg1541, -long arg1542, -long arg1543, -long arg1544, -long arg1545, -long arg1546, -long arg1547, -long arg1548, -long arg1549, -long arg1550, -long arg1551, -long arg1552, -long arg1553, -long arg1554, -long arg1555, -long arg1556, -long arg1557, -long arg1558, -long arg1559, -long arg1560, -long arg1561, -long arg1562, -long arg1563, -long arg1564, -long arg1565, -long arg1566, -long arg1567, -long arg1568, -long arg1569, -long arg1570, -long arg1571, -long arg1572, -long arg1573, -long arg1574, -long arg1575, -long arg1576, -long arg1577, -long arg1578, -long arg1579, -long arg1580, -long arg1581, -long arg1582, -long arg1583, -long arg1584, -long arg1585, -long arg1586, -long arg1587, -long arg1588, -long arg1589, -long arg1590, -long arg1591, -long arg1592, -long arg1593, -long arg1594, -long arg1595, -long arg1596, -long arg1597, -long arg1598, -long arg1599, -long arg1600, -long arg1601, -long arg1602, -long arg1603, -long arg1604, -long arg1605, -long arg1606, -long arg1607, -long arg1608, -long arg1609, -long arg1610, -long arg1611, -long arg1612, -long arg1613, -long arg1614, -long arg1615, -long arg1616, -long arg1617, -long arg1618, -long arg1619, -long arg1620, -long arg1621, -long arg1622, -long arg1623, -long arg1624, -long arg1625, -long arg1626, -long arg1627, -long arg1628, -long arg1629, -long arg1630, -long arg1631, -long arg1632, -long arg1633, -long arg1634, -long arg1635, -long arg1636, -long arg1637, -long arg1638, -long arg1639, -long arg1640, -long arg1641, -long arg1642, -long arg1643, -long arg1644, -long arg1645, -long arg1646, -long arg1647, -long arg1648, -long arg1649, -long arg1650, -long arg1651, -long arg1652, -long arg1653, -long arg1654, -long arg1655, -long arg1656, -long arg1657, -long arg1658, -long arg1659, -long arg1660, -long arg1661, -long arg1662, -long arg1663, -long arg1664, -long arg1665, -long arg1666, -long arg1667, -long arg1668, -long arg1669, -long arg1670, -long arg1671, -long arg1672, -long arg1673, -long arg1674, -long arg1675, -long arg1676, -long arg1677, -long arg1678, -long arg1679, -long arg1680, -long arg1681, -long arg1682, -long arg1683, -long arg1684, -long arg1685, -long arg1686, -long arg1687, -long arg1688, -long arg1689, -long arg1690, -long arg1691, -long arg1692, -long arg1693, -long arg1694, -long arg1695, -long arg1696, -long arg1697, -long arg1698, -long arg1699, -long arg1700, -long arg1701, -long arg1702, -long arg1703, -long arg1704, -long arg1705, -long arg1706, -long arg1707, -long arg1708, -long arg1709, -long arg1710, -long arg1711, -long arg1712, -long arg1713, -long arg1714, -long arg1715, -long arg1716, -long arg1717, -long arg1718, -long arg1719, -long arg1720, -long arg1721, -long arg1722, -long arg1723, -long arg1724, -long arg1725, -long arg1726, -long arg1727, -long arg1728, -long arg1729, -long arg1730, -long arg1731, -long arg1732, -long arg1733, -long arg1734, -long arg1735, -long arg1736, -long arg1737, -long arg1738, -long arg1739, -long arg1740, -long arg1741, -long arg1742, -long arg1743, -long arg1744, -long arg1745, -long arg1746, -long arg1747, -long arg1748, -long arg1749, -long arg1750, -long arg1751, -long arg1752, -long arg1753, -long arg1754, -long arg1755, -long arg1756, -long arg1757, -long arg1758, -long arg1759, -long arg1760, -long arg1761, -long arg1762, -long arg1763, -long arg1764, -long arg1765, -long arg1766, -long arg1767, -long arg1768, -long arg1769, -long arg1770, -long arg1771, -long arg1772, -long arg1773, -long arg1774, -long arg1775, -long arg1776, -long arg1777, -long arg1778, -long arg1779, -long arg1780, -long arg1781, -long arg1782, -long arg1783, -long arg1784, -long arg1785, -long arg1786, -long arg1787, -long arg1788, -long arg1789, -long arg1790, -long arg1791, -long arg1792, -long arg1793, -long arg1794, -long arg1795, -long arg1796, -long arg1797, -long arg1798, -long arg1799, -long arg1800, -long arg1801, -long arg1802, -long arg1803, -long arg1804, -long arg1805, -long arg1806, -long arg1807, -long arg1808, -long arg1809, -long arg1810, -long arg1811, -long arg1812, -long arg1813, -long arg1814, -long arg1815, -long arg1816, -long arg1817, -long arg1818, -long arg1819, -long arg1820, -long arg1821, -long arg1822, -long arg1823, -long arg1824, -long arg1825, -long arg1826, -long arg1827, -long arg1828, -long arg1829, -long arg1830, -long arg1831, -long arg1832, -long arg1833, -long arg1834, -long arg1835, -long arg1836, -long arg1837, -long arg1838, -long arg1839, -long arg1840, -long arg1841, -long arg1842, -long arg1843, -long arg1844, -long arg1845, -long arg1846, -long arg1847, -long arg1848, -long arg1849, -long arg1850, -long arg1851, -long arg1852, -long arg1853, -long arg1854, -long arg1855, -long arg1856, -long arg1857, -long arg1858, -long arg1859, -long arg1860, -long arg1861, -long arg1862, -long arg1863, -long arg1864, -long arg1865, -long arg1866, -long arg1867, -long arg1868, -long arg1869, -long arg1870, -long arg1871, -long arg1872, -long arg1873, -long arg1874, -long arg1875, -long arg1876, -long arg1877, -long arg1878, -long arg1879, -long arg1880, -long arg1881, -long arg1882, -long arg1883, -long arg1884, -long arg1885, -long arg1886, -long arg1887, -long arg1888, -long arg1889, -long arg1890, -long arg1891, -long arg1892, -long arg1893, -long arg1894, -long arg1895, -long arg1896, -long arg1897, -long arg1898, -long arg1899, -long arg1900, -long arg1901, -long arg1902, -long arg1903, -long arg1904, -long arg1905, -long arg1906, -long arg1907, -long arg1908, -long arg1909, -long arg1910, -long arg1911, -long arg1912, -long arg1913, -long arg1914, -long arg1915, -long arg1916, -long arg1917, -long arg1918, -long arg1919, -long arg1920, -long arg1921, -long arg1922, -long arg1923, -long arg1924, -long arg1925, -long arg1926, -long arg1927, -long arg1928, -long arg1929, -long arg1930, -long arg1931, -long arg1932, -long arg1933, -long arg1934, -long arg1935, -long arg1936, -long arg1937, -long arg1938, -long arg1939, -long arg1940, -long arg1941, -long arg1942, -long arg1943, -long arg1944, -long arg1945, -long arg1946, -long arg1947, -long arg1948, -long arg1949, -long arg1950, -long arg1951, -long arg1952, -long arg1953, -long arg1954, -long arg1955, -long arg1956, -long arg1957, -long arg1958, -long arg1959, -long arg1960, -long arg1961, -long arg1962, -long arg1963, -long arg1964, -long arg1965, -long arg1966, -long arg1967, -long arg1968, -long arg1969, -long arg1970, -long arg1971, -long arg1972, -long arg1973, -long arg1974, -long arg1975, -long arg1976, -long arg1977, -long arg1978, -long arg1979, -long arg1980, -long arg1981, -long arg1982, -long arg1983, -long arg1984, -long arg1985, -long arg1986, -long arg1987, -long arg1988, -long arg1989, -long arg1990, -long arg1991, -long arg1992, -long arg1993, -long arg1994, -long arg1995, -long arg1996, -long arg1997, -long arg1998, -long arg1999, -long arg2000, -long arg2001, -long arg2002, -long arg2003, -long arg2004, -long arg2005, -long arg2006, -long arg2007, -long arg2008, -long arg2009, -long arg2010, -long arg2011, -long arg2012, -long arg2013, -long arg2014, -long arg2015, -long arg2016, -long arg2017, -long arg2018, -long arg2019, -long arg2020, -long arg2021, -long arg2022, -long arg2023, -long arg2024, -long arg2025, -long arg2026, -long arg2027, -long arg2028, -long arg2029, -long arg2030, -long arg2031, -long arg2032, -long arg2033, -long arg2034, -long arg2035, -long arg2036, -long arg2037, -long arg2038, -long arg2039, -long arg2040, -long arg2041, -long arg2042, -long arg2043, -long arg2044, -long arg2045, -long arg2046, -long arg2047, -long arg2048, -long arg2049, -long arg2050, -long arg2051, -long arg2052, -long arg2053, -long arg2054, -long arg2055, -long arg2056, -long arg2057, -long arg2058, -long arg2059, -long arg2060, -long arg2061, -long arg2062, -long arg2063, -long arg2064, -long arg2065, -long arg2066, -long arg2067, -long arg2068, -long arg2069, -long arg2070, -long arg2071, -long arg2072, -long arg2073, -long arg2074, -long arg2075, -long arg2076, -long arg2077, -long arg2078, -long arg2079, -long arg2080, -long arg2081, -long arg2082, -long arg2083, -long arg2084, -long arg2085, -long arg2086, -long arg2087, -long arg2088, -long arg2089, -long arg2090, -long arg2091, -long arg2092, -long arg2093, -long arg2094, -long arg2095, -long arg2096, -long arg2097, -long arg2098, -long arg2099, -long arg2100, -long arg2101, -long arg2102, -long arg2103, -long arg2104, -long arg2105, -long arg2106, -long arg2107, -long arg2108, -long arg2109, -long arg2110, -long arg2111, -long arg2112, -long arg2113, -long arg2114, -long arg2115, -long arg2116, -long arg2117, -long arg2118, -long arg2119, -long arg2120, -long arg2121, -long arg2122, -long arg2123, -long arg2124, -long arg2125, -long arg2126, -long arg2127, -long arg2128, -long arg2129, -long arg2130, -long arg2131, -long arg2132, -long arg2133, -long arg2134, -long arg2135, -long arg2136, -long arg2137, -long arg2138, -long arg2139, -long arg2140, -long arg2141, -long arg2142, -long arg2143, -long arg2144, -long arg2145, -long arg2146, -long arg2147, -long arg2148, -long arg2149, -long arg2150, -long arg2151, -long arg2152, -long arg2153, -long arg2154, -long arg2155, -long arg2156, -long arg2157, -long arg2158, -long arg2159, -long arg2160, -long arg2161, -long arg2162, -long arg2163, -long arg2164, -long arg2165, -long arg2166, -long arg2167, -long arg2168, -long arg2169, -long arg2170, -long arg2171, -long arg2172, -long arg2173, -long arg2174, -long arg2175, -long arg2176, -long arg2177, -long arg2178, -long arg2179, -long arg2180, -long arg2181, -long arg2182, -long arg2183, -long arg2184, -long arg2185, -long arg2186, -long arg2187, -long arg2188, -long arg2189, -long arg2190, -long arg2191, -long arg2192, -long arg2193, -long arg2194, -long arg2195, -long arg2196, -long arg2197, -long arg2198, -long arg2199, -long arg2200, -long arg2201, -long arg2202, -long arg2203, -long arg2204, -long arg2205, -long arg2206, -long arg2207, -long arg2208, -long arg2209, -long arg2210, -long arg2211, -long arg2212, -long arg2213, -long arg2214, -long arg2215, -long arg2216, -long arg2217, -long arg2218, -long arg2219, -long arg2220, -long arg2221, -long arg2222, -long arg2223, -long arg2224, -long arg2225, -long arg2226, -long arg2227, -long arg2228, -long arg2229, -long arg2230, -long arg2231, -long arg2232, -long arg2233, -long arg2234, -long arg2235, -long arg2236, -long arg2237, -long arg2238, -long arg2239, -long arg2240, -long arg2241, -long arg2242, -long arg2243, -long arg2244, -long arg2245, -long arg2246, -long arg2247, -long arg2248, -long arg2249, -long arg2250, -long arg2251, -long arg2252, -long arg2253, -long arg2254, -long arg2255, -long arg2256, -long arg2257, -long arg2258, -long arg2259, -long arg2260, -long arg2261, -long arg2262, -long arg2263, -long arg2264, -long arg2265, -long arg2266, -long arg2267, -long arg2268, -long arg2269, -long arg2270, -long arg2271, -long arg2272, -long arg2273, -long arg2274, -long arg2275, -long arg2276, -long arg2277, -long arg2278, -long arg2279, -long arg2280, -long arg2281, -long arg2282, -long arg2283, -long arg2284, -long arg2285, -long arg2286, -long arg2287, -long arg2288, -long arg2289, -long arg2290, -long arg2291, -long arg2292, -long arg2293, -long arg2294, -long arg2295, -long arg2296, -long arg2297, -long arg2298, -long arg2299, -long arg2300, -long arg2301, -long arg2302, -long arg2303, -long arg2304, -long arg2305, -long arg2306, -long arg2307, -long arg2308, -long arg2309, -long arg2310, -long arg2311, -long arg2312, -long arg2313, -long arg2314, -long arg2315, -long arg2316, -long arg2317, -long arg2318, -long arg2319, -long arg2320, -long arg2321, -long arg2322, -long arg2323, -long arg2324, -long arg2325, -long arg2326, -long arg2327, -long arg2328, -long arg2329, -long arg2330, -long arg2331, -long arg2332, -long arg2333, -long arg2334, -long arg2335, -long arg2336, -long arg2337, -long arg2338, -long arg2339, -long arg2340, -long arg2341, -long arg2342, -long arg2343, -long arg2344, -long arg2345, -long arg2346, -long arg2347, -long arg2348, -long arg2349, -long arg2350, -long arg2351, -long arg2352, -long arg2353, -long arg2354, -long arg2355, -long arg2356, -long arg2357, -long arg2358, -long arg2359, -long arg2360, -long arg2361, -long arg2362, -long arg2363, -long arg2364, -long arg2365, -long arg2366, -long arg2367, -long arg2368, -long arg2369, -long arg2370, -long arg2371, -long arg2372, -long arg2373, -long arg2374, -long arg2375, -long arg2376, -long arg2377, -long arg2378, -long arg2379, -long arg2380, -long arg2381, -long arg2382, -long arg2383, -long arg2384, -long arg2385, -long arg2386, -long arg2387, -long arg2388, -long arg2389, -long arg2390, -long arg2391, -long arg2392, -long arg2393, -long arg2394, -long arg2395, -long arg2396, -long arg2397, -long arg2398, -long arg2399, -long arg2400, -long arg2401, -long arg2402, -long arg2403, -long arg2404, -long arg2405, -long arg2406, -long arg2407, -long arg2408, -long arg2409, -long arg2410, -long arg2411, -long arg2412, -long arg2413, -long arg2414, -long arg2415, -long arg2416, -long arg2417, -long arg2418, -long arg2419, -long arg2420, -long arg2421, -long arg2422, -long arg2423, -long arg2424, -long arg2425, -long arg2426, -long arg2427, -long arg2428, -long arg2429, -long arg2430, -long arg2431, -long arg2432, -long arg2433, -long arg2434, -long arg2435, -long arg2436, -long arg2437, -long arg2438, -long arg2439, -long arg2440, -long arg2441, -long arg2442, -long arg2443, -long arg2444, -long arg2445, -long arg2446, -long arg2447, -long arg2448, -long arg2449, -long arg2450, -long arg2451, -long arg2452, -long arg2453, -long arg2454, -long arg2455, -long arg2456, -long arg2457, -long arg2458, -long arg2459, -long arg2460, -long arg2461, -long arg2462, -long arg2463, -long arg2464, -long arg2465, -long arg2466, -long arg2467, -long arg2468, -long arg2469, -long arg2470, -long arg2471, -long arg2472, -long arg2473, -long arg2474, -long arg2475, -long arg2476, -long arg2477, -long arg2478, -long arg2479, -long arg2480, -long arg2481, -long arg2482, -long arg2483, -long arg2484, -long arg2485, -long arg2486, -long arg2487, -long arg2488, -long arg2489, -long arg2490, -long arg2491, -long arg2492, -long arg2493, -long arg2494, -long arg2495, -long arg2496, -long arg2497, -long arg2498, -long arg2499, -long arg2500, -long arg2501, -long arg2502, -long arg2503, -long arg2504, -long arg2505, -long arg2506, -long arg2507, -long arg2508, -long arg2509, -long arg2510, -long arg2511, -long arg2512, -long arg2513, -long arg2514, -long arg2515, -long arg2516, -long arg2517, -long arg2518, -long arg2519, -long arg2520, -long arg2521, -long arg2522, -long arg2523, -long arg2524, -long arg2525, -long arg2526, -long arg2527, -long arg2528, -long arg2529, -long arg2530, -long arg2531, -long arg2532, -long arg2533, -long arg2534, -long arg2535, -long arg2536, -long arg2537, -long arg2538, -long arg2539, -long arg2540, -long arg2541, -long arg2542, -long arg2543, -long arg2544, -long arg2545, -long arg2546, -long arg2547, -long arg2548, -long arg2549, -long arg2550, -long arg2551, -long arg2552, -long arg2553, -long arg2554, -long arg2555, -long arg2556, -long arg2557, -long arg2558, -long arg2559, -long arg2560, -long arg2561, -long arg2562, -long arg2563, -long arg2564, -long arg2565, -long arg2566, -long arg2567, -long arg2568, -long arg2569, -long arg2570, -long arg2571, -long arg2572, -long arg2573, -long arg2574, -long arg2575, -long arg2576, -long arg2577, -long arg2578, -long arg2579, -long arg2580, -long arg2581, -long arg2582, -long arg2583, -long arg2584, -long arg2585, -long arg2586, -long arg2587, -long arg2588, -long arg2589, -long arg2590, -long arg2591, -long arg2592, -long arg2593, -long arg2594, -long arg2595, -long arg2596, -long arg2597, -long arg2598, -long arg2599, -long arg2600, -long arg2601, -long arg2602, -long arg2603, -long arg2604, -long arg2605, -long arg2606, -long arg2607, -long arg2608, -long arg2609, -long arg2610, -long arg2611, -long arg2612, -long arg2613, -long arg2614, -long arg2615, -long arg2616, -long arg2617, -long arg2618, -long arg2619, -long arg2620, -long arg2621, -long arg2622, -long arg2623, -long arg2624, -long arg2625, -long arg2626, -long arg2627, -long arg2628, -long arg2629, -long arg2630, -long arg2631, -long arg2632, -long arg2633, -long arg2634, -long arg2635, -long arg2636, -long arg2637, -long arg2638, -long arg2639, -long arg2640, -long arg2641, -long arg2642, -long arg2643, -long arg2644, -long arg2645, -long arg2646, -long arg2647, -long arg2648, -long arg2649, -long arg2650, -long arg2651, -long arg2652, -long arg2653, -long arg2654, -long arg2655, -long arg2656, -long arg2657, -long arg2658, -long arg2659, -long arg2660, -long arg2661, -long arg2662, -long arg2663, -long arg2664, -long arg2665, -long arg2666, -long arg2667, -long arg2668, -long arg2669, -long arg2670, -long arg2671, -long arg2672, -long arg2673, -long arg2674, -long arg2675, -long arg2676, -long arg2677, -long arg2678, -long arg2679, -long arg2680, -long arg2681, -long arg2682, -long arg2683, -long arg2684, -long arg2685, -long arg2686, -long arg2687, -long arg2688, -long arg2689, -long arg2690, -long arg2691, -long arg2692, -long arg2693, -long arg2694, -long arg2695, -long arg2696, -long arg2697, -long arg2698, -long arg2699, -long arg2700, -long arg2701, -long arg2702, -long arg2703, -long arg2704, -long arg2705, -long arg2706, -long arg2707, -long arg2708, -long arg2709, -long arg2710, -long arg2711, -long arg2712, -long arg2713, -long arg2714, -long arg2715, -long arg2716, -long arg2717, -long arg2718, -long arg2719, -long arg2720, -long arg2721, -long arg2722, -long arg2723, -long arg2724, -long arg2725, -long arg2726, -long arg2727, -long arg2728, -long arg2729, -long arg2730, -long arg2731, -long arg2732, -long arg2733, -long arg2734, -long arg2735, -long arg2736, -long arg2737, -long arg2738, -long arg2739, -long arg2740, -long arg2741, -long arg2742, -long arg2743, -long arg2744, -long arg2745, -long arg2746, -long arg2747, -long arg2748, -long arg2749, -long arg2750, -long arg2751, -long arg2752, -long arg2753, -long arg2754, -long arg2755, -long arg2756, -long arg2757, -long arg2758, -long arg2759, -long arg2760, -long arg2761, -long arg2762, -long arg2763, -long arg2764, -long arg2765, -long arg2766, -long arg2767, -long arg2768, -long arg2769, -long arg2770, -long arg2771, -long arg2772, -long arg2773, -long arg2774, -long arg2775, -long arg2776, -long arg2777, -long arg2778, -long arg2779, -long arg2780, -long arg2781, -long arg2782, -long arg2783, -long arg2784, -long arg2785, -long arg2786, -long arg2787, -long arg2788, -long arg2789, -long arg2790, -long arg2791, -long arg2792, -long arg2793, -long arg2794, -long arg2795, -long arg2796, -long arg2797, -long arg2798, -long arg2799, -long arg2800, -long arg2801, -long arg2802, -long arg2803, -long arg2804, -long arg2805, -long arg2806, -long arg2807, -long arg2808, -long arg2809, -long arg2810, -long arg2811, -long arg2812, -long arg2813, -long arg2814, -long arg2815, -long arg2816, -long arg2817, -long arg2818, -long arg2819, -long arg2820, -long arg2821, -long arg2822, -long arg2823, -long arg2824, -long arg2825, -long arg2826, -long arg2827, -long arg2828, -long arg2829, -long arg2830, -long arg2831, -long arg2832, -long arg2833, -long arg2834, -long arg2835, -long arg2836, -long arg2837, -long arg2838, -long arg2839, -long arg2840, -long arg2841, -long arg2842, -long arg2843, -long arg2844, -long arg2845, -long arg2846, -long arg2847, -long arg2848, -long arg2849, -long arg2850, -long arg2851, -long arg2852, -long arg2853, -long arg2854, -long arg2855, -long arg2856, -long arg2857, -long arg2858, -long arg2859, -long arg2860, -long arg2861, -long arg2862, -long arg2863, -long arg2864, -long arg2865, -long arg2866, -long arg2867, -long arg2868, -long arg2869, -long arg2870, -long arg2871, -long arg2872, -long arg2873, -long arg2874, -long arg2875, -long arg2876, -long arg2877, -long arg2878, -long arg2879, -long arg2880, -long arg2881, -long arg2882, -long arg2883, -long arg2884, -long arg2885, -long arg2886, -long arg2887, -long arg2888, -long arg2889, -long arg2890, -long arg2891, -long arg2892, -long arg2893, -long arg2894, -long arg2895, -long arg2896, -long arg2897, -long arg2898, -long arg2899, -long arg2900, -long arg2901, -long arg2902, -long arg2903, -long arg2904, -long arg2905, -long arg2906, -long arg2907, -long arg2908, -long arg2909, -long arg2910, -long arg2911, -long arg2912, -long arg2913, -long arg2914, -long arg2915, -long arg2916, -long arg2917, -long arg2918, -long arg2919, -long arg2920, -long arg2921, -long arg2922, -long arg2923, -long arg2924, -long arg2925, -long arg2926, -long arg2927, -long arg2928, -long arg2929, -long arg2930, -long arg2931, -long arg2932, -long arg2933, -long arg2934, -long arg2935, -long arg2936, -long arg2937, -long arg2938, -long arg2939, -long arg2940, -long arg2941, -long arg2942, -long arg2943, -long arg2944, -long arg2945, -long arg2946, -long arg2947, -long arg2948, -long arg2949, -long arg2950, -long arg2951, -long arg2952, -long arg2953, -long arg2954, -long arg2955, -long arg2956, -long arg2957, -long arg2958, -long arg2959, -long arg2960, -long arg2961, -long arg2962, -long arg2963, -long arg2964, -long arg2965, -long arg2966, -long arg2967, -long arg2968, -long arg2969, -long arg2970, -long arg2971, -long arg2972, -long arg2973, -long arg2974, -long arg2975, -long arg2976, -long arg2977, -long arg2978, -long arg2979, -long arg2980, -long arg2981, -long arg2982, -long arg2983, -long arg2984, -long arg2985, -long arg2986, -long arg2987, -long arg2988, -long arg2989, -long arg2990, -long arg2991, -long arg2992, -long arg2993, -long arg2994, -long arg2995, -long arg2996, -long arg2997, -long arg2998, -long arg2999, -long arg3000, -long arg3001, -long arg3002, -long arg3003, -long arg3004, -long arg3005, -long arg3006, -long arg3007, -long arg3008, -long arg3009, -long arg3010, -long arg3011, -long arg3012, -long arg3013, -long arg3014, -long arg3015, -long arg3016, -long arg3017, -long arg3018, -long arg3019, -long arg3020, -long arg3021, -long arg3022, -long arg3023, -long arg3024, -long arg3025, -long arg3026, -long arg3027, -long arg3028, -long arg3029, -long arg3030, -long arg3031, -long arg3032, -long arg3033, -long arg3034, -long arg3035, -long arg3036, -long arg3037, -long arg3038, -long arg3039, -long arg3040, -long arg3041, -long arg3042, -long arg3043, -long arg3044, -long arg3045, -long arg3046, -long arg3047, -long arg3048, -long arg3049, -long arg3050, -long arg3051, -long arg3052, -long arg3053, -long arg3054, -long arg3055, -long arg3056, -long arg3057, -long arg3058, -long arg3059, -long arg3060, -long arg3061, -long arg3062, -long arg3063, -long arg3064, -long arg3065, -long arg3066, -long arg3067, -long arg3068, -long arg3069, -long arg3070, -long arg3071, -long arg3072, -long arg3073, -long arg3074, -long arg3075, -long arg3076, -long arg3077, -long arg3078, -long arg3079, -long arg3080, -long arg3081, -long arg3082, -long arg3083, -long arg3084, -long arg3085, -long arg3086, -long arg3087, -long arg3088, -long arg3089, -long arg3090, -long arg3091, -long arg3092, -long arg3093, -long arg3094, -long arg3095, -long arg3096, -long arg3097, -long arg3098, -long arg3099, -long arg3100, -long arg3101, -long arg3102, -long arg3103, -long arg3104, -long arg3105, -long arg3106, -long arg3107, -long arg3108, -long arg3109, -long arg3110, -long arg3111, -long arg3112, -long arg3113, -long arg3114, -long arg3115, -long arg3116, -long arg3117, -long arg3118, -long arg3119, -long arg3120, -long arg3121, -long arg3122, -long arg3123, -long arg3124, -long arg3125, -long arg3126, -long arg3127, -long arg3128, -long arg3129, -long arg3130, -long arg3131, -long arg3132, -long arg3133, -long arg3134, -long arg3135, -long arg3136, -long arg3137, -long arg3138, -long arg3139, -long arg3140, -long arg3141, -long arg3142, -long arg3143, -long arg3144, -long arg3145, -long arg3146, -long arg3147, -long arg3148, -long arg3149, -long arg3150, -long arg3151, -long arg3152, -long arg3153, -long arg3154, -long arg3155, -long arg3156, -long arg3157, -long arg3158, -long arg3159, -long arg3160, -long arg3161, -long arg3162, -long arg3163, -long arg3164, -long arg3165, -long arg3166, -long arg3167, -long arg3168, -long arg3169, -long arg3170, -long arg3171, -long arg3172, -long arg3173, -long arg3174, -long arg3175, -long arg3176, -long arg3177, -long arg3178, -long arg3179, -long arg3180, -long arg3181, -long arg3182, -long arg3183, -long arg3184, -long arg3185, -long arg3186, -long arg3187, -long arg3188, -long arg3189, -long arg3190, -long arg3191, -long arg3192, -long arg3193, -long arg3194, -long arg3195, -long arg3196, -long arg3197, -long arg3198, -long arg3199, -long arg3200, -long arg3201, -long arg3202, -long arg3203, -long arg3204, -long arg3205, -long arg3206, -long arg3207, -long arg3208, -long arg3209, -long arg3210, -long arg3211, -long arg3212, -long arg3213, -long arg3214, -long arg3215, -long arg3216, -long arg3217, -long arg3218, -long arg3219, -long arg3220, -long arg3221, -long arg3222, -long arg3223, -long arg3224, -long arg3225, -long arg3226, -long arg3227, -long arg3228, -long arg3229, -long arg3230, -long arg3231, -long arg3232, -long arg3233, -long arg3234, -long arg3235, -long arg3236, -long arg3237, -long arg3238, -long arg3239, -long arg3240, -long arg3241, -long arg3242, -long arg3243, -long arg3244, -long arg3245, -long arg3246, -long arg3247, -long arg3248, -long arg3249, -long arg3250, -long arg3251, -long arg3252, -long arg3253, -long arg3254, -long arg3255, -long arg3256, -long arg3257, -long arg3258, -long arg3259, -long arg3260, -long arg3261, -long arg3262, -long arg3263, -long arg3264, -long arg3265, -long arg3266, -long arg3267, -long arg3268, -long arg3269, -long arg3270, -long arg3271, -long arg3272, -long arg3273, -long arg3274, -long arg3275, -long arg3276, -long arg3277, -long arg3278, -long arg3279, -long arg3280, -long arg3281, -long arg3282, -long arg3283, -long arg3284, -long arg3285, -long arg3286, -long arg3287, -long arg3288, -long arg3289, -long arg3290, -long arg3291, -long arg3292, -long arg3293, -long arg3294, -long arg3295, -long arg3296, -long arg3297, -long arg3298, -long arg3299, -long arg3300, -long arg3301, -long arg3302, -long arg3303, -long arg3304, -long arg3305, -long arg3306, -long arg3307, -long arg3308, -long arg3309, -long arg3310, -long arg3311, -long arg3312, -long arg3313, -long arg3314, -long arg3315, -long arg3316, -long arg3317, -long arg3318, -long arg3319, -long arg3320, -long arg3321, -long arg3322, -long arg3323, -long arg3324, -long arg3325, -long arg3326, -long arg3327, -long arg3328, -long arg3329, -long arg3330, -long arg3331, -long arg3332, -long arg3333, -long arg3334, -long arg3335, -long arg3336, -long arg3337, -long arg3338, -long arg3339, -long arg3340, -long arg3341, -long arg3342, -long arg3343, -long arg3344, -long arg3345, -long arg3346, -long arg3347, -long arg3348, -long arg3349, -long arg3350, -long arg3351, -long arg3352, -long arg3353, -long arg3354, -long arg3355, -long arg3356, -long arg3357, -long arg3358, -long arg3359, -long arg3360, -long arg3361, -long arg3362, -long arg3363, -long arg3364, -long arg3365, -long arg3366, -long arg3367, -long arg3368, -long arg3369, -long arg3370, -long arg3371, -long arg3372, -long arg3373, -long arg3374, -long arg3375, -long arg3376, -long arg3377, -long arg3378, -long arg3379, -long arg3380, -long arg3381, -long arg3382, -long arg3383, -long arg3384, -long arg3385, -long arg3386, -long arg3387, -long arg3388, -long arg3389, -long arg3390, -long arg3391, -long arg3392, -long arg3393, -long arg3394, -long arg3395, -long arg3396, -long arg3397, -long arg3398, -long arg3399, -long arg3400, -long arg3401, -long arg3402, -long arg3403, -long arg3404, -long arg3405, -long arg3406, -long arg3407, -long arg3408, -long arg3409, -long arg3410, -long arg3411, -long arg3412, -long arg3413, -long arg3414, -long arg3415, -long arg3416, -long arg3417, -long arg3418, -long arg3419, -long arg3420, -long arg3421, -long arg3422, -long arg3423, -long arg3424, -long arg3425, -long arg3426, -long arg3427, -long arg3428, -long arg3429, -long arg3430, -long arg3431, -long arg3432, -long arg3433, -long arg3434, -long arg3435, -long arg3436, -long arg3437, -long arg3438, -long arg3439, -long arg3440, -long arg3441, -long arg3442, -long arg3443, -long arg3444, -long arg3445, -long arg3446, -long arg3447, -long arg3448, -long arg3449, -long arg3450, -long arg3451, -long arg3452, -long arg3453, -long arg3454, -long arg3455, -long arg3456, -long arg3457, -long arg3458, -long arg3459, -long arg3460, -long arg3461, -long arg3462, -long arg3463, -long arg3464, -long arg3465, -long arg3466, -long arg3467, -long arg3468, -long arg3469, -long arg3470, -long arg3471, -long arg3472, -long arg3473, -long arg3474, -long arg3475, -long arg3476, -long arg3477, -long arg3478, -long arg3479, -long arg3480, -long arg3481, -long arg3482, -long arg3483, -long arg3484, -long arg3485, -long arg3486, -long arg3487, -long arg3488, -long arg3489, -long arg3490, -long arg3491, -long arg3492, -long arg3493, -long arg3494, -long arg3495, -long arg3496, -long arg3497, -long arg3498, -long arg3499, -long arg3500, -long arg3501, -long arg3502, -long arg3503, -long arg3504, -long arg3505, -long arg3506, -long arg3507, -long arg3508, -long arg3509, -long arg3510, -long arg3511, -long arg3512, -long arg3513, -long arg3514, -long arg3515, -long arg3516, -long arg3517, -long arg3518, -long arg3519, -long arg3520, -long arg3521, -long arg3522, -long arg3523, -long arg3524, -long arg3525, -long arg3526, -long arg3527, -long arg3528, -long arg3529, -long arg3530, -long arg3531, -long arg3532, -long arg3533, -long arg3534, -long arg3535, -long arg3536, -long arg3537, -long arg3538, -long arg3539, -long arg3540, -long arg3541, -long arg3542, -long arg3543, -long arg3544, -long arg3545, -long arg3546, -long arg3547, -long arg3548, -long arg3549, -long arg3550, -long arg3551, -long arg3552, -long arg3553, -long arg3554, -long arg3555, -long arg3556, -long arg3557, -long arg3558, -long arg3559, -long arg3560, -long arg3561, -long arg3562, -long arg3563, -long arg3564, -long arg3565, -long arg3566, -long arg3567, -long arg3568, -long arg3569, -long arg3570, -long arg3571, -long arg3572, -long arg3573, -long arg3574, -long arg3575, -long arg3576, -long arg3577, -long arg3578, -long arg3579, -long arg3580, -long arg3581, -long arg3582, -long arg3583, -long arg3584, -long arg3585, -long arg3586, -long arg3587, -long arg3588, -long arg3589, -long arg3590, -long arg3591, -long arg3592, -long arg3593, -long arg3594, -long arg3595, -long arg3596, -long arg3597, -long arg3598, -long arg3599, -long arg3600, -long arg3601, -long arg3602, -long arg3603, -long arg3604, -long arg3605, -long arg3606, -long arg3607, -long arg3608, -long arg3609, -long arg3610, -long arg3611, -long arg3612, -long arg3613, -long arg3614, -long arg3615, -long arg3616, -long arg3617, -long arg3618, -long arg3619, -long arg3620, -long arg3621, -long arg3622, -long arg3623, -long arg3624, -long arg3625, -long arg3626, -long arg3627, -long arg3628, -long arg3629, -long arg3630, -long arg3631, -long arg3632, -long arg3633, -long arg3634, -long arg3635, -long arg3636, -long arg3637, -long arg3638, -long arg3639, -long arg3640, -long arg3641, -long arg3642, -long arg3643, -long arg3644, -long arg3645, -long arg3646, -long arg3647, -long arg3648, -long arg3649, -long arg3650, -long arg3651, -long arg3652, -long arg3653, -long arg3654, -long arg3655, -long arg3656, -long arg3657, -long arg3658, -long arg3659, -long arg3660, -long arg3661, -long arg3662, -long arg3663, -long arg3664, -long arg3665, -long arg3666, -long arg3667, -long arg3668, -long arg3669, -long arg3670, -long arg3671, -long arg3672, -long arg3673, -long arg3674, -long arg3675, -long arg3676, -long arg3677, -long arg3678, -long arg3679, -long arg3680, -long arg3681, -long arg3682, -long arg3683, -long arg3684, -long arg3685, -long arg3686, -long arg3687, -long arg3688, -long arg3689, -long arg3690, -long arg3691, -long arg3692, -long arg3693, -long arg3694, -long arg3695, -long arg3696, -long arg3697, -long arg3698, -long arg3699, -long arg3700, -long arg3701, -long arg3702, -long arg3703, -long arg3704, -long arg3705, -long arg3706, -long arg3707, -long arg3708, -long arg3709, -long arg3710, -long arg3711, -long arg3712, -long arg3713, -long arg3714, -long arg3715, -long arg3716, -long arg3717, -long arg3718, -long arg3719, -long arg3720, -long arg3721, -long arg3722, -long arg3723, -long arg3724, -long arg3725, -long arg3726, -long arg3727, -long arg3728, -long arg3729, -long arg3730, -long arg3731, -long arg3732, -long arg3733, -long arg3734, -long arg3735, -long arg3736, -long arg3737, -long arg3738, -long arg3739, -long arg3740, -long arg3741, -long arg3742, -long arg3743, -long arg3744, -long arg3745, -long arg3746, -long arg3747, -long arg3748, -long arg3749, -long arg3750, -long arg3751, -long arg3752, -long arg3753, -long arg3754, -long arg3755, -long arg3756, -long arg3757, -long arg3758, -long arg3759, -long arg3760, -long arg3761, -long arg3762, -long arg3763, -long arg3764, -long arg3765, -long arg3766, -long arg3767, -long arg3768, -long arg3769, -long arg3770, -long arg3771, -long arg3772, -long arg3773, -long arg3774, -long arg3775, -long arg3776, -long arg3777, -long arg3778, -long arg3779, -long arg3780, -long arg3781, -long arg3782, -long arg3783, -long arg3784, -long arg3785, -long arg3786, -long arg3787, -long arg3788, -long arg3789, -long arg3790, -long arg3791, -long arg3792, -long arg3793, -long arg3794, -long arg3795, -long arg3796, -long arg3797, -long arg3798, -long arg3799, -long arg3800, -long arg3801, -long arg3802, -long arg3803, -long arg3804, -long arg3805, -long arg3806, -long arg3807, -long arg3808, -long arg3809, -long arg3810, -long arg3811, -long arg3812, -long arg3813, -long arg3814, -long arg3815, -long arg3816, -long arg3817, -long arg3818, -long arg3819, -long arg3820, -long arg3821, -long arg3822, -long arg3823, -long arg3824, -long arg3825, -long arg3826, -long arg3827, -long arg3828, -long arg3829, -long arg3830, -long arg3831, -long arg3832, -long arg3833, -long arg3834, -long arg3835, -long arg3836, -long arg3837, -long arg3838, -long arg3839, -long arg3840, -long arg3841, -long arg3842, -long arg3843, -long arg3844, -long arg3845, -long arg3846, -long arg3847, -long arg3848, -long arg3849, -long arg3850, -long arg3851, -long arg3852, -long arg3853, -long arg3854, -long arg3855, -long arg3856, -long arg3857, -long arg3858, -long arg3859, -long arg3860, -long arg3861, -long arg3862, -long arg3863, -long arg3864, -long arg3865, -long arg3866, -long arg3867, -long arg3868, -long arg3869, -long arg3870, -long arg3871, -long arg3872, -long arg3873, -long arg3874, -long arg3875, -long arg3876, -long arg3877, -long arg3878, -long arg3879, -long arg3880, -long arg3881, -long arg3882, -long arg3883, -long arg3884, -long arg3885, -long arg3886, -long arg3887, -long arg3888, -long arg3889, -long arg3890, -long arg3891, -long arg3892, -long arg3893, -long arg3894, -long arg3895, -long arg3896, -long arg3897, -long arg3898, -long arg3899, -long arg3900, -long arg3901, -long arg3902, -long arg3903, -long arg3904, -long arg3905, -long arg3906, -long arg3907, -long arg3908, -long arg3909, -long arg3910, -long arg3911, -long arg3912, -long arg3913, -long arg3914, -long arg3915, -long arg3916, -long arg3917, -long arg3918, -long arg3919, -long arg3920, -long arg3921, -long arg3922, -long arg3923, -long arg3924, -long arg3925, -long arg3926, -long arg3927, -long arg3928, -long arg3929, -long arg3930, -long arg3931, -long arg3932, -long arg3933, -long arg3934, -long arg3935, -long arg3936, -long arg3937, -long arg3938, -long arg3939, -long arg3940, -long arg3941, -long arg3942, -long arg3943, -long arg3944, -long arg3945, -long arg3946, -long arg3947, -long arg3948, -long arg3949, -long arg3950, -long arg3951, -long arg3952, -long arg3953, -long arg3954, -long arg3955, -long arg3956, -long arg3957, -long arg3958, -long arg3959, -long arg3960, -long arg3961, -long arg3962, -long arg3963, -long arg3964, -long arg3965, -long arg3966, -long arg3967, -long arg3968, -long arg3969, -long arg3970, -long arg3971, -long arg3972, -long arg3973, -long arg3974, -long arg3975, -long arg3976, -long arg3977, -long arg3978, -long arg3979, -long arg3980, -long arg3981, -long arg3982, -long arg3983, -long arg3984, -long arg3985, -long arg3986, -long arg3987, -long arg3988, -long arg3989, -long arg3990, -long arg3991, -long arg3992, -long arg3993, -long arg3994, -long arg3995, -long arg3996, -long arg3997, -long arg3998, -long arg3999, -long arg4000, -long arg4001, -long arg4002, -long arg4003, -long arg4004, -long arg4005, -long arg4006, -long arg4007, -long arg4008, -long arg4009, -long arg4010, -long arg4011, -long arg4012, -long arg4013, -long arg4014, -long arg4015, -long arg4016, -long arg4017, -long arg4018, -long arg4019, -long arg4020, -long arg4021, -long arg4022, -long arg4023, -long arg4024, -long arg4025, -long arg4026, -long arg4027, -long arg4028, -long arg4029, -long arg4030, -long arg4031, -long arg4032, -long arg4033, -long arg4034, -long arg4035, -long arg4036, -long arg4037, -long arg4038, -long arg4039, -long arg4040, -long arg4041, -long arg4042, -long arg4043, -long arg4044, -long arg4045, -long arg4046, -long arg4047, -long arg4048, -long arg4049, -long arg4050, -long arg4051, -long arg4052, -long arg4053, -long arg4054, -long arg4055, -long arg4056, -long arg4057, -long arg4058, -long arg4059, -long arg4060, -long arg4061, -long arg4062, -long arg4063, -long arg4064, -long arg4065, -long arg4066, -long arg4067, -long arg4068, -long arg4069, -long arg4070, -long arg4071, -long arg4072, -long arg4073, -long arg4074, -long arg4075, -long arg4076, -long arg4077, -long arg4078, -long arg4079, -long arg4080, -long arg4081, -long arg4082, -long arg4083, -long arg4084, -long arg4085, -long arg4086, -long arg4087, -long arg4088, -long arg4089, -long arg4090, -long arg4091, -long arg4092, -long arg4093, -long arg4094, -long arg4095, -long arg4096, -long arg4097, -long arg4098, -long arg4099, -long arg4100, -long arg4101, -long arg4102, -long arg4103, -long arg4104, -long arg4105, -long arg4106, -long arg4107, -long arg4108, -long arg4109, -long arg4110, -long arg4111, -long arg4112, -long arg4113, -long arg4114, -long arg4115, -long arg4116, -long arg4117, -long arg4118, -long arg4119, -long arg4120, -long arg4121, -long arg4122, -long arg4123, -long arg4124, -long arg4125, -long arg4126, -long arg4127, -long arg4128, -long arg4129, -long arg4130, -long arg4131, -long arg4132, -long arg4133, -long arg4134, -long arg4135, -long arg4136, -long arg4137, -long arg4138, -long arg4139, -long arg4140, -long arg4141, -long arg4142, -long arg4143, -long arg4144, -long arg4145, -long arg4146, -long arg4147, -long arg4148, -long arg4149, -long arg4150, -long arg4151, -long arg4152, -long arg4153, -long arg4154, -long arg4155, -long arg4156, -long arg4157, -long arg4158, -long arg4159, -long arg4160, -long arg4161, -long arg4162, -long arg4163, -long arg4164, -long arg4165, -long arg4166, -long arg4167, -long arg4168, -long arg4169, -long arg4170, -long arg4171, -long arg4172, -long arg4173, -long arg4174, -long arg4175, -long arg4176, -long arg4177, -long arg4178, -long arg4179, -long arg4180, -long arg4181, -long arg4182, -long arg4183, -long arg4184, -long arg4185, -long arg4186, -long arg4187, -long arg4188, -long arg4189, -long arg4190, -long arg4191, -long arg4192, -long arg4193, -long arg4194, -long arg4195, -long arg4196, -long arg4197, -long arg4198, -long arg4199, -long arg4200, -long arg4201, -long arg4202, -long arg4203, -long arg4204, -long arg4205, -long arg4206, -long arg4207, -long arg4208, -long arg4209, -long arg4210, -long arg4211, -long arg4212, -long arg4213, -long arg4214, -long arg4215, -long arg4216, -long arg4217, -long arg4218, -long arg4219, -long arg4220, -long arg4221, -long arg4222, -long arg4223, -long arg4224, -long arg4225, -long arg4226, -long arg4227, -long arg4228, -long arg4229, -long arg4230, -long arg4231, -long arg4232, -long arg4233, -long arg4234, -long arg4235, -long arg4236, -long arg4237, -long arg4238, -long arg4239, -long arg4240, -long arg4241, -long arg4242, -long arg4243, -long arg4244, -long arg4245, -long arg4246, -long arg4247, -long arg4248, -long arg4249, -long arg4250, -long arg4251, -long arg4252, -long arg4253, -long arg4254, -long arg4255, -long arg4256, -long arg4257, -long arg4258, -long arg4259, -long arg4260, -long arg4261, -long arg4262, -long arg4263, -long arg4264, -long arg4265, -long arg4266, -long arg4267, -long arg4268, -long arg4269, -long arg4270, -long arg4271, -long arg4272, -long arg4273, -long arg4274, -long arg4275, -long arg4276, -long arg4277, -long arg4278, -long arg4279, -long arg4280, -long arg4281, -long arg4282, -long arg4283, -long arg4284, -long arg4285, -long arg4286, -long arg4287, -long arg4288, -long arg4289, -long arg4290, -long arg4291, -long arg4292, -long arg4293, -long arg4294, -long arg4295, -long arg4296, -long arg4297, -long arg4298, -long arg4299, -long arg4300, -long arg4301, -long arg4302, -long arg4303, -long arg4304, -long arg4305, -long arg4306, -long arg4307, -long arg4308, -long arg4309, -long arg4310, -long arg4311, -long arg4312, -long arg4313, -long arg4314, -long arg4315, -long arg4316, -long arg4317, -long arg4318, -long arg4319, -long arg4320, -long arg4321, -long arg4322, -long arg4323, -long arg4324, -long arg4325, -long arg4326, -long arg4327, -long arg4328, -long arg4329, -long arg4330, -long arg4331, -long arg4332, -long arg4333, -long arg4334, -long arg4335, -long arg4336, -long arg4337, -long arg4338, -long arg4339, -long arg4340, -long arg4341, -long arg4342, -long arg4343, -long arg4344, -long arg4345, -long arg4346, -long arg4347, -long arg4348, -long arg4349, -long arg4350, -long arg4351, -long arg4352, -long arg4353, -long arg4354, -long arg4355, -long arg4356, -long arg4357, -long arg4358, -long arg4359, -long arg4360, -long arg4361, -long arg4362, -long arg4363, -long arg4364, -long arg4365, -long arg4366, -long arg4367, -long arg4368, -long arg4369, -long arg4370, -long arg4371, -long arg4372, -long arg4373, -long arg4374, -long arg4375, -long arg4376, -long arg4377, -long arg4378, -long arg4379, -long arg4380, -long arg4381, -long arg4382, -long arg4383, -long arg4384, -long arg4385, -long arg4386, -long arg4387, -long arg4388, -long arg4389, -long arg4390, -long arg4391, -long arg4392, -long arg4393, -long arg4394, -long arg4395, -long arg4396, -long arg4397, -long arg4398, -long arg4399, -long arg4400, -long arg4401, -long arg4402, -long arg4403, -long arg4404, -long arg4405, -long arg4406, -long arg4407, -long arg4408, -long arg4409, -long arg4410, -long arg4411, -long arg4412, -long arg4413, -long arg4414, -long arg4415, -long arg4416, -long arg4417, -long arg4418, -long arg4419, -long arg4420, -long arg4421, -long arg4422, -long arg4423, -long arg4424, -long arg4425, -long arg4426, -long arg4427, -long arg4428, -long arg4429, -long arg4430, -long arg4431, -long arg4432, -long arg4433, -long arg4434, -long arg4435, -long arg4436, -long arg4437, -long arg4438, -long arg4439, -long arg4440, -long arg4441, -long arg4442, -long arg4443, -long arg4444, -long arg4445, -long arg4446, -long arg4447, -long arg4448, -long arg4449, -long arg4450, -long arg4451, -long arg4452, -long arg4453, -long arg4454, -long arg4455, -long arg4456, -long arg4457, -long arg4458, -long arg4459, -long arg4460, -long arg4461, -long arg4462, -long arg4463, -long arg4464, -long arg4465, -long arg4466, -long arg4467, -long arg4468, -long arg4469, -long arg4470, -long arg4471, -long arg4472, -long arg4473, -long arg4474, -long arg4475, -long arg4476, -long arg4477, -long arg4478, -long arg4479, -long arg4480, -long arg4481, -long arg4482, -long arg4483, -long arg4484, -long arg4485, -long arg4486, -long arg4487, -long arg4488, -long arg4489, -long arg4490, -long arg4491, -long arg4492, -long arg4493, -long arg4494, -long arg4495, -long arg4496, -long arg4497, -long arg4498, -long arg4499, -long arg4500, -long arg4501, -long arg4502, -long arg4503, -long arg4504, -long arg4505, -long arg4506, -long arg4507, -long arg4508, -long arg4509, -long arg4510, -long arg4511, -long arg4512, -long arg4513, -long arg4514, -long arg4515, -long arg4516, -long arg4517, -long arg4518, -long arg4519, -long arg4520, -long arg4521, -long arg4522, -long arg4523, -long arg4524, -long arg4525, -long arg4526, -long arg4527, -long arg4528, -long arg4529, -long arg4530, -long arg4531, -long arg4532, -long arg4533, -long arg4534, -long arg4535, -long arg4536, -long arg4537, -long arg4538, -long arg4539, -long arg4540, -long arg4541, -long arg4542, -long arg4543, -long arg4544, -long arg4545, -long arg4546, -long arg4547, -long arg4548, -long arg4549, -long arg4550, -long arg4551, -long arg4552, -long arg4553, -long arg4554, -long arg4555, -long arg4556, -long arg4557, -long arg4558, -long arg4559, -long arg4560, -long arg4561, -long arg4562, -long arg4563, -long arg4564, -long arg4565, -long arg4566, -long arg4567, -long arg4568, -long arg4569, -long arg4570, -long arg4571, -long arg4572, -long arg4573, -long arg4574, -long arg4575, -long arg4576, -long arg4577, -long arg4578, -long arg4579, -long arg4580, -long arg4581, -long arg4582, -long arg4583, -long arg4584, -long arg4585, -long arg4586, -long arg4587, -long arg4588, -long arg4589, -long arg4590, -long arg4591, -long arg4592, -long arg4593, -long arg4594, -long arg4595, -long arg4596, -long arg4597, -long arg4598, -long arg4599, -long arg4600, -long arg4601, -long arg4602, -long arg4603, -long arg4604, -long arg4605, -long arg4606, -long arg4607, -long arg4608, -long arg4609, -long arg4610, -long arg4611, -long arg4612, -long arg4613, -long arg4614, -long arg4615, -long arg4616, -long arg4617, -long arg4618, -long arg4619, -long arg4620, -long arg4621, -long arg4622, -long arg4623, -long arg4624, -long arg4625, -long arg4626, -long arg4627, -long arg4628, -long arg4629, -long arg4630, -long arg4631, -long arg4632, -long arg4633, -long arg4634, -long arg4635, -long arg4636, -long arg4637, -long arg4638, -long arg4639, -long arg4640, -long arg4641, -long arg4642, -long arg4643, -long arg4644, -long arg4645, -long arg4646, -long arg4647, -long arg4648, -long arg4649, -long arg4650, -long arg4651, -long arg4652, -long arg4653, -long arg4654, -long arg4655, -long arg4656, -long arg4657, -long arg4658, -long arg4659, -long arg4660, -long arg4661, -long arg4662, -long arg4663, -long arg4664, -long arg4665, -long arg4666, -long arg4667, -long arg4668, -long arg4669, -long arg4670, -long arg4671, -long arg4672, -long arg4673, -long arg4674, -long arg4675, -long arg4676, -long arg4677, -long arg4678, -long arg4679, -long arg4680, -long arg4681, -long arg4682, -long arg4683, -long arg4684, -long arg4685, -long arg4686, -long arg4687, -long arg4688, -long arg4689, -long arg4690, -long arg4691, -long arg4692, -long arg4693, -long arg4694, -long arg4695, -long arg4696, -long arg4697, -long arg4698, -long arg4699, -long arg4700, -long arg4701, -long arg4702, -long arg4703, -long arg4704, -long arg4705, -long arg4706, -long arg4707, -long arg4708, -long arg4709, -long arg4710, -long arg4711, -long arg4712, -long arg4713, -long arg4714, -long arg4715, -long arg4716, -long arg4717, -long arg4718, -long arg4719, -long arg4720, -long arg4721, -long arg4722, -long arg4723, -long arg4724, -long arg4725, -long arg4726, -long arg4727, -long arg4728, -long arg4729, -long arg4730, -long arg4731, -long arg4732, -long arg4733, -long arg4734, -long arg4735, -long arg4736, -long arg4737, -long arg4738, -long arg4739, -long arg4740, -long arg4741, -long arg4742, -long arg4743, -long arg4744, -long arg4745, -long arg4746, -long arg4747, -long arg4748, -long arg4749, -long arg4750, -long arg4751, -long arg4752, -long arg4753, -long arg4754, -long arg4755, -long arg4756, -long arg4757, -long arg4758, -long arg4759, -long arg4760, -long arg4761, -long arg4762, -long arg4763, -long arg4764, -long arg4765, -long arg4766, -long arg4767, -long arg4768, -long arg4769, -long arg4770, -long arg4771, -long arg4772, -long arg4773, -long arg4774, -long arg4775, -long arg4776, -long arg4777, -long arg4778, -long arg4779, -long arg4780, -long arg4781, -long arg4782, -long arg4783, -long arg4784, -long arg4785, -long arg4786, -long arg4787, -long arg4788, -long arg4789, -long arg4790, -long arg4791, -long arg4792, -long arg4793, -long arg4794, -long arg4795, -long arg4796, -long arg4797, -long arg4798, -long arg4799, -long arg4800, -long arg4801, -long arg4802, -long arg4803, -long arg4804, -long arg4805, -long arg4806, -long arg4807, -long arg4808, -long arg4809, -long arg4810, -long arg4811, -long arg4812, -long arg4813, -long arg4814, -long arg4815, -long arg4816, -long arg4817, -long arg4818, -long arg4819, -long arg4820, -long arg4821, -long arg4822, -long arg4823, -long arg4824, -long arg4825, -long arg4826, -long arg4827, -long arg4828, -long arg4829, -long arg4830, -long arg4831, -long arg4832, -long arg4833, -long arg4834, -long arg4835, -long arg4836, -long arg4837, -long arg4838, -long arg4839, -long arg4840, -long arg4841, -long arg4842, -long arg4843, -long arg4844, -long arg4845, -long arg4846, -long arg4847, -long arg4848, -long arg4849, -long arg4850, -long arg4851, -long arg4852, -long arg4853, -long arg4854, -long arg4855, -long arg4856, -long arg4857, -long arg4858, -long arg4859, -long arg4860, -long arg4861, -long arg4862, -long arg4863, -long arg4864, -long arg4865, -long arg4866, -long arg4867, -long arg4868, -long arg4869, -long arg4870, -long arg4871, -long arg4872, -long arg4873, -long arg4874, -long arg4875, -long arg4876, -long arg4877, -long arg4878, -long arg4879, -long arg4880, -long arg4881, -long arg4882, -long arg4883, -long arg4884, -long arg4885, -long arg4886, -long arg4887, -long arg4888, -long arg4889, -long arg4890, -long arg4891, -long arg4892, -long arg4893, -long arg4894, -long arg4895, -long arg4896, -long arg4897, -long arg4898, -long arg4899, -long arg4900, -long arg4901, -long arg4902, -long arg4903, -long arg4904, -long arg4905, -long arg4906, -long arg4907, -long arg4908, -long arg4909, -long arg4910, -long arg4911, -long arg4912, -long arg4913, -long arg4914, -long arg4915, -long arg4916, -long arg4917, -long arg4918, -long arg4919, -long arg4920, -long arg4921, -long arg4922, -long arg4923, -long arg4924, -long arg4925, -long arg4926, -long arg4927, -long arg4928, -long arg4929, -long arg4930, -long arg4931, -long arg4932, -long arg4933, -long arg4934, -long arg4935, -long arg4936, -long arg4937, -long arg4938, -long arg4939, -long arg4940, -long arg4941, -long arg4942, -long arg4943, -long arg4944, -long arg4945, -long arg4946, -long arg4947, -long arg4948, -long arg4949, -long arg4950, -long arg4951, -long arg4952, -long arg4953, -long arg4954, -long arg4955, -long arg4956, -long arg4957, -long arg4958, -long arg4959, -long arg4960, -long arg4961, -long arg4962, -long arg4963, -long arg4964, -long arg4965, -long arg4966, -long arg4967, -long arg4968, -long arg4969, -long arg4970, -long arg4971, -long arg4972, -long arg4973, -long arg4974, -long arg4975, -long arg4976, -long arg4977, -long arg4978, -long arg4979, -long arg4980, -long arg4981, -long arg4982, -long arg4983, -long arg4984, -long arg4985, -long arg4986, -long arg4987, -long arg4988, -long arg4989, -long arg4990, -long arg4991, -long arg4992, -long arg4993, -long arg4994, -long arg4995, -long arg4996, -long arg4997, -long arg4998, -long arg4999, -long arg5000, -long arg5001, -long arg5002, -long arg5003, -long arg5004, -long arg5005, -long arg5006, -long arg5007, -long arg5008, -long arg5009, -long arg5010, -long arg5011, -long arg5012, -long arg5013, -long arg5014, -long arg5015, -long arg5016, -long arg5017, -long arg5018, -long arg5019, -long arg5020, -long arg5021, -long arg5022, -long arg5023, -long arg5024, -long arg5025, -long arg5026, -long arg5027, -long arg5028, -long arg5029, -long arg5030, -long arg5031, -long arg5032, -long arg5033, -long arg5034, -long arg5035, -long arg5036, -long arg5037, -long arg5038, -long arg5039, -long arg5040, -long arg5041, -long arg5042, -long arg5043, -long arg5044, -long arg5045, -long arg5046, -long arg5047, -long arg5048, -long arg5049, -long arg5050, -long arg5051, -long arg5052, -long arg5053, -long arg5054, -long arg5055, -long arg5056, -long arg5057, -long arg5058, -long arg5059, -long arg5060, -long arg5061, -long arg5062, -long arg5063, -long arg5064, -long arg5065, -long arg5066, -long arg5067, -long arg5068, -long arg5069, -long arg5070, -long arg5071, -long arg5072, -long arg5073, -long arg5074, -long arg5075, -long arg5076, -long arg5077, -long arg5078, -long arg5079, -long arg5080, -long arg5081, -long arg5082, -long arg5083, -long arg5084, -long arg5085, -long arg5086, -long arg5087, -long arg5088, -long arg5089, -long arg5090, -long arg5091, -long arg5092, -long arg5093, -long arg5094, -long arg5095, -long arg5096, -long arg5097, -long arg5098, -long arg5099, -long arg5100, -long arg5101, -long arg5102, -long arg5103, -long arg5104, -long arg5105, -long arg5106, -long arg5107, -long arg5108, -long arg5109, -long arg5110, -long arg5111, -long arg5112, -long arg5113, -long arg5114, -long arg5115, -long arg5116, -long arg5117, -long arg5118, -long arg5119, -long arg5120, -long arg5121, -long arg5122, -long arg5123, -long arg5124, -long arg5125, -long arg5126, -long arg5127, -long arg5128, -long arg5129, -long arg5130, -long arg5131, -long arg5132, -long arg5133, -long arg5134, -long arg5135, -long arg5136, -long arg5137, -long arg5138, -long arg5139, -long arg5140, -long arg5141, -long arg5142, -long arg5143, -long arg5144, -long arg5145, -long arg5146, -long arg5147, -long arg5148, -long arg5149, -long arg5150, -long arg5151, -long arg5152, -long arg5153, -long arg5154, -long arg5155, -long arg5156, -long arg5157, -long arg5158, -long arg5159, -long arg5160, -long arg5161, -long arg5162, -long arg5163, -long arg5164, -long arg5165, -long arg5166, -long arg5167, -long arg5168, -long arg5169, -long arg5170, -long arg5171, -long arg5172, -long arg5173, -long arg5174, -long arg5175, -long arg5176, -long arg5177, -long arg5178, -long arg5179, -long arg5180, -long arg5181, -long arg5182, -long arg5183, -long arg5184, -long arg5185, -long arg5186, -long arg5187, -long arg5188, -long arg5189, -long arg5190, -long arg5191, -long arg5192, -long arg5193, -long arg5194, -long arg5195, -long arg5196, -long arg5197, -long arg5198, -long arg5199, -long arg5200, -long arg5201, -long arg5202, -long arg5203, -long arg5204, -long arg5205, -long arg5206, -long arg5207, -long arg5208, -long arg5209, -long arg5210, -long arg5211, -long arg5212, -long arg5213, -long arg5214, -long arg5215, -long arg5216, -long arg5217, -long arg5218, -long arg5219, -long arg5220, -long arg5221, -long arg5222, -long arg5223, -long arg5224, -long arg5225, -long arg5226, -long arg5227, -long arg5228, -long arg5229, -long arg5230, -long arg5231, -long arg5232, -long arg5233, -long arg5234, -long arg5235, -long arg5236, -long arg5237, -long arg5238, -long arg5239, -long arg5240, -long arg5241, -long arg5242, -long arg5243, -long arg5244, -long arg5245, -long arg5246, -long arg5247, -long arg5248, -long arg5249, -long arg5250, -long arg5251, -long arg5252, -long arg5253, -long arg5254, -long arg5255, -long arg5256, -long arg5257, -long arg5258, -long arg5259, -long arg5260, -long arg5261, -long arg5262, -long arg5263, -long arg5264, -long arg5265, -long arg5266, -long arg5267, -long arg5268, -long arg5269, -long arg5270, -long arg5271, -long arg5272, -long arg5273, -long arg5274, -long arg5275, -long arg5276, -long arg5277, -long arg5278, -long arg5279, -long arg5280, -long arg5281, -long arg5282, -long arg5283, -long arg5284, -long arg5285, -long arg5286, -long arg5287, -long arg5288, -long arg5289, -long arg5290, -long arg5291, -long arg5292, -long arg5293, -long arg5294, -long arg5295, -long arg5296, -long arg5297, -long arg5298, -long arg5299, -long arg5300, -long arg5301, -long arg5302, -long arg5303, -long arg5304, -long arg5305, -long arg5306, -long arg5307, -long arg5308, -long arg5309, -long arg5310, -long arg5311, -long arg5312, -long arg5313, -long arg5314, -long arg5315, -long arg5316, -long arg5317, -long arg5318, -long arg5319, -long arg5320, -long arg5321, -long arg5322, -long arg5323, -long arg5324, -long arg5325, -long arg5326, -long arg5327, -long arg5328, -long arg5329, -long arg5330, -long arg5331, -long arg5332, -long arg5333, -long arg5334, -long arg5335, -long arg5336, -long arg5337, -long arg5338, -long arg5339, -long arg5340, -long arg5341, -long arg5342, -long arg5343, -long arg5344, -long arg5345, -long arg5346, -long arg5347, -long arg5348, -long arg5349, -long arg5350, -long arg5351, -long arg5352, -long arg5353, -long arg5354, -long arg5355, -long arg5356, -long arg5357, -long arg5358, -long arg5359, -long arg5360, -long arg5361, -long arg5362, -long arg5363, -long arg5364, -long arg5365, -long arg5366, -long arg5367, -long arg5368, -long arg5369, -long arg5370, -long arg5371, -long arg5372, -long arg5373, -long arg5374, -long arg5375, -long arg5376, -long arg5377, -long arg5378, -long arg5379, -long arg5380, -long arg5381, -long arg5382, -long arg5383, -long arg5384, -long arg5385, -long arg5386, -long arg5387, -long arg5388, -long arg5389, -long arg5390, -long arg5391, -long arg5392, -long arg5393, -long arg5394, -long arg5395, -long arg5396, -long arg5397, -long arg5398, -long arg5399, -long arg5400, -long arg5401, -long arg5402, -long arg5403, -long arg5404, -long arg5405, -long arg5406, -long arg5407, -long arg5408, -long arg5409, -long arg5410, -long arg5411, -long arg5412, -long arg5413, -long arg5414, -long arg5415, -long arg5416, -long arg5417, -long arg5418, -long arg5419, -long arg5420, -long arg5421, -long arg5422, -long arg5423, -long arg5424, -long arg5425, -long arg5426, -long arg5427, -long arg5428, -long arg5429, -long arg5430, -long arg5431, -long arg5432, -long arg5433, -long arg5434, -long arg5435, -long arg5436, -long arg5437, -long arg5438, -long arg5439, -long arg5440, -long arg5441, -long arg5442, -long arg5443, -long arg5444, -long arg5445, -long arg5446, -long arg5447, -long arg5448, -long arg5449, -long arg5450, -long arg5451, -long arg5452, -long arg5453, -long arg5454, -long arg5455, -long arg5456, -long arg5457, -long arg5458, -long arg5459, -long arg5460, -long arg5461, -long arg5462, -long arg5463, -long arg5464, -long arg5465, -long arg5466, -long arg5467, -long arg5468, -long arg5469, -long arg5470, -long arg5471, -long arg5472, -long arg5473, -long arg5474, -long arg5475, -long arg5476, -long arg5477, -long arg5478, -long arg5479, -long arg5480, -long arg5481, -long arg5482, -long arg5483, -long arg5484, -long arg5485, -long arg5486, -long arg5487, -long arg5488, -long arg5489, -long arg5490, -long arg5491, -long arg5492, -long arg5493, -long arg5494, -long arg5495, -long arg5496, -long arg5497, -long arg5498, -long arg5499, -long arg5500, -long arg5501, -long arg5502, -long arg5503, -long arg5504, -long arg5505, -long arg5506, -long arg5507, -long arg5508, -long arg5509, -long arg5510, -long arg5511, -long arg5512, -long arg5513, -long arg5514, -long arg5515, -long arg5516, -long arg5517, -long arg5518, -long arg5519, -long arg5520, -long arg5521, -long arg5522, -long arg5523, -long arg5524, -long arg5525, -long arg5526, -long arg5527, -long arg5528, -long arg5529, -long arg5530, -long arg5531, -long arg5532, -long arg5533, -long arg5534, -long arg5535, -long arg5536, -long arg5537, -long arg5538, -long arg5539, -long arg5540, -long arg5541, -long arg5542, -long arg5543, -long arg5544, -long arg5545, -long arg5546, -long arg5547, -long arg5548, -long arg5549, -long arg5550, -long arg5551, -long arg5552, -long arg5553, -long arg5554, -long arg5555, -long arg5556, -long arg5557, -long arg5558, -long arg5559, -long arg5560, -long arg5561, -long arg5562, -long arg5563, -long arg5564, -long arg5565, -long arg5566, -long arg5567, -long arg5568, -long arg5569, -long arg5570, -long arg5571, -long arg5572, -long arg5573, -long arg5574, -long arg5575, -long arg5576, -long arg5577, -long arg5578, -long arg5579, -long arg5580, -long arg5581, -long arg5582, -long arg5583, -long arg5584, -long arg5585, -long arg5586, -long arg5587, -long arg5588, -long arg5589, -long arg5590, -long arg5591, -long arg5592, -long arg5593, -long arg5594, -long arg5595, -long arg5596, -long arg5597, -long arg5598, -long arg5599, -long arg5600, -long arg5601, -long arg5602, -long arg5603, -long arg5604, -long arg5605, -long arg5606, -long arg5607, -long arg5608, -long arg5609, -long arg5610, -long arg5611, -long arg5612, -long arg5613, -long arg5614, -long arg5615, -long arg5616, -long arg5617, -long arg5618, -long arg5619, -long arg5620, -long arg5621, -long arg5622, -long arg5623, -long arg5624, -long arg5625, -long arg5626, -long arg5627, -long arg5628, -long arg5629, -long arg5630, -long arg5631, -long arg5632, -long arg5633, -long arg5634, -long arg5635, -long arg5636, -long arg5637, -long arg5638, -long arg5639, -long arg5640, -long arg5641, -long arg5642, -long arg5643, -long arg5644, -long arg5645, -long arg5646, -long arg5647, -long arg5648, -long arg5649, -long arg5650, -long arg5651, -long arg5652, -long arg5653, -long arg5654, -long arg5655, -long arg5656, -long arg5657, -long arg5658, -long arg5659, -long arg5660, -long arg5661, -long arg5662, -long arg5663, -long arg5664, -long arg5665, -long arg5666, -long arg5667, -long arg5668, -long arg5669, -long arg5670, -long arg5671, -long arg5672, -long arg5673, -long arg5674, -long arg5675, -long arg5676, -long arg5677, -long arg5678, -long arg5679, -long arg5680, -long arg5681, -long arg5682, -long arg5683, -long arg5684, -long arg5685, -long arg5686, -long arg5687, -long arg5688, -long arg5689, -long arg5690, -long arg5691, -long arg5692, -long arg5693, -long arg5694, -long arg5695, -long arg5696, -long arg5697, -long arg5698, -long arg5699, -long arg5700, -long arg5701, -long arg5702, -long arg5703, -long arg5704, -long arg5705, -long arg5706, -long arg5707, -long arg5708, -long arg5709, -long arg5710, -long arg5711, -long arg5712, -long arg5713, -long arg5714, -long arg5715, -long arg5716, -long arg5717, -long arg5718, -long arg5719, -long arg5720, -long arg5721, -long arg5722, -long arg5723, -long arg5724, -long arg5725, -long arg5726, -long arg5727, -long arg5728, -long arg5729, -long arg5730, -long arg5731, -long arg5732, -long arg5733, -long arg5734, -long arg5735, -long arg5736, -long arg5737, -long arg5738, -long arg5739, -long arg5740, -long arg5741, -long arg5742, -long arg5743, -long arg5744, -long arg5745, -long arg5746, -long arg5747, -long arg5748, -long arg5749, -long arg5750, -long arg5751, -long arg5752, -long arg5753, -long arg5754, -long arg5755, -long arg5756, -long arg5757, -long arg5758, -long arg5759, -long arg5760, -long arg5761, -long arg5762, -long arg5763, -long arg5764, -long arg5765, -long arg5766, -long arg5767, -long arg5768, -long arg5769, -long arg5770, -long arg5771, -long arg5772, -long arg5773, -long arg5774, -long arg5775, -long arg5776, -long arg5777, -long arg5778, -long arg5779, -long arg5780, -long arg5781, -long arg5782, -long arg5783, -long arg5784, -long arg5785, -long arg5786, -long arg5787, -long arg5788, -long arg5789, -long arg5790, -long arg5791, -long arg5792, -long arg5793, -long arg5794, -long arg5795, -long arg5796, -long arg5797, -long arg5798, -long arg5799, -long arg5800, -long arg5801, -long arg5802, -long arg5803, -long arg5804, -long arg5805, -long arg5806, -long arg5807, -long arg5808, -long arg5809, -long arg5810, -long arg5811, -long arg5812, -long arg5813, -long arg5814, -long arg5815, -long arg5816, -long arg5817, -long arg5818, -long arg5819, -long arg5820, -long arg5821, -long arg5822, -long arg5823, -long arg5824, -long arg5825, -long arg5826, -long arg5827, -long arg5828, -long arg5829, -long arg5830, -long arg5831, -long arg5832, -long arg5833, -long arg5834, -long arg5835, -long arg5836, -long arg5837, -long arg5838, -long arg5839, -long arg5840, -long arg5841, -long arg5842, -long arg5843, -long arg5844, -long arg5845, -long arg5846, -long arg5847, -long arg5848, -long arg5849, -long arg5850, -long arg5851, -long arg5852, -long arg5853, -long arg5854, -long arg5855, -long arg5856, -long arg5857, -long arg5858, -long arg5859, -long arg5860, -long arg5861, -long arg5862, -long arg5863, -long arg5864, -long arg5865, -long arg5866, -long arg5867, -long arg5868, -long arg5869, -long arg5870, -long arg5871, -long arg5872, -long arg5873, -long arg5874, -long arg5875, -long arg5876, -long arg5877, -long arg5878, -long arg5879, -long arg5880, -long arg5881, -long arg5882, -long arg5883, -long arg5884, -long arg5885, -long arg5886, -long arg5887, -long arg5888, -long arg5889, -long arg5890, -long arg5891, -long arg5892, -long arg5893, -long arg5894, -long arg5895, -long arg5896, -long arg5897, -long arg5898, -long arg5899, -long arg5900, -long arg5901, -long arg5902, -long arg5903, -long arg5904, -long arg5905, -long arg5906, -long arg5907, -long arg5908, -long arg5909, -long arg5910, -long arg5911, -long arg5912, -long arg5913, -long arg5914, -long arg5915, -long arg5916, -long arg5917, -long arg5918, -long arg5919, -long arg5920, -long arg5921, -long arg5922, -long arg5923, -long arg5924, -long arg5925, -long arg5926, -long arg5927, -long arg5928, -long arg5929, -long arg5930, -long arg5931, -long arg5932, -long arg5933, -long arg5934, -long arg5935, -long arg5936, -long arg5937, -long arg5938, -long arg5939, -long arg5940, -long arg5941, -long arg5942, -long arg5943, -long arg5944, -long arg5945, -long arg5946, -long arg5947, -long arg5948, -long arg5949, -long arg5950, -long arg5951, -long arg5952, -long arg5953, -long arg5954, -long arg5955, -long arg5956, -long arg5957, -long arg5958, -long arg5959, -long arg5960, -long arg5961, -long arg5962, -long arg5963, -long arg5964, -long arg5965, -long arg5966, -long arg5967, -long arg5968, -long arg5969, -long arg5970, -long arg5971, -long arg5972, -long arg5973, -long arg5974, -long arg5975, -long arg5976, -long arg5977, -long arg5978, -long arg5979, -long arg5980, -long arg5981, -long arg5982, -long arg5983, -long arg5984, -long arg5985, -long arg5986, -long arg5987, -long arg5988, -long arg5989, -long arg5990, -long arg5991, -long arg5992, -long arg5993, -long arg5994, -long arg5995, -long arg5996, -long arg5997, -long arg5998, -long arg5999, -long arg6000, -long arg6001, -long arg6002, -long arg6003, -long arg6004, -long arg6005, -long arg6006, -long arg6007, -long arg6008, -long arg6009, -long arg6010, -long arg6011, -long arg6012, -long arg6013, -long arg6014, -long arg6015, -long arg6016, -long arg6017, -long arg6018, -long arg6019, -long arg6020, -long arg6021, -long arg6022, -long arg6023, -long arg6024, -long arg6025, -long arg6026, -long arg6027, -long arg6028, -long arg6029, -long arg6030, -long arg6031, -long arg6032, -long arg6033, -long arg6034, -long arg6035, -long arg6036, -long arg6037, -long arg6038, -long arg6039, -long arg6040, -long arg6041, -long arg6042, -long arg6043, -long arg6044, -long arg6045, -long arg6046, -long arg6047, -long arg6048, -long arg6049, -long arg6050, -long arg6051, -long arg6052, -long arg6053, -long arg6054, -long arg6055, -long arg6056, -long arg6057, -long arg6058, -long arg6059, -long arg6060, -long arg6061, -long arg6062, -long arg6063, -long arg6064, -long arg6065, -long arg6066, -long arg6067, -long arg6068, -long arg6069, -long arg6070, -long arg6071, -long arg6072, -long arg6073, -long arg6074, -long arg6075, -long arg6076, -long arg6077, -long arg6078, -long arg6079, -long arg6080, -long arg6081, -long arg6082, -long arg6083, -long arg6084, -long arg6085, -long arg6086, -long arg6087, -long arg6088, -long arg6089, -long arg6090, -long arg6091, -long arg6092, -long arg6093, -long arg6094, -long arg6095, -long arg6096, -long arg6097, -long arg6098, -long arg6099, -long arg6100, -long arg6101, -long arg6102, -long arg6103, -long arg6104, -long arg6105, -long arg6106, -long arg6107, -long arg6108, -long arg6109, -long arg6110, -long arg6111, -long arg6112, -long arg6113, -long arg6114, -long arg6115, -long arg6116, -long arg6117, -long arg6118, -long arg6119, -long arg6120, -long arg6121, -long arg6122, -long arg6123, -long arg6124, -long arg6125, -long arg6126, -long arg6127, -long arg6128, -long arg6129, -long arg6130, -long arg6131, -long arg6132, -long arg6133, -long arg6134, -long arg6135, -long arg6136, -long arg6137, -long arg6138, -long arg6139, -long arg6140, -long arg6141, -long arg6142, -long arg6143, -long arg6144, -long arg6145, -long arg6146, -long arg6147, -long arg6148, -long arg6149, -long arg6150, -long arg6151, -long arg6152, -long arg6153, -long arg6154, -long arg6155, -long arg6156, -long arg6157, -long arg6158, -long arg6159, -long arg6160, -long arg6161, -long arg6162, -long arg6163, -long arg6164, -long arg6165, -long arg6166, -long arg6167, -long arg6168, -long arg6169, -long arg6170, -long arg6171, -long arg6172, -long arg6173, -long arg6174, -long arg6175, -long arg6176, -long arg6177, -long arg6178, -long arg6179, -long arg6180, -long arg6181, -long arg6182, -long arg6183, -long arg6184, -long arg6185, -long arg6186, -long arg6187, -long arg6188, -long arg6189, -long arg6190, -long arg6191, -long arg6192, -long arg6193, -long arg6194, -long arg6195, -long arg6196, -long arg6197, -long arg6198, -long arg6199, -long arg6200, -long arg6201, -long arg6202, -long arg6203, -long arg6204, -long arg6205, -long arg6206, -long arg6207, -long arg6208, -long arg6209, -long arg6210, -long arg6211, -long arg6212, -long arg6213, -long arg6214, -long arg6215, -long arg6216, -long arg6217, -long arg6218, -long arg6219, -long arg6220, -long arg6221, -long arg6222, -long arg6223, -long arg6224, -long arg6225, -long arg6226, -long arg6227, -long arg6228, -long arg6229, -long arg6230, -long arg6231, -long arg6232, -long arg6233, -long arg6234, -long arg6235, -long arg6236, -long arg6237, -long arg6238, -long arg6239, -long arg6240, -long arg6241, -long arg6242, -long arg6243, -long arg6244, -long arg6245, -long arg6246, -long arg6247, -long arg6248, -long arg6249, -long arg6250, -long arg6251, -long arg6252, -long arg6253, -long arg6254, -long arg6255, -long arg6256, -long arg6257, -long arg6258, -long arg6259, -long arg6260, -long arg6261, -long arg6262, -long arg6263, -long arg6264, -long arg6265, -long arg6266, -long arg6267, -long arg6268, -long arg6269, -long arg6270, -long arg6271, -long arg6272, -long arg6273, -long arg6274, -long arg6275, -long arg6276, -long arg6277, -long arg6278, -long arg6279, -long arg6280, -long arg6281, -long arg6282, -long arg6283, -long arg6284, -long arg6285, -long arg6286, -long arg6287, -long arg6288, -long arg6289, -long arg6290, -long arg6291, -long arg6292, -long arg6293, -long arg6294, -long arg6295, -long arg6296, -long arg6297, -long arg6298, -long arg6299, -long arg6300, -long arg6301, -long arg6302, -long arg6303, -long arg6304, -long arg6305, -long arg6306, -long arg6307, -long arg6308, -long arg6309, -long arg6310, -long arg6311, -long arg6312, -long arg6313, -long arg6314, -long arg6315, -long arg6316, -long arg6317, -long arg6318, -long arg6319, -long arg6320, -long arg6321, -long arg6322, -long arg6323, -long arg6324, -long arg6325, -long arg6326, -long arg6327, -long arg6328, -long arg6329, -long arg6330, -long arg6331, -long arg6332, -long arg6333, -long arg6334, -long arg6335, -long arg6336, -long arg6337, -long arg6338, -long arg6339, -long arg6340, -long arg6341, -long arg6342, -long arg6343, -long arg6344, -long arg6345, -long arg6346, -long arg6347, -long arg6348, -long arg6349, -long arg6350, -long arg6351, -long arg6352, -long arg6353, -long arg6354, -long arg6355, -long arg6356, -long arg6357, -long arg6358, -long arg6359, -long arg6360, -long arg6361, -long arg6362, -long arg6363, -long arg6364, -long arg6365, -long arg6366, -long arg6367, -long arg6368, -long arg6369, -long arg6370, -long arg6371, -long arg6372, -long arg6373, -long arg6374, -long arg6375, -long arg6376, -long arg6377, -long arg6378, -long arg6379, -long arg6380, -long arg6381, -long arg6382, -long arg6383, -long arg6384, -long arg6385, -long arg6386, -long arg6387, -long arg6388, -long arg6389, -long arg6390, -long arg6391, -long arg6392, -long arg6393, -long arg6394, -long arg6395, -long arg6396, -long arg6397, -long arg6398, -long arg6399, -long arg6400, -long arg6401, -long arg6402, -long arg6403, -long arg6404, -long arg6405, -long arg6406, -long arg6407, -long arg6408, -long arg6409, -long arg6410, -long arg6411, -long arg6412, -long arg6413, -long arg6414, -long arg6415, -long arg6416, -long arg6417, -long arg6418, -long arg6419, -long arg6420, -long arg6421, -long arg6422, -long arg6423, -long arg6424, -long arg6425, -long arg6426, -long arg6427, -long arg6428, -long arg6429, -long arg6430, -long arg6431, -long arg6432, -long arg6433, -long arg6434, -long arg6435, -long arg6436, -long arg6437, -long arg6438, -long arg6439, -long arg6440, -long arg6441, -long arg6442, -long arg6443, -long arg6444, -long arg6445, -long arg6446, -long arg6447, -long arg6448, -long arg6449, -long arg6450, -long arg6451, -long arg6452, -long arg6453, -long arg6454, -long arg6455, -long arg6456, -long arg6457, -long arg6458, -long arg6459, -long arg6460, -long arg6461, -long arg6462, -long arg6463, -long arg6464, -long arg6465, -long arg6466, -long arg6467, -long arg6468, -long arg6469, -long arg6470, -long arg6471, -long arg6472, -long arg6473, -long arg6474, -long arg6475, -long arg6476, -long arg6477, -long arg6478, -long arg6479, -long arg6480, -long arg6481, -long arg6482, -long arg6483, -long arg6484, -long arg6485, -long arg6486, -long arg6487, -long arg6488, -long arg6489, -long arg6490, -long arg6491, -long arg6492, -long arg6493, -long arg6494, -long arg6495, -long arg6496, -long arg6497, -long arg6498, -long arg6499, -long arg6500, -long arg6501, -long arg6502, -long arg6503, -long arg6504, -long arg6505, -long arg6506, -long arg6507, -long arg6508, -long arg6509, -long arg6510, -long arg6511, -long arg6512, -long arg6513, -long arg6514, -long arg6515, -long arg6516, -long arg6517, -long arg6518, -long arg6519, -long arg6520, -long arg6521, -long arg6522, -long arg6523, -long arg6524, -long arg6525, -long arg6526, -long arg6527, -long arg6528, -long arg6529, -long arg6530, -long arg6531, -long arg6532, -long arg6533, -long arg6534, -long arg6535, -long arg6536, -long arg6537, -long arg6538, -long arg6539, -long arg6540, -long arg6541, -long arg6542, -long arg6543, -long arg6544, -long arg6545, -long arg6546, -long arg6547, -long arg6548, -long arg6549, -long arg6550, -long arg6551, -long arg6552, -long arg6553, -long arg6554, -long arg6555, -long arg6556, -long arg6557, -long arg6558, -long arg6559, -long arg6560, -long arg6561, -long arg6562, -long arg6563, -long arg6564, -long arg6565, -long arg6566, -long arg6567, -long arg6568, -long arg6569, -long arg6570, -long arg6571, -long arg6572, -long arg6573, -long arg6574, -long arg6575, -long arg6576, -long arg6577, -long arg6578, -long arg6579, -long arg6580, -long arg6581, -long arg6582, -long arg6583, -long arg6584, -long arg6585, -long arg6586, -long arg6587, -long arg6588, -long arg6589, -long arg6590, -long arg6591, -long arg6592, -long arg6593, -long arg6594, -long arg6595, -long arg6596, -long arg6597, -long arg6598, -long arg6599, -long arg6600, -long arg6601, -long arg6602, -long arg6603, -long arg6604, -long arg6605, -long arg6606, -long arg6607, -long arg6608, -long arg6609, -long arg6610, -long arg6611, -long arg6612, -long arg6613, -long arg6614, -long arg6615, -long arg6616, -long arg6617, -long arg6618, -long arg6619, -long arg6620, -long arg6621, -long arg6622, -long arg6623, -long arg6624, -long arg6625, -long arg6626, -long arg6627, -long arg6628, -long arg6629, -long arg6630, -long arg6631, -long arg6632, -long arg6633, -long arg6634, -long arg6635, -long arg6636, -long arg6637, -long arg6638, -long arg6639, -long arg6640, -long arg6641, -long arg6642, -long arg6643, -long arg6644, -long arg6645, -long arg6646, -long arg6647, -long arg6648, -long arg6649, -long arg6650, -long arg6651, -long arg6652, -long arg6653, -long arg6654, -long arg6655, -long arg6656, -long arg6657, -long arg6658, -long arg6659, -long arg6660, -long arg6661, -long arg6662, -long arg6663, -long arg6664, -long arg6665, -long arg6666, -long arg6667, -long arg6668, -long arg6669, -long arg6670, -long arg6671, -long arg6672, -long arg6673, -long arg6674, -long arg6675, -long arg6676, -long arg6677, -long arg6678, -long arg6679, -long arg6680, -long arg6681, -long arg6682, -long arg6683, -long arg6684, -long arg6685, -long arg6686, -long arg6687, -long arg6688, -long arg6689, -long arg6690, -long arg6691, -long arg6692, -long arg6693, -long arg6694, -long arg6695, -long arg6696, -long arg6697, -long arg6698, -long arg6699, -long arg6700, -long arg6701, -long arg6702, -long arg6703, -long arg6704, -long arg6705, -long arg6706, -long arg6707, -long arg6708, -long arg6709, -long arg6710, -long arg6711, -long arg6712, -long arg6713, -long arg6714, -long arg6715, -long arg6716, -long arg6717, -long arg6718, -long arg6719, -long arg6720, -long arg6721, -long arg6722, -long arg6723, -long arg6724, -long arg6725, -long arg6726, -long arg6727, -long arg6728, -long arg6729, -long arg6730, -long arg6731, -long arg6732, -long arg6733, -long arg6734, -long arg6735, -long arg6736, -long arg6737, -long arg6738, -long arg6739, -long arg6740, -long arg6741, -long arg6742, -long arg6743, -long arg6744, -long arg6745, -long arg6746, -long arg6747, -long arg6748, -long arg6749, -long arg6750, -long arg6751, -long arg6752, -long arg6753, -long arg6754, -long arg6755, -long arg6756, -long arg6757, -long arg6758, -long arg6759, -long arg6760, -long arg6761, -long arg6762, -long arg6763, -long arg6764, -long arg6765, -long arg6766, -long arg6767, -long arg6768, -long arg6769, -long arg6770, -long arg6771, -long arg6772, -long arg6773, -long arg6774, -long arg6775, -long arg6776, -long arg6777, -long arg6778, -long arg6779, -long arg6780, -long arg6781, -long arg6782, -long arg6783, -long arg6784, -long arg6785, -long arg6786, -long arg6787, -long arg6788, -long arg6789, -long arg6790, -long arg6791, -long arg6792, -long arg6793, -long arg6794, -long arg6795, -long arg6796, -long arg6797, -long arg6798, -long arg6799, -long arg6800, -long arg6801, -long arg6802, -long arg6803, -long arg6804, -long arg6805, -long arg6806, -long arg6807, -long arg6808, -long arg6809, -long arg6810, -long arg6811, -long arg6812, -long arg6813, -long arg6814, -long arg6815, -long arg6816, -long arg6817, -long arg6818, -long arg6819, -long arg6820, -long arg6821, -long arg6822, -long arg6823, -long arg6824, -long arg6825, -long arg6826, -long arg6827, -long arg6828, -long arg6829, -long arg6830, -long arg6831, -long arg6832, -long arg6833, -long arg6834, -long arg6835, -long arg6836, -long arg6837, -long arg6838, -long arg6839, -long arg6840, -long arg6841, -long arg6842, -long arg6843, -long arg6844, -long arg6845, -long arg6846, -long arg6847, -long arg6848, -long arg6849, -long arg6850, -long arg6851, -long arg6852, -long arg6853, -long arg6854, -long arg6855, -long arg6856, -long arg6857, -long arg6858, -long arg6859, -long arg6860, -long arg6861, -long arg6862, -long arg6863, -long arg6864, -long arg6865, -long arg6866, -long arg6867, -long arg6868, -long arg6869, -long arg6870, -long arg6871, -long arg6872, -long arg6873, -long arg6874, -long arg6875, -long arg6876, -long arg6877, -long arg6878, -long arg6879, -long arg6880, -long arg6881, -long arg6882, -long arg6883, -long arg6884, -long arg6885, -long arg6886, -long arg6887, -long arg6888, -long arg6889, -long arg6890, -long arg6891, -long arg6892, -long arg6893, -long arg6894, -long arg6895, -long arg6896, -long arg6897, -long arg6898, -long arg6899, -long arg6900, -long arg6901, -long arg6902, -long arg6903, -long arg6904, -long arg6905, -long arg6906, -long arg6907, -long arg6908, -long arg6909, -long arg6910, -long arg6911, -long arg6912, -long arg6913, -long arg6914, -long arg6915, -long arg6916, -long arg6917, -long arg6918, -long arg6919, -long arg6920, -long arg6921, -long arg6922, -long arg6923, -long arg6924, -long arg6925, -long arg6926, -long arg6927, -long arg6928, -long arg6929, -long arg6930, -long arg6931, -long arg6932, -long arg6933, -long arg6934, -long arg6935, -long arg6936, -long arg6937, -long arg6938, -long arg6939, -long arg6940, -long arg6941, -long arg6942, -long arg6943, -long arg6944, -long arg6945, -long arg6946, -long arg6947, -long arg6948, -long arg6949, -long arg6950, -long arg6951, -long arg6952, -long arg6953, -long arg6954, -long arg6955, -long arg6956, -long arg6957, -long arg6958, -long arg6959, -long arg6960, -long arg6961, -long arg6962, -long arg6963, -long arg6964, -long arg6965, -long arg6966, -long arg6967, -long arg6968, -long arg6969, -long arg6970, -long arg6971, -long arg6972, -long arg6973, -long arg6974, -long arg6975, -long arg6976, -long arg6977, -long arg6978, -long arg6979, -long arg6980, -long arg6981, -long arg6982, -long arg6983, -long arg6984, -long arg6985, -long arg6986, -long arg6987, -long arg6988, -long arg6989, -long arg6990, -long arg6991, -long arg6992, -long arg6993, -long arg6994, -long arg6995, -long arg6996, -long arg6997, -long arg6998, -long arg6999, -long arg7000, -long arg7001, -long arg7002, -long arg7003, -long arg7004, -long arg7005, -long arg7006, -long arg7007, -long arg7008, -long arg7009, -long arg7010, -long arg7011, -long arg7012, -long arg7013, -long arg7014, -long arg7015, -long arg7016, -long arg7017, -long arg7018, -long arg7019, -long arg7020, -long arg7021, -long arg7022, -long arg7023, -long arg7024, -long arg7025, -long arg7026, -long arg7027, -long arg7028, -long arg7029, -long arg7030, -long arg7031, -long arg7032, -long arg7033, -long arg7034, -long arg7035, -long arg7036, -long arg7037, -long arg7038, -long arg7039, -long arg7040, -long arg7041, -long arg7042, -long arg7043, -long arg7044, -long arg7045, -long arg7046, -long arg7047, -long arg7048, -long arg7049, -long arg7050, -long arg7051, -long arg7052, -long arg7053, -long arg7054, -long arg7055, -long arg7056, -long arg7057, -long arg7058, -long arg7059, -long arg7060, -long arg7061, -long arg7062, -long arg7063, -long arg7064, -long arg7065, -long arg7066, -long arg7067, -long arg7068, -long arg7069, -long arg7070, -long arg7071, -long arg7072, -long arg7073, -long arg7074, -long arg7075, -long arg7076, -long arg7077, -long arg7078, -long arg7079, -long arg7080, -long arg7081, -long arg7082, -long arg7083, -long arg7084, -long arg7085, -long arg7086, -long arg7087, -long arg7088, -long arg7089, -long arg7090, -long arg7091, -long arg7092, -long arg7093, -long arg7094, -long arg7095, -long arg7096, -long arg7097, -long arg7098, -long arg7099, -long arg7100, -long arg7101, -long arg7102, -long arg7103, -long arg7104, -long arg7105, -long arg7106, -long arg7107, -long arg7108, -long arg7109, -long arg7110, -long arg7111, -long arg7112, -long arg7113, -long arg7114, -long arg7115, -long arg7116, -long arg7117, -long arg7118, -long arg7119, -long arg7120, -long arg7121, -long arg7122, -long arg7123, -long arg7124, -long arg7125, -long arg7126, -long arg7127, -long arg7128, -long arg7129, -long arg7130, -long arg7131, -long arg7132, -long arg7133, -long arg7134, -long arg7135, -long arg7136, -long arg7137, -long arg7138, -long arg7139, -long arg7140, -long arg7141, -long arg7142, -long arg7143, -long arg7144, -long arg7145, -long arg7146, -long arg7147, -long arg7148, -long arg7149, -long arg7150, -long arg7151, -long arg7152, -long arg7153, -long arg7154, -long arg7155, -long arg7156, -long arg7157, -long arg7158, -long arg7159, -long arg7160, -long arg7161, -long arg7162, -long arg7163, -long arg7164, -long arg7165, -long arg7166, -long arg7167, -long arg7168, -long arg7169, -long arg7170, -long arg7171, -long arg7172, -long arg7173, -long arg7174, -long arg7175, -long arg7176, -long arg7177, -long arg7178, -long arg7179, -long arg7180, -long arg7181, -long arg7182, -long arg7183, -long arg7184, -long arg7185, -long arg7186, -long arg7187, -long arg7188, -long arg7189, -long arg7190, -long arg7191, -long arg7192, -long arg7193, -long arg7194, -long arg7195, -long arg7196, -long arg7197, -long arg7198, -long arg7199, -long arg7200, -long arg7201, -long arg7202, -long arg7203, -long arg7204, -long arg7205, -long arg7206, -long arg7207, -long arg7208, -long arg7209, -long arg7210, -long arg7211, -long arg7212, -long arg7213, -long arg7214, -long arg7215, -long arg7216, -long arg7217, -long arg7218, -long arg7219, -long arg7220, -long arg7221, -long arg7222, -long arg7223, -long arg7224, -long arg7225, -long arg7226, -long arg7227, -long arg7228, -long arg7229, -long arg7230, -long arg7231, -long arg7232, -long arg7233, -long arg7234, -long arg7235, -long arg7236, -long arg7237, -long arg7238, -long arg7239, -long arg7240, -long arg7241, -long arg7242, -long arg7243, -long arg7244, -long arg7245, -long arg7246, -long arg7247, -long arg7248, -long arg7249, -long arg7250, -long arg7251, -long arg7252, -long arg7253, -long arg7254, -long arg7255, -long arg7256, -long arg7257, -long arg7258, -long arg7259, -long arg7260, -long arg7261, -long arg7262, -long arg7263, -long arg7264, -long arg7265, -long arg7266, -long arg7267, -long arg7268, -long arg7269, -long arg7270, -long arg7271, -long arg7272, -long arg7273, -long arg7274, -long arg7275, -long arg7276, -long arg7277, -long arg7278, -long arg7279, -long arg7280, -long arg7281, -long arg7282, -long arg7283, -long arg7284, -long arg7285, -long arg7286, -long arg7287, -long arg7288, -long arg7289, -long arg7290, -long arg7291, -long arg7292, -long arg7293, -long arg7294, -long arg7295, -long arg7296, -long arg7297, -long arg7298, -long arg7299, -long arg7300, -long arg7301, -long arg7302, -long arg7303, -long arg7304, -long arg7305, -long arg7306, -long arg7307, -long arg7308, -long arg7309, -long arg7310, -long arg7311, -long arg7312, -long arg7313, -long arg7314, -long arg7315, -long arg7316, -long arg7317, -long arg7318, -long arg7319, -long arg7320, -long arg7321, -long arg7322, -long arg7323, -long arg7324, -long arg7325, -long arg7326, -long arg7327, -long arg7328, -long arg7329, -long arg7330, -long arg7331, -long arg7332, -long arg7333, -long arg7334, -long arg7335, -long arg7336, -long arg7337, -long arg7338, -long arg7339, -long arg7340, -long arg7341, -long arg7342, -long arg7343, -long arg7344, -long arg7345, -long arg7346, -long arg7347, -long arg7348, -long arg7349, -long arg7350, -long arg7351, -long arg7352, -long arg7353, -long arg7354, -long arg7355, -long arg7356, -long arg7357, -long arg7358, -long arg7359, -long arg7360, -long arg7361, -long arg7362, -long arg7363, -long arg7364, -long arg7365, -long arg7366, -long arg7367, -long arg7368, -long arg7369, -long arg7370, -long arg7371, -long arg7372, -long arg7373, -long arg7374, -long arg7375, -long arg7376, -long arg7377, -long arg7378, -long arg7379, -long arg7380, -long arg7381, -long arg7382, -long arg7383, -long arg7384, -long arg7385, -long arg7386, -long arg7387, -long arg7388, -long arg7389, -long arg7390, -long arg7391, -long arg7392, -long arg7393, -long arg7394, -long arg7395, -long arg7396, -long arg7397, -long arg7398, -long arg7399, -long arg7400, -long arg7401, -long arg7402, -long arg7403, -long arg7404, -long arg7405, -long arg7406, -long arg7407, -long arg7408, -long arg7409, -long arg7410, -long arg7411, -long arg7412, -long arg7413, -long arg7414, -long arg7415, -long arg7416, -long arg7417, -long arg7418, -long arg7419, -long arg7420, -long arg7421, -long arg7422, -long arg7423, -long arg7424, -long arg7425, -long arg7426, -long arg7427, -long arg7428, -long arg7429, -long arg7430, -long arg7431, -long arg7432, -long arg7433, -long arg7434, -long arg7435, -long arg7436, -long arg7437, -long arg7438, -long arg7439, -long arg7440, -long arg7441, -long arg7442, -long arg7443, -long arg7444, -long arg7445, -long arg7446, -long arg7447, -long arg7448, -long arg7449, -long arg7450, -long arg7451, -long arg7452, -long arg7453, -long arg7454, -long arg7455, -long arg7456, -long arg7457, -long arg7458, -long arg7459, -long arg7460, -long arg7461, -long arg7462, -long arg7463, -long arg7464, -long arg7465, -long arg7466, -long arg7467, -long arg7468, -long arg7469, -long arg7470, -long arg7471, -long arg7472, -long arg7473, -long arg7474, -long arg7475, -long arg7476, -long arg7477, -long arg7478, -long arg7479, -long arg7480, -long arg7481, -long arg7482, -long arg7483, -long arg7484, -long arg7485, -long arg7486, -long arg7487, -long arg7488, -long arg7489, -long arg7490, -long arg7491, -long arg7492, -long arg7493, -long arg7494, -long arg7495, -long arg7496, -long arg7497, -long arg7498, -long arg7499, -long arg7500, -long arg7501, -long arg7502, -long arg7503, -long arg7504, -long arg7505, -long arg7506, -long arg7507, -long arg7508, -long arg7509, -long arg7510, -long arg7511, -long arg7512, -long arg7513, -long arg7514, -long arg7515, -long arg7516, -long arg7517, -long arg7518, -long arg7519, -long arg7520, -long arg7521, -long arg7522, -long arg7523, -long arg7524, -long arg7525, -long arg7526, -long arg7527, -long arg7528, -long arg7529, -long arg7530, -long arg7531, -long arg7532, -long arg7533, -long arg7534, -long arg7535, -long arg7536, -long arg7537, -long arg7538, -long arg7539, -long arg7540, -long arg7541, -long arg7542, -long arg7543, -long arg7544, -long arg7545, -long arg7546, -long arg7547, -long arg7548, -long arg7549, -long arg7550, -long arg7551, -long arg7552, -long arg7553, -long arg7554, -long arg7555, -long arg7556, -long arg7557, -long arg7558, -long arg7559, -long arg7560, -long arg7561, -long arg7562, -long arg7563, -long arg7564, -long arg7565, -long arg7566, -long arg7567, -long arg7568, -long arg7569, -long arg7570, -long arg7571, -long arg7572, -long arg7573, -long arg7574, -long arg7575, -long arg7576, -long arg7577, -long arg7578, -long arg7579, -long arg7580, -long arg7581, -long arg7582, -long arg7583, -long arg7584, -long arg7585, -long arg7586, -long arg7587, -long arg7588, -long arg7589, -long arg7590, -long arg7591, -long arg7592, -long arg7593, -long arg7594, -long arg7595, -long arg7596, -long arg7597, -long arg7598, -long arg7599, -long arg7600, -long arg7601, -long arg7602, -long arg7603, -long arg7604, -long arg7605, -long arg7606, -long arg7607, -long arg7608, -long arg7609, -long arg7610, -long arg7611, -long arg7612, -long arg7613, -long arg7614, -long arg7615, -long arg7616, -long arg7617, -long arg7618, -long arg7619, -long arg7620, -long arg7621, -long arg7622, -long arg7623, -long arg7624, -long arg7625, -long arg7626, -long arg7627, -long arg7628, -long arg7629, -long arg7630, -long arg7631, -long arg7632, -long arg7633, -long arg7634, -long arg7635, -long arg7636, -long arg7637, -long arg7638, -long arg7639, -long arg7640, -long arg7641, -long arg7642, -long arg7643, -long arg7644, -long arg7645, -long arg7646, -long arg7647, -long arg7648, -long arg7649, -long arg7650, -long arg7651, -long arg7652, -long arg7653, -long arg7654, -long arg7655, -long arg7656, -long arg7657, -long arg7658, -long arg7659, -long arg7660, -long arg7661, -long arg7662, -long arg7663, -long arg7664, -long arg7665, -long arg7666, -long arg7667, -long arg7668, -long arg7669, -long arg7670, -long arg7671, -long arg7672, -long arg7673, -long arg7674, -long arg7675, -long arg7676, -long arg7677, -long arg7678, -long arg7679, -long arg7680, -long arg7681, -long arg7682, -long arg7683, -long arg7684, -long arg7685, -long arg7686, -long arg7687, -long arg7688, -long arg7689, -long arg7690, -long arg7691, -long arg7692, -long arg7693, -long arg7694, -long arg7695, -long arg7696, -long arg7697, -long arg7698, -long arg7699, -long arg7700, -long arg7701, -long arg7702, -long arg7703, -long arg7704, -long arg7705, -long arg7706, -long arg7707, -long arg7708, -long arg7709, -long arg7710, -long arg7711, -long arg7712, -long arg7713, -long arg7714, -long arg7715, -long arg7716, -long arg7717, -long arg7718, -long arg7719, -long arg7720, -long arg7721, -long arg7722, -long arg7723, -long arg7724, -long arg7725, -long arg7726, -long arg7727, -long arg7728, -long arg7729, -long arg7730, -long arg7731, -long arg7732, -long arg7733, -long arg7734, -long arg7735, -long arg7736, -long arg7737, -long arg7738, -long arg7739, -long arg7740, -long arg7741, -long arg7742, -long arg7743, -long arg7744, -long arg7745, -long arg7746, -long arg7747, -long arg7748, -long arg7749, -long arg7750, -long arg7751, -long arg7752, -long arg7753, -long arg7754, -long arg7755, -long arg7756, -long arg7757, -long arg7758, -long arg7759, -long arg7760, -long arg7761, -long arg7762, -long arg7763, -long arg7764, -long arg7765, -long arg7766, -long arg7767, -long arg7768, -long arg7769, -long arg7770, -long arg7771, -long arg7772, -long arg7773, -long arg7774, -long arg7775, -long arg7776, -long arg7777, -long arg7778, -long arg7779, -long arg7780, -long arg7781, -long arg7782, -long arg7783, -long arg7784, -long arg7785, -long arg7786, -long arg7787, -long arg7788, -long arg7789, -long arg7790, -long arg7791, -long arg7792, -long arg7793, -long arg7794, -long arg7795, -long arg7796, -long arg7797, -long arg7798, -long arg7799, -long arg7800, -long arg7801, -long arg7802, -long arg7803, -long arg7804, -long arg7805, -long arg7806, -long arg7807, -long arg7808, -long arg7809, -long arg7810, -long arg7811, -long arg7812, -long arg7813, -long arg7814, -long arg7815, -long arg7816, -long arg7817, -long arg7818, -long arg7819, -long arg7820, -long arg7821, -long arg7822, -long arg7823, -long arg7824, -long arg7825, -long arg7826, -long arg7827, -long arg7828, -long arg7829, -long arg7830, -long arg7831, -long arg7832, -long arg7833, -long arg7834, -long arg7835, -long arg7836, -long arg7837, -long arg7838, -long arg7839, -long arg7840, -long arg7841, -long arg7842, -long arg7843, -long arg7844, -long arg7845, -long arg7846, -long arg7847, -long arg7848, -long arg7849, -long arg7850, -long arg7851, -long arg7852, -long arg7853, -long arg7854, -long arg7855, -long arg7856, -long arg7857, -long arg7858, -long arg7859, -long arg7860, -long arg7861, -long arg7862, -long arg7863, -long arg7864, -long arg7865, -long arg7866, -long arg7867, -long arg7868, -long arg7869, -long arg7870, -long arg7871, -long arg7872, -long arg7873, -long arg7874, -long arg7875, -long arg7876, -long arg7877, -long arg7878, -long arg7879, -long arg7880, -long arg7881, -long arg7882, -long arg7883, -long arg7884, -long arg7885, -long arg7886, -long arg7887, -long arg7888, -long arg7889, -long arg7890, -long arg7891, -long arg7892, -long arg7893, -long arg7894, -long arg7895, -long arg7896, -long arg7897, -long arg7898, -long arg7899, -long arg7900, -long arg7901, -long arg7902, -long arg7903, -long arg7904, -long arg7905, -long arg7906, -long arg7907, -long arg7908, -long arg7909, -long arg7910, -long arg7911, -long arg7912, -long arg7913, -long arg7914, -long arg7915, -long arg7916, -long arg7917, -long arg7918, -long arg7919, -long arg7920, -long arg7921, -long arg7922, -long arg7923, -long arg7924, -long arg7925, -long arg7926, -long arg7927, -long arg7928, -long arg7929, -long arg7930, -long arg7931, -long arg7932, -long arg7933, -long arg7934, -long arg7935, -long arg7936, -long arg7937, -long arg7938, -long arg7939, -long arg7940, -long arg7941, -long arg7942, -long arg7943, -long arg7944, -long arg7945, -long arg7946, -long arg7947, -long arg7948, -long arg7949, -long arg7950, -long arg7951, -long arg7952, -long arg7953, -long arg7954, -long arg7955, -long arg7956, -long arg7957, -long arg7958, -long arg7959, -long arg7960, -long arg7961, -long arg7962, -long arg7963, -long arg7964, -long arg7965, -long arg7966, -long arg7967, -long arg7968, -long arg7969, -long arg7970, -long arg7971, -long arg7972, -long arg7973, -long arg7974, -long arg7975, -long arg7976, -long arg7977, -long arg7978, -long arg7979, -long arg7980, -long arg7981, -long arg7982, -long arg7983, -long arg7984, -long arg7985, -long arg7986, -long arg7987, -long arg7988, -long arg7989, -long arg7990, -long arg7991, -long arg7992, -long arg7993, -long arg7994, -long arg7995, -long arg7996, -long arg7997, -long arg7998, -long arg7999, -long arg8000, -long arg8001, -long arg8002, -long arg8003, -long arg8004, -long arg8005, -long arg8006, -long arg8007, -long arg8008, -long arg8009, -long arg8010, -long arg8011, -long arg8012, -long arg8013, -long arg8014, -long arg8015, -long arg8016, -long arg8017, -long arg8018, -long arg8019, -long arg8020, -long arg8021, -long arg8022, -long arg8023, -long arg8024, -long arg8025, -long arg8026, -long arg8027, -long arg8028, -long arg8029, -long arg8030, -long arg8031, -long arg8032, -long arg8033, -long arg8034, -long arg8035, -long arg8036, -long arg8037, -long arg8038, -long arg8039, -long arg8040, -long arg8041, -long arg8042, -long arg8043, -long arg8044, -long arg8045, -long arg8046, -long arg8047, -long arg8048, -long arg8049, -long arg8050, -long arg8051, -long arg8052, -long arg8053, -long arg8054, -long arg8055, -long arg8056, -long arg8057, -long arg8058, -long arg8059, -long arg8060, -long arg8061, -long arg8062, -long arg8063, -long arg8064, -long arg8065, -long arg8066, -long arg8067, -long arg8068, -long arg8069, -long arg8070, -long arg8071, -long arg8072, -long arg8073, -long arg8074, -long arg8075, -long arg8076, -long arg8077, -long arg8078, -long arg8079, -long arg8080, -long arg8081, -long arg8082, -long arg8083, -long arg8084, -long arg8085, -long arg8086, -long arg8087, -long arg8088, -long arg8089, -long arg8090, -long arg8091, -long arg8092, -long arg8093, -long arg8094, -long arg8095, -long arg8096, -long arg8097, -long arg8098){ - return 100; - } - -} diff --git a/src/coreclr/tests/src/Regressions/common/AboveStackLimit.csproj b/src/coreclr/tests/src/Regressions/common/AboveStackLimit.csproj deleted file mode 100644 index 618327b7c64ea3..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/AboveStackLimit.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - Exe - BuildAndRun - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/common/ArrayCopy.cs b/src/coreclr/tests/src/Regressions/common/ArrayCopy.cs deleted file mode 100644 index f14c9c5a8ba35a..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/ArrayCopy.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; - -public class Repro -{ - public static Boolean ubyte_short() - { - const int size = 50; - short[] shortArray = new short[size]; - byte[] ubyteArray = new byte[size]; - for(int i=0; i - - Exe - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/common/CompEx.cs b/src/coreclr/tests/src/Regressions/common/CompEx.cs deleted file mode 100644 index c2ea194200db79..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/CompEx.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; -using System.Threading; - -public class CompEx -{ - public static int Main() - { - Int64 total, initial, newValue; - Int64 newInitial; - - TestLibrary.TestFramework.BeginTestCase("CompareExchange(Int64&,Int64,Int64)"); - - TestLibrary.TestFramework.BeginScenario("CompareExchange(0,1,0)"); - - total = 0L; - newInitial = 0L; - for(int i=0; i<2; i++) - { - initial = total; - newValue = initial + 1L; - TestLibrary.TestFramework.LogInformation("BEFORE: T("+total+") NI("+newInitial+") NV("+newValue+") I("+initial+")"); - newInitial = Interlocked.CompareExchange( ref total, newValue, initial); - TestLibrary.TestFramework.LogInformation("AFTER: T("+total+") NI("+newInitial+") NV("+newValue+") I("+initial+")"); - TestLibrary.TestFramework.LogInformation(""); - } - - TestLibrary.TestFramework.EndTestCase(); - - if (2d == total) - { - TestLibrary.TestFramework.LogInformation("PASS"); - return 100; - } - else - { - TestLibrary.TestFramework.LogInformation("FAIL"); - return 0; - } - } - -} - diff --git a/src/coreclr/tests/src/Regressions/common/CompEx.csproj b/src/coreclr/tests/src/Regressions/common/CompEx.csproj deleted file mode 100644 index 2f8050b634f5da..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/CompEx.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - Exe - BuildAndRun - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/common/DisableTransparencyEnforcement.cs b/src/coreclr/tests/src/Regressions/common/DisableTransparencyEnforcement.cs deleted file mode 100644 index c437ee9b930f43..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/DisableTransparencyEnforcement.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -// This test is verifying that security transparency violations are ignored in CoreCLR - -using System; -using System.Security; - -[assembly:AllowPartiallyTrustedCallers] - -[SecurityCritical] -class CriticalType -{ - [SecurityCritical] - public CriticalType() - { - } -} - -class My { - static int Main() { - - new CriticalType().ToString(); - - // GC.Collect(int) is marked as security critical in CoreCLR for historic reasons. - // Verify that the transparency violations are ignored by calling it from here. - GC.Collect(1); - - TestLibrary.TestFramework.LogInformation("PASS"); - - return 100; - } -} diff --git a/src/coreclr/tests/src/Regressions/common/DisableTransparencyEnforcement.csproj b/src/coreclr/tests/src/Regressions/common/DisableTransparencyEnforcement.csproj deleted file mode 100644 index 6e01cd73d2a7a4..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/DisableTransparencyEnforcement.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - Exe - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/common/Marshal.cs b/src/coreclr/tests/src/Regressions/common/Marshal.cs deleted file mode 100644 index bff2d917ab018c..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/Marshal.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; -using System.Runtime.InteropServices; -using System.Security; - -public class MarshalTest -{ - [SecuritySafeCritical] - public unsafe static int Main() - { - int[] i = new int[2] {100, 99}; - int j = 0; - - TestLibrary.TestFramework.BeginTestCase("Marshal.ReadInt32()"); - - TestLibrary.TestFramework.BeginScenario("Marshal.ReadInt32(int[]&)"); - fixed (int* ip = &i[0]) - { - j = Marshal.ReadInt32( new IntPtr(ip) ); - - Console.WriteLine("j = {0} i = {1}", j, i[0]); - } - - TestLibrary.TestFramework.EndTestCase(); - - if (j == i[0]) - { - TestLibrary.TestFramework.LogInformation("PASS"); - return 100; - } - else - { - TestLibrary.TestFramework.LogInformation("FAIL"); - return 0; - } - } -} diff --git a/src/coreclr/tests/src/Regressions/common/Marshal.csproj b/src/coreclr/tests/src/Regressions/common/Marshal.csproj deleted file mode 100644 index f6049f49fe345e..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/Marshal.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - Exe - BuildAndRun - true - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/common/ThreadCulture.cs b/src/coreclr/tests/src/Regressions/common/ThreadCulture.cs deleted file mode 100644 index b7b012df3f9648..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/ThreadCulture.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; -using System.Globalization; -using System.Threading; - -public class ThreadCultureRegression -{ - public static int Main() - { - // On Mac setting the current thread culture to german - // resulted in an error. - - CultureInfo german = new CultureInfo("de-DE"); - - TestLibrary.Utilities.CurrentCulture = german; - - // verify that it was changed - if (TestLibrary.Utilities.CurrentCulture.Name == "de-DE") - { - Console.WriteLine("PASS"); - return 100; - } - else - { - Console.WriteLine("FAIL"); - return 0; - } - - } -} diff --git a/src/coreclr/tests/src/Regressions/common/ThreadCulture.csproj b/src/coreclr/tests/src/Regressions/common/ThreadCulture.csproj deleted file mode 100644 index 19412976f3f90b..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/ThreadCulture.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - Exe - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/common/ToLower.cs b/src/coreclr/tests/src/Regressions/common/ToLower.cs deleted file mode 100644 index e9672c80ac50f1..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/ToLower.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; - -public class ToLowerRepro -{ - private const string c_UPPERCASE = "TELESTO TEST TEaM"; - private const string c_LOWERCASE = "telesto test team"; - - public static int Main(string[] args) - { - string lowerCase; - - TestLibrary.TestFramework.BeginTestCase("ToLower stack overflow test"); - - TestLibrary.TestFramework.BeginScenario("ToLower(\""+ c_UPPERCASE +"\")"); - - lowerCase = c_UPPERCASE.ToLower(); - - if (lowerCase.Equals(c_LOWERCASE)) - { - TestLibrary.TestFramework.EndTestCase(); - TestLibrary.TestFramework.LogInformation("PASS"); - return 100; - } - else - { - TestLibrary.TestFramework.EndTestCase(); - TestLibrary.TestFramework.LogError("001", "String was not converted to lower case: Expected("+c_LOWERCASE+") Actual("+lowerCase+")"); - TestLibrary.TestFramework.LogInformation("FAIL"); - return 0; - } - } - -} diff --git a/src/coreclr/tests/src/Regressions/common/ToLower.csproj b/src/coreclr/tests/src/Regressions/common/ToLower.csproj deleted file mode 100644 index bf7fc939e06a3a..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/ToLower.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - Exe - BuildAndRun - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/common/Unsafe.csproj b/src/coreclr/tests/src/Regressions/common/Unsafe.csproj deleted file mode 100644 index 8b71348655766b..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/Unsafe.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - Exe - BuildAndRun - true - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/common/avtest.cs b/src/coreclr/tests/src/Regressions/common/avtest.cs deleted file mode 100644 index 0d8e98eeab9921..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/avtest.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; - -class ReflectObj -{ - public static int Main( String [] str ) - { - Random rand = null; - try - { - rand.Next(); - } - catch (NullReferenceException) - { - Console.WriteLine("Got expected NullReferenceException"); - Console.WriteLine("PASS"); - return 100; - } - catch (Exception e) - { - Console.WriteLine("Got unexpected exception: {0}", e); - } - - Console.WriteLine("FAIL"); - return 0; - } -} - diff --git a/src/coreclr/tests/src/Regressions/common/avtest.csproj b/src/coreclr/tests/src/Regressions/common/avtest.csproj deleted file mode 100644 index e5819f16c8b2b9..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/avtest.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - Exe - BuildAndRun - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/common/interlock.cs b/src/coreclr/tests/src/Regressions/common/interlock.cs deleted file mode 100644 index 3bd2f09d0a2c90..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/interlock.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; - -public class A -{ - public static int Main() - { - - long iNew; - long iTotal; - - iTotal = 0; - - iNew = System.Threading.Interlocked.Add( ref iTotal, 2); - - Console.WriteLine("iNew = {0} iTotal = {1}", iNew, iTotal); - - if (iNew == iTotal) - { - Console.WriteLine("PASS"); - return 100; - } - else - { - Console.WriteLine("FAIL (iNew and iTotal should be equal)"); - return 0; - } - } -} diff --git a/src/coreclr/tests/src/Regressions/common/interlock.csproj b/src/coreclr/tests/src/Regressions/common/interlock.csproj deleted file mode 100644 index fcd2f15d436ca2..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/interlock.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - Exe - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/common/pow3.cs b/src/coreclr/tests/src/Regressions/common/pow3.cs deleted file mode 100644 index 6b709c1c46d434..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/pow3.cs +++ /dev/null @@ -1,118 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -//different data types, Int16, Int32, Int64, etc -using System; - -class pow3 -{ - public static int Main() - { - bool pass = true; - - TestLibrary.TestFramework.BeginTestCase("Pow3"); - - TestLibrary.TestFramework.BeginScenario("Pow tests"); - - double a, b, y, z; - - //Int16 - Int16 x1 = 1; - y = Math.Sinh(x1); - a = Math.Pow(Math.E, x1); - b = Math.Pow(Math.E, -x1); - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x1+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - //Int32 - Int32 x2 = 1; - y = Math.Sinh(x2); - a = Math.Pow(Math.E, x2); - b = Math.Pow(Math.E, -x2); - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x2+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - //Int64 - Int64 x3 = 1; - y = Math.Sinh(x3); - a = Math.Pow(Math.E, x3); - b = Math.Pow(Math.E, -x3); - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x3+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - //UInt16 - UInt16 ux1 = 1; - y = Math.Sinh(x1); - a = Math.Pow(Math.E, ux1); - b = Math.Pow(Math.E, -ux1); - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x1+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - //UInt32 - UInt32 ux2 = 1; - y = Math.Sinh(ux2); - a = Math.Pow(Math.E, ux2); - b = Math.Pow(Math.E, -ux2); - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x2+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - //UInt64 - UInt64 ux3 = 1; - y = Math.Sinh(ux3); - a = Math.Pow(Math.E, ux3); - b = 1/a; - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x3+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - Single x4 = 1; - y = Math.Sinh(x4); - a = Math.Pow(Math.E, x4); - b = Math.Pow(Math.E, -x4); - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x3+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - Decimal x5 = 1; - y = Math.Sinh(Decimal.ToDouble(x5)); - a = Math.Pow(Math.E, Decimal.ToDouble(x5)); - b = Math.Pow(Math.E, -Decimal.ToDouble(x5)); - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x3+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - TestLibrary.TestFramework.EndTestCase(); - if (pass) { - TestLibrary.TestFramework.LogInformation("PASS"); - return 100; - } - else { - TestLibrary.TestFramework.LogInformation("FAIL"); - return 1; - } - - } -} diff --git a/src/coreclr/tests/src/Regressions/common/pow3.csproj b/src/coreclr/tests/src/Regressions/common/pow3.csproj deleted file mode 100644 index b3f90402b13103..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/pow3.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - Exe - BuildAndRun - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/common/test1307.cs b/src/coreclr/tests/src/Regressions/common/test1307.cs deleted file mode 100644 index 2f5cdf1dccbf45..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/test1307.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; -using System.Collections.Generic; - -public class Test -{ - public static int Main() - { - try - { - BodyDictionary obj = new BodyDictionary(); - - Console.WriteLine("PASS"); - return 100; - } - catch (Exception e) - { - Console.WriteLine("FAIL: Unexpected exception : " + e); - return 101; - } - } -} - -public class BodyDictionary : Dictionary -{ - public BodyDictionary() - : base() - { } -} diff --git a/src/coreclr/tests/src/Regressions/common/test1307.csproj b/src/coreclr/tests/src/Regressions/common/test1307.csproj deleted file mode 100644 index 65d8e445575c3b..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/test1307.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - Exe - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/common/testClass.cs b/src/coreclr/tests/src/Regressions/common/testClass.cs deleted file mode 100644 index 9361c2025d9689..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/testClass.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; -using System.Collections.Generic; -using System.Security; - -public class A -{ - public virtual object GetService(Type serviceType) - { - return this; - } -} - -[SecurityCritical] -public class Foo : A -{ - public override object GetService(Type serviceType) - { - return this; - } -} - -public class Class1 -{ - [SecuritySafeCritical] - public static int Main() - { - try - { - Foo f = new Foo(); - object o = f.GetService(null); // <-- MethodAccessException - Console.WriteLine("Success."); - return 100; - } - catch (Exception e) - { - Console.WriteLine("Error: " + e); - return 101; - } - } -} diff --git a/src/coreclr/tests/src/Regressions/common/testClass.csproj b/src/coreclr/tests/src/Regressions/common/testClass.csproj deleted file mode 100644 index 26512cdfe67852..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/testClass.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - Exe - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/common/testInterface.cs b/src/coreclr/tests/src/Regressions/common/testInterface.cs deleted file mode 100644 index 7ce2c7838da4a7..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/testInterface.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; -using System.Collections.Generic; -using System.Security; - -interface IFoo -{ - object GetService(Type t); -} - -[SecurityCritical] -public class Foo : IFoo -{ - public object GetService(Type serviceType) - { - return this; - } -} - -public class Class1 -{ - [SecuritySafeCritical] - public static int Main() - { - try - { - Foo f = new Foo(); - object o = f.GetService(null); // <-- MethodAccessException - Console.WriteLine("Success."); - return 100; - } - catch (Exception e) - { - Console.WriteLine("Error: " + e); - return 101; - } - - - } -} diff --git a/src/coreclr/tests/src/Regressions/common/testInterface.csproj b/src/coreclr/tests/src/Regressions/common/testInterface.csproj deleted file mode 100644 index 0b7e17f69decd4..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/testInterface.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - Exe - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/common/unsafe.cs b/src/coreclr/tests/src/Regressions/common/unsafe.cs deleted file mode 100644 index e8b38abc004d2e..00000000000000 --- a/src/coreclr/tests/src/Regressions/common/unsafe.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; -using System.Security; - -[SecurityCritical] -public unsafe class A -{ - public static int Main(string[] args) - { - bool retVal = true; - int[] array = new int[10]; - - TestLibrary.TestFramework.BeginTestCase("Using unsafe code and building against CoreCLR mscorlib"); - - TestLibrary.TestFramework.BeginScenario("Unsafe code take a dependecny on System.Security.Permissions.SecurityPermissionAttribute"); - - for(int j=0; j - - Exe - true - BuildAndRun - 0 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0018/ArrayCopy.csproj b/src/coreclr/tests/src/Regressions/coreclr/0018/ArrayCopy.csproj deleted file mode 100644 index f253a83ba8e60c..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0018/ArrayCopy.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0018/arraycopy.cool b/src/coreclr/tests/src/Regressions/coreclr/0018/arraycopy.cool deleted file mode 100644 index 71a6f9d4fa875e..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0018/arraycopy.cool +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -public class Repro -{ - public static Boolean ubyte_short() - { - const int size = 50; - short[] shortArray = new short[size]; - byte[] ubyteArray = new byte[size]; - for(int i=0; i - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0077/interlock.cs b/src/coreclr/tests/src/Regressions/coreclr/0077/interlock.cs deleted file mode 100644 index f2c81aa1e6b21c..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0077/interlock.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; - -public class A -{ - public static int Main() - { - - long iNew; - long iTotal; - - iTotal = 0; - - iNew = System.Threading.Interlocked.Add( ref iTotal, 2); - - Console.WriteLine("iNew = {0} iTotal = {1}", iNew, iTotal); - - if (iNew == iTotal) - { - Console.WriteLine("PASS"); - return 100; - } - else - { - Console.WriteLine("FAIL (iNew and iTotal should be equal)"); - return 0; - } - } -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/0077/interlock.csproj b/src/coreclr/tests/src/Regressions/coreclr/0077/interlock.csproj deleted file mode 100644 index 1308e32af53755..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0077/interlock.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0138/pow3.cs b/src/coreclr/tests/src/Regressions/coreclr/0138/pow3.cs deleted file mode 100644 index 9f57f55c3c4932..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0138/pow3.cs +++ /dev/null @@ -1,116 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -//different data types, Int16, Int32, Int64, etc -using System; - -class pow3 -{ - public static int Main() - { - bool pass = true; - - TestLibrary.TestFramework.BeginTestCase("Pow3"); - - TestLibrary.TestFramework.BeginScenario("Pow tests"); - - double a, b, y, z; - - //Int16 - Int16 x1 = 1; - y = Math.Sinh(x1); - a = Math.Pow(Math.E, x1); - b = Math.Pow(Math.E, -x1); - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x1+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - //Int32 - Int32 x2 = 1; - y = Math.Sinh(x2); - a = Math.Pow(Math.E, x2); - b = Math.Pow(Math.E, -x2); - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x2+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - //Int64 - Int64 x3 = 1; - y = Math.Sinh(x3); - a = Math.Pow(Math.E, x3); - b = Math.Pow(Math.E, -x3); - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x3+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - //UInt16 - UInt16 ux1 = 1; - y = Math.Sinh(x1); - a = Math.Pow(Math.E, ux1); - b = Math.Pow(Math.E, -ux1); - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x1+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - //UInt32 - UInt32 ux2 = 1; - y = Math.Sinh(ux2); - a = Math.Pow(Math.E, ux2); - b = Math.Pow(Math.E, -ux2); - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x2+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - //UInt64 - UInt64 ux3 = 1; - y = Math.Sinh(ux3); - a = Math.Pow(Math.E, ux3); - b = 1/a; - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x3+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - Single x4 = 1; - y = Math.Sinh(x4); - a = Math.Pow(Math.E, x4); - b = Math.Pow(Math.E, -x4); - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x3+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - Decimal x5 = 1; - y = Math.Sinh(Decimal.ToDouble(x5)); - a = Math.Pow(Math.E, Decimal.ToDouble(x5)); - b = Math.Pow(Math.E, -Decimal.ToDouble(x5)); - z = (a-b)/2; - if ((y-z)>10*Double.Epsilon) { - TestLibrary.TestFramework.LogError("001", "x: "+x3+", Sinh(x): "+y+", (Pow(E,x)-Pow(E,-x))/2: " + z); - pass = false; - } - - TestLibrary.TestFramework.EndTestCase(); - if (pass) { - TestLibrary.TestFramework.LogInformation("PASS"); - return 100; - } - else { - TestLibrary.TestFramework.LogInformation("FAIL"); - return 1; - } - - } -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/0138/pow3.csproj b/src/coreclr/tests/src/Regressions/coreclr/0138/pow3.csproj deleted file mode 100644 index 5ea20a48036964..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0138/pow3.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0149/SampleAssembly.csproj b/src/coreclr/tests/src/Regressions/coreclr/0149/SampleAssembly.csproj deleted file mode 100644 index 3563e780a47cf9..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0149/SampleAssembly.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Library - true - SharedLibrary - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0149/sampleassembly.cs b/src/coreclr/tests/src/Regressions/coreclr/0149/sampleassembly.cs deleted file mode 100644 index fe382bde9c1331..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0149/sampleassembly.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; - -public class TestClass -{ - int i; - - public TestClass(int iNew) - { - i = iNew; - } -} \ No newline at end of file diff --git a/src/coreclr/tests/src/Regressions/coreclr/0198/CompEx.csproj b/src/coreclr/tests/src/Regressions/coreclr/0198/CompEx.csproj deleted file mode 100644 index ad667df7314a61..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0198/CompEx.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0198/compex.cs b/src/coreclr/tests/src/Regressions/coreclr/0198/compex.cs deleted file mode 100644 index 58c62e882312bf..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0198/compex.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Threading; - -public class CompEx -{ - public static int Main() - { - Int64 total, initial, newValue; - Int64 newInitial; - - TestLibrary.TestFramework.BeginTestCase("CompareExchange(Int64&,Int64,Int64)"); - - TestLibrary.TestFramework.BeginScenario("CompareExchange(0,1,0)"); - - total = 0L; - newInitial = 0L; - for(int i=0; i<2; i++) - { - initial = total; - newValue = initial + 1L; - TestLibrary.TestFramework.LogInformation("BEFORE: T("+total+") NI("+newInitial+") NV("+newValue+") I("+initial+")"); - newInitial = Interlocked.CompareExchange( ref total, newValue, initial); - TestLibrary.TestFramework.LogInformation("AFTER: T("+total+") NI("+newInitial+") NV("+newValue+") I("+initial+")"); - TestLibrary.TestFramework.LogInformation(""); - } - - TestLibrary.TestFramework.EndTestCase(); - - if (2d == total) - { - TestLibrary.TestFramework.LogInformation("PASS"); - return 100; - } - else - { - TestLibrary.TestFramework.LogInformation("FAIL"); - return 0; - } - } - -} - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0202/ThreadCulture.csproj b/src/coreclr/tests/src/Regressions/coreclr/0202/ThreadCulture.csproj deleted file mode 100644 index bb4d88d7536035..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0202/ThreadCulture.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0202/threadculture.cs b/src/coreclr/tests/src/Regressions/coreclr/0202/threadculture.cs deleted file mode 100644 index c72fba87c6bace..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0202/threadculture.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Globalization; -using System.Threading; - -public class ThreadCultureRegression -{ - public static int Main() - { - // On Mac setting the current thread culture to german - // resulted in an error. - - CultureInfo german = new CultureInfo("de-DE"); - - TestLibrary.Utilities.CurrentCulture = german; - - // verify that it was changed - if (TestLibrary.Utilities.CurrentCulture.Name == "de-DE") - { - Console.WriteLine("PASS"); - return 100; - } - else - { - Console.WriteLine("FAIL"); - return 0; - } - - } -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/0275/Marshal.csproj b/src/coreclr/tests/src/Regressions/coreclr/0275/Marshal.csproj deleted file mode 100644 index 17f07c0fb162b6..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0275/Marshal.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0275/marshal.cs b/src/coreclr/tests/src/Regressions/coreclr/0275/marshal.cs deleted file mode 100644 index dc810b5a1c7be3..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0275/marshal.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Runtime.InteropServices; -using System.Security; - -public class MarshalTest -{ - [SecuritySafeCritical] - public unsafe static int Main() - { - int[] i = new int[2] {100, 99}; - int j = 0; - - TestLibrary.TestFramework.BeginTestCase("Marshal.ReadInt32()"); - - TestLibrary.TestFramework.BeginScenario("Marshal.ReadInt32(int[]&)"); - fixed (int* ip = &i[0]) - { - j = Marshal.ReadInt32( new IntPtr(ip) ); - - Console.WriteLine("j = {0} i = {1}", j, i[0]); - } - - TestLibrary.TestFramework.EndTestCase(); - - if (j == i[0]) - { - TestLibrary.TestFramework.LogInformation("PASS"); - return 100; - } - else - { - TestLibrary.TestFramework.LogInformation("FAIL"); - return 0; - } - } -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/0308/ToLower.csproj b/src/coreclr/tests/src/Regressions/coreclr/0308/ToLower.csproj deleted file mode 100644 index 7b5ed879021d27..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0308/ToLower.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0308/tolower.cs b/src/coreclr/tests/src/Regressions/coreclr/0308/tolower.cs deleted file mode 100644 index 6758875cdbb5ca..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0308/tolower.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; - -public class ToLowerRepro -{ - private const string c_UPPERCASE = "TELESTO TEST TEaM"; - private const string c_LOWERCASE = "telesto test team"; - - public static int Main(string[] args) - { - string lowerCase; - - TestLibrary.TestFramework.BeginTestCase("ToLower stack overflow test"); - - TestLibrary.TestFramework.BeginScenario("ToLower(\""+ c_UPPERCASE +"\")"); - - lowerCase = c_UPPERCASE.ToLower(); - - if (lowerCase.Equals(c_LOWERCASE)) - { - TestLibrary.TestFramework.EndTestCase(); - TestLibrary.TestFramework.LogInformation("PASS"); - return 100; - } - else - { - TestLibrary.TestFramework.EndTestCase(); - TestLibrary.TestFramework.LogError("001", "String was not converted to lower case: Expected("+c_LOWERCASE+") Actual("+lowerCase+")"); - TestLibrary.TestFramework.LogInformation("FAIL"); - return 0; - } - } - -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/0341/PlatformCode.csproj b/src/coreclr/tests/src/Regressions/coreclr/0341/PlatformCode.csproj deleted file mode 100644 index ad66db168c9f58..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0341/PlatformCode.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - Library - true - SharedLibrary - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0341/UserCode.csproj b/src/coreclr/tests/src/Regressions/coreclr/0341/UserCode.csproj deleted file mode 100644 index f4750c7f6ae5d4..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0341/UserCode.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - Library - true - SharedLibrary - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0341/platformcode.cs b/src/coreclr/tests/src/Regressions/coreclr/0341/platformcode.cs deleted file mode 100644 index c37fad813f772f..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0341/platformcode.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.IO; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Security; - -[assembly:SecurityCritical] - -public class PlatformCode -{ - public static void Begin(string testName) - { - TestLibrary.TestFramework.BeginTestCase(testName); - } -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/0341/usercode.cs b/src/coreclr/tests/src/Regressions/coreclr/0341/usercode.cs deleted file mode 100644 index 0542e22284759c..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0341/usercode.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Runtime.CompilerServices; -using System.Security; - -public class UserCode -{ - [SecuritySafeCritical] - public static bool StubCriticalCallTransparent() - { - bool retVal = true; - - try - { - retVal = CriticalCallTransparent(); - - if (!retVal) - { - TestLibrary.TestFramework.LogError("001", "Transparent UserCode should be able to call SecurityTreatAsSafe PlatformCode"); - retVal = false; - } - } - catch (Exception e) - { - TestLibrary.TestFramework.LogError("002", "Unexpected exception: " + e); - retVal = false; - } - - return retVal; - } - - [SecurityCritical] - [MethodImplAttribute(MethodImplOptions.NoInlining)] - public static bool CriticalCallTransparent() - { - return true; - } -} - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0342/unsafe.cs b/src/coreclr/tests/src/Regressions/coreclr/0342/unsafe.cs deleted file mode 100644 index e0ae737415f9ba..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0342/unsafe.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Security; - -[SecurityCritical] -public unsafe class A -{ - public static int Main(string[] args) - { - bool retVal = true; - int[] array = new int[10]; - - TestLibrary.TestFramework.BeginTestCase("Using unsafe code and building against CoreCLR mscorlib"); - - TestLibrary.TestFramework.BeginScenario("Unsafe code take a dependecny on System.Security.Permissions.SecurityPermissionAttribute"); - - for(int j=0; j - - Exe - true - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0433/assem.cs b/src/coreclr/tests/src/Regressions/coreclr/0433/assem.cs deleted file mode 100644 index 7e37b78a521272..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0433/assem.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; - - -public class A -{ - public int method1() - { - return 100; - } -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/0433/assem.csproj b/src/coreclr/tests/src/Regressions/coreclr/0433/assem.csproj deleted file mode 100644 index a1a17b326dd8df..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0433/assem.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Library - true - SharedLibrary - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0433/test.cs b/src/coreclr/tests/src/Regressions/coreclr/0433/test.cs deleted file mode 100644 index 03064dae2fe235..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0433/test.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// regression test for CoreCLR #433 -using System; - -public class Test -{ - public static int Main() - { - try - { - A obj = new A(); - - if (obj.method1() == 100) - { - Console.WriteLine("PASS"); - return 100; - } - else - { - Console.WriteLine("FAIL"); - return 101; - } - } - catch (Exception e) - { - Console.WriteLine("Caught unexpected exception: " + e); - return 102; - } - } -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/0433/test.csproj b/src/coreclr/tests/src/Regressions/coreclr/0433/test.csproj deleted file mode 100644 index 3d6c0c5f7f9ee8..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0433/test.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0570/Test570.csproj b/src/coreclr/tests/src/Regressions/coreclr/0570/Test570.csproj deleted file mode 100644 index 80fe7cd837af36..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0570/Test570.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0570/test570.cs b/src/coreclr/tests/src/Regressions/coreclr/0570/test570.cs deleted file mode 100644 index ce572f0a319f9b..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0570/test570.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Globalization; - -public class Test570 -{ - public static int Main() - { - int retVal = 100; - int numDigits = 2; - if (!TestLibrary.Utilities.IsWindows) - { - numDigits = 3; - } - - try - { - CultureInfo enUS = new CultureInfo("en-US"); - TestLibrary.Logging.WriteLine("enUS.NumberFormat.NumberDecimalDigits=" + enUS.NumberFormat.NumberDecimalDigits.ToString()); - if (enUS.NumberFormat.NumberDecimalDigits != numDigits) - { - TestLibrary.Logging.WriteLine("Error: enUS.NumberFormat.NumberDecimalDigits=" + enUS.NumberFormat.NumberDecimalDigits.ToString() + ", expected " + numDigits.ToString()); - retVal = 0; - } - TestLibrary.Logging.WriteLine("enUS.NumberFormat.PercentDecimalDigits=" + enUS.NumberFormat.PercentDecimalDigits.ToString()); - if (enUS.NumberFormat.PercentDecimalDigits != numDigits) - { - TestLibrary.Logging.WriteLine("Error: enUS.NumberFormat.PercentDecimalDigits=" + enUS.NumberFormat.PercentDecimalDigits.ToString() + ", expected " + numDigits.ToString()); - retVal = 0; - } - } - catch (Exception ex) - { - TestLibrary.Logging.WriteLine("Exception cought in main:"+ex.Message); - retVal = 0; - } - return retVal; - } - -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/0576/Test0576.csproj b/src/coreclr/tests/src/Regressions/coreclr/0576/Test0576.csproj deleted file mode 100644 index b90adb4f88402f..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0576/Test0576.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0576/test0576.cs b/src/coreclr/tests/src/Regressions/coreclr/0576/test0576.cs deleted file mode 100644 index 7c4fa69cfc9f4a..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0576/test0576.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Globalization; - -public class Test -{ - public static int Main() - { - try - { - CultureInfo ci = new CultureInfo("hu-HU"); - - string str1 = "Foobardzsdzs"; - string str2 = "rddzs"; - int result = ci.CompareInfo.IndexOf(str1, str2, CompareOptions.Ordinal); - int expected = -1; - - if (result != expected) - { - Console.WriteLine("!!!ERROR-001: Unexpected index. Expected: " + expected.ToString() + ", Actual: " + result.ToString()); - Console.WriteLine("FAIL"); - return 98; - } - } - catch (Exception e) - { - Console.WriteLine("!!!ERROR-XXX: Unexpected exception : " + e); - Console.WriteLine("FAIL"); - return 101; - } - Console.WriteLine("Pass"); - return 100; - } -} \ No newline at end of file diff --git a/src/coreclr/tests/src/Regressions/coreclr/0583/Test583.csproj b/src/coreclr/tests/src/Regressions/coreclr/0583/Test583.csproj deleted file mode 100644 index 88b00c80e98293..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0583/Test583.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0583/test583.cs b/src/coreclr/tests/src/Regressions/coreclr/0583/test583.cs deleted file mode 100644 index cf96c6ed6489d0..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0583/test583.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Resources; -using System.IO; -using System.Collections; -using System.Globalization; - -// Regression test for DevDiv Telesto 570 -// MAC: Globalization: DateTime.Parse throws FormatException when passed the ToString value of another DateTime -// Simply ensure that Mac no longer throws an exception when trying to parse the ToString of another DateTime. -public class Test570 -{ - private static bool Test() - { - bool retVal = true; - try - { - DateTime dtTemp = DateTime.Parse(DateTime.Now.ToString()); - - } - catch (Exception ex) - { - Console.WriteLine("Exception thrown DateTime.Parse(DateTime.Now.ToString()): " + ex); - retVal = false; - } - - return retVal; - } - - public static int Main() - { - int retVal = 100; - try - { - if (!Test()) - { - retVal = 0; - } - } - catch (Exception ex) - { - Console.WriteLine("Exception cought in main:"+ex.Message); - retVal = 0; - } - return retVal; - } - -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/0584/Test584.csproj b/src/coreclr/tests/src/Regressions/coreclr/0584/Test584.csproj deleted file mode 100644 index 2e1c3bc8fdc0ae..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0584/Test584.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - true - true - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0584/test584.cs b/src/coreclr/tests/src/Regressions/coreclr/0584/test584.cs deleted file mode 100644 index dfc778b2f8d5ee..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0584/test584.cs +++ /dev/null @@ -1,143 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Globalization; -public class test -{ - public static String[] locStrings = { - "ca-ES", // 0x00403; - "cs-CZ", // 0x00405; - "el-GR", // 0x00408; - "fr-FR", // 0x0040c; - "it-IT", // 0x00410; - "pt-BR", // 0x00416; - "sk-SK", // 0x0041b; - "gl-ES", // 0x00456; - "de-CH", // 0x00807; - "es-MX", // 0x0080a; - "fr-BE", // 0x0080c; - "it-CH", // 0x00810; - "pt-PT", // 0x00816; - "de-AT", // 0x00c07; - "fr-CA", // 0x00c0c; - "de-LU", // 0x01007; - "es-GT", // 0x0100a; - "fr-CH", // 0x0100c; - "de-LI", // 0x01407; - "es-CR", // 0x0140a; - "fr-LU", // 0x0140c; - "es-PA", // 0x0180a; - "fr-MC", // 0x0180c; - "es-DO", // 0x01c0a; - "es-VE", // 0x0200a; - "es-CO", // 0x0240a; - "es-PE", // 0x0280a; - "es-AR", // 0x02c0a; - "es-EC", // 0x0300a; - "es-UY", // 0x0380a; - "es-PY", // 0x03c0a; - "es-BO", // 0x0400a; - "es-SV", // 0x0440a; - "es-HN", // 0x0480a; - "es-NI", // 0x04c0a; - "es-PR", // 0x0500a; - "es-CL", // 13322; - "ja-JP", // 0x00411; - "ko-KR", // 0x00412; - "ur-PK", // 0x00420; - "fa-IR", // 0x00429; - "vi-VN", // 0x0042a; - "hy-AM", // 0x0042b; - "ka-GE", // 0x00437; - "hi-IN", // 0x00439; - "pa-IN", // 0x00446; - "gu-IN", // 0x00447; - "ta-IN", // 0x00449; - "te-IN", // 0x0044a; - "kn-IN", // 0x0044b; - "mr-IN", // 0x0044e; - "sa-IN", // 0x0044f; - "kok-IN", // 0x00457; - "syr-SY", // 0x0045a; - "ar-IQ", // 0x00801; - "zh-CN", // 0x00804; - "ar-EG", // 0x00c01; - "zh-HK", // 0x00c04; - "ar-LY", // 0x01001; - "zh-SG", // 0x01004; - "ar-DZ", // 0x01401; - "zh-MO", // 0x01404; - "ar-MA", // 0x01801; - "ar-TN", // 0x01c01; - "ar-OM", // 0x02001; - "ar-YE", // 0x02401; - "ar-SY", // 0x02801; - "ar-JO", // 0x02c01; - "ar-LB", // 0x03001; - "ar-KW", // 0x03401; - "ar-AE", // 0x03801; - "ar-BH", // 0x03c01; - "ar-QA", // 0x04001; - "ka-GE_modern", // 0x10437; - "zh-CN_stroke", // 0x20804; - "zh-SG_stroke", // 0x21004; - "zh-MO_stroke", // 0x21404; - "zh-TW_pronun", // 0x30404; - "he-IL", // 1037; - }; - - public static int Main() - { - int retVal = 100; - if (!TestLibrary.Utilities.IsWindows) - { - TestLibrary.Logging.WriteLine("running tests on Mac"); - if (!RunTest()) - { - retVal = 0; - } - - } - TestLibrary.Logging.WriteLine("returning " + retVal.ToString()); - return retVal; - } - - public static bool RunTest() - { - bool retVal = true; - for (int i = 0; i < locStrings.Length; i++) - { - retVal = retVal & CheckPattern(locStrings[i]); - } - return retVal; - } - public static bool CheckPattern(string locale) - { - string expectedMonthDayPattern = "MMMM dd"; - string expectedYearMonthPattern = "MMMM yyyy"; - bool retVal = false; - try - { - DateTimeFormatInfo DTFI = new CultureInfo(locale).DateTimeFormat; - if ((expectedMonthDayPattern.Equals(DTFI.MonthDayPattern)) && - (expectedYearMonthPattern.Equals(DTFI.YearMonthPattern))) - { - retVal = true; - } - else - { - TestLibrary.Logging.WriteLine("Error processing locale " + locale); - TestLibrary.Logging.WriteLine("MonthDayPattern, expected= " + expectedMonthDayPattern +", actual="+DTFI.MonthDayPattern); - TestLibrary.Logging.WriteLine("YearMonthPattern, expected= " + expectedYearMonthPattern + ", actual=" + DTFI.YearMonthPattern); - } - - } - catch (Exception ex) - { - TestLibrary.Logging.WriteLine("CheckPattern::Unexpected Exception Thrown processing locale "+locale+":" + ex); - retVal = false; - } - return retVal; - } -} \ No newline at end of file diff --git a/src/coreclr/tests/src/Regressions/coreclr/0694/CriticalCode.csproj b/src/coreclr/tests/src/Regressions/coreclr/0694/CriticalCode.csproj deleted file mode 100644 index fb66440159a4a1..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0694/CriticalCode.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - Library - true - SharedLibrary - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0694/criticalcode.cs b/src/coreclr/tests/src/Regressions/coreclr/0694/criticalcode.cs deleted file mode 100644 index 90eedf7c410d14..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0694/criticalcode.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.IO; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Security; - - -public class BaseClass -{ - [SecuritySafeCritical] - public virtual bool TreatAsSafe() - { - Console.WriteLine("BaseClass"); - return true; - } -} - -public class DerivedClassOverrideTransparent : BaseClass -{ - public override bool TreatAsSafe() - { - Console.WriteLine("DerivedClass"); - return true; - } -} \ No newline at end of file diff --git a/src/coreclr/tests/src/Regressions/coreclr/0792/Test0792.csproj b/src/coreclr/tests/src/Regressions/coreclr/0792/Test0792.csproj deleted file mode 100644 index 3ea99891aec3be..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0792/Test0792.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0792/test0792.cs b/src/coreclr/tests/src/Regressions/coreclr/0792/test0792.cs deleted file mode 100644 index cc4dc9c9b5fd39..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0792/test0792.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Reflection; - -public class Test -{ - public static int Main() - { - try - { - AssemblyName an = new AssemblyName("noname,PublicKeyToken=null"); - int expected = 0; - - if (an.GetPublicKeyToken() == null) - { - Console.WriteLine("!!!ERROR-001: Public key token unexpectedly null. Expected length: " + expected.ToString()); - Console.WriteLine("FAIL"); - return 98; - } - - if (an.GetPublicKeyToken().Length != expected) - { - Console.WriteLine("!!!ERROR-002: Public key token length not as expected. Expected: " + expected.ToString() + ", Actual: " + an.GetPublicKeyToken().Length.ToString()); - Console.WriteLine("FAIL"); - return 99; - } - } - catch (Exception e) - { - Console.WriteLine("!!!ERROR-XXX: Unexpected exception : " + e); - Console.WriteLine("FAIL"); - return 101; - } - Console.WriteLine("Pass"); - return 100; - } -} \ No newline at end of file diff --git a/src/coreclr/tests/src/Regressions/coreclr/0828/Test0828.csproj b/src/coreclr/tests/src/Regressions/coreclr/0828/Test0828.csproj deleted file mode 100644 index 86bc0f76f2f1d0..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0828/Test0828.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0828/test0828.cs b/src/coreclr/tests/src/Regressions/coreclr/0828/test0828.cs deleted file mode 100644 index 3ec2570da29067..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0828/test0828.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; - -public class Test -{ - public static int Main() - { - try - { - decimal i = decimal.MaxValue; - decimal j = decimal.MaxValue; - - decimal x = i + j; - - Console.WriteLine("!!!ERROR-001: Expected exeption not thrown. Result's value: " + x.ToString()); - Console.WriteLine("FAIL"); - return 99; - } - catch (OverflowException) - { - Console.WriteLine("Pass"); - return 100; - } - catch (Exception e) - { - Console.WriteLine("!!!ERROR-XXX: Unexpected exception : " + e); - Console.WriteLine("FAIL"); - return 101; - } - } -} \ No newline at end of file diff --git a/src/coreclr/tests/src/Regressions/coreclr/0829/Test0829.csproj b/src/coreclr/tests/src/Regressions/coreclr/0829/Test0829.csproj deleted file mode 100644 index 6d1f0e214f70e2..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0829/Test0829.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0829/test0829.cs b/src/coreclr/tests/src/Regressions/coreclr/0829/test0829.cs deleted file mode 100644 index 7a2895dfb75b89..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0829/test0829.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; - -public class Test -{ - public static int Main() - { - try - { - decimal i = new decimal(Single.MaxValue); - - Console.WriteLine("!!!ERROR-001: Expected exeption not thrown. Result's value: " + i.ToString()); - Console.WriteLine("FAIL"); - return 99; - } - catch (OverflowException) - { - Console.WriteLine("Pass"); - return 100; - } - catch (Exception e) - { - Console.WriteLine("!!!ERROR-XXX: Unexpected exception : " + e); - Console.WriteLine("FAIL"); - return 101; - } - } -} \ No newline at end of file diff --git a/src/coreclr/tests/src/Regressions/coreclr/0857/override.cs b/src/coreclr/tests/src/Regressions/coreclr/0857/override.cs deleted file mode 100644 index f5b7634d287c46..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0857/override.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; - -public class Test -{ - public static int Main() - { - Test t = new Test(); - - if (t.ToString().Equals("Hi")) - { - return 100; - } - - - return 0; - } - - public override string ToString() - { - return "Hi"; - } -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/0857/override.csproj b/src/coreclr/tests/src/Regressions/coreclr/0857/override.csproj deleted file mode 100644 index f781a2fbe6d77f..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0857/override.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0939/test0939.cs b/src/coreclr/tests/src/Regressions/coreclr/0939/test0939.cs deleted file mode 100644 index d7bbe2ab39193f..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0939/test0939.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; - -public class Test -{ - public static int Main() - { - bool retVal = true; - - try - { - string name = typeof(Test).Name; - } - catch (Exception e) - { - TestLibrary.TestFramework.LogError("001", "Unexpected exception: " + e); - retVal = false; - } - - try - { - string name2 = typeof(Test).ToString(); - } - catch (Exception e) - { - TestLibrary.TestFramework.LogError("001", "Unexpected exception: " + e); - retVal = false; - } - - if (retVal) - { - TestLibrary.TestFramework.LogInformation("PASS"); - return 100; - } - else - { - TestLibrary.TestFramework.LogVerbose("FAIL"); - return 101; - } - } -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/0939/test0939.csproj b/src/coreclr/tests/src/Regressions/coreclr/0939/test0939.csproj deleted file mode 100644 index 4ec8b0fa71e3a4..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0939/test0939.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0968/Test968.csproj b/src/coreclr/tests/src/Regressions/coreclr/0968/Test968.csproj deleted file mode 100644 index ea62e47b6790f6..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0968/Test968.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/0968/test968.cs b/src/coreclr/tests/src/Regressions/coreclr/0968/test968.cs deleted file mode 100644 index 6ab987f4d8c701..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/0968/test968.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Resources; -using System.IO; -using System.Collections; -using System.Globalization; - -// Regression test for DevDiv Telesto 968 -// MAC: Convert.ToDateTime(string) throws incorrect exception on JPN -// This will only really be hit in the globalization runs. -public class Test968 -{ - private static bool Test() - { - bool retVal = true; - try - { - DateTime result = Convert.ToDateTime("null"); - - } - catch (System.FormatException) - { - Console.WriteLine("Caughed expected System.FormatException calling Convert.ToDateTime(\"null\")"); - } - catch (Exception ex) - { - Console.WriteLine("Exception thrown Convert.ToDateTime(\"null\"): " + ex); - retVal = false; - } - - return retVal; - } - - public static int Main() - { - int retVal = 100; - try - { - if (!Test()) - { - retVal = 0; - } - } - catch (Exception ex) - { - Console.WriteLine("Exception cought in main:"+ex.Message); - retVal = 0; - } - return retVal; - } - -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/1307/test1307.cs b/src/coreclr/tests/src/Regressions/coreclr/1307/test1307.cs deleted file mode 100644 index 527871007337b8..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1307/test1307.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; - -public class Test -{ - public static int Main() - { - try - { - BodyDictionary obj = new BodyDictionary(); - - Console.WriteLine("PASS"); - return 100; - } - catch (Exception e) - { - Console.WriteLine("FAIL: Unexpected exception : " + e); - return 101; - } - } -} - -public class BodyDictionary : Dictionary -{ - public BodyDictionary() - : base() - { } -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/1307/test1307.csproj b/src/coreclr/tests/src/Regressions/coreclr/1307/test1307.csproj deleted file mode 100644 index 38a1c0a19d27c6..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1307/test1307.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/1333/testClass.csproj b/src/coreclr/tests/src/Regressions/coreclr/1333/testClass.csproj deleted file mode 100644 index 61bb3c50f78ac2..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1333/testClass.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/1333/testInterface.csproj b/src/coreclr/tests/src/Regressions/coreclr/1333/testInterface.csproj deleted file mode 100644 index 77680aed108242..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1333/testInterface.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/1333/testclass.cs b/src/coreclr/tests/src/Regressions/coreclr/1333/testclass.cs deleted file mode 100644 index a4927834aa0cd8..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1333/testclass.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; -using System.Security; - -public class A -{ - public virtual object GetService(Type serviceType) - { - return this; - } -} - -[SecurityCritical] -public class Foo : A -{ - public override object GetService(Type serviceType) - { - return this; - } -} - -public class Class1 -{ - [SecuritySafeCritical] - public static int Main() - { - try - { - Foo f = new Foo(); - object o = f.GetService(null); // <-- MethodAccessException - Console.WriteLine("Success."); - return 100; - } - catch (Exception e) - { - Console.WriteLine("Error: " + e); - return 101; - } - } -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/1333/testinterface.cs b/src/coreclr/tests/src/Regressions/coreclr/1333/testinterface.cs deleted file mode 100644 index d4a3f6c4f71348..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1333/testinterface.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; -using System.Security; - -interface IFoo -{ - object GetService(Type t); -} - -[SecurityCritical] -public class Foo : IFoo -{ - public object GetService(Type serviceType) - { - return this; - } -} - -public class Class1 -{ - [SecuritySafeCritical] - public static int Main() - { - try - { - Foo f = new Foo(); - object o = f.GetService(null); // <-- MethodAccessException - Console.WriteLine("Success."); - return 100; - } - catch (Exception e) - { - Console.WriteLine("Error: " + e); - return 101; - } - - - } -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/1337/Test1337.csproj b/src/coreclr/tests/src/Regressions/coreclr/1337/Test1337.csproj deleted file mode 100644 index a12ee31291ddc4..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1337/Test1337.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/1337/test1337.cs b/src/coreclr/tests/src/Regressions/coreclr/1337/test1337.cs deleted file mode 100644 index ec6555d4bd078e..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1337/test1337.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Text; - -public class Test -{ - public static int Main() - { - try - { - Encoding myEncoding = Encoding.GetEncoding("foo"); - - Console.WriteLine("!!!ERROR-001: Encoding created unexpectedly. Expected: ArgumentException, Actual: " + myEncoding.WebName); - Console.WriteLine("FAIL"); - return 99; - } - catch (ArgumentException) - { - Console.WriteLine("Pass"); - return 100; - } - catch (Exception e) - { - Console.WriteLine("!!!ERROR-002: Unexpected exception : " + e); - Console.WriteLine("FAIL"); - return 101; - } - } -} \ No newline at end of file diff --git a/src/coreclr/tests/src/Regressions/coreclr/1380/forwarder1.cs b/src/coreclr/tests/src/Regressions/coreclr/1380/forwarder1.cs deleted file mode 100644 index b34036b82c98ac..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1380/forwarder1.cs +++ /dev/null @@ -1,7 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -public class Foo -{ -} - diff --git a/src/coreclr/tests/src/Regressions/coreclr/1380/forwarder1.csproj b/src/coreclr/tests/src/Regressions/coreclr/1380/forwarder1.csproj deleted file mode 100644 index e6abdcab87d93a..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1380/forwarder1.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Library - true - SharedLibrary - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/1386/Co1727ctor_OO.csproj b/src/coreclr/tests/src/Regressions/coreclr/1386/Co1727ctor_OO.csproj deleted file mode 100644 index f02b43126b4927..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1386/Co1727ctor_OO.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/1386/co1727ctor_oo.cs b/src/coreclr/tests/src/Regressions/coreclr/1386/co1727ctor_oo.cs deleted file mode 100644 index 42beabee041d00..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1386/co1727ctor_oo.cs +++ /dev/null @@ -1,119 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Collections; -using System.Globalization; - -class Co1727 -{ - public bool runTest() - { - int iCountTestcases = 0; - int iCountErrors = 0; - - ///////////////// TEST 1 - //[]make new valid dictionary entry - TestLibrary.Logging.WriteLine( "make new valid dictionary entry" ); - try - { - ++iCountTestcases; - DictionaryEntry de = new DictionaryEntry( 1, 2 ); - - if ( ! 1.Equals( de.Key ) ) - { - ++iCountErrors; - TestLibrary.Logging.WriteLine( "Err_001a, incorrect key" ); - } - - if ( ! 2.Equals( de.Value ) ) - { - ++iCountErrors; - TestLibrary.Logging.WriteLine( "Err_001b, incorrect value" ); - } - - } - catch (Exception ex) - { - ++iCountErrors; - TestLibrary.Logging.WriteLine( "Err_001c, Unexpected exception was thrown ex: " + ex ); - } - - //////////////// TEST 2 - //[]make dictionary entry which should throw ArgumentNullException since key is null - TestLibrary.Logging.WriteLine( "make dictionary entry which should throw ArgumentNullException since key is null" ); - try - { - ++iCountTestcases; - DictionaryEntry de = new DictionaryEntry( null, 1 ); - - if ( de.Key != null ) - { - ++iCountErrors; - TestLibrary.Logging.WriteLine( "Err_002a, incorrect key" ); - } - - if ( !de.Value.Equals(1) ) - { - ++iCountErrors; - TestLibrary.Logging.WriteLine( "Err_002b, incorrect value" ); - } - - } - catch (Exception ex) - { - ++iCountErrors; - TestLibrary.Logging.WriteLine( "Err_002c, Excpected ArgumentNullException but thrown ex: " + ex.ToString() ); - } - - ///////////////// TEST 3 - //[]make new valid dictionary entry with value null - TestLibrary.Logging.WriteLine( "make new valid dictionary entry with value null" ); - try - { - ++iCountTestcases; - DictionaryEntry de = new DictionaryEntry( this, null ); - - if ( ! this.Equals( de.Key ) ) - { - ++iCountErrors; - TestLibrary.Logging.WriteLine( "Err_003a, incorrect key" ); - } - - if ( de.Value != null ) - { - ++iCountErrors; - TestLibrary.Logging.WriteLine( "Err_003b, incorrect value" ); - } - } - catch (Exception ex) - { - ++iCountErrors; - TestLibrary.Logging.WriteLine( "Err_003c, Unexpected exception was thrown ex: " + ex.ToString() ); - } - - - return (iCountErrors == 0 ); - } - - public static int Main( String [] args ) - { - Co1727 runClass; - bool bResult; - - runClass = new Co1727(); - bResult = runClass.runTest(); - - if (bResult) - { - TestLibrary.Logging.WriteLine("PASS"); - return 100; - } - else - { - TestLibrary.Logging.WriteLine("FAIL"); - return 0; - } - } - -} diff --git a/src/coreclr/tests/src/Regressions/coreclr/1402/Test1402.csproj b/src/coreclr/tests/src/Regressions/coreclr/1402/Test1402.csproj deleted file mode 100644 index fd85ce0fc12020..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1402/Test1402.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/1402/test1402.cs b/src/coreclr/tests/src/Regressions/coreclr/1402/test1402.cs deleted file mode 100644 index 0b55431a1e83d0..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1402/test1402.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Globalization; - -public class Test -{ - public static int Main() - { - try - { - CultureInfo ci = new CultureInfo("hu"); - - if (ci.ToString() != "hu") - { - Console.WriteLine("!!!ERROR-001: Result not as expected; expected value: hu, actual value: " + ci.ToString()); - Console.WriteLine("FAIL"); - return 99; - } - Console.WriteLine("Pass"); - return 100; - } - catch (Exception e) - { - Console.WriteLine("!!!ERROR-XXX: Unexpected exception : " + e); - Console.WriteLine("FAIL"); - return 101; - } - } -} \ No newline at end of file diff --git a/src/coreclr/tests/src/Regressions/coreclr/1534/Test1534.csproj b/src/coreclr/tests/src/Regressions/coreclr/1534/Test1534.csproj deleted file mode 100644 index 33ea90fe67494c..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1534/Test1534.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/1534/test1534.cs b/src/coreclr/tests/src/Regressions/coreclr/1534/test1534.cs deleted file mode 100644 index 7e1c91bb3718ae..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1534/test1534.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Globalization; - -public class Test -{ - public static int Main() - { - try - { - string str = "16:24:15"; - DateTime dt = DateTime.ParseExact(str, "HH:mm:HH", DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None); - - Console.WriteLine("!!!ERROR-001: Test parsed unexpectedly. Expected: FormatException, Actual: " + dt.ToString()); - Console.WriteLine("FAIL"); - return 99; - } - catch (FormatException) - { - Console.WriteLine("Pass"); - return 100; - } - catch (Exception e) - { - Console.WriteLine("!!!ERROR-002: Unexpected exception : " + e); - Console.WriteLine("FAIL"); - return 101; - } - } -} \ No newline at end of file diff --git a/src/coreclr/tests/src/Regressions/coreclr/1535/Test1535.csproj b/src/coreclr/tests/src/Regressions/coreclr/1535/Test1535.csproj deleted file mode 100644 index 90610898ac5d42..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1535/Test1535.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/1535/test1535.cs b/src/coreclr/tests/src/Regressions/coreclr/1535/test1535.cs deleted file mode 100644 index 75311e041a7a89..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1535/test1535.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Globalization; - -public class Test -{ - public static int Main() - { - try - { - string str = "16:24 AM"; - DateTime dt = DateTime.ParseExact(str, "HH:mm tt", DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None); - - Console.WriteLine("!!!ERROR-001: Test parsed unexpectedly. Expected: FormatException, Actual: " + dt.ToString()); - Console.WriteLine("FAIL"); - return 99; - } - catch (FormatException) - { - Console.WriteLine("Pass"); - return 100; - } - catch (Exception e) - { - Console.WriteLine("!!!ERROR-002: Unexpected exception : " + e); - Console.WriteLine("FAIL"); - return 101; - } - } -} \ No newline at end of file diff --git a/src/coreclr/tests/src/Regressions/coreclr/1549/Test1549.csproj b/src/coreclr/tests/src/Regressions/coreclr/1549/Test1549.csproj deleted file mode 100644 index f6f2650cfec9eb..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1549/Test1549.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - true - BuildAndRun - 1 - - - - - diff --git a/src/coreclr/tests/src/Regressions/coreclr/1549/test1549.cs b/src/coreclr/tests/src/Regressions/coreclr/1549/test1549.cs deleted file mode 100644 index 99166b3473affe..00000000000000 --- a/src/coreclr/tests/src/Regressions/coreclr/1549/test1549.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System; -using System.Text; - -public class Test -{ - public static int Main() - { - try - { - Encoding enc = Encoding.GetEncoding("utf-16"); - Decoder dec = enc.GetDecoder(); - int charPos = 0; - byte[] inBytes1 = new byte[] { 0x87 }; - byte[] inBytes2 = new byte[] { 0x90 }; - char[] outChars = new char[4]; - - int i = dec.GetChars(inBytes1, 0, inBytes1.Length, outChars, charPos, false); - charPos += i; - if (i != 0) - { - Console.WriteLine("!!!ERROR-001: Incorrect number of characters decoded. Expected: 0, Actual: " + i.ToString()); - Console.WriteLine("FAIL"); - return 91; - } - - i = dec.GetChars(inBytes2, 0, inBytes2.Length, outChars, charPos, false); - charPos += i; - if (i != 1) - { - Console.WriteLine("!!!ERROR-002: Incorrect number of characters decoded. Expected: 1, Actual: " + i.ToString()); - Console.WriteLine("FAIL"); - return 92; - } - - - if (outChars[0] != '\u9087') - { - Console.WriteLine("!!!ERROR-003: Incorrect character decoded. Expected: 9087, Actual: " + ((int)outChars[0]).ToString("x")); - Console.WriteLine("FAIL"); - return 93; - } - - for (int j = 1; j < 4; j++) - { - if (outChars[j] != '\u0000') - { - Console.WriteLine("!!!ERROR-004: Incorrect character decoded at index " + j.ToString() + ". Expected: 0000, Actual: " + ((int)outChars[j]).ToString("x")); - Console.WriteLine("FAIL"); - return 94; - } - } - - Console.WriteLine("Pass"); - return 100; - } - catch (Exception e) - { - Console.WriteLine("!!!ERROR-002: Unexpected exception : " + e); - Console.WriteLine("FAIL"); - return 101; - } - } -} \ No newline at end of file diff --git a/src/coreclr/tests/src/Regressions/coreclr/GitHub_1674/GitHub_1674.csproj b/src/coreclr/tests/src/Regressions/coreclr/GitHub_1674/GitHub_1674.csproj new file mode 100644 index 00000000000000..a1ab0938a415b5 --- /dev/null +++ b/src/coreclr/tests/src/Regressions/coreclr/GitHub_1674/GitHub_1674.csproj @@ -0,0 +1,14 @@ + + + Exe + true + BuildAndRun + 1 + + + + + + + + \ No newline at end of file diff --git a/src/coreclr/tests/src/Regressions/coreclr/GitHub_1674/TestConstraintOnDefaultInterfaceMethod.cs b/src/coreclr/tests/src/Regressions/coreclr/GitHub_1674/TestConstraintOnDefaultInterfaceMethod.cs new file mode 100644 index 00000000000000..39ce162f177e5b --- /dev/null +++ b/src/coreclr/tests/src/Regressions/coreclr/GitHub_1674/TestConstraintOnDefaultInterfaceMethod.cs @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace TestConstraint +{ + class TestConstraintOnDefaultInterfaceMethod + { + static int Main() + { + IAuditTrail auditTrail = new AuditTrail(); + // This should not fail per C# specs here: + // https://github.com/dotnet/csharplang/blob/master/spec/classes.md#type-parameter-constraints + auditTrail.AppendAsync(new EmptyLogEntry(), CancellationToken.None); + + // This should work since int always meets the constraint of IBuggy.Foo where T2: T1 + ((IBuggy)new Worky()).Foo(); + // This should work since Object always meets the constraint of IBuggy.Foo where T2: T1 + ((IBuggy)new Worky2()).Foo(); + // This should not throw since Open meets the constraint of IBuggy.Foo where T2: T1 + ((IBuggy)new Buggy()).Foo(); + + return 100; + + } + + interface IBuggy + { + public void Foo() where T2 : T1 => Console.WriteLine($"Works for type: {typeof(T1)}"); + } + public class Worky : IBuggy { } + public class Worky2 : IBuggy { } + public class Buggy : IBuggy { } + public class Open { } + + + private interface ILogEntry + { + long Index { get; } + } + + private interface IAuditTrail + where TRecord : class, ILogEntry + { + ValueTask AppendAsync(TRecordImpl impl, CancellationToken token) + where TRecordImpl : notnull, TRecord {Console.WriteLine("works.."); return new ValueTask();} + } + + private interface IRaftLogEntry : ILogEntry + { + long Term { get; } + } + + private sealed class AuditTrail : IAuditTrail + { + } + + private readonly struct EmptyLogEntry : IRaftLogEntry + { + long IRaftLogEntry.Term => 0L; + + long ILogEntry.Index => 0L; + } + } +} diff --git a/src/coreclr/tests/src/Regressions/coreclr/GitHub_34094/Test34094.csproj b/src/coreclr/tests/src/Regressions/coreclr/GitHub_34094/Test34094.csproj new file mode 100644 index 00000000000000..794de86714b2d3 --- /dev/null +++ b/src/coreclr/tests/src/Regressions/coreclr/GitHub_34094/Test34094.csproj @@ -0,0 +1,14 @@ + + + Exe + true + BuildAndRun + 0 + + + + + + + + diff --git a/src/coreclr/tests/src/Regressions/coreclr/GitHub_34094/test34094.cs b/src/coreclr/tests/src/Regressions/coreclr/GitHub_34094/test34094.cs new file mode 100644 index 00000000000000..e94e0e26eedbf2 --- /dev/null +++ b/src/coreclr/tests/src/Regressions/coreclr/GitHub_34094/test34094.cs @@ -0,0 +1,557 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +class Test34094 +{ + static bool TestSseCompareGreaterThan() + { + if (Sse.IsSupported) + { + const int expectedResult = 0b0100; + + Vector128 value1 = Vector128.Create(float.NaN, 1.0f, 2.0f, 3.0f); + Vector128 value2 = Vector128.Create(0.0f, 2.0f, 1.0f, 3.0f); + Vector128 result = Sse.CompareGreaterThan(value1, value2); + + int actualResult = Sse.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse)}.{nameof(Sse.CompareGreaterThan)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSseCompareGreaterThanOrEqual() + { + if (Sse.IsSupported) + { + const int expectedResult = 0b1100; + + Vector128 value1 = Vector128.Create(float.NaN, 1.0f, 2.0f, 3.0f); + Vector128 value2 = Vector128.Create(0.0f, 2.0f, 1.0f, 3.0f); + Vector128 result = Sse.CompareGreaterThanOrEqual(value1, value2); + + int actualResult = Sse.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse)}.{nameof(Sse.CompareGreaterThanOrEqual)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSseCompareNotGreaterThan() + { + if (Sse.IsSupported) + { + const int expectedResult = 0b1011; + + Vector128 value1 = Vector128.Create(float.NaN, 1.0f, 2.0f, 3.0f); + Vector128 value2 = Vector128.Create(0.0f, 2.0f, 1.0f, 3.0f); + Vector128 result = Sse.CompareNotGreaterThan(value1, value2); + + int actualResult = Sse.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse)}.{nameof(Sse.CompareNotGreaterThan)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSseCompareNotGreaterThanOrEqual() + { + if (Sse.IsSupported) + { + const int expectedResult = 0b0011; + + Vector128 value1 = Vector128.Create(float.NaN, 1.0f, 2.0f, 3.0f); + Vector128 value2 = Vector128.Create(0.0f, 2.0f, 1.0f, 3.0f); + Vector128 result = Sse.CompareNotGreaterThanOrEqual(value1, value2); + + int actualResult = Sse.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse)}.{nameof(Sse.CompareNotGreaterThanOrEqual)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSseCompareScalarGreaterThan() + { + if (Sse.IsSupported) + { + const int expectedResult = 0b0000; + + Vector128 value1 = Vector128.Create(float.NaN, 1.0f, 2.0f, 3.0f); + Vector128 value2 = Vector128.Create(0.0f, 2.0f, 1.0f, 3.0f); + Vector128 result = Sse.CompareScalarGreaterThan(value1, value2); + + int actualResult = Sse.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse)}.{nameof(Sse.CompareScalarGreaterThan)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSseCompareScalarGreaterThanOrEqual() + { + if (Sse.IsSupported) + { + const int expectedResult = 0b0000; + + Vector128 value1 = Vector128.Create(float.NaN, 1.0f, 2.0f, 3.0f); + Vector128 value2 = Vector128.Create(0.0f, 2.0f, 1.0f, 3.0f); + Vector128 result = Sse.CompareScalarGreaterThanOrEqual(value1, value2); + + int actualResult = Sse.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse)}.{nameof(Sse.CompareScalarGreaterThanOrEqual)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSseCompareScalarNotGreaterThan() + { + if (Sse.IsSupported) + { + const int expectedResult = 0b0001; + + Vector128 value1 = Vector128.Create(float.NaN, 1.0f, 2.0f, 3.0f); + Vector128 value2 = Vector128.Create(0.0f, 2.0f, 1.0f, 3.0f); + Vector128 result = Sse.CompareScalarNotGreaterThan(value1, value2); + + int actualResult = Sse.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse)}.{nameof(Sse.CompareScalarNotGreaterThan)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSseCompareScalarNotGreaterThanOrEqual() + { + if (Sse.IsSupported) + { + const int expectedResult = 0b0001; + + Vector128 value1 = Vector128.Create(float.NaN, 1.0f, 2.0f, 3.0f); + Vector128 value2 = Vector128.Create(0.0f, 2.0f, 1.0f, 3.0f); + Vector128 result = Sse.CompareScalarNotGreaterThanOrEqual(value1, value2); + + int actualResult = Sse.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse)}.{nameof(Sse.CompareScalarNotGreaterThanOrEqual)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSse2CompareGreaterThan() + { + if (Sse2.IsSupported) + { + const int expectedResult = 0b00; + + Vector128 value1 = Vector128.Create(double.NaN, 1.0); + Vector128 value2 = Vector128.Create(0.0, 2.0); + Vector128 result = Sse2.CompareGreaterThan(value1, value2); + + int actualResult = Sse2.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareGreaterThan)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSse2CompareGreaterThanOrEqual() + { + if (Sse2.IsSupported) + { + const int expectedResult = 0b00; + + Vector128 value1 = Vector128.Create(double.NaN, 1.0); + Vector128 value2 = Vector128.Create(0.0, 2.0); + Vector128 result = Sse2.CompareGreaterThanOrEqual(value1, value2); + + int actualResult = Sse2.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareGreaterThanOrEqual)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSse2CompareNotGreaterThan() + { + if (Sse2.IsSupported) + { + const int expectedResult = 0b11; + + Vector128 value1 = Vector128.Create(double.NaN, 1.0); + Vector128 value2 = Vector128.Create(0.0, 2.0); + Vector128 result = Sse2.CompareNotGreaterThan(value1, value2); + + int actualResult = Sse2.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareNotGreaterThan)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSse2CompareNotGreaterThanOrEqual() + { + if (Sse2.IsSupported) + { + const int expectedResult = 0b11; + + Vector128 value1 = Vector128.Create(double.NaN, 1.0); + Vector128 value2 = Vector128.Create(0.0, 2.0); + Vector128 result = Sse2.CompareNotGreaterThanOrEqual(value1, value2); + + int actualResult = Sse2.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareNotGreaterThanOrEqual)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSse2CompareScalarGreaterThan() + { + if (Sse2.IsSupported) + { + const int expectedResult = 0b00; + + Vector128 value1 = Vector128.Create(double.NaN, 1.0); + Vector128 value2 = Vector128.Create(0.0, 2.0); + Vector128 result = Sse2.CompareScalarGreaterThan(value1, value2); + + int actualResult = Sse2.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareScalarGreaterThan)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSse2CompareScalarGreaterThanOrEqual() + { + if (Sse2.IsSupported) + { + const int expectedResult = 0b00; + + Vector128 value1 = Vector128.Create(double.NaN, 1.0); + Vector128 value2 = Vector128.Create(0.0, 2.0); + Vector128 result = Sse2.CompareScalarGreaterThanOrEqual(value1, value2); + + int actualResult = Sse2.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareScalarGreaterThanOrEqual)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSse2CompareScalarNotGreaterThan() + { + if (Sse2.IsSupported) + { + const int expectedResult = 0b01; + + Vector128 value1 = Vector128.Create(double.NaN, 1.0); + Vector128 value2 = Vector128.Create(0.0, 2.0); + Vector128 result = Sse2.CompareScalarNotGreaterThan(value1, value2); + + int actualResult = Sse2.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareScalarNotGreaterThan)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestSse2CompareScalarNotGreaterThanOrEqual() + { + if (Sse2.IsSupported) + { + const int expectedResult = 0b01; + + Vector128 value1 = Vector128.Create(double.NaN, 1.0); + Vector128 value2 = Vector128.Create(0.0, 2.0); + Vector128 result = Sse2.CompareScalarNotGreaterThanOrEqual(value1, value2); + + int actualResult = Sse2.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.CompareScalarNotGreaterThanOrEqual)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestAvxCompareGreaterThanSingle() + { + if (Avx.IsSupported) + { + const int expectedResult = 0b0010_0100; + + Vector256 value1 = Vector256.Create(float.NaN, 1.0f, 2.0f, 3.0f, 0.0f, 2.0f, 1.0f, 3.0f); + Vector256 value2 = Vector256.Create(0.0f, 2.0f, 1.0f, 3.0f, float.NaN, 1.0f, 2.0f, 3.0f); + Vector256 result = Avx.CompareGreaterThan(value1, value2); + + int actualResult = Avx.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.CompareGreaterThan)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestAvxCompareGreaterThanOrEqualSingle() + { + if (Avx.IsSupported) + { + const int expectedResult = 0b1010_1100; + + Vector256 value1 = Vector256.Create(float.NaN, 1.0f, 2.0f, 3.0f, 0.0f, 2.0f, 1.0f, 3.0f); + Vector256 value2 = Vector256.Create(0.0f, 2.0f, 1.0f, 3.0f, float.NaN, 1.0f, 2.0f, 3.0f); + Vector256 result = Avx.CompareGreaterThanOrEqual(value1, value2); + + int actualResult = Avx.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.CompareGreaterThanOrEqual)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestAvxCompareNotGreaterThanSingle() + { + if (Avx.IsSupported) + { + const int expectedResult = 0b1101_1011; + + Vector256 value1 = Vector256.Create(float.NaN, 1.0f, 2.0f, 3.0f, 0.0f, 2.0f, 1.0f, 3.0f); + Vector256 value2 = Vector256.Create(0.0f, 2.0f, 1.0f, 3.0f, float.NaN, 1.0f, 2.0f, 3.0f); + Vector256 result = Avx.CompareNotGreaterThan(value1, value2); + + int actualResult = Avx.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.CompareNotGreaterThan)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestAvxCompareNotGreaterThanOrEqualSingle() + { + if (Avx.IsSupported) + { + const int expectedResult = 0b0101_0011; + + Vector256 value1 = Vector256.Create(float.NaN, 1.0f, 2.0f, 3.0f, 0.0f, 2.0f, 1.0f, 3.0f); + Vector256 value2 = Vector256.Create(0.0f, 2.0f, 1.0f, 3.0f, float.NaN, 1.0f, 2.0f, 3.0f); + Vector256 result = Avx.CompareNotGreaterThanOrEqual(value1, value2); + + int actualResult = Avx.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.CompareNotGreaterThanOrEqual)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestAvxCompareGreaterThanDouble() + { + if (Avx.IsSupported) + { + const int expectedResult = 0b1000; + + Vector256 value1 = Vector256.Create(double.NaN, 1.0, 0.0, 2.0); + Vector256 value2 = Vector256.Create(0.0, 2.0, double.NaN, 1.0); + Vector256 result = Avx.CompareGreaterThan(value1, value2); + + int actualResult = Avx.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.CompareGreaterThan)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestAvxCompareGreaterThanOrEqualDouble() + { + if (Avx.IsSupported) + { + const int expectedResult = 0b1000; + + Vector256 value1 = Vector256.Create(double.NaN, 1.0, 0.0, 2.0); + Vector256 value2 = Vector256.Create(0.0, 2.0, double.NaN, 1.0); + Vector256 result = Avx.CompareGreaterThanOrEqual(value1, value2); + + int actualResult = Avx.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.CompareGreaterThanOrEqual)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestAvxCompareNotGreaterThanDouble() + { + if (Avx.IsSupported) + { + const int expectedResult = 0b0111; + + Vector256 value1 = Vector256.Create(double.NaN, 1.0, 0.0, 2.0); + Vector256 value2 = Vector256.Create(0.0, 2.0, double.NaN, 1.0); + Vector256 result = Avx.CompareNotGreaterThan(value1, value2); + + int actualResult = Avx.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.CompareNotGreaterThan)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static bool TestAvxCompareNotGreaterThanOrEqualDouble() + { + if (Avx.IsSupported) + { + const int expectedResult = 0b0111; + + Vector256 value1 = Vector256.Create(double.NaN, 1.0, 0.0, 2.0); + Vector256 value2 = Vector256.Create(0.0, 2.0, double.NaN, 1.0); + Vector256 result = Avx.CompareNotGreaterThanOrEqual(value1, value2); + + int actualResult = Avx.MoveMask(result); + + if (actualResult != expectedResult) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.CompareNotGreaterThanOrEqual)}({value1}, {value2}) returned {Convert.ToString(actualResult, 2)}; expected {Convert.ToString(expectedResult, 2)}"); + return false; + } + } + return true; + } + + static unsafe int Main() + { + if (!Sse.IsSupported) + { + Console.WriteLine("SSE is not supported"); + } + + if (!Sse2.IsSupported) + { + Console.WriteLine("SSE2 is not supported"); + } + + if (!Avx.IsSupported) + { + Console.WriteLine("AVX is not supported"); + } + + return TestSseCompareGreaterThan() + & TestSseCompareGreaterThanOrEqual() + & TestSseCompareNotGreaterThan() + & TestSseCompareNotGreaterThanOrEqual() + & TestSseCompareScalarGreaterThan() + & TestSseCompareScalarGreaterThanOrEqual() + & TestSseCompareScalarNotGreaterThan() + & TestSseCompareScalarNotGreaterThanOrEqual() + & TestSse2CompareGreaterThan() + & TestSse2CompareGreaterThanOrEqual() + & TestSse2CompareNotGreaterThan() + & TestSse2CompareNotGreaterThanOrEqual() + & TestSse2CompareScalarGreaterThan() + & TestSse2CompareScalarGreaterThanOrEqual() + & TestSse2CompareScalarNotGreaterThan() + & TestSse2CompareScalarNotGreaterThanOrEqual() + & TestAvxCompareGreaterThanSingle() + & TestAvxCompareGreaterThanOrEqualSingle() + & TestAvxCompareNotGreaterThanSingle() + & TestAvxCompareNotGreaterThanOrEqualSingle() + & TestAvxCompareGreaterThanDouble() + & TestAvxCompareGreaterThanOrEqualDouble() + & TestAvxCompareNotGreaterThanDouble() + & TestAvxCompareNotGreaterThanOrEqualDouble() ? 100 : 0; + } +} diff --git a/src/coreclr/tests/src/Regressions/coreclr/GitHub_35000/test35000.cs b/src/coreclr/tests/src/Regressions/coreclr/GitHub_35000/test35000.cs new file mode 100644 index 00000000000000..30e03246a89356 --- /dev/null +++ b/src/coreclr/tests/src/Regressions/coreclr/GitHub_35000/test35000.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; +using System.Reflection; + +class Test35000 +{ + public class TestData0 + { + public virtual object MyMethod(int a, int b, int c, int d, int e, int f, int g, int h) { return null; } + } + + public class TestData1 : TestData0 + { + public override object MyMethod(int a, int b, int c, int d, int e, int f, int g, int h) { return null; } + } + + static int Main(string[] args) + { + var method = typeof(TestData0).GetMethod(nameof(TestData0.MyMethod)); + var func = (Func)Delegate.CreateDelegate(typeof(Func), null, method); + + TestData0 data = new TestData0(); + TestData0 data1 = new TestData1(); + + int nullRefCount = 0; + + const int LoopCount = 10; + + for (int j = 0; j < LoopCount; j++) + { + for (int i = 0; i < 50; i++) + { + func(data, 1, 2, 3, 4, 5, 6, 7, 8); + func(data1, 1, 2, 3, 4, 5, 6, 7, 8); + } + + try + { + func(null, 1, 2, 3, 4, 5, 6, 7, 8); + } + catch (NullReferenceException e) + { + nullRefCount++; + Console.WriteLine(e); + } + } + + return (nullRefCount == LoopCount) ? 100 : 101; + } +} diff --git a/src/coreclr/tests/src/Regressions/coreclr/GitHub_35000/test35000.csproj b/src/coreclr/tests/src/Regressions/coreclr/GitHub_35000/test35000.csproj new file mode 100644 index 00000000000000..b678cb6b392cc7 --- /dev/null +++ b/src/coreclr/tests/src/Regressions/coreclr/GitHub_35000/test35000.csproj @@ -0,0 +1,13 @@ + + + Exe + BuildAndRun + 1 + + + + + + + + diff --git a/src/coreclr/tests/src/Regressions/expl_double/body_double.cs b/src/coreclr/tests/src/Regressions/expl_double/body_double.cs deleted file mode 100644 index b21758c1eedaf0..00000000000000 --- a/src/coreclr/tests/src/Regressions/expl_double/body_double.cs +++ /dev/null @@ -1,742 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; -using System.Security; - -[SecuritySafeCritical] -class TestApp { - //***** TEST CODE ***** - static double test_0_0(double num, AA init, AA zero) { - return init.q; - } - static double test_0_1(double num, AA init, AA zero) { - zero.q=num; - return zero.q; - } - static double test_0_2(double num, AA init, AA zero) { - return init.q+zero.q; - } - static double test_0_3(double num, AA init, AA zero) { - return checked(init.q-zero.q); - } - static double test_0_4(double num, AA init, AA zero) { - zero.q+=num; return zero.q; - - } - static double test_0_5(double num, AA init, AA zero) { - zero.q+=init.q; return zero.q; - - } - static double test_0_6(double num, AA init, AA zero) { - if (init.q==num) - return 100; - else - return zero.q; - - } - static double test_0_7(double num, AA init, AA zero) { - return init.qzero.q?1:0)+99; - - } - static double test_0_9(double num, AA init, AA zero) { - object bb=init.q; - return (double)bb; - } - static double test_0_10(double num, AA init, AA zero) { - double dbl=init.q; - return (double)dbl; - } - static double test_0_11(double num, AA init, AA zero) { - return AA.call_target(init.q); - } - static double test_0_12(double num, AA init, AA zero) { - return AA.call_target_ref(ref init.q); - } - static double test_1_0(double num, ref AA r_init, ref AA r_zero) { - return r_init.q; - } - static double test_1_1(double num, ref AA r_init, ref AA r_zero) { - r_zero.q=num; - return r_zero.q; - } - static double test_1_2(double num, ref AA r_init, ref AA r_zero) { - return r_init.q+r_zero.q; - } - static double test_1_3(double num, ref AA r_init, ref AA r_zero) { - return checked(r_init.q-r_zero.q); - } - static double test_1_4(double num, ref AA r_init, ref AA r_zero) { - r_zero.q+=num; return r_zero.q; - - } - static double test_1_5(double num, ref AA r_init, ref AA r_zero) { - r_zero.q+=r_init.q; return r_zero.q; - - } - static double test_1_6(double num, ref AA r_init, ref AA r_zero) { - if (r_init.q==num) - return 100; - else - return r_zero.q; - - } - static double test_1_7(double num, ref AA r_init, ref AA r_zero) { - return r_init.qr_zero.q?1:0)+99; - - } - static double test_1_9(double num, ref AA r_init, ref AA r_zero) { - object bb=r_init.q; - return (double)bb; - } - static double test_1_10(double num, ref AA r_init, ref AA r_zero) { - double dbl=r_init.q; - return (double)dbl; - } - static double test_1_11(double num, ref AA r_init, ref AA r_zero) { - return AA.call_target(r_init.q); - } - static double test_1_12(double num, ref AA r_init, ref AA r_zero) { - return AA.call_target_ref(ref r_init.q); - } - static double test_2_0(double num) { - return AA.a_init[(int)num].q; - } - static double test_2_1(double num) { - AA.a_zero[(int)num].q=num; - return AA.a_zero[(int)num].q; - } - static double test_2_2(double num) { - return AA.a_init[(int)num].q+AA.a_zero[(int)num].q; - } - static double test_2_3(double num) { - return checked(AA.a_init[(int)num].q-AA.a_zero[(int)num].q); - } - static double test_2_4(double num) { - AA.a_zero[(int)num].q+=num; return AA.a_zero[(int)num].q; - - } - static double test_2_5(double num) { - AA.a_zero[(int)num].q+=AA.a_init[(int)num].q; return AA.a_zero[(int)num].q; - - } - static double test_2_6(double num) { - if (AA.a_init[(int)num].q==num) - return 100; - else - return AA.a_zero[(int)num].q; - - } - static double test_2_7(double num) { - return AA.a_init[(int)num].qAA.a_zero[(int)num].q?1:0)+99; - - } - static double test_2_9(double num) { - object bb=AA.a_init[(int)num].q; - return (double)bb; - } - static double test_2_10(double num) { - double dbl=AA.a_init[(int)num].q; - return (double)dbl; - } - static double test_2_11(double num) { - return AA.call_target(AA.a_init[(int)num].q); - } - static double test_2_12(double num) { - return AA.call_target_ref(ref AA.a_init[(int)num].q); - } - static double test_3_0(double num) { - return AA.aa_init[0,(int)num-1,(int)num/100].q; - } - static double test_3_1(double num) { - AA.aa_zero[0,(int)num-1,(int)num/100].q=num; - return AA.aa_zero[0,(int)num-1,(int)num/100].q; - } - static double test_3_2(double num) { - return AA.aa_init[0,(int)num-1,(int)num/100].q+AA.aa_zero[0,(int)num-1,(int)num/100].q; - } - static double test_3_3(double num) { - return checked(AA.aa_init[0,(int)num-1,(int)num/100].q-AA.aa_zero[0,(int)num-1,(int)num/100].q); - } - static double test_3_4(double num) { - AA.aa_zero[0,(int)num-1,(int)num/100].q+=num; return AA.aa_zero[0,(int)num-1,(int)num/100].q; - - } - static double test_3_5(double num) { - AA.aa_zero[0,(int)num-1,(int)num/100].q+=AA.aa_init[0,(int)num-1,(int)num/100].q; return AA.aa_zero[0,(int)num-1,(int)num/100].q; - - } - static double test_3_6(double num) { - if (AA.aa_init[0,(int)num-1,(int)num/100].q==num) - return 100; - else - return AA.aa_zero[0,(int)num-1,(int)num/100].q; - - } - static double test_3_7(double num) { - return AA.aa_init[0,(int)num-1,(int)num/100].qAA.aa_zero[0,(int)num-1,(int)num/100].q?1:0)+99; - - } - static double test_3_9(double num) { - object bb=AA.aa_init[0,(int)num-1,(int)num/100].q; - return (double)bb; - } - static double test_3_10(double num) { - double dbl=AA.aa_init[0,(int)num-1,(int)num/100].q; - return (double)dbl; - } - static double test_3_11(double num) { - return AA.call_target(AA.aa_init[0,(int)num-1,(int)num/100].q); - } - static double test_3_12(double num) { - return AA.call_target_ref(ref AA.aa_init[0,(int)num-1,(int)num/100].q); - } - static double test_4_0(double num) { - return BB.f_init.q; - } - static double test_4_1(double num) { - BB.f_zero.q=num; - return BB.f_zero.q; - } - static double test_4_2(double num) { - return BB.f_init.q+BB.f_zero.q; - } - static double test_4_3(double num) { - return checked(BB.f_init.q-BB.f_zero.q); - } - static double test_4_4(double num) { - BB.f_zero.q+=num; return BB.f_zero.q; - - } - static double test_4_5(double num) { - BB.f_zero.q+=BB.f_init.q; return BB.f_zero.q; - - } - static double test_4_6(double num) { - if (BB.f_init.q==num) - return 100; - else - return BB.f_zero.q; - - } - static double test_4_7(double num) { - return BB.f_init.qBB.f_zero.q?1:0)+99; - - } - static double test_4_9(double num) { - object bb=BB.f_init.q; - return (double)bb; - } - static double test_4_10(double num) { - double dbl=BB.f_init.q; - return (double)dbl; - } - static double test_4_11(double num) { - return AA.call_target(BB.f_init.q); - } - static double test_4_12(double num) { - return AA.call_target_ref(ref BB.f_init.q); - } - static double test_5_0(double num) { - return ((AA)AA.b_init).q; - } - static unsafe double test_7_0(double num, void *ptr_init, void *ptr_zero) { - return (*((AA*)ptr_init)).q; - } - static unsafe double test_7_1(double num, void *ptr_init, void *ptr_zero) { - (*((AA*)ptr_zero)).q=num; - return (*((AA*)ptr_zero)).q; - } - static unsafe double test_7_2(double num, void *ptr_init, void *ptr_zero) { - return (*((AA*)ptr_init)).q+(*((AA*)ptr_zero)).q; - } - static unsafe double test_7_3(double num, void *ptr_init, void *ptr_zero) { - return checked((*((AA*)ptr_init)).q-(*((AA*)ptr_zero)).q); - } - static unsafe double test_7_4(double num, void *ptr_init, void *ptr_zero) { - (*((AA*)ptr_zero)).q+=num; return (*((AA*)ptr_zero)).q; - - } - static unsafe double test_7_5(double num, void *ptr_init, void *ptr_zero) { - (*((AA*)ptr_zero)).q+=(*((AA*)ptr_init)).q; return (*((AA*)ptr_zero)).q; - - } - static unsafe double test_7_6(double num, void *ptr_init, void *ptr_zero) { - if ((*((AA*)ptr_init)).q==num) - return 100; - else - return (*((AA*)ptr_zero)).q; - - } - static unsafe double test_7_7(double num, void *ptr_init, void *ptr_zero) { - return (*((AA*)ptr_init)).q(*((AA*)ptr_zero)).q?1:0)+99; - - } - static unsafe double test_7_9(double num, void *ptr_init, void *ptr_zero) { - object bb=(*((AA*)ptr_init)).q; - return (double)bb; - } - static unsafe double test_7_10(double num, void *ptr_init, void *ptr_zero) { - double dbl=(*((AA*)ptr_init)).q; - return (double)dbl; - } - static unsafe double test_7_11(double num, void *ptr_init, void *ptr_zero) { - return AA.call_target((*((AA*)ptr_init)).q); - } - static unsafe double test_7_12(double num, void *ptr_init, void *ptr_zero) { - return AA.call_target_ref(ref (*((AA*)ptr_init)).q); - } - - //***** MAIN CODE ***** - static unsafe int Main() { - AA.reset(); - if (test_0_0(100, new AA(100), new AA(0)) != 100) { - Console.WriteLine("test_0_0() failed."); - return 101; - } - AA.verify_all(); AA.reset(); - if (test_0_1(100, new AA(100), new AA(0)) != 100) { - Console.WriteLine("test_0_1() failed."); - return 102; - } - AA.verify_all(); AA.reset(); - if (test_0_2(100, new AA(100), new AA(0)) != 100) { - Console.WriteLine("test_0_2() failed."); - return 103; - } - AA.verify_all(); AA.reset(); - if (test_0_3(100, new AA(100), new AA(0)) != 100) { - Console.WriteLine("test_0_3() failed."); - return 104; - } - AA.verify_all(); AA.reset(); - if (test_0_4(100, new AA(100), new AA(0)) != 100) { - Console.WriteLine("test_0_4() failed."); - return 105; - } - AA.verify_all(); AA.reset(); - if (test_0_5(100, new AA(100), new AA(0)) != 100) { - Console.WriteLine("test_0_5() failed."); - return 106; - } - AA.verify_all(); AA.reset(); - if (test_0_6(100, new AA(100), new AA(0)) != 100) { - Console.WriteLine("test_0_6() failed."); - return 107; - } - AA.verify_all(); AA.reset(); - if (test_0_7(100, new AA(100), new AA(0)) != 100) { - Console.WriteLine("test_0_7() failed."); - return 108; - } - AA.verify_all(); AA.reset(); - if (test_0_8(100, new AA(100), new AA(0)) != 100) { - Console.WriteLine("test_0_8() failed."); - return 109; - } - AA.verify_all(); AA.reset(); - if (test_0_9(100, new AA(100), new AA(0)) != 100) { - Console.WriteLine("test_0_9() failed."); - return 110; - } - AA.verify_all(); AA.reset(); - if (test_0_10(100, new AA(100), new AA(0)) != 100) { - Console.WriteLine("test_0_10() failed."); - return 111; - } - AA.verify_all(); AA.reset(); - if (test_0_11(100, new AA(100), new AA(0)) != 100) { - Console.WriteLine("test_0_11() failed."); - return 112; - } - AA.verify_all(); AA.reset(); - if (test_0_12(100, new AA(100), new AA(0)) != 100) { - Console.WriteLine("test_0_12() failed."); - return 113; - } - AA.verify_all(); AA.reset(); - if (test_1_0(100, ref AA._init, ref AA._zero) != 100) { - Console.WriteLine("test_1_0() failed."); - return 114; - } - AA.verify_all(); AA.reset(); - if (test_1_1(100, ref AA._init, ref AA._zero) != 100) { - Console.WriteLine("test_1_1() failed."); - return 115; - } - AA.verify_all(); AA.reset(); - if (test_1_2(100, ref AA._init, ref AA._zero) != 100) { - Console.WriteLine("test_1_2() failed."); - return 116; - } - AA.verify_all(); AA.reset(); - if (test_1_3(100, ref AA._init, ref AA._zero) != 100) { - Console.WriteLine("test_1_3() failed."); - return 117; - } - AA.verify_all(); AA.reset(); - if (test_1_4(100, ref AA._init, ref AA._zero) != 100) { - Console.WriteLine("test_1_4() failed."); - return 118; - } - AA.verify_all(); AA.reset(); - if (test_1_5(100, ref AA._init, ref AA._zero) != 100) { - Console.WriteLine("test_1_5() failed."); - return 119; - } - AA.verify_all(); AA.reset(); - if (test_1_6(100, ref AA._init, ref AA._zero) != 100) { - Console.WriteLine("test_1_6() failed."); - return 120; - } - AA.verify_all(); AA.reset(); - if (test_1_7(100, ref AA._init, ref AA._zero) != 100) { - Console.WriteLine("test_1_7() failed."); - return 121; - } - AA.verify_all(); AA.reset(); - if (test_1_8(100, ref AA._init, ref AA._zero) != 100) { - Console.WriteLine("test_1_8() failed."); - return 122; - } - AA.verify_all(); AA.reset(); - if (test_1_9(100, ref AA._init, ref AA._zero) != 100) { - Console.WriteLine("test_1_9() failed."); - return 123; - } - AA.verify_all(); AA.reset(); - if (test_1_10(100, ref AA._init, ref AA._zero) != 100) { - Console.WriteLine("test_1_10() failed."); - return 124; - } - AA.verify_all(); AA.reset(); - if (test_1_11(100, ref AA._init, ref AA._zero) != 100) { - Console.WriteLine("test_1_11() failed."); - return 125; - } - AA.verify_all(); AA.reset(); - if (test_1_12(100, ref AA._init, ref AA._zero) != 100) { - Console.WriteLine("test_1_12() failed."); - return 126; - } - AA.verify_all(); AA.reset(); - if (test_2_0(100) != 100) { - Console.WriteLine("test_2_0() failed."); - return 127; - } - AA.verify_all(); AA.reset(); - if (test_2_1(100) != 100) { - Console.WriteLine("test_2_1() failed."); - return 128; - } - AA.verify_all(); AA.reset(); - if (test_2_2(100) != 100) { - Console.WriteLine("test_2_2() failed."); - return 129; - } - AA.verify_all(); AA.reset(); - if (test_2_3(100) != 100) { - Console.WriteLine("test_2_3() failed."); - return 130; - } - AA.verify_all(); AA.reset(); - if (test_2_4(100) != 100) { - Console.WriteLine("test_2_4() failed."); - return 131; - } - AA.verify_all(); AA.reset(); - if (test_2_5(100) != 100) { - Console.WriteLine("test_2_5() failed."); - return 132; - } - AA.verify_all(); AA.reset(); - if (test_2_6(100) != 100) { - Console.WriteLine("test_2_6() failed."); - return 133; - } - AA.verify_all(); AA.reset(); - if (test_2_7(100) != 100) { - Console.WriteLine("test_2_7() failed."); - return 134; - } - AA.verify_all(); AA.reset(); - if (test_2_8(100) != 100) { - Console.WriteLine("test_2_8() failed."); - return 135; - } - AA.verify_all(); AA.reset(); - if (test_2_9(100) != 100) { - Console.WriteLine("test_2_9() failed."); - return 136; - } - AA.verify_all(); AA.reset(); - if (test_2_10(100) != 100) { - Console.WriteLine("test_2_10() failed."); - return 137; - } - AA.verify_all(); AA.reset(); - if (test_2_11(100) != 100) { - Console.WriteLine("test_2_11() failed."); - return 138; - } - AA.verify_all(); AA.reset(); - if (test_2_12(100) != 100) { - Console.WriteLine("test_2_12() failed."); - return 139; - } - AA.verify_all(); AA.reset(); - if (test_3_0(100) != 100) { - Console.WriteLine("test_3_0() failed."); - return 140; - } - AA.verify_all(); AA.reset(); - if (test_3_1(100) != 100) { - Console.WriteLine("test_3_1() failed."); - return 141; - } - AA.verify_all(); AA.reset(); - if (test_3_2(100) != 100) { - Console.WriteLine("test_3_2() failed."); - return 142; - } - AA.verify_all(); AA.reset(); - if (test_3_3(100) != 100) { - Console.WriteLine("test_3_3() failed."); - return 143; - } - AA.verify_all(); AA.reset(); - if (test_3_4(100) != 100) { - Console.WriteLine("test_3_4() failed."); - return 144; - } - AA.verify_all(); AA.reset(); - if (test_3_5(100) != 100) { - Console.WriteLine("test_3_5() failed."); - return 145; - } - AA.verify_all(); AA.reset(); - if (test_3_6(100) != 100) { - Console.WriteLine("test_3_6() failed."); - return 146; - } - AA.verify_all(); AA.reset(); - if (test_3_7(100) != 100) { - Console.WriteLine("test_3_7() failed."); - return 147; - } - AA.verify_all(); AA.reset(); - if (test_3_8(100) != 100) { - Console.WriteLine("test_3_8() failed."); - return 148; - } - AA.verify_all(); AA.reset(); - if (test_3_9(100) != 100) { - Console.WriteLine("test_3_9() failed."); - return 149; - } - AA.verify_all(); AA.reset(); - if (test_3_10(100) != 100) { - Console.WriteLine("test_3_10() failed."); - return 150; - } - AA.verify_all(); AA.reset(); - if (test_3_11(100) != 100) { - Console.WriteLine("test_3_11() failed."); - return 151; - } - AA.verify_all(); AA.reset(); - if (test_3_12(100) != 100) { - Console.WriteLine("test_3_12() failed."); - return 152; - } - AA.verify_all(); AA.reset(); - if (test_4_0(100) != 100) { - Console.WriteLine("test_4_0() failed."); - return 153; - } - AA.verify_all(); AA.reset(); - if (test_4_1(100) != 100) { - Console.WriteLine("test_4_1() failed."); - return 154; - } - AA.verify_all(); AA.reset(); - if (test_4_2(100) != 100) { - Console.WriteLine("test_4_2() failed."); - return 155; - } - AA.verify_all(); AA.reset(); - if (test_4_3(100) != 100) { - Console.WriteLine("test_4_3() failed."); - return 156; - } - AA.verify_all(); AA.reset(); - if (test_4_4(100) != 100) { - Console.WriteLine("test_4_4() failed."); - return 157; - } - AA.verify_all(); AA.reset(); - if (test_4_5(100) != 100) { - Console.WriteLine("test_4_5() failed."); - return 158; - } - AA.verify_all(); AA.reset(); - if (test_4_6(100) != 100) { - Console.WriteLine("test_4_6() failed."); - return 159; - } - AA.verify_all(); AA.reset(); - if (test_4_7(100) != 100) { - Console.WriteLine("test_4_7() failed."); - return 160; - } - AA.verify_all(); AA.reset(); - if (test_4_8(100) != 100) { - Console.WriteLine("test_4_8() failed."); - return 161; - } - AA.verify_all(); AA.reset(); - if (test_4_9(100) != 100) { - Console.WriteLine("test_4_9() failed."); - return 162; - } - AA.verify_all(); AA.reset(); - if (test_4_10(100) != 100) { - Console.WriteLine("test_4_10() failed."); - return 163; - } - AA.verify_all(); AA.reset(); - if (test_4_11(100) != 100) { - Console.WriteLine("test_4_11() failed."); - return 164; - } - AA.verify_all(); AA.reset(); - if (test_4_12(100) != 100) { - Console.WriteLine("test_4_12() failed."); - return 165; - } - AA.verify_all(); AA.reset(); - if (test_5_0(100) != 100) { - Console.WriteLine("test_5_0() failed."); - return 166; - } - AA.verify_all(); AA.reset(); - fixed (void *p_init = &AA._init, p_zero = &AA._zero) { - if (test_7_0(100, p_init, p_zero) != 100) { - Console.WriteLine("test_7_0() failed."); - return 168; - } - } - AA.verify_all(); AA.reset(); - fixed (void *p_init = &AA._init, p_zero = &AA._zero) { - if (test_7_1(100, p_init, p_zero) != 100) { - Console.WriteLine("test_7_1() failed."); - return 169; - } - } - AA.verify_all(); AA.reset(); - fixed (void *p_init = &AA._init, p_zero = &AA._zero) { - if (test_7_2(100, p_init, p_zero) != 100) { - Console.WriteLine("test_7_2() failed."); - return 170; - } - } - AA.verify_all(); AA.reset(); - fixed (void *p_init = &AA._init, p_zero = &AA._zero) { - if (test_7_3(100, p_init, p_zero) != 100) { - Console.WriteLine("test_7_3() failed."); - return 171; - } - } - AA.verify_all(); AA.reset(); - fixed (void *p_init = &AA._init, p_zero = &AA._zero) { - if (test_7_4(100, p_init, p_zero) != 100) { - Console.WriteLine("test_7_4() failed."); - return 172; - } - } - AA.verify_all(); AA.reset(); - fixed (void *p_init = &AA._init, p_zero = &AA._zero) { - if (test_7_5(100, p_init, p_zero) != 100) { - Console.WriteLine("test_7_5() failed."); - return 173; - } - } - AA.verify_all(); AA.reset(); - fixed (void *p_init = &AA._init, p_zero = &AA._zero) { - if (test_7_6(100, p_init, p_zero) != 100) { - Console.WriteLine("test_7_6() failed."); - return 174; - } - } - AA.verify_all(); AA.reset(); - fixed (void *p_init = &AA._init, p_zero = &AA._zero) { - if (test_7_7(100, p_init, p_zero) != 100) { - Console.WriteLine("test_7_7() failed."); - return 175; - } - } - AA.verify_all(); AA.reset(); - fixed (void *p_init = &AA._init, p_zero = &AA._zero) { - if (test_7_8(100, p_init, p_zero) != 100) { - Console.WriteLine("test_7_8() failed."); - return 176; - } - } - AA.verify_all(); AA.reset(); - fixed (void *p_init = &AA._init, p_zero = &AA._zero) { - if (test_7_9(100, p_init, p_zero) != 100) { - Console.WriteLine("test_7_9() failed."); - return 177; - } - } - AA.verify_all(); AA.reset(); - fixed (void *p_init = &AA._init, p_zero = &AA._zero) { - if (test_7_10(100, p_init, p_zero) != 100) { - Console.WriteLine("test_7_10() failed."); - return 178; - } - } - AA.verify_all(); AA.reset(); - fixed (void *p_init = &AA._init, p_zero = &AA._zero) { - if (test_7_11(100, p_init, p_zero) != 100) { - Console.WriteLine("test_7_11() failed."); - return 179; - } - } - AA.verify_all(); AA.reset(); - fixed (void *p_init = &AA._init, p_zero = &AA._zero) { - if (test_7_12(100, p_init, p_zero) != 100) { - Console.WriteLine("test_7_12() failed."); - return 180; - } - } - AA.verify_all(); Console.WriteLine("All tests passed."); - return 100; - } -} diff --git a/src/coreclr/tests/src/Regressions/expl_double/expl_double.csproj b/src/coreclr/tests/src/Regressions/expl_double/expl_double.csproj deleted file mode 100644 index 88b6aa8ef0fb36..00000000000000 --- a/src/coreclr/tests/src/Regressions/expl_double/expl_double.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - Exe - BuildAndRun - true - 1 - - - - - - diff --git a/src/coreclr/tests/src/Regressions/expl_double/expl_double_1.cs b/src/coreclr/tests/src/Regressions/expl_double/expl_double_1.cs deleted file mode 100644 index fa93215cd43cb6..00000000000000 --- a/src/coreclr/tests/src/Regressions/expl_double/expl_double_1.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; -using System.Runtime.InteropServices; - -[StructLayout(LayoutKind.Explicit)] struct AA { - [FieldOffset(4)] public byte tmp1; - - //this field is the testing subject - [FieldOffset(8)] - public double q; - - [FieldOffset(50)] public short tmp2; - - public AA(double qq) { - tmp1 = 0; - tmp2 = 0; - q = qq; - } - - public static AA[] a_init = new AA[101]; - public static AA[] a_zero = new AA[101]; - public static AA[,,] aa_init = new AA[1,101,2]; - public static AA[,,] aa_zero = new AA[1,101,2]; - public static object b_init = new AA(100); - public static AA _init, _zero; - - public static double call_target(double arg) { return arg; } - public static double call_target_ref(ref double arg) { return arg; } - - public void verify() { - } - - public static void verify_all() { - a_init[100].verify(); - a_zero[100].verify(); - aa_init[0,99,1].verify(); - aa_zero[0,99,1].verify(); - _init.verify(); - _zero.verify(); - BB.f_init.verify(); - BB.f_zero.verify(); - } - - public static void reset() { - a_init[100] = new AA(100); - a_zero[100] = new AA(0); - aa_init[0,99,1] = new AA(100); - aa_zero[0,99,1] = new AA(0); - _init = new AA(100); - _zero = new AA(0); - BB.f_init = new AA(100); - BB.f_zero = new AA(0); - } -} - -struct BB { - public static AA f_init, f_zero; -} diff --git a/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflow.cs b/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflow.cs new file mode 100644 index 00000000000000..3a4a363c7425bb --- /dev/null +++ b/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflow.cs @@ -0,0 +1,152 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; +using System.Threading; +using System.Runtime.CompilerServices; + +namespace TestStackOverflow +{ + struct LargeStruct256 + { + Guid g0; + Guid g1; + Guid g2; + Guid g3; + Guid g4; + Guid g5; + Guid g6; + Guid g7; + Guid g8; + Guid g9; + Guid ga; + Guid gb; + Guid gc; + Guid gd; + Guid ge; + Guid gf; + } + + struct LargeStruct4096 + { + LargeStruct256 s0; + LargeStruct256 s1; + LargeStruct256 s2; + LargeStruct256 s3; + LargeStruct256 s4; + LargeStruct256 s5; + LargeStruct256 s6; + LargeStruct256 s7; + LargeStruct256 s8; + LargeStruct256 s9; + LargeStruct256 sa; + LargeStruct256 sb; + LargeStruct256 sc; + LargeStruct256 sd; + LargeStruct256 se; + LargeStruct256 sf; + } + + struct LargeStruct65536 + { + LargeStruct4096 s0; + LargeStruct4096 s1; + LargeStruct4096 s2; + LargeStruct4096 s3; + LargeStruct4096 s4; + LargeStruct4096 s5; + LargeStruct4096 s6; + LargeStruct4096 s7; + LargeStruct4096 s8; + LargeStruct4096 s9; + LargeStruct4096 sa; + LargeStruct4096 sb; + LargeStruct4096 sc; + LargeStruct4096 sd; + LargeStruct4096 se; + LargeStruct4096 sf; + } + class Program + { + [MethodImpl(MethodImplOptions.NoInlining)] + static void InfiniteRecursionA() + { + InfiniteRecursionB(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void InfiniteRecursionB() + { + InfiniteRecursionC(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void InfiniteRecursionC() + { + InfiniteRecursionA(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void InfiniteRecursionA2() + { + LargeStruct65536 s; + InfiniteRecursionB2(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void InfiniteRecursionB2() + { + LargeStruct65536 s; + InfiniteRecursionC2(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void InfiniteRecursionC2() + { + LargeStruct65536 s; + InfiniteRecursionA2(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void Test(bool smallframe) + { + if (smallframe) + { + InfiniteRecursionA(); + } + else + { + InfiniteRecursionA2(); + } + } + + static void SecondaryThreadsTest(bool smallframe) + { + Thread[] threads = new Thread[32]; + for (int i = 0; i < threads.Length; i++) + { + threads[i] = new Thread(() => Test(smallframe)); + threads[i].Start(); + } + + for (int i = 0; i < threads.Length; i++) + { + threads[i].Join(); + } + } + + static void Main(string[] args) + { + bool smallframe = (args[0] == "smallframe"); + if (args[1] == "secondary") + { + SecondaryThreadsTest(smallframe); + } + else if (args[1] == "main") + { + Test(smallframe); + } + } + } +} + diff --git a/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflow.csproj b/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflow.csproj new file mode 100644 index 00000000000000..119fceb14efc96 --- /dev/null +++ b/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflow.csproj @@ -0,0 +1,12 @@ + + + Exe + false + BuildOnly + 0 + + + + + + diff --git a/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflow3.cs b/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflow3.cs new file mode 100644 index 00000000000000..bb53a0fb324c98 --- /dev/null +++ b/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflow3.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; + +namespace TestStackOverflow3 +{ + class Program + { + private const int MAX_RECURSIVE_CALLS = 1000000; + static int ctr = 0; + + public static void Main() + { + Program ex = new Program(); + ex.Execute(); + } + + private unsafe void Execute(string arg1 = "") + { + long* bar = stackalloc long [1000]; + ctr++; + if (ctr % 50 == 0) + Console.WriteLine("Call number {0} to the Execute method", ctr); + + if (ctr <= MAX_RECURSIVE_CALLS) + Execute(string.Format("{0}", (IntPtr)bar)); + + ctr--; + } + } +} + diff --git a/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflow3.csproj b/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflow3.csproj new file mode 100644 index 00000000000000..d75dd6ecbbe3d6 --- /dev/null +++ b/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflow3.csproj @@ -0,0 +1,13 @@ + + + Exe + false + true + BuildOnly + 0 + + + + + + diff --git a/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflowtester.cs b/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflowtester.cs new file mode 100644 index 00000000000000..d8326ff6666bf2 --- /dev/null +++ b/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflowtester.cs @@ -0,0 +1,277 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +namespace TestStackOverflow +{ + class Program + { + static string s_corerunPath; + static string s_currentPath; + + static bool TestStackOverflow(string testName, string testArgs, out List stderrLines) + { + Console.WriteLine($"Running {testName} test({testArgs})"); + List lines = new List(); + + Process testProcess = new Process(); + + testProcess.StartInfo.FileName = s_corerunPath; + testProcess.StartInfo.Arguments = $"{Path.Combine(s_currentPath, "..", testName, $"{testName}.dll")} {testArgs}"; + testProcess.StartInfo.UseShellExecute = false; + testProcess.StartInfo.RedirectStandardError = true; + testProcess.ErrorDataReceived += (sender, line) => + { + Console.WriteLine($"\"{line.Data}\""); + if (!string.IsNullOrEmpty(line.Data)) + { + lines.Add(line.Data); + } + }; + + testProcess.Start(); + testProcess.BeginErrorReadLine(); + testProcess.WaitForExit(); + testProcess.CancelErrorRead(); + + stderrLines = lines; + + int expectedExitCode; + if ((Environment.OSVersion.Platform == PlatformID.Unix) || (Environment.OSVersion.Platform == PlatformID.MacOSX)) + { + expectedExitCode = 128 + 6; + } + else + { + expectedExitCode = unchecked((int)0xC00000FD); + } + + if (testProcess.ExitCode != expectedExitCode) + { + Console.WriteLine($"Exit code: 0x{testProcess.ExitCode:X8}, expected 0x{expectedExitCode:X8}"); + return false; + } + + if (lines[0] != "Stack overflow.") + { + Console.WriteLine("Missing \"Stack overflow.\" at the first line"); + return false; + } + + return true; + } + + static bool TestStackOverflowSmallFrameMainThread() + { + List lines; + if (TestStackOverflow("stackoverflow", "smallframe main", out lines)) + { + if (!lines[lines.Count - 1].EndsWith("at TestStackOverflow.Program.Main(System.String[])")) + { + Console.WriteLine("Missing \"Main\" method frame at the last line"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("TestStackOverflow.Program.Test(Boolean)"))) + { + Console.WriteLine("Missing \"Test\" method frame"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionA()"))) + { + Console.WriteLine("Missing \"InfiniteRecursionA\" method frame"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionB()"))) + { + Console.WriteLine("Missing \"InfiniteRecursionB\" method frame"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionC()"))) + { + Console.WriteLine("Missing \"InfiniteRecursionC\" method frame"); + return false; + } + + return true; + } + + return false; + } + + static bool TestStackOverflowLargeFrameMainThread() + { + List lines; + if (TestStackOverflow("stackoverflow", "largeframe main", out lines)) + { + if (!lines[lines.Count - 1].EndsWith("at TestStackOverflow.Program.Main(System.String[])")) + { + Console.WriteLine("Missing \"Main\" method frame at the last line"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("TestStackOverflow.Program.Test(Boolean)"))) + { + Console.WriteLine("Missing \"Test\" method frame"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionA2()"))) + { + Console.WriteLine("Missing \"InfiniteRecursionA2\" method frame"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionB2()"))) + { + Console.WriteLine("Missing \"InfiniteRecursionB2\" method frame"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionC2()"))) + { + Console.WriteLine("Missing \"InfiniteRecursionC2\" method frame"); + return false; + } + + return true; + } + + return false; + } + + static bool TestStackOverflowSmallFrameSecondaryThread() + { + List lines; + if (TestStackOverflow("stackoverflow", "smallframe secondary", out lines)) + { + if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.Test(Boolean)"))) + { + Console.WriteLine("Missing \"TestStackOverflow.Program.Test\" method frame"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionA()"))) + { + Console.WriteLine("Missing \"InfiniteRecursionA\" method frame"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionB()"))) + { + Console.WriteLine("Missing \"InfiniteRecursionB\" method frame"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionC()"))) + { + Console.WriteLine("Missing \"InfiniteRecursionC\" method frame"); + return false; + } + + return true; + } + + return false; + } + + static bool TestStackOverflowLargeFrameSecondaryThread() + { + List lines; + if (TestStackOverflow("stackoverflow", "largeframe secondary", out lines)) + { + if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.Test(Boolean)"))) + { + Console.WriteLine("Missing \"TestStackOverflow.Program.Test\" method frame"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow.Program.InfiniteRecursionA2()"))) + { + Console.WriteLine("Missing \"InfiniteRecursionA2\" method frame"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("TestStackOverflow.Program.InfiniteRecursionB2()"))) + { + Console.WriteLine("Missing \"InfiniteRecursionB2\" method frame"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("TestStackOverflow.Program.InfiniteRecursionC2()"))) + { + Console.WriteLine("Missing \"InfiniteRecursionC2\" method frame"); + return false; + } + + return true; + } + + return false; + } + + static bool TestStackOverflow3() + { + List lines; + if (TestStackOverflow("stackoverflow3", "", out lines)) + { + if (!lines[lines.Count - 1].EndsWith("at TestStackOverflow3.Program.Main()")) + { + Console.WriteLine("Missing \"Main\" method frame at the last line"); + return false; + } + + if (!lines.Exists(elem => elem.EndsWith("at TestStackOverflow3.Program.Execute(System.String)"))) + { + Console.WriteLine("Missing \"Execute\" method frame"); + return false; + } + + return true; + } + + return false; + } + + static int Main(string[] args) + { + s_currentPath = Directory.GetCurrentDirectory(); + s_corerunPath = Path.Combine(Environment.GetEnvironmentVariable("CORE_ROOT"), "corerun"); + + if (!TestStackOverflowSmallFrameMainThread()) + { + return 101; + } + + if (!TestStackOverflowLargeFrameMainThread()) + { + return 102; + } + + if (!TestStackOverflowSmallFrameSecondaryThread()) + { + return 103; + } + + if (!TestStackOverflowLargeFrameSecondaryThread()) + { + return 104; + } + + if (!TestStackOverflow3()) + { + return 105; + } + + return 100; + } + } +} diff --git a/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflowtester.csproj b/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflowtester.csproj new file mode 100644 index 00000000000000..5cb94c1225699b --- /dev/null +++ b/src/coreclr/tests/src/baseservices/exceptions/stackoverflow/stackoverflowtester.csproj @@ -0,0 +1,12 @@ + + + Exe + false + BuildAndRun + 0 + + + + + + diff --git a/src/coreclr/tests/src/baseservices/mono/runningmono.cs b/src/coreclr/tests/src/baseservices/mono/runningmono.cs new file mode 100644 index 00000000000000..1a6a4151a38b6f --- /dev/null +++ b/src/coreclr/tests/src/baseservices/mono/runningmono.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; + +namespace TestRunningMono +{ + class Program + { + public static int Main(string[] args) + { + const int Pass = 100, Fail = 1; + bool isMono = typeof(object).Assembly.GetType("Mono.RuntimeStructs") != null; + + if(isMono) + { + return Pass; + } + else + { + return Fail; + } + } + } +} + diff --git a/src/coreclr/tests/src/baseservices/mono/runningmono.csproj b/src/coreclr/tests/src/baseservices/mono/runningmono.csproj new file mode 100644 index 00000000000000..c560a028e3b8c4 --- /dev/null +++ b/src/coreclr/tests/src/baseservices/mono/runningmono.csproj @@ -0,0 +1,11 @@ + + + Exe + false + 0 + + + + + + diff --git a/src/coreclr/tests/src/performance/Scenario/JitBench/Utilities/DotNetSetup.cs b/src/coreclr/tests/src/performance/Scenario/JitBench/Utilities/DotNetSetup.cs index ceeb3de640c202..2750c28ab667c8 100644 --- a/src/coreclr/tests/src/performance/Scenario/JitBench/Utilities/DotNetSetup.cs +++ b/src/coreclr/tests/src/performance/Scenario/JitBench/Utilities/DotNetSetup.cs @@ -235,7 +235,7 @@ public static string GetTargetFrameworkMonikerForFrameworkVersion(string runtime { if (runtimeVersion.StartsWith("5.0")) { - return "netcoreapp5.0"; + return "net5.0"; } else if (runtimeVersion.StartsWith("3.0")) { diff --git a/src/coreclr/tests/src/profiler/common/ProfilerTestRunner.cs b/src/coreclr/tests/src/profiler/common/ProfilerTestRunner.cs index d425d4f544cf6e..6b5bb26e0fa59e 100644 --- a/src/coreclr/tests/src/profiler/common/ProfilerTestRunner.cs +++ b/src/coreclr/tests/src/profiler/common/ProfilerTestRunner.cs @@ -15,7 +15,7 @@ namespace Profiler.Tests public enum ProfileeOptions { None = 0, - DisableTieredCompilation, + OptimizationSensitive, NoStartupAttach } @@ -41,10 +41,12 @@ public static int Run(string profileePath, envVars.Add("CORECLR_PROFILER", "{" + profilerClsid + "}"); } - if (profileeOptions.HasFlag(ProfileeOptions.DisableTieredCompilation)) + if (profileeOptions.HasFlag(ProfileeOptions.OptimizationSensitive)) { - Console.WriteLine("Disabling tiered compilation."); + Console.WriteLine("Disabling tiered compilation, jitstress, and minopts."); envVars.Add("COMPlus_TieredCompilation", "0"); + envVars.Add("COMPlus_JitStress", "0"); + envVars.Add("COMPlus_JITMinOpts", "0"); } string profilerPath = GetProfilerPath(); diff --git a/src/coreclr/tests/src/profiler/native/eventpipeprofiler/eventpipeprofiler.cpp b/src/coreclr/tests/src/profiler/native/eventpipeprofiler/eventpipeprofiler.cpp index d96fbc12233e9f..c89283e5c56c5f 100644 --- a/src/coreclr/tests/src/profiler/native/eventpipeprofiler/eventpipeprofiler.cpp +++ b/src/coreclr/tests/src/profiler/native/eventpipeprofiler/eventpipeprofiler.cpp @@ -24,7 +24,7 @@ HRESULT EventPipeProfiler::Initialize(IUnknown* pICorProfilerInfoUnk) } // No event mask, just calling the EventPipe APIs. - if (FAILED(hr = _pCorProfilerInfo12->SetEventMask2(COR_PRF_MONITOR_JIT_COMPILATION, 0))) + if (FAILED(hr = _pCorProfilerInfo12->SetEventMask2(COR_PRF_MONITOR_JIT_COMPILATION | COR_PRF_MONITOR_CACHE_SEARCHES, 0))) { _failures++; printf("FAIL: ICorProfilerInfo::SetEventMask2() failed hr=0x%x\n", hr); @@ -144,6 +144,22 @@ HRESULT EventPipeProfiler::Shutdown() } HRESULT EventPipeProfiler::JITCompilationStarted(FunctionID functionId, BOOL fIsSafeToBlock) +{ + return FunctionSeen(functionId); +} + +HRESULT STDMETHODCALLTYPE EventPipeProfiler::JITCachedFunctionSearchFinished(FunctionID functionId, COR_PRF_JIT_CACHE result) +{ + if (result == COR_PRF_CACHED_FUNCTION_FOUND) + { + return FunctionSeen(functionId); + } + + return S_OK; +} + + +HRESULT EventPipeProfiler::FunctionSeen(FunctionID functionId) { String functionName = GetFunctionIDName(functionId); if (functionName == WCHAR("TriggerMethod")) @@ -265,4 +281,4 @@ HRESULT EventPipeProfiler::JITCompilationStarted(FunctionID functionId, BOOL fIs } return S_OK; -} +} \ No newline at end of file diff --git a/src/coreclr/tests/src/profiler/native/eventpipeprofiler/eventpipeprofiler.h b/src/coreclr/tests/src/profiler/native/eventpipeprofiler/eventpipeprofiler.h index 7285e28c11f06a..0d6d497939d23a 100644 --- a/src/coreclr/tests/src/profiler/native/eventpipeprofiler/eventpipeprofiler.h +++ b/src/coreclr/tests/src/profiler/native/eventpipeprofiler/eventpipeprofiler.h @@ -21,6 +21,7 @@ class EventPipeProfiler : public Profiler virtual HRESULT STDMETHODCALLTYPE Initialize(IUnknown* pICorProfilerInfoUnk); virtual HRESULT STDMETHODCALLTYPE Shutdown(); virtual HRESULT STDMETHODCALLTYPE JITCompilationStarted(FunctionID functionId, BOOL fIsSafeToBlock); + virtual HRESULT STDMETHODCALLTYPE JITCachedFunctionSearchFinished(FunctionID functionId, COR_PRF_JIT_CACHE result); private: std::atomic _failures; @@ -29,4 +30,6 @@ class EventPipeProfiler : public Profiler EVENTPIPE_EVENT _allTypesEvent; EVENTPIPE_EVENT _emptyEvent; EVENTPIPE_EVENT _simpleEvent; + + HRESULT FunctionSeen(FunctionID functionId); }; \ No newline at end of file diff --git a/src/coreclr/tests/src/profiler/native/metadatagetdispenser/metadatagetdispenser.cpp b/src/coreclr/tests/src/profiler/native/metadatagetdispenser/metadatagetdispenser.cpp index 97bbe361a19676..2f4d0cfc914697 100644 --- a/src/coreclr/tests/src/profiler/native/metadatagetdispenser/metadatagetdispenser.cpp +++ b/src/coreclr/tests/src/profiler/native/metadatagetdispenser/metadatagetdispenser.cpp @@ -8,6 +8,12 @@ #include #else // WIN32 #include +#include +#include +#include +using std::string; +using std::ifstream; +using std::getline; #ifdef __APPLE__ #include #endif // __APPLE__ @@ -160,7 +166,6 @@ HRESULT MetaDataGetDispenser::GetDispenser(IMetaDataDispenserEx **disp) #else // WIN32 -#ifdef __APPLE__ bool EndsWith(const char *lhs, const char *rhs) { size_t lhsLen = strlen(lhs); @@ -186,7 +191,9 @@ bool EndsWith(const char *lhs, const char *rhs) return true; } -const char *GetCoreCLRPath() + +#ifdef __APPLE__ +string GetCoreCLRPath() { const char *coreclrName = "libcoreclr.dylib"; size_t count = _dyld_image_count(); @@ -201,22 +208,51 @@ const char *GetCoreCLRPath() return coreclrName; } + +#else // __APPLE__ + +string GetLibraryName(string line) +{ + // /proc/self/maps contains lines that look like the following: + // 7efdd3d22000-7efdd3f09000 r-xp 00000000 08:02 14160554 /lib/x86_64-linux-gnu/libc-2.27.so + // We can parse them by looking for the last space and return everything after that + // It assumes that none of the paths have spaces + size_t lastSpace = line.find_last_of(' '); + if (lastSpace == string::npos || lastSpace >= (line.size() - 1)) + { + return string(); + } + + return line.substr(lastSpace + 1, string::npos); +} + +string GetCoreCLRPath() +{ + string line; + ifstream sharedLibs("/proc/self/maps"); + while (getline(sharedLibs, line)) + { + string lib = GetLibraryName(line); + if (EndsWith(lib.c_str(), "libcoreclr.so")) + { + return lib; + } + } + + return string(); +} #endif // __APPLE__ HRESULT MetaDataGetDispenser::GetDispenser(IMetaDataDispenserEx **disp) { -#ifdef __APPLE__ - const char *profilerName = GetCoreCLRPath(); -#else // __APPLE__ - const char *profilerName = "libcoreclr.so"; -#endif // __APPLE__ + string profilerName = GetCoreCLRPath(); - void *coreclr = dlopen(profilerName, RTLD_LAZY | RTLD_NOLOAD); + void *coreclr = dlopen(profilerName.c_str(), RTLD_LAZY | RTLD_NOLOAD); if (coreclr == NULL) { _failures++; char *reason = dlerror(); - printf("Failed to find %s reason=%s\n", profilerName, reason); + printf("Failed to find %s reason=%s\n", profilerName.c_str(), reason); return E_FAIL; } @@ -240,4 +276,4 @@ HRESULT MetaDataGetDispenser::GetDispenser(IMetaDataDispenserEx **disp) printf("Got IMetaDataDispenserEx\n"); return S_OK; } -#endif // WIN32 +#endif // WIN32 \ No newline at end of file diff --git a/src/coreclr/tests/src/profiler/native/rejitprofiler/rejitprofiler.cpp b/src/coreclr/tests/src/profiler/native/rejitprofiler/rejitprofiler.cpp index 6394a7e867183b..2d241f37045d2a 100644 --- a/src/coreclr/tests/src/profiler/native/rejitprofiler/rejitprofiler.cpp +++ b/src/coreclr/tests/src/profiler/native/rejitprofiler/rejitprofiler.cpp @@ -70,7 +70,9 @@ HRESULT ReJITProfiler::Initialize(IUnknown* pICorProfilerInfoUnk) INFO(L"Initialize started"); - DWORD eventMaskLow = COR_PRF_ENABLE_REJIT | COR_PRF_MONITOR_JIT_COMPILATION; + DWORD eventMaskLow = COR_PRF_ENABLE_REJIT | + COR_PRF_MONITOR_JIT_COMPILATION | + COR_PRF_MONITOR_CACHE_SEARCHES; DWORD eventMaskHigh = 0x0; if (FAILED(hr = pCorProfilerInfo->SetEventMask2(eventMaskLow, eventMaskHigh))) { @@ -117,15 +119,10 @@ HRESULT ReJITProfiler::Shutdown() HRESULT STDMETHODCALLTYPE ReJITProfiler::JITCompilationStarted(FunctionID functionId, BOOL fIsSafeToBlock) { - ModuleID moduleId = GetModuleIDForFunction(functionId); - String moduleName = GetModuleIDName(moduleId); - - String funcName = GetFunctionIDName(functionId); - INFO(L"jitting started for " << funcName << L" in module " << moduleName); return S_OK; } -HRESULT STDMETHODCALLTYPE ReJITProfiler::JITCompilationFinished(FunctionID functionId, HRESULT hrStatus, BOOL fIsSafeToBlock) +HRESULT ReJITProfiler::FunctionSeen(FunctionID functionId) { String functionName = GetFunctionIDName(functionId); ModuleID moduleId = GetModuleIDForFunction(functionId); @@ -161,14 +158,59 @@ HRESULT STDMETHODCALLTYPE ReJITProfiler::JITCompilationFinished(FunctionID funct return S_OK; } +HRESULT STDMETHODCALLTYPE ReJITProfiler::JITCompilationFinished(FunctionID functionId, HRESULT hrStatus, BOOL fIsSafeToBlock) +{ + return FunctionSeen(functionId); +} + HRESULT STDMETHODCALLTYPE ReJITProfiler::JITInlining(FunctionID callerId, FunctionID calleeId, BOOL* pfShouldInline) { AddInlining(callerId, calleeId); *pfShouldInline = TRUE; - String calleeName = GetFunctionIDName(calleeId); - String moduleName = GetModuleIDName(GetModuleIDForFunction(calleeId)); - INFO(L"Inlining occurred! Inliner=" << GetFunctionIDName(callerId) << L" Inlinee=" << calleeName << L" Inlinee module name=" << moduleName); + return S_OK; +} + + +HRESULT STDMETHODCALLTYPE ReJITProfiler::JITCachedFunctionSearchFinished(FunctionID functionId, COR_PRF_JIT_CACHE result) +{ + if (result == COR_PRF_CACHED_FUNCTION_FOUND) + { + HRESULT hr; + if(FAILED(hr = FunctionSeen(functionId))) + { + return hr; + } + + // TODO: this only looks in the same module as the function, with version bubbles that may + // not hold. + ModuleID modId = GetModuleIDForFunction(functionId); + mdToken methodDef; + if (FAILED(hr = pCorProfilerInfo->GetFunctionInfo(functionId, NULL, NULL, &methodDef))) + { + printf("Call to GetFunctionInfo failed with hr=0x%x\n", hr); + return hr; + } + + COMPtrHolder pEnum = NULL; + if (FAILED(hr = pCorProfilerInfo->EnumNgenModuleMethodsInliningThisMethod(modId, modId, methodDef, NULL, &pEnum))) + { + printf("Call to EnumNgenModuleMethodsInliningThisMethod failed with hr=0x%x\n", hr); + return hr; + } + + COR_PRF_METHOD method; + while (pEnum->Next(1, &method, NULL) == S_OK) + { + FunctionID inlinerFuncId = GetFunctionIDFromToken(method.moduleId, method.methodId); + + // GetFunctionIDFromToken doesn't handle generics, will return NULL + if (inlinerFuncId != mdTokenNil) + { + AddInlining(inlinerFuncId, functionId); + } + } + } return S_OK; } @@ -182,7 +224,7 @@ HRESULT STDMETHODCALLTYPE ReJITProfiler::ReJITCompilationStarted(FunctionID func HRESULT STDMETHODCALLTYPE ReJITProfiler::GetReJITParameters(ModuleID moduleId, mdMethodDef methodId, ICorProfilerFunctionControl* pFunctionControl) { - INFO(L"Starting to build IL for methodDef=" << std::hex << methodId); + INFO(L"Starting to build IL for method " << GetFunctionIDName(GetFunctionIDFromToken(moduleId, methodId))); COMPtrHolder pUnk; HRESULT hr = _profInfo10->GetModuleMetaData(moduleId, ofWrite, IID_IMetaDataEmit2, &pUnk); if (FAILED(hr)) @@ -287,6 +329,25 @@ void ReJITProfiler::AddInlining(FunctionID inliner, FunctionID inlinee) { inliners->insert(inliner); } + + String calleeName = GetFunctionIDName(inlinee); + String moduleName = GetModuleIDName(GetModuleIDForFunction(inlinee)); + INFO(L"Inlining occurred! Inliner=" << GetFunctionIDName(inliner) << L" Inlinee=" << calleeName << L" Inlinee module name=" << moduleName); +} + +FunctionID ReJITProfiler::GetFunctionIDFromToken(ModuleID module, mdMethodDef token) +{ + HRESULT hr = S_OK; + FunctionID functionId; + if (FAILED(hr = pCorProfilerInfo->GetFunctionFromToken(module, + token, + &functionId))) + { + printf("Call to GetFunctionFromToken failed with hr=0x%x\n", hr); + return mdTokenNil; + } + + return functionId; } mdMethodDef ReJITProfiler::GetMethodDefForFunction(FunctionID functionId) diff --git a/src/coreclr/tests/src/profiler/native/rejitprofiler/rejitprofiler.h b/src/coreclr/tests/src/profiler/native/rejitprofiler/rejitprofiler.h index b26a690c63bb2d..08e657499cf319 100644 --- a/src/coreclr/tests/src/profiler/native/rejitprofiler/rejitprofiler.h +++ b/src/coreclr/tests/src/profiler/native/rejitprofiler/rejitprofiler.h @@ -37,6 +37,7 @@ class ReJITProfiler : public Profiler virtual HRESULT STDMETHODCALLTYPE JITCompilationStarted(FunctionID functionId, BOOL fIsSafeToBlock); virtual HRESULT STDMETHODCALLTYPE JITCompilationFinished(FunctionID functionId, HRESULT hrStatus, BOOL fIsSafeToBlock); virtual HRESULT STDMETHODCALLTYPE JITInlining(FunctionID callerId, FunctionID calleeId, BOOL* pfShouldInline); + virtual HRESULT STDMETHODCALLTYPE JITCachedFunctionSearchFinished(FunctionID functionId, COR_PRF_JIT_CACHE result); virtual HRESULT STDMETHODCALLTYPE ReJITCompilationStarted(FunctionID functionId, ReJITID rejitId, BOOL fIsSafeToBlock); virtual HRESULT STDMETHODCALLTYPE GetReJITParameters(ModuleID moduleId, mdMethodDef methodId, ICorProfilerFunctionControl* pFunctionControl); @@ -46,6 +47,9 @@ class ReJITProfiler : public Profiler private: void AddInlining(FunctionID inliner, FunctionID inlinee); + HRESULT FunctionSeen(FunctionID func); + + FunctionID GetFunctionIDFromToken(ModuleID module, mdMethodDef token); mdMethodDef GetMethodDefForFunction(FunctionID functionId); ModuleID GetModuleIDForFunction(FunctionID functionId); bool EndsWith(const String &lhs, const String &rhs); diff --git a/src/coreclr/tests/src/profiler/rejit/rejit.cs b/src/coreclr/tests/src/profiler/rejit/rejit.cs index da7ff60f9f7316..ec5cddc1bf9f06 100644 --- a/src/coreclr/tests/src/profiler/rejit/rejit.cs +++ b/src/coreclr/tests/src/profiler/rejit/rejit.cs @@ -100,7 +100,7 @@ public static int Main(string[] args) return ProfilerTestRunner.Run(profileePath: System.Reflection.Assembly.GetExecutingAssembly().Location, testName: "ReJITWithInlining", profilerClsid: ReJitProfilerGuid, - profileeOptions: ProfileeOptions.DisableTieredCompilation); + profileeOptions: ProfileeOptions.OptimizationSensitive); } } } diff --git a/src/coreclr/tests/src/profiler/rejit/rejit.csproj b/src/coreclr/tests/src/profiler/rejit/rejit.csproj index 7a525ce745d28c..7ea4cfaea5be58 100644 --- a/src/coreclr/tests/src/profiler/rejit/rejit.csproj +++ b/src/coreclr/tests/src/profiler/rejit/rejit.csproj @@ -6,6 +6,7 @@ true 0 true + True diff --git a/src/coreclr/tests/src/readytorun/coreroot_determinism/Program.cs b/src/coreclr/tests/src/readytorun/coreroot_determinism/Program.cs index 4f9706be3c686b..2492c145c6a7a8 100644 --- a/src/coreclr/tests/src/readytorun/coreroot_determinism/Program.cs +++ b/src/coreclr/tests/src/readytorun/coreroot_determinism/Program.cs @@ -84,7 +84,7 @@ private static void CopyDeterminismTestAssembly(string coreRootFolder, string co public static bool CompileWithSeed(int seed, string coreRootPath, string compilationInputFolder, string outDir) { - string superIlcPath = Path.Combine(coreRootPath, "ReadyToRun.SuperIlc", "ReadyToRun.SuperIlc.dll"); + string superIlcPath = Path.Combine(coreRootPath, "R2RTest", "R2RTest.dll"); string coreRunPath = Path.Combine(coreRootPath, OSExeSuffix("corerun")); Console.WriteLine($"================================== Compiling with seed {seed} =================================="); diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/a/a.cs b/src/coreclr/tests/src/readytorun/crossboundarylayout/a/a.cs new file mode 100644 index 00000000000000..271a8f6e15ee21 --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/a/a.cs @@ -0,0 +1,87 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading; + +namespace CrossBoundaryLayout +{ + public class A + { + public byte _aVal; + } + + public class AGeneric + { + public T _aVal; + } + + public class ABoringGeneric + { + public byte _aVal; + } + + public class ATest + { + public static volatile object s_testFailObj; + public static void ReportTestFailure(string test, object o, ref int failCount) + { + Console.WriteLine(test); + s_testFailObj = o; + failCount++; + } + + public static int Test() + { + int failure = 0; + { + var a = (A)Activator.CreateInstance(typeof(A)); + a._aVal = 1; + if (1 != (byte)typeof(A).GetField("_aVal").GetValue(a)) + { + ATest.ReportTestFailure("A a._aVal", a, ref failure); + } + } + + { + var a2 = (AGeneric)Activator.CreateInstance(typeof(AGeneric)); + a2._aVal = 1; + if (1 != (byte)typeof(AGeneric).GetField("_aVal").GetValue(a2)) + { + failure++; + ATest.ReportTestFailure("A a2_aVal", a2, ref failure); + } + } + + { + var a3 = (AGeneric)Activator.CreateInstance(typeof(AGeneric)); + a3._aVal._dVal = 1; + if (1 != ((ByteStruct)typeof(AGeneric).GetField("_aVal").GetValue(a3))._dVal) + { + ATest.ReportTestFailure("A a3_aVal", a3, ref failure); + } + } + + { + var a4 = (ABoringGeneric)Activator.CreateInstance(typeof(ABoringGeneric)); + a4._aVal = 1; + if (1 != (byte)typeof(ABoringGeneric).GetField("_aVal").GetValue(a4)) + { + ATest.ReportTestFailure("A a4_aVal", a4, ref failure); + } + } + + { + var a5 = (ABoringGeneric)Activator.CreateInstance(typeof(ABoringGeneric)); + a5._aVal = 1; + if (1 != (byte)typeof(ABoringGeneric).GetField("_aVal").GetValue(a5)) + { + ATest.ReportTestFailure("A a5_aVal", a5, ref failure); + } + } + + return failure; + } + } +} \ No newline at end of file diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/a/a.csproj b/src/coreclr/tests/src/readytorun/crossboundarylayout/a/a.csproj new file mode 100644 index 00000000000000..6e3c26249fc0e7 --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/a/a.csproj @@ -0,0 +1,14 @@ + + + library + SharedLibrary + + + + + + + + + + diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/b/b.cs b/src/coreclr/tests/src/readytorun/crossboundarylayout/b/b.cs new file mode 100644 index 00000000000000..6a7187c1f43ad1 --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/b/b.cs @@ -0,0 +1,273 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace CrossBoundaryLayout +{ + public struct ByteStructB + { + public byte _bsVal; + } + + public class B_A : A + { + public byte _bVal; + } + + public class B_A_byte : AGeneric + { + public byte _bVal; + } + + public class B_A_D : AGeneric + { + public byte _bVal; + } + + public class B_A_BS : AGeneric + { + public byte _bVal; + } + + public class B_A_E : AGeneric + { + public byte _bVal; + } + + public class B_A_Generic : A + { + public T _bVal; + } + + public class B_A_byte_Generic : AGeneric + { + public T _bVal; + } + + public class B_A_D_Generic : AGeneric + { + public T _bVal; + } + + public class B_A_BS_Generic : AGeneric + { + public T _bVal; + } + + public class B_A_E_Generic : AGeneric + { + public T _bVal; + } + + public class B_ABoring_byte : ABoringGeneric + { + public byte _bVal; + } + + public class B_ABoring_D : ABoringGeneric + { + public byte _bVal; + } + + public class B_ABoring_BS : ABoringGeneric + { + public byte _bVal; + } + + public class B_ABoring_E : ABoringGeneric + { + public byte _bVal; + } + + public class BTest + { + public static int Test() + { + int failure = 0; + { + var a = (A)Activator.CreateInstance(typeof(A)); + a._aVal = 1; + if (1 != (byte)typeof(A).GetField("_aVal").GetValue(a)) + { + ATest.ReportTestFailure("B a_aVal", a, ref failure); + } + } + + { + var a2 = (AGeneric)Activator.CreateInstance(typeof(AGeneric)); + a2._aVal = 1; + if (1 != (byte)typeof(AGeneric).GetField("_aVal").GetValue(a2)) + { + ATest.ReportTestFailure("B a2_aVal", a2, ref failure); + } + } + + { + var a3 = (AGeneric)Activator.CreateInstance(typeof(AGeneric)); + a3._aVal._dVal = 1; + if (1 != ((ByteStruct)typeof(AGeneric).GetField("_aVal").GetValue(a3))._dVal) + { + ATest.ReportTestFailure("B a3_aVal", a3, ref failure); + } + } + + { + var a4 = (ABoringGeneric)Activator.CreateInstance(typeof(ABoringGeneric)); + a4._aVal = 1; + if (1 != (byte)typeof(ABoringGeneric).GetField("_aVal").GetValue(a4)) + { + ATest.ReportTestFailure("B a4_aVal", a4, ref failure); + } + } + + { + var a5 = (ABoringGeneric)Activator.CreateInstance(typeof(ABoringGeneric)); + a5._aVal = 1; + if (1 != (byte)typeof(ABoringGeneric).GetField("_aVal").GetValue(a5)) + { + ATest.ReportTestFailure("B a5_aVal", a5, ref failure); + } + } + + + { + var b = (B_A)Activator.CreateInstance(typeof(B_A)); + b._bVal = 1; + if (1 != (byte)typeof(B_A).GetField("_bVal").GetValue(b)) + { + ATest.ReportTestFailure("B b_bVal", b, ref failure); + } + } + + { + var b2 = (B_A_byte)Activator.CreateInstance(typeof(B_A_byte)); + b2._bVal = 1; + if (1 != (byte)typeof(B_A_byte).GetField("_bVal").GetValue(b2)) + { + ATest.ReportTestFailure("B b2_bVal", b2, ref failure); + } + } + + { + var b3 = (B_A_D)Activator.CreateInstance(typeof(B_A_D)); + b3._bVal = 1; + if (1 != (byte)typeof(B_A_D).GetField("_bVal").GetValue(b3)) + { + ATest.ReportTestFailure("B b3_bVal", b3, ref failure); + } + } + + { + var b4 = (B_A_Generic)Activator.CreateInstance(typeof(B_A_Generic)); + b4._bVal = 1; + if (1 != (byte)typeof(B_A_Generic).GetField("_bVal").GetValue(b4)) + { + ATest.ReportTestFailure("B b4_bVal", b4, ref failure); + } + } + + { + var b5 = (B_A_byte_Generic)Activator.CreateInstance(typeof(B_A_byte_Generic)); + b5._bVal = 1; + if (1 != (byte)typeof(B_A_byte_Generic).GetField("_bVal").GetValue(b5)) + { + ATest.ReportTestFailure("B b5_bVal", b5, ref failure); + } + } + + { + var b6 = (B_A_D_Generic)Activator.CreateInstance(typeof(B_A_D_Generic)); + b6._bVal = 1; + if (1 != (byte)typeof(B_A_D_Generic).GetField("_bVal").GetValue(b6)) + { + ATest.ReportTestFailure("B b6_bVal", b6, ref failure); + } + } + + { + var b7 = (B_A_Generic)Activator.CreateInstance(typeof(B_A_Generic)); + b7._bVal._dVal = 1; + if (1 != ((ByteStruct)typeof(B_A_Generic).GetField("_bVal").GetValue(b7))._dVal) + { + ATest.ReportTestFailure("B b7_bVal", b7, ref failure); + } + } + + { + var b8 = (B_A_byte_Generic)Activator.CreateInstance(typeof(B_A_byte_Generic)); + b8._bVal._dVal = 1; + if (1 != ((ByteStruct)typeof(B_A_byte_Generic).GetField("_bVal").GetValue(b8))._dVal) + { + ATest.ReportTestFailure("B b8_bVal", b8, ref failure); + } + } + + { + var b9 = (B_A_D_Generic)Activator.CreateInstance(typeof(B_A_D_Generic)); + b9._bVal._dVal = 1; + if (1 != ((ByteStruct)typeof(B_A_D_Generic).GetField("_bVal").GetValue(b9))._dVal) + { + ATest.ReportTestFailure("B b9_bVal", b9, ref failure); + } + } + + { + var b10 = (B_ABoring_byte)Activator.CreateInstance(typeof(B_ABoring_byte)); + b10._bVal = 1; + if (1 != (byte)typeof(B_ABoring_byte).GetField("_bVal").GetValue(b10)) + { + ATest.ReportTestFailure("B b10_bVal", b10, ref failure); + } + } + + { + var b11 = (B_ABoring_D)Activator.CreateInstance(typeof(B_ABoring_D)); + b11._bVal = 1; + if (1 != (byte)typeof(B_ABoring_D).GetField("_bVal").GetValue(b11)) + { + ATest.ReportTestFailure("B b11_bVal", b11, ref failure); + } + } + + { + var b12 = (B_A_BS)Activator.CreateInstance(typeof(B_A_BS)); + b12._bVal = 1; + if (1 != (byte)typeof(B_A_BS).GetField("_bVal").GetValue(b12)) + { + ATest.ReportTestFailure("B b12_bVal", b12, ref failure); + } + } + + { + var b13 = (B_A_E)Activator.CreateInstance(typeof(B_A_E)); + b13._bVal = 1; + if (1 != (byte)typeof(B_A_E).GetField("_bVal").GetValue(b13)) + { + ATest.ReportTestFailure("B b12_bVal", b13, ref failure); + } + } + + { + var b14 = (B_ABoring_BS)Activator.CreateInstance(typeof(B_ABoring_BS)); + b14._bVal = 1; + if (1 != (byte)typeof(B_ABoring_BS).GetField("_bVal").GetValue(b14)) + { + ATest.ReportTestFailure("B b12_bVal", b14, ref failure); + } + } + + { + var b15 = (B_ABoring_E)Activator.CreateInstance(typeof(B_ABoring_E)); + b15._bVal = 1; + if (1 != (byte)typeof(B_ABoring_E).GetField("_bVal").GetValue(b15)) + { + ATest.ReportTestFailure("B b12_bVal", b15, ref failure); + } + } + + return failure; + } + } +} \ No newline at end of file diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/b/b.csproj b/src/coreclr/tests/src/readytorun/crossboundarylayout/b/b.csproj new file mode 100644 index 00000000000000..1eb8e6e923bcc7 --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/b/b.csproj @@ -0,0 +1,16 @@ + + + library + SharedLibrary + + + + + + + + + + + + diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/buildcrossgen2image.cmd b/src/coreclr/tests/src/readytorun/crossboundarylayout/buildcrossgen2image.cmd new file mode 100644 index 00000000000000..e75f4808a4d9e1 --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/buildcrossgen2image.cmd @@ -0,0 +1,95 @@ +setlocal +set COMPOSITENAME= +set COMPILEARG= +set TESTINITIALBINPATH=%2 +set TESTTARGET_DIR=%3 +set TESTBATCHROOT=%1 + + +:Loop +if "%4"=="" goto Continue + +set COMPILEARG=%COMPILEARG% %TESTINITIALBINPATH%\%4.dll +set COMPOSITENAME=%COMPOSITENAME%%4 + +if "%5"=="CG2Single" ( + call :CG2Single + shift +) ELSE ( + if "%5"=="CG2SingleInputBubble" ( + call :CG2SingleInputBubble + shift + ) ELSE ( + if "%5"=="CG1Single" ( + call :CG1Single + shift + ) ELSE ( + if "%5"=="CG2SingleBubbleADOnly" ( + call :CG2SingleBubbleADOnly + shift + ) ELSE ( + if "%5"=="CG2NoMethods" ( + call :CG2NoMethods + shift + ) ELSE ( + if "%5"=="CG2Composite" ( + shift + call :Continue + ) + ) + ) + ) + ) +) + +shift +goto Loop +:Continue + +if "%COMPOSITENAME%"=="" goto done + +set BUILDCMD=%TESTBATCHROOT%\..\..\..\..\..\..\.dotnet\dotnet %CORE_ROOT%\crossgen2\crossgen2.dll -r %CORE_ROOT%\* -r %TESTINITIALBINPATH%\*.dll -o %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%Composite.dll --composite %COMPILEARG% +echo %BUILDCMD% > %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%Composite.dll.log +call %BUILDCMD% >> %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%Composite.dll.log 2>&1 +if NOT EXIST %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%Composite.dll del %TESTINITIALBINPATH%\%TESTTARGET_DIR%\a.dll +goto done + +:CG2Single +del %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll +set BUILDCMD=%TESTBATCHROOT%\..\..\..\..\..\..\.dotnet\dotnet %CORE_ROOT%\crossgen2\crossgen2.dll -r %CORE_ROOT%\* -r %TESTINITIALBINPATH%\*.dll -o %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll %TESTINITIALBINPATH%\%COMPOSITENAME%.dll +echo %BUILDCMD% > %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll.log +call %BUILDCMD% >> %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll.log 2>&1 +goto done + +:CG2NoMethods +del %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll +set BUILDCMD=%TESTBATCHROOT%\..\..\..\..\..\..\.dotnet\dotnet %CORE_ROOT%\crossgen2\crossgen2.dll --compile-no-methods -r %CORE_ROOT%\* -r %TESTINITIALBINPATH%\*.dll -o %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll %TESTINITIALBINPATH%\%COMPOSITENAME%.dll +echo %BUILDCMD% > %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll.log +call %BUILDCMD% >> %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll.log 2>&1 +goto done + +:CG2SingleInputBubble +del %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll +set BUILDCMD=%TESTBATCHROOT%\..\..\..\..\..\..\.dotnet\dotnet %CORE_ROOT%\crossgen2\crossgen2.dll -r %CORE_ROOT%\* -r %TESTINITIALBINPATH%\*.dll -o %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll --inputbubble %TESTINITIALBINPATH%\%COMPOSITENAME%.dll +echo %BUILDCMD% > %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll.log +call %BUILDCMD% >> %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll.log 2>&1 +goto done + +:CG2SingleBubbleADOnly +del %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll +set BUILDCMD=%TESTBATCHROOT%\..\..\..\..\..\..\.dotnet\dotnet %CORE_ROOT%\crossgen2\crossgen2.dll -r %CORE_ROOT%\* -r %TESTINITIALBINPATH%\d.dll -o %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll --inputbubble %TESTINITIALBINPATH%\%COMPOSITENAME%.dll +echo %BUILDCMD% > %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll.log +call %BUILDCMD% >> %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll.log 2>&1 +goto done + +:CG1Single +del %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll +set BUILDCMD=%CORE_ROOT%\crossgen.exe /Platform_Assemblies_Paths %CORE_ROOT%;%TESTINITIALBINPATH% /out %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll /in %TESTINITIALBINPATH%\%COMPOSITENAME%.dll +echo %BUILDCMD% > %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll.log +call %BUILDCMD% >> %TESTINITIALBINPATH%\%TESTTARGET_DIR%\%COMPOSITENAME%.dll.log 2>&1 +goto done + +:done +shift +set COMPILEARG= +set COMPOSITENAME= diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytest/c.cs b/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytest/c.cs new file mode 100644 index 00000000000000..2e2bc2e42928bf --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytest/c.cs @@ -0,0 +1,289 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace CrossBoundaryLayout +{ + class C_B_A : B_A + { + public byte _cVal; + } + + class C_B_A_byte : B_A_byte + { + public byte _cVal; + } + + class C_B_A_D : B_A_D + { + public byte _cVal; + } + + class C_B_A_Generic_byte : B_A_Generic + { + public byte _cVal; + } + + class C_B_A_Generic_D : B_A_Generic + { + public byte _cVal; + } + + class C_B_A_byte_Generic_byte : B_A_byte_Generic + { + public byte _cVal; + } + + class C_B_A_byte_Generic_D : B_A_byte_Generic + { + public byte _cVal; + } + + class C_B_A_D_Generic_byte : B_A_D_Generic + { + public byte _cVal; + } + + class C_B_A_D_Generic_D : B_A_D_Generic + { + public byte _cVal; + } + + public class CTest + { + public static int Test() + { + int failure = 0; + + { + var a = (A)Activator.CreateInstance(typeof(A)); + a._aVal = 1; + if (1 != (byte)typeof(A).GetField("_aVal").GetValue(a)) + { + ATest.ReportTestFailure("C a_aVal", a, ref failure); + } + } + + { + var a2 = (AGeneric)Activator.CreateInstance(typeof(AGeneric)); + a2._aVal = 1; + if (1 != (byte)typeof(AGeneric).GetField("_aVal").GetValue(a2)) + { + ATest.ReportTestFailure("C a2_aVal", a2, ref failure); + } + } + + { + var a3 = (AGeneric)Activator.CreateInstance(typeof(AGeneric)); + a3._aVal._dVal = 1; + if (1 != ((ByteStruct)typeof(AGeneric).GetField("_aVal").GetValue(a3))._dVal) + { + ATest.ReportTestFailure("C a3_aVal", a3, ref failure); + } + } + + { + var a4 = (ABoringGeneric)Activator.CreateInstance(typeof(ABoringGeneric)); + a4._aVal = 1; + if (1 != (byte)typeof(ABoringGeneric).GetField("_aVal").GetValue(a4)) + { + ATest.ReportTestFailure("C a4_aVal", a4, ref failure); + } + } + + { + var a5 = (ABoringGeneric)Activator.CreateInstance(typeof(ABoringGeneric)); + a5._aVal = 1; + if (1 != (byte)typeof(ABoringGeneric).GetField("_aVal").GetValue(a5)) + { + ATest.ReportTestFailure("C a5_aVal", a5, ref failure); + } + } + + + { + var b = (B_A)Activator.CreateInstance(typeof(B_A)); + b._bVal = 1; + if (1 != (byte)typeof(B_A).GetField("_bVal").GetValue(b)) + { + ATest.ReportTestFailure("C b_bVal", b, ref failure); + } + } + + { + var b2 = (B_A_byte)Activator.CreateInstance(typeof(B_A_byte)); + b2._bVal = 1; + if (1 != (byte)typeof(B_A_byte).GetField("_bVal").GetValue(b2)) + { + ATest.ReportTestFailure("C b2_bVal", b2, ref failure); + } + } + + { + var b3 = (B_A_D)Activator.CreateInstance(typeof(B_A_D)); + b3._bVal = 1; + if (1 != (byte)typeof(B_A_D).GetField("_bVal").GetValue(b3)) + { + ATest.ReportTestFailure("C b3_bVal", b3, ref failure); + } + } + + { + var b4 = (B_A_Generic)Activator.CreateInstance(typeof(B_A_Generic)); + b4._bVal = 1; + if (1 != (byte)typeof(B_A_Generic).GetField("_bVal").GetValue(b4)) + { + ATest.ReportTestFailure("C b4_bVal", b4, ref failure); + } + } + + { + var b5 = (B_A_byte_Generic)Activator.CreateInstance(typeof(B_A_byte_Generic)); + b5._bVal = 1; + if (1 != (byte)typeof(B_A_byte_Generic).GetField("_bVal").GetValue(b5)) + { + ATest.ReportTestFailure("C b5_bVal", b5, ref failure); + } + } + + { + var b6 = (B_A_D_Generic)Activator.CreateInstance(typeof(B_A_D_Generic)); + b6._bVal = 1; + if (1 != (byte)typeof(B_A_D_Generic).GetField("_bVal").GetValue(b6)) + { + ATest.ReportTestFailure("C b6_bVal", b6, ref failure); + } + } + + { + var b7 = (B_A_Generic)Activator.CreateInstance(typeof(B_A_Generic)); + b7._bVal._dVal = 1; + if (1 != ((ByteStruct)typeof(B_A_Generic).GetField("_bVal").GetValue(b7))._dVal) + { + ATest.ReportTestFailure("C b7_bVal", b7, ref failure); + } + } + + { + var b8 = (B_A_byte_Generic)Activator.CreateInstance(typeof(B_A_byte_Generic)); + b8._bVal._dVal = 1; + if (1 != ((ByteStruct)typeof(B_A_byte_Generic).GetField("_bVal").GetValue(b8))._dVal) + { + ATest.ReportTestFailure("C b8_bVal", b8, ref failure); + } + } + + { + var b9 = (B_A_D_Generic)Activator.CreateInstance(typeof(B_A_D_Generic)); + b9._bVal._dVal = 1; + if (1 != ((ByteStruct)typeof(B_A_D_Generic).GetField("_bVal").GetValue(b9))._dVal) + { + ATest.ReportTestFailure("C b9_bVal", b9, ref failure); + } + } + + { + var b10 = (B_ABoring_byte)Activator.CreateInstance(typeof(B_ABoring_byte)); + b10._bVal = 1; + if (1 != (byte)typeof(B_ABoring_byte).GetField("_bVal").GetValue(b10)) + { + ATest.ReportTestFailure("C b10_bVal", b10, ref failure); + } + } + + { + var b11 = (B_ABoring_D)Activator.CreateInstance(typeof(B_ABoring_D)); + b11._bVal = 1; + if (1 != (byte)typeof(B_ABoring_D).GetField("_bVal").GetValue(b11)) + { + ATest.ReportTestFailure("C b11_bVal", b11, ref failure); + } + } + + { + var c = (C_B_A)Activator.CreateInstance(typeof(C_B_A)); + c._cVal = 1; + if (1 != (byte)typeof(C_B_A).GetField("_cVal").GetValue(c)) + { + ATest.ReportTestFailure("C c_bVal", c, ref failure); + } + } + + { + var c2 = (C_B_A_byte)Activator.CreateInstance(typeof(C_B_A_byte)); + c2._cVal = 1; + if (1 != (byte)typeof(C_B_A_byte).GetField("_cVal").GetValue(c2)) + { + ATest.ReportTestFailure("C c2_bVal", c2, ref failure); + } + } + + { + var c3 = (C_B_A_D)Activator.CreateInstance(typeof(C_B_A_D)); + c3._cVal = 1; + if (1 != (byte)typeof(C_B_A_D).GetField("_cVal").GetValue(c3)) + { + ATest.ReportTestFailure("C c3_bVal", c3, ref failure); + } + } + + { + var c4 = (C_B_A_Generic_byte)Activator.CreateInstance(typeof(C_B_A_Generic_byte)); + c4._cVal = 1; + if (1 != (byte)typeof(C_B_A_Generic_byte).GetField("_cVal").GetValue(c4)) + { + ATest.ReportTestFailure("C c4_bVal", c4, ref failure); + } + } + + { + var c5 = (C_B_A_byte_Generic_byte)Activator.CreateInstance(typeof(C_B_A_byte_Generic_byte)); + c5._cVal = 1; + if (1 != (byte)typeof(C_B_A_byte_Generic_byte).GetField("_cVal").GetValue(c5)) + { + ATest.ReportTestFailure("C c5_bVal", c5, ref failure); + } + } + + { + var c6 = (C_B_A_D_Generic_byte)Activator.CreateInstance(typeof(C_B_A_D_Generic_byte)); + c6._cVal = 1; + if (1 != (byte)typeof(C_B_A_D_Generic_byte).GetField("_cVal").GetValue(c6)) + { + ATest.ReportTestFailure("C c6_bVal", c6, ref failure); + } + } + + { + var c7 = (C_B_A_Generic_D)Activator.CreateInstance(typeof(C_B_A_Generic_D)); + c7._cVal = 1; + if (1 != (byte)typeof(C_B_A_Generic_D).GetField("_cVal").GetValue(c7)) + { + ATest.ReportTestFailure("C c7_bVal", c7, ref failure); + } + } + + { + var c8 = (C_B_A_byte_Generic_D)Activator.CreateInstance(typeof(C_B_A_byte_Generic_D)); + c8._cVal = 1; + if (1 != (byte)typeof(C_B_A_byte_Generic_D).GetField("_cVal").GetValue(c8)) + { + ATest.ReportTestFailure("C c8_bVal", c8, ref failure); + } + } + + { + var c9 = (C_B_A_D_Generic_D)Activator.CreateInstance(typeof(C_B_A_D_Generic_D)); + c9._cVal = 1; + if (1 != (byte)typeof(C_B_A_D_Generic_D).GetField("_cVal").GetValue(c9)) + { + ATest.ReportTestFailure("C c9_bVal", c9, ref failure); + } + } + + return failure; + } + } +} \ No newline at end of file diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytest/c1.cs b/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytest/c1.cs new file mode 100644 index 00000000000000..859a20aa5a68d0 --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytest/c1.cs @@ -0,0 +1,378 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace CrossBoundaryLayout +{ + public class A1BoringGeneric + { + public byte _aVal; + } + + public class B1_A : A + { + public byte _bVal; + } + + public class B1_A_byte : AGeneric + { + public byte _bVal; + } + + public class B1_A_D : AGeneric + { + public byte _bVal; + } + + public class B1_A_Generic : A + { + public T _bVal; + } + + public class B1_A_byte_Generic : AGeneric + { + public T _bVal; + } + + public class B1_A_D_Generic : AGeneric + { + public T _bVal; + } + + public class B1_ABoring_byte : ABoringGeneric + { + public byte _bVal; + } + + public class B1_ABoring_D : ABoringGeneric + { + public byte _bVal; + } + + public class B1_A1Boring_byte : A1BoringGeneric + { + public byte _bVal; + } + + public class B1_A1Boring_D : A1BoringGeneric + { + public byte _bVal; + } + + class C1_B_A : B1_A + { + public byte _cVal; + } + + class C1_B_A_byte : B1_A_byte + { + public byte _cVal; + } + + class C1_B_A_D : B1_A_D + { + public byte _cVal; + } + + class C1_B_A_Generic_byte : B1_A_Generic + { + public byte _cVal; + } + + class C1_B_A_Generic_D : B1_A_Generic + { + public byte _cVal; + } + + class C1_B_A_byte_Generic_byte : B1_A_byte_Generic + { + public byte _cVal; + } + + class C1_B_A_byte_Generic_D : B1_A_byte_Generic + { + public byte _cVal; + } + + class C1_B_A_D_Generic_byte : B1_A_D_Generic + { + public byte _cVal; + } + + class C1_B_A_D_Generic_D : B1_A_D_Generic + { + public byte _cVal; + } + + public class C1Test + { + public static int Test() + { + int failure = 0; + { + var a = (A)Activator.CreateInstance(typeof(A)); + a._aVal = 1; + if (1 != (byte)typeof(A).GetField("_aVal").GetValue(a)) + { + ATest.ReportTestFailure("C1 a_aVal", a, ref failure); + } + } + + { + var a2 = (AGeneric)Activator.CreateInstance(typeof(AGeneric)); + a2._aVal = 1; + if (1 != (byte)typeof(AGeneric).GetField("_aVal").GetValue(a2)) + { + ATest.ReportTestFailure("C1 a2_aVal", a2, ref failure); + } + } + + { + var a3 = (AGeneric)Activator.CreateInstance(typeof(AGeneric)); + a3._aVal._dVal = 1; + if (1 != ((ByteStruct)typeof(AGeneric).GetField("_aVal").GetValue(a3))._dVal) + { + ATest.ReportTestFailure("C1 a3_aVal", a3, ref failure); + } + } + + { + var a4 = (ABoringGeneric)Activator.CreateInstance(typeof(ABoringGeneric)); + a4._aVal = 1; + if (1 != (byte)typeof(ABoringGeneric).GetField("_aVal").GetValue(a4)) + { + ATest.ReportTestFailure("C1 a4_aVal", a4, ref failure); + } + } + + { + var a5 = (ABoringGeneric)Activator.CreateInstance(typeof(ABoringGeneric)); + a5._aVal = 1; + if (1 != (byte)typeof(ABoringGeneric).GetField("_aVal").GetValue(a5)) + { + ATest.ReportTestFailure("C1 a5_aVal", a5, ref failure); + } + } + + { + var a6 = (A1BoringGeneric)Activator.CreateInstance(typeof(A1BoringGeneric)); + a6._aVal = 1; + if (1 != (byte)typeof(A1BoringGeneric).GetField("_aVal").GetValue(a6)) + { + ATest.ReportTestFailure("C1 a6_aVal", a6, ref failure); + } + } + + { + var a7 = (A1BoringGeneric)Activator.CreateInstance(typeof(A1BoringGeneric)); + a7._aVal = 1; + if (1 != (byte)typeof(A1BoringGeneric).GetField("_aVal").GetValue(a7)) + { + ATest.ReportTestFailure("C1 a7_aVal", a7, ref failure); + } + } + + { + var b = (B1_A)Activator.CreateInstance(typeof(B1_A)); + b._bVal = 1; + if (1 != (byte)typeof(B1_A).GetField("_bVal").GetValue(b)) + { + ATest.ReportTestFailure("C1 b_bVal", b, ref failure); + } + } + + { + var b2 = (B1_A_byte)Activator.CreateInstance(typeof(B1_A_byte)); + b2._bVal = 1; + if (1 != (byte)typeof(B1_A_byte).GetField("_bVal").GetValue(b2)) + { + ATest.ReportTestFailure("C1 b2_bVal", b2, ref failure); + } + } + + { + var b3 = (B1_A_D)Activator.CreateInstance(typeof(B1_A_D)); + b3._bVal = 1; + if (1 != (byte)typeof(B1_A_D).GetField("_bVal").GetValue(b3)) + { + ATest.ReportTestFailure("C1 b3_bVal", b3, ref failure); + } + } + + { + var b4 = (B1_A_Generic)Activator.CreateInstance(typeof(B1_A_Generic)); + b4._bVal = 1; + if (1 != (byte)typeof(B1_A_Generic).GetField("_bVal").GetValue(b4)) + { + ATest.ReportTestFailure("C1 b4_bVal", b4, ref failure); + } + } + + { + var b5 = (B1_A_byte_Generic)Activator.CreateInstance(typeof(B1_A_byte_Generic)); + b5._bVal = 1; + if (1 != (byte)typeof(B1_A_byte_Generic).GetField("_bVal").GetValue(b5)) + { + ATest.ReportTestFailure("C1 b5_bVal", b5, ref failure); + } + } + + { + var b6 = (B1_A_D_Generic)Activator.CreateInstance(typeof(B1_A_D_Generic)); + b6._bVal = 1; + if (1 != (byte)typeof(B1_A_D_Generic).GetField("_bVal").GetValue(b6)) + { + ATest.ReportTestFailure("C1 b6_bVal", b6, ref failure); + } + } + + { + var b7 = (B1_A_Generic)Activator.CreateInstance(typeof(B1_A_Generic)); + b7._bVal._dVal = 1; + if (1 != ((ByteStruct)typeof(B1_A_Generic).GetField("_bVal").GetValue(b7))._dVal) + { + ATest.ReportTestFailure("C1 b7_bVal", b7, ref failure); + } + } + + { + var b8 = (B1_A_byte_Generic)Activator.CreateInstance(typeof(B1_A_byte_Generic)); + b8._bVal._dVal = 1; + if (1 != ((ByteStruct)typeof(B1_A_byte_Generic).GetField("_bVal").GetValue(b8))._dVal) + { + ATest.ReportTestFailure("C1 b8_bVal", b8, ref failure); + } + } + + { + var b9 = (B1_A_D_Generic)Activator.CreateInstance(typeof(B1_A_D_Generic)); + b9._bVal._dVal = 1; + if (1 != ((ByteStruct)typeof(B1_A_D_Generic).GetField("_bVal").GetValue(b9))._dVal) + { + ATest.ReportTestFailure("C1 b9_bVal", b9, ref failure); + } + } + + { + var b10 = (B1_ABoring_byte)Activator.CreateInstance(typeof(B1_ABoring_byte)); + b10._bVal = 1; + if (1 != (byte)typeof(B1_ABoring_byte).GetField("_bVal").GetValue(b10)) + { + ATest.ReportTestFailure("C1 b10_bVal", b10, ref failure); + } + } + + { + var b11 = (B1_ABoring_D)Activator.CreateInstance(typeof(B1_ABoring_D)); + b11._bVal = 1; + if (1 != (byte)typeof(B1_ABoring_D).GetField("_bVal").GetValue(b11)) + { + ATest.ReportTestFailure("C1 b11_bVal", b11, ref failure); + } + } + + { + var b12 = (B1_A1Boring_byte)Activator.CreateInstance(typeof(B1_A1Boring_byte)); + b12._bVal = 1; + if (1 != (byte)typeof(B1_A1Boring_byte).GetField("_bVal").GetValue(b12)) + { + ATest.ReportTestFailure("C1 b12_bVal", b12, ref failure); + } + } + + { + var b13 = (B1_A1Boring_D)Activator.CreateInstance(typeof(B1_A1Boring_D)); + b13._bVal = 1; + if (1 != (byte)typeof(B1_A1Boring_D).GetField("_bVal").GetValue(b13)) + { + ATest.ReportTestFailure("C1 b13_bVal", b13, ref failure); + } + } + + { + var c = (C1_B_A)Activator.CreateInstance(typeof(C1_B_A)); + c._cVal = 1; + if (1 != (byte)typeof(C1_B_A).GetField("_cVal").GetValue(c)) + { + ATest.ReportTestFailure("C1 c_bVal", c, ref failure); + } + } + + { + var c2 = (C1_B_A_byte)Activator.CreateInstance(typeof(C1_B_A_byte)); + c2._cVal = 1; + if (1 != (byte)typeof(C1_B_A_byte).GetField("_cVal").GetValue(c2)) + { + ATest.ReportTestFailure("C1 c2_bVal", c2, ref failure); + } + } + + { + var c3 = (C1_B_A_D)Activator.CreateInstance(typeof(C1_B_A_D)); + c3._cVal = 1; + if (1 != (byte)typeof(C1_B_A_D).GetField("_cVal").GetValue(c3)) + { + ATest.ReportTestFailure("C1 c3_bVal", c3, ref failure); + } + } + + { + var c4 = (C1_B_A_Generic_byte)Activator.CreateInstance(typeof(C1_B_A_Generic_byte)); + c4._cVal = 1; + if (1 != (byte)typeof(C1_B_A_Generic_byte).GetField("_cVal").GetValue(c4)) + { + ATest.ReportTestFailure("C1 c4_bVal", c4, ref failure); + } + } + + { + var c5 = (C1_B_A_byte_Generic_byte)Activator.CreateInstance(typeof(C1_B_A_byte_Generic_byte)); + c5._cVal = 1; + if (1 != (byte)typeof(C1_B_A_byte_Generic_byte).GetField("_cVal").GetValue(c5)) + { + ATest.ReportTestFailure("C1 c5_bVal", c5, ref failure); + } + } + + { + var c6 = (C1_B_A_D_Generic_byte)Activator.CreateInstance(typeof(C1_B_A_D_Generic_byte)); + c6._cVal = 1; + if (1 != (byte)typeof(C1_B_A_D_Generic_byte).GetField("_cVal").GetValue(c6)) + { + ATest.ReportTestFailure("C1 c6_bVal", c6, ref failure); + } + } + + { + var c7 = (C1_B_A_Generic_D)Activator.CreateInstance(typeof(C1_B_A_Generic_D)); + c7._cVal = 1; + if (1 != (byte)typeof(C1_B_A_Generic_D).GetField("_cVal").GetValue(c7)) + { + ATest.ReportTestFailure("C1 c7_bVal", c7, ref failure); + } + } + + { + var c8 = (C1_B_A_byte_Generic_D)Activator.CreateInstance(typeof(C1_B_A_byte_Generic_D)); + c8._cVal = 1; + if (1 != (byte)typeof(C1_B_A_byte_Generic_D).GetField("_cVal").GetValue(c8)) + { + ATest.ReportTestFailure("C1 c8_bVal", c8, ref failure); + } + } + + { + var c9 = (C1_B_A_D_Generic_D)Activator.CreateInstance(typeof(C1_B_A_D_Generic_D)); + c9._cVal = 1; + if (1 != (byte)typeof(C1_B_A_D_Generic_D).GetField("_cVal").GetValue(c9)) + { + ATest.ReportTestFailure("C1 c9_bVal", c9, ref failure); + } + } + + return failure; + } + } +} \ No newline at end of file diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytest/crossboundarytest.csproj b/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytest/crossboundarytest.csproj new file mode 100644 index 00000000000000..a1eb9a74a4a525 --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytest/crossboundarytest.csproj @@ -0,0 +1,19 @@ + + + exe + 1 + BuildAndRun + + + + + + + + + + + + + + diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytest/main.cs b/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytest/main.cs new file mode 100644 index 00000000000000..8b757a7bfa20d8 --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytest/main.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace CrossBoundaryLayout +{ + class Program + { + public static int Main(string[] args) + { + int failure = ATest.Test(); + failure += BTest.Test(); + failure += CTest.Test(); + failure += C1Test.Test(); + + return 100 + failure; + } + } +} \ No newline at end of file diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytests.cmd b/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytests.cmd new file mode 100644 index 00000000000000..f634952a02a7f3 --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/crossboundarytests.cmd @@ -0,0 +1,322 @@ +echo off +setlocal +set TESTDIR=%~dp0\..\..\..\..\..\..\artifacts\tests\coreclr\Windows_NT.x64.Debug\readytorun\crossboundarylayout\crossboundarytest\crossboundarytest +set TESTBATCHROOT=%~dp0 + +call :testSpecificCompositeScenarios +call :testAllCombinationsOfCompositeAndR2R +call :testCG2SingleInputBubbleCompiledWithoutReferenceToBCE +call :testCG2SingleMixedInputBubble +call :testCG2SingleInputBubbleAll +call :testCG2All +call :testCG1All + +goto done + +:testSpecificCompositeScenarios +echo Test some of the interesting composite scenarios first + +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B2C2D2E1 a e CG2Composite b crossboundarytest d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% all a b crossboundarytest d +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% ad a d +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% abd a b d +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% a_crossboundarytest_d a crossboundarytest d +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% a_b_crossboundarytest a b crossboundarytest + +goto done + +:testAllCombinationsOfCompositeAndR2R +echo testing all possible combinations of 1 regular R2R image mixed with the rest of the files being in a single composite image or alone +echo Also test all possible arrangements of 2 composite images +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B1C0D0E0 a b CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B0C1D0E0 a crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B1C1D0E0 b crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B1C1D0E0 a b crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B1C1D0E0 b crossboundarytest CG2Composite a CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B2C1D0E0 a crossboundarytest CG2Composite b CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B2C1D0E0 crossboundarytest CG2Single a b CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B0C0D1E0 a d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B1C0D1E0 b d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B1C0D1E0 a b d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B1C0D1E0 b d CG2Composite a CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B2C0D1E0 a d CG2Composite b CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B2C0D1E0 d CG2Single a b CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B0C1D1E0 crossboundarytest d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B0C1D1E0 a crossboundarytest d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B0C1D1E0 crossboundarytest d CG2Composite a CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B1C1D1E0 b crossboundarytest d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B1C1D1E0 a b crossboundarytest d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B1C1D1E0 b crossboundarytest d CG2Composite a CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B2C1D1E0 crossboundarytest d CG2Composite b CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B2C1D1E0 a crossboundarytest d CG2Composite b CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B2C1D1E0 crossboundarytest d CG2Composite a b CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B0C2D1E0 a d CG2Composite crossboundarytest CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B0C2D1E0 d CG2Single a crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B1C2D1E0 b d CG2Composite crossboundarytest CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B1C2D1E0 a b d CG2Composite crossboundarytest CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B1C2D1E0 b d CG2Composite a crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B2C2D1E0 d CG2Single b crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B2C2D1E0 a d CG2Composite b crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B2C2D1E0 d CG2Single a b crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B0C0D0E1 a e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B1C0D0E1 b e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B1C0D0E1 a b e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B1C0D0E1 b e CG2Composite a CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B2C0D0E1 a e CG2Composite b CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B2C0D0E1 e CG2Single a b CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B0C1D0E1 crossboundarytest e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B0C1D0E1 a crossboundarytest e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B0C1D0E1 crossboundarytest e CG2Composite a CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B1C1D0E1 b crossboundarytest e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B1C1D0E1 a b crossboundarytest e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B1C1D0E1 b crossboundarytest e CG2Composite a CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B2C1D0E1 crossboundarytest e CG2Composite b CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B2C1D0E1 a crossboundarytest e CG2Composite b CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B2C1D0E1 crossboundarytest e CG2Composite a b CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B0C2D0E1 a e CG2Composite crossboundarytest CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B0C2D0E1 e CG2Single a crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B1C2D0E1 b e CG2Composite crossboundarytest CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B1C2D0E1 a b e CG2Composite crossboundarytest CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B1C2D0E1 b e CG2Composite a crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B2C2D0E1 e CG2Single b crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B2C2D0E1 a e CG2Composite b crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B2C2D0E1 e CG2Single a b crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B0C0D1E1 d e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B0C0D1E1 a d e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B0C0D1E1 d e CG2Composite a CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B1C0D1E1 b d e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B1C0D1E1 a b d e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B1C0D1E1 b d e CG2Composite a CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B2C0D1E1 d e CG2Composite b CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B2C0D1E1 a d e CG2Composite b CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B2C0D1E1 d e CG2Composite a b CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B0C1D1E1 crossboundarytest d e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B0C1D1E1 a crossboundarytest d e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B0C1D1E1 crossboundarytest d e CG2Composite a CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B1C1D1E1 b crossboundarytest d e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B1C1D1E1 a b crossboundarytest d e CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B1C1D1E1 b crossboundarytest d e CG2Composite a CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B2C1D1E1 crossboundarytest d e CG2Composite b CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B2C1D1E1 a crossboundarytest d e CG2Composite b CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B2C1D1E1 crossboundarytest d e CG2Composite a b CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B0C2D1E1 d e CG2Composite crossboundarytest CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B0C2D1E1 a d e CG2Composite crossboundarytest CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B0C2D1E1 d e CG2Composite a crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B1C2D1E1 b d e CG2Composite crossboundarytest CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B1C2D1E1 a b d e CG2Composite crossboundarytest CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B1C2D1E1 b d e CG2Composite a crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B2C2D1E1 d e CG2Composite b crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B2C2D1E1 a d e CG2Composite b crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B2C2D1E1 d e CG2Composite a b crossboundarytest CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B0C0D2E1 a e CG2Composite d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B0C0D2E1 e CG2Single a d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B1C0D2E1 b e CG2Composite d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B1C0D2E1 a b e CG2Composite d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B1C0D2E1 b e CG2Composite a d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B2C0D2E1 e CG2Single b d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B2C0D2E1 a e CG2Composite b d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B2C0D2E1 e CG2Single a b d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B0C1D2E1 crossboundarytest e CG2Composite d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B0C1D2E1 a crossboundarytest e CG2Composite d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B0C1D2E1 crossboundarytest e CG2Composite a d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B1C1D2E1 b crossboundarytest e CG2Composite d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B1C1D2E1 a b crossboundarytest e CG2Composite d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B1C1D2E1 b crossboundarytest e CG2Composite a d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B2C1D2E1 crossboundarytest e CG2Composite b d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B2C1D2E1 a crossboundarytest e CG2Composite b d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B2C1D2E1 crossboundarytest e CG2Composite a b d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B0C2D2E1 e CG2Single crossboundarytest d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B0C2D2E1 a e CG2Composite crossboundarytest d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B0C2D2E1 e CG2Single a crossboundarytest d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B1C2D2E1 b e CG2Composite crossboundarytest d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B1C2D2E1 a b e CG2Composite crossboundarytest d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B1C2D2E1 b e CG2Composite a crossboundarytest d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA0B2C2D2E1 e CG2Single b crossboundarytest d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA1B2C2D2E1 a e CG2Composite b crossboundarytest d CG2Composite +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% compositeA2B2C2D2E1 e CG2Single a b crossboundarytest d CG2Composite + +goto done + +:testCG2SingleInputBubbleAll + +echo TEST All combinations of the 5 dlls compiled with Crossgen2 with input bubble enabled and all assemblies passed as reference inputs to crossgen2 +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_A____ a CG2SingleInputBubble d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble__B___ b CG2SingleInputBubble a CG2NoMethods d CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_AB___ a CG2SingleInputBubble b CG2SingleInputBubble d CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble___C__ crossboundarytest CG2SingleInputBubble a CG2NoMethods d CG2NoMethods b CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_A_C__ a CG2SingleInputBubble crossboundarytest CG2SingleInputBubble d CG2NoMethods b CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble__BC__ b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble a CG2NoMethods d CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_ABC__ a CG2SingleInputBubble b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble____D_ d CG2SingleInputBubble +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_A__D_ a CG2SingleInputBubble d CG2SingleInputBubble +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble__B_D_ b CG2SingleInputBubble d CG2SingleInputBubble a CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_AB_D_ a CG2SingleInputBubble b CG2SingleInputBubble d CG2SingleInputBubble e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble___CD_ crossboundarytest CG2SingleInputBubble d CG2SingleInputBubble a CG2NoMethods b CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_A_CD_ a CG2SingleInputBubble crossboundarytest CG2SingleInputBubble d CG2SingleInputBubble b CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble__BCD_ b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble d CG2SingleInputBubble a CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_ABCD_ a CG2SingleInputBubble b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble d CG2SingleInputBubble e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_____E e CG2SingleInputBubble +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_A___E a CG2SingleInputBubble e CG2SingleInputBubble d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble__B__E b CG2SingleInputBubble e CG2SingleInputBubble a CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_AB__E a CG2SingleInputBubble b CG2SingleInputBubble e CG2SingleInputBubble d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble___C_E crossboundarytest CG2SingleInputBubble e CG2SingleInputBubble a CG2NoMethods b CG2NoMethods d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_A_C_E a CG2SingleInputBubble crossboundarytest CG2SingleInputBubble e CG2SingleInputBubble d CG2NoMethods b CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble__BC_E b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble e CG2SingleInputBubble a CG2NoMethods d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_ABC_E a CG2SingleInputBubble b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble e CG2SingleInputBubble d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble____DE d CG2SingleInputBubble e CG2SingleInputBubble +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_A__DE a CG2SingleInputBubble d CG2SingleInputBubble e CG2SingleInputBubble +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble__B_DE b CG2SingleInputBubble d CG2SingleInputBubble e CG2SingleInputBubble a CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_AB_DE a CG2SingleInputBubble b CG2SingleInputBubble d CG2SingleInputBubble e CG2SingleInputBubble +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble___CDE crossboundarytest CG2SingleInputBubble d CG2SingleInputBubble e CG2SingleInputBubble a CG2NoMethods b CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_A_CDE a CG2SingleInputBubble crossboundarytest CG2SingleInputBubble d CG2SingleInputBubble e CG2SingleInputBubble b CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble__BCDE b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble d CG2SingleInputBubble e CG2SingleInputBubble a CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble_ABCDE a CG2SingleInputBubble b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble d CG2SingleInputBubble e CG2SingleInputBubble + +goto done + +:testCG2SingleInputBubbleCompiledWithoutReferenceToBCE +echo TEST All combinations of the 5 dlls compiled with Crossgen2 with input bubble enabled and all assemblies passed as +echo reference inputs to crossgen2 when compiled b, crossboundarytest and e. a, and d are compiled with the reference +echo set limited to a and d. This simulates a the model of two different sets of input bubble matched assemblies where there is a +echo root set such as the runtime repo worth of libraries, and a seperately compiled application set. + +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_A____ a CG2SingleBubbleADOnly d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2__B___ b CG2SingleInputBubble a CG2NoMethods d CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_AB___ a CG2SingleBubbleADOnly b CG2SingleInputBubble d CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2___C__ crossboundarytest CG2SingleInputBubble a CG2NoMethods d CG2NoMethods b CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_A_C__ a CG2SingleBubbleADOnly crossboundarytest CG2SingleInputBubble d CG2NoMethods b CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2__BC__ b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble a CG2NoMethods d CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_ABC__ a CG2SingleBubbleADOnly b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2____D_ d CG2SingleInputBubble +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_A__D_ a CG2SingleBubbleADOnly d CG2SingleBubbleADOnly +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2__B_D_ b CG2SingleInputBubble d CG2SingleBubbleADOnly a CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_AB_D_ a CG2SingleBubbleADOnly b CG2SingleInputBubble d CG2SingleBubbleADOnly e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2___CD_ crossboundarytest CG2SingleInputBubble d CG2SingleBubbleADOnly a CG2NoMethods b CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_A_CD_ a CG2SingleBubbleADOnly crossboundarytest CG2SingleInputBubble d CG2SingleBubbleADOnly b CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2__BCD_ b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble d CG2SingleBubbleADOnly a CG2NoMethods e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_ABCD_ a CG2SingleBubbleADOnly b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble d CG2SingleBubbleADOnly e CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_____E e CG2SingleInputBubble +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_A___E a CG2SingleBubbleADOnly e CG2SingleInputBubble d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2__B__E b CG2SingleInputBubble e CG2SingleInputBubble a CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_AB__E a CG2SingleBubbleADOnly b CG2SingleInputBubble e CG2SingleInputBubble d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2___C_E crossboundarytest CG2SingleInputBubble e CG2SingleInputBubble a CG2NoMethods b CG2NoMethods d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_A_C_E a CG2SingleBubbleADOnly crossboundarytest CG2SingleInputBubble e CG2SingleInputBubble b CG2NoMethods d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2__BC_E b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble e CG2SingleInputBubble d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_ABC_E a CG2SingleBubbleADOnly b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble e CG2SingleInputBubble d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2____DE d CG2SingleBubbleADOnly e CG2SingleInputBubble +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_A__DE a CG2SingleBubbleADOnly d CG2SingleBubbleADOnly e CG2SingleInputBubble +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2__B_DE b CG2SingleInputBubble d CG2SingleBubbleADOnly e CG2SingleInputBubble a CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_AB_DE a CG2SingleBubbleADOnly b CG2SingleInputBubble d CG2SingleBubbleADOnly e CG2SingleInputBubble +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2___CDE crossboundarytest CG2SingleInputBubble d CG2SingleBubbleADOnly e CG2SingleInputBubble a CG2NoMethods b CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_A_CDE a CG2SingleBubbleADOnly crossboundarytest CG2SingleInputBubble d CG2SingleBubbleADOnly e CG2SingleInputBubble b CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2__BCDE b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble d CG2SingleBubbleADOnly e CG2SingleInputBubble a CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble2_ABCDE a CG2SingleBubbleADOnly b CG2SingleInputBubble crossboundarytest CG2SingleInputBubble d CG2SingleBubbleADOnly e CG2SingleInputBubble + +goto done + +:testCG2SingleMixedInputBubble +echo TEST All combinations of the 5 dlls compiled with Crossgen2 with input bubble enabled for the root set and not +echo for the more derived set of assemblies. b, crossboundarytest, and e are compiled as standard R2R and +echo a, and d are compiled with the reference echo set limited to a and d with input bubble enabled. This simulates a the model +echo of a framework that ships with input bubble enabled, and the application with standard R2R rules. + +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_A____ a CG2SingleBubbleADOnly d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_AB___ a CG2SingleBubbleADOnly b CG2Single d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_A_C__ a CG2SingleBubbleADOnly crossboundarytest CG2Single d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_ABC__ a CG2SingleBubbleADOnly b CG2Single crossboundarytest CG2Single d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3____D_ d CG2SingleBubbleADOnly +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_A__D_ a CG2SingleBubbleADOnly d CG2SingleBubbleADOnly +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3__B_D_ b CG2Single d CG2SingleBubbleADOnly +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_AB_D_ a CG2SingleBubbleADOnly b CG2Single d CG2SingleBubbleADOnly +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3___CD_ crossboundarytest CG2Single d CG2SingleBubbleADOnly +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_A_CD_ a CG2SingleBubbleADOnly crossboundarytest CG2Single d CG2SingleBubbleADOnly +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3__BCD_ b CG2Single crossboundarytest CG2Single d CG2SingleBubbleADOnly +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_ABCD_ a CG2SingleBubbleADOnly b CG2Single crossboundarytest CG2Single d CG2SingleBubbleADOnly +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_A___E a CG2SingleBubbleADOnly e CG2Single d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_AB__E a CG2SingleBubbleADOnly b CG2Single e CG2Single d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_A_C_E a CG2SingleBubbleADOnly crossboundarytest CG2Single e CG2Single d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_ABC_E a CG2SingleBubbleADOnly b CG2Single crossboundarytest CG2Single e CG2Single d CG2NoMethods +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3____DE d CG2SingleBubbleADOnly e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_A__DE a CG2SingleBubbleADOnly d CG2SingleBubbleADOnly e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3__B_DE b CG2Single d CG2SingleBubbleADOnly e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_AB_DE a CG2SingleBubbleADOnly b CG2Single d CG2SingleBubbleADOnly e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3___CDE crossboundarytest CG2Single d CG2SingleBubbleADOnly e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_A_CDE a CG2SingleBubbleADOnly crossboundarytest CG2Single d CG2SingleBubbleADOnly e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3__BCDE b CG2Single crossboundarytest CG2Single d CG2SingleBubbleADOnly e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2bubble3_ABCDE a CG2SingleBubbleADOnly b CG2Single crossboundarytest CG2Single d CG2SingleBubbleADOnly e CG2Single + +goto done + + +:testCG2All +echo TEST All combinations of compiling standard R2R with the crossgen2 tool instad of crossgen1 +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_A____ a CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2__B___ b CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_AB___ a CG2Single b CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2___C__ crossboundarytest CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_A_C__ a CG2Single crossboundarytest CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2__BC__ b CG2Single crossboundarytest CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_ABC__ a CG2Single b CG2Single crossboundarytest CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2____D_ d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_A__D_ a CG2Single d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2__B_D_ b CG2Single d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_AB_D_ a CG2Single b CG2Single d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2___CD_ crossboundarytest CG2Single d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_A_CD_ a CG2Single crossboundarytest CG2Single d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2__BCD_ b CG2Single crossboundarytest CG2Single d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_ABCD_ a CG2Single b CG2Single crossboundarytest CG2Single d CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_____E e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_A___E a CG2Single e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2__B__E b CG2Single e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_AB__E a CG2Single b CG2Single e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2___C_E crossboundarytest CG2Single e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_A_C_E a CG2Single crossboundarytest CG2Single e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2__BC_E b CG2Single crossboundarytest CG2Single e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_ABC_E a CG2Single b CG2Single crossboundarytest CG2Single e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2____DE d CG2Single e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_A__DE a CG2Single d CG2Single e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2__B_DE b CG2Single d CG2Single e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_AB_DE a CG2Single b CG2Single d CG2Single e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2___CDE crossboundarytest CG2Single d CG2Single e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_A_CDE a CG2Single crossboundarytest CG2Single d CG2Single e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2__BCDE b CG2Single crossboundarytest CG2Single d CG2Single e CG2Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg2_ABCDE a CG2Single b CG2Single crossboundarytest CG2Single d CG2Single e CG2Single + +:testCG1All +echo TEST All combinations of compiling standard R2R with the crossgen tool instad of crossgen2 +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_A____ a CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1__B___ b CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_AB___ a CG1Single b CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1___C__ crossboundarytest CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_A_C__ a CG1Single crossboundarytest CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1__BC__ b CG1Single crossboundarytest CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_ABC__ a CG1Single b CG1Single crossboundarytest CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1____D_ d CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_A__D_ a CG1Single d CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1__B_D_ b CG1Single d CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_AB_D_ a CG1Single b CG1Single d CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1___CD_ crossboundarytest CG1Single d CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_A_CD_ a CG1Single crossboundarytest CG1Single d CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1__BCD_ b CG1Single crossboundarytest CG1Single d CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_ABCD_ a CG1Single b CG1Single crossboundarytest CG1Single d CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_____E e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_A___E a CG1Single e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1__B__E b CG1Single e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_AB__E a CG1Single b CG1Single e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1___C_E crossboundarytest CG1Single e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_A_C_E a CG1Single crossboundarytest CG1Single e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1__BC_E b CG1Single crossboundarytest CG1Single e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_ABC_E a CG1Single b CG1Single crossboundarytest CG1Single e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1____DE d CG1Single e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_A__DE a CG1Single d CG1Single e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1__B_DE b CG1Single d CG1Single e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_AB_DE a CG1Single b CG1Single d CG1Single e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1___CDE crossboundarytest CG1Single d CG1Single e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_A_CDE a CG1Single crossboundarytest CG1Single d CG1Single e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1__BCDE b CG1Single crossboundarytest CG1Single d CG1Single e CG1Single +call %TESTBATCHROOT%\runindividualtest.cmd %TESTBATCHROOT% %TESTDIR% cg1_ABCDE a CG1Single b CG1Single crossboundarytest CG1Single d CG1Single e CG1Single + + +goto done + +:done diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/d/d.cs b/src/coreclr/tests/src/readytorun/crossboundarylayout/d/d.cs new file mode 100644 index 00000000000000..9d6b8bd8ab1667 --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/d/d.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace CrossBoundaryLayout +{ + public struct ByteStruct + { + public byte _dVal; + } +} \ No newline at end of file diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/d/d.csproj b/src/coreclr/tests/src/readytorun/crossboundarylayout/d/d.csproj new file mode 100644 index 00000000000000..09eb1e5530790e --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/d/d.csproj @@ -0,0 +1,10 @@ + + + library + SharedLibrary + + + + + + diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/e/e.cs b/src/coreclr/tests/src/readytorun/crossboundarylayout/e/e.cs new file mode 100644 index 00000000000000..bbbc3387f43c6b --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/e/e.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace CrossBoundaryLayout +{ + public struct ByteStructE + { + public byte _eVal; + } +} \ No newline at end of file diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/e/e.csproj b/src/coreclr/tests/src/readytorun/crossboundarylayout/e/e.csproj new file mode 100644 index 00000000000000..3e752d68f2ea7e --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/e/e.csproj @@ -0,0 +1,10 @@ + + + library + SharedLibrary + + + + + + diff --git a/src/coreclr/tests/src/readytorun/crossboundarylayout/runindividualtest.cmd b/src/coreclr/tests/src/readytorun/crossboundarylayout/runindividualtest.cmd new file mode 100644 index 00000000000000..55d86f9e91e057 --- /dev/null +++ b/src/coreclr/tests/src/readytorun/crossboundarylayout/runindividualtest.cmd @@ -0,0 +1,14 @@ +setlocal +rd /s /q %2\%3 2> nul +md %2\%3 +copy %2\* %2\%3 > nul +call %1\buildcrossgen2image.cmd %* +@echo on +%CORE_ROOT%\corerun %2\%3\crossboundarytest.dll +@echo off +if %ERRORLEVEL% NEQ 100 ( + echo FAILED + goto done +) +echo PASSED +:done \ No newline at end of file diff --git a/src/coreclr/tests/src/readytorun/tests/mainv1.csproj b/src/coreclr/tests/src/readytorun/tests/mainv1.csproj index fb9898f100b0ab..8587289faf1054 100644 --- a/src/coreclr/tests/src/readytorun/tests/mainv1.csproj +++ b/src/coreclr/tests/src/readytorun/tests/mainv1.csproj @@ -27,7 +27,11 @@ if not exist test.dll ( echo FAILED to copy test.dll exit /b 1 ) -%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out test.ni.dll test.dll +if defined RunCrossGen2 ( + %Core_Root%\CoreRun.exe %Core_Root%\crossgen2\crossgen2.dll -r:%Core_Root%\*.dll -r:%25CD% -o:test.ni.dll test.dll +) else ( + %Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out test.ni.dll test.dll +) set CrossGenStatus=!ERRORLEVEL! IF NOT !CrossGenStatus!==0 ( ECHO Crossgen failed with exitcode - !CrossGenStatus! @@ -37,7 +41,11 @@ if not exist test.ni.dll ( echo FAILED to build test.ni.dll exit /b 1 ) -%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out fieldgetter.ni.dll fieldgetter.dll +if defined RunCrossGen2 ( + %Core_Root%\CoreRun.exe %Core_Root%\crossgen2\crossgen2.dll -r:%Core_Root%\*.dll -r:%25CD% -o:fieldgetter.ni.dll fieldgetter.dll +) else ( + %Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out fieldgetter.ni.dll fieldgetter.dll +) set CrossGenStatus=!ERRORLEVEL! IF NOT !CrossGenStatus!==0 ( ECHO Crossgen failed with exitcode - !CrossGenStatus! @@ -47,7 +55,11 @@ if not exist fieldgetter.ni.dll ( echo FAILED to build fieldgetter.ni.dll exit /b 1 ) -%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out mainv1.ni.dll mainv1.dll +if defined RunCrossGen2 ( + %Core_Root%\CoreRun.exe %Core_Root%\crossgen2\crossgen2.dll -r:%Core_Root%\*.dll -r:%25CD% -o:mainv1.ni.dll mainv1.dll +) else ( + %Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out mainv1.ni.dll mainv1.dll +) set CrossGenStatus=!ERRORLEVEL! IF NOT !CrossGenStatus!==0 ( ECHO Crossgen failed with exitcode - !CrossGenStatus! @@ -72,7 +84,11 @@ then echo Failed to copy test.dll exit 1 fi -$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out test.ni.dll test.dll +if [ ! -z "$RunCrossGen2" ]; then + $CORE_ROOT/corerun $CORE_ROOT/crossgen2/crossgen2.dll -r:$CORE_ROOT/*.dll -r:`pwd` -o:test.ni.dll test.dll +else + $CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out test.ni.dll test.dll +fi __cgExitCode=$? if [ $__cgExitCode -ne 0 ] then @@ -84,7 +100,11 @@ then echo Failed to build test.ni.dll exit 1 fi -$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out fieldgetter.ni.dll fieldgetter.dll +if [ ! -z "$RunCrossGen2" ]; then + $CORE_ROOT/corerun $CORE_ROOT/crossgen2/crossgen2.dll -r:$CORE_ROOT/*.dll -r:`pwd` -o:fieldgetter.ni.dll fieldgetter.dll +else + $CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out fieldgetter.ni.dll fieldgetter.dll +fi __cgExitCode=$? if [ $__cgExitCode -ne 0 ] then @@ -96,7 +116,11 @@ then echo Failed to build fieldgetter.ni.dll exit 1 fi -$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out mainv1.ni.dll mainv1.dll +if [ ! -z "$RunCrossGen2" ]; then + $CORE_ROOT/corerun $CORE_ROOT/crossgen2/crossgen2.dll -r:$CORE_ROOT/*.dll -r:`pwd` -o:mainv1.ni.dll mainv1.dll +else + $CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out mainv1.ni.dll mainv1.dll +fi __cgExitCode=$? if [ $__cgExitCode -ne 0 ] then diff --git a/src/coreclr/tests/src/readytorun/tests/mainv2.csproj b/src/coreclr/tests/src/readytorun/tests/mainv2.csproj index 69d0b0bb807862..9207507d02e13b 100644 --- a/src/coreclr/tests/src/readytorun/tests/mainv2.csproj +++ b/src/coreclr/tests/src/readytorun/tests/mainv2.csproj @@ -25,7 +25,11 @@ if not exist test.dll ( echo FAILED to copy test.dll exit /b 1 ) -%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out mainv2.ni.dll mainv2.dll +if defined RunCrossGen2 ( + %Core_Root%\CoreRun.exe %Core_Root%\crossgen2\crossgen2.dll -r:%Core_Root%\*.dll -r:%25CD% -o:mainv2.ni.dll mainv2.dll +) else ( + %Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out mainv2.ni.dll mainv2.dll +) set CrossGenStatus=!ERRORLEVEL! IF NOT !CrossGenStatus!==0 ( ECHO Crossgen failed with exitcode - !CrossGenStatus! @@ -35,7 +39,11 @@ if not exist mainv2.ni.dll ( echo FAILED to build mainv2.ni.dll exit /b 1 ) -%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out fieldgetter.ni.dll fieldgetter.dll +if defined RunCrossGen2 ( + %Core_Root%\CoreRun.exe %Core_Root%\crossgen2\crossgen2.dll -r:%Core_Root%\*.dll -r:%25CD% -o:fieldgetter.ni.dll fieldgetter.dll +) else ( + %Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out fieldgetter.ni.dll fieldgetter.dll +) set CrossGenStatus=!ERRORLEVEL! IF NOT !CrossGenStatus!==0 ( ECHO Crossgen failed with exitcode - !CrossGenStatus! @@ -55,7 +63,11 @@ if not exist test.dll ( echo FAILED to copy test.dll exit /b 1 ) -%Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out test.ni.dll test.dll +if defined RunCrossGen2 ( + %Core_Root%\CoreRun.exe %Core_Root%\crossgen2\crossgen2.dll -r:%Core_Root%\*.dll -r:%25CD% -o:test.ni.dll test.dll +) else ( + %Core_Root%\crossgen /readytorun /platform_assemblies_paths %Core_Root%%3B%25CD% /out test.ni.dll test.dll +) set CrossGenStatus=!ERRORLEVEL! IF NOT !CrossGenStatus!==0 ( ECHO Crossgen failed with exitcode - !CrossGenStatus! @@ -80,7 +92,11 @@ then echo Failed to copy test.dll exit 1 fi -$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out mainv2.ni.dll mainv2.dll +if [ ! -z "$RunCrossGen2" ]; then + $CORE_ROOT/corerun $CORE_ROOT/crossgen2/crossgen2.dll -r:$CORE_ROOT/*.dll -r:`pwd` -o:mainv2.ni.dll mainv2.dll +else + $CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out mainv2.ni.dll mainv2.dll +fi __cgExitCode=$? if [ $__cgExitCode -ne 0 ] then @@ -92,7 +108,11 @@ then echo Failed to build mainv2.ni.dll exit 1 fi -$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out fieldgetter.ni.dll fieldgetter.dll +if [ ! -z "$RunCrossGen2" ]; then + $CORE_ROOT/corerun $CORE_ROOT/crossgen2/crossgen2.dll -r:$CORE_ROOT/*.dll -r:`pwd` -o:fieldgetter.ni.dll fieldgetter.dll +else + $CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out fieldgetter.ni.dll fieldgetter.dll +fi __cgExitCode=$? if [ $__cgExitCode -ne 0 ] then @@ -116,7 +136,11 @@ then echo Failed to copy test.dll exit 1 fi -$CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out test.ni.dll test.dll +if [ ! -z "$RunCrossGen2" ]; then + $CORE_ROOT/corerun $CORE_ROOT/crossgen2/crossgen2.dll -r:$CORE_ROOT/*.dll -r:`pwd` -o:test.ni.dll test.dll +else + $CORE_ROOT/crossgen -readytorun -platform_assemblies_paths $CORE_ROOT:`pwd` -out test.ni.dll test.dll +fi __cgExitCode=$? if [ $__cgExitCode -ne 0 ] then diff --git a/src/coreclr/tests/src/runtest.proj b/src/coreclr/tests/src/runtest.proj index 562be79e4e2dcb..c99c8d148144e0 100644 --- a/src/coreclr/tests/src/runtest.proj +++ b/src/coreclr/tests/src/runtest.proj @@ -291,7 +291,7 @@ namespace $([System.String]::Copy($(Category)).Replace(".","_").Replace("\",""). if (infraEx != null) { - Assert.True(false, "Test Infrastructure Failure: " + infraEx.Message)%3B + Assert.True(false, "Test Infrastructure Failure: " + infraEx.ToString())%3B } else { @@ -304,7 +304,7 @@ namespace $([System.String]::Copy($(Category)).Replace(".","_").Replace("\",""). catch (Exception ex) { testOutput.Add("Unable to read error file: " + errorFile)%3B - testOutput.Add(ex.Message)%3B + testOutput.Add(ex.ToString())%3B } testOutput.Add(string.Empty)%3B @@ -319,7 +319,7 @@ namespace $([System.String]::Copy($(Category)).Replace(".","_").Replace("\",""). catch(Exception ex) { testOutput.Add("Unable to read output file: " + outputFile)%3B - testOutput.Add(ex.Message)%3B + testOutput.Add(ex.ToString())%3B } testOutput.Add("To run the test:")%3B @@ -354,7 +354,7 @@ namespace $([System.String]::Copy($(Category)).Replace(".","_").Replace("\",""). - + diff --git a/src/coreclr/tests/src/tracing/eventpipe/common/Reverse.cs b/src/coreclr/tests/src/tracing/eventpipe/common/Reverse.cs new file mode 100644 index 00000000000000..c4f1c9464e6096 --- /dev/null +++ b/src/coreclr/tests/src/tracing/eventpipe/common/Reverse.cs @@ -0,0 +1,178 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using System.IO.Pipes; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Threading.Tasks; + +namespace Tracing.Tests.Common +{ + /** + * ==ADVERTISE PROTOCOL== + * Before standard IPC Protocol communication can occur on a client-mode connection + * the runtime must advertise itself over the connection. ALL SUBSEQUENT COMMUNICATION + * IS STANDARD DIAGNOSTICS IPC PROTOCOL COMMUNICATION. + * + * The flow for Advertise is a one-way burst of 32 bytes consisting of + * 8 bytes - "ADVR_V1\0" (ASCII chars + null byte) + * 16 bytes - CLR Instance Cookie (little-endian) + * 8 bytes - PID (little-endian) + * 2 bytes - unused for futureproofing + */ + + public class IpcAdvertise + { + public static int Size_V1 => 34; + public static byte[] Magic_V1 => System.Text.Encoding.ASCII.GetBytes("ADVR_V1" + '\0'); + public static int MagicSize_V1 => 8; + + public byte[] Magic = Magic_V1; + public UInt64 ProcessId; + public Guid RuntimeInstanceCookie; + public UInt16 Unused; + + /// + /// + /// + /// (pid, clrInstanceId) + public static IpcAdvertise Parse(Stream stream) + { + var binaryReader = new BinaryReader(stream); + var advertise = new IpcAdvertise() + { + Magic = binaryReader.ReadBytes(Magic_V1.Length), + RuntimeInstanceCookie = new Guid(binaryReader.ReadBytes(16)), + ProcessId = binaryReader.ReadUInt64(), + Unused = binaryReader.ReadUInt16() + }; + + for (int i = 0; i < Magic_V1.Length; i++) + if (advertise.Magic[i] != Magic_V1[i]) + throw new Exception("Invalid advertise message from client connection"); + + // FUTURE: switch on incoming magic and change if version ever increments + return advertise; + } + + override public string ToString() + { + return $"{{ Magic={Magic}; ClrInstanceId={RuntimeInstanceCookie}; ProcessId={ProcessId}; Unused={Unused}; }}"; + } + } + public class ReverseServer + { + public static string MakeServerAddress() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return "DOTNET_TRACE_TESTS_" + Path.GetRandomFileName(); + } + else + { + return Path.Combine(Path.GetTempPath(), "DOTNET_TRACE_TESTS_" + Path.GetRandomFileName()); + } + } + + private object _server; // _server ::= socket | NamedPipeServerStream + private Socket _clientSocket; // only used on non-Windows + private string _serverAddress; + + public ReverseServer(string serverAddress, int bufferSize = 16 * 1024) + { + _serverAddress = serverAddress; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + _server = new NamedPipeServerStream( + serverAddress, + PipeDirection.InOut, + NamedPipeServerStream.MaxAllowedServerInstances, + PipeTransmissionMode.Byte, + PipeOptions.None, + bufferSize, + bufferSize); + } + else + { + if (File.Exists(serverAddress)) + File.Delete(serverAddress); + var remoteEP = new UnixDomainSocketEndPoint(serverAddress); + + var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified); + // socket(7) states that SO_RCVBUF has a minimum of 128 and SO_SNDBUF has minimum of 1024 + socket.SendBufferSize = Math.Max(bufferSize, 1024); + socket.ReceiveBufferSize = Math.Max(bufferSize, 128); + socket.Bind(remoteEP); + socket.Listen(255); + socket.LingerState.Enabled = false; + _server = socket; + } + } + + public async Task AcceptAsync() + { + switch (_server) + { + case NamedPipeServerStream serverStream: + await serverStream.WaitForConnectionAsync(); + return serverStream; + case Socket socket: + _clientSocket = await socket.AcceptAsync(); + return new NetworkStream(_clientSocket); + default: + throw new ArgumentException("Invalid server type"); + } + } + + public void Shutdown() + { + switch (_server) + { + case NamedPipeServerStream serverStream: + try + { + serverStream.Disconnect(); + } + catch {} + finally + { + serverStream.Dispose(); + } + break; + case Socket socket: + try + { + socket.Shutdown(SocketShutdown.Both); + } + catch {} + finally + { + _clientSocket?.Close(); + socket.Close(); + socket.Dispose(); + _clientSocket?.Dispose(); + if (File.Exists(_serverAddress)) + File.Delete(_serverAddress); + } + break; + default: + throw new ArgumentException("Invalid server type"); + } + } + + // Creates the server, listens, and closes the server + public static async Task CreateServerAndReceiveAdvertisement(string serverAddress) + { + var server = new ReverseServer(serverAddress); + Logger.logger.Log("Waiting for connection"); + Stream stream = await server.AcceptAsync(); + Logger.logger.Log("Got a connection"); + IpcAdvertise advertise = IpcAdvertise.Parse(stream); + server.Shutdown(); + return advertise; + } + } +} \ No newline at end of file diff --git a/src/coreclr/tests/src/tracing/eventpipe/common/common.csproj b/src/coreclr/tests/src/tracing/eventpipe/common/common.csproj index 0df38b391df232..a0b36c8336dcc6 100644 --- a/src/coreclr/tests/src/tracing/eventpipe/common/common.csproj +++ b/src/coreclr/tests/src/tracing/eventpipe/common/common.csproj @@ -9,5 +9,6 @@ + diff --git a/src/coreclr/tests/src/tracing/eventpipe/eventsourceerror/eventsourceerror.cs b/src/coreclr/tests/src/tracing/eventpipe/eventsourceerror/eventsourceerror.cs new file mode 100644 index 00000000000000..b8c7d9bd7d099d --- /dev/null +++ b/src/coreclr/tests/src/tracing/eventpipe/eventsourceerror/eventsourceerror.cs @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics.Tracing; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; +using Microsoft.Diagnostics.Tools.RuntimeClient; +using Microsoft.Diagnostics.Tracing; +using Tracing.Tests.Common; +using Microsoft.Diagnostics.Tracing.Parsers.Clr; + +namespace Tracing.Tests.EventSourceError +{ + // This class tries to use IEnumerable events with manifest based + // EventSource, which will cause an error. The test is validating we see + // that error over EventPipe. + class IllegalTypesEventSource : EventSource + { + public IllegalTypesEventSource() + { + + } + + [Event(1, Level = EventLevel.LogAlways)] + public void SimpleArrayEvent(int[] simpleArray) + { + WriteEvent(1, simpleArray); + } + + [Event(2, Level = EventLevel.LogAlways)] + public void BasicEvent(int i) + { + WriteEvent(2, i); + } + + protected override void OnEventCommand(EventCommandEventArgs command) + { + Console.WriteLine($"command={command.Command}"); + } + } + + public class EventSourceError + { + public static int Main(string[] args) + { + // This test validates that if an EventSource generates an error + // during construction it gets emitted over EventPipe + + List providers = new List + { + new Provider("IllegalTypesEventSource") + }; + + var configuration = new SessionConfiguration(circularBufferSizeMB: 1024, format: EventPipeSerializationFormat.NetTrace, providers: providers); + return IpcTraceTest.RunAndValidateEventCounts(_expectedEventCounts, _eventGeneratingAction, configuration, _DoesRundownContainMethodEvents); + } + + private static Dictionary _expectedEventCounts = new Dictionary() + { + { "IllegalTypesEventSource", 1 } + }; + + private static Action _eventGeneratingAction = () => + { + // Constructing the EventSource should generate the error message + IllegalTypesEventSource eventSource = new IllegalTypesEventSource(); + + // This will be a no-op since the EventSource failed to construct + eventSource.SimpleArrayEvent(new int[] { 12 }); + }; + + private static Func> _DoesRundownContainMethodEvents = (source) => + { + int eventCount = 0; + bool sawEvent = false; + source.Dynamic.All += (TraceEvent traceEvent) => + { + if (traceEvent.ProviderName == "SentinelEventSource" + || traceEvent.ProviderName == "Microsoft-Windows-DotNETRuntime" + || traceEvent.ProviderName == "Microsoft-Windows-DotNETRuntimeRundown" + || traceEvent.ProviderName == "Microsoft-DotNETCore-EventPipe") + { + return; + } + + ++eventCount; + + if (traceEvent.ProviderName == "IllegalTypesEventSource" + && traceEvent.EventName == "EventSourceMessage" + && traceEvent.FormattedMessage.StartsWith("ERROR: Exception in Command Processing for EventSource IllegalTypesEventSource", StringComparison.OrdinalIgnoreCase)) + { + sawEvent = true; + } + else + { + Console.WriteLine($"Saw unexpected event {traceEvent}"); + } + }; + + return () => ((eventCount == 1) && sawEvent) ? 100 : -1; + }; + } +} \ No newline at end of file diff --git a/src/coreclr/tests/src/tracing/eventpipe/eventsourceerror/eventsourceerror.csproj b/src/coreclr/tests/src/tracing/eventpipe/eventsourceerror/eventsourceerror.csproj new file mode 100644 index 00000000000000..a1915b163e35a8 --- /dev/null +++ b/src/coreclr/tests/src/tracing/eventpipe/eventsourceerror/eventsourceerror.csproj @@ -0,0 +1,14 @@ + + + .NETCoreApp + exe + BuildAndRun + true + true + 0 + + + + + + diff --git a/src/coreclr/tests/src/tracing/eventpipe/reverse/reverse.cs b/src/coreclr/tests/src/tracing/eventpipe/reverse/reverse.cs new file mode 100644 index 00000000000000..5fdc7ca11a235d --- /dev/null +++ b/src/coreclr/tests/src/tracing/eventpipe/reverse/reverse.cs @@ -0,0 +1,339 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics.Tracing; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Reflection; +using Microsoft.Diagnostics.Tools.RuntimeClient; +using Tracing.Tests.Common; +using System.Threading; +using System.IO; +using Microsoft.Diagnostics.Tracing; + +namespace Tracing.Tests.ReverseValidation +{ + public class ReverseValidation + { + // The runtime will do an exponential falloff by a factor of 1.25 starting at 10ms with a max of 500ms + // We can time tests out after waiting 30s which should have sufficient attempts + private static int _maxPollTimeMS = 30_000; + + private static async Task WaitTillTimeout(Task task, TimeSpan timeout) + { + using var cts = new CancellationTokenSource(); + var completedTask = await Task.WhenAny(task, Task.Delay(timeout, cts.Token)); + if (completedTask == task) + { + cts.Cancel(); + return await task; + } + else + { + throw new TimeoutException("Task timed out"); + } + } + + public static async Task RunSubprocess(string serverName, Func beforeExecution = null, Func duringExecution = null, Func afterExecution = null) + { + using (var process = new Process()) + { + if (beforeExecution != null) + await beforeExecution(); + + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + process.StartInfo.Environment.Add("DOTNET_DiagnosticsMonitorAddress", serverName); + process.StartInfo.FileName = Process.GetCurrentProcess().MainModule.FileName; + process.StartInfo.Arguments = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath + " 0"; + Logger.logger.Log($"running sub-process: {process.StartInfo.FileName} {process.StartInfo.Arguments}"); + bool fSuccess = process.Start(); + Logger.logger.Log($"subprocess started: {fSuccess}"); + Logger.logger.Log($"subprocess PID: {process.Id}"); + + while (!EventPipeClient.ListAvailablePorts().Contains(process.Id)) + await Task.Delay(100); + try + { + if (duringExecution != null) + await duringExecution(process.Id); + } + finally + { + process.Kill(); + } + + + if (afterExecution != null) + await afterExecution(); + } + } + + public static async Task TEST_RuntimeIsResilientToServerClosing() + { + string serverName = ReverseServer.MakeServerAddress(); + Logger.logger.Log($"Server name is '{serverName}'"); + await RunSubprocess( + serverName: serverName, + duringExecution: async (_) => + { + var ad1 = await WaitTillTimeout(ReverseServer.CreateServerAndReceiveAdvertisement(serverName), TimeSpan.FromMilliseconds(_maxPollTimeMS)); + Logger.logger.Log(ad1.ToString()); + var ad2 = await WaitTillTimeout(ReverseServer.CreateServerAndReceiveAdvertisement(serverName), TimeSpan.FromMilliseconds(_maxPollTimeMS)); + Logger.logger.Log(ad2.ToString()); + var ad3 = await WaitTillTimeout(ReverseServer.CreateServerAndReceiveAdvertisement(serverName), TimeSpan.FromMilliseconds(_maxPollTimeMS)); + Logger.logger.Log(ad3.ToString()); + var ad4 = await WaitTillTimeout(ReverseServer.CreateServerAndReceiveAdvertisement(serverName), TimeSpan.FromMilliseconds(_maxPollTimeMS)); + Logger.logger.Log(ad4.ToString()); + } + ); + + return true; + } + + public static async Task TEST_RuntimeConnectsToExistingServer() + { + string serverName = ReverseServer.MakeServerAddress(); + Task advertiseTask = ReverseServer.CreateServerAndReceiveAdvertisement(serverName); + Logger.logger.Log($"Server name is `{serverName}`"); + await RunSubprocess( + serverName: serverName, + duringExecution: async (_) => + { + IpcAdvertise advertise = await WaitTillTimeout(advertiseTask, TimeSpan.FromMilliseconds(_maxPollTimeMS)); + Logger.logger.Log(advertise.ToString()); + } + ); + + return true; + } + + + public static async Task TEST_CanConnectServerAndClientAtSameTime() + { + string serverName = ReverseServer.MakeServerAddress(); + Logger.logger.Log($"Server name is '{serverName}'"); + var server = new ReverseServer(serverName); + await RunSubprocess( + serverName: serverName, + duringExecution: async (int pid) => + { + Task reverseTask = Task.Run(async () => + { + Logger.logger.Log($"Waiting for reverse connection"); + Stream reverseStream = await server.AcceptAsync(); + Logger.logger.Log("Got reverse connection"); + IpcAdvertise advertise = IpcAdvertise.Parse(reverseStream); + Logger.logger.Log(advertise.ToString()); + }); + + Task regularTask = Task.Run(async () => + { + var config = new SessionConfiguration( + circularBufferSizeMB: 1000, + format: EventPipeSerializationFormat.NetTrace, + providers: new List { + new Provider("Microsoft-DotNETCore-SampleProfiler") + }); + Logger.logger.Log("Starting EventPipeSession over standard connection"); + using Stream stream = EventPipeClient.CollectTracing(pid, config, out var sessionId); + Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); + using var source = new EventPipeEventSource(stream); + Task readerTask = Task.Run(() => source.Process()); + await Task.Delay(500); + Logger.logger.Log("Stopping EventPipeSession over standard connection"); + EventPipeClient.StopTracing(pid, sessionId); + await readerTask; + Logger.logger.Log("Stopped EventPipeSession over standard connection"); + }); + + await Task.WhenAll(reverseTask, regularTask); + } + ); + + server.Shutdown(); + + return true; + } + + public static async Task TEST_ServerWorksIfClientDoesntAccept() + { + string serverName = ReverseServer.MakeServerAddress(); + Logger.logger.Log($"Server name is '{serverName}'"); + var server = new ReverseServer(serverName); + await RunSubprocess( + serverName: serverName, + duringExecution: async (int pid) => + { + var config = new SessionConfiguration( + circularBufferSizeMB: 10, + format: EventPipeSerializationFormat.NetTrace, + providers: new List { + new Provider("Microsoft-DotNETCore-SampleProfiler") + }); + Logger.logger.Log("Starting EventPipeSession over standard connection"); + using Stream stream = EventPipeClient.CollectTracing(pid, config, out var sessionId); + Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); + using var source = new EventPipeEventSource(stream); + Task readerTask = Task.Run(() => source.Process()); + await Task.Delay(500); + Logger.logger.Log("Stopping EventPipeSession over standard connection"); + EventPipeClient.StopTracing(pid, sessionId); + await readerTask; + Logger.logger.Log("Stopped EventPipeSession over standard connection"); + } + ); + + server.Shutdown(); + + return true; + } + + public static async Task TEST_ServerIsResilientToNoBufferAgent() + { + // N.B. - this test is only testing behavior on Windows since Unix Domain Sockets get their buffer size from the + // system configuration and isn't set here. Tests passing on Windows should indicate it would pass on Unix systems as well. + string serverName = ReverseServer.MakeServerAddress(); + Logger.logger.Log($"Server name is '{serverName}'"); + var server = new ReverseServer(serverName, 0); + await RunSubprocess( + serverName: serverName, + duringExecution: async (int pid) => + { + var config = new SessionConfiguration( + circularBufferSizeMB: 10, + format: EventPipeSerializationFormat.NetTrace, + providers: new List { + new Provider("Microsoft-DotNETCore-SampleProfiler") + }); + Logger.logger.Log("Starting EventPipeSession over standard connection"); + using Stream stream = EventPipeClient.CollectTracing(pid, config, out var sessionId); + Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); + using var source = new EventPipeEventSource(stream); + Task readerTask = Task.Run(() => source.Process()); + await Task.Delay(500); + Logger.logger.Log("Stopping EventPipeSession over standard connection"); + EventPipeClient.StopTracing(pid, sessionId); + await readerTask; + Logger.logger.Log("Stopped EventPipeSession over standard connection"); + } + ); + + server.Shutdown(); + + return true; + } + + public static async Task TEST_ReverseConnectionCanRecycleWhileTracing() + { + string serverName = ReverseServer.MakeServerAddress(); + Logger.logger.Log($"Server name is '{serverName}'"); + await RunSubprocess( + serverName: serverName, + duringExecution: async (int pid) => + { + Task regularTask = Task.Run(async () => + { + var config = new SessionConfiguration( + circularBufferSizeMB: 1000, + format: EventPipeSerializationFormat.NetTrace, + providers: new List { + new Provider("Microsoft-DotNETCore-SampleProfiler") + }); + Logger.logger.Log("Starting EventPipeSession over standard connection"); + using Stream stream = EventPipeClient.CollectTracing(pid, config, out var sessionId); + Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); + using var source = new EventPipeEventSource(stream); + Task readerTask = Task.Run(() => source.Process()); + await Task.Delay(500); + Logger.logger.Log("Stopping EventPipeSession over standard connection"); + EventPipeClient.StopTracing(pid, sessionId); + await readerTask; + Logger.logger.Log("Stopped EventPipeSession over standard connection"); + }); + + Task reverseTask = Task.Run(async () => + { + var ad1 = await WaitTillTimeout(ReverseServer.CreateServerAndReceiveAdvertisement(serverName), TimeSpan.FromMilliseconds(_maxPollTimeMS)); + Logger.logger.Log(ad1.ToString()); + var ad2 = await WaitTillTimeout(ReverseServer.CreateServerAndReceiveAdvertisement(serverName), TimeSpan.FromMilliseconds(_maxPollTimeMS)); + Logger.logger.Log(ad2.ToString()); + var ad3 = await WaitTillTimeout(ReverseServer.CreateServerAndReceiveAdvertisement(serverName), TimeSpan.FromMilliseconds(_maxPollTimeMS)); + Logger.logger.Log(ad3.ToString()); + var ad4 = await WaitTillTimeout(ReverseServer.CreateServerAndReceiveAdvertisement(serverName), TimeSpan.FromMilliseconds(_maxPollTimeMS)); + Logger.logger.Log(ad4.ToString()); + }); + + await Task.WhenAll(reverseTask, regularTask); + } + ); + + return true; + } + + public static async Task TEST_StandardConnectionStillWorksIfReverseConnectionIsBroken() + { + string serverName = ReverseServer.MakeServerAddress(); + Logger.logger.Log($"Server name is '{serverName}'"); + await RunSubprocess( + serverName: serverName, + duringExecution: async (int pid) => + { + var config = new SessionConfiguration( + circularBufferSizeMB: 1000, + format: EventPipeSerializationFormat.NetTrace, + providers: new List { + new Provider("Microsoft-DotNETCore-SampleProfiler") + }); + Logger.logger.Log("Starting EventPipeSession over standard connection"); + using Stream stream = EventPipeClient.CollectTracing(pid, config, out var sessionId); + Logger.logger.Log($"Started EventPipeSession over standard connection with session id: 0x{sessionId:x}"); + using var source = new EventPipeEventSource(stream); + Task readerTask = Task.Run(() => source.Process()); + await Task.Delay(500); + Logger.logger.Log("Stopping EventPipeSession over standard connection"); + EventPipeClient.StopTracing(pid, sessionId); + await readerTask; + Logger.logger.Log("Stopped EventPipeSession over standard connection"); + } + ); + + return true; + } + + public static async Task Main(string[] args) + { + if (args.Length >= 1) + { + await Task.Delay(TimeSpan.FromMinutes(10)); // will be killed in test + return 1; + } + + bool fSuccess = true; + IEnumerable tests = typeof(ReverseValidation).GetMethods().Where(mi => mi.Name.StartsWith("TEST_")); + foreach (var test in tests) + { + Logger.logger.Log($"::== Running test: {test.Name}"); + bool result = true; + try + { + result = await (Task)test.Invoke(null, new object[] {}); + } + catch (Exception e) + { + result = false; + Logger.logger.Log(e.ToString()); + } + fSuccess &= result; + Logger.logger.Log($"Test passed: {result}"); + Logger.logger.Log($""); + + } + return fSuccess ? 100 : -1; + } + } +} \ No newline at end of file diff --git a/src/coreclr/tests/src/tracing/eventpipe/reverse/reverse.csproj b/src/coreclr/tests/src/tracing/eventpipe/reverse/reverse.csproj new file mode 100644 index 00000000000000..2c10c6ed465339 --- /dev/null +++ b/src/coreclr/tests/src/tracing/eventpipe/reverse/reverse.csproj @@ -0,0 +1,15 @@ + + + .NETCoreApp + exe + BuildAndRun + true + 0 + true + true + + + + + + \ No newline at end of file diff --git a/src/coreclr/tests/testenvironment.proj b/src/coreclr/tests/testenvironment.proj index caed6ae7e1ee8c..199382c46df9bf 100644 --- a/src/coreclr/tests/testenvironment.proj +++ b/src/coreclr/tests/testenvironment.proj @@ -45,6 +45,7 @@ COMPlus_TC_QuickJitForLoops; COMPlus_TC_OnStackReplacement_InitialCounter; COMPlus_OSR_HitLimit; + COMPlus_TieredPGO; COMPlus_JitEnableGuardedDevirtualization; COMPlus_EnableEHWriteThru; COMPlus_JitObjectStackAllocation @@ -135,6 +136,7 @@ + @@ -174,11 +176,13 @@ <_TestEnvFileLine Include="@(_COMPlusVariable->'set %(Identity)=%(Value)')" /> + <_TestEnvFileLine Include="set MONO_ENV_OPTIONS=--interpreter" Condition="'$(Scenario)' == 'interpreter'" /> <_TestEnvFileLine Include="#!/usr/bin/env bash" /> <_TestEnvFileLine Include="@(_COMPlusVariable->'export %(Identity)=%(Value)')" /> + <_TestEnvFileLine Include="export MONO_ENV_OPTIONS=--interpreter" Condition="'$(Scenario)' == 'interpreter'" /> diff --git a/src/installer/Directory.Build.props b/src/installer/Directory.Build.props index 2a99c0661a4858..d1edd4ec5388fb 100644 --- a/src/installer/Directory.Build.props +++ b/src/installer/Directory.Build.props @@ -29,17 +29,6 @@ $(InstallerProjectRoot)signing\ - - $(ArtifactsObjDir)HostMachineInfo.props - - - - Microsoft.NETCore.App - .NETCoreApp - $(NETCoreAppFrameworkIdentifier),Version=v$(NETCoreAppFrameworkVersion) - .NET $(NETCoreAppFrameworkVersion) - - true @@ -81,11 +70,8 @@ .exe - - - - $(HostMachineRid.Remove($(HostMachineRid.LastIndexOf('-'))))-$(TargetArchitecture) + + $(HostRuntimeIdentifier.Remove($(HostRuntimeIdentifier.LastIndexOf('-'))))-$(TargetArchitecture) @@ -94,9 +80,16 @@ osx-$(TargetArchitecture) linux-$(TargetArchitecture) freebsd-$(TargetArchitecture) + netbsd-$(TargetArchitecture) + sunos-$(TargetArchitecture) ios-$(TargetArchitecture) tvos-$(TargetArchitecture) android-$(TargetArchitecture) + browser-$(TargetArchitecture) + + + + $(OutputRid) @@ -131,8 +124,8 @@ false true - - true + + true $(AssetOutputPath)sharedfx_$(OutputRid)_$(Configuration)_version_badge.svg @@ -180,6 +173,7 @@ false false false + false @@ -197,12 +191,14 @@ true true + true true true + true @@ -210,6 +206,14 @@ true true true + true + + + + + true + true + true @@ -281,6 +285,18 @@ true + + + true + true + + + + + true + true + + true @@ -288,9 +304,9 @@ true + $(HostRuntimeIdentifier.StartsWith('debian')) or + $(HostRuntimeIdentifier.StartsWith('ubuntu')) or + $(HostRuntimeIdentifier.StartsWith('linuxmint'))">true true @@ -355,7 +371,7 @@ .map .ni.pdb - + diff --git a/src/installer/Directory.Build.targets b/src/installer/Directory.Build.targets index 20b134d708ce29..7a859d808b2295 100644 --- a/src/installer/Directory.Build.targets +++ b/src/installer/Directory.Build.targets @@ -12,10 +12,8 @@ + - - - diff --git a/src/installer/Microsoft.DotNet.CoreSetup.sln b/src/installer/Microsoft.DotNet.CoreSetup.sln index e3b39fe6aff62e..9e432a1616caa6 100644 --- a/src/installer/Microsoft.DotNet.CoreSetup.sln +++ b/src/installer/Microsoft.DotNet.CoreSetup.sln @@ -9,8 +9,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution NuGet.Config = NuGet.Config EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.PlatformAbstractions", "managed\Microsoft.DotNet.PlatformAbstractions\Microsoft.DotNet.PlatformAbstractions.csproj", "{04D84DC8-A509-43FE-B846-16B770D9E3AA}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostActivation.Tests", "test\HostActivation.Tests\HostActivation.Tests.csproj", "{23F4AB97-D15C-4C51-A641-DF5C5D5EF70F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtils", "test\TestUtils\TestUtils.csproj", "{D6676666-D14D-4DFA-88FB-76E3E823E2E1}" @@ -41,22 +39,6 @@ Global RelWithDebInfo|x64 = RelWithDebInfo|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.Debug|x64.ActiveCfg = Debug|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.Debug|x64.Build.0 = Debug|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.MinSizeRel|Any CPU.ActiveCfg = Release|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.MinSizeRel|Any CPU.Build.0 = Release|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.MinSizeRel|x64.ActiveCfg = Release|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.MinSizeRel|x64.Build.0 = Release|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.Release|Any CPU.Build.0 = Release|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.Release|x64.ActiveCfg = Release|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.Release|x64.Build.0 = Release|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU - {04D84DC8-A509-43FE-B846-16B770D9E3AA}.RelWithDebInfo|x64.Build.0 = Release|Any CPU {23F4AB97-D15C-4C51-A641-DF5C5D5EF70F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {23F4AB97-D15C-4C51-A641-DF5C5D5EF70F}.Debug|Any CPU.Build.0 = Debug|Any CPU {23F4AB97-D15C-4C51-A641-DF5C5D5EF70F}.Debug|x64.ActiveCfg = Debug|Any CPU diff --git a/src/installer/corehost/CMakeLists.txt b/src/installer/corehost/CMakeLists.txt index 43a59a1a6955d1..4fa7f45b42ab00 100644 --- a/src/installer/corehost/CMakeLists.txt +++ b/src/installer/corehost/CMakeLists.txt @@ -9,6 +9,10 @@ if(MSVC) # Host components don't try to handle asynchronous exceptions add_compile_options(/EHsc) +elseif (CMAKE_CXX_COMPILER_ID MATCHES GNU) + # Prevents libc from calling pthread_cond_destroy on static objects in + # dlopen()'ed library which we dlclose() in pal::unload_library. + add_compile_options(-fno-use-cxa-atexit) endif() add_subdirectory(cli) diff --git a/src/installer/corehost/Windows/probe-win.ps1 b/src/installer/corehost/Windows/probe-win.ps1 index 353db37bfc63b8..8641741c6c79ee 100644 --- a/src/installer/corehost/Windows/probe-win.ps1 +++ b/src/installer/corehost/Windows/probe-win.ps1 @@ -34,7 +34,7 @@ function GetCMakeInfo($regKey) function LocateCMake { - $errorMsg = "CMake is a pre-requisite to build this repository but it was not found on the path. Please install CMake from http://www.cmake.org/download/ and ensure it is on your path." + $errorMsg = "CMake is a pre-requisite to build this repository but it was not found on the path. Please install CMake from https://cmake.org/download/ and ensure it is on your path." $inPathPath = (get-command cmake.exe -ErrorAction SilentlyContinue) if ($inPathPath -ne $null) { # Resolve the first version of CMake if multiple commands are found diff --git a/src/installer/corehost/build.proj b/src/installer/corehost/build.proj index 0d6d91ea43e08a..79f4c0a5f0e7df 100644 --- a/src/installer/corehost/build.proj +++ b/src/installer/corehost/build.proj @@ -6,7 +6,7 @@ package's targets into the build. --> - $(NETCoreAppFramework) + $(NetCoreAppCurrent) diff --git a/src/installer/corehost/cli/CMakeLists.txt b/src/installer/corehost/cli/CMakeLists.txt index 4945f6722598f9..3c1bdb1f2f0ec0 100644 --- a/src/installer/corehost/cli/CMakeLists.txt +++ b/src/installer/corehost/cli/CMakeLists.txt @@ -1,11 +1,10 @@ -add_subdirectory(hostmisc) add_subdirectory(hostcommon) add_subdirectory(apphost) add_subdirectory(dotnet) -add_subdirectory(fxr) -add_subdirectory(hostpolicy) add_subdirectory(nethost) add_subdirectory(test_fx_ver) +add_subdirectory(fxr) +add_subdirectory(hostpolicy) add_subdirectory(test) diff --git a/src/installer/corehost/cli/apphost/CMakeLists.txt b/src/installer/corehost/cli/apphost/CMakeLists.txt index ba01e32ec47c74..ec7e8e3e2ce4b0 100644 --- a/src/installer/corehost/cli/apphost/CMakeLists.txt +++ b/src/installer/corehost/cli/apphost/CMakeLists.txt @@ -2,49 +2,5 @@ # The .NET Foundation licenses this file to you under the MIT license. # See the LICENSE file in the project root for more information. -project(apphost) -set(DOTNET_PROJECT_NAME "apphost") - -# Add RPATH to the apphost binary that allows using local copies of shared libraries -# dotnet core depends on for special scenarios when system wide installation of such -# dependencies is not possible for some reason. -# This cannot be enabled for MacOS (Darwin) since its RPATH works in a different way, -# doesn't apply to libraries loaded via dlopen and most importantly, it is not transitive. -if (NOT CLR_CMAKE_TARGET_OSX) - set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) - set(CMAKE_INSTALL_RPATH "\$ORIGIN/netcoredeps") -endif() - -set(SKIP_VERSIONING 1) - -set(SOURCES - ./bundle_marker.cpp -) - -set(HEADERS - ./bundle_marker.h -) - -if(CLR_CMAKE_TARGET_WIN32) - list(APPEND SOURCES - apphost.windows.cpp) - - list(APPEND HEADERS - apphost.windows.h) -endif() - -include(../exe.cmake) - -add_definitions(-DFEATURE_APPHOST=1) - -# Disable manifest generation into the file .exe on Windows -if(CLR_CMAKE_TARGET_WIN32) - set_property(TARGET ${PROJECT_NAME} PROPERTY - LINK_FLAGS "/MANIFEST:NO" - ) -endif() - -# Specify non-default Windows libs to be used for Arm/Arm64 builds -if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_ARM64)) - target_link_libraries(apphost Advapi32.lib shell32.lib) -endif() +add_subdirectory(static) +add_subdirectory(standalone) diff --git a/src/installer/corehost/cli/apphost/standalone/CMakeLists.txt b/src/installer/corehost/cli/apphost/standalone/CMakeLists.txt new file mode 100644 index 00000000000000..60d9a103b12fbb --- /dev/null +++ b/src/installer/corehost/cli/apphost/standalone/CMakeLists.txt @@ -0,0 +1,54 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +project(apphost) +set(DOTNET_PROJECT_NAME "apphost") + +# Add RPATH to the apphost binary that allows using local copies of shared libraries +# dotnet core depends on for special scenarios when system wide installation of such +# dependencies is not possible for some reason. +# This cannot be enabled for MacOS (Darwin) since its RPATH works in a different way, +# doesn't apply to libraries loaded via dlopen and most importantly, it is not transitive. +if (NOT CLR_CMAKE_TARGET_OSX) + set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + set(CMAKE_INSTALL_RPATH "\$ORIGIN/netcoredeps") +endif() + +set(SKIP_VERSIONING 1) + +include_directories(..) + +set(SOURCES + ../bundle_marker.cpp + ./hostfxr_resolver_t.cpp +) + +set(HEADERS + ../bundle_marker.h + ../../../hostfxr_resolver_t.h +) + +if(CLR_CMAKE_TARGET_WIN32) + list(APPEND SOURCES + ../apphost.windows.cpp) + + list(APPEND HEADERS + ../apphost.windows.h) +endif() + +include(../../exe.cmake) + +add_definitions(-DFEATURE_APPHOST=1) + +# Disable manifest generation into the file .exe on Windows +if(CLR_CMAKE_TARGET_WIN32) + set_property(TARGET ${PROJECT_NAME} PROPERTY + LINK_FLAGS "/MANIFEST:NO" + ) +endif() + +# Specify non-default Windows libs to be used for Arm/Arm64 builds +if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_ARM64)) + target_link_libraries(apphost Advapi32.lib shell32.lib) +endif() diff --git a/src/installer/corehost/cli/apphost/standalone/hostfxr_resolver_t.cpp b/src/installer/corehost/cli/apphost/standalone/hostfxr_resolver_t.cpp new file mode 100644 index 00000000000000..4f3c3888428c5e --- /dev/null +++ b/src/installer/corehost/cli/apphost/standalone/hostfxr_resolver_t.cpp @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include + +#include "pal.h" +#include "fxr_resolver.h" +#include "trace.h" +#include "hostfxr_resolver_t.h" + +hostfxr_main_bundle_startupinfo_fn hostfxr_resolver_t::resolve_main_bundle_startupinfo() +{ + assert(m_hostfxr_dll != nullptr); + return reinterpret_cast(pal::get_symbol(m_hostfxr_dll, "hostfxr_main_bundle_startupinfo")); +} + +hostfxr_set_error_writer_fn hostfxr_resolver_t::resolve_set_error_writer() +{ + assert(m_hostfxr_dll != nullptr); + return reinterpret_cast(pal::get_symbol(m_hostfxr_dll, "hostfxr_set_error_writer")); +} + +hostfxr_main_startupinfo_fn hostfxr_resolver_t::resolve_main_startupinfo() +{ + assert(m_hostfxr_dll != nullptr); + return reinterpret_cast(pal::get_symbol(m_hostfxr_dll, "hostfxr_main_startupinfo")); +} + +hostfxr_main_fn hostfxr_resolver_t::resolve_main_v1() +{ + assert(m_hostfxr_dll != nullptr); + return reinterpret_cast(pal::get_symbol(m_hostfxr_dll, "hostfxr_main")); +} + +hostfxr_resolver_t::hostfxr_resolver_t(const pal::string_t& app_root) +{ + if (!fxr_resolver::try_get_path(app_root, &m_dotnet_root, &m_fxr_path)) + { + m_status_code = StatusCode::CoreHostLibMissingFailure; + } + else if (pal::load_library(&m_fxr_path, &m_hostfxr_dll)) + { + m_status_code = StatusCode::Success; + } + else + { + trace::error(_X("The library %s was found, but loading it from %s failed"), LIBFXR_NAME, m_fxr_path.c_str()); + trace::error(_X(" - Installing .NET prerequisites might help resolve this problem.")); + trace::error(_X(" %s"), DOTNET_CORE_INSTALL_PREREQUISITES_URL); + m_status_code = StatusCode::CoreHostLibLoadFailure; + } +} + +hostfxr_resolver_t::~hostfxr_resolver_t() +{ + if (m_hostfxr_dll != nullptr) + { + pal::unload_library(m_hostfxr_dll); + } +} diff --git a/src/installer/corehost/cli/apphost/static/CMakeLists.txt b/src/installer/corehost/cli/apphost/static/CMakeLists.txt new file mode 100644 index 00000000000000..967aebb24133a2 --- /dev/null +++ b/src/installer/corehost/cli/apphost/static/CMakeLists.txt @@ -0,0 +1,63 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +project(singlefilehost) +set(DOTNET_PROJECT_NAME "singlefilehost") + +# Add RPATH to the apphost binary that allows using local copies of shared libraries +# dotnet core depends on for special scenarios when system wide installation of such +# dependencies is not possible for some reason. +# This cannot be enabled for MacOS (Darwin) since its RPATH works in a different way, +# doesn't apply to libraries loaded via dlopen and most importantly, it is not transitive. +if (NOT CLR_CMAKE_TARGET_OSX) + set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + set(CMAKE_INSTALL_RPATH "\$ORIGIN/netcoredeps") +endif() + +set(SKIP_VERSIONING 1) + +include_directories(..) +include_directories(../../json) + +set(SOURCES + ../bundle_marker.cpp + ./hostfxr_resolver_t.cpp + ./hostpolicy_resolver.cpp +) + +set(HEADERS + ../bundle_marker.h + ../../../hostfxr_resolver_t.h +) + +if(CLR_CMAKE_TARGET_WIN32) + list(APPEND SOURCES + ../apphost.windows.cpp) + + list(APPEND HEADERS + ../apphost.windows.h) +endif() + +include(../../exe.cmake) + +add_definitions(-DFEATURE_APPHOST=1) +add_definitions(-DFEATURE_STATIC_HOST=1) + +# Disable manifest generation into the file .exe on Windows +if(CLR_CMAKE_TARGET_WIN32) + set_property(TARGET ${PROJECT_NAME} PROPERTY + LINK_FLAGS "/MANIFEST:NO" + ) +endif() + +# Specify non-default Windows libs to be used for Arm/Arm64 builds +if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_ARM64)) + target_link_libraries(singlefilehost Advapi32.lib shell32.lib) +endif() + +target_link_libraries(singlefilehost + libhostfxr_static + libhostpolicy_static + libhostcommon +) diff --git a/src/installer/corehost/cli/apphost/static/hostfxr_resolver_t.cpp b/src/installer/corehost/cli/apphost/static/hostfxr_resolver_t.cpp new file mode 100644 index 00000000000000..2c7e2b87a5f6df --- /dev/null +++ b/src/installer/corehost/cli/apphost/static/hostfxr_resolver_t.cpp @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include "trace.h" +#include "hostfxr.h" +#include "hostfxr_resolver_t.h" + +extern "C" +{ + int HOSTFXR_CALLTYPE hostfxr_main_bundle_startupinfo(const int argc, const pal::char_t* argv[], const pal::char_t* host_path, const pal::char_t* dotnet_root, const pal::char_t* app_path, int64_t bundle_header_offset); + int HOSTFXR_CALLTYPE hostfxr_main_startupinfo(const int argc, const pal::char_t* argv[], const pal::char_t* host_path, const pal::char_t* dotnet_root, const pal::char_t* app_path); + int HOSTFXR_CALLTYPE hostfxr_main(const int argc, const pal::char_t* argv[]); + hostfxr_error_writer_fn HOSTFXR_CALLTYPE hostfxr_set_error_writer(hostfxr_error_writer_fn error_writer); +} + +hostfxr_main_bundle_startupinfo_fn hostfxr_resolver_t::resolve_main_bundle_startupinfo() +{ + assert(m_hostfxr_dll == nullptr); + return hostfxr_main_bundle_startupinfo; +} + +hostfxr_set_error_writer_fn hostfxr_resolver_t::resolve_set_error_writer() +{ + assert(m_hostfxr_dll == nullptr); + return hostfxr_set_error_writer; +} + +hostfxr_main_startupinfo_fn hostfxr_resolver_t::resolve_main_startupinfo() +{ + assert(m_hostfxr_dll == nullptr); + return hostfxr_main_startupinfo; +} + +hostfxr_main_fn hostfxr_resolver_t::resolve_main_v1() +{ + assert(m_hostfxr_dll == nullptr); + assert(!"This function should not be called in a static host"); + return nullptr; +} + +hostfxr_resolver_t::hostfxr_resolver_t(const pal::string_t& app_root) +{ + if (app_root.length() == 0) + { + trace::info(_X("Application root path is empty. This shouldn't happen")); + m_status_code = StatusCode::CoreHostLibMissingFailure; + } + else + { + trace::info(_X("Using internal fxr")); + + m_dotnet_root.assign(app_root); + m_fxr_path.assign(app_root); + + m_status_code = StatusCode::Success; + } +} + +hostfxr_resolver_t::~hostfxr_resolver_t() +{ +} diff --git a/src/installer/corehost/cli/apphost/static/hostpolicy_resolver.cpp b/src/installer/corehost/cli/apphost/static/hostpolicy_resolver.cpp new file mode 100644 index 00000000000000..0b2a35639a2e11 --- /dev/null +++ b/src/installer/corehost/cli/apphost/static/hostpolicy_resolver.cpp @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include +#include +#include "hostpolicy_resolver.h" +#include +#include + +extern "C" +{ + int HOSTPOLICY_CALLTYPE corehost_load(const host_interface_t* init); + int HOSTPOLICY_CALLTYPE corehost_unload(); + corehost_error_writer_fn HOSTPOLICY_CALLTYPE corehost_set_error_writer(corehost_error_writer_fn error_writer); + int HOSTPOLICY_CALLTYPE corehost_initialize(const corehost_initialize_request_t *init_request, int32_t options, /*out*/ corehost_context_contract *context_contract); + int HOSTPOLICY_CALLTYPE corehost_main(const int argc, const pal::char_t* argv[]); + int HOSTPOLICY_CALLTYPE corehost_main_with_output_buffer(const int argc, const pal::char_t* argv[], pal::char_t buffer[], int32_t buffer_size, int32_t* required_buffer_size); +} + +int hostpolicy_resolver::load( + const pal::string_t& lib_dir, + pal::dll_t* dll, + hostpolicy_contract_t &hostpolicy_contract) +{ + static hostpolicy_contract_t contract; + + trace::info(_X("Using internal hostpolicy")); + + contract.load = corehost_load; + contract.unload = corehost_unload; + contract.set_error_writer = corehost_set_error_writer; + contract.initialize = corehost_initialize; + contract.corehost_main = corehost_main; + contract.corehost_main_with_output_buffer = corehost_main_with_output_buffer; + + hostpolicy_contract = contract; + *dll = nullptr; + + return StatusCode::Success; +} + +bool hostpolicy_resolver::try_get_dir( + host_mode_t mode, + const pal::string_t& dotnet_root, + const fx_definition_vector_t& fx_definitions, + const pal::string_t& app_candidate, + const pal::string_t& specified_deps_file, + const std::vector& probe_realpaths, + pal::string_t* impl_dir) +{ + // static apphost is not supposed to be used in a framework-dependent app + assert(!get_app(fx_definitions).get_runtime_config().get_is_framework_dependent()); + assert(mode == host_mode_t::apphost); + + impl_dir->assign(dotnet_root); + return true; +} diff --git a/src/installer/corehost/cli/bundle/file_entry.cpp b/src/installer/corehost/cli/bundle/file_entry.cpp index 775117fb9a1f6d..25e2cd01ce3fc6 100644 --- a/src/installer/corehost/cli/bundle/file_entry.cpp +++ b/src/installer/corehost/cli/bundle/file_entry.cpp @@ -38,10 +38,9 @@ bool file_entry_t::needs_extraction() const { switch (m_type) { - // Once the runtime can load assemblies from bundle, - // file_type_t::assembly should be in this category case file_type_t::deps_json: case file_type_t::runtime_config_json: + case file_type_t::assembly: return false; default: diff --git a/src/installer/corehost/cli/bundle/runner.cpp b/src/installer/corehost/cli/bundle/runner.cpp index 58d10a817855f9..dec93009e46830 100644 --- a/src/installer/corehost/cli/bundle/runner.cpp +++ b/src/installer/corehost/cli/bundle/runner.cpp @@ -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. // See the LICENSE file in the project root for more information. @@ -48,11 +48,11 @@ StatusCode runner_t::extract() } } -const file_entry_t* runner_t::probe(const pal::string_t& path) const +const file_entry_t* runner_t::probe(const pal::string_t &relative_path) const { for (const file_entry_t& entry : m_manifest.files) { - if (entry.relative_path() == path) + if (pal::pathcmp(entry.relative_path(), relative_path) == 0) { return &entry; } @@ -61,10 +61,27 @@ const file_entry_t* runner_t::probe(const pal::string_t& path) const return nullptr; } -bool runner_t::locate(const pal::string_t& relative_path, pal::string_t& full_path) const +bool runner_t::probe(const pal::string_t& relative_path, int64_t* offset, int64_t* size) const { - const bundle::runner_t* app = bundle::runner_t::app(); - const bundle::file_entry_t* entry = app->probe(relative_path); + const bundle::file_entry_t* entry = probe(relative_path); + + if (entry == nullptr) + { + return false; + } + + assert(entry->offset() != 0); + + *offset = entry->offset(); + *size = entry->size(); + + + return true; +} + +bool runner_t::locate(const pal::string_t& relative_path, pal::string_t& full_path, bool& extracted_to_disk) const +{ + const bundle::file_entry_t* entry = probe(relative_path); if (entry == nullptr) { @@ -72,12 +89,11 @@ bool runner_t::locate(const pal::string_t& relative_path, pal::string_t& full_pa return false; } - // Currently, all files except deps.json and runtimeconfig.json are extracted to disk. - // The json files are not queried by the host using this method. - assert(entry->needs_extraction()); + extracted_to_disk = entry->needs_extraction(); + full_path.assign(extracted_to_disk ? extraction_path() : base_path()); - full_path.assign(app->extraction_path()); append_path(&full_path, relative_path.c_str()); return true; } + diff --git a/src/installer/corehost/cli/bundle/runner.h b/src/installer/corehost/cli/bundle/runner.h index fb4d74bf877a2f..f632814df8f81e 100644 --- a/src/installer/corehost/cli/bundle/runner.h +++ b/src/installer/corehost/cli/bundle/runner.h @@ -21,20 +21,26 @@ namespace bundle { public: runner_t(const pal::char_t* bundle_path, - const pal::char_t *app_path, - int64_t header_offset) + const pal::char_t* app_path, + int64_t header_offset) : info_t(bundle_path, app_path, header_offset) {} const pal::string_t& extraction_path() const { return m_extraction_path; } - const file_entry_t *probe(const pal::string_t& path) const; - bool locate(const pal::string_t& relative_path, pal::string_t& full_path) const; + bool probe(const pal::string_t& relative_path, int64_t* offset, int64_t* size) const; + const file_entry_t* probe(const pal::string_t& relative_path) const; + bool locate(const pal::string_t& relative_path, pal::string_t& full_path, bool& extracted_to_disk) const; + bool locate(const pal::string_t& relative_path, pal::string_t& full_path) const + { + bool extracted_to_disk; + return locate(relative_path, full_path, extracted_to_disk); + } static StatusCode process_manifest_and_extract() { return ((runner_t*) the_app)->extract(); } - + static const runner_t* app() { return (const runner_t*)the_app; } private: diff --git a/src/installer/corehost/cli/common.cmake b/src/installer/corehost/cli/common.cmake index 5f9289659684c0..1ad7ee619abd8d 100644 --- a/src/installer/corehost/cli/common.cmake +++ b/src/installer/corehost/cli/common.cmake @@ -38,7 +38,7 @@ endif() # This is required to map a symbol reference to a matching definition local to the module (.so) # containing the reference instead of using definitions from other modules. -if(CLR_CMAKE_TARGET_LINUX) +if(CLR_CMAKE_TARGET_LINUX OR CLR_CMAKE_TARGET_SUNOS) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Xlinker -Bsymbolic") endif() diff --git a/src/installer/corehost/cli/coreclr_delegates.h b/src/installer/corehost/cli/coreclr_delegates.h index ca2800b3c05089..7e0dd1ac92f393 100644 --- a/src/installer/corehost/cli/coreclr_delegates.h +++ b/src/installer/corehost/cli/coreclr_delegates.h @@ -19,12 +19,16 @@ typedef char char_t; #endif +#define UNMANAGEDCALLERSONLY_METHOD ((const char_t*)-1) + // Signature of delegate returned by coreclr_delegate_type::load_assembly_and_get_function_pointer typedef int (CORECLR_DELEGATE_CALLTYPE *load_assembly_and_get_function_pointer_fn)( const char_t *assembly_path /* Fully qualified path to assembly */, const char_t *type_name /* Assembly qualified type name */, const char_t *method_name /* Public static method name compatible with delegateType */, - const char_t *delegate_type_name /* Assembly qualified delegate type name or null */, + const char_t *delegate_type_name /* Assembly qualified delegate type name or null + or UNMANAGEDCALLERSONLY_METHOD if the method is marked with + the UnmanagedCallersOnlyAttribute. */, void *reserved /* Extensibility parameter (currently unused and must be 0) */, /*out*/ void **delegate /* Pointer where to store the function pointer result */); diff --git a/src/installer/corehost/cli/deps_entry.cpp b/src/installer/corehost/cli/deps_entry.cpp index 449403fa038e2f..85c845047da4c9 100644 --- a/src/installer/corehost/cli/deps_entry.cpp +++ b/src/installer/corehost/cli/deps_entry.cpp @@ -38,11 +38,12 @@ static pal::string_t normalize_dir_separator(const pal::string_t& path) // Returns: // If the file exists in the path relative to the "base" directory within the // single-file or on disk. -bool deps_entry_t::to_path(const pal::string_t& base, const pal::string_t& ietf_dir, bool look_in_base, bool look_in_bundle, pal::string_t* str) const +bool deps_entry_t::to_path(const pal::string_t& base, const pal::string_t& ietf_dir, bool look_in_base, bool look_in_bundle, pal::string_t* str, bool &loaded_from_bundle) const { pal::string_t& candidate = *str; candidate.clear(); + loaded_from_bundle = false; // Base directory must be present to obtain full path if (base.empty()) @@ -67,9 +68,11 @@ bool deps_entry_t::to_path(const pal::string_t& base, const pal::string_t& ietf_ { // If sub_path is found in the single-file bundle, // app::locate() will set candidate to the full-path to the assembly extracted out to disk. - if (app->locate(sub_path, candidate)) + bool extracted_to_disk = false; + if (app->locate(sub_path, candidate, extracted_to_disk)) { - trace::verbose(_X(" %s found in bundle [%s]"), sub_path.c_str(), candidate.c_str()); + loaded_from_bundle = !extracted_to_disk; + trace::verbose(_X(" %s found in bundle [%s] %s"), sub_path.c_str(), candidate.c_str(), extracted_to_disk ? _X("(extracted)") : _X("")); return true; } else @@ -112,7 +115,7 @@ bool deps_entry_t::to_path(const pal::string_t& base, const pal::string_t& ietf_ // Returns: // If the file exists in the path relative to the "base" directory. // -bool deps_entry_t::to_dir_path(const pal::string_t& base, bool look_in_bundle, pal::string_t* str) const +bool deps_entry_t::to_dir_path(const pal::string_t& base, bool look_in_bundle, pal::string_t* str, bool& loaded_from_bundle) const { pal::string_t ietf_dir; @@ -134,7 +137,7 @@ bool deps_entry_t::to_dir_path(const pal::string_t& base, bool look_in_bundle, p base.c_str(), ietf_dir.c_str(), asset.name.c_str()); } - return to_path(base, ietf_dir, true, look_in_bundle, str); + return to_path(base, ietf_dir, true, look_in_bundle, str, loaded_from_bundle); } // ----------------------------------------------------------------------------- @@ -150,7 +153,10 @@ bool deps_entry_t::to_dir_path(const pal::string_t& base, bool look_in_bundle, p // bool deps_entry_t::to_rel_path(const pal::string_t& base, bool look_in_bundle, pal::string_t* str) const { - return to_path(base, _X(""), false, look_in_bundle, str); + bool loaded_from_bundle; + bool result = to_path(base, _X(""), false, look_in_bundle, str, loaded_from_bundle); + assert(!loaded_from_bundle); + return result; } // ----------------------------------------------------------------------------- diff --git a/src/installer/corehost/cli/deps_entry.h b/src/installer/corehost/cli/deps_entry.h index 2c66b1f0552732..a8e994bef5b21b 100644 --- a/src/installer/corehost/cli/deps_entry.h +++ b/src/installer/corehost/cli/deps_entry.h @@ -53,7 +53,7 @@ struct deps_entry_t bool is_rid_specific; // Given a "base" dir, yield the file path within this directory or single-file bundle. - bool to_dir_path(const pal::string_t& base, bool look_in_bundle, pal::string_t* str) const; + bool to_dir_path(const pal::string_t& base, bool look_in_bundle, pal::string_t* str, bool& loaded_from_bundle) const; // Given a "base" dir, yield the relative path in the package layout. bool to_rel_path(const pal::string_t& base, bool look_in_bundle, pal::string_t* str) const; @@ -64,7 +64,7 @@ struct deps_entry_t private: // Given a "base" dir, yield the filepath within this directory or relative to this directory based on "look_in_base" // Returns a path within the single-file bundle, or a file on disk, - bool to_path(const pal::string_t& base, const pal::string_t& ietf_code, bool look_in_base, bool look_in_bundle, pal::string_t* str) const; + bool to_path(const pal::string_t& base, const pal::string_t& ietf_code, bool look_in_base, bool look_in_bundle, pal::string_t* str, bool & loaded_from_bundle) const; }; #endif // __DEPS_ENTRY_H_ diff --git a/src/installer/corehost/cli/dotnet/CMakeLists.txt b/src/installer/corehost/cli/dotnet/CMakeLists.txt index 4527986acfe3c6..798ae4030ea0a0 100644 --- a/src/installer/corehost/cli/dotnet/CMakeLists.txt +++ b/src/installer/corehost/cli/dotnet/CMakeLists.txt @@ -10,4 +10,8 @@ if(CLR_CMAKE_TARGET_WIN32) dotnet.manifest) endif() +list(APPEND SOURCES + ../apphost/standalone/hostfxr_resolver_t.cpp +) + include(../exe.cmake) diff --git a/src/installer/corehost/cli/exe.cmake b/src/installer/corehost/cli/exe.cmake index de8cd49396bd80..3acc130174aa3f 100644 --- a/src/installer/corehost/cli/exe.cmake +++ b/src/installer/corehost/cli/exe.cmake @@ -8,6 +8,7 @@ cmake_policy(SET CMP0011 NEW) cmake_policy(SET CMP0083 NEW) include(${CMAKE_CURRENT_LIST_DIR}/common.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/hostmisc/hostmisc.cmake) # Include directories include_directories(${CMAKE_CURRENT_LIST_DIR}/fxr) @@ -17,9 +18,11 @@ list(APPEND SOURCES ${CMAKE_CURRENT_LIST_DIR}/fxr_resolver.cpp ${CMAKE_CURRENT_LIST_DIR}/../corehost.cpp ) +list(APPEND HEADERS + ${CMAKE_CURRENT_LIST_DIR}/../hostfxr_resolver_t.h +) add_executable(${DOTNET_PROJECT_NAME} ${SOURCES} ${RESOURCES}) -target_link_libraries(${DOTNET_PROJECT_NAME} libhostmisc) if(NOT CLR_CMAKE_TARGET_WIN32) disable_pax_mprotect(${DOTNET_PROJECT_NAME}) diff --git a/src/installer/corehost/cli/fxr/CMakeLists.txt b/src/installer/corehost/cli/fxr/CMakeLists.txt index 216ecbf076bb7b..ec7e8e3e2ce4b0 100644 --- a/src/installer/corehost/cli/fxr/CMakeLists.txt +++ b/src/installer/corehost/cli/fxr/CMakeLists.txt @@ -2,46 +2,5 @@ # The .NET Foundation licenses this file to you under the MIT license. # See the LICENSE file in the project root for more information. -project(hostfxr) - -set(DOTNET_PROJECT_NAME "hostfxr") - -# Include directories -include_directories(../json) - -# CMake does not recommend using globbing since it messes with the freshness checks -set(SOURCES - ./command_line.cpp - ./corehost_init.cpp - ./hostfxr.cpp - ./fx_muxer.cpp - ./fx_resolver.cpp - ./fx_resolver.messages.cpp - ./framework_info.cpp - ./host_context.cpp - ./hostpolicy_resolver.cpp - ./sdk_info.cpp - ./sdk_resolver.cpp -) - -set(HEADERS - ../corehost_context_contract.h - ../hostpolicy.h - ../fx_definition.h - ../fx_reference.h - ../roll_fwd_on_no_candidate_fx_option.h - ./command_line.h - ./corehost_init.h - ./fx_muxer.h - ./fx_resolver.h - ./framework_info.h - ./host_context.h - ./hostpolicy_resolver.h - ./sdk_info.h - ./sdk_resolver.h -) - -include(../lib.cmake) - -install_with_stripped_symbols(hostfxr TARGETS corehost) -target_link_libraries(hostfxr libhostcommon) +add_subdirectory(static) +add_subdirectory(standalone) diff --git a/src/installer/corehost/cli/fxr/fx_muxer.cpp b/src/installer/corehost/cli/fxr/fx_muxer.cpp index 31c8c177978078..f41e9095ef0648 100644 --- a/src/installer/corehost/cli/fxr/fx_muxer.cpp +++ b/src/installer/corehost/cli/fxr/fx_muxer.cpp @@ -66,16 +66,11 @@ namespace } } -template int load_hostpolicy( const pal::string_t& lib_dir, pal::dll_t* h_host, - hostpolicy_contract_t &hostpolicy_contract, - const char *main_entry_symbol, - T* main_fn) + hostpolicy_contract_t& hostpolicy_contract) { - assert(main_entry_symbol != nullptr && main_fn != nullptr); - int rc = hostpolicy_resolver::load(lib_dir, h_host, hostpolicy_contract); if (rc != StatusCode::Success) { @@ -83,11 +78,6 @@ int load_hostpolicy( return rc; } - // Obtain entrypoint symbol - *main_fn = reinterpret_cast(pal::get_symbol(*h_host, main_entry_symbol)); - if (*main_fn == nullptr) - return StatusCode::CoreHostEntryPointFailure; - return StatusCode::Success; } @@ -114,7 +104,18 @@ static int execute_app( hostpolicy_contract_t hostpolicy_contract{}; corehost_main_fn host_main = nullptr; - int code = load_hostpolicy(impl_dll_dir, &hostpolicy_dll, hostpolicy_contract, "corehost_main", &host_main); + int code = load_hostpolicy(impl_dll_dir, &hostpolicy_dll, hostpolicy_contract); + + // Obtain entrypoint symbol + if (code == StatusCode::Success) + { + host_main = hostpolicy_contract.corehost_main; + if (host_main == nullptr) + { + code = StatusCode::CoreHostEntryPointFailure; + } + } + if (code != StatusCode::Success) { handle_initialize_failure_or_abort(); @@ -164,7 +165,18 @@ static int execute_host_command( hostpolicy_contract_t hostpolicy_contract{}; corehost_main_with_output_buffer_fn host_main = nullptr; - int code = load_hostpolicy(impl_dll_dir, &hostpolicy_dll, hostpolicy_contract, "corehost_main_with_output_buffer", &host_main); + int code = load_hostpolicy(impl_dll_dir, &hostpolicy_dll, hostpolicy_contract); + + // Obtain entrypoint symbol + if (code == StatusCode::Success) + { + host_main = hostpolicy_contract.corehost_main_with_output_buffer; + if (host_main == nullptr) + { + code = StatusCode::CoreHostEntryPointFailure; + } + } + if (code != StatusCode::Success) return code; @@ -471,7 +483,7 @@ namespace if (!hostpolicy_resolver::try_get_dir(mode, host_info.dotnet_root, fx_definitions, app_candidate, deps_file, probe_realpaths, &hostpolicy_dir)) { - return CoreHostLibMissingFailure; + return StatusCode::CoreHostLibMissingFailure; } init.reset(new corehost_init_t(host_command, host_info, deps_file, additional_deps_serialized, probe_realpaths, mode, fx_definitions)); diff --git a/src/installer/corehost/cli/fxr/hostfxr.cpp b/src/installer/corehost/cli/fxr/hostfxr.cpp index 1fdfa210489358..23418b03da032c 100644 --- a/src/installer/corehost/cli/fxr/hostfxr.cpp +++ b/src/installer/corehost/cli/fxr/hostfxr.cpp @@ -438,7 +438,7 @@ namespace if (startup_info.dotnet_root.empty()) { pal::string_t mod_path; - if (!pal::get_own_module_path(&mod_path)) + if (!pal::get_method_module_path(&mod_path, (void*)&hostfxr_set_error_writer)) return StatusCode::CoreHostCurHostFindFailure; startup_info.dotnet_root = get_dotnet_root_from_fxr_path(mod_path); diff --git a/src/installer/corehost/cli/fxr/hostpolicy_resolver.cpp b/src/installer/corehost/cli/fxr/hostpolicy_resolver.cpp deleted file mode 100644 index de3291fecc5b53..00000000000000 --- a/src/installer/corehost/cli/fxr/hostpolicy_resolver.cpp +++ /dev/null @@ -1,321 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#include -#include -#include -#include "hostpolicy_resolver.h" -#include -#include -#include -#include - -#include "json_parser.h" - -namespace -{ - std::mutex g_hostpolicy_lock; - pal::dll_t g_hostpolicy; - hostpolicy_contract_t g_hostpolicy_contract; - pal::string_t g_hostpolicy_dir; - - /** - * Resolve the hostpolicy version from deps. - * - Scan the deps file's libraries section and find the hostpolicy version in the file. - */ - pal::string_t resolve_hostpolicy_version_from_deps(const pal::string_t& deps_json) - { - trace::verbose(_X("--- Resolving %s version from deps json [%s]"), LIBHOSTPOLICY_NAME, deps_json.c_str()); - - pal::string_t retval; - json_parser_t json; - if (!json.parse_file(deps_json)) - { - return retval; - } - - // Look up the root package instead of the "runtime" package because we can't do a full rid resolution. - // i.e., look for "Microsoft.NETCore.DotNetHostPolicy/" followed by version. - pal::string_t prefix = _X("Microsoft.NETCore.DotNetHostPolicy/"); - for (const auto& library : json.document()[_X("libraries")].GetObject()) - { - pal::string_t lib_name{library.name.GetString()}; - if (starts_with(lib_name, prefix, false)) - { - // Extract the version information that occurs after '/' - retval = lib_name.substr(prefix.size()); - break; - } - } - - trace::verbose(_X("Resolved version %s from dependency manifest file [%s]"), retval.c_str(), deps_json.c_str()); - return retval; - } - - /** - * Given a directory and a version, find if the package relative - * dir under the given directory contains hostpolicy.dll - */ - bool to_hostpolicy_package_dir(const pal::string_t& dir, const pal::string_t& version, pal::string_t* candidate) - { - assert(!version.empty()); - - candidate->clear(); - - // Ensure the relative dir contains platform directory separators. - pal::string_t rel_dir = _STRINGIFY(HOST_POLICY_PKG_REL_DIR); - if (DIR_SEPARATOR != '/') - { - replace_char(&rel_dir, '/', DIR_SEPARATOR); - } - - // Construct the path to directory containing hostpolicy. - pal::string_t path = dir; - append_path(&path, _STRINGIFY(HOST_POLICY_PKG_NAME)); // package name - append_path(&path, version.c_str()); // package version - append_path(&path, rel_dir.c_str()); // relative dir containing hostpolicy library - - // Check if "path" contains the required library. - if (!library_exists_in_dir(path, LIBHOSTPOLICY_NAME, nullptr)) - { - trace::verbose(_X("Did not find %s in directory %s"), LIBHOSTPOLICY_NAME, path.c_str()); - return false; - } - - // "path" contains the directory containing hostpolicy library. - *candidate = path; - - trace::verbose(_X("Found %s in directory %s"), LIBHOSTPOLICY_NAME, path.c_str()); - return true; - } - - /** - * Given a nuget version, detect if a serviced hostpolicy is available at - * platform servicing location. - */ - bool hostpolicy_exists_in_svc(const pal::string_t& version, pal::string_t* resolved_dir) - { - if (version.empty()) - { - return false; - } - - pal::string_t svc_dir; - pal::get_default_servicing_directory(&svc_dir); - append_path(&svc_dir, _X("pkgs")); - return to_hostpolicy_package_dir(svc_dir, version, resolved_dir); - } - - /** - * Given a version and probing paths, find if package layout - * directory containing hostpolicy exists. - */ - bool resolve_hostpolicy_dir_from_probe_paths(const pal::string_t& version, const std::vector& probe_realpaths, pal::string_t* candidate) - { - if (probe_realpaths.empty() || version.empty()) - { - return false; - } - - // Check if the package relative directory containing hostpolicy exists. - for (const auto& probe_path : probe_realpaths) - { - trace::verbose(_X("Considering %s to probe for %s"), probe_path.c_str(), LIBHOSTPOLICY_NAME); - if (to_hostpolicy_package_dir(probe_path, version, candidate)) - { - return true; - } - } - - // Print detailed message about the file not found in the probe paths. - trace::error(_X("Could not find required library %s in %d probing paths:"), - LIBHOSTPOLICY_NAME, probe_realpaths.size()); - for (const auto& path : probe_realpaths) - { - trace::error(_X(" %s"), path.c_str()); - } - return false; - } - - /** - * Return name of deps file for app. - */ - pal::string_t get_deps_file( - bool is_framework_dependent, - const pal::string_t& app_candidate, - const pal::string_t& specified_deps_file, - const fx_definition_vector_t& fx_definitions - ) - { - if (is_framework_dependent) - { - // The hostpolicy is resolved from the root framework's name and location. - pal::string_t deps_file = get_root_framework(fx_definitions).get_dir(); - if (!deps_file.empty() && deps_file.back() != DIR_SEPARATOR) - { - deps_file.push_back(DIR_SEPARATOR); - } - - return deps_file + get_root_framework(fx_definitions).get_name() + _X(".deps.json"); - } - else - { - // Self-contained app's hostpolicy is from specified deps or from app deps. - return !specified_deps_file.empty() ? specified_deps_file : get_deps_from_app_binary(get_directory(app_candidate), app_candidate); - } - } -} - -int hostpolicy_resolver::load( - const pal::string_t& lib_dir, - pal::dll_t* dll, - hostpolicy_contract_t &hostpolicy_contract) -{ - std::lock_guard lock{ g_hostpolicy_lock }; - if (g_hostpolicy == nullptr) - { - pal::string_t host_path; - if (!library_exists_in_dir(lib_dir, LIBHOSTPOLICY_NAME, &host_path)) - { - return StatusCode::CoreHostLibMissingFailure; - } - - // Load library - // We expect to leak hostpolicy - just as we do not unload coreclr, we do not unload hostpolicy - if (!pal::load_library(&host_path, &g_hostpolicy)) - { - trace::info(_X("Load library of %s failed"), host_path.c_str()); - return StatusCode::CoreHostLibLoadFailure; - } - - // Obtain entrypoint symbols - g_hostpolicy_contract.load = reinterpret_cast(pal::get_symbol(g_hostpolicy, "corehost_load")); - g_hostpolicy_contract.unload = reinterpret_cast(pal::get_symbol(g_hostpolicy, "corehost_unload")); - if ((g_hostpolicy_contract.load == nullptr) || (g_hostpolicy_contract.unload == nullptr)) - return StatusCode::CoreHostEntryPointFailure; - - g_hostpolicy_contract.set_error_writer = reinterpret_cast(pal::get_symbol(g_hostpolicy, "corehost_set_error_writer")); - g_hostpolicy_contract.initialize = reinterpret_cast(pal::get_symbol(g_hostpolicy, "corehost_initialize")); - - // It's possible to not have corehost_set_error_writer and corehost_initialize. These were - // introduced in 3.0, so 2.0 hostpolicy would not have the exports. In this case, we will - // not propagate the error writer and errors will still be reported to stderr. Callers are - // responsible for checking that the function pointers are not null before using them. - - g_hostpolicy_dir = lib_dir; - } - else - { - if (!pal::are_paths_equal_with_normalized_casing(g_hostpolicy_dir, lib_dir)) - trace::warning(_X("The library %s was already loaded from [%s]. Reusing the existing library for the request to load from [%s]"), LIBHOSTPOLICY_NAME, g_hostpolicy_dir.c_str(), lib_dir.c_str()); - } - - // Return global values - *dll = g_hostpolicy; - hostpolicy_contract = g_hostpolicy_contract; - - return StatusCode::Success; -} - -/** -* Return location that is expected to contain hostpolicy -*/ -bool hostpolicy_resolver::try_get_dir( - host_mode_t mode, - const pal::string_t& dotnet_root, - const fx_definition_vector_t& fx_definitions, - const pal::string_t& app_candidate, - const pal::string_t& specified_deps_file, - const std::vector& probe_realpaths, - pal::string_t* impl_dir) -{ - bool is_framework_dependent = get_app(fx_definitions).get_runtime_config().get_is_framework_dependent(); - - // Obtain deps file for the given configuration. - pal::string_t resolved_deps = get_deps_file(is_framework_dependent, app_candidate, specified_deps_file, fx_definitions); - - // Resolve hostpolicy version out of the deps file. - pal::string_t version = resolve_hostpolicy_version_from_deps(resolved_deps); - if (trace::is_enabled() && version.empty() && pal::file_exists(resolved_deps)) - { - trace::warning(_X("Dependency manifest %s does not contain an entry for %s"), - resolved_deps.c_str(), _STRINGIFY(HOST_POLICY_PKG_NAME)); - } - - // Check if the given version of the hostpolicy exists in servicing. - if (hostpolicy_exists_in_svc(version, impl_dir)) - { - return true; - } - - // Get the expected directory that would contain hostpolicy. - pal::string_t expected; - if (is_framework_dependent) - { - // The hostpolicy is required to be in the root framework's location - expected.assign(get_root_framework(fx_definitions).get_dir()); - assert(pal::directory_exists(expected)); - } - else - { - // Native apps can be activated by muxer, native exe host or "corehost" - // 1. When activated with dotnet.exe or corehost.exe, check for hostpolicy in the deps dir or - // app dir. - // 2. When activated with native exe, the standalone host, check own directory. - assert(mode != host_mode_t::invalid); - switch (mode) - { - case host_mode_t::apphost: - case host_mode_t::libhost: - expected = dotnet_root; - break; - - default: - expected = get_directory(specified_deps_file.empty() ? app_candidate : specified_deps_file); - break; - } - } - - // Check if hostpolicy exists in "expected" directory. - trace::verbose(_X("The expected %s directory is [%s]"), LIBHOSTPOLICY_NAME, expected.c_str()); - if (library_exists_in_dir(expected, LIBHOSTPOLICY_NAME, nullptr)) - { - impl_dir->assign(expected); - return true; - } - - trace::verbose(_X("The %s was not found in [%s]"), LIBHOSTPOLICY_NAME, expected.c_str()); - - // Start probing for hostpolicy in the specified probe paths. - pal::string_t candidate; - if (resolve_hostpolicy_dir_from_probe_paths(version, probe_realpaths, &candidate)) - { - impl_dir->assign(candidate); - return true; - } - - // If it still couldn't be found, somebody upstack messed up. Flag an error for the "expected" location. - trace::error(_X("A fatal error was encountered. The library '%s' required to execute the application was not found in '%s'."), - LIBHOSTPOLICY_NAME, expected.c_str()); - if ((mode == host_mode_t::muxer || mode == host_mode_t::apphost) && !is_framework_dependent) - { - trace::error(_X("Failed to run as a self-contained app.")); - const pal::string_t config_file_name = get_app(fx_definitions).get_runtime_config().get_path(); - if (!pal::file_exists(config_file_name)) - { - trace::error(_X(" - The application was run as a self-contained app because '%s' was not found."), - config_file_name.c_str()); - trace::error(_X(" - If this should be a framework-dependent app, add the '%s' file and specify the appropriate framework."), - config_file_name.c_str()); - } - else if (get_app(fx_definitions).get_name().empty()) - { - trace::error(_X(" - The application was run as a self-contained app because '%s' did not specify a framework."), - config_file_name.c_str()); - trace::error(_X(" - If this should be a framework-dependent app, specify the appropriate framework in '%s'."), - config_file_name.c_str()); - } - } - return false; -} diff --git a/src/installer/corehost/cli/fxr/hostpolicy_resolver.h b/src/installer/corehost/cli/fxr/hostpolicy_resolver.h index 4348a53c778e02..35128327b7bca2 100644 --- a/src/installer/corehost/cli/fxr/hostpolicy_resolver.h +++ b/src/installer/corehost/cli/fxr/hostpolicy_resolver.h @@ -20,6 +20,10 @@ struct hostpolicy_contract_t // 3.0+ contracts corehost_set_error_writer_fn set_error_writer; corehost_initialize_fn initialize; + + // 5.0+ contracts + corehost_main_fn corehost_main; + corehost_main_with_output_buffer_fn corehost_main_with_output_buffer; }; namespace hostpolicy_resolver @@ -38,4 +42,4 @@ namespace hostpolicy_resolver pal::string_t* impl_dir); }; -#endif // __HOSTPOLICY_RESOLVER_H__ \ No newline at end of file +#endif // __HOSTPOLICY_RESOLVER_H__ diff --git a/src/installer/corehost/cli/fxr/standalone/CMakeLists.txt b/src/installer/corehost/cli/fxr/standalone/CMakeLists.txt new file mode 100644 index 00000000000000..0a2ea92174b6f1 --- /dev/null +++ b/src/installer/corehost/cli/fxr/standalone/CMakeLists.txt @@ -0,0 +1,65 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +project(hostfxr) + +set(DOTNET_PROJECT_NAME "hostfxr") + +# Include directories +include_directories(../../json) +include_directories(../../fxr) + +# CMake does not recommend using globbing since it messes with the freshness checks +set(SOURCES + ./hostpolicy_resolver.cpp +) + +set(HEADERS + ../command_line.h + ../corehost_init.h + ../fx_muxer.h + ../fx_resolver.h + ../framework_info.h + ../host_context.h + ../sdk_info.h + ../sdk_resolver.h + ../hostpolicy_resolver.h +) + +if(CLR_CMAKE_TARGET_WIN32) + list(APPEND SOURCES + hostfxr.def) +else(CLR_CMAKE_TARGET_WIN32) + set(DEF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/hostfxr_unixexports.src) + set(EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/hostfxr.exports) + generate_exports_file(${DEF_SOURCES} ${EXPORTS_FILE}) + + if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) + # Add linker exports file option + set(EXPORTS_LINKER_OPTION -Wl,--version-script=${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) + + if(CLR_CMAKE_HOST_OSX) + # Add linker exports file option + set(EXPORTS_LINKER_OPTION -Wl,-exported_symbols_list,${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_OSX) + + if(CLR_CMAKE_HOST_SUNOS) + # Add linker exports file option + set(EXPORTS_LINKER_OPTION -Wl,-M,${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_SUNOS) +endif(CLR_CMAKE_TARGET_WIN32) + +include(../../lib.cmake) + +if(CLR_CMAKE_HOST_UNIX) + add_custom_target(hostfxr_exports DEPENDS ${EXPORTS_FILE}) + add_dependencies(hostfxr hostfxr_exports) + + set_property(TARGET hostfxr APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION}) + set_property(TARGET hostfxr APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE}) +endif(CLR_CMAKE_HOST_UNIX) + +install_with_stripped_symbols(hostfxr TARGETS corehost) +target_link_libraries(hostfxr libhostcommon libhostfxr_static) diff --git a/src/installer/corehost/cli/fxr/standalone/hostfxr.def b/src/installer/corehost/cli/fxr/standalone/hostfxr.def new file mode 100644 index 00000000000000..c86139a7fb58be --- /dev/null +++ b/src/installer/corehost/cli/fxr/standalone/hostfxr.def @@ -0,0 +1,21 @@ +; Licensed to the .NET Foundation under one or more agreements. +; The .NET Foundation licenses this file to you under the MIT license. +; See the LICENSE file in the project root for more information. + +EXPORTS + hostfxr_main_bundle_startupinfo + hostfxr_main_startupinfo + hostfxr_main + hostfxr_resolve_sdk + hostfxr_resolve_sdk2 + hostfxr_get_available_sdks + hostfxr_get_native_search_directories + hostfxr_set_error_writer + hostfxr_initialize_for_dotnet_command_line + hostfxr_initialize_for_runtime_config + hostfxr_run_app + hostfxr_get_runtime_delegate + hostfxr_get_runtime_property_value + hostfxr_set_runtime_property_value + hostfxr_get_runtime_properties + hostfxr_close diff --git a/src/installer/corehost/cli/fxr/standalone/hostfxr_unixexports.src b/src/installer/corehost/cli/fxr/standalone/hostfxr_unixexports.src new file mode 100644 index 00000000000000..fcf85d027fa641 --- /dev/null +++ b/src/installer/corehost/cli/fxr/standalone/hostfxr_unixexports.src @@ -0,0 +1,20 @@ +; Licensed to the .NET Foundation under one or more agreements. +; The .NET Foundation licenses this file to you under the MIT license. +; See the LICENSE file in the project root for more information. + +hostfxr_main_bundle_startupinfo +hostfxr_main_startupinfo +hostfxr_main +hostfxr_resolve_sdk +hostfxr_resolve_sdk2 +hostfxr_get_available_sdks +hostfxr_get_native_search_directories +hostfxr_set_error_writer +hostfxr_initialize_for_dotnet_command_line +hostfxr_initialize_for_runtime_config +hostfxr_run_app +hostfxr_get_runtime_delegate +hostfxr_get_runtime_property_value +hostfxr_set_runtime_property_value +hostfxr_get_runtime_properties +hostfxr_close diff --git a/src/installer/corehost/cli/fxr/standalone/hostpolicy_resolver.cpp b/src/installer/corehost/cli/fxr/standalone/hostpolicy_resolver.cpp new file mode 100644 index 00000000000000..67881d207944f9 --- /dev/null +++ b/src/installer/corehost/cli/fxr/standalone/hostpolicy_resolver.cpp @@ -0,0 +1,324 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include +#include +#include "hostpolicy_resolver.h" +#include +#include +#include +#include + +#include "json_parser.h" + +namespace +{ + std::mutex g_hostpolicy_lock; + pal::dll_t g_hostpolicy; + hostpolicy_contract_t g_hostpolicy_contract; + pal::string_t g_hostpolicy_dir; + + /** + * Resolve the hostpolicy version from deps. + * - Scan the deps file's libraries section and find the hostpolicy version in the file. + */ + pal::string_t resolve_hostpolicy_version_from_deps(const pal::string_t& deps_json) + { + trace::verbose(_X("--- Resolving %s version from deps json [%s]"), LIBHOSTPOLICY_NAME, deps_json.c_str()); + + pal::string_t retval; + json_parser_t json; + if (!json.parse_file(deps_json)) + { + return retval; + } + + // Look up the root package instead of the "runtime" package because we can't do a full rid resolution. + // i.e., look for "Microsoft.NETCore.DotNetHostPolicy/" followed by version. + pal::string_t prefix = _X("Microsoft.NETCore.DotNetHostPolicy/"); + for (const auto& library : json.document()[_X("libraries")].GetObject()) + { + pal::string_t lib_name{library.name.GetString()}; + if (starts_with(lib_name, prefix, false)) + { + // Extract the version information that occurs after '/' + retval = lib_name.substr(prefix.size()); + break; + } + } + + trace::verbose(_X("Resolved version %s from dependency manifest file [%s]"), retval.c_str(), deps_json.c_str()); + return retval; + } + + /** + * Given a directory and a version, find if the package relative + * dir under the given directory contains hostpolicy.dll + */ + bool to_hostpolicy_package_dir(const pal::string_t& dir, const pal::string_t& version, pal::string_t* candidate) + { + assert(!version.empty()); + + candidate->clear(); + + // Ensure the relative dir contains platform directory separators. + pal::string_t rel_dir = _STRINGIFY(HOST_POLICY_PKG_REL_DIR); + if (DIR_SEPARATOR != '/') + { + replace_char(&rel_dir, '/', DIR_SEPARATOR); + } + + // Construct the path to directory containing hostpolicy. + pal::string_t path = dir; + append_path(&path, _STRINGIFY(HOST_POLICY_PKG_NAME)); // package name + append_path(&path, version.c_str()); // package version + append_path(&path, rel_dir.c_str()); // relative dir containing hostpolicy library + + // Check if "path" contains the required library. + if (!library_exists_in_dir(path, LIBHOSTPOLICY_NAME, nullptr)) + { + trace::verbose(_X("Did not find %s in directory %s"), LIBHOSTPOLICY_NAME, path.c_str()); + return false; + } + + // "path" contains the directory containing hostpolicy library. + *candidate = path; + + trace::verbose(_X("Found %s in directory %s"), LIBHOSTPOLICY_NAME, path.c_str()); + return true; + } + + /** + * Given a nuget version, detect if a serviced hostpolicy is available at + * platform servicing location. + */ + bool hostpolicy_exists_in_svc(const pal::string_t& version, pal::string_t* resolved_dir) + { + if (version.empty()) + { + return false; + } + + pal::string_t svc_dir; + pal::get_default_servicing_directory(&svc_dir); + append_path(&svc_dir, _X("pkgs")); + return to_hostpolicy_package_dir(svc_dir, version, resolved_dir); + } + + /** + * Given a version and probing paths, find if package layout + * directory containing hostpolicy exists. + */ + bool resolve_hostpolicy_dir_from_probe_paths(const pal::string_t& version, const std::vector& probe_realpaths, pal::string_t* candidate) + { + if (probe_realpaths.empty() || version.empty()) + { + return false; + } + + // Check if the package relative directory containing hostpolicy exists. + for (const auto& probe_path : probe_realpaths) + { + trace::verbose(_X("Considering %s to probe for %s"), probe_path.c_str(), LIBHOSTPOLICY_NAME); + if (to_hostpolicy_package_dir(probe_path, version, candidate)) + { + return true; + } + } + + // Print detailed message about the file not found in the probe paths. + trace::error(_X("Could not find required library %s in %d probing paths:"), + LIBHOSTPOLICY_NAME, probe_realpaths.size()); + for (const auto& path : probe_realpaths) + { + trace::error(_X(" %s"), path.c_str()); + } + return false; + } + + /** + * Return name of deps file for app. + */ + pal::string_t get_deps_file( + bool is_framework_dependent, + const pal::string_t& app_candidate, + const pal::string_t& specified_deps_file, + const fx_definition_vector_t& fx_definitions + ) + { + if (is_framework_dependent) + { + // The hostpolicy is resolved from the root framework's name and location. + pal::string_t deps_file = get_root_framework(fx_definitions).get_dir(); + if (!deps_file.empty() && deps_file.back() != DIR_SEPARATOR) + { + deps_file.push_back(DIR_SEPARATOR); + } + + return deps_file + get_root_framework(fx_definitions).get_name() + _X(".deps.json"); + } + else + { + // Self-contained app's hostpolicy is from specified deps or from app deps. + return !specified_deps_file.empty() ? specified_deps_file : get_deps_from_app_binary(get_directory(app_candidate), app_candidate); + } + } +} + +int hostpolicy_resolver::load( + const pal::string_t& lib_dir, + pal::dll_t* dll, + hostpolicy_contract_t &hostpolicy_contract) +{ + std::lock_guard lock{ g_hostpolicy_lock }; + if (g_hostpolicy == nullptr) + { + pal::string_t host_path; + if (!library_exists_in_dir(lib_dir, LIBHOSTPOLICY_NAME, &host_path)) + { + return StatusCode::CoreHostLibMissingFailure; + } + + // Load library + // We expect to leak hostpolicy - just as we do not unload coreclr, we do not unload hostpolicy + if (!pal::load_library(&host_path, &g_hostpolicy)) + { + trace::info(_X("Load library of %s failed"), host_path.c_str()); + return StatusCode::CoreHostLibLoadFailure; + } + + // Obtain entrypoint symbols + g_hostpolicy_contract.load = reinterpret_cast(pal::get_symbol(g_hostpolicy, "corehost_load")); + g_hostpolicy_contract.unload = reinterpret_cast(pal::get_symbol(g_hostpolicy, "corehost_unload")); + if ((g_hostpolicy_contract.load == nullptr) || (g_hostpolicy_contract.unload == nullptr)) + return StatusCode::CoreHostEntryPointFailure; + + g_hostpolicy_contract.set_error_writer = reinterpret_cast(pal::get_symbol(g_hostpolicy, "corehost_set_error_writer")); + g_hostpolicy_contract.initialize = reinterpret_cast(pal::get_symbol(g_hostpolicy, "corehost_initialize")); + + g_hostpolicy_contract.corehost_main = reinterpret_cast(pal::get_symbol(g_hostpolicy, "corehost_main")); + g_hostpolicy_contract.corehost_main_with_output_buffer = reinterpret_cast(pal::get_symbol(g_hostpolicy, "corehost_main_with_output_buffer")); + + // It's possible to not have corehost_set_error_writer and corehost_initialize. These were + // introduced in 3.0, so 2.0 hostpolicy would not have the exports. In this case, we will + // not propagate the error writer and errors will still be reported to stderr. Callers are + // responsible for checking that the function pointers are not null before using them. + + g_hostpolicy_dir = lib_dir; + } + else + { + if (!pal::are_paths_equal_with_normalized_casing(g_hostpolicy_dir, lib_dir)) + trace::warning(_X("The library %s was already loaded from [%s]. Reusing the existing library for the request to load from [%s]"), LIBHOSTPOLICY_NAME, g_hostpolicy_dir.c_str(), lib_dir.c_str()); + } + + // Return global values + *dll = g_hostpolicy; + hostpolicy_contract = g_hostpolicy_contract; + + return StatusCode::Success; +} + +/** +* Return location that is expected to contain hostpolicy +*/ +bool hostpolicy_resolver::try_get_dir( + host_mode_t mode, + const pal::string_t& dotnet_root, + const fx_definition_vector_t& fx_definitions, + const pal::string_t& app_candidate, + const pal::string_t& specified_deps_file, + const std::vector& probe_realpaths, + pal::string_t* impl_dir) +{ + bool is_framework_dependent = get_app(fx_definitions).get_runtime_config().get_is_framework_dependent(); + + // Obtain deps file for the given configuration. + pal::string_t resolved_deps = get_deps_file(is_framework_dependent, app_candidate, specified_deps_file, fx_definitions); + + // Resolve hostpolicy version out of the deps file. + pal::string_t version = resolve_hostpolicy_version_from_deps(resolved_deps); + if (trace::is_enabled() && version.empty() && pal::file_exists(resolved_deps)) + { + trace::warning(_X("Dependency manifest %s does not contain an entry for %s"), + resolved_deps.c_str(), _STRINGIFY(HOST_POLICY_PKG_NAME)); + } + + // Check if the given version of the hostpolicy exists in servicing. + if (hostpolicy_exists_in_svc(version, impl_dir)) + { + return true; + } + + // Get the expected directory that would contain hostpolicy. + pal::string_t expected; + if (is_framework_dependent) + { + // The hostpolicy is required to be in the root framework's location + expected.assign(get_root_framework(fx_definitions).get_dir()); + assert(pal::directory_exists(expected)); + } + else + { + // Native apps can be activated by muxer, native exe host or "corehost" + // 1. When activated with dotnet.exe or corehost.exe, check for hostpolicy in the deps dir or + // app dir. + // 2. When activated with native exe, the standalone host, check own directory. + assert(mode != host_mode_t::invalid); + switch (mode) + { + case host_mode_t::apphost: + case host_mode_t::libhost: + expected = dotnet_root; + break; + + default: + expected = get_directory(specified_deps_file.empty() ? app_candidate : specified_deps_file); + break; + } + } + + // Check if hostpolicy exists in "expected" directory. + trace::verbose(_X("The expected %s directory is [%s]"), LIBHOSTPOLICY_NAME, expected.c_str()); + if (library_exists_in_dir(expected, LIBHOSTPOLICY_NAME, nullptr)) + { + impl_dir->assign(expected); + return true; + } + + trace::verbose(_X("The %s was not found in [%s]"), LIBHOSTPOLICY_NAME, expected.c_str()); + + // Start probing for hostpolicy in the specified probe paths. + pal::string_t candidate; + if (resolve_hostpolicy_dir_from_probe_paths(version, probe_realpaths, &candidate)) + { + impl_dir->assign(candidate); + return true; + } + + // If it still couldn't be found, somebody upstack messed up. Flag an error for the "expected" location. + trace::error(_X("A fatal error was encountered. The library '%s' required to execute the application was not found in '%s'."), + LIBHOSTPOLICY_NAME, expected.c_str()); + if ((mode == host_mode_t::muxer || mode == host_mode_t::apphost) && !is_framework_dependent) + { + trace::error(_X("Failed to run as a self-contained app.")); + const pal::string_t config_file_name = get_app(fx_definitions).get_runtime_config().get_path(); + if (!pal::file_exists(config_file_name)) + { + trace::error(_X(" - The application was run as a self-contained app because '%s' was not found."), + config_file_name.c_str()); + trace::error(_X(" - If this should be a framework-dependent app, add the '%s' file and specify the appropriate framework."), + config_file_name.c_str()); + } + else if (get_app(fx_definitions).get_name().empty()) + { + trace::error(_X(" - The application was run as a self-contained app because '%s' did not specify a framework."), + config_file_name.c_str()); + trace::error(_X(" - If this should be a framework-dependent app, specify the appropriate framework in '%s'."), + config_file_name.c_str()); + } + } + return false; +} diff --git a/src/installer/corehost/cli/fxr/static/CMakeLists.txt b/src/installer/corehost/cli/fxr/static/CMakeLists.txt new file mode 100644 index 00000000000000..16c0951c5b21b9 --- /dev/null +++ b/src/installer/corehost/cli/fxr/static/CMakeLists.txt @@ -0,0 +1,45 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +project(hostfxr_static) + +set(DOTNET_PROJECT_NAME "hostfxr_static") + +# Include directories +include_directories(../../json) +include_directories(../../fxr) + +# CMake does not recommend using globbing since it messes with the freshness checks +set(SOURCES + ../command_line.cpp + ../corehost_init.cpp + ../hostfxr.cpp + ../fx_muxer.cpp + ../fx_resolver.cpp + ../fx_resolver.messages.cpp + ../framework_info.cpp + ../host_context.cpp + ../sdk_info.cpp + ../sdk_resolver.cpp +) + +set(HEADERS + ../../corehost_context_contract.h + ../../hostpolicy.h + ../../fx_definition.h + ../../fx_reference.h + ../../roll_fwd_on_no_candidate_fx_option.h + ../command_line.h + ../corehost_init.h + ../fx_muxer.h + ../fx_resolver.h + ../framework_info.h + ../host_context.h + ../sdk_info.h + ../sdk_resolver.h +) + +set(SKIP_VERSIONING 1) +set(BUILD_OBJECT_LIBRARY 1) +include(../../lib_static.cmake) diff --git a/src/installer/corehost/cli/hostmisc/CMakeLists.txt b/src/installer/corehost/cli/hostmisc/CMakeLists.txt deleted file mode 100644 index 1b67c65ef7e784..00000000000000 --- a/src/installer/corehost/cli/hostmisc/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -# Licensed to the .NET Foundation under one or more agreements. -# The .NET Foundation licenses this file to you under the MIT license. -# See the LICENSE file in the project root for more information. - -project(hostmisc) - -set(DOTNET_PROJECT_NAME "hostmisc") - -include(configure.cmake) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - -# CMake does not recommend using globbing since it messes with the freshness checks -set(SOURCES - trace.cpp - utils.cpp - ../fxr/fx_ver.cpp -) - -set(HEADERS - trace.h - utils.h - pal.h - ../../error_codes.h - ../fxr/fx_ver.h -) - -if(CLR_CMAKE_TARGET_WIN32) - list(APPEND SOURCES - pal.windows.cpp - longfile.windows.cpp) - list(APPEND HEADERS - longfile.h) -else() - list(APPEND SOURCES - pal.unix.cpp) -endif() - -set(SKIP_VERSIONING 1) -include(../lib_static.cmake) - diff --git a/src/installer/corehost/cli/hostmisc/configure.cmake b/src/installer/corehost/cli/hostmisc/configure.cmake index 68193ace1566ba..1998dc6b26f027 100644 --- a/src/installer/corehost/cli/hostmisc/configure.cmake +++ b/src/installer/corehost/cli/hostmisc/configure.cmake @@ -2,4 +2,4 @@ include(CheckStructHasMember) check_struct_has_member("struct dirent" d_type dirent.h HAVE_DIRENT_D_TYPE) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) +configure_file(${CMAKE_CURRENT_LIST_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) diff --git a/src/installer/corehost/cli/hostmisc/hostmisc.cmake b/src/installer/corehost/cli/hostmisc/hostmisc.cmake new file mode 100644 index 00000000000000..f6813e1293cc36 --- /dev/null +++ b/src/installer/corehost/cli/hostmisc/hostmisc.cmake @@ -0,0 +1,32 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +include(${CMAKE_CURRENT_LIST_DIR}/configure.cmake) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +# CMake does not recommend using globbing since it messes with the freshness checks +list(APPEND SOURCES + ${CMAKE_CURRENT_LIST_DIR}/trace.cpp + ${CMAKE_CURRENT_LIST_DIR}/utils.cpp + ${CMAKE_CURRENT_LIST_DIR}/../fxr/fx_ver.cpp +) + +list(APPEND HEADERS + ${CMAKE_CURRENT_LIST_DIR}/trace.h + ${CMAKE_CURRENT_LIST_DIR}/utils.h + ${CMAKE_CURRENT_LIST_DIR}/pal.h + ${CMAKE_CURRENT_LIST_DIR}/../../error_codes.h + ${CMAKE_CURRENT_LIST_DIR}/../fxr/fx_ver.h +) + +if(CLR_CMAKE_TARGET_WIN32) + list(APPEND SOURCES + ${CMAKE_CURRENT_LIST_DIR}/pal.windows.cpp + ${CMAKE_CURRENT_LIST_DIR}/longfile.windows.cpp) + list(APPEND HEADERS + ${CMAKE_CURRENT_LIST_DIR}/longfile.h) +else() + list(APPEND SOURCES + ${CMAKE_CURRENT_LIST_DIR}/pal.unix.cpp) +endif() diff --git a/src/installer/corehost/cli/hostmisc/pal.h b/src/installer/corehost/cli/hostmisc/pal.h index 10cb0e2c302ae7..1e1f4cf5f5c4f2 100644 --- a/src/installer/corehost/cli/hostmisc/pal.h +++ b/src/installer/corehost/cli/hostmisc/pal.h @@ -79,8 +79,6 @@ #define FALLBACK_HOST_RID _X("linux") #endif -#define LIBCLRJIT_NAME MAKE_LIBNAME("clrjit") - #define LIBCORECLR_FILENAME (LIB_PREFIX _X("coreclr")) #define LIBCORECLR_NAME MAKE_LIBNAME("coreclr") @@ -146,7 +144,9 @@ namespace pal inline int strcasecmp(const char_t* str1, const char_t* str2) { return ::_wcsicmp(str1, str2); } inline int strncmp(const char_t* str1, const char_t* str2, int len) { return ::wcsncmp(str1, str2, len); } inline int strncasecmp(const char_t* str1, const char_t* str2, int len) { return ::_wcsnicmp(str1, str2, len); } - + inline int pathcmp(const pal::string_t &path1, const pal::string_t &path2) { return strcasecmp(path1.c_str(), path2.c_str()); } + inline string_t to_string(int value) { return std::to_wstring(value); } + inline size_t strlen(const char_t* str) { return ::wcslen(str); } inline FILE * file_open(const string_t& path, const char_t* mode) { return ::_wfopen(path.c_str(), mode); } @@ -204,6 +204,8 @@ namespace pal inline int strcasecmp(const char_t* str1, const char_t* str2) { return ::strcasecmp(str1, str2); } inline int strncmp(const char_t* str1, const char_t* str2, int len) { return ::strncmp(str1, str2, len); } inline int strncasecmp(const char_t* str1, const char_t* str2, int len) { return ::strncasecmp(str1, str2, len); } + inline int pathcmp(const pal::string_t& path1, const pal::string_t& path2) { return strcmp(path1.c_str(), path2.c_str()); } + inline string_t to_string(int value) { return std::to_string(value); } inline size_t strlen(const char_t* str) { return ::strlen(str); } inline FILE * file_open(const string_t& path, const char_t* mode) { return fopen(path.c_str(), mode); } @@ -237,7 +239,6 @@ namespace pal return ret; } - string_t to_string(int value); string_t get_timestamp(); bool getcwd(string_t* recv); @@ -248,7 +249,6 @@ namespace pal inline void err_flush() { std::fflush(stderr); } inline void out_flush() { std::fflush(stdout); } - // Based upon https://github.com/dotnet/core-setup/blob/master/src/Microsoft.DotNet.PlatformAbstractions/Native/PlatformApis.cs string_t get_current_os_rid_platform(); inline string_t get_current_os_fallback_rid() { @@ -271,6 +271,7 @@ namespace pal bool get_own_executable_path(string_t* recv); bool get_own_module_path(string_t* recv); + bool get_method_module_path(string_t* recv, void* method); bool get_module_path(dll_t mod, string_t* recv); bool get_current_module(dll_t *mod); bool getenv(const char_t* name, string_t* recv); @@ -297,6 +298,7 @@ namespace pal bool get_default_bundle_extraction_base_dir(string_t& extraction_dir); int xtoi(const char_t* input); + bool unicode_palstring(const char16_t* str, pal::string_t* out); bool get_loaded_library(const char_t *library_name, const char *symbol_name, /*out*/ dll_t *dll, /*out*/ string_t *path); bool load_library(const string_t* path, dll_t* dll); diff --git a/src/installer/corehost/cli/hostmisc/pal.unix.cpp b/src/installer/corehost/cli/hostmisc/pal.unix.cpp index 65338b619bf8c2..a17487636d60ba 100644 --- a/src/installer/corehost/cli/hostmisc/pal.unix.cpp +++ b/src/installer/corehost/cli/hostmisc/pal.unix.cpp @@ -2,6 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if defined(TARGET_FREEBSD) +#define _WITH_GETLINE +#endif + #include "pal.h" #include "utils.h" #include "trace.h" @@ -13,6 +17,8 @@ #include #include #include +#include +#include #include #include "config.h" @@ -35,7 +41,15 @@ #define DT_LNK 10 #endif -pal::string_t pal::to_string(int value) { return std::to_string(value); } +#ifdef __linux__ +#define PAL_CWD_SIZE 0 +#elif defined(MAXPATHLEN) +#define PAL_CWD_SIZE MAXPATHLEN +#elif defined(PATH_MAX) +#define PAL_CWD_SIZE PATH_MAX +#else +#error "Don't know how to obtain max path on this platform" +#endif pal::string_t pal::to_lower(const pal::string_t& in) { @@ -114,7 +128,7 @@ void* pal::mmap_copy_on_write(const string_t& path, size_t* length) bool pal::getcwd(pal::string_t* recv) { recv->clear(); - pal::char_t* buf = ::getcwd(nullptr, 0); + pal::char_t* buf = ::getcwd(nullptr, PAL_CWD_SIZE); if (buf == nullptr) { if (errno == ENOENT) @@ -125,6 +139,7 @@ bool pal::getcwd(pal::string_t* recv) trace::error(_X("getcwd() failed: %s"), strerror(errno)); return false; } + recv->assign(buf); ::free(buf); return true; @@ -250,6 +265,16 @@ int pal::xtoi(const char_t* input) return atoi(input); } +bool pal::unicode_palstring(const char16_t* str, pal::string_t* out) +{ + out->clear(); + + std::wstring_convert, char16_t> conversion; + out->assign(conversion.to_bytes(str)); + + return true; +} + bool pal::is_path_rooted(const pal::string_t& path) { return path.front() == '/'; @@ -754,6 +779,28 @@ bool pal::get_own_executable_path(pal::string_t* recv) } return false; } +#elif defined(__sun) +bool pal::get_own_executable_path(pal::string_t* recv) +{ + const char *path; + if ((path = getexecname()) == NULL) + { + return false; + } + else if (*path != '/') + { + if (!getcwd(recv)) + { + return false; + } + + recv->append("/").append(path); + return true; + } + + recv->assign(path); + return true; +} #else bool pal::get_own_executable_path(pal::string_t* recv) { @@ -774,6 +821,16 @@ bool pal::get_own_module_path(string_t* recv) return true; } +bool pal::get_method_module_path(string_t* recv, void* method) +{ + Dl_info info; + if (dladdr(method, &info) == 0) + return false; + + recv->assign(info.dli_fname); + return true; +} + bool pal::get_module_path(dll_t module, string_t* recv) { return false; diff --git a/src/installer/corehost/cli/hostmisc/pal.windows.cpp b/src/installer/corehost/cli/hostmisc/pal.windows.cpp index f8348a05d167b0..1c724611d72c6f 100644 --- a/src/installer/corehost/cli/hostmisc/pal.windows.cpp +++ b/src/installer/corehost/cli/hostmisc/pal.windows.cpp @@ -49,11 +49,6 @@ pal::string_t pal::to_lower(const pal::string_t& in) return ret; } -pal::string_t pal::to_string(int value) -{ - return std::to_wstring(value); -} - pal::string_t pal::get_timestamp() { std::time_t t = std::time(0); @@ -558,6 +553,16 @@ bool pal::get_own_module_path(string_t* recv) return GetModuleFileNameWrapper(hmod, recv); } +bool pal::get_method_module_path(string_t* recv, void* method) +{ + HMODULE hmod; + if (!GetModuleHandleFromAddress(method, &hmod)) + return false; + + return GetModuleFileNameWrapper(hmod, recv); +} + + bool pal::get_module_path(dll_t mod, string_t* recv) { return GetModuleFileNameWrapper(mod, recv); @@ -605,7 +610,6 @@ bool pal::get_default_bundle_extraction_base_dir(pal::string_t& extraction_dir) return realpath(&extraction_dir); } - static bool wchar_convert_helper(DWORD code_page, const char* cstr, int len, pal::string_t* out) { out->clear(); @@ -649,13 +653,20 @@ bool pal::clr_palstring(const char* cstr, pal::string_t* out) return wchar_convert_helper(CP_UTF8, cstr, ::strlen(cstr), out); } +bool pal::unicode_palstring(const char16_t* str, pal::string_t* out) +{ + out->assign((const wchar_t *)str); + return true; +} + // Return if path is valid and file exists, return true and adjust path as appropriate. bool pal::realpath(string_t* path, bool skip_error_logging) { - if (LongFile::IsNormalized(path->c_str())) + if (LongFile::IsNormalized(*path)) { WIN32_FILE_ATTRIBUTE_DATA data; - if (GetFileAttributesExW(path->c_str(), GetFileExInfoStandard, &data) != 0) + if (path->empty() // An empty path doesn't exist + || GetFileAttributesExW(path->c_str(), GetFileExInfoStandard, &data) != 0) { return true; } diff --git a/src/installer/corehost/cli/hostpolicy/CMakeLists.txt b/src/installer/corehost/cli/hostpolicy/CMakeLists.txt index ca2c78fa27951d..ec7e8e3e2ce4b0 100644 --- a/src/installer/corehost/cli/hostpolicy/CMakeLists.txt +++ b/src/installer/corehost/cli/hostpolicy/CMakeLists.txt @@ -2,47 +2,5 @@ # The .NET Foundation licenses this file to you under the MIT license. # See the LICENSE file in the project root for more information. -project(hostpolicy) - -set(DOTNET_PROJECT_NAME "hostpolicy") - -# Include directories -include_directories(../fxr) -include_directories(../json) - -# CMake does not recommend using globbing since it messes with the freshness checks -set(SOURCES - ./args.cpp - ./breadcrumbs.cpp - ./coreclr.cpp - ./deps_resolver.cpp - ./hostpolicy_context.cpp - ./hostpolicy.cpp - ./hostpolicy_init.cpp - ../bundle/dir_utils.cpp - ../bundle/extractor.cpp - ../bundle/file_entry.cpp - ../bundle/manifest.cpp - ../bundle/runner.cpp -) - -set(HEADERS - ./args.h - ./breadcrumbs.h - ./coreclr.h - ../corehost_context_contract.h - ./deps_resolver.h - ./hostpolicy_context.h - ../hostpolicy.h - ./hostpolicy_init.h - ../bundle/dir_utils.h - ../bundle/extractor.h - ../bundle/file_entry.h - ../bundle/manifest.h - ../bundle/runner.h -) - -include(../lib.cmake) - -install_with_stripped_symbols(hostpolicy TARGETS corehost) -target_link_libraries(hostpolicy libhostcommon) +add_subdirectory(static) +add_subdirectory(standalone) diff --git a/src/installer/corehost/cli/hostpolicy/coreclr.cpp b/src/installer/corehost/cli/hostpolicy/coreclr.cpp index b329a72d85886a..78a2021de05d34 100644 --- a/src/installer/corehost/cli/hostpolicy/coreclr.cpp +++ b/src/installer/corehost/cli/hostpolicy/coreclr.cpp @@ -199,12 +199,11 @@ namespace _X("APP_CONTEXT_DEPS_FILES"), _X("FX_DEPS_FILE"), _X("PROBING_DIRECTORIES"), - _X("FX_PRODUCT_VERSION"), - _X("JIT_PATH"), _X("STARTUP_HOOKS"), _X("APP_PATHS"), _X("APP_NI_PATHS"), - _X("RUNTIME_IDENTIFIER") + _X("RUNTIME_IDENTIFIER"), + _X("BUNDLE_PROBE") }; static_assert((sizeof(PropertyNameMapping) / sizeof(*PropertyNameMapping)) == static_cast(common_property::Last), "Invalid property count"); diff --git a/src/installer/corehost/cli/hostpolicy/coreclr.h b/src/installer/corehost/cli/hostpolicy/coreclr.h index a06e81fe2e346f..998daf4d648e18 100644 --- a/src/installer/corehost/cli/hostpolicy/coreclr.h +++ b/src/installer/corehost/cli/hostpolicy/coreclr.h @@ -62,13 +62,11 @@ enum class common_property AppContextDepsFiles, FxDepsFile, ProbingDirectories, - FxProductVersion, - JitPath, StartUpHooks, AppPaths, AppNIPaths, RuntimeIdentifier, - + BundleProbe, // Sentinel value - new values should be defined above Last }; diff --git a/src/installer/corehost/cli/hostpolicy/deps_resolver.cpp b/src/installer/corehost/cli/hostpolicy/deps_resolver.cpp index 06ededa7e60aab..de3762cb130984 100644 --- a/src/installer/corehost/cli/hostpolicy/deps_resolver.cpp +++ b/src/installer/corehost/cli/hostpolicy/deps_resolver.cpp @@ -281,10 +281,13 @@ void deps_resolver_t::setup_additional_probes(const std::vector& * -- When servicing directories are looked up, look up only if the deps file marks the entry as serviceable. * -- When a deps json based probe is performed, the deps entry's package name and version must match. * -- When looking into a published dir, for rid specific assets lookup rid split folders; for non-rid assets lookup the layout dir. + * The path to the resolved file is returned in candidate out parameter + * If the candidate is embedded within the single-file bundle (rather than an actual file on disk), loaded_from_bundle will be set to true. */ -bool deps_resolver_t::probe_deps_entry(const deps_entry_t& entry, const pal::string_t& deps_dir, int fx_level, pal::string_t* candidate) +bool deps_resolver_t::probe_deps_entry(const deps_entry_t& entry, const pal::string_t& deps_dir, int fx_level, pal::string_t* candidate, bool & loaded_from_bundle) { candidate->clear(); + loaded_from_bundle = false; for (const auto& config : m_probes) { @@ -316,8 +319,9 @@ bool deps_resolver_t::probe_deps_entry(const deps_entry_t& entry, const pal::str // If the deps json has the package name and version, then someone has already done rid selection and // put the right asset in the dir. So checking just package name and version would suffice. // No need to check further for the exact asset relative sub path. - if (config.probe_deps_json->has_package(entry.library_name, entry.library_version) && entry.to_dir_path(probe_dir, false, candidate)) + if (config.probe_deps_json->has_package(entry.library_name, entry.library_version) && entry.to_dir_path(probe_dir, false, candidate, loaded_from_bundle)) { + assert(!loaded_from_bundle); trace::verbose(_X(" Probed deps json and matched '%s'"), candidate->c_str()); return true; } @@ -343,7 +347,7 @@ bool deps_resolver_t::probe_deps_entry(const deps_entry_t& entry, const pal::str else { // Non-rid assets, lookup in the published dir. - if (entry.to_dir_path(deps_dir, true, candidate)) + if (entry.to_dir_path(deps_dir, true, candidate, loaded_from_bundle)) { trace::verbose(_X(" Probed deps dir and matched '%s'"), candidate->c_str()); return true; @@ -437,10 +441,17 @@ bool deps_resolver_t::resolve_tpa_list( name_to_resolved_asset_map_t::iterator existing = items.find(entry.asset.name); if (existing == items.end()) { - if (probe_deps_entry(entry, deps_dir, fx_level, &resolved_path)) + bool loaded_from_bundle = false; + if (probe_deps_entry(entry, deps_dir, fx_level, &resolved_path, loaded_from_bundle)) { - deps_resolved_asset_t resolved_asset(entry.asset, resolved_path); - add_tpa_asset(resolved_asset, &items); + // Assemblies loaded directly from the bundle are not added to the TPA list. + // The runtime directly probes the bundle-manifest using a host-callback. + if (!loaded_from_bundle) + { + deps_resolved_asset_t resolved_asset(entry.asset, resolved_path); + add_tpa_asset(resolved_asset, &items); + } + return true; } @@ -468,7 +479,8 @@ bool deps_resolver_t::resolve_tpa_list( if (entry.asset.assembly_version > existing_entry->asset.assembly_version || (entry.asset.assembly_version == existing_entry->asset.assembly_version && entry.asset.file_version >= existing_entry->asset.file_version)) { - if (probe_deps_entry(entry, deps_dir, fx_level, &resolved_path)) + bool loaded_from_bundle = false; + if (probe_deps_entry(entry, deps_dir, fx_level, &resolved_path, loaded_from_bundle)) { // If the path is the same, then no need to replace if (resolved_path != existing_entry->resolved_path) @@ -480,9 +492,12 @@ bool deps_resolver_t::resolve_tpa_list( existing_entry = nullptr; items.erase(existing); - deps_asset_t asset(entry.asset.name, entry.asset.relative_path, entry.asset.assembly_version, entry.asset.file_version); - deps_resolved_asset_t resolved_asset(asset, resolved_path); - add_tpa_asset(resolved_asset, &items); + if (!loaded_from_bundle) + { + deps_asset_t asset(entry.asset.name, entry.asset.relative_path, entry.asset.assembly_version, entry.asset.file_version); + deps_resolved_asset_t resolved_asset(asset, resolved_path); + add_tpa_asset(resolved_asset, &items); + } } } else if (fx_level != 0) @@ -505,9 +520,17 @@ bool deps_resolver_t::resolve_tpa_list( // First add managed assembly to the TPA. // TODO: Remove: the deps should contain the managed DLL. // Workaround for: csc.deps.json doesn't have the csc.dll - deps_asset_t asset(get_filename_without_ext(m_managed_app), get_filename(m_managed_app), version_t(), version_t()); - deps_resolved_asset_t resolved_asset(asset, m_managed_app); - add_tpa_asset(resolved_asset, &items); + + // If this is a single-file bundle, app.dll is expected to be within the bundle, unless it is explicitly excluded from the bundle. + // In all other cases, add its path to the TPA list. + pal::string_t managed_app_name = get_filename(m_managed_app); + if (!bundle::info_t::is_single_file_bundle() || + bundle::runner_t::app()->probe(managed_app_name) == nullptr) + { + deps_asset_t asset(get_filename_without_ext(m_managed_app), managed_app_name, version_t(), version_t()); + deps_resolved_asset_t resolved_asset(asset, m_managed_app); + add_tpa_asset(resolved_asset, &items); + } // Add the app's entries const auto& deps_entries = get_deps().get_entries(deps_entry_t::asset_types::runtime); @@ -590,12 +613,6 @@ void deps_resolver_t::init_known_entry_path(const deps_entry_t& entry, const pal if (m_coreclr_path.empty() && ends_with(path, DIR_SEPARATOR + pal::string_t(LIBCORECLR_NAME), false)) { m_coreclr_path = path; - m_coreclr_library_version = entry.library_version; - return; - } - if (m_clrjit_path.empty() && ends_with(path, DIR_SEPARATOR + pal::string_t(LIBCLRJIT_NAME), false)) - { - m_clrjit_path = path; return; } } @@ -789,10 +806,14 @@ bool deps_resolver_t::resolve_probe_dirs( trace::verbose(_X("Processing native/culture for deps entry [%s, %s, %s]"), entry.library_name.c_str(), entry.library_version.c_str(), entry.asset.relative_path.c_str()); - if (probe_deps_entry(entry, deps_dir, fx_level, &candidate)) + bool loaded_from_bundle = false; + if (probe_deps_entry(entry, deps_dir, fx_level, &candidate, loaded_from_bundle)) { - init_known_entry_path(entry, candidate); - add_unique_path(asset_type, action(candidate), &items, output, &non_serviced, core_servicing); + if (!loaded_from_bundle) + { + init_known_entry_path(entry, candidate); + add_unique_path(asset_type, action(candidate), &items, output, &non_serviced, core_servicing); + } } else { @@ -826,7 +847,6 @@ bool deps_resolver_t::resolve_probe_dirs( add_unique_path(asset_type, m_app_dir, &items, output, &non_serviced, core_servicing); (void) library_exists_in_dir(m_app_dir, LIBCORECLR_NAME, &m_coreclr_path); - (void) library_exists_in_dir(m_app_dir, LIBCLRJIT_NAME, &m_clrjit_path); } // Handle any additional deps.json that were specified. @@ -892,7 +912,6 @@ bool deps_resolver_t::resolve_probe_paths(probe_paths_t* probe_paths, std::unord // If we found coreclr and the jit during native path probe, set the paths now. probe_paths->coreclr = m_coreclr_path; - probe_paths->clrjit = m_clrjit_path; return true; } diff --git a/src/installer/corehost/cli/hostpolicy/deps_resolver.h b/src/installer/corehost/cli/hostpolicy/deps_resolver.h index f2b27d4620a100..8471d94b44c129 100644 --- a/src/installer/corehost/cli/hostpolicy/deps_resolver.h +++ b/src/installer/corehost/cli/hostpolicy/deps_resolver.h @@ -23,7 +23,6 @@ struct probe_paths_t pal::string_t native; pal::string_t resources; pal::string_t coreclr; - pal::string_t clrjit; }; struct deps_resolved_asset_t @@ -169,11 +168,6 @@ class deps_resolver_t return m_fx_definitions; } - const pal::string_t& get_coreclr_library_version() const - { - return m_coreclr_library_version; - } - bool is_framework_dependent() const { return m_is_framework_dependent; @@ -234,7 +228,8 @@ class deps_resolver_t const deps_entry_t& entry, const pal::string_t& deps_dir, int fx_level, - pal::string_t* candidate); + pal::string_t* candidate, + bool &loaded_from_bundle); fx_definition_vector_t& m_fx_definitions; @@ -256,12 +251,6 @@ class deps_resolver_t // Special entry for coreclr path pal::string_t m_coreclr_path; - // Special entry for coreclr library version - pal::string_t m_coreclr_library_version; - - // Special entry for JIT path - pal::string_t m_clrjit_path; - // The filepaths for the app custom deps std::vector m_additional_deps_files; diff --git a/src/installer/corehost/cli/hostpolicy/hostpolicy_context.cpp b/src/installer/corehost/cli/hostpolicy/hostpolicy_context.cpp index bb4a965126d962..ed6801342c4656 100644 --- a/src/installer/corehost/cli/hostpolicy/hostpolicy_context.cpp +++ b/src/installer/corehost/cli/hostpolicy/hostpolicy_context.cpp @@ -7,6 +7,8 @@ #include "deps_resolver.h" #include #include +#include "bundle/runner.h" +#include "bundle/file_entry.h" namespace { @@ -15,6 +17,43 @@ namespace trace::error(_X("Duplicate runtime property found: %s"), property_key); trace::error(_X("It is invalid to specify values for properties populated by the hosting layer in the the application's .runtimeconfig.json")); } + + // bundle_probe: + // Probe the app-bundle for the file 'path' and return its location ('offset', 'size') if found. + // + // This function is an API exported to the runtime via the BUNDLE_PROBE property. + // This function used by the runtime to probe for bundled assemblies + // This function assumes that the currently executing app is a single-file bundle. + // + // bundle_probe recieves its path argument as cha16_t* instead of pal::char_t*, because: + // * The host uses Unicode strings on Windows and UTF8 strings on Unix + // * The runtime uses Unicode strings on all platforms + // * Using a unicode encoded path presents a uniform interface to the runtime + // and minimizes the number if Unicode <-> UTF8 conversions necessary. + // + // The unicode char type is char16_t* instead of whcar_t*, because: + // * wchar_t is 16-bit encoding on Windows while it is 32-bit encoding on most Unix systems + // * The runtime uses 16-bit encoded unicode characters. + + bool STDMETHODCALLTYPE bundle_probe(const char16_t* path, int64_t* offset, int64_t* size) + { + if (path == nullptr) + { + return false; + } + + pal::string_t file_path; + + if (!pal::unicode_palstring(path, &file_path)) + { + trace::warning(_X("Failure probing contents of the application bundle.")); + trace::warning(_X("Failed to convert path [%ls] to UTF8"), path); + + return false; + } + + return bundle::runner_t::app()->probe(file_path, offset, size); + } } int hostpolicy_context_t::initialize(hostpolicy_init_t &hostpolicy_init, const arguments_t &args, bool enable_breadcrumbs) @@ -74,31 +113,23 @@ int hostpolicy_context_t::initialize(hostpolicy_init_t &hostpolicy_init, const a // Get path in which CoreCLR is present. clr_dir = get_directory(clr_path); + // If this is a self-contained single-file bundle, + // System.Private.CoreLib.dll is expected to be within the bundle, unless it is explicitly excluded from the bundle. + // In all other cases, // System.Private.CoreLib.dll is expected to be next to CoreCLR.dll - add its path to the TPA list. - pal::string_t corelib_path = clr_dir; - append_path(&corelib_path, CORELIB_NAME); - - // Append CoreLib path - if (!probe_paths.tpa.empty() && probe_paths.tpa.back() != PATH_SEPARATOR) + if (!bundle::info_t::is_single_file_bundle() || + bundle::runner_t::app()->probe(CORELIB_NAME) == nullptr) { - probe_paths.tpa.push_back(PATH_SEPARATOR); - } + pal::string_t corelib_path = clr_dir; + append_path(&corelib_path, CORELIB_NAME); - probe_paths.tpa.append(corelib_path); + // Append CoreLib path + if (!probe_paths.tpa.empty() && probe_paths.tpa.back() != PATH_SEPARATOR) + { + probe_paths.tpa.push_back(PATH_SEPARATOR); + } - pal::string_t clrjit_path = probe_paths.clrjit; - if (clrjit_path.empty()) - { - trace::warning(_X("Could not resolve CLRJit path")); - } - else if (pal::realpath(&clrjit_path)) - { - trace::verbose(_X("The resolved JIT path is '%s'"), clrjit_path.c_str()); - } - else - { - clrjit_path.clear(); - trace::warning(_X("Could not resolve symlink to CLRJit path '%s'"), probe_paths.clrjit.c_str()); + probe_paths.tpa.append(corelib_path); } const fx_definition_vector_t &fx_definitions = resolver.get_fx_definitions(); @@ -125,16 +156,6 @@ int hostpolicy_context_t::initialize(hostpolicy_init_t &hostpolicy_init, const a ++fx_curr; } - pal::string_t clr_library_version; - if (resolver.is_framework_dependent()) - { - clr_library_version = get_root_framework(fx_definitions).get_found_version(); - } - else - { - clr_library_version = resolver.get_coreclr_library_version(); - } - // Build properties for CoreCLR instantiation pal::string_t app_base = resolver.get_app_dir(); coreclr_properties.add(common_property::TrustedPlatformAssemblies, probe_paths.tpa.c_str()); @@ -144,12 +165,8 @@ int hostpolicy_context_t::initialize(hostpolicy_init_t &hostpolicy_init, const a coreclr_properties.add(common_property::AppContextDepsFiles, app_context_deps_str.c_str()); coreclr_properties.add(common_property::FxDepsFile, fx_deps_str.c_str()); coreclr_properties.add(common_property::ProbingDirectories, resolver.get_lookup_probe_directories().c_str()); - coreclr_properties.add(common_property::FxProductVersion, clr_library_version.c_str()); coreclr_properties.add(common_property::RuntimeIdentifier, get_current_runtime_id(true /*use_fallback*/).c_str()); - if (!clrjit_path.empty()) - coreclr_properties.add(common_property::JitPath, clrjit_path.c_str()); - bool set_app_paths = false; // Runtime options config properties. @@ -198,5 +215,15 @@ int hostpolicy_context_t::initialize(hostpolicy_init_t &hostpolicy_init, const a } } + // Single-File Bundle Probe + if (bundle::info_t::is_single_file_bundle()) + { + // Encode the bundle_probe function pointer as a string, and pass it to the runtime. + pal::stringstream_t ptr_stream; + ptr_stream << "0x" << std::hex << (size_t)(&bundle_probe); + + coreclr_properties.add(common_property::BundleProbe, ptr_stream.str().c_str()); + } + return StatusCode::Success; } diff --git a/src/installer/corehost/cli/hostpolicy/standalone/CMakeLists.txt b/src/installer/corehost/cli/hostpolicy/standalone/CMakeLists.txt new file mode 100644 index 00000000000000..d6631543f81b5b --- /dev/null +++ b/src/installer/corehost/cli/hostpolicy/standalone/CMakeLists.txt @@ -0,0 +1,59 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +project(hostpolicy) + +set(DOTNET_PROJECT_NAME "hostpolicy") + +# CMake does not recommend using globbing since it messes with the freshness checks + +# Can't call add_library() without source files. Create an empty .c file, +# then link with the static library just recently built. +if (NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/empty.cpp") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/empty.cpp" "") +endif () + +set(SOURCES + ${CMAKE_CURRENT_BINARY_DIR}/empty.cpp +) + +set(HEADERS +) + +if(CLR_CMAKE_TARGET_WIN32) + list(APPEND SOURCES + hostpolicy.def) +else(CLR_CMAKE_TARGET_WIN32) + set(DEF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/hostpolicy_unixexports.src) + set(EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/hostpolicy.exports) + generate_exports_file(${DEF_SOURCES} ${EXPORTS_FILE}) + + if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) + # Add linker exports file option + set(EXPORTS_LINKER_OPTION -Wl,--version-script=${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD) + + if(CLR_CMAKE_HOST_OSX) + # Add linker exports file option + set(EXPORTS_LINKER_OPTION -Wl,-exported_symbols_list,${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_OSX) + + if(CLR_CMAKE_HOST_SUNOS) + # Add linker exports file option + set(EXPORTS_LINKER_OPTION -Wl,-M,${EXPORTS_FILE}) + endif(CLR_CMAKE_HOST_SUNOS) +endif(CLR_CMAKE_TARGET_WIN32) + +include(../../lib.cmake) + +if(CLR_CMAKE_HOST_UNIX) + add_custom_target(hostpolicy_exports DEPENDS ${EXPORTS_FILE}) + add_dependencies(hostpolicy hostpolicy_exports) + + set_property(TARGET hostpolicy APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION}) + set_property(TARGET hostpolicy APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE}) +endif(CLR_CMAKE_HOST_UNIX) + +install_with_stripped_symbols(hostpolicy TARGETS corehost) +target_link_libraries(hostpolicy libhostcommon libhostpolicy_static) diff --git a/src/installer/corehost/cli/hostpolicy/standalone/hostpolicy.def b/src/installer/corehost/cli/hostpolicy/standalone/hostpolicy.def new file mode 100644 index 00000000000000..af03ab9dca68d4 --- /dev/null +++ b/src/installer/corehost/cli/hostpolicy/standalone/hostpolicy.def @@ -0,0 +1,12 @@ +; Licensed to the .NET Foundation under one or more agreements. +; The .NET Foundation licenses this file to you under the MIT license. +; See the LICENSE file in the project root for more information. + +EXPORTS + corehost_initialize + corehost_load + corehost_main + corehost_main_with_output_buffer + corehost_resolve_component_dependencies + corehost_set_error_writer + corehost_unload diff --git a/src/installer/corehost/cli/hostpolicy/standalone/hostpolicy_unixexports.src b/src/installer/corehost/cli/hostpolicy/standalone/hostpolicy_unixexports.src new file mode 100644 index 00000000000000..98f3e616e94991 --- /dev/null +++ b/src/installer/corehost/cli/hostpolicy/standalone/hostpolicy_unixexports.src @@ -0,0 +1,11 @@ +; Licensed to the .NET Foundation under one or more agreements. +; The .NET Foundation licenses this file to you under the MIT license. +; See the LICENSE file in the project root for more information. + +corehost_initialize +corehost_load +corehost_main +corehost_main_with_output_buffer +corehost_resolve_component_dependencies +corehost_set_error_writer +corehost_unload diff --git a/src/installer/corehost/cli/hostpolicy/static/CMakeLists.txt b/src/installer/corehost/cli/hostpolicy/static/CMakeLists.txt new file mode 100644 index 00000000000000..6845e369bdac30 --- /dev/null +++ b/src/installer/corehost/cli/hostpolicy/static/CMakeLists.txt @@ -0,0 +1,47 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +project(hostpolicy_static) + +set(DOTNET_PROJECT_NAME "hostpolicy_static") + +# Include directories +include_directories(../../fxr) +include_directories(../../json) + +# CMake does not recommend using globbing since it messes with the freshness checks +set(SOURCES + ../args.cpp + ../breadcrumbs.cpp + ../coreclr.cpp + ../deps_resolver.cpp + ../hostpolicy_context.cpp + ../hostpolicy.cpp + ../hostpolicy_init.cpp + ../../bundle/dir_utils.cpp + ../../bundle/extractor.cpp + ../../bundle/file_entry.cpp + ../../bundle/manifest.cpp + ../../bundle/runner.cpp +) + +set(HEADERS + ../args.h + ../breadcrumbs.h + ../coreclr.h + ../deps_resolver.h + ../hostpolicy_context.h + ../hostpolicy_init.h + ../../hostpolicy.h + ../../corehost_context_contract.h + ../../bundle/dir_utils.h + ../../bundle/extractor.h + ../../bundle/file_entry.h + ../../bundle/manifest.h + ../../bundle/runner.h +) + +set(SKIP_VERSIONING 1) +set(BUILD_OBJECT_LIBRARY 1) +include(../../lib_static.cmake) diff --git a/src/installer/corehost/cli/json_parser.cpp b/src/installer/corehost/cli/json_parser.cpp index c6f0cbbf0c9127..65e0fd3ccfde2a 100644 --- a/src/installer/corehost/cli/json_parser.cpp +++ b/src/installer/corehost/cli/json_parser.cpp @@ -77,16 +77,15 @@ void json_parser_t::realloc_buffer(size_t size) bool json_parser_t::parse_json(char* data, int64_t size, const pal::string_t& context) { + constexpr auto flags = rapidjson::ParseFlag::kParseStopWhenDoneFlag | rapidjson::ParseFlag::kParseCommentsFlag; #ifdef _WIN32 // Can't use in-situ parsing on Windows, as JSON data is encoded in // UTF-8 and the host expects wide strings. m_document will store // data in UTF-16 (with pal::char_t as the character type), but it // has to know that data is encoded in UTF-8 to convert during parsing. - constexpr auto flags = rapidjson::ParseFlag::kParseStopWhenDoneFlag - | rapidjson::ParseFlag::kParseCommentsFlag; m_document.Parse>(data); #else // _WIN32 - m_document.ParseInsitu(data); + m_document.ParseInsitu(data); #endif // _WIN32 if (m_document.HasParseError()) @@ -140,9 +139,10 @@ bool json_parser_t::parse_file(const pal::string_t& path) if (bundle::info_t::is_single_file_bundle()) { + // Due to in-situ parsing on Linux, + // * The json file is mapped as copy-on-write. + // * The mapping cannot be immediately released, and will be unmapped by the json_parser destructor. m_bundle_data = bundle::info_t::config_t::map(path, m_bundle_location); - // The mapping will be unmapped by the json_parser destructor. - // The mapping cannot be immediately released due to in-situ parsing on Linux. if (m_bundle_data != nullptr) { diff --git a/src/installer/corehost/cli/json_parser.h b/src/installer/corehost/cli/json_parser.h index 16ed21bd033072..344d03647774f2 100644 --- a/src/installer/corehost/cli/json_parser.h +++ b/src/installer/corehost/cli/json_parser.h @@ -5,6 +5,14 @@ #ifndef __JSON_PARSER_H__ #define __JSON_PARSER_H__ +#ifdef __sun +// This optimization relies on zeros in higher 16-bits, whereas SunOS has 1s. More details at +// https://github.com/Tencent/rapidjson/issues/1596. +// The impact here was that runtimeOptions key available in hwapp.runtimeconfig.json was not +// located by RapidJson's FindMember() API from runtime_config_t::ensure_parsed(). +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 +#endif + #include "pal.h" #include "rapidjson/document.h" #include "rapidjson/fwd.h" diff --git a/src/installer/corehost/cli/lib.cmake b/src/installer/corehost/cli/lib.cmake index d2305fdfe15a82..fe6632d6afc363 100644 --- a/src/installer/corehost/cli/lib.cmake +++ b/src/installer/corehost/cli/lib.cmake @@ -5,13 +5,13 @@ project(${DOTNET_PROJECT_NAME}) include(${CMAKE_CURRENT_LIST_DIR}/common.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/hostmisc/hostmisc.cmake) add_definitions(-D_NO_ASYNCRTIMP) add_definitions(-D_NO_PPLXIMP) add_definitions(-DEXPORT_SHARED_API=1) add_library(${DOTNET_PROJECT_NAME} SHARED ${SOURCES} ${RESOURCES}) -target_link_libraries(${DOTNET_PROJECT_NAME} libhostmisc) set_target_properties(${DOTNET_PROJECT_NAME} PROPERTIES MACOSX_RPATH TRUE) diff --git a/src/installer/corehost/cli/lib_static.cmake b/src/installer/corehost/cli/lib_static.cmake index 8135e9c19e0e09..00204df3ce9f40 100644 --- a/src/installer/corehost/cli/lib_static.cmake +++ b/src/installer/corehost/cli/lib_static.cmake @@ -10,7 +10,11 @@ add_definitions(-D_NO_ASYNCRTIMP) add_definitions(-D_NO_PPLXIMP) add_definitions(-DEXPORT_SHARED_API=1) -add_library(lib${DOTNET_PROJECT_NAME} STATIC ${SOURCES} ${RESOURCES}) +if (BUILD_OBJECT_LIBRARY) + add_library(lib${DOTNET_PROJECT_NAME} OBJECT ${SOURCES} ${RESOURCES}) +else () + add_library(lib${DOTNET_PROJECT_NAME} STATIC ${SOURCES} ${RESOURCES}) +endif () set_target_properties(lib${DOTNET_PROJECT_NAME} PROPERTIES MACOSX_RPATH TRUE) set_target_properties(lib${DOTNET_PROJECT_NAME} PROPERTIES PREFIX "") diff --git a/src/installer/corehost/cli/nethost/nethost.h b/src/installer/corehost/cli/nethost/nethost.h index 839a3fd62aa0bb..42498ea07ab539 100644 --- a/src/installer/corehost/cli/nethost/nethost.h +++ b/src/installer/corehost/cli/nethost/nethost.h @@ -7,11 +7,17 @@ #include -#if defined(_WIN32) +#ifdef _WIN32 #ifdef NETHOST_EXPORT #define NETHOST_API __declspec(dllexport) #else - #define NETHOST_API __declspec(dllimport) + // Consuming the nethost as a static library + // Shouldn't export attempt to dllimport. + #ifdef NETHOST_USE_AS_STATIC + #define NETHOST_API + #else + #define NETHOST_API __declspec(dllimport) + #endif #endif #define NETHOST_CALLTYPE __stdcall diff --git a/src/installer/corehost/cli/test/nativehost/CMakeLists.txt b/src/installer/corehost/cli/test/nativehost/CMakeLists.txt index 82d3cbcb36acdd..e9fd5f48087e31 100644 --- a/src/installer/corehost/cli/test/nativehost/CMakeLists.txt +++ b/src/installer/corehost/cli/test/nativehost/CMakeLists.txt @@ -45,6 +45,8 @@ if(CLR_CMAKE_TARGET_WIN32) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DELAYLOAD:nethost.dll") endif() +include(../../hostmisc/hostmisc.cmake) + include(../testexe.cmake) target_link_libraries(${DOTNET_PROJECT_NAME} nethost) diff --git a/src/installer/corehost/cli/test/nativehost/host_context_test.cpp b/src/installer/corehost/cli/test/nativehost/host_context_test.cpp index 708fa2bb3bf058..f2215439e24498 100644 --- a/src/installer/corehost/cli/test/nativehost/host_context_test.cpp +++ b/src/installer/corehost/cli/test/nativehost/host_context_test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -225,6 +226,74 @@ namespace return -1; } + struct _printable_delegate_name_t + { + const pal::char_t* name; + }; + + std::basic_ostream& operator<<(std::basic_ostream& stream, const _printable_delegate_name_t &p) + { + if (p.name == nullptr) + { + return stream << _X("nullptr"); + } + else if (p.name == UNMANAGEDCALLERSONLY_METHOD) + { + return stream << _X("UNMANAGEDCALLERSONLY_METHOD"); + } + else + { + return stream << _X("\"") << p.name << _X("\""); + } + } + + const _printable_delegate_name_t to_printable_delegate_name(const pal::char_t *delegate_name) + { + return _printable_delegate_name_t{ delegate_name }; + } + + int call_delegate_flavour( + load_assembly_and_get_function_pointer_fn delegate, + const pal::char_t *assembly_path, + const pal::char_t *type_name, + const pal::char_t *method_name, + const pal::char_t *log_prefix, + pal::stringstream_t &test_output) + { + const pal::char_t *delegate_name = nullptr; + pal::string_t method_name_local{ method_name }; + if (pal::string_t::npos != method_name_local.find(_X("Unmanaged"))) + delegate_name = UNMANAGEDCALLERSONLY_METHOD; + + test_output << log_prefix << _X("calling load_assembly_and_get_function_pointer(\"") + << assembly_path << _X("\", \"") + << type_name << _X("\", \"") + << method_name << _X("\", ") + << to_printable_delegate_name(delegate_name) << _X(", ") + << _X("nullptr, &componentEntryPointDelegate)") + << std::endl; + + component_entry_point_fn componentEntryPointDelegate = nullptr; + int rc = delegate(assembly_path, + type_name, + method_name, + delegate_name, + nullptr /* reserved */, + (void **)&componentEntryPointDelegate); + + if (rc != StatusCode::Success) + { + test_output << log_prefix << _X("load_assembly_and_get_function_pointer failed: ") << std::hex << std::showbase << rc << std::endl; + } + else + { + test_output << log_prefix << _X("load_assembly_and_get_function_pointer succeeded: ") << std::hex << std::showbase << rc << std::endl; + rc = call_delegate_with_try_except(componentEntryPointDelegate, method_name, log_prefix, test_output); + } + + return rc; + } + bool load_assembly_and_get_function_pointer_test( const hostfxr_exports &hostfxr, const pal::char_t *config_path, @@ -258,31 +327,7 @@ namespace else { test_output << log_prefix << _X("hostfxr_get_runtime_delegate succeeded: ") << std::hex << std::showbase << rc << std::endl; - - test_output << log_prefix << _X("calling load_assembly_and_get_function_pointer(\"") - << assembly_path << _X("\", \"") - << type_name << _X("\", \"") - << method_name << _X("\", \"") - << _X("nullptr, nullptr, &componentEntryPointDelegate)") - << std::endl; - - component_entry_point_fn componentEntryPointDelegate = nullptr; - rc = delegate(assembly_path, - type_name, - method_name, - nullptr /* delegateTypeNative */, - nullptr /* reserved */, - (void **)&componentEntryPointDelegate); - - if (rc != StatusCode::Success) - { - test_output << log_prefix << _X("load_assembly_and_get_function_pointer failed: ") << std::hex << std::showbase << rc << std::endl; - } - else - { - test_output << log_prefix << _X("load_assembly_and_get_function_pointer succeeded: ") << std::hex << std::showbase << rc << std::endl; - rc = call_delegate_with_try_except(componentEntryPointDelegate, method_name, log_prefix, test_output); - } + rc = call_delegate_flavour(delegate, assembly_path, type_name, method_name, log_prefix, test_output); } } @@ -525,4 +570,4 @@ bool host_context_test::load_assembly_and_get_function_pointer( hostfxr_exports hostfxr{ hostfxr_path }; return load_assembly_and_get_function_pointer_test(hostfxr, config_path, argc, argv, config_log_prefix, test_output); -} \ No newline at end of file +} diff --git a/src/installer/corehost/cli/test_fx_ver/CMakeLists.txt b/src/installer/corehost/cli/test_fx_ver/CMakeLists.txt index 87778202f25eb2..d68eea66656fed 100644 --- a/src/installer/corehost/cli/test_fx_ver/CMakeLists.txt +++ b/src/installer/corehost/cli/test_fx_ver/CMakeLists.txt @@ -5,6 +5,8 @@ project(test_fx_ver) set(EXE_NAME "test_fx_ver") +include_directories(../../) +include_directories(../) include_directories(../fxr) include_directories(../hostmisc) @@ -12,6 +14,8 @@ set(SOURCES test_fx_ver.cpp ) +include(${CMAKE_CURRENT_LIST_DIR}/../hostmisc/hostmisc.cmake) + if(CLR_CMAKE_HOST_WIN32) add_compile_options($<$:/MT>) add_compile_options($<$:/MT>) @@ -21,7 +25,7 @@ else() endif() add_executable(${EXE_NAME} ${SOURCES}) -target_link_libraries(${EXE_NAME} libhostmisc libhostcommon) +target_link_libraries(${EXE_NAME} libhostcommon) install(TARGETS ${EXE_NAME} DESTINATION corehost_test) diff --git a/src/installer/corehost/cli/winrthost/CMakeLists.txt b/src/installer/corehost/cli/winrthost/CMakeLists.txt index 9b3e2b44521c54..22b32e998771ad 100644 --- a/src/installer/corehost/cli/winrthost/CMakeLists.txt +++ b/src/installer/corehost/cli/winrthost/CMakeLists.txt @@ -30,6 +30,6 @@ if (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_AR target_link_libraries(winrthost Advapi32.lib Ole32.lib OleAut32.lib) endif() -target_link_libraries(winrthost RuntimeObject.lib libhostmisc libhostcommon) +target_link_libraries(winrthost RuntimeObject.lib libhostcommon) install_with_stripped_symbols(winrthost TARGETS corehost) diff --git a/src/installer/corehost/corehost.cpp b/src/installer/corehost/corehost.cpp index 55b8ed629827ce..65cfb61f3ac64f 100644 --- a/src/installer/corehost/corehost.cpp +++ b/src/installer/corehost/corehost.cpp @@ -9,6 +9,7 @@ #include "fx_ver.h" #include "trace.h" #include "utils.h" +#include "hostfxr_resolver_t.h" #if defined(FEATURE_APPHOST) #include "bundle_marker.h" @@ -176,51 +177,41 @@ int exe_start(const int argc, const pal::char_t* argv[]) app_path.append(_X(".dll")); #endif - pal::string_t dotnet_root; - pal::string_t fxr_path; - if (!fxr_resolver::try_get_path(app_root, &dotnet_root, &fxr_path)) - { - return StatusCode::CoreHostLibMissingFailure; - } + hostfxr_resolver_t fxr{app_root}; - // Load library - pal::dll_t fxr; - if (!pal::load_library(&fxr_path, &fxr)) + // Obtain the entrypoints. + int rc = fxr.status_code(); + if (rc != StatusCode::Success) { - trace::error(_X("The library %s was found, but loading it from %s failed"), LIBFXR_NAME, fxr_path.c_str()); - trace::error(_X(" - Installing .NET prerequisites might help resolve this problem.")); - trace::error(_X(" %s"), DOTNET_CORE_INSTALL_PREREQUISITES_URL); - return StatusCode::CoreHostLibLoadFailure; + return rc; } - // Obtain the entrypoints. - int rc; #if defined(FEATURE_APPHOST) if (bundle_marker_t::is_bundle()) { - hostfxr_main_bundle_startupinfo_fn hostfxr_main_bundle_startupinfo = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_main_bundle_startupinfo")); + auto hostfxr_main_bundle_startupinfo = fxr.resolve_main_bundle_startupinfo(); if (hostfxr_main_bundle_startupinfo != nullptr) { const pal::char_t* host_path_cstr = host_path.c_str(); - const pal::char_t* dotnet_root_cstr = dotnet_root.empty() ? nullptr : dotnet_root.c_str(); + const pal::char_t* dotnet_root_cstr = fxr.dotnet_root().empty() ? nullptr : fxr.dotnet_root().c_str(); const pal::char_t* app_path_cstr = app_path.empty() ? nullptr : app_path.c_str(); int64_t bundle_header_offset = bundle_marker_t::header_offset(); - trace::info(_X("Invoking fx resolver [%s] hostfxr_main_bundle_startupinfo"), fxr_path.c_str()); + trace::info(_X("Invoking fx resolver [%s] hostfxr_main_bundle_startupinfo"), fxr.fxr_path().c_str()); trace::info(_X("Host path: [%s]"), host_path.c_str()); - trace::info(_X("Dotnet path: [%s]"), dotnet_root.c_str()); + trace::info(_X("Dotnet path: [%s]"), fxr.dotnet_root().c_str()); trace::info(_X("App path: [%s]"), app_path.c_str()); trace::info(_X("Bundle Header Offset: [%lx]"), bundle_header_offset); - hostfxr_set_error_writer_fn set_error_writer_fn = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_set_error_writer")); - propagate_error_writer_t propagate_error_writer_to_hostfxr(set_error_writer_fn); + auto set_error_writer = fxr.resolve_set_error_writer(); + propagate_error_writer_t propagate_error_writer_to_hostfxr(set_error_writer); rc = hostfxr_main_bundle_startupinfo(argc, argv, host_path_cstr, dotnet_root_cstr, app_path_cstr, bundle_header_offset); } else { // The host components will be statically linked with the app-host: https://github.com/dotnet/runtime/issues/32823 // Once this work is completed, an outdated hostfxr can only be found for framework-related apps. - trace::error(_X("The required library %s does not support single-file apps."), fxr_path.c_str()); + trace::error(_X("The required library %s does not support single-file apps."), fxr.fxr_path().c_str()); need_newer_framework_error(); rc = StatusCode::FrameworkMissingFailure; } @@ -228,60 +219,61 @@ int exe_start(const int argc, const pal::char_t* argv[]) else #endif // defined(FEATURE_APPHOST) { - hostfxr_main_startupinfo_fn hostfxr_main_startupinfo = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_main_startupinfo")); + auto hostfxr_main_startupinfo = fxr.resolve_main_startupinfo(); if (hostfxr_main_startupinfo != nullptr) { const pal::char_t* host_path_cstr = host_path.c_str(); - const pal::char_t* dotnet_root_cstr = dotnet_root.empty() ? nullptr : dotnet_root.c_str(); + const pal::char_t* dotnet_root_cstr = fxr.dotnet_root().empty() ? nullptr : fxr.dotnet_root().c_str(); const pal::char_t* app_path_cstr = app_path.empty() ? nullptr : app_path.c_str(); - trace::info(_X("Invoking fx resolver [%s] hostfxr_main_startupinfo"), fxr_path.c_str()); + trace::info(_X("Invoking fx resolver [%s] hostfxr_main_startupinfo"), fxr.fxr_path().c_str()); trace::info(_X("Host path: [%s]"), host_path.c_str()); - trace::info(_X("Dotnet path: [%s]"), dotnet_root.c_str()); + trace::info(_X("Dotnet path: [%s]"), fxr.dotnet_root().c_str()); trace::info(_X("App path: [%s]"), app_path.c_str()); - hostfxr_set_error_writer_fn set_error_writer_fn = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_set_error_writer")); - propagate_error_writer_t propagate_error_writer_to_hostfxr(set_error_writer_fn); + auto set_error_writer = fxr.resolve_set_error_writer(); + propagate_error_writer_t propagate_error_writer_to_hostfxr(set_error_writer); rc = hostfxr_main_startupinfo(argc, argv, host_path_cstr, dotnet_root_cstr, app_path_cstr); // This check exists to provide an error message for UI apps when running 3.0 apps on 2.0 only hostfxr, which doesn't support error writer redirection. - if (trace::get_error_writer() != nullptr && rc == static_cast(StatusCode::FrameworkMissingFailure) && !set_error_writer_fn) + if (trace::get_error_writer() != nullptr && rc == static_cast(StatusCode::FrameworkMissingFailure) && set_error_writer == nullptr) { need_newer_framework_error(); } } +#if !defined(FEATURE_STATIC_HOST) else { if (requires_hostfxr_startupinfo_interface) { - trace::error(_X("The required library %s does not support relative app dll paths."), fxr_path.c_str()); + trace::error(_X("The required library %s does not support relative app dll paths."), fxr.fxr_path().c_str()); rc = StatusCode::CoreHostEntryPointFailure; } else { - trace::info(_X("Invoking fx resolver [%s] v1"), fxr_path.c_str()); + trace::info(_X("Invoking fx resolver [%s] v1"), fxr.fxr_path().c_str()); // Previous corehost trace messages must be printed before calling trace::setup in hostfxr trace::flush(); // For compat, use the v1 interface. This requires additional file I\O to re-parse parameters and // for apphost, does not support DOTNET_ROOT or dll with different name for exe. - hostfxr_main_fn main_fn_v1 = reinterpret_cast(pal::get_symbol(fxr, "hostfxr_main")); + auto main_fn_v1 = fxr.resolve_main_v1(); if (main_fn_v1 != nullptr) { rc = main_fn_v1(argc, argv); } else { - trace::error(_X("The required library %s does not contain the expected entry point."), fxr_path.c_str()); + trace::error(_X("The required library %s does not contain the expected entry point."), fxr.fxr_path().c_str()); rc = StatusCode::CoreHostEntryPointFailure; } } } +#endif // defined(FEATURE_STATIC_HOST) } - pal::unload_library(fxr); return rc; } diff --git a/src/installer/corehost/hostfxr_resolver_t.h b/src/installer/corehost/hostfxr_resolver_t.h new file mode 100644 index 00000000000000..21047b56a3c898 --- /dev/null +++ b/src/installer/corehost/hostfxr_resolver_t.h @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#ifndef __HOSTFXR_RESOLVER_T_H__ +#define __HOSTFXR_RESOLVER_T_H__ + +#include "hostfxr.h" +#include "pal.h" +#include "error_codes.h" + +class hostfxr_resolver_t +{ + public: + hostfxr_resolver_t(const pal::string_t& app_root); + ~hostfxr_resolver_t(); + + StatusCode status_code() const { return m_status_code; } + + const pal::string_t& host_path() const { return m_host_path; } + const pal::string_t& dotnet_root() const { return m_dotnet_root; } + const pal::string_t& fxr_path() const { return m_fxr_path; } + + hostfxr_main_bundle_startupinfo_fn resolve_main_bundle_startupinfo(); + hostfxr_set_error_writer_fn resolve_set_error_writer(); + hostfxr_main_startupinfo_fn resolve_main_startupinfo(); + hostfxr_main_fn resolve_main_v1(); + + private: + pal::dll_t m_hostfxr_dll{nullptr}; + + pal::string_t m_host_path; + pal::string_t m_dotnet_root; + pal::string_t m_fxr_path; + + bool m_requires_startupinfo_iface{false}; + StatusCode m_status_code; +}; + +#endif // __HOSTFXR_RESOLVER_T_H__ diff --git a/src/installer/managed/CommonManaged.props b/src/installer/managed/CommonManaged.props index 5195cc2c4dd56c..c96859a92e4a55 100644 --- a/src/installer/managed/CommonManaged.props +++ b/src/installer/managed/CommonManaged.props @@ -16,15 +16,6 @@ true $(NoWarn);CS1591 - - @@ -34,20 +25,6 @@ true - - true - - - - git - git://github.com/dotnet/core-setup - - - - - - - (TValue value, IEqualityComparer comparer) - { - var hashCode = value != null ? comparer.GetHashCode(value) : 0; - Add(hashCode); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static HashCodeCombiner Start() - { - return new HashCodeCombiner(0x1505L); - } - } -} \ No newline at end of file diff --git a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Microsoft.DotNet.PlatformAbstractions.csproj b/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Microsoft.DotNet.PlatformAbstractions.csproj deleted file mode 100644 index 06a5298a882093..00000000000000 --- a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Microsoft.DotNet.PlatformAbstractions.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - - Abstractions for making code that uses file system and environment testable. - net45;netstandard1.3;netstandard2.0 - netstandard1.3;netstandard2.0 - true - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Native/NativeMethods.Darwin.cs b/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Native/NativeMethods.Darwin.cs deleted file mode 100644 index 0e0b7c0c576d6a..00000000000000 --- a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Native/NativeMethods.Darwin.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Runtime.InteropServices; - -namespace Microsoft.DotNet.PlatformAbstractions.Native -{ - internal static partial class NativeMethods - { - public static class Darwin - { - private const int CTL_KERN = 1; - private const int KERN_OSRELEASE = 2; - - public unsafe static string GetKernelRelease() - { - const uint BUFFER_LENGTH = 32; - - var name = stackalloc int[2]; - name[0] = CTL_KERN; - name[1] = KERN_OSRELEASE; - - var buf = stackalloc byte[(int)BUFFER_LENGTH]; - var len = stackalloc uint[1]; - *len = BUFFER_LENGTH; - - try - { - // If the buffer isn't big enough, it seems sysctl still returns 0 and just sets len to the - // necessary buffer size. This appears to be contrary to the man page, but it's easy to detect - // by simply checking len against the buffer length. - if (sysctl(name, 2, buf, len, IntPtr.Zero, 0) == 0 && *len < BUFFER_LENGTH) - { - return Marshal.PtrToStringAnsi((IntPtr)buf, (int)*len); - } - } - catch (Exception ex) - { - throw new PlatformNotSupportedException("Error reading Darwin Kernel Version", ex); - } - throw new PlatformNotSupportedException("Unknown error reading Darwin Kernel Version"); - } - - [DllImport("libc")] - private unsafe static extern int sysctl( - int* name, - uint namelen, - byte* oldp, - uint* oldlenp, - IntPtr newp, - uint newlen); - } - } -} diff --git a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Native/NativeMethods.Unix.cs b/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Native/NativeMethods.Unix.cs deleted file mode 100644 index c1976308260f12..00000000000000 --- a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Native/NativeMethods.Unix.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#if NET45 - -using System; -using System.Runtime.InteropServices; - -namespace Microsoft.DotNet.PlatformAbstractions.Native -{ - internal static partial class NativeMethods - { - public static class Unix - { - public unsafe static string GetUname() - { - // Utsname shouldn't be larger than 2K - var buf = stackalloc byte[2048]; - - try - { - if (uname((IntPtr)buf) == 0) - { - return Marshal.PtrToStringAnsi((IntPtr)buf); - } - } - catch (Exception ex) - { - throw new PlatformNotSupportedException("Error reading Unix name", ex); - } - throw new PlatformNotSupportedException("Unknown error reading Unix name"); - } - - [DllImport("libc")] - private static extern int uname(IntPtr utsname); - } - } -} -#endif \ No newline at end of file diff --git a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Native/NativeMethods.Windows.cs b/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Native/NativeMethods.Windows.cs deleted file mode 100644 index 58c31603a0e1f4..00000000000000 --- a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Native/NativeMethods.Windows.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Runtime.InteropServices; - -namespace Microsoft.DotNet.PlatformAbstractions.Native -{ - internal static partial class NativeMethods - { - public static class Windows - { - [StructLayout(LayoutKind.Sequential)] - internal struct RTL_OSVERSIONINFOEX - { - internal uint dwOSVersionInfoSize; - internal uint dwMajorVersion; - internal uint dwMinorVersion; - internal uint dwBuildNumber; - internal uint dwPlatformId; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] - internal string szCSDVersion; - } - - // This call avoids the shimming Windows does to report old versions - [DllImport("ntdll")] - private static extern int RtlGetVersion(out RTL_OSVERSIONINFOEX lpVersionInformation); - - internal static string RtlGetVersion() - { - RTL_OSVERSIONINFOEX osvi = new RTL_OSVERSIONINFOEX(); - osvi.dwOSVersionInfoSize = (uint)Marshal.SizeOf(osvi); - if (RtlGetVersion(out osvi) == 0) - { - return $"{osvi.dwMajorVersion}.{osvi.dwMinorVersion}.{osvi.dwBuildNumber}"; - } - else - { - return null; - } - } - } - } -} diff --git a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Native/PlatformApis.cs b/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Native/PlatformApis.cs deleted file mode 100644 index 1a344034304e7e..00000000000000 --- a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Native/PlatformApis.cs +++ /dev/null @@ -1,236 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.IO; -using System.Runtime.InteropServices; - -namespace Microsoft.DotNet.PlatformAbstractions.Native -{ - internal static class PlatformApis - { - private class DistroInfo - { - public string Id; - public string VersionId; - } - - private static readonly Lazy _platform = new Lazy(DetermineOSPlatform); - private static readonly Lazy _distroInfo = new Lazy(LoadDistroInfo); - - public static string GetOSName() - { - switch (GetOSPlatform()) - { - case Platform.Windows: - return "Windows"; - case Platform.Linux: - return GetDistroId() ?? "Linux"; - case Platform.Darwin: - return "Mac OS X"; - case Platform.FreeBSD: - return "FreeBSD"; - default: - return "Unknown"; - } - } - - public static string GetOSVersion() - { - switch (GetOSPlatform()) - { - case Platform.Windows: - return NativeMethods.Windows.RtlGetVersion() ?? string.Empty; - case Platform.Linux: - return GetDistroVersionId() ?? string.Empty; - case Platform.Darwin: - return GetDarwinVersion() ?? string.Empty; - case Platform.FreeBSD: - return GetFreeBSDVersion() ?? string.Empty; - default: - return string.Empty; - } - } - - private static string GetDarwinVersion() - { - Version version; - var kernelRelease = NativeMethods.Darwin.GetKernelRelease(); - if (!Version.TryParse(kernelRelease, out version) || version.Major < 5) - { - // 10.0 covers all versions prior to Darwin 5 - // Similarly, if the version is not a valid version number, but we have still detected that it is Darwin, we just assume - // it is OS X 10.0 - return "10.0"; - } - else - { - // Mac OS X 10.1 mapped to Darwin 5.x, and the mapping continues that way - // So just subtract 4 from the Darwin version. - // https://en.wikipedia.org/wiki/Darwin_%28operating_system%29 - return $"10.{version.Major - 4}"; - } - } - - private static string GetFreeBSDVersion() - { - // This is same as sysctl kern.version - // FreeBSD 11.0-RELEASE-p1 FreeBSD 11.0-RELEASE-p1 #0 r306420: Thu Sep 29 01:43:23 UTC 2016 root@releng2.nyi.freebsd.org:/usr/obj/usr/src/sys/GENERIC - // What we want is major release as minor releases should be compatible. - String version = RuntimeInformation.OSDescription; - try - { - // second token up to first dot - return RuntimeInformation.OSDescription.Split()[1].Split('.')[0]; - } - catch - { - } - return string.Empty; - } - - public static Platform GetOSPlatform() - { - return _platform.Value; - } - - private static string GetDistroId() - { - return _distroInfo.Value?.Id; - } - - private static string GetDistroVersionId() - { - return _distroInfo.Value?.VersionId; - } - - private static DistroInfo LoadDistroInfo() - { - DistroInfo result = null; - - // Sample os-release file: - // NAME="Ubuntu" - // VERSION = "14.04.3 LTS, Trusty Tahr" - // ID = ubuntu - // ID_LIKE = debian - // PRETTY_NAME = "Ubuntu 14.04.3 LTS" - // VERSION_ID = "14.04" - // HOME_URL = "http://www.ubuntu.com/" - // SUPPORT_URL = "http://help.ubuntu.com/" - // BUG_REPORT_URL = "http://bugs.launchpad.net/ubuntu/" - // We use ID and VERSION_ID - - if (File.Exists("/etc/os-release")) - { - var lines = File.ReadAllLines("/etc/os-release"); - result = new DistroInfo(); - foreach (var line in lines) - { - if (line.StartsWith("ID=", StringComparison.Ordinal)) - { - result.Id = line.Substring(3).Trim('"', '\''); - } - else if (line.StartsWith("VERSION_ID=", StringComparison.Ordinal)) - { - result.VersionId = line.Substring(11).Trim('"', '\''); - } - } - } - - if (result != null) - { - result = NormalizeDistroInfo(result); - } - - return result; - } - - // For some distros, we don't want to use the full version from VERSION_ID. One example is - // Red Hat Enterprise Linux, which includes a minor version in their VERSION_ID but minor - // versions are backwards compatable. - // - // In this case, we'll normalized RIDs like 'rhel.7.2' and 'rhel.7.3' to a generic - // 'rhel.7'. This brings RHEL in line with other distros like CentOS or Debian which - // don't put minor version numbers in their VERSION_ID fields because all minor versions - // are backwards compatible. - private static DistroInfo NormalizeDistroInfo(DistroInfo distroInfo) - { - // Handle if VersionId is null by just setting the index to -1. - int lastVersionNumberSeparatorIndex = distroInfo.VersionId?.IndexOf('.') ?? -1; - - if (lastVersionNumberSeparatorIndex != -1 && distroInfo.Id == "alpine") - { - // For Alpine, the version reported has three components, so we need to find the second version separator - lastVersionNumberSeparatorIndex = distroInfo.VersionId.IndexOf('.', lastVersionNumberSeparatorIndex + 1); - } - - if (lastVersionNumberSeparatorIndex != -1 && (distroInfo.Id == "rhel" || distroInfo.Id == "alpine")) - { - distroInfo.VersionId = distroInfo.VersionId.Substring(0, lastVersionNumberSeparatorIndex); - } - - return distroInfo; - } - - // I could probably have just done one method signature and put the #if inside the body but the implementations - // are just completely different so I wanted to make that clear by putting the whole thing inside the #if. -#if NET45 - private static Platform DetermineOSPlatform() - { - var platform = (int)Environment.OSVersion.Platform; - var isWindows = (platform != 4) && (platform != 6) && (platform != 128); - - if (isWindows) - { - return Platform.Windows; - } - else - { - try - { - var uname = NativeMethods.Unix.GetUname(); - if (string.Equals(uname, "Darwin", StringComparison.OrdinalIgnoreCase)) - { - return Platform.Darwin; - } - if (string.Equals(uname, "Linux", StringComparison.OrdinalIgnoreCase)) - { - return Platform.Linux; - } - if (string.Equals(uname, "FreeBSD", StringComparison.OrdinalIgnoreCase)) - { - return Platform.FreeBSD; - } - } - catch - { - } - return Platform.Unknown; - } - } -#else - private static Platform DetermineOSPlatform() - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return Platform.Windows; - } - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - return Platform.Linux; - } - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return Platform.Darwin; - } - if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("FREEBSD"))) - { - return Platform.FreeBSD; - } - - return Platform.Unknown; - } -#endif - } -} diff --git a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Platform.cs b/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Platform.cs deleted file mode 100644 index a8d7477ec55c23..00000000000000 --- a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Platform.cs +++ /dev/null @@ -1,14 +0,0 @@ -// 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. - -namespace Microsoft.DotNet.PlatformAbstractions -{ - public enum Platform - { - Unknown = 0, - Windows = 1, - Linux = 2, - Darwin = 3, - FreeBSD = 4 - } -} diff --git a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Properties/Properties.cs b/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Properties/Properties.cs deleted file mode 100644 index ffc81f49b41fee..00000000000000 --- a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/Properties/Properties.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -[assembly: AssemblyMetadataAttribute("Serviceable", "True")] diff --git a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/RuntimeEnvironment.cs b/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/RuntimeEnvironment.cs deleted file mode 100644 index ffece180eb9605..00000000000000 --- a/src/installer/managed/Microsoft.DotNet.PlatformAbstractions/RuntimeEnvironment.cs +++ /dev/null @@ -1,110 +0,0 @@ -// 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 System.Runtime.InteropServices; -using Microsoft.DotNet.PlatformAbstractions.Native; - -namespace Microsoft.DotNet.PlatformAbstractions -{ - public static class RuntimeEnvironment - { - private static readonly string OverrideEnvironmentVariableName = "DOTNET_RUNTIME_ID"; - - public static Platform OperatingSystemPlatform { get; } = PlatformApis.GetOSPlatform(); - - public static string OperatingSystemVersion { get; } = PlatformApis.GetOSVersion(); - - public static string OperatingSystem { get; } = PlatformApis.GetOSName(); - - public static string RuntimeArchitecture { get; } = GetArch(); - - private static string GetArch() - { -#if NET45 - return Environment.Is64BitProcess ? "x64" : "x86"; -#else - return RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant(); -#endif - } - - public static string GetRuntimeIdentifier() - { - return - Environment.GetEnvironmentVariable(OverrideEnvironmentVariableName) ?? - (GetRIDOS() + GetRIDVersion() + GetRIDArch()); - } - - private static string GetRIDArch() - { - return $"-{RuntimeArchitecture}"; - } - - private static string GetRIDVersion() - { - // Windows RIDs do not separate OS name and version by "." due to legacy - // Others do, that's why we have the "." prefix on them below - switch (OperatingSystemPlatform) - { - case Platform.Windows: - return GetWindowsProductVersion(); - case Platform.Linux: - if (string.IsNullOrEmpty(OperatingSystemVersion)) - { - return string.Empty; - } - - return $".{OperatingSystemVersion}"; - case Platform.Darwin: - return $".{OperatingSystemVersion}"; - case Platform.FreeBSD: - return $".{OperatingSystemVersion}"; - default: - return string.Empty; // Unknown Platform? Unknown Version! - } - } - - private static string GetWindowsProductVersion() - { - var ver = Version.Parse(OperatingSystemVersion); - if (ver.Major == 6) - { - if (ver.Minor == 1) - { - return "7"; - } - else if (ver.Minor == 2) - { - return "8"; - } - else if (ver.Minor == 3) - { - return "81"; - } - } - else if (ver.Major >= 10) - { - // Return the major version for use in RID computation without applying any cap. - return ver.Major.ToString(); - } - return string.Empty; // Unknown version - } - - private static string GetRIDOS() - { - switch (OperatingSystemPlatform) - { - case Platform.Windows: - return "win"; - case Platform.Linux: - return OperatingSystem.ToLowerInvariant(); - case Platform.Darwin: - return "osx"; - case Platform.FreeBSD: - return "freebsd"; - default: - return "unknown"; - } - } - } -} diff --git a/src/installer/managed/Microsoft.NET.HostModel/Microsoft.NET.HostModel.csproj b/src/installer/managed/Microsoft.NET.HostModel/Microsoft.NET.HostModel.csproj index 7b1aecfe6cd391..1ea21fdd719233 100644 --- a/src/installer/managed/Microsoft.NET.HostModel/Microsoft.NET.HostModel.csproj +++ b/src/installer/managed/Microsoft.NET.HostModel/Microsoft.NET.HostModel.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -16,7 +16,7 @@ 1.8.0 - + diff --git a/src/installer/pkg/Directory.Build.targets b/src/installer/pkg/Directory.Build.targets index e19dd327b12201..0dd8ca63aef311 100644 --- a/src/installer/pkg/Directory.Build.targets +++ b/src/installer/pkg/Directory.Build.targets @@ -112,6 +112,7 @@ + diff --git a/src/installer/pkg/packaging/installers.proj b/src/installer/pkg/packaging/installers.proj index cfe1bdfc04fb43..2e81105f1a85fd 100644 --- a/src/installer/pkg/packaging/installers.proj +++ b/src/installer/pkg/packaging/installers.proj @@ -1,5 +1,9 @@ + + + true + @@ -117,10 +121,11 @@ - + + diff --git a/src/installer/pkg/packaging/pack-managed.proj b/src/installer/pkg/packaging/pack-managed.proj index 5db5f08264bdc1..acefdfff86d103 100644 --- a/src/installer/pkg/packaging/pack-managed.proj +++ b/src/installer/pkg/packaging/pack-managed.proj @@ -2,7 +2,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) diff --git a/src/installer/pkg/packaging/snaps/arm/dotnet-sdk-3.1/snap/snapcraft.yaml b/src/installer/pkg/packaging/snaps/arm/dotnet-sdk-3.1/snap/snapcraft.yaml new file mode 100644 index 00000000000000..b9d9593496a844 --- /dev/null +++ b/src/installer/pkg/packaging/snaps/arm/dotnet-sdk-3.1/snap/snapcraft.yaml @@ -0,0 +1,40 @@ +name: dotnet-sdk +version: 3.1.201 +summary: Cross-Platform .NET Core SDK +description: | + .NET Core SDK. https://dot.net/core. + +grade: stable +confinement: classic + +apps: + dotnet: + command: dotnet + +architectures: + - build-on: [amd64] + run-on: [armhf] + +base: core + +parts: + dotnet-sdk: + plugin: dump + source: https://download.visualstudio.microsoft.com/download/pr/ccbcbf70-9911-40b1-a8cf-e018a13e720e/03c0621c6510f9c6f4cca6951f2cc1a4/dotnet-sdk-3.1.201-linux-arm.tar.gz + source-checksum: sha512/f37d0e55c9f593c6951bea5a6bb1ea3194486956efe08a2a0f266b419d912cdcbf4ac279358976f0bfa1fe560c333ca5d5437f8e8c718bb5963991e4395e0cd7 + stage-packages: + - libicu55 + - libssl1.0.0 + - libcurl3 + - libgssapi-krb5-2 + - libstdc++6 + - zlib1g + - libgcc1 + - libtinfo5 + - liblttng-ust0 + - liburcu4 + + runtime-wrapper: + plugin: dump + source: . + diff --git a/src/installer/pkg/packaging/snaps/arm/dotnet-sdk-5.0/snap/snapcraft.yaml b/src/installer/pkg/packaging/snaps/arm/dotnet-sdk-5.0/snap/snapcraft.yaml new file mode 100644 index 00000000000000..c9e2ab7efb6c28 --- /dev/null +++ b/src/installer/pkg/packaging/snaps/arm/dotnet-sdk-5.0/snap/snapcraft.yaml @@ -0,0 +1,40 @@ +name: dotnet-sdk +version: 5.0.100-preview.2.20176.6 +summary: Cross-Platform .NET Core SDK +description: | + .NET Core SDK. https://dot.net/core. + +grade: stable +confinement: classic + +apps: + dotnet: + command: dotnet + +architectures: + - build-on: [amd64] + run-on: [armhf] + +base: core + +parts: + dotnet-sdk: + plugin: dump + source: https://download.visualstudio.microsoft.com/download/pr/f87574ee-c128-4e91-b436-68c99d801daf/b296bea9d987a4edaa71df47cd2e7aca/dotnet-sdk-5.0.100-preview.2.20176.6-linux-arm64.tar.gz + source-checksum: sha512/53cbf213e2e97b909b256d931f061178f26e5647424f144266d4af2e12d6443ef7398207a8f4e6f220c61db9ce49de3dc09d88417288a6a61d9b05e1def6b279 + stage-packages: + - libicu55 + - libssl1.0.0 + - libcurl3 + - libgssapi-krb5-2 + - libstdc++6 + - zlib1g + - libgcc1 + - libtinfo5 + - liblttng-ust0 + - liburcu4 + + runtime-wrapper: + plugin: dump + source: . + diff --git a/src/installer/pkg/packaging/snaps/arm64/dotnet-sdk-5.0/snap/snapcraft.yaml b/src/installer/pkg/packaging/snaps/arm64/dotnet-sdk-5.0/snap/snapcraft.yaml new file mode 100644 index 00000000000000..94a9af147619cd --- /dev/null +++ b/src/installer/pkg/packaging/snaps/arm64/dotnet-sdk-5.0/snap/snapcraft.yaml @@ -0,0 +1,40 @@ +name: dotnet-sdk +version: 5.0.100-preview.2.20176.6 +summary: Cross-Platform .NET Core SDK +description: | + .NET Core SDK. https://dot.net/core. + +grade: stable +confinement: classic + +apps: + dotnet: + command: dotnet + +architectures: + - build-on: [amd64] + run-on: [arm64] + +base: core18 + +parts: + dotnet-sdk: + plugin: dump + source: https://download.visualstudio.microsoft.com/download/pr/f87574ee-c128-4e91-b436-68c99d801daf/b296bea9d987a4edaa71df47cd2e7aca/dotnet-sdk-5.0.100-preview.2.20176.6-linux-arm64.tar.gz + source-checksum: sha512/53cbf213e2e97b909b256d931f061178f26e5647424f144266d4af2e12d6443ef7398207a8f4e6f220c61db9ce49de3dc09d88417288a6a61d9b05e1def6b279 + stage-packages: + - libicu60 + - libssl1.0.0 + - libcurl3 + - libgssapi-krb5-2 + - libstdc++6 + - zlib1g + - libgcc1 + - libtinfo5 + - liblttng-ust0 + - liburcu6 + + runtime-wrapper: + plugin: dump + source: . + diff --git a/src/installer/pkg/packaging/snaps/dotnet-runtime-5.0/snap/snapcraft.yaml b/src/installer/pkg/packaging/snaps/dotnet-runtime-5.0/snap/snapcraft.yaml index 4065eb2b2e1e86..8dd11b75f409fd 100644 --- a/src/installer/pkg/packaging/snaps/dotnet-runtime-5.0/snap/snapcraft.yaml +++ b/src/installer/pkg/packaging/snaps/dotnet-runtime-5.0/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: dotnet-runtime-50 base: core18 -version: 5.0.0-preview.1.20124.5 +version: 5.0.0-preview.2.20167.3 summary: Cross-Platform .NET Core Runtime. description: | .NET Core runtimes and libraries which are optimized for running .NET Core apps in production. See https://dot.net/core. @@ -27,8 +27,8 @@ slots: parts: dotnet-runtime: plugin: dump - source: https://download.visualstudio.microsoft.com/download/pr/c88ef7f1-c62a-4ef6-810e-87f5d6152217/96c52963aa875fbcd9131f42075ff5c9/aspnetcore-runtime-5.0.0-preview.1.20124.5-linux-x64.tar.gz - source-checksum: sha512/4ec2c9e8ed5e8ddaa52ed291c263412b754691ae2b95362ddc6fa75cfe087dbe59c7e4f65f21b0f096bc93967d04f4ea612a0c42c8a124ef4583d0de8daac01c + source: https://download.visualstudio.microsoft.com/download/pr/169871b7-ce8f-4518-a342-209f98342569/4bb2abeecf4b064eac907fb28f96b5ca/aspnetcore-runtime-5.0.0-preview.2.20167.3-linux-x64.tar.gz + source-checksum: sha512/c155a94b463020f413b9cc6650219b27c08f331f9d1926966e4c4471b1a3cc79e199fbbd4747e8ad89bd03d66cd90cbc68a5554c54e931ac59f7508810303327 stage-packages: - libicu60 - libssl1.0.0 diff --git a/src/installer/pkg/packaging/snaps/dotnet-sdk-5.0/snap/snapcraft.yaml b/src/installer/pkg/packaging/snaps/dotnet-sdk-5.0/snap/snapcraft.yaml index 12183ad1219d90..02eaa69deef59b 100644 --- a/src/installer/pkg/packaging/snaps/dotnet-sdk-5.0/snap/snapcraft.yaml +++ b/src/installer/pkg/packaging/snaps/dotnet-sdk-5.0/snap/snapcraft.yaml @@ -1,5 +1,5 @@ name: dotnet-sdk -version: 5.0.100-preview.1.20155.7 +version: 5.0.100-preview.2.20176.6 summary: Cross-Platform .NET Core SDK description: | .NET Core SDK. https://dot.net/core. @@ -16,8 +16,8 @@ base: core18 parts: dotnet-sdk: plugin: dump - source: https://download.visualstudio.microsoft.com/download/pr/5b2263be-2e9c-48f4-8bcb-46018b512dd3/664228f47b82f6c530b168c940a9dfa5/dotnet-sdk-5.0.100-preview.1.20155.7-linux-x64.tar.gz - source-checksum: sha512/e768641ef12604400edf4ba25bd7ea7a2e64c69fa447661b478ceff89f3c77c07ec69f3aa05b966400e88caae4f548a7bfc5a0747f511b5a10e88dd616f73b21 + source: https://download.visualstudio.microsoft.com/download/pr/727a5825-d29a-4f45-beaa-053399f8b5ee/5f15827ceb4851ef87a008f5de0acf6c/dotnet-sdk-5.0.100-preview.2.20176.6-linux-x64.tar.gz + source-checksum: sha512/fface8ff5facdec10d11f8249b426a71cd5bc17aa4e4b1fbe85f4a462e55bdb648a456973a3257f0a700be1aeb0f9bb41639ceca12c2e67d1571e4544ae62bd7 stage-packages: - libicu60 - libssl1.0.0 diff --git a/src/installer/pkg/packaging/vs-insertion-packages.proj b/src/installer/pkg/packaging/vs-insertion-packages.proj index f36b24f9d1cac1..fd69aea557f755 100644 --- a/src/installer/pkg/packaging/vs-insertion-packages.proj +++ b/src/installer/pkg/packaging/vs-insertion-packages.proj @@ -2,7 +2,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) diff --git a/src/installer/pkg/projects/Directory.Build.props b/src/installer/pkg/projects/Directory.Build.props index 40403c6fcd07f4..9d6ae93d467c39 100644 --- a/src/installer/pkg/projects/Directory.Build.props +++ b/src/installer/pkg/projects/Directory.Build.props @@ -81,9 +81,9 @@ null-refs when this isn't set and an analyzer is in the packages --> unused - $(NETCoreAppFrameworkMoniker) - $(NETCoreAppFramework) - $(NETCoreAppFramework) + $(NetCoreAppCurrentTargetFrameworkMoniker) + $(NetCoreAppCurrent) + $(NetCoreAppCurrent) $(CrossGenRootPath)$(MSBuildProjectName)\ true true @@ -92,7 +92,7 @@ $(PackageTargetFramework) - $(NETCoreAppFramework) + $(NetCoreAppCurrent) diff --git a/src/installer/pkg/projects/Directory.Build.targets b/src/installer/pkg/projects/Directory.Build.targets index 55c28ef3d5deba..cfe8c6400779ce 100644 --- a/src/installer/pkg/projects/Directory.Build.targets +++ b/src/installer/pkg/projects/Directory.Build.targets @@ -3,8 +3,8 @@ - - + + $(Version) + true - true + + .Mono + + + .Mono.LLVM + + + .Mono.LLVM.AOT + + - + @@ -320,7 +331,8 @@ FileClassifications="@(FrameworkListFileClass)" TargetFile="$(FrameworkListFile)" TargetFilePrefixes="ref/;runtimes/" - RootAttributes="@(FrameworkListRootAttributes)" /> + RootAttributes="@(FrameworkListRootAttributes)" + SingleFileHostIncludeFilenames="@(SingleFileHostIncludeFilename)" /> @@ -367,7 +379,7 @@ + ExcludeAssets="All" /> diff --git a/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/runtime.Windows_NT.Microsoft.NETCore.DotNetAppHost.props b/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/runtime.Windows_NT.Microsoft.NETCore.DotNetAppHost.props index c74da91a0f25ca..6d52e1984f8ce5 100644 --- a/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/runtime.Windows_NT.Microsoft.NETCore.DotNetAppHost.props +++ b/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/runtime.Windows_NT.Microsoft.NETCore.DotNetAppHost.props @@ -2,6 +2,7 @@ + diff --git a/src/installer/pkg/projects/netcoreapp/Directory.Build.props b/src/installer/pkg/projects/netcoreapp/Directory.Build.props index 859b4a53acf80d..59ac9e4269092b 100644 --- a/src/installer/pkg/projects/netcoreapp/Directory.Build.props +++ b/src/installer/pkg/projects/netcoreapp/Directory.Build.props @@ -12,7 +12,10 @@ iOS tvOS Android + Browser FreeBSD + NetBSD + SunOS $(CoreCLRTargetOS) diff --git a/src/installer/pkg/projects/netcoreapp/pkg/Directory.Build.props b/src/installer/pkg/projects/netcoreapp/pkg/Directory.Build.props index a34488f1be6c3a..e616a7cfc1f9a4 100644 --- a/src/installer/pkg/projects/netcoreapp/pkg/Directory.Build.props +++ b/src/installer/pkg/projects/netcoreapp/pkg/Directory.Build.props @@ -6,12 +6,39 @@ - $(NETCoreAppFrameworkBrandName) - $(NETCoreAppFrameworkIdentifier) - $(NETCoreAppFrameworkVersion) + $(NetCoreAppCurrentBrandName) + $(NetCoreAppCurrentIdentifier) + $(NetCoreAppCurrentVersion) $(SharedFrameworkName) + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -29,4 +30,4 @@ true - \ No newline at end of file + diff --git a/src/installer/pkg/projects/netcoreapp/pkg/Microsoft.NETCore.App.Runtime.pkgproj b/src/installer/pkg/projects/netcoreapp/pkg/Microsoft.NETCore.App.Runtime.pkgproj index 849156bc8a3e97..8d64fb1fc1aca4 100644 --- a/src/installer/pkg/projects/netcoreapp/pkg/Microsoft.NETCore.App.Runtime.pkgproj +++ b/src/installer/pkg/projects/netcoreapp/pkg/Microsoft.NETCore.App.Runtime.pkgproj @@ -5,9 +5,7 @@ shared framework on those platforms. --> - true - true - true + true - diff --git a/src/installer/pkg/projects/netcoreapp/pkg/legacy/Directory.Build.props b/src/installer/pkg/projects/netcoreapp/pkg/legacy/Directory.Build.props index 96a120662af60e..03473f6c66f5bb 100644 --- a/src/installer/pkg/projects/netcoreapp/pkg/legacy/Directory.Build.props +++ b/src/installer/pkg/projects/netcoreapp/pkg/legacy/Directory.Build.props @@ -3,7 +3,7 @@ true - build/$(NETCoreAppFramework)/ + build/$(NetCoreAppCurrent)/ false @@ -17,7 +17,7 @@ + TargetFramework="$(NetCoreAppCurrent)" /> diff --git a/src/installer/pkg/projects/netcoreapp/pkg/legacy/Microsoft.NETCore.App.Internal.pkgproj b/src/installer/pkg/projects/netcoreapp/pkg/legacy/Microsoft.NETCore.App.Internal.pkgproj index bea575e85c83ba..a46f80401902f5 100644 --- a/src/installer/pkg/projects/netcoreapp/pkg/legacy/Microsoft.NETCore.App.Internal.pkgproj +++ b/src/installer/pkg/projects/netcoreapp/pkg/legacy/Microsoft.NETCore.App.Internal.pkgproj @@ -3,6 +3,7 @@ $(MSBuildThisFileDirectory)Microsoft.NETCore.App.pkgproj + true @@ -19,8 +20,8 @@ - - + + diff --git a/src/installer/pkg/projects/netcoreapp/pkg/legacy/Microsoft.NETCore.App.pkgproj b/src/installer/pkg/projects/netcoreapp/pkg/legacy/Microsoft.NETCore.App.pkgproj index a797eccbbcf611..4ca074396a5380 100644 --- a/src/installer/pkg/projects/netcoreapp/pkg/legacy/Microsoft.NETCore.App.pkgproj +++ b/src/installer/pkg/projects/netcoreapp/pkg/legacy/Microsoft.NETCore.App.pkgproj @@ -8,6 +8,7 @@ false data/ + true diff --git a/src/installer/pkg/projects/netcoreapp/pkg/workaround/Microsoft.NETCore.App.pkgproj b/src/installer/pkg/projects/netcoreapp/pkg/workaround/Microsoft.NETCore.App.pkgproj index d9d6f3423c3dda..d5ae432d189a4b 100644 --- a/src/installer/pkg/projects/netcoreapp/pkg/workaround/Microsoft.NETCore.App.pkgproj +++ b/src/installer/pkg/projects/netcoreapp/pkg/workaround/Microsoft.NETCore.App.pkgproj @@ -17,6 +17,7 @@ false false + true diff --git a/src/installer/pkg/projects/netcoreapp/sfx/Microsoft.NETCore.App.SharedFx.sfxproj b/src/installer/pkg/projects/netcoreapp/sfx/Microsoft.NETCore.App.SharedFx.sfxproj index d12d993a3ff613..f1aab81eb8a4b8 100644 --- a/src/installer/pkg/projects/netcoreapp/sfx/Microsoft.NETCore.App.SharedFx.sfxproj +++ b/src/installer/pkg/projects/netcoreapp/sfx/Microsoft.NETCore.App.SharedFx.sfxproj @@ -45,6 +45,30 @@ + + + + + + + + + + + + + + + + + + + + x86 @@ -34,6 +36,7 @@ + armel diff --git a/src/installer/publish/Directory.Build.props b/src/installer/publish/Directory.Build.props index adae9ea9ed0af8..de832e525302d3 100644 --- a/src/installer/publish/Directory.Build.props +++ b/src/installer/publish/Directory.Build.props @@ -3,7 +3,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) diff --git a/src/installer/signing/Directory.Build.props b/src/installer/signing/Directory.Build.props index 8fcaf35bd68f99..7c45d0300be126 100644 --- a/src/installer/signing/Directory.Build.props +++ b/src/installer/signing/Directory.Build.props @@ -3,7 +3,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) true diff --git a/src/installer/signing/SignBinaries.proj b/src/installer/signing/SignBinaries.proj index d1f8fb542904eb..8b1f6811f442f4 100644 --- a/src/installer/signing/SignBinaries.proj +++ b/src/installer/signing/SignBinaries.proj @@ -1,7 +1,7 @@ - + diff --git a/src/installer/signing/SignBurnBundleFiles.proj b/src/installer/signing/SignBurnBundleFiles.proj index 52cac286090a1a..55c7a8c5810de0 100644 --- a/src/installer/signing/SignBurnBundleFiles.proj +++ b/src/installer/signing/SignBurnBundleFiles.proj @@ -4,7 +4,7 @@ diff --git a/src/installer/signing/SignBurnEngineFiles.proj b/src/installer/signing/SignBurnEngineFiles.proj index dc610b685cfb31..382eb202318fb5 100644 --- a/src/installer/signing/SignBurnEngineFiles.proj +++ b/src/installer/signing/SignBurnEngineFiles.proj @@ -1,7 +1,7 @@ - + diff --git a/src/installer/signing/SignMsiFiles.proj b/src/installer/signing/SignMsiFiles.proj index 55804e6c46c4ea..55dd18dca67327 100644 --- a/src/installer/signing/SignMsiFiles.proj +++ b/src/installer/signing/SignMsiFiles.proj @@ -1,7 +1,7 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ನಮಸ್ಕಾರ + + \ No newline at end of file diff --git a/src/installer/test/Assets/TestProjects/LocalizedApp/Hello.resx b/src/installer/test/Assets/TestProjects/LocalizedApp/Hello.resx new file mode 100644 index 00000000000000..81893ab57f0af6 --- /dev/null +++ b/src/installer/test/Assets/TestProjects/LocalizedApp/Hello.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Hello + + \ No newline at end of file diff --git a/src/installer/test/Assets/TestProjects/LocalizedApp/Hello.ta-IN.resx b/src/installer/test/Assets/TestProjects/LocalizedApp/Hello.ta-IN.resx new file mode 100644 index 00000000000000..b42699bbee2136 --- /dev/null +++ b/src/installer/test/Assets/TestProjects/LocalizedApp/Hello.ta-IN.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + வணக்கம் + + \ No newline at end of file diff --git a/src/installer/test/Assets/TestProjects/LocalizedApp/LocalizedApp.csproj b/src/installer/test/Assets/TestProjects/LocalizedApp/LocalizedApp.csproj new file mode 100644 index 00000000000000..dd7e2b67f9d89c --- /dev/null +++ b/src/installer/test/Assets/TestProjects/LocalizedApp/LocalizedApp.csproj @@ -0,0 +1,32 @@ + + + + $(NetCoreAppCurrent) + Exe + $(TestTargetRid) + $(MNAVersion) + + + + + True + True + Hello.resx + + + + + + ResXFileCodeGenerator + Hello.Designer.cs + + + PublicResXFileCodeGenerator + Always + + + ResXFileCodeGenerator + + + + diff --git a/src/installer/test/Assets/TestProjects/LocalizedApp/Program.cs b/src/installer/test/Assets/TestProjects/LocalizedApp/Program.cs new file mode 100644 index 00000000000000..1999cc46f1812b --- /dev/null +++ b/src/installer/test/Assets/TestProjects/LocalizedApp/Program.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information.using System; + +using System; +using System.Threading; +using System.Globalization; +using System.Resources; + +namespace LocalizedApp +{ + class Program + { + static void Main() + { + string [] cultures = { "kn-IN", "ta-IN", "en-US" }; + string greeting = ""; + foreach (var culture in cultures) + { + Thread.CurrentThread.CurrentUICulture = new CultureInfo(culture); + greeting += $"{Hello.Greet}! "; + } + + Console.WriteLine(greeting); + } + } +} diff --git a/src/installer/test/Assets/TestProjects/PortableApp/PortableApp.csproj b/src/installer/test/Assets/TestProjects/PortableApp/PortableApp.csproj index 369a294da0f7c1..0a72b6bc1fcd79 100644 --- a/src/installer/test/Assets/TestProjects/PortableApp/PortableApp.csproj +++ b/src/installer/test/Assets/TestProjects/PortableApp/PortableApp.csproj @@ -1,9 +1,9 @@ - + - $(NETCoreAppFramework) + $(NetCoreAppCurrent) Exe $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/PortableApp/Program.cs b/src/installer/test/Assets/TestProjects/PortableApp/Program.cs index 70117514e89fa7..5df7e2952f8fea 100644 --- a/src/installer/test/Assets/TestProjects/PortableApp/Program.cs +++ b/src/installer/test/Assets/TestProjects/PortableApp/Program.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Runtime.InteropServices; namespace PortableApp { @@ -12,15 +13,10 @@ public static void Main(string[] args) { Console.WriteLine("Hello World!"); Console.WriteLine(string.Join(Environment.NewLine, args)); - Console.WriteLine($"Framework Version:{GetFrameworkVersionFromAppDomain()}"); + Console.WriteLine(RuntimeInformation.FrameworkDescription); // A small operation involving NewtonSoft.Json to ensure the assembly is loaded properly var t = typeof(Newtonsoft.Json.JsonReader); } - - private static string GetFrameworkVersionFromAppDomain() - { - return System.AppDomain.CurrentDomain.GetData("FX_PRODUCT_VERSION") as string; - } } } diff --git a/src/installer/test/Assets/TestProjects/PortableAppWithException/PortableAppWithException.csproj b/src/installer/test/Assets/TestProjects/PortableAppWithException/PortableAppWithException.csproj index 80f4310d003df7..f413febe3ff59a 100644 --- a/src/installer/test/Assets/TestProjects/PortableAppWithException/PortableAppWithException.csproj +++ b/src/installer/test/Assets/TestProjects/PortableAppWithException/PortableAppWithException.csproj @@ -1,7 +1,7 @@ - + - $(NETCoreAppFramework) + $(NetCoreAppCurrent) Exe $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/PortableAppWithLongPath/PortableAppWithLongPath.csproj b/src/installer/test/Assets/TestProjects/PortableAppWithLongPath/PortableAppWithLongPath.csproj index 80f4310d003df7..f413febe3ff59a 100644 --- a/src/installer/test/Assets/TestProjects/PortableAppWithLongPath/PortableAppWithLongPath.csproj +++ b/src/installer/test/Assets/TestProjects/PortableAppWithLongPath/PortableAppWithLongPath.csproj @@ -1,7 +1,7 @@ - + - $(NETCoreAppFramework) + $(NetCoreAppCurrent) Exe $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/PortableAppWithMissingRef/PortableAppWithMissingRef.csproj b/src/installer/test/Assets/TestProjects/PortableAppWithMissingRef/PortableAppWithMissingRef.csproj index 138175a919dc11..17d3f0556923de 100644 --- a/src/installer/test/Assets/TestProjects/PortableAppWithMissingRef/PortableAppWithMissingRef.csproj +++ b/src/installer/test/Assets/TestProjects/PortableAppWithMissingRef/PortableAppWithMissingRef.csproj @@ -1,7 +1,7 @@ - + - $(NETCoreAppFramework) + $(NetCoreAppCurrent) Exe $(MNAVersion) false diff --git a/src/installer/test/Assets/TestProjects/PortableAppWithMissingRef/SharedLibrary/ReferenceLibrary.csproj b/src/installer/test/Assets/TestProjects/PortableAppWithMissingRef/SharedLibrary/ReferenceLibrary.csproj index 427e95cc1ac3a4..715eb5425edb00 100644 --- a/src/installer/test/Assets/TestProjects/PortableAppWithMissingRef/SharedLibrary/ReferenceLibrary.csproj +++ b/src/installer/test/Assets/TestProjects/PortableAppWithMissingRef/SharedLibrary/ReferenceLibrary.csproj @@ -1,7 +1,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) Library $(MNAVersion) SharedLibrary diff --git a/src/installer/test/Assets/TestProjects/PortableTestApp/PortableTestApp.csproj b/src/installer/test/Assets/TestProjects/PortableTestApp/PortableTestApp.csproj index fbd0b540b5adc5..26b183bbec0853 100644 --- a/src/installer/test/Assets/TestProjects/PortableTestApp/PortableTestApp.csproj +++ b/src/installer/test/Assets/TestProjects/PortableTestApp/PortableTestApp.csproj @@ -1,7 +1,7 @@ - + - $(NETCoreAppFramework) + $(NetCoreAppCurrent) true $(PackageTargetFallback);dotnet5.4;portable-net451+win8 $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/ResourceLookup/ResourceLookup.csproj b/src/installer/test/Assets/TestProjects/ResourceLookup/ResourceLookup.csproj index 554c7405d130f6..50e675ffb951f5 100644 --- a/src/installer/test/Assets/TestProjects/ResourceLookup/ResourceLookup.csproj +++ b/src/installer/test/Assets/TestProjects/ResourceLookup/ResourceLookup.csproj @@ -1,7 +1,7 @@ - + - $(NETCoreAppFramework) + $(NetCoreAppCurrent) Exe $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/RuntimeProperties/RuntimeProperties.csproj b/src/installer/test/Assets/TestProjects/RuntimeProperties/RuntimeProperties.csproj index 80f4310d003df7..f413febe3ff59a 100644 --- a/src/installer/test/Assets/TestProjects/RuntimeProperties/RuntimeProperties.csproj +++ b/src/installer/test/Assets/TestProjects/RuntimeProperties/RuntimeProperties.csproj @@ -1,7 +1,7 @@ - + - $(NETCoreAppFramework) + $(NetCoreAppCurrent) Exe $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/SharedFxLookupPortableApp/Program.cs b/src/installer/test/Assets/TestProjects/SharedFxLookupPortableApp/Program.cs index 6c0e33b99d4a1e..b4d2e65cb6aee3 100644 --- a/src/installer/test/Assets/TestProjects/SharedFxLookupPortableApp/Program.cs +++ b/src/installer/test/Assets/TestProjects/SharedFxLookupPortableApp/Program.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Runtime.InteropServices; namespace SharedFxLookupPortableApp { @@ -12,15 +13,10 @@ public static void Main(string[] args) { Console.WriteLine("Hello World!"); Console.WriteLine(string.Join(Environment.NewLine, args)); - Console.WriteLine($"Framework Version:{GetFrameworkVersionFromAppDomain()}"); + Console.WriteLine(RuntimeInformation.FrameworkDescription); // A small operation involving NewtonSoft.Json to ensure the assembly is loaded properly var t = typeof(Newtonsoft.Json.JsonReader); } - - private static string GetFrameworkVersionFromAppDomain() - { - return System.AppDomain.CurrentDomain.GetData("FX_PRODUCT_VERSION") as string; - } } } diff --git a/src/installer/test/Assets/TestProjects/SharedFxLookupPortableApp/SharedFxLookupPortableApp.csproj b/src/installer/test/Assets/TestProjects/SharedFxLookupPortableApp/SharedFxLookupPortableApp.csproj index 83efdd4f119d8e..e1f97d2216d9a8 100644 --- a/src/installer/test/Assets/TestProjects/SharedFxLookupPortableApp/SharedFxLookupPortableApp.csproj +++ b/src/installer/test/Assets/TestProjects/SharedFxLookupPortableApp/SharedFxLookupPortableApp.csproj @@ -1,7 +1,7 @@ - + - $(NETCoreAppFramework) + $(NetCoreAppCurrent) Exe $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/StandaloneApp/Program.cs b/src/installer/test/Assets/TestProjects/StandaloneApp/Program.cs index dca0b185f29bb7..9e65e3b0c84f2e 100644 --- a/src/installer/test/Assets/TestProjects/StandaloneApp/Program.cs +++ b/src/installer/test/Assets/TestProjects/StandaloneApp/Program.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Runtime.InteropServices; namespace StandaloneApp { @@ -12,15 +13,10 @@ public static void Main(string[] args) { Console.WriteLine("Hello World!"); Console.WriteLine(string.Join(Environment.NewLine, args)); - Console.WriteLine($"Framework Version:{GetFrameworkVersionFromAppDomain()}"); + Console.WriteLine(RuntimeInformation.FrameworkDescription); // A small operation involving NewtonSoft.Json to ensure the assembly is loaded properly var t = typeof(Newtonsoft.Json.JsonReader); } - - private static string GetFrameworkVersionFromAppDomain() - { - return System.AppDomain.CurrentDomain.GetData("FX_PRODUCT_VERSION") as string; - } } } diff --git a/src/installer/test/Assets/TestProjects/StandaloneApp/StandaloneApp.csproj b/src/installer/test/Assets/TestProjects/StandaloneApp/StandaloneApp.csproj index 6c7f3f31e9d537..0846750fb7c918 100644 --- a/src/installer/test/Assets/TestProjects/StandaloneApp/StandaloneApp.csproj +++ b/src/installer/test/Assets/TestProjects/StandaloneApp/StandaloneApp.csproj @@ -1,7 +1,7 @@ - + - $(NETCoreAppFramework) + $(NetCoreAppCurrent) Exe $(TestTargetRid) $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/StandaloneApp20/StandaloneApp20.csproj b/src/installer/test/Assets/TestProjects/StandaloneApp20/StandaloneApp20.csproj index db493aa1e3b0ac..14513b05b71a92 100644 --- a/src/installer/test/Assets/TestProjects/StandaloneApp20/StandaloneApp20.csproj +++ b/src/installer/test/Assets/TestProjects/StandaloneApp20/StandaloneApp20.csproj @@ -1,4 +1,4 @@ - + StandaloneApp diff --git a/src/installer/test/Assets/TestProjects/StandaloneApp21/StandaloneApp21.csproj b/src/installer/test/Assets/TestProjects/StandaloneApp21/StandaloneApp21.csproj index 5027077c2262c3..c8593050181b19 100644 --- a/src/installer/test/Assets/TestProjects/StandaloneApp21/StandaloneApp21.csproj +++ b/src/installer/test/Assets/TestProjects/StandaloneApp21/StandaloneApp21.csproj @@ -1,4 +1,4 @@ - + StandaloneApp diff --git a/src/installer/test/Assets/TestProjects/StandaloneApp3x/StandaloneApp3x.csproj b/src/installer/test/Assets/TestProjects/StandaloneApp3x/StandaloneApp3x.csproj index ef3ae317a3feaa..c4d62b9512ec81 100644 --- a/src/installer/test/Assets/TestProjects/StandaloneApp3x/StandaloneApp3x.csproj +++ b/src/installer/test/Assets/TestProjects/StandaloneApp3x/StandaloneApp3x.csproj @@ -1,4 +1,4 @@ - + StandaloneApp netcoreapp3.0;netcoreapp3.1 diff --git a/src/installer/test/Assets/TestProjects/StandaloneTestApp/StandaloneTestApp.csproj b/src/installer/test/Assets/TestProjects/StandaloneTestApp/StandaloneTestApp.csproj index dbc7efaea35ebb..42bc4348e5d5b9 100644 --- a/src/installer/test/Assets/TestProjects/StandaloneTestApp/StandaloneTestApp.csproj +++ b/src/installer/test/Assets/TestProjects/StandaloneTestApp/StandaloneTestApp.csproj @@ -1,7 +1,7 @@ - + - $(NETCoreAppFramework) + $(NetCoreAppCurrent) Exe true $(PackageTargetFallback);dotnet5.4;portable-net451+win8 diff --git a/src/installer/test/Assets/TestProjects/StartupHook/StartupHook.csproj b/src/installer/test/Assets/TestProjects/StartupHook/StartupHook.csproj index 07612ef9143b4a..637cbf46c656dd 100644 --- a/src/installer/test/Assets/TestProjects/StartupHook/StartupHook.csproj +++ b/src/installer/test/Assets/TestProjects/StartupHook/StartupHook.csproj @@ -1,7 +1,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/StartupHookFake/StartupHookFake.csproj b/src/installer/test/Assets/TestProjects/StartupHookFake/StartupHookFake.csproj index 30c7a27baa05c9..f55862545f6a5e 100644 --- a/src/installer/test/Assets/TestProjects/StartupHookFake/StartupHookFake.csproj +++ b/src/installer/test/Assets/TestProjects/StartupHookFake/StartupHookFake.csproj @@ -1,7 +1,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/StartupHookWithAssemblyResolver/SharedLibrary/SharedLibrary.csproj b/src/installer/test/Assets/TestProjects/StartupHookWithAssemblyResolver/SharedLibrary/SharedLibrary.csproj index 2affa7647bebeb..6c0a57b1b0b8aa 100644 --- a/src/installer/test/Assets/TestProjects/StartupHookWithAssemblyResolver/SharedLibrary/SharedLibrary.csproj +++ b/src/installer/test/Assets/TestProjects/StartupHookWithAssemblyResolver/SharedLibrary/SharedLibrary.csproj @@ -1,7 +1,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) Library $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/StartupHookWithAssemblyResolver/StartupHookWithAssemblyResolver.csproj b/src/installer/test/Assets/TestProjects/StartupHookWithAssemblyResolver/StartupHookWithAssemblyResolver.csproj index 3fe787852504b6..e15ced0349c714 100644 --- a/src/installer/test/Assets/TestProjects/StartupHookWithAssemblyResolver/StartupHookWithAssemblyResolver.csproj +++ b/src/installer/test/Assets/TestProjects/StartupHookWithAssemblyResolver/StartupHookWithAssemblyResolver.csproj @@ -1,7 +1,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) $(MNAVersion) false diff --git a/src/installer/test/Assets/TestProjects/StartupHookWithDependency/StartupHookWithDependency.csproj b/src/installer/test/Assets/TestProjects/StartupHookWithDependency/StartupHookWithDependency.csproj index 8726c60e29aa52..cc51ff2471c3e7 100644 --- a/src/installer/test/Assets/TestProjects/StartupHookWithDependency/StartupHookWithDependency.csproj +++ b/src/installer/test/Assets/TestProjects/StartupHookWithDependency/StartupHookWithDependency.csproj @@ -1,7 +1,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/StartupHookWithInstanceMethod/StartupHookWithInstanceMethod.csproj b/src/installer/test/Assets/TestProjects/StartupHookWithInstanceMethod/StartupHookWithInstanceMethod.csproj index 07612ef9143b4a..637cbf46c656dd 100644 --- a/src/installer/test/Assets/TestProjects/StartupHookWithInstanceMethod/StartupHookWithInstanceMethod.csproj +++ b/src/installer/test/Assets/TestProjects/StartupHookWithInstanceMethod/StartupHookWithInstanceMethod.csproj @@ -1,7 +1,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/StartupHookWithMultipleIncorrectSignatures/StartupHookWithMultipleIncorrectSignatures.csproj b/src/installer/test/Assets/TestProjects/StartupHookWithMultipleIncorrectSignatures/StartupHookWithMultipleIncorrectSignatures.csproj index 07612ef9143b4a..637cbf46c656dd 100644 --- a/src/installer/test/Assets/TestProjects/StartupHookWithMultipleIncorrectSignatures/StartupHookWithMultipleIncorrectSignatures.csproj +++ b/src/installer/test/Assets/TestProjects/StartupHookWithMultipleIncorrectSignatures/StartupHookWithMultipleIncorrectSignatures.csproj @@ -1,7 +1,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/StartupHookWithNonPublicMethod/StartupHookWithNonPublicMethod.csproj b/src/installer/test/Assets/TestProjects/StartupHookWithNonPublicMethod/StartupHookWithNonPublicMethod.csproj index 07612ef9143b4a..637cbf46c656dd 100644 --- a/src/installer/test/Assets/TestProjects/StartupHookWithNonPublicMethod/StartupHookWithNonPublicMethod.csproj +++ b/src/installer/test/Assets/TestProjects/StartupHookWithNonPublicMethod/StartupHookWithNonPublicMethod.csproj @@ -1,7 +1,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/StartupHookWithOverload/StartupHookWithOverload.csproj b/src/installer/test/Assets/TestProjects/StartupHookWithOverload/StartupHookWithOverload.csproj index 07612ef9143b4a..637cbf46c656dd 100644 --- a/src/installer/test/Assets/TestProjects/StartupHookWithOverload/StartupHookWithOverload.csproj +++ b/src/installer/test/Assets/TestProjects/StartupHookWithOverload/StartupHookWithOverload.csproj @@ -1,7 +1,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/StartupHookWithParameter/StartupHookWithParameter.csproj b/src/installer/test/Assets/TestProjects/StartupHookWithParameter/StartupHookWithParameter.csproj index 07612ef9143b4a..637cbf46c656dd 100644 --- a/src/installer/test/Assets/TestProjects/StartupHookWithParameter/StartupHookWithParameter.csproj +++ b/src/installer/test/Assets/TestProjects/StartupHookWithParameter/StartupHookWithParameter.csproj @@ -1,7 +1,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/StartupHookWithReturnType/StartupHookWithReturnType.csproj b/src/installer/test/Assets/TestProjects/StartupHookWithReturnType/StartupHookWithReturnType.csproj index 07612ef9143b4a..637cbf46c656dd 100644 --- a/src/installer/test/Assets/TestProjects/StartupHookWithReturnType/StartupHookWithReturnType.csproj +++ b/src/installer/test/Assets/TestProjects/StartupHookWithReturnType/StartupHookWithReturnType.csproj @@ -1,7 +1,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/StartupHookWithoutInitializeMethod/StartupHookWithoutInitializeMethod.csproj b/src/installer/test/Assets/TestProjects/StartupHookWithoutInitializeMethod/StartupHookWithoutInitializeMethod.csproj index 07612ef9143b4a..637cbf46c656dd 100644 --- a/src/installer/test/Assets/TestProjects/StartupHookWithoutInitializeMethod/StartupHookWithoutInitializeMethod.csproj +++ b/src/installer/test/Assets/TestProjects/StartupHookWithoutInitializeMethod/StartupHookWithoutInitializeMethod.csproj @@ -1,7 +1,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/StartupHookWithoutStartupHookType/StartupHookWithoutStartupHookType.csproj b/src/installer/test/Assets/TestProjects/StartupHookWithoutStartupHookType/StartupHookWithoutStartupHookType.csproj index 07612ef9143b4a..637cbf46c656dd 100644 --- a/src/installer/test/Assets/TestProjects/StartupHookWithoutStartupHookType/StartupHookWithoutStartupHookType.csproj +++ b/src/installer/test/Assets/TestProjects/StartupHookWithoutStartupHookType/StartupHookWithoutStartupHookType.csproj @@ -1,7 +1,7 @@ - $(NETCoreAppFramework) + $(NetCoreAppCurrent) $(MNAVersion) diff --git a/src/installer/test/Assets/TestProjects/StaticHostApp/Program.cs b/src/installer/test/Assets/TestProjects/StaticHostApp/Program.cs new file mode 100644 index 00000000000000..c631d81d540483 --- /dev/null +++ b/src/installer/test/Assets/TestProjects/StaticHostApp/Program.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace StaticHostApp +{ + public static class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/src/installer/test/Assets/TestProjects/StaticHostApp/StaticHostApp.csproj b/src/installer/test/Assets/TestProjects/StaticHostApp/StaticHostApp.csproj new file mode 100644 index 00000000000000..eff31e8532b40b --- /dev/null +++ b/src/installer/test/Assets/TestProjects/StaticHostApp/StaticHostApp.csproj @@ -0,0 +1,13 @@ + + + + $(NETCoreAppFramework) + Exe + $(TestTargetRid) + $(MNAVersion) + + + + + + diff --git a/src/installer/test/Assets/TestProjects/TestWindowsOsShimsApp/Program.cs b/src/installer/test/Assets/TestProjects/TestWindowsOsShimsApp/Program.cs index 23ad2c2f5d143b..bc065abc49d76c 100644 --- a/src/installer/test/Assets/TestProjects/TestWindowsOsShimsApp/Program.cs +++ b/src/installer/test/Assets/TestProjects/TestWindowsOsShimsApp/Program.cs @@ -13,9 +13,9 @@ public static void Main(string[] args) { Console.WriteLine("Hello World!"); Console.WriteLine(string.Join(Environment.NewLine, args)); - Console.WriteLine($"Framework Version:{GetFrameworkVersionFromAppDomain()}"); + Console.WriteLine(RuntimeInformation.FrameworkDescription); - #if WINDOWS +#if WINDOWS Version osVersion = RtlGetVersion(); if (osVersion == null) { @@ -33,12 +33,7 @@ public static void Main(string[] args) Console.WriteLine($"Reported OS version is lower than the true OS version - shims in use."); } } - #endif - } - - private static string GetFrameworkVersionFromAppDomain() - { - return System.AppDomain.CurrentDomain.GetData("FX_PRODUCT_VERSION") as string; +#endif } #if WINDOWS diff --git a/src/installer/test/Assets/TestProjects/TestWindowsOsShimsApp/TestWindowsOsShimsApp.csproj b/src/installer/test/Assets/TestProjects/TestWindowsOsShimsApp/TestWindowsOsShimsApp.csproj index 70d4c67081bd95..adda104a389e23 100644 --- a/src/installer/test/Assets/TestProjects/TestWindowsOsShimsApp/TestWindowsOsShimsApp.csproj +++ b/src/installer/test/Assets/TestProjects/TestWindowsOsShimsApp/TestWindowsOsShimsApp.csproj @@ -1,7 +1,7 @@ - + - $(NETCoreAppFramework) + $(NetCoreAppCurrent) $(TestTargetRid) Exe $(MNAVersion) diff --git a/src/installer/test/Assets/TestUtils/TestProjects.props b/src/installer/test/Assets/TestUtils/TestProjects.props index 97993c19cf9774..46ff7500357656 100644 --- a/src/installer/test/Assets/TestUtils/TestProjects.props +++ b/src/installer/test/Assets/TestUtils/TestProjects.props @@ -6,7 +6,7 @@ in a different manner than using the $(RepositoryEngineeringDir) variable. --> - + diff --git a/src/installer/test/Assets/TestUtils/TestProjects.targets b/src/installer/test/Assets/TestUtils/TestProjects.targets index 1ee0e9450058d2..32180ba2f700dd 100644 --- a/src/installer/test/Assets/TestUtils/TestProjects.targets +++ b/src/installer/test/Assets/TestUtils/TestProjects.targets @@ -4,12 +4,4 @@ provides basic info needed for restore and build with the vanilla SDK. --> - - - $(MajorVersion).$(MinorVersion) - - diff --git a/src/installer/test/Directory.Build.props b/src/installer/test/Directory.Build.props index 8cb17e0b062bca..918a11e2e3f63d 100644 --- a/src/installer/test/Directory.Build.props +++ b/src/installer/test/Directory.Build.props @@ -10,16 +10,7 @@ $(ArtifactsObjDir)ExtraNupkgsForTestRestore\ $(TargetArchitecture) $(NetCoreAppCurrent) - - - - nonwindowstests - nonlinuxtests - nonosxtests - nonfreebsdtests - nonnetbsdtests - - -notrait category=$(TargetOSTrait) + -notrait category=failing diff --git a/src/installer/test/Directory.Build.targets b/src/installer/test/Directory.Build.targets index da534ca005565e..7d93a09399835d 100644 --- a/src/installer/test/Directory.Build.targets +++ b/src/installer/test/Directory.Build.targets @@ -81,7 +81,7 @@ - + @@ -121,12 +121,8 @@ - - - - - $(_HostRid) + $(HostRuntimeIdentifier) $(MSBuildProjectName) $(ArtifactsDir)tests/$(Configuration)/ diff --git a/src/installer/test/HostActivation.Tests/HostActivation.Tests.csproj b/src/installer/test/HostActivation.Tests/HostActivation.Tests.csproj index 18a00b7b2a14da..95b8cfd9a9f6e9 100644 --- a/src/installer/test/HostActivation.Tests/HostActivation.Tests.csproj +++ b/src/installer/test/HostActivation.Tests/HostActivation.Tests.csproj @@ -1,4 +1,4 @@ - + $(TestInfraTargetFramework) @@ -17,8 +17,7 @@ - - + diff --git a/src/installer/test/HostActivation.Tests/HostVersionCompatibility.cs b/src/installer/test/HostActivation.Tests/HostVersionCompatibility.cs index 67a4f70b9c9b73..afb0862fecde92 100644 --- a/src/installer/test/HostActivation.Tests/HostVersionCompatibility.cs +++ b/src/installer/test/HostActivation.Tests/HostVersionCompatibility.cs @@ -3,9 +3,9 @@ // See the LICENSE file in the project root for more information. using Microsoft.DotNet.Cli.Build.Framework; -using Microsoft.DotNet.PlatformAbstractions; using System; using System.IO; +using System.Runtime.InteropServices; using Xunit; namespace Microsoft.DotNet.CoreSetup.Test.HostActivation @@ -137,13 +137,11 @@ private void Old_Host_Is_Forward_Compatible_With_Latest_Runtime(TestProjectFixtu private static bool IsRidSupported() { - Platform platform = RuntimeEnvironment.OperatingSystemPlatform; - // Some current Linux RIDs are not supported in 2.0\2.1; just test for Ubuntu 16. return ( - platform == Platform.Windows || - platform == Platform.Darwin || - (platform == Platform.Linux && RuntimeEnvironment.GetRuntimeIdentifier() == "ubuntu.16.04-x64") + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || + RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || + (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && RuntimeInformation.RuntimeIdentifier == "ubuntu.16.04-x64") ); } diff --git a/src/installer/test/HostActivation.Tests/NativeHosting/ComponentActivation.cs b/src/installer/test/HostActivation.Tests/NativeHosting/ComponentActivation.cs index e123787a39e34e..3e9c6b529a09f8 100644 --- a/src/installer/test/HostActivation.Tests/NativeHosting/ComponentActivation.cs +++ b/src/installer/test/HostActivation.Tests/NativeHosting/ComponentActivation.cs @@ -57,9 +57,11 @@ public void CallDelegate(bool validPath, bool validType, bool validMethod) } [Theory] - [InlineData(1)] - [InlineData(10)] - public void CallDelegate_MultipleEntryPoints(int callCount) + [InlineData(1, false)] + [InlineData(1, true)] + [InlineData(10, false)] + [InlineData(10, true)] + public void CallDelegate_MultipleEntryPoints(int callCount, bool callUnmanaged) { var componentProject = sharedState.ComponentWithNoDependenciesFixture.TestProject; string[] baseArgs = @@ -68,12 +70,14 @@ public void CallDelegate_MultipleEntryPoints(int callCount) sharedState.HostFxrPath, componentProject.RuntimeConfigJson, }; + + string comp1Name = callUnmanaged ? sharedState.UnmanagedComponentEntryPoint1 : sharedState.ComponentEntryPoint1; string[] componentInfo = { - // ComponentEntryPoint1 + // [Unmanaged]ComponentEntryPoint1 componentProject.AppDll, sharedState.ComponentTypeName, - sharedState.ComponentEntryPoint1, + comp1Name, // ComponentEntryPoint2 componentProject.AppDll, sharedState.ComponentTypeName, @@ -95,7 +99,7 @@ public void CallDelegate_MultipleEntryPoints(int callCount) for (int i = 1; i <= callCount; ++i) { result.Should() - .ExecuteComponentEntryPoint(sharedState.ComponentEntryPoint1, i * 2 - 1, i) + .ExecuteComponentEntryPoint(comp1Name, i * 2 - 1, i) .And.ExecuteComponentEntryPoint(sharedState.ComponentEntryPoint2, i * 2, i); } } @@ -175,6 +179,7 @@ public class SharedTestState : SharedTestStateBase public string ComponentTypeName { get; } public string ComponentEntryPoint1 => "ComponentEntryPoint1"; public string ComponentEntryPoint2 => "ComponentEntryPoint2"; + public string UnmanagedComponentEntryPoint1 => "UnmanagedComponentEntryPoint1"; public SharedTestState() { diff --git a/src/installer/test/HostActivation.Tests/PortableAppActivation.cs b/src/installer/test/HostActivation.Tests/PortableAppActivation.cs index 8ec51eb6e268a4..0835af7398e859 100644 --- a/src/installer/test/HostActivation.Tests/PortableAppActivation.cs +++ b/src/installer/test/HostActivation.Tests/PortableAppActivation.cs @@ -263,7 +263,7 @@ public void AppHost_FrameworkDependent_Succeeds() .Execute() .Should().Pass() .And.HaveStdOutContaining("Hello World") - .And.HaveStdOutContaining($"Framework Version:{sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"); + .And.HaveStdOutContaining(sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion); // Verify running from within the working directory @@ -276,7 +276,7 @@ public void AppHost_FrameworkDependent_Succeeds() .Execute() .Should().Pass() .And.HaveStdOutContaining("Hello World") - .And.HaveStdOutContaining($"Framework Version:{sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"); + .And.HaveStdOutContaining(sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion); } [Theory] @@ -315,7 +315,7 @@ public void AppHost_FrameworkDependent_GlobalLocation_Succeeds(bool useRegistere .Execute() .Should().Pass() .And.HaveStdOutContaining("Hello World") - .And.HaveStdOutContaining($"Framework Version:{sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"); + .And.HaveStdOutContaining(sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion); // Verify running from within the working directory Command.Create(appExe) @@ -329,7 +329,7 @@ public void AppHost_FrameworkDependent_GlobalLocation_Succeeds(bool useRegistere .Execute() .Should().Pass() .And.HaveStdOutContaining("Hello World") - .And.HaveStdOutContaining($"Framework Version:{sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"); + .And.HaveStdOutContaining(sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion); } } diff --git a/src/installer/test/HostActivation.Tests/RuntimeProperties.cs b/src/installer/test/HostActivation.Tests/RuntimeProperties.cs index 6010aa24c78799..fd9edf7106192a 100644 --- a/src/installer/test/HostActivation.Tests/RuntimeProperties.cs +++ b/src/installer/test/HostActivation.Tests/RuntimeProperties.cs @@ -17,27 +17,6 @@ public RuntimeProperties(RuntimeProperties.SharedTestState fixture) sharedState = fixture; } - [Fact] - public void CommonProperty_AppCanGetData() - { - var fixture = sharedState.RuntimePropertiesFixture - .Copy(); - - string name = "FX_PRODUCT_VERSION"; - string value = fixture.RepoDirProvider.MicrosoftNETCoreAppVersion; - - var dotnet = fixture.BuiltDotnet; - var appDll = fixture.TestProject.AppDll; - dotnet.Exec(appDll, name) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdErr() - .CaptureStdOut() - .Execute() - .Should().Pass() - .And.HaveStdErrContaining($"Property {name} = {value}") - .And.HaveStdOutContaining($"AppContext.GetData({name}) = {value}"); - } - [Fact] public void AppConfigProperty_AppCanGetData() { @@ -102,7 +81,7 @@ public void DuplicateCommonProperty_Fails() var fixture = sharedState.RuntimePropertiesFixture .Copy(); - string name = "FX_PRODUCT_VERSION"; + string name = "RUNTIME_IDENTIFIER"; RuntimeConfig.FromFile(fixture.TestProject.RuntimeConfigJson) .WithProperty(name, sharedState.AppTestPropertyValue) .Save(); diff --git a/src/installer/test/HostActivation.Tests/SharedFxLookup.cs b/src/installer/test/HostActivation.Tests/SharedFxLookup.cs index e7cd16d860cedd..0139077f16bf9a 100644 --- a/src/installer/test/HostActivation.Tests/SharedFxLookup.cs +++ b/src/installer/test/HostActivation.Tests/SharedFxLookup.cs @@ -189,13 +189,6 @@ public void CoreClrLookup_WithNoDirectorySeparatorInDeps() coreClrProperty.Parent.Add(newCoreClrProperty); coreClrProperty.Remove(); - // Change the clrjit.dll asset to specify only "clrjit.dll" as the relative path (no directories). - string clrJitLibraryName = RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("clrjit"); - JProperty clrJitProperty = netCoreAppNativeAssets.First(p => p.Name.Contains(clrJitLibraryName)); - JProperty newClrJitProperty = new JProperty(clrJitProperty.Name.Substring(clrJitProperty.Name.LastIndexOf('/') + 1), clrJitProperty.Value); - clrJitProperty.Parent.Add(newClrJitProperty); - clrJitProperty.Remove(); - File.WriteAllText(sharedFxDepsJsonPath, root.ToString()); dotnet.Exec(appDll) @@ -205,8 +198,7 @@ public void CoreClrLookup_WithNoDirectorySeparatorInDeps() .CaptureStdErr() .Execute() .Should().Pass() - .And.HaveStdErrContaining($"CoreCLR path = '{Path.Combine(sharedFxPath, coreClrLibraryName)}'") - .And.HaveStdErrContaining($"The resolved JIT path is '{Path.Combine(sharedFxPath, clrJitLibraryName)}'"); + .And.HaveStdErrContaining($"CoreCLR path = '{Path.Combine(sharedFxPath, coreClrLibraryName)}'"); } } } diff --git a/src/installer/test/HostActivation.Tests/StandaloneAppActivation.cs b/src/installer/test/HostActivation.Tests/StandaloneAppActivation.cs index 6ab2ccae681ec6..dac93e29407bd6 100644 --- a/src/installer/test/HostActivation.Tests/StandaloneAppActivation.cs +++ b/src/installer/test/HostActivation.Tests/StandaloneAppActivation.cs @@ -42,7 +42,7 @@ public void Running_Build_Output_Standalone_EXE_with_DepsJson_and_RuntimeConfig_ .Execute() .Should().Pass() .And.HaveStdOutContaining("Hello World") - .And.HaveStdOutContaining($"Framework Version:{sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"); + .And.HaveStdOutContaining(sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion); } [Fact] @@ -59,7 +59,7 @@ public void Running_Publish_Output_Standalone_EXE_with_DepsJson_and_RuntimeConfi .Execute() .Should().Pass() .And.HaveStdOutContaining("Hello World") - .And.HaveStdOutContaining($"Framework Version:{sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"); + .And.HaveStdOutContaining(sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion); } [Fact] @@ -136,7 +136,7 @@ public void Running_Publish_Output_Standalone_EXE_By_Renaming_apphost_exe_Succee .Execute() .Should().Pass() .And.HaveStdOutContaining("Hello World") - .And.HaveStdOutContaining($"Framework Version:{sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"); + .And.HaveStdOutContaining(sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion); } [Fact] @@ -172,7 +172,7 @@ public void Running_Publish_Output_Standalone_EXE_With_Relative_Embedded_Path_Su .Execute() .Should().Pass() .And.HaveStdOutContaining("Hello World") - .And.HaveStdOutContaining($"Framework Version:{sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"); + .And.HaveStdOutContaining(sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion); } [Fact] @@ -234,7 +234,7 @@ public void Running_Publish_Output_Standalone_EXE_with_Bound_AppHost_Succeeds() .Execute() .Should().Pass() .And.HaveStdOutContaining("Hello World") - .And.HaveStdOutContaining($"Framework Version:{sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion}"); + .And.HaveStdOutContaining(sharedTestState.RepoDirectories.MicrosoftNETCoreAppVersion); } [Fact] diff --git a/src/installer/test/Microsoft.DotNet.CoreSetup.Packaging.Tests/Microsoft.DotNet.CoreSetup.Packaging.Tests.csproj b/src/installer/test/Microsoft.DotNet.CoreSetup.Packaging.Tests/Microsoft.DotNet.CoreSetup.Packaging.Tests.csproj index 65489936f215a1..8dcef20c22dea9 100644 --- a/src/installer/test/Microsoft.DotNet.CoreSetup.Packaging.Tests/Microsoft.DotNet.CoreSetup.Packaging.Tests.csproj +++ b/src/installer/test/Microsoft.DotNet.CoreSetup.Packaging.Tests/Microsoft.DotNet.CoreSetup.Packaging.Tests.csproj @@ -1,4 +1,4 @@ - + $(TestInfraTargetFramework) diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/AppHost.Bundle.Tests.csproj b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/AppHost.Bundle.Tests.csproj index 857636af41f743..4a0f0cf96a4a5f 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/AppHost.Bundle.Tests.csproj +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/AppHost.Bundle.Tests.csproj @@ -1,4 +1,4 @@ - + Apphost Bundle Tests diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs index 26dbc3a00ef832..8f9e97415285bb 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs @@ -30,7 +30,7 @@ private void Bundle_Extraction_To_Specific_Path_Succeeds() // Publish the bundle string singleFile; - Bundler bundler = BundleHelper.BundleApp(fixture, out singleFile); + Bundler bundler = BundleHelper.BundleApp(fixture, out singleFile, options: BundleOptions.BundleNativeBinaries); // Verify expected files in the bundle directory var bundleDir = BundleHelper.GetBundleDir(fixture); @@ -157,7 +157,6 @@ private void Bundle_extraction_can_recover_missing_files() extractDir.Should().HaveFiles(extractedFiles); } - public class SharedTestState : IDisposable { public TestProjectFixture TestFixture { get; set; } diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleLocalizedApp.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleLocalizedApp.cs new file mode 100644 index 00000000000000..cadcbf8032b0ee --- /dev/null +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleLocalizedApp.cs @@ -0,0 +1,68 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using BundleTests.Helpers; +using Microsoft.DotNet.Cli.Build.Framework; +using Microsoft.NET.HostModel.Bundle; +using Microsoft.DotNet.CoreSetup.Test; +using System; +using System.Runtime.InteropServices; +using Xunit; + +namespace AppHost.Bundle.Tests +{ + public class BundleLocalizedApp : IClassFixture + { + private SharedTestState sharedTestState; + + public BundleLocalizedApp(SharedTestState fixture) + { + sharedTestState = fixture; + } + + [Fact] + public void Bundled_Localized_App_Run_Succeeds() + { + var fixture = sharedTestState.TestFixture.Copy(); + var singleFile = BundleHelper.BundleApp(fixture); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Set code page to output unicode characters. + Command.Create("chcp 65001").Execute(); + } + + Command.Create(singleFile) + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("ನಮಸ್ಕಾರ! வணக்கம்! Hello!"); + } + + public class SharedTestState : IDisposable + { + public TestProjectFixture TestFixture { get; set; } + public RepoDirectoriesProvider RepoDirectories { get; set; } + + public SharedTestState() + { + RepoDirectories = new RepoDirectoriesProvider(); + + TestFixture = new TestProjectFixture("LocalizedApp", RepoDirectories); + TestFixture + .EnsureRestoredForRid(TestFixture.CurrentRid, RepoDirectories.CorehostPackages) + .PublishProject(runtime: TestFixture.CurrentRid, + outputDirectory: BundleHelper.GetPublishPath(TestFixture)); + } + + public void Dispose() + { + TestFixture.Dispose(); + } + } + } +} diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleProbe.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleProbe.cs new file mode 100644 index 00000000000000..b178e0ee36e6d0 --- /dev/null +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleProbe.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using Xunit; +using Microsoft.DotNet.Cli.Build.Framework; +using Microsoft.DotNet.CoreSetup.Test; +using BundleTests.Helpers; +using System.Threading; + +namespace AppHost.Bundle.Tests +{ + public class BundleProbe : IClassFixture + { + private SharedTestState sharedTestState; + + public BundleProbe(SharedTestState fixture) + { + sharedTestState = fixture; + } + + [Fact] + private void Bundle_Probe_Not_Passed_For_Non_Single_File_App() + { + var fixture = sharedTestState.TestFixture.Copy(); + string appExe = BundleHelper.GetHostPath(fixture); + + Command.Create(appExe) + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("No BUNDLE_PROBE"); + } + + [Fact] + private void Bundle_Probe_Passed_For_Single_File_App() + { + var fixture = sharedTestState.TestFixture.Copy(); + string singleFile = BundleHelper.BundleApp(fixture); + + Command.Create(singleFile, "SingleFile") + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("BUNDLE_PROBE OK"); + } + + public class SharedTestState : IDisposable + { + public TestProjectFixture TestFixture { get; set; } + public RepoDirectoriesProvider RepoDirectories { get; set; } + + public SharedTestState() + { + RepoDirectories = new RepoDirectoriesProvider(); + TestFixture = new TestProjectFixture("BundleProbeTester", RepoDirectories); + TestFixture + .EnsureRestoredForRid(TestFixture.CurrentRid, RepoDirectories.CorehostPackages) + .PublishProject(runtime: TestFixture.CurrentRid, + outputDirectory: BundleHelper.GetPublishPath(TestFixture)); + } + + public void Dispose() + { + TestFixture.Dispose(); + } + } + } +} diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleRename.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleRename.cs index 581a1155c98f98..8decb641466908 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleRename.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleRename.cs @@ -7,6 +7,7 @@ using Xunit; using Microsoft.DotNet.Cli.Build.Framework; using Microsoft.DotNet.CoreSetup.Test; +using Microsoft.NET.HostModel.Bundle; using BundleTests.Helpers; using System.Threading; @@ -22,38 +23,30 @@ public BundleRename(SharedTestState fixture) } [Theory] - [InlineData(true)] // Test renaming the single-exe during the initial run, when contents are extracted - [InlineData(false)] // Test renaming the single-exe during subsequent runs, when contents are reused - private void Bundle_can_be_renamed_while_running(bool renameFirstRun) + [InlineData(true)] // Test renaming the single-exe when contents are extracted + [InlineData(false)] // Test renaming the single-exe when contents are not extracted + private void Bundle_can_be_renamed_while_running(bool testExtraction) { var fixture = sharedTestState.TestFixture.Copy(); - string singleFile = BundleHelper.BundleApp(fixture); + BundleOptions options = testExtraction ? BundleOptions.BundleAllContent : BundleOptions.None; + string singleFile = BundleHelper.BundleApp(fixture, options); string outputDir = Path.GetDirectoryName(singleFile); string renameFile = Path.Combine(outputDir, Path.GetRandomFileName()); string waitFile = Path.Combine(outputDir, "wait"); string resumeFile = Path.Combine(outputDir, "resume"); - if (!renameFirstRun) - { - Command.Create(singleFile) - .CaptureStdErr() - .CaptureStdOut() - .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Hello World!"); - } - // Once the App starts running, it creates the waitFile, and waits until resumeFile file is created. var singleExe = Command.Create(singleFile, waitFile, resumeFile) .CaptureStdErr() .CaptureStdOut() .Start(); - while (!File.Exists(waitFile) && !singleExe.Process.HasExited) + const int twoMitutes = 120000 /*milliseconds*/; + int waitTime = 0; + while (!File.Exists(waitFile) && !singleExe.Process.HasExited && waitTime < twoMitutes) { Thread.Sleep(100); + waitTime += 100; } Assert.True(File.Exists(waitFile)); @@ -61,7 +54,7 @@ private void Bundle_can_be_renamed_while_running(bool renameFirstRun) File.Move(singleFile, renameFile); File.Create(resumeFile).Close(); - var result = singleExe.WaitForExit(fExpectedToFail: false); + var result = singleExe.WaitForExit(fExpectedToFail: false, twoMitutes); result .Should() diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs index 33e05b5c0504dc..ff15ee6fb80f1e 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundledAppWithSubDirs.cs @@ -32,9 +32,7 @@ private void RunTheApp(string path) .HaveStdOutContaining("Wow! We now say hello to the big world and you."); } - // BundleOptions.BundleNativeBinaries: Test when the payload data files are unbundled, and beside the single-file app. - // BundleOptions.BundleAllContent: Test when the payload data files are bundled and extracted to temporary directory. - // Once the runtime can load assemblies from the bundle, BundleOptions.None can be used in place of BundleOptions.BundleNativeBinaries. + [InlineData(BundleOptions.None)] [InlineData(BundleOptions.BundleNativeBinaries)] [InlineData(BundleOptions.BundleAllContent)] [Theory] @@ -50,6 +48,7 @@ public void Bundled_Framework_dependent_App_Run_Succeeds(BundleOptions options) RunTheApp(singleFile); } + [InlineData(BundleOptions.None)] [InlineData(BundleOptions.BundleNativeBinaries)] [InlineData(BundleOptions.BundleAllContent)] [Theory] @@ -65,6 +64,7 @@ public void Bundled_Self_Contained_App_Run_Succeeds(BundleOptions options) RunTheApp(singleFile); } + [InlineData(BundleOptions.None)] [InlineData(BundleOptions.BundleNativeBinaries)] [InlineData(BundleOptions.BundleAllContent)] [Theory] diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/StaticHost.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/StaticHost.cs new file mode 100644 index 00000000000000..78b5c9449fe1b3 --- /dev/null +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/StaticHost.cs @@ -0,0 +1,98 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using BundleTests.Helpers; +using Microsoft.DotNet.Cli.Build.Framework; +using Microsoft.DotNet.CoreSetup.Test; +using Microsoft.NET.HostModel.AppHost; +using Microsoft.NET.HostModel.Bundle; +using System; +using System.IO; +using System.Threading; +using Xunit; + +namespace AppHost.Bundle.Tests +{ + public class StaticHost : IClassFixture + { + private SharedTestState sharedTestState; + + public StaticHost(SharedTestState fixture) + { + sharedTestState = fixture; + } + + // This helper is used in lieu of SDK support for publishing apps using the singlefilehost. + // It replaces the apphost with singlefilehost, and along with appropriate app.dll updates in the host. + // For now, we leave behind the hostpolicy and hostfxr DLLs in the publish directory, because + // removing them requires deps.json update. + void ReplaceApphostWithStaticHost(TestProjectFixture fixture) + { + var staticHost = Path.Combine(fixture.RepoDirProvider.HostArtifacts, + RuntimeInformationExtensions.GetExeFileNameForCurrentPlatform("singlefilehost")); + HostWriter.CreateAppHost(staticHost, + BundleHelper.GetHostPath(fixture), + BundleHelper.GetAppPath(fixture)); + + } + + [Fact] + private void Can_Run_App_With_StatiHost() + { + var fixture = sharedTestState.TestFixture.Copy(); + var appExe = BundleHelper.GetHostPath(fixture); + + ReplaceApphostWithStaticHost(fixture); + + Command.Create(appExe) + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("Hello World"); + } + + [Fact] + private void Can_Run_SingleFile_App_With_StatiHost() + { + var fixture = sharedTestState.TestFixture.Copy(); + + ReplaceApphostWithStaticHost(fixture); + + string singleFile = BundleHelper.BundleApp(fixture); + + Command.Create(singleFile) + .CaptureStdErr() + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("Hello World"); + } + + public class SharedTestState : IDisposable + { + public TestProjectFixture TestFixture { get; set; } + public RepoDirectoriesProvider RepoDirectories { get; set; } + + public SharedTestState() + { + RepoDirectories = new RepoDirectoriesProvider(); + TestFixture = new TestProjectFixture("StaticHostApp", RepoDirectories); + TestFixture + .EnsureRestoredForRid(TestFixture.CurrentRid, RepoDirectories.CorehostPackages) + .PublishProject(runtime: TestFixture.CurrentRid, + outputDirectory: BundleHelper.GetPublishPath(TestFixture)); + } + + public void Dispose() + { + TestFixture.Dispose(); + } + } + } +} diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs index c5f77179436768..def3a469563991 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs @@ -53,8 +53,7 @@ public static string[] GetBundledFiles(TestProjectFixture fixture) public static string[] GetExtractedFiles(TestProjectFixture fixture) { - string appBaseName = GetAppBaseName(fixture); - return new string[] { $"{appBaseName}.dll" }; + return new string[] { Path.GetFileName(fixture.TestProject.CoreClrDll) }; } public static string[] GetFilesNeverExtracted(TestProjectFixture fixture) @@ -62,6 +61,7 @@ public static string[] GetFilesNeverExtracted(TestProjectFixture fixture) string appBaseName = GetAppBaseName(fixture); return new string[] { $"{appBaseName}.deps.json", $"{appBaseName}.runtimeconfig.json", + $"{appBaseName}.dll", Path.GetFileName(fixture.TestProject.HostFxrDll), Path.GetFileName(fixture.TestProject.HostPolicyDll) }; } @@ -139,7 +139,7 @@ public static string GenerateBundle(Bundler bundler, string sourceDir, string ou // which may not (yet) be available in the SDK. public static Bundler BundleApp(TestProjectFixture fixture, out string singleFile, - BundleOptions options = BundleOptions.BundleNativeBinaries, + BundleOptions options = BundleOptions.None, Version targetFrameworkVersion = null, bool copyExcludedFiles = true) { @@ -153,11 +153,8 @@ public static Bundler BundleApp(TestProjectFixture fixture, return bundler; } - // The defaut option for Bundling apps is BundleOptions.BundleNativeBinaries - // Until CoreCLR runtime can learn how to process assemblies from the bundle. - // This is because CoreCLR expects System.Private.Corelib.dll to be beside CoreCLR.dll public static string BundleApp(TestProjectFixture fixture, - BundleOptions options = BundleOptions.BundleNativeBinaries, + BundleOptions options = BundleOptions.None, Version targetFrameworkVersion = null) { string singleFile; diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/Microsoft.NET.HostModel.AppHost.Tests.csproj b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/Microsoft.NET.HostModel.AppHost.Tests.csproj index 1723c7ad9121d6..012d7ce6261d21 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/Microsoft.NET.HostModel.AppHost.Tests.csproj +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/Microsoft.NET.HostModel.AppHost.Tests.csproj @@ -1,4 +1,4 @@ - + Microsoft.NET.HostModel.AppHost Tests diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleAndRun.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleAndRun.cs index e4949b47750daf..bf9ff14cf5b0f8 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleAndRun.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleAndRun.cs @@ -32,7 +32,7 @@ private void RunTheApp(string path) .HaveStdOutContaining("Wow! We now say hello to the big world and you."); } - private void BundleRun(TestProjectFixture fixture, string publishPath, string singleFileDir) + private void BundleRun(TestProjectFixture fixture, string publishPath) { var hostName = BundleHelper.GetHostName(fixture); @@ -56,33 +56,24 @@ private string RelativePath(string path) public void TestWithAbsolutePaths() { var fixture = sharedTestState.TestFixture.Copy(); - string publishDir = BundleHelper.GetPublishPath(fixture); - string outputDir = BundleHelper.GetBundleDir(fixture).FullName; - - BundleRun(fixture, publishDir, outputDir); + BundleRun(fixture, publishDir); } [Fact] public void TestWithRelativePaths() { var fixture = sharedTestState.TestFixture.Copy(); - string publishDir = RelativePath(BundleHelper.GetPublishPath(fixture)); - string outputDir = RelativePath(BundleHelper.GetBundleDir(fixture).FullName); - - BundleRun(fixture, publishDir, outputDir); + BundleRun(fixture, publishDir); } [Fact] public void TestWithRelativePathsDirSeparator() { var fixture = sharedTestState.TestFixture.Copy(); - string publishDir = RelativePath(BundleHelper.GetPublishPath(fixture)) + Path.DirectorySeparatorChar; - string outputDir = RelativePath(BundleHelper.GetBundleDir(fixture).FullName) + Path.DirectorySeparatorChar; - - BundleRun(fixture, publishDir, outputDir); + BundleRun(fixture, publishDir); } public class SharedTestState : IDisposable diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleLegacy.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleLegacy.cs index 7b9d6863607d20..1690be766e33aa 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleLegacy.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleLegacy.cs @@ -27,8 +27,7 @@ public void TestNetCoreApp3xApp(int minorVersion) { var fixture = (minorVersion == 0) ? sharedTestState.TestFixture30.Copy() : sharedTestState.TestFixture31.Copy(); - // Targetting netcoreap3.x implies BundleOption.BundleAllContent - var singleFile = BundleHelper.BundleApp(fixture, BundleOptions.None, new Version(3, minorVersion)); + var singleFile = BundleHelper.BundleApp(fixture, targetFrameworkVersion: new Version(3, minorVersion)); Command.Create(singleFile) .CaptureStdErr() @@ -50,7 +49,6 @@ private static TestProjectFixture CreatePublishedFixture(string netCoreAppFramew return fixture; } - public class SharedTestState : IDisposable { public TestProjectFixture TestFixture30 { get; set; } diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundlerConsistencyTests.cs b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundlerConsistencyTests.cs index 2e0bda9e45ed32..00f3b1cc843c26 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundlerConsistencyTests.cs +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundlerConsistencyTests.cs @@ -143,6 +143,17 @@ public void TestBundlingNativeBinaries(BundleOptions options) bundler.BundleManifest.Contains($"{coreclr}").Should().Be(options.HasFlag(BundleOptions.BundleNativeBinaries)); } + [Fact] + public void TestFileSizes() + { + var fixture = sharedTestState.TestFixture.Copy(); + var bundler = BundleHelper.Bundle(fixture); + var publishPath = BundleHelper.GetPublishPath(fixture); + + bundler.BundleManifest.Files.ForEach(file => + Assert.True(file.Size == new FileInfo(Path.Combine(publishPath, file.RelativePath)).Length)); + } + [Fact] public void TestAssemblyAlignment() { diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/Microsoft.NET.HostModel.Bundle.Tests.csproj b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/Microsoft.NET.HostModel.Bundle.Tests.csproj index 7faea066a7bace..7525988e5a356e 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/Microsoft.NET.HostModel.Bundle.Tests.csproj +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/Microsoft.NET.HostModel.Bundle.Tests.csproj @@ -1,4 +1,4 @@ - + Microsoft.NET.HostModel.Bundle Tests diff --git a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.ComHost.Tests/Microsoft.NET.HostModel.ComHost.Tests.csproj b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.ComHost.Tests/Microsoft.NET.HostModel.ComHost.Tests.csproj index 7a9016649da998..4f8d6cb298aff2 100644 --- a/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.ComHost.Tests/Microsoft.NET.HostModel.ComHost.Tests.csproj +++ b/src/installer/test/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.ComHost.Tests/Microsoft.NET.HostModel.ComHost.Tests.csproj @@ -1,4 +1,4 @@ - + Microsoft.NET.HostModel.ComHost Tests diff --git a/src/installer/test/TestUtils/TestProjectFixture.cs b/src/installer/test/TestUtils/TestProjectFixture.cs index b1a67453d716d7..5ab37de8f80ffd 100644 --- a/src/installer/test/TestUtils/TestProjectFixture.cs +++ b/src/installer/test/TestUtils/TestProjectFixture.cs @@ -233,7 +233,7 @@ public TestProjectFixture StoreProject( } storeArgs.Add($"/p:MNAVersion={RepoDirProvider.MicrosoftNETCoreAppVersion}"); - storeArgs.Add($"/p:NETCoreAppFramework={Framework}"); + storeArgs.Add($"/p:NetCoreAppCurrent={Framework}"); // Ensure the project's OutputType isn't 'Exe', since that causes issues with 'dotnet store' storeArgs.Add("/p:OutputType=Library"); @@ -286,7 +286,7 @@ public TestProjectFixture PublishProject( { publishArgs.Add("--framework"); publishArgs.Add(framework); - publishArgs.Add($"/p:NETCoreAppFramework={framework}"); + publishArgs.Add($"/p:NetCoreAppCurrent={framework}"); } if (selfContained != null) @@ -333,7 +333,7 @@ public TestProjectFixture RestoreProject(string[] fallbackSources, string extraM restoreArgs.Add("--disable-parallel"); restoreArgs.Add($"/p:MNAVersion={RepoDirProvider.MicrosoftNETCoreAppVersion}"); - restoreArgs.Add($"/p:NETCoreAppFramework={Framework}"); + restoreArgs.Add($"/p:NetCoreAppCurrent={Framework}"); if (extraMSBuildProperties != null) { diff --git a/src/installer/test/TestUtils/TestUtils.csproj b/src/installer/test/TestUtils/TestUtils.csproj index cf327e216df3dd..35cb3e19e9d77a 100644 --- a/src/installer/test/TestUtils/TestUtils.csproj +++ b/src/installer/test/TestUtils/TestUtils.csproj @@ -1,4 +1,4 @@ - + $(TestInfraTargetFramework) @@ -13,7 +13,6 @@ - diff --git a/src/libraries/Common/src/Extensions/BenchmarkRunner/DefaultCoreConfig.cs b/src/libraries/Common/src/Extensions/BenchmarkRunner/DefaultCoreConfig.cs index 7cad2fd106fe55..3504acbc2d70eb 100644 --- a/src/libraries/Common/src/Extensions/BenchmarkRunner/DefaultCoreConfig.cs +++ b/src/libraries/Common/src/Extensions/BenchmarkRunner/DefaultCoreConfig.cs @@ -36,7 +36,7 @@ public DefaultCoreConfig() #elif NETCOREAPP3_1 .With(CsProjCoreToolchain.From(new NetCoreAppSettings("netcoreapp3.1", null, ".NET Core 3.1"))) #elif NETCOREAPP5_0 - .With(CsProjCoreToolchain.From(new NetCoreAppSettings("netcoreapp5.0", null, ".NET Core 5.0"))) + .With(CsProjCoreToolchain.From(new NetCoreAppSettings("net5.0", null, ".NET 5.0"))) #else #error Target frameworks need to be updated. #endif diff --git a/src/libraries/Common/src/Interop/Android/Interop.Libraries.cs b/src/libraries/Common/src/Interop/Android/Interop.Libraries.cs new file mode 100644 index 00000000000000..c17d473ec503d7 --- /dev/null +++ b/src/libraries/Common/src/Interop/Android/Interop.Libraries.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +internal static partial class Interop +{ + internal static partial class Libraries + { + internal const string Liblog = "liblog"; + } +} diff --git a/src/libraries/Common/src/Interop/Android/Interop.Logcat.cs b/src/libraries/Common/src/Interop/Android/Interop.Logcat.cs new file mode 100644 index 00000000000000..1942beebca6d93 --- /dev/null +++ b/src/libraries/Common/src/Interop/Android/Interop.Logcat.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Logcat + { + [DllImport(Libraries.Liblog)] + private static extern void __android_log_print(LogLevel level, string? tag, string format, string args, IntPtr ptr); + + internal static void AndroidLogPrint(LogLevel level, string? tag, string message) => + __android_log_print(level, tag, "%s", message, IntPtr.Zero); + + internal enum LogLevel + { + Unknown = 0x00, + Default = 0x01, + Verbose = 0x02, + Debug = 0x03, + Info = 0x04, + Warn = 0x05, + Error = 0x06, + Fatal = 0x07, + Silent = 0x08 + } + } +} diff --git a/src/libraries/Common/src/Interop/FreeBSD/Interop.Libraries.cs b/src/libraries/Common/src/Interop/FreeBSD/Interop.Libraries.cs index 1cec655872f74b..25f0ce0a445e92 100644 --- a/src/libraries/Common/src/Interop/FreeBSD/Interop.Libraries.cs +++ b/src/libraries/Common/src/Interop/FreeBSD/Interop.Libraries.cs @@ -7,5 +7,6 @@ internal static partial class Interop internal static partial class Libraries { internal const string Odbc32 = "libodbc.so.2"; + internal const string MsQuic = "msquic"; } } diff --git a/src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs b/src/libraries/Common/src/Interop/Interop.Calendar.cs similarity index 100% rename from src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs rename to src/libraries/Common/src/Interop/Interop.Calendar.cs diff --git a/src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Casing.cs b/src/libraries/Common/src/Interop/Interop.Casing.cs similarity index 100% rename from src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Casing.cs rename to src/libraries/Common/src/Interop/Interop.Casing.cs diff --git a/src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Collation.cs b/src/libraries/Common/src/Interop/Interop.Collation.cs similarity index 98% rename from src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Collation.cs rename to src/libraries/Common/src/Interop/Interop.Collation.cs index a59292e0fca1df..07cf42b5ad7564 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Collation.cs +++ b/src/libraries/Common/src/Interop/Interop.Collation.cs @@ -23,10 +23,11 @@ internal static partial class Globalization internal static extern unsafe int IndexOf(IntPtr sortHandle, char* target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options, int* matchLengthPtr); [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_LastIndexOf")] - internal static extern unsafe int LastIndexOf(IntPtr sortHandle, char* target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options); + internal static extern unsafe int LastIndexOf(IntPtr sortHandle, char* target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options, int* matchLengthPtr); [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOfOrdinalIgnoreCase")] internal static extern unsafe int IndexOfOrdinalIgnoreCase(string target, int cwTargetLength, char* pSource, int cwSourceLength, bool findLast); + [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOfOrdinalIgnoreCase")] internal static extern unsafe int IndexOfOrdinalIgnoreCase(char* target, int cwTargetLength, char* pSource, int cwSourceLength, bool findLast); diff --git a/src/libraries/Common/src/Interop/Interop.ICU.cs b/src/libraries/Common/src/Interop/Interop.ICU.cs new file mode 100644 index 00000000000000..fb8b56e41d35f2 --- /dev/null +++ b/src/libraries/Common/src/Interop/Interop.ICU.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Globalization + { + [DllImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_LoadICU")] + internal static extern int LoadICU(); + + internal static void InitICUFunctions(IntPtr icuuc, IntPtr icuin, ReadOnlySpan version, ReadOnlySpan suffix) + { + Debug.Assert(icuuc != IntPtr.Zero); + Debug.Assert(icuin != IntPtr.Zero); + + InitICUFunctions(icuuc, icuin, version.ToString(), suffix.Length > 0 ? suffix.ToString() : null); + } + + [DllImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_InitICUFunctions")] + internal static extern void InitICUFunctions(IntPtr icuuc, IntPtr icuin, string version, string? suffix); + + [DllImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetICUVersion")] + internal static extern int GetICUVersion(); + } +} diff --git a/src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Idna.cs b/src/libraries/Common/src/Interop/Interop.Idna.cs similarity index 100% rename from src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Idna.cs rename to src/libraries/Common/src/Interop/Interop.Idna.cs diff --git a/src/libraries/Common/src/Interop/Interop.Ldap.cs b/src/libraries/Common/src/Interop/Interop.Ldap.cs new file mode 100644 index 00000000000000..1c312dca820e02 --- /dev/null +++ b/src/libraries/Common/src/Interop/Interop.Ldap.cs @@ -0,0 +1,181 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + public const int SEC_WINNT_AUTH_IDENTITY_UNICODE = 0x2; + public const int SEC_WINNT_AUTH_IDENTITY_VERSION = 0x200; + public const string MICROSOFT_KERBEROS_NAME_W = "Kerberos"; + public const uint LDAP_SASL_QUIET = 2; + public const string KerberosDefaultMechanism = "GSSAPI"; +} + +namespace System.DirectoryServices.Protocols +{ + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal class Luid + { + private readonly int _lowPart; + private readonly int _highPart; + + public int LowPart => _lowPart; + public int HighPart => _highPart; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal sealed class SEC_WINNT_AUTH_IDENTITY_EX + { + public int version; + public int length; + public string user; + public int userLength; + public string domain; + public int domainLength; + public string password; + public int passwordLength; + public int flags; + public string packageList; + public int packageListLength; + } + + internal enum BindMethod : uint // Not Supported in Linux + { + LDAP_AUTH_OTHERKIND = 0x86, + LDAP_AUTH_SICILY = LDAP_AUTH_OTHERKIND | 0x0200, + LDAP_AUTH_MSN = LDAP_AUTH_OTHERKIND | 0x0800, + LDAP_AUTH_NTLM = LDAP_AUTH_OTHERKIND | 0x1000, + LDAP_AUTH_DPA = LDAP_AUTH_OTHERKIND | 0x2000, + LDAP_AUTH_NEGOTIATE = LDAP_AUTH_OTHERKIND | 0x0400, + LDAP_AUTH_SSPI = LDAP_AUTH_NEGOTIATE, + LDAP_AUTH_DIGEST = LDAP_AUTH_OTHERKIND | 0x4000, + LDAP_AUTH_EXTERNAL = LDAP_AUTH_OTHERKIND | 0x0020, + LDAP_AUTH_KRBV4 = 0xFF, + LDAP_AUTH_SIMPLE = 0x80 + } + + internal enum LdapOption + { + LDAP_OPT_DESC = 0x01, + LDAP_OPT_DEREF = 0x02, + LDAP_OPT_SIZELIMIT = 0x03, + LDAP_OPT_TIMELIMIT = 0x04, + LDAP_OPT_REFERRALS = 0x08, + LDAP_OPT_RESTART = 0x09, + LDAP_OPT_SSL = 0x0a, // Not Supported in Linux + LDAP_OPT_REFERRAL_HOP_LIMIT = 0x10, // Not Supported in Linux + LDAP_OPT_VERSION = 0x11, + LDAP_OPT_SERVER_CONTROLS = 0x12, // Not Supported in Windows + LDAP_OPT_CLIENT_CONTROLS = 0x13, // Not Supported in Windows + LDAP_OPT_API_FEATURE_INFO = 0x15, + LDAP_OPT_HOST_NAME = 0x30, + LDAP_OPT_ERROR_NUMBER = 0x31, + LDAP_OPT_ERROR_STRING = 0x32, + LDAP_OPT_SERVER_ERROR = 0x33, + LDAP_OPT_SERVER_EXT_ERROR = 0x34, // Not Supported in Linux + LDAP_OPT_HOST_REACHABLE = 0x3E, // Not Supported in Linux + LDAP_OPT_PING_KEEP_ALIVE = 0x36, // Not Supported in Linux + LDAP_OPT_PING_WAIT_TIME = 0x37, // Not Supported in Linux + LDAP_OPT_PING_LIMIT = 0x38, // Not Supported in Linux + LDAP_OPT_DNSDOMAIN_NAME = 0x3B, // Not Supported in Linux + LDAP_OPT_GETDSNAME_FLAGS = 0x3D, // Not Supported in Linux + LDAP_OPT_PROMPT_CREDENTIALS = 0x3F, // Not Supported in Linux + LDAP_OPT_TCP_KEEPALIVE = 0x40, // Not Supported in Linux + LDAP_OPT_FAST_CONCURRENT_BIND = 0x41, // Not Supported in Linux + LDAP_OPT_SEND_TIMEOUT = 0x42, // Not Supported in Linux + LDAP_OPT_REFERRAL_CALLBACK = 0x70, // Not Supported in Linux + LDAP_OPT_CLIENT_CERTIFICATE = 0x80, // Not Supported in Linux + LDAP_OPT_SERVER_CERTIFICATE = 0x81, // Not Supported in Linux + LDAP_OPT_AUTO_RECONNECT = 0x91, // Not Supported in Linux + LDAP_OPT_SSPI_FLAGS = 0x92, + LDAP_OPT_SSL_INFO = 0x93, // Not Supported in Linux + LDAP_OPT_SIGN = 0x95, + LDAP_OPT_ENCRYPT = 0x96, + LDAP_OPT_SASL_METHOD = 0x97, + LDAP_OPT_AREC_EXCLUSIVE = 0x98, // Not Supported in Linux + LDAP_OPT_SECURITY_CONTEXT = 0x99, + LDAP_OPT_ROOTDSE_CACHE = 0x9a, // Not Supported in Linux + LDAP_OPT_X_SASL_REALM = 0x6101, + LDAP_OPT_X_SASL_AUTHCID = 0x6102, + LDAP_OPT_X_SASL_AUTHZID = 0x6103 + } + + internal enum ResultAll + { + LDAP_MSG_ALL = 1, + LDAP_MSG_RECEIVED = 2, + LDAP_MSG_POLLINGALL = 3 // Not Supported in Linux + } + + [StructLayout(LayoutKind.Sequential)] + internal sealed class LDAP_TIMEVAL + { + public int tv_sec; + public int tv_usec; + } + + [StructLayout(LayoutKind.Sequential)] + internal sealed class berval + { + public int bv_len = 0; + public IntPtr bv_val = IntPtr.Zero; + + public berval() { } + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal sealed class LdapControl + { + public IntPtr ldctl_oid = IntPtr.Zero; + public berval ldctl_value = null; + public bool ldctl_iscritical = false; + + public LdapControl() { } + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct LdapReferralCallback + { + public int sizeofcallback; + public QUERYFORCONNECTIONInternal query; + public NOTIFYOFNEWCONNECTIONInternal notify; + public DEREFERENCECONNECTIONInternal dereference; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct CRYPTOAPI_BLOB + { + public int cbData; + public IntPtr pbData; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct SecPkgContext_IssuerListInfoEx + { + public IntPtr aIssuers; + public int cIssuers; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal sealed class LdapMod + { + public int type = 0; + public IntPtr attribute = IntPtr.Zero; + public IntPtr values = IntPtr.Zero; + + ~LdapMod() + { + if (attribute != IntPtr.Zero) + { + Marshal.FreeHGlobal(attribute); + } + + if (values != IntPtr.Zero) + { + Marshal.FreeHGlobal(values); + } + } + } +} diff --git a/src/libraries/Common/src/Interop/Interop.Libraries.cs b/src/libraries/Common/src/Interop/Interop.Libraries.cs new file mode 100644 index 00000000000000..d58d6a2126a4d1 --- /dev/null +++ b/src/libraries/Common/src/Interop/Interop.Libraries.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +internal static partial class Interop +{ + internal static partial class Libraries + { +#if MONO + internal const string GlobalizationNative = "__Internal"; +#else + internal const string GlobalizationNative = "QCall"; +#endif + } +} diff --git a/src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Locale.cs b/src/libraries/Common/src/Interop/Interop.Locale.cs similarity index 100% rename from src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Locale.cs rename to src/libraries/Common/src/Interop/Interop.Locale.cs diff --git a/src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Normalization.cs b/src/libraries/Common/src/Interop/Interop.Normalization.cs similarity index 100% rename from src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Normalization.cs rename to src/libraries/Common/src/Interop/Interop.Normalization.cs diff --git a/src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs b/src/libraries/Common/src/Interop/Interop.ResultCode.cs similarity index 100% rename from src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs rename to src/libraries/Common/src/Interop/Interop.ResultCode.cs diff --git a/src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs b/src/libraries/Common/src/Interop/Interop.TimeZoneInfo.cs similarity index 100% rename from src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs rename to src/libraries/Common/src/Interop/Interop.TimeZoneInfo.cs diff --git a/src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Utils.cs b/src/libraries/Common/src/Interop/Interop.Utils.cs similarity index 100% rename from src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.Utils.cs rename to src/libraries/Common/src/Interop/Interop.Utils.cs diff --git a/src/libraries/Common/src/Interop/Linux/Interop.Libraries.cs b/src/libraries/Common/src/Interop/Linux/Interop.Libraries.cs index 25f0ce0a445e92..e7bc0d31f0d864 100644 --- a/src/libraries/Common/src/Interop/Linux/Interop.Libraries.cs +++ b/src/libraries/Common/src/Interop/Linux/Interop.Libraries.cs @@ -7,6 +7,7 @@ internal static partial class Interop internal static partial class Libraries { internal const string Odbc32 = "libodbc.so.2"; + internal const string OpenLdap = "libldap-2.4.so.2"; internal const string MsQuic = "msquic"; } } diff --git a/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ber.cs b/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ber.cs new file mode 100644 index 00000000000000..4a059e35dacdb8 --- /dev/null +++ b/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ber.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using System.DirectoryServices.Protocols; + +internal static partial class Interop +{ + [DllImport(Libraries.OpenLdap, EntryPoint = "ber_alloc_t", CharSet = CharSet.Ansi)] + public static extern IntPtr ber_alloc(int option); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ber_init", CharSet = CharSet.Ansi)] + public static extern IntPtr ber_init(berval value); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ber_free", CharSet = CharSet.Ansi)] + public static extern IntPtr ber_free([In] IntPtr berelement, int option); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ber_printf", CharSet = CharSet.Ansi)] + public static extern int ber_printf_emptyarg(SafeBerHandle berElement, string format); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ber_printf", CharSet = CharSet.Ansi)] + public static extern int ber_printf_int(SafeBerHandle berElement, string format, int value); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ber_printf", CharSet = CharSet.Ansi)] + public static extern int ber_printf_bytearray(SafeBerHandle berElement, string format, HGlobalMemHandle value, int length); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ber_printf", CharSet = CharSet.Ansi)] + public static extern int ber_printf_berarray(SafeBerHandle berElement, string format, IntPtr value); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ber_flatten", CharSet = CharSet.Ansi)] + public static extern int ber_flatten(SafeBerHandle berElement, ref IntPtr value); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ber_bvfree", CharSet = CharSet.Ansi)] + public static extern int ber_bvfree(IntPtr value); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ber_bvecfree", CharSet = CharSet.Ansi)] + public static extern int ber_bvecfree(IntPtr value); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ber_scanf", CharSet = CharSet.Ansi)] + public static extern int ber_scanf(SafeBerHandle berElement, string format); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ber_scanf", CharSet = CharSet.Ansi)] + public static extern int ber_scanf_int(SafeBerHandle berElement, string format, ref int value); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ber_scanf", CharSet = CharSet.Ansi)] + public static extern int ber_scanf_bitstring(SafeBerHandle berElement, string format, ref IntPtr value, ref int bitLength); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ber_scanf", CharSet = CharSet.Ansi)] + public static extern int ber_scanf_ptr(SafeBerHandle berElement, string format, ref IntPtr value); +} diff --git a/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs b/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs new file mode 100644 index 00000000000000..02fea9754b9c76 --- /dev/null +++ b/src/libraries/Common/src/Interop/Linux/OpenLdap/Interop.Ldap.cs @@ -0,0 +1,199 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using System.DirectoryServices.Protocols; + +namespace System.DirectoryServices.Protocols +{ + /// + /// Structure that will get passed into the Sasl interactive callback in case + /// the authentication process emits challenges to validate information. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct SaslDefaultCredentials + { + public string mech; + public string realm; + public string authcid; + public string passwd; + public string authzid; + } + + /// + /// Structure that will represent a Sasl Interactive challenge during a + /// Sasl interactive bind, which will contain the challenge and it is also + /// where we will have to resolve the result. + /// + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal class SaslInteractiveChallenge + { + public ulong saslChallengeType; + public string challenge; + public string prompt; + public string defresult; + public IntPtr result; + public uint len; + } + + internal enum SaslChallengeType + { + SASL_CB_LIST_END = 0, + SASL_CB_GETOPT = 1, + SASL_CB_LOG = 2, + SASL_CB_GETPATH = 3, + SASL_CB_VERIFYFILE = 4, + SASL_CB_GETCONFPATH = 5, + SASL_CB_USER = 0x4001, + SASL_CB_AUTHNAME = 0x4002, + SASL_CB_LANGUAGE = 0x4003, + SASL_CB_PASS = 0x4004, + SASL_CB_ECHOPROMPT = 0x4005, + SASL_CB_NOECHOPROMPT = 0x4006, + SASL_CB_CNONCE = 0x4007, + SASL_CB_GETREALM = 0x4008, + SASL_CB_PROXY_POLICY = 0x8001, + } +} + +internal delegate int LDAP_SASL_INTERACT_PROC(IntPtr ld, uint flags, IntPtr defaults, IntPtr interact); + +internal static partial class Interop +{ + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_initialize", CharSet = CharSet.Ansi, SetLastError = true)] + public static extern int ldap_initialize(out IntPtr ld, string hostname); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_init", CharSet = CharSet.Ansi, SetLastError = true)] + public static extern IntPtr ldap_init(string hostName, int portNumber); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_unbind_ext_s", CharSet = CharSet.Ansi)] + public static extern int ldap_unbind_ext_s(IntPtr ld, ref IntPtr serverctrls, ref IntPtr clientctrls); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_get_dn", CharSet = CharSet.Ansi)] + public static extern IntPtr ldap_get_dn([In] ConnectionHandle ldapHandle, [In] IntPtr result); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_get_option", CharSet = CharSet.Ansi)] + public static extern int ldap_get_option_secInfo([In] ConnectionHandle ldapHandle, [In] LdapOption option, [In, Out] SecurityPackageContextConnectionInformation outValue); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_get_option", CharSet = CharSet.Ansi)] + public static extern int ldap_get_option_sechandle([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref SecurityHandle outValue); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_get_option", CharSet = CharSet.Ansi)] + public static extern int ldap_get_option_int([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref int outValue); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_get_option", CharSet = CharSet.Ansi)] + public static extern int ldap_get_option_ptr([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref IntPtr outValue); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_get_values_len", CharSet = CharSet.Ansi)] + public static extern IntPtr ldap_get_values_len([In] ConnectionHandle ldapHandle, [In] IntPtr result, string name); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_result", SetLastError = true, CharSet = CharSet.Ansi)] + public static extern int ldap_result([In] ConnectionHandle ldapHandle, int messageId, int all, LDAP_TIMEVAL timeout, ref IntPtr Mesage); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_result2error", CharSet = CharSet.Ansi)] + public static extern int ldap_result2error([In] ConnectionHandle ldapHandle, [In] IntPtr result, int freeIt); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_search_ext", CharSet = CharSet.Ansi)] + public static extern int ldap_search([In] ConnectionHandle ldapHandle, string dn, int scope, string filter, IntPtr attributes, bool attributeOnly, IntPtr servercontrol, IntPtr clientcontrol, int timelimit, int sizelimit, ref int messageNumber); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_set_option", CharSet = CharSet.Ansi)] + public static extern int ldap_set_option_clientcert([In] ConnectionHandle ldapHandle, [In] LdapOption option, QUERYCLIENTCERT outValue); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_set_option", CharSet = CharSet.Ansi)] + public static extern int ldap_set_option_servercert([In] ConnectionHandle ldapHandle, [In] LdapOption option, VERIFYSERVERCERT outValue); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_set_option", CharSet = CharSet.Ansi, SetLastError = true)] + public static extern int ldap_set_option_int([In] ConnectionHandle ld, [In] LdapOption option, ref int inValue); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_set_option", CharSet = CharSet.Ansi)] + public static extern int ldap_set_option_ptr([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref IntPtr inValue); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_set_option", CharSet = CharSet.Ansi)] + public static extern int ldap_set_option_referral([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref LdapReferralCallback outValue); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_start_tls_s", CharSet = CharSet.Ansi)] + public static extern int ldap_start_tls(ConnectionHandle ldapHandle, ref int ServerReturnValue, ref IntPtr Message, IntPtr ServerControls, IntPtr ClientControls); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_parse_result", CharSet = CharSet.Ansi)] + public static extern int ldap_parse_result([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref int serverError, ref IntPtr dn, ref IntPtr message, ref IntPtr referral, ref IntPtr control, byte freeIt); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_parse_result", CharSet = CharSet.Ansi)] + public static extern int ldap_parse_result_referral([In] ConnectionHandle ldapHandle, [In] IntPtr result, IntPtr serverError, IntPtr dn, IntPtr message, ref IntPtr referral, IntPtr control, byte freeIt); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_parse_extended_result", CharSet = CharSet.Ansi)] + public static extern int ldap_parse_extended_result([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref IntPtr oid, ref IntPtr data, byte freeIt); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_parse_reference", CharSet = CharSet.Ansi)] + public static extern int ldap_parse_reference([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref IntPtr referrals, IntPtr ServerControls, byte freeIt); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_sasl_interactive_bind_s", CharSet = CharSet.Ansi)] + internal static extern int ldap_sasl_interactive_bind([In] ConnectionHandle ld, string dn, string mechanism, IntPtr serverctrls, IntPtr clientctrls, uint flags, [MarshalAs(UnmanagedType.FunctionPtr)] LDAP_SASL_INTERACT_PROC proc, IntPtr defaults); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_simple_bind_s", CharSet = CharSet.Ansi, SetLastError = true)] + public static extern int ldap_simple_bind([In] ConnectionHandle ld, string who, string passwd); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_bind_s", CharSet = CharSet.Ansi, SetLastError = true)] + public static extern int ldap_bind_s([In] ConnectionHandle ld, string who, string passwd, int method); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_err2string", CharSet = CharSet.Ansi)] + public static extern IntPtr ldap_err2string(int err); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_extended_operation", CharSet = CharSet.Ansi)] + public static extern int ldap_extended_operation([In] ConnectionHandle ldapHandle, string oid, berval data, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_first_attribute", CharSet = CharSet.Ansi)] + public static extern IntPtr ldap_first_attribute([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref IntPtr address); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_first_entry", CharSet = CharSet.Ansi)] + public static extern IntPtr ldap_first_entry([In] ConnectionHandle ldapHandle, [In] IntPtr result); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_first_reference", CharSet = CharSet.Ansi)] + public static extern IntPtr ldap_first_reference([In] ConnectionHandle ldapHandle, [In] IntPtr result); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_create_sort_control", CharSet = CharSet.Ansi)] + public static extern int ldap_create_sort_control(ConnectionHandle handle, IntPtr keys, byte critical, ref IntPtr control); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_control_free", CharSet = CharSet.Ansi)] + public static extern int ldap_control_free(IntPtr control); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_controls_free", CharSet = CharSet.Ansi)] + public static extern int ldap_controls_free([In] IntPtr value); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_value_free", CharSet = CharSet.Ansi)] + public static extern int ldap_value_free([In] IntPtr value); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_value_free_len", CharSet = CharSet.Ansi)] + public static extern IntPtr ldap_value_free_len([In] IntPtr berelement); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_memfree", CharSet = CharSet.Ansi)] + public static extern void ldap_memfree([In] IntPtr value); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_modify_ext", CharSet = CharSet.Ansi)] + public static extern int ldap_modify([In] ConnectionHandle ldapHandle, string dn, IntPtr attrs, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_next_attribute", CharSet = CharSet.Ansi)] + public static extern IntPtr ldap_next_attribute([In] ConnectionHandle ldapHandle, [In] IntPtr result, [In, Out] IntPtr address); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_next_entry", CharSet = CharSet.Ansi)] + public static extern IntPtr ldap_next_entry([In] ConnectionHandle ldapHandle, [In] IntPtr result); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_next_reference", CharSet = CharSet.Ansi)] + public static extern IntPtr ldap_next_reference([In] ConnectionHandle ldapHandle, [In] IntPtr result); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_abandon", CharSet = CharSet.Ansi)] + public static extern int ldap_abandon([In] ConnectionHandle ldapHandle, [In] int messagId); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_add_ext", CharSet = CharSet.Ansi)] + public static extern int ldap_add([In] ConnectionHandle ldapHandle, string dn, IntPtr attrs, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_delete_ext", CharSet = CharSet.Ansi)] + public static extern int ldap_delete_ext([In] ConnectionHandle ldapHandle, string dn, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_rename", CharSet = CharSet.Ansi)] + public static extern int ldap_rename([In] ConnectionHandle ldapHandle, string dn, string newRdn, string newParentDn, int deleteOldRdn, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); + + [DllImport(Libraries.OpenLdap, EntryPoint = "ldap_compare_ext", CharSet = CharSet.Ansi)] + public static extern int ldap_compare([In] ConnectionHandle ldapHandle, string dn, string attributeName, berval binaryValue, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); +} diff --git a/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs b/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs index 287fc21ebedf0b..f2417e20881bd6 100644 --- a/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs +++ b/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs @@ -16,17 +16,23 @@ internal static partial class cgroups { // For cgroup v1, see https://www.kernel.org/doc/Documentation/cgroup-v1/ // For cgroup v2, see https://www.kernel.org/doc/Documentation/cgroup-v2.txt + // For disambiguation, see https://systemd.io/CGROUP_DELEGATION/#three-different-tree-setups- - /// The version of cgroup that's being used + /// The supported versions of cgroup. internal enum CGroupVersion { None, CGroup1, CGroup2 }; + /// Path to cgroup filesystem that tells us which version of cgroup is in use. + private const string SysFsCgroupFileSystemPath = "/sys/fs/cgroup"; /// Path to mountinfo file in procfs for the current process. private const string ProcMountInfoFilePath = "/proc/self/mountinfo"; /// Path to cgroup directory in procfs for the current process. private const string ProcCGroupFilePath = "/proc/self/cgroup"; + /// The version of cgroup that's being used. Mutated by tests only. + internal static readonly CGroupVersion s_cgroupVersion = FindCGroupVersion(); + /// Path to the found cgroup memory limit path, or null if it couldn't be found. - internal static readonly string? s_cgroupMemoryLimitPath = FindCGroupMemoryLimitPath(); + internal static readonly string? s_cgroupMemoryLimitPath = FindCGroupMemoryLimitPath(s_cgroupVersion); /// Tries to read the memory limit from the cgroup memory location. /// The read limit, or 0 if it couldn't be read. @@ -102,19 +108,39 @@ internal static bool TryReadMemoryValueFromFile(string path, out ulong result) return false; } + /// Find the cgroup version in use on the system. + /// The cgroup version. + private static CGroupVersion FindCGroupVersion() + { + try + { + return new DriveInfo(SysFsCgroupFileSystemPath).DriveFormat switch + { + "cgroup2fs" => CGroupVersion.CGroup2, + "tmpfs" => CGroupVersion.CGroup1, + _ => CGroupVersion.None, + }; + } + catch (Exception ex) when (ex is DriveNotFoundException || ex is ArgumentException) + { + return CGroupVersion.None; + } + } + /// Find the cgroup memory limit path. + /// The cgroup version currently in use on the system. /// The limit path if found; otherwise, null. - private static string? FindCGroupMemoryLimitPath() + private static string? FindCGroupMemoryLimitPath(CGroupVersion cgroupVersion) { - string? cgroupMemoryPath = FindCGroupPath("memory", out CGroupVersion version); + string? cgroupMemoryPath = FindCGroupPath(cgroupVersion, "memory"); if (cgroupMemoryPath != null) { - if (version == CGroupVersion.CGroup1) + if (cgroupVersion == CGroupVersion.CGroup1) { return cgroupMemoryPath + "/memory.limit_in_bytes"; } - if (version == CGroupVersion.CGroup2) + if (cgroupVersion == CGroupVersion.CGroup2) { // 'memory.high' is a soft limit; the process may get throttled // 'memory.max' is where OOM killer kicks in @@ -126,34 +152,71 @@ internal static bool TryReadMemoryValueFromFile(string path, out ulong result) } /// Find the cgroup path for the specified subsystem. + /// The cgroup version currently in use on the system. /// The subsystem, e.g. "memory". /// The cgroup path if found; otherwise, null. - private static string? FindCGroupPath(string subsystem, out CGroupVersion version) + private static string? FindCGroupPath(CGroupVersion cgroupVersion, string subsystem) { - if (TryFindHierarchyMount(subsystem, out version, out string? hierarchyRoot, out string? hierarchyMount) && - TryFindCGroupPathForSubsystem(subsystem, out string? cgroupPathRelativeToMount)) + if (cgroupVersion == CGroupVersion.None) + { + return null; + } + + if (TryFindHierarchyMount(cgroupVersion, subsystem, out string? hierarchyRoot, out string? hierarchyMount) && + TryFindCGroupPathForSubsystem(cgroupVersion, subsystem, out string? cgroupPathRelativeToMount)) { - // For a host cgroup, we need to append the relative path. - // In a docker container, the root and relative path are the same and we don't need to append. - return (hierarchyRoot != cgroupPathRelativeToMount) ? - hierarchyMount + cgroupPathRelativeToMount : - hierarchyMount; + return FindCGroupPath(hierarchyRoot, hierarchyMount, cgroupPathRelativeToMount); } return null; } + internal static string FindCGroupPath(string hierarchyRoot, string hierarchyMount, string cgroupPathRelativeToMount) + { + // For a host cgroup, we need to append the relative path. + // The root and cgroup path can share a common prefix of the path that should not be appended. + // Example 1 (docker): + // hierarchyMount: /sys/fs/cgroup/cpu + // hierarchyRoot: /docker/87ee2de57e51bc75175a4d2e81b71d162811b179d549d6601ed70b58cad83578 + // cgroupPathRelativeToMount: /docker/87ee2de57e51bc75175a4d2e81b71d162811b179d549d6601ed70b58cad83578/my_named_cgroup + // append to the cgroupPath: /my_named_cgroup + // final cgroupPath: /sys/fs/cgroup/cpu/my_named_cgroup + // + // Example 2 (out of docker) + // hierarchyMount: /sys/fs/cgroup/cpu + // hierarchyRoot: / + // cgroupPathRelativeToMount: /my_named_cgroup + // append to the cgroupPath: /my_named_cgroup + // final cgroupPath: /sys/fs/cgroup/cpu/my_named_cgroup + + int commonPathPrefixLength = hierarchyRoot.Length; + if ((commonPathPrefixLength == 1) || !cgroupPathRelativeToMount.StartsWith(hierarchyRoot, StringComparison.Ordinal)) + { + commonPathPrefixLength = 0; + } + + return string.Concat(hierarchyMount, cgroupPathRelativeToMount.AsSpan(commonPathPrefixLength)); + } + /// Find the cgroup mount information for the specified subsystem. + /// The cgroup version currently in use on the system. /// The subsystem, e.g. "memory". /// The path of the directory in the filesystem which forms the root of this mount; null if not found. /// The path of the mount point relative to the process's root directory; null if not found. /// true if the mount was found; otherwise, null. - private static bool TryFindHierarchyMount(string subsystem, out CGroupVersion version, [NotNullWhen(true)] out string? root, [NotNullWhen(true)] out string? path) + private static bool TryFindHierarchyMount(CGroupVersion cgroupVersion, string subsystem, [NotNullWhen(true)] out string? root, [NotNullWhen(true)] out string? path) { - return TryFindHierarchyMount(ProcMountInfoFilePath, subsystem, out version, out root, out path); + return TryFindHierarchyMount(cgroupVersion, ProcMountInfoFilePath, subsystem, out root, out path); } - internal static bool TryFindHierarchyMount(string mountInfoFilePath, string subsystem, out CGroupVersion version, [NotNullWhen(true)] out string? root, [NotNullWhen(true)] out string? path) + /// Find the cgroup mount information for the specified subsystem. + /// The cgroup version currently in use on the system. + /// The path to the /mountinfo file. Useful for tests. + /// The subsystem, e.g. "memory". + /// The path of the directory in the filesystem which forms the root of this mount; null if not found. + /// The path of the mount point relative to the process's root directory; null if not found. + /// true if the mount was found; otherwise, null. + internal static bool TryFindHierarchyMount(CGroupVersion cgroupVersion, string mountInfoFilePath, string subsystem, [NotNullWhen(true)] out string? root, [NotNullWhen(true)] out string? path) { if (File.Exists(mountInfoFilePath)) { @@ -188,31 +251,30 @@ internal static bool TryFindHierarchyMount(string mountInfoFilePath, string subs continue; } - bool validCGroup1Entry = ((postSeparatorlineParts[0] == "cgroup") && - (Array.IndexOf(postSeparatorlineParts[2].Split(','), subsystem) >= 0)); - bool validCGroup2Entry = postSeparatorlineParts[0] == "cgroup2"; - - if (!validCGroup1Entry && !validCGroup2Entry) + if (cgroupVersion == CGroupVersion.CGroup1) { - // Not the relevant entry. - continue; + bool validCGroup1Entry = ((postSeparatorlineParts[0] == "cgroup") && + (Array.IndexOf(postSeparatorlineParts[2].Split(','), subsystem) >= 0)); + if (!validCGroup1Entry) + { + continue; + } } + else if (cgroupVersion == CGroupVersion.CGroup2) + { + bool validCGroup2Entry = postSeparatorlineParts[0] == "cgroup2"; + if (!validCGroup2Entry) + { + continue; + } - // Found the relevant entry. Extract the cgroup version, mount root and path. - switch (postSeparatorlineParts[0]) + } + else { - case "cgroup": - version = CGroupVersion.CGroup1; - break; - case "cgroup2": - version = CGroupVersion.CGroup2; - break; - default: - version = CGroupVersion.None; - Debug.Fail($"invalid value for CGroupVersion \"{postSeparatorlineParts[0]}\""); - break; + Debug.Fail($"Unexpected cgroup version \"{cgroupVersion}\""); } + string[] lineParts = line.Substring(0, endOfOptionalFields).Split(' '); root = lineParts[3]; path = lineParts[4]; @@ -227,22 +289,27 @@ internal static bool TryFindHierarchyMount(string mountInfoFilePath, string subs } } - version = CGroupVersion.None; root = null; path = null; return false; } /// Find the cgroup relative path for the specified subsystem. + /// The cgroup version currently in use on the system. /// The subsystem, e.g. "memory". /// The found path, or null if it couldn't be found. - /// - private static bool TryFindCGroupPathForSubsystem(string subsystem, [NotNullWhen(true)] out string? path) + /// true if a cgroup path for the subsystem is found. + private static bool TryFindCGroupPathForSubsystem(CGroupVersion cgroupVersion, string subsystem, [NotNullWhen(true)] out string? path) { - return TryFindCGroupPathForSubsystem(ProcCGroupFilePath, subsystem, out path); + return TryFindCGroupPathForSubsystem(cgroupVersion, ProcCGroupFilePath, subsystem, out path); } - internal static bool TryFindCGroupPathForSubsystem(string procCGroupFilePath, string subsystem, [NotNullWhen(true)] out string? path) + /// Find the cgroup relative path for the specified subsystem. + /// The cgroup version currently in use on the system. + /// The subsystem, e.g. "memory". + /// The found path, or null if it couldn't be found. + /// true if a cgroup path for the subsystem is found. + internal static bool TryFindCGroupPathForSubsystem(CGroupVersion cgroupVersion, string procCGroupFilePath, string subsystem, [NotNullWhen(true)] out string? path) { if (File.Exists(procCGroupFilePath)) { @@ -261,28 +328,36 @@ internal static bool TryFindCGroupPathForSubsystem(string procCGroupFilePath, st continue; } - // cgroup v2: Find the first entry that matches the cgroup v2 hierarchy: - // 0::$PATH - - if ((lineParts[0] == "0") && (string.Empty == lineParts[1])) + if (cgroupVersion == CGroupVersion.CGroup1) { + // cgroup v1: Find the first entry that has the subsystem listed in its controller + // list. See man page for cgroups for /proc/[pid]/cgroups format, e.g: + // hierarchy-ID:controller-list:cgroup-path + // 5:cpuacct,cpu,cpuset:/daemons + if (Array.IndexOf(lineParts[1].Split(','), subsystem) < 0) + { + // Not the relevant entry. + continue; + } + path = lineParts[2]; return true; } - - // cgroup v1: Find the first entry that has the subsystem listed in its controller - // list. See man page for cgroups for /proc/[pid]/cgroups format, e.g: - // hierarchy-ID:controller-list:cgroup-path - // 5:cpuacct,cpu,cpuset:/daemons - - if (Array.IndexOf(lineParts[1].Split(','), subsystem) < 0) + else if (cgroupVersion == CGroupVersion.CGroup2) { - // Not the relevant entry. - continue; + // cgroup v2: Find the first entry that matches the cgroup v2 hierarchy: + // 0::$PATH + + if ((lineParts[0] == "0") && (lineParts[1].Length == 0)) + { + path = lineParts[2]; + return true; + } + } + else + { + Debug.Fail($"Unexpected cgroup version: \"{cgroupVersion}\""); } - - path = lineParts[2]; - return true; } } } diff --git a/src/libraries/Common/src/Interop/OSX/Interop.Libraries.cs b/src/libraries/Common/src/Interop/OSX/Interop.Libraries.cs index 84bf6d6398da89..9ba6608df12124 100644 --- a/src/libraries/Common/src/Interop/OSX/Interop.Libraries.cs +++ b/src/libraries/Common/src/Interop/OSX/Interop.Libraries.cs @@ -9,13 +9,14 @@ internal static partial class Libraries internal const string CoreFoundationLibrary = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation"; internal const string CoreServicesLibrary = "/System/Library/Frameworks/CoreServices.framework/CoreServices"; internal const string CFNetworkLibrary = "/System/Library/Frameworks/CFNetwork.framework/CFNetwork"; - internal const string libproc = "libproc"; + internal const string libobjc = "/usr/lib/libobjc.dylib"; + internal const string libproc = "/usr/lib/libproc.dylib"; internal const string LibSystemCommonCrypto = "/usr/lib/system/libcommonCrypto"; internal const string LibSystemKernel = "/usr/lib/system/libsystem_kernel"; internal const string Odbc32 = "libodbc.2.dylib"; + internal const string OpenLdap = "libldap"; internal const string SystemConfigurationLibrary = "/System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration"; internal const string AppleCryptoNative = "System.Security.Cryptography.Native.Apple"; internal const string MsQuic = "msquic"; - } } diff --git a/src/libraries/Common/src/Interop/OSX/Interop.libobjc.cs b/src/libraries/Common/src/Interop/OSX/Interop.libobjc.cs new file mode 100644 index 00000000000000..d76c59bac334e9 --- /dev/null +++ b/src/libraries/Common/src/Interop/OSX/Interop.libobjc.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class libobjc + { +#if TARGET_ARM64 + private const string MessageSendStructReturnEntryPoint = "objc_msgSend"; +#else + private const string MessageSendStructReturnEntryPoint = "objc_msgSend_stret"; +#endif + + [StructLayout(LayoutKind.Sequential)] + private struct NSOperatingSystemVersion + { + public nint majorVersion; + public nint minorVersion; + public nint patchVersion; + } + + [DllImport(Libraries.libobjc)] + private static extern IntPtr objc_getClass(string className); + [DllImport(Libraries.libobjc)] + private static extern IntPtr sel_getUid(string selector); + [DllImport(Libraries.libobjc)] + private static extern IntPtr objc_msgSend(IntPtr basePtr, IntPtr selector); + + internal static Version GetOperatingSystemVersion() + { + int major = 0; + int minor = 0; + int patch = 0; + + IntPtr processInfo = objc_msgSend(objc_getClass("NSProcessInfo"), sel_getUid("processInfo")); + + if (processInfo != IntPtr.Zero) + { + NSOperatingSystemVersion osVersion = get_operatingSystemVersion(processInfo, sel_getUid("operatingSystemVersion")); + + checked + { + major = (int)osVersion.majorVersion; + minor = (int)osVersion.minorVersion; + patch = (int)osVersion.patchVersion; + } + } + + return new Version(major, minor, patch); + } + + [DllImport(Libraries.libobjc, EntryPoint = MessageSendStructReturnEntryPoint)] + private static extern NSOperatingSystemVersion get_operatingSystemVersion(IntPtr basePtr, IntPtr selector); + } +} diff --git a/src/libraries/Common/src/Interop/Unix/Interop.Errors.cs b/src/libraries/Common/src/Interop/Unix/Interop.Errors.cs index dad796280e71aa..e6de6c91723c36 100644 --- a/src/libraries/Common/src/Interop/Unix/Interop.Errors.cs +++ b/src/libraries/Common/src/Interop/Unix/Interop.Errors.cs @@ -182,6 +182,16 @@ internal static unsafe string StrError(int platformErrno) return Marshal.PtrToStringAnsi((IntPtr)message)!; } +#if SERIAL_PORTS + [DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_ConvertErrorPlatformToPal")] + internal static extern Error ConvertErrorPlatformToPal(int platformErrno); + + [DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_ConvertErrorPalToPlatform")] + internal static extern int ConvertErrorPalToPlatform(Error error); + + [DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_StrErrorR")] + private static extern unsafe byte* StrErrorR(int platformErrno, byte* buffer, int bufferSize); +#else [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_ConvertErrorPlatformToPal")] internal static extern Error ConvertErrorPlatformToPal(int platformErrno); @@ -190,6 +200,7 @@ internal static unsafe string StrError(int platformErrno) [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_StrErrorR")] private static extern unsafe byte* StrErrorR(int platformErrno, byte* buffer, int bufferSize); +#endif } } diff --git a/src/libraries/Common/src/Interop/Unix/Interop.Libraries.cs b/src/libraries/Common/src/Interop/Unix/Interop.Libraries.cs index 2ee0c3e7e841be..f511948294884e 100644 --- a/src/libraries/Common/src/Interop/Unix/Interop.Libraries.cs +++ b/src/libraries/Common/src/Interop/Unix/Interop.Libraries.cs @@ -8,7 +8,6 @@ internal static partial class Libraries { // Shims internal const string SystemNative = "libSystem.Native"; - internal const string GlobalizationNative = "libSystem.Globalization.Native"; internal const string NetSecurityNative = "libSystem.Net.Security.Native"; internal const string CryptoNative = "libSystem.Security.Cryptography.Native.OpenSsl"; internal const string CompressionNative = "libSystem.IO.Compression.Native"; diff --git a/src/libraries/Common/src/Interop/Unix/Interop.Poll.Structs.cs b/src/libraries/Common/src/Interop/Unix/Interop.Poll.Structs.cs new file mode 100644 index 00000000000000..34ca249bcdc958 --- /dev/null +++ b/src/libraries/Common/src/Interop/Unix/Interop.Poll.Structs.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. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + [Flags] + internal enum PollEvents : short + { + POLLNONE = 0x0000, // No events occurred. + POLLIN = 0x0001, // non-urgent readable data available + POLLPRI = 0x0002, // urgent readable data available + POLLOUT = 0x0004, // data can be written without blocked + POLLERR = 0x0008, // an error occurred + POLLHUP = 0x0010, // the file descriptor hung up + POLLNVAL = 0x0020, // the requested events were invalid + } + + internal struct PollEvent + { + internal int FileDescriptor; // The file descriptor to poll + internal PollEvents Events; // The events to poll for + internal PollEvents TriggeredEvents; // The events that occurred which triggered the poll + } +} diff --git a/src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.ICU.cs b/src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.ICU.cs deleted file mode 100644 index 0dce072958a7fa..00000000000000 --- a/src/libraries/Common/src/Interop/Unix/System.Globalization.Native/Interop.ICU.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Runtime.InteropServices; - -internal static partial class Interop -{ - internal static partial class Globalization - { - [DllImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_LoadICU")] - internal static extern int LoadICU(); - - [DllImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetICUVersion")] - internal static extern int GetICUVersion(); - } -} diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetMaximumAddressSize.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetMaximumAddressSize.cs new file mode 100644 index 00000000000000..9c106cbf469180 --- /dev/null +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetMaximumAddressSize.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Sys + { + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetMaximumAddressSize")] + internal static extern int GetMaximumAddressSize(); + } +} diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetSocketType.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetSocketType.cs index f857bf32f35375..044764e27e2529 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetSocketType.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetSocketType.cs @@ -10,6 +10,6 @@ internal static partial class Interop internal static partial class Sys { [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetSocketType")] - internal static extern Error GetSocketType(SafeSocketHandle socket, out AddressFamily addressFamily, out SocketType socketType, out ProtocolType protocolType); + internal static extern Error GetSocketType(SafeSocketHandle socket, out AddressFamily addressFamily, out SocketType socketType, out ProtocolType protocolType, out bool isListening); } } diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs index ee5e4272295286..e02afa58e91af1 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs @@ -44,6 +44,7 @@ internal enum UnixFileSystemTypes : long bdevfs = 0x62646576, bfs = 0x1BADFACE, binfmt_misc = 0x42494E4D, + bootfs = 0xA56D3FF9, btrfs = 0x9123683E, ceph = 0x00C36400, cgroupfs = 0x0027E0EB, @@ -65,6 +66,7 @@ internal enum UnixFileSystemTypes : long ext3 = 0xEF53, ext4 = 0xEF53, fat = 0x4006, + fd = 0xF00D1E, fhgfs = 0x19830326, fuse = 0x65735546, fuseblk = 0x65735546, @@ -86,6 +88,7 @@ internal enum UnixFileSystemTypes : long jffs2 = 0x72B6, jfs = 0x3153464A, kafs = 0x6B414653, + lofs = 0xEF53, /* loopback filesystem, magic same as ext2 */ logfs = 0xC97E8168, lustre = 0x0BD00BD0, minix_old = 0x137F, /* orig. minix */ @@ -227,6 +230,7 @@ private static DriveType GetDriveType(string fileSystemName) case "bdevfs": case "befs": case "bfs": + case "bootfs": case "bpf_fs": case "btrfs": case "btrfs_test": @@ -261,6 +265,7 @@ private static DriveType GetDriveType(string fileSystemName) case "jffs": case "jffs2": case "jfs": + case "lofs": case "logfs": case "lxfs": case "minix (30 char.)": @@ -384,15 +389,18 @@ private static DriveType GetDriveType(string fileSystemName) case "cgroupfs": case "cgroup2fs": case "configfs": + case "cpuset": case "cramfs": case "cramfs-wend": case "cryptkeeper": - case "cpuset": + case "ctfs": case "debugfs": + case "dev": case "devfs": case "devpts": case "devtmpfs": case "encfs": + case "fd": case "fdesc": case "fuse.gvfsd-fuse": case "fusectl": @@ -400,9 +408,11 @@ private static DriveType GetDriveType(string fileSystemName) case "hugetlbfs": case "libpam-encfs": case "ibpam-mount": + case "mntfs": + case "mqueue": case "mtpfs": case "mythtvfs": - case "mqueue": + case "objfs": case "openprom": case "openpromfs": case "pipefs": @@ -417,6 +427,7 @@ private static DriveType GetDriveType(string fileSystemName) case "securityfs": case "selinux": case "selinuxfs": + case "sharefs": case "sockfs": case "sysfs": case "tmpfs": diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Poll.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Poll.cs index 549617257de443..895ce720e31a31 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Poll.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Poll.cs @@ -10,25 +10,6 @@ internal static partial class Interop { internal static partial class Sys { - [Flags] - internal enum PollEvents : short - { - POLLNONE = 0x0000, // No events occurred. - POLLIN = 0x0001, // non-urgent readable data available - POLLPRI = 0x0002, // urgent readable data available - POLLOUT = 0x0004, // data can be written without blocked - POLLERR = 0x0008, // an error occurred - POLLHUP = 0x0010, // the file descriptor hung up - POLLNVAL = 0x0020, // the requested events were invalid - } - - internal struct PollEvent - { - internal int FileDescriptor; // The file descriptor to poll - internal PollEvents Events; // The events to poll for - internal PollEvents TriggeredEvents; // The events that occurred which triggered the poll - } - /// /// Polls a set of file descriptors for signals and returns what signals have been set /// diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Receive.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Receive.cs new file mode 100644 index 00000000000000..8f3cdbf9db07a8 --- /dev/null +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Receive.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Net.Sockets; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Sys + { + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Receive")] + internal static extern unsafe Error Receive(SafeHandle socket, byte* buffer, int bufferLen, SocketFlags flags, int* received); + } +} diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Send.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Send.cs new file mode 100644 index 00000000000000..b4a7e1c9bc8320 --- /dev/null +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Send.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Net.Sockets; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Sys + { + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Send")] + internal static extern unsafe Error Send(SafeHandle socket, byte* buffer, int bufferLen, SocketFlags flags, int* sent); + } +} diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.SysLog.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.SysLog.cs index 2edde6fbc11b0d..8933e9c3d39adb 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.SysLog.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.SysLog.cs @@ -19,28 +19,6 @@ internal enum SysLogPriority : int LOG_NOTICE = 5, /* normal but significant condition */ LOG_INFO = 6, /* informational */ LOG_DEBUG = 7, /* debug-level messages */ - // Facilities - LOG_KERN = (0<<3), /* kernel messages */ - LOG_USER = (1<<3), /* random user-level messages */ - LOG_MAIL = (2<<3), /* mail system */ - LOG_DAEMON = (3<<3), /* system daemons */ - LOG_AUTH = (4<<3), /* authorization messages */ - LOG_SYSLOG = (5<<3), /* messages generated internally by syslogd */ - LOG_LPR = (6<<3), /* line printer subsystem */ - LOG_NEWS = (7<<3), /* network news subsystem */ - LOG_UUCP = (8<<3), /* UUCP subsystem */ - LOG_CRON = (9<<3), /* clock daemon */ - LOG_AUTHPRIV = (10<<3), /* authorization messages (private) */ - LOG_FTP = (11<<3), /* ftp daemon */ - // Between FTP and Local is reserved for system use - LOG_LOCAL0 = (16<<3), /* reserved for local use */ - LOG_LOCAL1 = (17<<3), /* reserved for local use */ - LOG_LOCAL2 = (18<<3), /* reserved for local use */ - LOG_LOCAL3 = (19<<3), /* reserved for local use */ - LOG_LOCAL4 = (20<<3), /* reserved for local use */ - LOG_LOCAL5 = (21<<3), /* reserved for local use */ - LOG_LOCAL6 = (22<<3), /* reserved for local use */ - LOG_LOCAL7 = (23<<3), /* reserved for local use */ } /// diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Write.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Write.cs index c80f1041fd9623..9c4e0aa2a4e92a 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Write.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.Write.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Runtime.InteropServices; internal static partial class Interop @@ -21,6 +22,6 @@ internal static partial class Sys internal static extern unsafe int Write(SafeHandle fd, byte* buffer, int bufferSize); [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Write", SetLastError = true)] - internal static extern unsafe int Write(int fd, byte* buffer, int bufferSize); + internal static extern unsafe int Write(IntPtr fd, byte* buffer, int bufferSize); } } diff --git a/src/libraries/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs b/src/libraries/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs index c80283f5f218b7..b86d5caaeb350a 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs @@ -127,12 +127,11 @@ internal static extern Status GetUser( ref GssBuffer token); [DllImport(Interop.Libraries.NetSecurityNative, EntryPoint="NetSecurityNative_Wrap")] - private static extern Status Wrap( + private static extern unsafe Status Wrap( out Status minorStatus, SafeGssContextHandle? contextHandle, bool isEncrypt, - byte[] inputBytes, - int offset, + byte* inputBytes, int count, ref GssBuffer outBuffer); @@ -145,20 +144,17 @@ private static extern Status Unwrap( int count, ref GssBuffer outBuffer); - internal static Status WrapBuffer( + internal static unsafe Status WrapBuffer( out Status minorStatus, SafeGssContextHandle? contextHandle, bool isEncrypt, - byte[] inputBytes, - int offset, - int count, + ReadOnlySpan inputBytes, ref GssBuffer outBuffer) { - Debug.Assert(inputBytes != null, "inputBytes must be valid value"); - Debug.Assert(offset >= 0 && offset <= inputBytes.Length, "offset must be valid"); - Debug.Assert(count >= 0 && count <= (inputBytes.Length - offset), "count must be valid"); - - return Wrap(out minorStatus, contextHandle, isEncrypt, inputBytes, offset, count, ref outBuffer); + fixed (byte* inputBytesPtr = inputBytes) + { + return Wrap(out minorStatus, contextHandle, isEncrypt, inputBytesPtr, inputBytes.Length, ref outBuffer); + } } internal static Status UnwrapBuffer( diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.CryptImportKey.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.CryptImportKey.cs index c741fcd8f53824..d6d1e3b1b13acb 100644 --- a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.CryptImportKey.cs +++ b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.CryptImportKey.cs @@ -10,9 +10,9 @@ internal partial class Interop internal partial class Advapi32 { [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern bool CryptImportKey( + internal static extern unsafe bool CryptImportKey( SafeProvHandle hProv, - byte[] pbData, + byte* pbData, int dwDataLen, SafeKeyHandle hPubKey, int dwFlags, diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegCreateKeyEx.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegCreateKeyEx.cs index bb9da06c11d486..3caac3041f920f 100644 --- a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegCreateKeyEx.cs +++ b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegCreateKeyEx.cs @@ -16,7 +16,7 @@ internal static partial class Advapi32 { // Note: RegCreateKeyEx won't set the last error on failure - it returns // an error code if it fails. - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegCreateKeyExW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegCreateKeyExW", ExactSpelling = true)] internal static extern int RegCreateKeyEx( SafeRegistryHandle hKey, string lpSubKey, diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegDeleteKeyEx.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegDeleteKeyEx.cs index 487caf8b6d79d2..2fff3b1ed51641 100644 --- a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegDeleteKeyEx.cs +++ b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegDeleteKeyEx.cs @@ -13,7 +13,7 @@ internal static partial class Interop { internal static partial class Advapi32 { - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegDeleteKeyExW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegDeleteKeyExW", ExactSpelling = true)] internal static extern int RegDeleteKeyEx(SafeRegistryHandle hKey, string lpSubKey, int samDesired, int Reserved); } } diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegDeleteValue.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegDeleteValue.cs index 43cf683c2bddfe..7bb376930fa75e 100644 --- a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegDeleteValue.cs +++ b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegDeleteValue.cs @@ -14,7 +14,7 @@ internal static partial class Interop { internal static partial class Advapi32 { - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegDeleteValueW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegDeleteValueW", ExactSpelling = true)] internal static extern int RegDeleteValue(SafeRegistryHandle hKey, string? lpValueName); } } diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegEnumKeyEx.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegEnumKeyEx.cs index 11165cc91a9661..d618b50cd1cd84 100644 --- a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegEnumKeyEx.cs +++ b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegEnumKeyEx.cs @@ -14,7 +14,7 @@ internal static partial class Interop { internal static partial class Advapi32 { - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegEnumKeyExW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegEnumKeyExW", ExactSpelling = true)] internal static extern unsafe int RegEnumKeyEx( SafeRegistryHandle hKey, int dwIndex, diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegEnumValue.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegEnumValue.cs index e2ab45dea19331..02a7ad96928441 100644 --- a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegEnumValue.cs +++ b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegEnumValue.cs @@ -15,7 +15,7 @@ internal static partial class Interop { internal static partial class Advapi32 { - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegEnumValueW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegEnumValueW", ExactSpelling = true)] internal static extern unsafe int RegEnumValue( SafeRegistryHandle hKey, int dwIndex, diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegOpenKeyEx.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegOpenKeyEx.cs index 5f5b6b6e372ed5..0bc2cdce3c836e 100644 --- a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegOpenKeyEx.cs +++ b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegOpenKeyEx.cs @@ -15,7 +15,7 @@ internal static partial class Interop { internal static partial class Advapi32 { - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegOpenKeyExW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegOpenKeyExW", ExactSpelling = true)] internal static extern int RegOpenKeyEx( SafeRegistryHandle hKey, string? lpSubKey, @@ -24,7 +24,7 @@ internal static extern int RegOpenKeyEx( out SafeRegistryHandle hkResult); - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegOpenKeyExW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegOpenKeyExW", ExactSpelling = true)] internal static extern int RegOpenKeyEx( IntPtr hKey, string? lpSubKey, diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegQueryValueEx.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegQueryValueEx.cs index 72b8aa8f7bcf1b..bde703ad18632a 100644 --- a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegQueryValueEx.cs +++ b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegQueryValueEx.cs @@ -14,7 +14,7 @@ internal static partial class Interop { internal static partial class Advapi32 { - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegQueryValueExW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegQueryValueExW", ExactSpelling = true)] internal static extern int RegQueryValueEx( SafeRegistryHandle hKey, string? lpValueName, @@ -23,7 +23,7 @@ internal static extern int RegQueryValueEx( [Out] byte[]? lpData, ref int lpcbData); - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegQueryValueExW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegQueryValueExW", ExactSpelling = true)] internal static extern int RegQueryValueEx( SafeRegistryHandle hKey, string? lpValueName, @@ -32,7 +32,7 @@ internal static extern int RegQueryValueEx( ref int lpData, ref int lpcbData); - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegQueryValueExW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegQueryValueExW", ExactSpelling = true)] internal static extern int RegQueryValueEx( SafeRegistryHandle hKey, string? lpValueName, @@ -41,7 +41,7 @@ internal static extern int RegQueryValueEx( ref long lpData, ref int lpcbData); - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegQueryValueExW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegQueryValueExW", ExactSpelling = true)] internal static extern int RegQueryValueEx( SafeRegistryHandle hKey, string? lpValueName, diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegSetValueEx.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegSetValueEx.cs index 847d28fa1c577b..72cee21e1a17bb 100644 --- a/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegSetValueEx.cs +++ b/src/libraries/Common/src/Interop/Windows/Advapi32/Interop.RegSetValueEx.cs @@ -14,7 +14,7 @@ internal static partial class Interop { internal static partial class Advapi32 { - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegSetValueExW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegSetValueExW", ExactSpelling = true)] internal static extern int RegSetValueEx( SafeRegistryHandle hKey, string? lpValueName, @@ -23,7 +23,7 @@ internal static extern int RegSetValueEx( byte[]? lpData, int cbData); - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegSetValueExW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegSetValueExW", ExactSpelling = true)] internal static extern int RegSetValueEx( SafeRegistryHandle hKey, string? lpValueName, @@ -32,7 +32,7 @@ internal static extern int RegSetValueEx( char[]? lpData, int cbData); - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegSetValueExW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegSetValueExW", ExactSpelling = true)] internal static extern int RegSetValueEx( SafeRegistryHandle hKey, string? lpValueName, @@ -41,7 +41,7 @@ internal static extern int RegSetValueEx( ref int lpData, int cbData); - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegSetValueExW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegSetValueExW", ExactSpelling = true)] internal static extern int RegSetValueEx( SafeRegistryHandle hKey, string? lpValueName, @@ -50,7 +50,7 @@ internal static extern int RegSetValueEx( ref long lpData, int cbData); - [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegSetValueExW")] + [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, BestFitMapping = false, EntryPoint = "RegSetValueExW", ExactSpelling = true)] internal static extern int RegSetValueEx( SafeRegistryHandle hKey, string? lpValueName, diff --git a/src/libraries/Common/src/Interop/Windows/Interop.Libraries.cs b/src/libraries/Common/src/Interop/Windows/Interop.Libraries.cs index 1c1b3db6a0b762..2672c4cc489e52 100644 --- a/src/libraries/Common/src/Interop/Windows/Interop.Libraries.cs +++ b/src/libraries/Common/src/Interop/Windows/Interop.Libraries.cs @@ -34,6 +34,7 @@ internal static partial class Libraries internal const string WebSocket = "websocket.dll"; internal const string WinHttp = "winhttp.dll"; internal const string WinMM = "winmm.dll"; + internal const string Wldap32 = "wldap32.dll"; internal const string Ws2_32 = "ws2_32.dll"; internal const string Wtsapi32 = "wtsapi32.dll"; internal const string CompressionNative = "clrcompression.dll"; diff --git a/src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.NetworkInformation.cs b/src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.NetworkInformation.cs index fbc6b8020c65be..bbdb77924128b6 100644 --- a/src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.NetworkInformation.cs +++ b/src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.NetworkInformation.cs @@ -424,10 +424,9 @@ internal struct MibTcp6TableOwnerPid } [StructLayout(LayoutKind.Sequential)] - internal struct MibTcp6RowOwnerPid + internal unsafe struct MibTcp6RowOwnerPid { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - internal byte[] localAddr; + internal fixed byte localAddr[16]; internal uint localScopeId; internal byte localPort1; internal byte localPort2; @@ -435,8 +434,7 @@ internal struct MibTcp6RowOwnerPid // There are reports where the high order bytes have garbage in them. internal byte ignoreLocalPort3; internal byte ignoreLocalPort4; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - internal byte[] remoteAddr; + internal fixed byte remoteAddr[16]; internal uint remoteScopeId; internal byte remotePort1; internal byte remotePort2; @@ -446,6 +444,9 @@ internal struct MibTcp6RowOwnerPid internal byte ignoreRemotePort4; internal TcpState state; internal uint owningPid; + + internal ReadOnlySpan localAddrAsSpan => MemoryMarshal.CreateSpan(ref localAddr[0], 16); + internal ReadOnlySpan remoteAddrAsSpan => MemoryMarshal.CreateSpan(ref remoteAddr[0], 16); } internal enum TcpTableClass @@ -493,10 +494,9 @@ internal struct MibUdp6TableOwnerPid } [StructLayout(LayoutKind.Sequential)] - internal struct MibUdp6RowOwnerPid + internal unsafe struct MibUdp6RowOwnerPid { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - internal byte[] localAddr; + internal fixed byte localAddr[16]; internal uint localScopeId; internal byte localPort1; internal byte localPort2; @@ -505,6 +505,8 @@ internal struct MibUdp6RowOwnerPid internal byte ignoreLocalPort3; internal byte ignoreLocalPort4; internal uint owningPid; + + internal ReadOnlySpan localAddrAsSpan => MemoryMarshal.CreateSpan(ref localAddr[0], 16); } internal delegate void StableUnicastIpAddressTableDelegate(IntPtr context, IntPtr table); diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.EventWaitHandle.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.EventWaitHandle.cs index c3adfadb53d545..e4b0904b76ba1f 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.EventWaitHandle.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.EventWaitHandle.cs @@ -20,10 +20,10 @@ internal static partial class Kernel32 [DllImport(Libraries.Kernel32, SetLastError = true)] internal static extern bool ResetEvent(SafeWaitHandle handle); - [DllImport(Libraries.Kernel32, EntryPoint = "CreateEventExW", SetLastError = true, CharSet = CharSet.Unicode)] + [DllImport(Libraries.Kernel32, EntryPoint = "CreateEventExW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] internal static extern SafeWaitHandle CreateEventEx(IntPtr lpSecurityAttributes, string? name, uint flags, uint desiredAccess); - [DllImport(Libraries.Kernel32, EntryPoint = "OpenEventW", SetLastError = true, CharSet = CharSet.Unicode)] + [DllImport(Libraries.Kernel32, EntryPoint = "OpenEventW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] internal static extern SafeWaitHandle OpenEvent(uint desiredAccess, bool inheritHandle, string name); } } diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.ExpandEnvironmentStrings.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.ExpandEnvironmentStrings.cs index fbd5da84b8e0ac..94a3714644e121 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.ExpandEnvironmentStrings.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.ExpandEnvironmentStrings.cs @@ -8,7 +8,7 @@ internal static partial class Interop { internal static partial class Kernel32 { - [DllImport(Libraries.Kernel32, EntryPoint = "ExpandEnvironmentStringsW", CharSet = CharSet.Unicode, SetLastError = true)] + [DllImport(Libraries.Kernel32, EntryPoint = "ExpandEnvironmentStringsW", CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] internal static extern uint ExpandEnvironmentStrings(string lpSrc, ref char lpDst, uint nSize); } } diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FindFirstFileEx.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FindFirstFileEx.cs index 6ab52b4d0e9e20..a7cd35262d50d0 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FindFirstFileEx.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FindFirstFileEx.cs @@ -15,7 +15,7 @@ internal static partial class Kernel32 /// /// WARNING: This method does not implicitly handle long paths. Use FindFirstFile. /// - [DllImport(Libraries.Kernel32, EntryPoint = "FindFirstFileExW", SetLastError = true, CharSet = CharSet.Unicode)] + [DllImport(Libraries.Kernel32, EntryPoint = "FindFirstFileExW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] private static extern SafeFindHandle FindFirstFileExPrivate(string lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, ref WIN32_FIND_DATA lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, IntPtr lpSearchFilter, int dwAdditionalFlags); internal static SafeFindHandle FindFirstFile(string fileName, ref WIN32_FIND_DATA data) diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FormatMessage.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FormatMessage.cs index 2eda58f2504263..14ba39b044b9fb 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FormatMessage.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FormatMessage.cs @@ -16,7 +16,7 @@ internal static partial class Kernel32 private const int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100; private const int ERROR_INSUFFICIENT_BUFFER = 0x7A; - [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, EntryPoint = "FormatMessageW", SetLastError = true, BestFitMapping = true)] + [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, EntryPoint = "FormatMessageW", SetLastError = true, BestFitMapping = true, ExactSpelling = true)] private static extern unsafe int FormatMessage( int dwFlags, IntPtr lpSource, diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FreeEnvironmentStrings.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FreeEnvironmentStrings.cs index c222db8ef91b57..f325c281df8cf6 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FreeEnvironmentStrings.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FreeEnvironmentStrings.cs @@ -8,7 +8,7 @@ internal static partial class Interop { internal static partial class Kernel32 { - [DllImport(Libraries.Kernel32, EntryPoint = "FreeEnvironmentStringsW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)] + [DllImport(Libraries.Kernel32, EntryPoint = "FreeEnvironmentStringsW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)] internal static extern unsafe bool FreeEnvironmentStrings(char* lpszEnvironmentBlock); } } diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetComputerName.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetComputerName.cs index 011430da5c7e85..92cfb955a4cba0 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetComputerName.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetComputerName.cs @@ -10,7 +10,7 @@ internal static partial class Interop { internal static partial class Kernel32 { - [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, EntryPoint = "GetComputerNameW")] + [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, EntryPoint = "GetComputerNameW", ExactSpelling = true)] private static extern unsafe int GetComputerName(ref char lpBuffer, ref uint nSize); // maximum length of the NETBIOS name (not including NULL) diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetCurrentDirectory.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetCurrentDirectory.cs index 4e30a8be4328a1..bf283df9c40466 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetCurrentDirectory.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetCurrentDirectory.cs @@ -8,7 +8,7 @@ internal static partial class Interop { internal static partial class Kernel32 { - [DllImport(Libraries.Kernel32, EntryPoint = "GetCurrentDirectoryW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)] + [DllImport(Libraries.Kernel32, EntryPoint = "GetCurrentDirectoryW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)] internal static extern uint GetCurrentDirectory(uint nBufferLength, ref char lpBuffer); } } diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetEnvironmentStrings.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetEnvironmentStrings.cs index 5594fe7a4cb8e2..cdbd01ca502089 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetEnvironmentStrings.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetEnvironmentStrings.cs @@ -8,7 +8,7 @@ internal static partial class Interop { internal static partial class Kernel32 { - [DllImport(Libraries.Kernel32, EntryPoint = "GetEnvironmentStringsW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)] + [DllImport(Libraries.Kernel32, EntryPoint = "GetEnvironmentStringsW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)] internal static extern unsafe char* GetEnvironmentStrings(); } } diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetEnvironmentVariable.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetEnvironmentVariable.cs index 43463e52304cb0..0c14b3dd40398f 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetEnvironmentVariable.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetEnvironmentVariable.cs @@ -17,7 +17,7 @@ internal static unsafe int GetEnvironmentVariable(string lpName, Span buff } } - [DllImport(Libraries.Kernel32, EntryPoint = "GetEnvironmentVariableW", SetLastError = true, CharSet = CharSet.Unicode)] + [DllImport(Libraries.Kernel32, EntryPoint = "GetEnvironmentVariableW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] private static extern unsafe int GetEnvironmentVariable(string lpName, char* lpBuffer, int nSize); } } diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs index aed8919cd03e93..84cd7326b39fe8 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs @@ -13,7 +13,7 @@ internal static partial class Kernel32 /// /// WARNING: This method does not implicitly handle long paths. Use GetFileAttributesEx. /// - [DllImport(Libraries.Kernel32, EntryPoint = "GetFileAttributesExW", SetLastError = true, CharSet = CharSet.Unicode)] + [DllImport(Libraries.Kernel32, EntryPoint = "GetFileAttributesExW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] private static extern bool GetFileAttributesExPrivate(string? name, GET_FILEEX_INFO_LEVELS fileInfoLevel, ref WIN32_FILE_ATTRIBUTE_DATA lpFileInformation); internal static bool GetFileAttributesEx(string? name, GET_FILEEX_INFO_LEVELS fileInfoLevel, ref WIN32_FILE_ATTRIBUTE_DATA lpFileInformation) diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetSystemDirectoryW.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetSystemDirectoryW.cs index 197f6f5eadcdb6..b247a509c40d84 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetSystemDirectoryW.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetSystemDirectoryW.cs @@ -8,7 +8,7 @@ internal static partial class Interop { internal static partial class Kernel32 { - [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true)] + [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] internal static extern uint GetSystemDirectoryW(ref char lpBuffer, uint uSize); } } diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetTempFileNameW.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetTempFileNameW.cs index d7f9b828c0c035..5c3140b82ea664 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetTempFileNameW.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetTempFileNameW.cs @@ -8,7 +8,7 @@ internal static partial class Interop { internal static partial class Kernel32 { - [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)] + [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false, ExactSpelling = true)] internal static extern uint GetTempFileNameW(ref char lpPathName, string lpPrefixString, uint uUnique, ref char lpTempFileName); } } diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetTempPathW.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetTempPathW.cs index 8d2b0b199edd00..654a3b57011cd2 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetTempPathW.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetTempPathW.cs @@ -8,7 +8,7 @@ internal static partial class Interop { internal static partial class Kernel32 { - [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, BestFitMapping = false)] + [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)] internal static extern uint GetTempPathW(int bufferLen, ref char buffer); } } diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Globalization.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Globalization.cs index 608073d36b0504..2aa2d6a1787df2 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Globalization.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Globalization.cs @@ -53,7 +53,7 @@ internal static unsafe partial class Kernel32 [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] internal static extern int LocaleNameToLCID(string lpName, uint dwFlags); - [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] internal static extern int LCMapStringEx( string? lpLocaleName, uint dwMapFlags, diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.LoadLibraryEx_IntPtr.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.LoadLibraryEx_IntPtr.cs index a77cf49179382b..3e3d1d34a81a70 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.LoadLibraryEx_IntPtr.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.LoadLibraryEx_IntPtr.cs @@ -12,7 +12,7 @@ internal static partial class Kernel32 internal const int LOAD_LIBRARY_AS_DATAFILE = 0x00000002; internal const int LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800; - [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, EntryPoint = "LoadLibraryExW", SetLastError = true)] + [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, EntryPoint = "LoadLibraryExW", SetLastError = true, ExactSpelling = true)] internal static extern IntPtr LoadLibraryEx(string libFilename, IntPtr reserved, int flags); } } diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Mutex.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Mutex.cs index 6adaf987370406..ad1d649fe9da88 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Mutex.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Mutex.cs @@ -13,10 +13,10 @@ internal static partial class Kernel32 { internal const uint CREATE_MUTEX_INITIAL_OWNER = 0x1; - [DllImport(Libraries.Kernel32, EntryPoint = "OpenMutexW", SetLastError = true, CharSet = CharSet.Unicode)] + [DllImport(Libraries.Kernel32, EntryPoint = "OpenMutexW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] internal static extern SafeWaitHandle OpenMutex(uint desiredAccess, bool inheritHandle, string name); - [DllImport(Libraries.Kernel32, EntryPoint = "CreateMutexExW", SetLastError = true, CharSet = CharSet.Unicode)] + [DllImport(Libraries.Kernel32, EntryPoint = "CreateMutexExW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] internal static extern SafeWaitHandle CreateMutexEx(IntPtr lpMutexAttributes, string? name, uint flags, uint desiredAccess); [DllImport(Libraries.Kernel32, SetLastError = true)] diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Semaphore.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Semaphore.cs index 4f6d8de8768a34..c83db1f934c003 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Semaphore.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.Semaphore.cs @@ -11,10 +11,10 @@ internal static partial class Interop { internal static partial class Kernel32 { - [DllImport(Libraries.Kernel32, EntryPoint = "OpenSemaphoreW", SetLastError = true, CharSet = CharSet.Unicode)] + [DllImport(Libraries.Kernel32, EntryPoint = "OpenSemaphoreW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] internal static extern SafeWaitHandle OpenSemaphore(uint desiredAccess, bool inheritHandle, string name); - [DllImport(Libraries.Kernel32, EntryPoint = "CreateSemaphoreExW", SetLastError = true, CharSet = CharSet.Unicode)] + [DllImport(Libraries.Kernel32, EntryPoint = "CreateSemaphoreExW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] internal static extern SafeWaitHandle CreateSemaphoreEx(IntPtr lpSecurityAttributes, int initialCount, int maximumCount, string? name, uint flags, uint desiredAccess); [DllImport(Libraries.Kernel32, SetLastError = true)] diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetCurrentDirectory.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetCurrentDirectory.cs index d268d4daa6f774..17360399a7c0d6 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetCurrentDirectory.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetCurrentDirectory.cs @@ -8,7 +8,7 @@ internal static partial class Interop { internal static partial class Kernel32 { - [DllImport(Libraries.Kernel32, EntryPoint = "SetCurrentDirectoryW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)] + [DllImport(Libraries.Kernel32, EntryPoint = "SetCurrentDirectoryW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)] internal static extern bool SetCurrentDirectory(string path); } } diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetEnvironmentVariable.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetEnvironmentVariable.cs index 243bd6562e0341..ab3a6d34cd42b4 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetEnvironmentVariable.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.SetEnvironmentVariable.cs @@ -8,7 +8,7 @@ internal static partial class Interop { internal static partial class Kernel32 { - [DllImport(Libraries.Kernel32, EntryPoint = "SetEnvironmentVariableW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)] + [DllImport(Libraries.Kernel32, EntryPoint = "SetEnvironmentVariableW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)] internal static extern bool SetEnvironmentVariable(string lpName, string? lpValue); } } diff --git a/src/libraries/Common/src/Interop/Windows/Secur32/Interop.GetUserNameExW.cs b/src/libraries/Common/src/Interop/Windows/Secur32/Interop.GetUserNameExW.cs index e88864cd9e7470..7001cd6df09ea1 100644 --- a/src/libraries/Common/src/Interop/Windows/Secur32/Interop.GetUserNameExW.cs +++ b/src/libraries/Common/src/Interop/Windows/Secur32/Interop.GetUserNameExW.cs @@ -8,7 +8,7 @@ internal static partial class Interop { internal static partial class Secur32 { - [DllImport(Libraries.Secur32, CharSet = CharSet.Unicode, SetLastError = true)] + [DllImport(Libraries.Secur32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] internal static extern BOOLEAN GetUserNameExW(int NameFormat, ref char lpNameBuffer, ref uint lpnSize); internal const int NameSamCompatible = 2; diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.LoadString.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.LoadString.cs index 6ff50442eb4288..8824f7c3dfa024 100644 --- a/src/libraries/Common/src/Interop/Windows/User32/Interop.LoadString.cs +++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.LoadString.cs @@ -9,7 +9,7 @@ internal static partial class Interop { internal static partial class User32 { - [DllImport(Libraries.User32, SetLastError = true, EntryPoint = "LoadStringW", CharSet = CharSet.Unicode)] + [DllImport(Libraries.User32, SetLastError = true, EntryPoint = "LoadStringW", CharSet = CharSet.Unicode, ExactSpelling = true)] internal static extern unsafe int LoadString(IntPtr hInstance, uint uID, char* lpBuffer, int cchBufferMax); } } diff --git a/src/libraries/Common/src/Interop/Windows/WinSock/Interop.getpeername.cs b/src/libraries/Common/src/Interop/Windows/WinSock/Interop.getpeername.cs index c0e2592416e050..72f816834e45eb 100644 --- a/src/libraries/Common/src/Interop/Windows/WinSock/Interop.getpeername.cs +++ b/src/libraries/Common/src/Interop/Windows/WinSock/Interop.getpeername.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Runtime.InteropServices; using System.Net.Sockets; @@ -10,9 +11,9 @@ internal static partial class Interop internal static partial class Winsock { [DllImport(Interop.Libraries.Ws2_32, SetLastError = true)] - internal static extern SocketError getpeername( + internal static extern unsafe SocketError getpeername( [In] SafeSocketHandle socketHandle, - [Out] byte[] socketAddress, + [Out] byte* socketAddress, [In, Out] ref int socketAddressSize); } } diff --git a/src/libraries/Common/src/Interop/Windows/Wldap32/Interop.Ber.cs b/src/libraries/Common/src/Interop/Windows/Wldap32/Interop.Ber.cs new file mode 100644 index 00000000000000..5f87ea57938b07 --- /dev/null +++ b/src/libraries/Common/src/Interop/Windows/Wldap32/Interop.Ber.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.DirectoryServices.Protocols; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_free", CharSet = CharSet.Unicode)] + public static extern IntPtr ber_free([In] IntPtr berelement, int option); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_alloc_t", CharSet = CharSet.Unicode)] + public static extern IntPtr ber_alloc(int option); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_printf", CharSet = CharSet.Unicode)] + public static extern int ber_printf_emptyarg(SafeBerHandle berElement, string format); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_printf", CharSet = CharSet.Unicode)] + public static extern int ber_printf_int(SafeBerHandle berElement, string format, int value); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_printf", CharSet = CharSet.Unicode)] + public static extern int ber_printf_bytearray(SafeBerHandle berElement, string format, HGlobalMemHandle value, int length); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_printf", CharSet = CharSet.Unicode)] + public static extern int ber_printf_berarray(SafeBerHandle berElement, string format, IntPtr value); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_flatten", CharSet = CharSet.Unicode)] + public static extern int ber_flatten(SafeBerHandle berElement, ref IntPtr value); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_init", CharSet = CharSet.Unicode)] + public static extern IntPtr ber_init(berval value); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)] + public static extern int ber_scanf(SafeBerHandle berElement, string format); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)] + public static extern int ber_scanf_int(SafeBerHandle berElement, string format, ref int value); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)] + public static extern int ber_scanf_ptr(SafeBerHandle berElement, string format, ref IntPtr value); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)] + public static extern int ber_scanf_bitstring(SafeBerHandle berElement, string format, ref IntPtr value, ref int bitLength); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_bvfree", CharSet = CharSet.Unicode)] + public static extern int ber_bvfree(IntPtr value); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_bvecfree", CharSet = CharSet.Unicode)] + public static extern int ber_bvecfree(IntPtr value); +} diff --git a/src/libraries/Common/src/Interop/Windows/Wldap32/Interop.Ldap.cs b/src/libraries/Common/src/Interop/Windows/Wldap32/Interop.Ldap.cs new file mode 100644 index 00000000000000..a73cd89996e2dd --- /dev/null +++ b/src/libraries/Common/src/Interop/Windows/Wldap32/Interop.Ldap.cs @@ -0,0 +1,154 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.DirectoryServices.Protocols; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_bind_sW", CharSet = CharSet.Unicode)] + public static extern int ldap_bind_s([In]ConnectionHandle ldapHandle, string dn, SEC_WINNT_AUTH_IDENTITY_EX credentials, BindMethod method); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_initW", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr ldap_init(string hostName, int portNumber); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, EntryPoint = "ldap_connect", CharSet = CharSet.Unicode)] + public static extern int ldap_connect([In] ConnectionHandle ldapHandle, LDAP_TIMEVAL timeout); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, EntryPoint = "ldap_unbind", CharSet = CharSet.Unicode)] + public static extern int ldap_unbind([In] IntPtr ldapHandle); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_get_optionW", CharSet = CharSet.Unicode)] + public static extern int ldap_get_option_int([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref int outValue); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_set_optionW", CharSet = CharSet.Unicode)] + public static extern int ldap_set_option_int([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref int inValue); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_get_optionW", CharSet = CharSet.Unicode)] + public static extern int ldap_get_option_ptr([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref IntPtr outValue); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_set_optionW", CharSet = CharSet.Unicode)] + public static extern int ldap_set_option_ptr([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref IntPtr inValue); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_get_optionW", CharSet = CharSet.Unicode)] + public static extern int ldap_get_option_sechandle([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref SecurityHandle outValue); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_get_optionW", CharSet = CharSet.Unicode)] + public static extern int ldap_get_option_secInfo([In] ConnectionHandle ldapHandle, [In] LdapOption option, [In, Out] SecurityPackageContextConnectionInformation outValue); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_set_optionW", CharSet = CharSet.Unicode)] + public static extern int ldap_set_option_referral([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref LdapReferralCallback outValue); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_set_optionW", CharSet = CharSet.Unicode)] + public static extern int ldap_set_option_clientcert([In] ConnectionHandle ldapHandle, [In] LdapOption option, QUERYCLIENTCERT outValue); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_set_optionW", CharSet = CharSet.Unicode)] + public static extern int ldap_set_option_servercert([In] ConnectionHandle ldapHandle, [In] LdapOption option, VERIFYSERVERCERT outValue); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "LdapGetLastError")] + public static extern int LdapGetLastError(); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "cldap_openW", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr cldap_open(string hostName, int portNumber); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_simple_bind_sW", CharSet = CharSet.Unicode)] + public static extern int ldap_simple_bind_s([In] ConnectionHandle ldapHandle, string distinguishedName, string password); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_delete_extW", CharSet = CharSet.Unicode)] + public static extern int ldap_delete_ext([In] ConnectionHandle ldapHandle, string dn, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_result", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern int ldap_result([In] ConnectionHandle ldapHandle, int messageId, int all, LDAP_TIMEVAL timeout, ref IntPtr Mesage); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_parse_resultW", CharSet = CharSet.Unicode)] + public static extern int ldap_parse_result([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref int serverError, ref IntPtr dn, ref IntPtr message, ref IntPtr referral, ref IntPtr control, byte freeIt); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_parse_resultW", CharSet = CharSet.Unicode)] + public static extern int ldap_parse_result_referral([In] ConnectionHandle ldapHandle, [In] IntPtr result, IntPtr serverError, IntPtr dn, IntPtr message, ref IntPtr referral, IntPtr control, byte freeIt); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_memfreeW", CharSet = CharSet.Unicode)] + public static extern void ldap_memfree([In] IntPtr value); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_value_freeW", CharSet = CharSet.Unicode)] + public static extern int ldap_value_free([In] IntPtr value); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_controls_freeW", CharSet = CharSet.Unicode)] + public static extern int ldap_controls_free([In] IntPtr value); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_abandon", CharSet = CharSet.Unicode)] + public static extern int ldap_abandon([In] ConnectionHandle ldapHandle, [In] int messagId); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_start_tls_sW", CharSet = CharSet.Unicode)] + public static extern int ldap_start_tls(ConnectionHandle ldapHandle, ref int ServerReturnValue, ref IntPtr Message, IntPtr ServerControls, IntPtr ClientControls); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_stop_tls_s", CharSet = CharSet.Unicode)] + public static extern byte ldap_stop_tls(ConnectionHandle ldapHandle); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_rename_extW", CharSet = CharSet.Unicode)] + public static extern int ldap_rename([In] ConnectionHandle ldapHandle, string dn, string newRdn, string newParentDn, int deleteOldRdn, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_compare_extW", CharSet = CharSet.Unicode)] + public static extern int ldap_compare([In] ConnectionHandle ldapHandle, string dn, string attributeName, string strValue, berval binaryValue, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_add_extW", CharSet = CharSet.Unicode)] + public static extern int ldap_add([In] ConnectionHandle ldapHandle, string dn, IntPtr attrs, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_modify_extW", CharSet = CharSet.Unicode)] + public static extern int ldap_modify([In] ConnectionHandle ldapHandle, string dn, IntPtr attrs, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_extended_operationW", CharSet = CharSet.Unicode)] + public static extern int ldap_extended_operation([In] ConnectionHandle ldapHandle, string oid, berval data, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_parse_extended_resultW", CharSet = CharSet.Unicode)] + public static extern int ldap_parse_extended_result([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref IntPtr oid, ref IntPtr data, byte freeIt); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_msgfree", CharSet = CharSet.Unicode)] + public static extern int ldap_msgfree([In] IntPtr result); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_search_extW", CharSet = CharSet.Unicode)] + public static extern int ldap_search([In] ConnectionHandle ldapHandle, string dn, int scope, string filter, IntPtr attributes, bool attributeOnly, IntPtr servercontrol, IntPtr clientcontrol, int timelimit, int sizelimit, ref int messageNumber); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_first_entry", CharSet = CharSet.Unicode)] + public static extern IntPtr ldap_first_entry([In] ConnectionHandle ldapHandle, [In] IntPtr result); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_next_entry", CharSet = CharSet.Unicode)] + public static extern IntPtr ldap_next_entry([In] ConnectionHandle ldapHandle, [In] IntPtr result); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_first_reference", CharSet = CharSet.Unicode)] + public static extern IntPtr ldap_first_reference([In] ConnectionHandle ldapHandle, [In] IntPtr result); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_next_reference", CharSet = CharSet.Unicode)] + public static extern IntPtr ldap_next_reference([In] ConnectionHandle ldapHandle, [In] IntPtr result); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_get_dnW", CharSet = CharSet.Unicode)] + public static extern IntPtr ldap_get_dn([In] ConnectionHandle ldapHandle, [In] IntPtr result); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_first_attributeW", CharSet = CharSet.Unicode)] + public static extern IntPtr ldap_first_attribute([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref IntPtr address); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_next_attributeW", CharSet = CharSet.Unicode)] + public static extern IntPtr ldap_next_attribute([In] ConnectionHandle ldapHandle, [In] IntPtr result, [In, Out] IntPtr address); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_get_values_lenW", CharSet = CharSet.Unicode)] + public static extern IntPtr ldap_get_values_len([In] ConnectionHandle ldapHandle, [In] IntPtr result, string name); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_value_free_len", CharSet = CharSet.Unicode)] + public static extern IntPtr ldap_value_free_len([In] IntPtr berelement); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_parse_referenceW", CharSet = CharSet.Unicode)] + public static extern int ldap_parse_reference([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref IntPtr referrals); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_create_sort_controlW", CharSet = CharSet.Unicode)] + public static extern int ldap_create_sort_control(ConnectionHandle handle, IntPtr keys, byte critical, ref IntPtr control); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_control_freeW", CharSet = CharSet.Unicode)] + public static extern int ldap_control_free(IntPtr control); + + [DllImport("Crypt32.dll", EntryPoint = "CertFreeCRLContext", CharSet = CharSet.Unicode)] + public static extern int CertFreeCRLContext(IntPtr certContext); + + [DllImport(Libraries.Wldap32, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_result2error", CharSet = CharSet.Unicode)] + public static extern int ldap_result2error([In] ConnectionHandle ldapHandle, [In] IntPtr result, int freeIt); +} diff --git a/src/libraries/Common/src/System/Buffers/ArrayBufferWriter.cs b/src/libraries/Common/src/System/Buffers/ArrayBufferWriter.cs index 71b23e1f7cd3f7..a7b047119d5d5f 100644 --- a/src/libraries/Common/src/System/Buffers/ArrayBufferWriter.cs +++ b/src/libraries/Common/src/System/Buffers/ArrayBufferWriter.cs @@ -42,7 +42,7 @@ public ArrayBufferWriter() public ArrayBufferWriter(int initialCapacity) { if (initialCapacity <= 0) - throw new ArgumentException(nameof(initialCapacity)); + throw new ArgumentException(null, nameof(initialCapacity)); _buffer = new T[initialCapacity]; _index = 0; @@ -101,7 +101,7 @@ public void Clear() public void Advance(int count) { if (count < 0) - throw new ArgumentException(nameof(count)); + throw new ArgumentException(null, nameof(count)); if (_index > _buffer.Length - count) ThrowInvalidOperationException_AdvancedTooFar(_buffer.Length); diff --git a/src/libraries/Common/src/System/Collections/Generic/BidirectionalDictionary.cs b/src/libraries/Common/src/System/Collections/Generic/BidirectionalDictionary.cs index 6b5923d8f46dc5..5e3dec7e8268d3 100644 --- a/src/libraries/Common/src/System/Collections/Generic/BidirectionalDictionary.cs +++ b/src/libraries/Common/src/System/Collections/Generic/BidirectionalDictionary.cs @@ -4,6 +4,7 @@ #nullable enable using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Collections.Generic { @@ -36,12 +37,12 @@ public void Add(T1 item1, T2 item2) _backward.Add(item2, item1); } - public bool TryGetForward(T1 item1, out T2 item2) + public bool TryGetForward(T1 item1, [MaybeNullWhen(false)] out T2 item2) { return _forward.TryGetValue(item1, out item2); } - public bool TryGetBackward(T2 item2, out T1 item1) + public bool TryGetBackward(T2 item2, [MaybeNullWhen(false)] out T1 item1) { return _backward.TryGetValue(item2, out item1); } diff --git a/src/libraries/Common/src/System/IO/FileSystem.Attributes.Windows.cs b/src/libraries/Common/src/System/IO/FileSystem.Attributes.Windows.cs index 977293e3fe89d5..274f049f58471a 100644 --- a/src/libraries/Common/src/System/IO/FileSystem.Attributes.Windows.cs +++ b/src/libraries/Common/src/System/IO/FileSystem.Attributes.Windows.cs @@ -81,7 +81,7 @@ internal static int FillAttributeInfo(string? path, ref Interop.Kernel32.WIN32_F ) { // Assert so we can track down other cases (if any) to add to our test suite - Debug.Assert(errorCode == Interop.Errors.ERROR_ACCESS_DENIED || errorCode == Interop.Errors.ERROR_SHARING_VIOLATION, + Debug.Assert(errorCode == Interop.Errors.ERROR_ACCESS_DENIED || errorCode == Interop.Errors.ERROR_SHARING_VIOLATION || errorCode == Interop.Errors.ERROR_SEM_TIMEOUT, $"Unexpected error code getting attributes {errorCode} from path {path}"); // Files that are marked for deletion will not let you GetFileAttributes, diff --git a/src/libraries/Common/src/System/Net/ArrayBuffer.cs b/src/libraries/Common/src/System/Net/ArrayBuffer.cs index ca1a1c4066e505..fc0bbeb099bfde 100644 --- a/src/libraries/Common/src/System/Net/ArrayBuffer.cs +++ b/src/libraries/Common/src/System/Net/ArrayBuffer.cs @@ -50,7 +50,7 @@ public void Dispose() if (array != null) { - ArrayPool.Shared.Return(array, true); + ArrayPool.Shared.Return(array); } } } diff --git a/src/libraries/Common/src/System/Net/DebugCriticalHandleMinusOneIsInvalid.cs b/src/libraries/Common/src/System/Net/DebugCriticalHandleMinusOneIsInvalid.cs index 38c3a40d64884c..eed8ccb978a81b 100644 --- a/src/libraries/Common/src/System/Net/DebugCriticalHandleMinusOneIsInvalid.cs +++ b/src/libraries/Common/src/System/Net/DebugCriticalHandleMinusOneIsInvalid.cs @@ -33,7 +33,6 @@ private void Trace() ~DebugCriticalHandleMinusOneIsInvalid() { - DebugThreadTracking.SetThreadSource(ThreadKinds.Finalization); if (NetEventSource.IsEnabled) NetEventSource.Info(this, _trace); } } diff --git a/src/libraries/Common/src/System/Net/DebugCriticalHandleZeroOrMinusOneIsInvalid.cs b/src/libraries/Common/src/System/Net/DebugCriticalHandleZeroOrMinusOneIsInvalid.cs index 33bca4dee3f706..0d993cd60d738c 100644 --- a/src/libraries/Common/src/System/Net/DebugCriticalHandleZeroOrMinusOneIsInvalid.cs +++ b/src/libraries/Common/src/System/Net/DebugCriticalHandleZeroOrMinusOneIsInvalid.cs @@ -33,7 +33,6 @@ private void Trace() ~DebugCriticalHandleZeroOrMinusOneIsInvalid() { - DebugThreadTracking.SetThreadSource(ThreadKinds.Finalization); if (NetEventSource.IsEnabled) NetEventSource.Info(this, _trace); } } diff --git a/src/libraries/Common/src/System/Net/DebugSafeHandleMinusOneIsInvalid.cs b/src/libraries/Common/src/System/Net/DebugSafeHandleMinusOneIsInvalid.cs index 5cf3352115cdd4..4fd2c5b4e9850f 100644 --- a/src/libraries/Common/src/System/Net/DebugSafeHandleMinusOneIsInvalid.cs +++ b/src/libraries/Common/src/System/Net/DebugSafeHandleMinusOneIsInvalid.cs @@ -33,7 +33,6 @@ private void Trace() ~DebugSafeHandleMinusOneIsInvalid() { - DebugThreadTracking.SetThreadSource(ThreadKinds.Finalization); if (NetEventSource.IsEnabled) NetEventSource.Info(this, _trace); } } diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs index 0b9893333d7156..dd42af8ff61423 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/Quic/Implementations/MsQuic/Internal/MsQuicApi.cs @@ -142,8 +142,6 @@ static MsQuicApi() // - Otherwise, dial this in to reflect actual minimum requirements and add some sort of platform // error code mapping when creating exceptions. - OperatingSystem ver = Environment.OSVersion; - // TODO: try to initialize TLS 1.3 in SslStream. try diff --git a/src/libraries/Common/src/System/Net/Internals/IPEndPointExtensions.cs b/src/libraries/Common/src/System/Net/Internals/IPEndPointExtensions.cs index 89becdde08ba5a..2e261809bff34f 100644 --- a/src/libraries/Common/src/System/Net/Internals/IPEndPointExtensions.cs +++ b/src/libraries/Common/src/System/Net/Internals/IPEndPointExtensions.cs @@ -39,6 +39,10 @@ public static EndPoint Create(this EndPoint thisObj, Internals.SocketAddress soc return socketAddress.GetIPEndPoint(); } + else if (family == AddressFamily.Unknown) + { + return thisObj; + } System.Net.SocketAddress address = GetNetSocketAddress(socketAddress); return thisObj.Create(address); diff --git a/src/libraries/Common/src/System/Net/Logging/DebugThreadTracking.cs b/src/libraries/Common/src/System/Net/Logging/DebugThreadTracking.cs deleted file mode 100644 index eba97da8e3b20e..00000000000000 --- a/src/libraries/Common/src/System/Net/Logging/DebugThreadTracking.cs +++ /dev/null @@ -1,158 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable enable -using System.Collections.Generic; - -namespace System.Net -{ - internal static class DebugThreadTracking - { - [ThreadStatic] - private static Stack? t_threadKindStack; - - private static Stack ThreadKindStack => t_threadKindStack ?? (t_threadKindStack = new Stack()); - - internal static ThreadKinds CurrentThreadKind => ThreadKindStack.Count > 0 ? ThreadKindStack.Peek() : ThreadKinds.Other; - - internal static IDisposable? SetThreadKind(ThreadKinds kind) - { - if ((kind & ThreadKinds.SourceMask) != ThreadKinds.Unknown) - { - throw new InternalException(kind); - } - - // Ignore during shutdown. - if (Environment.HasShutdownStarted) - { - return null; - } - - ThreadKinds threadKind = CurrentThreadKind; - ThreadKinds source = threadKind & ThreadKinds.SourceMask; - - // Special warnings when doing dangerous things on a thread. - if ((threadKind & ThreadKinds.User) != 0 && (kind & ThreadKinds.System) != 0) - { - if (NetEventSource.IsEnabled) NetEventSource.Error(null, "Thread changed from User to System; user's thread shouldn't be hijacked."); - } - - if ((threadKind & ThreadKinds.Async) != 0 && (kind & ThreadKinds.Sync) != 0) - { - if (NetEventSource.IsEnabled) NetEventSource.Error(null, "Thread changed from Async to Sync, may block an Async thread."); - } - else if ((threadKind & (ThreadKinds.Other | ThreadKinds.CompletionPort)) == 0 && (kind & ThreadKinds.Sync) != 0) - { - if (NetEventSource.IsEnabled) NetEventSource.Error(null, "Thread from a limited resource changed to Sync, may deadlock or bottleneck."); - } - - ThreadKindStack.Push( - (((kind & ThreadKinds.OwnerMask) == 0 ? threadKind : kind) & ThreadKinds.OwnerMask) | - (((kind & ThreadKinds.SyncMask) == 0 ? threadKind : kind) & ThreadKinds.SyncMask) | - (kind & ~(ThreadKinds.OwnerMask | ThreadKinds.SyncMask)) | - source); - - if (CurrentThreadKind != threadKind) - { - if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"Thread becomes:({CurrentThreadKind})"); - } - - return new ThreadKindFrame(); - } - - private class ThreadKindFrame : IDisposable - { - private readonly int _frameNumber; - - internal ThreadKindFrame() - { - _frameNumber = ThreadKindStack.Count; - } - - void IDisposable.Dispose() - { - // Ignore during shutdown. - if (Environment.HasShutdownStarted) - { - return; - } - - if (_frameNumber != ThreadKindStack.Count) - { - throw new InternalException(_frameNumber); - } - - ThreadKinds previous = ThreadKindStack.Pop(); - - if (CurrentThreadKind != previous && NetEventSource.IsEnabled) - { - if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Thread reverts:({CurrentThreadKind})"); - } - } - } - - internal static void SetThreadSource(ThreadKinds source) - { - if ((source & ThreadKinds.SourceMask) != source || source == ThreadKinds.Unknown) - { - throw new ArgumentException("Must specify the thread source.", nameof(source)); - } - - if (ThreadKindStack.Count == 0) - { - ThreadKindStack.Push(source); - return; - } - - if (ThreadKindStack.Count > 1) - { - if (NetEventSource.IsEnabled) NetEventSource.Error(null, "SetThreadSource must be called at the base of the stack, or the stack has been corrupted."); - while (ThreadKindStack.Count > 1) - { - ThreadKindStack.Pop(); - } - } - - if (ThreadKindStack.Peek() != source) - { - if (NetEventSource.IsEnabled) NetEventSource.Error(null, "The stack has been corrupted."); - ThreadKinds last = ThreadKindStack.Pop() & ThreadKinds.SourceMask; - if (last != source && last != ThreadKinds.Other && NetEventSource.IsEnabled) - { - NetEventSource.Fail(null, $"Thread source changed.|Was:({last}) Now:({source})"); - } - ThreadKindStack.Push(source); - } - } - } - - [Flags] - internal enum ThreadKinds - { - Unknown = 0x0000, - - // Mutually exclusive. - User = 0x0001, // Thread has entered via an API. - System = 0x0002, // Thread has entered via a system callback (e.g. completion port) or is our own thread. - - // Mutually exclusive. - Sync = 0x0004, // Thread should block. - Async = 0x0008, // Thread should not block. - - // Mutually exclusive, not always known for a user thread. Never changes. - Timer = 0x0010, // Thread is the timer thread. (Can't call user code.) - CompletionPort = 0x0020, // Thread is a ThreadPool completion-port thread. - Worker = 0x0040, // Thread is a ThreadPool worker thread. - Finalization = 0x0080, // Thread is the finalization thread. - Other = 0x0100, // Unknown source. - - OwnerMask = User | System, - SyncMask = Sync | Async, - SourceMask = Timer | CompletionPort | Worker | Finalization | Other, - - // Useful "macros" - SafeSources = SourceMask & ~(Timer | Finalization), // Methods that "unsafe" sources can call must be explicitly marked. - ThreadPool = CompletionPort | Worker, // Like Thread.CurrentThread.IsThreadPoolThread - } -} diff --git a/src/libraries/Common/src/System/Net/Mail/MailBnfHelper.cs b/src/libraries/Common/src/System/Net/Mail/MailBnfHelper.cs index 5f72eaf1bafa1c..494eaea415eb2a 100644 --- a/src/libraries/Common/src/System/Net/Mail/MailBnfHelper.cs +++ b/src/libraries/Common/src/System/Net/Mail/MailBnfHelper.cs @@ -45,8 +45,6 @@ internal static class MailBnfHelper internal const char Comma = ','; internal const char Dot = '.'; - private static readonly char[] s_colonSeparator = new char[] { ':' }; - // NOTE: See RFC 2822 for more detail. By default, every value in the array is false and only // those values which are allowed in that particular set are then set to true. The numbers // annotating each definition below are the range of ASCII values which are allowed in that definition. @@ -317,7 +315,7 @@ internal static string ReadToken(string data, ref int offset, StringBuilder? bui localBuilder.Append(' '); } - string[] offsetFields = offset.Split(s_colonSeparator); + string[] offsetFields = offset.Split(':'); localBuilder.Append(offsetFields[0]); localBuilder.Append(offsetFields[1]); return (builder != null ? null : localBuilder.ToString()); diff --git a/src/libraries/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs b/src/libraries/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs index 157986f7bf649b..a4d3143a83cfa0 100644 --- a/src/libraries/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs +++ b/src/libraries/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs @@ -19,7 +19,8 @@ internal static class UnixCommandLinePing private static readonly string? s_discoveredPing4UtilityPath = GetPingUtilityPath(ipv4: true); private static readonly string? s_discoveredPing6UtilityPath = GetPingUtilityPath(ipv4: false); - private static readonly bool s_isBSD = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Create("FREEBSD")); + private static readonly bool s_isOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + private static readonly bool s_isBSD = RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD); private static readonly Lazy s_isBusybox = new Lazy(() => IsBusyboxPing(s_discoveredPing4UtilityPath)); // We don't want to pick up an arbitrary or malicious ping @@ -72,14 +73,59 @@ public enum PingFragmentOptions { Default, Do, Dont }; /// Constructs command line arguments appropriate for the ping or ping6 utility. /// /// The packet size to use in the ping. Exact packet payload cannot be specified. + /// The timeout to use in the ping, in milliseconds. /// A string representation of the IP address to ping. /// The constructed command line arguments, which can be passed to ping or ping6. - public static string ConstructCommandLine(int packetSize, string address, bool ipv4, int ttl = 0, PingFragmentOptions fragmentOption = PingFragmentOptions.Default) + public static string ConstructCommandLine(int packetSize, int timeout, string address, bool ipv4, int ttl = 0, PingFragmentOptions fragmentOption = PingFragmentOptions.Default) { - - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); sb.Append("-c 1"); // Just send a single ping ("count = 1") + //if timeout is zero then some ping implementations can stuck infinitely if endpoint is unreachable + if (timeout == 0) + timeout = 1; + + // Pass timeout argument to ping utility + // BusyBox, Linux: ping and ping6 requires -W flag which accepts timeout in SECONDS. + // FreeBSD: ping requires -W flag which accepts timeout in MILLISECONDS; + // ping6 requires -x which accepts timeout in MILLISECONDS + // OSX: ping requires -W flag which accepts timeout in MILLISECONDS; ping6 doesn't support timeout + if (s_isBSD) + { + if (ipv4) + { + sb.Append(" -W "); + } + else + { + sb.Append(" -x "); + } + } + else if (s_isOSX) + { + if (ipv4) + { + sb.Append(" -W "); + } + else + { + goto skipped_timeout; + } + } + else + { + sb.Append(" -W "); + const int millisInSecond = 1000; + timeout = Math.DivRem(timeout, millisInSecond, out int remainder); + if (remainder != 0) + { + timeout += 1; + } + } + sb.Append(timeout); + + skipped_timeout: + // The command-line flags for "Do-not-fragment" and "TTL" are not standard. // In fact, they are different even between ping and ping6 on the same machine. @@ -88,7 +134,7 @@ public static string ConstructCommandLine(int packetSize, string address, bool i if (ttl > 0) { - if (s_isBSD) + if (s_isBSD | s_isOSX) { // OSX and FreeBSD use -h to set hop limit for IPv6 and -m ttl for IPv4 if (ipv4) @@ -109,9 +155,9 @@ public static string ConstructCommandLine(int packetSize, string address, bool i sb.Append(ttl); } - if (fragmentOption != PingFragmentOptions.Default ) + if (fragmentOption != PingFragmentOptions.Default) { - if (s_isBSD) + if (s_isBSD | s_isOSX) { // The bit is off by default on OSX & FreeBSD if (fragmentOption == PingFragmentOptions.Dont) { diff --git a/src/libraries/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs b/src/libraries/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs index 21edf856505443..8ba6978f874b7d 100644 --- a/src/libraries/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs +++ b/src/libraries/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs @@ -43,19 +43,13 @@ internal static string QueryContextAuthenticationPackage(SafeDeleteContext secur private static byte[] GssWrap( SafeGssContextHandle? context, bool encrypt, - byte[] buffer, - int offset, - int count) + ReadOnlySpan buffer) { - Debug.Assert((buffer != null) && (buffer.Length > 0), "Invalid input buffer passed to Encrypt"); - Debug.Assert((offset >= 0) && (offset < buffer.Length), "Invalid input offset passed to Encrypt"); - Debug.Assert((count >= 0) && (count <= (buffer.Length - offset)), "Invalid input count passed to Encrypt"); - - Interop.NetSecurityNative.GssBuffer encryptedBuffer = default(Interop.NetSecurityNative.GssBuffer); + Interop.NetSecurityNative.GssBuffer encryptedBuffer = default; try { Interop.NetSecurityNative.Status minorStatus; - Interop.NetSecurityNative.Status status = Interop.NetSecurityNative.WrapBuffer(out minorStatus, context, encrypt, buffer, offset, count, ref encryptedBuffer); + Interop.NetSecurityNative.Status status = Interop.NetSecurityNative.WrapBuffer(out minorStatus, context, encrypt, buffer, ref encryptedBuffer); if (status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE) { throw new Interop.NetSecurityNative.GssApiException(status, minorStatus); @@ -555,16 +549,14 @@ internal static SecurityStatusPal CompleteAuthToken( internal static int Encrypt( SafeDeleteContext securityContext, - byte[] buffer, - int offset, - int count, + ReadOnlySpan buffer, bool isConfidential, bool isNtlm, - ref byte[]? output, + [NotNull] ref byte[]? output, uint sequenceNumber) { SafeDeleteNegoContext gssContext = (SafeDeleteNegoContext) securityContext; - byte[] tempOutput = GssWrap(gssContext.GssContext, isConfidential, buffer, offset, count); + byte[] tempOutput = GssWrap(gssContext.GssContext, isConfidential, buffer); // Create space for prefixing with the length const int prefixLength = 4; @@ -628,7 +620,7 @@ internal static int VerifySignature(SafeDeleteContext securityContext, byte[] bu internal static int MakeSignature(SafeDeleteContext securityContext, byte[] buffer, int offset, int count, [AllowNull] ref byte[] output) { SafeDeleteNegoContext gssContext = (SafeDeleteNegoContext)securityContext; - byte[] tempOutput = GssWrap(gssContext.GssContext, false, buffer, offset, count); + byte[] tempOutput = GssWrap(gssContext.GssContext, false, new ReadOnlySpan(buffer, offset, count)); // Create space for prefixing with the length const int prefixLength = 4; output = new byte[tempOutput.Length + prefixLength]; diff --git a/src/libraries/Common/src/System/Net/SocketAddressPal.Unix.cs b/src/libraries/Common/src/System/Net/SocketAddressPal.Unix.cs index c28b62ce70ba8a..f3e198f5031227 100644 --- a/src/libraries/Common/src/System/Net/SocketAddressPal.Unix.cs +++ b/src/libraries/Common/src/System/Net/SocketAddressPal.Unix.cs @@ -68,12 +68,16 @@ public static unsafe AddressFamily GetAddressFamily(ReadOnlySpan buffer) public static unsafe void SetAddressFamily(byte[] buffer, AddressFamily family) { Interop.Error err; - fixed (byte* rawAddress = buffer) + + if (family != AddressFamily.Unknown) { - err = Interop.Sys.SetAddressFamily(rawAddress, buffer.Length, (int)family); - } + fixed (byte* rawAddress = buffer) + { + err = Interop.Sys.SetAddressFamily(rawAddress, buffer.Length, (int)family); + } - ThrowOnFailure(err); + ThrowOnFailure(err); + } } public static unsafe ushort GetPort(ReadOnlySpan buffer) diff --git a/src/libraries/Common/src/System/Net/WebSockets/ManagedWebSocket.cs b/src/libraries/Common/src/System/Net/WebSockets/ManagedWebSocket.cs index 437c6eaff992cf..8a2d4252324183 100644 --- a/src/libraries/Common/src/System/Net/WebSockets/ManagedWebSocket.cs +++ b/src/libraries/Common/src/System/Net/WebSockets/ManagedWebSocket.cs @@ -514,8 +514,9 @@ private void SendKeepAliveFrameAsync() if (acquiredLock) { // This exists purely to keep the connection alive; don't wait for the result, and ignore any failures. - // The call will handle releasing the lock. - ValueTask t = SendFrameLockAcquiredNonCancelableAsync(MessageOpcode.Ping, true, Memory.Empty); + // The call will handle releasing the lock. We send a pong rather than ping, since it's allowed by + // the RFC as a unidirectional heartbeat and we're not interested in waiting for a response. + ValueTask t = SendFrameLockAcquiredNonCancelableAsync(MessageOpcode.Pong, true, ReadOnlyMemory.Empty); if (t.IsCompletedSuccessfully) { t.GetAwaiter().GetResult(); @@ -709,7 +710,7 @@ private async ValueTask ReceiveAsyncPrivate ((ManagedWebSocket)s!).Abort(), this) : default) + { + await receiveTask.ConfigureAwait(false); + } } } finally diff --git a/src/libraries/Common/src/System/Resources/ResourceWriter.cs b/src/libraries/Common/src/System/Resources/ResourceWriter.cs index 71e4be036dccfe..cde3d16d89e9bd 100644 --- a/src/libraries/Common/src/System/Resources/ResourceWriter.cs +++ b/src/libraries/Common/src/System/Resources/ResourceWriter.cs @@ -325,7 +325,7 @@ public void Generate() ResourceTypeCode typeCode = FindTypeCode(value, typeNames); // Write out type code - Write7BitEncodedInt(data, (int)typeCode); + data.Write7BitEncodedInt((int)typeCode); var userProvidedResource = value as PrecannedResource; if (userProvidedResource != null) @@ -417,20 +417,6 @@ public void Generate() _resourceList = null; } - private static void Write7BitEncodedInt(BinaryWriter store, int value) - { - Debug.Assert(store != null); - // Write out an int 7 bits at a time. The high bit of the byte, - // when on, tells reader to continue reading more bytes. - uint v = (uint)value; // support negative numbers - while (v >= 0x80) - { - store.Write((byte)(v | 0x80)); - v >>= 7; - } - store.Write((byte)v); - } - // Finds the ResourceTypeCode for a type, or adds this type to the // types list. private ResourceTypeCode FindTypeCode(object? value, List types) diff --git a/src/libraries/Common/src/System/Runtime/Serialization/SerializationGuard.cs b/src/libraries/Common/src/System/Runtime/Serialization/SerializationGuard.cs index 3fa5f3f49c3c2d..35614ed285774f 100644 --- a/src/libraries/Common/src/System/Runtime/Serialization/SerializationGuard.cs +++ b/src/libraries/Common/src/System/Runtime/Serialization/SerializationGuard.cs @@ -26,7 +26,7 @@ internal static partial class SerializationGuard if (throwMethod != null) { - throwIfDeserializationInProgressDelegate = (ThrowIfDeserializationInProgressWithSwitchDel)throwMethod.CreateDelegate(typeof(ThrowIfDeserializationInProgressWithSwitchDel)); + throwIfDeserializationInProgressDelegate = throwMethod.CreateDelegate(); } return throwIfDeserializationInProgressDelegate; diff --git a/src/libraries/Common/src/System/SR.cs b/src/libraries/Common/src/System/SR.cs index 357492065e5021..69a233ed668e33 100644 --- a/src/libraries/Common/src/System/SR.cs +++ b/src/libraries/Common/src/System/SR.cs @@ -29,7 +29,12 @@ internal static string GetResourceString(string resourceKey, string? defaultStri string? resourceString = null; try { - resourceString = ResourceManager.GetString(resourceKey); + resourceString = +#if SYSTEM_PRIVATE_CORELIB + InternalGetResourceString(resourceKey); +#else + ResourceManager.GetString(resourceKey); +#endif } catch (MissingManifestResourceException) { } diff --git a/src/libraries/Common/src/System/Text/StringBuilderCache.cs b/src/libraries/Common/src/System/Text/StringBuilderCache.cs index aac2c2e8a9a07e..4d96cb301e9e1f 100644 --- a/src/libraries/Common/src/System/Text/StringBuilderCache.cs +++ b/src/libraries/Common/src/System/Text/StringBuilderCache.cs @@ -11,7 +11,7 @@ internal static class StringBuilderCache // The value 360 was chosen in discussion with performance experts as a compromise between using // as litle memory per thread as possible and still covering a large part of short-lived // StringBuilder creations on the startup path of VS designers. - private const int MaxBuilderSize = 360; + internal const int MaxBuilderSize = 360; private const int DefaultCapacity = 16; // == StringBuilder.DefaultCapacity // WARNING: We allow diagnostic tools to directly inspect this member (t_cachedInstance). diff --git a/src/libraries/Common/src/System/Threading/Tasks/TaskToApm.cs b/src/libraries/Common/src/System/Threading/Tasks/TaskToApm.cs index ecd9f27ecb8dd8..7be4563cddecd1 100644 --- a/src/libraries/Common/src/System/Threading/Tasks/TaskToApm.cs +++ b/src/libraries/Common/src/System/Threading/Tasks/TaskToApm.cs @@ -14,6 +14,7 @@ #nullable enable using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace System.Threading.Tasks { @@ -43,7 +44,7 @@ public static void End(IAsyncResult asyncResult) return; } - throw new ArgumentNullException(); + ThrowArgumentException(asyncResult); } /// Processes an IAsyncResult returned by Begin. @@ -55,9 +56,17 @@ public static TResult End(IAsyncResult asyncResult) return task.GetAwaiter().GetResult(); } - throw new ArgumentNullException(); + ThrowArgumentException(asyncResult); + return default!; // unreachable } + /// Throws an argument exception for the invalid . + [DoesNotReturn] + private static void ThrowArgumentException(IAsyncResult asyncResult) => + throw (asyncResult is null ? + new ArgumentNullException(nameof(asyncResult)) : + new ArgumentException(null, nameof(asyncResult))); + /// Provides a simple IAsyncResult that wraps a Task. /// /// We could use the Task as the IAsyncResult if the Task's AsyncState is the same as the object state, diff --git a/src/libraries/Common/tests/AndroidTestRunner/AndroidTestRunner.cs b/src/libraries/Common/tests/AndroidTestRunner/AndroidTestRunner.cs new file mode 100644 index 00000000000000..9f232f549ba926 --- /dev/null +++ b/src/libraries/Common/tests/AndroidTestRunner/AndroidTestRunner.cs @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Linq; +using System.Text; +using System.IO; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using Microsoft.DotNet.XHarness.Tests.Runners; +using Microsoft.DotNet.XHarness.Tests.Runners.Core; + +public class SimpleAndroidTestRunner : AndroidApplicationEntryPoint, IDevice +{ + private static List s_testLibs = new List(); + private static string? s_MainTestName; + + public static async Task Main(string[] args) + { + s_testLibs = Directory.GetFiles(Environment.CurrentDirectory, "*.Tests.dll").ToList(); + if (s_testLibs.Count < 1) + { + Console.WriteLine($"Test libs were not found (*.Tests.dll was not found in {Environment.CurrentDirectory})"); + return -1; + } + int exitCode = 0; + s_MainTestName = Path.GetFileNameWithoutExtension(s_testLibs[0]); + var simpleTestRunner = new SimpleAndroidTestRunner(true); + simpleTestRunner.TestsCompleted += (e, result) => + { + if (result.FailedTests > 0) + exitCode = 1; + }; + + await simpleTestRunner.RunAsync(); + Console.WriteLine("----- Done -----"); + return exitCode; + } + + public SimpleAndroidTestRunner(bool verbose) + { + if (verbose) + { + MinimumLogLevel = MinimumLogLevel.Verbose; + _maxParallelThreads = 1; + } + else + { + MinimumLogLevel = MinimumLogLevel.Info; + _maxParallelThreads = Environment.ProcessorCount; + } + } + + protected override IEnumerable GetTestAssemblies() + { + foreach (string file in s_testLibs) + { + yield return new TestAssemblyInfo(Assembly.LoadFrom(file), file); + } + } + + protected override void TerminateWithSuccess() {} + + private int? _maxParallelThreads; + + protected override int? MaxParallelThreads => _maxParallelThreads; + + protected override IDevice Device => this; + + protected override TestRunnerType TestRunner => TestRunnerType.Xunit; + + protected override string? IgnoreFilesDirectory => null; + + protected override string IgnoredTraitsFilePath => "xunit-excludes.txt"; + + public string BundleIdentifier => "net.dot." + s_MainTestName; + + public string? UniqueIdentifier { get; } + + public string? Name { get; } + + public string? Model { get; } + + public string? SystemName { get; } + + public string? SystemVersion { get; } + + public string? Locale { get; } + + public override TextWriter? Logger => null; + + public override string TestsResultsFinalPath + { + get + { + string? publicDir = Environment.GetEnvironmentVariable("DOCSDIR"); + if (string.IsNullOrEmpty(publicDir)) + throw new ArgumentException("DOCSDIR should not be empty"); + + return Path.Combine(publicDir, "testResults.xml"); + } + } +} diff --git a/src/libraries/Common/tests/AndroidTestRunner/AndroidTestRunner.csproj b/src/libraries/Common/tests/AndroidTestRunner/AndroidTestRunner.csproj new file mode 100644 index 00000000000000..6f73d8ec7cefbc --- /dev/null +++ b/src/libraries/Common/tests/AndroidTestRunner/AndroidTestRunner.csproj @@ -0,0 +1,11 @@ + + + Exe + enable + $(NetCoreAppCurrent) + + + + + + diff --git a/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs b/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs new file mode 100644 index 00000000000000..22979b7d4cf370 --- /dev/null +++ b/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.cs @@ -0,0 +1,150 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Linq; +using System.Text; +using System.IO; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using Microsoft.DotNet.XHarness.Tests.Runners; +using Microsoft.DotNet.XHarness.Tests.Runners.Core; + +public class SimpleTestRunner : iOSApplicationEntryPoint, IDevice +{ + // to be wired once https://github.com/dotnet/xharness/pull/46 is merged + [DllImport("__Internal")] + public extern static void mono_ios_append_output (string value); + + [DllImport("__Internal")] + public extern static void mono_ios_set_summary (string value); + + private static List s_testLibs = new List(); + private static string? s_MainTestName; + + public static async Task Main(string[] args) + { + Console.WriteLine($"ProcessorCount = {Environment.ProcessorCount}"); + + Console.Write("Args: "); + foreach (string arg in args) + { + Console.Write(arg); + } + Console.WriteLine("."); + + foreach (string arg in args.Where(a => a.StartsWith("testlib:"))) + { + s_testLibs.Add(arg.Remove(0, "testlib:".Length)); + } + bool verbose = args.Contains("--verbose"); + + if (s_testLibs.Count < 1) + { + // Look for *.Tests.dll files if target test suites are not set via "testlib:" arguments + s_testLibs = Directory.GetFiles(Environment.CurrentDirectory, "*.Tests.dll").ToList(); + } + + if (s_testLibs.Count < 1) + { + Console.WriteLine($"Test libs were not found (*.Tests.dll was not found in {Environment.CurrentDirectory})"); + return -1; + } + + Console.Write("Test libs: "); + foreach (string testLib in s_testLibs) + { + Console.WriteLine(testLib); + } + Console.WriteLine("."); + s_MainTestName = Path.GetFileNameWithoutExtension(s_testLibs[0]); + + mono_ios_set_summary($"Starting tests..."); + var simpleTestRunner = new SimpleTestRunner(verbose); + simpleTestRunner.TestStarted += (target, e) => + { + mono_ios_append_output($"[STARTING] {e}\n"); + }; + + int failed = 0, passed = 0, skipped = 0; + simpleTestRunner.TestCompleted += (target, e) => + { + if (e.Item2 == TestResult.Passed) + { + passed++; + } + else if (e.Item2 == TestResult.Failed) + { + failed++; + } + else if (e.Item2 == TestResult.Skipped) + { + skipped++; + } + mono_ios_set_summary($"{s_MainTestName}\nPassed:{passed}, Failed: {failed}, Skipped:{skipped}"); + }; + + await simpleTestRunner.RunAsync(); + mono_ios_append_output($"\nDone.\n"); + Console.WriteLine("----- Done -----"); + return 0; + } + + public SimpleTestRunner(bool verbose) + { + if (verbose) + { + MinimumLogLevel = MinimumLogLevel.Verbose; + _maxParallelThreads = 1; + } + else + { + MinimumLogLevel = MinimumLogLevel.Info; + _maxParallelThreads = Environment.ProcessorCount; + } + } + + protected override IEnumerable GetTestAssemblies() + { + foreach (string file in s_testLibs) + { + yield return new TestAssemblyInfo(Assembly.LoadFrom(file), file); + } + } + + protected override void TerminateWithSuccess() + { + Console.WriteLine("[TerminateWithSuccess]"); + } + + private int? _maxParallelThreads; + + protected override int? MaxParallelThreads => _maxParallelThreads; + + protected override IDevice Device => this; + + protected override TestRunnerType TestRunner => TestRunnerType.Xunit; + + protected override string? IgnoreFilesDirectory => null; + + protected override string IgnoredTraitsFilePath => "xunit-excludes.txt"; + + public string BundleIdentifier => "net.dot." + s_MainTestName; + + public string? UniqueIdentifier { get; } + + public string? Name { get; } + + public string? Model { get; } + + public string? SystemName { get; } + + public string? SystemVersion { get; } + + public string? Locale { get; } +} diff --git a/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.csproj b/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.csproj new file mode 100644 index 00000000000000..906eea315338de --- /dev/null +++ b/src/libraries/Common/tests/AppleTestRunner/AppleTestRunner.csproj @@ -0,0 +1,11 @@ + + + Exe + enable + $(NetCoreAppCurrent) + + + + + + diff --git a/src/libraries/Common/tests/Common.Tests.csproj b/src/libraries/Common/tests/Common.Tests.csproj index 18a311eb4c6d90..313fb9f76de7e4 100644 --- a/src/libraries/Common/tests/Common.Tests.csproj +++ b/src/libraries/Common/tests/Common.Tests.csproj @@ -1,219 +1,149 @@ - + true - false true $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-OSX annotations - - Common\System\Collections\DictionaryExtensions.cs - - - Common\System\Security\Cryptography\ByteUtils.cs - - - Common\Interop\Linux\cgroups\Interop.cgroups.cs - - - Common\Interop\Linux\procfs\Interop.ProcFsStat.cs - - - Common\System\CharArrayHelpers.cs - - - Common\System\Marvin.cs - - - Common\System\StringExtensions.cs - - - Common\System\Collections\Generic\ArrayBuilder.cs - - - Common\System\Collections\Generic\LargeArrayBuilder.cs - - - Common\System\Collections\Generic\LargeArrayBuilder.SpeedOpt.cs - - - Common\System\IO\PathInternal.CaseSensitivity.cs - - - Common\System\IO\RowConfigReader.cs - - - Common\System\IO\StringParser.cs - - - Common\System\Net\HttpDateParser.cs - - - Common\System\Net\HttpKnownHeaderNames.cs - - - Common\System\Net\HttpKnownHeaderNames.TryGetHeaderName.cs - - - Common\System\Net\Http\aspnetcore\IHttpHeadersHandler.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\DynamicTable.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HeaderField.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HPackDecoder.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HPackDecodingException.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HPackEncoder.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HPackEncodingException.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\Huffman.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HuffmanDecodingException.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\IntegerDecoder.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\IntegerEncoder.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\H2StaticTable.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\StatusCodes.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicAddressHelpers.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicApi.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicParameterHelpers.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicSecurityConfig.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicSession.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\QuicExceptionHelpers.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\ResettableCompletionSource.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\MsQuicConnection.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\MsQuicImplementationProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\MsQuicListener.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\MsQuicStream.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\QuicImplementationProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\QuicListenerProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\QuicConnectionProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\QuicStreamProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\Mock\MockImplementationProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\Mock\MockListener.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\Mock\MockConnection.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\Mock\MockStream.cs - - - Common\System\Net\Http\aspnetcore\Quic\NetEventSource.Quic.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicClientConnectionOptions.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicImplementationProviders.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicConnection.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicListener.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicListenerOptions.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicOperationAbortedException.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicStream.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicException.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicConnectionAbortedException.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicStreamAbortedException.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\Interop.MsQuic.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\MsQuicEnums.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\MsQuicNativeMethods.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\MsQuicStatusCodes.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\MsQuicStatusHelper.cs - - - Common\System\Text\ReusableTextReader.cs - - - Common\System\Text\SimpleRegex.cs - - - Common\System\Text\ValueStringBuilder.cs - - - Common\System\Security\IdentityHelper.cs - - - System\PasteArguments.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -234,75 +164,57 @@ - - System\Net\Sockets\Fletcher32.cs - - - System\Net\VirtualNetwork\VirtualNetwork.cs - - - System\Net\VirtualNetwork\VirtualNetworkStream.cs - + + + - - Common\System\Net\Logging\NetEventSource.Common.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - - - System\IO\PathInternal.cs - + + + - - System\IO\PathInternal.Windows.cs - - - Common\Interop\Windows\Interop.Libraries.cs - + + - - Common\Interop\Windows\kernel32\Interop.FormatMessage.cs - - - Common\Interop\Windows\Interop.Errors.cs - - - Common\System\IO\Win32Marshal.cs - + + + - - System\PasteArguments.Windows.cs - + - - System\IO\PathInternal.Unix.cs - - - Common\Interop\Unix\Interop.PathConf.cs - - - Common\Interop\Unix\Interop.Libraries.cs - - - System\PasteArguments.Unix.cs - + + + + - - Common\Interop\Linux\Interop.Libraries.cs - + - - Common\Interop\OSX\Interop.Libraries.cs - + diff --git a/src/libraries/Common/tests/StaticTestGenerator/Program.cs b/src/libraries/Common/tests/StaticTestGenerator/Program.cs index 6ab713b8c62b92..f852d47aa2af06 100644 --- a/src/libraries/Common/tests/StaticTestGenerator/Program.cs +++ b/src/libraries/Common/tests/StaticTestGenerator/Program.cs @@ -274,7 +274,7 @@ from part in line.Split(' ') // Invalid command line arguments. Console.WriteLine("Usage: "); Console.WriteLine(" Example:"); - Console.WriteLine(@" dotnet run d:\tmpoutput d:\repos\runtime\artifacts\bin\testhost\netcoreapp5.0-Windows_NT-Debug-x64\shared\Microsoft.NETCore.App\$(ProductVersion) d:\repos\runtime\artifacts\bin\System.Runtime.Tests\netcoreapp5.0-Windows_NT-Debug\System.Runtime.Tests.dll"); + Console.WriteLine(@" dotnet run d:\tmpoutput d:\repos\runtime\artifacts\bin\testhost\net5.0-Windows_NT-Debug-x64\shared\Microsoft.NETCore.App\$(ProductVersion) d:\repos\runtime\artifacts\bin\System.Runtime.Tests\net5.0-Windows_NT-Debug\System.Runtime.Tests.dll"); testAssemblyPath = string.Empty; runtimeAssembliesPath = string.Empty; outputPath = string.Empty; diff --git a/src/libraries/Common/tests/StaticTestGenerator/README.md b/src/libraries/Common/tests/StaticTestGenerator/README.md index 657decbad1eb88..73a82c4d4258d5 100644 --- a/src/libraries/Common/tests/StaticTestGenerator/README.md +++ b/src/libraries/Common/tests/StaticTestGenerator/README.md @@ -22,16 +22,16 @@ From within the utility directory, run the utility with the arguments: For example: ``` -dotnet run d:\output "d:\repos\runtime\artifacts\bin\testhost\netcoreapp5.0-Windows_NT-Debug-x64\shared\Microsoft.NETCore.App\5.0.0" "d:\repos\runtime\artifacts\bin\System.Runtime.Tests\netcoreapp5.0-Windows_NT-Debug\System.Runtime.Tests.dll" +dotnet run d:\output "d:\repos\runtime\artifacts\bin\testhost\net5.0-Windows_NT-Debug-x64\shared\Microsoft.NETCore.App\5.0.0" "d:\repos\runtime\artifacts\bin\System.Runtime.Tests\net5.0-Windows_NT-Debug\System.Runtime.Tests.dll" ``` This will run the tool and result in output written to the console like: ``` -3/27/2019 10:55:37 PM | Test assembly path : d:\repos\runtime\artifacts\bin\System.Runtime.Tests\netcoreapp5.0-Windows_NT-Debug\System.Runtime.Tests.dll -3/27/2019 10:55:37 PM | Helper assemblies path: d:\repos\runtime\artifacts\bin\testhost\netcoreapp5.0-Windows_NT-Debug-x64\shared\Microsoft.NETCore.App\3.0.0\ +3/27/2019 10:55:37 PM | Test assembly path : d:\repos\runtime\artifacts\bin\System.Runtime.Tests\net5.0-Windows_NT-Debug\System.Runtime.Tests.dll +3/27/2019 10:55:37 PM | Helper assemblies path: d:\repos\runtime\artifacts\bin\testhost\net5.0-Windows_NT-Debug-x64\shared\Microsoft.NETCore.App\3.0.0\ 3/27/2019 10:55:37 PM | Output path : d:\output\System.Runtime.Tests\ -3/27/2019 10:55:37 PM | Xunit arguments : d:\repos\runtime\artifacts\bin\System.Runtime.Tests\netcoreapp5.0-Windows_NT-Debug\System.Runtime.Tests.dll -notrait category=nonnetcoreapptests -notrait category=nonwindowstests -notrait category=IgnoreForCI -notrait category=failing -notrait category=OuterLoop +3/27/2019 10:55:37 PM | Xunit arguments : d:\repos\runtime\artifacts\bin\System.Runtime.Tests\net5.0-Windows_NT-Debug\System.Runtime.Tests.dll -notrait category=nonnetcoreapptests -notrait category=nonwindowstests -notrait category=IgnoreForCI -notrait category=failing -notrait category=OuterLoop 3/27/2019 10:55:37 PM | -3/27/2019 10:55:37 PM | Loaded System.Runtime.Tests from d:\repos\runtime\artifacts\bin\System.Runtime.Tests\netcoreapp5.0-Windows_NT-Debug\System.Runtime.Tests.dll +3/27/2019 10:55:37 PM | Loaded System.Runtime.Tests from d:\repos\runtime\artifacts\bin\System.Runtime.Tests\net5.0-Windows_NT-Debug\System.Runtime.Tests.dll 3/27/2019 10:55:37 PM | Found 5322 test methods. 3/27/2019 10:55:38 PM | Found 3469 InlineDatas / 949 MethodDatas across 5322 test methods. 3/27/2019 10:55:38 PM | diff --git a/src/libraries/Common/tests/StaticTestGenerator/StaticTestGenerator.csproj b/src/libraries/Common/tests/StaticTestGenerator/StaticTestGenerator.csproj index 02be551619300a..6896b22f7ff5f0 100644 --- a/src/libraries/Common/tests/StaticTestGenerator/StaticTestGenerator.csproj +++ b/src/libraries/Common/tests/StaticTestGenerator/StaticTestGenerator.csproj @@ -1,4 +1,4 @@ - + Exe netcoreapp3.0 diff --git a/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs b/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs index ee774e0f23090c..40a3f962305cb8 100644 --- a/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs +++ b/src/libraries/Common/tests/System/Net/Http/Http2LoopbackConnection.cs @@ -470,7 +470,7 @@ private static (int bytesConsumed, HttpHeaderData headerData) DecodeHeader(ReadO } } - public async Task ReadBodyAsync() + public async Task ReadBodyAsync(bool expectEndOfStream = false) { byte[] body = null; Frame frame; @@ -478,7 +478,11 @@ public async Task ReadBodyAsync() do { frame = await ReadFrameAsync(Timeout).ConfigureAwait(false); - if (frame == null || frame.Type == FrameType.RstStream) + if (frame == null && expectEndOfStream) + { + break; + } + else if (frame == null || frame.Type == FrameType.RstStream) { throw new IOException( frame == null ? "End of stream" : "Got RST"); } diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs index b248f3470bbdda..679b5406f81702 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs @@ -341,7 +341,7 @@ public async Task MaxConnectionsPerServer_WaitingConnectionsAreCancelable() if (LoopbackServerFactory.Version >= HttpVersion20.Value) { // HTTP/2 does not use connection limits. - throw new SkipTestException("Not supported on HTTP/2 and later"); + return; } using (HttpClientHandler handler = CreateHttpClientHandler()) @@ -437,7 +437,7 @@ public static IEnumerable PostAsync_Cancel_CancellationTokenPassedToCo bool called = false; var content = new StreamContent(new DelegateStream( canReadFunc: () => true, - readAsyncFunc: (buffer, offset, count, cancellationToken) => + readAsyncFunc: async (buffer, offset, count, cancellationToken) => { int result = 1; if (called) @@ -445,11 +445,17 @@ public static IEnumerable PostAsync_Cancel_CancellationTokenPassedToCo result = 0; Assert.False(cancellationToken.IsCancellationRequested); tokenSource.Cancel(); - Assert.True(cancellationToken.IsCancellationRequested); + + // Wait for cancellation to occur. It should be very quickly after it's been requested. + var tcs = new TaskCompletionSource(); + using (cancellationToken.Register(() => tcs.SetResult(true))) + { + await tcs.Task; + } } called = true; - return Task.FromResult(result); + return result; } )); yield return new object[] { content, tokenSource }; @@ -467,7 +473,7 @@ public static IEnumerable PostAsync_Cancel_CancellationTokenPassedToCo lengthFunc: () => 1, positionGetFunc: () => 0, positionSetFunc: _ => {}, - readAsyncFunc: (buffer, offset, count, cancellationToken) => + readAsyncFunc: async (buffer, offset, count, cancellationToken) => { int result = 1; if (called) @@ -475,11 +481,17 @@ public static IEnumerable PostAsync_Cancel_CancellationTokenPassedToCo result = 0; Assert.False(cancellationToken.IsCancellationRequested); tokenSource.Cancel(); - Assert.True(cancellationToken.IsCancellationRequested); + + // Wait for cancellation to occur. It should be very quickly after it's been requested. + var tcs = new TaskCompletionSource(); + using (cancellationToken.Register(() => tcs.SetResult(true))) + { + await tcs.Task; + } } called = true; - return Task.FromResult(result); + return result; } ))); yield return new object[] { content, tokenSource }; @@ -497,7 +509,7 @@ public static IEnumerable PostAsync_Cancel_CancellationTokenPassedToCo lengthFunc: () => 1, positionGetFunc: () => 0, positionSetFunc: _ => {}, - readAsyncFunc: (buffer, offset, count, cancellationToken) => + readAsyncFunc: async (buffer, offset, count, cancellationToken) => { int result = 1; if (called) @@ -505,11 +517,17 @@ public static IEnumerable PostAsync_Cancel_CancellationTokenPassedToCo result = 0; Assert.False(cancellationToken.IsCancellationRequested); tokenSource.Cancel(); - Assert.True(cancellationToken.IsCancellationRequested); + + // Wait for cancellation to occur. It should be very quickly after it's been requested. + var tcs = new TaskCompletionSource(); + using (cancellationToken.Register(() => tcs.SetResult(true))) + { + await tcs.Task; + } } called = true; - return Task.FromResult(result); + return result; } ))); yield return new object[] { content, tokenSource }; diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs index 80ec9e25b244d6..8a30a894edf7af 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs @@ -113,9 +113,10 @@ await response.Content.ReadAsStringAsync(), } } + public static bool IsSocketsHttpHandler => !HttpClientHandlerTestBase.IsWinHttpHandler; + [OuterLoop("Uses external server")] - [ConditionalFact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/33558")] + [ConditionalFact(nameof(IsSocketsHttpHandler))] public void Proxy_UseEnvironmentVariableToSetSystemProxy_RequestGoesThruProxy() { RemoteExecutor.Invoke(async (useVersionString) => diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.SslProtocols.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.SslProtocols.cs index b264aa6bc6c5d9..735642702cded5 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.SslProtocols.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.SslProtocols.cs @@ -150,9 +150,7 @@ await TestHelper.WhenAllCompletedOrAnyFailed( public static IEnumerable SupportedSSLVersionServers() { #pragma warning disable 0618 // SSL2/3 are deprecated - if (PlatformDetection.IsWindows || - PlatformDetection.IsOSX || - (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && PlatformDetection.OpenSslVersion < new Version(1, 0, 2) && !PlatformDetection.IsDebian)) + if (PlatformDetection.SupportsSsl3) { yield return new object[] { SslProtocols.Ssl3, Configuration.Http.SSLv3RemoteServer }; } @@ -197,7 +195,7 @@ public async Task GetAsync_SupportedSSLVersion_Succeeds(SslProtocols sslProtocol public static IEnumerable NotSupportedSSLVersionServers() { #pragma warning disable 0618 - if (PlatformDetection.IsWindows10Version1607OrGreater) + if (PlatformDetection.SupportsSsl2) { yield return new object[] { SslProtocols.Ssl2, Configuration.Http.SSLv2RemoteServer }; } diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs index a866a5d076a995..f2dd96d75d614d 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs @@ -493,7 +493,8 @@ public async Task GetAsync_SecureAndNonSecureIPBasedUri_CorrectlyFormatted(IPAdd { if (LoopbackServerFactory.Version >= HttpVersion20.Value) { - throw new SkipTestException("Host header is not supported on HTTP/2 and later."); + // Host header is not supported on HTTP/2 and later. + return; } var options = new LoopbackServer.Options { Address = address, UseSsl= useSsl }; @@ -930,7 +931,8 @@ public async Task GetAsync_ManyDifferentResponseHeaders_ParsedCorrectly(string n { if (LoopbackServerFactory.Version >= HttpVersion20.Value) { - throw new SkipTestException("Folding is not supported on HTTP/2 and later."); + // Folding is not supported on HTTP/2 and later. + return; } // Using examples from https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields @@ -989,7 +991,7 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => Assert.Contains(new ViaHeaderValue("1.1", "example.com", null, "(Apache/1.1)"), resp.Headers.Via); Assert.Contains(new WarningHeaderValue(199, "-", "\"Miscellaneous warning\"", DateTimeOffset.Parse("Wed, 21 Oct 2015 07:28:00 GMT")), resp.Headers.Warning); Assert.Contains(new AuthenticationHeaderValue("Basic"), resp.Headers.WwwAuthenticate); - Assert.Contains("deny", resp.Headers.GetValues("X-Frame-Options")); + Assert.Contains("deny", resp.Headers.GetValues("X-Frame-Options"), StringComparer.OrdinalIgnoreCase); Assert.Contains("default-src 'self'", resp.Headers.GetValues("X-WebKit-CSP")); Assert.Contains("5; url=http://www.w3.org/pub/WWW/People.html", resp.Headers.GetValues("Refresh")); Assert.Contains("200 OK", resp.Headers.GetValues("Status")); @@ -1062,8 +1064,10 @@ public async Task GetAsync_NonTraditionalChunkSizes_Accepted() { if (LoopbackServerFactory.Version >= HttpVersion20.Value) { - throw new SkipTestException("Chunking is not supported on HTTP/2 and later."); + // Chunking is not supported on HTTP/2 and later. + return; } + await LoopbackServer.CreateServerAsync(async (server, url) => { using (HttpClient client = CreateHttpClient()) @@ -1292,7 +1296,8 @@ public async Task ReadAsStreamAsync_HandlerProducesWellBehavedResponseStream(boo #endif if (LoopbackServerFactory.Version >= HttpVersion20.Value && chunked == true) { - throw new SkipTestException("Chunking is not supported on HTTP/2 and later."); + // Chunking is not supported on HTTP/2 and later. + return; } await LoopbackServerFactory.CreateClientAndServerAsync(async uri => @@ -2166,7 +2171,8 @@ public async Task SendAsync_101SwitchingProtocolsResponse_Success() if (LoopbackServerFactory.Version >= HttpVersion20.Value) { - throw new SkipTestException("Upgrade is not supported on HTTP/2 and later"); + // Upgrade is not supported on HTTP/2 and later + return; } var clientFinished = new TaskCompletionSource(); diff --git a/src/libraries/Common/tests/System/Net/Http/TestHelper.cs b/src/libraries/Common/tests/System/Net/Http/TestHelper.cs index 4805ccd18554a1..c3f63a84ee3c73 100644 --- a/src/libraries/Common/tests/System/Net/Http/TestHelper.cs +++ b/src/libraries/Common/tests/System/Net/Http/TestHelper.cs @@ -130,6 +130,23 @@ public static void EnableUnencryptedHttp2IfNecessary(HttpClientHandler handler) object socketsHttpHandler = socketsHttpHandlerField.GetValue(handler); Assert.NotNull(socketsHttpHandler); + EnableUncryptedHttp2(socketsHttpHandler); + } + +#if !NETFRAMEWORK + public static void EnableUnencryptedHttp2IfNecessary(SocketsHttpHandler socketsHttpHandler) + { + if (PlatformDetection.SupportsAlpn && !Capability.Http2ForceUnencryptedLoopback()) + { + return; + } + + EnableUncryptedHttp2(socketsHttpHandler); + } +#endif + + private static void EnableUncryptedHttp2(object socketsHttpHandler) + { // Get HttpConnectionSettings object from SocketsHttpHandler. Type socketsHttpHandlerType = typeof(HttpClientHandler).Assembly.GetType("System.Net.Http.SocketsHttpHandler"); FieldInfo settingsField = socketsHttpHandlerType.GetField("_settings", BindingFlags.NonPublic | BindingFlags.Instance); diff --git a/src/libraries/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs b/src/libraries/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs index 0f45acc9f80f04..daf5caf54a60d0 100644 --- a/src/libraries/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs +++ b/src/libraries/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs @@ -22,6 +22,8 @@ public VirtualNetworkStream(VirtualNetwork network, bool isServer) _isServer = isServer; } + public int DelayMilliseconds { get; set; } + public bool Disposed { get; private set; } public override bool CanRead => true; @@ -87,6 +89,11 @@ public override async Task ReadAsync(byte[] buffer, int offset, int count, await _readStreamLock.WaitAsync(cancellationToken).ConfigureAwait(false); try { + if (DelayMilliseconds > 0) + { + await Task.Delay(DelayMilliseconds, cancellationToken); + } + if (_readStream == null || (_readStream.Position >= _readStream.Length)) { _readStream = new MemoryStream(await _network.ReadFrameAsync(_isServer, cancellationToken).ConfigureAwait(false)); @@ -105,22 +112,16 @@ public override void Write(byte[] buffer, int offset, int count) _network.WriteFrame(_isServer, buffer.AsSpan(offset, count).ToArray()); } - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - if (cancellationToken.IsCancellationRequested) - { - return Task.FromCanceled(cancellationToken); - } + cancellationToken.ThrowIfCancellationRequested(); - try + if (DelayMilliseconds > 0) { - Write(buffer, offset, count); - return Task.CompletedTask; - } - catch (Exception exc) - { - return Task.FromException(exc); + await Task.Delay(DelayMilliseconds, cancellationToken); } + + Write(buffer, offset, count); } public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) => diff --git a/src/libraries/Common/tests/TestUtilities.Unicode/TestUtilities.Unicode.csproj b/src/libraries/Common/tests/TestUtilities.Unicode/TestUtilities.Unicode.csproj index a3eaba2cfc48dc..5f241043489c38 100644 --- a/src/libraries/Common/tests/TestUtilities.Unicode/TestUtilities.Unicode.csproj +++ b/src/libraries/Common/tests/TestUtilities.Unicode/TestUtilities.Unicode.csproj @@ -47,7 +47,6 @@ - diff --git a/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs b/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs index d1688c9c860b08..45f0d593336675 100644 --- a/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs +++ b/src/libraries/Common/tests/TestUtilities/System/AssertExtensions.cs @@ -27,7 +27,7 @@ public static void ThrowsContains(Action action, string expectedMessageConten Assert.Contains(expectedMessageContent, Assert.Throws(action).Message); } - public static void Throws(string netCoreParamName, string netFxParamName, Action action) + public static T Throws(string netCoreParamName, string netFxParamName, Action action) where T : ArgumentException { T exception = Assert.Throws(action); @@ -35,7 +35,7 @@ public static void Throws(string netCoreParamName, string netFxParamName, Act if (netFxParamName == null && IsNetFramework) { // Param name varies between .NET Framework versions -- skip checking it - return; + return exception; } string expectedParamName = @@ -43,6 +43,7 @@ public static void Throws(string netCoreParamName, string netFxParamName, Act netFxParamName : netCoreParamName; Assert.Equal(expectedParamName, exception.ParamName); + return exception; } public static void Throws(string netCoreParamName, string netFxParamName, Func testCode) diff --git a/src/libraries/Common/tests/TestUtilities/System/IO/StreamExtensions.cs b/src/libraries/Common/tests/TestUtilities/System/IO/StreamExtensions.cs new file mode 100644 index 00000000000000..30ed13c80a2521 --- /dev/null +++ b/src/libraries/Common/tests/TestUtilities/System/IO/StreamExtensions.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Threading.Tasks; + +namespace System.IO +{ + public static class StreamExtensions + { + public static async Task ReadByteAsync(this Stream stream, CancellationToken cancellationToken = default) + { + byte[] buffer = new byte[1]; + + int numBytesRead = await stream.ReadAsync(buffer, 0, 1, cancellationToken); + if (numBytesRead == 0) + { + return -1; // EOF + } + + return buffer[0]; + } + } +} diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs index 58aa95010c0954..38fb7d598ce0a2 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs @@ -2,9 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Reflection; +using System.IO; using System.Runtime.InteropServices; -using System.Xml.Linq; namespace System { @@ -35,14 +34,10 @@ public static partial class PlatformDetection // OSX family public static bool IsOSX => RuntimeInformation.IsOSPlatform(OSPlatform.OSX); public static bool IsNotOSX => !IsOSX; - public static Version OSXVersion => IsOSX ? - ToVersion(Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.OperatingSystemVersion) : - throw new PlatformNotSupportedException(); - private static Lazy m_osxProductVersion = new Lazy(GetOSXProductVersion); - public static bool IsMacOsHighSierraOrHigher => IsOSX && (m_osxProductVersion.Value.Major > 10 || (m_osxProductVersion.Value.Major == 10 && m_osxProductVersion.Value.Minor >= 13)); + public static bool IsMacOsHighSierraOrHigher => IsOSX && Environment.OSVersion.Version >= new Version(10, 13); public static bool IsNotMacOsHighSierraOrHigher => !IsMacOsHighSierraOrHigher; - public static bool IsMacOsMojaveOrHigher => IsOSX && (m_osxProductVersion.Value.Major > 10 || (m_osxProductVersion.Value.Major == 10 && m_osxProductVersion.Value.Minor >= 14)); - public static bool IsMacOsCatalinaOrHigher => IsOSX && (m_osxProductVersion.Value.Major > 10 || (m_osxProductVersion.Value.Major == 10 && m_osxProductVersion.Value.Minor >= 15)); + public static bool IsMacOsMojaveOrHigher => IsOSX && Environment.OSVersion.Version >= new Version(10, 14); + public static bool IsMacOsCatalinaOrHigher => IsOSX && Environment.OSVersion.Version >= new Version(10, 15); // RedHat family covers RedHat and CentOS public static bool IsRedHatFamily => IsRedHatFamilyAndVersion(); @@ -51,9 +46,6 @@ public static partial class PlatformDetection public static bool IsNotFedoraOrRedHatFamily => !IsFedora && !IsRedHatFamily; public static bool IsNotDebian10 => !IsDebian10; - private static Lazy m_icuVersion = new Lazy(GetICUVersion); - public static Version ICUVersion => m_icuVersion.Value; - public static bool IsSuperUser => !IsWindows ? libc.geteuid() == 0 : throw new PlatformNotSupportedException(); @@ -110,75 +102,6 @@ public static string LibcVersion } } - private static Version GetICUVersion() - { - int version = 0; - Type interopGlobalization = Type.GetType("Interop+Globalization"); - if (interopGlobalization != null) - { - MethodInfo methodInfo = interopGlobalization.GetMethod("GetICUVersion", BindingFlags.NonPublic | BindingFlags.Static); - if (methodInfo != null) - { - version = (int)methodInfo.Invoke(null, null); - } - } - - return new Version( version & 0xFF, - (version >> 8) & 0xFF, - (version >> 16) & 0xFF, - version >> 24); - } - - private static Version GetOSXProductVersion() - { - if (IsOSX) - { - try - { - // - // - // ProductBuildVersion - // 17A330h - // ProductCopyright - // 1983-2017 Apple Inc. - // ProductName - // Mac OS X - // ProductUserVisibleVersion - // 10.13 - // ProductVersion - // 10.13 - // - // - - XElement dict = XDocument.Load("/System/Library/CoreServices/SystemVersion.plist").Root.Element("dict"); - if (dict != null) - { - foreach (XElement key in dict.Elements("key")) - { - if ("ProductVersion".Equals(key.Value)) - { - XElement stringElement = key.NextNode as XElement; - if (stringElement != null && stringElement.Name.LocalName.Equals("string")) - { - string versionString = stringElement.Value; - if (versionString != null) - { - return Version.Parse(versionString); - } - } - } - } - } - } - catch - { - } - } - - // In case of exception, couldn't get the version or non osx - return new Version(0, 0, 0); - } - private static Version s_opensslVersion; private static Version GetOpenSslVersion() { @@ -227,11 +150,38 @@ private static Version ToVersion(string versionString) } } - private static DistroInfo GetDistroInfo() => new DistroInfo() + private static DistroInfo GetDistroInfo() { - Id = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.OperatingSystem, - VersionId = ToVersion(Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.OperatingSystemVersion) - }; + DistroInfo result = new DistroInfo(); + + if (IsFreeBSD) + { + result.Id = "FreeBSD"; + // example: + // FreeBSD 11.0-RELEASE-p1 FreeBSD 11.0-RELEASE-p1 #0 r306420: Thu Sep 29 01:43:23 UTC 2016 root@releng2.nyi.freebsd.org:/usr/obj/usr/src/sys/GENERIC + // What we want is major release as minor releases should be compatible. + result.VersionId = ToVersion(RuntimeInformation.OSDescription.Split()[1].Split('.')[0]); + } + else if (File.Exists("/etc/os-release")) + { + foreach (string line in File.ReadAllLines("/etc/os-release")) + { + if (line.StartsWith("ID=", StringComparison.Ordinal)) + { + result.Id = line.Substring(3).Trim('"', '\''); + } + else if (line.StartsWith("VERSION_ID=", StringComparison.Ordinal)) + { + result.VersionId = ToVersion(line.Substring(11).Trim('"', '\'')); + } + } + } + + result.Id ??= "Linux"; + result.VersionId ??= ToVersion(string.Empty); + + return result; + } private static bool IsRedHatFamilyAndVersion(int major = -1, int minor = -1, int build = -1, int revision = -1) { diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs index a04e3b17509932..a17d3eebce28dc 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs @@ -4,6 +4,7 @@ using System.IO; using System.Security; +using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using Microsoft.Win32; @@ -23,6 +24,8 @@ public static partial class PlatformDetection public static bool IsMonoInterpreter => GetIsRunningOnMonoInterpreter(); public static bool IsFreeBSD => RuntimeInformation.IsOSPlatform(OSPlatform.Create("FREEBSD")); public static bool IsNetBSD => RuntimeInformation.IsOSPlatform(OSPlatform.Create("NETBSD")); + public static bool IsiOS => RuntimeInformation.IsOSPlatform(OSPlatform.Create("IOS")); + public static bool IstvOS => RuntimeInformation.IsOSPlatform(OSPlatform.Create("TVOS")); public static bool IsArmProcess => RuntimeInformation.ProcessArchitecture == Architecture.Arm; public static bool IsNotArmProcess => !IsArmProcess; @@ -62,6 +65,7 @@ public static bool IsDrawingSupported public static bool IsInContainer => GetIsInContainer(); public static bool SupportsSsl3 => GetSsl3Support(); + public static bool SupportsSsl2 => IsWindows && !PlatformDetection.IsWindows10Version1607OrGreater; #if NETCOREAPP public static bool IsReflectionEmitSupported = RuntimeFeature.IsDynamicCodeSupported; @@ -107,11 +111,13 @@ public static bool IsNonZeroLowerBoundArraySupported // Windows - Schannel supports alpn from win8.1/2012 R2 and higher. // Linux - OpenSsl supports alpn from openssl 1.0.2 and higher. // OSX - SecureTransport doesn't expose alpn APIs. TODO https://github.com/dotnet/runtime/issues/27727 + public static bool IsOpenSslSupported => IsLinux || IsFreeBSD; + public static bool SupportsAlpn => (IsWindows && !IsWindows7) || - ((!IsOSX && !IsWindows) && + (IsOpenSslSupported && (OpenSslVersion.Major >= 1 && (OpenSslVersion.Minor >= 1 || OpenSslVersion.Build >= 2))); - public static bool SupportsClientAlpn => SupportsAlpn || (IsOSX && PlatformDetection.OSXVersion > new Version(10, 12)); + public static bool SupportsClientAlpn => SupportsAlpn || IsOSX || IsiOS || IstvOS; // OpenSSL 1.1.1 and above. public static bool SupportsTls13 => GetTls13Support(); @@ -140,7 +146,7 @@ public static string GetDistroVersionString() } else if (IsOSX) { - return "OSX Version=" + m_osxProductVersion.Value.ToString(); + return "OSX Version=" + Environment.OSVersion.Version.ToString(); } else { @@ -150,6 +156,35 @@ public static string GetDistroVersionString() } } + private static Lazy m_icuVersion = new Lazy(GetICUVersion); + public static Version ICUVersion => m_icuVersion.Value; + + public static bool IsIcuGlobalization => ICUVersion > new Version(0,0,0,0); + public static bool IsNlsGlobalization => !IsIcuGlobalization; + + private static Version GetICUVersion() + { + int version = 0; + try + { + Type interopGlobalization = Type.GetType("Interop+Globalization"); + if (interopGlobalization != null) + { + MethodInfo methodInfo = interopGlobalization.GetMethod("GetICUVersion", BindingFlags.NonPublic | BindingFlags.Static); + if (methodInfo != null) + { + version = (int)methodInfo.Invoke(null, null); + } + } + } + catch { } + + return new Version(version >> 24, + (version >> 16) & 0xFF, + (version >> 8) & 0xFF, + version & 0xFF); + } + private static bool GetIsInContainer() { if (IsWindows) @@ -230,16 +265,18 @@ private static bool GetTls13Support() // assume no if key is missing or on error. return false; } - else if (IsOSX) + else if (IsOSX || IsiOS || IstvOS) { // [ActiveIssue("https://github.com/dotnet/runtime/issues/1979")] return false; } - else + else if (IsOpenSslSupported) { // Covers Linux and FreeBSD return OpenSslVersion >= new Version(1,1,1); } + + return false; } private static bool GetIsRunningOnMonoInterpreter() diff --git a/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj b/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj index 559cca7f20346b..b9207224c8709d 100644 --- a/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj +++ b/src/libraries/Common/tests/TestUtilities/TestUtilities.csproj @@ -11,6 +11,7 @@ + @@ -32,47 +33,35 @@ - - Common\Interop\Windows\Kernel32\Interop.GetCurrentProcess_IntPtr.cs - - - Common\Interop\Windows\NtDll\Interop.RtlGetVersion.cs - - - Common\Interop\Windows\Advapi32\Interop.OpenProcessToken_SafeAccessTokenHandle.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Kernel32\Interop.CloseHandle.cs - - - Common\Interop\Windows\Advapi32\Interop.TOKEN_INFORMATION_CLASS.cs - - - Common\Interop\Windows\Advapi32\Interop.GetTokenInformation_void.cs - - - Common\Interop\Windows\Advapi32\Interop.TOKEN_ELEVATION.cs - - - Common\Interop\Windows\Interop.BOOL.cs - + + + + + + + + + - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs - - - Common\Interop\Unix\Interop.GetEUid.cs - + + - diff --git a/src/libraries/Common/tests/Tests/Interop/cgroupsTests.cs b/src/libraries/Common/tests/Tests/Interop/cgroupsTests.cs index fc6ab5c9753ce4..a40713ed36899a 100644 --- a/src/libraries/Common/tests/Tests/Interop/cgroupsTests.cs +++ b/src/libraries/Common/tests/Tests/Interop/cgroupsTests.cs @@ -9,6 +9,12 @@ namespace Common.Tests { public class cgroupsTests : FileCleanupTestBase { + [Fact] + public void ValidateFindCGroupVersion() + { + Assert.InRange((int)Interop.cgroups.s_cgroupVersion, 0, 2); + } + [Theory] [InlineData(true, "0", 0)] [InlineData(false, "max", 0)] @@ -27,48 +33,57 @@ public void ValidateTryReadMemoryValue(bool expectedResult, string valueText, ul } [Theory] - [InlineData(false, "0 0 0:0 / /foo ignore ignore - overlay overlay ignore", "ignore", 0, "/", "/")] - [InlineData(true, "0 0 0:0 / /foo ignore ignore - cgroup2 cgroup2 ignore", "ignore", 2, "/", "/foo")] - [InlineData(true, "0 0 0:0 / /foo ignore ignore - cgroup2 cgroup2 ignore", "memory", 2, "/", "/foo")] - [InlineData(true, "0 0 0:0 / /foo ignore ignore - cgroup2 cgroup2 ignore", "cpu", 2, "/", "/foo")] - [InlineData(true, "0 0 0:0 / /foo ignore - cgroup2 cgroup2 ignore", "cpu", 2, "/", "/foo")] - [InlineData(true, "0 0 0:0 / /foo ignore ignore ignore - cgroup2 cgroup2 ignore", "cpu", 2, "/", "/foo")] - [InlineData(true, "0 0 0:0 / /foo-with-dashes ignore ignore - cgroup2 cgroup2 ignore", "ignore", 2, "/", "/foo-with-dashes")] - [InlineData(true, "0 0 0:0 / /foo ignore ignore - cgroup cgroup memory", "memory", 1, "/", "/foo")] - [InlineData(true, "0 0 0:0 / /foo-with-dashes ignore ignore - cgroup cgroup memory", "memory", 1, "/", "/foo-with-dashes")] - [InlineData(true, "0 0 0:0 / /foo ignore ignore - cgroup cgroup cpu,memory", "memory", 1, "/", "/foo")] - [InlineData(true, "0 0 0:0 / /foo ignore ignore - cgroup cgroup memory,cpu", "memory", 1, "/", "/foo")] - [InlineData(false, "0 0 0:0 / /foo ignore ignore - cgroup cgroup cpu", "memory", 0, "/", "/foo")] - public void ParseValidateMountInfo(bool expectedFound, string procSelfMountInfoText, string subsystem, int expectedVersion, string expectedRoot, string expectedMount) + [InlineData("/sys/fs/cgroup/cpu/my_cgroup", "/docker/1234", "/sys/fs/cgroup/cpu", "/docker/1234/my_cgroup")] + [InlineData("/sys/fs/cgroup/cpu/my_cgroup", "/", "/sys/fs/cgroup/cpu", "/my_cgroup")] + public void ValidateFindCGroupPath(string expectedResult, string hierarchyRoot, string hierarchyMount, string cgroupPathRelativeToMount) + { + Assert.Equal(expectedResult, Interop.cgroups.FindCGroupPath(hierarchyRoot, hierarchyMount, cgroupPathRelativeToMount)); + } + + [Theory] + [InlineData(true, 2, "0 0 0:0 / /foo ignore ignore - cgroup2 cgroup2 ignore", "ignore", "/", "/foo")] + [InlineData(true, 2, "0 0 0:0 / /foo ignore ignore - cgroup2 cgroup2 ignore", "memory", "/", "/foo")] + [InlineData(true, 2, "0 0 0:0 / /foo ignore ignore - cgroup2 cgroup2 ignore", "cpu", "/", "/foo")] + [InlineData(true, 2, "0 0 0:0 / /foo ignore - cgroup2 cgroup2 ignore", "cpu", "/", "/foo")] + [InlineData(true, 2, "0 0 0:0 / /foo ignore ignore ignore - cgroup2 cgroup2 ignore", "cpu", "/", "/foo")] + [InlineData(true, 2, "0 0 0:0 / /foo-with-dashes ignore ignore - cgroup2 cgroup2 ignore", "ignore", "/", "/foo-with-dashes")] + [InlineData(true, 1, "0 0 0:0 / /foo ignore ignore - cgroup cgroup memory", "memory", "/", "/foo")] + [InlineData(true, 1, "0 0 0:0 / /foo-with-dashes ignore ignore - cgroup cgroup memory", "memory", "/", "/foo-with-dashes")] + [InlineData(true, 1, "0 0 0:0 / /foo ignore ignore - cgroup cgroup cpu,memory", "memory", "/", "/foo")] + [InlineData(true, 1, "0 0 0:0 / /foo ignore ignore - cgroup cgroup memory,cpu", "memory", "/", "/foo")] + public void ParseValidateMountInfo(bool expectedFound, int cgroupVersion, string procSelfMountInfoText, string subsystem, string expectedRoot, string expectedMount) { string path = GetTestFilePath(); File.WriteAllText(path, procSelfMountInfoText); - Assert.Equal(expectedFound, Interop.cgroups.TryFindHierarchyMount(path, subsystem, out Interop.cgroups.CGroupVersion version, out string root, out string mount)); + Assert.Equal(expectedFound, Interop.cgroups.TryFindHierarchyMount((Interop.cgroups.CGroupVersion) cgroupVersion, + path, subsystem, out string root, out string mount)); if (expectedFound) { - Assert.Equal(expectedVersion, (int)version); Assert.Equal(expectedRoot, root); Assert.Equal(expectedMount, mount); } } [Theory] - [InlineData(true, "0::/foo", "ignore", "/foo")] - [InlineData(true, "0::/bar", "ignore", "/bar")] - [InlineData(true, "0::frob", "ignore", "frob")] - [InlineData(false, "1::frob", "ignore", "ignore")] - [InlineData(true, "1:foo:bar", "foo", "bar")] - [InlineData(true, "2:foo:bar", "foo", "bar")] - [InlineData(false, "2:foo:bar", "bar", "ignore")] - [InlineData(true, "1:foo:bar\n2:eggs:spam", "foo", "bar")] - [InlineData(true, "1:foo:bar\n2:eggs:spam", "eggs", "spam")] - public void ParseValidateProcCGroup(bool expectedFound, string procSelfCgroupText, string subsystem, string expectedMountPath) + [InlineData(true, 2, "0::/foo", "ignore", "/foo")] + [InlineData(true, 2, "0::/bar", "ignore", "/bar")] + [InlineData(true, 2, "0::frob", "ignore", "frob")] + [InlineData(false, 1, "1::frob", "ignore", "ignore")] + [InlineData(true, 1, "1:foo:bar", "foo", "bar")] + [InlineData(true, 1, "0::baz\n1:foo:bar", "foo", "bar")] + [InlineData(true, 1, "2:foo:bar", "foo", "bar")] + [InlineData(false, 1, "2:foo:bar", "bar", "ignore")] + [InlineData(true, 1, "1:foo:bar\n2:eggs:spam", "foo", "bar")] + [InlineData(true, 1, "1:foo:bar\n2:eggs:spam", "eggs", "spam")] + [InlineData(true, 1, "2:eggs:spam\n0:foo:bar", "eggs", "spam")] + public void ParseValidateProcCGroup(bool expectedFound, int cgroupVersion, string procSelfCgroupText, string subsystem, string expectedMountPath) { string path = GetTestFilePath(); File.WriteAllText(path, procSelfCgroupText); - Assert.Equal(expectedFound, Interop.cgroups.TryFindCGroupPathForSubsystem(path, subsystem, out string mountPath)); + Assert.Equal(expectedFound, Interop.cgroups.TryFindCGroupPathForSubsystem((Interop.cgroups.CGroupVersion) cgroupVersion, + path, subsystem, out string mountPath)); if (expectedFound) { Assert.Equal(expectedMountPath, mountPath); diff --git a/src/libraries/Common/tests/Tests/System/StringTests.cs b/src/libraries/Common/tests/Tests/System/StringTests.cs index 18f494d9440e4d..078765651b3faa 100644 --- a/src/libraries/Common/tests/Tests/System/StringTests.cs +++ b/src/libraries/Common/tests/Tests/System/StringTests.cs @@ -12,6 +12,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.DotNet.RemoteExecutor; +using Microsoft.DotNet.XUnitExtensions; using Xunit; #pragma warning disable xUnit2009 // these are the tests for String and so should be using the explicit methods on String @@ -1678,8 +1679,10 @@ public static void EndsWith_StringComparison(string s, string value, StringCompa Assert.Equal(expected, s.AsSpan().EndsWith(value.AsSpan(), comparisonType)); } - [Theory] - [ActiveIssue("https://github.com/dotnet/runtime/issues/4673", TestPlatforms.AnyUnix)] + // NOTE: This is by design. ICU ignores the null characters (i.e. null characters have no weights for the string comparison). + // For desired behavior, use ordinal comparison instead of linguistic comparison. + // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673). + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] [InlineData(StringComparison.CurrentCulture)] [InlineData(StringComparison.CurrentCultureIgnoreCase)] [InlineData(StringComparison.Ordinal)] @@ -1699,11 +1702,10 @@ public static void EndsWith_NullInStrings(StringComparison comparison) Assert.False("test".AsSpan().EndsWith("\0st".AsSpan(), comparison)); } - // NOTE: This is by design. Unix ignores the null characters (i.e. null characters have no weights for the string comparison). + // NOTE: This is by design. ICU ignores the null characters (i.e. null characters have no weights for the string comparison). // For desired behavior, use ordinal comparison instead of linguistic comparison. - // This is a known difference between Windows and Unix (https://github.com/dotnet/runtime/issues/4673). - [Theory] - [PlatformSpecific(TestPlatforms.Windows)] + // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673). + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] [InlineData(StringComparison.InvariantCulture)] [InlineData(StringComparison.InvariantCultureIgnoreCase)] public static void EndsWith_NullInStrings_NonOrdinal(StringComparison comparison) @@ -1862,11 +1864,11 @@ public static void EndsWithNoMatch_Char() string s1 = new string(first); string s2 = new string(second); - //On Linux there are some characters in the range of 0~32 which has a sort weight. - //For example null character on Linux will be ignored if it is compared to anything - //while on Windows null will be always compared as ordinal. - //For desired behavior, use ordinal comparison instead of linguistic comparison. - //This is a known difference between Windows and Unix (https://github.com/dotnet/runtime/issues/4673). + // On ICU there are some characters in the range of 0~32 which have a sort weight. + // For example null character on ICU will be ignored if it is compared to anything + // while on NLS null will be always compared as ordinal. + // For desired behavior, use ordinal comparison instead of linguistic comparison. + // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673). bool b = s1.EndsWith(s2, StringComparison.Ordinal); Assert.False(b); @@ -2514,7 +2516,15 @@ public static void EqualsTest(string s1, object obj, StringComparison comparison Assert.Equal(s1.GetHashCode(), s1.GetHashCode()); } - Assert.Equal(expected, s1.AsSpan().Equals(s2.AsSpan(), comparisonType)); + if (string.IsNullOrEmpty(s1) && string.IsNullOrEmpty(s2)) + { + // null strings are normalized to empty spans + Assert.True(s1.AsSpan().Equals(s2.AsSpan(), comparisonType)); + } + else + { + Assert.Equal(expected, s1.AsSpan().Equals(s2.AsSpan(), comparisonType)); + } } public static IEnumerable Equals_EncyclopaediaData() @@ -2524,9 +2534,9 @@ public static IEnumerable Equals_EncyclopaediaData() yield return new object[] { StringComparison.Ordinal, false }; yield return new object[] { StringComparison.OrdinalIgnoreCase, false }; - // Windows and ICU disagree about how these strings compare in the default locale. - yield return new object[] { StringComparison.InvariantCulture, PlatformDetection.IsWindows }; - yield return new object[] { StringComparison.InvariantCultureIgnoreCase, PlatformDetection.IsWindows }; + // NLS and ICU disagree about how these strings compare in the default locale. + yield return new object[] { StringComparison.InvariantCulture, PlatformDetection.IsNlsGlobalization }; + yield return new object[] { StringComparison.InvariantCultureIgnoreCase, PlatformDetection.IsNlsGlobalization }; } [Theory] @@ -2616,7 +2626,7 @@ public static void Format_Invalid() #pragma warning restore IDE0043 // Format string contains invalid placeholder } - [Theory] + [ConditionalTheory] [InlineData("Hello", 'l', 0, 5, 2)] [InlineData("Hello", 'x', 0, 5, -1)] [InlineData("Hello", 'l', 1, 4, 2)] @@ -2628,9 +2638,7 @@ public static void Format_Invalid() [InlineData("Hello", 'l', 0, 3, 2)] [InlineData("Hello", 'o', 5, 0, -1)] [InlineData("H" + SoftHyphen + "ello", 'e', 0, 3, 2)] - // For some reason, this is failing on *nix with ordinal comparisons. - // Possibly related issue: https://github.com/dotnet/runtime/issues/4673 - // [InlineData("Hello", '\0', 0, 5, -1)] // .NET strings are terminated with a null character, but they should not be included as part of the string + [InlineData("Hello", '\0', 0, 5, -1)] // .NET strings are terminated with a null character, but they should not be included as part of the string [InlineData("\ud800\udfff", '\ud800', 0, 1, 0)] // Surrogate characters [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'A', 0, 26, 0)] [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'B', 1, 25, 1)] @@ -2668,6 +2676,14 @@ public static void Format_Invalid() [InlineData("", 'H', 0, 0, -1)] public static void IndexOf_SingleLetter(string s, char target, int startIndex, int count, int expected) { + // This is by design. ICU ignores the null characters (i.e. null characters have no weights for the string comparison). + // For desired behavior, use ordinal comparison instead of linguistic comparison. + // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673). + if (target == '\0' && PlatformDetection.IsIcuGlobalization) + { + throw new SkipTestException("Target \\0 is not supported in ICU"); + } + bool safeForCurrentCulture = IsSafeForCurrentCultureComparisons(s) && IsSafeForCurrentCultureComparisons(target.ToString()); @@ -2774,8 +2790,10 @@ private static bool IsSafeForCurrentCultureComparisons(string str) return true; } - [Theory] - [ActiveIssue("https://github.com/dotnet/runtime/issues/4673", TestPlatforms.AnyUnix)] + // NOTE: This is by design. ICU ignores the null characters (i.e. null characters have no weights for the string comparison). + // For desired behavior, use ordinal comparison instead of linguistic comparison. + // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673). + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] [InlineData("He\0lo", "He\0lo", 0)] [InlineData("He\0lo", "He\0", 0)] [InlineData("He\0lo", "\0", 2)] @@ -2934,14 +2952,14 @@ public static void IndexOf_HungarianDoubleCompression_HungarianCulture() string target = "ddzs"; /* - There are differences between Windows and ICU regarding contractions. - Windows has equal contraction collation weights, including case (target="Ddzs" same behavior as "ddzs"). + There are differences between NLS and ICU regarding contractions. + NLS has equal contraction collation weights, including case (target="Ddzs" same behavior as "ddzs"). ICU has different contraction collation weights, depending on locale collation rules. If CurrentCultureIgnoreCase is specified, ICU will use 'secondary' collation rules which ignore the contraction collation weights (defined as 'tertiary' rules) */ - Assert.Equal(PlatformDetection.IsWindows ? 0 : -1, source.IndexOf(target)); - Assert.Equal(PlatformDetection.IsWindows ? 0 : -1, source.IndexOf(target, StringComparison.CurrentCulture)); + Assert.Equal(PlatformDetection.IsNlsGlobalization ? 0 : -1, source.IndexOf(target)); + Assert.Equal(PlatformDetection.IsNlsGlobalization ? 0 : -1, source.IndexOf(target, StringComparison.CurrentCulture)); Assert.Equal(0, source.IndexOf(target, StringComparison.CurrentCultureIgnoreCase)); Assert.Equal(-1, source.IndexOf(target, StringComparison.Ordinal)); @@ -2949,7 +2967,7 @@ which ignore the contraction collation weights (defined as 'tertiary' rules) ReadOnlySpan span = source.AsSpan(); - Assert.Equal(PlatformDetection.IsWindows ? 0 : -1, span.IndexOf(target.AsSpan(), StringComparison.CurrentCulture)); + Assert.Equal(PlatformDetection.IsNlsGlobalization ? 0 : -1, span.IndexOf(target.AsSpan(), StringComparison.CurrentCulture)); Assert.Equal(0, span.IndexOf(target.AsSpan(), StringComparison.CurrentCultureIgnoreCase)); Assert.Equal(-1, span.IndexOf(target.AsSpan(), StringComparison.Ordinal)); @@ -3861,8 +3879,10 @@ public static void LastIndexOf_Match_SingleLetter() } } - [Theory] - [ActiveIssue("https://github.com/dotnet/runtime/issues/4673", TestPlatforms.AnyUnix)] + // NOTE: This is by design. ICU ignores the null characters (i.e. null characters have no weights for the string comparison). + // For desired behavior, use ordinal comparison instead of linguistic comparison. + // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673). + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] [InlineData("He\0lo", "He\0lo", 0)] [InlineData("He\0lo", "He\0", 0)] [InlineData("He\0lo", "\0", 2)] @@ -4648,8 +4668,10 @@ public static void StartsWith_StringComparison(string s, string value, StringCom Assert.Equal(expected, s.AsSpan().StartsWith(value.AsSpan(), comparisonType)); } - [Theory] - [ActiveIssue("https://github.com/dotnet/runtime/issues/4673", TestPlatforms.AnyUnix)] + // NOTE: This is by design. ICU ignores the null characters (i.e. null characters have no weights for the string comparison). + // For desired behavior, use ordinal comparison instead of linguistic comparison. + // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673). + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] [InlineData(StringComparison.CurrentCulture)] [InlineData(StringComparison.CurrentCultureIgnoreCase)] [InlineData(StringComparison.Ordinal)] @@ -6765,6 +6787,19 @@ public static void StartEndWithTest(string source, string start, string end, str Assert.Equal(expected, source.EndsWith(end, ignoreCase, ci)); } + [Theory] + [InlineData("", StringComparison.InvariantCulture, true)] + [InlineData("", StringComparison.Ordinal, true)] + [InlineData(ZeroWidthJoiner, StringComparison.InvariantCulture, true)] + [InlineData(ZeroWidthJoiner, StringComparison.Ordinal, false)] + public static void StartEndWith_ZeroWeightValue(string value, StringComparison comparison, bool expectedStartsAndEndsWithResult) + { + Assert.Equal(expectedStartsAndEndsWithResult, string.Empty.StartsWith(value, comparison)); + Assert.Equal(expectedStartsAndEndsWithResult, string.Empty.EndsWith(value, comparison)); + Assert.Equal(expectedStartsAndEndsWithResult ? 0 : -1, string.Empty.IndexOf(value, comparison)); + Assert.Equal(expectedStartsAndEndsWithResult ? 0 : -1, string.Empty.LastIndexOf(value, comparison)); + } + [Fact] public static void StartEndNegativeTest() { @@ -7074,11 +7109,10 @@ public static void StartsWithNoMatchNonOrdinal_StringComparison() Assert.False(span.StartsWith(value, StringComparison.InvariantCultureIgnoreCase)); } - // NOTE: This is by design. Unix ignores the null characters (i.e. null characters have no weights for the string comparison). + // NOTE: This is by design. ICU ignores the null characters (i.e. null characters have no weights for the string comparison). // For desired behavior, use ordinal comparison instead of linguistic comparison. - // This is a known difference between Windows and Unix (https://github.com/dotnet/runtime/issues/4673). - [Theory] - [PlatformSpecific(TestPlatforms.Windows)] + // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673). + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] [InlineData(StringComparison.CurrentCulture)] [InlineData(StringComparison.CurrentCultureIgnoreCase)] [InlineData(StringComparison.InvariantCulture)] diff --git a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs new file mode 100644 index 00000000000000..0ee51166fbf294 --- /dev/null +++ b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Linq; +using System.Text; +using System.IO; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +public class WasmTestRunner +{ + public static int Main(string[] args) + { + Console.Write("Args: "); + foreach (string arg in args) + { + Console.Write(arg); + } + Console.WriteLine("."); + + return 0; + } +} diff --git a/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.csproj b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.csproj new file mode 100644 index 00000000000000..7d68c49a196a31 --- /dev/null +++ b/src/libraries/Common/tests/WasmTestRunner/WasmTestRunner.csproj @@ -0,0 +1,11 @@ + + + Exe + enable + $(NetCoreAppCurrent) + + + + + + diff --git a/src/libraries/Directory.Build.props b/src/libraries/Directory.Build.props index 51e21fa9b22897..fca7201e832daa 100644 --- a/src/libraries/Directory.Build.props +++ b/src/libraries/Directory.Build.props @@ -12,21 +12,22 @@ + $(RepositoryEngineeringDir)BeforeTargetFrameworkInference.targets $(RepoRoot)artifacts\toolset\Common\ $([System.Text.RegularExpressions.Regex]::IsMatch($(MSBuildProjectDirectory), 'src%24')) true $(RepositoryEngineeringDir)depProj.common.targets $(LibrariesProjectRoot)OSGroups.json - netcoreapp5.0 + $(NetCoreAppCurrent) false - - $(TargetOS) $(AdditionalBuildTargetFrameworks);$(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-NetBSD;$(NetCoreAppCurrent)-FreeBSD $(RepositoryEngineeringDir)LicenseHeader.txt - + + $(HostRuntimeIdentifier.Remove($(HostRuntimeIdentifier.LastIndexOf('-')))) + @@ -34,21 +35,17 @@ $([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant) arm arm64 - wasm - x64 - x64 - x64 + wasm + x64 x64 - - $(TargetOS.ToLowerInvariant()) - $(TargetOS.ToLowerInvariant()) - $(TargetOS.ToLowerInvariant()) - $(TargetOS.ToLowerInvariant()) + + $(TargetOS.ToLowerInvariant()) Debug + $(TargetFramework) $(BuildTargetFramework)-$(TargetOS)-$(Configuration)-$(TargetArchitecture) @@ -59,10 +56,9 @@ false true - true - false + false @@ -98,7 +94,7 @@ <_portableOS Condition="'$(_runtimeOSFamily)' == 'win' or '$(TargetOS)' == 'Windows_NT'">win <_portableOS Condition="'$(_runtimeOSFamily)' == 'osx'">osx <_portableOS Condition="'$(_runtimeOSFamily)' == 'FreeBSD'">freebsd - <_portableOS Condition="'$(RuntimeOS)' == 'WebAssembly'">webassembly + <_portableOS Condition="'$(RuntimeOS)' == 'Browser'">browser <_portableOS Condition="'$(RuntimeOS)' == 'ios'">ios <_portableOS Condition="'$(RuntimeOS)' == 'tvos'">tvos <_portableOS Condition="'$(RuntimeOS)' == 'android'">android @@ -108,15 +104,15 @@ <_runtimeOS Condition="'$(_runtimeOS)' == 'tizen.5.0.0'">linux <_runtimeOS Condition="'$(PortableBuild)' == 'true'">$(_portableOS) $(_runtimeOS)-x64 - $(_runtimeOS)-$(HostArch) + $(_runtimeOS)-$(HostArch) linux-x64 <_buildingInOSX>$([MSBuild]::IsOSPlatform('OSX')) - win-x64 - osx-x64 - linux-x64 + win-x64 + osx-x64 + linux-x64 win-x64 @@ -172,8 +168,8 @@ $([MSBuild]::NormalizeDirectory('$(ArtifactsObjDir)', '$(MSBuildProjectName)', 'ref')) $([MSBuild]::NormalizeDirectory('$(AssemblyBinDirOutputPath)', 'ref')) - - + + @@ -185,13 +181,10 @@ MicrosoftAspNetCore - + false - - - $(NoWarn);nullable @@ -271,12 +264,17 @@ $(ArtifactsBinDir)pkg\$(NetCoreAppCurrent)\ref $(ArtifactsBinDir)pkg\$(NetCoreAppCurrent)\lib - + $(ArtifactsBinDir)pkg\aspnetcoreapp\ref $(ArtifactsBinDir)pkg\aspnetcoreapp\lib $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'testhost', '$(BuildSettings)')) + $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'lib-runtime-packs', '$(BuildSettings)')) + $([MSBuild]::NormalizeDirectory('$(RuntimePackDir)', 'runtimes', '$(PackageRID)')) + $([MSBuild]::NormalizeDirectory('$(RuntimePackRidDir)', 'lib', '$(NetCoreAppCurrent)')) + $([MSBuild]::NormalizeDirectory('$(RuntimePackRidDir)', 'native')) + runtimes/$(PackageRID) $(ArtifactsObjDir)version.txt @@ -307,6 +305,8 @@ true true + true + $([MSBuild]::NormalizeDirectory('$(TestHostRootPath)', 'shared', 'Microsoft.NETCore.App', '$(ProductVersion)')) $(NETCoreAppTestSharedFrameworkPath) @@ -315,35 +315,35 @@ $(TestHostRuntimePath)PlatformManifest.txt - + - + - + true - true - true + + true + true - - - + + - + - + false @@ -355,12 +355,12 @@ feature unless they explicitly opt in to it. (Source projects explicitly reference their dependencies, so they can't inadvertently take a dependency on it.) --> - + - false + false true diff --git a/src/libraries/Directory.Build.targets b/src/libraries/Directory.Build.targets index 57a36f3db1b165..cad6c2ed4803af 100644 --- a/src/libraries/Directory.Build.targets +++ b/src/libraries/Directory.Build.targets @@ -2,17 +2,11 @@ $([MSBuild]::NormalizeDirectory('$(RefRootPath)', '$(TargetFramework)')) - - - $(TargetOS) - $(Configuration) - $(TargetOS) - $(Configuration) - + $(NoWarn);nullable @@ -26,10 +20,9 @@ Tests which wish to control this should set TestStrongNameKeyId. --> MicrosoftAspNetCore Open - $(TestStrongNameKeyId) + $(TestStrongNameKeyId) - @@ -46,7 +39,7 @@ - true + true true @@ -92,6 +85,23 @@ $(TestHostRootPath) + + + + $(RuntimePackLibDir) + + + + $(RuntimePackNativeDir) + NativeBinPlaceItem + + + + $(TestHostRuntimePath) + TestHostBinPlaceItem + + + $(NetStandard20RefPath) @@ -119,10 +129,10 @@ - - - + + + @@ -137,27 +147,23 @@ - + - <_RefSourceFileOutputPath>$([MSBuild]::NormalizePath('$(MSBuildProjectDirectory)', '..', 'ref', '$(AssemblyName).cs')) <_ExcludeAPIList>$([MSBuild]::NormalizePath('$(MSBuildProjectDirectory)', '..', 'ref', 'ReferenceSourceExcludeApi.txt')) <_ExcludeAttributesList>$(RepositoryEngineeringDir)DefaultGenApiDocIds.txt - <_LicenseHeaderTxtPath>$(RepositoryEngineeringDir)LicenseHeader.txt - - - - <_GenAPICmd>$(_GenAPICommand) - <_GenAPICmd>$(_GenAPICmd) "@(IntermediateAssembly)" - <_GenAPICmd>$(_GenAPICmd) --lib-path "$(RefPath.Trim('\/'))" - <_GenAPICmd>$(_GenAPICmd) --out "$(_RefSourceFileOutputPath)" - <_GenAPICmd>$(_GenAPICmd) --exclude-attributes-list "$(_ExcludeAttributesList)" - <_GenAPICmd Condition="Exists('$(_ExcludeAPIList)')">$(_GenAPICmd) --exclude-api-list "$(_ExcludeAPIList)" - <_GenAPICmd>$(_GenAPICmd) --header-file "$(_LicenseHeaderTxtPath)" - <_GenAPICmd Condition="'$(LangVersion)' != ''">$(_GenAPICmd) --lang-version "$(LangVersion)" + <_LicenseHeaderTxtPath>$(RepositoryEngineeringDir)LicenseHeader.txt + $([MSBuild]::NormalizePath('$(MSBuildProjectDirectory)', '..', 'ref', '$(AssemblyName).cs')) + $(GenAPIAdditionalParameters) --exclude-attributes-list "$(_ExcludeAttributesList)" + $(GenAPIAdditionalParameters) --exclude-api-list "$(_ExcludeAPIList)" + $(GenAPIAdditionalParameters) --header-file "$(_LicenseHeaderTxtPath)" + $(GenAPIAdditionalParameters) --lang-version "$(LangVersion)" + $(GenAPIAdditionalParameters) --follow-type-forwards + - - + + @@ -206,7 +212,7 @@ - + $(DefineConstants),INTERNAL_NULLABLE_ATTRIBUTES diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj b/src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj index 1e0036d0e92c76..dfa421a3900b90 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj +++ b/src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj @@ -1,4 +1,4 @@ - + Microsoft.CSharp Microsoft.CSharp @@ -160,23 +160,18 @@ - - Common\System\Collections\HashHelpers.cs - + - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\OleAut32\Interop.VariantClear.cs - - - Common\System\Runtime\InteropServices\ComEventsSink.cs - - - Common\System\Runtime\InteropServices\ComEventsMethod.cs - + + + + Common\System\Runtime\InteropServices\IDispatch.cs diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComRuntimeHelpers.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComRuntimeHelpers.cs index 7732a965da8967..11bfce9b08dcdf 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComRuntimeHelpers.cs +++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComRuntimeHelpers.cs @@ -342,32 +342,7 @@ public static IntPtr GetIdsOfNamedParameters(IDispatch dispatch, string[] names, private static void EmitLoadArg(ILGenerator il, int index) { Requires.Condition(index >= 0, nameof(index)); - - switch (index) - { - case 0: - il.Emit(OpCodes.Ldarg_0); - break; - case 1: - il.Emit(OpCodes.Ldarg_1); - break; - case 2: - il.Emit(OpCodes.Ldarg_2); - break; - case 3: - il.Emit(OpCodes.Ldarg_3); - break; - default: - if (index <= byte.MaxValue) - { - il.Emit(OpCodes.Ldarg_S, (byte)index); - } - else - { - il.Emit(OpCodes.Ldarg, index); - } - break; - } + il.Emit(OpCodes.Ldarg, index); } private static readonly object s_lock = new object(); @@ -424,7 +399,7 @@ private static IUnknownReleaseDelegate Create_IUnknownRelease() method.Emit(OpCodes.Ret); - return (IUnknownReleaseDelegate)dm.CreateDelegate(typeof(IUnknownReleaseDelegate)); + return dm.CreateDelegate(); } internal static readonly IntPtr s_nullInterfaceId = GetNullInterfaceId(); @@ -526,17 +501,21 @@ private static IDispatchInvokeDelegate Create_IDispatchInvoke(bool returnResult) EmitLoadArg(method, flagsIndex); EmitLoadArg(method, dispParamsIndex); + method.Emit(OpCodes.Conv_I); if (returnResult) { EmitLoadArg(method, resultIndex); + method.Emit(OpCodes.Conv_I); } else { method.Emit(OpCodes.Ldsfld, typeof(IntPtr).GetField(nameof(IntPtr.Zero))); } EmitLoadArg(method, exceptInfoIndex); + method.Emit(OpCodes.Conv_I); EmitLoadArg(method, argErrIndex); + method.Emit(OpCodes.Conv_I); // functionPtr = *(IntPtr*)(*(dispatchPointer) + VTABLE_OFFSET) int idispatchInvokeOffset = ((int)IDispatchMethodIndices.IDispatch_Invoke) * Marshal.SizeOf(typeof(IntPtr)); @@ -560,7 +539,7 @@ private static IDispatchInvokeDelegate Create_IDispatchInvoke(bool returnResult) method.EmitCalli(OpCodes.Calli, CallingConvention.Winapi, typeof(int), invokeParamTypes); method.Emit(OpCodes.Ret); - return (IDispatchInvokeDelegate)dm.CreateDelegate(typeof(IDispatchInvokeDelegate)); + return dm.CreateDelegate(); } #endregion diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/RuntimeBinderExtensions.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/RuntimeBinderExtensions.cs index e08bc7d9b66f24..3cc1e52fb30b4d 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/RuntimeBinderExtensions.cs +++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/RuntimeBinderExtensions.cs @@ -262,7 +262,7 @@ private static bool IsTypeParameterEquivalentToTypeInst(this Type typeParam, Typ modifiers: null); if (apiMethod != null) { - Func apiDelegate = (Func)(apiMethod.CreateDelegate(typeof(Func))); + Func apiDelegate = apiMethod.CreateDelegate>(); try { bool result = apiDelegate(m1, m2); diff --git a/src/libraries/Microsoft.CSharp/tests/Microsoft.CSharp.Tests.csproj b/src/libraries/Microsoft.CSharp/tests/Microsoft.CSharp.Tests.csproj index 443136c7068056..11dfc740701cd9 100644 --- a/src/libraries/Microsoft.CSharp/tests/Microsoft.CSharp.Tests.csproj +++ b/src/libraries/Microsoft.CSharp/tests/Microsoft.CSharp.Tests.csproj @@ -34,7 +34,7 @@ - + \ No newline at end of file diff --git a/src/libraries/Microsoft.Diagnostics.Tracing.EventSource.Redist/tests/Microsoft.Diagnostics.Tracing.EventSource.Redist.Tests.csproj b/src/libraries/Microsoft.Diagnostics.Tracing.EventSource.Redist/tests/Microsoft.Diagnostics.Tracing.EventSource.Redist.Tests.csproj index b3a2a37c488ead..050d2b686d0e75 100644 --- a/src/libraries/Microsoft.Diagnostics.Tracing.EventSource.Redist/tests/Microsoft.Diagnostics.Tracing.EventSource.Redist.Tests.csproj +++ b/src/libraries/Microsoft.Diagnostics.Tracing.EventSource.Redist/tests/Microsoft.Diagnostics.Tracing.EventSource.Redist.Tests.csproj @@ -1,6 +1,5 @@ - $(DefineConstants);FEATURE_ETLEVENTS;FEATURE_EVENTCOUNTER_DISPOSE $(DefineConstants);USE_MDT_EVENTSOURCE true $(NetFrameworkCurrent) diff --git a/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Microsoft.Extensions.Caching.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Microsoft.Extensions.Caching.Abstractions.csproj index 9633abd2b4f74a..911f1f0a34a560 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Microsoft.Extensions.Caching.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Microsoft.Extensions.Caching.Abstractions.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj b/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj index adb6a59860baa2..f1fc6de9692c75 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/Microsoft.Extensions.Caching.Memory.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/tests/AssemblyAttributes.cs b/src/libraries/Microsoft.Extensions.Caching.Memory/tests/AssemblyAttributes.cs new file mode 100644 index 00000000000000..82c60ec93e3098 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/tests/AssemblyAttributes.cs @@ -0,0 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +[assembly: ActiveIssue("https://github.com/dotnet/runtime/issues/35970", TestRuntimes.Mono)] diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/tests/Microsoft.Extensions.Caching.Memory.Tests.csproj b/src/libraries/Microsoft.Extensions.Caching.Memory/tests/Microsoft.Extensions.Caching.Memory.Tests.csproj index 723c7244522e13..5cff85d11fe393 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/tests/Microsoft.Extensions.Caching.Memory.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/tests/Microsoft.Extensions.Caching.Memory.Tests.csproj @@ -6,12 +6,10 @@ - - Common\tests\Extensions\TestingUtils\Microsoft.AspNetCore.Testing\src\ExceptionAssertions.cs - - - Common\tests\Extensions\TestingUtils\Microsoft.AspNetCore.Testing\src\CultureReplacer.cs - + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/Microsoft.Extensions.Configuration.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/Microsoft.Extensions.Configuration.Abstractions.csproj index d22e391d881975..7bbd535f36ab0f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/Microsoft.Extensions.Configuration.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Abstractions/src/Microsoft.Extensions.Configuration.Abstractions.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/Microsoft.Extensions.Configuration.Binder.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/Microsoft.Extensions.Configuration.Binder.csproj index 2c2e03156d12b2..0a40aca7a50947 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/Microsoft.Extensions.Configuration.Binder.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/Microsoft.Extensions.Configuration.Binder.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Microsoft.Extensions.Configuration.Binder.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Microsoft.Extensions.Configuration.Binder.Tests.csproj index df49f6059b5017..2f02865ce4f556 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Microsoft.Extensions.Configuration.Binder.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Microsoft.Extensions.Configuration.Binder.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) @@ -6,12 +6,10 @@ - - Common\ConfigurationProviderExtensions.cs - - - Common\TestStreamHelpers.cs - + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/Microsoft.Extensions.Configuration.CommandLine.csproj b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/Microsoft.Extensions.Configuration.CommandLine.csproj index ac7b708b934808..779f84028323ef 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/Microsoft.Extensions.Configuration.CommandLine.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/src/Microsoft.Extensions.Configuration.CommandLine.csproj @@ -1,4 +1,4 @@ - + netstandard2.0;$(DefaultNetCoreTargetFramework) diff --git a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/tests/Microsoft.Extensions.Configuration.CommandLine.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/tests/Microsoft.Extensions.Configuration.CommandLine.Tests.csproj index 4b9c4ed4aa1a43..6fd320df92dbb2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.CommandLine/tests/Microsoft.Extensions.Configuration.CommandLine.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.CommandLine/tests/Microsoft.Extensions.Configuration.CommandLine.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) @@ -6,15 +6,12 @@ - - Common\ConfigurationProviderTestBase.cs - - - Common\ConfigurationProviderExtensions.cs - - - Common\TestStreamHelpers.cs - + + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/Microsoft.Extensions.Configuration.EnvironmentVariables.csproj b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/Microsoft.Extensions.Configuration.EnvironmentVariables.csproj index 2c2e03156d12b2..0a40aca7a50947 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/Microsoft.Extensions.Configuration.EnvironmentVariables.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/Microsoft.Extensions.Configuration.EnvironmentVariables.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 diff --git a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/tests/Microsoft.Extensions.Configuration.EnvironmentVariables.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/tests/Microsoft.Extensions.Configuration.EnvironmentVariables.Tests.csproj index 74357f4d7bec52..ad7e1cb18d5322 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/tests/Microsoft.Extensions.Configuration.EnvironmentVariables.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/tests/Microsoft.Extensions.Configuration.EnvironmentVariables.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) @@ -6,15 +6,12 @@ - - Common\ConfigurationProviderTestBase.cs - - - Common\ConfigurationProviderExtensions.cs - - - Common\TestStreamHelpers.cs - + + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/Microsoft.Extensions.Configuration.FileExtensions.csproj b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/Microsoft.Extensions.Configuration.FileExtensions.csproj index 029fecf1e5f9b0..798c6584af88c1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/Microsoft.Extensions.Configuration.FileExtensions.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/src/Microsoft.Extensions.Configuration.FileExtensions.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 diff --git a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/tests/Microsoft.Extensions.Configuration.FileExtensions.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/tests/Microsoft.Extensions.Configuration.FileExtensions.Tests.csproj index c7ae00f4a0549d..d3c63062e03880 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/tests/Microsoft.Extensions.Configuration.FileExtensions.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.FileExtensions/tests/Microsoft.Extensions.Configuration.FileExtensions.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) @@ -6,9 +6,8 @@ - - Microsoft.Extensions.Configuration\tests\ConfigurationRootTest.cs - + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/Microsoft.Extensions.Configuration.Ini.csproj b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/Microsoft.Extensions.Configuration.Ini.csproj index 08941f9da565da..bcf7dc105d4de4 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Ini/src/Microsoft.Extensions.Configuration.Ini.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/src/Microsoft.Extensions.Configuration.Ini.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 diff --git a/src/libraries/Microsoft.Extensions.Configuration.Ini/tests/Microsoft.Extensions.Configuration.Ini.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Ini/tests/Microsoft.Extensions.Configuration.Ini.Tests.csproj index 52c2140100327a..ea3ba9cfb77546 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Ini/tests/Microsoft.Extensions.Configuration.Ini.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Ini/tests/Microsoft.Extensions.Configuration.Ini.Tests.csproj @@ -6,15 +6,12 @@ - - Microsoft.Extensions.Configuration\tests\ConfigurationProviderTestBase.cs - - - Microsoft.Extensions.Configuration\tests\Common\ConfigurationProviderExtensions.cs - - - Microsoft.Extensions.Configuration\tests\Common\TestStreamHelpers.cs - + + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Json/src/Microsoft.Extensions.Configuration.Json.csproj b/src/libraries/Microsoft.Extensions.Configuration.Json/src/Microsoft.Extensions.Configuration.Json.csproj index 3639c5abf063a3..edd848567a5c4f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Json/src/Microsoft.Extensions.Configuration.Json.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Json/src/Microsoft.Extensions.Configuration.Json.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);netstandard2.0 @@ -16,7 +16,7 @@ - + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Json/tests/Microsoft.Extensions.Configuration.Json.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Json/tests/Microsoft.Extensions.Configuration.Json.Tests.csproj index ebc496c00800d3..06c4ed8eefcdd3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Json/tests/Microsoft.Extensions.Configuration.Json.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Json/tests/Microsoft.Extensions.Configuration.Json.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) @@ -6,15 +6,12 @@ - - Microsoft.Extensions.Configuration\tests\ConfigurationProviderTestBase.cs - - - Microsoft.Extensions.Configuration\tests\Common\ConfigurationProviderExtensions.cs - - - Microsoft.Extensions.Configuration\tests\Common\TestStreamHelpers.cs - + + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/Microsoft.Extensions.Configuration.UserSecrets.csproj b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/Microsoft.Extensions.Configuration.UserSecrets.csproj index 30f8b84c2aeef1..654d0f9f53be65 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/Microsoft.Extensions.Configuration.UserSecrets.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/Microsoft.Extensions.Configuration.UserSecrets.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);netstandard2.0 @@ -12,7 +12,7 @@ - + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/Microsoft.Extensions.Configuration.Xml.csproj b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/Microsoft.Extensions.Configuration.Xml.csproj index f41429e7e7883a..33d909eeb98384 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/Microsoft.Extensions.Configuration.Xml.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/Microsoft.Extensions.Configuration.Xml.csproj @@ -1,11 +1,11 @@ - + $(NetCoreAppCurrent);netstandard2.0 true - + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/tests/Microsoft.Extensions.Configuration.Xml.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Xml/tests/Microsoft.Extensions.Configuration.Xml.Tests.csproj index b65127b6326679..dfb45ab9f8cecc 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/tests/Microsoft.Extensions.Configuration.Xml.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/tests/Microsoft.Extensions.Configuration.Xml.Tests.csproj @@ -6,33 +6,25 @@ - - Microsoft.Extensions.Configuration\tests\ConfigurationProviderTestBase.cs - - - Microsoft.Extensions.Configuration\tests\Common\ConfigurationProviderExtensions.cs - - - Microsoft.Extensions.Configuration\tests\Common\TestStreamHelpers.cs - - - Common\tests\Extensions\TestingUtils\Microsoft.AspNetCore.Testing\src\ReplaceCulture.cs - - - Common\tests\Extensions\TestingUtils\Microsoft.AspNetCore.Testing\src\xunit\FrameworkSkipConditionAttribute.cs - - - Common\tests\Extensions\TestingUtils\Microsoft.AspNetCore.Testing\src\xunit\ITestCondition.cs - - - Common\tests\Extensions\TestingUtils\Microsoft.AspNetCore.Testing\src\xunit\RuntimeFrameworks.cs - + + + + + + + - - - - Common\tests\Extensions\TestingUtils\Microsoft.AspNetCore.Testing\src\TestPlatformHelper.cs - + + + diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs b/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs index ffc3a406b9f8fd..56802e813c7955 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs +++ b/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs @@ -29,7 +29,7 @@ public ChainedConfigurationProvider(ChainedConfigurationSource source) } if (source.Configuration == null) { - throw new ArgumentNullException(nameof(source.Configuration)); + throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "source.Configuration"), nameof(source)); } _config = source.Configuration; diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/Microsoft.Extensions.Configuration.csproj b/src/libraries/Microsoft.Extensions.Configuration/src/Microsoft.Extensions.Configuration.csproj index da09e22fc90e3f..4a83026e0d99fe 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/src/Microsoft.Extensions.Configuration.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration/src/Microsoft.Extensions.Configuration.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/Resources/Strings.resx b/src/libraries/Microsoft.Extensions.Configuration/src/Resources/Strings.resx index 52fb2be3e50a17..1c4c38af9b51b8 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/src/Resources/Strings.resx +++ b/src/libraries/Microsoft.Extensions.Configuration/src/Resources/Strings.resx @@ -120,4 +120,7 @@ A configuration source is not registered. Please register one before setting a value. + + Null is not a valid value for '{0}'. + \ No newline at end of file diff --git a/src/libraries/Microsoft.Extensions.Configuration/tests/FunctionalTests/Microsoft.Extensions.Configuration.Functional.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration/tests/FunctionalTests/Microsoft.Extensions.Configuration.Functional.Tests.csproj index 38c800ff807a5d..c162152be6bdbd 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/tests/FunctionalTests/Microsoft.Extensions.Configuration.Functional.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration/tests/FunctionalTests/Microsoft.Extensions.Configuration.Functional.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) @@ -6,9 +6,8 @@ - - Common\ConfigurationProviderExtensions.cs - + diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj index a88b34d985e02a..167a6ebd19e972 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -7,18 +7,14 @@ - - Common\src\Extensions\ParameterDefaultValue\ParameterDefaultValue.cs - - - Common\src\Extensions\ActivatorUtilities\ActivatorUtilities.cs - - - Common\src\Extensions\ActivatorUtilities\ActivatorUtilitiesConstructorAttribute.cs - - - Common\src\Extensions\ActivatorUtilities\ObjectFactory.cs - + + + + diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/Microsoft.Extensions.DependencyInjection.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection/src/Microsoft.Extensions.DependencyInjection.csproj index 80589409dba6b0..50cdcabc140e56 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/Microsoft.Extensions.DependencyInjection.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/Microsoft.Extensions.DependencyInjection.csproj @@ -1,34 +1,36 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent);net461;netstandard2.0;netstandard2.1 true - - True - $(DefineConstants);IL_EMIT - False - $(DefineConstants);SAVE_ASSEMBLIES + + + + + True + $(DefineConstants);IL_EMIT + $(DefineConstants);SAVE_ASSEMBLIES - + - + - + @@ -48,12 +50,10 @@ - - Common\src\Extensions\ParameterDefaultValue\ParameterDefaultValue.cs - - - Common\src\Extensions\TypeNameHelper\TypeNameHelper.cs - + + diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Autofac.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Autofac.cs new file mode 100644 index 00000000000000..68fc0f2eaef3c1 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Autofac.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Autofac; +using Autofac.Extensions.DependencyInjection; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public class AutofacDependencyInjectionSpecificationTests: DependencyInjectionSpecificationTests + { + protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) + { + var builder = new ContainerBuilder(); + builder.Populate(serviceCollection); + return new AutofacServiceProvider(builder.Build()); + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/DryIoc.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/DryIoc.cs new file mode 100644 index 00000000000000..ca6238278cc95c --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/DryIoc.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using DryIoc; +using DryIoc.Microsoft.DependencyInjection; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public class DryIocDependencyInjectionSpecificationTests: DependencyInjectionSpecificationTests + { + protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) + { + return new Container() + .WithDependencyInjectionAdapter(serviceCollection) + .BuildServiceProvider(); + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Grace.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Grace.cs new file mode 100644 index 00000000000000..5cfe355fabefa7 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Grace.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Grace.DependencyInjection; +using Grace.DependencyInjection.Extensions; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public class GraceDependencyInjectionSpecificationTests: SkippableDependencyInjectionSpecificationTests + { + public override string[] SkippedTests => new[] + { + "ResolvesMixedOpenClosedGenericsAsEnumerable", + "TypeActivatorWorksWithCtorWithOptionalArgs_WithStructDefaults" + }; + + protected override IServiceProvider CreateServiceProviderImpl(IServiceCollection serviceCollection) + { + return new DependencyInjectionContainer().Populate(serviceCollection); + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Lamar.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Lamar.cs new file mode 100644 index 00000000000000..7e591e1e097127 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Lamar.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public class LamarDependencyInjectionSpecificationTests : SkippableDependencyInjectionSpecificationTests + { + public override string[] SkippedTests => new[] + { + "DisposesInReverseOrderOfCreation", + "ResolvesMixedOpenClosedGenericsAsEnumerable" + }; + + protected override IServiceProvider CreateServiceProviderImpl(IServiceCollection serviceCollection) + { + return Lamar.Container.BuildAsync(serviceCollection).Result; + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/LightInject.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/LightInject.cs new file mode 100644 index 00000000000000..65ab5a605d90eb --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/LightInject.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using Autofac; +using Autofac.Extensions.DependencyInjection; +using LightInject.Microsoft.DependencyInjection; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public class LightInjectDependencyInjectionSpecificationTests: DependencyInjectionSpecificationTests + { + protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) + { + var builder = new ContainerBuilder(); + builder.Populate(serviceCollection); + return serviceCollection.CreateLightInjectServiceProvider(); + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Microsoft.Extensions.DependencyInjection.ExternalContainers.Tests.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Microsoft.Extensions.DependencyInjection.ExternalContainers.Tests.csproj new file mode 100644 index 00000000000000..e229dcd1cadccd --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Microsoft.Extensions.DependencyInjection.ExternalContainers.Tests.csproj @@ -0,0 +1,31 @@ + + + + $(NetCoreAppCurrent);$(NetFrameworkCurrent) + true + $(NoWarn);CS8002 + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/SkippableDependencyInjectionSpecificationTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/SkippableDependencyInjectionSpecificationTests.cs new file mode 100644 index 00000000000000..321493bfb16d8a --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/SkippableDependencyInjectionSpecificationTests.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Linq; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public abstract class SkippableDependencyInjectionSpecificationTests: DependencyInjectionSpecificationTests + { + public abstract string[] SkippedTests { get; } + + + protected sealed override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) + { + foreach (var stackFrame in new StackTrace(1).GetFrames().Take(2)) + { + if (SkippedTests.Contains(stackFrame.GetMethod().Name)) + { + // We skip tests by returning MEDI service provider that we know passes the test + return serviceCollection.BuildServiceProvider(); + } + } + + return CreateServiceProviderImpl(serviceCollection); + } + + protected abstract IServiceProvider CreateServiceProviderImpl(IServiceCollection serviceCollection); + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/StashBox.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/StashBox.cs new file mode 100644 index 00000000000000..b9f469a528e5de --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/StashBox.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public class StashBoxDependencyInjectionSpecificationTests: DependencyInjectionSpecificationTests + { + protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) + { + return serviceCollection.UseStashbox(); + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/StructureMap.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/StructureMap.cs new file mode 100644 index 00000000000000..66803d35c869c1 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/StructureMap.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using StructureMap; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public class StructureMapDependencyInjectionSpecificationTests: SkippableDependencyInjectionSpecificationTests + { + public override string[] SkippedTests => new[] + { + "DisposesInReverseOrderOfCreation", + "ResolvesMixedOpenClosedGenericsAsEnumerable" + }; + + protected override IServiceProvider CreateServiceProviderImpl(IServiceCollection serviceCollection) + { + var container = new Container(); + container.Configure(config => + { + config.Populate(serviceCollection); + }); + + return container.GetInstance(); + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Unity.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Unity.cs new file mode 100644 index 00000000000000..eb101bc209615f --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.External.Tests/Unity.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.Extensions.DependencyInjection.Specification +{ + public class UnityDependencyInjectionSpecificationTests: SkippableDependencyInjectionSpecificationTests + { + public override string[] SkippedTests => new[] + { + "SingletonServiceCanBeResolvedFromScope" + }; + + protected override IServiceProvider CreateServiceProviderImpl(IServiceCollection serviceCollection) + { + return Unity.Microsoft.DependencyInjection.ServiceProviderExtensions.BuildServiceProvider(serviceCollection); + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ActivatorUtilitiesTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ActivatorUtilitiesTests.cs index d653a671f1ce91..769d47a0165b89 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ActivatorUtilitiesTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/ActivatorUtilitiesTests.cs @@ -41,6 +41,7 @@ public static IEnumerable CreateInstanceFuncs [Theory] [MemberData(nameof(CreateInstanceFuncs))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void TypeActivatorEnablesYouToCreateAnyTypeWithServicesEvenWhenNotInIocContainer(CreateInstanceFunc createFunc) { // Arrange @@ -55,6 +56,7 @@ public void TypeActivatorEnablesYouToCreateAnyTypeWithServicesEvenWhenNotInIocCo [Theory] [MemberData(nameof(CreateInstanceFuncs))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void TypeActivatorAcceptsAnyNumberOfAdditionalConstructorParametersToProvide(CreateInstanceFunc createFunc) { // Arrange @@ -119,6 +121,7 @@ public void TypeActivatorWorksWithCtorWithOptionalArgs_WithStructDefaults(Create [Theory] [MemberData(nameof(CreateInstanceFuncs))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void TypeActivatorCanDisambiguateConstructorsWithUniqueArguments(CreateInstanceFunc createFunc) { // Arrange @@ -267,6 +270,7 @@ public void TypeActivatorThrowsWhenMarkedCtorDoesntAcceptArguments(CreateInstanc } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void GetServiceOrCreateInstanceRegisteredServiceTransient() { // Reset the count because test order is not guaranteed @@ -293,6 +297,7 @@ public void GetServiceOrCreateInstanceRegisteredServiceTransient() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void GetServiceOrCreateInstanceRegisteredServiceSingleton() { lock (CreationCountFakeService.InstanceLock) @@ -320,6 +325,7 @@ public void GetServiceOrCreateInstanceRegisteredServiceSingleton() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void GetServiceOrCreateInstanceUnregisteredService() { lock (CreationCountFakeService.InstanceLock) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/DependencyInjectionSpecificationTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/DependencyInjectionSpecificationTests.cs index beed0c8661e4b8..0e71e3c15624ef 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/DependencyInjectionSpecificationTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Specification.Tests/DependencyInjectionSpecificationTests.cs @@ -32,6 +32,7 @@ public void ServicesRegisteredWithImplementationTypeCanBeResolved() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void ServicesRegisteredWithImplementationType_ReturnDifferentInstancesPerResolution_ForTransientServices() { // Arrange @@ -84,6 +85,7 @@ public void ServiceInstanceCanBeResolved() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void TransientServiceCanBeResolvedFromProvider() { // Arrange @@ -101,6 +103,7 @@ public void TransientServiceCanBeResolvedFromProvider() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void TransientServiceCanBeResolvedFromScope() { // Arrange @@ -191,6 +194,7 @@ public void MultipleServiceCanBeIEnumerableResolved() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void RegistrationOrderIsPreservedWhenServicesAreIEnumerableResolved() { // Arrange @@ -267,6 +271,7 @@ public void FactoryServicesCanBeCreatedByGetService() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void FactoryServicesAreCreatedAsPartOfCreatingObjectGraph() { // Arrange @@ -311,6 +316,7 @@ public void FactoryServicesAreCreatedAsPartOfCreatingObjectGraph() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void LastServiceReplacesPreviousServices() { // Arrange @@ -358,6 +364,7 @@ public void ServiceProviderRegistersServiceScopeFactory() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void ScopedServiceCanBeResolved() { // Arrange @@ -379,6 +386,7 @@ public void ScopedServiceCanBeResolved() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void NestedScopedServiceCanBeResolved() { // Arrange @@ -401,6 +409,7 @@ public void NestedScopedServiceCanBeResolved() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void ScopedServices_FromCachedScopeFactory_CanBeResolvedAndDisposed() { // Arrange @@ -436,6 +445,7 @@ public void ScopedServices_FromCachedScopeFactory_CanBeResolvedAndDisposed() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void DisposingScopeDisposesService() { // Arrange @@ -542,6 +552,7 @@ public void SingletonServicesComeFromRootProvider() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void NestedScopedServiceCanBeResolvedWithNoFallbackProvider() { // Arrange @@ -671,6 +682,7 @@ public static TheoryData ServiceContainerPicksConstructorWithLongestMatchesData [Theory] [MemberData(nameof(ServiceContainerPicksConstructorWithLongestMatchesData))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void ServiceContainerPicksConstructorWithLongestMatches( IServiceCollection serviceCollection, TypeWithSupersetConstructors expected) @@ -747,6 +759,7 @@ public void ResolvesMixedOpenClosedGenericsAsEnumerable() [InlineData(typeof(IFakeService), typeof(FakeService), typeof(IFakeService), ServiceLifetime.Singleton)] [InlineData(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>), typeof(IFakeOpenGenericService), ServiceLifetime.Scoped)] [InlineData(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>), typeof(IFakeOpenGenericService), ServiceLifetime.Singleton)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/33894", TestRuntimes.Mono)] public void ResolvesDifferentInstancesForServiceWhenResolvingEnumerable(Type serviceType, Type implementation, Type resolve, ServiceLifetime lifetime) { // Arrange diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/CallSiteTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/CallSiteTests.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/CallSiteTests.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/CallSiteTests.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/CircularDependencyTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/CircularDependencyTests.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/CircularDependencyTests.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/CircularDependencyTests.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DependencyInjectionEventSourceTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/DependencyInjectionEventSourceTests.cs similarity index 99% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/DependencyInjectionEventSourceTests.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/DependencyInjectionEventSourceTests.cs index 99b8a6ad7e8588..ddbde7bc46d993 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DependencyInjectionEventSourceTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/DependencyInjectionEventSourceTests.cs @@ -193,6 +193,7 @@ public void EmitsExpressionTreeBuiltEvent() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/35753", TestPlatforms.Windows)] public void EmitsDynamicMethodBuiltEvent() { // Arrange diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/AbstractClass.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/AbstractClass.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/AbstractClass.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/AbstractClass.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/DependencyOnCircularDependency.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/DependencyOnCircularDependency.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/DependencyOnCircularDependency.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/DependencyOnCircularDependency.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/DirectCircularDependencyA.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/DirectCircularDependencyA.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/DirectCircularDependencyA.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/DirectCircularDependencyA.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/DirectCircularDependencyB.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/DirectCircularDependencyB.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/DirectCircularDependencyB.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/DirectCircularDependencyB.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/ISelfCircularDependencyWithInterface.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/ISelfCircularDependencyWithInterface.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/ISelfCircularDependencyWithInterface.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/ISelfCircularDependencyWithInterface.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/IndirectCircularDependencyA.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/IndirectCircularDependencyA.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/IndirectCircularDependencyA.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/IndirectCircularDependencyA.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/IndirectCircularDependencyB.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/IndirectCircularDependencyB.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/IndirectCircularDependencyB.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/IndirectCircularDependencyB.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/IndirectCircularDependencyC.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/IndirectCircularDependencyC.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/IndirectCircularDependencyC.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/IndirectCircularDependencyC.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/NoCircularDependencySameTypeMultipleTimesA.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/NoCircularDependencySameTypeMultipleTimesA.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/NoCircularDependencySameTypeMultipleTimesA.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/NoCircularDependencySameTypeMultipleTimesA.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/NoCircularDependencySameTypeMultipleTimesB.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/NoCircularDependencySameTypeMultipleTimesB.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/NoCircularDependencySameTypeMultipleTimesB.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/NoCircularDependencySameTypeMultipleTimesB.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/NoCircularDependencySameTypeMultipleTimesC.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/NoCircularDependencySameTypeMultipleTimesC.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/NoCircularDependencySameTypeMultipleTimesC.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/NoCircularDependencySameTypeMultipleTimesC.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/SelfCircularDependency.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/SelfCircularDependency.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/SelfCircularDependency.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/SelfCircularDependency.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/SelfCircularDependencyGeneric.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/SelfCircularDependencyGeneric.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/SelfCircularDependencyGeneric.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/SelfCircularDependencyGeneric.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/SelfCircularDependencyWithInterface.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/SelfCircularDependencyWithInterface.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/CircularReferences/SelfCircularDependencyWithInterface.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/CircularReferences/SelfCircularDependencyWithInterface.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/ClassDependsOnPrivateConstructorClass.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/ClassDependsOnPrivateConstructorClass.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/ClassDependsOnPrivateConstructorClass.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/ClassDependsOnPrivateConstructorClass.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/ClassWithNestedReferencesToProvider.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/ClassWithNestedReferencesToProvider.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/ClassWithNestedReferencesToProvider.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/ClassWithNestedReferencesToProvider.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/ClassWithOptionalArgsCtorWithStructs.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/ClassWithOptionalArgsCtorWithStructs.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/ClassWithOptionalArgsCtorWithStructs.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/ClassWithOptionalArgsCtorWithStructs.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/DependOnNonexistentService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/DependOnNonexistentService.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/DependOnNonexistentService.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/DependOnNonexistentService.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/StructFakeMultipleService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/StructFakeMultipleService.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/StructFakeMultipleService.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/StructFakeMultipleService.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/StructFakeService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/StructFakeService.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/StructFakeService.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/StructFakeService.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/StructService.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/StructService.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Fakes/StructService.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Fakes/StructService.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Microsoft.Extensions.DependencyInjection.Tests.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Microsoft.Extensions.DependencyInjection.Tests.csproj new file mode 100644 index 00000000000000..6a2b15545e1608 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Microsoft.Extensions.DependencyInjection.Tests.csproj @@ -0,0 +1,25 @@ + + + + $(NetCoreAppCurrent);$(NetFrameworkCurrent) + true + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceCollectionDescriptorExtensionsTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceCollectionDescriptorExtensionsTests.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceCollectionDescriptorExtensionsTests.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceCollectionDescriptorExtensionsTests.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceCollectionServiceExtensionsTest.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceCollectionServiceExtensionsTest.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceCollectionServiceExtensionsTest.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceCollectionServiceExtensionsTest.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/CallSiteFactoryTest.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/CallSiteFactoryTest.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/CallSiteFactoryTest.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/CallSiteFactoryTest.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithDefaultConstructorParameters.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithDefaultConstructorParameters.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithDefaultConstructorParameters.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithDefaultConstructorParameters.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithEnumerableConstructors.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithEnumerableConstructors.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithEnumerableConstructors.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithEnumerableConstructors.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithGenericServices.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithGenericServices.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithGenericServices.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithGenericServices.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithMultipleParameterizedConstructors.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithMultipleParameterizedConstructors.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithMultipleParameterizedConstructors.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithMultipleParameterizedConstructors.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithNoConstructors.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithNoConstructors.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithNoConstructors.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithNoConstructors.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithNoPublicConstructors.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithNoPublicConstructors.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithNoPublicConstructors.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithNoPublicConstructors.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithNonOverlappedConstructors.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithNonOverlappedConstructors.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithNonOverlappedConstructors.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithNonOverlappedConstructors.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithParameterizedAndNullaryConstructor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithParameterizedAndNullaryConstructor.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithParameterizedAndNullaryConstructor.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithParameterizedAndNullaryConstructor.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithParameterizedConstructor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithParameterizedConstructor.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithParameterizedConstructor.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithParameterizedConstructor.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithParameterlessConstructor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithParameterlessConstructor.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithParameterlessConstructor.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithParameterlessConstructor.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithParameterlessPublicConstructor.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithParameterlessPublicConstructor.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithParameterlessPublicConstructor.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithParameterlessPublicConstructor.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithUnresolvableEnumerableConstructors.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithUnresolvableEnumerableConstructors.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceLookup/Types/TypeWithUnresolvableEnumerableConstructors.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceLookup/Types/TypeWithUnresolvableEnumerableConstructors.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderCompilationTest.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderCompilationTest.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderCompilationTest.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderCompilationTest.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderCompilationTestData.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderCompilationTestData.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderCompilationTestData.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderCompilationTestData.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderContainerTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderContainerTests.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderDefaultContainerTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderDefaultContainerTests.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderDefaultContainerTests.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderDefaultContainerTests.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderDynamicContainerTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderDynamicContainerTests.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderDynamicContainerTests.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderDynamicContainerTests.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderEngineScopeTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderEngineScopeTests.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderEngineScopeTests.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderEngineScopeTests.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderExpressionsContainerTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderExpressionsContainerTests.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderExpressionsContainerTests.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderExpressionsContainerTests.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderILEmitContainerTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderILEmitContainerTests.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderILEmitContainerTests.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderILEmitContainerTests.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderServiceExtensionsTest.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderServiceExtensionsTest.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderServiceExtensionsTest.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderServiceExtensionsTest.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderValidationTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderValidationTests.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceProviderValidationTests.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderValidationTests.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceTableTest.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceTableTest.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/ServiceTableTest.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceTableTest.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Utils/MultiServiceHelpers.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Utils/MultiServiceHelpers.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.DependencyInjection/tests/Utils/MultiServiceHelpers.cs rename to src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/Utils/MultiServiceHelpers.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Microsoft.Extensions.DependencyInjection.Tests.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Microsoft.Extensions.DependencyInjection.Tests.csproj deleted file mode 100644 index 2ce3453a2d2ff6..00000000000000 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/Microsoft.Extensions.DependencyInjection.Tests.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - $(NetCoreAppCurrent);$(NetFrameworkCurrent) - true - - - - - Common\tests\Extensions\TestingUtils\Microsoft.AspNetCore.Testing\src\ExceptionAssertions.cs - - - Common\tests\Extensions\TestingUtils\Microsoft.AspNetCore.Testing\src\CultureReplacer.cs - - - - - - - - - - - - - diff --git a/src/libraries/Microsoft.Extensions.DependencyModel/ref/Microsoft.Extensions.DependencyModel.csproj b/src/libraries/Microsoft.Extensions.DependencyModel/ref/Microsoft.Extensions.DependencyModel.csproj index 48d24ea1384289..4133d3704eca6f 100644 --- a/src/libraries/Microsoft.Extensions.DependencyModel/ref/Microsoft.Extensions.DependencyModel.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyModel/ref/Microsoft.Extensions.DependencyModel.csproj @@ -1,11 +1,11 @@ - + netstandard2.0;net461;$(NetFrameworkCurrent) - + diff --git a/src/libraries/Microsoft.Extensions.DependencyModel/src/Dependency.cs b/src/libraries/Microsoft.Extensions.DependencyModel/src/Dependency.cs index e60989f77a5c86..6c26416a9359e6 100644 --- a/src/libraries/Microsoft.Extensions.DependencyModel/src/Dependency.cs +++ b/src/libraries/Microsoft.Extensions.DependencyModel/src/Dependency.cs @@ -13,11 +13,11 @@ public Dependency(string name, string version) { if (string.IsNullOrEmpty(name)) { - throw new ArgumentException(nameof(name)); + throw new ArgumentException(null, nameof(name)); } if (string.IsNullOrEmpty(version)) { - throw new ArgumentException(nameof(version)); + throw new ArgumentException(null, nameof(version)); } Name = name; Version = version; diff --git a/src/libraries/Microsoft.Extensions.DependencyModel/src/Library.cs b/src/libraries/Microsoft.Extensions.DependencyModel/src/Library.cs index cef2b76d2c9c97..eb64ac5fc95da6 100644 --- a/src/libraries/Microsoft.Extensions.DependencyModel/src/Library.cs +++ b/src/libraries/Microsoft.Extensions.DependencyModel/src/Library.cs @@ -43,15 +43,15 @@ public Library(string type, { if (string.IsNullOrEmpty(type)) { - throw new ArgumentException(nameof(type)); + throw new ArgumentException(null, nameof(type)); } if (string.IsNullOrEmpty(name)) { - throw new ArgumentException(nameof(name)); + throw new ArgumentException(null, nameof(name)); } if (string.IsNullOrEmpty(version)) { - throw new ArgumentException(nameof(version)); + throw new ArgumentException(null, nameof(version)); } if (dependencies == null) { diff --git a/src/libraries/Microsoft.Extensions.DependencyModel/src/Microsoft.Extensions.DependencyModel.csproj b/src/libraries/Microsoft.Extensions.DependencyModel/src/Microsoft.Extensions.DependencyModel.csproj index dadbc7e0a0d02a..a164401909d9c2 100644 --- a/src/libraries/Microsoft.Extensions.DependencyModel/src/Microsoft.Extensions.DependencyModel.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyModel/src/Microsoft.Extensions.DependencyModel.csproj @@ -1,4 +1,4 @@ - + netstandard2.0;net461;$(NetFrameworkCurrent) true @@ -6,16 +6,15 @@ - - System\Numerics\Hashing\HashHelpers.cs - + - + diff --git a/src/libraries/Microsoft.Extensions.DependencyModel/src/ResourceAssembly.cs b/src/libraries/Microsoft.Extensions.DependencyModel/src/ResourceAssembly.cs index 998789b51001eb..4e754367b7791a 100644 --- a/src/libraries/Microsoft.Extensions.DependencyModel/src/ResourceAssembly.cs +++ b/src/libraries/Microsoft.Extensions.DependencyModel/src/ResourceAssembly.cs @@ -12,11 +12,11 @@ public ResourceAssembly(string path, string locale) { if (string.IsNullOrEmpty(path)) { - throw new ArgumentException(nameof(path)); + throw new ArgumentException(null, nameof(path)); } if (string.IsNullOrEmpty(locale)) { - throw new ArgumentException(nameof(locale)); + throw new ArgumentException(null, nameof(locale)); } Locale = locale; Path = path; @@ -27,4 +27,4 @@ public ResourceAssembly(string path, string locale) public string Path { get; set; } } -} \ No newline at end of file +} diff --git a/src/libraries/Microsoft.Extensions.DependencyModel/src/RuntimeAssembly.cs b/src/libraries/Microsoft.Extensions.DependencyModel/src/RuntimeAssembly.cs index c4e07fe7deb4ba..edf908e9766c6a 100644 --- a/src/libraries/Microsoft.Extensions.DependencyModel/src/RuntimeAssembly.cs +++ b/src/libraries/Microsoft.Extensions.DependencyModel/src/RuntimeAssembly.cs @@ -16,11 +16,11 @@ public RuntimeAssembly(string assemblyName, string path) { if (string.IsNullOrEmpty(assemblyName)) { - throw new ArgumentException(nameof(assemblyName)); + throw new ArgumentException(null, nameof(assemblyName)); } if (string.IsNullOrEmpty(path)) { - throw new ArgumentException(nameof(path)); + throw new ArgumentException(null, nameof(path)); } _assemblyName = assemblyName; Path = path; @@ -45,4 +45,4 @@ public static RuntimeAssembly Create(string path) return new RuntimeAssembly(assemblyName, path); } } -} \ No newline at end of file +} diff --git a/src/libraries/Microsoft.Extensions.DependencyModel/src/RuntimeFallbacks.cs b/src/libraries/Microsoft.Extensions.DependencyModel/src/RuntimeFallbacks.cs index 32b3635c92f669..9ce186d557b6ce 100644 --- a/src/libraries/Microsoft.Extensions.DependencyModel/src/RuntimeFallbacks.cs +++ b/src/libraries/Microsoft.Extensions.DependencyModel/src/RuntimeFallbacks.cs @@ -18,7 +18,7 @@ public RuntimeFallbacks(string runtime, IEnumerable fallbacks) { if (string.IsNullOrEmpty(runtime)) { - throw new ArgumentException(nameof(runtime)); + throw new ArgumentException(null, nameof(runtime)); } if (fallbacks == null) { @@ -28,4 +28,4 @@ public RuntimeFallbacks(string runtime, IEnumerable fallbacks) Fallbacks = fallbacks.ToArray(); } } -} \ No newline at end of file +} diff --git a/src/libraries/Microsoft.Extensions.DependencyModel/src/RuntimeFile.cs b/src/libraries/Microsoft.Extensions.DependencyModel/src/RuntimeFile.cs index 542a5b65a51aae..5777a34dfa2c47 100644 --- a/src/libraries/Microsoft.Extensions.DependencyModel/src/RuntimeFile.cs +++ b/src/libraries/Microsoft.Extensions.DependencyModel/src/RuntimeFile.cs @@ -12,7 +12,7 @@ public RuntimeFile(string path, string assemblyVersion, string fileVersion) { if (string.IsNullOrEmpty(path)) { - throw new ArgumentException(nameof(path)); + throw new ArgumentException(null, nameof(path)); } Path = path; diff --git a/src/libraries/Microsoft.Extensions.DependencyModel/src/TargetInfo.cs b/src/libraries/Microsoft.Extensions.DependencyModel/src/TargetInfo.cs index 0b2f53607b8634..485ff58d3eb23e 100644 --- a/src/libraries/Microsoft.Extensions.DependencyModel/src/TargetInfo.cs +++ b/src/libraries/Microsoft.Extensions.DependencyModel/src/TargetInfo.cs @@ -14,7 +14,7 @@ public TargetInfo(string framework, { if (string.IsNullOrEmpty(framework)) { - throw new ArgumentException(nameof(framework)); + throw new ArgumentException(null, nameof(framework)); } Framework = framework; @@ -32,4 +32,4 @@ public TargetInfo(string framework, public bool IsPortable { get; } } -} \ No newline at end of file +} diff --git a/src/libraries/Microsoft.Extensions.DependencyModel/tests/Microsoft.Extensions.DependencyModel.Tests.csproj b/src/libraries/Microsoft.Extensions.DependencyModel/tests/Microsoft.Extensions.DependencyModel.Tests.csproj index d5c329eb9479a1..997904f57d4d63 100644 --- a/src/libraries/Microsoft.Extensions.DependencyModel/tests/Microsoft.Extensions.DependencyModel.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyModel/tests/Microsoft.Extensions.DependencyModel.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) diff --git a/src/libraries/Microsoft.Extensions.DependencyModel/tests/ReferenceAssemblyResolverTests.cs b/src/libraries/Microsoft.Extensions.DependencyModel/tests/ReferenceAssemblyResolverTests.cs index 99f8fa4ed6c29c..a165d17eacccd0 100644 --- a/src/libraries/Microsoft.Extensions.DependencyModel/tests/ReferenceAssemblyResolverTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyModel/tests/ReferenceAssemblyResolverTests.cs @@ -6,8 +6,6 @@ using System.Collections.Generic; using System.IO; using FluentAssertions; -using Microsoft.DotNet.PlatformAbstractions; -using Microsoft.Extensions.DependencyModel; using Microsoft.Extensions.DependencyModel.Resolution; using Xunit; using F = Microsoft.Extensions.DependencyModel.Tests.TestLibraryFactory; diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/Microsoft.Extensions.FileProviders.Abstractions.csproj b/src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/Microsoft.Extensions.FileProviders.Abstractions.csproj index 6f7344c8ff8cfa..c165dfa6e216ef 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/Microsoft.Extensions.FileProviders.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.FileProviders.Abstractions/src/Microsoft.Extensions.FileProviders.Abstractions.csproj @@ -1,4 +1,4 @@ - + Microsoft.Extensions.FileProviders @@ -7,9 +7,8 @@ - - Common\src\Extensions\EmptyDisposable.cs - + diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Composite/src/Microsoft.Extensions.FileProviders.Composite.csproj b/src/libraries/Microsoft.Extensions.FileProviders.Composite/src/Microsoft.Extensions.FileProviders.Composite.csproj index 75718c41b115be..b9d2299128c3cb 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Composite/src/Microsoft.Extensions.FileProviders.Composite.csproj +++ b/src/libraries/Microsoft.Extensions.FileProviders.Composite/src/Microsoft.Extensions.FileProviders.Composite.csproj @@ -1,4 +1,4 @@ - + Microsoft.Extensions.FileProviders diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Composite/tests/Microsoft.Extensions.FileProviders.Composite.Tests.csproj b/src/libraries/Microsoft.Extensions.FileProviders.Composite/tests/Microsoft.Extensions.FileProviders.Composite.Tests.csproj index ecb606a8b719e8..05183b81816c20 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Composite/tests/Microsoft.Extensions.FileProviders.Composite.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.FileProviders.Composite/tests/Microsoft.Extensions.FileProviders.Composite.Tests.csproj @@ -1,4 +1,4 @@ - + Microsoft.Extensions.FileProviders.Composite diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj index 5f23ebcc600ad6..865c7a92183e88 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj +++ b/src/libraries/Microsoft.Extensions.FileProviders.Physical/src/Microsoft.Extensions.FileProviders.Physical.csproj @@ -1,4 +1,4 @@ - + Microsoft.Extensions.FileProviders @@ -8,12 +8,10 @@ - - Common\src\Extensions\EmptyDisposable.cs - - - Common\src\Extensions\NonCapturingTimer\NonCapturingTimer.cs - + + diff --git a/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/Microsoft.Extensions.FileProviders.Physical.Tests.csproj b/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/Microsoft.Extensions.FileProviders.Physical.Tests.csproj index 8cb5229c139d3e..11edb64eab6906 100644 --- a/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/Microsoft.Extensions.FileProviders.Physical.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.FileProviders.Physical/tests/Microsoft.Extensions.FileProviders.Physical.Tests.csproj @@ -1,4 +1,4 @@ - + Microsoft.Extensions.FileProviders.Physical @@ -7,12 +7,10 @@ - - Common\tests\Extensions\TestingUtils\Microsoft.AspNetCore.Testing\src\xunit\ITestCondition.cs - - - Common\tests\Extensions\TestingUtils\Microsoft.AspNetCore.Testing\src\TaskExtensions.cs - + + diff --git a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/Microsoft.Extensions.FileSystemGlobbing.csproj b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/Microsoft.Extensions.FileSystemGlobbing.csproj index 00d510d0cede57..8fef4c6ac7af68 100644 --- a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/Microsoft.Extensions.FileSystemGlobbing.csproj +++ b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/src/Microsoft.Extensions.FileSystemGlobbing.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -7,9 +7,8 @@ - - Common\src\Extensions\HashCodeCombiner\HashCodeCombiner.cs - + diff --git a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/Microsoft.Extensions.FileSystemGlobbing.Tests.csproj b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/Microsoft.Extensions.FileSystemGlobbing.Tests.csproj index ec30023fd0ec80..80a382c4ba14e4 100644 --- a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/Microsoft.Extensions.FileSystemGlobbing.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/Microsoft.Extensions.FileSystemGlobbing.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) diff --git a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/Microsoft.Extensions.Hosting.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/Microsoft.Extensions.Hosting.Abstractions.csproj index 1996b8d4effcb2..2194698876f88d 100644 --- a/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/Microsoft.Extensions.Hosting.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/Microsoft.Extensions.Hosting.Abstractions.csproj @@ -1,7 +1,7 @@ - netstandard2.0;$(NetCoreAppCurrent) + $(NetCoreAppCurrent);netstandard2.0 $(NoWarn);CS1591 Microsoft.Extensions.Hosting true diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs b/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs index 277995d71b1831..ddfb1feeb450a2 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs @@ -167,7 +167,7 @@ public static IHostBuilder UseConsoleLifetime(this IHostBuilder hostBuilder, Act /// /// The to configure. /// A that can be used to cancel the console. - /// A that only completes when the token is triggeredor shutdown is triggered. + /// A that only completes when the token is triggered or shutdown is triggered. public static Task RunConsoleAsync(this IHostBuilder hostBuilder, CancellationToken cancellationToken = default) { return hostBuilder.UseConsoleLifetime().Build().RunAsync(cancellationToken); @@ -179,7 +179,7 @@ public static Task RunConsoleAsync(this IHostBuilder hostBuilder, CancellationTo /// The to configure. /// The delegate for configuring the . /// A that can be used to cancel the console. - /// A that only completes when the token is triggeredor shutdown is triggered. + /// A that only completes when the token is triggered or shutdown is triggered. public static Task RunConsoleAsync(this IHostBuilder hostBuilder, Action configureOptions, CancellationToken cancellationToken = default) { return hostBuilder.UseConsoleLifetime(configureOptions).Build().RunAsync(cancellationToken); diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/Microsoft.Extensions.Hosting.csproj b/src/libraries/Microsoft.Extensions.Hosting/src/Microsoft.Extensions.Hosting.csproj index c19f0304ca3e18..7dc68b6e59196a 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/src/Microsoft.Extensions.Hosting.csproj +++ b/src/libraries/Microsoft.Extensions.Hosting/src/Microsoft.Extensions.Hosting.csproj @@ -1,7 +1,7 @@ - netstandard2.0;netstandard2.1;$(NetCoreAppCurrent) + $(NetCoreAppCurrent);netstandard2.0;netstandard2.1 $(NoWarn);CS1591 true @@ -30,7 +30,7 @@ - + diff --git a/src/libraries/Microsoft.Extensions.Hosting/tests/FunctionalTests/IntegrationTesting/src/Common/Tfm.cs b/src/libraries/Microsoft.Extensions.Hosting/tests/FunctionalTests/IntegrationTesting/src/Common/Tfm.cs index a52d1424907e43..fd74831782cd27 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/tests/FunctionalTests/IntegrationTesting/src/Common/Tfm.cs +++ b/src/libraries/Microsoft.Extensions.Hosting/tests/FunctionalTests/IntegrationTesting/src/Common/Tfm.cs @@ -14,7 +14,7 @@ public static class Tfm public const string NetCoreApp22 = "netcoreapp2.2"; public const string NetCoreApp30 = "netcoreapp3.0"; public const string NetCoreApp31 = "netcoreapp3.1"; - public const string NetCoreApp50 = "netcoreapp5.0"; + public const string NetCoreApp50 = "net5.0"; public static bool Matches(string tfm1, string tfm2) { diff --git a/src/libraries/Microsoft.Extensions.Hosting/tests/FunctionalTests/Microsoft.Extensions.Hosting.Functional.Tests.csproj b/src/libraries/Microsoft.Extensions.Hosting/tests/FunctionalTests/Microsoft.Extensions.Hosting.Functional.Tests.csproj index 0738e4ca3bbfea..fe116dda28fd30 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/tests/FunctionalTests/Microsoft.Extensions.Hosting.Functional.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Hosting/tests/FunctionalTests/Microsoft.Extensions.Hosting.Functional.Tests.csproj @@ -8,21 +8,16 @@ - - TestingUtils\Microsoft.AspNetCore.Testing\src\TaskExtensions.cs - - - tests\DI.Common\Common\src\LogLevelAttribute.cs - - - tests\DI.Common\Common\src\LogValuesAssert.cs - - - tests\DI.Common\Common\src\XunitLoggerFactoryExtensions.cs - - - tests\DI.Common\Common\src\XunitLoggerProvider.cs - + + + + + diff --git a/src/libraries/Microsoft.Extensions.Hosting/tests/TestApp/Microsoft.Extensions.Hosting.TestApp.csproj b/src/libraries/Microsoft.Extensions.Hosting/tests/TestApp/Microsoft.Extensions.Hosting.TestApp.csproj index f774716ddfe7a8..28b6ff9259f9cc 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/tests/TestApp/Microsoft.Extensions.Hosting.TestApp.csproj +++ b/src/libraries/Microsoft.Extensions.Hosting/tests/TestApp/Microsoft.Extensions.Hosting.TestApp.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) true diff --git a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Microsoft.Extensions.Hosting.Unit.Tests.csproj b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Microsoft.Extensions.Hosting.Unit.Tests.csproj index 287af4c213f48e..af2ed3b68a5c23 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Microsoft.Extensions.Hosting.Unit.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Microsoft.Extensions.Hosting.Unit.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) diff --git a/src/libraries/Microsoft.Extensions.Http/src/Microsoft.Extensions.Http.csproj b/src/libraries/Microsoft.Extensions.Http/src/Microsoft.Extensions.Http.csproj index c8a0848f510662..f059690d68b4fd 100644 --- a/src/libraries/Microsoft.Extensions.Http/src/Microsoft.Extensions.Http.csproj +++ b/src/libraries/Microsoft.Extensions.Http/src/Microsoft.Extensions.Http.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -7,15 +7,12 @@ - - Common\src\Extensions\NonCapturingTimer\NonCapturingTimer.cs - - - Common\src\Extensions\TypeNameHelper\TypeNameHelper.cs - - - Common\src\Extensions\ValueStopwatch\ValueStopwatch.cs - + + + diff --git a/src/libraries/Microsoft.Extensions.Http/tests/Logging/RedactedLogValueIntegrationTest.cs b/src/libraries/Microsoft.Extensions.Http/tests/Logging/RedactedLogValueIntegrationTest.cs index 67ec29684936e4..3b3c122b52fa97 100644 --- a/src/libraries/Microsoft.Extensions.Http/tests/Logging/RedactedLogValueIntegrationTest.cs +++ b/src/libraries/Microsoft.Extensions.Http/tests/Logging/RedactedLogValueIntegrationTest.cs @@ -51,7 +51,7 @@ public async Task RedactHeaderValueWithHeaderList_ValueIsRedactedBeforeLogging() m.EventId == LoggingScopeHttpMessageHandler.Log.EventIds.RequestHeader && m.LoggerName == "System.Net.Http.HttpClient.test.LogicalHandler"; })); - Assert.Equal( + Assert.StartsWith( @"Request Headers: Authorization: * Cache-Control: no-cache @@ -63,7 +63,7 @@ public async Task RedactHeaderValueWithHeaderList_ValueIsRedactedBeforeLogging() m.EventId == LoggingHttpMessageHandler.Log.EventIds.RequestHeader && m.LoggerName == "System.Net.Http.HttpClient.test.ClientHandler"; })); - Assert.Equal( + Assert.StartsWith( @"Request Headers: Authorization: * Cache-Control: no-cache @@ -75,7 +75,7 @@ public async Task RedactHeaderValueWithHeaderList_ValueIsRedactedBeforeLogging() m.EventId == LoggingHttpMessageHandler.Log.EventIds.ResponseHeader && m.LoggerName == "System.Net.Http.HttpClient.test.ClientHandler"; })); - Assert.Equal( + Assert.StartsWith( @"Response Headers: X-Sensitive: * Y-Non-Sensitive: innocuous value @@ -87,7 +87,7 @@ public async Task RedactHeaderValueWithHeaderList_ValueIsRedactedBeforeLogging() m.EventId == LoggingScopeHttpMessageHandler.Log.EventIds.ResponseHeader && m.LoggerName == "System.Net.Http.HttpClient.test.LogicalHandler"; })); - Assert.Equal( + Assert.StartsWith( @"Response Headers: X-Sensitive: * Y-Non-Sensitive: innocuous value @@ -132,7 +132,7 @@ public async Task RedactHeaderValueWithPredicate_ValueIsRedactedBeforeLogging() m.EventId == LoggingScopeHttpMessageHandler.Log.EventIds.RequestHeader && m.LoggerName == "System.Net.Http.HttpClient.test.LogicalHandler"; })); - Assert.Equal( + Assert.StartsWith( @"Request Headers: Authorization: * Cache-Control: no-cache @@ -144,7 +144,7 @@ public async Task RedactHeaderValueWithPredicate_ValueIsRedactedBeforeLogging() m.EventId == LoggingHttpMessageHandler.Log.EventIds.RequestHeader && m.LoggerName == "System.Net.Http.HttpClient.test.ClientHandler"; })); - Assert.Equal( + Assert.StartsWith( @"Request Headers: Authorization: * Cache-Control: no-cache @@ -156,7 +156,7 @@ public async Task RedactHeaderValueWithPredicate_ValueIsRedactedBeforeLogging() m.EventId == LoggingHttpMessageHandler.Log.EventIds.ResponseHeader && m.LoggerName == "System.Net.Http.HttpClient.test.ClientHandler"; })); - Assert.Equal( + Assert.StartsWith( @"Response Headers: X-Sensitive: * Y-Non-Sensitive: innocuous value @@ -168,7 +168,7 @@ public async Task RedactHeaderValueWithPredicate_ValueIsRedactedBeforeLogging() m.EventId == LoggingScopeHttpMessageHandler.Log.EventIds.ResponseHeader && m.LoggerName == "System.Net.Http.HttpClient.test.LogicalHandler"; })); - Assert.Equal( + Assert.StartsWith( @"Response Headers: X-Sensitive: * Y-Non-Sensitive: innocuous value diff --git a/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests.csproj b/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests.csproj index 345634c008664a..81926a709d7b33 100644 --- a/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Http/tests/Microsoft.Extensions.Http.Tests.csproj @@ -6,25 +6,20 @@ - - tests\DI.Common\Common\src\TestSink.cs - - - tests\DI.Common\Common\src\WriteContext.cs - - - tests\DI.Common\Common\src\BeginScopeContext.cs - - - tests\DI.Common\Common\src\ITestSink.cs - - - tests\DI.Common\Common\src\TestLogger.cs - - - tests\DI.Common\Common\src\TestLoggerFactory.cs - - + + + + + + + diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj index 247ee6768e7a8d..b50b22598e5616 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj @@ -7,15 +7,12 @@ - - Common\src\Extensions\TypeNameHelper\TypeNameHelper.cs - - - Common\src\Extensions\Logging\NullExternalScopeProvider.cs - - - Common\src\Extensions\Logging\NullScope.cs - + + + diff --git a/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj b/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj index a3bb2b570f8ae7..d45b23a82569a9 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Configuration/src/Microsoft.Extensions.Logging.Configuration.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);netstandard2.0 @@ -6,12 +6,11 @@ - - Common\Extensions\ProviderAliasUtilities\ProviderAliasUtilities.cs - + - + diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs index c2b9f5e73d3ef5..a2fb5967231b6c 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs @@ -40,7 +40,7 @@ public ConsoleLoggerFormat Format } /// - /// Gets or sets value indicating the minimum level of messaged that would get written to Console.Error. + /// Gets or sets value indicating the minimum level of messages that would get written to Console.Error. /// public LogLevel LogToStandardErrorThreshold { get; set; } = LogLevel.None; diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj index 9bf8ca6491ae0a..204a13c1432525 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);netstandard2.0 @@ -6,7 +6,7 @@ $(NoWarn);CS1591 - + @@ -15,12 +15,10 @@ - - Common\src\Extensions\Logging\NullExternalScopeProvider.cs - - - Common\src\Extensions\Logging\NullScope.cs - + + diff --git a/src/libraries/Microsoft.Extensions.Logging.Debug/src/Microsoft.Extensions.Logging.Debug.csproj b/src/libraries/Microsoft.Extensions.Logging.Debug/src/Microsoft.Extensions.Logging.Debug.csproj index 936305667687c2..4d4d73f32c648c 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Debug/src/Microsoft.Extensions.Logging.Debug.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Debug/src/Microsoft.Extensions.Logging.Debug.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);netstandard2.0 @@ -6,17 +6,15 @@ $(NoWarn);CS1591 - + - - Common\src\Extensions\Logging\NullExternalScopeProvider.cs - - - Common\src\Extensions\Logging\NullScope.cs - + + diff --git a/src/libraries/Microsoft.Extensions.Logging.EventLog/src/Microsoft.Extensions.Logging.EventLog.csproj b/src/libraries/Microsoft.Extensions.Logging.EventLog/src/Microsoft.Extensions.Logging.EventLog.csproj index 930e42aeef4520..f5b1a59103b9c8 100644 --- a/src/libraries/Microsoft.Extensions.Logging.EventLog/src/Microsoft.Extensions.Logging.EventLog.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.EventLog/src/Microsoft.Extensions.Logging.EventLog.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent);net461;netstandard2.0;netstandard2.1 @@ -6,28 +6,26 @@ $(NoWarn);CS1591 - + - + - - + + - - Common\src\Extensions\Logging\NullExternalScopeProvider.cs - - - Common\src\Extensions\Logging\NullScope.cs - + + diff --git a/src/libraries/Microsoft.Extensions.Logging.EventSource/src/Microsoft.Extensions.Logging.EventSource.csproj b/src/libraries/Microsoft.Extensions.Logging.EventSource/src/Microsoft.Extensions.Logging.EventSource.csproj index 9458321aabdfb4..92881fdf9439f0 100644 --- a/src/libraries/Microsoft.Extensions.Logging.EventSource/src/Microsoft.Extensions.Logging.EventSource.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.EventSource/src/Microsoft.Extensions.Logging.EventSource.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);netstandard2.0 @@ -8,12 +8,10 @@ - - Common\src\Extensions\Logging\NullExternalScopeProvider.cs - - - Common\src\Extensions\Logging\NullScope.cs - + + @@ -25,7 +23,7 @@ - + diff --git a/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/Microsoft.Extensions.Logging.EventSource.Tests.csproj b/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/Microsoft.Extensions.Logging.EventSource.Tests.csproj index 08a860a8a580ee..4fa230c5669f79 100644 --- a/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/Microsoft.Extensions.Logging.EventSource.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.EventSource/tests/Microsoft.Extensions.Logging.EventSource.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) diff --git a/src/libraries/Microsoft.Extensions.Logging.TraceSource/src/Microsoft.Extensions.Logging.TraceSource.csproj b/src/libraries/Microsoft.Extensions.Logging.TraceSource/src/Microsoft.Extensions.Logging.TraceSource.csproj index 5fee45899f0ff7..9980467a3404bd 100644 --- a/src/libraries/Microsoft.Extensions.Logging.TraceSource/src/Microsoft.Extensions.Logging.TraceSource.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.TraceSource/src/Microsoft.Extensions.Logging.TraceSource.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);netstandard2.0 @@ -6,7 +6,7 @@ $(NoWarn);CS1591 - + diff --git a/src/libraries/Microsoft.Extensions.Logging/src/Microsoft.Extensions.Logging.csproj b/src/libraries/Microsoft.Extensions.Logging/src/Microsoft.Extensions.Logging.csproj index b97b83142698c2..c8a03b2300a2ce 100644 --- a/src/libraries/Microsoft.Extensions.Logging/src/Microsoft.Extensions.Logging.csproj +++ b/src/libraries/Microsoft.Extensions.Logging/src/Microsoft.Extensions.Logging.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);netstandard2.0 @@ -7,18 +7,15 @@ - - Common\Extensions\ProviderAliasUtilities\ProviderAliasUtilities.cs - - - Common\src\Extensions\Logging\NullExternalScopeProvider.cs - - - Common\src\Extensions\Logging\NullScope.cs - + + + - + diff --git a/src/libraries/Microsoft.Extensions.Logging/tests/Common/Microsoft.Extensions.Logging.Tests.csproj b/src/libraries/Microsoft.Extensions.Logging/tests/Common/Microsoft.Extensions.Logging.Tests.csproj index 0e7e9d287a1201..cec257df2ecaa6 100644 --- a/src/libraries/Microsoft.Extensions.Logging/tests/Common/Microsoft.Extensions.Logging.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Logging/tests/Common/Microsoft.Extensions.Logging.Tests.csproj @@ -6,24 +6,18 @@ - - tests\DI.Common\Common\src\TestSink.cs - - - tests\DI.Common\Common\src\WriteContext.cs - - - tests\DI.Common\Common\src\BeginScopeContext.cs - - - tests\DI.Common\Common\src\ITestSink.cs - - - tests\DI.Common\Common\src\TestLogger.cs - - - tests\DI.Common\Common\src\TestLoggerFactory.cs - + + + + + + diff --git a/src/libraries/Microsoft.Extensions.Logging/tests/DI.Common/Common/tests/Microsoft.Extensions.Logging.Testing.Tests.csproj b/src/libraries/Microsoft.Extensions.Logging/tests/DI.Common/Common/tests/Microsoft.Extensions.Logging.Testing.Tests.csproj index 905b9a874c12d7..420524704ece84 100644 --- a/src/libraries/Microsoft.Extensions.Logging/tests/DI.Common/Common/tests/Microsoft.Extensions.Logging.Testing.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Logging/tests/DI.Common/Common/tests/Microsoft.Extensions.Logging.Testing.Tests.csproj @@ -1,27 +1,21 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) true - - Common\tests\Extensions\TestingUtils\Microsoft.AspNetCore.Testing\src\ShortClassNameAttribute.cs - - - tests\DI.Common\Common\src\LogLevelAttribute.cs - - - tests\DI.Common\Common\src\LogValuesAssert.cs - - - tests\Common\TestLoggerBuilder.cs - - - tests\DI.Common\Common\src\XunitLoggerFactoryExtensions.cs - - - tests\DI.Common\Common\src\XunitLoggerProvider.cs - + + + + + + diff --git a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/Microsoft.Extensions.Options.ConfigurationExtensions.csproj b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/Microsoft.Extensions.Options.ConfigurationExtensions.csproj index de569c7bd8fd90..9feb20a52838a4 100644 --- a/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/Microsoft.Extensions.Options.ConfigurationExtensions.csproj +++ b/src/libraries/Microsoft.Extensions.Options.ConfigurationExtensions/src/Microsoft.Extensions.Options.ConfigurationExtensions.csproj @@ -1,7 +1,7 @@ - + - netstandard2.0;$(NetCoreAppCurrent) + $(NetCoreAppCurrent);netstandard2.0 true @@ -13,7 +13,7 @@ - + diff --git a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/Microsoft.Extensions.Options.DataAnnotations.csproj b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/Microsoft.Extensions.Options.DataAnnotations.csproj index 18a3307bfe228f..8dadd0c88af192 100644 --- a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/Microsoft.Extensions.Options.DataAnnotations.csproj +++ b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/Microsoft.Extensions.Options.DataAnnotations.csproj @@ -1,7 +1,7 @@ - + - netstandard2.0;$(NetCoreAppCurrent) + $(NetCoreAppCurrent);netstandard2.0 true @@ -14,7 +14,7 @@ - + diff --git a/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj b/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj index a2fb7384785946..fcc42385829ffe 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj +++ b/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj @@ -1,7 +1,7 @@ - netstandard2.0;$(NetCoreAppCurrent) + $(NetCoreAppCurrent);netstandard2.0 true @@ -10,7 +10,7 @@ - + diff --git a/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests.csproj b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests.csproj index ec30023fd0ec80..80a382c4ba14e4 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/Microsoft.Extensions.Primitives.csproj b/src/libraries/Microsoft.Extensions.Primitives/src/Microsoft.Extensions.Primitives.csproj index 407d76de016d8e..b5de2b4e6f39d4 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/Microsoft.Extensions.Primitives.csproj +++ b/src/libraries/Microsoft.Extensions.Primitives/src/Microsoft.Extensions.Primitives.csproj @@ -1,13 +1,12 @@ - + $(NetCoreAppCurrent);netcoreapp3.0;netstandard2.0 true true - - Common\src\Extensions\HashCodeCombiner\HashCodeCombiner.cs - + @@ -20,7 +19,7 @@ - + @@ -35,4 +34,4 @@ - \ No newline at end of file + diff --git a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs index 5fe99cb6c188eb..cd71ddc770810d 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/src/StringValues.cs @@ -138,19 +138,20 @@ public string this[int index] { // Take local copy of _values so type checks remain valid even if the StringValues is overwritten in memory var value = _values; - if (index == 0 && value is string str) + if (value is string str) { - return str; + if (index == 0) + { + return str; + } } else if (value != null) { // Not string, not null, can only be string[] return Unsafe.As(value)[index]; // may throw } - else - { - return OutOfBounds(); // throws - } + + return OutOfBounds(); // throws } } diff --git a/src/libraries/Microsoft.Extensions.Primitives/tests/StringValuesTests.cs b/src/libraries/Microsoft.Extensions.Primitives/tests/StringValuesTests.cs index 505d6259daca4b..61f176d469a805 100644 --- a/src/libraries/Microsoft.Extensions.Primitives/tests/StringValuesTests.cs +++ b/src/libraries/Microsoft.Extensions.Primitives/tests/StringValuesTests.cs @@ -345,6 +345,57 @@ public void Enumerator(StringValues stringValues, string[] expected) Assert.False(e2.MoveNext()); } + [Fact] + public void Indexer() + { + StringValues sv; + + // Default empty + sv = default; + Assert.Throws(() => sv[0]); + Assert.Throws(() => sv[-1]); + + // Empty with null string ctor + sv = new StringValues((string)null); + Assert.Throws(() => sv[0]); + Assert.Throws(() => sv[-1]); + + // Empty with null string[] ctor + sv = new StringValues((string[])null); + Assert.Throws(() => sv[0]); + Assert.Throws(() => sv[-1]); + + // Empty with array + sv = Array.Empty(); + Assert.Throws(() => sv[0]); + Assert.Throws(() => sv[-1]); + + // One element with string + sv = "hello"; + Assert.Equal("hello", sv[0]); + Assert.Throws(() => sv[1]); + Assert.Throws(() => sv[-1]); + + // One element with string[] + sv = new string[] { "hello" }; + Assert.Equal("hello", sv[0]); + Assert.Throws(() => sv[1]); + Assert.Throws(() => sv[-1]); + + // One element with string[] containing null + sv = new string[] { null }; + Assert.Null(sv[0]); + Assert.Throws(() => sv[1]); + Assert.Throws(() => sv[-1]); + + // Two elements with string[] + sv = new string[] { "hello", "world" }; + Assert.Equal("hello", sv[0]); + Assert.Equal("world", sv[1]); + Assert.Throws(() => sv[2]); + Assert.Throws(() => sv[-1]); + } + [Theory] [MemberData(nameof(FilledStringValuesWithExpected))] public void IndexOf(StringValues stringValues, string[] expected) diff --git a/src/libraries/Microsoft.IO.Redist/src/Microsoft.IO.Redist.csproj b/src/libraries/Microsoft.IO.Redist/src/Microsoft.IO.Redist.csproj index ca9b170609880b..84e7c08c8965db 100644 --- a/src/libraries/Microsoft.IO.Redist/src/Microsoft.IO.Redist.csproj +++ b/src/libraries/Microsoft.IO.Redist/src/Microsoft.IO.Redist.csproj @@ -9,97 +9,188 @@ annotations - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -117,4 +208,4 @@ - \ No newline at end of file + diff --git a/src/libraries/Microsoft.Win32.Primitives/src/Microsoft.Win32.Primitives.csproj b/src/libraries/Microsoft.Win32.Primitives/src/Microsoft.Win32.Primitives.csproj index 1114cc984bd052..e949b5bddd0d88 100644 --- a/src/libraries/Microsoft.Win32.Primitives/src/Microsoft.Win32.Primitives.csproj +++ b/src/libraries/Microsoft.Win32.Primitives/src/Microsoft.Win32.Primitives.csproj @@ -8,25 +8,21 @@ - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.FormatMessage.cs - + + - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\Interop.Errors.cs - + + - \ No newline at end of file + diff --git a/src/libraries/Microsoft.Win32.Registry.AccessControl/ref/Microsoft.Win32.Registry.AccessControl.csproj b/src/libraries/Microsoft.Win32.Registry.AccessControl/ref/Microsoft.Win32.Registry.AccessControl.csproj index 764e814e8461b4..b33bdeee63c29d 100644 --- a/src/libraries/Microsoft.Win32.Registry.AccessControl/ref/Microsoft.Win32.Registry.AccessControl.csproj +++ b/src/libraries/Microsoft.Win32.Registry.AccessControl/ref/Microsoft.Win32.Registry.AccessControl.csproj @@ -7,10 +7,10 @@ - + - + diff --git a/src/libraries/Microsoft.Win32.Registry.AccessControl/src/Microsoft.Win32.Registry.AccessControl.csproj b/src/libraries/Microsoft.Win32.Registry.AccessControl/src/Microsoft.Win32.Registry.AccessControl.csproj index 519d2cea378044..c237f53d348289 100644 --- a/src/libraries/Microsoft.Win32.Registry.AccessControl/src/Microsoft.Win32.Registry.AccessControl.csproj +++ b/src/libraries/Microsoft.Win32.Registry.AccessControl/src/Microsoft.Win32.Registry.AccessControl.csproj @@ -1,16 +1,18 @@ - Microsoft.Win32.Registry.AccessControl true - true - SR.PlatformNotSupported_RegistryAccessControl netstandard2.0-Windows_NT;netstandard2.0;net461-Windows_NT;$(NetFrameworkCurrent)-Windows_NT true - + + + SR.PlatformNotSupported_RegistryAccessControl + true + + - + diff --git a/src/libraries/Microsoft.Win32.Registry/ref/Microsoft.Win32.Registry.csproj b/src/libraries/Microsoft.Win32.Registry/ref/Microsoft.Win32.Registry.csproj index 460ce738b8d0f2..b8b7036446b5b0 100644 --- a/src/libraries/Microsoft.Win32.Registry/ref/Microsoft.Win32.Registry.csproj +++ b/src/libraries/Microsoft.Win32.Registry/ref/Microsoft.Win32.Registry.csproj @@ -1,16 +1,19 @@ - true netstandard2.0;$(NetFrameworkCurrent);net461 enable + + + true + - + - + diff --git a/src/libraries/Microsoft.Win32.Registry/src/Microsoft.Win32.Registry.csproj b/src/libraries/Microsoft.Win32.Registry/src/Microsoft.Win32.Registry.csproj index c477714db0b9f0..9083620b97eddf 100644 --- a/src/libraries/Microsoft.Win32.Registry/src/Microsoft.Win32.Registry.csproj +++ b/src/libraries/Microsoft.Win32.Registry/src/Microsoft.Win32.Registry.csproj @@ -3,21 +3,22 @@ true $(NoWarn);CS1573 $(DefineConstants);REGISTRY_ASSEMBLY - true - SR.PlatformNotSupported_Registry - $(NoWarn);CA1823 $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix;$(NetFrameworkCurrent)-Windows_NT;netstandard2.0-Windows_NT;netstandard2.0-Unix;netstandard2.0;net461-Windows_NT true true enable - - - Common\Interop\Windows\Advapi32\Interop.RegistryConstants.cs - - - Microsoft\Win32\SafeHandles\SafeRegistryHandle.cs - + + + true + SR.PlatformNotSupported_Registry + $(NoWarn);CA1823 + + + + @@ -29,62 +30,44 @@ - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.Errors.cs - - - Common\Interop\Windows\Interop.FormatMessage.cs - - - Common\Interop\Windows\Interop.RegCloseKey.cs - - - Common\Interop\Windows\Interop.RegConnectRegistry.cs - - - Common\Interop\Windows\Interop.RegCreateKeyEx.cs - - - Common\Interop\Windows\Interop.RegDeleteKeyEx.cs - - - Common\Interop\Windows\Interop.RegDeleteValue.cs - - - Common\Interop\Windows\Interop.RegEnumKeyEx.cs - - - Common\Interop\Windows\Interop.RegEnumValue.cs - - - Common\Interop\Windows\Interop.RegFlushKey.cs - - - Common\Interop\Windows\Interop.RegOpenKeyEx.cs - - - Common\Interop\Windows\Interop.RegQueryInfoKey.cs - - - Common\Interop\Windows\Interop.RegQueryValueEx.cs - - - Common\Interop\Windows\Interop.RegSetValueEx.cs - - - Common\Interop\Windows\Interop.BOOL.cs - - - Common\Interop\Windows\Interop.SECURITY_ATTRIBUTES.cs - + + + + + + + + + + + + + + + + + + - - Microsoft\Win32\SafeHandles\SafeRegistryHandle.Windows.cs - + @@ -92,10 +75,10 @@ - + - + @@ -108,4 +91,4 @@ - + \ No newline at end of file diff --git a/src/libraries/Microsoft.Win32.Registry/tests/Microsoft.Win32.Registry.Tests.csproj b/src/libraries/Microsoft.Win32.Registry/tests/Microsoft.Win32.Registry.Tests.csproj index 0f007343e85222..1323c126075885 100644 --- a/src/libraries/Microsoft.Win32.Registry/tests/Microsoft.Win32.Registry.Tests.csproj +++ b/src/libraries/Microsoft.Win32.Registry/tests/Microsoft.Win32.Registry.Tests.csproj @@ -4,12 +4,10 @@ $(NetCoreAppCurrent)-Windows_NT;$(NetFrameworkCurrent)-Windows_NT - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.RegSetValueEx.cs - + + diff --git a/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj b/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj index bf847da2c572a4..00a2bef840b0fc 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj +++ b/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj @@ -1,13 +1,16 @@ - true netstandard2.0;$(NetFrameworkCurrent);net461 enable + + + true + - + diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj index 9305567a07479f..407a37698931ec 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj @@ -1,134 +1,97 @@ true - true enable - SR.PlatformNotSupported_SystemEvents $(NetCoreAppCurrent)-Windows_NT;netstandard2.0;netcoreapp2.0-Windows_NT;netcoreapp3.0-Windows_NT;net461;$(NetFrameworkCurrent) true true + + + true + SR.PlatformNotSupported_SystemEvents + - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.Errors.cs - - - Common\Interop\Windows\User32\Interop.Constants.cs - - - Common\Interop\Windows\User32\Interop.CreateWindowEx.cs - - - Common\Interop\Windows\User32\Interop.DefWindowProc.cs - - - Common\Interop\Windows\User32\Interop.DestroyWindow.cs - - - Common\Interop\Windows\User32\Interop.DispatchMessage.cs - - - Common\Interop\Windows\User32\Interop.GetClassInfo.cs - - - Common\Interop\Windows\User32\Interop.GetProcessWindowStation.cs - - - Common\Interop\Windows\User32\Interop.GetUserObjectInformation.cs - - - Common\Interop\Windows\User32\Interop.GetWindowThreadProcessId.cs - - - Common\Interop\Windows\User32\Interop.IsWindow.cs - - - Common\Interop\Windows\User32\Interop.KillTimer.cs - - - Common\Interop\Windows\User32\Interop.MSG.cs - - - Common\Interop\Windows\User32\Interop.MsgWaitForMultipleObjectsEx.cs - - - Common\Interop\Windows\User32\Interop.PeekMessage.cs - - - Common\Interop\Windows\User32\Interop.PostMessage.cs - - - Common\Interop\Windows\User32\Interop.RegisterClass.cs - - - Common\Interop\Windows\User32\Interop.RegisterWindowMessage.cs - - - Common\Interop\Windows\User32\Interop.SendMessage.cs - - - Common\Interop\Windows\User32\Interop.SetClassLong.cs - - - Common\Interop\Windows\User32\Interop.SetClassLongPtr.cs - - - Common\Interop\Windows\User32\Interop.SetTimer.cs - - - Common\Interop\Windows\User32\Interop.SetWindowLong.cs - - - Common\Interop\Windows\User32\Interop.SetWindowLongPtr.cs - - - Common\Interop\Windows\User32\Interop.TranslateMessage.cs - - - Common\Interop\Windows\User32\Interop.UnregisterClass.cs - - - Common\Interop\Windows\User32\Interop.USEROBJECTFLAGS.cs - - - Common\Interop\Windows\User32\Interop.WNDCLASS.cs - - - Common\Interop\Windows\User32\Interop.WndProc.cs - - - Common\Interop\Windows\Kernel32\Interop.GetCurrentThreadId.cs - - - Common\Interop\Windows\Kernel32\Interop.GetModuleHandle.cs - - - Common\Interop\Windows\Kernel32\Interop.GetProcAddress.cs - - - Common\Interop\Windows\Kernel32\Interop.LoadLibrary.cs - - - Common\Interop\Windows\Kernel32\Interop.FreeLibrary.cs - - - Common\Interop\Windows\Kernel32\Interop.SetConsoleCtrlHandler.cs - - - Common\Interop\Windows\WtsApi32\Interop.Constants.cs - - - Common\Interop\Windows\WtsApi32\Interop.WTSRegisterSessionNotification.cs - - - Common\Interop\Windows\WtsApi32\Interop.WTSUnRegisterSessionNotification.cs - - - Common\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -150,15 +113,14 @@ - - Common\System\Runtime\InteropServices\SuppressGCTransitionAttribute.internal.cs - + - + - + @@ -171,7 +133,7 @@ - + - \ No newline at end of file + diff --git a/src/libraries/Microsoft.Win32.SystemEvents/tests/Microsoft.Win32.SystemEvents.Tests.csproj b/src/libraries/Microsoft.Win32.SystemEvents/tests/Microsoft.Win32.SystemEvents.Tests.csproj index c536995d9bf272..3faa8abcdbe7da 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/tests/Microsoft.Win32.SystemEvents.Tests.csproj +++ b/src/libraries/Microsoft.Win32.SystemEvents/tests/Microsoft.Win32.SystemEvents.Tests.csproj @@ -3,18 +3,14 @@ $(NetCoreAppCurrent)-Windows_NT;$(NetFrameworkCurrent)-Windows_NT - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\User32\Interop.Constants.cs - - - Common\Interop\Windows\User32\Interop.FindWindow.cs - - - Common\Interop\Windows\User32\Interop.SendMessage.cs - + + + + @@ -33,4 +29,4 @@ - \ No newline at end of file + diff --git a/src/libraries/Microsoft.XmlSerializer.Generator/tests/Microsoft.XmlSerializer.Generator.Tests.csproj b/src/libraries/Microsoft.XmlSerializer.Generator/tests/Microsoft.XmlSerializer.Generator.Tests.csproj index 373a3d987d2e73..7cffe3caa31032 100644 --- a/src/libraries/Microsoft.XmlSerializer.Generator/tests/Microsoft.XmlSerializer.Generator.Tests.csproj +++ b/src/libraries/Microsoft.XmlSerializer.Generator/tests/Microsoft.XmlSerializer.Generator.Tests.csproj @@ -2,14 +2,12 @@ $(DefineConstants);XMLSERIALIZERGENERATORTESTS $(NetCoreAppCurrent) - false - true + true $(MSBuildToolsPath)\MSBuild.runtimeconfig.json - "$(TestHostRootPath)$([System.IO.Path]::GetFileName('$(DotNetTool)'))" --fx-version $(ProductVersion) - "$(DotNetTool)" + "$(TestHostRootPath)$([System.IO.Path]::GetFileName('$(DotNetTool)'))" --fx-version $(ProductVersion) set DOTNET_MULTILEVEL_LOOKUP=0 & $(GeneratorCommand) export DOTNET_MULTILEVEL_LOOKUP=0 && $(GeneratorCommand) @@ -50,4 +48,4 @@ - \ No newline at end of file + diff --git a/src/libraries/Native/Unix/CMakeLists.txt b/src/libraries/Native/Unix/CMakeLists.txt index 76742dd715f755..aafa771b5a775f 100644 --- a/src/libraries/Native/Unix/CMakeLists.txt +++ b/src/libraries/Native/Unix/CMakeLists.txt @@ -10,9 +10,9 @@ if(CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS) cmake_minimum_required(VERSION 3.14.5) endif() -if(NOT CLR_CMAKE_TARGET_ARCH_WASM) +if(NOT CLR_CMAKE_TARGET_BROWSER) cmake_policy(SET CMP0083 NEW) -endif(NOT CLR_CMAKE_TARGET_ARCH_WASM) +endif(NOT CLR_CMAKE_TARGET_BROWSER) set(CMAKE_MACOSX_RPATH ON) set(CMAKE_INSTALL_PREFIX $ENV{__CMakeBinDir}) @@ -46,8 +46,7 @@ if (PRERELEASE) add_compile_options(-Werror) endif() -if(CLR_CMAKE_TARGET_ARCH_WASM) - add_definitions(-D_WASM_) +if(CLR_CMAKE_TARGET_BROWSER) # The emscripten build has additional warnings so -Werror breaks add_compile_options(-Wno-unused-parameter) add_compile_options(-Wno-unused-function) @@ -55,7 +54,7 @@ if(CLR_CMAKE_TARGET_ARCH_WASM) add_compile_options(-Wno-implicit-int-float-conversion) else() set(GEN_SHARED_LIB 1) -endif(CLR_CMAKE_TARGET_ARCH_WASM) +endif(CLR_CMAKE_TARGET_BROWSER) if (CLR_CMAKE_TARGET_ARCH_AMD64) add_definitions(-DTARGET_64BIT=1) @@ -139,7 +138,7 @@ else () message(FATAL_ERROR "Unknown build type. Set CMAKE_BUILD_TYPE to DEBUG or RELEASE.") endif () -if(CLR_CMAKE_TARGET_ARCH_WASM) +if(CLR_CMAKE_TARGET_BROWSER) elseif (CLR_CMAKE_TARGET_OSX OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS) add_definitions(-D__APPLE_USE_RFC_3542) @@ -164,13 +163,19 @@ endif(CLR_CMAKE_TARGET_FREEBSD) # ./build-native.sh cmakeargs -DCLR_ADDITIONAL_COMPILER_OPTIONS=<...> cmakeargs -DCLR_ADDITIONAL_LINKER_FLAGS=<...> # if(CLR_CMAKE_TARGET_UNIX) - if(NOT CLR_CMAKE_TARGET_ARCH_WASM AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS) + if(NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS) if(CLR_CMAKE_TARGET_OSX) add_definitions(-DTARGET_OSX) add_link_options(-Wl,-bind_at_load) else() add_compile_options($<$:-Wa,--noexecstack>) - add_link_options(-Wl,--build-id=sha1 -Wl,-z,relro,-z,now) + if(CLR_CMAKE_TARGET_SUNOS) + add_definitions(-D__EXTENSIONS__ -D_XPG4_2 -D_POSIX_PTHREAD_SEMANTICS) + else() + # -z,now is required for full relro. + # see https://www.redhat.com/en/blog/hardening-elf-binaries-using-relocation-read-only-relro + add_link_options(-Wl,--build-id=sha1 -Wl,-z,relro,-z,now) + endif() endif() endif() @@ -184,7 +189,7 @@ include(configure.cmake) add_subdirectory(System.IO.Compression.Native) -if (NOT CLR_CMAKE_TARGET_ARCH_WASM AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID) +if (NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_IOS AND NOT CLR_CMAKE_TARGET_TVOS AND NOT CLR_CMAKE_TARGET_ANDROID) add_subdirectory(System.IO.Ports.Native) endif() @@ -194,24 +199,22 @@ endif() add_subdirectory(System.Native) -if(CLR_CMAKE_TARGET_ARCH_WASM) +if(CLR_CMAKE_TARGET_BROWSER) # skip for now elseif(CLR_CMAKE_TARGET_IOS) add_subdirectory(System.Net.Security.Native) - #add_subdirectory(System.Globalization.Native) # TODO: reenable # System.Security.Cryptography.Native is intentionally disabled on iOS # it is only used for interacting with OpenSSL which isn't useful there elseif(CLR_CMAKE_TARGET_TVOS) #add_subdirectory(System.Net.Security.Native) # no gssapi on tvOS, see https://developer.apple.com/documentation/gss - #add_subdirectory(System.Globalization.Native) # TODO: reenable # System.Security.Cryptography.Native is intentionally disabled on tvOS # it is only used for interacting with OpenSSL which isn't useful there elseif(CLR_CMAKE_TARGET_ANDROID AND NOT CROSS_ROOTFS) - add_subdirectory(System.Globalization.Native) #add_subdirectory(System.Net.Security.Native) # TODO: reenable - #add_subdirectory(System.Security.Cryptography.Native) # TODO: reenable + if (NOT "$ENV{ANDROID_OPENSSL_AAR}" STREQUAL "") + add_subdirectory(System.Security.Cryptography.Native) + endif() else() - add_subdirectory(System.Globalization.Native) add_subdirectory(System.Net.Security.Native) add_subdirectory(System.Security.Cryptography.Native) endif() diff --git a/src/libraries/Native/Unix/Common/pal_atomic.h b/src/libraries/Native/Unix/Common/pal_atomic.h index a2ebcf62612dc7..908f33043981be 100644 --- a/src/libraries/Native/Unix/Common/pal_atomic.h +++ b/src/libraries/Native/Unix/Common/pal_atomic.h @@ -9,10 +9,11 @@ #include "windows.h" #endif +// The args passed in should match InterlockedCompareExchangePointer Windows API static int pal_atomic_cas_ptr(void* volatile* dest, void* exchange, void* comparand) { #if defined(TARGET_UNIX) - return __atomic_compare_exchange_n(dest, exchange, comparand, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + return __atomic_compare_exchange_n(dest, &comparand, exchange, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); #elif defined(TARGET_WINDOWS) return InterlockedCompareExchangePointer(dest, exchange, comparand) == comparand; #endif diff --git a/src/libraries/Native/Unix/Common/pal_config.h.in b/src/libraries/Native/Unix/Common/pal_config.h.in index c74c4c97593040..00e97fd88a30c2 100644 --- a/src/libraries/Native/Unix/Common/pal_config.h.in +++ b/src/libraries/Native/Unix/Common/pal_config.h.in @@ -26,6 +26,7 @@ #cmakedefine01 HAVE_MNTINFO #cmakedefine01 HAVE_STATFS_FSTYPENAME #cmakedefine01 HAVE_STATVFS_FSTYPENAME +#cmakedefine01 HAVE_NON_LEGACY_STATFS #cmakedefine01 HAVE_STRCPY_S #cmakedefine01 HAVE_STRLCPY #cmakedefine01 HAVE_SHM_OPEN_THAT_WORKS_WELL_ENOUGH_WITH_MMAP @@ -72,6 +73,11 @@ #cmakedefine01 HAVE_RT_MSGHDR2 #cmakedefine01 HAVE_IF_MSGHDR2 #cmakedefine01 HAVE_SYS_SYSCTL_H +#cmakedefine01 HAVE_SYS_IOCTL_H +#cmakedefine01 HAVE_SYS_FILIO_H +#cmakedefine01 HAVE_NETPACKET_PACKET_H +#cmakedefine01 HAVE_NET_IF_ARP_H +#cmakedefine01 HAVE_SYS_MNTENT_H #cmakedefine01 HAVE_NET_IFMEDIA_H #cmakedefine01 HAVE_LINUX_RTNETLINK_H #cmakedefine01 HAVE_LINUX_CAN_H @@ -102,6 +108,10 @@ #cmakedefine01 HAVE_TCP_H_TCP_KEEPALIVE #cmakedefine01 HAVE_BUILTIN_MUL_OVERFLOW #cmakedefine01 HAVE_DISCONNECTX +#cmakedefine01 HAVE_CFSETSPEED +#cmakedefine01 HAVE_CFMAKERAW +#cmakedefine01 HAVE_GETGROUPLIST +#cmakedefine01 HAVE_SYS_PROCINFO_H // Mac OS X has stat64, but it is deprecated since plain stat now // provides the same 64-bit aware struct when targeting OS X > 10.5 diff --git a/src/libraries/Native/Unix/Common/pal_error_common.h b/src/libraries/Native/Unix/Common/pal_error_common.h new file mode 100644 index 00000000000000..f185811e6fb227 --- /dev/null +++ b/src/libraries/Native/Unix/Common/pal_error_common.h @@ -0,0 +1,580 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once + +#include "pal_compiler.h" +#include "pal_types.h" +#include "pal_config.h" +#include "pal_utilities.h" +#include +#include +#include +#include + +// ENODATA is not defined in FreeBSD 10.3 but is defined in 11.0 +#if defined(__FreeBSD__) & !defined(ENODATA) +#define ENODATA ENOATTR +#endif + +/** + * Error codes returned via ConvertErrno. + * + * Only the names (without the PAL_ prefix) are specified by POSIX. + * + * The values chosen below are simply assigned arbitrarily (originally + * in alphabetical order they appear in the spec, but they can't change so + * add new values to the end!). + * + * Also, the values chosen are deliberately outside the range of + * typical UNIX errnos (small numbers), HRESULTs (negative for errors) + * and Win32 errors (0x0000 - 0xFFFF). This isn't required for + * correctness, but may help debug a caller that is interpreting a raw + * int incorrectly. + * + * Wherever the spec says "x may be the same value as y", we do use + * the same value so that callers cannot not take a dependency on + * being able to distinguish between them. + */ +typedef enum +{ + Error_SUCCESS = 0, + + Error_E2BIG = 0x10001, // Argument list too long. + Error_EACCES = 0x10002, // Permission denied. + Error_EADDRINUSE = 0x10003, // Address in use. + Error_EADDRNOTAVAIL = 0x10004, // Address not available. + Error_EAFNOSUPPORT = 0x10005, // Address family not supported. + Error_EAGAIN = 0x10006, // Resource unavailable, try again (same value as EWOULDBLOCK), + Error_EALREADY = 0x10007, // Connection already in progress. + Error_EBADF = 0x10008, // Bad file descriptor. + Error_EBADMSG = 0x10009, // Bad message. + Error_EBUSY = 0x1000A, // Device or resource busy. + Error_ECANCELED = 0x1000B, // Operation canceled. + Error_ECHILD = 0x1000C, // No child processes. + Error_ECONNABORTED = 0x1000D, // Connection aborted. + Error_ECONNREFUSED = 0x1000E, // Connection refused. + Error_ECONNRESET = 0x1000F, // Connection reset. + Error_EDEADLK = 0x10010, // Resource deadlock would occur. + Error_EDESTADDRREQ = 0x10011, // Destination address required. + Error_EDOM = 0x10012, // Mathematics argument out of domain of function. + Error_EDQUOT = 0x10013, // Reserved. + Error_EEXIST = 0x10014, // File exists. + Error_EFAULT = 0x10015, // Bad address. + Error_EFBIG = 0x10016, // File too large. + Error_EHOSTUNREACH = 0x10017, // Host is unreachable. + Error_EIDRM = 0x10018, // Identifier removed. + Error_EILSEQ = 0x10019, // Illegal byte sequence. + Error_EINPROGRESS = 0x1001A, // Operation in progress. + Error_EINTR = 0x1001B, // Interrupted function. + Error_EINVAL = 0x1001C, // Invalid argument. + Error_EIO = 0x1001D, // I/O error. + Error_EISCONN = 0x1001E, // Socket is connected. + Error_EISDIR = 0x1001F, // Is a directory. + Error_ELOOP = 0x10020, // Too many levels of symbolic links. + Error_EMFILE = 0x10021, // File descriptor value too large. + Error_EMLINK = 0x10022, // Too many links. + Error_EMSGSIZE = 0x10023, // Message too large. + Error_EMULTIHOP = 0x10024, // Reserved. + Error_ENAMETOOLONG = 0x10025, // Filename too long. + Error_ENETDOWN = 0x10026, // Network is down. + Error_ENETRESET = 0x10027, // Connection aborted by network. + Error_ENETUNREACH = 0x10028, // Network unreachable. + Error_ENFILE = 0x10029, // Too many files open in system. + Error_ENOBUFS = 0x1002A, // No buffer space available. + Error_ENODEV = 0x1002C, // No such device. + Error_ENOENT = 0x1002D, // No such file or directory. + Error_ENOEXEC = 0x1002E, // Executable file format error. + Error_ENOLCK = 0x1002F, // No locks available. + Error_ENOLINK = 0x10030, // Reserved. + Error_ENOMEM = 0x10031, // Not enough space. + Error_ENOMSG = 0x10032, // No message of the desired type. + Error_ENOPROTOOPT = 0x10033, // Protocol not available. + Error_ENOSPC = 0x10034, // No space left on device. + Error_ENOSYS = 0x10037, // Function not supported. + Error_ENOTCONN = 0x10038, // The socket is not connected. + Error_ENOTDIR = 0x10039, // Not a directory or a symbolic link to a directory. + Error_ENOTEMPTY = 0x1003A, // Directory not empty. + Error_ENOTRECOVERABLE = 0x1003B, // State not recoverable. + Error_ENOTSOCK = 0x1003C, // Not a socket. + Error_ENOTSUP = 0x1003D, // Not supported (same value as EOPNOTSUP). + Error_ENOTTY = 0x1003E, // Inappropriate I/O control operation. + Error_ENXIO = 0x1003F, // No such device or address. + Error_EOVERFLOW = 0x10040, // Value too large to be stored in data type. + Error_EOWNERDEAD = 0x10041, // Previous owner died. + Error_EPERM = 0x10042, // Operation not permitted. + Error_EPIPE = 0x10043, // Broken pipe. + Error_EPROTO = 0x10044, // Protocol error. + Error_EPROTONOSUPPORT = 0x10045, // Protocol not supported. + Error_EPROTOTYPE = 0x10046, // Protocol wrong type for socket. + Error_ERANGE = 0x10047, // Result too large. + Error_EROFS = 0x10048, // Read-only file system. + Error_ESPIPE = 0x10049, // Invalid seek. + Error_ESRCH = 0x1004A, // No such process. + Error_ESTALE = 0x1004B, // Reserved. + Error_ETIMEDOUT = 0x1004D, // Connection timed out. + Error_ETXTBSY = 0x1004E, // Text file busy. + Error_EXDEV = 0x1004F, // Cross-device link. + Error_ESOCKTNOSUPPORT = 0x1005E, // Socket type not supported. + Error_EPFNOSUPPORT = 0x10060, // Protocol family not supported. + Error_ESHUTDOWN = 0x1006C, // Socket shutdown. + Error_EHOSTDOWN = 0x10070, // Host is down. + Error_ENODATA = 0x10071, // No data available. + + // Error codes to track errors beyond kernel. + Error_EHOSTNOTFOUND = 0x20001, // Name lookup failed. + + // POSIX permits these to have the same value and we make them + // always equal so that we cannot introduce a dependency on + // distinguishing between them that would not work on all + // platforms. + Error_EOPNOTSUPP = Error_ENOTSUP, // Operation not supported on socket + Error_EWOULDBLOCK = Error_EAGAIN, // Operation would block + + // This one is not part of POSIX, but is a catch-all for the case + // where we cannot convert the raw errno value to something above. + Error_ENONSTANDARD = 0x1FFFF, +} Error; + +inline static int32_t ConvertErrorPlatformToPal(int32_t platformErrno) +{ + switch (platformErrno) + { + case 0: + return Error_SUCCESS; + case E2BIG: + return Error_E2BIG; + case EACCES: + return Error_EACCES; + case EADDRINUSE: + return Error_EADDRINUSE; + case EADDRNOTAVAIL: + return Error_EADDRNOTAVAIL; + case EAFNOSUPPORT: + return Error_EAFNOSUPPORT; + case EAGAIN: + return Error_EAGAIN; + case EALREADY: + return Error_EALREADY; + case EBADF: + return Error_EBADF; + case EBADMSG: + return Error_EBADMSG; + case EBUSY: + return Error_EBUSY; + case ECANCELED: + return Error_ECANCELED; + case ECHILD: + return Error_ECHILD; + case ECONNABORTED: + return Error_ECONNABORTED; + case ECONNREFUSED: + return Error_ECONNREFUSED; + case ECONNRESET: + return Error_ECONNRESET; + case EDEADLK: + return Error_EDEADLK; + case EDESTADDRREQ: + return Error_EDESTADDRREQ; + case EDOM: + return Error_EDOM; + case EDQUOT: + return Error_EDQUOT; + case EEXIST: + return Error_EEXIST; + case EFAULT: + return Error_EFAULT; + case EFBIG: + return Error_EFBIG; + case EHOSTUNREACH: + return Error_EHOSTUNREACH; + case EIDRM: + return Error_EIDRM; + case EILSEQ: + return Error_EILSEQ; + case EINPROGRESS: + return Error_EINPROGRESS; + case EINTR: + return Error_EINTR; + case EINVAL: + return Error_EINVAL; + case EIO: + return Error_EIO; + case EISCONN: + return Error_EISCONN; + case EISDIR: + return Error_EISDIR; + case ELOOP: + return Error_ELOOP; + case EMFILE: + return Error_EMFILE; + case EMLINK: + return Error_EMLINK; + case EMSGSIZE: + return Error_EMSGSIZE; + case EMULTIHOP: + return Error_EMULTIHOP; + case ENAMETOOLONG: + return Error_ENAMETOOLONG; + case ENETDOWN: + return Error_ENETDOWN; + case ENETRESET: + return Error_ENETRESET; + case ENETUNREACH: + return Error_ENETUNREACH; + case ENFILE: + return Error_ENFILE; + case ENOBUFS: + return Error_ENOBUFS; + case ENODEV: + return Error_ENODEV; + case ENOENT: + return Error_ENOENT; + case ENOEXEC: + return Error_ENOEXEC; + case ENOLCK: + return Error_ENOLCK; + case ENOLINK: + return Error_ENOLINK; + case ENOMEM: + return Error_ENOMEM; + case ENOMSG: + return Error_ENOMSG; + case ENOPROTOOPT: + return Error_ENOPROTOOPT; + case ENOSPC: + return Error_ENOSPC; + case ENOSYS: + return Error_ENOSYS; + case ENOTCONN: + return Error_ENOTCONN; + case ENOTDIR: + return Error_ENOTDIR; +#if ENOTEMPTY != EEXIST // AIX defines this + case ENOTEMPTY: + return Error_ENOTEMPTY; +#endif +#ifdef ENOTRECOVERABLE // not available in NetBSD + case ENOTRECOVERABLE: + return Error_ENOTRECOVERABLE; +#endif + case ENOTSOCK: + return Error_ENOTSOCK; + case ENOTSUP: + return Error_ENOTSUP; + case ENOTTY: + return Error_ENOTTY; + case ENXIO: + return Error_ENXIO; + case EOVERFLOW: + return Error_EOVERFLOW; +#ifdef EOWNERDEAD // not available in NetBSD + case EOWNERDEAD: + return Error_EOWNERDEAD; +#endif + case EPERM: + return Error_EPERM; + case EPIPE: + return Error_EPIPE; + case EPROTO: + return Error_EPROTO; + case EPROTONOSUPPORT: + return Error_EPROTONOSUPPORT; + case EPROTOTYPE: + return Error_EPROTOTYPE; + case ERANGE: + return Error_ERANGE; + case EROFS: + return Error_EROFS; + case ESPIPE: + return Error_ESPIPE; + case ESRCH: + return Error_ESRCH; + case ESTALE: + return Error_ESTALE; + case ETIMEDOUT: + return Error_ETIMEDOUT; + case ETXTBSY: + return Error_ETXTBSY; + case EXDEV: + return Error_EXDEV; +#ifdef ESOCKTNOSUPPORT + case ESOCKTNOSUPPORT: + return Error_ESOCKTNOSUPPORT; +#endif + case EPFNOSUPPORT: + return Error_EPFNOSUPPORT; + case ESHUTDOWN: + return Error_ESHUTDOWN; + case EHOSTDOWN: + return Error_EHOSTDOWN; + case ENODATA: + return Error_ENODATA; + +// #if because these will trigger duplicate case label warnings when +// they have the same value, which is permitted by POSIX and common. +#if EOPNOTSUPP != ENOTSUP + case EOPNOTSUPP: + return Error_EOPNOTSUPP; +#endif +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: + return Error_EWOULDBLOCK; +#endif + } + + return Error_ENONSTANDARD; +} + +inline static int32_t ConvertErrorPalToPlatform(int32_t error) +{ + switch (error) + { + case Error_SUCCESS: + return 0; + case Error_E2BIG: + return E2BIG; + case Error_EACCES: + return EACCES; + case Error_EADDRINUSE: + return EADDRINUSE; + case Error_EADDRNOTAVAIL: + return EADDRNOTAVAIL; + case Error_EAFNOSUPPORT: + return EAFNOSUPPORT; + case Error_EAGAIN: + return EAGAIN; + case Error_EALREADY: + return EALREADY; + case Error_EBADF: + return EBADF; + case Error_EBADMSG: + return EBADMSG; + case Error_EBUSY: + return EBUSY; + case Error_ECANCELED: + return ECANCELED; + case Error_ECHILD: + return ECHILD; + case Error_ECONNABORTED: + return ECONNABORTED; + case Error_ECONNREFUSED: + return ECONNREFUSED; + case Error_ECONNRESET: + return ECONNRESET; + case Error_EDEADLK: + return EDEADLK; + case Error_EDESTADDRREQ: + return EDESTADDRREQ; + case Error_EDOM: + return EDOM; + case Error_EDQUOT: + return EDQUOT; + case Error_EEXIST: + return EEXIST; + case Error_EFAULT: + return EFAULT; + case Error_EFBIG: + return EFBIG; + case Error_EHOSTUNREACH: + return EHOSTUNREACH; + case Error_EIDRM: + return EIDRM; + case Error_EILSEQ: + return EILSEQ; + case Error_EINPROGRESS: + return EINPROGRESS; + case Error_EINTR: + return EINTR; + case Error_EINVAL: + return EINVAL; + case Error_EIO: + return EIO; + case Error_EISCONN: + return EISCONN; + case Error_EISDIR: + return EISDIR; + case Error_ELOOP: + return ELOOP; + case Error_EMFILE: + return EMFILE; + case Error_EMLINK: + return EMLINK; + case Error_EMSGSIZE: + return EMSGSIZE; + case Error_EMULTIHOP: + return EMULTIHOP; + case Error_ENAMETOOLONG: + return ENAMETOOLONG; + case Error_ENETDOWN: + return ENETDOWN; + case Error_ENETRESET: + return ENETRESET; + case Error_ENETUNREACH: + return ENETUNREACH; + case Error_ENFILE: + return ENFILE; + case Error_ENOBUFS: + return ENOBUFS; + case Error_ENODEV: + return ENODEV; + case Error_ENOENT: + return ENOENT; + case Error_ENOEXEC: + return ENOEXEC; + case Error_ENOLCK: + return ENOLCK; + case Error_ENOLINK: + return ENOLINK; + case Error_ENOMEM: + return ENOMEM; + case Error_ENOMSG: + return ENOMSG; + case Error_ENOPROTOOPT: + return ENOPROTOOPT; + case Error_ENOSPC: + return ENOSPC; + case Error_ENOSYS: + return ENOSYS; + case Error_ENOTCONN: + return ENOTCONN; + case Error_ENOTDIR: + return ENOTDIR; + case Error_ENOTEMPTY: + return ENOTEMPTY; +#ifdef ENOTRECOVERABLE // not available in NetBSD + case Error_ENOTRECOVERABLE: + return ENOTRECOVERABLE; +#endif + case Error_ENOTSOCK: + return ENOTSOCK; + case Error_ENOTSUP: + return ENOTSUP; + case Error_ENOTTY: + return ENOTTY; + case Error_ENXIO: + return ENXIO; + case Error_EOVERFLOW: + return EOVERFLOW; +#ifdef EOWNERDEAD // not available in NetBSD + case Error_EOWNERDEAD: + return EOWNERDEAD; +#endif + case Error_EPERM: + return EPERM; + case Error_EPIPE: + return EPIPE; + case Error_EPROTO: + return EPROTO; + case Error_EPROTONOSUPPORT: + return EPROTONOSUPPORT; + case Error_EPROTOTYPE: + return EPROTOTYPE; + case Error_ERANGE: + return ERANGE; + case Error_EROFS: + return EROFS; + case Error_ESPIPE: + return ESPIPE; + case Error_ESRCH: + return ESRCH; + case Error_ESTALE: + return ESTALE; + case Error_ETIMEDOUT: + return ETIMEDOUT; + case Error_ETXTBSY: + return ETXTBSY; + case Error_EXDEV: + return EXDEV; + case Error_EPFNOSUPPORT: + return EPFNOSUPPORT; +#ifdef ESOCKTNOSUPPORT + case Error_ESOCKTNOSUPPORT: + return ESOCKTNOSUPPORT; +#endif + case Error_ESHUTDOWN: + return ESHUTDOWN; + case Error_EHOSTDOWN: + return EHOSTDOWN; + case Error_ENODATA: + return ENODATA; + case Error_EHOSTNOTFOUND: + return -(Error_EHOSTNOTFOUND); + case Error_ENONSTANDARD: + break; // fall through to assert + } + + // We should not use this function to round-trip platform -> pal + // -> platform. It's here only to synthesize a platform number + // from the fixed set above. Note that the assert is outside the + // switch rather than in a default case block because not + // having a default will trigger a warning (as error) if there's + // an enum value we haven't handled. Should that trigger, make + // note that there is probably a corresponding missing case in the + // other direction above, but the compiler can't warn in that case + // because the platform values are not part of an enum. + assert_err(false, "Unknown error code", (int) error); + return -1; +} + +static int32_t ConvertErrorPalToGai(int32_t error) +{ + switch (error) + { + case -(Error_EHOSTNOTFOUND): + return EAI_NONAME; + } + // Fall-through for unknown codes. gai_strerror() will handle that. + + return error; +} + + + +inline static const char* StrErrorR(int32_t platformErrno, char* buffer, int32_t bufferSize) +{ + assert(buffer != NULL); + assert(bufferSize > 0); + + if (bufferSize < 0) + return NULL; + + if (platformErrno < 0) + { + // Not a system error + SafeStringCopy(buffer, (size_t)bufferSize, gai_strerror(ConvertErrorPalToGai(platformErrno))); + return buffer; + } + +// Note that we must use strerror_r because plain strerror is not +// thread-safe. +// +// However, there are two versions of strerror_r: +// - GNU: char* strerror_r(int, char*, size_t); +// - POSIX: int strerror_r(int, char*, size_t); +// +// The former may or may not use the supplied buffer, and returns +// the error message string. The latter stores the error message +// string into the supplied buffer and returns an error code. + +#if HAVE_GNU_STRERROR_R + const char* message = strerror_r(platformErrno, buffer, (uint32_t) bufferSize); + assert(message != NULL); + return message; +#else + int error = strerror_r(platformErrno, buffer, (uint32_t) bufferSize); + if (error == ERANGE) + { + // Buffer is too small to hold the entire message, but has + // still been filled to the extent possible and null-terminated. + return NULL; + } + + // The only other valid error codes are 0 for success or EINVAL for + // an unknown error, but in the latter case a reasonable string (e.g + // "Unknown error: 0x123") is returned. + assert_err(error == 0 || error == EINVAL, "invalid error", error); + return buffer; +#endif +} diff --git a/src/libraries/Native/Unix/Common/pal_io_common.h b/src/libraries/Native/Unix/Common/pal_io_common.h new file mode 100644 index 00000000000000..15bf1423aa327b --- /dev/null +++ b/src/libraries/Native/Unix/Common/pal_io_common.h @@ -0,0 +1,189 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once + +#include +#include +#include +#include +#include + +/** + * Our intermediate pollfd struct to normalize the data types + */ +typedef struct +{ + int32_t FileDescriptor; // The file descriptor to poll + int16_t Events; // The events to poll for + int16_t TriggeredEvents; // The events that triggered the poll +} PollEvent; + +/** + * Constants passed to and from poll describing what to poll for and what + * kind of data was received from poll. + */ +typedef enum +{ + PAL_POLLIN = 0x0001, /* non-urgent readable data available */ + PAL_POLLPRI = 0x0002, /* urgent readable data available */ + PAL_POLLOUT = 0x0004, /* data can be written without blocked */ + PAL_POLLERR = 0x0008, /* an error occurred */ + PAL_POLLHUP = 0x0010, /* the file descriptor hung up */ + PAL_POLLNVAL = 0x0020, /* the requested events were invalid */ +} PollEvents; + +inline static int32_t Common_Read(intptr_t fd, void* buffer, int32_t bufferSize) +{ + assert(buffer != NULL || bufferSize == 0); + assert(bufferSize >= 0); + + if (bufferSize < 0) + { + errno = EINVAL; + return -1; + } + + ssize_t count; + while ((count = read(ToFileDescriptor(fd), buffer, (uint32_t)bufferSize)) < 0 && errno == EINTR); + + assert(count >= -1 && count <= bufferSize); + return (int32_t)count; +} + +inline static int32_t Common_Write(intptr_t fd, const void* buffer, int32_t bufferSize) +{ + assert(buffer != NULL || bufferSize == 0); + assert(bufferSize >= 0); + + if (bufferSize < 0) + { + errno = ERANGE; + return -1; + } + + ssize_t count; + while ((count = write(ToFileDescriptor(fd), buffer, (uint32_t)bufferSize)) < 0 && errno == EINTR); + + assert(count >= -1 && count <= bufferSize); + return (int32_t)count; +} + +inline static int32_t Common_Poll(PollEvent* pollEvents, uint32_t eventCount, int32_t milliseconds, uint32_t* triggered) +{ + if (pollEvents == NULL || triggered == NULL) + { + return Error_EFAULT; + } + + if (milliseconds < -1) + { + return Error_EINVAL; + } + + struct pollfd stackBuffer[(uint32_t)(2048/sizeof(struct pollfd))]; + int useStackBuffer = eventCount <= ARRAY_SIZE(stackBuffer); + struct pollfd* pollfds = NULL; + if (useStackBuffer) + { + pollfds = &stackBuffer[0]; + } + else + { + pollfds = calloc(eventCount, sizeof(*pollfds)); + if (pollfds == NULL) + { + return Error_ENOMEM; + } + } + + for (uint32_t i = 0; i < eventCount; i++) + { + const PollEvent* event = &pollEvents[i]; + pollfds[i].fd = event->FileDescriptor; + // we need to do this for platforms like AIX where PAL_POLL* doesn't + // match up to their reality; this is PollEvent -> system polling + switch (event->Events) + { + case PAL_POLLIN: + pollfds[i].events = POLLIN; + break; + case PAL_POLLPRI: + pollfds[i].events = POLLPRI; + break; + case PAL_POLLOUT: + pollfds[i].events = POLLOUT; + break; + case PAL_POLLERR: + pollfds[i].events = POLLERR; + break; + case PAL_POLLHUP: + pollfds[i].events = POLLHUP; + break; + case PAL_POLLNVAL: + pollfds[i].events = POLLNVAL; + break; + default: + pollfds[i].events = event->Events; + break; + } + pollfds[i].revents = 0; + } + + int rv; + while ((rv = poll(pollfds, (nfds_t)eventCount, milliseconds)) < 0 && errno == EINTR); + + if (rv < 0) + { + if (!useStackBuffer) + { + free(pollfds); + } + + *triggered = 0; + return ConvertErrorPlatformToPal(errno); + } + + for (uint32_t i = 0; i < eventCount; i++) + { + const struct pollfd* pfd = &pollfds[i]; + assert(pfd->fd == pollEvents[i].FileDescriptor); + assert(pfd->events == pollEvents[i].Events); + + // same as the other switch, just system -> PollEvent + switch (pfd->revents) + { + case POLLIN: + pollEvents[i].TriggeredEvents = PAL_POLLIN; + break; + case POLLPRI: + pollEvents[i].TriggeredEvents = PAL_POLLPRI; + break; + case POLLOUT: + pollEvents[i].TriggeredEvents = PAL_POLLOUT; + break; + case POLLERR: + pollEvents[i].TriggeredEvents = PAL_POLLERR; + break; + case POLLHUP: + pollEvents[i].TriggeredEvents = PAL_POLLHUP; + break; + case POLLNVAL: + pollEvents[i].TriggeredEvents = PAL_POLLNVAL; + break; + default: + pollEvents[i].TriggeredEvents = (int16_t)pfd->revents; + break; + } + } + + *triggered = (uint32_t)rv; + + if (!useStackBuffer) + { + free(pollfds); + } + + return Error_SUCCESS; +} diff --git a/src/libraries/Native/Unix/Common/pal_networking_common.h b/src/libraries/Native/Unix/Common/pal_networking_common.h new file mode 100644 index 00000000000000..353862cd7ce0d1 --- /dev/null +++ b/src/libraries/Native/Unix/Common/pal_networking_common.h @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma once + +#include +#include + +/* + * Socket shutdown modes. + * + * NOTE: these values are taken from System.Net.SocketShutdown. + */ +typedef enum +{ + SocketShutdown_SHUT_READ = 0, // SHUT_RD + SocketShutdown_SHUT_WRITE = 1, // SHUT_WR + SocketShutdown_SHUT_BOTH = 2, // SHUT_RDWR +} SockerShutdown; + +inline static int32_t Common_Shutdown(intptr_t socket, int32_t socketShutdown) +{ + int fd = ToFileDescriptor(socket); + + int how; + switch (socketShutdown) + { + case SocketShutdown_SHUT_READ: + how = SHUT_RD; + break; + + case SocketShutdown_SHUT_WRITE: + how = SHUT_WR; + break; + + case SocketShutdown_SHUT_BOTH: + how = SHUT_RDWR; + break; + + default: + return Error_EINVAL; + } + + int err = shutdown(fd, how); + return err == 0 ? Error_SUCCESS : ConvertErrorPlatformToPal(errno); +} diff --git a/src/libraries/Native/Unix/System.Globalization.Native/pal_collation.c b/src/libraries/Native/Unix/System.Globalization.Native/pal_collation.c index 081a01693ecc83..508d3a41e37ed8 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/pal_collation.c +++ b/src/libraries/Native/Unix/System.Globalization.Native/pal_collation.c @@ -404,7 +404,7 @@ static const UCollator* GetCollatorFromSortHandle(SortHandle* pSortHandle, int32 pCollator = CloneCollatorWithOptions(pSortHandle->collatorsPerOption[0], options, pErr); UCollator* pNull = NULL; - if (!pal_atomic_cas_ptr((void* volatile*)&pSortHandle->collatorsPerOption[options], &pNull, pCollator)) + if (!pal_atomic_cas_ptr((void* volatile*)&pSortHandle->collatorsPerOption[options], pCollator, pNull)) { ucol_close(pCollator); pCollator = pSortHandle->collatorsPerOption[options]; @@ -445,6 +445,20 @@ int32_t GlobalizationNative_CompareString( if (U_SUCCESS(err)) { + // Workaround for https://unicode-org.atlassian.net/projects/ICU/issues/ICU-9396 + // The ucol_strcoll routine on some older versions of ICU doesn't correctly + // handle nullptr inputs. We'll play defensively and always flow a non-nullptr. + + UChar dummyChar = 0; + if (lpStr1 == NULL) + { + lpStr1 = &dummyChar; + } + if (lpStr2 == NULL) + { + lpStr2 = &dummyChar; + } + result = ucol_strcoll(pColl, lpStr1, cwStr1Length, lpStr2, cwStr2Length); } @@ -464,7 +478,28 @@ int32_t GlobalizationNative_IndexOf( int32_t options, int32_t* pMatchedLength) { + assert(cwTargetLength > 0); + int32_t result = USEARCH_DONE; + + // It's possible somebody passed us (source = , target = ). + // ICU's usearch_* APIs don't handle empty source inputs properly. However, + // if this occurs the user really just wanted us to perform an equality check. + // We can't short-circuit the operation because depending on the collation in + // use, certain code points may have zero weight, which means that empty + // strings may compare as equal to non-empty strings. + + if (cwSourceLength == 0) + { + result = GlobalizationNative_CompareString(pSortHandle, lpTarget, cwTargetLength, lpSource, cwSourceLength, options); + if (result == UCOL_EQUAL && pMatchedLength != NULL) + { + *pMatchedLength = cwTargetLength; + } + + return (result == UCOL_EQUAL) ? 0 : -1; + } + UErrorCode err = U_ZERO_ERROR; const UCollator* pColl = GetCollatorFromSortHandle(pSortHandle, options, &err); @@ -499,9 +534,31 @@ int32_t GlobalizationNative_LastIndexOf( int32_t cwTargetLength, const UChar* lpSource, int32_t cwSourceLength, - int32_t options) + int32_t options, + int32_t* pMatchedLength) { + assert(cwTargetLength > 0); + int32_t result = USEARCH_DONE; + + // It's possible somebody passed us (source = , target = ). + // ICU's usearch_* APIs don't handle empty source inputs properly. However, + // if this occurs the user really just wanted us to perform an equality check. + // We can't short-circuit the operation because depending on the collation in + // use, certain code points may have zero weight, which means that empty + // strings may compare as equal to non-empty strings. + + if (cwSourceLength == 0) + { + result = GlobalizationNative_CompareString(pSortHandle, lpTarget, cwTargetLength, lpSource, cwSourceLength, options); + if (result == UCOL_EQUAL && pMatchedLength != NULL) + { + *pMatchedLength = cwTargetLength; + } + + return (result == UCOL_EQUAL) ? 0 : -1; + } + UErrorCode err = U_ZERO_ERROR; const UCollator* pColl = GetCollatorFromSortHandle(pSortHandle, options, &err); @@ -512,6 +569,13 @@ int32_t GlobalizationNative_LastIndexOf( if (U_SUCCESS(err)) { result = usearch_last(pSearch, &err); + + // if the search was successful, + // we'll try to get the matched string length. + if (result != USEARCH_DONE && pMatchedLength != NULL) + { + *pMatchedLength = usearch_getMatchedLength(pSearch); + } usearch_close(pSearch); } } @@ -771,14 +835,16 @@ static int32_t ComplexEndsWith(const UCollator* pCollator, UErrorCode* pErrorCod int32_t idx = usearch_last(pSearch, pErrorCode); if (idx != USEARCH_DONE) { - if ((idx + usearch_getMatchedLength(pSearch)) == patternLength) + int32_t matchEnd = idx + usearch_getMatchedLength(pSearch); + assert(matchEnd <= textLength); + + if (matchEnd == textLength) { result = TRUE; } else { - int32_t matchEnd = idx + usearch_getMatchedLength(pSearch); - int32_t remainingStringLength = patternLength - matchEnd; + int32_t remainingStringLength = textLength - matchEnd; result = CanIgnoreAllCollationElements(pCollator, pText + matchEnd, remainingStringLength); } diff --git a/src/libraries/Native/Unix/System.Globalization.Native/pal_collation.h b/src/libraries/Native/Unix/System.Globalization.Native/pal_collation.h index 3d04ba735517f8..79f2fd72ff0b56 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/pal_collation.h +++ b/src/libraries/Native/Unix/System.Globalization.Native/pal_collation.h @@ -37,7 +37,8 @@ PALEXPORT int32_t GlobalizationNative_LastIndexOf(SortHandle* pSortHandle, int32_t cwTargetLength, const UChar* lpSource, int32_t cwSourceLength, - int32_t options); + int32_t options, + int32_t* pMatchedLength); PALEXPORT int32_t GlobalizationNative_IndexOfOrdinalIgnoreCase(const UChar* lpTarget, int32_t cwTargetLength, diff --git a/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim.c b/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim.c index 5438b44b372551..7fa6dd6fd8ac16 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim.c +++ b/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim.c @@ -3,6 +3,9 @@ // See the LICENSE file in the project root for more information. // +#include +#include "pal_icushim_internal.h" + #if defined(TARGET_UNIX) #include #elif defined(TARGET_WINDOWS) @@ -10,12 +13,10 @@ #include #include #endif -#include #include #include #include -#include "pal_icushim_internal.h" #include "pal_icushim.h" // Define pointers to all the used ICU functions @@ -23,11 +24,76 @@ FOR_ALL_ICU_FUNCTIONS #undef PER_FUNCTION_BLOCK +// 35 for the actual suffix, 1 for _ and 1 for '\0' +#define SYMBOL_CUSTOM_SUFFIX_SIZE 37 +#define SYMBOL_NAME_SIZE (128 + SYMBOL_CUSTOM_SUFFIX_SIZE) +#define MaxICUVersionStringWithSuffixLength (MaxICUVersionStringLength + SYMBOL_CUSTOM_SUFFIX_SIZE) + + +#if defined(TARGET_WINDOWS) || defined(TARGET_OSX) || defined(TARGET_ANDROID) + +#define MaxICUVersionStringLength 33 + +#endif + static void* libicuuc = NULL; static void* libicui18n = NULL; +#if defined (TARGET_UNIX) + +#define PER_FUNCTION_BLOCK(fn, lib) \ + c_static_assert_msg((sizeof(#fn) + MaxICUVersionStringWithSuffixLength + 1) <= sizeof(symbolName), "The symbolName is too small for symbol " #fn); \ + sprintf(symbolName, #fn "%s", symbolVersion); \ + fn##_ptr = (__typeof(fn)*)dlsym(lib, symbolName); \ + if (fn##_ptr == NULL) { fprintf(stderr, "Cannot get symbol %s from " #lib "\nError: %s\n", symbolName, dlerror()); abort(); } + +static int FindSymbolVersion(int majorVer, int minorVer, int subVer, char* symbolName, char* symbolVersion, char* suffix) +{ + // Find out the format of the version string added to each symbol + // First try just the unversioned symbol + if (dlsym(libicuuc, "u_strlen") == NULL) + { + // Now try just the _majorVer added + sprintf(symbolVersion, "_%d%s", majorVer, suffix); + sprintf(symbolName, "u_strlen%s", symbolVersion); + if (dlsym(libicuuc, symbolName) == NULL) + { + if (minorVer == -1) + return FALSE; + + // Now try the _majorVer_minorVer added + sprintf(symbolVersion, "_%d_%d%s", majorVer, minorVer, suffix); + sprintf(symbolName, "u_strlen%s", symbolVersion); + if (dlsym(libicuuc, symbolName) == NULL) + { + if (subVer == -1) + return FALSE; + + // Finally, try the _majorVer_minorVer_subVer added + sprintf(symbolVersion, "_%d_%d_%d%s", majorVer, minorVer, subVer, suffix); + sprintf(symbolName, "u_strlen%s", symbolVersion); + if (dlsym(libicuuc, symbolName) == NULL) + { + return FALSE; + } + } + } + } + + return TRUE; +} + +#endif // TARGET_UNIX + #if defined(TARGET_WINDOWS) +#define sscanf sscanf_s + +#define PER_FUNCTION_BLOCK(fn, lib) \ + sprintf_s(symbolName, SYMBOL_NAME_SIZE, #fn "%s", symbolVersion); \ + fn##_ptr = (__typeof(fn)*)GetProcAddress((HMODULE)lib, symbolName); \ + if (fn##_ptr == NULL) { fprintf(stderr, "Cannot get symbol %s from " #lib "\nError: %u\n", symbolName, GetLastError()); abort(); } + static int FindICULibs() { libicuuc = LoadLibraryExW(L"icu.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); @@ -41,6 +107,42 @@ static int FindICULibs() return TRUE; } +static int FindSymbolVersion(int majorVer, int minorVer, int subVer, char* symbolName, char* symbolVersion, char* suffix) +{ + HMODULE lib = (HMODULE)libicuuc; + // Find out the format of the version string added to each symbol + // First try just the unversioned symbol + if (GetProcAddress(lib, "u_strlen") == NULL) + { + // Now try just the _majorVer added + sprintf_s(symbolVersion, MaxICUVersionStringWithSuffixLength,"_%d%s", majorVer, suffix); + sprintf_s(symbolName, SYMBOL_NAME_SIZE, "u_strlen%s", symbolVersion); + if (GetProcAddress(lib, symbolName) == NULL) + { + if (minorVer == -1) + return FALSE; + + // Now try the _majorVer_minorVer added + sprintf_s(symbolVersion, MaxICUVersionStringWithSuffixLength, "_%d_%d%s", majorVer, minorVer, suffix); + sprintf_s(symbolName, SYMBOL_NAME_SIZE, "u_strlen%s", symbolVersion); + if (GetProcAddress(lib, symbolName) == NULL) + { + if (subVer == -1) + return FALSE; + // Finally, try the _majorVer_minorVer_subVer added + sprintf_s(symbolVersion, MaxICUVersionStringWithSuffixLength, "_%d_%d_%d%s", majorVer, minorVer, subVer, suffix); + sprintf_s(symbolName, SYMBOL_NAME_SIZE, "u_strlen%s", symbolVersion); + if (GetProcAddress(lib, symbolName) == NULL) + { + return FALSE; + } + } + } + } + + return TRUE; +} + #elif defined(TARGET_OSX) static int FindICULibs() @@ -68,22 +170,6 @@ static int FindICULibs() // support ICU versions from 50-255 #define MinICUVersion 50 #define MaxICUVersion 255 -#define MaxICUVersionStringLength 4 - -static int FindSymbolVersion(char* symbolName, char* symbolVersion) -{ - for (int i = MinICUVersion; i <= MaxICUVersion; i++) - { - sprintf(symbolVersion, "_%d", i); - sprintf(symbolName, "u_strlen%s", symbolVersion); - if (dlsym(libicuuc, symbolName) != NULL) - { - return TRUE; - } - } - - return FALSE; -} static int FindICULibs(char* symbolName, char* symbolVersion) { @@ -101,13 +187,17 @@ static int FindICULibs(char* symbolName, char* symbolVersion) return FALSE; } - if (!FindSymbolVersion(symbolName, symbolVersion)) + char symbolSuffix[SYMBOL_CUSTOM_SUFFIX_SIZE]=""; + for (int i = MinICUVersion; i <= MaxICUVersion; i++) { - fprintf(stderr, "Cannot determine ICU version."); - return FALSE; + if (FindSymbolVersion(i, -1, -1, symbolName, symbolVersion, symbolSuffix)) + { + return TRUE; + } } - return TRUE; + fprintf(stderr, "Cannot determine ICU version."); + return FALSE; } #else // !TARGET_WINDOWS && !TARGET_OSX && !TARGET_ANDROID @@ -153,36 +243,6 @@ static void GetVersionedLibFileName(const char* baseFileName, int majorVer, int } } -static int FindSymbolVersion(int majorVer, int minorVer, int subVer, char* symbolName, char* symbolVersion) -{ - // Find out the format of the version string added to each symbol - // First try just the unversioned symbol - if (dlsym(libicuuc, "u_strlen") == NULL) - { - // Now try just the _majorVer added - sprintf(symbolVersion, "_%d", majorVer); - sprintf(symbolName, "u_strlen%s", symbolVersion); - if ((dlsym(libicuuc, symbolName) == NULL) && (minorVer != -1)) - { - // Now try the _majorVer_minorVer added - sprintf(symbolVersion, "_%d_%d", majorVer, minorVer); - sprintf(symbolName, "u_strlen%s", symbolVersion); - if ((dlsym(libicuuc, symbolName) == NULL) && (subVer != -1)) - { - // Finally, try the _majorVer_minorVer_subVer added - sprintf(symbolVersion, "_%d_%d_%d", majorVer, minorVer, subVer); - sprintf(symbolName, "u_strlen%s", symbolVersion); - if (dlsym(libicuuc, symbolName) == NULL) - { - return FALSE; - } - } - } - } - - return TRUE; -} - // Try to open the necessary ICU libraries static int OpenICULibraries(int majorVer, int minorVer, int subVer, const char* versionPrefix, char* symbolName, char* symbolVersion) { @@ -198,7 +258,8 @@ static int OpenICULibraries(int majorVer, int minorVer, int subVer, const char* libicuuc = dlopen(libicuucName, RTLD_LAZY); if (libicuuc != NULL) { - if (FindSymbolVersion(majorVer, minorVer, subVer, symbolName, symbolVersion)) + char symbolSuffix[SYMBOL_CUSTOM_SUFFIX_SIZE]=""; + if (FindSymbolVersion(majorVer, minorVer, subVer, symbolName, symbolVersion, symbolSuffix)) { libicui18n = dlopen(libicui18nName, RTLD_LAZY); } @@ -306,41 +367,36 @@ static int FindICULibs(const char* versionPrefix, char* symbolName, char* symbol #endif +static void ValidateICUDataCanLoad() +{ + UVersionInfo version; + UErrorCode err = U_ZERO_ERROR; + ulocdata_getCLDRVersion(version, &err); + + if (U_FAILURE(err)) + { + fprintf(stderr, "Could not load ICU data. UErrorCode: %d\n", err); + abort(); + } +} + // GlobalizationNative_LoadICU // This method get called from the managed side during the globalization initialization. // This method shouldn't get called at all if we are running in globalization invariant mode // return 0 if failed to load ICU and 1 otherwise int32_t GlobalizationNative_LoadICU() { -#if defined(TARGET_WINDOWS) - - if (!FindICULibs()) - { - return FALSE; - } + char symbolName[SYMBOL_NAME_SIZE]; + char symbolVersion[MaxICUVersionStringLength + 1]=""; -#define PER_FUNCTION_BLOCK(fn, lib) \ - fn##_ptr = (__typeof(fn)*)GetProcAddress((HMODULE)lib, #fn); \ - if (fn##_ptr == NULL) { fprintf(stderr, "Cannot get symbol %s from " #lib "\nError: %u\n", #fn, GetLastError()); abort(); } - -#elif defined(TARGET_OSX) +#if defined(TARGET_WINDOWS) || defined(TARGET_OSX) if (!FindICULibs()) { return FALSE; } - // Get pointers to all the ICU functions that are needed -#define PER_FUNCTION_BLOCK(fn, lib) \ - fn##_ptr = (__typeof(fn)*)dlsym(lib, #fn); \ - if (fn##_ptr == NULL) { fprintf(stderr, "Cannot get symbol %s from " #lib "\nError: %s\n", #fn, dlerror()); abort(); } - -#else // !TARGET_WINDOWS && !TARGET_OSX - - char symbolName[128]; - char symbolVersion[MaxICUVersionStringLength + 1] = ""; - -#if defined(TARGET_ANDROID) +#elif defined(TARGET_ANDROID) if (!FindICULibs(symbolName, symbolVersion)) { return FALSE; @@ -353,28 +409,76 @@ int32_t GlobalizationNative_LoadICU() return FALSE; } } -#endif +#endif // TARGET_WINDOWS || TARGET_OSX - // Get pointers to all the ICU functions that are needed -#define PER_FUNCTION_BLOCK(fn, lib) \ - c_static_assert_msg((sizeof(#fn) + MaxICUVersionStringLength + 1) <= sizeof(symbolName), "The symbolName is too small for symbol " #fn); \ - sprintf(symbolName, #fn "%s", symbolVersion); \ - fn##_ptr = (__typeof(fn)*)dlsym(lib, symbolName); \ - if (fn##_ptr == NULL) { fprintf(stderr, "Cannot get symbol %s from " #lib "\nError: %s\n", symbolName, dlerror()); abort(); } + FOR_ALL_ICU_FUNCTIONS + ValidateICUDataCanLoad(); + return TRUE; +} + +void GlobalizationNative_InitICUFunctions(void* icuuc, void* icuin, const char* version, const char* suffix) +{ + assert(icuuc != NULL); + assert(icuin != NULL); + assert(version != NULL); + + libicuuc = icuuc; + libicui18n = icuin; + int major = -1; + int minor = -1; + int build = -1; + + char symbolName[SYMBOL_NAME_SIZE]; + char symbolVersion[MaxICUVersionStringWithSuffixLength + 1]=""; + char symbolSuffix[SYMBOL_CUSTOM_SUFFIX_SIZE]=""; + + if (strlen(version) > (size_t)MaxICUVersionStringLength) + { + fprintf(stderr, "The resolved version \"%s\" from System.Globalization.AppLocalIcu switch has to be < %zu chars long.\n", version, (size_t)MaxICUVersionStringLength); + abort(); + } + + sscanf(version, "%d.%d.%d", &major, &minor, &build); + + if (suffix != NULL) + { + size_t suffixAllowedSize = SYMBOL_CUSTOM_SUFFIX_SIZE - 2; // SYMBOL_CUSTOM_SUFFIX_SIZE considers `_` and `\0`. + if (strlen(suffix) > suffixAllowedSize) + { + fprintf(stderr, "The resolved suffix \"%s\" from System.Globalization.AppLocalIcu switch has to be < %zu chars long.\n", suffix, suffixAllowedSize); + abort(); + } + + assert(strlen(suffix) + 1 <= SYMBOL_CUSTOM_SUFFIX_SIZE); +#if defined(TARGET_WINDOWS) + sprintf_s(symbolSuffix, SYMBOL_CUSTOM_SUFFIX_SIZE, "_%s", suffix); +#else + sprintf(symbolSuffix, "_%s", suffix); #endif + } - FOR_ALL_ICU_FUNCTIONS -#undef PER_FUNCTION_BLOCK + if(!FindSymbolVersion(major, minor, build, symbolName, symbolVersion, symbolSuffix)) + { + fprintf(stderr, "Could not find symbol: %s from libicuuc\n", symbolName); + abort(); + } - return TRUE; + FOR_ALL_ICU_FUNCTIONS + ValidateICUDataCanLoad(); } +#undef PER_FUNCTION_BLOCK + // GlobalizationNative_GetICUVersion // return the current loaded ICU version int32_t GlobalizationNative_GetICUVersion() { - int32_t version; - u_getVersion((uint8_t *) &version); - return version; + if (u_getVersion_ptr == NULL) + return 0; + + UVersionInfo versionInfo; + u_getVersion(versionInfo); + + return (versionInfo[0] << 24) + (versionInfo[1] << 16) + (versionInfo[2] << 8) + versionInfo[3]; } diff --git a/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim.h b/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim.h index 49db55214bf8dd..ef940e2509355a 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim.h +++ b/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim.h @@ -5,4 +5,6 @@ PALEXPORT int32_t GlobalizationNative_LoadICU(void); +PALEXPORT void GlobalizationNative_InitICUFunctions(void* icuuc, void* icuin, const char* version, const char* suffix); + PALEXPORT int32_t GlobalizationNative_GetICUVersion(void); diff --git a/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim_internal.h b/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim_internal.h index a13ea5f7ad9219..33617e7f5d039d 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim_internal.h +++ b/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim_internal.h @@ -87,8 +87,6 @@ PER_FUNCTION_BLOCK(ucol_safeClone, libicui18n) \ PER_FUNCTION_BLOCK(ucol_setAttribute, libicui18n) \ PER_FUNCTION_BLOCK(ucol_strcoll, libicui18n) \ - PER_FUNCTION_BLOCK(ucurr_forLocale, libicui18n) \ - PER_FUNCTION_BLOCK(ucurr_getName, libicui18n) \ PER_FUNCTION_BLOCK(udat_close, libicui18n) \ PER_FUNCTION_BLOCK(udat_countSymbols, libicui18n) \ PER_FUNCTION_BLOCK(udat_getSymbols, libicui18n) \ @@ -105,9 +103,6 @@ PER_FUNCTION_BLOCK(uidna_nameToASCII, libicuuc) \ PER_FUNCTION_BLOCK(uidna_nameToUnicode, libicuuc) \ PER_FUNCTION_BLOCK(uidna_openUTS46, libicuuc) \ - PER_FUNCTION_BLOCK(uldn_close, libicui18n) \ - PER_FUNCTION_BLOCK(uldn_keyValueDisplayName, libicui18n) \ - PER_FUNCTION_BLOCK(uldn_open, libicui18n) \ PER_FUNCTION_BLOCK(uloc_canonicalize, libicuuc) \ PER_FUNCTION_BLOCK(uloc_countAvailable, libicuuc) \ PER_FUNCTION_BLOCK(uloc_getAvailable, libicuuc) \ @@ -126,6 +121,7 @@ PER_FUNCTION_BLOCK(uloc_getName, libicuuc) \ PER_FUNCTION_BLOCK(uloc_getParent, libicuuc) \ PER_FUNCTION_BLOCK(uloc_setKeywordValue, libicuuc) \ + PER_FUNCTION_BLOCK(ulocdata_getCLDRVersion, libicui18n) \ PER_FUNCTION_BLOCK(ulocdata_getMeasurementSystem, libicui18n) \ PER_FUNCTION_BLOCK(unorm2_getNFCInstance, libicuuc) \ PER_FUNCTION_BLOCK(unorm2_getNFDInstance, libicuuc) \ @@ -150,16 +146,37 @@ PER_FUNCTION_BLOCK(usearch_openFromCollator, libicui18n) #if HAVE_SET_MAX_VARIABLE -#define FOR_ALL_ICU_FUNCTIONS \ - FOR_ALL_UNCONDITIONAL_ICU_FUNCTIONS \ +#define FOR_ALL_SET_VARIABLE_ICU_FUNCTIONS \ PER_FUNCTION_BLOCK(ucol_setMaxVariable, libicui18n) #else -#define FOR_ALL_ICU_FUNCTIONS \ - FOR_ALL_UNCONDITIONAL_ICU_FUNCTIONS \ +#define FOR_ALL_SET_VARIABLE_ICU_FUNCTIONS \ PER_FUNCTION_BLOCK(ucol_setVariableTop, libicui18n) #endif +#if defined(TARGET_WINDOWS) +#define FOR_ALL_OS_CONDITIONAL_ICU_FUNCTIONS \ + PER_FUNCTION_BLOCK(ucurr_forLocale, libicuuc) \ + PER_FUNCTION_BLOCK(ucurr_getName, libicuuc) \ + PER_FUNCTION_BLOCK(uldn_close, libicuuc) \ + PER_FUNCTION_BLOCK(uldn_keyValueDisplayName, libicuuc) \ + PER_FUNCTION_BLOCK(uldn_open, libicuuc) +#else + // Unix ICU is dynamically resolved at runtime and these APIs in old versions + // of ICU were in libicui18n +#define FOR_ALL_OS_CONDITIONAL_ICU_FUNCTIONS \ + PER_FUNCTION_BLOCK(ucurr_forLocale, libicui18n) \ + PER_FUNCTION_BLOCK(ucurr_getName, libicui18n) \ + PER_FUNCTION_BLOCK(uldn_close, libicui18n) \ + PER_FUNCTION_BLOCK(uldn_keyValueDisplayName, libicui18n) \ + PER_FUNCTION_BLOCK(uldn_open, libicui18n) +#endif + +#define FOR_ALL_ICU_FUNCTIONS \ + FOR_ALL_UNCONDITIONAL_ICU_FUNCTIONS \ + FOR_ALL_SET_VARIABLE_ICU_FUNCTIONS \ + FOR_ALL_OS_CONDITIONAL_ICU_FUNCTIONS + // Declare pointers to all the used ICU functions #define PER_FUNCTION_BLOCK(fn, lib) EXTERN_C __typeof(fn)* fn##_ptr; FOR_ALL_ICU_FUNCTIONS @@ -240,6 +257,7 @@ FOR_ALL_ICU_FUNCTIONS #define uloc_getName(...) uloc_getName_ptr(__VA_ARGS__) #define uloc_getParent(...) uloc_getParent_ptr(__VA_ARGS__) #define uloc_setKeywordValue(...) uloc_setKeywordValue_ptr(__VA_ARGS__) +#define ulocdata_getCLDRVersion(...) ulocdata_getCLDRVersion_ptr(__VA_ARGS__) #define ulocdata_getMeasurementSystem(...) ulocdata_getMeasurementSystem_ptr(__VA_ARGS__) #define unorm2_getNFCInstance(...) unorm2_getNFCInstance_ptr(__VA_ARGS__) #define unorm2_getNFDInstance(...) unorm2_getNFDInstance_ptr(__VA_ARGS__) diff --git a/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim_internal_android.h b/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim_internal_android.h index 5a3ac55072e860..17e1b8d8c8ad03 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim_internal_android.h +++ b/src/libraries/Native/Unix/System.Globalization.Native/pal_icushim_internal_android.h @@ -490,6 +490,7 @@ uint32_t uloc_getLCID(const char * localeID); int32_t uloc_getName(const char * localeID, char * name, int32_t nameCapacity, UErrorCode * err); int32_t uloc_getParent(const char * localeID, char * parent, int32_t parentCapacity, UErrorCode * err); int32_t uloc_setKeywordValue(const char * keywordName, const char * keywordValue, char * buffer, int32_t bufferCapacity, UErrorCode * status); +void ulocdata_getCLDRVersion(UVersionInfo versionArray, UErrorCode * status); UMeasurementSystem ulocdata_getMeasurementSystem(const char * localeID, UErrorCode * status); const UNormalizer2 * unorm2_getNFCInstance(UErrorCode * pErrorCode); const UNormalizer2 * unorm2_getNFDInstance(UErrorCode * pErrorCode); diff --git a/src/libraries/Native/Unix/System.IO.Compression.Native/CMakeLists.txt b/src/libraries/Native/Unix/System.IO.Compression.Native/CMakeLists.txt index 3315941e1acebc..602d6a3989715d 100644 --- a/src/libraries/Native/Unix/System.IO.Compression.Native/CMakeLists.txt +++ b/src/libraries/Native/Unix/System.IO.Compression.Native/CMakeLists.txt @@ -1,10 +1,12 @@ project(System.IO.Compression.Native C) -if (CLR_CMAKE_TARGET_ARCH_WASM) +if (CLR_CMAKE_TARGET_BROWSER) add_definitions(-s USE_ZLIB) elseif (CLR_CMAKE_TARGET_ANDROID) # need special case here since we want to link against libz.so but find_package() would resolve libz.a set(ZLIB_LIBRARIES z) +elseif (CLR_CMAKE_TARGET_SUNOS) + set(ZLIB_LIBRARIES z m) else () find_package(ZLIB REQUIRED) endif () diff --git a/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.c b/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.c index cca1c53aa63e01..4a4babd1854488 100644 --- a/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.c +++ b/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.c @@ -10,6 +10,14 @@ #include #include #include +#include +#include +#include + +// ENODATA is not defined in FreeBSD 10.3 but is defined in 11.0 +#if defined(__FreeBSD__) & !defined(ENODATA) +#define ENODATA ENOATTR +#endif /* Open device file in non-blocking mode and without controlling terminal */ intptr_t SystemIoPortsNative_SerialPortOpen(const char * name) @@ -44,3 +52,38 @@ int SystemIoPortsNative_SerialPortClose(intptr_t handle) ioctl(fd, TIOCNXCL); return close(fd); } + +int32_t SystemIoPortsNative_Read(intptr_t fd, void* buffer, int32_t bufferSize) +{ + return Common_Read(fd, buffer, bufferSize); +} + +int32_t SystemIoPortsNative_Write(intptr_t fd, const void* buffer, int32_t bufferSize) +{ + return Common_Write(fd, buffer, bufferSize); +} + +int32_t SystemIoPortsNative_Poll(PollEvent* pollEvents, uint32_t eventCount, int32_t milliseconds, uint32_t* triggered) +{ + return Common_Poll(pollEvents, eventCount, milliseconds, triggered); +} + +int32_t SystemIoPortsNative_Shutdown(intptr_t socket, int32_t socketShutdown) +{ + return Common_Shutdown(socket, socketShutdown); +} + +int32_t SystemIoPortsNative_ConvertErrorPlatformToPal(int32_t platformErrno) +{ + return ConvertErrorPlatformToPal(platformErrno); +} + +int32_t SystemIoPortsNative_ConvertErrorPalToPlatform(int32_t error) +{ + return ConvertErrorPalToPlatform(error); +} + +const char* SystemIoPortsNative_StrErrorR(int32_t platformErrno, char* buffer, int32_t bufferSize) +{ + return StrErrorR(platformErrno, buffer, bufferSize); +} diff --git a/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.h b/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.h index 3d35b8186ed899..371ceba0e8f70c 100644 --- a/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.h +++ b/src/libraries/Native/Unix/System.IO.Ports.Native/pal_serial.h @@ -2,8 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#include "pal_types.h" -#include "pal_compiler.h" +#include PALEXPORT intptr_t SystemIoPortsNative_SerialPortOpen(const char * name); PALEXPORT int SystemIoPortsNative_SerialPortClose(intptr_t fd); +PALEXPORT int32_t SystemIoPortsNative_Read(intptr_t fd, void* buffer, int32_t bufferSize); +PALEXPORT int32_t SystemIoPortsNative_Write(intptr_t fd, const void* buffer, int32_t bufferSize); +PALEXPORT int32_t SystemIoPortsNative_Poll(PollEvent* pollEvents, uint32_t eventCount, int32_t milliseconds, uint32_t* triggered); +PALEXPORT int32_t SystemIoPortsNative_Shutdown(intptr_t socket, int32_t socketShutdown); +PALEXPORT int32_t SystemIoPortsNative_ConvertErrorPlatformToPal(int32_t platformErrno); +PALEXPORT int32_t SystemIoPortsNative_ConvertErrorPalToPlatform(int32_t error); +PALEXPORT const char* SystemIoPortsNative_StrErrorR(int32_t platformErrno, char* buffer, int32_t bufferSize); diff --git a/src/libraries/Native/Unix/System.IO.Ports.Native/pal_termios.c b/src/libraries/Native/Unix/System.IO.Ports.Native/pal_termios.c index ece77cbad71a75..0943826e8c871a 100644 --- a/src/libraries/Native/Unix/System.IO.Ports.Native/pal_termios.c +++ b/src/libraries/Native/Unix/System.IO.Ports.Native/pal_termios.c @@ -9,6 +9,9 @@ #include #include #include +#if HAVE_SYS_FILIO_H +#include +#endif /* This is dup of System/IO/Ports/NativeMethods.cs */ enum @@ -359,7 +362,12 @@ int32_t SystemIoPortsNative_TermiosSetSpeed(intptr_t handle, int32_t speed) return -1; } +#if HAVE_CFSETSPEED cfsetspeed(&term, brate); +#else // on SunOS, set input and output speeds individually + cfsetispeed(&term, brate); + cfsetospeed(&term, brate); +#endif if (tcsetattr(fd, TCSANOW, &term) < 0) { @@ -418,7 +426,15 @@ int32_t SystemIoPortsNative_TermiosReset(intptr_t handle, int32_t speed, int32_t return -1; } +#if HAVE_CFMAKERAW cfmakeraw(&term); +#else + term.c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + term.c_oflag &= ~OPOST; + term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + term.c_cflag &= ~(CSIZE|PARENB); + term.c_cflag |= CS8; +#endif term.c_cflag |= (CLOCAL | CREAD); term.c_lflag &= ~((tcflag_t)(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG | IEXTEN )); term.c_oflag &= ~((tcflag_t)(OPOST)); @@ -495,7 +511,11 @@ int32_t SystemIoPortsNative_TermiosReset(intptr_t handle, int32_t speed, int32_t return -1; } +#if HAVE_CFSETSPEED ret = cfsetspeed(&term, brate); +#else + ret = cfsetispeed(&term, brate) & cfsetospeed(&term, brate); +#endif } if ((ret != 0) || (tcsetattr(fd, TCSANOW, &term) < 0)) diff --git a/src/libraries/Native/Unix/System.Native/CMakeLists.txt b/src/libraries/Native/Unix/System.Native/CMakeLists.txt index 2c3da0decb9fd8..e72161d0ee77e3 100644 --- a/src/libraries/Native/Unix/System.Native/CMakeLists.txt +++ b/src/libraries/Native/Unix/System.Native/CMakeLists.txt @@ -30,7 +30,7 @@ else () set(NATIVE_SOURCES ${NATIVE_SOURCES} pal_console.c) endif () -if (CLR_CMAKE_TARGET_LINUX AND NOT CLR_CMAKE_TARGET_ARCH_WASM) +if (CLR_CMAKE_TARGET_LINUX AND NOT CLR_CMAKE_TARGET_BROWSER) set(NATIVE_SOURCES ${NATIVE_SOURCES} pal_networkchange.c) if (!HAVE_LINUX_RTNETLINK_H) @@ -52,14 +52,14 @@ if (GEN_SHARED_LIB) ) if (CLR_CMAKE_TARGET_LINUX AND NOT CLR_CMAKE_TARGET_ANDROID) target_link_libraries(System.Native rt) - endif () - - if (CLR_CMAKE_TARGET_FREEBSD) + elseif (CLR_CMAKE_TARGET_FREEBSD) target_link_libraries(System.Native pthread) - if (HAVE_INOTIFY) - find_library(INOTIFY_LIBRARY inotify HINTS /usr/local/lib) - target_link_libraries(System.Native ${INOTIFY_LIBRARY}) - endif () + if (HAVE_INOTIFY) + find_library(INOTIFY_LIBRARY inotify HINTS /usr/local/lib) + target_link_libraries(System.Native ${INOTIFY_LIBRARY}) + endif () + elseif (CLR_CMAKE_TARGET_SUNOS) + target_link_libraries(System.Native socket) endif () install_with_stripped_symbols (System.Native PROGRAMS .) endif () diff --git a/src/libraries/Native/Unix/System.Native/pal_errno.c b/src/libraries/Native/Unix/System.Native/pal_errno.c index d3bfde6d2f97e4..b0da1ec1f548e3 100644 --- a/src/libraries/Native/Unix/System.Native/pal_errno.c +++ b/src/libraries/Native/Unix/System.Native/pal_errno.c @@ -2,459 +2,19 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#include "pal_config.h" #include "pal_errno.h" -#include "pal_utilities.h" - -#include -#include - -// ENODATA is not defined in FreeBSD 10.3 but is defined in 11.0 -#if defined(__FreeBSD__) & !defined(ENODATA) -#define ENODATA ENOATTR -#endif - -#include -#include int32_t SystemNative_ConvertErrorPlatformToPal(int32_t platformErrno) { - switch (platformErrno) - { - case 0: - return Error_SUCCESS; - case E2BIG: - return Error_E2BIG; - case EACCES: - return Error_EACCES; - case EADDRINUSE: - return Error_EADDRINUSE; - case EADDRNOTAVAIL: - return Error_EADDRNOTAVAIL; - case EAFNOSUPPORT: - return Error_EAFNOSUPPORT; - case EAGAIN: - return Error_EAGAIN; - case EALREADY: - return Error_EALREADY; - case EBADF: - return Error_EBADF; - case EBADMSG: - return Error_EBADMSG; - case EBUSY: - return Error_EBUSY; - case ECANCELED: - return Error_ECANCELED; - case ECHILD: - return Error_ECHILD; - case ECONNABORTED: - return Error_ECONNABORTED; - case ECONNREFUSED: - return Error_ECONNREFUSED; - case ECONNRESET: - return Error_ECONNRESET; - case EDEADLK: - return Error_EDEADLK; - case EDESTADDRREQ: - return Error_EDESTADDRREQ; - case EDOM: - return Error_EDOM; - case EDQUOT: - return Error_EDQUOT; - case EEXIST: - return Error_EEXIST; - case EFAULT: - return Error_EFAULT; - case EFBIG: - return Error_EFBIG; - case EHOSTUNREACH: - return Error_EHOSTUNREACH; - case EIDRM: - return Error_EIDRM; - case EILSEQ: - return Error_EILSEQ; - case EINPROGRESS: - return Error_EINPROGRESS; - case EINTR: - return Error_EINTR; - case EINVAL: - return Error_EINVAL; - case EIO: - return Error_EIO; - case EISCONN: - return Error_EISCONN; - case EISDIR: - return Error_EISDIR; - case ELOOP: - return Error_ELOOP; - case EMFILE: - return Error_EMFILE; - case EMLINK: - return Error_EMLINK; - case EMSGSIZE: - return Error_EMSGSIZE; - case EMULTIHOP: - return Error_EMULTIHOP; - case ENAMETOOLONG: - return Error_ENAMETOOLONG; - case ENETDOWN: - return Error_ENETDOWN; - case ENETRESET: - return Error_ENETRESET; - case ENETUNREACH: - return Error_ENETUNREACH; - case ENFILE: - return Error_ENFILE; - case ENOBUFS: - return Error_ENOBUFS; - case ENODEV: - return Error_ENODEV; - case ENOENT: - return Error_ENOENT; - case ENOEXEC: - return Error_ENOEXEC; - case ENOLCK: - return Error_ENOLCK; - case ENOLINK: - return Error_ENOLINK; - case ENOMEM: - return Error_ENOMEM; - case ENOMSG: - return Error_ENOMSG; - case ENOPROTOOPT: - return Error_ENOPROTOOPT; - case ENOSPC: - return Error_ENOSPC; - case ENOSYS: - return Error_ENOSYS; - case ENOTCONN: - return Error_ENOTCONN; - case ENOTDIR: - return Error_ENOTDIR; -#if ENOTEMPTY != EEXIST // AIX defines this - case ENOTEMPTY: - return Error_ENOTEMPTY; -#endif -#ifdef ENOTRECOVERABLE // not available in NetBSD - case ENOTRECOVERABLE: - return Error_ENOTRECOVERABLE; -#endif - case ENOTSOCK: - return Error_ENOTSOCK; - case ENOTSUP: - return Error_ENOTSUP; - case ENOTTY: - return Error_ENOTTY; - case ENXIO: - return Error_ENXIO; - case EOVERFLOW: - return Error_EOVERFLOW; -#ifdef EOWNERDEAD // not available in NetBSD - case EOWNERDEAD: - return Error_EOWNERDEAD; -#endif - case EPERM: - return Error_EPERM; - case EPIPE: - return Error_EPIPE; - case EPROTO: - return Error_EPROTO; - case EPROTONOSUPPORT: - return Error_EPROTONOSUPPORT; - case EPROTOTYPE: - return Error_EPROTOTYPE; - case ERANGE: - return Error_ERANGE; - case EROFS: - return Error_EROFS; - case ESPIPE: - return Error_ESPIPE; - case ESRCH: - return Error_ESRCH; - case ESTALE: - return Error_ESTALE; - case ETIMEDOUT: - return Error_ETIMEDOUT; - case ETXTBSY: - return Error_ETXTBSY; - case EXDEV: - return Error_EXDEV; -#ifdef ESOCKTNOSUPPORT - case ESOCKTNOSUPPORT: - return Error_ESOCKTNOSUPPORT; -#endif - case EPFNOSUPPORT: - return Error_EPFNOSUPPORT; - case ESHUTDOWN: - return Error_ESHUTDOWN; - case EHOSTDOWN: - return Error_EHOSTDOWN; - case ENODATA: - return Error_ENODATA; - -// #if because these will trigger duplicate case label warnings when -// they have the same value, which is permitted by POSIX and common. -#if EOPNOTSUPP != ENOTSUP - case EOPNOTSUPP: - return Error_EOPNOTSUPP; -#endif -#if EWOULDBLOCK != EAGAIN - case EWOULDBLOCK: - return Error_EWOULDBLOCK; -#endif - } - - return Error_ENONSTANDARD; + return ConvertErrorPlatformToPal(platformErrno); } int32_t SystemNative_ConvertErrorPalToPlatform(int32_t error) { - switch (error) - { - case Error_SUCCESS: - return 0; - case Error_E2BIG: - return E2BIG; - case Error_EACCES: - return EACCES; - case Error_EADDRINUSE: - return EADDRINUSE; - case Error_EADDRNOTAVAIL: - return EADDRNOTAVAIL; - case Error_EAFNOSUPPORT: - return EAFNOSUPPORT; - case Error_EAGAIN: - return EAGAIN; - case Error_EALREADY: - return EALREADY; - case Error_EBADF: - return EBADF; - case Error_EBADMSG: - return EBADMSG; - case Error_EBUSY: - return EBUSY; - case Error_ECANCELED: - return ECANCELED; - case Error_ECHILD: - return ECHILD; - case Error_ECONNABORTED: - return ECONNABORTED; - case Error_ECONNREFUSED: - return ECONNREFUSED; - case Error_ECONNRESET: - return ECONNRESET; - case Error_EDEADLK: - return EDEADLK; - case Error_EDESTADDRREQ: - return EDESTADDRREQ; - case Error_EDOM: - return EDOM; - case Error_EDQUOT: - return EDQUOT; - case Error_EEXIST: - return EEXIST; - case Error_EFAULT: - return EFAULT; - case Error_EFBIG: - return EFBIG; - case Error_EHOSTUNREACH: - return EHOSTUNREACH; - case Error_EIDRM: - return EIDRM; - case Error_EILSEQ: - return EILSEQ; - case Error_EINPROGRESS: - return EINPROGRESS; - case Error_EINTR: - return EINTR; - case Error_EINVAL: - return EINVAL; - case Error_EIO: - return EIO; - case Error_EISCONN: - return EISCONN; - case Error_EISDIR: - return EISDIR; - case Error_ELOOP: - return ELOOP; - case Error_EMFILE: - return EMFILE; - case Error_EMLINK: - return EMLINK; - case Error_EMSGSIZE: - return EMSGSIZE; - case Error_EMULTIHOP: - return EMULTIHOP; - case Error_ENAMETOOLONG: - return ENAMETOOLONG; - case Error_ENETDOWN: - return ENETDOWN; - case Error_ENETRESET: - return ENETRESET; - case Error_ENETUNREACH: - return ENETUNREACH; - case Error_ENFILE: - return ENFILE; - case Error_ENOBUFS: - return ENOBUFS; - case Error_ENODEV: - return ENODEV; - case Error_ENOENT: - return ENOENT; - case Error_ENOEXEC: - return ENOEXEC; - case Error_ENOLCK: - return ENOLCK; - case Error_ENOLINK: - return ENOLINK; - case Error_ENOMEM: - return ENOMEM; - case Error_ENOMSG: - return ENOMSG; - case Error_ENOPROTOOPT: - return ENOPROTOOPT; - case Error_ENOSPC: - return ENOSPC; - case Error_ENOSYS: - return ENOSYS; - case Error_ENOTCONN: - return ENOTCONN; - case Error_ENOTDIR: - return ENOTDIR; - case Error_ENOTEMPTY: - return ENOTEMPTY; -#ifdef ENOTRECOVERABLE // not available in NetBSD - case Error_ENOTRECOVERABLE: - return ENOTRECOVERABLE; -#endif - case Error_ENOTSOCK: - return ENOTSOCK; - case Error_ENOTSUP: - return ENOTSUP; - case Error_ENOTTY: - return ENOTTY; - case Error_ENXIO: - return ENXIO; - case Error_EOVERFLOW: - return EOVERFLOW; -#ifdef EOWNERDEAD // not available in NetBSD - case Error_EOWNERDEAD: - return EOWNERDEAD; -#endif - case Error_EPERM: - return EPERM; - case Error_EPIPE: - return EPIPE; - case Error_EPROTO: - return EPROTO; - case Error_EPROTONOSUPPORT: - return EPROTONOSUPPORT; - case Error_EPROTOTYPE: - return EPROTOTYPE; - case Error_ERANGE: - return ERANGE; - case Error_EROFS: - return EROFS; - case Error_ESPIPE: - return ESPIPE; - case Error_ESRCH: - return ESRCH; - case Error_ESTALE: - return ESTALE; - case Error_ETIMEDOUT: - return ETIMEDOUT; - case Error_ETXTBSY: - return ETXTBSY; - case Error_EXDEV: - return EXDEV; - case Error_EPFNOSUPPORT: - return EPFNOSUPPORT; -#ifdef ESOCKTNOSUPPORT - case Error_ESOCKTNOSUPPORT: - return ESOCKTNOSUPPORT; -#endif - case Error_ESHUTDOWN: - return ESHUTDOWN; - case Error_EHOSTDOWN: - return EHOSTDOWN; - case Error_ENODATA: - return ENODATA; - case Error_EHOSTNOTFOUND: - return -(Error_EHOSTNOTFOUND); - case Error_ENONSTANDARD: - break; // fall through to assert - } - - // We should not use this function to round-trip platform -> pal - // -> platform. It's here only to synthesize a platform number - // from the fixed set above. Note that the assert is outside the - // switch rather than in a default case block because not - // having a default will trigger a warning (as error) if there's - // an enum value we haven't handled. Should that trigger, make - // note that there is probably a corresponding missing case in the - // other direction above, but the compiler can't warn in that case - // because the platform values are not part of an enum. - assert_err(false, "Unknown error code", (int) error); - return -1; + return ConvertErrorPalToPlatform(error); } -static int32_t SystemNative_ConvertErrorPalToGai(int32_t error) -{ - switch (error) - { - case -(Error_EHOSTNOTFOUND): - return EAI_NONAME; - } - // Fall-through for unknown codes. gai_strerror() will handle that. - - return error; -} - - - const char* SystemNative_StrErrorR(int32_t platformErrno, char* buffer, int32_t bufferSize) { - assert(buffer != NULL); - assert(bufferSize > 0); - - if (bufferSize < 0) - return NULL; - - if (platformErrno < 0) - { - // Not a system error - SafeStringCopy(buffer, (size_t)bufferSize, gai_strerror(SystemNative_ConvertErrorPalToGai(platformErrno))); - return buffer; - } - -// Note that we must use strerror_r because plain strerror is not -// thread-safe. -// -// However, there are two versions of strerror_r: -// - GNU: char* strerror_r(int, char*, size_t); -// - POSIX: int strerror_r(int, char*, size_t); -// -// The former may or may not use the supplied buffer, and returns -// the error message string. The latter stores the error message -// string into the supplied buffer and returns an error code. - -#if HAVE_GNU_STRERROR_R - const char* message = strerror_r(platformErrno, buffer, (uint32_t) bufferSize); - assert(message != NULL); - return message; -#else - int error = strerror_r(platformErrno, buffer, (uint32_t) bufferSize); - if (error == ERANGE) - { - // Buffer is too small to hold the entire message, but has - // still been filled to the extent possible and null-terminated. - return NULL; - } - - // The only other valid error codes are 0 for success or EINVAL for - // an unknown error, but in the latter case a reasonable string (e.g - // "Unknown error: 0x123") is returned. - assert_err(error == 0 || error == EINVAL, "invalid error", error); - return buffer; -#endif + return StrErrorR(platformErrno, buffer, bufferSize); } diff --git a/src/libraries/Native/Unix/System.Native/pal_errno.h b/src/libraries/Native/Unix/System.Native/pal_errno.h index c4ba9ccd6e5080..f73fe707c59fb2 100644 --- a/src/libraries/Native/Unix/System.Native/pal_errno.h +++ b/src/libraries/Native/Unix/System.Native/pal_errno.h @@ -4,127 +4,7 @@ #pragma once -#include "pal_compiler.h" -#include "pal_types.h" - -/** - * Error codes returned via ConvertErrno. - * - * Only the names (without the PAL_ prefix) are specified by POSIX. - * - * The values chosen below are simply assigned arbitrarily (originally - * in alphabetical order they appear in the spec, but they can't change so - * add new values to the end!). - * - * Also, the values chosen are deliberately outside the range of - * typical UNIX errnos (small numbers), HRESULTs (negative for errors) - * and Win32 errors (0x0000 - 0xFFFF). This isn't required for - * correctness, but may help debug a caller that is interpreting a raw - * int incorrectly. - * - * Wherever the spec says "x may be the same value as y", we do use - * the same value so that callers cannot not take a dependency on - * being able to distinguish between them. - */ -typedef enum -{ - Error_SUCCESS = 0, - - Error_E2BIG = 0x10001, // Argument list too long. - Error_EACCES = 0x10002, // Permission denied. - Error_EADDRINUSE = 0x10003, // Address in use. - Error_EADDRNOTAVAIL = 0x10004, // Address not available. - Error_EAFNOSUPPORT = 0x10005, // Address family not supported. - Error_EAGAIN = 0x10006, // Resource unavailable, try again (same value as EWOULDBLOCK), - Error_EALREADY = 0x10007, // Connection already in progress. - Error_EBADF = 0x10008, // Bad file descriptor. - Error_EBADMSG = 0x10009, // Bad message. - Error_EBUSY = 0x1000A, // Device or resource busy. - Error_ECANCELED = 0x1000B, // Operation canceled. - Error_ECHILD = 0x1000C, // No child processes. - Error_ECONNABORTED = 0x1000D, // Connection aborted. - Error_ECONNREFUSED = 0x1000E, // Connection refused. - Error_ECONNRESET = 0x1000F, // Connection reset. - Error_EDEADLK = 0x10010, // Resource deadlock would occur. - Error_EDESTADDRREQ = 0x10011, // Destination address required. - Error_EDOM = 0x10012, // Mathematics argument out of domain of function. - Error_EDQUOT = 0x10013, // Reserved. - Error_EEXIST = 0x10014, // File exists. - Error_EFAULT = 0x10015, // Bad address. - Error_EFBIG = 0x10016, // File too large. - Error_EHOSTUNREACH = 0x10017, // Host is unreachable. - Error_EIDRM = 0x10018, // Identifier removed. - Error_EILSEQ = 0x10019, // Illegal byte sequence. - Error_EINPROGRESS = 0x1001A, // Operation in progress. - Error_EINTR = 0x1001B, // Interrupted function. - Error_EINVAL = 0x1001C, // Invalid argument. - Error_EIO = 0x1001D, // I/O error. - Error_EISCONN = 0x1001E, // Socket is connected. - Error_EISDIR = 0x1001F, // Is a directory. - Error_ELOOP = 0x10020, // Too many levels of symbolic links. - Error_EMFILE = 0x10021, // File descriptor value too large. - Error_EMLINK = 0x10022, // Too many links. - Error_EMSGSIZE = 0x10023, // Message too large. - Error_EMULTIHOP = 0x10024, // Reserved. - Error_ENAMETOOLONG = 0x10025, // Filename too long. - Error_ENETDOWN = 0x10026, // Network is down. - Error_ENETRESET = 0x10027, // Connection aborted by network. - Error_ENETUNREACH = 0x10028, // Network unreachable. - Error_ENFILE = 0x10029, // Too many files open in system. - Error_ENOBUFS = 0x1002A, // No buffer space available. - Error_ENODEV = 0x1002C, // No such device. - Error_ENOENT = 0x1002D, // No such file or directory. - Error_ENOEXEC = 0x1002E, // Executable file format error. - Error_ENOLCK = 0x1002F, // No locks available. - Error_ENOLINK = 0x10030, // Reserved. - Error_ENOMEM = 0x10031, // Not enough space. - Error_ENOMSG = 0x10032, // No message of the desired type. - Error_ENOPROTOOPT = 0x10033, // Protocol not available. - Error_ENOSPC = 0x10034, // No space left on device. - Error_ENOSYS = 0x10037, // Function not supported. - Error_ENOTCONN = 0x10038, // The socket is not connected. - Error_ENOTDIR = 0x10039, // Not a directory or a symbolic link to a directory. - Error_ENOTEMPTY = 0x1003A, // Directory not empty. - Error_ENOTRECOVERABLE = 0x1003B, // State not recoverable. - Error_ENOTSOCK = 0x1003C, // Not a socket. - Error_ENOTSUP = 0x1003D, // Not supported (same value as EOPNOTSUP). - Error_ENOTTY = 0x1003E, // Inappropriate I/O control operation. - Error_ENXIO = 0x1003F, // No such device or address. - Error_EOVERFLOW = 0x10040, // Value too large to be stored in data type. - Error_EOWNERDEAD = 0x10041, // Previous owner died. - Error_EPERM = 0x10042, // Operation not permitted. - Error_EPIPE = 0x10043, // Broken pipe. - Error_EPROTO = 0x10044, // Protocol error. - Error_EPROTONOSUPPORT = 0x10045, // Protocol not supported. - Error_EPROTOTYPE = 0x10046, // Protocol wrong type for socket. - Error_ERANGE = 0x10047, // Result too large. - Error_EROFS = 0x10048, // Read-only file system. - Error_ESPIPE = 0x10049, // Invalid seek. - Error_ESRCH = 0x1004A, // No such process. - Error_ESTALE = 0x1004B, // Reserved. - Error_ETIMEDOUT = 0x1004D, // Connection timed out. - Error_ETXTBSY = 0x1004E, // Text file busy. - Error_EXDEV = 0x1004F, // Cross-device link. - Error_ESOCKTNOSUPPORT = 0x1005E, // Socket type not supported. - Error_EPFNOSUPPORT = 0x10060, // Protocol family not supported. - Error_ESHUTDOWN = 0x1006C, // Socket shutdown. - Error_EHOSTDOWN = 0x10070, // Host is down. - Error_ENODATA = 0x10071, // No data available. - - // Error codes to track errors beyond kernel. - Error_EHOSTNOTFOUND = 0x20001, // Name lookup failed. - - // POSIX permits these to have the same value and we make them - // always equal so that we cannot introduce a dependency on - // distinguishing between them that would not work on all - // platforms. - Error_EOPNOTSUPP = Error_ENOTSUP, // Operation not supported on socket - Error_EWOULDBLOCK = Error_EAGAIN, // Operation would block - - // This one is not part of POSIX, but is a catch-all for the case - // where we cannot convert the raw errno value to something above. - Error_ENONSTANDARD = 0x1FFFF, -} Error; +#include /** * Converts the given raw numeric value obtained via errno -> diff --git a/src/libraries/Native/Unix/System.Native/pal_interfaceaddresses.c b/src/libraries/Native/Unix/System.Native/pal_interfaceaddresses.c index a18257839cbf9a..7c64c54dfedb23 100644 --- a/src/libraries/Native/Unix/System.Native/pal_interfaceaddresses.c +++ b/src/libraries/Native/Unix/System.Native/pal_interfaceaddresses.c @@ -20,6 +20,9 @@ #if HAVE_SYS_SYSCTL_H #include #endif +#if HAVE_SYS_IOCTL_H +#include +#endif #if HAVE_ETHTOOL_H #include #include @@ -28,11 +31,11 @@ #if defined(AF_PACKET) #include -#if defined(_WASM_) +#if HAVE_NETPACKET_PACKET_H #include -#else // _WASM_ +#else #include -#endif // _WASM_ +#endif #elif defined(AF_LINK) #include #include @@ -431,7 +434,7 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter #endif } -#if HAVE_RT_MSGHDR +#if HAVE_RT_MSGHDR && defined(CTL_NET) int32_t SystemNative_EnumerateGatewayAddressesForInterface(uint32_t interfaceIndex, GatewayAddressFound onGatewayFound) { static struct in6_addr anyaddr = IN6ADDR_ANY_INIT; diff --git a/src/libraries/Native/Unix/System.Native/pal_io.c b/src/libraries/Native/Unix/System.Native/pal_io.c index 609084644c5c4c..ccae4e87c97568 100644 --- a/src/libraries/Native/Unix/System.Native/pal_io.c +++ b/src/libraries/Native/Unix/System.Native/pal_io.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -921,120 +920,7 @@ int32_t SystemNative_FTruncate(intptr_t fd, int64_t length) int32_t SystemNative_Poll(PollEvent* pollEvents, uint32_t eventCount, int32_t milliseconds, uint32_t* triggered) { - if (pollEvents == NULL || triggered == NULL) - { - return Error_EFAULT; - } - - if (milliseconds < -1) - { - return Error_EINVAL; - } - - struct pollfd stackBuffer[(uint32_t)(2048/sizeof(struct pollfd))]; - int useStackBuffer = eventCount <= (sizeof(stackBuffer)/sizeof(stackBuffer[0])); - struct pollfd* pollfds = NULL; - if (useStackBuffer) - { - pollfds = (struct pollfd*)&stackBuffer[0]; - } - else - { - pollfds = (struct pollfd*)calloc(eventCount, sizeof(*pollfds)); - if (pollfds == NULL) - { - return Error_ENOMEM; - } - } - - for (uint32_t i = 0; i < eventCount; i++) - { - const PollEvent* event = &pollEvents[i]; - pollfds[i].fd = event->FileDescriptor; - // we need to do this for platforms like AIX where PAL_POLL* doesn't - // match up to their reality; this is PollEvent -> system polling - switch (event->Events) - { - case PAL_POLLIN: - pollfds[i].events = POLLIN; - break; - case PAL_POLLPRI: - pollfds[i].events = POLLPRI; - break; - case PAL_POLLOUT: - pollfds[i].events = POLLOUT; - break; - case PAL_POLLERR: - pollfds[i].events = POLLERR; - break; - case PAL_POLLHUP: - pollfds[i].events = POLLHUP; - break; - case PAL_POLLNVAL: - pollfds[i].events = POLLNVAL; - break; - default: - pollfds[i].events = event->Events; - break; - } - pollfds[i].revents = 0; - } - - int rv; - while ((rv = poll(pollfds, (nfds_t)eventCount, milliseconds)) < 0 && errno == EINTR); - - if (rv < 0) - { - if (!useStackBuffer) - { - free(pollfds); - } - - *triggered = 0; - return SystemNative_ConvertErrorPlatformToPal(errno); - } - - for (uint32_t i = 0; i < eventCount; i++) - { - const struct pollfd* pfd = &pollfds[i]; - assert(pfd->fd == pollEvents[i].FileDescriptor); - assert(pfd->events == pollEvents[i].Events); - - // same as the other switch, just system -> PollEvent - switch (pfd->revents) - { - case POLLIN: - pollEvents[i].TriggeredEvents = PAL_POLLIN; - break; - case POLLPRI: - pollEvents[i].TriggeredEvents = PAL_POLLPRI; - break; - case POLLOUT: - pollEvents[i].TriggeredEvents = PAL_POLLOUT; - break; - case POLLERR: - pollEvents[i].TriggeredEvents = PAL_POLLERR; - break; - case POLLHUP: - pollEvents[i].TriggeredEvents = PAL_POLLHUP; - break; - case POLLNVAL: - pollEvents[i].TriggeredEvents = PAL_POLLNVAL; - break; - default: - pollEvents[i].TriggeredEvents = (int16_t)pfd->revents; - break; - } - } - - *triggered = (uint32_t)rv; - - if (!useStackBuffer) - { - free(pollfds); - } - - return Error_SUCCESS; + return Common_Poll(pollEvents, eventCount, milliseconds, triggered); } int32_t SystemNative_PosixFAdvise(intptr_t fd, int64_t offset, int64_t length, int32_t advice) @@ -1085,20 +971,7 @@ char* SystemNative_GetLine(FILE* stream) int32_t SystemNative_Read(intptr_t fd, void* buffer, int32_t bufferSize) { - assert(buffer != NULL || bufferSize == 0); - assert(bufferSize >= 0); - - if (bufferSize < 0) - { - errno = EINVAL; - return -1; - } - - ssize_t count; - while ((count = read(ToFileDescriptor(fd), buffer, (uint32_t)bufferSize)) < 0 && errno == EINTR); - - assert(count >= -1 && count <= bufferSize); - return (int32_t)count; + return Common_Read(fd, buffer, bufferSize); } int32_t SystemNative_ReadLink(const char* path, char* buffer, int32_t bufferSize) @@ -1139,20 +1012,7 @@ void SystemNative_Sync(void) int32_t SystemNative_Write(intptr_t fd, const void* buffer, int32_t bufferSize) { - assert(buffer != NULL || bufferSize == 0); - assert(bufferSize >= 0); - - if (bufferSize < 0) - { - errno = ERANGE; - return -1; - } - - ssize_t count; - while ((count = write(ToFileDescriptor(fd), buffer, (uint32_t)bufferSize)) < 0 && errno == EINTR); - - assert(count >= -1 && count <= bufferSize); - return (int32_t)count; + return Common_Write(fd, buffer, bufferSize); } // Read all data from inFd and write it to outFd @@ -1420,7 +1280,7 @@ int32_t SystemNative_GetPeerID(intptr_t socket, uid_t* euid) // ucred causes Emscripten to fail even though it's defined, // but getting peer credentials won't work for WebAssembly anyway -#if defined(SO_PEERCRED) && !defined(_WASM_) +#if defined(SO_PEERCRED) && !defined(TARGET_WASM) struct ucred creds; socklen_t len = sizeof(creds); if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &len) == 0) diff --git a/src/libraries/Native/Unix/System.Native/pal_io.h b/src/libraries/Native/Unix/System.Native/pal_io.h index 9f68aa3d62f9ea..3c7384b50f16a1 100644 --- a/src/libraries/Native/Unix/System.Native/pal_io.h +++ b/src/libraries/Native/Unix/System.Native/pal_io.h @@ -11,6 +11,7 @@ #include #include #include +#include /** * File status returned by Stat or FStat. @@ -259,20 +260,6 @@ typedef enum PAL_SC_PAGESIZE = 2, // Size of a page in bytes } SysConfName; -/** - * Constants passed to and from poll describing what to poll for and what - * kind of data was received from poll. - */ -typedef enum -{ - PAL_POLLIN = 0x0001, /* non-urgent readable data available */ - PAL_POLLPRI = 0x0002, /* urgent readable data available */ - PAL_POLLOUT = 0x0004, /* data can be written without blocked */ - PAL_POLLERR = 0x0008, /* an error occurred */ - PAL_POLLHUP = 0x0010, /* the file descriptor hung up */ - PAL_POLLNVAL = 0x0020, /* the requested events were invalid */ -} PollEvents; - /** * Constants passed to posix_advise to give hints to the kernel about the type of I/O * operations that will occur. @@ -297,16 +284,6 @@ typedef struct int32_t InodeType; // The inode type as described in the NodeType enum } DirectoryEntry; -/** - * Our intermediate pollfd struct to normalize the data types - */ -typedef struct -{ - int32_t FileDescriptor; // The file descriptor to poll - int16_t Events; // The events to poll for - int16_t TriggeredEvents; // The events that triggered the poll -} PollEvent; - /** * Constants passed in the mask argument of INotifyAddWatch which identify inotify events. */ diff --git a/src/libraries/Native/Unix/System.Native/pal_log.h b/src/libraries/Native/Unix/System.Native/pal_log.h index bf6f680ce375c4..a9a709391779e7 100644 --- a/src/libraries/Native/Unix/System.Native/pal_log.h +++ b/src/libraries/Native/Unix/System.Native/pal_log.h @@ -9,6 +9,8 @@ PALEXPORT void SystemNative_Log(uint8_t* buffer, int32_t length); +PALEXPORT int32_t SystemNative_InitializeTerminalAndSignalHandling(void); + // Called by pal_signal.cpp to reinitialize the console on SIGCONT/SIGCHLD. void ReinitializeTerminal(void) {} void UninitializeTerminal(void) {} \ No newline at end of file diff --git a/src/libraries/Native/Unix/System.Native/pal_log.m b/src/libraries/Native/Unix/System.Native/pal_log.m index e63bf4e8bd83a4..16452cd49ac6de 100644 --- a/src/libraries/Native/Unix/System.Native/pal_log.m +++ b/src/libraries/Native/Unix/System.Native/pal_log.m @@ -39,4 +39,9 @@ void SystemNative_Log (uint8_t* buffer, int32_t length) NSLog (@"%@", msg); } [msg release]; +} + +int32_t SystemNative_InitializeTerminalAndSignalHandling(void) +{ + return 0; } \ No newline at end of file diff --git a/src/libraries/Native/Unix/System.Native/pal_maphardwaretype.c b/src/libraries/Native/Unix/System.Native/pal_maphardwaretype.c index dbd74cc21047e1..1289307d303003 100644 --- a/src/libraries/Native/Unix/System.Native/pal_maphardwaretype.c +++ b/src/libraries/Native/Unix/System.Native/pal_maphardwaretype.c @@ -9,13 +9,16 @@ #include #if defined(AF_PACKET) -#if defined(_WASM_) +#if HAVE_NETPACKET_PACKET_H #include -#include -#else // _WASM_ +#else #include +#endif +#if HAVE_NET_IF_ARP_H +#include +#else #include -#endif // _WASM_ +#endif #elif defined(AF_LINK) #include #include @@ -43,7 +46,9 @@ uint16_t MapHardwareType(uint16_t nativeType) case ARPHRD_PPP: return NetworkInterfaceType_Ppp; case ARPHRD_TUNNEL: +#ifdef ARPHRD_TUNNEL6 case ARPHRD_TUNNEL6: +#endif return NetworkInterfaceType_Tunnel; case ARPHRD_LOOPBACK: return NetworkInterfaceType_Loopback; diff --git a/src/libraries/Native/Unix/System.Native/pal_mount.c b/src/libraries/Native/Unix/System.Native/pal_mount.c index 7fe0aeeaecf24d..ce4daa7786cb29 100644 --- a/src/libraries/Native/Unix/System.Native/pal_mount.c +++ b/src/libraries/Native/Unix/System.Native/pal_mount.c @@ -15,7 +15,13 @@ #include #else #include +#if HAVE_SYS_MNTENT_H +#include +#include +#include +#else #include +#endif #define STRING_BUFFER_SIZE 8192 // Android does not define MNTOPT_RO @@ -42,8 +48,28 @@ static int32_t GetMountInfo(MountPointFound onFound) return 0; } -#else +#elif HAVE_SYS_MNTENT_H + int result = -1; + FILE* fp = fopen("/proc/mounts", MNTOPT_RO); + if (fp != NULL) + { + char buffer[STRING_BUFFER_SIZE] = {0}; + struct mnttab entry; + while(getmntent(fp, &entry) == 0) + { + onFound(entry.mnt_mountp); + } + result = fclose(fp); + assert(result == 1); // documented to always return 1 + result = + 0; // We need to standardize a success return code between our implementations, so settle on 0 for success + } + + return result; +} + +#else int result = -1; FILE* fp = setmntent("/proc/mounts", MNTOPT_RO); if (fp != NULL) @@ -78,7 +104,7 @@ int32_t SystemNative_GetSpaceInfoForMountPoint(const char* name, MountPointInfor assert(name != NULL); assert(mpi != NULL); -#if defined(HAVE_STATFS) +#if HAVE_NON_LEGACY_STATFS struct statfs stats; memset(&stats, 0, sizeof(struct statfs)); @@ -117,7 +143,7 @@ SystemNative_GetFormatInfoForMountPoint(const char* name, char* formatNameBuffer assert((formatNameBuffer != NULL) && (formatType != NULL)); assert(bufferLength > 0); -#if defined(HAVE_STATFS) +#if HAVE_NON_LEGACY_STATFS struct statfs stats; int result = statfs(name, &stats); #else @@ -142,12 +168,12 @@ SystemNative_GetFormatInfoForMountPoint(const char* name, char* formatNameBuffer SafeStringCopy(formatNameBuffer, Int32ToSizeT(bufferLength), stats.f_fstypename); *formatType = -1; } -#elif defined(HAVE_STATFS) +#elif HAVE_NON_LEGACY_STATFS assert(formatType != NULL); *formatType = (int64_t)(stats.f_type); SafeStringCopy(formatNameBuffer, Int32ToSizeT(bufferLength), ""); #else - *formatType = 0; + *formatType = 0; #endif } else diff --git a/src/libraries/Native/Unix/System.Native/pal_networking.c b/src/libraries/Native/Unix/System.Native/pal_networking.c index 08540e24b18e54..9aabac040abe71 100644 --- a/src/libraries/Native/Unix/System.Native/pal_networking.c +++ b/src/libraries/Native/Unix/System.Native/pal_networking.c @@ -7,6 +7,7 @@ #include "pal_io.h" #include "pal_safecrt.h" #include "pal_utilities.h" +#include #include #include @@ -23,6 +24,10 @@ #elif HAVE_SYS_POLL_H #include #endif +#if HAVE_SYS_PROCINFO_H +#include +#include +#endif #include #include #include @@ -56,6 +61,10 @@ #if HAVE_LINUX_CAN_H #include #endif +#if HAVE_SYS_FILIO_H +#include +#endif + #if HAVE_KQUEUE #if KEVENT_HAS_VOID_UDATA static void* GetKeventUdata(uintptr_t udata) @@ -674,7 +683,7 @@ int32_t SystemNative_GetAddressFamily(const uint8_t* socketAddress, int32_t sock if (!TryConvertAddressFamilyPlatformToPal(sockAddr->sa_family, addressFamily)) { - return Error_EAFNOSUPPORT; + *addressFamily = AddressFamily_AF_UNKNOWN; } return Error_SUCCESS; @@ -1339,6 +1348,34 @@ static int32_t ConvertSocketFlagsPlatformToPal(int platformFlags) ((platformFlags & MSG_CTRUNC) == 0 ? 0 : SocketFlags_MSG_CTRUNC); } +int32_t SystemNative_Receive(intptr_t socket, void* buffer, int32_t bufferLen, int32_t flags, int32_t* received) +{ + if (buffer == NULL || bufferLen < 0 || received == NULL) + { + return Error_EFAULT; + } + + int fd = ToFileDescriptor(socket); + + int socketFlags; + if (!ConvertSocketFlagsPalToPlatform(flags, &socketFlags)) + { + return Error_ENOTSUP; + } + + ssize_t res; + while ((res = recv(fd, buffer, (size_t)bufferLen, socketFlags)) < 0 && errno == EINTR); + + if (res != -1) + { + *received = (int32_t)res; + return Error_SUCCESS; + } + + *received = 0; + return SystemNative_ConvertErrorPlatformToPal(errno); +} + int32_t SystemNative_ReceiveMessage(intptr_t socket, MessageHeader* messageHeader, int32_t flags, int64_t* received) { if (messageHeader == NULL || received == NULL || messageHeader->SocketAddressLen < 0 || @@ -1382,6 +1419,38 @@ int32_t SystemNative_ReceiveMessage(intptr_t socket, MessageHeader* messageHeade return SystemNative_ConvertErrorPlatformToPal(errno); } +int32_t SystemNative_Send(intptr_t socket, void* buffer, int32_t bufferLen, int32_t flags, int32_t* sent) +{ + if (buffer == NULL || bufferLen < 0 || sent == NULL) + { + return Error_EFAULT; + } + + int fd = ToFileDescriptor(socket); + + int socketFlags; + if (!ConvertSocketFlagsPalToPlatform(flags, &socketFlags)) + { + return Error_ENOTSUP; + } + + ssize_t res; +#if defined(__APPLE__) && __APPLE__ + // possible OSX kernel bug: https://github.com/dotnet/runtime/issues/27221 + while ((res = send(fd, buffer, (size_t)bufferLen, socketFlags)) < 0 && (errno == EINTR || errno == EPROTOTYPE)); +#else + while ((res = send(fd, buffer, (size_t)bufferLen, socketFlags)) < 0 && errno == EINTR); +#endif + if (res != -1) + { + *sent = (int32_t)res; + return Error_SUCCESS; + } + + *sent = 0; + return SystemNative_ConvertErrorPlatformToPal(errno); +} + int32_t SystemNative_SendMessage(intptr_t socket, MessageHeader* messageHeader, int32_t flags, int64_t* sent) { if (messageHeader == NULL || sent == NULL || messageHeader->SocketAddressLen < 0 || @@ -1403,7 +1472,7 @@ int32_t SystemNative_SendMessage(intptr_t socket, MessageHeader* messageHeader, ssize_t res; #if defined(__APPLE__) && __APPLE__ - // possible OSX kernel bug: #31927 + // possible OSX kernel bug: https://github.com/dotnet/runtime/issues/27221 while ((res = sendmsg(fd, &header, socketFlags)) < 0 && (errno == EINTR || errno == EPROTOTYPE)); #else while ((res = sendmsg(fd, &header, socketFlags)) < 0 && errno == EINTR); @@ -1558,29 +1627,7 @@ int32_t SystemNative_Listen(intptr_t socket, int32_t backlog) int32_t SystemNative_Shutdown(intptr_t socket, int32_t socketShutdown) { - int fd = ToFileDescriptor(socket); - - int how; - switch (socketShutdown) - { - case SocketShutdown_SHUT_READ: - how = SHUT_RD; - break; - - case SocketShutdown_SHUT_WRITE: - how = SHUT_WR; - break; - - case SocketShutdown_SHUT_BOTH: - how = SHUT_RDWR; - break; - - default: - return Error_EINVAL; - } - - int err = shutdown(fd, how); - return err == 0 ? Error_SUCCESS : SystemNative_ConvertErrorPlatformToPal(errno); + return Common_Shutdown(socket, socketShutdown); } int32_t SystemNative_GetSocketErrorOption(intptr_t socket, int32_t* error) @@ -1605,14 +1652,14 @@ int32_t SystemNative_GetSocketErrorOption(intptr_t socket, int32_t* error) return Error_SUCCESS; } -static bool TryGetPlatformSocketOption(int32_t socketOptionName, int32_t socketOptionLevel, int* optLevel, int* optName) +static bool TryGetPlatformSocketOption(int32_t socketOptionLevel, int32_t socketOptionName, int* optLevel, int* optName) { - switch (socketOptionName) + switch (socketOptionLevel) { case SocketOptionLevel_SOL_SOCKET: *optLevel = SOL_SOCKET; - switch (socketOptionLevel) + switch (socketOptionName) { case SocketOptionName_SO_DEBUG: *optName = SO_DEBUG; @@ -1693,7 +1740,7 @@ static bool TryGetPlatformSocketOption(int32_t socketOptionName, int32_t socketO case SocketOptionLevel_SOL_IP: *optLevel = IPPROTO_IP; - switch (socketOptionLevel) + switch (socketOptionName) { case SocketOptionName_SO_IP_OPTIONS: *optName = IP_OPTIONS; @@ -1772,7 +1819,7 @@ static bool TryGetPlatformSocketOption(int32_t socketOptionName, int32_t socketO case SocketOptionLevel_SOL_IPV6: *optLevel = IPPROTO_IPV6; - switch (socketOptionLevel) + switch (socketOptionName) { case SocketOptionName_SO_IPV6_HOPLIMIT: *optName = IPV6_HOPLIMIT; @@ -1806,7 +1853,7 @@ static bool TryGetPlatformSocketOption(int32_t socketOptionName, int32_t socketO case SocketOptionLevel_SOL_TCP: *optLevel = IPPROTO_TCP; - switch (socketOptionLevel) + switch (socketOptionName) { case SocketOptionName_SO_TCP_NODELAY: *optName = TCP_NODELAY; @@ -1838,7 +1885,7 @@ static bool TryGetPlatformSocketOption(int32_t socketOptionName, int32_t socketO case SocketOptionLevel_SOL_UDP: *optLevel = IPPROTO_UDP; - switch (socketOptionLevel) + switch (socketOptionName) { // case SocketOptionName_SO_UDP_NOCHECKSUM: @@ -1902,7 +1949,7 @@ int32_t SystemNative_GetSockOpt( int fd = ToFileDescriptor(socket); // - // Handle some special cases for compatibility with Windows + // Handle some special cases for compatibility with Windows and OSX // if (socketOptionLevel == SocketOptionLevel_SOL_SOCKET) { @@ -1939,6 +1986,25 @@ int32_t SystemNative_GetSockOpt( #endif return Error_SUCCESS; } +#if defined(__APPLE__) && HAVE_SYS_PROCINFO_H + // OSX does not have SO_ACCEPTCONN getsockopt. + else if (socketOptionName == SocketOptionName_SO_ACCEPTCONN) + { + if (*optionLen != sizeof(int32_t)) + { + return Error_EINVAL; + } + + struct socket_fdinfo fdi; + if (proc_pidfdinfo(getpid(), fd, PROC_PIDFDSOCKETINFO, &fdi, sizeof(fdi)) < sizeof(fdi)) + { + return SystemNative_ConvertErrorPlatformToPal(errno); + } + int value = (fdi.psi.soi_options & SO_ACCEPTCONN) != 0; + *(int32_t*)optionValue = value; + return Error_SUCCESS; + } +#endif } int optLevel, optName; @@ -2310,7 +2376,7 @@ static bool TryConvertProtocolTypePlatformToPal(int32_t palAddressFamily, int pl return true; default: - *palProtocolType = (int)palProtocolType; + *palProtocolType = (int32_t)(intptr_t)palProtocolType; return false; } @@ -2418,15 +2484,39 @@ int32_t SystemNative_Socket(int32_t addressFamily, int32_t socketType, int32_t p return Error_SUCCESS; } -int32_t SystemNative_GetSocketType(intptr_t socket, int32_t* addressFamily, int32_t* socketType, int32_t* protocolType) +int32_t SystemNative_GetSocketType(intptr_t socket, int32_t* addressFamily, int32_t* socketType, int32_t* protocolType, int32_t* isListening) { - if (addressFamily == NULL || socketType == NULL || protocolType == NULL) + if (addressFamily == NULL || socketType == NULL || protocolType == NULL || isListening == NULL) { return Error_EFAULT; } int fd = ToFileDescriptor(socket); +#if HAVE_SYS_PROCINFO_H + struct socket_fdinfo fdi; + if (proc_pidfdinfo(getpid(), fd, PROC_PIDFDSOCKETINFO, &fdi, sizeof(fdi)) < sizeof(fdi)) + { + return Error_EFAULT; + } + + if (!TryConvertAddressFamilyPlatformToPal((sa_family_t)fdi.psi.soi_family, addressFamily)) + { + *addressFamily = AddressFamily_AF_UNKNOWN; + } + + if (!TryConvertSocketTypePlatformToPal(fdi.psi.soi_type, socketType)) + { + *socketType = SocketType_UNKNOWN; + } + + if (!TryConvertProtocolTypePlatformToPal(*addressFamily, fdi.psi.soi_protocol, protocolType)) + { + *protocolType = ProtocolType_PT_UNKNOWN; + } + + *isListening = (fdi.psi.soi_options & SO_ACCEPTCONN) != 0; +#else #ifdef SO_DOMAIN int domainValue; socklen_t domainLength = sizeof(int); @@ -2457,6 +2547,17 @@ int32_t SystemNative_GetSocketType(intptr_t socket, int32_t* addressFamily, int3 *protocolType = ProtocolType_PT_UNKNOWN; } + int listeningValue; + socklen_t listeningLength = sizeof(int); + if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &listeningValue, &listeningLength) == 0) + { + *isListening = (listeningValue != 0); + } + else + { + *isListening = 0; + } +#endif return Error_SUCCESS; } @@ -2966,6 +3067,11 @@ void SystemNative_GetDomainSocketSizes(int32_t* pathOffset, int32_t* pathSize, i *addressSize = sizeof(domainSocket); } +int32_t SystemNative_GetMaximumAddressSize(void) +{ + return sizeof(struct sockaddr_storage); +} + int32_t SystemNative_Disconnect(intptr_t socket) { int fd = ToFileDescriptor(socket); diff --git a/src/libraries/Native/Unix/System.Native/pal_networking.h b/src/libraries/Native/Unix/System.Native/pal_networking.h index 3dbc08932b9208..04f26eb6650d18 100644 --- a/src/libraries/Native/Unix/System.Native/pal_networking.h +++ b/src/libraries/Native/Unix/System.Native/pal_networking.h @@ -7,6 +7,7 @@ #include "pal_compiler.h" #include "pal_types.h" #include "pal_errno.h" +#include /** * These error values are different on every platform so make a @@ -111,18 +112,6 @@ typedef enum MulticastOption_MULTICAST_IF = 2 // IP_MULTICAST_IF } MulticastOption; -/* - * Socket shutdown modes. - * - * NOTE: these values are taken from System.Net.SocketShutdown. - */ -typedef enum -{ - SocketShutdown_SHUT_READ = 0, // SHUT_RD - SocketShutdown_SHUT_WRITE = 1, // SHUT_WR - SocketShutdown_SHUT_BOTH = 2, // SHUT_RDWR -} SockerShutdown; - /* * Socket option levels. * @@ -371,8 +360,12 @@ PALEXPORT int32_t SystemNative_SetReceiveTimeout(intptr_t socket, int32_t millis PALEXPORT int32_t SystemNative_SetSendTimeout(intptr_t socket, int32_t millisecondsTimeout); +PALEXPORT int32_t SystemNative_Receive(intptr_t socket, void* buffer, int32_t bufferLen, int32_t flags, int32_t* received); + PALEXPORT int32_t SystemNative_ReceiveMessage(intptr_t socket, MessageHeader* messageHeader, int32_t flags, int64_t* received); +PALEXPORT int32_t SystemNative_Send(intptr_t socket, void* buffer, int32_t bufferLen, int32_t flags, int32_t* sent); + PALEXPORT int32_t SystemNative_SendMessage(intptr_t socket, MessageHeader* messageHeader, int32_t flags, int64_t* sent); PALEXPORT int32_t SystemNative_Accept(intptr_t socket, uint8_t* socketAddress, int32_t* socketAddressLen, intptr_t* acceptedSocket); @@ -405,7 +398,7 @@ PALEXPORT int32_t SystemNative_SetRawSockOpt( PALEXPORT int32_t SystemNative_Socket(int32_t addressFamily, int32_t socketType, int32_t protocolType, intptr_t* createdSocket); -PALEXPORT int32_t SystemNative_GetSocketType(intptr_t socket, int32_t* addressFamily, int32_t* socketType, int32_t* protocolType); +PALEXPORT int32_t SystemNative_GetSocketType(intptr_t socket, int32_t* addressFamily, int32_t* socketType, int32_t* protocolType, int32_t* isListening); PALEXPORT int32_t SystemNative_GetAtOutOfBandMark(intptr_t socket, int32_t* available); @@ -430,6 +423,8 @@ PALEXPORT char* SystemNative_GetPeerUserName(intptr_t socket); PALEXPORT void SystemNative_GetDomainSocketSizes(int32_t* pathOffset, int32_t* pathSize, int32_t* addressSize); +PALEXPORT int32_t SystemNative_GetMaximumAddressSize(void); + PALEXPORT int32_t SystemNative_SendFile(intptr_t out_fd, intptr_t in_fd, int64_t offset, int64_t count, int64_t* sent); PALEXPORT int32_t SystemNative_Disconnect(intptr_t socket); diff --git a/src/libraries/Native/Unix/System.Native/pal_process.c b/src/libraries/Native/Unix/System.Native/pal_process.c index 93d41880092b09..4b640ceef6fcfb 100644 --- a/src/libraries/Native/Unix/System.Native/pal_process.c +++ b/src/libraries/Native/Unix/System.Native/pal_process.c @@ -21,9 +21,8 @@ #if HAVE_CRT_EXTERNS_H #include #endif -#if HAVE_PIPE2 #include -#endif +#include #include #if HAVE_SCHED_SETAFFINITY || HAVE_SCHED_GETAFFINITY @@ -42,33 +41,13 @@ c_static_assert(PAL_LOG_WARNING == LOG_WARNING); c_static_assert(PAL_LOG_NOTICE == LOG_NOTICE); c_static_assert(PAL_LOG_INFO == LOG_INFO); c_static_assert(PAL_LOG_DEBUG == LOG_DEBUG); -c_static_assert(PAL_LOG_KERN == LOG_KERN); -c_static_assert(PAL_LOG_USER == LOG_USER); -c_static_assert(PAL_LOG_MAIL == LOG_MAIL); -c_static_assert(PAL_LOG_DAEMON == LOG_DAEMON); -c_static_assert(PAL_LOG_AUTH == LOG_AUTH); -c_static_assert(PAL_LOG_SYSLOG == LOG_SYSLOG); -c_static_assert(PAL_LOG_LPR == LOG_LPR); -c_static_assert(PAL_LOG_NEWS == LOG_NEWS); -c_static_assert(PAL_LOG_UUCP == LOG_UUCP); -c_static_assert(PAL_LOG_CRON == LOG_CRON); -c_static_assert(PAL_LOG_AUTHPRIV == LOG_AUTHPRIV); -c_static_assert(PAL_LOG_FTP == LOG_FTP); -c_static_assert(PAL_LOG_LOCAL0 == LOG_LOCAL0); -c_static_assert(PAL_LOG_LOCAL1 == LOG_LOCAL1); -c_static_assert(PAL_LOG_LOCAL2 == LOG_LOCAL2); -c_static_assert(PAL_LOG_LOCAL3 == LOG_LOCAL3); -c_static_assert(PAL_LOG_LOCAL4 == LOG_LOCAL4); -c_static_assert(PAL_LOG_LOCAL5 == LOG_LOCAL5); -c_static_assert(PAL_LOG_LOCAL6 == LOG_LOCAL6); -c_static_assert(PAL_LOG_LOCAL7 == LOG_LOCAL7); // Validate that out PriorityWhich values are correct for the platform c_static_assert(PAL_PRIO_PROCESS == (int)PRIO_PROCESS); c_static_assert(PAL_PRIO_PGRP == (int)PRIO_PGRP); c_static_assert(PAL_PRIO_USER == (int)PRIO_USER); -#if !HAVE_PIPE2 +#ifndef SOCK_CLOEXEC static pthread_mutex_t ProcessCreateLock = PTHREAD_MUTEX_INITIALIZER; #endif @@ -154,7 +133,7 @@ static int compare_groups(const void * a, const void * b) static int SetGroups(uint32_t* userGroups, int32_t userGroupsLength, uint32_t* processGroups) { -#if defined(__linux__) || defined(_WASM_) +#if defined(__linux__) || defined(TARGET_WASM) size_t platformGroupsLength = Int32ToSizeT(userGroupsLength); #else // BSD int platformGroupsLength = userGroupsLength; @@ -203,6 +182,31 @@ static int SetGroups(uint32_t* userGroups, int32_t userGroupsLength, uint32_t* p return rv; } +static int32_t SocketPair(int32_t sv[2]) +{ + int32_t result; + + int type = SOCK_STREAM; +#ifdef SOCK_CLOEXEC + type |= SOCK_CLOEXEC; +#endif + + while ((result = socketpair(AF_UNIX, type, 0, sv)) < 0 && errno == EINTR); + +#ifndef SOCK_CLOEXEC + if (result == 0) + { + while ((result = fcntl(sv[READ_END_OF_PIPE], F_SETFD, FD_CLOEXEC)) < 0 && errno == EINTR); + if (result == 0) + { + while ((result = fcntl(sv[WRITE_END_OF_PIPE], F_SETFD, FD_CLOEXEC)) < 0 && errno == EINTR); + } + } +#endif + + return result; +} + int32_t SystemNative_ForkAndExecProcess(const char* filename, char* const argv[], char* const envp[], @@ -221,7 +225,7 @@ int32_t SystemNative_ForkAndExecProcess(const char* filename, int32_t* stderrFd) { #if HAVE_FORK -#if !HAVE_PIPE2 +#ifndef SOCK_CLOEXEC bool haveProcessCreateLock = false; #endif bool success = true; @@ -277,11 +281,11 @@ int32_t SystemNative_ForkAndExecProcess(const char* filename, goto done; } -#if !HAVE_PIPE2 - // We do not have pipe2(); take the lock to emulate it race free. - // If another process were to be launched between the pipe creation and the fcntl call to set CLOEXEC on it, that - // file descriptor will be inherited into the other child process, eventually causing a deadlock either in the loop - // below that waits for that pipe to be closed or in StreamReader.ReadToEnd() in the calling code. +#ifndef SOCK_CLOEXEC + // We do not have SOCK_CLOEXEC; take the lock to emulate it race free. + // If another process were to be launched between the socket creation and the fcntl call to set CLOEXEC on it, that + // file descriptor would be inherited into the other child process, eventually causing a deadlock either in the loop + // below that waits for that socket to be closed or in StreamReader.ReadToEnd() in the calling code. if (pthread_mutex_lock(&ProcessCreateLock) != 0) { // This check is pretty much just checking for trashed memory. @@ -293,9 +297,9 @@ int32_t SystemNative_ForkAndExecProcess(const char* filename, // Open pipes for any requests to redirect stdin/stdout/stderr and set the // close-on-exec flag to the pipe file descriptors. - if ((redirectStdin && SystemNative_Pipe(stdinFds, PAL_O_CLOEXEC) != 0) || - (redirectStdout && SystemNative_Pipe(stdoutFds, PAL_O_CLOEXEC) != 0) || - (redirectStderr && SystemNative_Pipe(stderrFds, PAL_O_CLOEXEC) != 0)) + if ((redirectStdin && SocketPair(stdinFds) != 0) || + (redirectStdout && SocketPair(stdoutFds) != 0) || + (redirectStderr && SocketPair(stderrFds) != 0)) { success = false; goto done; @@ -446,7 +450,7 @@ int32_t SystemNative_ForkAndExecProcess(const char* filename, *stderrFd = stderrFds[READ_END_OF_PIPE]; done:; -#if !HAVE_PIPE2 +#ifndef SOCK_CLOEXEC if (haveProcessCreateLock) { pthread_mutex_unlock(&ProcessCreateLock); @@ -546,12 +550,21 @@ static int32_t ConvertRLimitResourcesPalToPlatform(RLimitResources value) return RLIMIT_CORE; case PAL_RLIMIT_AS: return RLIMIT_AS; +#ifdef RLIMIT_RSS case PAL_RLIMIT_RSS: return RLIMIT_RSS; +#endif +#ifdef RLIMIT_MEMLOCK case PAL_RLIMIT_MEMLOCK: return RLIMIT_MEMLOCK; +#elif defined(RLIMIT_VMEM) + case PAL_RLIMIT_MEMLOCK: + return RLIMIT_VMEM; +#endif +#ifdef RLIMIT_NPROC case PAL_RLIMIT_NPROC: return RLIMIT_NPROC; +#endif case PAL_RLIMIT_NOFILE: return RLIMIT_NOFILE; } @@ -656,7 +669,7 @@ int32_t SystemNative_GetSid(int32_t pid) void SystemNative_SysLog(SysLogPriority priority, const char* message, const char* arg1) { - syslog((int)priority, message, arg1); + syslog((int)(LOG_USER | priority), message, arg1); } int32_t SystemNative_WaitIdAnyExitedNoHangNoWait() diff --git a/src/libraries/Native/Unix/System.Native/pal_process.h b/src/libraries/Native/Unix/System.Native/pal_process.h index d75f25bcb43199..7ad8007aa70294 100644 --- a/src/libraries/Native/Unix/System.Native/pal_process.h +++ b/src/libraries/Native/Unix/System.Native/pal_process.h @@ -95,28 +95,6 @@ typedef enum PAL_LOG_NOTICE = 5, /* normal but significant condition */ PAL_LOG_INFO = 6, /* informational */ PAL_LOG_DEBUG = 7, /* debug-level messages */ - // Facilities - PAL_LOG_KERN = (0 << 3), /* kernel messages */ - PAL_LOG_USER = (1 << 3), /* random user-level messages */ - PAL_LOG_MAIL = (2 << 3), /* mail system */ - PAL_LOG_DAEMON = (3 << 3), /* system daemons */ - PAL_LOG_AUTH = (4 << 3), /* authorization messages */ - PAL_LOG_SYSLOG = (5 << 3), /* messages generated internally by syslogd */ - PAL_LOG_LPR = (6 << 3), /* line printer subsystem */ - PAL_LOG_NEWS = (7 << 3), /* network news subsystem */ - PAL_LOG_UUCP = (8 << 3), /* UUCP subsystem */ - PAL_LOG_CRON = (9 << 3), /* clock daemon */ - PAL_LOG_AUTHPRIV = (10 << 3), /* authorization messages (private) */ - PAL_LOG_FTP = (11 << 3), /* ftp daemon */ - // Between FTP and Local is reserved for system use - PAL_LOG_LOCAL0 = (16 << 3), /* reserved for local use */ - PAL_LOG_LOCAL1 = (17 << 3), /* reserved for local use */ - PAL_LOG_LOCAL2 = (18 << 3), /* reserved for local use */ - PAL_LOG_LOCAL3 = (19 << 3), /* reserved for local use */ - PAL_LOG_LOCAL4 = (20 << 3), /* reserved for local use */ - PAL_LOG_LOCAL5 = (21 << 3), /* reserved for local use */ - PAL_LOG_LOCAL6 = (22 << 3), /* reserved for local use */ - PAL_LOG_LOCAL7 = (23 << 3), /* reserved for local use */ } SysLogPriority; /** diff --git a/src/libraries/Native/Unix/System.Native/pal_sysctl.c b/src/libraries/Native/Unix/System.Native/pal_sysctl.c index 0adf8ac57d33a4..0d3b7f1e9a16ff 100644 --- a/src/libraries/Native/Unix/System.Native/pal_sysctl.c +++ b/src/libraries/Native/Unix/System.Native/pal_sysctl.c @@ -24,7 +24,7 @@ int32_t SystemNative_Sysctl(int* name, unsigned int namelen, void* value, size_t void* newp = NULL; size_t newlen = 0; -#if defined(__linux__) || defined(_WASM_) +#if defined(__linux__) || defined(TARGET_WASM) return sysctl(name, (int)(namelen), value, len, newp, newlen); #else return sysctl(name, namelen, value, len, newp, newlen); diff --git a/src/libraries/Native/Unix/System.Native/pal_uid.c b/src/libraries/Native/Unix/System.Native/pal_uid.c index 166465bccd4435..41053d326dccef 100644 --- a/src/libraries/Native/Unix/System.Native/pal_uid.c +++ b/src/libraries/Native/Unix/System.Native/pal_uid.c @@ -112,6 +112,73 @@ uint32_t SystemNative_GetUid() static pthread_mutex_t s_groupLock = PTHREAD_MUTEX_INITIALIZER; #endif +#if !HAVE_GETGROUPLIST +int getgrouplist(const char *uname, gid_t agroup, gid_t *groups, int *groupCount) +{ + int ngroups = 1; + int maxgroups = *groupCount; + + if (groups) + { + groups[ngroups] = agroup; + } + if (maxgroups > 1) + { + if (groups) + groups[ngroups++] = agroup; + else + ngroups++; + } + + setgrent(); + + int i; + int result = 0; + const struct group *group; + + while ((group = getgrent()) != NULL) + { + if (groups) + { + bool found = false; + for (i = 0; i < ngroups; i++) + { + if (group->gr_gid == groups[i]) + { + found = true; + break; + } + } + if (found) + break; + } + + for (i = 0; group->gr_mem[i]; i++) + { + if (!strcmp(group->gr_mem[i], uname)) + { + if (ngroups >= maxgroups) + { + result = -1; + break; + } + + if (groups) + groups[ngroups++] = group->gr_gid; + else + ngroups++; + + break; + } + } + } + + endgrent(); + *groupCount = ngroups; + return result; +} +#endif + int32_t SystemNative_GetGroupList(const char* name, uint32_t group, uint32_t* groups, int32_t* ngroups) { assert(name != NULL); diff --git a/src/libraries/Native/Unix/System.Net.Security.Native/pal_gssapi.c b/src/libraries/Native/Unix/System.Net.Security.Native/pal_gssapi.c index 0fbd518fa8bc0b..03eef6231a9302 100644 --- a/src/libraries/Native/Unix/System.Net.Security.Native/pal_gssapi.c +++ b/src/libraries/Native/Unix/System.Net.Security.Native/pal_gssapi.c @@ -417,7 +417,6 @@ uint32_t NetSecurityNative_Wrap(uint32_t* minorStatus, GssCtxId* contextHandle, int32_t isEncrypt, uint8_t* inputBytes, - int32_t offset, int32_t count, PAL_GssBuffer* outBuffer) { @@ -425,14 +424,13 @@ uint32_t NetSecurityNative_Wrap(uint32_t* minorStatus, assert(contextHandle != NULL); assert(isEncrypt == 1 || isEncrypt == 0); assert(inputBytes != NULL); - assert(offset >= 0); assert(count >= 0); assert(outBuffer != NULL); // count refers to the length of the input message. That is, number of bytes of inputBytes - // starting at offset that need to be wrapped. + // that need to be wrapped. int confState; - GssBuffer inputMessageBuffer = {.length = (size_t)count, .value = inputBytes + offset}; + GssBuffer inputMessageBuffer = {.length = (size_t)count, .value = inputBytes}; GssBuffer gssBuffer; uint32_t majorStatus = gss_wrap(minorStatus, contextHandle, isEncrypt, GSS_C_QOP_DEFAULT, &inputMessageBuffer, &confState, &gssBuffer); diff --git a/src/libraries/Native/Unix/System.Net.Security.Native/pal_gssapi.h b/src/libraries/Native/Unix/System.Net.Security.Native/pal_gssapi.h index 11e232d01501d9..489b66b09290a4 100644 --- a/src/libraries/Native/Unix/System.Net.Security.Native/pal_gssapi.h +++ b/src/libraries/Native/Unix/System.Net.Security.Native/pal_gssapi.h @@ -159,7 +159,6 @@ PALEXPORT uint32_t NetSecurityNative_Wrap(uint32_t* minorStatus, GssCtxId* contextHandle, int32_t isEncrypt, uint8_t* inputBytes, - int32_t offset, int32_t count, PAL_GssBuffer* outBuffer); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509chain.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509chain.c index fa3055efb3d224..7daa486ea7a5a8 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509chain.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509chain.c @@ -166,20 +166,25 @@ static void MergeStatusCodes(CFTypeRef key, CFTypeRef value, void* context) *pStatus |= PAL_X509ChainNotValidForUsage; else if (CFEqual(keyString, CFSTR("AnchorTrusted"))) *pStatus |= PAL_X509ChainUntrustedRoot; - else if (CFEqual(keyString, CFSTR("BasicConstraints"))) + else if (CFEqual(keyString, CFSTR("BasicConstraints")) || CFEqual(keyString, CFSTR("BasicConstraintsCA")) || + CFEqual(keyString, CFSTR("BasicConstraintsPathLen"))) *pStatus |= PAL_X509ChainInvalidBasicConstraints; - else if (CFEqual(keyString, CFSTR("UsageConstraints"))) + else if (CFEqual(keyString, CFSTR("UsageConstraints")) || CFEqual(keyString, CFSTR("BlackListedLeaf")) || + CFEqual(keyString, CFSTR("BlackListedKey"))) *pStatus |= PAL_X509ChainExplicitDistrust; else if (CFEqual(keyString, CFSTR("RevocationResponseRequired"))) *pStatus |= PAL_X509ChainRevocationStatusUnknown; else if (CFEqual(keyString, CFSTR("MissingIntermediate"))) *pStatus |= PAL_X509ChainPartialChain; + else if (CFEqual(keyString, CFSTR("CriticalExtensions"))) + *pStatus |= PAL_X509ChainHasNotSupportedCriticalExtension; else if (CFEqual(keyString, CFSTR("UnparseableExtension"))) { // 10.15 introduced new status code value which is not reported by Windows. Ignoring for now. } else if (CFEqual(keyString, CFSTR("WeakLeaf")) || CFEqual(keyString, CFSTR("WeakIntermediates")) || - CFEqual(keyString, CFSTR("WeakRoot")) || CFEqual(keyString, CFSTR("WeakKeySize"))) + CFEqual(keyString, CFSTR("WeakRoot")) || CFEqual(keyString, CFSTR("WeakKeySize")) || + CFEqual(keyString, CFSTR("WeakSignature"))) { // Because we won't report this out of a chain built by .NET on Windows, // don't report it here. diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt b/src/libraries/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt index 7be3d61aa3bc72..42f845d494d258 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt @@ -12,9 +12,29 @@ if(CMAKE_STATIC_LIB_LINK) set(CMAKE_FIND_LIBRARY_SUFFIXES .a) endif(CMAKE_STATIC_LIB_LINK) -find_package(OpenSSL) +if(CLR_CMAKE_TARGET_ANDROID AND NOT CROSS_ROOTFS) + # TEMP: consume OpenSSL dependencies from external sources via env. variables + set(OPENSSL_FOUND 1) + set(OPENSSL_INCLUDE_DIR $ENV{ANDROID_OPENSSL_AAR}/prefab/modules/ssl/include) + if(CLR_CMAKE_TARGET_ARCH_ARM64) + set(OPENSSL_CRYPTO_LIBRARY $ENV{ANDROID_OPENSSL_AAR}/prefab/modules/crypto/libs/android.arm64-v8a/libcrypto.so) + set(OPENSSL_SSL_LIBRARY $ENV{ANDROID_OPENSSL_AAR}/prefab/modules/ssl/libs/android.arm64-v8a/libssl.so) + elseif(CLR_CMAKE_TARGET_ARCH_ARM) + set(OPENSSL_CRYPTO_LIBRARY $ENV{ANDROID_OPENSSL_AAR}/prefab/modules/crypto/libs/android.armeabi-v7a/libcrypto.so) + set(OPENSSL_SSL_LIBRARY $ENV{ANDROID_OPENSSL_AAR}/prefab/modules/ssl/libs/android.armeabi-v7a/libssl.so) + elseif(CLR_CMAKE_TARGET_ARCH_I386) + set(OPENSSL_CRYPTO_LIBRARY $ENV{ANDROID_OPENSSL_AAR}/prefab/modules/crypto/libs/android.x86/libcrypto.so) + set(OPENSSL_SSL_LIBRARY $ENV{ANDROID_OPENSSL_AAR}/prefab/modules/ssl/libs/android.x86/libssl.so) + else() + set(OPENSSL_CRYPTO_LIBRARY $ENV{ANDROID_OPENSSL_AAR}/prefab/modules/crypto/libs/android.x86_64/libcrypto.so) + set(OPENSSL_SSL_LIBRARY $ENV{ANDROID_OPENSSL_AAR}/prefab/modules/ssl/libs/android.x86_64/libssl.so) + endif() +else() + find_package(OpenSSL) +endif() + if(NOT OPENSSL_FOUND) - message(FATAL_ERROR "!!! Cannot find libssl and System.Security.Cryptography.Native cannot build without it. Try installing libssl-dev (or the appropriate package for your platform) !!!") + message(FATAL_ERROR "!!! Cannot find libssl and System.Security.Cryptography.Native cannot build without it. Try installing libssl-dev (on Linux, but this may vary by distro) or openssl (on macOS) !!!. See the requirements document for your specific operating system: https://github.com/dotnet/runtime/tree/master/docs/workflow/requirements.") endif(NOT OPENSSL_FOUND) include_directories(${OPENSSL_INCLUDE_DIR}) diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/openssl.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/openssl.c index 1a9ea048397563..21820f8f443a1b 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/openssl.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/openssl.c @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#include "pal_err.h" #include "pal_types.h" #include "pal_utilities.h" #include "pal_safecrt.h" @@ -1263,6 +1264,23 @@ static int32_t EnsureOpenSsl10Initialized() #define OPENSSL_INIT_NO_ATEXIT 0x00080000L #endif +pthread_mutex_t g_err_mutex = PTHREAD_MUTEX_INITIALIZER; +int volatile g_err_unloaded = 0; + +static void HandleShutdown() +{ + // Generally, a mutex to set a boolean is overkill, but this lock + // ensures that there are no callers already inside the string table + // when the unload (possibly) executes. + int result = pthread_mutex_lock(&g_err_mutex); + assert(!result && "Acquiring the error string table mutex failed."); + + g_err_unloaded = 1; + + result = pthread_mutex_unlock(&g_err_mutex); + assert(!result && "Releasing the error string table mutex failed."); +} + static int32_t EnsureOpenSsl11Initialized() { // In OpenSSL 1.0 we call OPENSSL_add_all_algorithms_conf() and ERR_load_crypto_strings(), @@ -1279,6 +1297,10 @@ static int32_t EnsureOpenSsl11Initialized() OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); + // As a fallback for when the NO_ATEXIT isn't respected, register a later + // atexit handler, so we will indicate that we're in the shutdown state + // and stop asking problematic questions from other threads. + atexit(HandleShutdown); return 0; } diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.c index b33aa128280a49..47ae111bdc25db 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.c @@ -97,6 +97,23 @@ static bool OpenLibrary() DlOpen(MAKELIB("10")); } + // FreeBSD uses a different suffix numbering convention. + // Current supported FreeBSD releases should use the order .11 -> .111 -> .8 + if (libssl == NULL) + { + DlOpen(MAKELIB("11")); + } + + if (libssl == NULL) + { + DlOpen(MAKELIB("111")); + } + + if (libssl == NULL) + { + DlOpen(MAKELIB("8")); + } + return libssl != NULL; } diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_err.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_err.c index 252e7be59ce299..e38aaf71f7aecc 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_err.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_err.c @@ -34,10 +34,48 @@ uint64_t CryptoNative_ErrPeekLastError() const char* CryptoNative_ErrReasonErrorString(uint64_t error) { - return ERR_reason_error_string((unsigned long)error); + const char* errStr = NULL; + +#ifdef NEED_OPENSSL_1_1 + int result = pthread_mutex_lock(&g_err_mutex); + assert(!result && "Acquiring the error string table mutex failed."); + + if (!g_err_unloaded) + { +#endif + errStr = ERR_reason_error_string((unsigned long)error); +#ifdef NEED_OPENSSL_1_1 + } + + result = pthread_mutex_unlock(&g_err_mutex); + assert(!result && "Releasing the error string table mutex failed."); +#endif + + return errStr; } void CryptoNative_ErrErrorStringN(uint64_t e, char* buf, int32_t len) { - ERR_error_string_n((unsigned long)e, buf, Int32ToSizeT(len)); +#ifdef NEED_OPENSSL_1_1 + int result = pthread_mutex_lock(&g_err_mutex); + assert(!result && "Acquiring the error string table mutex failed."); + + if (!g_err_unloaded) + { +#endif + ERR_error_string_n((unsigned long)e, buf, Int32ToSizeT(len)); +#ifdef NEED_OPENSSL_1_1 + } + else + { + // If there's no string table, just make it be the empty string. + if (buf != NULL && len > 0) + { + buf[0] = 0; + } + } + + result = pthread_mutex_unlock(&g_err_mutex); + assert(!result && "Releasing the error string table mutex failed."); +#endif } diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_err.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_err.h index 3610c263d0af17..1c7470251e4113 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_err.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_err.h @@ -6,6 +6,13 @@ #include #include "opensslshim.h" +#include + +#ifdef NEED_OPENSSL_1_1 +extern pthread_mutex_t g_err_mutex; +extern int volatile g_err_unloaded; +#endif + /* Shims the ERR_clear_error method. */ diff --git a/src/libraries/Native/Unix/configure.cmake b/src/libraries/Native/Unix/configure.cmake index c043cedebb0319..4dc8b93c36de88 100644 --- a/src/libraries/Native/Unix/configure.cmake +++ b/src/libraries/Native/Unix/configure.cmake @@ -7,11 +7,10 @@ include(CheckStructHasMember) include(CheckSymbolExists) include(CheckTypeSize) - if (CLR_CMAKE_TARGET_ANDROID) set(PAL_UNIX_NAME \"ANDROID\") -elseif (CLR_CMAKE_TARGET_ARCH_WASM) - set(PAL_UNIX_NAME \"WEBASSEMBLY\") +elseif (CLR_CMAKE_TARGET_BROWSER) + set(PAL_UNIX_NAME \"BROWSER\") elseif (CLR_CMAKE_TARGET_LINUX) set(PAL_UNIX_NAME \"LINUX\") elseif (CLR_CMAKE_TARGET_OSX) @@ -32,11 +31,11 @@ elseif (CLR_CMAKE_TARGET_NETBSD) set(PAL_UNIX_NAME \"NETBSD\") elseif (CLR_CMAKE_TARGET_SUNOS) set(PAL_UNIX_NAME \"SUNOS\") - set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} /opt/local/include) - set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /opt/local/lib) - include_directories(SYSTEM /opt/local/include) + # requires /opt/tools when building in Global Zone (GZ) + include_directories(SYSTEM /opt/local/include /opt/tools/include) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector") else () - message(FATAL_ERROR "Unknown platform. Cannot define PAL_UNIX_NAME, used by RuntimeInformation.") + message(FATAL_ERROR "Unknown platform. Cannot define PAL_UNIX_NAME, used by RuntimeInformation.") endif () # We compile with -Werror, so we need to make sure these code fragments compile without warnings. @@ -232,6 +231,16 @@ check_symbol_exists( "termios.h" HAVE_TCSANOW) +check_symbol_exists( + cfsetspeed + termios.h + HAVE_CFSETSPEED) + +check_symbol_exists( + cfmakeraw + termios.h + HAVE_CFMAKERAW) + check_struct_has_member( "struct utsname" domainname @@ -303,8 +312,7 @@ set(CMAKE_EXTRA_INCLUDE_FILES ${STATFS_INCLUDES}) check_symbol_exists( "statfs" ${STATFS_INCLUDES} - HAVE_STATFS -) + HAVE_STATFS) check_type_size( "struct statfs" @@ -410,6 +418,10 @@ check_include_files( "sys/poll.h" HAVE_SYS_POLL_H) +check_include_files( + "sys/proc_info.h" + HAVE_SYS_PROCINFO_H) + check_symbol_exists( epoll_create1 sys/epoll.h @@ -578,8 +590,7 @@ check_c_source_compiles( return 0; } " - BIND_ADDRLEN_UNSIGNED -) + BIND_ADDRLEN_UNSIGNED) check_c_source_compiles( " @@ -594,8 +605,7 @@ check_c_source_compiles( return 0; } " - IPV6MR_INTERFACE_UNSIGNED -) + IPV6MR_INTERFACE_UNSIGNED) check_include_files( "sys/inotify.h" @@ -630,6 +640,13 @@ check_prototype_definition( "sys/types.h;sys/event.h" KEVENT_REQUIRES_INT_PARAMS) +check_prototype_definition( + statfs + "int statfs(const char *path, struct statfs *buf)" + 0 + ${STATFS_INCLUDES} + HAVE_NON_LEGACY_STATFS) + check_c_source_compiles( " #include @@ -671,8 +688,7 @@ check_c_source_compiles( #include int main(void) { return 0; } " - HAVE_NETINET_TCP_VAR_H -) + HAVE_NETINET_TCP_VAR_H) check_c_source_compiles( " @@ -686,8 +702,7 @@ check_c_source_compiles( #include int main(void) { return 0; } " - HAVE_NETINET_UDP_VAR_H -) + HAVE_NETINET_UDP_VAR_H) check_c_source_compiles( " @@ -699,8 +714,7 @@ check_c_source_compiles( #include int main(void) { return 0; } " - HAVE_NETINET_IP_VAR_H -) + HAVE_NETINET_IP_VAR_H) check_c_source_compiles( " @@ -713,8 +727,7 @@ check_c_source_compiles( #include int main(void) { return 0; } " - HAVE_NETINET_ICMP_VAR_H -) + HAVE_NETINET_ICMP_VAR_H) check_include_files( sys/cdefs.h @@ -734,16 +747,19 @@ check_c_source_compiles( #include int main(void) { int x = TCP_ESTABLISHED; return x; } " - HAVE_TCP_H_TCPSTATE_ENUM -) + HAVE_TCP_H_TCPSTATE_ENUM) set(CMAKE_REQUIRED_DEFINITIONS) check_symbol_exists( TCPS_ESTABLISHED "netinet/tcp_fsm.h" - HAVE_TCP_FSM_H -) + HAVE_TCP_FSM_H) + +check_symbol_exists( + getgrouplist + "unistd.h;grp.h" + HAVE_GETGROUPLIST) if(CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS) set(HAVE_IOS_NET_ROUTE_H 1) @@ -773,6 +789,26 @@ check_include_files( "sys/types.h;sys/sysctl.h" HAVE_SYS_SYSCTL_H) +check_include_files( + "sys/ioctl.h" + HAVE_SYS_IOCTL_H) + +check_include_files( + "sys/filio.h" + HAVE_SYS_FILIO_H) + +check_include_files( + "sys/types.h;netpacket/packet.h" + HAVE_NETPACKET_PACKET_H) + +check_include_files( + "net/if_arp.h" + HAVE_NET_IF_ARP_H) + +check_include_files( + "sys/mntent.h" + HAVE_SYS_MNTENT_H) + check_include_files( "stdint.h;net/if_media.h" HAVE_NET_IFMEDIA_H) @@ -816,8 +852,7 @@ check_c_source_compiles( return 0; } " - HAVE_GETDOMAINNAME_SIZET -) + HAVE_GETDOMAINNAME_SIZET) set (CMAKE_REQUIRED_FLAGS ${PREVIOUS_CMAKE_REQUIRED_FLAGS}) set (PREVIOUS_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) @@ -844,7 +879,7 @@ set (CMAKE_REQUIRED_LIBRARIES ${PREVIOUS_CMAKE_REQUIRED_LIBRARIES}) set (HAVE_INOTIFY 0) if (HAVE_INOTIFY_INIT AND HAVE_INOTIFY_ADD_WATCH AND HAVE_INOTIFY_RM_WATCH) set (HAVE_INOTIFY 1) -elseif (CLR_CMAKE_TARGET_LINUX AND NOT CLR_CMAKE_TARGET_ARCH_WASM) +elseif (CLR_CMAKE_TARGET_LINUX AND NOT CLR_CMAKE_TARGET_BROWSER) message(FATAL_ERROR "Cannot find inotify functions on a Linux platform.") endif() diff --git a/src/libraries/Native/Windows/probe-win.ps1 b/src/libraries/Native/Windows/probe-win.ps1 index 353db37bfc63b8..8641741c6c79ee 100644 --- a/src/libraries/Native/Windows/probe-win.ps1 +++ b/src/libraries/Native/Windows/probe-win.ps1 @@ -34,7 +34,7 @@ function GetCMakeInfo($regKey) function LocateCMake { - $errorMsg = "CMake is a pre-requisite to build this repository but it was not found on the path. Please install CMake from http://www.cmake.org/download/ and ensure it is on your path." + $errorMsg = "CMake is a pre-requisite to build this repository but it was not found on the path. Please install CMake from https://cmake.org/download/ and ensure it is on your path." $inPathPath = (get-command cmake.exe -ErrorAction SilentlyContinue) if ($inPathPath -ne $null) { # Resolve the first version of CMake if multiple commands are found diff --git a/src/libraries/Native/build-native.cmd b/src/libraries/Native/build-native.cmd index f59b71c0819bbe..87f78148dfaa38 100644 --- a/src/libraries/Native/build-native.cmd +++ b/src/libraries/Native/build-native.cmd @@ -32,7 +32,7 @@ if /i [%1] == [wasm] ( set __BuildArch=wasm&&set __VCBuildArch=x86_amd64& if /i [%1] == [outconfig] ( set __outConfig=%2&&shift&&shift&goto Arg_Loop) -if /i [%1] == [WebAssembly] ( set __TargetOS=WebAssembly&&shift&goto Arg_Loop) +if /i [%1] == [Browser] ( set __TargetOS=Browser&&shift&goto Arg_Loop) if /i [%1] == [rebuild] ( set __BuildTarget=rebuild&&shift&goto Arg_Loop) diff --git a/src/libraries/Native/build-native.proj b/src/libraries/Native/build-native.proj index ca3aa90476c15f..b0551571adf724 100644 --- a/src/libraries/Native/build-native.proj +++ b/src/libraries/Native/build-native.proj @@ -39,7 +39,7 @@ + Condition="'$(TargetOS)' == 'Windows_NT' and !$(TargetFramework.StartsWith('net4'))"> diff --git a/src/libraries/Native/build-native.sh b/src/libraries/Native/build-native.sh index 1e8faa998b7cd6..fb8b183403eb50 100755 --- a/src/libraries/Native/build-native.sh +++ b/src/libraries/Native/build-native.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -usage_list=("-outconfig: Configuration, typically a quadruplet such as 'netcoreapp5.0-Linux-Release-x64', used to name output directory.") +usage_list=("-outconfig: Configuration, typically a quadruplet such as 'net5.0-Linux-Release-x64', used to name output directory.") usage_list+=("-staticLibLink: Optional argument to statically link any native library.") __scriptpath="$(cd "$(dirname "$0")"; pwd -P)" @@ -79,13 +79,13 @@ if [[ "$__TargetOS" == OSX ]]; then # set default OSX deployment target __CMakeArgs="-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 $__CMakeArgs" elif [[ "$__TargetOS" == Android && -z "$ROOTFS_DIR" ]]; then - if [[ -z "$ANDROID_NDK_HOME" ]]; then - echo "Error: You need to set the ANDROID_NDK_HOME environment variable pointing to the Android NDK root." + if [[ -z "$ANDROID_NDK_ROOT" ]]; then + echo "Error: You need to set the ANDROID_NDK_ROOT environment variable pointing to the Android NDK root." exit 1 fi # keep ANDROID_NATIVE_API_LEVEL in sync with src/mono/Directory.Build.props - __CMakeArgs="-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake -DANDROID_STL=none -DANDROID_NATIVE_API_LEVEL=21 $__CMakeArgs" + __CMakeArgs="-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake -DANDROID_STL=none -DANDROID_NATIVE_API_LEVEL=21 $__CMakeArgs" # workaround init-compiler.sh trying to detect clang, it's handled in android.toolchain.cmake already export CLR_CC=$(which false) @@ -109,6 +109,10 @@ elif [[ "$__TargetOS" == iOS ]]; then # set default iOS simulator deployment target (8.0 is the minimum supported by Xcode 11) # keep in sync with src/mono/Directory.Build.props __CMakeArgs="-DCMAKE_OSX_SYSROOT=iphonesimulator -DCMAKE_OSX_DEPLOYMENT_TARGET=8.0 -DCMAKE_OSX_ARCHITECTURES=\"x86_64\" $__CMakeArgs" + elif [[ "$__BuildArch" == x86 ]]; then + # set default iOS simulator deployment target (8.0 is the minimum supported by Xcode 11) + # keep in sync with src/mono/Directory.Build.props + __CMakeArgs="-DCMAKE_OSX_SYSROOT=iphonesimulator -DCMAKE_OSX_DEPLOYMENT_TARGET=8.0 -DCMAKE_OSX_ARCHITECTURES=\"i386\" $__CMakeArgs" elif [[ "$__BuildArch" == arm64 ]]; then # set default iOS device deployment target (7.0 is the minimum supported by Xcode 11) # keep in sync with src/mono/Directory.Build.props diff --git a/src/libraries/Native/native-binplace.proj b/src/libraries/Native/native-binplace.proj index 2631ea732755c0..2cd59c4856f445 100644 --- a/src/libraries/Native/native-binplace.proj +++ b/src/libraries/Native/native-binplace.proj @@ -11,16 +11,28 @@ - - - - - - - - - - + + + + + + + + + + + wasm\runtimes\debug\ + + + wasm\runtimes\release\ + + + + + + + + diff --git a/src/libraries/OSGroups.json b/src/libraries/OSGroups.json index 062533affcfd73..6b26bd7e2aecf6 100644 --- a/src/libraries/OSGroups.json +++ b/src/libraries/OSGroups.json @@ -2,7 +2,7 @@ "runtimes": { "Unix" : { }, - "WebAssembly" : { + "Browser" : { "#import": [ "Linux" ] diff --git a/src/libraries/System.CodeDom/ref/System.CodeDom.csproj b/src/libraries/System.CodeDom/ref/System.CodeDom.csproj index 33a978c2358776..189b1e64476170 100644 --- a/src/libraries/System.CodeDom/ref/System.CodeDom.csproj +++ b/src/libraries/System.CodeDom/ref/System.CodeDom.csproj @@ -1,17 +1,20 @@ - true netstandard2.0;net461;$(NetFrameworkCurrent) true + + + true + - + - + \ No newline at end of file diff --git a/src/libraries/System.CodeDom/src/System.CodeDom.csproj b/src/libraries/System.CodeDom/src/System.CodeDom.csproj index 441673ef11f5b0..7217ca52bc65d7 100644 --- a/src/libraries/System.CodeDom/src/System.CodeDom.csproj +++ b/src/libraries/System.CodeDom/src/System.CodeDom.csproj @@ -1,12 +1,15 @@ true - true $(DefineConstants);CODEDOM netstandard2.0;net461;$(NetFrameworkCurrent) true - + + + true + + @@ -126,7 +129,7 @@ - + diff --git a/src/libraries/System.CodeDom/tests/System.CodeDom.Tests.csproj b/src/libraries/System.CodeDom/tests/System.CodeDom.Tests.csproj index e30f1847fded38..9e92688da3e9db 100644 --- a/src/libraries/System.CodeDom/tests/System.CodeDom.Tests.csproj +++ b/src/libraries/System.CodeDom/tests/System.CodeDom.Tests.csproj @@ -97,23 +97,17 @@ - - Common\System\Collections\IList.NonGeneric.Tests.cs - - - Common\System\Collections\ICollection.NonGeneric.Tests.cs - - - Common\System\Collections\IEnumerable.NonGeneric.Tests.cs - - - Common\System\Collections\TestBase.NonGeneric.cs - - - Common\System\IO\TempFile.cs - - - Common\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs - + + + + + + \ No newline at end of file diff --git a/src/libraries/System.Collections.Concurrent/System.Collections.Concurrent.sln b/src/libraries/System.Collections.Concurrent/System.Collections.Concurrent.sln index 81e92b55abb62c..0719882156cfa6 100644 --- a/src/libraries/System.Collections.Concurrent/System.Collections.Concurrent.sln +++ b/src/libraries/System.Collections.Concurrent/System.Collections.Concurrent.sln @@ -20,7 +20,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{91BAC0C0-2F64-4346-87AC-94DAB6911F5B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{91BAC0C0-2F64-4346-87AC-94DAB6911F5B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime", "..\System.Runtime\src\System.Runtime.csproj", "{FF830077-7D7A-45FC-80A1-4F0A9D546CC5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Diagnostics.Tracing", "..\System.Diagnostics.Tracing\src\System.Diagnostics.Tracing.csproj", "{541D25E4-A6F4-4189-AD42-14D31DEF4EB7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Numerics.Vectors", "..\System.Numerics.Vectors\src\System.Numerics.Vectors.csproj", "{961766E3-BB70-48D4-8F25-4F0356E7FA2E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.Extensions", "..\System.Runtime.Extensions\src\System.Runtime.Extensions.csproj", "{0CE46A80-39F9-4D76-ACF6-41F59BE739AA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Threading", "..\System.Threading\src\System.Threading.csproj", "{F8C58AD9-D9EA-4BBC-AB6E-E908007F607E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -44,6 +54,26 @@ Global {91BAC0C0-2F64-4346-87AC-94DAB6911F5B}.Debug|Any CPU.Build.0 = Debug|Any CPU {91BAC0C0-2F64-4346-87AC-94DAB6911F5B}.Release|Any CPU.ActiveCfg = Release|Any CPU {91BAC0C0-2F64-4346-87AC-94DAB6911F5B}.Release|Any CPU.Build.0 = Release|Any CPU + {FF830077-7D7A-45FC-80A1-4F0A9D546CC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF830077-7D7A-45FC-80A1-4F0A9D546CC5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF830077-7D7A-45FC-80A1-4F0A9D546CC5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF830077-7D7A-45FC-80A1-4F0A9D546CC5}.Release|Any CPU.Build.0 = Release|Any CPU + {541D25E4-A6F4-4189-AD42-14D31DEF4EB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {541D25E4-A6F4-4189-AD42-14D31DEF4EB7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {541D25E4-A6F4-4189-AD42-14D31DEF4EB7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {541D25E4-A6F4-4189-AD42-14D31DEF4EB7}.Release|Any CPU.Build.0 = Release|Any CPU + {961766E3-BB70-48D4-8F25-4F0356E7FA2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {961766E3-BB70-48D4-8F25-4F0356E7FA2E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {961766E3-BB70-48D4-8F25-4F0356E7FA2E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {961766E3-BB70-48D4-8F25-4F0356E7FA2E}.Release|Any CPU.Build.0 = Release|Any CPU + {0CE46A80-39F9-4D76-ACF6-41F59BE739AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0CE46A80-39F9-4D76-ACF6-41F59BE739AA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0CE46A80-39F9-4D76-ACF6-41F59BE739AA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0CE46A80-39F9-4D76-ACF6-41F59BE739AA}.Release|Any CPU.Build.0 = Release|Any CPU + {F8C58AD9-D9EA-4BBC-AB6E-E908007F607E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F8C58AD9-D9EA-4BBC-AB6E-E908007F607E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F8C58AD9-D9EA-4BBC-AB6E-E908007F607E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F8C58AD9-D9EA-4BBC-AB6E-E908007F607E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -53,6 +83,11 @@ Global {EA610394-CBA3-4E5C-B3DB-AAEA7F640E89} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {772CB0A7-3D45-4D3A-B975-671A1937C761} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} {91BAC0C0-2F64-4346-87AC-94DAB6911F5B} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} + {FF830077-7D7A-45FC-80A1-4F0A9D546CC5} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {541D25E4-A6F4-4189-AD42-14D31DEF4EB7} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {961766E3-BB70-48D4-8F25-4F0356E7FA2E} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {0CE46A80-39F9-4D76-ACF6-41F59BE739AA} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {F8C58AD9-D9EA-4BBC-AB6E-E908007F607E} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {87704D28-6290-402F-9B93-DE67CE2E3D06} diff --git a/src/libraries/System.Collections.Concurrent/ref/System.Collections.Concurrent.cs b/src/libraries/System.Collections.Concurrent/ref/System.Collections.Concurrent.cs index 022d5ce0456e59..c19a7197d8fcef 100644 --- a/src/libraries/System.Collections.Concurrent/ref/System.Collections.Concurrent.cs +++ b/src/libraries/System.Collections.Concurrent/ref/System.Collections.Concurrent.cs @@ -113,7 +113,7 @@ public void Clear() { } void System.Collections.Generic.IDictionary.Add(TKey key, TValue value) { } bool System.Collections.Generic.IDictionary.Remove(TKey key) { throw null; } void System.Collections.ICollection.CopyTo(System.Array array, int index) { } - void System.Collections.IDictionary.Add(object key, object value) { } + void System.Collections.IDictionary.Add(object key, object? value) { } bool System.Collections.IDictionary.Contains(object key) { throw null; } System.Collections.IDictionaryEnumerator System.Collections.IDictionary.GetEnumerator() { throw null; } void System.Collections.IDictionary.Remove(object key) { } diff --git a/src/libraries/System.Collections.Concurrent/src/System.Collections.Concurrent.csproj b/src/libraries/System.Collections.Concurrent/src/System.Collections.Concurrent.csproj index 208ab764456eee..c049418e129ad0 100644 --- a/src/libraries/System.Collections.Concurrent/src/System.Collections.Concurrent.csproj +++ b/src/libraries/System.Collections.Concurrent/src/System.Collections.Concurrent.csproj @@ -15,9 +15,8 @@ - - System\Collections\Concurrent\IProducerConsumerCollectionDebugView.cs - + diff --git a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.cs b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.cs index 71d94c8dc72d00..1939dd9d68b298 100644 --- a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.cs +++ b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.cs @@ -755,7 +755,13 @@ private bool TryTakeWithNoTimeValidation([MaybeNullWhen(false)] out T item, int } } } + +#pragma warning disable CS8762 + // https://github.com/dotnet/runtime/issues/36132 + // Compiler can't automatically deduce that nullability constraints + // for 'item' are satisfied at this exit point. return waitForSemaphoreWasSuccessful; +#pragma warning restore CS8762 } diff --git a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.cs b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.cs index c37a08aa82f874..3088224b471869 100644 --- a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.cs +++ b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentBag.cs @@ -170,7 +170,7 @@ private WorkStealingQueue CreateWorkStealingQueueForCurrentThread() /// To receive the item retrieved from the bag /// Whether to remove or peek. /// True if succeeded, false otherwise. - private bool TrySteal(out T result, bool take) + private bool TrySteal([MaybeNullWhen(false)] out T result, bool take) { if (CDSCollectionETWBCLProvider.Log.IsEnabled()) { @@ -219,7 +219,12 @@ private bool TrySteal(out T result, bool take) (TryStealFromTo(localQueue._nextQueue, null, out result, take) || TryStealFromTo(_workStealingQueues, localQueue, out result, take)); if (gotItem) { +#pragma warning disable CS8762 + // https://github.com/dotnet/runtime/issues/36132 + // Compiler can't automatically deduce that nullability constraints + // for 'result' are satisfied at this exit point. return true; +#pragma warning restore CS8762 } if (Interlocked.Read(ref _emptyToNonEmptyListTransitionCount) == initialEmptyToNonEmptyCounts) @@ -248,7 +253,7 @@ private bool TryStealFromTo(WorkStealingQueue? startInclusive, WorkStealingQueue } } - result = default(T)!; + result = default(T); return false; } @@ -870,7 +875,7 @@ internal bool TryLocalPop([MaybeNullWhen(false)] out T result) int tail = _tailIndex; if (_headIndex - tail >= 0) { - result = default(T)!; + result = default(T); return false; } @@ -914,7 +919,7 @@ internal bool TryLocalPop([MaybeNullWhen(false)] out T result) { // We encountered a race condition and the element was stolen, restore the tail. _tailIndex = tail + 1; - result = default(T)!; + result = default(T); return false; } } @@ -958,7 +963,7 @@ internal bool TryLocalPeek([MaybeNullWhen(false)] out T result) } } - result = default(T)!; + result = default(T); return false; } @@ -1015,7 +1020,7 @@ internal bool TrySteal([MaybeNullWhen(false)] out T result, bool take) } // The queue was empty. - result = default(T)!; + result = default(T); return false; } diff --git a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentDictionary.cs b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentDictionary.cs index e8a10a5d788eb2..7667e21505e7c4 100644 --- a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentDictionary.cs +++ b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentDictionary.cs @@ -44,7 +44,7 @@ private sealed class Tables { internal readonly Node[] _buckets; // A singly-linked list for each bucket. internal readonly object[] _locks; // A set of locks, each guarding a section of the table. - internal volatile int[] _countPerLock; // The number of elements guarded by each lock. + internal readonly int[] _countPerLock; // The number of elements guarded by each lock. internal Tables(Node[] buckets, object[] locks, int[] countPerLock) { diff --git a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentStack.cs b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentStack.cs index 6d5ca3a6af7013..0d9ea6434ea7a0 100644 --- a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentStack.cs +++ b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentStack.cs @@ -692,7 +692,7 @@ private static void CopyRemovedItems(Node head, T[] collection, int startIndex, /// For , this operation will attempt to pope the object at /// the top of the . /// - bool IProducerConsumerCollection.TryTake(out T item) + bool IProducerConsumerCollection.TryTake([MaybeNullWhen(false)] out T item) { return TryPop(out item); } diff --git a/src/libraries/System.Collections.Concurrent/tests/BlockingCollectionTests.cs b/src/libraries/System.Collections.Concurrent/tests/BlockingCollectionTests.cs index 6f8a107ccb8c62..9a21bc6ef01e77 100644 --- a/src/libraries/System.Collections.Concurrent/tests/BlockingCollectionTests.cs +++ b/src/libraries/System.Collections.Concurrent/tests/BlockingCollectionTests.cs @@ -966,6 +966,22 @@ public static void Test21_CopyToExceptions() }); } + [Fact] + public static void Test_WithNullEntries() + { + BlockingCollection collection = new BlockingCollection() + { + "hello", + null, + "goodbye" + }; + + Assert.Equal("hello", collection.Take()); + Assert.Null(collection.Take()); + Assert.Equal("goodbye", collection.Take()); + Assert.False(collection.TryTake(out _)); + } + [Fact] public static void Test_LargeSize() { diff --git a/src/libraries/System.Collections.Concurrent/tests/System.Collections.Concurrent.Tests.csproj b/src/libraries/System.Collections.Concurrent/tests/System.Collections.Concurrent.Tests.csproj index 08891beb71dbc4..1ef1827987185f 100644 --- a/src/libraries/System.Collections.Concurrent/tests/System.Collections.Concurrent.Tests.csproj +++ b/src/libraries/System.Collections.Concurrent/tests/System.Collections.Concurrent.Tests.csproj @@ -5,64 +5,45 @@ $(NetCoreAppCurrent) - - System\Collections\Concurrent\IProducerConsumerCollectionDebugView.cs - + - - Common\System\Collections\CollectionAsserts.cs - - - Common\System\Collections\ICollection.NonGeneric.Tests.cs - - - Common\System\Collections\ICollection.Generic.Tests.cs - - - Common\System\Collections\IDictionary.NonGeneric.Tests.cs - - - Common\System\Collections\IDictionary.Generic.Tests.cs - - - Common\System\Collections\IEnumerable.NonGeneric.Tests.cs - - - Common\System\Collections\IEnumerable.Generic.Tests.cs - - - Common\System\Collections\IList.NonGeneric.Tests.cs - - - Common\System\Collections\IList.Generic.Tests.cs - - - Common\System\Collections\IGenericSharedAPI.Tests.cs - - - Common\System\Collections\ISet.Generic.Tests.cs - - - Common\System\Collections\TestBase.NonGeneric.Tests.cs - - - Common\System\Collections\TestBase.Generic.Tests.cs - - - Common\System\Collections\DebugView.Tests.cs - - - Common\System\Collections\TestingTypes.cs - - - Common\System\Diagnostics\Tracing\TestEventListener.cs - - - Common\System\EnumTypes.cs - - - Common\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs - + + + + + + + + + + + + + + + + + + @@ -80,16 +61,13 @@ - - Common\System\Diagnostics\DebuggerAttributes.cs - + - - Common\System\Collections\IEnumerable.NonGeneric.Serialization.Tests.cs - - - Common\System\Collections\IEnumerable.Generic.Serialization.Tests.cs - + + \ No newline at end of file diff --git a/src/libraries/System.Collections.Immutable/Directory.Build.props b/src/libraries/System.Collections.Immutable/Directory.Build.props index 465e1110d6b07f..5f6e490332e15a 100644 --- a/src/libraries/System.Collections.Immutable/Directory.Build.props +++ b/src/libraries/System.Collections.Immutable/Directory.Build.props @@ -4,4 +4,4 @@ Microsoft true - \ No newline at end of file + diff --git a/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs b/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs index 89819bb3a75c7a..25cdd45c800706 100644 --- a/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs +++ b/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.cs @@ -89,7 +89,7 @@ public static partial class ImmutableArray public static System.Collections.Immutable.ImmutableArray Create(T item1, T item2) { throw null; } public static System.Collections.Immutable.ImmutableArray Create(T item1, T item2, T item3) { throw null; } public static System.Collections.Immutable.ImmutableArray Create(T item1, T item2, T item3, T item4) { throw null; } - public static System.Collections.Immutable.ImmutableArray Create(params T[] items) { throw null; } + public static System.Collections.Immutable.ImmutableArray Create(params T[]? items) { throw null; } public static System.Collections.Immutable.ImmutableArray Create(T[] items, int start, int length) { throw null; } public static System.Collections.Immutable.ImmutableArray ToImmutableArray(this System.Collections.Generic.IEnumerable items) { throw null; } public static System.Collections.Immutable.ImmutableArray ToImmutableArray(this System.Collections.Immutable.ImmutableArray.Builder builder) { throw null; } @@ -702,7 +702,7 @@ public void Sort(int index, int count, System.Collections.Generic.IComparer? System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } void System.Collections.ICollection.CopyTo(System.Array array, int arrayIndex) { } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - int System.Collections.IList.Add(object value) { throw null; } + int System.Collections.IList.Add(object? value) { throw null; } void System.Collections.IList.Clear() { } bool System.Collections.IList.Contains(object? value) { throw null; } int System.Collections.IList.IndexOf(object? value) { throw null; } @@ -819,7 +819,7 @@ void System.Collections.Generic.IDictionary.Add(TKey key, TValue va bool System.Collections.Generic.IDictionary.Remove(TKey key) { throw null; } System.Collections.Generic.IEnumerator> System.Collections.Generic.IEnumerable>.GetEnumerator() { throw null; } void System.Collections.ICollection.CopyTo(System.Array array, int index) { } - void System.Collections.IDictionary.Add(object key, object value) { } + void System.Collections.IDictionary.Add(object key, object? value) { } void System.Collections.IDictionary.Clear() { } bool System.Collections.IDictionary.Contains(object key) { throw null; } System.Collections.IDictionaryEnumerator System.Collections.IDictionary.GetEnumerator() { throw null; } diff --git a/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.csproj b/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.csproj index b2875fd23dca7b..48e1f0bde560bd 100644 --- a/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.csproj +++ b/src/libraries/System.Collections.Immutable/ref/System.Collections.Immutable.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj b/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj index ed5c6b9cd674c8..a942bf3a506cda 100644 --- a/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj +++ b/src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj @@ -1,11 +1,13 @@ - System.Collections.Immutable - netstandard1.0;portable-net45+win8+wp8+wpa81 $(NetCoreAppCurrent);netstandard1.0;netstandard1.3;netstandard2.0 true enable + + + netstandard1.0;portable-net45+win8+wp8+wpa81 + @@ -83,14 +85,12 @@ - - Common\System\Runtime\Versioning\NonVersionableAttribute.cs - + - - System\Diagnostics\CodeAnalysis\ExcludeFromCodeCoverageAttribute.cs - + @@ -105,7 +105,7 @@ - + diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableDictionary.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableDictionary.cs index ef33b1c2663199..43b91fdc4a86d6 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableDictionary.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableDictionary.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -18,7 +17,6 @@ public interface IImmutableDictionary : IReadOnlyDictionary /// Gets an empty dictionary with equivalent ordering and key/value comparison rules. /// - [Pure] IImmutableDictionary Clear(); /// @@ -31,7 +29,6 @@ public interface IImmutableDictionary : IReadOnlyDictionary /// If the given key-value pair are already in the dictionary, the existing instance is returned. /// - [Pure] IImmutableDictionary Add(TKey key, TValue value); /// @@ -40,7 +37,6 @@ public interface IImmutableDictionary : IReadOnlyDictionaryThe pairs. /// The new dictionary containing the additional key-value pairs. /// Thrown when one of the given keys already exists in the dictionary but has a different value. - [Pure] IImmutableDictionary AddRange(IEnumerable> pairs); /// @@ -53,7 +49,6 @@ public interface IImmutableDictionary : IReadOnlyDictionary - [Pure] IImmutableDictionary SetItem(TKey key, TValue value); /// @@ -61,7 +56,6 @@ public interface IImmutableDictionary : IReadOnlyDictionary /// The key=value pairs to set on the dictionary. Any keys that conflict with existing keys will overwrite the previous values. /// An immutable dictionary. - [Pure] IImmutableDictionary SetItems(IEnumerable> items); /// @@ -69,7 +63,6 @@ public interface IImmutableDictionary : IReadOnlyDictionary /// The keys to remove. /// A new dictionary with those keys removed; or this instance if those keys are not in the dictionary. - [Pure] IImmutableDictionary RemoveRange(IEnumerable keys); /// @@ -77,7 +70,6 @@ public interface IImmutableDictionary : IReadOnlyDictionary /// The key to remove. /// A new dictionary with the matching entry removed; or this instance if the key is not in the dictionary. - [Pure] IImmutableDictionary Remove(TKey key); /// @@ -87,7 +79,6 @@ public interface IImmutableDictionary : IReadOnlyDictionary /// true if this dictionary contains the key-value pair; otherwise, false. /// - [Pure] bool Contains(KeyValuePair pair); /// @@ -102,7 +93,6 @@ public interface IImmutableDictionary : IReadOnlyDictionary - [Pure] bool TryGetKey(TKey equalKey, out TKey actualKey); } } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableList.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableList.cs index 05545062d45708..2ad1fcfef6f767 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableList.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableList.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -21,7 +20,6 @@ public interface IImmutableList : IReadOnlyList /// /// Gets an empty list that retains the same sort semantics that this instance has. /// - [Pure] IImmutableList Clear(); /// @@ -49,7 +47,6 @@ public interface IImmutableList : IReadOnlyList /// elements in the that starts at index and /// contains count number of elements, if found; otherwise, -1. /// - [Pure] int IndexOf(T item, int index, int count, IEqualityComparer? equalityComparer); /// @@ -73,7 +70,6 @@ public interface IImmutableList : IReadOnlyList /// in the that contains number of elements /// and ends at , if found; otherwise, -1. /// - [Pure] int LastIndexOf(T item, int index, int count, IEqualityComparer? equalityComparer); /// @@ -81,7 +77,6 @@ public interface IImmutableList : IReadOnlyList /// /// The value to add. /// A new list with the element added. - [Pure] IImmutableList Add(T value); /// @@ -89,7 +84,6 @@ public interface IImmutableList : IReadOnlyList /// /// The values to add. /// A new list with the elements added. - [Pure] IImmutableList AddRange(IEnumerable items); /// @@ -98,7 +92,6 @@ public interface IImmutableList : IReadOnlyList /// The index at which to insert the value. /// The element to insert. /// The new immutable list. - [Pure] IImmutableList Insert(int index, T element); /// @@ -107,7 +100,6 @@ public interface IImmutableList : IReadOnlyList /// The index at which to insert the value. /// The elements to insert. /// The new immutable list. - [Pure] IImmutableList InsertRange(int index, IEnumerable items); /// @@ -119,7 +111,6 @@ public interface IImmutableList : IReadOnlyList /// If null, is used. /// /// A new list with the element removed, or this list if the element is not in this list. - [Pure] IImmutableList Remove(T value, IEqualityComparer? equalityComparer); /// @@ -133,7 +124,6 @@ public interface IImmutableList : IReadOnlyList /// /// The new list. /// - [Pure] IImmutableList RemoveAll(Predicate match); /// @@ -147,7 +137,6 @@ public interface IImmutableList : IReadOnlyList /// /// A new list with the elements removed. /// - [Pure] IImmutableList RemoveRange(IEnumerable items, IEqualityComparer? equalityComparer); /// @@ -158,7 +147,6 @@ public interface IImmutableList : IReadOnlyList /// /// A new list with the elements removed. /// - [Pure] IImmutableList RemoveRange(int index, int count); /// @@ -166,7 +154,6 @@ public interface IImmutableList : IReadOnlyList /// /// The index. /// A new list with the elements removed. - [Pure] IImmutableList RemoveAt(int index); /// @@ -175,7 +162,6 @@ public interface IImmutableList : IReadOnlyList /// The position in the list of the element to replace. /// The element to replace the old element with. /// The new list -- even if the value being replaced is equal to the new value for that position. - [Pure] IImmutableList SetItem(int index, T value); /// @@ -189,7 +175,6 @@ public interface IImmutableList : IReadOnlyList /// /// The new list -- even if the value being replaced is equal to the new value for that position. /// Thrown when the old value does not exist in the list. - [Pure] IImmutableList Replace(T oldValue, T newValue, IEqualityComparer? equalityComparer); } } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableQueue.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableQueue.cs index 9209b1a599d8b8..d6a18a1cae1160 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableQueue.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableQueue.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -20,13 +19,11 @@ public interface IImmutableQueue : IEnumerable /// /// true if this queue is empty; otherwise, false. /// - [Pure] bool IsEmpty { get; } /// /// Gets an empty queue. /// - [Pure] IImmutableQueue Clear(); /// @@ -36,7 +33,6 @@ public interface IImmutableQueue : IEnumerable /// The element at the front of the queue. /// /// Thrown when the queue is empty. - [Pure] T Peek(); /// @@ -46,7 +42,6 @@ public interface IImmutableQueue : IEnumerable /// /// The new queue. /// - [Pure] IImmutableQueue Enqueue(T value); /// @@ -54,7 +49,6 @@ public interface IImmutableQueue : IEnumerable /// /// A queue; never null. /// Thrown when the queue is empty. - [Pure] IImmutableQueue Dequeue(); } } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableSet.cs index 45acf280f7a7a6..8f2f60cea15167 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableSet.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -21,7 +20,6 @@ public interface IImmutableSet : IReadOnlyCollection /// /// Gets an empty set that retains the same sort or unordered semantics that this instance has. /// - [Pure] IImmutableSet Clear(); /// @@ -31,7 +29,6 @@ public interface IImmutableSet : IReadOnlyCollection /// /// true if the set contains the specified value; otherwise, false. /// - [Pure] bool Contains(T value); /// @@ -39,7 +36,6 @@ public interface IImmutableSet : IReadOnlyCollection /// /// The value to add. /// A new set with the element added, or this set if the element is already in this set. - [Pure] IImmutableSet Add(T value); /// @@ -47,7 +43,6 @@ public interface IImmutableSet : IReadOnlyCollection /// /// The value to remove. /// A new set with the element removed, or this set if the element is not in this set. - [Pure] IImmutableSet Remove(T value); /// @@ -62,7 +57,6 @@ public interface IImmutableSet : IReadOnlyCollection /// a value that has more complete data than the value you currently have, although their /// comparer functions indicate they are equal. /// - [Pure] bool TryGetValue(T equalValue, out T actualValue); /// @@ -70,7 +64,6 @@ public interface IImmutableSet : IReadOnlyCollection /// /// The set to intersect with this one. /// A new set that contains any elements that exist in both sets. - [Pure] IImmutableSet Intersect(IEnumerable other); /// @@ -78,7 +71,6 @@ public interface IImmutableSet : IReadOnlyCollection /// /// The items to remove from this set. /// The new set with the items removed; or the original set if none of the items were in the set. - [Pure] IImmutableSet Except(IEnumerable other); /// @@ -86,7 +78,6 @@ public interface IImmutableSet : IReadOnlyCollection /// /// The other sequence of items. /// The new set. - [Pure] IImmutableSet SymmetricExcept(IEnumerable other); /// @@ -94,7 +85,6 @@ public interface IImmutableSet : IReadOnlyCollection /// /// The items to add. /// The new set with the items added; or the original set if all the items were already in the set. - [Pure] IImmutableSet Union(IEnumerable other); /// @@ -102,7 +92,6 @@ public interface IImmutableSet : IReadOnlyCollection /// /// The sequence of items to check against this set. /// A value indicating whether the sets are equal. - [Pure] bool SetEquals(IEnumerable other); /// @@ -110,7 +99,6 @@ public interface IImmutableSet : IReadOnlyCollection /// /// The collection to compare to the current set. /// true if the current set is a correct subset of other; otherwise, false. - [Pure] bool IsProperSubsetOf(IEnumerable other); /// @@ -118,7 +106,6 @@ public interface IImmutableSet : IReadOnlyCollection /// /// The collection to compare to the current set. /// true if the current set is a correct superset of other; otherwise, false. - [Pure] bool IsProperSupersetOf(IEnumerable other); /// @@ -126,7 +113,6 @@ public interface IImmutableSet : IReadOnlyCollection /// /// The collection to compare to the current set. /// true if the current set is a subset of other; otherwise, false. - [Pure] bool IsSubsetOf(IEnumerable other); /// @@ -134,7 +120,6 @@ public interface IImmutableSet : IReadOnlyCollection /// /// The collection to compare to the current set. /// true if the current set is a superset of other; otherwise, false. - [Pure] bool IsSupersetOf(IEnumerable other); /// @@ -142,7 +127,6 @@ public interface IImmutableSet : IReadOnlyCollection /// /// The collection to compare to the current set. /// true if the current set and other share at least one common element; otherwise, false. - [Pure] bool Overlaps(IEnumerable other); } } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableStack.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableStack.cs index 73a892c909edaf..324b661f0910d5 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableStack.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/IImmutableStack.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -20,13 +19,11 @@ public interface IImmutableStack : IEnumerable /// /// true if this stack is empty; otherwise, false. /// - [Pure] bool IsEmpty { get; } /// /// Gets an empty stack. /// - [Pure] IImmutableStack Clear(); /// @@ -34,7 +31,6 @@ public interface IImmutableStack : IEnumerable /// /// The element to push onto the stack. /// The new stack. - [Pure] IImmutableStack Push(T value); /// @@ -42,14 +38,12 @@ public interface IImmutableStack : IEnumerable /// /// The new stack; never null /// Thrown when the stack is empty. - [Pure] IImmutableStack Pop(); /// /// Gets the element on the top of the stack. /// /// Thrown when the stack is empty. - [Pure] T Peek(); } } diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray.cs index 88f94fcf269c57..6729b89b97433a 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.Contracts; using System.Linq; namespace System.Collections.Immutable @@ -24,7 +23,6 @@ public static class ImmutableArray /// /// The type of element stored in the array. /// An empty array. - [Pure] public static ImmutableArray Create() { return ImmutableArray.Empty; @@ -36,7 +34,6 @@ public static ImmutableArray Create() /// The type of element stored in the array. /// The element to store in the array. /// A 1-element array. - [Pure] public static ImmutableArray Create(T item) { T[] array = new[] { item }; @@ -50,7 +47,6 @@ public static ImmutableArray Create(T item) /// The first element to store in the array. /// The second element to store in the array. /// A 2-element array. - [Pure] public static ImmutableArray Create(T item1, T item2) { T[] array = new[] { item1, item2 }; @@ -65,7 +61,6 @@ public static ImmutableArray Create(T item1, T item2) /// The second element to store in the array. /// The third element to store in the array. /// A 3-element array. - [Pure] public static ImmutableArray Create(T item1, T item2, T item3) { T[] array = new[] { item1, item2, item3 }; @@ -81,7 +76,6 @@ public static ImmutableArray Create(T item1, T item2, T item3) /// The third element to store in the array. /// The fourth element to store in the array. /// A 4-element array. - [Pure] public static ImmutableArray Create(T item1, T item2, T item3, T item4) { T[] array = new[] { item1, item2, item3, item4 }; @@ -94,7 +88,6 @@ public static ImmutableArray Create(T item1, T item2, T item3, T item4) /// The type of element stored in the array. /// The elements to store in the array. /// An immutable array. - [Pure] public static ImmutableArray CreateRange(IEnumerable items) { Requires.NotNull(items, nameof(items)); @@ -142,7 +135,6 @@ public static ImmutableArray CreateRange(IEnumerable items) /// The type of element stored in the array. /// The elements to store in the array. /// An immutable array. - [Pure] public static ImmutableArray Create(params T[]? items) { if (items == null || items.Length == 0) @@ -169,7 +161,6 @@ public static ImmutableArray Create(params T[]? items) /// This overload allows helper methods or custom builder classes to efficiently avoid paying a redundant /// tax for copying an array when the new array is a segment of an existing array. /// - [Pure] public static ImmutableArray Create(T[] items, int start, int length) { Requires.NotNull(items, nameof(items)); @@ -202,7 +193,6 @@ public static ImmutableArray Create(T[] items, int start, int length) /// This overload allows helper methods or custom builder classes to efficiently avoid paying a redundant /// tax for copying an array when the new array is a segment of an existing array. /// - [Pure] public static ImmutableArray Create(ImmutableArray items, int start, int length) { Requires.Range(start >= 0 && start <= items.Length, nameof(start)); @@ -233,7 +223,6 @@ public static ImmutableArray Create(ImmutableArray items, int start, in /// , where a mapping function needs to be applied to each element from /// the source array. /// - [Pure] public static ImmutableArray CreateRange(ImmutableArray items, Func selector) { Requires.NotNull(selector, nameof(selector)); @@ -266,7 +255,6 @@ public static ImmutableArray CreateRange(ImmutableArr /// , where a mapping function needs to be applied to each element from the source array /// included in the resulting array. /// - [Pure] public static ImmutableArray CreateRange(ImmutableArray items, int start, int length, Func selector) { int itemsLength = items.Length; @@ -300,7 +288,6 @@ public static ImmutableArray CreateRange(ImmutableArr /// , where a mapping function needs to be applied to each element from /// the source array. /// - [Pure] public static ImmutableArray CreateRange(ImmutableArray items, Func selector, TArg arg) { Requires.NotNull(selector, nameof(selector)); @@ -334,7 +321,6 @@ public static ImmutableArray CreateRange(Immuta /// , where a mapping function needs to be applied to each element from the source array /// included in the resulting array. /// - [Pure] public static ImmutableArray CreateRange(ImmutableArray items, int start, int length, Func selector, TArg arg) { int itemsLength = items.Length; @@ -362,7 +348,6 @@ public static ImmutableArray CreateRange(Immuta /// /// The type of elements stored in the array. /// A new builder. - [Pure] public static ImmutableArray.Builder CreateBuilder() { return Create().ToBuilder(); @@ -374,7 +359,6 @@ public static ImmutableArray.Builder CreateBuilder() /// The type of elements stored in the array. /// The size of the initial array backing the builder. /// A new builder. - [Pure] public static ImmutableArray.Builder CreateBuilder(int initialCapacity) { return new ImmutableArray.Builder(initialCapacity); @@ -386,7 +370,6 @@ public static ImmutableArray.Builder CreateBuilder(int initialCapacity) /// The type of element in the sequence. /// The sequence to enumerate. /// An immutable array. - [Pure] public static ImmutableArray ToImmutableArray(this IEnumerable items) { if (items is ImmutableArray) @@ -402,7 +385,6 @@ public static ImmutableArray ToImmutableArray(this IEnumerable /// /// The builder to create the immutable array from. /// An immutable array. - [Pure] public static ImmutableArray ToImmutableArray(this ImmutableArray.Builder builder) { Requires.NotNull(builder, nameof(builder)); @@ -431,7 +413,6 @@ public static ImmutableArray ToImmutableArray(this ImmutableAr /// the search encounters an element that does not implement the /// generic interface. /// - [Pure] public static int BinarySearch(this ImmutableArray array, T value) { return Array.BinarySearch(array.array!, value); @@ -462,7 +443,6 @@ public static int BinarySearch(this ImmutableArray array, T value) /// the search encounters an element that does not implement the /// generic interface. /// - [Pure] public static int BinarySearch(this ImmutableArray array, T value, IComparer? comparer) { return Array.BinarySearch(array.array!, value, comparer); @@ -497,7 +477,6 @@ public static int BinarySearch(this ImmutableArray array, T value, ICompar /// /// is less than the lower bound of . -or- is less than zero. /// - [Pure] public static int BinarySearch(this ImmutableArray array, int index, int length, T value) { return Array.BinarySearch(array.array!, index, length, value); @@ -538,7 +517,6 @@ public static int BinarySearch(this ImmutableArray array, int index, int l /// /// is less than the lower bound of . -or- is less than zero. /// - [Pure] public static int BinarySearch(this ImmutableArray array, int index, int length, T value, IComparer? comparer) { return Array.BinarySearch(array.array!, index, length, value, comparer); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs index ca27188f5dd892..d7007365492a3b 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -473,7 +472,6 @@ private void EnsureCapacity(int capacity) /// /// The index of if found in the list; otherwise, -1. /// - [Pure] public int IndexOf(T item) { return this.IndexOf(item, 0, _count, EqualityComparer.Default); @@ -485,7 +483,6 @@ public int IndexOf(T item) /// The item to search for. /// The index at which to begin the search. /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int IndexOf(T item, int startIndex) { return this.IndexOf(item, startIndex, this.Count - startIndex, EqualityComparer.Default); @@ -498,7 +495,6 @@ public int IndexOf(T item, int startIndex) /// The index at which to begin the search. /// The number of elements to search. /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int IndexOf(T item, int startIndex, int count) { return this.IndexOf(item, startIndex, count, EqualityComparer.Default); @@ -515,7 +511,6 @@ public int IndexOf(T item, int startIndex, int count) /// If null, is used. /// /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int IndexOf(T item, int startIndex, int count, IEqualityComparer? equalityComparer) { if (count == 0 && startIndex == 0) @@ -550,7 +545,6 @@ public int IndexOf(T item, int startIndex, int count, IEqualityComparer? equa /// /// The item to search for. /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int LastIndexOf(T item) { if (this.Count == 0) @@ -567,7 +561,6 @@ public int LastIndexOf(T item) /// The item to search for. /// The index at which to begin the search. /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int LastIndexOf(T item, int startIndex) { if (this.Count == 0 && startIndex == 0) @@ -587,7 +580,6 @@ public int LastIndexOf(T item, int startIndex) /// The index at which to begin the search. /// The number of elements to search. /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int LastIndexOf(T item, int startIndex, int count) { return this.LastIndexOf(item, startIndex, count, EqualityComparer.Default); @@ -601,7 +593,6 @@ public int LastIndexOf(T item, int startIndex, int count) /// The number of elements to search. /// The equality comparer to use in the search. /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer? equalityComparer) { if (count == 0 && startIndex == 0) @@ -672,7 +663,6 @@ public void Sort() /// The to use when comparing elements. /// /// is null. - [Pure] public void Sort(Comparison comparison) { Requires.NotNull(comparison, nameof(comparison)); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Minimal.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Minimal.cs index 6d0e50f02909ed..fee37d4d87fecb 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Minimal.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Minimal.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; @@ -227,7 +226,6 @@ private string DebuggerDisplay /// Copies the contents of this array to the specified array. /// /// The array to copy to. - [Pure] public void CopyTo(T[] destination) { var self = this; @@ -240,7 +238,6 @@ public void CopyTo(T[] destination) /// /// The array to copy to. /// The index into the destination array to which the first copied element is written. - [Pure] public void CopyTo(T[] destination, int destinationIndex) { var self = this; @@ -255,7 +252,6 @@ public void CopyTo(T[] destination, int destinationIndex) /// The array to copy to. /// The index into the destination array to which the first copied element is written. /// The number of elements to copy. - [Pure] public void CopyTo(int sourceIndex, T[] destination, int destinationIndex, int length) { var self = this; @@ -267,7 +263,6 @@ public void CopyTo(int sourceIndex, T[] destination, int destinationIndex, int l /// Returns a builder that is populated with the same contents as this array. /// /// The new builder. - [Pure] public ImmutableArray.Builder ToBuilder() { var self = this; @@ -285,7 +280,6 @@ public ImmutableArray.Builder ToBuilder() /// Returns an enumerator for the contents of the array. /// /// An enumerator. - [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] public Enumerator GetEnumerator() { @@ -300,7 +294,6 @@ public Enumerator GetEnumerator() /// /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. /// - [Pure] public override int GetHashCode() { var self = this; @@ -314,7 +307,6 @@ public override int GetHashCode() /// /// true if the specified is equal to this instance; otherwise, false. /// - [Pure] public override bool Equals(object? obj) { return obj is IImmutableArray other && this.array == other.Array; @@ -327,7 +319,6 @@ public override bool Equals(object? obj) /// /// true if the current object is equal to the parameter; otherwise, false. /// - [Pure] [NonVersionable] public bool Equals(ImmutableArray other) { @@ -343,7 +334,6 @@ public bool Equals(ImmutableArray other) /// Covariant upcasts from this method may be reversed by calling the /// or method. /// - [Pure] public static ImmutableArray CastUp(ImmutableArray items) where TDerived : class, T { @@ -355,7 +345,6 @@ public static ImmutableArray CastUp(ImmutableArray items) /// array to an array of type . /// /// Thrown if the cast is illegal. - [Pure] public ImmutableArray CastArray() where TOther : class { return new ImmutableArray((TOther[])(object)array!); @@ -376,7 +365,6 @@ public ImmutableArray CastArray() where TOther : class /// element types to their derived types. However, downcasting is only successful /// when it reverses a prior upcasting operation. /// - [Pure] public ImmutableArray As() where TOther : class { return new ImmutableArray((this.array as TOther[])!); @@ -387,7 +375,6 @@ public ImmutableArray As() where TOther : class /// /// An enumerator. /// Thrown if the property returns true. - [Pure] IEnumerator IEnumerable.GetEnumerator() { var self = this; @@ -400,7 +387,6 @@ IEnumerator IEnumerable.GetEnumerator() /// /// An enumerator. /// Thrown if the property returns true. - [Pure] IEnumerator IEnumerable.GetEnumerator() { var self = this; diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs index 81f7fe157a4fcb..71f58c8c418033 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Runtime.Versioning; @@ -102,7 +101,6 @@ T IReadOnlyList.this[int index] /// /// The item to search for. /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int IndexOf(T item) { var self = this; @@ -116,7 +114,6 @@ public int IndexOf(T item) /// The index at which to begin the search. /// The equality comparer to use in the search. /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int IndexOf(T item, int startIndex, IEqualityComparer? equalityComparer) { var self = this; @@ -129,7 +126,6 @@ public int IndexOf(T item, int startIndex, IEqualityComparer? equalityCompare /// The item to search for. /// The index at which to begin the search. /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int IndexOf(T item, int startIndex) { var self = this; @@ -143,7 +139,6 @@ public int IndexOf(T item, int startIndex) /// The index at which to begin the search. /// The number of elements to search. /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int IndexOf(T item, int startIndex, int count) { return this.IndexOf(item, startIndex, count, EqualityComparer.Default); @@ -160,7 +155,6 @@ public int IndexOf(T item, int startIndex, int count) /// If null, is used. /// /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int IndexOf(T item, int startIndex, int count, IEqualityComparer? equalityComparer) { var self = this; @@ -198,7 +192,6 @@ public int IndexOf(T item, int startIndex, int count, IEqualityComparer? equa /// /// The item to search for. /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int LastIndexOf(T item) { var self = this; @@ -216,7 +209,6 @@ public int LastIndexOf(T item) /// The item to search for. /// The index at which to begin the search. /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int LastIndexOf(T item, int startIndex) { var self = this; @@ -235,7 +227,6 @@ public int LastIndexOf(T item, int startIndex) /// The index at which to begin the search. /// The number of elements to search. /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int LastIndexOf(T item, int startIndex, int count) { return this.LastIndexOf(item, startIndex, count, EqualityComparer.Default); @@ -249,7 +240,6 @@ public int LastIndexOf(T item, int startIndex, int count) /// The number of elements to search. /// The equality comparer to use in the search. /// The 0-based index into the array where the item was found; or -1 if it could not be found. - [Pure] public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer? equalityComparer) { var self = this; @@ -287,7 +277,6 @@ public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer? /// /// The item to search for. /// true if an equal value was found in the array; false otherwise. - [Pure] public bool Contains(T item) { return this.IndexOf(item) >= 0; @@ -299,7 +288,6 @@ public bool Contains(T item) /// The 0-based index into the array at which the new item should be added. /// The item to insert at the start of the array. /// A new array. - [Pure] public ImmutableArray Insert(int index, T item) { var self = this; @@ -332,7 +320,6 @@ public ImmutableArray Insert(int index, T item) /// The index at which to insert the value. /// The elements to insert. /// The new immutable collection. - [Pure] public ImmutableArray InsertRange(int index, IEnumerable items) { var self = this; @@ -386,7 +373,6 @@ public ImmutableArray InsertRange(int index, IEnumerable items) /// The index at which to insert the value. /// The elements to insert. /// The new immutable collection. - [Pure] public ImmutableArray InsertRange(int index, ImmutableArray items) { var self = this; @@ -424,7 +410,6 @@ public ImmutableArray InsertRange(int index, ImmutableArray items) /// /// The item to insert at the end of the array. /// A new array. - [Pure] public ImmutableArray Add(T item) { var self = this; @@ -441,7 +426,6 @@ public ImmutableArray Add(T item) /// /// The values to add. /// A new list with the elements added. - [Pure] public ImmutableArray AddRange(IEnumerable items) { var self = this; @@ -453,7 +437,6 @@ public ImmutableArray AddRange(IEnumerable items) /// /// The values to add. /// A new list with the elements added. - [Pure] public ImmutableArray AddRange(ImmutableArray items) { var self = this; @@ -466,7 +449,6 @@ public ImmutableArray AddRange(ImmutableArray items) /// The index of the item to replace. /// The new item. /// The new array. - [Pure] public ImmutableArray SetItem(int index, T item) { var self = this; @@ -486,7 +468,6 @@ public ImmutableArray SetItem(int index, T item) /// The element to replace the old element with. /// The new list -- even if the value being replaced is equal to the new value for that position. /// Thrown when the old value does not exist in the list. - [Pure] public ImmutableArray Replace(T oldValue, T newValue) { return this.Replace(oldValue, newValue, EqualityComparer.Default); @@ -503,7 +484,6 @@ public ImmutableArray Replace(T oldValue, T newValue) /// /// The new list -- even if the value being replaced is equal to the new value for that position. /// Thrown when the old value does not exist in the list. - [Pure] public ImmutableArray Replace(T oldValue, T newValue, IEqualityComparer? equalityComparer) { var self = this; @@ -522,7 +502,6 @@ public ImmutableArray Replace(T oldValue, T newValue, IEqualityComparer? e /// /// The item to remove. /// The new array. - [Pure] public ImmutableArray Remove(T item) { return this.Remove(item, EqualityComparer.Default); @@ -538,7 +517,6 @@ public ImmutableArray Remove(T item) /// If null, is used. /// /// The new array. - [Pure] public ImmutableArray Remove(T item, IEqualityComparer? equalityComparer) { var self = this; @@ -554,7 +532,6 @@ public ImmutableArray Remove(T item, IEqualityComparer? equalityComparer) /// /// The 0-based index into the array for the element to omit from the returned array. /// The new array. - [Pure] public ImmutableArray RemoveAt(int index) { return this.RemoveRange(index, 1); @@ -566,7 +543,6 @@ public ImmutableArray RemoveAt(int index) /// The 0-based index into the array for the element to omit from the returned array. /// The number of elements to remove. /// The new array. - [Pure] public ImmutableArray RemoveRange(int index, int length) { var self = this; @@ -592,7 +568,6 @@ public ImmutableArray RemoveRange(int index, int length) /// /// A new list with the elements removed. /// - [Pure] public ImmutableArray RemoveRange(IEnumerable items) { return this.RemoveRange(items, EqualityComparer.Default); @@ -609,7 +584,6 @@ public ImmutableArray RemoveRange(IEnumerable items) /// /// A new list with the elements removed. /// - [Pure] public ImmutableArray RemoveRange(IEnumerable items, IEqualityComparer? equalityComparer) { var self = this; @@ -637,7 +611,6 @@ public ImmutableArray RemoveRange(IEnumerable items, IEqualityComparer? /// /// A new list with the elements removed. /// - [Pure] public ImmutableArray RemoveRange(ImmutableArray items) { return this.RemoveRange(items, EqualityComparer.Default); @@ -653,7 +626,6 @@ public ImmutableArray RemoveRange(ImmutableArray items) /// /// A new list with the elements removed. /// - [Pure] public ImmutableArray RemoveRange(ImmutableArray items, IEqualityComparer? equalityComparer) { var self = this; @@ -685,7 +657,6 @@ public ImmutableArray RemoveRange(ImmutableArray items, IEqualityComparer< /// /// The new list. /// - [Pure] public ImmutableArray RemoveAll(Predicate match) { var self = this; @@ -719,7 +690,6 @@ public ImmutableArray RemoveAll(Predicate match) /// /// Returns an empty array. /// - [Pure] public ImmutableArray Clear() { return Empty; @@ -728,7 +698,6 @@ public ImmutableArray Clear() /// /// Returns a sorted instance of this array. /// - [Pure] public ImmutableArray Sort() { var self = this; @@ -744,7 +713,6 @@ public ImmutableArray Sort() /// /// The sorted list. /// is null. - [Pure] public ImmutableArray Sort(Comparison comparison) { Requires.NotNull(comparison, nameof(comparison)); @@ -757,7 +725,6 @@ public ImmutableArray Sort(Comparison comparison) /// Returns a sorted instance of this array. /// /// The comparer to use in sorting. If null, the default comparer is used. - [Pure] public ImmutableArray Sort(IComparer? comparer) { var self = this; @@ -770,7 +737,6 @@ public ImmutableArray Sort(IComparer? comparer) /// The index of the first element to consider in the sort. /// The number of elements to include in the sort. /// The comparer to use in sorting. If null, the default comparer is used. - [Pure] public ImmutableArray Sort(int index, int count, IComparer? comparer) { var self = this; @@ -816,7 +782,6 @@ public ImmutableArray Sort(int index, int count, IComparer? comparer) /// An that contains elements from /// the input sequence of type . /// - [Pure] public IEnumerable OfType() { var self = this; @@ -830,31 +795,26 @@ public IEnumerable OfType() #region Explicit interface methods - [Pure] void IList.Insert(int index, T item) { throw new NotSupportedException(); } - [Pure] void IList.RemoveAt(int index) { throw new NotSupportedException(); } - [Pure] void ICollection.Add(T item) { throw new NotSupportedException(); } - [Pure] void ICollection.Clear() { throw new NotSupportedException(); } - [Pure] bool ICollection.Remove(T item) { throw new NotSupportedException(); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary.cs index 68b9bfc2670b27..deab2c00009bf3 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Linq; namespace System.Collections.Immutable @@ -20,7 +19,6 @@ public static class ImmutableDictionary /// The type of keys stored by the dictionary. /// The type of values stored by the dictionary. /// The immutable collection. - [Pure] public static ImmutableDictionary Create() where TKey : notnull { return ImmutableDictionary.Empty; @@ -35,7 +33,6 @@ public static ImmutableDictionary Create() where TKe /// /// The immutable collection. /// - [Pure] public static ImmutableDictionary Create(IEqualityComparer? keyComparer) where TKey : notnull { return ImmutableDictionary.Empty.WithComparers(keyComparer); @@ -51,7 +48,6 @@ public static ImmutableDictionary Create(IEqualityCo /// /// The immutable collection. /// - [Pure] public static ImmutableDictionary Create(IEqualityComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { return ImmutableDictionary.Empty.WithComparers(keyComparer, valueComparer); @@ -64,7 +60,6 @@ public static ImmutableDictionary Create(IEqualityCo /// The type of values stored by the dictionary. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableDictionary CreateRange(IEnumerable> items) where TKey : notnull { return ImmutableDictionary.Empty.AddRange(items); @@ -78,7 +73,6 @@ public static ImmutableDictionary CreateRange(IEnume /// The key comparer. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableDictionary CreateRange(IEqualityComparer? keyComparer, IEnumerable> items) where TKey : notnull { return ImmutableDictionary.Empty.WithComparers(keyComparer).AddRange(items); @@ -93,7 +87,6 @@ public static ImmutableDictionary CreateRange(IEqual /// The value comparer. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableDictionary CreateRange(IEqualityComparer? keyComparer, IEqualityComparer? valueComparer, IEnumerable> items) where TKey : notnull { return ImmutableDictionary.Empty.WithComparers(keyComparer, valueComparer).AddRange(items); @@ -105,7 +98,6 @@ public static ImmutableDictionary CreateRange(IEqual /// The type of keys stored by the dictionary. /// The type of values stored by the dictionary. /// The new builder. - [Pure] public static ImmutableDictionary.Builder CreateBuilder() where TKey : notnull { return Create().ToBuilder(); @@ -118,7 +110,6 @@ public static ImmutableDictionary.Builder CreateBuilderThe type of values stored by the dictionary. /// The key comparer. /// The new builder. - [Pure] public static ImmutableDictionary.Builder CreateBuilder(IEqualityComparer? keyComparer) where TKey : notnull { return Create(keyComparer).ToBuilder(); @@ -132,7 +123,6 @@ public static ImmutableDictionary.Builder CreateBuilderThe key comparer. /// The value comparer. /// The new builder. - [Pure] public static ImmutableDictionary.Builder CreateBuilder(IEqualityComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { return Create(keyComparer, valueComparer).ToBuilder(); @@ -150,7 +140,6 @@ public static ImmutableDictionary.Builder CreateBuilderThe key comparer to use for the map. /// The value comparer to use for the map. /// The immutable map. - [Pure] public static ImmutableDictionary ToImmutableDictionary(this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { Requires.NotNull(source, nameof(source)); @@ -166,7 +155,6 @@ public static ImmutableDictionary ToImmutableDictionary /// The builder to create the immutable dictionary from. /// An immutable dictionary. - [Pure] public static ImmutableDictionary ToImmutableDictionary(this ImmutableDictionary.Builder builder) where TKey : notnull { Requires.NotNull(builder, nameof(builder)); @@ -185,7 +173,6 @@ public static ImmutableDictionary ToImmutableDictionaryThe function that will produce the value for the map from each sequence element. /// The key comparer to use for the map. /// The immutable map. - [Pure] public static ImmutableDictionary ToImmutableDictionary(this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer? keyComparer) where TKey : notnull { return ToImmutableDictionary(source, keySelector, elementSelector, keyComparer, null); @@ -199,7 +186,6 @@ public static ImmutableDictionary ToImmutableDictionaryThe sequence to enumerate to generate the map. /// The function that will produce the key for the map from each sequence element. /// The immutable map. - [Pure] public static ImmutableDictionary ToImmutableDictionary(this IEnumerable source, Func keySelector) where TKey : notnull { return ToImmutableDictionary(source, keySelector, v => v, null, null); @@ -214,7 +200,6 @@ public static ImmutableDictionary ToImmutableDictionaryThe function that will produce the key for the map from each sequence element. /// The key comparer to use for the map. /// The immutable map. - [Pure] public static ImmutableDictionary ToImmutableDictionary(this IEnumerable source, Func keySelector, IEqualityComparer? keyComparer) where TKey : notnull { return ToImmutableDictionary(source, keySelector, v => v, keyComparer, null); @@ -230,7 +215,6 @@ public static ImmutableDictionary ToImmutableDictionaryThe function that will produce the key for the map from each sequence element. /// The function that will produce the value for the map from each sequence element. /// The immutable map. - [Pure] public static ImmutableDictionary ToImmutableDictionary(this IEnumerable source, Func keySelector, Func elementSelector) where TKey : notnull { return ToImmutableDictionary(source, keySelector, elementSelector, null, null); @@ -245,7 +229,6 @@ public static ImmutableDictionary ToImmutableDictionaryThe key comparer to use when building the immutable map. /// The value comparer to use for the immutable map. /// An immutable map. - [Pure] public static ImmutableDictionary ToImmutableDictionary(this IEnumerable> source, IEqualityComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { Requires.NotNull(source, nameof(source)); @@ -267,7 +250,6 @@ public static ImmutableDictionary ToImmutableDictionaryThe sequence of key=value pairs. /// The key comparer to use when building the immutable map. /// An immutable map. - [Pure] public static ImmutableDictionary ToImmutableDictionary(this IEnumerable> source, IEqualityComparer? keyComparer) where TKey : notnull { return ToImmutableDictionary(source, keyComparer, null); @@ -280,7 +262,6 @@ public static ImmutableDictionary ToImmutableDictionaryThe type of value in the map. /// The sequence of key=value pairs. /// An immutable map. - [Pure] public static ImmutableDictionary ToImmutableDictionary(this IEnumerable> source) where TKey : notnull { return ToImmutableDictionary(source, null, null); @@ -297,7 +278,6 @@ public static ImmutableDictionary ToImmutableDictionary /// true if this map contains the key-value pair; otherwise, false. /// - [Pure] public static bool Contains(this IImmutableDictionary map, TKey key, TValue value) where TKey : notnull { Requires.NotNull(map, nameof(map)); @@ -311,7 +291,6 @@ public static bool Contains(this IImmutableDictionaryThe dictionary to retrieve the value from. /// The key to search for. /// The value for the key, or the default value of type if no matching key was found. - [Pure] [return: MaybeNull] public static TValue GetValueOrDefault(this IImmutableDictionary dictionary, TKey key) where TKey : notnull { @@ -329,7 +308,6 @@ public static TValue GetValueOrDefault(this IImmutableDictionary /// The value for the key, or if no matching key was found. /// - [Pure] public static TValue GetValueOrDefault(this IImmutableDictionary dictionary, TKey key, TValue defaultValue) where TKey : notnull { Requires.NotNull(dictionary, nameof(dictionary)); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary_2.Builder.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary_2.Builder.cs index 5b94faa3d30b15..34f162d0977142 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary_2.Builder.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary_2.Builder.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -468,7 +467,6 @@ public Enumerator GetEnumerator() /// /// The key to search for. /// The value for the key, or the default value of type if no matching key was found. - [Pure] [return: MaybeNull] public TValue GetValueOrDefault(TKey key) { @@ -483,7 +481,6 @@ public TValue GetValueOrDefault(TKey key) /// /// The value for the key, or if no matching key was found. /// - [Pure] public TValue GetValueOrDefault(TKey key, TValue defaultValue) { Requires.NotNullAllowStructs(key, nameof(key)); @@ -561,7 +558,6 @@ public bool ContainsKey(TKey key) /// true if the contains /// an element with the specified value; otherwise, false. /// - [Pure] public bool ContainsValue(TValue value) { foreach (KeyValuePair item in this) diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary_2.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary_2.cs index 68643196c43b5c..2cad5c9fad674b 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary_2.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableDictionary_2.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Linq; namespace System.Collections.Immutable @@ -287,7 +286,6 @@ bool ICollection>.IsReadOnly /// This is an O(1) operation and results in only a single (small) memory allocation. /// The mutable collection that is returned is *not* thread-safe. /// - [Pure] public Builder ToBuilder() { // We must not cache the instance created here and return it to various callers. @@ -299,7 +297,6 @@ public Builder ToBuilder() /// /// See the interface. /// - [Pure] public ImmutableDictionary Add(TKey key, TValue value) { Requires.NotNullAllowStructs(key, nameof(key)); @@ -311,7 +308,6 @@ public ImmutableDictionary Add(TKey key, TValue value) /// /// See the interface. /// - [Pure] public ImmutableDictionary AddRange(IEnumerable> pairs) { Requires.NotNull(pairs, nameof(pairs)); @@ -322,7 +318,6 @@ public ImmutableDictionary AddRange(IEnumerable /// See the interface. /// - [Pure] public ImmutableDictionary SetItem(TKey key, TValue value) { Requires.NotNullAllowStructs(key, nameof(key)); @@ -336,7 +331,6 @@ public ImmutableDictionary SetItem(TKey key, TValue value) /// /// The key=value pairs to set on the map. Any keys that conflict with existing keys will overwrite the previous values. /// An immutable dictionary. - [Pure] public ImmutableDictionary SetItems(IEnumerable> items) { Requires.NotNull(items, nameof(items)); @@ -348,7 +342,6 @@ public ImmutableDictionary SetItems(IEnumerable /// See the interface. /// - [Pure] public ImmutableDictionary Remove(TKey key) { Requires.NotNullAllowStructs(key, nameof(key)); @@ -360,7 +353,6 @@ public ImmutableDictionary Remove(TKey key) /// /// See the interface. /// - [Pure] public ImmutableDictionary RemoveRange(IEnumerable keys) { Requires.NotNull(keys, nameof(keys)); @@ -432,7 +424,6 @@ public bool TryGetKey(TKey equalKey, out TKey actualKey) /// /// See the interface. /// - [Pure] public ImmutableDictionary WithComparers(IEqualityComparer? keyComparer, IEqualityComparer? valueComparer) { if (keyComparer == null) @@ -472,7 +463,6 @@ public ImmutableDictionary WithComparers(IEqualityComparer? /// /// See the interface. /// - [Pure] public ImmutableDictionary WithComparers(IEqualityComparer? keyComparer) { return this.WithComparers(keyComparer, _comparers.ValueComparer); @@ -490,7 +480,6 @@ public ImmutableDictionary WithComparers(IEqualityComparer? /// true if the contains /// an element with the specified value; otherwise, false. /// - [Pure] public bool ContainsValue(TValue value) { foreach (KeyValuePair item in this) @@ -851,7 +840,6 @@ IEnumerator IEnumerable.GetEnumerator() /// /// The comparers. /// The empty dictionary. - [Pure] private static ImmutableDictionary EmptyWithComparers(Comparers comparers) { Requires.NotNull(comparers, nameof(comparers)); @@ -1076,7 +1064,6 @@ private ImmutableDictionary Wrap(SortedInt32KeyNode? r /// /// The entries to add. /// true when being called from to avoid a stack overflow. - [Pure] private ImmutableDictionary AddRange(IEnumerable> pairs, bool avoidToHashMap) { Requires.NotNull(pairs, nameof(pairs)); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet.cs index 565e6655ff044b..4f0d89d06d24ad 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -17,7 +16,6 @@ public static class ImmutableHashSet /// /// The type of items stored by the collection. /// The immutable collection. - [Pure] public static ImmutableHashSet Create() { return ImmutableHashSet.Empty; @@ -31,7 +29,6 @@ public static ImmutableHashSet Create() /// /// The immutable collection. /// - [Pure] public static ImmutableHashSet Create(IEqualityComparer? equalityComparer) { return ImmutableHashSet.Empty.WithComparer(equalityComparer); @@ -43,7 +40,6 @@ public static ImmutableHashSet Create(IEqualityComparer? equalityCompar /// The type of items stored by the collection. /// The item to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableHashSet Create(T item) { return ImmutableHashSet.Empty.Add(item); @@ -56,7 +52,6 @@ public static ImmutableHashSet Create(T item) /// The equality comparer. /// The item to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableHashSet Create(IEqualityComparer? equalityComparer, T item) { return ImmutableHashSet.Empty.WithComparer(equalityComparer).Add(item); @@ -68,7 +63,6 @@ public static ImmutableHashSet Create(IEqualityComparer? equalityCompar /// The type of items stored by the collection. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableHashSet CreateRange(IEnumerable items) { return ImmutableHashSet.Empty.Union(items); @@ -81,7 +75,6 @@ public static ImmutableHashSet CreateRange(IEnumerable items) /// The equality comparer. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableHashSet CreateRange(IEqualityComparer? equalityComparer, IEnumerable items) { return ImmutableHashSet.Empty.WithComparer(equalityComparer).Union(items); @@ -93,7 +86,6 @@ public static ImmutableHashSet CreateRange(IEqualityComparer? equalityC /// The type of items stored by the collection. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableHashSet Create(params T[] items) { return ImmutableHashSet.Empty.Union(items); @@ -106,7 +98,6 @@ public static ImmutableHashSet Create(params T[] items) /// The equality comparer. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableHashSet Create(IEqualityComparer? equalityComparer, params T[] items) { return ImmutableHashSet.Empty.WithComparer(equalityComparer).Union(items); @@ -117,7 +108,6 @@ public static ImmutableHashSet Create(IEqualityComparer? equalityCompar /// /// The type of items stored by the collection. /// The immutable collection. - [Pure] public static ImmutableHashSet.Builder CreateBuilder() { return Create().ToBuilder(); @@ -131,7 +121,6 @@ public static ImmutableHashSet.Builder CreateBuilder() /// /// The immutable collection. /// - [Pure] public static ImmutableHashSet.Builder CreateBuilder(IEqualityComparer? equalityComparer) { return Create(equalityComparer).ToBuilder(); @@ -144,7 +133,6 @@ public static ImmutableHashSet.Builder CreateBuilder(IEqualityComparer? /// The sequence to enumerate. /// The equality comparer to use for initializing and adding members to the hash set. /// An immutable set. - [Pure] public static ImmutableHashSet ToImmutableHashSet(this IEnumerable source, IEqualityComparer? equalityComparer) { if (source is ImmutableHashSet existingSet) @@ -160,7 +148,6 @@ public static ImmutableHashSet ToImmutableHashSet(this IEnumer /// /// The builder to create the immutable set from. /// An immutable set. - [Pure] public static ImmutableHashSet ToImmutableHashSet(this ImmutableHashSet.Builder builder) { Requires.NotNull(builder, nameof(builder)); @@ -175,7 +162,6 @@ public static ImmutableHashSet ToImmutableHashSet(this Immutab /// The type of element in the sequence. /// The sequence to enumerate. /// An immutable set. - [Pure] public static ImmutableHashSet ToImmutableHashSet(this IEnumerable source) { return ToImmutableHashSet(source, null); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs index 8a54be5d5122e0..0a43dc18aaab79 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableHashSet_1.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Linq; namespace System.Collections.Immutable @@ -181,7 +180,6 @@ private MutationInput Origin /// This is an O(1) operation and results in only a single (small) memory allocation. /// The mutable collection that is returned is *not* thread-safe. /// - [Pure] public Builder ToBuilder() { // We must not cache the instance created here and return it to various callers. @@ -193,7 +191,6 @@ public Builder ToBuilder() /// /// See the interface. /// - [Pure] public ImmutableHashSet Add(T item) { var result = Add(item, this.Origin); @@ -221,7 +218,6 @@ public ImmutableHashSet Remove(T item) /// a value that has more complete data than the value you currently have, although their /// comparer functions indicate they are equal. /// - [Pure] public bool TryGetValue(T equalValue, out T actualValue) { int hashCode = equalValue != null ? _equalityComparer.GetHashCode(equalValue) : 0; @@ -238,7 +234,6 @@ public bool TryGetValue(T equalValue, out T actualValue) /// /// See the interface. /// - [Pure] public ImmutableHashSet Union(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -249,7 +244,6 @@ public ImmutableHashSet Union(IEnumerable other) /// /// See the interface. /// - [Pure] public ImmutableHashSet Intersect(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -274,7 +268,6 @@ public ImmutableHashSet Except(IEnumerable other) /// /// The other sequence of items. /// The new set. - [Pure] public ImmutableHashSet SymmetricExcept(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -288,7 +281,6 @@ public ImmutableHashSet SymmetricExcept(IEnumerable other) /// /// The sequence of items to check against this set. /// A value indicating whether the sets are equal. - [Pure] public bool SetEquals(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -306,7 +298,6 @@ public bool SetEquals(IEnumerable other) /// /// The collection to compare to the current set. /// true if the current set is a correct subset of ; otherwise, false. - [Pure] public bool IsProperSubsetOf(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -319,7 +310,6 @@ public bool IsProperSubsetOf(IEnumerable other) /// /// The collection to compare to the current set. /// true if the current set is a correct superset of ; otherwise, false. - [Pure] public bool IsProperSupersetOf(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -332,7 +322,6 @@ public bool IsProperSupersetOf(IEnumerable other) /// /// The collection to compare to the current set. /// true if the current set is a subset of ; otherwise, false. - [Pure] public bool IsSubsetOf(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -345,7 +334,6 @@ public bool IsSubsetOf(IEnumerable other) /// /// The collection to compare to the current set. /// true if the current set is a superset of ; otherwise, false. - [Pure] public bool IsSupersetOf(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -358,7 +346,6 @@ public bool IsSupersetOf(IEnumerable other) /// /// The collection to compare to the current set. /// true if the current set and share at least one common element; otherwise, false. - [Pure] public bool Overlaps(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -437,7 +424,6 @@ public bool Contains(T item) /// /// See the interface. /// - [Pure] public ImmutableHashSet WithComparer(IEqualityComparer? equalityComparer) { if (equalityComparer == null) @@ -835,7 +821,6 @@ private static MutationResult Except(IEnumerable other, IEqualityComparer /// /// Performs the set operation on a given data structure. /// - [Pure] private static MutationResult SymmetricExcept(IEnumerable other, MutationInput origin) { Requires.NotNull(other, nameof(other)); @@ -1027,7 +1012,6 @@ private ImmutableHashSet Wrap(SortedInt32KeyNode root, int adjust /// /// The entries to add. /// true when being called from to avoid a stack overflow. - [Pure] private ImmutableHashSet Union(IEnumerable items, bool avoidWithComparer) { Requires.NotNull(items, nameof(items)); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList.cs index 1025f475ae4524..83ebd120b23b5b 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -17,7 +16,6 @@ public static class ImmutableList /// /// The type of items stored by the collection. /// The immutable collection. - [Pure] public static ImmutableList Create() => ImmutableList.Empty; /// @@ -26,7 +24,6 @@ public static class ImmutableList /// The type of items stored by the collection. /// The item to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableList Create(T item) => ImmutableList.Empty.Add(item); /// @@ -35,7 +32,6 @@ public static class ImmutableList /// The type of items stored by the collection. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableList CreateRange(IEnumerable items) => ImmutableList.Empty.AddRange(items); /// @@ -44,7 +40,6 @@ public static class ImmutableList /// The type of items stored by the collection. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableList Create(params T[] items) => ImmutableList.Empty.AddRange(items); /// @@ -52,7 +47,6 @@ public static class ImmutableList /// /// The type of items stored by the collection. /// The immutable collection builder. - [Pure] public static ImmutableList.Builder CreateBuilder() => Create().ToBuilder(); /// @@ -61,7 +55,6 @@ public static class ImmutableList /// The type of element in the sequence. /// The sequence to enumerate. /// An immutable list. - [Pure] public static ImmutableList ToImmutableList(this IEnumerable source) { var existingList = source as ImmutableList; @@ -78,7 +71,6 @@ public static ImmutableList ToImmutableList(this IEnumerable /// The builder to create the immutable list from. /// An immutable list. - [Pure] public static ImmutableList ToImmutableList(this ImmutableList.Builder builder) { Requires.NotNull(builder, nameof(builder)); @@ -94,7 +86,6 @@ public static ImmutableList ToImmutableList(this ImmutableList /// The element to replace the old element with. /// The new list -- even if the value being replaced is equal to the new value for that position. /// Thrown when the old value does not exist in the list. - [Pure] public static IImmutableList Replace(this IImmutableList list, T oldValue, T newValue) { Requires.NotNull(list, nameof(list)); @@ -107,7 +98,6 @@ public static IImmutableList Replace(this IImmutableList list, T oldVal /// The list to search. /// The value to remove. /// A new list with the element removed, or this list if the element is not in this list. - [Pure] public static IImmutableList Remove(this IImmutableList list, T value) { Requires.NotNull(list, nameof(list)); @@ -122,7 +112,6 @@ public static IImmutableList Remove(this IImmutableList list, T value) /// /// A new list with the elements removed. /// - [Pure] public static IImmutableList RemoveRange(this IImmutableList list, IEnumerable items) { Requires.NotNull(list, nameof(list)); @@ -143,7 +132,6 @@ public static IImmutableList RemoveRange(this IImmutableList list, IEnu /// elements in the that extends from index /// to the last element, if found; otherwise, -1. /// - [Pure] public static int IndexOf(this IImmutableList list, T item) { Requires.NotNull(list, nameof(list)); @@ -165,7 +153,6 @@ public static int IndexOf(this IImmutableList list, T item) /// elements in the that extends from index /// to the last element, if found; otherwise, -1. /// - [Pure] public static int IndexOf(this IImmutableList list, T item, IEqualityComparer? equalityComparer) { Requires.NotNull(list, nameof(list)); @@ -191,7 +178,6 @@ public static int IndexOf(this IImmutableList list, T item, IEqualityCompa /// elements in the that extends from index /// to the last element, if found; otherwise, -1. /// - [Pure] public static int IndexOf(this IImmutableList list, T item, int startIndex) { Requires.NotNull(list, nameof(list)); @@ -220,7 +206,6 @@ public static int IndexOf(this IImmutableList list, T item, int startIndex /// elements in the that extends from index /// to the last element, if found; otherwise, -1. /// - [Pure] public static int IndexOf(this IImmutableList list, T item, int startIndex, int count) { Requires.NotNull(list, nameof(list)); @@ -240,7 +225,6 @@ public static int IndexOf(this IImmutableList list, T item, int startIndex /// The zero-based index of the last occurrence of item within the entire the /// , if found; otherwise, -1. /// - [Pure] public static int LastIndexOf(this IImmutableList list, T item) { Requires.NotNull(list, nameof(list)); @@ -268,7 +252,6 @@ public static int LastIndexOf(this IImmutableList list, T item) /// The zero-based index of the last occurrence of item within the entire the /// , if found; otherwise, -1. /// - [Pure] public static int LastIndexOf(this IImmutableList list, T item, IEqualityComparer? equalityComparer) { Requires.NotNull(list, nameof(list)); @@ -300,7 +283,6 @@ public static int LastIndexOf(this IImmutableList list, T item, IEqualityC /// in the that extends from the first element /// to index, if found; otherwise, -1. /// - [Pure] public static int LastIndexOf(this IImmutableList list, T item, int startIndex) { Requires.NotNull(list, nameof(list)); @@ -334,7 +316,6 @@ public static int LastIndexOf(this IImmutableList list, T item, int startI /// in the that extends from the first element /// to index, if found; otherwise, -1. /// - [Pure] public static int LastIndexOf(this IImmutableList list, T item, int startIndex, int count) { Requires.NotNull(list, nameof(list)); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Builder.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Builder.cs index 104ffe2e92f574..13c3942ed345b0 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Builder.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Builder.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -540,7 +539,6 @@ public ImmutableList ConvertAll(Func converter) /// elements in the ImmutableList<T> that extends from index /// to the last element, if found; otherwise, -1. /// - [Pure] public int IndexOf(T item, int index) => _root.IndexOf(item, index, this.Count - index, EqualityComparer.Default); @@ -565,7 +563,6 @@ public int IndexOf(T item, int index) => /// elements in the ImmutableList<T> that starts at index and /// contains count number of elements, if found; otherwise, -1. /// - [Pure] public int IndexOf(T item, int index, int count) => _root.IndexOf(item, index, count, EqualityComparer.Default); @@ -594,7 +591,6 @@ public int IndexOf(T item, int index, int count) => /// elements in the ImmutableList<T> that starts at index and /// contains count number of elements, if found; otherwise, -1. /// - [Pure] public int IndexOf(T item, int index, int count, IEqualityComparer? equalityComparer) => _root.IndexOf(item, index, count, equalityComparer); @@ -613,7 +609,6 @@ public int IndexOf(T item, int index, int count, IEqualityComparer? equalityC /// in the ImmutableList<T> that contains count number of elements /// and ends at index, if found; otherwise, -1. /// - [Pure] public int LastIndexOf(T item) { if (this.Count == 0) @@ -640,7 +635,6 @@ public int LastIndexOf(T item) /// in the ImmutableList<T> that contains count number of elements /// and ends at index, if found; otherwise, -1. /// - [Pure] public int LastIndexOf(T item, int startIndex) { if (this.Count == 0 && startIndex == 0) @@ -668,7 +662,6 @@ public int LastIndexOf(T item, int startIndex) /// in the ImmutableList<T> that contains count number of elements /// and ends at index, if found; otherwise, -1. /// - [Pure] public int LastIndexOf(T item, int startIndex, int count) => _root.LastIndexOf(item, startIndex, count, EqualityComparer.Default); @@ -690,7 +683,6 @@ public int LastIndexOf(T item, int startIndex, int count) => /// in the ImmutableList<T> that contains count number of elements /// and ends at index, if found; otherwise, -1. /// - [Pure] public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer? equalityComparer) => _root.LastIndexOf(item, startIndex, count, equalityComparer); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Node.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Node.cs index 211d166ad8309f..f12b89db195682 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Node.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.Node.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Runtime.CompilerServices; namespace System.Collections.Immutable @@ -259,7 +258,6 @@ internal ref readonly T ItemRef(int index) /// The starting index within that should be captured by the node tree. /// The number of elements from that should be captured by the node tree. /// The root of the created node tree. - [Pure] internal static Node NodeTreeFromList(IOrderedCollection items, int start, int length) { Requires.NotNull(items, nameof(items)); @@ -704,7 +702,6 @@ internal int BinarySearch(int index, int count, T item, IComparer? comparer) /// The zero-based index of the first occurrence of within the entire /// , if found; otherwise, -1. /// - [Pure] internal int IndexOf(T item, IEqualityComparer? equalityComparer) => this.IndexOf(item, 0, this.Count, equalityComparer); /// @@ -720,7 +717,6 @@ internal int BinarySearch(int index, int count, T item, IComparer? comparer) /// /// true if it is found, false otherwise. /// - [Pure] internal bool Contains(T item, IEqualityComparer equalityComparer) => Contains(this, item, equalityComparer); /// @@ -748,7 +744,6 @@ internal int BinarySearch(int index, int count, T item, IComparer? comparer) /// elements in the that starts at and /// contains number of elements, if found; otherwise, -1. /// - [Pure] internal int IndexOf(T item, int index, int count, IEqualityComparer? equalityComparer) { Requires.Range(index >= 0, nameof(index)); @@ -791,7 +786,6 @@ internal int IndexOf(T item, int index, int count, IEqualityComparer? equalit /// in the that contains number of elements /// and ends at , if found; otherwise, -1. /// - [Pure] internal int LastIndexOf(T item, int index, int count, IEqualityComparer? equalityComparer) { Requires.Range(index >= 0, nameof(index)); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.cs index d7a0f7fcb6acd1..82e49202abd16f 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableList_1.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Linq; namespace System.Collections.Immutable @@ -206,7 +205,6 @@ private ImmutableList(Node root) /// This is an O(1) operation and results in only a single (small) memory allocation. /// The mutable collection that is returned is *not* thread-safe. /// - [Pure] public Builder ToBuilder() { // We must not cache the instance created here and return it to various callers. @@ -218,7 +216,6 @@ public Builder ToBuilder() /// /// See the interface. /// - [Pure] public ImmutableList Add(T value) { var result = _root.Add(value); @@ -228,7 +225,6 @@ public ImmutableList Add(T value) /// /// See the interface. /// - [Pure] public ImmutableList AddRange(IEnumerable items) { Requires.NotNull(items, nameof(items)); @@ -247,7 +243,6 @@ public ImmutableList AddRange(IEnumerable items) /// /// See the interface. /// - [Pure] public ImmutableList Insert(int index, T item) { Requires.Range(index >= 0 && index <= this.Count, nameof(index)); @@ -257,7 +252,6 @@ public ImmutableList Insert(int index, T item) /// /// See the interface. /// - [Pure] public ImmutableList InsertRange(int index, IEnumerable items) { Requires.Range(index >= 0 && index <= this.Count, nameof(index)); @@ -271,13 +265,11 @@ public ImmutableList InsertRange(int index, IEnumerable items) /// /// See the interface. /// - [Pure] public ImmutableList Remove(T value) => this.Remove(value, EqualityComparer.Default); /// /// See the interface. /// - [Pure] public ImmutableList Remove(T value, IEqualityComparer? equalityComparer) { int index = this.IndexOf(value, equalityComparer); @@ -290,7 +282,6 @@ public ImmutableList Remove(T value, IEqualityComparer? equalityComparer) /// The starting index to begin removal. /// The number of elements to remove. /// A new list with the elements removed. - [Pure] public ImmutableList RemoveRange(int index, int count) { Requires.Range(index >= 0 && index <= this.Count, nameof(index)); @@ -313,7 +304,6 @@ public ImmutableList RemoveRange(int index, int count) /// /// A new list with the elements removed. /// - [Pure] public ImmutableList RemoveRange(IEnumerable items) => this.RemoveRange(items, EqualityComparer.Default); /// @@ -327,7 +317,6 @@ public ImmutableList RemoveRange(int index, int count) /// /// A new list with the elements removed. /// - [Pure] public ImmutableList RemoveRange(IEnumerable items, IEqualityComparer? equalityComparer) { Requires.NotNull(items, nameof(items)); @@ -356,7 +345,6 @@ public ImmutableList RemoveRange(IEnumerable items, IEqualityComparer? /// /// See the interface. /// - [Pure] public ImmutableList RemoveAt(int index) { Requires.Range(index >= 0 && index < this.Count, nameof(index)); @@ -375,7 +363,6 @@ public ImmutableList RemoveAt(int index) /// /// The new list. /// - [Pure] public ImmutableList RemoveAll(Predicate match) { Requires.NotNull(match, nameof(match)); @@ -386,19 +373,16 @@ public ImmutableList RemoveAll(Predicate match) /// /// See the interface. /// - [Pure] public ImmutableList SetItem(int index, T value) => this.Wrap(_root.ReplaceAt(index, value)); /// /// See the interface. /// - [Pure] public ImmutableList Replace(T oldValue, T newValue) => this.Replace(oldValue, newValue, EqualityComparer.Default); /// /// See the interface. /// - [Pure] public ImmutableList Replace(T oldValue, T newValue, IEqualityComparer? equalityComparer) { int index = this.IndexOf(oldValue, equalityComparer); @@ -414,7 +398,6 @@ public ImmutableList Replace(T oldValue, T newValue, IEqualityComparer? eq /// Reverses the order of the elements in the entire . /// /// The reversed list. - [Pure] public ImmutableList Reverse() => this.Wrap(_root.Reverse()); /// @@ -423,14 +406,12 @@ public ImmutableList Replace(T oldValue, T newValue, IEqualityComparer? eq /// The zero-based starting index of the range to reverse. /// The number of elements in the range to reverse. /// The reversed list. - [Pure] public ImmutableList Reverse(int index, int count) => this.Wrap(_root.Reverse(index, count)); /// /// Sorts the elements in the entire using /// the default comparer. /// - [Pure] public ImmutableList Sort() => this.Wrap(_root.Sort()); /// @@ -442,7 +423,6 @@ public ImmutableList Replace(T oldValue, T newValue, IEqualityComparer? eq /// /// The sorted list. /// is null. - [Pure] public ImmutableList Sort(Comparison comparison) { Requires.NotNull(comparison, nameof(comparison)); @@ -458,7 +438,6 @@ public ImmutableList Sort(Comparison comparison) /// elements, or null to use the default comparer . /// /// The sorted list. - [Pure] public ImmutableList Sort(IComparer? comparer) => this.Wrap(_root.Sort(comparer)); /// @@ -476,7 +455,6 @@ public ImmutableList Sort(Comparison comparison) /// elements, or null to use the default comparer . /// /// The sorted list. - [Pure] public ImmutableList Sort(int index, int count, IComparer? comparer) { Requires.Range(index >= 0, nameof(index)); @@ -765,7 +743,6 @@ public ImmutableList ConvertAll(Func converter) /// elements in the that starts at and /// contains number of elements, if found; otherwise, -1. /// - [Pure] public int IndexOf(T item, int index, int count, IEqualityComparer? equalityComparer) => _root.IndexOf(item, index, count, equalityComparer); /// @@ -788,7 +765,6 @@ public ImmutableList ConvertAll(Func converter) /// in the that contains number of elements /// and ends at , if found; otherwise, -1. /// - [Pure] public int LastIndexOf(T item, int index, int count, IEqualityComparer? equalityComparer) => _root.LastIndexOf(item, index, count, equalityComparer); /// @@ -1123,7 +1099,6 @@ T IList.this[int index] /// /// The root of the collection. /// The immutable sorted set instance. - [Pure] private static ImmutableList WrapNode(Node root) { return root.IsEmpty @@ -1176,7 +1151,6 @@ private static bool IsCompatibleObject(object? value) /// /// The root node to wrap. /// A wrapping collection type for the new tree. - [Pure] private ImmutableList Wrap(Node root) { if (root != _root) diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue.cs index 107fa536c11751..c54d5100a4b530 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -19,7 +18,6 @@ public static class ImmutableQueue /// /// The type of items stored by the collection. /// The immutable collection. - [Pure] public static ImmutableQueue Create() { return ImmutableQueue.Empty; @@ -31,7 +29,6 @@ public static ImmutableQueue Create() /// The type of items stored by the collection. /// The item to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableQueue Create(T item) => ImmutableQueue.Empty.Enqueue(item); /// @@ -40,7 +37,6 @@ public static ImmutableQueue Create() /// The type of items to store in the queue. /// The enumerable to copy items from. /// The new immutable queue. - [Pure] public static ImmutableQueue CreateRange(IEnumerable items) { Requires.NotNull(items, nameof(items)); @@ -76,7 +72,6 @@ public static ImmutableQueue CreateRange(IEnumerable items) /// The type of items to store in the queue. /// The array to copy items from. /// The new immutable queue. - [Pure] public static ImmutableQueue Create(params T[] items) { Requires.NotNull(items, nameof(items)); @@ -104,7 +99,6 @@ public static ImmutableQueue Create(params T[] items) /// Receives the value from the head of the queue. /// The new queue with the head element removed. /// Thrown when the stack is empty. - [Pure] public static IImmutableQueue Dequeue(this IImmutableQueue queue, out T value) { Requires.NotNull(queue, nameof(queue)); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue_1.cs index c0263bcec802bc..3c8a5be8d28903 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue_1.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Linq; namespace System.Collections.Immutable @@ -125,7 +124,6 @@ private ImmutableStack BackwardsReversed /// Gets the element at the front of the queue. /// /// Thrown when the queue is empty. - [Pure] public T Peek() { if (this.IsEmpty) @@ -141,7 +139,6 @@ public T Peek() /// Gets a read-only reference to the element at the front of the queue. /// /// Thrown when the queue is empty. - [Pure] public ref readonly T PeekRef() { if (this.IsEmpty) @@ -160,7 +157,6 @@ public ref readonly T PeekRef() /// /// The new queue. /// - [Pure] public ImmutableQueue Enqueue(T value) { if (this.IsEmpty) @@ -180,7 +176,6 @@ public ImmutableQueue Enqueue(T value) /// /// The new queue. /// - [Pure] IImmutableQueue IImmutableQueue.Enqueue(T value) { return this.Enqueue(value); @@ -191,7 +186,6 @@ IImmutableQueue IImmutableQueue.Enqueue(T value) /// /// A queue; never null. /// Thrown when the queue is empty. - [Pure] public ImmutableQueue Dequeue() { if (this.IsEmpty) @@ -220,7 +214,6 @@ public ImmutableQueue Dequeue() /// Receives the value from the head of the queue. /// The new queue with the head element removed. /// Thrown when the queue is empty. - [Pure] public ImmutableQueue Dequeue(out T value) { value = this.Peek(); @@ -232,7 +225,6 @@ public ImmutableQueue Dequeue(out T value) /// /// A queue; never null. /// Thrown when the queue is empty. - [Pure] IImmutableQueue IImmutableQueue.Dequeue() { return this.Dequeue(); @@ -244,7 +236,6 @@ IImmutableQueue IImmutableQueue.Dequeue() /// /// An that can be used to iterate through the collection. /// - [Pure] public Enumerator GetEnumerator() { return new Enumerator(this); @@ -256,7 +247,6 @@ public Enumerator GetEnumerator() /// /// A that can be used to iterate through the collection. /// - [Pure] IEnumerator IEnumerable.GetEnumerator() { return this.IsEmpty ? @@ -270,7 +260,6 @@ IEnumerator IEnumerable.GetEnumerator() /// /// An object that can be used to iterate through the collection. /// - [Pure] IEnumerator IEnumerable.GetEnumerator() { return new EnumeratorObject(this); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary.cs index 658c8299fdaf38..47009e77cec352 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Linq; namespace System.Collections.Immutable @@ -20,7 +19,6 @@ public static class ImmutableSortedDictionary /// The type of keys stored by the dictionary. /// The type of values stored by the dictionary. /// The immutable collection. - [Pure] public static ImmutableSortedDictionary Create() where TKey : notnull { return ImmutableSortedDictionary.Empty; @@ -33,7 +31,6 @@ public static ImmutableSortedDictionary Create() whe /// The type of values stored by the dictionary. /// The key comparer. /// The immutable collection. - [Pure] public static ImmutableSortedDictionary Create(IComparer? keyComparer) where TKey : notnull { return ImmutableSortedDictionary.Empty.WithComparers(keyComparer); @@ -47,7 +44,6 @@ public static ImmutableSortedDictionary Create(IComp /// The key comparer. /// The value comparer. /// The immutable collection. - [Pure] public static ImmutableSortedDictionary Create(IComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { return ImmutableSortedDictionary.Empty.WithComparers(keyComparer, valueComparer); @@ -60,7 +56,6 @@ public static ImmutableSortedDictionary Create(IComp /// The type of values stored by the dictionary. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableSortedDictionary CreateRange(IEnumerable> items) where TKey : notnull { return ImmutableSortedDictionary.Empty.AddRange(items); @@ -74,7 +69,6 @@ public static ImmutableSortedDictionary CreateRange( /// The key comparer. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableSortedDictionary CreateRange(IComparer? keyComparer, IEnumerable> items) where TKey : notnull { return ImmutableSortedDictionary.Empty.WithComparers(keyComparer).AddRange(items); @@ -89,7 +83,6 @@ public static ImmutableSortedDictionary CreateRange( /// The value comparer. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableSortedDictionary CreateRange(IComparer? keyComparer, IEqualityComparer? valueComparer, IEnumerable> items) where TKey : notnull { return ImmutableSortedDictionary.Empty.WithComparers(keyComparer, valueComparer).AddRange(items); @@ -101,7 +94,6 @@ public static ImmutableSortedDictionary CreateRange( /// The type of keys stored by the dictionary. /// The type of values stored by the dictionary. /// The immutable collection builder. - [Pure] public static ImmutableSortedDictionary.Builder CreateBuilder() where TKey : notnull { return Create().ToBuilder(); @@ -114,7 +106,6 @@ public static ImmutableSortedDictionary.Builder CreateBuilderThe type of values stored by the dictionary. /// The key comparer. /// The immutable collection builder. - [Pure] public static ImmutableSortedDictionary.Builder CreateBuilder(IComparer? keyComparer) where TKey : notnull { return Create(keyComparer).ToBuilder(); @@ -128,7 +119,6 @@ public static ImmutableSortedDictionary.Builder CreateBuilderThe key comparer. /// The value comparer. /// The immutable collection builder. - [Pure] public static ImmutableSortedDictionary.Builder CreateBuilder(IComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { return Create(keyComparer, valueComparer).ToBuilder(); @@ -146,7 +136,6 @@ public static ImmutableSortedDictionary.Builder CreateBuilderThe key comparer to use for the map. /// The value comparer to use for the map. /// The immutable map. - [Pure] public static ImmutableSortedDictionary ToImmutableSortedDictionary(this IEnumerable source, Func keySelector, Func elementSelector, IComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { Requires.NotNull(source, nameof(source)); @@ -162,7 +151,6 @@ public static ImmutableSortedDictionary ToImmutableSortedDictionar /// /// The builder to create the immutable map from. /// An immutable map. - [Pure] public static ImmutableSortedDictionary ToImmutableSortedDictionary(this ImmutableSortedDictionary.Builder builder) where TKey : notnull { Requires.NotNull(builder, nameof(builder)); @@ -181,7 +169,6 @@ public static ImmutableSortedDictionary ToImmutableSortedDictionar /// The function that will produce the value for the map from each sequence element. /// The key comparer to use for the map. /// The immutable map. - [Pure] public static ImmutableSortedDictionary ToImmutableSortedDictionary(this IEnumerable source, Func keySelector, Func elementSelector, IComparer? keyComparer) where TKey : notnull { return ToImmutableSortedDictionary(source, keySelector, elementSelector, keyComparer, null); @@ -197,7 +184,6 @@ public static ImmutableSortedDictionary ToImmutableSortedDictionar /// The function that will produce the key for the map from each sequence element. /// The function that will produce the value for the map from each sequence element. /// The immutable map. - [Pure] public static ImmutableSortedDictionary ToImmutableSortedDictionary(this IEnumerable source, Func keySelector, Func elementSelector) where TKey : notnull { return ToImmutableSortedDictionary(source, keySelector, elementSelector, null, null); @@ -212,7 +198,6 @@ public static ImmutableSortedDictionary ToImmutableSortedDictionar /// The key comparer to use when building the immutable map. /// The value comparer to use for the immutable map. /// An immutable map. - [Pure] public static ImmutableSortedDictionary ToImmutableSortedDictionary(this IEnumerable> source, IComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { Requires.NotNull(source, nameof(source)); @@ -234,7 +219,6 @@ public static ImmutableSortedDictionary ToImmutableSortedDictionar /// The sequence of key=value pairs. /// The key comparer to use when building the immutable map. /// An immutable map. - [Pure] public static ImmutableSortedDictionary ToImmutableSortedDictionary(this IEnumerable> source, IComparer? keyComparer) where TKey : notnull { return ToImmutableSortedDictionary(source, keyComparer, null); @@ -247,7 +231,6 @@ public static ImmutableSortedDictionary ToImmutableSortedDictionar /// The type of value in the map. /// The sequence of key=value pairs. /// An immutable map. - [Pure] public static ImmutableSortedDictionary ToImmutableSortedDictionary(this IEnumerable> source) where TKey : notnull { return ToImmutableSortedDictionary(source, null, null); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary_2.Builder.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary_2.Builder.cs index 03b403bb4d6d87..c72b8480420824 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary_2.Builder.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary_2.Builder.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -567,7 +566,6 @@ IEnumerator IEnumerable.GetEnumerator() /// true if the contains /// an element with the specified value; otherwise, false. /// - [Pure] public bool ContainsValue(TValue value) { return _root.ContainsValue(value, _valueComparer); @@ -606,7 +604,6 @@ public void RemoveRange(IEnumerable keys) /// /// The key to search for. /// The value for the key, or the default value for type if no matching key was found. - [Pure] [return: MaybeNull] public TValue GetValueOrDefault(TKey key) { @@ -621,7 +618,6 @@ public TValue GetValueOrDefault(TKey key) /// /// The value for the key, or if no matching key was found. /// - [Pure] public TValue GetValueOrDefault(TKey key, TValue defaultValue) { Requires.NotNullAllowStructs(key, nameof(key)); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary_2.Node.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary_2.Node.cs index 4872384c367188..7f579a3f9076f9 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary_2.Node.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary_2.Node.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Globalization; namespace System.Collections.Immutable @@ -270,7 +269,6 @@ internal void CopyTo(Array array, int arrayIndex, int dictionarySize) /// /// The collection. /// The root of the node tree. - [Pure] internal static Node NodeTreeFromSortedDictionary(SortedDictionary dictionary) { Requires.NotNull(dictionary, nameof(dictionary)); @@ -335,7 +333,6 @@ internal Node Remove(TKey key, IComparer keyComparer, out bool mutated) /// Returns a read-only reference to the value associated with the provided key. /// /// If the key is not present. - [Pure] internal ref readonly TValue ValueRef(TKey key, IComparer keyComparer) { Requires.NotNullAllowStructs(key, nameof(key)); @@ -358,7 +355,6 @@ internal ref readonly TValue ValueRef(TKey key, IComparer keyComparer) /// The key comparer. /// The value. /// True if the key was found. - [Pure] internal bool TryGetValue(TKey key, IComparer keyComparer, [MaybeNullWhen(false)] out TValue value) { Requires.NotNullAllowStructs(key, nameof(key)); @@ -390,7 +386,6 @@ internal bool TryGetValue(TKey key, IComparer keyComparer, [MaybeNullWhen( /// the canonical value, or a value that has more complete data than the value you currently have, /// although their comparer functions indicate they are equal. /// - [Pure] internal bool TryGetKey(TKey equalKey, IComparer keyComparer, out TKey actualKey) { Requires.NotNullAllowStructs(equalKey, nameof(equalKey)); @@ -417,7 +412,6 @@ internal bool TryGetKey(TKey equalKey, IComparer keyComparer, out TKey act /// /// true if the specified key contains key; otherwise, false. /// - [Pure] internal bool ContainsKey(TKey key, IComparer keyComparer) { Requires.NotNullAllowStructs(key, nameof(key)); @@ -438,7 +432,6 @@ internal bool ContainsKey(TKey key, IComparer keyComparer) /// true if the contains /// an element with the specified value; otherwise, false. /// - [Pure] internal bool ContainsValue(TValue value, IEqualityComparer valueComparer) { Requires.NotNull(valueComparer, nameof(valueComparer)); @@ -461,7 +454,6 @@ internal bool ContainsValue(TValue value, IEqualityComparer valueCompare /// /// true if [contains] [the specified pair]; otherwise, false. /// - [Pure] internal bool Contains(KeyValuePair pair, IComparer keyComparer, IEqualityComparer valueComparer) { Requires.NotNullAllowStructs(pair.Key, nameof(pair.Key)); @@ -574,7 +566,6 @@ private static Node DoubleRight(Node tree) /// /// The tree. /// 0 if the tree is in balance, a positive integer if the right side is heavy, or a negative integer if the left side is heavy. - [Pure] private static int Balance(Node tree) { Requires.NotNull(tree, nameof(tree)); @@ -590,7 +581,6 @@ private static int Balance(Node tree) /// /// true if [is right heavy] [the specified tree]; otherwise, false. /// - [Pure] private static bool IsRightHeavy(Node tree) { Requires.NotNull(tree, nameof(tree)); @@ -601,7 +591,6 @@ private static bool IsRightHeavy(Node tree) /// /// Determines whether the specified tree is left heavy. /// - [Pure] private static bool IsLeftHeavy(Node tree) { Requires.NotNull(tree, nameof(tree)); @@ -614,7 +603,6 @@ private static bool IsLeftHeavy(Node tree) /// /// The tree. /// A balanced tree. - [Pure] private static Node MakeBalanced(Node tree) { Requires.NotNull(tree, nameof(tree)); @@ -642,7 +630,6 @@ private static Node MakeBalanced(Node tree) /// The starting index within that should be captured by the node tree. /// The number of elements from that should be captured by the node tree. /// The root of the created node tree. - [Pure] private static Node NodeTreeFromList(IOrderedCollection> items, int start, int length) { Requires.NotNull(items, nameof(items)); @@ -839,7 +826,6 @@ private Node Mutate(Node? left = null, Node? right = null) /// /// The key. /// The key comparer. - [Pure] private Node Search(TKey key, IComparer keyComparer) { // Arg validation is too expensive for recursive methods. diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary_2.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary_2.cs index 50a582cae96579..bdfd5763222a70 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary_2.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedDictionary_2.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; @@ -243,7 +242,6 @@ TValue IDictionary.this[TKey key] /// This is an O(1) operation and results in only a single (small) memory allocation. /// The mutable collection that is returned is *not* thread-safe. /// - [Pure] public Builder ToBuilder() { // We must not cache the instance created here and return it to various callers. @@ -255,7 +253,6 @@ public Builder ToBuilder() /// /// See the interface. /// - [Pure] public ImmutableSortedDictionary Add(TKey key, TValue value) { Requires.NotNullAllowStructs(key, nameof(key)); @@ -267,7 +264,6 @@ public ImmutableSortedDictionary Add(TKey key, TValue value) /// /// See the interface. /// - [Pure] public ImmutableSortedDictionary SetItem(TKey key, TValue value) { Requires.NotNullAllowStructs(key, nameof(key)); @@ -281,7 +277,6 @@ public ImmutableSortedDictionary SetItem(TKey key, TValue value) /// /// The key=value pairs to set on the map. Any keys that conflict with existing keys will overwrite the previous values. /// An immutable dictionary. - [Pure] public ImmutableSortedDictionary SetItems(IEnumerable> items) { Requires.NotNull(items, nameof(items)); @@ -292,7 +287,6 @@ public ImmutableSortedDictionary SetItems(IEnumerable /// See the interface. /// - [Pure] public ImmutableSortedDictionary AddRange(IEnumerable> items) { Requires.NotNull(items, nameof(items)); @@ -303,7 +297,6 @@ public ImmutableSortedDictionary AddRange(IEnumerable /// See the interface. /// - [Pure] public ImmutableSortedDictionary Remove(TKey value) { Requires.NotNullAllowStructs(value, nameof(value)); @@ -315,7 +308,6 @@ public ImmutableSortedDictionary Remove(TKey value) /// /// See the interface. /// - [Pure] public ImmutableSortedDictionary RemoveRange(IEnumerable keys) { Requires.NotNull(keys, nameof(keys)); @@ -339,7 +331,6 @@ public ImmutableSortedDictionary RemoveRange(IEnumerable key /// /// See the interface. /// - [Pure] public ImmutableSortedDictionary WithComparers(IComparer? keyComparer, IEqualityComparer? valueComparer) { if (keyComparer == null) @@ -378,7 +369,6 @@ public ImmutableSortedDictionary WithComparers(IComparer? ke /// /// See the interface. /// - [Pure] public ImmutableSortedDictionary WithComparers(IComparer? keyComparer) { return this.WithComparers(keyComparer, _valueComparer); @@ -396,7 +386,6 @@ public ImmutableSortedDictionary WithComparers(IComparer? ke /// true if the contains /// an element with the specified value; otherwise, false. /// - [Pure] public bool ContainsValue(TValue value) { return _root.ContainsValue(value, _valueComparer); @@ -774,7 +763,6 @@ public Enumerator GetEnumerator() /// The key comparer to use for the map. /// The value comparer to use for the map. /// The immutable sorted set instance. - [Pure] private static ImmutableSortedDictionary Wrap(Node root, int count, IComparer keyComparer, IEqualityComparer valueComparer) { return root.IsEmpty @@ -812,7 +800,6 @@ private static bool TryCastToImmutableMap(IEnumerable /// The entries to add. /// true to allow the sequence to include duplicate keys and let the last one win; false to throw on collisions. /// true when being called from to avoid a stack overflow. - [Pure] private ImmutableSortedDictionary AddRange(IEnumerable> items, bool overwriteOnCollision, bool avoidToSortedMap) { Requires.NotNull(items, nameof(items)); @@ -853,7 +840,6 @@ private ImmutableSortedDictionary AddRange(IEnumerableThe root node to wrap. /// The number of elements in the new tree, assuming it's different from the current tree. /// A wrapping collection type for the new tree. - [Pure] private ImmutableSortedDictionary Wrap(Node root, int adjustedCountIfDifferentRoot) { if (_root != root) @@ -869,7 +855,6 @@ private ImmutableSortedDictionary Wrap(Node root, int adjustedCoun /// /// Efficiently creates a new collection based on the contents of some sequence. /// - [Pure] private ImmutableSortedDictionary FillFromEmpty(IEnumerable> items, bool overwriteOnCollision) { Debug.Assert(this.IsEmpty); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet.cs index 7bf8d4fa89dca5..530b4a3fa8a193 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -17,7 +16,6 @@ public static class ImmutableSortedSet /// /// The type of items stored by the collection. /// The immutable collection. - [Pure] public static ImmutableSortedSet Create() { return ImmutableSortedSet.Empty; @@ -31,7 +29,6 @@ public static ImmutableSortedSet Create() /// /// The immutable collection. /// - [Pure] public static ImmutableSortedSet Create(IComparer? comparer) { return ImmutableSortedSet.Empty.WithComparer(comparer); @@ -43,7 +40,6 @@ public static ImmutableSortedSet Create(IComparer? comparer) /// The type of items stored by the collection. /// The item to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableSortedSet Create(T item) { return ImmutableSortedSet.Empty.Add(item); @@ -56,7 +52,6 @@ public static ImmutableSortedSet Create(T item) /// The comparer. /// The item to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableSortedSet Create(IComparer? comparer, T item) { return ImmutableSortedSet.Empty.WithComparer(comparer).Add(item); @@ -68,7 +63,6 @@ public static ImmutableSortedSet Create(IComparer? comparer, T item) /// The type of items stored by the collection. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableSortedSet CreateRange(IEnumerable items) { return ImmutableSortedSet.Empty.Union(items); @@ -81,7 +75,6 @@ public static ImmutableSortedSet CreateRange(IEnumerable items) /// The comparer. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableSortedSet CreateRange(IComparer? comparer, IEnumerable items) { return ImmutableSortedSet.Empty.WithComparer(comparer).Union(items); @@ -93,7 +86,6 @@ public static ImmutableSortedSet CreateRange(IComparer? comparer, IEnum /// The type of items stored by the collection. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableSortedSet Create(params T[] items) { return ImmutableSortedSet.Empty.Union(items); @@ -106,7 +98,6 @@ public static ImmutableSortedSet Create(params T[] items) /// The comparer. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableSortedSet Create(IComparer? comparer, params T[] items) { return ImmutableSortedSet.Empty.WithComparer(comparer).Union(items); @@ -117,7 +108,6 @@ public static ImmutableSortedSet Create(IComparer? comparer, params T[] /// /// The type of items stored by the collection. /// The immutable collection. - [Pure] public static ImmutableSortedSet.Builder CreateBuilder() { return Create().ToBuilder(); @@ -131,7 +121,6 @@ public static ImmutableSortedSet.Builder CreateBuilder() /// /// The immutable collection. /// - [Pure] public static ImmutableSortedSet.Builder CreateBuilder(IComparer? comparer) { return Create(comparer).ToBuilder(); @@ -144,7 +133,6 @@ public static ImmutableSortedSet.Builder CreateBuilder(IComparer? compa /// The sequence to enumerate. /// The comparer to use for initializing and adding members to the sorted set. /// An immutable set. - [Pure] public static ImmutableSortedSet ToImmutableSortedSet(this IEnumerable source, IComparer? comparer) { if (source is ImmutableSortedSet existingSet) @@ -161,7 +149,6 @@ public static ImmutableSortedSet ToImmutableSortedSet(this IEn /// The type of element in the sequence. /// The sequence to enumerate. /// An immutable set. - [Pure] public static ImmutableSortedSet ToImmutableSortedSet(this IEnumerable source) { return ToImmutableSortedSet(source, null); @@ -172,7 +159,6 @@ public static ImmutableSortedSet ToImmutableSortedSet(this IEn /// /// The builder to create the immutable set from. /// An immutable set. - [Pure] public static ImmutableSortedSet ToImmutableSortedSet(this ImmutableSortedSet.Builder builder) { Requires.NotNull(builder, nameof(builder)); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.Builder.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.Builder.cs index 14803f12dd49e5..6c7b9ea72f8361 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.Builder.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.Builder.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -431,7 +430,6 @@ IEnumerator IEnumerable.GetEnumerator() /// An enumerator that iterates over the /// in reverse order. /// - [Pure] public IEnumerable Reverse() { return new ReverseEnumerable(_root); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.Node.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.Node.cs index c08056e004e370..2f4ca2fb4f78f4 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.Node.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.Node.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -492,7 +491,6 @@ internal Node Remove(T key, IComparer comparer, out bool mutated) /// /// true if the tree contains the specified key; otherwise, false. /// - [Pure] internal bool Contains(T key, IComparer comparer) { Requires.NotNull(comparer, nameof(comparer)); @@ -520,7 +518,6 @@ internal void Freeze() /// The key to search for. /// The comparer. /// The matching node, or if no match was found. - [Pure] internal Node Search(T key, IComparer comparer) { Requires.NotNull(comparer, nameof(comparer)); @@ -553,7 +550,6 @@ internal Node Search(T key, IComparer comparer) /// The key to search for. /// The comparer. /// The matching node, or if no match was found. - [Pure] internal int IndexOf(T key, IComparer comparer) { Requires.NotNull(comparer, nameof(comparer)); @@ -602,7 +598,6 @@ internal int IndexOf(T key, IComparer comparer) /// An enumerator that iterates over the /// in reverse order. /// - [Pure] internal IEnumerator Reverse() { return new Enumerator(this, reverse: true); @@ -691,7 +686,6 @@ private static Node DoubleRight(Node tree) /// /// The tree. /// 0 if the tree is in balance, a positive integer if the right side is heavy, or a negative integer if the left side is heavy. - [Pure] private static int Balance(Node tree) { Requires.NotNull(tree, nameof(tree)); @@ -707,7 +701,6 @@ private static int Balance(Node tree) /// /// true if [is right heavy] [the specified tree]; otherwise, false. /// - [Pure] private static bool IsRightHeavy(Node tree) { Requires.NotNull(tree, nameof(tree)); @@ -718,7 +711,6 @@ private static bool IsRightHeavy(Node tree) /// /// Determines whether the specified tree is left heavy. /// - [Pure] private static bool IsLeftHeavy(Node tree) { Requires.NotNull(tree, nameof(tree)); @@ -731,7 +723,6 @@ private static bool IsLeftHeavy(Node tree) /// /// The tree. /// A balanced tree. - [Pure] private static Node MakeBalanced(Node tree) { Requires.NotNull(tree, nameof(tree)); @@ -759,7 +750,6 @@ private static Node MakeBalanced(Node tree) /// The starting index within that should be captured by the node tree. /// The number of elements from that should be captured by the node tree. /// The root of the created node tree. - [Pure] internal static Node NodeTreeFromList(IOrderedCollection items, int start, int length) { Requires.NotNull(items, nameof(items)); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs index ce7eea29da5f8f..460aaf118bfb6f 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableSortedSet_1.cs @@ -6,7 +6,6 @@ using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Linq; namespace System.Collections.Immutable @@ -186,7 +185,6 @@ public ref readonly T ItemRef(int index) /// This is an O(1) operation and results in only a single (small) memory allocation. /// The mutable collection that is returned is *not* thread-safe. /// - [Pure] public Builder ToBuilder() { // We must not cache the instance created here and return it to various callers. @@ -198,7 +196,6 @@ public Builder ToBuilder() /// /// See the interface. /// - [Pure] public ImmutableSortedSet Add(T value) { bool mutated; @@ -208,7 +205,6 @@ public ImmutableSortedSet Add(T value) /// /// See the interface. /// - [Pure] public ImmutableSortedSet Remove(T value) { bool mutated; @@ -227,7 +223,6 @@ public ImmutableSortedSet Remove(T value) /// a value that has more complete data than the value you currently have, although their /// comparer functions indicate they are equal. /// - [Pure] public bool TryGetValue(T equalValue, out T actualValue) { Node searchResult = _root.Search(equalValue, _comparer); @@ -246,7 +241,6 @@ public bool TryGetValue(T equalValue, out T actualValue) /// /// See the interface. /// - [Pure] public ImmutableSortedSet Intersect(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -267,7 +261,6 @@ public ImmutableSortedSet Intersect(IEnumerable other) /// /// See the interface. /// - [Pure] public ImmutableSortedSet Except(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -287,7 +280,6 @@ public ImmutableSortedSet Except(IEnumerable other) /// /// The other sequence of items. /// The new set. - [Pure] public ImmutableSortedSet SymmetricExcept(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -317,7 +309,6 @@ public ImmutableSortedSet SymmetricExcept(IEnumerable other) /// /// See the interface. /// - [Pure] public ImmutableSortedSet Union(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -358,7 +349,6 @@ public ImmutableSortedSet Union(IEnumerable other) /// /// See the interface. /// - [Pure] public ImmutableSortedSet WithComparer(IComparer? comparer) { if (comparer == null) @@ -384,7 +374,6 @@ public ImmutableSortedSet WithComparer(IComparer? comparer) /// /// The sequence of items to check against this set. /// A value indicating whether the sets are equal. - [Pure] public bool SetEquals(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -419,7 +408,6 @@ public bool SetEquals(IEnumerable other) /// /// The collection to compare to the current set. /// true if the current set is a correct subset of other; otherwise, false. - [Pure] public bool IsProperSubsetOf(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -470,7 +458,6 @@ public bool IsProperSubsetOf(IEnumerable other) /// /// The collection to compare to the current set. /// true if the current set is a correct superset of other; otherwise, false. - [Pure] public bool IsProperSupersetOf(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -498,7 +485,6 @@ public bool IsProperSupersetOf(IEnumerable other) /// /// The collection to compare to the current set. /// true if the current set is a subset of other; otherwise, false. - [Pure] public bool IsSubsetOf(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -534,7 +520,6 @@ public bool IsSubsetOf(IEnumerable other) /// /// The collection to compare to the current set. /// true if the current set is a superset of other; otherwise, false. - [Pure] public bool IsSupersetOf(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -555,7 +540,6 @@ public bool IsSupersetOf(IEnumerable other) /// /// The collection to compare to the current set. /// true if the current set and other share at least one common element; otherwise, false. - [Pure] public bool Overlaps(IEnumerable other) { Requires.NotNull(other, nameof(other)); @@ -584,7 +568,6 @@ public bool Overlaps(IEnumerable other) /// An enumerator that iterates over the /// in reverse order. /// - [Pure] public IEnumerable Reverse() { return new ReverseEnumerable(_root); @@ -1042,7 +1025,6 @@ private static bool TryCastToImmutableSortedSet(IEnumerable sequence, [NotNul /// The root of the collection. /// The comparer used to build the tree. /// The immutable sorted set instance. - [Pure] private static ImmutableSortedSet Wrap(Node root, IComparer comparer) { return root.IsEmpty @@ -1061,7 +1043,6 @@ private static ImmutableSortedSet Wrap(Node root, IComparer comparer) /// It's performance is optimal for additions that do not significantly dwarf the existing /// size of this collection. /// - [Pure] private ImmutableSortedSet UnionIncremental(IEnumerable items) { Requires.NotNull(items, nameof(items)); @@ -1083,7 +1064,6 @@ private ImmutableSortedSet UnionIncremental(IEnumerable items) /// /// The root node to wrap. /// A wrapping collection type for the new tree. - [Pure] private ImmutableSortedSet Wrap(Node root) { if (root != _root) @@ -1101,7 +1081,6 @@ private ImmutableSortedSet Wrap(Node root) /// /// The sequence of elements to add to this set. /// The immutable sorted set. - [Pure] private ImmutableSortedSet LeafToRootRefill(IEnumerable addedItems) { Requires.NotNull(addedItems, nameof(addedItems)); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack.cs index 91cc379b79d460..827ac72fda5946 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; namespace System.Collections.Immutable { @@ -18,7 +17,6 @@ public static class ImmutableStack /// /// The type of items stored by the collection. /// The immutable collection. - [Pure] public static ImmutableStack Create() { return ImmutableStack.Empty; @@ -30,7 +28,6 @@ public static ImmutableStack Create() /// The type of items stored by the collection. /// The item to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableStack Create(T item) { return ImmutableStack.Empty.Push(item); @@ -42,7 +39,6 @@ public static ImmutableStack Create(T item) /// The type of items stored by the collection. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableStack CreateRange(IEnumerable items) { Requires.NotNull(items, nameof(items)); @@ -62,7 +58,6 @@ public static ImmutableStack CreateRange(IEnumerable items) /// The type of items stored by the collection. /// The items to prepopulate. /// The new immutable collection. - [Pure] public static ImmutableStack Create(params T[] items) { Requires.NotNull(items, nameof(items)); @@ -86,7 +81,6 @@ public static ImmutableStack Create(params T[] items) /// A stack; never null /// /// Thrown when the stack is empty. - [Pure] public static IImmutableStack Pop(this IImmutableStack stack, out T value) { Requires.NotNull(stack, nameof(stack)); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack_1.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack_1.cs index a6d0c1d8e22a1e..e2ca1d61368c4d 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack_1.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableStack_1.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Linq; namespace System.Collections.Immutable @@ -105,7 +104,6 @@ public bool IsEmpty /// The element on the top of the stack. /// /// Thrown when the stack is empty. - [Pure] public T Peek() { if (this.IsEmpty) @@ -124,7 +122,6 @@ public T Peek() /// A read-only reference to the element on the top of the stack. /// /// Thrown when the stack is empty. - [Pure] public ref readonly T PeekRef() { if (this.IsEmpty) @@ -141,7 +138,6 @@ public ref readonly T PeekRef() /// /// The element to push onto the stack. /// The new stack. - [Pure] public ImmutableStack Push(T value) { return new ImmutableStack(value, this); @@ -152,7 +148,6 @@ public ImmutableStack Push(T value) /// /// The element to push onto the stack. /// The new stack. - [Pure] IImmutableStack IImmutableStack.Push(T value) { return this.Push(value); @@ -163,7 +158,6 @@ IImmutableStack IImmutableStack.Push(T value) /// /// A stack; never null /// Thrown when the stack is empty. - [Pure] public ImmutableStack Pop() { if (this.IsEmpty) @@ -182,7 +176,6 @@ public ImmutableStack Pop() /// /// A stack; never null /// - [Pure] public ImmutableStack Pop(out T value) { value = this.Peek(); @@ -194,7 +187,6 @@ public ImmutableStack Pop(out T value) /// /// A stack; never null /// Thrown when the stack is empty. - [Pure] IImmutableStack IImmutableStack.Pop() { return this.Pop(); @@ -206,7 +198,6 @@ IImmutableStack IImmutableStack.Pop() /// /// An that can be used to iterate through the collection. /// - [Pure] public Enumerator GetEnumerator() { return new Enumerator(this); @@ -218,7 +209,6 @@ public Enumerator GetEnumerator() /// /// A that can be used to iterate through the collection. /// - [Pure] IEnumerator IEnumerable.GetEnumerator() { return this.IsEmpty ? @@ -232,7 +222,6 @@ IEnumerator IEnumerable.GetEnumerator() /// /// An object that can be used to iterate through the collection. /// - [Pure] IEnumerator IEnumerable.GetEnumerator() { return new EnumeratorObject(this); @@ -242,7 +231,6 @@ IEnumerator IEnumerable.GetEnumerator() /// Reverses the order of a stack. /// /// The reversed stack. - [Pure] internal ImmutableStack Reverse() { var r = this.Clear(); diff --git a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/SortedInt32KeyNode.cs b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/SortedInt32KeyNode.cs index 8161a231c45197..61cbaf15bafac2 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/SortedInt32KeyNode.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/SortedInt32KeyNode.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; using System.Globalization; namespace System.Collections.Immutable @@ -199,7 +198,6 @@ internal SortedInt32KeyNode Remove(int key, out bool mutated) /// /// The key. /// The value. - [Pure] [return: MaybeNull] internal TValue GetValueOrDefault(int key) { @@ -233,7 +231,6 @@ internal TValue GetValueOrDefault(int key) /// The key. /// The value. /// True if the key was found. - [Pure] internal bool TryGetValue(int key, [MaybeNullWhen(false)] out TValue value) { SortedInt32KeyNode node = this; @@ -359,7 +356,6 @@ private static SortedInt32KeyNode DoubleRight(SortedInt32KeyNode /// /// The tree. /// 0 if the tree is in balance, a positive integer if the right side is heavy, or a negative integer if the left side is heavy. - [Pure] private static int Balance(SortedInt32KeyNode tree) { Requires.NotNull(tree, nameof(tree)); @@ -375,7 +371,6 @@ private static int Balance(SortedInt32KeyNode tree) /// /// true if [is right heavy] [the specified tree]; otherwise, false. /// - [Pure] private static bool IsRightHeavy(SortedInt32KeyNode tree) { Requires.NotNull(tree, nameof(tree)); @@ -386,7 +381,6 @@ private static bool IsRightHeavy(SortedInt32KeyNode tree) /// /// Determines whether the specified tree is left heavy. /// - [Pure] private static bool IsLeftHeavy(SortedInt32KeyNode tree) { Requires.NotNull(tree, nameof(tree)); @@ -399,7 +393,6 @@ private static bool IsLeftHeavy(SortedInt32KeyNode tree) /// /// The tree. /// A balanced tree. - [Pure] private static SortedInt32KeyNode MakeBalanced(SortedInt32KeyNode tree) { Requires.NotNull(tree, nameof(tree)); diff --git a/src/libraries/System.Collections.Immutable/src/System/Linq/ImmutableArrayExtensions.cs b/src/libraries/System.Collections.Immutable/src/System/Linq/ImmutableArrayExtensions.cs index b18731702faf07..19832f407b1868 100644 --- a/src/libraries/System.Collections.Immutable/src/System/Linq/ImmutableArrayExtensions.cs +++ b/src/libraries/System.Collections.Immutable/src/System/Linq/ImmutableArrayExtensions.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics.Contracts; namespace System.Linq { @@ -23,7 +22,6 @@ public static class ImmutableArrayExtensions /// The type of the result element. /// The immutable array. /// The selector. - [Pure] public static IEnumerable Select(this ImmutableArray immutableArray, Func selector) { immutableArray.ThrowNullRefIfNotInitialized(); @@ -51,7 +49,6 @@ public static IEnumerable Select(this ImmutableArray imm /// element of and then mapping each of those sequence elements and their /// corresponding source element to a result element. /// - [Pure] public static IEnumerable SelectMany( this ImmutableArray immutableArray, Func> collectionSelector, @@ -83,7 +80,6 @@ public static IEnumerable SelectMany( /// Filters a sequence of values based on a predicate. /// /// The type of element contained by the collection. - [Pure] public static IEnumerable Where(this ImmutableArray immutableArray, Func predicate) { immutableArray.ThrowNullRefIfNotInitialized(); @@ -99,7 +95,6 @@ public static IEnumerable Where(this ImmutableArray immutableArray, Fun /// /// The type of element contained by the collection. /// - [Pure] public static bool Any(this ImmutableArray immutableArray) { return immutableArray.Length > 0; @@ -112,7 +107,6 @@ public static bool Any(this ImmutableArray immutableArray) /// The type of element contained by the collection. /// /// The predicate. - [Pure] public static bool Any(this ImmutableArray immutableArray, Func predicate) { immutableArray.ThrowNullRefIfNotInitialized(); @@ -139,7 +133,6 @@ public static bool Any(this ImmutableArray immutableArray, Func p /// /// true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false. /// - [Pure] public static bool All(this ImmutableArray immutableArray, Func predicate) { immutableArray.ThrowNullRefIfNotInitialized(); @@ -161,7 +154,6 @@ public static bool All(this ImmutableArray immutableArray, Func p /// /// The type of element in the compared array. /// The type of element contained by the collection. - [Pure] public static bool SequenceEqual(this ImmutableArray immutableArray, ImmutableArray items, IEqualityComparer? comparer = null) where TDerived : TBase { immutableArray.ThrowNullRefIfNotInitialized(); @@ -197,7 +189,6 @@ public static bool SequenceEqual(this ImmutableArray imm /// /// The type of element in the compared array. /// The type of element contained by the collection. - [Pure] public static bool SequenceEqual(this ImmutableArray immutableArray, IEnumerable items, IEqualityComparer? comparer = null) where TDerived : TBase { Requires.NotNull(items, nameof(items)); @@ -232,7 +223,6 @@ public static bool SequenceEqual(this ImmutableArray imm /// /// The type of element in the compared array. /// The type of element contained by the collection. - [Pure] public static bool SequenceEqual(this ImmutableArray immutableArray, ImmutableArray items, Func predicate) where TDerived : TBase { Requires.NotNull(predicate, nameof(predicate)); @@ -264,7 +254,6 @@ public static bool SequenceEqual(this ImmutableArray imm /// Applies an accumulator function over a sequence. /// /// The type of element contained by the collection. - [Pure] [return: MaybeNull] public static T Aggregate(this ImmutableArray immutableArray, Func func) { @@ -289,7 +278,6 @@ public static T Aggregate(this ImmutableArray immutableArray, Func /// The type of the accumulated value. /// The type of element contained by the collection. - [Pure] public static TAccumulate Aggregate(this ImmutableArray immutableArray, TAccumulate seed, Func func) { Requires.NotNull(func, nameof(func)); @@ -309,7 +297,6 @@ public static TAccumulate Aggregate(this ImmutableArray immut /// The type of the accumulated value. /// The type of result returned by the result selector. /// The type of element contained by the collection. - [Pure] public static TResult Aggregate(this ImmutableArray immutableArray, TAccumulate seed, Func func, Func resultSelector) { Requires.NotNull(resultSelector, nameof(resultSelector)); @@ -321,7 +308,6 @@ public static TResult Aggregate(this ImmutableArray /// Returns the element at a specified index in a sequence. /// /// The type of element contained by the collection. - [Pure] public static T ElementAt(this ImmutableArray immutableArray, int index) { return immutableArray[index]; @@ -331,7 +317,6 @@ public static T ElementAt(this ImmutableArray immutableArray, int index) /// Returns the element at a specified index in a sequence or a default value if the index is out of range. /// /// The type of element contained by the collection. - [Pure] [return: MaybeNull] public static T ElementAtOrDefault(this ImmutableArray immutableArray, int index) { @@ -347,7 +332,6 @@ public static T ElementAtOrDefault(this ImmutableArray immutableArray, int /// Returns the first element in a sequence that satisfies a specified condition. /// /// The type of element contained by the collection. - [Pure] public static T First(this ImmutableArray immutableArray, Func predicate) { Requires.NotNull(predicate, nameof(predicate)); @@ -369,7 +353,6 @@ public static T First(this ImmutableArray immutableArray, Func pr /// /// The type of element contained by the collection. /// - [Pure] public static T First(this ImmutableArray immutableArray) { @@ -385,7 +368,6 @@ public static T First(this ImmutableArray immutableArray) /// /// The type of element contained by the collection. /// - [Pure] [return: MaybeNull] public static T FirstOrDefault(this ImmutableArray immutableArray) { @@ -396,7 +378,6 @@ public static T FirstOrDefault(this ImmutableArray immutableArray) /// Returns the first element of the sequence that satisfies a condition or a default value if no such element is found. /// /// The type of element contained by the collection. - [Pure] [return: MaybeNull] public static T FirstOrDefault(this ImmutableArray immutableArray, Func predicate) { @@ -418,7 +399,6 @@ public static T FirstOrDefault(this ImmutableArray immutableArray, Func /// The type of element contained by the collection. /// - [Pure] public static T Last(this ImmutableArray immutableArray) { // In the event of an empty array, generate the same exception @@ -432,7 +412,6 @@ public static T Last(this ImmutableArray immutableArray) /// Returns the last element of a sequence that satisfies a specified condition. /// /// The type of element contained by the collection. - [Pure] public static T Last(this ImmutableArray immutableArray, Func predicate) { Requires.NotNull(predicate, nameof(predicate)); @@ -454,7 +433,6 @@ public static T Last(this ImmutableArray immutableArray, Func pre /// /// The type of element contained by the collection. /// - [Pure] [return: MaybeNull] public static T LastOrDefault(this ImmutableArray immutableArray) { @@ -466,7 +444,6 @@ public static T LastOrDefault(this ImmutableArray immutableArray) /// Returns the last element of a sequence that satisfies a condition or a default value if no such element is found. /// /// The type of element contained by the collection. - [Pure] [return: MaybeNull] public static T LastOrDefault(this ImmutableArray immutableArray, Func predicate) { @@ -488,7 +465,6 @@ public static T LastOrDefault(this ImmutableArray immutableArray, Func /// The type of element contained by the collection. /// - [Pure] public static T Single(this ImmutableArray immutableArray) { immutableArray.ThrowNullRefIfNotInitialized(); @@ -499,7 +475,6 @@ public static T Single(this ImmutableArray immutableArray) /// Returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists. /// /// The type of element contained by the collection. - [Pure] public static T Single(this ImmutableArray immutableArray, Func predicate) { Requires.NotNull(predicate, nameof(predicate)); @@ -533,7 +508,6 @@ public static T Single(this ImmutableArray immutableArray, Func p /// /// The type of element contained by the collection. /// - [Pure] [return: MaybeNull] public static T SingleOrDefault(this ImmutableArray immutableArray) { @@ -545,7 +519,6 @@ public static T SingleOrDefault(this ImmutableArray immutableArray) /// Returns the only element of a sequence that satisfies a specified condition or a default value if no such element exists; this method throws an exception if more than one element satisfies the condition. /// /// The type of element contained by the collection. - [Pure] [return: MaybeNull] public static T SingleOrDefault(this ImmutableArray immutableArray, Func predicate) { @@ -578,7 +551,6 @@ public static T SingleOrDefault(this ImmutableArray immutableArray, Func /// The key selector. /// The newly initialized dictionary. - [Pure] public static Dictionary ToDictionary(this ImmutableArray immutableArray, Func keySelector) where TKey : notnull { return ToDictionary(immutableArray, keySelector, EqualityComparer.Default); @@ -594,7 +566,6 @@ public static Dictionary ToDictionary(this ImmutableArray i /// The key selector. /// The element selector. /// The newly initialized dictionary. - [Pure] public static Dictionary ToDictionary(this ImmutableArray immutableArray, Func keySelector, Func elementSelector) where TKey : notnull { return ToDictionary(immutableArray, keySelector, elementSelector, EqualityComparer.Default); @@ -609,7 +580,6 @@ public static Dictionary ToDictionary(this Im /// The key selector. /// The comparer to initialize the dictionary with. /// The newly initialized dictionary. - [Pure] public static Dictionary ToDictionary(this ImmutableArray immutableArray, Func keySelector, IEqualityComparer? comparer) where TKey : notnull { Requires.NotNull(keySelector, nameof(keySelector)); @@ -634,7 +604,6 @@ public static Dictionary ToDictionary(this ImmutableArray i /// The element selector. /// The comparer to initialize the dictionary with. /// The newly initialized dictionary. - [Pure] public static Dictionary ToDictionary(this ImmutableArray immutableArray, Func keySelector, Func elementSelector, IEqualityComparer? comparer) where TKey : notnull { Requires.NotNull(keySelector, nameof(keySelector)); @@ -655,7 +624,6 @@ public static Dictionary ToDictionary(this Im /// The type of element contained by the collection. /// /// The newly instantiated array. - [Pure] public static T[] ToArray(this ImmutableArray immutableArray) { immutableArray.ThrowNullRefIfNotInitialized(); @@ -675,7 +643,6 @@ public static T[] ToArray(this ImmutableArray immutableArray) /// Returns the first element in the collection. /// /// Thrown if the collection is empty. - [Pure] public static T First(this ImmutableArray.Builder builder) { Requires.NotNull(builder, nameof(builder)); @@ -691,7 +658,6 @@ public static T First(this ImmutableArray.Builder builder) /// /// Returns the first element in the collection, or the default value if the collection is empty. /// - [Pure] [return: MaybeNull] public static T FirstOrDefault(this ImmutableArray.Builder builder) { @@ -704,7 +670,6 @@ public static T FirstOrDefault(this ImmutableArray.Builder builder) /// Returns the last element in the collection. /// /// Thrown if the collection is empty. - [Pure] public static T Last(this ImmutableArray.Builder builder) { Requires.NotNull(builder, nameof(builder)); @@ -720,7 +685,6 @@ public static T Last(this ImmutableArray.Builder builder) /// /// Returns the last element in the collection, or the default value if the collection is empty. /// - [Pure] [return: MaybeNull] public static T LastOrDefault(this ImmutableArray.Builder builder) { @@ -732,7 +696,6 @@ public static T LastOrDefault(this ImmutableArray.Builder builder) /// /// Returns a value indicating whether this collection contains any elements. /// - [Pure] public static bool Any(this ImmutableArray.Builder builder) { Requires.NotNull(builder, nameof(builder)); diff --git a/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj b/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj index e1b74ff9bd5154..f5130bcc181d61 100644 --- a/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj +++ b/src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj @@ -4,9 +4,8 @@ $(NetCoreAppCurrent);$(NetFrameworkCurrent) - - Common\System\Collections\DictionaryExtensions.cs - + @@ -32,70 +31,51 @@ - - Common\System\Diagnostics\DebuggerAttributes.cs - - - Common\System\ShouldNotBeInvokedException.cs - + + - - Common\System\Collections\CollectionAsserts.cs - - - Common\System\Collections\DelegateEqualityComparer.cs - - - Common\System\Collections\ICollection.NonGeneric.Tests.cs - - - Common\System\Collections\ICollection.Generic.Tests.cs - - - Common\System\Collections\IDictionary.NonGeneric.Tests.cs - - - Common\System\Collections\IDictionary.Generic.Tests.cs - - - Common\System\Collections\IEnumerable.NonGeneric.Tests.cs - - - Common\System\Collections\IEnumerable.Generic.Tests.cs - - - Common\System\Collections\IList.NonGeneric.Tests.cs - - - Common\System\Collections\IList.Generic.Tests.cs - - - Common\System\Collections\IGenericSharedAPI.Tests.cs - - - Common\System\Collections\ISet.Generic.Tests.cs - - - Common\System\Collections\TestBase.NonGeneric.Tests.cs - - - Common\System\Collections\TestBase.Generic.Tests.cs - - - Common\System\Collections\DebugView.Tests.cs - - - Common\System\Collections\TestingTypes.cs - - - Common\System\SerializableAttribute.cs - + + + + + + + + + + + + + + + + + - + @@ -116,4 +96,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Collections.NonGeneric/src/System.Collections.NonGeneric.csproj b/src/libraries/System.Collections.NonGeneric/src/System.Collections.NonGeneric.csproj index 2e6adcbba08cf8..9ec5c3a1eb93ad 100644 --- a/src/libraries/System.Collections.NonGeneric/src/System.Collections.NonGeneric.csproj +++ b/src/libraries/System.Collections.NonGeneric/src/System.Collections.NonGeneric.csproj @@ -16,9 +16,8 @@ - - Common\System\Collections\KeyValuePairs.cs - + diff --git a/src/libraries/System.Collections.NonGeneric/tests/System.Collections.NonGeneric.Tests.csproj b/src/libraries/System.Collections.NonGeneric/tests/System.Collections.NonGeneric.Tests.csproj index f5e98bb5275246..a7c767971ce90f 100644 --- a/src/libraries/System.Collections.NonGeneric/tests/System.Collections.NonGeneric.Tests.csproj +++ b/src/libraries/System.Collections.NonGeneric/tests/System.Collections.NonGeneric.Tests.csproj @@ -5,27 +5,20 @@ - - Common\System\Collections\ICollection.NonGeneric.Tests.cs - - - Common\System\Collections\IDictionary.NonGeneric.Tests.cs - - - Common\System\Collections\IEnumerable.NonGeneric.Tests.cs - - - Common\System\Collections\IList.NonGeneric.Tests.cs - - - Common\System\Collections\TestBase.NonGeneric.cs - - - Common\System\Collections\TestingTypes.cs - - - Common\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs - + + + + + + + @@ -42,12 +35,10 @@ - - Common\System\Diagnostics\DebuggerAttributes.cs - + - - Common\System\Collections\IEnumerable.NonGeneric.Serialization.Tests.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Collections.Specialized/ref/System.Collections.Specialized.cs b/src/libraries/System.Collections.Specialized/ref/System.Collections.Specialized.cs index fd2e1cbdd8de53..d99c32ebed7622 100644 --- a/src/libraries/System.Collections.Specialized/ref/System.Collections.Specialized.cs +++ b/src/libraries/System.Collections.Specialized/ref/System.Collections.Specialized.cs @@ -189,7 +189,7 @@ protected virtual void OnDeserialization(object? sender) { } public void Remove(object key) { } public void RemoveAt(int index) { } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object sender) { } + void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object? sender) { } } public partial class StringCollection : System.Collections.ICollection, System.Collections.IEnumerable, System.Collections.IList { diff --git a/src/libraries/System.Collections.Specialized/src/System.Collections.Specialized.csproj b/src/libraries/System.Collections.Specialized/src/System.Collections.Specialized.csproj index f024aa1179130b..6139444928b2ca 100644 --- a/src/libraries/System.Collections.Specialized/src/System.Collections.Specialized.csproj +++ b/src/libraries/System.Collections.Specialized/src/System.Collections.Specialized.csproj @@ -15,9 +15,8 @@ - - Common\System\Collections\CompatibleComparer.cs - + diff --git a/src/libraries/System.Collections.Specialized/tests/System.Collections.Specialized.Tests.csproj b/src/libraries/System.Collections.Specialized/tests/System.Collections.Specialized.Tests.csproj index 1027ec603631a6..9fe63e5d7a9b52 100644 --- a/src/libraries/System.Collections.Specialized/tests/System.Collections.Specialized.Tests.csproj +++ b/src/libraries/System.Collections.Specialized/tests/System.Collections.Specialized.Tests.csproj @@ -4,30 +4,22 @@ - - Common\System\Collections\CollectionAsserts.cs - - - Common\System\Collections\ICollection.NonGeneric.Tests.cs - - - Common\System\Collections\IDictionary.NonGeneric.Tests.cs - - - Common\System\Collections\IEnumerable.NonGeneric.Tests.cs - - - Common\System\Collections\TestBase.NonGeneric.Tests.cs - - - Common\System\Collections\TestingTypes.cs - - - Common\System\Diagnostics\DebuggerAttributes.cs - - - Common\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs - + + + + + + + + @@ -81,9 +73,8 @@ - - Common\System\Collections\IEnumerable.NonGeneric.Serialization.Tests.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Collections/System.Collections.sln b/src/libraries/System.Collections/System.Collections.sln index 047ae74e7bdc3d..c83b6b4dd0c56b 100644 --- a/src/libraries/System.Collections/System.Collections.sln +++ b/src/libraries/System.Collections/System.Collections.sln @@ -20,7 +20,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{BE45BF34-779D-4E14-9DD7-FD86E6EDC81E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{BE45BF34-779D-4E14-9DD7-FD86E6EDC81E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime", "..\System.Runtime\src\System.Runtime.csproj", "{DFC77569-7EAD-4C2B-840D-3A58847A2962}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -44,6 +46,10 @@ Global {BE45BF34-779D-4E14-9DD7-FD86E6EDC81E}.Debug|Any CPU.Build.0 = Debug|Any CPU {BE45BF34-779D-4E14-9DD7-FD86E6EDC81E}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE45BF34-779D-4E14-9DD7-FD86E6EDC81E}.Release|Any CPU.Build.0 = Release|Any CPU + {DFC77569-7EAD-4C2B-840D-3A58847A2962}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DFC77569-7EAD-4C2B-840D-3A58847A2962}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DFC77569-7EAD-4C2B-840D-3A58847A2962}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DFC77569-7EAD-4C2B-840D-3A58847A2962}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -53,6 +59,7 @@ Global {D5FF747F-7A0B-9003-885A-FE9A63E755E5} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {C746D448-E7C3-4850-9CA7-D3F1FA49742F} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} {BE45BF34-779D-4E14-9DD7-FD86E6EDC81E} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} + {DFC77569-7EAD-4C2B-840D-3A58847A2962} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7B3C136F-F7AB-498F-A4B3-F512E83806B0} diff --git a/src/libraries/System.Collections/ref/System.Collections.cs b/src/libraries/System.Collections/ref/System.Collections.cs index 918809a1211560..92958369371d23 100644 --- a/src/libraries/System.Collections/ref/System.Collections.cs +++ b/src/libraries/System.Collections/ref/System.Collections.cs @@ -56,7 +56,7 @@ protected Comparer() { } public static System.Collections.Generic.Comparer Default { get { throw null; } } public abstract int Compare([System.Diagnostics.CodeAnalysis.AllowNullAttribute] T x, [System.Diagnostics.CodeAnalysis.AllowNullAttribute] T y); public static System.Collections.Generic.Comparer Create(System.Comparison comparison) { throw null; } - int System.Collections.IComparer.Compare(object x, object y) { throw null; } + int System.Collections.IComparer.Compare(object? x, object? y) { throw null; } } public partial class Dictionary : System.Collections.Generic.ICollection>, System.Collections.Generic.IDictionary, System.Collections.Generic.IEnumerable>, System.Collections.Generic.IReadOnlyCollection>, System.Collections.Generic.IReadOnlyDictionary, System.Collections.ICollection, System.Collections.IDictionary, System.Collections.IEnumerable, System.Runtime.Serialization.IDeserializationCallback, System.Runtime.Serialization.ISerializable where TKey : notnull { @@ -102,7 +102,7 @@ public virtual void OnDeserialization(object? sender) { } bool System.Collections.Generic.ICollection>.Remove(System.Collections.Generic.KeyValuePair keyValuePair) { throw null; } System.Collections.Generic.IEnumerator> System.Collections.Generic.IEnumerable>.GetEnumerator() { throw null; } void System.Collections.ICollection.CopyTo(System.Array array, int index) { } - void System.Collections.IDictionary.Add(object key, object value) { } + void System.Collections.IDictionary.Add(object key, object? value) { } bool System.Collections.IDictionary.Contains(object key) { throw null; } System.Collections.IDictionaryEnumerator System.Collections.IDictionary.GetEnumerator() { throw null; } void System.Collections.IDictionary.Remove(object key) { } @@ -187,7 +187,7 @@ protected EqualityComparer() { } public static System.Collections.Generic.EqualityComparer Default { get { throw null; } } public abstract bool Equals([System.Diagnostics.CodeAnalysis.AllowNullAttribute] T x, [System.Diagnostics.CodeAnalysis.AllowNullAttribute] T y); public abstract int GetHashCode([System.Diagnostics.CodeAnalysis.DisallowNullAttribute] T obj); - bool System.Collections.IEqualityComparer.Equals(object x, object y) { throw null; } + bool System.Collections.IEqualityComparer.Equals(object? x, object? y) { throw null; } int System.Collections.IEqualityComparer.GetHashCode(object obj) { throw null; } } public partial class HashSet : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.ISet, System.Collections.Generic.IReadOnlySet, System.Collections.IEnumerable, System.Runtime.Serialization.IDeserializationCallback, System.Runtime.Serialization.ISerializable @@ -295,7 +295,7 @@ public partial struct Enumerator : System.Collections.Generic.IEnumerator, Sy public void Dispose() { } public bool MoveNext() { throw null; } void System.Collections.IEnumerator.Reset() { } - void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object sender) { } + void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object? sender) { } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } } } @@ -361,11 +361,11 @@ public void Sort(int index, int count, System.Collections.Generic.IComparer? System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } void System.Collections.ICollection.CopyTo(System.Array array, int arrayIndex) { } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - int System.Collections.IList.Add(object item) { throw null; } - bool System.Collections.IList.Contains(object item) { throw null; } - int System.Collections.IList.IndexOf(object item) { throw null; } - void System.Collections.IList.Insert(int index, object item) { } - void System.Collections.IList.Remove(object item) { } + int System.Collections.IList.Add(object? item) { throw null; } + bool System.Collections.IList.Contains(object? item) { throw null; } + int System.Collections.IList.IndexOf(object? item) { throw null; } + void System.Collections.IList.Insert(int index, object? item) { } + void System.Collections.IList.Remove(object? item) { } public T[] ToArray() { throw null; } public void TrimExcess() { } public bool TrueForAll(System.Predicate match) { throw null; } @@ -457,7 +457,7 @@ public void CopyTo(System.Collections.Generic.KeyValuePair[] array bool System.Collections.Generic.ICollection>.Remove(System.Collections.Generic.KeyValuePair keyValuePair) { throw null; } System.Collections.Generic.IEnumerator> System.Collections.Generic.IEnumerable>.GetEnumerator() { throw null; } void System.Collections.ICollection.CopyTo(System.Array array, int index) { } - void System.Collections.IDictionary.Add(object key, object value) { } + void System.Collections.IDictionary.Add(object key, object? value) { } bool System.Collections.IDictionary.Contains(object key) { throw null; } System.Collections.IDictionaryEnumerator System.Collections.IDictionary.GetEnumerator() { throw null; } void System.Collections.IDictionary.Remove(object key) { } @@ -572,7 +572,7 @@ public void RemoveAt(int index) { } bool System.Collections.Generic.ICollection>.Remove(System.Collections.Generic.KeyValuePair keyValuePair) { throw null; } System.Collections.Generic.IEnumerator> System.Collections.Generic.IEnumerable>.GetEnumerator() { throw null; } void System.Collections.ICollection.CopyTo(System.Array array, int arrayIndex) { } - void System.Collections.IDictionary.Add(object key, object value) { } + void System.Collections.IDictionary.Add(object key, object? value) { } bool System.Collections.IDictionary.Contains(object key) { throw null; } System.Collections.IDictionaryEnumerator System.Collections.IDictionary.GetEnumerator() { throw null; } void System.Collections.IDictionary.Remove(object key) { } @@ -624,7 +624,7 @@ void System.Collections.Generic.ICollection.Add(T item) { } System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } void System.Collections.ICollection.CopyTo(System.Array array, int index) { } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object sender) { } + void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object? sender) { } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } public bool TryGetValue(T equalValue, [System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute(false)] out T actualValue) { throw null; } public void UnionWith(System.Collections.Generic.IEnumerable other) { } @@ -637,7 +637,7 @@ public partial struct Enumerator : System.Collections.Generic.IEnumerator, Sy public void Dispose() { } public bool MoveNext() { throw null; } void System.Collections.IEnumerator.Reset() { } - void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object sender) { } + void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object? sender) { } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } } } diff --git a/src/libraries/System.Collections/src/System.Collections.csproj b/src/libraries/System.Collections/src/System.Collections.csproj index ca99c1d7aed64f..50eb24ec766ecf 100644 --- a/src/libraries/System.Collections/src/System.Collections.csproj +++ b/src/libraries/System.Collections/src/System.Collections.csproj @@ -13,12 +13,10 @@ - - Common\System\Collections\Generic\ICollectionDebugView.cs - - - Common\System\Collections\Generic\IDictionaryDebugView.cs - + + @@ -33,12 +31,10 @@ - - Common\System\Collections\HashHelpers.cs - - - Common\System\Collections\Generic\EnumerableHelpers.cs - + + diff --git a/src/libraries/System.Collections/tests/System.Collections.Tests.csproj b/src/libraries/System.Collections/tests/System.Collections.Tests.csproj index 0614402205bbe6..412f68fc8425f9 100644 --- a/src/libraries/System.Collections/tests/System.Collections.Tests.csproj +++ b/src/libraries/System.Collections/tests/System.Collections.Tests.csproj @@ -5,63 +5,44 @@ - - Common\System\Collections\CollectionAsserts.cs - - - Common\System\Collections\ICollection.NonGeneric.Tests.cs - - - Common\System\Collections\ICollection.Generic.Tests.cs - - - Common\System\Collections\IDictionary.NonGeneric.Tests.cs - - - Common\System\Collections\IDictionary.Generic.Tests.cs - - - Common\System\Collections\IEnumerable.NonGeneric.Tests.cs - - - Common\System\Collections\IEnumerable.Generic.Tests.cs - - - Common\System\Collections\IList.NonGeneric.Tests.cs - - - Common\System\Collections\IList.Generic.Tests.cs - - - Common\System\Collections\IGenericSharedAPI.Tests.cs - - - Common\System\Collections\ISet.Generic.Tests.cs - - - Common\System\Collections\TestBase.NonGeneric.Tests.cs - - - Common\System\Collections\TestBase.Generic.Tests.cs - - - Common\System\Collections\DebugView.Tests.cs - - - Common\System\Collections\TestingTypes.cs - - - Common\System\EnumTypes.cs - - - Common\System\ObjectCloner.cs - - - Common\System\RandomExtensions.cs - - - Common\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs - + + + + + + + + + + + + + + + + + + + @@ -133,21 +114,16 @@ - - Common\System\Diagnostics\DebuggerAttributes.cs - + - - Common\System\Collections\IEnumerable.NonGeneric.Serialization.Tests.cs - - - Common\System\Collections\IEnumerable.Generic.Serialization.Tests.cs - - - Common\System\Collections\IDictionary.Generic.Tests.netcoreapp.cs - - - Common\System\Collections\IDictionary.NonGeneric.Tests.netcoreapp.cs - + + + + - \ No newline at end of file + diff --git a/src/libraries/System.ComponentModel.Annotations/src/System.ComponentModel.Annotations.csproj b/src/libraries/System.ComponentModel.Annotations/src/System.ComponentModel.Annotations.csproj index e3898f5ee0da37..e871a28c7c0e62 100644 --- a/src/libraries/System.ComponentModel.Annotations/src/System.ComponentModel.Annotations.csproj +++ b/src/libraries/System.ComponentModel.Annotations/src/System.ComponentModel.Annotations.csproj @@ -50,8 +50,7 @@ - - Common\System\NotImplemented.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.ComponentModel.Annotations/tests/System.ComponentModel.Annotations.Tests.csproj b/src/libraries/System.ComponentModel.Annotations/tests/System.ComponentModel.Annotations.Tests.csproj index e351b8669f27f3..17571c6c8694fe 100644 --- a/src/libraries/System.ComponentModel.Annotations/tests/System.ComponentModel.Annotations.Tests.csproj +++ b/src/libraries/System.ComponentModel.Annotations/tests/System.ComponentModel.Annotations.Tests.csproj @@ -16,7 +16,7 @@ - + @@ -25,7 +25,7 @@ - + diff --git a/src/libraries/System.ComponentModel.Composition.Registration/src/System.ComponentModel.Composition.Registration.csproj b/src/libraries/System.ComponentModel.Composition.Registration/src/System.ComponentModel.Composition.Registration.csproj index a8442b7eedf766..bca38d6e8f46c5 100644 --- a/src/libraries/System.ComponentModel.Composition.Registration/src/System.ComponentModel.Composition.Registration.csproj +++ b/src/libraries/System.ComponentModel.Composition.Registration/src/System.ComponentModel.Composition.Registration.csproj @@ -13,24 +13,19 @@ - - Common\System\Composition\Diagnostics\CompositionTrace.cs - - - Common\System\Composition\Diagnostics\CompositionTraceId.cs - - - Common\System\Composition\Diagnostics\CompositionTraceSource.cs - - - Common\System\Composition\Diagnostics\DebuggerTraceWriter.cs - - - Common\System\Composition\Diagnostics\TraceWriter.cs - + + + + + - \ No newline at end of file + diff --git a/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj b/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj index bcd943cbd0b02c..d0930964790373 100644 --- a/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj +++ b/src/libraries/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj @@ -1,20 +1,21 @@ - System.ComponentModel.Composition - - + $(NoWarn);CS1573 - SR.PlatformNotSupported_ComponentModel_Composition $(NetCoreAppCurrent);netstandard2.0;netcoreapp2.0;_$(NetFrameworkCurrent) true enable - $(NoWarn);nullable + + + + SR.PlatformNotSupported_ComponentModel_Composition + $(NoWarn);nullable - + @@ -176,20 +177,16 @@ - - Common\System\Composition\Diagnostics\CompositionTraceId.cs - - - Common\System\Composition\Diagnostics\CompositionTraceSource.cs - - - Common\System\Composition\Diagnostics\DebuggerTraceWriter.cs - - - Common\System\Composition\Diagnostics\TraceWriter.cs - + + + + - + diff --git a/src/libraries/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Tests.csproj b/src/libraries/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Tests.csproj index 52d0ec7cfa6448..fc7811e645ef99 100644 --- a/src/libraries/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Tests.csproj +++ b/src/libraries/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Tests.csproj @@ -10,12 +10,10 @@ - - Common\System\IO\TempDirectory.cs - - - Common\System\IO\TempFile.cs - + + diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx b/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx index 84fd677ad67636..7de9810d591ed2 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx +++ b/src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx @@ -1,4 +1,5 @@ - + + @@ -76,16 +77,16 @@ The value '{0}' is not a valid value for the enum '{1}'. - Invalid event handler for the {0} event. + Invalid event handler for the {0} event. - Invalid type for the {0} event. + Invalid type for the {0} event. Invalid type for the {0} property - Accessor methods for the {0} event are missing. + Accessor methods for the {0} event are missing. Accessor methods for the {0} property are missing. @@ -170,7 +171,7 @@ The {0} culture cannot be converted to a CultureInfo object on this computer. - + The service instance must derive from or implement {0}. @@ -178,7 +179,7 @@ The service {0} already exists in the service container. - Value of '{1}' is not valid for '{0}'. + Value of '{0}' cannot be empty. Null is not a valid value for {0}. @@ -242,11 +243,11 @@ The checkout was canceled by the user. - - + + (none) - + Relationships between {0}.{1} and {2}.{3} are not supported. - + \ No newline at end of file diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj b/src/libraries/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj index 5285055594c6e3..9b57a22eee4b24 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj @@ -81,12 +81,10 @@ - - System\Drawing\ColorConverterCommon.cs - - - System\Drawing\ColorTable.cs - + + @@ -239,9 +237,8 @@ - - Common\System\Runtime\CompilerServices\PreserveDependencyAttribute.cs - + @@ -266,4 +263,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesignerOptionService.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesignerOptionService.cs index f80f2c00babdd0..3227d9c8170df5 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesignerOptionService.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesignerOptionService.cs @@ -14,7 +14,6 @@ namespace System.ComponentModel.Design public abstract class DesignerOptionService : IDesignerOptionService { private DesignerOptionCollection _options; - private static readonly char[] s_slash = { '\\' }; /// /// Returns the options collection for this service. There is @@ -48,7 +47,7 @@ protected DesignerOptionCollection CreateOptionCollection(DesignerOptionCollecti if (name.Length == 0) { - throw new ArgumentException(SR.Format(SR.InvalidArgumentValue, name.Length.ToString(), "0"), "name.Length"); + throw new ArgumentException(SR.Format(SR.InvalidArgumentValue, "name.Length"), nameof(name)); } return new DesignerOptionCollection(this, parent, name, value); @@ -70,7 +69,7 @@ private PropertyDescriptor GetOptionProperty(string pageName, string valueName) throw new ArgumentNullException(nameof(valueName)); } - string[] optionNames = pageName.Split(s_slash); + string[] optionNames = pageName.Split('\\'); DesignerOptionCollection options = Options; foreach (string optionName in optionNames) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/Serialization/MemberRelationshipService.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/Serialization/MemberRelationshipService.cs index c5bceb6e9d450a..81889b0ca6327c 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/Serialization/MemberRelationshipService.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/Serialization/MemberRelationshipService.cs @@ -44,7 +44,7 @@ public MemberRelationship this[MemberRelationship source] // and not the other as the main constructor performs argument validation. if (source.Owner == null) { - throw new ArgumentNullException(nameof(MemberRelationship.Owner)); + throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "source.Owner"), nameof(source)); } Debug.Assert(source.Member != null); @@ -57,7 +57,7 @@ public MemberRelationship this[MemberRelationship source] // and not the other as the main constructor performs argument validation. if (source.Owner == null) { - throw new ArgumentNullException(nameof(MemberRelationship.Owner)); + throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "source.Owner"), nameof(source)); } Debug.Assert(source.Member != null); diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/EnumConverter.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/EnumConverter.cs index b7db262f298305..2ae15a3c547417 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/EnumConverter.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/EnumConverter.cs @@ -16,8 +16,6 @@ namespace System.ComponentModel /// public class EnumConverter : TypeConverter { - private static readonly char[] s_separators = { ',' }; - /// /// Initializes a new instance of the class for the given /// type. @@ -83,7 +81,7 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c { bool isUnderlyingTypeUInt64 = Enum.GetUnderlyingType(EnumType) == typeof(ulong); long convertedValue = 0; - string[] values = strValue.Split(s_separators); + string[] values = strValue.Split(','); foreach (string v in values) { convertedValue |= GetEnumValue(isUnderlyingTypeUInt64, (Enum)Enum.Parse(EnumType, v, true), culture); diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesignerOptionServiceTests.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesignerOptionServiceTests.cs index 37aaf190737886..78778d048a330a 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesignerOptionServiceTests.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/DesignerOptionServiceTests.cs @@ -53,7 +53,7 @@ public void CreateOptionCollection_NullName_ThrowsArgumentNullException() public void CreateOptionCollection_EmptyName_ThrowsArgumentException() { var service = new TestDesignerOptionService(); - AssertExtensions.Throws("name.Length", () => service.DoCreateOptionCollection(service.Options, string.Empty, "value")); + AssertExtensions.Throws("name", () => service.DoCreateOptionCollection(service.Options, string.Empty, "value")); } [Fact] diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/Serialization/MemberRelationshipServiceTests.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/Serialization/MemberRelationshipServiceTests.cs index 9f85a1eeff671f..5bc0242ca9ed56 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/Design/Serialization/MemberRelationshipServiceTests.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/Design/Serialization/MemberRelationshipServiceTests.cs @@ -56,8 +56,8 @@ public void Indexer_NullSourceOwner_ThrowsArgumentNullException() Assert.Throws("sourceOwner", () => service[null, member]); Assert.Throws("sourceOwner", () => service[null, member] = new MemberRelationship()); - Assert.Throws("Owner", () => service[new MemberRelationship()]); - Assert.Throws("Owner", () => service[new MemberRelationship()] = new MemberRelationship()); + Assert.Throws("source", () => service[new MemberRelationship()]); + Assert.Throws("source", () => service[new MemberRelationship()] = new MemberRelationship()); } [Fact] diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/EnumConverterTest.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/EnumConverterTest.cs index 9e071a1d587990..1ba44811524dc6 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/EnumConverterTest.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/EnumConverterTest.cs @@ -109,7 +109,7 @@ public static void ConvertTo_WithContext_Flags() public static void ConvertTo_WithContext_Negative() { AssertExtensions.Throws(null, () => EnumConverterTests.s_someEnumConverter.ConvertTo(TypeConverterTests.s_context, null, 3, typeof(string))); - AssertExtensions.Throws(null, "enumType", () => new EnumConverter(typeof(Enum)).ConvertTo(TypeConverterTests.s_context, null, SomeFlagsEnum.Option1, typeof(string))); + AssertExtensions.Throws("enumType", () => new EnumConverter(typeof(Enum)).ConvertTo(TypeConverterTests.s_context, null, SomeFlagsEnum.Option1, typeof(string))); } [Fact] diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/System.ComponentModel.TypeConverter.Tests.csproj b/src/libraries/System.ComponentModel.TypeConverter/tests/System.ComponentModel.TypeConverter.Tests.csproj index 18015088fa8470..eb8dda3696e84e 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/System.ComponentModel.TypeConverter.Tests.csproj +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/System.ComponentModel.TypeConverter.Tests.csproj @@ -6,7 +6,7 @@ 9.9.9.9 $(NetCoreAppCurrent) - + diff --git a/src/libraries/System.Composition.Convention/src/System.Composition.Convention.csproj b/src/libraries/System.Composition.Convention/src/System.Composition.Convention.csproj index e83917a8d68038..635f6a2b2fcb39 100644 --- a/src/libraries/System.Composition.Convention/src/System.Composition.Convention.csproj +++ b/src/libraries/System.Composition.Convention/src/System.Composition.Convention.csproj @@ -13,21 +13,16 @@ - - Common\System\Composition\Diagnostics\CompositionTrace.cs - - - Common\System\Composition\Diagnostics\CompositionTraceId.cs - - - Common\System\Composition\Diagnostics\CompositionTraceSource.cs - - - Common\System\Composition\Diagnostics\DebuggerTraceWriter.cs - - - Common\System\Composition\Diagnostics\TraceWriter.cs - + + + + + diff --git a/src/libraries/System.Composition.TypedParts/src/System.Composition.TypedParts.csproj b/src/libraries/System.Composition.TypedParts/src/System.Composition.TypedParts.csproj index 8fc187238cd066..0171ea482a7c22 100644 --- a/src/libraries/System.Composition.TypedParts/src/System.Composition.TypedParts.csproj +++ b/src/libraries/System.Composition.TypedParts/src/System.Composition.TypedParts.csproj @@ -26,9 +26,8 @@ - - Common\System\Numerics\Hashing\HashHelpers.cs - + diff --git a/src/libraries/System.Composition.TypedParts/tests/System.Composition.TypedParts.Tests.csproj b/src/libraries/System.Composition.TypedParts/tests/System.Composition.TypedParts.Tests.csproj index d394da4cf09e93..b2a05265bb1e17 100644 --- a/src/libraries/System.Composition.TypedParts/tests/System.Composition.TypedParts.Tests.csproj +++ b/src/libraries/System.Composition.TypedParts/tests/System.Composition.TypedParts.Tests.csproj @@ -4,9 +4,8 @@ - - Common\System\Diagnostics\DebuggerAttributes.cs - + \ No newline at end of file diff --git a/src/libraries/System.Configuration.ConfigurationManager/ref/System.Configuration.ConfigurationManager.csproj b/src/libraries/System.Configuration.ConfigurationManager/ref/System.Configuration.ConfigurationManager.csproj index 1a58ecd7cfb1b4..36c443936cb09d 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/ref/System.Configuration.ConfigurationManager.csproj +++ b/src/libraries/System.Configuration.ConfigurationManager/ref/System.Configuration.ConfigurationManager.csproj @@ -1,9 +1,12 @@ - true netstandard2.0;net461;$(NetFrameworkCurrent) true + + + true + diff --git a/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj b/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj index 6de345cee06256..2d71eb3b7e3743 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj +++ b/src/libraries/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj @@ -1,9 +1,12 @@ - true netstandard2.0;net461;$(NetFrameworkCurrent) true + + + true + @@ -237,17 +240,15 @@ - - Common\System\Security\IdentityHelper.cs - + - - Common\System\IO\TempFileCollection.cs - + @@ -261,4 +262,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Configuration.ConfigurationManager/tests/Mono/KeyValueConfigurationElementTest.cs b/src/libraries/System.Configuration.ConfigurationManager/tests/Mono/KeyValueConfigurationElementTest.cs index 703e3180c974ed..7055f2f73c363c 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/tests/Mono/KeyValueConfigurationElementTest.cs +++ b/src/libraries/System.Configuration.ConfigurationManager/tests/Mono/KeyValueConfigurationElementTest.cs @@ -57,7 +57,6 @@ public ConfigurationPropertyCollection GetProperties() } [Fact] - // [NUnit.Framework.Category("NotWorking")] public void Properties() { Poker p = new Poker("name", "value"); diff --git a/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj b/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj index ae774993387fff..77b8fba4c8c275 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj +++ b/src/libraries/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj @@ -7,30 +7,22 @@ $(NetCoreAppCurrent);$(NetFrameworkCurrent) - - Common\System\IO\TempDirectory.cs - - - Common\System\IO\TempFile.cs - - - Source\ConfigPathUtility.cs - - - Source\ExceptionUtil.cs - - - Source\StringUtil.cs - - - Source\TypeUtil.cs - - - Source\UrlPath.cs - - - Source\ValidatorUtils.cs - + + + + + + + + @@ -112,4 +104,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Console/src/System.Console.csproj b/src/libraries/System.Console/src/System.Console.csproj index 1415fce320a6a6..23b21f1ee3168c 100644 --- a/src/libraries/System.Console/src/System.Console.csproj +++ b/src/libraries/System.Console/src/System.Console.csproj @@ -3,7 +3,7 @@ System.Console System.Console true - $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-tvOS + $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Android;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-tvOS enable @@ -17,267 +17,213 @@ - - Common\System\Text\ConsoleEncoding.cs - + - - Common\Interop\OSX\Interop.Log.cs + + + + + + + + Common\Interop\Android\Interop.Logcat.cs - - Common\Interop\Unix\Interop.Libraries.cs + + Common\Interop\Android\Interop.Libraries.cs + + + + + + + + + + - - Common\System\Text\OSEncoding.Windows.cs - - - Common\System\Text\OSEncoder.cs - - - Common\System\Text\DBCSDecoder.cs - - - Common\Interop\Windows\Interop.GetCPInfoEx.cs - - - Common\Interop\Windows\Interop.MAX_PATH.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.BOOL.cs - - - Common\Interop\Windows\Interop.Beep.cs - - - Common\Interop\Windows\Interop.FormatMessage.cs - - - Common\Interop\Windows\Interop.ConsoleCursorInfo.cs - - - Common\Interop\Windows\Interop.ConsoleScreenBufferInfo.cs - - - Common\Interop\Windows\Interop.Errors.cs - - - Common\Interop\Windows\Interop.FillConsoleOutputAttribute.cs - - - Common\Interop\Windows\Interop.FillConsoleOutputCharacter.cs - - - Common\Interop\Windows\Interop.FileTypes.cs - - - Common\Interop\Windows\Interop.GetConsoleScreenBufferInfo.cs - - - Common\Interop\Windows\Interop.GetConsoleCP.cs - - - Common\Interop\Windows\Interop.GetConsoleTitle.cs - - - Common\Interop\Windows\Interop.GetConsoleMode.cs - - - Common\Interop\Windows\Interop.GetConsoleOutputCP.cs - - - Common\Interop\Windows\Interop.GetLargestConsoleWindowSize.cs - - - Common\Interop\Windows\Interop.GetFileType.cs - - - Common\Interop\Windows\Interop.GetKeyState.cs - - - Common\Interop\Windows\Interop.GetStdHandle.cs - - - Common\Interop\Windows\Interop.HandleTypes.cs - - - Common\Interop\Windows\Interop.MultiByteToWideChar.cs - - - Common\Interop\Windows\Interop.PeekConsoleInput.cs - - - Common\Interop\Windows\Interop.ReadFile.cs - - - Common\Interop\Windows\Interop.ReadConsole.cs - - - Common\Interop\Windows\Interop.ReadConsoleInput.cs - - - Common\Interop\Windows\Interop.ReadConsoleOutput.cs - - - Common\Interop\Windows\Interop.SetConsoleCP.cs - - - Common\Interop\Windows\Interop.SetConsoleCtrlHandler.cs - - - Common\Interop\Windows\Interop.SetConsoleCursorPosition.cs - - - Common\Interop\Windows\Interop.SetConsoleOutputCP.cs - - - Common\Interop\Windows\Interop.SetConsoleScreenBufferSize.cs - - - Common\Interop\Windows\Interop.SetConsoleTextAttribute.cs - - - Common\Interop\Windows\Interop.SetConsoleTitle.cs - - - Common\Interop\Windows\Interop.SetConsoleWindowInfo.cs - - - Common\Interop\Windows\Interop.WideCharToMultiByte.cs - - - Common\Interop\Windows\Interop.WriteFile.cs - - - Common\Interop\Windows\Interop.WriteConsole.cs - - - Common\Interop\Windows\Interop.WriteConsoleOutput.cs - - - Common\System\IO\EncodingHelper.Windows.cs - - - Common\System\IO\Win32Marshal.cs - - - Common\System\Text\ValueStringBuilder.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - Common\Microsoft\Win32\SafeHandles\SafeFileHandleHelper.Unix.cs - - - Common\System\IO\PersistedFiles.Unix.cs - - - Common\System\IO\PersistedFiles.Names.Unix.cs - - - Common\System\Text\StringBuilderCache.cs - - - Common\System\Text\EncodingHelper.Unix.cs - - - Common\System\Text\StringOrCharArray.cs - - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\Interop.Errors.cs - - - Common\Interop\Unix\Interop.IOErrors.cs - - - Common\Interop\Unix\Interop.Close.cs - - - Common\Interop\Unix\Interop.Dup.cs - - - Common\Interop\Unix\Interop.FileDescriptors.cs - - - Common\Interop\Unix\Interop.FLock.cs - - - Common\Interop\Unix\Interop.GetControlCharacters.cs - - - Common\Interop\Unix\Interop.IsATty.cs - - - Common\Interop\Unix\Interop.LSeek.cs - - - Common\Interop\Unix\Interop.Open.cs - - - Common\Interop\Unix\Interop.OpenFlags.cs - - - Common\Interop\Unix\Interop.Poll.cs - - - Common\Interop\Unix\Interop.GetEUid.cs - - - Common\Interop\Unix\Interop.GetPwUid.cs - - - Common\Interop\Unix\Interop.RegisterForCtrlC.cs - - - Common\Interop\Unix\Interop.RestoreAndHandleCtrl.cs - - - Common\Interop\Unix\Interop.SetTerminalInvalidationHandler.cs - - - Common\Interop\Unix\Interop.SetSignalForBreak.cs - - - Common\Interop\Unix\Interop.SNPrintF.cs - - - Common\Interop\Unix\Interop.Stat.cs - - - Common\Interop\Unix\Interop.Read.cs - - - Common\Interop\Unix\Interop.Write.cs - - - Common\Interop\Unix\Interop.GetWindowWidth.cs - - - Common\Interop\Unix\Interop.InitializeTerminalAndSignalHandling.cs - - - Common\Interop\Unix\Interop.ReadStdinUnbuffered.cs - - - Common\Interop\Unix\Interop.StdinReady.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Console/src/System/Console.cs b/src/libraries/System.Console/src/System/Console.cs index 44ed46250a0d2a..9754ae541f20fd 100644 --- a/src/libraries/System.Console/src/System/Console.cs +++ b/src/libraries/System.Console/src/System/Console.cs @@ -28,8 +28,8 @@ public static class Console private static TextWriter? s_out, s_error; private static Encoding? s_inputEncoding; private static Encoding? s_outputEncoding; - private static bool s_isOutTextWriterRedirected = false; - private static bool s_isErrorTextWriterRedirected = false; + private static bool s_isOutTextWriterRedirected; + private static bool s_isErrorTextWriterRedirected; private static ConsoleCancelEventHandler? s_cancelCallbacks; private static ConsolePal.ControlCHandlerRegistrar? s_registrar; diff --git a/src/libraries/System.Console/src/System/ConsolePal.Android.cs b/src/libraries/System.Console/src/System/ConsolePal.Android.cs new file mode 100644 index 00000000000000..87958be3c48580 --- /dev/null +++ b/src/libraries/System.Console/src/System/ConsolePal.Android.cs @@ -0,0 +1,168 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using System.Text; +using System.Runtime.InteropServices; + +namespace System +{ + internal sealed unsafe class LogcatStream : ConsoleStream + { + public LogcatStream() : base(FileAccess.Write) {} + + public override int Read(byte[] buffer, int offset, int count) => throw Error.GetReadNotSupported(); + + public override unsafe void Write(byte[] buffer, int offset, int count) + { + string log = ConsolePal.OutputEncoding.GetString(buffer, offset, count); + Interop.Logcat.AndroidLogPrint(Interop.Logcat.LogLevel.Info, "DOTNET", log); + } + } + + internal static class ConsolePal + { + internal static void EnsureConsoleInitialized() { } + + public static Stream OpenStandardInput() => throw new PlatformNotSupportedException(); + + public static Stream OpenStandardOutput() => new LogcatStream(); + + public static Stream OpenStandardError() => new LogcatStream(); + + public static Encoding InputEncoding => throw new PlatformNotSupportedException(); + + public static void SetConsoleInputEncoding(Encoding enc) => throw new PlatformNotSupportedException(); + + public static Encoding OutputEncoding => Encoding.Unicode; + + public static void SetConsoleOutputEncoding(Encoding enc) => throw new PlatformNotSupportedException(); + + public static bool IsInputRedirectedCore() => false; + + public static bool IsOutputRedirectedCore() => false; + + public static bool IsErrorRedirectedCore() => false; + + internal static TextReader GetOrCreateReader() => throw new PlatformNotSupportedException(); + + public static bool NumberLock => false; + + public static bool CapsLock => false; + + public static bool KeyAvailable => false; + + public static ConsoleKeyInfo ReadKey(bool intercept) => throw new PlatformNotSupportedException(); + + public static bool TreatControlCAsInput + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static ConsoleColor BackgroundColor + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static ConsoleColor ForegroundColor + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static void ResetColor() => throw new PlatformNotSupportedException(); + + public static int CursorSize + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static bool CursorVisible + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int CursorLeft => throw new PlatformNotSupportedException(); + + public static int CursorTop => throw new PlatformNotSupportedException(); + + public static string Title + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static void Beep() => throw new PlatformNotSupportedException(); + + public static void Beep(int frequency, int duration) => throw new PlatformNotSupportedException(); + + public static void MoveBufferArea(int sourceLeft, int sourceTop, + int sourceWidth, int sourceHeight, int targetLeft, int targetTop, + char sourceChar, ConsoleColor sourceForeColor, + ConsoleColor sourceBackColor) => throw new PlatformNotSupportedException(); + + public static void Clear() => throw new PlatformNotSupportedException(); + + public static void SetCursorPosition(int left, int top) => throw new PlatformNotSupportedException(); + + public static int BufferWidth + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int BufferHeight + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static void SetBufferSize(int width, int height) => throw new PlatformNotSupportedException(); + + public static int LargestWindowWidth => throw new PlatformNotSupportedException(); + + public static int LargestWindowHeight => throw new PlatformNotSupportedException(); + + public static int WindowLeft + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int WindowTop + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int WindowWidth + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int WindowHeight + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static void SetWindowPosition(int left, int top) => throw new PlatformNotSupportedException(); + + public static void SetWindowSize(int width, int height) => throw new PlatformNotSupportedException(); + + internal sealed class ControlCHandlerRegistrar + { + internal ControlCHandlerRegistrar() => throw new PlatformNotSupportedException(); + + internal void Register() => throw new PlatformNotSupportedException(); + + internal void Unregister() => throw new PlatformNotSupportedException(); + } + } +} diff --git a/src/libraries/System.Console/src/System/ConsolePal.Unix.cs b/src/libraries/System.Console/src/System/ConsolePal.Unix.cs index ff7efd5b5f21bc..f3ac90adf6f08d 100644 --- a/src/libraries/System.Console/src/System/ConsolePal.Unix.cs +++ b/src/libraries/System.Console/src/System/ConsolePal.Unix.cs @@ -1279,7 +1279,7 @@ private static unsafe void Write(SafeFileHandle fd, byte* bufPtr, int count, boo // only the blocking behavior, and thus ignore any poll errors // and loop around to do another write (which may correctly fail // if something else has gone wrong). - Interop.Sys.Poll(fd, Interop.Sys.PollEvents.POLLOUT, Timeout.Infinite, out Interop.Sys.PollEvents triggered); + Interop.Sys.Poll(fd, Interop.PollEvents.POLLOUT, Timeout.Infinite, out Interop.PollEvents triggered); continue; } else diff --git a/src/libraries/System.Console/src/System/ConsolePal.WebAssembly.cs b/src/libraries/System.Console/src/System/ConsolePal.WebAssembly.cs new file mode 100644 index 00000000000000..77c49e4b57cb50 --- /dev/null +++ b/src/libraries/System.Console/src/System/ConsolePal.WebAssembly.cs @@ -0,0 +1,226 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using System.Text; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; + +namespace System +{ + internal sealed class WasmConsoleStream : ConsoleStream + { + private readonly SafeFileHandle _handle; + + internal WasmConsoleStream(SafeFileHandle handle, FileAccess access) + : base(access) + { + _handle = handle; + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _handle.Dispose(); + } + base.Dispose(disposing); + } + + public override int Read(byte[] buffer, int offset, int count) => throw Error.GetReadNotSupported(); + + public override unsafe void Write(byte[] buffer, int offset, int count) + { + ValidateWrite(buffer, offset, count); + + fixed (byte* bufPtr = buffer) + { + Write(_handle, bufPtr + offset, count); + } + } + + private static unsafe void Write(SafeFileHandle fd, byte* bufPtr, int count) + { + while (count > 0) + { + int bytesWritten = Interop.Sys.Write(fd, bufPtr, count); + if (bytesWritten < 0) + { + Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo(); + if (errorInfo.Error == Interop.Error.EPIPE) + { + return; + } + else + { + throw Interop.GetIOException(errorInfo); + } + } + + count -= bytesWritten; + bufPtr += bytesWritten; + } + } + + public override void Flush() + { + if (_handle.IsClosed) + { + throw Error.GetFileNotOpen(); + } + base.Flush(); + } + } + + internal static class ConsolePal + { + internal static void EnsureConsoleInitialized() { } + + public static Stream OpenStandardInput() => throw new PlatformNotSupportedException(); + + public static Stream OpenStandardOutput() + { + return new WasmConsoleStream(Interop.Sys.Dup(Interop.Sys.FileDescriptors.STDOUT_FILENO), FileAccess.Write); + } + + public static Stream OpenStandardError() + { + return new WasmConsoleStream(Interop.Sys.Dup(Interop.Sys.FileDescriptors.STDERR_FILENO), FileAccess.Write); + } + + public static Encoding InputEncoding => throw new PlatformNotSupportedException(); + + public static void SetConsoleInputEncoding(Encoding enc) => throw new PlatformNotSupportedException(); + + public static Encoding OutputEncoding => Encoding.Unicode; + + public static void SetConsoleOutputEncoding(Encoding enc) => throw new PlatformNotSupportedException(); + + public static bool IsInputRedirectedCore() => false; + + public static bool IsOutputRedirectedCore() => false; + + public static bool IsErrorRedirectedCore() => false; + + internal static TextReader GetOrCreateReader() => throw new PlatformNotSupportedException(); + + public static bool NumberLock => false; + + public static bool CapsLock => false; + + public static bool KeyAvailable => false; + + public static ConsoleKeyInfo ReadKey(bool intercept) => throw new PlatformNotSupportedException(); + + public static bool TreatControlCAsInput + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static ConsoleColor BackgroundColor + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static ConsoleColor ForegroundColor + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static void ResetColor() => throw new PlatformNotSupportedException(); + + public static int CursorSize + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static bool CursorVisible + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int CursorLeft => throw new PlatformNotSupportedException(); + + public static int CursorTop => throw new PlatformNotSupportedException(); + + public static string Title + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static void Beep() => throw new PlatformNotSupportedException(); + + public static void Beep(int frequency, int duration) => throw new PlatformNotSupportedException(); + + public static void MoveBufferArea(int sourceLeft, int sourceTop, + int sourceWidth, int sourceHeight, int targetLeft, int targetTop, + char sourceChar, ConsoleColor sourceForeColor, + ConsoleColor sourceBackColor) => throw new PlatformNotSupportedException(); + + public static void Clear() => throw new PlatformNotSupportedException(); + + public static void SetCursorPosition(int left, int top) => throw new PlatformNotSupportedException(); + + public static int BufferWidth + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int BufferHeight + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static void SetBufferSize(int width, int height) => throw new PlatformNotSupportedException(); + + public static int LargestWindowWidth => throw new PlatformNotSupportedException(); + + public static int LargestWindowHeight => throw new PlatformNotSupportedException(); + + public static int WindowLeft + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int WindowTop + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int WindowWidth + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static int WindowHeight + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public static void SetWindowPosition(int left, int top) => throw new PlatformNotSupportedException(); + + public static void SetWindowSize(int width, int height) => throw new PlatformNotSupportedException(); + + internal sealed class ControlCHandlerRegistrar + { + internal ControlCHandlerRegistrar() => throw new PlatformNotSupportedException(); + + internal void Register() => throw new PlatformNotSupportedException(); + + internal void Unregister() => throw new PlatformNotSupportedException(); + } + } +} diff --git a/src/libraries/System.Console/tests/System.Console.Tests.csproj b/src/libraries/System.Console/tests/System.Console.Tests.csproj index c16e3af1f24d3d..47bbf84fcd94db 100644 --- a/src/libraries/System.Console/tests/System.Console.Tests.csproj +++ b/src/libraries/System.Console/tests/System.Console.Tests.csproj @@ -23,12 +23,10 @@ - - Common\System\IO\InterceptStreamWriter.cs - - - Common\System\ShouldNotBeInvokedException.cs - + + @@ -42,11 +40,9 @@ - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Unix\System.Native\Interop.Fcntl.cs - + + - \ No newline at end of file + diff --git a/src/libraries/System.Data.Common/src/System.Data.Common.csproj b/src/libraries/System.Data.Common/src/System.Data.Common.csproj index 561674c584e34a..a9583ce2d19146 100644 --- a/src/libraries/System.Data.Common/src/System.Data.Common.csproj +++ b/src/libraries/System.Data.Common/src/System.Data.Common.csproj @@ -161,9 +161,8 @@ - - System\Data\Common\AdapterUtil.cs - + @@ -191,12 +190,10 @@ Component - - System\Data\Common\DbConnectionOptions.Common.cs - - - System\Data\Common\DbConnectionPoolKey.cs - + + @@ -228,12 +225,10 @@ - - System\Data\Common\MultipartIdentifier.cs - - - System\Data\Common\NameValuePair.cs - + + @@ -286,9 +281,8 @@ - - System\Data\SQLTypes\SQLResource.cs - + @@ -300,9 +294,8 @@ - - Common\System\Runtime\CompilerServices\PreserveDependencyAttribute.cs - + diff --git a/src/libraries/System.Data.Common/src/System/Data/DataColumn.cs b/src/libraries/System.Data.Common/src/System/Data/DataColumn.cs index c25ceec9fc051f..d44ec1e0b88751 100644 --- a/src/libraries/System.Data.Common/src/System/Data/DataColumn.cs +++ b/src/libraries/System.Data.Common/src/System/Data/DataColumn.cs @@ -475,9 +475,7 @@ internal string GetColumnValueAsString(DataRow row, DataRowVersion version) [TypeConverter(typeof(ColumnTypeConverter))] public Type DataType { - [PreserveDependency(".ctor", "System.Data.ColumnTypeConverter")] // TODO: Remove when https://github.com/mono/linker/issues/800 is fixed get { return _dataType; } - [PreserveDependency(".ctor", "System.Data.ColumnTypeConverter")] // TODO: Remove when https://github.com/mono/linker/issues/800 is fixed set { if (_dataType != value) @@ -641,7 +639,6 @@ public DataSetDateTime DateTimeMode [TypeConverter(typeof(DefaultValueTypeConverter))] public object DefaultValue { - [PreserveDependency(".ctor", "System.Data.DefaultValueTypeConverter")] // TODO: Remove when https://github.com/mono/linker/issues/800 is fixed get { Debug.Assert(_defaultValue != null, "It should not have been set to null."); @@ -668,7 +665,6 @@ public object DefaultValue return _defaultValue; } - [PreserveDependency(".ctor", "System.Data.DefaultValueTypeConverter")] // TODO: Remove when https://github.com/mono/linker/issues/800 is fixed set { DataCommonEventSource.Log.Trace(" {0}", ObjectID); diff --git a/src/libraries/System.Data.Common/src/System/Data/DataTable.cs b/src/libraries/System.Data.Common/src/System/Data/DataTable.cs index fbab54009fe570..264d03d1f728bc 100644 --- a/src/libraries/System.Data.Common/src/System/Data/DataTable.cs +++ b/src/libraries/System.Data.Common/src/System/Data/DataTable.cs @@ -1593,7 +1593,6 @@ internal int NestedParentsCount [TypeConverter(typeof(PrimaryKeyTypeConverter))] public DataColumn[] PrimaryKey { - [PreserveDependency(".ctor", "System.Data.PrimaryKeyTypeConverter")] // TODO: Remove when https://github.com/mono/linker/issues/800 is fixed get { UniqueConstraint primayKeyConstraint = _primaryKey; @@ -1604,7 +1603,6 @@ public DataColumn[] PrimaryKey } return Array.Empty(); } - [PreserveDependency(".ctor", "System.Data.DefaultValueTypeConverter")] // TODO: Remove when https://github.com/mono/linker/issues/800 is fixed set { UniqueConstraint key = null; diff --git a/src/libraries/System.Data.Common/src/System/Data/DataView.cs b/src/libraries/System.Data.Common/src/System/Data/DataView.cs index ced4b95b57c92c..350e5cf961385c 100644 --- a/src/libraries/System.Data.Common/src/System/Data/DataView.cs +++ b/src/libraries/System.Data.Common/src/System/Data/DataView.cs @@ -476,9 +476,7 @@ internal System.Comparison SortComparison [RefreshProperties(RefreshProperties.All)] public DataTable Table { - [PreserveDependency(".ctor", "System.Data.DataTableTypeConverter")] // TODO: Remove when https://github.com/mono/linker/issues/800 is fixed get { return _table; } - [PreserveDependency(".ctor", "System.Data.DataTableTypeConverter")] // TODO: Remove when https://github.com/mono/linker/issues/800 is fixed set { DataCommonEventSource.Log.Trace(" {0}, {1}", ObjectID, (value != null) ? value.ObjectID : 0); diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SqlXml.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SqlXml.cs index cb3efa48b6f7bf..02baf8afcd2d67 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SqlXml.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SqlXml.cs @@ -10,6 +10,7 @@ using System.Diagnostics; using System.Text; using System.Reflection; +using System.Runtime.CompilerServices; namespace System.Data.SqlTypes { @@ -122,11 +123,12 @@ private static Func Crea { Debug.Assert(CreateSqlReaderMethodInfo != null, "MethodInfo reference for XmlReader.CreateSqlReader should not be null."); - return (Func)CreateSqlReaderMethodInfo.CreateDelegate(typeof(Func)); + return CreateSqlReaderMethodInfo.CreateDelegate>(); } private static MethodInfo CreateSqlReaderMethodInfo { + [PreserveDependency("CreateSqlReader", "System.Xml.XmlReader", "System.Private.Xml")] get { if (s_createSqlReaderMethodInfo == null) diff --git a/src/libraries/System.Data.Common/src/System/Data/XDRSchema.cs b/src/libraries/System.Data.Common/src/System/Data/XDRSchema.cs index b2d21c2315b7c4..ef5ed183c08fe8 100644 --- a/src/libraries/System.Data.Common/src/System/Data/XDRSchema.cs +++ b/src/libraries/System.Data.Common/src/System/Data/XDRSchema.cs @@ -16,7 +16,6 @@ internal sealed class XDRSchema : XMLSchema internal string _schemaUri; internal XmlElement _schemaRoot; internal DataSet _ds; - private static readonly char[] s_colonArray = new char[] { ':' }; internal XDRSchema(DataSet ds, bool fInline) { @@ -294,7 +293,7 @@ private static NameType FindNameType(string name) private Type ParseDataType(string dt, string dtValues) { string strType = dt; - string[] parts = dt.Split(s_colonArray); // ":" + string[] parts = dt.Split(':'); if (parts.Length > 2) { diff --git a/src/libraries/System.Data.Common/tests/System.Data.Common.Tests.csproj b/src/libraries/System.Data.Common/tests/System.Data.Common.Tests.csproj index f82cb624c9c7d4..5bb9d46a3a8f55 100644 --- a/src/libraries/System.Data.Common/tests/System.Data.Common.Tests.csproj +++ b/src/libraries/System.Data.Common/tests/System.Data.Common.Tests.csproj @@ -57,7 +57,7 @@ - + @@ -113,11 +113,9 @@ - - Common\System\Diagnostics\Tracing\TestEventListener.cs - - - Common\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs - + + diff --git a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringSortingTest.cs b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringSortingTest.cs index a4403b41c6feb6..529116388e9a09 100644 --- a/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringSortingTest.cs +++ b/src/libraries/System.Data.Common/tests/System/Data/SqlTypes/SqlStringSortingTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Globalization; using System.Text; +using Microsoft.DotNet.XUnitExtensions; using Xunit; namespace System.Data.SqlTypes.Tests @@ -37,12 +38,8 @@ public static class SqlStringSortingTest private static readonly UnicodeEncoding s_unicodeEncoding = new UnicodeEncoding(bigEndian: false, byteOrderMark: false, throwOnInvalidBytes: true); - [ActiveIssue("https://github.com/dotnet/runtime/issues/18912", TestPlatforms.AnyUnix)] // TODO: Add this to the theory below when the issue is addressed on Unix - [Theory] + [ConditionalTheory] [InlineData("ja-JP", 0x0411)] // Japanese - Japan - public static void SqlStringValidComparisonTest_Windows(string cultureName, int localeId) => SqlStringValidComparisonTest(cultureName, localeId); - - [Theory] [InlineData("ar-SA", 0x0401)] // Arabic - Saudi Arabia [InlineData("de-DE", 0x0407)] // German - Germany [InlineData("hi-IN", 0x0439)] // Hindi - India @@ -56,6 +53,12 @@ public static class SqlStringSortingTest [InlineData("en-US", 0x0409)] // English - United States public static void SqlStringValidComparisonTest(string cultureName, int localeId) { + if (PlatformDetection.IsIcuGlobalization && cultureName == "ja-JP" && localeId == 0x0411) + { + // TODO: Remove this once: https://github.com/dotnet/runtime/issues/18912 is fixed on ICU. + throw new SkipTestException($"PlatformDetection.IsIcuGlobalization and cultureName == ja-JP"); + } + var culture = new CultureInfo(cultureName); const SqlCompareOptions DefaultCompareOption = SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth; diff --git a/src/libraries/System.Data.Odbc/ref/System.Data.Odbc.csproj b/src/libraries/System.Data.Odbc/ref/System.Data.Odbc.csproj index e8de99fff8ee60..1aa56e780adbeb 100644 --- a/src/libraries/System.Data.Odbc/ref/System.Data.Odbc.csproj +++ b/src/libraries/System.Data.Odbc/ref/System.Data.Odbc.csproj @@ -1,12 +1,15 @@ - true netstandard2.0;$(NetFrameworkCurrent);net461 + + + true + - + diff --git a/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj b/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj index 0712bcb677115a..553fdae9adbd9e 100644 --- a/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj +++ b/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj @@ -1,64 +1,52 @@ - System.Data.Odbc true - true - SR.Odbc_PlatformNotSupported - netcoreapp2.0-FreeBSD;netcoreapp2.0-Linux;netcoreapp2.0-OSX;netcoreapp2.0-Windows_NT;net461-Windows_NT;netstandard2.0;$(NetCoreAppCurrent)-FreeBSD;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-tvOS;$(NetCoreAppCurrent)-Windows_NT;$(NetFrameworkCurrent)-Windows_NT + $(NetCoreAppCurrent)-Windows_NT;netcoreapp2.0-FreeBSD;netcoreapp2.0-Linux;netcoreapp2.0-OSX;netcoreapp2.0-Windows_NT;net461-Windows_NT;netstandard2.0;$(NetCoreAppCurrent)-FreeBSD;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-tvOS;$(NetFrameworkCurrent)-Windows_NT true true - - - Common\System\Data\Common\AdapterUtil.cs - - - System\Data\Common\AdapterUtil.Drivers.cs - + + + true + SR.Odbc_PlatformNotSupported + + + + - - Common\System\Data\Common\DbConnectionOptions.Common.cs - - - System\Data\Common\DbConnectionPoolKey.cs - + + - - Common\System\Data\Common\NameValuePair.cs - + - - Common\System\Data\ProviderBase\FieldNameLookup.cs - - - Common\System\Data\ProviderBase\BasicFieldNameLookup.cs - - - System\Data\ProviderBase\DbConnectionInternal.cs - - - System\Data\ProviderBase\DbConnectionFactory.cs - - - System\Data\ProviderBase\DbConnectionPoolGroup.cs - - - System\Data\ProviderBase\TimeoutTimer.cs - - - System\Data\ProviderBase\DbReferenceCollection.cs - - - System\Data\ProviderBase\DbMetaDataFactory.cs - - - System\Data\ProviderBase\DbConnectionClosed.cs - + + + + + + + + + @@ -112,31 +100,25 @@ - - Common\System\NotImplemented.cs - + - - Common\System\Data\Common\MultipartIdentifier.cs - - - Common\Interop\Interop.Odbc.cs - + + - - Common\Interop\Linux\Interop.Libraries.cs - + - - Common\Interop\OSX\Interop.Libraries.cs - + - - - Common\Interop\Windows\Interop.Libraries.cs - + + @@ -175,7 +157,7 @@ - + @@ -186,4 +168,4 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Data.Odbc/tests/System.Data.Odbc.Tests.csproj b/src/libraries/System.Data.Odbc/tests/System.Data.Odbc.Tests.csproj index 7136986e7836c2..95c97d667a0ae9 100644 --- a/src/libraries/System.Data.Odbc/tests/System.Data.Odbc.Tests.csproj +++ b/src/libraries/System.Data.Odbc/tests/System.Data.Odbc.Tests.csproj @@ -16,29 +16,24 @@ - - Common\Interop\Unix\Interop.Libraries.cs - + - - Common\Interop\Linux\Interop.Libraries.cs - + - - Common\Interop\OSX\Interop.Libraries.cs - + - - Common\Interop\FreeBSD\Interop.Libraries.cs - + - - Common\Interop\Windows\Interop.Libraries.cs - + diff --git a/src/libraries/System.Data.OleDb/ref/System.Data.OleDb.csproj b/src/libraries/System.Data.OleDb/ref/System.Data.OleDb.csproj index bf322a4768a8d1..445fc32cff3d7a 100644 --- a/src/libraries/System.Data.OleDb/ref/System.Data.OleDb.csproj +++ b/src/libraries/System.Data.OleDb/ref/System.Data.OleDb.csproj @@ -1,21 +1,24 @@ - true netstandard2.0;net461;$(NetFrameworkCurrent) true $(NoWarn);0618 + + + true + - + - + - + diff --git a/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj b/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj index 9c2b886ca0671b..799efe243872c3 100644 --- a/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj +++ b/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj @@ -2,20 +2,21 @@ true $(NoWarn);CS1573 - true - SR.PlatformNotSupported_OleDb - $(NoWarn);CS0618 netstandard2.0-Windows_NT;netstandard2.0;net461-Windows_NT;$(NetFrameworkCurrent)-Windows_NT true true - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\System\Data\Common\MultipartIdentifier.cs - + + + true + SR.PlatformNotSupported_OleDb + $(NoWarn);CS0618 + + + + @@ -96,15 +97,15 @@ System.Data.OleDb.OleDbMetaData.xml - + - + - \ No newline at end of file + diff --git a/src/libraries/System.Diagnostics.Contracts/tests/System.Diagnostics.Contracts.Tests.csproj b/src/libraries/System.Diagnostics.Contracts/tests/System.Diagnostics.Contracts.Tests.csproj index 8da4908a1c08f8..4dbef1eb1e0b76 100644 --- a/src/libraries/System.Diagnostics.Contracts/tests/System.Diagnostics.Contracts.Tests.csproj +++ b/src/libraries/System.Diagnostics.Contracts/tests/System.Diagnostics.Contracts.Tests.csproj @@ -11,8 +11,7 @@ - - Common\System\ShouldNotBeInvokedException.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Diagnostics.Debug/tests/System.Diagnostics.Debug.Tests.csproj b/src/libraries/System.Diagnostics.Debug/tests/System.Diagnostics.Debug.Tests.csproj index 93d3bc9a6e6e19..b97ec7f384b6eb 100644 --- a/src/libraries/System.Diagnostics.Debug/tests/System.Diagnostics.Debug.Tests.csproj +++ b/src/libraries/System.Diagnostics.Debug/tests/System.Diagnostics.Debug.Tests.csproj @@ -1,13 +1,12 @@ - System.Diagnostics.Debug.Tests System.Diagnostics.Tests true None $(NetCoreAppCurrent) true - + @@ -15,17 +14,15 @@ - - + + + + + + - - - - - - \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSource.csproj index db385a8be9a166..1766bbf5625361 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSource.csproj @@ -2,12 +2,13 @@ netstandard2.0;netstandard1.1;netstandard1.3;net45;$(NetFrameworkCurrent) true - true false enable - - $(DefineConstants);ALLOW_PARTIALLY_TRUSTED_CALLERS + + + true + $(DefineConstants);ALLOW_PARTIALLY_TRUSTED_CALLERS diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs index 8de9ac09bb0a7e..6428488b65f0d2 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs @@ -7,7 +7,7 @@ namespace System.Diagnostics { - public partial class Activity + public partial class Activity : IDisposable { public Activity(string operationName) { } public System.Diagnostics.ActivityTraceFlags ActivityTraceFlags { get { throw null; } set { } } @@ -33,8 +33,13 @@ public string? Id #endif get { throw null; } } + + public bool IsAllDataRequested { get { throw null; } set { throw null; }} public System.Diagnostics.ActivityIdFormat IdFormat { get { throw null; } } + public System.Diagnostics.ActivityKind Kind { get { throw null; } } public string OperationName { get { throw null; } } + public string DisplayName { get { throw null; } set { throw null; } } + public System.Diagnostics.ActivitySource Source { get { throw null; } } public System.Diagnostics.Activity? Parent { get { throw null; } } public string? ParentId { get { throw null; } } public System.Diagnostics.ActivitySpanId ParentSpanId { get { throw null; } } @@ -43,9 +48,12 @@ public string? Id public System.Diagnostics.ActivitySpanId SpanId { get { throw null; } } public System.DateTime StartTimeUtc { get { throw null; } } public System.Collections.Generic.IEnumerable> Tags { get { throw null; } } + public System.Collections.Generic.IEnumerable Events { get { throw null; } } + public System.Collections.Generic.IEnumerable Links { get { throw null; } } public System.Diagnostics.ActivityTraceId TraceId { get { throw null; } } public string? TraceStateString { get { throw null; } set { } } public System.Diagnostics.Activity AddBaggage(string key, string? value) { throw null; } + public System.Diagnostics.Activity AddEvent(System.Diagnostics.ActivityEvent e) { throw null; } public System.Diagnostics.Activity AddTag(string key, string? value) { throw null; } public string? GetBaggageItem(string key) { throw null; } public System.Diagnostics.Activity SetEndTime(System.DateTime endTimeUtc) { throw null; } @@ -54,7 +62,12 @@ public string? Id public System.Diagnostics.Activity SetParentId(string parentId) { throw null; } public System.Diagnostics.Activity SetStartTime(System.DateTime startTimeUtc) { throw null; } public System.Diagnostics.Activity Start() { throw null; } - public void Stop() { } + public void Stop() { throw null; } + public void Dispose() { throw null; } + protected virtual void Dispose(bool disposing) { throw null; } + public void SetCustomProperty(string propertyName, object? propertyValue) { throw null; } + public object? GetCustomProperty(string propertyName) { throw null; } + public ActivityContext Context { get { throw null; } } } public enum ActivityIdFormat { @@ -82,6 +95,18 @@ public void CopyTo(System.Span destination) { } public string ToHexString() { throw null; } public override string ToString() { throw null; } } + public sealed class ActivitySource : IDisposable + { + public ActivitySource(string name, string? version = "") { throw null; } + public string Name { get { throw null; } } + public string? Version { get { throw null; } } + public bool HasListeners() { throw null; } + public System.Diagnostics.Activity? StartActivity(string name, System.Diagnostics.ActivityKind kind = ActivityKind.Internal) { throw null; } + public System.Diagnostics.Activity? StartActivity(string name, System.Diagnostics.ActivityKind kind, System.Diagnostics.ActivityContext parentContext, System.Collections.Generic.IEnumerable>? tags = null, System.Collections.Generic.IEnumerable? links = null, System.DateTimeOffset startTime = default) { throw null; } + public System.Diagnostics.Activity? StartActivity(string name, System.Diagnostics.ActivityKind kind, string parentId, System.Collections.Generic.IEnumerable>? tags = null, System.Collections.Generic.IEnumerable? links = null, System.DateTimeOffset startTime = default) { throw null; } + public static void AddActivityListener(System.Diagnostics.ActivityListener listener) { throw null; } + public void Dispose() { throw null; } + } [System.FlagsAttribute] public enum ActivityTraceFlags { @@ -121,4 +146,76 @@ public virtual void OnActivityImport(System.Diagnostics.Activity activity, objec public System.Diagnostics.Activity StartActivity(System.Diagnostics.Activity activity, object? args) { throw null; } public void StopActivity(System.Diagnostics.Activity activity, object? args) { } } + public enum ActivityDataRequest + { + None, + PropagationData, + AllData, + AllDataAndRecorded + } + public enum ActivityKind + { + Internal = 0, + Server = 1, + Client = 2, + Producer = 3, + Consumer = 4, + } + public readonly struct ActivityEvent + { + public ActivityEvent(string name) {throw null; } + public ActivityEvent(string name, System.DateTimeOffset timestamp) { throw null; } + public ActivityEvent(string name, System.DateTimeOffset timestamp, System.Collections.Generic.IEnumerable>? attributes) { throw null; } + public ActivityEvent(string name, System.Collections.Generic.IEnumerable>? attributes) { throw null; } + public string Name { get { throw null; } } + public System.DateTimeOffset Timestamp { get { throw null; } } + public System.Collections.Generic.IEnumerable> Attributes { get { throw null; } } + } + public readonly struct ActivityContext : System.IEquatable + { + public ActivityContext(System.Diagnostics.ActivityTraceId traceId, System.Diagnostics.ActivitySpanId spanId, System.Diagnostics.ActivityTraceFlags traceOptions, string? traceState = null) { throw null; } + public System.Diagnostics.ActivityTraceId TraceId { get { throw null; } } + public System.Diagnostics.ActivitySpanId SpanId { get { throw null; } } + public System.Diagnostics.ActivityTraceFlags TraceFlags { get { throw null; } } + public string? TraceState { get { throw null; } } + public static bool operator ==(System.Diagnostics.ActivityContext left, System.Diagnostics.ActivityContext right) { throw null; } + public static bool operator !=(System.Diagnostics.ActivityContext left, System.Diagnostics.ActivityContext right) { throw null; } + public bool Equals(System.Diagnostics.ActivityContext value) { throw null; } + public override bool Equals(object? obj) { throw null; } + public override int GetHashCode() { throw null; } + } + public readonly struct ActivityLink : IEquatable + { + public ActivityLink(System.Diagnostics.ActivityContext context) { throw null; } + public ActivityLink(System.Diagnostics.ActivityContext context, System.Collections.Generic.IEnumerable>? attributes) { throw null; } + public System.Diagnostics.ActivityContext Context { get { throw null; } } + public System.Collections.Generic.IEnumerable>? Attributes { get { throw null; } } + + public override bool Equals(object? obj) { throw null; } + public bool Equals(System.Diagnostics.ActivityLink value) { throw null; } + public static bool operator ==(System.Diagnostics.ActivityLink left, System.Diagnostics.ActivityLink right) { throw null; } + public static bool operator !=(System.Diagnostics.ActivityLink left, System.Diagnostics.ActivityLink right) { throw null; } + public override int GetHashCode() { throw null; } + } + public readonly struct ActivityCreationOptions + { + public System.Diagnostics.ActivitySource Source { get { throw null; } } + public string Name { get { throw null; } } + public System.Diagnostics.ActivityKind Kind { get { throw null; } } + public T Parent { get { throw null; } } + public System.Collections.Generic.IEnumerable> Tags { get { throw null; } } + public System.Collections.Generic.IEnumerable Links { get { throw null; } } + } + public delegate System.Diagnostics.ActivityDataRequest GetRequestedData(ref System.Diagnostics.ActivityCreationOptions options); + public sealed class ActivityListener : IDisposable + { + public ActivityListener() { throw null; } + public System.Action? ActivityStarted { get { throw null; } set { } } + public System.Action? ActivityStopped { get { throw null; } set { } } + public System.Func? ShouldListenTo { get { throw null; } set { } } + public System.Diagnostics.GetRequestedData? GetRequestedDataUsingParentId { get { throw null; } set { } } + public System.Diagnostics.GetRequestedData? GetRequestedDataUsingContext { get { throw null; } set { } } + public void Dispose() { throw null; } + } } + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/Resources/Strings.resx b/src/libraries/System.Diagnostics.DiagnosticSource/src/Resources/Strings.resx index 724068b2dc9e40..18036744326ffb 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/Resources/Strings.resx +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/Resources/Strings.resx @@ -1,17 +1,17 @@  - @@ -144,9 +144,15 @@ "Can not change format for an activity that was already started" + + "Can not add link to activity after it has been started" + "Can not set ParentId on activity which has parent" + + "Invalid SpanId or TraceId" + "StartTime is not UTC" diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index eb0dc38fc393ab..e3bb30d9cea2bc 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -1,37 +1,46 @@ - - netstandard1.1;portable-net45+win8+wpa81 true false $(NoWarn);SA1205 enable - $(DefineConstants);NO_EVENTSOURCE_COMPLEX_TYPE_SUPPORT - $(DefineConstants);EVENTSOURCE_ACTIVITY_SUPPORT - $(DefineConstants);EVENTSOURCE_ENUMERATE_SUPPORT - $(DefineConstants);ALLOW_PARTIALLY_TRUSTED_CALLERS;ENABLE_HTTP_HANDLER $(NetCoreAppCurrent);netstandard1.1;netstandard1.3;net45;net46;netstandard2.0;$(NetFrameworkCurrent) true true + + + + + netstandard1.1;portable-net45+win8+wpa81 + $(DefineConstants);NO_EVENTSOURCE_COMPLEX_TYPE_SUPPORT + $(DefineConstants);EVENTSOURCE_ACTIVITY_SUPPORT + $(DefineConstants);EVENTSOURCE_ENUMERATE_SUPPORT + $(DefineConstants);ALLOW_PARTIALLY_TRUSTED_CALLERS;ENABLE_HTTP_HANDLER true - - Common\System\Runtime\CompilerServices\PreserveDependencyAttribute.cs - + - - Common\System\HexConverter.cs - + + + + + + + + + @@ -45,16 +54,20 @@ - + - + + + - + + + - + @@ -69,7 +82,7 @@ - + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs index b98571feffb22d..8d7fffa0203572 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs @@ -5,6 +5,7 @@ using System.Buffers.Binary; using System.Buffers.Text; using System.Collections.Generic; +using System.Collections.Concurrent; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; @@ -29,11 +30,14 @@ namespace System.Diagnostics /// but the exception is suppressed, and the operation does something reasonable (typically /// doing nothing). /// - public partial class Activity + public partial class Activity : IDisposable { #pragma warning disable CA1825 // Array.Empty() doesn't exist in all configurations private static readonly IEnumerable> s_emptyBaggageTags = new KeyValuePair[0]; + private static readonly IEnumerable s_emptyLinks = new ActivityLink[0]; + private static readonly IEnumerable s_emptyEvents = new ActivityEvent[0]; #pragma warning restore CA1825 + private static readonly ActivitySource s_defaultSource = new ActivitySource(string.Empty); private const byte ActivityTraceFlagsIsSet = 0b_1_0000000; // Internal flag to indicate if flags have been set private const int RequestIdMaxLength = 1024; @@ -70,8 +74,17 @@ public partial class Activity private byte _w3CIdFlags; - private KeyValueListNode? _tags; - private KeyValueListNode? _baggage; + private LinkedList>? _tags; + private LinkedList>? _baggage; + private LinkedList? _links; + private LinkedList? _events; + private ConcurrentDictionary? _customProperties; + private string? _displayName; + + /// + /// Gets the relationship between the Activity, its parents, and its children in a Trace. + /// + public ActivityKind Kind { get; private set; } = ActivityKind.Internal; /// /// An operation name is a COARSEST name that is useful grouping/filtering. @@ -81,6 +94,23 @@ public partial class Activity /// public string OperationName { get; } = null!; + /// Gets or sets the display name of the Activity + /// + /// DisplayName is intended to be used in a user interface and need not be the same as OperationName. + /// + public string DisplayName + { + get => _displayName ?? OperationName; + set => _displayName = value ?? throw new ArgumentNullException(nameof(value)); + } + + /// Get the ActivitySource object associated with this Activity. + /// + /// All Activities created from public constructors will have a singleton source where the source name is an empty string. + /// Otherwise, the source will hold the object that created the Activity through ActivitySource.StartActivity. + /// + public ActivitySource Source { get; private set; } + /// /// If the Activity that created this activity is from the same process you can get /// that Activity with Parent. However, this can be null if the Activity has no @@ -208,29 +238,31 @@ public string? RootId /// /// Tags are string-string key-value pairs that represent information that will - /// be logged along with the Activity to the logging system. This information + /// be logged along with the Activity to the logging system. This information /// however is NOT passed on to the children of this activity. /// /// public IEnumerable> Tags { - get - { - KeyValueListNode? tags = _tags; - return tags != null ? - Iterate(tags) : - s_emptyBaggageTags; + get => _tags != null ? _tags.Enumerate() : s_emptyBaggageTags; + } - static IEnumerable> Iterate(KeyValueListNode? tags) - { - do - { - yield return tags!.keyValue; - tags = tags.Next; - } - while (tags != null); - } - } + /// + /// Events is the list of all objects attached to this Activity object. + /// If there is not any object attached to the Activity object, Events will return empty list. + /// + public IEnumerable Events + { + get => _events != null ? _events.Enumerate() : s_emptyEvents; + } + + /// + /// Links is the list of all objects attached to this Activity object. + /// If there is no any object attached to the Activity object, Links will return empty list. + /// + public IEnumerable Links + { + get => _links != null ? _links.Enumerate() : s_emptyLinks; } /// @@ -260,14 +292,16 @@ public string? RootId Debug.Assert(activity != null); do { - for (KeyValueListNode? baggage = activity._baggage; baggage != null; baggage = baggage.Next) + if (activity._baggage != null) { - yield return baggage.keyValue; + for (LinkedListNode>? current = activity._baggage.First; current != null; current = current.Next) + { + yield return current.Value; + } } activity = activity.Parent; - } - while (activity != null); + } while (activity != null); } } } @@ -293,6 +327,10 @@ public string? RootId /// Operation's name public Activity(string operationName) { + Source = s_defaultSource; + // Allow data by default in the constructor to keep the compatability. + IsAllDataRequested = true; + if (string.IsNullOrEmpty(operationName)) { NotifyError(new ArgumentException(SR.OperationNameInvalid)); @@ -310,13 +348,27 @@ public Activity(string operationName) /// 'this' for convenient chaining public Activity AddTag(string key, string? value) { - KeyValueListNode? currentTags = _tags; - KeyValueListNode newTags = new KeyValueListNode() { keyValue = new KeyValuePair(key, value) }; - do + KeyValuePair kvp = new KeyValuePair(key, value); + + if (_tags != null || Interlocked.CompareExchange(ref _tags, new LinkedList>(kvp), null) != null) + { + _tags.Add(kvp); + } + + return this; + } + + /// + /// Add object to the list. + /// + /// object of to add to the attached events list. + /// 'this' for convenient chaining + public Activity AddEvent(ActivityEvent e) + { + if (_events != null || Interlocked.CompareExchange(ref _events, new LinkedList(e), null) != null) { - newTags.Next = currentTags; - currentTags = Interlocked.CompareExchange(ref _tags, newTags, currentTags); - } while (!ReferenceEquals(newTags.Next, currentTags)); + _events.Add(e); + } return this; } @@ -332,14 +384,12 @@ public Activity AddTag(string key, string? value) /// 'this' for convenient chaining public Activity AddBaggage(string key, string? value) { - KeyValueListNode? currentBaggage = _baggage; - KeyValueListNode newBaggage = new KeyValueListNode() { keyValue = new KeyValuePair(key, value) }; + KeyValuePair kvp = new KeyValuePair(key, value); - do + if (_baggage != null || Interlocked.CompareExchange(ref _baggage, new LinkedList>(kvp), null) != null) { - newBaggage.Next = currentBaggage; - currentBaggage = Interlocked.CompareExchange(ref _baggage, newBaggage, currentBaggage); - } while (!ReferenceEquals(newBaggage.Next, currentBaggage)); + _baggage.Add(kvp); + } return this; } @@ -375,7 +425,7 @@ public Activity SetParentId(string parentId) } /// - /// Set the parent ID using the W3C convention using a TraceId and a SpanId. This + /// Set the parent ID using the W3C convention using a TraceId and a SpanId. This /// constructor has the advantage that no string manipulation is needed to set the ID. /// public Activity SetParentId(ActivityTraceId traceId, ActivitySpanId spanId, ActivityTraceFlags activityTraceFlags = ActivityTraceFlags.None) @@ -437,6 +487,12 @@ public Activity SetEndTime(DateTime endTimeUtc) return this; } + /// + /// Get the context of the activity. Context becomes valid only if the activity has been started. + /// otherwise will default context. + /// + public ActivityContext Context => new ActivityContext(TraceId, SpanId, ActivityTraceFlags, TraceStateString); + /// /// Starts activity /// @@ -464,7 +520,7 @@ public Activity Start() if (parent != null) { // The parent change should not form a loop. We are actually guaranteed this because - // 1. Unstarted activities can't be 'Current' (thus can't be 'parent'), we throw if you try. + // 1. Un-started activities can't be 'Current' (thus can't be 'parent'), we throw if you try. // 2. All started activities have a finite parent change (by inductive reasoning). Parent = parent; } @@ -492,6 +548,8 @@ public Activity Start() _id = GenerateHierarchicalId(); SetCurrent(this); + + Source.NotifyActivityStart(this); } return this; } @@ -521,6 +579,8 @@ public void Stop() } SetCurrent(Parent); + + Source.NotifyActivityStop(this); } } @@ -604,6 +664,12 @@ public ActivityTraceId TraceId /// public bool Recorded { get => (ActivityTraceFlags & ActivityTraceFlags.Recorded) != 0; } + /// + /// Indicate if the this Activity object should be populated with all the propagation info and also all other + /// properties such as Links, Tags, and Events. + /// + public bool IsAllDataRequested { get; set;} + /// /// Return the flags (defined by the W3C ID specification) associated with the activity. /// @@ -718,6 +784,146 @@ private static bool IsW3CId(string id) ('0' <= id[1] && id[1] <= '9' || 'a' <= id[1] && id[1] <= 'e'); } + /// + /// Dispose will stop the Activity if it is already started and notify any event listeners. Nothing will happen otherwise. + /// + public void Dispose() + { + if (!IsFinished) + { + Stop(); + } + + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + + } + + /// + /// SetCustomProperty allow attaching any custom object to this Activity object. + /// If the property name was previously associated with other object, SetCustomProperty will update to use the new propert value instead. + /// + /// The name to associate the value with. + /// The object to attach and map to the property name. + public void SetCustomProperty(string propertyName, object? propertyValue) + { + if (_customProperties == null) + { + Interlocked.CompareExchange(ref _customProperties, new ConcurrentDictionary(), null); + } + + if (propertyValue == null) + { + _customProperties.TryRemove(propertyName, out object _); + } + else + { + _customProperties[propertyName] = propertyValue!; + } + } + + /// + /// GetCustomProperty retrieve previously attached object mapped to the property name. + /// + /// The name to get the associated object with. + /// The object mapped to the property name. Or null if there is no mapping previously done with this property name. + public object? GetCustomProperty(string propertyName) + { + // We don't check null name here as the dictionary is performing this check anyway. + + if (_customProperties == null) + { + return null; + } + + return _customProperties.TryGetValue(propertyName, out object? o) ? o! : null; + } + + internal static Activity CreateAndStart(ActivitySource source, string name, ActivityKind kind, string? parentId, ActivityContext parentContext, + IEnumerable>? tags, IEnumerable? links, + DateTimeOffset startTime, ActivityDataRequest request) + { + Activity activity = new Activity(name); + + activity.Source = source; + activity.Kind = kind; + + if (parentId != null) + { + activity._parentId = parentId; + } + else if (parentContext != default) + { + activity._traceId = parentContext.TraceId.ToString(); + activity._parentSpanId = parentContext.SpanId.ToString(); + activity.ActivityTraceFlags = parentContext.TraceFlags; + activity._traceState = parentContext.TraceState; + } + else + { + Activity? parent = Current; + if (parent != null) + { + // The parent change should not form a loop. We are actually guaranteed this because + // 1. Un-started activities can't be 'Current' (thus can't be 'parent'), we throw if you try. + // 2. All started activities have a finite parent change (by inductive reasoning). + activity.Parent = parent; + } + } + + activity.IdFormat = + ForceDefaultIdFormat ? DefaultIdFormat : + activity.Parent != null ? activity.Parent.IdFormat : + activity._parentSpanId != null ? ActivityIdFormat.W3C : + activity._parentId == null ? DefaultIdFormat : + IsW3CId(activity._parentId) ? ActivityIdFormat.W3C : + ActivityIdFormat.Hierarchical; + + if (activity.IdFormat == ActivityIdFormat.W3C) + activity.GenerateW3CId(); + else + activity._id = activity.GenerateHierarchicalId(); + + if (links != null) + { + using (IEnumerator enumerator = links.GetEnumerator()) + { + if (enumerator.MoveNext()) + { + activity._links = new LinkedList(enumerator); + } + } + } + + if (tags != null) + { + using (IEnumerator> enumerator = tags.GetEnumerator()) + { + if (enumerator.MoveNext()) + { + activity._tags = new LinkedList>(enumerator); + } + } + } + + activity.StartTimeUtc = startTime == default ? DateTime.UtcNow : startTime.DateTime; + + activity.IsAllDataRequested = request == ActivityDataRequest.AllData || request == ActivityDataRequest.AllDataAndRecorded; + + if (request == ActivityDataRequest.AllDataAndRecorded) + { + activity.ActivityTraceFlags |= ActivityTraceFlags.Recorded; + } + + SetCurrent(activity); + + return activity; + } + /// /// Set the ID (lazily, avoiding strings if possible) to a W3C ID (using the /// traceId from the parent if possible @@ -943,13 +1149,54 @@ public ActivityIdFormat IdFormat private set => _state = (_state & ~State.FormatFlags) | (State)((byte)value & (byte)State.FormatFlags); } - /// - /// Having our own key-value linked list allows us to be more efficient - /// - private partial class KeyValueListNode + private partial class LinkedListNode + { + public LinkedListNode(T value) => Value = value; + public T Value; + public LinkedListNode? Next; + } + + // We are not using the public LinkedList because we need to ensure thread safety operation on the list. + private class LinkedList { - public KeyValuePair keyValue; - public KeyValueListNode? Next; + private LinkedListNode _first; + private LinkedListNode _last; + + public LinkedList(T firstValue) => _last = _first = new LinkedListNode(firstValue); + + public LinkedList(IEnumerator e) + { + _last = _first = new LinkedListNode(e.Current); + + while (e.MoveNext()) + { + _last.Next = new LinkedListNode(e.Current); + _last = _last.Next; + } + } + + public LinkedListNode First => _first; + + public void Add(T value) + { + LinkedListNode newNode = new LinkedListNode(value); + + lock (_first) + { + _last.Next = newNode; + _last = newNode; + } + } + + public IEnumerable Enumerate() + { + LinkedListNode? current = _first; + do + { + yield return current.Value; + current = current.Next; + } while (current != null); + } } [Flags] @@ -1218,7 +1465,7 @@ public static ActivitySpanId CreateFromString(ReadOnlySpan idData) } /// - /// Returns the TraceId as a 16 character hexadecimal string. + /// Returns the SpanId as a 16 character hexadecimal string. /// /// public string ToHexString() diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityContext.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityContext.cs new file mode 100644 index 00000000000000..9c242fd87e334f --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityContext.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +namespace System.Diagnostics +{ + /// + /// ActivityContext representation conforms to the w3c TraceContext specification. It contains two identifiers + /// a TraceId and a SpanId - along with a set of common TraceFlags and system-specific TraceState values. + /// + public readonly partial struct ActivityContext : IEquatable + { + /// + /// Construct a new object of ActivityContext. + /// + /// A trace identifier. + /// A span identifier + /// Contain details about the trace. + /// Carries system-specific configuration data. + public ActivityContext(ActivityTraceId traceId, ActivitySpanId spanId, ActivityTraceFlags traceFlags, string? traceState = null) + { + // We don't allow creating context with invalid span or trace Ids. + if (traceId == default || spanId == default) + { + throw new ArgumentException(SR.SpanIdOrTraceIdInvalid, traceId == default ? nameof(traceId) : nameof(spanId)); + } + + TraceId = traceId; + SpanId = spanId; + TraceFlags = traceFlags; + TraceState = traceState; + } + + /// + /// The trace identifier + /// + public ActivityTraceId TraceId { get; } + + /// + /// The span identifier + /// + public ActivitySpanId SpanId { get; } + + /// + /// These flags are defined by the W3C standard along with the ID for the activity. + /// + public ActivityTraceFlags TraceFlags { get; } + + /// + /// Holds the W3C 'tracestate' header as a string. + /// + public string? TraceState { get; } + + public bool Equals(ActivityContext value) => SpanId.Equals(value.SpanId) && TraceId.Equals(value.TraceId) && TraceFlags == value.TraceFlags && TraceState == value.TraceState; + + public override bool Equals(object? obj) => (obj is ActivityContext context) ? Equals(context) : false; + public static bool operator ==(ActivityContext left, ActivityContext right) => left.Equals(right); + public static bool operator !=(ActivityContext left, ActivityContext right) => !(left == right); + } +} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityContext.netcoreapp.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityContext.netcoreapp.cs new file mode 100644 index 00000000000000..ea94205c0001e6 --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityContext.netcoreapp.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Diagnostics +{ + /// + /// ActivityContext representation conforms to the w3c TraceContext specification. It contains two identifiers + /// a TraceId and a SpanId - along with a set of common TraceFlags and system-specific TraceState values. + /// + public readonly partial struct ActivityContext : IEquatable + { + public override int GetHashCode() => HashCode.Combine(TraceId, SpanId, TraceFlags, TraceState); + } +} \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityContext.netfx.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityContext.netfx.cs new file mode 100644 index 00000000000000..a84bad6f3cc743 --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityContext.netfx.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Diagnostics +{ + /// + /// ActivityContext representation conforms to the w3c TraceContext specification. It contains two identifiers + /// a TraceId and a SpanId - along with a set of common TraceFlags and system-specific TraceState values. + /// + public readonly partial struct ActivityContext : IEquatable + { + public override int GetHashCode() + { + if (this == default) + return 0; + + // HashCode.Combine would be the best but we need to compile for the full framework which require adding dependency + // on the extensions package. Considering this simple type and hashing is not expected to be used much, we are implementing + // the hashing manually. + int hash = 5381; + hash = ((hash << 5) + hash) + TraceId.GetHashCode(); + hash = ((hash << 5) + hash) + SpanId.GetHashCode(); + hash = ((hash << 5) + hash) + (int) TraceFlags; + hash = ((hash << 5) + hash) + (TraceState == null ? 0 : TraceState.GetHashCode()); + + return hash; + } + } +} \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityCreationOptions.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityCreationOptions.cs new file mode 100644 index 00000000000000..3483932b86fd48 --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityCreationOptions.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System.Collections.Generic; + +namespace System.Diagnostics +{ + /// + /// ActivityCreationOptions is encapsulating all needed information which will be sent to the ActivityListener to decide about creating the Activity object and with what state. + /// The possible generic type parameters is or + /// + public readonly struct ActivityCreationOptions + { + /// + /// Construct a new object. + /// + /// The trace Activity source used to request creating the Activity object. + /// The operation name of the Activity. + /// The requested parent to create the Activity object with. The parent either be a parent Id represented as string or it can be a parent context . + /// to create the Activity object with. + /// Key-value pairs list for the tags to create the Activity object with. + /// list to create the Activity object with. + internal ActivityCreationOptions(ActivitySource source, string name, T parent, ActivityKind kind, IEnumerable>? tags, IEnumerable? links) + { + Source = source; + Name = name; + Kind = kind; + Parent = parent; + Tags = tags; + Links = links; + } + + /// + /// Retrieve the object. + /// + public ActivitySource Source { get; } + + /// + /// Retrieve the name which requested to create the Activity object with. + /// + public string Name { get; } + + /// + /// Retrieve the which requested to create the Activity object with. + /// + public ActivityKind Kind { get; } + + /// + /// Retrieve the parent which requested to create the Activity object with. Parent will be either in form of string or . + /// + public T Parent { get; } + + /// + /// Retrieve the tags which requested to create the Activity object with. + /// + public IEnumerable>? Tags { get; } + + /// + /// Retrieve the list of which requested to create the Activity object with. + /// + public IEnumerable? Links { get; } + } +} \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityDataRequest.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityDataRequest.cs new file mode 100644 index 00000000000000..96eabcbe86cdd2 --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityDataRequest.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Diagnostics +{ + /// + /// Used by ActivityListener to indicate what amount of data should be collected for this Activity + /// Requesting more data causes greater performance overhead to collect it. + /// + public enum ActivityDataRequest + { + /// + /// The Activity object doesn't need to be created + /// + None, + + /// + /// The Activity object needs to be created. It will have Name, Source, Id and Baggage. + /// Other properties are unnecessary and will be ignored by this listener. + /// + PropagationData, + + /// + /// The activity object should be populated with all the propagation info and also all other + /// properties such as Links, Tags, and Events. Activity.IsAllDataRequested will return true. + /// + AllData, + + /// + /// The activity object should be populated the same as the AllData case and additionally + /// Activity.IsRecorded is set true. For activities using W3C trace ids this sets a flag bit in the + /// ID that will be propagated downstream requesting that trace is recorded everywhere. + /// + AllDataAndRecorded + } +} \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityEvent.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityEvent.cs new file mode 100644 index 00000000000000..27bc3b0ab2367a --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityEvent.cs @@ -0,0 +1,71 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; + +namespace System.Diagnostics +{ + /// + /// A text annotation associated with a collection of attributes. + /// + public readonly struct ActivityEvent + { + private static readonly IEnumerable> s_emptyAttributes = new Dictionary(); + + /// + /// Initializes a new instance of the class. + /// + /// Event name. + public ActivityEvent(string name) : this(name, DateTimeOffset.UtcNow, s_emptyAttributes) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Event name. + /// Event timestamp. Timestamp MUST only be used for the events that happened in the past, not at the moment of this call. + public ActivityEvent(string name, DateTimeOffset timestamp) : this(name, timestamp, s_emptyAttributes) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Event name. + /// Event attributes. + public ActivityEvent(string name, IEnumerable>? attributes) : this(name, default, attributes) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Event name. + /// Event timestamp. Timestamp MUST only be used for the events that happened in the past, not at the moment of this call. + /// Event attributes. + public ActivityEvent(string name, DateTimeOffset timestamp, IEnumerable>? attributes) + { + Name = name ?? string.Empty; + Attributes = attributes ?? s_emptyAttributes; + Timestamp = timestamp != default ? timestamp : DateTimeOffset.UtcNow; + } + + /// + /// Gets the name. + /// + public string Name { get; } + + /// + /// Gets the timestamp. + /// + public DateTimeOffset Timestamp { get; } + + /// + /// Gets the collection of attributes associated with the event. + /// + public IEnumerable> Attributes { get; } + } +} \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityKind.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityKind.cs new file mode 100644 index 00000000000000..8b78298704688b --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityKind.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Diagnostics +{ + /// + /// Kind describes the relationship between the Activity, its parents, and its children in a Trace. + /// -------------------------------------------------------------------------------- + /// ActivityKind Synchronous Asynchronous Remote Incoming Remote Outgoing + /// -------------------------------------------------------------------------------- + /// Internal + /// Client yes yes + /// Server yes yes + /// Producer yes maybe + /// Consumer yes maybe + /// -------------------------------------------------------------------------------- + /// + public enum ActivityKind + { + /// + /// Default value. + /// Indicates that the Activity represents an internal operation within an application, as opposed to an operations with remote parents or children. + /// + Internal = 0, + + /// + /// Server activity represents request incoming from external component. + /// + Server = 1, + + /// + /// Client activity represents outgoing request to the external component. + /// + Client = 2, + + /// + /// Producer activity represents output provided to external components. + /// + Producer = 3, + + /// + /// Consumer activity represents output received from an external component. + /// + Consumer = 4, + } +} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityLink.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityLink.cs new file mode 100644 index 00000000000000..920459e5083548 --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityLink.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +namespace System.Diagnostics +{ + /// + /// Activity may be linked to zero or more other that are causally related. + /// Links can point to ActivityContexts inside a single Trace or across different Traces. + /// Links can be used to represent batched operations where a Activity was initiated by multiple initiating Activities, + /// each representing a single incoming item being processed in the batch. + /// + public readonly partial struct ActivityLink : IEquatable + { + /// + /// Construct a new object which can be linked to an Activity object. + /// + /// The trace Activity context + public ActivityLink(ActivityContext context) : this(context, null) {} + + /// + /// Construct a new object which can be linked to an Activity object. + /// + /// The trace Activity context + /// The key-value pair list of attributes which associated to the + public ActivityLink(ActivityContext context, IEnumerable>? attributes) + { + Context = context; + Attributes = attributes; + } + + /// + /// Retrieve the object inside this object. + /// + public ActivityContext Context { get; } + + /// + /// Retrieve the key-value pair list of attributes attached with the . + /// + public IEnumerable>? Attributes { get; } + + public override bool Equals(object? obj) => (obj is ActivityLink link) && this.Equals(link); + + public bool Equals(ActivityLink value) => Context == value.Context && value.Attributes == Attributes; + public static bool operator ==(ActivityLink left, ActivityLink right) => left.Equals(right); + public static bool operator !=(ActivityLink left, ActivityLink right) => !left.Equals(right); + } +} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityLink.netcoreapp.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityLink.netcoreapp.cs new file mode 100644 index 00000000000000..62f1af752e4dc4 --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityLink.netcoreapp.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +namespace System.Diagnostics +{ + /// + /// Activity may be linked to zero or more other that are causally related. + /// Links can point to ActivityContexts inside a single Trace or across different Traces. + /// Links can be used to represent batched operations where a Activity was initiated by multiple initiating Activities, + /// each representing a single incoming item being processed in the batch. + /// + public readonly partial struct ActivityLink : IEquatable + { + public override int GetHashCode() + { + HashCode hashCode = default; + hashCode.Add(Context); + if (Attributes != null) + { + foreach (KeyValuePair kvp in Attributes) + { + hashCode.Add(kvp.Key); + hashCode.Add(kvp.Value); + } + } + return hashCode.ToHashCode(); + } + } +} \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityLink.netfx.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityLink.netfx.cs new file mode 100644 index 00000000000000..678e1d73a66beb --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityLink.netfx.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +namespace System.Diagnostics +{ + /// + /// Activity may be linked to zero or more other that are causally related. + /// Links can point to ActivityContexts inside a single Trace or across different Traces. + /// Links can be used to represent batched operations where a Activity was initiated by multiple initiating Activities, + /// each representing a single incoming item being processed in the batch. + /// + public readonly partial struct ActivityLink : IEquatable + { + public override int GetHashCode() + { + if (this == default) + return 0; + + // HashCode.Combine would be the best but we need to compile for the full framework which require adding dependency + // on the extensions package. Considering this simple type and hashing is not expected to be used, we are implementing + // the hashing manually. + int hash = 5381; + hash = ((hash << 5) + hash) + this.Context.GetHashCode(); + if (Attributes != null) + { + foreach (KeyValuePair kvp in Attributes) + { + hash = ((hash << 5) + hash) + kvp.Key.GetHashCode(); + if (kvp.Value != null) + { + hash = ((hash << 5) + hash) + kvp.Value.GetHashCode(); + } + } + } + return hash; + } + } +} \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityListener.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityListener.cs new file mode 100644 index 00000000000000..5c07128a2d0c14 --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivityListener.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; + +namespace System.Diagnostics +{ + /// + /// Define the callback that can be used in to allow deciding to create the Activity objects and with what data state. + /// + public delegate ActivityDataRequest GetRequestedData(ref ActivityCreationOptions options); + + /// + /// ActivityListener allows listening to the start and stop Activity events and give the oppertunity to decide creating the Activity for sampling scenarios. + /// + public sealed class ActivityListener : IDisposable + { + /// + /// Construct a new object to start listeneing to the events. + /// + public ActivityListener() + { + } + + /// + /// Set or get the callback used to listen to the start event. + /// + public Action? ActivityStarted { get; set; } + + /// + /// Set or get the callback used to listen to the stop event. + /// + public Action? ActivityStopped { get; set; } + + /// + /// Set or get the callback used to decide if want to listen to objects events which created using object. + /// + public Func? ShouldListenTo { get; set; } + + /// + /// Set or get the callback used to decide allowing creating objects with specific data state. + /// + public GetRequestedData? GetRequestedDataUsingParentId { get; set; } + + /// + /// Set or get the callback used to decide allowing creating objects with specific data state. + /// + public GetRequestedData? GetRequestedDataUsingContext { get; set; } + + /// + /// Dispose will unregister this object from listeneing to events. + /// + public void Dispose() => ActivitySource.DetachListener(this); + } +} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivitySource.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivitySource.cs new file mode 100644 index 00000000000000..dcf750c32b0785 --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivitySource.cs @@ -0,0 +1,355 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using System.Collections.Generic; + +namespace System.Diagnostics +{ + public sealed class ActivitySource : IDisposable + { + private static readonly SynchronizedList s_activeSources = new SynchronizedList(); + private static readonly SynchronizedList s_allListeners = new SynchronizedList(); + private SynchronizedList? _listeners; + + /// + /// Construct an ActivitySource object with the input name + /// + /// The name of the ActivitySource object + /// The version of the component publishing the tracing info. + public ActivitySource(string name, string? version = "") + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + Name = name; + Version = version; + + s_activeSources.Add(this); + + if (s_allListeners.Count > 0) + { + s_allListeners.EnumWithAction(listener => { + var shouldListenTo = listener.ShouldListenTo; + if (shouldListenTo != null && shouldListenTo(this)) + { + AddListener(listener); + } + }); + } + } + + /// + /// Returns the ActivitySource name. + /// + public string Name { get; } + + /// + /// Returns the ActivitySource version. + /// + public string? Version { get; } + + /// + /// Check if there is any listeners for this ActivitySource. + /// This property can be helpful to tell if there is no listener, then no need to create Activity object + /// and avoid creating the objects needed to create Activity (e.g. ActivityContext) + /// Example of that is http scenario which can avoid reading the context data from the wire. + /// + public bool HasListeners() + { + SynchronizedList? listeners = _listeners; + return listeners != null && listeners.Count > 0; + } + + /// + /// Creates a new object if there is any listener to the Activity, returns null otherwise. + /// + /// The operation name of the Activity + /// The + /// The created object or null if there is no any event listener. + public Activity? StartActivity(string name, ActivityKind kind = ActivityKind.Internal) + => StartActivity(name, kind, default, null, null, null, default); + + /// + /// Creates a new object if there is any listener to the Activity events, returns null otherwise. + /// + /// The operation name of the Activity. + /// The + /// The parent object to initialize the created Activity object with. + /// The optional tags list to initialize the created Activity object with. + /// The optional list to initialize the created Activity object with. + /// The optional start timestamp to set on the created Activity object. + /// The created object or null if there is no any listener. + public Activity? StartActivity(string name, ActivityKind kind, ActivityContext parentContext, IEnumerable>? tags = null, IEnumerable? links = null, DateTimeOffset startTime = default) + => StartActivity(name, kind, parentContext, null, tags, links, startTime); + + /// + /// Creates a new object if there is any listener to the Activity events, returns null otherwise. + /// + /// The operation name of the Activity. + /// The + /// The parent Id to initialize the created Activity object with. + /// The optional tags list to initialize the created Activity object with. + /// The optional list to initialize the created Activity object with. + /// The optional start timestamp to set on the created Activity object. + /// The created object or null if there is no any listener. + public Activity? StartActivity(string name, ActivityKind kind, string parentId, IEnumerable>? tags = null, IEnumerable? links = null, DateTimeOffset startTime = default) + => StartActivity(name, kind, default, parentId, tags, links, startTime); + + private Activity? StartActivity(string name, ActivityKind kind, ActivityContext context, string? parentId, IEnumerable>? tags, IEnumerable? links, DateTimeOffset startTime) + { + // _listeners can get assigned to null in Dispose. + SynchronizedList? listeners = _listeners; + if (listeners == null || listeners.Count == 0) + { + return null; + } + + Activity? activity = null; + + ActivityDataRequest dateRequest = ActivityDataRequest.None; + + if (parentId != null) + { + listeners.EnumWithFunc(listener => { + var getRequestedDataUsingParentId = listener.GetRequestedDataUsingParentId; + if (getRequestedDataUsingParentId != null) + { + ActivityCreationOptions aco = new ActivityCreationOptions(this, name, parentId, kind, tags, links); + ActivityDataRequest dr = getRequestedDataUsingParentId(ref aco); + if (dr > dateRequest) + { + dateRequest = dr; + } + + // Stop the enumeration if we get the max value RecordingAndSampling. + return dateRequest != ActivityDataRequest.AllDataAndRecorded; + } + return true; + }); + } + else + { + listeners.EnumWithFunc(listener => { + var getRequestedDataUsingContext = listener.GetRequestedDataUsingContext; + if (getRequestedDataUsingContext != null) + { + ActivityCreationOptions aco = new ActivityCreationOptions(this, name, context, kind, tags, links); + ActivityDataRequest dr = getRequestedDataUsingContext(ref aco); + if (dr > dateRequest) + { + dateRequest = dr; + } + + // Stop the enumeration if we get the max value RecordingAndSampling. + return dateRequest != ActivityDataRequest.AllDataAndRecorded; + } + return true; + }); + } + + if (dateRequest != ActivityDataRequest.None) + { + activity = Activity.CreateAndStart(this, name, kind, parentId, context, tags, links, startTime, dateRequest); + listeners.EnumWithAction(listener => { + var activityStarted = listener.ActivityStarted; + if (activityStarted != null) + { + activityStarted(activity); + } + }); + } + + return activity; + } + + /// + /// Dispose the ActivitySource object and remove the current instance from the global list. empty the listeners list too. + /// + public void Dispose() + { + _listeners = null; + s_activeSources.Remove(this); + } + + /// + /// Add a listener to the starting and stopping events. + /// + /// The object to use for listeneing to the events. + public static void AddActivityListener(ActivityListener listener) + { + if (listener == null) + { + throw new ArgumentNullException(nameof(listener)); + } + + if (s_allListeners.AddIfNotExist(listener)) + { + s_activeSources.EnumWithAction(source => { + var shouldListenTo = listener.ShouldListenTo; + if (shouldListenTo != null && shouldListenTo(source)) + { + source.AddListener(listener); + } + }); + } + } + + internal void AddListener(ActivityListener listener) + { + if (_listeners == null) + { + Interlocked.CompareExchange(ref _listeners, new SynchronizedList(), null); + } + + _listeners.AddIfNotExist(listener); + } + + internal static void DetachListener(ActivityListener listener) + { + s_allListeners.Remove(listener); + + s_activeSources.EnumWithAction(source => { + var listeners = source._listeners; + listeners?.Remove(listener); + }); + } + + internal void NotifyActivityStart(Activity activity) + { + Debug.Assert(activity != null); + + // _listeners can get assigned to null in Dispose. + SynchronizedList? listeners = _listeners; + if (listeners != null && listeners.Count > 0) + { + listeners.EnumWithAction(listener => listener.ActivityStarted?.Invoke(activity)); + } + } + + internal void NotifyActivityStop(Activity activity) + { + Debug.Assert(activity != null); + + // _listeners can get assigned to null in Dispose. + SynchronizedList? listeners = _listeners; + if (listeners != null && listeners.Count > 0) + { + listeners.EnumWithAction(listener => { + listeners.EnumWithAction(listener => listener.ActivityStopped?.Invoke(activity)); + }); + } + } + } + + // SynchronizedList is a helper collection which ensure thread safety on the collection + // and allow enumerating the collection items and execute some action on the enumerated item and can detect any change in the collection + // during the enumeration which force restarting the enumeration again. + // Caution: We can have the action executed on the same item more than once which is ok in our scenarios. + internal class SynchronizedList + { + private readonly List _list; + private uint _version; + + public SynchronizedList() => _list = new List(); + + public void Add(T item) + { + lock (_list) + { + _list.Add(item); + _version++; + } + } + + public bool AddIfNotExist(T item) + { + lock (_list) + { + if (!_list.Contains(item)) + { + _list.Add(item); + _version++; + return true; + } + return false; + } + } + + public bool Remove(T item) + { + lock (_list) + { + if (_list.Remove(item)) + { + _version++; + return true; + } + return false; + } + } + + public int Count => _list.Count; + + public void EnumWithFunc(Func func) + { + uint version = _version; + int index = 0; + + while (index < _list.Count) + { + T item; + lock (_list) + { + if (version != _version) + { + version = _version; + index = 0; + continue; + } + + item = _list[index]; + index++; + } + + // Important to call the func outside the lock. + // This is the whole point we are having this wrapper class. + if (!func(item)) + { + break; + } + } + } + + public void EnumWithAction(Action action) + { + uint version = _version; + int index = 0; + + while (index < _list.Count) + { + T item; + lock (_list) + { + if (version != _version) + { + version = _version; + index = 0; + continue; + } + + item = _list[index]; + index++; + } + + // Important to call the action outside the lock. + // This is the whole point we are having this wrapper class. + action(item); + } + } + + } +} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticListener.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticListener.cs index bfaeb3f406fbc2..9710efe818ea4b 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticListener.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagnosticListener.cs @@ -279,7 +279,7 @@ private class DiagnosticSubscription : IDisposable // - IsEnabled1Arg invoked for DiagnosticSource.IsEnabled(string) // - IsEnabled3Arg invoked for DiagnosticSource.IsEnabled(string, obj, obj) // Subscriber MUST set both IsEnabled1Arg and IsEnabled3Arg or none of them: - // when Predicate is provided in DiagosticListener.Subscribe, + // when Predicate is provided in DiagnosticListener.Subscribe, // - IsEnabled1Arg is set to predicate // - IsEnabled3Arg falls back to predicate ignoring extra arguments. // similarly, when Func is provided, diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivitySourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivitySourceTests.cs new file mode 100644 index 00000000000000..639629a798cc64 --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivitySourceTests.cs @@ -0,0 +1,365 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Reflection; +using System.Threading.Tasks; +using Microsoft.DotNet.RemoteExecutor; +using Xunit; + +namespace System.Diagnostics.Tests +{ + public class ActivitySourceTests : IDisposable + { + [Fact] + public void TestConstruction() + { + RemoteExecutor.Invoke(() => { + using (ActivitySource as1 = new ActivitySource("Source1")) + { + Assert.Equal("Source1", as1.Name); + Assert.Equal(String.Empty, as1.Version); + Assert.False(as1.HasListeners()); + using (ActivitySource as2 = new ActivitySource("Source2", "1.1.1.2")) + { + Assert.Equal("Source2", as2.Name); + Assert.Equal("1.1.1.2", as2.Version); + Assert.False(as2.HasListeners()); + } + } + }).Dispose(); + } + + [Fact] + public void TestStartActivityWithNoListener() + { + RemoteExecutor.Invoke(() => { + using (ActivitySource aSource = new ActivitySource("SourceActivity")) + { + Assert.Equal("SourceActivity", aSource.Name); + Assert.Equal(string.Empty, aSource.Version); + Assert.False(aSource.HasListeners()); + + Activity current = Activity.Current; + using (Activity a1 = aSource.StartActivity("a1")) + { + // no listeners, we should get null activity. + Assert.Null(a1); + Assert.Equal(Activity.Current, current); + } + } + }).Dispose(); + } + + [Fact] + public void TestActivityWithListenerNoActivityCreate() + { + RemoteExecutor.Invoke(() => { + using (ActivitySource aSource = new ActivitySource("SourceActivityListener")) + { + Assert.False(aSource.HasListeners()); + + using (ActivityListener listener = new ActivityListener + { + ActivityStarted = activity => Assert.NotNull(activity), + ActivityStopped = activity => Assert.NotNull(activity), + ShouldListenTo = (activitySource) => object.ReferenceEquals(aSource, activitySource), + GetRequestedDataUsingParentId = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.None, + GetRequestedDataUsingContext = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.None + } + ) + { + ActivitySource.AddActivityListener(listener); + Assert.True(aSource.HasListeners()); + + // The listener is not allowing to create a new Activity. + Assert.Null(aSource.StartActivity("nullActivity")); + } + } + }).Dispose(); + } + + [Fact] + public void TestActivityWithListenerActivityCreateAndAllDataRequested() + { + RemoteExecutor.Invoke(() => { + using (ActivitySource aSource = new ActivitySource("SourceActivityListener")) + { + int counter = 0; + Assert.False(aSource.HasListeners()); + + using (ActivityListener listener = new ActivityListener + { + ActivityStarted = activity => counter++, + ActivityStopped = activity => counter--, + ShouldListenTo = (activitySource) => object.ReferenceEquals(aSource, activitySource), + GetRequestedDataUsingParentId = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.AllDataAndRecorded, + GetRequestedDataUsingContext = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.AllDataAndRecorded + } + ) + { + ActivitySource.AddActivityListener(listener); + + Assert.True(aSource.HasListeners()); + + using (Activity activity = aSource.StartActivity("AllDataRequestedActivity")) + { + Assert.NotNull(activity); + Assert.True(activity.IsAllDataRequested); + Assert.Equal(1, counter); + + Assert.Equal(0, activity.Tags.Count()); + Assert.Equal(0, activity.Baggage.Count()); + + Assert.True(object.ReferenceEquals(activity, activity.AddTag("key", "value"))); + Assert.True(object.ReferenceEquals(activity, activity.AddBaggage("key", "value"))); + + Assert.Equal(1, activity.Tags.Count()); + Assert.Equal(1, activity.Baggage.Count()); + + using (Activity activity1 = aSource.StartActivity("AllDataRequestedActivity1")) + { + Assert.NotNull(activity1); + Assert.True(activity1.IsAllDataRequested); + Assert.Equal(2, counter); + + Assert.Equal(0, activity1.Links.Count()); + Assert.Equal(0, activity1.Events.Count()); + Assert.True(object.ReferenceEquals(activity1, activity1.AddEvent(new ActivityEvent("e1")))); + Assert.Equal(1, activity1.Events.Count()); + } + Assert.Equal(1, counter); + } + + Assert.Equal(0, counter); + } + } + }).Dispose(); + } + + [Fact] + public void TestActivitySourceAttachedObject() + { + RemoteExecutor.Invoke(() => { + // All Activities created through the constructor should have same source. + Assert.True(object.ReferenceEquals(new Activity("a1").Source, new Activity("a2").Source)); + Assert.Equal("", new Activity("a3").Source.Name); + Assert.Equal(string.Empty, new Activity("a4").Source.Version); + + using (ActivitySource aSource = new ActivitySource("SourceToTest", "1.2.3.4")) + { + //Ensure at least we have a listener to allow Activity creation + using (ActivityListener listener = new ActivityListener + { + ActivityStarted = activity => Assert.NotNull(activity), + ActivityStopped = activity => Assert.NotNull(activity), + ShouldListenTo = (activitySource) => object.ReferenceEquals(aSource, activitySource), + GetRequestedDataUsingParentId = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.AllData, + GetRequestedDataUsingContext = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.AllData + } + ) + { + ActivitySource.AddActivityListener(listener); + + using (Activity activity = aSource.StartActivity("ActivityToTest")) + { + Assert.True(object.ReferenceEquals(aSource, activity.Source)); + } + } + } + }).Dispose(); + } + + [Fact] + public void TestListeningToConstructedActivityEvents() + { + RemoteExecutor.Invoke(() => { + int activityStartCount = 0; + int activityStopCount = 0; + + using (ActivityListener listener = new ActivityListener + { + ActivityStarted = activity => activityStartCount++, + ActivityStopped = activity => activityStopCount++, + ShouldListenTo = (activitySource) => activitySource.Name == "" && activitySource.Version == "", + GetRequestedDataUsingParentId = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.AllData, + GetRequestedDataUsingContext = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.AllData + } + ) + { + ActivitySource.AddActivityListener(listener); + + Assert.Equal(0, activityStartCount); + Assert.Equal(0, activityStopCount); + + using (Activity a1 = new Activity("a1")) + { + Assert.Equal(0, activityStartCount); + Assert.Equal(0, activityStopCount); + + a1.Start(); + + Assert.Equal(1, activityStartCount); + Assert.Equal(0, activityStopCount); + } + + Assert.Equal(1, activityStartCount); + Assert.Equal(1, activityStopCount); + } + + // Ensure the listener is disposed + using (Activity a2 = new Activity("a2")) + { + a2.Start(); + + Assert.Equal(1, activityStartCount); + Assert.Equal(1, activityStopCount); + } + }).Dispose(); + } + + [Fact] + public void TestExpectedListenersReturnValues() + { + RemoteExecutor.Invoke(() => { + + ActivitySource source = new ActivitySource("MultipleListenerSource"); + ActivityListener [] listeners = new ActivityListener[4]; + + listeners[0] = new ActivityListener + { + ActivityStarted = activity => Assert.NotNull(activity), + ActivityStopped = activity => Assert.NotNull(activity), + ShouldListenTo = (activitySource) => true, + GetRequestedDataUsingParentId = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.None, + GetRequestedDataUsingContext = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.None + }; + ActivitySource.AddActivityListener(listeners[0]); + + Assert.Null(source.StartActivity("a1")); + + listeners[1] = new ActivityListener + { + ActivityStarted = activity => Assert.NotNull(activity), + ActivityStopped = activity => Assert.NotNull(activity), + ShouldListenTo = (activitySource) => true, + GetRequestedDataUsingParentId = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.PropagationData, + GetRequestedDataUsingContext = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.PropagationData + }; + ActivitySource.AddActivityListener(listeners[1]); + + using (Activity a2 = source.StartActivity("a2")) + { + Assert.False(a2.IsAllDataRequested); + Assert.True((a2.ActivityTraceFlags & ActivityTraceFlags.Recorded) == 0); + } + + listeners[2] = new ActivityListener + { + ActivityStarted = activity => Assert.NotNull(activity), + ActivityStopped = activity => Assert.NotNull(activity), + ShouldListenTo = (activitySource) => true, + GetRequestedDataUsingParentId = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.AllData, + GetRequestedDataUsingContext = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.AllData + }; + ActivitySource.AddActivityListener(listeners[2]); + + using (Activity a3 = source.StartActivity("a3")) + { + Assert.True(a3.IsAllDataRequested); + Assert.True((a3.ActivityTraceFlags & ActivityTraceFlags.Recorded) == 0); + } + + listeners[3] = new ActivityListener + { + ActivityStarted = activity => Assert.NotNull(activity), + ActivityStopped = activity => Assert.NotNull(activity), + ShouldListenTo = (activitySource) => true, + GetRequestedDataUsingParentId = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.AllDataAndRecorded, + GetRequestedDataUsingContext = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.AllDataAndRecorded + }; + ActivitySource.AddActivityListener(listeners[3]); + + using (Activity a4 = source.StartActivity("a4")) + { + Assert.True(a4.IsAllDataRequested); + Assert.True((a4.ActivityTraceFlags & ActivityTraceFlags.Recorded) != 0, $"a4.ActivityTraceFlags failed: {a4.ActivityTraceFlags}"); + } + + foreach (IDisposable listener in listeners) + { + listener.Dispose(); + } + + Assert.Null(source.StartActivity("a5")); + }).Dispose(); + } + + [Fact] + public void TestActivityCreationProperties() + { + RemoteExecutor.Invoke(() => { + ActivitySource source = new ActivitySource("MultipleListenerSource"); + + using (ActivityListener listener = new ActivityListener + { + ActivityStarted = activity => Assert.NotNull(activity), + ActivityStopped = activity => Assert.NotNull(activity), + ShouldListenTo = (activitySource) => true, + GetRequestedDataUsingParentId = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.AllData, + GetRequestedDataUsingContext = (ref ActivityCreationOptions activityOptions) => ActivityDataRequest.AllData + } + ) + { + ActivitySource.AddActivityListener(listener); + + ActivityContext ctx = new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded, "key0-value0"); + + List links = new List(); + links.Add(new ActivityLink(new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None, "key1-value1"))); + links.Add(new ActivityLink(new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None, "key2-value2"))); + + List> attributes = new List>(); + attributes.Add(new KeyValuePair("tag1", "tagValue1")); + attributes.Add(new KeyValuePair("tag2", "tagValue2")); + attributes.Add(new KeyValuePair("tag3", "tagValue3")); + + using (Activity activity = source.StartActivity("a1", ActivityKind.Client, ctx, attributes, links)) + { + Assert.NotNull(activity); + Assert.Equal("a1", activity.OperationName); + Assert.Equal("a1", activity.DisplayName); + Assert.Equal(ActivityKind.Client, activity.Kind); + + Assert.Equal(ctx.TraceId, activity.TraceId); + Assert.Equal(ctx.SpanId, activity.ParentSpanId); + Assert.Equal(ctx.TraceFlags, activity.ActivityTraceFlags); + Assert.Equal(ctx.TraceState, activity.TraceStateString); + Assert.Equal(ActivityIdFormat.W3C, activity.IdFormat); + + foreach (KeyValuePair pair in attributes) + { + Assert.NotEqual(default, activity.Tags.FirstOrDefault((p) => pair.Key == p.Key && pair.Value == pair.Value)); + } + + foreach (ActivityLink link in links) + { + Assert.NotEqual(default, activity.Links.FirstOrDefault((l) => link == l)); + } + } + + using (Activity activity = source.StartActivity("a2", ActivityKind.Client, "NoW3CParentId", attributes, links)) + { + Assert.Equal(ActivityIdFormat.Hierarchical, activity.IdFormat); + } + } + }).Dispose(); + } + public void Dispose() => Activity.Current = null; + } +} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs index 153990a6ee49b0..11dd57028538f4 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs @@ -7,6 +7,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading; +using System.Reflection; using System.Threading.Tasks; using Microsoft.DotNet.RemoteExecutor; using Xunit; @@ -84,9 +85,9 @@ public void Baggage() Assert.Equal("world", anotherActivity.GetBaggageItem("hello")); Assert.Equal(4, anotherActivity.Baggage.Count()); Assert.Equal(new KeyValuePair("hello", "world"), anotherActivity.Baggage.First()); - Assert.Equal(new KeyValuePair(Key + 2, Value + 2), anotherActivity.Baggage.Skip(1).First()); + Assert.Equal(new KeyValuePair(Key + 0, Value + 0), anotherActivity.Baggage.Skip(1).First()); Assert.Equal(new KeyValuePair(Key + 1, Value + 1), anotherActivity.Baggage.Skip(2).First()); - Assert.Equal(new KeyValuePair(Key + 0, Value + 0), anotherActivity.Baggage.Skip(3).First()); + Assert.Equal(new KeyValuePair(Key + 2, Value + 2), anotherActivity.Baggage.Skip(3).First()); } finally { @@ -115,8 +116,8 @@ public void Tags() Assert.Equal(activity, activity.AddTag(Key + i, Value + i)); List> tags = activity.Tags.ToList(); Assert.Equal(i + 1, tags.Count); - Assert.Equal(tags[tags.Count - i - 1].Key, Key + i); - Assert.Equal(tags[tags.Count - i - 1].Value, Value + i); + Assert.Equal(tags[i].Key, Key + i); + Assert.Equal(tags[i].Value, Value + i); } } @@ -1347,6 +1348,88 @@ public void ActivityCurrentNotSetToStopped() Assert.Same(started, Activity.Current); } + [Fact] + public void TestDispose() + { + Activity current = Activity.Current; + using (Activity activity = new Activity("Mine").Start()) + { + Assert.Same(activity, Activity.Current); + Assert.Same(current, activity.Parent); + } + + Assert.Same(current, Activity.Current); + } + + [Fact] + public void TestCustomProperties() + { + Activity activity = new Activity("Custom"); + activity.SetCustomProperty("P1", "Prop1"); + activity.SetCustomProperty("P2", "Prop2"); + activity.SetCustomProperty("P3", null); + + Assert.Equal("Prop1", activity.GetCustomProperty("P1")); + Assert.Equal("Prop2", activity.GetCustomProperty("P2")); + Assert.Null(activity.GetCustomProperty("P3")); + Assert.Null(activity.GetCustomProperty("P4")); + + activity.SetCustomProperty("P1", "Prop5"); + Assert.Equal("Prop5", activity.GetCustomProperty("P1")); + + } + + [Fact] + public void TestKind() + { + Activity activity = new Activity("Kind"); + Assert.Equal(ActivityKind.Internal, activity.Kind); + } + + [Fact] + public void TestDisplayName() + { + Activity activity = new Activity("Op1"); + Assert.Equal("Op1", activity.OperationName); + Assert.Equal("Op1", activity.DisplayName); + + activity.DisplayName = "Op2"; + Assert.Equal("Op1", activity.OperationName); + Assert.Equal("Op2", activity.DisplayName); + } + + [Fact] + public void TestEvent() + { + Activity activity = new Activity("EventTest"); + Assert.Equal(0, activity.Events.Count()); + + DateTimeOffset ts1 = DateTimeOffset.UtcNow; + DateTimeOffset ts2 = ts1.AddMinutes(1); + + Assert.True(object.ReferenceEquals(activity, activity.AddEvent(new ActivityEvent("Event1", ts1)))); + Assert.True(object.ReferenceEquals(activity, activity.AddEvent(new ActivityEvent("Event2", ts2)))); + + Assert.Equal(2, activity.Events.Count()); + Assert.Equal("Event1", activity.Events.ElementAt(0).Name); + Assert.Equal(ts1, activity.Events.ElementAt(0).Timestamp); + Assert.Equal(0, activity.Events.ElementAt(0).Attributes.Count()); + + Assert.Equal("Event2", activity.Events.ElementAt(1).Name); + Assert.Equal(ts2, activity.Events.ElementAt(1).Timestamp); + Assert.Equal(0, activity.Events.ElementAt(1).Attributes.Count()); + } + + [Fact] + public void TestIsAllDataRequested() + { + // Activity constructor allways set IsAllDataRequested to true for compatability. + Activity a1 = new Activity("a1"); + Assert.True(a1.IsAllDataRequested); + Assert.True(object.ReferenceEquals(a1, a1.AddTag("k1", "v1"))); + Assert.Equal(1, a1.Tags.Count()); + } + public void Dispose() { Activity.Current = null; diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj index 09d3a0d5d7f1b9..ed8d7de3079d1b 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj @@ -3,21 +3,20 @@ true $(NetCoreAppCurrent);$(NetFrameworkCurrent)-Windows_NT - + + - + - - Common\System\Net\Configuration.cs - - - Common\System\Net\Configuration.Http.cs - + + \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.EventLog/ref/System.Diagnostics.EventLog.csproj b/src/libraries/System.Diagnostics.EventLog/ref/System.Diagnostics.EventLog.csproj index e3957915d4e645..4a6216abc116c6 100644 --- a/src/libraries/System.Diagnostics.EventLog/ref/System.Diagnostics.EventLog.csproj +++ b/src/libraries/System.Diagnostics.EventLog/ref/System.Diagnostics.EventLog.csproj @@ -1,20 +1,23 @@ - true $(NetFrameworkCurrent);net461;netstandard2.0 + + + true + - + - + - + \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.EventLog/src/System.Diagnostics.EventLog.csproj b/src/libraries/System.Diagnostics.EventLog/src/System.Diagnostics.EventLog.csproj index 7bf58b00f29540..db056eb6bf9843 100644 --- a/src/libraries/System.Diagnostics.EventLog/src/System.Diagnostics.EventLog.csproj +++ b/src/libraries/System.Diagnostics.EventLog/src/System.Diagnostics.EventLog.csproj @@ -1,13 +1,16 @@ true - true - SR.PlatformNotSupported_EventLog - netcoreapp2.0-Windows_NT;net461;netstandard2.0;$(NetCoreAppCurrent)-Windows_NT;$(NetFrameworkCurrent) + $(NetCoreAppCurrent)-Windows_NT;netcoreapp2.0-Windows_NT;net461;netstandard2.0;$(NetFrameworkCurrent) true true - + + + true + SR.PlatformNotSupported_EventLog + + @@ -53,76 +56,55 @@ - - Common\Interop\Windows\Kernel32\Interop.CloseHandle.cs - - - Common\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs - - - Common\Interop\Windows\Advapi32\Interop.ClearEventLog.cs - - - Common\Interop\Windows\Advapi32\Interop.CloseEventLog.cs - - - Common\Interop\Windows\Advapi32\Interop.DeregisterEventSource.cs - - - Common\Interop\Windows\Advapi32\Interop.GetNumberOfEventLogRecords.cs - - - Common\Interop\Windows\Advapi32\Interop.GetOldestEventLogRecord.cs - - - Common\Interop\Windows\Advapi32\Interop.LookupAccountSid.cs - - - Common\Interop\Windows\Advapi32\Interop.NotifyChangeEventLog.cs - - - Common\Interop\Windows\Advapi32\Interop.OpenEventLog.cs - - - Common\Interop\Windows\Advapi32\Interop.ReadEventLog.cs - - - Common\Interop\Windows\Advapi32\Interop.RegisterEventSource.cs - - - Common\Interop\Windows\Advapi32\Interop.ReportEvent.cs - - - Common\Interop\Windows\Kernel32\Interop.Constants.cs - - - Common\Interop\Windows\Kernel32\Interop.FormatMessage_SafeLibraryHandle.cs - - - Common\Interop\Windows\Kernel32\Interop.FreeLibrary.cs - - - Common\Interop\Windows\Kernel32\Interop.LoadLibraryEx.cs - - - Common\Interop\Windows\Kernel32\Interop.WaitForSingleObject.cs - - - Common\Interop\Windows\Interop.Errors.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\System\Diagnostics\NetFrameworkUtils.cs - + + + + + + + + + + + + + + + + + + + + + - + - + diff --git a/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/ProviderMetadataCachedInformation.cs b/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/ProviderMetadataCachedInformation.cs index 8e49408433beaa..9b02652d605267 100644 --- a/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/ProviderMetadataCachedInformation.cs +++ b/src/libraries/System.Diagnostics.EventLog/src/System/Diagnostics/Reader/ProviderMetadataCachedInformation.cs @@ -156,7 +156,6 @@ private ProviderMetadata GetProviderMetadata(ProviderMetadataId key) try { - pm.CheckReleased(); UpdateCacheValueInfoForHit(cacheItem); } catch (EventLogException) diff --git a/src/libraries/System.Diagnostics.EventLog/tests/EventLogTests/EventLogSourceCreationTests.cs b/src/libraries/System.Diagnostics.EventLog/tests/EventLogTests/EventLogSourceCreationTests.cs index 29bfba9dcbe8b4..eaaa6160bb0d5d 100644 --- a/src/libraries/System.Diagnostics.EventLog/tests/EventLogTests/EventLogSourceCreationTests.cs +++ b/src/libraries/System.Diagnostics.EventLog/tests/EventLogTests/EventLogSourceCreationTests.cs @@ -3,13 +3,11 @@ // See the LICENSE file in the project root for more information. using Xunit; -using Microsoft.DotNet.XUnitExtensions; namespace System.Diagnostics.Tests { public class EventLogSourceCreationTests { - [Trait(XunitConstants.Category, "EventLog")] // Unreliable Win32 API call [ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] public void CheckSourceExistenceAndDeletion() { @@ -23,13 +21,13 @@ public void CheckSourceExistenceAndDeletion() finally { EventLog.DeleteEventSource(source); - Helpers.Retry(() => EventLog.Delete(log)); // unlike other tests, throw if delete fails + if (EventLog.Exists(log)) + Helpers.Retry(() => EventLog.Delete(log)); } Assert.False(EventLog.SourceExists(source)); } - [Trait(XunitConstants.Category, "EventLog")] // Unreliable Win32 API call [ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] public void LogNameWithSame8FirstChars_NetCore() @@ -50,13 +48,15 @@ public void LogNameWithSame8FirstChars_NetCore() finally { EventLog.DeleteEventSource(firstSource); - Helpers.Retry(() => EventLog.Delete(firstLog)); + if (EventLog.Exists(firstLog)) + Helpers.Retry(() => EventLog.Delete(firstLog)); + EventLog.DeleteEventSource(secondSource); - Helpers.Retry(() => EventLog.Delete(secondLog)); + if (EventLog.Exists(secondLog)) + Helpers.Retry(() => EventLog.Delete(secondLog)); } } - [Trait(XunitConstants.Category, "EventLog")] // Unreliable Win32 API call [ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)] public void LogNameWithSame8FirstChars_NetFramework() @@ -75,7 +75,8 @@ public void LogNameWithSame8FirstChars_NetFramework() finally { EventLog.DeleteEventSource(firstSource); - Helpers.Retry(() => EventLog.Delete(firstLog)); + if (EventLog.Exists(firstLog)) + Helpers.Retry(() => EventLog.Delete(firstLog)); } } @@ -145,7 +146,6 @@ public void SourceDataNull() Assert.Throws(() => EventLog.CreateEventSource(null)); } - [Trait(XunitConstants.Category, "EventLog")] // Unreliable Win32 API call [ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] public void SourceAlreadyExistsWhenCreatingSource() { @@ -160,7 +160,8 @@ public void SourceAlreadyExistsWhenCreatingSource() finally { EventLog.DeleteEventSource(source); - Helpers.RetrySilently(() => EventLog.Delete(log)); + if (EventLog.Exists(log)) + Helpers.RetrySilently(() => EventLog.Delete(log)); } } diff --git a/src/libraries/System.Diagnostics.FileVersionInfo/System.Diagnostics.FileVersionInfo.sln b/src/libraries/System.Diagnostics.FileVersionInfo/System.Diagnostics.FileVersionInfo.sln index 2766ba07345566..c5ef898a0f672b 100644 --- a/src/libraries/System.Diagnostics.FileVersionInfo/System.Diagnostics.FileVersionInfo.sln +++ b/src/libraries/System.Diagnostics.FileVersionInfo/System.Diagnostics.FileVersionInfo.sln @@ -40,7 +40,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{9624A23D-A470-496B-BEEA-D1E7DCE8BFA3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{9624A23D-A470-496B-BEEA-D1E7DCE8BFA3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Reflection.Metadata", "..\System.Reflection.Metadata\src\System.Reflection.Metadata.csproj", "{A1132F6D-4D68-4E23-B35C-FDBE12C04D99}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -80,6 +82,10 @@ Global {9624A23D-A470-496B-BEEA-D1E7DCE8BFA3}.Debug|Any CPU.Build.0 = Debug|Any CPU {9624A23D-A470-496B-BEEA-D1E7DCE8BFA3}.Release|Any CPU.ActiveCfg = Release|Any CPU {9624A23D-A470-496B-BEEA-D1E7DCE8BFA3}.Release|Any CPU.Build.0 = Release|Any CPU + {A1132F6D-4D68-4E23-B35C-FDBE12C04D99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1132F6D-4D68-4E23-B35C-FDBE12C04D99}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1132F6D-4D68-4E23-B35C-FDBE12C04D99}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1132F6D-4D68-4E23-B35C-FDBE12C04D99}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -93,6 +99,7 @@ Global {00EDA5FD-E802-40D3-92D5-56C27612D36D} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {F815A563-B6B8-49F3-9E90-1A134033B864} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} {9624A23D-A470-496B-BEEA-D1E7DCE8BFA3} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} + {A1132F6D-4D68-4E23-B35C-FDBE12C04D99} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A1E658C8-446E-42A1-BD77-7FD02C2CD549} diff --git a/src/libraries/System.Diagnostics.FileVersionInfo/src/System.Diagnostics.FileVersionInfo.csproj b/src/libraries/System.Diagnostics.FileVersionInfo/src/System.Diagnostics.FileVersionInfo.csproj index e2a81f05dd6719..956061590cb80a 100644 --- a/src/libraries/System.Diagnostics.FileVersionInfo/src/System.Diagnostics.FileVersionInfo.csproj +++ b/src/libraries/System.Diagnostics.FileVersionInfo/src/System.Diagnostics.FileVersionInfo.csproj @@ -11,42 +11,31 @@ - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.FileVersionInfo.cs - - - Common\Interop\Windows\Interop.FileVersionInfoType.cs - - - Common\Interop\Windows\Interop.GetFileVersionInfoEx.cs - - - Common\Interop\Windows\Interop.GetFileVersionInfoSizeEx.cs - - - Common\Interop\Windows\Interop.VerLanguageName.cs - - - Common\Interop\Windows\Interop.VerQueryValue.cs - - - Common\Interop\Windows\Interop.VSFixedFileInfo.cs - + + + + + + + + - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\Interop.Errors.cs - - - Common\Interop\Unix\Interop.Stat.cs - + + + @@ -59,4 +48,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Diagnostics.FileVersionInfo/src/System/Diagnostics/FileVersionInfo.Unix.cs b/src/libraries/System.Diagnostics.FileVersionInfo/src/System/Diagnostics/FileVersionInfo.Unix.cs index 661b0092b25373..842ba39e86b79a 100644 --- a/src/libraries/System.Diagnostics.FileVersionInfo/src/System/Diagnostics/FileVersionInfo.Unix.cs +++ b/src/libraries/System.Diagnostics.FileVersionInfo/src/System/Diagnostics/FileVersionInfo.Unix.cs @@ -11,8 +11,6 @@ namespace System.Diagnostics { public sealed partial class FileVersionInfo { - private static readonly char[] s_versionSeparators = new char[] { '.' }; - private FileVersionInfo(string fileName) { _fileName = fileName; @@ -204,7 +202,7 @@ private static void ParseVersion(string? versionString, out int major, out int m if (versionString != null) { - string[] parts = versionString.Split(s_versionSeparators); + string[] parts = versionString.Split('.'); if (parts.Length <= 4 && parts.Length > 0) { major = ParseUInt16UntilNonDigit(parts[0], out bool endedEarly); diff --git a/src/libraries/System.Diagnostics.FileVersionInfo/tests/System.Diagnostics.FileVersionInfo.Tests/System.Diagnostics.FileVersionInfo.Tests.csproj b/src/libraries/System.Diagnostics.FileVersionInfo/tests/System.Diagnostics.FileVersionInfo.Tests/System.Diagnostics.FileVersionInfo.Tests.csproj index ca49d982ae802e..2ea787c2fa9049 100644 --- a/src/libraries/System.Diagnostics.FileVersionInfo/tests/System.Diagnostics.FileVersionInfo.Tests/System.Diagnostics.FileVersionInfo.Tests.csproj +++ b/src/libraries/System.Diagnostics.FileVersionInfo/tests/System.Diagnostics.FileVersionInfo.Tests/System.Diagnostics.FileVersionInfo.Tests.csproj @@ -24,12 +24,10 @@ - - ProductionCode\Common\Interop\Windows\Interop.Libraries.cs - - - ProductionCode\Common\Interop\Windows\Kernel32\Interop.VerLanguageName.cs - + + diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.csproj b/src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.csproj index 9dd662dce81159..d7a3700fc963ce 100644 --- a/src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.csproj +++ b/src/libraries/System.Diagnostics.PerformanceCounter/ref/System.Diagnostics.PerformanceCounter.csproj @@ -1,13 +1,16 @@ - true netstandard2.0;net461;$(NetFrameworkCurrent) true + + + true + - + diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj b/src/libraries/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj index 2e1be8425bad80..5c19edbe2729b6 100644 --- a/src/libraries/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj +++ b/src/libraries/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj @@ -2,13 +2,16 @@ AnyCPU true - true - SR.PlatformNotSupported_PerfCounters - netcoreapp2.0-Windows_NT;netstandard2.0;net461;$(NetCoreAppCurrent)-Windows_NT;$(NetFrameworkCurrent) + $(NetCoreAppCurrent)-Windows_NT;netcoreapp2.0-Windows_NT;netstandard2.0;net461;$(NetFrameworkCurrent) true true - + + + true + SR.PlatformNotSupported_PerfCounters + + @@ -39,133 +42,93 @@ - - Common\Interop\Windows\Interop.BOOL.cs - - - Common\Interop\Windows\Interop.FormatMessage.cs - - - Common\Interop\Windows\Interop.RegCloseKey.cs - - - Common\Interop\Windows\Advapi32\Interop.RegQueryValueEx.cs - - - Microsoft\Win32\SafeHandles\SafeRegistryHandle.cs - - - Microsoft\Win32\SafeHandles\SafeRegistryHandle.Windows.cs - - - Common\Interop\Windows\Interop.Errors.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Advapi32\Interop.ConvertStringSecurityDescriptorToSecurityDescriptor.cs - - - Common\Interop\Windows\Advapi32\Interop.GetTokenInformation.cs - - - Common\Interop\Windows\Advapi32\Interop.PERF_INFO.cs - - - Common\Interop\Windows\Advapi32\Interop.ProcessOptions.cs - - - Common\Interop\Windows\Advapi32\Interop.RegConnectRegistry.cs - - - Common\Interop\Windows\Advapi32\Interop.TOKEN_INFORMATION_CLASS.cs - - - Common\Interop\Windows\Kernel32\Interop.Constants.cs - - - Common\Interop\Windows\Kernel32\Interop.CreateFileMapping.cs - - - Common\Interop\Windows\kernel32\Interop.DuplicateHandle.cs - - - Common\Interop\Windows\Kernel32\Interop.FreeLibrary.cs - - - Common\Interop\Windows\Kernel32\Interop.GetComputerName.cs - - - Common\Interop\Windows\kernel32\Interop.GetCurrentProcess.cs - - - Common\Interop\Windows\Kernel32\Interop.GetCurrentProcessId.cs - - - Common\Interop\Windows\Kernel32\Interop.GetProcessTimes.cs - - - Common\Interop\Windows\Kernel32\Interop.HandleOptions.cs - - - Common\Interop\Windows\Kernel32\Interop.LoadLibrary.cs - - - Common\Interop\Windows\Kernel32\Interop.MapViewOfFile.cs - - - Common\Interop\Windows\Kernel32\Interop.MemOptions.cs - - - Common\Interop\Windows\Kernel32\Interop.MEMORY_BASIC_INFO.cs - - - Common\Interop\Windows\Kernel32\Interop.OpenFileMapping.cs - - - Common\Interop\Windows\Kernel32\Interop.OpenProcess.cs - - - Common\Interop\Windows\Kernel32\Interop.PerformanceCounterOptions.cs - - - Common\Interop\Windows\Kernel32\Interop.ProcessWaitHandle.cs - - - Common\Interop\Windows\Kernel32\Interop.SECURITY_ATTRIBUTES.cs - - - Common\Interop\Windows\Kernel32\Interop.UnmapViewOfFile.cs - - - Common\Interop\Windows\Kernel32\Interop.VirtualQuery.cs - - - Common\Interop\Windows\Kernel32\Interop.WaitForSingleObject.cs - - - Common\Interop\Windows\PerfCounter\Interop.FormatFromRawValue.cs - - - Common\Interop\Windows\PerfCounter\Interop.PerformanceData.cs - - - Common\Microsoft\Win32\SafeHandles\SafeLocalAllocHandle.cs - - - Common\Microsoft\Win32\SafeHandles\SafePerfProviderHandle.cs - - - Common\System\Diagnostics\NetFrameworkUtils.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounter.cs b/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounter.cs index f1637f4998c360..37e4b41d98a4fa 100644 --- a/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounter.cs +++ b/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounter.cs @@ -470,9 +470,9 @@ private void InitializeImpl() string currentCategoryName = _categoryName; string currentMachineName = _machineName; - if (currentCategoryName == string.Empty) + if (currentCategoryName.Length == 0) throw new InvalidOperationException(SR.CategoryNameMissing); - if (_counterName == string.Empty) + if (_counterName.Length == 0) throw new InvalidOperationException(SR.CounterNameMissing); if (ReadOnly) diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounterLib.cs b/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounterLib.cs index 93ad673af15cba..7facea0fcdd6c7 100644 --- a/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounterLib.cs +++ b/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounterLib.cs @@ -455,7 +455,7 @@ private static void CreateIniFile(string categoryName, string categoryHelp, Coun iniWriter.Write(languageId); iniWriter.Write(HelpSufix); iniWriter.Write("="); - if (categoryHelp == null || categoryHelp == string.Empty) + if (string.IsNullOrEmpty(categoryHelp)) iniWriter.WriteLine(SR.HelpNotAvailable); else iniWriter.WriteLine(categoryHelp); diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceData/CounterSet.cs b/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceData/CounterSet.cs index 13ac7471b69685..3a62324c074619 100644 --- a/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceData/CounterSet.cs +++ b/src/libraries/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceData/CounterSet.cs @@ -195,7 +195,7 @@ public CounterSetInstance CreateCounterSetInstance(string instanceName) { if (_provider == null) { - throw new ArgumentException(SR.Format(SR.Perflib_Argument_ProviderNotFound, _providerGuid), "ProviderGuid"); + throw new InvalidOperationException(SR.Format(SR.Perflib_InvalidOperation_NoActiveProvider, _providerGuid)); } if (_provider._hProvider.IsInvalid) { @@ -256,7 +256,7 @@ public CounterSetInstance CreateCounterSetInstance(string instanceName) { throw Status switch { - (uint)Interop.Errors.ERROR_ALREADY_EXISTS => new ArgumentException(SR.Format(SR.Perflib_Argument_CounterSetAlreadyRegister, _counterSet), "CounterSetGuid"), + (uint)Interop.Errors.ERROR_ALREADY_EXISTS => new InvalidOperationException(SR.Format(SR.Perflib_Argument_CounterSetAlreadyRegister, _counterSet)), _ => new Win32Exception((int)Status), }; diff --git a/src/libraries/System.Diagnostics.PerformanceCounter/tests/System.Diagnostics.PerformanceCounter.Tests.csproj b/src/libraries/System.Diagnostics.PerformanceCounter/tests/System.Diagnostics.PerformanceCounter.Tests.csproj index a301f85bfc55a2..2e5d90aaaab9c9 100644 --- a/src/libraries/System.Diagnostics.PerformanceCounter/tests/System.Diagnostics.PerformanceCounter.Tests.csproj +++ b/src/libraries/System.Diagnostics.PerformanceCounter/tests/System.Diagnostics.PerformanceCounter.Tests.csproj @@ -13,9 +13,8 @@ - - Common\System\ShouldNotBeInvokedException.cs - + diff --git a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj index f6e156df516380..33d388e4441a40 100644 --- a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj +++ b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj @@ -1,7 +1,6 @@ AnyCPU - System.Diagnostics.Process $(DefineConstants);FEATURE_REGISTRY true $(NoWarn);CS1573 @@ -33,262 +32,178 @@ - - Common\System\Runtime\Serialization\SerializationGuard.cs - - - System\PasteArguments.cs - - - Common\Interop\Windows\Interop.Errors.cs - - - Common\System\Threading\Tasks\TaskCompletionSourceWithCancellation.cs - + + + + - - Common\Interop\Windows\Kernel32\Interop.EnumProcessModules.cs - - - Common\Interop\Windows\NtDll\Interop.NtQueryInformationProcess.cs - - - Common\Interop\Windows\NtDll\Interop.NtQuerySystemInformation.cs - - - Common\Interop\Windows\NtDll\Interop.PROCESS_BASIC_INFORMATION.cs - - - Common\Interop\Windows\NtDll\Interop.SYSTEM_PROCESS_INFORMATION.cs - - - Common\Interop\Windows\User32\Interop.EnumWindows.cs - - - Common\Interop\Windows\User32\Interop.GetWindow.cs - - - Common\Interop\Windows\User32\Interop.GetWindowLong.cs - - - Common\Interop\Windows\User32\Interop.GetWindowTextLengthW.cs - - - Common\Interop\Windows\User32\Interop.GetWindowTextW.cs - - - Common\Interop\Windows\User32\Interop.GetWindowThreadProcessId.cs - - - Common\Interop\Windows\User32\Interop.PostMessage.cs - - - Common\Interop\Windows\User32\Interop.IsWindowVisible.cs - - - Common\Interop\Windows\User32\Interop.SendMessageTimeout.cs - - - Common\Interop\Windows\User32\Interop.WaitForInputIdle.cs - + + + + + + + + + + + + + + + - - Microsoft\Win32\SafeHandles\SafeTokenHandle.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Kernel32\Interop.CloseHandle.cs - - - Common\Interop\Windows\Advapi32\Interop.PERF_INFO.cs - - - Common\Interop\Windows\Kernel32\Interop.IsWow64Process_SafeProcessHandle.cs - - - Common\Interop\Windows\Kernel32\Interop.GetExitCodeProcess.cs - - - Common\Interop\Windows\Kernel32\Interop.GetProcessTimes.cs - - - Common\Interop\Windows\Kernel32\Interop.GetThreadTimes.cs - - - Common\Interop\Windows\Kernel32\Interop.GetStdHandle.cs - - - Common\Interop\Windows\Kernel32\Interop.CreateProcess.cs - - - Common\Interop\Windows\Kernel32\Interop.TerminateProcess.cs - - - Common\Interop\Windows\kernel32\Interop.GetCurrentProcess.cs - - - Common\Interop\Windows\Kernel32\Interop.OpenProcess.cs - - - Common\Interop\Windows\Kernel32\Interop.EnumProcesses.cs - - - Common\Interop\Windows\Kernel32\Interop.GetModuleInformation.cs - - - Common\Interop\Windows\Kernel32\Interop.GetModuleBaseName.cs - - - Common\Interop\Windows\Kernel32\Interop.GetModuleFileNameEx.cs - - - Common\Interop\Windows\Kernel32\Interop.SetProcessWorkingSetSizeEx.cs - - - Common\Interop\Windows\Kernel32\Interop.GetProcessWorkingSetSizeEx.cs - - - Common\Interop\Windows\Kernel32\Interop.SetProcessAffinityMask.cs - - - Common\Interop\Windows\Kernel32\Interop.GetProcessAffinityMask.cs - - - Common\Interop\Windows\Kernel32\Interop.GetProcessId.cs - - - Common\Interop\Windows\Kernel32\Interop.GetThreadPriorityBoost.cs - - - Common\Interop\Windows\Kernel32\Interop.SetThreadPriorityBoost.cs - - - Common\Interop\Windows\Kernel32\Interop.GetProcessPriorityBoost.cs - - - Common\Interop\Windows\Kernel32\Interop.SetProcessPriorityBoost.cs - - - Common\Interop\Windows\Kernel32\Interop.OpenThread.cs - - - Common\Interop\Windows\Kernel32\Interop.SetThreadPriority.cs - - - Common\Interop\Windows\Kernel32\Interop.GetThreadPriority.cs - - - Common\Interop\Windows\Kernel32\Interop.SetThreadAffinityMask.cs - - - Common\Interop\Windows\Kernel32\Interop.SetThreadIdealProcessor.cs - - - Common\Interop\Windows\Kernel32\Interop.GetPriorityClass.cs - - - Common\Interop\Windows\Kernel32\Interop.SetPriorityClass.cs - - - Common\Interop\Windows\kernel32\Interop.DuplicateHandle.cs - - - Common\Interop\Windows\Kernel32\Interop.ProcessWaitHandle.cs - - - Common\Interop\Windows\Advapi32\Interop.OpenProcessToken.cs - - - Common\Interop\Windows\Advapi32\Interop.LookupPrivilegeValue.cs - - - Common\Interop\Windows\Advapi32\Interop.AdjustTokenPrivileges.cs - - - Common\Interop\Windows\Kernel32\Interop.GetComputerName.cs - - - Common\Interop\Windows\Kernel32\Interop.GetCurrentProcessId.cs - - - Common\Interop\Windows\Kernel32\Interop.GetConsoleCP.cs - - - Common\Interop\Windows\Kernel32\Interop.GetConsoleOutputCP.cs - - - Common\Interop\Windows\Advapi32\Interop.CreateProcessWithLogon.cs - - - Common\Interop\Windows\Interop.BOOL.cs - - - Common\Interop\Windows\Kernel32\Interop.SECURITY_ATTRIBUTES.cs - - - Common\Interop\Windows\Advapi32\Interop.LUID.cs - - - Common\Interop\Windows\Advapi32\Interop.LUID_AND_ATTRIBUTES.cs - - - Common\Interop\Windows\Advapi32\Interop.TOKEN_PRIVILEGE.cs - - - Common\Interop\Windows\Kernel32\Interop.Constants.cs - - - Common\Interop\Windows\kernel32\Interop.CreatePipe.cs - - - Common\Interop\Windows\Kernel32\Interop.ThreadOptions.cs - - - Common\Interop\Windows\Kernel32\Interop.HandleTypes.cs - - - Common\Interop\Windows\Advapi32\Interop.ProcessOptions.cs - - - Common\Interop\Windows\kernel32\Interop.ProcessOptions.cs - - - Common\Interop\Windows\Kernel32\Interop.MultiByteToWideChar.cs - - - Common\Interop\Interop.UNICODE_STRING.cs - - - Common\Interop\Windows\Kernel32\Interop.WideCharToMultiByte.cs - - - Common\System\Text\ConsoleEncoding.cs - - - Common\System\Text\EncodingHelper.Windows.cs - - - Common\System\Text\OSEncoding.Windows.cs - - - Common\System\Text\OSEncoder.cs - - - Common\System\Text\DBCSDecoder.cs - - - Common\Interop\Windows\Kernel32\Interop.GetCPInfoEx.cs - - - Common\Interop\Windows\Interop.MAX_PATH.cs - - - Common\System\HResults.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -306,101 +221,71 @@ - - Common\System\Text\ValueStringBuilder.cs - - - Common\System\IO\StringParser.cs - - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\Interop.Errors.cs - - - Common\Interop\Unix\Interop.Close.cs - - - Common\Interop\Unix\Interop.GetHostName.cs - - - Common\Interop\Unix\Interop.SysConf.cs - - - Common\Interop\Unix\Interop.ConfigureTerminalForChildProcess.cs - - - Common\Interop\Unix\Interop.ForkAndExecProcess.cs - - - Common\Interop\Unix\Interop.GetGroupList.cs - - - Common\Interop\Unix\Interop.GetLine.cs - - - Common\Interop\Unix\Interop.GetPid.cs - - - Common\Interop\Unix\Interop.GetPwUid.cs - - - Common\Interop\Unix\Interop.GetSetPriority.cs - - - Common\Interop\Unix\Interop.GetSid.cs - - - Common\Interop\Unix\Interop.GetUid.cs - - - Common\Interop\Unix\Interop.InitializeTerminalAndSignalHandling.cs - - - Common\Interop\Unix\Interop.Kill.cs - - - Common\Interop\Unix\Interop.ReadLink.cs - - - Common\Interop\Unix\Interop.RegisterForRegisterForSigChld.cs - - - Common\Interop\Unix\Interop.ResourceLimits.cs - - - Common\Interop\Unix\Interop.PathConf.cs - - - Common\Interop\Unix\Interop.POpen.cs - - - Common\Interop\Unix\Interop.WaitId.cs - - - Common\Interop\Unix\Interop.WaitPid.cs - - - Common\Interop\Unix\System.Native\Interop.Access.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + - - Common\Interop\Linux\Interop.cgroups.cs - - - Common\Interop\Linux\Interop.ProcFsStat.cs - - - Common\Interop\Linux\Interop.SchedGetSetAffinity.cs - - - Common\System\Text\ReusableTextReader.cs - + + + + @@ -408,17 +293,14 @@ - - Common\Interop\OSX\Interop.libproc.cs - - - Common\Interop\OSX\Interop.Libraries.cs - + + - - Common\Interop\Windows\Shell32\Interop.ShellExecuteExW.cs - + @@ -432,15 +314,12 @@ - - Common\Interop\BSD\System.Native\Interop.Sysctl.cs - - - Common\Interop\FreeBSD\Interop.Process.cs - - - Common\Unix\System.Native\Interop.Stat.cs - + + + @@ -458,8 +337,10 @@ + + diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs index 129963c07793ce..29ec30ccdd885e 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.IO; +using System.Net.Sockets; using System.Security; using System.Text; using System.Threading; @@ -761,16 +762,15 @@ internal static TimeSpan TicksToTimeSpan(double ticks) return TimeSpan.FromSeconds(ticks / (double)ticksPerSecond); } - /// Opens a stream around the specified file descriptor and with the specified access. - /// The file descriptor. + /// Opens a stream around the specified socket file descriptor and with the specified access. + /// The socket file descriptor. /// The access mode. /// The opened stream. - private static FileStream OpenStream(int fd, FileAccess access) + private static Stream OpenStream(int fd, FileAccess access) { Debug.Assert(fd >= 0); - return new FileStream( - new SafeFileHandle((IntPtr)fd, ownsHandle: true), - access, StreamBufferSize, isAsync: false); + var socket = new Socket(new SafeSocketHandle((IntPtr)fd, ownsHandle: true)); + return new NetworkStream(socket, access, ownsSocket: true); } /// Parses a command-line argument string into a list of arguments. diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs index 998ec9fa03f5c7..af85258d6a9ea4 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs @@ -536,7 +536,7 @@ private unsafe bool StartWithCreateProcess(ProcessStartInfo startInfo) environmentBlock = GetEnvironmentVariablesBlock(startInfo._environmentVariables!); } string workingDirectory = startInfo.WorkingDirectory; - if (workingDirectory == string.Empty) + if (workingDirectory.Length == 0) workingDirectory = Directory.GetCurrentDirectory(); bool retVal; diff --git a/src/libraries/System.Diagnostics.Process/tests/Helpers.cs b/src/libraries/System.Diagnostics.Process/tests/Helpers.cs index f762e00d5cfa39..0e12a1e534c1c8 100644 --- a/src/libraries/System.Diagnostics.Process/tests/Helpers.cs +++ b/src/libraries/System.Diagnostics.Process/tests/Helpers.cs @@ -12,6 +12,8 @@ namespace System.Diagnostics.Tests { internal static class Helpers { + public const int PassingTestTimeoutMilliseconds = 60_000; + public static async Task RetryWithBackoff(Action action, int delayInMilliseconds = 10, int times = 10) { // Guards against delay growing to an exceptionally large value. No special technical significance to @@ -36,5 +38,15 @@ public static async Task RetryWithBackoff(Action action, int delayInMilliseconds } } } + + public static void DumpAllProcesses() + { + Process[] all = Process.GetProcesses(); + foreach (Process p in all) + { + Console.WriteLine("{0,8} {1}", p.Id, p.ProcessName); + p.Dispose(); + } + } } } diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessStreamReadTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessStreamReadTests.cs index 8fac2af7d9b854..0fb4160d7eacb4 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessStreamReadTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessStreamReadTests.cs @@ -314,6 +314,42 @@ async private Task WaitPipeSignal(PipeStream pipe, int millisecond) } } + [PlatformSpecific(~TestPlatforms.Windows)] // currently on Windows these operations async-over-sync on Windows + [Fact] + public async Task ReadAsync_OutputStreams_Cancel_RespondsQuickly() + { + Process p = CreateProcessLong(); + try + { + p.StartInfo.RedirectStandardOutput = true; + p.StartInfo.RedirectStandardError = true; + Assert.True(p.Start()); + + using (var cts = new CancellationTokenSource()) + { + ValueTask vt = p.StandardOutput.ReadAsync(new char[1].AsMemory(), cts.Token); + await Task.Delay(1); + Assert.False(vt.IsCompleted); + cts.Cancel(); + await Assert.ThrowsAnyAsync(async () => await vt); + } + + using (var cts = new CancellationTokenSource()) + { + ValueTask vt = p.StandardError.ReadAsync(new char[1].AsMemory(), cts.Token); + await Task.Delay(1); + Assert.False(vt.IsCompleted); + cts.Cancel(); + await Assert.ThrowsAnyAsync(async () => await vt); + } + } + finally + { + p.Kill(); + p.Dispose(); + } + } + [Fact] public void TestSyncStreams() { diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.Unix.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.Unix.cs index 4e38d973a2d7c5..1944afa59968a3 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.Unix.cs @@ -817,7 +817,7 @@ public async Task Kill_ExitedNonChildProcess_DoesNotThrow(bool killTree) { // In this test, we kill a process in a way the Process instance // is not aware the process has terminated when we invoke Process.Kill. - + DateTime start = DateTime.UtcNow; using (Process nonChildProcess = CreateNonChildProcess()) { // Kill the process. @@ -833,6 +833,15 @@ public async Task Kill_ExitedNonChildProcess_DoesNotThrow(bool killTree) // process still exists, wait some time. await Task.Delay(100); } + + DateTime now = DateTime.UtcNow; + if (start.Ticks + (Helpers.PassingTestTimeoutMilliseconds * 10_000) <= now.Ticks) + { + Console.WriteLine("{0} Failed to kill process {1} started at {2}", now, nonChildProcess.Id, start); + Helpers.DumpAllProcesses(); + + Assert.True(false, "test timed out"); + } } // Call Process.Kill. diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs index 1b5eb65f043a28..167776c769ee1f 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs @@ -2119,7 +2119,7 @@ public void Kill_ExitedChildProcess_DoesNotThrow(bool killTree) Process process = CreateProcess(); process.Start(); - process.WaitForExit(); + Assert.True(process.WaitForExit(Helpers.PassingTestTimeoutMilliseconds), $"Proccess {process.Id} did not finish in {Helpers.PassingTestTimeoutMilliseconds}."); process.Kill(killTree); } diff --git a/src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj b/src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj index e2f3f7ad84f9f2..4abf44898ce809 100644 --- a/src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj +++ b/src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj @@ -6,18 +6,14 @@ $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix - - System\PasteArguments.cs - - - Common\System\IO\StringParser.cs - - - Common\System\ShouldNotBeInvokedException.cs - - - Common\Microsoft\Win32\TempRegistryKey.cs - + + + + @@ -37,15 +33,13 @@ - - System\PasteArguments.Windows.cs - + - - System\PasteArguments.Unix.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Diagnostics.StackTrace/System.Diagnostics.StackTrace.sln b/src/libraries/System.Diagnostics.StackTrace/System.Diagnostics.StackTrace.sln index a054d350640683..666faf8fa7ee57 100644 --- a/src/libraries/System.Diagnostics.StackTrace/System.Diagnostics.StackTrace.sln +++ b/src/libraries/System.Diagnostics.StackTrace/System.Diagnostics.StackTrace.sln @@ -20,7 +20,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{854C7BBD-8B87-44AE-B109-421647CD5959}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{854C7BBD-8B87-44AE-B109-421647CD5959}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Collections.Concurrent", "..\System.Collections.Concurrent\src\System.Collections.Concurrent.csproj", "{ADDF4CDC-9F80-492C-85B5-908E34B64D74}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.FileSystem", "..\System.IO.FileSystem\src\System.IO.FileSystem.csproj", "{6E4DEE24-716D-4E97-877B-83B138020091}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime", "..\System.Runtime\src\System.Runtime.csproj", "{20636DC7-EB9C-4E40-B10C-BC023B4AEEDF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.Extensions", "..\System.Runtime.Extensions\src\System.Runtime.Extensions.csproj", "{5D5B7D66-AEB4-41A1-AB8A-1AB884A65064}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Reflection.Metadata", "..\System.Reflection.Metadata\src\System.Reflection.Metadata.csproj", "{456DBDB3-EF0D-4517-8893-8D5087CA3254}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Collections.Immutable", "..\System.Collections.Immutable\src\System.Collections.Immutable.csproj", "{085360DE-8FF9-4725-8014-3C660BB36A25}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -44,6 +56,30 @@ Global {854C7BBD-8B87-44AE-B109-421647CD5959}.Debug|Any CPU.Build.0 = Debug|Any CPU {854C7BBD-8B87-44AE-B109-421647CD5959}.Release|Any CPU.ActiveCfg = Release|Any CPU {854C7BBD-8B87-44AE-B109-421647CD5959}.Release|Any CPU.Build.0 = Release|Any CPU + {ADDF4CDC-9F80-492C-85B5-908E34B64D74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ADDF4CDC-9F80-492C-85B5-908E34B64D74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ADDF4CDC-9F80-492C-85B5-908E34B64D74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ADDF4CDC-9F80-492C-85B5-908E34B64D74}.Release|Any CPU.Build.0 = Release|Any CPU + {6E4DEE24-716D-4E97-877B-83B138020091}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E4DEE24-716D-4E97-877B-83B138020091}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E4DEE24-716D-4E97-877B-83B138020091}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E4DEE24-716D-4E97-877B-83B138020091}.Release|Any CPU.Build.0 = Release|Any CPU + {20636DC7-EB9C-4E40-B10C-BC023B4AEEDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {20636DC7-EB9C-4E40-B10C-BC023B4AEEDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {20636DC7-EB9C-4E40-B10C-BC023B4AEEDF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {20636DC7-EB9C-4E40-B10C-BC023B4AEEDF}.Release|Any CPU.Build.0 = Release|Any CPU + {5D5B7D66-AEB4-41A1-AB8A-1AB884A65064}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D5B7D66-AEB4-41A1-AB8A-1AB884A65064}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D5B7D66-AEB4-41A1-AB8A-1AB884A65064}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D5B7D66-AEB4-41A1-AB8A-1AB884A65064}.Release|Any CPU.Build.0 = Release|Any CPU + {456DBDB3-EF0D-4517-8893-8D5087CA3254}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {456DBDB3-EF0D-4517-8893-8D5087CA3254}.Debug|Any CPU.Build.0 = Debug|Any CPU + {456DBDB3-EF0D-4517-8893-8D5087CA3254}.Release|Any CPU.ActiveCfg = Release|Any CPU + {456DBDB3-EF0D-4517-8893-8D5087CA3254}.Release|Any CPU.Build.0 = Release|Any CPU + {085360DE-8FF9-4725-8014-3C660BB36A25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {085360DE-8FF9-4725-8014-3C660BB36A25}.Debug|Any CPU.Build.0 = Debug|Any CPU + {085360DE-8FF9-4725-8014-3C660BB36A25}.Release|Any CPU.ActiveCfg = Release|Any CPU + {085360DE-8FF9-4725-8014-3C660BB36A25}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -53,6 +89,12 @@ Global {02304469-722E-4723-92A1-820B9A37D275} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {C38217EF-88F4-4D56-9F58-780BE1DDAFF6} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} {854C7BBD-8B87-44AE-B109-421647CD5959} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} + {ADDF4CDC-9F80-492C-85B5-908E34B64D74} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {6E4DEE24-716D-4E97-877B-83B138020091} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {20636DC7-EB9C-4E40-B10C-BC023B4AEEDF} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {5D5B7D66-AEB4-41A1-AB8A-1AB884A65064} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {456DBDB3-EF0D-4517-8893-8D5087CA3254} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {085360DE-8FF9-4725-8014-3C660BB36A25} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {207AB5D6-FFD0-42E8-88DF-0A3C6DF24251} diff --git a/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs b/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs index 900f6dbbb26d71..0a614bbe9e4d5d 100644 --- a/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs +++ b/src/libraries/System.Diagnostics.StackTrace/tests/StackTraceTests.cs @@ -313,7 +313,9 @@ public void ToString_NullFrame_ThrowsNullReferenceException() [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] private static StackTrace Generic() => new StackTrace(); + [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] private static StackTrace InvokeIgnoredMethod() => Ignored.Method(); + [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] private static StackTrace InvokeIgnoredMethodWithException() => Ignored.MethodWithException(); [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] @@ -335,6 +337,8 @@ private static Exception InvokeException() private class ClassWithConstructor { public StackTrace StackTrace { get; } + + [MethodImpl(MethodImplOptions.NoInlining)] public ClassWithConstructor() => StackTrace = new StackTrace(); } diff --git a/src/libraries/System.Diagnostics.StackTrace/tests/System.Diagnostics.StackTrace.Tests.csproj b/src/libraries/System.Diagnostics.StackTrace/tests/System.Diagnostics.StackTrace.Tests.csproj index 22f8deac3fe10a..0290d8432c8ffb 100644 --- a/src/libraries/System.Diagnostics.StackTrace/tests/System.Diagnostics.StackTrace.Tests.csproj +++ b/src/libraries/System.Diagnostics.StackTrace/tests/System.Diagnostics.StackTrace.Tests.csproj @@ -4,15 +4,13 @@ true + + + - - - - - \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.TextWriterTraceListener/src/System.Diagnostics.TextWriterTraceListener.csproj b/src/libraries/System.Diagnostics.TextWriterTraceListener/src/System.Diagnostics.TextWriterTraceListener.csproj index f326d869012406..4369501017e467 100644 --- a/src/libraries/System.Diagnostics.TextWriterTraceListener/src/System.Diagnostics.TextWriterTraceListener.csproj +++ b/src/libraries/System.Diagnostics.TextWriterTraceListener/src/System.Diagnostics.TextWriterTraceListener.csproj @@ -9,31 +9,24 @@ - - Common\System\Diagnostics\TraceListenerHelpers.cs - + - - Common\System\Diagnostics\TraceListenerHelpers.Windows.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.GetCurrentProcessId.cs - + + + - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\Interop.GetPid.cs - - - Common\System\Diagnostics\TraceListenerHelpers.Unix.cs - + + + diff --git a/src/libraries/System.Diagnostics.TextWriterTraceListener/tests/System.Diagnostics.TextWriterTraceListener.Tests.csproj b/src/libraries/System.Diagnostics.TextWriterTraceListener/tests/System.Diagnostics.TextWriterTraceListener.Tests.csproj index 0562cc460f471b..4a5c22ae09ef1a 100644 --- a/src/libraries/System.Diagnostics.TextWriterTraceListener/tests/System.Diagnostics.TextWriterTraceListener.Tests.csproj +++ b/src/libraries/System.Diagnostics.TextWriterTraceListener/tests/System.Diagnostics.TextWriterTraceListener.Tests.csproj @@ -4,15 +4,13 @@ $(NetCoreAppCurrent) - + - - - - + + \ No newline at end of file diff --git a/src/libraries/System.Diagnostics.TraceSource/System.Diagnostics.TraceSource.sln b/src/libraries/System.Diagnostics.TraceSource/System.Diagnostics.TraceSource.sln index 0f1245a8ae0b90..a952890b43bac2 100644 --- a/src/libraries/System.Diagnostics.TraceSource/System.Diagnostics.TraceSource.sln +++ b/src/libraries/System.Diagnostics.TraceSource/System.Diagnostics.TraceSource.sln @@ -20,7 +20,27 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{EB38F993-8EA4-466B-AD6B-488768274858}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{EB38F993-8EA4-466B-AD6B-488768274858}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Collections", "..\System.Collections\src\System.Collections.csproj", "{3690CF2A-3BA5-4BC6-BFAA-312A7976C2AF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Collections.NonGeneric", "..\System.Collections.NonGeneric\src\System.Collections.NonGeneric.csproj", "{8FE26689-26FA-46B7-9906-C26B5193B93C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Collections.Specialized", "..\System.Collections.Specialized\src\System.Collections.Specialized.csproj", "{0126A981-AC71-4961-9B14-0F78728DDAF6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.ComponentModel.Primitives", "..\System.ComponentModel.Primitives\src\System.ComponentModel.Primitives.csproj", "{FB0D7835-5734-4379-82F3-FBA98FE281EF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Diagnostics.Process", "..\System.Diagnostics.Process\src\System.Diagnostics.Process.csproj", "{7C1BEC52-C93B-459A-BEF8-02A8122B6466}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.FileSystem", "..\System.IO.FileSystem\src\System.IO.FileSystem.csproj", "{DA45FFC0-F398-492A-BD72-FC3B0625DF4B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime", "..\System.Runtime\src\System.Runtime.csproj", "{2C869A13-107A-47CE-92F7-C0C27CE20E47}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.Extensions", "..\System.Runtime.Extensions\src\System.Runtime.Extensions.csproj", "{B4CFBC40-0570-43F1-9752-CFFBFF1FFCF5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.InteropServices", "..\System.Runtime.InteropServices\src\System.Runtime.InteropServices.csproj", "{C447FF5D-6895-4261-BBD6-18F4FACCA3F4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Threading", "..\System.Threading\src\System.Threading.csproj", "{2426FD97-9202-498D-806A-E9A41F9B52DB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -44,6 +64,46 @@ Global {EB38F993-8EA4-466B-AD6B-488768274858}.Debug|Any CPU.Build.0 = Debug|Any CPU {EB38F993-8EA4-466B-AD6B-488768274858}.Release|Any CPU.ActiveCfg = Release|Any CPU {EB38F993-8EA4-466B-AD6B-488768274858}.Release|Any CPU.Build.0 = Release|Any CPU + {3690CF2A-3BA5-4BC6-BFAA-312A7976C2AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3690CF2A-3BA5-4BC6-BFAA-312A7976C2AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3690CF2A-3BA5-4BC6-BFAA-312A7976C2AF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3690CF2A-3BA5-4BC6-BFAA-312A7976C2AF}.Release|Any CPU.Build.0 = Release|Any CPU + {8FE26689-26FA-46B7-9906-C26B5193B93C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8FE26689-26FA-46B7-9906-C26B5193B93C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8FE26689-26FA-46B7-9906-C26B5193B93C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8FE26689-26FA-46B7-9906-C26B5193B93C}.Release|Any CPU.Build.0 = Release|Any CPU + {0126A981-AC71-4961-9B14-0F78728DDAF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0126A981-AC71-4961-9B14-0F78728DDAF6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0126A981-AC71-4961-9B14-0F78728DDAF6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0126A981-AC71-4961-9B14-0F78728DDAF6}.Release|Any CPU.Build.0 = Release|Any CPU + {FB0D7835-5734-4379-82F3-FBA98FE281EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB0D7835-5734-4379-82F3-FBA98FE281EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB0D7835-5734-4379-82F3-FBA98FE281EF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB0D7835-5734-4379-82F3-FBA98FE281EF}.Release|Any CPU.Build.0 = Release|Any CPU + {7C1BEC52-C93B-459A-BEF8-02A8122B6466}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7C1BEC52-C93B-459A-BEF8-02A8122B6466}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7C1BEC52-C93B-459A-BEF8-02A8122B6466}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7C1BEC52-C93B-459A-BEF8-02A8122B6466}.Release|Any CPU.Build.0 = Release|Any CPU + {DA45FFC0-F398-492A-BD72-FC3B0625DF4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA45FFC0-F398-492A-BD72-FC3B0625DF4B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA45FFC0-F398-492A-BD72-FC3B0625DF4B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA45FFC0-F398-492A-BD72-FC3B0625DF4B}.Release|Any CPU.Build.0 = Release|Any CPU + {2C869A13-107A-47CE-92F7-C0C27CE20E47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2C869A13-107A-47CE-92F7-C0C27CE20E47}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2C869A13-107A-47CE-92F7-C0C27CE20E47}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2C869A13-107A-47CE-92F7-C0C27CE20E47}.Release|Any CPU.Build.0 = Release|Any CPU + {B4CFBC40-0570-43F1-9752-CFFBFF1FFCF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B4CFBC40-0570-43F1-9752-CFFBFF1FFCF5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B4CFBC40-0570-43F1-9752-CFFBFF1FFCF5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B4CFBC40-0570-43F1-9752-CFFBFF1FFCF5}.Release|Any CPU.Build.0 = Release|Any CPU + {C447FF5D-6895-4261-BBD6-18F4FACCA3F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C447FF5D-6895-4261-BBD6-18F4FACCA3F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C447FF5D-6895-4261-BBD6-18F4FACCA3F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C447FF5D-6895-4261-BBD6-18F4FACCA3F4}.Release|Any CPU.Build.0 = Release|Any CPU + {2426FD97-9202-498D-806A-E9A41F9B52DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2426FD97-9202-498D-806A-E9A41F9B52DB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2426FD97-9202-498D-806A-E9A41F9B52DB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2426FD97-9202-498D-806A-E9A41F9B52DB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -53,6 +113,16 @@ Global {5380420C-EB1D-4C53-9CFC-916578C18334} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {6E515D9C-A5C2-4716-96A1-4716F007267D} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} {EB38F993-8EA4-466B-AD6B-488768274858} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} + {3690CF2A-3BA5-4BC6-BFAA-312A7976C2AF} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {8FE26689-26FA-46B7-9906-C26B5193B93C} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {0126A981-AC71-4961-9B14-0F78728DDAF6} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {FB0D7835-5734-4379-82F3-FBA98FE281EF} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {7C1BEC52-C93B-459A-BEF8-02A8122B6466} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {DA45FFC0-F398-492A-BD72-FC3B0625DF4B} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {2C869A13-107A-47CE-92F7-C0C27CE20E47} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {B4CFBC40-0570-43F1-9752-CFFBFF1FFCF5} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {C447FF5D-6895-4261-BBD6-18F4FACCA3F4} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {2426FD97-9202-498D-806A-E9A41F9B52DB} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {124F2F18-059D-4341-9BAF-7C33A33838B4} diff --git a/src/libraries/System.Diagnostics.TraceSource/ref/System.Diagnostics.TraceSource.cs b/src/libraries/System.Diagnostics.TraceSource/ref/System.Diagnostics.TraceSource.cs index 3252a3187f594a..da867700460dd0 100644 --- a/src/libraries/System.Diagnostics.TraceSource/ref/System.Diagnostics.TraceSource.cs +++ b/src/libraries/System.Diagnostics.TraceSource/ref/System.Diagnostics.TraceSource.cs @@ -263,10 +263,10 @@ public void Remove(System.Diagnostics.TraceListener? listener) { } public void Remove(string name) { } public void RemoveAt(int index) { } void System.Collections.ICollection.CopyTo(System.Array array, int index) { } - int System.Collections.IList.Add(object value) { throw null; } + int System.Collections.IList.Add(object? value) { throw null; } bool System.Collections.IList.Contains(object? value) { throw null; } int System.Collections.IList.IndexOf(object? value) { throw null; } - void System.Collections.IList.Insert(int index, object value) { } + void System.Collections.IList.Insert(int index, object? value) { } void System.Collections.IList.Remove(object? value) { } } [System.FlagsAttribute] diff --git a/src/libraries/System.Diagnostics.TraceSource/src/System.Diagnostics.TraceSource.csproj b/src/libraries/System.Diagnostics.TraceSource/src/System.Diagnostics.TraceSource.csproj index ce6fa0f43970ab..9db54bcc7a0ff2 100644 --- a/src/libraries/System.Diagnostics.TraceSource/src/System.Diagnostics.TraceSource.csproj +++ b/src/libraries/System.Diagnostics.TraceSource/src/System.Diagnostics.TraceSource.csproj @@ -29,31 +29,24 @@ - - Common\System\Diagnostics\TraceListenerHelpers.cs - + - - Common\System\Diagnostics\TraceListenerHelpers.Windows.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.GetCurrentProcessId.cs - + + + - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\Interop.GetPid.cs - - - Common\System\Diagnostics\TraceListenerHelpers.Unix.cs - + + + diff --git a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj index 03e74a6b2c0c8d..35c33d0095d48d 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj +++ b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj @@ -5,8 +5,8 @@ true true - - + + diff --git a/src/libraries/System.DirectoryServices.AccountManagement/src/System.DirectoryServices.AccountManagement.csproj b/src/libraries/System.DirectoryServices.AccountManagement/src/System.DirectoryServices.AccountManagement.csproj index daf24a4408f6e3..41b0189dc0a7c1 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/src/System.DirectoryServices.AccountManagement.csproj +++ b/src/libraries/System.DirectoryServices.AccountManagement/src/System.DirectoryServices.AccountManagement.csproj @@ -1,15 +1,17 @@ - System.DirectoryServices.AccountManagement true $(DefineConstants);FLAVOR_WHIDBEY;PAPI_AD;PAPI_REGSAM;USE_CTX_CACHE $(NoWarn);8073;CA1810 true - SR.DirectoryServicesAccountManagement_PlatformNotSupported $(NetCoreAppCurrent)-Windows_NT;netstandard2.0;netcoreapp2.0-Windows_NT;_$(NetFrameworkCurrent) true - + + + SR.DirectoryServicesAccountManagement_PlatformNotSupported + + @@ -83,12 +85,10 @@ - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Advapi32\Interop.LookupAccountSid.cs - + + @@ -99,7 +99,7 @@ - + diff --git a/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/Principal.cs b/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/Principal.cs index 040de0d0c932cb..8c2bcb0871291b 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/Principal.cs +++ b/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/Principal.cs @@ -124,7 +124,7 @@ public string SamAccountName set { if (null == value || 0 == value.Length) - throw new ArgumentNullException(PropertyNames.PrincipalSamAccountName); + throw new ArgumentNullException(nameof(value)); if (!GetStoreCtxToUse().IsValidProperty(this, PropertyNames.PrincipalSamAccountName)) throw new InvalidOperationException(SR.InvalidPropertyForStore); @@ -244,7 +244,7 @@ public string Name set { if (null == value || 0 == value.Length) - throw new ArgumentNullException(PropertyNames.PrincipalName); + throw new ArgumentNullException(nameof(value)); if (!GetStoreCtxToUse().IsValidProperty(this, PropertyNames.PrincipalName)) throw new InvalidOperationException(SR.InvalidPropertyForStore); diff --git a/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/PrincipalSearcher.cs b/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/PrincipalSearcher.cs index 62b8e52e5239de..68d1811c0a0eba 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/PrincipalSearcher.cs +++ b/src/libraries/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/PrincipalSearcher.cs @@ -23,7 +23,7 @@ public PrincipalSearcher() public PrincipalSearcher(Principal queryFilter) { if (null == queryFilter) - throw new ArgumentException(nameof(queryFilter)); + throw new ArgumentException(null, nameof(queryFilter)); _ctx = queryFilter.Context; this.QueryFilter = queryFilter; // use property to enforce "no persisted principals" check diff --git a/src/libraries/System.DirectoryServices.AccountManagement/tests/ComputerPrincipalTest.cs b/src/libraries/System.DirectoryServices.AccountManagement/tests/ComputerPrincipalTest.cs index e17eaf3f60aac8..9d83710d151682 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/tests/ComputerPrincipalTest.cs +++ b/src/libraries/System.DirectoryServices.AccountManagement/tests/ComputerPrincipalTest.cs @@ -35,7 +35,7 @@ public void Ctor_NullSamAccountName_ThrowsArgumentException() public void Ctor_EmptySamAccountName_ThrowsArgumentNullException() { var context = new PrincipalContext(ContextType.Machine); - AssertExtensions.Throws("Principal.SamAccountName", null, () => new ComputerPrincipal(context, string.Empty, "password", enabled: true)); + AssertExtensions.Throws("value", null, () => new ComputerPrincipal(context, string.Empty, "password", enabled: true)); } [Fact] diff --git a/src/libraries/System.DirectoryServices.AccountManagement/tests/System.DirectoryServices.AccountManagement.Tests.csproj b/src/libraries/System.DirectoryServices.AccountManagement/tests/System.DirectoryServices.AccountManagement.Tests.csproj index f40b0251aabdb9..52962b9e03d1cd 100644 --- a/src/libraries/System.DirectoryServices.AccountManagement/tests/System.DirectoryServices.AccountManagement.Tests.csproj +++ b/src/libraries/System.DirectoryServices.AccountManagement/tests/System.DirectoryServices.AccountManagement.Tests.csproj @@ -10,9 +10,8 @@ - - Common\DirectoryServices\LdapConfiguration.cs - + diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj b/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj index 6ad5f867b6e9db..03d310243f3b35 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj +++ b/src/libraries/System.DirectoryServices.Protocols/src/System.DirectoryServices.Protocols.csproj @@ -1,14 +1,16 @@ - System.DirectoryServices.Protocols true $(NoWarn);0649;CA1810 true - SR.DirectoryServicesProtocols_PlatformNotSupported - $(NetCoreAppCurrent)-Windows_NT;netstandard2.0;netcoreapp2.0-Windows_NT;_$(NetFrameworkCurrent) + $(NetCoreAppCurrent)-Windows_NT;netcoreapp2.0-Windows_NT;$(NetCoreAppCurrent)-OSX;netcoreapp2.0-OSX;$(NetCoreAppCurrent)-Linux;netcoreapp2.0-Linux;netstandard2.0;_$(NetFrameworkCurrent) true - + + + SR.DirectoryServicesProtocols_PlatformNotSupported + + @@ -33,14 +35,57 @@ - - + + + Common\Interop\Interop.Ldap.cs + + + + + + + + + + + Common\Interop\Windows\Interop.Libraries.cs + + + Common\Interop\Windows\Wldap32\Interop.Ldap.cs + + + Common\Interop\Windows\Wldap32\Interop.Ber.cs + + + + + + + + + + + Common\Interop\Linux\OpenLdap\Interop.Ldap.cs + + + Common\Interop\Linux\OpenLdap\Interop.Ber.cs + + + + + Common\Interop\Linux\Interop.Libraries.cs + + + + + Common\Interop\OSX\Interop.Libraries.cs + - + @@ -60,4 +105,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/BerPal.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/BerPal.Linux.cs new file mode 100644 index 00000000000000..f58a94df522348 --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/BerPal.Linux.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.DirectoryServices.Protocols +{ + internal static class BerPal + { + internal static void FreeBervalArray(IntPtr ptrResult) => Interop.ber_bvecfree(ptrResult); + + internal static void FreeBerval(IntPtr flattenptr) => Interop.ber_bvfree(flattenptr); + + internal static void FreeBerElement(IntPtr berelement, int option) => Interop.ber_free(berelement, option); + + internal static int FlattenBerElement(SafeBerHandle berElement, ref IntPtr flattenptr) => Interop.ber_flatten(berElement, ref flattenptr); + + internal static int PrintBerArray(SafeBerHandle berElement, string format, IntPtr value) => Interop.ber_printf_berarray(berElement, format, value); + + internal static int PrintByteArray(SafeBerHandle berElement, string format, HGlobalMemHandle value, int length) => Interop.ber_printf_bytearray(berElement, format, value, length); + + internal static int PrintEmptyArgument(SafeBerHandle berElement, string format) => Interop.ber_printf_emptyarg(berElement, format); + + internal static int PrintInt(SafeBerHandle berElement, string format, int value) => Interop.ber_printf_int(berElement, format, value); + + internal static int ScanNext(SafeBerHandle berElement, string format) => Interop.ber_scanf(berElement, format); + + internal static int ScanNextBitString(SafeBerHandle berElement, string format, ref IntPtr ptrResult, ref int bitLength) => Interop.ber_scanf_bitstring(berElement, format, ref ptrResult, ref bitLength); + + internal static int ScanNextInt(SafeBerHandle berElement, string format, ref int result) => Interop.ber_scanf_int(berElement, format, ref result); + + internal static int ScanNextPtr(SafeBerHandle berElement, string format, ref IntPtr value) => Interop.ber_scanf_ptr(berElement, format, ref value); + + internal static bool IsBerDecodeError(int errorCode) => errorCode == -1; + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/BerPal.Windows.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/BerPal.Windows.cs new file mode 100644 index 00000000000000..bec5b5a65d5ac9 --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/BerPal.Windows.cs @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; + +namespace System.DirectoryServices.Protocols +{ + internal static class BerPal + { + internal static void FreeBervalArray(IntPtr ptrResult) => Interop.ber_bvecfree(ptrResult); + + internal static void FreeBerval(IntPtr flattenptr) => Interop.ber_bvfree(flattenptr); + + internal static void FreeBerElement(IntPtr berelement, int option) => Interop.ber_free(berelement, option); + + internal static int FlattenBerElement(SafeBerHandle berElement, ref IntPtr flattenptr) => Interop.ber_flatten(berElement, ref flattenptr); + + internal static int PrintBerArray(SafeBerHandle berElement, string format, IntPtr value) => Interop.ber_printf_berarray(berElement, format, value); + + internal static int PrintByteArray(SafeBerHandle berElement, string format, HGlobalMemHandle value, int length) => Interop.ber_printf_bytearray(berElement, format, value, length); + + internal static int PrintEmptyArgument(SafeBerHandle berElement, string format) => Interop.ber_printf_emptyarg(berElement, format); + + internal static int PrintInt(SafeBerHandle berElement, string format, int value) => Interop.ber_printf_int(berElement, format, value); + + internal static int ScanNext(SafeBerHandle berElement, string format) => Interop.ber_scanf(berElement, format); + + internal static int ScanNextBitString(SafeBerHandle berElement, string format, ref IntPtr ptrResult, ref int bitLength) => Interop.ber_scanf_bitstring(berElement, format, ref ptrResult, ref bitLength); + + internal static int ScanNextInt(SafeBerHandle berElement, string format, ref int result) => Interop.ber_scanf_int(berElement, format, ref result); + + internal static int ScanNextPtr(SafeBerHandle berElement, string format, ref IntPtr value) => Interop.ber_scanf_ptr(berElement, format, ref value); + + internal static bool IsBerDecodeError(int errorCode) => errorCode != 0; + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Linux.cs new file mode 100644 index 00000000000000..9089e8902726cb --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Linux.cs @@ -0,0 +1,169 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; + +namespace System.DirectoryServices.Protocols +{ + internal static class LdapPal + { + internal static void CancelDirectoryAsyncOperation(ConnectionHandle ldapHandle, int messagId) => Interop.ldap_abandon(ldapHandle, messagId); + + internal static int AddDirectoryEntry(ConnectionHandle ldapHandle, string dn, IntPtr attrs, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber) => + Interop.ldap_add(ldapHandle, dn, attrs, servercontrol, clientcontrol, ref messageNumber); + + internal static int CompareDirectoryEntries(ConnectionHandle ldapHandle, string dn, string attributeName, string strValue, berval binaryValue, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber) => + Interop.ldap_compare(ldapHandle, dn, attributeName, binaryValue, servercontrol, clientcontrol, ref messageNumber); + + internal static void FreeDirectoryControl(IntPtr control) => Interop.ldap_control_free(control); + + internal static void FreeDirectoryControls(IntPtr value) => Interop.ldap_controls_free(value); + + internal static int CreateDirectorySortControl(ConnectionHandle handle, IntPtr keys, byte critical, ref IntPtr control) => Interop.ldap_create_sort_control(handle, keys, critical, ref control); + + internal static int DeleteDirectoryEntry(ConnectionHandle ldapHandle, string dn, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber) => Interop.ldap_delete_ext(ldapHandle, dn, servercontrol, clientcontrol, ref messageNumber); + + internal static int ExtendedDirectoryOperation(ConnectionHandle ldapHandle, string oid, berval data, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber) => + Interop.ldap_extended_operation(ldapHandle, oid, data, servercontrol, clientcontrol, ref messageNumber); + + internal static IntPtr GetFirstAttributeFromEntry(ConnectionHandle ldapHandle, IntPtr result, ref IntPtr address) => Interop.ldap_first_attribute(ldapHandle, result, ref address); + + internal static IntPtr GetFirstEntryFromResult(ConnectionHandle ldapHandle, IntPtr result) => Interop.ldap_first_entry(ldapHandle, result); + + internal static IntPtr GetFirstReferenceFromResult(ConnectionHandle ldapHandle, IntPtr result) => Interop.ldap_first_reference(ldapHandle, result); + + internal static IntPtr GetDistinguishedName(ConnectionHandle ldapHandle, IntPtr result) => Interop.ldap_get_dn(ldapHandle, result); + + internal static int GetLastErrorFromConnection(ConnectionHandle ldapHandle) + { + int result = 0; + Interop.ldap_get_option_int(ldapHandle, LdapOption.LDAP_OPT_ERROR_NUMBER, ref result); + return result; + } + + internal static int GetIntOption(ConnectionHandle ldapHandle, LdapOption option, ref int outValue) => Interop.ldap_get_option_int(ldapHandle, option, ref outValue); + + internal static int GetPtrOption(ConnectionHandle ldapHandle, LdapOption option, ref IntPtr outValue) => Interop.ldap_get_option_ptr(ldapHandle, option, ref outValue); + + internal static int GetSecurityHandleOption(ConnectionHandle ldapHandle, LdapOption option, ref SecurityHandle outValue) => Interop.ldap_get_option_sechandle(ldapHandle, option, ref outValue); + + // This option is not supported on Linux, so it would most likely throw. + internal static int GetSecInfoOption(ConnectionHandle ldapHandle, LdapOption option, SecurityPackageContextConnectionInformation outValue) => Interop.ldap_get_option_secInfo(ldapHandle, option, outValue); + + internal static IntPtr GetValuesFromAttribute(ConnectionHandle ldapHandle, IntPtr result, string name) => Interop.ldap_get_values_len(ldapHandle, result, name); + + internal static void FreeMemory(IntPtr outValue) => Interop.ldap_memfree(outValue); + + internal static int ModifyDirectoryEntry(ConnectionHandle ldapHandle, string dn, IntPtr attrs, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber) => + Interop.ldap_modify(ldapHandle, dn, attrs, servercontrol, clientcontrol, ref messageNumber); + + internal static IntPtr GetNextAttributeFromResult(ConnectionHandle ldapHandle, IntPtr result, IntPtr address) => Interop.ldap_next_attribute(ldapHandle, result, address); + + internal static IntPtr GetNextEntryFromResult(ConnectionHandle ldapHandle, IntPtr result) => Interop.ldap_next_entry(ldapHandle, result); + + internal static IntPtr GetNextReferenceFromResult(ConnectionHandle ldapHandle, IntPtr result) => Interop.ldap_next_reference(ldapHandle, result); + + internal static int ParseExtendedResult(ConnectionHandle ldapHandle, IntPtr result, ref IntPtr oid, ref IntPtr data, byte freeIt) => Interop.ldap_parse_extended_result(ldapHandle, result, ref oid, ref data, freeIt); + + internal static int ParseReference(ConnectionHandle ldapHandle, IntPtr result, ref IntPtr referrals) => Interop.ldap_parse_reference(ldapHandle, result, ref referrals, IntPtr.Zero, 0); + + internal static int ParseResult(ConnectionHandle ldapHandle, IntPtr result, ref int serverError, ref IntPtr dn, ref IntPtr message, ref IntPtr referral, ref IntPtr control, byte freeIt) => + Interop.ldap_parse_result(ldapHandle, result, ref serverError, ref dn, ref message, ref referral, ref control, freeIt); + + internal static int ParseResultReferral(ConnectionHandle ldapHandle, IntPtr result, IntPtr serverError, IntPtr dn, IntPtr message, ref IntPtr referral, IntPtr control, byte freeIt) + => Interop.ldap_parse_result_referral(ldapHandle, result, serverError, dn, message, ref referral, control, freeIt); + + internal static int RenameDirectoryEntry(ConnectionHandle ldapHandle, string dn, string newRdn, string newParentDn, int deleteOldRdn, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber) => + Interop.ldap_rename(ldapHandle, dn, newRdn, newParentDn, deleteOldRdn, servercontrol, clientcontrol, ref messageNumber); + + internal static int GetResultFromAsyncOperation(ConnectionHandle ldapHandle, int messageId, int all, LDAP_TIMEVAL timeout, ref IntPtr Message) => Interop.ldap_result(ldapHandle, messageId, all, timeout, ref Message); + + internal static int ResultToErrorCode(ConnectionHandle ldapHandle, IntPtr result, int freeIt) => Interop.ldap_result2error(ldapHandle, result, freeIt); + + internal static int SearchDirectory(ConnectionHandle ldapHandle, string dn, int scope, string filter, IntPtr attributes, bool attributeOnly, IntPtr servercontrol, IntPtr clientcontrol, int timelimit, int sizelimit, ref int messageNumber) => + Interop.ldap_search(ldapHandle, dn, scope, filter, attributes, attributeOnly, servercontrol, clientcontrol, timelimit, sizelimit, ref messageNumber); + + // This option is not supported in Linux, so it would most likely throw. + internal static int SetClientCertOption(ConnectionHandle ldapHandle, LdapOption option, QUERYCLIENTCERT outValue) => Interop.ldap_set_option_clientcert(ldapHandle, option, outValue); + + internal static int SetIntOption(ConnectionHandle ld, LdapOption option, ref int inValue) => Interop.ldap_set_option_int(ld, option, ref inValue); + + internal static int SetPtrOption(ConnectionHandle ldapHandle, LdapOption option, ref IntPtr inValue) => Interop.ldap_set_option_ptr(ldapHandle, option, ref inValue); + + internal static int SetReferralOption(ConnectionHandle ldapHandle, LdapOption option, ref LdapReferralCallback outValue) => Interop.ldap_set_option_referral(ldapHandle, option, ref outValue); + + // This option is not supported in Linux, so it would most likely throw. + internal static int SetServerCertOption(ConnectionHandle ldapHandle, LdapOption option, VERIFYSERVERCERT outValue) => Interop.ldap_set_option_servercert(ldapHandle, option, outValue); + + internal static int BindToDirectory(ConnectionHandle ld, string who, string passwd) => Interop.ldap_simple_bind(ld, who, passwd); + + internal static int StartTls(ConnectionHandle ldapHandle, ref int ServerReturnValue, ref IntPtr Message, IntPtr ServerControls, IntPtr ClientControls) => Interop.ldap_start_tls(ldapHandle, ref ServerReturnValue, ref Message, ServerControls, ClientControls); + + // openldap doesn't have a ldap_stop_tls function. Returning true as no-op for Linux. + internal static byte StopTls(ConnectionHandle ldapHandle) => 1; + + internal static void FreeValue(IntPtr referral) => Interop.ldap_value_free(referral); + + internal static void FreeAttributes(IntPtr berelement) => Interop.ldap_value_free_len(berelement); + + internal static string PtrToString(IntPtr requestName) => Marshal.PtrToStringAnsi(requestName); + + internal static IntPtr StringToPtr(string s) => Marshal.StringToHGlobalAnsi(s); + + /// + /// Function that will be sent to the Sasl interactive bind procedure which will resolve all Sasl challenges + /// that get passed in by using the defaults that we get passed in. + /// + /// The connection handle to the LDAP server. + /// Flags that control the interaction used to retrieve any necessary Sasl authentication parameters + /// Pointer to the defaults structure that was sent to sasl_interactive_bind + /// Pointer to the challenge we need to resolve + /// + internal static int SaslInteractionProcedure(IntPtr ldapHandle, uint flags, IntPtr defaultsPtr, IntPtr interactPtr) + { + if (ldapHandle == IntPtr.Zero) + { + return -9; // Parameter Error + } + // Convert pointers into managed structures. + IntPtr currentInteractPtr = interactPtr; + SaslInteractiveChallenge interactChallenge = Marshal.PtrToStructure(currentInteractPtr); + SaslDefaultCredentials defaults = Marshal.PtrToStructure(defaultsPtr); + + // loop through all of the challenges that were sent through the interactChallenge. + while (interactChallenge.saslChallengeType != (int)SaslChallengeType.SASL_CB_LIST_END) + { + // use defaults to fix the challenge type + switch (interactChallenge.saslChallengeType) + { + case (int)SaslChallengeType.SASL_CB_GETREALM: + interactChallenge.defresult = defaults.realm; + break; + case (int)SaslChallengeType.SASL_CB_AUTHNAME: + interactChallenge.defresult = defaults.authcid; + break; + case (int)SaslChallengeType.SASL_CB_PASS: + interactChallenge.defresult = defaults.passwd; + break; + case (int)SaslChallengeType.SASL_CB_USER: + interactChallenge.defresult = defaults.authzid; + break; + } + + if (!string.IsNullOrEmpty(interactChallenge.defresult)) + { + interactChallenge.result = Marshal.StringToHGlobalAnsi(interactChallenge.defresult); + interactChallenge.len = interactChallenge != null ? (uint)interactChallenge.defresult.Length : 0; + } + + // Move to next interact challenge + Marshal.StructureToPtr(interactChallenge, currentInteractPtr, false); + currentInteractPtr = IntPtr.Add(currentInteractPtr, Marshal.SizeOf()); + interactChallenge = Marshal.PtrToStructure(currentInteractPtr); + } + + return 0; + } + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Windows.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Windows.cs new file mode 100644 index 00000000000000..8a70be9f14e5ed --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/LdapPal.Windows.cs @@ -0,0 +1,105 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; + +namespace System.DirectoryServices.Protocols +{ + internal static class LdapPal + { + internal static void CancelDirectoryAsyncOperation(ConnectionHandle ldapHandle, int messagId) => Interop.ldap_abandon(ldapHandle, messagId); + + internal static int AddDirectoryEntry(ConnectionHandle ldapHandle, string dn, IntPtr attrs, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber) => + Interop.ldap_add(ldapHandle, dn, attrs, servercontrol, clientcontrol, ref messageNumber); + + internal static int CompareDirectoryEntries(ConnectionHandle ldapHandle, string dn, string attributeName, string strValue, berval binaryValue, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber) => + Interop.ldap_compare(ldapHandle, dn, attributeName, strValue, binaryValue, servercontrol, clientcontrol, ref messageNumber); + + internal static void FreeDirectoryControl(IntPtr control) => Interop.ldap_control_free(control); + + internal static void FreeDirectoryControls(IntPtr value) => Interop.ldap_controls_free(value); + + internal static int CreateDirectorySortControl(ConnectionHandle handle, IntPtr keys, byte critical, ref IntPtr control) => Interop.ldap_create_sort_control(handle, keys, critical, ref control); + + internal static int DeleteDirectoryEntry(ConnectionHandle ldapHandle, string dn, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber) => Interop.ldap_delete_ext(ldapHandle, dn, servercontrol, clientcontrol, ref messageNumber); + + internal static int ExtendedDirectoryOperation(ConnectionHandle ldapHandle, string oid, berval data, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber) => + Interop.ldap_extended_operation(ldapHandle, oid, data, servercontrol, clientcontrol, ref messageNumber); + + internal static IntPtr GetFirstAttributeFromEntry(ConnectionHandle ldapHandle, IntPtr result, ref IntPtr address) => Interop.ldap_first_attribute(ldapHandle, result, ref address); + + internal static IntPtr GetFirstEntryFromResult(ConnectionHandle ldapHandle, IntPtr result) => Interop.ldap_first_entry(ldapHandle, result); + + internal static IntPtr GetFirstReferenceFromResult(ConnectionHandle ldapHandle, IntPtr result) => Interop.ldap_first_reference(ldapHandle, result); + + internal static IntPtr GetDistinguishedName(ConnectionHandle ldapHandle, IntPtr result) => Interop.ldap_get_dn(ldapHandle, result); + + internal static int GetLastErrorFromConnection(ConnectionHandle ldapHandle) => Interop.LdapGetLastError(); + + internal static int GetIntOption(ConnectionHandle ldapHandle, LdapOption option, ref int outValue) => Interop.ldap_get_option_int(ldapHandle, option, ref outValue); + + internal static int GetPtrOption(ConnectionHandle ldapHandle, LdapOption option, ref IntPtr outValue) => Interop.ldap_get_option_ptr(ldapHandle, option, ref outValue); + + internal static int GetSecurityHandleOption(ConnectionHandle ldapHandle, LdapOption option, ref SecurityHandle outValue) => Interop.ldap_get_option_sechandle(ldapHandle, option, ref outValue); + + internal static int GetSecInfoOption(ConnectionHandle ldapHandle, LdapOption option, SecurityPackageContextConnectionInformation outValue) => Interop.ldap_get_option_secInfo(ldapHandle, option, outValue); + + internal static IntPtr GetValuesFromAttribute(ConnectionHandle ldapHandle, IntPtr result, string name) => Interop.ldap_get_values_len(ldapHandle, result, name); + + internal static void FreeMemory(IntPtr outValue) => Interop.ldap_memfree(outValue); + + internal static int ModifyDirectoryEntry(ConnectionHandle ldapHandle, string dn, IntPtr attrs, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber) => + Interop.ldap_modify(ldapHandle, dn, attrs, servercontrol, clientcontrol, ref messageNumber); + + internal static IntPtr GetNextAttributeFromResult(ConnectionHandle ldapHandle, IntPtr result, IntPtr address) => Interop.ldap_next_attribute(ldapHandle, result, address); + + internal static IntPtr GetNextEntryFromResult(ConnectionHandle ldapHandle, IntPtr result) => Interop.ldap_next_entry(ldapHandle, result); + + internal static IntPtr GetNextReferenceFromResult(ConnectionHandle ldapHandle, IntPtr result) => Interop.ldap_next_reference(ldapHandle, result); + + internal static int ParseExtendedResult(ConnectionHandle ldapHandle, IntPtr result, ref IntPtr oid, ref IntPtr data, byte freeIt) => Interop.ldap_parse_extended_result(ldapHandle, result, ref oid, ref data, freeIt); + + internal static int ParseReference(ConnectionHandle ldapHandle, IntPtr result, ref IntPtr referrals) => Interop.ldap_parse_reference(ldapHandle, result, ref referrals); + + internal static int ParseResult(ConnectionHandle ldapHandle, IntPtr result, ref int serverError, ref IntPtr dn, ref IntPtr message, ref IntPtr referral, ref IntPtr control, byte freeIt) => + Interop.ldap_parse_result(ldapHandle, result, ref serverError, ref dn, ref message, ref referral, ref control, freeIt); + + internal static int ParseResultReferral(ConnectionHandle ldapHandle, IntPtr result, IntPtr serverError, IntPtr dn, IntPtr message, ref IntPtr referral, IntPtr control, byte freeIt) + => Interop.ldap_parse_result_referral(ldapHandle, result, serverError, dn, message, ref referral, control, freeIt); + + internal static int RenameDirectoryEntry(ConnectionHandle ldapHandle, string dn, string newRdn, string newParentDn, int deleteOldRdn, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber) => + Interop.ldap_rename(ldapHandle, dn, newRdn, newParentDn, deleteOldRdn, servercontrol, clientcontrol, ref messageNumber); + + internal static int GetResultFromAsyncOperation(ConnectionHandle ldapHandle, int messageId, int all, LDAP_TIMEVAL timeout, ref IntPtr Message) => Interop.ldap_result(ldapHandle, messageId, all, timeout, ref Message); + + internal static int ResultToErrorCode(ConnectionHandle ldapHandle, IntPtr result, int freeIt) => Interop.ldap_result2error(ldapHandle, result, freeIt); + + internal static int SearchDirectory(ConnectionHandle ldapHandle, string dn, int scope, string filter, IntPtr attributes, bool attributeOnly, IntPtr servercontrol, IntPtr clientcontrol, int timelimit, int sizelimit, ref int messageNumber) => + Interop.ldap_search(ldapHandle, dn, scope, filter, attributes, attributeOnly, servercontrol, clientcontrol, timelimit, sizelimit, ref messageNumber); + + internal static int SetClientCertOption(ConnectionHandle ldapHandle, LdapOption option, QUERYCLIENTCERT outValue) => Interop.ldap_set_option_clientcert(ldapHandle, option, outValue); + + internal static int SetIntOption(ConnectionHandle ld, LdapOption option, ref int inValue) => Interop.ldap_set_option_int(ld, option, ref inValue); + + internal static int SetPtrOption(ConnectionHandle ldapHandle, LdapOption option, ref IntPtr inValue) => Interop.ldap_set_option_ptr(ldapHandle, option, ref inValue); + + internal static int SetReferralOption(ConnectionHandle ldapHandle, LdapOption option, ref LdapReferralCallback outValue) => Interop.ldap_set_option_referral(ldapHandle, option, ref outValue); + + internal static int SetServerCertOption(ConnectionHandle ldapHandle, LdapOption option, VERIFYSERVERCERT outValue) => Interop.ldap_set_option_servercert(ldapHandle, option, outValue); + + internal static int BindToDirectory(ConnectionHandle ld, string who, string passwd) => Interop.ldap_simple_bind_s(ld, who, passwd); + + internal static int StartTls(ConnectionHandle ldapHandle, ref int ServerReturnValue, ref IntPtr Message, IntPtr ServerControls, IntPtr ClientControls) => Interop.ldap_start_tls(ldapHandle, ref ServerReturnValue, ref Message, ServerControls, ClientControls); + + internal static byte StopTls(ConnectionHandle ldapHandle) => Interop.ldap_stop_tls(ldapHandle); + + internal static void FreeValue(IntPtr referral) => Interop.ldap_value_free(referral); + + internal static void FreeAttributes(IntPtr berelement) => Interop.ldap_value_free_len(berelement); + + internal static string PtrToString(IntPtr requestName) => Marshal.PtrToStringUni(requestName); + + internal static IntPtr StringToPtr(string s) => Marshal.StringToHGlobalUni(s); + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.Linux.cs new file mode 100644 index 00000000000000..8478b4b1504308 --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.Linux.cs @@ -0,0 +1,79 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Win32.SafeHandles; + +namespace System.DirectoryServices.Protocols +{ + internal sealed class ConnectionHandle : SafeHandleZeroOrMinusOneIsInvalid + { + internal bool _needDispose = false; + + internal ConnectionHandle() + :base(true) + { + Interop.ldap_initialize(out handle, null); + _needDispose = true; + } + + internal ConnectionHandle(IntPtr value, bool disposeHandle) : base(true) + { + _needDispose = disposeHandle; + if (value == IntPtr.Zero) + { + throw new LdapException(SR.LDAP_CONNECT_ERROR); + } + else + { + SetHandle(value); + } + } + + protected override bool ReleaseHandle() + { + if (_needDispose) + { + IntPtr nullPointer = IntPtr.Zero; + Interop.ldap_unbind_ext_s(handle, ref nullPointer, ref nullPointer); + } + + handle = IntPtr.Zero; + return true; + } + } + + internal sealed class SafeBerHandle : SafeHandleZeroOrMinusOneIsInvalid + { + internal SafeBerHandle() : base(true) + { + SetHandle(Interop.ber_alloc(1)); + if (handle == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + } + + internal SafeBerHandle(berval value) : base(true) + { + // In Linux if bv_val is null ber_init will segFault instead of returning IntPtr.Zero. + // In Linux if bv_len is 0 ber_init returns a valid pointer which will then fail when trying to use it, + // so we fail early by throwing exception if this is the case. + if (value.bv_val == IntPtr.Zero || value.bv_len == 0) + { + throw new BerConversionException(); + } + SetHandle(Interop.ber_init(value)); + if (handle == IntPtr.Zero) + { + throw new BerConversionException(); + } + } + + protected override bool ReleaseHandle() + { + Interop.ber_free(handle, 1); + return true; + } + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.Windows.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.Windows.cs new file mode 100644 index 00000000000000..26d3b4992b1bb2 --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.Windows.cs @@ -0,0 +1,94 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Win32.SafeHandles; + +namespace System.DirectoryServices.Protocols +{ + internal sealed class SafeBerHandle : SafeHandleZeroOrMinusOneIsInvalid + { + internal SafeBerHandle() : base(true) + { + SetHandle(Interop.ber_alloc(1)); + if (handle == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + } + + internal SafeBerHandle(berval value) : base(true) + { + SetHandle(Interop.ber_init(value)); + if (handle == IntPtr.Zero) + { + throw new BerConversionException(); + } + } + + protected override bool ReleaseHandle() + { + Interop.ber_free(handle, 1); + return true; + } + } + + internal sealed class ConnectionHandle : SafeHandleZeroOrMinusOneIsInvalid + { + internal bool _needDispose = false; + + internal ConnectionHandle() : base(true) + { + SetHandle(Interop.ldap_init(null, 389)); + + if (handle == IntPtr.Zero) + { + int error = Interop.LdapGetLastError(); + if (Utility.IsLdapError((LdapError)error)) + { + string errorMessage = LdapErrorMappings.MapResultCode(error); + throw new LdapException(error, errorMessage); + } + else + { + throw new LdapException(error); + } + } + } + + internal ConnectionHandle(IntPtr value, bool disposeHandle) : base(true) + { + _needDispose = disposeHandle; + if (value == IntPtr.Zero) + { + int error = Interop.LdapGetLastError(); + if (Utility.IsLdapError((LdapError)error)) + { + string errorMessage = LdapErrorMappings.MapResultCode(error); + throw new LdapException(error, errorMessage); + } + else + { + throw new LdapException(error); + } + } + else + { + SetHandle(value); + } + } + protected override bool ReleaseHandle() + { + if (handle != IntPtr.Zero) + { + if (_needDispose) + { + Interop.ldap_unbind(handle); + } + + handle = IntPtr.Zero; + } + return true; + } + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.cs new file mode 100644 index 00000000000000..0904f64bb092c3 --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/Interop/SafeHandles.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. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; + +namespace System.DirectoryServices.Protocols +{ + internal sealed class HGlobalMemHandle : SafeHandleZeroOrMinusOneIsInvalid + { + internal static IntPtr _dummyPointer = new IntPtr(1); + + internal HGlobalMemHandle(IntPtr value) : base(true) + { + SetHandle(value); + } + + protected override bool ReleaseHandle() + { + if (handle != _dummyPointer) + { + Marshal.FreeHGlobal(handle); + } + return true; + } + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.Linux.cs new file mode 100644 index 00000000000000..2d1b8508cecb18 --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.Linux.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. +// See the LICENSE file in the project root for more information. + +using System.Collections; + +namespace System.DirectoryServices.Protocols +{ + public static partial class BerConverter + { + private static unsafe int DecodeBitStringHelper(ArrayList resultList, SafeBerHandle berElement) + { + // Windows doesn't really decode BitStrings correctly, and wldap32 will internally treat it as 'O' Octet string. + // In order to match behavior, in Linux we will interpret 'B' as 'O' when passing the call to libldap. + + int error = 0; + // return berval + byte[] byteArray = DecodingByteArrayHelper(berElement, 'O', ref error); + if (!BerPal.IsBerDecodeError(error)) + { + // add result to the list + resultList.Add(byteArray); + } + + return error; + } + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.Windows.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.Windows.cs new file mode 100644 index 00000000000000..88e4f250bc30dc --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.Windows.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace System.DirectoryServices.Protocols +{ + public static partial class BerConverter + { + private static unsafe int DecodeBitStringHelper(ArrayList resultList, SafeBerHandle berElement) + { + int error; + // return a bitstring and its length + IntPtr ptrResult = IntPtr.Zero; + int length = 0; + error = BerPal.ScanNextBitString(berElement, "B", ref ptrResult, ref length); + + if (!BerPal.IsBerDecodeError(error)) + { + byte[] byteArray = null; + if (ptrResult != IntPtr.Zero) + { + byteArray = new byte[length]; + Marshal.Copy(ptrResult, byteArray, 0, length); + } + resultList.Add(byteArray); + } + else + { + Debug.WriteLine("ber_scanf for format character 'B' failed"); + } + + // no need to free memory as wldap32 returns the original pointer instead of a duplicating memory pointer that + // needs to be freed + return error; + } + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.cs index 65599433b1a7fc..dde428136c77e0 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.cs @@ -2,15 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections; using System.Diagnostics; -using System.Globalization; using System.Runtime.InteropServices; -using System.Collections; using System.Text; namespace System.DirectoryServices.Protocols { - public static class BerConverter + public static partial class BerConverter { public static byte[] Encode(string format, params object[] value) { @@ -27,7 +26,7 @@ public static byte[] Encode(string format, params object[] value) Debug.WriteLine("Begin encoding\n"); // allocate the berelement - BerSafeHandle berElement = new BerSafeHandle(); + SafeBerHandle berElement = new SafeBerHandle(); int valueCount = 0; int error = 0; @@ -37,7 +36,7 @@ public static byte[] Encode(string format, params object[] value) if (fmt == '{' || fmt == '}' || fmt == '[' || fmt == ']' || fmt == 'n') { // no argument needed - error = Wldap32.ber_printf_emptyarg(berElement, new string(fmt, 1)); + error = BerPal.PrintEmptyArgument(berElement, new string(fmt, 1)); } else if (fmt == 't' || fmt == 'i' || fmt == 'e') { @@ -56,7 +55,7 @@ public static byte[] Encode(string format, params object[] value) } // one int argument - error = Wldap32.ber_printf_int(berElement, new string(fmt, 1), (int)value[valueCount]); + error = BerPal.PrintInt(berElement, new string(fmt, 1), (int)value[valueCount]); // increase the value count valueCount++; @@ -78,7 +77,7 @@ public static byte[] Encode(string format, params object[] value) } // one int argument - error = Wldap32.ber_printf_int(berElement, new string(fmt, 1), (bool)value[valueCount] ? 1 : 0); + error = BerPal.PrintInt(berElement, new string(fmt, 1), (bool)value[valueCount] ? 1 : 0); // increase the value count valueCount++; @@ -220,7 +219,7 @@ public static byte[] Encode(string format, params object[] value) { // can't use SafeBerval here as CLR creates a SafeBerval which points to a different memory location, but when doing memory // deallocation, wldap has special check. So have to use IntPtr directly here. - error = Wldap32.ber_flatten(berElement, ref flattenptr); + error = BerPal.FlattenBerElement(berElement, ref flattenptr); if (error == -1) { @@ -247,7 +246,7 @@ public static byte[] Encode(string format, params object[] value) finally { if (flattenptr != IntPtr.Zero) - Wldap32.ber_bvfree(flattenptr); + BerPal.FreeBerval(flattenptr); } return encodingResult; @@ -273,7 +272,7 @@ internal static object[] TryDecode(string format, byte[] value, out bool decodeS UTF8Encoding utf8Encoder = new UTF8Encoding(false, true); berval berValue = new berval(); ArrayList resultList = new ArrayList(); - BerSafeHandle berElement = null; + SafeBerHandle berElement = null; object[] decodeResult = null; decodeSucceeded = false; @@ -292,7 +291,7 @@ internal static object[] TryDecode(string format, byte[] value, out bool decodeS try { - berElement = new BerSafeHandle(berValue); + berElement = new SafeBerHandle(berValue); } finally { @@ -307,17 +306,17 @@ internal static object[] TryDecode(string format, byte[] value, out bool decodeS char fmt = format[formatCount]; if (fmt == '{' || fmt == '}' || fmt == '[' || fmt == ']' || fmt == 'n' || fmt == 'x') { - error = Wldap32.ber_scanf(berElement, new string(fmt, 1)); + error = BerPal.ScanNext(berElement, new string(fmt, 1)); - if (error != 0) + if (BerPal.IsBerDecodeError(error)) Debug.WriteLine("ber_scanf for {, }, [, ], n or x failed"); } else if (fmt == 'i' || fmt == 'e' || fmt == 'b') { int result = 0; - error = Wldap32.ber_scanf_int(berElement, new string(fmt, 1), ref result); + error = BerPal.ScanNextInt(berElement, new string(fmt, 1), ref result); - if (error == 0) + if (!BerPal.IsBerDecodeError(error)) { if (fmt == 'b') { @@ -341,7 +340,7 @@ internal static object[] TryDecode(string format, byte[] value, out bool decodeS { // return a string byte[] byteArray = DecodingByteArrayHelper(berElement, 'O', ref error); - if (error == 0) + if (!BerPal.IsBerDecodeError(error)) { string s = null; if (byteArray != null) @@ -354,7 +353,7 @@ internal static object[] TryDecode(string format, byte[] value, out bool decodeS { // return berval byte[] byteArray = DecodingByteArrayHelper(berElement, fmt, ref error); - if (error == 0) + if (!BerPal.IsBerDecodeError(error)) { // add result to the list resultList.Add(byteArray); @@ -362,26 +361,7 @@ internal static object[] TryDecode(string format, byte[] value, out bool decodeS } else if (fmt == 'B') { - // return a bitstring and its length - IntPtr ptrResult = IntPtr.Zero; - int length = 0; - error = Wldap32.ber_scanf_bitstring(berElement, "B", ref ptrResult, ref length); - - if (error == 0) - { - byte[] byteArray = null; - if (ptrResult != IntPtr.Zero) - { - byteArray = new byte[length]; - Marshal.Copy(ptrResult, byteArray, 0, length); - } - resultList.Add(byteArray); - } - else - Debug.WriteLine("ber_scanf for format character 'B' failed"); - - // no need to free memory as wldap32 returns the original pointer instead of a duplicating memory pointer that - // needs to be freed + error = DecodeBitStringHelper(resultList, berElement); } else if (fmt == 'v') { @@ -390,7 +370,7 @@ internal static object[] TryDecode(string format, byte[] value, out bool decodeS string[] stringArray = null; byteArrayresult = DecodingMultiByteArrayHelper(berElement, 'V', ref error); - if (error == 0) + if (!BerPal.IsBerDecodeError(error)) { if (byteArrayresult != null) { @@ -416,7 +396,7 @@ internal static object[] TryDecode(string format, byte[] value, out bool decodeS byte[][] result = null; result = DecodingMultiByteArrayHelper(berElement, fmt, ref error); - if (error == 0) + if (!BerPal.IsBerDecodeError(error)) { resultList.Add(result); } @@ -427,7 +407,7 @@ internal static object[] TryDecode(string format, byte[] value, out bool decodeS throw new ArgumentException(SR.BerConverterUndefineChar); } - if (error != 0) + if (BerPal.IsBerDecodeError(error)) { // decode failed, just return return decodeResult; @@ -444,7 +424,7 @@ internal static object[] TryDecode(string format, byte[] value, out bool decodeS return decodeResult; } - private static int EncodingByteArrayHelper(BerSafeHandle berElement, byte[] tempValue, char fmt) + private static int EncodingByteArrayHelper(SafeBerHandle berElement, byte[] tempValue, char fmt) { int error = 0; @@ -454,18 +434,18 @@ private static int EncodingByteArrayHelper(BerSafeHandle berElement, byte[] temp IntPtr tmp = Marshal.AllocHGlobal(tempValue.Length); Marshal.Copy(tempValue, 0, tmp, tempValue.Length); HGlobalMemHandle memHandle = new HGlobalMemHandle(tmp); - - error = Wldap32.ber_printf_bytearray(berElement, new string(fmt, 1), memHandle, tempValue.Length); + error = BerPal.PrintByteArray(berElement, new string(fmt, 1), memHandle, tempValue.Length); } else { - error = Wldap32.ber_printf_bytearray(berElement, new string(fmt, 1), new HGlobalMemHandle(IntPtr.Zero), 0); + HGlobalMemHandle memHandle = new HGlobalMemHandle(HGlobalMemHandle._dummyPointer); + error = BerPal.PrintByteArray(berElement, new string(fmt, 1), memHandle, 0); } return error; } - private static byte[] DecodingByteArrayHelper(BerSafeHandle berElement, char fmt, ref int error) + private static byte[] DecodingByteArrayHelper(SafeBerHandle berElement, char fmt, ref int error) { error = 0; IntPtr result = IntPtr.Zero; @@ -474,11 +454,11 @@ private static byte[] DecodingByteArrayHelper(BerSafeHandle berElement, char fmt // can't use SafeBerval here as CLR creates a SafeBerval which points to a different memory location, but when doing memory // deallocation, wldap has special check. So have to use IntPtr directly here. - error = Wldap32.ber_scanf_ptr(berElement, new string(fmt, 1), ref result); + error = BerPal.ScanNextPtr(berElement, new string(fmt, 1), ref result); try { - if (error == 0) + if (!BerPal.IsBerDecodeError(error)) { if (result != IntPtr.Zero) { @@ -494,17 +474,17 @@ private static byte[] DecodingByteArrayHelper(BerSafeHandle berElement, char fmt finally { if (result != IntPtr.Zero) - Wldap32.ber_bvfree(result); + BerPal.FreeBerval(result); } return byteArray; } - private static int EncodingMultiByteArrayHelper(BerSafeHandle berElement, byte[][] tempValue, char fmt) + private static int EncodingMultiByteArrayHelper(SafeBerHandle berElement, byte[][] tempValue, char fmt) { IntPtr berValArray = IntPtr.Zero; IntPtr tempPtr = IntPtr.Zero; - SafeBerval[] managedBerVal = null; + berval[] managedBervalArray = null; int error = 0; try @@ -513,31 +493,26 @@ private static int EncodingMultiByteArrayHelper(BerSafeHandle berElement, byte[] { int i = 0; berValArray = Utility.AllocHGlobalIntPtrArray(tempValue.Length + 1); - int structSize = Marshal.SizeOf(typeof(SafeBerval)); - managedBerVal = new SafeBerval[tempValue.Length]; + int structSize = Marshal.SizeOf(typeof(berval)); + managedBervalArray = new berval[tempValue.Length]; for (i = 0; i < tempValue.Length; i++) { byte[] byteArray = tempValue[i]; // construct the managed berval - managedBerVal[i] = new SafeBerval(); + managedBervalArray[i] = new berval(); - if (byteArray == null) - { - managedBerVal[i].bv_len = 0; - managedBerVal[i].bv_val = IntPtr.Zero; - } - else + if (byteArray != null) { - managedBerVal[i].bv_len = byteArray.Length; - managedBerVal[i].bv_val = Marshal.AllocHGlobal(byteArray.Length); - Marshal.Copy(byteArray, 0, managedBerVal[i].bv_val, byteArray.Length); + managedBervalArray[i].bv_len = byteArray.Length; + managedBervalArray[i].bv_val = Marshal.AllocHGlobal(byteArray.Length); + Marshal.Copy(byteArray, 0, managedBervalArray[i].bv_val, byteArray.Length); } // allocate memory for the unmanaged structure IntPtr valPtr = Marshal.AllocHGlobal(structSize); - Marshal.StructureToPtr(managedBerVal[i], valPtr, false); + Marshal.StructureToPtr(managedBervalArray[i], valPtr, false); tempPtr = (IntPtr)((long)berValArray + IntPtr.Size * i); Marshal.WriteIntPtr(tempPtr, valPtr); @@ -547,9 +522,7 @@ private static int EncodingMultiByteArrayHelper(BerSafeHandle berElement, byte[] Marshal.WriteIntPtr(tempPtr, IntPtr.Zero); } - error = Wldap32.ber_printf_berarray(berElement, new string(fmt, 1), berValArray); - - GC.KeepAlive(managedBerVal); + error = BerPal.PrintBerArray(berElement, new string(fmt, 1), berValArray); } finally { @@ -563,12 +536,22 @@ private static int EncodingMultiByteArrayHelper(BerSafeHandle berElement, byte[] } Marshal.FreeHGlobal(berValArray); } + if (managedBervalArray != null) + { + foreach (berval managedBerval in managedBervalArray) + { + if (managedBerval.bv_val != IntPtr.Zero) + { + Marshal.FreeHGlobal(managedBerval.bv_val); + } + } + } } return error; } - private static byte[][] DecodingMultiByteArrayHelper(BerSafeHandle berElement, char fmt, ref int error) + private static byte[][] DecodingMultiByteArrayHelper(SafeBerHandle berElement, char fmt, ref int error) { error = 0; // several berval @@ -580,9 +563,9 @@ private static byte[][] DecodingMultiByteArrayHelper(BerSafeHandle berElement, c try { - error = Wldap32.ber_scanf_ptr(berElement, new string(fmt, 1), ref ptrResult); + error = BerPal.ScanNextPtr(berElement, new string(fmt, 1), ref ptrResult); - if (error == 0) + if (!BerPal.IsBerDecodeError(error)) { if (ptrResult != IntPtr.Zero) { @@ -615,7 +598,7 @@ private static byte[][] DecodingMultiByteArrayHelper(BerSafeHandle berElement, c { if (ptrResult != IntPtr.Zero) { - Wldap32.ber_bvecfree(ptrResult); + BerPal.FreeBervalArray(ptrResult); } } diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs index 8a9efa373315df..ca22f76d9d0be3 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs @@ -729,7 +729,7 @@ public override byte[] GetValue() Marshal.WriteIntPtr(tempPtr, IntPtr.Zero); bool critical = IsCritical; - int error = Wldap32.ldap_create_sort_control(UtilityHandle.GetHandle(), memHandle, critical ? (byte)1 : (byte)0, ref control); + int error = LdapPal.CreateDirectorySortControl(UtilityHandle.GetHandle(), memHandle, critical ? (byte)1 : (byte)0, ref control); if (error != 0) { @@ -759,7 +759,7 @@ public override byte[] GetValue() { if (control != IntPtr.Zero) { - Wldap32.ldap_control_free(control); + LdapPal.FreeDirectoryControl(control); } if (memHandle != IntPtr.Zero) diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Linux.cs new file mode 100644 index 00000000000000..6383c1c0446a54 --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Linux.cs @@ -0,0 +1,78 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Net; +using System.Runtime.InteropServices; + +namespace System.DirectoryServices.Protocols +{ + public partial class LdapConnection + { + // Linux doesn't support setting FQDN so we mark the flag as if it is already set so we don't make a call to set it again. + private bool _setFQDNDone = true; + + private void InternalInitConnectionHandle(string hostname) => _ldapHandle = new ConnectionHandle(Interop.ldap_init(hostname, ((LdapDirectoryIdentifier)_directoryIdentifier).PortNumber), _needDispose); + + private int InternalConnectToServer() + { + Debug.Assert(!_ldapHandle.IsInvalid); + // In Linux you don't have to call Connect after calling init. You directly call bind. + return 0; + } + + private int InternalBind(NetworkCredential tempCredential, SEC_WINNT_AUTH_IDENTITY_EX cred, BindMethod method) + { + int error; + if (tempCredential == null && (AuthType == AuthType.External || AuthType == AuthType.Kerberos)) + { + error = BindSasl(); + } + else + { + error = Interop.ldap_simple_bind(_ldapHandle, cred.user, cred.password); + } + + return error; + } + + private int BindSasl() + { + SaslDefaultCredentials defaults = GetSaslDefaults(); + IntPtr ptrToDefaults = Marshal.AllocHGlobal(Marshal.SizeOf(defaults)); + Marshal.StructureToPtr(defaults, ptrToDefaults, false); + try + { + return Interop.ldap_sasl_interactive_bind(_ldapHandle, null, Interop.KerberosDefaultMechanism, IntPtr.Zero, IntPtr.Zero, Interop.LDAP_SASL_QUIET, LdapPal.SaslInteractionProcedure, ptrToDefaults); + } + finally + { + GC.KeepAlive(defaults); //Making sure we keep it in scope as we will still use ptrToDefaults + Marshal.FreeHGlobal(ptrToDefaults); + } + } + + private SaslDefaultCredentials GetSaslDefaults() + { + var defaults = new SaslDefaultCredentials { mech = Interop.KerberosDefaultMechanism }; + IntPtr outValue = IntPtr.Zero; + int error = Interop.ldap_get_option_ptr(_ldapHandle, LdapOption.LDAP_OPT_X_SASL_REALM, ref outValue); + if (error == 0 && outValue != IntPtr.Zero) + { + defaults.realm = Marshal.PtrToStringAnsi(outValue); + } + error = Interop.ldap_get_option_ptr(_ldapHandle, LdapOption.LDAP_OPT_X_SASL_AUTHCID, ref outValue); + if (error == 0 && outValue != IntPtr.Zero) + { + defaults.authcid = Marshal.PtrToStringAnsi(outValue); + } + error = Interop.ldap_get_option_ptr(_ldapHandle, LdapOption.LDAP_OPT_X_SASL_AUTHZID, ref outValue); + if (error == 0 && outValue != IntPtr.Zero) + { + defaults.authzid = Marshal.PtrToStringAnsi(outValue); + } + return defaults; + } + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Windows.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Windows.cs new file mode 100644 index 00000000000000..6ae5eb96143f66 --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.Windows.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Net; + +namespace System.DirectoryServices.Protocols +{ + public partial class LdapConnection + { + private bool _setFQDNDone = false; + + private void InternalInitConnectionHandle(string hostname) + { + LdapDirectoryIdentifier directoryIdentifier = _directoryIdentifier as LdapDirectoryIdentifier; + + // User wants to setup a connectionless session with server. + if (directoryIdentifier.Connectionless) + { + _ldapHandle = new ConnectionHandle(Interop.cldap_open(hostname, directoryIdentifier.PortNumber), _needDispose); + } + else + { + _ldapHandle = new ConnectionHandle(Interop.ldap_init(hostname, directoryIdentifier.PortNumber), _needDispose); + } + } + + private int InternalConnectToServer() + { + // Connect explicitly to the server. + var timeout = new LDAP_TIMEVAL() + { + tv_sec = (int)(_connectionTimeOut.Ticks / TimeSpan.TicksPerSecond) + }; + Debug.Assert(!_ldapHandle.IsInvalid); + return Interop.ldap_connect(_ldapHandle, timeout); + } + + private int InternalBind(NetworkCredential tempCredential, SEC_WINNT_AUTH_IDENTITY_EX cred, BindMethod method) + => tempCredential == null && AuthType == AuthType.External ? Interop.ldap_bind_s(_ldapHandle, null, null, method) : Interop.ldap_bind_s(_ldapHandle, null, cred, method); + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.cs index eef1bd29f82107..c66383e6d8a97f 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapConnection.cs @@ -12,6 +12,7 @@ using System.Xml; using System.Threading; using System.Security.Cryptography.X509Certificates; +using System.Diagnostics.CodeAnalysis; namespace System.DirectoryServices.Protocols { @@ -20,7 +21,7 @@ namespace System.DirectoryServices.Protocols [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate bool QUERYCLIENTCERT(IntPtr Connection, IntPtr trusted_CAs, ref IntPtr certificateHandle); - public class LdapConnection : DirectoryConnection, IDisposable + public partial class LdapConnection : DirectoryConnection, IDisposable { internal enum LdapResult { @@ -48,7 +49,6 @@ internal enum LdapResult private static readonly LdapPartialResultsProcessor s_partialResultsProcessor = null; private static readonly ManualResetEvent s_waitHandle = null; private static readonly PartialResultsRetriever s_retriever = null; - private bool _setFQDNDone = false; internal bool _needDispose = true; private bool _connected = false; internal QUERYCLIENTCERT _clientCertificateRoutine = null; @@ -216,15 +216,7 @@ internal void Init() } } - // User wants to setup a connectionless session with server. - if (((LdapDirectoryIdentifier)_directoryIdentifier).Connectionless == true) - { - _ldapHandle = new ConnectionHandle(Wldap32.cldap_open(hostname, ((LdapDirectoryIdentifier)_directoryIdentifier).PortNumber), _needDispose); - } - else - { - _ldapHandle = new ConnectionHandle(Wldap32.ldap_init(hostname, ((LdapDirectoryIdentifier)_directoryIdentifier).PortNumber), _needDispose); - } + InternalInitConnectionHandle(hostname); // Create a WeakReference object with the target of ldapHandle and put it into our handle table. lock (s_objectLock) @@ -303,7 +295,7 @@ public DirectoryResponse SendRequest(DirectoryRequest request, TimeSpan requestT if (error == 0) { // Success code but message is -1, unexpected. - error = Wldap32.LdapGetLastError(); + error = LdapPal.GetLastErrorFromConnection(_ldapHandle); } throw ConstructException(error, operation); @@ -406,7 +398,7 @@ public IAsyncResult BeginSendRequest(DirectoryRequest request, TimeSpan requestT if (error == 0) { // Success code but message is -1, unexpected. - error = Wldap32.LdapGetLastError(); + error = LdapPal.GetLastErrorFromConnection(_ldapHandle); } throw ConstructException(error, operation); @@ -476,7 +468,7 @@ public void Abort(IAsyncResult asyncResult) } // Cancel the request. - Wldap32.ldap_abandon(_ldapHandle, messageId); + LdapPal.CancelDirectoryAsyncOperation(_ldapHandle, messageId); LdapRequestState resultObject = result._resultObject; if (resultObject != null) @@ -634,17 +626,18 @@ private int SendRequestHelper(DirectoryRequest request, ref int messageID) if (request is DeleteRequest) { // It is an delete operation. - error = Wldap32.ldap_delete_ext(_ldapHandle, ((DeleteRequest)request).DistinguishedName, serverControlArray, clientControlArray, ref messageID); + error = LdapPal.DeleteDirectoryEntry(_ldapHandle, ((DeleteRequest)request).DistinguishedName, serverControlArray, clientControlArray, ref messageID); } else if (request is ModifyDNRequest) { // It is a modify dn operation - error = Wldap32.ldap_rename(_ldapHandle, - ((ModifyDNRequest)request).DistinguishedName, - ((ModifyDNRequest)request).NewName, - ((ModifyDNRequest)request).NewParentDistinguishedName, - ((ModifyDNRequest)request).DeleteOldRdn ? 1 : 0, - serverControlArray, clientControlArray, ref messageID); + error = LdapPal.RenameDirectoryEntry( + _ldapHandle, + ((ModifyDNRequest)request).DistinguishedName, + ((ModifyDNRequest)request).NewName, + ((ModifyDNRequest)request).NewParentDistinguishedName, + ((ModifyDNRequest)request).DeleteOldRdn ? 1 : 0, + serverControlArray, clientControlArray, ref messageID); } else if (request is CompareRequest compareRequest) { @@ -680,12 +673,13 @@ private int SendRequestHelper(DirectoryRequest request, ref int messageID) } // It is a compare request. - error = Wldap32.ldap_compare(_ldapHandle, - ((CompareRequest)request).DistinguishedName, - assertion.Name, - stringValue, - berValuePtr, - serverControlArray, clientControlArray, ref messageID); + error = LdapPal.CompareDirectoryEntries( + _ldapHandle, + ((CompareRequest)request).DistinguishedName, + assertion.Name, + stringValue, + berValuePtr, + serverControlArray, clientControlArray, ref messageID); } else if (request is AddRequest || request is ModifyRequest) { @@ -715,17 +709,19 @@ private int SendRequestHelper(DirectoryRequest request, ref int messageID) if (request is AddRequest) { - error = Wldap32.ldap_add(_ldapHandle, - ((AddRequest)request).DistinguishedName, - modArray, - serverControlArray, clientControlArray, ref messageID); + error = LdapPal.AddDirectoryEntry( + _ldapHandle, + ((AddRequest)request).DistinguishedName, + modArray, + serverControlArray, clientControlArray, ref messageID); } else { - error = Wldap32.ldap_modify(_ldapHandle, - ((ModifyRequest)request).DistinguishedName, - modArray, - serverControlArray, clientControlArray, ref messageID); + error = LdapPal.ModifyDirectoryEntry( + _ldapHandle, + ((ModifyRequest)request).DistinguishedName, + modArray, + serverControlArray, clientControlArray, ref messageID); } } else if (request is ExtendedRequest extendedRequest) @@ -744,10 +740,11 @@ private int SendRequestHelper(DirectoryRequest request, ref int messageID) Marshal.Copy(val, 0, berValuePtr.bv_val, val.Length); } - error = Wldap32.ldap_extended_operation(_ldapHandle, - name, - berValuePtr, - serverControlArray, clientControlArray, ref messageID); + error = LdapPal.ExtendedDirectoryOperation( + _ldapHandle, + name, + berValuePtr, + serverControlArray, clientControlArray, ref messageID); } else if (request is SearchRequest searchRequest) { @@ -772,7 +769,7 @@ private int SendRequestHelper(DirectoryRequest request, ref int messageID) int i = 0; for (i = 0; i < attributeCount; i++) { - IntPtr controlPtr = Marshal.StringToHGlobalUni(searchRequest.Attributes[i]); + IntPtr controlPtr = LdapPal.StringToPtr(searchRequest.Attributes[i]); tempPtr = (IntPtr)((long)searchAttributes + IntPtr.Size * i); Marshal.WriteIntPtr(tempPtr, controlPtr); } @@ -793,17 +790,18 @@ private int SendRequestHelper(DirectoryRequest request, ref int messageID) try { - error = Wldap32.ldap_search(_ldapHandle, - searchRequest.DistinguishedName, - searchScope, - searchRequestFilter, - searchAttributes, - searchRequest.TypesOnly, - serverControlArray, - clientControlArray, - searchTimeLimit, - searchRequest.SizeLimit, - ref messageID); + error = LdapPal.SearchDirectory( + _ldapHandle, + searchRequest.DistinguishedName, + searchScope, + searchRequestFilter, + searchAttributes, + searchRequest.TypesOnly, + serverControlArray, + clientControlArray, + searchTimeLimit, + searchRequest.SizeLimit, + ref messageID); } finally { @@ -1006,7 +1004,7 @@ private void Connect() // Set the certificate callback routine here if user adds the certifcate to the certificate collection. if (ClientCertificates.Count != 0) { - int certError = Wldap32.ldap_set_option_clientcert(_ldapHandle, LdapOption.LDAP_OPT_CLIENT_CERTIFICATE, _clientCertificateRoutine); + int certError = LdapPal.SetClientCertOption(_ldapHandle, LdapOption.LDAP_OPT_CLIENT_CERTIFICATE, _clientCertificateRoutine); if (certError != (int)ResultCode.Success) { if (Utility.IsLdapError((LdapError)certError)) @@ -1025,19 +1023,13 @@ private void Connect() // Set the LDAP_OPT_AREC_EXCLUSIVE flag if necessary. if (((LdapDirectoryIdentifier)Directory).FullyQualifiedDnsHostName && !_setFQDNDone) { - SessionOptions.FQDN = true; + SessionOptions.SetFqdnRequired(); _setFQDNDone = true; } - // Connect explicitly to the server. - var timeout = new LDAP_TIMEVAL() - { - tv_sec = (int)(_connectionTimeOut.Ticks / TimeSpan.TicksPerSecond) - }; - Debug.Assert(!_ldapHandle.IsInvalid); - int error = Wldap32.ldap_connect(_ldapHandle, timeout); + int error = InternalConnectToServer(); - // Filed, throw an exception. + // Failed, throw an exception. if (error != (int)ResultCode.Success) { if (Utility.IsLdapError((LdapError)error)) @@ -1106,7 +1098,7 @@ private void BindHelper(NetworkCredential newCredential, bool needSetCredential) int error; if (AuthType == AuthType.Anonymous) { - error = Wldap32.ldap_simple_bind_s(_ldapHandle, null, null); + error = LdapPal.BindToDirectory(_ldapHandle, null, null); } else if (AuthType == AuthType.Basic) { @@ -1118,19 +1110,19 @@ private void BindHelper(NetworkCredential newCredential, bool needSetCredential) } tempDomainName.Append(username); - error = Wldap32.ldap_simple_bind_s(_ldapHandle, tempDomainName.ToString(), password); + error = LdapPal.BindToDirectory(_ldapHandle, tempDomainName.ToString(), password); } else { var cred = new SEC_WINNT_AUTH_IDENTITY_EX() { - version = Wldap32.SEC_WINNT_AUTH_IDENTITY_VERSION, + version = Interop.SEC_WINNT_AUTH_IDENTITY_VERSION, length = Marshal.SizeOf(typeof(SEC_WINNT_AUTH_IDENTITY_EX)), - flags = Wldap32.SEC_WINNT_AUTH_IDENTITY_UNICODE + flags = Interop.SEC_WINNT_AUTH_IDENTITY_UNICODE }; if (AuthType == AuthType.Kerberos) { - cred.packageList = Wldap32.MICROSOFT_KERBEROS_NAME_W; + cred.packageList = Interop.MICROSOFT_KERBEROS_NAME_W; cred.packageListLength = cred.packageList.Length; } @@ -1173,14 +1165,7 @@ private void BindHelper(NetworkCredential newCredential, bool needSetCredential) break; } - if (tempCredential == null && AuthType == AuthType.External) - { - error = Wldap32.ldap_bind_s(_ldapHandle, null, null, method); - } - else - { - error = Wldap32.ldap_bind_s(_ldapHandle, null, cred, method); - } + error = InternalBind(tempCredential, cred, method); } // Failed, throw exception. @@ -1275,7 +1260,7 @@ internal LdapControl[] BuildControlArray(DirectoryControlCollection controls, bo managedControls[i] = new LdapControl() { // Get the control type. - ldctl_oid = Marshal.StringToHGlobalUni(((DirectoryControl)controlList[i]).Type), + ldctl_oid = LdapPal.StringToPtr(((DirectoryControl)controlList[i]).Type), // Get the control cricality. ldctl_iscritical = ((DirectoryControl)controlList[i]).IsCritical @@ -1358,7 +1343,7 @@ internal LdapMod[] BuildAttributes(CollectionBase directoryAttributes, ArrayList attributes[i].type |= LDAP_MOD_BVALUES; // Write the attribute name. - attributes[i].attribute = Marshal.StringToHGlobalUni(modAttribute.Name); + attributes[i].attribute = LdapPal.StringToPtr(modAttribute.Name); // Write the values. int valuesCount = 0; @@ -1451,7 +1436,7 @@ internal DirectoryResponse ConstructResponse(int messageId, LdapOperation operat needAbandon = false; } - int error = Wldap32.ldap_result(_ldapHandle, messageId, (int)resultType, timeout, ref ldapResult); + int error = LdapPal.GetResultFromAsyncOperation(_ldapHandle, messageId, (int)resultType, timeout, ref ldapResult); if (error != -1 && error != 0) { // parsing the result @@ -1499,13 +1484,13 @@ internal DirectoryResponse ConstructResponse(int messageId, LdapOperation operat response = new ExtendedResponse(responseDn, responseControl, (ResultCode)resultError, responseMessage, responseReferral); if (resultError == (int)ResultCode.Success) { - resultError = Wldap32.ldap_parse_extended_result(_ldapHandle, ldapResult, ref requestName, ref requestValue, 0 /*not free it*/); + resultError = LdapPal.ParseExtendedResult(_ldapHandle, ldapResult, ref requestName, ref requestValue, 0 /*not free it*/); if (resultError == 0) { string name = null; if (requestName != IntPtr.Zero) { - name = Marshal.PtrToStringUni(requestName); + name = LdapPal.PtrToString(requestName); } berval val = null; @@ -1542,7 +1527,7 @@ internal DirectoryResponse ConstructResponse(int messageId, LdapOperation operat SearchResultReferenceCollection searchResultReferences = new SearchResultReferenceCollection(); // parsing the resultentry - entryMessage = Wldap32.ldap_first_entry(_ldapHandle, ldapResult); + entryMessage = LdapPal.GetFirstEntryFromResult(_ldapHandle, ldapResult); int entrycount = 0; while (entryMessage != IntPtr.Zero) @@ -1554,11 +1539,11 @@ internal DirectoryResponse ConstructResponse(int messageId, LdapOperation operat } entrycount++; - entryMessage = Wldap32.ldap_next_entry(_ldapHandle, entryMessage); + entryMessage = LdapPal.GetNextEntryFromResult(_ldapHandle, entryMessage); } // Parse the reference. - IntPtr referenceMessage = Wldap32.ldap_first_reference(_ldapHandle, ldapResult); + IntPtr referenceMessage = LdapPal.GetFirstReferenceFromResult(_ldapHandle, ldapResult); while (referenceMessage != IntPtr.Zero) { @@ -1568,7 +1553,7 @@ internal DirectoryResponse ConstructResponse(int messageId, LdapOperation operat searchResultReferences.Add(reference); } - referenceMessage = Wldap32.ldap_next_reference(_ldapHandle, referenceMessage); + referenceMessage = LdapPal.GetNextReferenceFromResult(_ldapHandle, referenceMessage); } ((SearchResponse)response).Entries = searchResultEntries; @@ -1601,17 +1586,17 @@ internal DirectoryResponse ConstructResponse(int messageId, LdapOperation operat { if (requestName != IntPtr.Zero) { - Wldap32.ldap_memfree(requestName); + LdapPal.FreeMemory(requestName); } if (requestValue != IntPtr.Zero) { - Wldap32.ldap_memfree(requestValue); + LdapPal.FreeMemory(requestValue); } if (ldapResult != IntPtr.Zero) { - Wldap32.ldap_msgfree(ldapResult); + LdapPal.FreeMemory(ldapResult); } } } @@ -1634,13 +1619,13 @@ internal DirectoryResponse ConstructResponse(int messageId, LdapOperation operat } else { - error = Wldap32.LdapGetLastError(); + error = LdapPal.GetLastErrorFromConnection(_ldapHandle); } // Abandon the request. if (needAbandon) { - Wldap32.ldap_abandon(_ldapHandle, messageId); + LdapPal.CancelDirectoryAsyncOperation(_ldapHandle, messageId); } } @@ -1657,15 +1642,15 @@ internal unsafe int ConstructParsedResult(IntPtr ldapResult, ref int serverError try { - int resultError = Wldap32.ldap_parse_result(_ldapHandle, ldapResult, ref serverError, ref dn, ref message, ref referral, ref control, 0 /* not free it */); + int resultError = LdapPal.ParseResult(_ldapHandle, ldapResult, ref serverError, ref dn, ref message, ref referral, ref control, 0 /* not free it */); if (resultError == 0) { // Parse the dn. - responseDn = Marshal.PtrToStringUni(dn); + responseDn = LdapPal.PtrToString(dn); // Parse the message. - responseMessage = Marshal.PtrToStringUni(message); + responseMessage = LdapPal.PtrToString(message); // Parse the referral. if (referral != IntPtr.Zero) @@ -1676,7 +1661,7 @@ internal unsafe int ConstructParsedResult(IntPtr ldapResult, ref int serverError var referralList = new ArrayList(); while (singleReferral != null) { - string s = Marshal.PtrToStringUni((IntPtr)singleReferral); + string s = LdapPal.PtrToString((IntPtr)singleReferral); referralList.Add(s); i++; @@ -1718,7 +1703,7 @@ internal unsafe int ConstructParsedResult(IntPtr ldapResult, ref int serverError // we need to take care of one special case, when can't connect to the server, ldap_parse_result fails with local error if (resultError == (int)LdapError.LocalError) { - int tmpResult = Wldap32.ldap_result2error(_ldapHandle, ldapResult, 0 /* not free it */); + int tmpResult = LdapPal.ResultToErrorCode(_ldapHandle, ldapResult, 0 /* not free it */); if (tmpResult != 0) { resultError = tmpResult; @@ -1732,22 +1717,22 @@ internal unsafe int ConstructParsedResult(IntPtr ldapResult, ref int serverError { if (dn != IntPtr.Zero) { - Wldap32.ldap_memfree(dn); + LdapPal.FreeMemory(dn); } if (message != IntPtr.Zero) { - Wldap32.ldap_memfree(message); + LdapPal.FreeMemory(message); } if (referral != IntPtr.Zero) { - Wldap32.ldap_value_free(referral); + LdapPal.FreeValue(referral); } if (control != IntPtr.Zero) { - Wldap32.ldap_controls_free(control); + LdapPal.FreeDirectoryControls(control); } } } @@ -1762,11 +1747,11 @@ internal SearchResultEntry ConstructEntry(IntPtr entryMessage) { // Get the dn. string entryDn = null; - dn = Wldap32.ldap_get_dn(_ldapHandle, entryMessage); + dn = LdapPal.GetDistinguishedName(_ldapHandle, entryMessage); if (dn != IntPtr.Zero) { - entryDn = Marshal.PtrToStringUni(dn); - Wldap32.ldap_memfree(dn); + entryDn = LdapPal.PtrToString(dn); + LdapPal.FreeMemory(dn); dn = IntPtr.Zero; } @@ -1774,7 +1759,7 @@ internal SearchResultEntry ConstructEntry(IntPtr entryMessage) SearchResultAttributeCollection attributes = resultEntry.Attributes; // Get attributes. - attribute = Wldap32.ldap_first_attribute(_ldapHandle, entryMessage, ref address); + attribute = LdapPal.GetFirstAttributeFromEntry(_ldapHandle, entryMessage, ref address); int tempcount = 0; while (attribute != IntPtr.Zero) @@ -1782,14 +1767,14 @@ internal SearchResultEntry ConstructEntry(IntPtr entryMessage) DirectoryAttribute attr = ConstructAttribute(entryMessage, attribute); attributes.Add(attr.Name, attr); - Wldap32.ldap_memfree(attribute); + LdapPal.FreeMemory(attribute); tempcount++; - attribute = Wldap32.ldap_next_attribute(_ldapHandle, entryMessage, address); + attribute = LdapPal.GetNextAttributeFromResult(_ldapHandle, entryMessage, address); } if (address != IntPtr.Zero) { - Wldap32.ber_free(address, 0); + BerPal.FreeBerElement(address, 0); address = IntPtr.Zero; } @@ -1799,17 +1784,17 @@ internal SearchResultEntry ConstructEntry(IntPtr entryMessage) { if (dn != IntPtr.Zero) { - Wldap32.ldap_memfree(dn); + LdapPal.FreeMemory(dn); } if (attribute != IntPtr.Zero) { - Wldap32.ldap_memfree(attribute); + LdapPal.FreeMemory(attribute); } if (address != IntPtr.Zero) { - Wldap32.ber_free(address, 0); + BerPal.FreeBerElement(address, 0); } } } @@ -1821,10 +1806,9 @@ internal DirectoryAttribute ConstructAttribute(IntPtr entryMessage, IntPtr attri _isSearchResult = true }; - string name = Marshal.PtrToStringUni(attributeName); + string name = LdapPal.PtrToString(attributeName); attribute.Name = name; - - IntPtr valuesArray = Wldap32.ldap_get_values_len(_ldapHandle, entryMessage, name); + IntPtr valuesArray = LdapPal.GetValuesFromAttribute(_ldapHandle, entryMessage, name); try { if (valuesArray != IntPtr.Zero) @@ -1852,7 +1836,7 @@ internal DirectoryAttribute ConstructAttribute(IntPtr entryMessage, IntPtr attri { if (valuesArray != IntPtr.Zero) { - Wldap32.ldap_value_free_len(valuesArray); + LdapPal.FreeAttributes(valuesArray); } } @@ -1862,8 +1846,7 @@ internal DirectoryAttribute ConstructAttribute(IntPtr entryMessage, IntPtr attri internal SearchResultReference ConstructReference(IntPtr referenceMessage) { IntPtr referenceArray = IntPtr.Zero; - - int error = Wldap32.ldap_parse_reference(_ldapHandle, referenceMessage, ref referenceArray); + int error = LdapPal.ParseReference(_ldapHandle, referenceMessage, ref referenceArray); try { @@ -1877,14 +1860,14 @@ internal SearchResultReference ConstructReference(IntPtr referenceMessage) tempPtr = Marshal.ReadIntPtr(referenceArray, IntPtr.Size * count); while (tempPtr != IntPtr.Zero) { - string s = Marshal.PtrToStringUni(tempPtr); + string s = LdapPal.PtrToString(tempPtr); referralList.Add(s); count++; tempPtr = Marshal.ReadIntPtr(referenceArray, IntPtr.Size * count); } - Wldap32.ldap_value_free(referenceArray); + LdapPal.FreeValue(referenceArray); referenceArray = IntPtr.Zero; } @@ -1904,7 +1887,7 @@ internal SearchResultReference ConstructReference(IntPtr referenceMessage) { if (referenceArray != IntPtr.Zero) { - Wldap32.ldap_value_free(referenceArray); + LdapPal.FreeValue(referenceArray); } } @@ -1973,7 +1956,7 @@ private DirectoryControl ConstructControl(IntPtr controlPtr) Marshal.PtrToStructure(controlPtr, control); Debug.Assert(control.ldctl_oid != IntPtr.Zero); - string controlType = Marshal.PtrToStringUni(control.ldctl_oid); + string controlType = LdapPal.PtrToString(control.ldctl_oid); byte[] bytes = new byte[control.ldctl_value.bv_len]; Marshal.Copy(control.ldctl_value.bv_val, bytes, 0, control.ldctl_value.bv_len); diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapPartialResultsProcessor.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapPartialResultsProcessor.cs index 0477e494f9f2de..3d6b85838ca013 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapPartialResultsProcessor.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapPartialResultsProcessor.cs @@ -214,7 +214,7 @@ private void GetResultsHelper(LdapPartialAsyncResult asyncResult) asyncResult._resultStatus = ResultsStatus.Done; // Need to abandon this request. - Wldap32.ldap_abandon(connection._ldapHandle, asyncResult._messageID); + LdapPal.CancelDirectoryAsyncOperation(connection._ldapHandle, asyncResult._messageID); } } diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs new file mode 100644 index 00000000000000..209aa7447abd87 --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Linux.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.DirectoryServices.Protocols +{ + public partial class LdapSessionOptions + { + private static void PALCertFreeCRLContext(IntPtr certPtr) { /* No op */ } + + public bool SecureSocketLayer + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs new file mode 100644 index 00000000000000..e78154995ea794 --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.Windows.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.DirectoryServices.Protocols +{ + public partial class LdapSessionOptions + { + private static void PALCertFreeCRLContext(IntPtr certPtr) => Interop.CertFreeCRLContext(certPtr); + + public bool SecureSocketLayer + { + get + { + int outValue = GetIntValueHelper(LdapOption.LDAP_OPT_SSL); + return outValue == 1; + } + set + { + int temp = value ? 1 : 0; + SetIntValueHelper(LdapOption.LDAP_OPT_SSL, temp); + } + } + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.cs index 2ff8d02bc4eb22..e59d8352ab68ef 100644 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.cs +++ b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/LdapSessionOptions.cs @@ -116,7 +116,7 @@ internal struct SecurityHandle public IntPtr Upper; } - public class LdapSessionOptions + public partial class LdapSessionOptions { private readonly LdapConnection _connection = null; private ReferralCallback _callbackRoutine = new ReferralCallback(); @@ -155,20 +155,6 @@ public ReferralChasingOptions ReferralChasing } } - public bool SecureSocketLayer - { - get - { - int outValue = GetIntValueHelper(LdapOption.LDAP_OPT_SSL); - return outValue == 1; - } - set - { - int temp = value ? 1 : 0; - SetIntValueHelper(LdapOption.LDAP_OPT_SSL, temp); - } - } - public int ReferralHopLimit { get => GetIntValueHelper(LdapOption.LDAP_OPT_REFERRAL_HOP_LIMIT); @@ -319,7 +305,7 @@ public SecurityPackageContextConnectionInformation SslInformation } var secInfo = new SecurityPackageContextConnectionInformation(); - int error = Wldap32.ldap_get_option_secInfo(_connection._ldapHandle, LdapOption.LDAP_OPT_SSL_INFO, secInfo); + int error = LdapPal.GetSecInfoOption(_connection._ldapHandle, LdapOption.LDAP_OPT_SSL_INFO, secInfo); ErrorChecking.CheckAndSetLdapError(error); return secInfo; @@ -337,7 +323,7 @@ public object SecurityContext SecurityHandle tempHandle = default; - int error = Wldap32.ldap_get_option_sechandle(_connection._ldapHandle, LdapOption.LDAP_OPT_SECURITY_CONTEXT, ref tempHandle); + int error = LdapPal.GetSecurityHandleOption(_connection._ldapHandle, LdapOption.LDAP_OPT_SECURITY_CONTEXT, ref tempHandle); ErrorChecking.CheckAndSetLdapError(error); return tempHandle; @@ -489,7 +475,7 @@ public QueryClientCertificateCallback QueryClientCertificate if (value != null) { - int certError = Wldap32.ldap_set_option_clientcert(_connection._ldapHandle, LdapOption.LDAP_OPT_CLIENT_CERTIFICATE, _connection._clientCertificateRoutine); + int certError = LdapPal.SetClientCertOption(_connection._ldapHandle, LdapOption.LDAP_OPT_CLIENT_CERTIFICATE, _connection._clientCertificateRoutine); if (certError != (int)ResultCode.Success) { if (Utility.IsLdapError((LdapError)certError)) @@ -531,7 +517,7 @@ public VerifyServerCertificateCallback VerifyServerCertificate if (value != null) { - int error = Wldap32.ldap_set_option_servercert(_connection._ldapHandle, LdapOption.LDAP_OPT_SERVER_CERTIFICATE, _serverCertificateRoutine); + int error = LdapPal.SetServerCertOption(_connection._ldapHandle, LdapOption.LDAP_OPT_SERVER_CERTIFICATE, _serverCertificateRoutine); ErrorChecking.CheckAndSetLdapError(error); } @@ -547,13 +533,9 @@ internal DereferenceAlias DerefAlias set => SetIntValueHelper(LdapOption.LDAP_OPT_DEREF, (int)value); } - internal bool FQDN + internal void SetFqdnRequired() { - set - { - // set the value to true - SetIntValueHelper(LdapOption.LDAP_OPT_AREC_EXCLUSIVE, 1); - } + SetIntValueHelper(LdapOption.LDAP_OPT_AREC_EXCLUSIVE, 1); } public void FastConcurrentBind() @@ -569,7 +551,7 @@ public void FastConcurrentBind() // Do the fast concurrent bind. int inValue = 1; - int error = Wldap32.ldap_set_option_int(_connection._ldapHandle, LdapOption.LDAP_OPT_FAST_CONCURRENT_BIND, ref inValue); + int error = LdapPal.SetIntOption(_connection._ldapHandle, LdapOption.LDAP_OPT_FAST_CONCURRENT_BIND, ref inValue); ErrorChecking.CheckAndSetLdapError(error); } @@ -629,11 +611,11 @@ public unsafe void StartTransportLayerSecurity(DirectoryControlCollection contro Marshal.WriteIntPtr(tempPtr, IntPtr.Zero); } - int error = Wldap32.ldap_start_tls(_connection._ldapHandle, ref serverError, ref ldapResult, serverControlArray, clientControlArray); + int error = LdapPal.StartTls(_connection._ldapHandle, ref serverError, ref ldapResult, serverControlArray, clientControlArray); if (ldapResult != IntPtr.Zero) { // Parse the referral. - int resultError = Wldap32.ldap_parse_result_referral(_connection._ldapHandle, ldapResult, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref referral, IntPtr.Zero, 0 /* not free it */); + int resultError = LdapPal.ParseResultReferral(_connection._ldapHandle, ldapResult, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref referral, IntPtr.Zero, 0 /* not free it */); if (resultError == 0 && referral != IntPtr.Zero) { char** referralPtr = (char**)referral; @@ -642,7 +624,7 @@ public unsafe void StartTransportLayerSecurity(DirectoryControlCollection contro ArrayList referralList = new ArrayList(); while (singleReferral != null) { - string s = Marshal.PtrToStringUni((IntPtr)singleReferral); + string s = LdapPal.PtrToString((IntPtr)singleReferral); referralList.Add(s); i++; @@ -652,7 +634,7 @@ public unsafe void StartTransportLayerSecurity(DirectoryControlCollection contro // Free heap memory. if (referral != IntPtr.Zero) { - Wldap32.ldap_value_free(referral); + LdapPal.FreeValue(referral); referral = IntPtr.Zero; } @@ -759,7 +741,7 @@ public unsafe void StartTransportLayerSecurity(DirectoryControlCollection contro if (referral != IntPtr.Zero) { - Wldap32.ldap_value_free(referral); + LdapPal.FreeValue(referral); } } } @@ -771,7 +753,7 @@ public void StopTransportLayerSecurity() throw new ObjectDisposedException(GetType().Name); } - byte result = Wldap32.ldap_stop_tls(_connection._ldapHandle); + byte result = LdapPal.StopTls(_connection._ldapHandle); if (result == 0) { throw new TlsOperationException(null, SR.TLSStopFailure); @@ -786,7 +768,7 @@ private int GetIntValueHelper(LdapOption option) } int outValue = 0; - int error = Wldap32.ldap_get_option_int(_connection._ldapHandle, option, ref outValue); + int error = LdapPal.GetIntOption(_connection._ldapHandle, option, ref outValue); ErrorChecking.CheckAndSetLdapError(error); return outValue; @@ -800,7 +782,7 @@ private void SetIntValueHelper(LdapOption option, int value) } int temp = value; - int error = Wldap32.ldap_set_option_int(_connection._ldapHandle, option, ref temp); + int error = LdapPal.SetIntOption(_connection._ldapHandle, option, ref temp); ErrorChecking.CheckAndSetLdapError(error); } @@ -813,18 +795,18 @@ private string GetStringValueHelper(LdapOption option, bool releasePtr) } IntPtr outValue = new IntPtr(0); - int error = Wldap32.ldap_get_option_ptr(_connection._ldapHandle, option, ref outValue); + int error = LdapPal.GetPtrOption(_connection._ldapHandle, option, ref outValue); ErrorChecking.CheckAndSetLdapError(error); string stringValue = null; if (outValue != IntPtr.Zero) { - stringValue = Marshal.PtrToStringUni(outValue); + stringValue = LdapPal.PtrToString(outValue); } if (releasePtr) { - Wldap32.ldap_memfree(outValue); + LdapPal.FreeMemory(outValue); } return stringValue; @@ -840,12 +822,12 @@ private void SetStringValueHelper(LdapOption option, string value) IntPtr inValue = IntPtr.Zero; if (value != null) { - inValue = Marshal.StringToHGlobalUni(value); + inValue = LdapPal.StringToPtr(value); } try { - int error = Wldap32.ldap_set_option_ptr(_connection._ldapHandle, option, ref inValue); + int error = LdapPal.SetPtrOption(_connection._ldapHandle, option, ref inValue); ErrorChecking.CheckAndSetLdapError(error); } finally @@ -866,8 +848,7 @@ private void ProcessCallBackRoutine(ReferralCallback tempCallback) notify = tempCallback.NotifyNewConnection == null ? null : _notifiyDelegate, dereference = tempCallback.DereferenceConnection == null ? null : _dereferenceDelegate }; - - int error = Wldap32.ldap_set_option_referral(_connection._ldapHandle, LdapOption.LDAP_OPT_REFERRAL_CALLBACK, ref value); + int error = LdapPal.SetReferralOption(_connection._ldapHandle, LdapOption.LDAP_OPT_REFERRAL_CALLBACK, ref value); ErrorChecking.CheckAndSetLdapError(error); } @@ -884,7 +865,7 @@ private int ProcessQueryConnection(IntPtr PrimaryConnection, IntPtr ReferralFrom { if (NewDNPtr != IntPtr.Zero) { - NewDN = Marshal.PtrToStringUni(NewDNPtr); + NewDN = LdapPal.PtrToString(NewDNPtr); } var target = new StringBuilder(); @@ -951,7 +932,7 @@ private bool ProcessNotifyConnection(IntPtr primaryConnection, IntPtr referralFr string newDN = null; if (newDNPtr != IntPtr.Zero) { - newDN = Marshal.PtrToStringUni(newDNPtr); + newDN = LdapPal.PtrToString(newDNPtr); } var target = new StringBuilder(); @@ -1099,7 +1080,7 @@ private bool ProcessServerCertificate(IntPtr connection, IntPtr serverCert) } finally { - Wldap32.CertFreeCRLContext(certPtr); + PALCertFreeCRLContext(certPtr); } value = _serverCertificateDelegate(_connection, certificate); diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/SafeHandles.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/SafeHandles.cs deleted file mode 100644 index 50a49660e34aca..00000000000000 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/SafeHandles.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Win32.SafeHandles; -using System.Runtime.InteropServices; -using System.Security; - -namespace System.DirectoryServices.Protocols -{ - internal sealed class BerSafeHandle : SafeHandleZeroOrMinusOneIsInvalid - { - internal BerSafeHandle() : base(true) - { - SetHandle(Wldap32.ber_alloc(1)); - if (handle == IntPtr.Zero) - { - throw new OutOfMemoryException(); - } - } - - internal BerSafeHandle(berval value) : base(true) - { - SetHandle(Wldap32.ber_init(value)); - if (handle == IntPtr.Zero) - { - throw new BerConversionException(); - } - } - - protected override bool ReleaseHandle() - { - Wldap32.ber_free(handle, 1); - return true; - } - } - - internal sealed class HGlobalMemHandle : SafeHandleZeroOrMinusOneIsInvalid - { - internal HGlobalMemHandle(IntPtr value) : base(true) - { - SetHandle(value); - } - - protected override bool ReleaseHandle() - { - Marshal.FreeHGlobal(handle); - return true; - } - } - - internal sealed class ConnectionHandle : SafeHandleZeroOrMinusOneIsInvalid - { - internal bool _needDispose = false; - - internal ConnectionHandle() : base(true) - { - SetHandle(Wldap32.ldap_init(null, 389)); - - if (handle == IntPtr.Zero) - { - int error = Wldap32.LdapGetLastError(); - if (Utility.IsLdapError((LdapError)error)) - { - string errorMessage = LdapErrorMappings.MapResultCode(error); - throw new LdapException(error, errorMessage); - } - else - { - throw new LdapException(error); - } - } - } - - internal ConnectionHandle(IntPtr value, bool disposeHandle) : base(true) - { - _needDispose = disposeHandle; - if (value == IntPtr.Zero) - { - int error = Wldap32.LdapGetLastError(); - if (Utility.IsLdapError((LdapError)error)) - { - string errorMessage = LdapErrorMappings.MapResultCode(error); - throw new LdapException(error, errorMessage); - } - else - { - throw new LdapException(error); - } - } - else - { - SetHandle(value); - } - } - protected override bool ReleaseHandle() - { - if (handle != IntPtr.Zero) - { - if (_needDispose) - { - Wldap32.ldap_unbind(handle); - } - - handle = IntPtr.Zero; - } - return true; - } - } -} diff --git a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/Wldap32UnsafeMethods.cs b/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/Wldap32UnsafeMethods.cs deleted file mode 100644 index 34605a49366b2a..00000000000000 --- a/src/libraries/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/ldap/Wldap32UnsafeMethods.cs +++ /dev/null @@ -1,376 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Runtime.InteropServices; -using System.Security; - -namespace System.DirectoryServices.Protocols -{ - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal class Luid - { - private readonly int _lowPart; - private readonly int _highPart; - - public int LowPart => _lowPart; - public int HighPart => _highPart; - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal sealed class SEC_WINNT_AUTH_IDENTITY_EX - { - public int version; - public int length; - public string user; - public int userLength; - public string domain; - public int domainLength; - public string password; - public int passwordLength; - public int flags; - public string packageList; - public int packageListLength; - } - - internal enum BindMethod : uint - { - LDAP_AUTH_OTHERKIND = 0x86, - LDAP_AUTH_SICILY = LDAP_AUTH_OTHERKIND | 0x0200, - LDAP_AUTH_MSN = LDAP_AUTH_OTHERKIND | 0x0800, - LDAP_AUTH_NTLM = LDAP_AUTH_OTHERKIND | 0x1000, - LDAP_AUTH_DPA = LDAP_AUTH_OTHERKIND | 0x2000, - LDAP_AUTH_NEGOTIATE = LDAP_AUTH_OTHERKIND | 0x0400, - LDAP_AUTH_SSPI = LDAP_AUTH_NEGOTIATE, - LDAP_AUTH_DIGEST = LDAP_AUTH_OTHERKIND | 0x4000, - LDAP_AUTH_EXTERNAL = LDAP_AUTH_OTHERKIND | 0x0020 - } - - internal enum LdapOption - { - LDAP_OPT_DESC = 0x01, - LDAP_OPT_DEREF = 0x02, - LDAP_OPT_SIZELIMIT = 0x03, - LDAP_OPT_TIMELIMIT = 0x04, - LDAP_OPT_REFERRALS = 0x08, - LDAP_OPT_RESTART = 0x09, - LDAP_OPT_SSL = 0x0a, - LDAP_OPT_REFERRAL_HOP_LIMIT = 0x10, - LDAP_OPT_VERSION = 0x11, - LDAP_OPT_API_FEATURE_INFO = 0x15, - LDAP_OPT_HOST_NAME = 0x30, - LDAP_OPT_ERROR_NUMBER = 0x31, - LDAP_OPT_ERROR_STRING = 0x32, - LDAP_OPT_SERVER_ERROR = 0x33, - LDAP_OPT_SERVER_EXT_ERROR = 0x34, - LDAP_OPT_HOST_REACHABLE = 0x3E, - LDAP_OPT_PING_KEEP_ALIVE = 0x36, - LDAP_OPT_PING_WAIT_TIME = 0x37, - LDAP_OPT_PING_LIMIT = 0x38, - LDAP_OPT_DNSDOMAIN_NAME = 0x3B, - LDAP_OPT_GETDSNAME_FLAGS = 0x3D, - LDAP_OPT_PROMPT_CREDENTIALS = 0x3F, - LDAP_OPT_TCP_KEEPALIVE = 0x40, - LDAP_OPT_FAST_CONCURRENT_BIND = 0x41, - LDAP_OPT_SEND_TIMEOUT = 0x42, - LDAP_OPT_REFERRAL_CALLBACK = 0x70, - LDAP_OPT_CLIENT_CERTIFICATE = 0x80, - LDAP_OPT_SERVER_CERTIFICATE = 0x81, - LDAP_OPT_AUTO_RECONNECT = 0x91, - LDAP_OPT_SSPI_FLAGS = 0x92, - LDAP_OPT_SSL_INFO = 0x93, - LDAP_OPT_SIGN = 0x95, - LDAP_OPT_ENCRYPT = 0x96, - LDAP_OPT_SASL_METHOD = 0x97, - LDAP_OPT_AREC_EXCLUSIVE = 0x98, - LDAP_OPT_SECURITY_CONTEXT = 0x99, - LDAP_OPT_ROOTDSE_CACHE = 0x9a - } - - internal enum ResultAll - { - LDAP_MSG_ALL = 1, - LDAP_MSG_RECEIVED = 2, - LDAP_MSG_POLLINGALL = 3 - } - - [StructLayout(LayoutKind.Sequential)] - internal sealed class LDAP_TIMEVAL - { - public int tv_sec; - public int tv_usec; - } - - [StructLayout(LayoutKind.Sequential)] - internal sealed class berval - { - public int bv_len = 0; - public IntPtr bv_val = IntPtr.Zero; - - public berval() { } - } - - [StructLayout(LayoutKind.Sequential)] - internal sealed class SafeBerval - { - public int bv_len = 0; - public IntPtr bv_val = IntPtr.Zero; - - ~SafeBerval() - { - if (bv_val != IntPtr.Zero) - { - Marshal.FreeHGlobal(bv_val); - } - } - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal sealed class LdapControl - { - public IntPtr ldctl_oid = IntPtr.Zero; - public berval ldctl_value = null; - public bool ldctl_iscritical = false; - - public LdapControl() { } - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct LdapReferralCallback - { - public int sizeofcallback; - public QUERYFORCONNECTIONInternal query; - public NOTIFYOFNEWCONNECTIONInternal notify; - public DEREFERENCECONNECTIONInternal dereference; - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct CRYPTOAPI_BLOB - { - public int cbData; - public IntPtr pbData; - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct SecPkgContext_IssuerListInfoEx - { - public IntPtr aIssuers; - public int cIssuers; - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal sealed class LdapMod - { - public int type = 0; - public IntPtr attribute = IntPtr.Zero; - public IntPtr values = IntPtr.Zero; - - ~LdapMod() - { - if (attribute != IntPtr.Zero) - { - Marshal.FreeHGlobal(attribute); - } - - if (values != IntPtr.Zero) - { - Marshal.FreeHGlobal(values); - } - } - } - - internal class Wldap32 - { - private const string Wldap32dll = "wldap32.dll"; - - public const int SEC_WINNT_AUTH_IDENTITY_UNICODE = 0x2; - public const int SEC_WINNT_AUTH_IDENTITY_VERSION = 0x200; - public const string MICROSOFT_KERBEROS_NAME_W = "Kerberos"; - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_bind_sW", CharSet = CharSet.Unicode)] - public static extern int ldap_bind_s([In]ConnectionHandle ldapHandle, string dn, SEC_WINNT_AUTH_IDENTITY_EX credentials, BindMethod method); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_initW", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr ldap_init(string hostName, int portNumber); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, EntryPoint = "ldap_connect", CharSet = CharSet.Unicode)] - public static extern int ldap_connect([In] ConnectionHandle ldapHandle, LDAP_TIMEVAL timeout); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, ExactSpelling = true, EntryPoint = "ldap_unbind", CharSet = CharSet.Unicode)] - public static extern int ldap_unbind([In] IntPtr ldapHandle); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_get_optionW", CharSet = CharSet.Unicode)] - public static extern int ldap_get_option_int([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref int outValue); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_set_optionW", CharSet = CharSet.Unicode)] - public static extern int ldap_set_option_int([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref int inValue); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_get_optionW", CharSet = CharSet.Unicode)] - public static extern int ldap_get_option_ptr([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref IntPtr outValue); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_set_optionW", CharSet = CharSet.Unicode)] - public static extern int ldap_set_option_ptr([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref IntPtr inValue); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_get_optionW", CharSet = CharSet.Unicode)] - public static extern int ldap_get_option_sechandle([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref SecurityHandle outValue); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_get_optionW", CharSet = CharSet.Unicode)] - public static extern int ldap_get_option_secInfo([In] ConnectionHandle ldapHandle, [In] LdapOption option, [In, Out] SecurityPackageContextConnectionInformation outValue); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_set_optionW", CharSet = CharSet.Unicode)] - public static extern int ldap_set_option_referral([In] ConnectionHandle ldapHandle, [In] LdapOption option, ref LdapReferralCallback outValue); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_set_optionW", CharSet = CharSet.Unicode)] - public static extern int ldap_set_option_clientcert([In] ConnectionHandle ldapHandle, [In] LdapOption option, QUERYCLIENTCERT outValue); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_set_optionW", CharSet = CharSet.Unicode)] - public static extern int ldap_set_option_servercert([In] ConnectionHandle ldapHandle, [In] LdapOption option, VERIFYSERVERCERT outValue); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "LdapGetLastError")] - public static extern int LdapGetLastError(); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "cldap_openW", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr cldap_open(string hostName, int portNumber); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_simple_bind_sW", CharSet = CharSet.Unicode)] - public static extern int ldap_simple_bind_s([In] ConnectionHandle ldapHandle, string distinguishedName, string password); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_delete_extW", CharSet = CharSet.Unicode)] - public static extern int ldap_delete_ext([In] ConnectionHandle ldapHandle, string dn, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_result", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern int ldap_result([In] ConnectionHandle ldapHandle, int messageId, int all, LDAP_TIMEVAL timeout, ref IntPtr Mesage); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_parse_resultW", CharSet = CharSet.Unicode)] - public static extern int ldap_parse_result([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref int serverError, ref IntPtr dn, ref IntPtr message, ref IntPtr referral, ref IntPtr control, byte freeIt); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_parse_resultW", CharSet = CharSet.Unicode)] - public static extern int ldap_parse_result_referral([In] ConnectionHandle ldapHandle, [In] IntPtr result, IntPtr serverError, IntPtr dn, IntPtr message, ref IntPtr referral, IntPtr control, byte freeIt); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_memfreeW", CharSet = CharSet.Unicode)] - public static extern void ldap_memfree([In] IntPtr value); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_value_freeW", CharSet = CharSet.Unicode)] - public static extern int ldap_value_free([In] IntPtr value); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_controls_freeW", CharSet = CharSet.Unicode)] - public static extern int ldap_controls_free([In] IntPtr value); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_abandon", CharSet = CharSet.Unicode)] - public static extern int ldap_abandon([In] ConnectionHandle ldapHandle, [In] int messagId); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_start_tls_sW", CharSet = CharSet.Unicode)] - public static extern int ldap_start_tls(ConnectionHandle ldapHandle, ref int ServerReturnValue, ref IntPtr Message, IntPtr ServerControls, IntPtr ClientControls); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_stop_tls_s", CharSet = CharSet.Unicode)] - public static extern byte ldap_stop_tls(ConnectionHandle ldapHandle); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_rename_extW", CharSet = CharSet.Unicode)] - public static extern int ldap_rename([In] ConnectionHandle ldapHandle, string dn, string newRdn, string newParentDn, int deleteOldRdn, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_compare_extW", CharSet = CharSet.Unicode)] - public static extern int ldap_compare([In] ConnectionHandle ldapHandle, string dn, string attributeName, string strValue, berval binaryValue, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_add_extW", CharSet = CharSet.Unicode)] - public static extern int ldap_add([In] ConnectionHandle ldapHandle, string dn, IntPtr attrs, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_modify_extW", CharSet = CharSet.Unicode)] - public static extern int ldap_modify([In] ConnectionHandle ldapHandle, string dn, IntPtr attrs, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_extended_operationW", CharSet = CharSet.Unicode)] - public static extern int ldap_extended_operation([In] ConnectionHandle ldapHandle, string oid, berval data, IntPtr servercontrol, IntPtr clientcontrol, ref int messageNumber); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_parse_extended_resultW", CharSet = CharSet.Unicode)] - public static extern int ldap_parse_extended_result([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref IntPtr oid, ref IntPtr data, byte freeIt); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_msgfree", CharSet = CharSet.Unicode)] - public static extern int ldap_msgfree([In] IntPtr result); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_search_extW", CharSet = CharSet.Unicode)] - public static extern int ldap_search([In] ConnectionHandle ldapHandle, string dn, int scope, string filter, IntPtr attributes, bool attributeOnly, IntPtr servercontrol, IntPtr clientcontrol, int timelimit, int sizelimit, ref int messageNumber); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_first_entry", CharSet = CharSet.Unicode)] - public static extern IntPtr ldap_first_entry([In] ConnectionHandle ldapHandle, [In] IntPtr result); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_next_entry", CharSet = CharSet.Unicode)] - public static extern IntPtr ldap_next_entry([In] ConnectionHandle ldapHandle, [In] IntPtr result); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_first_reference", CharSet = CharSet.Unicode)] - public static extern IntPtr ldap_first_reference([In] ConnectionHandle ldapHandle, [In] IntPtr result); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_next_reference", CharSet = CharSet.Unicode)] - public static extern IntPtr ldap_next_reference([In] ConnectionHandle ldapHandle, [In] IntPtr result); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_get_dnW", CharSet = CharSet.Unicode)] - public static extern IntPtr ldap_get_dn([In] ConnectionHandle ldapHandle, [In] IntPtr result); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_first_attributeW", CharSet = CharSet.Unicode)] - public static extern IntPtr ldap_first_attribute([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref IntPtr address); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_next_attributeW", CharSet = CharSet.Unicode)] - public static extern IntPtr ldap_next_attribute([In] ConnectionHandle ldapHandle, [In] IntPtr result, [In, Out] IntPtr address); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_free", CharSet = CharSet.Unicode)] - public static extern IntPtr ber_free([In] IntPtr berelement, int option); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_get_values_lenW", CharSet = CharSet.Unicode)] - public static extern IntPtr ldap_get_values_len([In] ConnectionHandle ldapHandle, [In] IntPtr result, string name); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_value_free_len", CharSet = CharSet.Unicode)] - public static extern IntPtr ldap_value_free_len([In] IntPtr berelement); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_parse_referenceW", CharSet = CharSet.Unicode)] - public static extern int ldap_parse_reference([In] ConnectionHandle ldapHandle, [In] IntPtr result, ref IntPtr referrals); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_alloc_t", CharSet = CharSet.Unicode)] - public static extern IntPtr ber_alloc(int option); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_printf", CharSet = CharSet.Unicode)] - public static extern int ber_printf_emptyarg(BerSafeHandle berElement, string format); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_printf", CharSet = CharSet.Unicode)] - public static extern int ber_printf_int(BerSafeHandle berElement, string format, int value); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_printf", CharSet = CharSet.Unicode)] - public static extern int ber_printf_bytearray(BerSafeHandle berElement, string format, HGlobalMemHandle value, int length); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_printf", CharSet = CharSet.Unicode)] - public static extern int ber_printf_berarray(BerSafeHandle berElement, string format, IntPtr value); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_flatten", CharSet = CharSet.Unicode)] - public static extern int ber_flatten(BerSafeHandle berElement, ref IntPtr value); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_init", CharSet = CharSet.Unicode)] - public static extern IntPtr ber_init(berval value); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)] - public static extern int ber_scanf(BerSafeHandle berElement, string format); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)] - public static extern int ber_scanf_int(BerSafeHandle berElement, string format, ref int value); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)] - public static extern int ber_scanf_ptr(BerSafeHandle berElement, string format, ref IntPtr value); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_scanf", CharSet = CharSet.Unicode)] - public static extern int ber_scanf_bitstring(BerSafeHandle berElement, string format, ref IntPtr value, ref int length); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_bvfree", CharSet = CharSet.Unicode)] - public static extern int ber_bvfree(IntPtr value); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ber_bvecfree", CharSet = CharSet.Unicode)] - public static extern int ber_bvecfree(IntPtr value); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_create_sort_controlW", CharSet = CharSet.Unicode)] - public static extern int ldap_create_sort_control(ConnectionHandle handle, IntPtr keys, byte critical, ref IntPtr control); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_control_freeW", CharSet = CharSet.Unicode)] - public static extern int ldap_control_free(IntPtr control); - - [DllImport("Crypt32.dll", EntryPoint = "CertFreeCRLContext", CharSet = CharSet.Unicode)] - public static extern int CertFreeCRLContext(IntPtr certContext); - - [DllImport(Wldap32dll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ldap_result2error", CharSet = CharSet.Unicode)] - public static extern int ldap_result2error([In] ConnectionHandle ldapHandle, [In] IntPtr result, int freeIt); - } -} diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/AsqRequestControlTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/AsqRequestControlTests.cs index 4c4f335a7933fc..97c70bf4c081c7 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/AsqRequestControlTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/AsqRequestControlTests.cs @@ -2,10 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; +using System.Runtime.InteropServices; using Xunit; namespace System.DirectoryServices.Protocols.Tests { + [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class AsqRequestControlTests { [Fact] @@ -17,13 +20,29 @@ public void Ctor_Default() Assert.True(control.ServerSide); Assert.Equal("1.2.840.113556.1.4.1504", control.Type); - Assert.Equal(new byte[] { 48, 132, 0, 0, 0, 2, 4, 0 }, control.GetValue()); + var expected = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 2, 4, 0 } : new byte[] { 48, 2, 4, 0 }; + + Assert.Equal(expected, control.GetValue()); + } + + public static IEnumerable Ctor_String_Test_data() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + yield return new object[] { null, new byte[] { 48, 132, 0, 0, 0, 2, 4, 0 } }; + yield return new object[] { "", new byte[] { 48, 132, 0, 0, 0, 2, 4, 0 } }; + yield return new object[] { "A", new byte[] { 48, 132, 0, 0, 0, 3, 4, 1, 65 } }; + } + else + { + yield return new object[] { null, new byte[] { 48, 2, 4, 0 } }; + yield return new object[] { "", new byte[] { 48, 2, 4, 0 } }; + yield return new object[] { "A", new byte[] { 48, 3, 4, 1, 65 } }; + } } [Theory] - [InlineData(null, new byte[] { 48, 132, 0, 0, 0, 2, 4, 0 })] - [InlineData("", new byte[] { 48, 132, 0, 0, 0, 2, 4, 0 })] - [InlineData("A", new byte[] { 48, 132, 0, 0, 0, 3, 4, 1, 65 })] + [MemberData(nameof(Ctor_String_Test_data))] public void Ctor_String(string attributeName, byte[] expectedValue) { var control = new AsqRequestControl(attributeName); diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/BerConverterTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/BerConverterTests.cs index 54f85a9e9783aa..890ce024efbb6b 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/BerConverterTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/BerConverterTests.cs @@ -2,11 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.DotNet.XUnitExtensions; using System.Collections.Generic; +using System.Runtime.InteropServices; using Xunit; namespace System.DirectoryServices.Protocols.Tests { + [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class BerConverterTests { public static IEnumerable Encode_TestData() @@ -15,22 +18,28 @@ public static IEnumerable Encode_TestData() yield return new object[] { "", new object[10], new byte[0] }; yield return new object[] { "b", new object[] { true, false, true, false }, new byte[] { 1, 1, 255 } }; - yield return new object[] { "{", new object[] { "a" }, new byte[] { 48, 0, 0, 0, 0, 0 } }; - yield return new object[] { "{}", new object[] { "a" }, new byte[] { 48, 132, 0, 0, 0, 0 } }; - yield return new object[] { "[", new object[] { "a" }, new byte[] { 49, 0, 0, 0, 0, 0 } }; - yield return new object[] { "[]", new object[] { "a" }, new byte[] { 49, 132, 0, 0, 0, 0 } }; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + yield return new object[] { "{", new object[] { "a" }, new byte[] { 48, 0, 0, 0, 0, 0 } }; // This format is not supported by Linux OpenLDAP + } + yield return new object[] { "{}", new object[] { "a" }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 0 } : new byte[] { 48, 0 } }; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + yield return new object[] { "[", new object[] { "a" }, new byte[] { 49, 0, 0, 0, 0, 0 } }; // This format is not supported by Linux OpenLDAP + } + yield return new object[] { "[]", new object[] { "a" }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 49, 132, 0, 0, 0, 0 } : new byte[] { 49, 0 } }; yield return new object[] { "n", new object[] { "a" }, new byte[] { 5, 0 } }; - yield return new object[] { "tetie", new object[] { -1, 0, 1, 2, 3 }, new byte[] { 255, 1, 0, 1, 1, 2, 10, 1, 3 } }; - yield return new object[] { "{tetie}", new object[] { -1, 0, 1, 2, 3 }, new byte[] { 48, 132, 0, 0, 0, 9, 255, 1, 0, 1, 1, 2, 10, 1, 3 } }; + yield return new object[] { "tetie", new object[] { 128, 0, 133, 2, 3 }, new byte[] { 128, 1, 0, 133, 1, 2, 10, 1, 3 } }; + yield return new object[] { "{tetie}", new object[] { 128, 0, 133, 2, 3 }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 9, 128, 1, 0, 133, 1, 2, 10, 1, 3 } : new byte[] { 48, 9, 128, 1, 0, 133, 1, 2, 10, 1, 3 } }; yield return new object[] { "bb", new object[] { true, false }, new byte[] { 1, 1, 255, 1, 1, 0 } }; - yield return new object[] { "{bb}", new object[] { true, false }, new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 } }; + yield return new object[] { "{bb}", new object[] { true, false }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 } : new byte[] { 48, 6, 1, 1, 255, 1, 1, 0 } }; yield return new object[] { "ssss", new object[] { null, "", "abc", "\0" }, new byte[] { 4, 0, 4, 0, 4, 3, 97, 98, 99, 4, 1, 0 } }; - yield return new object[] { "oXo", new object[] { null, new byte[] { 0, 1, 2, 255 }, new byte[0] }, new byte[] { 4, 0, 3, 4, 0, 1, 2, 255, 4, 0 } }; + yield return new object[] { "oXo", new object[] { null, new byte[] { 0, 1, 2, 255 }, new byte[0] }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 4, 0, 3, 4, 0, 1, 2, 255, 4, 0 } : new byte[] { 4, 0, 3, 2, 4, 0, 4, 0 } }; yield return new object[] { "vv", new object[] { null, new string[] { "abc", "", null } }, new byte[] { 4, 3, 97, 98, 99, 4, 0, 4, 0 } }; - yield return new object[] { "{vv}", new object[] { null, new string[] { "abc", "", null } }, new byte[] { 48, 132, 0, 0, 0, 9, 4, 3, 97, 98, 99, 4, 0, 4, 0 } }; + yield return new object[] { "{vv}", new object[] { null, new string[] { "abc", "", null } }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 9, 4, 3, 97, 98, 99, 4, 0, 4, 0 } : new byte[] { 48, 9, 4, 3, 97, 98, 99, 4, 0, 4, 0 } }; yield return new object[] { "VVVV", new object[] { null, new byte[][] { new byte[] { 0, 1, 2, 3 }, null }, new byte[][] { new byte[0] }, new byte[0][] }, new byte[] { 4, 4, 0, 1, 2, 3, 4, 0, 4, 0 } }; } @@ -112,10 +121,13 @@ public static IEnumerable Decode_TestData() yield return new object[] { "{bb}", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 }, new object[] { true, false } }; yield return new object[] { "{OO}", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 }, new object[] { new byte[] { 255 }, new byte[] { 0 } } }; yield return new object[] { "{BB}", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 }, new object[] { new byte[] { 255 }, new byte[] { 0 } } }; - yield return new object[] { "{vv}", new byte[] { 48, 132, 0, 0, 0, 9, 4, 3, 97, 98, 99, 4, 0, 4, 0 }, new object[] { null, null } }; - yield return new object[] { "{vv}", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 }, new object[] { new string[] { "\x01" }, null } }; - yield return new object[] { "{VV}", new byte[] { 48, 132, 0, 0, 0, 9, 4, 3, 97, 98, 99, 4, 0, 4, 0 }, new object[] { null, null } }; - yield return new object[] { "{VV}", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 }, new object[] { new byte[][] { new byte[] { 1 } }, null } }; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // vv and VV formats are not supported yet in Linux + { + yield return new object[] { "{vv}", new byte[] { 48, 132, 0, 0, 0, 9, 4, 3, 97, 98, 99, 4, 0, 4, 0 }, new object[] { null, null } }; + yield return new object[] { "{vv}", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 }, new object[] { new string[] { "\x01" }, null } }; + yield return new object[] { "{VV}", new byte[] { 48, 132, 0, 0, 0, 9, 4, 3, 97, 98, 99, 4, 0, 4, 0 }, new object[] { null, null } }; + yield return new object[] { "{VV}", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 }, new object[] { new byte[][] { new byte[] { 1 } }, null } }; + } } [Theory] @@ -139,18 +151,29 @@ public void UnknownFormat_ThrowsArgumentException(string format, byte[] values) AssertExtensions.Throws(null, () => BerConverter.Decode(format, values)); } + public static IEnumerable Decode_Invalid_ThrowsBerConversionException_Data() + { + yield return new object[] { "n", null }; + yield return new object[] { "n", new byte[0] }; + yield return new object[] { "{", new byte[] { 1 } }; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + yield return new object[] { "}", new byte[] { 1 } }; // This is considered a valid case in Linux + } + yield return new object[] { "{}{}{}{}{}{}{}", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 } }; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + yield return new object[] { "aaa", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 } }; + } + yield return new object[] { "iii", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 } }; + yield return new object[] { "eee", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 } }; + yield return new object[] { "bbb", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 } }; + yield return new object[] { "OOO", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 } }; + yield return new object[] { "BBB", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 } }; + } + [Theory] - [InlineData("n", null)] - [InlineData("n", new byte[0])] - [InlineData("{", new byte[] { 1 })] - [InlineData("}", new byte[] { 1 })] - [InlineData("{}{}{}{}{}{}{}", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 })] - [InlineData("aaa", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 })] - [InlineData("iii", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 })] - [InlineData("eee", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 })] - [InlineData("bbb", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 })] - [InlineData("OOO", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 })] - [InlineData("BBB", new byte[] { 48, 132, 0, 0, 0, 6, 1, 1, 255, 1, 1, 0 })] + [MemberData(nameof(Decode_Invalid_ThrowsBerConversionException_Data))] public void Decode_Invalid_ThrowsBerConversionException(string format, byte[] values) { Assert.Throws(() => BerConverter.Decode(format, values)); diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/DirSyncRequestControlTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/DirSyncRequestControlTests.cs index 09f212987f652e..8a494282e67f16 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/DirSyncRequestControlTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/DirSyncRequestControlTests.cs @@ -2,10 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; +using System.Runtime.InteropServices; using Xunit; namespace System.DirectoryServices.Protocols.Tests { + [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class DirSyncRequestControlTests { [Fact] @@ -20,13 +23,19 @@ public void Ctor_Default() Assert.True(control.ServerSide); Assert.Equal("1.2.840.113556.1.4.841", control.Type); - Assert.Equal(new byte[] { 48, 132, 0, 0, 0, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 }, control.GetValue()); + var expected = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 } : new byte[] { 48, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 }; + Assert.Equal(expected, control.GetValue()); + } + + public static IEnumerable Ctor_Cookie_Data() + { + yield return new object[] { null, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 } : new byte[] { 48, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 } }; + yield return new object[] { new byte[0], (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 } : new byte[] { 48, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 } }; + yield return new object[] { new byte[] { 97, 98, 99 }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 13, 2, 1, 0, 2, 3, 16, 0, 0, 4, 3, 97, 98, 99 } : new byte[] { 48, 13, 2, 1, 0, 2, 3, 16, 0, 0, 4, 3, 97, 98, 99 } }; } [Theory] - [InlineData(null, new byte[] { 48, 132, 0, 0, 0, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 })] - [InlineData(new byte[0], new byte[] { 48, 132, 0, 0, 0, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 })] - [InlineData(new byte[] { 97, 98, 99 }, new byte[] { 48, 132, 0, 0, 0, 13, 2, 1, 0, 2, 3, 16, 0, 0, 4, 3, 97, 98, 99 })] + [MemberData(nameof(Ctor_Cookie_Data))] public void Ctor_Cookie(byte[] cookie, byte[] expectedValue) { var control = new DirSyncRequestControl(cookie); @@ -41,10 +50,15 @@ public void Ctor_Cookie(byte[] cookie, byte[] expectedValue) Assert.Equal(expectedValue, control.GetValue()); } + public static IEnumerable Ctor_Cookie_Options_Data() + { + yield return new object[] { null, DirectorySynchronizationOptions.None, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 } : new byte[] { 48, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 } }; + yield return new object[] { new byte[0], DirectorySynchronizationOptions.None - 1, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 13, 2, 4, 255, 255, 255, 255, 2, 3, 16, 0, 0, 4, 0 } : new byte[] { 48, 10, 2, 1, 255, 2, 3, 16, 0, 0, 4, 0 } }; + yield return new object[] { new byte[] { 97, 98, 99 }, DirectorySynchronizationOptions.ObjectSecurity, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 13, 2, 1, 1, 2, 3, 16, 0, 0, 4, 3, 97, 98, 99 } : new byte[] { 48, 13, 2, 1, 1, 2, 3, 16, 0, 0, 4, 3, 97, 98, 99 } }; + } + [Theory] - [InlineData(null, DirectorySynchronizationOptions.None, new byte[] { 48, 132, 0, 0, 0, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 })] - [InlineData(new byte[0], DirectorySynchronizationOptions.None - 1, new byte[] { 48, 132, 0, 0, 0, 13, 2, 4, 255, 255, 255, 255, 2, 3, 16, 0, 0, 4, 0 })] - [InlineData(new byte[] { 97, 98, 99 }, DirectorySynchronizationOptions.ObjectSecurity, new byte[] { 48, 132, 0, 0, 0, 13, 2, 1, 1, 2, 3, 16, 0, 0, 4, 3, 97, 98, 99 })] + [MemberData(nameof(Ctor_Cookie_Options_Data))] public void Ctor_Cookie_Options(byte[] cookie, DirectorySynchronizationOptions option, byte[] expectedValue) { var control = new DirSyncRequestControl(cookie, option); @@ -59,10 +73,15 @@ public void Ctor_Cookie_Options(byte[] cookie, DirectorySynchronizationOptions o Assert.Equal(expectedValue, control.GetValue()); } + public static IEnumerable Ctor_Cookie_Options_AttributeCount_Data() + { + yield return new object[] { null, DirectorySynchronizationOptions.None, 1048576, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 } : new byte[] { 48, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 } }; + yield return new object[] { new byte[0], DirectorySynchronizationOptions.None - 1, 0, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 11, 2, 4, 255, 255, 255, 255, 2, 1, 0, 4, 0 } : new byte[] { 48, 8, 2, 1, 255, 2, 1, 0, 4, 0 } }; + yield return new object[] { new byte[] { 97, 98, 99 }, DirectorySynchronizationOptions.ObjectSecurity, 10, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 11, 2, 1, 1, 2, 1, 10, 4, 3, 97, 98, 99 } : new byte[] { 48, 11, 2, 1, 1, 2, 1, 10, 4, 3, 97, 98, 99 } }; + } + [Theory] - [InlineData(null, DirectorySynchronizationOptions.None, 1048576, new byte[] { 48, 132, 0, 0, 0, 10, 2, 1, 0, 2, 3, 16, 0, 0, 4, 0 })] - [InlineData(new byte[0], DirectorySynchronizationOptions.None - 1, 0, new byte[] { 48, 132, 0, 0, 0, 11, 2, 4, 255, 255, 255, 255, 2, 1, 0, 4, 0 })] - [InlineData(new byte[] { 97, 98, 99 }, DirectorySynchronizationOptions.ObjectSecurity, 10, new byte[] { 48, 132, 0, 0, 0, 11, 2, 1, 1, 2, 1, 10, 4, 3, 97, 98, 99 })] + [MemberData(nameof(Ctor_Cookie_Options_AttributeCount_Data))] public void Ctor_Cookie_Options_AttributeCount(byte[] cookie, DirectorySynchronizationOptions option, int attributeCount , byte[] expectedValue) { var control = new DirSyncRequestControl(cookie, option, attributeCount); diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs index f520df26b2b4dc..af065dfd6a393d 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesProtocolsTests.cs @@ -2,17 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Runtime.InteropServices; -using System.Collections.Generic; -using System.Collections; +using System.DirectoryServices.Tests; using System.Globalization; using System.Net; using Xunit; -using System.Threading; -using System.DirectoryServices.Tests; -using System.DirectoryServices.Protocols; -namespace System.DirectoryServicesProtocols.Tests +namespace System.DirectoryServices.Protocols.Tests { public partial class DirectoryServicesProtocolsTests { diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesTestHelpers.cs b/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesTestHelpers.cs new file mode 100644 index 00000000000000..98d45457c7ae70 --- /dev/null +++ b/src/libraries/System.DirectoryServices.Protocols/tests/DirectoryServicesTestHelpers.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; +using Xunit; + +[assembly: ActiveIssue("https://github.com/dotnet/runtime/issues/35912", TestRuntimes.Mono)] + +namespace System.DirectoryServices.Protocols.Tests +{ + public static class DirectoryServicesTestHelpers + { + public static bool IsWindowsOrLibLdapIsInstalled => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || IsLibLdapInstalled; + + // Cache the check once we have performed it once + private static bool? _isLibLdapInstalled = null; + + /// + /// Returns true if able to PInvoke into Linux or OSX, false otherwise + /// + public static bool IsLibLdapInstalled + { + get + { +#if NETCOREAPP + if (!_isLibLdapInstalled.HasValue) + { + if (PlatformDetection.IsOSX) + { + _isLibLdapInstalled = NativeLibrary.TryLoad("libldap.dylib", out _); + } + else + { + _isLibLdapInstalled = NativeLibrary.TryLoad("libldap-2.4.so.2", out _); + } + } + return _isLibLdapInstalled.Value; +#else + _isLibLdapInstalled = true; // In .NET Framework ldap is always installed. + return _isLibLdapInstalled.Value; +#endif + } + } + } +} diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/ExtendedDNControlTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/ExtendedDNControlTests.cs index 7a759afeb07ba6..ade556afd0d9f9 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/ExtendedDNControlTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/ExtendedDNControlTests.cs @@ -3,10 +3,12 @@ // See the LICENSE file in the project root for more information. using System.ComponentModel; +using System.Runtime.InteropServices; using Xunit; namespace System.DirectoryServices.Protocols.Tests { + [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class ExtendedDNControlTests { [Fact] @@ -18,7 +20,8 @@ public void Ctor_Default() Assert.True(control.ServerSide); Assert.Equal("1.2.840.113556.1.4.529", control.Type); - Assert.Equal(new byte[] { 48, 132, 0, 0, 0, 3, 2, 1, 0 }, control.GetValue()); + var expected = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 3, 2, 1, 0 } : new byte[] { 48, 3, 2, 1, 0 }; + Assert.Equal(expected, control.GetValue()); } [Fact] @@ -30,7 +33,8 @@ public void Ctor_Flag() Assert.True(control.ServerSide); Assert.Equal("1.2.840.113556.1.4.529", control.Type); - Assert.Equal(new byte[] { 48, 132, 0, 0, 0, 3, 2, 1, 1 }, control.GetValue()); + var expected = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 3, 2, 1, 1 } : new byte[] { 48, 3, 2, 1, 1 }; + Assert.Equal(expected, control.GetValue()); } [Theory] diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/LdapConnectionTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/LdapConnectionTests.cs index ee262ec1a03c17..c8b8fb0a5be95d 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/LdapConnectionTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/LdapConnectionTests.cs @@ -5,13 +5,12 @@ using System.Collections.Generic; using System.ComponentModel; using System.Net; -using System.Net.Sockets; using System.Threading; -using System.Threading.Tasks; using Xunit; namespace System.DirectoryServices.Protocols.Tests { + [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class LdapConnectionTests { [Theory] diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/LdapSessionOptionsTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/LdapSessionOptionsTests.cs index f8ea1cceea2e43..30abf231c19420 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/LdapSessionOptionsTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/LdapSessionOptionsTests.cs @@ -8,9 +8,11 @@ namespace System.DirectoryServices.Protocols.Tests { + [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class LdapSessionOptionsTests { [Theory] + [PlatformSpecific(TestPlatforms.Windows)] [InlineData(ReferralChasingOptions.None)] [InlineData(ReferralChasingOptions.External)] public void ReferralChasing_Set_GetReturnsExpected(ReferralChasingOptions value) @@ -47,6 +49,7 @@ public void ReferralChasing_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Theory] + [PlatformSpecific(TestPlatforms.Windows)] [InlineData(true)] [InlineData(false)] public void SecureSocketLayer_Set_GetReturnsExpected(bool value) @@ -62,6 +65,7 @@ public void SecureSocketLayer_Set_GetReturnsExpected(bool value) } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void SecureSocketLayer_GetSetWhenDisposed_ThrowsObjectDisposedException() { var connection = new LdapConnection("server"); @@ -72,6 +76,7 @@ public void SecureSocketLayer_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void ReferralHopLimit_Set_GetReturnsExpected() { using (var connection = new LdapConnection("server")) @@ -142,6 +147,7 @@ public void ProtocolVersion_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void HostName_Set_GetReturnsExpected() { using (var connection = new LdapConnection("server")) @@ -168,6 +174,7 @@ public void HostName_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void DomainName_Set_GetReturnsExpected() { using (var connection = new LdapConnection("server")) @@ -194,6 +201,7 @@ public void DomainName_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Theory] + [PlatformSpecific(TestPlatforms.Windows)] [InlineData(LocatorFlags.AvoidSelf)] [InlineData(LocatorFlags.None - 1)] public void LocatorFlag_Set_GetReturnsExpected(LocatorFlags value) @@ -219,6 +227,7 @@ public void LocatorFlag_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void HostReachable_Get_ReturnsTrue() { using (var connection = new LdapConnection("server")) @@ -238,6 +247,7 @@ public void HostReachable_GetWhenDisposed_ThrowsObjectDisposedException() } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void PingKeepAliveTimeout_Set_GetReturnsExpected() { using (var connection = new LdapConnection("server")) @@ -272,6 +282,7 @@ public void PingKeepAliveTimeout_GetSetWhenDisposed_ThrowsObjectDisposedExceptio } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void PingLimit_Set_GetReturnsExpected() { using (var connection = new LdapConnection("server")) @@ -304,6 +315,7 @@ public void PingLimit_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void PingWaitTimeout_Set_GetReturnsExpected() { using (var connection = new LdapConnection("server")) @@ -338,6 +350,7 @@ public void PingWaitTimeout_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Theory] + [PlatformSpecific(TestPlatforms.Windows)] [InlineData(true)] [InlineData(false)] public void AutoReconnect_Set_GetReturnsExpected(bool value) @@ -363,6 +376,7 @@ public void AutoReconnect_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Theory] + [PlatformSpecific(TestPlatforms.Windows)] [InlineData(-1)] [InlineData(10)] public void SspiFlag_Set_GetReturnsExpected(int value) @@ -388,6 +402,7 @@ public void SspiFlag_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void SslInformation_GetNotStarted_ThrowsDirectoryOperationException() { using (var connection = new LdapConnection("server")) @@ -407,6 +422,7 @@ public void SslInformation_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void SecurityContext_GetNotStarted_ThrowsDirectoryOperationException() { using (var connection = new LdapConnection("server")) @@ -426,6 +442,7 @@ public void SecurityContext_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Theory] + [PlatformSpecific(TestPlatforms.Windows)] [InlineData(true)] [InlineData(false)] public void Signing_Set_GetReturnsExpected(bool value) @@ -451,6 +468,7 @@ public void Signing_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Theory] + [PlatformSpecific(TestPlatforms.Windows)] [InlineData(true)] [InlineData(false)] public void Sealing_Set_GetReturnsExpected(bool value) @@ -476,6 +494,7 @@ public void Sealing_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void SaslMethod_Set_ThrowsLdapException() { using (var connection = new LdapConnection("server")) @@ -498,6 +517,7 @@ public void SaslMethod_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Theory] + [PlatformSpecific(TestPlatforms.Windows)] [InlineData(true)] [InlineData(false)] public void RootDseCache_Set_GetReturnsExpected(bool value) @@ -523,6 +543,7 @@ public void RootDseCache_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Theory] + [PlatformSpecific(TestPlatforms.Windows)] [InlineData(true)] [InlineData(false)] public void TcpKeepAlive_Set_GetReturnsExpected(bool value) @@ -548,6 +569,7 @@ public void TcpKeepAlive_GetSetWhenDisposed_ThrowsObjectDisposedException() } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void SendTimeout_Set_GetReturnsExpected() { using (var connection = new LdapConnection("server")) @@ -595,6 +617,7 @@ public void ReferralCallback_Get_ReturnsException() } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void ReferralCallback_Set_GetReturnsExpected() { using (var connection = new LdapConnection("server")) @@ -625,6 +648,7 @@ public void ReferralCallback_GetGetSetWhenDisposed_ThrowsObjectDisposedException } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void QueryClientCertificate_Set_GetReturnsExpected() { using (var connection = new LdapConnection("server")) @@ -653,6 +677,7 @@ public void QueryClientCertificate_GetGetSetWhenDisposed_ThrowsObjectDisposedExc } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void VerifyServerCertificate_Set_GetReturnsExpected() { using (var connection = new LdapConnection("server")) @@ -699,6 +724,7 @@ public void StartTransportLayerSecurity_Disposed_ThrowsObjectDisposedException() } [Fact] + [PlatformSpecific(TestPlatforms.Windows)] public void StopTransportLayerSecurity_NotStarted_ThrowsTlsOperationException() { using (var connection = new LdapConnection("server")) diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/PageResultRequestControlTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/PageResultRequestControlTests.cs index 6ce552719fb781..e629b5327b636c 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/PageResultRequestControlTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/PageResultRequestControlTests.cs @@ -3,12 +3,12 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.ComponentModel; -using System.Security.Principal; +using System.Runtime.InteropServices; using Xunit; namespace System.DirectoryServices.Protocols.Tests { + [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class PageResultRequestControlTests { [Fact] @@ -21,12 +21,18 @@ public void Ctor_Default() Assert.Equal(512, control.PageSize); Assert.Equal("1.2.840.113556.1.4.319", control.Type); - Assert.Equal(new byte[] { 48, 132, 0, 0, 0, 6, 2, 2, 2, 0, 4, 0 }, control.GetValue()); + var expected = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 6, 2, 2, 2, 0, 4, 0 } : new byte[] { 48, 6, 2, 2, 2, 0, 4, 0 }; + Assert.Equal(expected, control.GetValue()); + } + + public static IEnumerable Ctor_PageSize_Data() + { + yield return new object[] { 0, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 5, 2, 1, 0, 4, 0 } : new byte[] { 48, 5, 2, 1, 0, 4, 0 } }; + yield return new object[] { 10, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 5, 2, 1, 10, 4, 0 } : new byte[] { 48, 5, 2, 1, 10, 4, 0 } }; } [Theory] - [InlineData(0, new byte[] { 48, 132, 0, 0, 0, 5, 2, 1, 0, 4, 0 })] - [InlineData(10, new byte[] { 48, 132, 0, 0, 0, 5, 2, 1, 10, 4, 0 })] + [MemberData(nameof(Ctor_PageSize_Data))] public void Ctor_PageSize(int pageSize, byte[] expectedValue) { var control = new PageResultRequestControl(pageSize); @@ -45,10 +51,15 @@ public void Ctor_NegativePageSize_ThrowsArgumentException() AssertExtensions.Throws("value", () => new PageResultRequestControl(-1)); } + public static IEnumerable Ctor_Cookie_Data() + { + yield return new object[] { null, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 6, 2, 2, 2, 0, 4, 0 } : new byte[] { 48, 6, 2, 2, 2, 0, 4, 0 } }; + yield return new object[] { new byte[0], (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 6, 2, 2, 2, 0, 4, 0 } : new byte[] { 48, 6, 2, 2, 2, 0, 4, 0 } }; + yield return new object[] { new byte[] { 1, 2, 3, }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 9, 2, 2, 2, 0, 4, 3, 1, 2, 3 } : new byte[] { 48, 9, 2, 2, 2, 0, 4, 3, 1, 2, 3 } }; + } + [Theory] - [InlineData(null, new byte[] { 48, 132, 0, 0, 0, 6, 2, 2, 2, 0, 4, 0 })] - [InlineData(new byte[0], new byte[] { 48, 132, 0, 0, 0, 6, 2, 2, 2, 0, 4, 0 })] - [InlineData(new byte[] { 1, 2, 3, }, new byte[] { 48, 132, 0, 0, 0, 9, 2, 2, 2, 0, 4, 3, 1, 2, 3 })] + [MemberData(nameof(Ctor_Cookie_Data))] public void Ctor_Cookie(byte[] cookie, byte[] expectedValue) { var control = new PageResultRequestControl(cookie); diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/QuotaControlTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/QuotaControlTests.cs index 590da560d8383f..300bf8c4874f1a 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/QuotaControlTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/QuotaControlTests.cs @@ -3,12 +3,13 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.ComponentModel; +using System.Runtime.InteropServices; using System.Security.Principal; using Xunit; namespace System.DirectoryServices.Protocols.Tests { + [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class QuotaControlTests { [Fact] @@ -20,7 +21,8 @@ public void Ctor_Default() Assert.True(control.ServerSide); Assert.Equal("1.2.840.113556.1.4.1852", control.Type); - Assert.Equal(new byte[] { 48, 132, 0, 0, 0, 2, 4, 0 }, control.GetValue()); + var expected = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 2, 4, 0 } : new byte[] { 48, 2, 4, 0 }; + Assert.Equal(expected, control.GetValue()); } public static IEnumerable Ctor_QuerySid_TestData() @@ -30,6 +32,7 @@ public static IEnumerable Ctor_QuerySid_TestData() } [Theory] + [PlatformSpecific(TestPlatforms.Windows)] //Security Identifiers only work on Windows [MemberData(nameof(Ctor_QuerySid_TestData))] public void Ctor_QuerySid_Test(SecurityIdentifier querySid, byte[] expectedValue) { diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/SearchOptionsControlTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/SearchOptionsControlTests.cs index fbf5fc0dc87dc3..7fd2878537bb80 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/SearchOptionsControlTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/SearchOptionsControlTests.cs @@ -3,10 +3,12 @@ // See the LICENSE file in the project root for more information. using System.ComponentModel; +using System.Runtime.InteropServices; using Xunit; namespace System.DirectoryServices.Protocols.Tests { + [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class SearchOptionsControlTests { [Fact] @@ -18,7 +20,8 @@ public void Ctor_Default() Assert.True(control.ServerSide); Assert.Equal("1.2.840.113556.1.4.1340", control.Type); - Assert.Equal(new byte[] { 48, 132, 0, 0, 0, 3, 2, 1, 1 }, control.GetValue()); + var expected = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 3, 2, 1, 1 } : new byte[] { 48, 3, 2, 1, 1 }; + Assert.Equal(expected, control.GetValue()); } [Fact] @@ -30,7 +33,8 @@ public void Ctor_Flags() Assert.True(control.ServerSide); Assert.Equal("1.2.840.113556.1.4.1340", control.Type); - Assert.Equal(new byte[] { 48, 132, 0, 0, 0, 3, 2, 1, 2 }, control.GetValue()); + var expected = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 3, 2, 1, 2 } : new byte[] { 48, 3, 2, 1, 2 }; + Assert.Equal(expected, control.GetValue()); } [Theory] diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/SecurityDescriptorFlagControlTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/SecurityDescriptorFlagControlTests.cs index 3d0fc4e6d5024c..8c7fabf0ed8bb3 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/SecurityDescriptorFlagControlTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/SecurityDescriptorFlagControlTests.cs @@ -2,11 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.ComponentModel; +using System.Collections.Generic; +using System.Runtime.InteropServices; using Xunit; namespace System.DirectoryServices.Protocols.Tests { + [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class SecurityDescriptorFlagControlTests { [Fact] @@ -18,12 +20,18 @@ public void Ctor_Default() Assert.True(control.ServerSide); Assert.Equal("1.2.840.113556.1.4.801", control.Type); - Assert.Equal(new byte[] { 48, 132, 0, 0, 0, 3, 2, 1, 0 }, control.GetValue()); + var expected = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 3, 2, 1, 0 } : new byte[] { 48, 3, 2, 1, 0 }; + Assert.Equal(expected, control.GetValue()); + } + + public static IEnumerable Ctor_Flags_Data() + { + yield return new object[] { SecurityMasks.Group, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 3, 2, 1, 2 } : new byte[] { 48, 3, 2, 1, 2 } }; + yield return new object[] { SecurityMasks.None - 1, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 6, 2, 4, 255, 255, 255, 255 } : new byte[] { 48, 3, 2, 1, 255 } }; } [Theory] - [InlineData(SecurityMasks.Group, new byte[] { 48, 132, 0, 0, 0, 3, 2, 1, 2 })] - [InlineData(SecurityMasks.None - 1, new byte[] { 48, 132, 0, 0, 0, 6, 2, 4, 255, 255, 255, 255 })] + [MemberData(nameof(Ctor_Flags_Data))] public void Ctor_Flags(SecurityMasks masks, byte[] expectedValue) { var control = new SecurityDescriptorFlagControl(masks); @@ -31,7 +39,6 @@ public void Ctor_Flags(SecurityMasks masks, byte[] expectedValue) Assert.Equal(masks, control.SecurityMasks); Assert.True(control.ServerSide); Assert.Equal("1.2.840.113556.1.4.801", control.Type); - Assert.Equal(expectedValue, control.GetValue()); } } diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/SortRequestControlTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/SortRequestControlTests.cs index 24c57e840cf527..197a8f91c9b9cf 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/SortRequestControlTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/SortRequestControlTests.cs @@ -3,10 +3,12 @@ // See the LICENSE file in the project root for more information. using System.Reflection; +using System.Runtime.InteropServices; using Xunit; namespace System.DirectoryServices.Protocols.Tests { + [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class SortRequestControlTests { [Theory] @@ -30,13 +32,13 @@ public void Ctor_SortKeys(bool critical) } control.IsCritical = critical; - Assert.Equal(new byte[] - { - 48, 132, 0, 0, 0, 43, 48, 132, 0, 0, 0, 17, 4, 5,110, + var expected = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? + new byte[] { 48, 132, 0, 0, 0, 43, 48, 132, 0, 0, 0, 17, 4, 5,110, 97, 109, 101, 49, 128, 5, 114, 117, 108, 101, 49, 129, 1, 255, 48, 132, 0, 0, 0, 14, 4, 5, 110, 97, 109, 101, - 50, 128, 5, 114, 117, 108, 101, 50 - }, control.GetValue()); + 50, 128, 5, 114, 117, 108, 101, 50} : + new byte[] { 48, 19, 48, 9, 4, 1, 110, 128, 1, 114, 129, 1, 255, 48, 6, 4, 1, 110, 128, 1, 114 }; + Assert.Equal(expected, control.GetValue()); } [Fact] diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/System.DirectoryServices.Protocols.Tests.csproj b/src/libraries/System.DirectoryServices.Protocols/tests/System.DirectoryServices.Protocols.Tests.csproj index 45ee75557ac22e..4c621fb35408be 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/System.DirectoryServices.Protocols.Tests.csproj +++ b/src/libraries/System.DirectoryServices.Protocols/tests/System.DirectoryServices.Protocols.Tests.csproj @@ -1,6 +1,6 @@ - $(NetCoreAppCurrent)-Windows_NT;$(NetFrameworkCurrent) + $(NetCoreAppCurrent);$(NetFrameworkCurrent) @@ -47,9 +47,9 @@ - - Common\DirectoryServices\LdapConfiguration.cs - + + diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/VerifyNameControlTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/VerifyNameControlTests.cs index 73db25a5717599..93b790224c9509 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/VerifyNameControlTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/VerifyNameControlTests.cs @@ -2,10 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; +using System.Runtime.InteropServices; using Xunit; namespace System.DirectoryServices.Protocols.Tests { + [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class VerifyNameControlTests { [Fact] @@ -18,12 +21,18 @@ public void Ctor_Default() Assert.True(control.ServerSide); Assert.Equal("1.2.840.113556.1.4.1338", control.Type); - Assert.Equal(new byte[] { 48, 132, 0, 0, 0, 5, 2, 1, 0, 4, 0 }, control.GetValue()); + var expected = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 5, 2, 1, 0, 4, 0 } : new byte[] { 48, 5, 2, 1, 0, 4, 0 }; + Assert.Equal(expected, control.GetValue()); + } + + public static IEnumerable Ctor_ServerName_Data() + { + yield return new object[] { "", (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 5, 2, 1, 0, 4, 0 } : new byte[] { 48, 5, 2, 1, 0, 4, 0 } }; + yield return new object[] { "S", (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 7, 2, 1, 0, 4, 2, 83, 0 } : new byte[] { 48, 7, 2, 1, 0, 4, 2, 83, 0 } }; } [Theory] - [InlineData("", new byte[] { 48, 132, 0, 0, 0, 5, 2, 1, 0, 4, 0 })] - [InlineData("S", new byte[] { 48, 132, 0, 0, 0, 7, 2, 1, 0, 4, 2, 83, 0 })] + [MemberData(nameof(Ctor_ServerName_Data))] public void Ctor_ServerName(string serverName, byte[] expectedValue) { var control = new VerifyNameControl(serverName); @@ -36,9 +45,14 @@ public void Ctor_ServerName(string serverName, byte[] expectedValue) Assert.Equal(expectedValue, control.GetValue()); } + public static IEnumerable Ctor_ServerName_Flag_Data() + { + yield return new object[] { "", -1, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 8, 2, 4, 255, 255, 255, 255, 4, 0 } : new byte[] { 48, 5, 2, 1, 255, 4, 0 } }; + yield return new object[] { "S", 10, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 7, 2, 1, 10, 4, 2, 83, 0 } : new byte[] { 48, 7, 2, 1, 10, 4, 2, 83, 0 } }; + } + [Theory] - [InlineData("", -1, new byte[] { 48, 132, 0, 0, 0, 8, 2, 4, 255, 255, 255, 255, 4, 0 })] - [InlineData("S", 10, new byte[] { 48, 132, 0, 0, 0, 7, 2, 1, 10, 4, 2, 83, 0 })] + [MemberData(nameof(Ctor_ServerName_Flag_Data))] public void Ctor_ServerName_Flag(string serverName, int flag, byte[] expectedValue) { var control = new VerifyNameControl(serverName, flag); diff --git a/src/libraries/System.DirectoryServices.Protocols/tests/VlvRequestControlTests.cs b/src/libraries/System.DirectoryServices.Protocols/tests/VlvRequestControlTests.cs index d2f42a65fd6cec..7d1844b601e058 100644 --- a/src/libraries/System.DirectoryServices.Protocols/tests/VlvRequestControlTests.cs +++ b/src/libraries/System.DirectoryServices.Protocols/tests/VlvRequestControlTests.cs @@ -2,10 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; +using System.Runtime.InteropServices; using Xunit; namespace System.DirectoryServices.Protocols.Tests { + [ConditionalClass(typeof(DirectoryServicesTestHelpers), nameof(DirectoryServicesTestHelpers.IsWindowsOrLibLdapIsInstalled))] public class VlvRequestControlTests { [Fact] @@ -22,12 +25,18 @@ public void Ctor_Default() Assert.True(control.ServerSide); Assert.Equal("2.16.840.1.113730.3.4.9", control.Type); - Assert.Equal(new byte[] { 48, 132, 0, 0, 0, 18, 2, 1, 0, 2, 1, 0, 160, 132, 0, 0, 0, 6, 2, 1, 0, 2, 1, 0 }, control.GetValue()); + var expected = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 18, 2, 1, 0, 2, 1, 0, 160, 132, 0, 0, 0, 6, 2, 1, 0, 2, 1, 0 } : new byte[] { 48, 14, 2, 1, 0, 2, 1, 0, 160, 6, 2, 1, 0, 2, 1, 0 }; + Assert.Equal(expected, control.GetValue()); + } + + public static IEnumerable Ctor_BeforeCount_AfterCount_Offset_Data() + { + yield return new object[] { 0, 0, 0, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 18, 2, 1, 0, 2, 1, 0, 160, 132, 0, 0, 0, 6, 2, 1, 0, 2, 1, 0 } : new byte[] { 48, 14, 2, 1, 0, 2, 1, 0, 160, 6, 2, 1, 0, 2, 1, 0 } }; + yield return new object[] { 10, 10, 10, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 18, 2, 1, 10, 2, 1, 10, 160, 132, 0, 0, 0, 6, 2, 1, 10, 2, 1, 0 } : new byte[] { 48, 14, 2, 1, 10, 2, 1, 10, 160, 6, 2, 1, 10, 2, 1, 0 } }; } [Theory] - [InlineData(0, 0, 0, new byte[] { 48, 132, 0, 0, 0, 18, 2, 1, 0, 2, 1, 0, 160, 132, 0, 0, 0, 6, 2, 1, 0, 2, 1, 0 })] - [InlineData(10, 10, 10, new byte[] { 48, 132, 0, 0, 0, 18, 2, 1, 10, 2, 1, 10, 160, 132, 0, 0, 0, 6, 2, 1, 10, 2, 1, 0 })] + [MemberData(nameof(Ctor_BeforeCount_AfterCount_Offset_Data))] public void Ctor_BeforeCount_AfterCount_Offset(int beforeCount, int afterCount, int offset, byte[] expectedValue) { var control = new VlvRequestControl(beforeCount, afterCount, offset); @@ -44,9 +53,14 @@ public void Ctor_BeforeCount_AfterCount_Offset(int beforeCount, int afterCount, Assert.Equal(expectedValue, control.GetValue()); } + public static IEnumerable Ctor_BeforeCount_AfterCount_StringTarget_Data() + { + yield return new object[] { 0, 0, null, new byte[0], (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 18, 2, 1, 0, 2, 1, 0, 160, 132, 0, 0, 0, 6, 2, 1, 0, 2, 1, 0 } : new byte[] { 48, 14, 2, 1, 0, 2, 1, 0, 160, 6, 2, 1, 0, 2, 1, 0 } }; + yield return new object[] { 10, 10, "abc", new byte[] { 97, 98, 99 }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 11, 2, 1, 10, 2, 1, 10, 129, 3, 97, 98, 99 } : new byte[] { 48, 11, 2, 1, 10, 2, 1, 10, 129, 3, 97, 98, 99 } }; + } + [Theory] - [InlineData(0, 0, null, new byte[0], new byte[] { 48, 132, 0, 0, 0, 18, 2, 1, 0, 2, 1, 0, 160, 132, 0, 0, 0, 6, 2, 1, 0, 2, 1, 0 })] - [InlineData(10, 10, "abc", new byte[] { 97, 98, 99 }, new byte[] { 48, 132, 0, 0, 0, 11, 2, 1, 10, 2, 1, 10, 129, 3, 97, 98, 99 })] + [MemberData(nameof(Ctor_BeforeCount_AfterCount_StringTarget_Data))] public void Ctor_BeforeCount_AfterCount_StringTarget(int beforeCount, int afterCount, string target, byte[] expectedTarget, byte[] expectedValue) { var control = new VlvRequestControl(beforeCount, afterCount, target); @@ -64,9 +78,14 @@ public void Ctor_BeforeCount_AfterCount_StringTarget(int beforeCount, int afterC Assert.Equal(expectedValue, control.GetValue()); } + public static IEnumerable Ctor_BeforeCount_AfterCount_ByteArrayTarget_Data() + { + yield return new object[] { 0, 0, null, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 18, 2, 1, 0, 2, 1, 0, 160, 132, 0, 0, 0, 6, 2, 1, 0, 2, 1, 0 } : new byte[] { 48, 14, 2, 1, 0, 2, 1, 0, 160, 6, 2, 1, 0, 2, 1, 0 } }; + yield return new object[] { 10, 10, new byte[] { 1, 2, 3 }, (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 11, 2, 1, 10, 2, 1, 10, 129, 3, 1, 2, 3 } : new byte[] { 48, 11, 2, 1, 10, 2, 1, 10, 129, 3, 1, 2, 3 } }; + } + [Theory] - [InlineData(0, 0, null, new byte[] { 48, 132, 0, 0, 0, 18, 2, 1, 0, 2, 1, 0, 160, 132, 0, 0, 0, 6, 2, 1, 0, 2, 1, 0 })] - [InlineData(10, 10, new byte[] { 1, 2, 3 }, new byte[] { 48, 132, 0, 0, 0, 11, 2, 1, 10, 2, 1, 10, 129, 3, 1, 2, 3 })] + [MemberData(nameof(Ctor_BeforeCount_AfterCount_ByteArrayTarget_Data))] public void Ctor_BeforeCount_AfterCount_ByteArrayTarget(int beforeCount, int afterCount, byte[] target, byte[] expectedValue) { var control = new VlvRequestControl(beforeCount, afterCount, target); @@ -128,7 +147,8 @@ public void ContextId_Set_GetReturnsExpected() Assert.NotSame(contextId, control.ContextId); Assert.Equal(contextId, control.ContextId); - Assert.Equal(new byte[] { 48, 132, 0, 0, 0, 23, 2, 1, 0, 2, 1, 0, 160, 132, 0, 0, 0, 6, 2, 1, 0, 2, 1, 0, 4, 3, 1, 2, 3 }, control.GetValue()); + var expected = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? new byte[] { 48, 132, 0, 0, 0, 23, 2, 1, 0, 2, 1, 0, 160, 132, 0, 0, 0, 6, 2, 1, 0, 2, 1, 0, 4, 3, 1, 2, 3 } : new byte[] { 48, 19, 2, 1, 0, 2, 1, 0, 160, 6, 2, 1, 0, 2, 1, 0, 4, 3, 1, 2, 3 }; + Assert.Equal(expected, control.GetValue()); } } } diff --git a/src/libraries/System.DirectoryServices/src/System.DirectoryServices.csproj b/src/libraries/System.DirectoryServices/src/System.DirectoryServices.csproj index 6b2e2ad96e4810..e8ca838dc2aff1 100644 --- a/src/libraries/System.DirectoryServices/src/System.DirectoryServices.csproj +++ b/src/libraries/System.DirectoryServices/src/System.DirectoryServices.csproj @@ -1,13 +1,15 @@ - System.DirectoryServices true $(NoWarn);0649 - SR.DirectoryServices_PlatformNotSupported $(NetCoreAppCurrent)-Windows_NT;netstandard2.0;netcoreapp2.0-Windows_NT;_$(NetFrameworkCurrent) true - + + + SR.DirectoryServices_PlatformNotSupported + + @@ -147,7 +149,7 @@ - + diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchedule.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchedule.cs index e4eee6a47e26dd..2ae4757c6f3b93 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchedule.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchedule.cs @@ -59,7 +59,7 @@ public ActiveDirectorySchedule() public ActiveDirectorySchedule(ActiveDirectorySchedule schedule) : this() { if (schedule == null) - throw new ArgumentNullException(); + throw new ArgumentNullException(nameof(schedule)); bool[] tmpSchedule = schedule._scheduleArray; for (int i = 0; i < 672; i++) diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaClass.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaClass.cs index 71b87ab9d2225e..8b4b2d41af9af3 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaClass.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaClass.cs @@ -998,8 +998,6 @@ public Guid SchemaGuid { CheckIfDisposed(); - Guid schemaGuid = Guid.Empty; - if (isBound) { if (_schemaGuidBinaryForm == null) diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaClassCollection.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaClassCollection.cs index ae07de8d521e54..c506669acc8359 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaClassCollection.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaClassCollection.cs @@ -111,7 +111,7 @@ public void AddRange(ActiveDirectorySchemaClass[] schemaClasses) { if (schemaClass == null) { - throw new ArgumentException(nameof(schemaClasses)); + throw new ArgumentException(null, nameof(schemaClasses)); } } @@ -132,7 +132,7 @@ public void AddRange(ActiveDirectorySchemaClassCollection schemaClasses) { if (schemaClass == null) { - throw new ArgumentException(nameof(schemaClasses)); + throw new ArgumentException(null, nameof(schemaClasses)); } } @@ -154,7 +154,7 @@ public void AddRange(ReadOnlyActiveDirectorySchemaClassCollection schemaClasses) { if (schemaClass == null) { - throw new ArgumentException(nameof(schemaClasses)); + throw new ArgumentException(null, nameof(schemaClasses)); } } @@ -360,7 +360,7 @@ protected override void OnValidate(object value) if (!(value is ActiveDirectorySchemaClass)) { - throw new ArgumentException(nameof(value)); + throw new ArgumentException(null, nameof(value)); } if (!((ActiveDirectorySchemaClass)value).isBound) diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaProperty.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaProperty.cs index 62ac720c966e17..f13544ef2b14a9 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaProperty.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaProperty.cs @@ -1086,8 +1086,6 @@ public Guid SchemaGuid { CheckIfDisposed(); - Guid schemaGuid = Guid.Empty; - if (isBound) { if (_schemaGuidBinaryForm == null) diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaPropertyCollection.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaPropertyCollection.cs index 0e312f9b392cb8..5bea1fa12e76e1 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaPropertyCollection.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySchemaPropertyCollection.cs @@ -109,7 +109,7 @@ public void AddRange(ActiveDirectorySchemaProperty[] properties) { if (property == null) { - throw new ArgumentException(nameof(properties)); + throw new ArgumentException(null, nameof(properties)); } } @@ -130,7 +130,7 @@ public void AddRange(ActiveDirectorySchemaPropertyCollection properties) { if (property == null) { - throw new ArgumentException(nameof(properties)); + throw new ArgumentException(null, nameof(properties)); } } @@ -153,7 +153,7 @@ public void AddRange(ReadOnlyActiveDirectorySchemaPropertyCollection properties) { if (property == null) { - throw new ArgumentException(nameof(properties)); + throw new ArgumentException(null, nameof(properties)); } } @@ -369,7 +369,7 @@ protected override void OnValidate(object value) if (value == null) throw new ArgumentNullException(nameof(value)); if (!(value is ActiveDirectorySchemaProperty)) - throw new ArgumentException(nameof(value)); + throw new ArgumentException(null, nameof(value)); if (!((ActiveDirectorySchemaProperty)value).isBound) throw new InvalidOperationException(SR.Format(SR.SchemaObjectNotCommitted, ((ActiveDirectorySchemaProperty)value).Name)); diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySite.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySite.cs index b4f5125772444a..a5290e58c7c68a 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySite.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySite.cs @@ -419,7 +419,7 @@ public DirectoryServer InterSiteTopologyGenerator if (existing) { // for existing site, nTDSSiteSettings needs to exist - DirectoryEntry tmp = NTDSSiteEntry; + _ = NTDSSiteEntry; } _topologyTouched = true; @@ -1329,7 +1329,6 @@ private void GetDomains() if (count > 0) { Debug.Assert(val != (IntPtr)0); - int status = Marshal.ReadInt32(val); IntPtr tmpPtr = (IntPtr)0; for (int i = 0; i < count; i++) { diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySiteCollection.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySiteCollection.cs index 88beabbb7b3750..5e85364b26da9c 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySiteCollection.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySiteCollection.cs @@ -232,7 +232,7 @@ protected override void OnValidate(object value) if (value == null) throw new ArgumentNullException(nameof(value)); if (!(value is ActiveDirectorySite)) - throw new ArgumentException(nameof(value)); + throw new ArgumentException(null, nameof(value)); if (!((ActiveDirectorySite)value).existing) throw new InvalidOperationException(SR.Format(SR.SiteNotCommitted, ((ActiveDirectorySite)value).Name)); diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySiteLink.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySiteLink.cs index e35ece7285cfe1..244b020f7b3f32 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySiteLink.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySiteLink.cs @@ -268,7 +268,7 @@ public int Cost throw new ObjectDisposedException(GetType().Name); if (value < 0) - throw new ArgumentException(nameof(value)); + throw new ArgumentException(null, nameof(value)); try { diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySiteLinkCollection.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySiteLinkCollection.cs index 24d230c920a802..3f6afc747b36a9 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySiteLinkCollection.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySiteLinkCollection.cs @@ -226,7 +226,7 @@ protected override void OnValidate(object value) if (value == null) throw new ArgumentNullException(nameof(value)); if (!(value is ActiveDirectorySiteLink)) - throw new ArgumentException(nameof(value)); + throw new ArgumentException(null, nameof(value)); if (!((ActiveDirectorySiteLink)value).existing) throw new InvalidOperationException(SR.Format(SR.SiteLinkNotCommitted, ((ActiveDirectorySiteLink)value).Name)); diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySubnetCollection.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySubnetCollection.cs index b270eab2247fbc..540be8cbfc5c01 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySubnetCollection.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ActiveDirectorySubnetCollection.cs @@ -68,7 +68,7 @@ public void AddRange(ActiveDirectorySubnet[] subnets) { if (s == null) { - throw new ArgumentException(nameof(subnets)); + throw new ArgumentException(null, nameof(subnets)); } } @@ -263,7 +263,7 @@ protected override void OnValidate(object value) if (value == null) throw new ArgumentNullException(nameof(value)); if (!(value is ActiveDirectorySubnet)) - throw new ArgumentException(nameof(value)); + throw new ArgumentException(null, nameof(value)); if (!((ActiveDirectorySubnet)value).existing) throw new InvalidOperationException(SR.Format(SR.SubnetNotCommitted, ((ActiveDirectorySubnet)value).Name)); diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ConfigSet.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ConfigSet.cs index 675a72e3a74123..6fc86392dfc2cb 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ConfigSet.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/ConfigSet.cs @@ -436,7 +436,6 @@ internal static AdamInstance FindAnyAdamInstance(DirectoryContext context) try { - string entryName = (string)rootEntry.Properties["distinguishedName"].Value; // Search for computer "serviceConnectionObjects" where the keywords attribute // contains the specified keyword // set up the searcher object diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/DirectoryServer.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/DirectoryServer.cs index 2d9f940a292ad3..5f191c7770e035 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/DirectoryServer.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/DirectoryServer.cs @@ -109,7 +109,7 @@ public void MoveToAnotherSite(string siteName) DirectoryEntry serverEntry = directoryEntryMgr.GetCachedDirectoryEntry(serverName); // force binding (needed otherwise S.DS throw an exception while releasing the COM interface pointer) - string dn = (string)PropertyManager.GetPropertyValue(context, serverEntry, PropertyManager.DistinguishedName); + _ = (string)PropertyManager.GetPropertyValue(context, serverEntry, PropertyManager.DistinguishedName); // move the object to the servers container of the target site serverEntry.MoveTo(newParentEntry); diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/DirectoryServerCollection.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/DirectoryServerCollection.cs index 20ee51fd55c607..64de6d61b67e86 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/DirectoryServerCollection.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/DirectoryServerCollection.cs @@ -115,7 +115,7 @@ public void AddRange(DirectoryServer[] servers) { if (s == null) { - throw new ArgumentException(nameof(servers)); + throw new ArgumentException(null, nameof(servers)); } } @@ -386,7 +386,7 @@ protected override void OnValidate(object value) else { if (!(value is DirectoryServer)) - throw new ArgumentException(nameof(value)); + throw new ArgumentException(null, nameof(value)); } } diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/GlobalCatalog.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/GlobalCatalog.cs index e472e98acd26f1..cab5dfbab8ef2e 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/GlobalCatalog.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/GlobalCatalog.cs @@ -263,7 +263,7 @@ public ReadOnlyActiveDirectorySchemaPropertyCollection FindAllProperties() { throw ExceptionHelper.GetExceptionFromCOMException(context, e); } - DirectoryContext schemaContext = Utils.GetNewDirectoryContext(Name, DirectoryContextType.DirectoryServer, context); + _ = Utils.GetNewDirectoryContext(Name, DirectoryContextType.DirectoryServer, context); _schema = new ActiveDirectorySchema(context, schemaNC); } diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/Utils.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/Utils.cs index f7f6dd5d5302ab..805418b55354db 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/Utils.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/ActiveDirectory/Utils.cs @@ -689,7 +689,7 @@ internal static void FreeDSHandle(IntPtr dsHandle, LoadLibrarySafeHandle libHand throw ExceptionHelper.GetExceptionFromErrorCode(Marshal.GetLastWin32Error()); } NativeMethods.DsUnBind dsUnBind = (NativeMethods.DsUnBind)Marshal.GetDelegateForFunctionPointer(functionPtr, typeof(NativeMethods.DsUnBind)); - int result = dsUnBind(ref dsHandle); + _ = dsUnBind(ref dsHandle); } } @@ -782,7 +782,7 @@ internal static DirectoryEntry GetCrossRefEntry(DirectoryContext context, Direct throw ExceptionHelper.GetExceptionFromCOMException(context, e); } - string crossRefDN = (string)PropertyManager.GetSearchResultPropertyValue(res, PropertyManager.DistinguishedName); + _ = (string)PropertyManager.GetSearchResultPropertyValue(res, PropertyManager.DistinguishedName); return res.GetDirectoryEntry(); } @@ -1447,8 +1447,6 @@ internal static ArrayList GetReplicaList(DirectoryContext context, string partit } } - string[] propertiesToLoad2 = new string[5]; - ADSearcher searcher2 = new ADSearcher(searchRootEntry, filter2, Array.Empty(), SearchScope.Subtree); SearchResultCollection resCol = null; bool needToContinueRangeRetrieval = false; diff --git a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/PropertyCollection.cs b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/PropertyCollection.cs index 5855d93d7bf37f..c9f9e28873134c 100644 --- a/src/libraries/System.DirectoryServices/src/System/DirectoryServices/PropertyCollection.cs +++ b/src/libraries/System.DirectoryServices/src/System/DirectoryServices/PropertyCollection.cs @@ -110,7 +110,7 @@ public IDictionaryEnumerator GetEnumerator() DirectoryEntry entryToUse = _entry.CloneBrowsable(); entryToUse.FillCache(""); - UnsafeNativeMethods.IAdsPropertyList propList = (UnsafeNativeMethods.IAdsPropertyList)entryToUse.AdsObject; + _ = (UnsafeNativeMethods.IAdsPropertyList)entryToUse.AdsObject; entryToUse.propertiesAlreadyEnumerated = true; return new PropertyEnumerator(_entry, entryToUse); diff --git a/src/libraries/System.DirectoryServices/tests/System.DirectoryServices.Tests.csproj b/src/libraries/System.DirectoryServices/tests/System.DirectoryServices.Tests.csproj index c4df6bbeb60f50..0788f30fb8f65a 100644 --- a/src/libraries/System.DirectoryServices/tests/System.DirectoryServices.Tests.csproj +++ b/src/libraries/System.DirectoryServices/tests/System.DirectoryServices.Tests.csproj @@ -18,9 +18,8 @@ - - Common\DirectoryServices\LdapConfiguration.cs - + @@ -31,4 +30,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj index 46ac878a5842e0..34d6599a3369ab 100644 --- a/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj +++ b/src/libraries/System.Drawing.Common/ref/System.Drawing.Common.csproj @@ -1,6 +1,6 @@ - netcoreapp3.0;$(NetCoreAppCurrent) + $(NetCoreAppCurrent);netcoreapp3.0 true enable diff --git a/src/libraries/System.Drawing.Common/src/Resources/Strings.resx b/src/libraries/System.Drawing.Common/src/Resources/Strings.resx index e5b4b7e8d05aea..0ec4b7edab41d9 100644 --- a/src/libraries/System.Drawing.Common/src/Resources/Strings.resx +++ b/src/libraries/System.Drawing.Common/src/Resources/Strings.resx @@ -455,4 +455,7 @@ The value of the {0} property is not one of the {1} values + + The directory {0} of the filename {1} does not exist. + \ No newline at end of file diff --git a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj index 7a6ca380042f9b..0291615e11c0bd 100644 --- a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj +++ b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj @@ -5,7 +5,7 @@ CS0618 $(DefineConstants);FEATURE_WINDOWS_SYSTEM_COLORS;FEATURE_SYSTEM_EVENTS true - netcoreapp3.0-Windows_NT;netcoreapp3.0-Unix;$(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix + $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix;netcoreapp3.0-Windows_NT;netcoreapp3.0-Unix true enable @@ -151,12 +151,10 @@ - - Common\Interop\Windows\User32\Interop.LOGFONT.cs - - - Common\Interop\Windows\Gdi32\Interop.RasterOp.cs - + + System.Drawing.DefaultComponent.bmp @@ -166,7 +164,7 @@ - + @@ -221,117 +219,80 @@ - - System\LocalAppContextSwitches.Common.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Gdi32\Interop.CombineRgn.cs - - - Common\Interop\Windows\Gdi32\Interop.CreateCompatibleDC.cs - - - Common\Interop\Windows\Gdi32\Interop.CreateDC.cs - - - Common\Interop\Windows\Gdi32\Interop.CreateIC.cs - - - Common\Interop\Windows\Gdi32\Interop.CreateFontIndirect.cs - - - Common\Interop\Windows\Gdi32\Interop.CreateRectRgn.cs - - - Common\Interop\Windows\Gdi32\Interop.DeleteDC.cs - - - Common\Interop\Windows\Gdi32\Interop.DeleteObject.cs - - - Common\Interop\Windows\Gdi32\Interop.GetClipRgn.cs - - - Common\Interop\Windows\Gdi32\Interop.GetCurrentObject.cs - - - Common\Interop\Windows\Gdi32\Interop.GetDeviceCaps.cs - - - Common\Interop\Windows\Gdi32\Interop.GetObjectType.cs - - - Common\Interop\Windows\Gdi32\Interop.GetRgnBox.cs - - - Common\Interop\Windows\Gdi32\Interop.GetStockObject.cs - - - Common\Interop\Windows\Gdi32\Interop.ObjectType.cs - - - Common\Interop\Windows\Gdi32\Interop.OffsetViewportOrgEx.cs - - - Common\Interop\Windows\Gdi32\Interop.RECT.cs - - - Common\Interop\Windows\Gdi32\Interop.RegionType.cs - - - Common\Interop\Windows\Gdi32\Interop.RestoreDC.cs - - - Common\Interop\Windows\Gdi32\Interop.SaveDC.cs - - - Common\Interop\Windows\Gdi32\Interop.SelectClipRgn.cs - - - Common\Interop\Windows\Kernel32\Interop.GlobalFree.cs - - - Common\Interop\Windows\Kernel32\Interop.GlobalLock.cs - - - Common\Interop\Windows\Gdi32\Interop.BitBlt.cs - - - Common\Interop\Windows\Ole32\Interop.IStream.cs - - - Common\Interop\Windows\Ole32\Interop.STATSTG.cs - - - Common\Interop\Windows\Ole32\Interop.STGTY.cs - - - Common\Interop\Windows\Ole32\Interop.STATFLAG.cs - - - Common\Interop\Windows\Ole32\Interop.STGM.cs - - - Common\Interop\Windows\User32\Interop.GetDC.cs - - - Common\Interop\Windows\User32\Interop.ReleaseDC.cs - - - Common\Interop\Windows\User32\Interop.SystemParametersInfo.cs - - - Common\Interop\Windows\User32\Interop.NONCLIENTMETRICS.cs - - - Common\Interop\Windows\User32\Interop.WindowFromDC.cs - - - Common\Interop\Windows\Interop.HRESULT.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -377,9 +338,8 @@ - - Common\Interop\Unix\Interop.Libraries.cs - + placeholder.ico diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/BitmapSelector.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/BitmapSelector.cs index 06ccdf8e3c9c5a..ae11c6e29d640f 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/BitmapSelector.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/BitmapSelector.cs @@ -64,7 +64,7 @@ internal static string AppendSuffix(string filePath) /// public static string GetFileName(string originalPath) { - if (Suffix == string.Empty) + if (string.IsNullOrEmpty(Suffix)) return originalPath; string newPath = AppendSuffix(originalPath); diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Drawing2D/LinearGradientBrush.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Drawing2D/LinearGradientBrush.cs index 19228b5266f031..666eb631d7b37e 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Drawing2D/LinearGradientBrush.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Drawing2D/LinearGradientBrush.cs @@ -232,14 +232,14 @@ public Blend? Blend throw new NullReferenceException(); if (value.Positions == null) - throw new ArgumentNullException("source"); + throw new ArgumentException(SR.Format(SR.InvalidArgumentValue, "value.Positions", value.Positions), nameof(value)); int count = value.Factors.Length; if (count == 0 || value.Positions.Length == 0) throw new ArgumentException(SR.BlendObjectMustHaveTwoElements); if (count >= 2 && count != value.Positions.Length) - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(value)); if (count >= 2 && value.Positions[0] != 0.0F) throw new ArgumentException(SR.BlendObjectFirstElementInvalid); if (count >= 2 && value.Positions[count - 1] != 1.0F) diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Drawing2D/PathGradientBrush.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Drawing2D/PathGradientBrush.cs index bae8b7a6121d23..f416ff221aa693 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Drawing2D/PathGradientBrush.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Drawing2D/PathGradientBrush.cs @@ -185,10 +185,8 @@ public Blend Blend if (value == null || value.Factors == null) throw new NullReferenceException(); - // The Desktop implementation throws ArgumentNullException("source") because it never validates the value of value.Positions, and then passes it - // on to Marshal.Copy(value.Positions, 0, positions, count);. The first argument of Marshal.Copy is source, hence this exception. if (value.Positions == null) - throw new ArgumentNullException("source"); + throw new ArgumentException(SR.Format(SR.InvalidArgumentValue, "value.Positions", value.Positions), nameof(value)); int count = value.Factors.Length; @@ -196,7 +194,7 @@ public Blend Blend if (count == 0 || value.Positions.Length == 0) throw new ArgumentException(SR.BlendObjectMustHaveTwoElements); if (count >= 2 && count != value.Positions.Length) - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(value)); if (count >= 2 && value.Positions[0] != 0.0F) throw new ArgumentException(SR.BlendObjectFirstElementInvalid); if (count >= 2 && value.Positions[count - 1] != 1.0F) @@ -298,16 +296,12 @@ public ColorBlend InterpolationColors } set { - // The Desktop implementation will throw various exceptions - ranging from NullReferenceExceptions to Argument(OutOfRange)Exceptions - // depending on how sane the input is. These checks exist to replicate the exact Desktop behavior. int count = value.Colors.Length; if (value.Positions == null) - throw new ArgumentNullException("source"); - if (value.Colors.Length > value.Positions.Length) - throw new ArgumentOutOfRangeException(); - if (value.Colors.Length < value.Positions.Length) - throw new ArgumentException(); + throw new ArgumentException(SR.Format(SR.InvalidArgumentValue, "value.Positions", value.Positions), nameof(value)); + if (value.Colors.Length != value.Positions.Length) + throw new ArgumentOutOfRangeException(nameof(value)); float[] positions = value.Positions; int[] argbs = new int[count]; diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Font.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Font.Windows.cs index bfa06594420bc7..41ed7b89b7b408 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Font.Windows.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Font.Windows.cs @@ -306,7 +306,7 @@ public static unsafe Font FromLogFont(object lf, IntPtr hdc) { // If we don't actually have an object that is LOGFONT in size, trying to pass // it to GDI+ is likely to cause an AV. - throw new ArgumentException(); + throw new ArgumentException(null, nameof(lf)); } // Now that we know the marshalled size is the same as LOGFONT, copy in the data diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Font.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Font.cs index b030638dda6138..bbabbf88ed0b89 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Font.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Font.cs @@ -285,7 +285,7 @@ public unsafe void ToLogFont(object logFont, Graphics graphics) { // If we don't actually have an object that is LOGFONT in size, trying to pass // it to GDI+ is likely to cause an AV. - throw new ArgumentException(); + throw new ArgumentException(null, nameof(logFont)); } Interop.User32.LOGFONT nativeLogFont = ToLogFontInternal(graphics); diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiPlusStreamHelper.Unix.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiPlusStreamHelper.Unix.cs index 23494a11bef72f..abe50711c9fd65 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiPlusStreamHelper.Unix.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiPlusStreamHelper.Unix.cs @@ -43,10 +43,10 @@ internal sealed partial class GdiPlusStreamHelper { private Stream _stream; - public unsafe GdiPlusStreamHelper(Stream stream, bool seekToOrigin) + public unsafe GdiPlusStreamHelper(Stream stream, bool seekToOrigin, bool makeSeekable = true) { // Seeking required - if (!stream.CanSeek) + if (makeSeekable && !stream.CanSeek) { var memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Gdiplus.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Gdiplus.cs index e42459df59d1b4..2a9449435a9387 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Gdiplus.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Gdiplus.cs @@ -178,6 +178,7 @@ public const int DC_PAPERNAMES = 16, DC_ORIENTATION = 17, DC_COPIES = 18, + DC_COLORDEVICE = 32, PD_ALLPAGES = 0x00000000, PD_SELECTION = 0x00000001, PD_PAGENUMS = 0x00000002, diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.cs index c11ed0eda0e7cf..98aadfa2be2e30 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.cs @@ -1374,8 +1374,12 @@ internal struct StartupInput public static StartupInput GetDefault() { + OperatingSystem os = Environment.OSVersion; StartupInput result = default; - result.GdiplusVersion = 1; + + // In Windows 7 GDI+1.1 story is different as there are different binaries per GDI+ version. + bool isWindows7 = os.Platform == PlatformID.Win32NT && os.Version.Major == 6 && os.Version.Minor == 1; + result.GdiplusVersion = isWindows7 ? 1 : 2; // result.DebugEventCallback = null; result.SuppressBackgroundThread = false; result.SuppressExternalCodecs = false; diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Icon.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Icon.Windows.cs index 02021231f9f292..a71a09d6e793e4 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Icon.Windows.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Icon.Windows.cs @@ -639,9 +639,8 @@ public void Save(Stream outputStream) { try { - // We threw this way on NetFX if (outputStream == null) - throw new ArgumentNullException("dataStream"); + throw new ArgumentNullException(nameof(outputStream)); picture.SaveAsFile(new GPStream(outputStream, makeSeekable: false), -1, out int temp); } diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Unix.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Unix.cs index 63bda678e62aec..7398b5e2c98bb2 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Unix.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Unix.cs @@ -74,7 +74,7 @@ private protected static IntPtr InitializeFromStream(Stream stream) // We use a custom API for this, because there's no easy way // to get the Stream down to libgdiplus. So, we wrap the stream // with a set of delegates. - GdiPlusStreamHelper sh = new GdiPlusStreamHelper(stream, true); + GdiPlusStreamHelper sh = new GdiPlusStreamHelper(stream, seekToOrigin: true); int st = Gdip.GdipLoadImageFromDelegate_linux(sh.GetHeaderDelegate, sh.GetBytesDelegate, sh.PutBytesDelegate, sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, out IntPtr imagePtr); @@ -189,6 +189,11 @@ public void Save(string filename, ImageFormat format) public void Save(string filename, ImageCodecInfo encoder, EncoderParameters? encoderParams) { + if (filename == null) + throw new ArgumentNullException(nameof(filename)); + + ThrowIfDirectoryDoesntExist(filename); + int st; Guid guid = encoder.Clsid; @@ -242,7 +247,7 @@ public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters? encod try { - GdiPlusStreamHelper sh = new GdiPlusStreamHelper(stream, false); + GdiPlusStreamHelper sh = new GdiPlusStreamHelper(stream, seekToOrigin: false, makeSeekable: false); st = Gdip.GdipSaveImageToDelegate_linux(nativeImage, sh.GetBytesDelegate, sh.PutBytesDelegate, sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, ref guid, nativeEncoderParams); diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.cs index ba6812204591ff..da4dd3eac2fc68 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.cs @@ -135,6 +135,8 @@ public void Save(string filename, ImageCodecInfo encoder, EncoderParameters? enc if (encoder == null) throw new ArgumentNullException(nameof(encoder)); + ThrowIfDirectoryDoesntExist(filename); + IntPtr encoderParamsMemory = IntPtr.Zero; if (encoderParams != null) @@ -241,7 +243,7 @@ public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters? encod { Gdip.CheckStatus(Gdip.GdipSaveImageToStream( new HandleRef(this, nativeImage), - new GPStream(stream), + new GPStream(stream, makeSeekable: false), ref g, new HandleRef(encoderParams, encoderParamsMemory))); } diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.cs index 8adc6656cc1ef5..2019b33f24f148 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.cs @@ -153,6 +153,15 @@ public void Dispose() /// public void Save(string filename) => Save(filename, RawFormat); + private static void ThrowIfDirectoryDoesntExist(string filename) + { + var directoryPart = System.IO.Path.GetDirectoryName(filename); + if (!string.IsNullOrEmpty(directoryPart) && !System.IO.Directory.Exists(directoryPart)) + { + throw new DirectoryNotFoundException(SR.Format(SR.TargetDirectoryDoesNotExist, directoryPart, filename)); + } + } + /// /// Gets the width and height of this . /// diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Unix.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Unix.cs index d101b970b63f82..596a2e097fbf99 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Unix.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Unix.cs @@ -54,7 +54,7 @@ public Metafile(Stream stream) // With libgdiplus we use a custom API for this, because there's no easy way // to get the Stream down to libgdiplus. So, we wrap the stream with a set of delegates. - GdiPlusStreamHelper sh = new GdiPlusStreamHelper(stream, false); + GdiPlusStreamHelper sh = new GdiPlusStreamHelper(stream, seekToOrigin: false); int status = Gdip.GdipCreateMetafileFromDelegate_linux(sh.GetHeaderDelegate, sh.GetBytesDelegate, sh.PutBytesDelegate, sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, out nativeImage); @@ -101,7 +101,7 @@ public Metafile(Stream stream, IntPtr referenceHdc, Rectangle frameRect, Metafil // With libgdiplus we use a custom API for this, because there's no easy way // to get the Stream down to libgdiplus. So, we wrap the stream with a set of delegates. - GdiPlusStreamHelper sh = new GdiPlusStreamHelper(stream, false); + GdiPlusStreamHelper sh = new GdiPlusStreamHelper(stream, seekToOrigin: false); int status = Gdip.GdipRecordMetafileFromDelegateI_linux(sh.GetHeaderDelegate, sh.GetBytesDelegate, sh.PutBytesDelegate, sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, referenceHdc, type, ref frameRect, frameUnit, description, out nativeImage); @@ -120,7 +120,7 @@ public Metafile(Stream stream, IntPtr referenceHdc, RectangleF frameRect, Metafi // With libgdiplus we use a custom API for this, because there's no easy way // to get the Stream down to libgdiplus. So, we wrap the stream with a set of delegates. - GdiPlusStreamHelper sh = new GdiPlusStreamHelper(stream, false); + GdiPlusStreamHelper sh = new GdiPlusStreamHelper(stream, seekToOrigin: false); int status = Gdip.GdipRecordMetafileFromDelegate_linux(sh.GetHeaderDelegate, sh.GetBytesDelegate, sh.PutBytesDelegate, sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, referenceHdc, type, ref frameRect, frameUnit, description, out nativeImage); @@ -189,7 +189,7 @@ public static MetafileHeader GetMetafileHeader(Stream stream) { // With libgdiplus we use a custom API for this, because there's no easy way // to get the Stream down to libgdiplus. So, we wrap the stream with a set of delegates. - GdiPlusStreamHelper sh = new GdiPlusStreamHelper(stream, false); + GdiPlusStreamHelper sh = new GdiPlusStreamHelper(stream, seekToOrigin: false); int status = Gdip.GdipGetMetafileHeaderFromDelegate_linux(sh.GetHeaderDelegate, sh.GetBytesDelegate, sh.PutBytesDelegate, sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, header); diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Printing/PrinterSettings.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Printing/PrinterSettings.Windows.cs index 248ea747361199..2210000175fad7 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Printing/PrinterSettings.Windows.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Printing/PrinterSettings.Windows.cs @@ -517,7 +517,12 @@ public bool SupportsColor { get { - return GetDeviceCaps(Interop.Gdi32.DeviceCapability.BITSPIXEL, 1) > 1; + // If the printer supports color printing, the return value is 1; otherwise, the return value is zero. + // The pointerToBuffer parameter is not used. + return DeviceCapabilities( + capability: SafeNativeMethods.DC_COLORDEVICE, + pointerToBuffer: IntPtr.Zero, + defaultValue: 0) == 1; } } diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Printing/PrintingServices.Unix.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Printing/PrintingServices.Unix.cs index c9da109eb951d3..baf19efb84f6ca 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Printing/PrintingServices.Unix.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Printing/PrintingServices.Unix.cs @@ -422,9 +422,9 @@ internal static void LoadPrinterResolutions(string printer, PrinterSettings sett int x_resolution, y_resolution; try { - if (resolution.Contains("x")) // string.Contains(char) is .NetCore2.1+ specific + if (resolution.Contains('x')) { - string[] resolutions = resolution.Split(new[] { 'x' }); + string[] resolutions = resolution.Split('x'); x_resolution = Convert.ToInt32(resolutions[0]); y_resolution = Convert.ToInt32(resolutions[1]); } diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Text/PrivateFontCollection.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Text/PrivateFontCollection.cs index 3b150283b5dd60..60c016124d99e0 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Text/PrivateFontCollection.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Text/PrivateFontCollection.cs @@ -60,16 +60,16 @@ public void AddFontFile(string filename) { if (_nativeFontCollection == IntPtr.Zero) { +#pragma warning disable CA2208 // Instantiate argument exceptions correctly // This is the default behavior on Desktop. The ArgumentException originates from GdipPrivateAddFontFile which would // refuse the null pointer. throw new ArgumentException(); +#pragma warning restore CA2208 } if (filename == null) { - // This is the default behavior on Desktop. The name "path" originates from Path.GetFullPath or similar which would refuse - // a null value. - throw new ArgumentNullException("path"); + throw new ArgumentNullException(nameof(filename)); } // this ensure the filename is valid (or throw the correct exception) diff --git a/src/libraries/System.Drawing.Common/tests/BitmapTests.cs b/src/libraries/System.Drawing.Common/tests/BitmapTests.cs index f9123c253039c4..9c5ca385b9f995 100644 --- a/src/libraries/System.Drawing.Common/tests/BitmapTests.cs +++ b/src/libraries/System.Drawing.Common/tests/BitmapTests.cs @@ -29,6 +29,7 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; +using Microsoft.DotNet.XUnitExtensions; using Xunit; namespace System.Drawing.Tests @@ -804,6 +805,40 @@ public void GetHicon_Disposed_ThrowsArgumentException() AssertExtensions.Throws(null, () => bitmap.GetHicon()); } + [ConditionalFact(Helpers.IsDrawingSupported)] + [PlatformSpecific(TestPlatforms.Windows)] + [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "In .NET Framework we use GDI 1.0")] + public void SaveWmfAsPngDoesntChangeImageBoundaries() + { + if (PlatformDetection.IsWindows7) + { + throw new SkipTestException("GDI+ 1.1 is not supported"); + } + + if (PlatformDetection.IsArmOrArm64Process) + { + // https://github.com/dotnet/runtime/issues/28859 + throw new SkipTestException("Arm precision"); + } + + string output = GetTestFilePath() + ".png"; + using Stream wmfStream = File.OpenRead(Helpers.GetTestBitmapPath("gdiwmfboundariesbug.wmf")); + using Image bitmapFromWmf = Bitmap.FromStream(wmfStream); + bitmapFromWmf.Save(output, ImageFormat.Png); + + using Stream expectedPngStream = File.OpenRead(Helpers.GetTestBitmapPath("gdiwmfboundariesbug-output.png")); + using Image expectedPngBitmap = Bitmap.FromStream(expectedPngStream); + using MemoryStream expectedMemoryStream = new MemoryStream(); + expectedPngBitmap.Save(expectedMemoryStream, ImageFormat.Png); + + using Stream outputPngStream = File.OpenRead(output); + using Image outputPngBitmap = Bitmap.FromStream(outputPngStream); + using MemoryStream outputMemoryStream = new MemoryStream(); + outputPngBitmap.Save(outputMemoryStream, ImageFormat.Png); + + Assert.Equal(expectedMemoryStream.ToArray(), outputMemoryStream.ToArray()); + } + // This test causes an AV on Linux [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)] [ConditionalFact(Helpers.IsDrawingSupported)] @@ -1091,7 +1126,7 @@ public void SetResolution_Disposed_ThrowsArgumentException() public static IEnumerable LockBits_NotUnix_TestData() { Bitmap bitmap() => new Bitmap(2, 2, PixelFormat.Format32bppArgb); - yield return new object[] { bitmap(), new Rectangle(1, 1, 1,1), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb, 8, 1 }; + yield return new object[] { bitmap(), new Rectangle(1, 1, 1, 1), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb, 8, 1 }; yield return new object[] { bitmap(), new Rectangle(1, 1, 1, 1), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb, 8, 3 }; yield return new object[] { bitmap(), new Rectangle(1, 1, 1, 1), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb, 8, 2 }; @@ -1706,7 +1741,32 @@ public void FromNonSeekableStream() using (FileStream stream = new FileStream(path, FileMode.Open)) { - using (Bitmap bitmap = new Bitmap(new NonSeekableStream(stream))) + using (Bitmap bitmap = new Bitmap(new TestStream(stream, canSeek: false))) + { + Assert.Equal(100, bitmap.Height); + Assert.Equal(100, bitmap.Width); + Assert.Equal(ImageFormat.Png, bitmap.RawFormat); + } + } + } + + [ConditionalTheory(Helpers.IsDrawingSupported)] + [InlineData(true, false)] + [InlineData(false, false)] + [InlineData(false, true)] + public void SaveToRestrictiveStream(bool canRead, bool canSeek) + { + using (Stream backingStream = new MemoryStream()) + using (Stream restrictiveStream = new TestStream(backingStream, canRead, canSeek)) + { + using (Bitmap bitmap = new Bitmap(100, 100)) + { + bitmap.Save(restrictiveStream, ImageFormat.Png); + } + + backingStream.Position = 0; + + using (Bitmap bitmap = new Bitmap(backingStream)) { Assert.Equal(100, bitmap.Height); Assert.Equal(100, bitmap.Width); @@ -1715,22 +1775,30 @@ public void FromNonSeekableStream() } } - private class NonSeekableStream : Stream + private class TestStream : Stream { private Stream _stream; + private bool _canRead; + private bool _canSeek; - public NonSeekableStream(Stream stream) + public TestStream(Stream stream, bool canRead = true, bool canSeek = true) { _stream = stream; + _canRead = canRead; + _canSeek = canSeek; } - public override bool CanRead => _stream.CanRead; - public override bool CanSeek => false; + public override bool CanRead => _canRead && _stream.CanRead; + public override bool CanSeek => _canSeek && _stream.CanSeek; public override bool CanWrite => _stream.CanWrite; public override long Length => _stream.Length; - public override long Position { get => _stream.Position; set => throw new InvalidOperationException(); } + public override long Position + { + get => _stream.Position; + set => _stream.Position = _canSeek ? value : throw new NotSupportedException(); + } public override void Flush() => _stream.Flush(); - public override int Read(byte[] buffer, int offset, int count) => _stream.Read(buffer, offset, count); + public override int Read(byte[] buffer, int offset, int count) => _canRead ? _stream.Read(buffer, offset, count) : throw new NotSupportedException(); public override long Seek(long offset, SeekOrigin origin) => _stream.Seek(offset, origin); public override void SetLength(long value) => _stream.SetLength(value); public override void Write(byte[] buffer, int offset, int count) => _stream.Write(buffer, offset, count); diff --git a/src/libraries/System.Drawing.Common/tests/Drawing2D/LinearGradientBrushTests.cs b/src/libraries/System.Drawing.Common/tests/Drawing2D/LinearGradientBrushTests.cs index bcc33b61b72d5e..2140688e8e8bae 100644 --- a/src/libraries/System.Drawing.Common/tests/Drawing2D/LinearGradientBrushTests.cs +++ b/src/libraries/System.Drawing.Common/tests/Drawing2D/LinearGradientBrushTests.cs @@ -358,11 +358,11 @@ public void Blend_SetNullBlendFactors_ThrowsNullReferenceException() } [ConditionalFact(Helpers.IsDrawingSupported)] - public void Blend_SetNullBlendPositions_ThrowsArgumentNullException() + public void Blend_SetNullBlendPositions_ThrowsArgumentException() { using (var brush = new LinearGradientBrush(new Rectangle(1, 2, 3, 4), Color.Plum, Color.Red, 45, true)) { - AssertExtensions.Throws("source", () => brush.Blend = new Blend { Factors = new float[2], Positions = null }); + AssertExtensions.Throws("value", "source", () => brush.Blend = new Blend { Factors = new float[2], Positions = null }); } } @@ -371,7 +371,7 @@ public void Blend_SetFactorsLengthGreaterThanPositionsLength_ThrowsArgumentOutOf { using (var brush = new LinearGradientBrush(new Rectangle(1, 2, 3, 4), Color.Plum, Color.Red, 45, true)) { - AssertExtensions.Throws(null, () => brush.Blend = new Blend { Factors = new float[2], Positions = new float[1] }); + AssertExtensions.Throws("value", null, () => brush.Blend = new Blend { Factors = new float[2], Positions = new float[1] }); } } diff --git a/src/libraries/System.Drawing.Common/tests/Drawing2D/PathGradientBrushTests.cs b/src/libraries/System.Drawing.Common/tests/Drawing2D/PathGradientBrushTests.cs index 3046c016418469..3019394844d4d3 100644 --- a/src/libraries/System.Drawing.Common/tests/Drawing2D/PathGradientBrushTests.cs +++ b/src/libraries/System.Drawing.Common/tests/Drawing2D/PathGradientBrushTests.cs @@ -350,7 +350,7 @@ public void Blend_InvalidFactorPositionsLengthMismatch_ThrowsArgumentOutOfRangeE using (PathGradientBrush brush = new PathGradientBrush(_defaultFloatPoints)) { - AssertExtensions.Throws(null, () => brush.Blend = invalidBlend); + AssertExtensions.Throws("value", null, () => brush.Blend = invalidBlend); } } @@ -366,11 +366,11 @@ public void Blend_Null_ThrowsNullReferenceException() } [ConditionalFact(Helpers.IsDrawingSupported)] - public void Blend_NullBlendProperites_ThrowsArgumentNullException() + public void Blend_NullBlendProperites_ThrowsArgumentException() { using (PathGradientBrush brush = new PathGradientBrush(_defaultFloatPoints)) { - AssertExtensions.Throws("source", () => + AssertExtensions.Throws("value", "source", () => brush.Blend = new Blend() { Factors = new float[0], Positions = null }); } } @@ -651,11 +651,11 @@ public void InterpolationColors_NullColors_ThrowsNullReferenceException() } [ConditionalFact(Helpers.IsDrawingSupported)] - public void InterpolationColors_NullPoints_ArgumentNullException() + public void InterpolationColors_NullPoints_ArgumentException() { using (PathGradientBrush brush = new PathGradientBrush(_defaultFloatPoints)) { - AssertExtensions.Throws("source", () => + AssertExtensions.Throws("value", "source", () => brush.InterpolationColors = new ColorBlend() { Colors = new Color[1], Positions = null }); } } @@ -680,11 +680,11 @@ public void InterpolationColors_EmptyColors_ArgumentException() } [ConditionalFact(Helpers.IsDrawingSupported)] - public void InterpolationColors_PointsLengthGreaterThenColorsLength_ArgumentException() + public void InterpolationColors_PointsLengthGreaterThenColorsLength_ArgumentOutOfRangeException() { using (PathGradientBrush brush = new PathGradientBrush(_defaultFloatPoints)) { - AssertExtensions.Throws(null, () => + AssertExtensions.Throws("value", null, () => brush.InterpolationColors = new ColorBlend() { Colors = new Color[1], Positions = new float[2] }); } } diff --git a/src/libraries/System.Drawing.Common/tests/GdiplusTests.cs b/src/libraries/System.Drawing.Common/tests/GdiplusTests.cs index 69a9a84afb2b16..c2719dec150a86 100644 --- a/src/libraries/System.Drawing.Common/tests/GdiplusTests.cs +++ b/src/libraries/System.Drawing.Common/tests/GdiplusTests.cs @@ -2,9 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing.Text; using Xunit; namespace System.Drawing.Tests diff --git a/src/libraries/System.Drawing.Common/tests/IconTests.cs b/src/libraries/System.Drawing.Common/tests/IconTests.cs index a201c9bce16e36..25b8c5b9631e64 100644 --- a/src/libraries/System.Drawing.Common/tests/IconTests.cs +++ b/src/libraries/System.Drawing.Common/tests/IconTests.cs @@ -266,28 +266,6 @@ public void Ctor_NullIcon_ThrowsArgumentNullException() AssertExtensions.Throws("original", null, () => new Icon((Icon)null, new Size(32, 32))); } - // libgdiplus causes a segfault when given an invalid Icon handle. - [PlatformSpecific(TestPlatforms.Windows)] - [ConditionalFact(Helpers.IsDrawingSupported)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/34591", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] - public void Ctor_InvalidHandle_Success() - { - using (Icon icon = Icon.FromHandle((IntPtr)1)) - using (var stream = new MemoryStream()) - { - Exception ex = Assert.ThrowsAny(() => icon.Save(stream)); - Assert.True(ex is COMException || ex is ObjectDisposedException || ex is FileNotFoundException, $"{ex.GetType().ToString()} was thrown."); - - AssertExtensions.Throws(null, () => icon.ToBitmap()); - Assert.Equal(Size.Empty, icon.Size); - - using (var newIcon = new Icon(icon, 10, 10)) - { - Assert.Throws(() => newIcon.Handle); - } - } - } - [ConditionalFact(Helpers.IsDrawingSupported)] public void Ctor_Type_Resource() { @@ -525,7 +503,7 @@ public void Save_NullOutputStreamNoIconData_ThrowsArgumentNullException() var icon = Icon.FromHandle(source.Handle); icon.Dispose(); - AssertExtensions.Throws("dataStream", () => icon.Save(null)); + AssertExtensions.Throws("outputStream", "dataStream", () => icon.Save(null)); } } diff --git a/src/libraries/System.Drawing.Common/tests/ImageTests.cs b/src/libraries/System.Drawing.Common/tests/ImageTests.cs index e0ac720cd38f8e..120741fa05b02d 100644 --- a/src/libraries/System.Drawing.Common/tests/ImageTests.cs +++ b/src/libraries/System.Drawing.Common/tests/ImageTests.cs @@ -199,5 +199,16 @@ public void GetEncoderParameterList_ReturnsExpected(ImageFormat format, Guid[] e paramList.Param.Select(p => p.Encoder.Guid)); } } + + [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, ".NET Framework throws ExternalException")] + [ConditionalFact(Helpers.IsDrawingSupported)] + public void Save_InvalidDirectory_ThrowsDirectoryNotFoundException() + { + using (var bitmap = new Bitmap(1, 1)) + { + var badTarget = System.IO.Path.Combine("NoSuchDirectory", "NoSuchFile"); + AssertExtensions.Throws(() => bitmap.Save(badTarget), $"The directory NoSuchDirectory of the filename {badTarget} does not exist."); + } + } } } diff --git a/src/libraries/System.Drawing.Common/tests/Printing/PrinterSettingsTests.cs b/src/libraries/System.Drawing.Common/tests/Printing/PrinterSettingsTests.cs index 096ad2001e8d07..58393454f54250 100644 --- a/src/libraries/System.Drawing.Common/tests/Printing/PrinterSettingsTests.cs +++ b/src/libraries/System.Drawing.Common/tests/Printing/PrinterSettingsTests.cs @@ -431,12 +431,14 @@ public void IsDirectPrintingSupported_ImageNotSupported_ReturnsExpected() } } - [ActiveIssue("https://github.com/dotnet/runtime/issues/22221", TestPlatforms.AnyUnix)] - [ConditionalFact(Helpers.AnyInstalledPrinters, Helpers.IsDrawingSupported)] + [PlatformSpecific(TestPlatforms.Windows)] + [ConditionalFact(typeof(PrinterSettingsTests), nameof(CanTestSetHdevmode_IntPtr_Success))] public void SupportsColor_ReturnsExpected() { - var printerSettings = new PrinterSettings(); - bool supportsColor = printerSettings.SupportsColor; + // XPS and PDF printers support color. + // docs.microsoft.com/en-us/windows-hardware/drivers/print/improved-color-printing + var printerSettings = new PrinterSettings() { PrinterName = GetNameOfTestPrinterSuitableForDevModeTesting() }; + Assert.True(printerSettings.SupportsColor); } [Theory] @@ -608,7 +610,7 @@ private static string GetNameOfTestPrinterSuitableForDevModeTesting() private static readonly string[] s_TestPrinterNames = { - // Our method of testing this api requires a printer that supports multi-copy printing, collating and duplex settings. Not all printers + // Our method of testing some apis requires a printer that supports multi-copy printing, collating, color and duplex settings. Not all printers // support these so rather than trust the machine running the test to have configured such a printer as the default, use the name of // a known compliant printer that ships with Windows 10. "Microsoft Print to PDF", diff --git a/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj b/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj index 610e7ec4b39623..873e1e6dada7f2 100644 --- a/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj +++ b/src/libraries/System.Drawing.Common/tests/System.Drawing.Common.Tests.csproj @@ -79,15 +79,12 @@ - - Common\System\Diagnostics\DebuggerAttributes.cs - - - Common\System\Drawing\Helpers.cs - - - Common\System\IO\TempFile.cs - + + + diff --git a/src/libraries/System.Drawing.Common/tests/Text/PrivateFontCollectionTests.cs b/src/libraries/System.Drawing.Common/tests/Text/PrivateFontCollectionTests.cs index af934a15f458a6..364ba09bdb9dd8 100644 --- a/src/libraries/System.Drawing.Common/tests/Text/PrivateFontCollectionTests.cs +++ b/src/libraries/System.Drawing.Common/tests/Text/PrivateFontCollectionTests.cs @@ -107,7 +107,7 @@ public void AddFontFile_NullFileName_ThrowsArgumentNullException() { using (var fontCollection = new PrivateFontCollection()) { - AssertExtensions.Throws("path", () => fontCollection.AddFontFile(null)); + AssertExtensions.Throws("filename", "path", () => fontCollection.AddFontFile(null)); } } diff --git a/src/libraries/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj b/src/libraries/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj index 5a9c2609314a81..bb25694503ed25 100644 --- a/src/libraries/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj +++ b/src/libraries/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj @@ -25,34 +25,25 @@ - - System\Drawing\ColorConverterCommon.cs - - - System\Drawing\ColorTable.cs - - - System\Drawing\ColorTranslator.cs - - - System\Drawing\KnownColor.cs - - - System\Drawing\KnownColorTable.cs - - - System\Drawing\SystemColors.cs - + + + + + + - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\User32\Interop.GetSysColor.cs - - - Common\Interop\Windows\User32\Interop.Win32SystemColors.cs - + + + - \ No newline at end of file + diff --git a/src/libraries/System.Drawing.Primitives/tests/System.Drawing.Primitives.Tests.csproj b/src/libraries/System.Drawing.Primitives/tests/System.Drawing.Primitives.Tests.csproj index 1601346a37a00a..b3a3a3ea5e3d6f 100644 --- a/src/libraries/System.Drawing.Primitives/tests/System.Drawing.Primitives.Tests.csproj +++ b/src/libraries/System.Drawing.Primitives/tests/System.Drawing.Primitives.Tests.csproj @@ -12,14 +12,11 @@ - - Common\System\Diagnostics\DebuggerAttributes.cs - - - Common\System\Runtime\Serialization\DataContractSerializerHelper.cs - - - Common\System\Runtime\Serialization\Utils.cs - + + + - \ No newline at end of file + diff --git a/src/libraries/System.Globalization.Calendars/tests/System/Globalization/CalendarTestBase.cs b/src/libraries/System.Globalization.Calendars/tests/System/Globalization/CalendarTestBase.cs index 62c6166a8973cb..6e9b83982f2abb 100644 --- a/src/libraries/System.Globalization.Calendars/tests/System/Globalization/CalendarTestBase.cs +++ b/src/libraries/System.Globalization.Calendars/tests/System/Globalization/CalendarTestBase.cs @@ -430,8 +430,8 @@ public void GetEra_Invalid_ThrowsArgumentOutOfRangeException() Calendar calendar = Calendar; Assert.All(DateTime_TestData(calendar), dt => { - // JapaneseCalendar throws on Unix (ICU), but not on Windows - if ((calendar is JapaneseCalendar && PlatformDetection.IsWindows) || calendar is HebrewCalendar || calendar is TaiwanLunisolarCalendar || calendar is JapaneseLunisolarCalendar) + // JapaneseCalendar throws on ICU, but not on NLS + if ((calendar is JapaneseCalendar && PlatformDetection.IsNlsGlobalization) || calendar is HebrewCalendar || calendar is TaiwanLunisolarCalendar || calendar is JapaneseLunisolarCalendar) { calendar.GetEra(dt); } diff --git a/src/libraries/System.Globalization.Calendars/tests/TaiwanCalendar/TaiwanCalendarDaysAndMonths.cs b/src/libraries/System.Globalization.Calendars/tests/TaiwanCalendar/TaiwanCalendarDaysAndMonths.cs index a159467be35931..6da5b82fc4b748 100644 --- a/src/libraries/System.Globalization.Calendars/tests/TaiwanCalendar/TaiwanCalendarDaysAndMonths.cs +++ b/src/libraries/System.Globalization.Calendars/tests/TaiwanCalendar/TaiwanCalendarDaysAndMonths.cs @@ -32,7 +32,7 @@ public void DayNames_MonthNames() private static string[] GetExpectedMonthNames() { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (PlatformDetection.IsNlsGlobalization) { return new string[] { diff --git a/src/libraries/System.Globalization.Extensions/System.Globalization.Extensions.sln b/src/libraries/System.Globalization.Extensions/System.Globalization.Extensions.sln index 5e66148e84464f..af85e7b525730c 100644 --- a/src/libraries/System.Globalization.Extensions/System.Globalization.Extensions.sln +++ b/src/libraries/System.Globalization.Extensions/System.Globalization.Extensions.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27213.1 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29923.206 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Globalization.Extensions.Tests", "tests\System.Globalization.Extensions.Tests.csproj", "{BC439554-4AB4-4C94-8E28-C00EDE4FD1C7}" ProjectSection(ProjectDependencies) = postProject @@ -20,7 +20,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{A36A6300-3BE9-42CA-B7BC-62E926E07CC5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Globalization.Extensions.Nls.Tests", "tests\NlsTests\System.Globalization.Extensions.Nls.Tests.csproj", "{CB60359A-D0ED-474E-B395-9589F1A5656A}" + ProjectSection(ProjectDependencies) = postProject + {2B96AA10-84C0-4927-8611-8D2474B990E8} = {2B96AA10-84C0-4927-8611-8D2474B990E8} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -40,10 +43,10 @@ Global {3634FAA3-A33E-406A-94EE-5611C6CC2810}.Debug|Any CPU.Build.0 = Debug|Any CPU {3634FAA3-A33E-406A-94EE-5611C6CC2810}.Release|Any CPU.ActiveCfg = Release|Any CPU {3634FAA3-A33E-406A-94EE-5611C6CC2810}.Release|Any CPU.Build.0 = Release|Any CPU - {A36A6300-3BE9-42CA-B7BC-62E926E07CC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A36A6300-3BE9-42CA-B7BC-62E926E07CC5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A36A6300-3BE9-42CA-B7BC-62E926E07CC5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A36A6300-3BE9-42CA-B7BC-62E926E07CC5}.Release|Any CPU.Build.0 = Release|Any CPU + {CB60359A-D0ED-474E-B395-9589F1A5656A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB60359A-D0ED-474E-B395-9589F1A5656A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB60359A-D0ED-474E-B395-9589F1A5656A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB60359A-D0ED-474E-B395-9589F1A5656A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -52,7 +55,7 @@ Global {BC439554-4AB4-4C94-8E28-C00EDE4FD1C7} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} {2B96AA10-84C0-4927-8611-8D2474B990E8} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {3634FAA3-A33E-406A-94EE-5611C6CC2810} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} - {A36A6300-3BE9-42CA-B7BC-62E926E07CC5} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} + {CB60359A-D0ED-474E-B395-9589F1A5656A} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3E550ED4-6053-4B16-97D1-BAADB02924FE} diff --git a/src/libraries/System.Globalization.Extensions/tests/GetStringComparerTests.cs b/src/libraries/System.Globalization.Extensions/tests/GetStringComparerTests.cs index da82bbb23730c5..ff53746996900b 100644 --- a/src/libraries/System.Globalization.Extensions/tests/GetStringComparerTests.cs +++ b/src/libraries/System.Globalization.Extensions/tests/GetStringComparerTests.cs @@ -10,8 +10,6 @@ namespace System.Globalization.Tests { public class GetStringComparerTests { - private static bool s_isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - [Fact] public void GetStringComparer_Invalid() { @@ -35,9 +33,9 @@ public void GetStringComparer_Invalid() [InlineData("abc", "ABC", "en-US", CompareOptions.OrdinalIgnoreCase, 0, 0)] [InlineData("Cot\u00E9", "cot\u00E9", "fr-FR", CompareOptions.IgnoreCase, 0, 0)] [InlineData("cot\u00E9", "c\u00F4te", "fr-FR", CompareOptions.None, 1, -1)] - public static void Compare(string x, string y, string cultureName, CompareOptions options, int expectedWindows, int expectedICU) + public static void Compare(string x, string y, string cultureName, CompareOptions options, int expectedNls, int expectedICU) { - int expected = s_isWindows ? expectedWindows : expectedICU; + int expected = PlatformDetection.IsNlsGlobalization ? expectedNls : expectedICU; StringComparer comparer = new CultureInfo(cultureName).CompareInfo.GetStringComparer(options); Assert.Equal(expected, Math.Sign(comparer.Compare(x, y))); diff --git a/src/libraries/System.Globalization.Extensions/tests/IdnMapping/IdnMappingGetAsciiTests.cs b/src/libraries/System.Globalization.Extensions/tests/IdnMapping/IdnMappingGetAsciiTests.cs index f1a65e0fb8c4d7..93f093d061c7b8 100644 --- a/src/libraries/System.Globalization.Extensions/tests/IdnMapping/IdnMappingGetAsciiTests.cs +++ b/src/libraries/System.Globalization.Extensions/tests/IdnMapping/IdnMappingGetAsciiTests.cs @@ -22,9 +22,9 @@ public static IEnumerable GetAscii_TestData() continue; } string ascii = c.ToString(); - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // expected platform differences, see https://github.com/dotnet/runtime/issues/17190 + if (PlatformDetection.IsIcuGlobalization) // expected platform differences, see https://github.com/dotnet/runtime/issues/17190 { - if ((c >= 'A' && c <= 'Z')) + if (c >= 'A' && c <= 'Z') { yield return new object[] { ascii, 0, 1, ascii.ToLower() }; } diff --git a/src/libraries/System.Globalization.Extensions/tests/IdnMapping/IdnMappingGetUnicodeTests.cs b/src/libraries/System.Globalization.Extensions/tests/IdnMapping/IdnMappingGetUnicodeTests.cs index 6cafb29e901d12..6c583830d08c1c 100644 --- a/src/libraries/System.Globalization.Extensions/tests/IdnMapping/IdnMappingGetUnicodeTests.cs +++ b/src/libraries/System.Globalization.Extensions/tests/IdnMapping/IdnMappingGetUnicodeTests.cs @@ -96,7 +96,7 @@ public static IEnumerable GetUnicode_Invalid_TestData() yield return new object[] { "abc" + (char)0x7F + "def", 0, 7, typeof(ArgumentException) }; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // expected platform differences, see https://github.com/dotnet/runtime/issues/17190 + if (PlatformDetection.IsNlsGlobalization) // expected platform differences, see https://github.com/dotnet/runtime/issues/17190 { yield return new object[] { "xn--\u1234", 0, 5, typeof(ArgumentException) }; yield return new object[] { "xn--\u1234pck", 0, 8, typeof(ArgumentException) }; diff --git a/src/libraries/System.Globalization.Extensions/tests/IdnMapping/IdnMappingUseStd3AsciiRulesTests.cs b/src/libraries/System.Globalization.Extensions/tests/IdnMapping/IdnMappingUseStd3AsciiRulesTests.cs index 98949eac574d13..10d468ae33a538 100644 --- a/src/libraries/System.Globalization.Extensions/tests/IdnMapping/IdnMappingUseStd3AsciiRulesTests.cs +++ b/src/libraries/System.Globalization.Extensions/tests/IdnMapping/IdnMappingUseStd3AsciiRulesTests.cs @@ -22,8 +22,6 @@ namespace System.Globalization.Tests /// public class UseStd3AsciiRules { - private static bool s_isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - [Fact] public void UseStd3AsciiRules_IsFalseByDefault() { @@ -52,7 +50,7 @@ public void UseStd3AsciiRules_ChangesGetAsciiBehavior(string unicode, bool conta var idnStd3False = new IdnMapping { UseStd3AsciiRules = false }; var idnStd3True = new IdnMapping { UseStd3AsciiRules = true }; - if (containsInvalidHyphen && !s_isWindows) + if (containsInvalidHyphen && PlatformDetection.IsIcuGlobalization) { // ICU always fails on leading/trailing hyphens regardless of the Std3 rules option. AssertExtensions.Throws("unicode", () => idnStd3False.GetAscii(unicode)); diff --git a/src/libraries/System.Globalization.Extensions/tests/NlsTests/System.Globalization.Extensions.Nls.Tests.csproj b/src/libraries/System.Globalization.Extensions/tests/NlsTests/System.Globalization.Extensions.Nls.Tests.csproj new file mode 100644 index 00000000000000..671b64eaea1da0 --- /dev/null +++ b/src/libraries/System.Globalization.Extensions/tests/NlsTests/System.Globalization.Extensions.Nls.Tests.csproj @@ -0,0 +1,51 @@ + + + $(NetCoreAppCurrent)-Windows_NT + true + + + + + + + + + + + + + + + + + + + + + + + + + NormalizationDataWin8 + + + NormalizationDataWin7 + + + + \ No newline at end of file diff --git a/src/libraries/System.Globalization.Extensions/tests/NlsTests/runtimeconfig.template.json b/src/libraries/System.Globalization.Extensions/tests/NlsTests/runtimeconfig.template.json new file mode 100644 index 00000000000000..ec1e96166f3b3c --- /dev/null +++ b/src/libraries/System.Globalization.Extensions/tests/NlsTests/runtimeconfig.template.json @@ -0,0 +1,5 @@ +{ + "configProperties": { + "System.Globalization.UseNls": true + } +} diff --git a/src/libraries/System.Globalization/System.Globalization.sln b/src/libraries/System.Globalization/System.Globalization.sln index 4607fdfb149731..c4824927738b48 100644 --- a/src/libraries/System.Globalization/System.Globalization.sln +++ b/src/libraries/System.Globalization/System.Globalization.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27213.1 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29923.206 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Globalization.Tests", "tests\System.Globalization.Tests.csproj", "{484C92C6-6D2C-45BC-A5E2-4A12BA228E1E}" ProjectSection(ProjectDependencies) = postProject @@ -25,6 +25,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Globalization.Nls.Tests", "tests\NlsTests\System.Globalization.Nls.Tests.csproj", "{6B71E284-DA57-4657-9E08-A02BAFB877CC}" + ProjectSection(ProjectDependencies) = postProject + {2395E8CA-73CB-40DF-BE40-A60BC189B737} = {2395E8CA-73CB-40DF-BE40-A60BC189B737} + EndProjectSection +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{443745F1-A200-432B-A666-3D0E9F938DED}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities.Unicode", "..\Common\tests\TestUtilities.Unicode\TestUtilities.Unicode.csproj", "{E5ECA266-C7E9-4597-8FFA-095BD6890407}" @@ -51,6 +56,10 @@ Global {E1E58C98-808F-4065-9C1D-E6411166AF6F}.Debug|Any CPU.Build.0 = Debug|Any CPU {E1E58C98-808F-4065-9C1D-E6411166AF6F}.Release|Any CPU.ActiveCfg = Release|Any CPU {E1E58C98-808F-4065-9C1D-E6411166AF6F}.Release|Any CPU.Build.0 = Release|Any CPU + {6B71E284-DA57-4657-9E08-A02BAFB877CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B71E284-DA57-4657-9E08-A02BAFB877CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B71E284-DA57-4657-9E08-A02BAFB877CC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B71E284-DA57-4657-9E08-A02BAFB877CC}.Release|Any CPU.Build.0 = Release|Any CPU {443745F1-A200-432B-A666-3D0E9F938DED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {443745F1-A200-432B-A666-3D0E9F938DED}.Debug|Any CPU.Build.0 = Debug|Any CPU {443745F1-A200-432B-A666-3D0E9F938DED}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -68,6 +77,7 @@ Global {9A8926D9-1D4C-4069-8965-A626F6CA8C29} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} {2395E8CA-73CB-40DF-BE40-A60BC189B737} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {E1E58C98-808F-4065-9C1D-E6411166AF6F} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} + {6B71E284-DA57-4657-9E08-A02BAFB877CC} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} {443745F1-A200-432B-A666-3D0E9F938DED} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} {E5ECA266-C7E9-4597-8FFA-095BD6890407} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} EndGlobalSection diff --git a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.Compare.cs b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.Compare.cs index 3b2f121f586b7a..38f884c94bfb10 100644 --- a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.Compare.cs +++ b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.Compare.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Buffers; using System.Collections.Generic; using Xunit; @@ -16,12 +17,12 @@ public class CompareInfoCompareTests // On Windows, hiragana characters sort after katakana. // On ICU, it is the opposite - private static int s_expectedHiraganaToKatakanaCompare = PlatformDetection.IsWindows ? 1 : -1; + private static int s_expectedHiraganaToKatakanaCompare = PlatformDetection.IsNlsGlobalization ? 1 : -1; // On Windows, all halfwidth characters sort before fullwidth characters. // On ICU, half and fullwidth characters that aren't in the "Halfwidth and fullwidth forms" block U+FF00-U+FFEF // sort before the corresponding characters that are in the block U+FF00-U+FFEF - private static int s_expectedHalfToFullFormsComparison = PlatformDetection.IsWindows ? -1 : 1; + private static int s_expectedHalfToFullFormsComparison = PlatformDetection.IsNlsGlobalization ? -1 : 1; private const string SoftHyphen = "\u00AD"; @@ -39,13 +40,13 @@ public static IEnumerable Compare_Kana_TestData() yield return new object[] { s_invariantCompare, "\u3070\u3073\u3076\u3079\u307C", "\u30D0\u30D3\u3076\u30D9\uFF8E\uFF9E", CompareOptions.None, s_expectedHiraganaToKatakanaCompare }; yield return new object[] { s_invariantCompare, "\u3060", "\uFF80\uFF9E", CompareOptions.None, s_expectedHiraganaToKatakanaCompare }; - bool isWindows = PlatformDetection.IsWindows; + bool useNls = PlatformDetection.IsNlsGlobalization; - yield return new object[] { s_invariantCompare, "\u30C7\u30BF\u30D9\u30B9", "\uFF83\uFF9E\uFF80\uFF8D\uFF9E\uFF7D", CompareOptions.None, isWindows ? 1 : -1 }; - yield return new object[] { s_invariantCompare, "\u30C7", "\uFF83\uFF9E", CompareOptions.None, isWindows ? 1 : -1 }; - yield return new object[] { s_invariantCompare, "\u30C7\u30BF", "\uFF83\uFF9E\uFF80", CompareOptions.None, isWindows ? 1 : -1 }; - yield return new object[] { s_invariantCompare, "\u30C7\u30BF\u30D9", "\uFF83\uFF9E\uFF80\uFF8D\uFF9E", CompareOptions.None, isWindows ? 1 : -1 }; - yield return new object[] { s_invariantCompare, "\uFF83\uFF9E\uFF70\uFF80\uFF8D\uFF9E\uFF70\uFF7D", "\u3067\u30FC\u305F\u3079\u30FC\u3059", CompareOptions.None, isWindows ? -1 : 1 }; + yield return new object[] { s_invariantCompare, "\u30C7\u30BF\u30D9\u30B9", "\uFF83\uFF9E\uFF80\uFF8D\uFF9E\uFF7D", CompareOptions.None, useNls ? 1 : -1 }; + yield return new object[] { s_invariantCompare, "\u30C7", "\uFF83\uFF9E", CompareOptions.None, useNls ? 1 : -1 }; + yield return new object[] { s_invariantCompare, "\u30C7\u30BF", "\uFF83\uFF9E\uFF80", CompareOptions.None, useNls ? 1 : -1 }; + yield return new object[] { s_invariantCompare, "\u30C7\u30BF\u30D9", "\uFF83\uFF9E\uFF80\uFF8D\uFF9E", CompareOptions.None, useNls ? 1 : -1 }; + yield return new object[] { s_invariantCompare, "\uFF83\uFF9E\uFF70\uFF80\uFF8D\uFF9E\uFF70\uFF7D", "\u3067\u30FC\u305F\u3079\u30FC\u3059", CompareOptions.None, useNls ? -1 : 1 }; } public static IEnumerable Compare_TestData() @@ -207,6 +208,13 @@ public static IEnumerable Compare_TestData() yield return new object[] { s_invariantCompare, "Test's", null, CompareOptions.None, 1 }; yield return new object[] { s_invariantCompare, null, null, CompareOptions.None, 0 }; + yield return new object[] { s_invariantCompare, "", "Tests", CompareOptions.None, -1 }; + yield return new object[] { s_invariantCompare, "Tests", "", CompareOptions.None, 1 }; + + yield return new object[] { s_invariantCompare, null, "", CompareOptions.None, -1 }; + yield return new object[] { s_invariantCompare, "", null, CompareOptions.None, 1 }; + yield return new object[] { s_invariantCompare, "", "", CompareOptions.None, 0 }; + yield return new object[] { s_invariantCompare, new string('a', 5555), new string('a', 5555), CompareOptions.None, 0 }; yield return new object[] { s_invariantCompare, "foobar", "FooB\u00C0R", CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase, 0 }; yield return new object[] { s_invariantCompare, "foobar", "FooB\u00C0R", CompareOptions.IgnoreNonSpace, -1 }; @@ -237,28 +245,29 @@ public static IEnumerable Compare_TestData() yield return new object[] { new CultureInfo("es-ES").CompareInfo, "llegar", "lugar", CompareOptions.None, -1 }; // Misc differences between platforms - bool isWindows = PlatformDetection.IsWindows; - - yield return new object[] { s_invariantCompare, "\u3042", "\u30A1", CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase, isWindows ? 1: 0 }; - yield return new object[] { s_invariantCompare, "'\u3000'", "''", CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase, isWindows ? 1 : -1 }; - yield return new object[] { s_invariantCompare, "\u30BF", "\uFF80", CompareOptions.None, isWindows ? 1 : -1 }; - yield return new object[] { s_invariantCompare, "'\u3000'", "''", CompareOptions.None, isWindows ? 1 : -1 }; - yield return new object[] { s_invariantCompare, "\u30FC", "\uFF70", CompareOptions.None, isWindows ? 0 : -1 }; - yield return new object[] { s_hungarianCompare, "dzsdzs", "ddzs", CompareOptions.None, isWindows ? 0 : -1 }; - yield return new object[] { s_invariantCompare, "Test's", "Tests", CompareOptions.None, isWindows ? 1 : -1 }; + bool useNls = PlatformDetection.IsNlsGlobalization; + + yield return new object[] { s_invariantCompare, "\u3042", "\u30A1", CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase, useNls ? 1: 0 }; + yield return new object[] { s_invariantCompare, "'\u3000'", "''", CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase, useNls ? 1 : -1 }; + yield return new object[] { s_invariantCompare, "\u30BF", "\uFF80", CompareOptions.None, useNls ? 1 : -1 }; + yield return new object[] { s_invariantCompare, "'\u3000'", "''", CompareOptions.None, useNls ? 1 : -1 }; + yield return new object[] { s_invariantCompare, "\u30FC", "\uFF70", CompareOptions.None, useNls ? 0 : -1 }; + yield return new object[] { s_hungarianCompare, "dzsdzs", "ddzs", CompareOptions.None, useNls ? 0 : -1 }; + yield return new object[] { s_invariantCompare, "Test's", "Tests", CompareOptions.None, useNls ? 1 : -1 }; yield return new object[] { new CultureInfo("de-DE").CompareInfo, "\u00DC", "UE", CompareOptions.None, -1 }; - yield return new object[] { new CultureInfo("de-DE_phoneb").CompareInfo, "\u00DC", "UE", CompareOptions.None, isWindows ? 0 : -1 }; - yield return new object[] { new CultureInfo("es-ES_tradnl").CompareInfo, "llegar", "lugar", CompareOptions.None, isWindows ? 1 : -1 }; + yield return new object[] { new CultureInfo("de-DE_phoneb").CompareInfo, "\u00DC", "UE", CompareOptions.None, useNls ? 0 : -1 }; + yield return new object[] { new CultureInfo("es-ES_tradnl").CompareInfo, "llegar", "lugar", CompareOptions.None, useNls ? 1 : -1 }; } // There is a regression in Windows 190xx version with the Kana comparison. Avoid running this test there. public static bool IsNotWindowsKanaRegressedVersion() => !PlatformDetection.IsWindows10Version1903OrGreater || + PlatformDetection.IsIcuGlobalization || s_invariantCompare.Compare("\u3060", "\uFF80\uFF9E", CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase) == 0; [Fact] public void CompareWithUnassignedChars() { - int result = PlatformDetection.IsWindows ? 0 : -1; + int result = PlatformDetection.IsNlsGlobalization ? 0 : -1; Compare(s_invariantCompare, "FooBar", "Foo\uFFFFBar", CompareOptions.None, result); Compare(s_invariantCompare, "FooBar", "Foo\uFFFFBar", CompareOptions.IgnoreNonSpace, result); } @@ -361,6 +370,26 @@ public void Compare_Advanced(CompareInfo compareInfo, string string1, int offset // Use Compare(string, int, int, string, int, int, CompareOptions) Assert.Equal(expected, Math.Sign(compareInfo.Compare(string1, offset1, length1, string2, offset2, length2, options))); Assert.Equal(-expected, Math.Sign(compareInfo.Compare(string2, offset2, length2, string1, offset1, length1, options))); + + // Now test the span-based versions - use BoundedMemory to detect buffer overruns + // We can't run this test for null inputs since they implicitly convert to empty span + + if (string1 != null && string2 != null) + { + RunSpanCompareTest(compareInfo, string1.AsSpan(offset1, length1), string2.AsSpan(offset2, length2), options, expected); + } + + static void RunSpanCompareTest(CompareInfo compareInfo, ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options, int expected) + { + using BoundedMemory string1BoundedMemory = BoundedMemory.AllocateFromExistingData(string1); + string1BoundedMemory.MakeReadonly(); + + using BoundedMemory string2BoundedMemory = BoundedMemory.AllocateFromExistingData(string2); + string2BoundedMemory.MakeReadonly(); + + Assert.Equal(expected, Math.Sign(compareInfo.Compare(string1, string2, options))); + Assert.Equal(-expected, Math.Sign(compareInfo.Compare(string2, string1, options))); + } } [Fact] diff --git a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.IndexOf.cs b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.IndexOf.cs index 2036dc4d80ce17..311ae449706f9a 100644 --- a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.IndexOf.cs +++ b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.IndexOf.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Buffers; using System.Collections.Generic; +using System.Text; using Xunit; namespace System.Globalization.Tests @@ -63,6 +65,10 @@ public static IEnumerable IndexOf_TestData() yield return new object[] { s_invariantCompare, "TestFooBA\u0300R", "FooB\u00C0R", 0, 11, CompareOptions.IgnoreNonSpace, 4 }; yield return new object[] { s_invariantCompare, "o\u0308", "o", 0, 2, CompareOptions.None, -1 }; + // Weightless characters + yield return new object[] { s_invariantCompare, "", "\u200d", 0, 0, CompareOptions.None, 0 }; + yield return new object[] { s_invariantCompare, "hello", "\u200d", 1, 3, CompareOptions.IgnoreCase, 1 }; + // Ignore symbols yield return new object[] { s_invariantCompare, "More Test's", "Tests", 0, 11, CompareOptions.IgnoreSymbols, 5 }; yield return new object[] { s_invariantCompare, "More Test's", "Tests", 0, 11, CompareOptions.None, -1 }; @@ -109,26 +115,26 @@ public static IEnumerable IndexOf_TestData() yield return new object[] { s_currentCompare, "\u0131", "\u0130", 0, 1, CompareOptions.Ordinal, -1 }; // Platform differences - yield return new object[] { s_hungarianCompare, "foobardzsdzs", "rddzs", 0, 12, CompareOptions.None, PlatformDetection.IsWindows ? 5 : -1}; + yield return new object[] { s_hungarianCompare, "foobardzsdzs", "rddzs", 0, 12, CompareOptions.None, PlatformDetection.IsNlsGlobalization ? 5 : -1}; } public static IEnumerable IndexOf_Aesc_Ligature_TestData() { - bool isWindows = PlatformDetection.IsWindows; + bool useNls = PlatformDetection.IsNlsGlobalization; // Searches for the ligature \u00C6 string source1 = "Is AE or ae the same as \u00C6 or \u00E6?"; - yield return new object[] { s_invariantCompare, source1, "AE", 8, 18, CompareOptions.None, isWindows ? 24 : -1}; + yield return new object[] { s_invariantCompare, source1, "AE", 8, 18, CompareOptions.None, useNls ? 24 : -1}; yield return new object[] { s_invariantCompare, source1, "ae", 8, 18, CompareOptions.None, 9 }; yield return new object[] { s_invariantCompare, source1, "\u00C6", 8, 18, CompareOptions.None, 24 }; - yield return new object[] { s_invariantCompare, source1, "\u00E6", 8, 18, CompareOptions.None, isWindows ? 9 : -1}; + yield return new object[] { s_invariantCompare, source1, "\u00E6", 8, 18, CompareOptions.None, useNls ? 9 : -1}; yield return new object[] { s_invariantCompare, source1, "AE", 8, 18, CompareOptions.Ordinal, -1 }; yield return new object[] { s_invariantCompare, source1, "ae", 8, 18, CompareOptions.Ordinal, 9 }; yield return new object[] { s_invariantCompare, source1, "\u00C6", 8, 18, CompareOptions.Ordinal, 24 }; yield return new object[] { s_invariantCompare, source1, "\u00E6", 8, 18, CompareOptions.Ordinal, -1 }; yield return new object[] { s_invariantCompare, source1, "AE", 8, 18, CompareOptions.IgnoreCase, 9 }; yield return new object[] { s_invariantCompare, source1, "ae", 8, 18, CompareOptions.IgnoreCase, 9 }; - yield return new object[] { s_invariantCompare, source1, "\u00C6", 8, 18, CompareOptions.IgnoreCase, isWindows? 9 : 24 }; - yield return new object[] { s_invariantCompare, source1, "\u00E6", 8, 18, CompareOptions.IgnoreCase, isWindows? 9 : 24 }; + yield return new object[] { s_invariantCompare, source1, "\u00C6", 8, 18, CompareOptions.IgnoreCase, useNls ? 9 : 24 }; + yield return new object[] { s_invariantCompare, source1, "\u00E6", 8, 18, CompareOptions.IgnoreCase, useNls ? 9 : 24 }; } public static IEnumerable IndexOf_U_WithDiaeresis_TestData() @@ -192,7 +198,27 @@ public void IndexOf_String(CompareInfo compareInfo, string source, string value, // Use int MemoryExtensions.IndexOf(this ReadOnlySpan, ReadOnlySpan, StringComparison) Assert.Equal((expected == -1) ? -1 : (expected - startIndex), source.AsSpan(startIndex, count).IndexOf(value.AsSpan(), stringComparison)); } - } + + // Now test the span-based versions - use BoundedMemory to detect buffer overruns + + RunSpanIndexOfTest(compareInfo, source.AsSpan(startIndex, count), value, options, (expected < 0) ? expected : expected - startIndex); + + static void RunSpanIndexOfTest(CompareInfo compareInfo, ReadOnlySpan source, ReadOnlySpan value, CompareOptions options, int expected) + { + using BoundedMemory sourceBoundedMemory = BoundedMemory.AllocateFromExistingData(source); + sourceBoundedMemory.MakeReadonly(); + + using BoundedMemory valueBoundedMemory = BoundedMemory.AllocateFromExistingData(value); + valueBoundedMemory.MakeReadonly(); + + Assert.Equal(expected, compareInfo.IndexOf(sourceBoundedMemory.Span, valueBoundedMemory.Span, options)); + + if (TryCreateRuneFrom(value, out Rune rune)) + { + Assert.Equal(expected, compareInfo.IndexOf(sourceBoundedMemory.Span, rune, options)); // try the Rune-based version + } + } + } private static void IndexOf_Char(CompareInfo compareInfo, string source, char value, int startIndex, int count, CompareOptions options, int expected) { @@ -225,9 +251,9 @@ private static void IndexOf_Char(CompareInfo compareInfo, string source, char va [Fact] public void IndexOf_UnassignedUnicode() { - bool isWindows = PlatformDetection.IsWindows; - IndexOf_String(s_invariantCompare, "FooBar", "Foo\uFFFFBar", 0, 6, CompareOptions.None, isWindows ? 0 : -1); - IndexOf_String(s_invariantCompare, "~FooBar", "Foo\uFFFFBar", 0, 7, CompareOptions.IgnoreNonSpace, isWindows ? 1 : -1); + bool useNls = PlatformDetection.IsNlsGlobalization; + IndexOf_String(s_invariantCompare, "FooBar", "Foo\uFFFFBar", 0, 6, CompareOptions.None, useNls ? 0 : -1); + IndexOf_String(s_invariantCompare, "~FooBar", "Foo\uFFFFBar", 0, 7, CompareOptions.IgnoreNonSpace, useNls ? 1 : -1); } [Fact] @@ -331,14 +357,11 @@ public void IndexOf_Invalid() AssertExtensions.Throws("count", () => s_invariantCompare.IndexOf("Test", 'a', 2, 4, CompareOptions.None)); } - [Fact] - public static void IndexOf_MinusOneCompatability() + // Attempts to create a Rune from the entirety of a given text buffer. + private static bool TryCreateRuneFrom(ReadOnlySpan text, out Rune value) { - // This behavior was for .NET Framework 1.1 compatability. - // Allowing empty source strings with invalid offsets was quickly outed. - // with invalid offsets. - Assert.Equal(0, s_invariantCompare.IndexOf("", "", -1, CompareOptions.None)); - Assert.Equal(-1, s_invariantCompare.IndexOf("", "a", -1, CompareOptions.None)); + return Rune.DecodeFromUtf16(text, out value, out int charsConsumed) == OperationStatus.Done + && charsConsumed == text.Length; } } } diff --git a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.IsPrefix.cs b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.IsPrefix.cs index a9a93c5093468b..0d32af1f345b93 100644 --- a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.IsPrefix.cs +++ b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.IsPrefix.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Buffers; using System.Collections.Generic; using Xunit; @@ -56,6 +57,9 @@ public static IEnumerable IsPrefix_TestData() yield return new object[] { s_invariantCompare, "o\u0308", "o", CompareOptions.Ordinal, true }; yield return new object[] { s_invariantCompare, "o\u0000\u0308", "o", CompareOptions.None, true }; + // Weightless comparisons + yield return new object[] { s_invariantCompare, "", "\u200d", CompareOptions.None, true }; + // Surrogates yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uD800\uDC00", CompareOptions.None, true }; yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uD800\uDC00", CompareOptions.IgnoreCase, true }; @@ -71,15 +75,16 @@ public static IEnumerable IsPrefix_TestData() yield return new object[] { s_invariantCompare, "Test's can be interesting", "Tests", CompareOptions.None, false }; // Platform differences - yield return new object[] { s_hungarianCompare, "dzsdzsfoobar", "ddzsf", CompareOptions.None, PlatformDetection.IsWindows ? true : false }; - yield return new object[] { s_invariantCompare, "''Tests", "Tests", CompareOptions.IgnoreSymbols, PlatformDetection.IsWindows ? true : false }; - yield return new object[] { s_frenchCompare, "\u0153", "oe", CompareOptions.None, PlatformDetection.IsWindows ? true : false }; - yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uD800", CompareOptions.None, PlatformDetection.IsWindows ? true : false }; - yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uD800", CompareOptions.IgnoreCase, PlatformDetection.IsWindows ? true : false }; + bool useNls = PlatformDetection.IsNlsGlobalization; + yield return new object[] { s_hungarianCompare, "dzsdzsfoobar", "ddzsf", CompareOptions.None, useNls ? true : false }; + yield return new object[] { s_invariantCompare, "''Tests", "Tests", CompareOptions.IgnoreSymbols, useNls ? true : false }; + yield return new object[] { s_frenchCompare, "\u0153", "oe", CompareOptions.None, useNls ? true : false }; + yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uD800", CompareOptions.None, useNls ? true : false }; + yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uD800", CompareOptions.IgnoreCase, useNls ? true : false }; // ICU bugs // UInt16 overflow: https://unicode-org.atlassian.net/browse/ICU-20832 fixed in https://github.com/unicode-org/icu/pull/840 (ICU 65) - if (PlatformDetection.IsWindows || PlatformDetection.ICUVersion.Major >= 65) + if (useNls || PlatformDetection.ICUVersion.Major >= 65) { yield return new object[] { s_frenchCompare, "b", new string('a', UInt16.MaxValue + 1), CompareOptions.None, false }; } @@ -101,12 +106,22 @@ public void IsPrefix(CompareInfo compareInfo, string source, string value, Compa Assert.Equal(expected, source.StartsWith(value, stringComparison)); Assert.Equal(expected, source.AsSpan().StartsWith(value.AsSpan(), stringComparison)); } + + // Now test the span version - use BoundedMemory to detect buffer overruns + + using BoundedMemory sourceBoundedMemory = BoundedMemory.AllocateFromExistingData(source); + sourceBoundedMemory.MakeReadonly(); + + using BoundedMemory valueBoundedMemory = BoundedMemory.AllocateFromExistingData(value); + valueBoundedMemory.MakeReadonly(); + + Assert.Equal(expected, compareInfo.IsPrefix(sourceBoundedMemory.Span, valueBoundedMemory.Span, options)); } [Fact] public void IsPrefix_UnassignedUnicode() { - bool result = PlatformDetection.IsWindows ? true : false; + bool result = PlatformDetection.IsNlsGlobalization ? true : false; IsPrefix(s_invariantCompare, "FooBar", "Foo\uFFFFBar", CompareOptions.None, result); IsPrefix(s_invariantCompare, "FooBar", "Foo\uFFFFBar", CompareOptions.IgnoreNonSpace, result); } diff --git a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.IsSuffix.cs b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.IsSuffix.cs index 3d920dd917855f..05eb588720f221 100644 --- a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.IsSuffix.cs +++ b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.IsSuffix.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Buffers; using System.Collections.Generic; using Xunit; @@ -63,6 +64,9 @@ public static IEnumerable IsSuffix_TestData() yield return new object[] { s_invariantCompare, "o\u0308o", "o", CompareOptions.None, true }; yield return new object[] { s_invariantCompare, "o\u0308o", "o", CompareOptions.Ordinal, true }; + // Weightless comparisons + yield return new object[] { s_invariantCompare, "", "\u200d", CompareOptions.None, true }; + // Surrogates yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uD800\uDC00", CompareOptions.None, true }; yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uD800\uDC00", CompareOptions.IgnoreCase, true }; @@ -82,10 +86,10 @@ public static IEnumerable IsSuffix_TestData() yield return new object[] { s_invariantCompare, "a\u0000b", "b\u0000b", CompareOptions.None, false }; // Platform differences - yield return new object[] { s_hungarianCompare, "foobardzsdzs", "rddzs", CompareOptions.None, PlatformDetection.IsWindows ? true : false }; - yield return new object[] { s_frenchCompare, "\u0153", "oe", CompareOptions.None, PlatformDetection.IsWindows ? true : false }; - yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uDC00", CompareOptions.None, PlatformDetection.IsWindows ? true : false }; - yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uDC00", CompareOptions.IgnoreCase, PlatformDetection.IsWindows ? true : false }; + yield return new object[] { s_hungarianCompare, "foobardzsdzs", "rddzs", CompareOptions.None, PlatformDetection.IsIcuGlobalization ? false : true }; + yield return new object[] { s_frenchCompare, "\u0153", "oe", CompareOptions.None, PlatformDetection.IsIcuGlobalization ? false : true }; + yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uDC00", CompareOptions.None, PlatformDetection.IsIcuGlobalization ? false : true }; + yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uDC00", CompareOptions.IgnoreCase, PlatformDetection.IsIcuGlobalization ? false : true }; } [Theory] @@ -104,12 +108,22 @@ public void IsSuffix(CompareInfo compareInfo, string source, string value, Compa Assert.Equal(expected, source.EndsWith(value, stringComparison)); Assert.Equal(expected, source.AsSpan().EndsWith(value.AsSpan(), stringComparison)); } + + // Now test the span version - use BoundedMemory to detect buffer overruns + + using BoundedMemory sourceBoundedMemory = BoundedMemory.AllocateFromExistingData(source); + sourceBoundedMemory.MakeReadonly(); + + using BoundedMemory valueBoundedMemory = BoundedMemory.AllocateFromExistingData(value); + valueBoundedMemory.MakeReadonly(); + + Assert.Equal(expected, compareInfo.IsSuffix(sourceBoundedMemory.Span, valueBoundedMemory.Span, options)); } [Fact] public void IsSuffix_UnassignedUnicode() { - bool result = PlatformDetection.IsWindows ? true : false; + bool result = PlatformDetection.IsIcuGlobalization ? false : true; IsSuffix(s_invariantCompare, "FooBar", "Foo\uFFFFBar", CompareOptions.None, result); IsSuffix(s_invariantCompare, "FooBar", "Foo\uFFFFBar", CompareOptions.IgnoreNonSpace, result); diff --git a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.LastIndexOf.cs b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.LastIndexOf.cs index 4d0474e7d4a7b6..38bb08b1904417 100644 --- a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.LastIndexOf.cs +++ b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.LastIndexOf.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Buffers; using System.Collections.Generic; +using System.Text; using Xunit; namespace System.Globalization.Tests @@ -16,6 +18,8 @@ public class CompareInfoLastIndexOfTests public static IEnumerable LastIndexOf_TestData() { + bool useNls = PlatformDetection.IsNlsGlobalization; + // Empty strings yield return new object[] { s_invariantCompare, "foo", "", 2, 3, CompareOptions.None, 3 }; yield return new object[] { s_invariantCompare, "", "", 0, 0, CompareOptions.None, 0 }; @@ -75,32 +79,39 @@ public static IEnumerable LastIndexOf_TestData() yield return new object[] { s_invariantCompare, "TestFooBA\u0300R", "FooB\u00C0R", 10, 11, CompareOptions.IgnoreNonSpace, 4 }; yield return new object[] { s_invariantCompare, "o\u0308", "o", 1, 2, CompareOptions.None, -1 }; + // Weightless characters + // NLS matches weightless characters at the end of the string + // ICU matches weightless characters at 1 index prior to the end of the string + yield return new object[] { s_invariantCompare, "", "\u200d", 0, 0, CompareOptions.None, 0 }; + yield return new object[] { s_invariantCompare, "", "\u200d", -1, 0, CompareOptions.None, 0 }; + yield return new object[] { s_invariantCompare, "hello", "\u200d", 4, 5, CompareOptions.IgnoreCase, useNls ? 5 : 4 }; + // Ignore symbols yield return new object[] { s_invariantCompare, "More Test's", "Tests", 10, 11, CompareOptions.IgnoreSymbols, 5 }; yield return new object[] { s_invariantCompare, "More Test's", "Tests", 10, 11, CompareOptions.None, -1 }; yield return new object[] { s_invariantCompare, "cbabababdbaba", "ab", 12, 13, CompareOptions.None, 10 }; // Platform differences - yield return new object[] { s_hungarianCompare, "foobardzsdzs", "rddzs", 11, 12, CompareOptions.None, PlatformDetection.IsWindows ? 5 : -1 }; + yield return new object[] { s_hungarianCompare, "foobardzsdzs", "rddzs", 11, 12, CompareOptions.None, PlatformDetection.IsNlsGlobalization ? 5 : -1 }; } public static IEnumerable LastIndexOf_Aesc_Ligature_TestData() { - bool isWindows = PlatformDetection.IsWindows; + bool useNls = PlatformDetection.IsNlsGlobalization; // Searches for the ligature \u00C6 string source = "Is AE or ae the same as \u00C6 or \u00E6?"; - yield return new object[] { s_invariantCompare, source, "AE", 25, 18, CompareOptions.None, isWindows ? 24 : -1 }; + yield return new object[] { s_invariantCompare, source, "AE", 25, 18, CompareOptions.None, useNls ? 24 : -1 }; yield return new object[] { s_invariantCompare, source, "ae", 25, 18, CompareOptions.None, 9 }; yield return new object[] { s_invariantCompare, source, '\u00C6', 25, 18, CompareOptions.None, 24 }; - yield return new object[] { s_invariantCompare, source, '\u00E6', 25, 18, CompareOptions.None, isWindows ? 9 : -1 }; + yield return new object[] { s_invariantCompare, source, '\u00E6', 25, 18, CompareOptions.None, useNls ? 9 : -1 }; yield return new object[] { s_invariantCompare, source, "AE", 25, 18, CompareOptions.Ordinal, -1 }; yield return new object[] { s_invariantCompare, source, "ae", 25, 18, CompareOptions.Ordinal, 9 }; yield return new object[] { s_invariantCompare, source, '\u00C6', 25, 18, CompareOptions.Ordinal, 24 }; yield return new object[] { s_invariantCompare, source, '\u00E6', 25, 18, CompareOptions.Ordinal, -1 }; - yield return new object[] { s_invariantCompare, source, "AE", 25, 18, CompareOptions.IgnoreCase, isWindows ? 24 : 9 }; - yield return new object[] { s_invariantCompare, source, "ae", 25, 18, CompareOptions.IgnoreCase, isWindows ? 24 : 9 }; + yield return new object[] { s_invariantCompare, source, "AE", 25, 18, CompareOptions.IgnoreCase, useNls ? 24 : 9 }; + yield return new object[] { s_invariantCompare, source, "ae", 25, 18, CompareOptions.IgnoreCase, useNls ? 24 : 9 }; yield return new object[] { s_invariantCompare, source, '\u00C6', 25, 18, CompareOptions.IgnoreCase, 24 }; yield return new object[] { s_invariantCompare, source, '\u00E6', 25, 18, CompareOptions.IgnoreCase, 24 }; } @@ -193,6 +204,26 @@ public void LastIndexOf_String(CompareInfo compareInfo, string source, string va // Use int MemoryExtensions.LastIndexOf(this ReadOnlySpan, ReadOnlySpan, StringComparison) Assert.Equal(expected - adjustmentFactor, sourceSpan.LastIndexOf(value.AsSpan(), stringComparison)); } + + // Now test the span-based versions - use BoundedMemory to detect buffer overruns + + RunSpanLastIndexOfTest(compareInfo, sourceSpan, value, options, expected - adjustmentFactor); + + static void RunSpanLastIndexOfTest(CompareInfo compareInfo, ReadOnlySpan source, ReadOnlySpan value, CompareOptions options, int expected) + { + using BoundedMemory sourceBoundedMemory = BoundedMemory.AllocateFromExistingData(source); + sourceBoundedMemory.MakeReadonly(); + + using BoundedMemory valueBoundedMemory = BoundedMemory.AllocateFromExistingData(value); + valueBoundedMemory.MakeReadonly(); + + Assert.Equal(expected, compareInfo.LastIndexOf(sourceBoundedMemory.Span, valueBoundedMemory.Span, options)); + + if (TryCreateRuneFrom(value, out Rune rune)) + { + Assert.Equal(expected, compareInfo.LastIndexOf(sourceBoundedMemory.Span, rune, options)); // try the Rune-based version + } + } } private static void LastIndexOf_Char(CompareInfo compareInfo, string source, char value, int startIndex, int count, CompareOptions options, int expected) @@ -233,9 +264,9 @@ public void LastIndexOf_Aesc_Ligature(CompareInfo compareInfo, string source, st [Fact] public void LastIndexOf_UnassignedUnicode() { - bool isWindows = PlatformDetection.IsWindows; - LastIndexOf_String(s_invariantCompare, "FooBar", "Foo\uFFFFBar", 5, 6, CompareOptions.None, isWindows ? 0 : -1); - LastIndexOf_String(s_invariantCompare, "~FooBar", "Foo\uFFFFBar", 6, 7, CompareOptions.IgnoreNonSpace, isWindows ? 1 : -1); + bool useNls = PlatformDetection.IsNlsGlobalization; + LastIndexOf_String(s_invariantCompare, "FooBar", "Foo\uFFFFBar", 5, 6, CompareOptions.None, useNls ? 0 : -1); + LastIndexOf_String(s_invariantCompare, "~FooBar", "Foo\uFFFFBar", 6, 7, CompareOptions.IgnoreNonSpace, useNls ? 1 : -1); } [Fact] @@ -271,38 +302,38 @@ public void LastIndexOf_Invalid() // Options are invalid AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", CompareOptions.StringSort)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, CompareOptions.StringSort)); - AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, 2, CompareOptions.StringSort)); + AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, 1, CompareOptions.StringSort)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', CompareOptions.StringSort)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, CompareOptions.StringSort)); - AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, 2, CompareOptions.StringSort)); + AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, 1, CompareOptions.StringSort)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", CompareOptions.Ordinal | CompareOptions.IgnoreWidth)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, CompareOptions.Ordinal | CompareOptions.IgnoreWidth)); - AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, 2, CompareOptions.Ordinal | CompareOptions.IgnoreWidth)); + AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, 1, CompareOptions.Ordinal | CompareOptions.IgnoreWidth)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', CompareOptions.Ordinal | CompareOptions.IgnoreWidth)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, CompareOptions.Ordinal | CompareOptions.IgnoreWidth)); - AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, 2, CompareOptions.Ordinal | CompareOptions.IgnoreWidth)); + AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, 1, CompareOptions.Ordinal | CompareOptions.IgnoreWidth)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", CompareOptions.OrdinalIgnoreCase | CompareOptions.IgnoreWidth)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, CompareOptions.OrdinalIgnoreCase | CompareOptions.IgnoreWidth)); - AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, 2, CompareOptions.OrdinalIgnoreCase | CompareOptions.IgnoreWidth)); + AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, 1, CompareOptions.OrdinalIgnoreCase | CompareOptions.IgnoreWidth)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', CompareOptions.OrdinalIgnoreCase | CompareOptions.IgnoreWidth)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, CompareOptions.OrdinalIgnoreCase | CompareOptions.IgnoreWidth)); - AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, 2, CompareOptions.OrdinalIgnoreCase | CompareOptions.IgnoreWidth)); + AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, 1, CompareOptions.OrdinalIgnoreCase | CompareOptions.IgnoreWidth)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", (CompareOptions)(-1))); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, (CompareOptions)(-1))); - AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, 2, (CompareOptions)(-1))); + AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, 1, (CompareOptions)(-1))); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", (CompareOptions)(-1))); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, (CompareOptions)(-1))); - AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, 2, (CompareOptions)(-1))); + AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, 1, (CompareOptions)(-1))); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", (CompareOptions)0x11111111)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, (CompareOptions)0x11111111)); - AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, 2, (CompareOptions)0x11111111)); + AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", "Tests", 0, 1, (CompareOptions)0x11111111)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', (CompareOptions)0x11111111)); AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, (CompareOptions)0x11111111)); - AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, 2, (CompareOptions)0x11111111)); + AssertExtensions.Throws("options", () => s_invariantCompare.LastIndexOf("Test's", 'a', 0, 1, (CompareOptions)0x11111111)); // StartIndex < 0 AssertExtensions.Throws("startIndex", () => s_invariantCompare.LastIndexOf("Test", "Test", -1, CompareOptions.None)); @@ -350,6 +381,19 @@ public void LastIndexOf_Invalid() AssertExtensions.Throws("count", () => s_invariantCompare.LastIndexOf("Test", "s", 4, 7, CompareOptions.None)); AssertExtensions.Throws("count", () => s_invariantCompare.LastIndexOf("Test", 's', 4, 6)); AssertExtensions.Throws("count", () => s_invariantCompare.LastIndexOf("Test", 's', 4, 7, CompareOptions.None)); + + // Count > StartIndex + 1 + AssertExtensions.Throws("count", () => s_invariantCompare.LastIndexOf("Test", "e", 1, 3)); + AssertExtensions.Throws("count", () => s_invariantCompare.LastIndexOf("Test", "e", 1, 3, CompareOptions.None)); + AssertExtensions.Throws("count", () => s_invariantCompare.LastIndexOf("Test", 'e', 1, 3)); + AssertExtensions.Throws("count", () => s_invariantCompare.LastIndexOf("Test", 'e', 1, 3, CompareOptions.None)); + } + + // Attempts to create a Rune from the entirety of a given text buffer. + private static bool TryCreateRuneFrom(ReadOnlySpan text, out Rune value) + { + return Rune.DecodeFromUtf16(text, out value, out int charsConsumed) == OperationStatus.Done + && charsConsumed == text.Length; } } } diff --git a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.cs b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.cs index b83073a76f98a2..f2f3a0b2e45d87 100644 --- a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.cs +++ b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.cs @@ -2,8 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Buffers; using System.Collections.Generic; using System.Reflection; +using System.Text; using Xunit; namespace System.Globalization.Tests @@ -95,15 +97,16 @@ public static IEnumerable CompareInfo_TestData() yield return new object[] { "tr-TR" , 0x041f }; } - // On Windows, hiragana characters sort after katakana. + // On NLS, hiragana characters sort after katakana. // On ICU, it is the opposite - private static int s_expectedHiraganaToKatakanaCompare = PlatformDetection.IsWindows ? 1 : -1; + private static int s_expectedHiraganaToKatakanaCompare = PlatformDetection.IsNlsGlobalization ? 1 : -1; - // On Windows, all halfwidth characters sort before fullwidth characters. + // On NLS, all halfwidth characters sort before fullwidth characters. // On ICU, half and fullwidth characters that aren't in the "Halfwidth and fullwidth forms" block U+FF00-U+FFEF // sort before the corresponding characters that are in the block U+FF00-U+FFEF - private static int s_expectedHalfToFullFormsComparison = PlatformDetection.IsWindows ? -1 : 1; + private static int s_expectedHalfToFullFormsComparison = PlatformDetection.IsNlsGlobalization ? -1 : 1; + private static CompareInfo s_hungarianCompare = new CultureInfo("hu-HU").CompareInfo; private static CompareInfo s_invariantCompare = CultureInfo.InvariantCulture.CompareInfo; private static CompareInfo s_turkishCompare = new CultureInfo("tr-TR").CompareInfo; @@ -373,6 +376,33 @@ public void SortKeyTest(CompareInfo compareInfo, string string1, string string2, Assert.Equal(string1, sk1.OriginalString); Assert.Equal(string2, sk2.OriginalString); + + // Now try the span-based versions - use BoundedMemory to detect buffer overruns + + RunSpanSortKeyTest(compareInfo, string1, options, sk1.KeyData); + RunSpanSortKeyTest(compareInfo, string2, options, sk2.KeyData); + + unsafe static void RunSpanSortKeyTest(CompareInfo compareInfo, ReadOnlySpan source, CompareOptions options, byte[] expectedSortKey) + { + using BoundedMemory sourceBoundedMemory = BoundedMemory.AllocateFromExistingData(source); + sourceBoundedMemory.MakeReadonly(); + + Assert.Equal(expectedSortKey.Length, compareInfo.GetSortKeyLength(sourceBoundedMemory.Span, options)); + + using BoundedMemory sortKeyBoundedMemory = BoundedMemory.Allocate(expectedSortKey.Length); + + // First try with a destination which is too small - should result in an error + + Assert.Throws("destination", () => compareInfo.GetSortKey(sourceBoundedMemory.Span, sortKeyBoundedMemory.Span.Slice(1), options)); + + // Next, try with a destination which is perfectly sized - should succeed + + Span sortKeyBoundedSpan = sortKeyBoundedMemory.Span; + sortKeyBoundedSpan.Clear(); + + Assert.Equal(expectedSortKey.Length, compareInfo.GetSortKey(sourceBoundedMemory.Span, sortKeyBoundedSpan, options)); + Assert.Equal(expectedSortKey, sortKeyBoundedSpan[0..expectedSortKey.Length].ToArray()); + } } [Fact] @@ -436,6 +466,12 @@ public void IsSortableTest(object sourceObj, bool expected) string source = sourceObj as string ?? new string((char[])sourceObj); Assert.Equal(expected, CompareInfo.IsSortable(source)); + // Now test the span version - use BoundedMemory to detect buffer overruns + + using BoundedMemory sourceBoundedMemory = BoundedMemory.AllocateFromExistingData(source); + sourceBoundedMemory.MakeReadonly(); + Assert.Equal(expected, CompareInfo.IsSortable(sourceBoundedMemory.Span)); + // If the string as a whole is sortable, then all chars which aren't standalone // surrogate halves must also be sortable. diff --git a/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoAll.cs b/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoAll.cs index 028cf71e49780a..cf40173884bd6d 100644 --- a/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoAll.cs +++ b/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoAll.cs @@ -14,9 +14,9 @@ namespace System.Globalization.Tests { public class CultureInfoAll { - [Fact] [PlatformSpecific(TestPlatforms.Windows)] // P/Invoke to Win32 function - public void TestAllCultures() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] + public void TestAllCultures_Nls() { Assert.True(EnumSystemLocalesEx(EnumLocales, LOCALE_WINDOWS, IntPtr.Zero, IntPtr.Zero), "EnumSystemLocalesEx has failed"); diff --git a/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoData.cs b/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoData.cs index c8fcdb9de007d6..3d370acb843192 100644 --- a/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoData.cs +++ b/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoData.cs @@ -11,12 +11,12 @@ internal static class DateTimeFormatInfoData { public static string EnUSEraName() { - return PlatformDetection.IsWindows ? "A.D." : "AD"; + return PlatformDetection.IsNlsGlobalization ? "A.D." : "AD"; } public static string EnUSAbbreviatedEraName() { - return PlatformDetection.IsWindows ? "AD" : "A"; + return PlatformDetection.IsNlsGlobalization ? "AD" : "A"; } public static string JaJPAbbreviatedEraName() @@ -24,12 +24,12 @@ public static string JaJPAbbreviatedEraName() // For Windows(() => DateTimeFormatInfo.InvariantInfo.LongTimePattern = "HH:mm:ss"); } - [Fact] - [PlatformSpecific(TestPlatforms.AnyUnix)] - public void LongTimePattern_CheckReadingTimeFormatWithSingleQuotes() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))] + public void LongTimePattern_CheckReadingTimeFormatWithSingleQuotes_ICU() { // Usually fr-CA long time format has a single quotes e.g. "HH 'h' mm 'min' ss 's'". // Ensuring when reading such formats from ICU we'll not eat the spaces after the single quotes. diff --git a/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoShortDatePattern.cs b/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoShortDatePattern.cs index 4e67e1dcc7b08b..b0dcb3705f26c1 100644 --- a/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoShortDatePattern.cs +++ b/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoShortDatePattern.cs @@ -33,6 +33,21 @@ public void ShortDatePattern_Set_GetReturnsExpected(string value) Assert.Equal(value, format.ShortDatePattern); } + [Fact] + public void ShortDatePattern_Set_InvalidatesDerivedPatterns() + { + const string Pattern = "#$"; + var format = new DateTimeFormatInfo(); + var d = DateTimeOffset.Now; + d.ToString("G", format); // GeneralLongTimePattern + d.ToString("g", format); // GeneralShortTimePattern + d.ToString(format); // DateTimeOffsetPattern + format.ShortDatePattern = Pattern; + Assert.Contains(Pattern, d.ToString("G", format)); + Assert.Contains(Pattern, d.ToString("g", format)); + Assert.Contains(Pattern, d.ToString(format)); + } + [Fact] public void ShortDatePattern_SetNullValue_ThrowsArgumentNullException() { diff --git a/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoShortTimePattern.cs b/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoShortTimePattern.cs index bcea88b745296b..8c87f92ae81fa6 100644 --- a/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoShortTimePattern.cs +++ b/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoShortTimePattern.cs @@ -33,6 +33,17 @@ public void ShortTimePattern_Set_GetReturnsExpected(string value) Assert.Equal(value, format.ShortTimePattern); } + [Fact] + public void ShortTimePattern_Set_InvalidatesDerivedPattern() + { + const string Pattern = "#$"; + var format = new DateTimeFormatInfo(); + var d = DateTimeOffset.Now; + d.ToString("g", format); // GeneralShortTimePattern + format.ShortTimePattern = Pattern; + Assert.Contains(Pattern, d.ToString("g", format)); + } + [Fact] public void ShortTimePattern_SetNull_ThrowsArgumentNullException() { diff --git a/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoTests.cs b/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoTests.cs index e8ccf90be063f6..14c5afab100066 100644 --- a/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoTests.cs +++ b/src/libraries/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoTests.cs @@ -71,12 +71,12 @@ public void NativeCalendarName_Get_ReturnsExpected(DateTimeFormatInfo dtfi, Cale } catch { - if (PlatformDetection.IsWindows) + if (PlatformDetection.IsNlsGlobalization) { // Persian calendar is recently supported as one of the optional calendars for fa-IR Assert.True(calendar is PersianCalendar, "Exception can occur only with PersianCalendar"); } - else // !PlatformDetection.IsWindows + else // !PlatformDetection.IsNlsGlobalization { Assert.True(calendar is HijriCalendar || calendar is UmAlQuraCalendar || calendar is ThaiBuddhistCalendar || calendar is HebrewCalendar || calendar is KoreanCalendar, "failed to set the calendar on DTFI"); diff --git a/src/libraries/System.Globalization/tests/IcuTests.cs b/src/libraries/System.Globalization/tests/IcuTests.cs new file mode 100644 index 00000000000000..80533da8fb7d14 --- /dev/null +++ b/src/libraries/System.Globalization/tests/IcuTests.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Reflection; +using Xunit; +using Xunit.Sdk; + +namespace System.Globalization.Tests +{ + public class IcuTests + { + private static bool IsIcuCompatiblePlatform => PlatformDetection.IsNotWindows || + PlatformDetection.IsWindows10Version1903OrGreater; + + [ConditionalFact(nameof(IsIcuCompatiblePlatform))] + public static void IcuShouldBeUsedByDefault() + { + Type globalizationMode = Type.GetType("System.Globalization.GlobalizationMode"); + if (globalizationMode != null) + { + MethodInfo methodInfo = globalizationMode.GetProperty("UseNls", BindingFlags.NonPublic | BindingFlags.Static)?.GetMethod; + if (methodInfo != null) + { + Assert.False((bool)methodInfo.Invoke(null, null)); + return; + } + } + + throw new XunitException("Couldn't get System.Globalization.GlobalizationMode.UseIcu property."); + } + + [ConditionalFact(nameof(IsIcuCompatiblePlatform))] + public static void IcuShouldBeLoaded() + { + Assert.True(PlatformDetection.IsIcuGlobalization); + } + } +} diff --git a/src/libraries/System.Globalization/tests/Invariant/Invariant.Tests.csproj b/src/libraries/System.Globalization/tests/Invariant/Invariant.Tests.csproj index 78f6d5db78181a..1de762de1564b5 100644 --- a/src/libraries/System.Globalization/tests/Invariant/Invariant.Tests.csproj +++ b/src/libraries/System.Globalization/tests/Invariant/Invariant.Tests.csproj @@ -2,6 +2,7 @@ $(NetCoreAppCurrent) true + true diff --git a/src/libraries/System.Globalization/tests/Invariant/InvariantMode.cs b/src/libraries/System.Globalization/tests/Invariant/InvariantMode.cs index d6c7676eb1f805..8012d34ddf2be8 100644 --- a/src/libraries/System.Globalization/tests/Invariant/InvariantMode.cs +++ b/src/libraries/System.Globalization/tests/Invariant/InvariantMode.cs @@ -3,8 +3,10 @@ // See the LICENSE file in the project root for more information. using System.Buffers; +using System.Buffers.Binary; using System.Collections.Generic; -using System.Collections; +using System.IO; +using System.Runtime.InteropServices; using System.Text; using Xunit; @@ -63,6 +65,10 @@ public static IEnumerable IndexOf_TestData() yield return new object[] { "FooBar", "Foo\u0400Bar", 0, 6, CompareOptions.Ordinal, -1 }; yield return new object[] { "TestFooBA\u0300R", "FooB\u00C0R", 0, 11, CompareOptions.IgnoreNonSpace, -1 }; + // Weightless characters + yield return new object[] { "", "\u200d", 0, 0, CompareOptions.None, -1 }; + yield return new object[] { "hello", "\u200d", 0, 5, CompareOptions.IgnoreCase, -1 }; + // Ignore symbols yield return new object[] { "More Test's", "Tests", 0, 11, CompareOptions.IgnoreSymbols, -1 }; yield return new object[] { "More Test's", "Tests", 0, 11, CompareOptions.None, -1 }; @@ -167,6 +173,11 @@ public static IEnumerable LastIndexOf_TestData() yield return new object[] { "FooBar", "Foo\u0400Bar", 5, 6, CompareOptions.Ordinal, -1 }; yield return new object[] { "TestFooBA\u0300R", "FooB\u00C0R", 10, 11, CompareOptions.IgnoreNonSpace, -1 }; + // Weightless characters + yield return new object[] { "", "\u200d", 0, 0, CompareOptions.None, -1 }; + yield return new object[] { "", "\u200d", -1, 0, CompareOptions.None, -1 }; + yield return new object[] { "hello", "\u200d", 4, 5, CompareOptions.IgnoreCase, -1 }; + // Ignore symbols yield return new object[] { "More Test's", "Tests", 10, 11, CompareOptions.IgnoreSymbols, -1 }; yield return new object[] { "More Test's", "Tests", 10, 11, CompareOptions.None, -1 }; @@ -249,6 +260,10 @@ public static IEnumerable IsSuffix_TestData() yield return new object[] { "FooBar", "Foo\u0400Bar", CompareOptions.Ordinal, false }; yield return new object[] { "FooBA\u0300R", "FooB\u00C0R", CompareOptions.IgnoreNonSpace, false }; + // Weightless characters + yield return new object[] { "", "\u200d", CompareOptions.None, false }; + yield return new object[] { "", "\u200d", CompareOptions.IgnoreCase, false }; + // Ignore symbols yield return new object[] { "More Test's", "Tests", CompareOptions.IgnoreSymbols, false }; yield return new object[] { "More Test's", "Tests", CompareOptions.None, false }; @@ -476,6 +491,12 @@ public static IEnumerable GetUnicode_TestData() yield return new object[] { "xn--de-jg4avhby1noc0d", 0, 21, "\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0" }; } + [Fact] + public static void IcuShouldNotBeLoaded() + { + Assert.False(PlatformDetection.IsIcuGlobalization); + } + [Theory] [MemberData(nameof(Cultures_TestData))] public void TestCultureData(string cultureName) @@ -634,6 +655,77 @@ public void TestSortVersion(string cultureName) Assert.Equal(version, new CultureInfo(cultureName).CompareInfo.Version); } + [Theory] + [InlineData(0, 0)] + [InlineData(1, 2)] + [InlineData(100_000, 200_000)] + [InlineData(0x3FFF_FFFF, 0x7FFF_FFFE)] + public void TestGetSortKeyLength_Valid(int inputLength, int expectedSortKeyLength) + { + using BoundedMemory boundedMemory = BoundedMemory.Allocate(0); // AV if dereferenced + boundedMemory.MakeReadonly(); + ReadOnlySpan dummySpan = MemoryMarshal.CreateReadOnlySpan(ref MemoryMarshal.GetReference(boundedMemory.Span), inputLength); + Assert.Equal(expectedSortKeyLength, CultureInfo.InvariantCulture.CompareInfo.GetSortKeyLength(dummySpan)); + } + + [Theory] + [InlineData(0x4000_0000)] + [InlineData(int.MaxValue)] + public unsafe void TestGetSortKeyLength_OverlongArgument(int inputLength) + { + using BoundedMemory boundedMemory = BoundedMemory.Allocate(0); // AV if dereferenced + boundedMemory.MakeReadonly(); + + Assert.Throws("source", () => + { + ReadOnlySpan dummySpan = MemoryMarshal.CreateReadOnlySpan(ref MemoryMarshal.GetReference(boundedMemory.Span), inputLength); + CultureInfo.InvariantCulture.CompareInfo.GetSortKeyLength(dummySpan); + }); + } + + [Theory] + [InlineData("Hello", CompareOptions.None, "Hello")] + [InlineData("Hello", CompareOptions.IgnoreWidth, "Hello")] + [InlineData("Hello", CompareOptions.IgnoreCase, "HELLO")] + [InlineData("Hello", CompareOptions.IgnoreCase | CompareOptions.IgnoreWidth, "HELLO")] + [InlineData("Hell\u00F6", CompareOptions.None, "Hell\u00F6")] // U+00F6 = LATIN SMALL LETTER O WITH DIAERESIS + [InlineData("Hell\u00F6", CompareOptions.IgnoreCase, "HELL\u00F6")] // note the final "o with diaeresis" isn't capitalized + public unsafe void TestSortKey_FromSpan(string input, CompareOptions options, string expected) + { + byte[] expectedOutputBytes = GetExpectedInvariantOrdinalSortKey(expected); + + CompareInfo compareInfo = CultureInfo.InvariantCulture.CompareInfo; + + // First, validate that too short a buffer throws + + Assert.Throws("destination", () => compareInfo.GetSortKey(input, new byte[expectedOutputBytes.Length - 1], options)); + + // Next, validate that using a properly-sized buffer succeeds + // We'll use BoundedMemory to check for buffer overruns + + using BoundedMemory boundedInputMemory = BoundedMemory.AllocateFromExistingData(input); + boundedInputMemory.MakeReadonly(); + ReadOnlySpan boundedInputSpan = boundedInputMemory.Span; + + using BoundedMemory boundedOutputMemory = BoundedMemory.Allocate(expectedOutputBytes.Length); + Span boundedOutputSpan = boundedOutputMemory.Span; + + Assert.Equal(expectedOutputBytes.Length, compareInfo.GetSortKey(boundedInputSpan, boundedOutputSpan, options)); + Assert.Equal(expectedOutputBytes, boundedOutputSpan[0..expectedOutputBytes.Length].ToArray()); + + // Now try it once more, passing a larger span where the last byte points to unallocated memory. + // If GetSortKey attempts to write beyond the number of bytes we expect, the unit test will AV. + + boundedOutputSpan.Clear(); + + fixed (byte* pBoundedOutputSpan = boundedOutputSpan) + { + boundedOutputSpan = new Span(pBoundedOutputSpan, boundedOutputSpan.Length + 1); // last byte is unallocated memory + Assert.Equal(expectedOutputBytes.Length, compareInfo.GetSortKey(boundedInputSpan, boundedOutputSpan, options)); + Assert.Equal(expectedOutputBytes, boundedOutputSpan[0..expectedOutputBytes.Length].ToArray()); + } + } + [Fact] public void TestSortKey_ZeroWeightCodePoints() { @@ -767,6 +859,7 @@ public void TestIsSuffix(string source, string value, CompareOptions options, bo valueBoundedMemory.MakeReadonly(); ReadOnlySpan valueBoundedSpan = valueBoundedMemory.Span; + Assert.Equal(result, CultureInfo.GetCultureInfo(cul).CompareInfo.IsSuffix(sourceBoundedSpan, valueBoundedSpan, options)); Assert.Equal(result, sourceBoundedSpan.EndsWith(valueBoundedSpan, GetStringComparison(options))); } } @@ -810,6 +903,9 @@ public void TestCompare(string source, string value, CompareOptions options, int valueBoundedMemory.MakeReadonly(); ReadOnlySpan valueBoundedSpan = valueBoundedMemory.Span; + res = CultureInfo.GetCultureInfo(cul).CompareInfo.Compare(sourceBoundedSpan, valueBoundedSpan, options); + Assert.Equal(result, Math.Sign(res)); + res = sourceBoundedSpan.CompareTo(valueBoundedSpan, GetStringComparison(options)); Assert.Equal(result, Math.Sign(res)); } @@ -917,5 +1013,19 @@ public void TestRune(int original, int expectedToUpper, int expectedToLower) Assert.Equal(expectedToLower, Rune.ToLowerInvariant(originalRune).Value); Assert.Equal(expectedToLower, Rune.ToLower(originalRune, CultureInfo.GetCultureInfo("tr-TR")).Value); } + + private static byte[] GetExpectedInvariantOrdinalSortKey(ReadOnlySpan input) + { + MemoryStream memoryStream = new MemoryStream(); + Span tempBuffer = stackalloc byte[sizeof(char)]; + + foreach (char ch in input) + { + BinaryPrimitives.WriteUInt16BigEndian(tempBuffer, (ushort)ch); + memoryStream.Write(tempBuffer); + } + + return memoryStream.ToArray(); + } } } diff --git a/src/libraries/System.Globalization/tests/NlsTests/NlsSwitchTests.cs b/src/libraries/System.Globalization/tests/NlsTests/NlsSwitchTests.cs new file mode 100644 index 00000000000000..58da0a9dae525f --- /dev/null +++ b/src/libraries/System.Globalization/tests/NlsTests/NlsSwitchTests.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Reflection; +using Xunit; +using Xunit.Sdk; + +namespace System.Globalization.Tests +{ + public class NlsSwitchTests + { + [Fact] + public static void NlsRuntimeSwitchIsHonored() + { + Type globalizationMode = Type.GetType("System.Globalization.GlobalizationMode"); + if (globalizationMode != null) + { + MethodInfo methodInfo = globalizationMode.GetProperty("UseNls", BindingFlags.NonPublic | BindingFlags.Static)?.GetMethod; + if (methodInfo != null) + { + Assert.True((bool)methodInfo.Invoke(null, null)); + return; + } + } + + throw new XunitException("Couldn't get System.Globalization.GlobalizationMode.UseIcu property."); + } + + [Fact] + public static void IcuShouldNotBeLoaded() + { + Assert.False(PlatformDetection.IsIcuGlobalization, $"Found ICU: {PlatformDetection.ICUVersion}"); + } + } +} diff --git a/src/libraries/System.Globalization/tests/NlsTests/System.Globalization.Nls.Tests.csproj b/src/libraries/System.Globalization/tests/NlsTests/System.Globalization.Nls.Tests.csproj new file mode 100644 index 00000000000000..e1c20d97ca766b --- /dev/null +++ b/src/libraries/System.Globalization/tests/NlsTests/System.Globalization.Nls.Tests.csproj @@ -0,0 +1,240 @@ + + + true + true + true + + $(NetCoreAppCurrent)-Windows_NT + 13.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CharUnicodeInfo\UnicodeData.$(UnicodeUcdVersion).txt + UnicodeData.txt + + + CharUnicodeInfo\GraphemeBreakTest-$(UnicodeUcdVersion).0.txt + GraphemeBreakTest.txt + + + + + + + diff --git a/src/libraries/System.Globalization/tests/NlsTests/runtimeconfig.template.json b/src/libraries/System.Globalization/tests/NlsTests/runtimeconfig.template.json new file mode 100644 index 00000000000000..f93c6039127bd1 --- /dev/null +++ b/src/libraries/System.Globalization/tests/NlsTests/runtimeconfig.template.json @@ -0,0 +1,5 @@ +{ + "configProperties": { + "System.Globalization.UseNls": true + } +} diff --git a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoCurrencyDecimalDigits.cs b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoCurrencyDecimalDigits.cs index 475c74f19f77ea..e67bd53a742f3a 100644 --- a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoCurrencyDecimalDigits.cs +++ b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoCurrencyDecimalDigits.cs @@ -18,9 +18,9 @@ public static IEnumerable CurrencyDecimalDigits_TestData() [Theory] [MemberData(nameof(CurrencyDecimalDigits_TestData))] - public void CurrencyDecimalDigits_Get_ReturnsExpected(NumberFormatInfo format, int expectedWindows, int expectedIcu) + public void CurrencyDecimalDigits_Get_ReturnsExpected(NumberFormatInfo format, int expectedNls, int expectedIcu) { - int expected = PlatformDetection.IsWindows ? expectedWindows : expectedIcu; + int expected = PlatformDetection.IsNlsGlobalization ? expectedNls : expectedIcu; Assert.Equal(expected, format.CurrencyDecimalDigits); } diff --git a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoData.cs b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoData.cs index e6500c9741ff05..dfffa504f7f961 100644 --- a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoData.cs +++ b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoData.cs @@ -29,13 +29,13 @@ internal static int[] GetCurrencyNegativePatterns(string localeName) switch (localeName) { case "en-US": - return PlatformDetection.IsWindows ? new int[] { 0 } : new int[] { 1, 0 }; + return PlatformDetection.IsNlsGlobalization ? new int[] { 0 } : new int[] { 1, 0 }; case "en-CA": - return PlatformDetection.IsWindows ? new int[] { 1 } : new int[] { 1, 0 }; + return PlatformDetection.IsNlsGlobalization ? new int[] { 1 } : new int[] { 1, 0 }; case "fa-IR": - if (PlatformDetection.IsWindows) + if (PlatformDetection.IsNlsGlobalization) { return (PlatformDetection.WindowsVersion < 10) ? new int[] { 3 } : new int[] { 6, 3 }; } @@ -53,7 +53,7 @@ internal static int[] GetCurrencyNegativePatterns(string localeName) } case "fr-CD": - if (PlatformDetection.IsWindows) + if (PlatformDetection.IsNlsGlobalization) { return (PlatformDetection.WindowsVersion < 10) ? new int[] { 4 } : new int[] { 8 }; } @@ -63,13 +63,13 @@ internal static int[] GetCurrencyNegativePatterns(string localeName) } case "as": - return PlatformDetection.IsWindows ? new int[] { 12 } : new int[] { 9 }; + return PlatformDetection.IsNlsGlobalization ? new int[] { 12 } : new int[] { 9 }; case "es-BO": - return (PlatformDetection.IsWindows && PlatformDetection.WindowsVersion < 10) ? new int[] { 14 } : new int[] { 1 }; + return (PlatformDetection.IsNlsGlobalization && PlatformDetection.WindowsVersion < 10) ? new int[] { 14 } : new int[] { 1 }; case "fr-CA": - return PlatformDetection.IsWindows ? new int[] { 15 } : new int[] { 8, 15 }; + return PlatformDetection.IsNlsGlobalization ? new int[] { 15 } : new int[] { 8, 15 }; } throw DateTimeFormatInfoData.GetCultureNotSupportedException(CultureInfo.GetCultureInfo(localeName)); diff --git a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoNumberDecimalDigits.cs b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoNumberDecimalDigits.cs index 581c0e8c197536..9902cc6867d380 100644 --- a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoNumberDecimalDigits.cs +++ b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoNumberDecimalDigits.cs @@ -17,9 +17,9 @@ public static IEnumerable NumberDecimalDigits_TestData() [Theory] [MemberData(nameof(NumberDecimalDigits_TestData))] - public void NumberDecimalDigits_Get_ReturnsExpected(NumberFormatInfo format, int expectedWindows, int expectedIcu) + public void NumberDecimalDigits_Get_ReturnsExpected(NumberFormatInfo format, int expectedNls, int expectedIcu) { - int expected = PlatformDetection.IsWindows ? expectedWindows : expectedIcu; + int expected = PlatformDetection.IsNlsGlobalization ? expectedNls : expectedIcu; Assert.Equal(expected, format.NumberDecimalDigits); } diff --git a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoPercentDecimalDigits.cs b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoPercentDecimalDigits.cs index 30741388ba8426..8bbe772d6a22e3 100644 --- a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoPercentDecimalDigits.cs +++ b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoPercentDecimalDigits.cs @@ -2,16 +2,25 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; using Xunit; namespace System.Globalization.Tests { public class NumberFormatInfoPercentDecimalDigits { - [Fact] - public void PercentDecimalDigits_GetInvariantInfo_ReturnsExpected() + public static IEnumerable PercentDecimalDigits_TestData() + { + yield return new object[] { NumberFormatInfo.InvariantInfo, 2, 2 }; + yield return new object[] { CultureInfo.GetCultureInfo("en-US").NumberFormat, 2, 3 }; + } + + [Theory] + [MemberData(nameof(PercentDecimalDigits_TestData))] + public void PercentDecimalDigits_Get_ReturnsExpected(NumberFormatInfo format, int expectedNls, int expectedIcu) { - Assert.Equal(2, NumberFormatInfo.InvariantInfo.PercentDecimalDigits); + int expected = PlatformDetection.IsNlsGlobalization ? expectedNls : expectedIcu; + Assert.Equal(expected, format.PercentDecimalDigits); } [Theory] diff --git a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoPercentNegativePattern.cs b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoPercentNegativePattern.cs index 5bf6adc65e31d4..81fa3d986d0e79 100644 --- a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoPercentNegativePattern.cs +++ b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoPercentNegativePattern.cs @@ -18,15 +18,14 @@ public static IEnumerable PercentNegativePattern_TestData() } /// - /// Not testing for Windows as the culture data can change + /// Not testing for NLS as the culture data can change /// https://blogs.msdn.microsoft.com/shawnste/2005/04/05/culture-data-shouldnt-be-considered-stable-except-for-invariant/ /// In the CultureInfoAll test class we are testing the expected behavior - /// for Windows by enumerating all locales on the system and then test them. + /// for NLS by enumerating all locales on the system and then test them. /// - [Theory] - [PlatformSpecific(TestPlatforms.AnyUnix)] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))] [MemberData(nameof(PercentNegativePattern_TestData))] - public void PercentNegativePattern_Get_ReturnsExpected(NumberFormatInfo format, int expected) + public void PercentNegativePattern_Get_ReturnsExpected_ICU(NumberFormatInfo format, int expected) { Assert.Equal(expected, format.PercentNegativePattern); } diff --git a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoPercentPositivePattern.cs b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoPercentPositivePattern.cs index da028a2521dc35..1dd54259761c94 100644 --- a/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoPercentPositivePattern.cs +++ b/src/libraries/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoPercentPositivePattern.cs @@ -18,15 +18,14 @@ public static IEnumerable PercentPositivePattern_TestData() } /// - /// Not testing for Windows as the culture data can change + /// Not testing for NLS as the culture data can change /// https://blogs.msdn.microsoft.com/shawnste/2005/04/05/culture-data-shouldnt-be-considered-stable-except-for-invariant/ /// In the CultureInfoAll test class we are testing the expected behavior - /// for Windows by enumerating all locales on the system and then test them. + /// for NLS by enumerating all locales on the system and then test them. /// - [Theory] - [PlatformSpecific(TestPlatforms.AnyUnix)] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))] [MemberData(nameof(PercentPositivePattern_TestData))] - public void PercentPositivePattern_Get_ReturnsExpected(NumberFormatInfo format, int expected) + public void PercentPositivePattern_Get_ReturnsExpected_ICU(NumberFormatInfo format, int expected) { Assert.Equal(expected, format.PercentPositivePattern); } diff --git a/src/libraries/System.Globalization/tests/System.Globalization.Tests.csproj b/src/libraries/System.Globalization/tests/System.Globalization.Tests.csproj index be9b72574bcdcc..63be8e88f0066a 100644 --- a/src/libraries/System.Globalization/tests/System.Globalization.Tests.csproj +++ b/src/libraries/System.Globalization/tests/System.Globalization.Tests.csproj @@ -7,6 +7,7 @@ 13.0 + @@ -112,9 +113,8 @@ - - Common\System\RandomDataGenerator.cs - + diff --git a/src/libraries/System.Globalization/tests/System/Globalization/RegionInfoTests.cs b/src/libraries/System.Globalization/tests/System/Globalization/RegionInfoTests.cs index 6ca55371c4822b..be61f291aa8ee6 100644 --- a/src/libraries/System.Globalization/tests/System/Globalization/RegionInfoTests.cs +++ b/src/libraries/System.Globalization/tests/System/Globalization/RegionInfoTests.cs @@ -52,8 +52,9 @@ public void Ctor_InvalidName_ThrowsArgumentException(string name) AssertExtensions.Throws("name", () => new RegionInfo(name)); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows))] - public void CurrentRegion() + [Fact] + [PlatformSpecific(TestPlatforms.AnyUnix)] + public void CurrentRegion_Unix() { using (new ThreadCultureChange("en-US")) { @@ -63,8 +64,9 @@ public void CurrentRegion() } } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))] - public void TestCurrentRegion() + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public void CurrentRegion_Windows() { RemoteExecutor.Invoke(() => { @@ -149,15 +151,15 @@ public void TwoLetterISORegionName(string name, string expected) public static IEnumerable RegionInfo_TestData() { yield return new object[] { 0x409, 244, "US Dollar", "US Dollar", "\u0055\u0053\u0020\u0044\u006f\u006c\u006c\u0061\u0072", "USA", "USA" }; - yield return new object[] { 0x411, 122, "Japanese Yen", "Japanese Yen", PlatformDetection.IsWindows ? "\u5186" : "\u65e5\u672c\u5186", "JPN", "JPN" }; + yield return new object[] { 0x411, 122, "Japanese Yen", "Japanese Yen", PlatformDetection.IsNlsGlobalization ? "\u5186" : "\u65e5\u672c\u5186", "JPN", "JPN" }; yield return new object[] { 0x804, 45, "Chinese Yuan", "PRC Yuan Renminbi", "\u4eba\u6c11\u5e01", "CHN", "CHN" }; - yield return new object[] { 0x401, 205, "Saudi Riyal", "Saudi Riyal", PlatformDetection.IsWindows ? + yield return new object[] { 0x401, 205, "Saudi Riyal", "Saudi Riyal", PlatformDetection.IsNlsGlobalization ? "\u0631\u064a\u0627\u0644\u00a0\u0633\u0639\u0648\u062f\u064a" : "\u0631\u064a\u0627\u0644\u0020\u0633\u0639\u0648\u062f\u064a", "SAU", "SAU" }; - yield return new object[] { 0x412, 134, "South Korean Won", "Korean Won", PlatformDetection.IsWindows ? "\uc6d0" : "\ub300\ud55c\ubbfc\uad6d\u0020\uc6d0", "KOR", "KOR" }; + yield return new object[] { 0x412, 134, "South Korean Won", "Korean Won", PlatformDetection.IsNlsGlobalization ? "\uc6d0" : "\ub300\ud55c\ubbfc\uad6d\u0020\uc6d0", "KOR", "KOR" }; yield return new object[] { 0x40d, 117, "Israeli New Shekel", "Israeli New Sheqel", - PlatformDetection.IsWindows || PlatformDetection.ICUVersion.Major >= 58 ? "\u05e9\u05e7\u05dc\u0020\u05d7\u05d3\u05e9" : "\u05e9\u05f4\u05d7", "ISR", "ISR" }; + PlatformDetection.IsNlsGlobalization || PlatformDetection.ICUVersion.Major >= 58 ? "\u05e9\u05e7\u05dc\u0020\u05d7\u05d3\u05e9" : "\u05e9\u05f4\u05d7", "ISR", "ISR" }; } [Theory] diff --git a/src/libraries/System.IO.Compression.Brotli/src/System.IO.Compression.Brotli.csproj b/src/libraries/System.IO.Compression.Brotli/src/System.IO.Compression.Brotli.csproj index 626ab0f48a792b..418184e291d585 100644 --- a/src/libraries/System.IO.Compression.Brotli/src/System.IO.Compression.Brotli.csproj +++ b/src/libraries/System.IO.Compression.Brotli/src/System.IO.Compression.Brotli.csproj @@ -17,24 +17,20 @@ - - Common\System\Threading\Tasks\TaskToApm.cs - - - Common\Microsoft\Win32\SafeHandles\SafeBrotliHandle.cs - + + - - Common\Interop\Windows\Interop.Libraries.cs - + - - Common\Interop\Unix\Interop.Libraries.cs - + diff --git a/src/libraries/System.IO.Compression.Brotli/tests/System.IO.Compression.Brotli.Tests.csproj b/src/libraries/System.IO.Compression.Brotli/tests/System.IO.Compression.Brotli.Tests.csproj index 6cd5df420f23f9..e4ca77f85bda72 100644 --- a/src/libraries/System.IO.Compression.Brotli/tests/System.IO.Compression.Brotli.Tests.csproj +++ b/src/libraries/System.IO.Compression.Brotli/tests/System.IO.Compression.Brotli.Tests.csproj @@ -6,24 +6,18 @@ - - Common\System\IO\Compression\CompressionStreamTestBase.cs - - - Common\System\IO\Compression\CompressionStreamUnitTestBase.cs - - - Common\System\IO\Compression\LocalMemoryStream.cs - - - Common\System\IO\Compression\StreamHelpers.cs - - - Common\System\IO\TempFile.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - + + + + + + - - Common\System\IO\PathInternal.Windows.cs - - - Common\Interop\Windows\Interop.Libraries.cs - + + - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\System\IO\PathInternal.Unix.cs - - - Common\Interop\Unix\System.Native\Interop.PathConf.cs - + + + diff --git a/src/libraries/System.IO.Compression/tests/System.IO.Compression.Tests.csproj b/src/libraries/System.IO.Compression/tests/System.IO.Compression.Tests.csproj index 20bb882a1b9626..b2c7ef176fd6e9 100644 --- a/src/libraries/System.IO.Compression/tests/System.IO.Compression.Tests.csproj +++ b/src/libraries/System.IO.Compression/tests/System.IO.Compression.Tests.csproj @@ -14,36 +14,26 @@ - - Common\System\IO\PathFeatures.cs - - - Common\System\IO\Compression\CRC.cs - - - Common\System\IO\Compression\CompressionStreamTestBase.cs - - - Common\System\IO\Compression\CompressionStreamUnitTestBase.cs - - - Common\System\IO\Compression\FileData.cs - - - Common\System\IO\Compression\LocalMemoryStream.cs - - - Common\System\IO\Compression\StreamHelpers.cs - - - Common\System\IO\TempFile.cs - - - Common\System\IO\Compression\ZipTestHelper.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - + + + + + + + + + + + + true + - + - + diff --git a/src/libraries/System.IO.FileSystem.AccessControl/src/System.IO.FileSystem.AccessControl.csproj b/src/libraries/System.IO.FileSystem.AccessControl/src/System.IO.FileSystem.AccessControl.csproj index 890edd52f323f2..ac6c8e8a6690c4 100644 --- a/src/libraries/System.IO.FileSystem.AccessControl/src/System.IO.FileSystem.AccessControl.csproj +++ b/src/libraries/System.IO.FileSystem.AccessControl/src/System.IO.FileSystem.AccessControl.csproj @@ -1,20 +1,25 @@ - + - true - true - SR.PlatformNotSupported_AccessControl $(NetCoreAppCurrent)-Windows_NT;netstandard2.0;netstandard2.0-Windows_NT;net461-Windows_NT;$(NetFrameworkCurrent)-Windows_NT true true enable - + + + true + true + SR.PlatformNotSupported_AccessControl + + - - - + + + @@ -23,56 +28,89 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + @@ -83,4 +121,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.IO.FileSystem.AccessControl/tests/System.IO.FileSystem.AccessControl.Tests.csproj b/src/libraries/System.IO.FileSystem.AccessControl/tests/System.IO.FileSystem.AccessControl.Tests.csproj index 6041ad80240c77..2130178404f347 100644 --- a/src/libraries/System.IO.FileSystem.AccessControl/tests/System.IO.FileSystem.AccessControl.Tests.csproj +++ b/src/libraries/System.IO.FileSystem.AccessControl/tests/System.IO.FileSystem.AccessControl.Tests.csproj @@ -6,14 +6,12 @@ - - Common\System\IO\TempFile.cs - - - Common\System\IO\TempDirectory.cs - + + - \ No newline at end of file + diff --git a/src/libraries/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj b/src/libraries/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj index 716da85edb8037..abc8eb70f910d7 100644 --- a/src/libraries/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj +++ b/src/libraries/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj @@ -1,7 +1,5 @@ - System.IO.FileSystem.DriveInfo - System.IO.FileSystem.DriveInfo true $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix enable @@ -10,88 +8,63 @@ - - Common\System\HResults.cs - - - Common\System\IO\PathInternal.CaseSensitivity.cs - + + - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.GetDriveType.cs - - - Common\Interop\Windows\Interop.GetVolumeInformation.cs - - - Common\Interop\Windows\Interop.GetLogicalDrives.cs - - - Common\Interop\Windows\Interop.GetDiskFreeSpaceEx.cs - - - Common\Interop\Windows\Interop.MAX_PATH.cs - - - Common\Interop\Windows\Interop.SetVolumeLabel.cs - - - Common\Interop\Windows\Interop.SetThreadErrorMode.cs - - - Common\Interop\Windows\Interop.SecurityOptions.cs - - - Common\Interop\Windows\Interop.FileOperations.cs - - - Common\Interop\Windows\Interop.Errors.cs - - - Common\Interop\Windows\Interop.FormatMessage.cs - - - Common\System\IO\DisableMediaInsertionPrompt.cs - - - Common\System\IO\Win32Marshal.cs - - - Common\System\IO\DriveInfoInternal.Windows.cs - - - Common\System\IO\PathInternal.Windows.cs - + + + + + + + + + + + + + + + + - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\Interop.Errors.cs - - - Common\Interop\Unix\Interop.IOErrors.cs - - - Common\System\IO\PathInternal.Unix.cs - - - Common\Interop\Unix\Interop.PathConf.cs - - - Common\Interop\Unix\Interop.MountPoints.cs - - - Common\Interop\Unix\Interop.MountPoints.FormatInfo.cs - + + + + + + + @@ -100,4 +73,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.IO.FileSystem.Watcher/src/System.IO.FileSystem.Watcher.csproj b/src/libraries/System.IO.FileSystem.Watcher/src/System.IO.FileSystem.Watcher.csproj index 6476f8cff3335e..5872cdfcf17038 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/src/System.IO.FileSystem.Watcher.csproj +++ b/src/libraries/System.IO.FileSystem.Watcher/src/System.IO.FileSystem.Watcher.csproj @@ -19,112 +19,84 @@ - - Common\System\IO\PathInternal.CaseSensitivity.cs - + - - Common\System\IO\PathInternal.Windows.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.BOOL.cs - - - Common\Interop\Windows\Interop.SECURITY_ATTRIBUTES.cs - - - Common\Interop\Windows\Kernel32\Interop.FileOperations.cs - - - Common\Interop\Windows\Kernel32\Interop.ReadDirectoryChangesW.cs - + + + + + + Component - - Common\Interop\Windows\Interop.CloseHandle.cs - + - - Common\Interop\Windows\Interop.CreateFile.cs - + - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\libc\Interop.Read.cs - - - Common\Interop\Unix\Interop.Errors.cs - - - Common\Interop\Unix\Interop.IOErrors.cs - - - Common\System\IO\PathInternal.Unix.cs - - - Common\Interop\Unix\Interop.PathConf.cs - + + + + + + - - Common\Interop\Linux\Interop.inotify.cs - - - Common\Interop\Unix\Interop.Poll.cs - - - Common\Interop\Unix\Interop.Stat.cs - + + + + - - System.IO.FileSystem\src\System\IO\FileSystem.Exists.Unix.cs - - - Common\Interop\OSX\Interop.EventStream.cs - - - Common\Interop\OSX\Interop.CoreFoundation.cs - - - Common\Interop\OSX\Interop.Libraries.cs - - - Common\Interop\OSX\Interop.RunLoop.cs - - - Common\Interop\Unix\Interop.RealPath.cs - - - Common\Interop\Unix\Interop.Stat.Span.cs - - - Common\Interop\Unix\Interop.Stat.cs - - - Common\Interop\Unix\Interop.Sync.cs - - - Common\Microsoft\Win32\SafeHandles\SafeCreateHandle.OSX.cs - - - Common\Microsoft\Win32\SafeHandles\SafeEventStreamHandle.OSX.cs - - - Common\System\Text\ValueUtf8Converter.cs - + + + + + + + + + + + + diff --git a/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Linux.cs b/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Linux.cs index def4ae5681fe61..5b04282c713d63 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Linux.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Linux.cs @@ -680,11 +680,11 @@ private void ProcessEvents() // that's actually what's needed (otherwise it'd be fine to block indefinitely waiting // for the next event to arrive). const int MillisecondsTimeout = 2; - Interop.Sys.PollEvents events; - Interop.Sys.Poll(_inotifyHandle, Interop.Sys.PollEvents.POLLIN, MillisecondsTimeout, out events); + Interop.PollEvents events; + Interop.Sys.Poll(_inotifyHandle, Interop.PollEvents.POLLIN, MillisecondsTimeout, out events); // If we error or don't have any signaled handles, send the deleted event - if (events == Interop.Sys.PollEvents.POLLNONE) + if (events == Interop.PollEvents.POLLNONE) { // There isn't any more data in the queue so this is a deleted event watcher.NotifyFileSystemEventArgs(WatcherChangeTypes.Deleted, expandedName); diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/System.IO.FileSystem.Watcher.Tests.csproj b/src/libraries/System.IO.FileSystem.Watcher/tests/System.IO.FileSystem.Watcher.Tests.csproj index 589fb29ae21011..235f4860c757e9 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/tests/System.IO.FileSystem.Watcher.Tests.csproj +++ b/src/libraries/System.IO.FileSystem.Watcher/tests/System.IO.FileSystem.Watcher.Tests.csproj @@ -26,20 +26,16 @@ - - Common\System\IO\TempFile.cs - - - Common\System\IO\TempDirectory.cs - + + - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\System.Native\Interop.ResourceLimits.cs - + + diff --git a/src/libraries/System.IO.FileSystem/src/System.IO.FileSystem.csproj b/src/libraries/System.IO.FileSystem/src/System.IO.FileSystem.csproj index 3dfbc1ba581460..0e7728f070818b 100644 --- a/src/libraries/System.IO.FileSystem/src/System.IO.FileSystem.csproj +++ b/src/libraries/System.IO.FileSystem/src/System.IO.FileSystem.csproj @@ -16,10 +16,14 @@ - - - - + + + + @@ -53,62 +57,118 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -118,29 +178,52 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -152,4 +235,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.IO.FileSystem/tests/FileInfo/Open.cs b/src/libraries/System.IO.FileSystem/tests/FileInfo/Open.cs index 2927ab331708e2..a071f5d6639315 100644 --- a/src/libraries/System.IO.FileSystem/tests/FileInfo/Open.cs +++ b/src/libraries/System.IO.FileSystem/tests/FileInfo/Open.cs @@ -13,7 +13,6 @@ protected override FileStream CreateFileStream(string path, FileMode mode) return new FileInfo(path).Open(mode); } - [Theory, MemberData(nameof(StreamSpecifiers))] public override void FileModeAppend(string streamSpecifier) { using (FileStream fs = CreateFileStream(GetTestFilePath() + streamSpecifier, FileMode.Append)) @@ -23,7 +22,6 @@ public override void FileModeAppend(string streamSpecifier) } } - [Theory, MemberData(nameof(StreamSpecifiers))] public override void FileModeAppendExisting(string streamSpecifier) { string fileName = GetTestFilePath() + streamSpecifier; diff --git a/src/libraries/System.IO.FileSystem/tests/FileStream/Dispose.cs b/src/libraries/System.IO.FileSystem/tests/FileStream/Dispose.cs index 74d8e8f5bc5564..55eaecef0ca9de 100644 --- a/src/libraries/System.IO.FileSystem/tests/FileStream/Dispose.cs +++ b/src/libraries/System.IO.FileSystem/tests/FileStream/Dispose.cs @@ -111,7 +111,7 @@ public void Dispose_CallsVirtualDisposeTrueArg_ThrowsDuringFlushWriteBuffer_Disp }).Dispose(); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsPreciseGcSupported))] public void NoDispose_CallsVirtualDisposeFalseArg_ThrowsDuringFlushWriteBuffer_FinalizerWontThrow() { RemoteExecutor.Invoke(() => @@ -185,7 +185,7 @@ public void Dispose_CallsVirtualDispose_TrueArg() Assert.False(disposeInvoked, "Expected finalizer to have been suppressed"); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsPreciseGcSupported))] public void Finalizer_CallsVirtualDispose_FalseArg() { bool disposeInvoked = false; diff --git a/src/libraries/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj b/src/libraries/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj index c36d099b980f2a..ccec9a8185b6c6 100644 --- a/src/libraries/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj +++ b/src/libraries/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj @@ -14,7 +14,7 @@ - + @@ -161,15 +161,13 @@ - - - Common\System\Buffers\NativeMemoryManager.cs - - - Common\System\IO\TempFile.cs - - - Common\System\IO\PathFeatures.cs - + + + + - \ No newline at end of file + diff --git a/src/libraries/System.IO.FileSystem/tests/TestData.cs b/src/libraries/System.IO.FileSystem/tests/TestData.cs index 190a3d8b1d5542..c00f3fca34bdd7 100644 --- a/src/libraries/System.IO.FileSystem/tests/TestData.cs +++ b/src/libraries/System.IO.FileSystem/tests/TestData.cs @@ -59,7 +59,6 @@ public static TheoryData PathsWithInvalidCharacters { TheoryData data = new TheoryData { - "\0", "middle\0path", "trailing\0" }; diff --git a/src/libraries/System.IO.IsolatedStorage/src/System.IO.IsolatedStorage.csproj b/src/libraries/System.IO.IsolatedStorage/src/System.IO.IsolatedStorage.csproj index 710b00e4b4c83b..20b7ebd0b43e70 100644 --- a/src/libraries/System.IO.IsolatedStorage/src/System.IO.IsolatedStorage.csproj +++ b/src/libraries/System.IO.IsolatedStorage/src/System.IO.IsolatedStorage.csproj @@ -12,9 +12,8 @@ - - Common\System\Security\IdentityHelper.cs - + diff --git a/src/libraries/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorageFile.cs b/src/libraries/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorageFile.cs index d7d09f9bf3ff6e..1d13427bb66594 100644 --- a/src/libraries/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorageFile.cs +++ b/src/libraries/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorageFile.cs @@ -262,7 +262,7 @@ public DateTimeOffset GetCreationTime(string path) if (path == null) throw new ArgumentNullException(nameof(path)); - if (path == string.Empty) + if (path.Length == 0) { throw new ArgumentException(SR.Argument_EmptyPath, nameof(path)); } @@ -284,7 +284,7 @@ public DateTimeOffset GetLastAccessTime(string path) if (path == null) throw new ArgumentNullException(nameof(path)); - if (path == string.Empty) + if (path.Length == 0) { throw new ArgumentException(SR.Argument_EmptyPath, nameof(path)); } @@ -306,7 +306,7 @@ public DateTimeOffset GetLastWriteTime(string path) if (path == null) throw new ArgumentNullException(nameof(path)); - if (path == string.Empty) + if (path.Length == 0) { throw new ArgumentException(SR.Argument_EmptyPath, nameof(path)); } @@ -331,12 +331,12 @@ public void CopyFile(string sourceFileName, string destinationFileName) if (destinationFileName == null) throw new ArgumentNullException(nameof(destinationFileName)); - if (sourceFileName == string.Empty) + if (sourceFileName.Length == 0) { throw new ArgumentException(SR.Argument_EmptyPath, nameof(sourceFileName)); } - if (destinationFileName == string.Empty) + if (destinationFileName.Length == 0) { throw new ArgumentException(SR.Argument_EmptyPath, nameof(destinationFileName)); } @@ -352,12 +352,12 @@ public void CopyFile(string sourceFileName, string destinationFileName, bool ove if (destinationFileName == null) throw new ArgumentNullException(nameof(destinationFileName)); - if (sourceFileName == string.Empty) + if (sourceFileName.Length == 0) { throw new ArgumentException(SR.Argument_EmptyPath, nameof(sourceFileName)); } - if (destinationFileName == string.Empty) + if (destinationFileName.Length == 0) { throw new ArgumentException(SR.Argument_EmptyPath, nameof(destinationFileName)); } @@ -393,12 +393,12 @@ public void MoveFile(string sourceFileName, string destinationFileName) if (destinationFileName == null) throw new ArgumentNullException(nameof(destinationFileName)); - if (sourceFileName == string.Empty) + if (sourceFileName.Length == 0) { throw new ArgumentException(SR.Argument_EmptyPath, nameof(sourceFileName)); } - if (destinationFileName == string.Empty) + if (destinationFileName.Length == 0) { throw new ArgumentException(SR.Argument_EmptyPath, nameof(destinationFileName)); } @@ -434,12 +434,12 @@ public void MoveDirectory(string sourceDirectoryName, string destinationDirector if (destinationDirectoryName == null) throw new ArgumentNullException(nameof(destinationDirectoryName)); - if (sourceDirectoryName == string.Empty) + if (sourceDirectoryName.Length == 0) { throw new ArgumentException(SR.Argument_EmptyPath, nameof(sourceDirectoryName)); } - if (destinationDirectoryName == string.Empty) + if (destinationDirectoryName.Length == 0) { throw new ArgumentException(SR.Argument_EmptyPath, nameof(destinationDirectoryName)); } diff --git a/src/libraries/System.IO.IsolatedStorage/tests/System.IO.IsolatedStorage.Tests.csproj b/src/libraries/System.IO.IsolatedStorage/tests/System.IO.IsolatedStorage.Tests.csproj index 0aaf3693233c22..64bbfd8e028899 100644 --- a/src/libraries/System.IO.IsolatedStorage/tests/System.IO.IsolatedStorage.Tests.csproj +++ b/src/libraries/System.IO.IsolatedStorage/tests/System.IO.IsolatedStorage.Tests.csproj @@ -8,34 +8,27 @@ - - Internals\Helper.Win32Unix.cs - + - - Internals\Helper.Win32.cs - + - - Internals\Helper.Unix.cs - + - - Common\System\IO\TempDirectory.cs - - - Common\System\IO\TempFile.cs - - - Internals\Helper.cs - - - Common\System\Security\IdentityHelper.cs - + + + + @@ -59,4 +52,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.IO.MemoryMappedFiles/src/System.IO.MemoryMappedFiles.csproj b/src/libraries/System.IO.MemoryMappedFiles/src/System.IO.MemoryMappedFiles.csproj index c2dc86df1632e0..058554ec058b8d 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/src/System.IO.MemoryMappedFiles.csproj +++ b/src/libraries/System.IO.MemoryMappedFiles/src/System.IO.MemoryMappedFiles.csproj @@ -18,139 +18,98 @@ - - Common\Interop\Windows\Interop.CreateFileMapping.cs - - - Common\Interop\Windows\Interop.MapViewOfFile.cs - - - Common\Interop\Windows\Interop.OpenFileMapping.cs - - - Common\Interop\Windows\Interop.VirtualAlloc.cs - - - Common\Interop\Windows\Interop.GlobalMemoryStatusEx.cs - - - Common\Interop\Windows\Interop.SECURITY_ATTRIBUTES.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.CloseHandle.cs - - - Common\Interop\Windows\Interop.Errors.cs - - - Common\Interop\Windows\Interop.FormatMessage.cs - - - Common\Interop\Windows\Interop.FileAttributes.cs - - - Common\Interop\Windows\Interop.FileOperations.cs - - - Common\Interop\Windows\Interop.FlushViewOfFile.cs - - - Common\Interop\Windows\Interop.GenericOperations.cs - - - Common\Interop\Windows\Interop.GetSystemInfo.cs - - - Common\Interop\Windows\Interop.SYSTEM_INFO.cs - - - Common\Interop\Windows\Interop.HandleOptions.cs - - - Common\Interop\Windows\Interop.MEMORY_BASIC_INFO.cs - - - Common\Interop\Windows\Interop.MEMORYSTATUSEX.cs - - - Common\Interop\Windows\Interop.MemOptions.cs - - - Common\Interop\Windows\Interop.PipeOptions.cs - - - Common\Interop\Windows\Interop.BOOL.cs - - - Common\Interop\Windows\Interop.SecurityOptions.cs - - - Common\Interop\Windows\Interop.UnmapViewOfFile.cs - - - Common\Interop\Windows\Interop.VirtualQuery.cs - - - Common\System\IO\Win32Marshal.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\Interop.Errors.cs - - - Common\Interop\Unix\Interop.Fcntl.cs - - - Common\Interop\Unix\Interop.IOErrors.cs - - - Common\Interop\Unix\Interop.MMap.cs - - - Common\Interop\Unix\Interop.MUnmap.cs - - - Common\Interop\Unix\Interop.MSync.cs - - - Common\Interop\Unix\Interop.Open.cs - - - Common\Interop\Unix\Interop.OpenFlags.cs - - - Common\Interop\Unix\Interop.Permissions.cs - - - Common\Interop\Unix\Interop.SysConf.cs - + + + + + + + + + + + - - Common\Interop\Unix\Interop.FTruncate.cs - - - Common\Interop\Unix\Interop.MAdvise.cs - - - Common\Interop\Unix\Interop.ShmOpen.cs - - - Common\Interop\Unix\Interop.Unlink.cs - + + + + diff --git a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewAccessor.Tests.cs b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewAccessor.Tests.cs index 9a42307ec79dee..c81450e98cf495 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewAccessor.Tests.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewAccessor.Tests.cs @@ -91,9 +91,11 @@ public void ValidAccessLevelCombinations(MemoryMappedFileAccess mapAccess, Memor } catch (UnauthorizedAccessException) { - if (PlatformDetection.IsInContainer && (viewAccess == MemoryMappedFileAccess.ReadExecute || viewAccess == MemoryMappedFileAccess.ReadWriteExecute)) + if ((RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || PlatformDetection.IsInContainer) && + (viewAccess == MemoryMappedFileAccess.ReadExecute || viewAccess == MemoryMappedFileAccess.ReadWriteExecute)) { - throw new SkipTestException("Execute permission failing in container."); + // Containers and OSX with SIP enabled do not have execute permissions by default. + throw new SkipTestException("Insufficient execute permission."); } throw; @@ -491,11 +493,11 @@ public void AllowFinalization() GC.WaitForPendingFinalizers(); GC.Collect(); - MemoryMappedFile mmf; - Assert.False(mmfWeak.TryGetTarget(out mmf)); - - MemoryMappedViewAccessor mmva; - Assert.False(mmvaWeak.TryGetTarget(out mmva)); + if (PlatformDetection.IsPreciseGcSupported) + { + Assert.False(mmfWeak.TryGetTarget(out _)); + Assert.False(mmvaWeak.TryGetTarget(out _)); + } } [MethodImpl(MethodImplOptions.NoInlining)] diff --git a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs index 1291591c30f13e..860401865ecd93 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs +++ b/src/libraries/System.IO.MemoryMappedFiles/tests/MemoryMappedViewStream.Tests.cs @@ -91,9 +91,11 @@ public void ValidAccessLevelCombinations(MemoryMappedFileAccess mapAccess, Memor } catch (UnauthorizedAccessException) { - if (PlatformDetection.IsInContainer && (viewAccess == MemoryMappedFileAccess.ReadExecute || viewAccess == MemoryMappedFileAccess.ReadWriteExecute)) + if ((RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || PlatformDetection.IsInContainer) && + (viewAccess == MemoryMappedFileAccess.ReadExecute || viewAccess == MemoryMappedFileAccess.ReadWriteExecute)) { - throw new SkipTestException("Execute permission failing in container."); + // Containers and OSX with SIP enabled do not have execute permissions by default. + throw new SkipTestException("Insufficient execute permission."); } throw; @@ -424,11 +426,11 @@ public void AllowFinalization() GC.WaitForPendingFinalizers(); GC.Collect(); - MemoryMappedFile mmf; - Assert.False(mmfWeak.TryGetTarget(out mmf)); - - MemoryMappedViewStream s; - Assert.False(mmvsWeak.TryGetTarget(out s)); + if (PlatformDetection.IsPreciseGcSupported) + { + Assert.False(mmfWeak.TryGetTarget(out _)); + Assert.False(mmvsWeak.TryGetTarget(out _)); + } } [MethodImpl(MethodImplOptions.NoInlining)] diff --git a/src/libraries/System.IO.MemoryMappedFiles/tests/System.IO.MemoryMappedFiles.Tests.csproj b/src/libraries/System.IO.MemoryMappedFiles/tests/System.IO.MemoryMappedFiles.Tests.csproj index 830a1c5f73d846..c23e14c34f83ca 100644 --- a/src/libraries/System.IO.MemoryMappedFiles/tests/System.IO.MemoryMappedFiles.Tests.csproj +++ b/src/libraries/System.IO.MemoryMappedFiles/tests/System.IO.MemoryMappedFiles.Tests.csproj @@ -15,9 +15,8 @@ - - Common\System\IO\TempFile.cs - + \ No newline at end of file diff --git a/src/libraries/System.IO.Packaging/ref/System.IO.Packaging.csproj b/src/libraries/System.IO.Packaging/ref/System.IO.Packaging.csproj index b6f8f5ac2d04b7..56941538f8b06c 100644 --- a/src/libraries/System.IO.Packaging/ref/System.IO.Packaging.csproj +++ b/src/libraries/System.IO.Packaging/ref/System.IO.Packaging.csproj @@ -1,10 +1,13 @@ - true - $(DefineConstants);netcoreapp netstandard2.0;netstandard1.3;net46;$(NetFrameworkCurrent) true + + + $(DefineConstants);netcoreapp + true + diff --git a/src/libraries/System.IO.Packaging/src/System.IO.Packaging.csproj b/src/libraries/System.IO.Packaging/src/System.IO.Packaging.csproj index d08a0d0f2c0c81..49d04496c3c322 100644 --- a/src/libraries/System.IO.Packaging/src/System.IO.Packaging.csproj +++ b/src/libraries/System.IO.Packaging/src/System.IO.Packaging.csproj @@ -1,11 +1,14 @@ true - true - $(DefineConstants);FEATURE_SERIALIZATION - net46;netstandard1.3;netstandard2.0;$(NetFrameworkCurrent)-Windows_NT + netstandard2.0;net46;netstandard1.3;$(NetFrameworkCurrent)-Windows_NT true + + + $(DefineConstants);FEATURE_SERIALIZATION + true + @@ -50,7 +53,7 @@ - + diff --git a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/InternalRelationshipCollection.cs b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/InternalRelationshipCollection.cs index 09413c8a384445..db8cdf81d8b8e7 100644 --- a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/InternalRelationshipCollection.cs +++ b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/InternalRelationshipCollection.cs @@ -161,7 +161,7 @@ internal void Flush() internal static void ThrowIfInvalidRelationshipType(string relationshipType) { // Look for empty string or string with just spaces - if (relationshipType.Trim() == string.Empty) + if (string.IsNullOrWhiteSpace(relationshipType)) throw new ArgumentException(SR.InvalidRelationshipType); } diff --git a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.PackUriScheme.cs b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.PackUriScheme.cs index c2c79ee2318378..c43ca1ac61cd6e 100644 --- a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.PackUriScheme.cs +++ b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.PackUriScheme.cs @@ -79,7 +79,7 @@ public static Uri Create(Uri packageUri, Uri partUri, string fragment) if (fragment != null) { - if (fragment == string.Empty || fragment[0] != '#') + if (fragment.Length == 0 || fragment[0] != '#') throw new ArgumentException(SR.Format(SR.FragmentMustStartWithHash, nameof(fragment))); } @@ -323,7 +323,7 @@ private static PackUriHelper.ValidatedPartUri GetPartUriComponent(Uri packUri) string partName = GetStringForPartUriFromAnyUri(packUri); - if (partName == string.Empty) + if (partName.Length == 0) return null; else return ValidatePartUri(new Uri(partName, UriKind.Relative)); diff --git a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.cs b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.cs index 2b50ad0791ffaf..404e5e6fe9e24a 100644 --- a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.cs +++ b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.cs @@ -49,7 +49,7 @@ public static Uri CreatePartUri(Uri partUri) string partName = GetStringForPartUriFromAnyUri(resolvedUri); - if (partName == string.Empty) + if (partName.Length == 0) throw new ArgumentException(SR.PartUriIsEmpty); ThrowIfPartNameEndsWithSlash(partName); @@ -399,7 +399,7 @@ private static Exception GetExceptionIfPartUriInvalid(Uri partUri, out string pa //We need to make sure that the URI passed to us is not just "/" //"/" is a valid relative uri, but is not a valid partname - if (partName == string.Empty) + if (partName.Length == 0) return new ArgumentException(SR.PartUriIsEmpty); if (partName[0] != ForwardSlashChar) @@ -804,7 +804,7 @@ private bool IsRelationshipUri() // String.Split, will always return an empty string as the // first member in the array as the string starts with a "/" - Debug.Assert(segments.Length > 0 && segments[0] == string.Empty); + Debug.Assert(segments.Length > 0 && segments[0].Length == 0); //If the extension was not equal to .rels, we would have exited early. Debug.Assert(string.CompareOrdinal((Path.GetExtension(segments[segments.Length - 1])), RelationshipPartUpperCaseExtension) == 0); diff --git a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/ZipPackage.cs b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/ZipPackage.cs index f044bf76c1682c..f44daf64e07a0c 100644 --- a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/ZipPackage.cs +++ b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/ZipPackage.cs @@ -964,7 +964,7 @@ private void ValidateXmlAttribute(string attributeName, string attributeValue, s ThrowIfXmlAttributeMissing(attributeName, attributeValue, tagName, reader); //Checking for empty attribute - if (attributeValue == string.Empty) + if (attributeValue.Length == 0) throw new XmlException(SR.Format(SR.RequiredAttributeEmpty, tagName, attributeName), null, ((IXmlLineInfo)reader).LineNumber, ((IXmlLineInfo)reader).LinePosition); } diff --git a/src/libraries/System.IO.Pipelines/ref/System.IO.Pipelines.csproj b/src/libraries/System.IO.Pipelines/ref/System.IO.Pipelines.csproj index 7f1bb21bb6b55d..2af41b5283fb69 100644 --- a/src/libraries/System.IO.Pipelines/ref/System.IO.Pipelines.csproj +++ b/src/libraries/System.IO.Pipelines/ref/System.IO.Pipelines.csproj @@ -2,9 +2,9 @@ netstandard2.0 enable - - netcoreapp2.0 + + netcoreapp2.0 diff --git a/src/libraries/System.IO.Pipelines/src/System.IO.Pipelines.csproj b/src/libraries/System.IO.Pipelines/src/System.IO.Pipelines.csproj index c15a68ff5a26ca..804d66203782d4 100644 --- a/src/libraries/System.IO.Pipelines/src/System.IO.Pipelines.csproj +++ b/src/libraries/System.IO.Pipelines/src/System.IO.Pipelines.csproj @@ -5,9 +5,8 @@ enable - - Common\System\Threading\Tasks\TaskToApm.cs - + @@ -38,10 +37,10 @@ - + - + @@ -59,4 +58,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/BufferSegment.cs b/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/BufferSegment.cs index ffc27059d504f8..800b1414260838 100644 --- a/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/BufferSegment.cs +++ b/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/BufferSegment.cs @@ -10,7 +10,8 @@ namespace System.IO.Pipelines { internal sealed class BufferSegment : ReadOnlySequenceSegment { - private object? _memoryOwner; + private IMemoryOwner? _memoryOwner; + private byte[]? _array; private BufferSegment? _next; private int _end; @@ -55,36 +56,35 @@ public void SetOwnedMemory(IMemoryOwner memoryOwner) public void SetOwnedMemory(byte[] arrayPoolBuffer) { - _memoryOwner = arrayPoolBuffer; + _array = arrayPoolBuffer; AvailableMemory = arrayPoolBuffer; } public void ResetMemory() { - if (_memoryOwner is IMemoryOwner owner) + IMemoryOwner? memoryOwner = _memoryOwner; + if (memoryOwner != null) { - owner.Dispose(); + _memoryOwner = null; + memoryOwner.Dispose(); } else { - Debug.Assert(_memoryOwner is byte[]); - byte[] poolArray = (byte[])_memoryOwner; - ArrayPool.Shared.Return(poolArray); + Debug.Assert(_array != null); + ArrayPool.Shared.Return(_array); + _array = null; } - // Order of below field clears is significant as it clears in a sequential order - // https://github.com/dotnet/corefx/pull/35256#issuecomment-462800477 Next = null; RunningIndex = 0; Memory = default; - _memoryOwner = null; _next = null; _end = 0; AvailableMemory = default; } // Exposed for testing - internal object? MemoryOwner => _memoryOwner; + internal object? MemoryOwner => (object?)_memoryOwner ?? _array; public Memory AvailableMemory { get; private set; } @@ -124,6 +124,5 @@ internal static long GetLength(long startPosition, BufferSegment endSegment, int { return (endSegment.RunningIndex + (uint)endIndex) - startPosition; } - } } diff --git a/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs b/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs index d66d40d11e71c5..b92832c053dad5 100644 --- a/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs +++ b/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs @@ -69,6 +69,9 @@ public sealed partial class Pipe private BufferSegment? _readHead; private int _readHeadIndex; + private readonly int _maxPooledBufferSize; + private bool _disposed; + // The extent of the bytes available to the PipeReader to consume private BufferSegment? _readTail; private int _readTailIndex; @@ -81,7 +84,6 @@ public sealed partial class Pipe // Determines what current operation is in flight (reading/writing) private PipeOperationState _operationState; - private bool _disposed; internal long Length => _unconsumedBytes; @@ -111,6 +113,7 @@ public Pipe(PipeOptions options) // If we're using the default pool then mark it as null since we're just going to use the // array pool under the covers _pool = options.Pool == MemoryPool.Shared ? null : options.Pool; + _maxPooledBufferSize = _pool?.MaxBufferSize ?? 0; _minimumSegmentSize = options.MinimumSegmentSize; _pauseWriterThreshold = options.PauseWriterThreshold; _resumeWriterThreshold = options.ResumeWriterThreshold; @@ -223,16 +226,17 @@ private BufferSegment AllocateSegment(int sizeHint) { BufferSegment newSegment = CreateSegmentUnsynchronized(); - if (_pool is null || sizeHint > _pool.MaxBufferSize) + int maxSize = _maxPooledBufferSize; + if (_pool != null && sizeHint <= maxSize) { - // Use the array pool - int sizeToRequest = GetSegmentSize(sizeHint); - newSegment.SetOwnedMemory(ArrayPool.Shared.Rent(sizeToRequest)); + // Use the specified pool as it fits + newSegment.SetOwnedMemory(_pool.Rent(GetSegmentSize(sizeHint, maxSize))); } else { - // Use the specified pool as it fits - newSegment.SetOwnedMemory(_pool.Rent(GetSegmentSize(sizeHint, _pool.MaxBufferSize))); + // Use the array pool + int sizeToRequest = GetSegmentSize(sizeHint); + newSegment.SetOwnedMemory(ArrayPool.Shared.Rent(sizeToRequest)); } _writingHeadMemory = newSegment.AvailableMemory; @@ -245,7 +249,7 @@ private int GetSegmentSize(int sizeHint, int maxBufferSize = int.MaxValue) // First we need to handle case where hint is smaller than minimum segment size sizeHint = Math.Max(_minimumSegmentSize, sizeHint); // After that adjust it to fit into pools max buffer size - var adjustedToMaximumSize = Math.Min(maxBufferSize, sizeHint); + int adjustedToMaximumSize = Math.Min(maxBufferSize, sizeHint); return adjustedToMaximumSize; } diff --git a/src/libraries/System.IO.Pipelines/tests/System.IO.Pipelines.Tests.csproj b/src/libraries/System.IO.Pipelines/tests/System.IO.Pipelines.Tests.csproj index 0342bf98567242..0e9b268811fcf8 100644 --- a/src/libraries/System.IO.Pipelines/tests/System.IO.Pipelines.Tests.csproj +++ b/src/libraries/System.IO.Pipelines/tests/System.IO.Pipelines.Tests.csproj @@ -3,7 +3,7 @@ true $(NetCoreAppCurrent);$(NetFrameworkCurrent) - + @@ -40,7 +40,7 @@ - + diff --git a/src/libraries/System.IO.Pipes.AccessControl/System.IO.Pipes.AccessControl.sln b/src/libraries/System.IO.Pipes.AccessControl/System.IO.Pipes.AccessControl.sln index 2a79f326225b62..4a3fb342bfcc84 100644 --- a/src/libraries/System.IO.Pipes.AccessControl/System.IO.Pipes.AccessControl.sln +++ b/src/libraries/System.IO.Pipes.AccessControl/System.IO.Pipes.AccessControl.sln @@ -20,7 +20,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{3B8D8597-DC68-4915-8C2A-1DC33E78E607}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{3B8D8597-DC68-4915-8C2A-1DC33E78E607}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.IO.Pipes", "..\System.IO.Pipes\src\System.IO.Pipes.csproj", "{D0711B56-E234-45DB-A620-2F43041826BB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Security.AccessControl", "..\System.Security.AccessControl\src\System.Security.AccessControl.csproj", "{7C35E697-38D0-4A2C-BC25-816732BA2D91}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -44,6 +48,14 @@ Global {3B8D8597-DC68-4915-8C2A-1DC33E78E607}.Debug|Any CPU.Build.0 = Debug|Any CPU {3B8D8597-DC68-4915-8C2A-1DC33E78E607}.Release|Any CPU.ActiveCfg = Release|Any CPU {3B8D8597-DC68-4915-8C2A-1DC33E78E607}.Release|Any CPU.Build.0 = Release|Any CPU + {D0711B56-E234-45DB-A620-2F43041826BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D0711B56-E234-45DB-A620-2F43041826BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0711B56-E234-45DB-A620-2F43041826BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D0711B56-E234-45DB-A620-2F43041826BB}.Release|Any CPU.Build.0 = Release|Any CPU + {7C35E697-38D0-4A2C-BC25-816732BA2D91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7C35E697-38D0-4A2C-BC25-816732BA2D91}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7C35E697-38D0-4A2C-BC25-816732BA2D91}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7C35E697-38D0-4A2C-BC25-816732BA2D91}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -53,6 +65,8 @@ Global {40059634-BB03-4A6F-8657-CCE2D376BC8B} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {994DCE47-4CF6-479D-AB1D-4EA6A2809C34} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} {3B8D8597-DC68-4915-8C2A-1DC33E78E607} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} + {D0711B56-E234-45DB-A620-2F43041826BB} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {7C35E697-38D0-4A2C-BC25-816732BA2D91} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AFD36AE1-C562-46E4-8D24-6F36C0F106B1} diff --git a/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj b/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj index 8599e10012ec35..9c2991aedecb49 100644 --- a/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj +++ b/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj @@ -19,43 +19,78 @@ - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -74,8 +109,10 @@ - - + + @@ -84,31 +121,54 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -132,4 +192,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.IO.Pipes/tests/System.IO.Pipes.Tests.csproj b/src/libraries/System.IO.Pipes/tests/System.IO.Pipes.Tests.csproj index c49e5d41a7b031..13d93c5a066e48 100644 --- a/src/libraries/System.IO.Pipes/tests/System.IO.Pipes.Tests.csproj +++ b/src/libraries/System.IO.Pipes/tests/System.IO.Pipes.Tests.csproj @@ -27,29 +27,22 @@ - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - + - - Common\Interop\Windows\Interop.CancelIoEx.cs - - - Common\Interop\Windows\Interop.LoadLibraryEx_IntPtr.cs - - - Common\Interop\Windows\Interop.Errors.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.GetNamedPipeHandleState.cs - - - Common\Interop\Windows\Interop.MaxLengths.cs - + + + + + + @@ -63,4 +56,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.IO.Ports/ref/System.IO.Ports.csproj b/src/libraries/System.IO.Ports/ref/System.IO.Ports.csproj index d48f7a0a1c0667..fba4e13b90477f 100644 --- a/src/libraries/System.IO.Ports/ref/System.IO.Ports.csproj +++ b/src/libraries/System.IO.Ports/ref/System.IO.Ports.csproj @@ -1,13 +1,16 @@ - true netstandard2.0;net461;$(NetFrameworkCurrent) true + + + true + - + diff --git a/src/libraries/System.IO.Ports/src/Interop/Unix/Interop.Serial.cs b/src/libraries/System.IO.Ports/src/Interop/Unix/Interop.Serial.cs index 66822a7f9ca840..35e80402b009e3 100644 --- a/src/libraries/System.IO.Ports/src/Interop/Unix/Interop.Serial.cs +++ b/src/libraries/System.IO.Ports/src/Interop/Unix/Interop.Serial.cs @@ -4,6 +4,7 @@ using System; using System.IO.Ports; +using System.Net.Sockets; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; @@ -16,5 +17,79 @@ internal static partial class Serial [DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_SerialPortClose", SetLastError = true)] internal static extern int SerialPortClose(IntPtr handle); + + [DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_Shutdown")] + internal static extern Error Shutdown(IntPtr socket, SocketShutdown how); + + /// + /// Reads a number of bytes from an open file descriptor into a specified buffer. + /// + /// The open file descriptor to try to read from + /// The buffer to read info into + /// The size of the buffer + /// + /// Returns the number of bytes read on success; otherwise, -1 is returned + /// Note - on fail. the position of the stream may change depending on the platform; consult man 2 read for more info + /// + [DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_Read", SetLastError = true)] + internal static extern unsafe int Read(SafeHandle fd, byte* buffer, int count); + + /// + /// Writes the specified buffer to the provided open file descriptor + /// + /// The file descriptor to try and write to + /// The data to attempt to write + /// The amount of data to write, in bytes + /// + /// Returns the number of bytes written on success; otherwise, returns -1 and sets errno + /// + [DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_Write", SetLastError = true)] + internal static extern unsafe int Write(SafeHandle fd, byte* buffer, int bufferSize); + + /// + /// Polls a set of file descriptors for signals and returns what signals have been set + /// + /// A list of PollEvent entries + /// The number of entries in pollEvents + /// The amount of time to wait; -1 for infinite, 0 for immediate return, and a positive number is the number of milliseconds + /// The number of events triggered (i.e. the number of entries in pollEvents with a non-zero TriggeredEvents). May be zero in the event of a timeout. + /// An error or Error.SUCCESS. + [DllImport(Libraries.IOPortsNative, EntryPoint = "SystemIoPortsNative_Poll")] + private static extern unsafe Error Poll(PollEvent* pollEvents, uint eventCount, int timeout, uint* triggered); + + /// + /// Polls a File Descriptor for the passed in flags. + /// + /// The descriptor to poll + /// The events to poll for + /// The amount of time to wait; -1 for infinite, 0 for immediate return, and a positive number is the number of milliseconds + /// The events that were returned by the poll call. May be PollEvents.POLLNONE in the case of a timeout. + /// An error or Error.SUCCESS. + internal static unsafe Error Poll(SafeHandle fd, PollEvents events, int timeout, out PollEvents triggered) + { + bool gotRef = false; + try + { + fd.DangerousAddRef(ref gotRef); + + var pollEvent = new PollEvent + { + FileDescriptor = fd.DangerousGetHandle().ToInt32(), + Events = events, + }; + + uint unused; + Error err = Poll(&pollEvent, 1, timeout, &unused); + triggered = pollEvent.TriggeredEvents; + return err; + } + finally + { + if (gotRef) + { + fd.DangerousRelease(); + } + } + } } } diff --git a/src/libraries/System.IO.Ports/src/System.IO.Ports.csproj b/src/libraries/System.IO.Ports/src/System.IO.Ports.csproj index 8b261f91ada340..7dece0f9537c2b 100644 --- a/src/libraries/System.IO.Ports/src/System.IO.Ports.csproj +++ b/src/libraries/System.IO.Ports/src/System.IO.Ports.csproj @@ -1,16 +1,19 @@ true - true - SR.PlatformNotSupported_IOPorts - $(DefineConstants);NOSPAN + $(DefineConstants);NOSPAN;SERIAL_PORTS true annotations netstandard2.0-Windows_NT;netstandard2.0-Linux;netstandard2.0-OSX;netstandard2.0;net461-Windows_NT;netstandard2.0-FreeBSD;$(NetFrameworkCurrent)-Windows_NT true + + + + true + SR.PlatformNotSupported_IOPorts true - + @@ -27,120 +30,84 @@ - + - - Common\Interop\Windows\Kernel32\Interop.DCB.cs - - - Common\Interop\Windows\Kernel32\Interop.COMMPROP.cs - - - Common\Interop\Windows\Kernel32\Interop.COMMTIMEOUTS.cs - - - Common\Interop\Windows\Kernel32\Interop.COMSTAT.cs - - - Common\Interop\Windows\Kernel32\Interop.SetCommState.cs - - - Common\Interop\Windows\Kernel32\Interop.SetCommBreak.cs - - - Common\Interop\Windows\Kernel32\Interop.ClearCommBreak.cs - - - Common\Interop\Windows\Kernel32\Interop.EscapeCommFunction.cs - - - Common\Interop\Windows\Kernel32\Interop.SetCommTimeouts.cs - - - Common\Interop\Windows\Kernel32\Interop.GetCommModemStatus.cs - - - Common\Interop\Windows\Kernel32\Interop.ClearCommError.cs - - - Common\Interop\Windows\Kernel32\Interop.GetCommProperties.cs - - - Common\Interop\Windows\Kernel32\Interop.SetCommMask.cs - - - Common\Interop\Windows\Kernel32\Interop.PurgeComm.cs - - - Common\Interop\Windows\Kernel32\Interop.SetupComm.cs - - - Common\Interop\Windows\Kernel32\Interop.GetCommState.cs - - - Common\Interop\Windows\Kernel32\Interop.WaitCommEvent.cs - - - Common\Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_IntPtr.cs - - - Common\Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_NativeOverlapped.cs - - - Common\Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_IntPtr.cs - - - Common\Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs - - - Common\Interop\Windows\Kernel32\Interop.GetOverlappedResult.cs - - - Common\Interop\Windows\Kernel32\Interop.FlushFileBuffers.cs - - - Common\Interop\Windows\Kernel32\Interop.GenericOperations.cs - - - Common\Interop\Windows\Interop.SECURITY_ATTRIBUTES.cs - - - Common\Interop\Windows\Interop.FileTypes.cs - - - Common\System\IO\PathInternal.Windows.cs - - - Common\Interop\Windows\Kernel32\Interop.GetFileType_SafeHandle.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.Errors.cs - - - Common\Interop\Windows\Interop.BOOL.cs - - - Common\Interop\Windows\Kernel32\Interop.CloseHandle.cs - - - Common\System\IO\Win32Marshal.cs - - - Common\Interop\Windows\Interop.FormatMessage.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - Common\Interop\Windows\Kernel32\Interop.CreateFile.cs - - - Common\Interop\Windows\Kernel32\Interop.FileOperations.cs - + + @@ -156,36 +123,22 @@ - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\Interop.Errors.cs - - - Common\Interop\Unix\Interop.IOErrors.cs - - - Common\Interop\Unix\System.Native\Interop.Read.cs - - - Common\Interop\Unix\System.Native\Interop.Write.cs - - - Common\Interop\Unix\System.Native\Interop.Poll.cs - - - Common\Interop\Unix\System.Native\Interop.Shutdown.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - + + + + + - + - + @@ -205,4 +158,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.IO.Ports/src/System/IO/Ports/SafeSerialDeviceHandle.Unix.cs b/src/libraries/System.IO.Ports/src/System/IO/Ports/SafeSerialDeviceHandle.Unix.cs index db9d881dec64a7..a98bcd49542150 100644 --- a/src/libraries/System.IO.Ports/src/System/IO/Ports/SafeSerialDeviceHandle.Unix.cs +++ b/src/libraries/System.IO.Ports/src/System/IO/Ports/SafeSerialDeviceHandle.Unix.cs @@ -35,7 +35,7 @@ internal static SafeSerialDeviceHandle Open(string portName) protected override bool ReleaseHandle() { - Interop.Sys.Shutdown(handle, SocketShutdown.Both); + Interop.Serial.Shutdown(handle, SocketShutdown.Both); int result = Interop.Serial.SerialPortClose(handle); Debug.Assert(result == 0, $"Close failed with result {result} and error {Interop.Sys.GetLastErrorInfo()}"); diff --git a/src/libraries/System.IO.Ports/src/System/IO/Ports/SerialStream.Unix.cs b/src/libraries/System.IO.Ports/src/System/IO/Ports/SerialStream.Unix.cs index 4616384198b9ec..dd8ea97d7b96cc 100644 --- a/src/libraries/System.IO.Ports/src/System/IO/Ports/SerialStream.Unix.cs +++ b/src/libraries/System.IO.Ports/src/System/IO/Ports/SerialStream.Unix.cs @@ -464,7 +464,7 @@ public override IAsyncResult BeginRead(byte[] array, int offset, int numBytes, A // Will wait `timeout` miliseconds or until reading or writing is possible // If no operation is requested it will throw // Returns event which has happened - private Interop.Sys.PollEvents PollEvents(int timeout, bool pollReadEvents, bool pollWriteEvents, out Interop.ErrorInfo? error) + private Interop.PollEvents PollEvents(int timeout, bool pollReadEvents, bool pollWriteEvents, out Interop.ErrorInfo? error) { if (!pollReadEvents && !pollWriteEvents) { @@ -472,20 +472,20 @@ private Interop.Sys.PollEvents PollEvents(int timeout, bool pollReadEvents, bool throw new Exception(); } - Interop.Sys.PollEvents eventsToPoll = Interop.Sys.PollEvents.POLLERR; + Interop.PollEvents eventsToPoll = Interop.PollEvents.POLLERR; if (pollReadEvents) { - eventsToPoll |= Interop.Sys.PollEvents.POLLIN; + eventsToPoll |= Interop.PollEvents.POLLIN; } if (pollWriteEvents) { - eventsToPoll |= Interop.Sys.PollEvents.POLLOUT; + eventsToPoll |= Interop.PollEvents.POLLOUT; } - Interop.Sys.PollEvents events = Interop.Sys.PollEvents.POLLNONE; - Interop.Error ret = Interop.Sys.Poll( + Interop.PollEvents events = Interop.PollEvents.POLLNONE; + Interop.Error ret = Interop.Serial.Poll( _handle, eventsToPoll, timeout, @@ -699,7 +699,7 @@ private unsafe int ProcessRead(SerialStreamIORequest r) fixed (byte* bufPtr = buff) { // assumes dequeue-ing happens on a single thread - int numBytes = Interop.Sys.Read(_handle, bufPtr, buff.Length); + int numBytes = Interop.Serial.Read(_handle, bufPtr, buff.Length); if (numBytes < 0) { @@ -731,7 +731,7 @@ private unsafe int ProcessWrite(SerialStreamIORequest r) fixed (byte* bufPtr = buff) { // assumes dequeue-ing happens on a single thread - int numBytes = Interop.Sys.Write(_handle, bufPtr, buff.Length); + int numBytes = Interop.Serial.Write(_handle, bufPtr, buff.Length); if (numBytes <= 0) { @@ -843,7 +843,7 @@ private unsafe void IOLoop() } else { - Interop.Sys.PollEvents events = PollEvents(1, + Interop.PollEvents events = PollEvents(1, pollReadEvents: hasPendingReads, pollWriteEvents: hasPendingWrites, out Interop.ErrorInfo? error); @@ -854,21 +854,21 @@ private unsafe void IOLoop() break; } - if (events.HasFlag(Interop.Sys.PollEvents.POLLNVAL) || - events.HasFlag(Interop.Sys.PollEvents.POLLERR)) + if (events.HasFlag(Interop.PollEvents.POLLNVAL) || + events.HasFlag(Interop.PollEvents.POLLERR)) { // bad descriptor or some other error we can't handle FinishPendingIORequests(); break; } - if (events.HasFlag(Interop.Sys.PollEvents.POLLIN)) + if (events.HasFlag(Interop.PollEvents.POLLIN)) { int bytesRead = DoIORequest(_readQueue, _processReadDelegate); _totalBytesRead += bytesRead; } - if (events.HasFlag(Interop.Sys.PollEvents.POLLOUT)) + if (events.HasFlag(Interop.PollEvents.POLLOUT)) { DoIORequest(_writeQueue, _processWriteDelegate); } diff --git a/src/libraries/System.IO/tests/BinaryReader/BinaryReaderTests.cs b/src/libraries/System.IO/tests/BinaryReader/BinaryReaderTests.cs index cc46766e91c807..e97e3b4894eeab 100644 --- a/src/libraries/System.IO/tests/BinaryReader/BinaryReaderTests.cs +++ b/src/libraries/System.IO/tests/BinaryReader/BinaryReaderTests.cs @@ -63,6 +63,129 @@ public void BinaryReader_CloseTests_Negative() } } + [Fact] + public void BinaryReader_EofReachedEarlyTests_ThrowsException() + { + // test integer primitives + + RunTest(writer => writer.Write(byte.MinValue), reader => reader.ReadByte()); + RunTest(writer => writer.Write(byte.MaxValue), reader => reader.ReadByte()); + RunTest(writer => writer.Write(sbyte.MinValue), reader => reader.ReadSByte()); + RunTest(writer => writer.Write(sbyte.MaxValue), reader => reader.ReadSByte()); + RunTest(writer => writer.Write(short.MinValue), reader => reader.ReadInt16()); + RunTest(writer => writer.Write(short.MaxValue), reader => reader.ReadInt16()); + RunTest(writer => writer.Write(ushort.MinValue), reader => reader.ReadUInt16()); + RunTest(writer => writer.Write(ushort.MaxValue), reader => reader.ReadUInt16()); + RunTest(writer => writer.Write(int.MinValue), reader => reader.ReadInt32()); + RunTest(writer => writer.Write(int.MaxValue), reader => reader.ReadInt32()); + RunTest(writer => writer.Write(uint.MinValue), reader => reader.ReadUInt32()); + RunTest(writer => writer.Write(uint.MaxValue), reader => reader.ReadUInt32()); + RunTest(writer => writer.Write(long.MinValue), reader => reader.ReadInt64()); + RunTest(writer => writer.Write(long.MaxValue), reader => reader.ReadInt64()); + RunTest(writer => writer.Write(ulong.MinValue), reader => reader.ReadUInt64()); + RunTest(writer => writer.Write(ulong.MaxValue), reader => reader.ReadUInt64()); + RunTest(writer => writer.Write7BitEncodedInt(int.MinValue), reader => reader.Read7BitEncodedInt()); + RunTest(writer => writer.Write7BitEncodedInt(int.MaxValue), reader => reader.Read7BitEncodedInt()); + RunTest(writer => writer.Write7BitEncodedInt64(long.MinValue), reader => reader.Read7BitEncodedInt64()); + RunTest(writer => writer.Write7BitEncodedInt64(long.MaxValue), reader => reader.Read7BitEncodedInt64()); + + // test non-integer numeric types + + RunTest(writer => writer.Write((float)0.1234), reader => reader.ReadSingle()); + RunTest(writer => writer.Write((double)0.1234), reader => reader.ReadDouble()); + RunTest(writer => writer.Write((decimal)0.1234), reader => reader.ReadDecimal()); + + // test non-numeric primitive types + + RunTest(writer => writer.Write(true), reader => reader.ReadBoolean()); + RunTest(writer => writer.Write(false), reader => reader.ReadBoolean()); + RunTest(writer => writer.Write(string.Empty), reader => reader.ReadString()); + RunTest(writer => writer.Write("hello world"), reader => reader.ReadString()); + RunTest(writer => writer.Write(new string('x', 1024 * 1024)), reader => reader.ReadString()); + + void RunTest(Action writeAction, Action readAction) + { + UTF8Encoding encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); + MemoryStream memoryStream = new MemoryStream(); + + // First, call the write action twice + + BinaryWriter writer = new BinaryWriter(memoryStream, encoding, leaveOpen: true); + writeAction(writer); + writeAction(writer); + writer.Close(); + + // Make sure we populated the inner stream, then truncate it before EOF reached. + + Assert.True(memoryStream.Length > 0); + memoryStream.Position = 0; // reset read pointer + memoryStream.SetLength(memoryStream.Length - 1); // truncate the last byte of the stream + + BinaryReader reader = new BinaryReader(memoryStream, encoding); + readAction(reader); // should succeed + Assert.Throws(() => readAction(reader)); // should fail + } + } + + /* + * Other tests for Read7BitEncodedInt[64] are in BinaryWriter.WriteTests.cs, not here. + */ + + [Fact] + public void BinaryReader_Read7BitEncodedInt_AllowsOverlongEncodings() + { + MemoryStream memoryStream = new MemoryStream(new byte[] { 0x9F, 0x00 /* overlong */ }); + BinaryReader reader = new BinaryReader(memoryStream); + + int actual = reader.Read7BitEncodedInt(); + Assert.Equal(0x1F, actual); + } + + [Fact] + public void BinaryReader_Read7BitEncodedInt_BadFormat_Throws() + { + // Serialized form of 0b1_00000000_00000000_00000000_00000000 + // |0x10|| 0x80 || 0x80 || 0x80 || 0x80| + + MemoryStream memoryStream = new MemoryStream(new byte[] { 0x80, 0x80, 0x80, 0x80, 0x10 }); + BinaryReader reader = new BinaryReader(memoryStream); + Assert.Throws(() => reader.Read7BitEncodedInt()); + + // 5 bytes, all with the "there's more data after this" flag set + + memoryStream = new MemoryStream(new byte[] { 0x80, 0x80, 0x80, 0x80, 0x80 }); + reader = new BinaryReader(memoryStream); + Assert.Throws(() => reader.Read7BitEncodedInt()); + } + + [Fact] + public void BinaryReader_Read7BitEncodedInt64_AllowsOverlongEncodings() + { + MemoryStream memoryStream = new MemoryStream(new byte[] { 0x9F, 0x00 /* overlong */ }); + BinaryReader reader = new BinaryReader(memoryStream); + + long actual = reader.Read7BitEncodedInt64(); + Assert.Equal(0x1F, actual); + } + + [Fact] + public void BinaryReader_Read7BitEncodedInt64_BadFormat_Throws() + { + // Serialized form of 0b1_00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000 + // | || 0x80| | 0x80|| 0x80 || 0x80 || 0x80 || 0x80 || 0x80 || 0x80 || 0x80| + // `-- 0x02 + + MemoryStream memoryStream = new MemoryStream(new byte[] { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02 }); + BinaryReader reader = new BinaryReader(memoryStream); + Assert.Throws(() => reader.Read7BitEncodedInt64()); + + // 10 bytes, all with the "there's more data after this" flag set + + memoryStream = new MemoryStream(new byte[] { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }); + reader = new BinaryReader(memoryStream); + Assert.Throws(() => reader.Read7BitEncodedInt()); + } + private void ValidateDisposedExceptions(BinaryReader binaryReader) { byte[] byteBuffer = new byte[10]; diff --git a/src/libraries/System.IO/tests/BinaryWriter/BinaryWriter.WriteTests.cs b/src/libraries/System.IO/tests/BinaryWriter/BinaryWriter.WriteTests.cs index 6fd2f87d059282..54346ae27aa62c 100644 --- a/src/libraries/System.IO/tests/BinaryWriter/BinaryWriter.WriteTests.cs +++ b/src/libraries/System.IO/tests/BinaryWriter/BinaryWriter.WriteTests.cs @@ -2,10 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Xunit; -using System; -using System.IO; using System.Text; +using Xunit; namespace System.IO.Tests { @@ -90,6 +88,18 @@ public void BinaryWriter_WriteInt32Test() WriteTest(i32arr, (bw, s) => bw.Write(s), (br) => br.ReadInt32()); } + [Fact] + public void BinaryWriter_Write7BitEncodedIntTest() + { + int[] i32arr = new int[] + { + int.MinValue, int.MaxValue, 0, -10000, 10000, -50, 50, + unchecked((int)uint.MinValue), unchecked((int)uint.MaxValue), unchecked((int)(uint.MaxValue - 100)) + }; + + WriteTest(i32arr, (bw, s) => bw.Write7BitEncodedInt(s), (br) => br.Read7BitEncodedInt()); + } + [Fact] public void BinaryWriter_WriteInt64Test() { @@ -98,6 +108,18 @@ public void BinaryWriter_WriteInt64Test() WriteTest(i64arr, (bw, s) => bw.Write(s), (br) => br.ReadInt64()); } + [Fact] + public void BinaryWriter_Write7BitEncodedInt64Test() + { + long[] i64arr = new long[] + { + long.MinValue, long.MaxValue, 0, -10000, 10000, -50, 50, + unchecked((long)ulong.MinValue), unchecked((long)ulong.MaxValue), unchecked((long)(ulong.MaxValue - 100)) + }; + + WriteTest(i64arr, (bw, s) => bw.Write7BitEncodedInt64(s), (br) => br.Read7BitEncodedInt64()); + } + [Fact] public void BinaryWriter_WriteUInt16Test() { diff --git a/src/libraries/System.IO/tests/System.IO.Tests.csproj b/src/libraries/System.IO/tests/System.IO.Tests.csproj index 3262bfa8bb5013..44cd574154b951 100644 --- a/src/libraries/System.IO/tests/System.IO.Tests.csproj +++ b/src/libraries/System.IO/tests/System.IO.Tests.csproj @@ -46,22 +46,18 @@ - - Common\System\Buffers\NativeMemoryManager.cs - - - Common\System\IO\CallTrackingStream.cs - - - Common\System\IO\DelegateStream.cs - - - Common\System\IO\WrappedMemoryStream.cs - + + + + - \ No newline at end of file + diff --git a/src/libraries/System.Linq.Expressions/ref/System.Linq.Expressions.cs b/src/libraries/System.Linq.Expressions/ref/System.Linq.Expressions.cs index f52a771eba278c..196c19e62d9034 100644 --- a/src/libraries/System.Linq.Expressions/ref/System.Linq.Expressions.cs +++ b/src/libraries/System.Linq.Expressions/ref/System.Linq.Expressions.cs @@ -142,7 +142,7 @@ event System.ComponentModel.PropertyChangedEventHandler? System.ComponentModel.I bool System.Collections.Generic.ICollection>.Contains(System.Collections.Generic.KeyValuePair item) { throw null; } void System.Collections.Generic.ICollection>.CopyTo(System.Collections.Generic.KeyValuePair[] array, int arrayIndex) { } bool System.Collections.Generic.ICollection>.Remove(System.Collections.Generic.KeyValuePair item) { throw null; } - void System.Collections.Generic.IDictionary.Add(string key, object value) { } + void System.Collections.Generic.IDictionary.Add(string key, object? value) { } bool System.Collections.Generic.IDictionary.ContainsKey(string key) { throw null; } bool System.Collections.Generic.IDictionary.Remove(string key) { throw null; } bool System.Collections.Generic.IDictionary.TryGetValue(string key, out object? value) { throw null; } @@ -1193,11 +1193,11 @@ public void Reverse() { } public void Reverse(int index, int count) { } void System.Collections.ICollection.CopyTo(System.Array array, int index) { } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - int System.Collections.IList.Add(object value) { throw null; } - bool System.Collections.IList.Contains(object value) { throw null; } - int System.Collections.IList.IndexOf(object value) { throw null; } - void System.Collections.IList.Insert(int index, object value) { } - void System.Collections.IList.Remove(object value) { } + int System.Collections.IList.Add(object? value) { throw null; } + bool System.Collections.IList.Contains(object? value) { throw null; } + int System.Collections.IList.IndexOf(object? value) { throw null; } + void System.Collections.IList.Insert(int index, object? value) { } + void System.Collections.IList.Remove(object? value) { } public T[] ToArray() { throw null; } public System.Collections.ObjectModel.ReadOnlyCollection ToReadOnlyCollection() { throw null; } } diff --git a/src/libraries/System.Linq.Expressions/src/System.Linq.Expressions.csproj b/src/libraries/System.Linq.Expressions/src/System.Linq.Expressions.csproj index a88e5ca3b5e6a2..c9c9624cc3c946 100644 --- a/src/libraries/System.Linq.Expressions/src/System.Linq.Expressions.csproj +++ b/src/libraries/System.Linq.Expressions/src/System.Linq.Expressions.csproj @@ -13,12 +13,10 @@ $(DefineConstants);FEATURE_INTERPRET - - Common\System\Collections\Generic\ArrayBuilder.cs - - - Common\System\Runtime\CompilerServices\PreserveDependencyAttribute.cs - + + diff --git a/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/ILGen.cs b/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/ILGen.cs index a87dccf2c9f2c9..880f85ba26b34d 100644 --- a/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/ILGen.cs +++ b/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/ILGen.cs @@ -34,32 +34,7 @@ internal static void EmitLoadArg(this ILGenerator il, int index) Debug.Assert(index >= 0); Debug.Assert(index < ushort.MaxValue); - switch (index) - { - case 0: - il.Emit(OpCodes.Ldarg_0); - break; - case 1: - il.Emit(OpCodes.Ldarg_1); - break; - case 2: - il.Emit(OpCodes.Ldarg_2); - break; - case 3: - il.Emit(OpCodes.Ldarg_3); - break; - default: - if (index <= byte.MaxValue) - { - il.Emit(OpCodes.Ldarg_S, (byte)index); - } - else - { - // cast to short, result is correct ushort. - il.Emit(OpCodes.Ldarg, (short)index); - } - break; - } + il.Emit(OpCodes.Ldarg, index); } internal static void EmitLoadArgAddress(this ILGenerator il, int index) @@ -67,15 +42,7 @@ internal static void EmitLoadArgAddress(this ILGenerator il, int index) Debug.Assert(index >= 0); Debug.Assert(index < ushort.MaxValue); - if (index <= byte.MaxValue) - { - il.Emit(OpCodes.Ldarga_S, (byte)index); - } - else - { - // cast to short, result is correct ushort. - il.Emit(OpCodes.Ldarga, (short)index); - } + il.Emit(OpCodes.Ldarga, index); } internal static void EmitStoreArg(this ILGenerator il, int index) @@ -83,15 +50,7 @@ internal static void EmitStoreArg(this ILGenerator il, int index) Debug.Assert(index >= 0); Debug.Assert(index < ushort.MaxValue); - if (index <= byte.MaxValue) - { - il.Emit(OpCodes.Starg_S, (byte)index); - } - else - { - // cast to short, result is correct ushort. - il.Emit(OpCodes.Starg, (short)index); - } + il.Emit(OpCodes.Starg, index); } /// @@ -354,51 +313,7 @@ internal static void EmitPrimitive(this ILGenerator il, bool value) internal static void EmitPrimitive(this ILGenerator il, int value) { - OpCode c; - switch (value) - { - case -1: - c = OpCodes.Ldc_I4_M1; - break; - case 0: - c = OpCodes.Ldc_I4_0; - break; - case 1: - c = OpCodes.Ldc_I4_1; - break; - case 2: - c = OpCodes.Ldc_I4_2; - break; - case 3: - c = OpCodes.Ldc_I4_3; - break; - case 4: - c = OpCodes.Ldc_I4_4; - break; - case 5: - c = OpCodes.Ldc_I4_5; - break; - case 6: - c = OpCodes.Ldc_I4_6; - break; - case 7: - c = OpCodes.Ldc_I4_7; - break; - case 8: - c = OpCodes.Ldc_I4_8; - break; - default: - if (value >= sbyte.MinValue && value <= sbyte.MaxValue) - { - il.Emit(OpCodes.Ldc_I4_S, (sbyte)value); - } - else - { - il.Emit(OpCodes.Ldc_I4, value); - } - return; - } - il.Emit(c); + il.Emit(OpCodes.Ldc_I4, value); } private static void EmitPrimitive(this ILGenerator il, uint value) diff --git a/src/libraries/System.Linq.Expressions/tests/System.Linq.Expressions.Tests.csproj b/src/libraries/System.Linq.Expressions/tests/System.Linq.Expressions.Tests.csproj index 6ac48c2e3dca5c..35d8c92b8d1f49 100644 --- a/src/libraries/System.Linq.Expressions/tests/System.Linq.Expressions.Tests.csproj +++ b/src/libraries/System.Linq.Expressions/tests/System.Linq.Expressions.Tests.csproj @@ -224,9 +224,8 @@ - - Common\System\Collections\DictionaryExtensions.cs - + @@ -248,4 +247,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Linq.Parallel/tests/ParallelEnumerableTests.cs b/src/libraries/System.Linq.Parallel/tests/ParallelEnumerableTests.cs index eea02d8b45509a..5b716a1bd86cbf 100644 --- a/src/libraries/System.Linq.Parallel/tests/ParallelEnumerableTests.cs +++ b/src/libraries/System.Linq.Parallel/tests/ParallelEnumerableTests.cs @@ -39,7 +39,10 @@ public static IEnumerable RangeData() { foreach (int count in datapoints) { - yield return new object[] { start * sign, count }; + if (start != 0 || sign != -1) // don't yield a start*sign==0 twice + { + yield return new object[] { start * sign, count }; + } } } } @@ -183,8 +186,7 @@ public static IEnumerable RepeatData() //yield return new object[] { (decimal)element, count }; yield return new object[] { "" + element, count }; } - yield return new object[] { (object)null, count }; - yield return new object[] { (string)null, count }; + yield return new object[] { null, count }; } } diff --git a/src/libraries/System.Linq.Parallel/tests/System.Linq.Parallel.Tests.csproj b/src/libraries/System.Linq.Parallel/tests/System.Linq.Parallel.Tests.csproj index e7a85f6cc62c42..8b327c062a3e8f 100644 --- a/src/libraries/System.Linq.Parallel/tests/System.Linq.Parallel.Tests.csproj +++ b/src/libraries/System.Linq.Parallel/tests/System.Linq.Parallel.Tests.csproj @@ -4,15 +4,12 @@ $(NetCoreAppCurrent) - - Common\System\Diagnostics\Tracing\TestEventListener.cs - - - Common\System\ShouldNotBeInvokedException.cs - - - CommonTest\System\Threading\ThreadPoolHelpers.cs - + + + diff --git a/src/libraries/System.Linq.Queryable/tests/System.Linq.Queryable.Tests.csproj b/src/libraries/System.Linq.Queryable/tests/System.Linq.Queryable.Tests.csproj index ad309e2f7319b6..55af483dac0596 100644 --- a/src/libraries/System.Linq.Queryable/tests/System.Linq.Queryable.Tests.csproj +++ b/src/libraries/System.Linq.Queryable/tests/System.Linq.Queryable.Tests.csproj @@ -53,8 +53,7 @@ - - Common\System\Linq\SkipTakeData.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Linq/src/System.Linq.csproj b/src/libraries/System.Linq/src/System.Linq.csproj index 3b6ec801b5a492..a9caa2e36d3ea9 100644 --- a/src/libraries/System.Linq/src/System.Linq.csproj +++ b/src/libraries/System.Linq/src/System.Linq.csproj @@ -29,26 +29,20 @@ - - System\Collections\Generic\LargeArrayBuilder.SpeedOpt.cs - + - - System\Collections\Generic\ArrayBuilder.cs - - - System\Collections\Generic\EnumerableHelpers.cs - - - System\Collections\Generic\EnumerableHelpers.Linq.cs - - - System\Collections\Generic\LargeArrayBuilder.cs - - - System\Collections\Generic\SparseArrayBuilder.cs - + + + + + diff --git a/src/libraries/System.Linq/src/System/Linq/First.cs b/src/libraries/System.Linq/src/System/Linq/First.cs index 95ada9a81cf4ea..8763d207c133de 100644 --- a/src/libraries/System.Linq/src/System/Linq/First.cs +++ b/src/libraries/System.Linq/src/System/Linq/First.cs @@ -89,11 +89,6 @@ private static TSource TryGetFirst(this IEnumerable source, Fu ThrowHelper.ThrowArgumentNullException(ExceptionArgument.predicate); } - if (source is OrderedEnumerable ordered) - { - return ordered.TryGetFirst(predicate, out found); - } - foreach (TSource element in source) { if (predicate(element)) diff --git a/src/libraries/System.Linq/src/System/Linq/OrderedEnumerable.cs b/src/libraries/System.Linq/src/System/Linq/OrderedEnumerable.cs index da0ed0c7c47692..f28f7efa672de5 100644 --- a/src/libraries/System.Linq/src/System/Linq/OrderedEnumerable.cs +++ b/src/libraries/System.Linq/src/System/Linq/OrderedEnumerable.cs @@ -73,40 +73,6 @@ internal IEnumerator GetEnumerator(int minIdx, int maxIdx) IOrderedEnumerable IOrderedEnumerable.CreateOrderedEnumerable(Func keySelector, IComparer? comparer, bool descending) => new OrderedEnumerable(_source, keySelector, comparer, @descending, this); - [return: MaybeNull] - public TElement TryGetFirst(Func predicate, out bool found) - { - CachingComparer comparer = GetComparer(); - using (IEnumerator e = _source.GetEnumerator()) - { - TElement value; - do - { - if (!e.MoveNext()) - { - found = false; - return default!; - } - - value = e.Current; - } - while (!predicate(value)); - - comparer.SetElement(value); - while (e.MoveNext()) - { - TElement x = e.Current; - if (predicate(x) && comparer.Compare(x, true) < 0) - { - value = x; - } - } - - found = true; - return value; - } - } - [return: MaybeNull] public TElement TryGetLast(Func predicate, out bool found) { diff --git a/src/libraries/System.Linq/tests/OrderByTests.cs b/src/libraries/System.Linq/tests/OrderByTests.cs index 8c99b5668c763f..627becd98800b5 100644 --- a/src/libraries/System.Linq/tests/OrderByTests.cs +++ b/src/libraries/System.Linq/tests/OrderByTests.cs @@ -291,6 +291,38 @@ public void FirstOnEmptyOrderedThrows() Assert.Throws(() => Enumerable.Empty().OrderBy(i => i).First()); } + [Fact] + public void FirstWithPredicateOnOrdered() + { + IEnumerable orderBy = Enumerable.Range(0, 10).Shuffle().OrderBy(i => i); + IEnumerable orderByDescending = Enumerable.Range(0, 10).Shuffle().OrderByDescending(i => i); + int counter; + + counter = 0; + Assert.Equal(0, orderBy.First(i => { counter++; return true; })); + Assert.Equal(1, counter); + + counter = 0; + Assert.Equal(9, orderBy.First(i => { counter++; return i == 9; })); + Assert.Equal(10, counter); + + counter = 0; + Assert.Throws(() => orderBy.First(i => { counter++; return false; })); + Assert.Equal(10, counter); + + counter = 0; + Assert.Equal(9, orderByDescending.First(i => { counter++; return true; })); + Assert.Equal(1, counter); + + counter = 0; + Assert.Equal(0, orderByDescending.First(i => { counter++; return i == 0; })); + Assert.Equal(10, counter); + + counter = 0; + Assert.Throws(() => orderByDescending.First(i => { counter++; return false; })); + Assert.Equal(10, counter); + } + [Fact] public void FirstOrDefaultOnOrdered() { @@ -300,6 +332,38 @@ public void FirstOrDefaultOnOrdered() Assert.Equal(0, Enumerable.Empty().OrderBy(i => i).FirstOrDefault()); } + [Fact] + public void FirstOrDefaultWithPredicateOnOrdered() + { + IEnumerable orderBy = Enumerable.Range(0, 10).Shuffle().OrderBy(i => i); + IEnumerable orderByDescending = Enumerable.Range(0, 10).Shuffle().OrderByDescending(i => i); + int counter; + + counter = 0; + Assert.Equal(0, orderBy.FirstOrDefault(i => { counter++; return true; })); + Assert.Equal(1, counter); + + counter = 0; + Assert.Equal(9, orderBy.FirstOrDefault(i => { counter++; return i == 9; })); + Assert.Equal(10, counter); + + counter = 0; + Assert.Equal(0, orderBy.FirstOrDefault(i => { counter++; return false; })); + Assert.Equal(10, counter); + + counter = 0; + Assert.Equal(9, orderByDescending.FirstOrDefault(i => { counter++; return true; })); + Assert.Equal(1, counter); + + counter = 0; + Assert.Equal(0, orderByDescending.FirstOrDefault(i => { counter++; return i == 0; })); + Assert.Equal(10, counter); + + counter = 0; + Assert.Equal(0, orderByDescending.FirstOrDefault(i => { counter++; return false; })); + Assert.Equal(10, counter); + } + [Fact] public void LastOnOrdered() { diff --git a/src/libraries/System.Linq/tests/System.Linq.Tests.csproj b/src/libraries/System.Linq/tests/System.Linq.Tests.csproj index fe5b68dc5b1ebe..595a687a07f5d6 100644 --- a/src/libraries/System.Linq/tests/System.Linq.Tests.csproj +++ b/src/libraries/System.Linq/tests/System.Linq.Tests.csproj @@ -66,12 +66,10 @@ - - Common\System\Linq\SkipTakeData.cs - - - Common\System\Diagnostics\DebuggerAttributes.cs - + + diff --git a/src/libraries/System.Linq/tests/ToArrayTests.cs b/src/libraries/System.Linq/tests/ToArrayTests.cs index c6489ea4a7267c..07acb51e645119 100644 --- a/src/libraries/System.Linq/tests/ToArrayTests.cs +++ b/src/libraries/System.Linq/tests/ToArrayTests.cs @@ -332,9 +332,7 @@ public void NonConstantTimeCountEmptyPartitionSelectDiffTypeToArray() } [Theory] - [MemberData(nameof(JustBelowPowersOfTwoLengths))] - [MemberData(nameof(PowersOfTwoLengths))] - [MemberData(nameof(JustAbovePowersOfTwoLengths))] + [MemberData(nameof(ToArrayShouldWorkWithSpecialLengthLazyEnumerables_MemberData))] public void ToArrayShouldWorkWithSpecialLengthLazyEnumerables(int length) { Debug.Assert(length >= 0); @@ -371,34 +369,17 @@ public void ToArray_Cast() Assert.Equal(new[] { Enum1.First, Enum1.Second, Enum1.Third }, castArray); } - public static IEnumerable JustBelowPowersOfTwoLengths() + public static IEnumerable ToArrayShouldWorkWithSpecialLengthLazyEnumerables_MemberData() { - return SmallPowersOfTwo.Select(p => new object[] { p - 1 }); - } - - public static IEnumerable PowersOfTwoLengths() - { - return SmallPowersOfTwo.Select(p => new object[] { p }); - } - - public static IEnumerable JustAbovePowersOfTwoLengths() - { - return SmallPowersOfTwo.Select(p => new object[] { p + 1 }); - } - - private static IEnumerable SmallPowersOfTwo - { - get + // Return array sizes that should be small enough not to OOM + const int MaxPower = 18; + yield return new object[] { 1 }; + yield return new object[] { 2 }; + for (int i = 2; i <= MaxPower; i++) { - // By N being "small" we mean that allocating an array of - // size N doesn't come close to the risk of causing an OOME - - const int MaxPower = 18; - - for (int i = 0; i <= MaxPower; i++) - { - yield return 1 << i; // equivalent to pow(2, i) - } + yield return new object[] { (i << i) - 1 }; + yield return new object[] { (i << i) }; + yield return new object[] { (i << i) + 1 }; } } } diff --git a/src/libraries/System.Management/src/Resources/Strings.resx b/src/libraries/System.Management/src/Resources/Strings.resx index f740f60b40f998..40f915ba6f640e 100644 --- a/src/libraries/System.Management/src/Resources/Strings.resx +++ b/src/libraries/System.Management/src/Resources/Strings.resx @@ -1,4 +1,5 @@ - + + @@ -292,4 +293,7 @@ The native library '{0}' does not have all required functions. Please, update the .NET Framework. - + + The Query string supplied was invalid or improperly formed. Token `{0}` is expected + + \ No newline at end of file diff --git a/src/libraries/System.Management/src/System.Management.csproj b/src/libraries/System.Management/src/System.Management.csproj index e3a79752a63d86..ac50cd7a9b1bfa 100644 --- a/src/libraries/System.Management/src/System.Management.csproj +++ b/src/libraries/System.Management/src/System.Management.csproj @@ -3,44 +3,36 @@ true $(NoWarn);0618 true - SR.PlatformNotSupported_SystemManagement $(NetCoreAppCurrent)-Windows_NT;netstandard2.0;netcoreapp2.0-Windows_NT;_$(NetFrameworkCurrent) true - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Kernel32\Interop.FreeLibrary.cs - - - Common\Interop\Windows\Kernel32\Interop.GetProcAddress.cs - - - Common\Interop\Windows\Kernel32\Interop.GlobalLock.cs - - - Common\Interop\Windows\Kernel32\Interop.LoadLibrary.cs - - - Common\Interop\Windows\Ole32\Interop.CoGetObjectContext.cs - - - Common\Interop\Windows\Ole32\Interop.CoMarshalInterface.cs - - - Common\Interop\Windows\Ole32\Interop.CoUnmarshalInterface.cs - - - Common\Interop\Windows\Ole32\Interop.CreateStreamOnHGlobal.cs - - - Common\Interop\Windows\Ole32\Interop.GetHGlobalFromStream.cs - - - Common\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs - + + + SR.PlatformNotSupported_SystemManagement + + + + + + + + + + + + + @@ -72,7 +64,7 @@ - + @@ -87,4 +79,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Management/src/System/Management/ManagementDateTime.cs b/src/libraries/System.Management/src/System/Management/ManagementDateTime.cs index 27114f9453b219..6a71452dc11204 100644 --- a/src/libraries/System.Management/src/System/Management/ManagementDateTime.cs +++ b/src/libraries/System.Management/src/System/Management/ManagementDateTime.cs @@ -415,7 +415,7 @@ public static string ToDmtfTimeInterval(TimeSpan timespan) // and also negative timespan cannot be represented in DMTF if (timespan.Days > MAXDATE_INTIMESPAN || timespan < TimeSpan.Zero) { - throw new System.ArgumentOutOfRangeException(); + throw new System.ArgumentOutOfRangeException(nameof(timespan)); } dmtftimespan = (dmtftimespan + timespan.Hours.ToString(frmInt32).PadLeft(2, '0')); diff --git a/src/libraries/System.Management/src/System/Management/ManagementQuery.cs b/src/libraries/System.Management/src/System/Management/ManagementQuery.cs index 62797f9dbd3e5d..1c49c3019e4de6 100644 --- a/src/libraries/System.Management/src/System/Management/ManagementQuery.cs +++ b/src/libraries/System.Management/src/System/Management/ManagementQuery.cs @@ -1040,13 +1040,13 @@ protected internal override void ParseQuery(string query) // Should start with "select" if ((q.Length < keyword.Length) || (0 != string.Compare(q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase))) - throw new ArgumentException(SR.InvalidQuery, "select"); + throw new ArgumentException(SR.Format(SR.InvalidQueryTokenExpected, keyword), nameof(query)); q = q.Remove(0, keyword.Length).TrimStart(null); // Next should be a '*' if (0 != q.IndexOf('*', 0)) - throw new ArgumentException(SR.InvalidQuery, "*"); + throw new ArgumentException(SR.Format(SR.InvalidQueryTokenExpected, "*"), nameof(query)); q = q.Remove(0, 1).TrimStart(null); @@ -1055,7 +1055,7 @@ protected internal override void ParseQuery(string query) if ((q.Length < keyword.Length) || (0 != string.Compare(q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase))) - throw new ArgumentException(SR.InvalidQuery, "from"); + throw new ArgumentException(SR.Format(SR.InvalidQueryTokenExpected, keyword), nameof(query)); q = q.Remove(0, keyword.Length).TrimStart(null); @@ -1064,7 +1064,7 @@ protected internal override void ParseQuery(string query) if ((q.Length < keyword.Length) || (0 != string.Compare(q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase))) - throw new ArgumentException(SR.InvalidQuery, "meta_class"); + throw new ArgumentException(SR.Format(SR.InvalidQueryTokenExpected, keyword), nameof(query)); q = q.Remove(0, keyword.Length).TrimStart(null); @@ -1076,7 +1076,7 @@ protected internal override void ParseQuery(string query) if ((q.Length < keyword.Length) || (0 != string.Compare(q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase))) - throw new ArgumentException(SR.InvalidQuery, "where"); + throw new ArgumentException(SR.Format(SR.InvalidQueryTokenExpected, keyword), nameof(query)); q = q.Remove(0, keyword.Length); @@ -1650,7 +1650,7 @@ protected internal override void ParseQuery(string query) //Find "associators" clause if (0 != string.Compare(q, 0, TokenAssociators, 0, TokenAssociators.Length, StringComparison.OrdinalIgnoreCase)) - throw new ArgumentException(SR.InvalidQuery, "associators"); // Invalid query + throw new ArgumentException(SR.Format(SR.InvalidQueryTokenExpected, TokenAssociators), nameof(query)); // Invalid query // Strip off the clause q = q.Remove(0, TokenAssociators.Length); @@ -1663,7 +1663,7 @@ protected internal override void ParseQuery(string query) // Next token should be "of" if (0 != string.Compare(q, 0, TokenOf, 0, TokenOf.Length, StringComparison.OrdinalIgnoreCase)) - throw new ArgumentException(SR.InvalidQuery, "of"); // Invalid query + throw new ArgumentException(SR.Format(SR.InvalidQueryTokenExpected, TokenOf), nameof(query)); // Invalid query // Strip off the clause and leading WS q = q.Remove(0, TokenOf.Length).TrimStart(null); @@ -1687,7 +1687,7 @@ protected internal override void ParseQuery(string query) { // Next should be the "where" clause if (0 != string.Compare(q, 0, TokenWhere, 0, TokenWhere.Length, StringComparison.OrdinalIgnoreCase)) - throw new ArgumentException(SR.InvalidQuery, "where"); // Invalid query + throw new ArgumentException(SR.Format(SR.InvalidQueryTokenExpected, TokenWhere), nameof(query)); // Invalid query q = q.Remove(0, TokenWhere.Length); @@ -2167,7 +2167,7 @@ protected internal override void ParseQuery(string query) //Find "references" clause if (0 != string.Compare(q, 0, TokenReferences, 0, TokenReferences.Length, StringComparison.OrdinalIgnoreCase)) - throw new ArgumentException(SR.InvalidQuery, "references"); // Invalid query + throw new ArgumentException(SR.Format(SR.InvalidQueryTokenExpected, TokenReferences), nameof(query)); // Invalid query // Strip off the clause q = q.Remove(0, TokenReferences.Length); @@ -2180,7 +2180,7 @@ protected internal override void ParseQuery(string query) // Next token should be "of" if (0 != string.Compare(q, 0, TokenOf, 0, TokenOf.Length, StringComparison.OrdinalIgnoreCase)) - throw new ArgumentException(SR.InvalidQuery, "of"); // Invalid query + throw new ArgumentException(SR.Format(SR.InvalidQueryTokenExpected, TokenOf), nameof(query)); // Invalid query // Strip off the clause and leading WS q = q.Remove(0, TokenOf.Length).TrimStart(null); @@ -2204,7 +2204,7 @@ protected internal override void ParseQuery(string query) { // Next should be the "where" clause if (0 != string.Compare(q, 0, TokenWhere, 0, TokenWhere.Length, StringComparison.OrdinalIgnoreCase)) - throw new ArgumentException(SR.InvalidQuery, "where"); // Invalid query + throw new ArgumentException(SR.Format(SR.InvalidQueryTokenExpected, TokenWhere), nameof(query)); // Invalid query q = q.Remove(0, TokenWhere.Length); @@ -3043,13 +3043,13 @@ protected internal override void ParseQuery(string query) q = q.Remove(0, keyword.Length).TrimStart(null); if (!q.StartsWith("*", StringComparison.Ordinal)) - throw new ArgumentException(SR.InvalidQuery, "*"); + throw new ArgumentException(SR.Format(SR.InvalidQueryTokenExpected, "*"), nameof(query)); q = q.Remove(0, 1).TrimStart(null); //Find "from" clause keyword = "from "; if ((q.Length < keyword.Length) || (0 != string.Compare(q, 0, keyword, 0, keyword.Length, StringComparison.OrdinalIgnoreCase))) - throw new ArgumentException(SR.InvalidQuery, "from"); + throw new ArgumentException(SR.Format(SR.InvalidQueryTokenExpected, keyword), nameof(query)); ParseToken(ref q, keyword, null, ref bFound, ref eventClassName); //Find "within" clause @@ -3119,7 +3119,7 @@ protected internal override void ParseQuery(string query) q = q.Remove(0, keyword.Length); if (q.Length == 0) //bad query - throw new ArgumentException(SR.InvalidQuery, "having"); + throw new ArgumentException(SR.Format(SR.InvalidQueryTokenExpected, keyword), nameof(query)); havingCondition = q; } diff --git a/src/libraries/System.Memory/src/System.Memory.csproj b/src/libraries/System.Memory/src/System.Memory.csproj index bada3e64b157c4..a17e97c5713762 100644 --- a/src/libraries/System.Memory/src/System.Memory.csproj +++ b/src/libraries/System.Memory/src/System.Memory.csproj @@ -34,11 +34,10 @@ - - Common\System\Buffers\ArrayBufferWriter.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Memory/tests/System.Memory.Tests.csproj b/src/libraries/System.Memory/tests/System.Memory.Tests.csproj index ce1cdff0d5c2b2..d9b36dc5649f8e 100644 --- a/src/libraries/System.Memory/tests/System.Memory.Tests.csproj +++ b/src/libraries/System.Memory/tests/System.Memory.Tests.csproj @@ -15,9 +15,11 @@ - + - + @@ -169,9 +171,8 @@ - - ReadOnlySpan\StringTests.cs - + @@ -260,11 +261,9 @@ - - Common\System\Buffers\NativeMemoryManager.cs - - - Common\System\MutableDecimal.cs - + + - \ No newline at end of file + diff --git a/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.csproj b/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.csproj index b59dd09ae596cb..af8add8a69fa8f 100644 --- a/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.csproj +++ b/src/libraries/System.Net.Http.Json/ref/System.Net.Http.Json.csproj @@ -1,6 +1,6 @@ - + - netstandard2.0;$(NetCoreAppCurrent) + $(NetCoreAppCurrent);netstandard2.0 enable diff --git a/src/libraries/System.Net.Http.Json/src/Resources/Strings.resx b/src/libraries/System.Net.Http.Json/src/Resources/Strings.resx index 1722e93d5009d7..332b5e17c461c5 100644 --- a/src/libraries/System.Net.Http.Json/src/Resources/Strings.resx +++ b/src/libraries/System.Net.Http.Json/src/Resources/Strings.resx @@ -127,7 +127,7 @@ The character set provided in ContentType is not supported. - The provided ContentType is not supported; the supported types are 'application/json' and the structured syntax suffix 'application/+json'. + The provided ContentType '{0}' is not supported; the supported types are 'application/json' and the structured syntax suffix 'application/+json'. The specified type {0} must derive from the specific value's type {1}. diff --git a/src/libraries/System.Net.Http.Json/src/System.Net.Http.Json.csproj b/src/libraries/System.Net.Http.Json/src/System.Net.Http.Json.csproj index 04dd510bb1c79f..bb01bd45dbb169 100644 --- a/src/libraries/System.Net.Http.Json/src/System.Net.Http.Json.csproj +++ b/src/libraries/System.Net.Http.Json/src/System.Net.Http.Json.csproj @@ -1,4 +1,4 @@ - + netstandard2.0;$(NetCoreAppCurrent) enable @@ -9,8 +9,6 @@ - - @@ -21,6 +19,8 @@ + + diff --git a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpContentJsonExtensions.cs b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpContentJsonExtensions.cs index 6d1d309760f3a9..0d76a030f9fca9 100644 --- a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpContentJsonExtensions.cs +++ b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/HttpContentJsonExtensions.cs @@ -19,7 +19,7 @@ public static class HttpContentJsonExtensions Debug.Assert(content.Headers.ContentType != null); Encoding? sourceEncoding = JsonContent.GetEncoding(content.Headers.ContentType.CharSet); - return ReadFromJsonAsyncCore(content, type, sourceEncoding, options ?? JsonContent.DefaultSerializerOptions, cancellationToken); + return ReadFromJsonAsyncCore(content, type, sourceEncoding, options, cancellationToken); } public static Task ReadFromJsonAsync(this HttpContent content, JsonSerializerOptions? options = null, CancellationToken cancellationToken = default) @@ -28,7 +28,7 @@ public static Task ReadFromJsonAsync(this HttpContent content, JsonSeriali Debug.Assert(content.Headers.ContentType != null); Encoding? sourceEncoding = JsonContent.GetEncoding(content.Headers.ContentType.CharSet); - return ReadFromJsonAsyncCore(content, sourceEncoding, options ?? JsonContent.DefaultSerializerOptions, cancellationToken); + return ReadFromJsonAsyncCore(content, sourceEncoding, options, cancellationToken); } private static async Task ReadFromJsonAsyncCore(HttpContent content, Type type, Encoding? sourceEncoding, JsonSerializerOptions? options, CancellationToken cancellationToken) @@ -38,12 +38,16 @@ public static Task ReadFromJsonAsync(this HttpContent content, JsonSeriali // Wrap content stream into a transcoding stream that buffers the data transcoded from the sourceEncoding to utf-8. if (sourceEncoding != null && sourceEncoding != Encoding.UTF8) { +#if NETCOREAPP + contentStream = Encoding.CreateTranscodingStream(contentStream, innerStreamEncoding: sourceEncoding, outerStreamEncoding: Encoding.UTF8); +#else contentStream = new TranscodingReadStream(contentStream, sourceEncoding); +#endif } using (contentStream) { - return await JsonSerializer.DeserializeAsync(contentStream, type, options, cancellationToken).ConfigureAwait(false); + return await JsonSerializer.DeserializeAsync(contentStream, type, options ?? JsonContent.s_defaultSerializerOptions, cancellationToken).ConfigureAwait(false); } } @@ -54,12 +58,16 @@ private static async Task ReadFromJsonAsyncCore(HttpContent content, Encod // Wrap content stream into a transcoding stream that buffers the data transcoded from the sourceEncoding to utf-8. if (sourceEncoding != null && sourceEncoding != Encoding.UTF8) { +#if NETCOREAPP + contentStream = Encoding.CreateTranscodingStream(contentStream, innerStreamEncoding: sourceEncoding, outerStreamEncoding: Encoding.UTF8); +#else contentStream = new TranscodingReadStream(contentStream, sourceEncoding); +#endif } using (contentStream) { - return await JsonSerializer.DeserializeAsync(contentStream, options, cancellationToken).ConfigureAwait(false); + return await JsonSerializer.DeserializeAsync(contentStream, options ?? JsonContent.s_defaultSerializerOptions, cancellationToken).ConfigureAwait(false); } } @@ -76,7 +84,7 @@ private static void ValidateContent(HttpContent content) !mediaType.Equals(JsonContent.JsonMediaType, StringComparison.OrdinalIgnoreCase) && !IsValidStructuredSyntaxJsonSuffix(mediaType.AsSpan())) { - throw new NotSupportedException(SR.ContentTypeNotSupported); + throw new NotSupportedException(SR.Format(SR.ContentTypeNotSupported, mediaType)); } } diff --git a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.cs b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.cs index a84d375b137c1f..20a2133ccb7024 100644 --- a/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.cs +++ b/src/libraries/System.Net.Http.Json/src/System/Net/Http/Json/JsonContent.cs @@ -20,8 +20,8 @@ public sealed partial class JsonContent : HttpContent private static MediaTypeHeaderValue DefaultMediaType => new MediaTypeHeaderValue(JsonMediaType) { CharSet = "utf-8" }; - internal static JsonSerializerOptions DefaultSerializerOptions - => new JsonSerializerOptions { PropertyNameCaseInsensitive = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; + internal static readonly JsonSerializerOptions s_defaultSerializerOptions + = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; private readonly JsonSerializerOptions? _jsonSerializerOptions; public Type ObjectType { get; } @@ -42,7 +42,7 @@ private JsonContent(object? inputValue, Type inputType, MediaTypeHeaderValue? me Value = inputValue; ObjectType = inputType; Headers.ContentType = mediaType ?? DefaultMediaType; - _jsonSerializerOptions = options ?? DefaultSerializerOptions; + _jsonSerializerOptions = options ?? s_defaultSerializerOptions; } public static JsonContent Create(T inputValue, MediaTypeHeaderValue? mediaType = null, JsonSerializerOptions? options = null) @@ -67,6 +67,19 @@ private async Task SerializeToStreamAsyncCore(Stream targetStream, CancellationT // Wrap provided stream into a transcoding stream that buffers the data transcoded from utf-8 to the targetEncoding. if (targetEncoding != null && targetEncoding != Encoding.UTF8) { +#if NETCOREAPP + Stream transcodingStream = Encoding.CreateTranscodingStream(targetStream, targetEncoding, Encoding.UTF8, leaveOpen: true); + try + { + await JsonSerializer.SerializeAsync(transcodingStream, Value, ObjectType, _jsonSerializerOptions, cancellationToken).ConfigureAwait(false); + } + finally + { + // DisposeAsync will flush any partial write buffers. In practice our partial write + // buffers should be empty as we expect JsonSerializer to emit only well-formed UTF-8 data. + await transcodingStream.DisposeAsync().ConfigureAwait(false); + } +#else using (TranscodingWriteStream transcodingStream = new TranscodingWriteStream(targetStream, targetEncoding)) { await JsonSerializer.SerializeAsync(transcodingStream, Value, ObjectType, _jsonSerializerOptions, cancellationToken).ConfigureAwait(false); @@ -75,6 +88,7 @@ private async Task SerializeToStreamAsyncCore(Stream targetStream, CancellationT // acceptable to Flush a Stream (multiple times) prior to completion. await transcodingStream.FinalWriteAsync(cancellationToken).ConfigureAwait(false); } +#endif } else { diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/System.Net.Http.Json.Functional.Tests.csproj b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/System.Net.Http.Json.Functional.Tests.csproj index 278e36d4e102c0..ed58820d081f1a 100644 --- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/System.Net.Http.Json.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/System.Net.Http.Json.Functional.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) @@ -10,32 +10,23 @@ - - Common\System\Net\Capability.Security.cs - - - Common\System\Net\Configuration.cs - - - Common\System\Net\Configuration.Certificates.cs - - - Common\System\Net\Configuration.Http.cs - - - Common\System\Net\Configuration.Security.cs - - - Common\System\Net\Http\LoopbackServer.cs - - - Common\System\Net\Http\LoopbackServer.AuthenticationHelpers.cs - - - Common\System\Net\Http\GenericLoopbackServer.cs - - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - + + + + + + + + + diff --git a/src/libraries/System.Net.Http.Json/tests/UnitTests/System.Net.Http.Json.Unit.Tests.csproj b/src/libraries/System.Net.Http.Json/tests/UnitTests/System.Net.Http.Json.Unit.Tests.csproj index 4b7b36a6be21f5..0f09eb18d9f7a9 100644 --- a/src/libraries/System.Net.Http.Json/tests/UnitTests/System.Net.Http.Json.Unit.Tests.csproj +++ b/src/libraries/System.Net.Http.Json/tests/UnitTests/System.Net.Http.Json.Unit.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) @@ -7,16 +7,13 @@ - - ProductionCode\System\ArraySegmentExtensions.netstandard.cs - + - - ProductionCode\System\Net\Http\Json\TranscodingReadStream.cs - - - ProductionCode\System\Net\Http\Json\TranscodingWriteStream.cs - + + diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj b/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj index c402b8d09db8af..5a0609a36ed0e3 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj @@ -1,7 +1,6 @@ - + AnyCPU - SR.PlatformNotSupported_WinHttpHandler true netstandard2.0-Windows_NT;netstandard2.0;net461-Windows_NT;$(NetFrameworkCurrent)-Windows_NT true @@ -9,86 +8,63 @@ $(DefineConstants);WINHTTPHANDLER_DLL annotations + + + SR.PlatformNotSupported_WinHttpHandler + - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Crypt32\Interop.CertEnumCertificatesInStore.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates_types.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates.cs - - - Common\Interop\Windows\Kernel32\Interop.FormatMessage.cs - - - Common\Interop\Windows\Kernel32\Interop.GetModuleHandle.cs - - - Common\Interop\Windows\Interop.HRESULT_FROM_WIN32.cs - - - Common\Interop\Windows\SChannel\UnmanagedCertificateContext.IntPtr.cs - - - Common\Interop\Windows\WinHttp\Interop.SafeWinHttpHandle.cs - - - Common\Interop\Windows\WinHttp\Interop.winhttp_types.cs - - - Common\Interop\Windows\WinHttp\Interop.winhttp.cs - - - Common\System\CharArrayHelpers.cs - - - Common\System\StringExtensions.cs - - - Common\System\Net\HttpKnownHeaderNames.cs - - - Common\System\Net\HttpKnownHeaderNames.TryGetHeaderName.cs - - - Common\System\Net\Http\HttpStatusDescription.cs - - - Common\System\Net\SecurityProtocol.cs - - - Common\System\Net\UriScheme.cs - - - Common\System\Net\Http\HttpHandlerDefaults.cs - - - Common\System\Net\Http\NoWriteNoSeekStreamContent.cs - - - Common\System\Net\Http\WinInetProxyHelper.cs - - - Common\System\Net\Security\CertificateHelper.cs - - - Common\System\Net\Security\CertificateHelper.Windows.cs - - - Common\System\Runtime\ExceptionServices\ExceptionStackTrace.cs - - - Common\System\Threading\Tasks\RendezvousAwaitable.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -103,19 +79,17 @@ - - Common\System\IO\StreamHelpers.CopyValidation.cs - - - Common\System\Net\Logging\NetEventSource.Common.cs - + + - + diff --git a/src/libraries/Common/src/System/Net/Http/NoWriteNoSeekStreamContent.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/NoWriteNoSeekStreamContent.cs similarity index 100% rename from src/libraries/Common/src/System/Net/Http/NoWriteNoSeekStreamContent.cs rename to src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/NoWriteNoSeekStreamContent.cs diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj index 66515bbd3e1bf1..98985ef8fc344b 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent)-Windows_NT;$(NetFrameworkCurrent)-Windows_NT true @@ -6,194 +6,133 @@ 8.0 - - Common\System\Net\Configuration.cs - - - Common\System\Net\Configuration.Http.cs - + + - - Common\System\Net\Http\HttpHandlerDefaults.cs - - - Common\System\IO\DelegateStream.cs - - - Common\System\Net\Configuration.Certificates.cs - - - Common\System\Net\Configuration.Security.cs - - - Common\System\Net\Configuration.Sockets.cs - - - Common\System\Net\Capability.Security.cs - - - Common\System\Net\Capability.Security.Windows.cs - - - Common\System\Net\EventSourceTestLogging.cs - - - Common\System\Net\HttpsTestServer.cs - - - Common\System\Net\RemoteServerQuery.cs - - - Common\System\Net\VerboseTestLogging.cs - - - Common\System\Net\TestWebProxies.cs - - - Common\System\Net\StreamArrayExtensions.cs - - - Common\System\Net\Http\ByteAtATimeContent.cs - - - Common\System\Net\Http\ChannelBindingAwareContent.cs - - - Common\System\Net\Http\CustomContent.cs - - - Common\System\Net\Http\DefaultCredentialsTest.cs - - - Common\System\Net\Http\DribbleStream.cs - - - Common\System\Net\Http\GenericLoopbackServer.cs - - - Common\System\Net\Http\HttpClientHandlerTestBase.cs - - - Common\System\Net\Http\Http2Frames.cs - - - Common\System\Net\Http\HPackEncoder.cs - - - Common\System\Net\Http\Http2LoopbackServer.cs - - - Common\System\Net\Http\Http2LoopbackConnection.cs - - - Common\System\Net\Http\QPackTestDecoder.cs - - - Common\System\Net\Http\QPackTestEncoder.cs - - - Common\System\Net\Http\HuffmanDecoder.cs - - - Common\System\Net\Http\HuffmanEncoder.cs - - - Common\System\Net\Http\HttpClientHandlerTest.cs - - - Common\System\Net\Http\HttpClientHandlerTest.AcceptAllCerts.cs - - - Common\System\Net\Http\HttpClientHandlerTest.Asynchrony.cs - - - Common\System\Net\Http\HttpClientHandlerTest.Authentication.cs - - - Common\System\Net\Http\HttpClientHandlerTest.AutoRedirect.cs - - - Common\System\Net\Http\HttpClientHandlerTest.Cancellation.cs - - - Common\System\Net\Http\HttpClientHandlerTest.ClientCertificates.cs - - - Common\System\Net\Http\HttpClientHandlerTest.Cookies.cs - - - Common\System\Net\Http\HttpClientHandlerTest.Decompression.cs - - - Common\System\Net\Http\HttpClientHandlerTest.DefaultProxyCredentials.cs - - - Common\System\Net\Http\HttpClientHandlerTest.MaxConnectionsPerServer.cs - - - Common\System\Net\Http\HttpClientHandlerTest.MaxResponseHeadersLength.cs - - - Common\System\Net\Http\HttpClientHandlerTest.Proxy.cs - - - Common\System\Net\Http\HttpClientHandlerTest.ServerCertificates.cs - - - Common\System\Net\Http\HttpClientHandlerTest.SslProtocols.cs - - - Common\System\Net\Http\HttpProtocolTests.cs - - - Common\System\Net\Http\HttpClient.SelectedSitesTest.cs - - - Common\System\Net\Http\HttpClientEKUTest.cs - - - Common\System\Net\Http\HttpRetryProtocolTests.cs - - - Common\System\Net\Http\IdnaProtocolTests.cs - - - Common\System\Net\Http\LoopbackProxyServer.cs - - - Common\System\Net\Http\LoopbackServer.cs - - - Common\System\Net\Http\LoopbackServer.AuthenticationHelpers.cs - - - Common\System\Net\Http\TestHelper.cs - - - Common\System\Net\Http\PostScenarioTest.cs - - - Common\System\Net\Http\RepeatedFlushContent.cs - - - Common\System\Net\Http\ResponseStreamTest.cs - - - Common\System\Net\Http\SchSendAuxRecordHttpTest.cs - - - Common\System\Net\Http\SyncBlockingContent.cs - - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - - - Common\System\Threading\TrackingSynchronizationContext.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj b/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj index 9d1e3ba1e79cff..502c0cc8e46e8c 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj @@ -11,138 +11,94 @@ - - CommonTest\System\Net\SslProtocolSupport.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Crypt32\Interop.CertEnumCertificatesInStore.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates_types.cs - - - Common\Interop\Windows\Interop.HRESULT_FROM_WIN32.cs - - - Common\Interop\Windows\SChannel\UnmanagedCertificateContext.IntPtr.cs - - - Common\Interop\Windows\WinHttp\Interop.SafeWinHttpHandle.cs - - - Common\Interop\Windows\WinHttp\Interop.winhttp_types.cs - - - Common\System\CharArrayHelpers.cs - - - Common\System\StringExtensions.cs - - - Common\System\IO\StreamHelpers.CopyValidation.cs - - - Common\System\Net\HttpKnownHeaderNames.cs - - - Common\System\Net\HttpKnownHeaderNames.TryGetHeaderName.cs - - - Common\System\Net\HttpStatusDescription.cs - - - Common\System\Net\Logging\NetEventSource.Common.cs - - - Common\System\Net\UriScheme.cs - - - Common\System\Net\SecurityProtocol.cs - - - Common\System\Net\Http\HttpHandlerDefaults.cs - - - Common\System\Net\Http\NoWriteNoSeekStreamContent.cs - - - Common\System\Net\Http\WinInetProxyHelper.cs - - - Common\System\Net\Security\CertificateHelper.cs - - - Common\System\Net\Security\CertificateHelper.Windows.cs - - - Common\System\Runtime\ExceptionServices\ExceptionStackTrace.cs - - - Common\System\Text\SimpleRegex.cs - - - Common\System\Threading\Tasks\RendezvousAwaitable.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - - - ProductionCode\WinHttpAuthHelper.cs - - - ProductionCode\WinHttpCertificateHelper.cs - - - ProductionCode\WinHttpChannelBinding.cs - - - ProductionCode\WinHttpCookieContainerAdapter.cs - - - ProductionCode\WinHttpException.cs - - - ProductionCode\WinHttpHandler.cs - - - ProductionCode\WinHttpRequestCallback.cs - - - ProductionCode\WinHttpRequestState.cs - - - ProductionCode\WinHttpRequestStream.cs - - - ProductionCode\WinHttpResponseHeaderReader.cs - - - ProductionCode\WinHttpResponseParser.cs - - - ProductionCode\WinHttpResponseStream.cs - - - ProductionCode\WinHttpTraceHelper.cs - - - ProductionCode\WinHttpTransportContext.cs - - - ProductionCode\HttpWindowsProxy.cs - - - ProductionCode\FailedProxyCache.cs - - - ProductionCode\IMultiWebProxy.cs - - - ProductionCode\MultiProxy.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Net.Http/ref/System.Net.Http.cs b/src/libraries/System.Net.Http/ref/System.Net.Http.cs index 131f048c0d847f..91d4676d3ab998 100644 --- a/src/libraries/System.Net.Http/ref/System.Net.Http.cs +++ b/src/libraries/System.Net.Http/ref/System.Net.Http.cs @@ -99,7 +99,7 @@ public HttpClientHandler() { } public System.Security.Cryptography.X509Certificates.X509CertificateCollection ClientCertificates { get { throw null; } } public System.Net.CookieContainer CookieContainer { get { throw null; } set { } } public System.Net.ICredentials? Credentials { get { throw null; } set { } } - public static System.Func DangerousAcceptAnyServerCertificateValidator { get { throw null; } } + public static System.Func DangerousAcceptAnyServerCertificateValidator { get { throw null; } } public System.Net.ICredentials? DefaultProxyCredentials { get { throw null; } set { } } public int MaxAutomaticRedirections { get { throw null; } set { } } public int MaxConnectionsPerServer { get { throw null; } set { } } @@ -209,7 +209,8 @@ public partial class HttpResponseMessage : System.IDisposable { public HttpResponseMessage() { } public HttpResponseMessage(System.Net.HttpStatusCode statusCode) { } - public System.Net.Http.HttpContent? Content { get { throw null; } set { } } + [System.Diagnostics.CodeAnalysis.AllowNull] + public System.Net.Http.HttpContent Content { get { throw null; } set { } } public System.Net.Http.Headers.HttpResponseHeaders Headers { get { throw null; } } public bool IsSuccessStatusCode { get { throw null; } } public string? ReasonPhrase { get { throw null; } set { } } @@ -268,7 +269,7 @@ public SocketsHttpHandler() { } public bool AllowAutoRedirect { get { throw null; } set { } } public System.Net.DecompressionMethods AutomaticDecompression { get { throw null; } set { } } public System.TimeSpan ConnectTimeout { get { throw null; } set { } } - [System.Diagnostics.CodeAnalysis.AllowNull] + [System.Diagnostics.CodeAnalysis.AllowNullAttribute] public System.Net.CookieContainer CookieContainer { get { throw null; } set { } } public System.Net.ICredentials? Credentials { get { throw null; } set { } } public System.Net.ICredentials? DefaultProxyCredentials { get { throw null; } set { } } @@ -321,7 +322,7 @@ public AuthenticationHeaderValue(string scheme, string? parameter) { } public static System.Net.Http.Headers.AuthenticationHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.AuthenticationHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.AuthenticationHeaderValue? parsedValue) { throw null; } } public partial class CacheControlHeaderValue : System.ICloneable { @@ -347,7 +348,7 @@ public CacheControlHeaderValue() { } public static System.Net.Http.Headers.CacheControlHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.CacheControlHeaderValue? parsedValue) { throw null; } + public static bool TryParse(string? input, out System.Net.Http.Headers.CacheControlHeaderValue? parsedValue) { throw null; } } public partial class ContentDispositionHeaderValue : System.ICloneable { @@ -367,7 +368,7 @@ public ContentDispositionHeaderValue(string dispositionType) { } public static System.Net.Http.Headers.ContentDispositionHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.ContentDispositionHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.ContentDispositionHeaderValue? parsedValue) { throw null; } } public partial class ContentRangeHeaderValue : System.ICloneable { @@ -385,7 +386,7 @@ public ContentRangeHeaderValue(long from, long to, long length) { } public static System.Net.Http.Headers.ContentRangeHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.ContentRangeHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.ContentRangeHeaderValue? parsedValue) { throw null; } } public partial class EntityTagHeaderValue : System.ICloneable { @@ -399,7 +400,7 @@ public EntityTagHeaderValue(string tag, bool isWeak) { } public static System.Net.Http.Headers.EntityTagHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.EntityTagHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.EntityTagHeaderValue? parsedValue) { throw null; } } public sealed partial class HttpContentHeaders : System.Net.Http.Headers.HttpHeaders { @@ -520,7 +521,7 @@ public MediaTypeHeaderValue(string mediaType) { } public static System.Net.Http.Headers.MediaTypeHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.MediaTypeHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.MediaTypeHeaderValue? parsedValue) { throw null; } } public sealed partial class MediaTypeWithQualityHeaderValue : System.Net.Http.Headers.MediaTypeHeaderValue, System.ICloneable { @@ -529,7 +530,7 @@ public MediaTypeWithQualityHeaderValue(string mediaType, double quality) : base public double? Quality { get { throw null; } set { } } public static new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.MediaTypeWithQualityHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.MediaTypeWithQualityHeaderValue? parsedValue) { throw null; } } public partial class NameValueHeaderValue : System.ICloneable { @@ -543,7 +544,7 @@ public NameValueHeaderValue(string name, string? value) { } public static System.Net.Http.Headers.NameValueHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.NameValueHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.NameValueHeaderValue? parsedValue) { throw null; } } public partial class NameValueWithParametersHeaderValue : System.Net.Http.Headers.NameValueHeaderValue, System.ICloneable { @@ -556,7 +557,7 @@ public NameValueWithParametersHeaderValue(string name, string? value) : base (de public static new System.Net.Http.Headers.NameValueWithParametersHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.NameValueWithParametersHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.NameValueWithParametersHeaderValue? parsedValue) { throw null; } } public partial class ProductHeaderValue : System.ICloneable { @@ -569,7 +570,7 @@ public ProductHeaderValue(string name, string? version) { } public static System.Net.Http.Headers.ProductHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, out System.Net.Http.Headers.ProductHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.ProductHeaderValue? parsedValue) { throw null; } } public partial class ProductInfoHeaderValue : System.ICloneable { @@ -583,7 +584,7 @@ public ProductInfoHeaderValue(string productName, string? productVersion) { } public static System.Net.Http.Headers.ProductInfoHeaderValue Parse(string input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.ProductInfoHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.ProductInfoHeaderValue? parsedValue) { throw null; } } public partial class RangeConditionHeaderValue : System.ICloneable { @@ -597,7 +598,7 @@ public RangeConditionHeaderValue(string entityTag) { } public static System.Net.Http.Headers.RangeConditionHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.RangeConditionHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.RangeConditionHeaderValue? parsedValue) { throw null; } } public partial class RangeHeaderValue : System.ICloneable { @@ -610,7 +611,7 @@ public RangeHeaderValue(long? from, long? to) { } public static System.Net.Http.Headers.RangeHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.RangeHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.RangeHeaderValue? parsedValue) { throw null; } } public partial class RangeItemHeaderValue : System.ICloneable { @@ -633,7 +634,7 @@ public RetryConditionHeaderValue(System.TimeSpan delta) { } public static System.Net.Http.Headers.RetryConditionHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.RetryConditionHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.RetryConditionHeaderValue? parsedValue) { throw null; } } public partial class StringWithQualityHeaderValue : System.ICloneable { @@ -646,7 +647,7 @@ public StringWithQualityHeaderValue(string value, double quality) { } public static System.Net.Http.Headers.StringWithQualityHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.StringWithQualityHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.StringWithQualityHeaderValue? parsedValue) { throw null; } } public partial class TransferCodingHeaderValue : System.ICloneable { @@ -659,7 +660,7 @@ public TransferCodingHeaderValue(string value) { } public static System.Net.Http.Headers.TransferCodingHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.TransferCodingHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.TransferCodingHeaderValue? parsedValue) { throw null; } } public sealed partial class TransferCodingWithQualityHeaderValue : System.Net.Http.Headers.TransferCodingHeaderValue, System.ICloneable { @@ -668,7 +669,7 @@ public TransferCodingWithQualityHeaderValue(string value, double quality) : base public double? Quality { get { throw null; } set { } } public static new System.Net.Http.Headers.TransferCodingWithQualityHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.TransferCodingWithQualityHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.TransferCodingWithQualityHeaderValue? parsedValue) { throw null; } } public partial class ViaHeaderValue : System.ICloneable { @@ -684,7 +685,7 @@ public ViaHeaderValue(string protocolVersion, string receivedBy, string? protoco public static System.Net.Http.Headers.ViaHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.ViaHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.ViaHeaderValue? parsedValue) { throw null; } } public partial class WarningHeaderValue : System.ICloneable { @@ -699,6 +700,6 @@ public WarningHeaderValue(int code, string agent, string text, System.DateTimeOf public static System.Net.Http.Headers.WarningHeaderValue Parse(string? input) { throw null; } object System.ICloneable.Clone() { throw null; } public override string ToString() { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.WarningHeaderValue? parsedValue) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Net.Http.Headers.WarningHeaderValue? parsedValue) { throw null; } } } diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index cebece24f4e13b..2f7eb9dc48f43e 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -1,4 +1,4 @@ - + Library System.Net.Http @@ -7,7 +7,7 @@ $(NoWarn);0436;CS1573 true $(DefineConstants);HTTP_DLL - $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-tvOS + $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-tvOS;$(NetCoreAppCurrent)-FreeBSD enable @@ -18,12 +18,15 @@ + + + @@ -89,33 +92,25 @@ - - Common\System\IO\StreamHelpers.CopyValidation.cs - - - Common\System\Net\Security\SslClientAuthenticationOptionsExtensions.cs - - - Common\System\IO\DelegatingStream.cs - - - Common\System\IO\ReadOnlyMemoryStream.cs - - - Common\System\Text\StringBuilderCache.cs - - - Common\System\Net\Logging\NetEventSource.Common.cs - - - Common\System\Net\HttpDateParser.cs - - - Common\System\Text\SimpleRegex.cs - - - Common\System\HexConverter.cs - + + + + + + + + + + Common\System\Net\ArrayBuffer.cs @@ -136,7 +131,6 @@ - @@ -150,7 +144,6 @@ - @@ -169,276 +162,192 @@ - - Common\System\Net\NTAuthentication.Common.cs - - - Common\System\Net\ContextFlagsPal.cs - - - Common\System\Net\Http\aspnetcore\IHttpHeadersHandler.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\DynamicTable.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HeaderField.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HPackDecoder.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HPackDecodingException.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HPackEncoder.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HPackEncodingException.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\Huffman.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HuffmanDecodingException.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\IntegerDecoder.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\IntegerEncoder.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\H2StaticTable.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\StatusCodes.cs - - - Common\System\Net\Http\aspnetcore\Http3\Http3SettingType.cs - - - Common\System\Net\Http\aspnetcore\Http3\Http3StreamType.cs - - - Common\System\Net\Http\aspnetcore\Http3\Helpers\VariableLengthIntegerHelper.cs - - - Common\System\Net\Http\aspnetcore\Http3\Frames\Http3ErrorCode.cs - - - Common\System\Net\Http\aspnetcore\Http3\Frames\Http3Frame.cs - - - Common\System\Net\Http\aspnetcore\Http3\Frames\Http3FrameType.cs - - - Common\System\Net\Http\aspnetcore\Http3\QPack\HeaderField.cs - - - Common\System\Net\Http\aspnetcore\Http3\QPack\QPackDecoder.cs - - - Common\System\Net\Http\aspnetcore\Http3\QPack\QPackDecodingException.cs - - - Common\System\Net\Http\aspnetcore\Http3\QPack\QPackEncoder.cs - - - Common\System\Net\Http\aspnetcore\Http3\QPack\QPackEncodingException.cs - - - Common\System\Net\Http\aspnetcore\Http3\QPack\H3StaticTable.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicAddressHelpers.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicApi.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicParameterHelpers.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicSecurityConfig.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicSession.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\QuicExceptionHelpers.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\ResettableCompletionSource.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\MsQuicConnection.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\MsQuicImplementationProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\MsQuicListener.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\MsQuicStream.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\QuicImplementationProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\QuicListenerProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\QuicConnectionProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\QuicStreamProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\Mock\MockImplementationProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\Mock\MockListener.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\Mock\MockConnection.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\Mock\MockStream.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\MsQuicStatusCodes.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\MsQuicStatusHelper.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicClientConnectionOptions.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicImplementationProviders.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicConnection.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicListener.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicListenerOptions.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicOperationAbortedException.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicStream.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicException.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicConnectionAbortedException.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicStreamAbortedException.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\Interop.MsQuic.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\MsQuicEnums.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\MsQuicNativeMethods.cs - - - Common\System\Net\SecurityStatusPal.cs - - - Common\System\Net\Security\SSPIHandleCache.cs - - - Common\System\Net\Security\NetEventSource.Security.cs - - - Common\System\Net\ExceptionCheck.cs - - - Common\System\Collections\Generic\BidirectionalDictionary.cs - - - Common\System\NotImplemented.cs - - - Common\System\Net\NegotiationInfoClass.cs - - - Common\System\Net\InternalException.cs - - - Common\System\Net\Logging\DebugThreadTracking.cs - - - Common\System\Net\DebugSafeHandle.cs - - - Common\System\Net\DebugCriticalHandleMinusOneIsInvalid.cs - - - Common\System\Net\DebugCriticalHandleZeroOrMinusOneIsInvalid.cs - - - Common\System\Text\ValueStringBuilder.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - Common\Interop\Linux\Interop.Libraries.cs - + + + + + - - Common\System\Net\ContextFlagsAdapterPal.Unix.cs - - - Common\System\Net\Security\Unix\SafeFreeCredentials.cs - - - Common\System\Net\Security\Unix\SafeDeleteContext.cs - - - Common\System\Net\Security\NegotiateStreamPal.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\GssSafeHandles.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.GssApiException.cs - - - Common\System\Net\Security\Unix\SafeFreeNegoCredentials.cs - - - Common\System\Net\Security\Unix\SecChannelBindings.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.IsNtlmInstalled.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.GssBuffer.cs - - - Common\System\Net\Security\Unix\SafeDeleteNegoContext.cs - + + + + + + + + + + + + @@ -447,383 +356,261 @@ - - Common\Interop\OSX\Interop.CoreFoundation.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFArray.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFData.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFDictionary.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFProxy.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFUrl.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFString.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFString.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFError.cs - - - Common\Interop\OSX\Interop.RunLoop.cs - - - Common\Interop\OSX\Interop.Libraries.cs - - - Common\Microsoft\Win32\SafeHandles\SafeCreateHandle.OSX.cs - + + + + + + + + + + + + - - Common\System\Net\HttpStatusDescription.cs - + - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Crypt32\Interop.CertEnumCertificatesInStore.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates_types.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates.cs - - - Common\Interop\Windows\Kernel32\Interop.FormatMessage.cs - - - Common\Interop\Windows\Kernel32\Interop.GetModuleHandle.cs - - - Common\Interop\Windows\Interop.HRESULT_FROM_WIN32.cs - - - Common\Interop\Windows\SChannel\UnmanagedCertificateContext.IntPtr.cs - - - Common\Interop\Windows\WinHttp\Interop.SafeWinHttpHandle.cs - - - Common\Interop\Windows\WinHttp\Interop.winhttp_types.cs - - - Common\Interop\Windows\WinHttp\Interop.winhttp.cs - - - Common\System\CharArrayHelpers.cs - - - Common\System\StringExtensions.cs - - - Common\System\Net\HttpKnownHeaderNames.cs - - - Common\System\Net\HttpKnownHeaderNames.TryGetHeaderName.cs - - - Common\System\Net\SecurityProtocol.cs - - - Common\System\Net\UriScheme.cs - - - Common\System\Net\Http\HttpHandlerDefaults.cs - - - Common\System\Net\Http\NoWriteNoSeekStreamContent.cs - - - Common\System\Net\Http\WinInetProxyHelper.cs - - - Common\System\Net\Security\CertificateHelper.cs - - - Common\System\Net\Security\CertificateHelper.Windows.cs - - - Common\System\Runtime\ExceptionServices\ExceptionStackTrace.cs - - - Common\System\Threading\Tasks\RendezvousAwaitable.cs - - - System\System\Threading\Tasks\TaskToApm.cs - - - Common\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs - - - Common\System\Net\Security\SecurityBuffer.Windows.cs - - - Common\System\Net\Security\SecurityBufferType.Windows.cs - - - Common\System\Net\Security\SecurityContextTokenHandle.cs - - - Common\System\Net\SecurityStatusAdapterPal.Windows.cs - - - Common\System\Net\ContextFlagsAdapterPal.Windows.cs - - - Common\System\Net\Security\NegotiateStreamPal.Windows.cs - - - Common\System\Net\Security\NetEventSource.Security.Windows.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_Bindings.cs - - - Common\Interop\Windows\SChannel\Interop.SECURITY_STATUS.cs - - - Common\Interop\Windows\Kernel32\Interop.CloseHandle.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_StreamSizes.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_NegotiationInfoW.cs - - - Common\Interop\Windows\SspiCli\NegotiationInfoClass.cs - - - Common\Interop\Windows\SChannel\SecPkgContext_ConnectionInfo.cs - - - Common\Interop\Windows\SChannel\SecPkgContext_CipherInfo.cs - - - Common\Interop\Windows\SspiCli\SSPISecureChannelType.cs - - - Common\Interop\Windows\SspiCli\ISSPIInterface.cs - - - Common\Interop\Windows\SspiCli\SSPIAuthType.cs - - - Common\Interop\Windows\SspiCli\SecurityPackageInfoClass.cs - - - Common\Interop\Windows\SspiCli\SecurityPackageInfo.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_Sizes.cs - - - Common\Interop\Windows\SspiCli\SafeDeleteContext.cs - - - Common\Interop\Windows\SspiCli\GlobalSSPI.cs - - - Common\Interop\Windows\SspiCli\Interop.SSPI.cs - - - Common\Interop\Windows\SspiCli\SecuritySafeHandles.cs - - - Common\Interop\Windows\SspiCli\SSPIWrapper.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - Common\System\Net\Mail\DomainLiteralReader.cs - - - Common\System\Net\Mail\DotAtomReader.cs - - - Common\System\Net\Mail\MailAddress.cs - - - Common\System\Net\Mail\MailAddressParser.cs - - - Common\System\Net\Mail\MailBnfHelper.cs - - - Common\System\Net\Mail\QuotedPairReader.cs - - - Common\System\Net\Mail\QuotedStringFormatReader.cs - - - Common\System\Net\Mail\WhitespaceReader.cs - - - Common\System\Threading\Tasks\TaskCompletionSourceWithCancellation.cs - + + + + + + + + + - - Common\Interop\Unix\StrongToWeakReference.cs - - - Common\System\Net\SecurityProtocol.cs - - - Common\System\Net\UriScheme.cs - - - Common\Interop\Unix\Interop.Errors.cs - - - Common\Interop\Unix\Interop.IOErrors.cs - - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\System.Native\Interop.Close.cs - - - Common\Interop\Unix\System.Native\Interop.Open.cs - - - Common\Interop\Unix\System.Native\Interop.OpenFlags.cs - - - Common\Interop\Unix\System.Native\Interop.Pipe.cs - - - Common\Interop\Unix\libc\Interop.Poll.cs - - - Common\Interop\Unix\libc\Interop.Read.cs - - - Common\Interop\Unix\libc\Interop.Write.cs - - - Common\System\CharArrayHelpers.cs - - - Common\System\StringExtensions.cs - - - Common\System\Net\HttpKnownHeaderNames.cs - - - Common\System\Net\HttpKnownHeaderNames.TryGetHeaderName.cs - - - Common\System\Net\HttpStatusDescription.cs - - - Common\System\Net\Http\HttpHandlerDefaults.cs - - - Common\System\Net\Http\NoWriteNoSeekStreamContent.cs - - - Common\System\Net\Http\TlsCertificateExtensions - - - Common\System\Net\Security\CertificateHelper.cs - - - Common\System\Net\Security\CertificateHelper.Unix.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - + + + + + + + + + + + + + + + + + + + + + + + + - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ASN1.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.BIO.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Initialization.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Crypto.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Ssl.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.SslCtx.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.SetProtocolOptions.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509Name.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509Ext.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509Stack.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509StoreCtx.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.Initialization.cs - - - Common\Microsoft\Win32\SafeHandles\SafeX509Handles.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\X509ExtensionSafeHandles.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeInteriorHandle.cs - - - Common\Microsoft\Win32\SafeHandles\SafeBioHandle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeHandleCache.cs - - - Common\System\Net\Security\CertificateValidation.Unix.cs - + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/ByteArrayContent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/ByteArrayContent.cs index 9b1e9b0e86dfe2..e4d9cca3c1bb41 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/ByteArrayContent.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/ByteArrayContent.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Diagnostics; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -25,8 +24,6 @@ public ByteArrayContent(byte[] content) _content = content; _offset = 0; _count = content.Length; - - SetBuffer(_content, _offset, _count); } public ByteArrayContent(byte[] content, int offset, int count) @@ -47,8 +44,6 @@ public ByteArrayContent(byte[] content, int offset, int count) _content = content; _offset = offset; _count = count; - - SetBuffer(_content, _offset, _count); } protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/EmptyContent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/EmptyContent.cs new file mode 100644 index 00000000000000..728229337c675a --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/EmptyContent.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. +// See the LICENSE file in the project root for more information. + +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Net.Http +{ + /// Provides a zero-length HttpContent implementation. + internal sealed class EmptyContent : HttpContent + { + protected internal override bool TryComputeLength(out long length) + { + length = 0; + return true; + } + + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => + Task.CompletedTask; + + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) => + cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : + SerializeToStreamAsync(stream, context); + + protected override Task CreateContentReadStreamAsync() => + Task.FromResult(EmptyReadStream.Instance); + + protected override Task CreateContentReadStreamAsync(CancellationToken cancellationToken) => + cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) : + CreateContentReadStreamAsync(); + + internal override Stream? TryCreateContentReadStream() => EmptyReadStream.Instance; + + internal override bool AllowDuplex => false; + } +} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/EmptyReadStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/EmptyReadStream.cs similarity index 100% rename from src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/EmptyReadStream.cs rename to src/libraries/System.Net.Http/src/System/Net/Http/EmptyReadStream.cs diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AuthenticationHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AuthenticationHeaderValue.cs index 069e59c0731f03..bc20aa28eb0893 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AuthenticationHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AuthenticationHeaderValue.cs @@ -104,7 +104,7 @@ public static AuthenticationHeaderValue Parse(string? input) input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out AuthenticationHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out AuthenticationHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentDispositionHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentDispositionHeaderValue.cs index 57a4bd8ca0ccc9..77cd28611103bc 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentDispositionHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentDispositionHeaderValue.cs @@ -199,7 +199,7 @@ public static ContentDispositionHeaderValue Parse(string? input) null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out ContentDispositionHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out ContentDispositionHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentRangeHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentRangeHeaderValue.cs index ecb3f51aca7393..c7e619e84a9e94 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentRangeHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentRangeHeaderValue.cs @@ -187,7 +187,7 @@ public static ContentRangeHeaderValue Parse(string? input) return (ContentRangeHeaderValue)GenericHeaderParser.ContentRangeParser.ParseValue(input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out ContentRangeHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out ContentRangeHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/EntityTagHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/EntityTagHeaderValue.cs index 46abb6a7f58b3c..5c32f76236eda8 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/EntityTagHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/EntityTagHeaderValue.cs @@ -109,7 +109,7 @@ public static EntityTagHeaderValue Parse(string? input) input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out EntityTagHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out EntityTagHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs index 2b955dbd10774c..2bb01857d4629a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs @@ -126,9 +126,9 @@ public string GetHeaderValue(ReadOnlySpan headerValue) // If it's a known header value, use the known value instead of allocating a new string. if (_knownHeader != null) { - if (_knownHeader.KnownValues != null) + string[]? knownValues = _knownHeader.KnownValues; + if (knownValues != null) { - string[] knownValues = _knownHeader.KnownValues; for (int i = 0; i < knownValues.Length; i++) { if (ByteArrayHelpers.EqualsOrdinalAsciiIgnoreCase(knownValues[i], headerValue)) @@ -138,7 +138,15 @@ public string GetHeaderValue(ReadOnlySpan headerValue) } } - if (_knownHeader == KnownHeaders.Location) + if (_knownHeader == KnownHeaders.ContentType) + { + string? contentType = GetKnownContentType(headerValue); + if (contentType != null) + { + return contentType; + } + } + else if (_knownHeader == KnownHeaders.Location) { // Normally Location should be in ISO-8859-1 but occasionally some servers respond with UTF-8. if (TryDecodeUtf8(headerValue, out string? decoded)) @@ -151,6 +159,90 @@ public string GetHeaderValue(ReadOnlySpan headerValue) return HttpRuleParser.DefaultHttpEncoding.GetString(headerValue); } + internal static string? GetKnownContentType(ReadOnlySpan contentTypeValue) + { + string? candidate = null; + switch (contentTypeValue.Length) + { + case 8: + switch (contentTypeValue[7] | 0x20) + { + case 'l': candidate = "text/xml"; break; // text/xm[l] + case 's': candidate = "text/css"; break; // text/cs[s] + case 'v': candidate = "text/csv"; break; // text/cs[v] + } + break; + + case 9: + switch (contentTypeValue[6] | 0x20) + { + case 'g': candidate = "image/gif"; break; // image/[g]if + case 'p': candidate = "image/png"; break; // image/[p]ng + case 't': candidate = "text/html"; break; // text/h[t]ml + } + break; + + case 10: + switch (contentTypeValue[0] | 0x20) + { + case 't': candidate = "text/plain"; break; // [t]ext/plain + case 'i': candidate = "image/jpeg"; break; // [i]mage/jpeg + } + break; + + case 15: + switch (contentTypeValue[12] | 0x20) + { + case 'p': candidate = "application/pdf"; break; // application/[p]df + case 'x': candidate = "application/xml"; break; // application/[x]ml + case 'z': candidate = "application/zip"; break; // application/[z]ip + } + break; + + case 16: + switch (contentTypeValue[12] | 0x20) + { + case 'g': candidate = "application/grpc"; break; // application/[g]rpc + case 'j': candidate = "application/json"; break; // application/[j]son + } + break; + + case 19: + candidate = "multipart/form-data"; // multipart/form-data + break; + + case 22: + candidate = "application/javascript"; // application/javascript + break; + + case 24: + switch (contentTypeValue[0] | 0x20) + { + case 'a': candidate = "application/octet-stream"; break; // application/octet-stream + case 't': candidate = "text/html; charset=utf-8"; break; // text/html; charset=utf-8 + } + break; + + case 25: + candidate = "text/plain; charset=utf-8"; // text/plain; charset=utf-8 + break; + + case 31: + candidate = "application/json; charset=utf-8"; // application/json; charset=utf-8 + break; + + case 33: + candidate = "application/x-www-form-urlencoded"; // application/x-www-form-urlencoded + break; + } + + Debug.Assert(candidate is null || candidate.Length == contentTypeValue.Length); + + return candidate != null && ByteArrayHelpers.EqualsOrdinalAsciiIgnoreCase(candidate, contentTypeValue) ? + candidate : + null; + } + private static bool TryDecodeUtf8(ReadOnlySpan input, [NotNullWhen(true)] out string? decoded) { char[] rented = ArrayPool.Shared.Rent(input.Length); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs index 7ba6b35324084f..840a55a1ed3552 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs @@ -161,7 +161,7 @@ internal bool TryAddWithoutValidation(HeaderDescriptor descriptor, string? value else { // The header store did not contain the header. Add the raw string. - _headerStore.Add(descriptor, _forceHeaderStoreItems ? new HeaderStoreItemInfo { RawValue = currentValue } : (object)value); + _headerStore.Add(descriptor, _forceHeaderStoreItems ? new HeaderStoreItemInfo { RawValue = value } : (object)value); } return true; @@ -1194,8 +1194,10 @@ private static string[] GetValuesAsStrings(HeaderDescriptor descriptor, object v return values; } - internal static int GetValuesAsStrings(HeaderDescriptor descriptor, object sourceValues, ref string[] values) + internal static int GetValuesAsStrings(HeaderDescriptor descriptor, object sourceValues, [NotNull] ref string[]? values) { + values ??= Array.Empty(); + HeaderStoreItemInfo? info = sourceValues as HeaderStoreItemInfo; if (info is null) { @@ -1210,7 +1212,6 @@ internal static int GetValuesAsStrings(HeaderDescriptor descriptor, object sourc return 1; } - Debug.Assert(values != null); int length = GetValueCount(info); if (length > 0) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpResponseHeaders.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpResponseHeaders.cs index 8da6741d187480..38643801d34e2a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpResponseHeaders.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpResponseHeaders.cs @@ -147,6 +147,8 @@ internal HttpResponseHeaders(bool containsTrailingHeaders = false) _containsTrailingHeaders = containsTrailingHeaders; } + internal bool ContainsTrailingHeaders => _containsTrailingHeaders; + internal override void AddHeaders(HttpHeaders sourceHeaders) { base.AddHeaders(sourceHeaders); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeader.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeader.cs index ce0705bbf5f19f..e166e71d8060ec 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeader.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeader.cs @@ -21,7 +21,6 @@ public KnownHeader(string name, HttpHeaderType headerType, HttpHeaderParser? par { Debug.Assert(!string.IsNullOrEmpty(name)); Debug.Assert(name[0] == ':' || HttpRuleParser.GetTokenLength(name, 0) == name.Length); - Debug.Assert(knownValues == null || (headerType & HttpHeaderType.Custom) != HttpHeaderType.Custom); Name = name; HeaderType = headerType; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs index d07b87977ebbda..b8f9b98a0e5626 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs @@ -46,8 +46,12 @@ internal static class KnownHeaders public static readonly KnownHeader Date = new KnownHeader("Date", HttpHeaderType.General | HttpHeaderType.NonTrailing, DateHeaderParser.Parser, null, H2StaticTable.Date, H3StaticTable.Date); public static readonly KnownHeader ETag = new KnownHeader("ETag", HttpHeaderType.Response, GenericHeaderParser.SingleValueEntityTagParser, null, H2StaticTable.ETag, H3StaticTable.ETag); public static readonly KnownHeader Expect = new KnownHeader("Expect", HttpHeaderType.Request | HttpHeaderType.NonTrailing, GenericHeaderParser.MultipleValueNameValueWithParametersParser, new string[] { "100-continue" }, H2StaticTable.Expect); + public static readonly KnownHeader ExpectCT = new KnownHeader("Expect-CT"); public static readonly KnownHeader Expires = new KnownHeader("Expires", HttpHeaderType.Content | HttpHeaderType.NonTrailing, DateHeaderParser.Parser, null, H2StaticTable.Expires); public static readonly KnownHeader From = new KnownHeader("From", HttpHeaderType.Request, GenericHeaderParser.MailAddressParser, null, H2StaticTable.From); + public static readonly KnownHeader GrpcEncoding = new KnownHeader("grpc-encoding", HttpHeaderType.Custom, null, new string[] { "identity", "gzip", "deflate" }); + public static readonly KnownHeader GrpcMessage = new KnownHeader("grpc-message"); + public static readonly KnownHeader GrpcStatus = new KnownHeader("grpc-status", HttpHeaderType.Custom, null, new string[] { "0" }); public static readonly KnownHeader Host = new KnownHeader("Host", HttpHeaderType.Request | HttpHeaderType.NonTrailing, GenericHeaderParser.HostParser, null, H2StaticTable.Host); public static readonly KnownHeader IfMatch = new KnownHeader("If-Match", HttpHeaderType.Request | HttpHeaderType.NonTrailing, GenericHeaderParser.MultipleValueEntityTagParser, null, H2StaticTable.IfMatch); public static readonly KnownHeader IfModifiedSince = new KnownHeader("If-Modified-Since", HttpHeaderType.Request | HttpHeaderType.NonTrailing, DateHeaderParser.Parser, null, H2StaticTable.IfModifiedSince, H3StaticTable.IfModifiedSince); @@ -69,6 +73,7 @@ internal static class KnownHeaders public static readonly KnownHeader PublicKeyPins = new KnownHeader("Public-Key-Pins"); public static readonly KnownHeader Range = new KnownHeader("Range", HttpHeaderType.Request | HttpHeaderType.NonTrailing, GenericHeaderParser.RangeParser, null, H2StaticTable.Range, H3StaticTable.RangeBytes0ToAll); public static readonly KnownHeader Referer = new KnownHeader("Referer", HttpHeaderType.Request, UriHeaderParser.RelativeOrAbsoluteUriParser, null, H2StaticTable.Referer, H3StaticTable.Referer); // NB: The spelling-mistake "Referer" for "Referrer" must be matched. + public static readonly KnownHeader ReferrerPolicy = new KnownHeader("Referrer-Policy", HttpHeaderType.Custom, null, new string[] { "strict-origin-when-cross-origin", "origin-when-cross-origin", "strict-origin", "origin", "same-origin", "no-referrer-when-downgrade", "no-referrer", "unsafe-url" }); public static readonly KnownHeader Refresh = new KnownHeader("Refresh", H2StaticTable.Refresh); public static readonly KnownHeader RetryAfter = new KnownHeader("Retry-After", HttpHeaderType.Response | HttpHeaderType.NonTrailing, GenericHeaderParser.RetryConditionParser, null, H2StaticTable.RetryAfter); public static readonly KnownHeader SecWebSocketAccept = new KnownHeader("Sec-WebSocket-Accept"); @@ -86,20 +91,22 @@ internal static class KnownHeaders public static readonly KnownHeader Trailer = new KnownHeader("Trailer", HttpHeaderType.General | HttpHeaderType.NonTrailing, GenericHeaderParser.TokenListParser); public static readonly KnownHeader TransferEncoding = new KnownHeader("Transfer-Encoding", HttpHeaderType.General | HttpHeaderType.NonTrailing, TransferCodingHeaderParser.MultipleValueParser, new string[] { "chunked", "compress", "deflate", "gzip", "identity" }, H2StaticTable.TransferEncoding); public static readonly KnownHeader Upgrade = new KnownHeader("Upgrade", HttpHeaderType.General, GenericHeaderParser.MultipleValueProductParser); - public static readonly KnownHeader UpgradeInsecureRequests = new KnownHeader("Upgrade-Insecure-Requests", http3StaticTableIndex: H3StaticTable.UpgradeInsecureRequests1); + public static readonly KnownHeader UpgradeInsecureRequests = new KnownHeader("Upgrade-Insecure-Requests", HttpHeaderType.Custom, null, new string[] { "1" }, http3StaticTableIndex: H3StaticTable.UpgradeInsecureRequests1); public static readonly KnownHeader UserAgent = new KnownHeader("User-Agent", HttpHeaderType.Request, ProductInfoHeaderParser.MultipleValueParser, null, H2StaticTable.UserAgent, H3StaticTable.UserAgent); - public static readonly KnownHeader Vary = new KnownHeader("Vary", HttpHeaderType.Response | HttpHeaderType.NonTrailing, GenericHeaderParser.TokenListParser, null, H2StaticTable.Vary, H3StaticTable.VaryAcceptEncoding); + public static readonly KnownHeader Vary = new KnownHeader("Vary", HttpHeaderType.Response | HttpHeaderType.NonTrailing, GenericHeaderParser.TokenListParser, new string[] { "*" }, H2StaticTable.Vary, H3StaticTable.VaryAcceptEncoding); public static readonly KnownHeader Via = new KnownHeader("Via", HttpHeaderType.General, GenericHeaderParser.MultipleValueViaParser, null, H2StaticTable.Via); public static readonly KnownHeader WWWAuthenticate = new KnownHeader("WWW-Authenticate", HttpHeaderType.Response | HttpHeaderType.NonTrailing, GenericHeaderParser.MultipleValueAuthenticationParser, null, H2StaticTable.WwwAuthenticate); public static readonly KnownHeader Warning = new KnownHeader("Warning", HttpHeaderType.General | HttpHeaderType.NonTrailing, GenericHeaderParser.MultipleValueWarningParser); public static readonly KnownHeader XAspNetVersion = new KnownHeader("X-AspNet-Version"); + public static readonly KnownHeader XCache = new KnownHeader("X-Cache"); public static readonly KnownHeader XContentDuration = new KnownHeader("X-Content-Duration"); - public static readonly KnownHeader XContentTypeOptions = new KnownHeader("X-Content-Type-Options", http3StaticTableIndex: H3StaticTable.XContentTypeOptionsNoSniff); - public static readonly KnownHeader XFrameOptions = new KnownHeader("X-Frame-Options", http3StaticTableIndex: H3StaticTable.XFrameOptionsDeny); + public static readonly KnownHeader XContentTypeOptions = new KnownHeader("X-Content-Type-Options", HttpHeaderType.Custom, null, new string[] { "nosniff" }, http3StaticTableIndex: H3StaticTable.XContentTypeOptionsNoSniff); + public static readonly KnownHeader XFrameOptions = new KnownHeader("X-Frame-Options", HttpHeaderType.Custom, null, new string[] { "DENY", "SAMEORIGIN" }, http3StaticTableIndex: H3StaticTable.XFrameOptionsDeny); public static readonly KnownHeader XMSEdgeRef = new KnownHeader("X-MSEdge-Ref"); public static readonly KnownHeader XPoweredBy = new KnownHeader("X-Powered-By"); public static readonly KnownHeader XRequestID = new KnownHeader("X-Request-ID"); public static readonly KnownHeader XUACompatible = new KnownHeader("X-UA-Compatible"); + public static readonly KnownHeader XXssProtection = new KnownHeader("X-XSS-Protection", HttpHeaderType.Custom, null, new string[] { "0", "1", "1; mode=block" }); // Helper interface for making GetCandidate generic over strings, utf8, etc private interface IHeaderNameAccessor @@ -137,13 +144,19 @@ public BytePtrAccessor(byte* p, int length) public char this[int index] => (char)_p[index]; } - // Find possible known header match via lookup on length and a distinguishing char for that length. - // Matching is case-insenstive. - // NOTE: Because of this, we do not preserve the case of the original header, - // whether from the wire or from the user explicitly setting a known header using a header name string. + /// + /// Find possible known header match via lookup on length and a distinguishing char for that length. + /// + /// + /// Matching is case-insensitive. Because of this, we do not preserve the case of the original header, + /// whether from the wire or from the user explicitly setting a known header using a header name string. + /// private static KnownHeader? GetCandidate(T key) where T : struct, IHeaderNameAccessor // Enforce struct for performance { + // Lookup is performed by first switching on the header name's length, and then switching + // on the most unique position in that length's string. + int length = key.Length; switch (length) { @@ -151,175 +164,195 @@ public BytePtrAccessor(byte* p, int length) return TE; // TE case 3: - switch (key[0]) + switch (key[0] | 0x20) { - case 'A': case 'a': return Age; // [A]ge - case 'P': case 'p': return P3P; // [P]3P - case 'T': case 't': return TSV; // [T]SV - case 'V': case 'v': return Via; // [V]ia + case 'a': return Age; // [A]ge + case 'p': return P3P; // [P]3P + case 't': return TSV; // [T]SV + case 'v': return Via; // [V]ia } break; case 4: - switch (key[0]) + switch (key[0] | 0x20) { - case 'D': case 'd': return Date; // [D]ate - case 'E': case 'e': return ETag; // [E]Tag - case 'F': case 'f': return From; // [F]rom - case 'H': case 'h': return Host; // [H]ost - case 'L': case 'l': return Link; // [L]ink - case 'V': case 'v': return Vary; // [V]ary + case 'd': return Date; // [D]ate + case 'e': return ETag; // [E]Tag + case 'f': return From; // [F]rom + case 'h': return Host; // [H]ost + case 'l': return Link; // [L]ink + case 'v': return Vary; // [V]ary } break; case 5: - switch (key[0]) + switch (key[0] | 0x20) { - case 'A': case 'a': return Allow; // [A]llow - case 'R': case 'r': return Range; // [R]ange + case 'a': return Allow; // [A]llow + case 'r': return Range; // [R]ange } break; case 6: - switch (key[0]) + switch (key[0] | 0x20) { - case 'A': case 'a': return Accept; // [A]ccept - case 'C': case 'c': return Cookie; // [C]ookie - case 'E': case 'e': return Expect; // [E]xpect - case 'O': case 'o': return Origin; // [O]rigin - case 'P': case 'p': return Pragma; // [P]ragma - case 'S': case 's': return Server; // [S]erver + case 'a': return Accept; // [A]ccept + case 'c': return Cookie; // [C]ookie + case 'e': return Expect; // [E]xpect + case 'o': return Origin; // [O]rigin + case 'p': return Pragma; // [P]ragma + case 's': return Server; // [S]erver } break; case 7: - switch (key[0]) + switch (key[0] | 0x20) { case ':': return PseudoStatus; // [:]status - case 'A': case 'a': return AltSvc; // [A]lt-Svc - case 'C': case 'c': return Cookie2; // [C]ookie2 - case 'E': case 'e': return Expires; // [E]xpires - case 'R': case 'r': - switch (key[3]) + case 'a': return AltSvc; // [A]lt-Svc + case 'c': return Cookie2; // [C]ookie2 + case 'e': return Expires; // [E]xpires + case 'r': + switch (key[3] | 0x20) { - case 'E': case 'e': return Referer; // [R]ef[e]rer - case 'R': case 'r': return Refresh; // [R]ef[r]esh + case 'e': return Referer; // [R]ef[e]rer + case 'r': return Refresh; // [R]ef[r]esh } break; - case 'T': case 't': return Trailer; // [T]railer - case 'U': case 'u': return Upgrade; // [U]pgrade - case 'W': case 'w': return Warning; // [W]arning + case 't': return Trailer; // [T]railer + case 'u': return Upgrade; // [U]pgrade + case 'w': return Warning; // [W]arning + case 'x': return XCache; // [X]-Cache } break; case 8: - switch (key[3]) + switch (key[3] | 0x20) { - case 'M': case 'm': return IfMatch; // If-[M]atch - case 'R': case 'r': return IfRange; // If-[R]ange - case 'A': case 'a': return Location; // Loc[a]tion + case '-': return AltUsed; // Alt[-]Used + case 'a': return Location; // Loc[a]tion + case 'm': return IfMatch; // If-[M]atch + case 'r': return IfRange; // If-[R]ange } break; + case 9: + return ExpectCT; // Expect-CT + case 10: - switch (key[0]) + switch (key[0] | 0x20) { - case 'C': case 'c': return Connection; // [C]onnection - case 'K': case 'k': return KeepAlive; // [K]eep-Alive - case 'S': case 's': return SetCookie; // [S]et-Cookie - case 'U': case 'u': return UserAgent; // [U]ser-Agent + case 'c': return Connection; // [C]onnection + case 'k': return KeepAlive; // [K]eep-Alive + case 's': return SetCookie; // [S]et-Cookie + case 'u': return UserAgent; // [U]ser-Agent } break; case 11: - switch (key[0]) + switch (key[0] | 0x20) { - case 'C': case 'c': return ContentMD5; // [C]ontent-MD5 - case 'R': case 'r': return RetryAfter; // [R]etry-After - case 'S': case 's': return SetCookie2; // [S]et-Cookie2 + case 'c': return ContentMD5; // [C]ontent-MD5 + case 'g': return GrpcStatus; // [g]rpc-status + case 'r': return RetryAfter; // [R]etry-After + case 's': return SetCookie2; // [S]et-Cookie2 } break; case 12: - switch (key[2]) + switch (key[5] | 0x20) { - case 'C': case 'c': return AcceptPatch; // Ac[c]ept-Patch - case 'N': case 'n': return ContentType; // Co[n]tent-Type - case 'X': case 'x': return MaxForwards; // Ma[x]-Forwards - case 'M': case 'm': return XMSEdgeRef; // X-[M]SEdge-Ref - case 'P': case 'p': return XPoweredBy; // X-[P]owered-By - case 'R': case 'r': return XRequestID; // X-[R]equest-ID + case 'd': return XMSEdgeRef; // X-MSE[d]ge-Ref + case 'e': return XPoweredBy; // X-Pow[e]red-By + case 'm': return GrpcMessage; // grpc-[m]essage + case 'n': return ContentType; // Conte[n]t-Type + case 'o': return MaxForwards; // Max-F[o]rwards + case 't': return AcceptPatch; // Accep[t]-Patch + case 'u': return XRequestID; // X-Req[u]est-ID } break; case 13: - switch (key[12]) + switch (key[12] | 0x20) { - case 'S': case 's': return AcceptRanges; // Accept-Range[s] - case 'N': case 'n': return Authorization; // Authorizatio[n] - case 'L': case 'l': return CacheControl; // Cache-Contro[l] - case 'E': case 'e': return ContentRange; // Content-Rang[e] - case 'H': case 'h': return IfNoneMatch; // If-None-Matc[h] - case 'D': case 'd': return LastModified; // Last-Modifie[d] - case 'T': case 't': return ProxySupport; // Proxy-Suppor[t] - case 'G': case 'g': return ServerTiming; // Server-Timin[g] + case 'd': return LastModified; // Last-Modifie[d] + case 'e': return ContentRange; // Content-Rang[e] + case 'g': + switch (key[0] | 0x20) + { + case 's': return ServerTiming; // [S]erver-Timin[g] + case 'g': return GrpcEncoding; // [g]rpc-encodin[g] + } + break; + case 'h': return IfNoneMatch; // If-None-Matc[h] + case 'l': return CacheControl; // Cache-Contro[l] + case 'n': return Authorization; // Authorizatio[n] + case 's': return AcceptRanges; // Accept-Range[s] + case 't': return ProxySupport; // Proxy-Suppor[t] } break; case 14: - switch (key[0]) + switch (key[0] | 0x20) { - case 'A': case 'a': return AcceptCharset; // [A]ccept-Charset - case 'C': case 'c': return ContentLength; // [C]ontent-Length + case 'a': return AcceptCharset; // [A]ccept-Charset + case 'c': return ContentLength; // [C]ontent-Length } break; case 15: - switch (key[7]) + switch (key[7] | 0x20) { case '-': return XFrameOptions; // X-Frame[-]Options - case 'M': case 'm': return XUACompatible; // X-UA-Co[m]patible - case 'E': case 'e': return AcceptEncoding; // Accept-[E]ncoding - case 'K': case 'k': return PublicKeyPins; // Public-[K]ey-Pins - case 'L': case 'l': return AcceptLanguage; // Accept-[L]anguage + case 'e': return AcceptEncoding; // Accept-[E]ncoding + case 'k': return PublicKeyPins; // Public-[K]ey-Pins + case 'l': return AcceptLanguage; // Accept-[L]anguage + case 'm': return XUACompatible; // X-UA-Co[m]patible + case 'r': return ReferrerPolicy; // Referre[r]-Policy } break; case 16: - switch (key[11]) + switch (key[11] | 0x20) { - case 'O': case 'o': return ContentEncoding; // Content-Enc[o]ding - case 'G': case 'g': return ContentLanguage; // Content-Lan[g]uage - case 'A': case 'a': return ContentLocation; // Content-Loc[a]tion - case 'C': case 'c': return ProxyConnection; // Proxy-Conne[c]tion - case 'I': case 'i': return WWWAuthenticate; // WWW-Authent[i]cate - case 'R': case 'r': return XAspNetVersion; // X-AspNet-Ve[r]sion + case 'a': return ContentLocation; // Content-Loc[a]tion + case 'c': + switch (key[0] | 0x20) + { + case 'p': return ProxyConnection; // [P]roxy-Conne[c]tion + case 'x': return XXssProtection; // [X]-XSS-Prote[c]tion + } + break; + case 'g': return ContentLanguage; // Content-Lan[g]uage + case 'i': return WWWAuthenticate; // WWW-Authent[i]cate + case 'o': return ContentEncoding; // Content-Enc[o]ding + case 'r': return XAspNetVersion; // X-AspNet-Ve[r]sion } break; case 17: - switch (key[0]) + switch (key[0] | 0x20) { - case 'I': case 'i': return IfModifiedSince; // [I]f-Modified-Since - case 'S': case 's': return SecWebSocketKey; // [S]ec-WebSocket-Key - case 'T': case 't': return TransferEncoding; // [T]ransfer-Encoding + case 'i': return IfModifiedSince; // [I]f-Modified-Since + case 's': return SecWebSocketKey; // [S]ec-WebSocket-Key + case 't': return TransferEncoding; // [T]ransfer-Encoding } break; case 18: - switch (key[0]) + switch (key[0] | 0x20) { - case 'P': case 'p': return ProxyAuthenticate; // [P]roxy-Authenticate - case 'X': case 'x': return XContentDuration; // [X]-Content-Duration + case 'p': return ProxyAuthenticate; // [P]roxy-Authenticate + case 'x': return XContentDuration; // [X]-Content-Duration } break; case 19: - switch (key[0]) + switch (key[0] | 0x20) { - case 'C': case 'c': return ContentDisposition; // [C]ontent-Disposition - case 'I': case 'i': return IfUnmodifiedSince; // [I]f-Unmodified-Since - case 'P': case 'p': return ProxyAuthorization; // [P]roxy-Authorization + case 'c': return ContentDisposition; // [C]ontent-Disposition + case 'i': return IfUnmodifiedSince; // [I]f-Unmodified-Since + case 'p': return ProxyAuthorization; // [P]roxy-Authorization } break; @@ -330,11 +363,11 @@ public BytePtrAccessor(byte* p, int length) return SecWebSocketVersion; // Sec-WebSocket-Version case 22: - switch (key[0]) + switch (key[0] | 0x20) { - case 'A': case 'a': return AccessControlMaxAge; // [A]ccess-Control-Max-Age - case 'S': case 's': return SecWebSocketProtocol; // [S]ec-WebSocket-Protocol - case 'X': case 'x': return XContentTypeOptions; // [X]-Content-Type-Options + case 'a': return AccessControlMaxAge; // [A]ccess-Control-Max-Age + case 's': return SecWebSocketProtocol; // [S]ec-WebSocket-Protocol + case 'x': return XContentTypeOptions; // [X]-Content-Type-Options } break; @@ -345,10 +378,10 @@ public BytePtrAccessor(byte* p, int length) return SecWebSocketExtensions; // Sec-WebSocket-Extensions case 25: - switch (key[0]) + switch (key[0] | 0x20) { - case 'S': case 's': return StrictTransportSecurity; // [S]trict-Transport-Security - case 'U': case 'u': return UpgradeInsecureRequests; // [U]pgrade-Insecure-Requests + case 's': return StrictTransportSecurity; // [S]trict-Transport-Security + case 'u': return UpgradeInsecureRequests; // [U]pgrade-Insecure-Requests } break; @@ -356,10 +389,10 @@ public BytePtrAccessor(byte* p, int length) return AccessControlAllowOrigin; // Access-Control-Allow-Origin case 28: - switch (key[21]) + switch (key[21] | 0x20) { - case 'H': case 'h': return AccessControlAllowHeaders; // Access-Control-Allow-[H]eaders - case 'M': case 'm': return AccessControlAllowMethods; // Access-Control-Allow-[M]ethods + case 'h': return AccessControlAllowHeaders; // Access-Control-Allow-[H]eaders + case 'm': return AccessControlAllowMethods; // Access-Control-Allow-[M]ethods } break; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeHeaderValue.cs index 36651d68a984ac..6e59561aa8e6b7 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeHeaderValue.cs @@ -127,7 +127,7 @@ public static MediaTypeHeaderValue Parse(string? input) return (MediaTypeHeaderValue)MediaTypeHeaderParser.SingleValueParser.ParseValue(input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out MediaTypeHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out MediaTypeHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeWithQualityHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeWithQualityHeaderValue.cs index c5d6aeb590bd91..9d83e7c568413a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeWithQualityHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/MediaTypeWithQualityHeaderValue.cs @@ -50,7 +50,7 @@ object ICloneable.Clone() input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out MediaTypeWithQualityHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out MediaTypeWithQualityHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueHeaderValue.cs index 098576e977ed1a..d92ee2f4861b5e 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueHeaderValue.cs @@ -122,7 +122,7 @@ public static NameValueHeaderValue Parse(string? input) input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out NameValueHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out NameValueHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueWithParametersHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueWithParametersHeaderValue.cs index 3c624ab7693407..39ce4299747119 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueWithParametersHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/NameValueWithParametersHeaderValue.cs @@ -85,7 +85,7 @@ public override string ToString() .ParseValue(input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out NameValueWithParametersHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out NameValueWithParametersHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductHeaderValue.cs index ac3a6b5004172a..4fe9d68645bae6 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductHeaderValue.cs @@ -93,7 +93,7 @@ public static ProductHeaderValue Parse(string? input) return (ProductHeaderValue)GenericHeaderParser.SingleValueProductParser.ParseValue(input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out ProductHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out ProductHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductInfoHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductInfoHeaderValue.cs index 85d02c1607fb48..751bbba8a4c925 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductInfoHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ProductInfoHeaderValue.cs @@ -107,7 +107,7 @@ public static ProductInfoHeaderValue Parse(string input) return (ProductInfoHeaderValue)result; } - public static bool TryParse(string input, [NotNullWhen(true)] out ProductInfoHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string input, [NotNullWhen(true)] out ProductInfoHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeConditionHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeConditionHeaderValue.cs index dbfdf670cdea19..ee2923a20926f5 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeConditionHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeConditionHeaderValue.cs @@ -100,7 +100,7 @@ public static RangeConditionHeaderValue Parse(string? input) input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out RangeConditionHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out RangeConditionHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeHeaderValue.cs index a6b80ac851c168..17b926e265100a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RangeHeaderValue.cs @@ -116,7 +116,7 @@ public static RangeHeaderValue Parse(string? input) return (RangeHeaderValue)GenericHeaderParser.RangeParser.ParseValue(input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out RangeHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out RangeHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RetryConditionHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RetryConditionHeaderValue.cs index f0c187a7ca176c..1d0602f9d0ce8c 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RetryConditionHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/RetryConditionHeaderValue.cs @@ -97,7 +97,7 @@ public static RetryConditionHeaderValue Parse(string? input) input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out RetryConditionHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out RetryConditionHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/StringWithQualityHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/StringWithQualityHeaderValue.cs index 60c0e668865465..ad77797366e848 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/StringWithQualityHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/StringWithQualityHeaderValue.cs @@ -111,7 +111,7 @@ public static StringWithQualityHeaderValue Parse(string? input) input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out StringWithQualityHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out StringWithQualityHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingHeaderValue.cs index c833b894d45499..4f393812ee9f78 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingHeaderValue.cs @@ -55,7 +55,7 @@ public static TransferCodingHeaderValue Parse(string? input) input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out TransferCodingHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out TransferCodingHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingWithQualityHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingWithQualityHeaderValue.cs index 6b4781043eab08..0dbf2ca7c1987f 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingWithQualityHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/TransferCodingWithQualityHeaderValue.cs @@ -49,7 +49,7 @@ object ICloneable.Clone() .ParseValue(input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out TransferCodingWithQualityHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out TransferCodingWithQualityHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ViaHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ViaHeaderValue.cs index 7aaef31fdf5114..8336c5c23acf8c 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ViaHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ViaHeaderValue.cs @@ -145,7 +145,7 @@ public static ViaHeaderValue Parse(string? input) return (ViaHeaderValue)GenericHeaderParser.SingleValueViaParser.ParseValue(input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out ViaHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out ViaHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/WarningHeaderValue.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/WarningHeaderValue.cs index a6e21c2a9a85f5..b7359b0e44d074 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/WarningHeaderValue.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/WarningHeaderValue.cs @@ -143,7 +143,7 @@ public static WarningHeaderValue Parse(string? input) return (WarningHeaderValue)GenericHeaderParser.SingleValueWarningParser.ParseValue(input, null, ref index); } - public static bool TryParse(string? input, [NotNullWhen(true)] out WarningHeaderValue? parsedValue) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out WarningHeaderValue? parsedValue) { int index = 0; parsedValue = null; diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpBaseStream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpBaseStream.cs similarity index 100% rename from src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpBaseStream.cs rename to src/libraries/System.Net.Http/src/System/Net/Http/HttpBaseStream.cs diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs index 1851c5aa3da6aa..304b810d548742 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs @@ -222,7 +222,7 @@ protected internal override Task SendAsync(HttpRequestMessa _socketsHttpHandler.SendAsync(request, cancellationToken); } - public static Func DangerousAcceptAnyServerCertificateValidator { get; } = delegate { return true; }; + public static Func DangerousAcceptAnyServerCertificateValidator { get; } = delegate { return true; }; private void ThrowForModifiedManagedSslOptionsIfStarted() { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs index 2ba227249dc3ce..23abf0afebfec2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpContent.cs @@ -131,11 +131,6 @@ private bool IsBuffered get { return _bufferedContent != null; } } - internal void SetBuffer(byte[] buffer, int offset, int count) - { - _bufferedContent = new MemoryStream(buffer, offset, count, writable: false, publiclyVisible: true); - } - internal bool TryGetBuffer(out ArraySegment buffer) { if (_bufferedContent != null) @@ -351,41 +346,41 @@ public Task CopyToAsync(Stream stream, TransportContext? context, CancellationTo try { - ArraySegment buffer; - if (TryGetBuffer(out buffer)) - { - return CopyToAsyncCore(stream.WriteAsync(new ReadOnlyMemory(buffer.Array, buffer.Offset, buffer.Count), cancellationToken)); - } - else - { - Task task = SerializeToStreamAsync(stream, context, cancellationToken); - CheckTaskNotNull(task); - return CopyToAsyncCore(new ValueTask(task)); - } + return WaitAsync(InternalCopyToAsync(stream, context, cancellationToken)); } catch (Exception e) when (StreamCopyExceptionNeedsWrapping(e)) { return Task.FromException(GetStreamCopyException(e)); } - } - private static async Task CopyToAsyncCore(ValueTask copyTask) - { - try + static async Task WaitAsync(ValueTask copyTask) { - await copyTask.ConfigureAwait(false); - } - catch (Exception e) when (StreamCopyExceptionNeedsWrapping(e)) - { - throw WrapStreamCopyException(e); + try + { + await copyTask.ConfigureAwait(false); + } + catch (Exception e) when (StreamCopyExceptionNeedsWrapping(e)) + { + throw WrapStreamCopyException(e); + } } } - public Task LoadIntoBufferAsync() + internal ValueTask InternalCopyToAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) { - return LoadIntoBufferAsync(MaxBufferSize); + if (TryGetBuffer(out ArraySegment buffer)) + { + return stream.WriteAsync(buffer, cancellationToken); + } + + Task task = SerializeToStreamAsync(stream, context, cancellationToken); + CheckTaskNotNull(task); + return new ValueTask(task); } + public Task LoadIntoBufferAsync() => + LoadIntoBufferAsync(MaxBufferSize); + // No "CancellationToken" parameter needed since canceling the CTS will close the connection, resulting // in an exception being thrown while we're buffering. // If buffering is used without a connection, it is supposed to be fast, thus no cancellation required. diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpMethod.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpMethod.cs index fef238f73b272b..44b1e4fac8a013 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpMethod.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpMethod.cs @@ -176,9 +176,12 @@ public override string ToString() /// internal static HttpMethod Normalize(HttpMethod method) { + // _http3EncodedBytes is only set for the singleton instances, so if it's not null, + // we can avoid the dictionary lookup. Otherwise, look up the method instance in the + // dictionary and return the normalized instance if it's found. Debug.Assert(method != null); - return s_knownMethods.TryGetValue(method, out HttpMethod? normalized) ? - normalized : + return + method._http3EncodedBytes is null && s_knownMethods.TryGetValue(method, out HttpMethod? normalized) ? normalized : method; } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpResponseMessage.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpResponseMessage.cs index dbe85b55dea63e..9873b4246f5548 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpResponseMessage.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpResponseMessage.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Net.Http.Headers; using System.Text; @@ -39,9 +41,10 @@ public Version Version internal void SetVersionWithoutValidation(Version value) => _version = value; - public HttpContent? Content + [AllowNull] + public HttpContent Content { - get { return _content; } + get { return _content ??= new EmptyContent(); } set { CheckDisposed(); @@ -104,28 +107,28 @@ public string? ReasonPhrase internal void SetReasonPhraseWithoutValidation(string value) => _reasonPhrase = value; - public HttpResponseHeaders Headers + public HttpResponseHeaders Headers => _headers ??= new HttpResponseHeaders(); + + public HttpResponseHeaders TrailingHeaders => _trailingHeaders ??= new HttpResponseHeaders(containsTrailingHeaders: true); + + /// Stores the supplied trailing headers into this instance. + /// + /// In the common/desired case where response.TrailingHeaders isn't accessed until after the whole payload has been + /// received, will still be null, and we can simply store the supplied instance into + /// and assume ownership of the instance. In the uncommon case where it was accessed, + /// we add all of the headers to the existing instance. + /// + internal void StoreReceivedTrailingHeaders(HttpResponseHeaders headers) { - get + Debug.Assert(headers.ContainsTrailingHeaders); + + if (_trailingHeaders is null) { - if (_headers == null) - { - _headers = new HttpResponseHeaders(); - } - return _headers; + _trailingHeaders = headers; } - } - - public HttpResponseHeaders TrailingHeaders - { - get + else { - if (_trailingHeaders == null) - { - _trailingHeaders = new HttpResponseHeaders(containsTrailingHeaders: true); - } - - return _trailingHeaders; + _trailingHeaders.AddHeaders(headers); } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/ReadOnlyMemoryContent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/ReadOnlyMemoryContent.cs index b2140a91a3553f..d4b91c29ad15ff 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/ReadOnlyMemoryContent.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/ReadOnlyMemoryContent.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.IO; -using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -13,16 +12,8 @@ public sealed class ReadOnlyMemoryContent : HttpContent { private readonly ReadOnlyMemory _content; - public ReadOnlyMemoryContent(ReadOnlyMemory content) - { + public ReadOnlyMemoryContent(ReadOnlyMemory content) => _content = content; - if (MemoryMarshal.TryGetArray(content, out ArraySegment array)) - { - // If we have an array, allow HttpClient to take optimized paths by just - // giving it the array content to use as its already buffered data. - SetBuffer(array.Array!, array.Offset, array.Count); - } - } protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => stream.WriteAsync(_content).AsTask(); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs index 7f88b005bfdfd6..288022837e8321 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs @@ -136,7 +136,12 @@ public static ValueTask EstablishSslConnectionAsync(SslClientAuthenti Func localFromHttpClientHandler = mapper.FromHttpClientHandler; HttpRequestMessage localRequest = request; sslOptions.RemoteCertificateValidationCallback = (object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors) => - localFromHttpClientHandler(localRequest, certificate as X509Certificate2, chain, sslPolicyErrors); + { + Debug.Assert(localRequest != null); + bool result = localFromHttpClientHandler(localRequest, certificate as X509Certificate2, chain, sslPolicyErrors); + localRequest = null!; // ensure the SslOptions and this callback don't keep the first HttpRequestMessage alive indefinitely + return result; + }; } // Create the SslStream, authenticate, and return it. diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs index 92468925108020..9af644504a03e2 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs @@ -5,6 +5,7 @@ using System.Buffers.Binary; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net.Http.Headers; using System.Net.Http.HPack; @@ -24,10 +25,10 @@ internal sealed partial class Http2Connection : HttpConnectionBase, IDisposable // NOTE: These are mutable structs; do not make these readonly. private ArrayBuffer _incomingBuffer; private ArrayBuffer _outgoingBuffer; - private ArrayBuffer _headerBuffer; /// Reusable array used to get the values for each header being written to the wire. - private string[] _headerValues = Array.Empty(); + [ThreadStatic] + private static string[]? t_headerValues; private int _currentWriteSize; // as passed to StartWriteAsync @@ -35,9 +36,7 @@ internal sealed partial class Http2Connection : HttpConnectionBase, IDisposable private readonly Dictionary _httpStreams; - private readonly SemaphoreSlim _writerLock; - private readonly SemaphoreSlim _headerSerializationLock; - + private readonly AsyncMutex _writerLock; private readonly CreditManager _connectionWindow; private readonly CreditManager _concurrentStreams; @@ -106,14 +105,12 @@ public Http2Connection(HttpConnectionPool pool, Stream stream) _stream = stream; _incomingBuffer = new ArrayBuffer(InitialConnectionBufferSize); _outgoingBuffer = new ArrayBuffer(InitialConnectionBufferSize); - _headerBuffer = new ArrayBuffer(InitialConnectionBufferSize); _hpackDecoder = new HPackDecoder(maxHeadersLength: pool.Settings._maxResponseHeadersLength * 1024); _httpStreams = new Dictionary(); - _writerLock = new SemaphoreSlim(1, 1); - _headerSerializationLock = new SemaphoreSlim(1, 1); + _writerLock = new AsyncMutex(); _connectionWindow = new CreditManager(this, nameof(_connectionWindow), DefaultInitialWindowSize); _concurrentStreams = new CreditManager(this, nameof(_concurrentStreams), int.MaxValue); @@ -137,17 +134,17 @@ public async ValueTask SetupAsync() s_http2ConnectionPreface.AsSpan().CopyTo(_outgoingBuffer.AvailableSpan); _outgoingBuffer.Commit(s_http2ConnectionPreface.Length); - // Send SETTINGS frame - WriteFrameHeader(new FrameHeader(FrameHeader.SettingLength, FrameType.Settings, FrameFlags.None, 0)); - - // Disable push promise + // Send SETTINGS frame. Disable push promise. + FrameHeader.WriteTo(_outgoingBuffer.AvailableSpan, FrameHeader.SettingLength, FrameType.Settings, FrameFlags.None, streamId: 0); + _outgoingBuffer.Commit(FrameHeader.Size); BinaryPrimitives.WriteUInt16BigEndian(_outgoingBuffer.AvailableSpan, (ushort)SettingId.EnablePush); _outgoingBuffer.Commit(2); BinaryPrimitives.WriteUInt32BigEndian(_outgoingBuffer.AvailableSpan, 0); _outgoingBuffer.Commit(4); // Send initial connection-level WINDOW_UPDATE - WriteFrameHeader(new FrameHeader(FrameHeader.WindowUpdateLength, FrameType.WindowUpdate, FrameFlags.None, 0)); + FrameHeader.WriteTo(_outgoingBuffer.AvailableSpan, FrameHeader.WindowUpdateLength, FrameType.WindowUpdate, FrameFlags.None, streamId: 0); + _outgoingBuffer.Commit(FrameHeader.Size); BinaryPrimitives.WriteUInt32BigEndian(_outgoingBuffer.AvailableSpan, (ConnectionWindowSize - DefaultInitialWindowSize)); _outgoingBuffer.Commit(4); @@ -199,7 +196,7 @@ private async ValueTask ReadFrameAsync(bool initialFrame = false) // Parse the frame header from our read buffer and validate it. FrameHeader frameHeader = FrameHeader.ReadFrom(_incomingBuffer.ActiveSpan); - if (frameHeader.Length > FrameHeader.MaxLength) + if (frameHeader.PayloadLength > FrameHeader.MaxPayloadLength) { if (initialFrame && NetEventSource.IsEnabled) { @@ -208,21 +205,21 @@ private async ValueTask ReadFrameAsync(bool initialFrame = false) } _incomingBuffer.Discard(FrameHeader.Size); - throw new Http2ConnectionException(initialFrame ? Http2ProtocolErrorCode.ProtocolError : Http2ProtocolErrorCode.FrameSizeError); + ThrowProtocolError(initialFrame ? Http2ProtocolErrorCode.ProtocolError : Http2ProtocolErrorCode.FrameSizeError); } _incomingBuffer.Discard(FrameHeader.Size); // Ensure we've read the frame contents into our buffer. - if (_incomingBuffer.ActiveLength < frameHeader.Length) + if (_incomingBuffer.ActiveLength < frameHeader.PayloadLength) { - _incomingBuffer.EnsureAvailableSpace(frameHeader.Length - _incomingBuffer.ActiveLength); + _incomingBuffer.EnsureAvailableSpace(frameHeader.PayloadLength - _incomingBuffer.ActiveLength); do { int bytesRead = await _stream.ReadAsync(_incomingBuffer.AvailableMemory).ConfigureAwait(false); _incomingBuffer.Commit(bytesRead); - if (bytesRead == 0) ThrowPrematureEOF(frameHeader.Length); + if (bytesRead == 0) ThrowPrematureEOF(frameHeader.PayloadLength); } - while (_incomingBuffer.ActiveLength < frameHeader.Length); + while (_incomingBuffer.ActiveLength < frameHeader.PayloadLength); } // Return the read frame header. @@ -240,7 +237,7 @@ private async Task ProcessIncomingFramesAsync() FrameHeader frameHeader = await ReadFrameAsync(initialFrame: true).ConfigureAwait(false); if (frameHeader.Type != FrameType.Settings || frameHeader.AckFlag) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } if (NetEventSource.IsEnabled) Trace($"Frame 0: {frameHeader}."); @@ -322,7 +319,8 @@ private async Task ProcessIncomingFramesAsync() case FrameType.PushPromise: // Should not happen, since we disable this in our initial SETTINGS case FrameType.Continuation: // Should only be received while processing headers in ProcessHeadersFrame default: - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); + break; } } } @@ -342,7 +340,7 @@ private async Task ProcessIncomingFramesAsync() { if (streamId <= 0 || streamId >= _nextStream) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } lock (SyncObject) @@ -373,10 +371,10 @@ private async ValueTask ProcessHeadersFrame(FrameHeader frameHeader) http2Stream?.OnHeadersStart(); _hpackDecoder.Decode( - GetFrameData(_incomingBuffer.ActiveSpan.Slice(0, frameHeader.Length), frameHeader.PaddedFlag, frameHeader.PriorityFlag), + GetFrameData(_incomingBuffer.ActiveSpan.Slice(0, frameHeader.PayloadLength), frameHeader.PaddedFlag, frameHeader.PriorityFlag), frameHeader.EndHeadersFlag, http2Stream); - _incomingBuffer.Discard(frameHeader.Length); + _incomingBuffer.Discard(frameHeader.PayloadLength); while (!frameHeader.EndHeadersFlag) { @@ -384,14 +382,14 @@ private async ValueTask ProcessHeadersFrame(FrameHeader frameHeader) if (frameHeader.Type != FrameType.Continuation || frameHeader.StreamId != streamId) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } _hpackDecoder.Decode( - _incomingBuffer.ActiveSpan.Slice(0, frameHeader.Length), + _incomingBuffer.ActiveSpan.Slice(0, frameHeader.PayloadLength), frameHeader.EndHeadersFlag, http2Stream); - _incomingBuffer.Discard(frameHeader.Length); + _incomingBuffer.Discard(frameHeader.PayloadLength); } _hpackDecoder.CompleteDecode(); @@ -408,7 +406,7 @@ private ReadOnlySpan GetFrameData(ReadOnlySpan frameData, bool hasPa { if (frameData.Length == 0) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } int padLength = frameData[0]; @@ -416,7 +414,7 @@ private ReadOnlySpan GetFrameData(ReadOnlySpan frameData, bool hasPa if (frameData.Length < padLength) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } frameData = frameData.Slice(0, frameData.Length - padLength); @@ -426,7 +424,7 @@ private ReadOnlySpan GetFrameData(ReadOnlySpan frameData, bool hasPa { if (frameData.Length < FrameHeader.PriorityInfoLength) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } // We ignore priority info. @@ -447,7 +445,7 @@ private void ProcessAltSvcFrame(FrameHeader frameHeader) if (NetEventSource.IsEnabled) Trace($"{frameHeader}"); Debug.Assert(frameHeader.Type == FrameType.AltSvc); - ReadOnlySpan span = _incomingBuffer.ActiveSpan.Slice(0, frameHeader.Length); + ReadOnlySpan span = _incomingBuffer.ActiveSpan.Slice(0, frameHeader.PayloadLength); if (BinaryPrimitives.TryReadUInt16BigEndian(span, out ushort originLength)) { @@ -468,7 +466,7 @@ private void ProcessAltSvcFrame(FrameHeader frameHeader) } } - _incomingBuffer.Discard(frameHeader.Length); + _incomingBuffer.Discard(frameHeader.PayloadLength); } private void ProcessDataFrame(FrameHeader frameHeader) @@ -480,7 +478,7 @@ private void ProcessDataFrame(FrameHeader frameHeader) // Note, http2Stream will be null if this is a closed stream. // Just ignore the frame in this case. - ReadOnlySpan frameData = GetFrameData(_incomingBuffer.ActiveSpan.Slice(0, frameHeader.Length), hasPad: frameHeader.PaddedFlag, hasPriority: false); + ReadOnlySpan frameData = GetFrameData(_incomingBuffer.ActiveSpan.Slice(0, frameHeader.PayloadLength), hasPad: frameHeader.PaddedFlag, hasPriority: false); if (http2Stream != null) { @@ -494,7 +492,7 @@ private void ProcessDataFrame(FrameHeader frameHeader) ExtendWindow(frameData.Length); } - _incomingBuffer.Discard(frameHeader.Length); + _incomingBuffer.Discard(frameHeader.PayloadLength); } private void ProcessSettingsFrame(FrameHeader frameHeader) @@ -503,19 +501,19 @@ private void ProcessSettingsFrame(FrameHeader frameHeader) if (frameHeader.StreamId != 0) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } if (frameHeader.AckFlag) { - if (frameHeader.Length != 0) + if (frameHeader.PayloadLength != 0) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.FrameSizeError); + ThrowProtocolError(Http2ProtocolErrorCode.FrameSizeError); } if (!_expectingSettingsAck) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } // We only send SETTINGS once initially, so we don't need to do anything in response to the ACK. @@ -524,13 +522,13 @@ private void ProcessSettingsFrame(FrameHeader frameHeader) } else { - if ((frameHeader.Length % 6) != 0) + if ((frameHeader.PayloadLength % 6) != 0) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.FrameSizeError); + ThrowProtocolError(Http2ProtocolErrorCode.FrameSizeError); } // Parse settings and process the ones we care about. - ReadOnlySpan settings = _incomingBuffer.ActiveSpan.Slice(0, frameHeader.Length); + ReadOnlySpan settings = _incomingBuffer.ActiveSpan.Slice(0, frameHeader.PayloadLength); while (settings.Length > 0) { Debug.Assert((settings.Length % 6) == 0); @@ -549,7 +547,7 @@ private void ProcessSettingsFrame(FrameHeader frameHeader) case SettingId.InitialWindowSize: if (settingValue > 0x7FFFFFFF) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.FlowControlError); + ThrowProtocolError(Http2ProtocolErrorCode.FlowControlError); } ChangeInitialWindowSize((int)settingValue); @@ -558,7 +556,7 @@ private void ProcessSettingsFrame(FrameHeader frameHeader) case SettingId.MaxFrameSize: if (settingValue < 16384 || settingValue > 16777215) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } // We don't actually store this value; we always send frames of the minimum size (16K). @@ -571,7 +569,7 @@ private void ProcessSettingsFrame(FrameHeader frameHeader) } } - _incomingBuffer.Discard(frameHeader.Length); + _incomingBuffer.Discard(frameHeader.PayloadLength); // Send acknowledgement // Don't wait for completion, which could happen asynchronously. @@ -615,14 +613,14 @@ private void ProcessPriorityFrame(FrameHeader frameHeader) { Debug.Assert(frameHeader.Type == FrameType.Priority); - if (frameHeader.StreamId == 0 || frameHeader.Length != FrameHeader.PriorityInfoLength) + if (frameHeader.StreamId == 0 || frameHeader.PayloadLength != FrameHeader.PriorityInfoLength) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } // Ignore priority info. - _incomingBuffer.Discard(frameHeader.Length); + _incomingBuffer.Discard(frameHeader.PayloadLength); } private void ProcessPingFrame(FrameHeader frameHeader) @@ -631,18 +629,18 @@ private void ProcessPingFrame(FrameHeader frameHeader) if (frameHeader.StreamId != 0) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } if (frameHeader.AckFlag) { // We never send PING, so an ACK indicates a protocol error - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } - if (frameHeader.Length != FrameHeader.PingLength) + if (frameHeader.PayloadLength != FrameHeader.PingLength) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.FrameSizeError); + ThrowProtocolError(Http2ProtocolErrorCode.FrameSizeError); } // We don't wait for SendPingAckAsync to complete before discarding @@ -654,16 +652,16 @@ private void ProcessPingFrame(FrameHeader frameHeader) LogExceptions(SendPingAckAsync(pingContentLong)); - _incomingBuffer.Discard(frameHeader.Length); + _incomingBuffer.Discard(frameHeader.PayloadLength); } private void ProcessWindowUpdateFrame(FrameHeader frameHeader) { Debug.Assert(frameHeader.Type == FrameType.WindowUpdate); - if (frameHeader.Length != FrameHeader.WindowUpdateLength) + if (frameHeader.PayloadLength != FrameHeader.WindowUpdateLength) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.FrameSizeError); + ThrowProtocolError(Http2ProtocolErrorCode.FrameSizeError); } int amount = BinaryPrimitives.ReadInt32BigEndian(_incomingBuffer.ActiveSpan) & 0x7FFFFFFF; @@ -672,10 +670,10 @@ private void ProcessWindowUpdateFrame(FrameHeader frameHeader) Debug.Assert(amount >= 0); if (amount == 0) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } - _incomingBuffer.Discard(frameHeader.Length); + _incomingBuffer.Discard(frameHeader.PayloadLength); if (frameHeader.StreamId == 0) { @@ -698,28 +696,28 @@ private void ProcessRstStreamFrame(FrameHeader frameHeader) { Debug.Assert(frameHeader.Type == FrameType.RstStream); - if (frameHeader.Length != FrameHeader.RstStreamLength) + if (frameHeader.PayloadLength != FrameHeader.RstStreamLength) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.FrameSizeError); + ThrowProtocolError(Http2ProtocolErrorCode.FrameSizeError); } if (frameHeader.StreamId == 0) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } Http2Stream? http2Stream = GetStream(frameHeader.StreamId); if (http2Stream == null) { // Ignore invalid stream ID, as per RFC - _incomingBuffer.Discard(frameHeader.Length); + _incomingBuffer.Discard(frameHeader.PayloadLength); return; } var protocolError = (Http2ProtocolErrorCode)BinaryPrimitives.ReadInt32BigEndian(_incomingBuffer.ActiveSpan); if (NetEventSource.IsEnabled) Trace(frameHeader.StreamId, $"{nameof(protocolError)}={protocolError}"); - _incomingBuffer.Discard(frameHeader.Length); + _incomingBuffer.Discard(frameHeader.PayloadLength); if (protocolError == Http2ProtocolErrorCode.RefusedStream) { @@ -735,16 +733,16 @@ private void ProcessGoAwayFrame(FrameHeader frameHeader) { Debug.Assert(frameHeader.Type == FrameType.GoAway); - if (frameHeader.Length < FrameHeader.GoAwayMinLength) + if (frameHeader.PayloadLength < FrameHeader.GoAwayMinLength) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.FrameSizeError); + ThrowProtocolError(Http2ProtocolErrorCode.FrameSizeError); } // GoAway frames always apply to the whole connection, never to a single stream. // According to RFC 7540 section 6.8, this should be a connection error. if (frameHeader.StreamId != 0) { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + ThrowProtocolError(); } int lastValidStream = (int)(BinaryPrimitives.ReadUInt32BigEndian(_incomingBuffer.ActiveSpan) & 0x7FFFFFFF); @@ -753,7 +751,7 @@ private void ProcessGoAwayFrame(FrameHeader frameHeader) StartTerminatingConnection(lastValidStream, new Http2ConnectionException(errorCode)); - _incomingBuffer.Discard(frameHeader.Length); + _incomingBuffer.Discard(frameHeader.PayloadLength); } internal async Task FlushAsync(CancellationToken cancellationToken = default) @@ -765,27 +763,69 @@ internal async Task FlushAsync(CancellationToken cancellationToken = default) private async ValueTask> StartWriteAsync(int writeBytes, CancellationToken cancellationToken = default) { if (NetEventSource.IsEnabled) Trace($"{nameof(writeBytes)}={writeBytes}"); - await AcquireWriteLockAsync(cancellationToken).ConfigureAwait(false); + // Acquire the write lock + ValueTask acquireLockTask = _writerLock.EnterAsync(cancellationToken); + if (acquireLockTask.IsCompletedSuccessfully) + { + acquireLockTask.GetAwaiter().GetResult(); // to enable the value task sources to be pooled + } + else + { + Interlocked.Increment(ref _pendingWriters); + try + { + await acquireLockTask.ConfigureAwait(false); + } + catch + { + if (Interlocked.Decrement(ref _pendingWriters) == 0) + { + // If a pending waiter is canceled, we may end up in a situation where a previously written frame + // saw that there were pending writers and as such deferred its flush to them, but if/when that pending + // writer is canceled, nothing may end up flushing the deferred work (at least not promptly). To compensate, + // if a pending writer does end up being canceled, we flush asynchronously. We can't check whether there's such + // a pending operation because we failed to acquire the lock that protects that state. But we can at least only + // do the flush if our decrement caused the pending count to reach 0: if it's still higher than zero, then there's + // at least one other pending writer who can handle the flush. Worst case, we pay for a flush that ends up being + // a nop. Note: we explicitly do not pass in the cancellationToken; if we're here, it's almost certainly because + // cancellation was requested, and it's because of that cancellation that we need to flush. + LogExceptions(FlushAsync(cancellationToken: default)); + } + + throw; + } + Interlocked.Decrement(ref _pendingWriters); + } + + // If the connection has been aborted, then fail now instead of trying to send more data. + if (_abortException != null) + { + _writerLock.Exit(); + ThrowRequestAborted(_abortException); + } + + // Flush anything necessary, and return back the write buffer to use. try { // If there is a pending write that was canceled while in progress, wait for it to complete. if (_inProgressWrite != null) { - await _inProgressWrite.ConfigureAwait(false); + await new ValueTask(_inProgressWrite).ConfigureAwait(false); // await ValueTask to minimize number of awaiter fields _inProgressWrite = null; } int totalBufferLength = _outgoingBuffer.Capacity; int activeBufferLength = _outgoingBuffer.ActiveLength; + // If the buffer has already grown to 32k, does not have room for the next request, + // and is non-empty, flush the current contents to the wire. if (totalBufferLength >= UnflushedOutgoingBufferSize && writeBytes >= totalBufferLength - activeBufferLength && activeBufferLength > 0) { - // If the buffer has already grown to 32k, does not have room for the next request, - // and is non-empty, flush the current contents to the wire. - await FlushOutgoingBytesAsync().ConfigureAwait(false); // we explicitly do not pass cancellationToken here, as this flush impacts more than just this operation + // We explicitly do not pass cancellationToken here, as this flush impacts more than just this operation. + await new ValueTask(FlushOutgoingBytesAsync()).ConfigureAwait(false); // await ValueTask to minimize number of awaiter fields } _outgoingBuffer.EnsureAvailableSpace(writeBytes); @@ -796,7 +836,7 @@ private async ValueTask> StartWriteAsync(int writeBytes, Cancellati } catch { - _writerLock.Release(); + _writerLock.Exit(); throw; } } @@ -811,8 +851,8 @@ private void FinishWrite(FlushTiming flush) { if (NetEventSource.IsEnabled) Trace($"{nameof(flush)}={flush}"); - // We can't validate that we hold the semaphore, but we can at least validate that someone is holding it. - Debug.Assert(_writerLock.CurrentCount == 0); + // We can't validate that we hold the mutex, but we can at least validate that someone is holding it. + Debug.Assert(_writerLock.IsHeld); _outgoingBuffer.Commit(_currentWriteSize); _lastPendingWriterShouldFlush |= (flush == FlushTiming.AfterPendingWrites); @@ -823,16 +863,16 @@ private void CancelWrite() { if (NetEventSource.IsEnabled) Trace(""); - // We can't validate that we hold the semaphore, but we can at least validate that someone is holding it. - Debug.Assert(_writerLock.CurrentCount == 0); + // We can't validate that we hold the mutex, but we can at least validate that someone is holding it. + Debug.Assert(_writerLock.IsHeld); EndWrite(forceFlush: false); } private void EndWrite(bool forceFlush) { - // We can't validate that we hold the semaphore, but we can at least validate that someone is holding it. - Debug.Assert(_writerLock.CurrentCount == 0); + // We can't validate that we hold the mutex, but we can at least validate that someone is holding it. + Debug.Assert(_writerLock.IsHeld); try { @@ -849,48 +889,7 @@ private void EndWrite(bool forceFlush) } finally { - _writerLock.Release(); - } - } - - private async ValueTask AcquireWriteLockAsync(CancellationToken cancellationToken) - { - Task acquireLockTask = _writerLock.WaitAsync(cancellationToken); - if (!acquireLockTask.IsCompletedSuccessfully) - { - Interlocked.Increment(ref _pendingWriters); - - try - { - await acquireLockTask.ConfigureAwait(false); - } - catch - { - if (Interlocked.Decrement(ref _pendingWriters) == 0) - { - // If a pending waiter is canceled, we may end up in a situation where a previously written frame - // saw that there were pending writers and as such deferred its flush to them, but if/when that pending - // writer is canceled, nothing may end up flushing the deferred work (at least not promptly). To compensate, - // if a pending writer does end up being canceled, we flush asynchronously. We can't check whether there's such - // a pending operation because we failed to acquire the lock that protects that state. But we can at least only - // do the flush if our decrement caused the pending count to reach 0: if it's still higher than zero, then there's - // at least one other pending writer who can handle the flush. Worst case, we pay for a flush that ends up being - // a nop. Note: we explicitly do not pass in the cancellationToken; if we're here, it's almost certainly because - // cancellation was requested, and it's because of that cancellation that we need to flush. - LogExceptions(FlushAsync()); - } - - throw; - } - - Interlocked.Decrement(ref _pendingWriters); - } - - // If the connection has been aborted, then fail now instead of trying to send more data. - if (_abortException != null) - { - _writerLock.Release(); - throw new IOException(SR.net_http_request_aborted, _abortException); + _writerLock.Exit(); } } @@ -899,8 +898,7 @@ private async Task SendSettingsAckAsync() Memory writeBuffer = await StartWriteAsync(FrameHeader.Size).ConfigureAwait(false); if (NetEventSource.IsEnabled) Trace("Started writing."); - FrameHeader frameHeader = new FrameHeader(0, FrameType.Settings, FrameFlags.Ack, 0); - frameHeader.WriteTo(writeBuffer); + FrameHeader.WriteTo(writeBuffer.Span, 0, FrameType.Settings, FrameFlags.Ack, streamId: 0); FinishWrite(FlushTiming.AfterPendingWrites); } @@ -911,12 +909,9 @@ private async Task SendPingAckAsync(long pingContent) Memory writeBuffer = await StartWriteAsync(FrameHeader.Size + FrameHeader.PingLength).ConfigureAwait(false); if (NetEventSource.IsEnabled) Trace("Started writing."); - FrameHeader frameHeader = new FrameHeader(FrameHeader.PingLength, FrameType.Ping, FrameFlags.Ack, 0); - frameHeader.WriteTo(writeBuffer); - writeBuffer = writeBuffer.Slice(FrameHeader.Size); - Debug.Assert(sizeof(long) == FrameHeader.PingLength); - BinaryPrimitives.WriteInt64BigEndian(writeBuffer.Span, pingContent); + FrameHeader.WriteTo(writeBuffer.Span, FrameHeader.PingLength, FrameType.Ping, FrameFlags.Ack, streamId: 0); + BinaryPrimitives.WriteInt64BigEndian(writeBuffer.Span.Slice(FrameHeader.Size), pingContent); FinishWrite(FlushTiming.AfterPendingWrites); } @@ -926,11 +921,8 @@ private async Task SendRstStreamAsync(int streamId, Http2ProtocolErrorCode error Memory writeBuffer = await StartWriteAsync(FrameHeader.Size + FrameHeader.RstStreamLength).ConfigureAwait(false); if (NetEventSource.IsEnabled) Trace(streamId, $"Started writing. {nameof(errorCode)}={errorCode}"); - FrameHeader frameHeader = new FrameHeader(FrameHeader.RstStreamLength, FrameType.RstStream, FrameFlags.None, streamId); - frameHeader.WriteTo(writeBuffer); - writeBuffer = writeBuffer.Slice(FrameHeader.Size); - - BinaryPrimitives.WriteInt32BigEndian(writeBuffer.Span, (int)errorCode); + FrameHeader.WriteTo(writeBuffer.Span, FrameHeader.RstStreamLength, FrameType.RstStream, FrameFlags.None, streamId); + BinaryPrimitives.WriteInt32BigEndian(writeBuffer.Span.Slice(FrameHeader.Size), (int)errorCode); FinishWrite(FlushTiming.Now); // ensure cancellation is seen as soon as possible } @@ -940,85 +932,85 @@ private static (ReadOnlyMemory first, ReadOnlyMemory rest) SplitBuff (buffer.Slice(0, maxSize), buffer.Slice(maxSize)) : (buffer, Memory.Empty); - private void WriteIndexedHeader(int index) + private void WriteIndexedHeader(int index, ref ArrayBuffer headerBuffer) { if (NetEventSource.IsEnabled) Trace($"{nameof(index)}={index}"); int bytesWritten; - while (!HPackEncoder.EncodeIndexedHeaderField(index, _headerBuffer.AvailableSpan, out bytesWritten)) + while (!HPackEncoder.EncodeIndexedHeaderField(index, headerBuffer.AvailableSpan, out bytesWritten)) { - _headerBuffer.EnsureAvailableSpace(_headerBuffer.AvailableLength + 1); + headerBuffer.EnsureAvailableSpace(headerBuffer.AvailableLength + 1); } - _headerBuffer.Commit(bytesWritten); + headerBuffer.Commit(bytesWritten); } - private void WriteIndexedHeader(int index, string value) + private void WriteIndexedHeader(int index, string value, ref ArrayBuffer headerBuffer) { if (NetEventSource.IsEnabled) Trace($"{nameof(index)}={index}, {nameof(value)}={value}"); int bytesWritten; - while (!HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexing(index, value, _headerBuffer.AvailableSpan, out bytesWritten)) + while (!HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexing(index, value, headerBuffer.AvailableSpan, out bytesWritten)) { - _headerBuffer.EnsureAvailableSpace(_headerBuffer.AvailableLength + 1); + headerBuffer.EnsureAvailableSpace(headerBuffer.AvailableLength + 1); } - _headerBuffer.Commit(bytesWritten); + headerBuffer.Commit(bytesWritten); } - private void WriteLiteralHeader(string name, ReadOnlySpan values) + private void WriteLiteralHeader(string name, ReadOnlySpan values, ref ArrayBuffer headerBuffer) { if (NetEventSource.IsEnabled) Trace($"{nameof(name)}={name}, {nameof(values)}={string.Join(", ", values.ToArray())}"); int bytesWritten; - while (!HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexingNewName(name, values, HttpHeaderParser.DefaultSeparator, _headerBuffer.AvailableSpan, out bytesWritten)) + while (!HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexingNewName(name, values, HttpHeaderParser.DefaultSeparator, headerBuffer.AvailableSpan, out bytesWritten)) { - _headerBuffer.EnsureAvailableSpace(_headerBuffer.AvailableLength + 1); + headerBuffer.EnsureAvailableSpace(headerBuffer.AvailableLength + 1); } - _headerBuffer.Commit(bytesWritten); + headerBuffer.Commit(bytesWritten); } - private void WriteLiteralHeaderValues(ReadOnlySpan values, string? separator) + private void WriteLiteralHeaderValues(ReadOnlySpan values, string? separator, ref ArrayBuffer headerBuffer) { if (NetEventSource.IsEnabled) Trace($"{nameof(values)}={string.Join(separator, values.ToArray())}"); int bytesWritten; - while (!HPackEncoder.EncodeStringLiterals(values, separator, _headerBuffer.AvailableSpan, out bytesWritten)) + while (!HPackEncoder.EncodeStringLiterals(values, separator, headerBuffer.AvailableSpan, out bytesWritten)) { - _headerBuffer.EnsureAvailableSpace(_headerBuffer.AvailableLength + 1); + headerBuffer.EnsureAvailableSpace(headerBuffer.AvailableLength + 1); } - _headerBuffer.Commit(bytesWritten); + headerBuffer.Commit(bytesWritten); } - private void WriteLiteralHeaderValue(string value) + private void WriteLiteralHeaderValue(string value, ref ArrayBuffer headerBuffer) { if (NetEventSource.IsEnabled) Trace($"{nameof(value)}={value}"); int bytesWritten; - while (!HPackEncoder.EncodeStringLiteral(value, _headerBuffer.AvailableSpan, out bytesWritten)) + while (!HPackEncoder.EncodeStringLiteral(value, headerBuffer.AvailableSpan, out bytesWritten)) { - _headerBuffer.EnsureAvailableSpace(_headerBuffer.AvailableLength + 1); + headerBuffer.EnsureAvailableSpace(headerBuffer.AvailableLength + 1); } - _headerBuffer.Commit(bytesWritten); + headerBuffer.Commit(bytesWritten); } - private void WriteBytes(ReadOnlySpan bytes) + private void WriteBytes(ReadOnlySpan bytes, ref ArrayBuffer headerBuffer) { if (NetEventSource.IsEnabled) Trace($"{nameof(bytes.Length)}={bytes.Length}"); - if (bytes.Length > _headerBuffer.AvailableLength) + if (bytes.Length > headerBuffer.AvailableLength) { - _headerBuffer.EnsureAvailableSpace(bytes.Length); + headerBuffer.EnsureAvailableSpace(bytes.Length); } - bytes.CopyTo(_headerBuffer.AvailableSpan); - _headerBuffer.Commit(bytes.Length); + bytes.CopyTo(headerBuffer.AvailableSpan); + headerBuffer.Commit(bytes.Length); } - private void WriteHeaderCollection(HttpHeaders headers) + private void WriteHeaderCollection(HttpHeaders headers, ref ArrayBuffer headerBuffer) { if (NetEventSource.IsEnabled) Trace(""); @@ -1027,11 +1019,12 @@ private void WriteHeaderCollection(HttpHeaders headers) return; } + ref string[]? tmpHeaderValuesArray = ref t_headerValues; foreach (KeyValuePair header in headers.HeaderStore) { - int headerValuesCount = HttpHeaders.GetValuesAsStrings(header.Key, header.Value, ref _headerValues); + int headerValuesCount = HttpHeaders.GetValuesAsStrings(header.Key, header.Value, ref tmpHeaderValuesArray); Debug.Assert(headerValuesCount > 0, "No values for header??"); - ReadOnlySpan headerValues = _headerValues.AsSpan(0, headerValuesCount); + ReadOnlySpan headerValues = tmpHeaderValuesArray.AsSpan(0, headerValuesCount); KnownHeader? knownHeader = header.Key.KnownHeader; if (knownHeader != null) @@ -1048,8 +1041,8 @@ private void WriteHeaderCollection(HttpHeaders headers) { if (string.Equals(value, "trailers", StringComparison.OrdinalIgnoreCase)) { - WriteBytes(knownHeader.Http2EncodedName); - WriteLiteralHeaderValue(value); + WriteBytes(knownHeader.Http2EncodedName, ref headerBuffer); + WriteLiteralHeaderValue(value, ref headerBuffer); break; } } @@ -1057,7 +1050,7 @@ private void WriteHeaderCollection(HttpHeaders headers) } // For all other known headers, send them via their pre-encoded name and the associated value. - WriteBytes(knownHeader.Http2EncodedName); + WriteBytes(knownHeader.Http2EncodedName, ref headerBuffer); string? separator = null; if (headerValues.Length > 1) { @@ -1072,21 +1065,20 @@ private void WriteHeaderCollection(HttpHeaders headers) } } - WriteLiteralHeaderValues(headerValues, separator); + WriteLiteralHeaderValues(headerValues, separator, ref headerBuffer); } } else { // The header is not known: fall back to just encoding the header name and value(s). - WriteLiteralHeader(header.Key.Name, headerValues); + WriteLiteralHeader(header.Key.Name, headerValues, ref headerBuffer); } } } - private void WriteHeaders(HttpRequestMessage request) + private void WriteHeaders(HttpRequestMessage request, ref ArrayBuffer headerBuffer) { if (NetEventSource.IsEnabled) Trace(""); - Debug.Assert(_headerBuffer.ActiveLength == 0); // HTTP2 does not support Transfer-Encoding: chunked, so disable this on the request. if (request.HasHeaders && request.Headers.TransferEncodingChunked == true) @@ -1099,42 +1091,42 @@ private void WriteHeaders(HttpRequestMessage request) // Method is normalized so we can do reference equality here. if (ReferenceEquals(normalizedMethod, HttpMethod.Get)) { - WriteIndexedHeader(H2StaticTable.MethodGet); + WriteIndexedHeader(H2StaticTable.MethodGet, ref headerBuffer); } else if (ReferenceEquals(normalizedMethod, HttpMethod.Post)) { - WriteIndexedHeader(H2StaticTable.MethodPost); + WriteIndexedHeader(H2StaticTable.MethodPost, ref headerBuffer); } else { - WriteIndexedHeader(H2StaticTable.MethodGet, normalizedMethod.Method); + WriteIndexedHeader(H2StaticTable.MethodGet, normalizedMethod.Method, ref headerBuffer); } - WriteIndexedHeader(_stream is SslStream ? H2StaticTable.SchemeHttps : H2StaticTable.SchemeHttp); + WriteIndexedHeader(_stream is SslStream ? H2StaticTable.SchemeHttps : H2StaticTable.SchemeHttp, ref headerBuffer); if (request.HasHeaders && request.Headers.Host != null) { - WriteIndexedHeader(H2StaticTable.Authority, request.Headers.Host); + WriteIndexedHeader(H2StaticTable.Authority, request.Headers.Host, ref headerBuffer); } else { - WriteBytes(_pool._http2EncodedAuthorityHostHeader); + WriteBytes(_pool._http2EncodedAuthorityHostHeader, ref headerBuffer); } Debug.Assert(request.RequestUri != null); string pathAndQuery = request.RequestUri.PathAndQuery; if (pathAndQuery == "/") { - WriteIndexedHeader(H2StaticTable.PathSlash); + WriteIndexedHeader(H2StaticTable.PathSlash, ref headerBuffer); } else { - WriteIndexedHeader(H2StaticTable.PathSlash, pathAndQuery); + WriteIndexedHeader(H2StaticTable.PathSlash, pathAndQuery, ref headerBuffer); } if (request.HasHeaders) { - WriteHeaderCollection(request.Headers); + WriteHeaderCollection(request.Headers, ref headerBuffer); } // Determine cookies to send. @@ -1143,8 +1135,8 @@ private void WriteHeaders(HttpRequestMessage request) string cookiesFromContainer = _pool.Settings._cookieContainer!.GetCookieHeader(request.RequestUri); if (cookiesFromContainer != string.Empty) { - WriteBytes(KnownHeaders.Cookie.Http2EncodedName); - WriteLiteralHeaderValue(cookiesFromContainer); + WriteBytes(KnownHeaders.Cookie.Http2EncodedName, ref headerBuffer); + WriteLiteralHeaderValue(cookiesFromContainer, ref headerBuffer); } } @@ -1154,17 +1146,18 @@ private void WriteHeaders(HttpRequestMessage request) // unless this is a method that never has a body. if (normalizedMethod.MustHaveRequestBody) { - WriteBytes(KnownHeaders.ContentLength.Http2EncodedName); - WriteLiteralHeaderValue("0"); + WriteBytes(KnownHeaders.ContentLength.Http2EncodedName, ref headerBuffer); + WriteLiteralHeaderValue("0", ref headerBuffer); } } else { - WriteHeaderCollection(request.Content.Headers); + WriteHeaderCollection(request.Content.Headers, ref headerBuffer); } } - private HttpRequestException GetShutdownException() + [DoesNotReturn] + private void ThrowShutdownException() { Debug.Assert(Monitor.IsEntered(SyncObject)); @@ -1191,51 +1184,72 @@ private HttpRequestException GetShutdownException() innerException = new ObjectDisposedException(nameof(Http2Connection)); } - return new HttpRequestException(SR.net_http_client_execution_error, innerException, allowRetry: RequestRetryType.RetryOnSameOrNextProxy); + ThrowRetry(SR.net_http_client_execution_error, innerException); } private async ValueTask SendHeadersAsync(HttpRequestMessage request, CancellationToken cancellationToken, bool mustFlush) { - // We serialize usage of the header encoder and the header buffer. - // This also ensures that new streams are always created in ascending order. - await _headerSerializationLock.WaitAsync(cancellationToken).ConfigureAwait(false); + // Enforce MAX_CONCURRENT_STREAMS setting value. We do this before anything else, e.g. renting buffers to serialize headers, + // in order to avoid consuming resources in potentially many requests waiting for access. try { - // Generate the entire header block, without framing, into the connection header buffer. - WriteHeaders(request); - - try + await _concurrentStreams.RequestCreditAsync(1, cancellationToken).ConfigureAwait(false); + } + catch (ObjectDisposedException) + { + // We have race condition between shutting down and initiating new requests. + // When we are shutting down the connection (e.g. due to receiving GOAWAY, etc) + // we will wait until the stream count goes to 0, and then we will close the connetion + // and perform clean up, including disposing _concurrentStreams. + // So if we get ObjectDisposedException here, we must have shut down the connection. + // Throw a retryable request exception if this is not result of some other error. + // This will cause retry logic to kick in and perform another connection attempt. + // The user should never see this exception. See similar handling below. + // Throw a retryable request exception if this is not result of some other error. + // This will cause retry logic to kick in and perform another connection attempt. + // The user should never see this exception. See also below. + lock (SyncObject) { - // Enforce MAX_CONCURRENT_STREAMS setting value. - await _concurrentStreams.RequestCreditAsync(1, cancellationToken).ConfigureAwait(false); - } - catch (ObjectDisposedException) - { - // We have race condition between shutting down and initiating new requests. - // When we are shutting down the connection (e.g. due to receiving GOAWAY, etc) - // we will wait until the stream count goes to 0, and then we will close the connetion - // and perform clean up, including disposing _concurrentStreams. - // So if we get ObjectDisposedException here, we must have shut down the connection. - // Throw a retryable request exception if this is not result of some other error. - // This will cause retry logic to kick in and perform another connection attempt. - // The user should never see this exception. See similar handling below. - // Throw a retryable request exception if this is not result of some other error. - // This will cause retry logic to kick in and perform another connection attempt. - // The user should never see this exception. See also below. Debug.Assert(_disposed || _lastStreamId != -1); Debug.Assert(_httpStreams.Count == 0); - - lock (SyncObject) - { - throw GetShutdownException(); - } + ThrowShutdownException(); + throw; // unreachable } + } + + ArrayBuffer headerBuffer = default; + try + { + // Serialize headers to a temporary buffer, and do as much work to prepare to send the headers as we can + // before taking the write lock. + headerBuffer = new ArrayBuffer(InitialConnectionBufferSize, usePool: true); + WriteHeaders(request, ref headerBuffer); + ReadOnlyMemory remaining = headerBuffer.ActiveMemory; + Debug.Assert(remaining.Length > 0); + + // Calculate the total number of bytes we're going to use (content + headers). + int frameCount = ((remaining.Length - 1) / FrameHeader.MaxPayloadLength) + 1; + int totalSize = remaining.Length + (frameCount * FrameHeader.Size); + ReadOnlyMemory current; + (current, remaining) = SplitBuffer(remaining, FrameHeader.MaxPayloadLength); + FrameFlags flags = + (remaining.Length == 0 ? FrameFlags.EndHeaders : FrameFlags.None) | + (request.Content == null ? FrameFlags.EndStream : FrameFlags.None); + + // Construct and initialize the new Http2Stream instance. It's stream ID must be set below + // before the instance is used and stored into the dictionary. However, we construct it here + // so as to avoid the allocation and initialization expense while holding multiple locks. + var http2Stream = new Http2Stream(request, this, _initialWindowSize); + + // Start the write. This serializes access to write to the connection, and ensures that HEADERS + // and CONTINUATION frames stay together, as they must do. We use the lock as well to ensure new + // streams are created and started in order. + Memory writeBuffer = await StartWriteAsync(totalSize, cancellationToken).ConfigureAwait(false); try { - // Allocate the next available stream ID. - // Note that if we fail before sending the headers, we'll just skip this stream ID, which is fine. - int streamId; + // Allocate the next available stream ID. Note that if we fail before sending the headers, + // we'll just skip this stream ID, which is fine. lock (SyncObject) { if (_nextStream == MaxStreamId || _disposed || _lastStreamId != -1) @@ -1243,90 +1257,60 @@ private async ValueTask SendHeadersAsync(HttpRequestMessage request // We ran out of stream IDs or we raced between acquiring the connection from the pool and shutting down. // Throw a retryable request exception. This will cause retry logic to kick in // and perform another connection attempt. The user should never see this exception. - throw GetShutdownException(); + ThrowShutdownException(); } - streamId = _nextStream; - // Client-initiated streams are always odd-numbered, so increase by 2. + http2Stream.StreamId = _nextStream; _nextStream += 2; - } - - ReadOnlyMemory remaining = _headerBuffer.ActiveMemory; - Debug.Assert(remaining.Length > 0); - - // Calculate the total number of bytes we're going to use (content + headers). - int frameCount = ((remaining.Length - 1) / FrameHeader.MaxLength) + 1; - int totalSize = remaining.Length + frameCount * FrameHeader.Size; - // Note, HEADERS and CONTINUATION frames must be together, so hold the writer lock across sending all of them. - Memory writeBuffer = await StartWriteAsync(totalSize, cancellationToken).ConfigureAwait(false); - if (NetEventSource.IsEnabled) Trace(streamId, $"Started writing. {nameof(totalSize)}={totalSize}"); - - // Send the HEADERS frame. - ReadOnlyMemory current; - (current, remaining) = SplitBuffer(remaining, FrameHeader.MaxLength); + // We're about to flush the HEADERS frame, so add the stream to the dictionary now. + // The lifetime of the stream is now controlled by the stream itself and the connection. + // This can fail if the connection is shutting down, in which case we will cancel sending this frame. + _httpStreams.Add(http2Stream.StreamId, http2Stream); + } - FrameFlags flags = - (remaining.Length == 0 ? FrameFlags.EndHeaders : FrameFlags.None) | - (request.Content == null ? FrameFlags.EndStream : FrameFlags.None); + if (NetEventSource.IsEnabled) Trace(http2Stream.StreamId, $"Started writing. {nameof(totalSize)}={totalSize}"); - FrameHeader frameHeader = new FrameHeader(current.Length, FrameType.Headers, flags, streamId); - frameHeader.WriteTo(writeBuffer.Span); + // Copy the HEADERS frame. + FrameHeader.WriteTo(writeBuffer.Span, current.Length, FrameType.Headers, flags, http2Stream.StreamId); writeBuffer = writeBuffer.Slice(FrameHeader.Size); - current.CopyTo(writeBuffer); writeBuffer = writeBuffer.Slice(current.Length); + if (NetEventSource.IsEnabled) Trace(http2Stream.StreamId, $"Wrote HEADERS frame. Length={current.Length}, flags={flags}"); - if (NetEventSource.IsEnabled) Trace(streamId, $"Wrote HEADERS frame. Length={current.Length}, flags={flags}"); - - // Send CONTINUATION frames, if any. + // Copy CONTINUATION frames, if any. while (remaining.Length > 0) { - (current, remaining) = SplitBuffer(remaining, FrameHeader.MaxLength); - - flags = (remaining.Length == 0 ? FrameFlags.EndHeaders : FrameFlags.None); + (current, remaining) = SplitBuffer(remaining, FrameHeader.MaxPayloadLength); + flags = remaining.Length == 0 ? FrameFlags.EndHeaders : FrameFlags.None; - frameHeader = new FrameHeader(current.Length, FrameType.Continuation, flags, streamId); - frameHeader.WriteTo(writeBuffer.Span); + FrameHeader.WriteTo(writeBuffer.Span, current.Length, FrameType.Continuation, flags, http2Stream.StreamId); writeBuffer = writeBuffer.Slice(FrameHeader.Size); - current.CopyTo(writeBuffer); writeBuffer = writeBuffer.Slice(current.Length); - - if (NetEventSource.IsEnabled) Trace(streamId, $"Wrote CONTINUATION frame. Length={current.Length}, flags={flags}"); + if (NetEventSource.IsEnabled) Trace(http2Stream.StreamId, $"Wrote CONTINUATION frame. Length={current.Length}, flags={flags}"); } Debug.Assert(writeBuffer.Length == 0); - Http2Stream http2Stream; - try - { - // We're about to write the HEADERS frame, so add the stream to the dictionary now. - // The lifetime of the stream is now controlled by the stream itself and the connection. - // This can fail if the connection is shutting down, in which case we will cancel sending this frame. - http2Stream = AddStream(streamId, request); - } - catch - { - CancelWrite(); - throw; - } - FinishWrite(mustFlush || (flags & FrameFlags.EndStream) != 0 ? FlushTiming.AfterPendingWrites : FlushTiming.Eventually); - return http2Stream; } catch { - _concurrentStreams.AdjustCredit(1); + CancelWrite(); throw; } } + catch + { + _concurrentStreams.AdjustCredit(1); + throw; + } finally { - _headerBuffer.Discard(_headerBuffer.ActiveLength); - _headerSerializationLock.Release(); + headerBuffer.Dispose(); } } @@ -1336,7 +1320,7 @@ private async Task SendStreamDataAsync(int streamId, ReadOnlyMemory buffer while (remaining.Length > 0) { - int frameSize = Math.Min(remaining.Length, FrameHeader.MaxLength); + int frameSize = Math.Min(remaining.Length, FrameHeader.MaxPayloadLength); // Once credit had been granted, we want to actually consume those bytes. frameSize = await _connectionWindow.RequestCreditAsync(frameSize, cancellationToken).ConfigureAwait(false); @@ -1352,20 +1336,14 @@ private async Task SendStreamDataAsync(int streamId, ReadOnlyMemory buffer writeBuffer = await StartWriteAsync(FrameHeader.Size + current.Length, cancellationToken).ConfigureAwait(false); if (NetEventSource.IsEnabled) Trace(streamId, $"Started writing. {nameof(writeBuffer.Length)}={writeBuffer.Length}"); } - catch (OperationCanceledException) + catch { _connectionWindow.AdjustCredit(frameSize); throw; } - FrameHeader frameHeader = new FrameHeader(current.Length, FrameType.Data, FrameFlags.None, streamId); - frameHeader.WriteTo(writeBuffer); - writeBuffer = writeBuffer.Slice(FrameHeader.Size); - - current.CopyTo(writeBuffer); - writeBuffer = writeBuffer.Slice(current.Length); - - Debug.Assert(writeBuffer.Length == 0); + FrameHeader.WriteTo(writeBuffer.Span, current.Length, FrameType.Data, FrameFlags.None, streamId); + current.CopyTo(writeBuffer.Slice(FrameHeader.Size)); FinishWrite(FlushTiming.Eventually); // no need to flush, as the request content may do so explicitly, or worst case we'll do so as part of the end data frame } @@ -1376,8 +1354,7 @@ private async Task SendEndStreamAsync(int streamId) Memory writeBuffer = await StartWriteAsync(FrameHeader.Size).ConfigureAwait(false); if (NetEventSource.IsEnabled) Trace(streamId, "Started writing."); - FrameHeader frameHeader = new FrameHeader(0, FrameType.Data, FrameFlags.EndStream, streamId); - frameHeader.WriteTo(writeBuffer); + FrameHeader.WriteTo(writeBuffer.Span, 0, FrameType.Data, FrameFlags.EndStream, streamId); FinishWrite(FlushTiming.AfterPendingWrites); // finished sending request body, so flush soon (but ok to wait for pending packets) } @@ -1390,11 +1367,8 @@ private async Task SendWindowUpdateAsync(int streamId, int amount) Memory writeBuffer = await StartWriteAsync(FrameHeader.Size + FrameHeader.WindowUpdateLength).ConfigureAwait(false); if (NetEventSource.IsEnabled) Trace(streamId, $"Started writing. {nameof(amount)}={amount}"); - FrameHeader frameHeader = new FrameHeader(FrameHeader.WindowUpdateLength, FrameType.WindowUpdate, FrameFlags.None, streamId); - frameHeader.WriteTo(writeBuffer); - writeBuffer = writeBuffer.Slice(FrameHeader.Size); - - BinaryPrimitives.WriteInt32BigEndian(writeBuffer.Span, amount); + FrameHeader.WriteTo(writeBuffer.Span, FrameHeader.WindowUpdateLength, FrameType.WindowUpdate, FrameFlags.None, streamId); + BinaryPrimitives.WriteInt32BigEndian(writeBuffer.Span.Slice(FrameHeader.Size), amount); FinishWrite(FlushTiming.Now); // make sure window updates are seen as soon as possible } @@ -1423,15 +1397,6 @@ private void ExtendWindow(int amount) LogExceptions(SendWindowUpdateAsync(0, windowUpdateSize)); } - private void WriteFrameHeader(FrameHeader frameHeader) - { - if (NetEventSource.IsEnabled) Trace($"{frameHeader}"); - Debug.Assert(_outgoingBuffer.AvailableMemory.Length >= FrameHeader.Size); - - frameHeader.WriteTo(_outgoingBuffer.AvailableSpan); - _outgoingBuffer.Commit(FrameHeader.Size); - } - /// Abort all streams and cause further processing to fail. /// Exception causing Abort to be called. private void Abort(Exception abortException) @@ -1619,15 +1584,15 @@ private enum FrameType : byte Last = 10 } - private struct FrameHeader + private readonly struct FrameHeader { - public int Length; - public FrameType Type; - public FrameFlags Flags; - public int StreamId; + public readonly int PayloadLength; + public readonly FrameType Type; + public readonly FrameFlags Flags; + public readonly int StreamId; public const int Size = 9; - public const int MaxLength = 16384; + public const int MaxPayloadLength = 16384; public const int SettingLength = 6; // per setting (total SETTINGS length must be a multiple of this) public const int PriorityInfoLength = 5; // for both PRIORITY frame and priority info within HEADERS @@ -1636,11 +1601,11 @@ private struct FrameHeader public const int RstStreamLength = 4; public const int GoAwayMinLength = 8; - public FrameHeader(int length, FrameType type, FrameFlags flags, int streamId) + public FrameHeader(int payloadLength, FrameType type, FrameFlags flags, int streamId) { Debug.Assert(streamId >= 0); - Length = length; + PayloadLength = payloadLength; Type = type; Flags = flags; StreamId = streamId; @@ -1656,36 +1621,31 @@ public static FrameHeader ReadFrom(ReadOnlySpan buffer) { Debug.Assert(buffer.Length >= Size); - return new FrameHeader( - (buffer[0] << 16) | (buffer[1] << 8) | buffer[2], - (FrameType)buffer[3], - (FrameFlags)buffer[4], - (int)((uint)((buffer[5] << 24) | (buffer[6] << 16) | (buffer[7] << 8) | buffer[8]) & 0x7FFFFFFF)); + FrameFlags flags = (FrameFlags)buffer[4]; // do first to avoid some bounds checks + int payloadLength = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2]; + FrameType type = (FrameType)buffer[3]; + int streamId = (int)(BinaryPrimitives.ReadUInt32BigEndian(buffer.Slice(5)) & 0x7FFFFFFF); + + return new FrameHeader(payloadLength, type, flags, streamId); } - public void WriteTo(Span buffer) + public static void WriteTo(Span destination, int payloadLength, FrameType type, FrameFlags flags, int streamId) { - Debug.Assert(buffer.Length >= Size); - Debug.Assert(Type <= FrameType.Last); - Debug.Assert((Flags & FrameFlags.ValidBits) == Flags); - Debug.Assert(Length <= MaxLength); - - buffer[0] = (byte)((Length & 0x00FF0000) >> 16); - buffer[1] = (byte)((Length & 0x0000FF00) >> 8); - buffer[2] = (byte)(Length & 0x000000FF); + Debug.Assert(destination.Length >= Size); + Debug.Assert(type <= FrameType.Last); + Debug.Assert((flags & FrameFlags.ValidBits) == flags); + Debug.Assert((uint)payloadLength <= MaxPayloadLength); - buffer[3] = (byte)Type; - buffer[4] = (byte)Flags; - - buffer[5] = (byte)((StreamId & 0xFF000000) >> 24); - buffer[6] = (byte)((StreamId & 0x00FF0000) >> 16); - buffer[7] = (byte)((StreamId & 0x0000FF00) >> 8); - buffer[8] = (byte)(StreamId & 0x000000FF); + // This ordering helps eliminate bounds checks. + BinaryPrimitives.WriteInt32BigEndian(destination.Slice(5), streamId); + destination[4] = (byte)flags; + destination[0] = (byte)((payloadLength & 0x00FF0000) >> 16); + destination[1] = (byte)((payloadLength & 0x0000FF00) >> 8); + destination[2] = (byte)(payloadLength & 0x000000FF); + destination[3] = (byte)type; } - public void WriteTo(Memory buffer) => WriteTo(buffer.Span); - - public override string ToString() => $"StreamId={StreamId}; Type={Type}; Flags={Flags}; Length={Length}"; // Description for diagnostic purposes + public override string ToString() => $"StreamId={StreamId}; Type={Type}; Flags={Flags}; PayloadLength={PayloadLength}"; // Description for diagnostic purposes } [Flags] @@ -1806,26 +1766,6 @@ e is Http2ProtocolException || } } - private Http2Stream AddStream(int streamId, HttpRequestMessage request) - { - lock (SyncObject) - { - if (_disposed || _lastStreamId != -1) - { - // The connection is shutting down. - // Throw a retryable request exception. This will cause retry logic to kick in - // and perform another connection attempt. The user should never see this exception. - throw GetShutdownException(); - } - - Http2Stream http2Stream = new Http2Stream(request, this, streamId, _initialWindowSize); - - _httpStreams.Add(streamId, http2Stream); - - return http2Stream; - } - } - private void RemoveStream(Http2Stream http2Stream) { if (NetEventSource.IsEnabled) Trace(http2Stream.StreamId, ""); @@ -1833,27 +1773,25 @@ private void RemoveStream(Http2Stream http2Stream) lock (SyncObject) { - if (!_httpStreams.Remove(http2Stream.StreamId, out Http2Stream? removed)) + if (!_httpStreams.Remove(http2Stream.StreamId)) { Debug.Fail($"Stream {http2Stream.StreamId} not found in dictionary during RemoveStream???"); return; } - _concurrentStreams.AdjustCredit(1); - - Debug.Assert(removed == http2Stream, "_httpStreams.TryRemove returned unexpected stream"); - if (_httpStreams.Count == 0) { // If this was last pending request, get timestamp so we can monitor idle time. _idleSinceTickCount = Environment.TickCount64; - } - if (_disposed || _lastStreamId != -1) - { - CheckForShutdown(); + if (_disposed || _lastStreamId != -1) + { + CheckForShutdown(); + } } } + + _concurrentStreams.AdjustCredit(1); } public sealed override string ToString() => $"{nameof(Http2Connection)}({_pool})"; // Description for diagnostic purposes @@ -1869,5 +1807,20 @@ internal void Trace(int streamId, string message, [CallerMemberName] string? mem memberName, // method name message); // message + [DoesNotReturn] + private static void ThrowRetry(string message, Exception innerException) => + throw new HttpRequestException(message, innerException, allowRetry: RequestRetryType.RetryOnSameOrNextProxy); + + [DoesNotReturn] + private static void ThrowRequestAborted(Exception? innerException = null) => + throw new IOException(SR.net_http_request_aborted, innerException); + + [DoesNotReturn] + private static void ThrowProtocolError() => + ThrowProtocolError(Http2ProtocolErrorCode.ProtocolError); + + [DoesNotReturn] + private static void ThrowProtocolError(Http2ProtocolErrorCode errorCode) => + throw new Http2ConnectionException(errorCode); } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs index 5e4a3839de6d47..146a48da27d186 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs @@ -18,7 +18,7 @@ namespace System.Net.Http { internal sealed partial class Http2Connection { - private sealed class Http2Stream : IValueTaskSource, IHttpTrace, IHttpHeadersHandler + private sealed class Http2Stream : IValueTaskSource, IHttpHeadersHandler, IHttpTrace { private const int InitialStreamBufferSize = #if DEBUG @@ -27,14 +27,13 @@ private sealed class Http2Stream : IValueTaskSource, IHttpTrace, IHttpHeadersHan 1024; #endif - private static readonly byte[] s_statusHeaderName = Encoding.ASCII.GetBytes(":status"); + private static ReadOnlySpan StatusHeaderName => new byte[] { (byte)':', (byte)'s', (byte)'t', (byte)'a', (byte)'t', (byte)'u', (byte)'s' }; private readonly Http2Connection _connection; - private readonly int _streamId; private readonly HttpRequestMessage _request; private HttpResponseMessage? _response; /// Stores any trailers received after returning the response content to the caller. - private List>? _trailers; + private HttpResponseHeaders? _trailers; private ArrayBuffer _responseBuffer; // mutable struct, do not make this readonly private int _pendingWindowUpdate; @@ -71,6 +70,8 @@ private sealed class Http2Stream : IValueTaskSource, IHttpTrace, IHttpHeadersHan /// Reset _waitSource. /// private ManualResetValueTaskSourceCore _waitSource = new ManualResetValueTaskSourceCore { RunContinuationsAsynchronously = true }; // mutable struct, do not make this readonly + /// Cancellation registration used to cancel the . + private CancellationTokenRegistration _waitSourceCancellation; /// /// Whether code has requested or is about to request a wait be performed and thus requires a call to SetResult to complete it. /// This is read and written while holding the lock so that most operations on _waitSource don't need to be. @@ -79,9 +80,6 @@ private sealed class Http2Stream : IValueTaskSource, IHttpTrace, IHttpHeadersHan private readonly CancellationTokenSource? _requestBodyCancellationSource; - // This is a linked token combining the above source and the user-supplied token to SendRequestBodyAsync - private CancellationToken _requestBodyCancellationToken; - private readonly TaskCompletionSource? _expect100ContinueWaiter; private int _headerBudgetRemaining; @@ -91,11 +89,10 @@ private sealed class Http2Stream : IValueTaskSource, IHttpTrace, IHttpHeadersHan // See comment on ConnectionWindowThreshold. private const int StreamWindowThreshold = StreamWindowSize / 8; - public Http2Stream(HttpRequestMessage request, Http2Connection connection, int streamId, int initialWindowSize) + public Http2Stream(HttpRequestMessage request, Http2Connection connection, int initialWindowSize) { _request = request; _connection = connection; - _streamId = streamId; _requestCompletionState = StreamCompletionState.InProgress; _responseCompletionState = StreamCompletionState.InProgress; @@ -132,12 +129,19 @@ public Http2Stream(HttpRequestMessage request, Http2Connection connection, int s } } + _response = new HttpResponseMessage() + { + Version = HttpVersion.Version20, + RequestMessage = _request, + Content = new HttpConnectionResponseContent() + }; + if (NetEventSource.IsEnabled) Trace($"{request}, {nameof(initialWindowSize)}={initialWindowSize}"); } private object SyncObject => this; // this isn't handed out to code that may lock on it - public int StreamId => _streamId; + public int StreamId { get; set; } public HttpResponseMessage GetAndClearResponse() { @@ -160,28 +164,44 @@ public async Task SendRequestBodyAsync(CancellationToken cancellationToken) } if (NetEventSource.IsEnabled) Trace($"{_request.Content}"); - Debug.Assert(_requestBodyCancellationSource != null); - // Create a linked cancellation token source so that we can cancel the request in the event of receiving RST_STREAM - // and similiar situations where we need to cancel the request body (see Cancel method). - _requestBodyCancellationToken = cancellationToken.CanBeCanceled ? - CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _requestBodyCancellationSource.Token).Token : - _requestBodyCancellationSource.Token; - + // Cancel the request body sending if cancellation is requested on the supplied cancellation token. + // Normally we might create a linked token, but once cancellation is requested, we can't recover anyway, + // so it's fine to cancel the source representing the whole request body, and doing so allows us to avoid + // creating another CTS instance and the associated nodes inside of it. With this, cancellation will be + // requested on _requestBodyCancellationSource when we need to cancel the request stream for any reason, + // such as receiving an RST_STREAM or when the passed in token has cancellation requested. However, to + // avoid unnecessarily registering with the cancellation token unless we have to, we wait to do so until + // either we know we need to do a Expect: 100-continue send or until we know that the copying of our + // content completed asynchronously. + CancellationTokenRegistration linkedRegistration = default; try { bool sendRequestContent = true; if (_expect100ContinueWaiter != null) { - sendRequestContent = await WaitFor100ContinueAsync(_requestBodyCancellationToken).ConfigureAwait(false); + linkedRegistration = RegisterRequestBodyCancellation(cancellationToken); + sendRequestContent = await WaitFor100ContinueAsync(_requestBodyCancellationSource.Token).ConfigureAwait(false); } if (sendRequestContent) { - using (Http2WriteStream writeStream = new Http2WriteStream(this)) + using var writeStream = new Http2WriteStream(this); + + ValueTask vt = _request.Content.InternalCopyToAsync(writeStream, context: null, _requestBodyCancellationSource.Token); + if (vt.IsCompleted) + { + vt.GetAwaiter().GetResult(); + } + else { - await _request.Content.CopyToAsync(writeStream, null, _requestBodyCancellationToken).ConfigureAwait(false); + if (linkedRegistration.Equals(default)) + { + linkedRegistration = RegisterRequestBodyCancellation(cancellationToken); + } + + await vt.ConfigureAwait(false); } } @@ -190,9 +210,7 @@ public async Task SendRequestBodyAsync(CancellationToken cancellationToken) catch (Exception e) { if (NetEventSource.IsEnabled) Trace($"Failed to send request body: {e}"); - - bool signalWaiter = false; - bool sendReset = false; + bool signalWaiter; Debug.Assert(!Monitor.IsEntered(SyncObject)); lock (SyncObject) @@ -211,19 +229,15 @@ public async Task SendRequestBodyAsync(CancellationToken cancellationToken) } // This should not cause RST_STREAM to be sent because the request is still marked as in progress. + bool sendReset; (signalWaiter, sendReset) = CancelResponseBody(); Debug.Assert(!sendReset); _requestCompletionState = StreamCompletionState.Failed; - sendReset = true; Complete(); } - if (sendReset) - { - SendReset(); - } - + SendReset(); if (signalWaiter) { _waitSource.SetResult(true); @@ -231,6 +245,10 @@ public async Task SendRequestBodyAsync(CancellationToken cancellationToken) throw; } + finally + { + linkedRegistration.Dispose(); + } // New scope here to avoid variable name conflict on "sendReset" { @@ -239,21 +257,14 @@ public async Task SendRequestBodyAsync(CancellationToken cancellationToken) lock (SyncObject) { Debug.Assert(_requestCompletionState == StreamCompletionState.InProgress, $"Request already completed with state={_requestCompletionState}"); - _requestCompletionState = StreamCompletionState.Completed; - if (_responseCompletionState == StreamCompletionState.Failed) + + if (_responseCompletionState != StreamCompletionState.InProgress) { // Note, we can reach this point if the response stream failed but cancellation didn't propagate before we finished. - sendReset = true; + sendReset = _responseCompletionState == StreamCompletionState.Failed; Complete(); } - else - { - if (_responseCompletionState == StreamCompletionState.Completed) - { - Complete(); - } - } } if (sendReset) @@ -264,7 +275,7 @@ public async Task SendRequestBodyAsync(CancellationToken cancellationToken) { // Send EndStream asynchronously and without cancellation. // If this fails, it means that the connection is aborting and we will be reset. - _connection.LogExceptions(_connection.SendEndStreamAsync(_streamId)); + _connection.LogExceptions(_connection.SendEndStreamAsync(StreamId)); } } } @@ -275,29 +286,31 @@ public async Task SendRequestBodyAsync(CancellationToken cancellationToken) // If we get response status >= 300, we will not send the request body. public async ValueTask WaitFor100ContinueAsync(CancellationToken cancellationToken) { - Debug.Assert(_request.Content != null); + Debug.Assert(_request?.Content != null); if (NetEventSource.IsEnabled) Trace($"Waiting to send request body content for 100-Continue."); - // use TCS created in constructor. It will complete when one of two things occurs: - // 1. if a timer fires before we receive the relevant response from the server. - // 2. if we receive the relevant response from the server before a timer fires. - // In the first case, we could run this continuation synchronously, but in the latter, we shouldn't, - // as we could end up starting the body copy operation on the main event loop thread, which could - // then starve the processing of other requests. So, we make the TCS RunContinuationsAsynchronously. - bool sendRequestContent; + // Use TCS created in constructor. It will complete when one of three things occurs: + // 1. we receive the relevant response from the server. + // 2. the timer fires before we receive the relevant response from the server. + // 3. cancellation is requested before we receive the relevant response from the server. + // We need to run the continuation asynchronously for cases 1 and 3 (for 1 so that we don't starve the body copy operation, and + // for 3 so that we don't run a lot of work as part of code calling Cancel), so the TCS is created to run continuations asynchronously. + // We await the created Timer's disposal so that we ensure any work associated with it has quiesced prior to this method + // returning, just in case this object is pooled and potentially reused for another operation in the future. TaskCompletionSource waiter = _expect100ContinueWaiter!; - using (var expect100Timer = new Timer(s => + using (cancellationToken.UnsafeRegister(s => ((TaskCompletionSource)s!).TrySetResult(false), waiter)) + await using (new Timer(s => { var thisRef = (Http2Stream)s!; if (NetEventSource.IsEnabled) thisRef.Trace($"100-Continue timer expired."); thisRef._expect100ContinueWaiter?.TrySetResult(true); - }, this, _connection._pool.Settings._expect100ContinueTimeout, Timeout.InfiniteTimeSpan)) + }, this, _connection._pool.Settings._expect100ContinueTimeout, Timeout.InfiniteTimeSpan).ConfigureAwait(false)) { - sendRequestContent = await waiter.Task.ConfigureAwait(false); - // By now, either we got a response from the server or the timer expired. + bool shouldSendContent = await waiter.Task.ConfigureAwait(false); + // By now, either we got a response from the server or the timer expired or cancellation was requested. + CancellationHelper.ThrowIfCancellationRequested(cancellationToken); + return shouldSendContent; } - - return sendRequestContent; } private void SendReset() @@ -313,7 +326,7 @@ private void SendReset() // Don't send a RST_STREAM if we've already received one from the server. if (_resetException == null) { - _connection.LogExceptions(_connection.SendRstStreamAsync(_streamId, Http2ProtocolErrorCode.Cancel)); + _connection.LogExceptions(_connection.SendRstStreamAsync(StreamId, Http2ProtocolErrorCode.Cancel)); } } @@ -327,14 +340,11 @@ private void Complete() _connection.RemoveStream(this); - lock (SyncObject) + CreditWaiter? w = _creditWaiter; + if (w != null) { - CreditWaiter? w = _creditWaiter; - if (w != null) - { - w.Dispose(); - _creditWaiter = null; - } + w.Dispose(); + _creditWaiter = null; } } @@ -358,11 +368,8 @@ private void Cancel() (signalWaiter, sendReset) = CancelResponseBody(); } - if (requestBodyCancellationSource != null) - { - // When cancellation propagates, SendRequestBodyAsync will set _requestCompletionState to Failed - requestBodyCancellationSource.Cancel(); - } + // When cancellation propagates, SendRequestBodyAsync will set _requestCompletionState to Failed + requestBodyCancellationSource?.Cancel(); if (sendReset) { @@ -437,7 +444,7 @@ void IHttpHeadersHandler.OnStaticIndexedHeader(int index, ReadOnlySpan val public void OnHeader(ReadOnlySpan name, ReadOnlySpan value) { if (NetEventSource.IsEnabled) Trace($"{Encoding.ASCII.GetString(name)}: {Encoding.ASCII.GetString(value)}"); - Debug.Assert(name != null && name.Length > 0); + Debug.Assert(name.Length > 0); _headerBudgetRemaining -= name.Length + value.Length; if (_headerBudgetRemaining < 0) @@ -463,7 +470,7 @@ public void OnHeader(ReadOnlySpan name, ReadOnlySpan value) throw new HttpRequestException(SR.net_http_invalid_response_pseudo_header_in_trailer); } - if (name.SequenceEqual(s_statusHeaderName)) + if (name.SequenceEqual(StatusHeaderName)) { if (_responseProtocolState != ResponseProtocolState.ExpectingStatus) { @@ -472,13 +479,8 @@ public void OnHeader(ReadOnlySpan name, ReadOnlySpan value) } int statusValue = ParseStatusCode(value); - _response = new HttpResponseMessage() - { - Version = HttpVersion.Version20, - RequestMessage = _request, - Content = new HttpConnectionResponseContent(), - StatusCode = (HttpStatusCode)statusValue - }; + Debug.Assert(_response != null); + _response.StatusCode = (HttpStatusCode)statusValue; if (statusValue < 200) { @@ -538,7 +540,7 @@ public void OnHeader(ReadOnlySpan name, ReadOnlySpan value) { Debug.Assert(_trailers != null); string headerValue = descriptor.GetHeaderValue(value); - _trailers.Add(KeyValuePair.Create((descriptor.HeaderType & HttpHeaderType.Request) == HttpHeaderType.Request ? descriptor.AsCustomHeader() : descriptor, headerValue)); + _trailers.TryAddWithoutValidation((descriptor.HeaderType & HttpHeaderType.Request) == HttpHeaderType.Request ? descriptor.AsCustomHeader() : descriptor, headerValue); } else if ((descriptor.HeaderType & HttpHeaderType.Content) == HttpHeaderType.Content) { @@ -561,20 +563,20 @@ public void OnHeadersStart() Debug.Assert(!Monitor.IsEntered(SyncObject)); lock (SyncObject) { - if (_responseProtocolState == ResponseProtocolState.Aborted) - { - return; - } - - if (_responseProtocolState != ResponseProtocolState.ExpectingStatus && _responseProtocolState != ResponseProtocolState.ExpectingData) - { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); - } - - if (_responseProtocolState == ResponseProtocolState.ExpectingData) + switch (_responseProtocolState) { - _responseProtocolState = ResponseProtocolState.ExpectingTrailingHeaders; - _trailers ??= new List>(); + case ResponseProtocolState.ExpectingStatus: + case ResponseProtocolState.Aborted: + break; + + case ResponseProtocolState.ExpectingData: + _responseProtocolState = ResponseProtocolState.ExpectingTrailingHeaders; + _trailers ??= new HttpResponseHeaders(containsTrailingHeaders: true); + break; + + default: + ThrowProtocolError(); + break; } } } @@ -585,45 +587,38 @@ public void OnHeadersComplete(bool endStream) bool signalWaiter; lock (SyncObject) { - if (_responseProtocolState == ResponseProtocolState.Aborted) + switch (_responseProtocolState) { - return; - } + case ResponseProtocolState.Aborted: + return; - if (_responseProtocolState != ResponseProtocolState.ExpectingHeaders && _responseProtocolState != ResponseProtocolState.ExpectingTrailingHeaders && _responseProtocolState != ResponseProtocolState.ExpectingIgnoredHeaders) - { - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); - } + case ResponseProtocolState.ExpectingHeaders: + _responseProtocolState = endStream ? ResponseProtocolState.Complete : ResponseProtocolState.ExpectingData; + break; - if (_responseProtocolState == ResponseProtocolState.ExpectingHeaders) - { - _responseProtocolState = endStream ? ResponseProtocolState.Complete : ResponseProtocolState.ExpectingData; - } - else if (_responseProtocolState == ResponseProtocolState.ExpectingTrailingHeaders) - { - if (!endStream) - { - if (NetEventSource.IsEnabled) Trace("Trailing headers received without endStream"); - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); - } + case ResponseProtocolState.ExpectingTrailingHeaders: + if (!endStream) + { + if (NetEventSource.IsEnabled) Trace("Trailing headers received without endStream"); + ThrowProtocolError(); + } + _responseProtocolState = ResponseProtocolState.Complete; + break; - _responseProtocolState = ResponseProtocolState.Complete; - } - else if (_responseProtocolState == ResponseProtocolState.ExpectingIgnoredHeaders) - { - if (endStream) - { - // we should not get endStream while processing 1xx response. - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); - } + case ResponseProtocolState.ExpectingIgnoredHeaders: + if (endStream) + { + // we should not get endStream while processing 1xx response. + ThrowProtocolError(); + } - _responseProtocolState = ResponseProtocolState.ExpectingStatus; - // We should wait for final response before signaling to waiter. - return; - } - else - { - _responseProtocolState = ResponseProtocolState.ExpectingData; + // We should wait for final response before signaling to waiter. + _responseProtocolState = ResponseProtocolState.ExpectingStatus; + return; + + default: + ThrowProtocolError(); + break; } if (endStream) @@ -657,21 +652,24 @@ public void OnResponseData(ReadOnlySpan buffer, bool endStream) bool signalWaiter; lock (SyncObject) { - if (_responseProtocolState == ResponseProtocolState.Aborted) + switch (_responseProtocolState) { - return; - } + case ResponseProtocolState.ExpectingData: + break; - if (_responseProtocolState != ResponseProtocolState.ExpectingData) - { - // Flow control messages are not valid in this state. - throw new Http2ConnectionException(Http2ProtocolErrorCode.ProtocolError); + case ResponseProtocolState.Aborted: + return; + + default: + // Flow control messages are not valid in this state. + ThrowProtocolError(); + break; } if (_responseBuffer.ActiveLength + buffer.Length > StreamWindowSize) { // Window size exceeded. - throw new Http2ConnectionException(Http2ProtocolErrorCode.FlowControlError); + ThrowProtocolError(Http2ProtocolErrorCode.FlowControlError); } _responseBuffer.EnsureAvailableSpace(buffer.Length); @@ -783,19 +781,19 @@ private void CheckResponseBodyState() { Debug.Assert(Monitor.IsEntered(SyncObject)); - if (_resetException != null) + if (_resetException is Exception resetException) { if (_canRetry) { - throw new HttpRequestException(SR.net_http_request_aborted, _resetException, allowRetry: RequestRetryType.RetryOnSameOrNextProxy); + ThrowRetry(SR.net_http_request_aborted, resetException); } - throw new IOException(SR.net_http_request_aborted, _resetException); + ThrowRequestAborted(resetException); } if (_responseProtocolState == ResponseProtocolState.Aborted) { - throw new IOException(SR.net_http_request_aborted); + ThrowRequestAborted(); } } @@ -857,7 +855,7 @@ public async Task ReadResponseHeadersAsync(CancellationToken cancellationToken) { // If there are any trailers, copy them over to the response. Normally this would be handled by // the response stream hitting EOF, but if there is no response body, we do it here. - CopyTrailersToResponseMessage(_response); + MoveTrailersToResponseMessage(_response); responseContent.SetStream(EmptyReadStream.Instance); } else @@ -893,7 +891,7 @@ private void ExtendWindow(int amount) int windowUpdateSize = _pendingWindowUpdate; _pendingWindowUpdate = 0; - _connection.LogExceptions(_connection.SendWindowUpdateAsync(_streamId, windowUpdateSize)); + _connection.LogExceptions(_connection.SendWindowUpdateAsync(StreamId, windowUpdateSize)); } private (bool wait, int bytesRead) TryReadFromBuffer(Span buffer, bool partOfSyncRead = false) @@ -952,7 +950,7 @@ public int ReadData(Span buffer, HttpResponseMessage responseMessage) else { // We've hit EOF. Pull in from the Http2Stream any trailers that were temporarily stored there. - CopyTrailersToResponseMessage(responseMessage); + MoveTrailersToResponseMessage(responseMessage); } return bytesRead; @@ -981,7 +979,7 @@ public async ValueTask ReadDataAsync(Memory buffer, HttpResponseMessa else { // We've hit EOF. Pull in from the Http2Stream any trailers that were temporarily stored there. - CopyTrailersToResponseMessage(responseMessage); + MoveTrailersToResponseMessage(responseMessage); } return bytesRead; @@ -992,7 +990,7 @@ public void CopyTo(HttpResponseMessage responseMessage, Stream destination, int byte[] buffer = ArrayPool.Shared.Rent(bufferSize); try { - // Generallly the same logic as in ReadData, but wrapped in a loop where every read segment is written to the destination. + // Generally the same logic as in ReadData, but wrapped in a loop where every read segment is written to the destination. while (true) { (bool wait, int bytesRead) = TryReadFromBuffer(buffer, partOfSyncRead: true); @@ -1012,7 +1010,7 @@ public void CopyTo(HttpResponseMessage responseMessage, Stream destination, int else { // We've hit EOF. Pull in from the Http2Stream any trailers that were temporarily stored there. - CopyTrailersToResponseMessage(responseMessage); + MoveTrailersToResponseMessage(responseMessage); return; } } @@ -1028,7 +1026,7 @@ public async Task CopyToAsync(HttpResponseMessage responseMessage, Stream destin byte[] buffer = ArrayPool.Shared.Rent(bufferSize); try { - // Generallly the same logic as in ReadDataAsync, but wrapped in a loop where every read segment is written to the destination. + // Generally the same logic as in ReadDataAsync, but wrapped in a loop where every read segment is written to the destination. while (true) { (bool wait, int bytesRead) = TryReadFromBuffer(buffer); @@ -1048,7 +1046,7 @@ public async Task CopyToAsync(HttpResponseMessage responseMessage, Stream destin else { // We've hit EOF. Pull in from the Http2Stream any trailers that were temporarily stored there. - CopyTrailersToResponseMessage(responseMessage); + MoveTrailersToResponseMessage(responseMessage); return; } } @@ -1059,36 +1057,24 @@ public async Task CopyToAsync(HttpResponseMessage responseMessage, Stream destin } } - private void CopyTrailersToResponseMessage(HttpResponseMessage responseMessage) + private void MoveTrailersToResponseMessage(HttpResponseMessage responseMessage) { - if (_trailers != null && _trailers.Count > 0) + if (_trailers != null) { - foreach (KeyValuePair trailer in _trailers) - { - responseMessage.TrailingHeaders.TryAddWithoutValidation(trailer.Key, trailer.Value); - } - _trailers.Clear(); + responseMessage.StoreReceivedTrailingHeaders(_trailers); } } private async ValueTask SendDataAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken) { + Debug.Assert(_requestBodyCancellationSource != null); + // Deal with [ActiveIssue("https://github.com/dotnet/runtime/issues/17492")] // Custom HttpContent classes do not get passed the cancellationToken. // So, inject the expected CancellationToken here, to ensure we can cancel the request body send if needed. - CancellationTokenSource? customCancellationSource = null; - if (!cancellationToken.CanBeCanceled) - { - cancellationToken = _requestBodyCancellationToken; - } - else if (cancellationToken != _requestBodyCancellationToken) - { - // User passed a custom CancellationToken. - // We can't tell if it includes our Token or not, so assume it doesn't. - customCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _requestBodyCancellationSource!.Token); - cancellationToken = customCancellationSource.Token; - } - + CancellationTokenRegistration linkedRegistration = cancellationToken.CanBeCanceled && cancellationToken != _requestBodyCancellationSource.Token ? + RegisterRequestBodyCancellation(cancellationToken) : + default; try { while (buffer.Length > 0) @@ -1105,12 +1091,12 @@ private async ValueTask SendDataAsync(ReadOnlyMemory buffer, CancellationT { if (_creditWaiter is null) { - _creditWaiter = new CancelableCreditWaiter(SyncObject, cancellationToken); + _creditWaiter = new CancelableCreditWaiter(SyncObject, _requestBodyCancellationSource.Token); } else { Debug.Assert(!_creditWaiter.IsPending); - _creditWaiter.ResetForAwait(cancellationToken); + _creditWaiter.ResetForAwait(_requestBodyCancellationSource.Token); } _creditWaiter.Amount = buffer.Length; } @@ -1126,12 +1112,12 @@ private async ValueTask SendDataAsync(ReadOnlyMemory buffer, CancellationT ReadOnlyMemory current; (current, buffer) = SplitBuffer(buffer, sendSize); - await _connection.SendStreamDataAsync(_streamId, current, cancellationToken).ConfigureAwait(false); + await _connection.SendStreamDataAsync(StreamId, current, _requestBodyCancellationSource.Token).ConfigureAwait(false); } } finally { - customCancellationSource?.Dispose(); + linkedRegistration.Dispose(); } } @@ -1157,12 +1143,26 @@ private void CloseResponseBody() _responseBuffer.Dispose(); } + private CancellationTokenRegistration RegisterRequestBodyCancellation(CancellationToken cancellationToken) => + cancellationToken.UnsafeRegister(s => ((CancellationTokenSource)s!).Cancel(), _requestBodyCancellationSource); + // This object is itself usable as a backing source for ValueTask. Since there's only ever one awaiter // for this object's state transitions at a time, we allow the object to be awaited directly. All functionality // associated with the implementation is just delegated to the ManualResetValueTaskSourceCore. ValueTaskSourceStatus IValueTaskSource.GetStatus(short token) => _waitSource.GetStatus(token); void IValueTaskSource.OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) => _waitSource.OnCompleted(continuation, state, token, flags); - void IValueTaskSource.GetResult(short token) => _waitSource.GetResult(token); + void IValueTaskSource.GetResult(short token) + { + Debug.Assert(!Monitor.IsEntered(SyncObject)); + + // Clean up the registration. It's important to Dispose rather than Unregister, so that we wait + // for any in-flight cancellation to complete. + _waitSourceCancellation.Dispose(); + _waitSourceCancellation = default; + + // Propagate any exceptions if there were any. + _waitSource.GetResult(token); + } private void WaitForData() { @@ -1180,50 +1180,45 @@ private ValueTask WaitForDataAsync(CancellationToken cancellationToken) // Reset'ing it is this code here. It's possible for this to race with the _waitSource being completed, but that's ok and is // handled by _waitSource as one of its primary purposes. We can't assert _hasWaiter here, though, as once we released the // lock, a producer could have seen _hasWaiter as true and both set it to false and signaled _waitSource. - if (!cancellationToken.CanBeCanceled) - { - return new ValueTask(this, _waitSource.Version); - } // With HttpClient, the supplied cancellation token will always be cancelable, as HttpClient supplies a token that // will have cancellation requested if CancelPendingRequests is called (or when a non-infinite Timeout expires). // However, this could still be non-cancelable if HttpMessageInvoker was used, at which point this will only be - // cancelable if the caller's token was cancelable. To avoid the extra allocation here in such a case, we make - // this pay-for-play: if the token isn't cancelable, return a ValueTask wrapping this object directly, and only - // if it is cancelable, then register for the cancellation callback, allocate a task for the asynchronously - // completing case, etc. - return GetCancelableWaiterTask(cancellationToken); + // cancelable if the caller's token was cancelable. - async ValueTask GetCancelableWaiterTask(CancellationToken cancellationToken) + _waitSourceCancellation = cancellationToken.UnsafeRegister(s => { - using (cancellationToken.UnsafeRegister(s => - { - var thisRef = (Http2Stream)s!; + var thisRef = (Http2Stream)s!; - bool signalWaiter; - Debug.Assert(!Monitor.IsEntered(thisRef.SyncObject)); - lock (thisRef.SyncObject) - { - signalWaiter = thisRef._hasWaiter; - thisRef._hasWaiter = false; - } + bool signalWaiter; + Debug.Assert(!Monitor.IsEntered(thisRef.SyncObject)); + lock (thisRef.SyncObject) + { + signalWaiter = thisRef._hasWaiter; + thisRef._hasWaiter = false; + } - if (signalWaiter) - { - // Wake up the wait. It will then immediately check whether cancellation was requested and throw if it was. - thisRef._waitSource.SetResult(true); - } - }, this)) + if (signalWaiter) { - await new ValueTask(this, _waitSource.Version).ConfigureAwait(false); + // Wake up the wait. It will then immediately check whether cancellation was requested and throw if it was. + thisRef._waitSource.SetException(ExceptionDispatchInfo.SetCurrentStackTrace( + CancellationHelper.CreateOperationCanceledException(null, thisRef._waitSourceCancellation.Token))); } + }, this); - CancellationHelper.ThrowIfCancellationRequested(cancellationToken); - } + // There's a race condition in UnsafeRegister above. If cancellation is requested prior to UnsafeRegister, + // the delegate may be invoked synchronously as part of the UnsafeRegister call. In that case, it will execute + // before _waitSourceCancellation has been set, which means UnsafeRegister will have set a cancellation + // exception into the wait source with a default token rather than the ideal one. To handle that, + // we check for cancellation again, and throw here with the right token. Worst case, if cancellation is + // requested prior to here, we end up allocating an extra OCE object. + CancellationHelper.ThrowIfCancellationRequested(cancellationToken); + + return new ValueTask(this, _waitSource.Version); } public void Trace(string message, [CallerMemberName] string? memberName = null) => - _connection.Trace(_streamId, message, memberName); + _connection.Trace(StreamId, message, memberName); private enum ResponseProtocolState : byte { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs index 7104057aa13498..a516450542eb7f 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net.Http.Headers; @@ -101,41 +102,43 @@ internal static int ParseStatusCode(ReadOnlySpan value) /// Awaits a task, ignoring any resulting exceptions. internal static void IgnoreExceptions(ValueTask task) { - _ = IgnoreExceptionsAsync(task); - - static async Task IgnoreExceptionsAsync(ValueTask task) + // Avoid TaskScheduler.UnobservedTaskException firing for any exceptions. + if (task.IsCompleted) { - try { await task.ConfigureAwait(false); } catch { } + if (task.IsFaulted) + { + _ = task.AsTask().Exception; + } } - } - - /// Awaits a task, ignoring any resulting exceptions. - internal static void IgnoreExceptions(Task task) - { - _ = IgnoreExceptionsAsync(task); - - static async Task IgnoreExceptionsAsync(Task task) + else { - try { await task.ConfigureAwait(false); } catch { } + task.AsTask().ContinueWith(t => _ = t.Exception, + CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); } } /// Awaits a task, logging any resulting exceptions (which are otherwise ignored). internal void LogExceptions(Task task) { - _ = LogExceptionsAsync(task); - - async Task LogExceptionsAsync(Task task) + if (task.IsCompleted) { - try - { - await task.ConfigureAwait(false); - } - catch (Exception e) + if (task.IsFaulted) { - if (NetEventSource.IsEnabled) Trace($"Exception from asynchronous processing: {e}"); + LogFaulted(this, task); } } + else + { + task.ContinueWith((t, state) => LogFaulted((HttpConnectionBase)state!, t), this, + CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default); + } + + static void LogFaulted(HttpConnectionBase connection, Task task) + { + Debug.Assert(task.IsFaulted); + Exception? e = task.Exception!.InnerException; // Access Exception even if not tracing, to avoid TaskScheduler.UnobservedTaskException firing + if (NetEventSource.IsEnabled) connection.Trace($"Exception from asynchronous processing: {e}"); + } } } } diff --git a/src/libraries/System.Net.Http/src/System/Threading/AsyncMutex.cs b/src/libraries/System.Net.Http/src/System/Threading/AsyncMutex.cs new file mode 100644 index 00000000000000..1065304f074b2a --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Threading/AsyncMutex.cs @@ -0,0 +1,301 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Concurrent; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; +using System.Threading.Tasks; +using System.Threading.Tasks.Sources; + +namespace System.Threading +{ + /// Provides an async mutex. + /// + /// This could be achieved with a constructed with an initial + /// and max limit of 1. However, this implementation is optimized to the needs of HTTP/2, + /// where the mutex is held for a very short period of time, when it is held any other + /// attempts to access it must wait asynchronously, where it's only binary rather than counting, and where + /// we want to minimize contention that a releaser incurs while trying to unblock a waiter. The primary + /// value-add is the fast-path interlocked checks that minimize contention for these use cases (essentially + /// making it an async futex), and then as long as we're wrapping something and we know exactly how all + /// consumers use the type, we can offer a ValueTask-based implementation that reuses waiter nodes. + /// + internal sealed class AsyncMutex + { + /// Fast-path gate count tracking access to the mutex. + /// + /// If the value is 1, the mutex can be entered atomically with an interlocked operation. + /// If the value is less than or equal to 0, the mutex is held and requires fallback to enter it. + /// + private int _gate = 1; + /// Secondary check guarded by the lock to indicate whether the mutex is acquired. + /// + /// This is only meaningful after having updated via interlockeds and taken the appropriate path. + /// If after decrementing we end up with a negative count, the mutex is contended, hence + /// starting as true. The primary purpose of this field + /// is to handle the race condition between one thread acquiring the mutex, then another thread trying to acquire + /// and getting as far as completing the interlocked operation, and then the original thread releasing; at that point + /// it'll hit the lock and we need to store that the mutex is available to enter. If we instead used a + /// SemaphoreSlim as the fallback from the interlockeds, this would have been its count, and it would have started + /// with an initial count of 0. + /// + private bool _lockedSemaphoreFull = true; + /// The tail of the double-linked circular waiting queue. + /// + /// Waiters are added at the tail. + /// Items are dequeued from the head (tail.Prev). + /// + private Waiter? _waitersTail; + /// A pool of waiter objects that are ready to be reused. + /// + /// There is no bound on this pool, but it ends up being implicitly bounded by the maximum number of concurrent + /// waiters there ever were, which for our uses in HTTP/2 will end up being the high-water mark of concurrent streams + /// on a single connection. + /// + private readonly ConcurrentQueue _unusedWaiters = new ConcurrentQueue(); + + /// Gets whether the mutex is currently held by some operation (not necessarily the caller). + /// This should be used only for asserts and debugging. + public bool IsHeld => _gate != 1; + + /// Objects used to synchronize operations on the instance. + private object SyncObj => _unusedWaiters; + + /// Asynchronously waits to enter the mutex. + /// The CancellationToken token to observe. + /// A task that will complete when the mutex has been entered or the enter canceled. + public ValueTask EnterAsync(CancellationToken cancellationToken) + { + // If cancellation was requested, bail immediately. + // If the mutex is not currently held nor contended, enter immediately. + // Otherwise, fall back to a more expensive likely-asynchronous wait. + return + cancellationToken.IsCancellationRequested ? FromCanceled(cancellationToken) : + Interlocked.Decrement(ref _gate) >= 0 ? default : + Contended(cancellationToken); + + // Everything that follows is the equivalent of: + // return _sem.WaitAsync(cancellationToken); + // if _sem were to be constructed as `new SemaphoreSlim(0)`. + + ValueTask Contended(CancellationToken cancellationToken) + { + // Get a reusable waiter object. We do this before the lock to minimize work (and especially allocation) + // done while holding the lock. It's possible we'll end up dequeuing a waiter and then under the lock + // discovering the mutex is now available, at which point we will have wasted an object. That's currently + // showing to be the better alternative (including not trying to put it back in that case). + if (!_unusedWaiters.TryDequeue(out Waiter? w)) + { + w = new Waiter(this); + } + + lock (SyncObj) + { + // Now that we're holding the lock, check to see whether the async lock is acquirable. + if (!_lockedSemaphoreFull) + { + // If we are able to acquire the lock, we're done. + _lockedSemaphoreFull = true; + return default; + } + + // The lock couldn't be acquired. + // Add the waiter to the linked list of waiters. + if (_waitersTail is null) + { + w.Next = w.Prev = w; + } + else + { + Debug.Assert(_waitersTail.Next != null && _waitersTail.Prev != null); + w.Next = _waitersTail; + w.Prev = _waitersTail.Prev; + w.Prev.Next = w.Next.Prev = w; + } + _waitersTail = w; + } + + // At this point the waiter was added to the list of waiters, so we want to + // register for cancellation in order to cancel it and remove it from the list + // if cancellation is requested. However, since we've released the lock, it's + // possible the waiter could have actually already been completed and removed + // from the list by another thread releasing the mutex. That's ok; we'll + // end up registering for cancellation here, and then when the consumer awaits + // it, the act of awaiting it will Dispose of the registration, ensuring that + // it won't run after that point, making it safe to pool that instance. + w.CancellationRegistration = cancellationToken.UnsafeRegister(s => OnCancellation(s), w); + + // Return the waiter as a value task. + return new ValueTask(w, w.Version); + + // Cancels the specified waiter if it's still in the list. + static void OnCancellation(object? state) + { + Waiter? w = (Waiter)state!; + AsyncMutex m = w.Owner; + + lock (m.SyncObj) + { + bool inList = w.Next != null; + if (inList) + { + // The waiter is in the list. + Debug.Assert(w.Prev != null); + + // The gate counter was decremented when this waiter was added. We need + // to undo that. Since the waiter is still in the list, the lock must + // still be held by someone, which means we don't need to do anything with + // the result of this increment. If it increments to < 1, then there are + // still other waiters. If it increments to 1, we're in a rare race condition + // where there are no other waiters and the owner just incremented the gate + // count; they would have seen it be < 1, so they will proceed to take the + // contended code path and synchronize on the lock we're holding... once we + // release it, they will appropriately update state. + Interlocked.Increment(ref m._gate); + + if (w.Next == w) + { + Debug.Assert(m._waitersTail == w); + m._waitersTail = null; + } + else + { + w.Next!.Prev = w.Prev; + w.Prev.Next = w.Next; + if (m._waitersTail == w) + { + m._waitersTail = w.Next; + } + } + + // Remove it from the list. + w.Next = w.Prev = null; + } + else + { + // The waiter was no longer in the list. We must not cancel it. + w = null; + } + } + + // If the waiter was in the list, we removed it under the lock and thus own + // the ability to cancel it. Do so. + w?.Cancel(); + } + } + } + + /// Releases the mutex. + /// The caller must logically own the mutex. This is not validated. + public void Exit() + { + if (Interlocked.Increment(ref _gate) < 1) + { + // This is the equivalent of: + // _sem.Release(); + // if _sem were to be constructed as `new SemaphoreSlim(0)`. + Contended(); + } + + void Contended() + { + Waiter? w; + lock (SyncObj) + { + Debug.Assert(_lockedSemaphoreFull); + + w = _waitersTail; + if (w is null) + { + _lockedSemaphoreFull = false; + } + else + { + Debug.Assert(w.Next != null && w.Prev != null); + Debug.Assert(w.Next != w || w.Prev == w); + Debug.Assert(w.Prev != w || w.Next == w); + + if (w.Next == w) + { + _waitersTail = null; + } + else + { + w = w.Prev; // get the head + Debug.Assert(w.Next != null && w.Prev != null); + Debug.Assert(w.Next != w && w.Prev != w); + + w.Next.Prev = w.Prev; + w.Prev.Next = w.Next; + } + + w.Next = w.Prev = null; + } + } + + // Either there wasn't a waiter, or we got one and successfully removed it from the list, + // at which point we own the ability to complete it. Do so. + w?.Set(); + } + } + + /// Creates a canceled ValueTask. + /// Separated out to reduce asm for this rare path in the call site. + [MethodImpl(MethodImplOptions.NoInlining)] + private static ValueTask FromCanceled(CancellationToken cancellationToken) => + new ValueTask(Task.FromCanceled(cancellationToken)); + + /// Represents a waiter for the mutex. + /// Implemented as a reusable backing source for a value task. + private sealed class Waiter : IValueTaskSource + { + private ManualResetValueTaskSourceCore _mrvtsc; // mutable struct; do not make this readonly + + public Waiter(AsyncMutex owner) + { + Owner = owner; + _mrvtsc.RunContinuationsAsynchronously = true; + } + + public AsyncMutex Owner { get; } + public CancellationTokenRegistration CancellationRegistration { get; set; } + public Waiter? Next { get; set; } + public Waiter? Prev { get; set; } + + public short Version => _mrvtsc.Version; + + public void Set() => _mrvtsc.SetResult(true); + public void Cancel() => _mrvtsc.SetException(ExceptionDispatchInfo.SetCurrentStackTrace(new OperationCanceledException(CancellationRegistration.Token))); + + void IValueTaskSource.GetResult(short token) + { + Debug.Assert(Next is null && Prev is null); + + // Dispose of the registration. It's critical that this Dispose rather than Unregister, + // so that we can be guaranteed all cancellation-related work has completed by the time + // we return the instance to the pool. Otherwise, a race condition could result in + // a cancellation request for this operation canceling another unlucky request that + // happened to reuse the same node. + Debug.Assert(!Monitor.IsEntered(Owner.SyncObj)); + CancellationRegistration.Dispose(); + + // Complete the operation, propagating any exceptions. + _mrvtsc.GetResult(token); + + // Reset the instance and return it to the pool. + // We don't bother with a try/finally to return instances + // to the pool in the case of exceptions. + _mrvtsc.Reset(); + Owner._unusedWaiters.Enqueue(this); + } + + public ValueTaskSourceStatus GetStatus(short token) => + _mrvtsc.GetStatus(token); + + public void OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) => + _mrvtsc.OnCompleted(continuation, state, token, flags); + } + } +} diff --git a/src/libraries/System.Net.Http/tests/EnterpriseTests/System.Net.Http.Enterprise.Tests.csproj b/src/libraries/System.Net.Http/tests/EnterpriseTests/System.Net.Http.Enterprise.Tests.csproj index 38385b5d780a71..f741b1160caf86 100644 --- a/src/libraries/System.Net.Http/tests/EnterpriseTests/System.Net.Http.Enterprise.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/EnterpriseTests/System.Net.Http.Enterprise.Tests.csproj @@ -5,8 +5,7 @@ - - Common\System\Net\EnterpriseTests\EnterpriseTestConfiguration.cs - + \ No newline at end of file diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs index b66becd57b419d..48cc1cee5f2d6f 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Headers.cs @@ -45,6 +45,33 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => }); } + [Fact] + public async Task SendAsync_DefaultHeaders_CorrectlyWritten() + { + const string Version = "2017-04-17"; + const string Blob = "BlockBlob"; + + await LoopbackServerFactory.CreateClientAndServerAsync(async uri => + { + using (HttpClient client = CreateHttpClient()) + { + client.DefaultRequestHeaders.TryAddWithoutValidation("x-ms-version", Version); + client.DefaultRequestHeaders.Add("x-ms-blob-type", Blob); + var message = new HttpRequestMessage(HttpMethod.Get, uri) { Version = UseVersion }; + (await client.SendAsync(message).ConfigureAwait(false)).Dispose(); + } + }, + async server => + { + HttpRequestData requestData = await server.HandleRequestAsync(HttpStatusCode.OK); + + string headerValue = requestData.GetSingleHeaderValue("x-ms-blob-type"); + Assert.Equal(Blob, headerValue); + headerValue = requestData.GetSingleHeaderValue("x-ms-version"); + Assert.Equal(Version, Version); + }); + } + [Theory] [InlineData("\u05D1\u05F1")] [InlineData("jp\u30A5")] diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs index 034ab35b739dd3..6f513bd363c35c 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs @@ -1636,6 +1636,7 @@ public async Task Http2_PendingSend_Cancellation() public async Task Http2_PendingSend_SendsReset(bool waitForData) { var cts = new CancellationTokenSource(); + var rstReceived = new TaskCompletionSource(); string content = new string('*', 300); var stream = new CustomContent.SlowTestStream(Encoding.UTF8.GetBytes(content), null, count: 60); @@ -1649,8 +1650,8 @@ await Http2LoopbackServer.CreateClientAndServerAsync(async url => await Assert.ThrowsAnyAsync(async () => await client.SendAsync(request, cts.Token)); - // Delay for a bit to ensure that the RST_STREAM for the previous request is sent before the next request starts. - await Task.Delay(2000); + // Wait until the RST_STREAM for the previous request is received before the next request starts. + await rstReceived.Task.TimeoutAfter(TimeSpan.FromSeconds(60)); // Send another request to verify that connection is still functional. request = new HttpRequestMessage(HttpMethod.Get, url); @@ -1678,7 +1679,9 @@ await Http2LoopbackServer.CreateClientAndServerAsync(async url => frameCount++; } while (frame.Type != FrameType.RstStream); - Assert.Equal(1, frame.StreamId); + Assert.Equal(1, frame.StreamId); + + rstReceived.SetResult(true); frame = null; (streamId, requestData) = await connection.ReadAndParseRequestHeaderAsync(); @@ -1862,7 +1865,6 @@ await Http2LoopbackServer.CreateClientAndServerAsync(async url => } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/31220")] public async Task PostAsyncExpect100Continue_NonSuccessResponse_RequestBodyNotSent() { string responseContent = "no no!"; @@ -1870,8 +1872,9 @@ public async Task PostAsyncExpect100Continue_NonSuccessResponse_RequestBodyNotSe await Http2LoopbackServer.CreateClientAndServerAsync(async url => { using (var handler = new SocketsHttpHandler()) - using (HttpClient client = CreateHttpClient()) + using (HttpClient client = CreateHttpClient(handler)) { + TestHelper.EnableUnencryptedHttp2IfNecessary(handler); handler.SslOptions.RemoteCertificateValidationCallback = delegate { return true; }; // Increase default Expect: 100-continue timeout to ensure that we don't accidentally fire the timer and send the request body. handler.Expect100ContinueTimeout = TimeSpan.FromSeconds(300); @@ -1899,7 +1902,7 @@ await Http2LoopbackServer.CreateClientAndServerAsync(async url => await connection.SendResponseBodyAsync(streamId, Encoding.ASCII.GetBytes(responseContent)); // Client should send empty request body - byte[] requestBody = await connection.ReadBodyAsync(); + byte[] requestBody = await connection.ReadBodyAsync(expectEndOfStream:true); Assert.Null(requestBody); await connection.ShutdownIgnoringErrorsAsync(streamId); @@ -1937,13 +1940,11 @@ public Task WaitForStreamAsync() public void Complete() { _waitForCompletion.SetResult(true); - _waitForCompletion = null; } public void Fail(Exception e) { _waitForCompletion.SetException(e); - _waitForCompletion = null; } } diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientMiniStressTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientMiniStressTest.cs index 2f28f98ab16b26..554c5ba5fa3fff 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientMiniStressTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientMiniStressTest.cs @@ -21,6 +21,7 @@ public sealed class SocketsHttpHandler_HttpClientMiniStress_NoVersion : HttpClie public SocketsHttpHandler_HttpClientMiniStress_NoVersion(ITestOutputHelper output) : base(output) { } [ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))] + [OuterLoop] [InlineData(1000000)] public void CreateAndDestroyManyClients(int numClients) { @@ -49,6 +50,7 @@ public sealed class SocketsHttpHandler_HttpClientMiniStress_Http11 : HttpClientM public SocketsHttpHandler_HttpClientMiniStress_Http11(ITestOutputHelper output) : base(output) { } [ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))] + [OuterLoop] [MemberData(nameof(PostStressOptions))] public async Task ManyClients_ManyPosts_Async(int numRequests, int dop, int numBytes) { @@ -86,6 +88,7 @@ await server.AcceptConnectionAsync(async connection => } } + [Collection(nameof(HttpClientMiniStress))] public abstract class HttpClientMiniStress : HttpClientHandlerTestBase { public HttpClientMiniStress(ITestOutputHelper output) : base(output) { } @@ -101,6 +104,7 @@ protected override HttpClient CreateHttpClient() => }); [ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))] + [OuterLoop] [MemberData(nameof(GetStressOptions))] public void SingleClient_ManyGets_Sync(int numRequests, int dop, HttpCompletionOption completionOption) { @@ -115,6 +119,7 @@ public void SingleClient_ManyGets_Sync(int numRequests, int dop, HttpCompletionO } [ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))] + [OuterLoop] [MemberData(nameof(GetStressOptions))] public async Task SingleClient_ManyGets_Async(int numRequests, int dop, HttpCompletionOption completionOption) { @@ -126,6 +131,7 @@ public async Task SingleClient_ManyGets_Async(int numRequests, int dop, HttpComp } [ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))] + [OuterLoop] [MemberData(nameof(GetStressOptions))] public void ManyClients_ManyGets(int numRequests, int dop, HttpCompletionOption completionOption) { @@ -140,6 +146,7 @@ public void ManyClients_ManyGets(int numRequests, int dop, HttpCompletionOption } [ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))] + [OuterLoop] [InlineData(5000)] public async Task MakeAndFaultManyRequests(int numRequests) { @@ -216,6 +223,7 @@ public static IEnumerable PostStressOptions() } [ConditionalFact(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))] + [OuterLoop] public async Task UnreadResponseMessage_Collectible() { await LoopbackServerFactory.CreateServerAsync(async (server, url) => diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs index ef0257e1cc56e4..544f188bd57707 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs @@ -221,7 +221,10 @@ public async Task GetContentAsync_NullResponseContent_ReturnsDefaultValue() { Assert.Same(string.Empty, await client.GetStringAsync(CreateFakeUri())); Assert.Same(Array.Empty(), await client.GetByteArrayAsync(CreateFakeUri())); - Assert.Same(Stream.Null, await client.GetStreamAsync(CreateFakeUri())); + + Stream s = await client.GetStreamAsync(CreateFakeUri()); + Assert.NotNull(s); + Assert.Equal(-1, s.ReadByte()); } } @@ -607,7 +610,7 @@ public void Timeout_TooShort_AllPendingOperationsCanceled(HttpCompletionOption c { using (var client = new HttpClient(new CustomResponseHandler((r, c) => WhenCanceled(c)))) { - client.Timeout = TimeSpan.FromMilliseconds(1); + client.Timeout = TimeSpan.FromMilliseconds(10); Task[] tasks = Enumerable.Range(0, 3).Select(_ => client.GetAsync(CreateFakeUri(), completionOption)).ToArray(); Assert.All(tasks, task => { OperationCanceledException e = Assert.ThrowsAny(() => task.GetAwaiter().GetResult()); diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpResponseMessageTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpResponseMessageTest.cs index fdeeeb065ca236..7c7fafee8d3486 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpResponseMessageTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpResponseMessageTest.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.IO; -using System.Net.Http.Headers; -using System.Threading; using System.Threading.Tasks; using Xunit; @@ -22,7 +19,7 @@ public void Ctor_Default_CorrectDefaults() Assert.Equal(HttpStatusCode.OK, rm.StatusCode); Assert.Equal("OK", rm.ReasonPhrase); Assert.Equal(new Version(1, 1), rm.Version); - Assert.Null(rm.Content); + Assert.NotNull(rm.Content); Assert.Null(rm.RequestMessage); } } @@ -35,7 +32,7 @@ public void Ctor_SpecifiedValues_CorrectValues() Assert.Equal(HttpStatusCode.Accepted, rm.StatusCode); Assert.Equal("Accepted", rm.ReasonPhrase); Assert.Equal(new Version(1, 1), rm.Version); - Assert.Null(rm.Content); + Assert.NotNull(rm.Content); Assert.Null(rm.RequestMessage); } } @@ -232,8 +229,15 @@ public void Content_SetToNull_Accepted() { using (var rm = new HttpResponseMessage()) { + HttpContent c1 = rm.Content; + Assert.Same(c1, rm.Content); + rm.Content = null; - Assert.Null(rm.Content); + + HttpContent c2 = rm.Content; + Assert.Same(c2, rm.Content); + + Assert.NotSame(c1, c2); } } @@ -249,6 +253,35 @@ public void StatusCode_InvalidStatusCodeRange_ThrowsArgumentOutOfRangeException( } } + [Fact] + public async Task DefaultContent_ReadableNotWritable_Success() + { + var resp = new HttpResponseMessage(); + + HttpContent c = resp.Content; + Assert.NotNull(c); + Assert.Same(c, resp.Content); + Assert.NotSame(resp.Content, new HttpResponseMessage().Content); + + Assert.Equal(0, c.Headers.ContentLength); + + Task t = c.ReadAsStreamAsync(); + Assert.Equal(TaskStatus.RanToCompletion, t.Status); + + Stream s = await t; + Assert.NotNull(s); + + Assert.Equal(-1, s.ReadByte()); + Assert.Equal(0, s.Read(new byte[1], 0, 1)); + Assert.Equal(0, await s.ReadAsync(new byte[1], 0, 1)); + Assert.Equal(0, await s.ReadAsync(new Memory(new byte[1]))); + + Assert.Throws(() => s.WriteByte(0)); + Assert.Throws(() => s.Write(new byte[1], 0, 1)); + await Assert.ThrowsAsync(() => s.WriteAsync(new byte[1], 0, 1)); + await Assert.ThrowsAsync(async () => await s.WriteAsync(new ReadOnlyMemory(new byte[1]))); + } + [Fact] public void ToString_DefaultAndNonDefaultInstance_DumpAllFields() { diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj index 6aa7ae56441b3a..d05f66c3ce992a 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj @@ -1,4 +1,4 @@ - + ../../src/Resources/Strings.resx $(DefineConstants);TargetsWindows @@ -8,285 +8,198 @@ $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-OSX - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\System\Net\Http\aspnetcore\NetEventSource.Common.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicAddressHelpers.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicApi.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicParameterHelpers.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicSecurityConfig.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\MsQuicSession.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\QuicExceptionHelpers.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\Internal\ResettableCompletionSource.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\MsQuicConnection.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\MsQuicImplementationProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\MsQuicListener.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\MsQuic\MsQuicStream.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\QuicImplementationProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\QuicListenerProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\QuicConnectionProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\QuicStreamProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\Mock\MockImplementationProvider.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\Mock\MockListener.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\Mock\MockConnection.cs - - - Common\System\Net\Http\aspnetcore\Quic\Implementations\Mock\MockStream.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\MsQuicStatusCodes.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\MsQuicStatusHelper.cs - - - Common\System\Net\Http\aspnetcore\Quic\NetEventSource.Quic.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicClientConnectionOptions.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicImplementationProviders.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicConnection.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicListener.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicListenerOptions.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicOperationAbortedException.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicStream.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicException.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicConnectionAbortedException.cs - - - Common\System\Net\Http\aspnetcore\Quic\QuicStreamAbortedException.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\Interop.MsQuic.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\MsQuicEnums.cs - - - Common\System\Net\Http\aspnetcore\Quic\Interop\MsQuicNativeMethods.cs - - - System\System\Threading\Tasks\TaskToApm.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.IsNtlmInstalled.cs - - - Common\System\Buffers\NativeMemoryManager.cs - - - Common\System\Diagnostics\Tracing\TestEventListener.cs - - - Common\System\Diagnostics\Tracing\ConsoleEventListener.cs - - - Common\System\IO\DelegateStream.cs - - - Common\System\Net\RemoteServerQuery.cs - - - Common\System\Net\Configuration.Certificates.cs - - - Common\System\Net\EventSourceTestLogging.cs - - - Common\System\Net\HttpsTestServer.cs - - - Common\System\Net\Capability.Security.cs - - - Common\System\Net\Capability.Security.Windows.cs - - - Common\System\Net\Capability.Security.Unix.cs - - - Common\System\Net\Configuration.cs - - - Common\System\Net\Configuration.Http.cs - - - Common\System\Net\Configuration.Security.cs - - - Common\System\Net\Configuration.Sockets.cs - - - Common\System\Net\TestWebProxies.cs - - - Common\System\Net\VerboseTestLogging.cs - - - Common\System\Net\Http\LoopbackProxyServer.cs - - - Common\System\Net\Http\LoopbackServer.cs - - - Common\System\Net\Http\LoopbackServer.AuthenticationHelpers.cs - - - Common\System\Net\Http\GenericLoopbackServer.cs - - - Common\System\Net\Http\HttpClientHandlerTestBase.cs - - - Common\System\Net\Http\TestHelper.cs - - - Common\System\Threading\TrackingSynchronizationContext.cs - - - Common\System\Threading\Tasks\GetStateMachineData.cs - - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - Common\System\Net\Http\ChannelBindingAwareContent.cs - - - Common\System\Net\Http\DribbleStream.cs - - - Common\System\Net\Http\CustomContent.cs - + + + - - Common\System\Net\Http\ByteAtATimeContent.cs - - - Common\System\Net\Http\HttpClientHandlerTest.cs - - - Common\System\Net\Http\HttpClientHandlerTest.Asynchrony.cs - - - Common\System\Net\Http\HttpClientHandlerTest.Authentication.cs - - - Common\System\Net\Http\HttpClientHandlerTest.AutoRedirect.cs - - - Common\System\Net\Http\HttpClientHandlerTest.Cancellation.cs - - - Common\System\Net\Http\HttpClientHandlerTest.ClientCertificates.cs - - - Common\System\Net\Http\HttpClientHandlerTest.Cookies.cs - - - Common\System\Net\Http\HttpClientHandlerTest.DefaultProxyCredentials.cs - + + + + + + + + + - - Common\System\Net\Http\HttpClientHandlerTest.MaxConnectionsPerServer.cs - - - Common\System\Net\Http\HttpClientHandlerTest.MaxResponseHeadersLength.cs - - - Common\System\Net\Http\HttpClientHandlerTest.Proxy.cs - + + + - - Common\System\Net\Http\HttpClientHandlerTest.ServerCertificates.cs - - - Common\System\Net\Http\HttpClientHandlerTest.SslProtocols.cs - + + - - Common\System\Net\Http\HttpClientEKUTest.cs - - - Common\System\Net\Http\HttpClient.SelectedSitesTest.cs - + + - - Common\System\Net\Http\HttpRetryProtocolTests.cs - - - Common\System\Net\Http\IdnaProtocolTests.cs - - - Common\System\Net\Http\HttpProtocolTests.cs - + + + @@ -294,98 +207,76 @@ - - Common\System\Net\Http\PostScenarioTest.cs - + - - Common\System\Net\Http\RepeatedFlushContent.cs - - - Common\System\Net\Http\ResponseStreamTest.cs - - - Common\System\Net\Http\SchSendAuxRecordHttpTest.cs - + + + - - Common\System\Net\Http\SyncBlockingContent.cs - - - Common\System\Net\Http\DefaultCredentialsTest.cs - + + - - Common\Interop\Windows\Interop.Libraries.cs - + - - Common\Interop\Linux\Interop.Libraries.cs - + - - Common\Interop\OSX\Interop.Libraries.cs - + - - Common\System\Net\Http\HttpClientHandlerTest.AcceptAllCerts.cs - - - Common\System\Net\Http\HttpClientHandlerTest.Decompression.cs - + + - - Common\System\Net\Http\Http2Frames.cs - - - Common\System\Net\Http\HPackEncoder.cs - - - Common\System\Net\Http\QPackTestDecoder.cs - - - Common\System\Net\Http\QPackTestEncoder.cs - - - Common\System\Net\Http\Http2LoopbackServer.cs - - - Common\System\Net\Http\Http2LoopbackConnection.cs - - - Common\System\Net\Http\Http3LoopbackServer.cs - - - Common\System\Net\Http\Http3LoopbackConnection.cs - - - Common\System\Net\Http\Http3LoopbackStream.cs - - - Common\System\Net\Http\HuffmanDecoder.cs - - - Common\System\Net\Http\HuffmanEncoder.cs - + + + + + + + + + + + diff --git a/src/libraries/System.Net.Http/tests/StressTests/HttpStress/ClientOperations.cs b/src/libraries/System.Net.Http/tests/StressTests/HttpStress/ClientOperations.cs index 01fb03fc8a78b0..8342fed20b6947 100644 --- a/src/libraries/System.Net.Http/tests/StressTests/HttpStress/ClientOperations.cs +++ b/src/libraries/System.Net.Http/tests/StressTests/HttpStress/ClientOperations.cs @@ -29,6 +29,8 @@ public sealed class RequestContext public RequestContext(Configuration config, HttpClient httpClient, Random random, CancellationToken globalToken, int taskNum) { + Debug.Assert(httpClient.BaseAddress != null); + _random = random; _client = httpClient; _globalToken = globalToken; @@ -47,7 +49,7 @@ public RequestContext(Configuration config, HttpClient httpClient, Random random public int MaxRequestHeaderCount => _config.MaxRequestHeaderCount; public int MaxRequestHeaderTotalSize => _config.MaxRequestHeaderTotalSize; public int MaxContentLength => _config.MaxContentLength; - public Uri BaseAddress => _client.BaseAddress; + public Uri BaseAddress => _client.BaseAddress!; // HttpClient.SendAsync() wrapper that wires randomized cancellation public async Task SendAsync(HttpRequestMessage request, HttpCompletionOption httpCompletion = HttpCompletionOption.ResponseContentRead, CancellationToken? token = null) @@ -222,19 +224,18 @@ public static (string name, Func operation)[] Operations = await res.Content.ReadAsStringAsync(); bool isValidChecksum = ValidateServerChecksum(res.Headers, expectedChecksum); - string GetFailureDetails() => isValidChecksum ? "server checksum matches client checksum" : "server checksum mismatch"; + string failureDetails = isValidChecksum ? "server checksum matches client checksum" : "server checksum mismatch"; // Validate that request headers are being echoed foreach (KeyValuePair> reqHeader in req.Headers) { - if (!res.Headers.TryGetValues(reqHeader.Key, out IEnumerable values)) + if (!res.Headers.TryGetValues(reqHeader.Key, out IEnumerable? values)) { - throw new Exception($"Expected response header name {reqHeader.Key} missing. {GetFailureDetails()}"); + throw new Exception($"Expected response header name {reqHeader.Key} missing. {failureDetails}"); } else if (!reqHeader.Value.SequenceEqual(values)) { - string FmtValues(IEnumerable values) => string.Join(", ", values.Select(x => $"\"{x}\"")); - throw new Exception($"Unexpected values for header {reqHeader.Key}. Expected {FmtValues(reqHeader.Value)} but got {FmtValues(values)}. {GetFailureDetails()}"); + throw new Exception($"Unexpected values for header {reqHeader.Key}. Expected {FmtValues(reqHeader.Value)} but got {FmtValues(values)}. {failureDetails}"); } } @@ -243,14 +244,13 @@ public static (string name, Func operation)[] Operations = { foreach (KeyValuePair> reqHeader in req.Headers) { - if (!res.TrailingHeaders.TryGetValues(reqHeader.Key + "-trailer", out IEnumerable values)) + if (!res.TrailingHeaders.TryGetValues(reqHeader.Key + "-trailer", out IEnumerable? values)) { - throw new Exception($"Expected trailing header name {reqHeader.Key}-trailer missing. {GetFailureDetails()}"); + throw new Exception($"Expected trailing header name {reqHeader.Key}-trailer missing. {failureDetails}"); } else if (!reqHeader.Value.SequenceEqual(values)) { - string FmtValues(IEnumerable values) => string.Join(", ", values.Select(x => $"\"{x}\"")); - throw new Exception($"Unexpected values for trailing header {reqHeader.Key}-trailer. Expected {FmtValues(reqHeader.Value)} but got {FmtValues(values)}. {GetFailureDetails()}"); + throw new Exception($"Unexpected values for trailing header {reqHeader.Key}-trailer. Expected {FmtValues(reqHeader.Value)} but got {FmtValues(values)}. {failureDetails}"); } } } @@ -260,6 +260,8 @@ public static (string name, Func operation)[] Operations = // Should not reach this block unless there's a bug in checksum validation logic. Do throw now throw new Exception("server checksum mismatch"); } + + static string FmtValues(IEnumerable values) => string.Join(", ", values.Select(x => $"\"{x}\"")); }), ("GET Parameters", @@ -573,7 +575,7 @@ private static (string, MultipartContent) GetMultipartContent(RequestContext cli private static bool ValidateServerChecksum(HttpResponseHeaders headers, ulong expectedChecksum, bool required = true) { - if (headers.TryGetValues("crc32", out IEnumerable values) && + if (headers.TryGetValues("crc32", out IEnumerable? values) && uint.TryParse(values.First(), out uint serverChecksum)) { return serverChecksum == expectedChecksum; @@ -595,7 +597,7 @@ private sealed class StringDuplexContent : HttpContent public StringDuplexContent(string value) => _data = Encoding.UTF8.GetBytes(value); - protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) => + protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => stream.WriteAsync(_data, 0, _data.Length); protected override bool TryComputeLength(out long length) @@ -612,7 +614,7 @@ private sealed class ByteAtATimeNoLengthContent : HttpContent public ByteAtATimeNoLengthContent(byte[] buffer) => _buffer = buffer; - protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context) + protected override async Task SerializeToStreamAsync(Stream stream, TransportContext? context) { for (int i = 0; i < _buffer.Length; i++) { diff --git a/src/libraries/System.Net.Http/tests/StressTests/HttpStress/HttpStress.csproj b/src/libraries/System.Net.Http/tests/StressTests/HttpStress/HttpStress.csproj index 551e07230ae3b0..0d8818fb1d0827 100644 --- a/src/libraries/System.Net.Http/tests/StressTests/HttpStress/HttpStress.csproj +++ b/src/libraries/System.Net.Http/tests/StressTests/HttpStress/HttpStress.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressClient.cs b/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressClient.cs index e930d4a48a9365..37c86da44bd545 100644 --- a/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressClient.cs +++ b/src/libraries/System.Net.Http/tests/StressTests/HttpStress/StressClient.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.Concurrent; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net.Http; using System.Net.Security; @@ -452,7 +453,7 @@ public void PrintFailureTypes() private class StructuralEqualityComparer : IEqualityComparer where T : IStructuralEquatable { - public bool Equals(T left, T right) => left.Equals(right, StructuralComparisons.StructuralEqualityComparer); + public bool Equals([AllowNull] T left, [AllowNull] T right) => left != null && left.Equals(right, StructuralComparisons.StructuralEqualityComparer); public int GetHashCode(T value) => value.GetHashCode(StructuralComparisons.StructuralEqualityComparer); } } diff --git a/src/libraries/System.Net.Http/tests/UnitTests/Headers/KnownHeadersTest.cs b/src/libraries/System.Net.Http/tests/UnitTests/Headers/KnownHeadersTest.cs new file mode 100644 index 00000000000000..3d65a6c05a35d3 --- /dev/null +++ b/src/libraries/System.Net.Http/tests/UnitTests/Headers/KnownHeadersTest.cs @@ -0,0 +1,250 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Linq; +using System.Net.Http.Headers; +using Xunit; + +namespace System.Net.Http.Tests +{ + public class KnownHeadersTest + { + [Theory] + [InlineData(":status")] + [InlineData("Accept")] + [InlineData("Accept-Charset")] + [InlineData("Accept-Encoding")] + [InlineData("Accept-Language")] + [InlineData("Accept-Patch")] + [InlineData("Accept-Ranges")] + [InlineData("Access-Control-Allow-Credentials")] + [InlineData("Access-Control-Allow-Headers")] + [InlineData("Access-Control-Allow-Methods")] + [InlineData("Access-Control-Allow-Origin")] + [InlineData("Access-Control-Expose-Headers")] + [InlineData("Access-Control-Max-Age")] + [InlineData("Age")] + [InlineData("Allow")] + [InlineData("Alt-Svc")] + [InlineData("Alt-Used")] + [InlineData("Authorization")] + [InlineData("Cache-Control")] + [InlineData("Connection")] + [InlineData("Content-Disposition")] + [InlineData("Content-Encoding")] + [InlineData("Content-Language")] + [InlineData("Content-Length")] + [InlineData("Content-Location")] + [InlineData("Content-MD5")] + [InlineData("Content-Range")] + [InlineData("Content-Security-Policy")] + [InlineData("Content-Type")] + [InlineData("Cookie")] + [InlineData("Cookie2")] + [InlineData("Date")] + [InlineData("ETag")] + [InlineData("Expect")] + [InlineData("Expect-CT")] + [InlineData("Expires")] + [InlineData("From")] + [InlineData("grpc-encoding")] + [InlineData("grpc-message")] + [InlineData("grpc-status")] + [InlineData("Host")] + [InlineData("If-Match")] + [InlineData("If-Modified-Since")] + [InlineData("If-None-Match")] + [InlineData("If-Range")] + [InlineData("If-Unmodified-Since")] + [InlineData("Keep-Alive")] + [InlineData("Last-Modified")] + [InlineData("Link")] + [InlineData("Location")] + [InlineData("Max-Forwards")] + [InlineData("Origin")] + [InlineData("P3P")] + [InlineData("Pragma")] + [InlineData("Proxy-Authenticate")] + [InlineData("Proxy-Authorization")] + [InlineData("Proxy-Connection")] + [InlineData("Proxy-Support")] + [InlineData("Public-Key-Pins")] + [InlineData("Range")] + [InlineData("Referer")] + [InlineData("Referrer-Policy")] + [InlineData("Refresh")] + [InlineData("Retry-After")] + [InlineData("Sec-WebSocket-Accept")] + [InlineData("Sec-WebSocket-Extensions")] + [InlineData("Sec-WebSocket-Key")] + [InlineData("Sec-WebSocket-Protocol")] + [InlineData("Sec-WebSocket-Version")] + [InlineData("Server")] + [InlineData("Server-Timing")] + [InlineData("Set-Cookie")] + [InlineData("Set-Cookie2")] + [InlineData("Strict-Transport-Security")] + [InlineData("TE")] + [InlineData("Trailer")] + [InlineData("Transfer-Encoding")] + [InlineData("TSV")] + [InlineData("Upgrade")] + [InlineData("Upgrade-Insecure-Requests")] + [InlineData("User-Agent")] + [InlineData("Vary")] + [InlineData("Via")] + [InlineData("Warning")] + [InlineData("WWW-Authenticate")] + [InlineData("X-AspNet-Version")] + [InlineData("X-Cache")] + [InlineData("X-Content-Duration")] + [InlineData("X-Content-Type-Options")] + [InlineData("X-Frame-Options")] + [InlineData("X-MSEdge-Ref")] + [InlineData("X-Powered-By")] + [InlineData("X-Request-ID")] + [InlineData("X-UA-Compatible")] + [InlineData("X-XSS-Protection")] + public void TryGetKnownHeader_Known_Found(string name) + { + foreach (string casedName in new[] { name, name.ToUpperInvariant(), name.ToLowerInvariant() }) + { + Validate(casedName, KnownHeaders.TryGetKnownHeader(casedName)); + Validate(casedName, KnownHeaders.TryGetKnownHeader(casedName.Select(c => (byte)c).ToArray())); + } + + static void Validate(string name, KnownHeader h) + { + Assert.NotNull(h); + Assert.Same(h, KnownHeaders.TryGetKnownHeader(name)); + + Assert.Same(h, h.Descriptor.KnownHeader); + Assert.Equal(name, h.Name, StringComparer.OrdinalIgnoreCase); + Assert.Equal(name, h.Descriptor.Name, StringComparer.OrdinalIgnoreCase); + } + } + + [Theory] + [InlineData("")] + [InlineData(" \t ")] + [InlineData("Something")] + [InlineData("X-Unknown")] + public void TryGetKnownHeader_Unknown_NotFound(string name) + { + foreach (string casedName in new[] { name, name.ToUpperInvariant(), name.ToLowerInvariant() }) + { + Assert.Null(KnownHeaders.TryGetKnownHeader(casedName)); + Assert.Null(KnownHeaders.TryGetKnownHeader(casedName.Select(c => (byte)c).ToArray())); + } + } + + [Theory] + [InlineData("Access-Control-Allow-Credentials", "true")] + [InlineData("Access-Control-Allow-Headers", "*")] + [InlineData("Access-Control-Allow-Methods", "*")] + [InlineData("Access-Control-Allow-Origin", "*")] + [InlineData("Access-Control-Allow-Origin", "null")] + [InlineData("Access-Control-Expose-Headers", "*")] + [InlineData("Cache-Control", "must-revalidate")] + [InlineData("Cache-Control", "no-cache")] + [InlineData("Cache-Control", "no-store")] + [InlineData("Cache-Control", "no-transform")] + [InlineData("Cache-Control", "private")] + [InlineData("Cache-Control", "proxy-revalidate")] + [InlineData("Cache-Control", "public")] + [InlineData("Connection", "close")] + [InlineData("Content-Disposition", "attachment")] + [InlineData("Content-Disposition", "inline")] + [InlineData("Content-Encoding", "gzip")] + [InlineData("Content-Encoding", "deflate")] + [InlineData("Content-Encoding", "br")] + [InlineData("Content-Encoding", "compress")] + [InlineData("Content-Encoding", "identity")] + [InlineData("Content-Type", "text/xml")] + [InlineData("Content-Type", "text/css")] + [InlineData("Content-Type", "text/csv")] + [InlineData("Content-Type", "image/gif")] + [InlineData("Content-Type", "image/png")] + [InlineData("Content-Type", "text/html")] + [InlineData("Content-Type", "text/plain")] + [InlineData("Content-Type", "image/jpeg")] + [InlineData("Content-Type", "application/pdf")] + [InlineData("Content-Type", "application/xml")] + [InlineData("Content-Type", "application/zip")] + [InlineData("Content-Type", "application/grpc")] + [InlineData("Content-Type", "application/json")] + [InlineData("Content-Type", "multipart/form-data")] + [InlineData("Content-Type", "application/javascript")] + [InlineData("Content-Type", "application/octet-stream")] + [InlineData("Content-Type", "text/html; charset=utf-8")] + [InlineData("Content-Type", "text/plain; charset=utf-8")] + [InlineData("Content-Type", "application/json; charset=utf-8")] + [InlineData("Content-Type", "application/x-www-form-urlencoded")] + [InlineData("Expect", "100-continue")] + [InlineData("grpc-encoding", "identity")] + [InlineData("grpc-encoding", "gzip")] + [InlineData("grpc-encoding", "deflate")] + [InlineData("grpc-status", "0")] + [InlineData("Pragma", "no-cache")] + [InlineData("Referrer-Policy", "strict-origin-when-cross-origin")] + [InlineData("Referrer-Policy", "origin-when-cross-origin")] + [InlineData("Referrer-Policy", "strict-origin")] + [InlineData("Referrer-Policy", "origin")] + [InlineData("Referrer-Policy", "same-origin")] + [InlineData("Referrer-Policy", "no-referrer-when-downgrade")] + [InlineData("Referrer-Policy", "no-referrer")] + [InlineData("Referrer-Policy", "unsafe-url")] + [InlineData("TE", "trailers")] + [InlineData("TE", "compress")] + [InlineData("TE", "deflate")] + [InlineData("TE", "gzip")] + [InlineData("Transfer-Encoding", "chunked")] + [InlineData("Transfer-Encoding", "compress")] + [InlineData("Transfer-Encoding", "deflate")] + [InlineData("Transfer-Encoding", "gzip")] + [InlineData("Transfer-Encoding", "identity")] + [InlineData("Upgrade-Insecure-Requests", "1")] + [InlineData("Vary", "*")] + [InlineData("X-Content-Type-Options", "nosniff")] + [InlineData("X-Frame-Options", "DENY")] + [InlineData("X-Frame-Options", "SAMEORIGIN")] + [InlineData("X-XSS-Protection", "0")] + [InlineData("X-XSS-Protection", "1")] + [InlineData("X-XSS-Protection", "1; mode=block")] + public void GetKnownHeaderValue_Known_Found(string name, string value) + { + foreach (string casedValue in new[] { value, value.ToUpperInvariant(), value.ToLowerInvariant() }) + { + Validate(KnownHeaders.TryGetKnownHeader(name), casedValue); + } + + static void Validate(KnownHeader knownHeader, string value) + { + Assert.NotNull(knownHeader); + + string v1 = knownHeader.Descriptor.GetHeaderValue(value.Select(c => (byte)c).ToArray()); + Assert.NotNull(v1); + Assert.Equal(value, v1, StringComparer.OrdinalIgnoreCase); + + string v2 = knownHeader.Descriptor.GetHeaderValue(value.Select(c => (byte)c).ToArray()); + Assert.Same(v1, v2); + } + } + + [Theory] + [InlineData("Content-Type", "application/jsot")] + [InlineData("Content-Type", "application/jsons")] + public void GetKnownHeaderValue_Unknown_NotFound(string name, string value) + { + KnownHeader knownHeader = KnownHeaders.TryGetKnownHeader(name); + Assert.NotNull(knownHeader); + + string v1 = knownHeader.Descriptor.GetHeaderValue(value.Select(c => (byte)c).ToArray()); + string v2 = knownHeader.Descriptor.GetHeaderValue(value.Select(c => (byte)c).ToArray()); + Assert.Equal(value, v1); + Assert.Equal(value, v2); + Assert.NotSame(v1, v2); + } + } +} diff --git a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj index 33d33d6ad9e8f6..b4c31ba80fd7b2 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj @@ -12,336 +12,232 @@ - - Common\System\HexConverter.cs - - - ProductionCode\Common\System\NotImplemented.cs - - - ProductionCode\Common\System\CharArrayHelpers.cs - - - ProductionCode\Common\System\StringExtensions.cs - - - ProductionCode\Common\System\Text\StringBuilderCache.cs - - - ProductionCode\Common\System\IO\StreamHelpers.CopyValidation.cs - - - Common\System\Net\ArrayBuffer.cs - - - ProductionCode\Common\System\Net\InternalException.cs - - - ProductionCode\Common\System\Net\HttpDateParser.cs - - - ProductionCode\Common\System\Net\HttpKnownHeaderNames.cs - - - ProductionCode\Common\System\Net\HttpKnownHeaderNames.TryGetHeaderName.cs - - - ProductionCode\Common\System\Net\HttpStatusDescription.cs - - - ProductionCode\Common\System\Net\Logging\NetEventSource.Common.cs - - - ProductionCode\Common\System\Net\SecurityProtocol.cs - - - ProductionCode\Common\System\Net\UriScheme.cs - - - Common\System\Text\SimpleRegex.cs - - - Common\System\ShouldNotBeInvokedException.cs - - - Common\System\Net\Http\HPackEncoder.cs - - - Common\System\Net\Http\HuffmanEncoder.cs - - - ProductionCode\Common\src\System\Net\Mail\MailAddress.cs - - - ProductionCode\Common\src\System\Net\Mail\DomainLiteralReader.cs - - - ProductionCode\Common\src\System\Net\Mail\DotAtomReader.cs - - - ProductionCode\Common\src\System\Net\Mail\MailAddressParser.cs - - - ProductionCode\Common\src\System\Net\Mail\MailBnfHelper.cs - - - ProductionCode\Common\src\System\Net\Mail\QuotedPairReader.cs - - - ProductionCode\Common\src\System\Net\Mail\QuotedStringFormatReader.cs - - - ProductionCode\Common\src\System\Net\Mail\WhitespaceReader.cs - - - ProductionCode\Common\System\Threading\Tasks\TaskToApm.cs - - - ProductionCode\System\Net\Http\SocketsHttpHandler\AuthenticationHelper.Digest.cs - - - ProductionCode\System\Net\Http\ByteArrayContent.cs - - - ProductionCode\System\Net\Http\ClientCertificateOption.cs - - - ProductionCode\System\Net\Http\DelegatingHandler.cs - - - ProductionCode\System\IO\DelegatingStream.cs - - - ProductionCode\System\Net\Http\ByteArrayHelpers.cs - - - ProductionCode\System\Net\Http\FormUrlEncodedContent.cs - - - ProductionCode\System\Net\Http\Headers\AltSvcHeaderParser.cs - - - ProductionCode\System\Net\Http\Headers\AltSvcHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\AuthenticationHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\BaseHeaderParser.cs - - - ProductionCode\System\Net\Http\Headers\ByteArrayHeaderParser.cs - - - ProductionCode\System\Net\Http\Headers\CacheControlHeaderParser.cs - - - ProductionCode\System\Net\Http\Headers\CacheControlHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\ContentDispositionHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\ContentRangeHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\DateHeaderParser.cs - - - ProductionCode\System\Net\Http\Headers\EntityTagHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\GenericHeaderParser.cs - - - ProductionCode\System\Net\Http\Headers\HeaderDescriptor.cs - - - ProductionCode\System\Net\Http\Headers\HeaderUtilities.cs - - - ProductionCode\System\Net\Http\Headers\HttpContentHeaders.cs - - - ProductionCode\System\Net\Http\Headers\HttpGeneralHeaders.cs - - - ProductionCode\System\Net\Http\Headers\HttpHeaderParser.cs - - - ProductionCode\System\Net\Http\Headers\HttpHeaders.cs - - - ProductionCode\System\Net\Http\Headers\HttpHeaderType.cs - - - ProductionCode\System\Net\Http\Headers\HttpHeaderValueCollection.cs - - - ProductionCode\System\Net\Http\Headers\HttpRequestHeaders.cs - - - ProductionCode\System\Net\Http\Headers\HttpResponseHeaders.cs - - - ProductionCode\System\Net\Http\Headers\Int32NumberHeaderParser.cs - - - ProductionCode\System\Net\Http\Headers\Int64NumberHeaderParser.cs - - - ProductionCode\System\Net\Http\Headers\KnownHeaders.cs - - - ProductionCode\System\Net\Http\Headers\KnownHeader.cs - - - ProductionCode\System\Net\Http\Headers\MediaTypeHeaderParser.cs - - - ProductionCode\System\Net\Http\Headers\MediaTypeHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\MediaTypeWithQualityHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\NameValueHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\.cs - - - ProductionCode\System\Net\Http\Headers\ObjectCollection.cs - - - ProductionCode\System\Net\Http\Headers\ProductHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\ProductInfoHeaderParser.cs - - - ProductionCode\System\Net\Http\Headers\ProductInfoHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\RangeConditionHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\RangeHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\RangeItemHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\RetryConditionHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\StringWithQualityHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\TimeSpanHeaderParser.cs - - - ProductionCode\System\Net\Http\Headers\TransferCodingHeaderParser.cs - - - ProductionCode\System\Net\Http\Headers\TransferCodingHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\TransferCodingWithQualityHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\UriHeaderParser.cs - - - ProductionCode\System\Net\Http\Headers\ViaHeaderValue.cs - - - ProductionCode\System\Net\Http\Headers\WarningHeaderValue.cs - - - ProductionCode\System\Net\Http\HttpClient.cs - - - ProductionCode\System\Net\Http\HttpCompletionOption.cs - - - ProductionCode\System\Net\Http\HttpContent.cs - - - ProductionCode\System\Net\Http\HttpMessageHandler.cs - - - ProductionCode\System\Net\Http\HttpMessageInvoker.cs - - - ProductionCode\System\Net\Http\HttpMethod.cs - - - ProductionCode\System\Net\Http\HttpParseResult.cs - - - ProductionCode\System\Net\Http\HttpRequestException.cs - - - ProductionCode\System\Net\Http\RequestRetryType.cs - - - ProductionCode\System\Net\Http\HttpRequestMessage.cs - - - ProductionCode\System\Net\Http\HttpResponseMessage.cs - - - ProductionCode\System\Net\Http\HttpRuleParser.cs - - - ProductionCode\System\Net\Http\HttpUtilities.cs - - - ProductionCode\System\Net\Http\MessageProcessingHandler.cs - - - ProductionCode\System\Net\Http\MultipartContent.cs - - - ProductionCode\System\Net\Http\MultipartFormDataContent.cs - - - ProductionCode\System\Net\Http\NetEventSource.Http.cs - - - ProductionCode\System\Net\Http\StreamContent.cs - - - ProductionCode\System\Net\Http\StreamToStreamCopy.cs - - - ProductionCode\System\Net\Http\StringContent.cs - - - ProductionCode\System\Net\Http\SocketsHttpHandler\HttpEnvironmentProxy.cs - - - ProductionCode\System\Net\Http\SocketsHttpHandler\HttpEnvironmentProxy.Unix.cs - - - ProductionCode\System\Net\Http\SocketsHttpHandler\HttpEnvironmentProxy.Windows.cs - - - ProductionCode\System\Net\Http\SocketsHttpHandler\SystemProxyInfo.cs - - - ProductionCode\System\Net\Http\SocketsHttpHandler\SystemProxyInfo.OSX.cs - - - ProductionCode\System\Net\Http\SocketsHttpHandler\SystemProxyInfo.Unix.cs - - - ProductionCode\System\Net\Http\SocketsHttpHandler\SystemProxyInfo.Windows.cs - - - ProductionCode\System\Net\Http\HttpHandlerDefaults.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -377,6 +273,7 @@ + @@ -399,18 +296,14 @@ - - HPack\DynamicTableTest.cs - - - HPack\HPackDecoderTest.cs - - - HPack\HPackIntegerTest.cs - - - HPack\HuffmanDecodingTests.cs - + + + + @@ -419,122 +312,83 @@ - - ProductionCode\System\Net\Http\HttpNoProxy.cs - - - ProductionCode\System\Net\Http\HttpWindowsProxy.cs - - - ProductionCode\System\Net\Http\IMultiWebProxy.cs - - - ProductionCode\System\Net\Http\MultiProxy.cs - - - ProductionCode\System\Net\Http\FailedProxyCache.cs - - - ProductionCode\System\Net\Http\WinHttpException.cs - - - ProductionCode\System\Net\Http\WinHttpTraceHelper.cs - - - ProductionCode\Common\Interop\Windows\Interop.Libraries.cs - - - ProductionCode\Common\Interop\Windows\Crypt32\Interop.CertEnumCertificatesInStore.cs - - - ProductionCode\Common\Interop\Windows\Crypt32\Interop.certificates_types.cs - - - ProductionCode\Common\Interop\Windows\Interop.HRESULT_FROM_WIN32.cs - - - ProductionCode\Common\Interop\Windows\WinHttp\Interop.SafeWinHttpHandle.cs - - - ProductionCode\Common\System\Runtime\ExceptionServices\ExceptionStackTrace.cs - - - ProductionCode\Common\Interop\Windows\WinHttp\Interop.winhttp_types.cs - - - Common\System\Net\Http\WinInetProxyHelper.cs - - - Common\System\Net\Http\aspnetcore\IHttpHeadersHandler.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\DynamicTable.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HeaderField.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HPackDecoder.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HPackDecodingException.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HPackEncoder.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HPackEncodingException.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\Huffman.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\HuffmanDecodingException.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\IntegerDecoder.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\IntegerEncoder.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\H2StaticTable.cs - - - Common\System\Net\Http\aspnetcore\Http2\Hpack\StatusCodes.cs - - - Common\System\Net\Http\aspnetcore\Http3\QPack\H3StaticTable.cs - - - Common\System\Net\Http\aspnetcore\Http3\QPack\HeaderField.cs - - - Common\System\Net\Http\aspnetcore\Http3\QPack\QPackEncoder.cs - - - Common\System\Net\Http\aspnetcore\Http3\QPack\QPackEncodingException.cs - - - Common\System\Text\ValueStringBuilder.cs - - - WinHttpHandler\UnitTests\FakeInterop.cs - - - WinHttpHandler\UnitTests\FakeRegistry.cs - - - WinHttpHandler\UnitTests\FakeSafeWinHttpHandle.cs - - - WinHttpHandler\UnitTests\TestControl.cs - - - WinHttpHandler\UnitTests\APICallHistory.cs - - - WinHttpHandler\UnitTests\TestServer.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Net.HttpListener/src/System.Net.HttpListener.csproj b/src/libraries/System.Net.HttpListener/src/System.Net.HttpListener.csproj index d88ccb13f96788..b27d2d05646c7f 100644 --- a/src/libraries/System.Net.HttpListener/src/System.Net.HttpListener.csproj +++ b/src/libraries/System.Net.HttpListener/src/System.Net.HttpListener.csproj @@ -56,49 +56,35 @@ - - Common\System\StringExtensions.cs - - - Common\System\Net\Logging\NetEventSource.Common.cs - - - Common\System\Net\CookieComparer.cs - - - Common\System\Net\CookieFields.cs - - - Common\System\Net\CookieParser.cs - - - Common\System\Net\CaseInsensitiveAscii.cs - - - Common\System\Net\ExceptionCheck.cs - - - Common\System\Net\HttpStatusDescription.cs - - - Common\System\Net\HttpKnownHeaderNames.cs - - - Common\System\Net\LazyAsyncResult.cs - - - Common\System\Net\UriScheme.cs - - - Common\System\Net\WebHeaderEncoding.cs - - - Common\System\Net\WebSockets\WebSocketValidate.cs - + + + + + + + + + + + + + - - Common\System\Runtime\CompilerServices\PreserveDependencyAttribute.cs - + @@ -114,12 +100,10 @@ - - Common\System\Net\DebugSafeHandle.cs - - - Common\System\Net\InternalException.cs - + + @@ -130,191 +114,128 @@ - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs - - - Common\Interop\Windows\Interop.BOOL.cs - - - Common\Interop\Windows\WebSocket\Interop.Structs.cs - - - Common\Interop\Windows\WebSocket\Interop.WebSocketAbortHandle.cs - - - Common\Interop\Windows\WebSocket\Interop.WebSocketBeginClientHandshake.cs - - - Common\Interop\Windows\WebSocket\Interop.WebSocketBeginServerHandshake.cs - - - Common\Interop\Windows\WebSocket\Interop.WebSocketCompleteAction.cs - - - Common\Interop\Windows\WebSocket\Interop.WebSocketCreateClientHandle.cs - - - Common\Interop\Windows\WebSocket\Interop.WebSocketCreateServerHandle.cs - - - Common\Interop\Windows\WebSocket\Interop.WebSocketDeleteHandle.cs - - - Common\Interop\Windows\WebSocket\Interop.WebSocketEndServerHandshake.cs - - - Common\Interop\Windows\WebSocket\Interop.WebSocketGetAction.cs - - - Common\Interop\Windows\WebSocket\Interop.WebSocketReceive.cs - - - Common\Interop\Windows\WebSocket\Interop.WebSocketSend.cs - - - Common\Interop\Windows\HttpApi\Interop.ErrorCodes.cs - - - Common\Interop\Windows\HttpApi\Interop.HttpApi.cs - - - Common\Interop\Windows\Kernel32\Interop.SetFileCompletionNotificationModes.cs - - - Common\Interop\Windows\Kernel32\Interop.CancelIoEx.cs - - - Common\Interop\Windows\Kernel32\Interop.LoadLibraryEx_IntPtr.cs - - - Common\Interop\Windows\Kernel32\Interop.SECURITY_ATTRIBUTES.cs - - - Common\Microsoft\Win32\SafeHandles\SafeLocalAllocHandle.cs - + + + + + + + + + + + + + + + + + + + + + + - - Common\System\Net\DebugCriticalHandleMinusOneIsInvalid.cs - - - Common\System\Net\DebugCriticalHandleZeroOrMinusOneIsInvalid.cs - - - Common\System\Collections\Generic\BidirectionalDictionary.cs - - - Common\System\NotImplemented.cs - - - Common\System\Net\Logging\DebugThreadTracking.cs - - - Common\System\Net\ContextFlagsPal.cs - - - Common\System\Net\NegotiationInfoClass.cs - - - Common\System\Net\NTAuthentication.Common.cs - - - Common\System\Net\SecurityStatusPal.cs - - - Common\System\Net\Security\SecurityBuffer.Windows.cs - - - Common\System\Net\Security\SecurityBufferType.Windows.cs - - - Common\System\Net\Security\SSPIHandleCache.cs - - - Common\System\Net\Security\NetEventSource.Security.cs - + + + + + + + + + + + + - - Common\System\Net\Security\SecurityContextTokenHandle.cs - - - Common\System\Net\SecurityStatusAdapterPal.Windows.cs - - - Common\System\Net\ContextFlagsAdapterPal.Windows.cs - - - Common\System\Net\Security\NegotiateStreamPal.Windows.cs - - - Common\System\Net\Security\NetEventSource.Security.Windows.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates_types.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_Bindings.cs - - - Common\Interop\Windows\SChannel\Interop.SECURITY_STATUS.cs - - - Common\Interop\Windows\Kernel32\Interop.CloseHandle.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_StreamSizes.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_NegotiationInfoW.cs - - - Common\Interop\Windows\SspiCli\NegotiationInfoClass.cs - - - Common\Interop\Windows\SChannel\SecPkgContext_ConnectionInfo.cs - - - Common\Interop\Windows\SChannel\SecPkgContext_CipherInfo.cs - - - Common\Interop\Windows\SspiCli\SSPISecureChannelType.cs - - - Common\Interop\Windows\SspiCli\ISSPIInterface.cs - - - Common\Interop\Windows\SspiCli\SSPIAuthType.cs - - - Common\Interop\Windows\SspiCli\SecurityPackageInfoClass.cs - - - Common\Interop\Windows\SspiCli\SecurityPackageInfo.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_Sizes.cs - - - Common\Interop\Windows\SspiCli\SafeDeleteContext.cs - - - Common\Interop\Windows\SspiCli\GlobalSSPI.cs - - - Common\Interop\Windows\SspiCli\Interop.SSPI.cs - - - Common\Interop\Windows\SspiCli\SecuritySafeHandles.cs - - - Common\Interop\Windows\SspiCli\SSPIWrapper.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -335,11 +256,10 @@ - - Common\System\Threading\Tasks\TaskToApm.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Net.HttpListener/src/System/Net/HttpListenerResponse.cs b/src/libraries/System.Net.HttpListener/src/System/Net/HttpListenerResponse.cs index 41e3f78d340c82..97c8339c3b95f6 100644 --- a/src/libraries/System.Net.HttpListener/src/System/Net/HttpListenerResponse.cs +++ b/src/libraries/System.Net.HttpListener/src/System/Net/HttpListenerResponse.cs @@ -188,7 +188,7 @@ public string StatusDescription char c = (char)(0x000000ff & (uint)value[i]); if ((c <= 31 && c != (byte)'\t') || c == 127) { - throw new ArgumentException(SR.net_WebHeaderInvalidControlChars, "name"); + throw new ArgumentException(SR.net_WebHeaderInvalidControlChars, nameof(value)); } } diff --git a/src/libraries/System.Net.HttpListener/tests/HttpListenerResponseTests.Headers.cs b/src/libraries/System.Net.HttpListener/tests/HttpListenerResponseTests.Headers.cs index 112c841b8594a6..f52b79f355844b 100644 --- a/src/libraries/System.Net.HttpListener/tests/HttpListenerResponseTests.Headers.cs +++ b/src/libraries/System.Net.HttpListener/tests/HttpListenerResponseTests.Headers.cs @@ -436,7 +436,7 @@ public async Task StatusDescription_SetInvalid_ThrowsArgumentException(string st { using (HttpListenerResponse response = await GetResponse()) { - AssertExtensions.Throws("name", () => response.StatusDescription = statusDescription); + AssertExtensions.Throws("value", () => response.StatusDescription = statusDescription); Assert.Equal("OK", response.StatusDescription); } } diff --git a/src/libraries/System.Net.HttpListener/tests/System.Net.HttpListener.Tests.csproj b/src/libraries/System.Net.HttpListener/tests/System.Net.HttpListener.Tests.csproj index fb2211a5258098..b9a13777450542 100644 --- a/src/libraries/System.Net.HttpListener/tests/System.Net.HttpListener.Tests.csproj +++ b/src/libraries/System.Net.HttpListener/tests/System.Net.HttpListener.Tests.csproj @@ -23,11 +23,10 @@ - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Net.Mail/src/System.Net.Mail.csproj b/src/libraries/System.Net.Mail/src/System.Net.Mail.csproj index babcb1dc6f1150..9567cbde450486 100644 --- a/src/libraries/System.Net.Mail/src/System.Net.Mail.csproj +++ b/src/libraries/System.Net.Mail/src/System.Net.Mail.csproj @@ -63,231 +63,156 @@ - - Common\System\Net\TlsStream.cs - - - Common\System\Net\InternalException.cs - - - Common\System\Net\LazyAsyncResult.cs - - - Common\System\Net\ContextAwareResult.cs - - - Common\System\Net\Mail\MailBnfHelper.cs - - - Common\System\Net\Logging\NetEventSource.Common.cs - - - Common\System\Net\Mail\DotAtomReader.cs - - - Common\System\Net\Mail\MailAddressParser.cs - - - Common\System\Net\Mail\QuotedStringFormatReader.cs - - - Common\System\Net\Mail\WhitespaceReader.cs - - - Common\System\Net\Mail\QuotedPairReader.cs - - - Common\System\Net\Mail\DomainLiteralReader.cs - - - Common\System\Net\SecurityProtocol.cs - - - Common\System\StringExtensions.cs - - - Common\System\Net\DebugCriticalHandleMinusOneIsInvalid.cs - - - Common\System\Net\DebugCriticalHandleZeroOrMinusOneIsInvalid.cs - - - Common\System\Net\DebugSafeHandle.cs - - - Common\System\Net\ExceptionCheck.cs - - - Common\System\Collections\Generic\BidirectionalDictionary.cs - - - Common\System\NotImplemented.cs - - - Common\System\Net\Logging\DebugThreadTracking.cs - - - Common\System\Net\ContextFlagsPal.cs - - - Common\System\Net\NegotiationInfoClass.cs - - - Common\System\Net\NTAuthentication.Common.cs - - - Common\System\Net\SecurityStatusPal.cs - - - Common\System\Net\Security\SSPIHandleCache.cs - - - Common\System\Net\Security\NetEventSource.Security.cs - - - Common\System\HexConverter.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - Common\System\Net\ContextAwareResult.Unix.cs - - - Common\System\Net\ContextFlagsAdapterPal.Unix.cs - - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.GssBuffer.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.GssApiException.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.IsNtlmInstalled.cs - - - Common\System\Net\Security\Unix\SafeDeleteNegoContext.cs - - - Common\System\Net\Security\Unix\SafeFreeCredentials.cs - - - Common\System\Net\Security\Unix\SafeDeleteContext.cs - - - Common\System\Net\Security\NegotiateStreamPal.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\GssSafeHandles.cs - - - Common\System\Net\Security\Unix\SafeFreeNegoCredentials.cs - - - Common\System\Net\Security\Unix\SecChannelBindings.cs - + + + + + + + + + + + + + + - - Common\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs - - - Common\System\Net\Security\SecurityBuffer.Windows.cs - - - Common\System\Net\Security\SecurityBufferType.Windows.cs - - - Common\System\Net\Security\SecurityContextTokenHandle.cs - - - Common\System\Net\ContextAwareResult.Windows.cs - - - Common\System\Net\SecurityStatusAdapterPal.Windows.cs - - - Common\System\Net\ContextFlagsAdapterPal.Windows.cs - - - Common\System\Net\Security\NegotiateStreamPal.Windows.cs - - - Common\System\Net\Security\NetEventSource.Security.Windows.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates_types.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_Bindings.cs - - - Common\Interop\Windows\SChannel\Interop.SECURITY_STATUS.cs - - - Common\Interop\Windows\Kernel32\Interop.CloseHandle.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_StreamSizes.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_NegotiationInfoW.cs - - - Common\Interop\Windows\SspiCli\NegotiationInfoClass.cs - - - Common\Interop\Windows\SChannel\SecPkgContext_ConnectionInfo.cs - - - Common\Interop\Windows\SChannel\SecPkgContext_CipherInfo.cs - - - Common\Interop\Windows\SspiCli\SSPISecureChannelType.cs - - - Common\Interop\Windows\SspiCli\ISSPIInterface.cs - - - Common\Interop\Windows\SspiCli\SSPIAuthType.cs - - - Common\Interop\Windows\SspiCli\SecurityPackageInfoClass.cs - - - Common\Interop\Windows\SspiCli\SecurityPackageInfo.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_Sizes.cs - - - Common\Interop\Windows\SspiCli\SafeDeleteContext.cs - - - Common\Interop\Windows\SspiCli\GlobalSSPI.cs - - - Common\Interop\Windows\SspiCli\Interop.SSPI.cs - - - Common\Interop\Windows\SspiCli\SecuritySafeHandles.cs - - - Common\Interop\Windows\SspiCli\SSPIWrapper.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -315,4 +240,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Net.Mail/src/System/Net/BufferedReadStream.cs b/src/libraries/System.Net.Mail/src/System/Net/BufferedReadStream.cs index 95f851e240dc69..c9f5c51e5c3469 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/BufferedReadStream.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/BufferedReadStream.cs @@ -97,7 +97,7 @@ public override Task ReadAsync(byte[] buffer, int offset, int count, Cancel private async Task ReadMoreAsync(int bytesAlreadyRead, byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - int returnValue = await base.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + int returnValue = await base.ReadAsync(buffer.AsMemory(offset, count), cancellationToken).ConfigureAwait(false); return bytesAlreadyRead + returnValue; } diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/Attachment.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/Attachment.cs index 44e48f7fc9e3eb..91ffd955517069 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/Attachment.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/Attachment.cs @@ -75,7 +75,7 @@ internal void SetContentFromFile(string fileName, ContentType? contentType) throw new ArgumentNullException(nameof(fileName)); } - if (fileName == string.Empty) + if (fileName.Length == 0) { throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(fileName)), nameof(fileName)); } @@ -91,7 +91,7 @@ internal void SetContentFromFile(string fileName, string? mediaType) throw new ArgumentNullException(nameof(fileName)); } - if (fileName == string.Empty) + if (fileName.Length == 0) { throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(fileName)), nameof(fileName)); } @@ -154,7 +154,7 @@ internal void SetContentFromString(string content, Encoding? encoding, string? m _part.Stream.Close(); } - if (mediaType == null || mediaType == string.Empty) + if (string.IsNullOrEmpty(mediaType)) { mediaType = MediaTypeNames.Text.Plain; } @@ -340,7 +340,7 @@ public Attachment(string fileName, string? mediaType) : public Attachment(string fileName, ContentType contentType) : base(fileName, contentType) { - if (contentType.Name == null || contentType.Name == string.Empty) + if (string.IsNullOrEmpty(contentType.Name)) { Name = Path.GetFileName(fileName); } diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs index 9519b3f80d87c6..76d97dd95f4e54 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddress.cs @@ -124,7 +124,7 @@ private static bool TryParse(string address, string? displayName, Encoding? disp { throw new ArgumentNullException(nameof(address)); } - if (address == string.Empty) + if (address.Length == 0) { throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(address)), nameof(address)); } diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddressCollection.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddressCollection.cs index 5b1b687e30179d..bc63f116fcea93 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddressCollection.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailAddressCollection.cs @@ -23,7 +23,7 @@ public void Add(string addresses) { throw new ArgumentNullException(nameof(addresses)); } - if (addresses == string.Empty) + if (addresses.Length == 0) { throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(addresses)), nameof(addresses)); } diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailMessage.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailMessage.cs index 83eddcd9f755f9..4bb5e9e8663d2c 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailMessage.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailMessage.cs @@ -44,10 +44,10 @@ public MailMessage(string from, string to) if (to == null) throw new ArgumentNullException(nameof(to)); - if (from == string.Empty) + if (from.Length == 0) throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(from)), nameof(from)); - if (to == string.Empty) + if (to.Length == 0) throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(to)), nameof(to)); _message = new Message(from, to); diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailPriority.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailPriority.cs index 6c912e3239c258..ee4618cdd83c3b 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/MailPriority.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/MailPriority.cs @@ -51,10 +51,10 @@ internal Message(string from, string to) : this() if (to == null) throw new ArgumentNullException(nameof(to)); - if (from == string.Empty) + if (from.Length == 0) throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(from)), nameof(from)); - if (to == string.Empty) + if (to.Length == 0) throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(to)), nameof(to)); _from = new MailAddress(from); diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.cs index 834b5ba0b80818..0def5723b3064a 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.cs @@ -187,7 +187,7 @@ public string? Host throw new ArgumentNullException(nameof(value)); } - if (value == string.Empty) + if (value.Length == 0) { throw new ArgumentException(SR.net_emptystringset, nameof(value)); } diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mime/ContentDisposition.cs b/src/libraries/System.Net.Mail/src/System/Net/Mime/ContentDisposition.cs index be078ae7edcdfa..891d17ef06882d 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mime/ContentDisposition.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mime/ContentDisposition.cs @@ -83,7 +83,7 @@ public string DispositionType { throw new ArgumentNullException(nameof(value)); } - if (value == string.Empty) + if (value.Length == 0) { throw new ArgumentException(SR.net_emptystringset, nameof(value)); } diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mime/ContentType.cs b/src/libraries/System.Net.Mail/src/System/Net/Mime/ContentType.cs index d3a183fb3b31fc..7394cfdd20c5e1 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mime/ContentType.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mime/ContentType.cs @@ -50,7 +50,7 @@ public ContentType(string contentType) { throw new ArgumentNullException(nameof(contentType)); } - if (contentType == string.Empty) + if (contentType.Length == 0) { throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(contentType)), nameof(contentType)); } @@ -65,7 +65,7 @@ public string? Boundary get { return Parameters["boundary"]; } set { - if (value == null || value == string.Empty) + if (string.IsNullOrEmpty(value)) { Parameters.Remove("boundary"); } @@ -81,7 +81,7 @@ public string? CharSet get { return Parameters["charset"]; } set { - if (value == null || value == string.Empty) + if (string.IsNullOrEmpty(value)) { Parameters.Remove("charset"); } @@ -105,7 +105,7 @@ public string MediaType throw new ArgumentNullException(nameof(value)); } - if (value == string.Empty) + if (value.Length == 0) { throw new ArgumentException(SR.net_emptystringset, nameof(value)); } diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mime/HeaderCollection.cs b/src/libraries/System.Net.Mail/src/System/Net/Mime/HeaderCollection.cs index 6c4b2827175020..1b468f725477fc 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mime/HeaderCollection.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mime/HeaderCollection.cs @@ -22,16 +22,16 @@ internal HeaderCollection() : base(StringComparer.OrdinalIgnoreCase) { } -#pragma warning disable CS8610 // Nullability of reference types in type of parameter doesn't match overridden member. +#pragma warning disable CS8765 // Nullability of parameter 'name' doesn't match overridden member public override void Remove(string name) -#pragma warning restore CS8610 +#pragma warning restore CS8765 { if (name == null) { throw new ArgumentNullException(nameof(name)); } - if (name == string.Empty) + if (name.Length == 0) { throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(name)), nameof(name)); } @@ -51,16 +51,16 @@ public override void Remove(string name) } -#pragma warning disable CS8610 // Nullability of reference types in type of parameter doesn't match overridden member. +#pragma warning disable CS8765 // Nullability of parameter 'name' doesn't match overridden member public override string? Get(string name) -#pragma warning restore CS8610 +#pragma warning restore CS8765 { if (name == null) { throw new ArgumentNullException(nameof(name)); } - if (name == string.Empty) + if (name.Length == 0) { throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(name)), nameof(name)); } @@ -78,16 +78,16 @@ public override void Remove(string name) return base.Get(name); } -#pragma warning disable CS8610 // Nullability of reference types in type of parameter doesn't match overridden member. +#pragma warning disable CS8765 // Nullability of parameter 'name' doesn't match overridden member public override string[]? GetValues(string name) -#pragma warning restore CS8610 +#pragma warning restore CS8765 { if (name == null) { throw new ArgumentNullException(nameof(name)); } - if (name == string.Empty) + if (name.Length == 0) { throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(name)), nameof(name)); } @@ -124,9 +124,9 @@ internal void InternalAdd(string name, string value) } } -#pragma warning disable CS8610 // Nullability of reference types in type of parameter doesn't match overridden member. +#pragma warning disable CS8765 // Nullability of parameters 'name' and 'value' don't match overridden member public override void Set(string name, string value) -#pragma warning restore CS8610 +#pragma warning restore CS8765 { if (name == null) { @@ -138,12 +138,12 @@ public override void Set(string name, string value) throw new ArgumentNullException(nameof(value)); } - if (name == string.Empty) + if (name.Length == 0) { throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(name)), nameof(name)); } - if (value == string.Empty) + if (value.Length == 0) { throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(value)), nameof(value)); } @@ -175,9 +175,9 @@ public override void Set(string name, string value) } -#pragma warning disable CS8610 // Nullability of reference types in type of parameter doesn't match overridden member. +#pragma warning disable CS8765 // Nullability of parameters 'name' and 'value' don't match overridden member public override void Add(string name, string value) -#pragma warning restore CS8610 +#pragma warning restore CS8765 { if (name == null) { @@ -187,11 +187,11 @@ public override void Add(string name, string value) { throw new ArgumentNullException(nameof(value)); } - if (name == string.Empty) + if (name.Length == 0) { throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(name)), nameof(name)); } - if (value == string.Empty) + if (value.Length == 0) { throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(value)), nameof(value)); } diff --git a/src/libraries/System.Net.Mail/tests/Functional/AlternateViewCollectionTest.cs b/src/libraries/System.Net.Mail/tests/Functional/AlternateViewCollectionTest.cs index 6540a168b5b920..ed20522d401c0e 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/AlternateViewCollectionTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/AlternateViewCollectionTest.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // See the LICENSE file in the project root for more information. // -// AlternateViewCollectionTest.cs - NUnit Test Cases for System.Net.MailAddress.AlternateViewCollection +// AlternateViewCollectionTest.cs - Unit Test Cases for System.Net.MailAddress.AlternateViewCollection // // Authors: // John Luke (john.luke@gmail.com) diff --git a/src/libraries/System.Net.Mail/tests/Functional/AlternateViewTest.cs b/src/libraries/System.Net.Mail/tests/Functional/AlternateViewTest.cs index 302dd3e156b82a..59320cbb1d54e4 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/AlternateViewTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/AlternateViewTest.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // See the LICENSE file in the project root for more information. // -// AlternateViewTest.cs - NUnit Test Cases for System.Net.MailAddress.AlternateView +// AlternateViewTest.cs - Unit Test Cases for System.Net.MailAddress.AlternateView // // Authors: // John Luke (john.luke@gmail.com) diff --git a/src/libraries/System.Net.Mail/tests/Functional/AttachmentCollectionTest.cs b/src/libraries/System.Net.Mail/tests/Functional/AttachmentCollectionTest.cs index 2237a9838d30cb..68e4c1ef78f1c9 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/AttachmentCollectionTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/AttachmentCollectionTest.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // See the LICENSE file in the project root for more information. // -// AttachmentCollectionTest.cs - NUnit Test Cases for System.Net.MailAddress.AttachmentCollection +// AttachmentCollectionTest.cs - Unit Test Cases for System.Net.MailAddress.AttachmentCollection // // Authors: // John Luke (john.luke@gmail.com) diff --git a/src/libraries/System.Net.Mail/tests/Functional/AttachmentTest.cs b/src/libraries/System.Net.Mail/tests/Functional/AttachmentTest.cs index a3264ea162a2d3..9a0b9f41e966a8 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/AttachmentTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/AttachmentTest.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // See the LICENSE file in the project root for more information. // -// AttachmentTest.cs - NUnit Test Cases for System.Net.MailAddress.Attachment +// AttachmentTest.cs - Unit Test Cases for System.Net.MailAddress.Attachment // // Authors: // John Luke (john.luke@gmail.com) diff --git a/src/libraries/System.Net.Mail/tests/Functional/LinkedResourceCollectionTest.cs b/src/libraries/System.Net.Mail/tests/Functional/LinkedResourceCollectionTest.cs index 8bed530fbbc9dc..68ef77002980eb 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/LinkedResourceCollectionTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/LinkedResourceCollectionTest.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // See the LICENSE file in the project root for more information. // -// LinkedResourceCollectionTest.cs - NUnit Test Cases for System.Net.MailAddress.LinkedResourceCollection +// LinkedResourceCollectionTest.cs - Unit Test Cases for System.Net.MailAddress.LinkedResourceCollection // // Authors: // John Luke (john.luke@gmail.com) diff --git a/src/libraries/System.Net.Mail/tests/Functional/LinkedResourceTest.cs b/src/libraries/System.Net.Mail/tests/Functional/LinkedResourceTest.cs index c64a92ed08efdb..00b6a62f64d0bf 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/LinkedResourceTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/LinkedResourceTest.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // See the LICENSE file in the project root for more information. // -// LinkedResourceTest.cs - NUnit Test Cases for System.Net.MailAddress.LinkedResource +// LinkedResourceTest.cs - Unit Test Cases for System.Net.MailAddress.LinkedResource // // Authors: // John Luke (john.luke@gmail.com) diff --git a/src/libraries/System.Net.Mail/tests/Functional/MailAddressCollectionTest.cs b/src/libraries/System.Net.Mail/tests/Functional/MailAddressCollectionTest.cs index 8d1a2156b7ac45..5aa41b4a26b730 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/MailAddressCollectionTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/MailAddressCollectionTest.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // See the LICENSE file in the project root for more information. // -// MailAddressCollectionTest.cs - NUnit Test Cases for System.Net.MailAddress.MailAddressCollection +// MailAddressCollectionTest.cs - Unit Test Cases for System.Net.MailAddress.MailAddressCollection // // Authors: // John Luke (john.luke@gmail.com) diff --git a/src/libraries/System.Net.Mail/tests/Functional/MailMessageTest.cs b/src/libraries/System.Net.Mail/tests/Functional/MailMessageTest.cs index f8be941b6c7501..bdd41aa31cb607 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/MailMessageTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/MailMessageTest.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // See the LICENSE file in the project root for more information. // -// MailMessageTest.cs - NUnit Test Cases for System.Net.MailAddress.MailMessage +// MailMessageTest.cs - Unit Test Cases for System.Net.MailAddress.MailMessage // // Authors: // John Luke (john.luke@gmail.com) diff --git a/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs b/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs index 7e1c86d2fadef7..ddcb811b8b5c65 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // See the LICENSE file in the project root for more information. // -// SmtpClientTest.cs - NUnit Test Cases for System.Net.Mail.SmtpClient +// SmtpClientTest.cs - Unit Test Cases for System.Net.Mail.SmtpClient // // Authors: // John Luke (john.luke@gmail.com) diff --git a/src/libraries/System.Net.Mail/tests/Functional/SmtpExceptionTest.cs b/src/libraries/System.Net.Mail/tests/Functional/SmtpExceptionTest.cs index 2846746446e71e..443a32ebd4d665 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/SmtpExceptionTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/SmtpExceptionTest.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // See the LICENSE file in the project root for more information. // -// SmtpExceptionTest.cs - NUnit Test Cases for System.Net.Mail.SmtpException +// SmtpExceptionTest.cs - Unit Test Cases for System.Net.Mail.SmtpException // // Authors: // Gert Driesen (drieseng@users.sourceforge.net) diff --git a/src/libraries/System.Net.Mail/tests/Functional/System.Net.Mail.Functional.Tests.csproj b/src/libraries/System.Net.Mail/tests/Functional/System.Net.Mail.Functional.Tests.csproj index a11dcc181d3e57..b68e44c598cf69 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/System.Net.Mail.Functional.Tests.csproj +++ b/src/libraries/System.Net.Mail/tests/Functional/System.Net.Mail.Functional.Tests.csproj @@ -22,15 +22,12 @@ - - Common\System\Diagnostics\Tracing\TestEventListener.cs - - - Common\System\IO\TempFile.cs - - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - + + + diff --git a/src/libraries/System.Net.Mail/tests/Unit/System.Net.Mail.Unit.Tests.csproj b/src/libraries/System.Net.Mail/tests/Unit/System.Net.Mail.Unit.Tests.csproj index 6750ab32a4ec4e..d4da9df33459e6 100644 --- a/src/libraries/System.Net.Mail/tests/Unit/System.Net.Mail.Unit.Tests.csproj +++ b/src/libraries/System.Net.Mail/tests/Unit/System.Net.Mail.Unit.Tests.csproj @@ -27,342 +27,230 @@ - - ProductionCode\Base64Stream.cs - - - ProductionCode\SmtpException.cs - - - ProductionCode\SmtpStatusCode.cs - - - ProductionCode\DelegatedStream.cs - - - ProductionCode\MailAddress.cs - - - ProductionCode\NetEventSource.Mail.cs - - - ProductionCode\SmtpConnection.Auth.cs - - - ProductionCode\ISmtpAuthenticationModule.cs - - - ProductionCode\SmtpLoginAuthenticationModule.cs - - - ProductionCode\SmtpNegotiateAuthenticationModule.cs - - - ProductionCode\SmtpNtlmAuthenticationModule.cs - - - ProductionCode\MailAddressCollection.cs - - - ProductionCode\MailPriority.cs - - - ProductionCode\MimePart.cs - - - ProductionCode\Base64WriteStateInfo.cs - - - ProductionCode\QuotedPrintableStream.cs - - - ProductionCode\CloseableStream.cs - - - ProductionCode\EightBitStream.cs - - - ProductionCode\EncodedStreamFactory.cs - - - ProductionCode\IEncodableStream.cs - - - ProductionCode\QEncodedStream.cs - - - ProductionCode\WriteStateInfoBase.cs - - - ProductionCode\BaseWriter.cs - - - ProductionCode\TransferEncoding.cs - - - ProductionCode\ContentDisposition.cs - - - ProductionCode\ContentType.cs - - - ProductionCode\DispositionTypeNames.cs - - - ProductionCode\HeaderCollection.cs - - - ProductionCode\MediaTypeNames.cs - - - ProductionCode\MimeBasePart.cs - - - ProductionCode\SmtpDateTime.cs - - - ProductionCode\MultiAsyncResult.cs - - - ProductionCode\TrackingStringDictionary.cs - - - ProductionCode\TrackingValidationObjectDictionary.cs - - - ProductionCode\MailHeaderID.cs - - - ProductionCode\MailHeaderInfo.cs - - - ProductionCode\BufferBuilder.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - Common\System\Net\TlsStream.cs - - - Common\System\Net\InternalException.cs - - - Common\System\Net\LazyAsyncResult.cs - - - Common\System\Net\ContextAwareResult.cs - - - Common\System\Net\Mail\MailBnfHelper.cs - - - Common\System\Net\Logging\NetEventSource.Common.cs - - - Common\System\Net\Mail\DotAtomReader.cs - - - Common\System\Net\Mail\MailAddressParser.cs - - - Common\System\Net\Mail\QuotedStringFormatReader.cs - - - Common\System\Net\Mail\WhitespaceReader.cs - - - Common\System\Net\Mail\QuotedPairReader.cs - - - Common\System\Net\Mail\DomainLiteralReader.cs - - - Common\System\Net\SecurityProtocol.cs - - - Common\System\StringExtensions.cs - - - Common\System\Net\DebugCriticalHandleMinusOneIsInvalid.cs - - - Common\System\Net\DebugCriticalHandleZeroOrMinusOneIsInvalid.cs - - - Common\System\Net\DebugSafeHandle.cs - - - Common\System\Net\ExceptionCheck.cs - - - Common\System\Collections\Generic\BidirectionalDictionary.cs - - - Common\System\NotImplemented.cs - - - Common\System\Net\Logging\DebugThreadTracking.cs - - - Common\System\Net\ContextFlagsPal.cs - - - Common\System\Net\NegotiationInfoClass.cs - - - Common\System\Net\NTAuthentication.Common.cs - - - Common\System\Net\SecurityStatusPal.cs - - - Common\System\Net\Security\SSPIHandleCache.cs - - - Common\System\Net\Security\NetEventSource.Security.cs - - - Common\System\HexConverter.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - Common\System\Net\ContextAwareResult.Unix.cs - - - Common\System\Net\ContextFlagsAdapterPal.Unix.cs - - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.GssBuffer.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.GssApiException.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.IsNtlmInstalled.cs - - - Common\System\Net\Security\Unix\SafeDeleteNegoContext.cs - - - Common\System\Net\Security\Unix\SafeFreeCredentials.cs - - - Common\System\Net\Security\Unix\SafeDeleteContext.cs - - - Common\System\Net\Security\NegotiateStreamPal.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\GssSafeHandles.cs - - - Common\System\Net\Security\Unix\SafeFreeNegoCredentials.cs - - - Common\System\Net\Security\Unix\SecChannelBindings.cs - + + + + + + + + + + + + + + - - Common\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs - - - Common\System\Net\Security\SecurityBuffer.Windows.cs - - - Common\System\Net\Security\SecurityBufferType.Windows.cs - - - Common\System\Net\Security\SecurityContextTokenHandle.cs - - - Common\System\Net\ContextAwareResult.Windows.cs - - - Common\System\Net\SecurityStatusAdapterPal.Windows.cs - - - Common\System\Net\ContextFlagsAdapterPal.Windows.cs - - - Common\System\Net\Security\NegotiateStreamPal.Windows.cs - - - Common\System\Net\Security\NetEventSource.Security.Windows.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates_types.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_Bindings.cs - - - Common\Interop\Windows\SChannel\Interop.SECURITY_STATUS.cs - - - Common\Interop\Windows\Kernel32\Interop.CloseHandle.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_StreamSizes.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_NegotiationInfoW.cs - - - Common\Interop\Windows\SspiCli\NegotiationInfoClass.cs - - - Common\Interop\Windows\SChannel\SecPkgContext_ConnectionInfo.cs - - - Common\Interop\Windows\SChannel\SecPkgContext_CipherInfo.cs - - - Common\Interop\Windows\SspiCli\SSPISecureChannelType.cs - - - Common\Interop\Windows\SspiCli\ISSPIInterface.cs - - - Common\Interop\Windows\SspiCli\SSPIAuthType.cs - - - Common\Interop\Windows\SspiCli\SecurityPackageInfoClass.cs - - - Common\Interop\Windows\SspiCli\SecurityPackageInfo.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_Sizes.cs - - - Common\Interop\Windows\SspiCli\SafeDeleteContext.cs - - - Common\Interop\Windows\SspiCli\GlobalSSPI.cs - - - Common\Interop\Windows\SspiCli\Interop.SSPI.cs - - - Common\Interop\Windows\SspiCli\SecuritySafeHandles.cs - - - Common\Interop\Windows\SspiCli\SSPIWrapper.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/src/libraries/System.Net.NameResolution/src/System.Net.NameResolution.csproj b/src/libraries/System.Net.NameResolution/src/System.Net.NameResolution.csproj index e4107a9b1a3290..498f4e8fce267a 100644 --- a/src/libraries/System.Net.NameResolution/src/System.Net.NameResolution.csproj +++ b/src/libraries/System.Net.NameResolution/src/System.Net.NameResolution.csproj @@ -10,140 +10,97 @@ - - Common\System\Net\Logging\DebugThreadTracking.cs - - - Common\System\Net\Logging\NetEventSource.Common.cs - - - Common\System\Net\InternalException.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - + + + - - Common\System\Net\Sockets\ProtocolType.cs - - - Common\System\Net\Sockets\SocketType.cs - - - Common\System\Net\IPAddressParserStatics.cs - - - Common\System\Net\IPEndPointStatics.cs - - - Common\System\Net\ByteOrder.cs - + + + + + - - Common\System\Net\DebugSafeHandle.cs - + - - Common\System\Net\Internals\IPAddressExtensions.cs - - - Common\System\Net\Internals\SocketExceptionFactory.Windows.cs - - - Common\System\Net\SocketProtocolSupportPal.Windows - - - Common\System\Net\SocketAddressPal.Windows - + + + + - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\WinSock\AddressInfoHints.cs - - - Common\Interop\Windows\WinSock\hostent.cs - - - Common\Interop\Windows\WinSock\Interop.closesocket.cs - - - Common\Interop\Windows\WinSock\Interop.gethostname.cs - - - Common\Interop\Windows\WinSock\Interop.GetNameInfoW.cs - - - Common\Interop\Windows\WinSock\Interop.GetAddrInfoW.cs - - - Common\Interop\Windows\WinSock\Interop.WSAStartup.cs - - - Common\Interop\Windows\WinSock\Interop.WSASocketW.cs - - - Common\Interop\Windows\WinSock\Interop.SocketConstructorFlags.cs - - - Common\System\Net\Sockets\ProtocolFamily.cs - - - Common\Interop\Windows\WinSock\Interop.GetAddrInfoExW.cs - + + + + + + + + + + + + - - Common\System\Net\InteropIPAddressExtensions.Unix.cs - - - Common\System\Net\Internals\SocketAddressPal.Unix.cs - - - Common\System\Net\SocketProtocolSupportPal.Unix - - - Common\System\Net\Internals\SocketExceptionFactory.cs - - - Common\System\Net\Internals\SocketExceptionFactory.Unix.cs - - - Common\System\Net\Internals\Interop.CheckedAccess.cs - - - Common\Interop\CoreLib\Unix\Interop.Errors.cs - - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\System.Native\Interop.Close.cs - - - Common\Interop\Unix\System.Native\Interop.GetHostName.cs - - - Common\Interop\Unix\System.Native\Interop.GetNameInfo.cs - - - Common\Interop\Unix\System.Native\Interop.HostEntries.cs - - - Common\Interop\Unix\System.Native\Interop.IPAddress.cs - - - Common\Interop\Unix\System.Native\Interop.Socket.cs - - - Common\Interop\Unix\System.Native\Interop.SocketAddress.cs - + + + + + + + + + + + + + + + @@ -161,4 +118,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostEntryTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostEntryTest.cs index 7677b365d5b718..679d336c0211f1 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostEntryTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostEntryTest.cs @@ -186,7 +186,6 @@ public async Task DnsGetHostEntry_BadName_ThrowsArgumentOutOfRangeException(stri await Assert.ThrowsAnyAsync(() => Task.Factory.FromAsync(Dns.BeginGetHostEntry, Dns.EndGetHostEntry, hostNameOrAddress, null)); } - [ActiveIssue("https://github.com/dotnet/runtime/issues/34317")] [Theory] [InlineData(0)] [InlineData(1)] diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/System.Net.NameResolution.Functional.Tests.csproj b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/System.Net.NameResolution.Functional.Tests.csproj index 48b39fe6179402..eb8576ed2e55f6 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/System.Net.NameResolution.Functional.Tests.csproj +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/System.Net.NameResolution.Functional.Tests.csproj @@ -12,17 +12,13 @@ - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - - - Common\System\Net\Configuration.cs - - - Common\System\Net\Configuration.Sockets.cs - - - Common\System\Diagnostics\Tracing\TestEventListener.cs - + + + + \ No newline at end of file diff --git a/src/libraries/System.Net.NameResolution/tests/PalTests/Fakes/DebugThreadTracking.cs b/src/libraries/System.Net.NameResolution/tests/PalTests/Fakes/DebugThreadTracking.cs deleted file mode 100644 index ebe478f65fbdf0..00000000000000 --- a/src/libraries/System.Net.NameResolution/tests/PalTests/Fakes/DebugThreadTracking.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace System.Net -{ - public static class DebugThreadTracking - { - internal static void SetThreadSource(ThreadKinds source) - { - } - } - - [Flags] - internal enum ThreadKinds - { - Unknown = 0x0000, - - // Mutually exclusive. - User = 0x0001, // Thread has entered via an API. - System = 0x0002, // Thread has entered via a system callback (e.g. completion port) or is our own thread. - - // Mutually exclusive. - Sync = 0x0004, // Thread should block. - Async = 0x0008, // Thread should not block. - - // Mutually exclusive, not always known for a user thread. Never changes. - Timer = 0x0010, // Thread is the timer thread. (Can't call user code.) - CompletionPort = 0x0020, // Thread is a ThreadPool completion-port thread. - Worker = 0x0040, // Thread is a ThreadPool worker thread. - Finalization = 0x0080, // Thread is the finalization thread. - Other = 0x0100, // Unknown source. - - OwnerMask = User | System, - SyncMask = Sync | Async, - SourceMask = Timer | CompletionPort | Worker | Finalization | Other, - - // Useful "macros" - SafeSources = SourceMask & ~(Timer | Finalization), // Methods that "unsafe" sources can call must be explicitly marked. - ThreadPool = CompletionPort | Worker, // Like Thread.CurrentThread.IsThreadPoolThread - } -} diff --git a/src/libraries/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj b/src/libraries/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj index 7fcacc540d25db..70e8ac2a4c1a53 100644 --- a/src/libraries/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj +++ b/src/libraries/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj @@ -10,145 +10,101 @@ - - ProductionCode\System\Net\IPHostEntry.cs - + - - - Common\System\Net\Logging\NetEventSource.cs - - - Common\System\Net\Sockets\ProtocolType.cs - - - Common\System\Net\Sockets\SocketType.cs - - - Common\System\Net\IPEndPointStatics.cs - - - Common\System\Net\IPAddressParserStatics.cs - - - Common\System\Net\Configuration.cs - - - Common\System\Net\Configuration.Http.cs - - - Common\System\Net\ByteOrder.cs - + + + + + + + + - - ProductionCode\System\Net\NameResolutionPal.Windows.cs - - - ProductionCode\System\Net\NameResolutionPal.Win32.cs - - - Common\System\Net\InternalException.cs - - - System\Net\SocketProtocolSupportPal.Windows - - - Common\System\Net\SocketAddressPal.Windows - + + + + + - - Common\System\Net\DebugSafeHandle.cs - + - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\WinSock\AddressInfoHints.cs - - - Common\Interop\Windows\WinSock\hostent.cs - - - Common\Interop\Windows\WinSock\Interop.closesocket.cs - - - Common\Interop\Windows\WinSock\Interop.gethostname.cs - - - Common\Interop\Windows\WinSock\Interop.GetNameInfoW.cs - - - Common\Interop\Windows\WinSock\Interop.GetAddrInfoW.cs - - - Common\Interop\Windows\WinSock\Interop.WSAStartup.cs - - - Common\Interop\Windows\WinSock\Interop.WSASocketW.cs - - - Common\Interop\Windows\WinSock\Interop.SocketConstructorFlags.cs - - - Common\System\Net\Sockets\ProtocolFamily.cs - - - Common\Interop\Windows\WinSock\Interop.GetAddrInfoExW.cs - + + + + + + + + + + + + - - Common\System\Net\Internals\SocketAddressPal.Unix.cs - - - Common\System\Net\Internals\Interop.CheckedAccess.cs - - - Common\System\Net\InteropIPAddressExtensions.Unix.cs - - - ProductionCode\Common\System\Net\Internals\SocketExceptionFactory.cs - - - ProductionCode\Common\System\Net\Internals\SocketExceptionFactory.Unix.cs - - - ProductionCode\System\Net\NameResolutionPal.Unix.cs - - - System\Net\SocketProtocolSupportPal.Unix.cs - - - Common\Interop\CoreLib\Unix\Interop.Errors.cs - - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\System.Native\Interop.Close.cs - - - Common\Interop\Unix\System.Native\Interop.GetHostName.cs - - - Common\Interop\Unix\System.Native\Interop.GetNameInfo.cs - - - Common\Interop\Unix\System.Native\Interop.HostEntry.cs - - - Common\Interop\Unix\System.Native\Interop.IPAddress.cs - - - Common\Interop\Unix\System.Native\Interop.Socket.cs - - - Common\Interop\Unix\System.Native\Interop.SocketAddress.cs - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/libraries/System.Net.NameResolution/tests/UnitTests/System.Net.NameResolution.Unit.Tests.csproj b/src/libraries/System.Net.NameResolution/tests/UnitTests/System.Net.NameResolution.Unit.Tests.csproj index ff5ea142ae7ac1..fa51396ca607c2 100644 --- a/src/libraries/System.Net.NameResolution/tests/UnitTests/System.Net.NameResolution.Unit.Tests.csproj +++ b/src/libraries/System.Net.NameResolution/tests/UnitTests/System.Net.NameResolution.Unit.Tests.csproj @@ -12,12 +12,10 @@ - - ProductionCode\System\Net\IPHostEntry.cs - - - ProductionCode\System\Net\Dns.cs - + + @@ -32,17 +30,13 @@ - - ProductionCode\Common\System\Net\Internals\SocketExceptionFactory.cs - - - Common\System\Net\Logging\NetEventSource.Common.cs - - - Common\System\Net\InternalException.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - + + + + \ No newline at end of file diff --git a/src/libraries/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj b/src/libraries/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj index 1dafbcc8a66948..1b1b6bf5a74e1d 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj +++ b/src/libraries/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj @@ -44,31 +44,26 @@ - - Common\System\NotImplemented.cs - - - Common\System\Net\NetworkInformation\HostInformation.cs - - - Common\System\Net\NetworkInformation\NetworkInformationException.cs - - - Common\System\HexConverter.cs - + + + + + - - Common\System\Net\Logging\NetEventSource.Common.cs - + - - Common\Interop\Windows\IpHlpApi\Interop.FIXED_INFO.cs - - - Common\Interop\Windows\IpHlpApi\Interop.IP_ADDR_STRING.cs - + + @@ -93,55 +88,39 @@ - - Common\System\Net\ContextAwareResult.cs - - - Common\System\Net\ContextAwareResult.Windows.cs - - - Common\System\Net\LazyAsyncResult.cs - - - Common\System\Net\ByteOrder.cs - - - Common\System\Net\IPAddressParserStatics.cs - - - Common\System\Net\SocketAddress.cs - - - Common\System\Net\SocketAddressPal.Windows.cs - - - Common\System\Net\NetworkInformation\StartIPOptions.cs - - - Common\System\Net\NetworkInformation\HostInformationPal.Windows.cs - + + + + + + + + + - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\IpHlpApi\Interop.ErrorCodes.cs - - - Common\Interop\Windows\IpHlpApi\Interop.GetNetworkParams.cs - - - Common\Interop\Windows\IpHlpApi\Interop.NetworkInformation.cs - - - Common\Interop\Windows\WinSock\Interop.WinsockBSD.cs - - - Common\Interop\Windows\WinSock\Interop.WSAEventSelect.cs - - - Common\Interop\Windows\WinSock\Interop.WSAIoctl.cs - + + + + + + + @@ -158,33 +137,22 @@ - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\System.Native\Interop.EnumerateInterfaceAddresses.cs - - - System\Net\NetworkInformation\HostInformationPal.Unix.cs - - - Common\Interop\Unix\System.Native\Interop.GetDomainName.cs - - - Common\Interop\Unix\System.Native\Interop.GetHostName.cs - - - Common\Interop\Unix\System.Native\Interop.MapTcpState.cs - - - Common\Interop\CoreLib\Unix\Interop.Errors.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - - - Common\System\IO\RowConfigReader.cs - + + + + + + + + @@ -209,12 +177,10 @@ - - Common\System\IO\StringParser.cs - - - Common\Interop\Linux\Interop.LinuxNetDeviceFlags.cs - + + @@ -233,42 +199,33 @@ - - Common\Interop\BSD\System.Native\Interop.ProtocolStatistics.cs - - - Common\Interop\BSD\System.Native\Interop.TcpConnectionInfo.cs - + + - - Common\Interop\OSX\Interop.CoreFoundation.cs - - - Common\Interop\OSX\Interop.Libraries.cs - - - Common\Interop\OSX\Interop.RunLoop.cs - - - Common\Interop\OSX\Interop.SystemConfiguration.cs - - - Common\Microsoft\Win32\SafeHandles\SafeCreateHandle.OSX.cs - + + + + + - - Common\Interop\FreeBSD\Interop.Libraries.cs - + - - Common\Interop\Unix\System.Native\Interop.NetworkChange.cs - + diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemIPGlobalProperties.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemIPGlobalProperties.cs index f792c6d1be3284..39220cab5c2042 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemIPGlobalProperties.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemIPGlobalProperties.cs @@ -2,17 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Win32.SafeHandles; - using System.Collections.Generic; using System.Net.Sockets; using System.Runtime.InteropServices; -using System.Threading; using System.Threading.Tasks; namespace System.Net.NetworkInformation { - internal class SystemIPGlobalProperties : IPGlobalProperties + internal sealed class SystemIPGlobalProperties : IPGlobalProperties { internal SystemIPGlobalProperties() { @@ -106,7 +103,7 @@ public override IPEndPoint[] GetActiveTcpListeners() /// /// Gets the active TCP connections. Uses the native GetTcpTable API. - private List GetAllTcpConnections() + private unsafe List GetAllTcpConnections() { uint size = 0; uint result = 0; @@ -128,21 +125,20 @@ private List GetAllTcpConnections() if (result == Interop.IpHlpApi.ERROR_SUCCESS) { + var span = new ReadOnlySpan((byte*)buffer, (int)size); + // The table info just gives us the number of rows. - Interop.IpHlpApi.MibTcpTable tcpTableInfo = Marshal.PtrToStructure(buffer); + ref readonly Interop.IpHlpApi.MibTcpTable tcpTableInfo = ref MemoryMarshal.AsRef(span); if (tcpTableInfo.numberOfEntries > 0) { // Skip over the tableinfo to get the inline rows. - IntPtr newPtr = (IntPtr)((long)buffer + Marshal.SizeOf(tcpTableInfo.numberOfEntries)); + span = span.Slice(sizeof(Interop.IpHlpApi.MibTcpTable)); for (int i = 0; i < tcpTableInfo.numberOfEntries; i++) { - Interop.IpHlpApi.MibTcpRow tcpRow = Marshal.PtrToStructure(newPtr); - tcpConnections.Add(new SystemTcpConnectionInformation(tcpRow)); - - // Increment the pointer to the next row. - newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcpRow)); + tcpConnections.Add(new SystemTcpConnectionInformation(in MemoryMarshal.AsRef(span))); + span = span.Slice(sizeof(Interop.IpHlpApi.MibTcpRow)); } } } @@ -179,21 +175,22 @@ private List GetAllTcpConnections() Interop.IpHlpApi.TcpTableClass.TcpTableOwnerPidAll, 0); if (result == Interop.IpHlpApi.ERROR_SUCCESS) { + var span = new ReadOnlySpan((byte*)buffer, (int)size); + // The table info just gives us the number of rows. - Interop.IpHlpApi.MibTcp6TableOwnerPid tcpTable6OwnerPid = Marshal.PtrToStructure(buffer); + ref readonly Interop.IpHlpApi.MibTcp6TableOwnerPid tcpTable6OwnerPid = ref MemoryMarshal.AsRef(span); if (tcpTable6OwnerPid.numberOfEntries > 0) { // Skip over the tableinfo to get the inline rows. - IntPtr newPtr = (IntPtr)((long)buffer + Marshal.SizeOf(tcpTable6OwnerPid.numberOfEntries)); + span = span.Slice(sizeof(Interop.IpHlpApi.MibTcp6TableOwnerPid)); for (int i = 0; i < tcpTable6OwnerPid.numberOfEntries; i++) { - Interop.IpHlpApi.MibTcp6RowOwnerPid tcp6RowOwnerPid = Marshal.PtrToStructure(newPtr); - tcpConnections.Add(new SystemTcpConnectionInformation(tcp6RowOwnerPid)); + tcpConnections.Add(new SystemTcpConnectionInformation(in MemoryMarshal.AsRef(span))); // We increment the pointer to the next row. - newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcp6RowOwnerPid)); + span = span.Slice(sizeof(Interop.IpHlpApi.MibTcp6RowOwnerPid)); } } } @@ -215,7 +212,7 @@ private List GetAllTcpConnections() } /// Gets the active UDP listeners. Uses the native GetUdpTable API. - public override IPEndPoint[] GetActiveUdpListeners() + public unsafe override IPEndPoint[] GetActiveUdpListeners() { uint size = 0; uint result = 0; @@ -229,29 +226,33 @@ public override IPEndPoint[] GetActiveUdpListeners() while (result == Interop.IpHlpApi.ERROR_INSUFFICIENT_BUFFER) { // Allocate the buffer and get the UDP table. - IntPtr buffer = IntPtr.Zero; + IntPtr buffer = Marshal.AllocHGlobal((int)size); + try { result = Interop.IpHlpApi.GetUdpTable(buffer, ref size, true); if (result == Interop.IpHlpApi.ERROR_SUCCESS) { + var span = new ReadOnlySpan((byte*)buffer, (int)size); + // The table info just gives us the number of rows. - Interop.IpHlpApi.MibUdpTable udpTableInfo = Marshal.PtrToStructure(buffer); + ref readonly Interop.IpHlpApi.MibUdpTable udpTableInfo = ref MemoryMarshal.AsRef(span); if (udpTableInfo.numberOfEntries > 0) { // Skip over the tableinfo to get the inline rows. - IntPtr newPtr = (IntPtr)((long)buffer + Marshal.SizeOf(udpTableInfo.numberOfEntries)); + span = span.Slice(sizeof(Interop.IpHlpApi.MibUdpTable)); + for (int i = 0; i < udpTableInfo.numberOfEntries; i++) { - Interop.IpHlpApi.MibUdpRow udpRow = Marshal.PtrToStructure(newPtr); + ref readonly Interop.IpHlpApi.MibUdpRow udpRow = ref MemoryMarshal.AsRef(span); int localPort = udpRow.localPort1 << 8 | udpRow.localPort2; udpListeners.Add(new IPEndPoint(udpRow.localAddr, (int)localPort)); // We increment the pointer to the next row. - newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udpRow)); + span = span.Slice(sizeof(Interop.IpHlpApi.MibUdpRow)); } } } @@ -288,23 +289,26 @@ public override IPEndPoint[] GetActiveUdpListeners() if (result == Interop.IpHlpApi.ERROR_SUCCESS) { + var span = new ReadOnlySpan((byte*)buffer, (int)size); + // The table info just gives us the number of rows. - Interop.IpHlpApi.MibUdp6TableOwnerPid udp6TableOwnerPid = Marshal.PtrToStructure(buffer); + ref readonly Interop.IpHlpApi.MibUdp6TableOwnerPid udp6TableOwnerPid = ref MemoryMarshal.AsRef(span); if (udp6TableOwnerPid.numberOfEntries > 0) { // Skip over the tableinfo to get the inline rows. - IntPtr newPtr = (IntPtr)((long)buffer + Marshal.SizeOf(udp6TableOwnerPid.numberOfEntries)); + span = span.Slice(sizeof(Interop.IpHlpApi.MibUdp6TableOwnerPid)); + for (int i = 0; i < udp6TableOwnerPid.numberOfEntries; i++) { - Interop.IpHlpApi.MibUdp6RowOwnerPid udp6RowOwnerPid = Marshal.PtrToStructure(newPtr); + ref readonly Interop.IpHlpApi.MibUdp6RowOwnerPid udp6RowOwnerPid = ref MemoryMarshal.AsRef(span); int localPort = udp6RowOwnerPid.localPort1 << 8 | udp6RowOwnerPid.localPort2; - udpListeners.Add(new IPEndPoint(new IPAddress(udp6RowOwnerPid.localAddr, + udpListeners.Add(new IPEndPoint(new IPAddress(udp6RowOwnerPid.localAddrAsSpan, udp6RowOwnerPid.localScopeId), localPort)); // We increment the pointer to the next row. - newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udp6RowOwnerPid)); + span = span.Slice(sizeof(Interop.IpHlpApi.MibUdp6RowOwnerPid)); } } } @@ -364,96 +368,39 @@ public override IcmpV6Statistics GetIcmpV6Statistics() return new SystemIcmpV6Statistics(); } - public override IAsyncResult BeginGetUnicastAddresses(AsyncCallback? callback, object? state) - { - ContextAwareResult asyncResult = new ContextAwareResult(false, false, this, state, callback); - asyncResult.StartPostingAsyncOp(false); - if (TeredoHelper.UnsafeNotifyStableUnicastIpAddressTable(StableUnicastAddressTableCallback, asyncResult)) - { - asyncResult.InvokeCallback(); - } + public override IAsyncResult BeginGetUnicastAddresses(AsyncCallback? callback, object? state) => + TaskToApm.Begin(GetUnicastAddressesAsync(), callback, state); - asyncResult.FinishPostingAsyncOp(); + public override UnicastIPAddressInformationCollection EndGetUnicastAddresses(IAsyncResult asyncResult) => + TaskToApm.End(asyncResult); - return asyncResult; - } + public override UnicastIPAddressInformationCollection GetUnicastAddresses() => + GetUnicastAddressesAsync().GetAwaiter().GetResult(); - public override UnicastIPAddressInformationCollection EndGetUnicastAddresses(IAsyncResult asyncResult) + public override async Task GetUnicastAddressesAsync() { - if (asyncResult == null) + // Wait for the address table to stabilize. + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + if (!TeredoHelper.UnsafeNotifyStableUnicastIpAddressTable(s => ((TaskCompletionSource)s).TrySetResult(true), tcs)) { - throw new ArgumentNullException(nameof(asyncResult)); + await tcs.Task.ConfigureAwait(false); } - ContextAwareResult? result = asyncResult as ContextAwareResult; - if (result == null || result.AsyncObject == null || result.AsyncObject.GetType() != typeof(SystemIPGlobalProperties)) - { - throw new ArgumentException(SR.net_io_invalidasyncresult); - } + // Get the address table. + var addresses = new UnicastIPAddressInformationCollection(); - if (result.EndCalled) + foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces()) { - throw new InvalidOperationException(SR.Format(SR.net_io_invalidendcall, "EndGetStableUnicastAddresses")); - } - - result.InternalWaitForCompletion(); - - result.EndCalled = true; - return GetUnicastAddressTable(); - } - - public override UnicastIPAddressInformationCollection GetUnicastAddresses() - { - // Wait for the Address Table to stabilize - using (ManualResetEvent stable = new ManualResetEvent(false)) - { - if (!TeredoHelper.UnsafeNotifyStableUnicastIpAddressTable(StableUnicastAddressTableCallback, stable)) - { - stable.WaitOne(); - } - } - - return GetUnicastAddressTable(); - } - - public override Task GetUnicastAddressesAsync() - { - return Task.Factory.FromAsync(BeginGetUnicastAddresses, EndGetUnicastAddresses, null); - } - - private static void StableUnicastAddressTableCallback(object param) - { - EventWaitHandle? handle = param as EventWaitHandle; - if (handle != null) - { - handle.Set(); - } - else - { - LazyAsyncResult asyncResult = (LazyAsyncResult)param; - asyncResult.InvokeCallback(); - } - } - - private static UnicastIPAddressInformationCollection GetUnicastAddressTable() - { - UnicastIPAddressInformationCollection rval = new UnicastIPAddressInformationCollection(); - - NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces(); - for (int i = 0; i < interfaces.Length; ++i) - { - UnicastIPAddressInformationCollection addresses = interfaces[i].GetIPProperties().UnicastAddresses; - - foreach (UnicastIPAddressInformation address in addresses) + foreach (UnicastIPAddressInformation address in ni.GetIPProperties().UnicastAddresses) { - if (!rval.Contains(address)) + if (!addresses.Contains(address)) { - rval.InternalAdd(address); + addresses.InternalAdd(address); } } } - return rval; + return addresses; } } } diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemTcpConnection.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemTcpConnection.cs index a0db0237229b22..a588a0c970cb56 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemTcpConnection.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemTcpConnection.cs @@ -11,7 +11,7 @@ internal class SystemTcpConnectionInformation : TcpConnectionInformation private readonly IPEndPoint _remoteEndPoint; private readonly TcpState _state; - internal SystemTcpConnectionInformation(Interop.IpHlpApi.MibTcpRow row) + internal SystemTcpConnectionInformation(in Interop.IpHlpApi.MibTcpRow row) { _state = row.state; @@ -25,7 +25,7 @@ internal SystemTcpConnectionInformation(Interop.IpHlpApi.MibTcpRow row) } // IPV6 version of the Tcp row. - internal SystemTcpConnectionInformation(Interop.IpHlpApi.MibTcp6RowOwnerPid row) + internal unsafe SystemTcpConnectionInformation(in Interop.IpHlpApi.MibTcp6RowOwnerPid row) { _state = row.state; @@ -34,8 +34,8 @@ internal SystemTcpConnectionInformation(Interop.IpHlpApi.MibTcp6RowOwnerPid row) int localPort = row.localPort1 << 8 | row.localPort2; int remotePort = ((_state == TcpState.Listen) ? 0 : row.remotePort1 << 8 | row.remotePort2); - _localEndPoint = new IPEndPoint(new IPAddress(row.localAddr, row.localScopeId), (int)localPort); - _remoteEndPoint = new IPEndPoint(new IPAddress(row.remoteAddr, row.remoteScopeId), (int)remotePort); + _localEndPoint = new IPEndPoint(new IPAddress(row.localAddrAsSpan, row.localScopeId), (int)localPort); + _remoteEndPoint = new IPEndPoint(new IPAddress(row.remoteAddrAsSpan, row.remoteScopeId), (int)remotePort); } public override TcpState State { get { return _state; } } diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs index 0b30f861cf95f3..b5134e10728f61 100644 --- a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs @@ -28,7 +28,6 @@ public IPGlobalPropertiesTest(ITestOutputHelper output) } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsSubsystemForLinux))] // [ActiveIssue("https://github.com/dotnet/runtime/issues/18258")] - [PlatformSpecific(TestPlatforms.AnyUnix)] public void IPGlobalProperties_AccessAllMethods_NoErrors() { IPGlobalProperties gp = IPGlobalProperties.GetIPGlobalProperties(); @@ -54,7 +53,6 @@ public void IPGlobalProperties_AccessAllMethods_NoErrors() [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsSubsystemForLinux))] // [ActiveIssue("https://github.com/dotnet/runtime/issues/18258")] [MemberData(nameof(Loopbacks))] - [PlatformSpecific(TestPlatforms.AnyUnix)] public void IPGlobalProperties_TcpListeners_Succeed(IPAddress address) { using (var server = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) @@ -79,8 +77,8 @@ public void IPGlobalProperties_TcpListeners_Succeed(IPAddress address) } [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsSubsystemForLinux))] // [ActiveIssue("https://github.com/dotnet/runtime/issues/18258")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [MemberData(nameof(Loopbacks))] - [PlatformSpecific(TestPlatforms.AnyUnix)] public async Task IPGlobalProperties_TcpActiveConnections_Succeed(IPAddress address) { using (var server = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) @@ -110,7 +108,6 @@ public async Task IPGlobalProperties_TcpActiveConnections_Succeed(IPAddress addr } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsSubsystemForLinux))] // [ActiveIssue("https://github.com/dotnet/runtime/issues/18258")] - [PlatformSpecific(TestPlatforms.AnyUnix)] public void IPGlobalProperties_TcpActiveConnections_NotListening() { TcpConnectionInformation[] tcpCconnections = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections(); @@ -119,5 +116,14 @@ public void IPGlobalProperties_TcpActiveConnections_NotListening() Assert.NotEqual(TcpState.Listen, ti.State); } } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsSubsystemForLinux))] // [ActiveIssue("https://github.com/dotnet/runtime/issues/18258")] + public async Task GetUnicastAddresses_NotEmpty() + { + IPGlobalProperties props = IPGlobalProperties.GetIPGlobalProperties(); + Assert.NotEmpty(props.GetUnicastAddresses()); + Assert.NotEmpty(await props.GetUnicastAddressesAsync()); + Assert.NotEmpty(await Task.Factory.FromAsync(props.BeginGetUnicastAddresses, props.EndGetUnicastAddresses, null)); + } } } diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/System.Net.NetworkInformation.Functional.Tests.csproj b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/System.Net.NetworkInformation.Functional.Tests.csproj index 4e5a858b2fb43f..f9b964b19b5dac 100644 --- a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/System.Net.NetworkInformation.Functional.Tests.csproj +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/System.Net.NetworkInformation.Functional.Tests.csproj @@ -6,30 +6,22 @@ - - SharedSource\StringParsingHelpers.Addresses.cs - - - SharedSource\StringParsingHelpers.Connections.cs - - - SharedSource\StringParsingHelpers.Dns.cs - - - SharedSource\StringParsingHelpers.Misc.cs - - - SharedSource\StringParsingHelpers.Statistics.cs - - - SharedSource\NetworkFiles.cs - - - SharedSource\SimpleTcpConnectionInformation.cs - - - SharedSource\SimpleGatewayIPAddressInformation.cs - + + + + + + + + @@ -47,24 +39,18 @@ - - Common\System\Net\TestLogging.cs - - - Common\System\Net\VerboseTestLogging.cs - - - Common\System\Net\EventSourceTestLogging.cs - - - Common\System\Net\Capability.Sockets.cs - - - Common\System\IO\StringParser.cs - - - Common\System\IO\RowConfigReader.cs - + + + + + + diff --git a/src/libraries/System.Net.Ping/src/System.Net.Ping.csproj b/src/libraries/System.Net.Ping/src/System.Net.Ping.csproj index 36d2f01f06dd80..d21687048995d7 100644 --- a/src/libraries/System.Net.Ping/src/System.Net.Ping.csproj +++ b/src/libraries/System.Net.Ping/src/System.Net.Ping.csproj @@ -17,108 +17,81 @@ - - Common\System\Net\ByteOrder.cs - - - Common\System\Net\IPAddressParserStatics.cs - - - Common\System\Net\SocketAddress.cs - + + + - - Common\System\Net\Logging\NetEventSource.Common.cs - - - Common\System\Net\InternalException.cs - + + - - Common\System\Net\Internals\IPAddressExtensions.cs - - - Common\System\Net\Internals\IPEndPointExtensions.cs - + + - - Common\System\Net\RawSocketPermissions.cs - - - Common\System\Net\SocketAddressPal.Unix.cs - - - Common\System\Net\SocketProtocolSupportPal.Unix.cs - - - Common\System\Net\NetworkInformation\UnixCommandLinePing.cs - + + + + - - Common\Interop\Unix\Interop.Errors.cs - - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\System.Native\Interop.Close.cs - - - Common\Interop\Unix\System.Native\Interop.ReadLink.cs - - - Common\Interop\Unix\System.Native\Interop.Socket.cs - - - Common\Interop\Unix\System.Native\Interop.SocketAddress.cs - + + + + + + - - Common\System\Net\SocketAddressPal.Windows.cs - - - Common\System\Net\SocketProtocolSupportPal.Windows.cs - - - Common\Microsoft\Win32\SafeHandles\SafeLocalAllocHandle.cs - + + + - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\IpHlpApi\Interop.ErrorCodes.cs - - - Common\Interop\Windows\IpHlpApi\Interop.ICMP.cs - - - Common\Interop\Windows\WinSock\Interop.closesocket.cs - - - Common\Interop\Windows\WinSock\Interop.WSASocketW.cs - - - Common\Interop\Windows\WinSock\Interop.SocketConstructorFlags.cs - + + + + + + - - Common\System\Net\Sockets\SocketType.cs - + diff --git a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Unix.cs b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Unix.cs index b0b008d6d8b4b3..9b5c56ed8ba695 100644 --- a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Unix.cs +++ b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Unix.cs @@ -19,6 +19,8 @@ public partial class Ping private const int IcmpHeaderLengthInBytes = 8; private const int MinIpHeaderLengthInBytes = 20; private const int MaxIpHeaderLengthInBytes = 60; + private static readonly bool _sendIpHeader = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + private static readonly bool _needsConnect = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); [ThreadStatic] private static Random? t_idGenerator; @@ -46,19 +48,36 @@ private async Task SendPingAsyncCore(IPAddress address, byte[] buffer return reply; } - private SocketConfig GetSocketConfig(IPAddress address, byte[] buffer, int timeout, PingOptions? options) + private unsafe SocketConfig GetSocketConfig(IPAddress address, byte[] buffer, int timeout, PingOptions? options) { // Use a random value as the identifier. This doesn't need to be perfectly random // or very unpredictable, rather just good enough to avoid unexpected conflicts. Random rand = t_idGenerator ??= new Random(); ushort id = (ushort)rand.Next(ushort.MaxValue + 1); + IpHeader iph = default; bool ipv4 = address.AddressFamily == AddressFamily.InterNetwork; + bool sendIpHeader = ipv4 && options != null && _sendIpHeader; + + if (sendIpHeader) + { + iph.VersionAndLength = 0x45; + // On OSX this strangely must be host byte order. + iph.TotalLength = (ushort)(sizeof(IpHeader) + checked(sizeof(IcmpHeader) + buffer.Length)); + iph.Protocol = 1; // ICMP + iph.Ttl = (byte)options!.Ttl; + iph.Flags = (ushort)(options.DontFragment ? 0x4000 : 0); +#pragma warning disable 618 + iph.DestinationAddress = (uint)address.Address; +#pragma warning restore 618 + // No need to fill in SourceAddress or checksum. + // If left blank, kernel will fill it in - at least on OSX. + } return new SocketConfig( new IPEndPoint(address, 0), timeout, options, ipv4, ipv4 ? ProtocolType.Icmp : ProtocolType.IcmpV6, id, - CreateSendMessageBuffer(new IcmpHeader() + CreateSendMessageBuffer(iph, new IcmpHeader() { Type = ipv4 ? (byte)IcmpV4MessageType.EchoRequest : (byte)IcmpV6MessageType.EchoRequest, Identifier = id, @@ -68,12 +87,16 @@ private SocketConfig GetSocketConfig(IPAddress address, byte[] buffer, int timeo private Socket GetRawSocket(SocketConfig socketConfig) { IPEndPoint ep = (IPEndPoint)socketConfig.EndPoint; - - // Setting Socket.DontFragment and .Ttl is not supported on Unix, so socketConfig.Options is ignored. AddressFamily addrFamily = ep.Address.AddressFamily; + Socket socket = new Socket(addrFamily, SocketType.Raw, socketConfig.ProtocolType); socket.ReceiveTimeout = socketConfig.Timeout; socket.SendTimeout = socketConfig.Timeout; + if (addrFamily == AddressFamily.InterNetworkV6 && RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + socket.DualMode = false; + } + if (socketConfig.Options != null && socketConfig.Options.Ttl > 0) { socket.Ttl = (short)socketConfig.Options.Ttl; @@ -81,13 +104,21 @@ private Socket GetRawSocket(SocketConfig socketConfig) if (socketConfig.Options != null && addrFamily == AddressFamily.InterNetwork) { - socket.DontFragment = socketConfig.Options.DontFragment; + if (_sendIpHeader) + { + // some platforms like OSX don't support DontFragment so we construct IP header instead. + socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, 1); + } + else + { + socket.DontFragment = socketConfig.Options.DontFragment; + } } #pragma warning disable 618 // Disable warning about obsolete property. We could use GetAddressBytes but that allocates. // IPv4 multicast address starts with 1110 bits so mask rest and test if we get correct value e.g. 0xe0. - if (!ep.Address.IsIPv6Multicast && !(addrFamily == AddressFamily.InterNetwork && (ep.Address.Address & 0xf0) == 0xe0)) + if (_needsConnect && !ep.Address.IsIPv6Multicast && !(addrFamily == AddressFamily.InterNetwork && (ep.Address.Address & 0xf0) == 0xe0)) { // If it is not multicast, use Connect to scope responses only to the target address. socket.Connect(socketConfig.EndPoint); @@ -247,7 +278,7 @@ await socket.SendToAsync( } } - private Process GetPingProcess(IPAddress address, byte[] buffer, PingOptions? options) + private Process GetPingProcess(IPAddress address, byte[] buffer, int timeout, PingOptions? options) { bool isIpv4 = address.AddressFamily == AddressFamily.InterNetwork; string? pingExecutable = isIpv4 ? UnixCommandLinePing.Ping4UtilityPath : UnixCommandLinePing.Ping6UtilityPath; @@ -262,7 +293,7 @@ private Process GetPingProcess(IPAddress address, byte[] buffer, PingOptions? op fragmentOption = options.DontFragment ? UnixCommandLinePing.PingFragmentOptions.Do : UnixCommandLinePing.PingFragmentOptions.Dont; } - string processArgs = UnixCommandLinePing.ConstructCommandLine(buffer.Length, address.ToString(), isIpv4, options?.Ttl ?? 0, fragmentOption); + string processArgs = UnixCommandLinePing.ConstructCommandLine(buffer.Length, timeout, address.ToString(), isIpv4, options?.Ttl ?? 0, fragmentOption); ProcessStartInfo psi = new ProcessStartInfo(pingExecutable, processArgs); psi.RedirectStandardOutput = true; @@ -272,7 +303,7 @@ private Process GetPingProcess(IPAddress address, byte[] buffer, PingOptions? op private PingReply SendWithPingUtility(IPAddress address, byte[] buffer, int timeout, PingOptions? options) { - using (Process p = GetPingProcess(address, buffer, options)) + using (Process p = GetPingProcess(address, buffer, timeout, options)) { p.Start(); if (!p.WaitForExit(timeout) || p.ExitCode == 1 || p.ExitCode == 2) @@ -295,7 +326,7 @@ private PingReply SendWithPingUtility(IPAddress address, byte[] buffer, int time private async Task SendWithPingUtilityAsync(IPAddress address, byte[] buffer, int timeout, PingOptions? options) { - using (Process p = GetPingProcess(address, buffer, options)) + using (Process p = GetPingProcess(address, buffer, timeout, options)) { var processCompletion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); p.EnableRaisingEvents = true; @@ -359,6 +390,24 @@ static Ping() } #endif + [StructLayout(LayoutKind.Sequential)] + internal struct IpHeader + { + internal byte VersionAndLength; + internal byte Tos; + internal ushort TotalLength; + + internal ushort Identifier; + internal ushort Flags; + + internal byte Ttl; + internal byte Protocol; + internal ushort HeaderChecksum; + + internal uint SourceAddress; + internal uint DestinationAddress; + }; + // Must be 8 bytes total. [StructLayout(LayoutKind.Sequential)] internal struct IcmpHeader @@ -395,21 +444,34 @@ public SocketConfig(EndPoint endPoint, int timeout, PingOptions? options, bool i public readonly byte[] SendBuffer; } - private static unsafe byte[] CreateSendMessageBuffer(IcmpHeader header, byte[] payload) + private static unsafe byte[] CreateSendMessageBuffer(IpHeader ipHeader, IcmpHeader icmpHeader, byte[] payload) { - int headerSize = sizeof(IcmpHeader); - byte[] result = new byte[headerSize + payload.Length]; - Marshal.Copy(new IntPtr(&header), result, 0, headerSize); - payload.CopyTo(result, headerSize); - ushort checksum = ComputeBufferChecksum(result); + int icmpHeaderSize = sizeof(IcmpHeader); + int offset = 0; + int packetSize = ipHeader.TotalLength != 0 ? ipHeader.TotalLength : checked(icmpHeaderSize + payload.Length); + byte[] result = new byte[packetSize]; + + if (ipHeader.TotalLength != 0) + { + int ipHeaderSize = sizeof(IpHeader); + new Span(&ipHeader, sizeof(IpHeader)).CopyTo(result); + offset = ipHeaderSize; + } + + //byte[] result = new byte[headerSize + payload.Length]; + Marshal.Copy(new IntPtr(&icmpHeader), result, offset, icmpHeaderSize); + payload.CopyTo(result, offset + icmpHeaderSize); + + // offset now still points to beginning of ICMP header. + ushort checksum = ComputeBufferChecksum(result.AsSpan().Slice(offset)); // Jam the checksum into the buffer. - result[2] = (byte)(checksum >> 8); - result[3] = (byte)(checksum & (0xFF)); + result[offset + 2] = (byte)(checksum >> 8); + result[offset + 3] = (byte)(checksum & (0xFF)); return result; } - private static ushort ComputeBufferChecksum(byte[] buffer) + private static ushort ComputeBufferChecksum(ReadOnlySpan buffer) { // This is using the "deferred carries" approach outlined in RFC 1071. uint sum = 0; diff --git a/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs b/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs index 90154a83c8cd6f..5d69069dc9b375 100644 --- a/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs +++ b/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs @@ -9,6 +9,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Microsoft.DotNet.RemoteExecutor; using Xunit; using Xunit.Abstractions; @@ -46,10 +47,12 @@ public PingTest(ITestOutputHelper output) private void PingResultValidator(PingReply pingReply, IPAddress localIpAddress) { - PingResultValidator(pingReply, new IPAddress[] { localIpAddress }); + PingResultValidator(pingReply, new IPAddress[] { localIpAddress }, _output); } - private void PingResultValidator(PingReply pingReply, IPAddress[] localIpAddresses) + private void PingResultValidator(PingReply pingReply, IPAddress[] localIpAddresses) => PingResultValidator(pingReply, localIpAddresses, null); + + private static void PingResultValidator(PingReply pingReply, IPAddress[] localIpAddresses, ITestOutputHelper output) { if (pingReply.Status == IPStatus.TimedOut && pingReply.Address.AddressFamily == AddressFamily.InterNetworkV6 && PlatformDetection.IsOSX) { @@ -65,10 +68,13 @@ private void PingResultValidator(PingReply pingReply, IPAddress[] localIpAddress } // We did not find response address in given list. // Test is going to fail. Collect some more info. - _output.WriteLine($"Reply address {pingReply.Address} is not expected local address."); - foreach (IPAddress address in localIpAddresses) + if (output != null) { - _output.WriteLine($"Local address {address}"); + output.WriteLine($"Reply address {pingReply.Address} is not expected local address."); + foreach (IPAddress address in localIpAddresses) + { + output.WriteLine($"Local address {address}"); + } } Assert.Contains(pingReply.Address, localIpAddresses); ///, "Reply address {pingReply.Address} is not expected local address."); @@ -134,7 +140,7 @@ public void SendPingWithIPAddress(AddressFamily addressFamily) } SendBatchPing( - (ping) => ping.Send(localIpAddress), + (ping) => ping.Send(localIpAddress, TestSettings.PingTimeout), (pingReply) => { PingResultValidator(pingReply, localIpAddress); @@ -880,5 +886,35 @@ public async Task Ping_TimedOut_TAP_Success() PingReply reply = await sender.SendPingAsync(TestSettings.UnreachableAddress); Assert.Equal(IPStatus.TimedOut, reply.Status); } + + [PlatformSpecific(TestPlatforms.AnyUnix)] + [Theory] + [Trait(XunitConstants.Category, XunitConstants.RequiresElevation)] + [InlineData(AddressFamily.InterNetwork)] + [InlineData(AddressFamily.InterNetworkV6)] + [OuterLoop] // Depends on sudo + public void SendPingWithIPAddressAndTimeoutAndBufferAndPingOptions_ElevatedUnix(AddressFamily addressFamily) + { + IPAddress localIpAddress = TestSettings.GetLocalIPAddress(addressFamily); + if (localIpAddress == null) + { + // No local address for given address family. + return; + } + + _output.WriteLine($"pinging '{localIpAddress}'"); + + RemoteExecutor.Invoke(address => + { + byte[] buffer = TestSettings.PayloadAsBytes; + SendBatchPing( + (ping) => ping.Send(address, TestSettings.PingTimeout, buffer, new PingOptions()), + (pingReply) => + { + PingResultValidator(pingReply, new IPAddress[] { IPAddress.Parse(address) }, null); + Assert.Equal(buffer, pingReply.Buffer); + }); + }, localIpAddress.ToString(), new RemoteInvokeOptions { RunAsSudo = true }).Dispose(); + } } } diff --git a/src/libraries/System.Net.Ping/tests/FunctionalTests/System.Net.Ping.Functional.Tests.csproj b/src/libraries/System.Net.Ping/tests/FunctionalTests/System.Net.Ping.Functional.Tests.csproj index f7710a18bb4d0a..e8b25d0500fcba 100644 --- a/src/libraries/System.Net.Ping/tests/FunctionalTests/System.Net.Ping.Functional.Tests.csproj +++ b/src/libraries/System.Net.Ping/tests/FunctionalTests/System.Net.Ping.Functional.Tests.csproj @@ -2,6 +2,7 @@ $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix true + true @@ -12,26 +13,19 @@ - - SocketCommon\Configuration.cs - - - SocketCommon\Configuration.Ping.cs - - - Common\System\Net\RawSocketPermissions.cs - - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\System.Native\Interop.ReadLink.cs - - - Common\System\Net\NetworkInformation\UnixCommandLinePing.cs - - - Common\System\Net\Capability.RawSocketPermissions.cs - + + + + + + + diff --git a/src/libraries/System.Net.Ping/tests/FunctionalTests/UnixPingUtilityTests.cs b/src/libraries/System.Net.Ping/tests/FunctionalTests/UnixPingUtilityTests.cs index 7711aff9cb87cc..899a2eaa179454 100644 --- a/src/libraries/System.Net.Ping/tests/FunctionalTests/UnixPingUtilityTests.cs +++ b/src/libraries/System.Net.Ping/tests/FunctionalTests/UnixPingUtilityTests.cs @@ -19,6 +19,28 @@ public class UnixPingUtilityTests { private const int IcmpHeaderLengthInBytes = 8; + [Theory] + [InlineData(0)] + [InlineData(100)] + [InlineData(1000)] + [InlineData(1500)] + [PlatformSpecific(TestPlatforms.AnyUnix)] + public static void TimeoutIsRespected(int timeout) + { + Process p = ConstructPingProcess(IPAddress.Parse(TestSettings.UnreachableAddress), 50, timeout); + //suppress Ping output to console/terminal stdout during test execution + p.StartInfo.RedirectStandardError = true; + p.StartInfo.RedirectStandardOutput = true; + + Stopwatch stopWatch = Stopwatch.StartNew(); + + p.Start(); + p.WaitForExit(); + + //ensure that the process takes longer than or equal to 'timeout' + Assert.True(stopWatch.ElapsedMilliseconds >= timeout); + } + [Theory] [InlineData(0)] [InlineData(1)] @@ -27,36 +49,28 @@ public class UnixPingUtilityTests [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests un-priviledged Ping support on Unix public static async Task PacketSizeIsRespected(int payloadSize) { - IPAddress localAddress = await TestSettings.GetLocalIPAddressAsync(); - bool ipv4 = localAddress.AddressFamily == AddressFamily.InterNetwork; - string arguments = UnixCommandLinePing.ConstructCommandLine(payloadSize, localAddress.ToString(), ipv4); - string utilityPath = (localAddress.AddressFamily == AddressFamily.InterNetwork) - ? UnixCommandLinePing.Ping4UtilityPath - : UnixCommandLinePing.Ping6UtilityPath; - - var p = new Process(); - p.StartInfo.FileName = utilityPath; - p.StartInfo.Arguments = arguments; - p.StartInfo.UseShellExecute = false; + var stdOutLines = new List(); + var stdErrLines = new List(); + Process p = ConstructPingProcess(await TestSettings.GetLocalIPAddressAsync(), payloadSize, 1000); p.StartInfo.RedirectStandardOutput = true; - var stdOutLines = new List(); - p.OutputDataReceived += new DataReceivedEventHandler( - delegate (object sendingProcess, DataReceivedEventArgs outputLine) { stdOutLines.Add(outputLine.Data); }); + p.OutputDataReceived += delegate (object sendingProcess, DataReceivedEventArgs outputLine) + { + stdOutLines.Add(outputLine.Data); + }; p.StartInfo.RedirectStandardError = true; - var stdErrLines = new List(); - p.ErrorDataReceived += new DataReceivedEventHandler( - delegate (object sendingProcess, DataReceivedEventArgs errorLine) { stdErrLines.Add(errorLine.Data); }); + p.ErrorDataReceived += delegate (object sendingProcess, DataReceivedEventArgs errorLine) + { + stdErrLines.Add(errorLine.Data); + }; p.Start(); p.BeginOutputReadLine(); p.BeginErrorReadLine(); // There are multiple issues with ping6 in macOS 10.12 (Sierra), see https://github.com/dotnet/runtime/issues/24682. - bool isPing6OnMacSierra = utilityPath.Equals(UnixCommandLinePing.Ping6UtilityPath) && - RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && - !PlatformDetection.IsMacOsHighSierraOrHigher; + bool isPing6OnMacSierra = IsPing6OnMacSierra(p.StartInfo); string pingOutput; if (!p.WaitForExit(TestSettings.PingTimeout)) @@ -68,7 +82,7 @@ public static async Task PacketSizeIsRespected(int payloadSize) pingOutput = string.Join("\n", stdOutLines); string stdErr = string.Join("\n", stdErrLines); throw new Exception( - $"[{utilityPath} {arguments}] process did not exit in {TestSettings.PingTimeout} ms.\nStdOut:[{pingOutput}]\nStdErr:[{stdErr}]"); + $"[{p.StartInfo.FileName} {p.StartInfo.Arguments}] process did not exit in {TestSettings.PingTimeout} ms.\nStdOut:[{pingOutput}]\nStdErr:[{stdErr}]"); } // Ensure standard output and error are flushed @@ -84,7 +98,7 @@ public static async Task PacketSizeIsRespected(int payloadSize) string stdErr = string.Join("\n", stdErrLines); throw new Exception( - $"[{utilityPath} {arguments}] process exit code is {exitCode}.\nStdOut:[{pingOutput}]\nStdErr:[{stdErr}]"); + $"[{p.StartInfo.FileName} {p.StartInfo.Arguments}] process exit code is {exitCode}.\nStdOut:[{pingOutput}]\nStdErr:[{stdErr}]"); } try @@ -106,10 +120,33 @@ public static async Task PacketSizeIsRespected(int payloadSize) { string stdErr = string.Join("\n", stdErrLines); throw new Exception( - $"Parse error for [{utilityPath} {arguments}] process exit code is {exitCode}.\nStdOut:[{pingOutput}]\nStdErr:[{stdErr}]", e); + $"Parse error for [{p.StartInfo.FileName} {p.StartInfo.Arguments}] process exit code is {exitCode}.\nStdOut:[{pingOutput}]\nStdErr:[{stdErr}]", e); } } + private static bool IsPing6OnMacSierra(ProcessStartInfo startInfo) + { + return startInfo.FileName.Equals(UnixCommandLinePing.Ping6UtilityPath) && + RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && + !PlatformDetection.IsMacOsHighSierraOrHigher; + } + + private static Process ConstructPingProcess(IPAddress localAddress, int payloadSize, int timeout) + { + bool ipv4 = localAddress.AddressFamily == AddressFamily.InterNetwork; + string arguments = UnixCommandLinePing.ConstructCommandLine(payloadSize, timeout, localAddress.ToString(), ipv4); + string utilityPath = (localAddress.AddressFamily == AddressFamily.InterNetwork) + ? UnixCommandLinePing.Ping4UtilityPath + : UnixCommandLinePing.Ping6UtilityPath; + + var p = new Process(); + p.StartInfo.FileName = utilityPath; + p.StartInfo.Arguments = arguments; + p.StartInfo.UseShellExecute = false; + + return p; + } + private static int ParseReturnedPacketSize(string pingOutput) { int indexOfBytesFrom = pingOutput.IndexOf("bytes from"); diff --git a/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs b/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs index ff1ed569735099..36b256f3757b3f 100644 --- a/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs +++ b/src/libraries/System.Net.Primitives/ref/System.Net.Primitives.cs @@ -259,7 +259,7 @@ public IPAddress(System.ReadOnlySpan address, long scopeid) { } public override string ToString() { throw null; } public bool TryFormat(System.Span destination, out int charsWritten) { throw null; } public static bool TryParse(System.ReadOnlySpan ipString, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Net.IPAddress? address) { throw null; } - public static bool TryParse(string? ipString, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Net.IPAddress? address) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? ipString, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out System.Net.IPAddress? address) { throw null; } public bool TryWriteBytes(System.Span destination, out int bytesWritten) { throw null; } } public partial class IPEndPoint : System.Net.EndPoint diff --git a/src/libraries/System.Net.Primitives/src/MatchingRefApiCompatBaseline.netcoreapp5.0.txt b/src/libraries/System.Net.Primitives/src/MatchingRefApiCompatBaseline.txt similarity index 100% rename from src/libraries/System.Net.Primitives/src/MatchingRefApiCompatBaseline.netcoreapp5.0.txt rename to src/libraries/System.Net.Primitives/src/MatchingRefApiCompatBaseline.txt diff --git a/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj b/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj index 4d6d6413db52f2..336460cdd13268 100644 --- a/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj +++ b/src/libraries/System.Net.Primitives/src/System.Net.Primitives.csproj @@ -29,12 +29,10 @@ - - System\Net\IPv4AddressHelper.Common.cs - - - System\Net\IPv6AddressHelper.Common.cs - + + @@ -50,145 +48,101 @@ - - Common\System\StringExtensions.cs - - - Common\System\Net\ByteOrder.cs - - - ProductionCode\System\Net\CookieComparer.cs - - - Common\System\Net\CookieFields.cs - - - Common\System\Net\CookieParser.cs - - - Common\System\Net\IPAddressParserStatics.cs - - - Common\System\Net\HttpKnownHeaderNames.cs - - - Common\System\Net\TcpValidationHelpers.cs - - - Common\System\Net\UriScheme.cs - - - Common\System\Net\SocketAddress.cs - - - Common\System\Net\NegotiationInfoClass.cs - - - Common\System\Net\NetworkInformation\HostInformation.cs - - - Common\System\Marvin.cs - - - Common\System\Text\StringBuilderCache.cs - - - Common\System\Runtime\CompilerServices\PreserveDependencyAttribute.cs - - - Common\System\HexConverter.cs - + + + + + + + + + + + + + + + + - - Common\System\Net\Logging\NetEventSource.Common.cs - - - Common\System\NotImplemented.cs - - - Common\Interop\Windows\Crypt32\Interop.Alg.cs - - - Common\Interop\Windows\SChannel\Interop.SchProtocols.cs - - - Common\Interop\Windows\WinSock\Interop.ErrorCodes.cs - + + + + + - - Common\System\Net\SocketAddressPal.Windows.cs - - - Common\Interop\Windows\IpHlpApi\Interop.ErrorCodes.cs - - - Common\Interop\Windows\IpHlpApi\Interop.FIXED_INFO.cs - - - Common\Interop\Windows\IpHlpApi\Interop.IP_ADDR_STRING.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\System\Net\NetworkInformation\HostInformationPal.Windows.cs - - - Common\Interop\Windows\IpHlpApi\Interop.GetNetworkParams.cs - - - Common\Interop\Windows\Kernel32\Interop.LocalAlloc.cs - - - Common\System\Net\NetworkInformation\InterfaceInfoPal.Windows.cs - - - Common\Interop\Windows\IpHlpApi\Interop.if_nametoindex.cs - + + + + + + + + + + - - Common\System\Net\SocketAddressPal.Unix.cs - - - Common\System\Net\NetworkInformation\HostInformationPal.Unix.cs - - - Common\System\Net\Sockets\SocketErrorPal.Unix.cs - - - Common\Interop\Unix\Interop.Errors.cs - - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\System.Native\Interop.GetDomainName.cs - - - Common\Interop\Unix\System.Native\Interop.GetHostName.cs - - - Common\Interop\Unix\System.Native\Interop.GetNameInfo.cs - - - Common\Interop\Unix\System.Native\Interop.HostEntry.cs - - - Common\Interop\Unix\System.Native\Interop.IPAddress.cs - - - Common\System\Net\NetworkInformation\InterfaceInfoPal.Unix.cs - - - Common\Interop\Unix\System.Native\Interop.InterfaceNameToIndex.cs - - - Common\Interop\Unix\System.Native\Interop.SocketAddress.cs - + + + + + + + + + + + + + diff --git a/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs b/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs index 87a5db6e9883b8..b514d78d65201f 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs @@ -38,7 +38,7 @@ public sealed class Cookie internal const string MaxSupportedVersionString = "1"; internal const string SeparatorLiteral = "; "; - internal const string EqualsLiteral = "="; + internal const char EqualsLiteral = '='; internal const string QuotesLiteral = "\""; internal const string SpecialAttributeLiteral = "$"; @@ -837,7 +837,7 @@ internal void ToString(StringBuilder sb) { result += SeparatorLiteral + CookieFields.VersionAttributeName + EqualsLiteral + m_version.ToString(NumberFormatInfo.InvariantInfo); } - return result == EqualsLiteral ? null : result; + return result == "=" ? null : result; } } } diff --git a/src/libraries/System.Net.Primitives/src/System/Net/CookieContainer.cs b/src/libraries/System.Net.Primitives/src/System/Net/CookieContainer.cs index 75f68bb98086e5..af1f75ebc9d490 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/CookieContainer.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/CookieContainer.cs @@ -118,7 +118,7 @@ public CookieContainer(int capacity) { if (capacity <= 0) { - throw new ArgumentException(SR.net_toosmall, "Capacity"); + throw new ArgumentException(SR.net_toosmall, nameof(capacity)); } m_maxCookies = capacity; } @@ -132,7 +132,7 @@ public CookieContainer(int capacity, int perDomainCapacity, int maxCookieSize) : m_maxCookiesPerDomain = perDomainCapacity; if (maxCookieSize <= 0) { - throw new ArgumentException(SR.net_toosmall, "MaxCookieSize"); + throw new ArgumentException(SR.net_toosmall, nameof(maxCookieSize)); } m_maxCookieSize = maxCookieSize; } @@ -230,7 +230,7 @@ public void Add(Cookie cookie) { throw new ArgumentException( SR.Format(SR.net_emptystringcall, nameof(cookie) + "." + nameof(cookie.Domain)), - nameof(cookie) + "." + nameof(cookie.Domain)); + nameof(cookie)); } Uri? uri; diff --git a/src/libraries/System.Net.Primitives/src/System/Net/IPAddress.cs b/src/libraries/System.Net.Primitives/src/System/Net/IPAddress.cs index 1d70c5e9f6441e..45ead27e784d95 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/IPAddress.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/IPAddress.cs @@ -215,7 +215,7 @@ internal IPAddress(int newAddress) /// Converts an IP address string to an instance. /// /// - public static bool TryParse(string? ipString, [NotNullWhen(true)] out IPAddress? address) + public static bool TryParse([NotNullWhen(true)] string? ipString, [NotNullWhen(true)] out IPAddress? address) { if (ipString == null) { diff --git a/src/libraries/System.Net.Primitives/tests/FunctionalTests/System.Net.Primitives.Functional.Tests.csproj b/src/libraries/System.Net.Primitives/tests/FunctionalTests/System.Net.Primitives.Functional.Tests.csproj index 57187bfa326d07..1ef5c758214de5 100644 --- a/src/libraries/System.Net.Primitives/tests/FunctionalTests/System.Net.Primitives.Functional.Tests.csproj +++ b/src/libraries/System.Net.Primitives/tests/FunctionalTests/System.Net.Primitives.Functional.Tests.csproj @@ -24,9 +24,8 @@ - - Common\System\Diagnostics\Tracing\TestEventListener.cs - + diff --git a/src/libraries/System.Net.Primitives/tests/PalTests/System.Net.Primitives.Pal.Tests.csproj b/src/libraries/System.Net.Primitives/tests/PalTests/System.Net.Primitives.Pal.Tests.csproj index 2cf3d34ae653c1..1dd265af159561 100644 --- a/src/libraries/System.Net.Primitives/tests/PalTests/System.Net.Primitives.Pal.Tests.csproj +++ b/src/libraries/System.Net.Primitives/tests/PalTests/System.Net.Primitives.Pal.Tests.csproj @@ -14,149 +14,104 @@ - - ProductionCode\System\Net\Sockets\AddressFamily.cs - - - ProductionCode\System\Net\Sockets\SocketError.cs - - - ProductionCode\System\Net\IPAddress.cs - - - ProductionCode\System\Net\IPAddressParser.cs - - - ProductionCode\System\Net\IPv4AddressHelper.Common.cs - - - ProductionCode\System\Net\IPv6AddressHelper.Common.cs - - - ProductionCode\System\Net\IPEndPoint.cs - - - Common\System\Net\SocketAddress.cs - - - ProductionCode\System\Net\EndPoint.cs - - - ProductionCode\Common\System\Marvin.cs - - - ProductionCode\Common\System\Text\StringBuilderCache.cs - - - Common\System\HexConverter.cs - + + + + + + + + + + + + - - ProductionCode\System\Net\SocketException.cs - - - ProductionCode\Common\System\Net\ByteOrder.cs - - - ProductionCode\Common\System\Net\InternalException.cs - - - ProductionCode\Common\System\Net\IPAddressParserStatics.cs - - - ProductionCode\Common\System\Net\TcpValidationHelpers.cs - - - ProductionCode\Common\System\NotImplemented.cs - - - ProductionCode\Common\Interop\Windows\WinSock\Interop.ErrorCodes.cs - + + + + + + + - - ProductionCode\System\Net\SocketException.Windows.cs - - - Common\System\Net\SocketAddressPal.Windows.cs - - - Common\System\Net\NetworkInformation\HostInformationPal.Windows.cs - - - Common\Interop\Windows\IpHlpApi\Interop.ErrorCodes.cs - - - Common\Interop\Windows\IpHlpApi\Interop.FIXED_INFO.cs - - - Common\Interop\Windows\IpHlpApi\Interop.GetNetworkParams.cs - - - Common\Interop\Windows\IpHlpApi\Interop.IP_ADDR_STRING.cs - - - ProductionCode\Common\Interop\Windows\Interop.Libraries.cs - - - ProductionCode\Common\Interop\Windows\NtDll\Interop.NtStatus.cs - - - ProductionCode\System\Net\NetworkInformation\InterfaceInfoPal.Windows.cs - - - ProductionCode\Common\Interop\Windows\IpHlpApi\Interop.if_nametoindex.cs - + + + + + + + + + + + - - ProductionCode\System\Net\SocketException.Unix.cs - - - Common\System\Net\NetworkInformation\HostInformationPal.Unix.cs - - - Common\System\Net\SocketAddressPal.Unix.cs - - - Common\System\Net\Sockets\SocketErrorPal.Unix.cs - - - ProductionCode\Common\Interop\Interop.CheckedAccess.cs - - - ProductionCode\Interop\Unix\Interop.Errors.cs - - - ProductionCode\Common\Interop\Unix\Interop.Libraries.cs - - - ProductionCode\Common\Interop\Unix\System.Native\Interop.GetDomainName.cs - - - ProductionCode\Common\Interop\Unix\System.Native\Interop.GetHostName.cs - - - ProductionCode\Common\Interop\Unix\System.Native\Interop.GetNameInfo.cs - - - ProductionCode\Common\Interop\Unix\System.Native\Interop.HostEntry.cs - - - ProductionCode\Common\Interop\Unix\System.Native\Interop.IPAddress.cs - - - ProductionCode\Common\Interop\Unix\System.Native\Interop.SocketAddress.cs - - - ProductionCode\Common\System\Net\NetworkInformation\InterfaceInfoPal.Unix.cs - - - ProductionCode\Common\Interop\Unix\System.Native\Interop.InterfaceNameToIndex.cs - + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/libraries/System.Net.Primitives/tests/UnitTests/CookieContainerTest.cs b/src/libraries/System.Net.Primitives/tests/UnitTests/CookieContainerTest.cs index d3ce1f523d0ecc..7bd84309abf0ce 100644 --- a/src/libraries/System.Net.Primitives/tests/UnitTests/CookieContainerTest.cs +++ b/src/libraries/System.Net.Primitives/tests/UnitTests/CookieContainerTest.cs @@ -486,7 +486,7 @@ public void Ctor_Capacity_Success() [Fact] public void Ctor_Capacity_Invalid() { - AssertExtensions.Throws("Capacity", () => new CookieContainer(0)); // Capacity <= 0 + AssertExtensions.Throws("capacity", () => new CookieContainer(0)); // Capacity <= 0 } [Fact] @@ -595,7 +595,7 @@ public void Add_Cookie_Invalid() { CookieContainer cc = new CookieContainer(); Assert.Throws(() => cc.Add((Cookie)null)); // Null cookie - AssertExtensions.Throws("cookie.Domain", () => cc.Add(new Cookie("name", "value", "", ""))); // Empty domain + AssertExtensions.Throws("cookie", () => cc.Add(new Cookie("name", "value", "", ""))); // Empty domain cc.MaxCookieSize = 1; Assert.Throws(() => cc.Add(new Cookie("name", "long-text", "", "contoso.com"))); // Value.Length > MaxCookieSize @@ -625,11 +625,11 @@ public void Capacity_ShrinkNoneExpired_RemovesAll() [Fact] public void Ctor_CapacityPerDomainCapacityMaxCookieSize_Invalid() { - AssertExtensions.Throws("Capacity", () => new CookieContainer(0, 10, 5)); // Capacity <= 0 + AssertExtensions.Throws("capacity", () => new CookieContainer(0, 10, 5)); // Capacity <= 0 Assert.Throws(() => new CookieContainer(5, 0, 5)); // Per domain capacity <= 0 Assert.Throws(() => new CookieContainer(5, 10, 5)); // Per domain capacity > Capacity - AssertExtensions.Throws("MaxCookieSize", () => new CookieContainer(15, 10, 0)); // Max cookie size <= 0 + AssertExtensions.Throws("maxCookieSize", () => new CookieContainer(15, 10, 0)); // Max cookie size <= 0 } [Fact] diff --git a/src/libraries/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj b/src/libraries/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj index 23430eac94c227..a88f09f865e9ea 100644 --- a/src/libraries/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj +++ b/src/libraries/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj @@ -17,54 +17,38 @@ - - ProductionCode\System\Net\CookieCollection.cs - - - ProductionCode\System\Net\Cookie.cs - - - ProductionCode\System\Net\CookieContainer.cs - - - ProductionCode\System\Net\Sockets\SocketError.cs - - - ProductionCode\System\Net\IPAddress.cs - - - ProductionCode\System\Net\EndPoint.cs - - - ProductionCode\System\Net\Sockets\AddressFamily.cs - - - ProductionCode\System\Net\CookieComparer.cs - - - Common\System\Net\CookieFields.cs - - - ProductionCode\System\Net\CookieParser.cs - - - ProductionCode\System\Net\SocketAddress.cs - - - ProductionCode\System\Net\IPEndPoint.cs - - - ProductionCode\System\Net\SocketException.cs - - - ProductionCode\System\Net\IPAddressParser.cs - - - Common\System\Runtime\CompilerServices\PreserveDependencyAttribute.cs - - - Common\System\HexConverter.cs - + + + + + + + + + + + + + + + + @@ -72,85 +56,60 @@ - - Common\System\StringExtensions.cs - - - ProductionCode\Common\System\Net\ByteOrder.cs - - - ProductionCode\Common\System\Net\HttpKnownHeaderNames.cs - - - ProductionCode\Common\System\Net\IPAddressParserStatics.cs - - - ProductionCode\Common\System\Net\TcpValidationHelpers.cs - - - ProductionCode\Common\System\Net\UriScheme.cs - - - Common\System\Marvin.cs - - - Common\System\Text\StringBuilderCache.cs - + + + + + + + + - - ProductionCode\Common\System\Net\Logging\NetEventSource.Common.cs - - - ProductionCode\Common\System\Net\InternalException.cs - - - ProductionCode\Common\System\NotImplemented.cs - - - ProductionCode\Common\Interop\Windows\WinSock\Interop.ErrorCodes.cs - + + + + - - ProductionCode\System\Net\SocketException.Unix.cs - - - Common\System\Net\SocketAddressPal.Windows.cs - - - ProductionCode\System\Net\NetworkInformation\InterfaceInfoPal.Windows.cs - - - ProductionCode\Common\Interop\Windows\IpHlpApi\Interop.if_nametoindex.cs - - - ProductionCode\Common\Interop\Windows\Interop.Libraries.cs - + + + + + - - ProductionCode\System\Net\SocketException.Unix.cs - - - ProductionCode\System\Net\NetworkInformation\InterfaceInfoPal.Unix.cs - - - Common\System\Net\SocketAddressPal.Unix.cs - - - ProductionCode\Common\System\Net\Sockets\SocketErrorPal.Unix.cs - - - ProductionCode\Common\Interop\Unix\Interop.Libraries.cs - - - ProductionCode\Interop\Unix\Interop.Errors.cs - - - ProductionCode\Common\Interop\Unix\System.Native\Interop.SocketAddress.cs - - - ProductionCode\Common\Interop\Unix\System.Native\Interop.InterfaceNameToIndex.cs - + + + + + + + + \ No newline at end of file diff --git a/src/libraries/System.Net.Requests/src/System.Net.Requests.csproj b/src/libraries/System.Net.Requests/src/System.Net.Requests.csproj index 63f1a993667655..8b748818b3a0e8 100644 --- a/src/libraries/System.Net.Requests/src/System.Net.Requests.csproj +++ b/src/libraries/System.Net.Requests/src/System.Net.Requests.csproj @@ -43,62 +43,43 @@ - - Common\System\Net\Http\HttpHandlerDefaults.cs - - - Common\System\Net\InternalException.cs - - - Common\System\Net\Logging\NetEventSource.Common.cs - - - Common\System\Net\Logging\DebugThreadTracking.cs - - - Common\System\Net\HttpDateParser.cs - - - Common\System\Net\HttpKnownHeaderNames.cs - - - Common\System\Net\HttpValidationHelpers.cs - - - Common\System\Net\LazyAsyncResult.cs - - - Common\System\Net\ContextAwareResult.cs - - - Common\System\Net\ExceptionCheck.cs - - - Common\System\Net\TlsStream.cs - - - Common\System\Net\SecurityProtocol.cs - - - Common\System\NotImplemented.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - + + + + + + + + + + + + + - - Common\Interop\Windows\WinInet\Interop.wininet_errors.cs - - - Common\System\Net\ContextAwareResult.Windows.cs - + + - - Common\System\Net\ContextAwareResult.Unix.cs - + @@ -124,4 +105,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs b/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs index f36b48483d54a6..3cd68e4ad068b5 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs @@ -595,7 +595,7 @@ protected override PipelineEntry[] BuildCommandsList(WebRequest req) if (request.MethodInfo.Operation == FtpOperation.Rename) { - string baseDir = (requestDirectory == string.Empty) + string baseDir = (requestDirectory.Length == 0) ? string.Empty : requestDirectory + "/"; commandList.Add(new PipelineEntry(FormatFtpCommand("RNFR", baseDir + requestFilename), flags)); diff --git a/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs b/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs index ca3d4a671af2b4..33a7936c63344b 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs @@ -439,49 +439,42 @@ public string? TransferEncoding } set { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) + bool fChunked; + // + // on blank string, remove current header + // + if (string.IsNullOrWhiteSpace(value)) { -#endif - bool fChunked; // - // on blank string, remove current header + // if the value is blank, then remove the header // - if (string.IsNullOrWhiteSpace(value)) - { - // - // if the value is blank, then remove the header - // - _webHeaderCollection.Remove(HttpKnownHeaderNames.TransferEncoding); - return; - } + _webHeaderCollection.Remove(HttpKnownHeaderNames.TransferEncoding); + return; + } - // - // if not check if the user is trying to set chunked: - // - fChunked = (value.IndexOf(ChunkedHeader, StringComparison.OrdinalIgnoreCase) != -1); + // + // if not check if the user is trying to set chunked: + // + fChunked = (value.IndexOf(ChunkedHeader, StringComparison.OrdinalIgnoreCase) != -1); - // - // prevent them from adding chunked, or from adding an Encoding without - // turning on chunked, the reason is due to the HTTP Spec which prevents - // additional encoding types from being used without chunked - // - if (fChunked) - { - throw new ArgumentException(SR.net_nochunked, nameof(value)); - } - else if (!SendChunked) - { - throw new InvalidOperationException(SR.net_needchunked); - } - else - { - string checkedValue = HttpValidationHelpers.CheckBadHeaderValueChars(value); - _webHeaderCollection[HttpKnownHeaderNames.TransferEncoding] = checkedValue; - } -#if DEBUG + // + // prevent them from adding chunked, or from adding an Encoding without + // turning on chunked, the reason is due to the HTTP Spec which prevents + // additional encoding types from being used without chunked + // + if (fChunked) + { + throw new ArgumentException(SR.net_nochunked, nameof(value)); + } + else if (!SendChunked) + { + throw new InvalidOperationException(SR.net_needchunked); + } + else + { + string checkedValue = HttpValidationHelpers.CheckBadHeaderValueChars(value); + _webHeaderCollection[HttpKnownHeaderNames.TransferEncoding] = checkedValue; } -#endif } } @@ -587,42 +580,35 @@ public string? Connection } set { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) - { -#endif - bool fKeepAlive; - bool fClose; + bool fKeepAlive; + bool fClose; - // - // on blank string, remove current header - // - if (string.IsNullOrWhiteSpace(value)) - { - _webHeaderCollection.Remove(HttpKnownHeaderNames.Connection); - return; - } + // + // on blank string, remove current header + // + if (string.IsNullOrWhiteSpace(value)) + { + _webHeaderCollection.Remove(HttpKnownHeaderNames.Connection); + return; + } - fKeepAlive = (value.IndexOf("keep-alive", StringComparison.OrdinalIgnoreCase) != -1); - fClose = (value.IndexOf("close", StringComparison.OrdinalIgnoreCase) != -1); + fKeepAlive = (value.IndexOf("keep-alive", StringComparison.OrdinalIgnoreCase) != -1); + fClose = (value.IndexOf("close", StringComparison.OrdinalIgnoreCase) != -1); - // - // Prevent keep-alive and close from being added - // + // + // Prevent keep-alive and close from being added + // - if (fKeepAlive || - fClose) - { - throw new ArgumentException(SR.net_connarg, nameof(value)); - } - else - { - string checkedValue = HttpValidationHelpers.CheckBadHeaderValueChars(value); - _webHeaderCollection[HttpKnownHeaderNames.Connection] = checkedValue; - } -#if DEBUG + if (fKeepAlive || + fClose) + { + throw new ArgumentException(SR.net_connarg, nameof(value)); + } + else + { + string checkedValue = HttpValidationHelpers.CheckBadHeaderValueChars(value); + _webHeaderCollection[HttpKnownHeaderNames.Connection] = checkedValue; } -#endif } } @@ -644,41 +630,34 @@ public string? Expect } set { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) - { -#endif - // only remove everything other than 100-cont - bool fContinue100; + // only remove everything other than 100-cont + bool fContinue100; - // - // on blank string, remove current header - // + // + // on blank string, remove current header + // - if (string.IsNullOrWhiteSpace(value)) - { - _webHeaderCollection.Remove(HttpKnownHeaderNames.Expect); - return; - } + if (string.IsNullOrWhiteSpace(value)) + { + _webHeaderCollection.Remove(HttpKnownHeaderNames.Expect); + return; + } - // - // Prevent 100-continues from being added - // + // + // Prevent 100-continues from being added + // - fContinue100 = (value.IndexOf(ContinueHeader, StringComparison.OrdinalIgnoreCase) != -1); + fContinue100 = (value.IndexOf(ContinueHeader, StringComparison.OrdinalIgnoreCase) != -1); - if (fContinue100) - { - throw new ArgumentException(SR.net_no100, nameof(value)); - } - else - { - string checkedValue = HttpValidationHelpers.CheckBadHeaderValueChars(value); - _webHeaderCollection[HttpKnownHeaderNames.Expect] = checkedValue; - } -#if DEBUG + if (fContinue100) + { + throw new ArgumentException(SR.net_no100, nameof(value)); + } + else + { + string checkedValue = HttpValidationHelpers.CheckBadHeaderValueChars(value); + _webHeaderCollection[HttpKnownHeaderNames.Expect] = checkedValue; } -#endif } } @@ -1435,42 +1414,28 @@ private bool IsWellKnownContentHeader(string header) private DateTime GetDateHeaderHelper(string headerName) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) - { -#endif - string? headerValue = _webHeaderCollection[headerName]; + string? headerValue = _webHeaderCollection[headerName]; - if (headerValue == null) - { - return DateTime.MinValue; // MinValue means header is not present - } - if (HttpDateParser.TryParse(headerValue, out DateTimeOffset dateTimeOffset)) - { - return dateTimeOffset.LocalDateTime; - } - else - { - throw new ProtocolViolationException(SR.net_baddate); - } -#if DEBUG + if (headerValue == null) + { + return DateTime.MinValue; // MinValue means header is not present + } + if (HttpDateParser.TryParse(headerValue, out DateTimeOffset dateTimeOffset)) + { + return dateTimeOffset.LocalDateTime; + } + else + { + throw new ProtocolViolationException(SR.net_baddate); } -#endif } private void SetDateHeaderHelper(string headerName, DateTime dateTime) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) - { -#endif - if (dateTime == DateTime.MinValue) - SetSpecialHeaders(headerName, null); // remove header - else - SetSpecialHeaders(headerName, HttpDateParser.DateToString(dateTime.ToUniversalTime())); -#if DEBUG - } -#endif + if (dateTime == DateTime.MinValue) + SetSpecialHeaders(headerName, null); // remove header + else + SetSpecialHeaders(headerName, HttpDateParser.DateToString(dateTime.ToUniversalTime())); } private bool TryGetHostUri(string hostName, [NotNullWhen(true)] out Uri? hostUri) diff --git a/src/libraries/System.Net.Requests/src/System/Net/TimerThread.cs b/src/libraries/System.Net.Requests/src/System/Net/TimerThread.cs index a64a6ca5775dbf..8024ce1d4d5bf2 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/TimerThread.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/TimerThread.cs @@ -485,140 +485,133 @@ private static void Prod() private static void ThreadProc() { if (NetEventSource.IsEnabled) NetEventSource.Enter(null); -#if DEBUG - DebugThreadTracking.SetThreadSource(ThreadKinds.Timer); - using (DebugThreadTracking.SetThreadKind(ThreadKinds.System | ThreadKinds.Async)) + + // Set this thread as a background thread. On AppDomain/Process shutdown, the thread will just be killed. + Thread.CurrentThread.IsBackground = true; + + // Keep a permanent lock on s_Queues. This lets for example Shutdown() know when this thread isn't running. + lock (s_queues) { -#endif - // Set this thread as a background thread. On AppDomain/Process shutdown, the thread will just be killed. - Thread.CurrentThread.IsBackground = true; + // If shutdown was recently called, abort here. + if (Interlocked.CompareExchange(ref s_threadState, (int)TimerThreadState.Running, (int)TimerThreadState.Running) != + (int)TimerThreadState.Running) + { + return; + } - // Keep a permanent lock on s_Queues. This lets for example Shutdown() know when this thread isn't running. - lock (s_queues) + bool running = true; + while (running) { - // If shutdown was recently called, abort here. - if (Interlocked.CompareExchange(ref s_threadState, (int)TimerThreadState.Running, (int)TimerThreadState.Running) != - (int)TimerThreadState.Running) + try { - return; - } + s_threadReadyEvent.Reset(); - bool running = true; - while (running) - { - try + while (true) { - s_threadReadyEvent.Reset(); - - while (true) + // Copy all the new queues to the real queues. Since only this thread modifies the real queues, it doesn't have to lock it. + if (s_newQueues.Count > 0) { - // Copy all the new queues to the real queues. Since only this thread modifies the real queues, it doesn't have to lock it. - if (s_newQueues.Count > 0) + lock (s_newQueues) { - lock (s_newQueues) + for (LinkedListNode? node = s_newQueues.First; node != null; node = s_newQueues.First) { - for (LinkedListNode? node = s_newQueues.First; node != null; node = s_newQueues.First) - { - s_newQueues.Remove(node); - s_queues.AddLast(node); - } + s_newQueues.Remove(node); + s_queues.AddLast(node); } } + } - int now = Environment.TickCount; - int nextTick = 0; - bool haveNextTick = false; - for (LinkedListNode? node = s_queues.First; node != null; /* node = node.Next must be done in the body */) + int now = Environment.TickCount; + int nextTick = 0; + bool haveNextTick = false; + for (LinkedListNode? node = s_queues.First; node != null; /* node = node.Next must be done in the body */) + { + TimerQueue? queue = (TimerQueue?)node.Value.Target; + if (queue == null) { - TimerQueue? queue = (TimerQueue?)node.Value.Target; - if (queue == null) - { - LinkedListNode? next = node.Next; - s_queues.Remove(node); - node = next; - continue; - } - - // Fire() will always return values that should be interpreted as later than 'now' (that is, even if 'now' is - // returned, it is 0x100000000 milliseconds in the future). There's also a chance that Fire() will return a value - // intended as > 0x100000000 milliseconds from 'now'. Either case will just cause an extra scan through the timers. - int nextTickInstance; - if (queue.Fire(out nextTickInstance) && (!haveNextTick || IsTickBetween(now, nextTick, nextTickInstance))) - { - nextTick = nextTickInstance; - haveNextTick = true; - } + LinkedListNode? next = node.Next; + s_queues.Remove(node); + node = next; + continue; + } - node = node.Next; + // Fire() will always return values that should be interpreted as later than 'now' (that is, even if 'now' is + // returned, it is 0x100000000 milliseconds in the future). There's also a chance that Fire() will return a value + // intended as > 0x100000000 milliseconds from 'now'. Either case will just cause an extra scan through the timers. + int nextTickInstance; + if (queue.Fire(out nextTickInstance) && (!haveNextTick || IsTickBetween(now, nextTick, nextTickInstance))) + { + nextTick = nextTickInstance; + haveNextTick = true; } - // Figure out how long to wait, taking into account how long the loop took. - // Add 15 ms to compensate for poor TickCount resolution (want to guarantee a firing). - int newNow = Environment.TickCount; - int waitDuration = haveNextTick ? - (int)(IsTickBetween(now, nextTick, newNow) ? - Math.Min(unchecked((uint)(nextTick - newNow)), (uint)(int.MaxValue - TickCountResolution)) + TickCountResolution : - 0) : - ThreadIdleTimeoutMilliseconds; + node = node.Next; + } - if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"Waiting for {waitDuration}ms"); + // Figure out how long to wait, taking into account how long the loop took. + // Add 15 ms to compensate for poor TickCount resolution (want to guarantee a firing). + int newNow = Environment.TickCount; + int waitDuration = haveNextTick ? + (int)(IsTickBetween(now, nextTick, newNow) ? + Math.Min(unchecked((uint)(nextTick - newNow)), (uint)(int.MaxValue - TickCountResolution)) + TickCountResolution : + 0) : + ThreadIdleTimeoutMilliseconds; - int waitResult = WaitHandle.WaitAny(s_threadEvents, waitDuration, false); + if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"Waiting for {waitDuration}ms"); - // 0 is s_ThreadShutdownEvent - die. - if (waitResult == 0) - { - if (NetEventSource.IsEnabled) NetEventSource.Info(null, "Awoke, cause: Shutdown"); - running = false; - break; - } + int waitResult = WaitHandle.WaitAny(s_threadEvents, waitDuration, false); + + // 0 is s_ThreadShutdownEvent - die. + if (waitResult == 0) + { + if (NetEventSource.IsEnabled) NetEventSource.Info(null, "Awoke, cause: Shutdown"); + running = false; + break; + } - if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"Awoke, cause {(waitResult == WaitHandle.WaitTimeout ? "Timeout" : "Prod")}"); + if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"Awoke, cause {(waitResult == WaitHandle.WaitTimeout ? "Timeout" : "Prod")}"); - // If we timed out with nothing to do, shut down. - if (waitResult == WaitHandle.WaitTimeout && !haveNextTick) + // If we timed out with nothing to do, shut down. + if (waitResult == WaitHandle.WaitTimeout && !haveNextTick) + { + Interlocked.CompareExchange(ref s_threadState, (int)TimerThreadState.Idle, (int)TimerThreadState.Running); + // There could have been one more prod between the wait and the exchange. Check, and abort if necessary. + if (s_threadReadyEvent.WaitOne(0, false)) { - Interlocked.CompareExchange(ref s_threadState, (int)TimerThreadState.Idle, (int)TimerThreadState.Running); - // There could have been one more prod between the wait and the exchange. Check, and abort if necessary. - if (s_threadReadyEvent.WaitOne(0, false)) + if (Interlocked.CompareExchange(ref s_threadState, (int)TimerThreadState.Running, (int)TimerThreadState.Idle) == + (int)TimerThreadState.Idle) { - if (Interlocked.CompareExchange(ref s_threadState, (int)TimerThreadState.Running, (int)TimerThreadState.Idle) == - (int)TimerThreadState.Idle) - { - continue; - } + continue; } - - running = false; - break; } + + running = false; + break; } } - catch (Exception exception) - { - if (ExceptionCheck.IsFatal(exception)) - throw; + } + catch (Exception exception) + { + if (ExceptionCheck.IsFatal(exception)) + throw; - if (NetEventSource.IsEnabled) NetEventSource.Error(null, exception); + if (NetEventSource.IsEnabled) NetEventSource.Error(null, exception); - // The only options are to continue processing and likely enter an error-loop, - // shut down timers for this AppDomain, or shut down the AppDomain. Go with shutting - // down the AppDomain in debug, and going into a loop in retail, but try to make the - // loop somewhat slow. Note that in retail, this can only be triggered by OutOfMemory or StackOverflow, - // or an exception thrown within TimerThread - the rest are caught in Fire(). + // The only options are to continue processing and likely enter an error-loop, + // shut down timers for this AppDomain, or shut down the AppDomain. Go with shutting + // down the AppDomain in debug, and going into a loop in retail, but try to make the + // loop somewhat slow. Note that in retail, this can only be triggered by OutOfMemory or StackOverflow, + // or an exception thrown within TimerThread - the rest are caught in Fire(). #if !DEBUG - Thread.Sleep(1000); + Thread.Sleep(1000); #else - throw; + throw; #endif - } } } - - if (NetEventSource.IsEnabled) NetEventSource.Info(null, "Stop"); -#if DEBUG } -#endif + + if (NetEventSource.IsEnabled) NetEventSource.Info(null, "Stop"); } /// diff --git a/src/libraries/System.Net.Requests/tests/System.Net.Requests.Tests.csproj b/src/libraries/System.Net.Requests/tests/System.Net.Requests.Tests.csproj index d10fd19dfe020d..e0c47d0262bdbf 100644 --- a/src/libraries/System.Net.Requests/tests/System.Net.Requests.Tests.csproj +++ b/src/libraries/System.Net.Requests/tests/System.Net.Requests.Tests.csproj @@ -11,33 +11,24 @@ - - Common\System\Net\Capability.Security.cs - - - Common\System\Net\Configuration.cs - - - Common\System\Net\Configuration.Certificates.cs - - - Common\System\Net\Configuration.Http.cs - - - Common\System\Net\Configuration.Security.cs - - - Common\System\Net\Http\LoopbackServer.cs - - - Common\System\Net\Http\LoopbackServer.AuthenticationHelpers.cs - - - Common\System\Net\Http\GenericLoopbackServer.cs - - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - + + + + + + + + + @@ -52,4 +43,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Net.Security/ref/System.Net.Security.cs b/src/libraries/System.Net.Security/ref/System.Net.Security.cs index c022960def9c77..d657bb1fd59d79 100644 --- a/src/libraries/System.Net.Security/ref/System.Net.Security.cs +++ b/src/libraries/System.Net.Security/ref/System.Net.Security.cs @@ -91,9 +91,13 @@ public override void EndWrite(System.IAsyncResult asyncResult) { } public override void Flush() { } public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) { throw null; } public override int Read(byte[] buffer, int offset, int count) { throw null; } + public override System.Threading.Tasks.Task ReadAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; } + public override System.Threading.Tasks.ValueTask ReadAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken = default) { throw null; } public override long Seek(long offset, System.IO.SeekOrigin origin) { throw null; } public override void SetLength(long value) { } public override void Write(byte[] buffer, int offset, int count) { } + public override System.Threading.Tasks.Task WriteAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; } + public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken = default) { throw null; } } public enum ProtectionLevel { @@ -182,6 +186,7 @@ public partial class SslStream : System.Net.Security.AuthenticatedStream public virtual System.Security.Authentication.SslProtocols SslProtocol { get { throw null; } } public System.Net.TransportContext TransportContext { get { throw null; } } public override int WriteTimeout { get { throw null; } set { } } + public void AuthenticateAsClient(System.Net.Security.SslClientAuthenticationOptions sslClientAuthenticationOptions) { } public virtual void AuthenticateAsClient(string targetHost) { } public virtual void AuthenticateAsClient(string targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection? clientCertificates, bool checkCertificateRevocation) { } public virtual void AuthenticateAsClient(string targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection? clientCertificates, System.Security.Authentication.SslProtocols enabledSslProtocols, bool checkCertificateRevocation) { } @@ -189,6 +194,7 @@ public virtual void AuthenticateAsClient(string targetHost, System.Security.Cryp public virtual System.Threading.Tasks.Task AuthenticateAsClientAsync(string targetHost) { throw null; } public virtual System.Threading.Tasks.Task AuthenticateAsClientAsync(string targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection? clientCertificates, bool checkCertificateRevocation) { throw null; } public virtual System.Threading.Tasks.Task AuthenticateAsClientAsync(string targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection? clientCertificates, System.Security.Authentication.SslProtocols enabledSslProtocols, bool checkCertificateRevocation) { throw null; } + public void AuthenticateAsServer(System.Net.Security.SslServerAuthenticationOptions sslServerAuthenticationOptions) { } public virtual void AuthenticateAsServer(System.Security.Cryptography.X509Certificates.X509Certificate serverCertificate) { } public virtual void AuthenticateAsServer(System.Security.Cryptography.X509Certificates.X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation) { } public virtual void AuthenticateAsServer(System.Security.Cryptography.X509Certificates.X509Certificate serverCertificate, bool clientCertificateRequired, System.Security.Authentication.SslProtocols enabledSslProtocols, bool checkCertificateRevocation) { } @@ -210,6 +216,7 @@ public virtual void EndAuthenticateAsClient(System.IAsyncResult asyncResult) { } public virtual void EndAuthenticateAsServer(System.IAsyncResult asyncResult) { } public override int EndRead(System.IAsyncResult asyncResult) { throw null; } public override void EndWrite(System.IAsyncResult asyncResult) { } + ~SslStream() { } public override void Flush() { } public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) { throw null; } public override int Read(byte[] buffer, int offset, int count) { throw null; } diff --git a/src/libraries/System.Net.Security/src/Resources/Strings.resx b/src/libraries/System.Net.Security/src/Resources/Strings.resx index 7270ea80faefdc..8af05ebe134c8d 100644 --- a/src/libraries/System.Net.Security/src/Resources/Strings.resx +++ b/src/libraries/System.Net.Security/src/Resources/Strings.resx @@ -212,6 +212,9 @@ Authentication failed because the remote party has closed the transport stream. + + Authentication failed because the remote party sent a TLS alert: '{0}'. + Authentication failed on the remote side (the stream might still be available for additional authentication attempts). 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 dbf541c0f4a3da..73d613dfa729d5 100644 --- a/src/libraries/System.Net.Security/src/System.Net.Security.csproj +++ b/src/libraries/System.Net.Security/src/System.Net.Security.csproj @@ -12,101 +12,75 @@ - - + + + + + + + - - - - - - - + - - - - - Common\System\Net\Logging\DebugThreadTracking.cs - - - Common\System\Net\Logging\NetEventSource.Common.cs - - - Common\System\Net\InternalException.cs - + + - - Common\System\Net\DebugSafeHandle.cs - - - Common\System\Net\DebugCriticalHandleMinusOneIsInvalid.cs - - - Common\System\Net\DebugCriticalHandleZeroOrMinusOneIsInvalid.cs - + + + Common\System\Net\ArrayBuffer.cs - - Common\System\Net\ExceptionCheck.cs - - - Common\System\Net\LazyAsyncResult.cs - - - Common\System\Net\SecurityProtocol.cs - - - Common\System\Net\UriScheme.cs - + + + - - Common\System\NotImplemented.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - - - Common\System\Net\Security\SSPIHandleCache.cs - - - Common\System\Net\ContextFlagsPal.cs - - - Common\System\Net\NegotiationInfoClass.cs - - - Common\System\Net\NTAuthentication.Common.cs - - - Common\System\Net\SecurityStatusPal.cs - - - Common\System\HexConverter.cs - + + + + + + + + @@ -155,166 +129,114 @@ - - Common\System\Net\Security\SecurityBuffer.Windows.cs - - - Common\System\Net\Security\SecurityBufferType.Windows.cs - + + - - Common\System\Net\SecurityStatusAdapterPal.Windows.cs - - - Common\System\Net\ContextFlagsAdapterPal.Windows.cs - - - Common\System\Net\Security\NegotiateStreamPal.Windows.cs - - - Common\System\Net\Security\SecurityContextTokenHandle.cs - + + + + - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates_types.cs - - - Common\Interop\Windows\Crypt32\Interop.CertEnumCertificatesInStore.cs - - - Common\Interop\Windows\Kernel32\Interop.CloseHandle.cs - - - Common\Interop\Windows\SChannel\Interop.Alerts.cs - - - Common\Interop\Windows\SChannel\Interop.SchProtocols.cs - - - Common\Interop\Windows\SChannel\Interop.SECURITY_STATUS.cs - - - Common\Interop\Windows\SChannel\SecPkgContext_ConnectionInfo.cs - - - Common\Interop\Windows\SChannel\SecPkgContext_CipherInfo.cs - - - Common\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs - - - Common\Interop\Windows\SChannel\Interop.Sec_Application_Protocols.cs - - - Common\Interop\Windows\SChannel\UnmanagedCertificateContext.cs - - - Common\Interop\Windows\SChannel\UnmanagedCertificateContext.IntPtr.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_Bindings.cs - - - Common\Interop\Windows\SspiCli\GlobalSSPI.cs - - - Common\Interop\Windows\SspiCli\Interop.SSPI.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_NegotiationInfoW.cs - - - Common\Interop\Windows\SspiCli\NegotiationInfoClass.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_Sizes.cs - - - Common\System\Collections\Generic\BidirectionalDictionary.cs - - - Common\Interop\Windows\SspiCli\SafeDeleteContext.cs - - - Common\Interop\Windows\SspiCli\SecurityPackageInfo.cs - - - Common\Interop\Windows\SspiCli\SecurityPackageInfoClass.cs - - - Common\Interop\Windows\SspiCli\SecuritySafeHandles.cs - - - Common\Interop\Windows\SspiCli\SSPIAuthType.cs - - - Common\Interop\Windows\SspiCli\ISSPIInterface.cs - - - Common\Interop\Windows\SspiCli\SSPISecureChannelType.cs - - - Common\Interop\Windows\SspiCli\SSPIWrapper.cs - - - Common\Interop\Windows\SspiCli\SecPkgContext_StreamSizes.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\Interop.Errors.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.Initialization.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.GssApiException.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.GssBuffer.cs - - - Common\Microsoft\Win32\SafeHandles\GssSafeHandles.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.IsNtlmInstalled.cs - - - Common\System\Net\ContextFlagsAdapterPal.Unix.cs - - - Common\System\Net\Http\TlsCertificateExtensions.cs - - - Common\System\Net\Security\NegotiateStreamPal.Unix.cs - - - Common\System\Net\Security\Unix\SafeDeleteContext.cs - - - Common\System\Net\Security\Unix\SafeDeleteNegoContext.cs - - - Common\System\Net\Security\Unix\SafeFreeCredentials.cs - - - Common\System\Net\Security\Unix\SafeFreeNegoCredentials.cs - - - Common\System\Net\Security\Unix\SecChannelBindings.cs - + + + + + + + + + + + + + + + + @@ -327,119 +249,82 @@ - - Common\System\Net\Security\CertificateValidation.Unix.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ASN1.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.BIO.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Initialization.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Crypto.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSsl.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Ssl.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.SslCtx.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.SetProtocolOptions.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.SslCtxOptions.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509Name.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509Ext.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509Stack.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509StoreCtx.cs - - - Common\Microsoft\Win32\SafeHandles\SafeX509Handles.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\X509ExtensionSafeHandles.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeInteriorHandle.cs - - - Common\Microsoft\Win32\SafeHandles\SafeBioHandle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeHandleCache.cs - - - Common\System\Net\Security\Unix\SafeDeleteSslContext.cs - - - Common\System\Net\Security\Unix\SafeFreeCertContext.cs - - - Common\System\Net\Security\Unix\SafeFreeSslCredentials.cs - + + + + + + + + + + + + + + + + + + + + + + + + + - - Common\Interop\OSX\Interop.CoreFoundation.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFArray.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFData.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFDate.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFError.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFString.cs - - - Common\Interop\OSX\Interop.Libraries.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.SecErrMessage.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.SslErr.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Ssl.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.X509Chain.cs - - - Common\Microsoft\Win32\SafeHandles\SafeCreateHandle.OSX.cs - + + + + + + + + + + + + diff --git a/src/libraries/System.Net.Security/src/System/Net/FixedSizeReader.cs b/src/libraries/System.Net.Security/src/System/Net/FixedSizeReader.cs deleted file mode 100644 index 3152739f198a7d..00000000000000 --- a/src/libraries/System.Net.Security/src/System/Net/FixedSizeReader.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.IO; -using System.Threading.Tasks; - -namespace System.Net -{ - /// - /// The class is a simple wrapper on top of a read stream. It will read the exact number of bytes requested. - /// It will throw if EOF is reached before the expected number of bytes is returned. - /// - internal static class FixedSizeReader - { - /// - /// Returns 0 on legitimate EOF or if 0 bytes were requested, otherwise reads as directed or throws. - /// Returns count on success. - /// - public static int ReadPacket(Stream transport, byte[] buffer, int offset, int count) - { - int remainingCount = count; - do - { - int bytes = transport.Read(buffer, offset, remainingCount); - if (bytes == 0) - { - if (remainingCount != count) - { - throw new IOException(SR.net_io_eof); - } - - return 0; - } - - remainingCount -= bytes; - offset += bytes; - } while (remainingCount > 0); - - Debug.Assert(remainingCount == 0); - return count; - } - - /// - /// Completes "request" with 0 if 0 bytes was requested or legitimate EOF received. - /// Otherwise, reads as directed or completes "request" with an Exception. - /// - public static async Task ReadPacketAsync(Stream transport, AsyncProtocolRequest request) - { - try - { - int remainingCount = request.Count, offset = request.Offset; - do - { - int bytes = await transport.ReadAsync(new Memory(request.Buffer, offset, remainingCount), request.CancellationToken).ConfigureAwait(false); - if (bytes == 0) - { - if (remainingCount != request.Count) - { - throw new IOException(SR.net_io_eof); - } - request.CompleteRequest(0); - return; - } - - offset += bytes; - remainingCount -= bytes; - } while (remainingCount > 0); - - Debug.Assert(remainingCount == 0); - request.CompleteRequest(request.Count); - } - catch (Exception e) - { - request.CompleteUserWithError(e); - } - } - } -} diff --git a/src/libraries/System.Net.Security/src/System/Net/NTAuthentication.cs b/src/libraries/System.Net.Security/src/System/Net/NTAuthentication.cs index af931677016e75..0f4f7afef338df 100644 --- a/src/libraries/System.Net.Security/src/System/Net/NTAuthentication.cs +++ b/src/libraries/System.Net.Security/src/System/Net/NTAuthentication.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.Net.Security; using System.Security.Authentication.ExtendedProtection; @@ -114,13 +115,11 @@ private static void InitializeCallback(object state) context.ThisPtr.Initialize(context.IsServer, context.Package, context.Credential, context.Spn, context.RequestedContextFlags, context.ChannelBinding); } - internal int Encrypt(byte[] buffer, int offset, int count, ref byte[]? output, uint sequenceNumber) + internal int Encrypt(ReadOnlySpan buffer, [NotNull] ref byte[]? output, uint sequenceNumber) { return NegotiateStreamPal.Encrypt( _securityContext!, buffer, - offset, - count, IsConfidentialityFlag, IsNTLM, ref output, diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/AuthenticatedStream.cs b/src/libraries/System.Net.Security/src/System/Net/Security/AuthenticatedStream.cs index c8c79449d04ec4..9c8eac2d1969d3 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/AuthenticatedStream.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/AuthenticatedStream.cs @@ -47,31 +47,24 @@ protected Stream InnerStream protected override void Dispose(bool disposing) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User)) + try { -#endif - try + if (disposing) { - if (disposing) + if (_leaveStreamOpen) { - if (_leaveStreamOpen) - { - _innerStream.Flush(); - } - else - { - _innerStream.Dispose(); - } + _innerStream.Flush(); + } + else + { + _innerStream.Dispose(); } } - finally - { - base.Dispose(disposing); - } -#if DEBUG } -#endif + finally + { + base.Dispose(disposing); + } } public override ValueTask DisposeAsync() diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/InternalNegotiateStream.cs b/src/libraries/System.Net.Security/src/System/Net/Security/InternalNegotiateStream.cs deleted file mode 100644 index 4c748bd307c29d..00000000000000 --- a/src/libraries/System.Net.Security/src/System/Net/Security/InternalNegotiateStream.cs +++ /dev/null @@ -1,446 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace System.Net.Security -{ - // - // This is a wrapping stream that does data encryption/decryption based on a successfully authenticated SSPI context. - // This file contains the private implementation. - // - public partial class NegotiateStream : AuthenticatedStream - { - private static readonly AsyncCallback s_writeCallback = new AsyncCallback(WriteCallback); - private static readonly AsyncProtocolCallback s_readCallback = new AsyncProtocolCallback(ReadCallback); - - private int _NestedWrite; - private int _NestedRead; - private byte[] _ReadHeader = null!; // will be initialized by ctor helper - - // Never updated directly, special properties are used. - private byte[]? _InternalBuffer; - private int _InternalOffset; - private int _InternalBufferCount; - - private void InitializeStreamPart() - { - _ReadHeader = new byte[4]; - } - - private byte[]? InternalBuffer - { - get - { - return _InternalBuffer; - } - } - - private int InternalOffset - { - get - { - return _InternalOffset; - } - } - - private int InternalBufferCount - { - get - { - return _InternalBufferCount; - } - } - - private void DecrementInternalBufferCount(int decrCount) - { - _InternalOffset += decrCount; - _InternalBufferCount -= decrCount; - } - - private void EnsureInternalBufferSize(int bytes) - { - _InternalBufferCount = bytes; - _InternalOffset = 0; - if (InternalBuffer == null || InternalBuffer.Length < bytes) - { - _InternalBuffer = new byte[bytes]; - } - } - - private void AdjustInternalBufferOffsetSize(int bytes, int offset) - { - _InternalBufferCount = bytes; - _InternalOffset = offset; - } - - // - // Validates user parameters for all Read/Write methods. - // - private void ValidateParameters(byte[] buffer, int offset, int count) - { - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - - if (offset < 0) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - - if (count < 0) - { - throw new ArgumentOutOfRangeException(nameof(count)); - } - - if (count > buffer.Length - offset) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.net_offset_plus_count); - } - } - - // - // Combined sync/async write method. For sync request asyncRequest==null. - // - private void ProcessWrite(byte[] buffer, int offset, int count, AsyncProtocolRequest? asyncRequest) - { - ValidateParameters(buffer, offset, count); - - if (Interlocked.Exchange(ref _NestedWrite, 1) == 1) - { - throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, (asyncRequest != null ? "BeginWrite" : "Write"), "write")); - } - - bool failed = false; - try - { - StartWriting(buffer, offset, count, asyncRequest); - } - catch (Exception e) - { - failed = true; - if (e is IOException) - { - throw; - } - - throw new IOException(SR.net_io_write, e); - } - finally - { - if (asyncRequest == null || failed) - { - _NestedWrite = 0; - } - } - } - - private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest? asyncRequest) - { - // We loop to this method from the callback. - // If the last chunk was just completed from async callback (count < 0), we complete user request. - if (count >= 0) - { - byte[]? outBuffer = null; - do - { - int chunkBytes = Math.Min(count, NegoState.MaxWriteDataSize); - int encryptedBytes; - - try - { - encryptedBytes = _negoState.EncryptData(buffer, offset, chunkBytes, ref outBuffer); - } - catch (Exception e) - { - throw new IOException(SR.net_io_encrypt, e); - } - - if (asyncRequest != null) - { - // prepare for the next request - asyncRequest.SetNextRequest(buffer, offset + chunkBytes, count - chunkBytes, null); - Task t = InnerStream.WriteAsync(outBuffer!, 0, encryptedBytes); - if (t.IsCompleted) - { - t.GetAwaiter().GetResult(); - } - else - { - IAsyncResult ar = TaskToApm.Begin(t, s_writeCallback, asyncRequest); - if (!ar.CompletedSynchronously) - { - return; - } - TaskToApm.End(ar); - } - } - else - { - InnerStream.Write(outBuffer!, 0, encryptedBytes); - } - - offset += chunkBytes; - count -= chunkBytes; - } while (count != 0); - } - - if (asyncRequest != null) - { - asyncRequest.CompleteUser(); - } - } - - // - // Combined sync/async read method. For sync request asyncRequest==null. - // There is a little overhead because we need to pass buffer/offset/count used only in sync. - // Still the benefit is that we have a common sync/async code path. - // - private int ProcessRead(byte[] buffer, int offset, int count, AsyncProtocolRequest? asyncRequest) - { - ValidateParameters(buffer, offset, count); - - if (Interlocked.Exchange(ref _NestedRead, 1) == 1) - { - throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, (asyncRequest != null ? "BeginRead" : "Read"), "read")); - } - - bool failed = false; - try - { - if (InternalBufferCount != 0) - { - int copyBytes = InternalBufferCount > count ? count : InternalBufferCount; - if (copyBytes != 0) - { - Buffer.BlockCopy(InternalBuffer!, InternalOffset, buffer, offset, copyBytes); - DecrementInternalBufferCount(copyBytes); - } - asyncRequest?.CompleteUser(copyBytes); - return copyBytes; - } - - // Performing actual I/O. - return StartReading(buffer, offset, count, asyncRequest); - } - catch (Exception e) - { - failed = true; - if (e is IOException) - { - throw; - } - throw new IOException(SR.net_io_read, e); - } - finally - { - if (asyncRequest == null || failed) - { - _NestedRead = 0; - } - } - } - - // - // To avoid recursion when 0 bytes have been decrypted, loop until decryption results in at least 1 byte. - // - private int StartReading(byte[] buffer, int offset, int count, AsyncProtocolRequest? asyncRequest) - { - int result; - // When we read -1 bytes means we have decrypted 0 bytes, need looping. - while ((result = StartFrameHeader(buffer, offset, count, asyncRequest)) == -1); - - return result; - } - - private int StartFrameHeader(byte[] buffer, int offset, int count, AsyncProtocolRequest? asyncRequest) - { - int readBytes = 0; - if (asyncRequest != null) - { - asyncRequest.SetNextRequest(_ReadHeader, 0, _ReadHeader.Length, s_readCallback); - _ = FixedSizeReader.ReadPacketAsync(InnerStream, asyncRequest); - if (!asyncRequest.MustCompleteSynchronously) - { - return 0; - } - - readBytes = asyncRequest.Result; - } - else - { - readBytes = FixedSizeReader.ReadPacket(InnerStream, _ReadHeader, 0, _ReadHeader.Length); - } - - return StartFrameBody(readBytes, buffer, offset, count, asyncRequest); - } - - private int StartFrameBody(int readBytes, byte[] buffer, int offset, int count, AsyncProtocolRequest? asyncRequest) - { - if (readBytes == 0) - { - //EOF - asyncRequest?.CompleteUser(0); - return 0; - } - - if (!(readBytes == _ReadHeader.Length)) - { - NetEventSource.Fail(this, $"Frame size must be 4 but received {readBytes} bytes."); - } - - // Replace readBytes with the body size recovered from the header content. - readBytes = _ReadHeader[3]; - readBytes = (readBytes << 8) | _ReadHeader[2]; - readBytes = (readBytes << 8) | _ReadHeader[1]; - readBytes = (readBytes << 8) | _ReadHeader[0]; - - // - // The body carries 4 bytes for trailer size slot plus trailer, hence <=4 frame size is always an error. - // Additionally we'd like to restrict the read frame size to 64k. - // - if (readBytes <= 4 || readBytes > NegoState.MaxReadFrameSize) - { - throw new IOException(SR.net_frame_read_size); - } - - // - // Always pass InternalBuffer for SSPI "in place" decryption. - // A user buffer can be shared by many threads in that case decryption/integrity check may fail cause of data corruption. - // - EnsureInternalBufferSize(readBytes); - if (asyncRequest != null) - { - asyncRequest.SetNextRequest(InternalBuffer, 0, readBytes, s_readCallback); - - _ = FixedSizeReader.ReadPacketAsync(InnerStream, asyncRequest); - - if (!asyncRequest.MustCompleteSynchronously) - { - return 0; - } - - readBytes = asyncRequest.Result; - } - else //Sync - { - readBytes = FixedSizeReader.ReadPacket(InnerStream, InternalBuffer!, 0, readBytes); - } - - return ProcessFrameBody(readBytes, buffer, offset, count, asyncRequest); - } - - private int ProcessFrameBody(int readBytes, byte[] buffer, int offset, int count, AsyncProtocolRequest? asyncRequest) - { - if (readBytes == 0) - { - // We already checked that the frame body is bigger than 0 bytes - // Hence, this is an EOF ... fire. - throw new IOException(SR.net_io_eof); - } - - // Decrypt into internal buffer, change "readBytes" to count now _Decrypted Bytes_ - int internalOffset; - readBytes = _negoState.DecryptData(InternalBuffer!, 0, readBytes, out internalOffset); - - // Decrypted data start from zero offset, the size can be shrunk after decryption. - AdjustInternalBufferOffsetSize(readBytes, internalOffset); - - if (readBytes == 0 && count != 0) - { - // Read again. - return -1; - } - - if (readBytes > count) - { - readBytes = count; - } - - Buffer.BlockCopy(InternalBuffer!, InternalOffset, buffer, offset, readBytes); - - // This will adjust both the remaining internal buffer count and the offset. - DecrementInternalBufferCount(readBytes); - - asyncRequest?.CompleteUser(readBytes); - - return readBytes; - } - - private static void WriteCallback(IAsyncResult transportResult) - { - if (transportResult.CompletedSynchronously) - { - return; - } - - if (!(transportResult.AsyncState is AsyncProtocolRequest)) - { - NetEventSource.Fail(transportResult, "State type is wrong, expected AsyncProtocolRequest."); - } - - AsyncProtocolRequest asyncRequest = (AsyncProtocolRequest)transportResult.AsyncState!; - - try - { - NegotiateStream negoStream = (NegotiateStream)asyncRequest.AsyncObject!; - TaskToApm.End(transportResult); - if (asyncRequest.Count == 0) - { - // This was the last chunk. - asyncRequest.Count = -1; - } - - negoStream.StartWriting(asyncRequest.Buffer!, asyncRequest.Offset, asyncRequest.Count, asyncRequest); - } - catch (Exception e) - { - if (asyncRequest.IsUserCompleted) - { - // This will throw on a worker thread. - throw; - } - - asyncRequest.CompleteUserWithError(e); - } - } - - private static void ReadCallback(AsyncProtocolRequest asyncRequest) - { - // Async ONLY completion. - try - { - NegotiateStream negoStream = (NegotiateStream)asyncRequest.AsyncObject!; - BufferAsyncResult bufferResult = (BufferAsyncResult)asyncRequest.UserAsyncResult; - - // This is an optimization to avoid an additional callback. - if ((object?)asyncRequest.Buffer == (object?)negoStream._ReadHeader) - { - negoStream.StartFrameBody(asyncRequest.Result, bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest); - } - else - { - if (-1 == negoStream.ProcessFrameBody(asyncRequest.Result, bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest)) - { - // In case we decrypted 0 bytes, start another reading. - negoStream.StartReading(bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest); - } - } - } - catch (Exception e) - { - if (asyncRequest.IsUserCompleted) - { - // This will throw on a worker thread. - throw; - } - - asyncRequest.CompleteUserWithError(e); - } - } - } -} diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/NegoState.cs b/src/libraries/System.Net.Security/src/System/Net/Security/NegoState.cs deleted file mode 100644 index b59ffb97692ca1..00000000000000 --- a/src/libraries/System.Net.Security/src/System/Net/Security/NegoState.cs +++ /dev/null @@ -1,840 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.IO; -using System.Security.Principal; -using System.Threading; -using System.ComponentModel; -using System.Runtime.ExceptionServices; -using System.Security.Authentication; -using System.Security.Authentication.ExtendedProtection; - -namespace System.Net.Security -{ - // - // The class maintains the state of the authentication process and the security context. - // It encapsulates security context and does the real work in authentication and - // user data encryption - // - internal class NegoState - { -#pragma warning disable CA1825 // used in reference comparison, requires unique object identity - private static readonly byte[] s_emptyMessage = new byte[0]; -#pragma warning restore CA1825 - private static readonly AsyncCallback s_readCallback = new AsyncCallback(ReadCallback); - private static readonly AsyncCallback s_writeCallback = new AsyncCallback(WriteCallback); - - private readonly Stream _innerStream; - - private Exception? _exception; - - private StreamFramer? _framer; - private NTAuthentication? _context; - - private int _nestedAuth; - - internal const int ERROR_TRUST_FAILURE = 1790; // Used to serialize protectionLevel or impersonationLevel mismatch error to the remote side. - internal const int MaxReadFrameSize = 64 * 1024; - internal const int MaxWriteDataSize = 63 * 1024; // 1k for the framing and trailer that is always less as per SSPI. - - private bool _canRetryAuthentication; - private ProtectionLevel _expectedProtectionLevel; - private TokenImpersonationLevel _expectedImpersonationLevel; - private uint _writeSequenceNumber; - private uint _readSequenceNumber; - - private ExtendedProtectionPolicy? _extendedProtectionPolicy; - - // SSPI does not send a server ack on successful auth. - // This is a state variable used to gracefully handle auth confirmation. - private bool _remoteOk = false; - - internal NegoState(Stream innerStream) - { - Debug.Assert(innerStream != null); - - _innerStream = innerStream; - } - - internal static string DefaultPackage - { - get - { - return NegotiationInfoClass.Negotiate; - } - } - - internal IIdentity GetIdentity() - { - CheckThrow(true); - return NegotiateStreamPal.GetIdentity(_context!); - } - - internal void ValidateCreateContext( - string package, - NetworkCredential credential, - string servicePrincipalName, - ExtendedProtectionPolicy? policy, - ProtectionLevel protectionLevel, - TokenImpersonationLevel impersonationLevel) - { - if (policy != null) - { - // One of these must be set if EP is turned on - if (policy.CustomChannelBinding == null && policy.CustomServiceNames == null) - { - throw new ArgumentException(SR.net_auth_must_specify_extended_protection_scheme, nameof(policy)); - } - - _extendedProtectionPolicy = policy; - } - else - { - _extendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Never); - } - - ValidateCreateContext(package, true, credential, servicePrincipalName, _extendedProtectionPolicy!.CustomChannelBinding, protectionLevel, impersonationLevel); - } - - internal void ValidateCreateContext( - string package, - bool isServer, - NetworkCredential credential, - string? servicePrincipalName, - ChannelBinding? channelBinding, - ProtectionLevel protectionLevel, - TokenImpersonationLevel impersonationLevel) - { - if (_exception != null && !_canRetryAuthentication) - { - ExceptionDispatchInfo.Throw(_exception); - } - - if (_context != null && _context.IsValidContext) - { - throw new InvalidOperationException(SR.net_auth_reauth); - } - - if (credential == null) - { - throw new ArgumentNullException(nameof(credential)); - } - - if (servicePrincipalName == null) - { - throw new ArgumentNullException(nameof(servicePrincipalName)); - } - - NegotiateStreamPal.ValidateImpersonationLevel(impersonationLevel); - if (_context != null && IsServer != isServer) - { - throw new InvalidOperationException(SR.net_auth_client_server); - } - - _exception = null; - _remoteOk = false; - _framer = new StreamFramer(_innerStream); - _framer.WriteHeader.MessageId = FrameHeader.HandshakeId; - - _expectedProtectionLevel = protectionLevel; - _expectedImpersonationLevel = isServer ? impersonationLevel : TokenImpersonationLevel.None; - _writeSequenceNumber = 0; - _readSequenceNumber = 0; - - ContextFlagsPal flags = ContextFlagsPal.Connection; - - // A workaround for the client when talking to Win9x on the server side. - if (protectionLevel == ProtectionLevel.None && !isServer) - { - package = NegotiationInfoClass.NTLM; - } - else if (protectionLevel == ProtectionLevel.EncryptAndSign) - { - flags |= ContextFlagsPal.Confidentiality; - } - else if (protectionLevel == ProtectionLevel.Sign) - { - // Assuming user expects NT4 SP4 and above. - flags |= (ContextFlagsPal.ReplayDetect | ContextFlagsPal.SequenceDetect | ContextFlagsPal.InitIntegrity); - } - - if (isServer) - { - if (_extendedProtectionPolicy!.PolicyEnforcement == PolicyEnforcement.WhenSupported) - { - flags |= ContextFlagsPal.AllowMissingBindings; - } - - if (_extendedProtectionPolicy.PolicyEnforcement != PolicyEnforcement.Never && - _extendedProtectionPolicy.ProtectionScenario == ProtectionScenario.TrustedProxy) - { - flags |= ContextFlagsPal.ProxyBindings; - } - } - else - { - // Server side should not request any of these flags. - if (protectionLevel != ProtectionLevel.None) - { - flags |= ContextFlagsPal.MutualAuth; - } - - if (impersonationLevel == TokenImpersonationLevel.Identification) - { - flags |= ContextFlagsPal.InitIdentify; - } - - if (impersonationLevel == TokenImpersonationLevel.Delegation) - { - flags |= ContextFlagsPal.Delegate; - } - } - - _canRetryAuthentication = false; - - try - { - _context = new NTAuthentication(isServer, package, credential, servicePrincipalName, flags, channelBinding!); - } - catch (Win32Exception e) - { - throw new AuthenticationException(SR.net_auth_SSPI, e); - } - } - - private Exception SetException(Exception e) - { - if (_exception == null || !(_exception is ObjectDisposedException)) - { - _exception = e; - } - - if (_exception != null && _context != null) - { - _context.CloseContext(); - } - - return _exception!; - } - - internal bool IsAuthenticated - { - get - { - return _context != null && HandshakeComplete && _exception == null && _remoteOk; - } - } - - internal bool IsMutuallyAuthenticated - { - get - { - if (!IsAuthenticated) - { - return false; - } - - // Suppressing for NTLM since SSPI does not return correct value in the context flags. - if (_context!.IsNTLM) - { - return false; - } - - return _context.IsMutualAuthFlag; - } - } - - internal bool IsEncrypted - { - get - { - return IsAuthenticated && _context!.IsConfidentialityFlag; - } - } - - internal bool IsSigned - { - get - { - return IsAuthenticated && (_context!.IsIntegrityFlag || _context.IsConfidentialityFlag); - } - } - - internal bool IsServer - { - get - { - return _context != null && _context.IsServer; - } - } - - internal bool CanGetSecureStream - { - get - { - return (_context!.IsConfidentialityFlag || _context.IsIntegrityFlag); - } - } - - internal TokenImpersonationLevel AllowedImpersonation - { - get - { - CheckThrow(true); - return PrivateImpersonationLevel; - } - } - - private TokenImpersonationLevel PrivateImpersonationLevel - { - get - { - // We should suppress the delegate flag in NTLM case. - return (_context!.IsDelegationFlag && _context.ProtocolName != NegotiationInfoClass.NTLM) ? TokenImpersonationLevel.Delegation - : _context.IsIdentifyFlag ? TokenImpersonationLevel.Identification - : TokenImpersonationLevel.Impersonation; - } - } - - private bool HandshakeComplete - { - get - { - return _context!.IsCompleted && _context.IsValidContext; - } - } - - internal void CheckThrow(bool authSucessCheck) - { - if (_exception != null) - { - ExceptionDispatchInfo.Throw(_exception); - } - - if (authSucessCheck && !IsAuthenticated) - { - throw new InvalidOperationException(SR.net_auth_noauth); - } - } - - // - // This is to not depend on GC&SafeHandle class if the context is not needed anymore. - // - internal void Close() - { - // Mark this instance as disposed. - _exception = new ObjectDisposedException("NegotiateStream"); - if (_context != null) - { - _context.CloseContext(); - } - } - - internal void ProcessAuthentication(LazyAsyncResult? lazyResult) - { - CheckThrow(false); - if (Interlocked.Exchange(ref _nestedAuth, 1) == 1) - { - throw new InvalidOperationException(SR.Format(SR.net_io_invalidnestedcall, lazyResult == null ? "BeginAuthenticate" : "Authenticate", "authenticate")); - } - - try - { - if (_context!.IsServer) - { - // Listen for a client blob. - StartReceiveBlob(lazyResult); - } - else - { - // Start with the first blob. - StartSendBlob(null, lazyResult); - } - } - catch (Exception e) - { - // Round-trip it through SetException(). - e = SetException(e); - throw; - } - finally - { - if (lazyResult == null || _exception != null) - { - _nestedAuth = 0; - } - } - } - - internal void EndProcessAuthentication(IAsyncResult result) - { - if (result == null) - { - throw new ArgumentNullException("asyncResult"); - } - - LazyAsyncResult? lazyResult = result as LazyAsyncResult; - if (lazyResult == null) - { - throw new ArgumentException(SR.Format(SR.net_io_async_result, result.GetType().FullName), "asyncResult"); - } - - if (Interlocked.Exchange(ref _nestedAuth, 0) == 0) - { - throw new InvalidOperationException(SR.Format(SR.net_io_invalidendcall, "EndAuthenticate")); - } - - // No "artificial" timeouts implemented so far, InnerStream controls that. - lazyResult.InternalWaitForCompletion(); - - Exception? e = lazyResult.Result as Exception; - - if (e != null) - { - // Round-trip it through the SetException(). - e = SetException(e); - ExceptionDispatchInfo.Throw(e); - } - } - - private bool CheckSpn() - { - if (_context!.IsKerberos) - { - return true; - } - - if (_extendedProtectionPolicy!.PolicyEnforcement == PolicyEnforcement.Never || - _extendedProtectionPolicy.CustomServiceNames == null) - { - return true; - } - - string? clientSpn = _context.ClientSpecifiedSpn; - - if (string.IsNullOrEmpty(clientSpn)) - { - if (_extendedProtectionPolicy.PolicyEnforcement == PolicyEnforcement.WhenSupported) - { - return true; - } - } - else - { - return _extendedProtectionPolicy.CustomServiceNames.Contains(clientSpn); - } - - return false; - } - - // - // Client side starts here, but server also loops through this method. - // - private void StartSendBlob(byte[]? message, LazyAsyncResult? lazyResult) - { - Exception? exception = null; - if (message != s_emptyMessage) - { - message = GetOutgoingBlob(message, ref exception); - } - - if (exception != null) - { - // Signal remote side on a failed attempt. - StartSendAuthResetSignal(lazyResult, message!, exception); - return; - } - - if (HandshakeComplete) - { - if (_context!.IsServer && !CheckSpn()) - { - exception = new AuthenticationException(SR.net_auth_bad_client_creds_or_target_mismatch); - int statusCode = ERROR_TRUST_FAILURE; - message = new byte[8]; //sizeof(long) - - for (int i = message.Length - 1; i >= 0; --i) - { - message[i] = (byte)(statusCode & 0xFF); - statusCode = (int)((uint)statusCode >> 8); - } - - StartSendAuthResetSignal(lazyResult, message, exception); - return; - } - - if (PrivateImpersonationLevel < _expectedImpersonationLevel) - { - exception = new AuthenticationException(SR.Format(SR.net_auth_context_expectation, _expectedImpersonationLevel.ToString(), PrivateImpersonationLevel.ToString())); - int statusCode = ERROR_TRUST_FAILURE; - message = new byte[8]; //sizeof(long) - - for (int i = message.Length - 1; i >= 0; --i) - { - message[i] = (byte)(statusCode & 0xFF); - statusCode = (int)((uint)statusCode >> 8); - } - - StartSendAuthResetSignal(lazyResult, message, exception); - return; - } - - ProtectionLevel result = _context.IsConfidentialityFlag ? ProtectionLevel.EncryptAndSign : _context.IsIntegrityFlag ? ProtectionLevel.Sign : ProtectionLevel.None; - - if (result < _expectedProtectionLevel) - { - exception = new AuthenticationException(SR.Format(SR.net_auth_context_expectation, result.ToString(), _expectedProtectionLevel.ToString())); - int statusCode = ERROR_TRUST_FAILURE; - message = new byte[8]; //sizeof(long) - - for (int i = message.Length - 1; i >= 0; --i) - { - message[i] = (byte)(statusCode & 0xFF); - statusCode = (int)((uint)statusCode >> 8); - } - - StartSendAuthResetSignal(lazyResult, message, exception); - return; - } - - // Signal remote party that we are done - _framer!.WriteHeader.MessageId = FrameHeader.HandshakeDoneId; - if (_context.IsServer) - { - // Server may complete now because client SSPI would not complain at this point. - _remoteOk = true; - - // However the client will wait for server to send this ACK - //Force signaling server OK to the client - if (message == null) - { - message = s_emptyMessage; - } - } - } - else if (message == null || message == s_emptyMessage) - { - throw new InternalException(); - } - - if (message != null) - { - //even if we are completed, there could be a blob for sending. - if (lazyResult == null) - { - _framer!.WriteMessage(message); - } - else - { - IAsyncResult ar = _framer!.BeginWriteMessage(message, s_writeCallback, lazyResult); - if (!ar.CompletedSynchronously) - { - return; - } - _framer.EndWriteMessage(ar); - } - } - CheckCompletionBeforeNextReceive(lazyResult); - } - - // - // This will check and logically complete the auth handshake. - // - private void CheckCompletionBeforeNextReceive(LazyAsyncResult? lazyResult) - { - if (HandshakeComplete && _remoteOk) - { - // We are done with success. - if (lazyResult != null) - { - lazyResult.InvokeCallback(); - } - - return; - } - - StartReceiveBlob(lazyResult); - } - - // - // Server side starts here, but client also loops through this method. - // - private void StartReceiveBlob(LazyAsyncResult? lazyResult) - { - Debug.Assert(_framer != null); - - byte[]? message; - if (lazyResult == null) - { - message = _framer.ReadMessage(); - } - else - { - IAsyncResult ar = _framer.BeginReadMessage(s_readCallback, lazyResult); - if (!ar.CompletedSynchronously) - { - return; - } - - message = _framer.EndReadMessage(ar); - } - - ProcessReceivedBlob(message, lazyResult); - } - - private void ProcessReceivedBlob(byte[]? message, LazyAsyncResult? lazyResult) - { - // This is an EOF otherwise we would get at least *empty* message but not a null one. - if (message == null) - { - throw new AuthenticationException(SR.net_auth_eof, null); - } - - // Process Header information. - if (_framer!.ReadHeader.MessageId == FrameHeader.HandshakeErrId) - { - if (message.Length >= 8) // sizeof(long) - { - // Try to recover remote win32 Exception. - long error = 0; - for (int i = 0; i < 8; ++i) - { - error = (error << 8) + message[i]; - } - - ThrowCredentialException(error); - } - - throw new AuthenticationException(SR.net_auth_alert, null); - } - - if (_framer.ReadHeader.MessageId == FrameHeader.HandshakeDoneId) - { - _remoteOk = true; - } - else if (_framer.ReadHeader.MessageId != FrameHeader.HandshakeId) - { - throw new AuthenticationException(SR.Format(SR.net_io_header_id, "MessageId", _framer.ReadHeader.MessageId, FrameHeader.HandshakeId), null); - } - - CheckCompletionBeforeNextSend(message, lazyResult); - } - - // - // This will check and logically complete the auth handshake. - // - private void CheckCompletionBeforeNextSend(byte[] message, LazyAsyncResult? lazyResult) - { - //If we are done don't go into send. - if (HandshakeComplete) - { - if (!_remoteOk) - { - throw new AuthenticationException(SR.Format(SR.net_io_header_id, "MessageId", _framer!.ReadHeader.MessageId, FrameHeader.HandshakeDoneId), null); - } - if (lazyResult != null) - { - lazyResult.InvokeCallback(); - } - - return; - } - - // Not yet done, get a new blob and send it if any. - StartSendBlob(message, lazyResult); - } - - // - // This is to reset auth state on the remote side. - // If this write succeeds we will allow auth retrying. - // - private void StartSendAuthResetSignal(LazyAsyncResult? lazyResult, byte[] message, Exception exception) - { - _framer!.WriteHeader.MessageId = FrameHeader.HandshakeErrId; - - if (IsLogonDeniedException(exception)) - { - if (IsServer) - { - exception = new InvalidCredentialException(SR.net_auth_bad_client_creds, exception); - } - else - { - exception = new InvalidCredentialException(SR.net_auth_bad_client_creds_or_target_mismatch, exception); - } - } - - if (!(exception is AuthenticationException)) - { - exception = new AuthenticationException(SR.net_auth_SSPI, exception); - } - - if (lazyResult == null) - { - _framer.WriteMessage(message); - } - else - { - lazyResult.Result = exception; - IAsyncResult ar = _framer.BeginWriteMessage(message, s_writeCallback, lazyResult); - if (!ar.CompletedSynchronously) - { - return; - } - - _framer.EndWriteMessage(ar); - } - - _canRetryAuthentication = true; - ExceptionDispatchInfo.Throw(exception); - } - - private static void WriteCallback(IAsyncResult transportResult) - { - if (!(transportResult.AsyncState is LazyAsyncResult)) - { - NetEventSource.Fail(transportResult, "State type is wrong, expected LazyAsyncResult."); - } - - if (transportResult.CompletedSynchronously) - { - return; - } - - LazyAsyncResult lazyResult = (LazyAsyncResult)transportResult.AsyncState!; - - // Async completion. - try - { - NegoState authState = (NegoState)lazyResult.AsyncObject!; - authState._framer!.EndWriteMessage(transportResult); - - // Special case for an error notification. - if (lazyResult.Result is Exception e) - { - authState._canRetryAuthentication = true; - ExceptionDispatchInfo.Throw(e); - } - - authState.CheckCompletionBeforeNextReceive(lazyResult); - } - catch (Exception e) - { - if (lazyResult.InternalPeekCompleted) - { - // This will throw on a worker thread. - throw; - } - - lazyResult.InvokeCallback(e); - } - } - - private static void ReadCallback(IAsyncResult transportResult) - { - if (!(transportResult.AsyncState is LazyAsyncResult)) - { - NetEventSource.Fail(transportResult, "State type is wrong, expected LazyAsyncResult."); - } - - if (transportResult.CompletedSynchronously) - { - return; - } - - LazyAsyncResult lazyResult = (LazyAsyncResult)transportResult.AsyncState!; - - // Async completion. - try - { - NegoState authState = (NegoState)lazyResult.AsyncObject!; - byte[]? message = authState._framer!.EndReadMessage(transportResult); - authState.ProcessReceivedBlob(message, lazyResult); - } - catch (Exception e) - { - if (lazyResult.InternalPeekCompleted) - { - // This will throw on a worker thread. - throw; - } - - lazyResult.InvokeCallback(e); - } - } - - internal static bool IsError(SecurityStatusPal status) - { - return ((int)status.ErrorCode >= (int)SecurityStatusPalErrorCode.OutOfMemory); - } - - private unsafe byte[]? GetOutgoingBlob(byte[]? incomingBlob, ref Exception? e) - { - byte[]? message = _context!.GetOutgoingBlob(incomingBlob, false, out SecurityStatusPal statusCode); - - if (IsError(statusCode)) - { - e = NegotiateStreamPal.CreateExceptionFromError(statusCode); - uint error = (uint)e.HResult; - - message = new byte[sizeof(long)]; - for (int i = message.Length - 1; i >= 0; --i) - { - message[i] = (byte)(error & 0xFF); - error = (error >> 8); - } - } - - if (message != null && message.Length == 0) - { - message = s_emptyMessage; - } - - return message; - } - - internal int EncryptData(byte[] buffer, int offset, int count, ref byte[]? outBuffer) - { - CheckThrow(true); - - // SSPI seems to ignore this sequence number. - ++_writeSequenceNumber; - return _context!.Encrypt(buffer, offset, count, ref outBuffer, _writeSequenceNumber); - } - - internal int DecryptData(byte[] buffer, int offset, int count, out int newOffset) - { - CheckThrow(true); - - // SSPI seems to ignore this sequence number. - ++_readSequenceNumber; - return _context!.Decrypt(buffer, offset, count, out newOffset, _readSequenceNumber); - } - - internal static void ThrowCredentialException(long error) - { - Win32Exception e = new Win32Exception((int)error); - - if (e.NativeErrorCode == (int)SecurityStatusPalErrorCode.LogonDenied) - { - throw new InvalidCredentialException(SR.net_auth_bad_client_creds, e); - } - - if (e.NativeErrorCode == NegoState.ERROR_TRUST_FAILURE) - { - throw new AuthenticationException(SR.net_auth_context_expectation_remote, e); - } - - throw new AuthenticationException(SR.net_auth_alert, e); - } - - internal static bool IsLogonDeniedException(Exception exception) - { - Win32Exception? win32exception = exception as Win32Exception; - - return (win32exception != null) && (win32exception.NativeErrorCode == (int)SecurityStatusPalErrorCode.LogonDenied); - } - } -} diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/NegotiateStream.cs b/src/libraries/System.Net.Security/src/System/Net/Security/NegotiateStream.cs index 7fdf5ab50f3d8e..8a420ed6a4baf4 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/NegotiateStream.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/NegotiateStream.cs @@ -2,34 +2,59 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.ComponentModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Threading; -using System.Threading.Tasks; +using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; +using System.Security.Authentication; using System.Security.Authentication.ExtendedProtection; using System.Security.Principal; +using System.Threading; +using System.Threading.Tasks; namespace System.Net.Security { - /* - An authenticated stream based on NEGO SSP. - - The class that can be used by client and server side applications - - to transfer Identities across the stream - - to encrypt data based on NEGO SSP package - - In most cases the innerStream will be of type NetworkStream. - On Win9x data encryption is not available and both sides have - to explicitly drop SecurityLevel and MuatualAuth requirements. - - This is a simple wrapper class. - All real work is done by internal NegoState class and the other partial implementation files. - */ + /// + /// Provides a stream that uses the Negotiate security protocol to authenticate the client, and optionally the server, in client-server communication. + /// public partial class NegotiateStream : AuthenticatedStream { - private readonly NegoState _negoState; - private readonly string _package; + private const int ERROR_TRUST_FAILURE = 1790; // Used to serialize protectionLevel or impersonationLevel mismatch error to the remote side. + private const int MaxReadFrameSize = 64 * 1024; + private const int MaxWriteDataSize = 63 * 1024; // 1k for the framing and trailer that is always less as per SSPI. + private const string DefaultPackage = NegotiationInfoClass.Negotiate; + +#pragma warning disable CA1825 // used in reference comparison, requires unique object identity + private static readonly byte[] s_emptyMessage = new byte[0]; +#pragma warning restore CA1825 + + private readonly byte[] _readHeader; private IIdentity? _remoteIdentity; + private byte[] _buffer; + private int _bufferOffset; + private int _bufferCount; + + private volatile int _writeInProgress; + private volatile int _readInProgress; + private volatile int _authInProgress; + + private Exception? _exception; + private StreamFramer? _framer; + private NTAuthentication? _context; + private bool _canRetryAuthentication; + private ProtectionLevel _expectedProtectionLevel; + private TokenImpersonationLevel _expectedImpersonationLevel; + private uint _writeSequenceNumber; + private uint _readSequenceNumber; + private ExtendedProtectionPolicy? _extendedProtectionPolicy; + + /// + /// SSPI does not send a server ack on successful auth. + /// This is a state variable used to gracefully handle auth confirmation. + /// + private bool _remoteOk = false; public NegotiateStream(Stream innerStream) : this(innerStream, false) { @@ -37,687 +62,920 @@ public NegotiateStream(Stream innerStream) : this(innerStream, false) public NegotiateStream(Stream innerStream, bool leaveInnerStreamOpen) : base(innerStream, leaveInnerStreamOpen) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User)) - { -#endif - _negoState = new NegoState(innerStream); - _package = NegoState.DefaultPackage; - InitializeStreamPart(); -#if DEBUG - } -#endif + _readHeader = new byte[4]; + _buffer = Array.Empty(); } - public virtual IAsyncResult BeginAuthenticateAsClient(AsyncCallback? asyncCallback, object? asyncState) + protected override void Dispose(bool disposing) { - return BeginAuthenticateAsClient((NetworkCredential)CredentialCache.DefaultCredentials, null, string.Empty, - ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification, - asyncCallback, asyncState); + try + { + _exception = new ObjectDisposedException(nameof(NegotiateStream)); + _context?.CloseContext(); + } + finally + { + base.Dispose(disposing); + } } - public virtual IAsyncResult BeginAuthenticateAsClient(NetworkCredential credential, string targetName, AsyncCallback? asyncCallback, object? asyncState) + public override async ValueTask DisposeAsync() { - return BeginAuthenticateAsClient(credential, null, targetName, - ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification, - asyncCallback, asyncState); + try + { + _exception = new ObjectDisposedException(nameof(NegotiateStream)); + _context?.CloseContext(); + } + finally + { + await base.DisposeAsync().ConfigureAwait(false); + } } - public virtual IAsyncResult BeginAuthenticateAsClient(NetworkCredential credential, ChannelBinding? binding, string targetName, AsyncCallback? asyncCallback, object? asyncState) - { - return BeginAuthenticateAsClient(credential, binding, targetName, - ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification, - asyncCallback, asyncState); - } + public virtual IAsyncResult BeginAuthenticateAsClient(AsyncCallback? asyncCallback, object? asyncState) => + BeginAuthenticateAsClient((NetworkCredential)CredentialCache.DefaultCredentials, binding: null, string.Empty, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification, + asyncCallback, asyncState); - public virtual IAsyncResult BeginAuthenticateAsClient( - NetworkCredential credential, - string targetName, - ProtectionLevel requiredProtectionLevel, - TokenImpersonationLevel allowedImpersonationLevel, - AsyncCallback? asyncCallback, - object? asyncState) - { - return BeginAuthenticateAsClient(credential, null, targetName, - requiredProtectionLevel, allowedImpersonationLevel, - asyncCallback, asyncState); - } + public virtual IAsyncResult BeginAuthenticateAsClient(NetworkCredential credential, string targetName, AsyncCallback? asyncCallback, object? asyncState) => + BeginAuthenticateAsClient(credential, binding: null, targetName, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification, + asyncCallback, asyncState); - public virtual IAsyncResult BeginAuthenticateAsClient( - NetworkCredential credential, - ChannelBinding? binding, - string targetName, - ProtectionLevel requiredProtectionLevel, - TokenImpersonationLevel allowedImpersonationLevel, - AsyncCallback? asyncCallback, - object? asyncState) - { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) - { -#endif - _negoState.ValidateCreateContext(_package, false, credential, targetName, binding, requiredProtectionLevel, allowedImpersonationLevel); + public virtual IAsyncResult BeginAuthenticateAsClient(NetworkCredential credential, ChannelBinding? binding, string targetName, AsyncCallback? asyncCallback, object? asyncState) => + BeginAuthenticateAsClient(credential, binding, targetName, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification, + asyncCallback, asyncState); - LazyAsyncResult result = new LazyAsyncResult(_negoState, asyncState, asyncCallback); - _negoState.ProcessAuthentication(result); + public virtual IAsyncResult BeginAuthenticateAsClient( + NetworkCredential credential, string targetName, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel allowedImpersonationLevel, + AsyncCallback? asyncCallback, object? asyncState) => + BeginAuthenticateAsClient(credential, binding: null, targetName, requiredProtectionLevel, allowedImpersonationLevel, + asyncCallback, asyncState); - return result; -#if DEBUG - } -#endif - } + public virtual IAsyncResult BeginAuthenticateAsClient( + NetworkCredential credential, ChannelBinding? binding, string targetName, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel allowedImpersonationLevel, + AsyncCallback? asyncCallback, object? asyncState) => + TaskToApm.Begin(AuthenticateAsClientAsync(credential, binding, targetName, requiredProtectionLevel, allowedImpersonationLevel), asyncCallback, asyncState); - public virtual void EndAuthenticateAsClient(IAsyncResult asyncResult) - { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User)) - { -#endif - _negoState.EndProcessAuthentication(asyncResult); -#if DEBUG - } -#endif - } + public virtual void EndAuthenticateAsClient(IAsyncResult asyncResult) => TaskToApm.End(asyncResult); - public virtual void AuthenticateAsServer() - { - AuthenticateAsServer((NetworkCredential)CredentialCache.DefaultCredentials, null, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); - } + public virtual void AuthenticateAsServer() => + AuthenticateAsServer((NetworkCredential)CredentialCache.DefaultCredentials, policy: null, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); - public virtual void AuthenticateAsServer(ExtendedProtectionPolicy? policy) - { + public virtual void AuthenticateAsServer(ExtendedProtectionPolicy? policy) => AuthenticateAsServer((NetworkCredential)CredentialCache.DefaultCredentials, policy, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); - } - public virtual void AuthenticateAsServer(NetworkCredential credential, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel requiredImpersonationLevel) - { - AuthenticateAsServer(credential, null, requiredProtectionLevel, requiredImpersonationLevel); - } + public virtual void AuthenticateAsServer(NetworkCredential credential, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel requiredImpersonationLevel) => + AuthenticateAsServer(credential, policy: null, requiredProtectionLevel, requiredImpersonationLevel); public virtual void AuthenticateAsServer(NetworkCredential credential, ExtendedProtectionPolicy? policy, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel requiredImpersonationLevel) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) - { -#endif - _negoState.ValidateCreateContext(_package, credential, string.Empty, policy, requiredProtectionLevel, requiredImpersonationLevel); - _negoState.ProcessAuthentication(null); -#if DEBUG - } -#endif + ValidateCreateContext(DefaultPackage, credential, string.Empty, policy, requiredProtectionLevel, requiredImpersonationLevel); + AuthenticateAsync(new SyncReadWriteAdapter(InnerStream)).GetAwaiter().GetResult(); } - public virtual IAsyncResult BeginAuthenticateAsServer(AsyncCallback? asyncCallback, object? asyncState) - { - return BeginAuthenticateAsServer((NetworkCredential)CredentialCache.DefaultCredentials, null, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification, asyncCallback, asyncState); - } + public virtual IAsyncResult BeginAuthenticateAsServer(AsyncCallback? asyncCallback, object? asyncState) => + BeginAuthenticateAsServer((NetworkCredential)CredentialCache.DefaultCredentials, policy: null, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification, asyncCallback, asyncState); - public virtual IAsyncResult BeginAuthenticateAsServer(ExtendedProtectionPolicy? policy, AsyncCallback? asyncCallback, object? asyncState) - { - return BeginAuthenticateAsServer((NetworkCredential)CredentialCache.DefaultCredentials, policy, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification, asyncCallback, asyncState); - } + public virtual IAsyncResult BeginAuthenticateAsServer(ExtendedProtectionPolicy? policy, AsyncCallback? asyncCallback, object? asyncState) => + BeginAuthenticateAsServer((NetworkCredential)CredentialCache.DefaultCredentials, policy, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification, asyncCallback, asyncState); public virtual IAsyncResult BeginAuthenticateAsServer( - NetworkCredential credential, - ProtectionLevel requiredProtectionLevel, - TokenImpersonationLevel requiredImpersonationLevel, - AsyncCallback? asyncCallback, - object? asyncState) - { - return BeginAuthenticateAsServer(credential, null, requiredProtectionLevel, requiredImpersonationLevel, asyncCallback, asyncState); - } + NetworkCredential credential, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel requiredImpersonationLevel, + AsyncCallback? asyncCallback, object? asyncState) => + BeginAuthenticateAsServer(credential, policy: null, requiredProtectionLevel, requiredImpersonationLevel, asyncCallback, asyncState); public virtual IAsyncResult BeginAuthenticateAsServer( - NetworkCredential credential, - ExtendedProtectionPolicy? policy, - ProtectionLevel requiredProtectionLevel, - TokenImpersonationLevel requiredImpersonationLevel, - AsyncCallback? asyncCallback, - object? asyncState) - { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) - { -#endif - _negoState.ValidateCreateContext(_package, credential, string.Empty, policy, requiredProtectionLevel, requiredImpersonationLevel); + NetworkCredential credential, ExtendedProtectionPolicy? policy, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel requiredImpersonationLevel, + AsyncCallback? asyncCallback, object? asyncState) => + TaskToApm.Begin(AuthenticateAsServerAsync(credential, policy, requiredProtectionLevel, requiredImpersonationLevel), asyncCallback, asyncState); - LazyAsyncResult result = new LazyAsyncResult(_negoState, asyncState, asyncCallback); - _negoState.ProcessAuthentication(result); + public virtual void EndAuthenticateAsServer(IAsyncResult asyncResult) => TaskToApm.End(asyncResult); - return result; -#if DEBUG - } -#endif - } - // - public virtual void EndAuthenticateAsServer(IAsyncResult asyncResult) - { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User)) - { -#endif - _negoState.EndProcessAuthentication(asyncResult); -#if DEBUG - } -#endif - } + public virtual void AuthenticateAsClient() => + AuthenticateAsClient((NetworkCredential)CredentialCache.DefaultCredentials, binding: null, string.Empty, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); - public virtual void AuthenticateAsClient() - { - AuthenticateAsClient((NetworkCredential)CredentialCache.DefaultCredentials, null, string.Empty, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); - } - - public virtual void AuthenticateAsClient(NetworkCredential credential, string targetName) - { - AuthenticateAsClient(credential, null, targetName, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); - } + public virtual void AuthenticateAsClient(NetworkCredential credential, string targetName) => + AuthenticateAsClient(credential, binding: null, targetName, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); - public virtual void AuthenticateAsClient(NetworkCredential credential, ChannelBinding? binding, string targetName) - { + public virtual void AuthenticateAsClient(NetworkCredential credential, ChannelBinding? binding, string targetName) => AuthenticateAsClient(credential, binding, targetName, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); - } public virtual void AuthenticateAsClient( - NetworkCredential credential, string targetName, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel allowedImpersonationLevel) - { - AuthenticateAsClient(credential, null, targetName, requiredProtectionLevel, allowedImpersonationLevel); - } + NetworkCredential credential, string targetName, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel allowedImpersonationLevel) => + AuthenticateAsClient(credential, binding: null, targetName, requiredProtectionLevel, allowedImpersonationLevel); public virtual void AuthenticateAsClient( NetworkCredential credential, ChannelBinding? binding, string targetName, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel allowedImpersonationLevel) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) - { -#endif - _negoState.ValidateCreateContext(_package, false, credential, targetName, binding, requiredProtectionLevel, allowedImpersonationLevel); - _negoState.ProcessAuthentication(null); -#if DEBUG - } -#endif + ValidateCreateContext(DefaultPackage, isServer: false, credential, targetName, binding, requiredProtectionLevel, allowedImpersonationLevel); + AuthenticateAsync(new SyncReadWriteAdapter(InnerStream)).GetAwaiter().GetResult(); } - public virtual Task AuthenticateAsClientAsync() - { - return Task.Factory.FromAsync(BeginAuthenticateAsClient, EndAuthenticateAsClient, null); - } + public virtual Task AuthenticateAsClientAsync() => + AuthenticateAsClientAsync((NetworkCredential)CredentialCache.DefaultCredentials, binding: null, string.Empty, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); - public virtual Task AuthenticateAsClientAsync(NetworkCredential credential, string targetName) - { - return Task.Factory.FromAsync(BeginAuthenticateAsClient, EndAuthenticateAsClient, credential, targetName, null); - } + public virtual Task AuthenticateAsClientAsync(NetworkCredential credential, string targetName) => + AuthenticateAsClientAsync(credential, binding: null, targetName, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); public virtual Task AuthenticateAsClientAsync( NetworkCredential credential, string targetName, ProtectionLevel requiredProtectionLevel, - TokenImpersonationLevel allowedImpersonationLevel) - { - return Task.Factory.FromAsync((callback, state) => BeginAuthenticateAsClient(credential, targetName, requiredProtectionLevel, allowedImpersonationLevel, callback, state), EndAuthenticateAsClient, null); - } + TokenImpersonationLevel allowedImpersonationLevel) => + AuthenticateAsClientAsync(credential, binding: null, targetName, requiredProtectionLevel, allowedImpersonationLevel); - public virtual Task AuthenticateAsClientAsync(NetworkCredential credential, ChannelBinding? binding, string targetName) - { - return Task.Factory.FromAsync(BeginAuthenticateAsClient, EndAuthenticateAsClient, credential, binding, targetName, null); - } + public virtual Task AuthenticateAsClientAsync(NetworkCredential credential, ChannelBinding? binding, string targetName) => + AuthenticateAsClientAsync(credential, binding, targetName, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); public virtual Task AuthenticateAsClientAsync( - NetworkCredential credential, ChannelBinding? binding, - string targetName, ProtectionLevel requiredProtectionLevel, + NetworkCredential credential, ChannelBinding? binding, string targetName, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel allowedImpersonationLevel) { - return Task.Factory.FromAsync((callback, state) => BeginAuthenticateAsClient(credential, binding, targetName, requiredProtectionLevel, allowedImpersonationLevel, callback, state), EndAuthenticateAsClient, null); + ValidateCreateContext(DefaultPackage, isServer: false, credential, targetName, binding, requiredProtectionLevel, allowedImpersonationLevel); + return AuthenticateAsync(new AsyncReadWriteAdapter(InnerStream, cancellationToken: default)); } - public virtual Task AuthenticateAsServerAsync() - { - return Task.Factory.FromAsync(BeginAuthenticateAsServer, EndAuthenticateAsServer, null); - } + public virtual Task AuthenticateAsServerAsync() => + AuthenticateAsServerAsync((NetworkCredential)CredentialCache.DefaultCredentials, policy: null, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); - public virtual Task AuthenticateAsServerAsync(ExtendedProtectionPolicy? policy) - { - return Task.Factory.FromAsync(BeginAuthenticateAsServer, EndAuthenticateAsServer, policy, null); - } + public virtual Task AuthenticateAsServerAsync(ExtendedProtectionPolicy? policy) => + AuthenticateAsServerAsync((NetworkCredential)CredentialCache.DefaultCredentials, policy, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); - public virtual Task AuthenticateAsServerAsync(NetworkCredential credential, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel requiredImpersonationLevel) - { - return Task.Factory.FromAsync(BeginAuthenticateAsServer, EndAuthenticateAsServer, credential, requiredProtectionLevel, requiredImpersonationLevel, null); - } + public virtual Task AuthenticateAsServerAsync(NetworkCredential credential, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel requiredImpersonationLevel) => + AuthenticateAsServerAsync(credential, policy: null, requiredProtectionLevel, requiredImpersonationLevel); public virtual Task AuthenticateAsServerAsync( - NetworkCredential credential, ExtendedProtectionPolicy? policy, - ProtectionLevel requiredProtectionLevel, - TokenImpersonationLevel requiredImpersonationLevel) + NetworkCredential credential, ExtendedProtectionPolicy? policy, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel requiredImpersonationLevel) { - return Task.Factory.FromAsync((callback, state) => BeginAuthenticateAsServer(credential, policy, requiredProtectionLevel, requiredImpersonationLevel, callback, state), EndAuthenticateAsClient, null); + ValidateCreateContext(DefaultPackage, credential, string.Empty, policy, requiredProtectionLevel, requiredImpersonationLevel); + return AuthenticateAsync(new AsyncReadWriteAdapter(InnerStream, cancellationToken: default)); } - public override bool IsAuthenticated + public override bool IsAuthenticated => IsAuthenticatedCore; + + [MemberNotNullWhen(true, nameof(_context))] + private bool IsAuthenticatedCore => _context != null && HandshakeComplete && _exception == null && _remoteOk; + + public override bool IsMutuallyAuthenticated => + IsAuthenticatedCore && + !_context.IsNTLM && // suppressing for NTLM since SSPI does not return correct value in the context flags. + _context.IsMutualAuthFlag; + + public override bool IsEncrypted => IsAuthenticatedCore && _context.IsConfidentialityFlag; + + public override bool IsSigned => IsAuthenticatedCore && (_context.IsIntegrityFlag || _context.IsConfidentialityFlag); + + public override bool IsServer => _context != null && _context.IsServer; + + public virtual TokenImpersonationLevel ImpersonationLevel { get { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) - { -#endif - return _negoState.IsAuthenticated; -#if DEBUG - } -#endif + ThrowIfFailed(authSuccessCheck: true); + return PrivateImpersonationLevel; } } - public override bool IsMutuallyAuthenticated + private TokenImpersonationLevel PrivateImpersonationLevel => + _context!.IsDelegationFlag && _context.ProtocolName != NegotiationInfoClass.NTLM ? TokenImpersonationLevel.Delegation : // We should suppress the delegate flag in NTLM case. + _context.IsIdentifyFlag ? TokenImpersonationLevel.Identification : + TokenImpersonationLevel.Impersonation; + + private bool HandshakeComplete => _context!.IsCompleted && _context.IsValidContext; + + private bool CanGetSecureStream => _context!.IsConfidentialityFlag || _context.IsIntegrityFlag; + + public virtual IIdentity RemoteIdentity { get { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) + IIdentity? identity = _remoteIdentity; + if (identity is null) { -#endif - return _negoState.IsMutuallyAuthenticated; -#if DEBUG + ThrowIfFailed(authSuccessCheck: true); + _remoteIdentity = identity = NegotiateStreamPal.GetIdentity(_context!); } -#endif + return identity; } } - public override bool IsEncrypted + public override bool CanSeek => false; + + public override bool CanRead => IsAuthenticated && InnerStream.CanRead; + + public override bool CanTimeout => InnerStream.CanTimeout; + + public override bool CanWrite => IsAuthenticated && InnerStream.CanWrite; + + public override int ReadTimeout { - get - { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) - { -#endif - return _negoState.IsEncrypted; -#if DEBUG - } -#endif - } + get => InnerStream.ReadTimeout; + set => InnerStream.ReadTimeout = value; } - public override bool IsSigned + public override int WriteTimeout { - get + get => InnerStream.WriteTimeout; + set => InnerStream.WriteTimeout = value; + } + + public override long Length => InnerStream.Length; + + public override long Position + { + get => InnerStream.Position; + set => throw new NotSupportedException(SR.net_noseek); + } + + public override void SetLength(long value) => + InnerStream.SetLength(value); + + public override long Seek(long offset, SeekOrigin origin) => + throw new NotSupportedException(SR.net_noseek); + + public override void Flush() => + InnerStream.Flush(); + + public override Task FlushAsync(CancellationToken cancellationToken) => + InnerStream.FlushAsync(cancellationToken); + + public override int Read(byte[] buffer, int offset, int count) + { + ValidateParameters(buffer, offset, count); + + ThrowIfFailed(authSuccessCheck: true); + if (!CanGetSecureStream) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) - { -#endif - return _negoState.IsSigned; -#if DEBUG - } -#endif + return InnerStream.Read(buffer, offset, count); } + + ValueTask vt = ReadAsync(new SyncReadWriteAdapter(InnerStream), new Memory(buffer, offset, count)); + Debug.Assert(vt.IsCompleted, "Should have completed synchroously with sync adapter"); + return vt.GetAwaiter().GetResult(); } - public override bool IsServer + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - get + ValidateParameters(buffer, offset, count); + + ThrowIfFailed(authSuccessCheck: true); + if (!CanGetSecureStream) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) - { -#endif - return _negoState.IsServer; -#if DEBUG - } -#endif + return InnerStream.ReadAsync(buffer, offset, count, cancellationToken); } + + return ReadAsync(new AsyncReadWriteAdapter(InnerStream, cancellationToken), new Memory(buffer, offset, count)).AsTask(); } - public virtual TokenImpersonationLevel ImpersonationLevel + public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) { - get + ThrowIfFailed(authSuccessCheck: true); + if (!CanGetSecureStream) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) - { -#endif - return _negoState.AllowedImpersonation; -#if DEBUG - } -#endif + return InnerStream.ReadAsync(buffer, cancellationToken); } + + return ReadAsync(new AsyncReadWriteAdapter(InnerStream, cancellationToken), buffer); } - public virtual IIdentity RemoteIdentity + private async ValueTask ReadAsync(TAdapter adapter, Memory buffer, [CallerMemberName] string? callerName = null) where TAdapter : IReadWriteAdapter { - get + if (Interlocked.Exchange(ref _readInProgress, 1) == 1) + { + throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, callerName, "read")); + } + + try { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) + if (_bufferCount != 0) + { + int copyBytes = Math.Min(_bufferCount, buffer.Length); + if (copyBytes != 0) + { + _buffer.AsMemory(_bufferOffset, copyBytes).CopyTo(buffer); + _bufferOffset += copyBytes; + _bufferCount -= copyBytes; + } + return copyBytes; + } + + while (true) { -#endif + int readBytes = await adapter.ReadAllAsync(_readHeader).ConfigureAwait(false); + if (readBytes == 0) + { + return 0; + } + + // Replace readBytes with the body size recovered from the header content. + readBytes = BitConverter.ToInt32(_readHeader, 0); + + // The body carries 4 bytes for trailer size slot plus trailer, hence <= 4 frame size is always an error. + // Additionally we'd like to restrict the read frame size to 64k. + if (readBytes <= 4 || readBytes > MaxReadFrameSize) + { + throw new IOException(SR.net_frame_read_size); + } - if (_remoteIdentity == null) + // Always pass InternalBuffer for SSPI "in place" decryption. + // A user buffer can be shared by many threads in that case decryption/integrity check may fail cause of data corruption. + _bufferCount = readBytes; + _bufferOffset = 0; + if (_buffer.Length < readBytes) { - _remoteIdentity = _negoState.GetIdentity(); + _buffer = new byte[readBytes]; } + readBytes = await adapter.ReadAllAsync(new Memory(_buffer, 0, readBytes)).ConfigureAwait(false); + if (readBytes == 0) + { + // We already checked that the frame body is bigger than 0 bytes. Hence, this is an EOF. + throw new IOException(SR.net_io_eof); + } + + // Decrypt into internal buffer, change "readBytes" to count now _Decrypted Bytes_ + // Decrypted data start from zero offset, the size can be shrunk after decryption. + _bufferCount = readBytes = DecryptData(_buffer!, 0, readBytes, out _bufferOffset); + if (readBytes == 0 && buffer.Length != 0) + { + // Read again. + continue; + } + + if (readBytes > buffer.Length) + { + readBytes = buffer.Length; + } + + _buffer.AsMemory(_bufferOffset, readBytes).CopyTo(buffer); + _bufferOffset += readBytes; + _bufferCount -= readBytes; - return _remoteIdentity; -#if DEBUG + return readBytes; } -#endif + } + catch (Exception e) when (!(e is IOException || e is OperationCanceledException)) + { + throw new IOException(SR.net_io_read, e); + } + finally + { + _readInProgress = 0; } } - // - // Stream contract implementation - // - public override bool CanSeek + public override void Write(byte[] buffer, int offset, int count) { - get + ValidateParameters(buffer, offset, count); + + ThrowIfFailed(authSuccessCheck: true); + if (!CanGetSecureStream) { - return false; + InnerStream.Write(buffer, offset, count); + return; } + + WriteAsync(new SyncReadWriteAdapter(InnerStream), new ReadOnlyMemory(buffer, offset, count)).GetAwaiter().GetResult(); } - public override bool CanRead + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - get + ValidateParameters(buffer, offset, count); + + ThrowIfFailed(authSuccessCheck: true); + if (!CanGetSecureStream) { - return IsAuthenticated && InnerStream.CanRead; + return InnerStream.WriteAsync(buffer, offset, count, cancellationToken); } + + return WriteAsync(new AsyncReadWriteAdapter(InnerStream, cancellationToken), new ReadOnlyMemory(buffer, offset, count)); } - public override bool CanTimeout + public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) { - get + ThrowIfFailed(authSuccessCheck: true); + if (!CanGetSecureStream) { - return InnerStream.CanTimeout; + return InnerStream.WriteAsync(buffer, cancellationToken); } + + return new ValueTask(WriteAsync(new AsyncReadWriteAdapter(InnerStream, cancellationToken), buffer)); } - public override bool CanWrite + private async Task WriteAsync(TAdapter adapter, ReadOnlyMemory buffer) where TAdapter : IReadWriteAdapter { - get + if (Interlocked.Exchange(ref _writeInProgress, 1) == 1) { - return IsAuthenticated && InnerStream.CanWrite; + throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, nameof(Write), "write")); } - } - public override int ReadTimeout - { - get + try { - return InnerStream.ReadTimeout; + byte[]? outBuffer = null; + while (!buffer.IsEmpty) + { + int chunkBytes = Math.Min(buffer.Length, MaxWriteDataSize); + int encryptedBytes; + try + { + encryptedBytes = EncryptData(buffer.Slice(0, chunkBytes).Span, ref outBuffer); + } + catch (Exception e) + { + throw new IOException(SR.net_io_encrypt, e); + } + + await adapter.WriteAsync(outBuffer, 0, encryptedBytes).ConfigureAwait(false); + buffer = buffer.Slice(chunkBytes); + } } - set + catch (Exception e) when (!(e is IOException || e is OperationCanceledException)) { - InnerStream.ReadTimeout = value; + throw new IOException(SR.net_io_write, e); + } + finally + { + _writeInProgress = 0; } } - public override int WriteTimeout + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? asyncCallback, object? asyncState) => + TaskToApm.Begin(ReadAsync(buffer, offset, count), asyncCallback, asyncState); + + public override int EndRead(IAsyncResult asyncResult) => + TaskToApm.End(asyncResult); + + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? asyncCallback, object? asyncState) => + TaskToApm.Begin(WriteAsync(buffer, offset, count), asyncCallback, asyncState); + + public override void EndWrite(IAsyncResult asyncResult) => + TaskToApm.End(asyncResult); + + /// Validates user parameters for all Read/Write methods. + private static void ValidateParameters(byte[] buffer, int offset, int count) { - get + if (buffer == null) { - return InnerStream.WriteTimeout; + throw new ArgumentNullException(nameof(buffer)); } - set + + if (offset < 0) { - InnerStream.WriteTimeout = value; + throw new ArgumentOutOfRangeException(nameof(offset)); } - } - public override long Length - { - get + if (count < 0) { - return InnerStream.Length; + throw new ArgumentOutOfRangeException(nameof(count)); + } + + if (count > buffer.Length - offset) + { + throw new ArgumentOutOfRangeException(nameof(count), SR.net_offset_plus_count); } } - public override long Position + private void ValidateCreateContext( + string package, + NetworkCredential credential, + string servicePrincipalName, + ExtendedProtectionPolicy? policy, + ProtectionLevel protectionLevel, + TokenImpersonationLevel impersonationLevel) { - get + if (policy != null) { - return InnerStream.Position; + // One of these must be set if EP is turned on + if (policy.CustomChannelBinding == null && policy.CustomServiceNames == null) + { + throw new ArgumentException(SR.net_auth_must_specify_extended_protection_scheme, nameof(policy)); + } + + _extendedProtectionPolicy = policy; } - set + else { - throw new NotSupportedException(SR.net_noseek); + _extendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Never); } - } - public override void SetLength(long value) - { - InnerStream.SetLength(value); + ValidateCreateContext(package, isServer: true, credential, servicePrincipalName, _extendedProtectionPolicy.CustomChannelBinding, protectionLevel, impersonationLevel); } - public override long Seek(long offset, SeekOrigin origin) + private void ValidateCreateContext( + string package, + bool isServer, + NetworkCredential credential, + string? servicePrincipalName, + ChannelBinding? channelBinding, + ProtectionLevel protectionLevel, + TokenImpersonationLevel impersonationLevel) { - throw new NotSupportedException(SR.net_noseek); - } + if (_exception != null && !_canRetryAuthentication) + { + ExceptionDispatchInfo.Throw(_exception); + } - public override void Flush() - { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) + if (_context != null && _context.IsValidContext) { -#endif - InnerStream.Flush(); -#if DEBUG + throw new InvalidOperationException(SR.net_auth_reauth); } -#endif - } - public override Task FlushAsync(CancellationToken cancellationToken) - { - return InnerStream.FlushAsync(cancellationToken); - } + if (credential == null) + { + throw new ArgumentNullException(nameof(credential)); + } - protected override void Dispose(bool disposing) - { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User)) + if (servicePrincipalName == null) + { + throw new ArgumentNullException(nameof(servicePrincipalName)); + } + + NegotiateStreamPal.ValidateImpersonationLevel(impersonationLevel); + if (_context != null && IsServer != isServer) + { + throw new InvalidOperationException(SR.net_auth_client_server); + } + + _exception = null; + _remoteOk = false; + _framer = new StreamFramer(); + _framer.WriteHeader.MessageId = FrameHeader.HandshakeId; + + _expectedProtectionLevel = protectionLevel; + _expectedImpersonationLevel = isServer ? impersonationLevel : TokenImpersonationLevel.None; + _writeSequenceNumber = 0; + _readSequenceNumber = 0; + + ContextFlagsPal flags = ContextFlagsPal.Connection; + + // A workaround for the client when talking to Win9x on the server side. + if (protectionLevel == ProtectionLevel.None && !isServer) + { + package = NegotiationInfoClass.NTLM; + } + else if (protectionLevel == ProtectionLevel.EncryptAndSign) + { + flags |= ContextFlagsPal.Confidentiality; + } + else if (protectionLevel == ProtectionLevel.Sign) + { + // Assuming user expects NT4 SP4 and above. + flags |= ContextFlagsPal.ReplayDetect | ContextFlagsPal.SequenceDetect | ContextFlagsPal.InitIntegrity; + } + + if (isServer) { -#endif - try + if (_extendedProtectionPolicy!.PolicyEnforcement == PolicyEnforcement.WhenSupported) { - _negoState.Close(); + flags |= ContextFlagsPal.AllowMissingBindings; } - finally + + if (_extendedProtectionPolicy.PolicyEnforcement != PolicyEnforcement.Never && + _extendedProtectionPolicy.ProtectionScenario == ProtectionScenario.TrustedProxy) { - base.Dispose(disposing); + flags |= ContextFlagsPal.ProxyBindings; } -#if DEBUG } -#endif - } + else + { + // Server side should not request any of these flags. + if (protectionLevel != ProtectionLevel.None) + { + flags |= ContextFlagsPal.MutualAuth; + } + + if (impersonationLevel == TokenImpersonationLevel.Identification) + { + flags |= ContextFlagsPal.InitIdentify; + } + + if (impersonationLevel == TokenImpersonationLevel.Delegation) + { + flags |= ContextFlagsPal.Delegate; + } + } + + _canRetryAuthentication = false; - public override async ValueTask DisposeAsync() - { try { - _negoState.Close(); + _context = new NTAuthentication(isServer, package, credential, servicePrincipalName, flags, channelBinding!); } - finally + catch (Win32Exception e) { - await base.DisposeAsync().ConfigureAwait(false); + throw new AuthenticationException(SR.net_auth_SSPI, e); } } - public override int Read(byte[] buffer, int offset, int count) + private void SetFailed(Exception e) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) + if (!(_exception is ObjectDisposedException)) { -#endif - _negoState.CheckThrow(true); + _exception = e; + } - if (!_negoState.CanGetSecureStream) - { - return InnerStream.Read(buffer, offset, count); - } + _context?.CloseContext(); + } + + private void ThrowIfFailed(bool authSuccessCheck) + { + if (_exception != null) + { + ExceptionDispatchInfo.Throw(_exception); + } - return ProcessRead(buffer, offset, count, null); -#if DEBUG + if (authSuccessCheck && !IsAuthenticatedCore) + { + throw new InvalidOperationException(SR.net_auth_noauth); } -#endif } - public override void Write(byte[] buffer, int offset, int count) + private async Task AuthenticateAsync(TAdapter adapter, [CallerMemberName] string? callerName = null) where TAdapter : IReadWriteAdapter { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) - { -#endif - _negoState.CheckThrow(true); + Debug.Assert(_context != null); - if (!_negoState.CanGetSecureStream) - { - InnerStream.Write(buffer, offset, count); - return; - } + ThrowIfFailed(authSuccessCheck: false); + if (Interlocked.Exchange(ref _authInProgress, 1) == 1) + { + throw new InvalidOperationException(SR.Format(SR.net_io_invalidnestedcall, callerName, "authenticate")); + } - ProcessWrite(buffer, offset, count, null); -#if DEBUG + try + { + await (_context.IsServer ? + ReceiveBlobAsync(adapter) : // server should listen for a client blob + SendBlobAsync(adapter, message: null)).ConfigureAwait(false); // client should send the first blob + } + catch (Exception e) + { + SetFailed(e); + throw; + } + finally + { + _authInProgress = 0; } -#endif } - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? asyncCallback, object? asyncState) + private bool CheckSpn() { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) + Debug.Assert(_context != null); + + if (_context.IsKerberos || + _extendedProtectionPolicy!.PolicyEnforcement == PolicyEnforcement.Never || + _extendedProtectionPolicy.CustomServiceNames == null) { -#endif - _negoState.CheckThrow(true); + return true; + } - if (!_negoState.CanGetSecureStream) - { - return TaskToApm.Begin(InnerStream.ReadAsync(buffer, offset, count), asyncCallback, asyncState); - } + string? clientSpn = _context.ClientSpecifiedSpn; - BufferAsyncResult bufferResult = new BufferAsyncResult(this, buffer, offset, count, asyncState, asyncCallback); - AsyncProtocolRequest asyncRequest = new AsyncProtocolRequest(bufferResult); - ProcessRead(buffer, offset, count, asyncRequest); - return bufferResult; -#if DEBUG + if (string.IsNullOrEmpty(clientSpn)) + { + return _extendedProtectionPolicy.PolicyEnforcement == PolicyEnforcement.WhenSupported; } -#endif + + return _extendedProtectionPolicy.CustomServiceNames.Contains(clientSpn); } - public override int EndRead(IAsyncResult asyncResult) + // Client authentication starts here, but server also loops through this method. + private async Task SendBlobAsync(TAdapter adapter, byte[]? message) where TAdapter : IReadWriteAdapter { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User)) + Debug.Assert(_context != null); + + Exception? exception = null; + if (message != s_emptyMessage) + { + message = GetOutgoingBlob(message, ref exception); + } + + if (exception != null) { -#endif - _negoState.CheckThrow(true); + // Signal remote side on a failed attempt. + await SendAuthResetSignalAndThrowAsync(adapter, message!, exception).ConfigureAwait(false); + Debug.Fail("Unreachable"); + } - if (!_negoState.CanGetSecureStream) + if (HandshakeComplete) + { + if (_context.IsServer && !CheckSpn()) { - return TaskToApm.End(asyncResult); - } + exception = new AuthenticationException(SR.net_auth_bad_client_creds_or_target_mismatch); + int statusCode = ERROR_TRUST_FAILURE; + message = new byte[sizeof(long)]; + for (int i = message.Length - 1; i >= 0; --i) + { + message[i] = (byte)(statusCode & 0xFF); + statusCode = (int)((uint)statusCode >> 8); + } - if (asyncResult == null) + await SendAuthResetSignalAndThrowAsync(adapter, message, exception).ConfigureAwait(false); + Debug.Fail("Unreachable"); + } + + if (PrivateImpersonationLevel < _expectedImpersonationLevel) { - throw new ArgumentNullException(nameof(asyncResult)); + exception = new AuthenticationException(SR.Format(SR.net_auth_context_expectation, _expectedImpersonationLevel.ToString(), PrivateImpersonationLevel.ToString())); + int statusCode = ERROR_TRUST_FAILURE; + message = new byte[sizeof(long)]; + + for (int i = message.Length - 1; i >= 0; --i) + { + message[i] = (byte)(statusCode & 0xFF); + statusCode = (int)((uint)statusCode >> 8); + } + + await SendAuthResetSignalAndThrowAsync(adapter, message, exception).ConfigureAwait(false); + Debug.Fail("Unreachable"); } - BufferAsyncResult? bufferResult = asyncResult as BufferAsyncResult; - if (bufferResult == null) + ProtectionLevel result = _context.IsConfidentialityFlag ? ProtectionLevel.EncryptAndSign : _context.IsIntegrityFlag ? ProtectionLevel.Sign : ProtectionLevel.None; + + if (result < _expectedProtectionLevel) { - throw new ArgumentException(SR.Format(SR.net_io_async_result, asyncResult.GetType().FullName), nameof(asyncResult)); + exception = new AuthenticationException(SR.Format(SR.net_auth_context_expectation, result.ToString(), _expectedProtectionLevel.ToString())); + int statusCode = ERROR_TRUST_FAILURE; + message = new byte[sizeof(long)]; + + for (int i = message.Length - 1; i >= 0; --i) + { + message[i] = (byte)(statusCode & 0xFF); + statusCode = (int)((uint)statusCode >> 8); + } + + await SendAuthResetSignalAndThrowAsync(adapter, message, exception).ConfigureAwait(false); + Debug.Fail("Unreachable"); } - if (Interlocked.Exchange(ref _NestedRead, 0) == 0) + // Signal remote party that we are done + _framer!.WriteHeader.MessageId = FrameHeader.HandshakeDoneId; + if (_context.IsServer) { - throw new InvalidOperationException(SR.Format(SR.net_io_invalidendcall, "EndRead")); + // Server may complete now because client SSPI would not complain at this point. + _remoteOk = true; + + // However the client will wait for server to send this ACK + // Force signaling server OK to the client + message ??= s_emptyMessage; } + } + else if (message == null || message == s_emptyMessage) + { + throw new InternalException(); + } + + if (message != null) + { + //even if we are completed, there could be a blob for sending. + await _framer!.WriteMessageAsync(adapter, message).ConfigureAwait(false); + } - // No "artificial" timeouts implemented so far, InnerStream controls timeout. - bufferResult.InternalWaitForCompletion(); + if (HandshakeComplete && _remoteOk) + { + // We are done with success. + return; + } + + await ReceiveBlobAsync(adapter).ConfigureAwait(false); + } + + // Server authentication starts here, but client also loops through this method. + private async Task ReceiveBlobAsync(TAdapter adapter) where TAdapter : IReadWriteAdapter + { + Debug.Assert(_framer != null); - if (bufferResult.Result is Exception e) + byte[]? message = await _framer.ReadMessageAsync(adapter).ConfigureAwait(false); + if (message == null) + { + // This is an EOF otherwise we would get at least *empty* message but not a null one. + throw new AuthenticationException(SR.net_auth_eof); + } + + // Process Header information. + if (_framer.ReadHeader.MessageId == FrameHeader.HandshakeErrId) + { + if (message.Length >= sizeof(long)) { - if (e is IOException) + // Try to recover remote win32 Exception. + long error = 0; + for (int i = 0; i < 8; ++i) { - ExceptionDispatchInfo.Throw(e); + error = (error << 8) + message[i]; } - throw new IOException(SR.net_io_read, e); + ThrowCredentialException(error); } - return bufferResult.Int32Result; -#if DEBUG + throw new AuthenticationException(SR.net_auth_alert); } -#endif - } - // - // - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? asyncCallback, object? asyncState) - { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) + + if (_framer.ReadHeader.MessageId == FrameHeader.HandshakeDoneId) + { + _remoteOk = true; + } + else if (_framer.ReadHeader.MessageId != FrameHeader.HandshakeId) { -#endif - _negoState.CheckThrow(true); + throw new AuthenticationException(SR.Format(SR.net_io_header_id, nameof(FrameHeader.MessageId), _framer.ReadHeader.MessageId, FrameHeader.HandshakeId)); + } - if (!_negoState.CanGetSecureStream) + // If we are done don't go into send. + if (HandshakeComplete) + { + if (!_remoteOk) { - return TaskToApm.Begin(InnerStream.WriteAsync(buffer, offset, count), asyncCallback, asyncState); + throw new AuthenticationException(SR.Format(SR.net_io_header_id, nameof(FrameHeader.MessageId), _framer.ReadHeader.MessageId, FrameHeader.HandshakeDoneId)); } - BufferAsyncResult bufferResult = new BufferAsyncResult(this, buffer, offset, count, asyncState, asyncCallback); - AsyncProtocolRequest asyncRequest = new AsyncProtocolRequest(bufferResult); + return; + } + + // Not yet done, get a new blob and send it if any. + await SendBlobAsync(adapter, message).ConfigureAwait(false); + } + + // This is to reset auth state on the remote side. + // If this write succeeds we will allow auth retrying. + private async Task SendAuthResetSignalAndThrowAsync(TAdapter adapter, byte[] message, Exception exception) where TAdapter : IReadWriteAdapter + { + _framer!.WriteHeader.MessageId = FrameHeader.HandshakeErrId; + + if (IsLogonDeniedException(exception)) + { + exception = new InvalidCredentialException(IsServer ? SR.net_auth_bad_client_creds : SR.net_auth_bad_client_creds_or_target_mismatch, exception); + } - ProcessWrite(buffer, offset, count, asyncRequest); - return bufferResult; -#if DEBUG + if (!(exception is AuthenticationException)) + { + exception = new AuthenticationException(SR.net_auth_SSPI, exception); } -#endif + + await _framer.WriteMessageAsync(adapter, message).ConfigureAwait(false); + + _canRetryAuthentication = true; + ExceptionDispatchInfo.Throw(exception); } - public override void EndWrite(IAsyncResult asyncResult) + private static bool IsError(SecurityStatusPal status) => + (int)status.ErrorCode >= (int)SecurityStatusPalErrorCode.OutOfMemory; + + private unsafe byte[]? GetOutgoingBlob(byte[]? incomingBlob, ref Exception? e) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User)) + Debug.Assert(_context != null); + + byte[]? message = _context.GetOutgoingBlob(incomingBlob, false, out SecurityStatusPal statusCode); + + if (IsError(statusCode)) { -#endif - _negoState.CheckThrow(true); + e = NegotiateStreamPal.CreateExceptionFromError(statusCode); + uint error = (uint)e.HResult; - if (!_negoState.CanGetSecureStream) + message = new byte[sizeof(long)]; + for (int i = message.Length - 1; i >= 0; --i) { - TaskToApm.End(asyncResult); - return; + message[i] = (byte)(error & 0xFF); + error >>= 8; } + } - if (asyncResult == null) - { - throw new ArgumentNullException(nameof(asyncResult)); - } + if (message != null && message.Length == 0) + { + message = s_emptyMessage; + } - BufferAsyncResult? bufferResult = asyncResult as BufferAsyncResult; - if (bufferResult == null) - { - throw new ArgumentException(SR.Format(SR.net_io_async_result, asyncResult.GetType().FullName), nameof(asyncResult)); - } + return message; + } - if (Interlocked.Exchange(ref _NestedWrite, 0) == 0) - { - throw new InvalidOperationException(SR.Format(SR.net_io_invalidendcall, "EndWrite")); - } + private int EncryptData(ReadOnlySpan buffer, [NotNull] ref byte[]? outBuffer) + { + Debug.Assert(_context != null); + ThrowIfFailed(authSuccessCheck: true); - // No "artificial" timeouts implemented so far, InnerStream controls timeout. - bufferResult.InternalWaitForCompletion(); + // SSPI seems to ignore this sequence number. + ++_writeSequenceNumber; + return _context.Encrypt(buffer, ref outBuffer, _writeSequenceNumber); + } - if (bufferResult.Result is Exception e) - { - if (e is IOException) - { - ExceptionDispatchInfo.Throw(e); - } + private int DecryptData(byte[] buffer, int offset, int count, out int newOffset) + { + Debug.Assert(_context != null); + ThrowIfFailed(authSuccessCheck: true); - throw new IOException(SR.net_io_write, e); - } -#if DEBUG - } -#endif + // SSPI seems to ignore this sequence number. + ++_readSequenceNumber; + return _context.Decrypt(buffer, offset, count, out newOffset, _readSequenceNumber); + } + + private static void ThrowCredentialException(long error) + { + var e = new Win32Exception((int)error); + throw e.NativeErrorCode switch + { + (int)SecurityStatusPalErrorCode.LogonDenied => new InvalidCredentialException(SR.net_auth_bad_client_creds, e), + ERROR_TRUST_FAILURE => new AuthenticationException(SR.net_auth_context_expectation_remote, e), + _ => new AuthenticationException(SR.net_auth_alert, e) + }; } + + private static bool IsLogonDeniedException(Exception exception) => + exception is Win32Exception win32exception && + win32exception.NativeErrorCode == (int)SecurityStatusPalErrorCode.LogonDenied; } } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/NegotiateStreamPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/Security/NegotiateStreamPal.Windows.cs index a03fe69151f6ee..51d69634b36e5e 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/NegotiateStreamPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/NegotiateStreamPal.Windows.cs @@ -4,6 +4,7 @@ using System.ComponentModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Security; using System.Security.Principal; @@ -85,12 +86,10 @@ internal static void ValidateImpersonationLevel(TokenImpersonationLevel imperson internal static int Encrypt( SafeDeleteContext securityContext, - byte[] buffer, - int offset, - int count, + ReadOnlySpan buffer, bool isConfidential, bool isNtlm, - ref byte[]? output, + [NotNull] ref byte[]? output, uint sequenceNumber) { SecPkgContext_Sizes sizes = default; @@ -101,9 +100,9 @@ internal static int Encrypt( { int maxCount = checked(int.MaxValue - 4 - sizes.cbBlockSize - sizes.cbSecurityTrailer); - if (count > maxCount || count < 0) + if (buffer.Length > maxCount) { - throw new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.net_io_out_range, maxCount)); + throw new ArgumentOutOfRangeException(nameof(buffer.Length), SR.Format(SR.net_io_out_range, maxCount)); } } catch (Exception e) when (!ExceptionCheck.IsFatal(e)) @@ -112,21 +111,21 @@ internal static int Encrypt( throw; } - int resultSize = count + sizes.cbSecurityTrailer + sizes.cbBlockSize; + int resultSize = buffer.Length + sizes.cbSecurityTrailer + sizes.cbBlockSize; if (output == null || output.Length < resultSize + 4) { output = new byte[resultSize + 4]; } // Make a copy of user data for in-place encryption. - Buffer.BlockCopy(buffer, offset, output, 4 + sizes.cbSecurityTrailer, count); + buffer.CopyTo(output.AsSpan(4 + sizes.cbSecurityTrailer)); // Prepare buffers TOKEN(signature), DATA and Padding. ThreeSecurityBuffers buffers = default; var securityBuffer = MemoryMarshal.CreateSpan(ref buffers._item0, 3); securityBuffer[0] = new SecurityBuffer(output, 4, sizes.cbSecurityTrailer, SecurityBufferType.SECBUFFER_TOKEN); - securityBuffer[1] = new SecurityBuffer(output, 4 + sizes.cbSecurityTrailer, count, SecurityBufferType.SECBUFFER_DATA); - securityBuffer[2] = new SecurityBuffer(output, 4 + sizes.cbSecurityTrailer + count, sizes.cbBlockSize, SecurityBufferType.SECBUFFER_PADDING); + securityBuffer[1] = new SecurityBuffer(output, 4 + sizes.cbSecurityTrailer, buffer.Length, SecurityBufferType.SECBUFFER_DATA); + securityBuffer[2] = new SecurityBuffer(output, 4 + sizes.cbSecurityTrailer + buffer.Length, sizes.cbBlockSize, SecurityBufferType.SECBUFFER_PADDING); int errorCode; if (isConfidential) @@ -160,7 +159,7 @@ internal static int Encrypt( } resultSize += securityBuffer[1].size; - if (securityBuffer[2].size != 0 && (forceCopy || resultSize != (count + sizes.cbSecurityTrailer))) + if (securityBuffer[2].size != 0 && (forceCopy || resultSize != (buffer.Length + sizes.cbSecurityTrailer))) { Buffer.BlockCopy(output, securityBuffer[2].offset, output, 4 + resultSize, securityBuffer[2].size); } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs b/src/libraries/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs index 222fba5549dc23..72189aa2428012 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs @@ -14,11 +14,12 @@ namespace System.Net { internal sealed class SafeDeleteSslContext : SafeDeleteContext { + private const int InitialBufferSize = 2048; private SafeSslHandle _sslContext; private Interop.AppleCrypto.SSLReadFunc _readCallback; private Interop.AppleCrypto.SSLWriteFunc _writeCallback; - private Queue _fromConnection = new Queue(); - private Queue _toConnection = new Queue(); + private ArrayBuffer _inputBuffer = new ArrayBuffer(InitialBufferSize); + private ArrayBuffer _outputBuffer = new ArrayBuffer(InitialBufferSize); public SafeSslHandle SslContext => _sslContext; @@ -141,10 +142,12 @@ protected override void Dispose(bool disposing) { if (disposing) { - if (null != _sslContext) + SafeSslHandle sslContext = _sslContext; + if (null != sslContext) { - _sslContext.Dispose(); - _sslContext = null!; + _inputBuffer.Dispose(); + _outputBuffer.Dispose(); + sslContext.Dispose(); } } @@ -153,18 +156,15 @@ protected override void Dispose(bool disposing) private unsafe int WriteToConnection(void* connection, byte* data, void** dataLength) { - ulong toWrite = (ulong)*dataLength; - byte* readFrom = data; + ulong length = (ulong)*dataLength; + Debug.Assert(length <= int.MaxValue); - lock (_toConnection) - { - while (toWrite > 0) - { - _toConnection.Enqueue(*readFrom); - readFrom++; - toWrite--; - } - } + int toWrite = (int)length; + var inputBuffer = new ReadOnlySpan(data, toWrite); + + _outputBuffer.EnsureAvailableSpace(toWrite); + inputBuffer.CopyTo(_outputBuffer.AvailableSpan); + _outputBuffer.Commit(toWrite); // Since we can enqueue everything, no need to re-assign *dataLength. const int noErr = 0; @@ -175,78 +175,51 @@ private unsafe int ReadFromConnection(void* connection, byte* data, void** dataL { const int noErr = 0; const int errSSLWouldBlock = -9803; - ulong toRead = (ulong)*dataLength; if (toRead == 0) { - return noErr; } uint transferred = 0; - lock (_fromConnection) + if (_inputBuffer.ActiveLength == 0) { + *dataLength = (void*)0; + return errSSLWouldBlock; + } - if (_fromConnection.Count == 0) - { - - *dataLength = (void*)0; - return errSSLWouldBlock; - } + int limit = Math.Min((int)toRead, _inputBuffer.ActiveLength); - byte* writePos = data; - - while (transferred < toRead && _fromConnection.Count > 0) - { - *writePos = _fromConnection.Dequeue(); - writePos++; - transferred++; - } - } + _inputBuffer.ActiveSpan.Slice(0, limit).CopyTo(new Span(data, limit)); + _inputBuffer.Discard(limit); + transferred = (uint)limit; *dataLength = (void*)transferred; return noErr; } - internal void Write(byte[] buf, int offset, int count) - { - Debug.Assert(buf != null); - Debug.Assert(offset >= 0); - Debug.Assert(count >= 0); - Debug.Assert(count <= buf.Length - offset); - - Write(buf.AsSpan(offset, count)); - } - internal void Write(ReadOnlySpan buf) { - lock (_fromConnection) - { - foreach (byte b in buf) - { - _fromConnection.Enqueue(b); - } - } + _inputBuffer.EnsureAvailableSpace(buf.Length); + buf.CopyTo(_inputBuffer.AvailableSpan); + _inputBuffer.Commit(buf.Length); } - internal int BytesReadyForConnection => _toConnection.Count; + internal int BytesReadyForConnection => _outputBuffer.ActiveLength; internal byte[]? ReadPendingWrites() { - lock (_toConnection) + if (_outputBuffer.ActiveLength == 0) { - if (_toConnection.Count == 0) - { - return null; - } + return null; + } - byte[] data = _toConnection.ToArray(); - _toConnection.Clear(); + byte[] buffer = _outputBuffer.ActiveSpan.ToArray(); + _outputBuffer.Discard(_outputBuffer.ActiveLength); - return data; - } + return buffer; } internal int ReadPendingWrites(byte[] buf, int offset, int count) @@ -256,17 +229,12 @@ internal int ReadPendingWrites(byte[] buf, int offset, int count) Debug.Assert(count >= 0); Debug.Assert(count <= buf.Length - offset); - lock (_toConnection) - { - int limit = Math.Min(count, _toConnection.Count); + int limit = Math.Min(count, _outputBuffer.ActiveLength); - for (int i = 0; i < limit; i++) - { - buf[offset + i] = _toConnection.Dequeue(); - } + _outputBuffer.ActiveSpan.Slice(0, limit).CopyTo(new Span(buf, offset, limit)); + _outputBuffer.Discard(limit); - return limit; - } + return limit; } private static readonly SslProtocols[] s_orderedSslProtocols = new SslProtocols[5] diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/ReadWriteAdapter.cs b/src/libraries/System.Net.Security/src/System/Net/Security/ReadWriteAdapter.cs new file mode 100644 index 00000000000000..497baeb4ccf6e0 --- /dev/null +++ b/src/libraries/System.Net.Security/src/System/Net/Security/ReadWriteAdapter.cs @@ -0,0 +1,89 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Net.Security +{ + internal interface IReadWriteAdapter + { + ValueTask ReadAsync(Memory buffer); + + ValueTask WriteAsync(byte[] buffer, int offset, int count); + + Task WaitAsync(TaskCompletionSource waiter); + + CancellationToken CancellationToken { get; } + + public async ValueTask ReadAllAsync(Memory buffer) + { + int length = buffer.Length; + + do + { + int bytes = await ReadAsync(buffer).ConfigureAwait(false); + if (bytes == 0) + { + if (!buffer.IsEmpty) + { + throw new IOException(SR.net_io_eof); + } + break; + } + + buffer = buffer.Slice(bytes); + } + while (!buffer.IsEmpty); + + return length; + } + } + + internal readonly struct AsyncReadWriteAdapter : IReadWriteAdapter + { + private readonly Stream _stream; + + public AsyncReadWriteAdapter(Stream stream, CancellationToken cancellationToken) + { + _stream = stream; + CancellationToken = cancellationToken; + } + + public ValueTask ReadAsync(Memory buffer) => + _stream.ReadAsync(buffer, CancellationToken); + + public ValueTask WriteAsync(byte[] buffer, int offset, int count) => + _stream.WriteAsync(new ReadOnlyMemory(buffer, offset, count), CancellationToken); + + public Task WaitAsync(TaskCompletionSource waiter) => waiter.Task; + + public CancellationToken CancellationToken { get; } + } + + internal readonly struct SyncReadWriteAdapter : IReadWriteAdapter + { + private readonly Stream _stream; + + public SyncReadWriteAdapter(Stream stream) => _stream = stream; + + public ValueTask ReadAsync(Memory buffer) => + new ValueTask(_stream.Read(buffer.Span)); + + public ValueTask WriteAsync(byte[] buffer, int offset, int count) + { + _stream.Write(buffer, offset, count); + return default; + } + + public Task WaitAsync(TaskCompletionSource waiter) + { + waiter.Task.GetAwaiter().GetResult(); + return Task.CompletedTask; + } + + public CancellationToken CancellationToken => default; + } +} diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SecureChannel.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SecureChannel.cs index 82aab9fe951968..b770ef26fb78a6 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SecureChannel.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SecureChannel.cs @@ -625,7 +625,7 @@ private bool AcquireClientCredentials(ref byte[]? thumbPrint) // // Acquire Server Side Certificate information and set it on the class. // - private bool AcquireServerCredentials(ref byte[]? thumbPrint, ReadOnlySpan clientHello) + private bool AcquireServerCredentials(ref byte[]? thumbPrint) { if (NetEventSource.IsEnabled) NetEventSource.Enter(this); @@ -639,13 +639,13 @@ private bool AcquireServerCredentials(ref byte[]? thumbPrint, ReadOnlySpan // with .NET Framework), and if neither is set we fall back to using ServerCertificate. if (_sslAuthenticationOptions.ServerCertSelectionDelegate != null) { - string? serverIdentity = SniHelper.GetServerName(clientHello); - localCertificate = _sslAuthenticationOptions.ServerCertSelectionDelegate(serverIdentity); - + localCertificate = _sslAuthenticationOptions.ServerCertSelectionDelegate(_sslAuthenticationOptions.TargetHost); if (localCertificate == null) { throw new AuthenticationException(SR.net_ssl_io_no_server_cert); } + if (NetEventSource.IsEnabled) + NetEventSource.Info(this, "Use delegate selected Cert"); } else if (_sslAuthenticationOptions.CertSelectionDelegate != null) { @@ -784,7 +784,7 @@ private SecurityStatusPal GenerateToken(ReadOnlySpan inputBuffer, ref byte if (_refreshCredentialNeeded) { cachedCreds = _sslAuthenticationOptions.IsServer - ? AcquireServerCredentials(ref thumbPrint, inputBuffer) + ? AcquireServerCredentials(ref thumbPrint) : AcquireClientCredentials(ref thumbPrint); } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SniHelper.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SniHelper.cs index ffbf730e7d9712..db682188997e1b 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SniHelper.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SniHelper.cs @@ -26,13 +26,13 @@ internal class SniHelper // opaque fragment[SSLPlaintext.length]; // } SSLPlaintext; const int ContentTypeOffset = 0; - const int ProtocolVersionOffset = ContentTypeOffset + sizeof(ContentType); + const int ProtocolVersionOffset = ContentTypeOffset + sizeof(TlsContentType); const int LengthOffset = ProtocolVersionOffset + ProtocolVersionSize; const int HandshakeOffset = LengthOffset + sizeof(ushort); // SSL v2's ContentType has 0x80 bit set. // We do not care about SSL v2 here because it does not support client hello extensions - if (sslPlainText.Length < HandshakeOffset || (ContentType)sslPlainText[ContentTypeOffset] != ContentType.Handshake) + if (sslPlainText.Length < HandshakeOffset || (TlsContentType)sslPlainText[ContentTypeOffset] != TlsContentType.Handshake) { return null; } @@ -62,10 +62,10 @@ internal class SniHelper // } body; // } Handshake; const int HandshakeTypeOffset = 0; - const int ClientHelloLengthOffset = HandshakeTypeOffset + sizeof(HandshakeType); + const int ClientHelloLengthOffset = HandshakeTypeOffset + sizeof(TlsHandshakeType); const int ClientHelloOffset = ClientHelloLengthOffset + UInt24Size; - if (sslHandshake.Length < ClientHelloOffset || (HandshakeType)sslHandshake[HandshakeTypeOffset] != HandshakeType.ClientHello) + if (sslHandshake.Length < ClientHelloOffset || (TlsHandshakeType)sslHandshake[HandshakeTypeOffset] != TlsHandshakeType.ClientHello) { return null; } @@ -363,16 +363,6 @@ private static Encoding CreateEncoding() return Encoding.GetEncoding("utf-8", new EncoderExceptionFallback(), new DecoderExceptionFallback()); } - private enum ContentType : byte - { - Handshake = 0x16 - } - - private enum HandshakeType : byte - { - ClientHello = 0x01 - } - private enum ExtensionType : ushort { ServerName = 0x00 diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.Adapters.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.Adapters.cs deleted file mode 100644 index 4995f3fd09bf0e..00000000000000 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.Adapters.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using System.Threading; -using System.Threading.Tasks; - -namespace System.Net.Security -{ - // This contains adapters to allow a single code path for sync/async logic - public partial class SslStream - { - private interface ISslIOAdapter - { - ValueTask ReadAsync(Memory buffer); - ValueTask WriteAsync(byte[] buffer, int offset, int count); - Task WaitAsync(TaskCompletionSource waiter); - CancellationToken CancellationToken { get; } - } - - private readonly struct AsyncSslIOAdapter : ISslIOAdapter - { - private readonly SslStream _sslStream; - private readonly CancellationToken _cancellationToken; - - public AsyncSslIOAdapter(SslStream sslStream, CancellationToken cancellationToken) - { - _cancellationToken = cancellationToken; - _sslStream = sslStream; - } - - public ValueTask ReadAsync(Memory buffer) => _sslStream.InnerStream.ReadAsync(buffer, _cancellationToken); - - public ValueTask WriteAsync(byte[] buffer, int offset, int count) => _sslStream.InnerStream.WriteAsync(new ReadOnlyMemory(buffer, offset, count), _cancellationToken); - - public Task WaitAsync(TaskCompletionSource waiter) => waiter.Task; - - public CancellationToken CancellationToken => _cancellationToken; - } - - private readonly struct SyncSslIOAdapter : ISslIOAdapter - { - private readonly SslStream _sslStream; - - public SyncSslIOAdapter(SslStream sslStream) => _sslStream = sslStream; - - public ValueTask ReadAsync(Memory buffer) => new ValueTask(_sslStream.InnerStream.Read(buffer.Span)); - - public ValueTask WriteAsync(byte[] buffer, int offset, int count) - { - _sslStream.InnerStream.Write(buffer, offset, count); - return default; - } - - public Task WaitAsync(TaskCompletionSource waiter) - { - waiter.Task.Wait(); - return Task.CompletedTask; - } - - public CancellationToken CancellationToken => default; - } - } -} diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs index 600163be36290a..7b9dd62870c4e5 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs @@ -24,24 +24,18 @@ public partial class SslStream private enum Framing { - Unknown = 0, - BeforeSSL3, - SinceSSL3, - Unified, - Invalid + Unknown = 0, // Initial before any frame is processd. + BeforeSSL3, // SSlv2 + SinceSSL3, // SSlv3 & TLS + Unified, // Intermediate on first frame until response is processes. + Invalid // Somthing is wrong. } // This is set on the first packet to figure out the framing style. private Framing _framing = Framing.Unknown; - // SSL3/TLS protocol frames definitions. - private enum FrameType : byte - { - ChangeCipherSpec = 20, - Alert = 21, - Handshake = 22, - AppData = 23 - } + private TlsAlertDescription _lastAlertDescription; + private TlsFrameHandshakeInfo _lastFrame; private readonly object _handshakeLock = new object(); private volatile TaskCompletionSource? _handshakeWaiter; @@ -202,11 +196,11 @@ private SecurityStatusPal PrivateDecryptData(byte[]? buffer, ref int offset, ref if (isAsync) { - result = ForceAuthenticationAsync(new AsyncSslIOAdapter(this, cancellationToken), _context!.IsServer, null, isApm); + result = ForceAuthenticationAsync(new AsyncReadWriteAdapter(InnerStream, cancellationToken), _context!.IsServer, null, isApm); } else { - ForceAuthenticationAsync(new SyncSslIOAdapter(this), _context!.IsServer, null).GetAwaiter().GetResult(); + ForceAuthenticationAsync(new SyncReadWriteAdapter(InnerStream), _context!.IsServer, null).GetAwaiter().GetResult(); result = null; } @@ -217,7 +211,7 @@ private SecurityStatusPal PrivateDecryptData(byte[]? buffer, ref int offset, ref // This is used to reply on re-handshake when received SEC_I_RENEGOTIATE on Read(). // private async Task ReplyOnReAuthenticationAsync(TIOAdapter adapter, byte[]? buffer) - where TIOAdapter : ISslIOAdapter + where TIOAdapter : IReadWriteAdapter { try { @@ -232,7 +226,7 @@ private async Task ReplyOnReAuthenticationAsync(TIOAdapter adapter, // reAuthenticationData is only used on Windows in case of renegotiation. private async Task ForceAuthenticationAsync(TIOAdapter adapter, bool receiveFirst, byte[]? reAuthenticationData, bool isApm = false) - where TIOAdapter : ISslIOAdapter + where TIOAdapter : IReadWriteAdapter { ProtocolToken message; bool handshakeCompleted = false; @@ -274,7 +268,6 @@ private async Task ForceAuthenticationAsync(TIOAdapter adapter, bool { // get ready to receive first frame _handshakeBuffer = new ArrayBuffer(InitialHandshakeBufferSize); - _framing = Framing.Unknown; } while (!handshakeCompleted) @@ -288,6 +281,19 @@ private async Task ForceAuthenticationAsync(TIOAdapter adapter, bool if (message.Failed) { + if (_lastFrame.Header.Type == TlsContentType.Handshake && message.Size == 0) + { + // If we failed without OS sending out alert, inject one here to be consistent across platforms. + byte[] alert = TlsFrameHelper.CreateAlertFrame(_lastFrame.Header.Version, TlsAlertDescription.ProtocolVersion); + await adapter.WriteAsync(alert, 0, alert.Length).ConfigureAwait(false); + } + else if (_lastFrame.Header.Type == TlsContentType.Alert && _lastAlertDescription != TlsAlertDescription.CloseNotify && + message.Status.ErrorCode == SecurityStatusPalErrorCode.IllegalMessage) + { + // Improve generic message and show details if we failed because of TLS Alert. + throw new AuthenticationException(SR.Format(SR.net_auth_tls_alert, _lastAlertDescription.ToString()), message.GetException()); + } + throw new AuthenticationException(SR.net_auth_SSPI, message.GetException()); } else if (message.Status.ErrorCode == SecurityStatusPalErrorCode.OK) @@ -333,7 +339,7 @@ private async Task ForceAuthenticationAsync(TIOAdapter adapter, bool } private async ValueTask ReceiveBlobAsync(TIOAdapter adapter) - where TIOAdapter : ISslIOAdapter + where TIOAdapter : IReadWriteAdapter { int readBytes = await FillHandshakeBufferAsync(adapter, SecureChannel.ReadHeaderSize).ConfigureAwait(false); if (readBytes == 0) @@ -346,17 +352,49 @@ private async ValueTask ReceiveBlobAsync(TIOAdapter a _framing = DetectFraming(_handshakeBuffer.ActiveReadOnlySpan); } - int frameSize = GetFrameSize(_handshakeBuffer.ActiveReadOnlySpan); - if (frameSize < 0) + if (_framing != Framing.SinceSSL3) + { +#pragma warning disable 0618 + _lastFrame.Header.Version = SslProtocols.Ssl2; +#pragma warning restore 0618 + _lastFrame.Header.Length = GetFrameSize(_handshakeBuffer.ActiveReadOnlySpan) - TlsFrameHelper.HeaderSize; + } + else + { + TlsFrameHelper.TryGetFrameHeader(_handshakeBuffer.ActiveReadOnlySpan, ref _lastFrame.Header); + } + + if (_lastFrame.Header.Length < 0) { throw new IOException(SR.net_frame_read_size); } + // Header length is content only so we must add header size as well. + int frameSize = _lastFrame.Header.Length + TlsFrameHelper.HeaderSize; if (_handshakeBuffer.ActiveLength < frameSize) { await FillHandshakeBufferAsync(adapter, frameSize).ConfigureAwait(false); } + // At this point, we have at least one TLS frame. + if (_lastFrame.Header.Type == TlsContentType.Alert) + { + TlsAlertLevel level = 0; + if (TlsFrameHelper.TryGetAlertInfo(_handshakeBuffer.ActiveReadOnlySpan, ref level, ref _lastAlertDescription)) + { + if (NetEventSource.IsEnabled && _lastAlertDescription != TlsAlertDescription.CloseNotify) NetEventSource.Fail(this, $"Received TLS alert {_lastAlertDescription}"); + } + } + else if (_lastFrame.Header.Type == TlsContentType.Handshake) + { + if (_handshakeBuffer.ActiveReadOnlySpan[TlsFrameHelper.HeaderSize] == (byte)TlsHandshakeType.ClientHello && + _sslAuthenticationOptions!.ServerCertSelectionDelegate != null) + { + // Process SNI from Client Hello message + TlsFrameHelper.TryGetHandshakeInfo(_handshakeBuffer.ActiveReadOnlySpan, ref _lastFrame); + _sslAuthenticationOptions.TargetHost = _lastFrame.TargetName; + } + } return ProcessBlob(frameSize); } @@ -371,24 +409,28 @@ private ProtocolToken ProcessBlob(int frameSize) // ActiveSpan will exclude the "discarded" data. _handshakeBuffer.Discard(frameSize); - // Often more TLS messages fit into same packet. Get as many complete frames as we can. - while (_handshakeBuffer.ActiveLength > SecureChannel.ReadHeaderSize) + if (_framing == Framing.SinceSSL3) { - ReadOnlySpan remainingData = _handshakeBuffer.ActiveReadOnlySpan; - if (remainingData[0] >= (int)FrameType.AppData) + // Often more TLS messages fit into same packet. Get as many complete frames as we can. + while (_handshakeBuffer.ActiveLength > TlsFrameHelper.HeaderSize) { - break; - } + TlsFrameHeader nextHeader = default; + + if (!TlsFrameHelper.TryGetFrameHeader(_handshakeBuffer.ActiveReadOnlySpan, ref nextHeader)) + { + break; + } + + frameSize = nextHeader.Length + TlsFrameHelper.HeaderSize; + if (nextHeader.Type == TlsContentType.AppData || frameSize > _handshakeBuffer.ActiveLength) + { + // We don't have full frame left or we already have app data which needs to be processed by decrypt. + break; + } - frameSize = GetFrameSize(remainingData); - if (_handshakeBuffer.ActiveLength >= frameSize) - { chunkSize += frameSize; _handshakeBuffer.Discard(frameSize); - continue; } - - break; } return _context!.NextMessage(availableData.Slice(0, chunkSize)); @@ -447,7 +489,7 @@ private bool CompleteHandshake(ref ProtocolToken? alertToken) } private async ValueTask WriteAsyncChunked(TIOAdapter writeAdapter, ReadOnlyMemory buffer) - where TIOAdapter : struct, ISslIOAdapter + where TIOAdapter : struct, IReadWriteAdapter { do { @@ -458,7 +500,7 @@ private async ValueTask WriteAsyncChunked(TIOAdapter writeAdapter, R } private ValueTask WriteSingleChunk(TIOAdapter writeAdapter, ReadOnlyMemory buffer) - where TIOAdapter : struct, ISslIOAdapter + where TIOAdapter : struct, IReadWriteAdapter { byte[] rentedBuffer = ArrayPool.Shared.Rent(buffer.Length + FrameOverhead); byte[] outBuffer = rentedBuffer; @@ -604,7 +646,7 @@ private void ReturnReadBufferIfEmpty() } private async ValueTask ReadAsyncInternal(TIOAdapter adapter, Memory buffer) - where TIOAdapter : ISslIOAdapter + where TIOAdapter : IReadWriteAdapter { if (Interlocked.Exchange(ref _nestedRead, 1) == 1) { @@ -751,7 +793,7 @@ private async ValueTask ReadAsyncInternal(TIOAdapter adapter, M // If we have enough data, it returns synchronously. If not, it will try to read // remaining bytes from given stream. private ValueTask FillHandshakeBufferAsync(TIOAdapter adapter, int minSize) - where TIOAdapter : ISslIOAdapter + where TIOAdapter : IReadWriteAdapter { if (_handshakeBuffer.ActiveLength >= minSize) { @@ -801,7 +843,7 @@ async ValueTask InternalFillHandshakeBufferAsync(TIOAdapter adap, ValueTas } private async ValueTask FillBufferAsync(TIOAdapter adapter, int numBytesRequired) - where TIOAdapter : ISslIOAdapter + where TIOAdapter : IReadWriteAdapter { Debug.Assert(_internalBufferCount > 0); Debug.Assert(_internalBufferCount < numBytesRequired); @@ -819,7 +861,7 @@ private async ValueTask FillBufferAsync(TIOAdapter adapter, int numB } private async ValueTask WriteAsyncInternal(TIOAdapter writeAdapter, ReadOnlyMemory buffer) - where TIOAdapter : struct, ISslIOAdapter + where TIOAdapter : struct, IReadWriteAdapter { ThrowIfExceptionalOrNotAuthenticatedOrShutdown(); @@ -913,6 +955,7 @@ private static byte[] EnsureBufferSize(byte[] buffer, int copyCount, int size) Buffer.BlockCopy(saved, 0, buffer, 0, copyCount); } } + return buffer; } @@ -1003,8 +1046,8 @@ private Framing DetectFraming(ReadOnlySpan bytes) } // If the first byte is SSL3 HandShake, then check if we have a SSLv3 Type3 client hello. - if (bytes[0] == (byte)FrameType.Handshake || bytes[0] == (byte)FrameType.AppData - || bytes[0] == (byte)FrameType.Alert) + if (bytes[0] == (byte)TlsContentType.Handshake || bytes[0] == (byte)TlsContentType.AppData + || bytes[0] == (byte)TlsContentType.Alert) { if (bytes.Length < 3) { diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs index 73f4417dacc215..f3638799d77324 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.cs @@ -304,8 +304,13 @@ public virtual void AuthenticateAsClient(string targetHost, X509CertificateColle AuthenticateAsClient(options); } - private void AuthenticateAsClient(SslClientAuthenticationOptions sslClientAuthenticationOptions) + public void AuthenticateAsClient(SslClientAuthenticationOptions sslClientAuthenticationOptions) { + if (sslClientAuthenticationOptions == null) + { + throw new ArgumentNullException(nameof(sslClientAuthenticationOptions)); + } + SetAndVerifyValidationCallback(sslClientAuthenticationOptions.RemoteCertificateValidationCallback); SetAndVerifySelectionCallback(sslClientAuthenticationOptions.LocalCertificateSelectionCallback); @@ -337,8 +342,13 @@ public virtual void AuthenticateAsServer(X509Certificate serverCertificate, bool AuthenticateAsServer(options); } - private void AuthenticateAsServer(SslServerAuthenticationOptions sslServerAuthenticationOptions) + public void AuthenticateAsServer(SslServerAuthenticationOptions sslServerAuthenticationOptions) { + if (sslServerAuthenticationOptions == null) + { + throw new ArgumentNullException(nameof(sslServerAuthenticationOptions)); + } + SetAndVerifyValidationCallback(sslServerAuthenticationOptions.RemoteCertificateValidationCallback); ValidateCreateContext(CreateAuthenticationOptions(sslServerAuthenticationOptions)); @@ -367,6 +377,11 @@ public virtual Task AuthenticateAsClientAsync(string targetHost, X509Certificate public Task AuthenticateAsClientAsync(SslClientAuthenticationOptions sslClientAuthenticationOptions, CancellationToken cancellationToken = default) { + if (sslClientAuthenticationOptions == null) + { + throw new ArgumentNullException(nameof(sslClientAuthenticationOptions)); + } + SetAndVerifyValidationCallback(sslClientAuthenticationOptions.RemoteCertificateValidationCallback); SetAndVerifySelectionCallback(sslClientAuthenticationOptions.LocalCertificateSelectionCallback); @@ -417,6 +432,11 @@ public virtual Task AuthenticateAsServerAsync(X509Certificate serverCertificate, public Task AuthenticateAsServerAsync(SslServerAuthenticationOptions sslServerAuthenticationOptions, CancellationToken cancellationToken = default) { + if (sslServerAuthenticationOptions == null) + { + throw new ArgumentNullException(nameof(sslServerAuthenticationOptions)); + } + SetAndVerifyValidationCallback(sslServerAuthenticationOptions.RemoteCertificateValidationCallback); ValidateCreateContext(CreateAuthenticationOptions(sslServerAuthenticationOptions)); @@ -742,8 +762,7 @@ public override int Read(byte[] buffer, int offset, int count) { ThrowIfExceptionalOrNotAuthenticated(); ValidateParameters(buffer, offset, count); - SyncSslIOAdapter reader = new SyncSslIOAdapter(this); - ValueTask vt = ReadAsyncInternal(reader, new Memory(buffer, offset, count)); + ValueTask vt = ReadAsyncInternal(new SyncReadWriteAdapter(InnerStream), new Memory(buffer, offset, count)); Debug.Assert(vt.IsCompleted, "Sync operation must have completed synchronously"); return vt.GetAwaiter().GetResult(); } @@ -755,8 +774,7 @@ public override void Write(byte[] buffer, int offset, int count) ThrowIfExceptionalOrNotAuthenticated(); ValidateParameters(buffer, offset, count); - SyncSslIOAdapter writeAdapter = new SyncSslIOAdapter(this); - ValueTask vt = WriteAsyncInternal(writeAdapter, new ReadOnlyMemory(buffer, offset, count)); + ValueTask vt = WriteAsyncInternal(new SyncReadWriteAdapter(InnerStream), new ReadOnlyMemory(buffer, offset, count)); Debug.Assert(vt.IsCompleted, "Sync operation must have completed synchronously"); vt.GetAwaiter().GetResult(); } @@ -792,26 +810,23 @@ public override Task WriteAsync(byte[] buffer, int offset, int count, Cancellati return WriteAsync(new ReadOnlyMemory(buffer, offset, count), cancellationToken).AsTask(); } - public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken) + public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) { ThrowIfExceptionalOrNotAuthenticated(); - AsyncSslIOAdapter writeAdapter = new AsyncSslIOAdapter(this, cancellationToken); - return WriteAsyncInternal(writeAdapter, buffer); + return WriteAsyncInternal(new AsyncReadWriteAdapter(InnerStream, cancellationToken), buffer); } public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { ThrowIfExceptionalOrNotAuthenticated(); ValidateParameters(buffer, offset, count); - AsyncSslIOAdapter read = new AsyncSslIOAdapter(this, cancellationToken); - return ReadAsyncInternal(read, new Memory(buffer, offset, count)).AsTask(); + return ReadAsyncInternal(new AsyncReadWriteAdapter(InnerStream, cancellationToken), new Memory(buffer, offset, count)).AsTask(); } public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) { ThrowIfExceptionalOrNotAuthenticated(); - AsyncSslIOAdapter read = new AsyncSslIOAdapter(this, cancellationToken); - return ReadAsyncInternal(read, buffer); + return ReadAsyncInternal(new AsyncReadWriteAdapter(InnerStream, cancellationToken), buffer); } private void ThrowIfExceptional() diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs index 7c6d13ac22bd69..3cf26e783a9d06 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs @@ -92,16 +92,11 @@ public static SecurityStatusPal EncryptMessage( MemoryHandle memHandle = input.Pin(); try { - PAL_TlsIo status; - - lock (sslHandle) - { - status = Interop.AppleCrypto.SslWrite( + PAL_TlsIo status = Interop.AppleCrypto.SslWrite( sslHandle, (byte*)memHandle.Pointer, input.Length, out int written); - } if (status < 0) { @@ -154,19 +149,13 @@ public static SecurityStatusPal DecryptMessage( SafeDeleteSslContext sslContext = (SafeDeleteSslContext)securityContext; SafeSslHandle sslHandle = sslContext.SslContext; - sslContext.Write(buffer, offset, count); + sslContext.Write(buffer.AsSpan(offset, count)); unsafe { fixed (byte* offsetInput = &buffer[offset]) { - int written; - PAL_TlsIo status; - - lock (sslHandle) - { - status = Interop.AppleCrypto.SslRead(sslHandle, offsetInput, count, out written); - } + PAL_TlsIo status = Interop.AppleCrypto.SslRead(sslHandle, offsetInput, count, out int written); if (status < 0) { @@ -248,9 +237,8 @@ private static SecurityStatusPal HandshakeInternal( sslContext = new SafeDeleteSslContext((credential as SafeFreeSslCredentials)!, sslAuthenticationOptions); context = sslContext; - if (!string.IsNullOrEmpty(sslAuthenticationOptions.TargetHost)) + if (!string.IsNullOrEmpty(sslAuthenticationOptions.TargetHost) && !sslAuthenticationOptions.IsServer) { - Debug.Assert(!sslAuthenticationOptions.IsServer, "targetName should not be set for server-side handshakes"); Interop.AppleCrypto.SslSetTargetName(sslContext.SslContext, sslAuthenticationOptions.TargetHost); } @@ -266,12 +254,7 @@ private static SecurityStatusPal HandshakeInternal( } SafeSslHandle sslHandle = sslContext!.SslContext; - SecurityStatusPal status; - - lock (sslHandle) - { - status = PerformHandshake(sslHandle); - } + SecurityStatusPal status = PerformHandshake(sslHandle); outputBuffer = sslContext.ReadPendingWrites(); return status; @@ -329,12 +312,8 @@ public static SecurityStatusPal ApplyShutdownToken( { SafeDeleteSslContext sslContext = ((SafeDeleteSslContext)securityContext); SafeSslHandle sslHandle = sslContext.SslContext; - int osStatus; - lock (sslHandle) - { - osStatus = Interop.AppleCrypto.SslShutdown(sslHandle); - } + int osStatus = Interop.AppleCrypto.SslShutdown(sslHandle); if (osStatus == 0) { diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/TlsFrameHelper.cs b/src/libraries/System.Net.Security/src/System/Net/Security/TlsFrameHelper.cs new file mode 100644 index 00000000000000..58906a3dda740c --- /dev/null +++ b/src/libraries/System.Net.Security/src/System/Net/Security/TlsFrameHelper.cs @@ -0,0 +1,239 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Security.Authentication; + +namespace System.Net.Security +{ + // SSL3/TLS protocol frames definitions. + internal enum TlsContentType : byte + { + ChangeCipherSpec = 20, + Alert = 21, + Handshake = 22, + AppData = 23 + } + + internal enum TlsHandshakeType : byte + { + HelloRequest = 0, + ClientHello = 1, + ServerHello = 2, + NewSessionTicket = 4, + EndOfEarlyData = 5, + EncryptedExtensions = 8, + Certificate = 11, + ServerKeyExchange = 12, + CertificateRequest = 13, + ServerHelloDone = 14, + CertificateVerify = 15, + ClientKeyExchange = 16, + Finished = 20, + KeyEpdate = 24, + MessageHash = 254 + } + + internal enum TlsAlertLevel : byte + { + Warning = 1, + Fatal = 2, + } + + internal enum TlsAlertDescription : byte + { + CloseNotify = 0, // warning + UnexpectedMessage = 10, // error + BadRecordMac = 20, // error + DecryptionFailed = 21, // reserved + RecordOverflow = 22, // error + DecompressionFail = 30, // error + HandshakeFailure = 40, // error + BadCertificate = 42, // warning or error + UnsupportedCert = 43, // warning or error + CertificateRevoked = 44, // warning or error + CertificateExpired = 45, // warning or error + CertificateUnknown = 46, // warning or error + IllegalParameter = 47, // error + UnknownCA = 48, // error + AccessDenied = 49, // error + DecodeError = 50, // error + DecryptError = 51, // error + ExportRestriction = 60, // reserved + ProtocolVersion = 70, // error + InsuffientSecurity = 71, // error + InternalError = 80, // error + UserCanceled = 90, // warning or error + NoRenegotiation = 100, // warning + UnsupportedExt = 110, // error + } + + internal struct TlsFrameHeader + { + public TlsContentType Type; + public SslProtocols Version; + public int Length; + } + + internal struct TlsFrameHandshakeInfo + { + public TlsFrameHeader Header; + public TlsHandshakeType HandshakeType; + public SslProtocols SupportedVersions; + public string? TargetName; + } + + internal class TlsFrameHelper + { + public const int HeaderSize = 5; + + private static byte[] s_protocolMismatch13 = new byte[] { (byte)TlsContentType.Alert, 3, 4, 0, 2, 2, 70 }; + private static byte[] s_protocolMismatch12 = new byte[] { (byte)TlsContentType.Alert, 3, 3, 0, 2, 2, 70 }; + private static byte[] s_protocolMismatch11 = new byte[] { (byte)TlsContentType.Alert, 3, 2, 0, 2, 2, 70 }; + private static byte[] s_protocolMismatch10 = new byte[] { (byte)TlsContentType.Alert, 3, 1, 0, 2, 2, 70 }; + private static byte[] s_protocolMismatch30 = new byte[] { (byte)TlsContentType.Alert, 3, 0, 0, 2, 2, 40 }; + + public static bool TryGetFrameHeader(ReadOnlySpan frame, ref TlsFrameHeader header) + { + bool result = frame.Length > 4; + + if (frame.Length >= 1) + { + header.Type = (TlsContentType)frame[0]; + + if (frame.Length >= 3) + { + // SSLv3, TLS or later + if (frame[1] == 3) + { + if (frame.Length > 4) + { + header.Length = ((frame[3] << 8) | frame[4]); + } + + switch (frame[2]) + { + case 4: + header.Version = SslProtocols.Tls13; + break; + case 3: + header.Version = SslProtocols.Tls12; + break; + case 2: + header.Version = SslProtocols.Tls11; + break; + case 1: + header.Version = SslProtocols.Tls; + break; + case 0: +#pragma warning disable 0618 + header.Version = SslProtocols.Ssl3; +#pragma warning restore 0618 + break; + default: + header.Version = SslProtocols.None; + break; + } + } + else + { + header.Length = -1; + header.Version = SslProtocols.None; + } + } + } + + return result; + } + + // Returns frame size e.g. header + content + public static int GetFrameSize(ReadOnlySpan frame) + { + if (frame.Length < 5 || frame[1] < 3) + { + return - 1; + } + + return ((frame[3] << 8) | frame[4]) + HeaderSize; + } + + public static bool TryGetHandshakeInfo(ReadOnlySpan frame, ref TlsFrameHandshakeInfo info) + { + if (frame.Length < 6 || frame[0] != (byte)TlsContentType.Handshake) + { + return false; + } + + // This will not fail since we have enough data. + bool gotHeader = TryGetFrameHeader(frame, ref info.Header); + Debug.Assert(gotHeader); + + info.SupportedVersions = info.Header.Version; + + info.HandshakeType = (TlsHandshakeType)frame[5]; + + if (info.HandshakeType == TlsHandshakeType.ClientHello) + { + info.TargetName = SniHelper.GetServerName(frame); + } + + return true; + } + + public static bool TryGetAlertInfo(ReadOnlySpan frame, ref TlsAlertLevel level, ref TlsAlertDescription description) + { + if (frame.Length < 7 || frame[0] != (byte)TlsContentType.Alert) + { + return false; + } + + level = (TlsAlertLevel)frame[5]; + description = (TlsAlertDescription)frame[6]; + + return true; + } + + private static byte[] CreateProtocolVersionAlert(SslProtocols version) => + version switch + { + SslProtocols.Tls13 => s_protocolMismatch13, + SslProtocols.Tls12 => s_protocolMismatch12, + SslProtocols.Tls11 => s_protocolMismatch11, + SslProtocols.Tls => s_protocolMismatch10, +#pragma warning disable 0618 + SslProtocols.Ssl3 => s_protocolMismatch30, +#pragma warning restore 0618 + _ => Array.Empty(), + }; + + public static byte[] CreateAlertFrame(SslProtocols version, TlsAlertDescription reason) + { + if (reason == TlsAlertDescription.ProtocolVersion) + { + return CreateProtocolVersionAlert(version); + } + else if ((int)version > (int)SslProtocols.Tls) + { + // Create TLS1.2 alert + byte[] buffer = new byte[] { (byte)TlsContentType.Alert, 3, 3, 0, 2, 2, (byte)reason }; + switch (version) + { + case SslProtocols.Tls13: + buffer[2] = 4; + break; + case SslProtocols.Tls11: + buffer[2] = 2; + break; + case SslProtocols.Tls: + buffer[2] = 1; + break; + } + + return buffer; + } + + return Array.Empty(); + } + } +} diff --git a/src/libraries/System.Net.Security/src/System/Net/SslStreamContext.cs b/src/libraries/System.Net.Security/src/System/Net/SslStreamContext.cs index eda52c9d784ef9..338e3c84434b5a 100644 --- a/src/libraries/System.Net.Security/src/System/Net/SslStreamContext.cs +++ b/src/libraries/System.Net.Security/src/System/Net/SslStreamContext.cs @@ -2,28 +2,23 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics; using System.Net.Security; using System.Security.Authentication.ExtendedProtection; namespace System.Net { - internal class SslStreamContext : TransportContext + internal sealed class SslStreamContext : TransportContext { + private readonly SslStream _sslStream; + internal SslStreamContext(SslStream sslStream) { - if (sslStream == null) - { - NetEventSource.Fail(this, "Not expecting a null sslStream!"); - } - + Debug.Assert(sslStream != null); _sslStream = sslStream!; } - public override ChannelBinding? GetChannelBinding(ChannelBindingKind kind) - { - return _sslStream.GetChannelBinding(kind); - } - - private readonly SslStream _sslStream; + public override ChannelBinding? GetChannelBinding(ChannelBindingKind kind) => + _sslStream.GetChannelBinding(kind); } } diff --git a/src/libraries/System.Net.Security/src/System/Net/StreamFramer.cs b/src/libraries/System.Net.Security/src/System/Net/StreamFramer.cs index dc494ca17e1b0b..264fb4d6accfdc 100644 --- a/src/libraries/System.Net.Security/src/System/Net/StreamFramer.cs +++ b/src/libraries/System.Net.Security/src/System/Net/StreamFramer.cs @@ -4,83 +4,37 @@ using System.IO; using System.Globalization; -using System.Runtime.ExceptionServices; +using System.Net.Security; using System.Threading.Tasks; namespace System.Net { - internal class StreamFramer + internal sealed class StreamFramer { - private readonly Stream _transport; - - private bool _eof; - private readonly FrameHeader _writeHeader = new FrameHeader(); private readonly FrameHeader _curReadHeader = new FrameHeader(); - private readonly FrameHeader _readVerifier = new FrameHeader( - FrameHeader.IgnoreValue, - FrameHeader.IgnoreValue, - FrameHeader.IgnoreValue); - - private readonly byte[] _readHeaderBuffer; - private readonly byte[] _writeHeaderBuffer; - private readonly AsyncCallback _readFrameCallback; - private readonly AsyncCallback _beginWriteCallback; - - public StreamFramer(Stream Transport) - { - if (Transport == null || Transport == Stream.Null) - { - throw new ArgumentNullException(nameof(Transport)); - } - - _transport = Transport; - _readHeaderBuffer = new byte[_curReadHeader.Size]; - _writeHeaderBuffer = new byte[_writeHeader.Size]; - - _readFrameCallback = new AsyncCallback(ReadFrameCallback); - _beginWriteCallback = new AsyncCallback(BeginWriteCallback); - } - - public FrameHeader ReadHeader - { - get - { - return _curReadHeader; - } - } - - public FrameHeader WriteHeader - { - get - { - return _writeHeader; - } - } + private readonly byte[] _readHeaderBuffer = new byte[FrameHeader.Size]; + private readonly byte[] _writeHeaderBuffer = new byte[FrameHeader.Size]; + private bool _eof; - public Stream Transport - { - get - { - return _transport; - } - } + public FrameHeader ReadHeader => _curReadHeader; + public FrameHeader WriteHeader => _writeHeader; - public byte[]? ReadMessage() + public async ValueTask ReadMessageAsync(TAdapter adapter) where TAdapter : IReadWriteAdapter { if (_eof) { return null; } - int offset = 0; byte[] buffer = _readHeaderBuffer; int bytesRead; + int offset = 0; while (offset < buffer.Length) { - bytesRead = Transport.Read(buffer, offset, buffer.Length - offset); + bytesRead = await adapter.ReadAsync(buffer.AsMemory(offset)).ConfigureAwait(false); if (bytesRead == 0) { if (offset == 0) @@ -89,20 +43,18 @@ public Stream Transport _eof = true; return null; } - else - { - throw new IOException(SR.Format(SR.net_io_readfailure, SR.net_io_connectionclosed)); - } + + throw new IOException(SR.Format(SR.net_io_readfailure, SR.net_io_connectionclosed)); } offset += bytesRead; } - _curReadHeader.CopyFrom(buffer, 0, _readVerifier); - if (_curReadHeader.PayloadSize > _curReadHeader.MaxMessageSize) + _curReadHeader.CopyFrom(buffer, 0); + if (_curReadHeader.PayloadSize > FrameHeader.MaxMessageSize) { throw new InvalidOperationException(SR.Format(SR.net_frame_size, - _curReadHeader.MaxMessageSize.ToString(NumberFormatInfo.InvariantInfo), + FrameHeader.MaxMessageSize, _curReadHeader.PayloadSize.ToString(NumberFormatInfo.InvariantInfo))); } @@ -111,7 +63,7 @@ public Stream Transport offset = 0; while (offset < buffer.Length) { - bytesRead = Transport.Read(buffer, offset, buffer.Length - offset); + bytesRead = await adapter.ReadAsync(buffer.AsMemory(offset)).ConfigureAwait(false); if (bytesRead == 0) { throw new IOException(SR.Format(SR.net_io_readfailure, SR.net_io_connectionclosed)); @@ -122,226 +74,7 @@ public Stream Transport return buffer; } - public IAsyncResult BeginReadMessage(AsyncCallback asyncCallback, object stateObject) - { - WorkerAsyncResult workerResult; - - if (_eof) - { - workerResult = new WorkerAsyncResult(this, stateObject, asyncCallback, null, 0, 0); - workerResult.InvokeCallback(-1); - return workerResult; - } - - workerResult = new WorkerAsyncResult(this, stateObject, asyncCallback, - _readHeaderBuffer, 0, - _readHeaderBuffer.Length); - - IAsyncResult result = TaskToApm.Begin(_transport.ReadAsync(_readHeaderBuffer, 0, _readHeaderBuffer.Length), - _readFrameCallback, workerResult); - - if (result.CompletedSynchronously) - { - ReadFrameComplete(result); - } - - return workerResult; - } - - private void ReadFrameCallback(IAsyncResult transportResult) - { - if (!(transportResult.AsyncState is WorkerAsyncResult)) - { - NetEventSource.Fail(this, $"The state expected to be WorkerAsyncResult, received {transportResult}."); - } - - if (transportResult.CompletedSynchronously) - { - return; - } - - WorkerAsyncResult workerResult = (WorkerAsyncResult)transportResult.AsyncState!; - - try - { - ReadFrameComplete(transportResult); - } - catch (Exception e) - { - if (e is OutOfMemoryException) - { - throw; - } - - if (!(e is IOException)) - { - e = new System.IO.IOException(SR.Format(SR.net_io_readfailure, e.Message), e); - } - - workerResult.InvokeCallback(e); - } - } - - // IO COMPLETION CALLBACK - // - // This callback is responsible for getting the complete protocol frame. - // 1. it reads the header. - // 2. it determines the frame size. - // 3. loops while not all frame received or an error. - // - private void ReadFrameComplete(IAsyncResult transportResult) - { - do - { - if (!(transportResult.AsyncState is WorkerAsyncResult)) - { - NetEventSource.Fail(this, $"The state expected to be WorkerAsyncResult, received {transportResult}."); - } - - WorkerAsyncResult workerResult = (WorkerAsyncResult)transportResult.AsyncState!; - - int bytesRead = TaskToApm.End(transportResult); - workerResult.Offset += bytesRead; - - if (!(workerResult.Offset <= workerResult.End)) - { - NetEventSource.Fail(this, $"WRONG: offset - end = {workerResult.Offset - workerResult.End}"); - } - - if (bytesRead <= 0) - { - // (by design) This indicates the stream has receives EOF - // If we are in the middle of a Frame - fail, otherwise - produce EOF - object? result = null; - if (!workerResult.HeaderDone && workerResult.Offset == 0) - { - result = (object)-1; - } - else - { - result = new System.IO.IOException(SR.net_frame_read_io); - } - - workerResult.InvokeCallback(result); - return; - } - - if (workerResult.Offset >= workerResult.End) - { - if (!workerResult.HeaderDone) - { - workerResult.HeaderDone = true; - // This indicates the header has been read successfully - _curReadHeader.CopyFrom(workerResult.Buffer!, 0, _readVerifier); - int payloadSize = _curReadHeader.PayloadSize; - if (payloadSize < 0) - { - // Let's call user callback and they call us back and we will throw - workerResult.InvokeCallback(new System.IO.IOException(SR.net_frame_read_size)); - } - - if (payloadSize == 0) - { - // report empty frame (NOT eof!) to the caller, he might be interested in - workerResult.InvokeCallback(0); - return; - } - - if (payloadSize > _curReadHeader.MaxMessageSize) - { - throw new InvalidOperationException(SR.Format(SR.net_frame_size, - _curReadHeader.MaxMessageSize.ToString(NumberFormatInfo.InvariantInfo), - payloadSize.ToString(NumberFormatInfo.InvariantInfo))); - } - - // Start reading the remaining frame data (note header does not count). - byte[] frame = new byte[payloadSize]; - // Save the ref of the data block - workerResult.Buffer = frame; - workerResult.End = frame.Length; - workerResult.Offset = 0; - - // Transport.ReadAsync below will pickup those changes. - } - else - { - workerResult.HeaderDone = false; // Reset for optional object reuse. - workerResult.InvokeCallback(workerResult.End); - return; - } - } - - // This means we need more data to complete the data block. - transportResult = TaskToApm.Begin(_transport.ReadAsync(workerResult.Buffer!, workerResult.Offset, workerResult.End - workerResult.Offset), - _readFrameCallback, workerResult); - } while (transportResult.CompletedSynchronously); - } - - // - // User code will call this when workerResult gets signaled. - // - // On BeginRead, the user always gets back our WorkerAsyncResult. - // The Result property represents either a number of bytes read or an - // exception put by our async state machine. - // - public byte[]? EndReadMessage(IAsyncResult asyncResult) - { - if (asyncResult == null) - { - throw new ArgumentNullException(nameof(asyncResult)); - } - WorkerAsyncResult? workerResult = asyncResult as WorkerAsyncResult; - - if (workerResult == null) - { - throw new ArgumentException(SR.Format(SR.net_io_async_result, typeof(WorkerAsyncResult).FullName), nameof(asyncResult)); - } - - if (!workerResult.InternalPeekCompleted) - { - workerResult.InternalWaitForCompletion(); - } - - if (workerResult.Result is Exception e) - { - ExceptionDispatchInfo.Throw(e); - } - - int size = (int)workerResult.Result!; - if (size == -1) - { - _eof = true; - return null; - } - else if (size == 0) - { - // Empty frame. - return Array.Empty(); - } - - return workerResult.Buffer; - } - - public void WriteMessage(byte[] message) - { - if (message == null) - { - throw new ArgumentNullException(nameof(message)); - } - - _writeHeader.PayloadSize = message.Length; - _writeHeader.CopyTo(_writeHeaderBuffer, 0); - - Transport.Write(_writeHeaderBuffer, 0, _writeHeaderBuffer.Length); - if (message.Length == 0) - { - return; - } - - Transport.Write(message, 0, message.Length); - } - - public IAsyncResult BeginWriteMessage(byte[] message, AsyncCallback asyncCallback, object stateObject) + public async Task WriteMessageAsync(TAdapter adapter, byte[] message) where TAdapter : IReadWriteAdapter { if (message == null) { @@ -351,141 +84,16 @@ public IAsyncResult BeginWriteMessage(byte[] message, AsyncCallback asyncCallbac _writeHeader.PayloadSize = message.Length; _writeHeader.CopyTo(_writeHeaderBuffer, 0); - if (message.Length == 0) - { - return TaskToApm.Begin(_transport.WriteAsync(_writeHeaderBuffer, 0, _writeHeaderBuffer.Length), - asyncCallback, stateObject); - } - - // Will need two async writes. Prepare the second: - WorkerAsyncResult workerResult = new WorkerAsyncResult(this, stateObject, asyncCallback, - message, 0, message.Length); - - // Charge the first: - IAsyncResult result = TaskToApm.Begin(_transport.WriteAsync(_writeHeaderBuffer, 0, _writeHeaderBuffer.Length), - _beginWriteCallback, workerResult); - - if (result.CompletedSynchronously) - { - BeginWriteComplete(result); - } - - return workerResult; - } - - private void BeginWriteCallback(IAsyncResult transportResult) - { - if (!(transportResult.AsyncState is WorkerAsyncResult)) - { - NetEventSource.Fail(this, $"The state expected to be WorkerAsyncResult, received {transportResult}."); - } - - if (transportResult.CompletedSynchronously) - { - return; - } - - var workerResult = (WorkerAsyncResult)transportResult.AsyncState!; - - try - { - BeginWriteComplete(transportResult); - } - catch (Exception e) - { - if (e is OutOfMemoryException) - { - throw; - } - - workerResult.InvokeCallback(e); - } - } - - // IO COMPLETION CALLBACK - // - // Called when user IO request was wrapped to do several underlined IO. - // - private void BeginWriteComplete(IAsyncResult transportResult) - { - do - { - WorkerAsyncResult workerResult = (WorkerAsyncResult)transportResult.AsyncState!; - - // First, complete the previous portion write. - TaskToApm.End(transportResult); - - // Check on exit criterion. - if (workerResult.Offset == workerResult.End) - { - workerResult.InvokeCallback(); - return; - } - - // Setup exit criterion. - workerResult.Offset = workerResult.End; - - // Write next portion (frame body) using Async IO. - transportResult = TaskToApm.Begin(_transport.WriteAsync(workerResult.Buffer!, 0, workerResult.End), - _beginWriteCallback, workerResult); - } - while (transportResult.CompletedSynchronously); - } - - public void EndWriteMessage(IAsyncResult asyncResult) - { - if (asyncResult == null) - { - throw new ArgumentNullException(nameof(asyncResult)); - } - - WorkerAsyncResult? workerResult = asyncResult as WorkerAsyncResult; - - if (workerResult != null) + await adapter.WriteAsync(_writeHeaderBuffer, 0, _writeHeaderBuffer.Length).ConfigureAwait(false); + if (message.Length != 0) { - if (!workerResult.InternalPeekCompleted) - { - workerResult.InternalWaitForCompletion(); - } - - if (workerResult.Result is Exception e) - { - ExceptionDispatchInfo.Throw(e); - } - } - else - { - TaskToApm.End(asyncResult); + await adapter.WriteAsync(message, 0, message.Length).ConfigureAwait(false); } } } - // - // This class wraps an Async IO request. It is based on our internal LazyAsyncResult helper. - // - If ParentResult is not null then the base class (LazyAsyncResult) methods must not be used. - // - If ParentResult == null, then real user IO request is wrapped. - // - - internal class WorkerAsyncResult : LazyAsyncResult - { - public byte[]? Buffer; - public int Offset; - public int End; - public bool HeaderDone; // This might be reworked so we read both header and frame in one chunk. - - public WorkerAsyncResult(object asyncObject, object asyncState, - AsyncCallback savedAsyncCallback, - byte[]? buffer, int offset, int end) - : base(asyncObject, asyncState, savedAsyncCallback) - { - Buffer = buffer; - Offset = offset; - End = end; - } - } - // Describes the header used in framing of the stream data. - internal class FrameHeader + internal sealed class FrameHeader { public const int IgnoreValue = -1; public const int HandshakeDoneId = 20; @@ -493,121 +101,44 @@ internal class FrameHeader public const int HandshakeId = 22; public const int DefaultMajorV = 1; public const int DefaultMinorV = 0; + public const int Size = 5; + public const int MaxMessageSize = 0xFFFF; - private int _MessageId; - private int _MajorV; - private int _MinorV; - private int _PayloadSize; - - public FrameHeader() - { - _MessageId = HandshakeId; - _MajorV = DefaultMajorV; - _MinorV = DefaultMinorV; - _PayloadSize = -1; - } - - public FrameHeader(int messageId, int majorV, int minorV) - { - _MessageId = messageId; - _MajorV = majorV; - _MinorV = minorV; - _PayloadSize = -1; - } - - public int Size - { - get - { - return 5; - } - } - - public int MaxMessageSize - { - get - { - return 0xFFFF; - } - } - - public int MessageId - { - get - { - return _MessageId; - } - set - { - _MessageId = value; - } - } + private int _payloadSize = -1; - public int MajorV - { - get - { - return _MajorV; - } - } - - public int MinorV - { - get - { - return _MinorV; - } - } + public int MessageId { get; set; } = HandshakeId; + public int MajorV { get; private set; } = DefaultMajorV; + public int MinorV { get; private set; } = DefaultMinorV; public int PayloadSize { - get - { - return _PayloadSize; - } + get => _payloadSize; set { if (value > MaxMessageSize) { - throw new ArgumentException(SR.Format(SR.net_frame_max_size, - MaxMessageSize.ToString(NumberFormatInfo.InvariantInfo), - value.ToString(NumberFormatInfo.InvariantInfo)), "PayloadSize"); + throw new ArgumentException(SR.Format(SR.net_frame_max_size, MaxMessageSize, value), nameof(PayloadSize)); } - _PayloadSize = value; + _payloadSize = value; } } public void CopyTo(byte[] dest, int start) { - dest[start++] = (byte)_MessageId; - dest[start++] = (byte)_MajorV; - dest[start++] = (byte)_MinorV; - dest[start++] = (byte)((_PayloadSize >> 8) & 0xFF); - dest[start] = (byte)(_PayloadSize & 0xFF); + dest[start++] = (byte)MessageId; + dest[start++] = (byte)MajorV; + dest[start++] = (byte)MinorV; + dest[start++] = (byte)((_payloadSize >> 8) & 0xFF); + dest[start] = (byte)(_payloadSize & 0xFF); } - public void CopyFrom(byte[] bytes, int start, FrameHeader verifier) + public void CopyFrom(byte[] bytes, int start) { - _MessageId = bytes[start++]; - _MajorV = bytes[start++]; - _MinorV = bytes[start++]; - _PayloadSize = (int)((bytes[start++] << 8) | bytes[start]); - - if (verifier.MessageId != FrameHeader.IgnoreValue && MessageId != verifier.MessageId) - { - throw new InvalidOperationException(SR.Format(SR.net_io_header_id, "MessageId", MessageId, verifier.MessageId)); - } - - if (verifier.MajorV != FrameHeader.IgnoreValue && MajorV != verifier.MajorV) - { - throw new InvalidOperationException(SR.Format(SR.net_io_header_id, "MajorV", MajorV, verifier.MajorV)); - } - - if (verifier.MinorV != FrameHeader.IgnoreValue && MinorV != verifier.MinorV) - { - throw new InvalidOperationException(SR.Format(SR.net_io_header_id, "MinorV", MinorV, verifier.MinorV)); - } + MessageId = bytes[start++]; + MajorV = bytes[start++]; + MinorV = bytes[start++]; + _payloadSize = (bytes[start++] << 8) | bytes[start]; } } } diff --git a/src/libraries/System.Net.Security/tests/EnterpriseTests/System.Net.Security.Enterprise.Tests.csproj b/src/libraries/System.Net.Security/tests/EnterpriseTests/System.Net.Security.Enterprise.Tests.csproj index 81eb118f1cc598..b1b8131d7655a6 100644 --- a/src/libraries/System.Net.Security/tests/EnterpriseTests/System.Net.Security.Enterprise.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/EnterpriseTests/System.Net.Security.Enterprise.Tests.csproj @@ -7,20 +7,15 @@ - - Common\System\Net\EnterpriseTests\EnterpriseTestConfiguration.cs - - - Common\System\Net\VirtualNetwork\VirtualNetwork.cs - - - Common\System\Net\VirtualNetwork\VirtualNetworkStream.cs - - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - - - ProductionCode\Common\System\Threading\Tasks\TaskToApm.cs - + + + + + \ No newline at end of file diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs index 69c96735809da4..a8dba5b6b0b6b0 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs @@ -19,9 +19,9 @@ public class ClientAsyncAuthenticateTest { private readonly ITestOutputHelper _log; - public ClientAsyncAuthenticateTest() + public ClientAsyncAuthenticateTest(ITestOutputHelper output) { - _log = TestLogging.GetInstance(); + _log = output; } [Fact] @@ -44,11 +44,7 @@ public async Task ClientAsyncAuthenticate_ServerRequireEncryption_ConnectWithEnc public async Task ClientAsyncAuthenticate_ServerNoEncryption_NoConnect() { // Don't use Tls13 since we are trying to use NullEncryption - Type expectedExceptionType = TestConfiguration.SupportsHandshakeAlerts && TestConfiguration.SupportsNullEncryption ? - typeof(AuthenticationException) : - typeof(IOException); - - await Assert.ThrowsAsync(expectedExceptionType, + await Assert.ThrowsAsync( () => ClientAsyncSslHelper( EncryptionPolicy.NoEncryption, SslProtocolSupport.DefaultSslProtocols, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 )); @@ -67,7 +63,7 @@ public async Task ClientAsyncAuthenticate_Ssl2WithSelf_Success() { // Test Ssl2 against itself. This is a standalone test as even on versions where Windows supports Ssl2, // it appears to have rules around not using it when other protocols are mentioned. - if (!PlatformDetection.IsWindows10Version1607OrGreater) + if (PlatformDetection.SupportsSsl2) { #pragma warning disable 0618 await ClientAsyncSslHelper(SslProtocols.Ssl2, SslProtocols.Ssl2); @@ -120,12 +116,12 @@ public static IEnumerable ProtocolMismatchData() yield return new object[] { SslProtocols.Ssl2, SslProtocols.Tls12, typeof(Exception) }; yield return new object[] { SslProtocols.Ssl3, SslProtocols.Tls12, typeof(Exception) }; #pragma warning restore 0618 - yield return new object[] { SslProtocols.Tls, SslProtocols.Tls11, TestConfiguration.SupportsVersionAlerts ? typeof(AuthenticationException) : typeof(IOException) }; - yield return new object[] { SslProtocols.Tls, SslProtocols.Tls12, TestConfiguration.SupportsVersionAlerts ? typeof(AuthenticationException) : typeof(IOException) }; + yield return new object[] { SslProtocols.Tls, SslProtocols.Tls11, typeof(AuthenticationException) }; + yield return new object[] { SslProtocols.Tls, SslProtocols.Tls12, typeof(AuthenticationException) }; yield return new object[] { SslProtocols.Tls11, SslProtocols.Tls, typeof(AuthenticationException) }; yield return new object[] { SslProtocols.Tls12, SslProtocols.Tls, typeof(AuthenticationException) }; yield return new object[] { SslProtocols.Tls12, SslProtocols.Tls11, typeof(AuthenticationException) }; - yield return new object[] { SslProtocols.Tls11, SslProtocols.Tls12, TestConfiguration.SupportsVersionAlerts ? typeof(AuthenticationException) : typeof(IOException) }; + yield return new object[] { SslProtocols.Tls11, SslProtocols.Tls12, typeof(AuthenticationException) }; } #region Helpers diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/ClientDefaultEncryptionTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/ClientDefaultEncryptionTest.cs index 4a57ca90631615..ed3a2c635e6927 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/ClientDefaultEncryptionTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/ClientDefaultEncryptionTest.cs @@ -84,7 +84,7 @@ public async Task ClientDefaultEncryption_ServerNoEncryption_NoConnect() using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null)) { - await Assert.ThrowsAsync(TestConfiguration.SupportsHandshakeAlerts ? typeof(AuthenticationException) : typeof(IOException), () => + await Assert.ThrowsAsync(() => sslStream.AuthenticateAsClientAsync("localhost", null, SslProtocolSupport.DefaultSslProtocols, false)); } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamInvalidOperationTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamInvalidOperationTest.cs index bdde8c6bded933..68c6368969902a 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamInvalidOperationTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamInvalidOperationTest.cs @@ -98,56 +98,6 @@ await TestConfiguration.WhenAllOrAnyFailedWithTimeout( } } - [Fact] - public async Task NegotiateStream_ConcurrentAsyncReadOrWrite_ThrowsNotSupportedException() - { - byte[] recvBuf = new byte[s_sampleMsg.Length]; - var network = new VirtualNetwork(); - - using (var clientStream = new VirtualNetworkStream(network, isServer: false)) - using (var serverStream = new VirtualNetworkStream(network, isServer: true)) - using (var client = new NegotiateStream(clientStream)) - using (var server = new NegotiateStream(serverStream)) - { - await TestConfiguration.WhenAllOrAnyFailedWithTimeout( - client.AuthenticateAsClientAsync(CredentialCache.DefaultNetworkCredentials, string.Empty), - server.AuthenticateAsServerAsync()); - - // Custom EndWrite/Read will not reset the variable which monitors concurrent write/read. - await TestConfiguration.WhenAllOrAnyFailedWithTimeout( - Task.Factory.FromAsync(client.BeginWrite, (ar) => { Assert.NotNull(ar); }, s_sampleMsg, 0, s_sampleMsg.Length, client), - Task.Factory.FromAsync(server.BeginRead, (ar) => { Assert.NotNull(ar); }, recvBuf, 0, s_sampleMsg.Length, server)); - - Assert.Throws(() => client.BeginWrite(s_sampleMsg, 0, s_sampleMsg.Length, (ar) => { Assert.Null(ar); }, null)); - Assert.Throws(() => server.BeginRead(recvBuf, 0, s_sampleMsg.Length, (ar) => { Assert.Null(ar); }, null)); - } - } - - [Fact] - public async Task NegotiateStream_ConcurrentSyncReadOrWrite_ThrowsNotSupportedException() - { - byte[] recvBuf = new byte[s_sampleMsg.Length]; - var network = new VirtualNetwork(); - - using (var clientStream = new VirtualNetworkStream(network, isServer: false)) - using (var serverStream = new VirtualNetworkStream(network, isServer: true)) - using (var client = new NegotiateStream(clientStream)) - using (var server = new NegotiateStream(serverStream)) - { - await TestConfiguration.WhenAllOrAnyFailedWithTimeout( - client.AuthenticateAsClientAsync(CredentialCache.DefaultNetworkCredentials, string.Empty), - server.AuthenticateAsServerAsync()); - - // Custom EndWrite/Read will not reset the variable which monitors concurrent write/read. - await TestConfiguration.WhenAllOrAnyFailedWithTimeout( - Task.Factory.FromAsync(client.BeginWrite, (ar) => { Assert.NotNull(ar); }, s_sampleMsg, 0, s_sampleMsg.Length, client), - Task.Factory.FromAsync(server.BeginRead, (ar) => { Assert.NotNull(ar); }, recvBuf, 0, s_sampleMsg.Length, server)); - - Assert.Throws(() => client.Write(s_sampleMsg, 0, s_sampleMsg.Length)); - Assert.Throws(() => server.Read(recvBuf, 0, s_sampleMsg.Length)); - } - } - [Fact] public async Task NegotiateStream_DisposeTooEarly_Throws() { @@ -336,7 +286,6 @@ await TestConfiguration.WhenAllOrAnyFailedWithTimeout( AssertExtensions.Throws(nameof(asyncResult), () => authStream.EndAuthenticateAsClient(result)); authStream.EndAuthenticateAsClient(asyncResult); - Assert.Throws(() => authStream.EndAuthenticateAsClient(asyncResult)); }, CredentialCache.DefaultNetworkCredentials, string.Empty, client), Task.Factory.FromAsync(server.BeginAuthenticateAsServer, (asyncResult) => @@ -348,7 +297,6 @@ await TestConfiguration.WhenAllOrAnyFailedWithTimeout( AssertExtensions.Throws(nameof(asyncResult), () => authStream.EndAuthenticateAsServer(result)); authStream.EndAuthenticateAsServer(asyncResult); - Assert.Throws(() => authStream.EndAuthenticateAsServer(asyncResult)); }, server)); } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs index a507020420be9f..1ffe2216a5a9ed 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs @@ -2,11 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Diagnostics; +using System.IO; using System.Linq; using System.Net.Test.Common; +using System.Security.Authentication.ExtendedProtection; using System.Security.Principal; using System.Text; +using System.Threading; using System.Threading.Tasks; using Xunit; @@ -19,7 +21,7 @@ public abstract class NegotiateStreamStreamToStreamTest public static bool IsNtlmInstalled => Capability.IsNtlmInstalled(); private const int PartialBytesToRead = 5; - private static readonly byte[] s_sampleMsg = Encoding.UTF8.GetBytes("Sample Test Message"); + protected static readonly byte[] s_sampleMsg = Encoding.UTF8.GetBytes("Sample Test Message"); private const int MaxWriteDataSize = 63 * 1024; // NegoState.MaxWriteDataSize private static string s_longString = new string('A', MaxWriteDataSize) + 'Z'; @@ -27,14 +29,20 @@ public abstract class NegotiateStreamStreamToStreamTest protected abstract Task AuthenticateAsClientAsync(NegotiateStream client, NetworkCredential credential, string targetName); protected abstract Task AuthenticateAsServerAsync(NegotiateStream server); - - [ConditionalFact(nameof(IsNtlmInstalled))] - public async Task NegotiateStream_StreamToStream_Authentication_Success() + protected abstract Task ReadAsync(NegotiateStream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken = default); + protected abstract Task WriteAsync(NegotiateStream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken = default); + protected virtual bool SupportsCancelableReadsWrites => false; + protected virtual bool IsEncryptedAndSigned => true; + + [ConditionalTheory(nameof(IsNtlmInstalled))] + [InlineData(0)] + [InlineData(1)] + public async Task NegotiateStream_StreamToStream_Authentication_Success(int delay) { VirtualNetwork network = new VirtualNetwork(); - using (var clientStream = new VirtualNetworkStream(network, isServer: false)) - using (var serverStream = new VirtualNetworkStream(network, isServer: true)) + using (var clientStream = new VirtualNetworkStream(network, isServer: false) { DelayMilliseconds = delay }) + using (var serverStream = new VirtualNetworkStream(network, isServer: true) { DelayMilliseconds = delay }) using (var client = new NegotiateStream(clientStream)) using (var server = new NegotiateStream(serverStream)) { @@ -49,10 +57,10 @@ public async Task NegotiateStream_StreamToStream_Authentication_Success() // Expected Client property values: Assert.True(client.IsAuthenticated); Assert.Equal(TokenImpersonationLevel.Identification, client.ImpersonationLevel); - Assert.True(client.IsEncrypted); + Assert.Equal(IsEncryptedAndSigned, client.IsEncrypted); Assert.False(client.IsMutuallyAuthenticated); Assert.False(client.IsServer); - Assert.True(client.IsSigned); + Assert.Equal(IsEncryptedAndSigned, client.IsSigned); Assert.False(client.LeaveInnerStreamOpen); IIdentity serverIdentity = client.RemoteIdentity; @@ -63,10 +71,10 @@ public async Task NegotiateStream_StreamToStream_Authentication_Success() // Expected Server property values: Assert.True(server.IsAuthenticated); Assert.Equal(TokenImpersonationLevel.Identification, server.ImpersonationLevel); - Assert.True(server.IsEncrypted); + Assert.Equal(IsEncryptedAndSigned, server.IsEncrypted); Assert.False(server.IsMutuallyAuthenticated); Assert.True(server.IsServer); - Assert.True(server.IsSigned); + Assert.Equal(IsEncryptedAndSigned, server.IsSigned); Assert.False(server.LeaveInnerStreamOpen); IIdentity clientIdentity = server.RemoteIdentity; @@ -78,6 +86,43 @@ public async Task NegotiateStream_StreamToStream_Authentication_Success() } } + [ConditionalTheory(nameof(IsNtlmInstalled))] + [InlineData(0)] + [InlineData(1)] + public async Task NegotiateStream_StreamToStream_Authenticated_DisposeAsync(int delay) + { + var network = new VirtualNetwork(); + await using (var client = new NegotiateStream(new VirtualNetworkStream(network, isServer: false) { DelayMilliseconds = delay })) + await using (var server = new NegotiateStream(new VirtualNetworkStream(network, isServer: true) { DelayMilliseconds = delay })) + { + Assert.False(client.IsServer); + Assert.False(server.IsServer); + + Assert.False(client.IsAuthenticated); + Assert.False(server.IsAuthenticated); + + Assert.False(client.IsMutuallyAuthenticated); + Assert.False(server.IsMutuallyAuthenticated); + + Assert.False(client.IsEncrypted); + Assert.False(server.IsEncrypted); + + Assert.False(client.IsSigned); + Assert.False(server.IsSigned); + + await TestConfiguration.WhenAllOrAnyFailedWithTimeout( + AuthenticateAsClientAsync(client, CredentialCache.DefaultNetworkCredentials, string.Empty), + AuthenticateAsServerAsync(server)); + } + } + + [ConditionalFact(nameof(IsNtlmInstalled))] + public async Task NegotiateStream_StreamToStream_Unauthenticated_Dispose() + { + new NegotiateStream(new MemoryStream()).Dispose(); + await new NegotiateStream(new MemoryStream()).DisposeAsync(); + } + [ConditionalFact(nameof(IsNtlmInstalled))] public async Task NegotiateStream_StreamToStream_Authentication_TargetName_Success() { @@ -105,10 +150,10 @@ public async Task NegotiateStream_StreamToStream_Authentication_TargetName_Succe // Expected Client property values: Assert.True(client.IsAuthenticated); Assert.Equal(TokenImpersonationLevel.Identification, client.ImpersonationLevel); - Assert.True(client.IsEncrypted); + Assert.Equal(IsEncryptedAndSigned, client.IsEncrypted); Assert.False(client.IsMutuallyAuthenticated); Assert.False(client.IsServer); - Assert.True(client.IsSigned); + Assert.Equal(IsEncryptedAndSigned, client.IsSigned); Assert.False(client.LeaveInnerStreamOpen); IIdentity serverIdentity = client.RemoteIdentity; @@ -119,10 +164,10 @@ public async Task NegotiateStream_StreamToStream_Authentication_TargetName_Succe // Expected Server property values: Assert.True(server.IsAuthenticated); Assert.Equal(TokenImpersonationLevel.Identification, server.ImpersonationLevel); - Assert.True(server.IsEncrypted); + Assert.Equal(IsEncryptedAndSigned, server.IsEncrypted); Assert.False(server.IsMutuallyAuthenticated); Assert.True(server.IsServer); - Assert.True(server.IsSigned); + Assert.Equal(IsEncryptedAndSigned, server.IsSigned); Assert.False(server.LeaveInnerStreamOpen); IIdentity clientIdentity = server.RemoteIdentity; @@ -165,10 +210,10 @@ public async Task NegotiateStream_StreamToStream_Authentication_EmptyCredentials // Expected Client property values: Assert.True(client.IsAuthenticated); Assert.Equal(TokenImpersonationLevel.Identification, client.ImpersonationLevel); - Assert.True(client.IsEncrypted); + Assert.Equal(IsEncryptedAndSigned, client.IsEncrypted); Assert.False(client.IsMutuallyAuthenticated); Assert.False(client.IsServer); - Assert.True(client.IsSigned); + Assert.Equal(IsEncryptedAndSigned, client.IsSigned); Assert.False(client.LeaveInnerStreamOpen); IIdentity serverIdentity = client.RemoteIdentity; @@ -179,10 +224,10 @@ public async Task NegotiateStream_StreamToStream_Authentication_EmptyCredentials // Expected Server property values: Assert.True(server.IsAuthenticated); Assert.Equal(TokenImpersonationLevel.Identification, server.ImpersonationLevel); - Assert.True(server.IsEncrypted); + Assert.Equal(IsEncryptedAndSigned, server.IsEncrypted); Assert.False(server.IsMutuallyAuthenticated); Assert.True(server.IsServer); - Assert.True(server.IsSigned); + Assert.Equal(IsEncryptedAndSigned, server.IsSigned); Assert.False(server.LeaveInnerStreamOpen); IIdentity clientIdentity = server.RemoteIdentity; @@ -195,15 +240,17 @@ public async Task NegotiateStream_StreamToStream_Authentication_EmptyCredentials } } - [ConditionalFact(nameof(IsNtlmInstalled))] - public async Task NegotiateStream_StreamToStream_Successive_ClientWrite_Sync_Success() + [ConditionalTheory(nameof(IsNtlmInstalled))] + [InlineData(0)] + [InlineData(1)] + public async Task NegotiateStream_StreamToStream_Successive_ClientWrite_Success(int delay) { byte[] recvBuf = new byte[s_sampleMsg.Length]; VirtualNetwork network = new VirtualNetwork(); int bytesRead = 0; - using (var clientStream = new VirtualNetworkStream(network, isServer: false)) - using (var serverStream = new VirtualNetworkStream(network, isServer: true)) + using (var clientStream = new VirtualNetworkStream(network, isServer: false) { DelayMilliseconds = delay }) + using (var serverStream = new VirtualNetworkStream(network, isServer: true) { DelayMilliseconds = delay }) using (var client = new NegotiateStream(clientStream)) using (var server = new NegotiateStream(serverStream)) { @@ -216,99 +263,35 @@ public async Task NegotiateStream_StreamToStream_Successive_ClientWrite_Sync_Suc await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth); - client.Write(s_sampleMsg, 0, s_sampleMsg.Length); - server.Read(recvBuf, 0, s_sampleMsg.Length); - - Assert.True(s_sampleMsg.SequenceEqual(recvBuf)); - - client.Write(s_sampleMsg, 0, s_sampleMsg.Length); - - // Test partial sync read. - bytesRead = server.Read(recvBuf, 0, PartialBytesToRead); - Assert.Equal(PartialBytesToRead, bytesRead); - - bytesRead = server.Read(recvBuf, PartialBytesToRead, s_sampleMsg.Length - PartialBytesToRead); - Assert.Equal(s_sampleMsg.Length - PartialBytesToRead, bytesRead); - - Assert.True(s_sampleMsg.SequenceEqual(recvBuf)); - } - } - - [ConditionalFact(nameof(IsNtlmInstalled))] - public async Task NegotiateStream_StreamToStream_Successive_ClientWrite_Async_Success() - { - byte[] recvBuf = new byte[s_sampleMsg.Length]; - VirtualNetwork network = new VirtualNetwork(); - int bytesRead = 0; - - using (var clientStream = new VirtualNetworkStream(network, isServer: false)) - using (var serverStream = new VirtualNetworkStream(network, isServer: true)) - using (var client = new NegotiateStream(clientStream)) - using (var server = new NegotiateStream(serverStream)) - { - Assert.False(client.IsAuthenticated); - Assert.False(server.IsAuthenticated); - - Task[] auth = new Task[2]; - auth[0] = AuthenticateAsClientAsync(client, CredentialCache.DefaultNetworkCredentials, string.Empty); - auth[1] = AuthenticateAsServerAsync(server); - - await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth); - - auth[0] = client.WriteAsync(s_sampleMsg, 0, s_sampleMsg.Length); - auth[1] = server.ReadAsync(recvBuf, 0, s_sampleMsg.Length); + auth[0] = WriteAsync(client, s_sampleMsg, 0, s_sampleMsg.Length); + auth[1] = ReadAsync(server, recvBuf, 0, s_sampleMsg.Length); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(auth); Assert.True(s_sampleMsg.SequenceEqual(recvBuf)); - await client.WriteAsync(s_sampleMsg, 0, s_sampleMsg.Length); + await WriteAsync(client, s_sampleMsg, 0, s_sampleMsg.Length); // Test partial async read. - bytesRead = await server.ReadAsync(recvBuf, 0, PartialBytesToRead); + bytesRead = await ReadAsync(server, recvBuf, 0, PartialBytesToRead); Assert.Equal(PartialBytesToRead, bytesRead); - bytesRead = await server.ReadAsync(recvBuf, PartialBytesToRead, s_sampleMsg.Length - PartialBytesToRead); + bytesRead = await ReadAsync(server, recvBuf, PartialBytesToRead, s_sampleMsg.Length - PartialBytesToRead); Assert.Equal(s_sampleMsg.Length - PartialBytesToRead, bytesRead); Assert.True(s_sampleMsg.SequenceEqual(recvBuf)); } } - [ConditionalFact(nameof(IsNtlmInstalled))] - public async Task NegotiateStream_ReadWriteLongMsgSync_Success() - { - byte[] recvBuf = new byte[s_longMsg.Length]; - var network = new VirtualNetwork(); - int bytesRead = 0; - - using (var clientStream = new VirtualNetworkStream(network, isServer: false)) - using (var serverStream = new VirtualNetworkStream(network, isServer: true)) - using (var client = new NegotiateStream(clientStream)) - using (var server = new NegotiateStream(serverStream)) - { - await TestConfiguration.WhenAllOrAnyFailedWithTimeout( - client.AuthenticateAsClientAsync(CredentialCache.DefaultNetworkCredentials, string.Empty), - server.AuthenticateAsServerAsync()); - - client.Write(s_longMsg, 0, s_longMsg.Length); - - while (bytesRead < s_longMsg.Length) - { - bytesRead += server.Read(recvBuf, bytesRead, s_longMsg.Length - bytesRead); - } - - Assert.True(s_longMsg.SequenceEqual(recvBuf)); - } - } - - [ConditionalFact(nameof(IsNtlmInstalled))] - public async Task NegotiateStream_ReadWriteLongMsgAsync_Success() + [ConditionalTheory(nameof(IsNtlmInstalled))] + [InlineData(0)] + [InlineData(1)] + public async Task NegotiateStream_ReadWriteLongMsg_Success(int delay) { byte[] recvBuf = new byte[s_longMsg.Length]; var network = new VirtualNetwork(); int bytesRead = 0; - using (var clientStream = new VirtualNetworkStream(network, isServer: false)) - using (var serverStream = new VirtualNetworkStream(network, isServer: true)) + using (var clientStream = new VirtualNetworkStream(network, isServer: false) { DelayMilliseconds = delay }) + using (var serverStream = new VirtualNetworkStream(network, isServer: true) { DelayMilliseconds = delay }) using (var client = new NegotiateStream(clientStream)) using (var server = new NegotiateStream(serverStream)) { @@ -316,11 +299,11 @@ await TestConfiguration.WhenAllOrAnyFailedWithTimeout( client.AuthenticateAsClientAsync(CredentialCache.DefaultNetworkCredentials, string.Empty), server.AuthenticateAsServerAsync()); - await client.WriteAsync(s_longMsg, 0, s_longMsg.Length); + await WriteAsync(client, s_longMsg, 0, s_longMsg.Length); while (bytesRead < s_longMsg.Length) { - bytesRead += await server.ReadAsync(recvBuf, bytesRead, s_longMsg.Length - bytesRead); + bytesRead += await ReadAsync(server, recvBuf, bytesRead, s_longMsg.Length - bytesRead); } Assert.True(s_longMsg.SequenceEqual(recvBuf)); @@ -356,18 +339,91 @@ public void NegotiateStream_StreamToStream_FlushAsync_Propagated() Assert.True(task.IsCompleted); } } + + [ConditionalFact(nameof(IsNtlmInstalled))] + public async Task NegotiateStream_StreamToStream_Successive_CancelableReadsWrites() + { + if (!SupportsCancelableReadsWrites) + { + return; + } + + byte[] recvBuf = new byte[s_sampleMsg.Length]; + VirtualNetwork network = new VirtualNetwork(); + + using (var clientStream = new VirtualNetworkStream(network, isServer: false)) + using (var serverStream = new VirtualNetworkStream(network, isServer: true)) + using (var client = new NegotiateStream(clientStream)) + using (var server = new NegotiateStream(serverStream)) + { + await TestConfiguration.WhenAllOrAnyFailedWithTimeout( + AuthenticateAsClientAsync(client, CredentialCache.DefaultNetworkCredentials, string.Empty), + AuthenticateAsServerAsync(server)); + + clientStream.DelayMilliseconds = int.MaxValue; + serverStream.DelayMilliseconds = int.MaxValue; + + var cts = new CancellationTokenSource(); + Task t = WriteAsync(client, s_sampleMsg, 0, s_sampleMsg.Length, cts.Token); + Assert.False(t.IsCompleted); + cts.Cancel(); + await Assert.ThrowsAnyAsync(() => t); + + cts = new CancellationTokenSource(); + t = ReadAsync(server, s_sampleMsg, 0, s_sampleMsg.Length, cts.Token); + Assert.False(t.IsCompleted); + cts.Cancel(); + await Assert.ThrowsAnyAsync(() => t); + } + } } - public sealed class NegotiateStreamStreamToStreamTest_Async : NegotiateStreamStreamToStreamTest + public sealed class NegotiateStreamStreamToStreamTest_Async_Array : NegotiateStreamStreamToStreamTest { protected override Task AuthenticateAsClientAsync(NegotiateStream client, NetworkCredential credential, string targetName) => client.AuthenticateAsClientAsync(credential, targetName); protected override Task AuthenticateAsServerAsync(NegotiateStream server) => server.AuthenticateAsServerAsync(); + + protected override Task ReadAsync(NegotiateStream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) => + stream.ReadAsync(buffer, offset, count, cancellationToken); + + protected override Task WriteAsync(NegotiateStream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) => + stream.WriteAsync(buffer, offset, count, cancellationToken); + + protected override bool SupportsCancelableReadsWrites => true; } - public sealed class NegotiateStreamStreamToStreamTest_Async_TestOverloadNullBinding : NegotiateStreamStreamToStreamTest + public class NegotiateStreamStreamToStreamTest_Async_Memory : NegotiateStreamStreamToStreamTest + { + protected override Task AuthenticateAsClientAsync(NegotiateStream client, NetworkCredential credential, string targetName) => + client.AuthenticateAsClientAsync(credential, targetName); + + protected override Task AuthenticateAsServerAsync(NegotiateStream server) => + server.AuthenticateAsServerAsync(); + + protected override Task ReadAsync(NegotiateStream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) => + stream.ReadAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask(); + + protected override Task WriteAsync(NegotiateStream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) => + stream.WriteAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask(); + + protected override bool SupportsCancelableReadsWrites => true; + } + + public class NegotiateStreamStreamToStreamTest_Async_Memory_NotEncrypted : NegotiateStreamStreamToStreamTest_Async_Memory + { + protected override Task AuthenticateAsClientAsync(NegotiateStream client, NetworkCredential credential, string targetName) => + client.AuthenticateAsClientAsync(credential, targetName, ProtectionLevel.None, TokenImpersonationLevel.Identification); + + protected override Task AuthenticateAsServerAsync(NegotiateStream server) => + server.AuthenticateAsServerAsync(CredentialCache.DefaultNetworkCredentials, ProtectionLevel.None, TokenImpersonationLevel.Identification); + + protected override bool IsEncryptedAndSigned => false; + } + + public sealed class NegotiateStreamStreamToStreamTest_Async_TestOverloadNullBinding : NegotiateStreamStreamToStreamTest_Async_Memory { protected override Task AuthenticateAsClientAsync(NegotiateStream client, NetworkCredential credential, string targetName) => client.AuthenticateAsClientAsync(credential, null, targetName); @@ -376,7 +432,7 @@ protected override Task AuthenticateAsServerAsync(NegotiateStream server) => server.AuthenticateAsServerAsync(null); } - public sealed class NegotiateStreamStreamToStreamTest_Async_TestOverloadProtectionLevel : NegotiateStreamStreamToStreamTest + public sealed class NegotiateStreamStreamToStreamTest_Async_TestOverloadProtectionLevel : NegotiateStreamStreamToStreamTest_Async_Memory { protected override Task AuthenticateAsClientAsync(NegotiateStream client, NetworkCredential credential, string targetName) => client.AuthenticateAsClientAsync(credential, targetName, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); @@ -385,7 +441,7 @@ protected override Task AuthenticateAsServerAsync(NegotiateStream server) => server.AuthenticateAsServerAsync((NetworkCredential)CredentialCache.DefaultCredentials, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); } - public sealed class NegotiateStreamStreamToStreamTest_Async_TestOverloadAllParameters : NegotiateStreamStreamToStreamTest + public sealed class NegotiateStreamStreamToStreamTest_Async_TestOverloadAllParameters : NegotiateStreamStreamToStreamTest_Async_Memory { protected override Task AuthenticateAsClientAsync(NegotiateStream client, NetworkCredential credential, string targetName) => client.AuthenticateAsClientAsync(credential, null, targetName, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); @@ -394,25 +450,62 @@ protected override Task AuthenticateAsServerAsync(NegotiateStream server) => server.AuthenticateAsServerAsync((NetworkCredential)CredentialCache.DefaultCredentials, null, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification); } - public sealed class NegotiateStreamStreamToStreamTest_BeginEnd : NegotiateStreamStreamToStreamTest + public class NegotiateStreamStreamToStreamTest_BeginEnd : NegotiateStreamStreamToStreamTest { protected override Task AuthenticateAsClientAsync(NegotiateStream client, NetworkCredential credential, string targetName) => Task.Factory.FromAsync(client.BeginAuthenticateAsClient, client.EndAuthenticateAsClient, credential, targetName, null); protected override Task AuthenticateAsServerAsync(NegotiateStream server) => Task.Factory.FromAsync(server.BeginAuthenticateAsServer, server.EndAuthenticateAsServer, null); + + protected override Task ReadAsync(NegotiateStream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) => + Task.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, offset, count, null); + + protected override Task WriteAsync(NegotiateStream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) => + Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, buffer, offset, count, null); } - public sealed class NegotiateStreamStreamToStreamTest_Sync : NegotiateStreamStreamToStreamTest + public sealed class NegotiateStreamStreamToStreamTest_BeginEnd_TestOverloadNullBinding : NegotiateStreamStreamToStreamTest_BeginEnd + { + protected override Task AuthenticateAsClientAsync(NegotiateStream client, NetworkCredential credential, string targetName) => + Task.Factory.FromAsync(client.BeginAuthenticateAsClient, client.EndAuthenticateAsClient, credential, (ChannelBinding)null, targetName, null); + + protected override Task AuthenticateAsServerAsync(NegotiateStream server) => + Task.Factory.FromAsync(server.BeginAuthenticateAsServer, server.EndAuthenticateAsServer, (ExtendedProtectionPolicy)null, null); + } + + public sealed class NegotiateStreamStreamToStreamTest_BeginEnd_TestOverloadProtectionLevel : NegotiateStreamStreamToStreamTest_BeginEnd + { + protected override Task AuthenticateAsClientAsync(NegotiateStream client, NetworkCredential credential, string targetName) => + Task.Factory.FromAsync( + (callback, state) => client.BeginAuthenticateAsClient(credential, targetName, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification, callback, state), + client.EndAuthenticateAsClient, null); + + protected override Task AuthenticateAsServerAsync(NegotiateStream server) => + Task.Factory.FromAsync( + (callback, state) => server.BeginAuthenticateAsServer((NetworkCredential)CredentialCache.DefaultCredentials, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification, callback, state), + server.EndAuthenticateAsServer, null); + } + + public class NegotiateStreamStreamToStreamTest_Sync : NegotiateStreamStreamToStreamTest { protected override Task AuthenticateAsClientAsync(NegotiateStream client, NetworkCredential credential, string targetName) => Task.Run(() => client.AuthenticateAsClient(credential, targetName)); protected override Task AuthenticateAsServerAsync(NegotiateStream server) => Task.Run(() => server.AuthenticateAsServer()); + + protected override Task ReadAsync(NegotiateStream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) => + Task.FromResult(stream.Read(buffer, offset, count)); + + protected override Task WriteAsync(NegotiateStream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + stream.Write(buffer, offset, count); + return Task.CompletedTask; + } } - public sealed class NegotiateStreamStreamToStreamTest_Sync_TestOverloadNullBinding : NegotiateStreamStreamToStreamTest + public sealed class NegotiateStreamStreamToStreamTest_Sync_TestOverloadNullBinding : NegotiateStreamStreamToStreamTest_Sync { protected override Task AuthenticateAsClientAsync(NegotiateStream client, NetworkCredential credential, string targetName) => Task.Run(() => client.AuthenticateAsClient(credential, null, targetName)); @@ -421,7 +514,7 @@ protected override Task AuthenticateAsServerAsync(NegotiateStream server) => Task.Run(() => server.AuthenticateAsServer(null)); } - public sealed class NegotiateStreamStreamToStreamTest_Sync_TestOverloadAllParameters : NegotiateStreamStreamToStreamTest + public sealed class NegotiateStreamStreamToStreamTest_Sync_TestOverloadAllParameters : NegotiateStreamStreamToStreamTest_Sync { protected override Task AuthenticateAsClientAsync(NegotiateStream client, NetworkCredential credential, string targetName) => Task.Run(() => client.AuthenticateAsClient(credential, targetName, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification)); @@ -429,4 +522,15 @@ protected override Task AuthenticateAsClientAsync(NegotiateStream client, Networ protected override Task AuthenticateAsServerAsync(NegotiateStream server) => Task.Run(() => server.AuthenticateAsServer((NetworkCredential)CredentialCache.DefaultCredentials, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification)); } + + public class NegotiateStreamStreamToStreamTest_Sync_NotEncrypted : NegotiateStreamStreamToStreamTest_Sync + { + protected override Task AuthenticateAsClientAsync(NegotiateStream client, NetworkCredential credential, string targetName) => + Task.Run(() => client.AuthenticateAsClient(credential, targetName, ProtectionLevel.None, TokenImpersonationLevel.Identification)); + + protected override Task AuthenticateAsServerAsync(NegotiateStream server) => + Task.Run(() => server.AuthenticateAsServer((NetworkCredential)CredentialCache.DefaultCredentials, ProtectionLevel.None, TokenImpersonationLevel.Identification)); + + protected override bool IsEncryptedAndSigned => false; + } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/ServerAllowNoEncryptionTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/ServerAllowNoEncryptionTest.cs index 12918eaf9c2a49..cc59578b61930c 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/ServerAllowNoEncryptionTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/ServerAllowNoEncryptionTest.cs @@ -17,9 +17,9 @@ public class ServerAllowNoEncryptionTest { private readonly ITestOutputHelper _log; - public ServerAllowNoEncryptionTest() + public ServerAllowNoEncryptionTest(ITestOutputHelper output) { - _log = TestLogging.GetInstance(); + _log = output; } // The following method is invoked by the RemoteCertificateValidationDelegate. diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs index 5ecb21d630a9af..bc58e68aa5eba1 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs @@ -23,9 +23,9 @@ public class ServerAsyncAuthenticateTest : IDisposable private readonly ITestOutputHelper _logVerbose; private readonly X509Certificate2 _serverCertificate; - public ServerAsyncAuthenticateTest() + public ServerAsyncAuthenticateTest(ITestOutputHelper output) { - _log = TestLogging.GetInstance(); + _log = output; _logVerbose = VerboseTestLogging.GetInstance(); _serverCertificate = Configuration.Certificates.GetServerCertificate(); } @@ -44,7 +44,7 @@ public async Task ServerAsyncAuthenticate_EachSupportedProtocol_Success(SslProto [Theory] [MemberData(nameof(ProtocolMismatchData))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/29642")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/36192", TestPlatforms.AnyUnix)] public async Task ServerAsyncAuthenticate_MismatchProtocols_Fails( SslProtocols serverProtocol, SslProtocols clientProtocol, @@ -73,17 +73,24 @@ public async Task ServerAsyncAuthenticate_AllClientVsIndividualServerSupportedPr public static IEnumerable ProtocolMismatchData() { + if (PlatformDetection.SupportsSsl3) + { #pragma warning disable 0618 - yield return new object[] { SslProtocols.Ssl2, SslProtocols.Ssl3, typeof(Exception) }; - yield return new object[] { SslProtocols.Ssl2, SslProtocols.Tls12, typeof(Exception) }; - yield return new object[] { SslProtocols.Ssl3, SslProtocols.Tls12, typeof(Exception) }; + yield return new object[] { SslProtocols.Ssl3, SslProtocols.Tls12, typeof(Exception) }; + if (PlatformDetection.SupportsSsl2) + { + yield return new object[] { SslProtocols.Ssl2, SslProtocols.Ssl3, typeof(Exception) }; + yield return new object[] { SslProtocols.Ssl2, SslProtocols.Tls12, typeof(Exception) }; + } #pragma warning restore 0618 + } + yield return new object[] { SslProtocols.Tls, SslProtocols.Tls11, typeof(AuthenticationException) }; yield return new object[] { SslProtocols.Tls, SslProtocols.Tls12, typeof(AuthenticationException) }; - yield return new object[] { SslProtocols.Tls11, SslProtocols.Tls, TestConfiguration.SupportsVersionAlerts ? typeof(AuthenticationException) : typeof(TimeoutException) }; + yield return new object[] { SslProtocols.Tls11, SslProtocols.Tls, typeof(AuthenticationException) }; yield return new object[] { SslProtocols.Tls11, SslProtocols.Tls12, typeof(AuthenticationException) }; - yield return new object[] { SslProtocols.Tls12, SslProtocols.Tls, TestConfiguration.SupportsVersionAlerts ? typeof(AuthenticationException) : typeof(TimeoutException) }; - yield return new object[] { SslProtocols.Tls12, SslProtocols.Tls11, TestConfiguration.SupportsVersionAlerts ? typeof(AuthenticationException) : typeof(TimeoutException) }; + yield return new object[] { SslProtocols.Tls12, SslProtocols.Tls, typeof(AuthenticationException) }; + yield return new object[] { SslProtocols.Tls12, SslProtocols.Tls11, typeof(AuthenticationException) }; } #region Helpers diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/ServerNoEncryptionTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/ServerNoEncryptionTest.cs index 65efb78767f9cc..5dd06233c06a3a 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/ServerNoEncryptionTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/ServerNoEncryptionTest.cs @@ -17,9 +17,9 @@ public class ServerNoEncryptionTest { private readonly ITestOutputHelper _log; - public ServerNoEncryptionTest() + public ServerNoEncryptionTest(ITestOutputHelper output) { - _log = TestLogging.GetInstance(); + _log = output; } // The following method is invoked by the RemoteCertificateValidationDelegate. @@ -43,7 +43,7 @@ public async Task ServerNoEncryption_ClientRequireEncryption_NoConnect() using (var sslStream = new SslStream(client.GetStream(), false, AllowAnyServerCertificate, null, EncryptionPolicy.RequireEncryption)) { - await Assert.ThrowsAsync(TestConfiguration.SupportsHandshakeAlerts ? typeof(AuthenticationException) : typeof(IOException), () => + await Assert.ThrowsAsync(() => sslStream.AuthenticateAsClientAsync("localhost", null, SslProtocolSupport.DefaultSslProtocols, false)); } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/ServerRequireEncryptionTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/ServerRequireEncryptionTest.cs index 1b15a408084ef9..f538b55bebceca 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/ServerRequireEncryptionTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/ServerRequireEncryptionTest.cs @@ -17,9 +17,9 @@ public class ServerRequireEncryptionTest { private readonly ITestOutputHelper _log; - public ServerRequireEncryptionTest() + public ServerRequireEncryptionTest(ITestOutputHelper output) { - _log = TestLogging.GetInstance(); + _log = output; } // The following method is invoked by the RemoteCertificateValidationDelegate. diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslAuthenticationOptionsTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslAuthenticationOptionsTest.cs index ada4a652b6e776..af9e02ad03ed60 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslAuthenticationOptionsTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslAuthenticationOptionsTest.cs @@ -14,8 +14,10 @@ namespace System.Net.Security.Tests { using Configuration = System.Net.Test.Common.Configuration; - public class SslClientAuthenticationOptionsTest + public abstract class SslClientAuthenticationOptionsTestBase { + protected abstract bool TestAuthenticateAsync { get; } + [Fact] public async Task ClientOptions_ServerOptions_NotMutatedDuringAuthentication() { @@ -74,9 +76,9 @@ public async Task ClientOptions_ServerOptions_NotMutatedDuringAuthentication() }; // Authenticate - Task clientTask = client.AuthenticateAsClientAsync(clientOptions, default); - Task serverTask = server.AuthenticateAsServerAsync(serverOptions, default); - await new[] { clientTask, serverTask }.WhenAllOrAnyFailed(); + Task clientTask = client.AuthenticateAsClientAsync(TestAuthenticateAsync, clientOptions); + Task serverTask = server.AuthenticateAsServerAsync(TestAuthenticateAsync, serverOptions); + await new[] {clientTask, serverTask}.WhenAllOrAnyFailed(); // Validate that client options are unchanged Assert.Equal(clientAllowRenegotiation, clientOptions.AllowRenegotiation); @@ -105,4 +107,14 @@ public async Task ClientOptions_ServerOptions_NotMutatedDuringAuthentication() } } } + + public sealed class SslClientAuthenticationOptionsTestBase_Sync : SslClientAuthenticationOptionsTestBase + { + protected override bool TestAuthenticateAsync => false; + } + + public sealed class SslClientAuthenticationOptionsTestBase_Async : SslClientAuthenticationOptionsTestBase + { + protected override bool TestAuthenticateAsync => true; + } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowRenegotiationTests.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowRenegotiationTests.cs index 1895d118ea6f24..b4147844b9060e 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowRenegotiationTests.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowRenegotiationTests.cs @@ -17,8 +17,10 @@ namespace System.Net.Security.Tests { using Configuration = System.Net.Test.Common.Configuration; - public class SslStreamAllowRenegotiationTests + public abstract class SslStreamAllowRenegotiationTestsBase { + protected abstract bool TestAuthenticateAsync { get; } + [Fact] [OuterLoop] // Test hits external azure server. public async Task SslStream_AllowRenegotiation_True_Succeeds() @@ -49,7 +51,7 @@ public async Task SslStream_AllowRenegotiation_True_Succeeds() }; // Perform handshake to establish secure connection. - await ssl.AuthenticateAsClientAsync(options, CancellationToken.None); + await ssl.AuthenticateAsClientAsync(TestAuthenticateAsync, options); Assert.True(ssl.IsAuthenticated); Assert.True(ssl.IsEncrypted); @@ -89,7 +91,7 @@ public async Task SslStream_AllowRenegotiation_False_Throws() }; // Perform handshake to establish secure connection. - await ssl.AuthenticateAsClientAsync(options, CancellationToken.None); + await ssl.AuthenticateAsClientAsync(TestAuthenticateAsync, options); Assert.True(ssl.IsAuthenticated); Assert.True(ssl.IsEncrypted); @@ -103,4 +105,14 @@ public async Task SslStream_AllowRenegotiation_False_Throws() } } } + + public sealed class SslStreamAllowRenegotiationTests_Sync : SslStreamAllowRenegotiationTestsBase + { + protected override bool TestAuthenticateAsync => false; + } + + public sealed class SslStreamAllowRenegotiationTests_Async : SslStreamAllowRenegotiationTestsBase + { + protected override bool TestAuthenticateAsync => true; + } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAlpnTests.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAlpnTests.cs index de5212a93fc4c6..c5284653585b78 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAlpnTests.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAlpnTests.cs @@ -21,19 +21,21 @@ namespace System.Net.Security.Tests { using Configuration = System.Net.Test.Common.Configuration; - public class SslStreamAlpnTests + public abstract class SslStreamAlpnTestBase { private static bool BackendSupportsAlpn => PlatformDetection.SupportsAlpn; private static bool ClientSupportsAlpn => PlatformDetection.SupportsClientAlpn; readonly ITestOutputHelper _output; public static readonly object[][] Http2Servers = Configuration.Http.Http2Servers; - public SslStreamAlpnTests(ITestOutputHelper output) + // Whether AuthenticateAs(Client/Server) or AuthenticateAs(Client/Server)Async will be called + public abstract bool TestAuthenticateAsync { get; } + + protected SslStreamAlpnTestBase(ITestOutputHelper output) { _output = output; } - private async Task DoHandshakeWithOptions(SslStream clientSslStream, SslStream serverSslStream, SslClientAuthenticationOptions clientOptions, SslServerAuthenticationOptions serverOptions) { using (X509Certificate2 certificate = Configuration.Certificates.GetServerCertificate()) @@ -42,8 +44,8 @@ private async Task DoHandshakeWithOptions(SslStream clientSslStream, SslStream s clientOptions.TargetHost = certificate.GetNameInfo(X509NameType.SimpleName, false); serverOptions.ServerCertificate = certificate; - Task t1 = clientSslStream.AuthenticateAsClientAsync(clientOptions, CancellationToken.None); - Task t2 = serverSslStream.AuthenticateAsServerAsync(serverOptions, CancellationToken.None); + Task t1 = clientSslStream.AuthenticateAsClientAsync(TestAuthenticateAsync, clientOptions); + Task t2 = serverSslStream.AuthenticateAsServerAsync(TestAuthenticateAsync, serverOptions); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); } @@ -95,8 +97,8 @@ public async Task SslStream_StreamToStream_DuplicateOptions_Throws() serverOptions.ServerCertificate = certificate; serverOptions.RemoteCertificateValidationCallback = AllowAnyServerCertificate; - Task t1 = Assert.ThrowsAsync(() => client.AuthenticateAsClientAsync(clientOptions, CancellationToken.None)); - Task t2 = Assert.ThrowsAsync(() => server.AuthenticateAsServerAsync(serverOptions, CancellationToken.None)); + Task t1 = Assert.ThrowsAsync(() => client.AuthenticateAsClientAsync(TestAuthenticateAsync, clientOptions)); + Task t2 = Assert.ThrowsAsync(() => server.AuthenticateAsServerAsync(TestAuthenticateAsync, serverOptions)); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); } @@ -163,11 +165,11 @@ public async Task SslStream_StreamToStream_Alpn_NonMatchingProtocols_Fail() { // schannel sends alert on ALPN failure, openssl does not. Task t1 = Assert.ThrowsAsync(TestConfiguration.SupportsAlpnAlerts ? typeof(AuthenticationException) : typeof(IOException), () => - clientStream.AuthenticateAsClientAsync(clientOptions, CancellationToken.None)); + clientStream.AuthenticateAsClientAsync(TestAuthenticateAsync, clientOptions)); try { - await serverStream.AuthenticateAsServerAsync(serverOptions, CancellationToken.None); + await serverStream.AuthenticateAsServerAsync(TestAuthenticateAsync, serverOptions); Assert.True(false, "AuthenticationException was not thrown."); } catch (AuthenticationException) { server.Dispose(); } @@ -176,8 +178,8 @@ public async Task SslStream_StreamToStream_Alpn_NonMatchingProtocols_Fail() } else { - Task t1 = clientStream.AuthenticateAsClientAsync(clientOptions, CancellationToken.None); - Task t2 = serverStream.AuthenticateAsServerAsync(serverOptions, CancellationToken.None); + Task t1 = clientStream.AuthenticateAsClientAsync(TestAuthenticateAsync, clientOptions); + Task t2 = serverStream.AuthenticateAsServerAsync(TestAuthenticateAsync, serverOptions); await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); @@ -211,7 +213,7 @@ public async Task SslStream_Http2_Alpn_Success(Uri server) TargetHost = server.Host }; - await clientStream.AuthenticateAsClientAsync(clientOptions, CancellationToken.None); + await clientStream.AuthenticateAsClientAsync(TestAuthenticateAsync, clientOptions); Assert.Equal("h2", clientStream.NegotiatedApplicationProtocol.ToString()); } } @@ -246,4 +248,20 @@ public static IEnumerable Alpn_TestData() } } } + + public sealed class SslStreamAlpnTest_Async : SslStreamAlpnTestBase + { + public override bool TestAuthenticateAsync => true; + + public SslStreamAlpnTest_Async(ITestOutputHelper output) + : base (output) { } + } + + public sealed class SslStreamAlpnTest_Sync : SslStreamAlpnTestBase + { + public override bool TestAuthenticateAsync => false; + + public SslStreamAlpnTest_Sync(ITestOutputHelper output) + : base(output) { } + } } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamExtensions.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamExtensions.cs new file mode 100644 index 00000000000000..e7e423ee89580c --- /dev/null +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamExtensions.cs @@ -0,0 +1,25 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace System.Net.Security.Tests +{ + internal static class SslStreamExtensions + { + public static Task AuthenticateAsClientAsync(this SslStream stream, + bool async, SslClientAuthenticationOptions clientOptions, + CancellationToken cancellationToken = default) + { + return async + ? stream.AuthenticateAsClientAsync(clientOptions, cancellationToken) + : Task.Run(() => stream.AuthenticateAsClient(clientOptions)); + } + public static Task AuthenticateAsServerAsync(this SslStream stream, + bool async, SslServerAuthenticationOptions serverOptions, + CancellationToken cancellationToken = default) + { + return async + ? stream.AuthenticateAsServerAsync(serverOptions, cancellationToken) + : Task.Run(() => stream.AuthenticateAsServer(serverOptions)); + } + } +} diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs index a54624100da2a8..b98a9ea992bdeb 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using System.IO; using System.Net.Test.Common; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; @@ -201,9 +202,7 @@ private static SslServerAuthenticationOptions DefaultServerOptions() private async Task WithVirtualConnection(Func serverClientConnection, RemoteCertificateValidationCallback clientCertValidate) { - VirtualNetwork vn = new VirtualNetwork(); - using (VirtualNetworkStream serverStream = new VirtualNetworkStream(vn, isServer: true), - clientStream = new VirtualNetworkStream(vn, isServer: false)) + (Stream clientStream, Stream serverStream) = TestHelper.GetConnectedStreams(); using (SslStream server = new SslStream(serverStream, leaveInnerStreamOpen: false), client = new SslStream(clientStream, leaveInnerStreamOpen: false, clientCertValidate)) { diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs index 93baf83fd156fe..9fb2ac9fefbd6b 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs @@ -395,7 +395,7 @@ public async Task SslStream_StreamToStream_WriteAsync_ReadByte_Success() [Fact] public async Task SslStream_StreamToStream_WriteAsync_ReadAsync_Pending_Success() { - if (this is SslStreamStreamToStreamTest_Sync) + if (this is SslStreamStreamToStreamTest_SyncBase) { // This test assumes operations complete asynchronously. return; @@ -488,7 +488,7 @@ public async Task SslStream_ConcurrentBidirectionalReadsWrites_Success() [Fact] public async Task SslStream_StreamToStream_Dispose_Throws() { - if (this is SslStreamStreamToStreamTest_Sync) + if (this is SslStreamStreamToStreamTest_SyncBase) { // This test assumes operations complete asynchronously. return; @@ -511,7 +511,7 @@ public async Task SslStream_StreamToStream_Dispose_Throws() await WriteAsync(serverSslStream, new byte[] { 1 }, 0, 1) .TimeoutAfter(TestConfiguration.PassingTestTimeoutMilliseconds); - // Shouldn't throw, the context is diposed now. + // Shouldn't throw, the context is disposed now. // Since the server read task is in progress, the read buffer is not returned to ArrayPool. serverSslStream.Dispose(); @@ -821,19 +821,8 @@ protected override Task WriteAsync(Stream stream, byte[] buffer, int offset, int Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, buffer, offset, count, null); } - public sealed class SslStreamStreamToStreamTest_Sync : SslStreamStreamToStreamTest + public abstract class SslStreamStreamToStreamTest_SyncBase : SslStreamStreamToStreamTest { - protected override async Task DoHandshake(SslStream clientSslStream, SslStream serverSslStream, X509Certificate serverCertificate = null, X509Certificate clientCertificate = null) - { - X509CertificateCollection clientCerts = clientCertificate != null ? new X509CertificateCollection() { clientCertificate } : null; - await WithServerCertificate(serverCertificate, async (certificate, name) => - { - Task t1 = Task.Run(() => clientSslStream.AuthenticateAsClient(name, clientCerts, SslProtocols.None, checkCertificateRevocation: false)); - Task t2 = Task.Run(() => serverSslStream.AuthenticateAsServer(certificate, clientCertificateRequired: clientCertificate != null, checkCertificateRevocation: false)); - await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); - }); - } - protected override Task ReadAsync(Stream stream, byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) @@ -868,6 +857,108 @@ protected override Task WriteAsync(Stream stream, byte[] buffer, int offset, int return Task.FromException(e); } } + + [Fact] + public async Task SslStream_StreamToStream_Handshake_DisposeClient_Throws() + { + VirtualNetwork network = new VirtualNetwork(); + + var clientStream = new VirtualNetworkStream(network, isServer: false); + using (var serverStream = new VirtualNetworkStream(network, isServer: true)) + using (var clientSslStream = new SslStream(clientStream, false, AllowAnyServerCertificate)) + using (var serverSslStream = new SslStream(serverStream)) + { + clientStream.Dispose(); + + await Assert.ThrowsAsync(() => DoHandshake(clientSslStream, serverSslStream)); + } + } + + [Fact] + public async Task SslStream_StreamToStream_Handshake_DisposeServer_Throws() + { + VirtualNetwork network = new VirtualNetwork(); + + var serverStream = new VirtualNetworkStream(network, isServer: true); + using (var clientStream = new VirtualNetworkStream(network, isServer: false)) + using (var clientSslStream = new SslStream(clientStream, false, AllowAnyServerCertificate)) + using (var serverSslStream = new SslStream(serverStream)) + { + serverStream.Dispose(); + + await Assert.ThrowsAsync(() => DoHandshake(clientSslStream, serverSslStream)); + } + } + + [Fact] + public async Task SslStream_StreamToStream_Handshake_DisposeClientSsl_Throws() + { + VirtualNetwork network = new VirtualNetwork() { DisableConnectionBreaking = true }; + + using (var clientStream = new VirtualNetworkStream(network, isServer: false)) + using (var serverStream = new VirtualNetworkStream(network, isServer: true)) + using (var serverSslStream = new SslStream(serverStream)) + { + var clientSslStream = new SslStream(clientStream, false, AllowAnyServerCertificate); + clientSslStream.Dispose(); + + await Assert.ThrowsAsync(() => DoHandshake(clientSslStream, serverSslStream)); + } + } + + [Fact] + public async Task SslStream_StreamToStream_Handshake_DisposeServerSsl_Throws() + { + VirtualNetwork network = new VirtualNetwork() {DisableConnectionBreaking = true}; + + using (var clientStream = new VirtualNetworkStream(network, isServer: false)) + using (var serverStream = new VirtualNetworkStream(network, isServer: true)) + using (var clientSslStream = new SslStream(clientStream, false, AllowAnyServerCertificate)) + { + var serverSslStream = new SslStream(serverStream); + serverSslStream.Dispose(); + + await Assert.ThrowsAsync(() => DoHandshake(clientSslStream, serverSslStream)); + } + } + } + + public sealed class SslStreamStreamToStreamTest_SyncParameters : SslStreamStreamToStreamTest_SyncBase + { + protected override async Task DoHandshake(SslStream clientSslStream, SslStream serverSslStream, X509Certificate serverCertificate = null, X509Certificate clientCertificate = null) + { + X509CertificateCollection clientCerts = clientCertificate != null ? new X509CertificateCollection() { clientCertificate } : null; + await WithServerCertificate(serverCertificate, async (certificate, name) => + { + Task t1 = Task.Run(() => clientSslStream.AuthenticateAsClient(name, clientCerts, SslProtocols.None, checkCertificateRevocation: false)); + Task t2 = Task.Run(() => serverSslStream.AuthenticateAsServer(certificate, clientCertificateRequired: clientCertificate != null, checkCertificateRevocation: false)); + await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); + }); + } + } + + public sealed class SslStreamStreamToStreamTest_SyncSslOptions : SslStreamStreamToStreamTest_SyncBase + { + protected override async Task DoHandshake(SslStream clientSslStream, SslStream serverSslStream, X509Certificate serverCertificate = null, X509Certificate clientCertificate = null) + { + X509CertificateCollection clientCerts = clientCertificate != null ? new X509CertificateCollection() { clientCertificate } : null; + await WithServerCertificate(serverCertificate, async (certificate, name) => + { + SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions + { + TargetHost = name, + ClientCertificates = clientCerts, + EnabledSslProtocols = SslProtocols.None, + }; + SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions() + { + ServerCertificate = certificate, ClientCertificateRequired = clientCertificate != null, + }; + Task t1 = Task.Run(() => clientSslStream.AuthenticateAsClient(clientOptions)); + Task t2 = Task.Run(() => serverSslStream.AuthenticateAsServer(serverOptions)); + await TestConfiguration.WhenAllOrAnyFailedWithTimeout(t1, t2); + }); + } } public sealed class SslStreamStreamToStreamTest_MemoryAsync : SslStreamStreamToStreamTest_CancelableReadWriteAsync diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamSystemDefaultsTest.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamSystemDefaultsTest.cs index 4943401bc51eee..bc704fae67fda3 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamSystemDefaultsTest.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamSystemDefaultsTest.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.IO; using System.Net.Http; using System.Net.Test.Common; using System.Security.Cryptography.X509Certificates; @@ -21,10 +22,7 @@ public abstract class SslStreamSystemDefaultTest public SslStreamSystemDefaultTest() { - var network = new VirtualNetwork(); - var clientNet = new VirtualNetworkStream(network, isServer:false); - var serverNet = new VirtualNetworkStream(network, isServer: true); - + (Stream clientNet, Stream serverNet) = TestHelper.GetConnectedTcpStreams(); _clientStream = new SslStream(clientNet, false, ClientCertCallback); _serverStream = new SslStream(serverNet, false, ServerCertCallback); } diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj index 1717a98df4cc8c..94026f1078c10d 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj @@ -9,6 +9,7 @@ + @@ -30,62 +31,44 @@ - - Common\System\IO\DelegateStream.cs - - - Common\System\Net\Capability.Security.cs - - - Common\System\Net\SslStreamCertificatePolicy.cs - - - Common\System\Net\Configuration.cs - - - Common\System\Net\Configuration.Security.cs - - - Common\System\Net\Configuration.Certificates.cs - - - Common\System\Net\Configuration.Http.cs - - - Common\System\Net\HttpsTestClient.cs - - - Common\System\Net\HttpsTestServer.cs - - - Common\System\Net\SslProtocolSupport.cs - - - Common\System\Net\TestLogging.cs - - - Common\System\Net\VerboseTestLogging.cs - - - Common\System\Net\EventSourceTestLogging.cs - - - Common\System\Net\VirtualNetwork\VirtualNetwork.cs - - - Common\System\Net\VirtualNetwork\VirtualNetworkStream.cs - - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - - - ProductionCode\Common\System\Threading\Tasks\TaskToApm.cs - - - - - src\SniHelper.cs - + + + + + + + + + + + + + + + + + + + @@ -101,27 +84,22 @@ - - Common\System\Diagnostics\Tracing\TestEventListener.cs - + - - Common\System\Net\Capability.Security.Windows.cs - + - - Common\System\Net\Capability.Security.Unix.cs - - - Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.IsNtlmInstalled.cs - - - Common\Interop\Unix\Interop.Libraries.cs - + + + diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/TestConfiguration.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/TestConfiguration.cs index 9769590181342e..1473b3065c46aa 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/TestConfiguration.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/TestConfiguration.cs @@ -16,7 +16,7 @@ namespace System.Net.Security.Tests internal static class TestConfiguration { public const int PassingTestTimeoutMilliseconds = 4 * 60 * 1000; - public const int FailingTestTimeoutMiliseconds = 250; + public const int FailingTestTimeoutMiliseconds = 500; public const string Realm = "TEST.COREFX.NET"; public const string KerberosUser = "krb_user"; @@ -32,9 +32,7 @@ internal static class TestConfiguration public static bool SupportsHandshakeAlerts { get { return RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.Windows); } } - public static bool SupportsAlpnAlerts { get { return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && PlatformDetection.OpenSslVersion.CompareTo(new Version(1,1,0)) >= 0); } } - - public static bool SupportsVersionAlerts { get { return RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && PlatformDetection.OpenSslVersion.CompareTo(new Version(1,1,0)) >= 0; } } + public static bool SupportsAlpnAlerts { get { return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && PlatformDetection.OpenSslVersion.CompareTo(new Version(1,0,2)) >= 0); } } public static Task WhenAllOrAnyFailedWithTimeout(params Task[] tasks) => tasks.WhenAllOrAnyFailed(PassingTestTimeoutMilliseconds); diff --git a/src/libraries/System.Net.Security/tests/StressTests/SslStress/SslStress.csproj b/src/libraries/System.Net.Security/tests/StressTests/SslStress/SslStress.csproj index 439b1e86e02c89..f383e35086a6e5 100644 --- a/src/libraries/System.Net.Security/tests/StressTests/SslStress/SslStress.csproj +++ b/src/libraries/System.Net.Security/tests/StressTests/SslStress/SslStress.csproj @@ -1,14 +1,15 @@ - + Exe netcoreapp3.0 enable - + - \ No newline at end of file + diff --git a/src/libraries/System.Net.Security/tests/UnitTests/Fakes/FakeLazyAsyncResult.cs b/src/libraries/System.Net.Security/tests/UnitTests/Fakes/FakeLazyAsyncResult.cs deleted file mode 100644 index 709fc583536f26..00000000000000 --- a/src/libraries/System.Net.Security/tests/UnitTests/Fakes/FakeLazyAsyncResult.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading; - -namespace System.Net.Security -{ - internal class LazyAsyncResult : IAsyncResult - { - public LazyAsyncResult(SslStream sslState, object asyncState, AsyncCallback asyncCallback) - { - AsyncState = asyncState; - asyncCallback?.Invoke(this); - } - - public object AsyncState { get; } - - public WaitHandle AsyncWaitHandle - { - get - { - throw new NotImplementedException(); - } - } - - public bool CompletedSynchronously - { - get - { - return true; - } - } - - public bool IsCompleted - { - get - { - return true; - } - } - } -} diff --git a/src/libraries/System.Net.Security/tests/UnitTests/Fakes/FakeSslStream.Implementation.cs b/src/libraries/System.Net.Security/tests/UnitTests/Fakes/FakeSslStream.Implementation.cs index 3dffb86a4da38a..ccd294beb54ddd 100644 --- a/src/libraries/System.Net.Security/tests/UnitTests/Fakes/FakeSslStream.Implementation.cs +++ b/src/libraries/System.Net.Security/tests/UnitTests/Fakes/FakeSslStream.Implementation.cs @@ -38,7 +38,7 @@ private void ValidateCreateContext(SslAuthenticationOptions sslAuthenticationOpt } private ValueTask WriteAsyncInternal(TWriteAdapter writeAdapter, ReadOnlyMemory buffer) - where TWriteAdapter : struct, ISslIOAdapter => default; + where TWriteAdapter : struct, IReadWriteAdapter => default; private ValueTask ReadAsyncInternal(TReadAdapter adapter, Memory buffer) => default; diff --git a/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj b/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj index d61c5a77775955..50d702a0b094ca 100644 --- a/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj +++ b/src/libraries/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj @@ -24,63 +24,45 @@ - - - CommonTest\System\Net\SslProtocolSupport.cs - - - Common\System\HexConverter.cs - + + - - ProductionCode\System\Net\Security\SslStream.cs - - - ProductionCode\System\Net\Security\SslClientAuthenticationOptions.cs - - - ProductionCode\System\Net\Security\SslServerAuthenticationOptions.cs - - - ProductionCode\System\Net\Security\SslAuthenticationOptions.cs - - - ProductionCode\System\Net\Security\SslApplicationProtocol.cs - - - ProductionCode\System\Net\Security\SslConnectionInfo.cs - - - ProductionCode\System\Net\Security\SslStream.Implementation.Adapters.cs - - - ProductionCode\System\Net\SslStreamContext.cs - - - ProductionCode\Common\System\Net\SecurityProtocol.cs - - - ProductionCode\Common\System\Net\TlsAlertType.cs - - - ProductionCode\Common\System\Net\TlsAlertMessage.cs - - - Common\Interop\Windows\SChannel\Interop.Alerts.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - + + + + + + + + + + + + + - - ProductionCode\Common\System\Net\Logging\NetEventSource.Common.cs - - - ProductionCode\Common\System\Net\InternalException.cs - + + diff --git a/src/libraries/System.Net.ServicePoint/tests/System.Net.ServicePoint.Tests.csproj b/src/libraries/System.Net.ServicePoint/tests/System.Net.ServicePoint.Tests.csproj index d3e7e345b74bfb..c82e88cf2d9074 100644 --- a/src/libraries/System.Net.ServicePoint/tests/System.Net.ServicePoint.Tests.csproj +++ b/src/libraries/System.Net.ServicePoint/tests/System.Net.ServicePoint.Tests.csproj @@ -5,8 +5,6 @@ - - \ No newline at end of file diff --git a/src/libraries/System.Net.Sockets/src/Resources/Strings.resx b/src/libraries/System.Net.Sockets/src/Resources/Strings.resx index 3078fabf5d5fd6..62f9bb2b41db9f 100644 --- a/src/libraries/System.Net.Sockets/src/Resources/Strings.resx +++ b/src/libraries/System.Net.Sockets/src/Resources/Strings.resx @@ -1,4 +1,5 @@ - + + @@ -192,8 +193,8 @@ The specified value cannot be negative. - - Argument must be between {0} and {1}. + + Argument '{2}' must be between {0} and {1}. Sockets on this platform are invalid for use after a failed connection attempt. @@ -258,4 +259,7 @@ Asynchronous operations are not allowed on this socket. The underlying OS handle might have been already bound to an IO completion port. - + + Null is not a valid value for {0}. + + \ No newline at end of file diff --git a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj index 3d74a783912353..ae41d45e7d897d 100644 --- a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj +++ b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj @@ -1,8 +1,8 @@ - + System.Net.Sockets true - $(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent)-Windows_NT + $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix enable @@ -48,70 +48,48 @@ - - Common\System\IO\StreamHelpers.CopyValidation.cs - + - - Common\System\Net\Logging\DebugThreadTracking.cs - - - Common\System\Net\Logging\NetEventSource.Common.cs - - - Common\System\Net\InternalException.cs - + + - - Common\System\Net\DebugSafeHandleMinusOneIsInvalid.cs - + - - Common\System\Net\ContextAwareResult.cs - - - Common\System\Net\LazyAsyncResult.cs - - - Common\System\Net\ByteOrder.cs - - - Common\System\Net\IPEndPointStatics.cs - - - Common\System\Net\IPAddressParserStatics.cs - - - Common\System\Net\ExceptionCheck.cs - - - Common\System\Net\RangeValidationHelpers.cs - - - Common\System\Net\SocketAddress.cs - - - Common\System\Net\TcpValidationHelpers.cs - + + + + + + + + + - - Common\System\Net\Internals\IPEndPointExtensions.cs - - - Common\System\Net\Internals\IPAddressExtensions.cs - - - Common\System\Net\Internals\SocketExceptionFactory.cs - - - Common\System\Net\Sockets\ProtocolFamily.cs - - - Common\System\Net\Sockets\ProtocolType.cs - - - Common\System\Net\Sockets\SocketType.cs - + + + + + + @@ -128,127 +106,87 @@ - - Common\System\Net\ContextAwareResult.Windows.cs - - - Common\System\Net\SocketAddressPal.Windows.cs - - - Common\System\Net\SocketProtocolSupportPal.Windows - + + + - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\WinSock\Interop.accept.cs - - - Common\Interop\Windows\WinSock\Interop.bind.cs - - - Common\Interop\Windows\WinSock\Interop.closesocket.cs - - - Common\Interop\Windows\WinSock\Interop.getpeername.cs - - - Common\Interop\Windows\WinSock\Interop.getsockname.cs - - - Common\Interop\Windows\WinSock\Interop.getsockopt.cs - - - Common\Interop\Windows\WinSock\Interop.ioctlsocket.cs - - - Common\Interop\Windows\WinSock\Interop.listen.cs - - - Common\Interop\Windows\WinSock\Interop.recv.cs - - - Common\Interop\Windows\WinSock\Interop.recvfrom.cs - - - Common\Interop\Windows\WinSock\Interop.select.cs - - - Common\Interop\Windows\WinSock\Interop.send.cs - - - Common\Interop\Windows\WinSock\Interop.sendto.cs - - - Common\Interop\Windows\WinSock\Interop.setsockopt.cs - - - Common\Interop\Windows\WinSock\Interop.shutdown.cs - - - Common\Interop\Windows\WinSock\Interop.TransmitFile.cs - - - Common\Interop\Windows\WinSock\Interop.WinsockBSD.cs - - - Common\Interop\Windows\WinSock\Interop.WinsockAsync.cs - - - Common\Interop\Windows\WinSock\Interop.WSAConnect.cs - - - Common\Interop\Windows\WinSock\Interop.WSADuplicateSocket.cs - - - Common\Interop\Windows\WinSock\Interop.WSAGetOverlappedResult.cs - - - Common\Interop\Windows\WinSock\Interop.WSAIoctl.cs - - - Common\Interop\Windows\WinSock\Interop.WSARecv.cs - - - Common\Interop\Windows\WinSock\Interop.WSARecvFrom.cs - - - Common\Interop\Windows\WinSock\Interop.WSASend.cs - - - Common\Interop\Windows\WinSock\Interop.WSASendTo.cs - - - Common\Interop\Windows\WinSock\Interop.WSASocketW.cs - - - Common\Interop\Windows\WinSock\Interop.WSASocketW.SafeCloseSocket.cs - - - Common\Interop\Windows\WinSock\Interop.SocketConstructorFlags.cs - - - Common\Interop\Windows\WinSock\SafeNativeOverlapped.cs - - - Common\Interop\Windows\WinSock\WSABuffer.cs - - - Common\Interop\Windows\WinSock\Interop.WSAPROTOCOL_INFOW.cs - - - Common\Interop\Windows\Interop.CancelIoEx.cs - - - Common\Interop\Windows\Kernel32\Interop.SetFileCompletionNotificationModes.cs - - - Common\Interop\Windows\Kernel32\Interop.HandleInformation.cs - - - Common\System\Net\CompletionPortHelper.Windows.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -264,135 +202,100 @@ - - Common\System\Net\ContextAwareResult.Unix.cs - - - Common\System\Net\InteropIPAddressExtensions.Unix.cs - - - Common\System\Net\SocketAddressPal.Unix.cs - - - Common\System\Net\SocketProtocolSupportPal.Unix - - - Common\System\Net\Sockets\SocketErrorPal.Unix - - - Common\System\Threading\Tasks\TaskToApm.cs - - - Common\Interop\Unix\Interop.Errors.cs - - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\System.Native\Interop.Accept.cs - - - Common\Interop\Unix\System.Native\Interop.Bind.cs - - - Common\Interop\Unix\System.Native\Interop.Close.cs - - - Common\Interop\Unix\System.Native\Interop.Connect.cs - - - Common\Interop\Unix\System.Native\Interop.Fcntl.cs - - - Common\Interop\Unix\Interop.Disconnect.cs - - - Common\Interop\Unix\System.Native\Interop.GetBytesAvailable.cs - - - Common\Interop\Unix\Interop.GetDomainSocketSizes.cs - - - Common\Interop\Unix\System.Native\Interop.GetPeerName.cs - - - Common\Interop\Unix\System.Native\Interop.GetSocketErrorOption.cs - - - Common\Interop\Unix\System.Native\Interop.GetSocketType.cs - - - Common\Interop\Unix\System.Native\Interop.GetSockName.cs - - - Common\Interop\Unix\System.Native\Interop.GetSockOpt.cs - - - Common\Interop\Unix\System.Native\Interop.IPAddress.cs - - - Common\Interop\Unix\System.Native\Interop.IPPacketInformation.cs - - - Common\Interop\Unix\System.Native\Interop.LingerOption.cs - - - Common\Interop\Unix\System.Native\Interop.SendFile.cs - - - Common\Interop\Unix\System.Native\Interop.SetSendTimeout.cs - - - Common\Interop\Unix\System.Native\Interop.SetReceiveTimeout.cs - - - Common\Interop\Unix\Interop.Stat.cs - - - Common\Interop\Unix\System.Native\Interop.Listen.cs - - - Common\Interop\Unix\System.Native\Interop.MemSet.cs - - - Common\Interop\Unix\System.Native\Interop.MessageHeader.cs - - - Common\Interop\Unix\System.Native\Interop.MulticastOption.cs - - - Common\Interop\Unix\System.Native\Interop.Poll.cs - - - Common\Interop\Unix\System.Native\Interop.PlatformSocketSupport.cs - - - Common\Interop\Unix\System.Native\Interop.ReceiveMessage.cs - - - Common\Interop\Unix\System.Native\Interop.SendMessage.cs - - - Common\Interop\Unix\System.Native\Interop.SetSockOpt.cs - - - Common\Interop\Unix\System.Native\Interop.Shutdown.cs - - - Common\Interop\Unix\System.Native\Interop.Socket.cs - - - Common\Interop\Unix\System.Native\Interop.SocketEvent.cs - - - Common\Interop\Unix\System.Native\Interop.SocketAddress.cs - - - Common\Interop\Unix\System.Native\Interop.Pipe.cs - - - Common\Interop\Unix\System.Native\Interop.Write.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -413,4 +316,7 @@ - \ No newline at end of file + + + + diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/BaseOverlappedAsyncResult.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/BaseOverlappedAsyncResult.Windows.cs index 004c0598796592..a92b87c084048d 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/BaseOverlappedAsyncResult.Windows.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/BaseOverlappedAsyncResult.Windows.cs @@ -60,74 +60,66 @@ internal void SetUnmanagedStructures(object? objectsToPin) private static unsafe void CompletionPortCallback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) { -#if DEBUG - DebugThreadTracking.SetThreadSource(ThreadKinds.CompletionPort); - using (DebugThreadTracking.SetThreadKind(ThreadKinds.System)) + BaseOverlappedAsyncResult asyncResult = (BaseOverlappedAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped)!; + + if (asyncResult.InternalPeekCompleted) { -#endif - BaseOverlappedAsyncResult asyncResult = (BaseOverlappedAsyncResult)ThreadPoolBoundHandle.GetNativeOverlappedState(nativeOverlapped)!; + NetEventSource.Fail(null, $"asyncResult.IsCompleted: {asyncResult}"); + } + if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"errorCode:{errorCode} numBytes:{numBytes} nativeOverlapped:{(IntPtr)nativeOverlapped}"); + + // Complete the IO and invoke the user's callback. + SocketError socketError = (SocketError)errorCode; - if (asyncResult.InternalPeekCompleted) + if (socketError != SocketError.Success && socketError != SocketError.OperationAborted) + { + // There are cases where passed errorCode does not reflect the details of the underlined socket error. + // "So as of today, the key is the difference between WSAECONNRESET and ConnectionAborted, + // .e.g remote party or network causing the connection reset or something on the local host (e.g. closesocket + // or receiving data after shutdown (SD_RECV)). With Winsock/TCP stack rewrite in longhorn, there may + // be other differences as well." + + Socket? socket = asyncResult.AsyncObject as Socket; + if (socket == null) { - NetEventSource.Fail(null, $"asyncResult.IsCompleted: {asyncResult}"); + socketError = SocketError.NotSocket; } - if (NetEventSource.IsEnabled) NetEventSource.Info(null, $"errorCode:{errorCode} numBytes:{numBytes} nativeOverlapped:{(IntPtr)nativeOverlapped}"); - - // Complete the IO and invoke the user's callback. - SocketError socketError = (SocketError)errorCode; - - if (socketError != SocketError.Success && socketError != SocketError.OperationAborted) + else if (socket.Disposed) { - // There are cases where passed errorCode does not reflect the details of the underlined socket error. - // "So as of today, the key is the difference between WSAECONNRESET and ConnectionAborted, - // .e.g remote party or network causing the connection reset or something on the local host (e.g. closesocket - // or receiving data after shutdown (SD_RECV)). With Winsock/TCP stack rewrite in longhorn, there may - // be other differences as well." - - Socket? socket = asyncResult.AsyncObject as Socket; - if (socket == null) - { - socketError = SocketError.NotSocket; - } - else if (socket.Disposed) - { - socketError = SocketError.OperationAborted; - } - else + socketError = SocketError.OperationAborted; + } + else + { + try { - try + // The async IO completed with a failure. + // Here we need to call WSAGetOverlappedResult() just so GetLastSocketError() will return the correct error. + SocketFlags ignore; + bool success = Interop.Winsock.WSAGetOverlappedResult( + socket.SafeHandle, + nativeOverlapped, + out numBytes, + false, + out ignore); + if (!success) { - // The async IO completed with a failure. - // Here we need to call WSAGetOverlappedResult() just so GetLastSocketError() will return the correct error. - SocketFlags ignore; - bool success = Interop.Winsock.WSAGetOverlappedResult( - socket.SafeHandle, - nativeOverlapped, - out numBytes, - false, - out ignore); - if (!success) - { - socketError = SocketPal.GetLastSocketError(); - } - if (success) - { - NetEventSource.Fail(asyncResult, $"Unexpectedly succeeded. errorCode:{errorCode} numBytes:{numBytes}"); - } + socketError = SocketPal.GetLastSocketError(); } - catch (ObjectDisposedException) + if (success) { - // Disposed check above does not always work since this code is subject to race conditions - socketError = SocketError.OperationAborted; + NetEventSource.Fail(asyncResult, $"Unexpectedly succeeded. errorCode:{errorCode} numBytes:{numBytes}"); } } + catch (ObjectDisposedException) + { + // Disposed check above does not always work since this code is subject to race conditions + socketError = SocketError.OperationAborted; + } } - - // Set results and invoke callback - asyncResult.CompletionCallback((int)numBytes, socketError); -#if DEBUG } -#endif + + // Set results and invoke callback + asyncResult.CompletionCallback((int)numBytes, socketError); } // Called either synchronously from SocketPal async routines or asynchronously via CompletionPortCallback above. diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/MultipleConnectAsync.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/MultipleConnectAsync.cs index e301f6d5f1019e..c201d247f9edf3 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/MultipleConnectAsync.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/MultipleConnectAsync.cs @@ -230,55 +230,31 @@ private void InternalConnectCallback(object? sender, SocketAsyncEventArgs args) { try { - Socket? attemptSocket; - IPAddress? attemptAddress = GetNextAddress(out attemptSocket); - + IPAddress? attemptAddress = GetNextAddress(out Socket? attemptSocket); if (attemptAddress == null) { return new SocketException((int)SocketError.NoData); } + Debug.Assert(attemptSocket != null); - _internalArgs!.RemoteEndPoint = new IPEndPoint(attemptAddress, _endPoint!.Port); - - return AttemptConnection(attemptSocket!, _internalArgs); - } - catch (Exception e) - { - if (e is ObjectDisposedException) - { - NetEventSource.Fail(this, "unexpected ObjectDisposedException"); - } - return e; - } - } - - private Exception? AttemptConnection(Socket attemptSocket, SocketAsyncEventArgs args) - { - try - { - if (attemptSocket == null) - { - NetEventSource.Fail(null, "attemptSocket is null!"); - } - - bool pending = attemptSocket.ConnectAsync(args); - if (!pending) + SocketAsyncEventArgs args = _internalArgs!; + args.RemoteEndPoint = new IPEndPoint(attemptAddress, _endPoint!.Port); + if (!attemptSocket.ConnectAsync(args)) { InternalConnectCallback(null, args); } + + return null; } catch (ObjectDisposedException) { - // This can happen if the user closes the socket, and is equivalent to a call - // to CancelConnectAsync + // This can happen if the user closes the socket and is equivalent to a call to CancelConnectAsync. return new SocketException((int)SocketError.OperationAborted); } catch (Exception e) { return e; } - - return null; } protected abstract void OnSucceed(); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs index 78f87814575a6a..077ad2d818d27a 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs @@ -41,47 +41,44 @@ public NetworkStream(Socket socket, FileAccess access) public NetworkStream(Socket socket, FileAccess access, bool ownsSocket) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User)) + if (socket == null) { -#endif - if (socket == null) - { - throw new ArgumentNullException(nameof(socket)); - } - if (!socket.Blocking) - { - throw new IOException(SR.net_sockets_blocking); - } - if (!socket.Connected) - { - throw new IOException(SR.net_notconnected); - } - if (socket.SocketType != SocketType.Stream) - { - throw new IOException(SR.net_notstream); - } + throw new ArgumentNullException(nameof(socket)); + } + if (!socket.Blocking) + { + // Stream.Read*/Write* are incompatible with the semantics of non-blocking sockets, and + // allowing non-blocking sockets could result in non-deterministic failures from those + // operations. A developer that requires using NetworkStream with a non-blocking socket can + // temporarily flip Socket.Blocking as a workaround. + throw new IOException(SR.net_sockets_blocking); + } + if (!socket.Connected) + { + throw new IOException(SR.net_notconnected); + } + if (socket.SocketType != SocketType.Stream) + { + throw new IOException(SR.net_notstream); + } - _streamSocket = socket; - _ownsSocket = ownsSocket; + _streamSocket = socket; + _ownsSocket = ownsSocket; - switch (access) - { - case FileAccess.Read: - _readable = true; - break; - case FileAccess.Write: - _writeable = true; - break; - case FileAccess.ReadWrite: - default: // assume FileAccess.ReadWrite - _readable = true; - _writeable = true; - break; - } -#if DEBUG + switch (access) + { + case FileAccess.Read: + _readable = true; + break; + case FileAccess.Write: + _writeable = true; + break; + case FileAccess.ReadWrite: + default: // assume FileAccess.ReadWrite + _readable = true; + _writeable = true; + break; } -#endif } public Socket Socket => _streamSocket; @@ -120,34 +117,20 @@ public override int ReadTimeout { get { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) + int timeout = (int)_streamSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout)!; + if (timeout == 0) { -#endif - int timeout = (int)_streamSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout)!; - if (timeout == 0) - { - return -1; - } - return timeout; -#if DEBUG + return -1; } -#endif + return timeout; } set { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) + if (value <= 0 && value != System.Threading.Timeout.Infinite) { -#endif - if (value <= 0 && value != System.Threading.Timeout.Infinite) - { - throw new ArgumentOutOfRangeException(nameof(value), SR.net_io_timeout_use_gt_zero); - } - SetSocketTimeoutOption(SocketShutdown.Receive, value, false); -#if DEBUG + throw new ArgumentOutOfRangeException(nameof(value), SR.net_io_timeout_use_gt_zero); } -#endif + SetSocketTimeoutOption(SocketShutdown.Receive, value, false); } } @@ -157,34 +140,20 @@ public override int WriteTimeout { get { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) + int timeout = (int)_streamSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout)!; + if (timeout == 0) { -#endif - int timeout = (int)_streamSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout)!; - if (timeout == 0) - { - return -1; - } - return timeout; -#if DEBUG + return -1; } -#endif + return timeout; } set { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) + if (value <= 0 && value != System.Threading.Timeout.Infinite) { -#endif - if (value <= 0 && value != System.Threading.Timeout.Infinite) - { - throw new ArgumentOutOfRangeException(nameof(value), SR.net_io_timeout_use_gt_zero); - } - SetSocketTimeoutOption(SocketShutdown.Send, value, false); -#if DEBUG + throw new ArgumentOutOfRangeException(nameof(value), SR.net_io_timeout_use_gt_zero); } -#endif + SetSocketTimeoutOption(SocketShutdown.Send, value, false); } } @@ -194,18 +163,11 @@ public virtual bool DataAvailable { get { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) - { -#endif - ThrowIfDisposed(); + ThrowIfDisposed(); - // Ask the socket how many bytes are available. If it's - // not zero, return true. - return _streamSocket.Available != 0; -#if DEBUG - } -#endif + // Ask the socket how many bytes are available. If it's + // not zero, return true. + return _streamSocket.Available != 0; } } @@ -255,44 +217,37 @@ public override long Seek(long offset, SeekOrigin origin) // Number of bytes we read, or 0 if the socket is closed. public override int Read(byte[] buffer, int offset, int size) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) + bool canRead = CanRead; // Prevent race with Dispose. + ThrowIfDisposed(); + if (!canRead) { -#endif - bool canRead = CanRead; // Prevent race with Dispose. - ThrowIfDisposed(); - if (!canRead) - { - throw new InvalidOperationException(SR.net_writeonlystream); - } + throw new InvalidOperationException(SR.net_writeonlystream); + } - // Validate input parameters. - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - if ((uint)offset > buffer.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - if ((uint)size > buffer.Length - offset) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } + // Validate input parameters. + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + if ((uint)offset > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + if ((uint)size > buffer.Length - offset) + { + throw new ArgumentOutOfRangeException(nameof(size)); + } - try - { - return _streamSocket.Receive(buffer, offset, size, 0); - } - catch (Exception exception) when (!(exception is OutOfMemoryException)) - { - // Some sort of error occurred on the socket call, - // set the SocketException as InnerException and throw. - throw new IOException(SR.Format(SR.net_io_readfailure, exception.Message), exception); - } -#if DEBUG + try + { + return _streamSocket.Receive(buffer, offset, size, 0); + } + catch (Exception exception) when (!(exception is OutOfMemoryException)) + { + // Some sort of error occurred on the socket call, + // set the SocketException as InnerException and throw. + throw new IOException(SR.Format(SR.net_io_readfailure, exception.Message), exception); } -#endif } public override int Read(Span buffer) @@ -341,46 +296,39 @@ public override unsafe int ReadByte() // way to indicate an error. public override void Write(byte[] buffer, int offset, int size) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) + bool canWrite = CanWrite; // Prevent race with Dispose. + ThrowIfDisposed(); + if (!canWrite) { -#endif - bool canWrite = CanWrite; // Prevent race with Dispose. - ThrowIfDisposed(); - if (!canWrite) - { - throw new InvalidOperationException(SR.net_readonlystream); - } + throw new InvalidOperationException(SR.net_readonlystream); + } - // Validate input parameters. - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - if ((uint)offset > buffer.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - if ((uint)size > buffer.Length - offset) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } + // Validate input parameters. + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + if ((uint)offset > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + if ((uint)size > buffer.Length - offset) + { + throw new ArgumentOutOfRangeException(nameof(size)); + } - try - { - // Since the socket is in blocking mode this will always complete - // after ALL the requested number of bytes was transferred. - _streamSocket.Send(buffer, offset, size, SocketFlags.None); - } - catch (Exception exception) when (!(exception is OutOfMemoryException)) - { - // Some sort of error occurred on the socket call, - // set the SocketException as InnerException and throw. - throw new IOException(SR.Format(SR.net_io_writefailure, exception.Message), exception); - } -#if DEBUG + try + { + // Since the socket is in blocking mode this will always complete + // after ALL the requested number of bytes was transferred. + _streamSocket.Send(buffer, offset, size, SocketFlags.None); + } + catch (Exception exception) when (!(exception is OutOfMemoryException)) + { + // Some sort of error occurred on the socket call, + // set the SocketException as InnerException and throw. + throw new IOException(SR.Format(SR.net_io_writefailure, exception.Message), exception); } -#endif } public override void Write(ReadOnlySpan buffer) @@ -412,61 +360,42 @@ public override unsafe void WriteByte(byte value) => public void Close(int timeout) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) + if (timeout < -1) { -#endif - if (timeout < -1) - { - throw new ArgumentOutOfRangeException(nameof(timeout)); - } - _closeTimeout = timeout; - Dispose(); -#if DEBUG + throw new ArgumentOutOfRangeException(nameof(timeout)); } -#endif + _closeTimeout = timeout; + Dispose(); } private volatile bool _disposed = false; protected override void Dispose(bool disposing) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User)) + // Mark this as disposed before changing anything else. + bool disposed = _disposed; + _disposed = true; + if (!disposed && disposing) { -#endif - // Mark this as disposed before changing anything else. - bool disposed = _disposed; - _disposed = true; - if (!disposed && disposing) + // The only resource we need to free is the network stream, since this + // is based on the client socket, closing the stream will cause us + // to flush the data to the network, close the stream and (in the + // NetoworkStream code) close the socket as well. + _readable = false; + _writeable = false; + if (_ownsSocket) { - // The only resource we need to free is the network stream, since this - // is based on the client socket, closing the stream will cause us - // to flush the data to the network, close the stream and (in the - // NetoworkStream code) close the socket as well. - _readable = false; - _writeable = false; - if (_ownsSocket) - { - // If we own the Socket (false by default), close it - // ignoring possible exceptions (eg: the user told us - // that we own the Socket but it closed at some point of time, - // here we would get an ObjectDisposedException) - _streamSocket.InternalShutdown(SocketShutdown.Both); - _streamSocket.Close(_closeTimeout); - } + // If we own the Socket (false by default), close it + // ignoring possible exceptions (eg: the user told us + // that we own the Socket but it closed at some point of time, + // here we would get an ObjectDisposedException) + _streamSocket.InternalShutdown(SocketShutdown.Both); + _streamSocket.Close(_closeTimeout); } -#if DEBUG } -#endif + base.Dispose(disposing); } - ~NetworkStream() - { -#if DEBUG - DebugThreadTracking.SetThreadSource(ThreadKinds.Finalization); -#endif - Dispose(false); - } + ~NetworkStream() => Dispose(false); // BeginRead - provide async read functionality. // @@ -484,50 +413,43 @@ protected override void Dispose(bool disposing) // An IASyncResult, representing the read. public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback? callback, object? state) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) + bool canRead = CanRead; // Prevent race with Dispose. + ThrowIfDisposed(); + if (!canRead) { -#endif - bool canRead = CanRead; // Prevent race with Dispose. - ThrowIfDisposed(); - if (!canRead) - { - throw new InvalidOperationException(SR.net_writeonlystream); - } + throw new InvalidOperationException(SR.net_writeonlystream); + } - // Validate input parameters. - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - if ((uint)offset > buffer.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - if ((uint)size > buffer.Length - offset) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } + // Validate input parameters. + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + if ((uint)offset > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + if ((uint)size > buffer.Length - offset) + { + throw new ArgumentOutOfRangeException(nameof(size)); + } - try - { - return _streamSocket.BeginReceive( - buffer, - offset, - size, - SocketFlags.None, - callback, - state); - } - catch (Exception exception) when (!(exception is OutOfMemoryException)) - { - // Some sort of error occurred on the socket call, - // set the SocketException as InnerException and throw. - throw new IOException(SR.Format(SR.net_io_readfailure, exception.Message), exception); - } -#if DEBUG + try + { + return _streamSocket.BeginReceive( + buffer, + offset, + size, + SocketFlags.None, + callback, + state); + } + catch (Exception exception) when (!(exception is OutOfMemoryException)) + { + // Some sort of error occurred on the socket call, + // set the SocketException as InnerException and throw. + throw new IOException(SR.Format(SR.net_io_readfailure, exception.Message), exception); } -#endif } // EndRead - handle the end of an async read. @@ -540,31 +462,24 @@ public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, Asyn // The number of bytes read. May throw an exception. public override int EndRead(IAsyncResult asyncResult) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User)) - { -#endif - ThrowIfDisposed(); + ThrowIfDisposed(); - // Validate input parameters. - if (asyncResult == null) - { - throw new ArgumentNullException(nameof(asyncResult)); - } + // Validate input parameters. + if (asyncResult == null) + { + throw new ArgumentNullException(nameof(asyncResult)); + } - try - { - return _streamSocket.EndReceive(asyncResult); - } - catch (Exception exception) when (!(exception is OutOfMemoryException)) - { - // Some sort of error occurred on the socket call, - // set the SocketException as InnerException and throw. - throw new IOException(SR.Format(SR.net_io_readfailure, exception.Message), exception); - } -#if DEBUG + try + { + return _streamSocket.EndReceive(asyncResult); + } + catch (Exception exception) when (!(exception is OutOfMemoryException)) + { + // Some sort of error occurred on the socket call, + // set the SocketException as InnerException and throw. + throw new IOException(SR.Format(SR.net_io_readfailure, exception.Message), exception); } -#endif } // BeginWrite - provide async write functionality. @@ -583,51 +498,44 @@ public override int EndRead(IAsyncResult asyncResult) // An IASyncResult, representing the write. public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback? callback, object? state) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) + bool canWrite = CanWrite; // Prevent race with Dispose. + ThrowIfDisposed(); + if (!canWrite) { -#endif - bool canWrite = CanWrite; // Prevent race with Dispose. - ThrowIfDisposed(); - if (!canWrite) - { - throw new InvalidOperationException(SR.net_readonlystream); - } + throw new InvalidOperationException(SR.net_readonlystream); + } - // Validate input parameters. - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - if ((uint)offset > buffer.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - if ((uint)size > buffer.Length - offset) - { - throw new ArgumentOutOfRangeException(nameof(size)); - } + // Validate input parameters. + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + if ((uint)offset > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + if ((uint)size > buffer.Length - offset) + { + throw new ArgumentOutOfRangeException(nameof(size)); + } - try - { - // Call BeginSend on the Socket. - return _streamSocket.BeginSend( - buffer, - offset, - size, - SocketFlags.None, - callback, - state); - } - catch (Exception exception) when (!(exception is OutOfMemoryException)) - { - // Some sort of error occurred on the socket call, - // set the SocketException as InnerException and throw. - throw new IOException(SR.Format(SR.net_io_writefailure, exception.Message), exception); - } -#if DEBUG + try + { + // Call BeginSend on the Socket. + return _streamSocket.BeginSend( + buffer, + offset, + size, + SocketFlags.None, + callback, + state); + } + catch (Exception exception) when (!(exception is OutOfMemoryException)) + { + // Some sort of error occurred on the socket call, + // set the SocketException as InnerException and throw. + throw new IOException(SR.Format(SR.net_io_writefailure, exception.Message), exception); } -#endif } // Handle the end of an asynchronous write. @@ -636,31 +544,24 @@ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, Asy // Returns: The number of bytes read. May throw an exception. public override void EndWrite(IAsyncResult asyncResult) { -#if DEBUG - using (DebugThreadTracking.SetThreadKind(ThreadKinds.User)) - { -#endif - ThrowIfDisposed(); + ThrowIfDisposed(); - // Validate input parameters. - if (asyncResult == null) - { - throw new ArgumentNullException(nameof(asyncResult)); - } + // Validate input parameters. + if (asyncResult == null) + { + throw new ArgumentNullException(nameof(asyncResult)); + } - try - { - _streamSocket.EndSend(asyncResult); - } - catch (Exception exception) when (!(exception is OutOfMemoryException)) - { - // Some sort of error occurred on the socket call, - // set the SocketException as InnerException and throw. - throw new IOException(SR.Format(SR.net_io_writefailure, exception.Message), exception); - } -#if DEBUG + try + { + _streamSocket.EndSend(asyncResult); + } + catch (Exception exception) when (!(exception is OutOfMemoryException)) + { + // Some sort of error occurred on the socket call, + // set the SocketException as InnerException and throw. + throw new IOException(SR.Format(SR.net_io_writefailure, exception.Message), exception); } -#endif } // ReadAsync - provide async read functionality. diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs index 3a8593d0b0745a..cde90ae0931cc5 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs @@ -119,66 +119,70 @@ private Task AcceptAsyncApm(Socket? acceptSocket) internal Task ConnectAsync(EndPoint remoteEP) { - var tcs = new TaskCompletionSource(this); - BeginConnect(remoteEP, iar => + // Use ValueTaskReceive so the AwaitableSocketAsyncEventArgs can be re-used later. + AwaitableSocketAsyncEventArgs saea = LazyInitializer.EnsureInitialized(ref EventArgs.ValueTaskReceive, () => new AwaitableSocketAsyncEventArgs()); + + if (!saea.Reserve()) { - var innerTcs = (TaskCompletionSource)iar.AsyncState!; - try - { - ((Socket)innerTcs.Task.AsyncState!).EndConnect(iar); - innerTcs.TrySetResult(true); - } - catch (Exception e) { innerTcs.TrySetException(e); } - }, tcs); - return tcs.Task; + saea = new AwaitableSocketAsyncEventArgs(); + saea.Reserve(); + } + + saea.RemoteEndPoint = remoteEP; + return saea.ConnectAsync(this).AsTask(); } internal Task ConnectAsync(IPAddress address, int port) + => ConnectAsync(new IPEndPoint(address, port)); + + internal Task ConnectAsync(IPAddress[] addresses, int port) { - var tcs = new TaskCompletionSource(this); - BeginConnect(address, port, iar => + if (addresses == null) { - var innerTcs = (TaskCompletionSource)iar.AsyncState!; - try - { - ((Socket)innerTcs.Task.AsyncState!).EndConnect(iar); - innerTcs.TrySetResult(true); - } - catch (Exception e) { innerTcs.TrySetException(e); } - }, tcs); - return tcs.Task; + throw new ArgumentNullException(nameof(addresses)); + } + if (addresses.Length == 0) + { + throw new ArgumentException(SR.net_invalidAddressList, nameof(addresses)); + } + + return DoConnectAsync(addresses, port); } - internal Task ConnectAsync(IPAddress[] addresses, int port) + private async Task DoConnectAsync(IPAddress[] addresses, int port) { - var tcs = new TaskCompletionSource(this); - BeginConnect(addresses, port, iar => + Exception? lastException = null; + foreach (IPAddress address in addresses) { - var innerTcs = (TaskCompletionSource)iar.AsyncState!; try { - ((Socket)innerTcs.Task.AsyncState!).EndConnect(iar); - innerTcs.TrySetResult(true); + await ConnectAsync(address, port).ConfigureAwait(false); + return; } - catch (Exception e) { innerTcs.TrySetException(e); } - }, tcs); - return tcs.Task; + catch (Exception ex) + { + lastException = ex; + } + } + Debug.Assert(lastException != null); + ExceptionDispatchInfo.Throw(lastException); } internal Task ConnectAsync(string host, int port) { - var tcs = new TaskCompletionSource(this); - BeginConnect(host, port, iar => + if (host == null) { - var innerTcs = (TaskCompletionSource)iar.AsyncState!; - try - { - ((Socket)innerTcs.Task.AsyncState!).EndConnect(iar); - innerTcs.TrySetResult(true); - } - catch (Exception e) { innerTcs.TrySetException(e); } - }, tcs); - return tcs.Task; + throw new ArgumentNullException(nameof(host)); + } + + if (IPAddress.TryParse(host, out IPAddress? parsedAddress)) + { + return ConnectAsync(new IPEndPoint(parsedAddress, port)); + } + else + { + return ConnectAsync(new DnsEndPoint(host, port)); + } } internal Task ReceiveAsync(ArraySegment buffer, SocketFlags socketFlags, bool fromNetworkStream) @@ -946,6 +950,32 @@ public ValueTask SendAsyncForNetworkStream(Socket socket, CancellationToken canc new ValueTask(Task.FromException(CreateException(error))); } + public ValueTask ConnectAsync(Socket socket) + { + Debug.Assert(Volatile.Read(ref _continuation) == null, $"Expected null continuation to indicate reserved for use"); + + try + { + if (socket.ConnectAsync(this)) + { + return new ValueTask(this, _token); + } + } + catch + { + Release(); + throw; + } + + SocketError error = SocketError; + + Release(); + + return error == SocketError.Success ? + default : + new ValueTask(Task.FromException(CreateException(error))); + } + /// Gets the status of the operation. public ValueTaskSourceStatus GetStatus(short token) { diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs index d5092637f52447..1540d733a40843 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs @@ -48,7 +48,7 @@ partial void ValidateForMultiConnect(bool isMultiEndpoint) } private static unsafe void LoadSocketTypeFromHandle( - SafeSocketHandle handle, out AddressFamily addressFamily, out SocketType socketType, out ProtocolType protocolType, out bool blocking) + SafeSocketHandle handle, out AddressFamily addressFamily, out SocketType socketType, out ProtocolType protocolType, out bool blocking, out bool isListening) { // Validate that the supplied handle is indeed a socket. if (Interop.Sys.FStat(handle, out Interop.Sys.FileStatus stat) == -1 || @@ -61,7 +61,7 @@ private static unsafe void LoadSocketTypeFromHandle( // address family, socket type, and protocol type, respectively. On macOS, this will only succeed // in getting the socket type, and the others will be unknown. Subsequently the Socket ctor // can use getsockname to retrieve the address family as part of trying to get the local end point. - Interop.Error e = Interop.Sys.GetSocketType(handle, out addressFamily, out socketType, out protocolType); + Interop.Error e = Interop.Sys.GetSocketType(handle, out addressFamily, out socketType, out protocolType, out isListening); Debug.Assert(e == Interop.Error.SUCCESS, e.ToString()); // Get whether the socket is in non-blocking mode. On Unix, we automatically put the underlying diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs index 2034cab6efb063..8e1be908e3d664 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs @@ -85,7 +85,7 @@ public Socket(SocketInformation socketInformation) } private unsafe void LoadSocketTypeFromHandle( - SafeSocketHandle handle, out AddressFamily addressFamily, out SocketType socketType, out ProtocolType protocolType, out bool blocking) + SafeSocketHandle handle, out AddressFamily addressFamily, out SocketType socketType, out ProtocolType protocolType, out bool blocking, out bool isListening) { Interop.Winsock.WSAPROTOCOL_INFOW info = default; int optionLength = sizeof(Interop.Winsock.WSAPROTOCOL_INFOW); @@ -100,6 +100,10 @@ private unsafe void LoadSocketTypeFromHandle( socketType = info.iSocketType; protocolType = info.iProtocol; + isListening = + SocketPal.GetSockOpt(_handle, SocketOptionLevel.Socket, SocketOptionName.AcceptConnection, out int isListeningValue) == SocketError.Success && + isListeningValue != 0; + // There's no API to retrieve this (WSAIsBlocking isn't supported any more). Assume it's blocking, but we might be wrong. // This affects the result of querying Socket.Blocking, which will mostly only affect user code that happens to query // that property, though there are a few places we check it internally, e.g. as part of NetworkStream argument validation. diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index 925e4e89c0f06f..e307dc4d6812b3 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -140,15 +140,12 @@ private unsafe Socket(SafeSocketHandle handle, bool loadPropertiesFromHandle) try { // Get properties like address family and blocking mode from the OS. - LoadSocketTypeFromHandle(handle, out _addressFamily, out _socketType, out _protocolType, out _willBlockInternal); - - // Determine whether the socket is in listening mode. - _isListening = - SocketPal.GetSockOpt(_handle, SocketOptionLevel.Socket, SocketOptionName.AcceptConnection, out int isListening) == SocketError.Success && - isListening != 0; + LoadSocketTypeFromHandle(handle, out _addressFamily, out _socketType, out _protocolType, out _willBlockInternal, out _isListening); + // We should change stackalloc if this ever grows too big. + Debug.Assert(SocketPal.MaximumAddressSize <= 512); // Try to get the address of the socket. - Span buffer = stackalloc byte[512]; // arbitrary high limit that should suffice for almost all scenarios + Span buffer = stackalloc byte[SocketPal.MaximumAddressSize]; int bufferLength = buffer.Length; fixed (byte* bufferPtr = buffer) { @@ -158,30 +155,7 @@ private unsafe Socket(SafeSocketHandle handle, bool loadPropertiesFromHandle) } } - if (bufferLength > buffer.Length) - { - buffer = new byte[buffer.Length]; - fixed (byte* bufferPtr = buffer) - { - if (SocketPal.GetSockName(handle, bufferPtr, &bufferLength) != SocketError.Success || - bufferLength > buffer.Length) - { - return; - } - } - } - - buffer = buffer.Slice(0, bufferLength); - if (_addressFamily == AddressFamily.Unknown) - { - _addressFamily = SocketAddressPal.GetAddressFamily(buffer); - } -#if DEBUG - else - { - Debug.Assert(_addressFamily == SocketAddressPal.GetAddressFamily(buffer)); - } -#endif + Debug.Assert(bufferLength <= buffer.Length); // Try to get the local end point. That will in turn enable the remote // end point to be retrieved on-demand when the property is accessed. @@ -190,20 +164,20 @@ private unsafe Socket(SafeSocketHandle handle, bool loadPropertiesFromHandle) { case AddressFamily.InterNetwork: _rightEndPoint = new IPEndPoint( - new IPAddress((long)SocketAddressPal.GetIPv4Address(buffer) & 0x0FFFFFFFF), + new IPAddress((long)SocketAddressPal.GetIPv4Address(buffer.Slice(0, bufferLength)) & 0x0FFFFFFFF), SocketAddressPal.GetPort(buffer)); break; case AddressFamily.InterNetworkV6: Span address = stackalloc byte[IPAddressParserStatics.IPv6AddressBytes]; - SocketAddressPal.GetIPv6Address(buffer, address, out uint scope); + SocketAddressPal.GetIPv6Address(buffer.Slice(0, bufferLength), address, out uint scope); _rightEndPoint = new IPEndPoint( new IPAddress(address, scope), SocketAddressPal.GetPort(buffer)); break; case AddressFamily.Unix: - socketAddress = new Internals.SocketAddress(_addressFamily, buffer); + socketAddress = new Internals.SocketAddress(_addressFamily, buffer.Slice(0, bufferLength)); _rightEndPoint = new UnixDomainSocketEndPoint(IPEndPointExtensions.GetNetSocketAddress(socketAddress)); break; } @@ -214,23 +188,45 @@ private unsafe Socket(SafeSocketHandle handle, bool loadPropertiesFromHandle) { try { - socketAddress ??= new Internals.SocketAddress(_addressFamily, buffer); - if (SocketPal.GetPeerName(_handle, socketAddress.Buffer, ref socketAddress.InternalSize) != SocketError.Success) + // Local and remote end points may be different sizes for protocols like Unix Domain Sockets. + bufferLength = buffer.Length; + switch (SocketPal.GetPeerName(handle, buffer, ref bufferLength)) { - return; - } + case SocketError.Success: + switch (_addressFamily) + { + case AddressFamily.InterNetwork: + _remoteEndPoint = new IPEndPoint( + new IPAddress((long)SocketAddressPal.GetIPv4Address(buffer.Slice(0, bufferLength)) & 0x0FFFFFFFF), + SocketAddressPal.GetPort(buffer)); + break; + + case AddressFamily.InterNetworkV6: + Span address = stackalloc byte[IPAddressParserStatics.IPv6AddressBytes]; + SocketAddressPal.GetIPv6Address(buffer.Slice(0, bufferLength), address, out uint scope); + _remoteEndPoint = new IPEndPoint( + new IPAddress(address, scope), + SocketAddressPal.GetPort(buffer)); + break; + + case AddressFamily.Unix: + socketAddress = new Internals.SocketAddress(_addressFamily, buffer.Slice(0, bufferLength)); + _remoteEndPoint = new UnixDomainSocketEndPoint(IPEndPointExtensions.GetNetSocketAddress(socketAddress)); + break; + } - if (socketAddress.InternalSize > socketAddress.Buffer.Length) - { - socketAddress.Buffer = new byte[socketAddress.InternalSize]; - if (SocketPal.GetPeerName(_handle, socketAddress.Buffer, ref socketAddress.InternalSize) != SocketError.Success) - { - return; - } + _isConnected = true; + break; + + case SocketError.InvalidArgument: + // On some OSes (e.g. macOS), EINVAL means the socket has been shut down. + // This can happen if, for example, socketpair was used and the parent + // process closed its copy of the child's socket. Since we don't know + // whether we're actually connected or not, err on the side of saying + // we're connected. + _isConnected = true; + break; } - - _remoteEndPoint = _rightEndPoint.Create(socketAddress); - _isConnected = true; } catch { } } @@ -367,12 +363,15 @@ public EndPoint? RemoteEndPoint _nonBlockingConnectInProgress = false; } - if (_rightEndPoint == null) + if (_rightEndPoint == null || !_isConnected) { return null; } - Internals.SocketAddress socketAddress = IPEndPointExtensions.Serialize(_rightEndPoint); + Internals.SocketAddress socketAddress = + _addressFamily == AddressFamily.InterNetwork || _addressFamily == AddressFamily.InterNetworkV6 ? + IPEndPointExtensions.Serialize(_rightEndPoint) : + new Internals.SocketAddress(_addressFamily, SocketPal.MaximumAddressSize); // may be different size than _rightEndPoint. // This may throw ObjectDisposedException. SocketError errorCode = SocketPal.GetPeerName( @@ -1136,7 +1135,10 @@ public Socket Accept() ValidateBlockingMode(); if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"SRC:{LocalEndPoint}"); - Internals.SocketAddress socketAddress = IPEndPointExtensions.Serialize(_rightEndPoint); + Internals.SocketAddress socketAddress = + _addressFamily == AddressFamily.InterNetwork || _addressFamily == AddressFamily.InterNetworkV6 ? + IPEndPointExtensions.Serialize(_rightEndPoint) : + new Internals.SocketAddress(_addressFamily, SocketPal.MaximumAddressSize); // may be different size. // This may throw ObjectDisposedException. SafeSocketHandle acceptedSocketHandle; @@ -1602,7 +1604,7 @@ public int Receive(IList> buffers, SocketFlags socketFlags, o if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"SRC:{LocalEndPoint} DST:{RemoteEndPoint}"); int bytesTransferred; - errorCode = SocketPal.Receive(_handle, buffers, ref socketFlags, out bytesTransferred); + errorCode = SocketPal.Receive(_handle, buffers, socketFlags, out bytesTransferred); #if TRACE_VERBOSE if (NetEventSource.IsEnabled) @@ -1915,7 +1917,7 @@ public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName opti } if (lingerOption.LingerTime < 0 || lingerOption.LingerTime > (int)ushort.MaxValue) { - throw new ArgumentException(SR.Format(SR.ArgumentOutOfRange_Bounds_Lower_Upper, 0, (int)ushort.MaxValue), "optionValue.LingerTime"); + throw new ArgumentException(SR.Format(SR.ArgumentOutOfRange_Bounds_Lower_Upper_Named, 0, (int)ushort.MaxValue, "optionValue.LingerTime"), nameof(optionValue)); } SetLingerOption(lingerOption); } @@ -3823,7 +3825,7 @@ public bool AcceptAsync(SocketAsyncEventArgs e) } if (e.HasMultipleBuffers) { - throw new ArgumentException(SR.net_multibuffernotsupported, "BufferList"); + throw new ArgumentException(SR.net_multibuffernotsupported, nameof(e)); } if (_rightEndPoint == null) { @@ -3986,11 +3988,11 @@ public static bool ConnectAsync(SocketType socketType, ProtocolType protocolType } if (e.HasMultipleBuffers) { - throw new ArgumentException(SR.net_multibuffernotsupported, "BufferList"); + throw new ArgumentException(SR.net_multibuffernotsupported, nameof(e)); } if (e.RemoteEndPoint == null) { - throw new ArgumentNullException("remoteEP"); + throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "e.RemoteEndPoint"), nameof(e)); } EndPoint endPointSnapshot = e.RemoteEndPoint; @@ -4123,11 +4125,11 @@ public bool ReceiveFromAsync(SocketAsyncEventArgs e) } if (e.RemoteEndPoint == null) { - throw new ArgumentNullException(nameof(e.RemoteEndPoint)); + throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "e.RemoteEndPoint"), nameof(e)); } if (!CanTryAddressFamily(e.RemoteEndPoint.AddressFamily)) { - throw new ArgumentException(SR.Format(SR.net_InvalidEndPointAddressFamily, e.RemoteEndPoint.AddressFamily, _addressFamily), "RemoteEndPoint"); + throw new ArgumentException(SR.Format(SR.net_InvalidEndPointAddressFamily, e.RemoteEndPoint.AddressFamily, _addressFamily), nameof(e)); } SocketPal.CheckDualModeReceiveSupport(this); @@ -4173,11 +4175,11 @@ public bool ReceiveMessageFromAsync(SocketAsyncEventArgs e) } if (e.RemoteEndPoint == null) { - throw new ArgumentNullException(nameof(e.RemoteEndPoint)); + throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "e.RemoteEndPoint"), nameof(e)); } if (!CanTryAddressFamily(e.RemoteEndPoint.AddressFamily)) { - throw new ArgumentException(SR.Format(SR.net_InvalidEndPointAddressFamily, e.RemoteEndPoint.AddressFamily, _addressFamily), "RemoteEndPoint"); + throw new ArgumentException(SR.Format(SR.net_InvalidEndPointAddressFamily, e.RemoteEndPoint.AddressFamily, _addressFamily), nameof(e)); } SocketPal.CheckDualModeReceiveSupport(this); @@ -4257,7 +4259,7 @@ public bool SendPacketsAsync(SocketAsyncEventArgs e) } if (e.SendPacketsElements == null) { - throw new ArgumentNullException("e.SendPacketsElements"); + throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "e.SendPacketsElements"), nameof(e)); } if (!Connected) { @@ -4295,7 +4297,7 @@ public bool SendToAsync(SocketAsyncEventArgs e) } if (e.RemoteEndPoint == null) { - throw new ArgumentNullException(nameof(RemoteEndPoint)); + throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "e.RemoteEndPoint"), nameof(e)); } // Prepare SocketAddress diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs index beb4cc088839d8..a35d181f328398 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs @@ -126,17 +126,12 @@ private enum State public readonly SocketAsyncContext AssociatedContext; public AsyncOperation Next = null!; // initialized by helper called from ctor - protected object? CallbackOrEvent; public SocketError ErrorCode; public byte[]? SocketAddress; public int SocketAddressLen; public CancellationTokenRegistration CancellationRegistration; - public ManualResetEventSlim? Event - { - get { return CallbackOrEvent as ManualResetEventSlim; } - set { CallbackOrEvent = value; } - } + public ManualResetEventSlim? Event { get; set; } public AsyncOperation(SocketAsyncContext context) { @@ -147,6 +142,7 @@ public AsyncOperation(SocketAsyncContext context) public void Reset() { _state = (int)State.Waiting; + Event = null; Next = this; #if DEBUG _callbackQueued = 0; @@ -240,10 +236,10 @@ public bool TryCancel() // It's our responsibility to set the error code and queue the completion. DoAbort(); - var @event = CallbackOrEvent as ManualResetEventSlim; - if (@event != null) + ManualResetEventSlim? e = Event; + if (e != null) { - @event.Set(); + e.Set(); } else { @@ -274,11 +270,21 @@ public void Dispatch() } else { - // Async operation. Process the IO on the threadpool. - ThreadPool.UnsafeQueueUserWorkItem(this, preferLocal: false); + // Async operation. + Schedule(); } } + public void Schedule() + { + Debug.Assert(Event == null); + + // Async operation. Process the IO on the threadpool. + ThreadPool.UnsafeQueueUserWorkItem(this, preferLocal: false); + } + + public void Process() => ((IThreadPoolWorkItem)this).Execute(); + void IThreadPoolWorkItem.Execute() { // ReadOperation and WriteOperation, the only two types derived from @@ -350,13 +356,10 @@ public SendOperation(SocketAsyncContext context) : base(context) { } protected sealed override void Abort() { } - public Action? Callback - { - set => CallbackOrEvent = value; - } + public Action? Callback { get; set; } public override void InvokeCallback(bool allowPooling) => - ((Action)CallbackOrEvent!)(BytesTransferred, SocketAddress, SocketAddressLen, SocketFlags.None, ErrorCode); + Callback!(BytesTransferred, SocketAddress, SocketAddressLen, SocketFlags.None, ErrorCode); } private sealed class BufferMemorySendOperation : SendOperation @@ -373,7 +376,7 @@ protected override bool DoTryComplete(SocketAsyncContext context) public override void InvokeCallback(bool allowPooling) { - var cb = (Action)CallbackOrEvent!; + var cb = Callback!; int bt = BytesTransferred; byte[]? sa = SocketAddress; int sal = SocketAddressLen; @@ -402,7 +405,7 @@ protected override bool DoTryComplete(SocketAsyncContext context) public override void InvokeCallback(bool allowPooling) { - var cb = (Action)CallbackOrEvent!; + var cb = Callback!; int bt = BytesTransferred; byte[]? sa = SocketAddress; int sal = SocketAddressLen; @@ -440,19 +443,16 @@ public ReceiveOperation(SocketAsyncContext context) : base(context) { } protected sealed override void Abort() { } - public Action? Callback - { - set => CallbackOrEvent = value; - } + public Action? Callback { get; set; } public override void InvokeCallback(bool allowPooling) => - ((Action)CallbackOrEvent!)( - BytesTransferred, SocketAddress, SocketAddressLen, ReceivedFlags, ErrorCode); + Callback!(BytesTransferred, SocketAddress, SocketAddressLen, ReceivedFlags, ErrorCode); } private sealed class BufferMemoryReceiveOperation : ReceiveOperation { public Memory Buffer; + public bool SetReceivedFlags; public BufferMemoryReceiveOperation(SocketAsyncContext context) : base(context) { } @@ -469,13 +469,23 @@ protected override bool DoTryComplete(SocketAsyncContext context) } else { - return SocketPal.TryCompleteReceiveFrom(context._socket, Buffer.Span, null, Flags, SocketAddress, ref SocketAddressLen, out BytesTransferred, out ReceivedFlags, out ErrorCode); + if (!SetReceivedFlags) + { + Debug.Assert(SocketAddress == null); + + ReceivedFlags = SocketFlags.None; + return SocketPal.TryCompleteReceive(context._socket, Buffer.Span, Flags, out BytesTransferred, out ErrorCode); + } + else + { + return SocketPal.TryCompleteReceiveFrom(context._socket, Buffer.Span, null, Flags, SocketAddress, ref SocketAddressLen, out BytesTransferred, out ReceivedFlags, out ErrorCode); + } } } public override void InvokeCallback(bool allowPooling) { - var cb = (Action)CallbackOrEvent!; + var cb = Callback!; int bt = BytesTransferred; byte[]? sa = SocketAddress; int sal = SocketAddressLen; @@ -502,7 +512,7 @@ protected override bool DoTryComplete(SocketAsyncContext context) => public override void InvokeCallback(bool allowPooling) { - var cb = (Action)CallbackOrEvent!; + var cb = Callback!; int bt = BytesTransferred; byte[]? sa = SocketAddress; int sal = SocketAddressLen; @@ -545,17 +555,13 @@ public ReceiveMessageFromOperation(SocketAsyncContext context) : base(context) { protected sealed override void Abort() { } - public Action Callback - { - set => CallbackOrEvent = value; - } + public Action? Callback { get; set; } protected override bool DoTryComplete(SocketAsyncContext context) => SocketPal.TryCompleteReceiveMessageFrom(context._socket, Buffer.Span, Buffers, Flags, SocketAddress!, ref SocketAddressLen, IsIPv4, IsIPv6, out BytesTransferred, out ReceivedFlags, out IPPacketInformation, out ErrorCode); public override void InvokeCallback(bool allowPooling) => - ((Action)CallbackOrEvent!)( - BytesTransferred, SocketAddress!, SocketAddressLen, ReceivedFlags, IPPacketInformation, ErrorCode); + Callback!(BytesTransferred, SocketAddress!, SocketAddressLen, ReceivedFlags, IPPacketInformation, ErrorCode); } private sealed class AcceptOperation : ReadOperation @@ -564,10 +570,7 @@ private sealed class AcceptOperation : ReadOperation public AcceptOperation(SocketAsyncContext context) : base(context) { } - public Action? Callback - { - set => CallbackOrEvent = value; - } + public Action? Callback { get; set; } protected override void Abort() => AcceptedFileDescriptor = (IntPtr)(-1); @@ -581,7 +584,7 @@ protected override bool DoTryComplete(SocketAsyncContext context) public override void InvokeCallback(bool allowPooling) { - var cb = (Action)CallbackOrEvent!; + var cb = Callback!; IntPtr fd = AcceptedFileDescriptor; byte[] sa = SocketAddress!; int sal = SocketAddressLen; @@ -600,10 +603,7 @@ private sealed class ConnectOperation : WriteOperation { public ConnectOperation(SocketAsyncContext context) : base(context) { } - public Action Callback - { - set => CallbackOrEvent = value; - } + public Action? Callback { get; set; } protected override void Abort() { } @@ -615,7 +615,7 @@ protected override bool DoTryComplete(SocketAsyncContext context) } public override void InvokeCallback(bool allowPooling) => - ((Action)CallbackOrEvent!)(ErrorCode); + Callback!(ErrorCode); } private sealed class SendFileOperation : WriteOperation @@ -629,13 +629,10 @@ public SendFileOperation(SocketAsyncContext context) : base(context) { } protected override void Abort() { } - public Action Callback - { - set => CallbackOrEvent = value; - } + public Action? Callback { get; set; } public override void InvokeCallback(bool allowPooling) => - ((Action)CallbackOrEvent!)(BytesTransferred, ErrorCode); + Callback!(BytesTransferred, ErrorCode); protected override bool DoTryComplete(SocketAsyncContext context) => SocketPal.TryCompleteSendFile(context._socket, FileHandle, ref Offset, ref Count, ref BytesTransferred, out ErrorCode); @@ -706,6 +703,7 @@ private enum QueueState : byte // These fields define the queue state. private QueueState _state; // See above + private bool _isNextOperationSynchronous; private int _sequenceNumber; // This sequence number is updated when we receive an epoll notification. // It allows us to detect when a new epoll notification has arrived // since the last time we checked the state of the queue. @@ -720,6 +718,8 @@ private enum QueueState : byte private LockToken Lock() => new LockToken(_queueLock); + public bool IsNextOperationSynchronous_Speculative => _isNextOperationSynchronous; + public void Init() { Debug.Assert(_queueLock == null); @@ -779,7 +779,12 @@ public bool StartAsyncOperation(SocketAsyncContext context, TOperation operation // Enqueue the operation. Debug.Assert(operation.Next == operation, "Expected operation.Next == operation"); - if (_tail != null) + if (_tail == null) + { + Debug.Assert(!_isNextOperationSynchronous); + _isNextOperationSynchronous = operation.Event != null; + } + else { operation.Next = _tail.Next; _tail.Next = operation; @@ -825,8 +830,7 @@ public bool StartAsyncOperation(SocketAsyncContext context, TOperation operation } } - // Called on the epoll thread whenever we receive an epoll notification. - public void HandleEvent(SocketAsyncContext context) + public AsyncOperation? ProcessSyncEventOrGetAsyncEvent(SocketAsyncContext context, bool skipAsyncEvents = false) { AsyncOperation op; using (Lock()) @@ -839,12 +843,20 @@ public void HandleEvent(SocketAsyncContext context) Debug.Assert(_tail == null, "State == Ready but queue is not empty!"); _sequenceNumber++; Trace(context, $"Exit (previously ready)"); - return; + return null; case QueueState.Waiting: Debug.Assert(_tail != null, "State == Waiting but queue is empty!"); - _state = QueueState.Processing; op = _tail.Next; + Debug.Assert(_isNextOperationSynchronous == (op.Event != null)); + if (skipAsyncEvents && !_isNextOperationSynchronous) + { + // Return the operation to indicate that the async operation was not processed, without making + // any state changes because async operations are being skipped + return op; + } + + _state = QueueState.Processing; // Break out and release lock break; @@ -852,21 +864,32 @@ public void HandleEvent(SocketAsyncContext context) Debug.Assert(_tail != null, "State == Processing but queue is empty!"); _sequenceNumber++; Trace(context, $"Exit (currently processing)"); - return; + return null; case QueueState.Stopped: Debug.Assert(_tail == null); Trace(context, $"Exit (stopped)"); - return; + return null; default: Environment.FailFast("unexpected queue state"); - return; + return null; } } - // Dispatch the op so we can try to process it. - op.Dispatch(); + ManualResetEventSlim? e = op.Event; + if (e != null) + { + // Sync operation. Signal waiting thread to continue processing. + e.Set(); + return null; + } + else + { + // Async operation. The caller will figure out how to process the IO. + Debug.Assert(!skipAsyncEvents); + return op; + } } internal void ProcessAsyncOperation(TOperation op) @@ -991,6 +1014,7 @@ public OperationResult ProcessQueuedOperation(TOperation op) { // No more operations to process _tail = null; + _isNextOperationSynchronous = false; _state = QueueState.Ready; _sequenceNumber++; Trace(context, $"Exit (finished queue)"); @@ -999,6 +1023,7 @@ public OperationResult ProcessQueuedOperation(TOperation op) { // Pop current operation and advance to next nextOp = _tail.Next = op.Next; + _isNextOperationSynchronous = nextOp.Event != null; } } } @@ -1033,11 +1058,13 @@ public void CancelAndContinueProcessing(TOperation op) { // No more operations _tail = null; + _isNextOperationSynchronous = false; } else { // Pop current operation and advance to next _tail.Next = op.Next; + _isNextOperationSynchronous = op.Next.Event != null; } // We're the first op in the queue. @@ -1112,6 +1139,7 @@ public bool StopAndAbort(SocketAsyncContext context) } _tail = null; + _isNextOperationSynchronous = false; Trace(context, $"Exit"); } @@ -1424,13 +1452,13 @@ public SocketError ConnectAsync(byte[] socketAddress, int socketAddressLen, Acti return SocketError.IOPending; } - public SocketError Receive(Memory buffer, ref SocketFlags flags, int timeout, out int bytesReceived) + public SocketError Receive(Memory buffer, SocketFlags flags, int timeout, out int bytesReceived) { int socketAddressLen = 0; return ReceiveFrom(buffer, ref flags, null, ref socketAddressLen, timeout, out bytesReceived); } - public SocketError Receive(Span buffer, ref SocketFlags flags, int timeout, out int bytesReceived) + public SocketError Receive(Span buffer, SocketFlags flags, int timeout, out int bytesReceived) { int socketAddressLen = 0; return ReceiveFrom(buffer, ref flags, null, ref socketAddressLen, timeout, out bytesReceived); @@ -1504,6 +1532,39 @@ public unsafe SocketError ReceiveFrom(Span buffer, ref SocketFlags flags, } } + public SocketError ReceiveAsync(Memory buffer, SocketFlags flags, out int bytesReceived, Action callback, CancellationToken cancellationToken = default) + { + SetNonBlocking(); + + SocketError errorCode; + int observedSequenceNumber; + if (_receiveQueue.IsReady(this, out observedSequenceNumber) && + SocketPal.TryCompleteReceive(_socket, buffer.Span, flags, out bytesReceived, out errorCode)) + { + return errorCode; + } + + BufferMemoryReceiveOperation operation = RentBufferMemoryReceiveOperation(); + operation.SetReceivedFlags = false; + operation.Callback = callback; + operation.Buffer = buffer; + operation.Flags = flags; + operation.SocketAddress = null; + operation.SocketAddressLen = 0; + + if (!_receiveQueue.StartAsyncOperation(this, operation, observedSequenceNumber, cancellationToken)) + { + bytesReceived = operation.BytesTransferred; + errorCode = operation.ErrorCode; + + ReturnOperation(operation); + return errorCode; + } + + bytesReceived = 0; + return SocketError.IOPending; + } + public SocketError ReceiveFromAsync(Memory buffer, SocketFlags flags, byte[]? socketAddress, ref int socketAddressLen, out int bytesReceived, out SocketFlags receivedFlags, Action callback, CancellationToken cancellationToken = default) { SetNonBlocking(); @@ -1517,6 +1578,7 @@ public SocketError ReceiveFromAsync(Memory buffer, SocketFlags flags, byt } BufferMemoryReceiveOperation operation = RentBufferMemoryReceiveOperation(); + operation.SetReceivedFlags = true; operation.Callback = callback; operation.Buffer = buffer; operation.Flags = flags; @@ -1538,7 +1600,7 @@ public SocketError ReceiveFromAsync(Memory buffer, SocketFlags flags, byt return SocketError.IOPending; } - public SocketError Receive(IList> buffers, ref SocketFlags flags, int timeout, out int bytesReceived) + public SocketError Receive(IList> buffers, SocketFlags flags, int timeout, out int bytesReceived) { return ReceiveFrom(buffers, ref flags, null, 0, timeout, out bytesReceived); } @@ -1946,6 +2008,42 @@ public SocketError SendFileAsync(SafeFileHandle fileHandle, long offset, long co return SocketError.IOPending; } + // Called on the epoll thread, speculatively tries to process synchronous events and errors for synchronous events, and + // returns any remaining events that remain to be processed. Taking a lock for each operation queue to deterministically + // handle synchronous events on the epoll thread seems to significantly reduce throughput in benchmarks. On the other + // hand, the speculative checks make it nondeterministic, where it would be possible for the epoll thread to think that + // the next operation in a queue is not synchronous when it is (due to a race, old caches, etc.) and cause the event to + // be scheduled instead. It's not functionally incorrect to schedule the release of a synchronous operation, just it may + // lead to thread pool starvation issues if the synchronous operations are blocking thread pool threads (typically not + // advised) and more threads are not immediately available to run work items that would release those operations. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Interop.Sys.SocketEvents HandleSyncEventsSpeculatively(Interop.Sys.SocketEvents events) + { + if ((events & Interop.Sys.SocketEvents.Error) != 0) + { + // Set the Read and Write flags; the processing for these events + // will pick up the error. + events ^= Interop.Sys.SocketEvents.Error; + events |= Interop.Sys.SocketEvents.Read | Interop.Sys.SocketEvents.Write; + } + + if ((events & Interop.Sys.SocketEvents.Read) != 0 && + _receiveQueue.IsNextOperationSynchronous_Speculative && + _receiveQueue.ProcessSyncEventOrGetAsyncEvent(this, skipAsyncEvents: true) == null) + { + events ^= Interop.Sys.SocketEvents.Read; + } + + if ((events & Interop.Sys.SocketEvents.Write) != 0 && + _sendQueue.IsNextOperationSynchronous_Speculative && + _sendQueue.ProcessSyncEventOrGetAsyncEvent(this, skipAsyncEvents: true) == null) + { + events ^= Interop.Sys.SocketEvents.Write; + } + + return events; + } + public unsafe void HandleEvents(Interop.Sys.SocketEvents events) { if ((events & Interop.Sys.SocketEvents.Error) != 0) @@ -1955,14 +2053,23 @@ public unsafe void HandleEvents(Interop.Sys.SocketEvents events) events |= Interop.Sys.SocketEvents.Read | Interop.Sys.SocketEvents.Write; } - if ((events & Interop.Sys.SocketEvents.Read) != 0) + AsyncOperation? receiveOperation = + (events & Interop.Sys.SocketEvents.Read) != 0 ? _receiveQueue.ProcessSyncEventOrGetAsyncEvent(this) : null; + AsyncOperation? sendOperation = + (events & Interop.Sys.SocketEvents.Write) != 0 ? _sendQueue.ProcessSyncEventOrGetAsyncEvent(this) : null; + + // This method is called from a thread pool thread. When we have only one operation to process, process it + // synchronously to avoid an extra thread pool work item. When we have two operations to process, processing both + // synchronously may delay the second operation, so schedule one onto the thread pool and process the other + // synchronously. There might be better ways of doing this. + if (sendOperation == null) { - _receiveQueue.HandleEvent(this); + receiveOperation?.Process(); } - - if ((events & Interop.Sys.SocketEvents.Write) != 0) + else { - _sendQueue.HandleEvent(this); + receiveOperation?.Schedule(); + sendOperation.Process(); } } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs index 9d5f48b7045e37..053cc4fcb6f77c 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs @@ -2,16 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Concurrent; using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; -using System.Threading.Tasks; namespace System.Net.Sockets { - internal sealed unsafe class SocketAsyncEngine + internal sealed unsafe class SocketAsyncEngine : IThreadPoolWorkItem { // // Encapsulates a particular SocketAsyncContext object's access to a SocketAsyncEngine. @@ -55,22 +54,40 @@ public bool TryRegister(SafeSocketHandle socket, out Interop.Error error) private static readonly object s_lock = new object(); - // In debug builds, force there to be 2 engines. In release builds, use half the number of processors when - // there are at least 6. The lower bound is to avoid using multiple engines on systems which aren't servers. -#pragma warning disable CA1802 // const works for debug, but needs to be static readonly for release - private static readonly int s_engineCount = -#if DEBUG - 2; -#else - Environment.ProcessorCount >= 6 ? Environment.ProcessorCount / 2 : 1; -#endif -#pragma warning restore CA1802 + private static readonly int s_maxEngineCount = GetEngineCount(); + + private static int GetEngineCount() + { + // The responsibility of SocketAsyncEngine is to get notifications from epoll|kqueue + // and schedule corresponding work items to ThreadPool (socket reads and writes). + // + // Using TechEmpower benchmarks that generate a LOT of SMALL socket reads and writes under a VERY HIGH load + // we have observed that a single engine is capable of keeping busy up to thirty x64 and eight ARM64 CPU Cores. + // + // The vast majority of real-life scenarios is never going to generate such a huge load (hundreds of thousands of requests per second) + // and having a single producer should be almost always enough. + // + // We want to be sure that we can handle extreme loads and that's why we have decided to use these values. + // + // It's impossible to predict all possible scenarios so we have added a possibility to configure this value using environment variables. + if (uint.TryParse(Environment.GetEnvironmentVariable("DOTNET_SYSTEM_NET_SOCKETS_THREAD_COUNT"), out uint count)) + { + return (int)count; + } + + Architecture architecture = RuntimeInformation.ProcessArchitecture; + int coresPerEngine = architecture == Architecture.Arm64 || architecture == Architecture.Arm + ? 8 + : 30; + + return Math.Max(1, (int)Math.Round(Environment.ProcessorCount / (double)coresPerEngine)); + } // // The current engines. We replace an engine when it runs out of "handle" values. // Must be accessed under s_lock. // - private static readonly SocketAsyncEngine?[] s_currentEngines = new SocketAsyncEngine?[s_engineCount]; + private static readonly SocketAsyncEngine?[] s_currentEngines = new SocketAsyncEngine?[s_maxEngineCount]; private static int s_allocateFromEngine = 0; private readonly IntPtr _port; @@ -105,8 +122,6 @@ public bool TryRegister(SafeSocketHandle socket, out Interop.Error error) // private static readonly IntPtr MaxHandles = IntPtr.Size == 4 ? (IntPtr)int.MaxValue : (IntPtr)long.MaxValue; #endif - private static readonly IntPtr MinHandlesForAdditionalEngine = s_engineCount == 1 ? MaxHandles : (IntPtr)32; - // // Sentinel handle value to identify events from the "shutdown pipe," used to signal an event loop to stop // processing events. @@ -120,15 +135,21 @@ public bool TryRegister(SafeSocketHandle socket, out Interop.Error error) private IntPtr _nextHandle; // - // Count of handles that have been allocated for this event port, but not yet freed. - // Must be accessed under s_lock. + // Maps handle values to SocketAsyncContext instances. // - private IntPtr _outstandingHandles; + private readonly ConcurrentDictionary _handleToContextMap = new ConcurrentDictionary(); // - // Maps handle values to SocketAsyncContext instances. + // Queue of events generated by EventLoop() that would be processed by the thread pool // - private readonly ConcurrentDictionary _handleToContextMap = new ConcurrentDictionary(); + private readonly ConcurrentQueue _eventQueue = new ConcurrentQueue(); + + // + // This field is set to 1 to indicate that a thread pool work item is scheduled to process events in _eventQueue. It is + // set to 0 when the scheduled work item starts running, to indicate that a thread pool work item to process events is + // not scheduled. Changes are protected by atomic operations as appropriate. + // + private int _eventQueueProcessingRequested; // // True if we've reached the handle value limit for this event port, and thus must allocate a new event port @@ -136,16 +157,6 @@ public bool TryRegister(SafeSocketHandle socket, out Interop.Error error) // private bool IsFull { get { return _nextHandle == MaxHandles; } } - // True if we've don't have sufficient active sockets to allow allocating a new engine. - private bool HasLowNumberOfSockets - { - get - { - return IntPtr.Size == 4 ? _outstandingHandles.ToInt32() < MinHandlesForAdditionalEngine.ToInt32() : - _outstandingHandles.ToInt64() < MinHandlesForAdditionalEngine.ToInt64(); - } - } - // // Allocates a new {SocketAsyncEngine, handle} pair. // @@ -156,21 +167,7 @@ private static void AllocateToken(SocketAsyncContext context, out SocketAsyncEng engine = s_currentEngines[s_allocateFromEngine]; if (engine == null) { - // We minimize the number of engines on applications that have a low number of concurrent sockets. - for (int i = 0; i < s_allocateFromEngine; i++) - { - var previousEngine = s_currentEngines[i]; - if (previousEngine == null || previousEngine.HasLowNumberOfSockets) - { - s_allocateFromEngine = i; - engine = previousEngine; - break; - } - } - if (engine == null) - { - s_currentEngines[s_allocateFromEngine] = engine = new SocketAsyncEngine(); - } + s_currentEngines[s_allocateFromEngine] = engine = new SocketAsyncEngine(); } handle = engine.AllocateHandle(context); @@ -182,10 +179,7 @@ private static void AllocateToken(SocketAsyncContext context, out SocketAsyncEng } // Round-robin to the next engine once we have sufficient sockets on this one. - if (!engine.HasLowNumberOfSockets) - { - s_allocateFromEngine = (s_allocateFromEngine + 1) % s_engineCount; - } + s_allocateFromEngine = (s_allocateFromEngine + 1) % s_maxEngineCount; } } @@ -195,12 +189,11 @@ private IntPtr AllocateHandle(SocketAsyncContext context) Debug.Assert(!IsFull, "Expected !IsFull"); IntPtr handle = _nextHandle; - _handleToContextMap.TryAdd(handle, context); - + Debug.Assert(handle != ShutdownHandle, "ShutdownHandle must not be added to the dictionary"); + bool added = _handleToContextMap.TryAdd(handle, new SocketAsyncContextWrapper(context)); + Debug.Assert(added, "Add should always succeed"); _nextHandle = IntPtr.Add(_nextHandle, 1); - _outstandingHandles = IntPtr.Add(_outstandingHandles, 1); - Debug.Assert(handle != ShutdownHandle, $"Expected handle != ShutdownHandle: {handle}"); return handle; } @@ -214,14 +207,11 @@ private void FreeHandle(IntPtr handle) { if (_handleToContextMap.TryRemove(handle, out _)) { - _outstandingHandles = IntPtr.Subtract(_outstandingHandles, 1); - Debug.Assert(_outstandingHandles.ToInt64() >= 0, $"Unexpected _outstandingHandles: {_outstandingHandles}"); - // // If we've allocated all possible handles for this instance, and freed them all, then // we don't need the event loop any more, and can reclaim resources. // - if (IsFull && _outstandingHandles == IntPtr.Zero) + if (IsFull && _handleToContextMap.IsEmpty) { shutdownNeeded = true; } @@ -277,19 +267,15 @@ private SocketAsyncEngine() throw new InternalException(err); } - // - // Start the event loop on its own thread. - // bool suppressFlow = !ExecutionContext.IsFlowSuppressed(); try { if (suppressFlow) ExecutionContext.SuppressFlow(); - Task.Factory.StartNew( - s => ((SocketAsyncEngine)s!).EventLoop(), - this, - CancellationToken.None, - TaskCreationOptions.LongRunning, - TaskScheduler.Default); + + Thread thread = new Thread(s => ((SocketAsyncEngine)s!).EventLoop()); + thread.IsBackground = true; + thread.Name = ".NET Sockets"; + thread.Start(this); } finally { @@ -308,10 +294,15 @@ private void EventLoop() try { bool shutdown = false; + Interop.Sys.SocketEvent* buffer = _buffer; + ConcurrentDictionary handleToContextMap = _handleToContextMap; + ConcurrentQueue eventQueue = _eventQueue; + IntPtr shutdownHandle = ShutdownHandle; + SocketAsyncContext? context = null; while (!shutdown) { int numEvents = EventBufferCount; - Interop.Error err = Interop.Sys.WaitForSocketEvents(_port, _buffer, &numEvents); + Interop.Error err = Interop.Sys.WaitForSocketEvents(_port, buffer, &numEvents); if (err != Interop.Error.SUCCESS) { throw new InternalException(err); @@ -320,24 +311,44 @@ private void EventLoop() // The native shim is responsible for ensuring this condition. Debug.Assert(numEvents > 0, $"Unexpected numEvents: {numEvents}"); - for (int i = 0; i < numEvents; i++) + bool enqueuedEvent = false; + foreach (var socketEvent in new ReadOnlySpan(buffer, numEvents)) { - IntPtr handle = _buffer[i].Data; - if (handle == ShutdownHandle) - { - shutdown = true; - } - else + IntPtr handle = socketEvent.Data; + + if (handleToContextMap.TryGetValue(handle, out SocketAsyncContextWrapper contextWrapper) && (context = contextWrapper.Context) != null) { Debug.Assert(handle.ToInt64() < MaxHandles.ToInt64(), $"Unexpected values: handle={handle}, MaxHandles={MaxHandles}"); - _handleToContextMap.TryGetValue(handle, out SocketAsyncContext? context); - if (context != null) + + Interop.Sys.SocketEvents events = context.HandleSyncEventsSpeculatively(socketEvent.Events); + if (events != Interop.Sys.SocketEvents.None) { - context.HandleEvents(_buffer[i].Events); - context = null; + var ev = new SocketIOEvent(context, events); + eventQueue.Enqueue(ev); + enqueuedEvent = true; + + // This is necessary when the JIT generates unoptimized code (debug builds, live debugging, + // quick JIT, etc.) to ensure that the context does not remain referenced by this method, as + // such code may keep the stack location live for longer than necessary + ev = default; } + + // This is necessary when the JIT generates unoptimized code (debug builds, live debugging, + // quick JIT, etc.) to ensure that the context does not remain referenced by this method, as + // such code may keep the stack location live for longer than necessary + context = null; + contextWrapper = default; + } + else if (handle == shutdownHandle) + { + shutdown = true; } } + + if (enqueuedEvent) + { + ScheduleToProcessEvents(); + } } FreeNativeResources(); @@ -348,13 +359,79 @@ private void EventLoop() } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ScheduleToProcessEvents() + { + // Schedule a thread pool work item to process events. Only one work item is scheduled at any given time to avoid + // over-parallelization. When the work item begins running, this field is reset to 0, allowing for another work item + // to be scheduled for parallelizing processing of events. + if (Interlocked.CompareExchange(ref _eventQueueProcessingRequested, 1, 0) == 0) + { + ThreadPool.UnsafeQueueUserWorkItem(this, preferLocal: false); + } + } + + void IThreadPoolWorkItem.Execute() + { + // Indicate that a work item is no longer scheduled to process events. The change needs to be visible to enqueuer + // threads (only for EventLoop() currently) before an event is attempted to be dequeued. In particular, if an + // enqueuer queues an event and does not schedule a work item because it is already scheduled, and this thread is + // the last thread processing events, it must see the event queued by the enqueuer. + Interlocked.Exchange(ref _eventQueueProcessingRequested, 0); + + ConcurrentQueue eventQueue = _eventQueue; + if (!eventQueue.TryDequeue(out SocketIOEvent ev)) + { + return; + } + + int startTimeMs = Environment.TickCount; + + // An event was successfully dequeued, and there may be more events to process. Schedule a work item to parallelize + // processing of events, before processing more events. Following this, it is the responsibility of the new work + // item and the epoll thread to schedule more work items as necessary. The parallelization may be necessary here if + // the user callback as part of handling the event blocks for some reason that may have a dependency on other queued + // socket events. + ScheduleToProcessEvents(); + + while (true) + { + ev.Context.HandleEvents(ev.Events); + + // If there is a constant stream of new events, and/or if user callbacks take long to process an event, this + // work item may run for a long time. If work items of this type are using up all of the thread pool threads, + // collectively they may starve other types of work items from running. Before dequeuing and processing another + // event, check the elapsed time since the start of the work item and yield the thread after some time has + // elapsed to allow the thread pool to run other work items. + // + // The threshold chosen below was based on trying various thresholds and in trying to keep the latency of + // running another work item low when these work items are using up all of the thread pool worker threads. In + // such cases, the latency would be something like threshold / proc count. Smaller thresholds were tried and + // using Stopwatch instead (like 1 ms, 5 ms, etc.), from quick tests they appeared to have a slightly greater + // impact on throughput compared to the threshold chosen below, though it is slight enough that it may not + // matter much. Higher thresholds didn't seem to have any noticeable effect. + if (Environment.TickCount - startTimeMs >= 15) + { + break; + } + + if (!eventQueue.TryDequeue(out ev)) + { + return; + } + } + + // The queue was not observed to be empty, schedule another work item before yielding the thread + ScheduleToProcessEvents(); + } + private void RequestEventLoopShutdown() { // // Write to the pipe, which will wake up the event loop and cause it to exit. // byte b = 1; - int bytesWritten = Interop.Sys.Write(_shutdownWritePipe, &b, 1); + int bytesWritten = Interop.Sys.Write((IntPtr)_shutdownWritePipe, &b, 1); if (bytesWritten != 1) { throw new InternalException(bytesWritten); @@ -387,5 +464,29 @@ private bool TryRegister(SafeSocketHandle socket, IntPtr handle, out Interop.Err Interop.Sys.SocketEvents.Read | Interop.Sys.SocketEvents.Write, handle); return error == Interop.Error.SUCCESS; } + + // struct wrapper is used in order to improve the performance of the epoll thread hot path by up to 3% of some TechEmpower benchmarks + // the goal is to have a dedicated generic instantiation and using: + // System.Collections.Concurrent.ConcurrentDictionary`2[System.IntPtr,System.Net.Sockets.SocketAsyncContextWrapper]::TryGetValueInternal(!0,int32,!1&) + // instead of: + // System.Collections.Concurrent.ConcurrentDictionary`2[System.IntPtr,System.__Canon]::TryGetValueInternal(!0,int32,!1&) + private readonly struct SocketAsyncContextWrapper + { + public SocketAsyncContextWrapper(SocketAsyncContext context) => Context = context; + + internal SocketAsyncContext Context { get; } + } + + private readonly struct SocketIOEvent + { + public SocketAsyncContext Context { get; } + public Interop.Sys.SocketEvents Events { get; } + + public SocketIOEvent(SocketAsyncContext context, Interop.Sys.SocketEvents events) + { + Context = context; + Events = events; + } + } } } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Unix.cs index d2ca491a52ae9a..99147f05a429c2 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Unix.cs @@ -128,7 +128,17 @@ internal unsafe SocketError DoOperationReceive(SafeSocketHandle handle, Cancella SocketError errorCode; if (_bufferList == null) { - errorCode = handle.AsyncContext.ReceiveAsync(_buffer.Slice(_offset, _count), _socketFlags, out bytesReceived, out flags, TransferCompletionCallback, cancellationToken); + // TCP has no out-going receive flags. We can use different syscalls which give better performance. + bool noReceivedFlags = _currentSocket!.ProtocolType == ProtocolType.Tcp; + if (noReceivedFlags) + { + errorCode = handle.AsyncContext.ReceiveAsync(_buffer.Slice(_offset, _count), _socketFlags, out bytesReceived, TransferCompletionCallback, cancellationToken); + flags = SocketFlags.None; + } + else + { + errorCode = handle.AsyncContext.ReceiveAsync(_buffer.Slice(_offset, _count), _socketFlags, out bytesReceived, out flags, TransferCompletionCallback, cancellationToken); + } } else { diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs index ef5be1880d2d1b..8515b343613fea 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs @@ -21,16 +21,13 @@ private enum SingleBufferHandleState : byte { None, InProcess, Set } // BufferList property variables. // Note that these arrays are allocated and then grown as necessary, but never shrunk. // Thus the actual in-use length is defined by _bufferListInternal.Count, not the length of these arrays. - private WSABuffer[]? _wsaBufferArray; + private WSABuffer[]? _wsaBufferArrayPinned; private GCHandle[]? _multipleBufferGCHandles; // Internal buffers for WSARecvMsg - private byte[]? _wsaMessageBuffer; - private GCHandle _wsaMessageBufferGCHandle; - private byte[]? _controlBuffer; - private GCHandle _controlBufferGCHandle; - private WSABuffer[]? _wsaRecvMsgWSABufferArray; - private GCHandle _wsaRecvMsgWSABufferArrayGCHandle; + private byte[]? _wsaMessageBufferPinned; + private byte[]? _controlBufferPinned; + private WSABuffer[]? _wsaRecvMsgWSABufferArrayPinned; // Internal SocketAddress buffer private GCHandle _socketAddressGCHandle; @@ -377,7 +374,7 @@ internal unsafe SocketError DoOperationReceiveMultiBuffer(SafeSocketHandle handl SocketFlags flags = _socketFlags; SocketError socketError = Interop.Winsock.WSARecv( handle, - _wsaBufferArray, + _wsaBufferArrayPinned, _bufferListInternal!.Count, out int bytesTransferred, ref flags, @@ -449,7 +446,7 @@ internal unsafe SocketError DoOperationReceiveFromMultiBuffer(SafeSocketHandle h SocketFlags flags = _socketFlags; SocketError socketError = Interop.Winsock.WSARecvFrom( handle, - _wsaBufferArray!, + _wsaBufferArrayPinned!, _bufferListInternal!.Count, out int bytesTransferred, ref flags, @@ -470,7 +467,7 @@ internal unsafe SocketError DoOperationReceiveFromMultiBuffer(SafeSocketHandle h internal unsafe SocketError DoOperationReceiveMessageFrom(Socket socket, SafeSocketHandle handle) { // WSARecvMsg uses a WSAMsg descriptor. - // The WSAMsg buffer is pinned with a GCHandle to avoid complicating the use of Overlapped. + // The WSAMsg buffer is a pinned array to avoid complicating the use of Overlapped. // WSAMsg contains a pointer to a sockaddr. // The sockaddr is pinned with a GCHandle to avoid complicating the use of Overlapped. // WSAMsg contains a pointer to a WSABuffer array describing data buffers. @@ -478,17 +475,9 @@ internal unsafe SocketError DoOperationReceiveMessageFrom(Socket socket, SafeSoc PinSocketAddressBuffer(); // Create a WSAMessageBuffer if none exists yet. - if (_wsaMessageBuffer == null) + if (_wsaMessageBufferPinned == null) { - Debug.Assert(!_wsaMessageBufferGCHandle.IsAllocated); - _wsaMessageBuffer = new byte[sizeof(Interop.Winsock.WSAMsg)]; - } - - // And ensure the WSAMessageBuffer is appropriately pinned. - Debug.Assert(!_wsaMessageBufferGCHandle.IsAllocated || _wsaMessageBufferGCHandle.Target == _wsaMessageBuffer); - if (!_wsaMessageBufferGCHandle.IsAllocated) - { - _wsaMessageBufferGCHandle = GCHandle.Alloc(_wsaMessageBuffer, GCHandleType.Pinned); + _wsaMessageBufferPinned = GC.AllocateUninitializedArray(sizeof(Interop.Winsock.WSAMsg), pinned: true); } // Create and pin an appropriately sized control buffer if none already @@ -496,21 +485,13 @@ internal unsafe SocketError DoOperationReceiveMessageFrom(Socket socket, SafeSoc bool ipv4 = (_currentSocket!.AddressFamily == AddressFamily.InterNetwork || (ipAddress != null && ipAddress.IsIPv4MappedToIPv6)); // DualMode bool ipv6 = _currentSocket.AddressFamily == AddressFamily.InterNetworkV6; - if (ipv4 && (_controlBuffer == null || _controlBuffer.Length != sizeof(Interop.Winsock.ControlData))) + if (ipv4 && (_controlBufferPinned == null || _controlBufferPinned.Length != sizeof(Interop.Winsock.ControlData))) { - if (_controlBufferGCHandle.IsAllocated) - { - _controlBufferGCHandle.Free(); - } - _controlBuffer = new byte[sizeof(Interop.Winsock.ControlData)]; + _controlBufferPinned = GC.AllocateUninitializedArray(sizeof(Interop.Winsock.ControlData), pinned: true); } - else if (ipv6 && (_controlBuffer == null || _controlBuffer.Length != sizeof(Interop.Winsock.ControlDataIPv6))) + else if (ipv6 && (_controlBufferPinned == null || _controlBufferPinned.Length != sizeof(Interop.Winsock.ControlDataIPv6))) { - if (_controlBufferGCHandle.IsAllocated) - { - _controlBufferGCHandle.Free(); - } - _controlBuffer = new byte[sizeof(Interop.Winsock.ControlDataIPv6)]; + _controlBufferPinned = GC.AllocateUninitializedArray(sizeof(Interop.Winsock.ControlDataIPv6), pinned: true); } // If single buffer we need a single element WSABuffer. @@ -518,38 +499,31 @@ internal unsafe SocketError DoOperationReceiveMessageFrom(Socket socket, SafeSoc uint wsaRecvMsgWSABufferCount; if (_bufferList == null) { - if (_wsaRecvMsgWSABufferArray == null) + if (_wsaRecvMsgWSABufferArrayPinned == null) { - _wsaRecvMsgWSABufferArray = new WSABuffer[1]; + _wsaRecvMsgWSABufferArrayPinned = GC.AllocateUninitializedArray(1, pinned: true); } Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None); _singleBufferHandle = _buffer.Pin(); _singleBufferHandleState = SingleBufferHandleState.Set; - _wsaRecvMsgWSABufferArray[0].Pointer = (IntPtr)_singleBufferHandle.Pointer; - _wsaRecvMsgWSABufferArray[0].Length = _count; - wsaRecvMsgWSABufferArray = _wsaRecvMsgWSABufferArray; + _wsaRecvMsgWSABufferArrayPinned[0].Pointer = (IntPtr)_singleBufferHandle.Pointer; + _wsaRecvMsgWSABufferArrayPinned[0].Length = _count; + wsaRecvMsgWSABufferArray = _wsaRecvMsgWSABufferArrayPinned; wsaRecvMsgWSABufferCount = 1; } else { // Use the multi-buffer WSABuffer. - wsaRecvMsgWSABufferArray = _wsaBufferArray!; + wsaRecvMsgWSABufferArray = _wsaBufferArrayPinned!; wsaRecvMsgWSABufferCount = (uint)_bufferListInternal!.Count; } - // Ensure the array is pinned. - Debug.Assert(!_wsaRecvMsgWSABufferArrayGCHandle.IsAllocated || _wsaRecvMsgWSABufferArrayGCHandle.Target == wsaRecvMsgWSABufferArray); - if (!_wsaRecvMsgWSABufferArrayGCHandle.IsAllocated) - { - _wsaRecvMsgWSABufferArrayGCHandle = GCHandle.Alloc(wsaRecvMsgWSABufferArray, GCHandleType.Pinned); - } - // Fill in WSAMessageBuffer. unsafe { - Interop.Winsock.WSAMsg* pMessage = (Interop.Winsock.WSAMsg*)Marshal.UnsafeAddrOfPinnedArrayElement(_wsaMessageBuffer, 0); + Interop.Winsock.WSAMsg* pMessage = (Interop.Winsock.WSAMsg*)Marshal.UnsafeAddrOfPinnedArrayElement(_wsaMessageBufferPinned, 0); pMessage->socketAddress = PtrSocketAddressBuffer; pMessage->addressLength = (uint)_socketAddress.Size; fixed (void* ptrWSARecvMsgWSABufferArray = &wsaRecvMsgWSABufferArray[0]) @@ -558,20 +532,14 @@ internal unsafe SocketError DoOperationReceiveMessageFrom(Socket socket, SafeSoc } pMessage->count = wsaRecvMsgWSABufferCount; - if (_controlBuffer != null) + if (_controlBufferPinned != null) { - Debug.Assert(_controlBuffer.Length > 0); - Debug.Assert(!_controlBufferGCHandle.IsAllocated || _controlBufferGCHandle.Target == _controlBuffer); - if (!_controlBufferGCHandle.IsAllocated) - { - _controlBufferGCHandle = GCHandle.Alloc(_controlBuffer, GCHandleType.Pinned); - } - - fixed (void* ptrControlBuffer = &_controlBuffer[0]) + Debug.Assert(_controlBufferPinned.Length > 0); + fixed (void* ptrControlBuffer = &_controlBufferPinned[0]) { pMessage->controlBuffer.Pointer = (IntPtr)ptrControlBuffer; } - pMessage->controlBuffer.Length = _controlBuffer.Length; + pMessage->controlBuffer.Length = _controlBufferPinned.Length; } pMessage->flags = _socketFlags; } @@ -581,7 +549,7 @@ internal unsafe SocketError DoOperationReceiveMessageFrom(Socket socket, SafeSoc { SocketError socketError = socket.WSARecvMsg( handle, - Marshal.UnsafeAddrOfPinnedArrayElement(_wsaMessageBuffer, 0), + Marshal.UnsafeAddrOfPinnedArrayElement(_wsaMessageBufferPinned, 0), out int bytesTransferred, overlapped, IntPtr.Zero); @@ -639,7 +607,7 @@ internal unsafe SocketError DoOperationSendMultiBuffer(SafeSocketHandle handle) { SocketError socketError = Interop.Winsock.WSASend( handle, - _wsaBufferArray, + _wsaBufferArrayPinned, _bufferListInternal!.Count, out int bytesTransferred, _socketFlags, @@ -725,22 +693,19 @@ internal unsafe SocketError DoOperationSendPackets(Socket socket, SafeSocketHand } } - Interop.Winsock.TransmitPacketsElement[] sendPacketsDescriptor = + Interop.Winsock.TransmitPacketsElement[] sendPacketsDescriptorPinned = SetupPinHandlesSendPackets(sendPacketsElementsCopy, sendPacketsElementsFileCount, sendPacketsElementsFileStreamCount, sendPacketsElementsBufferCount); - Debug.Assert(sendPacketsDescriptor != null); - Debug.Assert(sendPacketsDescriptor.Length > 0); - Debug.Assert(_multipleBufferGCHandles != null); - Debug.Assert(_multipleBufferGCHandles[0].IsAllocated); - Debug.Assert(_multipleBufferGCHandles[0].Target == sendPacketsDescriptor); + Debug.Assert(sendPacketsDescriptorPinned != null); + Debug.Assert(sendPacketsDescriptorPinned.Length > 0); NativeOverlapped* overlapped = AllocateNativeOverlapped(); try { bool result = socket.TransmitPackets( handle, - _multipleBufferGCHandles[0].AddrOfPinnedObject(), - sendPacketsDescriptor.Length, + Marshal.UnsafeAddrOfPinnedArrayElement(sendPacketsDescriptorPinned, 0), + sendPacketsDescriptorPinned.Length, _sendPacketsSendSize, overlapped, _sendPacketsFlags); @@ -809,7 +774,7 @@ internal unsafe SocketError DoOperationSendToMultiBuffer(SafeSocketHandle handle { SocketError socketError = Interop.Winsock.WSASendTo( handle, - _wsaBufferArray!, + _wsaBufferArrayPinned!, _bufferListInternal!.Count, out int bytesTransferred, _socketFlags, @@ -870,16 +835,16 @@ private void SetupMultipleBuffers() _multipleBufferGCHandles[i] = GCHandle.Alloc(_bufferListInternal[i].Array, GCHandleType.Pinned); } - if (_wsaBufferArray == null || _wsaBufferArray.Length < bufferCount) + if (_wsaBufferArrayPinned == null || _wsaBufferArrayPinned.Length < bufferCount) { - _wsaBufferArray = new WSABuffer[bufferCount]; + _wsaBufferArrayPinned = GC.AllocateUninitializedArray(bufferCount, pinned: true); } for (int i = 0; i < bufferCount; i++) { ArraySegment localCopy = _bufferListInternal[i]; - _wsaBufferArray[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(localCopy.Array!, localCopy.Offset); - _wsaBufferArray[i].Length = localCopy.Count; + _wsaBufferArrayPinned[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(localCopy.Array!, localCopy.Offset); + _wsaBufferArrayPinned[i].Length = localCopy.Count; } _pinState = PinState.MultipleBuffer; @@ -969,21 +934,6 @@ private void FreePinHandles() _socketAddressGCHandle.Free(); _pinnedSocketAddress = null; } - - if (_wsaMessageBufferGCHandle.IsAllocated) - { - _wsaMessageBufferGCHandle.Free(); - } - - if (_wsaRecvMsgWSABufferArrayGCHandle.IsAllocated) - { - _wsaRecvMsgWSABufferArrayGCHandle.Free(); - } - - if (_controlBufferGCHandle.IsAllocated) - { - _controlBufferGCHandle.Free(); - } } // Sets up an Overlapped object for SendPacketsAsync. @@ -996,7 +946,9 @@ private unsafe Interop.Winsock.TransmitPacketsElement[] SetupPinHandlesSendPacke } // Alloc native descriptor. - var sendPacketsDescriptor = new Interop.Winsock.TransmitPacketsElement[sendPacketsElementsFileCount + sendPacketsElementsFileStreamCount + sendPacketsElementsBufferCount]; + var sendPacketsDescriptorPinned = GC.AllocateUninitializedArray( + sendPacketsElementsFileCount + sendPacketsElementsFileStreamCount + sendPacketsElementsBufferCount, + pinned: true); // Number of things to pin is number of buffers + 1 (native descriptor). // Ensure we have properly sized object array. @@ -1010,15 +962,13 @@ private unsafe Interop.Winsock.TransmitPacketsElement[] SetupPinHandlesSendPacke } #endif - if (_multipleBufferGCHandles == null || (_multipleBufferGCHandles.Length < sendPacketsElementsBufferCount + 1)) + if (_multipleBufferGCHandles == null || (_multipleBufferGCHandles.Length < sendPacketsElementsBufferCount)) { - _multipleBufferGCHandles = new GCHandle[sendPacketsElementsBufferCount + 1]; + _multipleBufferGCHandles = new GCHandle[sendPacketsElementsBufferCount]; } - // Pin objects. Native descriptor buffer first and then user specified buffers. - Debug.Assert(!_multipleBufferGCHandles[0].IsAllocated); - _multipleBufferGCHandles[0] = GCHandle.Alloc(sendPacketsDescriptor, GCHandleType.Pinned); - int index = 1; + // Pin user specified buffers. + int index = 0; foreach (SendPacketsElement spe in sendPacketsElementsCopy) { if (spe?.Buffer != null && spe.Count > 0) @@ -1040,9 +990,9 @@ private unsafe Interop.Winsock.TransmitPacketsElement[] SetupPinHandlesSendPacke if (spe.Buffer != null && spe.Count > 0) { // This element is a buffer. - sendPacketsDescriptor[descriptorIndex].buffer = Marshal.UnsafeAddrOfPinnedArrayElement(spe.Buffer, spe.Offset); - sendPacketsDescriptor[descriptorIndex].length = (uint)spe.Count; - sendPacketsDescriptor[descriptorIndex].flags = + sendPacketsDescriptorPinned[descriptorIndex].buffer = Marshal.UnsafeAddrOfPinnedArrayElement(spe.Buffer, spe.Offset); + sendPacketsDescriptorPinned[descriptorIndex].length = (uint)spe.Count; + sendPacketsDescriptorPinned[descriptorIndex].flags = Interop.Winsock.TransmitPacketsElementFlags.Memory | (spe.EndOfPacket ? Interop.Winsock.TransmitPacketsElementFlags.EndOfPacket : 0); @@ -1051,10 +1001,10 @@ private unsafe Interop.Winsock.TransmitPacketsElement[] SetupPinHandlesSendPacke else if (spe.FilePath != null) { // This element is a file. - sendPacketsDescriptor[descriptorIndex].fileHandle = _sendPacketsFileStreams![fileIndex].SafeFileHandle.DangerousGetHandle(); - sendPacketsDescriptor[descriptorIndex].fileOffset = spe.OffsetLong; - sendPacketsDescriptor[descriptorIndex].length = (uint)spe.Count; - sendPacketsDescriptor[descriptorIndex].flags = + sendPacketsDescriptorPinned[descriptorIndex].fileHandle = _sendPacketsFileStreams![fileIndex].SafeFileHandle.DangerousGetHandle(); + sendPacketsDescriptorPinned[descriptorIndex].fileOffset = spe.OffsetLong; + sendPacketsDescriptorPinned[descriptorIndex].length = (uint)spe.Count; + sendPacketsDescriptorPinned[descriptorIndex].flags = Interop.Winsock.TransmitPacketsElementFlags.File | (spe.EndOfPacket ? Interop.Winsock.TransmitPacketsElementFlags.EndOfPacket : 0); @@ -1066,11 +1016,11 @@ private unsafe Interop.Winsock.TransmitPacketsElement[] SetupPinHandlesSendPacke // This element is a file stream. SendPacketsElement throws if the FileStream is not opened asynchronously; // Synchronously opened FileStream can't be used concurrently (e.g. multiple SendPacketsElements with the same // FileStream). - sendPacketsDescriptor[descriptorIndex].fileHandle = spe.FileStream.SafeFileHandle.DangerousGetHandle(); - sendPacketsDescriptor[descriptorIndex].fileOffset = spe.OffsetLong; + sendPacketsDescriptorPinned[descriptorIndex].fileHandle = spe.FileStream.SafeFileHandle.DangerousGetHandle(); + sendPacketsDescriptorPinned[descriptorIndex].fileOffset = spe.OffsetLong; - sendPacketsDescriptor[descriptorIndex].length = (uint)spe.Count; - sendPacketsDescriptor[descriptorIndex].flags = + sendPacketsDescriptorPinned[descriptorIndex].length = (uint)spe.Count; + sendPacketsDescriptorPinned[descriptorIndex].flags = Interop.Winsock.TransmitPacketsElementFlags.File | (spe.EndOfPacket ? Interop.Winsock.TransmitPacketsElementFlags.EndOfPacket : 0); @@ -1080,7 +1030,7 @@ private unsafe Interop.Winsock.TransmitPacketsElement[] SetupPinHandlesSendPacke } _pinState = PinState.SendPackets; - return sendPacketsDescriptor; + return sendPacketsDescriptorPinned; } internal void LogBuffer(int size) @@ -1094,7 +1044,7 @@ internal void LogBuffer(int size) { for (int i = 0; i < _bufferListInternal!.Count; i++) { - WSABuffer wsaBuffer = _wsaBufferArray![i]; + WSABuffer wsaBuffer = _wsaBufferArrayPinned![i]; NetEventSource.DumpBuffer(this, wsaBuffer.Pointer, Math.Min(wsaBuffer.Length, size)); if ((size -= wsaBuffer.Length) <= 0) { @@ -1233,14 +1183,14 @@ void CompleteCoreSpin() // separate out to help inline the fast path private unsafe void FinishOperationReceiveMessageFrom() { - Interop.Winsock.WSAMsg* PtrMessage = (Interop.Winsock.WSAMsg*)Marshal.UnsafeAddrOfPinnedArrayElement(_wsaMessageBuffer!, 0); + Interop.Winsock.WSAMsg* PtrMessage = (Interop.Winsock.WSAMsg*)Marshal.UnsafeAddrOfPinnedArrayElement(_wsaMessageBufferPinned!, 0); - if (_controlBuffer!.Length == sizeof(Interop.Winsock.ControlData)) + if (_controlBufferPinned!.Length == sizeof(Interop.Winsock.ControlData)) { // IPv4. _receiveMessageFromPacketInfo = SocketPal.GetIPPacketInformation((Interop.Winsock.ControlData*)PtrMessage->controlBuffer.Pointer); } - else if (_controlBuffer.Length == sizeof(Interop.Winsock.ControlDataIPv6)) + else if (_controlBufferPinned.Length == sizeof(Interop.Winsock.ControlDataIPv6)) { // IPv6. _receiveMessageFromPacketInfo = SocketPal.GetIPPacketInformation((Interop.Winsock.ControlDataIPv6*)PtrMessage->controlBuffer.Pointer); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs index dd3f8953e988bc..e8857e5bfcf229 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs @@ -690,7 +690,14 @@ internal void FinishOperationSyncSuccess(int bytesTransferred, SocketFlags flags { _acceptSocket = _currentSocket.UpdateAcceptSocket(_acceptSocket!, _currentSocket._rightEndPoint!.Create(remoteSocketAddress)); - if (NetEventSource.IsEnabled) NetEventSource.Accepted(_acceptSocket, _acceptSocket.RemoteEndPoint, _acceptSocket.LocalEndPoint); + if (NetEventSource.IsEnabled) + { + try + { + NetEventSource.Accepted(_acceptSocket, _acceptSocket.RemoteEndPoint, _acceptSocket.LocalEndPoint); + } + catch (ObjectDisposedException) { } + } } else { @@ -704,7 +711,14 @@ internal void FinishOperationSyncSuccess(int bytesTransferred, SocketFlags flags socketError = FinishOperationConnect(); if (socketError == SocketError.Success) { - if (NetEventSource.IsEnabled) NetEventSource.Connected(_currentSocket!, _currentSocket!.LocalEndPoint, _currentSocket.RemoteEndPoint); + if (NetEventSource.IsEnabled) + { + try + { + NetEventSource.Connected(_currentSocket!, _currentSocket!.LocalEndPoint, _currentSocket.RemoteEndPoint); + } + catch (ObjectDisposedException) { } + } // Mark socket connected. _currentSocket!.SetToConnected(); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs index 3c43b02163d1eb..f174b732c25528 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs @@ -16,6 +16,7 @@ namespace System.Net.Sockets internal static partial class SocketPal { public const bool SupportsMultipleConnectAttempts = false; + public static readonly int MaximumAddressSize = Interop.Sys.GetMaximumAddressSize(); private static readonly bool SupportsDualModeIPv4PacketInfo = GetPlatformSupportsDualModeIPv4PacketInfo(); private static bool GetPlatformSupportsDualModeIPv4PacketInfo() @@ -95,7 +96,29 @@ public static unsafe SocketError CreateSocket(AddressFamily addressFamily, Socke return errorCode; } - private static unsafe int Receive(SafeSocketHandle socket, SocketFlags flags, Span buffer, byte[]? socketAddress, ref int socketAddressLen, out SocketFlags receivedFlags, out Interop.Error errno) + private static unsafe int SysReceive(SafeSocketHandle socket, SocketFlags flags, Span buffer, out Interop.Error errno) + { + int received = 0; + + fixed (byte* b = &MemoryMarshal.GetReference(buffer)) + { + errno = Interop.Sys.Receive( + socket, + b, + buffer.Length, + flags, + &received); + } + + if (errno != Interop.Error.SUCCESS) + { + return -1; + } + + return received; + } + + private static unsafe int SysReceive(SafeSocketHandle socket, SocketFlags flags, Span buffer, byte[]? socketAddress, ref int socketAddressLen, out SocketFlags receivedFlags, out Interop.Error errno) { Debug.Assert(socketAddress != null || socketAddressLen == 0, $"Unexpected values: socketAddress={socketAddress}, socketAddressLen={socketAddressLen}"); @@ -136,7 +159,30 @@ private static unsafe int Receive(SafeSocketHandle socket, SocketFlags flags, Sp return checked((int)received); } - private static unsafe int Send(SafeSocketHandle socket, SocketFlags flags, ReadOnlySpan buffer, ref int offset, ref int count, byte[]? socketAddress, int socketAddressLen, out Interop.Error errno) + private static unsafe int SysSend(SafeSocketHandle socket, SocketFlags flags, ReadOnlySpan buffer, ref int offset, ref int count, out Interop.Error errno) + { + int sent; + fixed (byte* b = &MemoryMarshal.GetReference(buffer)) + { + errno = Interop.Sys.Send( + socket, + &b[offset], + count, + flags, + &sent); + } + + if (errno != Interop.Error.SUCCESS) + { + return -1; + } + + offset += sent; + count -= sent; + return sent; + } + + private static unsafe int SysSend(SafeSocketHandle socket, SocketFlags flags, ReadOnlySpan buffer, ref int offset, ref int count, byte[] socketAddress, int socketAddressLen, out Interop.Error errno) { int sent; fixed (byte* sockAddr = socketAddress) @@ -176,7 +222,7 @@ private static unsafe int Send(SafeSocketHandle socket, SocketFlags flags, ReadO return sent; } - private static unsafe int Send(SafeSocketHandle socket, SocketFlags flags, IList> buffers, ref int bufferIndex, ref int offset, byte[]? socketAddress, int socketAddressLen, out Interop.Error errno) + private static unsafe int SysSend(SafeSocketHandle socket, SocketFlags flags, IList> buffers, ref int bufferIndex, ref int offset, byte[]? socketAddress, int socketAddressLen, out Interop.Error errno) { // Pin buffers and set up iovecs. int startIndex = bufferIndex, startOffset = offset; @@ -273,7 +319,7 @@ private static unsafe long SendFile(SafeSocketHandle socket, SafeFileHandle file return bytesSent; } - private static unsafe int Receive(SafeSocketHandle socket, SocketFlags flags, IList> buffers, byte[]? socketAddress, ref int socketAddressLen, out SocketFlags receivedFlags, out Interop.Error errno) + private static unsafe int SysReceive(SafeSocketHandle socket, SocketFlags flags, IList> buffers, byte[]? socketAddress, ref int socketAddressLen, out SocketFlags receivedFlags, out Interop.Error errno) { int available = 0; errno = Interop.Sys.GetBytesAvailable(socket, &available); @@ -372,7 +418,7 @@ private static unsafe int Receive(SafeSocketHandle socket, SocketFlags flags, IL return checked((int)received); } - private static unsafe int ReceiveMessageFrom(SafeSocketHandle socket, SocketFlags flags, Span buffer, byte[] socketAddress, ref int socketAddressLen, bool isIPv4, bool isIPv6, out SocketFlags receivedFlags, out IPPacketInformation ipPacketInformation, out Interop.Error errno) + private static unsafe int SysReceiveMessageFrom(SafeSocketHandle socket, SocketFlags flags, Span buffer, byte[] socketAddress, ref int socketAddressLen, bool isIPv4, bool isIPv6, out SocketFlags receivedFlags, out IPPacketInformation ipPacketInformation, out Interop.Error errno) { Debug.Assert(socketAddress != null, "Expected non-null socketAddress"); @@ -422,7 +468,7 @@ private static unsafe int ReceiveMessageFrom(SafeSocketHandle socket, SocketFlag return checked((int)received); } - private static unsafe int ReceiveMessageFrom( + private static unsafe int SysReceiveMessageFrom( SafeSocketHandle socket, SocketFlags flags, IList> buffers, byte[] socketAddress, ref int socketAddressLen, bool isIPv4, bool isIPv6, out SocketFlags receivedFlags, out IPPacketInformation ipPacketInformation, out Interop.Error errno) @@ -616,6 +662,60 @@ public static bool TryCompleteReceiveFrom(SafeSocketHandle socket, Span bu public static bool TryCompleteReceiveFrom(SafeSocketHandle socket, IList> buffers, SocketFlags flags, byte[]? socketAddress, ref int socketAddressLen, out int bytesReceived, out SocketFlags receivedFlags, out SocketError errorCode) => TryCompleteReceiveFrom(socket, default(Span), buffers, flags, socketAddress, ref socketAddressLen, out bytesReceived, out receivedFlags, out errorCode); + public static unsafe bool TryCompleteReceive(SafeSocketHandle socket, Span buffer, SocketFlags flags, out int bytesReceived, out SocketError errorCode) + { + try + { + Interop.Error errno; + int received; + + if (buffer.Length == 0) + { + // Special case a receive of 0 bytes into a single buffer. A common pattern is to ReceiveAsync 0 bytes in order + // to be asynchronously notified when data is available, without needing to dedicate a buffer. Some platforms (e.g. macOS), + // however complete a 0-byte read successfully when data isn't available, as the request can logically be satisfied + // synchronously. As such, we treat 0 specially, and perform a 1-byte peek. + byte oneBytePeekBuffer; + received = SysReceive(socket, flags | SocketFlags.Peek, new Span(&oneBytePeekBuffer, 1), out errno); + if (received > 0) + { + // Peeked for 1-byte, but the actual request was for 0. + received = 0; + } + } + else + { + // Receive > 0 bytes into a single buffer + received = SysReceive(socket, flags, buffer, out errno); + } + + if (received != -1) + { + bytesReceived = received; + errorCode = SocketError.Success; + return true; + } + + bytesReceived = 0; + + if (errno != Interop.Error.EAGAIN && errno != Interop.Error.EWOULDBLOCK) + { + errorCode = GetSocketErrorForErrorCode(errno); + return true; + } + + errorCode = SocketError.Success; + return false; + } + catch (ObjectDisposedException) + { + // The socket was closed, or is closing. + bytesReceived = 0; + errorCode = SocketError.OperationAborted; + return true; + } + } + public static unsafe bool TryCompleteReceiveFrom(SafeSocketHandle socket, Span buffer, IList>? buffers, SocketFlags flags, byte[]? socketAddress, ref int socketAddressLen, out int bytesReceived, out SocketFlags receivedFlags, out SocketError errorCode) { try @@ -626,7 +726,7 @@ public static unsafe bool TryCompleteReceiveFrom(SafeSocketHandle socket, Span(&oneBytePeekBuffer, 1), socketAddress, ref socketAddressLen, out receivedFlags, out errno); + received = SysReceive(socket, flags | SocketFlags.Peek, new Span(&oneBytePeekBuffer, 1), socketAddress, ref socketAddressLen, out receivedFlags, out errno); if (received > 0) { // Peeked for 1-byte, but the actual request was for 0. @@ -645,7 +745,7 @@ public static unsafe bool TryCompleteReceiveFrom(SafeSocketHandle socket, Span 0 bytes into a single buffer - received = Receive(socket, flags, buffer, socketAddress, ref socketAddressLen, out receivedFlags, out errno); + received = SysReceive(socket, flags, buffer, socketAddress, ref socketAddressLen, out receivedFlags, out errno); } if (received != -1) @@ -683,8 +783,8 @@ public static unsafe bool TryCompleteReceiveMessageFrom(SafeSocketHandle socket, Interop.Error errno; int received = buffers == null ? - ReceiveMessageFrom(socket, flags, buffer, socketAddress, ref socketAddressLen, isIPv4, isIPv6, out receivedFlags, out ipPacketInformation, out errno) : - ReceiveMessageFrom(socket, flags, buffers, socketAddress, ref socketAddressLen, isIPv4, isIPv6, out receivedFlags, out ipPacketInformation, out errno); + SysReceiveMessageFrom(socket, flags, buffer, socketAddress, ref socketAddressLen, isIPv4, isIPv6, out receivedFlags, out ipPacketInformation, out errno) : + SysReceiveMessageFrom(socket, flags, buffers, socketAddress, ref socketAddressLen, isIPv4, isIPv6, out receivedFlags, out ipPacketInformation, out errno); if (received != -1) { @@ -745,8 +845,9 @@ public static bool TryCompleteSendTo(SafeSocketHandle socket, ReadOnlySpan try { sent = buffers != null ? - Send(socket, flags, buffers, ref bufferIndex, ref offset, socketAddress, socketAddressLen, out errno) : - Send(socket, flags, buffer, ref offset, ref count, socketAddress, socketAddressLen, out errno); + SysSend(socket, flags, buffers, ref bufferIndex, ref offset, socketAddress, socketAddressLen, out errno) : + socketAddress == null ? SysSend(socket, flags, buffer, ref offset, ref count, out errno) : + SysSend(socket, flags, buffer, ref offset, ref count, socketAddress, socketAddressLen, out errno); } catch (ObjectDisposedException) { @@ -861,7 +962,7 @@ public static unsafe SocketError GetAtOutOfBandMark(SafeSocketHandle handle, out return err == Interop.Error.SUCCESS ? SocketError.Success : GetSocketErrorForErrorCode(err); } - public static unsafe SocketError GetPeerName(SafeSocketHandle handle, byte[] buffer, ref int nameLen) + public static unsafe SocketError GetPeerName(SafeSocketHandle handle, Span buffer, ref int nameLen) { Interop.Error err; int addrLen = nameLen; @@ -1008,12 +1109,12 @@ public static SocketError SendTo(SafeSocketHandle handle, byte[] buffer, int off return errorCode; } - public static SocketError Receive(SafeSocketHandle handle, IList> buffers, ref SocketFlags socketFlags, out int bytesTransferred) + public static SocketError Receive(SafeSocketHandle handle, IList> buffers, SocketFlags socketFlags, out int bytesTransferred) { SocketError errorCode; if (!handle.IsNonBlocking) { - errorCode = handle.AsyncContext.Receive(buffers, ref socketFlags, handle.ReceiveTimeout, out bytesTransferred); + errorCode = handle.AsyncContext.Receive(buffers, socketFlags, handle.ReceiveTimeout, out bytesTransferred); } else { @@ -1031,12 +1132,11 @@ public static SocketError Receive(SafeSocketHandle handle, byte[] buffer, int of { if (!handle.IsNonBlocking) { - return handle.AsyncContext.Receive(new Memory(buffer, offset, count), ref socketFlags, handle.ReceiveTimeout, out bytesTransferred); + return handle.AsyncContext.Receive(new Memory(buffer, offset, count), socketFlags, handle.ReceiveTimeout, out bytesTransferred); } - int socketAddressLen = 0; SocketError errorCode; - bool completed = TryCompleteReceiveFrom(handle, new Span(buffer, offset, count), socketFlags, null, ref socketAddressLen, out bytesTransferred, out socketFlags, out errorCode); + bool completed = TryCompleteReceive(handle, new Span(buffer, offset, count), socketFlags, out bytesTransferred, out errorCode); return completed ? errorCode : SocketError.WouldBlock; } @@ -1044,12 +1144,11 @@ public static SocketError Receive(SafeSocketHandle handle, Span buffer, So { if (!handle.IsNonBlocking) { - return handle.AsyncContext.Receive(buffer, ref socketFlags, handle.ReceiveTimeout, out bytesTransferred); + return handle.AsyncContext.Receive(buffer, socketFlags, handle.ReceiveTimeout, out bytesTransferred); } - int socketAddressLen = 0; SocketError errorCode; - bool completed = TryCompleteReceiveFrom(handle, buffer, socketFlags, null, ref socketAddressLen, out bytesTransferred, out socketFlags, out errorCode); + bool completed = TryCompleteReceive(handle, buffer, socketFlags, out bytesTransferred, out errorCode); return completed ? errorCode : SocketError.WouldBlock; } @@ -1452,17 +1551,17 @@ public static unsafe SocketError GetLingerOption(SafeSocketHandle handle, out Li public static unsafe SocketError Poll(SafeSocketHandle handle, int microseconds, SelectMode mode, out bool status) { - Interop.Sys.PollEvents inEvent = Interop.Sys.PollEvents.POLLNONE; + Interop.PollEvents inEvent = Interop.PollEvents.POLLNONE; switch (mode) { - case SelectMode.SelectRead: inEvent = Interop.Sys.PollEvents.POLLIN; break; - case SelectMode.SelectWrite: inEvent = Interop.Sys.PollEvents.POLLOUT; break; - case SelectMode.SelectError: inEvent = Interop.Sys.PollEvents.POLLPRI; break; + case SelectMode.SelectRead: inEvent = Interop.PollEvents.POLLIN; break; + case SelectMode.SelectWrite: inEvent = Interop.PollEvents.POLLOUT; break; + case SelectMode.SelectError: inEvent = Interop.PollEvents.POLLPRI; break; } int milliseconds = microseconds == -1 ? -1 : microseconds / 1000; - Interop.Sys.PollEvents outEvents; + Interop.PollEvents outEvents; Interop.Error err = Interop.Sys.Poll(handle, inEvent, milliseconds, out outEvents); if (err != Interop.Error.SUCCESS) { @@ -1472,9 +1571,9 @@ public static unsafe SocketError Poll(SafeSocketHandle handle, int microseconds, switch (mode) { - case SelectMode.SelectRead: status = (outEvents & (Interop.Sys.PollEvents.POLLIN | Interop.Sys.PollEvents.POLLHUP)) != 0; break; - case SelectMode.SelectWrite: status = (outEvents & Interop.Sys.PollEvents.POLLOUT) != 0; break; - case SelectMode.SelectError: status = (outEvents & (Interop.Sys.PollEvents.POLLERR | Interop.Sys.PollEvents.POLLPRI)) != 0; break; + case SelectMode.SelectRead: status = (outEvents & (Interop.PollEvents.POLLIN | Interop.PollEvents.POLLHUP)) != 0; break; + case SelectMode.SelectWrite: status = (outEvents & Interop.PollEvents.POLLOUT) != 0; break; + case SelectMode.SelectError: status = (outEvents & (Interop.PollEvents.POLLERR | Interop.PollEvents.POLLPRI)) != 0; break; default: status = false; break; } return SocketError.Success; @@ -1497,7 +1596,7 @@ public static unsafe SocketError Select(IList? checkRead, IList? checkWrite, ILi const int StackThreshold = 80; // arbitrary limit to avoid too much space on stack if (count < StackThreshold) { - Interop.Sys.PollEvent* eventsOnStack = stackalloc Interop.Sys.PollEvent[count]; + Interop.PollEvent* eventsOnStack = stackalloc Interop.PollEvent[count]; return SelectViaPoll( checkRead, checkReadInitialCount, checkWrite, checkWriteInitialCount, @@ -1506,8 +1605,8 @@ public static unsafe SocketError Select(IList? checkRead, IList? checkWrite, ILi } else { - var eventsOnHeap = new Interop.Sys.PollEvent[count]; - fixed (Interop.Sys.PollEvent* eventsOnHeapPtr = &eventsOnHeap[0]) + var eventsOnHeap = new Interop.PollEvent[count]; + fixed (Interop.PollEvent* eventsOnHeapPtr = &eventsOnHeap[0]) { return SelectViaPoll( checkRead, checkReadInitialCount, @@ -1522,7 +1621,7 @@ private static unsafe SocketError SelectViaPoll( IList? checkRead, int checkReadInitialCount, IList? checkWrite, int checkWriteInitialCount, IList? checkError, int checkErrorInitialCount, - Interop.Sys.PollEvent* events, int eventsLength, + Interop.PollEvent* events, int eventsLength, int microseconds) { // Add each of the list's contents to the events array @@ -1533,9 +1632,9 @@ private static unsafe SocketError SelectViaPoll( { // In case we can't increase the reference count for each Socket, // we'll unref refAdded Sockets in the finally block ordered: [checkRead, checkWrite, checkError]. - AddToPollArray(events, eventsLength, checkRead, ref offset, Interop.Sys.PollEvents.POLLIN | Interop.Sys.PollEvents.POLLHUP, ref refsAdded); - AddToPollArray(events, eventsLength, checkWrite, ref offset, Interop.Sys.PollEvents.POLLOUT, ref refsAdded); - AddToPollArray(events, eventsLength, checkError, ref offset, Interop.Sys.PollEvents.POLLPRI, ref refsAdded); + AddToPollArray(events, eventsLength, checkRead, ref offset, Interop.PollEvents.POLLIN | Interop.PollEvents.POLLHUP, ref refsAdded); + AddToPollArray(events, eventsLength, checkWrite, ref offset, Interop.PollEvents.POLLOUT, ref refsAdded); + AddToPollArray(events, eventsLength, checkError, ref offset, Interop.PollEvents.POLLPRI, ref refsAdded); Debug.Assert(offset == eventsLength, $"Invalid adds. offset={offset}, eventsLength={eventsLength}."); Debug.Assert(refsAdded == eventsLength, $"Invalid ref adds. refsAdded={refsAdded}, eventsLength={eventsLength}."); @@ -1561,9 +1660,9 @@ private static unsafe SocketError SelectViaPoll( } else { - FilterPollList(checkRead, events, checkReadInitialCount - 1, Interop.Sys.PollEvents.POLLIN | Interop.Sys.PollEvents.POLLHUP, ref refsAdded); - FilterPollList(checkWrite, events, checkWriteInitialCount + checkReadInitialCount - 1, Interop.Sys.PollEvents.POLLOUT, ref refsAdded); - FilterPollList(checkError, events, checkErrorInitialCount + checkWriteInitialCount + checkReadInitialCount - 1, Interop.Sys.PollEvents.POLLERR | Interop.Sys.PollEvents.POLLPRI, ref refsAdded); + FilterPollList(checkRead, events, checkReadInitialCount - 1, Interop.PollEvents.POLLIN | Interop.PollEvents.POLLHUP, ref refsAdded); + FilterPollList(checkWrite, events, checkWriteInitialCount + checkReadInitialCount - 1, Interop.PollEvents.POLLOUT, ref refsAdded); + FilterPollList(checkError, events, checkErrorInitialCount + checkWriteInitialCount + checkReadInitialCount - 1, Interop.PollEvents.POLLERR | Interop.PollEvents.POLLPRI, ref refsAdded); } return SocketError.Success; @@ -1579,7 +1678,7 @@ private static unsafe SocketError SelectViaPoll( } } - private static unsafe void AddToPollArray(Interop.Sys.PollEvent* arr, int arrLength, IList? socketList, ref int arrOffset, Interop.Sys.PollEvents events, ref int refsAdded) + private static unsafe void AddToPollArray(Interop.PollEvent* arr, int arrLength, IList? socketList, ref int arrOffset, Interop.PollEvents events, ref int refsAdded) { if (socketList == null) return; @@ -1602,12 +1701,12 @@ private static unsafe void AddToPollArray(Interop.Sys.PollEvent* arr, int arrLen bool success = false; socket.InternalSafeHandle.DangerousAddRef(ref success); int fd = (int)socket.InternalSafeHandle.DangerousGetHandle(); - arr[arrOffset++] = new Interop.Sys.PollEvent { Events = events, FileDescriptor = fd }; + arr[arrOffset++] = new Interop.PollEvent { Events = events, FileDescriptor = fd }; refsAdded++; } } - private static unsafe void FilterPollList(IList? socketList, Interop.Sys.PollEvent* arr, int arrEndOffset, Interop.Sys.PollEvents desiredEvents, ref int refsAdded) + private static unsafe void FilterPollList(IList? socketList, Interop.PollEvent* arr, int arrEndOffset, Interop.PollEvents desiredEvents, ref int refsAdded) { if (socketList == null) return; @@ -1755,11 +1854,11 @@ public static async void SendPacketsAsync( if ((options & (TransmitFileOptions.Disconnect | TransmitFileOptions.ReuseSocket)) != 0) { - await Task.Factory.FromAsync( - (reuse, c, s) => ((Socket)s!).BeginDisconnect(reuse, c, s), - iar => ((Socket)iar.AsyncState!).EndDisconnect(iar), - (options & TransmitFileOptions.ReuseSocket) != 0, - socket).ConfigureAwait(false); + error = Disconnect(socket, socket.InternalSafeHandle, (options & TransmitFileOptions.ReuseSocket) != 0); + if (error != SocketError.Success) + { + throw new SocketException((int)error); + } } } catch (Exception exc) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs index c3e113b0841249..6ea3e1cc03aa21 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs @@ -17,6 +17,7 @@ namespace System.Net.Sockets internal static class SocketPal { public const bool SupportsMultipleConnectAttempts = true; + public static readonly int MaximumAddressSize = UnixDomainSocketEndPoint.MaxAddressSize; private static void MicrosecondsToTimeValue(long microseconds, ref Interop.Winsock.TimeValue socketTime) { @@ -155,10 +156,13 @@ public static SocketError GetAvailable(SafeSocketHandle handle, out int availabl return errorCode == SocketError.SocketError ? GetLastSocketError() : SocketError.Success; } - public static SocketError GetPeerName(SafeSocketHandle handle, byte[] buffer, ref int nameLen) + public static unsafe SocketError GetPeerName(SafeSocketHandle handle, Span buffer, ref int nameLen) { - SocketError errorCode = Interop.Winsock.getpeername(handle, buffer, ref nameLen); - return errorCode == SocketError.SocketError ? GetLastSocketError() : SocketError.Success; + fixed (byte* rawBuffer = buffer) + { + SocketError errorCode = Interop.Winsock.getpeername(handle, rawBuffer, ref nameLen); + return errorCode == SocketError.SocketError ? GetLastSocketError() : SocketError.Success; + } } public static SocketError Bind(SafeSocketHandle handle, ProtocolType socketProtocolType, byte[] buffer, int nameLen) @@ -334,7 +338,7 @@ public static unsafe SocketError SendTo(SafeSocketHandle handle, byte[] buffer, return SocketError.Success; } - public static SocketError Receive(SafeSocketHandle handle, IList> buffers, ref SocketFlags socketFlags, out int bytesTransferred) + public static SocketError Receive(SafeSocketHandle handle, IList> buffers, SocketFlags socketFlags, out int bytesTransferred) { const int StackThreshold = 16; // arbitrary limit to avoid too much space on stack (note: may be over-sized, that's OK - length passed separately) int count = buffers.Count; diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs index ead0a6ebc47f7f..71480cffbd6e0b 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs @@ -285,23 +285,41 @@ public void Connect(IPAddress[] ipAddresses, int port) if (NetEventSource.IsEnabled) NetEventSource.Exit(this); } - public Task ConnectAsync(IPAddress address, int port) => - Task.Factory.FromAsync( - (targetAddess, targetPort, callback, state) => ((TcpClient)state!).BeginConnect(targetAddess, targetPort, callback, state), - asyncResult => ((TcpClient)asyncResult.AsyncState!).EndConnect(asyncResult), - address, port, state: this); - - public Task ConnectAsync(string host, int port) => - Task.Factory.FromAsync( - (targetHost, targetPort, callback, state) => ((TcpClient)state!).BeginConnect(targetHost, targetPort, callback, state), - asyncResult => ((TcpClient)asyncResult.AsyncState!).EndConnect(asyncResult), - host, port, state: this); - - public Task ConnectAsync(IPAddress[] addresses, int port) => - Task.Factory.FromAsync( - (targetAddresses, targetPort, callback, state) => ((TcpClient)state!).BeginConnect(targetAddresses, targetPort, callback, state), - asyncResult => ((TcpClient)asyncResult.AsyncState!).EndConnect(asyncResult), - addresses, port, state: this); + public Task ConnectAsync(IPAddress address, int port) + { + if (NetEventSource.IsEnabled) NetEventSource.Enter(this, address); + + Task result = CompleteConnectAsync(Client.ConnectAsync(address, port)); + + if (NetEventSource.IsEnabled) NetEventSource.Exit(this); + return result; + } + + public Task ConnectAsync(string host, int port) + { + if (NetEventSource.IsEnabled) NetEventSource.Enter(this, host); + + Task result = CompleteConnectAsync(Client.ConnectAsync(host, port)); + + if (NetEventSource.IsEnabled) NetEventSource.Exit(this); + return result; + } + + public Task ConnectAsync(IPAddress[] addresses, int port) + { + if (NetEventSource.IsEnabled) NetEventSource.Enter(this, addresses); + + Task result = CompleteConnectAsync(Client.ConnectAsync(addresses, port)); + + if (NetEventSource.IsEnabled) NetEventSource.Exit(this); + return result; + } + + private async Task CompleteConnectAsync(Task task) + { + await task.ConfigureAwait(false); + _active = true; + } public IAsyncResult BeginConnect(IPAddress address, int port, AsyncCallback? requestCallback, object? state) { @@ -409,18 +427,7 @@ protected virtual void Dispose(bool disposing) public void Dispose() => Dispose(true); - ~TcpClient() - { -#if DEBUG - DebugThreadTracking.SetThreadSource(ThreadKinds.Finalization); - using (DebugThreadTracking.SetThreadKind(ThreadKinds.System | ThreadKinds.Async)) - { -#endif - Dispose(false); -#if DEBUG - } -#endif - } + ~TcpClient() => Dispose(false); // Gets or sets the size of the receive buffer in bytes. public int ReceiveBufferSize diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs index 9dae2af1c57f80..a183eb22f254f1 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs @@ -262,56 +262,34 @@ public Socket EndAcceptSocket(IAsyncResult asyncResult) return socket; } - public IAsyncResult BeginAcceptTcpClient(AsyncCallback? callback, object? state) - { - if (NetEventSource.IsEnabled) NetEventSource.Enter(this); + public IAsyncResult BeginAcceptTcpClient(AsyncCallback? callback, object? state) => + BeginAcceptSocket(callback, state); - if (!_active) - { - throw new InvalidOperationException(SR.net_stopped); - } + public TcpClient EndAcceptTcpClient(IAsyncResult asyncResult) => + new TcpClient(EndAcceptSocket(asyncResult)); - IAsyncResult result = _serverSocket!.BeginAccept(callback, state); - if (NetEventSource.IsEnabled) NetEventSource.Exit(this, result); - return result; - } - - public TcpClient EndAcceptTcpClient(IAsyncResult asyncResult) + public Task AcceptSocketAsync() { if (NetEventSource.IsEnabled) NetEventSource.Enter(this); - if (asyncResult == null) + if (!_active) { - throw new ArgumentNullException(nameof(asyncResult)); + throw new InvalidOperationException(SR.net_stopped); } - LazyAsyncResult? lazyResult = asyncResult as LazyAsyncResult; - Socket? asyncSocket = lazyResult == null ? null : lazyResult.AsyncObject as Socket; - if (asyncSocket == null) - { - throw new ArgumentException(SR.net_io_invalidasyncresult, nameof(asyncResult)); - } + Task result = _serverSocket!.AcceptAsync(); - // This will throw ObjectDisposedException if Stop() has been called. - Socket socket = asyncSocket.EndAccept(asyncResult); - if (NetEventSource.IsEnabled) NetEventSource.Exit(this, socket); - return new TcpClient(socket); - } + if (NetEventSource.IsEnabled) NetEventSource.Exit(this); - public Task AcceptSocketAsync() - { - return Task.Factory.FromAsync( - (callback, state) => ((TcpListener)state!).BeginAcceptSocket(callback, state), - asyncResult => ((TcpListener)asyncResult.AsyncState!).EndAcceptSocket(asyncResult), - state: this); + return result; } public Task AcceptTcpClientAsync() { - return Task.Factory.FromAsync( - (callback, state) => ((TcpListener)state!).BeginAcceptTcpClient(callback, state), - asyncResult => ((TcpListener)asyncResult.AsyncState!).EndAcceptTcpClient(asyncResult), - state: this); + return WaitAndWrap(AcceptSocketAsync()); + + static async Task WaitAndWrap(Task task) => + new TcpClient(await task.ConfigureAwait(false)); } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs index c7d280fc3c59d6..7daf3a58aeb916 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs @@ -282,11 +282,40 @@ private bool IsBroadcast(IPAddress address) } } + public IAsyncResult BeginSend(byte[] datagram, int bytes, AsyncCallback? requestCallback, object? state) => + BeginSend(datagram, bytes, null, requestCallback, state); + + public IAsyncResult BeginSend(byte[] datagram, int bytes, string? hostname, int port, AsyncCallback? requestCallback, object? state) => + BeginSend(datagram, bytes, GetEndpoint(hostname, port), requestCallback, state); + public IAsyncResult BeginSend(byte[] datagram, int bytes, IPEndPoint? endPoint, AsyncCallback? requestCallback, object? state) + { + ValidateDatagram(datagram, bytes, endPoint); + + if (endPoint is null) + { + return _clientSocket.BeginSend(datagram, 0, bytes, SocketFlags.None, requestCallback, state); + } + else + { + CheckForBroadcast(endPoint.Address); + return _clientSocket.BeginSendTo(datagram, 0, bytes, SocketFlags.None, endPoint, requestCallback, state); + } + } + + public int EndSend(IAsyncResult asyncResult) + { + ThrowIfDisposed(); + + return _active ? + _clientSocket.EndSend(asyncResult) : + _clientSocket.EndSendTo(asyncResult); + } + + private void ValidateDatagram(byte[] datagram, int bytes, IPEndPoint? endPoint) { ThrowIfDisposed(); - // Validate input parameters. if (datagram == null) { throw new ArgumentNullException(nameof(datagram)); @@ -302,18 +331,9 @@ public IAsyncResult BeginSend(byte[] datagram, int bytes, IPEndPoint? endPoint, // Do not allow sending packets to arbitrary host when connected. throw new InvalidOperationException(SR.net_udpconnected); } - - if (endPoint == null) - { - return _clientSocket.BeginSend(datagram, 0, bytes, SocketFlags.None, requestCallback, state); - } - - CheckForBroadcast(endPoint.Address); - - return _clientSocket.BeginSendTo(datagram, 0, bytes, SocketFlags.None, endPoint, requestCallback, state); } - public IAsyncResult BeginSend(byte[] datagram, int bytes, string? hostname, int port, AsyncCallback? requestCallback, object? state) + private IPEndPoint? GetEndpoint(string? hostname, int port) { if (_active && ((hostname != null) || (port != 0))) { @@ -340,26 +360,7 @@ public IAsyncResult BeginSend(byte[] datagram, int bytes, string? hostname, int ipEndPoint = new IPEndPoint(addresses[i], port); } - return BeginSend(datagram, bytes, ipEndPoint, requestCallback, state); - } - - public IAsyncResult BeginSend(byte[] datagram, int bytes, AsyncCallback? requestCallback, object? state) - { - return BeginSend(datagram, bytes, null, requestCallback, state); - } - - public int EndSend(IAsyncResult asyncResult) - { - ThrowIfDisposed(); - - if (_active) - { - return _clientSocket.EndSend(asyncResult); - } - else - { - return _clientSocket.EndSendTo(asyncResult); - } + return ipEndPoint; } public IAsyncResult BeginReceive(AsyncCallback? requestCallback, object? state) @@ -595,59 +596,46 @@ public void DropMulticastGroup(IPAddress multicastAddr, int ifindex) mcOpt); } - public Task SendAsync(byte[] datagram, int bytes) - { - return Task.Factory.FromAsync( - (targetDatagram, targetBytes, callback, state) => ((UdpClient)state!).BeginSend(targetDatagram, targetBytes, callback, state), - asyncResult => ((UdpClient)asyncResult.AsyncState!).EndSend(asyncResult), - datagram, - bytes, - state: this); - } + public Task SendAsync(byte[] datagram, int bytes) => + SendAsync(datagram, bytes, null); + + public Task SendAsync(byte[] datagram, int bytes, string? hostname, int port) => + SendAsync(datagram, bytes, GetEndpoint(hostname, port)); public Task SendAsync(byte[] datagram, int bytes, IPEndPoint? endPoint) { - return Task.Factory.FromAsync( - (targetDatagram, targetBytes, targetEndpoint, callback, state) => ((UdpClient)state!).BeginSend(targetDatagram, targetBytes, targetEndpoint, callback, state), - asyncResult => ((UdpClient)asyncResult.AsyncState!).EndSend(asyncResult), - datagram, - bytes, - endPoint, - state: this); + ValidateDatagram(datagram, bytes, endPoint); + + if (endPoint is null) + { + return _clientSocket.SendAsync(new ArraySegment(datagram, 0, bytes), SocketFlags.None); + } + else + { + CheckForBroadcast(endPoint.Address); + return _clientSocket.SendToAsync(new ArraySegment(datagram, 0, bytes), SocketFlags.None, endPoint); + } } - public Task SendAsync(byte[] datagram, int bytes, string? hostname, int port) + public Task ReceiveAsync() { - Tuple packedArguments = Tuple.Create(datagram, hostname); + ThrowIfDisposed(); - return Task.Factory.FromAsync( - (targetPackedArguments, targetBytes, targetPort, callback, state) => - { - byte[] targetDatagram = targetPackedArguments.Item1; - string? targetHostname = targetPackedArguments.Item2; - var client = (UdpClient)state!; + return WaitAndWrap(_clientSocket.ReceiveFromAsync( + new ArraySegment(_buffer, 0, MaxUDPSize), + SocketFlags.None, + _family == AddressFamily.InterNetwork ? IPEndPointStatics.Any : IPEndPointStatics.IPv6Any)); - return client.BeginSend(targetDatagram, targetBytes, targetHostname, targetPort, callback, state); - }, - asyncResult => ((UdpClient)asyncResult.AsyncState!).EndSend(asyncResult), - packedArguments, - bytes, - port, - state: this); - } + async Task WaitAndWrap(Task task) + { + SocketReceiveFromResult result = await task.ConfigureAwait(false); - public Task ReceiveAsync() - { - return Task.Factory.FromAsync( - (callback, state) => ((UdpClient)state!).BeginReceive(callback, state), - asyncResult => - { - var client = (UdpClient)asyncResult.AsyncState!; - IPEndPoint? remoteEP = null; - byte[] buffer = client.EndReceive(asyncResult, ref remoteEP); - return new UdpReceiveResult(buffer, remoteEP!); - }, - state: this); + byte[] buffer = result.ReceivedBytes < MaxUDPSize ? + _buffer.AsSpan(0, result.ReceivedBytes).ToArray() : + _buffer; + + return new UdpReceiveResult(buffer, (IPEndPoint)result.RemoteEndPoint); + } } private void CreateClientSocket() diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.cs index 2aba1266cd7e1e..2c2c0d7b1347f4 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.cs @@ -50,6 +50,8 @@ public UnixDomainSocketEndPoint(string path) } } + internal static int MaxAddressSize => s_nativeAddressSize; + internal UnixDomainSocketEndPoint(SocketAddress socketAddress) { if (socketAddress == null) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs index e11e5f7778b0bf..8c3af3465b9df5 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs @@ -454,8 +454,8 @@ public void SetSocketOption_Linger_NotLingerOption_Throws_Argument() [Fact] public void SetSocketOption_Linger_InvalidLingerTime_Throws_Argument() { - AssertExtensions.Throws("optionValue.LingerTime", () => GetSocket().SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, new LingerOption(true, -1))); - AssertExtensions.Throws("optionValue.LingerTime", () => GetSocket().SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, new LingerOption(true, (int)ushort.MaxValue + 1))); + AssertExtensions.Throws("optionValue", () => GetSocket().SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, new LingerOption(true, -1))); + AssertExtensions.Throws("optionValue", () => GetSocket().SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, new LingerOption(true, (int)ushort.MaxValue + 1))); } [Fact] @@ -516,7 +516,7 @@ public void AcceptAsync_BufferList_Throws_Argument() BufferList = s_buffers }; - AssertExtensions.Throws("BufferList", () => GetSocket().AcceptAsync(eventArgs)); + AssertExtensions.Throws("e", () => GetSocket().AcceptAsync(eventArgs)); } [Fact] @@ -598,13 +598,13 @@ public void ConnectAsync_Static_BufferList_Throws_Argument() BufferList = s_buffers }; - AssertExtensions.Throws("BufferList", () => Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, eventArgs)); + AssertExtensions.Throws("e", () => Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, eventArgs)); } [Fact] - public void ConnectAsync_Static_NullRemoteEndPoint_Throws_ArgumentNull() + public void ConnectAsync_Static_NullRemoteEndPoint_Throws_ArgumentException() { - Assert.Throws(() => Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, s_eventArgs)); + Assert.Throws("e", () => Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, s_eventArgs)); } [Fact] @@ -620,9 +620,9 @@ public void ReceiveFromAsync_NullAsyncEventArgs_Throws_ArgumentNull() } [Fact] - public void ReceiveFromAsync_NullRemoteEndPoint_Throws_ArgumentNull() + public void ReceiveFromAsync_NullRemoteEndPoint_Throws_ArgumentException() { - Assert.Throws(() => GetSocket().ReceiveFromAsync(s_eventArgs)); + Assert.Throws("e", () => GetSocket().ReceiveFromAsync(s_eventArgs)); } [Fact] @@ -632,7 +632,7 @@ public void ReceiveFromAsync_AddressFamily_Throws_Argument() RemoteEndPoint = new IPEndPoint(IPAddress.IPv6Loopback, 1) }; - AssertExtensions.Throws("RemoteEndPoint", () => GetSocket(AddressFamily.InterNetwork).ReceiveFromAsync(eventArgs)); + AssertExtensions.Throws("e", () => GetSocket(AddressFamily.InterNetwork).ReceiveFromAsync(eventArgs)); } [Fact] @@ -642,9 +642,9 @@ public void ReceiveMessageFromAsync_NullAsyncEventArgs_Throws_ArgumentNull() } [Fact] - public void ReceiveMessageFromAsync_NullRemoteEndPoint_Throws_ArgumentNull() + public void ReceiveMessageFromAsync_NullRemoteEndPoint_Throws_ArgumentException() { - Assert.Throws(() => GetSocket().ReceiveMessageFromAsync(s_eventArgs)); + Assert.Throws("e", () => GetSocket().ReceiveMessageFromAsync(s_eventArgs)); } [Fact] @@ -654,7 +654,7 @@ public void ReceiveMessageFromAsync_AddressFamily_Throws_Argument() RemoteEndPoint = new IPEndPoint(IPAddress.IPv6Loopback, 1) }; - AssertExtensions.Throws("RemoteEndPoint", () => GetSocket(AddressFamily.InterNetwork).ReceiveMessageFromAsync(eventArgs)); + AssertExtensions.Throws("e", () => GetSocket(AddressFamily.InterNetwork).ReceiveMessageFromAsync(eventArgs)); } [Fact] @@ -670,9 +670,9 @@ public void SendPacketsAsync_NullAsyncEventArgs_Throws_ArgumentNull() } [Fact] - public void SendPacketsAsync_NullSendPacketsElements_Throws_ArgumentNull() + public void SendPacketsAsync_NullSendPacketsElements_Throws_ArgumentException() { - Assert.Throws(() => GetSocket().SendPacketsAsync(s_eventArgs)); + Assert.Throws("e", () => GetSocket().SendPacketsAsync(s_eventArgs)); } [Fact] @@ -694,7 +694,7 @@ public void SendToAsync_NullAsyncEventArgs_Throws_ArgumentNull() [Fact] public void SendToAsync_NullRemoteEndPoint_Throws_ArgumentNull() { - Assert.Throws(() => GetSocket().SendToAsync(s_eventArgs)); + Assert.Throws(() => GetSocket().SendToAsync(s_eventArgs)); } [Theory] @@ -1114,7 +1114,14 @@ public void BeginConnect_IPAddresses_EmptyIPAddresses_Throws_Argument() public void BeginConnect_IPAddresses_InvalidPort_Throws_ArgumentOutOfRange(int port) { Assert.Throws(() => GetSocket().BeginConnect(new[] { IPAddress.Loopback }, port, TheAsyncCallback, null)); - Assert.Throws(() => { GetSocket().ConnectAsync(new[] { IPAddress.Loopback }, port); }); + } + + [Theory] + [InlineData(-1)] + [InlineData(65536)] + public async Task ConnectAsync_IPAddresses_InvalidPort_Throws_ArgumentOutOfRange(int port) + { + await Assert.ThrowsAsync(() => GetSocket().ConnectAsync(new[] { IPAddress.Loopback }, port)); } [Fact] @@ -1126,12 +1133,16 @@ public void BeginConnect_IPAddresses_ListeningSocket_Throws_InvalidOperation() socket.Listen(1); Assert.Throws(() => socket.BeginConnect(new[] { IPAddress.Loopback }, 1, TheAsyncCallback, null)); } + } + [Fact] + public async Task ConnectAsync_IPAddresses_ListeningSocket_Throws_InvalidOperation() + { using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { socket.Bind(new IPEndPoint(IPAddress.Loopback, 0)); socket.Listen(1); - Assert.Throws(() => { socket.ConnectAsync(new[] { IPAddress.Loopback }, 1); }); + await Assert.ThrowsAsync(() => socket.ConnectAsync(new[] { IPAddress.Loopback }, 1)); } } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs index 6f01d22ca57bb1..d4bdcfed80a0f6 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs @@ -125,9 +125,6 @@ public async Task Connect_AfterDisconnect_Fails() [PlatformSpecific(~(TestPlatforms.OSX | TestPlatforms.FreeBSD))] // Not supported on BSD like OSes. public async Task ConnectGetsCanceledByDispose() { - bool usesApm = UsesApm || - (this is ConnectTask); // .NET Core ConnectAsync Task API is implemented using Apm - // We try this a couple of times to deal with a timing race: if the Dispose happens // before the operation is started, we won't see a SocketException. int msDelay = 100; @@ -167,7 +164,7 @@ await RetryHelper.ExecuteAsync(async () => disposedException = true; } - if (usesApm) + if (UsesApm) { Assert.Null(localSocketError); Assert.True(disposedException); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs index 86e1b2dea2fc6d..56d07d546a6d8f 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs @@ -5,15 +5,24 @@ using System.Diagnostics; using System.IO; using System.IO.Pipes; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.DotNet.RemoteExecutor; using Xunit; +using Xunit.Abstractions; namespace System.Net.Sockets.Tests { public class CreateSocket { + readonly ITestOutputHelper _output; + + public CreateSocket(ITestOutputHelper output) + { + _output = output; + } + public static object[][] DualModeSuccessInputs = { new object[] { SocketType.Stream, ProtocolType.Tcp }, new object[] { SocketType.Dgram, ProtocolType.Udp }, @@ -310,6 +319,7 @@ public void Ctor_SafeHandle_BasicPropertiesPropagate_Success(AddressFamily addre break; } } + Assert.Null(copy.RemoteEndPoint); } else { @@ -323,7 +333,7 @@ public void Ctor_SafeHandle_BasicPropertiesPropagate_Success(AddressFamily addre Assert.Equal(addressFamily, copy.AddressFamily); Assert.Equal(socketType, copy.SocketType); - Assert.True(copy.ProtocolType == orig.ProtocolType || copy.ProtocolType == ProtocolType.Unknown, $"Expected: {protocolType} or Unknown, Actual: {copy.ProtocolType}"); + Assert.Equal(protocolType, copy.ProtocolType); Assert.True(orig.Blocking); Assert.True(copy.Blocking); @@ -367,7 +377,7 @@ public async Task Ctor_SafeHandle_Tcp_SendReceive_Success(AddressFamily addressF Assert.True(client.Connected); Assert.Equal(orig.AddressFamily, client.AddressFamily); Assert.Equal(orig.SocketType, client.SocketType); - Assert.True(client.ProtocolType == orig.ProtocolType || client.ProtocolType == ProtocolType.Unknown, $"Expected: {protocolType} or Unknown, Actual: {client.ProtocolType}"); + Assert.Equal(orig.ProtocolType, client.ProtocolType); // Validate accessing end points Assert.Equal(orig.LocalEndPoint, client.LocalEndPoint); @@ -409,7 +419,6 @@ public async Task Ctor_SafeHandle_Tcp_SendReceive_Success(AddressFamily addressF Assert.Equal(42, buffer[0]); } - [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.Linux)] // OSX/FreeBSD doesn't support SO_ACCEPTCONN, so we can't query for whether a socket is listening [Theory] [InlineData(false)] [InlineData(true)] @@ -418,16 +427,17 @@ public async Task Ctor_SafeHandle_Listening_Success(bool shareSafeHandle) using var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); listener.Bind(new IPEndPoint(IPAddress.Loopback, 0)); listener.Listen(); - Assert.Equal(1, listener.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.AcceptConnection)); using var listenerCopy = new Socket(shareSafeHandle ? listener.SafeHandle : new SafeSocketHandle(listener.Handle, ownsHandle: false)); - Assert.Equal(1, listenerCopy.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.AcceptConnection)); + Assert.False(listenerCopy.Connected); + // This will throw if _isListening is set internally. (before reaching any real code) + Assert.Throws(() => listenerCopy.Connect(new IPEndPoint(IPAddress.Loopback,0))); Assert.Equal(listener.AddressFamily, listenerCopy.AddressFamily); Assert.Equal(listener.Handle, listenerCopy.Handle); Assert.Equal(listener.IsBound, listenerCopy.IsBound); - Assert.Equal(listener.LocalEndPoint, listener.LocalEndPoint); - Assert.True(listenerCopy.ProtocolType == listener.ProtocolType || listenerCopy.ProtocolType == ProtocolType.Unknown, $"Expected: {listener.ProtocolType} or Unknown, Actual: {listenerCopy.ProtocolType}"); + Assert.Equal(listener.LocalEndPoint, listenerCopy.LocalEndPoint); + Assert.Equal(listener.ProtocolType, listenerCopy.ProtocolType); Assert.Equal(listener.SocketType, listenerCopy.SocketType); foreach (Socket listenerSocket in new[] { listener, listenerCopy }) @@ -445,6 +455,191 @@ public async Task Ctor_SafeHandle_Listening_Success(bool shareSafeHandle) } } + [DllImport("libc")] + private static extern int socket(int domain, int type, int protocol); + + private const int PF_NETLINK = 16; + + private class NlEndPoint : EndPoint + { + [StructLayout(LayoutKind.Sequential)] + internal struct sockaddr_nl + { + internal ushort sin_family; + private ushort pad; + internal int pid; + private int nl_groups; + } + + private readonly int _pid; + + public NlEndPoint(int pid) + { + _pid = pid; + } + + public override AddressFamily AddressFamily + { + get + { + return AddressFamily.Unknown; + } + } + + public class NlSocketAddress : SocketAddress + { + // We need to create base from something known. + public unsafe NlSocketAddress(int pid) : base(AddressFamily.Packet) + { + sockaddr_nl addr = default; + + addr.sin_family = PF_NETLINK; + addr.pid = pid; + + var bytes = new ReadOnlySpan(&addr, sizeof(sockaddr_nl)); + + for (int i = 0; i < bytes.Length; i++) + { + this[i] = bytes[i]; + } + } + } + + public override SocketAddress Serialize() + { + SocketAddress a = (SocketAddress)new NlSocketAddress(_pid); + return a; + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct nlmsghdr + { + internal int nlmsg_len; /* Length of message including header */ + internal ushort nlmsg_type; /* Type of message content */ + internal ushort nlmsg_flags; /* Additional flags */ + internal int nlmsg_seq; /* Sequence number */ + internal uint nlmsg_pid; /* Sender port ID */ + }; + + [StructLayout(LayoutKind.Sequential)] + private struct nlmsgerr { + internal int error; + internal nlmsghdr msg; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct rtmsg + { + internal byte rtm_family; + internal byte rtm_dst_len; + internal byte rtm_src_len; + internal byte rtm_tos; + + internal byte rtm_table; + internal byte rtm_protocol; + internal byte rtm_scope; + internal byte rtm_type; + + internal uint rtm_flags; + } + + [StructLayout(LayoutKind.Sequential)] + private unsafe struct nl_request + { + internal nlmsghdr nlh; + internal rtmsg rtm; + } + + [Fact] + [PlatformSpecific(TestPlatforms.Linux)] + public unsafe void Ctor_SafeHandle_UnknownSocket_Success() + { + const int PF_INET = 2; + const int NETLINK_ROUTE = 0; + const int SOCK_DGRAM = 2; + const int RTM_NEWROUTE = 24; + const int RTM_GETROUTE = 26; + const int NLM_F_REQUEST = 1; + const int NLM_F_DUMP = 0x300; + const int NLMSG_ERROR = 2; + const int SEQ = 42; + + int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + Assert.InRange(fd, 0, int.MaxValue); + using (Socket netlink = new Socket(new SafeSocketHandle((IntPtr)fd, ownsHandle: true))) + { + Assert.Equal(AddressFamily.Unknown, netlink.AddressFamily); + + netlink.Bind(new NlEndPoint(Process.GetCurrentProcess().Id)); + + nl_request req = default; + req.nlh.nlmsg_pid = (uint)Process.GetCurrentProcess().Id; + req.nlh.nlmsg_type = RTM_GETROUTE; /* We wish to get routes */ + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + req.nlh.nlmsg_len = sizeof(nl_request); + req.nlh.nlmsg_seq = SEQ; + req.rtm.rtm_family = PF_INET; + + netlink.Send(new ReadOnlySpan(Unsafe.AsPointer(ref req), sizeof(nl_request))); + + Assert.True(netlink.Poll(TestSettings.PassingTestTimeout, SelectMode.SelectRead)); + + byte[] response = new byte[4000]; + int readBytes = netlink.Receive(response); + // We should get at least header. + Assert.True(readBytes > sizeof(nlmsghdr)); + + MemoryMarshal.TryRead(response.AsSpan(), out nlmsghdr nlh); + Assert.Equal(SEQ, nlh.nlmsg_seq); + + if (nlh.nlmsg_type == NLMSG_ERROR) + { + MemoryMarshal.TryRead(response.AsSpan().Slice(sizeof(nlmsghdr)), out nlmsgerr err); + _output.WriteLine("Netlink request failed with {0}", err.error); + } + + Assert.Equal(RTM_NEWROUTE, nlh.nlmsg_type); + } + } + + + [DllImport("libc")] + private static unsafe extern int socketpair(int domain, int type, int protocol, int* ptr); + + [DllImport("libc")] + private static extern int close(int fd); + + [Fact] + [PlatformSpecific(TestPlatforms.AnyUnix)] + public unsafe void Ctor_SafeHandle_SocketPair_Success() + { + // This is platform dependent but it seems like this is same on all supported platforms. + const int AF_UNIX = 1; + const int SOCK_STREAM = 1; + Span ptr = stackalloc int[2]; + + fixed (int* bufferPtr = ptr) + { + int result = socketpair(AF_UNIX, SOCK_STREAM, 0, bufferPtr); + Assert.Equal(0, result); + } + + for (int i = 0; i <= 1; i++) + { + Assert.InRange(ptr[0], 0, int.MaxValue); + Socket s = new Socket(new SafeSocketHandle((IntPtr)ptr[i], ownsHandle: false)); + + Assert.True(s.Connected); + Assert.Equal(AddressFamily.Unix, s.AddressFamily); + Assert.Equal(SocketType.Stream, s.SocketType); + Assert.Equal(ProtocolType.Unspecified, s.ProtocolType); + } + + close(ptr[0]); + close(ptr[1]); + } + private static void AssertEqualOrSameException(Func expected, Func actual) { T r1 = default, r2 = default; diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/DisposedSocketTests.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/DisposedSocketTests.cs index e15249c19c3bef..ee81d7cdf81ac0 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/DisposedSocketTests.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/DisposedSocketTests.cs @@ -751,6 +751,7 @@ public void EndAccept_Throws_ObjectDisposed() [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsPreciseGcSupported))] [InlineData(false)] [InlineData(true)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/35846", TestPlatforms.AnyUnix)] public async Task NonDisposedSocket_SafeHandlesCollected(bool clientAsync) { List handles = await CreateHandlesAsync(clientAsync); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/DualModeSocketTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/DualModeSocketTest.cs index bb88d9a93806df..e53c90d949f0ae 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/DualModeSocketTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/DualModeSocketTest.cs @@ -1649,7 +1649,7 @@ public void Socket_ReceiveFromAsyncV4IPEndPointFromV4Client_Throws() args.RemoteEndPoint = new IPEndPoint(IPAddress.Loopback, UnusedPort); args.SetBuffer(new byte[1], 0, 1); - AssertExtensions.Throws("RemoteEndPoint", () => + AssertExtensions.Throws("e", () => { socket.ReceiveFromAsync(args); }); @@ -2188,7 +2188,7 @@ public void Socket_ReceiveMessageFromAsyncV4IPEndPointFromV4Client_Throws() args.RemoteEndPoint = new IPEndPoint(IPAddress.Loopback, UnusedPort); args.SetBuffer(new byte[1], 0, 1); - AssertExtensions.Throws("RemoteEndPoint", () => + AssertExtensions.Throws("e", () => { socket.ReceiveMessageFromAsync(args); }); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/KeepAliveTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/KeepAliveTest.cs index 6a6e07a962257c..77b41f8e8245a1 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/KeepAliveTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/KeepAliveTest.cs @@ -54,6 +54,7 @@ public void Socket_KeepAlive_RetryCount_Success() } [ConditionalFact(typeof(KeepAliveTest), nameof(IsWindowsBelow1703))] // RetryCount not supported by earlier versions of Windows + [PlatformSpecific(TestPlatforms.Windows)] public void Socket_KeepAlive_RetryCount_Failure() { using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/LingerStateTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/LingerStateTest.cs index c2d98010766af0..80c9c54e8d4281 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/LingerStateTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/LingerStateTest.cs @@ -19,7 +19,7 @@ private void TestLingerState_Success(Socket sock, bool enabled, int lingerTime) private void TestLingerState_ArgumentException(Socket sock, bool enabled, int lingerTime) { - AssertExtensions.Throws("optionValue.LingerTime", () => + AssertExtensions.Throws("optionValue", () => { sock.LingerState = new LingerOption(enabled, lingerTime); }); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendPacketsAsync.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendPacketsAsync.cs index 8c81909054b74c..3406be95327374 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendPacketsAsync.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendPacketsAsync.cs @@ -111,7 +111,7 @@ public void NotConnected_Throw() [InlineData(SocketImplementationType.Async)] public void NullList_Throws(SocketImplementationType type) { - AssertExtensions.Throws("e.SendPacketsElements", () => SendPackets(type, (SendPacketsElement[])null, SocketError.Success, 0)); + AssertExtensions.Throws("e", () => SendPackets(type, (SendPacketsElement[])null, SocketError.Success, 0)); } [OuterLoop] diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendTo.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendTo.cs index c767e30b8f143a..d10c8775582775 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendTo.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendTo.cs @@ -47,7 +47,7 @@ public async Task NullEndpoint_Throws() { using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - await Assert.ThrowsAsync(() => SendToAsync(socket, new byte[1], null)); + await Assert.ThrowsAnyAsync(() => SendToAsync(socket, new byte[1], null)); } [Fact] diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs index de05418d9c696b..064a9548b60a8a 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs @@ -558,6 +558,21 @@ public void GetSetRawSocketOption_Roundtrips(AddressFamily family) Assert.Equal(ExpectedGetSize, socket.ReceiveBufferSize); } } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsSubsystemForLinux))] // [ActiveIssue("https://github.com/dotnet/runtime/issues/18258")] + public void Get_AcceptConnection_Succeeds() + { + using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + Assert.Equal(0, s.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.AcceptConnection)); + + s.Bind(new IPEndPoint(IPAddress.Loopback, 0)); + s.Listen(); + + Assert.Equal(1, s.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.AcceptConnection)); + } + } + } [Collection("NoParallelTests")] diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj b/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj index 7d1142099157c0..ab01170df35f44 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj @@ -47,63 +47,44 @@ - - SocketCommon\Configuration.cs - - - SocketCommon\Configuration.Sockets.cs - - - SocketCommon\TestSettings.cs - - - SocketCommon\Fletcher32.cs - - - SocketCommon\SocketTestExtensions.cs - - - SocketCommon\SocketTestServer.cs - - - SocketCommon\SocketTestServerAsync.cs - - - SocketCommon\SocketTestServerAPM.cs - - - SocketCommon\SocketImplementationType.cs - + + + + + + + + + - - Common\System\Net\TestLogging.cs - - - Common\System\Net\VerboseTestLogging.cs - - - Common\System\Net\EventSourceTestLogging.cs - - - Common\System\Net\Capability.Sockets.cs - - - Common\System\ShouldNotBeInvokedException.cs - - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - - - Common\System\Buffers\NativeMemoryManager.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - - - Common\System\Diagnostics\Tracing\TestEventListener.cs - - - Common\System\Net\Logging\NetEventSource.Common.cs - + + + + + + + + + + \ No newline at end of file diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs index 5be7b946a549ff..45a40c4a424c3e 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs @@ -429,12 +429,12 @@ public async Task Dispose_CancelsConnectAsync(bool connectByName) // There is a race condition here. If the connection succeeds before the // disposal, then the task will complete successfully. Otherwise, it should - // fail with an ObjectDisposedException. + // fail with an exception. try { await connectTask; } - catch (ObjectDisposedException) { } + catch (SocketException e) when (e.SocketErrorCode == SocketError.OperationAborted) { } sw.Stop(); Assert.Null(client.Client); // should be nulled out after Dispose diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs index 02be71a5e2f518..6c9473d280a8f8 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs @@ -125,8 +125,11 @@ public void Accept_Invalid_Throws() AssertExtensions.Throws("asyncResult", () => listener.EndAcceptTcpClient(Task.CompletedTask)); } - [Fact] - public async Task Accept_AcceptsPendingSocketOrClient() + [Theory] + [InlineData(0)] // Sync + [InlineData(1)] // Async + [InlineData(2)] // APM + public async Task Accept_AcceptsPendingSocketOrClient(int mode) { var listener = new TcpListener(IPAddress.Loopback, 0); listener.Start(); @@ -134,7 +137,12 @@ public async Task Accept_AcceptsPendingSocketOrClient() using (var client = new TcpClient()) { Task connectTask = client.ConnectAsync(IPAddress.Loopback, ((IPEndPoint)listener.LocalEndpoint).Port); - using (Socket s = listener.AcceptSocket()) + using (Socket s = mode switch + { + 0 => listener.AcceptSocket(), + 1 => await listener.AcceptSocketAsync(), + _ => await Task.Factory.FromAsync(listener.BeginAcceptSocket, listener.EndAcceptSocket, null), + }) { Assert.False(listener.Pending()); } @@ -144,7 +152,12 @@ public async Task Accept_AcceptsPendingSocketOrClient() using (var client = new TcpClient()) { Task connectTask = client.ConnectAsync(IPAddress.Loopback, ((IPEndPoint)listener.LocalEndpoint).Port); - using (TcpClient c = listener.AcceptTcpClient()) + using (TcpClient c = mode switch + { + 0 => listener.AcceptTcpClient(), + 1 => await listener.AcceptTcpClientAsync(), + _ => await Task.Factory.FromAsync(listener.BeginAcceptTcpClient, listener.EndAcceptTcpClient, null), + }) { Assert.False(listener.Pending()); } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs index 3e5e7d9d64e417..34654c50b39e1a 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs @@ -10,11 +10,20 @@ using System.Threading.Tasks; using Xunit; +using Xunit.Abstractions; namespace System.Net.Sockets.Tests { public class UnixDomainSocketTest { + private readonly ITestOutputHelper _log; + private static Random _random = new Random(); + + public UnixDomainSocketTest(ITestOutputHelper output) + { + _log = output; + } + [Fact] public void OSSupportsUnixDomainSockets_ReturnsCorrectValue() { @@ -166,6 +175,11 @@ public void Socket_SendReceive_Clone_Success() using var clientClone = new Socket(client.SafeHandle); using var acceptedClone = new Socket(accepted.SafeHandle); + _log.WriteLine($"accepted: LocalEndPoint={accepted.LocalEndPoint} RemoteEndPoint={accepted.RemoteEndPoint}"); + _log.WriteLine($"acceptedClone: LocalEndPoint={acceptedClone.LocalEndPoint} RemoteEndPoint={acceptedClone.RemoteEndPoint}"); + + Assert.True(clientClone.Connected); + Assert.True(acceptedClone.Connected); Assert.Equal(client.LocalEndPoint.ToString(), clientClone.LocalEndPoint.ToString()); Assert.Equal(client.RemoteEndPoint.ToString(), clientClone.RemoteEndPoint.ToString()); Assert.Equal(accepted.LocalEndPoint.ToString(), acceptedClone.LocalEndPoint.ToString()); @@ -470,6 +484,7 @@ public void UnixDomainSocketEndPoint_UsingAbstractSocketAddressOnUnsupported_Thr } [ConditionalFact(nameof(IsSubWindows10))] + [PlatformSpecific(TestPlatforms.Windows)] public void Socket_CreateUnixDomainSocket_Throws_OnWindows() { AssertExtensions.Throws("path", () => new UnixDomainSocketEndPoint(null)); @@ -483,7 +498,8 @@ private static string GetRandomNonExistingFilePath() string result; do { - result = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + // get random name and append random number of characters to get variable name length. + result = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + new string('A', _random.Next(1, 32))); } while (File.Exists(result)); diff --git a/src/libraries/System.Net.WebClient/src/System.Net.WebClient.csproj b/src/libraries/System.Net.WebClient/src/System.Net.WebClient.csproj index 282b766f7fcb36..525298aa6f339b 100644 --- a/src/libraries/System.Net.WebClient/src/System.Net.WebClient.csproj +++ b/src/libraries/System.Net.WebClient/src/System.Net.WebClient.csproj @@ -6,24 +6,18 @@ - - Common\System\IO\DelegatingStream.cs - - - Common\System\IO\ChunkedMemoryStream.cs - - - Common\System\Threading\Tasks\BeginEndAwaitableAdapter.cs - - - Common\System\Threading\Tasks\RendezvousAwaitable.cs - - - Common\System\Net\HttpKnownHeaderNames.cs - - - Common\System\HexConverter.cs - + + + + + + diff --git a/src/libraries/System.Net.WebClient/tests/System.Net.WebClient.Tests.csproj b/src/libraries/System.Net.WebClient/tests/System.Net.WebClient.Tests.csproj index b011f8361e954f..140cbb8132dd0b 100644 --- a/src/libraries/System.Net.WebClient/tests/System.Net.WebClient.Tests.csproj +++ b/src/libraries/System.Net.WebClient/tests/System.Net.WebClient.Tests.csproj @@ -6,29 +6,21 @@ - - Common\System\Net\Capability.Security.cs - - - Common\System\Net\Configuration.cs - - - Common\System\Net\Configuration.Certificates.cs - - - Common\System\Net\Configuration.Http.cs - - - Common\System\Net\Configuration.Security.cs - - - Common\System\Net\Http\LoopbackServer.cs - - - Common\System\Net\Http\GenericLoopbackServer.cs - - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - + + + + + + + + - \ No newline at end of file + diff --git a/src/libraries/System.Net.WebHeaderCollection/ref/System.Net.WebHeaderCollection.cs b/src/libraries/System.Net.WebHeaderCollection/ref/System.Net.WebHeaderCollection.cs index f4aa1444be2515..0cdc475f1a94aa 100644 --- a/src/libraries/System.Net.WebHeaderCollection/ref/System.Net.WebHeaderCollection.cs +++ b/src/libraries/System.Net.WebHeaderCollection/ref/System.Net.WebHeaderCollection.cs @@ -97,7 +97,9 @@ protected WebHeaderCollection(System.Runtime.Serialization.SerializationInfo ser public void Add(System.Net.HttpRequestHeader header, string? value) { } public void Add(System.Net.HttpResponseHeader header, string? value) { } public void Add(string header) { } +#pragma warning disable CS8765 // Nullability of parameter 'name' doesn't match overridden member public override void Add(string name, string? value) { } +#pragma warning restore CS8765 protected void AddWithoutValidate(string headerName, string? headerValue) { } public override void Clear() { } public override string? Get(int index) { throw null; } @@ -106,16 +108,22 @@ public override void Clear() { } public override string GetKey(int index) { throw null; } public override void GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } public override string[]? GetValues(int index) { throw null; } +#pragma warning disable CS8765 // Nullability of parameter 'header' doesn't match overridden member public override string[]? GetValues(string header) { throw null; } +#pragma warning restore CS8765 public static bool IsRestricted(string headerName) { throw null; } public static bool IsRestricted(string headerName, bool response) { throw null; } public override void OnDeserialization(object? sender) { } public void Remove(System.Net.HttpRequestHeader header) { } public void Remove(System.Net.HttpResponseHeader header) { } +#pragma warning disable CS8765 // Nullability of parameter 'name' doesn't match overridden member public override void Remove(string name) { } +#pragma warning restore CS8765 public void Set(System.Net.HttpRequestHeader header, string? value) { } public void Set(System.Net.HttpResponseHeader header, string? value) { } +#pragma warning disable CS8765 // Nullability of parameter 'name' doesn't match overridden member public override void Set(string name, string? value) { } +#pragma warning restore CS8765 void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } public byte[] ToByteArray() { throw null; } public override string ToString() { throw null; } diff --git a/src/libraries/System.Net.WebHeaderCollection/src/System.Net.WebHeaderCollection.csproj b/src/libraries/System.Net.WebHeaderCollection/src/System.Net.WebHeaderCollection.csproj index e7d45fd91bcca9..5fd0e9acb783c0 100644 --- a/src/libraries/System.Net.WebHeaderCollection/src/System.Net.WebHeaderCollection.csproj +++ b/src/libraries/System.Net.WebHeaderCollection/src/System.Net.WebHeaderCollection.csproj @@ -12,21 +12,16 @@ - - Common\System\Net\CaseInsensitiveAscii.cs - - - Common\System\StringExtensions.cs - - - Common\System\Net\HttpKnownHeaderNames.cs - - - Common\System\Net\HttpValidationHelpers.cs - - - Common\System\Net\Logging\NetEventSource.Common.cs - + + + + + diff --git a/src/libraries/System.Net.WebHeaderCollection/src/System/Net/WebHeaderCollection.cs b/src/libraries/System.Net.WebHeaderCollection/src/System/Net/WebHeaderCollection.cs index 875caac4c46fd7..2214534a9d5ab6 100644 --- a/src/libraries/System.Net.WebHeaderCollection/src/System/Net/WebHeaderCollection.cs +++ b/src/libraries/System.Net.WebHeaderCollection/src/System/Net/WebHeaderCollection.cs @@ -132,9 +132,9 @@ public string? this[HttpResponseHeader header] } } -#pragma warning disable CS8610 // Nullability of parameter 'name' doesn't match overridden member +#pragma warning disable CS8765 // Nullability of parameter 'name' doesn't match overridden member public override void Set(string name, string? value) -#pragma warning restore CS8610 +#pragma warning restore CS8765 { if (string.IsNullOrEmpty(name)) { @@ -241,9 +241,9 @@ public static bool IsRestricted(string headerName, bool response) // header - Name of the header. // Return Value: // string[] - array of parsed string objects -#pragma warning disable CS8610 // Nullability of parameter 'header' doesn't match overridden member +#pragma warning disable CS8765 // Nullability of parameter 'header' doesn't match overridden member public override string[]? GetValues(string header) -#pragma warning restore CS8610 +#pragma warning restore CS8765 { // First get the information about the header and the values for // the header. @@ -378,16 +378,16 @@ public void Add(string header) { if (value != null && value.Length > ushort.MaxValue) { - throw new ArgumentOutOfRangeException(nameof(value), value, SR.Format(CultureInfo.InvariantCulture, SR.net_headers_toolong, ushort.MaxValue)); + throw new ArgumentOutOfRangeException(nameof(header), value, SR.Format(CultureInfo.InvariantCulture, SR.net_headers_toolong, ushort.MaxValue)); } } InvalidateCachedArrays(); InnerCollection.Add(name, value); } -#pragma warning disable CS8610 // Nullability of parameter 'name' doesn't match overridden member +#pragma warning disable CS8765 // Nullability of parameter 'name' doesn't match overridden member public override void Add(string name, string? value) -#pragma warning restore CS8610 +#pragma warning restore CS8765 { if (name == null) { @@ -460,9 +460,9 @@ internal void ThrowOnRestrictedHeader(string headerName) /// /// Removes the specified header. /// -#pragma warning disable CS8610 // Nullability of parameter 'name' doesn't match overridden member +#pragma warning disable CS8765 // Nullability of parameter 'name' doesn't match overridden member public override void Remove(string name) -#pragma warning restore CS8610 +#pragma warning restore CS8765 { if (string.IsNullOrEmpty(name)) { diff --git a/src/libraries/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj b/src/libraries/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj index 60ee641776b69b..cfed5c7b931139 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj +++ b/src/libraries/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj @@ -10,22 +10,17 @@ - - Common\System\Net\Logging\NetEventSource.Common.cs - - - Common\System\Net\UriScheme.cs - - - Common\System\Net\WebSockets\WebSocketValidate.cs - + + + - - Common\System\Net\HttpKnownHeaderNames.cs - - - Common\System\Net\SecurityProtocol.cs - + + @@ -54,4 +49,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Net.WebSockets.Client/tests/CancelTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/CancelTest.cs index 30cd92e70e910a..434ced69d47dcf 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/CancelTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/CancelTest.cs @@ -75,7 +75,7 @@ public async Task CloseAsync_Cancel_Success(Uri server) await TestCancellation(async (cws) => { var ctsDefault = new CancellationTokenSource(TimeOutMilliseconds); - var cts = new CancellationTokenSource(5); + var cts = new CancellationTokenSource(TimeOutMilliseconds); await cws.SendAsync( WebSocketData.GetBufferFromText(".delay5sec"), @@ -97,7 +97,7 @@ public async Task CloseOutputAsync_Cancel_Success(Uri server) await TestCancellation(async (cws) => { - var cts = new CancellationTokenSource(5); + var cts = new CancellationTokenSource(TimeOutMilliseconds); var ctsDefault = new CancellationTokenSource(TimeOutMilliseconds); await cws.SendAsync( diff --git a/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs index 918c5e6d086a96..c0774aa1298fde 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using System.Diagnostics; using System.Net.Test.Common; using System.Text; using System.Threading; @@ -324,5 +325,47 @@ public async Task CloseAsync_DuringConcurrentReceiveAsync_ExpectedStates(Uri ser } } } + + [ConditionalFact(nameof(WebSocketsSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] + public async Task CloseAsync_CancelableEvenWhenPendingReceive_Throws() + { + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + await LoopbackServer.CreateClientAndServerAsync(async uri => + { + try + { + using (var cws = new ClientWebSocket()) + using (var cts = new CancellationTokenSource(TimeOutMilliseconds)) + { + await cws.ConnectAsync(uri, cts.Token); + + Task receiveTask = cws.ReceiveAsync(new byte[1], CancellationToken.None); + + var cancelCloseCts = new CancellationTokenSource(); + await Assert.ThrowsAnyAsync(async () => + { + Task t = cws.CloseAsync(WebSocketCloseStatus.NormalClosure, null, cancelCloseCts.Token); + cancelCloseCts.Cancel(); + await t; + }); + + await Assert.ThrowsAnyAsync(() => receiveTask); + } + } + finally + { + tcs.SetResult(true); + } + }, server => server.AcceptConnectionAsync(async connection => + { + Dictionary headers = await LoopbackHelper.WebSocketHandshakeAsync(connection); + Assert.NotNull(headers); + + await tcs.Task; + + }), new LoopbackServer.Options { WebSocketEndpoint = true }); + } } } diff --git a/src/libraries/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj b/src/libraries/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj index d685d7b270d7f2..3b7eb276d0e9c3 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj +++ b/src/libraries/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj @@ -9,39 +9,28 @@ - - Common\System\Net\Capability.Security.cs - - - Common\System\Net\Configuration.cs - - - Common\System\Net\Configuration.Certificates.cs - - - Common\System\Net\Configuration.Http.cs - - - Common\System\Net\Configuration.Security.cs - - - Common\System\Net\Configuration.WebSockets.cs - - - Common\System\Net\EventSourceTestLogging.cs - - - Common\System\Net\Http\LoopbackProxyServer.cs - - - Common\System\Net\Http\LoopbackServer.cs - - - Common\System\Net\Http\GenericLoopbackServer.cs - - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - + + + + + + + + + + + @@ -60,4 +49,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Net.WebSockets.WebSocketProtocol/src/System.Net.WebSockets.WebSocketProtocol.csproj b/src/libraries/System.Net.WebSockets.WebSocketProtocol/src/System.Net.WebSockets.WebSocketProtocol.csproj index 81bfe86e00cd77..a85b95b6c768d6 100644 --- a/src/libraries/System.Net.WebSockets.WebSocketProtocol/src/System.Net.WebSockets.WebSocketProtocol.csproj +++ b/src/libraries/System.Net.WebSockets.WebSocketProtocol/src/System.Net.WebSockets.WebSocketProtocol.csproj @@ -8,12 +8,10 @@ annotations - - Common\System\Net\WebSockets\ManagedWebSocket.cs - - - Common\System\Net\WebSockets\WebSocketValidate.cs - + + @@ -21,7 +19,7 @@ - + @@ -42,4 +40,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Net.WebSockets.WebSocketProtocol/tests/System.Net.WebSockets.WebSocketProtocol.Tests.csproj b/src/libraries/System.Net.WebSockets.WebSocketProtocol/tests/System.Net.WebSockets.WebSocketProtocol.Tests.csproj index 733a9034568525..eb4d89c4de15c4 100644 --- a/src/libraries/System.Net.WebSockets.WebSocketProtocol/tests/System.Net.WebSockets.WebSocketProtocol.Tests.csproj +++ b/src/libraries/System.Net.WebSockets.WebSocketProtocol/tests/System.Net.WebSockets.WebSocketProtocol.Tests.csproj @@ -3,18 +3,14 @@ $(NetCoreAppCurrent);$(NetFrameworkCurrent) - - Common\System\Net\WebSockets\WebSocketCreateTest.cs - - - Common\System\Net\Configuration.cs - - - Common\System\Net\Configuration.WebSockets.cs - - - Common\System\Net\HttpKnownHeaderNames.cs - + + + + - \ No newline at end of file + diff --git a/src/libraries/System.Net.WebSockets/src/System.Net.WebSockets.csproj b/src/libraries/System.Net.WebSockets/src/System.Net.WebSockets.csproj index 06f9a2cf0c80bb..40ce98387e9db6 100644 --- a/src/libraries/System.Net.WebSockets/src/System.Net.WebSockets.csproj +++ b/src/libraries/System.Net.WebSockets/src/System.Net.WebSockets.csproj @@ -17,12 +17,10 @@ - - Common\System\Net\WebSockets\WebSocketValidate.cs - - - Common\System\Net\WebSockets\ManagedWebSocket.cs - + + @@ -38,4 +36,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Net.WebSockets/tests/System.Net.WebSockets.Tests.csproj b/src/libraries/System.Net.WebSockets/tests/System.Net.WebSockets.Tests.csproj index 453ddb8ea157a2..be4a5cfccf8fce 100644 --- a/src/libraries/System.Net.WebSockets/tests/System.Net.WebSockets.Tests.csproj +++ b/src/libraries/System.Net.WebSockets/tests/System.Net.WebSockets.Tests.csproj @@ -6,17 +6,13 @@ - - Common\System\Net\WebSockets\WebSocketCreateTest.cs - - - Common\System\Net\Configuration.cs - - - Common\System\Net\Configuration.WebSockets.cs - - - Common\System\Net\HttpKnownHeaderNames.cs - + + + + - \ No newline at end of file + diff --git a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.csproj b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.csproj index 4f65c31e1ce46c..ef145e7ec407d0 100644 --- a/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.csproj +++ b/src/libraries/System.Numerics.Tensors/ref/System.Numerics.Tensors.csproj @@ -1,9 +1,10 @@ netstandard2.0;netstandard1.1 - true + + true diff --git a/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj b/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj index d56053cbd493f0..5548e9a52d3793 100644 --- a/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj +++ b/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj @@ -2,10 +2,10 @@ true netstandard2.0;netstandard1.1 - true - System.Numerics.Tensors + + true diff --git a/src/libraries/System.Numerics.Vectors/tests/Matrix4x4Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Matrix4x4Tests.cs index 4c6fa0c0637d31..fc82fb83850f01 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Matrix4x4Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Matrix4x4Tests.cs @@ -219,6 +219,23 @@ public void Matrix4x4InvertAffineTest() Assert.True(MathHelper.Equal(i, Matrix4x4.Identity)); } + // A test for Invert (Matrix4x4) + [Fact] + public void Matrix4x4InvertRank3() + { + // A 4x4 Matrix having a rank of 3 + Matrix4x4 mtx = new Matrix4x4(1.0f, 2.0f, 3.0f, 0.0f, + 5.0f, 1.0f, 6.0f, 0.0f, + 8.0f, 9.0f, 1.0f, 0.0f, + 4.0f, 7.0f, 3.0f, 0.0f); + + Matrix4x4 actual; + Assert.False(Matrix4x4.Invert(mtx, out actual)); + + Matrix4x4 i = mtx * actual; + Assert.False(MathHelper.Equal(i, Matrix4x4.Identity)); + } + void DecomposeTest(float yaw, float pitch, float roll, Vector3 expectedTranslation, Vector3 expectedScales) { Quaternion expectedRotation = Quaternion.CreateFromYawPitchRoll(MathHelper.ToRadians(yaw), diff --git a/src/libraries/System.ObjectModel/tests/System.ObjectModel.Tests.csproj b/src/libraries/System.ObjectModel/tests/System.ObjectModel.Tests.csproj index 61d5ca2cc9cbf4..0adc822c3d1e8c 100644 --- a/src/libraries/System.ObjectModel/tests/System.ObjectModel.Tests.csproj +++ b/src/libraries/System.ObjectModel/tests/System.ObjectModel.Tests.csproj @@ -3,24 +3,18 @@ $(NetCoreAppCurrent) - - Common\System\CollectionsIEnumerableTest.cs - - - Common\System\CollectionsICollectionTest.cs - - - Common\System\CollectionsIListTest.cs - - - Common\System\CollectionsUtils.cs - - - Common\System\ShouldNotBeInvokedException.cs - - - Common\System\CollectionsIDictionaryTest.cs - + + + + + + @@ -39,16 +33,14 @@ - - Common\System\Diagnostics\DebuggerAttributes.cs - + - - Common\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/Unsafe.cs b/src/libraries/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/Unsafe.cs index 62649b4c224636..ca63162736745b 100644 --- a/src/libraries/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/Unsafe.cs +++ b/src/libraries/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/Unsafe.cs @@ -8,15 +8,6 @@ using System.Runtime.CompilerServices; using System.Runtime.Versioning; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -using nint = System.Int64; -#else -using nuint = System.UInt32; -using nint = System.Int32; -#endif - // // The implementations of most the methods in this file are provided as intrinsics. // In CoreCLR, the body of the functions are replaced by the EE with unsafe code. See see getILIntrinsicImplementationForUnsafe for details. @@ -145,19 +136,6 @@ public static ref T Add(ref T source, IntPtr elementOffset) #endif } -#if TARGET_64BIT - /// - /// Adds an element offset to the given reference. - /// - [Intrinsic] - [NonVersionable] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ref T Add(ref T source, nint elementOffset) - { - return ref Unsafe.Add(ref source, (IntPtr)(void*)elementOffset); - } -#endif - /// /// Adds an byte offset to the given reference. /// diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index 74ea5902d7e716..c5c6a8603e8dff 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -523,6 +523,9 @@ Object must be of type Int64. + + Object must be of type IntPtr. + Type passed must be an interface. @@ -562,6 +565,9 @@ Object must be of type UInt64. + + Object must be of type UIntPtr. + Object must be of type Version. @@ -1337,7 +1343,7 @@ The specified object must not be an instance of a generic type. - The specified Type must not be a generic type definition. + The specified Type must not be a generic type. The specified Type must be a struct containing no references. @@ -2188,8 +2194,8 @@ Duplicate AttributeUsageAttribute found on attribute type {0}. - - Too many bytes in what should have been a 7 bit encoded Int32. + + Too many bytes in what should have been a 7-bit encoded integer. Invalid digits for the specified base. @@ -2876,7 +2882,7 @@ Collection was of a fixed size. - Generic methods with NativeCallableAttribute are invalid. + Generic methods with UnmanagedCallersOnlyAttribute are invalid. This operation is invalid on overlapping buffers. @@ -2905,20 +2911,23 @@ Module argument must be a ModuleBuilder. - - Methods with NativeCallableAttribute cannot be used as delegate target. + + Methods with UnmanagedCallersOnlyAttribute cannot be used as delegate target. No data is available for encoding {0}. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method. + + Function not marked with UnmanagedCallersOnlyAttribute. + - Non-blittable parameter types are invalid for NativeCallable methods. + Non-blittable parameter types are invalid for UnmanagedCallersOnly methods. Not supported in a non-reflected type. - Non-static methods with NativeCallableAttribute are invalid. + Non-static methods with UnmanagedCallersOnlyAttribute are invalid. Parent does not have a default constructor. The default constructor must be explicitly defined. diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 9d531ff4ff1dc8..61270d5c25e0e8 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -8,6 +8,7 @@ enable + true @@ -193,7 +194,12 @@ + + + + + @@ -240,16 +246,24 @@ + + + + + + + + @@ -261,20 +275,29 @@ + + + + + + + + + @@ -287,6 +310,8 @@ + + @@ -709,7 +734,7 @@ - + @@ -852,6 +877,7 @@ + @@ -976,9 +1002,64 @@ + + Common\Interop\Interop.Libraries.cs + + + Common\Interop\Interop.Calendar.cs + + + Common\Interop\Interop.Casing.cs + + + Common\Interop\Interop.Collation.cs + + + Common\Interop\Interop.ICU.cs + + + Common\Interop\Interop.Idna.cs + + + Common\Interop\Interop.Locale.cs + + + Common\Interop\Interop.Normalization.cs + + + Common\Interop\Interop.ResultCode.cs + + + Common\Interop\Interop.TimeZoneInfo.cs + + + Common\Interop\Interop.Utils.cs + + + Common\Interop\Interop.Errors.cs + + + + Common\Interop\Windows\Interop.BOOL.cs + + + Common\Interop\Windows\Kernel32\Interop.Globalization.cs + + + Common\Interop\Windows\Kernel32\Interop.ResolveLocaleName.cs + + + Common\Interop\Windows\Normaliz\Interop.Idna.cs + + + Common\Interop\Windows\Normaliz\Interop.Normalization.cs + Common\System\HResults.cs + + Common\System\SR.cs + Common\System\Collections\Generic\ReferenceEqualityComparer.cs @@ -1180,9 +1261,6 @@ Common\Interop\Windows\Crypt32\Interop.CryptProtectMemory.cs - - Common\Interop\Windows\Interop.BOOL.cs - Common\Interop\Windows\Interop.BOOLEAN.cs @@ -1297,9 +1375,6 @@ Common\Interop\Windows\Kernel32\Interop.GetTempPathW.cs - - Common\Interop\Windows\Kernel32\Interop.Globalization.cs - Common\Interop\Windows\Kernel32\Interop.GlobalMemoryStatusEx.cs @@ -1348,9 +1423,6 @@ Common\Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_NativeOverlapped.cs - - Common\Interop\Windows\Kernel32\Interop.ResolveLocaleName.cs - Common\Interop\Windows\Kernel32\Interop.SECURITY_ATTRIBUTES.cs @@ -1411,12 +1483,6 @@ Common\Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs - - Common\Interop\Windows\Normaliz\Interop.Idna.cs - - - Common\Interop\Windows\Normaliz\Interop.Normalization.cs - Common\Interop\Windows\NtDll\Interop.NtQueryInformationFile.cs @@ -1471,15 +1537,10 @@ - - - + + - - - - @@ -1513,13 +1574,12 @@ - - + + - Common\Interop\Windows\OleAut32\Interop.SysAllocStringLen.cs @@ -1585,36 +1645,6 @@ Common\Interop\Unix\Interop.Libraries.cs - - Common\Interop\Unix\System.Globalization.Native\Interop.Calendar.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.Casing.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.Collation.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.ICU.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.Idna.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.Locale.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.Normalization.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.ResultCode.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.TimeZoneInfo.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.Utils.cs - Common\Interop\Unix\System.Native\Interop.Access.cs @@ -1727,21 +1757,17 @@ - - - + + + + - - - - - - - + + @@ -1757,6 +1783,14 @@ + + + Common\Interop\OSX\Interop.libobjc.cs + + + Common\Interop\OSX\Interop.Libraries.cs + + @@ -1773,6 +1807,7 @@ + @@ -1790,6 +1825,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs b/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs index 7cd1e8e97a4e8c..19164e5ce634c8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs +++ b/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.IO; using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.Loader; using System.Runtime.Remoting; @@ -386,6 +387,8 @@ public void SetThreadPrincipal(IPrincipal principal) return oh?.Unwrap(); } + [PreserveDependency("GetDefaultInstance", "System.Security.Principal.GenericPrincipal", "System.Security.Claims")] + [PreserveDependency("GetDefaultInstance", "System.Security.Principal.WindowsPrincipal", "System.Security.Principal.Windows")] internal IPrincipal? GetThreadPrincipal() { IPrincipal? principal = _defaultPrincipal; @@ -402,7 +405,7 @@ public void SetThreadPrincipal(IPrincipal principal) // Don't throw PNSE if null like for WindowsPrincipal as UnauthenticatedPrincipal should // be available on all platforms. Volatile.Write(ref s_getUnauthenticatedPrincipal, - (Func)mi.CreateDelegate(typeof(Func))); + mi.CreateDelegate>()); } principal = s_getUnauthenticatedPrincipal(); @@ -418,7 +421,7 @@ public void SetThreadPrincipal(IPrincipal principal) throw new PlatformNotSupportedException(SR.PlatformNotSupported_Principal); } Volatile.Write(ref s_getWindowsPrincipal, - (Func)mi.CreateDelegate(typeof(Func))); + mi.CreateDelegate>()); } principal = s_getWindowsPrincipal(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Array.cs b/src/libraries/System.Private.CoreLib/src/System/Array.cs index 5e22383eb1d815..d3753a1b6bf785 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Array.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Array.cs @@ -7,6 +7,7 @@ using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -26,6 +27,11 @@ public abstract partial class Array : ICloneable, IList, IStructuralComparable, internal const int MaxArrayLength = 0X7FEFFFFF; internal const int MaxByteArrayLength = 0x7FFFFFC7; + // This is the threshold where Introspective sort switches to Insertion sort. + // Empirically, 16 seems to speed up most cases without slowing down others, at least for integers. + // Large value types may benefit from a smaller number. + internal const int IntrosortSizeThreshold = 16; + // This ctor exists solely to prevent C# from generating a protected .ctor that violates the surface area. private protected Array() { } @@ -58,6 +64,8 @@ public static void Resize([NotNull] ref T[]? array, int newSize) Copy(larray, 0, newArray, 0, larray.Length > newSize ? newSize : larray.Length); array = newArray; } + + Debug.Assert(array != null); } public static Array CreateInstance(Type elementType, params long[] lengths) @@ -510,9 +518,7 @@ public static int BinarySearch(Array array, int index, int length, object? value if (comparer == Comparer.Default) { CorElementType et = array.GetCorElementTypeOfElementType(); - if (et.IsPrimitiveType() - // IntPtr/UIntPtr does not implement IComparable - && (et != CorElementType.ELEMENT_TYPE_I) && (et != CorElementType.ELEMENT_TYPE_U)) + if (et.IsPrimitiveType()) { if (value == null) return ~index; @@ -538,15 +544,27 @@ public static int BinarySearch(Array array, int index, int length, object? value result = GenericBinarySearch(array, adjustedIndex, length, value); break; case CorElementType.ELEMENT_TYPE_I4: +#if TARGET_32BIT + case CorElementType.ELEMENT_TYPE_I: +#endif result = GenericBinarySearch(array, adjustedIndex, length, value); break; case CorElementType.ELEMENT_TYPE_U4: +#if TARGET_32BIT + case CorElementType.ELEMENT_TYPE_U: +#endif result = GenericBinarySearch(array, adjustedIndex, length, value); break; case CorElementType.ELEMENT_TYPE_I8: +#if TARGET_64BIT + case CorElementType.ELEMENT_TYPE_I: +#endif result = GenericBinarySearch(array, adjustedIndex, length, value); break; case CorElementType.ELEMENT_TYPE_U8: +#if TARGET_64BIT + case CorElementType.ELEMENT_TYPE_U: +#endif result = GenericBinarySearch(array, adjustedIndex, length, value); break; case CorElementType.ELEMENT_TYPE_R4: @@ -1674,15 +1692,27 @@ public static void Sort(Array keys, Array? items, int index, int length, ICompar GenericSort(keys, items, adjustedIndex, length); return; case CorElementType.ELEMENT_TYPE_I4: +#if TARGET_32BIT + case CorElementType.ELEMENT_TYPE_I: +#endif GenericSort(keys, items, adjustedIndex, length); return; case CorElementType.ELEMENT_TYPE_U4: +#if TARGET_32BIT + case CorElementType.ELEMENT_TYPE_U: +#endif GenericSort(keys, items, adjustedIndex, length); return; case CorElementType.ELEMENT_TYPE_I8: +#if TARGET_64BIT + case CorElementType.ELEMENT_TYPE_I: +#endif GenericSort(keys, items, adjustedIndex, length); return; case CorElementType.ELEMENT_TYPE_U8: +#if TARGET_64BIT + case CorElementType.ELEMENT_TYPE_U: +#endif GenericSort(keys, items, adjustedIndex, length); return; case CorElementType.ELEMENT_TYPE_R4: @@ -1691,10 +1721,6 @@ public static void Sort(Array keys, Array? items, int index, int length, ICompar case CorElementType.ELEMENT_TYPE_R8: GenericSort(keys, items, adjustedIndex, length); return; - case CorElementType.ELEMENT_TYPE_I: - case CorElementType.ELEMENT_TYPE_U: - // IntPtr/UIntPtr does not implement IComparable - break; } static void GenericSort(Array keys, Array? items, int adjustedIndex, int length) where T: struct @@ -1898,11 +1924,11 @@ private void IntrospectiveSort(int left, int length) try { - IntroSort(left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(length)); + IntroSort(left, length + left - 1, 2 * (BitOperations.Log2((uint)length) + 1)); } catch (IndexOutOfRangeException) { - IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); + ThrowHelper.ThrowArgumentException_BadComparer(comparer); } catch (Exception e) { @@ -1912,20 +1938,22 @@ private void IntrospectiveSort(int left, int length) private void IntroSort(int lo, int hi, int depthLimit) { + Debug.Assert(hi >= lo); + Debug.Assert(depthLimit >= 0); + while (hi > lo) { int partitionSize = hi - lo + 1; - if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold) + if (partitionSize <= IntrosortSizeThreshold) { - if (partitionSize == 1) - { - return; - } + Debug.Assert(partitionSize >= 2); + if (partitionSize == 2) { SwapIfGreater(lo, hi); return; } + if (partitionSize == 3) { SwapIfGreater(lo, hi - 1); @@ -1953,8 +1981,11 @@ private void IntroSort(int lo, int hi, int depthLimit) private int PickPivotAndPartition(int lo, int hi) { + Debug.Assert(hi - lo >= IntrosortSizeThreshold); + // Compute median-of-three. But also partition them, since we've done the comparison. int mid = lo + (hi - lo) / 2; + // Sort lo, mid and hi appropriately, then pick mid as the pivot. SwapIfGreater(lo, mid); SwapIfGreater(lo, hi); @@ -1976,7 +2007,10 @@ private int PickPivotAndPartition(int lo, int hi) } // Put pivot in the right location. - Swap(left, hi - 1); + if (left != hi - 1) + { + Swap(left, hi - 1); + } return left; } @@ -2104,11 +2138,11 @@ private void IntrospectiveSort(int left, int length) try { - IntroSort(left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(length)); + IntroSort(left, length + left - 1, 2 * (BitOperations.Log2((uint)length) + 1)); } catch (IndexOutOfRangeException) { - IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); + ThrowHelper.ThrowArgumentException_BadComparer(comparer); } catch (Exception e) { @@ -2118,20 +2152,22 @@ private void IntrospectiveSort(int left, int length) private void IntroSort(int lo, int hi, int depthLimit) { + Debug.Assert(hi >= lo); + Debug.Assert(depthLimit >= 0); + while (hi > lo) { int partitionSize = hi - lo + 1; - if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold) + if (partitionSize <= IntrosortSizeThreshold) { - if (partitionSize == 1) - { - return; - } + Debug.Assert(partitionSize >= 2); + if (partitionSize == 2) { SwapIfGreater(lo, hi); return; } + if (partitionSize == 3) { SwapIfGreater(lo, hi - 1); @@ -2159,6 +2195,8 @@ private void IntroSort(int lo, int hi, int depthLimit) private int PickPivotAndPartition(int lo, int hi) { + Debug.Assert(hi - lo >= IntrosortSizeThreshold); + // Compute median-of-three. But also partition them, since we've done the comparison. int mid = lo + (hi - lo) / 2; @@ -2182,7 +2220,10 @@ private int PickPivotAndPartition(int lo, int hi) } // Put pivot in the right location. - Swap(left, hi - 1); + if (left != hi - 1) + { + Swap(left, hi - 1); + } return left; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Boolean.cs b/src/libraries/System.Private.CoreLib/src/System/Boolean.cs index aad5656aa94d63..71a498d2461e6e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Boolean.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Boolean.cs @@ -12,6 +12,7 @@ ** ===========================================================*/ +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Versioning; @@ -223,7 +224,7 @@ public static bool Parse(ReadOnlySpan value) => // Determines whether a String represents true or false. // - public static bool TryParse(string? value, out bool result) + public static bool TryParse([NotNullWhen(true)] string? value, out bool result) { if (value == null) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffer.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Buffer.Unix.cs index 6c6a823a521e06..18f55d3bb39812 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffer.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffer.Unix.cs @@ -2,26 +2,19 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System { public static partial class Buffer { #if TARGET_ARM64 - // Managed code is currently faster than glibc unoptimized memmove - // TODO-ARM64-UNIX-OPT revisit when glibc optimized memmove is in Linux distros - // https://github.com/dotnet/runtime/issues/8897 - private const nuint MemmoveNativeThreshold = ulong.MaxValue; + // Managed code is currently faster than glibc unoptimized memmove + // TODO-ARM64-UNIX-OPT revisit when glibc optimized memmove is in Linux distros + // https://github.com/dotnet/runtime/issues/8897 + private static nuint MemmoveNativeThreshold => nuint.MaxValue; #elif TARGET_ARM - private const nuint MemmoveNativeThreshold = 512; + private const nuint MemmoveNativeThreshold = 512; #else - private const nuint MemmoveNativeThreshold = 2048; + private const nuint MemmoveNativeThreshold = 2048; #endif } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffer.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Buffer.Windows.cs index 226a0cd7e1d1b0..d5607de9134784 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffer.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffer.Windows.cs @@ -2,13 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System { public static partial class Buffer @@ -16,7 +9,7 @@ public static partial class Buffer #if TARGET_ARM64 // Determine optimal value for Windows. // https://github.com/dotnet/runtime/issues/8896 - private const nuint MemmoveNativeThreshold = ulong.MaxValue; + private static nuint MemmoveNativeThreshold => nuint.MaxValue; #else private const nuint MemmoveNativeThreshold = 2048; #endif diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffer.cs b/src/libraries/System.Private.CoreLib/src/System/Buffer.cs index e8d9b778282216..3880d590ca4ce0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffer.cs @@ -12,15 +12,6 @@ using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nint = System.Int64; -using nuint = System.UInt64; -#else -using nint = System.Int32; -using nuint = System.UInt32; -#endif - namespace System { public static partial class Buffer @@ -341,7 +332,7 @@ ref Unsafe.As(ref source), private static void Memmove(ref byte dest, ref byte src, nuint len) { // P/Invoke into the native version when the buffers are overlapping. - if (((nuint)Unsafe.ByteOffset(ref src, ref dest) < len) || ((nuint)Unsafe.ByteOffset(ref dest, ref src) < len)) + if (((nuint)(nint)Unsafe.ByteOffset(ref src, ref dest) < len) || ((nuint)(nint)Unsafe.ByteOffset(ref dest, ref src) < len)) { goto BuffersOverlap; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/FormattingHelpers.CountDigits.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/FormattingHelpers.CountDigits.cs index 8235339820dfea..eb339b89576d67 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/FormattingHelpers.CountDigits.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/FormattingHelpers.CountDigits.cs @@ -104,7 +104,8 @@ public static int CountDigits(uint value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int CountHexDigits(ulong value) { - return (64 - BitOperations.LeadingZeroCount(value | 1) + 3) >> 2; + // The number of hex digits is log16(value) + 1, or log2(value) / 4 + 1 + return (BitOperations.Log2(value) >> 2) + 1; } // Counts the number of trailing '0' digits in a decimal number. diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Utilities.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Utilities.cs index 7e1caa039b36c1..9fe7233e16486c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Utilities.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Utilities.cs @@ -14,8 +14,13 @@ internal static class Utilities internal static int SelectBucketIndex(int bufferSize) { Debug.Assert(bufferSize >= 0); - uint bits = ((uint)bufferSize - 1) >> 4; - return 32 - BitOperations.LeadingZeroCount(bits); + + // Buffers are bucketed so that a request between 2^(n-1) + 1 and 2^n is given a buffer of 2^n + // Bucket index is log2(bufferSize - 1) with the exception that buffers between 1 and 16 bytes + // are combined, and the index is slid down by 3 to compensate. + // Zero is a valid bufferSize, and it is assigned the highest bucket index so that zero-length + // buffers are not retained by the pool. The pool will return the Array.Empty singleton for these. + return BitOperations.Log2((uint)bufferSize - 1 | 15) - 3; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Byte.cs b/src/libraries/System.Private.CoreLib/src/System/Byte.cs index 77b10c44251131..c587097485aab6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Byte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Byte.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -117,7 +118,7 @@ private static byte Parse(ReadOnlySpan s, NumberStyles style, NumberFormat return (byte)i; } - public static bool TryParse(string? s, out byte result) + public static bool TryParse([NotNullWhen(true)] string? s, out byte result) { if (s == null) { @@ -133,7 +134,7 @@ public static bool TryParse(ReadOnlySpan s, out byte result) return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out byte result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out byte result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/libraries/System.Private.CoreLib/src/System/Char.cs b/src/libraries/System.Private.CoreLib/src/System/Char.cs index 02e49c90420da2..2ccf35ee737548 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Char.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Char.cs @@ -13,6 +13,7 @@ ===========================================================*/ using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.InteropServices; using System.Text; @@ -182,7 +183,7 @@ public static char Parse(string s) return s[0]; } - public static bool TryParse(string? s, out char result) + public static bool TryParse([NotNullWhen(true)] string? s, out char result) { result = '\0'; if (s == null) @@ -353,10 +354,7 @@ public static char ToUpper(char c) } // Converts a character to upper-case for invariant culture. - public static char ToUpperInvariant(char c) - { - return TextInfo.Invariant.ToUpper(c); - } + public static char ToUpperInvariant(char c) => TextInfo.ToUpperInvariant(c); /*===================================ToLower==================================== ** @@ -382,10 +380,7 @@ public static char ToLower(char c) } // Converts a character to lower-case for invariant culture. - public static char ToLowerInvariant(char c) - { - return TextInfo.Invariant.ToLower(c); - } + public static char ToLowerInvariant(char c) => TextInfo.ToLowerInvariant(c); // // IConvertible implementation diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/ArrayList.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/ArrayList.cs index cb7f2cdde7f682..061672601a022a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/ArrayList.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/ArrayList.cs @@ -28,18 +28,12 @@ namespace System.Collections [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public class ArrayList : IList, ICloneable { - private object?[] _items = null!; // Do not rename (binary serialization) + private object?[] _items; // Do not rename (binary serialization) private int _size; // Do not rename (binary serialization) private int _version; // Do not rename (binary serialization) private const int _defaultCapacity = 4; - // Note: this constructor is a bogus constructor that does nothing - // and is for use only with SyncArrayList. - internal ArrayList(bool trash) - { - } - // Constructs a ArrayList. The list is initially empty and has a capacity // of zero. Upon adding the first element to the list the capacity is // increased to _defaultCapacity, and then increased in multiples of two as required. @@ -1196,7 +1190,6 @@ private class SyncArrayList : ArrayList private readonly object _root; internal SyncArrayList(ArrayList list) - : base(false) { _list = list; _root = list.SyncRoot; @@ -2215,7 +2208,7 @@ private class Range : ArrayList private int _baseSize; private int _baseVersion; - internal Range(ArrayList list, int index, int count) : base(false) + internal Range(ArrayList list, int index, int count) { _baseList = list; _baseIndex = index; diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs index 480890eca55b80..b47e97c9d20c81 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentQueue.cs @@ -198,7 +198,7 @@ bool IProducerConsumerCollection.TryAdd(T item) /// For , this operation will attempt to remove the object /// from the beginning of the . /// - bool IProducerConsumerCollection.TryTake(out T item) => TryDequeue(out item); + bool IProducerConsumerCollection.TryTake([MaybeNullWhen(false)] out T item) => TryDequeue(out item); /// /// Gets a value that indicates whether the is empty. diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs index 0ebaafc8031e1f..321c2119cfe567 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs @@ -2,50 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -/*============================================================ -** -** -** -** -** -** Purpose: class to sort arrays -** -** -===========================================================*/ - using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; +using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Internal.Runtime.CompilerServices; namespace System.Collections.Generic { #region ArraySortHelper for single arrays - internal static class IntrospectiveSortUtilities - { - // This is the threshold where Introspective sort switches to Insertion sort. - // Empirically, 16 seems to speed up most cases without slowing down others, at least for integers. - // Large value types may benefit from a smaller number. - internal const int IntrosortSizeThreshold = 16; - - internal static int FloorLog2PlusOne(int n) - { - int result = 0; - while (n >= 1) - { - result++; - n /= 2; - } - return result; - } - - [DoesNotReturn] - internal static void ThrowOrIgnoreBadComparer(object? comparer) - { - throw new ArgumentException(SR.Format(SR.Arg_BogusIComparer, comparer)); - } - } - internal partial class ArraySortHelper { #region IArraySortHelper Members @@ -61,11 +27,11 @@ public void Sort(Span keys, IComparer? comparer) } catch (IndexOutOfRangeException) { - IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); + ThrowHelper.ThrowArgumentException_BadComparer(comparer); } catch (Exception e) { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e); } } @@ -78,7 +44,8 @@ public int BinarySearch(T[] array, int index, int length, T value, IComparer? } catch (Exception e) { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e); + return 0; } } @@ -95,11 +62,11 @@ internal static void Sort(Span keys, Comparison comparer) } catch (IndexOutOfRangeException) { - IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); + ThrowHelper.ThrowArgumentException_BadComparer(comparer); } catch (Exception e) { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e); } } @@ -131,26 +98,24 @@ internal static int InternalBinarySearch(T[] array, int index, int length, T val private static void SwapIfGreater(Span keys, Comparison comparer, int i, int j) { - if (i != j) + Debug.Assert(i != j); + + if (comparer(keys[i], keys[j]) > 0) { - if (comparer(keys[i], keys[j]) > 0) - { - T key = keys[i]; - keys[i] = keys[j]; - keys[j] = key; - } + T key = keys[i]; + keys[i] = keys[j]; + keys[j] = key; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Swap(Span a, int i, int j) { - if (i != j) - { - T t = a[i]; - a[i] = a[j]; - a[j] = t; - } + Debug.Assert(i != j); + + T t = a[i]; + a[i] = a[j]; + a[j] = t; } internal static void IntrospectiveSort(Span keys, Comparison comparer) @@ -159,79 +124,73 @@ internal static void IntrospectiveSort(Span keys, Comparison comparer) if (keys.Length > 1) { - IntroSort(keys, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length), comparer); + IntroSort(keys, 2 * (BitOperations.Log2((uint)keys.Length) + 1), comparer); } } private static void IntroSort(Span keys, int depthLimit, Comparison comparer) { - int lo = 0; - int hi = keys.Length - 1; - + Debug.Assert(!keys.IsEmpty); + Debug.Assert(depthLimit >= 0); Debug.Assert(comparer != null); - while (hi > lo) + int partitionSize = keys.Length; + while (partitionSize > 1) { - int partitionSize = hi - lo + 1; - if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold) + if (partitionSize <= Array.IntrosortSizeThreshold) { - if (partitionSize == 1) - { - return; - } if (partitionSize == 2) { - SwapIfGreater(keys, comparer, lo, hi); + SwapIfGreater(keys, comparer, 0, 1); return; } if (partitionSize == 3) { - SwapIfGreater(keys, comparer, lo, hi - 1); - SwapIfGreater(keys, comparer, lo, hi); - SwapIfGreater(keys, comparer, hi - 1, hi); + SwapIfGreater(keys, comparer, 0, 1); + SwapIfGreater(keys, comparer, 0, 2); + SwapIfGreater(keys, comparer, 1, 2); return; } - InsertionSort(keys[lo..(hi+1)], comparer); + InsertionSort(keys.Slice(0, partitionSize), comparer); return; } if (depthLimit == 0) { - HeapSort(keys[lo..(hi+1)], comparer); + HeapSort(keys.Slice(0, partitionSize), comparer); return; } depthLimit--; - int p = PickPivotAndPartition(keys[lo..(hi+1)], comparer); + int p = PickPivotAndPartition(keys.Slice(0, partitionSize), comparer); // Note we've already partitioned around the pivot and do not have to move the pivot again. - IntroSort(keys[(p+1)..(hi+1)], depthLimit, comparer); - hi = p - 1; + IntroSort(keys[(p+1)..partitionSize], depthLimit, comparer); + partitionSize = p; } } private static int PickPivotAndPartition(Span keys, Comparison comparer) { + Debug.Assert(keys.Length >= Array.IntrosortSizeThreshold); Debug.Assert(comparer != null); - Debug.Assert(!keys.IsEmpty); - int lo = 0; int hi = keys.Length - 1; // Compute median-of-three. But also partition them, since we've done the comparison. - int middle = lo + ((hi - lo) / 2); + int middle = hi >> 1; // Sort lo, mid and hi appropriately, then pick mid as the pivot. - SwapIfGreater(keys, comparer, lo, middle); // swap the low with the mid point - SwapIfGreater(keys, comparer, lo, hi); // swap the low with the high + SwapIfGreater(keys, comparer, 0, middle); // swap the low with the mid point + SwapIfGreater(keys, comparer, 0, hi); // swap the low with the high SwapIfGreater(keys, comparer, middle, hi); // swap the middle with the high T pivot = keys[middle]; Swap(keys, middle, hi - 1); - int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. + int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. while (left < right) { @@ -245,7 +204,10 @@ private static int PickPivotAndPartition(Span keys, Comparison comparer) } // Put pivot in the right location. - Swap(keys, left, hi - 1); + if (left != hi - 1) + { + Swap(keys, left, hi - 1); + } return left; } @@ -254,20 +216,16 @@ private static void HeapSort(Span keys, Comparison comparer) Debug.Assert(comparer != null); Debug.Assert(!keys.IsEmpty); - int lo = 0; - int hi = keys.Length - 1; - - int n = hi - lo + 1; - - for (int i = n / 2; i >= 1; i--) + int n = keys.Length; + for (int i = n >> 1; i >= 1; i--) { - DownHeap(keys, i, n, lo, comparer); + DownHeap(keys, i, n, 0, comparer); } for (int i = n; i > 1; i--) { - Swap(keys, lo, lo + i - 1); - DownHeap(keys, 1, i - 1, lo, comparer); + Swap(keys, 0, i - 1); + DownHeap(keys, 1, i - 1, 0, comparer); } } @@ -278,7 +236,7 @@ private static void DownHeap(Span keys, int i, int n, int lo, Comparison c Debug.Assert(lo < keys.Length); T d = keys[lo + i - 1]; - while (i <= n / 2) + while (i <= n >> 1) { int child = 2 * i; if (child < n && comparer(keys[lo + child - 1], keys[lo + child]) < 0) @@ -327,7 +285,10 @@ public void Sort(Span keys, IComparer? comparer) { if (comparer == null || comparer == Comparer.Default) { - IntrospectiveSort(keys); + if (keys.Length > 1) + { + IntroSort(keys, 2 * (BitOperations.Log2((uint)keys.Length) + 1)); + } } else { @@ -336,11 +297,11 @@ public void Sort(Span keys, IComparer? comparer) } catch (IndexOutOfRangeException) { - IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); + ThrowHelper.ThrowArgumentException_BadComparer(comparer); } catch (Exception e) { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e); } } @@ -362,7 +323,8 @@ public int BinarySearch(T[] array, int index, int length, T value, IComparer? } catch (Exception e) { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e); + return 0; } } @@ -406,147 +368,137 @@ private static int BinarySearch(T[] array, int index, int length, T value) return ~lo; } - private static void SwapIfGreater(Span keys, int i, int j) + /// Swaps the values in the two references if the first is greater than the second. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void SwapIfGreater(ref T i, ref T j) { - Debug.Assert(0 <= i && i < keys.Length); - Debug.Assert(0 <= j && j < keys.Length); - - if (i != j) + if (i != null && i.CompareTo(j) > 0) { - if (keys[i] != null && keys[i].CompareTo(keys[j]) > 0) - { - T key = keys[i]; - keys[i] = keys[j]; - keys[j] = key; - } + Swap(ref i, ref j); } } + /// Swaps the values in the two references, regardless of whether the two references are the same. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Swap(Span a, int i, int j) + private static void Swap(ref T i, ref T j) { - if (i != j) - { - T t = a[i]; - a[i] = a[j]; - a[j] = t; - } - } + Debug.Assert(!Unsafe.AreSame(ref i, ref j)); - internal static void IntrospectiveSort(Span keys) - { - if (keys.Length > 1) - { - IntroSort(keys, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length)); - } + T t = i; + i = j; + j = t; } private static void IntroSort(Span keys, int depthLimit) { - int lo = 0; - int hi = keys.Length - 1; + Debug.Assert(!keys.IsEmpty); + Debug.Assert(depthLimit >= 0); - while (hi > lo) + int partitionSize = keys.Length; + while (partitionSize > 1) { - int partitionSize = hi - lo + 1; - if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold) + if (partitionSize <= Array.IntrosortSizeThreshold) { - if (partitionSize == 1) - { - return; - } + if (partitionSize == 2) { - SwapIfGreater(keys, lo, hi); + SwapIfGreater(ref keys[0], ref keys[1]); return; } + if (partitionSize == 3) { - SwapIfGreater(keys, lo, hi - 1); - SwapIfGreater(keys, lo, hi); - SwapIfGreater(keys, hi - 1, hi); + ref T hiRef = ref keys[2]; + ref T him1Ref = ref keys[1]; + ref T loRef = ref keys[0]; + + SwapIfGreater(ref loRef, ref him1Ref); + SwapIfGreater(ref loRef, ref hiRef); + SwapIfGreater(ref him1Ref, ref hiRef); return; } - InsertionSort(keys[lo..(hi+1)]); + InsertionSort(keys.Slice(0, partitionSize)); return; } if (depthLimit == 0) { - HeapSort(keys[lo..(hi+1)]); + HeapSort(keys.Slice(0, partitionSize)); return; } depthLimit--; - int p = PickPivotAndPartition(keys[lo..(hi+1)]); + int p = PickPivotAndPartition(keys.Slice(0, partitionSize)); // Note we've already partitioned around the pivot and do not have to move the pivot again. - IntroSort(keys[(p+1)..(hi+1)], depthLimit); - hi = p - 1; + IntroSort(keys[(p+1)..partitionSize], depthLimit); + partitionSize = p; } } private static int PickPivotAndPartition(Span keys) { - Debug.Assert(!keys.IsEmpty); + Debug.Assert(keys.Length >= Array.IntrosortSizeThreshold); - int lo = 0; - int hi = keys.Length - 1; + // Use median-of-three to select a pivot. Grab a reference to the 0th, Length-1th, and Length/2th elements, and sort them. + ref T zeroRef = ref MemoryMarshal.GetReference(keys); + ref T lastRef = ref Unsafe.Add(ref zeroRef, keys.Length - 1); + ref T middleRef = ref Unsafe.Add(ref zeroRef, (keys.Length - 1) >> 1); + SwapIfGreater(ref zeroRef, ref middleRef); + SwapIfGreater(ref zeroRef, ref lastRef); + SwapIfGreater(ref middleRef, ref lastRef); - // Compute median-of-three. But also partition them, since we've done the comparison. - int middle = lo + ((hi - lo) / 2); + // Select the middle value as the pivot, and move it to be just before the last element. + ref T nextToLastRef = ref Unsafe.Add(ref zeroRef, keys.Length - 2); + T pivot = middleRef; + Swap(ref middleRef, ref nextToLastRef); - // Sort lo, mid and hi appropriately, then pick mid as the pivot. - SwapIfGreater(keys, lo, middle); // swap the low with the mid point - SwapIfGreater(keys, lo, hi); // swap the low with the high - SwapIfGreater(keys, middle, hi); // swap the middle with the high - - T pivot = keys[middle]; - Swap(keys, middle, hi - 1); - int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. - - while (left < right) + // Walk the left and right pointers, swapping elements as necessary, until they cross. + ref T leftRef = ref zeroRef, rightRef = ref nextToLastRef; + while (Unsafe.IsAddressLessThan(ref leftRef, ref rightRef)) { if (pivot == null) { - while (left < (hi - 1) && keys[++left] == null) ; - while (right > lo && keys[--right] != null) ; + while (Unsafe.IsAddressLessThan(ref leftRef, ref nextToLastRef) && (leftRef = ref Unsafe.Add(ref leftRef, 1)) == null) ; + while (Unsafe.IsAddressGreaterThan(ref rightRef, ref zeroRef) && (rightRef = ref Unsafe.Add(ref rightRef, -1)) == null) ; } else { - while (pivot.CompareTo(keys[++left]) > 0) ; - while (pivot.CompareTo(keys[--right]) < 0) ; + while (Unsafe.IsAddressLessThan(ref leftRef, ref nextToLastRef) && pivot.CompareTo(leftRef = ref Unsafe.Add(ref leftRef, 1)) > 0) ; + while (Unsafe.IsAddressGreaterThan(ref rightRef, ref zeroRef) && pivot.CompareTo(rightRef = ref Unsafe.Add(ref rightRef, -1)) < 0) ; } - if (left >= right) + if (!Unsafe.IsAddressLessThan(ref leftRef, ref rightRef)) + { break; + } - Swap(keys, left, right); + Swap(ref leftRef, ref rightRef); } - // Put pivot in the right location. - Swap(keys, left, hi - 1); - return left; + // Put the pivot in the correct location. + if (!Unsafe.AreSame(ref leftRef, ref nextToLastRef)) + { + Swap(ref leftRef, ref nextToLastRef); + } + return (int)((nint)Unsafe.ByteOffset(ref zeroRef, ref leftRef) / Unsafe.SizeOf()); } private static void HeapSort(Span keys) { Debug.Assert(!keys.IsEmpty); - int lo = 0; - int hi = keys.Length - 1; - - int n = hi - lo + 1; - for (int i = n / 2; i >= 1; i--) + int n = keys.Length; + for (int i = n >> 1; i >= 1; i--) { - DownHeap(keys, i, n, lo); + DownHeap(keys, i, n, 0); } for (int i = n; i > 1; i--) { - Swap(keys, lo, lo + i - 1); - DownHeap(keys, 1, i - 1, lo); + Swap(ref keys[0], ref keys[i - 1]); + DownHeap(keys, 1, i - 1, 0); } } @@ -556,7 +508,7 @@ private static void DownHeap(Span keys, int i, int n, int lo) Debug.Assert(lo < keys.Length); T d = keys[lo + i - 1]; - while (i <= n / 2) + while (i <= n >> 1) { int child = 2 * i; if (child < n && (keys[lo + child - 1] == null || keys[lo + child - 1].CompareTo(keys[lo + child]) < 0)) @@ -578,16 +530,16 @@ private static void InsertionSort(Span keys) { for (int i = 0; i < keys.Length - 1; i++) { - T t = keys[i + 1]; + T t = Unsafe.Add(ref MemoryMarshal.GetReference(keys), i + 1); int j = i; - while (j >= 0 && (t == null || t.CompareTo(keys[j]) < 0)) + while (j >= 0 && (t == null || t.CompareTo(Unsafe.Add(ref MemoryMarshal.GetReference(keys), j)) < 0)) { - keys[j + 1] = keys[j]; + Unsafe.Add(ref MemoryMarshal.GetReference(keys), j + 1) = Unsafe.Add(ref MemoryMarshal.GetReference(keys), j); j--; } - keys[j + 1] = t; + Unsafe.Add(ref MemoryMarshal.GetReference(keys), j + 1) = t; } } } @@ -608,11 +560,11 @@ public void Sort(Span keys, Span values, IComparer? comparer } catch (IndexOutOfRangeException) { - IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); + ThrowHelper.ThrowArgumentException_BadComparer(comparer); } catch (Exception e) { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e); } } @@ -621,35 +573,32 @@ private static void SwapIfGreaterWithValues(Span keys, Span values Debug.Assert(comparer != null); Debug.Assert(0 <= i && i < keys.Length && i < values.Length); Debug.Assert(0 <= j && j < keys.Length && j < values.Length); + Debug.Assert(i != j); - if (i != j) + if (comparer.Compare(keys[i], keys[j]) > 0) { - if (comparer.Compare(keys[i], keys[j]) > 0) - { - TKey key = keys[i]; - keys[i] = keys[j]; - keys[j] = key; + TKey key = keys[i]; + keys[i] = keys[j]; + keys[j] = key; - TValue value = values[i]; - values[i] = values[j]; - values[j] = value; - } + TValue value = values[i]; + values[i] = values[j]; + values[j] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Swap(Span keys, Span values, int i, int j) { - if (i != j) - { - TKey k = keys[i]; - keys[i] = keys[j]; - keys[j] = k; + Debug.Assert(i != j); - TValue v = values[i]; - values[i] = values[j]; - values[j] = v; - } + TKey k = keys[i]; + keys[i] = keys[j]; + keys[j] = k; + + TValue v = values[i]; + values[i] = values[j]; + values[j] = v; } internal static void IntrospectiveSort(Span keys, Span values, IComparer comparer) @@ -659,79 +608,74 @@ internal static void IntrospectiveSort(Span keys, Span values, ICo if (keys.Length > 1) { - IntroSort(keys, values, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length), comparer); + IntroSort(keys, values, 2 * (BitOperations.Log2((uint)keys.Length) + 1), comparer); } } private static void IntroSort(Span keys, Span values, int depthLimit, IComparer comparer) { + Debug.Assert(!keys.IsEmpty); + Debug.Assert(values.Length == keys.Length); + Debug.Assert(depthLimit >= 0); Debug.Assert(comparer != null); - int lo = 0; - int hi = keys.Length - 1; - - while (hi > lo) + int partitionSize = keys.Length; + while (partitionSize > 1) { - int partitionSize = hi - lo + 1; - if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold) + if (partitionSize <= Array.IntrosortSizeThreshold) { - if (partitionSize == 1) - { - return; - } if (partitionSize == 2) { - SwapIfGreaterWithValues(keys, values, comparer, lo, hi); + SwapIfGreaterWithValues(keys, values, comparer, 0, 1); return; } if (partitionSize == 3) { - SwapIfGreaterWithValues(keys, values, comparer, lo, hi - 1); - SwapIfGreaterWithValues(keys, values, comparer, lo, hi); - SwapIfGreaterWithValues(keys, values, comparer, hi - 1, hi); + SwapIfGreaterWithValues(keys, values, comparer, 0, 1); + SwapIfGreaterWithValues(keys, values, comparer, 0, 2); + SwapIfGreaterWithValues(keys, values, comparer, 1, 2); return; } - InsertionSort(keys[lo..(hi+1)], values[lo..(hi+1)], comparer); + InsertionSort(keys.Slice(0, partitionSize), values.Slice(0, partitionSize), comparer); return; } if (depthLimit == 0) { - HeapSort(keys[lo..(hi+1)], values[lo..(hi+1)], comparer); + HeapSort(keys.Slice(0, partitionSize), values.Slice(0, partitionSize), comparer); return; } depthLimit--; - int p = PickPivotAndPartition(keys[lo..(hi+1)], values[lo..(hi+1)], comparer); + int p = PickPivotAndPartition(keys.Slice(0, partitionSize), values.Slice(0, partitionSize), comparer); // Note we've already partitioned around the pivot and do not have to move the pivot again. - IntroSort(keys[(p+1)..(hi+1)], values[(p+1)..(hi+1)], depthLimit, comparer); - hi = p - 1; + IntroSort(keys[(p+1)..partitionSize], values[(p+1)..partitionSize], depthLimit, comparer); + partitionSize = p; } } private static int PickPivotAndPartition(Span keys, Span values, IComparer comparer) { + Debug.Assert(keys.Length >= Array.IntrosortSizeThreshold); Debug.Assert(comparer != null); - Debug.Assert(!keys.IsEmpty); - int lo = 0; int hi = keys.Length - 1; // Compute median-of-three. But also partition them, since we've done the comparison. - int middle = lo + ((hi - lo) / 2); + int middle = hi >> 1; // Sort lo, mid and hi appropriately, then pick mid as the pivot. - SwapIfGreaterWithValues(keys, values, comparer, lo, middle); // swap the low with the mid point - SwapIfGreaterWithValues(keys, values, comparer, lo, hi); // swap the low with the high + SwapIfGreaterWithValues(keys, values, comparer, 0, middle); // swap the low with the mid point + SwapIfGreaterWithValues(keys, values, comparer, 0, hi); // swap the low with the high SwapIfGreaterWithValues(keys, values, comparer, middle, hi); // swap the middle with the high TKey pivot = keys[middle]; Swap(keys, values, middle, hi - 1); - int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. + int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. while (left < right) { @@ -745,7 +689,10 @@ private static int PickPivotAndPartition(Span keys, Span values, I } // Put pivot in the right location. - Swap(keys, values, left, hi - 1); + if (left != hi - 1) + { + Swap(keys, values, left, hi - 1); + } return left; } @@ -754,19 +701,16 @@ private static void HeapSort(Span keys, Span values, IComparer= 1; i--) + int n = keys.Length; + for (int i = n >> 1; i >= 1; i--) { - DownHeap(keys, values, i, n, lo, comparer); + DownHeap(keys, values, i, n, 0, comparer); } for (int i = n; i > 1; i--) { - Swap(keys, values, lo, lo + i - 1); - DownHeap(keys, values, 1, i - 1, lo, comparer); + Swap(keys, values, 0, i - 1); + DownHeap(keys, values, 1, i - 1, 0, comparer); } } @@ -779,7 +723,7 @@ private static void DownHeap(Span keys, Span values, int i, int n, TKey d = keys[lo + i - 1]; TValue dValue = values[lo + i - 1]; - while (i <= n / 2) + while (i <= n >> 1) { int child = 2 * i; if (child < n && comparer.Compare(keys[lo + child - 1], keys[lo + child]) < 0) @@ -842,44 +786,42 @@ public void Sort(Span keys, Span values, IComparer? comparer } catch (IndexOutOfRangeException) { - IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); + ThrowHelper.ThrowArgumentException_BadComparer(comparer); } catch (Exception e) { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e); } } private static void SwapIfGreaterWithValues(Span keys, Span values, int i, int j) { - if (i != j) + Debug.Assert(i != j); + + if (keys[i] != null && keys[i].CompareTo(keys[j]) > 0) { - if (keys[i] != null && keys[i].CompareTo(keys[j]) > 0) - { - TKey key = keys[i]; - keys[i] = keys[j]; - keys[j] = key; + TKey key = keys[i]; + keys[i] = keys[j]; + keys[j] = key; - TValue value = values[i]; - values[i] = values[j]; - values[j] = value; - } + TValue value = values[i]; + values[i] = values[j]; + values[j] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Swap(Span keys, Span values, int i, int j) { - if (i != j) - { - TKey k = keys[i]; - keys[i] = keys[j]; - keys[j] = k; + Debug.Assert(i != j); - TValue v = values[i]; - values[i] = values[j]; - values[j] = v; - } + TKey k = keys[i]; + keys[i] = keys[j]; + keys[j] = k; + + TValue v = values[i]; + values[i] = values[j]; + values[j] = v; } internal static void IntrospectiveSort(Span keys, Span values) @@ -888,83 +830,79 @@ internal static void IntrospectiveSort(Span keys, Span values) if (keys.Length > 1) { - IntroSort(keys, values, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length)); + IntroSort(keys, values, 2 * (BitOperations.Log2((uint)keys.Length) + 1)); } } private static void IntroSort(Span keys, Span values, int depthLimit) { - int lo = 0; - int hi = keys.Length - 1; + Debug.Assert(!keys.IsEmpty); + Debug.Assert(values.Length == keys.Length); + Debug.Assert(depthLimit >= 0); - while (hi > lo) + int partitionSize = keys.Length; + while (partitionSize > 1) { - int partitionSize = hi - lo + 1; - if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold) + if (partitionSize <= Array.IntrosortSizeThreshold) { - if (partitionSize == 1) - { - return; - } if (partitionSize == 2) { - SwapIfGreaterWithValues(keys, values, lo, hi); + SwapIfGreaterWithValues(keys, values, 0, 1); return; } if (partitionSize == 3) { - SwapIfGreaterWithValues(keys, values, lo, hi - 1); - SwapIfGreaterWithValues(keys, values, lo, hi); - SwapIfGreaterWithValues(keys, values, hi - 1, hi); + SwapIfGreaterWithValues(keys, values, 0, 1); + SwapIfGreaterWithValues(keys, values, 0, 2); + SwapIfGreaterWithValues(keys, values, 1, 2); return; } - InsertionSort(keys[lo..(hi+1)], values[lo..(hi+1)]); + InsertionSort(keys.Slice(0, partitionSize), values.Slice(0, partitionSize)); return; } if (depthLimit == 0) { - HeapSort(keys[lo..(hi+1)], values[lo..(hi+1)]); + HeapSort(keys.Slice(0, partitionSize), values.Slice(0, partitionSize)); return; } depthLimit--; - int p = PickPivotAndPartition(keys[lo..(hi+1)], values[lo..(hi+1)]); + int p = PickPivotAndPartition(keys.Slice(0, partitionSize), values.Slice(0, partitionSize)); // Note we've already partitioned around the pivot and do not have to move the pivot again. - IntroSort(keys[(p+1)..(hi+1)], values[(p+1)..(hi+1)], depthLimit); - hi = p - 1; + IntroSort(keys[(p+1)..partitionSize], values[(p+1)..partitionSize], depthLimit); + partitionSize = p; } } private static int PickPivotAndPartition(Span keys, Span values) { - Debug.Assert(!keys.IsEmpty); + Debug.Assert(keys.Length >= Array.IntrosortSizeThreshold); - int lo = 0; int hi = keys.Length - 1; // Compute median-of-three. But also partition them, since we've done the comparison. - int middle = lo + ((hi - lo) / 2); + int middle = hi >> 1; // Sort lo, mid and hi appropriately, then pick mid as the pivot. - SwapIfGreaterWithValues(keys, values, lo, middle); // swap the low with the mid point - SwapIfGreaterWithValues(keys, values, lo, hi); // swap the low with the high + SwapIfGreaterWithValues(keys, values, 0, middle); // swap the low with the mid point + SwapIfGreaterWithValues(keys, values, 0, hi); // swap the low with the high SwapIfGreaterWithValues(keys, values, middle, hi); // swap the middle with the high TKey pivot = keys[middle]; Swap(keys, values, middle, hi - 1); - int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. + int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. while (left < right) { if (pivot == null) { while (left < (hi - 1) && keys[++left] == null) ; - while (right > lo && keys[--right] != null) ; + while (right > 0 && keys[--right] != null) ; } else { @@ -979,7 +917,10 @@ private static int PickPivotAndPartition(Span keys, Span values) } // Put pivot in the right location. - Swap(keys, values, left, hi - 1); + if (left != hi - 1) + { + Swap(keys, values, left, hi - 1); + } return left; } @@ -987,19 +928,16 @@ private static void HeapSort(Span keys, Span values) { Debug.Assert(!keys.IsEmpty); - int lo = 0; - int hi = keys.Length - 1; - - int n = hi - lo + 1; - for (int i = n / 2; i >= 1; i--) + int n = keys.Length; + for (int i = n >> 1; i >= 1; i--) { - DownHeap(keys, values, i, n, lo); + DownHeap(keys, values, i, n, 0); } for (int i = n; i > 1; i--) { - Swap(keys, values, lo, lo + i - 1); - DownHeap(keys, values, 1, i - 1, lo); + Swap(keys, values, 0, i - 1); + DownHeap(keys, values, 1, i - 1, 0); } } @@ -1011,7 +949,7 @@ private static void DownHeap(Span keys, Span values, int i, int n, TKey d = keys[lo + i - 1]; TValue dValue = values[lo + i - 1]; - while (i <= n / 2) + while (i <= n >> 1) { int child = 2 * i; if (child < n && (keys[lo + child - 1] == null || keys[lo + child - 1].CompareTo(keys[lo + child]) < 0)) diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/HashHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/HashHelpers.cs index abdf95c05ed79b..9ae197ee1bcf93 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/HashHelpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/HashHelpers.cs @@ -101,10 +101,9 @@ public static uint FastMod(uint value, uint divisor, ulong multiplier) // which allows to avoid the long multiplication if the divisor is less than 2**31. Debug.Assert(divisor <= int.MaxValue); - ulong lowbits = multiplier * value; - // 64bit * 64bit => 128bit isn't currently supported by Math https://github.com/dotnet/runtime/issues/31184 - // otherwise we'd want this to be (uint)Math.BigMul(lowbits, divisor, out _) - uint highbits = (uint)((((lowbits >> 32) + 1) * divisor) >> 32); + // This is equivalent of (uint)Math.BigMul(multiplier * value, divisor, out _). This version + // is faster than BigMul currently because we only need the high bits. + uint highbits = (uint)(((((multiplier * value) >> 32) + 1) * divisor) >> 32); Debug.Assert(highbits == value % divisor); return highbits; diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTime.cs b/src/libraries/System.Private.CoreLib/src/System/DateTime.cs index 456c93415f4304..1561e99a724349 100644 --- a/src/libraries/System.Private.CoreLib/src/System/DateTime.cs +++ b/src/libraries/System.Private.CoreLib/src/System/DateTime.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; @@ -580,9 +581,7 @@ public DateTime AddYears(int value) { if (value < -10000 || value > 10000) { - // DateTimeOffset.AddYears(int years) is implemented on top of DateTime.AddYears(int value). Use the more appropriate - // parameter name out of the two for the exception. - throw new ArgumentOutOfRangeException("years", SR.ArgumentOutOfRange_DateTimeBadYears); + throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_DateTimeBadYears); } return AddMonths(value * 12); } @@ -1355,7 +1354,7 @@ public DateTime ToUniversalTime() return TimeZoneInfo.ConvertTimeToUtc(this, TimeZoneInfoOptions.NoThrowOnInvalidTime); } - public static bool TryParse(string? s, out DateTime result) + public static bool TryParse([NotNullWhen(true)] string? s, out DateTime result) { if (s == null) { @@ -1370,7 +1369,7 @@ public static bool TryParse(ReadOnlySpan s, out DateTime result) return DateTimeParse.TryParse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out result); } - public static bool TryParse(string? s, IFormatProvider? provider, DateTimeStyles styles, out DateTime result) + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, DateTimeStyles styles, out DateTime result) { DateTimeFormatInfo.ValidateStyles(styles, nameof(styles)); @@ -1389,7 +1388,7 @@ public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, Dat return DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), styles, out result); } - public static bool TryParseExact(string? s, string? format, IFormatProvider? provider, DateTimeStyles style, out DateTime result) + public static bool TryParseExact([NotNullWhen(true)] string? s, [NotNullWhen(true)] string? format, IFormatProvider? provider, DateTimeStyles style, out DateTime result) { DateTimeFormatInfo.ValidateStyles(style, nameof(style)); @@ -1408,7 +1407,7 @@ public static bool TryParseExact(ReadOnlySpan s, ReadOnlySpan format return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result); } - public static bool TryParseExact(string? s, string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result) + public static bool TryParseExact([NotNullWhen(true)] string? s, [NotNullWhen(true)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result) { DateTimeFormatInfo.ValidateStyles(style, nameof(style)); @@ -1421,7 +1420,7 @@ public static bool TryParseExact(string? s, string?[]? formats, IFormatProvider? return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result); } - public static bool TryParseExact(ReadOnlySpan s, string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result) + public static bool TryParseExact(ReadOnlySpan s, [NotNullWhen(true)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result) { DateTimeFormatInfo.ValidateStyles(style, nameof(style)); return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.cs b/src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.cs index b1536f9855f49b..45338f361ac0d7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.cs +++ b/src/libraries/System.Private.CoreLib/src/System/DateTimeOffset.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.InteropServices; using System.Runtime.Serialization; @@ -648,7 +649,7 @@ public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan public DateTimeOffset ToUniversalTime() => new DateTimeOffset(UtcDateTime); - public static bool TryParse(string? input, out DateTimeOffset result) + public static bool TryParse([NotNullWhen(true)] string? input, out DateTimeOffset result) { bool parsed = DateTimeParse.TryParse(input, DateTimeFormatInfo.CurrentInfo, @@ -666,7 +667,7 @@ public static bool TryParse(ReadOnlySpan input, out DateTimeOffset result) return parsed; } - public static bool TryParse(string? input, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) + public static bool TryParse([NotNullWhen(true)] string? input, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); if (input == null) @@ -692,7 +693,7 @@ public static bool TryParse(ReadOnlySpan input, IFormatProvider? formatPro return parsed; } - public static bool TryParseExact(string? input, string? format, IFormatProvider? formatProvider, DateTimeStyles styles, + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string? format, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); @@ -721,7 +722,7 @@ public static bool TryParseExact( return parsed; } - public static bool TryParseExact(string? input, string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); @@ -742,7 +743,7 @@ public static bool TryParseExact(string? input, string?[]? formats, IFormatProvi } public static bool TryParseExact( - ReadOnlySpan input, string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) + ReadOnlySpan input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); bool parsed = DateTimeParse.TryParseExactMultiple(input, formats, DateTimeFormatInfo.GetInstance(formatProvider), styles, out DateTime dateResult, out TimeSpan offset); diff --git a/src/libraries/System.Private.CoreLib/src/System/Decimal.cs b/src/libraries/System.Private.CoreLib/src/System/Decimal.cs index 72b85bfeaf44fe..cc32ce56213e1b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Decimal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Decimal.cs @@ -4,6 +4,7 @@ using System.Buffers.Binary; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -480,7 +481,7 @@ public static decimal Parse(ReadOnlySpan s, NumberStyles style = NumberSty return Number.ParseDecimal(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse(string? s, out decimal result) + public static bool TryParse([NotNullWhen(true)] string? s, out decimal result) { if (s == null) { @@ -496,7 +497,7 @@ public static bool TryParse(ReadOnlySpan s, out decimal result) return Number.TryParseDecimal(s, NumberStyles.Number, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out decimal result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out decimal result) { NumberFormatInfo.ValidateParseStyleFloatingPoint(style); diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicDependencyAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicDependencyAttribute.cs new file mode 100644 index 00000000000000..8c730d2fb6abda --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicDependencyAttribute.cs @@ -0,0 +1,131 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// States a dependency that one member has on another. + /// + /// + /// This can be used to inform tooling of a dependency that is otherwise not evident purely from + /// metadata and IL, for example a member relied on via reflection. + /// + [AttributeUsage( + AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method, + AllowMultiple = true, Inherited = false)] + public sealed class DynamicDependencyAttribute : Attribute + { + /// + /// Initializes a new instance of the class + /// with the specified signature of a member on the same type as the consumer. + /// + /// The signature of the member depended on. + public DynamicDependencyAttribute(string memberSignature) + { + MemberSignature = memberSignature; + } + + /// + /// Initializes a new instance of the class + /// with the specified signature of a member on a . + /// + /// The signature of the member depended on. + /// The containing . + public DynamicDependencyAttribute(string memberSignature, Type type) + { + MemberSignature = memberSignature; + Type = type; + } + + /// + /// Initializes a new instance of the class + /// with the specified signature of a member on a type in an assembly. + /// + /// The signature of the member depended on. + /// The full name of the type containing the specified member. + /// The assembly name of the type containing the specified member. + public DynamicDependencyAttribute(string memberSignature, string typeName, string assemblyName) + { + MemberSignature = memberSignature; + TypeName = typeName; + AssemblyName = assemblyName; + } + + /// + /// Initializes a new instance of the class + /// with the specified types of members on a . + /// + /// The types of members depended on. + /// The containing the specified members. + public DynamicDependencyAttribute(DynamicallyAccessedMemberTypes memberTypes, Type type) + { + MemberTypes = memberTypes; + Type = type; + } + + /// + /// Initializes a new instance of the class + /// with the specified types of members on a type in an assembly. + /// + /// The types of members depended on. + /// The full name of the type containing the specified members. + /// The assembly name of the type containing the specified members. + public DynamicDependencyAttribute(DynamicallyAccessedMemberTypes memberTypes, string typeName, string assemblyName) + { + MemberTypes = memberTypes; + TypeName = typeName; + AssemblyName = assemblyName; + } + + /// + /// Gets the signature of the member depended on. + /// + /// + /// Either must be a valid string or + /// must not equal , but not both. + /// + public string? MemberSignature { get; } + + /// + /// Gets the which specifies the type + /// of members depended on. + /// + /// + /// Either must be a valid string or + /// must not equal , but not both. + /// + public DynamicallyAccessedMemberTypes MemberTypes { get; } + + /// + /// Gets the containing the specified member. + /// + /// + /// If neither nor are specified, + /// the type of the consumer is assumed. + /// + public Type? Type { get; } + + /// + /// Gets the full name of the type containing the specified member. + /// + /// + /// If neither nor are specified, + /// the type of the consumer is assumed. + /// + public string? TypeName { get; } + + /// + /// Gets the assembly name of the specified type. + /// + /// + /// is only valid when is specified. + /// + public string? AssemblyName { get; } + + /// + /// Gets or sets the condition in which the dependency is applicable, e.g. "DEBUG". + /// + public string? Condition { get; set; } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicallyAccessedMemberTypes.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicallyAccessedMemberTypes.cs new file mode 100644 index 00000000000000..90c29af0d22824 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicallyAccessedMemberTypes.cs @@ -0,0 +1,91 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// Specifies the types of members that are dynamically accessed. + /// + /// This enumeration has a attribute that allows a + /// bitwise combination of its member values. + /// + [Flags] + public enum DynamicallyAccessedMemberTypes + { + /// + /// Specifies no members. + /// + None = 0, + + /// + /// Specifies the default, parameterless public constructor. + /// + DefaultConstructor = 0x0001, + + /// + /// Specifies all public constructors. + /// + PublicConstructors = 0x0002 | DefaultConstructor, + + /// + /// Specifies all non-public constructors. + /// + NonPublicConstructors = 0x0004, + + /// + /// Specifies all public methods. + /// + PublicMethods = 0x0008, + + /// + /// Specifies all non-public methods. + /// + NonPublicMethods = 0x0010, + + /// + /// Specifies all public fields. + /// + PublicFields = 0x0020, + + /// + /// Specifies all non-public fields. + /// + NonPublicFields = 0x0040, + + /// + /// Specifies all public nested types. + /// + PublicNestedTypes = 0x0080, + + /// + /// Specifies all non-public nested types. + /// + NonPublicNestedTypes = 0x0100, + + /// + /// Specifies all public properties. + /// + PublicProperties = 0x0200, + + /// + /// Specifies all non-public properties. + /// + NonPublicProperties = 0x0400, + + /// + /// Specifies all public events. + /// + PublicEvents = 0x0800, + + /// + /// Specifies all non-public events. + /// + NonPublicEvents = 0x1000, + + /// + /// Specifies all members. + /// + All = ~None + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicallyAccessedMembersAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicallyAccessedMembersAttribute.cs new file mode 100644 index 00000000000000..13d4d669fc29dc --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicallyAccessedMembersAttribute.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// Indicates that certain members on a specified are accessed dynamically, + /// for example through . + /// + /// + /// This allows tools to understand which members are being accessed during the execution + /// of a program. + /// + /// This attribute is valid on members whose type is or . + /// + /// When this attribute is applied to a location of type , the assumption is + /// that the string represents a fully qualified type name. + /// + [AttributeUsage( + AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter | + AttributeTargets.Parameter | AttributeTargets.Property, + Inherited = false)] + public sealed class DynamicallyAccessedMembersAttribute : Attribute + { + /// + /// Initializes a new instance of the class + /// with the specified member types. + /// + /// The types of members dynamically accessed. + public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes) + { + MemberTypes = memberTypes; + } + + /// + /// Gets the which specifies the type + /// of members dynamically accessed. + /// + public DynamicallyAccessedMemberTypes MemberTypes { get; } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresUnreferencedCodeAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresUnreferencedCodeAttribute.cs new file mode 100644 index 00000000000000..5ab29034e1a8b5 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresUnreferencedCodeAttribute.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// Indicates that the specified method requires dynamic access to code that is not referenced + /// statically, for example through . + /// + /// + /// This allows tools to understand which methods are unsafe to call when removing unreferenced + /// code from an application. + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false)] + public sealed class RequiresUnreferencedCodeAttribute : Attribute + { + /// + /// Initializes a new instance of the class + /// with the specified message. + /// + /// + /// A message that contains information about the usage of unreferenced code. + /// + public RequiresUnreferencedCodeAttribute(string message) + { + Message = message; + } + + /// + /// Gets a message that contains information about the usage of unreferenced code. + /// + public string Message { get; } + + /// + /// Gets or sets an optional URL that contains more information about the method, + /// why it requries unreferenced code, and what options a consumer has to deal with it. + /// + public string? Url { get; set; } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttribute.cs new file mode 100644 index 00000000000000..74046b094d348f --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttribute.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// Suppresses reporting of a specific rule violation, allowing multiple suppressions on a + /// single code artifact. + /// + /// + /// is different than + /// in that it doesn't have a + /// . So it is always preserved in the compiled assembly. + /// + [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)] + public sealed class UnconditionalSuppressMessageAttribute : Attribute + { + /// + /// Initializes a new instance of the + /// class, specifying the category of the tool and the identifier for an analysis rule. + /// + /// The category for the attribute. + /// The identifier of the analysis rule the attribute applies to. + public UnconditionalSuppressMessageAttribute(string category, string checkId) + { + Category = category; + CheckId = checkId; + } + + /// + /// Gets the category identifying the classification of the attribute. + /// + /// + /// The property describes the tool or tool analysis category + /// for which a message suppression attribute applies. + /// + public string Category { get; } + + /// + /// Gets the identifier of the analysis tool rule to be suppressed. + /// + /// + /// Concatenated together, the and + /// properties form a unique check identifier. + /// + public string CheckId { get; } + + /// + /// Gets or sets the scope of the code that is relevant for the attribute. + /// + /// + /// The Scope property is an optional argument that specifies the metadata scope for which + /// the attribute is relevant. + /// + public string? Scope { get; set; } + + /// + /// Gets or sets a fully qualified path that represents the target of the attribute. + /// + /// + /// The property is an optional argument identifying the analysis target + /// of the attribute. An example value is "System.IO.Stream.ctor():System.Void". + /// Because it is fully qualified, it can be long, particularly for targets such as parameters. + /// The analysis tool user interface should be capable of automatically formatting the parameter. + /// + public string? Target { get; set; } + + /// + /// Gets or sets an optional argument expanding on exclusion criteria. + /// + /// + /// The property is an optional argument that specifies additional + /// exclusion where the literal metadata target is not sufficiently precise. For example, + /// the cannot be applied within a method, + /// and it may be desirable to suppress a violation against a statement in the method that will + /// give a rule violation, but not against all statements in the method. + /// + public string? MessageId { get; set; } + + /// + /// Gets or sets the justification for suppressing the code analysis message. + /// + public string? Justification { get; set; } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/DebugProvider.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/DebugProvider.Unix.cs index 55dcaffa0ea3bf..2cc40f94e2ff76 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/DebugProvider.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/DebugProvider.Unix.cs @@ -54,7 +54,7 @@ private static void WriteToDebugger(string message) } else { - Interop.Sys.SysLog(Interop.Sys.SysLogPriority.LOG_USER | Interop.Sys.SysLogPriority.LOG_DEBUG, "%s", message); + Interop.Sys.SysLog(Interop.Sys.SysLogPriority.LOG_DEBUG, "%s", message); } } @@ -87,7 +87,7 @@ private static void WriteToStderr(string message) int totalBytesWritten = 0; while (bufCount > 0) { - int bytesWritten = Interop.Sys.Write(2 /* stderr */, buf + totalBytesWritten, bufCount); + int bytesWritten = Interop.Sys.Write((IntPtr)2 /* stderr */, buf + totalBytesWritten, bufCount); if (bytesWritten < 0) { // On error, simply stop writing the debug output. This could commonly happen if stderr diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs index 1a41810b25965b..2fbe8b40e18ca3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs @@ -6,6 +6,7 @@ using System; using System.Diagnostics; #endif +using System.Diagnostics.CodeAnalysis; using System.Threading; #if ES_BUILD_STANDALONE @@ -135,9 +136,10 @@ internal void ResetStatistics() // Values buffering private const int BufferedSize = 10; private const double UnusedBufferSlotValue = double.NegativeInfinity; - private volatile double[] _bufferedValues = null!; + private volatile double[] _bufferedValues; private volatile int _bufferedValuesIndex; + [MemberNotNull(nameof(_bufferedValues))] private void InitializeBuffer() { _bufferedValues = new double[BufferedSize]; diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventProvider.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventProvider.cs index 52b9e4ddf666c3..8d0afa17111fce 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventProvider.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventProvider.cs @@ -50,7 +50,7 @@ unsafe EventProvider.WriteEventErrorCode IEventProvider.EventWriteTransfer( int userDataCount, EventProvider.EventData* userData) { - if (eventDescriptor.EventId != 0 && eventHandle != IntPtr.Zero) + if (eventHandle != IntPtr.Zero) { if (userDataCount == 0) { @@ -69,6 +69,7 @@ unsafe EventProvider.WriteEventErrorCode IEventProvider.EventWriteTransfer( } EventPipeInternal.WriteEventData(eventHandle, userData, (uint)userDataCount, activityId, relatedActivityId); } + return EventProvider.WriteEventErrorCode.NoError; } @@ -79,7 +80,8 @@ int IEventProvider.EventActivityIdControl(Interop.Advapi32.ActivityControl Contr } // Define an EventPipeEvent handle. - unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, long keywords, uint eventVersion, uint level, byte* pMetadata, uint metadataLength) + unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, long keywords, uint eventVersion, uint level, + byte *pMetadata, uint metadataLength) { IntPtr eventHandlePtr = EventPipeInternal.DefineEvent(m_provHandle, eventID, keywords, eventVersion, level, pMetadata, metadataLength); return eventHandlePtr; diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeMetadataGenerator.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeMetadataGenerator.cs index 428543cf7887d7..50f1f41bbbf9b4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeMetadataGenerator.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeMetadataGenerator.cs @@ -9,6 +9,12 @@ namespace System.Diagnostics.Tracing #if FEATURE_PERFTRACING internal sealed class EventPipeMetadataGenerator { + private enum MetadataTag + { + Opcode = 1, + ParameterPayload = 2 + } + public static EventPipeMetadataGenerator Instance = new EventPipeMetadataGenerator(); private EventPipeMetadataGenerator() { } @@ -19,7 +25,8 @@ private EventPipeMetadataGenerator() { } EventParameterInfo[] eventParams = new EventParameterInfo[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { - eventParams[i].SetInfo(parameters[i].Name!, parameters[i].ParameterType); + EventParameterInfo.GetTypeInfoFromType(parameters[i].ParameterType, out TraceLoggingTypeInfo? paramTypeInfo); + eventParams[i].SetInfo(parameters[i].Name!, parameters[i].ParameterType, paramTypeInfo); } return GenerateMetadata( @@ -28,6 +35,7 @@ private EventPipeMetadataGenerator() { } eventMetadata.Descriptor.Keywords, eventMetadata.Descriptor.Level, eventMetadata.Descriptor.Version, + (EventOpcode)eventMetadata.Descriptor.Opcode, eventParams); } @@ -37,6 +45,7 @@ private EventPipeMetadataGenerator() { } EventKeywords keywords, EventLevel level, uint version, + EventOpcode opcode, TraceLoggingEventTypes eventTypes) { TraceLoggingTypeInfo[] typeInfos = eventTypes.typeInfos; @@ -52,18 +61,20 @@ private EventPipeMetadataGenerator() { } eventParams[i].SetInfo(paramName, typeInfos[i].DataType, typeInfos[i]); } - return GenerateMetadata(eventId, eventName, (long)keywords, (uint)level, version, eventParams); + return GenerateMetadata(eventId, eventName, (long)keywords, (uint)level, version, opcode, eventParams); } - private unsafe byte[]? GenerateMetadata( + internal unsafe byte[]? GenerateMetadata( int eventId, string eventName, long keywords, uint level, uint version, + EventOpcode opcode, EventParameterInfo[] parameters) { byte[]? metadata = null; + bool hasV2ParameterTypes = false; try { // eventID : 4 bytes @@ -72,8 +83,9 @@ private EventPipeMetadataGenerator() { } // eventVersion : 4 bytes // level : 4 bytes // parameterCount : 4 bytes - uint metadataLength = 24 + ((uint)eventName.Length + 1) * 2; - uint defaultMetadataLength = metadataLength; + uint v1MetadataLength = 24 + ((uint)eventName.Length + 1) * 2; + uint v2MetadataLength = 0; + uint defaultV1MetadataLength = v1MetadataLength; // Check for an empty payload. // Write calls with no arguments by convention have a parameter of @@ -86,42 +98,115 @@ private EventPipeMetadataGenerator() { } // Increase the metadataLength for parameters. foreach (EventParameterInfo parameter in parameters) { - int pMetadataLength = parameter.GetMetadataLength(); - // The call above may return -1 which means we failed to get the metadata length. - // We then return a default metadata blob (with parameterCount of 0) to prevent it from generating malformed metadata. - if (pMetadataLength < 0) + uint pMetadataLength; + if (!parameter.GetMetadataLength(out pMetadataLength)) { - parameters = Array.Empty(); - metadataLength = defaultMetadataLength; + // The call above may return false which means it is an unsupported type for V1. + // If that is the case we use the v2 blob for metadata instead + hasV2ParameterTypes = true; break; } - metadataLength += (uint)pMetadataLength; + + v1MetadataLength += (uint)pMetadataLength; + } + + + if (hasV2ParameterTypes) + { + v1MetadataLength = defaultV1MetadataLength; + + // V2 length is the parameter count (4 bytes) plus the size of the params + v2MetadataLength = 4; + foreach (EventParameterInfo parameter in parameters) + { + uint pMetadataLength; + if (!parameter.GetMetadataLengthV2(out pMetadataLength)) + { + // We ran in to an unsupported type, return empty event metadata + parameters = Array.Empty(); + v1MetadataLength = defaultV1MetadataLength; + v2MetadataLength = 0; + hasV2ParameterTypes = false; + break; + } + + v2MetadataLength += (uint)pMetadataLength; + } } - metadata = new byte[metadataLength]; + // Optional opcode length needs 1 byte for the opcode + 5 bytes for the tag (4 bytes size, 1 byte kind) + uint opcodeMetadataLength = opcode == EventOpcode.Info ? 0u : 6u; + // Optional V2 metadata needs the size of the params + 5 bytes for the tag (4 bytes size, 1 byte kind) + uint v2MetadataPayloadLength = v2MetadataLength == 0 ? 0 : v2MetadataLength + 5; + uint totalV2MetadataLength = v2MetadataPayloadLength + opcodeMetadataLength; + uint totalMetadataLength = v1MetadataLength + totalV2MetadataLength; + metadata = new byte[totalMetadataLength]; - // Write metadata: eventID, eventName, keywords, eventVersion, level, parameterCount, param1 type, param1 name... + // Write metadata: metadataHeaderLength, eventID, eventName, keywords, eventVersion, level, + // parameterCount, param1..., optional extended metadata fixed (byte* pMetadata = metadata) { uint offset = 0; - WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)eventId); + + WriteToBuffer(pMetadata, totalMetadataLength, ref offset, (uint)eventId); fixed (char* pEventName = eventName) { - WriteToBuffer(pMetadata, metadataLength, ref offset, (byte*)pEventName, ((uint)eventName.Length + 1) * 2); + WriteToBuffer(pMetadata, totalMetadataLength, ref offset, (byte*)pEventName, ((uint)eventName.Length + 1) * 2); } - WriteToBuffer(pMetadata, metadataLength, ref offset, keywords); - WriteToBuffer(pMetadata, metadataLength, ref offset, version); - WriteToBuffer(pMetadata, metadataLength, ref offset, level); - WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)parameters.Length); - foreach (EventParameterInfo parameter in parameters) + WriteToBuffer(pMetadata, totalMetadataLength, ref offset, keywords); + WriteToBuffer(pMetadata, totalMetadataLength, ref offset, version); + WriteToBuffer(pMetadata, totalMetadataLength, ref offset, level); + + if (hasV2ParameterTypes) + { + // If we have unsupported types, the V1 metadata must be empty. Write 0 count of params. + WriteToBuffer(pMetadata, totalMetadataLength, ref offset, 0); + } + else + { + // Without unsupported V1 types we can write all the params now. + WriteToBuffer(pMetadata, totalMetadataLength, ref offset, (uint)parameters.Length); + foreach (var parameter in parameters) + { + if (!parameter.GenerateMetadata(pMetadata, ref offset, totalMetadataLength)) + { + // If we fail to generate metadata for any parameter, we should return the "default" metadata without any parameters + return GenerateMetadata(eventId, eventName, keywords, level, version, opcode, Array.Empty()); + } + } + } + + Debug.Assert(offset == v1MetadataLength); + + if (opcode != EventOpcode.Info) { - if (!parameter.GenerateMetadata(pMetadata, ref offset, metadataLength)) + // Size of opcode + WriteToBuffer(pMetadata, totalMetadataLength, ref offset, 1); + WriteToBuffer(pMetadata, totalMetadataLength, ref offset, (byte)MetadataTag.Opcode); + WriteToBuffer(pMetadata, totalMetadataLength, ref offset, (byte)opcode); + } + + if (hasV2ParameterTypes) + { + // Write the V2 supported metadata now + // Starting with the size of the V2 payload + WriteToBuffer(pMetadata, totalMetadataLength, ref offset, v2MetadataLength); + // Now the tag to identify it as a V2 parameter payload + WriteToBuffer(pMetadata, totalMetadataLength, ref offset, (byte)MetadataTag.ParameterPayload); + // Then the count of parameters + WriteToBuffer(pMetadata, totalMetadataLength, ref offset, (uint)parameters.Length); + // Finally the parameters themselves + foreach (var parameter in parameters) { - // If we fail to generate metadata for any parameter, we should return the "default" metadata without any parameters - return GenerateMetadata(eventId, eventName, keywords, level, version, Array.Empty()); + if (!parameter.GenerateMetadataV2(pMetadata, ref offset, totalMetadataLength)) + { + // If we fail to generate metadata for any parameter, we should return the "default" metadata without any parameters + return GenerateMetadata(eventId, eventName, keywords, level, version, opcode, Array.Empty()); + } } } - Debug.Assert(metadataLength == offset); + + Debug.Assert(totalMetadataLength == offset); } } catch @@ -147,28 +232,11 @@ internal static unsafe void WriteToBuffer(byte* buffer, uint bufferLength, ref u offset += srcLength; } - // Copy uint value to buffer. - internal static unsafe void WriteToBuffer(byte* buffer, uint bufferLength, ref uint offset, uint value) - { - Debug.Assert(bufferLength >= (offset + 4)); - *(uint*)(buffer + offset) = value; - offset += 4; - } - - // Copy long value to buffer. - internal static unsafe void WriteToBuffer(byte* buffer, uint bufferLength, ref uint offset, long value) + internal static unsafe void WriteToBuffer(byte* buffer, uint bufferLength, ref uint offset, T value) where T : unmanaged { - Debug.Assert(bufferLength >= (offset + 8)); - *(long*)(buffer + offset) = value; - offset += 8; - } - - // Copy char value to buffer. - internal static unsafe void WriteToBuffer(byte* buffer, uint bufferLength, ref uint offset, char value) - { - Debug.Assert(bufferLength >= (offset + 2)); - *(char*)(buffer + offset) = value; - offset += 2; + Debug.Assert(bufferLength >= (offset + sizeof(T))); + *(T*)(buffer + offset) = value; + offset += (uint)sizeof(T); } } @@ -307,16 +375,207 @@ private static unsafe bool GenerateMetadataForProperty(PropertyAnalysis property return true; } - internal int GetMetadataLength() + internal unsafe bool GenerateMetadataV2(byte* pMetadataBlob, ref uint offset, uint blobSize) + { + if (TypeInfo == null) + return false; + return GenerateMetadataForNamedTypeV2(ParameterName, TypeInfo, pMetadataBlob, ref offset, blobSize); + } + + private static unsafe bool GenerateMetadataForNamedTypeV2(string name, TraceLoggingTypeInfo typeInfo, byte* pMetadataBlob, ref uint offset, uint blobSize) { - int ret = 0; + Debug.Assert(pMetadataBlob != null); + + if (!GetMetadataLengthForNamedTypeV2(name, typeInfo, out uint length)) + { + return false; + } + + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, length); + + // Write the property name. + fixed (char *pPropertyName = name) + { + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (byte *)pPropertyName, ((uint)name.Length + 1) * 2); + } + + return GenerateMetadataForTypeV2(typeInfo, pMetadataBlob, ref offset, blobSize); + } + + private static unsafe bool GenerateMetadataForTypeV2(TraceLoggingTypeInfo? typeInfo, byte* pMetadataBlob, ref uint offset, uint blobSize) + { + Debug.Assert(typeInfo != null); + Debug.Assert(pMetadataBlob != null); + + // Check if this type is a nested struct. + if (typeInfo is InvokeTypeInfo invokeTypeInfo) + { + // Each nested struct is serialized as: + // TypeCode.Object : 4 bytes + // Number of properties : 4 bytes + // Property description 0...N + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)TypeCode.Object); + + // Get the set of properties to be serialized. + PropertyAnalysis[]? properties = invokeTypeInfo.properties; + if (properties != null) + { + // Write the count of serializable properties. + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)properties.Length); + + foreach (PropertyAnalysis prop in properties) + { + if (!GenerateMetadataForNamedTypeV2(prop.name, prop.typeInfo, pMetadataBlob, ref offset, blobSize)) + { + return false; + } + } + } + else + { + // This struct has zero serializable properties so we just write the property count. + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)0); + } + } + else if (typeInfo is EnumerableTypeInfo enumerableTypeInfo) + { + // Each enumerable is serialized as: + // TypeCode.Array : 4 bytes + // ElementType : N bytes + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, EventPipeTypeCodeArray); + GenerateMetadataForTypeV2(enumerableTypeInfo.ElementInfo, pMetadataBlob, ref offset, blobSize); + } + else if (typeInfo is ScalarArrayTypeInfo arrayTypeInfo) + { + // Each enumerable is serialized as: + // TypeCode.Array : 4 bytes + // ElementType : N bytes + if (!arrayTypeInfo.DataType.HasElementType) + { + return false; + } + + TraceLoggingTypeInfo? elementTypeInfo; + if (!GetTypeInfoFromType(arrayTypeInfo.DataType.GetElementType(), out elementTypeInfo)) + { + return false; + } + + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, EventPipeTypeCodeArray); + GenerateMetadataForTypeV2(elementTypeInfo, pMetadataBlob, ref offset, blobSize); + } + else + { + // Each primitive type is serialized as: + // TypeCode : 4 bytes + TypeCode typeCode = GetTypeCodeExtended(typeInfo.DataType); + + // EventPipe does not support this type. Throw, which will cause no metadata to be registered for this event. + if (typeCode == TypeCode.Object) + { + return false; + } + + // Write the type code. + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)typeCode); + } + return true; + } + + internal static bool GetTypeInfoFromType(Type? type, out TraceLoggingTypeInfo? typeInfo) + { + if (type == typeof(bool)) + { + typeInfo = ScalarTypeInfo.Boolean(); + return true; + } + else if (type == typeof(byte)) + { + typeInfo = ScalarTypeInfo.Byte(); + return true; + } + else if (type == typeof(sbyte)) + { + typeInfo = ScalarTypeInfo.SByte(); + return true; + } + else if (type == typeof(char)) + { + typeInfo = ScalarTypeInfo.Char(); + return true; + } + else if (type == typeof(short)) + { + typeInfo = ScalarTypeInfo.Int16(); + return true; + } + else if (type == typeof(ushort)) + { + typeInfo = ScalarTypeInfo.UInt16(); + return true; + } + else if (type == typeof(int)) + { + typeInfo = ScalarTypeInfo.Int32(); + return true; + } + else if (type == typeof(uint)) + { + typeInfo = ScalarTypeInfo.UInt32(); + return true; + } + else if (type == typeof(long)) + { + typeInfo = ScalarTypeInfo.Int64(); + return true; + } + else if (type == typeof(ulong)) + { + typeInfo = ScalarTypeInfo.UInt64(); + return true; + } + else if (type == typeof(IntPtr)) + { + typeInfo = ScalarTypeInfo.IntPtr(); + return true; + } + else if (type == typeof(UIntPtr)) + { + typeInfo = ScalarTypeInfo.UIntPtr(); + return true; + } + else if (type == typeof(float)) + { + typeInfo = ScalarTypeInfo.Single(); + return true; + } + else if (type == typeof(double)) + { + typeInfo = ScalarTypeInfo.Double(); + return true; + } + else if (type == typeof(Guid)) + { + typeInfo = ScalarTypeInfo.Guid(); + return true; + } + else + { + typeInfo = null; + return false; + } + } + + internal bool GetMetadataLength(out uint size) + { + size = 0; TypeCode typeCode = GetTypeCodeExtended(ParameterType); if (typeCode == TypeCode.Object) { if (!(TypeInfo is InvokeTypeInfo typeInfo)) { - return -1; + return false; } // Each nested struct is serialized as: @@ -324,7 +583,7 @@ internal int GetMetadataLength() // Number of properties : 4 bytes // Property description 0...N // Nested struct property name : NULL-terminated string. - ret += sizeof(uint) // TypeCode + size += sizeof(uint) // TypeCode + sizeof(uint); // Property count // Get the set of properties to be serialized. @@ -333,21 +592,21 @@ internal int GetMetadataLength() { foreach (PropertyAnalysis prop in properties) { - ret += (int)GetMetadataLengthForProperty(prop); + size += GetMetadataLengthForProperty(prop); } } // For simplicity when writing a reader, we write a NULL char // after the metadata for a top-level struct (for its name) so that // readers don't have do special case the outer-most struct. - ret += sizeof(char); + size += sizeof(char); } else { - ret += (int)(sizeof(uint) + ((ParameterName.Length + 1) * 2)); + size += (uint)(sizeof(uint) + ((ParameterName.Length + 1) * 2)); } - return ret; + return true; } private static uint GetMetadataLengthForProperty(PropertyAnalysis property) @@ -388,6 +647,9 @@ private static uint GetMetadataLengthForProperty(PropertyAnalysis property) return ret; } + // Array is not part of TypeCode, we decided to use 19 to represent it. (18 is the last type code value, string) + private const int EventPipeTypeCodeArray = 19; + private static TypeCode GetTypeCodeExtended(Type parameterType) { // Guid is not part of TypeCode, we decided to use 17 to represent it, as it's the "free slot" @@ -406,6 +668,99 @@ private static TypeCode GetTypeCodeExtended(Type parameterType) return Type.GetTypeCode(parameterType); } + + internal bool GetMetadataLengthV2(out uint size) + { + return GetMetadataLengthForNamedTypeV2(ParameterName, TypeInfo, out size); + } + + private static bool GetMetadataLengthForTypeV2(TraceLoggingTypeInfo? typeInfo, out uint size) + { + size = 0; + if (typeInfo == null) + { + return false; + } + + if (typeInfo is InvokeTypeInfo invokeTypeInfo) + { + // Struct is serialized as: + // TypeCode.Object : 4 bytes + // Number of properties : 4 bytes + // Property description 0...N + size += sizeof(uint) // TypeCode + + sizeof(uint); // Property count + + // Get the set of properties to be serialized. + PropertyAnalysis[]? properties = invokeTypeInfo.properties; + if (properties != null) + { + foreach (PropertyAnalysis prop in properties) + { + if (!GetMetadataLengthForNamedTypeV2(prop.name, prop.typeInfo, out uint typeSize)) + { + return false; + } + + size += typeSize; + } + } + } + else if (typeInfo is EnumerableTypeInfo enumerableTypeInfo) + { + // IEnumerable is serialized as: + // TypeCode : 4 bytes + // ElementType : N bytes + size += sizeof(uint); + if (!GetMetadataLengthForTypeV2(enumerableTypeInfo.ElementInfo, out uint typeSize)) + { + return false; + } + + size += typeSize; + } + else if (typeInfo is ScalarArrayTypeInfo arrayTypeInfo) + { + TraceLoggingTypeInfo? elementTypeInfo; + if (!arrayTypeInfo.DataType.HasElementType + || !GetTypeInfoFromType(arrayTypeInfo.DataType.GetElementType(), out elementTypeInfo)) + { + return false; + } + + size += sizeof(uint); + if (!GetMetadataLengthForTypeV2(elementTypeInfo, out uint typeSize)) + { + return false; + } + + size += typeSize; + } + else + { + size += (uint)sizeof(uint); + } + + return true; + } + + private static bool GetMetadataLengthForNamedTypeV2(string name, TraceLoggingTypeInfo? typeInfo, out uint size) + { + // Named type is serialized + // SizeOfTypeDescription : 4 bytes + // Name : NULL-terminated UTF16 string + // Type : N bytes + size = (uint)(sizeof(uint) + + ((name.Length + 1) * 2)); + + if (!GetMetadataLengthForTypeV2(typeInfo, out uint typeSize)) + { + return false; + } + + size += typeSize; + return true; + } } #endif // FEATURE_PERFTRACING diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventProvider.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventProvider.cs index fd0bd6eab4a32a..dbc70abfb741db 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventProvider.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventProvider.cs @@ -1325,7 +1325,8 @@ int IEventProvider.EventActivityIdControl(Interop.Advapi32.ActivityControl Contr } // Define an EventPipeEvent handle. - unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, long keywords, uint eventVersion, uint level, byte* pMetadata, uint metadataLength) + unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, long keywords, uint eventVersion, + uint level, byte* pMetadata, uint metadataLength) { throw new System.NotSupportedException(); } @@ -1366,7 +1367,8 @@ int IEventProvider.EventActivityIdControl(Interop.Advapi32.ActivityControl Contr } // Define an EventPipeEvent handle. - unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, long keywords, uint eventVersion, uint level, byte* pMetadata, uint metadataLength) + unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, long keywords, uint eventVersion, + uint level, byte* pMetadata, uint metadataLength) { return IntPtr.Zero; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index 14c0bfda465165..90e260acd62541 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -691,7 +691,7 @@ private unsafe void DefineEventPipeEvents() uint eventVersion = m_eventData[i].Descriptor.Version; uint level = m_eventData[i].Descriptor.Level; - fixed (byte* pMetadata = metadata) + fixed (byte *pMetadata = metadata) { IntPtr eventHandle = m_eventPipeProvider.m_eventProvider.DefineEventHandle( eventID, @@ -1371,28 +1371,29 @@ private unsafe void WriteEventRaw( int dataCount, IntPtr data) { +#if FEATURE_MANAGED_ETW || FEATURE_PERFTRACING + bool allAreNull = true; #if FEATURE_MANAGED_ETW - if (m_etwProvider == null) + allAreNull &= (m_etwProvider == null); + if (m_etwProvider != null + && !m_etwProvider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data)) { ThrowEventSourceException(eventName); } - else - { - if (!m_etwProvider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data)) - ThrowEventSourceException(eventName); - } #endif // FEATURE_MANAGED_ETW #if FEATURE_PERFTRACING - if (m_eventPipeProvider == null) + allAreNull &= (m_eventPipeProvider == null); + if (m_eventPipeProvider != null + && !m_eventPipeProvider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data)) { ThrowEventSourceException(eventName); } - else +#endif // FEATURE_PERFTRACING + if (allAreNull) { - if (!m_eventPipeProvider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data)) - ThrowEventSourceException(eventName); + ThrowEventSourceException(eventName); } -#endif // FEATURE_PERFTRACING +#endif // FEATURE_MANAGED_ETW || FEATURE_PERFTRACING } // FrameworkEventSource is on the startup path for the framework, so we have this internal overload that it can use @@ -2148,49 +2149,96 @@ private unsafe void DispatchToAllListeners(int eventId, EventWrittenEventArgs ev } } - private unsafe void WriteEventString(EventLevel level, long keywords, string msgString) + // WriteEventString is used for logging an error message (or similar) to + // ETW and EventPipe providers. It is not a general purpose API, it will + // log the message with Level=LogAlways and Keywords=All to make sure whoever + // is listening gets the message. + private unsafe void WriteEventString(string msgString) { +#if FEATURE_MANAGED_ETW || FEATURE_PERFTRACING + bool allAreNull = true; #if FEATURE_MANAGED_ETW - if (m_etwProvider != null) + allAreNull &= (m_etwProvider == null); +#endif // FEATURE_MANAGED_ETW +#if FEATURE_PERFTRACING + allAreNull &= (m_eventPipeProvider == null); +#endif // FEATURE_PERFTRACING + if (allAreNull) + { + return; + } + + EventLevel level = EventLevel.LogAlways; + long keywords = -1; + const string EventName = "EventSourceMessage"; + if (SelfDescribingEvents) { - const string EventName = "EventSourceMessage"; - if (SelfDescribingEvents) + EventSourceOptions opt = new EventSourceOptions { - EventSourceOptions opt = new EventSourceOptions - { - Keywords = (EventKeywords)unchecked(keywords), - Level = level - }; - var msg = new { message = msgString }; - var tlet = new TraceLoggingEventTypes(EventName, EventTags.None, new Type[] { msg.GetType() }); - WriteMultiMergeInner(EventName, ref opt, tlet, null, null, msg); + Keywords = (EventKeywords)unchecked(keywords), + Level = level + }; + var msg = new { message = msgString }; + var tlet = new TraceLoggingEventTypes(EventName, EventTags.None, new Type[] { msg.GetType() }); + WriteMultiMergeInner(EventName, ref opt, tlet, null, null, msg); + } + else + { + // We want the name of the provider to show up so if we don't have a manifest we create + // on that at least has the provider name (I don't define any events). + if (m_rawManifest == null && m_outOfBandMessageCount == 1) + { + ManifestBuilder manifestBuilder = new ManifestBuilder(Name, Guid, Name, null, EventManifestOptions.None); + manifestBuilder.StartEvent(EventName, new EventAttribute(0) { Level = level, Task = (EventTask)0xFFFE }); + manifestBuilder.AddEventParameter(typeof(string), "message"); + manifestBuilder.EndEvent(); + SendManifest(manifestBuilder.CreateManifest()); } - else + + // We use this low level routine to bypass the enabled checking, since the eventSource itself is only partially inited. + fixed (char* msgStringPtr = msgString) { - // We want the name of the provider to show up so if we don't have a manifest we create - // on that at least has the provider name (I don't define any events). - if (m_rawManifest == null && m_outOfBandMessageCount == 1) + EventDescriptor descr = new EventDescriptor(0, 0, 0, (byte)level, 0, 0, keywords); + EventProvider.EventData data = default; + data.Ptr = (ulong)msgStringPtr; + data.Size = (uint)(2 * (msgString.Length + 1)); + data.Reserved = 0; +#if FEATURE_MANAGED_ETW + if (m_etwProvider != null) { - ManifestBuilder manifestBuilder = new ManifestBuilder(Name, Guid, Name, null, EventManifestOptions.None); - manifestBuilder.StartEvent(EventName, new EventAttribute(0) { Level = EventLevel.LogAlways, Task = (EventTask)0xFFFE }); - manifestBuilder.AddEventParameter(typeof(string), "message"); - manifestBuilder.EndEvent(); - SendManifest(manifestBuilder.CreateManifest()); + m_etwProvider.WriteEvent(ref descr, IntPtr.Zero, null, null, 1, (IntPtr)((void*)&data)); } - - // We use this low level routine to bypass the enabled checking, since the eventSource itself is only partially inited. - fixed (char* msgStringPtr = msgString) +#endif // FEATURE_MANAGED_ETW +#if FEATURE_PERFTRACING + if (m_eventPipeProvider != null) { - EventDescriptor descr = new EventDescriptor(0, 0, 0, (byte)level, 0, 0, keywords); - EventProvider.EventData data = default; - data.Ptr = (ulong)msgStringPtr; - data.Size = (uint)(2 * (msgString.Length + 1)); - data.Reserved = 0; - m_etwProvider.WriteEvent(ref descr, IntPtr.Zero, null, null, 1, (IntPtr)((void*)&data)); + if (m_writeEventStringEventHandle == IntPtr.Zero) + { + lock (m_createEventLock) + { + if (m_writeEventStringEventHandle == IntPtr.Zero) + { + string eventName = "EventSourceMessage"; + EventParameterInfo paramInfo = default(EventParameterInfo); + paramInfo.SetInfo("message", typeof(string)); + byte[]? metadata = EventPipeMetadataGenerator.Instance.GenerateMetadata(0, eventName, keywords, (uint)level, 0, EventOpcode.Info, new EventParameterInfo[] { paramInfo }); + uint metadataLength = (metadata != null) ? (uint)metadata.Length : 0; + + fixed (byte* pMetadata = metadata) + { + m_writeEventStringEventHandle = m_eventPipeProvider.m_eventProvider.DefineEventHandle(0, eventName, keywords, 0, (uint)level, + pMetadata, metadataLength); + } + } + } + } + + m_eventPipeProvider.WriteEvent(ref descr, m_writeEventStringEventHandle, null, null, 1, (IntPtr)((void*)&data)); } +#endif // FEATURE_PERFTRACING } } -#endif // FEATURE_MANAGED_ETW +#endif // FEATURE_MANAGED_ETW || FEATURE_PERFTRACING } /// @@ -3803,7 +3851,7 @@ internal void ReportOutOfBandMessage(string msg) msg = "Reached message limit. End of EventSource error messages."; } - WriteEventString(EventLevel.LogAlways, -1, msg); + WriteEventString(msg); WriteStringToAllListeners("EventSourceMessage", msg); } catch { } // If we fail during last chance logging, well, we have to give up.... @@ -3860,6 +3908,8 @@ private bool SelfDescribingEvents private volatile OverideEventProvider m_etwProvider = null!; // This hooks up ETW commands to our 'OnEventCommand' callback #endif #if FEATURE_PERFTRACING + private object m_createEventLock = new object(); + private IntPtr m_writeEventStringEventHandle = IntPtr.Zero; private volatile OverideEventProvider m_eventPipeProvider = null!; #endif private bool m_completelyInited; // The EventSource constructor has returned without exception. diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IEventProvider.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IEventProvider.cs index 2ceb92f99c0349..fc50ec76af5b55 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IEventProvider.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IEventProvider.cs @@ -39,6 +39,7 @@ unsafe EventProvider.WriteEventErrorCode EventWriteTransfer( int EventActivityIdControl(Interop.Advapi32.ActivityControl ControlCode, ref Guid ActivityId); // Define an EventPipeEvent handle. - unsafe IntPtr DefineEventHandle(uint eventID, string eventName, long keywords, uint eventVersion, uint level, byte* pMetadata, uint metadataLength); + unsafe IntPtr DefineEventHandle(uint eventID, string eventName, long keywords, uint eventVersion, + uint level, byte *pMetadata, uint metadataLength); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs index 336e981bd622ae..663074856b21b7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs @@ -35,7 +35,10 @@ internal sealed class RuntimeEventSource : EventSource private PollingCounter? _gen1SizeCounter; private PollingCounter? _gen2SizeCounter; private PollingCounter? _lohSizeCounter; + private PollingCounter? _pohSizeCounter; private PollingCounter? _assemblyCounter; + private PollingCounter? _ilBytesJittedCounter; + private PollingCounter? _methodsJittedCounter; #endif public static void Initialize() @@ -68,7 +71,6 @@ protected override void OnEventCommand(EventCommandEventArgs command) _completedItemsCounter ??= new IncrementingPollingCounter("threadpool-completed-items-count", this, () => ThreadPool.CompletedWorkItemCount) { DisplayName = "ThreadPool Completed Work Item Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; _allocRateCounter ??= new IncrementingPollingCounter("alloc-rate", this, () => GC.GetTotalAllocatedBytes()) { DisplayName = "Allocation Rate", DisplayUnits = "B", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; _timerCounter ??= new PollingCounter("active-timer-count", this, () => Timer.ActiveCount) { DisplayName = "Number of Active Timers" }; - #if !MONO _exceptionCounter ??= new IncrementingPollingCounter("exception-count", this, () => Exception.GetExceptionCount()) { DisplayName = "Exception Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; _gcTimeCounter ??= new PollingCounter("time-in-gc", this, () => GC.GetLastGCPercentTimeInGC()) { DisplayName = "% Time in GC since last GC", DisplayUnits = "%" }; @@ -76,7 +78,10 @@ protected override void OnEventCommand(EventCommandEventArgs command) _gen1SizeCounter ??= new PollingCounter("gen-1-size", this, () => GC.GetGenerationSize(1)) { DisplayName = "Gen 1 Size", DisplayUnits = "B" }; _gen2SizeCounter ??= new PollingCounter("gen-2-size", this, () => GC.GetGenerationSize(2)) { DisplayName = "Gen 2 Size", DisplayUnits = "B" }; _lohSizeCounter ??= new PollingCounter("loh-size", this, () => GC.GetGenerationSize(3)) { DisplayName = "LOH Size", DisplayUnits = "B" }; + _pohSizeCounter ??= new PollingCounter("poh-size", this, () => GC.GetGenerationSize(4)) { DisplayName = "POH (Pinned Object Heap) Size", DisplayUnits = "B" }; _assemblyCounter ??= new PollingCounter("assembly-count", this, () => System.Reflection.Assembly.GetAssemblyCount()) { DisplayName = "Number of Assemblies Loaded" }; + _ilBytesJittedCounter ??= new PollingCounter("il-bytes-jitted", this, () => System.Runtime.CompilerServices.RuntimeHelpers.GetILBytesJitted()) { DisplayName = "IL Bytes Jitted", DisplayUnits = "B" }; + _methodsJittedCounter ??= new PollingCounter("methods-jitted-count", this, () => System.Runtime.CompilerServices.RuntimeHelpers.GetMethodsJittedCount()) { DisplayName = "Number of Methods Jitted" }; #endif } diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/EnumerableTypeInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/EnumerableTypeInfo.cs index 92a1a823f94eec..56d0e061d5a2d8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/EnumerableTypeInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/EnumerableTypeInfo.cs @@ -25,6 +25,8 @@ public EnumerableTypeInfo(Type type, TraceLoggingTypeInfo elementInfo) this.elementInfo = elementInfo; } + internal TraceLoggingTypeInfo ElementInfo { get { return elementInfo; } } + public override void WriteMetadata( TraceLoggingMetadataCollector collector, string? name, diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs index 17bf2eb2aeda6b..4ca0b83988f268 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs @@ -88,18 +88,19 @@ public IntPtr GetOrCreateEventHandle(EventProvider provider, TraceLoggingEventHa { if ((eventHandle = eventHandleTable[descriptor.EventId]) == IntPtr.Zero) { - byte[]? metadataBlob = EventPipeMetadataGenerator.Instance.GenerateEventMetadata( + byte[]? metadata = EventPipeMetadataGenerator.Instance.GenerateEventMetadata( descriptor.EventId, name, (EventKeywords)descriptor.Keywords, (EventLevel)descriptor.Level, descriptor.Version, + (EventOpcode)descriptor.Opcode, eventTypes); - uint metadataLength = (metadataBlob != null) ? (uint)metadataBlob.Length : 0; + uint metadataLength = (metadata != null) ? (uint)metadata.Length : 0; unsafe { - fixed (byte* pMetadataBlob = metadataBlob) + fixed (byte* pMetadataBlob = metadata) { // Define the event. eventHandle = provider.m_eventProvider.DefineEventHandle( diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index fedbed02de3d07..fd15e714507190 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -12,6 +12,7 @@ ** ===========================================================*/ +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -321,7 +322,7 @@ public static double Parse(ReadOnlySpan s, NumberStyles style = NumberStyl return Number.ParseDouble(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse(string? s, out double result) + public static bool TryParse([NotNullWhen(true)] string? s, out double result) { if (s == null) { @@ -337,7 +338,7 @@ public static bool TryParse(ReadOnlySpan s, out double result) return TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result); } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out double result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out double result) { NumberFormatInfo.ValidateParseStyleFloatingPoint(style); diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index 9d80c82f1a4fe5..33e294a7862c1e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -10,7 +10,6 @@ using Internal.Runtime.CompilerServices; #if CORERT -using CorElementType = System.Runtime.RuntimeImports.RhCorElementType; using RuntimeType = System.Type; using EnumInfo = Internal.Runtime.Augments.EnumInfo; #endif diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.GetFolderPathCore.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.GetFolderPathCore.Unix.cs new file mode 100644 index 00000000000000..385b5788904029 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.GetFolderPathCore.Unix.cs @@ -0,0 +1,250 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +namespace System +{ + public static partial class Environment + { + private static Func? s_directoryCreateDirectory; + + private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOption option) + { + // Get the path for the SpecialFolder + string path = GetFolderPathCoreWithoutValidation(folder); + Debug.Assert(path != null); + + // If we didn't get one, or if we got one but we're not supposed to verify it, + // or if we're supposed to verify it and it passes verification, return the path. + if (path.Length == 0 || + option == SpecialFolderOption.DoNotVerify || + Interop.Sys.Access(path, Interop.Sys.AccessMode.R_OK) == 0) + { + return path; + } + + // Failed verification. If None, then we're supposed to return an empty string. + // If Create, we're supposed to create it and then return the path. + if (option == SpecialFolderOption.None) + { + return string.Empty; + } + else + { + Debug.Assert(option == SpecialFolderOption.Create); + + Func createDirectory = LazyInitializer.EnsureInitialized(ref s_directoryCreateDirectory, () => + { + Type dirType = Type.GetType("System.IO.Directory, System.IO.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: true)!; + MethodInfo mi = dirType.GetTypeInfo().GetDeclaredMethod("CreateDirectory")!; + return mi.CreateDelegate>(); + }); + createDirectory(path); + + return path; + } + } + + private static string GetFolderPathCoreWithoutValidation(SpecialFolder folder) + { + // First handle any paths that involve only static paths, avoiding the overheads of getting user-local paths. + // https://www.freedesktop.org/software/systemd/man/file-hierarchy.html + switch (folder) + { + case SpecialFolder.CommonApplicationData: return "/usr/share"; + case SpecialFolder.CommonTemplates: return "/usr/share/templates"; +#if TARGET_OSX + case SpecialFolder.ProgramFiles: return "/Applications"; + case SpecialFolder.System: return "/System"; +#endif + } + + // All other paths are based on the XDG Base Directory Specification: + // https://specifications.freedesktop.org/basedir-spec/latest/ + string? home = null; + try + { + home = PersistedFiles.GetHomeDirectory(); + } + catch (Exception exc) + { + Debug.Fail($"Unable to get home directory: {exc}"); + } + + // Fall back to '/' when we can't determine the home directory. + // This location isn't writable by non-root users which provides some safeguard + // that the application doesn't write data which is meant to be private. + if (string.IsNullOrEmpty(home)) + { + home = "/"; + } + + // TODO: Consider caching (or precomputing and caching) all subsequent results. + // This would significantly improve performance for repeated access, at the expense + // of not being responsive to changes in the underlying environment variables, + // configuration files, etc. + + switch (folder) + { + case SpecialFolder.UserProfile: + case SpecialFolder.MyDocuments: // same value as Personal + return home; + case SpecialFolder.ApplicationData: + return GetXdgConfig(home); + case SpecialFolder.LocalApplicationData: + // "$XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored." + // "If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used." + string? data = GetEnvironmentVariable("XDG_DATA_HOME"); + if (string.IsNullOrEmpty(data) || data[0] != '/') + { + data = Path.Combine(home, ".local", "share"); + } + return data; + + case SpecialFolder.Desktop: + case SpecialFolder.DesktopDirectory: + return ReadXdgDirectory(home, "XDG_DESKTOP_DIR", "Desktop"); + case SpecialFolder.Templates: + return ReadXdgDirectory(home, "XDG_TEMPLATES_DIR", "Templates"); + case SpecialFolder.MyVideos: + return ReadXdgDirectory(home, "XDG_VIDEOS_DIR", "Videos"); + +#if TARGET_OSX + case SpecialFolder.MyMusic: + return Path.Combine(home, "Music"); + case SpecialFolder.MyPictures: + return Path.Combine(home, "Pictures"); + case SpecialFolder.Fonts: + return Path.Combine(home, "Library", "Fonts"); + case SpecialFolder.Favorites: + return Path.Combine(home, "Library", "Favorites"); + case SpecialFolder.InternetCache: + return Path.Combine(home, "Library", "Caches"); +#else + case SpecialFolder.MyMusic: + return ReadXdgDirectory(home, "XDG_MUSIC_DIR", "Music"); + case SpecialFolder.MyPictures: + return ReadXdgDirectory(home, "XDG_PICTURES_DIR", "Pictures"); + case SpecialFolder.Fonts: + return Path.Combine(home, ".fonts"); +#endif + } + + // No known path for the SpecialFolder + return string.Empty; + } + + private static string GetXdgConfig(string home) + { + // "$XDG_CONFIG_HOME defines the base directory relative to which user specific configuration files should be stored." + // "If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME/.config should be used." + string? config = GetEnvironmentVariable("XDG_CONFIG_HOME"); + if (string.IsNullOrEmpty(config) || config[0] != '/') + { + config = Path.Combine(home, ".config"); + } + return config; + } + + private static string ReadXdgDirectory(string homeDir, string key, string fallback) + { + Debug.Assert(!string.IsNullOrEmpty(homeDir), $"Expected non-empty homeDir"); + Debug.Assert(!string.IsNullOrEmpty(key), $"Expected non-empty key"); + Debug.Assert(!string.IsNullOrEmpty(fallback), $"Expected non-empty fallback"); + + string? envPath = GetEnvironmentVariable(key); + if (!string.IsNullOrEmpty(envPath) && envPath[0] == '/') + { + return envPath; + } + + // Use the user-dirs.dirs file to look up the right config. + // Note that the docs also highlight a list of directories in which to look for this file: + // "$XDG_CONFIG_DIRS defines the preference-ordered set of base directories to search for configuration files in addition + // to the $XDG_CONFIG_HOME base directory. The directories in $XDG_CONFIG_DIRS should be separated with a colon ':'. If + // $XDG_CONFIG_DIRS is either not set or empty, a value equal to / etc / xdg should be used." + // For simplicity, we don't currently do that. We can add it if/when necessary. + + string userDirsPath = Path.Combine(GetXdgConfig(homeDir), "user-dirs.dirs"); + if (Interop.Sys.Access(userDirsPath, Interop.Sys.AccessMode.R_OK) == 0) + { + try + { + using (var reader = new StreamReader(userDirsPath)) + { + string? line; + while ((line = reader.ReadLine()) != null) + { + // Example lines: + // XDG_DESKTOP_DIR="$HOME/Desktop" + // XDG_PICTURES_DIR = "/absolute/path" + + // Skip past whitespace at beginning of line + int pos = 0; + SkipWhitespace(line, ref pos); + if (pos >= line.Length) continue; + + // Skip past requested key name + if (string.CompareOrdinal(line, pos, key, 0, key.Length) != 0) continue; + pos += key.Length; + + // Skip past whitespace and past '=' + SkipWhitespace(line, ref pos); + if (pos >= line.Length - 4 || line[pos] != '=') continue; // 4 for ="" and at least one char between quotes + pos++; // skip past '=' + + // Skip past whitespace and past first quote + SkipWhitespace(line, ref pos); + if (pos >= line.Length - 3 || line[pos] != '"') continue; // 3 for "" and at least one char between quotes + pos++; // skip past opening '"' + + // Skip past relative prefix if one exists + bool relativeToHome = false; + const string RelativeToHomePrefix = "$HOME/"; + if (string.CompareOrdinal(line, pos, RelativeToHomePrefix, 0, RelativeToHomePrefix.Length) == 0) + { + relativeToHome = true; + pos += RelativeToHomePrefix.Length; + } + else if (line[pos] != '/') // if not relative to home, must be absolute path + { + continue; + } + + // Find end of path + int endPos = line.IndexOf('"', pos); + if (endPos <= pos) continue; + + // Got we need. Now extract it. + string path = line.Substring(pos, endPos - pos); + return relativeToHome ? + Path.Combine(homeDir, path) : + path; + } + } + } + catch (Exception exc) + { + // assembly not found, file not found, errors reading file, etc. Just eat everything. + Debug.Fail($"Failed reading {userDirsPath}: {exc}"); + } + } + + return Path.Combine(homeDir, fallback); + } + + private static void SkipWhitespace(string line, ref int pos) + { + while (pos < line.Length && char.IsWhiteSpace(line[pos])) pos++; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.OSVersion.OSX.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.OSVersion.OSX.cs new file mode 100644 index 00000000000000..0c8771938f0414 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.OSVersion.OSX.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. +// See the LICENSE file in the project root for more information. + +namespace System +{ + public static partial class Environment + { + private static OperatingSystem GetOSVersion() + { + Version version = Interop.libobjc.GetOperatingSystemVersion(); + + // For compatibility reasons with Mono, PlatformID.Unix is returned on MacOSX. PlatformID.MacOSX + // is hidden from the editor and shouldn't be used. + return new OperatingSystem(PlatformID.Unix, version); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.OSVersion.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.OSVersion.Unix.cs new file mode 100644 index 00000000000000..0ccea27611aeda --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.OSVersion.Unix.cs @@ -0,0 +1,67 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System +{ + public static partial class Environment + { + private static OperatingSystem GetOSVersion() => GetOperatingSystem(Interop.Sys.GetUnixRelease()); + + // Tests exercise this method for corner cases via private reflection + private static OperatingSystem GetOperatingSystem(string release) + { + int major = 0, minor = 0, build = 0, revision = 0; + + // Parse the uname's utsname.release for the first four numbers found. + // This isn't perfect, but Version already doesn't map exactly to all possible release + // formats, e.g. 2.6.19-1.2895.fc6 + if (release != null) + { + int i = 0; + major = FindAndParseNextNumber(release, ref i); + minor = FindAndParseNextNumber(release, ref i); + build = FindAndParseNextNumber(release, ref i); + revision = FindAndParseNextNumber(release, ref i); + } + + return new OperatingSystem(PlatformID.Unix, new Version(major, minor, build, revision)); + } + + private static int FindAndParseNextNumber(string text, ref int pos) + { + // Move to the beginning of the number + for (; pos < text.Length; pos++) + { + char c = text[pos]; + if ('0' <= c && c <= '9') + { + break; + } + } + + // Parse the number; + int num = 0; + for (; pos < text.Length; pos++) + { + char c = text[pos]; + if ('0' > c || c > '9') + break; + + try + { + num = checked((num * 10) + (c - '0')); + } + // Integer overflow can occur for example with: + // Linux nelknet 4.15.0-24201807041620-generic + // To form a valid Version, num must be positive. + catch (OverflowException) + { + return int.MaxValue; + } + } + + return num; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.GetFolderPathCore.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.GetFolderPathCore.cs deleted file mode 100644 index ad37bba3746e57..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.GetFolderPathCore.cs +++ /dev/null @@ -1,250 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; - -namespace System -{ - public static partial class Environment - { - private static Func? s_directoryCreateDirectory; - - private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOption option) - { - // Get the path for the SpecialFolder - string path = GetFolderPathCoreWithoutValidation(folder); - Debug.Assert(path != null); - - // If we didn't get one, or if we got one but we're not supposed to verify it, - // or if we're supposed to verify it and it passes verification, return the path. - if (path.Length == 0 || - option == SpecialFolderOption.DoNotVerify || - Interop.Sys.Access(path, Interop.Sys.AccessMode.R_OK) == 0) - { - return path; - } - - // Failed verification. If None, then we're supposed to return an empty string. - // If Create, we're supposed to create it and then return the path. - if (option == SpecialFolderOption.None) - { - return string.Empty; - } - else - { - Debug.Assert(option == SpecialFolderOption.Create); - - Func createDirectory = LazyInitializer.EnsureInitialized(ref s_directoryCreateDirectory, () => - { - Type dirType = Type.GetType("System.IO.Directory, System.IO.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: true)!; - MethodInfo mi = dirType.GetTypeInfo().GetDeclaredMethod("CreateDirectory")!; - return (Func)mi.CreateDelegate(typeof(Func)); - }); - createDirectory(path); - - return path; - } - } - - private static string GetFolderPathCoreWithoutValidation(SpecialFolder folder) - { - // First handle any paths that involve only static paths, avoiding the overheads of getting user-local paths. - // https://www.freedesktop.org/software/systemd/man/file-hierarchy.html - switch (folder) - { - case SpecialFolder.CommonApplicationData: return "/usr/share"; - case SpecialFolder.CommonTemplates: return "/usr/share/templates"; -#if TARGET_OSX - case SpecialFolder.ProgramFiles: return "/Applications"; - case SpecialFolder.System: return "/System"; -#endif - } - - // All other paths are based on the XDG Base Directory Specification: - // https://specifications.freedesktop.org/basedir-spec/latest/ - string? home = null; - try - { - home = PersistedFiles.GetHomeDirectory(); - } - catch (Exception exc) - { - Debug.Fail($"Unable to get home directory: {exc}"); - } - - // Fall back to '/' when we can't determine the home directory. - // This location isn't writable by non-root users which provides some safeguard - // that the application doesn't write data which is meant to be private. - if (string.IsNullOrEmpty(home)) - { - home = "/"; - } - - // TODO: Consider caching (or precomputing and caching) all subsequent results. - // This would significantly improve performance for repeated access, at the expense - // of not being responsive to changes in the underlying environment variables, - // configuration files, etc. - - switch (folder) - { - case SpecialFolder.UserProfile: - case SpecialFolder.MyDocuments: // same value as Personal - return home; - case SpecialFolder.ApplicationData: - return GetXdgConfig(home); - case SpecialFolder.LocalApplicationData: - // "$XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored." - // "If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used." - string? data = GetEnvironmentVariable("XDG_DATA_HOME"); - if (string.IsNullOrEmpty(data) || data[0] != '/') - { - data = Path.Combine(home, ".local", "share"); - } - return data; - - case SpecialFolder.Desktop: - case SpecialFolder.DesktopDirectory: - return ReadXdgDirectory(home, "XDG_DESKTOP_DIR", "Desktop"); - case SpecialFolder.Templates: - return ReadXdgDirectory(home, "XDG_TEMPLATES_DIR", "Templates"); - case SpecialFolder.MyVideos: - return ReadXdgDirectory(home, "XDG_VIDEOS_DIR", "Videos"); - -#if TARGET_OSX - case SpecialFolder.MyMusic: - return Path.Combine(home, "Music"); - case SpecialFolder.MyPictures: - return Path.Combine(home, "Pictures"); - case SpecialFolder.Fonts: - return Path.Combine(home, "Library", "Fonts"); - case SpecialFolder.Favorites: - return Path.Combine(home, "Library", "Favorites"); - case SpecialFolder.InternetCache: - return Path.Combine(home, "Library", "Caches"); -#else - case SpecialFolder.MyMusic: - return ReadXdgDirectory(home, "XDG_MUSIC_DIR", "Music"); - case SpecialFolder.MyPictures: - return ReadXdgDirectory(home, "XDG_PICTURES_DIR", "Pictures"); - case SpecialFolder.Fonts: - return Path.Combine(home, ".fonts"); -#endif - } - - // No known path for the SpecialFolder - return string.Empty; - } - - private static string GetXdgConfig(string home) - { - // "$XDG_CONFIG_HOME defines the base directory relative to which user specific configuration files should be stored." - // "If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME/.config should be used." - string? config = GetEnvironmentVariable("XDG_CONFIG_HOME"); - if (string.IsNullOrEmpty(config) || config[0] != '/') - { - config = Path.Combine(home, ".config"); - } - return config; - } - - private static string ReadXdgDirectory(string homeDir, string key, string fallback) - { - Debug.Assert(!string.IsNullOrEmpty(homeDir), $"Expected non-empty homeDir"); - Debug.Assert(!string.IsNullOrEmpty(key), $"Expected non-empty key"); - Debug.Assert(!string.IsNullOrEmpty(fallback), $"Expected non-empty fallback"); - - string? envPath = GetEnvironmentVariable(key); - if (!string.IsNullOrEmpty(envPath) && envPath[0] == '/') - { - return envPath; - } - - // Use the user-dirs.dirs file to look up the right config. - // Note that the docs also highlight a list of directories in which to look for this file: - // "$XDG_CONFIG_DIRS defines the preference-ordered set of base directories to search for configuration files in addition - // to the $XDG_CONFIG_HOME base directory. The directories in $XDG_CONFIG_DIRS should be separated with a colon ':'. If - // $XDG_CONFIG_DIRS is either not set or empty, a value equal to / etc / xdg should be used." - // For simplicity, we don't currently do that. We can add it if/when necessary. - - string userDirsPath = Path.Combine(GetXdgConfig(homeDir), "user-dirs.dirs"); - if (Interop.Sys.Access(userDirsPath, Interop.Sys.AccessMode.R_OK) == 0) - { - try - { - using (var reader = new StreamReader(userDirsPath)) - { - string? line; - while ((line = reader.ReadLine()) != null) - { - // Example lines: - // XDG_DESKTOP_DIR="$HOME/Desktop" - // XDG_PICTURES_DIR = "/absolute/path" - - // Skip past whitespace at beginning of line - int pos = 0; - SkipWhitespace(line, ref pos); - if (pos >= line.Length) continue; - - // Skip past requested key name - if (string.CompareOrdinal(line, pos, key, 0, key.Length) != 0) continue; - pos += key.Length; - - // Skip past whitespace and past '=' - SkipWhitespace(line, ref pos); - if (pos >= line.Length - 4 || line[pos] != '=') continue; // 4 for ="" and at least one char between quotes - pos++; // skip past '=' - - // Skip past whitespace and past first quote - SkipWhitespace(line, ref pos); - if (pos >= line.Length - 3 || line[pos] != '"') continue; // 3 for "" and at least one char between quotes - pos++; // skip past opening '"' - - // Skip past relative prefix if one exists - bool relativeToHome = false; - const string RelativeToHomePrefix = "$HOME/"; - if (string.CompareOrdinal(line, pos, RelativeToHomePrefix, 0, RelativeToHomePrefix.Length) == 0) - { - relativeToHome = true; - pos += RelativeToHomePrefix.Length; - } - else if (line[pos] != '/') // if not relative to home, must be absolute path - { - continue; - } - - // Find end of path - int endPos = line.IndexOf('"', pos); - if (endPos <= pos) continue; - - // Got we need. Now extract it. - string path = line.Substring(pos, endPos - pos); - return relativeToHome ? - Path.Combine(homeDir, path) : - path; - } - } - } - catch (Exception exc) - { - // assembly not found, file not found, errors reading file, etc. Just eat everything. - Debug.Fail($"Failed reading {userDirsPath}: {exc}"); - } - } - - return Path.Combine(homeDir, fallback); - } - - private static void SkipWhitespace(string line, ref int pos) - { - while (pos < line.Length && char.IsWhiteSpace(line[pos])) pos++; - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.cs index c29a56c14b53f0..81b516dd45f5df 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.cs @@ -63,66 +63,6 @@ public static string MachineName internal const string NewLineConst = "\n"; - private static OperatingSystem GetOSVersion() => GetOperatingSystem(Interop.Sys.GetUnixRelease()); - - // Tests exercise this method for corner cases via private reflection - private static OperatingSystem GetOperatingSystem(string release) - { - int major = 0, minor = 0, build = 0, revision = 0; - - // Parse the uname's utsname.release for the first four numbers found. - // This isn't perfect, but Version already doesn't map exactly to all possible release - // formats, e.g. 2.6.19-1.2895.fc6 - if (release != null) - { - int i = 0; - major = FindAndParseNextNumber(release, ref i); - minor = FindAndParseNextNumber(release, ref i); - build = FindAndParseNextNumber(release, ref i); - revision = FindAndParseNextNumber(release, ref i); - } - - // For compatibility reasons with Mono, PlatformID.Unix is returned on MacOSX. PlatformID.MacOSX - // is hidden from the editor and shouldn't be used. - return new OperatingSystem(PlatformID.Unix, new Version(major, minor, build, revision)); - } - - private static int FindAndParseNextNumber(string text, ref int pos) - { - // Move to the beginning of the number - for (; pos < text.Length; pos++) - { - char c = text[pos]; - if ('0' <= c && c <= '9') - { - break; - } - } - - // Parse the number; - int num = 0; - for (; pos < text.Length; pos++) - { - char c = text[pos]; - if ('0' > c || c > '9') - break; - - try - { - num = checked((num * 10) + (c - '0')); - } - // Integer overflow can occur for example with: - // Linux nelknet 4.15.0-24201807041620-generic - // To form a valid Version, num must be positive. - catch (OverflowException) - { - return int.MaxValue; - } - } - - return num; - } - public static string SystemDirectory => GetFolderPathCore(SpecialFolder.System, SpecialFolderOption.None); public static int SystemPageSize => CheckedSysConf(Interop.Sys.SysConfName._SC_PAGESIZE); diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.cs index a71c68131c5403..d3f03d05197ce8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.cs @@ -142,10 +142,7 @@ public static Version Version { get { - // FX_PRODUCT_VERSION is expected to be set by the host - // Use AssemblyInformationalVersionAttribute as fallback if the exact product version is not specified by the host - string? versionString = AppContext.GetData("FX_PRODUCT_VERSION") as string ?? - typeof(object).Assembly.GetCustomAttribute()?.InformationalVersion; + string? versionString = typeof(object).Assembly.GetCustomAttribute()?.InformationalVersion; ReadOnlySpan versionSpan = versionString.AsSpan(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/Calendar.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/Calendar.cs index 7d86971a87919f..48e34ffaad35cd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/Calendar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/Calendar.cs @@ -725,7 +725,7 @@ internal static long TimeToTicks(int hour, int minute, int second, int milliseco internal static int GetSystemTwoDigitYearSetting(CalendarId CalID, int defaultYearValue) { - int twoDigitYearMax = CalendarData.GetTwoDigitYearMax(CalID); + int twoDigitYearMax = GlobalizationMode.UseNls ? CalendarData.NlsGetTwoDigitYearMax(CalID) : CalendarData.IcuGetTwoDigitYearMax(CalID); return twoDigitYearMax >= 0 ? twoDigitYearMax : defaultYearValue; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Icu.cs new file mode 100644 index 00000000000000..b58bc4a311ec19 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Icu.cs @@ -0,0 +1,465 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using Internal.Runtime.CompilerServices; + +namespace System.Globalization +{ + // needs to be kept in sync with CalendarDataType in System.Globalization.Native + internal enum CalendarDataType + { + Uninitialized = 0, + NativeName = 1, + MonthDay = 2, + ShortDates = 3, + LongDates = 4, + YearMonths = 5, + DayNames = 6, + AbbrevDayNames = 7, + MonthNames = 8, + AbbrevMonthNames = 9, + SuperShortDayNames = 10, + MonthGenitiveNames = 11, + AbbrevMonthGenitiveNames = 12, + EraNames = 13, + AbbrevEraNames = 14, + } + + internal partial class CalendarData + { + private bool IcuLoadCalendarDataFromSystem(string localeName, CalendarId calendarId) + { + Debug.Assert(!GlobalizationMode.UseNls); + + bool result = true; + + // these can return null but are later replaced with String.Empty or other non-nullable value + result &= GetCalendarInfo(localeName, calendarId, CalendarDataType.NativeName, out this.sNativeName!); + result &= GetCalendarInfo(localeName, calendarId, CalendarDataType.MonthDay, out this.sMonthDay!); + + if (this.sMonthDay != null) + { + this.sMonthDay = NormalizeDatePattern(this.sMonthDay); + } + + result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.ShortDates, out this.saShortDates!); + result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.LongDates, out this.saLongDates!); + result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.YearMonths, out this.saYearMonths!); + result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.DayNames, out this.saDayNames!); + result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.AbbrevDayNames, out this.saAbbrevDayNames!); + result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.SuperShortDayNames, out this.saSuperShortDayNames!); + + string? leapHebrewMonthName = null; + result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthNames, out this.saMonthNames!, ref leapHebrewMonthName); + if (leapHebrewMonthName != null) + { + Debug.Assert(this.saMonthNames != null); + + // In Hebrew calendar, get the leap month name Adar II and override the non-leap month 7 + Debug.Assert(calendarId == CalendarId.HEBREW && saMonthNames.Length == 13); + saLeapYearMonthNames = (string[]) saMonthNames.Clone(); + saLeapYearMonthNames[6] = leapHebrewMonthName; + + // The returned data from ICU has 6th month name as 'Adar I' and 7th month name as 'Adar' + // We need to adjust that in the list used with non-leap year to have 6th month as 'Adar' and 7th month as 'Adar II' + // note that when formatting non-leap year dates, 7th month shouldn't get used at all. + saMonthNames[5] = saMonthNames[6]; + saMonthNames[6] = leapHebrewMonthName; + + } + result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthNames, out this.saAbbrevMonthNames!, ref leapHebrewMonthName); + result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthGenitiveNames, out this.saMonthGenitiveNames!, ref leapHebrewMonthName); + result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames, out this.saAbbrevMonthGenitiveNames!, ref leapHebrewMonthName); + + result &= EnumEraNames(localeName, calendarId, CalendarDataType.EraNames, out this.saEraNames!); + result &= EnumEraNames(localeName, calendarId, CalendarDataType.AbbrevEraNames, out this.saAbbrevEraNames!); + + return result; + } + + internal static int IcuGetTwoDigitYearMax(CalendarId calendarId) + { + Debug.Assert(!GlobalizationMode.UseNls); + + // There is no user override for this value on Linux or in ICU. + // So just return -1 to use the hard-coded defaults. + return -1; + } + + // Call native side to figure out which calendars are allowed + internal static int IcuGetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + // NOTE: there are no 'user overrides' on Linux + int count = Interop.Globalization.GetCalendars(localeName, calendars, calendars.Length); + + // ensure there is at least 1 calendar returned + if (count == 0 && calendars.Length > 0) + { + calendars[0] = CalendarId.GREGORIAN; + count = 1; + } + + return count; + } + + private static bool IcuSystemSupportsTaiwaneseCalendar() + { + Debug.Assert(!GlobalizationMode.UseNls); + return true; + } + + // PAL Layer ends here + + private static unsafe bool GetCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, out string? calendarString) + { + Debug.Assert(!GlobalizationMode.Invariant); + + return Interop.CallStringMethod( + (buffer, locale, id, type) => + { + fixed (char* bufferPtr = buffer) + { + return Interop.Globalization.GetCalendarInfo(locale, id, type, bufferPtr, buffer.Length); + } + }, + localeName, + calendarId, + dataType, + out calendarString); + } + + private static bool EnumDatePatterns(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[]? datePatterns) + { + datePatterns = null; + + IcuEnumCalendarsData callbackContext = default; + callbackContext.Results = new List(); + callbackContext.DisallowDuplicates = true; + bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext); + if (result) + { + List datePatternsList = callbackContext.Results; + + for (int i = 0; i < datePatternsList.Count; i++) + { + datePatternsList[i] = NormalizeDatePattern(datePatternsList[i]); + } + + if (dataType == CalendarDataType.ShortDates) + FixDefaultShortDatePattern(datePatternsList); + + datePatterns = datePatternsList.ToArray(); + } + + return result; + } + + // FixDefaultShortDatePattern will convert the default short date pattern from using 'yy' to using 'yyyy' + // And will ensure the original pattern still exist in the list. + // doing that will have the short date pattern format the year as 4-digit number and not just 2-digit number. + // Example: June 5, 2018 will be formatted to something like 6/5/2018 instead of 6/5/18 fro en-US culture. + private static void FixDefaultShortDatePattern(List shortDatePatterns) + { + if (shortDatePatterns.Count == 0) + return; + + string s = shortDatePatterns[0]; + + // We are not expecting any pattern have length more than 100. + // We have to do this check to prevent stack overflow as we allocate the buffer on the stack. + if (s.Length > 100) + return; + + Span modifiedPattern = stackalloc char[s.Length + 2]; + int index = 0; + + while (index < s.Length) + { + if (s[index] == '\'') + { + do + { + modifiedPattern[index] = s[index]; + index++; + } while (index < s.Length && s[index] != '\''); + + if (index >= s.Length) + return; + } + else if (s[index] == 'y') + { + modifiedPattern[index] = 'y'; + break; + } + + modifiedPattern[index] = s[index]; + index++; + } + + if (index >= s.Length - 1 || s[index + 1] != 'y') + { + // not a 'yy' pattern + return; + } + + if (index + 2 < s.Length && s[index + 2] == 'y') + { + // we have 'yyy' then nothing to do + return; + } + + // we are sure now we have 'yy' pattern + + Debug.Assert(index + 3 < modifiedPattern.Length); + + modifiedPattern[index + 1] = 'y'; // second y + modifiedPattern[index + 2] = 'y'; // third y + modifiedPattern[index + 3] = 'y'; // fourth y + + index += 2; + + // Now, copy the rest of the pattern to the destination buffer + while (index < s.Length) + { + modifiedPattern[index + 2] = s[index]; + index++; + } + + shortDatePatterns[0] = modifiedPattern.ToString(); + + for (int i = 1; i < shortDatePatterns.Count; i++) + { + if (shortDatePatterns[i] == shortDatePatterns[0]) + { + // Found match in the list to the new constructed pattern, then replace it with the original modified pattern + shortDatePatterns[i] = s; + return; + } + } + + // if we come here means the newly constructed pattern not found on the list, then add the original pattern + shortDatePatterns.Add(s); + } + + /// + /// The ICU date format characters are not exactly the same as the .NET date format characters. + /// NormalizeDatePattern will take in an ICU date pattern and return the equivalent .NET date pattern. + /// + /// + /// see Date Field Symbol Table in http://userguide.icu-project.org/formatparse/datetime + /// and https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx + /// + private static string NormalizeDatePattern(string input) + { + StringBuilder destination = StringBuilderCache.Acquire(input.Length); + + int index = 0; + while (index < input.Length) + { + switch (input[index]) + { + case '\'': + // single quotes escape characters, like 'de' in es-SP + // so read verbatim until the next single quote + destination.Append(input[index++]); + while (index < input.Length) + { + char current = input[index++]; + destination.Append(current); + if (current == '\'') + { + break; + } + } + break; + case 'E': + case 'e': + case 'c': + // 'E' in ICU is the day of the week, which maps to 3 or 4 'd's in .NET + // 'e' in ICU is the local day of the week, which has no representation in .NET, but + // maps closest to 3 or 4 'd's in .NET + // 'c' in ICU is the stand-alone day of the week, which has no representation in .NET, but + // maps closest to 3 or 4 'd's in .NET + NormalizeDayOfWeek(input, destination, ref index); + break; + case 'L': + case 'M': + // 'L' in ICU is the stand-alone name of the month, + // which maps closest to 'M' in .NET since it doesn't support stand-alone month names in patterns + // 'M' in both ICU and .NET is the month, + // but ICU supports 5 'M's, which is the super short month name + int occurrences = CountOccurrences(input, input[index], ref index); + if (occurrences > 4) + { + // 5 'L's or 'M's in ICU is the super short name, which maps closest to MMM in .NET + occurrences = 3; + } + destination.Append('M', occurrences); + break; + case 'G': + // 'G' in ICU is the era, which maps to 'g' in .NET + occurrences = CountOccurrences(input, 'G', ref index); + + // it doesn't matter how many 'G's, since .NET only supports 'g' or 'gg', and they + // have the same meaning + destination.Append('g'); + break; + case 'y': + // a single 'y' in ICU is the year with no padding or trimming. + // a single 'y' in .NET is the year with 1 or 2 digits + // so convert any single 'y' to 'yyyy' + occurrences = CountOccurrences(input, 'y', ref index); + if (occurrences == 1) + { + occurrences = 4; + } + destination.Append('y', occurrences); + break; + default: + const string unsupportedDateFieldSymbols = "YuUrQqwWDFg"; + Debug.Assert(!unsupportedDateFieldSymbols.Contains(input[index]), + $"Encountered an unexpected date field symbol '{input[index]}' from ICU which has no known corresponding .NET equivalent."); + + destination.Append(input[index++]); + break; + } + } + + return StringBuilderCache.GetStringAndRelease(destination); + } + + private static void NormalizeDayOfWeek(string input, StringBuilder destination, ref int index) + { + char dayChar = input[index]; + int occurrences = CountOccurrences(input, dayChar, ref index); + occurrences = Math.Max(occurrences, 3); + if (occurrences > 4) + { + // 5 and 6 E/e/c characters in ICU is the super short names, which maps closest to ddd in .NET + occurrences = 3; + } + + destination.Append('d', occurrences); + } + + private static int CountOccurrences(string input, char value, ref int index) + { + int startIndex = index; + while (index < input.Length && input[index] == value) + { + index++; + } + + return index - startIndex; + } + + private static bool EnumMonthNames(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[]? monthNames, ref string? leapHebrewMonthName) + { + monthNames = null; + + IcuEnumCalendarsData callbackContext = default; + callbackContext.Results = new List(); + bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext); + if (result) + { + // the month-name arrays are expected to have 13 elements. If ICU only returns 12, add an + // extra empty string to fill the array. + if (callbackContext.Results.Count == 12) + { + callbackContext.Results.Add(string.Empty); + } + + if (callbackContext.Results.Count > 13) + { + Debug.Assert(calendarId == CalendarId.HEBREW && callbackContext.Results.Count == 14); + + if (calendarId == CalendarId.HEBREW) + { + leapHebrewMonthName = callbackContext.Results[13]; + } + callbackContext.Results.RemoveRange(13, callbackContext.Results.Count - 13); + } + + monthNames = callbackContext.Results.ToArray(); + } + + return result; + } + + private static bool EnumEraNames(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[]? eraNames) + { + bool result = EnumCalendarInfo(localeName, calendarId, dataType, out eraNames); + + // .NET expects that only the Japanese calendars have more than 1 era. + // So for other calendars, only return the latest era. + if (calendarId != CalendarId.JAPAN && calendarId != CalendarId.JAPANESELUNISOLAR && eraNames?.Length > 0) + { + string[] latestEraName = new string[] { eraNames![eraNames.Length - 1] }; + eraNames = latestEraName; + } + + return result; + } + + internal static bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[]? calendarData) + { + calendarData = null; + + IcuEnumCalendarsData callbackContext = default; + callbackContext.Results = new List(); + bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext); + if (result) + { + calendarData = callbackContext.Results.ToArray(); + } + + return result; + } + + private static unsafe bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, ref IcuEnumCalendarsData callbackContext) + { + return Interop.Globalization.EnumCalendarInfo(EnumCalendarInfoCallback, localeName, calendarId, dataType, (IntPtr)Unsafe.AsPointer(ref callbackContext)); + } + + private static unsafe void EnumCalendarInfoCallback(string calendarString, IntPtr context) + { + try + { + ref IcuEnumCalendarsData callbackContext = ref Unsafe.As(ref *(byte*)context); + + if (callbackContext.DisallowDuplicates) + { + foreach (string existingResult in callbackContext.Results) + { + if (string.Equals(calendarString, existingResult, StringComparison.Ordinal)) + { + // the value is already in the results, so don't add it again + return; + } + } + } + + callbackContext.Results.Add(calendarString); + } + catch (Exception e) + { + Debug.Fail(e.ToString()); + // we ignore the managed exceptions here because EnumCalendarInfoCallback will get called from the native code. + // If we don't ignore the exception here that can cause the runtime to fail fast. + } + } + + private struct IcuEnumCalendarsData + { + public List Results; + public bool DisallowDuplicates; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Nls.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Nls.cs new file mode 100644 index 00000000000000..a42c8724af72cd --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Nls.cs @@ -0,0 +1,456 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Collections.Generic; +using Internal.Runtime.CompilerServices; + +namespace System.Globalization +{ + internal partial class CalendarData + { + private bool NlsLoadCalendarDataFromSystem(string localeName, CalendarId calendarId) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + + bool ret = true; + + uint useOverrides = this.bUseUserOverrides ? 0 : CAL_NOUSEROVERRIDE; + + // + // Windows doesn't support some calendars right now, so remap those. + // + switch (calendarId) + { + case CalendarId.JAPANESELUNISOLAR: // Data looks like Japanese + calendarId = CalendarId.JAPAN; + break; + case CalendarId.JULIAN: // Data looks like gregorian US + case CalendarId.CHINESELUNISOLAR: // Algorithmic, so actual data is irrelevent + case CalendarId.SAKA: // reserved to match Office but not implemented in our code, so data is irrelevent + case CalendarId.LUNAR_ETO_CHN: // reserved to match Office but not implemented in our code, so data is irrelevent + case CalendarId.LUNAR_ETO_KOR: // reserved to match Office but not implemented in our code, so data is irrelevent + case CalendarId.LUNAR_ETO_ROKUYOU: // reserved to match Office but not implemented in our code, so data is irrelevent + case CalendarId.KOREANLUNISOLAR: // Algorithmic, so actual data is irrelevent + case CalendarId.TAIWANLUNISOLAR: // Algorithmic, so actual data is irrelevent + calendarId = CalendarId.GREGORIAN_US; + break; + } + + // + // Special handling for some special calendar due to OS limitation. + // This includes calendar like Taiwan calendar, UmAlQura calendar, etc. + // + CheckSpecialCalendar(ref calendarId, ref localeName); + + // Numbers + ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_ITWODIGITYEARMAX | useOverrides, out this.iTwoDigitYearMax); + + // Strings + ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_SCALNAME, out this.sNativeName); + ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_SMONTHDAY | useOverrides, out this.sMonthDay); + + // String Arrays + // Formats + ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SSHORTDATE, LOCALE_SSHORTDATE | useOverrides, out this.saShortDates!); + ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SLONGDATE, LOCALE_SLONGDATE | useOverrides, out this.saLongDates!); + + // Get the YearMonth pattern. + ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SYEARMONTH, LOCALE_SYEARMONTH, out this.saYearMonths!); + + // Day & Month Names + // These are all single calType entries, 1 per day, so we have to make 7 or 13 calls to collect all the names + + // Day + // Note that we're off-by-one since managed starts on sunday and windows starts on monday + ret &= GetCalendarDayInfo(localeName, calendarId, CAL_SDAYNAME7, out this.saDayNames); + ret &= GetCalendarDayInfo(localeName, calendarId, CAL_SABBREVDAYNAME7, out this.saAbbrevDayNames); + + // Month names + ret &= GetCalendarMonthInfo(localeName, calendarId, CAL_SMONTHNAME1, out this.saMonthNames); + ret &= GetCalendarMonthInfo(localeName, calendarId, CAL_SABBREVMONTHNAME1, out this.saAbbrevMonthNames); + + // + // The following LCTYPE are not supported in some platforms. If the call fails, + // don't return a failure. + // + GetCalendarDayInfo(localeName, calendarId, CAL_SSHORTESTDAYNAME7, out this.saSuperShortDayNames); + + // Gregorian may have genitive month names + if (calendarId == CalendarId.GREGORIAN) + { + GetCalendarMonthInfo(localeName, calendarId, CAL_SMONTHNAME1 | CAL_RETURN_GENITIVE_NAMES, out this.saMonthGenitiveNames); + GetCalendarMonthInfo(localeName, calendarId, CAL_SABBREVMONTHNAME1 | CAL_RETURN_GENITIVE_NAMES, out this.saAbbrevMonthGenitiveNames); + } + + // Calendar Parts Names + // This doesn't get always get localized names for gregorian (not available in windows < 7) + // so: eg: coreclr on win < 7 won't get these + CallEnumCalendarInfo(localeName, calendarId, CAL_SERASTRING, 0, out this.saEraNames!); + CallEnumCalendarInfo(localeName, calendarId, CAL_SABBREVERASTRING, 0, out this.saAbbrevEraNames!); + + // + // Calendar Era Info + // Note that calendar era data (offsets, etc) is hard coded for each calendar since this + // data is implementation specific and not dynamic (except perhaps Japanese) + // + + // Clean up the escaping of the formats + this.saShortDates = CultureData.ReescapeWin32Strings(this.saShortDates)!; + this.saLongDates = CultureData.ReescapeWin32Strings(this.saLongDates)!; + this.saYearMonths = CultureData.ReescapeWin32Strings(this.saYearMonths)!; + this.sMonthDay = CultureData.ReescapeWin32String(this.sMonthDay)!; + + return ret; + } + + // Get native two digit year max + internal static int NlsGetTwoDigitYearMax(CalendarId calendarId) + { + Debug.Assert(GlobalizationMode.UseNls); + + return GlobalizationMode.Invariant ? Invariant.iTwoDigitYearMax : + CallGetCalendarInfoEx(null, calendarId, CAL_ITWODIGITYEARMAX, out int twoDigitYearMax) ? + twoDigitYearMax : + -1; + } + + // Call native side to figure out which calendars are allowed + internal static int NlsGetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + + NlsEnumCalendarsData data = default; + data.userOverride = 0; + data.calendars = new List(); + + // First call GetLocaleInfo if necessary + if (useUserOverride) + { + // They want user overrides, see if the user calendar matches the input calendar + int userCalendar = CultureData.GetLocaleInfoExInt(localeName, LOCALE_ICALENDARTYPE); + + // If we got a default, then use it as the first calendar + if (userCalendar != 0) + { + data.userOverride = userCalendar; + data.calendars.Add(userCalendar); + } + } + + unsafe + { + Interop.Kernel32.EnumCalendarInfoExEx(EnumCalendarsCallback, localeName, ENUM_ALL_CALENDARS, null, CAL_ICALINTVALUE, Unsafe.AsPointer(ref data)); + } + + // Copy to the output array + for (int i = 0; i < Math.Min(calendars.Length, data.calendars.Count); i++) + calendars[i] = (CalendarId)data.calendars[i]; + + // Now we have a list of data, return the count + return data.calendars.Count; + } + + private static bool NlsSystemSupportsTaiwaneseCalendar() + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + + // Taiwanese calendar get listed as one of the optional zh-TW calendars only when having zh-TW UI + return CallGetCalendarInfoEx("zh-TW", CalendarId.TAIWAN, CAL_SCALNAME, out string _); + } + + // PAL Layer ends here + + private const uint CAL_RETURN_NUMBER = 0x20000000; + private const uint CAL_RETURN_GENITIVE_NAMES = 0x10000000; + private const uint CAL_NOUSEROVERRIDE = 0x80000000; + private const uint CAL_SCALNAME = 0x00000002; + private const uint CAL_SMONTHDAY = 0x00000038; + private const uint CAL_SSHORTDATE = 0x00000005; + private const uint CAL_SLONGDATE = 0x00000006; + private const uint CAL_SYEARMONTH = 0x0000002f; + private const uint CAL_SDAYNAME7 = 0x0000000d; + private const uint CAL_SABBREVDAYNAME7 = 0x00000014; + private const uint CAL_SMONTHNAME1 = 0x00000015; + private const uint CAL_SABBREVMONTHNAME1 = 0x00000022; + private const uint CAL_SSHORTESTDAYNAME7 = 0x00000037; + private const uint CAL_SERASTRING = 0x00000004; + private const uint CAL_SABBREVERASTRING = 0x00000039; + private const uint CAL_ICALINTVALUE = 0x00000001; + private const uint CAL_ITWODIGITYEARMAX = 0x00000030; + + private const uint ENUM_ALL_CALENDARS = 0xffffffff; + + private const uint LOCALE_SSHORTDATE = 0x0000001F; + private const uint LOCALE_SLONGDATE = 0x00000020; + private const uint LOCALE_SYEARMONTH = 0x00001006; + private const uint LOCALE_ICALENDARTYPE = 0x00001009; + + //////////////////////////////////////////////////////////////////////// + // + // For calendars like Gregorain US/Taiwan/UmAlQura, they are not available + // in all OS or all localized versions of OS. + // If OS does not support these calendars, we will fallback by using the + // appropriate fallback calendar and locale combination to retrieve data from OS. + // + // Parameters: + // __deref_inout pCalendarInt: + // Pointer to the calendar ID. This will be updated to new fallback calendar ID if needed. + // __in_out pLocaleNameStackBuffer + // Pointer to the StackSString object which holds the locale name to be checked. + // This will be updated to new fallback locale name if needed. + // + //////////////////////////////////////////////////////////////////////// + private static void CheckSpecialCalendar(ref CalendarId calendar, ref string localeName) + { + // Gregorian-US isn't always available in the OS, however it is the same for all locales + switch (calendar) + { + case CalendarId.GREGORIAN_US: + // See if this works + if (!CallGetCalendarInfoEx(localeName, calendar, CAL_SCALNAME, out string _)) + { + // Failed, set it to a locale (fa-IR) that's alway has Gregorian US available in the OS + localeName = "fa-IR"; + } + // See if that works + if (!CallGetCalendarInfoEx(localeName, calendar, CAL_SCALNAME, out string _)) + { + // Failed again, just use en-US with the gregorian calendar + localeName = "en-US"; + calendar = CalendarId.GREGORIAN; + } + break; + case CalendarId.TAIWAN: + // Taiwan calendar data is not always in all language version of OS due to Geopolical reasons. + // It is only available in zh-TW localized versions of Windows. + // Let's check if OS supports it. If not, fallback to Greogrian localized for Taiwan calendar. + if (!NlsSystemSupportsTaiwaneseCalendar()) + { + calendar = CalendarId.GREGORIAN; + } + break; + } + } + + private static bool CallGetCalendarInfoEx(string? localeName, CalendarId calendar, uint calType, out int data) + { + return Interop.Kernel32.GetCalendarInfoEx(localeName, (uint)calendar, IntPtr.Zero, calType | CAL_RETURN_NUMBER, IntPtr.Zero, 0, out data) != 0; + } + + private static unsafe bool CallGetCalendarInfoEx(string localeName, CalendarId calendar, uint calType, out string data) + { + const int BUFFER_LENGTH = 80; + + // The maximum size for values returned from GetCalendarInfoEx is 80 characters. + char* buffer = stackalloc char[BUFFER_LENGTH]; + + int ret = Interop.Kernel32.GetCalendarInfoEx(localeName, (uint)calendar, IntPtr.Zero, calType, (IntPtr)buffer, BUFFER_LENGTH, IntPtr.Zero); + if (ret > 0) + { + if (buffer[ret - 1] == '\0') + { + ret--; // don't include the null termination in the string + } + data = new string(buffer, 0, ret); + return true; + } + data = ""; + return false; + } + + // Context for EnumCalendarInfoExEx callback. + private struct EnumData + { + public string? userOverride; + public List? strings; + } + + // EnumCalendarInfoExEx callback itself. + // [UnmanagedCallersOnly(CallingConvention = CallingConvention.StdCall)] + private static unsafe Interop.BOOL EnumCalendarInfoCallback(char* lpCalendarInfoString, uint calendar, IntPtr pReserved, void* lParam) + { + ref EnumData context = ref Unsafe.As(ref *(byte*)lParam); + try + { + string calendarInfo = new string(lpCalendarInfoString); + + // If we had a user override, check to make sure this differs + if (context.userOverride != calendarInfo) + { + Debug.Assert(context.strings != null); + context.strings.Add(calendarInfo); + } + + return Interop.BOOL.TRUE; + } + catch (Exception) + { + return Interop.BOOL.FALSE; + } + } + + private static unsafe bool CallEnumCalendarInfo(string localeName, CalendarId calendar, uint calType, uint lcType, out string[]? data) + { + EnumData context = default; + context.userOverride = null; + context.strings = new List(); + // First call GetLocaleInfo if necessary + if ((lcType != 0) && ((lcType & CAL_NOUSEROVERRIDE) == 0) && + // Get user locale, see if it matches localeName. + // Note that they should match exactly, including letter case + GetUserDefaultLocaleName() == localeName) + { + // They want user overrides, see if the user calendar matches the input calendar + CalendarId userCalendar = (CalendarId)CultureData.GetLocaleInfoExInt(localeName, LOCALE_ICALENDARTYPE); + + // If the calendars were the same, see if the locales were the same + if (userCalendar == calendar) + { + // They matched, get the user override since locale & calendar match + string? res = CultureData.GetLocaleInfoEx(localeName, lcType); + + // if it succeeded remember the override for the later callers + if (res != null) + { + // Remember this was the override (so we can look for duplicates later in the enum function) + context.userOverride = res; + + // Add to the result strings. + context.strings.Add(res); + } + } + } + + // Now call the enumeration API. Work is done by our callback function + Interop.Kernel32.EnumCalendarInfoExEx(EnumCalendarInfoCallback, localeName, (uint)calendar, null, calType, Unsafe.AsPointer(ref context)); + + // Now we have a list of data, fail if we didn't find anything. + Debug.Assert(context.strings != null); + if (context.strings.Count == 0) + { + data = null; + return false; + } + + string[] output = context.strings.ToArray(); + + if (calType == CAL_SABBREVERASTRING || calType == CAL_SERASTRING) + { + // Eras are enumerated backwards. (oldest era name first, but + // Japanese calendar has newest era first in array, and is only + // calendar with multiple eras) + Array.Reverse(output, 0, output.Length); + } + + data = output; + + return true; + } + + //////////////////////////////////////////////////////////////////////// + // + // Get the native day names + // + // NOTE: There's a disparity between .NET & windows day orders, the input day should + // start with Sunday + // + // Parameters: + // OUT pOutputStrings The output string[] value. + // + //////////////////////////////////////////////////////////////////////// + private static bool GetCalendarDayInfo(string localeName, CalendarId calendar, uint calType, out string[] outputStrings) + { + bool result = true; + + // + // We'll need a new array of 7 items + // + string[] results = new string[7]; + + // Get each one of them + for (int i = 0; i < 7; i++, calType++) + { + result &= CallGetCalendarInfoEx(localeName, calendar, calType, out results[i]); + + // On the first iteration we need to go from CAL_SDAYNAME7 to CAL_SDAYNAME1, so subtract 7 before the ++ happens + // This is because the framework starts on sunday and windows starts on monday when counting days + if (i == 0) + calType -= 7; + } + + outputStrings = results; + + return result; + } + + //////////////////////////////////////////////////////////////////////// + // + // Get the native month names + // + // Parameters: + // OUT pOutputStrings The output string[] value. + // + //////////////////////////////////////////////////////////////////////// + private static bool GetCalendarMonthInfo(string localeName, CalendarId calendar, uint calType, out string[] outputStrings) + { + // + // We'll need a new array of 13 items + // + string[] results = new string[13]; + + // Get each one of them + for (int i = 0; i < 13; i++, calType++) + { + if (!CallGetCalendarInfoEx(localeName, calendar, calType, out results[i])) + results[i] = ""; + } + + outputStrings = results; + + return true; + } + + // + // struct to help our calendar data enumaration callback + // + public struct NlsEnumCalendarsData + { + public int userOverride; // user override value (if found) + public List calendars; // list of calendars found so far + } + + // [UnmanagedCallersOnly(CallingConvention = CallingConvention.StdCall)] + private static unsafe Interop.BOOL EnumCalendarsCallback(char* lpCalendarInfoString, uint calendar, IntPtr reserved, void* lParam) + { + ref NlsEnumCalendarsData context = ref Unsafe.As(ref *(byte*)lParam); + try + { + // If we had a user override, check to make sure this differs + if (context.userOverride != calendar) + context.calendars.Add((int)calendar); + + return Interop.BOOL.TRUE; + } + catch (Exception) + { + return Interop.BOOL.FALSE; + } + } + + private static unsafe string GetUserDefaultLocaleName() + { + Debug.Assert(!GlobalizationMode.Invariant); + + int result; + char* localeName = stackalloc char[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH]; + result = CultureData.GetLocaleInfoEx(Interop.Kernel32.LOCALE_NAME_USER_DEFAULT, Interop.Kernel32.LOCALE_SNAME, localeName, Interop.Kernel32.LOCALE_NAME_MAX_LENGTH); + + return result <= 0 ? "" : new string(localeName, 0, result - 1); // exclude the null termination + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Unix.cs deleted file mode 100644 index e62a707684cc09..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Unix.cs +++ /dev/null @@ -1,459 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; -using Internal.Runtime.CompilerServices; - -namespace System.Globalization -{ - // needs to be kept in sync with CalendarDataType in System.Globalization.Native - internal enum CalendarDataType - { - Uninitialized = 0, - NativeName = 1, - MonthDay = 2, - ShortDates = 3, - LongDates = 4, - YearMonths = 5, - DayNames = 6, - AbbrevDayNames = 7, - MonthNames = 8, - AbbrevMonthNames = 9, - SuperShortDayNames = 10, - MonthGenitiveNames = 11, - AbbrevMonthGenitiveNames = 12, - EraNames = 13, - AbbrevEraNames = 14, - } - - internal partial class CalendarData - { - private bool LoadCalendarDataFromSystem(string localeName, CalendarId calendarId) - { - bool result = true; - - // these can return null but are later replaced with String.Empty or other non-nullable value - result &= GetCalendarInfo(localeName, calendarId, CalendarDataType.NativeName, out this.sNativeName!); - result &= GetCalendarInfo(localeName, calendarId, CalendarDataType.MonthDay, out this.sMonthDay!); - - if (this.sMonthDay != null) - { - this.sMonthDay = NormalizeDatePattern(this.sMonthDay); - } - - result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.ShortDates, out this.saShortDates!); - result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.LongDates, out this.saLongDates!); - result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.YearMonths, out this.saYearMonths!); - result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.DayNames, out this.saDayNames!); - result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.AbbrevDayNames, out this.saAbbrevDayNames!); - result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.SuperShortDayNames, out this.saSuperShortDayNames!); - - string? leapHebrewMonthName = null; - result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthNames, out this.saMonthNames!, ref leapHebrewMonthName); - if (leapHebrewMonthName != null) - { - Debug.Assert(this.saMonthNames != null); - - // In Hebrew calendar, get the leap month name Adar II and override the non-leap month 7 - Debug.Assert(calendarId == CalendarId.HEBREW && saMonthNames.Length == 13); - saLeapYearMonthNames = (string[]) saMonthNames.Clone(); - saLeapYearMonthNames[6] = leapHebrewMonthName; - - // The returned data from ICU has 6th month name as 'Adar I' and 7th month name as 'Adar' - // We need to adjust that in the list used with non-leap year to have 6th month as 'Adar' and 7th month as 'Adar II' - // note that when formatting non-leap year dates, 7th month shouldn't get used at all. - saMonthNames[5] = saMonthNames[6]; - saMonthNames[6] = leapHebrewMonthName; - - } - result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthNames, out this.saAbbrevMonthNames!, ref leapHebrewMonthName); - result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthGenitiveNames, out this.saMonthGenitiveNames!, ref leapHebrewMonthName); - result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames, out this.saAbbrevMonthGenitiveNames!, ref leapHebrewMonthName); - - result &= EnumEraNames(localeName, calendarId, CalendarDataType.EraNames, out this.saEraNames!); - result &= EnumEraNames(localeName, calendarId, CalendarDataType.AbbrevEraNames, out this.saAbbrevEraNames!); - - return result; - } - - internal static int GetTwoDigitYearMax(CalendarId calendarId) - { - // There is no user override for this value on Linux or in ICU. - // So just return -1 to use the hard-coded defaults. - return -1; - } - - // Call native side to figure out which calendars are allowed - internal static int GetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars) - { - Debug.Assert(!GlobalizationMode.Invariant); - - // NOTE: there are no 'user overrides' on Linux - int count = Interop.Globalization.GetCalendars(localeName, calendars, calendars.Length); - - // ensure there is at least 1 calendar returned - if (count == 0 && calendars.Length > 0) - { - calendars[0] = CalendarId.GREGORIAN; - count = 1; - } - - return count; - } - - private static bool SystemSupportsTaiwaneseCalendar() - { - return true; - } - - // PAL Layer ends here - - private static unsafe bool GetCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, out string? calendarString) - { - Debug.Assert(!GlobalizationMode.Invariant); - - return Interop.CallStringMethod( - (buffer, locale, id, type) => - { - fixed (char* bufferPtr = buffer) - { - return Interop.Globalization.GetCalendarInfo(locale, id, type, bufferPtr, buffer.Length); - } - }, - localeName, - calendarId, - dataType, - out calendarString); - } - - private static bool EnumDatePatterns(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[]? datePatterns) - { - datePatterns = null; - - EnumCalendarsData callbackContext = default; - callbackContext.Results = new List(); - callbackContext.DisallowDuplicates = true; - bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext); - if (result) - { - List datePatternsList = callbackContext.Results; - - for (int i = 0; i < datePatternsList.Count; i++) - { - datePatternsList[i] = NormalizeDatePattern(datePatternsList[i]); - } - - if (dataType == CalendarDataType.ShortDates) - FixDefaultShortDatePattern(datePatternsList); - - datePatterns = datePatternsList.ToArray(); - } - - return result; - } - - // FixDefaultShortDatePattern will convert the default short date pattern from using 'yy' to using 'yyyy' - // And will ensure the original pattern still exist in the list. - // doing that will have the short date pattern format the year as 4-digit number and not just 2-digit number. - // Example: June 5, 2018 will be formatted to something like 6/5/2018 instead of 6/5/18 fro en-US culture. - private static void FixDefaultShortDatePattern(List shortDatePatterns) - { - if (shortDatePatterns.Count == 0) - return; - - string s = shortDatePatterns[0]; - - // We are not expecting any pattern have length more than 100. - // We have to do this check to prevent stack overflow as we allocate the buffer on the stack. - if (s.Length > 100) - return; - - Span modifiedPattern = stackalloc char[s.Length + 2]; - int index = 0; - - while (index < s.Length) - { - if (s[index] == '\'') - { - do - { - modifiedPattern[index] = s[index]; - index++; - } while (index < s.Length && s[index] != '\''); - - if (index >= s.Length) - return; - } - else if (s[index] == 'y') - { - modifiedPattern[index] = 'y'; - break; - } - - modifiedPattern[index] = s[index]; - index++; - } - - if (index >= s.Length - 1 || s[index + 1] != 'y') - { - // not a 'yy' pattern - return; - } - - if (index + 2 < s.Length && s[index + 2] == 'y') - { - // we have 'yyy' then nothing to do - return; - } - - // we are sure now we have 'yy' pattern - - Debug.Assert(index + 3 < modifiedPattern.Length); - - modifiedPattern[index + 1] = 'y'; // second y - modifiedPattern[index + 2] = 'y'; // third y - modifiedPattern[index + 3] = 'y'; // fourth y - - index += 2; - - // Now, copy the rest of the pattern to the destination buffer - while (index < s.Length) - { - modifiedPattern[index + 2] = s[index]; - index++; - } - - shortDatePatterns[0] = modifiedPattern.ToString(); - - for (int i = 1; i < shortDatePatterns.Count; i++) - { - if (shortDatePatterns[i] == shortDatePatterns[0]) - { - // Found match in the list to the new constructed pattern, then replace it with the original modified pattern - shortDatePatterns[i] = s; - return; - } - } - - // if we come here means the newly constructed pattern not found on the list, then add the original pattern - shortDatePatterns.Add(s); - } - - /// - /// The ICU date format characters are not exactly the same as the .NET date format characters. - /// NormalizeDatePattern will take in an ICU date pattern and return the equivalent .NET date pattern. - /// - /// - /// see Date Field Symbol Table in http://userguide.icu-project.org/formatparse/datetime - /// and https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx - /// - private static string NormalizeDatePattern(string input) - { - StringBuilder destination = StringBuilderCache.Acquire(input.Length); - - int index = 0; - while (index < input.Length) - { - switch (input[index]) - { - case '\'': - // single quotes escape characters, like 'de' in es-SP - // so read verbatim until the next single quote - destination.Append(input[index++]); - while (index < input.Length) - { - char current = input[index++]; - destination.Append(current); - if (current == '\'') - { - break; - } - } - break; - case 'E': - case 'e': - case 'c': - // 'E' in ICU is the day of the week, which maps to 3 or 4 'd's in .NET - // 'e' in ICU is the local day of the week, which has no representation in .NET, but - // maps closest to 3 or 4 'd's in .NET - // 'c' in ICU is the stand-alone day of the week, which has no representation in .NET, but - // maps closest to 3 or 4 'd's in .NET - NormalizeDayOfWeek(input, destination, ref index); - break; - case 'L': - case 'M': - // 'L' in ICU is the stand-alone name of the month, - // which maps closest to 'M' in .NET since it doesn't support stand-alone month names in patterns - // 'M' in both ICU and .NET is the month, - // but ICU supports 5 'M's, which is the super short month name - int occurrences = CountOccurrences(input, input[index], ref index); - if (occurrences > 4) - { - // 5 'L's or 'M's in ICU is the super short name, which maps closest to MMM in .NET - occurrences = 3; - } - destination.Append('M', occurrences); - break; - case 'G': - // 'G' in ICU is the era, which maps to 'g' in .NET - occurrences = CountOccurrences(input, 'G', ref index); - - // it doesn't matter how many 'G's, since .NET only supports 'g' or 'gg', and they - // have the same meaning - destination.Append('g'); - break; - case 'y': - // a single 'y' in ICU is the year with no padding or trimming. - // a single 'y' in .NET is the year with 1 or 2 digits - // so convert any single 'y' to 'yyyy' - occurrences = CountOccurrences(input, 'y', ref index); - if (occurrences == 1) - { - occurrences = 4; - } - destination.Append('y', occurrences); - break; - default: - const string unsupportedDateFieldSymbols = "YuUrQqwWDFg"; - Debug.Assert(!unsupportedDateFieldSymbols.Contains(input[index]), - $"Encountered an unexpected date field symbol '{input[index]}' from ICU which has no known corresponding .NET equivalent."); - - destination.Append(input[index++]); - break; - } - } - - return StringBuilderCache.GetStringAndRelease(destination); - } - - private static void NormalizeDayOfWeek(string input, StringBuilder destination, ref int index) - { - char dayChar = input[index]; - int occurrences = CountOccurrences(input, dayChar, ref index); - occurrences = Math.Max(occurrences, 3); - if (occurrences > 4) - { - // 5 and 6 E/e/c characters in ICU is the super short names, which maps closest to ddd in .NET - occurrences = 3; - } - - destination.Append('d', occurrences); - } - - private static int CountOccurrences(string input, char value, ref int index) - { - int startIndex = index; - while (index < input.Length && input[index] == value) - { - index++; - } - - return index - startIndex; - } - - private static bool EnumMonthNames(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[]? monthNames, ref string? leapHebrewMonthName) - { - monthNames = null; - - EnumCalendarsData callbackContext = default; - callbackContext.Results = new List(); - bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext); - if (result) - { - // the month-name arrays are expected to have 13 elements. If ICU only returns 12, add an - // extra empty string to fill the array. - if (callbackContext.Results.Count == 12) - { - callbackContext.Results.Add(string.Empty); - } - - if (callbackContext.Results.Count > 13) - { - Debug.Assert(calendarId == CalendarId.HEBREW && callbackContext.Results.Count == 14); - - if (calendarId == CalendarId.HEBREW) - { - leapHebrewMonthName = callbackContext.Results[13]; - } - callbackContext.Results.RemoveRange(13, callbackContext.Results.Count - 13); - } - - monthNames = callbackContext.Results.ToArray(); - } - - return result; - } - - private static bool EnumEraNames(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[]? eraNames) - { - bool result = EnumCalendarInfo(localeName, calendarId, dataType, out eraNames); - - // .NET expects that only the Japanese calendars have more than 1 era. - // So for other calendars, only return the latest era. - if (calendarId != CalendarId.JAPAN && calendarId != CalendarId.JAPANESELUNISOLAR && eraNames?.Length > 0) - { - string[] latestEraName = new string[] { eraNames![eraNames.Length - 1] }; - eraNames = latestEraName; - } - - return result; - } - - internal static bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[]? calendarData) - { - calendarData = null; - - EnumCalendarsData callbackContext = default; - callbackContext.Results = new List(); - bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext); - if (result) - { - calendarData = callbackContext.Results.ToArray(); - } - - return result; - } - - private static unsafe bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, ref EnumCalendarsData callbackContext) - { - return Interop.Globalization.EnumCalendarInfo(EnumCalendarInfoCallback, localeName, calendarId, dataType, (IntPtr)Unsafe.AsPointer(ref callbackContext)); - } - - private static unsafe void EnumCalendarInfoCallback(string calendarString, IntPtr context) - { - try - { - ref EnumCalendarsData callbackContext = ref Unsafe.As(ref *(byte*)context); - - if (callbackContext.DisallowDuplicates) - { - foreach (string existingResult in callbackContext.Results) - { - if (string.Equals(calendarString, existingResult, StringComparison.Ordinal)) - { - // the value is already in the results, so don't add it again - return; - } - } - } - - callbackContext.Results.Add(calendarString); - } - catch (Exception e) - { - Debug.Fail(e.ToString()); - // we ignore the managed exceptions here because EnumCalendarInfoCallback will get called from the native code. - // If we don't ignore the exception here that can cause the runtime to fail fast. - } - } - - private struct EnumCalendarsData - { - public List Results; - public bool DisallowDuplicates; - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Windows.cs deleted file mode 100644 index 8031df90e0e28a..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Windows.cs +++ /dev/null @@ -1,448 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.Collections.Generic; -using Internal.Runtime.CompilerServices; - -namespace System.Globalization -{ - internal partial class CalendarData - { - private bool LoadCalendarDataFromSystem(string localeName, CalendarId calendarId) - { - Debug.Assert(!GlobalizationMode.Invariant); - - bool ret = true; - - uint useOverrides = this.bUseUserOverrides ? 0 : CAL_NOUSEROVERRIDE; - - // - // Windows doesn't support some calendars right now, so remap those. - // - switch (calendarId) - { - case CalendarId.JAPANESELUNISOLAR: // Data looks like Japanese - calendarId = CalendarId.JAPAN; - break; - case CalendarId.JULIAN: // Data looks like gregorian US - case CalendarId.CHINESELUNISOLAR: // Algorithmic, so actual data is irrelevent - case CalendarId.SAKA: // reserved to match Office but not implemented in our code, so data is irrelevent - case CalendarId.LUNAR_ETO_CHN: // reserved to match Office but not implemented in our code, so data is irrelevent - case CalendarId.LUNAR_ETO_KOR: // reserved to match Office but not implemented in our code, so data is irrelevent - case CalendarId.LUNAR_ETO_ROKUYOU: // reserved to match Office but not implemented in our code, so data is irrelevent - case CalendarId.KOREANLUNISOLAR: // Algorithmic, so actual data is irrelevent - case CalendarId.TAIWANLUNISOLAR: // Algorithmic, so actual data is irrelevent - calendarId = CalendarId.GREGORIAN_US; - break; - } - - // - // Special handling for some special calendar due to OS limitation. - // This includes calendar like Taiwan calendar, UmAlQura calendar, etc. - // - CheckSpecialCalendar(ref calendarId, ref localeName); - - // Numbers - ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_ITWODIGITYEARMAX | useOverrides, out this.iTwoDigitYearMax); - - // Strings - ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_SCALNAME, out this.sNativeName); - ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_SMONTHDAY | useOverrides, out this.sMonthDay); - - // String Arrays - // Formats - ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SSHORTDATE, LOCALE_SSHORTDATE | useOverrides, out this.saShortDates!); - ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SLONGDATE, LOCALE_SLONGDATE | useOverrides, out this.saLongDates!); - - // Get the YearMonth pattern. - ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SYEARMONTH, LOCALE_SYEARMONTH, out this.saYearMonths!); - - // Day & Month Names - // These are all single calType entries, 1 per day, so we have to make 7 or 13 calls to collect all the names - - // Day - // Note that we're off-by-one since managed starts on sunday and windows starts on monday - ret &= GetCalendarDayInfo(localeName, calendarId, CAL_SDAYNAME7, out this.saDayNames); - ret &= GetCalendarDayInfo(localeName, calendarId, CAL_SABBREVDAYNAME7, out this.saAbbrevDayNames); - - // Month names - ret &= GetCalendarMonthInfo(localeName, calendarId, CAL_SMONTHNAME1, out this.saMonthNames); - ret &= GetCalendarMonthInfo(localeName, calendarId, CAL_SABBREVMONTHNAME1, out this.saAbbrevMonthNames); - - // - // The following LCTYPE are not supported in some platforms. If the call fails, - // don't return a failure. - // - GetCalendarDayInfo(localeName, calendarId, CAL_SSHORTESTDAYNAME7, out this.saSuperShortDayNames); - - // Gregorian may have genitive month names - if (calendarId == CalendarId.GREGORIAN) - { - GetCalendarMonthInfo(localeName, calendarId, CAL_SMONTHNAME1 | CAL_RETURN_GENITIVE_NAMES, out this.saMonthGenitiveNames); - GetCalendarMonthInfo(localeName, calendarId, CAL_SABBREVMONTHNAME1 | CAL_RETURN_GENITIVE_NAMES, out this.saAbbrevMonthGenitiveNames); - } - - // Calendar Parts Names - // This doesn't get always get localized names for gregorian (not available in windows < 7) - // so: eg: coreclr on win < 7 won't get these - CallEnumCalendarInfo(localeName, calendarId, CAL_SERASTRING, 0, out this.saEraNames!); - CallEnumCalendarInfo(localeName, calendarId, CAL_SABBREVERASTRING, 0, out this.saAbbrevEraNames!); - - // - // Calendar Era Info - // Note that calendar era data (offsets, etc) is hard coded for each calendar since this - // data is implementation specific and not dynamic (except perhaps Japanese) - // - - // Clean up the escaping of the formats - this.saShortDates = CultureData.ReescapeWin32Strings(this.saShortDates)!; - this.saLongDates = CultureData.ReescapeWin32Strings(this.saLongDates)!; - this.saYearMonths = CultureData.ReescapeWin32Strings(this.saYearMonths)!; - this.sMonthDay = CultureData.ReescapeWin32String(this.sMonthDay)!; - - return ret; - } - - // Get native two digit year max - internal static int GetTwoDigitYearMax(CalendarId calendarId) => - GlobalizationMode.Invariant ? Invariant.iTwoDigitYearMax : - CallGetCalendarInfoEx(null, calendarId, CAL_ITWODIGITYEARMAX, out int twoDigitYearMax) ? twoDigitYearMax : - -1; - - // Call native side to figure out which calendars are allowed - internal static int GetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars) - { - Debug.Assert(!GlobalizationMode.Invariant); - - EnumCalendarsData data = default; - data.userOverride = 0; - data.calendars = new List(); - - // First call GetLocaleInfo if necessary - if (useUserOverride) - { - // They want user overrides, see if the user calendar matches the input calendar - int userCalendar = CultureData.GetLocaleInfoExInt(localeName, LOCALE_ICALENDARTYPE); - - // If we got a default, then use it as the first calendar - if (userCalendar != 0) - { - data.userOverride = userCalendar; - data.calendars.Add(userCalendar); - } - } - - unsafe - { - Interop.Kernel32.EnumCalendarInfoExEx(EnumCalendarsCallback, localeName, ENUM_ALL_CALENDARS, null, CAL_ICALINTVALUE, Unsafe.AsPointer(ref data)); - } - - // Copy to the output array - for (int i = 0; i < Math.Min(calendars.Length, data.calendars.Count); i++) - calendars[i] = (CalendarId)data.calendars[i]; - - // Now we have a list of data, return the count - return data.calendars.Count; - } - - private static bool SystemSupportsTaiwaneseCalendar() - { - Debug.Assert(!GlobalizationMode.Invariant); - - // Taiwanese calendar get listed as one of the optional zh-TW calendars only when having zh-TW UI - return CallGetCalendarInfoEx("zh-TW", CalendarId.TAIWAN, CAL_SCALNAME, out string _); - } - - // PAL Layer ends here - - private const uint CAL_RETURN_NUMBER = 0x20000000; - private const uint CAL_RETURN_GENITIVE_NAMES = 0x10000000; - private const uint CAL_NOUSEROVERRIDE = 0x80000000; - private const uint CAL_SCALNAME = 0x00000002; - private const uint CAL_SMONTHDAY = 0x00000038; - private const uint CAL_SSHORTDATE = 0x00000005; - private const uint CAL_SLONGDATE = 0x00000006; - private const uint CAL_SYEARMONTH = 0x0000002f; - private const uint CAL_SDAYNAME7 = 0x0000000d; - private const uint CAL_SABBREVDAYNAME7 = 0x00000014; - private const uint CAL_SMONTHNAME1 = 0x00000015; - private const uint CAL_SABBREVMONTHNAME1 = 0x00000022; - private const uint CAL_SSHORTESTDAYNAME7 = 0x00000037; - private const uint CAL_SERASTRING = 0x00000004; - private const uint CAL_SABBREVERASTRING = 0x00000039; - private const uint CAL_ICALINTVALUE = 0x00000001; - private const uint CAL_ITWODIGITYEARMAX = 0x00000030; - - private const uint ENUM_ALL_CALENDARS = 0xffffffff; - - private const uint LOCALE_SSHORTDATE = 0x0000001F; - private const uint LOCALE_SLONGDATE = 0x00000020; - private const uint LOCALE_SYEARMONTH = 0x00001006; - private const uint LOCALE_ICALENDARTYPE = 0x00001009; - - //////////////////////////////////////////////////////////////////////// - // - // For calendars like Gregorain US/Taiwan/UmAlQura, they are not available - // in all OS or all localized versions of OS. - // If OS does not support these calendars, we will fallback by using the - // appropriate fallback calendar and locale combination to retrieve data from OS. - // - // Parameters: - // __deref_inout pCalendarInt: - // Pointer to the calendar ID. This will be updated to new fallback calendar ID if needed. - // __in_out pLocaleNameStackBuffer - // Pointer to the StackSString object which holds the locale name to be checked. - // This will be updated to new fallback locale name if needed. - // - //////////////////////////////////////////////////////////////////////// - private static void CheckSpecialCalendar(ref CalendarId calendar, ref string localeName) - { - // Gregorian-US isn't always available in the OS, however it is the same for all locales - switch (calendar) - { - case CalendarId.GREGORIAN_US: - // See if this works - if (!CallGetCalendarInfoEx(localeName, calendar, CAL_SCALNAME, out string _)) - { - // Failed, set it to a locale (fa-IR) that's alway has Gregorian US available in the OS - localeName = "fa-IR"; - } - // See if that works - if (!CallGetCalendarInfoEx(localeName, calendar, CAL_SCALNAME, out string _)) - { - // Failed again, just use en-US with the gregorian calendar - localeName = "en-US"; - calendar = CalendarId.GREGORIAN; - } - break; - case CalendarId.TAIWAN: - // Taiwan calendar data is not always in all language version of OS due to Geopolical reasons. - // It is only available in zh-TW localized versions of Windows. - // Let's check if OS supports it. If not, fallback to Greogrian localized for Taiwan calendar. - if (!SystemSupportsTaiwaneseCalendar()) - { - calendar = CalendarId.GREGORIAN; - } - break; - } - } - - private static bool CallGetCalendarInfoEx(string? localeName, CalendarId calendar, uint calType, out int data) - { - return Interop.Kernel32.GetCalendarInfoEx(localeName, (uint)calendar, IntPtr.Zero, calType | CAL_RETURN_NUMBER, IntPtr.Zero, 0, out data) != 0; - } - - private static unsafe bool CallGetCalendarInfoEx(string localeName, CalendarId calendar, uint calType, out string data) - { - const int BUFFER_LENGTH = 80; - - // The maximum size for values returned from GetCalendarInfoEx is 80 characters. - char* buffer = stackalloc char[BUFFER_LENGTH]; - - int ret = Interop.Kernel32.GetCalendarInfoEx(localeName, (uint)calendar, IntPtr.Zero, calType, (IntPtr)buffer, BUFFER_LENGTH, IntPtr.Zero); - if (ret > 0) - { - if (buffer[ret - 1] == '\0') - { - ret--; // don't include the null termination in the string - } - data = new string(buffer, 0, ret); - return true; - } - data = ""; - return false; - } - - // Context for EnumCalendarInfoExEx callback. - private struct EnumData - { - public string? userOverride; - public List? strings; - } - - // EnumCalendarInfoExEx callback itself. - // [NativeCallable(CallingConvention = CallingConvention.StdCall)] - private static unsafe Interop.BOOL EnumCalendarInfoCallback(char* lpCalendarInfoString, uint calendar, IntPtr pReserved, void* lParam) - { - ref EnumData context = ref Unsafe.As(ref *(byte*)lParam); - try - { - string calendarInfo = new string(lpCalendarInfoString); - - // If we had a user override, check to make sure this differs - if (context.userOverride != calendarInfo) - { - Debug.Assert(context.strings != null); - context.strings.Add(calendarInfo); - } - - return Interop.BOOL.TRUE; - } - catch (Exception) - { - return Interop.BOOL.FALSE; - } - } - - private static unsafe bool CallEnumCalendarInfo(string localeName, CalendarId calendar, uint calType, uint lcType, out string[]? data) - { - EnumData context = default; - context.userOverride = null; - context.strings = new List(); - // First call GetLocaleInfo if necessary - if ((lcType != 0) && ((lcType & CAL_NOUSEROVERRIDE) == 0) && - // Get user locale, see if it matches localeName. - // Note that they should match exactly, including letter case - GetUserDefaultLocaleName() == localeName) - { - // They want user overrides, see if the user calendar matches the input calendar - CalendarId userCalendar = (CalendarId)CultureData.GetLocaleInfoExInt(localeName, LOCALE_ICALENDARTYPE); - - // If the calendars were the same, see if the locales were the same - if (userCalendar == calendar) - { - // They matched, get the user override since locale & calendar match - string? res = CultureData.GetLocaleInfoEx(localeName, lcType); - - // if it succeeded remember the override for the later callers - if (res != null) - { - // Remember this was the override (so we can look for duplicates later in the enum function) - context.userOverride = res; - - // Add to the result strings. - context.strings.Add(res); - } - } - } - - // Now call the enumeration API. Work is done by our callback function - Interop.Kernel32.EnumCalendarInfoExEx(EnumCalendarInfoCallback, localeName, (uint)calendar, null, calType, Unsafe.AsPointer(ref context)); - - // Now we have a list of data, fail if we didn't find anything. - Debug.Assert(context.strings != null); - if (context.strings.Count == 0) - { - data = null; - return false; - } - - string[] output = context.strings.ToArray(); - - if (calType == CAL_SABBREVERASTRING || calType == CAL_SERASTRING) - { - // Eras are enumerated backwards. (oldest era name first, but - // Japanese calendar has newest era first in array, and is only - // calendar with multiple eras) - Array.Reverse(output, 0, output.Length); - } - - data = output; - - return true; - } - - //////////////////////////////////////////////////////////////////////// - // - // Get the native day names - // - // NOTE: There's a disparity between .NET & windows day orders, the input day should - // start with Sunday - // - // Parameters: - // OUT pOutputStrings The output string[] value. - // - //////////////////////////////////////////////////////////////////////// - private static bool GetCalendarDayInfo(string localeName, CalendarId calendar, uint calType, out string[] outputStrings) - { - bool result = true; - - // - // We'll need a new array of 7 items - // - string[] results = new string[7]; - - // Get each one of them - for (int i = 0; i < 7; i++, calType++) - { - result &= CallGetCalendarInfoEx(localeName, calendar, calType, out results[i]); - - // On the first iteration we need to go from CAL_SDAYNAME7 to CAL_SDAYNAME1, so subtract 7 before the ++ happens - // This is because the framework starts on sunday and windows starts on monday when counting days - if (i == 0) - calType -= 7; - } - - outputStrings = results; - - return result; - } - - //////////////////////////////////////////////////////////////////////// - // - // Get the native month names - // - // Parameters: - // OUT pOutputStrings The output string[] value. - // - //////////////////////////////////////////////////////////////////////// - private static bool GetCalendarMonthInfo(string localeName, CalendarId calendar, uint calType, out string[] outputStrings) - { - // - // We'll need a new array of 13 items - // - string[] results = new string[13]; - - // Get each one of them - for (int i = 0; i < 13; i++, calType++) - { - if (!CallGetCalendarInfoEx(localeName, calendar, calType, out results[i])) - results[i] = ""; - } - - outputStrings = results; - - return true; - } - - // - // struct to help our calendar data enumaration callback - // - private struct EnumCalendarsData - { - public int userOverride; // user override value (if found) - public List calendars; // list of calendars found so far - } - - // [NativeCallable(CallingConvention = CallingConvention.StdCall)] - private static unsafe Interop.BOOL EnumCalendarsCallback(char* lpCalendarInfoString, uint calendar, IntPtr reserved, void* lParam) - { - ref EnumCalendarsData context = ref Unsafe.As(ref *(byte*)lParam); - try - { - // If we had a user override, check to make sure this differs - if (context.userOverride != calendar) - context.calendars.Add((int)calendar); - - return Interop.BOOL.TRUE; - } - catch (Exception) - { - return Interop.BOOL.FALSE; - } - } - - private static unsafe string GetUserDefaultLocaleName() - { - Debug.Assert(!GlobalizationMode.Invariant); - - int result; - char* localeName = stackalloc char[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH]; - result = CultureData.GetLocaleInfoEx(Interop.Kernel32.LOCALE_NAME_USER_DEFAULT, Interop.Kernel32.LOCALE_SNAME, localeName, Interop.Kernel32.LOCALE_NAME_MAX_LENGTH); - - return result <= 0 ? "" : new string(localeName, 0, result - 1); // exclude the null termination - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.cs index 997cfb406e430a..72d14b38d0cd23 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.cs @@ -105,7 +105,11 @@ internal CalendarData(string localeName, CalendarId calendarId, bool bUseUserOve Debug.Assert(!GlobalizationMode.Invariant); - if (!LoadCalendarDataFromSystem(localeName, calendarId)) + bool loadedCalendarData = GlobalizationMode.UseNls ? + NlsLoadCalendarDataFromSystem(localeName, calendarId) : + IcuLoadCalendarDataFromSystem(localeName, calendarId); + + if (!loadedCalendarData) { // LoadCalendarDataFromSystem sometimes can fail on Linux if the installed ICU package is missing some resources. // The ICU package can miss some resources in some cases like if someone compile and build the ICU package manually or ICU has a regression. @@ -376,5 +380,9 @@ private static string CalendarIdToCultureName(CalendarId calendarId) return "en-US"; } + + private bool SystemSupportsTaiwaneseCalendar() => GlobalizationMode.UseNls ? + NlsSystemSupportsTaiwaneseCalendar() : + IcuSystemSupportsTaiwaneseCalendar(); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CharUnicodeInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CharUnicodeInfo.cs index 9a1c24607e71f7..51d0ae46b3ae10 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CharUnicodeInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CharUnicodeInfo.cs @@ -9,13 +9,6 @@ using System.Text.Unicode; using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System.Globalization { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs new file mode 100644 index 00000000000000..3cc636bb65dd5a --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs @@ -0,0 +1,1082 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; + +namespace System.Globalization +{ + public partial class CompareInfo + { + [NonSerialized] + private bool _isAsciiEqualityOrdinal; + + private void IcuInitSortHandle() + { + if (GlobalizationMode.Invariant) + { + _isAsciiEqualityOrdinal = true; + } + else + { + Debug.Assert(!GlobalizationMode.UseNls); + + // Inline the following condition to avoid potential implementation cycles within globalization + // + // _isAsciiEqualityOrdinal = _sortName == "" || _sortName == "en" || _sortName.StartsWith("en-", StringComparison.Ordinal); + // + _isAsciiEqualityOrdinal = _sortName.Length == 0 || + (_sortName.Length >= 2 && _sortName[0] == 'e' && _sortName[1] == 'n' && (_sortName.Length == 2 || _sortName[2] == '-')); + + _sortHandle = SortHandleCache.GetCachedSortHandle(_sortName); + } + } + + private static unsafe int IcuIndexOfOrdinalCore(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase, bool fromBeginning) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert(!value.IsEmpty); + + // Ordinal (non-linguistic) comparisons require the length of the target string to be no greater + // than the length of the search space. Since our caller already checked for empty target strings, + // the below check also handles the case of empty search space strings. + + if (source.Length < value.Length) + { + return -1; + } + + Debug.Assert(!source.IsEmpty); + + if (ignoreCase) + { + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (char* pValue = &MemoryMarshal.GetReference(value)) + { + return Interop.Globalization.IndexOfOrdinalIgnoreCase(pValue, value.Length, pSource, source.Length, findLast: !fromBeginning); + } + } + + int startIndex, endIndex, jump; + if (fromBeginning) + { + // Left to right, from zero to last possible index in the source string. + // Incrementing by one after each iteration. Stop condition is last possible index plus 1. + startIndex = 0; + endIndex = source.Length - value.Length + 1; + jump = 1; + } + else + { + // Right to left, from first possible index in the source string to zero. + // Decrementing by one after each iteration. Stop condition is last possible index minus 1. + startIndex = source.Length - value.Length; + endIndex = -1; + jump = -1; + } + + for (int i = startIndex; i != endIndex; i += jump) + { + int valueIndex, sourceIndex; + + for (valueIndex = 0, sourceIndex = i; + valueIndex < value.Length && source[sourceIndex] == value[valueIndex]; + valueIndex++, sourceIndex++) + ; + + if (valueIndex == value.Length) + { + return i; + } + } + + return -1; + } + + private static unsafe int IcuLastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + Debug.Assert(source != null); + Debug.Assert(value != null); + + if (value.Length == 0) + { + return startIndex; + } + + if (count < value.Length) + { + return -1; + } + + // startIndex is the index into source where we start search backwards from. + // leftStartIndex is the index into source of the start of the string that is + // count characters away from startIndex. + int leftStartIndex = startIndex - count + 1; + + if (ignoreCase) + { + fixed (char* pSource = source) + { + int lastIndex = Interop.Globalization.IndexOfOrdinalIgnoreCase(value, value.Length, pSource + leftStartIndex, count, findLast: true); + return lastIndex != -1 ? + leftStartIndex + lastIndex : + -1; + } + } + + for (int i = startIndex - value.Length + 1; i >= leftStartIndex; i--) + { + int valueIndex, sourceIndex; + + for (valueIndex = 0, sourceIndex = i; + valueIndex < value.Length && source[sourceIndex] == value[valueIndex]; + valueIndex++, sourceIndex++) ; + + if (valueIndex == value.Length) { + return i; + } + } + + return -1; + } + + private static unsafe int IcuCompareStringOrdinalIgnoreCase(ref char string1, int count1, ref char string2, int count2) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + Debug.Assert(count1 > 0); + Debug.Assert(count2 > 0); + + fixed (char* char1 = &string1) + fixed (char* char2 = &string2) + { + Debug.Assert(char1 != null); + Debug.Assert(char2 != null); + return Interop.Globalization.CompareStringOrdinalIgnoreCase(char1, count1, char2, count2); + } + } + + private unsafe int IcuCompareString(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + + // GetReference may return nullptr if the input span is defaulted. The native layer handles + // this appropriately; no workaround is needed on the managed side. + + fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) + fixed (char* pString2 = &MemoryMarshal.GetReference(string2)) + { + return Interop.Globalization.CompareString(_sortHandle, pString1, string1.Length, pString2, string2.Length, options); + } + } + + private unsafe int IcuIndexOfCore(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert(target.Length != 0); + + if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) + { + if ((options & CompareOptions.IgnoreCase) != 0) + return IndexOfOrdinalIgnoreCaseHelper(source, target, options, matchLengthPtr, fromBeginning); + else + return IndexOfOrdinalHelper(source, target, options, matchLengthPtr, fromBeginning); + } + else + { + // GetReference may return nullptr if the input span is defaulted. The native layer handles + // this appropriately; no workaround is needed on the managed side. + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (char* pTarget = &MemoryMarshal.GetReference(target)) + { + if (fromBeginning) + return Interop.Globalization.IndexOf(_sortHandle, pTarget, target.Length, pSource, source.Length, options, matchLengthPtr); + else + return Interop.Globalization.LastIndexOf(_sortHandle, pTarget, target.Length, pSource, source.Length, options, matchLengthPtr); + } + } + } + + /// + /// Duplicate of IndexOfOrdinalHelper that also handles ignore case. Can't converge both methods + /// as the JIT wouldn't be able to optimize the ignoreCase path away. + /// + /// + private unsafe int IndexOfOrdinalIgnoreCaseHelper(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) + { + Debug.Assert(!GlobalizationMode.Invariant); + + Debug.Assert(!target.IsEmpty); + Debug.Assert(_isAsciiEqualityOrdinal); + + fixed (char* ap = &MemoryMarshal.GetReference(source)) + fixed (char* bp = &MemoryMarshal.GetReference(target)) + { + char* a = ap; + char* b = bp; + + for (int j = 0; j < target.Length; j++) + { + char targetChar = *(b + j); + if (targetChar >= 0x80 || HighCharTable[targetChar]) + goto InteropCall; + } + + if (target.Length > source.Length) + { + for (int k = 0; k < source.Length; k++) + { + char targetChar = *(a + k); + if (targetChar >= 0x80 || HighCharTable[targetChar]) + goto InteropCall; + } + return -1; + } + + int startIndex, endIndex, jump; + if (fromBeginning) + { + // Left to right, from zero to last possible index in the source string. + // Incrementing by one after each iteration. Stop condition is last possible index plus 1. + startIndex = 0; + endIndex = source.Length - target.Length + 1; + jump = 1; + } + else + { + // Right to left, from first possible index in the source string to zero. + // Decrementing by one after each iteration. Stop condition is last possible index minus 1. + startIndex = source.Length - target.Length; + endIndex = -1; + jump = -1; + } + + for (int i = startIndex; i != endIndex; i += jump) + { + int targetIndex = 0; + int sourceIndex = i; + + for (; targetIndex < target.Length; targetIndex++, sourceIndex++) + { + char valueChar = *(a + sourceIndex); + char targetChar = *(b + targetIndex); + + if (valueChar >= 0x80 || HighCharTable[valueChar]) + goto InteropCall; + + if (valueChar == targetChar) + { + continue; + } + + // uppercase both chars - notice that we need just one compare per char + if ((uint)(valueChar - 'a') <= ('z' - 'a')) + valueChar = (char)(valueChar - 0x20); + if ((uint)(targetChar - 'a') <= ('z' - 'a')) + targetChar = (char)(targetChar - 0x20); + + if (valueChar == targetChar) + { + continue; + } + + // The match may be affected by special character. Verify that the following character is regular ASCII. + if (sourceIndex < source.Length - 1 && *(a + sourceIndex + 1) >= 0x80) + goto InteropCall; + goto Next; + } + + // The match may be affected by special character. Verify that the following character is regular ASCII. + if (sourceIndex < source.Length && *(a + sourceIndex) >= 0x80) + goto InteropCall; + if (matchLengthPtr != null) + *matchLengthPtr = target.Length; + return i; + + Next: ; + } + + return -1; + + InteropCall: + if (fromBeginning) + return Interop.Globalization.IndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr); + else + return Interop.Globalization.LastIndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr); + } + } + + private unsafe int IndexOfOrdinalHelper(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) + { + Debug.Assert(!GlobalizationMode.Invariant); + + Debug.Assert(!target.IsEmpty); + Debug.Assert(_isAsciiEqualityOrdinal); + + fixed (char* ap = &MemoryMarshal.GetReference(source)) + fixed (char* bp = &MemoryMarshal.GetReference(target)) + { + char* a = ap; + char* b = bp; + + for (int j = 0; j < target.Length; j++) + { + char targetChar = *(b + j); + if (targetChar >= 0x80 || HighCharTable[targetChar]) + goto InteropCall; + } + + if (target.Length > source.Length) + { + for (int k = 0; k < source.Length; k++) + { + char targetChar = *(a + k); + if (targetChar >= 0x80 || HighCharTable[targetChar]) + goto InteropCall; + } + return -1; + } + + int startIndex, endIndex, jump; + if (fromBeginning) + { + // Left to right, from zero to last possible index in the source string. + // Incrementing by one after each iteration. Stop condition is last possible index plus 1. + startIndex = 0; + endIndex = source.Length - target.Length + 1; + jump = 1; + } + else + { + // Right to left, from first possible index in the source string to zero. + // Decrementing by one after each iteration. Stop condition is last possible index minus 1. + startIndex = source.Length - target.Length; + endIndex = -1; + jump = -1; + } + + for (int i = startIndex; i != endIndex; i += jump) + { + int targetIndex = 0; + int sourceIndex = i; + + for (; targetIndex < target.Length; targetIndex++, sourceIndex++) + { + char valueChar = *(a + sourceIndex); + char targetChar = *(b + targetIndex); + + if (valueChar >= 0x80 || HighCharTable[valueChar]) + goto InteropCall; + + if (valueChar == targetChar) + { + continue; + } + + // The match may be affected by special character. Verify that the following character is regular ASCII. + if (sourceIndex < source.Length - 1 && *(a + sourceIndex + 1) >= 0x80) + goto InteropCall; + goto Next; + } + + // The match may be affected by special character. Verify that the following character is regular ASCII. + if (sourceIndex < source.Length && *(a + sourceIndex) >= 0x80) + goto InteropCall; + if (matchLengthPtr != null) + *matchLengthPtr = target.Length; + return i; + + Next: ; + } + + return -1; + + InteropCall: + if (fromBeginning) + return Interop.Globalization.IndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr); + else + return Interop.Globalization.LastIndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr); + } + } + + private unsafe bool IcuStartsWith(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + Debug.Assert(!prefix.IsEmpty); + Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + + if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) + { + if ((options & CompareOptions.IgnoreCase) != 0) + return StartsWithOrdinalIgnoreCaseHelper(source, prefix, options); + else + return StartsWithOrdinalHelper(source, prefix, options); + } + else + { + fixed (char* pSource = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) + fixed (char* pPrefix = &MemoryMarshal.GetReference(prefix)) + { + return Interop.Globalization.StartsWith(_sortHandle, pPrefix, prefix.Length, pSource, source.Length, options); + } + } + } + + private unsafe bool StartsWithOrdinalIgnoreCaseHelper(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + + Debug.Assert(!prefix.IsEmpty); + Debug.Assert(_isAsciiEqualityOrdinal); + + int length = Math.Min(source.Length, prefix.Length); + + fixed (char* ap = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) + fixed (char* bp = &MemoryMarshal.GetReference(prefix)) + { + char* a = ap; + char* b = bp; + + while (length != 0) + { + int charA = *a; + int charB = *b; + + if (charA >= 0x80 || charB >= 0x80 || HighCharTable[charA] || HighCharTable[charB]) + goto InteropCall; + + if (charA == charB) + { + a++; b++; + length--; + continue; + } + + // uppercase both chars - notice that we need just one compare per char + if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20; + if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20; + + if (charA == charB) + { + a++; b++; + length--; + continue; + } + + // The match may be affected by special character. Verify that the following character is regular ASCII. + if (a < ap + source.Length - 1 && *(a + 1) >= 0x80) + goto InteropCall; + if (b < bp + prefix.Length - 1 && *(b + 1) >= 0x80) + goto InteropCall; + return false; + } + + // The match may be affected by special character. Verify that the following character is regular ASCII. + + if (source.Length < prefix.Length) + { + if (*b >= 0x80) + goto InteropCall; + return false; + } + + if (source.Length > prefix.Length) + { + if (*a >= 0x80) + goto InteropCall; + } + return true; + + InteropCall: + return Interop.Globalization.StartsWith(_sortHandle, bp, prefix.Length, ap, source.Length, options); + } + } + + private unsafe bool StartsWithOrdinalHelper(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + + Debug.Assert(!prefix.IsEmpty); + Debug.Assert(_isAsciiEqualityOrdinal); + + int length = Math.Min(source.Length, prefix.Length); + + fixed (char* ap = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) + fixed (char* bp = &MemoryMarshal.GetReference(prefix)) + { + char* a = ap; + char* b = bp; + + while (length != 0) + { + int charA = *a; + int charB = *b; + + if (charA >= 0x80 || charB >= 0x80 || HighCharTable[charA] || HighCharTable[charB]) + goto InteropCall; + + if (charA == charB) + { + a++; b++; + length--; + continue; + } + + // The match may be affected by special character. Verify that the following character is regular ASCII. + if (a < ap + source.Length - 1 && *(a + 1) >= 0x80) + goto InteropCall; + if (b < bp + prefix.Length - 1 && *(b + 1) >= 0x80) + goto InteropCall; + return false; + } + + // The match may be affected by special character. Verify that the following character is regular ASCII. + + if (source.Length < prefix.Length) + { + if (*b >= 0x80) + goto InteropCall; + return false; + } + + if (source.Length > prefix.Length) + { + if (*a >= 0x80) + goto InteropCall; + } + return true; + + InteropCall: + return Interop.Globalization.StartsWith(_sortHandle, bp, prefix.Length, ap, source.Length, options); + } + } + + private unsafe bool IcuEndsWith(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + Debug.Assert(!suffix.IsEmpty); + Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + + if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) + { + if ((options & CompareOptions.IgnoreCase) != 0) + return EndsWithOrdinalIgnoreCaseHelper(source, suffix, options); + else + return EndsWithOrdinalHelper(source, suffix, options); + } + else + { + fixed (char* pSource = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) + fixed (char* pSuffix = &MemoryMarshal.GetReference(suffix)) + { + return Interop.Globalization.EndsWith(_sortHandle, pSuffix, suffix.Length, pSource, source.Length, options); + } + } + } + + private unsafe bool EndsWithOrdinalIgnoreCaseHelper(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + + Debug.Assert(!suffix.IsEmpty); + Debug.Assert(_isAsciiEqualityOrdinal); + + int length = Math.Min(source.Length, suffix.Length); + + fixed (char* ap = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) + fixed (char* bp = &MemoryMarshal.GetReference(suffix)) + { + char* a = ap + source.Length - 1; + char* b = bp + suffix.Length - 1; + + while (length != 0) + { + int charA = *a; + int charB = *b; + + if (charA >= 0x80 || charB >= 0x80 || HighCharTable[charA] || HighCharTable[charB]) + goto InteropCall; + + if (charA == charB) + { + a--; b--; + length--; + continue; + } + + // uppercase both chars - notice that we need just one compare per char + if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20; + if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20; + + if (charA == charB) + { + a--; b--; + length--; + continue; + } + + // The match may be affected by special character. Verify that the preceding character is regular ASCII. + if (a > ap && *(a - 1) >= 0x80) + goto InteropCall; + if (b > bp && *(b - 1) >= 0x80) + goto InteropCall; + return false; + } + + // The match may be affected by special character. Verify that the preceding character is regular ASCII. + + if (source.Length < suffix.Length) + { + if (*b >= 0x80) + goto InteropCall; + return false; + } + + if (source.Length > suffix.Length) + { + if (*a >= 0x80) + goto InteropCall; + } + return true; + + InteropCall: + return Interop.Globalization.EndsWith(_sortHandle, bp, suffix.Length, ap, source.Length, options); + } + } + + private unsafe bool EndsWithOrdinalHelper(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + + Debug.Assert(!suffix.IsEmpty); + Debug.Assert(_isAsciiEqualityOrdinal); + + int length = Math.Min(source.Length, suffix.Length); + + fixed (char* ap = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) + fixed (char* bp = &MemoryMarshal.GetReference(suffix)) + { + char* a = ap + source.Length - 1; + char* b = bp + suffix.Length - 1; + + while (length != 0) + { + int charA = *a; + int charB = *b; + + if (charA >= 0x80 || charB >= 0x80 || HighCharTable[charA] || HighCharTable[charB]) + goto InteropCall; + + if (charA == charB) + { + a--; b--; + length--; + continue; + } + + // The match may be affected by special character. Verify that the preceding character is regular ASCII. + if (a > ap && *(a - 1) >= 0x80) + goto InteropCall; + if (b > bp && *(b - 1) >= 0x80) + goto InteropCall; + return false; + } + + // The match may be affected by special character. Verify that the preceding character is regular ASCII. + + if (source.Length < suffix.Length) + { + if (*b >= 0x80) + goto InteropCall; + return false; + } + + if (source.Length > suffix.Length) + { + if (*a >= 0x80) + goto InteropCall; + } + return true; + + InteropCall: + return Interop.Globalization.EndsWith(_sortHandle, bp, suffix.Length, ap, source.Length, options); + } + } + + private unsafe SortKey IcuCreateSortKey(string source, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + if (source==null) { throw new ArgumentNullException(nameof(source)); } + + if ((options & ValidCompareMaskOffFlags) != 0) + { + throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + } + + byte[] keyData; + fixed (char* pSource = source) + { + int sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, null, 0, options); + keyData = new byte[sortKeyLength]; + + fixed (byte* pSortKey = keyData) + { + if (Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKeyLength, options) != sortKeyLength) + { + throw new ArgumentException(SR.Arg_ExternalException); + } + } + } + + return new SortKey(this, source, options, keyData); + } + + private unsafe int IcuGetSortKey(ReadOnlySpan source, Span destination, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert((options & ValidCompareMaskOffFlags) == 0); + + // It's ok to pass nullptr (for empty buffers) to ICU's sort key routines. + + int actualSortKeyLength; + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (byte* pDest = &MemoryMarshal.GetReference(destination)) + { + actualSortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pDest, destination.Length, options); + } + + // The check below also handles errors due to negative values / overflow being returned. + + if ((uint)actualSortKeyLength > (uint)destination.Length) + { + if (actualSortKeyLength > destination.Length) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + else + { + throw new ArgumentException(SR.Arg_ExternalException); + } + } + + return actualSortKeyLength; + } + + private unsafe int IcuGetSortKeyLength(ReadOnlySpan source, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert((options & ValidCompareMaskOffFlags) == 0); + + // It's ok to pass nullptr (for empty buffers) to ICU's sort key routines. + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + { + return Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, null, 0, options); + } + } + + private static bool IcuIsSortable(ReadOnlySpan text) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert(!text.IsEmpty); + + do + { + if (Rune.DecodeFromUtf16(text, out Rune result, out int charsConsumed) != OperationStatus.Done) + { + return false; // found an unpaired surrogate somewhere in the text + } + + UnicodeCategory category = Rune.GetUnicodeCategory(result); + if (category == UnicodeCategory.PrivateUse || category == UnicodeCategory.OtherNotAssigned) + { + return false; // can't sort private use or unassigned code points + } + + text = text.Slice(charsConsumed); + } while (!text.IsEmpty); + + return true; // saw no unsortable data in the buffer + } + + // ----------------------------- + // ---- PAL layer ends here ---- + // ----------------------------- + + private unsafe int IcuGetHashCodeOfString(ReadOnlySpan source, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + + // according to ICU User Guide the performance of ucol_getSortKey is worse when it is called with null output buffer + // the solution is to try to fill the sort key in a temporary buffer of size equal 4 x string length + // 1MB is the biggest array that can be rented from ArrayPool.Shared without memory allocation + int sortKeyLength = (source.Length > 1024 * 1024 / 4) ? 0 : 4 * source.Length; + + byte[]? borrowedArray = null; + Span sortKey = sortKeyLength <= 1024 + ? stackalloc byte[1024] + : (borrowedArray = ArrayPool.Shared.Rent(sortKeyLength)); + + fixed (char* pSource = &MemoryMarshal.GetNonNullPinnableReference(source)) + { + fixed (byte* pSortKey = &MemoryMarshal.GetReference(sortKey)) + { + sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKey.Length, options); + } + + if (sortKeyLength > sortKey.Length) // slow path for big strings + { + if (borrowedArray != null) + { + ArrayPool.Shared.Return(borrowedArray); + } + + sortKey = (borrowedArray = ArrayPool.Shared.Rent(sortKeyLength)); + + fixed (byte* pSortKey = &MemoryMarshal.GetReference(sortKey)) + { + sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKey.Length, options); + } + } + } + + if (sortKeyLength == 0 || sortKeyLength > sortKey.Length) // internal error (0) or a bug (2nd call failed) in ucol_getSortKey + { + throw new ArgumentException(SR.Arg_ExternalException); + } + + int hash = Marvin.ComputeHash32(sortKey.Slice(0, sortKeyLength), Marvin.DefaultSeed); + + if (borrowedArray != null) + { + ArrayPool.Shared.Return(borrowedArray); + } + + return hash; + } + + private static CompareOptions GetOrdinalCompareOptions(CompareOptions options) + { + if ((options & CompareOptions.IgnoreCase) != 0) + { + return CompareOptions.OrdinalIgnoreCase; + } + else + { + return CompareOptions.Ordinal; + } + } + + private static bool CanUseAsciiOrdinalForOptions(CompareOptions options) + { + // Unlike the other Ignore options, IgnoreSymbols impacts ASCII characters (e.g. '). + return (options & CompareOptions.IgnoreSymbols) == 0; + } + + private SortVersion IcuGetSortVersion() + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + int sortVersion = Interop.Globalization.GetSortVersion(_sortHandle); + return new SortVersion(sortVersion, LCID, new Guid(sortVersion, 0, 0, 0, 0, 0, 0, + (byte) (LCID >> 24), + (byte) ((LCID & 0x00FF0000) >> 16), + (byte) ((LCID & 0x0000FF00) >> 8), + (byte) (LCID & 0xFF))); + } + + private static class SortHandleCache + { + // in most scenarios there is a limited number of cultures with limited number of sort options + // so caching the sort handles and not freeing them is OK, see https://github.com/dotnet/coreclr/pull/25117 for more + private static readonly Dictionary s_sortNameToSortHandleCache = new Dictionary(); + + internal static IntPtr GetCachedSortHandle(string sortName) + { + lock (s_sortNameToSortHandleCache) + { + if (!s_sortNameToSortHandleCache.TryGetValue(sortName, out IntPtr result)) + { + Interop.Globalization.ResultCode resultCode = Interop.Globalization.GetSortHandle(sortName, out result); + + if (resultCode == Interop.Globalization.ResultCode.OutOfMemory) + throw new OutOfMemoryException(); + else if (resultCode != Interop.Globalization.ResultCode.Success) + throw new ExternalException(SR.Arg_ExternalException); + + try + { + s_sortNameToSortHandleCache.Add(sortName, result); + } + catch + { + Interop.Globalization.CloseSortHandle(result); + + throw; + } + } + + return result; + } + } + } + + private static ReadOnlySpan HighCharTable => new bool[0x80] + { + true, /* 0x0, 0x0 */ + true, /* 0x1, .*/ + true, /* 0x2, .*/ + true, /* 0x3, .*/ + true, /* 0x4, .*/ + true, /* 0x5, .*/ + true, /* 0x6, .*/ + true, /* 0x7, .*/ + true, /* 0x8, .*/ + false, /* 0x9, */ + true, /* 0xA, */ + false, /* 0xB, .*/ + false, /* 0xC, .*/ + true, /* 0xD, */ + true, /* 0xE, .*/ + true, /* 0xF, .*/ + true, /* 0x10, .*/ + true, /* 0x11, .*/ + true, /* 0x12, .*/ + true, /* 0x13, .*/ + true, /* 0x14, .*/ + true, /* 0x15, .*/ + true, /* 0x16, .*/ + true, /* 0x17, .*/ + true, /* 0x18, .*/ + true, /* 0x19, .*/ + true, /* 0x1A, */ + true, /* 0x1B, .*/ + true, /* 0x1C, .*/ + true, /* 0x1D, .*/ + true, /* 0x1E, .*/ + true, /* 0x1F, .*/ + false, /*0x20, */ + false, /*0x21, !*/ + false, /*0x22, "*/ + false, /*0x23, #*/ + false, /*0x24, $*/ + false, /*0x25, %*/ + false, /*0x26, &*/ + true, /*0x27, '*/ + false, /*0x28, (*/ + false, /*0x29, )*/ + false, /*0x2A **/ + false, /*0x2B, +*/ + false, /*0x2C, ,*/ + true, /*0x2D, -*/ + false, /*0x2E, .*/ + false, /*0x2F, /*/ + false, /*0x30, 0*/ + false, /*0x31, 1*/ + false, /*0x32, 2*/ + false, /*0x33, 3*/ + false, /*0x34, 4*/ + false, /*0x35, 5*/ + false, /*0x36, 6*/ + false, /*0x37, 7*/ + false, /*0x38, 8*/ + false, /*0x39, 9*/ + false, /*0x3A, :*/ + false, /*0x3B, ;*/ + false, /*0x3C, <*/ + false, /*0x3D, =*/ + false, /*0x3E, >*/ + false, /*0x3F, ?*/ + false, /*0x40, @*/ + false, /*0x41, A*/ + false, /*0x42, B*/ + false, /*0x43, C*/ + false, /*0x44, D*/ + false, /*0x45, E*/ + false, /*0x46, F*/ + false, /*0x47, G*/ + false, /*0x48, H*/ + false, /*0x49, I*/ + false, /*0x4A, J*/ + false, /*0x4B, K*/ + false, /*0x4C, L*/ + false, /*0x4D, M*/ + false, /*0x4E, N*/ + false, /*0x4F, O*/ + false, /*0x50, P*/ + false, /*0x51, Q*/ + false, /*0x52, R*/ + false, /*0x53, S*/ + false, /*0x54, T*/ + false, /*0x55, U*/ + false, /*0x56, V*/ + false, /*0x57, W*/ + false, /*0x58, X*/ + false, /*0x59, Y*/ + false, /*0x5A, Z*/ + false, /*0x5B, [*/ + false, /*0x5C, \*/ + false, /*0x5D, ]*/ + false, /*0x5E, ^*/ + false, /*0x5F, _*/ + false, /*0x60, `*/ + false, /*0x61, a*/ + false, /*0x62, b*/ + false, /*0x63, c*/ + false, /*0x64, d*/ + false, /*0x65, e*/ + false, /*0x66, f*/ + false, /*0x67, g*/ + false, /*0x68, h*/ + false, /*0x69, i*/ + false, /*0x6A, j*/ + false, /*0x6B, k*/ + false, /*0x6C, l*/ + false, /*0x6D, m*/ + false, /*0x6E, n*/ + false, /*0x6F, o*/ + false, /*0x70, p*/ + false, /*0x71, q*/ + false, /*0x72, r*/ + false, /*0x73, s*/ + false, /*0x74, t*/ + false, /*0x75, u*/ + false, /*0x76, v*/ + false, /*0x77, w*/ + false, /*0x78, x*/ + false, /*0x79, y*/ + false, /*0x7A, z*/ + false, /*0x7B, {*/ + false, /*0x7C, |*/ + false, /*0x7D, }*/ + false, /*0x7E, ~*/ + true, /*0x7F, */ + }; + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Invariant.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Invariant.cs index 922a471d3fb3cc..9904655cea01e4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Invariant.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Invariant.cs @@ -269,5 +269,52 @@ private static void InvariantCreateSortKeyOrdinalIgnoreCase(ReadOnlySpan s sortKey = sortKey.Slice(sizeof(ushort)); } } + + private int InvariantGetSortKey(ReadOnlySpan source, Span destination, CompareOptions options) + { + Debug.Assert(GlobalizationMode.Invariant); + Debug.Assert((options & ValidCompareMaskOffFlags) == 0); + + // Make sure the destination buffer is large enough to hold the source projection. + // Using unsigned arithmetic below also checks for buffer overflow since the incoming + // length is always a non-negative signed integer. + + if ((uint)destination.Length < (uint)source.Length * sizeof(char)) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + + if ((options & CompareOptions.IgnoreCase) == 0) + { + InvariantCreateSortKeyOrdinal(source, destination); + } + else + { + InvariantCreateSortKeyOrdinalIgnoreCase(source, destination); + } + + return source.Length * sizeof(char); + } + + private int InvariantGetSortKeyLength(ReadOnlySpan source, CompareOptions options) + { + Debug.Assert(GlobalizationMode.Invariant); + Debug.Assert((options & ValidCompareMaskOffFlags) == 0); + + // In invariant mode, sort keys are simply a byte projection of the source input, + // optionally with casing modifications. We need to make sure we don't overflow + // while computing the length. + + int byteLength = source.Length * sizeof(char); + + if (byteLength < 0) + { + throw new ArgumentException( + paramName: nameof(source), + message: SR.ArgumentOutOfRange_GetByteCountOverflow); + } + + return byteLength; + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Nls.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Nls.cs new file mode 100644 index 00000000000000..2d96f963b1b1e5 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Nls.cs @@ -0,0 +1,611 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace System.Globalization +{ + public partial class CompareInfo + { + private void NlsInitSortHandle() + { + Debug.Assert(GlobalizationMode.UseNls); + _sortHandle = NlsGetSortHandle(_sortName); + } + + internal static unsafe IntPtr NlsGetSortHandle(string cultureName) + { + if (GlobalizationMode.Invariant) + { + return IntPtr.Zero; + } + + IntPtr handle; + int ret = Interop.Kernel32.LCMapStringEx(cultureName, Interop.Kernel32.LCMAP_SORTHANDLE, null, 0, &handle, IntPtr.Size, null, null, IntPtr.Zero); + if (ret > 0) + { + // Even if we can get the sort handle, it is not guaranteed to work when Windows compatibility shim is applied + // e.g. Windows 7 compatibility mode. We need to ensure it is working before using it. + // otherwise the whole framework app will not start. + int hashValue = 0; + char a = 'a'; + ret = Interop.Kernel32.LCMapStringEx(null, Interop.Kernel32.LCMAP_HASH, &a, 1, &hashValue, sizeof(int), null, null, handle); + if (ret > 1) + { + return handle; + } + } + + return IntPtr.Zero; + } + + private static unsafe int FindStringOrdinal( + uint dwFindStringOrdinalFlags, + ReadOnlySpan source, + ReadOnlySpan value, + bool bIgnoreCase) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!source.IsEmpty); + Debug.Assert(!value.IsEmpty); + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (char* pValue = &MemoryMarshal.GetReference(value)) + { + Debug.Assert(pSource != null); + Debug.Assert(pValue != null); + + int ret = Interop.Kernel32.FindStringOrdinal( + dwFindStringOrdinalFlags, + pSource, + source.Length, + pValue, + value.Length, + bIgnoreCase ? Interop.BOOL.TRUE : Interop.BOOL.FALSE); + + Debug.Assert(ret >= -1 && ret <= source.Length); + + // SetLastError is only performed under debug builds. + Debug.Assert(ret >= 0 || Marshal.GetLastWin32Error() == Interop.Errors.ERROR_SUCCESS); + + return ret; + } + } + + private static int NlsIndexOfOrdinalCore(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase, bool fromBeginning) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + + Debug.Assert(source.Length != 0); + Debug.Assert(value.Length != 0); + + uint positionFlag = fromBeginning ? (uint)FIND_FROMSTART : FIND_FROMEND; + return FindStringOrdinal(positionFlag, source, value, ignoreCase); + } + + private static int NlsLastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + + Debug.Assert(source != null); + Debug.Assert(value != null); + + int offset = startIndex - count + 1; + int result = FindStringOrdinal(FIND_FROMEND, source.AsSpan(offset, count), value, ignoreCase); + if (result >= 0) + { + result += offset; + } + return result; + } + + private unsafe int NlsGetHashCodeOfString(ReadOnlySpan source, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + +#if TARGET_WINDOWS + if (!Environment.IsWindows8OrAbove) + { + // On Windows 7 / Server 2008, LCMapStringEx exhibits strange behaviors if the destination + // buffer is both non-null and too small for the required output. To prevent this from + // causing issues for us, we need to make an immutable copy of the input buffer so that + // its contents can't change between when we calculate the required sort key length and + // when we populate the sort key buffer. + + source = source.ToString(); + } +#endif + + // LCMapStringEx doesn't support passing cchSrc = 0, so if given a null or empty input + // we'll normalize it to an empty null-terminated string and pass -1 to indicate that + // the underlying OS function should read until it encounters the null terminator. + + int sourceLength = source.Length; + if (sourceLength == 0) + { + source = string.Empty; + sourceLength = -1; + } + + uint flags = LCMAP_SORTKEY | (uint)GetNativeCompareFlags(options); + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + { + int sortKeyLength = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, + flags, + pSource, sourceLength /* in chars */, + null, 0, + null, null, _sortHandle); + if (sortKeyLength == 0) + { + throw new ArgumentException(SR.Arg_ExternalException); + } + + // Note in calls to LCMapStringEx below, the input buffer is specified in wchars (and wchar count), + // but the output buffer is specified in bytes (and byte count). This is because when generating + // sort keys, LCMapStringEx treats the output buffer as containing opaque binary data. + // See https://docs.microsoft.com/en-us/windows/desktop/api/winnls/nf-winnls-lcmapstringex. + + byte[]? borrowedArr = null; + Span span = sortKeyLength <= 512 ? + stackalloc byte[512] : + (borrowedArr = ArrayPool.Shared.Rent(sortKeyLength)); + + fixed (byte* pSortKey = &MemoryMarshal.GetReference(span)) + { + if (Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, + flags, + pSource, sourceLength /* in chars */, + pSortKey, sortKeyLength, + null, null, _sortHandle) != sortKeyLength) + { + throw new ArgumentException(SR.Arg_ExternalException); + } + } + + int hash = Marvin.ComputeHash32(span.Slice(0, sortKeyLength), Marvin.DefaultSeed); + + // Return the borrowed array if necessary. + if (borrowedArr != null) + { + ArrayPool.Shared.Return(borrowedArr); + } + + return hash; + } + } + + private static unsafe int NlsCompareStringOrdinalIgnoreCase(ref char string1, int count1, ref char string2, int count2) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + + Debug.Assert(count1 > 0); + Debug.Assert(count2 > 0); + + fixed (char* char1 = &string1) + fixed (char* char2 = &string2) + { + Debug.Assert(char1 != null); + Debug.Assert(char2 != null); + + // Use the OS to compare and then convert the result to expected value by subtracting 2 + int result = Interop.Kernel32.CompareStringOrdinal(char1, count1, char2, count2, bIgnoreCase: true); + if (result == 0) + { + throw new ArgumentException(SR.Arg_ExternalException); + } + return result - 2; + } + } + + private unsafe int NlsCompareString(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + + string? localeName = _sortHandle != IntPtr.Zero ? null : _sortName; + + // CompareStringEx may try to dereference the first character of its input, even if an explicit + // length of 0 is specified. To work around potential AVs we'll always ensure zero-length inputs + // are normalized to a null-terminated empty string. + + if (string1.IsEmpty) + { + string1 = string.Empty; + } + + if (string2.IsEmpty) + { + string2 = string.Empty; + } + + fixed (char* pLocaleName = localeName) + fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) + fixed (char* pString2 = &MemoryMarshal.GetReference(string2)) + { + Debug.Assert(*pString1 >= 0); // assert that we can always dereference this + Debug.Assert(*pString2 >= 0); // assert that we can always dereference this + + int result = Interop.Kernel32.CompareStringEx( + pLocaleName, + (uint)GetNativeCompareFlags(options), + pString1, + string1.Length, + pString2, + string2.Length, + null, + null, + _sortHandle); + + if (result == 0) + { + throw new ArgumentException(SR.Arg_ExternalException); + } + + // Map CompareStringEx return value to -1, 0, 1. + return result - 2; + } + } + + private unsafe int FindString( + uint dwFindNLSStringFlags, + ReadOnlySpan lpStringSource, + ReadOnlySpan lpStringValue, + int* pcchFound) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!lpStringValue.IsEmpty); + + string? localeName = _sortHandle != IntPtr.Zero ? null : _sortName; + + // FindNLSStringEx disallows passing an explicit 0 for cchSource or cchValue. + // The caller should've already checked that 'lpStringValue' isn't empty, + // but it's possible for 'lpStringSource' to be empty. In this case we'll + // substitute an empty null-terminated string and pass -1 so that the NLS + // function uses the implicit string length. + + int lpStringSourceLength = lpStringSource.Length; + if (lpStringSourceLength == 0) + { + lpStringSource = string.Empty; + lpStringSourceLength = -1; + } + + fixed (char* pLocaleName = localeName) + fixed (char* pSource = &MemoryMarshal.GetReference(lpStringSource)) + fixed (char* pValue = &MemoryMarshal.GetReference(lpStringValue)) + { + Debug.Assert(pSource != null && pValue != null); + + int result = Interop.Kernel32.FindNLSStringEx( + pLocaleName, + dwFindNLSStringFlags, + pSource, + lpStringSourceLength, + pValue, + lpStringValue.Length, + pcchFound, + null, + null, + _sortHandle); + + Debug.Assert(result >= -1 && result <= lpStringSource.Length); + + // SetLastError is only performed under debug builds. + Debug.Assert(result >= 0 || Marshal.GetLastWin32Error() == Interop.Errors.ERROR_SUCCESS); + + return result; + } + } + + private unsafe int NlsIndexOfCore(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + + Debug.Assert(target.Length != 0); + + uint positionFlag = fromBeginning ? (uint)FIND_FROMSTART : FIND_FROMEND; + return FindString(positionFlag | (uint)GetNativeCompareFlags(options), source, target, matchLengthPtr); + } + + private unsafe bool NlsStartsWith(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + + Debug.Assert(!prefix.IsEmpty); + Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + + return FindString(FIND_STARTSWITH | (uint)GetNativeCompareFlags(options), source, prefix, null) >= 0; + } + + private unsafe bool NlsEndsWith(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + + Debug.Assert(!suffix.IsEmpty); + Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + + return FindString(FIND_ENDSWITH | (uint)GetNativeCompareFlags(options), source, suffix, null) >= 0; + } + + private const uint LCMAP_SORTKEY = 0x00000400; + + private const int FIND_STARTSWITH = 0x00100000; + private const int FIND_ENDSWITH = 0x00200000; + private const int FIND_FROMSTART = 0x00400000; + private const int FIND_FROMEND = 0x00800000; + + private unsafe SortKey NlsCreateSortKey(string source, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + + if (source == null) { throw new ArgumentNullException(nameof(source)); } + + if ((options & ValidCompareMaskOffFlags) != 0) + { + throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + } + + byte[] keyData; + uint flags = LCMAP_SORTKEY | (uint)GetNativeCompareFlags(options); + + // LCMapStringEx doesn't support passing cchSrc = 0, so if given an empty string + // we'll instead pass -1 to indicate a null-terminated empty string. + + int sourceLength = source.Length; + if (sourceLength == 0) + { + sourceLength = -1; + } + + fixed (char* pSource = source) + { + int sortKeyLength = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, + flags, + pSource, sourceLength, + null, 0, + null, null, _sortHandle); + if (sortKeyLength == 0) + { + throw new ArgumentException(SR.Arg_ExternalException); + } + + keyData = new byte[sortKeyLength]; + + fixed (byte* pBytes = keyData) + { + if (Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, + flags, + pSource, sourceLength, + pBytes, keyData.Length, + null, null, _sortHandle) != sortKeyLength) + { + throw new ArgumentException(SR.Arg_ExternalException); + } + } + } + + return new SortKey(this, source, options, keyData); + } + + private unsafe int NlsGetSortKey(ReadOnlySpan source, Span destination, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert((options & ValidCompareMaskOffFlags) == 0); + + // LCMapStringEx doesn't allow cchDest = 0 unless we're trying to query + // the total number of bytes necessary. + + if (destination.IsEmpty) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + +#if TARGET_WINDOWS + if (!Environment.IsWindows8OrAbove) + { + // On Windows 7 / Server 2008, LCMapStringEx exhibits strange behaviors if the destination + // buffer is both non-null and too small for the required output. To prevent this from + // causing issues for us, we need to make an immutable copy of the input buffer so that + // its contents can't change between when we calculate the required sort key length and + // when we populate the sort key buffer. + + source = source.ToString(); + } +#endif + + uint flags = LCMAP_SORTKEY | (uint)GetNativeCompareFlags(options); + + // LCMapStringEx doesn't support passing cchSrc = 0, so if given an empty span + // we'll instead normalize to a null-terminated empty string and pass -1 as + // the length to indicate that the implicit null terminator should be used. + + int sourceLength = source.Length; + if (sourceLength == 0) + { + source = string.Empty; + sourceLength = -1; + } + + int actualSortKeyLength; + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (byte* pSortKey = &MemoryMarshal.GetReference(destination)) + { + Debug.Assert(pSource != null); + Debug.Assert(pSortKey != null); + +#if TARGET_WINDOWS + if (!Environment.IsWindows8OrAbove) + { + // Manually check that the destination buffer is large enough to hold the full output. + // See earlier comment for reasoning. + + int requiredSortKeyLength = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, + flags, + pSource, sourceLength, + null, 0, + null, null, _sortHandle); + + if (requiredSortKeyLength > destination.Length) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + + if (requiredSortKeyLength <= 0) + { + throw new ArgumentException(SR.Arg_ExternalException); + } + } +#endif + + actualSortKeyLength = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, + flags, + pSource, sourceLength, + pSortKey, destination.Length, + null, null, _sortHandle); + } + + if (actualSortKeyLength <= 0) + { + Debug.Assert(actualSortKeyLength == 0, "LCMapStringEx should never return a negative value."); + + // This could fail for a variety of reasons, including NLS being unable + // to allocate a temporary buffer large enough to hold intermediate state, + // or the destination buffer being too small. + + if (Marshal.GetLastWin32Error() == Interop.Errors.ERROR_INSUFFICIENT_BUFFER) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + else + { + throw new ArgumentException(SR.Arg_ExternalException); + } + } + + Debug.Assert(actualSortKeyLength <= destination.Length); + return actualSortKeyLength; + } + + private unsafe int NlsGetSortKeyLength(ReadOnlySpan source, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert((options & ValidCompareMaskOffFlags) == 0); + + uint flags = LCMAP_SORTKEY | (uint)GetNativeCompareFlags(options); + + // LCMapStringEx doesn't support passing cchSrc = 0, so if given an empty span + // we'll instead normalize to a null-terminated empty string and pass -1 as + // the length to indicate that the implicit null terminator should be used. + + int sourceLength = source.Length; + if (sourceLength == 0) + { + source = string.Empty; + sourceLength = -1; + } + + int sortKeyLength; + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + { + Debug.Assert(pSource != null); + sortKeyLength = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, + flags, + pSource, sourceLength, + null, 0, + null, null, _sortHandle); + } + + if (sortKeyLength <= 0) + { + Debug.Assert(sortKeyLength == 0, "LCMapStringEx should never return a negative value."); + + // This could fail for a variety of reasons, including NLS being unable + // to allocate a temporary buffer large enough to hold intermediate state. + + throw new ArgumentException(SR.Arg_ExternalException); + } + + return sortKeyLength; + } + + private static unsafe bool NlsIsSortable(ReadOnlySpan text) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(!text.IsEmpty); + + fixed (char* pText = &MemoryMarshal.GetReference(text)) + { + return Interop.Kernel32.IsNLSDefinedString(Interop.Kernel32.COMPARE_STRING, 0, IntPtr.Zero, pText, text.Length); + } + } + + private const int COMPARE_OPTIONS_ORDINAL = 0x40000000; // Ordinal + private const int NORM_IGNORECASE = 0x00000001; // Ignores case. (use LINGUISTIC_IGNORECASE instead) + private const int NORM_IGNOREKANATYPE = 0x00010000; // Does not differentiate between Hiragana and Katakana characters. Corresponding Hiragana and Katakana will compare as equal. + private const int NORM_IGNORENONSPACE = 0x00000002; // Ignores nonspacing. This flag also removes Japanese accent characters. (use LINGUISTIC_IGNOREDIACRITIC instead) + private const int NORM_IGNORESYMBOLS = 0x00000004; // Ignores symbols. + private const int NORM_IGNOREWIDTH = 0x00020000; // Does not differentiate between a single-byte character and the same character as a double-byte character. + private const int NORM_LINGUISTIC_CASING = 0x08000000; // use linguistic rules for casing + private const int SORT_STRINGSORT = 0x00001000; // Treats punctuation the same as symbols. + + private static int GetNativeCompareFlags(CompareOptions options) + { + // Use "linguistic casing" by default (load the culture's casing exception tables) + int nativeCompareFlags = NORM_LINGUISTIC_CASING; + + if ((options & CompareOptions.IgnoreCase) != 0) { nativeCompareFlags |= NORM_IGNORECASE; } + if ((options & CompareOptions.IgnoreKanaType) != 0) { nativeCompareFlags |= NORM_IGNOREKANATYPE; } + if ((options & CompareOptions.IgnoreNonSpace) != 0) { nativeCompareFlags |= NORM_IGNORENONSPACE; } + if ((options & CompareOptions.IgnoreSymbols) != 0) { nativeCompareFlags |= NORM_IGNORESYMBOLS; } + if ((options & CompareOptions.IgnoreWidth) != 0) { nativeCompareFlags |= NORM_IGNOREWIDTH; } + if ((options & CompareOptions.StringSort) != 0) { nativeCompareFlags |= SORT_STRINGSORT; } + + // TODO: Can we try for GetNativeCompareFlags to never + // take Ordinal or OrdinalIgnoreCase. This value is not part of Win32, we just handle it special + // in some places. + // Suffix & Prefix shouldn't use this, make sure to turn off the NORM_LINGUISTIC_CASING flag + if (options == CompareOptions.Ordinal) { nativeCompareFlags = COMPARE_OPTIONS_ORDINAL; } + + Debug.Assert(((options & ~(CompareOptions.IgnoreCase | + CompareOptions.IgnoreKanaType | + CompareOptions.IgnoreNonSpace | + CompareOptions.IgnoreSymbols | + CompareOptions.IgnoreWidth | + CompareOptions.StringSort)) == 0) || + (options == CompareOptions.Ordinal), "[CompareInfo.GetNativeCompareFlags]Expected all flags to be handled"); + + return nativeCompareFlags; + } + + private unsafe SortVersion NlsGetSortVersion() + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + + Interop.Kernel32.NlsVersionInfoEx nlsVersion = default; + nlsVersion.dwNLSVersionInfoSize = sizeof(Interop.Kernel32.NlsVersionInfoEx); + Interop.Kernel32.GetNLSVersionEx(Interop.Kernel32.COMPARE_STRING, _sortName, &nlsVersion); + return new SortVersion( + nlsVersion.dwNLSVersion, + nlsVersion.dwEffectiveId == 0 ? LCID : nlsVersion.dwEffectiveId, + nlsVersion.guidCustomVersion); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Unix.cs deleted file mode 100644 index d0db147a746070..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Unix.cs +++ /dev/null @@ -1,1097 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Buffers; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace System.Globalization -{ - public partial class CompareInfo - { - [NonSerialized] - private IntPtr _sortHandle; - - [NonSerialized] - private bool _isAsciiEqualityOrdinal; - - private void InitSort(CultureInfo culture) - { - _sortName = culture.SortName; - - if (GlobalizationMode.Invariant) - { - _isAsciiEqualityOrdinal = true; - } - else - { - // Inline the following condition to avoid potential implementation cycles within globalization - // - // _isAsciiEqualityOrdinal = _sortName == "" || _sortName == "en" || _sortName.StartsWith("en-", StringComparison.Ordinal); - // - _isAsciiEqualityOrdinal = _sortName.Length == 0 || - (_sortName.Length >= 2 && _sortName[0] == 'e' && _sortName[1] == 'n' && (_sortName.Length == 2 || _sortName[2] == '-')); - - _sortHandle = SortHandleCache.GetCachedSortHandle(_sortName); - } - } - - internal static unsafe int IndexOfOrdinalCore(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!value.IsEmpty); - - // Ordinal (non-linguistic) comparisons require the length of the target string to be no greater - // than the length of the search space. Since our caller already checked for empty target strings, - // the below check also handles the case of empty search space strings. - - if (source.Length < value.Length) - { - return -1; - } - - Debug.Assert(!source.IsEmpty); - - if (ignoreCase) - { - fixed (char* pSource = &MemoryMarshal.GetReference(source)) - fixed (char* pValue = &MemoryMarshal.GetReference(value)) - { - return Interop.Globalization.IndexOfOrdinalIgnoreCase(pValue, value.Length, pSource, source.Length, findLast: !fromBeginning); - } - } - - int startIndex, endIndex, jump; - if (fromBeginning) - { - // Left to right, from zero to last possible index in the source string. - // Incrementing by one after each iteration. Stop condition is last possible index plus 1. - startIndex = 0; - endIndex = source.Length - value.Length + 1; - jump = 1; - } - else - { - // Right to left, from first possible index in the source string to zero. - // Decrementing by one after each iteration. Stop condition is last possible index minus 1. - startIndex = source.Length - value.Length; - endIndex = -1; - jump = -1; - } - - for (int i = startIndex; i != endIndex; i += jump) - { - int valueIndex, sourceIndex; - - for (valueIndex = 0, sourceIndex = i; - valueIndex < value.Length && source[sourceIndex] == value[valueIndex]; - valueIndex++, sourceIndex++) - ; - - if (valueIndex == value.Length) - { - return i; - } - } - - return -1; - } - - internal static unsafe int LastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source != null); - Debug.Assert(value != null); - - if (value.Length == 0) - { - return startIndex; - } - - if (count < value.Length) - { - return -1; - } - - // startIndex is the index into source where we start search backwards from. - // leftStartIndex is the index into source of the start of the string that is - // count characters away from startIndex. - int leftStartIndex = startIndex - count + 1; - - if (ignoreCase) - { - fixed (char* pSource = source) - { - int lastIndex = Interop.Globalization.IndexOfOrdinalIgnoreCase(value, value.Length, pSource + leftStartIndex, count, findLast: true); - return lastIndex != -1 ? - leftStartIndex + lastIndex : - -1; - } - } - - for (int i = startIndex - value.Length + 1; i >= leftStartIndex; i--) - { - int valueIndex, sourceIndex; - - for (valueIndex = 0, sourceIndex = i; - valueIndex < value.Length && source[sourceIndex] == value[valueIndex]; - valueIndex++, sourceIndex++) ; - - if (valueIndex == value.Length) { - return i; - } - } - - return -1; - } - - private static unsafe int CompareStringOrdinalIgnoreCase(ref char string1, int count1, ref char string2, int count2) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(count1 > 0); - Debug.Assert(count2 > 0); - - fixed (char* char1 = &string1) - fixed (char* char2 = &string2) - { - Debug.Assert(char1 != null); - Debug.Assert(char2 != null); - return Interop.Globalization.CompareStringOrdinalIgnoreCase(char1, count1, char2, count2); - } - } - - // TODO https://github.com/dotnet/runtime/issues/8890: - // This method shouldn't be necessary, as we should be able to just use the overload - // that takes two spans. But due to this issue, that's adding significant overhead. - private unsafe int CompareString(ReadOnlySpan string1, string string2, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(string2 != null); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - // Unlike NLS, ICU (ucol_getSortKey) allows passing nullptr for either of the source arguments - // as long as the corresponding length parameter is 0. - - fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) - fixed (char* pString2 = &string2.GetRawStringData()) - { - return Interop.Globalization.CompareString(_sortHandle, pString1, string1.Length, pString2, string2.Length, options); - } - } - - private unsafe int CompareString(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - // Unlike NLS, ICU (ucol_getSortKey) allows passing nullptr for either of the source arguments - // as long as the corresponding length parameter is 0. - - fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) - fixed (char* pString2 = &MemoryMarshal.GetReference(string2)) - { - return Interop.Globalization.CompareString(_sortHandle, pString1, string1.Length, pString2, string2.Length, options); - } - } - - internal unsafe int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options, int* matchLengthPtr) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!string.IsNullOrEmpty(source)); - Debug.Assert(target != null); - Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0); - Debug.Assert((options & CompareOptions.Ordinal) == 0); - - int index; - - if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) - { - if ((options & CompareOptions.IgnoreCase) != 0) - index = IndexOfOrdinalIgnoreCaseHelper(source.AsSpan(startIndex, count), target.AsSpan(), options, matchLengthPtr, fromBeginning: true); - else - index = IndexOfOrdinalHelper(source.AsSpan(startIndex, count), target.AsSpan(), options, matchLengthPtr, fromBeginning: true); - } - else - { - fixed (char* pSource = source) - fixed (char* pTarget = target) - { - index = Interop.Globalization.IndexOf(_sortHandle, pTarget, target.Length, pSource + startIndex, count, options, matchLengthPtr); - } - } - - return index != -1 ? index + startIndex : -1; - } - - // For now, this method is only called from Span APIs with either options == CompareOptions.None or CompareOptions.IgnoreCase - internal unsafe int IndexOfCore(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(source.Length != 0); - Debug.Assert(target.Length != 0); - - if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) - { - if ((options & CompareOptions.IgnoreCase) != 0) - return IndexOfOrdinalIgnoreCaseHelper(source, target, options, matchLengthPtr, fromBeginning); - else - return IndexOfOrdinalHelper(source, target, options, matchLengthPtr, fromBeginning); - } - else - { - fixed (char* pSource = &MemoryMarshal.GetReference(source)) - fixed (char* pTarget = &MemoryMarshal.GetReference(target)) - { - if (fromBeginning) - return Interop.Globalization.IndexOf(_sortHandle, pTarget, target.Length, pSource, source.Length, options, matchLengthPtr); - else - return Interop.Globalization.LastIndexOf(_sortHandle, pTarget, target.Length, pSource, source.Length, options); - } - } - } - - /// - /// Duplicate of IndexOfOrdinalHelper that also handles ignore case. Can't converge both methods - /// as the JIT wouldn't be able to optimize the ignoreCase path away. - /// - /// - private unsafe int IndexOfOrdinalIgnoreCaseHelper(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!target.IsEmpty); - Debug.Assert(_isAsciiEqualityOrdinal); - - fixed (char* ap = &MemoryMarshal.GetReference(source)) - fixed (char* bp = &MemoryMarshal.GetReference(target)) - { - char* a = ap; - char* b = bp; - - for (int j = 0; j < target.Length; j++) - { - char targetChar = *(b + j); - if (targetChar >= 0x80 || HighCharTable[targetChar]) - goto InteropCall; - } - - if (target.Length > source.Length) - { - for (int k = 0; k < source.Length; k++) - { - char targetChar = *(a + k); - if (targetChar >= 0x80 || HighCharTable[targetChar]) - goto InteropCall; - } - return -1; - } - - int startIndex, endIndex, jump; - if (fromBeginning) - { - // Left to right, from zero to last possible index in the source string. - // Incrementing by one after each iteration. Stop condition is last possible index plus 1. - startIndex = 0; - endIndex = source.Length - target.Length + 1; - jump = 1; - } - else - { - // Right to left, from first possible index in the source string to zero. - // Decrementing by one after each iteration. Stop condition is last possible index minus 1. - startIndex = source.Length - target.Length; - endIndex = -1; - jump = -1; - } - - for (int i = startIndex; i != endIndex; i += jump) - { - int targetIndex = 0; - int sourceIndex = i; - - for (; targetIndex < target.Length; targetIndex++, sourceIndex++) - { - char valueChar = *(a + sourceIndex); - char targetChar = *(b + targetIndex); - - if (valueChar >= 0x80 || HighCharTable[valueChar]) - goto InteropCall; - - if (valueChar == targetChar) - { - continue; - } - - // uppercase both chars - notice that we need just one compare per char - if ((uint)(valueChar - 'a') <= ('z' - 'a')) - valueChar = (char)(valueChar - 0x20); - if ((uint)(targetChar - 'a') <= ('z' - 'a')) - targetChar = (char)(targetChar - 0x20); - - if (valueChar == targetChar) - { - continue; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - if (sourceIndex < source.Length - 1 && *(a + sourceIndex + 1) >= 0x80) - goto InteropCall; - goto Next; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - if (sourceIndex < source.Length && *(a + sourceIndex) >= 0x80) - goto InteropCall; - if (matchLengthPtr != null) - *matchLengthPtr = target.Length; - return i; - - Next: ; - } - - return -1; - - InteropCall: - if (fromBeginning) - return Interop.Globalization.IndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr); - else - return Interop.Globalization.LastIndexOf(_sortHandle, b, target.Length, a, source.Length, options); - } - } - - private unsafe int IndexOfOrdinalHelper(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!target.IsEmpty); - Debug.Assert(_isAsciiEqualityOrdinal); - - fixed (char* ap = &MemoryMarshal.GetReference(source)) - fixed (char* bp = &MemoryMarshal.GetReference(target)) - { - char* a = ap; - char* b = bp; - - for (int j = 0; j < target.Length; j++) - { - char targetChar = *(b + j); - if (targetChar >= 0x80 || HighCharTable[targetChar]) - goto InteropCall; - } - - if (target.Length > source.Length) - { - for (int k = 0; k < source.Length; k++) - { - char targetChar = *(a + k); - if (targetChar >= 0x80 || HighCharTable[targetChar]) - goto InteropCall; - } - return -1; - } - - int startIndex, endIndex, jump; - if (fromBeginning) - { - // Left to right, from zero to last possible index in the source string. - // Incrementing by one after each iteration. Stop condition is last possible index plus 1. - startIndex = 0; - endIndex = source.Length - target.Length + 1; - jump = 1; - } - else - { - // Right to left, from first possible index in the source string to zero. - // Decrementing by one after each iteration. Stop condition is last possible index minus 1. - startIndex = source.Length - target.Length; - endIndex = -1; - jump = -1; - } - - for (int i = startIndex; i != endIndex; i += jump) - { - int targetIndex = 0; - int sourceIndex = i; - - for (; targetIndex < target.Length; targetIndex++, sourceIndex++) - { - char valueChar = *(a + sourceIndex); - char targetChar = *(b + targetIndex); - - if (valueChar >= 0x80 || HighCharTable[valueChar]) - goto InteropCall; - - if (valueChar == targetChar) - { - continue; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - if (sourceIndex < source.Length - 1 && *(a + sourceIndex + 1) >= 0x80) - goto InteropCall; - goto Next; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - if (sourceIndex < source.Length && *(a + sourceIndex) >= 0x80) - goto InteropCall; - if (matchLengthPtr != null) - *matchLengthPtr = target.Length; - return i; - - Next: ; - } - - return -1; - - InteropCall: - if (fromBeginning) - return Interop.Globalization.IndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr); - else - return Interop.Globalization.LastIndexOf(_sortHandle, b, target.Length, a, source.Length, options); - } - } - - private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!string.IsNullOrEmpty(source)); - Debug.Assert(target != null); - Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0); - - // startIndex points to the final char to include in the search space. - // empty target strings trivially occur at the end of the search space. - - if (target.Length == 0) - { - return startIndex + 1; - } - - if (options == CompareOptions.Ordinal) - { - return LastIndexOfOrdinalCore(source, target, startIndex, count, ignoreCase: false); - } - - // startIndex is the index into source where we start search backwards from. leftStartIndex is the index into source - // of the start of the string that is count characters away from startIndex. - int leftStartIndex = (startIndex - count + 1); - - int lastIndex; - - if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) - { - if ((options & CompareOptions.IgnoreCase) != 0) - lastIndex = IndexOfOrdinalIgnoreCaseHelper(source.AsSpan(leftStartIndex, count), target.AsSpan(), options, matchLengthPtr: null, fromBeginning: false); - else - lastIndex = IndexOfOrdinalHelper(source.AsSpan(leftStartIndex, count), target.AsSpan(), options, matchLengthPtr: null, fromBeginning: false); - } - else - { - fixed (char* pSource = source) - fixed (char* pTarget = target) - { - lastIndex = Interop.Globalization.LastIndexOf(_sortHandle, pTarget, target.Length, pSource + (startIndex - count + 1), count, options); - } - } - - return lastIndex != -1 ? lastIndex + leftStartIndex : -1; - } - - private unsafe bool StartsWith(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!prefix.IsEmpty); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) - { - if ((options & CompareOptions.IgnoreCase) != 0) - return StartsWithOrdinalIgnoreCaseHelper(source, prefix, options); - else - return StartsWithOrdinalHelper(source, prefix, options); - } - else - { - fixed (char* pSource = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) - fixed (char* pPrefix = &MemoryMarshal.GetReference(prefix)) - { - return Interop.Globalization.StartsWith(_sortHandle, pPrefix, prefix.Length, pSource, source.Length, options); - } - } - } - - private unsafe bool StartsWithOrdinalIgnoreCaseHelper(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!prefix.IsEmpty); - Debug.Assert(_isAsciiEqualityOrdinal); - - int length = Math.Min(source.Length, prefix.Length); - - fixed (char* ap = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) - fixed (char* bp = &MemoryMarshal.GetReference(prefix)) - { - char* a = ap; - char* b = bp; - - while (length != 0) - { - int charA = *a; - int charB = *b; - - if (charA >= 0x80 || charB >= 0x80 || HighCharTable[charA] || HighCharTable[charB]) - goto InteropCall; - - if (charA == charB) - { - a++; b++; - length--; - continue; - } - - // uppercase both chars - notice that we need just one compare per char - if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20; - if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20; - - if (charA == charB) - { - a++; b++; - length--; - continue; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - if (a < ap + source.Length - 1 && *(a + 1) >= 0x80) - goto InteropCall; - if (b < bp + prefix.Length - 1 && *(b + 1) >= 0x80) - goto InteropCall; - return false; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - - if (source.Length < prefix.Length) - { - if (*b >= 0x80) - goto InteropCall; - return false; - } - - if (source.Length > prefix.Length) - { - if (*a >= 0x80) - goto InteropCall; - } - return true; - - InteropCall: - return Interop.Globalization.StartsWith(_sortHandle, bp, prefix.Length, ap, source.Length, options); - } - } - - private unsafe bool StartsWithOrdinalHelper(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!prefix.IsEmpty); - Debug.Assert(_isAsciiEqualityOrdinal); - - int length = Math.Min(source.Length, prefix.Length); - - fixed (char* ap = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) - fixed (char* bp = &MemoryMarshal.GetReference(prefix)) - { - char* a = ap; - char* b = bp; - - while (length != 0) - { - int charA = *a; - int charB = *b; - - if (charA >= 0x80 || charB >= 0x80 || HighCharTable[charA] || HighCharTable[charB]) - goto InteropCall; - - if (charA == charB) - { - a++; b++; - length--; - continue; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - if (a < ap + source.Length - 1 && *(a + 1) >= 0x80) - goto InteropCall; - if (b < bp + prefix.Length - 1 && *(b + 1) >= 0x80) - goto InteropCall; - return false; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - - if (source.Length < prefix.Length) - { - if (*b >= 0x80) - goto InteropCall; - return false; - } - - if (source.Length > prefix.Length) - { - if (*a >= 0x80) - goto InteropCall; - } - return true; - - InteropCall: - return Interop.Globalization.StartsWith(_sortHandle, bp, prefix.Length, ap, source.Length, options); - } - } - - private unsafe bool EndsWith(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!suffix.IsEmpty); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) - { - if ((options & CompareOptions.IgnoreCase) != 0) - return EndsWithOrdinalIgnoreCaseHelper(source, suffix, options); - else - return EndsWithOrdinalHelper(source, suffix, options); - } - else - { - fixed (char* pSource = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) - fixed (char* pSuffix = &MemoryMarshal.GetReference(suffix)) - { - return Interop.Globalization.EndsWith(_sortHandle, pSuffix, suffix.Length, pSource, source.Length, options); - } - } - } - - private unsafe bool EndsWithOrdinalIgnoreCaseHelper(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!suffix.IsEmpty); - Debug.Assert(_isAsciiEqualityOrdinal); - - int length = Math.Min(source.Length, suffix.Length); - - fixed (char* ap = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) - fixed (char* bp = &MemoryMarshal.GetReference(suffix)) - { - char* a = ap + source.Length - 1; - char* b = bp + suffix.Length - 1; - - while (length != 0) - { - int charA = *a; - int charB = *b; - - if (charA >= 0x80 || charB >= 0x80 || HighCharTable[charA] || HighCharTable[charB]) - goto InteropCall; - - if (charA == charB) - { - a--; b--; - length--; - continue; - } - - // uppercase both chars - notice that we need just one compare per char - if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20; - if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20; - - if (charA == charB) - { - a--; b--; - length--; - continue; - } - - return false; - } - - return (source.Length >= suffix.Length); - - InteropCall: - return Interop.Globalization.EndsWith(_sortHandle, bp, suffix.Length, ap, source.Length, options); - } - } - - private unsafe bool EndsWithOrdinalHelper(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!suffix.IsEmpty); - Debug.Assert(_isAsciiEqualityOrdinal); - - int length = Math.Min(source.Length, suffix.Length); - - fixed (char* ap = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) - fixed (char* bp = &MemoryMarshal.GetReference(suffix)) - { - char* a = ap + source.Length - 1; - char* b = bp + suffix.Length - 1; - - while (length != 0) - { - int charA = *a; - int charB = *b; - - if (charA >= 0x80 || charB >= 0x80 || HighCharTable[charA] || HighCharTable[charB]) - goto InteropCall; - - if (charA == charB) - { - a--; b--; - length--; - continue; - } - - return false; - } - - return (source.Length >= suffix.Length); - - InteropCall: - return Interop.Globalization.EndsWith(_sortHandle, bp, suffix.Length, ap, source.Length, options); - } - } - - private unsafe SortKey CreateSortKey(string source, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - if (source==null) { throw new ArgumentNullException(nameof(source)); } - - if ((options & ValidCompareMaskOffFlags) != 0) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } - - byte[] keyData; - fixed (char* pSource = source) - { - int sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, null, 0, options); - keyData = new byte[sortKeyLength]; - - fixed (byte* pSortKey = keyData) - { - if (Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKeyLength, options) != sortKeyLength) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - } - } - - return new SortKey(this, source, options, keyData); - } - - private static unsafe bool IsSortable(char *text, int length) - { - Debug.Assert(!GlobalizationMode.Invariant); - - int index = 0; - UnicodeCategory uc; - - while (index < length) - { - if (char.IsHighSurrogate(text[index])) - { - if (index == length - 1 || !char.IsLowSurrogate(text[index+1])) - return false; // unpaired surrogate - - uc = CharUnicodeInfo.GetUnicodeCategory(char.ConvertToUtf32(text[index], text[index+1])); - if (uc == UnicodeCategory.PrivateUse || uc == UnicodeCategory.OtherNotAssigned) - return false; - - index += 2; - continue; - } - - if (char.IsLowSurrogate(text[index])) - { - return false; // unpaired surrogate - } - - uc = CharUnicodeInfo.GetUnicodeCategory(text[index]); - if (uc == UnicodeCategory.PrivateUse || uc == UnicodeCategory.OtherNotAssigned) - { - return false; - } - - index++; - } - - return true; - } - - // ----------------------------- - // ---- PAL layer ends here ---- - // ----------------------------- - - internal unsafe int GetHashCodeOfStringCore(ReadOnlySpan source, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - // according to ICU User Guide the performance of ucol_getSortKey is worse when it is called with null output buffer - // the solution is to try to fill the sort key in a temporary buffer of size equal 4 x string length - // 1MB is the biggest array that can be rented from ArrayPool.Shared without memory allocation - int sortKeyLength = (source.Length > 1024 * 1024 / 4) ? 0 : 4 * source.Length; - - byte[]? borrowedArray = null; - Span sortKey = sortKeyLength <= 1024 - ? stackalloc byte[1024] - : (borrowedArray = ArrayPool.Shared.Rent(sortKeyLength)); - - fixed (char* pSource = &MemoryMarshal.GetNonNullPinnableReference(source)) - { - fixed (byte* pSortKey = &MemoryMarshal.GetReference(sortKey)) - { - sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKey.Length, options); - } - - if (sortKeyLength > sortKey.Length) // slow path for big strings - { - if (borrowedArray != null) - { - ArrayPool.Shared.Return(borrowedArray); - } - - sortKey = (borrowedArray = ArrayPool.Shared.Rent(sortKeyLength)); - - fixed (byte* pSortKey = &MemoryMarshal.GetReference(sortKey)) - { - sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKey.Length, options); - } - } - } - - if (sortKeyLength == 0 || sortKeyLength > sortKey.Length) // internal error (0) or a bug (2nd call failed) in ucol_getSortKey - { - throw new ArgumentException(SR.Arg_ExternalException); - } - - int hash = Marvin.ComputeHash32(sortKey.Slice(0, sortKeyLength), Marvin.DefaultSeed); - - if (borrowedArray != null) - { - ArrayPool.Shared.Return(borrowedArray); - } - - return hash; - } - - private static CompareOptions GetOrdinalCompareOptions(CompareOptions options) - { - if ((options & CompareOptions.IgnoreCase) != 0) - { - return CompareOptions.OrdinalIgnoreCase; - } - else - { - return CompareOptions.Ordinal; - } - } - - private static bool CanUseAsciiOrdinalForOptions(CompareOptions options) - { - // Unlike the other Ignore options, IgnoreSymbols impacts ASCII characters (e.g. '). - return (options & CompareOptions.IgnoreSymbols) == 0; - } - - private SortVersion GetSortVersion() - { - Debug.Assert(!GlobalizationMode.Invariant); - - int sortVersion = Interop.Globalization.GetSortVersion(_sortHandle); - return new SortVersion(sortVersion, LCID, new Guid(sortVersion, 0, 0, 0, 0, 0, 0, - (byte) (LCID >> 24), - (byte) ((LCID & 0x00FF0000) >> 16), - (byte) ((LCID & 0x0000FF00) >> 8), - (byte) (LCID & 0xFF))); - } - - private static class SortHandleCache - { - // in most scenarios there is a limited number of cultures with limited number of sort options - // so caching the sort handles and not freeing them is OK, see https://github.com/dotnet/coreclr/pull/25117 for more - private static readonly Dictionary s_sortNameToSortHandleCache = new Dictionary(); - - internal static IntPtr GetCachedSortHandle(string sortName) - { - lock (s_sortNameToSortHandleCache) - { - if (!s_sortNameToSortHandleCache.TryGetValue(sortName, out IntPtr result)) - { - Interop.Globalization.ResultCode resultCode = Interop.Globalization.GetSortHandle(sortName, out result); - - if (resultCode == Interop.Globalization.ResultCode.OutOfMemory) - throw new OutOfMemoryException(); - else if (resultCode != Interop.Globalization.ResultCode.Success) - throw new ExternalException(SR.Arg_ExternalException); - - try - { - s_sortNameToSortHandleCache.Add(sortName, result); - } - catch - { - Interop.Globalization.CloseSortHandle(result); - - throw; - } - } - - return result; - } - } - } - - private static ReadOnlySpan HighCharTable => new bool[0x80] - { - true, /* 0x0, 0x0 */ - true, /* 0x1, .*/ - true, /* 0x2, .*/ - true, /* 0x3, .*/ - true, /* 0x4, .*/ - true, /* 0x5, .*/ - true, /* 0x6, .*/ - true, /* 0x7, .*/ - true, /* 0x8, .*/ - false, /* 0x9, */ - true, /* 0xA, */ - false, /* 0xB, .*/ - false, /* 0xC, .*/ - true, /* 0xD, */ - true, /* 0xE, .*/ - true, /* 0xF, .*/ - true, /* 0x10, .*/ - true, /* 0x11, .*/ - true, /* 0x12, .*/ - true, /* 0x13, .*/ - true, /* 0x14, .*/ - true, /* 0x15, .*/ - true, /* 0x16, .*/ - true, /* 0x17, .*/ - true, /* 0x18, .*/ - true, /* 0x19, .*/ - true, /* 0x1A, */ - true, /* 0x1B, .*/ - true, /* 0x1C, .*/ - true, /* 0x1D, .*/ - true, /* 0x1E, .*/ - true, /* 0x1F, .*/ - false, /*0x20, */ - false, /*0x21, !*/ - false, /*0x22, "*/ - false, /*0x23, #*/ - false, /*0x24, $*/ - false, /*0x25, %*/ - false, /*0x26, &*/ - true, /*0x27, '*/ - false, /*0x28, (*/ - false, /*0x29, )*/ - false, /*0x2A **/ - false, /*0x2B, +*/ - false, /*0x2C, ,*/ - true, /*0x2D, -*/ - false, /*0x2E, .*/ - false, /*0x2F, /*/ - false, /*0x30, 0*/ - false, /*0x31, 1*/ - false, /*0x32, 2*/ - false, /*0x33, 3*/ - false, /*0x34, 4*/ - false, /*0x35, 5*/ - false, /*0x36, 6*/ - false, /*0x37, 7*/ - false, /*0x38, 8*/ - false, /*0x39, 9*/ - false, /*0x3A, :*/ - false, /*0x3B, ;*/ - false, /*0x3C, <*/ - false, /*0x3D, =*/ - false, /*0x3E, >*/ - false, /*0x3F, ?*/ - false, /*0x40, @*/ - false, /*0x41, A*/ - false, /*0x42, B*/ - false, /*0x43, C*/ - false, /*0x44, D*/ - false, /*0x45, E*/ - false, /*0x46, F*/ - false, /*0x47, G*/ - false, /*0x48, H*/ - false, /*0x49, I*/ - false, /*0x4A, J*/ - false, /*0x4B, K*/ - false, /*0x4C, L*/ - false, /*0x4D, M*/ - false, /*0x4E, N*/ - false, /*0x4F, O*/ - false, /*0x50, P*/ - false, /*0x51, Q*/ - false, /*0x52, R*/ - false, /*0x53, S*/ - false, /*0x54, T*/ - false, /*0x55, U*/ - false, /*0x56, V*/ - false, /*0x57, W*/ - false, /*0x58, X*/ - false, /*0x59, Y*/ - false, /*0x5A, Z*/ - false, /*0x5B, [*/ - false, /*0x5C, \*/ - false, /*0x5D, ]*/ - false, /*0x5E, ^*/ - false, /*0x5F, _*/ - false, /*0x60, `*/ - false, /*0x61, a*/ - false, /*0x62, b*/ - false, /*0x63, c*/ - false, /*0x64, d*/ - false, /*0x65, e*/ - false, /*0x66, f*/ - false, /*0x67, g*/ - false, /*0x68, h*/ - false, /*0x69, i*/ - false, /*0x6A, j*/ - false, /*0x6B, k*/ - false, /*0x6C, l*/ - false, /*0x6D, m*/ - false, /*0x6E, n*/ - false, /*0x6F, o*/ - false, /*0x70, p*/ - false, /*0x71, q*/ - false, /*0x72, r*/ - false, /*0x73, s*/ - false, /*0x74, t*/ - false, /*0x75, u*/ - false, /*0x76, v*/ - false, /*0x77, w*/ - false, /*0x78, x*/ - false, /*0x79, y*/ - false, /*0x7A, z*/ - false, /*0x7B, {*/ - false, /*0x7C, |*/ - false, /*0x7D, }*/ - false, /*0x7E, ~*/ - true, /*0x7F, */ - }; - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Windows.cs deleted file mode 100644 index cbc7ac00209d27..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Windows.cs +++ /dev/null @@ -1,587 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Buffers; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace System.Globalization -{ - public partial class CompareInfo - { - internal static unsafe IntPtr GetSortHandle(string cultureName) - { - if (GlobalizationMode.Invariant) - { - return IntPtr.Zero; - } - - IntPtr handle; - int ret = Interop.Kernel32.LCMapStringEx(cultureName, Interop.Kernel32.LCMAP_SORTHANDLE, null, 0, &handle, IntPtr.Size, null, null, IntPtr.Zero); - if (ret > 0) - { - // Even if we can get the sort handle, it is not guaranteed to work when Windows compatibility shim is applied - // e.g. Windows 7 compatibility mode. We need to ensure it is working before using it. - // otherwise the whole framework app will not start. - int hashValue = 0; - char a = 'a'; - ret = Interop.Kernel32.LCMapStringEx(null, Interop.Kernel32.LCMAP_HASH, &a, 1, &hashValue, sizeof(int), null, null, handle); - if (ret > 1) - { - return handle; - } - } - - return IntPtr.Zero; - } - - private void InitSort(CultureInfo culture) - { - _sortName = culture.SortName; - _sortHandle = GetSortHandle(_sortName); - } - - private static unsafe int FindStringOrdinal( - uint dwFindStringOrdinalFlags, - ReadOnlySpan source, - ReadOnlySpan value, - bool bIgnoreCase) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); - Debug.Assert(!value.IsEmpty); - - fixed (char* pSource = &MemoryMarshal.GetReference(source)) - fixed (char* pValue = &MemoryMarshal.GetReference(value)) - { - Debug.Assert(pSource != null); - Debug.Assert(pValue != null); - - int ret = Interop.Kernel32.FindStringOrdinal( - dwFindStringOrdinalFlags, - pSource, - source.Length, - pValue, - value.Length, - bIgnoreCase ? Interop.BOOL.TRUE : Interop.BOOL.FALSE); - - Debug.Assert(ret >= -1 && ret <= source.Length); - - // SetLastError is only performed under debug builds. - Debug.Assert(ret >= 0 || Marshal.GetLastWin32Error() == Interop.Errors.ERROR_SUCCESS); - - return ret; - } - } - - internal static int IndexOfOrdinalCore(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source.Length != 0); - Debug.Assert(value.Length != 0); - - uint positionFlag = fromBeginning ? (uint)FIND_FROMSTART : FIND_FROMEND; - return FindStringOrdinal(positionFlag, source, value, ignoreCase); - } - - internal static int LastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source != null); - Debug.Assert(value != null); - - int offset = startIndex - count + 1; - int result = FindStringOrdinal(FIND_FROMEND, source.AsSpan(offset, count), value, ignoreCase); - if (result >= 0) - { - result += offset; - } - return result; - } - - private unsafe int GetHashCodeOfStringCore(ReadOnlySpan source, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - // LCMapStringEx doesn't support passing cchSrc = 0, so if given a null or empty input - // we'll normalize it to an empty null-terminated string and pass -1 to indicate that - // the underlying OS function should read until it encounters the null terminator. - - int sourceLength = source.Length; - if (sourceLength == 0) - { - source = string.Empty; - sourceLength = -1; - } - - uint flags = LCMAP_SORTKEY | (uint)GetNativeCompareFlags(options); - - fixed (char* pSource = &MemoryMarshal.GetReference(source)) - { - int sortKeyLength = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, - flags, - pSource, sourceLength /* in chars */, - null, 0, - null, null, _sortHandle); - if (sortKeyLength == 0) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - - // Note in calls to LCMapStringEx below, the input buffer is specified in wchars (and wchar count), - // but the output buffer is specified in bytes (and byte count). This is because when generating - // sort keys, LCMapStringEx treats the output buffer as containing opaque binary data. - // See https://docs.microsoft.com/en-us/windows/desktop/api/winnls/nf-winnls-lcmapstringex. - - byte[]? borrowedArr = null; - Span span = sortKeyLength <= 512 ? - stackalloc byte[512] : - (borrowedArr = ArrayPool.Shared.Rent(sortKeyLength)); - - fixed (byte* pSortKey = &MemoryMarshal.GetReference(span)) - { - if (Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, - flags, - pSource, sourceLength /* in chars */, - pSortKey, sortKeyLength, - null, null, _sortHandle) != sortKeyLength) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - } - - int hash = Marvin.ComputeHash32(span.Slice(0, sortKeyLength), Marvin.DefaultSeed); - - // Return the borrowed array if necessary. - if (borrowedArr != null) - { - ArrayPool.Shared.Return(borrowedArr); - } - - return hash; - } - } - - private static unsafe int CompareStringOrdinalIgnoreCase(ref char string1, int count1, ref char string2, int count2) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(count1 > 0); - Debug.Assert(count2 > 0); - - fixed (char* char1 = &string1) - fixed (char* char2 = &string2) - { - Debug.Assert(char1 != null); - Debug.Assert(char2 != null); - - // Use the OS to compare and then convert the result to expected value by subtracting 2 - int result = Interop.Kernel32.CompareStringOrdinal(char1, count1, char2, count2, bIgnoreCase: true); - if (result == 0) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - return result - 2; - } - } - - // TODO https://github.com/dotnet/runtime/issues/8890: - // This method shouldn't be necessary, as we should be able to just use the overload - // that takes two spans. But due to this issue, that's adding significant overhead. - private unsafe int CompareString(ReadOnlySpan string1, string string2, CompareOptions options) - { - Debug.Assert(string2 != null); - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - string? localeName = _sortHandle != IntPtr.Zero ? null : _sortName; - - // CompareStringEx may try to dereference the first character of its input, even if an explicit - // length of 0 is specified. To work around potential AVs we'll always ensure zero-length inputs - // are normalized to a null-terminated empty string. - - if (string1.IsEmpty) - { - string1 = string.Empty; - } - - fixed (char* pLocaleName = localeName) - fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) - fixed (char* pString2 = &string2.GetPinnableReference()) - { - Debug.Assert(*pString1 >= 0); // assert that we can always dereference this - Debug.Assert(*pString2 >= 0); // assert that we can always dereference this - - int result = Interop.Kernel32.CompareStringEx( - pLocaleName, - (uint)GetNativeCompareFlags(options), - pString1, - string1.Length, - pString2, - string2.Length, - null, - null, - _sortHandle); - - if (result == 0) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - - // Map CompareStringEx return value to -1, 0, 1. - return result - 2; - } - } - - private unsafe int CompareString(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - string? localeName = _sortHandle != IntPtr.Zero ? null : _sortName; - - // CompareStringEx may try to dereference the first character of its input, even if an explicit - // length of 0 is specified. To work around potential AVs we'll always ensure zero-length inputs - // are normalized to a null-terminated empty string. - - if (string1.IsEmpty) - { - string1 = string.Empty; - } - - if (string2.IsEmpty) - { - string2 = string.Empty; - } - - fixed (char* pLocaleName = localeName) - fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) - fixed (char* pString2 = &MemoryMarshal.GetReference(string2)) - { - Debug.Assert(*pString1 >= 0); // assert that we can always dereference this - Debug.Assert(*pString2 >= 0); // assert that we can always dereference this - - int result = Interop.Kernel32.CompareStringEx( - pLocaleName, - (uint)GetNativeCompareFlags(options), - pString1, - string1.Length, - pString2, - string2.Length, - null, - null, - _sortHandle); - - if (result == 0) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - - // Map CompareStringEx return value to -1, 0, 1. - return result - 2; - } - } - - private unsafe int FindString( - uint dwFindNLSStringFlags, - ReadOnlySpan lpStringSource, - ReadOnlySpan lpStringValue, - int* pcchFound) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!lpStringValue.IsEmpty); - - string? localeName = _sortHandle != IntPtr.Zero ? null : _sortName; - - // FindNLSStringEx disallows passing an explicit 0 for cchSource or cchValue. - // The caller should've already checked that 'lpStringValue' isn't empty, - // but it's possible for 'lpStringSource' to be empty. In this case we'll - // substitute an empty null-terminated string and pass -1 so that the NLS - // function uses the implicit string length. - - int lpStringSourceLength = lpStringSource.Length; - if (lpStringSourceLength == 0) - { - lpStringSource = string.Empty; - lpStringSourceLength = -1; - } - - fixed (char* pLocaleName = localeName) - fixed (char* pSource = &MemoryMarshal.GetReference(lpStringSource)) - fixed (char* pValue = &MemoryMarshal.GetReference(lpStringValue)) - { - Debug.Assert(pSource != null && pValue != null); - - int result = Interop.Kernel32.FindNLSStringEx( - pLocaleName, - dwFindNLSStringFlags, - pSource, - lpStringSourceLength, - pValue, - lpStringValue.Length, - pcchFound, - null, - null, - _sortHandle); - - Debug.Assert(result >= -1 && result <= lpStringSource.Length); - - // SetLastError is only performed under debug builds. - Debug.Assert(result >= 0 || Marshal.GetLastWin32Error() == Interop.Errors.ERROR_SUCCESS); - - return result; - } - } - - internal unsafe int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options, int* matchLengthPtr) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(target != null); - Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0); - Debug.Assert((options & CompareOptions.Ordinal) == 0); - - int retValue = FindString(FIND_FROMSTART | (uint)GetNativeCompareFlags(options), source.AsSpan(startIndex, count), target, matchLengthPtr); - if (retValue >= 0) - { - return retValue + startIndex; - } - - return -1; - } - - internal unsafe int IndexOfCore(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(target.Length != 0); - Debug.Assert(options == CompareOptions.None || options == CompareOptions.IgnoreCase); - - uint positionFlag = fromBeginning ? (uint)FIND_FROMSTART : FIND_FROMEND; - return FindString(positionFlag | (uint)GetNativeCompareFlags(options), source, target, matchLengthPtr); - } - - private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!string.IsNullOrEmpty(source)); - Debug.Assert(target != null); - Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0); - - // startIndex points to the final char to include in the search space. - // empty target strings trivially occur at the end of the search space. - - if (target.Length == 0) - return startIndex + 1; - - if ((options & CompareOptions.Ordinal) != 0) - { - return FastLastIndexOfString(source, target, startIndex, count, target.Length); - } - else - { - int retValue = FindString(FIND_FROMEND | (uint)GetNativeCompareFlags(options), source.AsSpan(startIndex - count + 1, count), target, null); - - if (retValue >= 0) - { - return retValue + startIndex - (count - 1); - } - } - - return -1; - } - - private unsafe bool StartsWith(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!source.IsEmpty); - Debug.Assert(!prefix.IsEmpty); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - return FindString(FIND_STARTSWITH | (uint)GetNativeCompareFlags(options), source, prefix, null) >= 0; - } - - private unsafe bool EndsWith(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!suffix.IsEmpty); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - return FindString(FIND_ENDSWITH | (uint)GetNativeCompareFlags(options), source, suffix, null) >= 0; - } - - // PAL ends here - [NonSerialized] - private IntPtr _sortHandle; - - private const uint LCMAP_SORTKEY = 0x00000400; - - private const int FIND_STARTSWITH = 0x00100000; - private const int FIND_ENDSWITH = 0x00200000; - private const int FIND_FROMSTART = 0x00400000; - private const int FIND_FROMEND = 0x00800000; - - // TODO: Instead of this method could we just have upstack code call LastIndexOfOrdinal with ignoreCase = false? - private static unsafe int FastLastIndexOfString(string source, string target, int startIndex, int sourceCount, int targetCount) - { - int retValue = -1; - - int sourceStartIndex = startIndex - sourceCount + 1; - - fixed (char* pSource = source, spTarget = target) - { - char* spSubSource = pSource + sourceStartIndex; - - int endPattern = sourceCount - targetCount; - if (endPattern < 0) - return -1; - - Debug.Assert(target.Length >= 1); - char patternChar0 = spTarget[0]; - for (int ctrSrc = endPattern; ctrSrc >= 0; ctrSrc--) - { - if (spSubSource[ctrSrc] != patternChar0) - continue; - - int ctrPat; - for (ctrPat = 1; ctrPat < targetCount; ctrPat++) - { - if (spSubSource[ctrSrc + ctrPat] != spTarget[ctrPat]) - break; - } - if (ctrPat == targetCount) - { - retValue = ctrSrc; - break; - } - } - - if (retValue >= 0) - { - retValue += startIndex - sourceCount + 1; - } - } - - return retValue; - } - - private unsafe SortKey CreateSortKey(string source, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - if (source == null) { throw new ArgumentNullException(nameof(source)); } - - if ((options & ValidCompareMaskOffFlags) != 0) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } - - byte[] keyData; - uint flags = LCMAP_SORTKEY | (uint)GetNativeCompareFlags(options); - - // LCMapStringEx doesn't support passing cchSrc = 0, so if given an empty string - // we'll instead pass -1 to indicate a null-terminated empty string. - - int sourceLength = source.Length; - if (sourceLength == 0) - { - sourceLength = -1; - } - - fixed (char* pSource = source) - { - int sortKeyLength = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, - flags, - pSource, sourceLength, - null, 0, - null, null, _sortHandle); - if (sortKeyLength == 0) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - - keyData = new byte[sortKeyLength]; - - fixed (byte* pBytes = keyData) - { - if (Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, - flags, - pSource, sourceLength, - pBytes, keyData.Length, - null, null, _sortHandle) != sortKeyLength) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - } - } - - return new SortKey(this, source, options, keyData); - } - - private static unsafe bool IsSortable(char* text, int length) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(text != null); - - return Interop.Kernel32.IsNLSDefinedString(Interop.Kernel32.COMPARE_STRING, 0, IntPtr.Zero, text, length); - } - - private const int COMPARE_OPTIONS_ORDINAL = 0x40000000; // Ordinal - private const int NORM_IGNORECASE = 0x00000001; // Ignores case. (use LINGUISTIC_IGNORECASE instead) - private const int NORM_IGNOREKANATYPE = 0x00010000; // Does not differentiate between Hiragana and Katakana characters. Corresponding Hiragana and Katakana will compare as equal. - private const int NORM_IGNORENONSPACE = 0x00000002; // Ignores nonspacing. This flag also removes Japanese accent characters. (use LINGUISTIC_IGNOREDIACRITIC instead) - private const int NORM_IGNORESYMBOLS = 0x00000004; // Ignores symbols. - private const int NORM_IGNOREWIDTH = 0x00020000; // Does not differentiate between a single-byte character and the same character as a double-byte character. - private const int NORM_LINGUISTIC_CASING = 0x08000000; // use linguistic rules for casing - private const int SORT_STRINGSORT = 0x00001000; // Treats punctuation the same as symbols. - - private static int GetNativeCompareFlags(CompareOptions options) - { - // Use "linguistic casing" by default (load the culture's casing exception tables) - int nativeCompareFlags = NORM_LINGUISTIC_CASING; - - if ((options & CompareOptions.IgnoreCase) != 0) { nativeCompareFlags |= NORM_IGNORECASE; } - if ((options & CompareOptions.IgnoreKanaType) != 0) { nativeCompareFlags |= NORM_IGNOREKANATYPE; } - if ((options & CompareOptions.IgnoreNonSpace) != 0) { nativeCompareFlags |= NORM_IGNORENONSPACE; } - if ((options & CompareOptions.IgnoreSymbols) != 0) { nativeCompareFlags |= NORM_IGNORESYMBOLS; } - if ((options & CompareOptions.IgnoreWidth) != 0) { nativeCompareFlags |= NORM_IGNOREWIDTH; } - if ((options & CompareOptions.StringSort) != 0) { nativeCompareFlags |= SORT_STRINGSORT; } - - // TODO: Can we try for GetNativeCompareFlags to never - // take Ordinal or OrdinalIgnoreCase. This value is not part of Win32, we just handle it special - // in some places. - // Suffix & Prefix shouldn't use this, make sure to turn off the NORM_LINGUISTIC_CASING flag - if (options == CompareOptions.Ordinal) { nativeCompareFlags = COMPARE_OPTIONS_ORDINAL; } - - Debug.Assert(((options & ~(CompareOptions.IgnoreCase | - CompareOptions.IgnoreKanaType | - CompareOptions.IgnoreNonSpace | - CompareOptions.IgnoreSymbols | - CompareOptions.IgnoreWidth | - CompareOptions.StringSort)) == 0) || - (options == CompareOptions.Ordinal), "[CompareInfo.GetNativeCompareFlags]Expected all flags to be handled"); - - return nativeCompareFlags; - } - - private unsafe SortVersion GetSortVersion() - { - Debug.Assert(!GlobalizationMode.Invariant); - - Interop.Kernel32.NlsVersionInfoEx nlsVersion = default; - nlsVersion.dwNLSVersionInfoSize = sizeof(Interop.Kernel32.NlsVersionInfoEx); - Interop.Kernel32.GetNLSVersionEx(Interop.Kernel32.COMPARE_STRING, _sortName, &nlsVersion); - return new SortVersion( - nlsVersion.dwNLSVersion, - nlsVersion.dwEffectiveId == 0 ? LCID : nlsVersion.dwEffectiveId, - nlsVersion.guidCustomVersion); - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.cs index 57c6f81afeb2c8..16bf6d16f4baeb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.cs @@ -3,10 +3,12 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; +using System.Text; using System.Text.Unicode; using Internal.Runtime.CompilerServices; @@ -40,7 +42,10 @@ public sealed partial class CompareInfo : IDeserializationCallback private string m_name; // The name used to construct this CompareInfo. Do not rename (binary serialization) [NonSerialized] - private string _sortName = null!; // The name that defines our behavior + private IntPtr _sortHandle; + + [NonSerialized] + private string _sortName; // The name that defines our behavior [OptionalField(VersionAdded = 3)] private SortVersion? m_SortVersion; // Do not rename (binary serialization) @@ -123,24 +128,31 @@ public static CompareInfo GetCompareInfo(string name) return CultureInfo.GetCultureInfo(name).CompareInfo; } - public static unsafe bool IsSortable(char ch) + public static bool IsSortable(char ch) { - if (GlobalizationMode.Invariant) - { - return true; - } - - char* pChar = &ch; - return IsSortable(pChar, 1); + return IsSortable(MemoryMarshal.CreateReadOnlySpan(ref ch, 1)); } - public static unsafe bool IsSortable(string text) + public static bool IsSortable(string text) { if (text == null) { throw new ArgumentNullException(nameof(text)); } + return IsSortable(text.AsSpan()); + } + + /// + /// Indicates whether a specified Unicode string is sortable. + /// + /// A string of zero or more Unicode characters. + /// + /// if is non-empty and contains + /// only sortable Unicode characters; otherwise, . + /// + public static bool IsSortable(ReadOnlySpan text) + { if (text.Length == 0) { return false; @@ -148,12 +160,39 @@ public static unsafe bool IsSortable(string text) if (GlobalizationMode.Invariant) { - return true; + return true; // all chars are sortable in invariant mode } - fixed (char* pChar = text) + return (GlobalizationMode.UseNls) ? NlsIsSortable(text) : IcuIsSortable(text); + } + + /// + /// Indicates whether a specified is sortable. + /// + /// A Unicode scalar value. + /// + /// if is a sortable Unicode scalar + /// value; otherwise, . + /// + public static bool IsSortable(Rune value) + { + Span valueAsUtf16 = stackalloc char[Rune.MaxUtf16CharsPerRune]; + int charCount = value.EncodeToUtf16(valueAsUtf16); + return IsSortable(valueAsUtf16.Slice(0, charCount)); + } + + [MemberNotNull(nameof(_sortName))] + private void InitSort(CultureInfo culture) + { + _sortName = culture.SortName; + + if (GlobalizationMode.UseNls) { - return IsSortable(pChar, text.Length); + NlsInitSortHandle(); + } + else + { + IcuInitSortHandle(); } } @@ -235,121 +274,38 @@ public int Compare(string? string1, string? string2) public int Compare(string? string1, string? string2, CompareOptions options) { - if (options == CompareOptions.OrdinalIgnoreCase) - { - return string.Compare(string1, string2, StringComparison.OrdinalIgnoreCase); - } - - // Verify the options before we do any real comparison. - if ((options & CompareOptions.Ordinal) != 0) - { - if (options != CompareOptions.Ordinal) - { - throw new ArgumentException(SR.Argument_CompareOptionOrdinal, nameof(options)); - } - - return string.CompareOrdinal(string1, string2); - } - - if ((options & ValidCompareMaskOffFlags) != 0) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } + int retVal; // Our paradigm is that null sorts less than any other string and // that two nulls sort as equal. - if (string1 == null) - { - if (string2 == null) - { - return 0; - } - return -1; // null < non-null - } - if (string2 == null) - { - return 1; // non-null > null - } - - if (GlobalizationMode.Invariant) - { - if ((options & CompareOptions.IgnoreCase) != 0) - { - return CompareOrdinalIgnoreCase(string1, string2); - } - - return string.CompareOrdinal(string1, string2); - } - - return CompareString(string1.AsSpan(), string2.AsSpan(), options); - } - - // TODO https://github.com/dotnet/runtime/issues/8890: - // This method shouldn't be necessary, as we should be able to just use the overload - // that takes two spans. But due to this issue, that's adding significant overhead. - internal int Compare(ReadOnlySpan string1, string? string2, CompareOptions options) - { - if (options == CompareOptions.OrdinalIgnoreCase) - { - return CompareOrdinalIgnoreCase(string1, string2.AsSpan()); - } - - // Verify the options before we do any real comparison. - if ((options & CompareOptions.Ordinal) != 0) - { - if (options != CompareOptions.Ordinal) - { - throw new ArgumentException(SR.Argument_CompareOptionOrdinal, nameof(options)); - } - return string.CompareOrdinal(string1, string2.AsSpan()); - } - - if ((options & ValidCompareMaskOffFlags) != 0) + if (string1 == null) { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + retVal = (string2 == null) ? 0 : -1; + goto CheckOptionsAndReturn; } - - // null sorts less than any other string. if (string2 == null) { - return 1; + retVal = 1; + goto CheckOptionsAndReturn; } - if (GlobalizationMode.Invariant) - { - return (options & CompareOptions.IgnoreCase) != 0 ? - CompareOrdinalIgnoreCase(string1, string2.AsSpan()) : - string.CompareOrdinal(string1, string2.AsSpan()); - } + return Compare(string1.AsSpan(), string2.AsSpan(), options); - return CompareString(string1, string2, options); - } + CheckOptionsAndReturn: - internal int CompareOptionNone(ReadOnlySpan string1, ReadOnlySpan string2) - { - // Check for empty span or span from a null string - if (string1.Length == 0 || string2.Length == 0) - { - return string1.Length - string2.Length; - } + // If we're short-circuiting the globalization logic, we still need to check that + // the provided options were valid. - return GlobalizationMode.Invariant ? - string.CompareOrdinal(string1, string2) : - CompareString(string1, string2, CompareOptions.None); + CheckCompareOptionsForCompare(options); + return retVal; } internal int CompareOptionIgnoreCase(ReadOnlySpan string1, ReadOnlySpan string2) { - // Check for empty span or span from a null string - if (string1.Length == 0 || string2.Length == 0) - { - return string1.Length - string2.Length; - } - return GlobalizationMode.Invariant ? CompareOrdinalIgnoreCase(string1, string2) : - CompareString(string1, string2, CompareOptions.IgnoreCase); + CompareStringCore(string1, string2, CompareOptions.IgnoreCase); } /// @@ -361,7 +317,7 @@ internal int CompareOptionIgnoreCase(ReadOnlySpan string1, ReadOnlySpan public int Compare(string? string1, int offset1, int length1, string? string2, int offset2, int length2) { - return Compare(string1, offset1, length1, string2, offset2, length2, 0); + return Compare(string1, offset1, length1, string2, offset2, length2, CompareOptions.None); } public int Compare(string? string1, int offset1, string? string2, int offset2, CompareOptions options) @@ -372,85 +328,195 @@ public int Compare(string? string1, int offset1, string? string2, int offset2, C public int Compare(string? string1, int offset1, string? string2, int offset2) { - return Compare(string1, offset1, string2, offset2, 0); + return Compare(string1, offset1, string2, offset2, CompareOptions.None); } public int Compare(string? string1, int offset1, int length1, string? string2, int offset2, int length2, CompareOptions options) { - if (options == CompareOptions.OrdinalIgnoreCase) + ReadOnlySpan span1 = default; + ReadOnlySpan span2 = default; + + if (string1 == null) { - int result = string.Compare(string1, offset1, string2, offset2, length1 < length2 ? length1 : length2, StringComparison.OrdinalIgnoreCase); - if ((length1 != length2) && result == 0) + if (offset1 != 0 || length1 != 0) { - return length1 > length2 ? 1 : -1; + goto BoundsCheckError; } + } + else if (!string1.TryGetSpan(offset1, length1, out span1)) + { + goto BoundsCheckError; + } + + if (string2 == null) + { + if (offset2 != 0 || length2 != 0) + { + goto BoundsCheckError; + } + } + else if (!string2.TryGetSpan(offset2, length2, out span2)) + { + goto BoundsCheckError; + } + + // At this point both string1 and string2 have been bounds-checked. + + int retVal; - return result; + // Our paradigm is that null sorts less than any other string and + // that two nulls sort as equal. + + if (string1 == null) + { + retVal = (string2 == null) ? 0 : -1; + goto CheckOptionsAndReturn; + } + if (string2 == null) + { + retVal = 1; + goto CheckOptionsAndReturn; } + // At this point we know both string1 and string2 weren't null, + // though they may have been empty. + + Debug.Assert(!Unsafe.IsNullRef(ref MemoryMarshal.GetReference(span1))); + Debug.Assert(!Unsafe.IsNullRef(ref MemoryMarshal.GetReference(span2))); + + return Compare(span1, span2, options); + + CheckOptionsAndReturn: + + // If we're short-circuiting the globalization logic, we still need to check that + // the provided options were valid. + + CheckCompareOptionsForCompare(options); + return retVal; + + BoundsCheckError: + + // We know a bounds check error occurred. Now we just need to figure + // out the correct error message to surface. + if (length1 < 0 || length2 < 0) { throw new ArgumentOutOfRangeException((length1 < 0) ? nameof(length1) : nameof(length2), SR.ArgumentOutOfRange_NeedPosNum); } + if (offset1 < 0 || offset2 < 0) { throw new ArgumentOutOfRangeException((offset1 < 0) ? nameof(offset1) : nameof(offset2), SR.ArgumentOutOfRange_NeedPosNum); } + if (offset1 > (string1 == null ? 0 : string1.Length) - length1) { throw new ArgumentOutOfRangeException(nameof(string1), SR.ArgumentOutOfRange_OffsetLength); } - if (offset2 > (string2 == null ? 0 : string2.Length) - length2) + + Debug.Assert(offset2 > (string2 == null ? 0 : string2.Length) - length2); + throw new ArgumentOutOfRangeException(nameof(string2), SR.ArgumentOutOfRange_OffsetLength); + } + + /// + /// Compares two strings. + /// + /// The first string to compare. + /// The second string to compare. + /// The to use during the comparison. + /// + /// Zero if and are equal; + /// or a negative value if sorts before ; + /// or a positive value if sorts after . + /// + /// + /// contains an unsupported combination of flags. + /// + public int Compare(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options = CompareOptions.None) + { + if (string1 == string2) // referential equality + length { - throw new ArgumentOutOfRangeException(nameof(string2), SR.ArgumentOutOfRange_OffsetLength); + CheckCompareOptionsForCompare(options); + return 0; } - if ((options & CompareOptions.Ordinal) != 0) + + if ((options & ValidCompareMaskOffFlags) == 0) { - if (options != CompareOptions.Ordinal) + // Common case: caller is attempting to perform linguistic comparison. + // Pass the flags down to NLS or ICU unless we're running in invariant + // mode, at which point we normalize the flags to Orginal[IgnoreCase]. + + if (!GlobalizationMode.Invariant) { - throw new ArgumentException(SR.Argument_CompareOptionOrdinal, - nameof(options)); + return CompareStringCore(string1, string2, options); + } + else if ((options & CompareOptions.IgnoreCase) == 0) + { + goto ReturnOrdinal; + } + else + { + goto ReturnOrdinalIgnoreCase; } } - else if ((options & ValidCompareMaskOffFlags) != 0) + else { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } + // Less common case: caller is attempting to perform non-linguistic comparison, + // or an invalid combination of flags was supplied. - if (string1 == null) - { - if (string2 == null) + if (options == CompareOptions.Ordinal) { - return 0; + goto ReturnOrdinal; + } + else if (options == CompareOptions.OrdinalIgnoreCase) + { + goto ReturnOrdinalIgnoreCase; + } + else + { + ThrowCompareOptionsCheckFailed(options); } - return -1; - } - if (string2 == null) - { - return 1; } - ReadOnlySpan span1 = string1.AsSpan(offset1, length1); - ReadOnlySpan span2 = string2.AsSpan(offset2, length2); + ReturnOrdinal: + return string1.SequenceCompareTo(string2); - if (options == CompareOptions.Ordinal) - { - return string.CompareOrdinal(span1, span2); - } + ReturnOrdinalIgnoreCase: + return CompareOrdinalIgnoreCase(string1, string2); + } - if (GlobalizationMode.Invariant) + // Checks that 'CompareOptions' is valid for a call to Compare, throwing the appropriate + // exception if the check fails. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [StackTraceHidden] + private static void CheckCompareOptionsForCompare(CompareOptions options) + { + // Any combination of defined CompareOptions flags is valid, except for + // Ordinal and OrdinalIgnoreCase, which may only be used in isolation. + + if ((options & ValidCompareMaskOffFlags) != 0) { - if ((options & CompareOptions.IgnoreCase) != 0) + if (options != CompareOptions.Ordinal && options != CompareOptions.OrdinalIgnoreCase) { - return CompareOrdinalIgnoreCase(span1, span2); + ThrowCompareOptionsCheckFailed(options); } - - return string.CompareOrdinal(span1, span2); } + } - return CompareString(span1, span2, options); + [DoesNotReturn] + [StackTraceHidden] + private static void ThrowCompareOptionsCheckFailed(CompareOptions options) + { + throw new ArgumentException( + paramName: nameof(options), + message: ((options & CompareOptions.Ordinal) != 0) ? SR.Argument_CompareOptionOrdinal : SR.Argument_InvalidFlag); } + private unsafe int CompareStringCore(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) => + GlobalizationMode.UseNls ? + NlsCompareString(string1, string2, options) : + IcuCompareString(string1, string2, options); + /// /// CompareOrdinalIgnoreCase compare two string ordinally with ignoring the case. /// it assumes the strings are Ascii string till we hit non Ascii character in strA or strB and then we continue the comparison by @@ -528,7 +594,7 @@ internal static int CompareOrdinalIgnoreCase(ref char strA, int lengthA, ref cha range -= length; - return CompareStringOrdinalIgnoreCase(ref charA, lengthA - range, ref charB, lengthB - range); + return CompareStringOrdinalIgnoreCaseCore(ref charA, lengthA - range, ref charB, lengthB - range); } internal static bool EqualsOrdinalIgnoreCase(ref char charA, ref char charB, int length) @@ -638,7 +704,7 @@ private static bool EqualsOrdinalIgnoreCaseNonAscii(ref char charA, ref char cha { if (!GlobalizationMode.Invariant) { - return CompareStringOrdinalIgnoreCase(ref charA, length, ref charB, length) == 0; + return CompareStringOrdinalIgnoreCaseCore(ref charA, length, ref charB, length) == 0; } else { @@ -670,6 +736,11 @@ private static bool EqualsOrdinalIgnoreCaseNonAscii(ref char charA, ref char cha } } + private static unsafe int CompareStringOrdinalIgnoreCaseCore(ref char string1, int count1, ref char string2, int count2) => + GlobalizationMode.UseNls ? + NlsCompareStringOrdinalIgnoreCase(ref string1, count1, ref string2, count2) : + IcuCompareStringOrdinalIgnoreCase(ref string1, count1, ref string2, count2); + /// /// Determines whether prefix is a prefix of string. If prefix equals /// string.Empty, true is returned. @@ -678,59 +749,93 @@ public bool IsPrefix(string source, string prefix, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } if (prefix == null) { - throw new ArgumentNullException(nameof(prefix)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.prefix); } - if (prefix.Length == 0) + return IsPrefix(source.AsSpan(), prefix.AsSpan(), options); + } + + /// + /// Determines whether a string starts with a specific prefix. + /// + /// The string to search within. + /// The prefix to attempt to match at the start of . + /// The to use during the match. + /// + /// if occurs at the start of ; + /// otherwise, . + /// + /// + /// contains an unsupported combination of flags. + /// + public bool IsPrefix(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options = CompareOptions.None) + { + // The empty string is trivially a prefix of every other string. For compat with + // earlier versions of the Framework we'll early-exit here before validating the + // 'options' argument. + + if (prefix.IsEmpty) { return true; } - if (source.Length == 0) - { - return false; - } - if (options == CompareOptions.OrdinalIgnoreCase) + if ((options & ValidIndexMaskOffFlags) == 0) { - return source.StartsWith(prefix, StringComparison.OrdinalIgnoreCase); - } + // Common case: caller is attempting to perform a linguistic search. + // Pass the flags down to NLS or ICU unless we're running in invariant + // mode, at which point we normalize the flags to Orginal[IgnoreCase]. - if (options == CompareOptions.Ordinal) - { - return source.StartsWith(prefix, StringComparison.Ordinal); + if (!GlobalizationMode.Invariant) + { + return StartsWithCore(source, prefix, options); + } + else if ((options & CompareOptions.IgnoreCase) == 0) + { + goto ReturnOrdinal; + } + else + { + goto ReturnOrdinalIgnoreCase; + } } - - if ((options & ValidIndexMaskOffFlags) != 0) + else { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } + // Less common case: caller is attempting to perform non-linguistic comparison, + // or an invalid combination of flags was supplied. - if (GlobalizationMode.Invariant) - { - return source.StartsWith(prefix, (options & CompareOptions.IgnoreCase) != 0 ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); + if (options == CompareOptions.Ordinal) + { + goto ReturnOrdinal; + } + else if (options == CompareOptions.OrdinalIgnoreCase) + { + goto ReturnOrdinalIgnoreCase; + } + else + { + ThrowCompareOptionsCheckFailed(options); + } } - return StartsWith(source, prefix, options); - } + ReturnOrdinal: + return source.StartsWith(prefix); - internal bool IsPrefix(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) - { - Debug.Assert(prefix.Length != 0); - Debug.Assert(source.Length != 0); - Debug.Assert((options & ValidIndexMaskOffFlags) == 0); - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - return StartsWith(source, prefix, options); + ReturnOrdinalIgnoreCase: + return source.StartsWithOrdinalIgnoreCase(prefix); } + private unsafe bool StartsWithCore(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) => + GlobalizationMode.UseNls ? + NlsStartsWith(source, prefix, options) : + IcuStartsWith(source, prefix, options); + public bool IsPrefix(string source, string prefix) { - return IsPrefix(source, prefix, 0); + return IsPrefix(source, prefix, CompareOptions.None); } /// @@ -741,140 +846,163 @@ public bool IsSuffix(string source, string suffix, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } if (suffix == null) { - throw new ArgumentNullException(nameof(suffix)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.suffix); } - if (suffix.Length == 0) + return IsSuffix(source.AsSpan(), suffix.AsSpan(), options); + } + + /// + /// Determines whether a string ends with a specific suffix. + /// + /// The string to search within. + /// The suffix to attempt to match at the end of . + /// The to use during the match. + /// + /// if occurs at the end of ; + /// otherwise, . + /// + /// + /// contains an unsupported combination of flags. + /// + public bool IsSuffix(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options = CompareOptions.None) + { + // The empty string is trivially a suffix of every other string. For compat with + // earlier versions of the Framework we'll early-exit here before validating the + // 'options' argument. + + if (suffix.IsEmpty) { return true; } - if (source.Length == 0) - { - return false; - } - if (options == CompareOptions.OrdinalIgnoreCase) + if ((options & ValidIndexMaskOffFlags) == 0) { - return source.EndsWith(suffix, StringComparison.OrdinalIgnoreCase); - } + // Common case: caller is attempting to perform a linguistic search. + // Pass the flags down to NLS or ICU unless we're running in invariant + // mode, at which point we normalize the flags to Orginal[IgnoreCase]. - if (options == CompareOptions.Ordinal) - { - return source.EndsWith(suffix, StringComparison.Ordinal); + if (!GlobalizationMode.Invariant) + { + return EndsWithCore(source, suffix, options); + } + else if ((options & CompareOptions.IgnoreCase) == 0) + { + goto ReturnOrdinal; + } + else + { + goto ReturnOrdinalIgnoreCase; + } } - - if ((options & ValidIndexMaskOffFlags) != 0) + else { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } + // Less common case: caller is attempting to perform non-linguistic comparison, + // or an invalid combination of flags was supplied. - if (GlobalizationMode.Invariant) - { - return source.EndsWith(suffix, (options & CompareOptions.IgnoreCase) != 0 ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); + if (options == CompareOptions.Ordinal) + { + goto ReturnOrdinal; + } + else if (options == CompareOptions.OrdinalIgnoreCase) + { + goto ReturnOrdinalIgnoreCase; + } + else + { + ThrowCompareOptionsCheckFailed(options); + } } - return EndsWith(source, suffix, options); - } + ReturnOrdinal: + return source.EndsWith(suffix); - internal bool IsSuffix(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) - { - Debug.Assert(suffix.Length != 0); - Debug.Assert(source.Length != 0); - Debug.Assert((options & ValidIndexMaskOffFlags) == 0); - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - return EndsWith(source, suffix, options); + ReturnOrdinalIgnoreCase: + return source.EndsWithOrdinalIgnoreCase(suffix); } public bool IsSuffix(string source, string suffix) { - return IsSuffix(source, suffix, 0); + return IsSuffix(source, suffix, CompareOptions.None); } + private unsafe bool EndsWithCore(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) => + GlobalizationMode.UseNls ? + NlsEndsWith(source, suffix, options) : + IcuEndsWith(source, suffix, options); + /// /// Returns the first index where value is found in string. The /// search starts from startIndex and ends at endIndex. Returns -1 if /// the specified value is not found. If value equals string.Empty, /// startIndex is returned. Throws IndexOutOfRange if startIndex or /// endIndex is less than zero or greater than the length of string. - /// Throws ArgumentException if value is null. + /// Throws ArgumentException if value (as a string) is null. /// public int IndexOf(string source, char value) { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - return IndexOf(source, value, 0, source.Length, CompareOptions.None); + return IndexOf(source, value, CompareOptions.None); } public int IndexOf(string source, string value) { - if (source == null) - throw new ArgumentNullException(nameof(source)); - - return IndexOf(source, value, 0, source.Length, CompareOptions.None); + return IndexOf(source, value, CompareOptions.None); } public int IndexOf(string source, char value, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - return IndexOf(source, value, 0, source.Length, options); + return IndexOf(source, MemoryMarshal.CreateReadOnlySpan(ref value, 1), options); } public int IndexOf(string source, string value, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); + } + if (value == null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); } - return IndexOf(source, value, 0, source.Length, options); + return IndexOf(source.AsSpan(), value.AsSpan(), options); } public int IndexOf(string source, char value, int startIndex) { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - return IndexOf(source, value, startIndex, source.Length - startIndex, CompareOptions.None); + return IndexOf(source, value, startIndex, CompareOptions.None); } public int IndexOf(string source, string value, int startIndex) { - if (source == null) - throw new ArgumentNullException(nameof(source)); - - return IndexOf(source, value, startIndex, source.Length - startIndex, CompareOptions.None); + return IndexOf(source, value, startIndex, CompareOptions.None); } public int IndexOf(string source, char value, int startIndex, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } return IndexOf(source, value, startIndex, source.Length - startIndex, options); + } public int IndexOf(string source, string value, int startIndex, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } return IndexOf(source, value, startIndex, source.Length - startIndex, options); @@ -894,222 +1022,266 @@ public unsafe int IndexOf(string source, char value, int startIndex, int count, { if (source == null) { - throw new ArgumentNullException(nameof(source)); - } - if (startIndex < 0 || startIndex > source.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - if (count < 0 || startIndex > source.Length - count) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - if (source.Length == 0) + if (!source.TryGetSpan(startIndex, count, out ReadOnlySpan sourceSpan)) { - return -1; + // Bounds check failed - figure out exactly what went wrong so that we can + // surface the correct argument exception. + + if ((uint)startIndex > (uint)source.Length) + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); + } + else + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_Count); + } } - // Validate CompareOptions - // Ordinal can't be selected with other flags - if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal && options != CompareOptions.OrdinalIgnoreCase)) + int result = IndexOf(sourceSpan, MemoryMarshal.CreateReadOnlySpan(ref value, 1), options); + if (result >= 0) { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + result += startIndex; } - - return IndexOf(source, char.ToString(value), startIndex, count, options, null); + return result; } public unsafe int IndexOf(string source, string value, int startIndex, int count, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } if (value == null) { - throw new ArgumentNullException(nameof(value)); - } - if (startIndex > source.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); } - // In Everett we used to return -1 for empty string even if startIndex is negative number so we keeping same behavior here. - // We return 0 if both source and value are empty strings for Everett compatibility too. - if (source.Length == 0) + if (!source.TryGetSpan(startIndex, count, out ReadOnlySpan sourceSpan)) { - if (value.Length == 0) + // Bounds check failed - figure out exactly what went wrong so that we can + // surface the correct argument exception. + + if ((uint)startIndex > (uint)source.Length) { - return 0; + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); + } + else + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_Count); } - return -1; } - if (startIndex < 0) + int result = IndexOf(sourceSpan, value, options); + if (result >= 0) { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + result += startIndex; } + return result; + } - if (count < 0 || startIndex > source.Length - count) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + /// + /// Searches for the first occurrence of a substring within a source string. + /// + /// The string to search within. + /// The substring to locate within . + /// The to use during the search. + /// + /// The zero-based index into where the substring + /// first appears; or -1 if cannot be found within . + /// + /// + /// contains an unsupported combination of flags. + /// + public unsafe int IndexOf(ReadOnlySpan source, ReadOnlySpan value, CompareOptions options = CompareOptions.None) + { + if ((options & ValidIndexMaskOffFlags) == 0) + { + // Common case: caller is attempting to perform a linguistic search. + // Pass the flags down to NLS or ICU unless we're running in invariant + // mode, at which point we normalize the flags to Orginal[IgnoreCase]. + + if (!GlobalizationMode.Invariant) + { + if (value.IsEmpty) + { + return 0; // Empty target string trivially occurs at index 0 of every search space. + } + else + { + return IndexOfCore(source, value, options, null /* matchLengthPtr */, fromBeginning: true); + } + } + else if ((options & CompareOptions.IgnoreCase) == 0) + { + goto ReturnOrdinal; + } + else + { + goto ReturnOrdinalIgnoreCase; + } } - - // Validate CompareOptions - // Ordinal can't be selected with other flags - if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal && options != CompareOptions.OrdinalIgnoreCase)) + else { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } + // Less common case: caller is attempting to perform non-linguistic comparison, + // or an invalid combination of flags was supplied. - return IndexOf(source, value, startIndex, count, options, null); - } + if (options == CompareOptions.Ordinal) + { + goto ReturnOrdinal; + } + else if (options == CompareOptions.OrdinalIgnoreCase) + { + goto ReturnOrdinalIgnoreCase; + } + else + { + ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidFlag, ExceptionArgument.options); + } + } - internal int IndexOfOrdinalIgnoreCase(ReadOnlySpan source, ReadOnlySpan value) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); - Debug.Assert(!value.IsEmpty); + ReturnOrdinal: + return source.IndexOf(value); - return IndexOfOrdinalCore(source, value, ignoreCase: true, fromBeginning: true); + ReturnOrdinalIgnoreCase: + return IndexOfOrdinalIgnoreCase(source, value, fromBeginning: true); } - internal int LastIndexOfOrdinal(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase) + /// + /// Searches for the first occurrence of a within a source string. + /// + /// The string to search within. + /// The to locate within . + /// The to use during the search. + /// + /// The zero-based index into where + /// first appears; or -1 if cannot be found within . + /// + /// + /// contains an unsupported combination of flags. + /// + public int IndexOf(ReadOnlySpan source, Rune value, CompareOptions options = CompareOptions.None) { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); - Debug.Assert(!value.IsEmpty); - return IndexOfOrdinalCore(source, value, ignoreCase, fromBeginning: false); + Span valueAsUtf16 = stackalloc char[Rune.MaxUtf16CharsPerRune]; + int charCount = value.EncodeToUtf16(valueAsUtf16); + return IndexOf(source, valueAsUtf16.Slice(0, charCount), options); } - internal unsafe int IndexOf(ReadOnlySpan source, ReadOnlySpan value, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); - Debug.Assert(!value.IsEmpty); - return IndexOfCore(source, value, options, null, fromBeginning: true); - } + private static int IndexOfOrdinalCore(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase, bool fromBeginning) => + GlobalizationMode.UseNls ? + NlsIndexOfOrdinalCore(source, value, ignoreCase, fromBeginning) : + IcuIndexOfOrdinalCore(source, value, ignoreCase, fromBeginning); - internal unsafe int LastIndexOf(ReadOnlySpan source, ReadOnlySpan value, CompareOptions options) + internal static int IndexOfOrdinalIgnoreCase(ReadOnlySpan source, ReadOnlySpan value, bool fromBeginning) { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); - Debug.Assert(!value.IsEmpty); - return IndexOfCore(source, value, options, null, fromBeginning: false); - } + if (value.IsEmpty) + { + // Empty target string trivially appears at all indexes of all search spaces. - /// - /// The following IndexOf overload is mainly used by String.Replace. This overload assumes the parameters are already validated - /// and the caller is passing a valid matchLengthPtr pointer. - /// - internal unsafe int IndexOf(string source, string value, int startIndex, int count, CompareOptions options, int* matchLengthPtr, bool fromBeginning = true) - { - Debug.Assert(source != null); - Debug.Assert(value != null); - Debug.Assert(startIndex >= 0); + return (fromBeginning) ? 0 : source.Length; + } - if (matchLengthPtr != null) + if (value.Length > source.Length) { - *matchLengthPtr = 0; + // A non-linguistic search compares chars directly against one another, so large + // target strings can never be found inside small search spaces. This check also + // handles empty 'source' spans. + + return -1; } - if (value.Length == 0) + if (GlobalizationMode.Invariant) { - return startIndex; + return InvariantIndexOf(source, value, ignoreCase: true, fromBeginning); } - - if (startIndex >= source.Length) + else { - return -1; + return IndexOfOrdinalCore(source, value, ignoreCase: true, fromBeginning); } + } + + /// + /// The following IndexOf overload is mainly used by String.Replace. This overload assumes the parameters are already validated + /// and the caller is passing a valid matchLengthPtr pointer. + /// + internal unsafe int IndexOf(ReadOnlySpan source, ReadOnlySpan value, int* matchLengthPtr, CompareOptions options, bool fromBeginning) + { + Debug.Assert(matchLengthPtr != null); + *matchLengthPtr = 0; - if (options == CompareOptions.OrdinalIgnoreCase) + if ((options & ValidIndexMaskOffFlags) == 0) { - int res; - if (fromBeginning) + // Common case: caller is attempting to perform a linguistic search. + // Pass the flags down to NLS or ICU unless we're running in invariant + // mode, at which point we normalize the flags to Orginal[IgnoreCase]. + + if (!GlobalizationMode.Invariant) { - res = IndexOfOrdinal(source, value, startIndex, count, ignoreCase: true); + if (value.IsEmpty) + { + // empty target substring trivially occurs at beginning / end of search space + return (fromBeginning) ? 0 : source.Length; + } + else + { + return IndexOfCore(source, value, options, matchLengthPtr, fromBeginning); + } } - else + else if ((options & CompareOptions.IgnoreCase) == 0) { - res = LastIndexOfOrdinal(source, value, startIndex, count, ignoreCase: true); + goto ReturnOrdinal; } - - if (res >= 0 && matchLengthPtr != null) + else { - *matchLengthPtr = value.Length; + goto ReturnOrdinalIgnoreCase; } - return res; } - - if (GlobalizationMode.Invariant) + else { - bool ignoreCase = (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0; - int res; + // Less common case: caller is attempting to perform non-linguistic comparison, + // or an invalid combination of flags was supplied. - if (fromBeginning) + if (options == CompareOptions.Ordinal) { - res = IndexOfOrdinal(source, value, startIndex, count, ignoreCase); + goto ReturnOrdinal; } - else + else if (options == CompareOptions.OrdinalIgnoreCase) { - res = LastIndexOfOrdinal(source, value, startIndex, count, ignoreCase); + goto ReturnOrdinalIgnoreCase; } - - if (res >= 0 && matchLengthPtr != null) + else { - *matchLengthPtr = value.Length; + ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidFlag, ExceptionArgument.options); } - return res; } - if (options == CompareOptions.Ordinal) - { - int retValue; + ReturnOrdinal: + int retVal = (fromBeginning) ? source.IndexOf(value) : source.LastIndexOf(value); + goto OrdinalReturn; - if (fromBeginning) - { - retValue = SpanHelpers.IndexOf( - ref Unsafe.Add(ref source.GetRawStringData(), startIndex), - count, - ref value.GetRawStringData(), - value.Length); - } - else - { - retValue = SpanHelpers.LastIndexOf( - ref Unsafe.Add(ref source.GetRawStringData(), startIndex), - count, - ref value.GetRawStringData(), - value.Length); - } + ReturnOrdinalIgnoreCase: + retVal = IndexOfOrdinalIgnoreCase(source, value, fromBeginning); + goto OrdinalReturn; - if (retValue >= 0) - { - retValue += startIndex; - if (matchLengthPtr != null) - { - *matchLengthPtr = value.Length; - } - } + OrdinalReturn: + // Both Ordinal and OrdinalIgnoreCase match by individual code points in a non-linguistic manner. + // Non-BMP code points will never match BMP code points, so given UTF-16 inputs the match length + // will always be equivalent to the target string length. - return retValue; - } - else + if (retVal >= 0) { - if (fromBeginning) - { - // Call the string-based overload, as it special-cases IsFastSort as a perf optimization. - return IndexOfCore(source, value, startIndex, count, options, matchLengthPtr); - } - else - { - return IndexOfCore(source.AsSpan(startIndex, count), value, options, matchLengthPtr, fromBeginning: false); - } + *matchLengthPtr = value.Length; } + return retVal; } + private unsafe int IndexOfCore(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) => + GlobalizationMode.UseNls ? + NlsIndexOfCore(source, target, options, matchLengthPtr, fromBeginning) : + IcuIndexOfCore(source, target, options, matchLengthPtr, fromBeginning); + internal static int IndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase) { Debug.Assert(source != null); @@ -1164,51 +1336,40 @@ ref value.GetRawStringData(), /// the specified value is not found. If value equals string.Empty, /// endIndex is returned. Throws IndexOutOfRange if startIndex or /// endIndex is less than zero or greater than the length of string. - /// Throws ArgumentException if value is null. + /// Throws ArgumentException if value (as a string) is null. /// public int LastIndexOf(string source, char value) { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - // Can't start at negative index, so make sure we check for the length == 0 case. - return LastIndexOf(source, value, source.Length - 1, source.Length, CompareOptions.None); + return LastIndexOf(source, value, CompareOptions.None); } public int LastIndexOf(string source, string value) { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - // Can't start at negative index, so make sure we check for the length == 0 case. - return LastIndexOf(source, value, source.Length - 1, - source.Length, CompareOptions.None); + return LastIndexOf(source, value, CompareOptions.None); } public int LastIndexOf(string source, char value, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - // Can't start at negative index, so make sure we check for the length == 0 case. - return LastIndexOf(source, value, source.Length - 1, source.Length, options); + return LastIndexOf(source, MemoryMarshal.CreateReadOnlySpan(ref value, 1), options); } public int LastIndexOf(string source, string value, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); + } + if (value == null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); } - // Can't start at negative index, so make sure we check for the length == 0 case. - return LastIndexOf(source, value, source.Length - 1, source.Length, options); + return LastIndexOf(source.AsSpan(), value.AsSpan(), options); } public int LastIndexOf(string source, char value, int startIndex) @@ -1245,122 +1406,208 @@ public int LastIndexOf(string source, char value, int startIndex, int count, Com { if (source == null) { - throw new ArgumentNullException(nameof(source)); - } - // Validate CompareOptions - // Ordinal can't be selected with other flags - if ((options & ValidIndexMaskOffFlags) != 0 && - (options != CompareOptions.Ordinal) && - (options != CompareOptions.OrdinalIgnoreCase)) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - // Special case for 0 length input strings - if (source.Length == 0 && (startIndex == -1 || startIndex == 0)) - { - return -1; - } + TryAgain: - // Make sure we're not out of range - if (startIndex < 0 || startIndex > source.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } + // Previous versions of the Framework special-cased empty 'source' to allow startIndex = -1 or startIndex = 0, + // ignoring 'count' and short-circuiting the entire operation. We'll silently fix up the 'count' parameter + // if this occurs. + // + // See the comments just before string.IndexOf(string) for more information on how these computations are + // performed. - // Make sure that we allow startIndex == source.Length - if (startIndex == source.Length) + if ((uint)startIndex >= (uint)source.Length) { - startIndex--; - if (count > 0) + if (startIndex == -1 && source.Length == 0) { - count--; + count = 0; // normalize } - } + else if (startIndex == source.Length) + { + // The caller likely had an off-by-one error when invoking the API. The Framework has historically + // allowed for this and tried to fix up the parameters, so we'll continue to do so for compat. - // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0. - if (count < 0 || startIndex - count + 1 < 0) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + startIndex--; + if (count > 0) + { + count--; + } + + goto TryAgain; // guaranteed never to loop more than once + } + else + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); + } } - if (options == CompareOptions.OrdinalIgnoreCase) + startIndex = startIndex - count + 1; // this will be the actual index where we begin our search + + if (!source.TryGetSpan(startIndex, count, out ReadOnlySpan sourceSpan)) { - return source.LastIndexOf(value.ToString(), startIndex, count, StringComparison.OrdinalIgnoreCase); + ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count(); } - if (GlobalizationMode.Invariant) + int retVal = LastIndexOf(sourceSpan, MemoryMarshal.CreateReadOnlySpan(ref value, 1), options); + if (retVal >= 0) { - return InvariantLastIndexOf(source, char.ToString(value), startIndex, count, (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0); + retVal += startIndex; } - - return LastIndexOfCore(source, value.ToString(), startIndex, count, options); + return retVal; } public int LastIndexOf(string source, string value, int startIndex, int count, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } if (value == null) { - throw new ArgumentNullException(nameof(value)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); } - // Validate CompareOptions - // Ordinal can't be selected with other flags - if ((options & ValidIndexMaskOffFlags) != 0 && - (options != CompareOptions.Ordinal) && - (options != CompareOptions.OrdinalIgnoreCase)) - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + TryAgain: - // Special case for 0 length input strings - if (source.Length == 0 && (startIndex == -1 || startIndex == 0)) + // Previous versions of the Framework special-cased empty 'source' to allow startIndex = -1 or startIndex = 0, + // ignoring 'count' and short-circuiting the entire operation. We'll silently fix up the 'count' parameter + // if this occurs. + // + // See the comments just before string.IndexOf(string) for more information on how these computations are + // performed. + + if ((uint)startIndex >= (uint)source.Length) { - return (value.Length == 0) ? 0 : -1; + if (startIndex == -1 && source.Length == 0) + { + count = 0; // normalize + } + else if (startIndex == source.Length) + { + // The caller likely had an off-by-one error when invoking the API. The Framework has historically + // allowed for this and tried to fix up the parameters, so we'll continue to do so for compat. + + startIndex--; + if (count > 0) + { + count--; + } + + goto TryAgain; // guaranteed never to loop more than once + } + else + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); + } } - // Make sure we're not out of range - if (startIndex < 0 || startIndex > source.Length) + startIndex = startIndex - count + 1; // this will be the actual index where we begin our search + + if (!source.TryGetSpan(startIndex, count, out ReadOnlySpan sourceSpan)) { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count(); } - // Make sure that we allow startIndex == source.Length - if (startIndex == source.Length) + int retVal = LastIndexOf(sourceSpan, value, options); + if (retVal >= 0) { - startIndex--; - if (count > 0) + retVal += startIndex; + } + return retVal; + } + + /// + /// Searches for the last occurrence of a substring within a source string. + /// + /// The string to search within. + /// The substring to locate within . + /// The to use during the search. + /// + /// The zero-based index into where the substring + /// last appears; or -1 if cannot be found within . + /// + /// + /// contains an unsupported combination of flags. + /// + public unsafe int LastIndexOf(ReadOnlySpan source, ReadOnlySpan value, CompareOptions options = CompareOptions.None) + { + if ((options & ValidIndexMaskOffFlags) == 0) + { + // Common case: caller is attempting to perform a linguistic search. + // Pass the flags down to NLS or ICU unless we're running in invariant + // mode, at which point we normalize the flags to Orginal[IgnoreCase]. + + if (!GlobalizationMode.Invariant) + { + if (value.IsEmpty) + { + return source.Length; // Empty target string trivially occurs at the last index of every search space. + } + else + { + return IndexOfCore(source, value, options, null /* matchLengthPtr */, fromBeginning: false); + } + } + else if ((options & CompareOptions.IgnoreCase) == 0) { - count--; + goto ReturnOrdinal; } - - // empty substrings trivially occur at the end of the search space - if (value.Length == 0 && count >= 0 && startIndex - count + 1 >= 0) + else { - return startIndex + 1; + goto ReturnOrdinalIgnoreCase; } } - - // 2nd half of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0. - if (count < 0 || startIndex - count + 1 < 0) + else { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - } + // Less common case: caller is attempting to perform non-linguistic comparison, + // or an invalid combination of flags was supplied. - if (options == CompareOptions.OrdinalIgnoreCase) - { - return LastIndexOfOrdinal(source, value, startIndex, count, ignoreCase: true); + if (options == CompareOptions.Ordinal) + { + goto ReturnOrdinal; + } + else if (options == CompareOptions.OrdinalIgnoreCase) + { + goto ReturnOrdinalIgnoreCase; + } + else + { + throw new ArgumentException( + paramName: nameof(options), + message: SR.Argument_InvalidFlag); + } } - if (GlobalizationMode.Invariant) - return InvariantLastIndexOf(source, value, startIndex, count, (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0); + ReturnOrdinal: + return source.LastIndexOf(value); - return LastIndexOfCore(source, value, startIndex, count, options); + ReturnOrdinalIgnoreCase: + return IndexOfOrdinalIgnoreCase(source, value, fromBeginning: false); } - private static int LastIndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase) + /// + /// Searches for the last occurrence of a within a source string. + /// + /// The string to search within. + /// The to locate within . + /// The to use during the search. + /// + /// The zero-based index into where + /// last appears; or -1 if cannot be found within . + /// + /// + /// contains an unsupported combination of flags. + /// + public unsafe int LastIndexOf(ReadOnlySpan source, Rune value, CompareOptions options = CompareOptions.None) + { + Span valueAsUtf16 = stackalloc char[Rune.MaxUtf16CharsPerRune]; + int charCount = value.EncodeToUtf16(valueAsUtf16); + return LastIndexOf(source, valueAsUtf16.Slice(0, charCount), options); + } + + internal static int LastIndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase) { Debug.Assert(!string.IsNullOrEmpty(source)); Debug.Assert(value != null); @@ -1385,7 +1632,9 @@ private static int LastIndexOfOrdinal(string source, string value, int startInde return -1; } - return LastIndexOfOrdinalCore(source, value, startIndex, count, ignoreCase); + return GlobalizationMode.UseNls ? + NlsLastIndexOfOrdinalCore(source, value, startIndex, count, ignoreCase) : + IcuLastIndexOfOrdinalCore(source, value, startIndex, count, ignoreCase); } /// @@ -1398,7 +1647,7 @@ public SortKey GetSortKey(string source, CompareOptions options) return InvariantCreateSortKey(source, options); } - return CreateSortKey(source, options); + return CreateSortKeyCore(source, options); } public SortKey GetSortKey(string source) @@ -1408,9 +1657,86 @@ public SortKey GetSortKey(string source) return InvariantCreateSortKey(source, CompareOptions.None); } - return CreateSortKey(source, CompareOptions.None); + return CreateSortKeyCore(source, CompareOptions.None); } + private SortKey CreateSortKeyCore(string source, CompareOptions options) => + GlobalizationMode.UseNls ? + NlsCreateSortKey(source, options) : + IcuCreateSortKey(source, options); + + /// + /// Computes a sort key over the specified input. + /// + /// The text over which to compute the sort key. + /// The buffer into which to write the resulting sort key bytes. + /// The used for computing the sort key. + /// The number of bytes written to . + /// + /// Use to query the required size of . + /// It is acceptable to provide a larger-than-necessary output buffer to this method. + /// + /// + /// is too small to contain the resulting sort key; + /// or contains an unsupported flag; + /// or cannot be processed using the desired + /// under the current . + /// + public int GetSortKey(ReadOnlySpan source, Span destination, CompareOptions options = CompareOptions.None) + { + if ((options & ValidCompareMaskOffFlags) != 0) + { + ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidFlag, ExceptionArgument.options); + } + + if (GlobalizationMode.Invariant) + { + return InvariantGetSortKey(source, destination, options); + } + else + { + return GetSortKeyCore(source, destination, options); + } + } + + private int GetSortKeyCore(ReadOnlySpan source, Span destination, CompareOptions options) => + GlobalizationMode.UseNls ? + NlsGetSortKey(source, destination, options) : + IcuGetSortKey(source, destination, options); + + /// + /// Returns the length (in bytes) of the sort key that would be produced from the specified input. + /// + /// The text over which to compute the sort key. + /// The used for computing the sort key. + /// The length (in bytes) of the sort key. + /// + /// contains an unsupported flag; + /// or cannot be processed using the desired + /// under the current . + /// + public int GetSortKeyLength(ReadOnlySpan source, CompareOptions options = CompareOptions.None) + { + if ((options & ValidCompareMaskOffFlags) != 0) + { + ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidFlag, ExceptionArgument.options); + } + + if (GlobalizationMode.Invariant) + { + return InvariantGetSortKeyLength(source, options); + } + else + { + return GetSortKeyLengthCore(source, options); + } + } + + private int GetSortKeyLengthCore(ReadOnlySpan source, CompareOptions options) => + GlobalizationMode.UseNls ? + NlsGetSortKeyLength(source, options) : + IcuGetSortKeyLength(source, options); + public override bool Equals(object? value) { return value is CompareInfo otherCompareInfo @@ -1432,64 +1758,64 @@ public int GetHashCode(string source, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - if ((options & ValidCompareMaskOffFlags) == 0) - { - // No unsupported flags are set - continue on with the regular logic - if (GlobalizationMode.Invariant) - { - return ((options & CompareOptions.IgnoreCase) != 0) ? source.GetHashCodeOrdinalIgnoreCase() : source.GetHashCode(); - } - return GetHashCodeOfStringCore(source, options); - } - else if (options == CompareOptions.Ordinal) - { - // We allow Ordinal in isolation - return source.GetHashCode(); - } - else if (options == CompareOptions.OrdinalIgnoreCase) - { - // We allow OrdinalIgnoreCase in isolation - return source.GetHashCodeOrdinalIgnoreCase(); - } - else - { - // Unsupported combination of flags specified - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } + return GetHashCode(source.AsSpan(), options); } public int GetHashCode(ReadOnlySpan source, CompareOptions options) { if ((options & ValidCompareMaskOffFlags) == 0) { - // No unsupported flags are set - continue on with the regular logic - if (GlobalizationMode.Invariant) + // Common case: caller is attempting to get a linguistic sort key. + // Pass the flags down to NLS or ICU unless we're running in invariant + // mode, at which point we normalize the flags to Orginal[IgnoreCase]. + + if (!GlobalizationMode.Invariant) { - return ((options & CompareOptions.IgnoreCase) != 0) ? string.GetHashCodeOrdinalIgnoreCase(source) : string.GetHashCode(source); + return GetHashCodeOfStringCore(source, options); + } + else if ((options & CompareOptions.IgnoreCase) == 0) + { + goto ReturnOrdinal; + } + else + { + goto ReturnOrdinalIgnoreCase; } - - return GetHashCodeOfStringCore(source, options); - } - else if (options == CompareOptions.Ordinal) - { - // We allow Ordinal in isolation - return string.GetHashCode(source); - } - else if (options == CompareOptions.OrdinalIgnoreCase) - { - // We allow OrdinalIgnoreCase in isolation - return string.GetHashCodeOrdinalIgnoreCase(source); } else { - // Unsupported combination of flags specified - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + // Less common case: caller is attempting to get a non-linguistic sort key, + // or an invalid combination of flags was supplied. + + if (options == CompareOptions.Ordinal) + { + goto ReturnOrdinal; + } + else if (options == CompareOptions.OrdinalIgnoreCase) + { + goto ReturnOrdinalIgnoreCase; + } + else + { + ThrowCompareOptionsCheckFailed(options); + } } + + ReturnOrdinal: + return string.GetHashCode(source); + + ReturnOrdinalIgnoreCase: + return string.GetHashCodeOrdinalIgnoreCase(source); } + private unsafe int GetHashCodeOfStringCore(ReadOnlySpan source, CompareOptions options) => + GlobalizationMode.UseNls ? + NlsGetHashCodeOfString(source, options) : + IcuGetHashCodeOfString(source, options); + public override string ToString() => "CompareInfo - " + Name; public SortVersion Version @@ -1508,7 +1834,7 @@ public SortVersion Version } else { - m_SortVersion = GetSortVersion(); + m_SortVersion = GlobalizationMode.UseNls ? NlsGetSortVersion() : IcuGetSortVersion(); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Icu.cs new file mode 100644 index 00000000000000..2936e25c84f58c --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Icu.cs @@ -0,0 +1,360 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace System.Globalization +{ + internal partial class CultureData + { + // ICU constants + private const int ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY = 100; // max size of keyword or value + private const int ICU_ULOC_FULLNAME_CAPACITY = 157; // max size of locale name + + internal static unsafe bool GetLocaleName(string localeName, out string? windowsName) + { + // Get the locale name from ICU + char* buffer = stackalloc char[ICU_ULOC_FULLNAME_CAPACITY]; + if (!Interop.Globalization.GetLocaleName(localeName, buffer, ICU_ULOC_FULLNAME_CAPACITY)) + { + windowsName = null; + return false; // fail + } + + // Success - use the locale name returned which may be different than realNameBuffer (casing) + windowsName = new string(buffer); // the name passed to subsequent ICU calls + return true; + } + + internal static unsafe bool GetDefaultLocaleName([NotNullWhen(true)] out string? windowsName) + { + // Get the default (system) locale name from ICU + char* buffer = stackalloc char[ICU_ULOC_FULLNAME_CAPACITY]; + if (!Interop.Globalization.GetDefaultLocaleName(buffer, ICU_ULOC_FULLNAME_CAPACITY)) + { + windowsName = null; + return false; // fail + } + + // Success - use the locale name returned which may be different than realNameBuffer (casing) + windowsName = new string(buffer); // the name passed to subsequent ICU calls + return true; + } + + private string IcuGetLocaleInfo(LocaleStringData type) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + Debug.Assert(_sWindowsName != null, "[CultureData.IcuGetLocaleInfo] Expected _sWindowsName to be populated already"); + return IcuGetLocaleInfo(_sWindowsName, type); + } + + // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the + // "windows" name, which can be specific for downlevel (< windows 7) os's. + private unsafe string IcuGetLocaleInfo(string localeName, LocaleStringData type) + { + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert(localeName != null, "[CultureData.IcuGetLocaleInfo] Expected localeName to be not be null"); + + switch (type) + { + case LocaleStringData.NegativeInfinitySymbol: + // not an equivalent in ICU; prefix the PositiveInfinitySymbol with NegativeSign + return IcuGetLocaleInfo(localeName, LocaleStringData.NegativeSign) + + IcuGetLocaleInfo(localeName, LocaleStringData.PositiveInfinitySymbol); + } + + char* buffer = stackalloc char[ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY]; + bool result = Interop.Globalization.GetLocaleInfoString(localeName, (uint)type, buffer, ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY); + if (!result) + { + // Failed, just use empty string + Debug.Fail("[CultureData.IcuGetLocaleInfo(LocaleStringData)] Failed"); + return string.Empty; + } + + return new string(buffer); + } + + private int IcuGetLocaleInfo(LocaleNumberData type) + { + Debug.Assert(!GlobalizationMode.UseNls); + + Debug.Assert(_sWindowsName != null, "[CultureData.IcuGetLocaleInfo(LocaleNumberData)] Expected _sWindowsName to be populated already"); + + switch (type) + { + case LocaleNumberData.CalendarType: + // returning 0 will cause the first supported calendar to be returned, which is the preferred calendar + return 0; + } + + + int value = 0; + bool result = Interop.Globalization.GetLocaleInfoInt(_sWindowsName, (uint)type, ref value); + if (!result) + { + // Failed, just use 0 + Debug.Fail("[CultureData.IcuGetLocaleInfo(LocaleNumberData)] failed"); + } + + return value; + } + + private int[] IcuGetLocaleInfo(LocaleGroupingData type) + { + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert(_sWindowsName != null, "[CultureData.IcuGetLocaleInfo(LocaleGroupingData)] Expected _sWindowsName to be populated already"); + + int primaryGroupingSize = 0; + int secondaryGroupingSize = 0; + bool result = Interop.Globalization.GetLocaleInfoGroupingSizes(_sWindowsName, (uint)type, ref primaryGroupingSize, ref secondaryGroupingSize); + if (!result) + { + Debug.Fail("[CultureData.IcuGetLocaleInfo(LocaleGroupingData type)] failed"); + } + + if (secondaryGroupingSize == 0) + { + return new int[] { primaryGroupingSize }; + } + + return new int[] { primaryGroupingSize, secondaryGroupingSize }; + } + + private string IcuGetTimeFormatString() => IcuGetTimeFormatString(shortFormat: false); + + private unsafe string IcuGetTimeFormatString(bool shortFormat) + { + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert(_sWindowsName != null, "[CultureData.GetTimeFormatString(bool shortFormat)] Expected _sWindowsName to be populated already"); + + char* buffer = stackalloc char[ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY]; + + bool result = Interop.Globalization.GetLocaleTimeFormat(_sWindowsName, shortFormat, buffer, ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY); + if (!result) + { + // Failed, just use empty string + Debug.Fail("[CultureData.GetTimeFormatString(bool shortFormat)] Failed"); + return string.Empty; + } + + var span = new ReadOnlySpan(buffer, ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY); + return ConvertIcuTimeFormatString(span.Slice(0, span.IndexOf('\0'))); + } + + private int IcuGetFirstDayOfWeek() => IcuGetLocaleInfo(LocaleNumberData.FirstDayOfWeek); + + private string[] IcuGetTimeFormats() + { + string format = IcuGetTimeFormatString(false); + return new string[] { format }; + } + + private string[] IcuGetShortTimeFormats() + { + string format = IcuGetTimeFormatString(true); + return new string[] { format }; + } + + private static CultureData? IcuGetCultureDataFromRegionName(string? regionName) + { + // no support to lookup by region name, other than the hard-coded list in CultureData + return null; + } + + private static string IcuGetLanguageDisplayName(string cultureName) + { + return new CultureInfo(cultureName)._cultureData.IcuGetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName); + } + + private static string? IcuGetRegionDisplayName() + { + // use the fallback which is to return NativeName + return null; + } + + private static string ConvertIcuTimeFormatString(ReadOnlySpan icuFormatString) + { + Debug.Assert(icuFormatString.Length < ICU_ULOC_FULLNAME_CAPACITY); + Span result = stackalloc char[ICU_ULOC_FULLNAME_CAPACITY]; + + bool amPmAdded = false; + int resultPos = 0; + + for (int i = 0; i < icuFormatString.Length; i++) + { + switch (icuFormatString[i]) + { + case '\'': + result[resultPos++] = icuFormatString[i++]; + while (i < icuFormatString.Length) + { + char current = icuFormatString[i]; + result[resultPos++] = current; + if (current == '\'') + { + break; + } + i++; + } + break; + + case ':': + case '.': + case 'H': + case 'h': + case 'm': + case 's': + result[resultPos++] = icuFormatString[i]; + break; + + case ' ': + case '\u00A0': + // Convert nonbreaking spaces into regular spaces + result[resultPos++] = ' '; + break; + + case 'a': // AM/PM + if (!amPmAdded) + { + amPmAdded = true; + result[resultPos++] = 't'; + result[resultPos++] = 't'; + } + break; + + } + } + + return result.Slice(0, resultPos).ToString(); + } + + private static string? IcuLCIDToLocaleName(int culture) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + return IcuLocaleData.LCIDToLocaleName(culture); + } + + private static int IcuLocaleNameToLCID(string cultureName) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + int lcid = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.Lcid); + return lcid == -1 ? CultureInfo.LOCALE_CUSTOM_UNSPECIFIED : lcid; + } + + private static int IcuGetAnsiCodePage(string cultureName) + { + Debug.Assert(!GlobalizationMode.UseNls); + int ansiCodePage = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.AnsiCodePage); + return ansiCodePage == -1 ? CultureData.Invariant.ANSICodePage : ansiCodePage; + } + + private static int IcuGetOemCodePage(string cultureName) + { + Debug.Assert(!GlobalizationMode.UseNls); + int oemCodePage = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.OemCodePage); + return oemCodePage == -1 ? CultureData.Invariant.OEMCodePage : oemCodePage; + } + + private static int IcuGetMacCodePage(string cultureName) + { + Debug.Assert(!GlobalizationMode.UseNls); + int macCodePage = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.MacCodePage); + return macCodePage == -1 ? CultureData.Invariant.MacCodePage : macCodePage; + } + + private static int IcuGetEbcdicCodePage(string cultureName) + { + Debug.Assert(!GlobalizationMode.UseNls); + int ebcdicCodePage = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.EbcdicCodePage); + return ebcdicCodePage == -1 ? CultureData.Invariant.EBCDICCodePage : ebcdicCodePage; + } + + private static int IcuGetGeoId(string cultureName) + { + Debug.Assert(!GlobalizationMode.UseNls); + int geoId = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.GeoId); + return geoId == -1 ? CultureData.Invariant.GeoId : geoId; + } + + private static int IcuGetDigitSubstitution(string cultureName) + { + Debug.Assert(!GlobalizationMode.UseNls); + int digitSubstitution = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.DigitSubstitution); + return digitSubstitution == -1 ? (int) DigitShapes.None : digitSubstitution; + } + + private static string IcuGetThreeLetterWindowsLanguageName(string cultureName) + { + Debug.Assert(!GlobalizationMode.UseNls); + return IcuLocaleData.GetThreeLetterWindowsLanguageName(cultureName) ?? "ZZZ" /* default lang name */; + } + + private static CultureInfo[] IcuEnumCultures(CultureTypes types) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + if ((types & (CultureTypes.NeutralCultures | CultureTypes.SpecificCultures)) == 0) + { + return Array.Empty(); + } + + int bufferLength = Interop.Globalization.GetLocales(null, 0); + if (bufferLength <= 0) + { + return Array.Empty(); + } + + char [] chars = new char[bufferLength]; + + bufferLength = Interop.Globalization.GetLocales(chars, bufferLength); + if (bufferLength <= 0) + { + return Array.Empty(); + } + + bool enumNeutrals = (types & CultureTypes.NeutralCultures) != 0; + bool enumSpecificss = (types & CultureTypes.SpecificCultures) != 0; + + List list = new List(); + if (enumNeutrals) + { + list.Add(CultureInfo.InvariantCulture); + } + + int index = 0; + while (index < bufferLength) + { + int length = (int) chars[index++]; + if (index + length <= bufferLength) + { + CultureInfo ci = CultureInfo.GetCultureInfo(new string(chars, index, length)); + if ((enumNeutrals && ci.IsNeutralCulture) || (enumSpecificss && !ci.IsNeutralCulture)) + { + list.Add(ci); + } + } + + index += length; + } + + return list.ToArray(); + } + + private static string IcuGetConsoleFallbackName(string cultureName) + { + Debug.Assert(!GlobalizationMode.UseNls); + return IcuLocaleData.GetConsoleUICulture(cultureName); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Nls.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Nls.cs new file mode 100644 index 00000000000000..e8d4d05c974b95 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Nls.cs @@ -0,0 +1,607 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Text; +using Internal.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace System.Globalization +{ + internal partial class CultureData + { + // Wrappers around the GetLocaleInfoEx APIs which handle marshalling the returned + // data as either and Int or string. + internal static unsafe string? GetLocaleInfoEx(string localeName, uint field) + { + // REVIEW: Determine the maximum size for the buffer + const int BUFFER_SIZE = 530; + + char* pBuffer = stackalloc char[BUFFER_SIZE]; + int resultCode = GetLocaleInfoEx(localeName, field, pBuffer, BUFFER_SIZE); + if (resultCode > 0) + { + return new string(pBuffer); + } + + return null; + } + + internal static unsafe int GetLocaleInfoExInt(string localeName, uint field) + { + field |= Interop.Kernel32.LOCALE_RETURN_NUMBER; + int value = 0; + GetLocaleInfoEx(localeName, field, (char*)&value, sizeof(int)); + return value; + } + + internal static unsafe int GetLocaleInfoEx(string lpLocaleName, uint lcType, char* lpLCData, int cchData) + { + Debug.Assert(!GlobalizationMode.Invariant); + + return Interop.Kernel32.GetLocaleInfoEx(lpLocaleName, lcType, lpLCData, cchData); + } + + private string NlsGetLocaleInfo(LocaleStringData type) + { + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfo] Expected _sWindowsName to be populated by already"); + return NlsGetLocaleInfo(_sWindowsName, type); + } + + // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the + // "windows" name, which can be specific for downlevel (< windows 7) os's. + private string NlsGetLocaleInfo(string localeName, LocaleStringData type) + { + Debug.Assert(GlobalizationMode.UseNls); + uint lctype = (uint)type; + + return GetLocaleInfoFromLCType(localeName, lctype, UseUserOverride); + } + + private int NlsGetLocaleInfo(LocaleNumberData type) + { + Debug.Assert(GlobalizationMode.UseNls); + uint lctype = (uint)type; + + // Fix lctype if we don't want overrides + if (!UseUserOverride) + { + lctype |= Interop.Kernel32.LOCALE_NOUSEROVERRIDE; + } + + // Ask OS for data, note that we presume it returns success, so we have to know that + // sWindowsName is valid before calling. + Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); + return GetLocaleInfoExInt(_sWindowsName, lctype); + } + + private int[] NlsGetLocaleInfo(LocaleGroupingData type) + { + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); + return ConvertWin32GroupString(GetLocaleInfoFromLCType(_sWindowsName, (uint)type, UseUserOverride)); + } + + private string? NlsGetTimeFormatString() + { + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); + return ReescapeWin32String(GetLocaleInfoFromLCType(_sWindowsName, Interop.Kernel32.LOCALE_STIMEFORMAT, UseUserOverride)); + } + + private int NlsGetFirstDayOfWeek() + { + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); + + int result = GetLocaleInfoExInt(_sWindowsName, Interop.Kernel32.LOCALE_IFIRSTDAYOFWEEK | (!UseUserOverride ? Interop.Kernel32.LOCALE_NOUSEROVERRIDE : 0)); + + // Win32 and .NET disagree on the numbering for days of the week, so we have to convert. + return ConvertFirstDayOfWeekMonToSun(result); + } + + private string[]? NlsGetTimeFormats() + { + // Note that this gets overrides for us all the time + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(_sWindowsName != null, "[CultureData.DoEnumTimeFormats] Expected _sWindowsName to be populated by already"); + string[]? result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, 0, UseUserOverride)); + + return result; + } + + private string[]? NlsGetShortTimeFormats() + { + // Note that this gets overrides for us all the time + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(_sWindowsName != null, "[CultureData.DoEnumShortTimeFormats] Expected _sWindowsName to be populated by already"); + string[]? result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, Interop.Kernel32.TIME_NOSECONDS, UseUserOverride)); + + return result; + } + + // Enumerate all system cultures and then try to find out which culture has + // region name match the requested region name + private static CultureData? NlsGetCultureDataFromRegionName(string regionName) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(regionName != null); + + EnumLocaleData context; + context.cultureName = null; + context.regionName = regionName; + + unsafe + { + Interop.Kernel32.EnumSystemLocalesEx(EnumSystemLocalesProc, Interop.Kernel32.LOCALE_SPECIFICDATA | Interop.Kernel32.LOCALE_SUPPLEMENTAL, Unsafe.AsPointer(ref context), IntPtr.Zero); + } + + if (context.cultureName != null) + { + // we got a matched culture + return GetCultureData(context.cultureName, true); + } + + return null; + } + + private string NlsGetLanguageDisplayName(string cultureName) + { + Debug.Assert(GlobalizationMode.UseNls); + + // Usually the UI culture shouldn't be different than what we got from WinRT except + // if DefaultThreadCurrentUICulture was set + CultureInfo? ci; + + if (CultureInfo.DefaultThreadCurrentUICulture != null && + ((ci = CultureInfo.GetUserDefaultCulture()) != null) && + !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name)) + { + return NativeName; + } + else + { + return NlsGetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName); + } + } + + private string NlsGetRegionDisplayName() + { + Debug.Assert(GlobalizationMode.UseNls); + + // If the current UI culture matching the OS UI language, we'll get the display name from the OS. + // otherwise, we use the native name as we don't carry resources for the region display names anyway. + if (CultureInfo.CurrentUICulture.Name.Equals(CultureInfo.UserDefaultUICulture.Name)) + { + return NlsGetLocaleInfo(LocaleStringData.LocalizedCountryName); + } + + return NativeCountryName; + } + + // PAL methods end here. + + private static string GetLocaleInfoFromLCType(string localeName, uint lctype, bool useUserOveride) + { + Debug.Assert(localeName != null, "[CultureData.GetLocaleInfoFromLCType] Expected localeName to be not be null"); + + // Fix lctype if we don't want overrides + if (!useUserOveride) + { + lctype |= Interop.Kernel32.LOCALE_NOUSEROVERRIDE; + } + + // Ask OS for data + // Failed? Just use empty string + return GetLocaleInfoEx(localeName, lctype) ?? string.Empty; + } + + /// + /// Reescape a Win32 style quote string as a NLS+ style quoted string + /// + /// This is also the escaping style used by custom culture data files + /// + /// NLS+ uses \ to escape the next character, whether in a quoted string or + /// not, so we always have to change \ to \\. + /// + /// NLS+ uses \' to escape a quote inside a quoted string so we have to change + /// '' to \' (if inside a quoted string) + /// + /// We don't build the stringbuilder unless we find something to change + /// + [return: NotNullIfNotNull("str")] + internal static string? ReescapeWin32String(string? str) + { + // If we don't have data, then don't try anything + if (str == null) + { + return null; + } + + StringBuilder? result = null; + + bool inQuote = false; + for (int i = 0; i < str.Length; i++) + { + // Look for quote + if (str[i] == '\'') + { + // Already in quote? + if (inQuote) + { + // See another single quote. Is this '' of 'fred''s' or '''', or is it an ending quote? + if (i + 1 < str.Length && str[i + 1] == '\'') + { + // Found another ', so we have ''. Need to add \' instead. + // 1st make sure we have our stringbuilder + result ??= new StringBuilder(str, 0, i, str.Length * 2); + + // Append a \' and keep going (so we don't turn off quote mode) + result.Append("\\'"); + i++; + continue; + } + + // Turning off quote mode, fall through to add it + inQuote = false; + } + else + { + // Found beginning quote, fall through to add it + inQuote = true; + } + } + // Is there a single \ character? + else if (str[i] == '\\') + { + // Found a \, need to change it to \\ + // 1st make sure we have our stringbuilder + result ??= new StringBuilder(str, 0, i, str.Length * 2); + + // Append our \\ to the string & continue + result.Append("\\\\"); + continue; + } + + // If we have a builder we need to add our character + result?.Append(str[i]); + } + + // Unchanged string? , just return input string + if (result == null) + return str; + + // String changed, need to use the builder + return result.ToString(); + } + + [return: NotNullIfNotNull("array")] + internal static string[]? ReescapeWin32Strings(string[]? array) + { + if (array != null) + { + for (int i = 0; i < array.Length; i++) + { + array[i] = ReescapeWin32String(array[i]); + } + } + + return array; + } + + // If we get a group from windows, then its in 3;0 format with the 0 backwards + // of how NLS+ uses it (ie: if the string has a 0, then the int[] shouldn't and vice versa) + // EXCEPT in the case where the list only contains 0 in which NLS and NLS+ have the same meaning. + private static int[] ConvertWin32GroupString(string win32Str) + { + // None of these cases make any sense + if (string.IsNullOrEmpty(win32Str)) + { + return new int[] { 3 }; + } + + if (win32Str[0] == '0') + { + return new int[] { 0 }; + } + + // Since its in n;n;n;n;n format, we can always get the length quickly + int[] values; + if (win32Str[^1] == '0') + { + // Trailing 0 gets dropped. 1;0 -> 1 + values = new int[win32Str.Length / 2]; + } + else + { + // Need extra space for trailing zero 1 -> 1;0 + values = new int[(win32Str.Length / 2) + 2]; + values[^1] = 0; + } + + int i; + int j; + for (i = 0, j = 0; i < win32Str.Length && j < values.Length; i += 2, j++) + { + // Note that this # shouldn't ever be zero, 'cause 0 is only at end + // But we'll test because its registry that could be anything + if (win32Str[i] < '1' || win32Str[i] > '9') + return new int[] { 3 }; + + values[j] = (int)(win32Str[i] - '0'); + } + + return values; + } + + private static int ConvertFirstDayOfWeekMonToSun(int iTemp) + { + // Convert Mon-Sun to Sun-Sat format + iTemp++; + if (iTemp > 6) + { + // Wrap Sunday and convert invalid data to Sunday + iTemp = 0; + } + return iTemp; + } + + // Context for EnumCalendarInfoExEx callback. + private struct EnumLocaleData + { + public string regionName; + public string? cultureName; + } + + // EnumSystemLocaleEx callback. + // [UnmanagedCallersOnly(CallingConvention = CallingConvention.StdCall)] + private static unsafe Interop.BOOL EnumSystemLocalesProc(char* lpLocaleString, uint flags, void* contextHandle) + { + ref EnumLocaleData context = ref Unsafe.As(ref *(byte*)contextHandle); + try + { + string cultureName = new string(lpLocaleString); + string? regionName = GetLocaleInfoEx(cultureName, Interop.Kernel32.LOCALE_SISO3166CTRYNAME); + if (regionName != null && regionName.Equals(context.regionName, StringComparison.OrdinalIgnoreCase)) + { + context.cultureName = cultureName; + return Interop.BOOL.FALSE; // we found a match, then stop the enumeration + } + + return Interop.BOOL.TRUE; + } + catch (Exception) + { + return Interop.BOOL.FALSE; + } + } + + // EnumSystemLocaleEx callback. + // [UnmanagedCallersOnly(CallingConvention = CallingConvention.StdCall)] + private static unsafe Interop.BOOL EnumAllSystemLocalesProc(char* lpLocaleString, uint flags, void* contextHandle) + { + ref EnumData context = ref Unsafe.As(ref *(byte*)contextHandle); + try + { + context.strings.Add(new string(lpLocaleString)); + return Interop.BOOL.TRUE; + } + catch (Exception) + { + return Interop.BOOL.FALSE; + } + } + + // Context for EnumTimeFormatsEx callback. + private struct EnumData + { + public List strings; + } + + // EnumTimeFormatsEx callback itself. + // [UnmanagedCallersOnly(CallingConvention = CallingConvention.StdCall)] + private static unsafe Interop.BOOL EnumTimeCallback(char* lpTimeFormatString, void* lParam) + { + ref EnumData context = ref Unsafe.As(ref *(byte*)lParam); + try + { + context.strings.Add(new string(lpTimeFormatString)); + return Interop.BOOL.TRUE; + } + catch (Exception) + { + return Interop.BOOL.FALSE; + } + } + + private static unsafe string[]? nativeEnumTimeFormats(string localeName, uint dwFlags, bool useUserOverride) + { + EnumData data = default; + data.strings = new List(); + + // Now call the enumeration API. Work is done by our callback function + Interop.Kernel32.EnumTimeFormatsEx(EnumTimeCallback, localeName, (uint)dwFlags, Unsafe.AsPointer(ref data)); + + if (data.strings.Count > 0) + { + // Now we need to allocate our stringarray and populate it + string[] results = data.strings.ToArray(); + + if (!useUserOverride && data.strings.Count > 1) + { + // Since there is no "NoUserOverride" aware EnumTimeFormatsEx, we always get an override + // The override is the first entry if it is overriden. + // We can check if we have overrides by checking the GetLocaleInfo with no override + // If we do have an override, we don't know if it is a user defined override or if the + // user has just selected one of the predefined formats so we can't just remove it + // but we can move it down. + uint lcType = (dwFlags == Interop.Kernel32.TIME_NOSECONDS) ? Interop.Kernel32.LOCALE_SSHORTTIME : Interop.Kernel32.LOCALE_STIMEFORMAT; + string timeFormatNoUserOverride = GetLocaleInfoFromLCType(localeName, lcType, useUserOverride); + if (timeFormatNoUserOverride != "") + { + string firstTimeFormat = results[0]; + if (timeFormatNoUserOverride != firstTimeFormat) + { + results[0] = results[1]; + results[1] = firstTimeFormat; + } + } + } + + return results; + } + + return null; + } + + private static int NlsLocaleNameToLCID(string cultureName) + { + Debug.Assert(!GlobalizationMode.Invariant); + + return Interop.Kernel32.LocaleNameToLCID(cultureName, Interop.Kernel32.LOCALE_ALLOW_NEUTRAL_NAMES); + } + + private static unsafe string? NlsLCIDToLocaleName(int culture) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + + char* pBuffer = stackalloc char[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH + 1]; // +1 for the null termination + int length = Interop.Kernel32.LCIDToLocaleName(culture, pBuffer, Interop.Kernel32.LOCALE_NAME_MAX_LENGTH + 1, Interop.Kernel32.LOCALE_ALLOW_NEUTRAL_NAMES); + + if (length > 0) + { + return new string(pBuffer); + } + + return null; + } + + private int NlsGetAnsiCodePage(string cultureName) + { + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(LocaleNumberData.AnsiCodePage); + } + + private int NlsGetOemCodePage(string cultureName) + { + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(LocaleNumberData.OemCodePage); + } + + private int NlsGetMacCodePage(string cultureName) + { + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(LocaleNumberData.MacCodePage); + } + + private int NlsGetEbcdicCodePage(string cultureName) + { + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(LocaleNumberData.EbcdicCodePage); + } + + private int NlsGetGeoId(string cultureName) + { + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(LocaleNumberData.GeoId); + } + + private int NlsGetDigitSubstitution(string cultureName) + { + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(LocaleNumberData.DigitSubstitution); + } + + private string NlsGetThreeLetterWindowsLanguageName(string cultureName) + { + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(cultureName, LocaleStringData.AbbreviatedWindowsLanguageName); + } + + private static CultureInfo[] NlsEnumCultures(CultureTypes types) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + + uint flags = 0; + +#pragma warning disable 618 + if ((types & (CultureTypes.FrameworkCultures | CultureTypes.InstalledWin32Cultures | CultureTypes.ReplacementCultures)) != 0) + { + flags |= Interop.Kernel32.LOCALE_NEUTRALDATA | Interop.Kernel32.LOCALE_SPECIFICDATA; + } +#pragma warning restore 618 + + if ((types & CultureTypes.NeutralCultures) != 0) + { + flags |= Interop.Kernel32.LOCALE_NEUTRALDATA; + } + + if ((types & CultureTypes.SpecificCultures) != 0) + { + flags |= Interop.Kernel32.LOCALE_SPECIFICDATA; + } + + if ((types & CultureTypes.UserCustomCulture) != 0) + { + flags |= Interop.Kernel32.LOCALE_SUPPLEMENTAL; + } + + if ((types & CultureTypes.ReplacementCultures) != 0) + { + flags |= Interop.Kernel32.LOCALE_SUPPLEMENTAL; + } + + EnumData context = default; + context.strings = new List(); + + unsafe + { + Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, flags, Unsafe.AsPointer(ref context), IntPtr.Zero); + } + + CultureInfo[] cultures = new CultureInfo[context.strings.Count]; + for (int i = 0; i < cultures.Length; i++) + { + cultures[i] = new CultureInfo(context.strings[i]); + } + + return cultures; + } + + private string NlsGetConsoleFallbackName(string cultureName) + { + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(cultureName, LocaleStringData.ConsoleFallbackName); + } + + internal bool NlsIsReplacementCulture + { + get + { + Debug.Assert(GlobalizationMode.UseNls); + EnumData context = default; + context.strings = new List(); + + unsafe + { + Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, Interop.Kernel32.LOCALE_REPLACEMENT, Unsafe.AsPointer(ref context), IntPtr.Zero); + } + + for (int i = 0; i < context.strings.Count; i++) + { + if (string.Equals(context.strings[i], _sWindowsName, StringComparison.OrdinalIgnoreCase)) + return true; + } + + return false; + } + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Unix.cs index 67ad489e47adf2..99b07c463cb3e2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Unix.cs @@ -2,26 +2,21 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; using System.Diagnostics; namespace System.Globalization { internal partial class CultureData { - // ICU constants - private const int ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY = 100; // max size of keyword or value - private const int ICU_ULOC_FULLNAME_CAPACITY = 157; // max size of locale name private const string ICU_COLLATION_KEYWORD = "@collation="; /// /// This method uses the sRealName field (which is initialized by the constructor before this is called) to /// initialize the rest of the state of CultureData based on the underlying OS globalization library. /// - private unsafe bool InitCultureData() + private bool InitCultureDataCore() { Debug.Assert(_sRealName != null); - Debug.Assert(!GlobalizationMode.Invariant); string realNameBuffer = _sRealName; @@ -73,7 +68,7 @@ private unsafe bool InitCultureData() _bNeutral = TwoLetterISOCountryName.Length == 0; - _sSpecificCulture = _bNeutral ? LocaleData.GetSpecificCultureName(_sRealName) : _sRealName; + _sSpecificCulture = _bNeutral ? IcuLocaleData.GetSpecificCultureName(_sRealName) : _sRealName; // Remove the sort from sName unless custom culture if (index > 0 && !_bNeutral && !IsCustomCultureId(_iLanguage)) @@ -83,338 +78,8 @@ private unsafe bool InitCultureData() return true; } - internal static unsafe bool GetLocaleName(string localeName, out string? windowsName) - { - // Get the locale name from ICU - char* buffer = stackalloc char[ICU_ULOC_FULLNAME_CAPACITY]; - if (!Interop.Globalization.GetLocaleName(localeName, buffer, ICU_ULOC_FULLNAME_CAPACITY)) - { - windowsName = null; - return false; // fail - } - - // Success - use the locale name returned which may be different than realNameBuffer (casing) - windowsName = new string(buffer); // the name passed to subsequent ICU calls - return true; - } - - internal static unsafe bool GetDefaultLocaleName(out string? windowsName) - { - // Get the default (system) locale name from ICU - char* buffer = stackalloc char[ICU_ULOC_FULLNAME_CAPACITY]; - if (!Interop.Globalization.GetDefaultLocaleName(buffer, ICU_ULOC_FULLNAME_CAPACITY)) - { - windowsName = null; - return false; // fail - } - - // Success - use the locale name returned which may be different than realNameBuffer (casing) - windowsName = new string(buffer); // the name passed to subsequent ICU calls - return true; - } - - private string GetLocaleInfo(LocaleStringData type) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo] Expected _sWindowsName to be populated already"); - return GetLocaleInfo(_sWindowsName, type); - } - - // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the - // "windows" name, which can be specific for downlevel (< windows 7) os's. - private unsafe string GetLocaleInfo(string localeName, LocaleStringData type) - { - Debug.Assert(localeName != null, "[CultureData.GetLocaleInfo] Expected localeName to be not be null"); - - switch (type) - { - case LocaleStringData.NegativeInfinitySymbol: - // not an equivalent in ICU; prefix the PositiveInfinitySymbol with NegativeSign - return GetLocaleInfo(localeName, LocaleStringData.NegativeSign) + - GetLocaleInfo(localeName, LocaleStringData.PositiveInfinitySymbol); - } - - char* buffer = stackalloc char[ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY]; - bool result = Interop.Globalization.GetLocaleInfoString(localeName, (uint)type, buffer, ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY); - if (!result) - { - // Failed, just use empty string - Debug.Fail("[CultureData.GetLocaleInfo(LocaleStringData)] Failed"); - return string.Empty; - } - - return new string(buffer); - } - - private int GetLocaleInfo(LocaleNumberData type) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo(LocaleNumberData)] Expected _sWindowsName to be populated already"); - - switch (type) - { - case LocaleNumberData.CalendarType: - // returning 0 will cause the first supported calendar to be returned, which is the preferred calendar - return 0; - } - - - int value = 0; - bool result = Interop.Globalization.GetLocaleInfoInt(_sWindowsName, (uint)type, ref value); - if (!result) - { - // Failed, just use 0 - Debug.Fail("[CultureData.GetLocaleInfo(LocaleNumberData)] failed"); - } - - return value; - } - - private int[] GetLocaleInfo(LocaleGroupingData type) - { - Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo(LocaleGroupingData)] Expected _sWindowsName to be populated already"); - - int primaryGroupingSize = 0; - int secondaryGroupingSize = 0; - bool result = Interop.Globalization.GetLocaleInfoGroupingSizes(_sWindowsName, (uint)type, ref primaryGroupingSize, ref secondaryGroupingSize); - if (!result) - { - Debug.Fail("[CultureData.GetLocaleInfo(LocaleGroupingData type)] failed"); - } - - if (secondaryGroupingSize == 0) - { - return new int[] { primaryGroupingSize }; - } - - return new int[] { primaryGroupingSize, secondaryGroupingSize }; - } - - private string GetTimeFormatString() => GetTimeFormatString(shortFormat: false); - - private unsafe string GetTimeFormatString(bool shortFormat) - { - Debug.Assert(_sWindowsName != null, "[CultureData.GetTimeFormatString(bool shortFormat)] Expected _sWindowsName to be populated already"); - - char* buffer = stackalloc char[ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY]; - - bool result = Interop.Globalization.GetLocaleTimeFormat(_sWindowsName, shortFormat, buffer, ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY); - if (!result) - { - // Failed, just use empty string - Debug.Fail("[CultureData.GetTimeFormatString(bool shortFormat)] Failed"); - return string.Empty; - } - - var span = new ReadOnlySpan(buffer, ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY); - return ConvertIcuTimeFormatString(span.Slice(0, span.IndexOf('\0'))); - } - - private int GetFirstDayOfWeek() => GetLocaleInfo(LocaleNumberData.FirstDayOfWeek); - - private string[] GetTimeFormats() - { - string format = GetTimeFormatString(false); - return new string[] { format }; - } - - private string[] GetShortTimeFormats() - { - string format = GetTimeFormatString(true); - return new string[] { format }; - } - - private static CultureData? GetCultureDataFromRegionName(string? regionName) - { - // no support to lookup by region name, other than the hard-coded list in CultureData - return null; - } - - private static string GetLanguageDisplayName(string cultureName) - { - return new CultureInfo(cultureName)._cultureData.GetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName); - } - - private static string? GetRegionDisplayName() - { - // use the fallback which is to return NativeName - return null; - } - - private static string ConvertIcuTimeFormatString(ReadOnlySpan icuFormatString) - { - Debug.Assert(icuFormatString.Length < ICU_ULOC_FULLNAME_CAPACITY); - Span result = stackalloc char[ICU_ULOC_FULLNAME_CAPACITY]; - - bool amPmAdded = false; - int resultPos = 0; - - for (int i = 0; i < icuFormatString.Length; i++) - { - switch (icuFormatString[i]) - { - case '\'': - result[resultPos++] = icuFormatString[i++]; - while (i < icuFormatString.Length) - { - char current = icuFormatString[i]; - result[resultPos++] = current; - if (current == '\'') - { - break; - } - i++; - } - break; - - case ':': - case '.': - case 'H': - case 'h': - case 'm': - case 's': - result[resultPos++] = icuFormatString[i]; - break; - - case ' ': - case '\u00A0': - // Convert nonbreaking spaces into regular spaces - result[resultPos++] = ' '; - break; - - case 'a': // AM/PM - if (!amPmAdded) - { - amPmAdded = true; - result[resultPos++] = 't'; - result[resultPos++] = 't'; - } - break; - - } - } - - return result.Slice(0, resultPos).ToString(); - } - - private static string? LCIDToLocaleName(int culture) - { - Debug.Assert(!GlobalizationMode.Invariant); - - return LocaleData.LCIDToLocaleName(culture); - } - - private static int LocaleNameToLCID(string cultureName) - { - Debug.Assert(!GlobalizationMode.Invariant); - - int lcid = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.Lcid); - return lcid == -1 ? CultureInfo.LOCALE_CUSTOM_UNSPECIFIED : lcid; - } - - private static int GetAnsiCodePage(string cultureName) - { - int ansiCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.AnsiCodePage); - return ansiCodePage == -1 ? CultureData.Invariant.ANSICodePage : ansiCodePage; - } - - private static int GetOemCodePage(string cultureName) - { - int oemCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.OemCodePage); - return oemCodePage == -1 ? CultureData.Invariant.OEMCodePage : oemCodePage; - } - - private static int GetMacCodePage(string cultureName) - { - int macCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.MacCodePage); - return macCodePage == -1 ? CultureData.Invariant.MacCodePage : macCodePage; - } - - private static int GetEbcdicCodePage(string cultureName) - { - int ebcdicCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.EbcdicCodePage); - return ebcdicCodePage == -1 ? CultureData.Invariant.EBCDICCodePage : ebcdicCodePage; - } - - private static int GetGeoId(string cultureName) - { - int geoId = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.GeoId); - return geoId == -1 ? CultureData.Invariant.GeoId : geoId; - } - - private static int GetDigitSubstitution(string cultureName) - { - int digitSubstitution = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.DigitSubstitution); - return digitSubstitution == -1 ? (int) DigitShapes.None : digitSubstitution; - } - - private static string GetThreeLetterWindowsLanguageName(string cultureName) - { - return LocaleData.GetThreeLetterWindowsLanguageName(cultureName) ?? "ZZZ" /* default lang name */; - } - - private static CultureInfo[] EnumCultures(CultureTypes types) - { - Debug.Assert(!GlobalizationMode.Invariant); - - if ((types & (CultureTypes.NeutralCultures | CultureTypes.SpecificCultures)) == 0) - { - return Array.Empty(); - } - - int bufferLength = Interop.Globalization.GetLocales(null, 0); - if (bufferLength <= 0) - { - return Array.Empty(); - } - - char [] chars = new char[bufferLength]; - - bufferLength = Interop.Globalization.GetLocales(chars, bufferLength); - if (bufferLength <= 0) - { - return Array.Empty(); - } - - bool enumNeutrals = (types & CultureTypes.NeutralCultures) != 0; - bool enumSpecificss = (types & CultureTypes.SpecificCultures) != 0; - - List list = new List(); - if (enumNeutrals) - { - list.Add(CultureInfo.InvariantCulture); - } - - int index = 0; - while (index < bufferLength) - { - int length = (int) chars[index++]; - if (index + length <= bufferLength) - { - CultureInfo ci = CultureInfo.GetCultureInfo(new string(chars, index, length)); - if ((enumNeutrals && ci.IsNeutralCulture) || (enumSpecificss && !ci.IsNeutralCulture)) - { - list.Add(ci); - } - } - - index += length; - } - - return list.ToArray(); - } - - private static string GetConsoleFallbackName(string cultureName) - { - return LocaleData.GetConsoleUICulture(cultureName); - } - internal bool IsWin32Installed => false; - internal bool IsReplacementCulture => false; - - internal static CultureData GetCurrentRegionData() => CultureInfo.CurrentCulture._cultureData; + internal static unsafe CultureData GetCurrentRegionData() => CultureInfo.CurrentCulture._cultureData; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Windows.cs index 48e4552c520ef5..e67747bddcff99 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Windows.cs @@ -2,12 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Text; -using Internal.Runtime.CompilerServices; -using System.Runtime.InteropServices; namespace System.Globalization { @@ -46,7 +41,7 @@ internal partial class CultureData /// For a neutral we just populate the neutral name, but we leave the windows name pointing to the /// windows locale that's going to provide data for us. /// - private unsafe bool InitCultureData() + private unsafe bool InitCultureDataCore() { Debug.Assert(!GlobalizationMode.Invariant); @@ -103,6 +98,7 @@ private unsafe bool InitCultureData() { return false; } + // We found a locale name, so use it. // In vista this should look like a sort name (de-DE_phoneb) or a specific culture (en-US) and be in the "pretty" form _sSpecificCulture = new string(pBuffer, 0, result - 1); @@ -136,7 +132,7 @@ private unsafe bool InitCultureData() { // not custom locale int index = realNameBuffer.IndexOf('_'); - if (index > 0 && index < realNameBuffer.Length) + if (index > 0) { _sName = realNameBuffer.Substring(0, index); } @@ -147,575 +143,8 @@ private unsafe bool InitCultureData() return true; } - // Wrappers around the GetLocaleInfoEx APIs which handle marshalling the returned - // data as either and Int or string. - internal static unsafe string? GetLocaleInfoEx(string localeName, uint field) - { - // REVIEW: Determine the maximum size for the buffer - const int BUFFER_SIZE = 530; - - char* pBuffer = stackalloc char[BUFFER_SIZE]; - int resultCode = GetLocaleInfoEx(localeName, field, pBuffer, BUFFER_SIZE); - if (resultCode > 0) - { - return new string(pBuffer); - } - - return null; - } - - internal static unsafe int GetLocaleInfoExInt(string localeName, uint field) - { - field |= Interop.Kernel32.LOCALE_RETURN_NUMBER; - int value = 0; - GetLocaleInfoEx(localeName, field, (char*)&value, sizeof(int)); - return value; - } - - internal static unsafe int GetLocaleInfoEx(string lpLocaleName, uint lcType, char* lpLCData, int cchData) - { - Debug.Assert(!GlobalizationMode.Invariant); - - return Interop.Kernel32.GetLocaleInfoEx(lpLocaleName, lcType, lpLCData, cchData); - } - - private string GetLocaleInfo(LocaleStringData type) - { - Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfo] Expected _sWindowsName to be populated by already"); - return GetLocaleInfo(_sWindowsName, type); - } - - // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the - // "windows" name, which can be specific for downlevel (< windows 7) os's. - private string GetLocaleInfo(string localeName, LocaleStringData type) - { - uint lctype = (uint)type; - - return GetLocaleInfoFromLCType(localeName, lctype, UseUserOverride); - } - - private int GetLocaleInfo(LocaleNumberData type) - { - uint lctype = (uint)type; - - // Fix lctype if we don't want overrides - if (!UseUserOverride) - { - lctype |= Interop.Kernel32.LOCALE_NOUSEROVERRIDE; - } - - // Ask OS for data, note that we presume it returns success, so we have to know that - // sWindowsName is valid before calling. - Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); - return GetLocaleInfoExInt(_sWindowsName, lctype); - } - - private int[] GetLocaleInfo(LocaleGroupingData type) - { - Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); - return ConvertWin32GroupString(GetLocaleInfoFromLCType(_sWindowsName, (uint)type, UseUserOverride)); - } - - private string? GetTimeFormatString() - { - Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); - return ReescapeWin32String(GetLocaleInfoFromLCType(_sWindowsName, Interop.Kernel32.LOCALE_STIMEFORMAT, UseUserOverride)); - } - - private int GetFirstDayOfWeek() - { - Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); - - int result = GetLocaleInfoExInt(_sWindowsName, Interop.Kernel32.LOCALE_IFIRSTDAYOFWEEK | (!UseUserOverride ? Interop.Kernel32.LOCALE_NOUSEROVERRIDE : 0)); - - // Win32 and .NET disagree on the numbering for days of the week, so we have to convert. - return ConvertFirstDayOfWeekMonToSun(result); - } - - private string[]? GetTimeFormats() - { - // Note that this gets overrides for us all the time - Debug.Assert(_sWindowsName != null, "[CultureData.DoEnumTimeFormats] Expected _sWindowsName to be populated by already"); - string[]? result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, 0, UseUserOverride)); - - return result; - } - - private string[]? GetShortTimeFormats() - { - // Note that this gets overrides for us all the time - Debug.Assert(_sWindowsName != null, "[CultureData.DoEnumShortTimeFormats] Expected _sWindowsName to be populated by already"); - string[]? result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, Interop.Kernel32.TIME_NOSECONDS, UseUserOverride)); - - return result; - } - - // Enumerate all system cultures and then try to find out which culture has - // region name match the requested region name - private static CultureData? GetCultureDataFromRegionName(string regionName) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(regionName != null); - - EnumLocaleData context; - context.cultureName = null; - context.regionName = regionName; - - unsafe - { - Interop.Kernel32.EnumSystemLocalesEx(EnumSystemLocalesProc, Interop.Kernel32.LOCALE_SPECIFICDATA | Interop.Kernel32.LOCALE_SUPPLEMENTAL, Unsafe.AsPointer(ref context), IntPtr.Zero); - } - - if (context.cultureName != null) - { - // we got a matched culture - return GetCultureData(context.cultureName, true); - } - - return null; - } - - private string GetLanguageDisplayName(string cultureName) - { - // Usually the UI culture shouldn't be different than what we got from WinRT except - // if DefaultThreadCurrentUICulture was set - CultureInfo? ci; - - if (CultureInfo.DefaultThreadCurrentUICulture != null && - ((ci = CultureInfo.GetUserDefaultCulture()) != null) && - !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name)) - { - return NativeName; - } - else - { - return GetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName); - } - } - - private string GetRegionDisplayName() - { - // If the current UI culture matching the OS UI language, we'll get the display name from the OS. - // otherwise, we use the native name as we don't carry resources for the region display names anyway. - if (CultureInfo.CurrentUICulture.Name.Equals(CultureInfo.UserDefaultUICulture.Name)) - { - return GetLocaleInfo(LocaleStringData.LocalizedCountryName); - } - - return NativeCountryName; - } - - // PAL methods end here. - - private static string GetLocaleInfoFromLCType(string localeName, uint lctype, bool useUserOveride) - { - Debug.Assert(localeName != null, "[CultureData.GetLocaleInfoFromLCType] Expected localeName to be not be null"); - - // Fix lctype if we don't want overrides - if (!useUserOveride) - { - lctype |= Interop.Kernel32.LOCALE_NOUSEROVERRIDE; - } - - // Ask OS for data - // Failed? Just use empty string - return GetLocaleInfoEx(localeName, lctype) ?? string.Empty; - } - - /// - /// Reescape a Win32 style quote string as a NLS+ style quoted string - /// - /// This is also the escaping style used by custom culture data files - /// - /// NLS+ uses \ to escape the next character, whether in a quoted string or - /// not, so we always have to change \ to \\. - /// - /// NLS+ uses \' to escape a quote inside a quoted string so we have to change - /// '' to \' (if inside a quoted string) - /// - /// We don't build the stringbuilder unless we find something to change - /// - [return: NotNullIfNotNull("str")] - internal static string? ReescapeWin32String(string? str) - { - // If we don't have data, then don't try anything - if (str == null) - { - return null; - } - - StringBuilder? result = null; - - bool inQuote = false; - for (int i = 0; i < str.Length; i++) - { - // Look for quote - if (str[i] == '\'') - { - // Already in quote? - if (inQuote) - { - // See another single quote. Is this '' of 'fred''s' or '''', or is it an ending quote? - if (i + 1 < str.Length && str[i + 1] == '\'') - { - // Found another ', so we have ''. Need to add \' instead. - // 1st make sure we have our stringbuilder - result ??= new StringBuilder(str, 0, i, str.Length * 2); - - // Append a \' and keep going (so we don't turn off quote mode) - result.Append("\\'"); - i++; - continue; - } - - // Turning off quote mode, fall through to add it - inQuote = false; - } - else - { - // Found beginning quote, fall through to add it - inQuote = true; - } - } - // Is there a single \ character? - else if (str[i] == '\\') - { - // Found a \, need to change it to \\ - // 1st make sure we have our stringbuilder - result ??= new StringBuilder(str, 0, i, str.Length * 2); - - // Append our \\ to the string & continue - result.Append("\\\\"); - continue; - } - - // If we have a builder we need to add our character - result?.Append(str[i]); - } - - // Unchanged string? , just return input string - if (result == null) - return str; - - // String changed, need to use the builder - return result.ToString(); - } - - [return: NotNullIfNotNull("array")] - internal static string[]? ReescapeWin32Strings(string[]? array) - { - if (array != null) - { - for (int i = 0; i < array.Length; i++) - { - array[i] = ReescapeWin32String(array[i]); - } - } - - return array; - } - - // If we get a group from windows, then its in 3;0 format with the 0 backwards - // of how NLS+ uses it (ie: if the string has a 0, then the int[] shouldn't and vice versa) - // EXCEPT in the case where the list only contains 0 in which NLS and NLS+ have the same meaning. - private static int[] ConvertWin32GroupString(string win32Str) - { - // None of these cases make any sense - if (string.IsNullOrEmpty(win32Str)) - { - return new int[] { 3 }; - } - - if (win32Str[0] == '0') - { - return new int[] { 0 }; - } - - // Since its in n;n;n;n;n format, we can always get the length quickly - int[] values; - if (win32Str[^1] == '0') - { - // Trailing 0 gets dropped. 1;0 -> 1 - values = new int[win32Str.Length / 2]; - } - else - { - // Need extra space for trailing zero 1 -> 1;0 - values = new int[(win32Str.Length / 2) + 2]; - values[^1] = 0; - } - - int i; - int j; - for (i = 0, j = 0; i < win32Str.Length && j < values.Length; i += 2, j++) - { - // Note that this # shouldn't ever be zero, 'cause 0 is only at end - // But we'll test because its registry that could be anything - if (win32Str[i] < '1' || win32Str[i] > '9') - return new int[] { 3 }; - - values[j] = (int)(win32Str[i] - '0'); - } - - return values; - } - - private static int ConvertFirstDayOfWeekMonToSun(int iTemp) - { - // Convert Mon-Sun to Sun-Sat format - iTemp++; - if (iTemp > 6) - { - // Wrap Sunday and convert invalid data to Sunday - iTemp = 0; - } - return iTemp; - } - - // Context for EnumCalendarInfoExEx callback. - private struct EnumLocaleData - { - public string regionName; - public string? cultureName; - } - - // EnumSystemLocaleEx callback. - // [NativeCallable(CallingConvention = CallingConvention.StdCall)] - private static unsafe Interop.BOOL EnumSystemLocalesProc(char* lpLocaleString, uint flags, void* contextHandle) - { - ref EnumLocaleData context = ref Unsafe.As(ref *(byte*)contextHandle); - try - { - string cultureName = new string(lpLocaleString); - string? regionName = GetLocaleInfoEx(cultureName, Interop.Kernel32.LOCALE_SISO3166CTRYNAME); - if (regionName != null && regionName.Equals(context.regionName, StringComparison.OrdinalIgnoreCase)) - { - context.cultureName = cultureName; - return Interop.BOOL.FALSE; // we found a match, then stop the enumeration - } - - return Interop.BOOL.TRUE; - } - catch (Exception) - { - return Interop.BOOL.FALSE; - } - } - - // EnumSystemLocaleEx callback. - // [NativeCallable(CallingConvention = CallingConvention.StdCall)] - private static unsafe Interop.BOOL EnumAllSystemLocalesProc(char* lpLocaleString, uint flags, void* contextHandle) - { - ref EnumData context = ref Unsafe.As(ref *(byte*)contextHandle); - try - { - context.strings.Add(new string(lpLocaleString)); - return Interop.BOOL.TRUE; - } - catch (Exception) - { - return Interop.BOOL.FALSE; - } - } - - // Context for EnumTimeFormatsEx callback. - private struct EnumData - { - public List strings; - } - - // EnumTimeFormatsEx callback itself. - // [NativeCallable(CallingConvention = CallingConvention.StdCall)] - private static unsafe Interop.BOOL EnumTimeCallback(char* lpTimeFormatString, void* lParam) - { - ref EnumData context = ref Unsafe.As(ref *(byte*)lParam); - try - { - context.strings.Add(new string(lpTimeFormatString)); - return Interop.BOOL.TRUE; - } - catch (Exception) - { - return Interop.BOOL.FALSE; - } - } - - private static unsafe string[]? nativeEnumTimeFormats(string localeName, uint dwFlags, bool useUserOverride) - { - EnumData data = default; - data.strings = new List(); - - // Now call the enumeration API. Work is done by our callback function - Interop.Kernel32.EnumTimeFormatsEx(EnumTimeCallback, localeName, (uint)dwFlags, Unsafe.AsPointer(ref data)); - - if (data.strings.Count > 0) - { - // Now we need to allocate our stringarray and populate it - string[] results = data.strings.ToArray(); - - if (!useUserOverride && data.strings.Count > 1) - { - // Since there is no "NoUserOverride" aware EnumTimeFormatsEx, we always get an override - // The override is the first entry if it is overriden. - // We can check if we have overrides by checking the GetLocaleInfo with no override - // If we do have an override, we don't know if it is a user defined override or if the - // user has just selected one of the predefined formats so we can't just remove it - // but we can move it down. - uint lcType = (dwFlags == Interop.Kernel32.TIME_NOSECONDS) ? Interop.Kernel32.LOCALE_SSHORTTIME : Interop.Kernel32.LOCALE_STIMEFORMAT; - string timeFormatNoUserOverride = GetLocaleInfoFromLCType(localeName, lcType, useUserOverride); - if (timeFormatNoUserOverride != "") - { - string firstTimeFormat = results[0]; - if (timeFormatNoUserOverride != firstTimeFormat) - { - results[0] = results[1]; - results[1] = firstTimeFormat; - } - } - } - - return results; - } - - return null; - } - - private static int LocaleNameToLCID(string cultureName) - { - Debug.Assert(!GlobalizationMode.Invariant); - - return Interop.Kernel32.LocaleNameToLCID(cultureName, Interop.Kernel32.LOCALE_ALLOW_NEUTRAL_NAMES); - } - - private static unsafe string? LCIDToLocaleName(int culture) - { - Debug.Assert(!GlobalizationMode.Invariant); - - char* pBuffer = stackalloc char[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH + 1]; // +1 for the null termination - int length = Interop.Kernel32.LCIDToLocaleName(culture, pBuffer, Interop.Kernel32.LOCALE_NAME_MAX_LENGTH + 1, Interop.Kernel32.LOCALE_ALLOW_NEUTRAL_NAMES); - - if (length > 0) - { - return new string(pBuffer); - } - - return null; - } - - private int GetAnsiCodePage(string cultureName) - { - return GetLocaleInfo(LocaleNumberData.AnsiCodePage); - } - - private int GetOemCodePage(string cultureName) - { - return GetLocaleInfo(LocaleNumberData.OemCodePage); - } - - private int GetMacCodePage(string cultureName) - { - return GetLocaleInfo(LocaleNumberData.MacCodePage); - } - - private int GetEbcdicCodePage(string cultureName) - { - return GetLocaleInfo(LocaleNumberData.EbcdicCodePage); - } - - private int GetGeoId(string cultureName) - { - return GetLocaleInfo(LocaleNumberData.GeoId); - } - - private int GetDigitSubstitution(string cultureName) - { - return GetLocaleInfo(LocaleNumberData.DigitSubstitution); - } - - private string GetThreeLetterWindowsLanguageName(string cultureName) - { - return GetLocaleInfo(cultureName, LocaleStringData.AbbreviatedWindowsLanguageName); - } - - private static CultureInfo[] EnumCultures(CultureTypes types) - { - Debug.Assert(!GlobalizationMode.Invariant); - - uint flags = 0; - -#pragma warning disable 618 - if ((types & (CultureTypes.FrameworkCultures | CultureTypes.InstalledWin32Cultures | CultureTypes.ReplacementCultures)) != 0) - { - flags |= Interop.Kernel32.LOCALE_NEUTRALDATA | Interop.Kernel32.LOCALE_SPECIFICDATA; - } -#pragma warning restore 618 - - if ((types & CultureTypes.NeutralCultures) != 0) - { - flags |= Interop.Kernel32.LOCALE_NEUTRALDATA; - } - - if ((types & CultureTypes.SpecificCultures) != 0) - { - flags |= Interop.Kernel32.LOCALE_SPECIFICDATA; - } - - if ((types & CultureTypes.UserCustomCulture) != 0) - { - flags |= Interop.Kernel32.LOCALE_SUPPLEMENTAL; - } - - if ((types & CultureTypes.ReplacementCultures) != 0) - { - flags |= Interop.Kernel32.LOCALE_SUPPLEMENTAL; - } - - EnumData context = default; - context.strings = new List(); - - unsafe - { - Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, flags, Unsafe.AsPointer(ref context), IntPtr.Zero); - } - - CultureInfo[] cultures = new CultureInfo[context.strings.Count]; - for (int i = 0; i < cultures.Length; i++) - { - cultures[i] = new CultureInfo(context.strings[i]); - } - - return cultures; - } - - private string GetConsoleFallbackName(string cultureName) - { - return GetLocaleInfo(cultureName, LocaleStringData.ConsoleFallbackName); - } - internal bool IsWin32Installed => true; - internal bool IsReplacementCulture - { - get - { - EnumData context = default; - context.strings = new List(); - - unsafe - { - Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, Interop.Kernel32.LOCALE_REPLACEMENT, Unsafe.AsPointer(ref context), IntPtr.Zero); - } - - for (int i = 0; i < context.strings.Count; i++) - { - if (string.Equals(context.strings[i], _sWindowsName, StringComparison.OrdinalIgnoreCase)) - return true; - } - - return false; - } - } - internal static unsafe CultureData GetCurrentRegionData() { Span geoIso2Letters = stackalloc char[10]; diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs index 70fc78879bbd80..de5f78b503e76a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs @@ -474,7 +474,7 @@ internal partial class CultureData // If not found in the hard coded table we'll have to find a culture that works for us if (!GlobalizationMode.Invariant && (retVal == null || retVal.IsNeutralCulture)) { - retVal = GetCultureDataFromRegionName(cultureName); + retVal = GlobalizationMode.UseNls ? NlsGetCultureDataFromRegionName(cultureName) : IcuGetCultureDataFromRegionName(cultureName); } // If we found one we can use, then cache it for next time @@ -540,7 +540,7 @@ internal static CultureInfo[] GetCultures(CultureTypes types) } #pragma warning restore 618 - return EnumCultures(types); + return GlobalizationMode.UseNls ? NlsEnumCultures(types) : IcuEnumCultures(types); } private static CultureData CreateCultureWithInvariantData() @@ -802,7 +802,7 @@ private static string NormalizeCultureName(string name, out bool isNeutralName) culture._sRealName = cultureName; // Ask native code if that one's real - if (!culture.InitCultureData() && !culture.InitCompatibilityCultureData()) + if (!culture.InitCultureDataCore() && !culture.InitCompatibilityCultureData()) { return null; } @@ -832,7 +832,7 @@ private bool InitCompatibilityCultureData() } _sRealName = fallbackCultureName; - if (!InitCultureData()) + if (!InitCultureDataCore()) { return false; } @@ -863,7 +863,7 @@ internal static CultureData GetCultureData(int culture, bool bUseUserOverride) // Convert the lcid to a name, then use that // Note that this will return neutral names (unlike Vista native API) - localeName = LCIDToLocaleName(culture); + localeName = GlobalizationMode.UseNls ? NlsLCIDToLocaleName(culture) : IcuLCIDToLocaleName(culture); if (!string.IsNullOrEmpty(localeName)) { @@ -914,7 +914,7 @@ internal string CultureName // Parent name (which may be a custom locale/culture) // Ask using the real name, so that we get parents of neutrals - internal string ParentName => _sParent ??= GetLocaleInfo(_sRealName!, LocaleStringData.ParentName); + internal string ParentName => _sParent ??= GetLocaleInfoCore(_sRealName!, LocaleStringData.ParentName); // Localized pretty name for this locale (ie: Inglis (estados Unitos)) internal string DisplayName @@ -944,15 +944,15 @@ internal string DisplayName if (Name.Equals(ZH_CHT, StringComparison.OrdinalIgnoreCase)) { - localizedDisplayName = GetLanguageDisplayName("zh-Hant"); + localizedDisplayName = GetLanguageDisplayNameCore("zh-Hant"); } else if (Name.Equals(ZH_CHS, StringComparison.OrdinalIgnoreCase)) { - localizedDisplayName = GetLanguageDisplayName("zh-Hans"); + localizedDisplayName = GetLanguageDisplayNameCore("zh-Hans"); } else { - localizedDisplayName = GetLanguageDisplayName(Name); + localizedDisplayName = GetLanguageDisplayNameCore(Name); } } catch @@ -983,7 +983,7 @@ internal string DisplayName } else { - localizedDisplayName = GetLocaleInfo(LocaleStringData.LocalizedDisplayName); + localizedDisplayName = GetLocaleInfoCore(LocaleStringData.LocalizedDisplayName); } } } @@ -995,6 +995,10 @@ internal string DisplayName } } + private string GetLanguageDisplayNameCore(string cultureName) => GlobalizationMode.UseNls ? + NlsGetLanguageDisplayName(cultureName) : + IcuGetLanguageDisplayName(cultureName); + /// /// English pretty name for this locale (ie: English (United States)) /// @@ -1020,7 +1024,7 @@ internal string EnglishName } else { - englishDisplayName = GetLocaleInfo(LocaleStringData.EnglishDisplayName); + englishDisplayName = GetLocaleInfoCore(LocaleStringData.EnglishDisplayName); // if it isn't found build one: if (string.IsNullOrEmpty(englishDisplayName)) @@ -1079,7 +1083,7 @@ internal string NativeName } else { - nativeDisplayName = GetLocaleInfo(LocaleStringData.NativeDisplayName); + nativeDisplayName = GetLocaleInfoCore(LocaleStringData.NativeDisplayName); // if it isn't found build one: if (string.IsNullOrEmpty(nativeDisplayName)) @@ -1112,17 +1116,19 @@ internal string SpecificCultureName /// /// iso 639 language name, ie: en /// - internal string TwoLetterISOLanguageName => _sISO639Language ??= GetLocaleInfo(LocaleStringData.Iso639LanguageTwoLetterName); + internal string TwoLetterISOLanguageName => _sISO639Language ??= GetLocaleInfoCore(LocaleStringData.Iso639LanguageTwoLetterName); /// /// iso 639 language name, ie: eng /// - internal string ThreeLetterISOLanguageName => _sISO639Language2 ??= GetLocaleInfo(LocaleStringData.Iso639LanguageThreeLetterName); + internal string ThreeLetterISOLanguageName => _sISO639Language2 ??= GetLocaleInfoCore(LocaleStringData.Iso639LanguageThreeLetterName); /// /// abbreviated windows language name (ie: enu) (non-standard, avoid this) /// - internal string ThreeLetterWindowsLanguageName => _sAbbrevLang ??= GetThreeLetterWindowsLanguageName(_sRealName!); + internal string ThreeLetterWindowsLanguageName => _sAbbrevLang ??= GlobalizationMode.UseNls ? + NlsGetThreeLetterWindowsLanguageName(_sRealName!) : + IcuGetThreeLetterWindowsLanguageName(_sRealName!); /// /// Localized name for this language (Windows Only) ie: Inglis @@ -1146,7 +1152,7 @@ private string LocalizedLanguageName } else { - _sLocalizedLanguage = GetLocaleInfo(LocaleStringData.LocalizedLanguageName); + _sLocalizedLanguage = GetLocaleInfoCore(LocaleStringData.LocalizedLanguageName); } } @@ -1157,17 +1163,17 @@ private string LocalizedLanguageName /// /// English name for this language (Windows Only) ie: German /// - private string EnglishLanguageName => _sEnglishLanguage ??= GetLocaleInfo(LocaleStringData.EnglishLanguageName); + private string EnglishLanguageName => _sEnglishLanguage ??= GetLocaleInfoCore(LocaleStringData.EnglishLanguageName); /// /// Native name of this language (Windows Only) ie: Deutsch /// - private string NativeLanguageName => _sNativeLanguage ??= GetLocaleInfo(LocaleStringData.NativeLanguageName); + private string NativeLanguageName => _sNativeLanguage ??= GetLocaleInfoCore(LocaleStringData.NativeLanguageName); /// /// region name (eg US) /// - internal string RegionName => _sRegionName ??= GetLocaleInfo(LocaleStringData.Iso3166CountryName); + internal string RegionName => _sRegionName ??= GetLocaleInfoCore(LocaleStringData.Iso3166CountryName); internal int GeoId { @@ -1175,7 +1181,7 @@ internal int GeoId { if (_iGeoId == undef) { - _iGeoId = GetGeoId(_sRealName!); + _iGeoId = GlobalizationMode.UseNls ? NlsGetGeoId(_sRealName!) : IcuGetGeoId(_sRealName!); } return _iGeoId; } @@ -1193,7 +1199,7 @@ internal string LocalizedCountryName { try { - localizedCountry = GetRegionDisplayName(); + localizedCountry = GlobalizationMode.UseNls ? NlsGetRegionDisplayName() : IcuGetRegionDisplayName(); } catch { @@ -1211,22 +1217,22 @@ internal string LocalizedCountryName /// /// english country name (RegionInfo) ie: Germany /// - internal string EnglishCountryName => _sEnglishCountry ??= GetLocaleInfo(LocaleStringData.EnglishCountryName); + internal string EnglishCountryName => _sEnglishCountry ??= GetLocaleInfoCore(LocaleStringData.EnglishCountryName); /// /// native country name (RegionInfo) ie: Deutschland /// - internal string NativeCountryName => _sNativeCountry ??= GetLocaleInfo(LocaleStringData.NativeCountryName); + internal string NativeCountryName => _sNativeCountry ??= GetLocaleInfoCore(LocaleStringData.NativeCountryName); /// /// ISO 3166 Country Name /// - internal string TwoLetterISOCountryName => _sISO3166CountryName ??= GetLocaleInfo(LocaleStringData.Iso3166CountryName); + internal string TwoLetterISOCountryName => _sISO3166CountryName ??= GetLocaleInfoCore(LocaleStringData.Iso3166CountryName); /// /// 3 letter ISO 3166 country code /// - internal string ThreeLetterISOCountryName => _sISO3166CountryName2 ??= GetLocaleInfo(LocaleStringData.Iso3166CountryName2); + internal string ThreeLetterISOCountryName => _sISO3166CountryName2 ??= GetLocaleInfoCore(LocaleStringData.Iso3166CountryName2); internal int KeyboardLayoutId { @@ -1251,27 +1257,29 @@ internal int KeyboardLayoutId /// /// Console fallback name (ie: locale to use for console apps for unicode-only locales) /// - internal string SCONSOLEFALLBACKNAME => _sConsoleFallbackName ??= GetConsoleFallbackName(_sRealName!); + internal string SCONSOLEFALLBACKNAME => _sConsoleFallbackName ??= GlobalizationMode.UseNls ? + NlsGetConsoleFallbackName(_sRealName!) : + IcuGetConsoleFallbackName(_sRealName!); /// /// (user can override) grouping of digits /// - internal int[] NumberGroupSizes => _waGrouping ??= GetLocaleInfo(LocaleGroupingData.Digit); + internal int[] NumberGroupSizes => _waGrouping ??= GetLocaleInfoCore(LocaleGroupingData.Digit); /// /// Not a Number /// - private string NaNSymbol => _sNaN ??= GetLocaleInfo(LocaleStringData.NaNSymbol); + private string NaNSymbol => _sNaN ??= GetLocaleInfoCore(LocaleStringData.NaNSymbol); /// /// + Infinity /// - private string PositiveInfinitySymbol => _sPositiveInfinity ??= GetLocaleInfo(LocaleStringData.PositiveInfinitySymbol); + private string PositiveInfinitySymbol => _sPositiveInfinity ??= GetLocaleInfoCore(LocaleStringData.PositiveInfinitySymbol); /// /// - Infinity /// - private string NegativeInfinitySymbol => _sNegativeInfinity ??= GetLocaleInfo(LocaleStringData.NegativeInfinitySymbol); + private string NegativeInfinitySymbol => _sNegativeInfinity ??= GetLocaleInfoCore(LocaleStringData.NegativeInfinitySymbol); /// /// Negative Percent (0-3) @@ -1283,7 +1291,7 @@ private int PercentNegativePattern if (_iNegativePercent == undef) { // Note that <= Windows Vista this is synthesized by native code - _iNegativePercent = GetLocaleInfo(LocaleNumberData.NegativePercentFormat); + _iNegativePercent = GetLocaleInfoCore(LocaleNumberData.NegativePercentFormat); } return _iNegativePercent; } @@ -1299,7 +1307,7 @@ private int PercentPositivePattern if (_iPositivePercent == undef) { // Note that <= Windows Vista this is synthesized by native code - _iPositivePercent = GetLocaleInfo(LocaleNumberData.PositivePercentFormat); + _iPositivePercent = GetLocaleInfoCore(LocaleNumberData.PositivePercentFormat); } return _iPositivePercent; } @@ -1308,37 +1316,37 @@ private int PercentPositivePattern /// /// Percent (%) symbol /// - private string PercentSymbol => _sPercent ??= GetLocaleInfo(LocaleStringData.PercentSymbol); + private string PercentSymbol => _sPercent ??= GetLocaleInfoCore(LocaleStringData.PercentSymbol); /// /// PerMille symbol /// - private string PerMilleSymbol => _sPerMille ??= GetLocaleInfo(LocaleStringData.PerMilleSymbol); + private string PerMilleSymbol => _sPerMille ??= GetLocaleInfoCore(LocaleStringData.PerMilleSymbol); /// /// (user can override) local monetary symbol, eg: $ /// - internal string CurrencySymbol => _sCurrency ??= GetLocaleInfo(LocaleStringData.MonetarySymbol); + internal string CurrencySymbol => _sCurrency ??= GetLocaleInfoCore(LocaleStringData.MonetarySymbol); /// /// international monetary symbol (RegionInfo), eg: USD /// - internal string ISOCurrencySymbol => _sIntlMonetarySymbol ??= GetLocaleInfo(LocaleStringData.Iso4217MonetarySymbol); + internal string ISOCurrencySymbol => _sIntlMonetarySymbol ??= GetLocaleInfoCore(LocaleStringData.Iso4217MonetarySymbol); /// /// English name for this currency (RegionInfo), eg: US Dollar /// - internal string CurrencyEnglishName => _sEnglishCurrency ??= GetLocaleInfo(LocaleStringData.CurrencyEnglishName); + internal string CurrencyEnglishName => _sEnglishCurrency ??= GetLocaleInfoCore(LocaleStringData.CurrencyEnglishName); /// /// Native name for this currency (RegionInfo), eg: Schweiz Frank /// - internal string CurrencyNativeName => _sNativeCurrency ??= GetLocaleInfo(LocaleStringData.CurrencyNativeName); + internal string CurrencyNativeName => _sNativeCurrency ??= GetLocaleInfoCore(LocaleStringData.CurrencyNativeName); /// /// (user can override) monetary grouping of digits /// - internal int[] CurrencyGroupSizes => _waMonetaryGrouping ??= GetLocaleInfo(LocaleGroupingData.Monetary); + internal int[] CurrencyGroupSizes => _waMonetaryGrouping ??= GetLocaleInfoCore(LocaleGroupingData.Monetary); /// /// (user can override) system of measurement 0=metric, 1=US (RegionInfo) @@ -1349,7 +1357,7 @@ internal int MeasurementSystem { if (_iMeasure == undef) { - _iMeasure = GetLocaleInfo(LocaleNumberData.MeasurementSystem); + _iMeasure = GetLocaleInfoCore(LocaleNumberData.MeasurementSystem); } return _iMeasure; } @@ -1358,17 +1366,17 @@ internal int MeasurementSystem /// /// (user can override) list Separator /// - internal string ListSeparator => _sListSeparator ??= GetLocaleInfo(LocaleStringData.ListSeparator); + internal string ListSeparator => _sListSeparator ??= GetLocaleInfoCore(LocaleStringData.ListSeparator); /// /// (user can override) AM designator /// - internal string AMDesignator => _sAM1159 ??= GetLocaleInfo(LocaleStringData.AMDesignator); + internal string AMDesignator => _sAM1159 ??= GetLocaleInfoCore(LocaleStringData.AMDesignator); /// /// (user can override) PM designator /// - internal string PMDesignator => _sPM2359 ??= GetLocaleInfo(LocaleStringData.PMDesignator); + internal string PMDesignator => _sPM2359 ??= GetLocaleInfoCore(LocaleStringData.PMDesignator); /// /// (user can override) time format @@ -1381,7 +1389,7 @@ internal string[] LongTimes { Debug.Assert(!GlobalizationMode.Invariant); - string[]? longTimes = GetTimeFormats(); + string[]? longTimes = GlobalizationMode.UseNls ? NlsGetTimeFormats() : IcuGetTimeFormats(); if (longTimes == null || longTimes.Length == 0) { _saLongTimes = Invariant._saLongTimes!; @@ -1408,7 +1416,7 @@ internal string[] ShortTimes Debug.Assert(!GlobalizationMode.Invariant); // Try to get the short times from the OS/culture.dll - string[]? shortTimes = GetShortTimeFormats(); + string[]? shortTimes = GlobalizationMode.UseNls ? NlsGetShortTimeFormats() : IcuGetShortTimeFormats(); if (shortTimes == null || shortTimes.Length == 0) { @@ -1559,7 +1567,7 @@ internal int FirstDayOfWeek { if (_iFirstDayOfWeek == undef) { - _iFirstDayOfWeek = GetFirstDayOfWeek(); + _iFirstDayOfWeek = GlobalizationMode.UseNls ? NlsGetFirstDayOfWeek() : IcuGetFirstDayOfWeek(); } return _iFirstDayOfWeek; } @@ -1572,7 +1580,7 @@ internal int CalendarWeekRule { if (_iFirstWeekOfYear == undef) { - _iFirstWeekOfYear = GetLocaleInfo(LocaleNumberData.FirstWeekOfYear); + _iFirstWeekOfYear = GetLocaleInfoCore(LocaleNumberData.FirstWeekOfYear); } return _iFirstWeekOfYear; } @@ -1665,7 +1673,10 @@ internal CalendarId[] CalendarIds // Default calendar should be first CalendarId[] calendars = new CalendarId[23]; Debug.Assert(_sWindowsName != null, "[CultureData.CalendarIds] Expected _sWindowsName to be populated by already"); - int count = CalendarData.GetCalendars(_sWindowsName, _bUseOverrides, calendars); + + int count = GlobalizationMode.UseNls + ? CalendarData.NlsGetCalendars(_sWindowsName, _bUseOverrides, calendars) + : CalendarData.IcuGetCalendars(_sWindowsName, _bUseOverrides, calendars); // See if we had a calendar to add. if (count == 0) @@ -1711,7 +1722,7 @@ internal CalendarId[] CalendarIds // Prior to Vista the enumeration didn't have default calendar first if (temp.Length > 1) { - CalendarId i = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType); + CalendarId i = (CalendarId)GetLocaleInfoCore(LocaleNumberData.CalendarType); if (temp[1] == i) { temp[1] = temp[0]; @@ -1784,7 +1795,7 @@ private int ReadingLayout if (_iReadingLayout == undef) { Debug.Assert(_sRealName != null, "[CultureData.IsRightToLeft] Expected _sRealName to be populated by already"); - _iReadingLayout = GetLocaleInfo(LocaleNumberData.ReadingLayout); + _iReadingLayout = GetLocaleInfoCore(LocaleNumberData.ReadingLayout); } return _iReadingLayout; @@ -1835,7 +1846,7 @@ internal int ANSICodePage { if (_iDefaultAnsiCodePage == undef) { - _iDefaultAnsiCodePage = GetAnsiCodePage(_sRealName!); + _iDefaultAnsiCodePage = GlobalizationMode.UseNls ? NlsGetAnsiCodePage(_sRealName!) : IcuGetAnsiCodePage(_sRealName!); } return _iDefaultAnsiCodePage; } @@ -1850,7 +1861,7 @@ internal int OEMCodePage { if (_iDefaultOemCodePage == undef) { - _iDefaultOemCodePage = GetOemCodePage(_sRealName!); + _iDefaultOemCodePage = GlobalizationMode.UseNls ? NlsGetOemCodePage(_sRealName!) : IcuGetOemCodePage(_sRealName!); } return _iDefaultOemCodePage; } @@ -1865,7 +1876,7 @@ internal int MacCodePage { if (_iDefaultMacCodePage == undef) { - _iDefaultMacCodePage = GetMacCodePage(_sRealName!); + _iDefaultMacCodePage = GlobalizationMode.UseNls ? NlsGetMacCodePage(_sRealName!) : IcuGetMacCodePage(_sRealName!); } return _iDefaultMacCodePage; } @@ -1880,7 +1891,7 @@ internal int EBCDICCodePage { if (_iDefaultEbcdicCodePage == undef) { - _iDefaultEbcdicCodePage = GetEbcdicCodePage(_sRealName!); + _iDefaultEbcdicCodePage = GlobalizationMode.UseNls ? NlsGetEbcdicCodePage(_sRealName!) : IcuGetEbcdicCodePage(_sRealName!); } return _iDefaultEbcdicCodePage; } @@ -1893,7 +1904,7 @@ internal int LCID if (_iLanguage == 0) { Debug.Assert(_sRealName != null, "[CultureData.LCID] Expected this.sRealName to be populated already"); - _iLanguage = LocaleNameToLCID(_sRealName); + _iLanguage = GlobalizationMode.UseNls ? NlsLocaleNameToLCID(_sRealName) : IcuLocaleNameToLCID(_sRealName); } return _iLanguage; } @@ -1905,6 +1916,8 @@ internal int LCID internal bool IsInvariantCulture => string.IsNullOrEmpty(Name); + internal bool IsReplacementCulture => GlobalizationMode.UseNls ? NlsIsReplacementCulture : false; + /// /// Get an instance of our default calendar /// @@ -1917,7 +1930,7 @@ internal Calendar DefaultCalendar return CultureInfo.GetCalendarInstance(CalendarIds[0]); } - CalendarId defaultCalId = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType); + CalendarId defaultCalId = (CalendarId)GetLocaleInfoCore(LocaleNumberData.CalendarType); if (defaultCalId == 0) { @@ -1958,7 +1971,7 @@ internal string TimeSeparator { if (_sTimeSeparator == null) { - string? longTimeFormat = GetTimeFormatString(); + string? longTimeFormat = GlobalizationMode.UseNls ? NlsGetTimeFormatString() : IcuGetTimeFormatString(); if (string.IsNullOrEmpty(longTimeFormat)) { longTimeFormat = LongTimes[0]; @@ -2160,24 +2173,24 @@ internal void GetNFIValues(NumberFormatInfo nfi) { Debug.Assert(_sWindowsName != null, "[CultureData.GetNFIValues] Expected _sWindowsName to be populated by already"); // String values - nfi._positiveSign = GetLocaleInfo(LocaleStringData.PositiveSign); - nfi._negativeSign = GetLocaleInfo(LocaleStringData.NegativeSign); + nfi._positiveSign = GetLocaleInfoCore(LocaleStringData.PositiveSign); + nfi._negativeSign = GetLocaleInfoCore(LocaleStringData.NegativeSign); - nfi._numberDecimalSeparator = GetLocaleInfo(LocaleStringData.DecimalSeparator); - nfi._numberGroupSeparator = GetLocaleInfo(LocaleStringData.ThousandSeparator); - nfi._currencyGroupSeparator = GetLocaleInfo(LocaleStringData.MonetaryThousandSeparator); - nfi._currencyDecimalSeparator = GetLocaleInfo(LocaleStringData.MonetaryDecimalSeparator); - nfi._currencySymbol = GetLocaleInfo(LocaleStringData.MonetarySymbol); + nfi._numberDecimalSeparator = GetLocaleInfoCore(LocaleStringData.DecimalSeparator); + nfi._numberGroupSeparator = GetLocaleInfoCore(LocaleStringData.ThousandSeparator); + nfi._currencyGroupSeparator = GetLocaleInfoCore(LocaleStringData.MonetaryThousandSeparator); + nfi._currencyDecimalSeparator = GetLocaleInfoCore(LocaleStringData.MonetaryDecimalSeparator); + nfi._currencySymbol = GetLocaleInfoCore(LocaleStringData.MonetarySymbol); // Numeric values - nfi._numberDecimalDigits = GetLocaleInfo(LocaleNumberData.FractionalDigitsCount); - nfi._currencyDecimalDigits = GetLocaleInfo(LocaleNumberData.MonetaryFractionalDigitsCount); - nfi._currencyPositivePattern = GetLocaleInfo(LocaleNumberData.PositiveMonetaryNumberFormat); - nfi._currencyNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeMonetaryNumberFormat); - nfi._numberNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeNumberFormat); + nfi._numberDecimalDigits = GetLocaleInfoCore(LocaleNumberData.FractionalDigitsCount); + nfi._currencyDecimalDigits = GetLocaleInfoCore(LocaleNumberData.MonetaryFractionalDigitsCount); + nfi._currencyPositivePattern = GetLocaleInfoCore(LocaleNumberData.PositiveMonetaryNumberFormat); + nfi._currencyNegativePattern = GetLocaleInfoCore(LocaleNumberData.NegativeMonetaryNumberFormat); + nfi._numberNegativePattern = GetLocaleInfoCore(LocaleNumberData.NegativeNumberFormat); // LOCALE_SNATIVEDIGITS (array of 10 single character strings). - string digits = GetLocaleInfo(LocaleStringData.Digits); + string digits = GetLocaleInfoCore(LocaleStringData.Digits); nfi._nativeDigits = new string[10]; for (int i = 0; i < nfi._nativeDigits.Length; i++) { @@ -2185,7 +2198,7 @@ internal void GetNFIValues(NumberFormatInfo nfi) } Debug.Assert(_sRealName != null); - nfi._digitSubstitution = GetDigitSubstitution(_sRealName); + nfi._digitSubstitution = GlobalizationMode.UseNls ? NlsGetDigitSubstitution(_sRealName) : IcuGetDigitSubstitution(_sRealName); } // Gather additional data @@ -2230,6 +2243,22 @@ internal void GetNFIValues(NumberFormatInfo nfi) /// internal static string AnsiToLower(string testString) => TextInfo.ToLowerAsciiInvariant(testString); + private int GetLocaleInfoCore(LocaleNumberData type) => GlobalizationMode.UseNls ? + NlsGetLocaleInfo(type) : + IcuGetLocaleInfo(type); + + private string GetLocaleInfoCore(LocaleStringData type) => GlobalizationMode.UseNls ? + NlsGetLocaleInfo(type) : + IcuGetLocaleInfo(type); + + private string GetLocaleInfoCore(string localeName, LocaleStringData type) => GlobalizationMode.UseNls ? + NlsGetLocaleInfo(localeName, type) : + IcuGetLocaleInfo(localeName, type); + + private int[] GetLocaleInfoCore(LocaleGroupingData type) => GlobalizationMode.UseNls ? + NlsGetLocaleInfo(type) : + IcuGetLocaleInfo(type); + /// /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes. diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Icu.cs new file mode 100644 index 00000000000000..4d6c415e6189d8 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Icu.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +namespace System.Globalization +{ + public partial class CultureInfo : IFormatProvider + { + private static CultureInfo IcuGetPredefinedCultureInfo(string name) + { + Debug.Assert(!GlobalizationMode.UseNls); + + if (!Interop.Globalization.IsPredefinedLocale(name)) + { + throw new CultureNotFoundException(nameof(name), SR.Format(SR.Argument_InvalidPredefinedCultureName, name)); + } + + return GetCultureInfo(name); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Nls.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Nls.cs new file mode 100644 index 00000000000000..1cc13d71ef4a0b --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Nls.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +namespace System.Globalization +{ + public partial class CultureInfo : IFormatProvider + { + private static CultureInfo NlsGetPredefinedCultureInfo(string name) + { + Debug.Assert(GlobalizationMode.UseNls); + + CultureInfo culture = GetCultureInfo(name); + string englishName = culture.EnglishName; + + // Check if the English Name starts with "Unknown Locale" or "Unknown Language" terms. + const int SecondTermIndex = 8; + + if (englishName.StartsWith("Unknown ", StringComparison.Ordinal) && englishName.Length > SecondTermIndex && + (englishName.IndexOf("Locale", SecondTermIndex, StringComparison.Ordinal) == SecondTermIndex || + englishName.IndexOf("Language", SecondTermIndex, StringComparison.Ordinal) == SecondTermIndex)) + { + throw new CultureNotFoundException(nameof(name), SR.Format(SR.Argument_InvalidPredefinedCultureName, name)); + } + + return culture; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Unix.cs index da4c00af2f487d..a81b62e1c6b00c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Unix.cs @@ -14,8 +14,7 @@ internal static CultureInfo GetUserDefaultCulture() return CultureInfo.InvariantCulture; CultureInfo cultureInfo; - string? localeName; - if (CultureData.GetDefaultLocaleName(out localeName)) + if (CultureData.GetDefaultLocaleName(out string? localeName)) { Debug.Assert(localeName != null); cultureInfo = GetCultureByName(localeName); @@ -28,16 +27,6 @@ internal static CultureInfo GetUserDefaultCulture() return cultureInfo; } - private static CultureInfo GetPredefinedCultureInfo(string name) - { - if (!Interop.Globalization.IsPredefinedLocale(name)) - { - throw new CultureNotFoundException(nameof(name), SR.Format(SR.Argument_InvalidPredefinedCultureName, name)); - } - - return GetCultureInfo(name); - } - private static CultureInfo GetUserDefaultUICulture() { return InitializeUserDefaultCulture(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Windows.cs index dd4f34f58c2c25..99e093ac09d740 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.Windows.cs @@ -11,37 +11,12 @@ internal static CultureInfo GetUserDefaultCulture() if (GlobalizationMode.Invariant) return CultureInfo.InvariantCulture; - string? strDefault = CultureData.GetLocaleInfoEx(Interop.Kernel32.LOCALE_NAME_USER_DEFAULT, Interop.Kernel32.LOCALE_SNAME); - if (strDefault == null) - { - strDefault = CultureData.GetLocaleInfoEx(Interop.Kernel32.LOCALE_NAME_SYSTEM_DEFAULT, Interop.Kernel32.LOCALE_SNAME); - - if (strDefault == null) - { - // If system default doesn't work, use invariant - return CultureInfo.InvariantCulture; - } - } - - return GetCultureByName(strDefault); - } + string? strDefault = CultureData.GetLocaleInfoEx(Interop.Kernel32.LOCALE_NAME_USER_DEFAULT, Interop.Kernel32.LOCALE_SNAME) ?? + CultureData.GetLocaleInfoEx(Interop.Kernel32.LOCALE_NAME_SYSTEM_DEFAULT, Interop.Kernel32.LOCALE_SNAME); - private static CultureInfo GetPredefinedCultureInfo(string name) - { - CultureInfo culture = GetCultureInfo(name); - string englishName = culture.EnglishName; - - // Check if the English Name starts with "Unknown Locale" or "Unknown Language" terms. - const int SecondTermIndex = 8; - - if (englishName.StartsWith("Unknown ", StringComparison.Ordinal) && englishName.Length > SecondTermIndex && - (englishName.IndexOf("Locale", SecondTermIndex, StringComparison.Ordinal) == SecondTermIndex || - englishName.IndexOf("Language", SecondTermIndex, StringComparison.Ordinal) == SecondTermIndex)) - { - throw new CultureNotFoundException(nameof(name), SR.Format(SR.Argument_InvalidPredefinedCultureName, name)); - } - - return culture; + return strDefault != null ? + GetCultureByName(strDefault) : + CultureInfo.InvariantCulture; } private static unsafe CultureInfo GetUserDefaultUICulture() @@ -55,18 +30,12 @@ private static unsafe CultureInfo GetUserDefaultUICulture() if (Interop.Kernel32.GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &langCount, null, &bufLen) != Interop.BOOL.FALSE) { - char[] languages = new char[bufLen]; + Span languages = bufLen <= 256 ? stackalloc char[(int)bufLen] : new char[bufLen]; fixed (char* pLanguages = languages) { if (Interop.Kernel32.GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &langCount, pLanguages, &bufLen) != Interop.BOOL.FALSE) { - int index = 0; - while (languages[index] != (char)0 && index < languages.Length) - { - index++; - } - - return GetCultureByName(new string(languages, 0, index)); + return GetCultureByName(languages.ToString()); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.cs index e853316861459a..71011882bd9e3d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureInfo.cs @@ -1103,7 +1103,9 @@ public static CultureInfo GetCultureInfo(string name, string altName) } catch (ArgumentException) { +#pragma warning disable CA2208 // Instantiate argument exceptions correctly, combination of arguments used throw new CultureNotFoundException("name/altName", SR.Format(SR.Argument_OneOfCulturesNotSupported, name, altName)); +#pragma warning restore CA2208 } lock (nameTable) @@ -1123,7 +1125,9 @@ public static CultureInfo GetCultureInfo(string name, bool predefinedOnly) if (predefinedOnly) { - return GetPredefinedCultureInfo(name); + return GlobalizationMode.UseNls ? + NlsGetPredefinedCultureInfo(name) : + IcuGetPredefinedCultureInfo(name); } return GetCultureInfo(name); diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormatInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormatInfo.cs index 722c5839209639..f7a7c687966f8c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormatInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormatInfo.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace System.Globalization @@ -87,7 +88,7 @@ public sealed class DateTimeFormatInfo : IFormatProvider, ICloneable private const string sortableDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss"; private const string universalSortableDateTimePattern = "yyyy'-'MM'-'dd HH':'mm':'ss'Z'"; - private Calendar calendar = null!; // initialized in helper called by ctors + private Calendar calendar; private int firstDayOfWeek = -1; private int calendarWeekRule = -1; @@ -389,6 +390,7 @@ public Calendar Calendar Debug.Assert(calendar != null, "DateTimeFormatInfo.Calendar: calendar != null"); return calendar; } + [MemberNotNull(nameof(calendar))] set { if (IsReadOnly) @@ -732,14 +734,19 @@ public string LongDatePattern // Remember the new string longDatePattern = value; - // Clear the token hash table - ClearTokenHashTable(); - - // Clean up cached values that will be affected by this property. - fullDateTimePattern = null; + OnLongDatePatternChanged(); } } + private void OnLongDatePatternChanged() + { + // Clear the token hash table + ClearTokenHashTable(); + + // Clean up cached values that will be affected by this property. + fullDateTimePattern = null; + } + /// /// For our "patterns" arrays we have 2 variables, a string and a string[] /// @@ -764,16 +771,21 @@ public string LongTimePattern // Remember the new string longTimePattern = value; - // Clear the token hash table - ClearTokenHashTable(); - - // Clean up cached values that will be affected by this property. - fullDateTimePattern = null; // Full date = long date + long Time - generalLongTimePattern = null; // General long date = short date + long Time - dateTimeOffsetPattern = null; + OnLongTimePatternChanged(); } } + private void OnLongTimePatternChanged() + { + // Clear the token hash table + ClearTokenHashTable(); + + // Clean up cached values that will be affected by this property. + fullDateTimePattern = null; // Full date = long date + long Time + generalLongTimePattern = null; // General long date = short date + long Time + dateTimeOffsetPattern = null; + } + /// /// Just to be confusing there's only 1 month day pattern, not a whole list /// @@ -862,16 +874,21 @@ public string ShortDatePattern // Remember the new string shortDatePattern = value; - // Clear the token hash table, note that even short dates could require this - ClearTokenHashTable(); - - // Clean up cached values that will be affected by this property. - generalLongTimePattern = null; // General long time = short date + long time - generalShortTimePattern = null; // General short time = short date + short Time - dateTimeOffsetPattern = null; + OnShortDatePatternChanged(); } } + private void OnShortDatePatternChanged() + { + // Clear the token hash table, note that even short dates could require this + ClearTokenHashTable(); + + // Clean up cached values that will be affected by this property. + generalLongTimePattern = null; // General long time = short date + long time + generalShortTimePattern = null; // General short time = short date + short Time + dateTimeOffsetPattern = null; + } + /// /// For our "patterns" arrays we have 2 variables, a string and a string[] /// @@ -896,14 +913,19 @@ public string ShortTimePattern // Remember the new string shortTimePattern = value; - // Clear the token hash table, note that even short times could require this - ClearTokenHashTable(); - - // Clean up cached values that will be affected by this property. - generalShortTimePattern = null; // General short date = short date + short time. + OnShortTimePatternChanged(); } } + private void OnShortTimePatternChanged() + { + // Clear the token hash table, note that even short times could require this + ClearTokenHashTable(); + + // Clean up cached values that will be affected by this property. + generalShortTimePattern = null; // General short date = short date + short time. + } + public string SortableDateTimePattern => sortableDateTimePattern; /// @@ -1036,11 +1058,16 @@ public string YearMonthPattern // Remember the new string yearMonthPattern = value; - // Clear the token hash table, note that even short times could require this - ClearTokenHashTable(); + OnYearMonthPatternChanged(); } } + private void OnYearMonthPatternChanged() + { + // Clear the token hash table, note that even short times could require this + ClearTokenHashTable(); + } + /// /// Check if a string array contains a null value, and throw ArgumentNullException with parameter name "value" /// @@ -1682,7 +1709,7 @@ public void SetAllDateTimePatterns(string[] patterns, char format) { if (patterns[i] == null) { - throw new ArgumentNullException("patterns[" + i + "]", SR.ArgumentNull_ArrayValue); + throw new ArgumentNullException(nameof(patterns) + "[" + i + "]", SR.ArgumentNull_ArrayValue); } } @@ -1692,35 +1719,37 @@ public void SetAllDateTimePatterns(string[] patterns, char format) case 'd': allShortDatePatterns = patterns; shortDatePattern = allShortDatePatterns[0]; + OnShortDatePatternChanged(); break; case 'D': allLongDatePatterns = patterns; longDatePattern = allLongDatePatterns[0]; + OnLongDatePatternChanged(); break; case 't': allShortTimePatterns = patterns; shortTimePattern = allShortTimePatterns[0]; + OnShortTimePatternChanged(); break; case 'T': allLongTimePatterns = patterns; longTimePattern = allLongTimePatterns[0]; + OnLongTimePatternChanged(); break; case 'y': case 'Y': allYearMonthPatterns = patterns; yearMonthPattern = allYearMonthPatterns[0]; + OnYearMonthPatternChanged(); break; default: throw new ArgumentException(SR.Format(SR.Format_BadFormatSpecifier, format), nameof(format)); } - - // Clear the token hash table, note that even short dates could require this - ClearTokenHashTable(); } public string[] AbbreviatedMonthGenitiveNames diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs new file mode 100644 index 00000000000000..14c7699d1b7133 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs @@ -0,0 +1,57 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Globalization +{ + internal static partial class GlobalizationMode + { + // Order of these properties in Windows matter because GetUseIcuMode is dependent on Invariant. + // So we need Invariant to be initialized first. + internal static bool Invariant { get; } = GetGlobalizationInvariantMode(); + + internal static bool UseNls => false; + + private static bool GetGlobalizationInvariantMode() + { + bool invariantEnabled = GetInvariantSwitchValue(); + if (!invariantEnabled) + { + if (TryGetAppLocalIcuSwitchValue(out string? icuSuffixAndVersion)) + { + LoadAppLocalIcu(icuSuffixAndVersion, suffixWithSeparator: true); + } + else if (Interop.Globalization.LoadICU() == 0) + { + string message = "Couldn't find a valid ICU package installed on the system. " + + "Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support."; + Environment.FailFast(message); + } + } + return invariantEnabled; + } + + private static void LoadAppLocalIcuCore(ReadOnlySpan version, ReadOnlySpan suffix) + { + +#if TARGET_OSX + const string extension = ".dylib"; + bool versionAtEnd = false; +#else + string extension = version.Length > 0 ? "so." : "so"; + bool versionAtEnd = true; +#endif + +#if !TARGET_OSX + // In Linux we need to load libicudata first because libicuuc and libicui18n depend on it. In order for the loader to find + // it on the same path, we load it before loading the other two libraries. + LoadLibrary(CreateLibraryName("libicudata", suffix, extension, version, versionAtEnd), failOnLoadFailure: true); +#endif + + IntPtr icuucLib = LoadLibrary(CreateLibraryName("libicuuc", suffix, extension, version, versionAtEnd), failOnLoadFailure: true); + IntPtr icuinLib = LoadLibrary(CreateLibraryName("libicui18n", suffix, extension, version, versionAtEnd), failOnLoadFailure: true); + + Interop.Globalization.InitICUFunctions(icuucLib, icuinLib, version, suffix); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Windows.cs new file mode 100644 index 00000000000000..1fa21bc928b6d3 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Windows.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Globalization +{ + internal static partial class GlobalizationMode + { + // Order of these properties in Windows matter because GetUseIcuMode is dependent on Invariant. + // So we need Invariant to be initialized first. + internal static bool Invariant { get; } = GetInvariantSwitchValue(); + + internal static bool UseNls { get; } = !Invariant && + (GetSwitchValue("System.Globalization.UseNls", "DOTNET_SYSTEM_GLOBALIZATION_USENLS") || + !LoadIcu()); + + private static bool LoadIcu() + { + if (!TryGetAppLocalIcuSwitchValue(out string? icuSuffixAndVersion)) + { + return Interop.Globalization.LoadICU() != 0; + } + + LoadAppLocalIcu(icuSuffixAndVersion); + return true; + } + + private static void LoadAppLocalIcuCore(ReadOnlySpan version, ReadOnlySpan suffix) + { + const string extension = ".dll"; + const string icuucBase = "icuuc"; + const string icuinBase = "icuin"; + IntPtr icuucLib = IntPtr.Zero; + IntPtr icuinLib = IntPtr.Zero; + + int index = version.IndexOf('.'); + if (index > 0) + { + ReadOnlySpan truncatedVersion = version.Slice(0, index); + icuucLib = LoadLibrary(CreateLibraryName(icuucBase, suffix, extension, truncatedVersion), failOnLoadFailure: false); + + if (icuucLib != IntPtr.Zero) + { + icuinLib = LoadLibrary(CreateLibraryName(icuinBase, suffix, extension, truncatedVersion), failOnLoadFailure: false); + } + } + + if (icuucLib == IntPtr.Zero) + { + icuucLib = LoadLibrary(CreateLibraryName(icuucBase, suffix, extension, version), failOnLoadFailure: true); + } + + if (icuinLib == IntPtr.Zero) + { + icuinLib = LoadLibrary(CreateLibraryName(icuinBase, suffix, extension, version), failOnLoadFailure: true); + } + + Interop.Globalization.InitICUFunctions(icuucLib, icuinLib, version, suffix); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.cs new file mode 100644 index 00000000000000..79e85e85021826 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.cs @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace System.Globalization +{ + internal static partial class GlobalizationMode + { + private static bool GetInvariantSwitchValue() => + GetSwitchValue("System.Globalization.Invariant", "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT"); + + private static bool TryGetAppLocalIcuSwitchValue([NotNullWhen(true)] out string? value) => + TryGetStringValue("System.Globalization.AppLocalIcu", "DOTNET_SYSTEM_GLOBALIZATION_APPLOCALICU", out value); + + private static bool GetSwitchValue(string switchName, string envVariable) + { + if (!AppContext.TryGetSwitch(switchName, out bool ret)) + { + string? switchValue = Environment.GetEnvironmentVariable(envVariable); + if (switchValue != null) + { + ret = bool.IsTrueStringIgnoreCase(switchValue) || switchValue.Equals("1"); + } + } + + return ret; + } + + private static bool TryGetStringValue(string switchName, string envVariable, [NotNullWhen(true)] out string? value) + { + value = AppContext.GetData(switchName) as string; + if (string.IsNullOrEmpty(value)) + { + value = Environment.GetEnvironmentVariable(envVariable); + if (string.IsNullOrEmpty(value)) + { + return false; + } + } + + return true; + } + + private static void LoadAppLocalIcu(string icuSuffixAndVersion, bool suffixWithSeparator = false) + { + ReadOnlySpan version; + ReadOnlySpan icuSuffix = default; + + // Custom built ICU can have a suffix on the name, i.e: libicuucmyapp.so.67.1 + // So users would set the runtime switch as: myapp:67.1 + int indexOfSeparator = icuSuffixAndVersion.IndexOf(':'); + if (indexOfSeparator >= 0) + { + icuSuffix = icuSuffixAndVersion.AsSpan().Slice(0, indexOfSeparator); + version = icuSuffixAndVersion.AsSpan().Slice(icuSuffix.Length + 1); + } + else + { + version = icuSuffixAndVersion; + } + + if (suffixWithSeparator) + { + icuSuffix = string.Concat(icuSuffix, "."); + } + + LoadAppLocalIcuCore(version, icuSuffix); + } + + private static string CreateLibraryName(ReadOnlySpan baseName, ReadOnlySpan suffix, ReadOnlySpan extension, ReadOnlySpan version, bool versionAtEnd = false) => + versionAtEnd ? + string.Concat(baseName, suffix, extension, version) : + string.Concat(baseName, suffix, version, extension); + + private static IntPtr LoadLibrary(string library, bool failOnLoadFailure) + { + if (!NativeLibrary.TryLoad(library, typeof(object).Assembly, DllImportSearchPath.ApplicationDirectory, out IntPtr lib) && failOnLoadFailure) + { + Environment.FailFast($"Failed to load app-local ICU: {library}"); + } + + return lib; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/IcuLocaleData.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/IcuLocaleData.cs new file mode 100644 index 00000000000000..3750e755193722 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/IcuLocaleData.cs @@ -0,0 +1,4573 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +#pragma warning disable SA1001 + +// This file contains the handling of Windows OS specific culture features. + +namespace System.Globalization +{ + internal enum IcuLocaleDataParts + { + Lcid = 0, + AnsiCodePage = 1, + OemCodePage = 2, + MacCodePage = 3, + EbcdicCodePage = 4, + GeoId = 5, + DigitSubstitution = 6, + SpecificLocaleIndex = 7, + ConsoleLocaleIndex = 8 + } + + internal static class IcuLocaleData + { + // this is done rather than using a large readonly array of strings to avoid + // generating a large amount of code in the static constructor. + // Using indices from s_localeNamesIndices, we binary search this string when mapping + // an culture name to Lcid. Note that these names are all lowercase and are + // sorted alphabetically (ordinal). + private const string c_localeNames = + // culture name Lcid + "aa" + // 01000 - 0 + "aa-dj" + // 01000 - 2 + "aa-er" + // 01000 - 7 + "aa-et" + // 01000 - 12 + "af" + // 00036 - 17 + "af-na" + // 01000 - 19 + "af-za" + // 00436 - 24 + "agq" + // 01000 - 29 + "agq-cm" + // 01000 - 32 + "ak" + // 01000 - 38 + "ak-gh" + // 01000 - 40 + "am" + // 0005e - 45 + "am-et" + // 0045e - 47 + "ar" + // 00001 - 52 + "ar-001" + // 01000 - 54 + "ar-ae" + // 03801 - 60 + "ar-bh" + // 03c01 - 65 + "ar-dj" + // 01000 - 70 + "ar-dz" + // 01401 - 75 + "ar-eg" + // 00c01 - 80 + "ar-er" + // 01000 - 85 + "ar-il" + // 01000 - 90 + "ar-iq" + // 00801 - 95 + "ar-jo" + // 02c01 - 100 + "ar-km" + // 01000 - 105 + "ar-kw" + // 03401 - 110 + "ar-lb" + // 03001 - 115 + "ar-ly" + // 01001 - 120 + "ar-ma" + // 01801 - 125 + "ar-mr" + // 01000 - 130 + "ar-om" + // 02001 - 135 + "ar-ps" + // 01000 - 140 + "ar-qa" + // 04001 - 145 + "ar-sa" + // 00401 - 150 + "ar-sd" + // 01000 - 155 + "ar-so" + // 01000 - 160 + "ar-ss" + // 01000 - 165 + "ar-sy" + // 02801 - 170 + "ar-td" + // 01000 - 175 + "ar-tn" + // 01c01 - 180 + "ar-ye" + // 02401 - 185 + "arn" + // 0007a - 190 + "arn-cl" + // 0047a - 193 + "as" + // 0004d - 199 + "as-in" + // 0044d - 201 + "asa" + // 01000 - 206 + "asa-tz" + // 01000 - 209 + "ast" + // 01000 - 215 + "ast-es" + // 01000 - 218 + "az" + // 0002c - 224 + "az-cyrl" + // 0742c - 226 + "az-cyrl-az" + // 0082c - 233 + "az-latn" + // 0782c - 243 + "az-latn-az" + // 0042c - 250 + "ba" + // 0006d - 260 + "ba-ru" + // 0046d - 262 + "bas" + // 01000 - 267 + "bas-cm" + // 01000 - 270 + "be" + // 00023 - 276 + "be-by" + // 00423 - 278 + "bem" + // 01000 - 283 + "bem-zm" + // 01000 - 286 + "bez" + // 01000 - 292 + "bez-tz" + // 01000 - 295 + "bg" + // 00002 - 301 + "bg-bg" + // 00402 - 303 + "bin" + // 00066 - 308 + "bin-ng" + // 00466 - 311 + "bm" + // 01000 - 317 + "bm-latn" + // 01000 - 319 + "bm-latn-ml" + // 01000 - 326 + "bn" + // 00045 - 336 + "bn-bd" + // 00845 - 338 + "bn-in" + // 00445 - 343 + "bo" + // 00051 - 348 + "bo-cn" + // 00451 - 350 + "bo-in" + // 01000 - 355 + "br" + // 0007e - 360 + "br-fr" + // 0047e - 362 + "brx" + // 01000 - 367 + "brx-in" + // 01000 - 370 + "bs" + // 0781a - 376 + "bs-cyrl" + // 0641a - 378 + "bs-cyrl-ba" + // 0201a - 385 + "bs-latn" + // 0681a - 395 + "bs-latn-ba" + // 0141a - 402 + "byn" + // 01000 - 412 + "byn-er" + // 01000 - 415 + "ca" + // 00003 - 421 + "ca-ad" + // 01000 - 423 + "ca-es" + // 00403 - 428 + "ca-es-valencia" + // 00803 - 433 + "ca-fr" + // 01000 - 447 + "ca-it" + // 01000 - 452 + "ce" + // 01000 - 457 + "ce-ru" + // 01000 - 459 + "cgg" + // 01000 - 464 + "cgg-ug" + // 01000 - 467 + "chr" + // 0005c - 473 + "chr-cher" + // 07c5c - 476 + "chr-cher-us" + // 0045c - 484 + "co" + // 00083 - 495 + "co-fr" + // 00483 - 497 + "cs" + // 00005 - 502 + "cs-cz" + // 00405 - 504 + "cu" + // 01000 - 509 + "cu-ru" + // 01000 - 511 + "cy" + // 00052 - 516 + "cy-gb" + // 00452 - 518 + "da" + // 00006 - 523 + "da-dk" + // 00406 - 525 + "da-gl" + // 01000 - 530 + "dav" + // 01000 - 535 + "dav-ke" + // 01000 - 538 + "de" + // 00007 - 544 + "de-at" + // 00c07 - 546 + "de-be" + // 01000 - 551 + "de-ch" + // 00807 - 556 + "de-de" + // 00407 - 561 + "de-de_phoneb" + // 10407 - 566 + "de-it" + // 01000 - 578 + "de-li" + // 01407 - 583 + "de-lu" + // 01007 - 588 + "dje" + // 01000 - 593 + "dje-ne" + // 01000 - 596 + "dsb" + // 07c2e - 602 + "dsb-de" + // 0082e - 605 + "dua" + // 01000 - 611 + "dua-cm" + // 01000 - 614 + "dv" + // 00065 - 620 + "dv-mv" + // 00465 - 622 + "dyo" + // 01000 - 627 + "dyo-sn" + // 01000 - 630 + "dz" + // 01000 - 636 + "dz-bt" + // 00c51 - 638 + "ebu" + // 01000 - 643 + "ebu-ke" + // 01000 - 646 + "ee" + // 01000 - 652 + "ee-gh" + // 01000 - 654 + "ee-tg" + // 01000 - 659 + "el" + // 00008 - 664 + "el-cy" + // 01000 - 666 + "el-gr" + // 00408 - 671 + "en" + // 00009 - 676 + "en-001" + // 01000 - 678 + "en-029" + // 02409 - 684 + "en-150" + // 01000 - 690 + "en-ag" + // 01000 - 696 + "en-ai" + // 01000 - 701 + "en-as" + // 01000 - 706 + "en-at" + // 01000 - 711 + "en-au" + // 00c09 - 716 + "en-bb" + // 01000 - 721 + "en-be" + // 01000 - 726 + "en-bi" + // 01000 - 731 + "en-bm" + // 01000 - 736 + "en-bs" + // 01000 - 741 + "en-bw" + // 01000 - 746 + "en-bz" + // 02809 - 751 + "en-ca" + // 01009 - 756 + "en-cc" + // 01000 - 761 + "en-ch" + // 01000 - 766 + "en-ck" + // 01000 - 771 + "en-cm" + // 01000 - 776 + "en-cx" + // 01000 - 781 + "en-cy" + // 01000 - 786 + "en-de" + // 01000 - 791 + "en-dk" + // 01000 - 796 + "en-dm" + // 01000 - 801 + "en-er" + // 01000 - 806 + "en-fi" + // 01000 - 811 + "en-fj" + // 01000 - 816 + "en-fk" + // 01000 - 821 + "en-fm" + // 01000 - 826 + "en-gb" + // 00809 - 831 + "en-gd" + // 01000 - 836 + "en-gg" + // 01000 - 841 + "en-gh" + // 01000 - 846 + "en-gi" + // 01000 - 851 + "en-gm" + // 01000 - 856 + "en-gu" + // 01000 - 861 + "en-gy" + // 01000 - 866 + "en-hk" + // 03c09 - 871 + "en-id" + // 03809 - 876 + "en-ie" + // 01809 - 881 + "en-il" + // 01000 - 886 + "en-im" + // 01000 - 891 + "en-in" + // 04009 - 896 + "en-io" + // 01000 - 901 + "en-je" + // 01000 - 906 + "en-jm" + // 02009 - 911 + "en-ke" + // 01000 - 916 + "en-ki" + // 01000 - 921 + "en-kn" + // 01000 - 926 + "en-ky" + // 01000 - 931 + "en-lc" + // 01000 - 936 + "en-lr" + // 01000 - 941 + "en-ls" + // 01000 - 946 + "en-mg" + // 01000 - 951 + "en-mh" + // 01000 - 956 + "en-mo" + // 01000 - 961 + "en-mp" + // 01000 - 966 + "en-ms" + // 01000 - 971 + "en-mt" + // 01000 - 976 + "en-mu" + // 01000 - 981 + "en-mw" + // 01000 - 986 + "en-my" + // 04409 - 991 + "en-na" + // 01000 - 996 + "en-nf" + // 01000 - 1001 + "en-ng" + // 01000 - 1006 + "en-nl" + // 01000 - 1011 + "en-nr" + // 01000 - 1016 + "en-nu" + // 01000 - 1021 + "en-nz" + // 01409 - 1026 + "en-pg" + // 01000 - 1031 + "en-ph" + // 03409 - 1036 + "en-pk" + // 01000 - 1041 + "en-pn" + // 01000 - 1046 + "en-pr" + // 01000 - 1051 + "en-pw" + // 01000 - 1056 + "en-rw" + // 01000 - 1061 + "en-sb" + // 01000 - 1066 + "en-sc" + // 01000 - 1071 + "en-sd" + // 01000 - 1076 + "en-se" + // 01000 - 1081 + "en-sg" + // 04809 - 1086 + "en-sh" + // 01000 - 1091 + "en-si" + // 01000 - 1096 + "en-sl" + // 01000 - 1101 + "en-ss" + // 01000 - 1106 + "en-sx" + // 01000 - 1111 + "en-sz" + // 01000 - 1116 + "en-tc" + // 01000 - 1121 + "en-tk" + // 01000 - 1126 + "en-to" + // 01000 - 1131 + "en-tt" + // 02c09 - 1136 + "en-tv" + // 01000 - 1141 + "en-tz" + // 01000 - 1146 + "en-ug" + // 01000 - 1151 + "en-um" + // 01000 - 1156 + "en-us" + // 00409 - 1161 + "en-vc" + // 01000 - 1166 + "en-vg" + // 01000 - 1171 + "en-vi" + // 01000 - 1176 + "en-vu" + // 01000 - 1181 + "en-ws" + // 01000 - 1186 + "en-za" + // 01c09 - 1191 + "en-zm" + // 01000 - 1196 + "en-zw" + // 03009 - 1201 + "eo" + // 01000 - 1206 + "eo-001" + // 01000 - 1208 + "es" + // 0000a - 1214 + "es-419" + // 0580a - 1216 + "es-ar" + // 02c0a - 1222 + "es-bo" + // 0400a - 1227 + "es-br" + // 01000 - 1232 + "es-cl" + // 0340a - 1237 + "es-co" + // 0240a - 1242 + "es-cr" + // 0140a - 1247 + "es-cu" + // 05c0a - 1252 + "es-do" + // 01c0a - 1257 + "es-ec" + // 0300a - 1262 + "es-es" + // 00c0a - 1267 + "es-es_tradnl" + // 0040a - 1272 + "es-gq" + // 01000 - 1284 + "es-gt" + // 0100a - 1289 + "es-hn" + // 0480a - 1294 + "es-mx" + // 0080a - 1299 + "es-ni" + // 04c0a - 1304 + "es-pa" + // 0180a - 1309 + "es-pe" + // 0280a - 1314 + "es-ph" + // 01000 - 1319 + "es-pr" + // 0500a - 1324 + "es-py" + // 03c0a - 1329 + "es-sv" + // 0440a - 1334 + "es-us" + // 0540a - 1339 + "es-uy" + // 0380a - 1344 + "es-ve" + // 0200a - 1349 + "et" + // 00025 - 1354 + "et-ee" + // 00425 - 1356 + "eu" + // 0002d - 1361 + "eu-es" + // 0042d - 1363 + "ewo" + // 01000 - 1368 + "ewo-cm" + // 01000 - 1371 + "fa" + // 00029 - 1377 + "fa-ir" + // 00429 - 1379 + "ff" + // 00067 - 1384 + "ff-cm" + // 01000 - 1386 + "ff-gn" + // 01000 - 1391 + "ff-latn" + // 07c67 - 1396 + "ff-latn-sn" + // 00867 - 1403 + "ff-mr" + // 01000 - 1413 + "ff-ng" + // 00467 - 1418 + "fi" + // 0000b - 1423 + "fi-fi" + // 0040b - 1425 + "fil" + // 00064 - 1430 + "fil-ph" + // 00464 - 1433 + "fo" + // 00038 - 1439 + "fo-dk" + // 01000 - 1441 + "fo-fo" + // 00438 - 1446 + "fr" + // 0000c - 1451 + "fr-029" + // 01c0c - 1453 + "fr-be" + // 0080c - 1459 + "fr-bf" + // 01000 - 1464 + "fr-bi" + // 01000 - 1469 + "fr-bj" + // 01000 - 1474 + "fr-bl" + // 01000 - 1479 + "fr-ca" + // 00c0c - 1484 + "fr-cd" + // 0240c - 1489 + "fr-cf" + // 01000 - 1494 + "fr-cg" + // 01000 - 1499 + "fr-ch" + // 0100c - 1504 + "fr-ci" + // 0300c - 1509 + "fr-cm" + // 02c0c - 1514 + "fr-dj" + // 01000 - 1519 + "fr-dz" + // 01000 - 1524 + "fr-fr" + // 0040c - 1529 + "fr-ga" + // 01000 - 1534 + "fr-gf" + // 01000 - 1539 + "fr-gn" + // 01000 - 1544 + "fr-gp" + // 01000 - 1549 + "fr-gq" + // 01000 - 1554 + "fr-ht" + // 03c0c - 1559 + "fr-km" + // 01000 - 1564 + "fr-lu" + // 0140c - 1569 + "fr-ma" + // 0380c - 1574 + "fr-mc" + // 0180c - 1579 + "fr-mf" + // 01000 - 1584 + "fr-mg" + // 01000 - 1589 + "fr-ml" + // 0340c - 1594 + "fr-mq" + // 01000 - 1599 + "fr-mr" + // 01000 - 1604 + "fr-mu" + // 01000 - 1609 + "fr-nc" + // 01000 - 1614 + "fr-ne" + // 01000 - 1619 + "fr-pf" + // 01000 - 1624 + "fr-pm" + // 01000 - 1629 + "fr-re" + // 0200c - 1634 + "fr-rw" + // 01000 - 1639 + "fr-sc" + // 01000 - 1644 + "fr-sn" + // 0280c - 1649 + "fr-sy" + // 01000 - 1654 + "fr-td" + // 01000 - 1659 + "fr-tg" + // 01000 - 1664 + "fr-tn" + // 01000 - 1669 + "fr-vu" + // 01000 - 1674 + "fr-wf" + // 01000 - 1679 + "fr-yt" + // 01000 - 1684 + "fur" + // 01000 - 1689 + "fur-it" + // 01000 - 1692 + "fy" + // 00062 - 1698 + "fy-nl" + // 00462 - 1700 + "ga" + // 0003c - 1705 + "ga-ie" + // 0083c - 1707 + "gd" + // 00091 - 1712 + "gd-gb" + // 00491 - 1714 + "gl" + // 00056 - 1719 + "gl-es" + // 00456 - 1721 + "gn" + // 00074 - 1726 + "gn-py" + // 00474 - 1728 + "gsw" + // 00084 - 1733 + "gsw-ch" + // 01000 - 1736 + "gsw-fr" + // 00484 - 1742 + "gsw-li" + // 01000 - 1748 + "gu" + // 00047 - 1754 + "gu-in" + // 00447 - 1756 + "guz" + // 01000 - 1761 + "guz-ke" + // 01000 - 1764 + "gv" + // 01000 - 1770 + "gv-im" + // 01000 - 1772 + "ha" + // 00068 - 1777 + "ha-latn" + // 07c68 - 1779 + "ha-latn-gh" + // 01000 - 1786 + "ha-latn-ne" + // 01000 - 1796 + "ha-latn-ng" + // 00468 - 1806 + "haw" + // 00075 - 1816 + "haw-us" + // 00475 - 1819 + "he" + // 0000d - 1825 + "he-il" + // 0040d - 1827 + "hi" + // 00039 - 1832 + "hi-in" + // 00439 - 1834 + "hr" + // 0001a - 1839 + "hr-ba" + // 0101a - 1841 + "hr-hr" + // 0041a - 1846 + "hsb" + // 0002e - 1851 + "hsb-de" + // 0042e - 1854 + "hu" + // 0000e - 1860 + "hu-hu" + // 0040e - 1862 + "hu-hu_technl" + // 1040e - 1867 + "hy" + // 0002b - 1879 + "hy-am" + // 0042b - 1881 + "ia" + // 01000 - 1886 + "ia-001" + // 01000 - 1888 + "ia-fr" + // 01000 - 1894 + "ibb" + // 00069 - 1899 + "ibb-ng" + // 00469 - 1902 + "id" + // 00021 - 1908 + "id-id" + // 00421 - 1910 + "ig" + // 00070 - 1915 + "ig-ng" + // 00470 - 1917 + "ii" + // 00078 - 1922 + "ii-cn" + // 00478 - 1924 + "is" + // 0000f - 1929 + "is-is" + // 0040f - 1931 + "it" + // 00010 - 1936 + "it-ch" + // 00810 - 1938 + "it-it" + // 00410 - 1943 + "it-sm" + // 01000 - 1948 + "iu" + // 0005d - 1953 + "iu-cans" + // 0785d - 1955 + "iu-cans-ca" + // 0045d - 1962 + "iu-latn" + // 07c5d - 1972 + "iu-latn-ca" + // 0085d - 1979 + "ja" + // 00011 - 1989 + "ja-jp" + // 00411 - 1991 + "ja-jp_radstr" + // 40411 - 1996 + "jgo" + // 01000 - 2008 + "jgo-cm" + // 01000 - 2011 + "jmc" + // 01000 - 2017 + "jmc-tz" + // 01000 - 2020 + "jv" + // 01000 - 2026 + "jv-java" + // 01000 - 2028 + "jv-java-id" + // 01000 - 2035 + "jv-latn" + // 01000 - 2045 + "jv-latn-id" + // 01000 - 2052 + "ka" + // 00037 - 2062 + "ka-ge" + // 00437 - 2064 + "ka-ge_modern" + // 10437 - 2069 + "kab" + // 01000 - 2081 + "kab-dz" + // 01000 - 2084 + "kam" + // 01000 - 2090 + "kam-ke" + // 01000 - 2093 + "kde" + // 01000 - 2099 + "kde-tz" + // 01000 - 2102 + "kea" + // 01000 - 2108 + "kea-cv" + // 01000 - 2111 + "khq" + // 01000 - 2117 + "khq-ml" + // 01000 - 2120 + "ki" + // 01000 - 2126 + "ki-ke" + // 01000 - 2128 + "kk" + // 0003f - 2133 + "kk-kz" + // 0043f - 2135 + "kkj" + // 01000 - 2140 + "kkj-cm" + // 01000 - 2143 + "kl" + // 0006f - 2149 + "kl-gl" + // 0046f - 2151 + "kln" + // 01000 - 2156 + "kln-ke" + // 01000 - 2159 + "km" + // 00053 - 2165 + "km-kh" + // 00453 - 2167 + "kn" + // 0004b - 2172 + "kn-in" + // 0044b - 2174 + "ko" + // 00012 - 2179 + "ko-kp" + // 01000 - 2181 + "ko-kr" + // 00412 - 2186 + "kok" + // 00057 - 2191 + "kok-in" + // 00457 - 2194 + "kr" + // 00071 - 2200 + "kr-ng" + // 00471 - 2202 + "ks" + // 00060 - 2207 + "ks-arab" + // 00460 - 2209 + "ks-arab-in" + // 01000 - 2216 + "ks-deva" + // 01000 - 2226 + "ks-deva-in" + // 00860 - 2233 + "ksb" + // 01000 - 2243 + "ksb-tz" + // 01000 - 2246 + "ksf" + // 01000 - 2252 + "ksf-cm" + // 01000 - 2255 + "ksh" + // 01000 - 2261 + "ksh-de" + // 01000 - 2264 + "ku" + // 00092 - 2270 + "ku-arab" + // 07c92 - 2272 + "ku-arab-iq" + // 00492 - 2279 + "ku-arab-ir" + // 01000 - 2289 + "kw" + // 01000 - 2299 + "kw-gb" + // 01000 - 2301 + "ky" + // 00040 - 2306 + "ky-kg" + // 00440 - 2308 + "la" + // 00076 - 2313 + "la-001" + // 00476 - 2315 + "lag" + // 01000 - 2321 + "lag-tz" + // 01000 - 2324 + "lb" + // 0006e - 2330 + "lb-lu" + // 0046e - 2332 + "lg" + // 01000 - 2337 + "lg-ug" + // 01000 - 2339 + "lkt" + // 01000 - 2344 + "lkt-us" + // 01000 - 2347 + "ln" + // 01000 - 2353 + "ln-ao" + // 01000 - 2355 + "ln-cd" + // 01000 - 2360 + "ln-cf" + // 01000 - 2365 + "ln-cg" + // 01000 - 2370 + "lo" + // 00054 - 2375 + "lo-la" + // 00454 - 2377 + "lrc" + // 01000 - 2382 + "lrc-iq" + // 01000 - 2385 + "lrc-ir" + // 01000 - 2391 + "lt" + // 00027 - 2397 + "lt-lt" + // 00427 - 2399 + "lu" + // 01000 - 2404 + "lu-cd" + // 01000 - 2406 + "luo" + // 01000 - 2411 + "luo-ke" + // 01000 - 2414 + "luy" + // 01000 - 2420 + "luy-ke" + // 01000 - 2423 + "lv" + // 00026 - 2429 + "lv-lv" + // 00426 - 2431 + "mas" + // 01000 - 2436 + "mas-ke" + // 01000 - 2439 + "mas-tz" + // 01000 - 2445 + "mer" + // 01000 - 2451 + "mer-ke" + // 01000 - 2454 + "mfe" + // 01000 - 2460 + "mfe-mu" + // 01000 - 2463 + "mg" + // 01000 - 2469 + "mg-mg" + // 01000 - 2471 + "mgh" + // 01000 - 2476 + "mgh-mz" + // 01000 - 2479 + "mgo" + // 01000 - 2485 + "mgo-cm" + // 01000 - 2488 + "mi" + // 00081 - 2494 + "mi-nz" + // 00481 - 2496 + "mk" + // 0002f - 2501 + "mk-mk" + // 0042f - 2503 + "ml" + // 0004c - 2508 + "ml-in" + // 0044c - 2510 + "mn" + // 00050 - 2515 + "mn-cyrl" + // 07850 - 2517 + "mn-mn" + // 00450 - 2524 + "mn-mong" + // 07c50 - 2529 + "mn-mong-cn" + // 00850 - 2536 + "mn-mong-mn" + // 00c50 - 2546 + "mni" + // 00058 - 2556 + "mni-in" + // 00458 - 2559 + "moh" + // 0007c - 2565 + "moh-ca" + // 0047c - 2568 + "mr" + // 0004e - 2574 + "mr-in" + // 0044e - 2576 + "ms" + // 0003e - 2581 + "ms-bn" + // 0083e - 2583 + "ms-my" + // 0043e - 2588 + "ms-sg" + // 01000 - 2593 + "mt" + // 0003a - 2598 + "mt-mt" + // 0043a - 2600 + "mua" + // 01000 - 2605 + "mua-cm" + // 01000 - 2608 + "my" + // 00055 - 2614 + "my-mm" + // 00455 - 2616 + "mzn" + // 01000 - 2621 + "mzn-ir" + // 01000 - 2624 + "naq" + // 01000 - 2630 + "naq-na" + // 01000 - 2633 + "nb" + // 07c14 - 2639 + "nb-no" + // 00414 - 2641 + "nb-sj" + // 01000 - 2646 + "nd" + // 01000 - 2651 + "nd-zw" + // 01000 - 2653 + "nds" + // 01000 - 2658 + "nds-de" + // 01000 - 2661 + "nds-nl" + // 01000 - 2667 + "ne" + // 00061 - 2673 + "ne-in" + // 00861 - 2675 + "ne-np" + // 00461 - 2680 + "nl" + // 00013 - 2685 + "nl-aw" + // 01000 - 2687 + "nl-be" + // 00813 - 2692 + "nl-bq" + // 01000 - 2697 + "nl-cw" + // 01000 - 2702 + "nl-nl" + // 00413 - 2707 + "nl-sr" + // 01000 - 2712 + "nl-sx" + // 01000 - 2717 + "nmg" + // 01000 - 2722 + "nmg-cm" + // 01000 - 2725 + "nn" + // 07814 - 2731 + "nn-no" + // 00814 - 2733 + "nnh" + // 01000 - 2738 + "nnh-cm" + // 01000 - 2741 + "no" + // 00014 - 2747 + "nqo" + // 01000 - 2749 + "nqo-gn" + // 01000 - 2752 + "nr" + // 01000 - 2758 + "nr-za" + // 01000 - 2760 + "nso" + // 0006c - 2765 + "nso-za" + // 0046c - 2768 + "nus" + // 01000 - 2774 + "nus-ss" + // 01000 - 2777 + "nyn" + // 01000 - 2783 + "nyn-ug" + // 01000 - 2786 + "oc" + // 00082 - 2792 + "oc-fr" + // 00482 - 2794 + "om" + // 00072 - 2799 + "om-et" + // 00472 - 2801 + "om-ke" + // 01000 - 2806 + "or" + // 00048 - 2811 + "or-in" + // 00448 - 2813 + "os" + // 01000 - 2818 + "os-ge" + // 01000 - 2820 + "os-ru" + // 01000 - 2825 + "pa" + // 00046 - 2830 + "pa-arab" + // 07c46 - 2832 + "pa-arab-pk" + // 00846 - 2839 + "pa-in" + // 00446 - 2849 + "pap" + // 00079 - 2854 + "pap-029" + // 00479 - 2857 + "pl" + // 00015 - 2864 + "pl-pl" + // 00415 - 2866 + "prg" + // 01000 - 2871 + "prg-001" + // 01000 - 2874 + "prs" + // 0008c - 2881 + "prs-af" + // 0048c - 2884 + "ps" + // 00063 - 2890 + "ps-af" + // 00463 - 2892 + "pt" + // 00016 - 2897 + "pt-ao" + // 01000 - 2899 + "pt-br" + // 00416 - 2904 + "pt-ch" + // 01000 - 2909 + "pt-cv" + // 01000 - 2914 + "pt-gq" + // 01000 - 2919 + "pt-gw" + // 01000 - 2924 + "pt-lu" + // 01000 - 2929 + "pt-mo" + // 01000 - 2934 + "pt-mz" + // 01000 - 2939 + "pt-pt" + // 00816 - 2944 + "pt-st" + // 01000 - 2949 + "pt-tl" + // 01000 - 2954 + "qps-latn-x-sh" + // 00901 - 2959 + "qps-ploc" + // 00501 - 2972 + "qps-ploca" + // 005fe - 2980 + "qps-plocm" + // 009ff - 2989 + "quc" + // 00086 - 2998 + "quc-latn" + // 07c86 - 3001 + "quc-latn-gt" + // 00486 - 3009 + "quz" + // 0006b - 3020 + "quz-bo" + // 0046b - 3023 + "quz-ec" + // 0086b - 3029 + "quz-pe" + // 00c6b - 3035 + "rm" + // 00017 - 3041 + "rm-ch" + // 00417 - 3043 + "rn" + // 01000 - 3048 + "rn-bi" + // 01000 - 3050 + "ro" + // 00018 - 3055 + "ro-md" + // 00818 - 3057 + "ro-ro" + // 00418 - 3062 + "rof" + // 01000 - 3067 + "rof-tz" + // 01000 - 3070 + "ru" + // 00019 - 3076 + "ru-by" + // 01000 - 3078 + "ru-kg" + // 01000 - 3083 + "ru-kz" + // 01000 - 3088 + "ru-md" + // 00819 - 3093 + "ru-ru" + // 00419 - 3098 + "ru-ua" + // 01000 - 3103 + "rw" + // 00087 - 3108 + "rw-rw" + // 00487 - 3110 + "rwk" + // 01000 - 3115 + "rwk-tz" + // 01000 - 3118 + "sa" + // 0004f - 3124 + "sa-in" + // 0044f - 3126 + "sah" + // 00085 - 3131 + "sah-ru" + // 00485 - 3134 + "saq" + // 01000 - 3140 + "saq-ke" + // 01000 - 3143 + "sbp" + // 01000 - 3149 + "sbp-tz" + // 01000 - 3152 + "sd" + // 00059 - 3158 + "sd-arab" + // 07c59 - 3160 + "sd-arab-pk" + // 00859 - 3167 + "sd-deva" + // 01000 - 3177 + "sd-deva-in" + // 00459 - 3184 + "se" + // 0003b - 3194 + "se-fi" + // 00c3b - 3196 + "se-no" + // 0043b - 3201 + "se-se" + // 0083b - 3206 + "seh" + // 01000 - 3211 + "seh-mz" + // 01000 - 3214 + "ses" + // 01000 - 3220 + "ses-ml" + // 01000 - 3223 + "sg" + // 01000 - 3229 + "sg-cf" + // 01000 - 3231 + "shi" + // 01000 - 3236 + "shi-latn" + // 01000 - 3239 + "shi-latn-ma" + // 01000 - 3247 + "shi-tfng" + // 01000 - 3258 + "shi-tfng-ma" + // 01000 - 3266 + "si" + // 0005b - 3277 + "si-lk" + // 0045b - 3279 + "sk" + // 0001b - 3284 + "sk-sk" + // 0041b - 3286 + "sl" + // 00024 - 3291 + "sl-si" + // 00424 - 3293 + "sma" + // 0783b - 3298 + "sma-no" + // 0183b - 3301 + "sma-se" + // 01c3b - 3307 + "smj" + // 07c3b - 3313 + "smj-no" + // 0103b - 3316 + "smj-se" + // 0143b - 3322 + "smn" + // 0703b - 3328 + "smn-fi" + // 0243b - 3331 + "sms" + // 0743b - 3337 + "sms-fi" + // 0203b - 3340 + "sn" + // 01000 - 3346 + "sn-latn" + // 01000 - 3348 + "sn-latn-zw" + // 01000 - 3355 + "so" + // 00077 - 3365 + "so-dj" + // 01000 - 3367 + "so-et" + // 01000 - 3372 + "so-ke" + // 01000 - 3377 + "so-so" + // 00477 - 3382 + "sq" + // 0001c - 3387 + "sq-al" + // 0041c - 3389 + "sq-mk" + // 01000 - 3394 + "sq-xk" + // 01000 - 3399 + "sr" + // 07c1a - 3404 + "sr-cyrl" + // 06c1a - 3406 + "sr-cyrl-ba" + // 01c1a - 3413 + "sr-cyrl-cs" + // 00c1a - 3423 + "sr-cyrl-me" + // 0301a - 3433 + "sr-cyrl-rs" + // 0281a - 3443 + "sr-cyrl-xk" + // 01000 - 3453 + "sr-latn" + // 0701a - 3463 + "sr-latn-ba" + // 0181a - 3470 + "sr-latn-cs" + // 0081a - 3480 + "sr-latn-me" + // 02c1a - 3490 + "sr-latn-rs" + // 0241a - 3500 + "sr-latn-xk" + // 01000 - 3510 + "ss" + // 01000 - 3520 + "ss-sz" + // 01000 - 3522 + "ss-za" + // 01000 - 3527 + "ssy" + // 01000 - 3532 + "ssy-er" + // 01000 - 3535 + "st" + // 00030 - 3541 + "st-ls" + // 01000 - 3543 + "st-za" + // 00430 - 3548 + "sv" + // 0001d - 3553 + "sv-ax" + // 01000 - 3555 + "sv-fi" + // 0081d - 3560 + "sv-se" + // 0041d - 3565 + "sw" + // 00041 - 3570 + "sw-cd" + // 01000 - 3572 + "sw-ke" + // 00441 - 3577 + "sw-tz" + // 01000 - 3582 + "sw-ug" + // 01000 - 3587 + "swc" + // 01000 - 3592 + "swc-cd" + // 01000 - 3595 + "syr" + // 0005a - 3601 + "syr-sy" + // 0045a - 3604 + "ta" + // 00049 - 3610 + "ta-in" + // 00449 - 3612 + "ta-lk" + // 00849 - 3617 + "ta-my" + // 01000 - 3622 + "ta-sg" + // 01000 - 3627 + "te" + // 0004a - 3632 + "te-in" + // 0044a - 3634 + "teo" + // 01000 - 3639 + "teo-ke" + // 01000 - 3642 + "teo-ug" + // 01000 - 3648 + "tg" + // 00028 - 3654 + "tg-cyrl" + // 07c28 - 3656 + "tg-cyrl-tj" + // 00428 - 3663 + "th" + // 0001e - 3673 + "th-th" + // 0041e - 3675 + "ti" + // 00073 - 3680 + "ti-er" + // 00873 - 3682 + "ti-et" + // 00473 - 3687 + "tig" + // 01000 - 3692 + "tig-er" + // 01000 - 3695 + "tk" + // 00042 - 3701 + "tk-tm" + // 00442 - 3703 + "tn" + // 00032 - 3708 + "tn-bw" + // 00832 - 3710 + "tn-za" + // 00432 - 3715 + "to" + // 01000 - 3720 + "to-to" + // 01000 - 3722 + "tr" + // 0001f - 3727 + "tr-cy" + // 01000 - 3729 + "tr-tr" + // 0041f - 3734 + "ts" + // 00031 - 3739 + "ts-za" + // 00431 - 3741 + "tt" + // 00044 - 3746 + "tt-ru" + // 00444 - 3748 + "twq" + // 01000 - 3753 + "twq-ne" + // 01000 - 3756 + "tzm" + // 0005f - 3762 + "tzm-arab" + // 01000 - 3765 + "tzm-arab-ma" + // 0045f - 3773 + "tzm-latn" + // 07c5f - 3784 + "tzm-latn-dz" + // 0085f - 3792 + "tzm-latn-ma" + // 01000 - 3803 + "tzm-tfng" + // 0785f - 3814 + "tzm-tfng-ma" + // 0105f - 3822 + "ug" + // 00080 - 3833 + "ug-cn" + // 00480 - 3835 + "uk" + // 00022 - 3840 + "uk-ua" + // 00422 - 3842 + "ur" + // 00020 - 3847 + "ur-in" + // 00820 - 3849 + "ur-pk" + // 00420 - 3854 + "uz" + // 00043 - 3859 + "uz-arab" + // 01000 - 3861 + "uz-arab-af" + // 01000 - 3868 + "uz-cyrl" + // 07843 - 3878 + "uz-cyrl-uz" + // 00843 - 3885 + "uz-latn" + // 07c43 - 3895 + "uz-latn-uz" + // 00443 - 3902 + "vai" + // 01000 - 3912 + "vai-latn" + // 01000 - 3915 + "vai-latn-lr" + // 01000 - 3923 + "vai-vaii" + // 01000 - 3934 + "vai-vaii-lr" + // 01000 - 3942 + "ve" + // 00033 - 3953 + "ve-za" + // 00433 - 3955 + "vi" + // 0002a - 3960 + "vi-vn" + // 0042a - 3962 + "vo" + // 01000 - 3967 + "vo-001" + // 01000 - 3969 + "vun" + // 01000 - 3975 + "vun-tz" + // 01000 - 3978 + "wae" + // 01000 - 3984 + "wae-ch" + // 01000 - 3987 + "wal" + // 01000 - 3993 + "wal-et" + // 01000 - 3996 + "wo" + // 00088 - 4002 + "wo-sn" + // 00488 - 4004 + "x-iv_mathan" + // 1007f - 4009 + "xh" + // 00034 - 4020 + "xh-za" + // 00434 - 4022 + "xog" + // 01000 - 4027 + "xog-ug" + // 01000 - 4030 + "yav" + // 01000 - 4036 + "yav-cm" + // 01000 - 4039 + "yi" + // 0003d - 4045 + "yi-001" + // 0043d - 4047 + "yo" + // 0006a - 4053 + "yo-bj" + // 01000 - 4055 + "yo-ng" + // 0046a - 4060 + "yue" + // 01000 - 4065 + "yue-hk" + // 01000 - 4068 + "zgh" + // 01000 - 4074 + "zgh-tfng" + // 01000 - 4077 + "zgh-tfng-ma" + // 01000 - 4085 + "zh" + // 07804 - 4096 + "zh-chs" + // 00004 - 4098 + "zh-cht" + // 07c04 - 4104 + "zh-cn" + // 00804 - 4110 + "zh-cn_phoneb" + // 50804 - 4115 + "zh-cn_stroke" + // 20804 - 4127 + "zh-hans" + // 00004 - 4139 + "zh-hans-hk" + // 01000 - 4146 + "zh-hans-mo" + // 01000 - 4156 + "zh-hant" + // 07c04 - 4166 + "zh-hk" + // 00c04 - 4173 + "zh-hk_radstr" + // 40c04 - 4178 + "zh-mo" + // 01404 - 4190 + "zh-mo_radstr" + // 41404 - 4195 + "zh-mo_stroke" + // 21404 - 4207 + "zh-sg" + // 01004 - 4219 + "zh-sg_phoneb" + // 51004 - 4224 + "zh-sg_stroke" + // 21004 - 4236 + "zh-tw" + // 00404 - 4248 + "zh-tw_pronun" + // 30404 - 4253 + "zh-tw_radstr" + // 40404 - 4265 + "zu" + // 00035 - 4277 + "zu-za"; // 00435 - 4279 + + // c_threeLetterWindowsLanguageName is string containing 3-letter Windows language names + // every 3-characters entry is matching locale name entry in c_localeNames + + private const string c_threeLetterWindowsLanguageName = + "ZZZ" + // aa + "ZZZ" + // aa-dj + "ZZZ" + // aa-er + "ZZZ" + // aa-et + "AFK" + // af + "ZZZ" + // af-na + "AFK" + // af-za + "ZZZ" + // agq + "ZZZ" + // agq-cm + "ZZZ" + // ak + "ZZZ" + // ak-gh + "AMH" + // am + "AMH" + // am-et + "ARA" + // ar + "ZZZ" + // ar-001 + "ARU" + // ar-ae + "ARH" + // ar-bh + "ZZZ" + // ar-dj + "ARG" + // ar-dz + "ARE" + // ar-eg + "ZZZ" + // ar-er + "ZZZ" + // ar-il + "ARI" + // ar-iq + "ARJ" + // ar-jo + "ZZZ" + // ar-km + "ARK" + // ar-kw + "ARB" + // ar-lb + "ARL" + // ar-ly + "ARM" + // ar-ma + "ZZZ" + // ar-mr + "ARO" + // ar-om + "ZZZ" + // ar-ps + "ARQ" + // ar-qa + "ARA" + // ar-sa + "ZZZ" + // ar-sd + "ZZZ" + // ar-so + "ZZZ" + // ar-ss + "ARS" + // ar-sy + "ZZZ" + // ar-td + "ART" + // ar-tn + "ARY" + // ar-ye + "MPD" + // arn + "MPD" + // arn-cl + "ASM" + // as + "ASM" + // as-in + "ZZZ" + // asa + "ZZZ" + // asa-tz + "ZZZ" + // ast + "ZZZ" + // ast-es + "AZE" + // az + "AZC" + // az-cyrl + "AZC" + // az-cyrl-az + "AZE" + // az-latn + "AZE" + // az-latn-az + "BAS" + // ba + "BAS" + // ba-ru + "ZZZ" + // bas + "ZZZ" + // bas-cm + "BEL" + // be + "BEL" + // be-by + "ZZZ" + // bem + "ZZZ" + // bem-zm + "ZZZ" + // bez + "ZZZ" + // bez-tz + "BGR" + // bg + "BGR" + // bg-bg + "ZZZ" + // bin + "ZZZ" + // bin-ng + "ZZZ" + // bm + "ZZZ" + // bm-latn + "ZZZ" + // bm-latn-ml + "BNB" + // bn + "BNB" + // bn-bd + "BNG" + // bn-in + "BOB" + // bo + "BOB" + // bo-cn + "ZZZ" + // bo-in + "BRE" + // br + "BRE" + // br-fr + "ZZZ" + // brx + "ZZZ" + // brx-in + "BSB" + // bs + "BSC" + // bs-cyrl + "BSC" + // bs-cyrl-ba + "BSB" + // bs-latn + "BSB" + // bs-latn-ba + "ZZZ" + // byn + "ZZZ" + // byn-er + "CAT" + // ca + "ZZZ" + // ca-ad + "CAT" + // ca-es + "VAL" + // ca-es-valencia + "ZZZ" + // ca-fr + "ZZZ" + // ca-it + "ZZZ" + // ce + "ZZZ" + // ce-ru + "ZZZ" + // cgg + "ZZZ" + // cgg-ug + "CRE" + // chr + "CRE" + // chr-cher + "CRE" + // chr-cher-us + "COS" + // co + "COS" + // co-fr + "CSY" + // cs + "CSY" + // cs-cz + "ZZZ" + // cu + "ZZZ" + // cu-ru + "CYM" + // cy + "CYM" + // cy-gb + "DAN" + // da + "DAN" + // da-dk + "ZZZ" + // da-gl + "ZZZ" + // dav + "ZZZ" + // dav-ke + "DEU" + // de + "DEA" + // de-at + "ZZZ" + // de-be + "DES" + // de-ch + "DEU" + // de-de + "DEU" + // de-de_phoneb + "ZZZ" + // de-it + "DEC" + // de-li + "DEL" + // de-lu + "ZZZ" + // dje + "ZZZ" + // dje-ne + "DSB" + // dsb + "DSB" + // dsb-de + "ZZZ" + // dua + "ZZZ" + // dua-cm + "DIV" + // dv + "DIV" + // dv-mv + "ZZZ" + // dyo + "ZZZ" + // dyo-sn + "ZZZ" + // dz + "ZZZ" + // dz-bt + "ZZZ" + // ebu + "ZZZ" + // ebu-ke + "ZZZ" + // ee + "ZZZ" + // ee-gh + "ZZZ" + // ee-tg + "ELL" + // el + "ZZZ" + // el-cy + "ELL" + // el-gr + "ENU" + // en + "ZZZ" + // en-001 + "ENB" + // en-029 + "ZZZ" + // en-150 + "ZZZ" + // en-ag + "ZZZ" + // en-ai + "ZZZ" + // en-as + "ZZZ" + // en-at + "ENA" + // en-au + "ZZZ" + // en-bb + "ZZZ" + // en-be + "ZZZ" + // en-bi + "ZZZ" + // en-bm + "ZZZ" + // en-bs + "ZZZ" + // en-bw + "ENL" + // en-bz + "ENC" + // en-ca + "ZZZ" + // en-cc + "ZZZ" + // en-ch + "ZZZ" + // en-ck + "ZZZ" + // en-cm + "ZZZ" + // en-cx + "ZZZ" + // en-cy + "ZZZ" + // en-de + "ZZZ" + // en-dk + "ZZZ" + // en-dm + "ZZZ" + // en-er + "ZZZ" + // en-fi + "ZZZ" + // en-fj + "ZZZ" + // en-fk + "ZZZ" + // en-fm + "ENG" + // en-gb + "ZZZ" + // en-gd + "ZZZ" + // en-gg + "ZZZ" + // en-gh + "ZZZ" + // en-gi + "ZZZ" + // en-gm + "ZZZ" + // en-gu + "ZZZ" + // en-gy + "ENH" + // en-hk + "ZZZ" + // en-id + "ENI" + // en-ie + "ZZZ" + // en-il + "ZZZ" + // en-im + "ENN" + // en-in + "ZZZ" + // en-io + "ZZZ" + // en-je + "ENJ" + // en-jm + "ZZZ" + // en-ke + "ZZZ" + // en-ki + "ZZZ" + // en-kn + "ZZZ" + // en-ky + "ZZZ" + // en-lc + "ZZZ" + // en-lr + "ZZZ" + // en-ls + "ZZZ" + // en-mg + "ZZZ" + // en-mh + "ZZZ" + // en-mo + "ZZZ" + // en-mp + "ZZZ" + // en-ms + "ZZZ" + // en-mt + "ZZZ" + // en-mu + "ZZZ" + // en-mw + "ENM" + // en-my + "ZZZ" + // en-na + "ZZZ" + // en-nf + "ZZZ" + // en-ng + "ZZZ" + // en-nl + "ZZZ" + // en-nr + "ZZZ" + // en-nu + "ENZ" + // en-nz + "ZZZ" + // en-pg + "ENP" + // en-ph + "ZZZ" + // en-pk + "ZZZ" + // en-pn + "ZZZ" + // en-pr + "ZZZ" + // en-pw + "ZZZ" + // en-rw + "ZZZ" + // en-sb + "ZZZ" + // en-sc + "ZZZ" + // en-sd + "ZZZ" + // en-se + "ENE" + // en-sg + "ZZZ" + // en-sh + "ZZZ" + // en-si + "ZZZ" + // en-sl + "ZZZ" + // en-ss + "ZZZ" + // en-sx + "ZZZ" + // en-sz + "ZZZ" + // en-tc + "ZZZ" + // en-tk + "ZZZ" + // en-to + "ENT" + // en-tt + "ZZZ" + // en-tv + "ZZZ" + // en-tz + "ZZZ" + // en-ug + "ZZZ" + // en-um + "ENU" + // en-us + "ZZZ" + // en-vc + "ZZZ" + // en-vg + "ZZZ" + // en-vi + "ZZZ" + // en-vu + "ZZZ" + // en-ws + "ENS" + // en-za + "ZZZ" + // en-zm + "ENW" + // en-zw + "ZZZ" + // eo + "ZZZ" + // eo-001 + "ESN" + // es + "ESJ" + // es-419 + "ESS" + // es-ar + "ESB" + // es-bo + "ZZZ" + // es-br + "ESL" + // es-cl + "ESO" + // es-co + "ESC" + // es-cr + "ESK" + // es-cu + "ESD" + // es-do + "ESF" + // es-ec + "ESN" + // es-es + "ESP" + // es-es_tradnl + "ZZZ" + // es-gq + "ESG" + // es-gt + "ESH" + // es-hn + "ESM" + // es-mx + "ESI" + // es-ni + "ESA" + // es-pa + "ESR" + // es-pe + "ZZZ" + // es-ph + "ESU" + // es-pr + "ESZ" + // es-py + "ESE" + // es-sv + "EST" + // es-us + "ESY" + // es-uy + "ESV" + // es-ve + "ETI" + // et + "ETI" + // et-ee + "EUQ" + // eu + "EUQ" + // eu-es + "ZZZ" + // ewo + "ZZZ" + // ewo-cm + "FAR" + // fa + "FAR" + // fa-ir + "FUL" + // ff + "ZZZ" + // ff-cm + "ZZZ" + // ff-gn + "FUL" + // ff-latn + "FUL" + // ff-latn-sn + "ZZZ" + // ff-mr + "ZZZ" + // ff-ng + "FIN" + // fi + "FIN" + // fi-fi + "FPO" + // fil + "FPO" + // fil-ph + "FOS" + // fo + "ZZZ" + // fo-dk + "FOS" + // fo-fo + "FRA" + // fr + "ZZZ" + // fr-029 + "FRB" + // fr-be + "ZZZ" + // fr-bf + "ZZZ" + // fr-bi + "ZZZ" + // fr-bj + "ZZZ" + // fr-bl + "FRC" + // fr-ca + "FRD" + // fr-cd + "ZZZ" + // fr-cf + "ZZZ" + // fr-cg + "FRS" + // fr-ch + "FRI" + // fr-ci + "FRE" + // fr-cm + "ZZZ" + // fr-dj + "ZZZ" + // fr-dz + "FRA" + // fr-fr + "ZZZ" + // fr-ga + "ZZZ" + // fr-gf + "ZZZ" + // fr-gn + "ZZZ" + // fr-gp + "ZZZ" + // fr-gq + "FRH" + // fr-ht + "ZZZ" + // fr-km + "FRL" + // fr-lu + "FRO" + // fr-ma + "FRM" + // fr-mc + "ZZZ" + // fr-mf + "ZZZ" + // fr-mg + "FRF" + // fr-ml + "ZZZ" + // fr-mq + "ZZZ" + // fr-mr + "ZZZ" + // fr-mu + "ZZZ" + // fr-nc + "ZZZ" + // fr-ne + "ZZZ" + // fr-pf + "ZZZ" + // fr-pm + "FRR" + // fr-re + "ZZZ" + // fr-rw + "ZZZ" + // fr-sc + "FRN" + // fr-sn + "ZZZ" + // fr-sy + "ZZZ" + // fr-td + "ZZZ" + // fr-tg + "ZZZ" + // fr-tn + "ZZZ" + // fr-vu + "ZZZ" + // fr-wf + "ZZZ" + // fr-yt + "ZZZ" + // fur + "ZZZ" + // fur-it + "FYN" + // fy + "FYN" + // fy-nl + "IRE" + // ga + "IRE" + // ga-ie + "GLA" + // gd + "GLA" + // gd-gb + "GLC" + // gl + "GLC" + // gl-es + "GRN" + // gn + "GRN" + // gn-py + "ZZZ" + // gsw + "ZZZ" + // gsw-ch + "GSW" + // gsw-fr + "ZZZ" + // gsw-li + "GUJ" + // gu + "GUJ" + // gu-in + "ZZZ" + // guz + "ZZZ" + // guz-ke + "ZZZ" + // gv + "ZZZ" + // gv-im + "HAU" + // ha + "HAU" + // ha-latn + "ZZZ" + // ha-latn-gh + "ZZZ" + // ha-latn-ne + "HAU" + // ha-latn-ng + "HAW" + // haw + "HAW" + // haw-us + "HEB" + // he + "HEB" + // he-il + "HIN" + // hi + "HIN" + // hi-in + "HRV" + // hr + "HRB" + // hr-ba + "HRV" + // hr-hr + "HSB" + // hsb + "HSB" + // hsb-de + "HUN" + // hu + "HUN" + // hu-hu + "HUN" + // hu-hu_technl + "HYE" + // hy + "HYE" + // hy-am + "ZZZ" + // ia + "ZZZ" + // ia-001 + "ZZZ" + // ia-fr + "ZZZ" + // ibb + "ZZZ" + // ibb-ng + "IND" + // id + "IND" + // id-id + "IBO" + // ig + "IBO" + // ig-ng + "III" + // ii + "III" + // ii-cn + "ISL" + // is + "ISL" + // is-is + "ITA" + // it + "ITS" + // it-ch + "ITA" + // it-it + "ZZZ" + // it-sm + "IUK" + // iu + "IUS" + // iu-cans + "IUS" + // iu-cans-ca + "IUK" + // iu-latn + "IUK" + // iu-latn-ca + "JPN" + // ja + "JPN" + // ja-jp + "JPN" + // ja-jp_radstr + "ZZZ" + // jgo + "ZZZ" + // jgo-cm + "ZZZ" + // jmc + "ZZZ" + // jmc-tz + "JAV" + // jv + "ZZZ" + // jv-java + "ZZZ" + // jv-java-id + "JAV" + // jv-latn + "JAV" + // jv-latn-id + "KAT" + // ka + "KAT" + // ka-ge + "KAT" + // ka-ge_modern + "ZZZ" + // kab + "ZZZ" + // kab-dz + "ZZZ" + // kam + "ZZZ" + // kam-ke + "ZZZ" + // kde + "ZZZ" + // kde-tz + "ZZZ" + // kea + "ZZZ" + // kea-cv + "ZZZ" + // khq + "ZZZ" + // khq-ml + "ZZZ" + // ki + "ZZZ" + // ki-ke + "KKZ" + // kk + "KKZ" + // kk-kz + "ZZZ" + // kkj + "ZZZ" + // kkj-cm + "KAL" + // kl + "KAL" + // kl-gl + "ZZZ" + // kln + "ZZZ" + // kln-ke + "KHM" + // km + "KHM" + // km-kh + "KDI" + // kn + "KDI" + // kn-in + "KOR" + // ko + "ZZZ" + // ko-kp + "KOR" + // ko-kr + "KNK" + // kok + "KNK" + // kok-in + "ZZZ" + // kr + "ZZZ" + // kr-ng + "ZZZ" + // ks + "ZZZ" + // ks-arab + "ZZZ" + // ks-arab-in + "ZZZ" + // ks-deva + "ZZZ" + // ks-deva-in + "ZZZ" + // ksb + "ZZZ" + // ksb-tz + "ZZZ" + // ksf + "ZZZ" + // ksf-cm + "ZZZ" + // ksh + "ZZZ" + // ksh-de + "KUR" + // ku + "KUR" + // ku-arab + "KUR" + // ku-arab-iq + "ZZZ" + // ku-arab-ir + "ZZZ" + // kw + "ZZZ" + // kw-gb + "KYR" + // ky + "KYR" + // ky-kg + "ZZZ" + // la + "ZZZ" + // la-001 + "ZZZ" + // lag + "ZZZ" + // lag-tz + "LBX" + // lb + "LBX" + // lb-lu + "ZZZ" + // lg + "ZZZ" + // lg-ug + "ZZZ" + // lkt + "ZZZ" + // lkt-us + "ZZZ" + // ln + "ZZZ" + // ln-ao + "ZZZ" + // ln-cd + "ZZZ" + // ln-cf + "ZZZ" + // ln-cg + "LAO" + // lo + "LAO" + // lo-la + "ZZZ" + // lrc + "ZZZ" + // lrc-iq + "ZZZ" + // lrc-ir + "LTH" + // lt + "LTH" + // lt-lt + "ZZZ" + // lu + "ZZZ" + // lu-cd + "ZZZ" + // luo + "ZZZ" + // luo-ke + "ZZZ" + // luy + "ZZZ" + // luy-ke + "LVI" + // lv + "LVI" + // lv-lv + "ZZZ" + // mas + "ZZZ" + // mas-ke + "ZZZ" + // mas-tz + "ZZZ" + // mer + "ZZZ" + // mer-ke + "ZZZ" + // mfe + "ZZZ" + // mfe-mu + "MLG" + // mg + "MLG" + // mg-mg + "ZZZ" + // mgh + "ZZZ" + // mgh-mz + "ZZZ" + // mgo + "ZZZ" + // mgo-cm + "MRI" + // mi + "MRI" + // mi-nz + "MKI" + // mk + "MKI" + // mk-mk + "MYM" + // ml + "MYM" + // ml-in + "MNN" + // mn + "MNN" + // mn-cyrl + "MNN" + // mn-mn + "MNG" + // mn-mong + "MNG" + // mn-mong-cn + "MNM" + // mn-mong-mn + "ZZZ" + // mni + "ZZZ" + // mni-in + "MWK" + // moh + "MWK" + // moh-ca + "MAR" + // mr + "MAR" + // mr-in + "MSL" + // ms + "MSB" + // ms-bn + "MSL" + // ms-my + "ZZZ" + // ms-sg + "MLT" + // mt + "MLT" + // mt-mt + "ZZZ" + // mua + "ZZZ" + // mua-cm + "MYA" + // my + "MYA" + // my-mm + "ZZZ" + // mzn + "ZZZ" + // mzn-ir + "ZZZ" + // naq + "ZZZ" + // naq-na + "NOR" + // nb + "NOR" + // nb-no + "ZZZ" + // nb-sj + "ZZZ" + // nd + "ZZZ" + // nd-zw + "ZZZ" + // nds + "ZZZ" + // nds-de + "ZZZ" + // nds-nl + "NEP" + // ne + "NEI" + // ne-in + "NEP" + // ne-np + "NLD" + // nl + "ZZZ" + // nl-aw + "NLB" + // nl-be + "ZZZ" + // nl-bq + "ZZZ" + // nl-cw + "NLD" + // nl-nl + "ZZZ" + // nl-sr + "ZZZ" + // nl-sx + "ZZZ" + // nmg + "ZZZ" + // nmg-cm + "NON" + // nn + "NON" + // nn-no + "ZZZ" + // nnh + "ZZZ" + // nnh-cm + "NOR" + // no + "NQO" + // nqo + "NQO" + // nqo-gn + "ZZZ" + // nr + "ZZZ" + // nr-za + "NSO" + // nso + "NSO" + // nso-za + "ZZZ" + // nus + "ZZZ" + // nus-ss + "ZZZ" + // nyn + "ZZZ" + // nyn-ug + "OCI" + // oc + "OCI" + // oc-fr + "ORM" + // om + "ORM" + // om-et + "ZZZ" + // om-ke + "ORI" + // or + "ORI" + // or-in + "ZZZ" + // os + "ZZZ" + // os-ge + "ZZZ" + // os-ru + "PAN" + // pa + "PAP" + // pa-arab + "PAP" + // pa-arab-pk + "PAN" + // pa-in + "ZZZ" + // pap + "ZZZ" + // pap-029 + "PLK" + // pl + "PLK" + // pl-pl + "ZZZ" + // prg + "ZZZ" + // prg-001 + "PRS" + // prs + "PRS" + // prs-af + "PAS" + // ps + "PAS" + // ps-af + "PTB" + // pt + "PTA" + // pt-ao + "PTB" + // pt-br + "ZZZ" + // pt-ch + "ZZZ" + // pt-cv + "ZZZ" + // pt-gq + "ZZZ" + // pt-gw + "ZZZ" + // pt-lu + "ZZZ" + // pt-mo + "ZZZ" + // pt-mz + "PTG" + // pt-pt + "ZZZ" + // pt-st + "ZZZ" + // pt-tl + "ENJ" + // qps-latn-x-sh + "ENU" + // qps-ploc + "JPN" + // qps-ploca + "ARA" + // qps-plocm + "QUT" + // quc + "QUT" + // quc-latn + "QUT" + // quc-latn-gt + "QUB" + // quz + "QUB" + // quz-bo + "QUE" + // quz-ec + "QUP" + // quz-pe + "RMC" + // rm + "RMC" + // rm-ch + "ZZZ" + // rn + "ZZZ" + // rn-bi + "ROM" + // ro + "ROD" + // ro-md + "ROM" + // ro-ro + "ZZZ" + // rof + "ZZZ" + // rof-tz + "RUS" + // ru + "ZZZ" + // ru-by + "ZZZ" + // ru-kg + "ZZZ" + // ru-kz + "RUM" + // ru-md + "RUS" + // ru-ru + "ZZZ" + // ru-ua + "KIN" + // rw + "KIN" + // rw-rw + "ZZZ" + // rwk + "ZZZ" + // rwk-tz + "SAN" + // sa + "SAN" + // sa-in + "SAH" + // sah + "SAH" + // sah-ru + "ZZZ" + // saq + "ZZZ" + // saq-ke + "ZZZ" + // sbp + "ZZZ" + // sbp-tz + "SIP" + // sd + "SIP" + // sd-arab + "SIP" + // sd-arab-pk + "ZZZ" + // sd-deva + "ZZZ" + // sd-deva-in + "SME" + // se + "SMG" + // se-fi + "SME" + // se-no + "SMF" + // se-se + "ZZZ" + // seh + "ZZZ" + // seh-mz + "ZZZ" + // ses + "ZZZ" + // ses-ml + "ZZZ" + // sg + "ZZZ" + // sg-cf + "ZZZ" + // shi + "ZZZ" + // shi-latn + "ZZZ" + // shi-latn-ma + "ZZZ" + // shi-tfng + "ZZZ" + // shi-tfng-ma + "SIN" + // si + "SIN" + // si-lk + "SKY" + // sk + "SKY" + // sk-sk + "SLV" + // sl + "SLV" + // sl-si + "SMB" + // sma + "SMA" + // sma-no + "SMB" + // sma-se + "SMK" + // smj + "SMJ" + // smj-no + "SMK" + // smj-se + "SMN" + // smn + "SMN" + // smn-fi + "SMS" + // sms + "SMS" + // sms-fi + "SNA" + // sn + "SNA" + // sn-latn + "SNA" + // sn-latn-zw + "SOM" + // so + "ZZZ" + // so-dj + "ZZZ" + // so-et + "ZZZ" + // so-ke + "SOM" + // so-so + "SQI" + // sq + "SQI" + // sq-al + "ZZZ" + // sq-mk + "ZZZ" + // sq-xk + "SRM" + // sr + "SRO" + // sr-cyrl + "SRN" + // sr-cyrl-ba + "SRB" + // sr-cyrl-cs + "SRQ" + // sr-cyrl-me + "SRO" + // sr-cyrl-rs + "ZZZ" + // sr-cyrl-xk + "SRM" + // sr-latn + "SRS" + // sr-latn-ba + "SRL" + // sr-latn-cs + "SRP" + // sr-latn-me + "SRM" + // sr-latn-rs + "ZZZ" + // sr-latn-xk + "ZZZ" + // ss + "ZZZ" + // ss-sz + "ZZZ" + // ss-za + "ZZZ" + // ssy + "ZZZ" + // ssy-er + "SOT" + // st + "ZZZ" + // st-ls + "SOT" + // st-za + "SVE" + // sv + "ZZZ" + // sv-ax + "SVF" + // sv-fi + "SVE" + // sv-se + "SWK" + // sw + "ZZZ" + // sw-cd + "SWK" + // sw-ke + "ZZZ" + // sw-tz + "ZZZ" + // sw-ug + "ZZZ" + // swc + "ZZZ" + // swc-cd + "SYR" + // syr + "SYR" + // syr-sy + "TAI" + // ta + "TAI" + // ta-in + "TAM" + // ta-lk + "ZZZ" + // ta-my + "ZZZ" + // ta-sg + "TEL" + // te + "TEL" + // te-in + "ZZZ" + // teo + "ZZZ" + // teo-ke + "ZZZ" + // teo-ug + "TAJ" + // tg + "TAJ" + // tg-cyrl + "TAJ" + // tg-cyrl-tj + "THA" + // th + "THA" + // th-th + "TIR" + // ti + "TIR" + // ti-er + "TIE" + // ti-et + "ZZZ" + // tig + "ZZZ" + // tig-er + "TUK" + // tk + "TUK" + // tk-tm + "TSN" + // tn + "TSB" + // tn-bw + "TSN" + // tn-za + "ZZZ" + // to + "ZZZ" + // to-to + "TRK" + // tr + "ZZZ" + // tr-cy + "TRK" + // tr-tr + "TSO" + // ts + "TSO" + // ts-za + "TTT" + // tt + "TTT" + // tt-ru + "ZZZ" + // twq + "ZZZ" + // twq-ne + "TZA" + // tzm + "ZZZ" + // tzm-arab + "ZZZ" + // tzm-arab-ma + "TZA" + // tzm-latn + "TZA" + // tzm-latn-dz + "ZZZ" + // tzm-latn-ma + "TZM" + // tzm-tfng + "TZM" + // tzm-tfng-ma + "UIG" + // ug + "UIG" + // ug-cn + "UKR" + // uk + "UKR" + // uk-ua + "URD" + // ur + "URI" + // ur-in + "URD" + // ur-pk + "UZB" + // uz + "ZZZ" + // uz-arab + "ZZZ" + // uz-arab-af + "UZC" + // uz-cyrl + "UZC" + // uz-cyrl-uz + "UZB" + // uz-latn + "UZB" + // uz-latn-uz + "ZZZ" + // vai + "ZZZ" + // vai-latn + "ZZZ" + // vai-latn-lr + "ZZZ" + // vai-vaii + "ZZZ" + // vai-vaii-lr + "ZZZ" + // ve + "ZZZ" + // ve-za + "VIT" + // vi + "VIT" + // vi-vn + "ZZZ" + // vo + "ZZZ" + // vo-001 + "ZZZ" + // vun + "ZZZ" + // vun-tz + "ZZZ" + // wae + "ZZZ" + // wae-ch + "ZZZ" + // wal + "ZZZ" + // wal-et + "WOL" + // wo + "WOL" + // wo-sn + "IVL" + // x-iv_mathan + "XHO" + // xh + "XHO" + // xh-za + "ZZZ" + // xog + "ZZZ" + // xog-ug + "ZZZ" + // yav + "ZZZ" + // yav-cm + "ZZZ" + // yi + "ZZZ" + // yi-001 + "YOR" + // yo + "ZZZ" + // yo-bj + "YOR" + // yo-ng + "ZZZ" + // yue + "ZZZ" + // yue-hk + "ZHG" + // zgh + "ZHG" + // zgh-tfng + "ZHG" + // zgh-tfng-ma + "CHS" + // zh + "CHS" + // zh-chs + "CHT" + // zh-cht + "CHS" + // zh-cn + "CHS" + // zh-cn_phoneb + "CHS" + // zh-cn_stroke + "CHS" + // zh-hans + "ZZZ" + // zh-hans-hk + "ZZZ" + // zh-hans-mo + "ZHH" + // zh-hant + "ZHH" + // zh-hk + "ZHH" + // zh-hk_radstr + "ZHM" + // zh-mo + "ZHM" + // zh-mo_radstr + "ZHM" + // zh-mo_stroke + "ZHI" + // zh-sg + "ZHI" + // zh-sg_phoneb + "ZHI" + // zh-sg_stroke + "CHT" + // zh-tw + "CHT" + // zh-tw_pronun + "CHT" + // zh-tw_radstr + "ZUL" + // zu + "ZUL"; // zu-za + + // s_localeNamesIndices contains the start index of every culture name in the string + // s_localeNames. We infer the length of each string by looking at the start index + // of the next string. + private static readonly int[] s_localeNamesIndices = new int[] + { + // c_localeNames index, // index to this array - culture name + 0 , // 0 - aa + 2 , // 1 - aa-dj + 7 , // 2 - aa-er + 12 , // 3 - aa-et + 17 , // 4 - af + 19 , // 5 - af-na + 24 , // 6 - af-za + 29 , // 7 - agq + 32 , // 8 - agq-cm + 38 , // 9 - ak + 40 , // 10 - ak-gh + 45 , // 11 - am + 47 , // 12 - am-et + 52 , // 13 - ar + 54 , // 14 - ar-001 + 60 , // 15 - ar-ae + 65 , // 16 - ar-bh + 70 , // 17 - ar-dj + 75 , // 18 - ar-dz + 80 , // 19 - ar-eg + 85 , // 20 - ar-er + 90 , // 21 - ar-il + 95 , // 22 - ar-iq + 100 , // 23 - ar-jo + 105 , // 24 - ar-km + 110 , // 25 - ar-kw + 115 , // 26 - ar-lb + 120 , // 27 - ar-ly + 125 , // 28 - ar-ma + 130 , // 29 - ar-mr + 135 , // 30 - ar-om + 140 , // 31 - ar-ps + 145 , // 32 - ar-qa + 150 , // 33 - ar-sa + 155 , // 34 - ar-sd + 160 , // 35 - ar-so + 165 , // 36 - ar-ss + 170 , // 37 - ar-sy + 175 , // 38 - ar-td + 180 , // 39 - ar-tn + 185 , // 40 - ar-ye + 190 , // 41 - arn + 193 , // 42 - arn-cl + 199 , // 43 - as + 201 , // 44 - as-in + 206 , // 45 - asa + 209 , // 46 - asa-tz + 215 , // 47 - ast + 218 , // 48 - ast-es + 224 , // 49 - az + 226 , // 50 - az-cyrl + 233 , // 51 - az-cyrl-az + 243 , // 52 - az-latn + 250 , // 53 - az-latn-az + 260 , // 54 - ba + 262 , // 55 - ba-ru + 267 , // 56 - bas + 270 , // 57 - bas-cm + 276 , // 58 - be + 278 , // 59 - be-by + 283 , // 60 - bem + 286 , // 61 - bem-zm + 292 , // 62 - bez + 295 , // 63 - bez-tz + 301 , // 64 - bg + 303 , // 65 - bg-bg + 308 , // 66 - bin + 311 , // 67 - bin-ng + 317 , // 68 - bm + 319 , // 69 - bm-latn + 326 , // 70 - bm-latn-ml + 336 , // 71 - bn + 338 , // 72 - bn-bd + 343 , // 73 - bn-in + 348 , // 74 - bo + 350 , // 75 - bo-cn + 355 , // 76 - bo-in + 360 , // 77 - br + 362 , // 78 - br-fr + 367 , // 79 - brx + 370 , // 80 - brx-in + 376 , // 81 - bs + 378 , // 82 - bs-cyrl + 385 , // 83 - bs-cyrl-ba + 395 , // 84 - bs-latn + 402 , // 85 - bs-latn-ba + 412 , // 86 - byn + 415 , // 87 - byn-er + 421 , // 88 - ca + 423 , // 89 - ca-ad + 428 , // 90 - ca-es + 433 , // 91 - ca-es-valencia + 447 , // 92 - ca-fr + 452 , // 93 - ca-it + 457 , // 94 - ce + 459 , // 95 - ce-ru + 464 , // 96 - cgg + 467 , // 97 - cgg-ug + 473 , // 98 - chr + 476 , // 99 - chr-cher + 484 , // 100 - chr-cher-us + 495 , // 101 - co + 497 , // 102 - co-fr + 502 , // 103 - cs + 504 , // 104 - cs-cz + 509 , // 105 - cu + 511 , // 106 - cu-ru + 516 , // 107 - cy + 518 , // 108 - cy-gb + 523 , // 109 - da + 525 , // 110 - da-dk + 530 , // 111 - da-gl + 535 , // 112 - dav + 538 , // 113 - dav-ke + 544 , // 114 - de + 546 , // 115 - de-at + 551 , // 116 - de-be + 556 , // 117 - de-ch + 561 , // 118 - de-de + 566 , // 119 - de-de_phoneb + 578 , // 120 - de-it + 583 , // 121 - de-li + 588 , // 122 - de-lu + 593 , // 123 - dje + 596 , // 124 - dje-ne + 602 , // 125 - dsb + 605 , // 126 - dsb-de + 611 , // 127 - dua + 614 , // 128 - dua-cm + 620 , // 129 - dv + 622 , // 130 - dv-mv + 627 , // 131 - dyo + 630 , // 132 - dyo-sn + 636 , // 133 - dz + 638 , // 134 - dz-bt + 643 , // 135 - ebu + 646 , // 136 - ebu-ke + 652 , // 137 - ee + 654 , // 138 - ee-gh + 659 , // 139 - ee-tg + 664 , // 140 - el + 666 , // 141 - el-cy + 671 , // 142 - el-gr + 676 , // 143 - en + 678 , // 144 - en-001 + 684 , // 145 - en-029 + 690 , // 146 - en-150 + 696 , // 147 - en-ag + 701 , // 148 - en-ai + 706 , // 149 - en-as + 711 , // 150 - en-at + 716 , // 151 - en-au + 721 , // 152 - en-bb + 726 , // 153 - en-be + 731 , // 154 - en-bi + 736 , // 155 - en-bm + 741 , // 156 - en-bs + 746 , // 157 - en-bw + 751 , // 158 - en-bz + 756 , // 159 - en-ca + 761 , // 160 - en-cc + 766 , // 161 - en-ch + 771 , // 162 - en-ck + 776 , // 163 - en-cm + 781 , // 164 - en-cx + 786 , // 165 - en-cy + 791 , // 166 - en-de + 796 , // 167 - en-dk + 801 , // 168 - en-dm + 806 , // 169 - en-er + 811 , // 170 - en-fi + 816 , // 171 - en-fj + 821 , // 172 - en-fk + 826 , // 173 - en-fm + 831 , // 174 - en-gb + 836 , // 175 - en-gd + 841 , // 176 - en-gg + 846 , // 177 - en-gh + 851 , // 178 - en-gi + 856 , // 179 - en-gm + 861 , // 180 - en-gu + 866 , // 181 - en-gy + 871 , // 182 - en-hk + 876 , // 183 - en-id + 881 , // 184 - en-ie + 886 , // 185 - en-il + 891 , // 186 - en-im + 896 , // 187 - en-in + 901 , // 188 - en-io + 906 , // 189 - en-je + 911 , // 190 - en-jm + 916 , // 191 - en-ke + 921 , // 192 - en-ki + 926 , // 193 - en-kn + 931 , // 194 - en-ky + 936 , // 195 - en-lc + 941 , // 196 - en-lr + 946 , // 197 - en-ls + 951 , // 198 - en-mg + 956 , // 199 - en-mh + 961 , // 200 - en-mo + 966 , // 201 - en-mp + 971 , // 202 - en-ms + 976 , // 203 - en-mt + 981 , // 204 - en-mu + 986 , // 205 - en-mw + 991 , // 206 - en-my + 996 , // 207 - en-na + 1001, // 208 - en-nf + 1006, // 209 - en-ng + 1011, // 210 - en-nl + 1016, // 211 - en-nr + 1021, // 212 - en-nu + 1026, // 213 - en-nz + 1031, // 214 - en-pg + 1036, // 215 - en-ph + 1041, // 216 - en-pk + 1046, // 217 - en-pn + 1051, // 218 - en-pr + 1056, // 219 - en-pw + 1061, // 220 - en-rw + 1066, // 221 - en-sb + 1071, // 222 - en-sc + 1076, // 223 - en-sd + 1081, // 224 - en-se + 1086, // 225 - en-sg + 1091, // 226 - en-sh + 1096, // 227 - en-si + 1101, // 228 - en-sl + 1106, // 229 - en-ss + 1111, // 230 - en-sx + 1116, // 231 - en-sz + 1121, // 232 - en-tc + 1126, // 233 - en-tk + 1131, // 234 - en-to + 1136, // 235 - en-tt + 1141, // 236 - en-tv + 1146, // 237 - en-tz + 1151, // 238 - en-ug + 1156, // 239 - en-um + 1161, // 240 - en-us + 1166, // 241 - en-vc + 1171, // 242 - en-vg + 1176, // 243 - en-vi + 1181, // 244 - en-vu + 1186, // 245 - en-ws + 1191, // 246 - en-za + 1196, // 247 - en-zm + 1201, // 248 - en-zw + 1206, // 249 - eo + 1208, // 250 - eo-001 + 1214, // 251 - es + 1216, // 252 - es-419 + 1222, // 253 - es-ar + 1227, // 254 - es-bo + 1232, // 255 - es-br + 1237, // 256 - es-cl + 1242, // 257 - es-co + 1247, // 258 - es-cr + 1252, // 259 - es-cu + 1257, // 260 - es-do + 1262, // 261 - es-ec + 1267, // 262 - es-es + 1272, // 263 - es-es_tradnl + 1284, // 264 - es-gq + 1289, // 265 - es-gt + 1294, // 266 - es-hn + 1299, // 267 - es-mx + 1304, // 268 - es-ni + 1309, // 269 - es-pa + 1314, // 270 - es-pe + 1319, // 271 - es-ph + 1324, // 272 - es-pr + 1329, // 273 - es-py + 1334, // 274 - es-sv + 1339, // 275 - es-us + 1344, // 276 - es-uy + 1349, // 277 - es-ve + 1354, // 278 - et + 1356, // 279 - et-ee + 1361, // 280 - eu + 1363, // 281 - eu-es + 1368, // 282 - ewo + 1371, // 283 - ewo-cm + 1377, // 284 - fa + 1379, // 285 - fa-ir + 1384, // 286 - ff + 1386, // 287 - ff-cm + 1391, // 288 - ff-gn + 1396, // 289 - ff-latn + 1403, // 290 - ff-latn-sn + 1413, // 291 - ff-mr + 1418, // 292 - ff-ng + 1423, // 293 - fi + 1425, // 294 - fi-fi + 1430, // 295 - fil + 1433, // 296 - fil-ph + 1439, // 297 - fo + 1441, // 298 - fo-dk + 1446, // 299 - fo-fo + 1451, // 300 - fr + 1453, // 301 - fr-029 + 1459, // 302 - fr-be + 1464, // 303 - fr-bf + 1469, // 304 - fr-bi + 1474, // 305 - fr-bj + 1479, // 306 - fr-bl + 1484, // 307 - fr-ca + 1489, // 308 - fr-cd + 1494, // 309 - fr-cf + 1499, // 310 - fr-cg + 1504, // 311 - fr-ch + 1509, // 312 - fr-ci + 1514, // 313 - fr-cm + 1519, // 314 - fr-dj + 1524, // 315 - fr-dz + 1529, // 316 - fr-fr + 1534, // 317 - fr-ga + 1539, // 318 - fr-gf + 1544, // 319 - fr-gn + 1549, // 320 - fr-gp + 1554, // 321 - fr-gq + 1559, // 322 - fr-ht + 1564, // 323 - fr-km + 1569, // 324 - fr-lu + 1574, // 325 - fr-ma + 1579, // 326 - fr-mc + 1584, // 327 - fr-mf + 1589, // 328 - fr-mg + 1594, // 329 - fr-ml + 1599, // 330 - fr-mq + 1604, // 331 - fr-mr + 1609, // 332 - fr-mu + 1614, // 333 - fr-nc + 1619, // 334 - fr-ne + 1624, // 335 - fr-pf + 1629, // 336 - fr-pm + 1634, // 337 - fr-re + 1639, // 338 - fr-rw + 1644, // 339 - fr-sc + 1649, // 340 - fr-sn + 1654, // 341 - fr-sy + 1659, // 342 - fr-td + 1664, // 343 - fr-tg + 1669, // 344 - fr-tn + 1674, // 345 - fr-vu + 1679, // 346 - fr-wf + 1684, // 347 - fr-yt + 1689, // 348 - fur + 1692, // 349 - fur-it + 1698, // 350 - fy + 1700, // 351 - fy-nl + 1705, // 352 - ga + 1707, // 353 - ga-ie + 1712, // 354 - gd + 1714, // 355 - gd-gb + 1719, // 356 - gl + 1721, // 357 - gl-es + 1726, // 358 - gn + 1728, // 359 - gn-py + 1733, // 360 - gsw + 1736, // 361 - gsw-ch + 1742, // 362 - gsw-fr + 1748, // 363 - gsw-li + 1754, // 364 - gu + 1756, // 365 - gu-in + 1761, // 366 - guz + 1764, // 367 - guz-ke + 1770, // 368 - gv + 1772, // 369 - gv-im + 1777, // 370 - ha + 1779, // 371 - ha-latn + 1786, // 372 - ha-latn-gh + 1796, // 373 - ha-latn-ne + 1806, // 374 - ha-latn-ng + 1816, // 375 - haw + 1819, // 376 - haw-us + 1825, // 377 - he + 1827, // 378 - he-il + 1832, // 379 - hi + 1834, // 380 - hi-in + 1839, // 381 - hr + 1841, // 382 - hr-ba + 1846, // 383 - hr-hr + 1851, // 384 - hsb + 1854, // 385 - hsb-de + 1860, // 386 - hu + 1862, // 387 - hu-hu + 1867, // 388 - hu-hu_technl + 1879, // 389 - hy + 1881, // 390 - hy-am + 1886, // 391 - ia + 1888, // 392 - ia-001 + 1894, // 393 - ia-fr + 1899, // 394 - ibb + 1902, // 395 - ibb-ng + 1908, // 396 - id + 1910, // 397 - id-id + 1915, // 398 - ig + 1917, // 399 - ig-ng + 1922, // 400 - ii + 1924, // 401 - ii-cn + 1929, // 402 - is + 1931, // 403 - is-is + 1936, // 404 - it + 1938, // 405 - it-ch + 1943, // 406 - it-it + 1948, // 407 - it-sm + 1953, // 408 - iu + 1955, // 409 - iu-cans + 1962, // 410 - iu-cans-ca + 1972, // 411 - iu-latn + 1979, // 412 - iu-latn-ca + 1989, // 413 - ja + 1991, // 414 - ja-jp + 1996, // 415 - ja-jp_radstr + 2008, // 416 - jgo + 2011, // 417 - jgo-cm + 2017, // 418 - jmc + 2020, // 419 - jmc-tz + 2026, // 420 - jv + 2028, // 421 - jv-java + 2035, // 422 - jv-java-id + 2045, // 423 - jv-latn + 2052, // 424 - jv-latn-id + 2062, // 425 - ka + 2064, // 426 - ka-ge + 2069, // 427 - ka-ge_modern + 2081, // 428 - kab + 2084, // 429 - kab-dz + 2090, // 430 - kam + 2093, // 431 - kam-ke + 2099, // 432 - kde + 2102, // 433 - kde-tz + 2108, // 434 - kea + 2111, // 435 - kea-cv + 2117, // 436 - khq + 2120, // 437 - khq-ml + 2126, // 438 - ki + 2128, // 439 - ki-ke + 2133, // 440 - kk + 2135, // 441 - kk-kz + 2140, // 442 - kkj + 2143, // 443 - kkj-cm + 2149, // 444 - kl + 2151, // 445 - kl-gl + 2156, // 446 - kln + 2159, // 447 - kln-ke + 2165, // 448 - km + 2167, // 449 - km-kh + 2172, // 450 - kn + 2174, // 451 - kn-in + 2179, // 452 - ko + 2181, // 453 - ko-kp + 2186, // 454 - ko-kr + 2191, // 455 - kok + 2194, // 456 - kok-in + 2200, // 457 - kr + 2202, // 458 - kr-ng + 2207, // 459 - ks + 2209, // 460 - ks-arab + 2216, // 461 - ks-arab-in + 2226, // 462 - ks-deva + 2233, // 463 - ks-deva-in + 2243, // 464 - ksb + 2246, // 465 - ksb-tz + 2252, // 466 - ksf + 2255, // 467 - ksf-cm + 2261, // 468 - ksh + 2264, // 469 - ksh-de + 2270, // 470 - ku + 2272, // 471 - ku-arab + 2279, // 472 - ku-arab-iq + 2289, // 473 - ku-arab-ir + 2299, // 474 - kw + 2301, // 475 - kw-gb + 2306, // 476 - ky + 2308, // 477 - ky-kg + 2313, // 478 - la + 2315, // 479 - la-001 + 2321, // 480 - lag + 2324, // 481 - lag-tz + 2330, // 482 - lb + 2332, // 483 - lb-lu + 2337, // 484 - lg + 2339, // 485 - lg-ug + 2344, // 486 - lkt + 2347, // 487 - lkt-us + 2353, // 488 - ln + 2355, // 489 - ln-ao + 2360, // 490 - ln-cd + 2365, // 491 - ln-cf + 2370, // 492 - ln-cg + 2375, // 493 - lo + 2377, // 494 - lo-la + 2382, // 495 - lrc + 2385, // 496 - lrc-iq + 2391, // 497 - lrc-ir + 2397, // 498 - lt + 2399, // 499 - lt-lt + 2404, // 500 - lu + 2406, // 501 - lu-cd + 2411, // 502 - luo + 2414, // 503 - luo-ke + 2420, // 504 - luy + 2423, // 505 - luy-ke + 2429, // 506 - lv + 2431, // 507 - lv-lv + 2436, // 508 - mas + 2439, // 509 - mas-ke + 2445, // 510 - mas-tz + 2451, // 511 - mer + 2454, // 512 - mer-ke + 2460, // 513 - mfe + 2463, // 514 - mfe-mu + 2469, // 515 - mg + 2471, // 516 - mg-mg + 2476, // 517 - mgh + 2479, // 518 - mgh-mz + 2485, // 519 - mgo + 2488, // 520 - mgo-cm + 2494, // 521 - mi + 2496, // 522 - mi-nz + 2501, // 523 - mk + 2503, // 524 - mk-mk + 2508, // 525 - ml + 2510, // 526 - ml-in + 2515, // 527 - mn + 2517, // 528 - mn-cyrl + 2524, // 529 - mn-mn + 2529, // 530 - mn-mong + 2536, // 531 - mn-mong-cn + 2546, // 532 - mn-mong-mn + 2556, // 533 - mni + 2559, // 534 - mni-in + 2565, // 535 - moh + 2568, // 536 - moh-ca + 2574, // 537 - mr + 2576, // 538 - mr-in + 2581, // 539 - ms + 2583, // 540 - ms-bn + 2588, // 541 - ms-my + 2593, // 542 - ms-sg + 2598, // 543 - mt + 2600, // 544 - mt-mt + 2605, // 545 - mua + 2608, // 546 - mua-cm + 2614, // 547 - my + 2616, // 548 - my-mm + 2621, // 549 - mzn + 2624, // 550 - mzn-ir + 2630, // 551 - naq + 2633, // 552 - naq-na + 2639, // 553 - nb + 2641, // 554 - nb-no + 2646, // 555 - nb-sj + 2651, // 556 - nd + 2653, // 557 - nd-zw + 2658, // 558 - nds + 2661, // 559 - nds-de + 2667, // 560 - nds-nl + 2673, // 561 - ne + 2675, // 562 - ne-in + 2680, // 563 - ne-np + 2685, // 564 - nl + 2687, // 565 - nl-aw + 2692, // 566 - nl-be + 2697, // 567 - nl-bq + 2702, // 568 - nl-cw + 2707, // 569 - nl-nl + 2712, // 570 - nl-sr + 2717, // 571 - nl-sx + 2722, // 572 - nmg + 2725, // 573 - nmg-cm + 2731, // 574 - nn + 2733, // 575 - nn-no + 2738, // 576 - nnh + 2741, // 577 - nnh-cm + 2747, // 578 - no + 2749, // 579 - nqo + 2752, // 580 - nqo-gn + 2758, // 581 - nr + 2760, // 582 - nr-za + 2765, // 583 - nso + 2768, // 584 - nso-za + 2774, // 585 - nus + 2777, // 586 - nus-ss + 2783, // 587 - nyn + 2786, // 588 - nyn-ug + 2792, // 589 - oc + 2794, // 590 - oc-fr + 2799, // 591 - om + 2801, // 592 - om-et + 2806, // 593 - om-ke + 2811, // 594 - or + 2813, // 595 - or-in + 2818, // 596 - os + 2820, // 597 - os-ge + 2825, // 598 - os-ru + 2830, // 599 - pa + 2832, // 600 - pa-arab + 2839, // 601 - pa-arab-pk + 2849, // 602 - pa-in + 2854, // 603 - pap + 2857, // 604 - pap-029 + 2864, // 605 - pl + 2866, // 606 - pl-pl + 2871, // 607 - prg + 2874, // 608 - prg-001 + 2881, // 609 - prs + 2884, // 610 - prs-af + 2890, // 611 - ps + 2892, // 612 - ps-af + 2897, // 613 - pt + 2899, // 614 - pt-ao + 2904, // 615 - pt-br + 2909, // 616 - pt-ch + 2914, // 617 - pt-cv + 2919, // 618 - pt-gq + 2924, // 619 - pt-gw + 2929, // 620 - pt-lu + 2934, // 621 - pt-mo + 2939, // 622 - pt-mz + 2944, // 623 - pt-pt + 2949, // 624 - pt-st + 2954, // 625 - pt-tl + 2959, // 626 - qps-latn-x-sh + 2972, // 627 - qps-ploc + 2980, // 628 - qps-ploca + 2989, // 629 - qps-plocm + 2998, // 630 - quc + 3001, // 631 - quc-latn + 3009, // 632 - quc-latn-gt + 3020, // 633 - quz + 3023, // 634 - quz-bo + 3029, // 635 - quz-ec + 3035, // 636 - quz-pe + 3041, // 637 - rm + 3043, // 638 - rm-ch + 3048, // 639 - rn + 3050, // 640 - rn-bi + 3055, // 641 - ro + 3057, // 642 - ro-md + 3062, // 643 - ro-ro + 3067, // 644 - rof + 3070, // 645 - rof-tz + 3076, // 646 - ru + 3078, // 647 - ru-by + 3083, // 648 - ru-kg + 3088, // 649 - ru-kz + 3093, // 650 - ru-md + 3098, // 651 - ru-ru + 3103, // 652 - ru-ua + 3108, // 653 - rw + 3110, // 654 - rw-rw + 3115, // 655 - rwk + 3118, // 656 - rwk-tz + 3124, // 657 - sa + 3126, // 658 - sa-in + 3131, // 659 - sah + 3134, // 660 - sah-ru + 3140, // 661 - saq + 3143, // 662 - saq-ke + 3149, // 663 - sbp + 3152, // 664 - sbp-tz + 3158, // 665 - sd + 3160, // 666 - sd-arab + 3167, // 667 - sd-arab-pk + 3177, // 668 - sd-deva + 3184, // 669 - sd-deva-in + 3194, // 670 - se + 3196, // 671 - se-fi + 3201, // 672 - se-no + 3206, // 673 - se-se + 3211, // 674 - seh + 3214, // 675 - seh-mz + 3220, // 676 - ses + 3223, // 677 - ses-ml + 3229, // 678 - sg + 3231, // 679 - sg-cf + 3236, // 680 - shi + 3239, // 681 - shi-latn + 3247, // 682 - shi-latn-ma + 3258, // 683 - shi-tfng + 3266, // 684 - shi-tfng-ma + 3277, // 685 - si + 3279, // 686 - si-lk + 3284, // 687 - sk + 3286, // 688 - sk-sk + 3291, // 689 - sl + 3293, // 690 - sl-si + 3298, // 691 - sma + 3301, // 692 - sma-no + 3307, // 693 - sma-se + 3313, // 694 - smj + 3316, // 695 - smj-no + 3322, // 696 - smj-se + 3328, // 697 - smn + 3331, // 698 - smn-fi + 3337, // 699 - sms + 3340, // 700 - sms-fi + 3346, // 701 - sn + 3348, // 702 - sn-latn + 3355, // 703 - sn-latn-zw + 3365, // 704 - so + 3367, // 705 - so-dj + 3372, // 706 - so-et + 3377, // 707 - so-ke + 3382, // 708 - so-so + 3387, // 709 - sq + 3389, // 710 - sq-al + 3394, // 711 - sq-mk + 3399, // 712 - sq-xk + 3404, // 713 - sr + 3406, // 714 - sr-cyrl + 3413, // 715 - sr-cyrl-ba + 3423, // 716 - sr-cyrl-cs + 3433, // 717 - sr-cyrl-me + 3443, // 718 - sr-cyrl-rs + 3453, // 719 - sr-cyrl-xk + 3463, // 720 - sr-latn + 3470, // 721 - sr-latn-ba + 3480, // 722 - sr-latn-cs + 3490, // 723 - sr-latn-me + 3500, // 724 - sr-latn-rs + 3510, // 725 - sr-latn-xk + 3520, // 726 - ss + 3522, // 727 - ss-sz + 3527, // 728 - ss-za + 3532, // 729 - ssy + 3535, // 730 - ssy-er + 3541, // 731 - st + 3543, // 732 - st-ls + 3548, // 733 - st-za + 3553, // 734 - sv + 3555, // 735 - sv-ax + 3560, // 736 - sv-fi + 3565, // 737 - sv-se + 3570, // 738 - sw + 3572, // 739 - sw-cd + 3577, // 740 - sw-ke + 3582, // 741 - sw-tz + 3587, // 742 - sw-ug + 3592, // 743 - swc + 3595, // 744 - swc-cd + 3601, // 745 - syr + 3604, // 746 - syr-sy + 3610, // 747 - ta + 3612, // 748 - ta-in + 3617, // 749 - ta-lk + 3622, // 750 - ta-my + 3627, // 751 - ta-sg + 3632, // 752 - te + 3634, // 753 - te-in + 3639, // 754 - teo + 3642, // 755 - teo-ke + 3648, // 756 - teo-ug + 3654, // 757 - tg + 3656, // 758 - tg-cyrl + 3663, // 759 - tg-cyrl-tj + 3673, // 760 - th + 3675, // 761 - th-th + 3680, // 762 - ti + 3682, // 763 - ti-er + 3687, // 764 - ti-et + 3692, // 765 - tig + 3695, // 766 - tig-er + 3701, // 767 - tk + 3703, // 768 - tk-tm + 3708, // 769 - tn + 3710, // 770 - tn-bw + 3715, // 771 - tn-za + 3720, // 772 - to + 3722, // 773 - to-to + 3727, // 774 - tr + 3729, // 775 - tr-cy + 3734, // 776 - tr-tr + 3739, // 777 - ts + 3741, // 778 - ts-za + 3746, // 779 - tt + 3748, // 780 - tt-ru + 3753, // 781 - twq + 3756, // 782 - twq-ne + 3762, // 783 - tzm + 3765, // 784 - tzm-arab + 3773, // 785 - tzm-arab-ma + 3784, // 786 - tzm-latn + 3792, // 787 - tzm-latn-dz + 3803, // 788 - tzm-latn-ma + 3814, // 789 - tzm-tfng + 3822, // 790 - tzm-tfng-ma + 3833, // 791 - ug + 3835, // 792 - ug-cn + 3840, // 793 - uk + 3842, // 794 - uk-ua + 3847, // 795 - ur + 3849, // 796 - ur-in + 3854, // 797 - ur-pk + 3859, // 798 - uz + 3861, // 799 - uz-arab + 3868, // 800 - uz-arab-af + 3878, // 801 - uz-cyrl + 3885, // 802 - uz-cyrl-uz + 3895, // 803 - uz-latn + 3902, // 804 - uz-latn-uz + 3912, // 805 - vai + 3915, // 806 - vai-latn + 3923, // 807 - vai-latn-lr + 3934, // 808 - vai-vaii + 3942, // 809 - vai-vaii-lr + 3953, // 810 - ve + 3955, // 811 - ve-za + 3960, // 812 - vi + 3962, // 813 - vi-vn + 3967, // 814 - vo + 3969, // 815 - vo-001 + 3975, // 816 - vun + 3978, // 817 - vun-tz + 3984, // 818 - wae + 3987, // 819 - wae-ch + 3993, // 820 - wal + 3996, // 821 - wal-et + 4002, // 822 - wo + 4004, // 823 - wo-sn + 4009, // 824 - x-iv_mathan + 4020, // 825 - xh + 4022, // 826 - xh-za + 4027, // 827 - xog + 4030, // 828 - xog-ug + 4036, // 829 - yav + 4039, // 830 - yav-cm + 4045, // 831 - yi + 4047, // 832 - yi-001 + 4053, // 833 - yo + 4055, // 834 - yo-bj + 4060, // 835 - yo-ng + 4065, // 836 - yue + 4068, // 837 - yue-hk + 4074, // 838 - zgh + 4077, // 839 - zgh-tfng + 4085, // 840 - zgh-tfng-ma + 4096, // 841 - zh + 4098, // 842 - zh-chs + 4104, // 843 - zh-cht + 4110, // 844 - zh-cn + 4115, // 845 - zh-cn_phoneb + 4127, // 846 - zh-cn_stroke + 4139, // 847 - zh-hans + 4146, // 848 - zh-hans-hk + 4156, // 849 - zh-hans-mo + 4166, // 850 - zh-hant + 4173, // 851 - zh-hk + 4178, // 852 - zh-hk_radstr + 4190, // 853 - zh-mo + 4195, // 854 - zh-mo_radstr + 4207, // 855 - zh-mo_stroke + 4219, // 856 - zh-sg + 4224, // 857 - zh-sg_phoneb + 4236, // 858 - zh-sg_stroke + 4248, // 859 - zh-tw + 4253, // 860 - zh-tw_pronun + 4265, // 861 - zh-tw_radstr + 4277, // 862 - zu + 4279, // 863 - zu-za + 4284 + }; + + private const int NUMERIC_LOCALE_DATA_COUNT_PER_ROW = 9; + // s_nameIndexToNumericData is mapping from index in s_localeNamesIndices to locale data. + // each row in the table will have the following data: + // Lcid, Ansi codepage, Oem codepage, MAC codepage, EBCDIC codepage, Geo Id, Digit Substitution, specific locale index, Console locale index + private static readonly int[] s_nameIndexToNumericData = new int[] + { + // Lcid, Ansi CP, Oem CP, MAC CP, EBCDIC CP, Geo Id, digit substitution, Specific culture index, keyboard Id, Console locale index // index - locale name + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 3 , 240 , // 0 - aa + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3e , 1 , 1 , 240 , // 1 - aa-dj + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 2 , 240 , // 2 - aa-er + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 3 , 240 , // 3 - aa-et + 0x36 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 6 , 6 , // 4 - af + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfe , 1 , 5 , 240 , // 5 - af-na + 0x436 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 6 , 6 , // 6 - af-za + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 8 , 240 , // 7 - agq + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 8 , 240 , // 8 - agq-cm + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 10 , 240 , // 9 - ak + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 10 , 240 , // 10 - ak-gh + 0x5e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 12 , 143 , // 11 - am + 0x45e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 12 , 143 , // 12 - am-et + 0x1 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 , 33 , 143 , // 13 - ar + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x989e, 0 , 14 , 240 , // 14 - ar-001 + 0x3801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xe0 , 0 , 15 , 143 , // 15 - ar-ae + 0x3c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x11 , 0 , 16 , 143 , // 16 - ar-bh + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3e , 0 , 17 , 240 , // 17 - ar-dj + 0x1401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x4 , 1 , 18 , 300 , // 18 - ar-dz + 0xc01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x43 , 0 , 19 , 143 , // 19 - ar-eg + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x47 , 0 , 20 , 240 , // 20 - ar-er + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x75 , 0 , 21 , 240 , // 21 - ar-il + 0x801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 22 , 143 , // 22 - ar-iq + 0x2c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x7e , 0 , 23 , 143 , // 23 - ar-jo + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x32 , 0 , 24 , 240 , // 24 - ar-km + 0x3401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x88 , 0 , 25 , 143 , // 25 - ar-kw + 0x3001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x8b , 0 , 26 , 143 , // 26 - ar-lb + 0x1001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x94 , 1 , 27 , 143 , // 27 - ar-ly + 0x1801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 , 28 , 300 , // 28 - ar-ma + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xa2 , 0 , 29 , 240 , // 29 - ar-mr + 0x2001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xa4 , 0 , 30 , 143 , // 30 - ar-om + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xb8 , 0 , 31 , 240 , // 31 - ar-ps + 0x4001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xc5 , 0 , 32 , 143 , // 32 - ar-qa + 0x401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 , 33 , 143 , // 33 - ar-sa + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xdb , 0 , 34 , 240 , // 34 - ar-sd + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xd8 , 0 , 35 , 240 , // 35 - ar-so + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x114 , 0 , 36 , 240 , // 36 - ar-ss + 0x2801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xde , 0 , 37 , 143 , // 37 - ar-sy + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x29 , 0 , 38 , 240 , // 38 - ar-td + 0x1c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xea , 1 , 39 , 300 , // 39 - ar-tn + 0x2401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x105 , 0 , 40 , 143 , // 40 - ar-ye + 0x7a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 , 42 , 42 , // 41 - arn + 0x47a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 , 42 , 42 , // 42 - arn-cl + 0x4d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 44 , 143 , // 43 - as + 0x44d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 44 , 143 , // 44 - as-in + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 46 , 240 , // 45 - asa + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 46 , 240 , // 46 - asa-tz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd9 , 1 , 48 , 240 , // 47 - ast + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd9 , 1 , 48 , 240 , // 48 - ast-es + 0x2c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 , 53 , 53 , // 49 - az + 0x742c , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x5 , 1 , 51 , 51 , // 50 - az-cyrl + 0x82c , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x5 , 1 , 51 , 51 , // 51 - az-cyrl-az + 0x782c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 , 53 , 53 , // 52 - az-latn + 0x42c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 , 53 , 53 , // 53 - az-latn-az + 0x6d , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 55 , 55 , // 54 - ba + 0x46d , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 55 , 55 , // 55 - ba-ru + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 57 , 240 , // 56 - bas + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 57 , 240 , // 57 - bas-cm + 0x23 , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x1d , 1 , 59 , 59 , // 58 - be + 0x423 , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x1d , 1 , 59 , 59 , // 59 - be-by + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x107 , 1 , 61 , 240 , // 60 - bem + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x107 , 1 , 61 , 240 , // 61 - bem-zm + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 63 , 240 , // 62 - bez + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 63 , 240 , // 63 - bez-tz + 0x2 , 0x4e3 , 0x362 , 0x2717, 0x5221, 0x23 , 1 , 65 , 65 , // 64 - bg + 0x402 , 0x4e3 , 0x362 , 0x2717, 0x5221, 0x23 , 1 , 65 , 65 , // 65 - bg-bg + 0x66 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 67 , 240 , // 66 - bin + 0x466 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 67 , 240 , // 67 - bin-ng + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 70 , 240 , // 68 - bm + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 70 , 240 , // 69 - bm-latn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 70 , 240 , // 70 - bm-latn-ml + 0x45 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x17 , 1 , 72 , 143 , // 71 - bn + 0x845 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x17 , 1 , 72 , 143 , // 72 - bn-bd + 0x445 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 73 , 143 , // 73 - bn-in + 0x51 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 75 , 143 , // 74 - bo + 0x451 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 75 , 143 , // 75 - bo-cn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 76 , 240 , // 76 - bo-in + 0x7e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 78 , 78 , // 77 - br + 0x47e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 78 , 78 , // 78 - br-fr + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 80 , 240 , // 79 - brx + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 80 , 240 , // 80 - brx-in + 0x781a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 85 , 85 , // 81 - bs + 0x641a , 0x4e3 , 0x357 , 0x2762, 0x366 , 0x19 , 1 , 83 , 83 , // 82 - bs-cyrl + 0x201a , 0x4e3 , 0x357 , 0x2762, 0x366 , 0x19 , 1 , 83 , 83 , // 83 - bs-cyrl-ba + 0x681a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 85 , 85 , // 84 - bs-latn + 0x141a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 85 , 85 , // 85 - bs-latn-ba + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 87 , 240 , // 86 - byn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 87 , 240 , // 87 - byn-er + 0x3 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 90 , 90 , // 88 - ca + 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x8 , 1 , 89 , 240 , // 89 - ca-ad + 0x403 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 90 , 90 , // 90 - ca-es + 0x803 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 91 , 90 , // 91 - ca-es-valencia + 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x54 , 1 , 92 , 240 , // 92 - ca-fr + 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x76 , 1 , 93 , 240 , // 93 - ca-it + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 95 , 240 , // 94 - ce + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 95 , 240 , // 95 - ce-ru + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 97 , 240 , // 96 - cgg + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 97 , 240 , // 97 - cgg-ug + 0x5c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 100 , 240 , // 98 - chr + 0x7c5c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 100 , 240 , // 99 - chr-cher + 0x45c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 100 , 240 , // 100 - chr-cher-us + 0x83 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 102 , 102 , // 101 - co + 0x483 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 102 , 102 , // 102 - co-fr + 0x5 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x4b , 1 , 104 , 104 , // 103 - cs + 0x405 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x4b , 1 , 104 , 104 , // 104 - cs-cz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 106 , 240 , // 105 - cu + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 106 , 240 , // 106 - cu-ru + 0x52 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 108 , 108 , // 107 - cy + 0x452 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 108 , 108 , // 108 - cy-gb + 0x6 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x3d , 1 , 110 , 110 , // 109 - da + 0x406 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x3d , 1 , 110 , 110 , // 110 - da-dk + 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x5d , 1 , 111 , 240 , // 111 - da-gl + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 113 , 240 , // 112 - dav + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 113 , 240 , // 113 - dav-ke + 0x7 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 , 118 , 118 , // 114 - de + 0xc07 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xe , 1 , 115 , 115 , // 115 - de-at + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x15 , 1 , 116 , 240 , // 116 - de-be + 0x807 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 , 117 , 117 , // 117 - de-ch + 0x407 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 , 118 , 118 , // 118 - de-de + 0x10407, 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 , 118 , 118 , // 119 - de-de_phoneb + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 , 120 , 240 , // 120 - de-it + 0x1407 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x91 , 1 , 121 , 121 , // 121 - de-li + 0x1007 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x93 , 1 , 122 , 122 , // 122 - de-lu + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 124 , 240 , // 123 - dje + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 124 , 240 , // 124 - dje-ne + 0x7c2e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 126 , 126 , // 125 - dsb + 0x82e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 126 , 126 , // 126 - dsb-de + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 128 , 240 , // 127 - dua + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 128 , 240 , // 128 - dua-cm + 0x65 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa5 , 1 , 130 , 143 , // 129 - dv + 0x465 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa5 , 1 , 130 , 143 , // 130 - dv-mv + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd2 , 1 , 132 , 240 , // 131 - dyo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd2 , 1 , 132 , 240 , // 132 - dyo-sn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x22 , 2 , 134 , 240 , // 133 - dz + 0xc51 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x22 , 2 , 134 , 240 , // 134 - dz-bt + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 136 , 240 , // 135 - ebu + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 136 , 240 , // 136 - ebu-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 138 , 240 , // 137 - ee + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 138 , 240 , // 138 - ee-gh + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe8 , 1 , 139 , 240 , // 139 - ee-tg + 0x8 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x62 , 1 , 142 , 142 , // 140 - el + 0x1000 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x3b , 1 , 141 , 240 , // 141 - el-cy + 0x408 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x62 , 1 , 142 , 142 , // 142 - el-gr + 0x9 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 240 , 240 , // 143 - en + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x989e, 1 , 144 , 240 , // 144 - en-001 + 0x2409 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 , 145 , 145 , // 145 - en-029 + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x292d, 1 , 146 , 240 , // 146 - en-150 + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x2 , 1 , 147 , 240 , // 147 - en-ag + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12c , 1 , 148 , 240 , // 148 - en-ai + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa , 1 , 149 , 240 , // 149 - en-as + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe , 1 , 150 , 240 , // 150 - en-at + 0xc09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc , 1 , 151 , 151 , // 151 - en-au + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12 , 1 , 152 , 240 , // 152 - en-bb + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15 , 1 , 153 , 240 , // 153 - en-be + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 , 154 , 240 , // 154 - en-bi + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14 , 1 , 155 , 240 , // 155 - en-bm + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x16 , 1 , 156 , 240 , // 156 - en-bs + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13 , 1 , 157 , 240 , // 157 - en-bw + 0x2809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x18 , 1 , 158 , 158 , // 158 - en-bz + 0x1009 , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 , 159 , 159 , // 159 - en-ca + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x137 , 1 , 160 , 240 , // 160 - en-cc + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 161 , 240 , // 161 - en-ch + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x138 , 1 , 162 , 240 , // 162 - en-ck + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x31 , 1 , 163 , 240 , // 163 - en-cm + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x135 , 1 , 164 , 240 , // 164 - en-cx + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b , 1 , 165 , 240 , // 165 - en-cy + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 166 , 240 , // 166 - en-de + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3d , 1 , 167 , 240 , // 167 - en-dk + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x3f , 1 , 168 , 240 , // 168 - en-dm + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x47 , 1 , 169 , 240 , // 169 - en-er + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4d , 1 , 170 , 240 , // 170 - en-fi + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x4e , 1 , 171 , 240 , // 171 - en-fj + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13b , 1 , 172 , 240 , // 172 - en-fk + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x50 , 1 , 173 , 240 , // 173 - en-fm + 0x809 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 174 , 174 , // 174 - en-gb + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x5b , 1 , 175 , 240 , // 175 - en-gd + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x144 , 1 , 176 , 240 , // 176 - en-gg + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x59 , 1 , 177 , 240 , // 177 - en-gh + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x5a , 1 , 178 , 240 , // 178 - en-gi + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x56 , 1 , 179 , 240 , // 179 - en-gm + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x142 , 1 , 180 , 240 , // 180 - en-gu + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x65 , 1 , 181 , 240 , // 181 - en-gy + 0x3c09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x68 , 1 , 182 , 240 , // 182 - en-hk + 0x3809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 183 , 240 , // 183 - en-id + 0x1809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 , 184 , 184 , // 184 - en-ie + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x75 , 1 , 185 , 240 , // 185 - en-il + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x3b16, 1 , 186 , 240 , // 186 - en-im + 0x4009 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x71 , 1 , 187 , 187 , // 187 - en-in + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x72 , 1 , 188 , 240 , // 188 - en-io + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x148 , 1 , 189 , 240 , // 189 - en-je + 0x2009 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x7c , 1 , 190 , 190 , // 190 - en-jm + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x81 , 1 , 191 , 240 , // 191 - en-ke + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x85 , 1 , 192 , 240 , // 192 - en-ki + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xcf , 1 , 193 , 240 , // 193 - en-kn + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x133 , 1 , 194 , 240 , // 194 - en-ky + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xda , 1 , 195 , 240 , // 195 - en-lc + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x8e , 1 , 196 , 240 , // 196 - en-lr + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x92 , 1 , 197 , 240 , // 197 - en-ls + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x95 , 1 , 198 , 240 , // 198 - en-mg + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc7 , 1 , 199 , 240 , // 199 - en-mh + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x97 , 1 , 200 , 240 , // 200 - en-mo + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x151 , 1 , 201 , 240 , // 201 - en-mp + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14c , 1 , 202 , 240 , // 202 - en-ms + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa3 , 1 , 203 , 240 , // 203 - en-mt + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa0 , 1 , 204 , 240 , // 204 - en-mu + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9c , 1 , 205 , 240 , // 205 - en-mw + 0x4409 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xa7 , 1 , 206 , 206 , // 206 - en-my + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfe , 1 , 207 , 240 , // 207 - en-na + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x150 , 1 , 208 , 240 , // 208 - en-nf + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 209 , 240 , // 209 - en-ng + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb0 , 1 , 210 , 240 , // 210 - en-nl + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb4 , 1 , 211 , 240 , // 211 - en-nr + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14f , 1 , 212 , 240 , // 212 - en-nu + 0x1409 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb7 , 1 , 213 , 213 , // 213 - en-nz + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc2 , 1 , 214 , 240 , // 214 - en-pg + 0x3409 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 , 215 , 215 , // 215 - en-ph + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xbe , 1 , 216 , 240 , // 216 - en-pk + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x153 , 1 , 217 , 240 , // 217 - en-pn + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xca , 1 , 218 , 240 , // 218 - en-pr + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc3 , 1 , 219 , 240 , // 219 - en-pw + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xcc , 1 , 220 , 240 , // 220 - en-rw + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x1e , 1 , 221 , 240 , // 221 - en-sb + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd0 , 1 , 222 , 240 , // 222 - en-sc + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xdb , 1 , 223 , 240 , // 223 - en-sd + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdd , 1 , 224 , 240 , // 224 - en-se + 0x4809 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xd7 , 1 , 225 , 225 , // 225 - en-sg + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x157 , 1 , 226 , 240 , // 226 - en-sh + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd4 , 1 , 227 , 240 , // 227 - en-si + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd5 , 1 , 228 , 240 , // 228 - en-sl + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x114 , 1 , 229 , 240 , // 229 - en-ss + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x78f7, 1 , 230 , 240 , // 230 - en-sx + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x104 , 1 , 231 , 240 , // 231 - en-sz + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15d , 1 , 232 , 240 , // 232 - en-tc + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15b , 1 , 233 , 240 , // 233 - en-tk + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe7 , 1 , 234 , 240 , // 234 - en-to + 0x2c09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe1 , 1 , 235 , 235 , // 235 - en-tt + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xec , 1 , 236 , 240 , // 236 - en-tv + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xef , 1 , 237 , 240 , // 237 - en-tz + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xf0 , 1 , 238 , 240 , // 238 - en-ug + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9a55d40, 1 , 239 , 240 , // 239 - en-um + 0x409 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 240 , 240 , // 240 - en-us + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xf8 , 1 , 241 , 240 , // 241 - en-vc + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15f , 1 , 242 , 240 , // 242 - en-vg + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfc , 1 , 243 , 240 , // 243 - en-vi + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xae , 1 , 244 , 240 , // 244 - en-vu + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x103 , 1 , 245 , 240 , // 245 - en-ws + 0x1c09 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xd1 , 1 , 246 , 246 , // 246 - en-za + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x107 , 1 , 247 , 240 , // 247 - en-zm + 0x3009 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x108 , 1 , 248 , 248 , // 248 - en-zw + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 250 , 240 , // 249 - eo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 250 , 240 , // 250 - eo-001 + 0xa , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 , 262 , 262 , // 251 - es + 0x580a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x9a55d41, 1 , 252 , 240 , // 252 - es-419 + 0x2c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb , 1 , 253 , 253 , // 253 - es-ar + 0x400a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 , 254 , 254 , // 254 - es-bo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x20 , 1 , 255 , 240 , // 255 - es-br + 0x340a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 , 256 , 256 , // 256 - es-cl + 0x240a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x33 , 1 , 257 , 257 , // 257 - es-co + 0x140a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x36 , 1 , 258 , 258 , // 258 - es-cr + 0x5c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x38 , 1 , 259 , 240 , // 259 - es-cu + 0x1c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x41 , 1 , 260 , 260 , // 260 - es-do + 0x300a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x42 , 1 , 261 , 261 , // 261 - es-ec + 0xc0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 , 262 , 262 , // 262 - es-es + 0x40a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 , 263 , 263 , // 263 - es-es_tradnl + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x45 , 1 , 264 , 240 , // 264 - es-gq + 0x100a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 265 , 265 , // 265 - es-gt + 0x480a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x6a , 1 , 266 , 266 , // 266 - es-hn + 0x80a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xa6 , 1 , 267 , 267 , // 267 - es-mx + 0x4c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb6 , 1 , 268 , 268 , // 268 - es-ni + 0x180a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xc0 , 1 , 269 , 269 , // 269 - es-pa + 0x280a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xbb , 1 , 270 , 270 , // 270 - es-pe + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xc9 , 1 , 271 , 240 , // 271 - es-ph + 0x500a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xca , 1 , 272 , 272 , // 272 - es-pr + 0x3c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 , 273 , 273 , // 273 - es-py + 0x440a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x48 , 1 , 274 , 274 , // 274 - es-sv + 0x540a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf4 , 1 , 275 , 275 , // 275 - es-us + 0x380a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf6 , 1 , 276 , 276 , // 276 - es-uy + 0x200a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf9 , 1 , 277 , 277 , // 277 - es-ve + 0x25 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x46 , 1 , 279 , 279 , // 278 - et + 0x425 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x46 , 1 , 279 , 279 , // 279 - et-ee + 0x2d , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0xd9 , 1 , 281 , 240 , // 280 - eu + 0x42d , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0xd9 , 1 , 281 , 240 , // 281 - eu-es + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 283 , 240 , // 282 - ewo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 283 , 240 , // 283 - ewo-cm + 0x29 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x74 , 0 , 285 , 143 , // 284 - fa + 0x429 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x74 , 0 , 285 , 143 , // 285 - fa-ir + 0x67 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 290 , 290 , // 286 - ff + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x31 , 1 , 287 , 240 , // 287 - ff-cm + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x64 , 1 , 288 , 240 , // 288 - ff-gn + 0x7c67 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 290 , 290 , // 289 - ff-latn + 0x867 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 290 , 290 , // 290 - ff-latn-sn + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa2 , 1 , 291 , 240 , // 291 - ff-mr + 0x467 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xaf , 1 , 292 , 240 , // 292 - ff-ng + 0xb , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 294 , 294 , // 293 - fi + 0x40b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 294 , 294 , // 294 - fi-fi + 0x64 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 , 296 , 296 , // 295 - fil + 0x464 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 , 296 , 296 , // 296 - fil-ph + 0x38 , 0x4e4 , 0x352 , 0x275f, 0x4f35, 0x51 , 1 , 299 , 299 , // 297 - fo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3d , 1 , 298 , 240 , // 298 - fo-dk + 0x438 , 0x4e4 , 0x352 , 0x275f, 0x4f35, 0x51 , 1 , 299 , 299 , // 299 - fo-fo + 0xc , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 316 , 316 , // 300 - fr + 0x1c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x993248, 1 , 301 , 316 , // 301 - fr-029 + 0x80c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x15 , 1 , 302 , 302 , // 302 - fr-be + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xf5 , 1 , 303 , 240 , // 303 - fr-bf + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x26 , 1 , 304 , 240 , // 304 - fr-bi + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x1c , 1 , 305 , 240 , // 305 - fr-bj + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9a55c4f, 1 , 306 , 240 , // 306 - fr-bl + 0xc0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x27 , 1 , 307 , 307 , // 307 - fr-ca + 0x240c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x2c , 1 , 308 , 240 , // 308 - fr-cd + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x37 , 1 , 309 , 240 , // 309 - fr-cf + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x2b , 1 , 310 , 240 , // 310 - fr-cg + 0x100c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 , 311 , 311 , // 311 - fr-ch + 0x300c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x77 , 1 , 312 , 240 , // 312 - fr-ci + 0x2c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x31 , 1 , 313 , 240 , // 313 - fr-cm + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x3e , 1 , 314 , 240 , // 314 - fr-dj + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 315 , 240 , // 315 - fr-dz + 0x40c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 316 , 316 , // 316 - fr-fr + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x57 , 1 , 317 , 240 , // 317 - fr-ga + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x13d , 1 , 318 , 240 , // 318 - fr-gf + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x64 , 1 , 319 , 240 , // 319 - fr-gn + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x141 , 1 , 320 , 240 , // 320 - fr-gp + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x45 , 1 , 321 , 240 , // 321 - fr-gq + 0x3c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x67 , 1 , 322 , 240 , // 322 - fr-ht + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x32 , 1 , 323 , 240 , // 323 - fr-km + 0x140c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 , 324 , 324 , // 324 - fr-lu + 0x380c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9f , 1 , 325 , 240 , // 325 - fr-ma + 0x180c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9e , 1 , 326 , 326 , // 326 - fr-mc + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x7bda, 1 , 327 , 240 , // 327 - fr-mf + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x95 , 1 , 328 , 240 , // 328 - fr-mg + 0x340c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9d , 1 , 329 , 240 , // 329 - fr-ml + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14a , 1 , 330 , 240 , // 330 - fr-mq + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa2 , 1 , 331 , 240 , // 331 - fr-mr + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa0 , 1 , 332 , 240 , // 332 - fr-mu + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14e , 1 , 333 , 240 , // 333 - fr-nc + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xad , 1 , 334 , 240 , // 334 - fr-ne + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x13e , 1 , 335 , 240 , // 335 - fr-pf + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xce , 1 , 336 , 240 , // 336 - fr-pm + 0x200c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xc6 , 1 , 337 , 240 , // 337 - fr-re + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xcc , 1 , 338 , 240 , // 338 - fr-rw + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd0 , 1 , 339 , 240 , // 339 - fr-sc + 0x280c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 340 , 240 , // 340 - fr-sn + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xde , 1 , 341 , 240 , // 341 - fr-sy + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x29 , 1 , 342 , 240 , // 342 - fr-td + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xe8 , 1 , 343 , 240 , // 343 - fr-tg + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xea , 1 , 344 , 240 , // 344 - fr-tn + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xae , 1 , 345 , 240 , // 345 - fr-vu + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x160 , 1 , 346 , 240 , // 346 - fr-wf + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14b , 1 , 347 , 240 , // 347 - fr-yt + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 , 349 , 240 , // 348 - fur + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 , 349 , 240 , // 349 - fur-it + 0x62 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 351 , 351 , // 350 - fy + 0x462 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 351 , 351 , // 351 - fy-nl + 0x3c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 , 353 , 353 , // 352 - ga + 0x83c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 , 353 , 353 , // 353 - ga-ie + 0x91 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 355 , 355 , // 354 - gd + 0x491 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 355 , 355 , // 355 - gd-gb + 0x56 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 357 , 357 , // 356 - gl + 0x456 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 357 , 357 , // 357 - gl-es + 0x74 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 , 359 , 359 , // 358 - gn + 0x474 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 , 359 , 359 , // 359 - gn-py + 0x84 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 , 361 , 240 , // 360 - gsw + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 , 361 , 240 , // 361 - gsw-ch + 0x484 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 362 , 362 , // 362 - gsw-fr + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x91 , 1 , 363 , 240 , // 363 - gsw-li + 0x47 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 365 , 143 , // 364 - gu + 0x447 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 365 , 143 , // 365 - gu-in + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 367 , 240 , // 366 - guz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 367 , 240 , // 367 - guz-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b16, 1 , 369 , 240 , // 368 - gv + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b16, 1 , 369 , 240 , // 369 - gv-im + 0x68 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 374 , 374 , // 370 - ha + 0x7c68 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 374 , 374 , // 371 - ha-latn + 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x59 , 1 , 372 , 240 , // 372 - ha-latn-gh + 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xad , 1 , 373 , 240 , // 373 - ha-latn-ne + 0x468 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 374 , 374 , // 374 - ha-latn-ng + 0x75 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 376 , 376 , // 375 - haw + 0x475 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 376 , 376 , // 376 - haw-us + 0xd , 0x4e7 , 0x35e , 0x2715, 0x1f4 , 0x75 , 1 , 378 , 143 , // 377 - he + 0x40d , 0x4e7 , 0x35e , 0x2715, 0x1f4 , 0x75 , 1 , 378 , 143 , // 378 - he-il + 0x39 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 380 , 143 , // 379 - hi + 0x439 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 380 , 143 , // 380 - hi-in + 0x1a , 0x4e2 , 0x354 , 0x2762, 0x1f4 , 0x6c , 1 , 383 , 383 , // 381 - hr + 0x101a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 382 , 382 , // 382 - hr-ba + 0x41a , 0x4e2 , 0x354 , 0x2762, 0x1f4 , 0x6c , 1 , 383 , 383 , // 383 - hr-hr + 0x2e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 385 , 385 , // 384 - hsb + 0x42e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 385 , 385 , // 385 - hsb-de + 0xe , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 , 387 , 387 , // 386 - hu + 0x40e , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 , 387 , 387 , // 387 - hu-hu + 0x1040e, 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 , 387 , 387 , // 388 - hu-hu_technl + 0x2b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x7 , 1 , 390 , 390 , // 389 - hy + 0x42b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x7 , 1 , 390 , 390 , // 390 - hy-am + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x54 , 1 , 393 , 240 , // 391 - ia + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 392 , 240 , // 392 - ia-001 + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x54 , 1 , 393 , 240 , // 393 - ia-fr + 0x69 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 395 , 240 , // 394 - ibb + 0x469 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 395 , 240 , // 395 - ibb-ng + 0x21 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 397 , 397 , // 396 - id + 0x421 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 397 , 397 , // 397 - id-id + 0x70 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 399 , 399 , // 398 - ig + 0x470 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 399 , 399 , // 399 - ig-ng + 0x78 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 401 , 143 , // 400 - ii + 0x478 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 401 , 143 , // 401 - ii-cn + 0xf , 0x4e4 , 0x352 , 0x275f, 0x5187, 0x6e , 1 , 403 , 403 , // 402 - is + 0x40f , 0x4e4 , 0x352 , 0x275f, 0x5187, 0x6e , 1 , 403 , 403 , // 403 - is-is + 0x10 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0x76 , 1 , 406 , 406 , // 404 - it + 0x810 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xdf , 1 , 405 , 405 , // 405 - it-ch + 0x410 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0x76 , 1 , 406 , 406 , // 406 - it-it + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0xd6 , 1 , 407 , 240 , // 407 - it-sm + 0x5d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 , 412 , 412 , // 408 - iu + 0x785d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x27 , 1 , 410 , 143 , // 409 - iu-cans + 0x45d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x27 , 1 , 410 , 143 , // 410 - iu-cans-ca + 0x7c5d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 , 412 , 412 , // 411 - iu-latn + 0x85d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 , 412 , 412 , // 412 - iu-latn-ca + 0x11 , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 414 , 414 , // 413 - ja + 0x411 , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 414 , 414 , // 414 - ja-jp + 0x40411, 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 414 , 414 , // 415 - ja-jp_radstr + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 417 , 240 , // 416 - jgo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 417 , 240 , // 417 - jgo-cm + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 419 , 240 , // 418 - jmc + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 419 , 240 , // 419 - jmc-tz + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 424 , 424 , // 420 - jv + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 422 , 424 , // 421 - jv-java + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 422 , 424 , // 422 - jv-java-id + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 424 , 424 , // 423 - jv-latn + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 424 , 424 , // 424 - jv-latn-id + 0x37 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 426 , 426 , // 425 - ka + 0x437 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 426 , 426 , // 426 - ka-ge + 0x10437, 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 426 , 426 , // 427 - ka-ge_modern + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4 , 1 , 429 , 240 , // 428 - kab + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4 , 1 , 429 , 240 , // 429 - kab-dz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 431 , 240 , // 430 - kam + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 431 , 240 , // 431 - kam-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 433 , 240 , // 432 - kde + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 433 , 240 , // 433 - kde-tz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x39 , 1 , 435 , 240 , // 434 - kea + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x39 , 1 , 435 , 240 , // 435 - kea-cv + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 437 , 240 , // 436 - khq + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 437 , 240 , // 437 - khq-ml + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 439 , 240 , // 438 - ki + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 439 , 240 , // 439 - ki-ke + 0x3f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x89 , 1 , 441 , 441 , // 440 - kk + 0x43f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x89 , 1 , 441 , 441 , // 441 - kk-kz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 443 , 240 , // 442 - kkj + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 443 , 240 , // 443 - kkj-cm + 0x6f , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x5d , 1 , 445 , 445 , // 444 - kl + 0x46f , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x5d , 1 , 445 , 445 , // 445 - kl-gl + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 447 , 240 , // 446 - kln + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 447 , 240 , // 447 - kln-ke + 0x53 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x28 , 2 , 449 , 143 , // 448 - km + 0x453 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x28 , 2 , 449 , 143 , // 449 - km-kh + 0x4b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 451 , 143 , // 450 - kn + 0x44b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 451 , 143 , // 451 - kn-in + 0x12 , 0x3b5 , 0x3b5 , 0x2713, 0x5161, 0x86 , 1 , 454 , 454 , // 452 - ko + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x83 , 1 , 453 , 240 , // 453 - ko-kp + 0x412 , 0x3b5 , 0x3b5 , 0x2713, 0x5161, 0x86 , 1 , 454 , 454 , // 454 - ko-kr + 0x57 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 456 , 143 , // 455 - kok + 0x457 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 456 , 143 , // 456 - kok-in + 0x71 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 458 , 240 , // 457 - kr + 0x471 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 458 , 240 , // 458 - kr-ng + 0x60 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 461 , 240 , // 459 - ks + 0x460 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 461 , 240 , // 460 - ks-arab + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 461 , 240 , // 461 - ks-arab-in + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 463 , 187 , // 462 - ks-deva + 0x860 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 463 , 187 , // 463 - ks-deva-in + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 465 , 240 , // 464 - ksb + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 465 , 240 , // 465 - ksb-tz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 467 , 240 , // 466 - ksf + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 467 , 240 , // 467 - ksf-cm + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 469 , 240 , // 468 - ksh + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 469 , 240 , // 469 - ksh-de + 0x92 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 472 , 143 , // 470 - ku + 0x7c92 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 472 , 143 , // 471 - ku-arab + 0x492 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 472 , 143 , // 472 - ku-arab-iq + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 0 , 473 , 240 , // 473 - ku-arab-ir + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf2 , 1 , 475 , 240 , // 474 - kw + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf2 , 1 , 475 , 240 , // 475 - kw-gb + 0x40 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x82 , 1 , 477 , 477 , // 476 - ky + 0x440 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x82 , 1 , 477 , 477 , // 477 - ky-kg + 0x76 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x989e, 1 , 479 , 143 , // 478 - la + 0x476 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x989e, 1 , 479 , 143 , // 479 - la-001 + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 481 , 240 , // 480 - lag + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 481 , 240 , // 481 - lag-tz + 0x6e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 , 483 , 483 , // 482 - lb + 0x46e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 , 483 , 483 , // 483 - lb-lu + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 485 , 240 , // 484 - lg + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 485 , 240 , // 485 - lg-ug + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 487 , 240 , // 486 - lkt + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 487 , 240 , // 487 - lkt-us + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 490 , 240 , // 488 - ln + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9 , 1 , 489 , 240 , // 489 - ln-ao + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 490 , 240 , // 490 - ln-cd + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 , 491 , 240 , // 491 - ln-cf + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2b , 1 , 492 , 240 , // 492 - ln-cg + 0x54 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8a , 1 , 494 , 143 , // 493 - lo + 0x454 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8a , 1 , 494 , 143 , // 494 - lo-la + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 497 , 240 , // 495 - lrc + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x79 , 2 , 496 , 240 , // 496 - lrc-iq + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 497 , 240 , // 497 - lrc-ir + 0x27 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8d , 1 , 499 , 499 , // 498 - lt + 0x427 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8d , 1 , 499 , 499 , // 499 - lt-lt + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 501 , 240 , // 500 - lu + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 501 , 240 , // 501 - lu-cd + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 503 , 240 , // 502 - luo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 503 , 240 , // 503 - luo-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 505 , 240 , // 504 - luy + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 505 , 240 , // 505 - luy-ke + 0x26 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8c , 1 , 507 , 507 , // 506 - lv + 0x426 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8c , 1 , 507 , 507 , // 507 - lv-lv + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 509 , 240 , // 508 - mas + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 509 , 240 , // 509 - mas-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 510 , 240 , // 510 - mas-tz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 512 , 240 , // 511 - mer + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 512 , 240 , // 512 - mer-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa0 , 1 , 514 , 240 , // 513 - mfe + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa0 , 1 , 514 , 240 , // 514 - mfe-mu + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x95 , 1 , 516 , 240 , // 515 - mg + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x95 , 1 , 516 , 240 , // 516 - mg-mg + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 518 , 240 , // 517 - mgh + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 518 , 240 , // 518 - mgh-mz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 520 , 240 , // 519 - mgo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 520 , 240 , // 520 - mgo-cm + 0x81 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb7 , 1 , 522 , 522 , // 521 - mi + 0x481 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb7 , 1 , 522 , 522 , // 522 - mi-nz + 0x2f , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x4ca2, 1 , 524 , 524 , // 523 - mk + 0x42f , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x4ca2, 1 , 524 , 524 , // 524 - mk-mk + 0x4c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 526 , 143 , // 525 - ml + 0x44c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 526 , 143 , // 526 - ml-in + 0x50 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 , 529 , 529 , // 527 - mn + 0x7850 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 , 529 , 529 , // 528 - mn-cyrl + 0x450 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 , 529 , 529 , // 529 - mn-mn + 0x7c50 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 531 , 531 , // 530 - mn-mong + 0x850 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 531 , 531 , // 531 - mn-mong-cn + 0xc50 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9a , 1 , 532 , 532 , // 532 - mn-mong-mn + 0x58 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 534 , 187 , // 533 - mni + 0x458 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 534 , 187 , // 534 - mni-in + 0x7c , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 , 536 , 240 , // 535 - moh + 0x47c , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 , 536 , 240 , // 536 - moh-ca + 0x4e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 538 , 143 , // 537 - mr + 0x44e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 538 , 143 , // 538 - mr-in + 0x3e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa7 , 1 , 541 , 541 , // 539 - ms + 0x83e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x25 , 1 , 540 , 540 , // 540 - ms-bn + 0x43e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa7 , 1 , 541 , 541 , // 541 - ms-my + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd7 , 1 , 542 , 240 , // 542 - ms-sg + 0x3a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa3 , 1 , 544 , 544 , // 543 - mt + 0x43a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa3 , 1 , 544 , 544 , // 544 - mt-mt + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 546 , 240 , // 545 - mua + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 546 , 240 , // 546 - mua-cm + 0x55 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x1b , 2 , 548 , 240 , // 547 - my + 0x455 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x1b , 2 , 548 , 240 , // 548 - my-mm + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 550 , 240 , // 549 - mzn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 550 , 240 , // 550 - mzn-ir + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xfe , 1 , 552 , 240 , // 551 - naq + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xfe , 1 , 552 , 240 , // 552 - naq-na + 0x7c14 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 554 , 554 , // 553 - nb + 0x414 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 554 , 554 , // 554 - nb-no + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xdc , 1 , 555 , 240 , // 555 - nb-sj + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 557 , 240 , // 556 - nd + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 557 , 240 , // 557 - nd-zw + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 559 , 240 , // 558 - nds + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 559 , 240 , // 559 - nds-de + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb0 , 1 , 560 , 240 , // 560 - nds-nl + 0x61 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb2 , 1 , 563 , 143 , // 561 - ne + 0x861 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 562 , 240 , // 562 - ne-in + 0x461 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb2 , 1 , 563 , 143 , // 563 - ne-np + 0x13 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 569 , 569 , // 564 - nl + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12e , 1 , 565 , 240 , // 565 - nl-aw + 0x813 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15 , 1 , 566 , 566 , // 566 - nl-be + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9a55d42, 1 , 567 , 240 , // 567 - nl-bq + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x111 , 1 , 568 , 240 , // 568 - nl-cw + 0x413 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 569 , 569 , // 569 - nl-nl + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb5 , 1 , 570 , 240 , // 570 - nl-sr + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x78f7, 1 , 571 , 240 , // 571 - nl-sx + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 573 , 240 , // 572 - nmg + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 573 , 240 , // 573 - nmg-cm + 0x7814 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 575 , 575 , // 574 - nn + 0x814 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 575 , 575 , // 575 - nn-no + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 577 , 240 , // 576 - nnh + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 577 , 240 , // 577 - nnh-cm + 0x14 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 554 , 554 , // 578 - no + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x64 , 2 , 580 , 143 , // 579 - nqo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x64 , 2 , 580 , 143 , // 580 - nqo-gn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 582 , 240 , // 581 - nr + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 582 , 240 , // 582 - nr-za + 0x6c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 584 , 584 , // 583 - nso + 0x46c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 584 , 584 , // 584 - nso-za + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x114 , 1 , 586 , 240 , // 585 - nus + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x114 , 1 , 586 , 240 , // 586 - nus-ss + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 588 , 240 , // 587 - nyn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 588 , 240 , // 588 - nyn-ug + 0x82 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 590 , 590 , // 589 - oc + 0x482 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 590 , 590 , // 590 - oc-fr + 0x72 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 592 , 240 , // 591 - om + 0x472 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 592 , 240 , // 592 - om-et + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 593 , 240 , // 593 - om-ke + 0x48 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 595 , 143 , // 594 - or + 0x448 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 595 , 143 , // 595 - or-in + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 597 , 240 , // 596 - os + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 597 , 240 , // 597 - os-ge + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 598 , 240 , // 598 - os-ru + 0x46 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 602 , 143 , // 599 - pa + 0x7c46 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 601 , 143 , // 600 - pa-arab + 0x846 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 601 , 143 , // 601 - pa-arab-pk + 0x446 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 602 , 143 , // 602 - pa-in + 0x79 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 , 604 , 145 , // 603 - pap + 0x479 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 , 604 , 145 , // 604 - pap-029 + 0x15 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xbf , 1 , 606 , 606 , // 605 - pl + 0x415 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xbf , 1 , 606 , 606 , // 606 - pl-pl + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 608 , 240 , // 607 - prg + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 608 , 240 , // 608 - prg-001 + 0x8c , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3 , 2 , 610 , 143 , // 609 - prs + 0x48c , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3 , 2 , 610 , 143 , // 610 - prs-af + 0x63 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 612 , 143 , // 611 - ps + 0x463 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 612 , 143 , // 612 - ps-af + 0x16 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x20 , 1 , 615 , 615 , // 613 - pt + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9 , 1 , 614 , 240 , // 614 - pt-ao + 0x416 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x20 , 1 , 615 , 615 , // 615 - pt-br + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 616 , 240 , // 616 - pt-ch + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x39 , 1 , 617 , 240 , // 617 - pt-cv + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x45 , 1 , 618 , 240 , // 618 - pt-gq + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc4 , 1 , 619 , 240 , // 619 - pt-gw + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x93 , 1 , 620 , 240 , // 620 - pt-lu + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x97 , 1 , 621 , 240 , // 621 - pt-mo + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa8 , 1 , 622 , 240 , // 622 - pt-mz + 0x816 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc1 , 1 , 623 , 623 , // 623 - pt-pt + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe9 , 1 , 624 , 240 , // 624 - pt-st + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f60e7, 1 , 625 , 240 , // 625 - pt-tl + 0x901 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x7c , 1 , 626 , 190 , // 626 - qps-latn-x-sh + 0x501 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xf4 , 1 , 627 , 627 , // 627 - qps-ploc + 0x5fe , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 628 , 628 , // 628 - qps-ploca + 0x9ff , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 , 629 , 143 , // 629 - qps-plocm + 0x86 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 632 , 632 , // 630 - quc + 0x7c86 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 632 , 632 , // 631 - quc-latn + 0x486 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 632 , 632 , // 632 - quc-latn-gt + 0x6b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 , 634 , 634 , // 633 - quz + 0x46b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 , 634 , 634 , // 634 - quz-bo + 0x86b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x42 , 1 , 635 , 635 , // 635 - quz-ec + 0xc6b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xbb , 1 , 636 , 636 , // 636 - quz-pe + 0x17 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 , 638 , 638 , // 637 - rm + 0x417 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 , 638 , 638 , // 638 - rm-ch + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 , 640 , 240 , // 639 - rn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 , 640 , 240 , // 640 - rn-bi + 0x18 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xc8 , 1 , 643 , 643 , // 641 - ro + 0x818 , 0x4e2 , 0x354 , 0x2 , 0x1f4 , 0x98 , 1 , 642 , 240 , // 642 - ro-md + 0x418 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xc8 , 1 , 643 , 643 , // 643 - ro-ro + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 645 , 240 , // 644 - rof + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 645 , 240 , // 645 - rof-tz + 0x19 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 651 , 651 , // 646 - ru + 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x1d , 1 , 647 , 240 , // 647 - ru-by + 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x82 , 1 , 648 , 240 , // 648 - ru-kg + 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x89 , 1 , 649 , 240 , // 649 - ru-kz + 0x819 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x98 , 1 , 650 , 240 , // 650 - ru-md + 0x419 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 651 , 651 , // 651 - ru-ru + 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0xf1 , 1 , 652 , 240 , // 652 - ru-ua + 0x87 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xcc , 1 , 654 , 654 , // 653 - rw + 0x487 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xcc , 1 , 654 , 654 , // 654 - rw-rw + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 656 , 240 , // 655 - rwk + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 656 , 240 , // 656 - rwk-tz + 0x4f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 658 , 143 , // 657 - sa + 0x44f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 658 , 143 , // 658 - sa-in + 0x85 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 660 , 660 , // 659 - sah + 0x485 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 660 , 660 , // 660 - sah-ru + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 662 , 240 , // 661 - saq + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 662 , 240 , // 662 - saq-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 664 , 240 , // 663 - sbp + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 664 , 240 , // 664 - sbp-tz + 0x59 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 667 , 143 , // 665 - sd + 0x7c59 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 667 , 143 , // 666 - sd-arab + 0x859 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 667 , 143 , // 667 - sd-arab-pk + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 669 , 187 , // 668 - sd-deva + 0x459 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 669 , 187 , // 669 - sd-deva-in + 0x3b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 672 , 672 , // 670 - se + 0xc3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 671 , 671 , // 671 - se-fi + 0x43b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 672 , 672 , // 672 - se-no + 0x83b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 673 , 673 , // 673 - se-se + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 675 , 240 , // 674 - seh + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 675 , 240 , // 675 - seh-mz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 677 , 240 , // 676 - ses + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 677 , 240 , // 677 - ses-ml + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 , 679 , 240 , // 678 - sg + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 , 679 , 240 , // 679 - sg-cf + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 684 , 240 , // 680 - shi + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 682 , 240 , // 681 - shi-latn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 682 , 240 , // 682 - shi-latn-ma + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 684 , 240 , // 683 - shi-tfng + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 684 , 240 , // 684 - shi-tfng-ma + 0x5b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 , 686 , 143 , // 685 - si + 0x45b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 , 686 , 143 , // 686 - si-lk + 0x1b , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x8f , 1 , 688 , 688 , // 687 - sk + 0x41b , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x8f , 1 , 688 , 688 , // 688 - sk-sk + 0x24 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xd4 , 1 , 690 , 690 , // 689 - sl + 0x424 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xd4 , 1 , 690 , 690 , // 690 - sl-si + 0x783b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 693 , 693 , // 691 - sma + 0x183b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 692 , 692 , // 692 - sma-no + 0x1c3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 693 , 693 , // 693 - sma-se + 0x7c3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 696 , 696 , // 694 - smj + 0x103b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 695 , 695 , // 695 - smj-no + 0x143b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 696 , 696 , // 696 - smj-se + 0x703b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 698 , 698 , // 697 - smn + 0x243b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 698 , 698 , // 698 - smn-fi + 0x743b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 700 , 700 , // 699 - sms + 0x203b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 700 , 700 , // 700 - sms-fi + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 703 , 240 , // 701 - sn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 703 , 240 , // 702 - sn-latn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 703 , 240 , // 703 - sn-latn-zw + 0x77 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd8 , 1 , 708 , 240 , // 704 - so + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3e , 1 , 705 , 240 , // 705 - so-dj + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 706 , 240 , // 706 - so-et + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 707 , 240 , // 707 - so-ke + 0x477 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd8 , 1 , 708 , 240 , // 708 - so-so + 0x1c , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x6 , 1 , 710 , 710 , // 709 - sq + 0x41c , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x6 , 1 , 710 , 710 , // 710 - sq-al + 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x4ca2, 1 , 711 , 240 , // 711 - sq-mk + 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x974941, 1 , 712 , 240 , // 712 - sq-xk + 0x7c1a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 , 724 , 724 , // 713 - sr + 0x6c1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10f , 1 , 718 , 718 , // 714 - sr-cyrl + 0x1c1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x19 , 1 , 715 , 715 , // 715 - sr-cyrl-ba + 0xc1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10d , 1 , 716 , 716 , // 716 - sr-cyrl-cs + 0x301a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10e , 1 , 717 , 717 , // 717 - sr-cyrl-me + 0x281a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10f , 1 , 718 , 718 , // 718 - sr-cyrl-rs + 0x1000 , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x974941, 1 , 719 , 240 , // 719 - sr-cyrl-xk + 0x701a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 , 724 , 724 , // 720 - sr-latn + 0x181a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 721 , 721 , // 721 - sr-latn-ba + 0x81a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10d , 1 , 722 , 722 , // 722 - sr-latn-cs + 0x2c1a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10e , 1 , 723 , 723 , // 723 - sr-latn-me + 0x241a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 , 724 , 724 , // 724 - sr-latn-rs + 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x974941, 1 , 725 , 240 , // 725 - sr-latn-xk + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 728 , 240 , // 726 - ss + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x104 , 1 , 727 , 240 , // 727 - ss-sz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 728 , 240 , // 728 - ss-za + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 730 , 240 , // 729 - ssy + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 730 , 240 , // 730 - ssy-er + 0x30 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 733 , 240 , // 731 - st + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x92 , 1 , 732 , 240 , // 732 - st-ls + 0x430 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 733 , 240 , // 733 - st-za + 0x1d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 737 , 737 , // 734 - sv + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x9906f5, 1 , 735 , 240 , // 735 - sv-ax + 0x81d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 736 , 736 , // 736 - sv-fi + 0x41d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 737 , 737 , // 737 - sv-se + 0x41 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x81 , 1 , 740 , 740 , // 738 - sw + 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x2c , 1 , 739 , 740 , // 739 - sw-cd + 0x441 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x81 , 1 , 740 , 740 , // 740 - sw-ke + 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xef , 1 , 741 , 240 , // 741 - sw-tz + 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xf0 , 1 , 742 , 240 , // 742 - sw-ug + 0x1000 , 0x0 , 0x1 , 0x0 , 0x1f4 , 0x2c , 1 , 744 , 240 , // 743 - swc + 0x1000 , 0x0 , 0x1 , 0x0 , 0x1f4 , 0x2c , 1 , 744 , 240 , // 744 - swc-cd + 0x5a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xde , 1 , 746 , 143 , // 745 - syr + 0x45a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xde , 1 , 746 , 143 , // 746 - syr-sy + 0x49 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 748 , 143 , // 747 - ta + 0x449 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 748 , 143 , // 748 - ta-in + 0x849 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 , 749 , 143 , // 749 - ta-lk + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa7 , 1 , 750 , 240 , // 750 - ta-my + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd7 , 1 , 751 , 240 , // 751 - ta-sg + 0x4a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 753 , 143 , // 752 - te + 0x44a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 753 , 143 , // 753 - te-in + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 756 , 240 , // 754 - teo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 755 , 240 , // 755 - teo-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 756 , 240 , // 756 - teo-ug + 0x28 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 , 759 , 759 , // 757 - tg + 0x7c28 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 , 759 , 759 , // 758 - tg-cyrl + 0x428 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 , 759 , 759 , // 759 - tg-cyrl-tj + 0x1e , 0x36a , 0x36a , 0x2725, 0x5166, 0xe3 , 1 , 761 , 143 , // 760 - th + 0x41e , 0x36a , 0x36a , 0x2725, 0x5166, 0xe3 , 1 , 761 , 143 , // 761 - th-th + 0x73 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 763 , 143 , // 762 - ti + 0x873 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 763 , 143 , // 763 - ti-er + 0x473 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 764 , 143 , // 764 - ti-et + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 766 , 240 , // 765 - tig + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 766 , 240 , // 766 - tig-er + 0x42 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xee , 1 , 768 , 768 , // 767 - tk + 0x442 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xee , 1 , 768 , 768 , // 768 - tk-tm + 0x32 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 771 , 771 , // 769 - tn + 0x832 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13 , 1 , 770 , 770 , // 770 - tn-bw + 0x432 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 771 , 771 , // 771 - tn-za + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe7 , 1 , 773 , 240 , // 772 - to + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe7 , 1 , 773 , 240 , // 773 - to-to + 0x1f , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0xeb , 1 , 776 , 776 , // 774 - tr + 0x1000 , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x3b , 1 , 775 , 240 , // 775 - tr-cy + 0x41f , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0xeb , 1 , 776 , 776 , // 776 - tr-tr + 0x31 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 778 , 240 , // 777 - ts + 0x431 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 778 , 240 , // 778 - ts-za + 0x44 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 780 , 780 , // 779 - tt + 0x444 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 780 , 780 , // 780 - tt-ru + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 782 , 240 , // 781 - twq + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 782 , 240 , // 782 - twq-ne + 0x5f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 787 , 787 , // 783 - tzm + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 , 785 , 240 , // 784 - tzm-arab + 0x45f , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 , 785 , 240 , // 785 - tzm-arab-ma + 0x7c5f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 787 , 787 , // 786 - tzm-latn + 0x85f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 787 , 787 , // 787 - tzm-latn-dz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 788 , 240 , // 788 - tzm-latn-ma + 0x785f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 790 , 316 , // 789 - tzm-tfng + 0x105f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 790 , 316 , // 790 - tzm-tfng-ma + 0x80 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x2d , 1 , 792 , 143 , // 791 - ug + 0x480 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x2d , 1 , 792 , 143 , // 792 - ug-cn + 0x22 , 0x4e3 , 0x362 , 0x2721, 0x1f4 , 0xf1 , 1 , 794 , 794 , // 793 - uk + 0x422 , 0x4e3 , 0x362 , 0x2721, 0x1f4 , 0xf1 , 1 , 794 , 794 , // 794 - uk-ua + 0x20 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 1 , 797 , 143 , // 795 - ur + 0x820 , 0x4e8 , 0x2d0 , 0x2 , 0x1f4 , 0x71 , 2 , 796 , 240 , // 796 - ur-in + 0x420 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 1 , 797 , 143 , // 797 - ur-pk + 0x43 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 , 804 , 804 , // 798 - uz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 800 , 240 , // 799 - uz-arab + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 800 , 240 , // 800 - uz-arab-af + 0x7843 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xf7 , 1 , 802 , 802 , // 801 - uz-cyrl + 0x843 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xf7 , 1 , 802 , 802 , // 802 - uz-cyrl-uz + 0x7c43 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 , 804 , 804 , // 803 - uz-latn + 0x443 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 , 804 , 804 , // 804 - uz-latn-uz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 809 , 240 , // 805 - vai + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 807 , 240 , // 806 - vai-latn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 807 , 240 , // 807 - vai-latn-lr + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 809 , 240 , // 808 - vai-vaii + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 809 , 240 , // 809 - vai-vaii-lr + 0x33 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 811 , 240 , // 810 - ve + 0x433 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 811 , 240 , // 811 - ve-za + 0x2a , 0x4ea , 0x4ea , 0x2710, 0x1f4 , 0xfb , 1 , 813 , 143 , // 812 - vi + 0x42a , 0x4ea , 0x4ea , 0x2710, 0x1f4 , 0xfb , 1 , 813 , 143 , // 813 - vi-vn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 815 , 240 , // 814 - vo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 815 , 240 , // 815 - vo-001 + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 817 , 240 , // 816 - vun + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 817 , 240 , // 817 - vun-tz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 819 , 240 , // 818 - wae + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 819 , 240 , // 819 - wae-ch + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 821 , 240 , // 820 - wal + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 821 , 240 , // 821 - wal-et + 0x88 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 823 , 823 , // 822 - wo + 0x488 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 823 , 823 , // 823 - wo-sn + 0x1007f, 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , -1 , -1 , // 824 - x-iv_mathan + 0x34 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 826 , 826 , // 825 - xh + 0x434 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 826 , 826 , // 826 - xh-za + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 828 , 240 , // 827 - xog + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 828 , 240 , // 828 - xog-ug + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 830 , 240 , // 829 - yav + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 830 , 240 , // 830 - yav-cm + 0x3d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 832 , 240 , // 831 - yi + 0x43d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 832 , 240 , // 832 - yi-001 + 0x6a , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 835 , 835 , // 833 - yo + 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x1c , 1 , 834 , 240 , // 834 - yo-bj + 0x46a , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 835 , 835 , // 835 - yo-ng + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x68 , 1 , 837 , 240 , // 836 - yue + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x68 , 1 , 837 , 240 , // 837 - yue-hk + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 840 , 316 , // 838 - zgh + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 840 , 316 , // 839 - zgh-tfng + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 840 , 316 , // 840 - zgh-tfng-ma + 0x7804 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 841 - zh + 0x4 , 0x3a8 , 0x3a8 , 0x0 , 0x1f4 , 0x2d , 1 , 844 , 844 , // 842 - zh-chs + 0x7c04 , 0x3b6 , 0x3b6 , 0x0 , 0x1f4 , 0x68 , 1 , 851 , 851 , // 843 - zh-cht + 0x804 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 844 - zh-cn + 0x50804, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 845 - zh-cn_phoneb + 0x20804, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 846 - zh-cn_stroke + 0x4 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 847 - zh-hans + 0x1000 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x68 , 1 , 848 , 240 , // 848 - zh-hans-hk + 0x1000 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x97 , 1 , 849 , 240 , // 849 - zh-hans-mo + 0x7c04 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 , 851 , 851 , // 850 - zh-hant + 0xc04 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 , 851 , 851 , // 851 - zh-hk + 0x40c04, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 , 851 , 851 , // 852 - zh-hk_radstr + 0x1404 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 , 853 , 853 , // 853 - zh-mo + 0x41404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 , 853 , 853 , // 854 - zh-mo_radstr + 0x21404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 , 853 , 853 , // 855 - zh-mo_stroke + 0x1004 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 , 856 , 856 , // 856 - zh-sg + 0x51004, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 , 856 , 856 , // 857 - zh-sg_phoneb + 0x21004, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 , 856 , 856 , // 858 - zh-sg_stroke + 0x404 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 , 859 , 859 , // 859 - zh-tw + 0x30404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 , 859 , 859 , // 860 - zh-tw_pronun + 0x40404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 , 859 , 859 , // 861 - zh-tw_radstr + 0x35 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 863 , 863 , // 862 - zu + 0x435 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 863 , 863 , // 863 - zu-za + }; + + // s_lcids list all supported lcids. used to binary search and we use the index of the matched lcid to + // get the index in s_localeNamesIndices using s_lcidToCultureNameIndices + private static readonly int[] s_lcids = new int[] + { + // Lcid , index - index in c_localeNames + 0x1 , // 0 - 52 + 0x2 , // 1 - 301 + 0x3 , // 2 - 421 + 0x4 , // 3 - 4139 + 0x5 , // 4 - 502 + 0x6 , // 5 - 523 + 0x7 , // 6 - 544 + 0x8 , // 7 - 664 + 0x9 , // 8 - 676 + 0xa , // 9 - 1214 + 0xb , // 10 - 1423 + 0xc , // 11 - 1451 + 0xd , // 12 - 1825 + 0xe , // 13 - 1860 + 0xf , // 14 - 1929 + 0x10 , // 15 - 1936 + 0x11 , // 16 - 1989 + 0x12 , // 17 - 2179 + 0x13 , // 18 - 2685 + 0x14 , // 19 - 2747 + 0x15 , // 20 - 2864 + 0x16 , // 21 - 2897 + 0x17 , // 22 - 3041 + 0x18 , // 23 - 3055 + 0x19 , // 24 - 3076 + 0x1a , // 25 - 1839 + 0x1b , // 26 - 3284 + 0x1c , // 27 - 3387 + 0x1d , // 28 - 3553 + 0x1e , // 29 - 3673 + 0x1f , // 30 - 3727 + 0x20 , // 31 - 3847 + 0x21 , // 32 - 1908 + 0x22 , // 33 - 3840 + 0x23 , // 34 - 276 + 0x24 , // 35 - 3291 + 0x25 , // 36 - 1354 + 0x26 , // 37 - 2429 + 0x27 , // 38 - 2397 + 0x28 , // 39 - 3654 + 0x29 , // 40 - 1377 + 0x2a , // 41 - 3960 + 0x2b , // 42 - 1879 + 0x2c , // 43 - 224 + 0x2d , // 44 - 1361 + 0x2e , // 45 - 1851 + 0x2f , // 46 - 2501 + 0x30 , // 47 - 3541 + 0x31 , // 48 - 3739 + 0x32 , // 49 - 3708 + 0x33 , // 50 - 3953 + 0x34 , // 51 - 4020 + 0x35 , // 52 - 4277 + 0x36 , // 53 - 17 + 0x37 , // 54 - 2062 + 0x38 , // 55 - 1439 + 0x39 , // 56 - 1832 + 0x3a , // 57 - 2598 + 0x3b , // 58 - 3194 + 0x3c , // 59 - 1705 + 0x3d , // 60 - 4045 + 0x3e , // 61 - 2581 + 0x3f , // 62 - 2133 + 0x40 , // 63 - 2306 + 0x41 , // 64 - 3570 + 0x42 , // 65 - 3701 + 0x43 , // 66 - 3859 + 0x44 , // 67 - 3746 + 0x45 , // 68 - 336 + 0x46 , // 69 - 2830 + 0x47 , // 70 - 1754 + 0x48 , // 71 - 2811 + 0x49 , // 72 - 3610 + 0x4a , // 73 - 3632 + 0x4b , // 74 - 2172 + 0x4c , // 75 - 2508 + 0x4d , // 76 - 199 + 0x4e , // 77 - 2574 + 0x4f , // 78 - 3124 + 0x50 , // 79 - 2515 + 0x51 , // 80 - 348 + 0x52 , // 81 - 516 + 0x53 , // 82 - 2165 + 0x54 , // 83 - 2375 + 0x55 , // 84 - 2614 + 0x56 , // 85 - 1719 + 0x57 , // 86 - 2191 + 0x58 , // 87 - 2556 + 0x59 , // 88 - 3158 + 0x5a , // 89 - 3601 + 0x5b , // 90 - 3277 + 0x5c , // 91 - 473 + 0x5d , // 92 - 1953 + 0x5e , // 93 - 45 + 0x5f , // 94 - 3762 + 0x60 , // 95 - 2207 + 0x61 , // 96 - 2673 + 0x62 , // 97 - 1698 + 0x63 , // 98 - 2890 + 0x64 , // 99 - 1430 + 0x65 , // 100 - 620 + 0x66 , // 101 - 308 + 0x67 , // 102 - 1384 + 0x68 , // 103 - 1777 + 0x69 , // 104 - 1899 + 0x6a , // 105 - 4053 + 0x6b , // 106 - 3020 + 0x6c , // 107 - 2765 + 0x6d , // 108 - 260 + 0x6e , // 109 - 2330 + 0x6f , // 110 - 2149 + 0x70 , // 111 - 1915 + 0x71 , // 112 - 2200 + 0x72 , // 113 - 2799 + 0x73 , // 114 - 3680 + 0x74 , // 115 - 1726 + 0x75 , // 116 - 1816 + 0x76 , // 117 - 2313 + 0x77 , // 118 - 3365 + 0x78 , // 119 - 1922 + 0x79 , // 120 - 2854 + 0x7a , // 121 - 190 + 0x7c , // 122 - 2565 + 0x7e , // 123 - 360 + 0x80 , // 124 - 3833 + 0x81 , // 125 - 2494 + 0x82 , // 126 - 2792 + 0x83 , // 127 - 495 + 0x84 , // 128 - 1733 + 0x85 , // 129 - 3131 + 0x86 , // 130 - 2998 + 0x87 , // 131 - 3108 + 0x88 , // 132 - 4002 + 0x8c , // 133 - 2881 + 0x91 , // 134 - 1712 + 0x92 , // 135 - 2270 + 0x401 , // 136 - 150 + 0x402 , // 137 - 303 + 0x403 , // 138 - 428 + 0x404 , // 139 - 4248 + 0x405 , // 140 - 504 + 0x406 , // 141 - 525 + 0x407 , // 142 - 561 + 0x408 , // 143 - 671 + 0x409 , // 144 - 1161 + 0x40a , // 145 - 1272 + 0x40b , // 146 - 1425 + 0x40c , // 147 - 1529 + 0x40d , // 148 - 1827 + 0x40e , // 149 - 1862 + 0x40f , // 150 - 1931 + 0x410 , // 151 - 1943 + 0x411 , // 152 - 1991 + 0x412 , // 153 - 2186 + 0x413 , // 154 - 2707 + 0x414 , // 155 - 2641 + 0x415 , // 156 - 2866 + 0x416 , // 157 - 2904 + 0x417 , // 158 - 3043 + 0x418 , // 159 - 3062 + 0x419 , // 160 - 3098 + 0x41a , // 161 - 1846 + 0x41b , // 162 - 3286 + 0x41c , // 163 - 3389 + 0x41d , // 164 - 3565 + 0x41e , // 165 - 3675 + 0x41f , // 166 - 3734 + 0x420 , // 167 - 3854 + 0x421 , // 168 - 1910 + 0x422 , // 169 - 3842 + 0x423 , // 170 - 278 + 0x424 , // 171 - 3293 + 0x425 , // 172 - 1356 + 0x426 , // 173 - 2431 + 0x427 , // 174 - 2399 + 0x428 , // 175 - 3663 + 0x429 , // 176 - 1379 + 0x42a , // 177 - 3962 + 0x42b , // 178 - 1881 + 0x42c , // 179 - 250 + 0x42d , // 180 - 1363 + 0x42e , // 181 - 1854 + 0x42f , // 182 - 2503 + 0x430 , // 183 - 3548 + 0x431 , // 184 - 3741 + 0x432 , // 185 - 3715 + 0x433 , // 186 - 3955 + 0x434 , // 187 - 4022 + 0x435 , // 188 - 4279 + 0x436 , // 189 - 24 + 0x437 , // 190 - 2064 + 0x438 , // 191 - 1446 + 0x439 , // 192 - 1834 + 0x43a , // 193 - 2600 + 0x43b , // 194 - 3201 + 0x43d , // 195 - 4047 + 0x43e , // 196 - 2588 + 0x43f , // 197 - 2135 + 0x440 , // 198 - 2308 + 0x441 , // 199 - 3577 + 0x442 , // 200 - 3703 + 0x443 , // 201 - 3902 + 0x444 , // 202 - 3748 + 0x445 , // 203 - 343 + 0x446 , // 204 - 2849 + 0x447 , // 205 - 1756 + 0x448 , // 206 - 2813 + 0x449 , // 207 - 3612 + 0x44a , // 208 - 3634 + 0x44b , // 209 - 2174 + 0x44c , // 210 - 2510 + 0x44d , // 211 - 201 + 0x44e , // 212 - 2576 + 0x44f , // 213 - 3126 + 0x450 , // 214 - 2524 + 0x451 , // 215 - 350 + 0x452 , // 216 - 518 + 0x453 , // 217 - 2167 + 0x454 , // 218 - 2377 + 0x455 , // 219 - 2616 + 0x456 , // 220 - 1721 + 0x457 , // 221 - 2194 + 0x458 , // 222 - 2559 + 0x459 , // 223 - 3184 + 0x45a , // 224 - 3604 + 0x45b , // 225 - 3279 + 0x45c , // 226 - 484 + 0x45d , // 227 - 1962 + 0x45e , // 228 - 47 + 0x45f , // 229 - 3773 + 0x460 , // 230 - 2209 + 0x461 , // 231 - 2680 + 0x462 , // 232 - 1700 + 0x463 , // 233 - 2892 + 0x464 , // 234 - 1433 + 0x465 , // 235 - 622 + 0x466 , // 236 - 311 + 0x467 , // 237 - 1418 + 0x468 , // 238 - 1806 + 0x469 , // 239 - 1902 + 0x46a , // 240 - 4060 + 0x46b , // 241 - 3023 + 0x46c , // 242 - 2768 + 0x46d , // 243 - 262 + 0x46e , // 244 - 2332 + 0x46f , // 245 - 2151 + 0x470 , // 246 - 1917 + 0x471 , // 247 - 2202 + 0x472 , // 248 - 2801 + 0x473 , // 249 - 3687 + 0x474 , // 250 - 1728 + 0x475 , // 251 - 1819 + 0x476 , // 252 - 2315 + 0x477 , // 253 - 3382 + 0x478 , // 254 - 1924 + 0x479 , // 255 - 2857 + 0x47a , // 256 - 193 + 0x47c , // 257 - 2568 + 0x47e , // 258 - 362 + 0x480 , // 259 - 3835 + 0x481 , // 260 - 2496 + 0x482 , // 261 - 2794 + 0x483 , // 262 - 497 + 0x484 , // 263 - 1742 + 0x485 , // 264 - 3134 + 0x486 , // 265 - 3009 + 0x487 , // 266 - 3110 + 0x488 , // 267 - 4004 + 0x48c , // 268 - 2884 + 0x491 , // 269 - 1714 + 0x492 , // 270 - 2279 + 0x501 , // 271 - 2972 + 0x5fe , // 272 - 2980 + 0x801 , // 273 - 95 + 0x803 , // 274 - 433 + 0x804 , // 275 - 4110 + 0x807 , // 276 - 556 + 0x809 , // 277 - 831 + 0x80a , // 278 - 1299 + 0x80c , // 279 - 1459 + 0x810 , // 280 - 1938 + 0x813 , // 281 - 2692 + 0x814 , // 282 - 2733 + 0x816 , // 283 - 2944 + 0x818 , // 284 - 3057 + 0x819 , // 285 - 3093 + 0x81a , // 286 - 3480 + 0x81d , // 287 - 3560 + 0x820 , // 288 - 3849 + 0x82c , // 289 - 233 + 0x82e , // 290 - 605 + 0x832 , // 291 - 3710 + 0x83b , // 292 - 3206 + 0x83c , // 293 - 1707 + 0x83e , // 294 - 2583 + 0x843 , // 295 - 3885 + 0x845 , // 296 - 338 + 0x846 , // 297 - 2839 + 0x849 , // 298 - 3617 + 0x850 , // 299 - 2536 + 0x859 , // 300 - 3167 + 0x85d , // 301 - 1979 + 0x85f , // 302 - 3792 + 0x860 , // 303 - 2233 + 0x861 , // 304 - 2675 + 0x867 , // 305 - 1403 + 0x86b , // 306 - 3029 + 0x873 , // 307 - 3682 + 0x901 , // 308 - 2959 + 0x9ff , // 309 - 2989 + 0xc01 , // 310 - 80 + 0xc04 , // 311 - 4173 + 0xc07 , // 312 - 546 + 0xc09 , // 313 - 716 + 0xc0a , // 314 - 1267 + 0xc0c , // 315 - 1484 + 0xc1a , // 316 - 3423 + 0xc3b , // 317 - 3196 + 0xc50 , // 318 - 2546 + 0xc51 , // 319 - 638 + 0xc6b , // 320 - 3035 + 0x1001 , // 321 - 120 + 0x1004 , // 322 - 4219 + 0x1007 , // 323 - 588 + 0x1009 , // 324 - 756 + 0x100a , // 325 - 1289 + 0x100c , // 326 - 1504 + 0x101a , // 327 - 1841 + 0x103b , // 328 - 3316 + 0x105f , // 329 - 3822 + 0x1401 , // 330 - 75 + 0x1404 , // 331 - 4190 + 0x1407 , // 332 - 583 + 0x1409 , // 333 - 1026 + 0x140a , // 334 - 1247 + 0x140c , // 335 - 1569 + 0x141a , // 336 - 402 + 0x143b , // 337 - 3322 + 0x1801 , // 338 - 125 + 0x1809 , // 339 - 881 + 0x180a , // 340 - 1309 + 0x180c , // 341 - 1579 + 0x181a , // 342 - 3470 + 0x183b , // 343 - 3301 + 0x1c01 , // 344 - 180 + 0x1c09 , // 345 - 1191 + 0x1c0a , // 346 - 1257 + 0x1c0c , // 347 - 1453 + 0x1c1a , // 348 - 3413 + 0x1c3b , // 349 - 3307 + 0x2001 , // 350 - 135 + 0x2009 , // 351 - 911 + 0x200a , // 352 - 1349 + 0x200c , // 353 - 1634 + 0x201a , // 354 - 385 + 0x203b , // 355 - 3340 + 0x2401 , // 356 - 185 + 0x2409 , // 357 - 684 + 0x240a , // 358 - 1242 + 0x240c , // 359 - 1489 + 0x241a , // 360 - 3500 + 0x243b , // 361 - 3331 + 0x2801 , // 362 - 170 + 0x2809 , // 363 - 751 + 0x280a , // 364 - 1314 + 0x280c , // 365 - 1649 + 0x281a , // 366 - 3443 + 0x2c01 , // 367 - 100 + 0x2c09 , // 368 - 1136 + 0x2c0a , // 369 - 1222 + 0x2c0c , // 370 - 1514 + 0x2c1a , // 371 - 3490 + 0x3001 , // 372 - 115 + 0x3009 , // 373 - 1201 + 0x300a , // 374 - 1262 + 0x300c , // 375 - 1509 + 0x301a , // 376 - 3433 + 0x3401 , // 377 - 110 + 0x3409 , // 378 - 1036 + 0x340a , // 379 - 1237 + 0x340c , // 380 - 1594 + 0x3801 , // 381 - 60 + 0x3809 , // 382 - 876 + 0x380a , // 383 - 1344 + 0x380c , // 384 - 1574 + 0x3c01 , // 385 - 65 + 0x3c09 , // 386 - 871 + 0x3c0a , // 387 - 1329 + 0x3c0c , // 388 - 1559 + 0x4001 , // 389 - 145 + 0x4009 , // 390 - 896 + 0x400a , // 391 - 1227 + 0x4409 , // 392 - 991 + 0x440a , // 393 - 1334 + 0x4809 , // 394 - 1086 + 0x480a , // 395 - 1294 + 0x4c0a , // 396 - 1304 + 0x500a , // 397 - 1324 + 0x540a , // 398 - 1339 + 0x580a , // 399 - 1216 + 0x5c0a , // 400 - 1252 + 0x641a , // 401 - 378 + 0x681a , // 402 - 395 + 0x6c1a , // 403 - 3406 + 0x701a , // 404 - 3463 + 0x703b , // 405 - 3328 + 0x742c , // 406 - 226 + 0x743b , // 407 - 3337 + 0x7804 , // 408 - 4096 + 0x7814 , // 409 - 2731 + 0x781a , // 410 - 376 + 0x782c , // 411 - 243 + 0x783b , // 412 - 3298 + 0x7843 , // 413 - 3878 + 0x7850 , // 414 - 2517 + 0x785d , // 415 - 1955 + 0x785f , // 416 - 3814 + 0x7c04 , // 417 - 4166 + 0x7c14 , // 418 - 2639 + 0x7c1a , // 419 - 3404 + 0x7c28 , // 420 - 3656 + 0x7c2e , // 421 - 602 + 0x7c3b , // 422 - 3313 + 0x7c43 , // 423 - 3895 + 0x7c46 , // 424 - 2832 + 0x7c50 , // 425 - 2529 + 0x7c59 , // 426 - 3160 + 0x7c5c , // 427 - 476 + 0x7c5d , // 428 - 1972 + 0x7c5f , // 429 - 3784 + 0x7c67 , // 430 - 1396 + 0x7c68 , // 431 - 1779 + 0x7c86 , // 432 - 3001 + 0x7c92 , // 433 - 2272 + 0x1007f, // 434 - 4009 + 0x10407, // 435 - 566 + 0x1040e, // 436 - 1867 + 0x10437, // 437 - 2069 + 0x20804, // 438 - 4127 + 0x21004, // 439 - 4236 + 0x21404, // 440 - 4207 + 0x30404, // 441 - 4253 + 0x40404, // 442 - 4265 + 0x40411, // 443 - 1996 + 0x40c04, // 444 - 4178 + 0x41404, // 445 - 4195 + 0x50804, // 446 - 4115 + 0x51004 // 447 - 4224 + }; + // each element in s_lcidToCultureNameIndices is index to s_localeNamesIndices + private static readonly int[] s_lcidToCultureNameIndices = new int[] + { + // Index to s_localeNamesIndices, index to this array - lcid - index to the c_localeNames + 13 , // 0 - 1 - 52 + 64 , // 1 - 2 - 301 + 88 , // 2 - 3 - 421 + 847 , // 3 - 4 - 4139 + 103 , // 4 - 5 - 502 + 109 , // 5 - 6 - 523 + 114 , // 6 - 7 - 544 + 140 , // 7 - 8 - 664 + 143 , // 8 - 9 - 676 + 251 , // 9 - a - 1214 + 293 , // 10 - b - 1423 + 300 , // 11 - c - 1451 + 377 , // 12 - d - 1825 + 386 , // 13 - e - 1860 + 402 , // 14 - f - 1929 + 404 , // 15 - 10 - 1936 + 413 , // 16 - 11 - 1989 + 452 , // 17 - 12 - 2179 + 564 , // 18 - 13 - 2685 + 578 , // 19 - 14 - 2747 + 605 , // 20 - 15 - 2864 + 613 , // 21 - 16 - 2897 + 637 , // 22 - 17 - 3041 + 641 , // 23 - 18 - 3055 + 646 , // 24 - 19 - 3076 + 381 , // 25 - 1a - 1839 + 687 , // 26 - 1b - 3284 + 709 , // 27 - 1c - 3387 + 734 , // 28 - 1d - 3553 + 760 , // 29 - 1e - 3673 + 774 , // 30 - 1f - 3727 + 795 , // 31 - 20 - 3847 + 396 , // 32 - 21 - 1908 + 793 , // 33 - 22 - 3840 + 58 , // 34 - 23 - 276 + 689 , // 35 - 24 - 3291 + 278 , // 36 - 25 - 1354 + 506 , // 37 - 26 - 2429 + 498 , // 38 - 27 - 2397 + 757 , // 39 - 28 - 3654 + 284 , // 40 - 29 - 1377 + 812 , // 41 - 2a - 3960 + 389 , // 42 - 2b - 1879 + 49 , // 43 - 2c - 224 + 280 , // 44 - 2d - 1361 + 384 , // 45 - 2e - 1851 + 523 , // 46 - 2f - 2501 + 731 , // 47 - 30 - 3541 + 777 , // 48 - 31 - 3739 + 769 , // 49 - 32 - 3708 + 810 , // 50 - 33 - 3953 + 825 , // 51 - 34 - 4020 + 862 , // 52 - 35 - 4277 + 4 , // 53 - 36 - 17 + 425 , // 54 - 37 - 2062 + 297 , // 55 - 38 - 1439 + 379 , // 56 - 39 - 1832 + 543 , // 57 - 3a - 2598 + 670 , // 58 - 3b - 3194 + 352 , // 59 - 3c - 1705 + 831 , // 60 - 3d - 4045 + 539 , // 61 - 3e - 2581 + 440 , // 62 - 3f - 2133 + 476 , // 63 - 40 - 2306 + 738 , // 64 - 41 - 3570 + 767 , // 65 - 42 - 3701 + 798 , // 66 - 43 - 3859 + 779 , // 67 - 44 - 3746 + 71 , // 68 - 45 - 336 + 599 , // 69 - 46 - 2830 + 364 , // 70 - 47 - 1754 + 594 , // 71 - 48 - 2811 + 747 , // 72 - 49 - 3610 + 752 , // 73 - 4a - 3632 + 450 , // 74 - 4b - 2172 + 525 , // 75 - 4c - 2508 + 43 , // 76 - 4d - 199 + 537 , // 77 - 4e - 2574 + 657 , // 78 - 4f - 3124 + 527 , // 79 - 50 - 2515 + 74 , // 80 - 51 - 348 + 107 , // 81 - 52 - 516 + 448 , // 82 - 53 - 2165 + 493 , // 83 - 54 - 2375 + 547 , // 84 - 55 - 2614 + 356 , // 85 - 56 - 1719 + 455 , // 86 - 57 - 2191 + 533 , // 87 - 58 - 2556 + 665 , // 88 - 59 - 3158 + 745 , // 89 - 5a - 3601 + 685 , // 90 - 5b - 3277 + 98 , // 91 - 5c - 473 + 408 , // 92 - 5d - 1953 + 11 , // 93 - 5e - 45 + 783 , // 94 - 5f - 3762 + 459 , // 95 - 60 - 2207 + 561 , // 96 - 61 - 2673 + 350 , // 97 - 62 - 1698 + 611 , // 98 - 63 - 2890 + 295 , // 99 - 64 - 1430 + 129 , // 100 - 65 - 620 + 66 , // 101 - 66 - 308 + 286 , // 102 - 67 - 1384 + 370 , // 103 - 68 - 1777 + 394 , // 104 - 69 - 1899 + 833 , // 105 - 6a - 4053 + 633 , // 106 - 6b - 3020 + 583 , // 107 - 6c - 2765 + 54 , // 108 - 6d - 260 + 482 , // 109 - 6e - 2330 + 444 , // 110 - 6f - 2149 + 398 , // 111 - 70 - 1915 + 457 , // 112 - 71 - 2200 + 591 , // 113 - 72 - 2799 + 762 , // 114 - 73 - 3680 + 358 , // 115 - 74 - 1726 + 375 , // 116 - 75 - 1816 + 478 , // 117 - 76 - 2313 + 704 , // 118 - 77 - 3365 + 400 , // 119 - 78 - 1922 + 603 , // 120 - 79 - 2854 + 41 , // 121 - 7a - 190 + 535 , // 122 - 7c - 2565 + 77 , // 123 - 7e - 360 + 791 , // 124 - 80 - 3833 + 521 , // 125 - 81 - 2494 + 589 , // 126 - 82 - 2792 + 101 , // 127 - 83 - 495 + 360 , // 128 - 84 - 1733 + 659 , // 129 - 85 - 3131 + 630 , // 130 - 86 - 2998 + 653 , // 131 - 87 - 3108 + 822 , // 132 - 88 - 4002 + 609 , // 133 - 8c - 2881 + 354 , // 134 - 91 - 1712 + 470 , // 135 - 92 - 2270 + 33 , // 136 - 401 - 150 + 65 , // 137 - 402 - 303 + 90 , // 138 - 403 - 428 + 859 , // 139 - 404 - 4248 + 104 , // 140 - 405 - 504 + 110 , // 141 - 406 - 525 + 118 , // 142 - 407 - 561 + 142 , // 143 - 408 - 671 + 240 , // 144 - 409 - 1161 + 263 , // 145 - 40a - 1272 + 294 , // 146 - 40b - 1425 + 316 , // 147 - 40c - 1529 + 378 , // 148 - 40d - 1827 + 387 , // 149 - 40e - 1862 + 403 , // 150 - 40f - 1931 + 406 , // 151 - 410 - 1943 + 414 , // 152 - 411 - 1991 + 454 , // 153 - 412 - 2186 + 569 , // 154 - 413 - 2707 + 554 , // 155 - 414 - 2641 + 606 , // 156 - 415 - 2866 + 615 , // 157 - 416 - 2904 + 638 , // 158 - 417 - 3043 + 643 , // 159 - 418 - 3062 + 651 , // 160 - 419 - 3098 + 383 , // 161 - 41a - 1846 + 688 , // 162 - 41b - 3286 + 710 , // 163 - 41c - 3389 + 737 , // 164 - 41d - 3565 + 761 , // 165 - 41e - 3675 + 776 , // 166 - 41f - 3734 + 797 , // 167 - 420 - 3854 + 397 , // 168 - 421 - 1910 + 794 , // 169 - 422 - 3842 + 59 , // 170 - 423 - 278 + 690 , // 171 - 424 - 3293 + 279 , // 172 - 425 - 1356 + 507 , // 173 - 426 - 2431 + 499 , // 174 - 427 - 2399 + 759 , // 175 - 428 - 3663 + 285 , // 176 - 429 - 1379 + 813 , // 177 - 42a - 3962 + 390 , // 178 - 42b - 1881 + 53 , // 179 - 42c - 250 + 281 , // 180 - 42d - 1363 + 385 , // 181 - 42e - 1854 + 524 , // 182 - 42f - 2503 + 733 , // 183 - 430 - 3548 + 778 , // 184 - 431 - 3741 + 771 , // 185 - 432 - 3715 + 811 , // 186 - 433 - 3955 + 826 , // 187 - 434 - 4022 + 863 , // 188 - 435 - 4279 + 6 , // 189 - 436 - 24 + 426 , // 190 - 437 - 2064 + 299 , // 191 - 438 - 1446 + 380 , // 192 - 439 - 1834 + 544 , // 193 - 43a - 2600 + 672 , // 194 - 43b - 3201 + 832 , // 195 - 43d - 4047 + 541 , // 196 - 43e - 2588 + 441 , // 197 - 43f - 2135 + 477 , // 198 - 440 - 2308 + 740 , // 199 - 441 - 3577 + 768 , // 200 - 442 - 3703 + 804 , // 201 - 443 - 3902 + 780 , // 202 - 444 - 3748 + 73 , // 203 - 445 - 343 + 602 , // 204 - 446 - 2849 + 365 , // 205 - 447 - 1756 + 595 , // 206 - 448 - 2813 + 748 , // 207 - 449 - 3612 + 753 , // 208 - 44a - 3634 + 451 , // 209 - 44b - 2174 + 526 , // 210 - 44c - 2510 + 44 , // 211 - 44d - 201 + 538 , // 212 - 44e - 2576 + 658 , // 213 - 44f - 3126 + 529 , // 214 - 450 - 2524 + 75 , // 215 - 451 - 350 + 108 , // 216 - 452 - 518 + 449 , // 217 - 453 - 2167 + 494 , // 218 - 454 - 2377 + 548 , // 219 - 455 - 2616 + 357 , // 220 - 456 - 1721 + 456 , // 221 - 457 - 2194 + 534 , // 222 - 458 - 2559 + 669 , // 223 - 459 - 3184 + 746 , // 224 - 45a - 3604 + 686 , // 225 - 45b - 3279 + 100 , // 226 - 45c - 484 + 410 , // 227 - 45d - 1962 + 12 , // 228 - 45e - 47 + 785 , // 229 - 45f - 3773 + 460 , // 230 - 460 - 2209 + 563 , // 231 - 461 - 2680 + 351 , // 232 - 462 - 1700 + 612 , // 233 - 463 - 2892 + 296 , // 234 - 464 - 1433 + 130 , // 235 - 465 - 622 + 67 , // 236 - 466 - 311 + 292 , // 237 - 467 - 1418 + 374 , // 238 - 468 - 1806 + 395 , // 239 - 469 - 1902 + 835 , // 240 - 46a - 4060 + 634 , // 241 - 46b - 3023 + 584 , // 242 - 46c - 2768 + 55 , // 243 - 46d - 262 + 483 , // 244 - 46e - 2332 + 445 , // 245 - 46f - 2151 + 399 , // 246 - 470 - 1917 + 458 , // 247 - 471 - 2202 + 592 , // 248 - 472 - 2801 + 764 , // 249 - 473 - 3687 + 359 , // 250 - 474 - 1728 + 376 , // 251 - 475 - 1819 + 479 , // 252 - 476 - 2315 + 708 , // 253 - 477 - 3382 + 401 , // 254 - 478 - 1924 + 604 , // 255 - 479 - 2857 + 42 , // 256 - 47a - 193 + 536 , // 257 - 47c - 2568 + 78 , // 258 - 47e - 362 + 792 , // 259 - 480 - 3835 + 522 , // 260 - 481 - 2496 + 590 , // 261 - 482 - 2794 + 102 , // 262 - 483 - 497 + 362 , // 263 - 484 - 1742 + 660 , // 264 - 485 - 3134 + 632 , // 265 - 486 - 3009 + 654 , // 266 - 487 - 3110 + 823 , // 267 - 488 - 4004 + 610 , // 268 - 48c - 2884 + 355 , // 269 - 491 - 1714 + 472 , // 270 - 492 - 2279 + 627 , // 271 - 501 - 2972 + 628 , // 272 - 5fe - 2980 + 22 , // 273 - 801 - 95 + 91 , // 274 - 803 - 433 + 844 , // 275 - 804 - 4110 + 117 , // 276 - 807 - 556 + 174 , // 277 - 809 - 831 + 267 , // 278 - 80a - 1299 + 302 , // 279 - 80c - 1459 + 405 , // 280 - 810 - 1938 + 566 , // 281 - 813 - 2692 + 575 , // 282 - 814 - 2733 + 623 , // 283 - 816 - 2944 + 642 , // 284 - 818 - 3057 + 650 , // 285 - 819 - 3093 + 722 , // 286 - 81a - 3480 + 736 , // 287 - 81d - 3560 + 796 , // 288 - 820 - 3849 + 51 , // 289 - 82c - 233 + 126 , // 290 - 82e - 605 + 770 , // 291 - 832 - 3710 + 673 , // 292 - 83b - 3206 + 353 , // 293 - 83c - 1707 + 540 , // 294 - 83e - 2583 + 802 , // 295 - 843 - 3885 + 72 , // 296 - 845 - 338 + 601 , // 297 - 846 - 2839 + 749 , // 298 - 849 - 3617 + 531 , // 299 - 850 - 2536 + 667 , // 300 - 859 - 3167 + 412 , // 301 - 85d - 1979 + 787 , // 302 - 85f - 3792 + 463 , // 303 - 860 - 2233 + 562 , // 304 - 861 - 2675 + 290 , // 305 - 867 - 1403 + 635 , // 306 - 86b - 3029 + 763 , // 307 - 873 - 3682 + 626 , // 308 - 901 - 2959 + 629 , // 309 - 9ff - 2989 + 19 , // 310 - c01 - 80 + 851 , // 311 - c04 - 4173 + 115 , // 312 - c07 - 546 + 151 , // 313 - c09 - 716 + 262 , // 314 - c0a - 1267 + 307 , // 315 - c0c - 1484 + 716 , // 316 - c1a - 3423 + 671 , // 317 - c3b - 3196 + 532 , // 318 - c50 - 2546 + 134 , // 319 - c51 - 638 + 636 , // 320 - c6b - 3035 + 27 , // 321 - 1001 - 120 + 856 , // 322 - 1004 - 4219 + 122 , // 323 - 1007 - 588 + 159 , // 324 - 1009 - 756 + 265 , // 325 - 100a - 1289 + 311 , // 326 - 100c - 1504 + 382 , // 327 - 101a - 1841 + 695 , // 328 - 103b - 3316 + 790 , // 329 - 105f - 3822 + 18 , // 330 - 1401 - 75 + 853 , // 331 - 1404 - 4190 + 121 , // 332 - 1407 - 583 + 213 , // 333 - 1409 - 1026 + 258 , // 334 - 140a - 1247 + 324 , // 335 - 140c - 1569 + 85 , // 336 - 141a - 402 + 696 , // 337 - 143b - 3322 + 28 , // 338 - 1801 - 125 + 184 , // 339 - 1809 - 881 + 269 , // 340 - 180a - 1309 + 326 , // 341 - 180c - 1579 + 721 , // 342 - 181a - 3470 + 692 , // 343 - 183b - 3301 + 39 , // 344 - 1c01 - 180 + 246 , // 345 - 1c09 - 1191 + 260 , // 346 - 1c0a - 1257 + 301 , // 347 - 1c0c - 1453 + 715 , // 348 - 1c1a - 3413 + 693 , // 349 - 1c3b - 3307 + 30 , // 350 - 2001 - 135 + 190 , // 351 - 2009 - 911 + 277 , // 352 - 200a - 1349 + 337 , // 353 - 200c - 1634 + 83 , // 354 - 201a - 385 + 700 , // 355 - 203b - 3340 + 40 , // 356 - 2401 - 185 + 145 , // 357 - 2409 - 684 + 257 , // 358 - 240a - 1242 + 308 , // 359 - 240c - 1489 + 724 , // 360 - 241a - 3500 + 698 , // 361 - 243b - 3331 + 37 , // 362 - 2801 - 170 + 158 , // 363 - 2809 - 751 + 270 , // 364 - 280a - 1314 + 340 , // 365 - 280c - 1649 + 718 , // 366 - 281a - 3443 + 23 , // 367 - 2c01 - 100 + 235 , // 368 - 2c09 - 1136 + 253 , // 369 - 2c0a - 1222 + 313 , // 370 - 2c0c - 1514 + 723 , // 371 - 2c1a - 3490 + 26 , // 372 - 3001 - 115 + 248 , // 373 - 3009 - 1201 + 261 , // 374 - 300a - 1262 + 312 , // 375 - 300c - 1509 + 717 , // 376 - 301a - 3433 + 25 , // 377 - 3401 - 110 + 215 , // 378 - 3409 - 1036 + 256 , // 379 - 340a - 1237 + 329 , // 380 - 340c - 1594 + 15 , // 381 - 3801 - 60 + 183 , // 382 - 3809 - 876 + 276 , // 383 - 380a - 1344 + 325 , // 384 - 380c - 1574 + 16 , // 385 - 3c01 - 65 + 182 , // 386 - 3c09 - 871 + 273 , // 387 - 3c0a - 1329 + 322 , // 388 - 3c0c - 1559 + 32 , // 389 - 4001 - 145 + 187 , // 390 - 4009 - 896 + 254 , // 391 - 400a - 1227 + 206 , // 392 - 4409 - 991 + 274 , // 393 - 440a - 1334 + 225 , // 394 - 4809 - 1086 + 266 , // 395 - 480a - 1294 + 268 , // 396 - 4c0a - 1304 + 272 , // 397 - 500a - 1324 + 275 , // 398 - 540a - 1339 + 252 , // 399 - 580a - 1216 + 259 , // 400 - 5c0a - 1252 + 82 , // 401 - 641a - 378 + 84 , // 402 - 681a - 395 + 714 , // 403 - 6c1a - 3406 + 720 , // 404 - 701a - 3463 + 697 , // 405 - 703b - 3328 + 50 , // 406 - 742c - 226 + 699 , // 407 - 743b - 3337 + 841 , // 408 - 7804 - 4096 + 574 , // 409 - 7814 - 2731 + 81 , // 410 - 781a - 376 + 52 , // 411 - 782c - 243 + 691 , // 412 - 783b - 3298 + 801 , // 413 - 7843 - 3878 + 528 , // 414 - 7850 - 2517 + 409 , // 415 - 785d - 1955 + 789 , // 416 - 785f - 3814 + 850 , // 417 - 7c04 - 4166 + 553 , // 418 - 7c14 - 2639 + 713 , // 419 - 7c1a - 3404 + 758 , // 420 - 7c28 - 3656 + 125 , // 421 - 7c2e - 602 + 694 , // 422 - 7c3b - 3313 + 803 , // 423 - 7c43 - 3895 + 600 , // 424 - 7c46 - 2832 + 530 , // 425 - 7c50 - 2529 + 666 , // 426 - 7c59 - 3160 + 99 , // 427 - 7c5c - 476 + 411 , // 428 - 7c5d - 1972 + 786 , // 429 - 7c5f - 3784 + 289 , // 430 - 7c67 - 1396 + 371 , // 431 - 7c68 - 1779 + 631 , // 432 - 7c86 - 3001 + 471 , // 433 - 7c92 - 2272 + 824 , // 434 - 1007f - 4009 + 119 , // 435 - 10407 - 566 + 388 , // 436 - 1040e - 1867 + 427 , // 437 - 10437 - 2069 + 846 , // 438 - 20804 - 4127 + 858 , // 439 - 21004 - 4236 + 855 , // 440 - 21404 - 4207 + 860 , // 441 - 30404 - 4253 + 861 , // 442 - 40404 - 4265 + 415 , // 443 - 40411 - 1996 + 852 , // 444 - 40c04 - 4178 + 854 , // 445 - 41404 - 4195 + 845 , // 446 - 50804 - 4115 + 857 // 447 - 51004 - 4224 + }; + + internal static string? LCIDToLocaleName(int culture) + { + int left = 0; + int right = s_lcids.Length - 1; + int index; + + Debug.Assert(s_lcids.Length == s_lcidToCultureNameIndices.Length); + + while (left <= right) + { + index = (right + left) / 2; + + if (culture == s_lcids[index]) + { + int indexToLocaleNamesIndices = s_lcidToCultureNameIndices[index]; + Debug.Assert(indexToLocaleNamesIndices < s_localeNamesIndices.Length - 1); + + return c_localeNames.Substring(s_localeNamesIndices[indexToLocaleNamesIndices], + s_localeNamesIndices[indexToLocaleNamesIndices + 1] - + s_localeNamesIndices[indexToLocaleNamesIndices]); + } + else if (culture < s_lcids[index]) + { + right = index - 1; + } + else + { + left = index + 1; + } + } + + return null; + } + + internal static int GetLocaleDataNumericPart(string cultureName, IcuLocaleDataParts part) + { + int index = SearchCultureName(cultureName); + if (index < 0) + { + return -1; + } + + Debug.Assert((s_localeNamesIndices.Length-1 == (s_nameIndexToNumericData.Length/NUMERIC_LOCALE_DATA_COUNT_PER_ROW)) && + index < s_localeNamesIndices.Length); + + return s_nameIndexToNumericData[index * NUMERIC_LOCALE_DATA_COUNT_PER_ROW + (int) part]; + } + + internal static string? GetThreeLetterWindowsLanguageName(string cultureName) + { + int index = SearchCultureName(cultureName); + if (index < 0) + { + return null; + } + + Debug.Assert(s_localeNamesIndices.Length-1 == (c_threeLetterWindowsLanguageName.Length / 3)); + return c_threeLetterWindowsLanguageName.Substring(index * 3, 3); + } + + internal static string GetLocaleDataMappedCulture(string cultureName, IcuLocaleDataParts part) + { + int indexToIndicesTable = GetLocaleDataNumericPart(cultureName, part); + if (indexToIndicesTable < 0) + { + return ""; // fallback to invariant + } + + Debug.Assert(indexToIndicesTable < s_localeNamesIndices.Length-1); + + return c_localeNames.Substring(s_localeNamesIndices[indexToIndicesTable], + s_localeNamesIndices[indexToIndicesTable+1] - s_localeNamesIndices[indexToIndicesTable]); + } + + internal static string GetSpecificCultureName(string cultureName) + { + return GetLocaleDataMappedCulture(cultureName, IcuLocaleDataParts.SpecificLocaleIndex); + } + + internal static string GetConsoleUICulture(string cultureName) + { + return GetLocaleDataMappedCulture(cultureName, IcuLocaleDataParts.ConsoleLocaleIndex); + } + + // SearchCultureName will binary search c_localeNames using s_localeNamesIndices. + // return index in s_localeNamesIndices, or -1 if it fail finding any match + private static int SearchCultureName(string name) + { + int left = 0; + int right = s_localeNamesIndices.Length - 2; + int index; + int result; + + Debug.Assert(s_localeNamesIndices[s_localeNamesIndices.Length - 1] == c_localeNames.Length); + + name = CultureData.AnsiToLower(name); + + // Binary search the array until we have only a couple of elements left and then + // just walk those elements. + while ((right - left) > 3) + { + index = ((right - left) / 2) + left; + + Debug.Assert(index < s_localeNamesIndices.Length - 1); + result = CompareOrdinal(name, c_localeNames, s_localeNamesIndices[index], s_localeNamesIndices[index + 1] - s_localeNamesIndices[index]); + if (result == 0) + { + return index; + } + else if (result < 0) + { + right = index; + } + else + { + left = index; + } + } + + // Walk the remaining elements (it'll be 3 or fewer). + for (; left <= right; left++) + { + Debug.Assert(left < s_localeNamesIndices.Length - 1); + if (CompareOrdinal(name, c_localeNames, s_localeNamesIndices[left], s_localeNamesIndices[left + 1] - s_localeNamesIndices[left]) == 0) + { + return (left); + } + } + + // couldn't find culture name + return -1; + } + + // optimized to avoid parameters checking + private static int CompareOrdinal(string s1, string s2, int index, int length) + { + int count = s1.Length; + if (count > length) + count = length; + + int i = 0; + while (i < count && s1[i] == s2[index + i]) + i++; + + if (i < count) + return (int)(s1[i] - s2[index + i]); + + return s1.Length - length; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.Icu.cs new file mode 100644 index 00000000000000..82b97b27d3c862 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.Icu.cs @@ -0,0 +1,148 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +namespace System.Globalization +{ + public sealed partial class IdnMapping + { + private unsafe string IcuGetAsciiCore(string unicodeString, char* unicode, int count) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert(unicodeString != null && unicodeString.Length >= count); + + uint flags = IcuFlags; + CheckInvalidIdnCharacters(unicode, count, flags, nameof(unicode)); + + const int StackallocThreshold = 512; + // Each unicode character is represented by up to 3 ASCII chars + // and the whole string is prefixed by "xn--" (length 4) + int estimatedLength = (int)Math.Min(count * 3L + 4, StackallocThreshold); + int actualLength; + if (estimatedLength < StackallocThreshold) + { + char* outputStack = stackalloc char[estimatedLength]; + actualLength = Interop.Globalization.ToAscii(flags, unicode, count, outputStack, estimatedLength); + if (actualLength > 0 && actualLength <= estimatedLength) + { + return GetStringForOutput(unicodeString, unicode, count, outputStack, actualLength); + } + } + else + { + actualLength = Interop.Globalization.ToAscii(flags, unicode, count, null, 0); + } + if (actualLength == 0) + { + throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(unicode)); + } + + char[] outputHeap = new char[actualLength]; + fixed (char* pOutputHeap = &outputHeap[0]) + { + actualLength = Interop.Globalization.ToAscii(flags, unicode, count, pOutputHeap, actualLength); + if (actualLength == 0 || actualLength > outputHeap.Length) + { + throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(unicode)); + } + return GetStringForOutput(unicodeString, unicode, count, pOutputHeap, actualLength); + } + } + + private unsafe string IcuGetUnicodeCore(string asciiString, char* ascii, int count) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert(asciiString != null && asciiString.Length >= count); + + uint flags = IcuFlags; + CheckInvalidIdnCharacters(ascii, count, flags, nameof(ascii)); + + const int StackAllocThreshold = 512; + if (count < StackAllocThreshold) + { + char* output = stackalloc char[count]; + return IcuGetUnicodeCore(asciiString, ascii, count, flags, output, count, reattempt: true); + } + else + { + char[] output = new char[count]; + fixed (char* pOutput = &output[0]) + { + return IcuGetUnicodeCore(asciiString, ascii, count, flags, pOutput, count, reattempt: true); + } + } + } + + private unsafe string IcuGetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength, bool reattempt) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert(asciiString != null && asciiString.Length >= count); + + int realLen = Interop.Globalization.ToUnicode(flags, ascii, count, output, outputLength); + + if (realLen == 0) + { + throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(ascii)); + } + else if (realLen <= outputLength) + { + return GetStringForOutput(asciiString, ascii, count, output, realLen); + } + else if (reattempt) + { + char[] newOutput = new char[realLen]; + fixed (char* pNewOutput = newOutput) + { + return IcuGetUnicodeCore(asciiString, ascii, count, flags, pNewOutput, realLen, reattempt: false); + } + } + + throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(ascii)); + } + + // ----------------------------- + // ---- PAL layer ends here ---- + // ----------------------------- + + private uint IcuFlags + { + get + { + int flags = + (AllowUnassigned ? Interop.Globalization.AllowUnassigned : 0) | + (UseStd3AsciiRules ? Interop.Globalization.UseStd3AsciiRules : 0); + return (uint)flags; + } + } + + /// + /// ICU doesn't check for invalid characters unless the STD3 rules option + /// is enabled. + /// + /// To match Windows behavior, we walk the string ourselves looking for these + /// bad characters so we can continue to throw ArgumentException in these cases. + /// + private static unsafe void CheckInvalidIdnCharacters(char* s, int count, uint flags, string paramName) + { + if ((flags & Interop.Globalization.UseStd3AsciiRules) == 0) + { + for (int i = 0; i < count; i++) + { + char c = s[i]; + + // These characters are prohibited regardless of the UseStd3AsciiRules property. + // See https://msdn.microsoft.com/en-us/library/system.globalization.idnmapping.usestd3asciirules(v=vs.110).aspx + if (c <= 0x1F || c == 0x7F) + { + throw new ArgumentException(SR.Argument_IdnIllegalName, paramName); + } + } + } + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.Nls.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.Nls.cs new file mode 100644 index 00000000000000..54ebee2742a18c --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.Nls.cs @@ -0,0 +1,133 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace System.Globalization +{ + public sealed partial class IdnMapping + { + private unsafe string NlsGetAsciiCore(string unicodeString, char* unicode, int count) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(unicodeString != null && unicodeString.Length >= count); + + uint flags = NlsFlags; + + // Determine the required length + int length = Interop.Normaliz.IdnToAscii(flags, unicode, count, null, 0); + if (length == 0) + { + ThrowForZeroLength(unicode: true); + } + + // Do the conversion + const int StackAllocThreshold = 512; // arbitrary limit to switch from stack to heap allocation + if (length < StackAllocThreshold) + { + char* output = stackalloc char[length]; + return NlsGetAsciiCore(unicodeString, unicode, count, flags, output, length); + } + else + { + char[] output = new char[length]; + fixed (char* pOutput = &output[0]) + { + return NlsGetAsciiCore(unicodeString, unicode, count, flags, pOutput, length); + } + } + } + + private unsafe string NlsGetAsciiCore(string unicodeString, char* unicode, int count, uint flags, char* output, int outputLength) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(unicodeString != null && unicodeString.Length >= count); + + int length = Interop.Normaliz.IdnToAscii(flags, unicode, count, output, outputLength); + if (length == 0) + { + ThrowForZeroLength(unicode: true); + } + Debug.Assert(length == outputLength); + return GetStringForOutput(unicodeString, unicode, count, output, length); + } + + private unsafe string NlsGetUnicodeCore(string asciiString, char* ascii, int count) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(asciiString != null && asciiString.Length >= count); + + uint flags = NlsFlags; + + // Determine the required length + int length = Interop.Normaliz.IdnToUnicode(flags, ascii, count, null, 0); + if (length == 0) + { + ThrowForZeroLength(unicode: false); + } + + // Do the conversion + const int StackAllocThreshold = 512; // arbitrary limit to switch from stack to heap allocation + if (length < StackAllocThreshold) + { + char* output = stackalloc char[length]; + return NlsGetUnicodeCore(asciiString, ascii, count, flags, output, length); + } + else + { + char[] output = new char[length]; + fixed (char* pOutput = &output[0]) + { + return NlsGetUnicodeCore(asciiString, ascii, count, flags, pOutput, length); + } + } + } + + private unsafe string NlsGetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(asciiString != null && asciiString.Length >= count); + + int length = Interop.Normaliz.IdnToUnicode(flags, ascii, count, output, outputLength); + if (length == 0) + { + ThrowForZeroLength(unicode: false); + } + Debug.Assert(length == outputLength); + return GetStringForOutput(asciiString, ascii, count, output, length); + } + + // ----------------------------- + // ---- PAL layer ends here ---- + // ----------------------------- + + private uint NlsFlags + { + get + { + int flags = + (AllowUnassigned ? Interop.Normaliz.IDN_ALLOW_UNASSIGNED : 0) | + (UseStd3AsciiRules ? Interop.Normaliz.IDN_USE_STD3_ASCII_RULES : 0); + return (uint)flags; + } + } + + [DoesNotReturn] + private static void ThrowForZeroLength(bool unicode) + { + int lastError = Marshal.GetLastWin32Error(); + + throw new ArgumentException( + lastError == Interop.Errors.ERROR_INVALID_NAME ? SR.Argument_IdnIllegalName : + (unicode ? SR.Argument_InvalidCharSequenceNoIndex : SR.Argument_IdnBadPunycode), + unicode ? "unicode" : "ascii"); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.Unix.cs deleted file mode 100644 index 4c6ee2c4041562..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.Unix.cs +++ /dev/null @@ -1,145 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; - -namespace System.Globalization -{ - public sealed partial class IdnMapping - { - private unsafe string GetAsciiCore(string unicodeString, char* unicode, int count) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(unicodeString != null && unicodeString.Length >= count); - - uint flags = Flags; - CheckInvalidIdnCharacters(unicode, count, flags, nameof(unicode)); - - const int StackallocThreshold = 512; - // Each unicode character is represented by up to 3 ASCII chars - // and the whole string is prefixed by "xn--" (length 4) - int estimatedLength = (int)Math.Min(count * 3L + 4, StackallocThreshold); - int actualLength; - if (estimatedLength < StackallocThreshold) - { - char* outputStack = stackalloc char[estimatedLength]; - actualLength = Interop.Globalization.ToAscii(flags, unicode, count, outputStack, estimatedLength); - if (actualLength > 0 && actualLength <= estimatedLength) - { - return GetStringForOutput(unicodeString, unicode, count, outputStack, actualLength); - } - } - else - { - actualLength = Interop.Globalization.ToAscii(flags, unicode, count, null, 0); - } - if (actualLength == 0) - { - throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(unicode)); - } - - char[] outputHeap = new char[actualLength]; - fixed (char* pOutputHeap = &outputHeap[0]) - { - actualLength = Interop.Globalization.ToAscii(flags, unicode, count, pOutputHeap, actualLength); - if (actualLength == 0 || actualLength > outputHeap.Length) - { - throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(unicode)); - } - return GetStringForOutput(unicodeString, unicode, count, pOutputHeap, actualLength); - } - } - - private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(asciiString != null && asciiString.Length >= count); - - uint flags = Flags; - CheckInvalidIdnCharacters(ascii, count, flags, nameof(ascii)); - - const int StackAllocThreshold = 512; - if (count < StackAllocThreshold) - { - char* output = stackalloc char[count]; - return GetUnicodeCore(asciiString, ascii, count, flags, output, count, reattempt: true); - } - else - { - char[] output = new char[count]; - fixed (char* pOutput = &output[0]) - { - return GetUnicodeCore(asciiString, ascii, count, flags, pOutput, count, reattempt: true); - } - } - } - - private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength, bool reattempt) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(asciiString != null && asciiString.Length >= count); - - int realLen = Interop.Globalization.ToUnicode(flags, ascii, count, output, outputLength); - - if (realLen == 0) - { - throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(ascii)); - } - else if (realLen <= outputLength) - { - return GetStringForOutput(asciiString, ascii, count, output, realLen); - } - else if (reattempt) - { - char[] newOutput = new char[realLen]; - fixed (char* pNewOutput = newOutput) - { - return GetUnicodeCore(asciiString, ascii, count, flags, pNewOutput, realLen, reattempt: false); - } - } - - throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(ascii)); - } - - // ----------------------------- - // ---- PAL layer ends here ---- - // ----------------------------- - - private uint Flags - { - get - { - int flags = - (AllowUnassigned ? Interop.Globalization.AllowUnassigned : 0) | - (UseStd3AsciiRules ? Interop.Globalization.UseStd3AsciiRules : 0); - return (uint)flags; - } - } - - /// - /// ICU doesn't check for invalid characters unless the STD3 rules option - /// is enabled. - /// - /// To match Windows behavior, we walk the string ourselves looking for these - /// bad characters so we can continue to throw ArgumentException in these cases. - /// - private static unsafe void CheckInvalidIdnCharacters(char* s, int count, uint flags, string paramName) - { - if ((flags & Interop.Globalization.UseStd3AsciiRules) == 0) - { - for (int i = 0; i < count; i++) - { - char c = s[i]; - - // These characters are prohibited regardless of the UseStd3AsciiRules property. - // See https://msdn.microsoft.com/en-us/library/system.globalization.idnmapping.usestd3asciirules(v=vs.110).aspx - if (c <= 0x1F || c == 0x7F) - { - throw new ArgumentException(SR.Argument_IdnIllegalName, paramName); - } - } - } - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.Windows.cs deleted file mode 100644 index 6a97c04ebf6613..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.Windows.cs +++ /dev/null @@ -1,129 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; - -namespace System.Globalization -{ - public sealed partial class IdnMapping - { - private unsafe string GetAsciiCore(string unicodeString, char* unicode, int count) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(unicodeString != null && unicodeString.Length >= count); - - uint flags = Flags; - - // Determine the required length - int length = Interop.Normaliz.IdnToAscii(flags, unicode, count, null, 0); - if (length == 0) - { - ThrowForZeroLength(unicode: true); - } - - // Do the conversion - const int StackAllocThreshold = 512; // arbitrary limit to switch from stack to heap allocation - if (length < StackAllocThreshold) - { - char* output = stackalloc char[length]; - return GetAsciiCore(unicodeString, unicode, count, flags, output, length); - } - else - { - char[] output = new char[length]; - fixed (char* pOutput = &output[0]) - { - return GetAsciiCore(unicodeString, unicode, count, flags, pOutput, length); - } - } - } - - private unsafe string GetAsciiCore(string unicodeString, char* unicode, int count, uint flags, char* output, int outputLength) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(unicodeString != null && unicodeString.Length >= count); - - int length = Interop.Normaliz.IdnToAscii(flags, unicode, count, output, outputLength); - if (length == 0) - { - ThrowForZeroLength(unicode: true); - } - Debug.Assert(length == outputLength); - return GetStringForOutput(unicodeString, unicode, count, output, length); - } - - private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(asciiString != null && asciiString.Length >= count); - - uint flags = Flags; - - // Determine the required length - int length = Interop.Normaliz.IdnToUnicode(flags, ascii, count, null, 0); - if (length == 0) - { - ThrowForZeroLength(unicode: false); - } - - // Do the conversion - const int StackAllocThreshold = 512; // arbitrary limit to switch from stack to heap allocation - if (length < StackAllocThreshold) - { - char* output = stackalloc char[length]; - return GetUnicodeCore(asciiString, ascii, count, flags, output, length); - } - else - { - char[] output = new char[length]; - fixed (char* pOutput = &output[0]) - { - return GetUnicodeCore(asciiString, ascii, count, flags, pOutput, length); - } - } - } - - private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(asciiString != null && asciiString.Length >= count); - - int length = Interop.Normaliz.IdnToUnicode(flags, ascii, count, output, outputLength); - if (length == 0) - { - ThrowForZeroLength(unicode: false); - } - Debug.Assert(length == outputLength); - return GetStringForOutput(asciiString, ascii, count, output, length); - } - - // ----------------------------- - // ---- PAL layer ends here ---- - // ----------------------------- - - private uint Flags - { - get - { - int flags = - (AllowUnassigned ? Interop.Normaliz.IDN_ALLOW_UNASSIGNED : 0) | - (UseStd3AsciiRules ? Interop.Normaliz.IDN_USE_STD3_ASCII_RULES : 0); - return (uint)flags; - } - } - - [DoesNotReturn] - private static void ThrowForZeroLength(bool unicode) - { - int lastError = Marshal.GetLastWin32Error(); - - throw new ArgumentException( - lastError == Interop.Errors.ERROR_INVALID_NAME ? SR.Argument_IdnIllegalName : - (unicode ? SR.Argument_InvalidCharSequenceNoIndex : SR.Argument_IdnBadPunycode), - unicode ? "unicode" : "ascii"); - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.cs index 3ec32b27a6666e..f309a42270fef1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.cs @@ -92,7 +92,9 @@ public string GetAscii(string unicode, int index, int count) { fixed (char* pUnicode = unicode) { - return GetAsciiCore(unicode, pUnicode + index, count); + return GlobalizationMode.UseNls ? + NlsGetAsciiCore(unicode, pUnicode + index, count) : + IcuGetAsciiCore(unicode, pUnicode + index, count); } } } @@ -134,7 +136,9 @@ public string GetUnicode(string ascii, int index, int count) { fixed (char* pAscii = ascii) { - return GetUnicodeCore(ascii, pAscii + index, count); + return GlobalizationMode.UseNls ? + NlsGetUnicodeCore(ascii, pAscii + index, count) : + IcuGetUnicodeCore(ascii, pAscii + index, count); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.Icu.cs new file mode 100644 index 00000000000000..3f9aac684a2016 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.Icu.cs @@ -0,0 +1,98 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Diagnostics; + +namespace System.Globalization +{ + public partial class JapaneseCalendar : Calendar + { + private static EraInfo[]? IcuGetJapaneseEras() + { + if (GlobalizationMode.Invariant) + { + return null; + } + + Debug.Assert(!GlobalizationMode.UseNls); + + string[]? eraNames; + if (!CalendarData.EnumCalendarInfo("ja-JP", CalendarId.JAPAN, CalendarDataType.EraNames, out eraNames)) + { + return null; + } + + string[]? abbrevEnglishEraNames; + if (!CalendarData.EnumCalendarInfo("en", CalendarId.JAPAN, CalendarDataType.AbbrevEraNames, out abbrevEnglishEraNames)) + { + return null; + } + + List eras = new List(); + int lastMaxYear = GregorianCalendar.MaxYear; + + int latestEra = Interop.Globalization.GetLatestJapaneseEra(); + for (int i = latestEra; i >= 0; i--) + { + DateTime dt; + if (!GetJapaneseEraStartDate(i, out dt)) + { + return null; + } + + if (dt < s_calendarMinValue) + { + // only populate the Eras that are valid JapaneseCalendar date times + break; + } + + eras.Add(new EraInfo(i, dt.Year, dt.Month, dt.Day, dt.Year - 1, 1, lastMaxYear - dt.Year + 1, + eraNames![i], GetAbbreviatedEraName(eraNames, i), abbrevEnglishEraNames![i])); + + lastMaxYear = dt.Year; + } + + // remap the Era numbers, now that we know how many there will be + for (int i = 0; i < eras.Count; i++) + { + eras[i].era = eras.Count - i; + } + + return eras.ToArray(); + } + + // PAL Layer ends here + + private static string GetAbbreviatedEraName(string[] eraNames, int eraIndex) + { + // This matches the behavior on Win32 - only returning the first character of the era name. + // See Calendar.EraAsString(Int32) - https://msdn.microsoft.com/en-us/library/windows/apps/br206751.aspx + return eraNames[eraIndex].Substring(0, 1); + } + + private static bool GetJapaneseEraStartDate(int era, out DateTime dateTime) + { + Debug.Assert(!GlobalizationMode.Invariant); + + dateTime = default; + + int startYear; + int startMonth; + int startDay; + bool result = Interop.Globalization.GetJapaneseEraStartDate( + era, + out startYear, + out startMonth, + out startDay); + + if (result) + { + dateTime = new DateTime(startYear, startMonth, startDay); + } + + return result; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.Nls.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.Nls.cs new file mode 100644 index 00000000000000..09a59adb02ae6a --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.Nls.cs @@ -0,0 +1,213 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +#if TARGET_WINDOWS +using Internal.Win32; +#endif + +namespace System.Globalization +{ + public partial class JapaneseCalendar : Calendar + { +#if TARGET_WINDOWS + private const string JapaneseErasHive = @"System\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras"; + + // We know about 4 built-in eras, however users may add additional era(s) from the + // registry, by adding values to HKLM\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras + // + // Registry values look like: + // yyyy.mm.dd=era_abbrev_english_englishabbrev + // + // Where yyyy.mm.dd is the registry value name, and also the date of the era start. + // yyyy, mm, and dd are the year, month & day the era begins (4, 2 & 2 digits long) + // era is the Japanese Era name + // abbrev is the Abbreviated Japanese Era Name + // english is the English name for the Era (unused) + // englishabbrev is the Abbreviated English name for the era. + // . is a delimiter, but the value of . doesn't matter. + // '_' marks the space between the japanese era name, japanese abbreviated era name + // english name, and abbreviated english names. + private static EraInfo[]? NlsGetJapaneseEras() + { + Debug.Assert(GlobalizationMode.UseNls); + + // Look in the registry key and see if we can find any ranges + int iFoundEras = 0; + EraInfo[]? registryEraRanges = null; + + try + { + // Need to access registry + using (RegistryKey? key = Registry.LocalMachine.OpenSubKey(JapaneseErasHive)) + { + // Abort if we didn't find anything + if (key == null) return null; + + // Look up the values in our reg key + string[] valueNames = key.GetValueNames(); + if (valueNames != null && valueNames.Length > 0) + { + registryEraRanges = new EraInfo[valueNames.Length]; + + // Loop through the registry and read in all the values + for (int i = 0; i < valueNames.Length; i++) + { + // See if the era is a valid date + EraInfo? era = GetEraFromValue(valueNames[i], key.GetValue(valueNames[i])?.ToString()); + + // continue if not valid + if (era == null) continue; + + // Remember we found one. + registryEraRanges[iFoundEras] = era; + iFoundEras++; + } + } + } + } + catch (System.Security.SecurityException) + { + // If we weren't allowed to read, then just ignore the error + return null; + } + catch (System.IO.IOException) + { + // If key is being deleted just ignore the error + return null; + } + catch (System.UnauthorizedAccessException) + { + // Registry access rights permissions, just ignore the error + return null; + } + + // + // If we didn't have valid eras, then fail + // should have at least 4 eras + // + if (iFoundEras < 4) return null; + + // + // Now we have eras, clean them up. + // + // Clean up array length + Array.Resize(ref registryEraRanges, iFoundEras); + + // Sort them + Array.Sort(registryEraRanges, CompareEraRanges); + + // Clean up era information + for (int i = 0; i < registryEraRanges.Length; i++) + { + // eras count backwards from length to 1 (and are 1 based indexes into string arrays) + registryEraRanges[i].era = registryEraRanges.Length - i; + + // update max era year + if (i == 0) + { + // First range is 'til the end of the calendar + registryEraRanges[0].maxEraYear = GregorianCalendar.MaxYear - registryEraRanges[0].yearOffset; + } + else + { + // Rest are until the next era (remember most recent era is first in array) + registryEraRanges[i].maxEraYear = registryEraRanges[i - 1].yearOffset + 1 - registryEraRanges[i].yearOffset; + } + } + + // Return our ranges + return registryEraRanges; + } +#else + // no-op, in Unix we never call this function. + // the reason to have it is to simplify the build + // this way we avoid having to include RegistryKey + // and all it's windows PInvokes. + private static EraInfo[]? NlsGetJapaneseEras() + { + Debug.Fail("Should never be called non-Windows platforms."); + throw new PlatformNotSupportedException(); + } +#endif + + // + // Compare two era ranges, eg just the ticks + // Remember the era array is supposed to be in reverse chronological order + // + private static int CompareEraRanges(EraInfo a, EraInfo b) + { + return b.ticks.CompareTo(a.ticks); + } + + // + // GetEraFromValue + // + // Parse the registry value name/data pair into an era + // + // Registry values look like: + // yyyy.mm.dd=era_abbrev_english_englishabbrev + // + // Where yyyy.mm.dd is the registry value name, and also the date of the era start. + // yyyy, mm, and dd are the year, month & day the era begins (4, 2 & 2 digits long) + // era is the Japanese Era name + // abbrev is the Abbreviated Japanese Era Name + // english is the English name for the Era (unused) + // englishabbrev is the Abbreviated English name for the era. + // . is a delimiter, but the value of . doesn't matter. + // '_' marks the space between the japanese era name, japanese abbreviated era name + // english name, and abbreviated english names. + private static EraInfo? GetEraFromValue(string? value, string? data) + { + // Need inputs + if (value == null || data == null) return null; + + // + // Get Date + // + // Need exactly 10 characters in name for date + // yyyy.mm.dd although the . can be any character + if (value.Length != 10) return null; + + + ReadOnlySpan valueSpan = value.AsSpan(); + if (!int.TryParse(valueSpan.Slice(0, 4), NumberStyles.None, NumberFormatInfo.InvariantInfo, out int year) || + !int.TryParse(valueSpan.Slice(5, 2), NumberStyles.None, NumberFormatInfo.InvariantInfo, out int month) || + !int.TryParse(valueSpan.Slice(8, 2), NumberStyles.None, NumberFormatInfo.InvariantInfo, out int day)) + { + // Couldn't convert integer, fail + return null; + } + + // + // Get Strings + // + // Needs to be a certain length e_a_E_A at least (7 chars, exactly 4 groups) + string[] names = data.Split('_'); + + // Should have exactly 4 parts + // 0 - Era Name + // 1 - Abbreviated Era Name + // 2 - English Era Name + // 3 - Abbreviated English Era Name + if (names.Length != 4) return null; + + // Each part should have data in it + if (names[0].Length == 0 || + names[1].Length == 0 || + names[2].Length == 0 || + names[3].Length == 0) + return null; + + // + // Now we have an era we can build + // Note that the era # and max era year need cleaned up after sorting + // Don't use the full English Era Name (names[2]) + // + return new EraInfo(0, year, month, day, year - 1, 1, 0, + names[0], names[1], names[3]); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.Unix.cs deleted file mode 100644 index ed4e20de104472..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.Unix.cs +++ /dev/null @@ -1,96 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Diagnostics; - -namespace System.Globalization -{ - public partial class JapaneseCalendar : Calendar - { - private static EraInfo[]? GetJapaneseEras() - { - if (GlobalizationMode.Invariant) - { - return null; - } - - string[]? eraNames; - if (!CalendarData.EnumCalendarInfo("ja-JP", CalendarId.JAPAN, CalendarDataType.EraNames, out eraNames)) - { - return null; - } - - string[]? abbrevEnglishEraNames; - if (!CalendarData.EnumCalendarInfo("en", CalendarId.JAPAN, CalendarDataType.AbbrevEraNames, out abbrevEnglishEraNames)) - { - return null; - } - - List eras = new List(); - int lastMaxYear = GregorianCalendar.MaxYear; - - int latestEra = Interop.Globalization.GetLatestJapaneseEra(); - for (int i = latestEra; i >= 0; i--) - { - DateTime dt; - if (!GetJapaneseEraStartDate(i, out dt)) - { - return null; - } - - if (dt < s_calendarMinValue) - { - // only populate the Eras that are valid JapaneseCalendar date times - break; - } - - eras.Add(new EraInfo(i, dt.Year, dt.Month, dt.Day, dt.Year - 1, 1, lastMaxYear - dt.Year + 1, - eraNames![i], GetAbbreviatedEraName(eraNames, i), abbrevEnglishEraNames![i])); - - lastMaxYear = dt.Year; - } - - // remap the Era numbers, now that we know how many there will be - for (int i = 0; i < eras.Count; i++) - { - eras[i].era = eras.Count - i; - } - - return eras.ToArray(); - } - - // PAL Layer ends here - - private static string GetAbbreviatedEraName(string[] eraNames, int eraIndex) - { - // This matches the behavior on Win32 - only returning the first character of the era name. - // See Calendar.EraAsString(Int32) - https://msdn.microsoft.com/en-us/library/windows/apps/br206751.aspx - return eraNames[eraIndex].Substring(0, 1); - } - - private static bool GetJapaneseEraStartDate(int era, out DateTime dateTime) - { - Debug.Assert(!GlobalizationMode.Invariant); - - dateTime = default; - - int startYear; - int startMonth; - int startDay; - bool result = Interop.Globalization.GetJapaneseEraStartDate( - era, - out startYear, - out startMonth, - out startDay); - - if (result) - { - dateTime = new DateTime(startYear, startMonth, startDay); - } - - return result; - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.Win32.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.Win32.cs deleted file mode 100644 index 23ac1eebed26e6..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.Win32.cs +++ /dev/null @@ -1,195 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Internal.Win32; - -namespace System.Globalization -{ - public partial class JapaneseCalendar : Calendar - { - private const string JapaneseErasHive = @"System\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras"; - - // We know about 4 built-in eras, however users may add additional era(s) from the - // registry, by adding values to HKLM\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras - // - // Registry values look like: - // yyyy.mm.dd=era_abbrev_english_englishabbrev - // - // Where yyyy.mm.dd is the registry value name, and also the date of the era start. - // yyyy, mm, and dd are the year, month & day the era begins (4, 2 & 2 digits long) - // era is the Japanese Era name - // abbrev is the Abbreviated Japanese Era Name - // english is the English name for the Era (unused) - // englishabbrev is the Abbreviated English name for the era. - // . is a delimiter, but the value of . doesn't matter. - // '_' marks the space between the japanese era name, japanese abbreviated era name - // english name, and abbreviated english names. - private static EraInfo[]? GetJapaneseEras() - { - // Look in the registry key and see if we can find any ranges - int iFoundEras = 0; - EraInfo[]? registryEraRanges = null; - - try - { - // Need to access registry - using (RegistryKey? key = Registry.LocalMachine.OpenSubKey(JapaneseErasHive)) - { - // Abort if we didn't find anything - if (key == null) return null; - - // Look up the values in our reg key - string[] valueNames = key.GetValueNames(); - if (valueNames != null && valueNames.Length > 0) - { - registryEraRanges = new EraInfo[valueNames.Length]; - - // Loop through the registry and read in all the values - for (int i = 0; i < valueNames.Length; i++) - { - // See if the era is a valid date - EraInfo? era = GetEraFromValue(valueNames[i], key.GetValue(valueNames[i])?.ToString()); - - // continue if not valid - if (era == null) continue; - - // Remember we found one. - registryEraRanges[iFoundEras] = era; - iFoundEras++; - } - } - } - } - catch (System.Security.SecurityException) - { - // If we weren't allowed to read, then just ignore the error - return null; - } - catch (System.IO.IOException) - { - // If key is being deleted just ignore the error - return null; - } - catch (System.UnauthorizedAccessException) - { - // Registry access rights permissions, just ignore the error - return null; - } - - // - // If we didn't have valid eras, then fail - // should have at least 4 eras - // - if (iFoundEras < 4) return null; - - // - // Now we have eras, clean them up. - // - // Clean up array length - Array.Resize(ref registryEraRanges, iFoundEras); - - // Sort them - Array.Sort(registryEraRanges, CompareEraRanges); - - // Clean up era information - for (int i = 0; i < registryEraRanges.Length; i++) - { - // eras count backwards from length to 1 (and are 1 based indexes into string arrays) - registryEraRanges[i].era = registryEraRanges.Length - i; - - // update max era year - if (i == 0) - { - // First range is 'til the end of the calendar - registryEraRanges[0].maxEraYear = GregorianCalendar.MaxYear - registryEraRanges[0].yearOffset; - } - else - { - // Rest are until the next era (remember most recent era is first in array) - registryEraRanges[i].maxEraYear = registryEraRanges[i - 1].yearOffset + 1 - registryEraRanges[i].yearOffset; - } - } - - // Return our ranges - return registryEraRanges; - } - - // - // Compare two era ranges, eg just the ticks - // Remember the era array is supposed to be in reverse chronological order - // - private static int CompareEraRanges(EraInfo a, EraInfo b) - { - return b.ticks.CompareTo(a.ticks); - } - - // - // GetEraFromValue - // - // Parse the registry value name/data pair into an era - // - // Registry values look like: - // yyyy.mm.dd=era_abbrev_english_englishabbrev - // - // Where yyyy.mm.dd is the registry value name, and also the date of the era start. - // yyyy, mm, and dd are the year, month & day the era begins (4, 2 & 2 digits long) - // era is the Japanese Era name - // abbrev is the Abbreviated Japanese Era Name - // english is the English name for the Era (unused) - // englishabbrev is the Abbreviated English name for the era. - // . is a delimiter, but the value of . doesn't matter. - // '_' marks the space between the japanese era name, japanese abbreviated era name - // english name, and abbreviated english names. - private static EraInfo? GetEraFromValue(string? value, string? data) - { - // Need inputs - if (value == null || data == null) return null; - - // - // Get Date - // - // Need exactly 10 characters in name for date - // yyyy.mm.dd although the . can be any character - if (value.Length != 10) return null; - - - ReadOnlySpan valueSpan = value.AsSpan(); - if (!int.TryParse(valueSpan.Slice(0, 4), NumberStyles.None, NumberFormatInfo.InvariantInfo, out int year) || - !int.TryParse(valueSpan.Slice(5, 2), NumberStyles.None, NumberFormatInfo.InvariantInfo, out int month) || - !int.TryParse(valueSpan.Slice(8, 2), NumberStyles.None, NumberFormatInfo.InvariantInfo, out int day)) - { - // Couldn't convert integer, fail - return null; - } - - // - // Get Strings - // - // Needs to be a certain length e_a_E_A at least (7 chars, exactly 4 groups) - string[] names = data.Split('_'); - - // Should have exactly 4 parts - // 0 - Era Name - // 1 - Abbreviated Era Name - // 2 - English Era Name - // 3 - Abbreviated English Era Name - if (names.Length != 4) return null; - - // Each part should have data in it - if (names[0].Length == 0 || - names[1].Length == 0 || - names[2].Length == 0 || - names[3].Length == 0) - return null; - - // - // Now we have an era we can build - // Note that the era # and max era year need cleaned up after sorting - // Don't use the full English Era Name (names[2]) - // - return new EraInfo(0, year, month, day, year - 1, 1, 0, - names[0], names[1], names[3]); - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.cs index 02b15af270d983..2ed5af5b8e72d9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseCalendar.cs @@ -69,7 +69,7 @@ internal static EraInfo[] GetEraInfo() { // See if we need to build it return s_japaneseEraInfo ?? - (s_japaneseEraInfo = GetJapaneseEras()) ?? + (s_japaneseEraInfo = GlobalizationMode.UseNls ? NlsGetJapaneseEras() : IcuGetJapaneseEras()) ?? // See if we have to use the built-in eras (s_japaneseEraInfo = new EraInfo[] { diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/LocaleData.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/LocaleData.Unix.cs deleted file mode 100644 index 2af5eb9c250a19..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/LocaleData.Unix.cs +++ /dev/null @@ -1,4573 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; - -#pragma warning disable SA1001 - -// This file contains the handling of Windows OS specific culture features. - -namespace System.Globalization -{ - internal enum LocaleDataParts - { - Lcid = 0, - AnsiCodePage = 1, - OemCodePage = 2, - MacCodePage = 3, - EbcdicCodePage = 4, - GeoId = 5, - DigitSubstitution = 6, - SpecificLocaleIndex = 7, - ConsoleLocaleIndex = 8 - } - - internal static class LocaleData - { - // this is done rather than using a large readonly array of strings to avoid - // generating a large amount of code in the static constructor. - // Using indices from s_localeNamesIndices, we binary search this string when mapping - // an culture name to Lcid. Note that these names are all lowercase and are - // sorted alphabetically (ordinal). - private const string c_localeNames = - // culture name Lcid - "aa" + // 01000 - 0 - "aa-dj" + // 01000 - 2 - "aa-er" + // 01000 - 7 - "aa-et" + // 01000 - 12 - "af" + // 00036 - 17 - "af-na" + // 01000 - 19 - "af-za" + // 00436 - 24 - "agq" + // 01000 - 29 - "agq-cm" + // 01000 - 32 - "ak" + // 01000 - 38 - "ak-gh" + // 01000 - 40 - "am" + // 0005e - 45 - "am-et" + // 0045e - 47 - "ar" + // 00001 - 52 - "ar-001" + // 01000 - 54 - "ar-ae" + // 03801 - 60 - "ar-bh" + // 03c01 - 65 - "ar-dj" + // 01000 - 70 - "ar-dz" + // 01401 - 75 - "ar-eg" + // 00c01 - 80 - "ar-er" + // 01000 - 85 - "ar-il" + // 01000 - 90 - "ar-iq" + // 00801 - 95 - "ar-jo" + // 02c01 - 100 - "ar-km" + // 01000 - 105 - "ar-kw" + // 03401 - 110 - "ar-lb" + // 03001 - 115 - "ar-ly" + // 01001 - 120 - "ar-ma" + // 01801 - 125 - "ar-mr" + // 01000 - 130 - "ar-om" + // 02001 - 135 - "ar-ps" + // 01000 - 140 - "ar-qa" + // 04001 - 145 - "ar-sa" + // 00401 - 150 - "ar-sd" + // 01000 - 155 - "ar-so" + // 01000 - 160 - "ar-ss" + // 01000 - 165 - "ar-sy" + // 02801 - 170 - "ar-td" + // 01000 - 175 - "ar-tn" + // 01c01 - 180 - "ar-ye" + // 02401 - 185 - "arn" + // 0007a - 190 - "arn-cl" + // 0047a - 193 - "as" + // 0004d - 199 - "as-in" + // 0044d - 201 - "asa" + // 01000 - 206 - "asa-tz" + // 01000 - 209 - "ast" + // 01000 - 215 - "ast-es" + // 01000 - 218 - "az" + // 0002c - 224 - "az-cyrl" + // 0742c - 226 - "az-cyrl-az" + // 0082c - 233 - "az-latn" + // 0782c - 243 - "az-latn-az" + // 0042c - 250 - "ba" + // 0006d - 260 - "ba-ru" + // 0046d - 262 - "bas" + // 01000 - 267 - "bas-cm" + // 01000 - 270 - "be" + // 00023 - 276 - "be-by" + // 00423 - 278 - "bem" + // 01000 - 283 - "bem-zm" + // 01000 - 286 - "bez" + // 01000 - 292 - "bez-tz" + // 01000 - 295 - "bg" + // 00002 - 301 - "bg-bg" + // 00402 - 303 - "bin" + // 00066 - 308 - "bin-ng" + // 00466 - 311 - "bm" + // 01000 - 317 - "bm-latn" + // 01000 - 319 - "bm-latn-ml" + // 01000 - 326 - "bn" + // 00045 - 336 - "bn-bd" + // 00845 - 338 - "bn-in" + // 00445 - 343 - "bo" + // 00051 - 348 - "bo-cn" + // 00451 - 350 - "bo-in" + // 01000 - 355 - "br" + // 0007e - 360 - "br-fr" + // 0047e - 362 - "brx" + // 01000 - 367 - "brx-in" + // 01000 - 370 - "bs" + // 0781a - 376 - "bs-cyrl" + // 0641a - 378 - "bs-cyrl-ba" + // 0201a - 385 - "bs-latn" + // 0681a - 395 - "bs-latn-ba" + // 0141a - 402 - "byn" + // 01000 - 412 - "byn-er" + // 01000 - 415 - "ca" + // 00003 - 421 - "ca-ad" + // 01000 - 423 - "ca-es" + // 00403 - 428 - "ca-es-valencia" + // 00803 - 433 - "ca-fr" + // 01000 - 447 - "ca-it" + // 01000 - 452 - "ce" + // 01000 - 457 - "ce-ru" + // 01000 - 459 - "cgg" + // 01000 - 464 - "cgg-ug" + // 01000 - 467 - "chr" + // 0005c - 473 - "chr-cher" + // 07c5c - 476 - "chr-cher-us" + // 0045c - 484 - "co" + // 00083 - 495 - "co-fr" + // 00483 - 497 - "cs" + // 00005 - 502 - "cs-cz" + // 00405 - 504 - "cu" + // 01000 - 509 - "cu-ru" + // 01000 - 511 - "cy" + // 00052 - 516 - "cy-gb" + // 00452 - 518 - "da" + // 00006 - 523 - "da-dk" + // 00406 - 525 - "da-gl" + // 01000 - 530 - "dav" + // 01000 - 535 - "dav-ke" + // 01000 - 538 - "de" + // 00007 - 544 - "de-at" + // 00c07 - 546 - "de-be" + // 01000 - 551 - "de-ch" + // 00807 - 556 - "de-de" + // 00407 - 561 - "de-de_phoneb" + // 10407 - 566 - "de-it" + // 01000 - 578 - "de-li" + // 01407 - 583 - "de-lu" + // 01007 - 588 - "dje" + // 01000 - 593 - "dje-ne" + // 01000 - 596 - "dsb" + // 07c2e - 602 - "dsb-de" + // 0082e - 605 - "dua" + // 01000 - 611 - "dua-cm" + // 01000 - 614 - "dv" + // 00065 - 620 - "dv-mv" + // 00465 - 622 - "dyo" + // 01000 - 627 - "dyo-sn" + // 01000 - 630 - "dz" + // 01000 - 636 - "dz-bt" + // 00c51 - 638 - "ebu" + // 01000 - 643 - "ebu-ke" + // 01000 - 646 - "ee" + // 01000 - 652 - "ee-gh" + // 01000 - 654 - "ee-tg" + // 01000 - 659 - "el" + // 00008 - 664 - "el-cy" + // 01000 - 666 - "el-gr" + // 00408 - 671 - "en" + // 00009 - 676 - "en-001" + // 01000 - 678 - "en-029" + // 02409 - 684 - "en-150" + // 01000 - 690 - "en-ag" + // 01000 - 696 - "en-ai" + // 01000 - 701 - "en-as" + // 01000 - 706 - "en-at" + // 01000 - 711 - "en-au" + // 00c09 - 716 - "en-bb" + // 01000 - 721 - "en-be" + // 01000 - 726 - "en-bi" + // 01000 - 731 - "en-bm" + // 01000 - 736 - "en-bs" + // 01000 - 741 - "en-bw" + // 01000 - 746 - "en-bz" + // 02809 - 751 - "en-ca" + // 01009 - 756 - "en-cc" + // 01000 - 761 - "en-ch" + // 01000 - 766 - "en-ck" + // 01000 - 771 - "en-cm" + // 01000 - 776 - "en-cx" + // 01000 - 781 - "en-cy" + // 01000 - 786 - "en-de" + // 01000 - 791 - "en-dk" + // 01000 - 796 - "en-dm" + // 01000 - 801 - "en-er" + // 01000 - 806 - "en-fi" + // 01000 - 811 - "en-fj" + // 01000 - 816 - "en-fk" + // 01000 - 821 - "en-fm" + // 01000 - 826 - "en-gb" + // 00809 - 831 - "en-gd" + // 01000 - 836 - "en-gg" + // 01000 - 841 - "en-gh" + // 01000 - 846 - "en-gi" + // 01000 - 851 - "en-gm" + // 01000 - 856 - "en-gu" + // 01000 - 861 - "en-gy" + // 01000 - 866 - "en-hk" + // 03c09 - 871 - "en-id" + // 03809 - 876 - "en-ie" + // 01809 - 881 - "en-il" + // 01000 - 886 - "en-im" + // 01000 - 891 - "en-in" + // 04009 - 896 - "en-io" + // 01000 - 901 - "en-je" + // 01000 - 906 - "en-jm" + // 02009 - 911 - "en-ke" + // 01000 - 916 - "en-ki" + // 01000 - 921 - "en-kn" + // 01000 - 926 - "en-ky" + // 01000 - 931 - "en-lc" + // 01000 - 936 - "en-lr" + // 01000 - 941 - "en-ls" + // 01000 - 946 - "en-mg" + // 01000 - 951 - "en-mh" + // 01000 - 956 - "en-mo" + // 01000 - 961 - "en-mp" + // 01000 - 966 - "en-ms" + // 01000 - 971 - "en-mt" + // 01000 - 976 - "en-mu" + // 01000 - 981 - "en-mw" + // 01000 - 986 - "en-my" + // 04409 - 991 - "en-na" + // 01000 - 996 - "en-nf" + // 01000 - 1001 - "en-ng" + // 01000 - 1006 - "en-nl" + // 01000 - 1011 - "en-nr" + // 01000 - 1016 - "en-nu" + // 01000 - 1021 - "en-nz" + // 01409 - 1026 - "en-pg" + // 01000 - 1031 - "en-ph" + // 03409 - 1036 - "en-pk" + // 01000 - 1041 - "en-pn" + // 01000 - 1046 - "en-pr" + // 01000 - 1051 - "en-pw" + // 01000 - 1056 - "en-rw" + // 01000 - 1061 - "en-sb" + // 01000 - 1066 - "en-sc" + // 01000 - 1071 - "en-sd" + // 01000 - 1076 - "en-se" + // 01000 - 1081 - "en-sg" + // 04809 - 1086 - "en-sh" + // 01000 - 1091 - "en-si" + // 01000 - 1096 - "en-sl" + // 01000 - 1101 - "en-ss" + // 01000 - 1106 - "en-sx" + // 01000 - 1111 - "en-sz" + // 01000 - 1116 - "en-tc" + // 01000 - 1121 - "en-tk" + // 01000 - 1126 - "en-to" + // 01000 - 1131 - "en-tt" + // 02c09 - 1136 - "en-tv" + // 01000 - 1141 - "en-tz" + // 01000 - 1146 - "en-ug" + // 01000 - 1151 - "en-um" + // 01000 - 1156 - "en-us" + // 00409 - 1161 - "en-vc" + // 01000 - 1166 - "en-vg" + // 01000 - 1171 - "en-vi" + // 01000 - 1176 - "en-vu" + // 01000 - 1181 - "en-ws" + // 01000 - 1186 - "en-za" + // 01c09 - 1191 - "en-zm" + // 01000 - 1196 - "en-zw" + // 03009 - 1201 - "eo" + // 01000 - 1206 - "eo-001" + // 01000 - 1208 - "es" + // 0000a - 1214 - "es-419" + // 0580a - 1216 - "es-ar" + // 02c0a - 1222 - "es-bo" + // 0400a - 1227 - "es-br" + // 01000 - 1232 - "es-cl" + // 0340a - 1237 - "es-co" + // 0240a - 1242 - "es-cr" + // 0140a - 1247 - "es-cu" + // 05c0a - 1252 - "es-do" + // 01c0a - 1257 - "es-ec" + // 0300a - 1262 - "es-es" + // 00c0a - 1267 - "es-es_tradnl" + // 0040a - 1272 - "es-gq" + // 01000 - 1284 - "es-gt" + // 0100a - 1289 - "es-hn" + // 0480a - 1294 - "es-mx" + // 0080a - 1299 - "es-ni" + // 04c0a - 1304 - "es-pa" + // 0180a - 1309 - "es-pe" + // 0280a - 1314 - "es-ph" + // 01000 - 1319 - "es-pr" + // 0500a - 1324 - "es-py" + // 03c0a - 1329 - "es-sv" + // 0440a - 1334 - "es-us" + // 0540a - 1339 - "es-uy" + // 0380a - 1344 - "es-ve" + // 0200a - 1349 - "et" + // 00025 - 1354 - "et-ee" + // 00425 - 1356 - "eu" + // 0002d - 1361 - "eu-es" + // 0042d - 1363 - "ewo" + // 01000 - 1368 - "ewo-cm" + // 01000 - 1371 - "fa" + // 00029 - 1377 - "fa-ir" + // 00429 - 1379 - "ff" + // 00067 - 1384 - "ff-cm" + // 01000 - 1386 - "ff-gn" + // 01000 - 1391 - "ff-latn" + // 07c67 - 1396 - "ff-latn-sn" + // 00867 - 1403 - "ff-mr" + // 01000 - 1413 - "ff-ng" + // 00467 - 1418 - "fi" + // 0000b - 1423 - "fi-fi" + // 0040b - 1425 - "fil" + // 00064 - 1430 - "fil-ph" + // 00464 - 1433 - "fo" + // 00038 - 1439 - "fo-dk" + // 01000 - 1441 - "fo-fo" + // 00438 - 1446 - "fr" + // 0000c - 1451 - "fr-029" + // 01c0c - 1453 - "fr-be" + // 0080c - 1459 - "fr-bf" + // 01000 - 1464 - "fr-bi" + // 01000 - 1469 - "fr-bj" + // 01000 - 1474 - "fr-bl" + // 01000 - 1479 - "fr-ca" + // 00c0c - 1484 - "fr-cd" + // 0240c - 1489 - "fr-cf" + // 01000 - 1494 - "fr-cg" + // 01000 - 1499 - "fr-ch" + // 0100c - 1504 - "fr-ci" + // 0300c - 1509 - "fr-cm" + // 02c0c - 1514 - "fr-dj" + // 01000 - 1519 - "fr-dz" + // 01000 - 1524 - "fr-fr" + // 0040c - 1529 - "fr-ga" + // 01000 - 1534 - "fr-gf" + // 01000 - 1539 - "fr-gn" + // 01000 - 1544 - "fr-gp" + // 01000 - 1549 - "fr-gq" + // 01000 - 1554 - "fr-ht" + // 03c0c - 1559 - "fr-km" + // 01000 - 1564 - "fr-lu" + // 0140c - 1569 - "fr-ma" + // 0380c - 1574 - "fr-mc" + // 0180c - 1579 - "fr-mf" + // 01000 - 1584 - "fr-mg" + // 01000 - 1589 - "fr-ml" + // 0340c - 1594 - "fr-mq" + // 01000 - 1599 - "fr-mr" + // 01000 - 1604 - "fr-mu" + // 01000 - 1609 - "fr-nc" + // 01000 - 1614 - "fr-ne" + // 01000 - 1619 - "fr-pf" + // 01000 - 1624 - "fr-pm" + // 01000 - 1629 - "fr-re" + // 0200c - 1634 - "fr-rw" + // 01000 - 1639 - "fr-sc" + // 01000 - 1644 - "fr-sn" + // 0280c - 1649 - "fr-sy" + // 01000 - 1654 - "fr-td" + // 01000 - 1659 - "fr-tg" + // 01000 - 1664 - "fr-tn" + // 01000 - 1669 - "fr-vu" + // 01000 - 1674 - "fr-wf" + // 01000 - 1679 - "fr-yt" + // 01000 - 1684 - "fur" + // 01000 - 1689 - "fur-it" + // 01000 - 1692 - "fy" + // 00062 - 1698 - "fy-nl" + // 00462 - 1700 - "ga" + // 0003c - 1705 - "ga-ie" + // 0083c - 1707 - "gd" + // 00091 - 1712 - "gd-gb" + // 00491 - 1714 - "gl" + // 00056 - 1719 - "gl-es" + // 00456 - 1721 - "gn" + // 00074 - 1726 - "gn-py" + // 00474 - 1728 - "gsw" + // 00084 - 1733 - "gsw-ch" + // 01000 - 1736 - "gsw-fr" + // 00484 - 1742 - "gsw-li" + // 01000 - 1748 - "gu" + // 00047 - 1754 - "gu-in" + // 00447 - 1756 - "guz" + // 01000 - 1761 - "guz-ke" + // 01000 - 1764 - "gv" + // 01000 - 1770 - "gv-im" + // 01000 - 1772 - "ha" + // 00068 - 1777 - "ha-latn" + // 07c68 - 1779 - "ha-latn-gh" + // 01000 - 1786 - "ha-latn-ne" + // 01000 - 1796 - "ha-latn-ng" + // 00468 - 1806 - "haw" + // 00075 - 1816 - "haw-us" + // 00475 - 1819 - "he" + // 0000d - 1825 - "he-il" + // 0040d - 1827 - "hi" + // 00039 - 1832 - "hi-in" + // 00439 - 1834 - "hr" + // 0001a - 1839 - "hr-ba" + // 0101a - 1841 - "hr-hr" + // 0041a - 1846 - "hsb" + // 0002e - 1851 - "hsb-de" + // 0042e - 1854 - "hu" + // 0000e - 1860 - "hu-hu" + // 0040e - 1862 - "hu-hu_technl" + // 1040e - 1867 - "hy" + // 0002b - 1879 - "hy-am" + // 0042b - 1881 - "ia" + // 01000 - 1886 - "ia-001" + // 01000 - 1888 - "ia-fr" + // 01000 - 1894 - "ibb" + // 00069 - 1899 - "ibb-ng" + // 00469 - 1902 - "id" + // 00021 - 1908 - "id-id" + // 00421 - 1910 - "ig" + // 00070 - 1915 - "ig-ng" + // 00470 - 1917 - "ii" + // 00078 - 1922 - "ii-cn" + // 00478 - 1924 - "is" + // 0000f - 1929 - "is-is" + // 0040f - 1931 - "it" + // 00010 - 1936 - "it-ch" + // 00810 - 1938 - "it-it" + // 00410 - 1943 - "it-sm" + // 01000 - 1948 - "iu" + // 0005d - 1953 - "iu-cans" + // 0785d - 1955 - "iu-cans-ca" + // 0045d - 1962 - "iu-latn" + // 07c5d - 1972 - "iu-latn-ca" + // 0085d - 1979 - "ja" + // 00011 - 1989 - "ja-jp" + // 00411 - 1991 - "ja-jp_radstr" + // 40411 - 1996 - "jgo" + // 01000 - 2008 - "jgo-cm" + // 01000 - 2011 - "jmc" + // 01000 - 2017 - "jmc-tz" + // 01000 - 2020 - "jv" + // 01000 - 2026 - "jv-java" + // 01000 - 2028 - "jv-java-id" + // 01000 - 2035 - "jv-latn" + // 01000 - 2045 - "jv-latn-id" + // 01000 - 2052 - "ka" + // 00037 - 2062 - "ka-ge" + // 00437 - 2064 - "ka-ge_modern" + // 10437 - 2069 - "kab" + // 01000 - 2081 - "kab-dz" + // 01000 - 2084 - "kam" + // 01000 - 2090 - "kam-ke" + // 01000 - 2093 - "kde" + // 01000 - 2099 - "kde-tz" + // 01000 - 2102 - "kea" + // 01000 - 2108 - "kea-cv" + // 01000 - 2111 - "khq" + // 01000 - 2117 - "khq-ml" + // 01000 - 2120 - "ki" + // 01000 - 2126 - "ki-ke" + // 01000 - 2128 - "kk" + // 0003f - 2133 - "kk-kz" + // 0043f - 2135 - "kkj" + // 01000 - 2140 - "kkj-cm" + // 01000 - 2143 - "kl" + // 0006f - 2149 - "kl-gl" + // 0046f - 2151 - "kln" + // 01000 - 2156 - "kln-ke" + // 01000 - 2159 - "km" + // 00053 - 2165 - "km-kh" + // 00453 - 2167 - "kn" + // 0004b - 2172 - "kn-in" + // 0044b - 2174 - "ko" + // 00012 - 2179 - "ko-kp" + // 01000 - 2181 - "ko-kr" + // 00412 - 2186 - "kok" + // 00057 - 2191 - "kok-in" + // 00457 - 2194 - "kr" + // 00071 - 2200 - "kr-ng" + // 00471 - 2202 - "ks" + // 00060 - 2207 - "ks-arab" + // 00460 - 2209 - "ks-arab-in" + // 01000 - 2216 - "ks-deva" + // 01000 - 2226 - "ks-deva-in" + // 00860 - 2233 - "ksb" + // 01000 - 2243 - "ksb-tz" + // 01000 - 2246 - "ksf" + // 01000 - 2252 - "ksf-cm" + // 01000 - 2255 - "ksh" + // 01000 - 2261 - "ksh-de" + // 01000 - 2264 - "ku" + // 00092 - 2270 - "ku-arab" + // 07c92 - 2272 - "ku-arab-iq" + // 00492 - 2279 - "ku-arab-ir" + // 01000 - 2289 - "kw" + // 01000 - 2299 - "kw-gb" + // 01000 - 2301 - "ky" + // 00040 - 2306 - "ky-kg" + // 00440 - 2308 - "la" + // 00076 - 2313 - "la-001" + // 00476 - 2315 - "lag" + // 01000 - 2321 - "lag-tz" + // 01000 - 2324 - "lb" + // 0006e - 2330 - "lb-lu" + // 0046e - 2332 - "lg" + // 01000 - 2337 - "lg-ug" + // 01000 - 2339 - "lkt" + // 01000 - 2344 - "lkt-us" + // 01000 - 2347 - "ln" + // 01000 - 2353 - "ln-ao" + // 01000 - 2355 - "ln-cd" + // 01000 - 2360 - "ln-cf" + // 01000 - 2365 - "ln-cg" + // 01000 - 2370 - "lo" + // 00054 - 2375 - "lo-la" + // 00454 - 2377 - "lrc" + // 01000 - 2382 - "lrc-iq" + // 01000 - 2385 - "lrc-ir" + // 01000 - 2391 - "lt" + // 00027 - 2397 - "lt-lt" + // 00427 - 2399 - "lu" + // 01000 - 2404 - "lu-cd" + // 01000 - 2406 - "luo" + // 01000 - 2411 - "luo-ke" + // 01000 - 2414 - "luy" + // 01000 - 2420 - "luy-ke" + // 01000 - 2423 - "lv" + // 00026 - 2429 - "lv-lv" + // 00426 - 2431 - "mas" + // 01000 - 2436 - "mas-ke" + // 01000 - 2439 - "mas-tz" + // 01000 - 2445 - "mer" + // 01000 - 2451 - "mer-ke" + // 01000 - 2454 - "mfe" + // 01000 - 2460 - "mfe-mu" + // 01000 - 2463 - "mg" + // 01000 - 2469 - "mg-mg" + // 01000 - 2471 - "mgh" + // 01000 - 2476 - "mgh-mz" + // 01000 - 2479 - "mgo" + // 01000 - 2485 - "mgo-cm" + // 01000 - 2488 - "mi" + // 00081 - 2494 - "mi-nz" + // 00481 - 2496 - "mk" + // 0002f - 2501 - "mk-mk" + // 0042f - 2503 - "ml" + // 0004c - 2508 - "ml-in" + // 0044c - 2510 - "mn" + // 00050 - 2515 - "mn-cyrl" + // 07850 - 2517 - "mn-mn" + // 00450 - 2524 - "mn-mong" + // 07c50 - 2529 - "mn-mong-cn" + // 00850 - 2536 - "mn-mong-mn" + // 00c50 - 2546 - "mni" + // 00058 - 2556 - "mni-in" + // 00458 - 2559 - "moh" + // 0007c - 2565 - "moh-ca" + // 0047c - 2568 - "mr" + // 0004e - 2574 - "mr-in" + // 0044e - 2576 - "ms" + // 0003e - 2581 - "ms-bn" + // 0083e - 2583 - "ms-my" + // 0043e - 2588 - "ms-sg" + // 01000 - 2593 - "mt" + // 0003a - 2598 - "mt-mt" + // 0043a - 2600 - "mua" + // 01000 - 2605 - "mua-cm" + // 01000 - 2608 - "my" + // 00055 - 2614 - "my-mm" + // 00455 - 2616 - "mzn" + // 01000 - 2621 - "mzn-ir" + // 01000 - 2624 - "naq" + // 01000 - 2630 - "naq-na" + // 01000 - 2633 - "nb" + // 07c14 - 2639 - "nb-no" + // 00414 - 2641 - "nb-sj" + // 01000 - 2646 - "nd" + // 01000 - 2651 - "nd-zw" + // 01000 - 2653 - "nds" + // 01000 - 2658 - "nds-de" + // 01000 - 2661 - "nds-nl" + // 01000 - 2667 - "ne" + // 00061 - 2673 - "ne-in" + // 00861 - 2675 - "ne-np" + // 00461 - 2680 - "nl" + // 00013 - 2685 - "nl-aw" + // 01000 - 2687 - "nl-be" + // 00813 - 2692 - "nl-bq" + // 01000 - 2697 - "nl-cw" + // 01000 - 2702 - "nl-nl" + // 00413 - 2707 - "nl-sr" + // 01000 - 2712 - "nl-sx" + // 01000 - 2717 - "nmg" + // 01000 - 2722 - "nmg-cm" + // 01000 - 2725 - "nn" + // 07814 - 2731 - "nn-no" + // 00814 - 2733 - "nnh" + // 01000 - 2738 - "nnh-cm" + // 01000 - 2741 - "no" + // 00014 - 2747 - "nqo" + // 01000 - 2749 - "nqo-gn" + // 01000 - 2752 - "nr" + // 01000 - 2758 - "nr-za" + // 01000 - 2760 - "nso" + // 0006c - 2765 - "nso-za" + // 0046c - 2768 - "nus" + // 01000 - 2774 - "nus-ss" + // 01000 - 2777 - "nyn" + // 01000 - 2783 - "nyn-ug" + // 01000 - 2786 - "oc" + // 00082 - 2792 - "oc-fr" + // 00482 - 2794 - "om" + // 00072 - 2799 - "om-et" + // 00472 - 2801 - "om-ke" + // 01000 - 2806 - "or" + // 00048 - 2811 - "or-in" + // 00448 - 2813 - "os" + // 01000 - 2818 - "os-ge" + // 01000 - 2820 - "os-ru" + // 01000 - 2825 - "pa" + // 00046 - 2830 - "pa-arab" + // 07c46 - 2832 - "pa-arab-pk" + // 00846 - 2839 - "pa-in" + // 00446 - 2849 - "pap" + // 00079 - 2854 - "pap-029" + // 00479 - 2857 - "pl" + // 00015 - 2864 - "pl-pl" + // 00415 - 2866 - "prg" + // 01000 - 2871 - "prg-001" + // 01000 - 2874 - "prs" + // 0008c - 2881 - "prs-af" + // 0048c - 2884 - "ps" + // 00063 - 2890 - "ps-af" + // 00463 - 2892 - "pt" + // 00016 - 2897 - "pt-ao" + // 01000 - 2899 - "pt-br" + // 00416 - 2904 - "pt-ch" + // 01000 - 2909 - "pt-cv" + // 01000 - 2914 - "pt-gq" + // 01000 - 2919 - "pt-gw" + // 01000 - 2924 - "pt-lu" + // 01000 - 2929 - "pt-mo" + // 01000 - 2934 - "pt-mz" + // 01000 - 2939 - "pt-pt" + // 00816 - 2944 - "pt-st" + // 01000 - 2949 - "pt-tl" + // 01000 - 2954 - "qps-latn-x-sh" + // 00901 - 2959 - "qps-ploc" + // 00501 - 2972 - "qps-ploca" + // 005fe - 2980 - "qps-plocm" + // 009ff - 2989 - "quc" + // 00086 - 2998 - "quc-latn" + // 07c86 - 3001 - "quc-latn-gt" + // 00486 - 3009 - "quz" + // 0006b - 3020 - "quz-bo" + // 0046b - 3023 - "quz-ec" + // 0086b - 3029 - "quz-pe" + // 00c6b - 3035 - "rm" + // 00017 - 3041 - "rm-ch" + // 00417 - 3043 - "rn" + // 01000 - 3048 - "rn-bi" + // 01000 - 3050 - "ro" + // 00018 - 3055 - "ro-md" + // 00818 - 3057 - "ro-ro" + // 00418 - 3062 - "rof" + // 01000 - 3067 - "rof-tz" + // 01000 - 3070 - "ru" + // 00019 - 3076 - "ru-by" + // 01000 - 3078 - "ru-kg" + // 01000 - 3083 - "ru-kz" + // 01000 - 3088 - "ru-md" + // 00819 - 3093 - "ru-ru" + // 00419 - 3098 - "ru-ua" + // 01000 - 3103 - "rw" + // 00087 - 3108 - "rw-rw" + // 00487 - 3110 - "rwk" + // 01000 - 3115 - "rwk-tz" + // 01000 - 3118 - "sa" + // 0004f - 3124 - "sa-in" + // 0044f - 3126 - "sah" + // 00085 - 3131 - "sah-ru" + // 00485 - 3134 - "saq" + // 01000 - 3140 - "saq-ke" + // 01000 - 3143 - "sbp" + // 01000 - 3149 - "sbp-tz" + // 01000 - 3152 - "sd" + // 00059 - 3158 - "sd-arab" + // 07c59 - 3160 - "sd-arab-pk" + // 00859 - 3167 - "sd-deva" + // 01000 - 3177 - "sd-deva-in" + // 00459 - 3184 - "se" + // 0003b - 3194 - "se-fi" + // 00c3b - 3196 - "se-no" + // 0043b - 3201 - "se-se" + // 0083b - 3206 - "seh" + // 01000 - 3211 - "seh-mz" + // 01000 - 3214 - "ses" + // 01000 - 3220 - "ses-ml" + // 01000 - 3223 - "sg" + // 01000 - 3229 - "sg-cf" + // 01000 - 3231 - "shi" + // 01000 - 3236 - "shi-latn" + // 01000 - 3239 - "shi-latn-ma" + // 01000 - 3247 - "shi-tfng" + // 01000 - 3258 - "shi-tfng-ma" + // 01000 - 3266 - "si" + // 0005b - 3277 - "si-lk" + // 0045b - 3279 - "sk" + // 0001b - 3284 - "sk-sk" + // 0041b - 3286 - "sl" + // 00024 - 3291 - "sl-si" + // 00424 - 3293 - "sma" + // 0783b - 3298 - "sma-no" + // 0183b - 3301 - "sma-se" + // 01c3b - 3307 - "smj" + // 07c3b - 3313 - "smj-no" + // 0103b - 3316 - "smj-se" + // 0143b - 3322 - "smn" + // 0703b - 3328 - "smn-fi" + // 0243b - 3331 - "sms" + // 0743b - 3337 - "sms-fi" + // 0203b - 3340 - "sn" + // 01000 - 3346 - "sn-latn" + // 01000 - 3348 - "sn-latn-zw" + // 01000 - 3355 - "so" + // 00077 - 3365 - "so-dj" + // 01000 - 3367 - "so-et" + // 01000 - 3372 - "so-ke" + // 01000 - 3377 - "so-so" + // 00477 - 3382 - "sq" + // 0001c - 3387 - "sq-al" + // 0041c - 3389 - "sq-mk" + // 01000 - 3394 - "sq-xk" + // 01000 - 3399 - "sr" + // 07c1a - 3404 - "sr-cyrl" + // 06c1a - 3406 - "sr-cyrl-ba" + // 01c1a - 3413 - "sr-cyrl-cs" + // 00c1a - 3423 - "sr-cyrl-me" + // 0301a - 3433 - "sr-cyrl-rs" + // 0281a - 3443 - "sr-cyrl-xk" + // 01000 - 3453 - "sr-latn" + // 0701a - 3463 - "sr-latn-ba" + // 0181a - 3470 - "sr-latn-cs" + // 0081a - 3480 - "sr-latn-me" + // 02c1a - 3490 - "sr-latn-rs" + // 0241a - 3500 - "sr-latn-xk" + // 01000 - 3510 - "ss" + // 01000 - 3520 - "ss-sz" + // 01000 - 3522 - "ss-za" + // 01000 - 3527 - "ssy" + // 01000 - 3532 - "ssy-er" + // 01000 - 3535 - "st" + // 00030 - 3541 - "st-ls" + // 01000 - 3543 - "st-za" + // 00430 - 3548 - "sv" + // 0001d - 3553 - "sv-ax" + // 01000 - 3555 - "sv-fi" + // 0081d - 3560 - "sv-se" + // 0041d - 3565 - "sw" + // 00041 - 3570 - "sw-cd" + // 01000 - 3572 - "sw-ke" + // 00441 - 3577 - "sw-tz" + // 01000 - 3582 - "sw-ug" + // 01000 - 3587 - "swc" + // 01000 - 3592 - "swc-cd" + // 01000 - 3595 - "syr" + // 0005a - 3601 - "syr-sy" + // 0045a - 3604 - "ta" + // 00049 - 3610 - "ta-in" + // 00449 - 3612 - "ta-lk" + // 00849 - 3617 - "ta-my" + // 01000 - 3622 - "ta-sg" + // 01000 - 3627 - "te" + // 0004a - 3632 - "te-in" + // 0044a - 3634 - "teo" + // 01000 - 3639 - "teo-ke" + // 01000 - 3642 - "teo-ug" + // 01000 - 3648 - "tg" + // 00028 - 3654 - "tg-cyrl" + // 07c28 - 3656 - "tg-cyrl-tj" + // 00428 - 3663 - "th" + // 0001e - 3673 - "th-th" + // 0041e - 3675 - "ti" + // 00073 - 3680 - "ti-er" + // 00873 - 3682 - "ti-et" + // 00473 - 3687 - "tig" + // 01000 - 3692 - "tig-er" + // 01000 - 3695 - "tk" + // 00042 - 3701 - "tk-tm" + // 00442 - 3703 - "tn" + // 00032 - 3708 - "tn-bw" + // 00832 - 3710 - "tn-za" + // 00432 - 3715 - "to" + // 01000 - 3720 - "to-to" + // 01000 - 3722 - "tr" + // 0001f - 3727 - "tr-cy" + // 01000 - 3729 - "tr-tr" + // 0041f - 3734 - "ts" + // 00031 - 3739 - "ts-za" + // 00431 - 3741 - "tt" + // 00044 - 3746 - "tt-ru" + // 00444 - 3748 - "twq" + // 01000 - 3753 - "twq-ne" + // 01000 - 3756 - "tzm" + // 0005f - 3762 - "tzm-arab" + // 01000 - 3765 - "tzm-arab-ma" + // 0045f - 3773 - "tzm-latn" + // 07c5f - 3784 - "tzm-latn-dz" + // 0085f - 3792 - "tzm-latn-ma" + // 01000 - 3803 - "tzm-tfng" + // 0785f - 3814 - "tzm-tfng-ma" + // 0105f - 3822 - "ug" + // 00080 - 3833 - "ug-cn" + // 00480 - 3835 - "uk" + // 00022 - 3840 - "uk-ua" + // 00422 - 3842 - "ur" + // 00020 - 3847 - "ur-in" + // 00820 - 3849 - "ur-pk" + // 00420 - 3854 - "uz" + // 00043 - 3859 - "uz-arab" + // 01000 - 3861 - "uz-arab-af" + // 01000 - 3868 - "uz-cyrl" + // 07843 - 3878 - "uz-cyrl-uz" + // 00843 - 3885 - "uz-latn" + // 07c43 - 3895 - "uz-latn-uz" + // 00443 - 3902 - "vai" + // 01000 - 3912 - "vai-latn" + // 01000 - 3915 - "vai-latn-lr" + // 01000 - 3923 - "vai-vaii" + // 01000 - 3934 - "vai-vaii-lr" + // 01000 - 3942 - "ve" + // 00033 - 3953 - "ve-za" + // 00433 - 3955 - "vi" + // 0002a - 3960 - "vi-vn" + // 0042a - 3962 - "vo" + // 01000 - 3967 - "vo-001" + // 01000 - 3969 - "vun" + // 01000 - 3975 - "vun-tz" + // 01000 - 3978 - "wae" + // 01000 - 3984 - "wae-ch" + // 01000 - 3987 - "wal" + // 01000 - 3993 - "wal-et" + // 01000 - 3996 - "wo" + // 00088 - 4002 - "wo-sn" + // 00488 - 4004 - "x-iv_mathan" + // 1007f - 4009 - "xh" + // 00034 - 4020 - "xh-za" + // 00434 - 4022 - "xog" + // 01000 - 4027 - "xog-ug" + // 01000 - 4030 - "yav" + // 01000 - 4036 - "yav-cm" + // 01000 - 4039 - "yi" + // 0003d - 4045 - "yi-001" + // 0043d - 4047 - "yo" + // 0006a - 4053 - "yo-bj" + // 01000 - 4055 - "yo-ng" + // 0046a - 4060 - "yue" + // 01000 - 4065 - "yue-hk" + // 01000 - 4068 - "zgh" + // 01000 - 4074 - "zgh-tfng" + // 01000 - 4077 - "zgh-tfng-ma" + // 01000 - 4085 - "zh" + // 07804 - 4096 - "zh-chs" + // 00004 - 4098 - "zh-cht" + // 07c04 - 4104 - "zh-cn" + // 00804 - 4110 - "zh-cn_phoneb" + // 50804 - 4115 - "zh-cn_stroke" + // 20804 - 4127 - "zh-hans" + // 00004 - 4139 - "zh-hans-hk" + // 01000 - 4146 - "zh-hans-mo" + // 01000 - 4156 - "zh-hant" + // 07c04 - 4166 - "zh-hk" + // 00c04 - 4173 - "zh-hk_radstr" + // 40c04 - 4178 - "zh-mo" + // 01404 - 4190 - "zh-mo_radstr" + // 41404 - 4195 - "zh-mo_stroke" + // 21404 - 4207 - "zh-sg" + // 01004 - 4219 - "zh-sg_phoneb" + // 51004 - 4224 - "zh-sg_stroke" + // 21004 - 4236 - "zh-tw" + // 00404 - 4248 - "zh-tw_pronun" + // 30404 - 4253 - "zh-tw_radstr" + // 40404 - 4265 - "zu" + // 00035 - 4277 - "zu-za"; // 00435 - 4279 - - // c_threeLetterWindowsLanguageName is string containing 3-letter Windows language names - // every 3-characters entry is matching locale name entry in c_localeNames - - private const string c_threeLetterWindowsLanguageName = - "ZZZ" + // aa - "ZZZ" + // aa-dj - "ZZZ" + // aa-er - "ZZZ" + // aa-et - "AFK" + // af - "ZZZ" + // af-na - "AFK" + // af-za - "ZZZ" + // agq - "ZZZ" + // agq-cm - "ZZZ" + // ak - "ZZZ" + // ak-gh - "AMH" + // am - "AMH" + // am-et - "ARA" + // ar - "ZZZ" + // ar-001 - "ARU" + // ar-ae - "ARH" + // ar-bh - "ZZZ" + // ar-dj - "ARG" + // ar-dz - "ARE" + // ar-eg - "ZZZ" + // ar-er - "ZZZ" + // ar-il - "ARI" + // ar-iq - "ARJ" + // ar-jo - "ZZZ" + // ar-km - "ARK" + // ar-kw - "ARB" + // ar-lb - "ARL" + // ar-ly - "ARM" + // ar-ma - "ZZZ" + // ar-mr - "ARO" + // ar-om - "ZZZ" + // ar-ps - "ARQ" + // ar-qa - "ARA" + // ar-sa - "ZZZ" + // ar-sd - "ZZZ" + // ar-so - "ZZZ" + // ar-ss - "ARS" + // ar-sy - "ZZZ" + // ar-td - "ART" + // ar-tn - "ARY" + // ar-ye - "MPD" + // arn - "MPD" + // arn-cl - "ASM" + // as - "ASM" + // as-in - "ZZZ" + // asa - "ZZZ" + // asa-tz - "ZZZ" + // ast - "ZZZ" + // ast-es - "AZE" + // az - "AZC" + // az-cyrl - "AZC" + // az-cyrl-az - "AZE" + // az-latn - "AZE" + // az-latn-az - "BAS" + // ba - "BAS" + // ba-ru - "ZZZ" + // bas - "ZZZ" + // bas-cm - "BEL" + // be - "BEL" + // be-by - "ZZZ" + // bem - "ZZZ" + // bem-zm - "ZZZ" + // bez - "ZZZ" + // bez-tz - "BGR" + // bg - "BGR" + // bg-bg - "ZZZ" + // bin - "ZZZ" + // bin-ng - "ZZZ" + // bm - "ZZZ" + // bm-latn - "ZZZ" + // bm-latn-ml - "BNB" + // bn - "BNB" + // bn-bd - "BNG" + // bn-in - "BOB" + // bo - "BOB" + // bo-cn - "ZZZ" + // bo-in - "BRE" + // br - "BRE" + // br-fr - "ZZZ" + // brx - "ZZZ" + // brx-in - "BSB" + // bs - "BSC" + // bs-cyrl - "BSC" + // bs-cyrl-ba - "BSB" + // bs-latn - "BSB" + // bs-latn-ba - "ZZZ" + // byn - "ZZZ" + // byn-er - "CAT" + // ca - "ZZZ" + // ca-ad - "CAT" + // ca-es - "VAL" + // ca-es-valencia - "ZZZ" + // ca-fr - "ZZZ" + // ca-it - "ZZZ" + // ce - "ZZZ" + // ce-ru - "ZZZ" + // cgg - "ZZZ" + // cgg-ug - "CRE" + // chr - "CRE" + // chr-cher - "CRE" + // chr-cher-us - "COS" + // co - "COS" + // co-fr - "CSY" + // cs - "CSY" + // cs-cz - "ZZZ" + // cu - "ZZZ" + // cu-ru - "CYM" + // cy - "CYM" + // cy-gb - "DAN" + // da - "DAN" + // da-dk - "ZZZ" + // da-gl - "ZZZ" + // dav - "ZZZ" + // dav-ke - "DEU" + // de - "DEA" + // de-at - "ZZZ" + // de-be - "DES" + // de-ch - "DEU" + // de-de - "DEU" + // de-de_phoneb - "ZZZ" + // de-it - "DEC" + // de-li - "DEL" + // de-lu - "ZZZ" + // dje - "ZZZ" + // dje-ne - "DSB" + // dsb - "DSB" + // dsb-de - "ZZZ" + // dua - "ZZZ" + // dua-cm - "DIV" + // dv - "DIV" + // dv-mv - "ZZZ" + // dyo - "ZZZ" + // dyo-sn - "ZZZ" + // dz - "ZZZ" + // dz-bt - "ZZZ" + // ebu - "ZZZ" + // ebu-ke - "ZZZ" + // ee - "ZZZ" + // ee-gh - "ZZZ" + // ee-tg - "ELL" + // el - "ZZZ" + // el-cy - "ELL" + // el-gr - "ENU" + // en - "ZZZ" + // en-001 - "ENB" + // en-029 - "ZZZ" + // en-150 - "ZZZ" + // en-ag - "ZZZ" + // en-ai - "ZZZ" + // en-as - "ZZZ" + // en-at - "ENA" + // en-au - "ZZZ" + // en-bb - "ZZZ" + // en-be - "ZZZ" + // en-bi - "ZZZ" + // en-bm - "ZZZ" + // en-bs - "ZZZ" + // en-bw - "ENL" + // en-bz - "ENC" + // en-ca - "ZZZ" + // en-cc - "ZZZ" + // en-ch - "ZZZ" + // en-ck - "ZZZ" + // en-cm - "ZZZ" + // en-cx - "ZZZ" + // en-cy - "ZZZ" + // en-de - "ZZZ" + // en-dk - "ZZZ" + // en-dm - "ZZZ" + // en-er - "ZZZ" + // en-fi - "ZZZ" + // en-fj - "ZZZ" + // en-fk - "ZZZ" + // en-fm - "ENG" + // en-gb - "ZZZ" + // en-gd - "ZZZ" + // en-gg - "ZZZ" + // en-gh - "ZZZ" + // en-gi - "ZZZ" + // en-gm - "ZZZ" + // en-gu - "ZZZ" + // en-gy - "ENH" + // en-hk - "ZZZ" + // en-id - "ENI" + // en-ie - "ZZZ" + // en-il - "ZZZ" + // en-im - "ENN" + // en-in - "ZZZ" + // en-io - "ZZZ" + // en-je - "ENJ" + // en-jm - "ZZZ" + // en-ke - "ZZZ" + // en-ki - "ZZZ" + // en-kn - "ZZZ" + // en-ky - "ZZZ" + // en-lc - "ZZZ" + // en-lr - "ZZZ" + // en-ls - "ZZZ" + // en-mg - "ZZZ" + // en-mh - "ZZZ" + // en-mo - "ZZZ" + // en-mp - "ZZZ" + // en-ms - "ZZZ" + // en-mt - "ZZZ" + // en-mu - "ZZZ" + // en-mw - "ENM" + // en-my - "ZZZ" + // en-na - "ZZZ" + // en-nf - "ZZZ" + // en-ng - "ZZZ" + // en-nl - "ZZZ" + // en-nr - "ZZZ" + // en-nu - "ENZ" + // en-nz - "ZZZ" + // en-pg - "ENP" + // en-ph - "ZZZ" + // en-pk - "ZZZ" + // en-pn - "ZZZ" + // en-pr - "ZZZ" + // en-pw - "ZZZ" + // en-rw - "ZZZ" + // en-sb - "ZZZ" + // en-sc - "ZZZ" + // en-sd - "ZZZ" + // en-se - "ENE" + // en-sg - "ZZZ" + // en-sh - "ZZZ" + // en-si - "ZZZ" + // en-sl - "ZZZ" + // en-ss - "ZZZ" + // en-sx - "ZZZ" + // en-sz - "ZZZ" + // en-tc - "ZZZ" + // en-tk - "ZZZ" + // en-to - "ENT" + // en-tt - "ZZZ" + // en-tv - "ZZZ" + // en-tz - "ZZZ" + // en-ug - "ZZZ" + // en-um - "ENU" + // en-us - "ZZZ" + // en-vc - "ZZZ" + // en-vg - "ZZZ" + // en-vi - "ZZZ" + // en-vu - "ZZZ" + // en-ws - "ENS" + // en-za - "ZZZ" + // en-zm - "ENW" + // en-zw - "ZZZ" + // eo - "ZZZ" + // eo-001 - "ESN" + // es - "ESJ" + // es-419 - "ESS" + // es-ar - "ESB" + // es-bo - "ZZZ" + // es-br - "ESL" + // es-cl - "ESO" + // es-co - "ESC" + // es-cr - "ESK" + // es-cu - "ESD" + // es-do - "ESF" + // es-ec - "ESN" + // es-es - "ESP" + // es-es_tradnl - "ZZZ" + // es-gq - "ESG" + // es-gt - "ESH" + // es-hn - "ESM" + // es-mx - "ESI" + // es-ni - "ESA" + // es-pa - "ESR" + // es-pe - "ZZZ" + // es-ph - "ESU" + // es-pr - "ESZ" + // es-py - "ESE" + // es-sv - "EST" + // es-us - "ESY" + // es-uy - "ESV" + // es-ve - "ETI" + // et - "ETI" + // et-ee - "EUQ" + // eu - "EUQ" + // eu-es - "ZZZ" + // ewo - "ZZZ" + // ewo-cm - "FAR" + // fa - "FAR" + // fa-ir - "FUL" + // ff - "ZZZ" + // ff-cm - "ZZZ" + // ff-gn - "FUL" + // ff-latn - "FUL" + // ff-latn-sn - "ZZZ" + // ff-mr - "ZZZ" + // ff-ng - "FIN" + // fi - "FIN" + // fi-fi - "FPO" + // fil - "FPO" + // fil-ph - "FOS" + // fo - "ZZZ" + // fo-dk - "FOS" + // fo-fo - "FRA" + // fr - "ZZZ" + // fr-029 - "FRB" + // fr-be - "ZZZ" + // fr-bf - "ZZZ" + // fr-bi - "ZZZ" + // fr-bj - "ZZZ" + // fr-bl - "FRC" + // fr-ca - "FRD" + // fr-cd - "ZZZ" + // fr-cf - "ZZZ" + // fr-cg - "FRS" + // fr-ch - "FRI" + // fr-ci - "FRE" + // fr-cm - "ZZZ" + // fr-dj - "ZZZ" + // fr-dz - "FRA" + // fr-fr - "ZZZ" + // fr-ga - "ZZZ" + // fr-gf - "ZZZ" + // fr-gn - "ZZZ" + // fr-gp - "ZZZ" + // fr-gq - "FRH" + // fr-ht - "ZZZ" + // fr-km - "FRL" + // fr-lu - "FRO" + // fr-ma - "FRM" + // fr-mc - "ZZZ" + // fr-mf - "ZZZ" + // fr-mg - "FRF" + // fr-ml - "ZZZ" + // fr-mq - "ZZZ" + // fr-mr - "ZZZ" + // fr-mu - "ZZZ" + // fr-nc - "ZZZ" + // fr-ne - "ZZZ" + // fr-pf - "ZZZ" + // fr-pm - "FRR" + // fr-re - "ZZZ" + // fr-rw - "ZZZ" + // fr-sc - "FRN" + // fr-sn - "ZZZ" + // fr-sy - "ZZZ" + // fr-td - "ZZZ" + // fr-tg - "ZZZ" + // fr-tn - "ZZZ" + // fr-vu - "ZZZ" + // fr-wf - "ZZZ" + // fr-yt - "ZZZ" + // fur - "ZZZ" + // fur-it - "FYN" + // fy - "FYN" + // fy-nl - "IRE" + // ga - "IRE" + // ga-ie - "GLA" + // gd - "GLA" + // gd-gb - "GLC" + // gl - "GLC" + // gl-es - "GRN" + // gn - "GRN" + // gn-py - "ZZZ" + // gsw - "ZZZ" + // gsw-ch - "GSW" + // gsw-fr - "ZZZ" + // gsw-li - "GUJ" + // gu - "GUJ" + // gu-in - "ZZZ" + // guz - "ZZZ" + // guz-ke - "ZZZ" + // gv - "ZZZ" + // gv-im - "HAU" + // ha - "HAU" + // ha-latn - "ZZZ" + // ha-latn-gh - "ZZZ" + // ha-latn-ne - "HAU" + // ha-latn-ng - "HAW" + // haw - "HAW" + // haw-us - "HEB" + // he - "HEB" + // he-il - "HIN" + // hi - "HIN" + // hi-in - "HRV" + // hr - "HRB" + // hr-ba - "HRV" + // hr-hr - "HSB" + // hsb - "HSB" + // hsb-de - "HUN" + // hu - "HUN" + // hu-hu - "HUN" + // hu-hu_technl - "HYE" + // hy - "HYE" + // hy-am - "ZZZ" + // ia - "ZZZ" + // ia-001 - "ZZZ" + // ia-fr - "ZZZ" + // ibb - "ZZZ" + // ibb-ng - "IND" + // id - "IND" + // id-id - "IBO" + // ig - "IBO" + // ig-ng - "III" + // ii - "III" + // ii-cn - "ISL" + // is - "ISL" + // is-is - "ITA" + // it - "ITS" + // it-ch - "ITA" + // it-it - "ZZZ" + // it-sm - "IUK" + // iu - "IUS" + // iu-cans - "IUS" + // iu-cans-ca - "IUK" + // iu-latn - "IUK" + // iu-latn-ca - "JPN" + // ja - "JPN" + // ja-jp - "JPN" + // ja-jp_radstr - "ZZZ" + // jgo - "ZZZ" + // jgo-cm - "ZZZ" + // jmc - "ZZZ" + // jmc-tz - "JAV" + // jv - "ZZZ" + // jv-java - "ZZZ" + // jv-java-id - "JAV" + // jv-latn - "JAV" + // jv-latn-id - "KAT" + // ka - "KAT" + // ka-ge - "KAT" + // ka-ge_modern - "ZZZ" + // kab - "ZZZ" + // kab-dz - "ZZZ" + // kam - "ZZZ" + // kam-ke - "ZZZ" + // kde - "ZZZ" + // kde-tz - "ZZZ" + // kea - "ZZZ" + // kea-cv - "ZZZ" + // khq - "ZZZ" + // khq-ml - "ZZZ" + // ki - "ZZZ" + // ki-ke - "KKZ" + // kk - "KKZ" + // kk-kz - "ZZZ" + // kkj - "ZZZ" + // kkj-cm - "KAL" + // kl - "KAL" + // kl-gl - "ZZZ" + // kln - "ZZZ" + // kln-ke - "KHM" + // km - "KHM" + // km-kh - "KDI" + // kn - "KDI" + // kn-in - "KOR" + // ko - "ZZZ" + // ko-kp - "KOR" + // ko-kr - "KNK" + // kok - "KNK" + // kok-in - "ZZZ" + // kr - "ZZZ" + // kr-ng - "ZZZ" + // ks - "ZZZ" + // ks-arab - "ZZZ" + // ks-arab-in - "ZZZ" + // ks-deva - "ZZZ" + // ks-deva-in - "ZZZ" + // ksb - "ZZZ" + // ksb-tz - "ZZZ" + // ksf - "ZZZ" + // ksf-cm - "ZZZ" + // ksh - "ZZZ" + // ksh-de - "KUR" + // ku - "KUR" + // ku-arab - "KUR" + // ku-arab-iq - "ZZZ" + // ku-arab-ir - "ZZZ" + // kw - "ZZZ" + // kw-gb - "KYR" + // ky - "KYR" + // ky-kg - "ZZZ" + // la - "ZZZ" + // la-001 - "ZZZ" + // lag - "ZZZ" + // lag-tz - "LBX" + // lb - "LBX" + // lb-lu - "ZZZ" + // lg - "ZZZ" + // lg-ug - "ZZZ" + // lkt - "ZZZ" + // lkt-us - "ZZZ" + // ln - "ZZZ" + // ln-ao - "ZZZ" + // ln-cd - "ZZZ" + // ln-cf - "ZZZ" + // ln-cg - "LAO" + // lo - "LAO" + // lo-la - "ZZZ" + // lrc - "ZZZ" + // lrc-iq - "ZZZ" + // lrc-ir - "LTH" + // lt - "LTH" + // lt-lt - "ZZZ" + // lu - "ZZZ" + // lu-cd - "ZZZ" + // luo - "ZZZ" + // luo-ke - "ZZZ" + // luy - "ZZZ" + // luy-ke - "LVI" + // lv - "LVI" + // lv-lv - "ZZZ" + // mas - "ZZZ" + // mas-ke - "ZZZ" + // mas-tz - "ZZZ" + // mer - "ZZZ" + // mer-ke - "ZZZ" + // mfe - "ZZZ" + // mfe-mu - "MLG" + // mg - "MLG" + // mg-mg - "ZZZ" + // mgh - "ZZZ" + // mgh-mz - "ZZZ" + // mgo - "ZZZ" + // mgo-cm - "MRI" + // mi - "MRI" + // mi-nz - "MKI" + // mk - "MKI" + // mk-mk - "MYM" + // ml - "MYM" + // ml-in - "MNN" + // mn - "MNN" + // mn-cyrl - "MNN" + // mn-mn - "MNG" + // mn-mong - "MNG" + // mn-mong-cn - "MNM" + // mn-mong-mn - "ZZZ" + // mni - "ZZZ" + // mni-in - "MWK" + // moh - "MWK" + // moh-ca - "MAR" + // mr - "MAR" + // mr-in - "MSL" + // ms - "MSB" + // ms-bn - "MSL" + // ms-my - "ZZZ" + // ms-sg - "MLT" + // mt - "MLT" + // mt-mt - "ZZZ" + // mua - "ZZZ" + // mua-cm - "MYA" + // my - "MYA" + // my-mm - "ZZZ" + // mzn - "ZZZ" + // mzn-ir - "ZZZ" + // naq - "ZZZ" + // naq-na - "NOR" + // nb - "NOR" + // nb-no - "ZZZ" + // nb-sj - "ZZZ" + // nd - "ZZZ" + // nd-zw - "ZZZ" + // nds - "ZZZ" + // nds-de - "ZZZ" + // nds-nl - "NEP" + // ne - "NEI" + // ne-in - "NEP" + // ne-np - "NLD" + // nl - "ZZZ" + // nl-aw - "NLB" + // nl-be - "ZZZ" + // nl-bq - "ZZZ" + // nl-cw - "NLD" + // nl-nl - "ZZZ" + // nl-sr - "ZZZ" + // nl-sx - "ZZZ" + // nmg - "ZZZ" + // nmg-cm - "NON" + // nn - "NON" + // nn-no - "ZZZ" + // nnh - "ZZZ" + // nnh-cm - "NOR" + // no - "NQO" + // nqo - "NQO" + // nqo-gn - "ZZZ" + // nr - "ZZZ" + // nr-za - "NSO" + // nso - "NSO" + // nso-za - "ZZZ" + // nus - "ZZZ" + // nus-ss - "ZZZ" + // nyn - "ZZZ" + // nyn-ug - "OCI" + // oc - "OCI" + // oc-fr - "ORM" + // om - "ORM" + // om-et - "ZZZ" + // om-ke - "ORI" + // or - "ORI" + // or-in - "ZZZ" + // os - "ZZZ" + // os-ge - "ZZZ" + // os-ru - "PAN" + // pa - "PAP" + // pa-arab - "PAP" + // pa-arab-pk - "PAN" + // pa-in - "ZZZ" + // pap - "ZZZ" + // pap-029 - "PLK" + // pl - "PLK" + // pl-pl - "ZZZ" + // prg - "ZZZ" + // prg-001 - "PRS" + // prs - "PRS" + // prs-af - "PAS" + // ps - "PAS" + // ps-af - "PTB" + // pt - "PTA" + // pt-ao - "PTB" + // pt-br - "ZZZ" + // pt-ch - "ZZZ" + // pt-cv - "ZZZ" + // pt-gq - "ZZZ" + // pt-gw - "ZZZ" + // pt-lu - "ZZZ" + // pt-mo - "ZZZ" + // pt-mz - "PTG" + // pt-pt - "ZZZ" + // pt-st - "ZZZ" + // pt-tl - "ENJ" + // qps-latn-x-sh - "ENU" + // qps-ploc - "JPN" + // qps-ploca - "ARA" + // qps-plocm - "QUT" + // quc - "QUT" + // quc-latn - "QUT" + // quc-latn-gt - "QUB" + // quz - "QUB" + // quz-bo - "QUE" + // quz-ec - "QUP" + // quz-pe - "RMC" + // rm - "RMC" + // rm-ch - "ZZZ" + // rn - "ZZZ" + // rn-bi - "ROM" + // ro - "ROD" + // ro-md - "ROM" + // ro-ro - "ZZZ" + // rof - "ZZZ" + // rof-tz - "RUS" + // ru - "ZZZ" + // ru-by - "ZZZ" + // ru-kg - "ZZZ" + // ru-kz - "RUM" + // ru-md - "RUS" + // ru-ru - "ZZZ" + // ru-ua - "KIN" + // rw - "KIN" + // rw-rw - "ZZZ" + // rwk - "ZZZ" + // rwk-tz - "SAN" + // sa - "SAN" + // sa-in - "SAH" + // sah - "SAH" + // sah-ru - "ZZZ" + // saq - "ZZZ" + // saq-ke - "ZZZ" + // sbp - "ZZZ" + // sbp-tz - "SIP" + // sd - "SIP" + // sd-arab - "SIP" + // sd-arab-pk - "ZZZ" + // sd-deva - "ZZZ" + // sd-deva-in - "SME" + // se - "SMG" + // se-fi - "SME" + // se-no - "SMF" + // se-se - "ZZZ" + // seh - "ZZZ" + // seh-mz - "ZZZ" + // ses - "ZZZ" + // ses-ml - "ZZZ" + // sg - "ZZZ" + // sg-cf - "ZZZ" + // shi - "ZZZ" + // shi-latn - "ZZZ" + // shi-latn-ma - "ZZZ" + // shi-tfng - "ZZZ" + // shi-tfng-ma - "SIN" + // si - "SIN" + // si-lk - "SKY" + // sk - "SKY" + // sk-sk - "SLV" + // sl - "SLV" + // sl-si - "SMB" + // sma - "SMA" + // sma-no - "SMB" + // sma-se - "SMK" + // smj - "SMJ" + // smj-no - "SMK" + // smj-se - "SMN" + // smn - "SMN" + // smn-fi - "SMS" + // sms - "SMS" + // sms-fi - "SNA" + // sn - "SNA" + // sn-latn - "SNA" + // sn-latn-zw - "SOM" + // so - "ZZZ" + // so-dj - "ZZZ" + // so-et - "ZZZ" + // so-ke - "SOM" + // so-so - "SQI" + // sq - "SQI" + // sq-al - "ZZZ" + // sq-mk - "ZZZ" + // sq-xk - "SRM" + // sr - "SRO" + // sr-cyrl - "SRN" + // sr-cyrl-ba - "SRB" + // sr-cyrl-cs - "SRQ" + // sr-cyrl-me - "SRO" + // sr-cyrl-rs - "ZZZ" + // sr-cyrl-xk - "SRM" + // sr-latn - "SRS" + // sr-latn-ba - "SRL" + // sr-latn-cs - "SRP" + // sr-latn-me - "SRM" + // sr-latn-rs - "ZZZ" + // sr-latn-xk - "ZZZ" + // ss - "ZZZ" + // ss-sz - "ZZZ" + // ss-za - "ZZZ" + // ssy - "ZZZ" + // ssy-er - "SOT" + // st - "ZZZ" + // st-ls - "SOT" + // st-za - "SVE" + // sv - "ZZZ" + // sv-ax - "SVF" + // sv-fi - "SVE" + // sv-se - "SWK" + // sw - "ZZZ" + // sw-cd - "SWK" + // sw-ke - "ZZZ" + // sw-tz - "ZZZ" + // sw-ug - "ZZZ" + // swc - "ZZZ" + // swc-cd - "SYR" + // syr - "SYR" + // syr-sy - "TAI" + // ta - "TAI" + // ta-in - "TAM" + // ta-lk - "ZZZ" + // ta-my - "ZZZ" + // ta-sg - "TEL" + // te - "TEL" + // te-in - "ZZZ" + // teo - "ZZZ" + // teo-ke - "ZZZ" + // teo-ug - "TAJ" + // tg - "TAJ" + // tg-cyrl - "TAJ" + // tg-cyrl-tj - "THA" + // th - "THA" + // th-th - "TIR" + // ti - "TIR" + // ti-er - "TIE" + // ti-et - "ZZZ" + // tig - "ZZZ" + // tig-er - "TUK" + // tk - "TUK" + // tk-tm - "TSN" + // tn - "TSB" + // tn-bw - "TSN" + // tn-za - "ZZZ" + // to - "ZZZ" + // to-to - "TRK" + // tr - "ZZZ" + // tr-cy - "TRK" + // tr-tr - "TSO" + // ts - "TSO" + // ts-za - "TTT" + // tt - "TTT" + // tt-ru - "ZZZ" + // twq - "ZZZ" + // twq-ne - "TZA" + // tzm - "ZZZ" + // tzm-arab - "ZZZ" + // tzm-arab-ma - "TZA" + // tzm-latn - "TZA" + // tzm-latn-dz - "ZZZ" + // tzm-latn-ma - "TZM" + // tzm-tfng - "TZM" + // tzm-tfng-ma - "UIG" + // ug - "UIG" + // ug-cn - "UKR" + // uk - "UKR" + // uk-ua - "URD" + // ur - "URI" + // ur-in - "URD" + // ur-pk - "UZB" + // uz - "ZZZ" + // uz-arab - "ZZZ" + // uz-arab-af - "UZC" + // uz-cyrl - "UZC" + // uz-cyrl-uz - "UZB" + // uz-latn - "UZB" + // uz-latn-uz - "ZZZ" + // vai - "ZZZ" + // vai-latn - "ZZZ" + // vai-latn-lr - "ZZZ" + // vai-vaii - "ZZZ" + // vai-vaii-lr - "ZZZ" + // ve - "ZZZ" + // ve-za - "VIT" + // vi - "VIT" + // vi-vn - "ZZZ" + // vo - "ZZZ" + // vo-001 - "ZZZ" + // vun - "ZZZ" + // vun-tz - "ZZZ" + // wae - "ZZZ" + // wae-ch - "ZZZ" + // wal - "ZZZ" + // wal-et - "WOL" + // wo - "WOL" + // wo-sn - "IVL" + // x-iv_mathan - "XHO" + // xh - "XHO" + // xh-za - "ZZZ" + // xog - "ZZZ" + // xog-ug - "ZZZ" + // yav - "ZZZ" + // yav-cm - "ZZZ" + // yi - "ZZZ" + // yi-001 - "YOR" + // yo - "ZZZ" + // yo-bj - "YOR" + // yo-ng - "ZZZ" + // yue - "ZZZ" + // yue-hk - "ZHG" + // zgh - "ZHG" + // zgh-tfng - "ZHG" + // zgh-tfng-ma - "CHS" + // zh - "CHS" + // zh-chs - "CHT" + // zh-cht - "CHS" + // zh-cn - "CHS" + // zh-cn_phoneb - "CHS" + // zh-cn_stroke - "CHS" + // zh-hans - "ZZZ" + // zh-hans-hk - "ZZZ" + // zh-hans-mo - "ZHH" + // zh-hant - "ZHH" + // zh-hk - "ZHH" + // zh-hk_radstr - "ZHM" + // zh-mo - "ZHM" + // zh-mo_radstr - "ZHM" + // zh-mo_stroke - "ZHI" + // zh-sg - "ZHI" + // zh-sg_phoneb - "ZHI" + // zh-sg_stroke - "CHT" + // zh-tw - "CHT" + // zh-tw_pronun - "CHT" + // zh-tw_radstr - "ZUL" + // zu - "ZUL"; // zu-za - - // s_localeNamesIndices contains the start index of every culture name in the string - // s_localeNames. We infer the length of each string by looking at the start index - // of the next string. - private static readonly int[] s_localeNamesIndices = new int[] - { - // c_localeNames index, // index to this array - culture name - 0 , // 0 - aa - 2 , // 1 - aa-dj - 7 , // 2 - aa-er - 12 , // 3 - aa-et - 17 , // 4 - af - 19 , // 5 - af-na - 24 , // 6 - af-za - 29 , // 7 - agq - 32 , // 8 - agq-cm - 38 , // 9 - ak - 40 , // 10 - ak-gh - 45 , // 11 - am - 47 , // 12 - am-et - 52 , // 13 - ar - 54 , // 14 - ar-001 - 60 , // 15 - ar-ae - 65 , // 16 - ar-bh - 70 , // 17 - ar-dj - 75 , // 18 - ar-dz - 80 , // 19 - ar-eg - 85 , // 20 - ar-er - 90 , // 21 - ar-il - 95 , // 22 - ar-iq - 100 , // 23 - ar-jo - 105 , // 24 - ar-km - 110 , // 25 - ar-kw - 115 , // 26 - ar-lb - 120 , // 27 - ar-ly - 125 , // 28 - ar-ma - 130 , // 29 - ar-mr - 135 , // 30 - ar-om - 140 , // 31 - ar-ps - 145 , // 32 - ar-qa - 150 , // 33 - ar-sa - 155 , // 34 - ar-sd - 160 , // 35 - ar-so - 165 , // 36 - ar-ss - 170 , // 37 - ar-sy - 175 , // 38 - ar-td - 180 , // 39 - ar-tn - 185 , // 40 - ar-ye - 190 , // 41 - arn - 193 , // 42 - arn-cl - 199 , // 43 - as - 201 , // 44 - as-in - 206 , // 45 - asa - 209 , // 46 - asa-tz - 215 , // 47 - ast - 218 , // 48 - ast-es - 224 , // 49 - az - 226 , // 50 - az-cyrl - 233 , // 51 - az-cyrl-az - 243 , // 52 - az-latn - 250 , // 53 - az-latn-az - 260 , // 54 - ba - 262 , // 55 - ba-ru - 267 , // 56 - bas - 270 , // 57 - bas-cm - 276 , // 58 - be - 278 , // 59 - be-by - 283 , // 60 - bem - 286 , // 61 - bem-zm - 292 , // 62 - bez - 295 , // 63 - bez-tz - 301 , // 64 - bg - 303 , // 65 - bg-bg - 308 , // 66 - bin - 311 , // 67 - bin-ng - 317 , // 68 - bm - 319 , // 69 - bm-latn - 326 , // 70 - bm-latn-ml - 336 , // 71 - bn - 338 , // 72 - bn-bd - 343 , // 73 - bn-in - 348 , // 74 - bo - 350 , // 75 - bo-cn - 355 , // 76 - bo-in - 360 , // 77 - br - 362 , // 78 - br-fr - 367 , // 79 - brx - 370 , // 80 - brx-in - 376 , // 81 - bs - 378 , // 82 - bs-cyrl - 385 , // 83 - bs-cyrl-ba - 395 , // 84 - bs-latn - 402 , // 85 - bs-latn-ba - 412 , // 86 - byn - 415 , // 87 - byn-er - 421 , // 88 - ca - 423 , // 89 - ca-ad - 428 , // 90 - ca-es - 433 , // 91 - ca-es-valencia - 447 , // 92 - ca-fr - 452 , // 93 - ca-it - 457 , // 94 - ce - 459 , // 95 - ce-ru - 464 , // 96 - cgg - 467 , // 97 - cgg-ug - 473 , // 98 - chr - 476 , // 99 - chr-cher - 484 , // 100 - chr-cher-us - 495 , // 101 - co - 497 , // 102 - co-fr - 502 , // 103 - cs - 504 , // 104 - cs-cz - 509 , // 105 - cu - 511 , // 106 - cu-ru - 516 , // 107 - cy - 518 , // 108 - cy-gb - 523 , // 109 - da - 525 , // 110 - da-dk - 530 , // 111 - da-gl - 535 , // 112 - dav - 538 , // 113 - dav-ke - 544 , // 114 - de - 546 , // 115 - de-at - 551 , // 116 - de-be - 556 , // 117 - de-ch - 561 , // 118 - de-de - 566 , // 119 - de-de_phoneb - 578 , // 120 - de-it - 583 , // 121 - de-li - 588 , // 122 - de-lu - 593 , // 123 - dje - 596 , // 124 - dje-ne - 602 , // 125 - dsb - 605 , // 126 - dsb-de - 611 , // 127 - dua - 614 , // 128 - dua-cm - 620 , // 129 - dv - 622 , // 130 - dv-mv - 627 , // 131 - dyo - 630 , // 132 - dyo-sn - 636 , // 133 - dz - 638 , // 134 - dz-bt - 643 , // 135 - ebu - 646 , // 136 - ebu-ke - 652 , // 137 - ee - 654 , // 138 - ee-gh - 659 , // 139 - ee-tg - 664 , // 140 - el - 666 , // 141 - el-cy - 671 , // 142 - el-gr - 676 , // 143 - en - 678 , // 144 - en-001 - 684 , // 145 - en-029 - 690 , // 146 - en-150 - 696 , // 147 - en-ag - 701 , // 148 - en-ai - 706 , // 149 - en-as - 711 , // 150 - en-at - 716 , // 151 - en-au - 721 , // 152 - en-bb - 726 , // 153 - en-be - 731 , // 154 - en-bi - 736 , // 155 - en-bm - 741 , // 156 - en-bs - 746 , // 157 - en-bw - 751 , // 158 - en-bz - 756 , // 159 - en-ca - 761 , // 160 - en-cc - 766 , // 161 - en-ch - 771 , // 162 - en-ck - 776 , // 163 - en-cm - 781 , // 164 - en-cx - 786 , // 165 - en-cy - 791 , // 166 - en-de - 796 , // 167 - en-dk - 801 , // 168 - en-dm - 806 , // 169 - en-er - 811 , // 170 - en-fi - 816 , // 171 - en-fj - 821 , // 172 - en-fk - 826 , // 173 - en-fm - 831 , // 174 - en-gb - 836 , // 175 - en-gd - 841 , // 176 - en-gg - 846 , // 177 - en-gh - 851 , // 178 - en-gi - 856 , // 179 - en-gm - 861 , // 180 - en-gu - 866 , // 181 - en-gy - 871 , // 182 - en-hk - 876 , // 183 - en-id - 881 , // 184 - en-ie - 886 , // 185 - en-il - 891 , // 186 - en-im - 896 , // 187 - en-in - 901 , // 188 - en-io - 906 , // 189 - en-je - 911 , // 190 - en-jm - 916 , // 191 - en-ke - 921 , // 192 - en-ki - 926 , // 193 - en-kn - 931 , // 194 - en-ky - 936 , // 195 - en-lc - 941 , // 196 - en-lr - 946 , // 197 - en-ls - 951 , // 198 - en-mg - 956 , // 199 - en-mh - 961 , // 200 - en-mo - 966 , // 201 - en-mp - 971 , // 202 - en-ms - 976 , // 203 - en-mt - 981 , // 204 - en-mu - 986 , // 205 - en-mw - 991 , // 206 - en-my - 996 , // 207 - en-na - 1001, // 208 - en-nf - 1006, // 209 - en-ng - 1011, // 210 - en-nl - 1016, // 211 - en-nr - 1021, // 212 - en-nu - 1026, // 213 - en-nz - 1031, // 214 - en-pg - 1036, // 215 - en-ph - 1041, // 216 - en-pk - 1046, // 217 - en-pn - 1051, // 218 - en-pr - 1056, // 219 - en-pw - 1061, // 220 - en-rw - 1066, // 221 - en-sb - 1071, // 222 - en-sc - 1076, // 223 - en-sd - 1081, // 224 - en-se - 1086, // 225 - en-sg - 1091, // 226 - en-sh - 1096, // 227 - en-si - 1101, // 228 - en-sl - 1106, // 229 - en-ss - 1111, // 230 - en-sx - 1116, // 231 - en-sz - 1121, // 232 - en-tc - 1126, // 233 - en-tk - 1131, // 234 - en-to - 1136, // 235 - en-tt - 1141, // 236 - en-tv - 1146, // 237 - en-tz - 1151, // 238 - en-ug - 1156, // 239 - en-um - 1161, // 240 - en-us - 1166, // 241 - en-vc - 1171, // 242 - en-vg - 1176, // 243 - en-vi - 1181, // 244 - en-vu - 1186, // 245 - en-ws - 1191, // 246 - en-za - 1196, // 247 - en-zm - 1201, // 248 - en-zw - 1206, // 249 - eo - 1208, // 250 - eo-001 - 1214, // 251 - es - 1216, // 252 - es-419 - 1222, // 253 - es-ar - 1227, // 254 - es-bo - 1232, // 255 - es-br - 1237, // 256 - es-cl - 1242, // 257 - es-co - 1247, // 258 - es-cr - 1252, // 259 - es-cu - 1257, // 260 - es-do - 1262, // 261 - es-ec - 1267, // 262 - es-es - 1272, // 263 - es-es_tradnl - 1284, // 264 - es-gq - 1289, // 265 - es-gt - 1294, // 266 - es-hn - 1299, // 267 - es-mx - 1304, // 268 - es-ni - 1309, // 269 - es-pa - 1314, // 270 - es-pe - 1319, // 271 - es-ph - 1324, // 272 - es-pr - 1329, // 273 - es-py - 1334, // 274 - es-sv - 1339, // 275 - es-us - 1344, // 276 - es-uy - 1349, // 277 - es-ve - 1354, // 278 - et - 1356, // 279 - et-ee - 1361, // 280 - eu - 1363, // 281 - eu-es - 1368, // 282 - ewo - 1371, // 283 - ewo-cm - 1377, // 284 - fa - 1379, // 285 - fa-ir - 1384, // 286 - ff - 1386, // 287 - ff-cm - 1391, // 288 - ff-gn - 1396, // 289 - ff-latn - 1403, // 290 - ff-latn-sn - 1413, // 291 - ff-mr - 1418, // 292 - ff-ng - 1423, // 293 - fi - 1425, // 294 - fi-fi - 1430, // 295 - fil - 1433, // 296 - fil-ph - 1439, // 297 - fo - 1441, // 298 - fo-dk - 1446, // 299 - fo-fo - 1451, // 300 - fr - 1453, // 301 - fr-029 - 1459, // 302 - fr-be - 1464, // 303 - fr-bf - 1469, // 304 - fr-bi - 1474, // 305 - fr-bj - 1479, // 306 - fr-bl - 1484, // 307 - fr-ca - 1489, // 308 - fr-cd - 1494, // 309 - fr-cf - 1499, // 310 - fr-cg - 1504, // 311 - fr-ch - 1509, // 312 - fr-ci - 1514, // 313 - fr-cm - 1519, // 314 - fr-dj - 1524, // 315 - fr-dz - 1529, // 316 - fr-fr - 1534, // 317 - fr-ga - 1539, // 318 - fr-gf - 1544, // 319 - fr-gn - 1549, // 320 - fr-gp - 1554, // 321 - fr-gq - 1559, // 322 - fr-ht - 1564, // 323 - fr-km - 1569, // 324 - fr-lu - 1574, // 325 - fr-ma - 1579, // 326 - fr-mc - 1584, // 327 - fr-mf - 1589, // 328 - fr-mg - 1594, // 329 - fr-ml - 1599, // 330 - fr-mq - 1604, // 331 - fr-mr - 1609, // 332 - fr-mu - 1614, // 333 - fr-nc - 1619, // 334 - fr-ne - 1624, // 335 - fr-pf - 1629, // 336 - fr-pm - 1634, // 337 - fr-re - 1639, // 338 - fr-rw - 1644, // 339 - fr-sc - 1649, // 340 - fr-sn - 1654, // 341 - fr-sy - 1659, // 342 - fr-td - 1664, // 343 - fr-tg - 1669, // 344 - fr-tn - 1674, // 345 - fr-vu - 1679, // 346 - fr-wf - 1684, // 347 - fr-yt - 1689, // 348 - fur - 1692, // 349 - fur-it - 1698, // 350 - fy - 1700, // 351 - fy-nl - 1705, // 352 - ga - 1707, // 353 - ga-ie - 1712, // 354 - gd - 1714, // 355 - gd-gb - 1719, // 356 - gl - 1721, // 357 - gl-es - 1726, // 358 - gn - 1728, // 359 - gn-py - 1733, // 360 - gsw - 1736, // 361 - gsw-ch - 1742, // 362 - gsw-fr - 1748, // 363 - gsw-li - 1754, // 364 - gu - 1756, // 365 - gu-in - 1761, // 366 - guz - 1764, // 367 - guz-ke - 1770, // 368 - gv - 1772, // 369 - gv-im - 1777, // 370 - ha - 1779, // 371 - ha-latn - 1786, // 372 - ha-latn-gh - 1796, // 373 - ha-latn-ne - 1806, // 374 - ha-latn-ng - 1816, // 375 - haw - 1819, // 376 - haw-us - 1825, // 377 - he - 1827, // 378 - he-il - 1832, // 379 - hi - 1834, // 380 - hi-in - 1839, // 381 - hr - 1841, // 382 - hr-ba - 1846, // 383 - hr-hr - 1851, // 384 - hsb - 1854, // 385 - hsb-de - 1860, // 386 - hu - 1862, // 387 - hu-hu - 1867, // 388 - hu-hu_technl - 1879, // 389 - hy - 1881, // 390 - hy-am - 1886, // 391 - ia - 1888, // 392 - ia-001 - 1894, // 393 - ia-fr - 1899, // 394 - ibb - 1902, // 395 - ibb-ng - 1908, // 396 - id - 1910, // 397 - id-id - 1915, // 398 - ig - 1917, // 399 - ig-ng - 1922, // 400 - ii - 1924, // 401 - ii-cn - 1929, // 402 - is - 1931, // 403 - is-is - 1936, // 404 - it - 1938, // 405 - it-ch - 1943, // 406 - it-it - 1948, // 407 - it-sm - 1953, // 408 - iu - 1955, // 409 - iu-cans - 1962, // 410 - iu-cans-ca - 1972, // 411 - iu-latn - 1979, // 412 - iu-latn-ca - 1989, // 413 - ja - 1991, // 414 - ja-jp - 1996, // 415 - ja-jp_radstr - 2008, // 416 - jgo - 2011, // 417 - jgo-cm - 2017, // 418 - jmc - 2020, // 419 - jmc-tz - 2026, // 420 - jv - 2028, // 421 - jv-java - 2035, // 422 - jv-java-id - 2045, // 423 - jv-latn - 2052, // 424 - jv-latn-id - 2062, // 425 - ka - 2064, // 426 - ka-ge - 2069, // 427 - ka-ge_modern - 2081, // 428 - kab - 2084, // 429 - kab-dz - 2090, // 430 - kam - 2093, // 431 - kam-ke - 2099, // 432 - kde - 2102, // 433 - kde-tz - 2108, // 434 - kea - 2111, // 435 - kea-cv - 2117, // 436 - khq - 2120, // 437 - khq-ml - 2126, // 438 - ki - 2128, // 439 - ki-ke - 2133, // 440 - kk - 2135, // 441 - kk-kz - 2140, // 442 - kkj - 2143, // 443 - kkj-cm - 2149, // 444 - kl - 2151, // 445 - kl-gl - 2156, // 446 - kln - 2159, // 447 - kln-ke - 2165, // 448 - km - 2167, // 449 - km-kh - 2172, // 450 - kn - 2174, // 451 - kn-in - 2179, // 452 - ko - 2181, // 453 - ko-kp - 2186, // 454 - ko-kr - 2191, // 455 - kok - 2194, // 456 - kok-in - 2200, // 457 - kr - 2202, // 458 - kr-ng - 2207, // 459 - ks - 2209, // 460 - ks-arab - 2216, // 461 - ks-arab-in - 2226, // 462 - ks-deva - 2233, // 463 - ks-deva-in - 2243, // 464 - ksb - 2246, // 465 - ksb-tz - 2252, // 466 - ksf - 2255, // 467 - ksf-cm - 2261, // 468 - ksh - 2264, // 469 - ksh-de - 2270, // 470 - ku - 2272, // 471 - ku-arab - 2279, // 472 - ku-arab-iq - 2289, // 473 - ku-arab-ir - 2299, // 474 - kw - 2301, // 475 - kw-gb - 2306, // 476 - ky - 2308, // 477 - ky-kg - 2313, // 478 - la - 2315, // 479 - la-001 - 2321, // 480 - lag - 2324, // 481 - lag-tz - 2330, // 482 - lb - 2332, // 483 - lb-lu - 2337, // 484 - lg - 2339, // 485 - lg-ug - 2344, // 486 - lkt - 2347, // 487 - lkt-us - 2353, // 488 - ln - 2355, // 489 - ln-ao - 2360, // 490 - ln-cd - 2365, // 491 - ln-cf - 2370, // 492 - ln-cg - 2375, // 493 - lo - 2377, // 494 - lo-la - 2382, // 495 - lrc - 2385, // 496 - lrc-iq - 2391, // 497 - lrc-ir - 2397, // 498 - lt - 2399, // 499 - lt-lt - 2404, // 500 - lu - 2406, // 501 - lu-cd - 2411, // 502 - luo - 2414, // 503 - luo-ke - 2420, // 504 - luy - 2423, // 505 - luy-ke - 2429, // 506 - lv - 2431, // 507 - lv-lv - 2436, // 508 - mas - 2439, // 509 - mas-ke - 2445, // 510 - mas-tz - 2451, // 511 - mer - 2454, // 512 - mer-ke - 2460, // 513 - mfe - 2463, // 514 - mfe-mu - 2469, // 515 - mg - 2471, // 516 - mg-mg - 2476, // 517 - mgh - 2479, // 518 - mgh-mz - 2485, // 519 - mgo - 2488, // 520 - mgo-cm - 2494, // 521 - mi - 2496, // 522 - mi-nz - 2501, // 523 - mk - 2503, // 524 - mk-mk - 2508, // 525 - ml - 2510, // 526 - ml-in - 2515, // 527 - mn - 2517, // 528 - mn-cyrl - 2524, // 529 - mn-mn - 2529, // 530 - mn-mong - 2536, // 531 - mn-mong-cn - 2546, // 532 - mn-mong-mn - 2556, // 533 - mni - 2559, // 534 - mni-in - 2565, // 535 - moh - 2568, // 536 - moh-ca - 2574, // 537 - mr - 2576, // 538 - mr-in - 2581, // 539 - ms - 2583, // 540 - ms-bn - 2588, // 541 - ms-my - 2593, // 542 - ms-sg - 2598, // 543 - mt - 2600, // 544 - mt-mt - 2605, // 545 - mua - 2608, // 546 - mua-cm - 2614, // 547 - my - 2616, // 548 - my-mm - 2621, // 549 - mzn - 2624, // 550 - mzn-ir - 2630, // 551 - naq - 2633, // 552 - naq-na - 2639, // 553 - nb - 2641, // 554 - nb-no - 2646, // 555 - nb-sj - 2651, // 556 - nd - 2653, // 557 - nd-zw - 2658, // 558 - nds - 2661, // 559 - nds-de - 2667, // 560 - nds-nl - 2673, // 561 - ne - 2675, // 562 - ne-in - 2680, // 563 - ne-np - 2685, // 564 - nl - 2687, // 565 - nl-aw - 2692, // 566 - nl-be - 2697, // 567 - nl-bq - 2702, // 568 - nl-cw - 2707, // 569 - nl-nl - 2712, // 570 - nl-sr - 2717, // 571 - nl-sx - 2722, // 572 - nmg - 2725, // 573 - nmg-cm - 2731, // 574 - nn - 2733, // 575 - nn-no - 2738, // 576 - nnh - 2741, // 577 - nnh-cm - 2747, // 578 - no - 2749, // 579 - nqo - 2752, // 580 - nqo-gn - 2758, // 581 - nr - 2760, // 582 - nr-za - 2765, // 583 - nso - 2768, // 584 - nso-za - 2774, // 585 - nus - 2777, // 586 - nus-ss - 2783, // 587 - nyn - 2786, // 588 - nyn-ug - 2792, // 589 - oc - 2794, // 590 - oc-fr - 2799, // 591 - om - 2801, // 592 - om-et - 2806, // 593 - om-ke - 2811, // 594 - or - 2813, // 595 - or-in - 2818, // 596 - os - 2820, // 597 - os-ge - 2825, // 598 - os-ru - 2830, // 599 - pa - 2832, // 600 - pa-arab - 2839, // 601 - pa-arab-pk - 2849, // 602 - pa-in - 2854, // 603 - pap - 2857, // 604 - pap-029 - 2864, // 605 - pl - 2866, // 606 - pl-pl - 2871, // 607 - prg - 2874, // 608 - prg-001 - 2881, // 609 - prs - 2884, // 610 - prs-af - 2890, // 611 - ps - 2892, // 612 - ps-af - 2897, // 613 - pt - 2899, // 614 - pt-ao - 2904, // 615 - pt-br - 2909, // 616 - pt-ch - 2914, // 617 - pt-cv - 2919, // 618 - pt-gq - 2924, // 619 - pt-gw - 2929, // 620 - pt-lu - 2934, // 621 - pt-mo - 2939, // 622 - pt-mz - 2944, // 623 - pt-pt - 2949, // 624 - pt-st - 2954, // 625 - pt-tl - 2959, // 626 - qps-latn-x-sh - 2972, // 627 - qps-ploc - 2980, // 628 - qps-ploca - 2989, // 629 - qps-plocm - 2998, // 630 - quc - 3001, // 631 - quc-latn - 3009, // 632 - quc-latn-gt - 3020, // 633 - quz - 3023, // 634 - quz-bo - 3029, // 635 - quz-ec - 3035, // 636 - quz-pe - 3041, // 637 - rm - 3043, // 638 - rm-ch - 3048, // 639 - rn - 3050, // 640 - rn-bi - 3055, // 641 - ro - 3057, // 642 - ro-md - 3062, // 643 - ro-ro - 3067, // 644 - rof - 3070, // 645 - rof-tz - 3076, // 646 - ru - 3078, // 647 - ru-by - 3083, // 648 - ru-kg - 3088, // 649 - ru-kz - 3093, // 650 - ru-md - 3098, // 651 - ru-ru - 3103, // 652 - ru-ua - 3108, // 653 - rw - 3110, // 654 - rw-rw - 3115, // 655 - rwk - 3118, // 656 - rwk-tz - 3124, // 657 - sa - 3126, // 658 - sa-in - 3131, // 659 - sah - 3134, // 660 - sah-ru - 3140, // 661 - saq - 3143, // 662 - saq-ke - 3149, // 663 - sbp - 3152, // 664 - sbp-tz - 3158, // 665 - sd - 3160, // 666 - sd-arab - 3167, // 667 - sd-arab-pk - 3177, // 668 - sd-deva - 3184, // 669 - sd-deva-in - 3194, // 670 - se - 3196, // 671 - se-fi - 3201, // 672 - se-no - 3206, // 673 - se-se - 3211, // 674 - seh - 3214, // 675 - seh-mz - 3220, // 676 - ses - 3223, // 677 - ses-ml - 3229, // 678 - sg - 3231, // 679 - sg-cf - 3236, // 680 - shi - 3239, // 681 - shi-latn - 3247, // 682 - shi-latn-ma - 3258, // 683 - shi-tfng - 3266, // 684 - shi-tfng-ma - 3277, // 685 - si - 3279, // 686 - si-lk - 3284, // 687 - sk - 3286, // 688 - sk-sk - 3291, // 689 - sl - 3293, // 690 - sl-si - 3298, // 691 - sma - 3301, // 692 - sma-no - 3307, // 693 - sma-se - 3313, // 694 - smj - 3316, // 695 - smj-no - 3322, // 696 - smj-se - 3328, // 697 - smn - 3331, // 698 - smn-fi - 3337, // 699 - sms - 3340, // 700 - sms-fi - 3346, // 701 - sn - 3348, // 702 - sn-latn - 3355, // 703 - sn-latn-zw - 3365, // 704 - so - 3367, // 705 - so-dj - 3372, // 706 - so-et - 3377, // 707 - so-ke - 3382, // 708 - so-so - 3387, // 709 - sq - 3389, // 710 - sq-al - 3394, // 711 - sq-mk - 3399, // 712 - sq-xk - 3404, // 713 - sr - 3406, // 714 - sr-cyrl - 3413, // 715 - sr-cyrl-ba - 3423, // 716 - sr-cyrl-cs - 3433, // 717 - sr-cyrl-me - 3443, // 718 - sr-cyrl-rs - 3453, // 719 - sr-cyrl-xk - 3463, // 720 - sr-latn - 3470, // 721 - sr-latn-ba - 3480, // 722 - sr-latn-cs - 3490, // 723 - sr-latn-me - 3500, // 724 - sr-latn-rs - 3510, // 725 - sr-latn-xk - 3520, // 726 - ss - 3522, // 727 - ss-sz - 3527, // 728 - ss-za - 3532, // 729 - ssy - 3535, // 730 - ssy-er - 3541, // 731 - st - 3543, // 732 - st-ls - 3548, // 733 - st-za - 3553, // 734 - sv - 3555, // 735 - sv-ax - 3560, // 736 - sv-fi - 3565, // 737 - sv-se - 3570, // 738 - sw - 3572, // 739 - sw-cd - 3577, // 740 - sw-ke - 3582, // 741 - sw-tz - 3587, // 742 - sw-ug - 3592, // 743 - swc - 3595, // 744 - swc-cd - 3601, // 745 - syr - 3604, // 746 - syr-sy - 3610, // 747 - ta - 3612, // 748 - ta-in - 3617, // 749 - ta-lk - 3622, // 750 - ta-my - 3627, // 751 - ta-sg - 3632, // 752 - te - 3634, // 753 - te-in - 3639, // 754 - teo - 3642, // 755 - teo-ke - 3648, // 756 - teo-ug - 3654, // 757 - tg - 3656, // 758 - tg-cyrl - 3663, // 759 - tg-cyrl-tj - 3673, // 760 - th - 3675, // 761 - th-th - 3680, // 762 - ti - 3682, // 763 - ti-er - 3687, // 764 - ti-et - 3692, // 765 - tig - 3695, // 766 - tig-er - 3701, // 767 - tk - 3703, // 768 - tk-tm - 3708, // 769 - tn - 3710, // 770 - tn-bw - 3715, // 771 - tn-za - 3720, // 772 - to - 3722, // 773 - to-to - 3727, // 774 - tr - 3729, // 775 - tr-cy - 3734, // 776 - tr-tr - 3739, // 777 - ts - 3741, // 778 - ts-za - 3746, // 779 - tt - 3748, // 780 - tt-ru - 3753, // 781 - twq - 3756, // 782 - twq-ne - 3762, // 783 - tzm - 3765, // 784 - tzm-arab - 3773, // 785 - tzm-arab-ma - 3784, // 786 - tzm-latn - 3792, // 787 - tzm-latn-dz - 3803, // 788 - tzm-latn-ma - 3814, // 789 - tzm-tfng - 3822, // 790 - tzm-tfng-ma - 3833, // 791 - ug - 3835, // 792 - ug-cn - 3840, // 793 - uk - 3842, // 794 - uk-ua - 3847, // 795 - ur - 3849, // 796 - ur-in - 3854, // 797 - ur-pk - 3859, // 798 - uz - 3861, // 799 - uz-arab - 3868, // 800 - uz-arab-af - 3878, // 801 - uz-cyrl - 3885, // 802 - uz-cyrl-uz - 3895, // 803 - uz-latn - 3902, // 804 - uz-latn-uz - 3912, // 805 - vai - 3915, // 806 - vai-latn - 3923, // 807 - vai-latn-lr - 3934, // 808 - vai-vaii - 3942, // 809 - vai-vaii-lr - 3953, // 810 - ve - 3955, // 811 - ve-za - 3960, // 812 - vi - 3962, // 813 - vi-vn - 3967, // 814 - vo - 3969, // 815 - vo-001 - 3975, // 816 - vun - 3978, // 817 - vun-tz - 3984, // 818 - wae - 3987, // 819 - wae-ch - 3993, // 820 - wal - 3996, // 821 - wal-et - 4002, // 822 - wo - 4004, // 823 - wo-sn - 4009, // 824 - x-iv_mathan - 4020, // 825 - xh - 4022, // 826 - xh-za - 4027, // 827 - xog - 4030, // 828 - xog-ug - 4036, // 829 - yav - 4039, // 830 - yav-cm - 4045, // 831 - yi - 4047, // 832 - yi-001 - 4053, // 833 - yo - 4055, // 834 - yo-bj - 4060, // 835 - yo-ng - 4065, // 836 - yue - 4068, // 837 - yue-hk - 4074, // 838 - zgh - 4077, // 839 - zgh-tfng - 4085, // 840 - zgh-tfng-ma - 4096, // 841 - zh - 4098, // 842 - zh-chs - 4104, // 843 - zh-cht - 4110, // 844 - zh-cn - 4115, // 845 - zh-cn_phoneb - 4127, // 846 - zh-cn_stroke - 4139, // 847 - zh-hans - 4146, // 848 - zh-hans-hk - 4156, // 849 - zh-hans-mo - 4166, // 850 - zh-hant - 4173, // 851 - zh-hk - 4178, // 852 - zh-hk_radstr - 4190, // 853 - zh-mo - 4195, // 854 - zh-mo_radstr - 4207, // 855 - zh-mo_stroke - 4219, // 856 - zh-sg - 4224, // 857 - zh-sg_phoneb - 4236, // 858 - zh-sg_stroke - 4248, // 859 - zh-tw - 4253, // 860 - zh-tw_pronun - 4265, // 861 - zh-tw_radstr - 4277, // 862 - zu - 4279, // 863 - zu-za - 4284 - }; - - private const int NUMERIC_LOCALE_DATA_COUNT_PER_ROW = 9; - // s_nameIndexToNumericData is mapping from index in s_localeNamesIndices to locale data. - // each row in the table will have the following data: - // Lcid, Ansi codepage, Oem codepage, MAC codepage, EBCDIC codepage, Geo Id, Digit Substitution, specific locale index, Console locale index - private static readonly int[] s_nameIndexToNumericData = new int[] - { - // Lcid, Ansi CP, Oem CP, MAC CP, EBCDIC CP, Geo Id, digit substitution, Specific culture index, keyboard Id, Console locale index // index - locale name - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 3 , 240 , // 0 - aa - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3e , 1 , 1 , 240 , // 1 - aa-dj - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 2 , 240 , // 2 - aa-er - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 3 , 240 , // 3 - aa-et - 0x36 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 6 , 6 , // 4 - af - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfe , 1 , 5 , 240 , // 5 - af-na - 0x436 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 6 , 6 , // 6 - af-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 8 , 240 , // 7 - agq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 8 , 240 , // 8 - agq-cm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 10 , 240 , // 9 - ak - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 10 , 240 , // 10 - ak-gh - 0x5e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 12 , 143 , // 11 - am - 0x45e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 12 , 143 , // 12 - am-et - 0x1 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 , 33 , 143 , // 13 - ar - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x989e, 0 , 14 , 240 , // 14 - ar-001 - 0x3801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xe0 , 0 , 15 , 143 , // 15 - ar-ae - 0x3c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x11 , 0 , 16 , 143 , // 16 - ar-bh - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3e , 0 , 17 , 240 , // 17 - ar-dj - 0x1401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x4 , 1 , 18 , 300 , // 18 - ar-dz - 0xc01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x43 , 0 , 19 , 143 , // 19 - ar-eg - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x47 , 0 , 20 , 240 , // 20 - ar-er - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x75 , 0 , 21 , 240 , // 21 - ar-il - 0x801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 22 , 143 , // 22 - ar-iq - 0x2c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x7e , 0 , 23 , 143 , // 23 - ar-jo - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x32 , 0 , 24 , 240 , // 24 - ar-km - 0x3401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x88 , 0 , 25 , 143 , // 25 - ar-kw - 0x3001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x8b , 0 , 26 , 143 , // 26 - ar-lb - 0x1001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x94 , 1 , 27 , 143 , // 27 - ar-ly - 0x1801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 , 28 , 300 , // 28 - ar-ma - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xa2 , 0 , 29 , 240 , // 29 - ar-mr - 0x2001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xa4 , 0 , 30 , 143 , // 30 - ar-om - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xb8 , 0 , 31 , 240 , // 31 - ar-ps - 0x4001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xc5 , 0 , 32 , 143 , // 32 - ar-qa - 0x401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 , 33 , 143 , // 33 - ar-sa - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xdb , 0 , 34 , 240 , // 34 - ar-sd - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xd8 , 0 , 35 , 240 , // 35 - ar-so - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x114 , 0 , 36 , 240 , // 36 - ar-ss - 0x2801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xde , 0 , 37 , 143 , // 37 - ar-sy - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x29 , 0 , 38 , 240 , // 38 - ar-td - 0x1c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xea , 1 , 39 , 300 , // 39 - ar-tn - 0x2401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x105 , 0 , 40 , 143 , // 40 - ar-ye - 0x7a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 , 42 , 42 , // 41 - arn - 0x47a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 , 42 , 42 , // 42 - arn-cl - 0x4d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 44 , 143 , // 43 - as - 0x44d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 44 , 143 , // 44 - as-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 46 , 240 , // 45 - asa - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 46 , 240 , // 46 - asa-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd9 , 1 , 48 , 240 , // 47 - ast - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd9 , 1 , 48 , 240 , // 48 - ast-es - 0x2c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 , 53 , 53 , // 49 - az - 0x742c , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x5 , 1 , 51 , 51 , // 50 - az-cyrl - 0x82c , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x5 , 1 , 51 , 51 , // 51 - az-cyrl-az - 0x782c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 , 53 , 53 , // 52 - az-latn - 0x42c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 , 53 , 53 , // 53 - az-latn-az - 0x6d , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 55 , 55 , // 54 - ba - 0x46d , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 55 , 55 , // 55 - ba-ru - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 57 , 240 , // 56 - bas - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 57 , 240 , // 57 - bas-cm - 0x23 , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x1d , 1 , 59 , 59 , // 58 - be - 0x423 , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x1d , 1 , 59 , 59 , // 59 - be-by - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x107 , 1 , 61 , 240 , // 60 - bem - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x107 , 1 , 61 , 240 , // 61 - bem-zm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 63 , 240 , // 62 - bez - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 63 , 240 , // 63 - bez-tz - 0x2 , 0x4e3 , 0x362 , 0x2717, 0x5221, 0x23 , 1 , 65 , 65 , // 64 - bg - 0x402 , 0x4e3 , 0x362 , 0x2717, 0x5221, 0x23 , 1 , 65 , 65 , // 65 - bg-bg - 0x66 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 67 , 240 , // 66 - bin - 0x466 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 67 , 240 , // 67 - bin-ng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 70 , 240 , // 68 - bm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 70 , 240 , // 69 - bm-latn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 70 , 240 , // 70 - bm-latn-ml - 0x45 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x17 , 1 , 72 , 143 , // 71 - bn - 0x845 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x17 , 1 , 72 , 143 , // 72 - bn-bd - 0x445 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 73 , 143 , // 73 - bn-in - 0x51 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 75 , 143 , // 74 - bo - 0x451 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 75 , 143 , // 75 - bo-cn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 76 , 240 , // 76 - bo-in - 0x7e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 78 , 78 , // 77 - br - 0x47e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 78 , 78 , // 78 - br-fr - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 80 , 240 , // 79 - brx - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 80 , 240 , // 80 - brx-in - 0x781a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 85 , 85 , // 81 - bs - 0x641a , 0x4e3 , 0x357 , 0x2762, 0x366 , 0x19 , 1 , 83 , 83 , // 82 - bs-cyrl - 0x201a , 0x4e3 , 0x357 , 0x2762, 0x366 , 0x19 , 1 , 83 , 83 , // 83 - bs-cyrl-ba - 0x681a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 85 , 85 , // 84 - bs-latn - 0x141a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 85 , 85 , // 85 - bs-latn-ba - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 87 , 240 , // 86 - byn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 87 , 240 , // 87 - byn-er - 0x3 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 90 , 90 , // 88 - ca - 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x8 , 1 , 89 , 240 , // 89 - ca-ad - 0x403 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 90 , 90 , // 90 - ca-es - 0x803 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 91 , 90 , // 91 - ca-es-valencia - 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x54 , 1 , 92 , 240 , // 92 - ca-fr - 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x76 , 1 , 93 , 240 , // 93 - ca-it - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 95 , 240 , // 94 - ce - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 95 , 240 , // 95 - ce-ru - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 97 , 240 , // 96 - cgg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 97 , 240 , // 97 - cgg-ug - 0x5c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 100 , 240 , // 98 - chr - 0x7c5c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 100 , 240 , // 99 - chr-cher - 0x45c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 100 , 240 , // 100 - chr-cher-us - 0x83 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 102 , 102 , // 101 - co - 0x483 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 102 , 102 , // 102 - co-fr - 0x5 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x4b , 1 , 104 , 104 , // 103 - cs - 0x405 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x4b , 1 , 104 , 104 , // 104 - cs-cz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 106 , 240 , // 105 - cu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 106 , 240 , // 106 - cu-ru - 0x52 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 108 , 108 , // 107 - cy - 0x452 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 108 , 108 , // 108 - cy-gb - 0x6 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x3d , 1 , 110 , 110 , // 109 - da - 0x406 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x3d , 1 , 110 , 110 , // 110 - da-dk - 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x5d , 1 , 111 , 240 , // 111 - da-gl - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 113 , 240 , // 112 - dav - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 113 , 240 , // 113 - dav-ke - 0x7 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 , 118 , 118 , // 114 - de - 0xc07 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xe , 1 , 115 , 115 , // 115 - de-at - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x15 , 1 , 116 , 240 , // 116 - de-be - 0x807 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 , 117 , 117 , // 117 - de-ch - 0x407 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 , 118 , 118 , // 118 - de-de - 0x10407, 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 , 118 , 118 , // 119 - de-de_phoneb - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 , 120 , 240 , // 120 - de-it - 0x1407 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x91 , 1 , 121 , 121 , // 121 - de-li - 0x1007 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x93 , 1 , 122 , 122 , // 122 - de-lu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 124 , 240 , // 123 - dje - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 124 , 240 , // 124 - dje-ne - 0x7c2e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 126 , 126 , // 125 - dsb - 0x82e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 126 , 126 , // 126 - dsb-de - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 128 , 240 , // 127 - dua - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 128 , 240 , // 128 - dua-cm - 0x65 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa5 , 1 , 130 , 143 , // 129 - dv - 0x465 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa5 , 1 , 130 , 143 , // 130 - dv-mv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd2 , 1 , 132 , 240 , // 131 - dyo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd2 , 1 , 132 , 240 , // 132 - dyo-sn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x22 , 2 , 134 , 240 , // 133 - dz - 0xc51 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x22 , 2 , 134 , 240 , // 134 - dz-bt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 136 , 240 , // 135 - ebu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 136 , 240 , // 136 - ebu-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 138 , 240 , // 137 - ee - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 138 , 240 , // 138 - ee-gh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe8 , 1 , 139 , 240 , // 139 - ee-tg - 0x8 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x62 , 1 , 142 , 142 , // 140 - el - 0x1000 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x3b , 1 , 141 , 240 , // 141 - el-cy - 0x408 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x62 , 1 , 142 , 142 , // 142 - el-gr - 0x9 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 240 , 240 , // 143 - en - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x989e, 1 , 144 , 240 , // 144 - en-001 - 0x2409 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 , 145 , 145 , // 145 - en-029 - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x292d, 1 , 146 , 240 , // 146 - en-150 - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x2 , 1 , 147 , 240 , // 147 - en-ag - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12c , 1 , 148 , 240 , // 148 - en-ai - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa , 1 , 149 , 240 , // 149 - en-as - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe , 1 , 150 , 240 , // 150 - en-at - 0xc09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc , 1 , 151 , 151 , // 151 - en-au - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12 , 1 , 152 , 240 , // 152 - en-bb - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15 , 1 , 153 , 240 , // 153 - en-be - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 , 154 , 240 , // 154 - en-bi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14 , 1 , 155 , 240 , // 155 - en-bm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x16 , 1 , 156 , 240 , // 156 - en-bs - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13 , 1 , 157 , 240 , // 157 - en-bw - 0x2809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x18 , 1 , 158 , 158 , // 158 - en-bz - 0x1009 , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 , 159 , 159 , // 159 - en-ca - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x137 , 1 , 160 , 240 , // 160 - en-cc - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 161 , 240 , // 161 - en-ch - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x138 , 1 , 162 , 240 , // 162 - en-ck - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x31 , 1 , 163 , 240 , // 163 - en-cm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x135 , 1 , 164 , 240 , // 164 - en-cx - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b , 1 , 165 , 240 , // 165 - en-cy - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 166 , 240 , // 166 - en-de - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3d , 1 , 167 , 240 , // 167 - en-dk - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x3f , 1 , 168 , 240 , // 168 - en-dm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x47 , 1 , 169 , 240 , // 169 - en-er - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4d , 1 , 170 , 240 , // 170 - en-fi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x4e , 1 , 171 , 240 , // 171 - en-fj - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13b , 1 , 172 , 240 , // 172 - en-fk - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x50 , 1 , 173 , 240 , // 173 - en-fm - 0x809 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 174 , 174 , // 174 - en-gb - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x5b , 1 , 175 , 240 , // 175 - en-gd - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x144 , 1 , 176 , 240 , // 176 - en-gg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x59 , 1 , 177 , 240 , // 177 - en-gh - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x5a , 1 , 178 , 240 , // 178 - en-gi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x56 , 1 , 179 , 240 , // 179 - en-gm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x142 , 1 , 180 , 240 , // 180 - en-gu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x65 , 1 , 181 , 240 , // 181 - en-gy - 0x3c09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x68 , 1 , 182 , 240 , // 182 - en-hk - 0x3809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 183 , 240 , // 183 - en-id - 0x1809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 , 184 , 184 , // 184 - en-ie - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x75 , 1 , 185 , 240 , // 185 - en-il - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x3b16, 1 , 186 , 240 , // 186 - en-im - 0x4009 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x71 , 1 , 187 , 187 , // 187 - en-in - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x72 , 1 , 188 , 240 , // 188 - en-io - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x148 , 1 , 189 , 240 , // 189 - en-je - 0x2009 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x7c , 1 , 190 , 190 , // 190 - en-jm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x81 , 1 , 191 , 240 , // 191 - en-ke - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x85 , 1 , 192 , 240 , // 192 - en-ki - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xcf , 1 , 193 , 240 , // 193 - en-kn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x133 , 1 , 194 , 240 , // 194 - en-ky - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xda , 1 , 195 , 240 , // 195 - en-lc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x8e , 1 , 196 , 240 , // 196 - en-lr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x92 , 1 , 197 , 240 , // 197 - en-ls - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x95 , 1 , 198 , 240 , // 198 - en-mg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc7 , 1 , 199 , 240 , // 199 - en-mh - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x97 , 1 , 200 , 240 , // 200 - en-mo - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x151 , 1 , 201 , 240 , // 201 - en-mp - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14c , 1 , 202 , 240 , // 202 - en-ms - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa3 , 1 , 203 , 240 , // 203 - en-mt - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa0 , 1 , 204 , 240 , // 204 - en-mu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9c , 1 , 205 , 240 , // 205 - en-mw - 0x4409 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xa7 , 1 , 206 , 206 , // 206 - en-my - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfe , 1 , 207 , 240 , // 207 - en-na - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x150 , 1 , 208 , 240 , // 208 - en-nf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 209 , 240 , // 209 - en-ng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb0 , 1 , 210 , 240 , // 210 - en-nl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb4 , 1 , 211 , 240 , // 211 - en-nr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14f , 1 , 212 , 240 , // 212 - en-nu - 0x1409 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb7 , 1 , 213 , 213 , // 213 - en-nz - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc2 , 1 , 214 , 240 , // 214 - en-pg - 0x3409 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 , 215 , 215 , // 215 - en-ph - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xbe , 1 , 216 , 240 , // 216 - en-pk - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x153 , 1 , 217 , 240 , // 217 - en-pn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xca , 1 , 218 , 240 , // 218 - en-pr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc3 , 1 , 219 , 240 , // 219 - en-pw - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xcc , 1 , 220 , 240 , // 220 - en-rw - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x1e , 1 , 221 , 240 , // 221 - en-sb - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd0 , 1 , 222 , 240 , // 222 - en-sc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xdb , 1 , 223 , 240 , // 223 - en-sd - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdd , 1 , 224 , 240 , // 224 - en-se - 0x4809 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xd7 , 1 , 225 , 225 , // 225 - en-sg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x157 , 1 , 226 , 240 , // 226 - en-sh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd4 , 1 , 227 , 240 , // 227 - en-si - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd5 , 1 , 228 , 240 , // 228 - en-sl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x114 , 1 , 229 , 240 , // 229 - en-ss - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x78f7, 1 , 230 , 240 , // 230 - en-sx - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x104 , 1 , 231 , 240 , // 231 - en-sz - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15d , 1 , 232 , 240 , // 232 - en-tc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15b , 1 , 233 , 240 , // 233 - en-tk - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe7 , 1 , 234 , 240 , // 234 - en-to - 0x2c09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe1 , 1 , 235 , 235 , // 235 - en-tt - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xec , 1 , 236 , 240 , // 236 - en-tv - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xef , 1 , 237 , 240 , // 237 - en-tz - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xf0 , 1 , 238 , 240 , // 238 - en-ug - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9a55d40, 1 , 239 , 240 , // 239 - en-um - 0x409 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 240 , 240 , // 240 - en-us - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xf8 , 1 , 241 , 240 , // 241 - en-vc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15f , 1 , 242 , 240 , // 242 - en-vg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfc , 1 , 243 , 240 , // 243 - en-vi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xae , 1 , 244 , 240 , // 244 - en-vu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x103 , 1 , 245 , 240 , // 245 - en-ws - 0x1c09 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xd1 , 1 , 246 , 246 , // 246 - en-za - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x107 , 1 , 247 , 240 , // 247 - en-zm - 0x3009 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x108 , 1 , 248 , 248 , // 248 - en-zw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 250 , 240 , // 249 - eo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 250 , 240 , // 250 - eo-001 - 0xa , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 , 262 , 262 , // 251 - es - 0x580a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x9a55d41, 1 , 252 , 240 , // 252 - es-419 - 0x2c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb , 1 , 253 , 253 , // 253 - es-ar - 0x400a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 , 254 , 254 , // 254 - es-bo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x20 , 1 , 255 , 240 , // 255 - es-br - 0x340a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 , 256 , 256 , // 256 - es-cl - 0x240a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x33 , 1 , 257 , 257 , // 257 - es-co - 0x140a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x36 , 1 , 258 , 258 , // 258 - es-cr - 0x5c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x38 , 1 , 259 , 240 , // 259 - es-cu - 0x1c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x41 , 1 , 260 , 260 , // 260 - es-do - 0x300a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x42 , 1 , 261 , 261 , // 261 - es-ec - 0xc0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 , 262 , 262 , // 262 - es-es - 0x40a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 , 263 , 263 , // 263 - es-es_tradnl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x45 , 1 , 264 , 240 , // 264 - es-gq - 0x100a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 265 , 265 , // 265 - es-gt - 0x480a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x6a , 1 , 266 , 266 , // 266 - es-hn - 0x80a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xa6 , 1 , 267 , 267 , // 267 - es-mx - 0x4c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb6 , 1 , 268 , 268 , // 268 - es-ni - 0x180a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xc0 , 1 , 269 , 269 , // 269 - es-pa - 0x280a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xbb , 1 , 270 , 270 , // 270 - es-pe - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xc9 , 1 , 271 , 240 , // 271 - es-ph - 0x500a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xca , 1 , 272 , 272 , // 272 - es-pr - 0x3c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 , 273 , 273 , // 273 - es-py - 0x440a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x48 , 1 , 274 , 274 , // 274 - es-sv - 0x540a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf4 , 1 , 275 , 275 , // 275 - es-us - 0x380a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf6 , 1 , 276 , 276 , // 276 - es-uy - 0x200a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf9 , 1 , 277 , 277 , // 277 - es-ve - 0x25 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x46 , 1 , 279 , 279 , // 278 - et - 0x425 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x46 , 1 , 279 , 279 , // 279 - et-ee - 0x2d , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0xd9 , 1 , 281 , 240 , // 280 - eu - 0x42d , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0xd9 , 1 , 281 , 240 , // 281 - eu-es - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 283 , 240 , // 282 - ewo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 283 , 240 , // 283 - ewo-cm - 0x29 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x74 , 0 , 285 , 143 , // 284 - fa - 0x429 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x74 , 0 , 285 , 143 , // 285 - fa-ir - 0x67 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 290 , 290 , // 286 - ff - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x31 , 1 , 287 , 240 , // 287 - ff-cm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x64 , 1 , 288 , 240 , // 288 - ff-gn - 0x7c67 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 290 , 290 , // 289 - ff-latn - 0x867 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 290 , 290 , // 290 - ff-latn-sn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa2 , 1 , 291 , 240 , // 291 - ff-mr - 0x467 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xaf , 1 , 292 , 240 , // 292 - ff-ng - 0xb , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 294 , 294 , // 293 - fi - 0x40b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 294 , 294 , // 294 - fi-fi - 0x64 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 , 296 , 296 , // 295 - fil - 0x464 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 , 296 , 296 , // 296 - fil-ph - 0x38 , 0x4e4 , 0x352 , 0x275f, 0x4f35, 0x51 , 1 , 299 , 299 , // 297 - fo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3d , 1 , 298 , 240 , // 298 - fo-dk - 0x438 , 0x4e4 , 0x352 , 0x275f, 0x4f35, 0x51 , 1 , 299 , 299 , // 299 - fo-fo - 0xc , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 316 , 316 , // 300 - fr - 0x1c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x993248, 1 , 301 , 316 , // 301 - fr-029 - 0x80c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x15 , 1 , 302 , 302 , // 302 - fr-be - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xf5 , 1 , 303 , 240 , // 303 - fr-bf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x26 , 1 , 304 , 240 , // 304 - fr-bi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x1c , 1 , 305 , 240 , // 305 - fr-bj - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9a55c4f, 1 , 306 , 240 , // 306 - fr-bl - 0xc0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x27 , 1 , 307 , 307 , // 307 - fr-ca - 0x240c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x2c , 1 , 308 , 240 , // 308 - fr-cd - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x37 , 1 , 309 , 240 , // 309 - fr-cf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x2b , 1 , 310 , 240 , // 310 - fr-cg - 0x100c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 , 311 , 311 , // 311 - fr-ch - 0x300c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x77 , 1 , 312 , 240 , // 312 - fr-ci - 0x2c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x31 , 1 , 313 , 240 , // 313 - fr-cm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x3e , 1 , 314 , 240 , // 314 - fr-dj - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 315 , 240 , // 315 - fr-dz - 0x40c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 316 , 316 , // 316 - fr-fr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x57 , 1 , 317 , 240 , // 317 - fr-ga - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x13d , 1 , 318 , 240 , // 318 - fr-gf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x64 , 1 , 319 , 240 , // 319 - fr-gn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x141 , 1 , 320 , 240 , // 320 - fr-gp - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x45 , 1 , 321 , 240 , // 321 - fr-gq - 0x3c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x67 , 1 , 322 , 240 , // 322 - fr-ht - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x32 , 1 , 323 , 240 , // 323 - fr-km - 0x140c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 , 324 , 324 , // 324 - fr-lu - 0x380c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9f , 1 , 325 , 240 , // 325 - fr-ma - 0x180c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9e , 1 , 326 , 326 , // 326 - fr-mc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x7bda, 1 , 327 , 240 , // 327 - fr-mf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x95 , 1 , 328 , 240 , // 328 - fr-mg - 0x340c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9d , 1 , 329 , 240 , // 329 - fr-ml - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14a , 1 , 330 , 240 , // 330 - fr-mq - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa2 , 1 , 331 , 240 , // 331 - fr-mr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa0 , 1 , 332 , 240 , // 332 - fr-mu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14e , 1 , 333 , 240 , // 333 - fr-nc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xad , 1 , 334 , 240 , // 334 - fr-ne - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x13e , 1 , 335 , 240 , // 335 - fr-pf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xce , 1 , 336 , 240 , // 336 - fr-pm - 0x200c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xc6 , 1 , 337 , 240 , // 337 - fr-re - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xcc , 1 , 338 , 240 , // 338 - fr-rw - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd0 , 1 , 339 , 240 , // 339 - fr-sc - 0x280c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 340 , 240 , // 340 - fr-sn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xde , 1 , 341 , 240 , // 341 - fr-sy - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x29 , 1 , 342 , 240 , // 342 - fr-td - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xe8 , 1 , 343 , 240 , // 343 - fr-tg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xea , 1 , 344 , 240 , // 344 - fr-tn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xae , 1 , 345 , 240 , // 345 - fr-vu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x160 , 1 , 346 , 240 , // 346 - fr-wf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14b , 1 , 347 , 240 , // 347 - fr-yt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 , 349 , 240 , // 348 - fur - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 , 349 , 240 , // 349 - fur-it - 0x62 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 351 , 351 , // 350 - fy - 0x462 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 351 , 351 , // 351 - fy-nl - 0x3c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 , 353 , 353 , // 352 - ga - 0x83c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 , 353 , 353 , // 353 - ga-ie - 0x91 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 355 , 355 , // 354 - gd - 0x491 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 355 , 355 , // 355 - gd-gb - 0x56 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 357 , 357 , // 356 - gl - 0x456 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 357 , 357 , // 357 - gl-es - 0x74 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 , 359 , 359 , // 358 - gn - 0x474 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 , 359 , 359 , // 359 - gn-py - 0x84 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 , 361 , 240 , // 360 - gsw - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 , 361 , 240 , // 361 - gsw-ch - 0x484 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 362 , 362 , // 362 - gsw-fr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x91 , 1 , 363 , 240 , // 363 - gsw-li - 0x47 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 365 , 143 , // 364 - gu - 0x447 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 365 , 143 , // 365 - gu-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 367 , 240 , // 366 - guz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 367 , 240 , // 367 - guz-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b16, 1 , 369 , 240 , // 368 - gv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b16, 1 , 369 , 240 , // 369 - gv-im - 0x68 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 374 , 374 , // 370 - ha - 0x7c68 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 374 , 374 , // 371 - ha-latn - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x59 , 1 , 372 , 240 , // 372 - ha-latn-gh - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xad , 1 , 373 , 240 , // 373 - ha-latn-ne - 0x468 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 374 , 374 , // 374 - ha-latn-ng - 0x75 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 376 , 376 , // 375 - haw - 0x475 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 376 , 376 , // 376 - haw-us - 0xd , 0x4e7 , 0x35e , 0x2715, 0x1f4 , 0x75 , 1 , 378 , 143 , // 377 - he - 0x40d , 0x4e7 , 0x35e , 0x2715, 0x1f4 , 0x75 , 1 , 378 , 143 , // 378 - he-il - 0x39 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 380 , 143 , // 379 - hi - 0x439 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 380 , 143 , // 380 - hi-in - 0x1a , 0x4e2 , 0x354 , 0x2762, 0x1f4 , 0x6c , 1 , 383 , 383 , // 381 - hr - 0x101a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 382 , 382 , // 382 - hr-ba - 0x41a , 0x4e2 , 0x354 , 0x2762, 0x1f4 , 0x6c , 1 , 383 , 383 , // 383 - hr-hr - 0x2e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 385 , 385 , // 384 - hsb - 0x42e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 385 , 385 , // 385 - hsb-de - 0xe , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 , 387 , 387 , // 386 - hu - 0x40e , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 , 387 , 387 , // 387 - hu-hu - 0x1040e, 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 , 387 , 387 , // 388 - hu-hu_technl - 0x2b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x7 , 1 , 390 , 390 , // 389 - hy - 0x42b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x7 , 1 , 390 , 390 , // 390 - hy-am - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x54 , 1 , 393 , 240 , // 391 - ia - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 392 , 240 , // 392 - ia-001 - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x54 , 1 , 393 , 240 , // 393 - ia-fr - 0x69 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 395 , 240 , // 394 - ibb - 0x469 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 395 , 240 , // 395 - ibb-ng - 0x21 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 397 , 397 , // 396 - id - 0x421 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 397 , 397 , // 397 - id-id - 0x70 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 399 , 399 , // 398 - ig - 0x470 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 399 , 399 , // 399 - ig-ng - 0x78 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 401 , 143 , // 400 - ii - 0x478 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 401 , 143 , // 401 - ii-cn - 0xf , 0x4e4 , 0x352 , 0x275f, 0x5187, 0x6e , 1 , 403 , 403 , // 402 - is - 0x40f , 0x4e4 , 0x352 , 0x275f, 0x5187, 0x6e , 1 , 403 , 403 , // 403 - is-is - 0x10 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0x76 , 1 , 406 , 406 , // 404 - it - 0x810 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xdf , 1 , 405 , 405 , // 405 - it-ch - 0x410 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0x76 , 1 , 406 , 406 , // 406 - it-it - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0xd6 , 1 , 407 , 240 , // 407 - it-sm - 0x5d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 , 412 , 412 , // 408 - iu - 0x785d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x27 , 1 , 410 , 143 , // 409 - iu-cans - 0x45d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x27 , 1 , 410 , 143 , // 410 - iu-cans-ca - 0x7c5d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 , 412 , 412 , // 411 - iu-latn - 0x85d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 , 412 , 412 , // 412 - iu-latn-ca - 0x11 , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 414 , 414 , // 413 - ja - 0x411 , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 414 , 414 , // 414 - ja-jp - 0x40411, 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 414 , 414 , // 415 - ja-jp_radstr - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 417 , 240 , // 416 - jgo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 417 , 240 , // 417 - jgo-cm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 419 , 240 , // 418 - jmc - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 419 , 240 , // 419 - jmc-tz - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 424 , 424 , // 420 - jv - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 422 , 424 , // 421 - jv-java - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 422 , 424 , // 422 - jv-java-id - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 424 , 424 , // 423 - jv-latn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 424 , 424 , // 424 - jv-latn-id - 0x37 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 426 , 426 , // 425 - ka - 0x437 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 426 , 426 , // 426 - ka-ge - 0x10437, 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 426 , 426 , // 427 - ka-ge_modern - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4 , 1 , 429 , 240 , // 428 - kab - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4 , 1 , 429 , 240 , // 429 - kab-dz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 431 , 240 , // 430 - kam - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 431 , 240 , // 431 - kam-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 433 , 240 , // 432 - kde - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 433 , 240 , // 433 - kde-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x39 , 1 , 435 , 240 , // 434 - kea - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x39 , 1 , 435 , 240 , // 435 - kea-cv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 437 , 240 , // 436 - khq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 437 , 240 , // 437 - khq-ml - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 439 , 240 , // 438 - ki - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 439 , 240 , // 439 - ki-ke - 0x3f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x89 , 1 , 441 , 441 , // 440 - kk - 0x43f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x89 , 1 , 441 , 441 , // 441 - kk-kz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 443 , 240 , // 442 - kkj - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 443 , 240 , // 443 - kkj-cm - 0x6f , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x5d , 1 , 445 , 445 , // 444 - kl - 0x46f , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x5d , 1 , 445 , 445 , // 445 - kl-gl - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 447 , 240 , // 446 - kln - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 447 , 240 , // 447 - kln-ke - 0x53 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x28 , 2 , 449 , 143 , // 448 - km - 0x453 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x28 , 2 , 449 , 143 , // 449 - km-kh - 0x4b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 451 , 143 , // 450 - kn - 0x44b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 451 , 143 , // 451 - kn-in - 0x12 , 0x3b5 , 0x3b5 , 0x2713, 0x5161, 0x86 , 1 , 454 , 454 , // 452 - ko - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x83 , 1 , 453 , 240 , // 453 - ko-kp - 0x412 , 0x3b5 , 0x3b5 , 0x2713, 0x5161, 0x86 , 1 , 454 , 454 , // 454 - ko-kr - 0x57 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 456 , 143 , // 455 - kok - 0x457 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 456 , 143 , // 456 - kok-in - 0x71 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 458 , 240 , // 457 - kr - 0x471 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 458 , 240 , // 458 - kr-ng - 0x60 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 461 , 240 , // 459 - ks - 0x460 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 461 , 240 , // 460 - ks-arab - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 461 , 240 , // 461 - ks-arab-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 463 , 187 , // 462 - ks-deva - 0x860 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 463 , 187 , // 463 - ks-deva-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 465 , 240 , // 464 - ksb - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 465 , 240 , // 465 - ksb-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 467 , 240 , // 466 - ksf - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 467 , 240 , // 467 - ksf-cm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 469 , 240 , // 468 - ksh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 469 , 240 , // 469 - ksh-de - 0x92 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 472 , 143 , // 470 - ku - 0x7c92 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 472 , 143 , // 471 - ku-arab - 0x492 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 472 , 143 , // 472 - ku-arab-iq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 0 , 473 , 240 , // 473 - ku-arab-ir - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf2 , 1 , 475 , 240 , // 474 - kw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf2 , 1 , 475 , 240 , // 475 - kw-gb - 0x40 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x82 , 1 , 477 , 477 , // 476 - ky - 0x440 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x82 , 1 , 477 , 477 , // 477 - ky-kg - 0x76 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x989e, 1 , 479 , 143 , // 478 - la - 0x476 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x989e, 1 , 479 , 143 , // 479 - la-001 - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 481 , 240 , // 480 - lag - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 481 , 240 , // 481 - lag-tz - 0x6e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 , 483 , 483 , // 482 - lb - 0x46e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 , 483 , 483 , // 483 - lb-lu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 485 , 240 , // 484 - lg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 485 , 240 , // 485 - lg-ug - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 487 , 240 , // 486 - lkt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 487 , 240 , // 487 - lkt-us - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 490 , 240 , // 488 - ln - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9 , 1 , 489 , 240 , // 489 - ln-ao - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 490 , 240 , // 490 - ln-cd - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 , 491 , 240 , // 491 - ln-cf - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2b , 1 , 492 , 240 , // 492 - ln-cg - 0x54 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8a , 1 , 494 , 143 , // 493 - lo - 0x454 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8a , 1 , 494 , 143 , // 494 - lo-la - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 497 , 240 , // 495 - lrc - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x79 , 2 , 496 , 240 , // 496 - lrc-iq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 497 , 240 , // 497 - lrc-ir - 0x27 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8d , 1 , 499 , 499 , // 498 - lt - 0x427 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8d , 1 , 499 , 499 , // 499 - lt-lt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 501 , 240 , // 500 - lu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 501 , 240 , // 501 - lu-cd - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 503 , 240 , // 502 - luo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 503 , 240 , // 503 - luo-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 505 , 240 , // 504 - luy - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 505 , 240 , // 505 - luy-ke - 0x26 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8c , 1 , 507 , 507 , // 506 - lv - 0x426 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8c , 1 , 507 , 507 , // 507 - lv-lv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 509 , 240 , // 508 - mas - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 509 , 240 , // 509 - mas-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 510 , 240 , // 510 - mas-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 512 , 240 , // 511 - mer - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 512 , 240 , // 512 - mer-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa0 , 1 , 514 , 240 , // 513 - mfe - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa0 , 1 , 514 , 240 , // 514 - mfe-mu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x95 , 1 , 516 , 240 , // 515 - mg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x95 , 1 , 516 , 240 , // 516 - mg-mg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 518 , 240 , // 517 - mgh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 518 , 240 , // 518 - mgh-mz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 520 , 240 , // 519 - mgo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 520 , 240 , // 520 - mgo-cm - 0x81 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb7 , 1 , 522 , 522 , // 521 - mi - 0x481 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb7 , 1 , 522 , 522 , // 522 - mi-nz - 0x2f , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x4ca2, 1 , 524 , 524 , // 523 - mk - 0x42f , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x4ca2, 1 , 524 , 524 , // 524 - mk-mk - 0x4c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 526 , 143 , // 525 - ml - 0x44c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 526 , 143 , // 526 - ml-in - 0x50 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 , 529 , 529 , // 527 - mn - 0x7850 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 , 529 , 529 , // 528 - mn-cyrl - 0x450 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 , 529 , 529 , // 529 - mn-mn - 0x7c50 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 531 , 531 , // 530 - mn-mong - 0x850 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 531 , 531 , // 531 - mn-mong-cn - 0xc50 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9a , 1 , 532 , 532 , // 532 - mn-mong-mn - 0x58 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 534 , 187 , // 533 - mni - 0x458 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 534 , 187 , // 534 - mni-in - 0x7c , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 , 536 , 240 , // 535 - moh - 0x47c , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 , 536 , 240 , // 536 - moh-ca - 0x4e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 538 , 143 , // 537 - mr - 0x44e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 538 , 143 , // 538 - mr-in - 0x3e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa7 , 1 , 541 , 541 , // 539 - ms - 0x83e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x25 , 1 , 540 , 540 , // 540 - ms-bn - 0x43e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa7 , 1 , 541 , 541 , // 541 - ms-my - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd7 , 1 , 542 , 240 , // 542 - ms-sg - 0x3a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa3 , 1 , 544 , 544 , // 543 - mt - 0x43a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa3 , 1 , 544 , 544 , // 544 - mt-mt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 546 , 240 , // 545 - mua - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 546 , 240 , // 546 - mua-cm - 0x55 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x1b , 2 , 548 , 240 , // 547 - my - 0x455 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x1b , 2 , 548 , 240 , // 548 - my-mm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 550 , 240 , // 549 - mzn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 550 , 240 , // 550 - mzn-ir - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xfe , 1 , 552 , 240 , // 551 - naq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xfe , 1 , 552 , 240 , // 552 - naq-na - 0x7c14 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 554 , 554 , // 553 - nb - 0x414 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 554 , 554 , // 554 - nb-no - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xdc , 1 , 555 , 240 , // 555 - nb-sj - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 557 , 240 , // 556 - nd - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 557 , 240 , // 557 - nd-zw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 559 , 240 , // 558 - nds - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 559 , 240 , // 559 - nds-de - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb0 , 1 , 560 , 240 , // 560 - nds-nl - 0x61 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb2 , 1 , 563 , 143 , // 561 - ne - 0x861 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 562 , 240 , // 562 - ne-in - 0x461 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb2 , 1 , 563 , 143 , // 563 - ne-np - 0x13 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 569 , 569 , // 564 - nl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12e , 1 , 565 , 240 , // 565 - nl-aw - 0x813 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15 , 1 , 566 , 566 , // 566 - nl-be - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9a55d42, 1 , 567 , 240 , // 567 - nl-bq - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x111 , 1 , 568 , 240 , // 568 - nl-cw - 0x413 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 569 , 569 , // 569 - nl-nl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb5 , 1 , 570 , 240 , // 570 - nl-sr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x78f7, 1 , 571 , 240 , // 571 - nl-sx - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 573 , 240 , // 572 - nmg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 573 , 240 , // 573 - nmg-cm - 0x7814 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 575 , 575 , // 574 - nn - 0x814 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 575 , 575 , // 575 - nn-no - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 577 , 240 , // 576 - nnh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 577 , 240 , // 577 - nnh-cm - 0x14 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 554 , 554 , // 578 - no - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x64 , 2 , 580 , 143 , // 579 - nqo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x64 , 2 , 580 , 143 , // 580 - nqo-gn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 582 , 240 , // 581 - nr - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 582 , 240 , // 582 - nr-za - 0x6c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 584 , 584 , // 583 - nso - 0x46c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 584 , 584 , // 584 - nso-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x114 , 1 , 586 , 240 , // 585 - nus - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x114 , 1 , 586 , 240 , // 586 - nus-ss - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 588 , 240 , // 587 - nyn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 588 , 240 , // 588 - nyn-ug - 0x82 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 590 , 590 , // 589 - oc - 0x482 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 590 , 590 , // 590 - oc-fr - 0x72 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 592 , 240 , // 591 - om - 0x472 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 592 , 240 , // 592 - om-et - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 593 , 240 , // 593 - om-ke - 0x48 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 595 , 143 , // 594 - or - 0x448 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 595 , 143 , // 595 - or-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 597 , 240 , // 596 - os - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 597 , 240 , // 597 - os-ge - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 598 , 240 , // 598 - os-ru - 0x46 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 602 , 143 , // 599 - pa - 0x7c46 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 601 , 143 , // 600 - pa-arab - 0x846 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 601 , 143 , // 601 - pa-arab-pk - 0x446 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 602 , 143 , // 602 - pa-in - 0x79 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 , 604 , 145 , // 603 - pap - 0x479 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 , 604 , 145 , // 604 - pap-029 - 0x15 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xbf , 1 , 606 , 606 , // 605 - pl - 0x415 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xbf , 1 , 606 , 606 , // 606 - pl-pl - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 608 , 240 , // 607 - prg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 608 , 240 , // 608 - prg-001 - 0x8c , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3 , 2 , 610 , 143 , // 609 - prs - 0x48c , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3 , 2 , 610 , 143 , // 610 - prs-af - 0x63 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 612 , 143 , // 611 - ps - 0x463 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 612 , 143 , // 612 - ps-af - 0x16 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x20 , 1 , 615 , 615 , // 613 - pt - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9 , 1 , 614 , 240 , // 614 - pt-ao - 0x416 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x20 , 1 , 615 , 615 , // 615 - pt-br - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 616 , 240 , // 616 - pt-ch - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x39 , 1 , 617 , 240 , // 617 - pt-cv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x45 , 1 , 618 , 240 , // 618 - pt-gq - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc4 , 1 , 619 , 240 , // 619 - pt-gw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x93 , 1 , 620 , 240 , // 620 - pt-lu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x97 , 1 , 621 , 240 , // 621 - pt-mo - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa8 , 1 , 622 , 240 , // 622 - pt-mz - 0x816 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc1 , 1 , 623 , 623 , // 623 - pt-pt - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe9 , 1 , 624 , 240 , // 624 - pt-st - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f60e7, 1 , 625 , 240 , // 625 - pt-tl - 0x901 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x7c , 1 , 626 , 190 , // 626 - qps-latn-x-sh - 0x501 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xf4 , 1 , 627 , 627 , // 627 - qps-ploc - 0x5fe , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 628 , 628 , // 628 - qps-ploca - 0x9ff , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 , 629 , 143 , // 629 - qps-plocm - 0x86 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 632 , 632 , // 630 - quc - 0x7c86 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 632 , 632 , // 631 - quc-latn - 0x486 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 632 , 632 , // 632 - quc-latn-gt - 0x6b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 , 634 , 634 , // 633 - quz - 0x46b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 , 634 , 634 , // 634 - quz-bo - 0x86b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x42 , 1 , 635 , 635 , // 635 - quz-ec - 0xc6b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xbb , 1 , 636 , 636 , // 636 - quz-pe - 0x17 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 , 638 , 638 , // 637 - rm - 0x417 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 , 638 , 638 , // 638 - rm-ch - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 , 640 , 240 , // 639 - rn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 , 640 , 240 , // 640 - rn-bi - 0x18 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xc8 , 1 , 643 , 643 , // 641 - ro - 0x818 , 0x4e2 , 0x354 , 0x2 , 0x1f4 , 0x98 , 1 , 642 , 240 , // 642 - ro-md - 0x418 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xc8 , 1 , 643 , 643 , // 643 - ro-ro - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 645 , 240 , // 644 - rof - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 645 , 240 , // 645 - rof-tz - 0x19 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 651 , 651 , // 646 - ru - 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x1d , 1 , 647 , 240 , // 647 - ru-by - 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x82 , 1 , 648 , 240 , // 648 - ru-kg - 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x89 , 1 , 649 , 240 , // 649 - ru-kz - 0x819 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x98 , 1 , 650 , 240 , // 650 - ru-md - 0x419 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 651 , 651 , // 651 - ru-ru - 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0xf1 , 1 , 652 , 240 , // 652 - ru-ua - 0x87 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xcc , 1 , 654 , 654 , // 653 - rw - 0x487 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xcc , 1 , 654 , 654 , // 654 - rw-rw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 656 , 240 , // 655 - rwk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 656 , 240 , // 656 - rwk-tz - 0x4f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 658 , 143 , // 657 - sa - 0x44f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 658 , 143 , // 658 - sa-in - 0x85 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 660 , 660 , // 659 - sah - 0x485 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 660 , 660 , // 660 - sah-ru - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 662 , 240 , // 661 - saq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 662 , 240 , // 662 - saq-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 664 , 240 , // 663 - sbp - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 664 , 240 , // 664 - sbp-tz - 0x59 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 667 , 143 , // 665 - sd - 0x7c59 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 667 , 143 , // 666 - sd-arab - 0x859 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 667 , 143 , // 667 - sd-arab-pk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 669 , 187 , // 668 - sd-deva - 0x459 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 669 , 187 , // 669 - sd-deva-in - 0x3b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 672 , 672 , // 670 - se - 0xc3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 671 , 671 , // 671 - se-fi - 0x43b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 672 , 672 , // 672 - se-no - 0x83b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 673 , 673 , // 673 - se-se - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 675 , 240 , // 674 - seh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 675 , 240 , // 675 - seh-mz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 677 , 240 , // 676 - ses - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 677 , 240 , // 677 - ses-ml - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 , 679 , 240 , // 678 - sg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 , 679 , 240 , // 679 - sg-cf - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 684 , 240 , // 680 - shi - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 682 , 240 , // 681 - shi-latn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 682 , 240 , // 682 - shi-latn-ma - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 684 , 240 , // 683 - shi-tfng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 684 , 240 , // 684 - shi-tfng-ma - 0x5b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 , 686 , 143 , // 685 - si - 0x45b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 , 686 , 143 , // 686 - si-lk - 0x1b , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x8f , 1 , 688 , 688 , // 687 - sk - 0x41b , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x8f , 1 , 688 , 688 , // 688 - sk-sk - 0x24 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xd4 , 1 , 690 , 690 , // 689 - sl - 0x424 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xd4 , 1 , 690 , 690 , // 690 - sl-si - 0x783b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 693 , 693 , // 691 - sma - 0x183b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 692 , 692 , // 692 - sma-no - 0x1c3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 693 , 693 , // 693 - sma-se - 0x7c3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 696 , 696 , // 694 - smj - 0x103b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 695 , 695 , // 695 - smj-no - 0x143b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 696 , 696 , // 696 - smj-se - 0x703b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 698 , 698 , // 697 - smn - 0x243b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 698 , 698 , // 698 - smn-fi - 0x743b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 700 , 700 , // 699 - sms - 0x203b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 700 , 700 , // 700 - sms-fi - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 703 , 240 , // 701 - sn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 703 , 240 , // 702 - sn-latn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 703 , 240 , // 703 - sn-latn-zw - 0x77 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd8 , 1 , 708 , 240 , // 704 - so - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3e , 1 , 705 , 240 , // 705 - so-dj - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 706 , 240 , // 706 - so-et - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 707 , 240 , // 707 - so-ke - 0x477 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd8 , 1 , 708 , 240 , // 708 - so-so - 0x1c , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x6 , 1 , 710 , 710 , // 709 - sq - 0x41c , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x6 , 1 , 710 , 710 , // 710 - sq-al - 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x4ca2, 1 , 711 , 240 , // 711 - sq-mk - 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x974941, 1 , 712 , 240 , // 712 - sq-xk - 0x7c1a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 , 724 , 724 , // 713 - sr - 0x6c1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10f , 1 , 718 , 718 , // 714 - sr-cyrl - 0x1c1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x19 , 1 , 715 , 715 , // 715 - sr-cyrl-ba - 0xc1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10d , 1 , 716 , 716 , // 716 - sr-cyrl-cs - 0x301a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10e , 1 , 717 , 717 , // 717 - sr-cyrl-me - 0x281a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10f , 1 , 718 , 718 , // 718 - sr-cyrl-rs - 0x1000 , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x974941, 1 , 719 , 240 , // 719 - sr-cyrl-xk - 0x701a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 , 724 , 724 , // 720 - sr-latn - 0x181a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 721 , 721 , // 721 - sr-latn-ba - 0x81a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10d , 1 , 722 , 722 , // 722 - sr-latn-cs - 0x2c1a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10e , 1 , 723 , 723 , // 723 - sr-latn-me - 0x241a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 , 724 , 724 , // 724 - sr-latn-rs - 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x974941, 1 , 725 , 240 , // 725 - sr-latn-xk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 728 , 240 , // 726 - ss - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x104 , 1 , 727 , 240 , // 727 - ss-sz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 728 , 240 , // 728 - ss-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 730 , 240 , // 729 - ssy - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 730 , 240 , // 730 - ssy-er - 0x30 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 733 , 240 , // 731 - st - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x92 , 1 , 732 , 240 , // 732 - st-ls - 0x430 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 733 , 240 , // 733 - st-za - 0x1d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 737 , 737 , // 734 - sv - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x9906f5, 1 , 735 , 240 , // 735 - sv-ax - 0x81d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 736 , 736 , // 736 - sv-fi - 0x41d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 737 , 737 , // 737 - sv-se - 0x41 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x81 , 1 , 740 , 740 , // 738 - sw - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x2c , 1 , 739 , 740 , // 739 - sw-cd - 0x441 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x81 , 1 , 740 , 740 , // 740 - sw-ke - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xef , 1 , 741 , 240 , // 741 - sw-tz - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xf0 , 1 , 742 , 240 , // 742 - sw-ug - 0x1000 , 0x0 , 0x1 , 0x0 , 0x1f4 , 0x2c , 1 , 744 , 240 , // 743 - swc - 0x1000 , 0x0 , 0x1 , 0x0 , 0x1f4 , 0x2c , 1 , 744 , 240 , // 744 - swc-cd - 0x5a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xde , 1 , 746 , 143 , // 745 - syr - 0x45a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xde , 1 , 746 , 143 , // 746 - syr-sy - 0x49 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 748 , 143 , // 747 - ta - 0x449 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 748 , 143 , // 748 - ta-in - 0x849 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 , 749 , 143 , // 749 - ta-lk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa7 , 1 , 750 , 240 , // 750 - ta-my - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd7 , 1 , 751 , 240 , // 751 - ta-sg - 0x4a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 753 , 143 , // 752 - te - 0x44a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 753 , 143 , // 753 - te-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 756 , 240 , // 754 - teo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 755 , 240 , // 755 - teo-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 756 , 240 , // 756 - teo-ug - 0x28 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 , 759 , 759 , // 757 - tg - 0x7c28 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 , 759 , 759 , // 758 - tg-cyrl - 0x428 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 , 759 , 759 , // 759 - tg-cyrl-tj - 0x1e , 0x36a , 0x36a , 0x2725, 0x5166, 0xe3 , 1 , 761 , 143 , // 760 - th - 0x41e , 0x36a , 0x36a , 0x2725, 0x5166, 0xe3 , 1 , 761 , 143 , // 761 - th-th - 0x73 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 763 , 143 , // 762 - ti - 0x873 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 763 , 143 , // 763 - ti-er - 0x473 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 764 , 143 , // 764 - ti-et - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 766 , 240 , // 765 - tig - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 766 , 240 , // 766 - tig-er - 0x42 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xee , 1 , 768 , 768 , // 767 - tk - 0x442 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xee , 1 , 768 , 768 , // 768 - tk-tm - 0x32 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 771 , 771 , // 769 - tn - 0x832 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13 , 1 , 770 , 770 , // 770 - tn-bw - 0x432 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 771 , 771 , // 771 - tn-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe7 , 1 , 773 , 240 , // 772 - to - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe7 , 1 , 773 , 240 , // 773 - to-to - 0x1f , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0xeb , 1 , 776 , 776 , // 774 - tr - 0x1000 , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x3b , 1 , 775 , 240 , // 775 - tr-cy - 0x41f , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0xeb , 1 , 776 , 776 , // 776 - tr-tr - 0x31 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 778 , 240 , // 777 - ts - 0x431 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 778 , 240 , // 778 - ts-za - 0x44 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 780 , 780 , // 779 - tt - 0x444 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 780 , 780 , // 780 - tt-ru - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 782 , 240 , // 781 - twq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 782 , 240 , // 782 - twq-ne - 0x5f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 787 , 787 , // 783 - tzm - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 , 785 , 240 , // 784 - tzm-arab - 0x45f , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 , 785 , 240 , // 785 - tzm-arab-ma - 0x7c5f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 787 , 787 , // 786 - tzm-latn - 0x85f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 787 , 787 , // 787 - tzm-latn-dz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 788 , 240 , // 788 - tzm-latn-ma - 0x785f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 790 , 316 , // 789 - tzm-tfng - 0x105f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 790 , 316 , // 790 - tzm-tfng-ma - 0x80 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x2d , 1 , 792 , 143 , // 791 - ug - 0x480 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x2d , 1 , 792 , 143 , // 792 - ug-cn - 0x22 , 0x4e3 , 0x362 , 0x2721, 0x1f4 , 0xf1 , 1 , 794 , 794 , // 793 - uk - 0x422 , 0x4e3 , 0x362 , 0x2721, 0x1f4 , 0xf1 , 1 , 794 , 794 , // 794 - uk-ua - 0x20 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 1 , 797 , 143 , // 795 - ur - 0x820 , 0x4e8 , 0x2d0 , 0x2 , 0x1f4 , 0x71 , 2 , 796 , 240 , // 796 - ur-in - 0x420 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 1 , 797 , 143 , // 797 - ur-pk - 0x43 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 , 804 , 804 , // 798 - uz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 800 , 240 , // 799 - uz-arab - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 800 , 240 , // 800 - uz-arab-af - 0x7843 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xf7 , 1 , 802 , 802 , // 801 - uz-cyrl - 0x843 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xf7 , 1 , 802 , 802 , // 802 - uz-cyrl-uz - 0x7c43 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 , 804 , 804 , // 803 - uz-latn - 0x443 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 , 804 , 804 , // 804 - uz-latn-uz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 809 , 240 , // 805 - vai - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 807 , 240 , // 806 - vai-latn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 807 , 240 , // 807 - vai-latn-lr - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 809 , 240 , // 808 - vai-vaii - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 809 , 240 , // 809 - vai-vaii-lr - 0x33 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 811 , 240 , // 810 - ve - 0x433 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 811 , 240 , // 811 - ve-za - 0x2a , 0x4ea , 0x4ea , 0x2710, 0x1f4 , 0xfb , 1 , 813 , 143 , // 812 - vi - 0x42a , 0x4ea , 0x4ea , 0x2710, 0x1f4 , 0xfb , 1 , 813 , 143 , // 813 - vi-vn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 815 , 240 , // 814 - vo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 815 , 240 , // 815 - vo-001 - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 817 , 240 , // 816 - vun - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 817 , 240 , // 817 - vun-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 819 , 240 , // 818 - wae - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 819 , 240 , // 819 - wae-ch - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 821 , 240 , // 820 - wal - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 821 , 240 , // 821 - wal-et - 0x88 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 823 , 823 , // 822 - wo - 0x488 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 823 , 823 , // 823 - wo-sn - 0x1007f, 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , -1 , -1 , // 824 - x-iv_mathan - 0x34 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 826 , 826 , // 825 - xh - 0x434 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 826 , 826 , // 826 - xh-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 828 , 240 , // 827 - xog - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 828 , 240 , // 828 - xog-ug - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 830 , 240 , // 829 - yav - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 830 , 240 , // 830 - yav-cm - 0x3d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 832 , 240 , // 831 - yi - 0x43d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 832 , 240 , // 832 - yi-001 - 0x6a , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 835 , 835 , // 833 - yo - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x1c , 1 , 834 , 240 , // 834 - yo-bj - 0x46a , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 835 , 835 , // 835 - yo-ng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x68 , 1 , 837 , 240 , // 836 - yue - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x68 , 1 , 837 , 240 , // 837 - yue-hk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 840 , 316 , // 838 - zgh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 840 , 316 , // 839 - zgh-tfng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 840 , 316 , // 840 - zgh-tfng-ma - 0x7804 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 841 - zh - 0x4 , 0x3a8 , 0x3a8 , 0x0 , 0x1f4 , 0x2d , 1 , 844 , 844 , // 842 - zh-chs - 0x7c04 , 0x3b6 , 0x3b6 , 0x0 , 0x1f4 , 0x68 , 1 , 851 , 851 , // 843 - zh-cht - 0x804 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 844 - zh-cn - 0x50804, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 845 - zh-cn_phoneb - 0x20804, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 846 - zh-cn_stroke - 0x4 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 847 - zh-hans - 0x1000 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x68 , 1 , 848 , 240 , // 848 - zh-hans-hk - 0x1000 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x97 , 1 , 849 , 240 , // 849 - zh-hans-mo - 0x7c04 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 , 851 , 851 , // 850 - zh-hant - 0xc04 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 , 851 , 851 , // 851 - zh-hk - 0x40c04, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 , 851 , 851 , // 852 - zh-hk_radstr - 0x1404 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 , 853 , 853 , // 853 - zh-mo - 0x41404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 , 853 , 853 , // 854 - zh-mo_radstr - 0x21404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 , 853 , 853 , // 855 - zh-mo_stroke - 0x1004 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 , 856 , 856 , // 856 - zh-sg - 0x51004, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 , 856 , 856 , // 857 - zh-sg_phoneb - 0x21004, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 , 856 , 856 , // 858 - zh-sg_stroke - 0x404 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 , 859 , 859 , // 859 - zh-tw - 0x30404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 , 859 , 859 , // 860 - zh-tw_pronun - 0x40404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 , 859 , 859 , // 861 - zh-tw_radstr - 0x35 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 863 , 863 , // 862 - zu - 0x435 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 863 , 863 , // 863 - zu-za - }; - - // s_lcids list all supported lcids. used to binary search and we use the index of the matched lcid to - // get the index in s_localeNamesIndices using s_lcidToCultureNameIndices - private static readonly int[] s_lcids = new int[] - { - // Lcid , index - index in c_localeNames - 0x1 , // 0 - 52 - 0x2 , // 1 - 301 - 0x3 , // 2 - 421 - 0x4 , // 3 - 4139 - 0x5 , // 4 - 502 - 0x6 , // 5 - 523 - 0x7 , // 6 - 544 - 0x8 , // 7 - 664 - 0x9 , // 8 - 676 - 0xa , // 9 - 1214 - 0xb , // 10 - 1423 - 0xc , // 11 - 1451 - 0xd , // 12 - 1825 - 0xe , // 13 - 1860 - 0xf , // 14 - 1929 - 0x10 , // 15 - 1936 - 0x11 , // 16 - 1989 - 0x12 , // 17 - 2179 - 0x13 , // 18 - 2685 - 0x14 , // 19 - 2747 - 0x15 , // 20 - 2864 - 0x16 , // 21 - 2897 - 0x17 , // 22 - 3041 - 0x18 , // 23 - 3055 - 0x19 , // 24 - 3076 - 0x1a , // 25 - 1839 - 0x1b , // 26 - 3284 - 0x1c , // 27 - 3387 - 0x1d , // 28 - 3553 - 0x1e , // 29 - 3673 - 0x1f , // 30 - 3727 - 0x20 , // 31 - 3847 - 0x21 , // 32 - 1908 - 0x22 , // 33 - 3840 - 0x23 , // 34 - 276 - 0x24 , // 35 - 3291 - 0x25 , // 36 - 1354 - 0x26 , // 37 - 2429 - 0x27 , // 38 - 2397 - 0x28 , // 39 - 3654 - 0x29 , // 40 - 1377 - 0x2a , // 41 - 3960 - 0x2b , // 42 - 1879 - 0x2c , // 43 - 224 - 0x2d , // 44 - 1361 - 0x2e , // 45 - 1851 - 0x2f , // 46 - 2501 - 0x30 , // 47 - 3541 - 0x31 , // 48 - 3739 - 0x32 , // 49 - 3708 - 0x33 , // 50 - 3953 - 0x34 , // 51 - 4020 - 0x35 , // 52 - 4277 - 0x36 , // 53 - 17 - 0x37 , // 54 - 2062 - 0x38 , // 55 - 1439 - 0x39 , // 56 - 1832 - 0x3a , // 57 - 2598 - 0x3b , // 58 - 3194 - 0x3c , // 59 - 1705 - 0x3d , // 60 - 4045 - 0x3e , // 61 - 2581 - 0x3f , // 62 - 2133 - 0x40 , // 63 - 2306 - 0x41 , // 64 - 3570 - 0x42 , // 65 - 3701 - 0x43 , // 66 - 3859 - 0x44 , // 67 - 3746 - 0x45 , // 68 - 336 - 0x46 , // 69 - 2830 - 0x47 , // 70 - 1754 - 0x48 , // 71 - 2811 - 0x49 , // 72 - 3610 - 0x4a , // 73 - 3632 - 0x4b , // 74 - 2172 - 0x4c , // 75 - 2508 - 0x4d , // 76 - 199 - 0x4e , // 77 - 2574 - 0x4f , // 78 - 3124 - 0x50 , // 79 - 2515 - 0x51 , // 80 - 348 - 0x52 , // 81 - 516 - 0x53 , // 82 - 2165 - 0x54 , // 83 - 2375 - 0x55 , // 84 - 2614 - 0x56 , // 85 - 1719 - 0x57 , // 86 - 2191 - 0x58 , // 87 - 2556 - 0x59 , // 88 - 3158 - 0x5a , // 89 - 3601 - 0x5b , // 90 - 3277 - 0x5c , // 91 - 473 - 0x5d , // 92 - 1953 - 0x5e , // 93 - 45 - 0x5f , // 94 - 3762 - 0x60 , // 95 - 2207 - 0x61 , // 96 - 2673 - 0x62 , // 97 - 1698 - 0x63 , // 98 - 2890 - 0x64 , // 99 - 1430 - 0x65 , // 100 - 620 - 0x66 , // 101 - 308 - 0x67 , // 102 - 1384 - 0x68 , // 103 - 1777 - 0x69 , // 104 - 1899 - 0x6a , // 105 - 4053 - 0x6b , // 106 - 3020 - 0x6c , // 107 - 2765 - 0x6d , // 108 - 260 - 0x6e , // 109 - 2330 - 0x6f , // 110 - 2149 - 0x70 , // 111 - 1915 - 0x71 , // 112 - 2200 - 0x72 , // 113 - 2799 - 0x73 , // 114 - 3680 - 0x74 , // 115 - 1726 - 0x75 , // 116 - 1816 - 0x76 , // 117 - 2313 - 0x77 , // 118 - 3365 - 0x78 , // 119 - 1922 - 0x79 , // 120 - 2854 - 0x7a , // 121 - 190 - 0x7c , // 122 - 2565 - 0x7e , // 123 - 360 - 0x80 , // 124 - 3833 - 0x81 , // 125 - 2494 - 0x82 , // 126 - 2792 - 0x83 , // 127 - 495 - 0x84 , // 128 - 1733 - 0x85 , // 129 - 3131 - 0x86 , // 130 - 2998 - 0x87 , // 131 - 3108 - 0x88 , // 132 - 4002 - 0x8c , // 133 - 2881 - 0x91 , // 134 - 1712 - 0x92 , // 135 - 2270 - 0x401 , // 136 - 150 - 0x402 , // 137 - 303 - 0x403 , // 138 - 428 - 0x404 , // 139 - 4248 - 0x405 , // 140 - 504 - 0x406 , // 141 - 525 - 0x407 , // 142 - 561 - 0x408 , // 143 - 671 - 0x409 , // 144 - 1161 - 0x40a , // 145 - 1272 - 0x40b , // 146 - 1425 - 0x40c , // 147 - 1529 - 0x40d , // 148 - 1827 - 0x40e , // 149 - 1862 - 0x40f , // 150 - 1931 - 0x410 , // 151 - 1943 - 0x411 , // 152 - 1991 - 0x412 , // 153 - 2186 - 0x413 , // 154 - 2707 - 0x414 , // 155 - 2641 - 0x415 , // 156 - 2866 - 0x416 , // 157 - 2904 - 0x417 , // 158 - 3043 - 0x418 , // 159 - 3062 - 0x419 , // 160 - 3098 - 0x41a , // 161 - 1846 - 0x41b , // 162 - 3286 - 0x41c , // 163 - 3389 - 0x41d , // 164 - 3565 - 0x41e , // 165 - 3675 - 0x41f , // 166 - 3734 - 0x420 , // 167 - 3854 - 0x421 , // 168 - 1910 - 0x422 , // 169 - 3842 - 0x423 , // 170 - 278 - 0x424 , // 171 - 3293 - 0x425 , // 172 - 1356 - 0x426 , // 173 - 2431 - 0x427 , // 174 - 2399 - 0x428 , // 175 - 3663 - 0x429 , // 176 - 1379 - 0x42a , // 177 - 3962 - 0x42b , // 178 - 1881 - 0x42c , // 179 - 250 - 0x42d , // 180 - 1363 - 0x42e , // 181 - 1854 - 0x42f , // 182 - 2503 - 0x430 , // 183 - 3548 - 0x431 , // 184 - 3741 - 0x432 , // 185 - 3715 - 0x433 , // 186 - 3955 - 0x434 , // 187 - 4022 - 0x435 , // 188 - 4279 - 0x436 , // 189 - 24 - 0x437 , // 190 - 2064 - 0x438 , // 191 - 1446 - 0x439 , // 192 - 1834 - 0x43a , // 193 - 2600 - 0x43b , // 194 - 3201 - 0x43d , // 195 - 4047 - 0x43e , // 196 - 2588 - 0x43f , // 197 - 2135 - 0x440 , // 198 - 2308 - 0x441 , // 199 - 3577 - 0x442 , // 200 - 3703 - 0x443 , // 201 - 3902 - 0x444 , // 202 - 3748 - 0x445 , // 203 - 343 - 0x446 , // 204 - 2849 - 0x447 , // 205 - 1756 - 0x448 , // 206 - 2813 - 0x449 , // 207 - 3612 - 0x44a , // 208 - 3634 - 0x44b , // 209 - 2174 - 0x44c , // 210 - 2510 - 0x44d , // 211 - 201 - 0x44e , // 212 - 2576 - 0x44f , // 213 - 3126 - 0x450 , // 214 - 2524 - 0x451 , // 215 - 350 - 0x452 , // 216 - 518 - 0x453 , // 217 - 2167 - 0x454 , // 218 - 2377 - 0x455 , // 219 - 2616 - 0x456 , // 220 - 1721 - 0x457 , // 221 - 2194 - 0x458 , // 222 - 2559 - 0x459 , // 223 - 3184 - 0x45a , // 224 - 3604 - 0x45b , // 225 - 3279 - 0x45c , // 226 - 484 - 0x45d , // 227 - 1962 - 0x45e , // 228 - 47 - 0x45f , // 229 - 3773 - 0x460 , // 230 - 2209 - 0x461 , // 231 - 2680 - 0x462 , // 232 - 1700 - 0x463 , // 233 - 2892 - 0x464 , // 234 - 1433 - 0x465 , // 235 - 622 - 0x466 , // 236 - 311 - 0x467 , // 237 - 1418 - 0x468 , // 238 - 1806 - 0x469 , // 239 - 1902 - 0x46a , // 240 - 4060 - 0x46b , // 241 - 3023 - 0x46c , // 242 - 2768 - 0x46d , // 243 - 262 - 0x46e , // 244 - 2332 - 0x46f , // 245 - 2151 - 0x470 , // 246 - 1917 - 0x471 , // 247 - 2202 - 0x472 , // 248 - 2801 - 0x473 , // 249 - 3687 - 0x474 , // 250 - 1728 - 0x475 , // 251 - 1819 - 0x476 , // 252 - 2315 - 0x477 , // 253 - 3382 - 0x478 , // 254 - 1924 - 0x479 , // 255 - 2857 - 0x47a , // 256 - 193 - 0x47c , // 257 - 2568 - 0x47e , // 258 - 362 - 0x480 , // 259 - 3835 - 0x481 , // 260 - 2496 - 0x482 , // 261 - 2794 - 0x483 , // 262 - 497 - 0x484 , // 263 - 1742 - 0x485 , // 264 - 3134 - 0x486 , // 265 - 3009 - 0x487 , // 266 - 3110 - 0x488 , // 267 - 4004 - 0x48c , // 268 - 2884 - 0x491 , // 269 - 1714 - 0x492 , // 270 - 2279 - 0x501 , // 271 - 2972 - 0x5fe , // 272 - 2980 - 0x801 , // 273 - 95 - 0x803 , // 274 - 433 - 0x804 , // 275 - 4110 - 0x807 , // 276 - 556 - 0x809 , // 277 - 831 - 0x80a , // 278 - 1299 - 0x80c , // 279 - 1459 - 0x810 , // 280 - 1938 - 0x813 , // 281 - 2692 - 0x814 , // 282 - 2733 - 0x816 , // 283 - 2944 - 0x818 , // 284 - 3057 - 0x819 , // 285 - 3093 - 0x81a , // 286 - 3480 - 0x81d , // 287 - 3560 - 0x820 , // 288 - 3849 - 0x82c , // 289 - 233 - 0x82e , // 290 - 605 - 0x832 , // 291 - 3710 - 0x83b , // 292 - 3206 - 0x83c , // 293 - 1707 - 0x83e , // 294 - 2583 - 0x843 , // 295 - 3885 - 0x845 , // 296 - 338 - 0x846 , // 297 - 2839 - 0x849 , // 298 - 3617 - 0x850 , // 299 - 2536 - 0x859 , // 300 - 3167 - 0x85d , // 301 - 1979 - 0x85f , // 302 - 3792 - 0x860 , // 303 - 2233 - 0x861 , // 304 - 2675 - 0x867 , // 305 - 1403 - 0x86b , // 306 - 3029 - 0x873 , // 307 - 3682 - 0x901 , // 308 - 2959 - 0x9ff , // 309 - 2989 - 0xc01 , // 310 - 80 - 0xc04 , // 311 - 4173 - 0xc07 , // 312 - 546 - 0xc09 , // 313 - 716 - 0xc0a , // 314 - 1267 - 0xc0c , // 315 - 1484 - 0xc1a , // 316 - 3423 - 0xc3b , // 317 - 3196 - 0xc50 , // 318 - 2546 - 0xc51 , // 319 - 638 - 0xc6b , // 320 - 3035 - 0x1001 , // 321 - 120 - 0x1004 , // 322 - 4219 - 0x1007 , // 323 - 588 - 0x1009 , // 324 - 756 - 0x100a , // 325 - 1289 - 0x100c , // 326 - 1504 - 0x101a , // 327 - 1841 - 0x103b , // 328 - 3316 - 0x105f , // 329 - 3822 - 0x1401 , // 330 - 75 - 0x1404 , // 331 - 4190 - 0x1407 , // 332 - 583 - 0x1409 , // 333 - 1026 - 0x140a , // 334 - 1247 - 0x140c , // 335 - 1569 - 0x141a , // 336 - 402 - 0x143b , // 337 - 3322 - 0x1801 , // 338 - 125 - 0x1809 , // 339 - 881 - 0x180a , // 340 - 1309 - 0x180c , // 341 - 1579 - 0x181a , // 342 - 3470 - 0x183b , // 343 - 3301 - 0x1c01 , // 344 - 180 - 0x1c09 , // 345 - 1191 - 0x1c0a , // 346 - 1257 - 0x1c0c , // 347 - 1453 - 0x1c1a , // 348 - 3413 - 0x1c3b , // 349 - 3307 - 0x2001 , // 350 - 135 - 0x2009 , // 351 - 911 - 0x200a , // 352 - 1349 - 0x200c , // 353 - 1634 - 0x201a , // 354 - 385 - 0x203b , // 355 - 3340 - 0x2401 , // 356 - 185 - 0x2409 , // 357 - 684 - 0x240a , // 358 - 1242 - 0x240c , // 359 - 1489 - 0x241a , // 360 - 3500 - 0x243b , // 361 - 3331 - 0x2801 , // 362 - 170 - 0x2809 , // 363 - 751 - 0x280a , // 364 - 1314 - 0x280c , // 365 - 1649 - 0x281a , // 366 - 3443 - 0x2c01 , // 367 - 100 - 0x2c09 , // 368 - 1136 - 0x2c0a , // 369 - 1222 - 0x2c0c , // 370 - 1514 - 0x2c1a , // 371 - 3490 - 0x3001 , // 372 - 115 - 0x3009 , // 373 - 1201 - 0x300a , // 374 - 1262 - 0x300c , // 375 - 1509 - 0x301a , // 376 - 3433 - 0x3401 , // 377 - 110 - 0x3409 , // 378 - 1036 - 0x340a , // 379 - 1237 - 0x340c , // 380 - 1594 - 0x3801 , // 381 - 60 - 0x3809 , // 382 - 876 - 0x380a , // 383 - 1344 - 0x380c , // 384 - 1574 - 0x3c01 , // 385 - 65 - 0x3c09 , // 386 - 871 - 0x3c0a , // 387 - 1329 - 0x3c0c , // 388 - 1559 - 0x4001 , // 389 - 145 - 0x4009 , // 390 - 896 - 0x400a , // 391 - 1227 - 0x4409 , // 392 - 991 - 0x440a , // 393 - 1334 - 0x4809 , // 394 - 1086 - 0x480a , // 395 - 1294 - 0x4c0a , // 396 - 1304 - 0x500a , // 397 - 1324 - 0x540a , // 398 - 1339 - 0x580a , // 399 - 1216 - 0x5c0a , // 400 - 1252 - 0x641a , // 401 - 378 - 0x681a , // 402 - 395 - 0x6c1a , // 403 - 3406 - 0x701a , // 404 - 3463 - 0x703b , // 405 - 3328 - 0x742c , // 406 - 226 - 0x743b , // 407 - 3337 - 0x7804 , // 408 - 4096 - 0x7814 , // 409 - 2731 - 0x781a , // 410 - 376 - 0x782c , // 411 - 243 - 0x783b , // 412 - 3298 - 0x7843 , // 413 - 3878 - 0x7850 , // 414 - 2517 - 0x785d , // 415 - 1955 - 0x785f , // 416 - 3814 - 0x7c04 , // 417 - 4166 - 0x7c14 , // 418 - 2639 - 0x7c1a , // 419 - 3404 - 0x7c28 , // 420 - 3656 - 0x7c2e , // 421 - 602 - 0x7c3b , // 422 - 3313 - 0x7c43 , // 423 - 3895 - 0x7c46 , // 424 - 2832 - 0x7c50 , // 425 - 2529 - 0x7c59 , // 426 - 3160 - 0x7c5c , // 427 - 476 - 0x7c5d , // 428 - 1972 - 0x7c5f , // 429 - 3784 - 0x7c67 , // 430 - 1396 - 0x7c68 , // 431 - 1779 - 0x7c86 , // 432 - 3001 - 0x7c92 , // 433 - 2272 - 0x1007f, // 434 - 4009 - 0x10407, // 435 - 566 - 0x1040e, // 436 - 1867 - 0x10437, // 437 - 2069 - 0x20804, // 438 - 4127 - 0x21004, // 439 - 4236 - 0x21404, // 440 - 4207 - 0x30404, // 441 - 4253 - 0x40404, // 442 - 4265 - 0x40411, // 443 - 1996 - 0x40c04, // 444 - 4178 - 0x41404, // 445 - 4195 - 0x50804, // 446 - 4115 - 0x51004 // 447 - 4224 - }; - // each element in s_lcidToCultureNameIndices is index to s_localeNamesIndices - private static readonly int[] s_lcidToCultureNameIndices = new int[] - { - // Index to s_localeNamesIndices, index to this array - lcid - index to the c_localeNames - 13 , // 0 - 1 - 52 - 64 , // 1 - 2 - 301 - 88 , // 2 - 3 - 421 - 847 , // 3 - 4 - 4139 - 103 , // 4 - 5 - 502 - 109 , // 5 - 6 - 523 - 114 , // 6 - 7 - 544 - 140 , // 7 - 8 - 664 - 143 , // 8 - 9 - 676 - 251 , // 9 - a - 1214 - 293 , // 10 - b - 1423 - 300 , // 11 - c - 1451 - 377 , // 12 - d - 1825 - 386 , // 13 - e - 1860 - 402 , // 14 - f - 1929 - 404 , // 15 - 10 - 1936 - 413 , // 16 - 11 - 1989 - 452 , // 17 - 12 - 2179 - 564 , // 18 - 13 - 2685 - 578 , // 19 - 14 - 2747 - 605 , // 20 - 15 - 2864 - 613 , // 21 - 16 - 2897 - 637 , // 22 - 17 - 3041 - 641 , // 23 - 18 - 3055 - 646 , // 24 - 19 - 3076 - 381 , // 25 - 1a - 1839 - 687 , // 26 - 1b - 3284 - 709 , // 27 - 1c - 3387 - 734 , // 28 - 1d - 3553 - 760 , // 29 - 1e - 3673 - 774 , // 30 - 1f - 3727 - 795 , // 31 - 20 - 3847 - 396 , // 32 - 21 - 1908 - 793 , // 33 - 22 - 3840 - 58 , // 34 - 23 - 276 - 689 , // 35 - 24 - 3291 - 278 , // 36 - 25 - 1354 - 506 , // 37 - 26 - 2429 - 498 , // 38 - 27 - 2397 - 757 , // 39 - 28 - 3654 - 284 , // 40 - 29 - 1377 - 812 , // 41 - 2a - 3960 - 389 , // 42 - 2b - 1879 - 49 , // 43 - 2c - 224 - 280 , // 44 - 2d - 1361 - 384 , // 45 - 2e - 1851 - 523 , // 46 - 2f - 2501 - 731 , // 47 - 30 - 3541 - 777 , // 48 - 31 - 3739 - 769 , // 49 - 32 - 3708 - 810 , // 50 - 33 - 3953 - 825 , // 51 - 34 - 4020 - 862 , // 52 - 35 - 4277 - 4 , // 53 - 36 - 17 - 425 , // 54 - 37 - 2062 - 297 , // 55 - 38 - 1439 - 379 , // 56 - 39 - 1832 - 543 , // 57 - 3a - 2598 - 670 , // 58 - 3b - 3194 - 352 , // 59 - 3c - 1705 - 831 , // 60 - 3d - 4045 - 539 , // 61 - 3e - 2581 - 440 , // 62 - 3f - 2133 - 476 , // 63 - 40 - 2306 - 738 , // 64 - 41 - 3570 - 767 , // 65 - 42 - 3701 - 798 , // 66 - 43 - 3859 - 779 , // 67 - 44 - 3746 - 71 , // 68 - 45 - 336 - 599 , // 69 - 46 - 2830 - 364 , // 70 - 47 - 1754 - 594 , // 71 - 48 - 2811 - 747 , // 72 - 49 - 3610 - 752 , // 73 - 4a - 3632 - 450 , // 74 - 4b - 2172 - 525 , // 75 - 4c - 2508 - 43 , // 76 - 4d - 199 - 537 , // 77 - 4e - 2574 - 657 , // 78 - 4f - 3124 - 527 , // 79 - 50 - 2515 - 74 , // 80 - 51 - 348 - 107 , // 81 - 52 - 516 - 448 , // 82 - 53 - 2165 - 493 , // 83 - 54 - 2375 - 547 , // 84 - 55 - 2614 - 356 , // 85 - 56 - 1719 - 455 , // 86 - 57 - 2191 - 533 , // 87 - 58 - 2556 - 665 , // 88 - 59 - 3158 - 745 , // 89 - 5a - 3601 - 685 , // 90 - 5b - 3277 - 98 , // 91 - 5c - 473 - 408 , // 92 - 5d - 1953 - 11 , // 93 - 5e - 45 - 783 , // 94 - 5f - 3762 - 459 , // 95 - 60 - 2207 - 561 , // 96 - 61 - 2673 - 350 , // 97 - 62 - 1698 - 611 , // 98 - 63 - 2890 - 295 , // 99 - 64 - 1430 - 129 , // 100 - 65 - 620 - 66 , // 101 - 66 - 308 - 286 , // 102 - 67 - 1384 - 370 , // 103 - 68 - 1777 - 394 , // 104 - 69 - 1899 - 833 , // 105 - 6a - 4053 - 633 , // 106 - 6b - 3020 - 583 , // 107 - 6c - 2765 - 54 , // 108 - 6d - 260 - 482 , // 109 - 6e - 2330 - 444 , // 110 - 6f - 2149 - 398 , // 111 - 70 - 1915 - 457 , // 112 - 71 - 2200 - 591 , // 113 - 72 - 2799 - 762 , // 114 - 73 - 3680 - 358 , // 115 - 74 - 1726 - 375 , // 116 - 75 - 1816 - 478 , // 117 - 76 - 2313 - 704 , // 118 - 77 - 3365 - 400 , // 119 - 78 - 1922 - 603 , // 120 - 79 - 2854 - 41 , // 121 - 7a - 190 - 535 , // 122 - 7c - 2565 - 77 , // 123 - 7e - 360 - 791 , // 124 - 80 - 3833 - 521 , // 125 - 81 - 2494 - 589 , // 126 - 82 - 2792 - 101 , // 127 - 83 - 495 - 360 , // 128 - 84 - 1733 - 659 , // 129 - 85 - 3131 - 630 , // 130 - 86 - 2998 - 653 , // 131 - 87 - 3108 - 822 , // 132 - 88 - 4002 - 609 , // 133 - 8c - 2881 - 354 , // 134 - 91 - 1712 - 470 , // 135 - 92 - 2270 - 33 , // 136 - 401 - 150 - 65 , // 137 - 402 - 303 - 90 , // 138 - 403 - 428 - 859 , // 139 - 404 - 4248 - 104 , // 140 - 405 - 504 - 110 , // 141 - 406 - 525 - 118 , // 142 - 407 - 561 - 142 , // 143 - 408 - 671 - 240 , // 144 - 409 - 1161 - 263 , // 145 - 40a - 1272 - 294 , // 146 - 40b - 1425 - 316 , // 147 - 40c - 1529 - 378 , // 148 - 40d - 1827 - 387 , // 149 - 40e - 1862 - 403 , // 150 - 40f - 1931 - 406 , // 151 - 410 - 1943 - 414 , // 152 - 411 - 1991 - 454 , // 153 - 412 - 2186 - 569 , // 154 - 413 - 2707 - 554 , // 155 - 414 - 2641 - 606 , // 156 - 415 - 2866 - 615 , // 157 - 416 - 2904 - 638 , // 158 - 417 - 3043 - 643 , // 159 - 418 - 3062 - 651 , // 160 - 419 - 3098 - 383 , // 161 - 41a - 1846 - 688 , // 162 - 41b - 3286 - 710 , // 163 - 41c - 3389 - 737 , // 164 - 41d - 3565 - 761 , // 165 - 41e - 3675 - 776 , // 166 - 41f - 3734 - 797 , // 167 - 420 - 3854 - 397 , // 168 - 421 - 1910 - 794 , // 169 - 422 - 3842 - 59 , // 170 - 423 - 278 - 690 , // 171 - 424 - 3293 - 279 , // 172 - 425 - 1356 - 507 , // 173 - 426 - 2431 - 499 , // 174 - 427 - 2399 - 759 , // 175 - 428 - 3663 - 285 , // 176 - 429 - 1379 - 813 , // 177 - 42a - 3962 - 390 , // 178 - 42b - 1881 - 53 , // 179 - 42c - 250 - 281 , // 180 - 42d - 1363 - 385 , // 181 - 42e - 1854 - 524 , // 182 - 42f - 2503 - 733 , // 183 - 430 - 3548 - 778 , // 184 - 431 - 3741 - 771 , // 185 - 432 - 3715 - 811 , // 186 - 433 - 3955 - 826 , // 187 - 434 - 4022 - 863 , // 188 - 435 - 4279 - 6 , // 189 - 436 - 24 - 426 , // 190 - 437 - 2064 - 299 , // 191 - 438 - 1446 - 380 , // 192 - 439 - 1834 - 544 , // 193 - 43a - 2600 - 672 , // 194 - 43b - 3201 - 832 , // 195 - 43d - 4047 - 541 , // 196 - 43e - 2588 - 441 , // 197 - 43f - 2135 - 477 , // 198 - 440 - 2308 - 740 , // 199 - 441 - 3577 - 768 , // 200 - 442 - 3703 - 804 , // 201 - 443 - 3902 - 780 , // 202 - 444 - 3748 - 73 , // 203 - 445 - 343 - 602 , // 204 - 446 - 2849 - 365 , // 205 - 447 - 1756 - 595 , // 206 - 448 - 2813 - 748 , // 207 - 449 - 3612 - 753 , // 208 - 44a - 3634 - 451 , // 209 - 44b - 2174 - 526 , // 210 - 44c - 2510 - 44 , // 211 - 44d - 201 - 538 , // 212 - 44e - 2576 - 658 , // 213 - 44f - 3126 - 529 , // 214 - 450 - 2524 - 75 , // 215 - 451 - 350 - 108 , // 216 - 452 - 518 - 449 , // 217 - 453 - 2167 - 494 , // 218 - 454 - 2377 - 548 , // 219 - 455 - 2616 - 357 , // 220 - 456 - 1721 - 456 , // 221 - 457 - 2194 - 534 , // 222 - 458 - 2559 - 669 , // 223 - 459 - 3184 - 746 , // 224 - 45a - 3604 - 686 , // 225 - 45b - 3279 - 100 , // 226 - 45c - 484 - 410 , // 227 - 45d - 1962 - 12 , // 228 - 45e - 47 - 785 , // 229 - 45f - 3773 - 460 , // 230 - 460 - 2209 - 563 , // 231 - 461 - 2680 - 351 , // 232 - 462 - 1700 - 612 , // 233 - 463 - 2892 - 296 , // 234 - 464 - 1433 - 130 , // 235 - 465 - 622 - 67 , // 236 - 466 - 311 - 292 , // 237 - 467 - 1418 - 374 , // 238 - 468 - 1806 - 395 , // 239 - 469 - 1902 - 835 , // 240 - 46a - 4060 - 634 , // 241 - 46b - 3023 - 584 , // 242 - 46c - 2768 - 55 , // 243 - 46d - 262 - 483 , // 244 - 46e - 2332 - 445 , // 245 - 46f - 2151 - 399 , // 246 - 470 - 1917 - 458 , // 247 - 471 - 2202 - 592 , // 248 - 472 - 2801 - 764 , // 249 - 473 - 3687 - 359 , // 250 - 474 - 1728 - 376 , // 251 - 475 - 1819 - 479 , // 252 - 476 - 2315 - 708 , // 253 - 477 - 3382 - 401 , // 254 - 478 - 1924 - 604 , // 255 - 479 - 2857 - 42 , // 256 - 47a - 193 - 536 , // 257 - 47c - 2568 - 78 , // 258 - 47e - 362 - 792 , // 259 - 480 - 3835 - 522 , // 260 - 481 - 2496 - 590 , // 261 - 482 - 2794 - 102 , // 262 - 483 - 497 - 362 , // 263 - 484 - 1742 - 660 , // 264 - 485 - 3134 - 632 , // 265 - 486 - 3009 - 654 , // 266 - 487 - 3110 - 823 , // 267 - 488 - 4004 - 610 , // 268 - 48c - 2884 - 355 , // 269 - 491 - 1714 - 472 , // 270 - 492 - 2279 - 627 , // 271 - 501 - 2972 - 628 , // 272 - 5fe - 2980 - 22 , // 273 - 801 - 95 - 91 , // 274 - 803 - 433 - 844 , // 275 - 804 - 4110 - 117 , // 276 - 807 - 556 - 174 , // 277 - 809 - 831 - 267 , // 278 - 80a - 1299 - 302 , // 279 - 80c - 1459 - 405 , // 280 - 810 - 1938 - 566 , // 281 - 813 - 2692 - 575 , // 282 - 814 - 2733 - 623 , // 283 - 816 - 2944 - 642 , // 284 - 818 - 3057 - 650 , // 285 - 819 - 3093 - 722 , // 286 - 81a - 3480 - 736 , // 287 - 81d - 3560 - 796 , // 288 - 820 - 3849 - 51 , // 289 - 82c - 233 - 126 , // 290 - 82e - 605 - 770 , // 291 - 832 - 3710 - 673 , // 292 - 83b - 3206 - 353 , // 293 - 83c - 1707 - 540 , // 294 - 83e - 2583 - 802 , // 295 - 843 - 3885 - 72 , // 296 - 845 - 338 - 601 , // 297 - 846 - 2839 - 749 , // 298 - 849 - 3617 - 531 , // 299 - 850 - 2536 - 667 , // 300 - 859 - 3167 - 412 , // 301 - 85d - 1979 - 787 , // 302 - 85f - 3792 - 463 , // 303 - 860 - 2233 - 562 , // 304 - 861 - 2675 - 290 , // 305 - 867 - 1403 - 635 , // 306 - 86b - 3029 - 763 , // 307 - 873 - 3682 - 626 , // 308 - 901 - 2959 - 629 , // 309 - 9ff - 2989 - 19 , // 310 - c01 - 80 - 851 , // 311 - c04 - 4173 - 115 , // 312 - c07 - 546 - 151 , // 313 - c09 - 716 - 262 , // 314 - c0a - 1267 - 307 , // 315 - c0c - 1484 - 716 , // 316 - c1a - 3423 - 671 , // 317 - c3b - 3196 - 532 , // 318 - c50 - 2546 - 134 , // 319 - c51 - 638 - 636 , // 320 - c6b - 3035 - 27 , // 321 - 1001 - 120 - 856 , // 322 - 1004 - 4219 - 122 , // 323 - 1007 - 588 - 159 , // 324 - 1009 - 756 - 265 , // 325 - 100a - 1289 - 311 , // 326 - 100c - 1504 - 382 , // 327 - 101a - 1841 - 695 , // 328 - 103b - 3316 - 790 , // 329 - 105f - 3822 - 18 , // 330 - 1401 - 75 - 853 , // 331 - 1404 - 4190 - 121 , // 332 - 1407 - 583 - 213 , // 333 - 1409 - 1026 - 258 , // 334 - 140a - 1247 - 324 , // 335 - 140c - 1569 - 85 , // 336 - 141a - 402 - 696 , // 337 - 143b - 3322 - 28 , // 338 - 1801 - 125 - 184 , // 339 - 1809 - 881 - 269 , // 340 - 180a - 1309 - 326 , // 341 - 180c - 1579 - 721 , // 342 - 181a - 3470 - 692 , // 343 - 183b - 3301 - 39 , // 344 - 1c01 - 180 - 246 , // 345 - 1c09 - 1191 - 260 , // 346 - 1c0a - 1257 - 301 , // 347 - 1c0c - 1453 - 715 , // 348 - 1c1a - 3413 - 693 , // 349 - 1c3b - 3307 - 30 , // 350 - 2001 - 135 - 190 , // 351 - 2009 - 911 - 277 , // 352 - 200a - 1349 - 337 , // 353 - 200c - 1634 - 83 , // 354 - 201a - 385 - 700 , // 355 - 203b - 3340 - 40 , // 356 - 2401 - 185 - 145 , // 357 - 2409 - 684 - 257 , // 358 - 240a - 1242 - 308 , // 359 - 240c - 1489 - 724 , // 360 - 241a - 3500 - 698 , // 361 - 243b - 3331 - 37 , // 362 - 2801 - 170 - 158 , // 363 - 2809 - 751 - 270 , // 364 - 280a - 1314 - 340 , // 365 - 280c - 1649 - 718 , // 366 - 281a - 3443 - 23 , // 367 - 2c01 - 100 - 235 , // 368 - 2c09 - 1136 - 253 , // 369 - 2c0a - 1222 - 313 , // 370 - 2c0c - 1514 - 723 , // 371 - 2c1a - 3490 - 26 , // 372 - 3001 - 115 - 248 , // 373 - 3009 - 1201 - 261 , // 374 - 300a - 1262 - 312 , // 375 - 300c - 1509 - 717 , // 376 - 301a - 3433 - 25 , // 377 - 3401 - 110 - 215 , // 378 - 3409 - 1036 - 256 , // 379 - 340a - 1237 - 329 , // 380 - 340c - 1594 - 15 , // 381 - 3801 - 60 - 183 , // 382 - 3809 - 876 - 276 , // 383 - 380a - 1344 - 325 , // 384 - 380c - 1574 - 16 , // 385 - 3c01 - 65 - 182 , // 386 - 3c09 - 871 - 273 , // 387 - 3c0a - 1329 - 322 , // 388 - 3c0c - 1559 - 32 , // 389 - 4001 - 145 - 187 , // 390 - 4009 - 896 - 254 , // 391 - 400a - 1227 - 206 , // 392 - 4409 - 991 - 274 , // 393 - 440a - 1334 - 225 , // 394 - 4809 - 1086 - 266 , // 395 - 480a - 1294 - 268 , // 396 - 4c0a - 1304 - 272 , // 397 - 500a - 1324 - 275 , // 398 - 540a - 1339 - 252 , // 399 - 580a - 1216 - 259 , // 400 - 5c0a - 1252 - 82 , // 401 - 641a - 378 - 84 , // 402 - 681a - 395 - 714 , // 403 - 6c1a - 3406 - 720 , // 404 - 701a - 3463 - 697 , // 405 - 703b - 3328 - 50 , // 406 - 742c - 226 - 699 , // 407 - 743b - 3337 - 841 , // 408 - 7804 - 4096 - 574 , // 409 - 7814 - 2731 - 81 , // 410 - 781a - 376 - 52 , // 411 - 782c - 243 - 691 , // 412 - 783b - 3298 - 801 , // 413 - 7843 - 3878 - 528 , // 414 - 7850 - 2517 - 409 , // 415 - 785d - 1955 - 789 , // 416 - 785f - 3814 - 850 , // 417 - 7c04 - 4166 - 553 , // 418 - 7c14 - 2639 - 713 , // 419 - 7c1a - 3404 - 758 , // 420 - 7c28 - 3656 - 125 , // 421 - 7c2e - 602 - 694 , // 422 - 7c3b - 3313 - 803 , // 423 - 7c43 - 3895 - 600 , // 424 - 7c46 - 2832 - 530 , // 425 - 7c50 - 2529 - 666 , // 426 - 7c59 - 3160 - 99 , // 427 - 7c5c - 476 - 411 , // 428 - 7c5d - 1972 - 786 , // 429 - 7c5f - 3784 - 289 , // 430 - 7c67 - 1396 - 371 , // 431 - 7c68 - 1779 - 631 , // 432 - 7c86 - 3001 - 471 , // 433 - 7c92 - 2272 - 824 , // 434 - 1007f - 4009 - 119 , // 435 - 10407 - 566 - 388 , // 436 - 1040e - 1867 - 427 , // 437 - 10437 - 2069 - 846 , // 438 - 20804 - 4127 - 858 , // 439 - 21004 - 4236 - 855 , // 440 - 21404 - 4207 - 860 , // 441 - 30404 - 4253 - 861 , // 442 - 40404 - 4265 - 415 , // 443 - 40411 - 1996 - 852 , // 444 - 40c04 - 4178 - 854 , // 445 - 41404 - 4195 - 845 , // 446 - 50804 - 4115 - 857 // 447 - 51004 - 4224 - }; - - internal static string? LCIDToLocaleName(int culture) - { - int left = 0; - int right = s_lcids.Length - 1; - int index; - - Debug.Assert(s_lcids.Length == s_lcidToCultureNameIndices.Length); - - while (left <= right) - { - index = (right + left) / 2; - - if (culture == s_lcids[index]) - { - int indexToLocaleNamesIndices = s_lcidToCultureNameIndices[index]; - Debug.Assert(indexToLocaleNamesIndices < s_localeNamesIndices.Length - 1); - - return c_localeNames.Substring(s_localeNamesIndices[indexToLocaleNamesIndices], - s_localeNamesIndices[indexToLocaleNamesIndices + 1] - - s_localeNamesIndices[indexToLocaleNamesIndices]); - } - else if (culture < s_lcids[index]) - { - right = index - 1; - } - else - { - left = index + 1; - } - } - - return null; - } - - internal static int GetLocaleDataNumericPart(string cultureName, LocaleDataParts part) - { - int index = SearchCultureName(cultureName); - if (index < 0) - { - return -1; - } - - Debug.Assert((s_localeNamesIndices.Length-1 == (s_nameIndexToNumericData.Length/NUMERIC_LOCALE_DATA_COUNT_PER_ROW)) && - index < s_localeNamesIndices.Length); - - return s_nameIndexToNumericData[index * NUMERIC_LOCALE_DATA_COUNT_PER_ROW + (int) part]; - } - - internal static string? GetThreeLetterWindowsLanguageName(string cultureName) - { - int index = SearchCultureName(cultureName); - if (index < 0) - { - return null; - } - - Debug.Assert(s_localeNamesIndices.Length-1 == (c_threeLetterWindowsLanguageName.Length / 3)); - return c_threeLetterWindowsLanguageName.Substring(index * 3, 3); - } - - internal static string GetLocaleDataMappedCulture(string cultureName, LocaleDataParts part) - { - int indexToIndicesTable = GetLocaleDataNumericPart(cultureName, part); - if (indexToIndicesTable < 0) - { - return ""; // fallback to invariant - } - - Debug.Assert(indexToIndicesTable < s_localeNamesIndices.Length-1); - - return c_localeNames.Substring(s_localeNamesIndices[indexToIndicesTable], - s_localeNamesIndices[indexToIndicesTable+1] - s_localeNamesIndices[indexToIndicesTable]); - } - - internal static string GetSpecificCultureName(string cultureName) - { - return GetLocaleDataMappedCulture(cultureName, LocaleDataParts.SpecificLocaleIndex); - } - - internal static string GetConsoleUICulture(string cultureName) - { - return GetLocaleDataMappedCulture(cultureName, LocaleDataParts.ConsoleLocaleIndex); - } - - // SearchCultureName will binary search c_localeNames using s_localeNamesIndices. - // return index in s_localeNamesIndices, or -1 if it fail finding any match - private static int SearchCultureName(string name) - { - int left = 0; - int right = s_localeNamesIndices.Length - 2; - int index; - int result; - - Debug.Assert(s_localeNamesIndices[s_localeNamesIndices.Length - 1] == c_localeNames.Length); - - name = CultureData.AnsiToLower(name); - - // Binary search the array until we have only a couple of elements left and then - // just walk those elements. - while ((right - left) > 3) - { - index = ((right - left) / 2) + left; - - Debug.Assert(index < s_localeNamesIndices.Length - 1); - result = CompareOrdinal(name, c_localeNames, s_localeNamesIndices[index], s_localeNamesIndices[index + 1] - s_localeNamesIndices[index]); - if (result == 0) - { - return index; - } - else if (result < 0) - { - right = index; - } - else - { - left = index; - } - } - - // Walk the remaining elements (it'll be 3 or fewer). - for (; left <= right; left++) - { - Debug.Assert(left < s_localeNamesIndices.Length - 1); - if (CompareOrdinal(name, c_localeNames, s_localeNamesIndices[left], s_localeNamesIndices[left + 1] - s_localeNamesIndices[left]) == 0) - { - return (left); - } - } - - // couldn't find culture name - return -1; - } - - // optimized to avoid parameters checking - private static int CompareOrdinal(string s1, string s2, int index, int length) - { - int count = s1.Length; - if (count > length) - count = length; - - int i = 0; - while (i < count && s1[i] == s2[index + i]) - i++; - - if (i < count) - return (int)(s1[i] - s2[index + i]); - - return s1.Length - length; - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Icu.cs new file mode 100644 index 00000000000000..a897fcf6f1f023 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Icu.cs @@ -0,0 +1,168 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; + +namespace System.Globalization +{ + internal static partial class Normalization + { + private static unsafe bool IcuIsNormalized(string strInput, NormalizationForm normalizationForm) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + ValidateArguments(strInput, normalizationForm); + + int ret; + fixed (char* pInput = strInput) + { + ret = Interop.Globalization.IsNormalized(normalizationForm, pInput, strInput.Length); + } + + if (ret == -1) + { + throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); + } + + return ret == 1; + } + + private static unsafe string IcuNormalize(string strInput, NormalizationForm normalizationForm) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + ValidateArguments(strInput, normalizationForm); + + char[]? toReturn = null; + try + { + const int StackallocThreshold = 512; + + Span buffer = strInput.Length <= StackallocThreshold + ? stackalloc char[StackallocThreshold] + : (toReturn = ArrayPool.Shared.Rent(strInput.Length)); + + for (int attempt = 0; attempt < 2; attempt++) + { + int realLen; + fixed (char* pInput = strInput) + fixed (char* pDest = &MemoryMarshal.GetReference(buffer)) + { + realLen = Interop.Globalization.NormalizeString(normalizationForm, pInput, strInput.Length, pDest, buffer.Length); + } + + if (realLen == -1) + { + throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); + } + + if (realLen <= buffer.Length) + { + ReadOnlySpan result = buffer.Slice(0, realLen); + return result.SequenceEqual(strInput) + ? strInput + : new string(result); + } + + Debug.Assert(realLen > StackallocThreshold); + + if (attempt == 0) + { + if (toReturn != null) + { + // Clear toReturn first to ensure we don't return the same buffer twice + char[] temp = toReturn; + toReturn = null; + ArrayPool.Shared.Return(temp); + } + + buffer = toReturn = ArrayPool.Shared.Rent(realLen); + } + } + + throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); + } + finally + { + if (toReturn != null) + { + ArrayPool.Shared.Return(toReturn); + } + } + } + + // ----------------------------- + // ---- PAL layer ends here ---- + // ----------------------------- + + private static void ValidateArguments(string strInput, NormalizationForm normalizationForm) + { + Debug.Assert(strInput != null); + + if (normalizationForm != NormalizationForm.FormC && normalizationForm != NormalizationForm.FormD && + normalizationForm != NormalizationForm.FormKC && normalizationForm != NormalizationForm.FormKD) + { + throw new ArgumentException(SR.Argument_InvalidNormalizationForm, nameof(normalizationForm)); + } + + if (HasInvalidUnicodeSequence(strInput)) + { + throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); + } + } + + /// + /// ICU does not signal an error during normalization if the input string has invalid unicode, + /// unlike Windows (which uses the ERROR_NO_UNICODE_TRANSLATION error value to signal an error). + /// + /// We walk the string ourselves looking for these bad sequences so we can continue to throw + /// ArgumentException in these cases. + /// + private static bool HasInvalidUnicodeSequence(string s) + { + for (int i = 0; i < s.Length; i++) + { + char c = s[i]; + + if (c < '\ud800') + { + continue; + } + + if (c == '\uFFFE') + { + return true; + } + + // If we see low surrogate before a high one, the string is invalid. + if (char.IsLowSurrogate(c)) + { + return true; + } + + if (char.IsHighSurrogate(c)) + { + if (i + 1 >= s.Length || !char.IsLowSurrogate(s[i + 1])) + { + // A high surrogate at the end of the string or a high surrogate + // not followed by a low surrogate + return true; + } + else + { + i++; // consume the low surrogate. + continue; + } + } + } + + return false; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Nls.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Nls.cs new file mode 100644 index 00000000000000..e6c413580f8f8b --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Nls.cs @@ -0,0 +1,144 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; + +namespace System.Globalization +{ + internal static partial class Normalization + { + private static unsafe bool NlsIsNormalized(string strInput, NormalizationForm normalizationForm) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(strInput != null); + + // The only way to know if IsNormalizedString failed is through checking the Win32 last error + // IsNormalizedString pinvoke has SetLastError attribute property which will set the last error + // to 0 (ERROR_SUCCESS) before executing the calls. + Interop.BOOL result; + fixed (char* pInput = strInput) + { + result = Interop.Normaliz.IsNormalizedString(normalizationForm, pInput, strInput.Length); + } + + int lastError = Marshal.GetLastWin32Error(); + switch (lastError) + { + case Interop.Errors.ERROR_SUCCESS: + break; + + case Interop.Errors.ERROR_INVALID_PARAMETER: + case Interop.Errors.ERROR_NO_UNICODE_TRANSLATION: + if (normalizationForm != NormalizationForm.FormC && + normalizationForm != NormalizationForm.FormD && + normalizationForm != NormalizationForm.FormKC && + normalizationForm != NormalizationForm.FormKD) + { + throw new ArgumentException(SR.Argument_InvalidNormalizationForm, nameof(normalizationForm)); + } + + throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); + + case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY: + throw new OutOfMemoryException(); + + default: + throw new InvalidOperationException(SR.Format(SR.UnknownError_Num, lastError)); + } + + return result != Interop.BOOL.FALSE; + } + + private static unsafe string NlsNormalize(string strInput, NormalizationForm normalizationForm) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(strInput != null); + + if (strInput.Length == 0) + { + return string.Empty; + } + + char[]? toReturn = null; + try + { + const int StackallocThreshold = 512; + + Span buffer = strInput.Length <= StackallocThreshold + ? stackalloc char[StackallocThreshold] + : (toReturn = ArrayPool.Shared.Rent(strInput.Length)); + + while (true) + { + // we depend on Win32 last error when calling NormalizeString + // NormalizeString pinvoke has SetLastError attribute property which will set the last error + // to 0 (ERROR_SUCCESS) before executing the calls. + int realLength; + fixed (char* pInput = strInput) + fixed (char* pDest = &MemoryMarshal.GetReference(buffer)) + { + realLength = Interop.Normaliz.NormalizeString(normalizationForm, pInput, strInput.Length, pDest, buffer.Length); + } + int lastError = Marshal.GetLastWin32Error(); + + switch (lastError) + { + case Interop.Errors.ERROR_SUCCESS: + ReadOnlySpan result = buffer.Slice(0, realLength); + return result.SequenceEqual(strInput) + ? strInput + : new string(result); + + // Do appropriate stuff for the individual errors: + case Interop.Errors.ERROR_INSUFFICIENT_BUFFER: + realLength = Math.Abs(realLength); + Debug.Assert(realLength > buffer.Length, "Buffer overflow should have iLength > cBuffer.Length"); + if (toReturn != null) + { + // Clear toReturn first to ensure we don't return the same buffer twice + char[] temp = toReturn; + toReturn = null; + ArrayPool.Shared.Return(temp); + } + Debug.Assert(realLength > StackallocThreshold); + buffer = toReturn = ArrayPool.Shared.Rent(realLength); + continue; + + case Interop.Errors.ERROR_INVALID_PARAMETER: + case Interop.Errors.ERROR_NO_UNICODE_TRANSLATION: + if (normalizationForm != NormalizationForm.FormC && + normalizationForm != NormalizationForm.FormD && + normalizationForm != NormalizationForm.FormKC && + normalizationForm != NormalizationForm.FormKD) + { + throw new ArgumentException(SR.Argument_InvalidNormalizationForm, nameof(normalizationForm)); + } + + // Illegal code point or order found. Ie: FFFE or D800 D800, etc. + throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); + + case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY: + throw new OutOfMemoryException(); + + default: + // We shouldn't get here... + throw new InvalidOperationException(SR.Format(SR.UnknownError_Num, lastError)); + } + } + } + finally + { + if (toReturn != null) + { + ArrayPool.Shared.Return(toReturn); + } + } + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Unix.cs deleted file mode 100644 index 0a95d018f0ab03..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Unix.cs +++ /dev/null @@ -1,176 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Buffers; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Text; - -namespace System.Globalization -{ - internal static partial class Normalization - { - internal static unsafe bool IsNormalized(string strInput, NormalizationForm normalizationForm) - { - if (GlobalizationMode.Invariant) - { - // In Invariant mode we assume all characters are normalized. - // This is because we don't support any linguistic operation on the strings - return true; - } - - ValidateArguments(strInput, normalizationForm); - - int ret; - fixed (char* pInput = strInput) - { - ret = Interop.Globalization.IsNormalized(normalizationForm, pInput, strInput.Length); - } - - if (ret == -1) - { - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - } - - return ret == 1; - } - - internal static unsafe string Normalize(string strInput, NormalizationForm normalizationForm) - { - if (GlobalizationMode.Invariant) - { - // In Invariant mode we assume all characters are normalized. - // This is because we don't support any linguistic operation on the strings - return strInput; - } - - ValidateArguments(strInput, normalizationForm); - - char[]? toReturn = null; - try - { - const int StackallocThreshold = 512; - - Span buffer = strInput.Length <= StackallocThreshold - ? stackalloc char[StackallocThreshold] - : (toReturn = ArrayPool.Shared.Rent(strInput.Length)); - - for (int attempt = 0; attempt < 2; attempt++) - { - int realLen; - fixed (char* pInput = strInput) - fixed (char* pDest = &MemoryMarshal.GetReference(buffer)) - { - realLen = Interop.Globalization.NormalizeString(normalizationForm, pInput, strInput.Length, pDest, buffer.Length); - } - - if (realLen == -1) - { - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - } - - if (realLen <= buffer.Length) - { - ReadOnlySpan result = buffer.Slice(0, realLen); - return result.SequenceEqual(strInput) - ? strInput - : new string(result); - } - - Debug.Assert(realLen > StackallocThreshold); - - if (attempt == 0) - { - if (toReturn != null) - { - // Clear toReturn first to ensure we don't return the same buffer twice - char[] temp = toReturn; - toReturn = null; - ArrayPool.Shared.Return(temp); - } - - buffer = toReturn = ArrayPool.Shared.Rent(realLen); - } - } - - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - } - finally - { - if (toReturn != null) - { - ArrayPool.Shared.Return(toReturn); - } - } - } - - // ----------------------------- - // ---- PAL layer ends here ---- - // ----------------------------- - - private static void ValidateArguments(string strInput, NormalizationForm normalizationForm) - { - Debug.Assert(strInput != null); - - if (normalizationForm != NormalizationForm.FormC && normalizationForm != NormalizationForm.FormD && - normalizationForm != NormalizationForm.FormKC && normalizationForm != NormalizationForm.FormKD) - { - throw new ArgumentException(SR.Argument_InvalidNormalizationForm, nameof(normalizationForm)); - } - - if (HasInvalidUnicodeSequence(strInput)) - { - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - } - } - - /// - /// ICU does not signal an error during normalization if the input string has invalid unicode, - /// unlike Windows (which uses the ERROR_NO_UNICODE_TRANSLATION error value to signal an error). - /// - /// We walk the string ourselves looking for these bad sequences so we can continue to throw - /// ArgumentException in these cases. - /// - private static bool HasInvalidUnicodeSequence(string s) - { - for (int i = 0; i < s.Length; i++) - { - char c = s[i]; - - if (c < '\ud800') - { - continue; - } - - if (c == '\uFFFE') - { - return true; - } - - // If we see low surrogate before a high one, the string is invalid. - if (char.IsLowSurrogate(c)) - { - return true; - } - - if (char.IsHighSurrogate(c)) - { - if (i + 1 >= s.Length || !char.IsLowSurrogate(s[i + 1])) - { - // A high surrogate at the end of the string or a high surrogate - // not followed by a low surrogate - return true; - } - else - { - i++; // consume the low surrogate. - continue; - } - } - } - - return false; - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Windows.cs deleted file mode 100644 index 65e459a13a3e92..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.Windows.cs +++ /dev/null @@ -1,154 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Buffers; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Text; - -namespace System.Globalization -{ - internal static partial class Normalization - { - internal static unsafe bool IsNormalized(string strInput, NormalizationForm normalizationForm) - { - if (GlobalizationMode.Invariant) - { - // In Invariant mode we assume all characters are normalized. - // This is because we don't support any linguistic operation on the strings - return true; - } - - Debug.Assert(strInput != null); - - // The only way to know if IsNormalizedString failed is through checking the Win32 last error - // IsNormalizedString pinvoke has SetLastError attribute property which will set the last error - // to 0 (ERROR_SUCCESS) before executing the calls. - Interop.BOOL result; - fixed (char* pInput = strInput) - { - result = Interop.Normaliz.IsNormalizedString(normalizationForm, pInput, strInput.Length); - } - - int lastError = Marshal.GetLastWin32Error(); - switch (lastError) - { - case Interop.Errors.ERROR_SUCCESS: - break; - - case Interop.Errors.ERROR_INVALID_PARAMETER: - case Interop.Errors.ERROR_NO_UNICODE_TRANSLATION: - if (normalizationForm != NormalizationForm.FormC && - normalizationForm != NormalizationForm.FormD && - normalizationForm != NormalizationForm.FormKC && - normalizationForm != NormalizationForm.FormKD) - { - throw new ArgumentException(SR.Argument_InvalidNormalizationForm, nameof(normalizationForm)); - } - - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - - case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY: - throw new OutOfMemoryException(); - - default: - throw new InvalidOperationException(SR.Format(SR.UnknownError_Num, lastError)); - } - - return result != Interop.BOOL.FALSE; - } - - internal static unsafe string Normalize(string strInput, NormalizationForm normalizationForm) - { - if (GlobalizationMode.Invariant) - { - // In Invariant mode we assume all characters are normalized. - // This is because we don't support any linguistic operation on the strings - return strInput; - } - - Debug.Assert(strInput != null); - - if (strInput.Length == 0) - { - return string.Empty; - } - - char[]? toReturn = null; - try - { - const int StackallocThreshold = 512; - - Span buffer = strInput.Length <= StackallocThreshold - ? stackalloc char[StackallocThreshold] - : (toReturn = ArrayPool.Shared.Rent(strInput.Length)); - - while (true) - { - // we depend on Win32 last error when calling NormalizeString - // NormalizeString pinvoke has SetLastError attribute property which will set the last error - // to 0 (ERROR_SUCCESS) before executing the calls. - int realLength; - fixed (char* pInput = strInput) - fixed (char* pDest = &MemoryMarshal.GetReference(buffer)) - { - realLength = Interop.Normaliz.NormalizeString(normalizationForm, pInput, strInput.Length, pDest, buffer.Length); - } - int lastError = Marshal.GetLastWin32Error(); - - switch (lastError) - { - case Interop.Errors.ERROR_SUCCESS: - ReadOnlySpan result = buffer.Slice(0, realLength); - return result.SequenceEqual(strInput) - ? strInput - : new string(result); - - // Do appropriate stuff for the individual errors: - case Interop.Errors.ERROR_INSUFFICIENT_BUFFER: - realLength = Math.Abs(realLength); - Debug.Assert(realLength > buffer.Length, "Buffer overflow should have iLength > cBuffer.Length"); - if (toReturn != null) - { - // Clear toReturn first to ensure we don't return the same buffer twice - char[] temp = toReturn; - toReturn = null; - ArrayPool.Shared.Return(temp); - } - Debug.Assert(realLength > StackallocThreshold); - buffer = toReturn = ArrayPool.Shared.Rent(realLength); - continue; - - case Interop.Errors.ERROR_INVALID_PARAMETER: - case Interop.Errors.ERROR_NO_UNICODE_TRANSLATION: - if (normalizationForm != NormalizationForm.FormC && - normalizationForm != NormalizationForm.FormD && - normalizationForm != NormalizationForm.FormKC && - normalizationForm != NormalizationForm.FormKD) - { - throw new ArgumentException(SR.Argument_InvalidNormalizationForm, nameof(normalizationForm)); - } - - // Illegal code point or order found. Ie: FFFE or D800 D800, etc. - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - - case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY: - throw new OutOfMemoryException(); - - default: - // We shouldn't get here... - throw new InvalidOperationException(SR.Format(SR.UnknownError_Num, lastError)); - } - } - } - finally - { - if (toReturn != null) - { - ArrayPool.Shared.Return(toReturn); - } - } - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.cs new file mode 100644 index 00000000000000..d71b3380a5463f --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/Normalization.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Text; + +namespace System.Globalization +{ + internal static partial class Normalization + { + internal static bool IsNormalized(string strInput, NormalizationForm normalizationForm) + { + if (GlobalizationMode.Invariant) + { + // In Invariant mode we assume all characters are normalized. + // This is because we don't support any linguistic operation on the strings + return true; + } + + return GlobalizationMode.UseNls ? + NlsIsNormalized(strInput, normalizationForm) : + IcuIsNormalized(strInput, normalizationForm); + } + + internal static string Normalize(string strInput, NormalizationForm normalizationForm) + { + if (GlobalizationMode.Invariant) + { + // In Invariant mode we assume all characters are normalized. + // This is because we don't support any linguistic operation on the strings + return strInput; + } + + return GlobalizationMode.UseNls ? + NlsNormalize(strInput, normalizationForm) : + IcuNormalize(strInput, normalizationForm); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/StringInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/StringInfo.cs index 2e8cf088cba05d..6fa07d94dee635 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/StringInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/StringInfo.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Text.Unicode; namespace System.Globalization @@ -15,7 +16,7 @@ namespace System.Globalization /// public class StringInfo { - private string _str = null!; // initialized in helper called by ctors + private string _str; private int[]? _indexes; @@ -56,6 +57,7 @@ private int[]? Indexes public string String { get => _str; + [MemberNotNull(nameof(_str))] set { _str = value ?? throw new ArgumentNullException(nameof(value)); diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Icu.cs new file mode 100644 index 00000000000000..d499c408530dde --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Icu.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +namespace System.Globalization +{ + public partial class TextInfo + { + private Tristate _needsTurkishCasing = Tristate.NotInitialized; + + // ----------------------------- + // ---- PAL layer ends here ---- + // ----------------------------- + + private static bool NeedsTurkishCasing(string localeName) + { + Debug.Assert(localeName != null); + + return CultureInfo.GetCultureInfo(localeName).CompareInfo.Compare("\u0131", "I", CompareOptions.IgnoreCase) == 0; + } + + private bool IsInvariant { get { return _cultureName.Length == 0; } } + + internal unsafe void IcuChangeCase(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + if (IsInvariant) + { + Interop.Globalization.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); + } + else + { + if (_needsTurkishCasing == Tristate.NotInitialized) + { + _needsTurkishCasing = NeedsTurkishCasing(_textInfoName) ? Tristate.True : Tristate.False; + } + if (_needsTurkishCasing == Tristate.True) + { + Interop.Globalization.ChangeCaseTurkish(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); + } + else + { + Interop.Globalization.ChangeCase(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); + } + } + } + + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Nls.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Nls.cs new file mode 100644 index 00000000000000..b49552f2062aea --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Nls.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +namespace System.Globalization +{ + public partial class TextInfo + { + private unsafe void NlsChangeCase(char* pSource, int pSourceLen, char* pResult, int pResultLen, bool toUpper) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(pSource != null); + Debug.Assert(pResult != null); + Debug.Assert(pSourceLen >= 0); + Debug.Assert(pResultLen >= 0); + Debug.Assert(pSourceLen <= pResultLen); + + // Check for Invariant to avoid A/V in LCMapStringEx + uint linguisticCasing = IsInvariantLocale(_textInfoName) ? 0 : LCMAP_LINGUISTIC_CASING; + + int ret = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _textInfoName, + linguisticCasing | (toUpper ? LCMAP_UPPERCASE : LCMAP_LOWERCASE), + pSource, + pSourceLen, + pResult, + pSourceLen, + null, + null, + _sortHandle); + if (ret == 0) + { + throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); + } + + Debug.Assert(ret == pSourceLen, "Expected getting the same length of the original string"); + } + + // PAL Ends here + + private IntPtr _sortHandle; + + private const uint LCMAP_LINGUISTIC_CASING = 0x01000000; + private const uint LCMAP_LOWERCASE = 0x00000100; + private const uint LCMAP_UPPERCASE = 0x00000200; + + private static bool IsInvariantLocale(string localeName) => localeName == ""; + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Unix.cs deleted file mode 100644 index ef6cff420b9d23..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Unix.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; - -namespace System.Globalization -{ - public partial class TextInfo - { - private Tristate _needsTurkishCasing = Tristate.NotInitialized; - - private void FinishInitialization() { } - - // ----------------------------- - // ---- PAL layer ends here ---- - // ----------------------------- - - private static bool NeedsTurkishCasing(string localeName) - { - Debug.Assert(localeName != null); - - return CultureInfo.GetCultureInfo(localeName).CompareInfo.Compare("\u0131", "I", CompareOptions.IgnoreCase) == 0; - } - - private bool IsInvariant { get { return _cultureName.Length == 0; } } - - internal unsafe void ChangeCase(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper) - { - Debug.Assert(!GlobalizationMode.Invariant); - - if (IsInvariant) - { - Interop.Globalization.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); - } - else - { - if (_needsTurkishCasing == Tristate.NotInitialized) - { - _needsTurkishCasing = NeedsTurkishCasing(_textInfoName) ? Tristate.True : Tristate.False; - } - if (_needsTurkishCasing == Tristate.True) - { - Interop.Globalization.ChangeCaseTurkish(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); - } - else - { - Interop.Globalization.ChangeCase(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); - } - } - } - - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Windows.cs deleted file mode 100644 index 948644769da095..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.Windows.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; - -namespace System.Globalization -{ - public partial class TextInfo - { - private unsafe void FinishInitialization() - { - _sortHandle = CompareInfo.GetSortHandle(_textInfoName); - } - - private unsafe void ChangeCase(char* pSource, int pSourceLen, char* pResult, int pResultLen, bool toUpper) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(pSource != null); - Debug.Assert(pResult != null); - Debug.Assert(pSourceLen >= 0); - Debug.Assert(pResultLen >= 0); - Debug.Assert(pSourceLen <= pResultLen); - - // Check for Invariant to avoid A/V in LCMapStringEx - uint linguisticCasing = IsInvariantLocale(_textInfoName) ? 0 : LCMAP_LINGUISTIC_CASING; - - int ret = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _textInfoName, - linguisticCasing | (toUpper ? LCMAP_UPPERCASE : LCMAP_LOWERCASE), - pSource, - pSourceLen, - pResult, - pSourceLen, - null, - null, - _sortHandle); - if (ret == 0) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - - Debug.Assert(ret == pSourceLen, "Expected getting the same length of the original string"); - } - - // PAL Ends here - - private IntPtr _sortHandle; - - private const uint LCMAP_LINGUISTIC_CASING = 0x01000000; - private const uint LCMAP_LOWERCASE = 0x00000100; - private const uint LCMAP_UPPERCASE = 0x00000200; - - private static bool IsInvariantLocale(string localeName) => localeName == ""; - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs index 7e8d1ff673e39c..0481c684cd8a98 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs @@ -10,13 +10,6 @@ using System.Text.Unicode; using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else // TARGET_64BIT -using nuint = System.UInt32; -#endif // TARGET_64BIT - namespace System.Globalization { /// @@ -54,7 +47,10 @@ internal TextInfo(CultureData cultureData) _cultureName = _cultureData.CultureName; _textInfoName = _cultureData.TextInfoName; - FinishInitialization(); + if (GlobalizationMode.UseNls) + { + _sortHandle = CompareInfo.NlsGetSortHandle(_textInfoName); + } } private TextInfo(CultureData cultureData, bool readOnly) @@ -148,7 +144,7 @@ public string ListSeparator /// public char ToLower(char c) { - if (GlobalizationMode.Invariant || (IsAscii(c) && IsAsciiCasingSameAsInvariant)) + if (GlobalizationMode.Invariant || (UnicodeUtility.IsAsciiCodePoint(c) && IsAsciiCasingSameAsInvariant)) { return ToLowerAsciiInvariant(c); } @@ -156,6 +152,16 @@ public char ToLower(char c) return ChangeCase(c, toUpper: false); } + internal static char ToLowerInvariant(char c) + { + if (GlobalizationMode.Invariant || UnicodeUtility.IsAsciiCodePoint(c)) + { + return ToLowerAsciiInvariant(c); + } + + return Invariant.ChangeCase(c, toUpper: false); + } + public string ToLower(string str) { if (str == null) @@ -176,7 +182,7 @@ private unsafe char ChangeCase(char c, bool toUpper) Debug.Assert(!GlobalizationMode.Invariant); char dst = default; - ChangeCase(&c, 1, &dst, 1, toUpper); + ChangeCaseCore(&c, 1, &dst, 1, toUpper); return dst; } @@ -301,7 +307,7 @@ private unsafe void ChangeCaseCommon(ref char source, ref char dest // has a case conversion that's different from the invariant culture, even for ASCII data (e.g., tr-TR converts // 'i' (U+0069) to Latin Capital Letter I With Dot Above (U+0130)). - ChangeCase(pSource + currIdx, charCount, pDestination + currIdx, charCount, toUpper); + ChangeCaseCore(pSource + currIdx, charCount, pDestination + currIdx, charCount, toUpper); } Return: @@ -406,7 +412,7 @@ private unsafe string ChangeCaseCommon(string source) where TConver // and run the culture-aware logic over the remainder of the data fixed (char* pResult = result) { - ChangeCase(pSource + currIdx, source.Length - (int)currIdx, pResult + currIdx, result.Length - (int)currIdx, toUpper); + ChangeCaseCore(pSource + currIdx, source.Length - (int)currIdx, pResult + currIdx, result.Length - (int)currIdx, toUpper); } return result; } @@ -525,11 +531,13 @@ internal static void ToUpperAsciiInvariant(ReadOnlySpan source, Span } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static char ToLowerAsciiInvariant(char c) { - if ((uint)(c - 'A') <= (uint)('Z' - 'A')) + if (UnicodeUtility.IsInRangeInclusive(c, 'A', 'Z')) { - c = (char)(c | 0x20); + // on x86, extending BYTE -> DWORD is more efficient than WORD -> DWORD + c = (char)(byte)(c | 0x20); } return c; } @@ -540,7 +548,7 @@ private static char ToLowerAsciiInvariant(char c) /// public char ToUpper(char c) { - if (GlobalizationMode.Invariant || (IsAscii(c) && IsAsciiCasingSameAsInvariant)) + if (GlobalizationMode.Invariant || (UnicodeUtility.IsAsciiCodePoint(c) && IsAsciiCasingSameAsInvariant)) { return ToUpperAsciiInvariant(c); } @@ -548,6 +556,16 @@ public char ToUpper(char c) return ChangeCase(c, toUpper: true); } + internal static char ToUpperInvariant(char c) + { + if (GlobalizationMode.Invariant || UnicodeUtility.IsAsciiCodePoint(c)) + { + return ToUpperAsciiInvariant(c); + } + + return Invariant.ChangeCase(c, toUpper: true); + } + public string ToUpper(string str) { if (str == null) @@ -563,17 +581,16 @@ public string ToUpper(string str) return ChangeCaseCommon(str); } - internal static char ToUpperAsciiInvariant(char c) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static char ToUpperAsciiInvariant(char c) { - if ((uint)(c - 'a') <= (uint)('z' - 'a')) + if (UnicodeUtility.IsInRangeInclusive(c, 'a', 'z')) { - c = (char)(c & ~0x20); + c = (char)(c & 0x5F); // = low 7 bits of ~0x20 } return c; } - private static bool IsAscii(char c) => c < 0x80; - private bool IsAsciiCasingSameAsInvariant { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -815,6 +832,18 @@ private int AddTitlecaseLetter(ref StringBuilder result, ref string input, int i return inputIndex; } + private unsafe void ChangeCaseCore(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper) + { + if (GlobalizationMode.UseNls) + { + NlsChangeCase(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); + } + else + { + IcuChangeCase(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); + } + } + // Used in ToTitleCase(): // When we find a starting letter, the following array decides if a category should be // considered as word seprator or not. diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanParse.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanParse.cs index 9793f5d1feb5d1..0bc27f555106b8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanParse.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanParse.cs @@ -652,7 +652,7 @@ internal static bool TryParseExact(ReadOnlySpan input, ReadOnlySpan return false; } - internal static TimeSpan ParseExactMultiple(ReadOnlySpan input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles) + internal static TimeSpan ParseExactMultiple(ReadOnlySpan input, string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles) { var parseResult = new TimeSpanResult(throwOnFailure: true, originalTimeSpanString: input); bool success = TryParseExactMultipleTimeSpan(input, formats, formatProvider, styles, ref parseResult); @@ -660,7 +660,7 @@ internal static TimeSpan ParseExactMultiple(ReadOnlySpan input, string[] f return parseResult.parsedTimeSpan; } - internal static bool TryParseExactMultiple(ReadOnlySpan input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) + internal static bool TryParseExactMultiple(ReadOnlySpan input, string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { var parseResult = new TimeSpanResult(throwOnFailure: false, originalTimeSpanString: input); @@ -1657,7 +1657,7 @@ internal void SkipBlanks() } /// Common private ParseExactMultiple method called by both ParseExactMultiple and TryParseExactMultiple. - private static bool TryParseExactMultipleTimeSpan(ReadOnlySpan input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles, ref TimeSpanResult result) + private static bool TryParseExactMultipleTimeSpan(ReadOnlySpan input, string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles, ref TimeSpanResult result) { if (formats == null) { @@ -1678,7 +1678,9 @@ private static bool TryParseExactMultipleTimeSpan(ReadOnlySpan input, stri // one of the formats. for (int i = 0; i < formats.Length; i++) { - if (formats[i] == null || formats[i].Length == 0) + string? format = formats[i]; + + if (string.IsNullOrEmpty(format)) { return result.SetBadFormatSpecifierFailure(); } @@ -1686,7 +1688,7 @@ private static bool TryParseExactMultipleTimeSpan(ReadOnlySpan input, stri // Create a new non-throwing result each time to ensure the runs are independent. TimeSpanResult innerResult = new TimeSpanResult(throwOnFailure: false, originalTimeSpanString: input); - if (TryParseExactTimeSpan(input, formats[i], formatProvider, styles, ref innerResult)) + if (TryParseExactTimeSpan(input, format, formatProvider, styles, ref innerResult)) { result.parsedTimeSpan = innerResult.parsedTimeSpan; return true; diff --git a/src/libraries/System.Private.CoreLib/src/System/Guid.cs b/src/libraries/System.Private.CoreLib/src/System/Guid.cs index 5281e08c896403..47838475459d40 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Guid.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Guid.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -196,7 +197,7 @@ public static Guid Parse(ReadOnlySpan input) return result._parsedGuid; } - public static bool TryParse(string? input, out Guid result) + public static bool TryParse([NotNullWhen(true)] string? input, out Guid result) { if (input == null) { @@ -251,7 +252,7 @@ public static Guid ParseExact(ReadOnlySpan input, ReadOnlySpan forma return result._parsedGuid; } - public static bool TryParseExact(string? input, string? format, out Guid result) + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string? format, out Guid result) { if (input == null) { diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs index cf8e495459395f..8b9a53f3952fcc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs @@ -306,7 +306,10 @@ public virtual string ReadString() return new string(_charBuffer, 0, charsRead); } - sb ??= StringBuilderCache.Acquire(stringLength); // Actual string length in chars may be smaller. + // Since we could be reading from an untrusted data source, limit the initial size of the + // StringBuilder instance we're about to get or create. It'll expand automatically as needed. + + sb ??= StringBuilderCache.Acquire(Math.Min(stringLength, StringBuilderCache.MaxBuilderSize)); // Actual string length in chars may be smaller. sb.Append(_charBuffer, 0, charsRead); currPos += n; } while (currPos < stringLength); @@ -584,28 +587,88 @@ protected virtual void FillBuffer(int numBytes) } while (bytesRead < numBytes); } - protected internal int Read7BitEncodedInt() + public int Read7BitEncodedInt() { - // Read out an Int32 7 bits at a time. The high bit + // Unlike writing, we can't delegate to the 64-bit read on + // 64-bit platforms. The reason for this is that we want to + // stop consuming bytes if we encounter an integer overflow. + + uint result = 0; + byte byteReadJustNow; + + // Read the integer 7 bits at a time. The high bit // of the byte when on means to continue reading more bytes. - int count = 0; - int shift = 0; - byte b; - do + // + // There are two failure cases: we've read more than 5 bytes, + // or the fifth byte is about to cause integer overflow. + // This means that we can read the first 4 bytes without + // worrying about integer overflow. + + const int MaxBytesWithoutOverflow = 4; + for (int shift = 0; shift < MaxBytesWithoutOverflow * 7; shift += 7) { - // Check for a corrupted stream. Read a max of 5 bytes. - // In a future version, add a DataFormatException. - if (shift == 5 * 7) // 5 bytes max per Int32, shift += 7 + // ReadByte handles end of stream cases for us. + byteReadJustNow = ReadByte(); + result |= (byteReadJustNow & 0x7Fu) << shift; + + if (byteReadJustNow <= 0x7Fu) { - throw new FormatException(SR.Format_Bad7BitInt32); + return (int)result; // early exit } + } + + // Read the 5th byte. Since we already read 28 bits, + // the value of this byte must fit within 4 bits (32 - 28), + // and it must not have the high bit set. + + byteReadJustNow = ReadByte(); + if (byteReadJustNow > 0b_1111u) + { + throw new FormatException(SR.Format_Bad7BitInt); + } + + result |= (uint)byteReadJustNow << (MaxBytesWithoutOverflow * 7); + return (int)result; + } + public long Read7BitEncodedInt64() + { + ulong result = 0; + byte byteReadJustNow; + + // Read the integer 7 bits at a time. The high bit + // of the byte when on means to continue reading more bytes. + // + // There are two failure cases: we've read more than 10 bytes, + // or the tenth byte is about to cause integer overflow. + // This means that we can read the first 9 bytes without + // worrying about integer overflow. + + const int MaxBytesWithoutOverflow = 9; + for (int shift = 0; shift < MaxBytesWithoutOverflow * 7; shift += 7) + { // ReadByte handles end of stream cases for us. - b = ReadByte(); - count |= (b & 0x7F) << shift; - shift += 7; - } while ((b & 0x80) != 0); - return count; + byteReadJustNow = ReadByte(); + result |= (byteReadJustNow & 0x7Ful) << shift; + + if (byteReadJustNow <= 0x7Fu) + { + return (long)result; // early exit + } + } + + // Read the 10th byte. Since we already read 63 bits, + // the value of this byte must fit within 1 bit (64 - 63), + // and it must not have the high bit set. + + byteReadJustNow = ReadByte(); + if (byteReadJustNow > 0b_1u) + { + throw new FormatException(SR.Format_Bad7BitInt); + } + + result |= (ulong)byteReadJustNow << (MaxBytesWithoutOverflow * 7); + return (long)result; } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs index fde451656a5dee..b4393da162f445 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs @@ -394,7 +394,7 @@ public virtual unsafe void Write(string value) { if (charStart < 0 || charCount < 0 || charStart > value.Length - charCount) { - throw new ArgumentOutOfRangeException(nameof(charCount)); + throw new ArgumentOutOfRangeException(nameof(value)); } fixed (char* pChars = value) { @@ -453,17 +453,42 @@ public virtual void Write(ReadOnlySpan chars) } } - protected void Write7BitEncodedInt(int value) + public void Write7BitEncodedInt(int value) { - // Write out an int 7 bits at a time. The high bit of the byte, + uint uValue = (uint)value; + + // Write out an int 7 bits at a time. The high bit of the byte, + // when on, tells reader to continue reading more bytes. + // + // Using the constants 0x7F and ~0x7F below offers smaller + // codegen than using the constant 0x80. + + while (uValue > 0x7Fu) + { + Write((byte)(uValue | ~0x7Fu)); + uValue >>= 7; + } + + Write((byte)uValue); + } + + public void Write7BitEncodedInt64(long value) + { + ulong uValue = (ulong)value; + + // Write out an int 7 bits at a time. The high bit of the byte, // when on, tells reader to continue reading more bytes. - uint v = (uint)value; // support negative numbers - while (v >= 0x80) + // + // Using the constants 0x7F and ~0x7F below offers smaller + // codegen than using the constant 0x80. + + while (uValue > 0x7Fu) { - Write((byte)(v | 0x80)); - v >>= 7; + Write((byte)((uint)uValue | ~0x7Fu)); + uValue >>= 7; } - Write((byte)v); + + Write((byte)uValue); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileStream.OSX.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileStream.Lock.OSX.cs similarity index 100% rename from src/libraries/System.Private.CoreLib/src/System/IO/FileStream.OSX.cs rename to src/libraries/System.Private.CoreLib/src/System/IO/FileStream.Lock.OSX.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileStream.Linux.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileStream.Lock.Unix.cs similarity index 100% rename from src/libraries/System.Private.CoreLib/src/System/IO/FileStream.Linux.cs rename to src/libraries/System.Private.CoreLib/src/System/IO/FileStream.Lock.Unix.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.cs index 25cec9463f3f20..752eca83063947 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.cs @@ -122,13 +122,12 @@ public static bool IsPathRooted(ReadOnlySpan path) public static string? GetPathRoot(string? path) { if (PathInternal.IsEffectivelyEmpty(path)) return null; - return IsPathRooted(path) ? PathInternal.DirectorySeparatorCharAsString : string.Empty; } public static ReadOnlySpan GetPathRoot(ReadOnlySpan path) { - return PathInternal.IsEffectivelyEmpty(path) && IsPathRooted(path) ? PathInternal.DirectorySeparatorCharAsString.AsSpan() : ReadOnlySpan.Empty; + return IsPathRooted(path) ? PathInternal.DirectorySeparatorCharAsString.AsSpan() : ReadOnlySpan.Empty; } /// Gets whether the system is case-sensitive. diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryAccessor.cs b/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryAccessor.cs index a2c6bd1764fe01..409e62b87609bb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryAccessor.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryAccessor.cs @@ -23,7 +23,7 @@ namespace System.IO /// this gives better throughput; benchmarks showed about 12-15% better. public class UnmanagedMemoryAccessor : IDisposable { - private SafeBuffer _buffer = null!; // initialized in helper called by ctor + private SafeBuffer _buffer = null!; // initialized in helper called by ctor, but also not initialized by protected ctor private long _offset; private long _capacity; private FileAccess _access; diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryStream.cs b/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryStream.cs index ecdb454203bf4e..20fc078c954674 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryStream.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/UnmanagedMemoryStream.cs @@ -8,13 +8,6 @@ using System.Threading; using System.Threading.Tasks; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System.IO { /* @@ -415,7 +408,7 @@ public unsafe byte* PositionPointer throw new IOException(SR.IO_SeekBeforeBegin); long newPosition = (long)value - (long)_mem; if (newPosition < 0) - throw new ArgumentOutOfRangeException("offset", SR.ArgumentOutOfRange_UnmanagedMemStreamLength); + throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_UnmanagedMemStreamLength); Interlocked.Exchange(ref _position, newPosition); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Int16.cs b/src/libraries/System.Private.CoreLib/src/System/Int16.cs index 8a45dbee02ba87..379fa89993039b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int16.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -141,7 +142,7 @@ private static short Parse(ReadOnlySpan s, NumberStyles style, NumberForma return (short)i; } - public static bool TryParse(string? s, out short result) + public static bool TryParse([NotNullWhen(true)] string? s, out short result) { if (s == null) { @@ -157,7 +158,7 @@ public static bool TryParse(ReadOnlySpan s, out short result) return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out short result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out short result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/libraries/System.Private.CoreLib/src/System/Int32.cs b/src/libraries/System.Private.CoreLib/src/System/Int32.cs index 9ecd926998bc91..91e6218888afb6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int32.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -145,7 +146,7 @@ public static int Parse(ReadOnlySpan s, NumberStyles style = NumberStyles. // Parses an integer from a String. Returns false rather // than throwing exceptin if input is invalid // - public static bool TryParse(string? s, out int result) + public static bool TryParse([NotNullWhen(true)] string? s, out int result) { if (s == null) { @@ -164,7 +165,7 @@ public static bool TryParse(ReadOnlySpan s, out int result) // Parses an integer from a String in the given style. Returns false rather // than throwing exceptin if input is invalid // - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out int result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out int result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/libraries/System.Private.CoreLib/src/System/Int64.cs b/src/libraries/System.Private.CoreLib/src/System/Int64.cs index d4d22e070ca0ca..b0374b96b6f459 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int64.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -135,7 +136,7 @@ public static long Parse(ReadOnlySpan s, NumberStyles style = NumberStyles return Number.ParseInt64(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse(string? s, out long result) + public static bool TryParse([NotNullWhen(true)] string? s, out long result) { if (s == null) { @@ -151,7 +152,7 @@ public static bool TryParse(ReadOnlySpan s, out long result) return Number.TryParseInt64IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out long result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out long result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs b/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs index e14dbc752f6fff..720da614f236e2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs @@ -4,21 +4,24 @@ using System.Globalization; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; +using Internal.Runtime.CompilerServices; #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types #if TARGET_64BIT -using nint = System.Int64; +using nint_t = System.Int64; #else -using nint = System.Int32; +using nint_t = System.Int32; #endif namespace System { [Serializable] + [StructLayout(LayoutKind.Sequential)] [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public readonly struct IntPtr : IEquatable, ISerializable + public readonly struct IntPtr : IEquatable, IComparable, IComparable, IFormattable, ISerializable { // WARNING: We allow diagnostic tools to directly inspect this member (_value). // See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details. @@ -74,9 +77,6 @@ public override unsafe bool Equals(object? obj) => obj is IntPtr other && _value == other._value; - unsafe bool IEquatable.Equals(IntPtr other) => - _value == other._value; - public override unsafe int GetHashCode() { #if TARGET_64BIT @@ -162,17 +162,67 @@ public static IntPtr Subtract(IntPtr pointer, int offset) => public static int Size { [NonVersionable] - get => sizeof(nint); + get => sizeof(nint_t); } [CLSCompliant(false)] [NonVersionable] public unsafe void* ToPointer() => _value; - public override unsafe string ToString() => - ((nint)_value).ToString(CultureInfo.InvariantCulture); + public static IntPtr MaxValue + { + [NonVersionable] + get => (IntPtr)nint_t.MaxValue; + } + + public static IntPtr MinValue + { + [NonVersionable] + get => (IntPtr)nint_t.MinValue; + } + + // Don't just delegate to nint_t.CompareTo as it needs to throw when not IntPtr + public unsafe int CompareTo(object? value) + { + if (value is null) + { + return 1; + } + if (value is nint i) + { + if ((nint)_value < i) return -1; + if ((nint)_value > i) return 1; + return 0; + } + + throw new ArgumentException(SR.Arg_MustBeIntPtr); + } + + public unsafe int CompareTo(IntPtr value) => ((nint_t)_value).CompareTo((nint_t)value); + + [NonVersionable] + public unsafe bool Equals(IntPtr other) => (nint_t)_value == (nint_t)other; + + public unsafe override string ToString() => ((nint_t)_value).ToString(); + public unsafe string ToString(string? format) => ((nint_t)_value).ToString(format); + public unsafe string ToString(IFormatProvider? provider) => ((nint_t)_value).ToString(provider); + public unsafe string ToString(string? format, IFormatProvider? provider) => ((nint_t)_value).ToString(format, provider); + + public static IntPtr Parse(string s) => (IntPtr)nint_t.Parse(s); + public static IntPtr Parse(string s, NumberStyles style) => (IntPtr)nint_t.Parse(s, style); + public static IntPtr Parse(string s, IFormatProvider? provider) => (IntPtr)nint_t.Parse(s, provider); + public static IntPtr Parse(string s, NumberStyles style, IFormatProvider? provider) => (IntPtr)nint_t.Parse(s, style, provider); - public unsafe string ToString(string format) => - ((nint)_value).ToString(format, CultureInfo.InvariantCulture); + public static bool TryParse(string? s, out IntPtr result) + { + Unsafe.SkipInit(out result); + return nint_t.TryParse(s, out Unsafe.As(ref result)); + } + + public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out IntPtr result) + { + Unsafe.SkipInit(out result); + return nint_t.TryParse(s, style, provider, out Unsafe.As(ref result)); + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Marvin.OrdinalIgnoreCase.cs b/src/libraries/System.Private.CoreLib/src/System/Marvin.OrdinalIgnoreCase.cs index c8ff3fb7eaefef..9867caac97dbd4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Marvin.OrdinalIgnoreCase.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Marvin.OrdinalIgnoreCase.cs @@ -8,13 +8,6 @@ using System.Text.Unicode; using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System { internal static partial class Marvin diff --git a/src/libraries/System.Private.CoreLib/src/System/Marvin.cs b/src/libraries/System.Private.CoreLib/src/System/Marvin.cs index 4e5b9d5a035b67..f397c230b5019b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Marvin.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Marvin.cs @@ -8,13 +8,6 @@ using System.Runtime.InteropServices; using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System { internal static partial class Marvin diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 8432f458aec07b..2b0ca9e0f279ba 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -18,6 +18,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics.X86; using System.Runtime.Versioning; namespace System @@ -113,6 +114,61 @@ public static long BigMul(int a, int b) return ((long)a) * b; } + /// Produces the full product of two unsigned 64-bit numbers. + /// The first number to multiply. + /// The second number to multiply. + /// The low 64-bit of the product of the specied numbers. + /// The high 64-bit of the product of the specied numbers. + [CLSCompliant(false)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe ulong BigMul(ulong a, ulong b, out ulong low) + { + if (Bmi2.X64.IsSupported) + { + ulong tmp; + ulong high = Bmi2.X64.MultiplyNoFlags(a, b, &tmp); + low = tmp; + return high; + } + + return SoftwareFallback(a, b, out low); + + static ulong SoftwareFallback(ulong a, ulong b, out ulong low) + { + // Adaptation of algorithm for multiplication + // of 32-bit unsigned integers described + // in Hacker's Delight by Henry S. Warren, Jr. (ISBN 0-201-91465-4), Chapter 8 + // Basically, it's an optimized version of FOIL method applied to + // low and high dwords of each operand + + // Use 32-bit uints to optimize the fallback for 32-bit platforms. + uint al = (uint)a; + uint ah = (uint)(a >> 32); + uint bl = (uint)b; + uint bh = (uint)(b >> 32); + + ulong mull = ((ulong)al) * bl; + ulong t = ((ulong)ah) * bl + (mull >> 32); + ulong tl = ((ulong)al) * bh + (uint)t; + + low = tl << 32 | (uint)mull; + + return ((ulong)ah) * bh + (t >> 32) + (tl >> 32); + } + } + + /// Produces the full product of two 64-bit numbers. + /// The first number to multiply. + /// The second number to multiply. + /// The low 64-bit of the product of the specied numbers. + /// The high 64-bit of the product of the specied numbers. + public static long BigMul(long a, long b, out long low) + { + ulong high = BigMul((ulong)a, (ulong)b, out ulong ulow); + low = (long)ulow; + return (long)high - ((a >> 63) & b) - ((b >> 63) & a); + } + public static double BitDecrement(double x) { long bits = BitConverter.DoubleToInt64Bits(x); @@ -539,6 +595,7 @@ public static decimal Max(decimal val1, decimal val2) return decimal.Max(val1, val2); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Max(double val1, double val2) { // This matches the IEEE 754:2019 `maximum` function @@ -547,17 +604,17 @@ public static double Max(double val1, double val2) // otherwise returns the larger of the inputs. It // treats +0 as larger than -0 as per the specification. - if ((val1 > val2) || double.IsNaN(val1)) + if (val1 != val2) { - return val1; - } + if (!double.IsNaN(val1)) + { + return val2 < val1 ? val1 : val2; + } - if (val1 == val2) - { - return double.IsNegative(val1) ? val2 : val1; + return val1; } - return val2; + return double.IsNegative(val2) ? val1 : val2; } [NonVersionable] @@ -585,6 +642,7 @@ public static sbyte Max(sbyte val1, sbyte val2) return (val1 >= val2) ? val1 : val2; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Max(float val1, float val2) { // This matches the IEEE 754:2019 `maximum` function @@ -593,17 +651,17 @@ public static float Max(float val1, float val2) // otherwise returns the larger of the inputs. It // treats +0 as larger than -0 as per the specification. - if ((val1 > val2) || float.IsNaN(val1)) + if (val1 != val2) { - return val1; - } + if (!float.IsNaN(val1)) + { + return val2 < val1 ? val1 : val2; + } - if (val1 == val2) - { - return float.IsNegative(val1) ? val2 : val1; + return val1; } - return val2; + return float.IsNegative(val2) ? val1 : val2; } [CLSCompliant(false)] @@ -663,6 +721,7 @@ public static decimal Min(decimal val1, decimal val2) return decimal.Min(val1, val2); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Min(double val1, double val2) { // This matches the IEEE 754:2019 `minimum` function @@ -671,17 +730,12 @@ public static double Min(double val1, double val2) // otherwise returns the larger of the inputs. It // treats +0 as larger than -0 as per the specification. - if ((val1 < val2) || double.IsNaN(val1)) - { - return val1; - } - - if (val1 == val2) + if (val1 != val2 && !double.IsNaN(val1)) { - return double.IsNegative(val1) ? val1 : val2; + return val1 < val2 ? val1 : val2; } - return val2; + return double.IsNegative(val1) ? val1 : val2; } [NonVersionable] @@ -709,6 +763,7 @@ public static sbyte Min(sbyte val1, sbyte val2) return (val1 <= val2) ? val1 : val2; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Min(float val1, float val2) { // This matches the IEEE 754:2019 `minimum` function @@ -717,17 +772,12 @@ public static float Min(float val1, float val2) // otherwise returns the larger of the inputs. It // treats +0 as larger than -0 as per the specification. - if ((val1 < val2) || float.IsNaN(val1)) - { - return val1; - } - - if (val1 == val2) + if (val1 != val2 && !float.IsNaN(val1)) { - return float.IsNegative(val1) ? val1 : val2; + return val1 < val2 ? val1 : val2; } - return val2; + return float.IsNegative(val1) ? val1 : val2; } [CLSCompliant(false)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Memory.cs b/src/libraries/System.Private.CoreLib/src/System/Memory.cs index cb8f631c5d44c6..bed73caea13571 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Memory.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Memory.cs @@ -12,13 +12,6 @@ using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else // TARGET_64BIT -using nuint = System.UInt32; -#endif // TARGET_64BIT - namespace System { /// @@ -364,7 +357,7 @@ public unsafe Span Span ThrowHelper.ThrowArgumentOutOfRangeException(); } #else - if ((uint)desiredStartIndex > (uint)lengthOfUnderlyingSpan || (uint)desiredLength > (uint)(lengthOfUnderlyingSpan - desiredStartIndex)) + if ((uint)desiredStartIndex > (uint)lengthOfUnderlyingSpan || (uint)desiredLength > (uint)lengthOfUnderlyingSpan - (uint)desiredStartIndex) { ThrowHelper.ThrowArgumentOutOfRangeException(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.Globalization.cs b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.Globalization.cs index fb339f76cc71bc..4974928afd7036 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.Globalization.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.Globalization.cs @@ -7,6 +7,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using Internal.Runtime.CompilerServices; namespace System { @@ -50,26 +51,20 @@ public static bool Equals(this ReadOnlySpan span, ReadOnlySpan other switch (comparisonType) { case StringComparison.CurrentCulture: - return CultureInfo.CurrentCulture.CompareInfo.CompareOptionNone(span, other) == 0; - case StringComparison.CurrentCultureIgnoreCase: - return CultureInfo.CurrentCulture.CompareInfo.CompareOptionIgnoreCase(span, other) == 0; + return CultureInfo.CurrentCulture.CompareInfo.Compare(span, other, string.GetCaseCompareOfComparisonCulture(comparisonType)) == 0; case StringComparison.InvariantCulture: - return CompareInfo.Invariant.CompareOptionNone(span, other) == 0; - case StringComparison.InvariantCultureIgnoreCase: - return CompareInfo.Invariant.CompareOptionIgnoreCase(span, other) == 0; + return CompareInfo.Invariant.Compare(span, other, string.GetCaseCompareOfComparisonCulture(comparisonType)) == 0; case StringComparison.Ordinal: return EqualsOrdinal(span, other); - case StringComparison.OrdinalIgnoreCase: + default: + Debug.Assert(comparisonType == StringComparison.OrdinalIgnoreCase); return EqualsOrdinalIgnoreCase(span, other); } - - Debug.Fail("StringComparison outside range"); - return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -106,28 +101,22 @@ public static int CompareTo(this ReadOnlySpan span, ReadOnlySpan oth switch (comparisonType) { case StringComparison.CurrentCulture: - return CultureInfo.CurrentCulture.CompareInfo.CompareOptionNone(span, other); - case StringComparison.CurrentCultureIgnoreCase: - return CultureInfo.CurrentCulture.CompareInfo.CompareOptionIgnoreCase(span, other); + return CultureInfo.CurrentCulture.CompareInfo.Compare(span, other, string.GetCaseCompareOfComparisonCulture(comparisonType)); case StringComparison.InvariantCulture: - return CompareInfo.Invariant.CompareOptionNone(span, other); - case StringComparison.InvariantCultureIgnoreCase: - return CompareInfo.Invariant.CompareOptionIgnoreCase(span, other); + return CompareInfo.Invariant.Compare(span, other, string.GetCaseCompareOfComparisonCulture(comparisonType)); case StringComparison.Ordinal: if (span.Length == 0 || other.Length == 0) return span.Length - other.Length; return string.CompareOrdinal(span, other); - case StringComparison.OrdinalIgnoreCase: + default: + Debug.Assert(comparisonType == StringComparison.OrdinalIgnoreCase); return CompareInfo.CompareOrdinalIgnoreCase(span, other); } - - Debug.Fail("StringComparison outside range"); - return 0; } /// @@ -140,16 +129,6 @@ public static int IndexOf(this ReadOnlySpan span, ReadOnlySpan value { string.CheckStringComparison(comparisonType); - if (value.Length == 0) - { - return 0; // empty substring trivially occurs at every index (including start) of search space - } - - if (span.Length == 0) - { - return -1; - } - if (comparisonType == StringComparison.Ordinal) { return SpanHelpers.IndexOf( @@ -159,11 +138,6 @@ ref MemoryMarshal.GetReference(value), value.Length); } - if (GlobalizationMode.Invariant) - { - return CompareInfo.InvariantIndexOf(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType) != CompareOptions.None); - } - switch (comparisonType) { case StringComparison.CurrentCulture: @@ -176,7 +150,7 @@ ref MemoryMarshal.GetReference(value), default: Debug.Assert(comparisonType == StringComparison.OrdinalIgnoreCase); - return CompareInfo.Invariant.IndexOfOrdinalIgnoreCase(span, value); + return CompareInfo.IndexOfOrdinalIgnoreCase(span, value, fromBeginning: true); } } @@ -190,19 +164,13 @@ public static int LastIndexOf(this ReadOnlySpan span, ReadOnlySpan v { string.CheckStringComparison(comparisonType); - if (value.Length == 0) - { - return span.Length; // empty substring trivially occurs at every index (including end) of search space - } - - if (span.Length == 0) - { - return -1; - } - - if (GlobalizationMode.Invariant) + if (comparisonType == StringComparison.Ordinal) { - return CompareInfo.InvariantIndexOf(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType) != CompareOptions.None, fromBeginning: false); + return SpanHelpers.LastIndexOf( + ref MemoryMarshal.GetReference(span), + span.Length, + ref MemoryMarshal.GetReference(value), + value.Length); } switch (comparisonType) @@ -216,8 +184,8 @@ public static int LastIndexOf(this ReadOnlySpan span, ReadOnlySpan v return CompareInfo.Invariant.LastIndexOf(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)); default: - Debug.Assert(comparisonType == StringComparison.Ordinal || comparisonType == StringComparison.OrdinalIgnoreCase); - return CompareInfo.Invariant.LastIndexOfOrdinal(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType) != CompareOptions.None); + Debug.Assert(comparisonType == StringComparison.OrdinalIgnoreCase); + return CompareInfo.IndexOfOrdinalIgnoreCase(span, value, fromBeginning: false); } } @@ -335,29 +303,33 @@ public static bool EndsWith(this ReadOnlySpan span, ReadOnlySpan val { string.CheckStringComparison(comparisonType); - if (value.Length == 0) + switch (comparisonType) { - return true; // the empty string is trivially a suffix of every other string - } + case StringComparison.CurrentCulture: + case StringComparison.CurrentCultureIgnoreCase: + return CultureInfo.CurrentCulture.CompareInfo.IsSuffix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)); - if (comparisonType >= StringComparison.Ordinal || GlobalizationMode.Invariant) - { - if (string.GetCaseCompareOfComparisonCulture(comparisonType) == CompareOptions.None) - return span.EndsWith(value); + case StringComparison.InvariantCulture: + case StringComparison.InvariantCultureIgnoreCase: + return CompareInfo.Invariant.IsSuffix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)); - return (span.Length >= value.Length) ? (CompareInfo.CompareOrdinalIgnoreCase(span.Slice(span.Length - value.Length), value) == 0) : false; - } + case StringComparison.Ordinal: + return span.EndsWith(value); - if (span.Length == 0) - { - return false; + default: + Debug.Assert(comparisonType == StringComparison.OrdinalIgnoreCase); + return span.EndsWithOrdinalIgnoreCase(value); } - - return (comparisonType >= StringComparison.InvariantCulture) ? - CompareInfo.Invariant.IsSuffix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)) : - CultureInfo.CurrentCulture.CompareInfo.IsSuffix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool EndsWithOrdinalIgnoreCase(this ReadOnlySpan span, ReadOnlySpan value) + => value.Length <= span.Length + && CompareInfo.EqualsOrdinalIgnoreCase( + ref Unsafe.Add(ref MemoryMarshal.GetReference(span), span.Length - value.Length), + ref MemoryMarshal.GetReference(value), + value.Length); + /// /// Determines whether the beginning of the matches the specified when compared using the specified option. /// @@ -368,29 +340,30 @@ public static bool StartsWith(this ReadOnlySpan span, ReadOnlySpan v { string.CheckStringComparison(comparisonType); - if (value.Length == 0) + switch (comparisonType) { - return true; // the empty string is trivially a prefix of every other string - } + case StringComparison.CurrentCulture: + case StringComparison.CurrentCultureIgnoreCase: + return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)); - if (comparisonType >= StringComparison.Ordinal || GlobalizationMode.Invariant) - { - if (string.GetCaseCompareOfComparisonCulture(comparisonType) == CompareOptions.None) - return span.StartsWith(value); + case StringComparison.InvariantCulture: + case StringComparison.InvariantCultureIgnoreCase: + return CompareInfo.Invariant.IsPrefix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)); - return (span.Length >= value.Length) ? (CompareInfo.CompareOrdinalIgnoreCase(span.Slice(0, value.Length), value) == 0) : false; - } + case StringComparison.Ordinal: + return span.StartsWith(value); - if (span.Length == 0) - { - return false; + default: + Debug.Assert(comparisonType == StringComparison.OrdinalIgnoreCase); + return span.StartsWithOrdinalIgnoreCase(value); } - - return (comparisonType >= StringComparison.InvariantCulture) ? - CompareInfo.Invariant.IsPrefix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)) : - CultureInfo.CurrentCulture.CompareInfo.IsPrefix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool StartsWithOrdinalIgnoreCase(this ReadOnlySpan span, ReadOnlySpan value) + => value.Length <= span.Length + && CompareInfo.EqualsOrdinalIgnoreCase(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(value), value.Length); + /// /// Returns an enumeration of from the provided span. /// diff --git a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs index 2a66efac7709c6..33bc6f9e1fffc3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs @@ -8,13 +8,6 @@ using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif // TARGET_64BIT - namespace System { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Nullable.cs b/src/libraries/System.Private.CoreLib/src/System/Nullable.cs index 223a446ae8eb60..8a5416d7286567 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Nullable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Nullable.cs @@ -111,7 +111,7 @@ public static bool Equals(Nullable n1, Nullable n2) where T : struct { if (nullableEEType.IsNullable) { - return Internal.Reflection.Core.NonPortable.RuntimeTypeUnifier.GetRuntimeTypeForEEType(nullableEEType.NullableType); + return Type.GetTypeFromEETypePtr(nullableEEType.NullableType); } } return null; diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs index 74fe7c0c4863d6..9cba193c2135e2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs @@ -1069,7 +1069,7 @@ static unsafe bool TryFormatUInt64Slow(ulong value, ReadOnlySpan format, I NumberFormatInfo info = NumberFormatInfo.GetInstance(provider); byte* pDigits = stackalloc byte[UInt64NumberBufferLength]; - NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, UInt32NumberBufferLength); + NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, UInt64NumberBufferLength); UInt64ToNumber(value, ref number); diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs index 9844240e1058a3..28b341633de4e9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs @@ -4,6 +4,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; @@ -67,13 +68,21 @@ public static int LeadingZeroCount(uint value) return ArmBase.LeadingZeroCount(value); } - // Unguarded fallback contract is 0->31 + // Unguarded fallback contract is 0->31, BSR contract is 0->undefined if (value == 0) { return 32; } - return 31 - Log2SoftwareFallback(value); + if (X86Base.IsSupported) + { + // LZCNT returns index starting from MSB, whereas BSR gives the index from LSB. + // 31 ^ BSR here is equivalent to 31 - BSR since the BSR result is always between 0 and 31. + // This saves an instruction, as subtraction from constant requires either MOV/SUB or NEG/ADD. + return 31 ^ (int)X86Base.BitScanReverse(value); + } + + return 31 ^ Log2SoftwareFallback(value); } /// @@ -96,6 +105,12 @@ public static int LeadingZeroCount(ulong value) return ArmBase.Arm64.LeadingZeroCount(value); } + if (X86Base.X64.IsSupported) + { + // BSR contract is 0->undefined + return value == 0 ? 64 : 63 ^ (int)X86Base.X64.BitScanReverse(value); + } + uint hi = (uint)(value >> 32); if (hi == 0) @@ -108,21 +123,18 @@ public static int LeadingZeroCount(ulong value) /// /// Returns the integer (floor) log of the specified value, base 2. - /// Note that by convention, input value 0 returns 0 since Log(0) is undefined. + /// Note that by convention, input value 0 returns 0 since log(0) is undefined. /// /// The value. [MethodImpl(MethodImplOptions.AggressiveInlining)] [CLSCompliant(false)] public static int Log2(uint value) { - // Enforce conventional contract 0->0 (Log(0) is undefined) - if (value == 0) - { - return 0; - } + // The 0->0 contract is fulfilled by setting the LSB to 1. + // Log(1) is 0, and setting the LSB for values > 1 does not change the log2 result. + value |= 1; // value lzcnt actual expected - // ..0000 32 0 0 (by convention, guard clause) // ..0001 31 31-31 0 // ..0010 30 31-30 1 // 0010.. 2 31-2 29 @@ -130,13 +142,19 @@ public static int Log2(uint value) // 1000.. 0 31-0 31 if (Lzcnt.IsSupported) { - // LZCNT contract is 0->32 - return 31 - (int)Lzcnt.LeadingZeroCount(value); + return 31 ^ (int)Lzcnt.LeadingZeroCount(value); } if (ArmBase.IsSupported) { - return 31 - ArmBase.LeadingZeroCount(value); + return 31 ^ ArmBase.LeadingZeroCount(value); + } + + // BSR returns the log2 result directly. However BSR is slower than LZCNT + // on AMD processors, so we leave it as a fallback only. + if (X86Base.IsSupported) + { + return (int)X86Base.BitScanReverse(value); } // Fallback contract is 0->0 @@ -145,28 +163,28 @@ public static int Log2(uint value) /// /// Returns the integer (floor) log of the specified value, base 2. - /// Note that by convention, input value 0 returns 0 since Log(0) is undefined. + /// Note that by convention, input value 0 returns 0 since log(0) is undefined. /// /// The value. [MethodImpl(MethodImplOptions.AggressiveInlining)] [CLSCompliant(false)] public static int Log2(ulong value) { - // Enforce conventional contract 0->0 (Log(0) is undefined) - if (value == 0) - { - return 0; - } + value |= 1; if (Lzcnt.X64.IsSupported) { - // LZCNT contract is 0->64 - return 63 - (int)Lzcnt.X64.LeadingZeroCount(value); + return 63 ^ (int)Lzcnt.X64.LeadingZeroCount(value); } if (ArmBase.Arm64.IsSupported) { - return 63 - ArmBase.Arm64.LeadingZeroCount(value); + return 63 ^ ArmBase.Arm64.LeadingZeroCount(value); + } + + if (X86Base.X64.IsSupported) + { + return (int)X86Base.X64.BitScanReverse(value); } uint hi = (uint)(value >> 32); @@ -219,6 +237,19 @@ public static int PopCount(uint value) return (int)Popcnt.PopCount(value); } + if (AdvSimd.Arm64.IsSupported) + { + // PopCount works on vector so convert input value to vector first. + + // Vector64.CreateScalar(uint) generates suboptimal code by storing and + // loading the result to memory. + // See https://github.com/dotnet/runtime/issues/35976 for details. + // Hence use Vector64.Create(ulong) to create Vector64 and operate on that. + Vector64 input = Vector64.Create((ulong)value); + Vector64 aggregated = AdvSimd.Arm64.AddAcross(AdvSimd.PopCount(input.AsByte())); + return aggregated.ToScalar(); + } + return SoftwareFallback(value); static int SoftwareFallback(uint value) @@ -250,6 +281,14 @@ public static int PopCount(ulong value) return (int)Popcnt.X64.PopCount(value); } + if (AdvSimd.Arm64.IsSupported) + { + // PopCount works on vector so convert input value to vector first. + Vector64 input = Vector64.Create(value); + Vector64 aggregated = AdvSimd.Arm64.AddAcross(AdvSimd.PopCount(input.AsByte())); + return aggregated.ToScalar(); + } + #if TARGET_32BIT return PopCount((uint)value) // lo + PopCount((uint)(value >> 32)); // hi @@ -301,12 +340,17 @@ public static int TrailingZeroCount(uint value) return ArmBase.LeadingZeroCount(ArmBase.ReverseElementBits(value)); } - // Unguarded fallback contract is 0->0 + // Unguarded fallback contract is 0->0, BSF contract is 0->undefined if (value == 0) { return 32; } + if (X86Base.IsSupported) + { + return (int)X86Base.BitScanForward(value); + } + // uint.MaxValue >> 27 is always in range [0 - 31] so we use Unsafe.AddByteOffset to avoid bounds check return Unsafe.AddByteOffset( // Using deBruijn sequence, k=2, n=5 (2^5=32) : 0b_0000_0111_0111_1100_1011_0101_0011_0001u @@ -343,6 +387,13 @@ public static int TrailingZeroCount(ulong value) { return ArmBase.Arm64.LeadingZeroCount(ArmBase.Arm64.ReverseElementBits(value)); } + + if (X86Base.X64.IsSupported) + { + // BSF contract is 0->undefined + return value == 0 ? 64 : (int)X86Base.X64.BitScanForward(value); + } + uint lo = (uint)value; if (lo == 0) diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.cs index c49c02c18dd203..7323ba23e3dd7e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.cs @@ -1,8 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. - +using Internal.Runtime.CompilerServices; +using System.Diagnostics; using System.Globalization; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; @@ -1305,171 +1307,360 @@ public readonly float GetDeterminant() d * (e * jo_kn - f * io_km + g * in_jm); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector128 Permute(Vector128 value, byte control) + { + if (Avx.IsSupported) + { + return Avx.Permute(value, control); + } + + Debug.Assert(Sse.IsSupported); + return Sse.Shuffle(value, value, control); + } + /// /// Attempts to calculate the inverse of the given matrix. If successful, result will contain the inverted matrix. /// /// The source matrix to invert. /// If successful, contains the inverted matrix. /// True if the source matrix could be inverted; False otherwise. - public static bool Invert(Matrix4x4 matrix, out Matrix4x4 result) + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe bool Invert(Matrix4x4 matrix, out Matrix4x4 result) { - // -1 - // If you have matrix M, inverse Matrix M can compute - // - // -1 1 - // M = --------- A - // det(M) - // - // A is adjugate (adjoint) of M, where, - // - // T - // A = C - // - // C is Cofactor matrix of M, where, - // i + j - // C = (-1) * det(M ) - // ij ij - // - // [ a b c d ] - // M = [ e f g h ] - // [ i j k l ] - // [ m n o p ] - // - // First Row - // 2 | f g h | - // C = (-1) | j k l | = + ( f ( kp - lo ) - g ( jp - ln ) + h ( jo - kn ) ) - // 11 | n o p | - // - // 3 | e g h | - // C = (-1) | i k l | = - ( e ( kp - lo ) - g ( ip - lm ) + h ( io - km ) ) - // 12 | m o p | - // - // 4 | e f h | - // C = (-1) | i j l | = + ( e ( jp - ln ) - f ( ip - lm ) + h ( in - jm ) ) - // 13 | m n p | - // - // 5 | e f g | - // C = (-1) | i j k | = - ( e ( jo - kn ) - f ( io - km ) + g ( in - jm ) ) - // 14 | m n o | - // - // Second Row - // 3 | b c d | - // C = (-1) | j k l | = - ( b ( kp - lo ) - c ( jp - ln ) + d ( jo - kn ) ) - // 21 | n o p | - // - // 4 | a c d | - // C = (-1) | i k l | = + ( a ( kp - lo ) - c ( ip - lm ) + d ( io - km ) ) - // 22 | m o p | - // - // 5 | a b d | - // C = (-1) | i j l | = - ( a ( jp - ln ) - b ( ip - lm ) + d ( in - jm ) ) - // 23 | m n p | - // - // 6 | a b c | - // C = (-1) | i j k | = + ( a ( jo - kn ) - b ( io - km ) + c ( in - jm ) ) - // 24 | m n o | - // - // Third Row - // 4 | b c d | - // C = (-1) | f g h | = + ( b ( gp - ho ) - c ( fp - hn ) + d ( fo - gn ) ) - // 31 | n o p | - // - // 5 | a c d | - // C = (-1) | e g h | = - ( a ( gp - ho ) - c ( ep - hm ) + d ( eo - gm ) ) - // 32 | m o p | - // - // 6 | a b d | - // C = (-1) | e f h | = + ( a ( fp - hn ) - b ( ep - hm ) + d ( en - fm ) ) - // 33 | m n p | - // - // 7 | a b c | - // C = (-1) | e f g | = - ( a ( fo - gn ) - b ( eo - gm ) + c ( en - fm ) ) - // 34 | m n o | - // - // Fourth Row - // 5 | b c d | - // C = (-1) | f g h | = - ( b ( gl - hk ) - c ( fl - hj ) + d ( fk - gj ) ) - // 41 | j k l | - // - // 6 | a c d | - // C = (-1) | e g h | = + ( a ( gl - hk ) - c ( el - hi ) + d ( ek - gi ) ) - // 42 | i k l | - // - // 7 | a b d | - // C = (-1) | e f h | = - ( a ( fl - hj ) - b ( el - hi ) + d ( ej - fi ) ) - // 43 | i j l | - // - // 8 | a b c | - // C = (-1) | e f g | = + ( a ( fk - gj ) - b ( ek - gi ) + c ( ej - fi ) ) - // 44 | i j k | - // - // Cost of operation - // 53 adds, 104 muls, and 1 div. - float a = matrix.M11, b = matrix.M12, c = matrix.M13, d = matrix.M14; - float e = matrix.M21, f = matrix.M22, g = matrix.M23, h = matrix.M24; - float i = matrix.M31, j = matrix.M32, k = matrix.M33, l = matrix.M34; - float m = matrix.M41, n = matrix.M42, o = matrix.M43, p = matrix.M44; + if (Sse.IsSupported) + { + return SseImpl(matrix, out result); + } - float kp_lo = k * p - l * o; - float jp_ln = j * p - l * n; - float jo_kn = j * o - k * n; - float ip_lm = i * p - l * m; - float io_km = i * o - k * m; - float in_jm = i * n - j * m; + return SoftwareFallback(matrix, out result); - float a11 = +(f * kp_lo - g * jp_ln + h * jo_kn); - float a12 = -(e * kp_lo - g * ip_lm + h * io_km); - float a13 = +(e * jp_ln - f * ip_lm + h * in_jm); - float a14 = -(e * jo_kn - f * io_km + g * in_jm); + static unsafe bool SseImpl(Matrix4x4 matrix, out Matrix4x4 result) + { + // This implementation is based on the DirectX Math Library XMMInverse method + // https://github.com/microsoft/DirectXMath/blob/master/Inc/DirectXMathMatrix.inl - float det = a * a11 + b * a12 + c * a13 + d * a14; + // Load the matrix values into rows + Vector128 row1 = Sse.LoadVector128(&matrix.M11); + Vector128 row2 = Sse.LoadVector128(&matrix.M21); + Vector128 row3 = Sse.LoadVector128(&matrix.M31); + Vector128 row4 = Sse.LoadVector128(&matrix.M41); - if (MathF.Abs(det) < float.Epsilon) - { - result = new Matrix4x4(float.NaN, float.NaN, float.NaN, float.NaN, - float.NaN, float.NaN, float.NaN, float.NaN, - float.NaN, float.NaN, float.NaN, float.NaN, - float.NaN, float.NaN, float.NaN, float.NaN); - return false; + // Transpose the matrix + Vector128 vTemp1 = Sse.Shuffle(row1, row2, 0x44); //_MM_SHUFFLE(1, 0, 1, 0) + Vector128 vTemp3 = Sse.Shuffle(row1, row2, 0xEE); //_MM_SHUFFLE(3, 2, 3, 2) + Vector128 vTemp2 = Sse.Shuffle(row3, row4, 0x44); //_MM_SHUFFLE(1, 0, 1, 0) + Vector128 vTemp4 = Sse.Shuffle(row3, row4, 0xEE); //_MM_SHUFFLE(3, 2, 3, 2) + + row1 = Sse.Shuffle(vTemp1, vTemp2, 0x88); //_MM_SHUFFLE(2, 0, 2, 0) + row2 = Sse.Shuffle(vTemp1, vTemp2, 0xDD); //_MM_SHUFFLE(3, 1, 3, 1) + row3 = Sse.Shuffle(vTemp3, vTemp4, 0x88); //_MM_SHUFFLE(2, 0, 2, 0) + row4 = Sse.Shuffle(vTemp3, vTemp4, 0xDD); //_MM_SHUFFLE(3, 1, 3, 1) + + Vector128 V00 = Permute(row3, 0x50); //_MM_SHUFFLE(1, 1, 0, 0) + Vector128 V10 = Permute(row4, 0xEE); //_MM_SHUFFLE(3, 2, 3, 2) + Vector128 V01 = Permute(row1, 0x50); //_MM_SHUFFLE(1, 1, 0, 0) + Vector128 V11 = Permute(row2, 0xEE); //_MM_SHUFFLE(3, 2, 3, 2) + Vector128 V02 = Sse.Shuffle(row3, row1, 0x88); //_MM_SHUFFLE(2, 0, 2, 0) + Vector128 V12 = Sse.Shuffle(row4, row2, 0xDD); //_MM_SHUFFLE(3, 1, 3, 1) + + Vector128 D0 = Sse.Multiply(V00, V10); + Vector128 D1 = Sse.Multiply(V01, V11); + Vector128 D2 = Sse.Multiply(V02, V12); + + V00 = Permute(row3, 0xEE); //_MM_SHUFFLE(3, 2, 3, 2) + V10 = Permute(row4, 0x50); //_MM_SHUFFLE(1, 1, 0, 0) + V01 = Permute(row1, 0xEE); //_MM_SHUFFLE(3, 2, 3, 2) + V11 = Permute(row2, 0x50); //_MM_SHUFFLE(1, 1, 0, 0) + V02 = Sse.Shuffle(row3, row1, 0xDD); //_MM_SHUFFLE(3, 1, 3, 1) + V12 = Sse.Shuffle(row4, row2, 0x88); //_MM_SHUFFLE(2, 0, 2, 0) + + // Note: We use this expansion pattern instead of Fused Multiply Add + // in order to support older hardware + D0 = Sse.Subtract(D0, Sse.Multiply(V00, V10)); + D1 = Sse.Subtract(D1, Sse.Multiply(V01, V11)); + D2 = Sse.Subtract(D2, Sse.Multiply(V02, V12)); + + // V11 = D0Y,D0W,D2Y,D2Y + V11 = Sse.Shuffle(D0, D2, 0x5D); //_MM_SHUFFLE(1, 1, 3, 1) + V00 = Permute(row2, 0x49); //_MM_SHUFFLE(1, 0, 2, 1) + V10 = Sse.Shuffle(V11, D0, 0x32); //_MM_SHUFFLE(0, 3, 0, 2) + V01 = Permute(row1, 0x12); //_MM_SHUFFLE(0, 1, 0, 2) + V11 = Sse.Shuffle(V11, D0, 0x99); //_MM_SHUFFLE(2, 1, 2, 1) + + // V13 = D1Y,D1W,D2W,D2W + Vector128 V13 = Sse.Shuffle(D1, D2, 0xFD); //_MM_SHUFFLE(3, 3, 3, 1) + V02 = Permute(row4, 0x49); //_MM_SHUFFLE(1, 0, 2, 1) + V12 = Sse.Shuffle(V13, D1, 0x32); //_MM_SHUFFLE(0, 3, 0, 2) + Vector128 V03 = Permute(row3, 0x12); //_MM_SHUFFLE(0, 1, 0, 2) + V13 = Sse.Shuffle(V13, D1, 0x99); //_MM_SHUFFLE(2, 1, 2, 1) + + Vector128 C0 = Sse.Multiply(V00, V10); + Vector128 C2 = Sse.Multiply(V01, V11); + Vector128 C4 = Sse.Multiply(V02, V12); + Vector128 C6 = Sse.Multiply(V03, V13); + + // V11 = D0X,D0Y,D2X,D2X + V11 = Sse.Shuffle(D0, D2, 0x4); //_MM_SHUFFLE(0, 0, 1, 0) + V00 = Permute(row2, 0x9e); //_MM_SHUFFLE(2, 1, 3, 2) + V10 = Sse.Shuffle(D0, V11, 0x93); //_MM_SHUFFLE(2, 1, 0, 3) + V01 = Permute(row1, 0x7b); //_MM_SHUFFLE(1, 3, 2, 3) + V11 = Sse.Shuffle(D0, V11, 0x26); //_MM_SHUFFLE(0, 2, 1, 2) + + // V13 = D1X,D1Y,D2Z,D2Z + V13 = Sse.Shuffle(D1, D2, 0xa4); //_MM_SHUFFLE(2, 2, 1, 0) + V02 = Permute(row4, 0x9e); //_MM_SHUFFLE(2, 1, 3, 2) + V12 = Sse.Shuffle(D1, V13, 0x93); //_MM_SHUFFLE(2, 1, 0, 3) + V03 = Permute(row3, 0x7b); //_MM_SHUFFLE(1, 3, 2, 3) + V13 = Sse.Shuffle(D1, V13, 0x26); //_MM_SHUFFLE(0, 2, 1, 2) + + C0 = Sse.Subtract(C0, Sse.Multiply(V00, V10)); + C2 = Sse.Subtract(C2, Sse.Multiply(V01, V11)); + C4 = Sse.Subtract(C4, Sse.Multiply(V02, V12)); + C6 = Sse.Subtract(C6, Sse.Multiply(V03, V13)); + + V00 = Permute(row2, 0x33); //_MM_SHUFFLE(0, 3, 0, 3) + + // V10 = D0Z,D0Z,D2X,D2Y + V10 = Sse.Shuffle(D0, D2, 0x4A); //_MM_SHUFFLE(1, 0, 2, 2) + V10 = Permute(V10, 0x2C); //_MM_SHUFFLE(0, 2, 3, 0) + V01 = Permute(row1, 0x8D); //_MM_SHUFFLE(2, 0, 3, 1) + + // V11 = D0X,D0W,D2X,D2Y + V11 = Sse.Shuffle(D0, D2, 0x4C); //_MM_SHUFFLE(1, 0, 3, 0) + V11 = Permute(V11, 0x93); //_MM_SHUFFLE(2, 1, 0, 3) + V02 = Permute(row4, 0x33); //_MM_SHUFFLE(0, 3, 0, 3) + + // V12 = D1Z,D1Z,D2Z,D2W + V12 = Sse.Shuffle(D1, D2, 0xEA); //_MM_SHUFFLE(3, 2, 2, 2) + V12 = Permute(V12, 0x2C); //_MM_SHUFFLE(0, 2, 3, 0) + V03 = Permute(row3, 0x8D); //_MM_SHUFFLE(2, 0, 3, 1) + + // V13 = D1X,D1W,D2Z,D2W + V13 = Sse.Shuffle(D1, D2, 0xEC); //_MM_SHUFFLE(3, 2, 3, 0) + V13 = Permute(V13, 0x93); //_MM_SHUFFLE(2, 1, 0, 3) + + V00 = Sse.Multiply(V00, V10); + V01 = Sse.Multiply(V01, V11); + V02 = Sse.Multiply(V02, V12); + V03 = Sse.Multiply(V03, V13); + + Vector128 C1 = Sse.Subtract(C0, V00); + C0 = Sse.Add(C0, V00); + Vector128 C3 = Sse.Add(C2, V01); + C2 = Sse.Subtract(C2, V01); + Vector128 C5 = Sse.Subtract(C4, V02); + C4 = Sse.Add(C4, V02); + Vector128 C7 = Sse.Add(C6, V03); + C6 = Sse.Subtract(C6, V03); + + C0 = Sse.Shuffle(C0, C1, 0xD8); //_MM_SHUFFLE(3, 1, 2, 0) + C2 = Sse.Shuffle(C2, C3, 0xD8); //_MM_SHUFFLE(3, 1, 2, 0) + C4 = Sse.Shuffle(C4, C5, 0xD8); //_MM_SHUFFLE(3, 1, 2, 0) + C6 = Sse.Shuffle(C6, C7, 0xD8); //_MM_SHUFFLE(3, 1, 2, 0) + + C0 = Permute(C0, 0xD8); //_MM_SHUFFLE(3, 1, 2, 0) + C2 = Permute(C2, 0xD8); //_MM_SHUFFLE(3, 1, 2, 0) + C4 = Permute(C4, 0xD8); //_MM_SHUFFLE(3, 1, 2, 0) + C6 = Permute(C6, 0xD8); //_MM_SHUFFLE(3, 1, 2, 0) + + // Get the determinant + vTemp2 = row1; + float det = Vector4.Dot(C0.AsVector4(), vTemp2.AsVector4()); + + // Check determinate is not zero + if (MathF.Abs(det) < float.Epsilon) + { + result = new Matrix4x4(float.NaN, float.NaN, float.NaN, float.NaN, + float.NaN, float.NaN, float.NaN, float.NaN, + float.NaN, float.NaN, float.NaN, float.NaN, + float.NaN, float.NaN, float.NaN, float.NaN); + return false; + } + + // Create Vector128 copy of the determinant and invert them. + Vector128 ones = Vector128.Create(1.0f); + Vector128 vTemp = Vector128.Create(det); + vTemp = Sse.Divide(ones, vTemp); + + row1 = Sse.Multiply(C0, vTemp); + row2 = Sse.Multiply(C2, vTemp); + row3 = Sse.Multiply(C4, vTemp); + row4 = Sse.Multiply(C6, vTemp); + + Unsafe.SkipInit(out result); + ref Vector128 vResult = ref Unsafe.As>(ref result); + + vResult = row1; + Unsafe.Add(ref vResult, 1) = row2; + Unsafe.Add(ref vResult, 2) = row3; + Unsafe.Add(ref vResult, 3) = row4; + + return true; } - float invDet = 1.0f / det; - - result.M11 = a11 * invDet; - result.M21 = a12 * invDet; - result.M31 = a13 * invDet; - result.M41 = a14 * invDet; - - result.M12 = -(b * kp_lo - c * jp_ln + d * jo_kn) * invDet; - result.M22 = +(a * kp_lo - c * ip_lm + d * io_km) * invDet; - result.M32 = -(a * jp_ln - b * ip_lm + d * in_jm) * invDet; - result.M42 = +(a * jo_kn - b * io_km + c * in_jm) * invDet; - - float gp_ho = g * p - h * o; - float fp_hn = f * p - h * n; - float fo_gn = f * o - g * n; - float ep_hm = e * p - h * m; - float eo_gm = e * o - g * m; - float en_fm = e * n - f * m; - - result.M13 = +(b * gp_ho - c * fp_hn + d * fo_gn) * invDet; - result.M23 = -(a * gp_ho - c * ep_hm + d * eo_gm) * invDet; - result.M33 = +(a * fp_hn - b * ep_hm + d * en_fm) * invDet; - result.M43 = -(a * fo_gn - b * eo_gm + c * en_fm) * invDet; - - float gl_hk = g * l - h * k; - float fl_hj = f * l - h * j; - float fk_gj = f * k - g * j; - float el_hi = e * l - h * i; - float ek_gi = e * k - g * i; - float ej_fi = e * j - f * i; - - result.M14 = -(b * gl_hk - c * fl_hj + d * fk_gj) * invDet; - result.M24 = +(a * gl_hk - c * el_hi + d * ek_gi) * invDet; - result.M34 = -(a * fl_hj - b * el_hi + d * ej_fi) * invDet; - result.M44 = +(a * fk_gj - b * ek_gi + c * ej_fi) * invDet; - - return true; + static bool SoftwareFallback(Matrix4x4 matrix, out Matrix4x4 result) + { + // -1 + // If you have matrix M, inverse Matrix M can compute + // + // -1 1 + // M = --------- A + // det(M) + // + // A is adjugate (adjoint) of M, where, + // + // T + // A = C + // + // C is Cofactor matrix of M, where, + // i + j + // C = (-1) * det(M ) + // ij ij + // + // [ a b c d ] + // M = [ e f g h ] + // [ i j k l ] + // [ m n o p ] + // + // First Row + // 2 | f g h | + // C = (-1) | j k l | = + ( f ( kp - lo ) - g ( jp - ln ) + h ( jo - kn ) ) + // 11 | n o p | + // + // 3 | e g h | + // C = (-1) | i k l | = - ( e ( kp - lo ) - g ( ip - lm ) + h ( io - km ) ) + // 12 | m o p | + // + // 4 | e f h | + // C = (-1) | i j l | = + ( e ( jp - ln ) - f ( ip - lm ) + h ( in - jm ) ) + // 13 | m n p | + // + // 5 | e f g | + // C = (-1) | i j k | = - ( e ( jo - kn ) - f ( io - km ) + g ( in - jm ) ) + // 14 | m n o | + // + // Second Row + // 3 | b c d | + // C = (-1) | j k l | = - ( b ( kp - lo ) - c ( jp - ln ) + d ( jo - kn ) ) + // 21 | n o p | + // + // 4 | a c d | + // C = (-1) | i k l | = + ( a ( kp - lo ) - c ( ip - lm ) + d ( io - km ) ) + // 22 | m o p | + // + // 5 | a b d | + // C = (-1) | i j l | = - ( a ( jp - ln ) - b ( ip - lm ) + d ( in - jm ) ) + // 23 | m n p | + // + // 6 | a b c | + // C = (-1) | i j k | = + ( a ( jo - kn ) - b ( io - km ) + c ( in - jm ) ) + // 24 | m n o | + // + // Third Row + // 4 | b c d | + // C = (-1) | f g h | = + ( b ( gp - ho ) - c ( fp - hn ) + d ( fo - gn ) ) + // 31 | n o p | + // + // 5 | a c d | + // C = (-1) | e g h | = - ( a ( gp - ho ) - c ( ep - hm ) + d ( eo - gm ) ) + // 32 | m o p | + // + // 6 | a b d | + // C = (-1) | e f h | = + ( a ( fp - hn ) - b ( ep - hm ) + d ( en - fm ) ) + // 33 | m n p | + // + // 7 | a b c | + // C = (-1) | e f g | = - ( a ( fo - gn ) - b ( eo - gm ) + c ( en - fm ) ) + // 34 | m n o | + // + // Fourth Row + // 5 | b c d | + // C = (-1) | f g h | = - ( b ( gl - hk ) - c ( fl - hj ) + d ( fk - gj ) ) + // 41 | j k l | + // + // 6 | a c d | + // C = (-1) | e g h | = + ( a ( gl - hk ) - c ( el - hi ) + d ( ek - gi ) ) + // 42 | i k l | + // + // 7 | a b d | + // C = (-1) | e f h | = - ( a ( fl - hj ) - b ( el - hi ) + d ( ej - fi ) ) + // 43 | i j l | + // + // 8 | a b c | + // C = (-1) | e f g | = + ( a ( fk - gj ) - b ( ek - gi ) + c ( ej - fi ) ) + // 44 | i j k | + // + // Cost of operation + // 53 adds, 104 muls, and 1 div. + float a = matrix.M11, b = matrix.M12, c = matrix.M13, d = matrix.M14; + float e = matrix.M21, f = matrix.M22, g = matrix.M23, h = matrix.M24; + float i = matrix.M31, j = matrix.M32, k = matrix.M33, l = matrix.M34; + float m = matrix.M41, n = matrix.M42, o = matrix.M43, p = matrix.M44; + + float kp_lo = k * p - l * o; + float jp_ln = j * p - l * n; + float jo_kn = j * o - k * n; + float ip_lm = i * p - l * m; + float io_km = i * o - k * m; + float in_jm = i * n - j * m; + + float a11 = +(f * kp_lo - g * jp_ln + h * jo_kn); + float a12 = -(e * kp_lo - g * ip_lm + h * io_km); + float a13 = +(e * jp_ln - f * ip_lm + h * in_jm); + float a14 = -(e * jo_kn - f * io_km + g * in_jm); + + float det = a * a11 + b * a12 + c * a13 + d * a14; + + if (MathF.Abs(det) < float.Epsilon) + { + result = new Matrix4x4(float.NaN, float.NaN, float.NaN, float.NaN, + float.NaN, float.NaN, float.NaN, float.NaN, + float.NaN, float.NaN, float.NaN, float.NaN, + float.NaN, float.NaN, float.NaN, float.NaN); + return false; + } + + float invDet = 1.0f / det; + + result.M11 = a11 * invDet; + result.M21 = a12 * invDet; + result.M31 = a13 * invDet; + result.M41 = a14 * invDet; + + result.M12 = -(b * kp_lo - c * jp_ln + d * jo_kn) * invDet; + result.M22 = +(a * kp_lo - c * ip_lm + d * io_km) * invDet; + result.M32 = -(a * jp_ln - b * ip_lm + d * in_jm) * invDet; + result.M42 = +(a * jo_kn - b * io_km + c * in_jm) * invDet; + + float gp_ho = g * p - h * o; + float fp_hn = f * p - h * n; + float fo_gn = f * o - g * n; + float ep_hm = e * p - h * m; + float eo_gm = e * o - g * m; + float en_fm = e * n - f * m; + + result.M13 = +(b * gp_ho - c * fp_hn + d * fo_gn) * invDet; + result.M23 = -(a * gp_ho - c * ep_hm + d * eo_gm) * invDet; + result.M33 = +(a * fp_hn - b * ep_hm + d * en_fm) * invDet; + result.M43 = -(a * fo_gn - b * eo_gm + c * en_fm) * invDet; + + float gl_hk = g * l - h * k; + float fl_hj = f * l - h * j; + float fk_gj = f * k - g * j; + float el_hi = e * l - h * i; + float ek_gi = e * k - g * i; + float ej_fi = e * j - f * i; + + result.M14 = -(b * gl_hk - c * fl_hj + d * fk_gj) * invDet; + result.M24 = +(a * gl_hk - c * el_hi + d * ek_gi) * invDet; + result.M34 = -(a * fl_hj - b * el_hi + d * ej_fi) * invDet; + result.M44 = +(a * fk_gj - b * ek_gi + c * ej_fi) * invDet; + + return true; + } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index f20b762afbf13f..4cfebe72cab69d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -10,13 +10,6 @@ using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nint = System.Int64; -#else -using nint = System.Int32; -#endif - namespace System.Numerics { /* Note: The following patterns are used throughout the code here and are described here @@ -91,12 +84,12 @@ public static Vector One } private static readonly Vector s_one = new Vector(GetOneValue()); - internal static Vector AllOnes + internal static Vector AllBitsSet { [Intrinsic] - get => s_allOnes; + get => s_allBitsSet; } - private static readonly Vector s_allOnes = new Vector(GetAllBitsSetValue()); + private static readonly Vector s_allBitsSet = new Vector(GetAllBitsSetValue()); #endregion Static Members #region Constructors @@ -485,11 +478,7 @@ public readonly unsafe T this[int index] [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object? obj) { - if (!(obj is Vector)) - { - return false; - } - return Equals((Vector)obj); + return (obj is Vector other) && Equals(other); } /// @@ -500,130 +489,7 @@ public override readonly bool Equals(object? obj) [Intrinsic] public readonly bool Equals(Vector other) { - if (Vector.IsHardwareAccelerated) - { - for (int g = 0; g < Count; g++) - { - if (!ScalarEquals(this[g], other[g])) - { - return false; - } - } - return true; - } - else - { - if (typeof(T) == typeof(byte)) - { - return - this.register.byte_0 == other.register.byte_0 - && this.register.byte_1 == other.register.byte_1 - && this.register.byte_2 == other.register.byte_2 - && this.register.byte_3 == other.register.byte_3 - && this.register.byte_4 == other.register.byte_4 - && this.register.byte_5 == other.register.byte_5 - && this.register.byte_6 == other.register.byte_6 - && this.register.byte_7 == other.register.byte_7 - && this.register.byte_8 == other.register.byte_8 - && this.register.byte_9 == other.register.byte_9 - && this.register.byte_10 == other.register.byte_10 - && this.register.byte_11 == other.register.byte_11 - && this.register.byte_12 == other.register.byte_12 - && this.register.byte_13 == other.register.byte_13 - && this.register.byte_14 == other.register.byte_14 - && this.register.byte_15 == other.register.byte_15; - } - else if (typeof(T) == typeof(sbyte)) - { - return - this.register.sbyte_0 == other.register.sbyte_0 - && this.register.sbyte_1 == other.register.sbyte_1 - && this.register.sbyte_2 == other.register.sbyte_2 - && this.register.sbyte_3 == other.register.sbyte_3 - && this.register.sbyte_4 == other.register.sbyte_4 - && this.register.sbyte_5 == other.register.sbyte_5 - && this.register.sbyte_6 == other.register.sbyte_6 - && this.register.sbyte_7 == other.register.sbyte_7 - && this.register.sbyte_8 == other.register.sbyte_8 - && this.register.sbyte_9 == other.register.sbyte_9 - && this.register.sbyte_10 == other.register.sbyte_10 - && this.register.sbyte_11 == other.register.sbyte_11 - && this.register.sbyte_12 == other.register.sbyte_12 - && this.register.sbyte_13 == other.register.sbyte_13 - && this.register.sbyte_14 == other.register.sbyte_14 - && this.register.sbyte_15 == other.register.sbyte_15; - } - else if (typeof(T) == typeof(ushort)) - { - return - this.register.uint16_0 == other.register.uint16_0 - && this.register.uint16_1 == other.register.uint16_1 - && this.register.uint16_2 == other.register.uint16_2 - && this.register.uint16_3 == other.register.uint16_3 - && this.register.uint16_4 == other.register.uint16_4 - && this.register.uint16_5 == other.register.uint16_5 - && this.register.uint16_6 == other.register.uint16_6 - && this.register.uint16_7 == other.register.uint16_7; - } - else if (typeof(T) == typeof(short)) - { - return - this.register.int16_0 == other.register.int16_0 - && this.register.int16_1 == other.register.int16_1 - && this.register.int16_2 == other.register.int16_2 - && this.register.int16_3 == other.register.int16_3 - && this.register.int16_4 == other.register.int16_4 - && this.register.int16_5 == other.register.int16_5 - && this.register.int16_6 == other.register.int16_6 - && this.register.int16_7 == other.register.int16_7; - } - else if (typeof(T) == typeof(uint)) - { - return - this.register.uint32_0 == other.register.uint32_0 - && this.register.uint32_1 == other.register.uint32_1 - && this.register.uint32_2 == other.register.uint32_2 - && this.register.uint32_3 == other.register.uint32_3; - } - else if (typeof(T) == typeof(int)) - { - return - this.register.int32_0 == other.register.int32_0 - && this.register.int32_1 == other.register.int32_1 - && this.register.int32_2 == other.register.int32_2 - && this.register.int32_3 == other.register.int32_3; - } - else if (typeof(T) == typeof(ulong)) - { - return - this.register.uint64_0 == other.register.uint64_0 - && this.register.uint64_1 == other.register.uint64_1; - } - else if (typeof(T) == typeof(long)) - { - return - this.register.int64_0 == other.register.int64_0 - && this.register.int64_1 == other.register.int64_1; - } - else if (typeof(T) == typeof(float)) - { - return - this.register.single_0 == other.register.single_0 - && this.register.single_1 == other.register.single_1 - && this.register.single_2 == other.register.single_2 - && this.register.single_3 == other.register.single_3; - } - else if (typeof(T) == typeof(double)) - { - return - this.register.double_0 == other.register.double_0 - && this.register.double_1 == other.register.double_1; - } - else - { - throw new NotSupportedException(SR.Arg_TypeNotSupported); - } - } + return this == other; } /// @@ -1729,7 +1595,7 @@ public readonly bool TryCopyTo(Span destination) /// The one's complement vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector operator ~(Vector value) => - s_allOnes ^ value; + AllBitsSet ^ value; #endregion Bitwise Operators #region Logical Operators @@ -1741,8 +1607,133 @@ public readonly bool TryCopyTo(Span destination) /// True if all elements are equal; False otherwise. [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Vector left, Vector right) => - left.Equals(right); + public static bool operator ==(Vector left, Vector right) + { + if (Vector.IsHardwareAccelerated) + { + for (int g = 0; g < Count; g++) + { + if (!ScalarEquals(left[g], right[g])) + { + return false; + } + } + return true; + } + else + { + if (typeof(T) == typeof(byte)) + { + return + left.register.byte_0 == right.register.byte_0 + && left.register.byte_1 == right.register.byte_1 + && left.register.byte_2 == right.register.byte_2 + && left.register.byte_3 == right.register.byte_3 + && left.register.byte_4 == right.register.byte_4 + && left.register.byte_5 == right.register.byte_5 + && left.register.byte_6 == right.register.byte_6 + && left.register.byte_7 == right.register.byte_7 + && left.register.byte_8 == right.register.byte_8 + && left.register.byte_9 == right.register.byte_9 + && left.register.byte_10 == right.register.byte_10 + && left.register.byte_11 == right.register.byte_11 + && left.register.byte_12 == right.register.byte_12 + && left.register.byte_13 == right.register.byte_13 + && left.register.byte_14 == right.register.byte_14 + && left.register.byte_15 == right.register.byte_15; + } + else if (typeof(T) == typeof(sbyte)) + { + return + left.register.sbyte_0 == right.register.sbyte_0 + && left.register.sbyte_1 == right.register.sbyte_1 + && left.register.sbyte_2 == right.register.sbyte_2 + && left.register.sbyte_3 == right.register.sbyte_3 + && left.register.sbyte_4 == right.register.sbyte_4 + && left.register.sbyte_5 == right.register.sbyte_5 + && left.register.sbyte_6 == right.register.sbyte_6 + && left.register.sbyte_7 == right.register.sbyte_7 + && left.register.sbyte_8 == right.register.sbyte_8 + && left.register.sbyte_9 == right.register.sbyte_9 + && left.register.sbyte_10 == right.register.sbyte_10 + && left.register.sbyte_11 == right.register.sbyte_11 + && left.register.sbyte_12 == right.register.sbyte_12 + && left.register.sbyte_13 == right.register.sbyte_13 + && left.register.sbyte_14 == right.register.sbyte_14 + && left.register.sbyte_15 == right.register.sbyte_15; + } + else if (typeof(T) == typeof(ushort)) + { + return + left.register.uint16_0 == right.register.uint16_0 + && left.register.uint16_1 == right.register.uint16_1 + && left.register.uint16_2 == right.register.uint16_2 + && left.register.uint16_3 == right.register.uint16_3 + && left.register.uint16_4 == right.register.uint16_4 + && left.register.uint16_5 == right.register.uint16_5 + && left.register.uint16_6 == right.register.uint16_6 + && left.register.uint16_7 == right.register.uint16_7; + } + else if (typeof(T) == typeof(short)) + { + return + left.register.int16_0 == right.register.int16_0 + && left.register.int16_1 == right.register.int16_1 + && left.register.int16_2 == right.register.int16_2 + && left.register.int16_3 == right.register.int16_3 + && left.register.int16_4 == right.register.int16_4 + && left.register.int16_5 == right.register.int16_5 + && left.register.int16_6 == right.register.int16_6 + && left.register.int16_7 == right.register.int16_7; + } + else if (typeof(T) == typeof(uint)) + { + return + left.register.uint32_0 == right.register.uint32_0 + && left.register.uint32_1 == right.register.uint32_1 + && left.register.uint32_2 == right.register.uint32_2 + && left.register.uint32_3 == right.register.uint32_3; + } + else if (typeof(T) == typeof(int)) + { + return + left.register.int32_0 == right.register.int32_0 + && left.register.int32_1 == right.register.int32_1 + && left.register.int32_2 == right.register.int32_2 + && left.register.int32_3 == right.register.int32_3; + } + else if (typeof(T) == typeof(ulong)) + { + return + left.register.uint64_0 == right.register.uint64_0 + && left.register.uint64_1 == right.register.uint64_1; + } + else if (typeof(T) == typeof(long)) + { + return + left.register.int64_0 == right.register.int64_0 + && left.register.int64_1 == right.register.int64_1; + } + else if (typeof(T) == typeof(float)) + { + return + left.register.single_0 == right.register.single_0 + && left.register.single_1 == right.register.single_1 + && left.register.single_2 == right.register.single_2 + && left.register.single_3 == right.register.single_3; + } + else if (typeof(T) == typeof(double)) + { + return + left.register.double_0 == right.register.double_0 + && left.register.double_1 == right.register.double_1; + } + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } /// /// Returns a boolean indicating whether any single pair of elements in the given vectors are not equal. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.tt b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.tt index 3c02ba2bebac02..b556656e918c49 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.tt +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.tt @@ -15,13 +15,6 @@ using System.Text; using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nint = System.Int64; -#else -using nint = System.Int32; -#endif - namespace System.Numerics { /* Note: The following patterns are used throughout the code here and are described here @@ -96,12 +89,12 @@ namespace System.Numerics } private static readonly Vector s_one = new Vector(GetOneValue()); - internal static Vector AllOnes + internal static Vector AllBitsSet { [Intrinsic] - get => s_allOnes; + get => s_allBitsSet; } - private static readonly Vector s_allOnes = new Vector(GetAllBitsSetValue()); + private static readonly Vector s_allBitsSet = new Vector(GetAllBitsSetValue()); #endregion Static Members #region Constructors @@ -329,11 +322,7 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object? obj) { - if (!(obj is Vector)) - { - return false; - } - return Equals((Vector)obj); + return (obj is Vector other) && Equals(other); } /// @@ -344,56 +333,7 @@ namespace System.Numerics [Intrinsic] public readonly bool Equals(Vector other) { - if (Vector.IsHardwareAccelerated) - { - for (int g = 0; g < Count; g++) - { - if (!ScalarEquals(this[g], other[g])) - { - return false; - } - } - return true; - } - else - { -<# - foreach (Type type in supportedTypes) - { -#> - <#=GenerateIfStatementHeader(type)#> - { - return -<# - for (int g = 0; g < GetNumFields(type, totalSize); g++) - { -#> -<# - if (g == 0) - { -#> - this.<#=GetRegisterFieldName(type, g)#> == other.<#=GetRegisterFieldName(type, g)#> -<# - } - else - { -#> - && this.<#=GetRegisterFieldName(type, g)#> == other.<#=GetRegisterFieldName(type, g)#><#=(g == (GetNumFields(type, totalSize) -1)) ? ";" : ""#> -<# - } -#> -<# - } -#> - } -<# - } -#> - else - { - throw new NotSupportedException(SR.Arg_TypeNotSupported); - } - } + return this == other; } /// @@ -891,7 +831,7 @@ namespace System.Numerics /// The one's complement vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector operator ~(Vector value) => - s_allOnes ^ value; + AllBitsSet ^ value; #endregion Bitwise Operators #region Logical Operators @@ -903,8 +843,59 @@ namespace System.Numerics /// True if all elements are equal; False otherwise. [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Vector left, Vector right) => - left.Equals(right); + public static bool operator ==(Vector left, Vector right) + { + if (Vector.IsHardwareAccelerated) + { + for (int g = 0; g < Count; g++) + { + if (!ScalarEquals(left[g], right[g])) + { + return false; + } + } + return true; + } + else + { +<# + foreach (Type type in supportedTypes) + { +#> + <#=GenerateIfStatementHeader(type)#> + { + return +<# + for (int g = 0; g < GetNumFields(type, totalSize); g++) + { +#> +<# + if (g == 0) + { +#> + left.<#=GetRegisterFieldName(type, g)#> == right.<#=GetRegisterFieldName(type, g)#> +<# + } + else + { +#> + && left.<#=GetRegisterFieldName(type, g)#> == right.<#=GetRegisterFieldName(type, g)#><#=(g == (GetNumFields(type, totalSize) -1)) ? ";" : ""#> +<# + } +#> +<# + } +#> + } +<# + } +#> + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } /// /// Returns a boolean indicating whether any single pair of elements in the given vectors are not equal. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs index 10bdc32eba503f..cee4a0e4ca66a0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs @@ -65,9 +65,7 @@ public override readonly int GetHashCode() [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object? obj) { - if (!(obj is Vector2)) - return false; - return Equals((Vector2)obj); + return (obj is Vector2 other) && Equals(other); } /// @@ -193,17 +191,8 @@ public static Vector2 Reflect(Vector2 vector, Vector2 normal) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max) { - // This compare order is very important!!! // We must follow HLSL behavior in the case user specified min value is bigger than max value. - float x = value1.X; - x = (min.X > x) ? min.X : x; // max(x, minx) - x = (max.X < x) ? max.X : x; // min(x, maxx) - - float y = value1.Y; - y = (min.Y > y) ? min.Y : y; // max(y, miny) - y = (max.Y < y) ? max.Y : y; // min(y, maxy) - - return new Vector2(x, y); + return Vector2.Min(Vector2.Max(value1, min), max); } /// @@ -216,9 +205,7 @@ public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Lerp(Vector2 value1, Vector2 value2, float amount) { - return new Vector2( - value1.X + (value2.X - value1.X) * amount, - value1.Y + (value2.Y - value1.Y) * amount); + return value1 + (value2 - value1) * amount; } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2_Intrinsics.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2_Intrinsics.cs index b2d58347904e5f..b776c5d0a3cad8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2_Intrinsics.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2_Intrinsics.cs @@ -91,7 +91,7 @@ public readonly void CopyTo(float[] array, int index) [Intrinsic] public readonly bool Equals(Vector2 other) { - return this.X == other.X && this.Y == other.Y; + return this == other; } #endregion Public Instance Methods @@ -211,7 +211,6 @@ public static Vector2 SquareRoot(Vector2 value) /// The scalar value. /// The source vector. /// The scaled vector. - [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 operator *(float left, Vector2 right) { @@ -224,7 +223,6 @@ public static Vector2 SquareRoot(Vector2 value) /// The source vector. /// The scalar value. /// The scaled vector. - [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 operator *(Vector2 left, float right) { @@ -277,7 +275,8 @@ public static Vector2 SquareRoot(Vector2 value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Vector2 left, Vector2 right) { - return left.Equals(right); + return left.X == right.X && + left.Y == right.Y; } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs index a1e5c8c81d4e7e..1ca945caa5bf5f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs @@ -70,9 +70,7 @@ public override readonly int GetHashCode() [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object? obj) { - if (!(obj is Vector3)) - return false; - return Equals((Vector3)obj); + return (obj is Vector3 other) && Equals(other); } /// @@ -218,21 +216,8 @@ public static Vector3 Reflect(Vector3 vector, Vector3 normal) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Clamp(Vector3 value1, Vector3 min, Vector3 max) { - // This compare order is very important!!! // We must follow HLSL behavior in the case user specified min value is bigger than max value. - float x = value1.X; - x = (min.X > x) ? min.X : x; // max(x, minx) - x = (max.X < x) ? max.X : x; // min(x, maxx) - - float y = value1.Y; - y = (min.Y > y) ? min.Y : y; // max(y, miny) - y = (max.Y < y) ? max.Y : y; // min(y, maxy) - - float z = value1.Z; - z = (min.Z > z) ? min.Z : z; // max(z, minz) - z = (max.Z < z) ? max.Z : z; // min(z, maxz) - - return new Vector3(x, y, z); + return Vector3.Min(Vector3.Max(value1, min), max); } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3_Intrinsics.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3_Intrinsics.cs index c41baa46aa8f71..3ff9a8aa6525ad 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3_Intrinsics.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3_Intrinsics.cs @@ -106,9 +106,7 @@ public readonly void CopyTo(float[] array, int index) [Intrinsic] public readonly bool Equals(Vector3 other) { - return X == other.X && - Y == other.Y && - Z == other.Z; + return this == other; } #endregion Public Instance Methods @@ -230,7 +228,6 @@ public static Vector3 SquareRoot(Vector3 value) /// The source vector. /// The scalar value. /// The scaled vector. - [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator *(Vector3 left, float right) { @@ -243,7 +240,6 @@ public static Vector3 SquareRoot(Vector3 value) /// The scalar value. /// The source vector. /// The scaled vector. - [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator *(float left, Vector3 right) { @@ -296,9 +292,9 @@ public static Vector3 SquareRoot(Vector3 value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Vector3 left, Vector3 right) { - return (left.X == right.X && - left.Y == right.Y && - left.Z == right.Z); + return left.X == right.X && + left.Y == right.Y && + left.Z == right.Z; } /// @@ -311,9 +307,7 @@ public static Vector3 SquareRoot(Vector3 value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Vector3 left, Vector3 right) { - return (left.X != right.X || - left.Y != right.Y || - left.Z != right.Z); + return !(left == right); } #endregion Public Static Operators } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs index b240061551def1..c6dc6a8de8c4f5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs @@ -73,9 +73,7 @@ public override readonly int GetHashCode() [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly bool Equals(object? obj) { - if (!(obj is Vector4)) - return false; - return Equals((Vector4)obj); + return (obj is Vector4 other) && Equals(other); } /// @@ -195,25 +193,8 @@ public static Vector4 Normalize(Vector4 vector) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Clamp(Vector4 value1, Vector4 min, Vector4 max) { - // This compare order is very important!!! // We must follow HLSL behavior in the case user specified min value is bigger than max value. - float x = value1.X; - x = (min.X > x) ? min.X : x; // max(x, minx) - x = (max.X < x) ? max.X : x; // min(x, maxx) - - float y = value1.Y; - y = (min.Y > y) ? min.Y : y; // max(y, miny) - y = (max.Y < y) ? max.Y : y; // min(y, maxy) - - float z = value1.Z; - z = (min.Z > z) ? min.Z : z; // max(z, minz) - z = (max.Z < z) ? max.Z : z; // min(z, maxz) - - float w = value1.W; - w = (min.W > w) ? min.W : w; // max(w, minw) - w = (max.W < w) ? max.W : w; // min(w, minw) - - return new Vector4(x, y, z, w); + return Vector4.Min(Vector4.Max(value1, min), max); } /// @@ -226,11 +207,7 @@ public static Vector4 Clamp(Vector4 value1, Vector4 min, Vector4 max) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Lerp(Vector4 value1, Vector4 value2, float amount) { - return new Vector4( - value1.X + (value2.X - value1.X) * amount, - value1.Y + (value2.Y - value1.Y) * amount, - value1.Z + (value2.Z - value1.Z) * amount, - value1.W + (value2.W - value1.W) * amount); + return value1 + (value2 - value1) * amount; } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4_Intrinsics.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4_Intrinsics.cs index 440c78882d44a4..4e95120c244c9e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4_Intrinsics.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4_Intrinsics.cs @@ -136,10 +136,7 @@ public readonly void CopyTo(float[] array, int index) [Intrinsic] public readonly bool Equals(Vector4 other) { - return this.X == other.X - && this.Y == other.Y - && this.Z == other.Z - && this.W == other.W; + return this == other; } #endregion Public Instance Methods @@ -265,7 +262,6 @@ public static Vector4 SquareRoot(Vector4 value) /// The source vector. /// The scalar value. /// The scaled vector. - [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 operator *(Vector4 left, float right) { @@ -278,7 +274,6 @@ public static Vector4 SquareRoot(Vector4 value) /// The scalar value. /// The source vector. /// The scaled vector. - [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 operator *(float left, Vector4 right) { @@ -331,7 +326,10 @@ public static Vector4 SquareRoot(Vector4 value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Vector4 left, Vector4 right) { - return left.Equals(right); + return left.X == right.X + && left.Y == right.Y + && left.Z == right.Z + && left.W == right.W; } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_Operations.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_Operations.cs index f16d1c4fc57775..4d97d1ad70caa6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_Operations.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_Operations.cs @@ -230,7 +230,7 @@ public static Vector LessThan(Vector left, Vector right) public static bool LessThanAll(Vector left, Vector right) where T : struct { Vector cond = (Vector)Vector.LessThan(left, right); - return cond.Equals(Vector.AllOnes); + return cond.Equals(Vector.AllBitsSet); } /// @@ -328,7 +328,7 @@ public static Vector LessThanOrEqual(Vector left, Vector r public static bool LessThanOrEqualAll(Vector left, Vector right) where T : struct { Vector cond = (Vector)Vector.LessThanOrEqual(left, right); - return cond.Equals(Vector.AllOnes); + return cond.Equals(Vector.AllBitsSet); } /// @@ -427,7 +427,7 @@ public static Vector GreaterThan(Vector left, Vector right) public static bool GreaterThanAll(Vector left, Vector right) where T : struct { Vector cond = (Vector)Vector.GreaterThan(left, right); - return cond.Equals(Vector.AllOnes); + return cond.Equals(Vector.AllBitsSet); } /// @@ -526,7 +526,7 @@ public static Vector GreaterThanOrEqual(Vector left, Vector(Vector left, Vector right) where T : struct { Vector cond = (Vector)Vector.GreaterThanOrEqual(left, right); - return cond.Equals(Vector.AllOnes); + return cond.Equals(Vector.AllBitsSet); } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs b/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs index 77552dea34750a..c66cd3b699a564 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs @@ -12,13 +12,6 @@ using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else // TARGET_64BIT -using nuint = System.UInt32; -#endif // TARGET_64BIT - namespace System { /// @@ -286,7 +279,7 @@ public unsafe ReadOnlySpan Span ThrowHelper.ThrowArgumentOutOfRangeException(); } #else - if ((uint)desiredStartIndex > (uint)lengthOfUnderlyingSpan || (uint)desiredLength > (uint)(lengthOfUnderlyingSpan - desiredStartIndex)) + if ((uint)desiredStartIndex > (uint)lengthOfUnderlyingSpan || (uint)desiredLength > (uint)lengthOfUnderlyingSpan - (uint)desiredStartIndex) { ThrowHelper.ThrowArgumentOutOfRangeException(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs b/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs index a765967f5f87a8..7ce5284ad2d33f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs @@ -13,13 +13,6 @@ #pragma warning disable 0809 //warning CS0809: Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameFormatter.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameFormatter.cs index 09585f8d58f197..3ead4ce8e87f39 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameFormatter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameFormatter.cs @@ -54,7 +54,7 @@ public static string ComputeDisplayName(string? name, Version? version, string? if (cultureName != null) { - if (cultureName == string.Empty) + if (cultureName.Length == 0) cultureName = "neutral"; sb.Append(", Culture="); sb.AppendQuoted(cultureName); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInfo.cs index 622ba56e44fe69..12412fe536eebd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInfo.cs @@ -26,6 +26,12 @@ protected MethodInfo() { } public virtual Delegate CreateDelegate(Type delegateType) { throw new NotSupportedException(SR.NotSupported_SubclassOverride); } public virtual Delegate CreateDelegate(Type delegateType, object? target) { throw new NotSupportedException(SR.NotSupported_SubclassOverride); } + /// Creates a delegate of the given type 'T' from this method. + public T CreateDelegate() where T : Delegate => (T)CreateDelegate(typeof(T)); + + /// Creates a delegate of the given type 'T' with the specified target from this method. + public T CreateDelegate(object? target) where T : Delegate => (T)CreateDelegate(typeof(T), target); + public override bool Equals(object? obj) => base.Equals(obj); public override int GetHashCode() => base.GetHashCode(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceManager.cs b/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceManager.cs index 4ab1ecf19efc80..8e3dbf95fcf307 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceManager.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceManager.cs @@ -2,11 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.IO; -using System.Globalization; -using System.Reflection; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Reflection; namespace System.Resources { @@ -120,7 +121,7 @@ internal class CultureNameResourceSetPair private Version? _satelliteContractVersion; private bool _lookedForSatelliteContractVersion; - private IResourceGroveler _resourceGroveler = null!; + private IResourceGroveler _resourceGroveler; public static readonly int MagicNumber = unchecked((int)0xBEEFCACE); // If only hex had a K... @@ -234,6 +235,7 @@ public ResourceManager(Type resourceSource) // Trying to unify code as much as possible, even though having to do a // security check in each constructor prevents it. + [MemberNotNull(nameof(_resourceGroveler))] private void CommonAssemblyInit() { #if FEATURE_APPX diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs index 8aefd8a1773fd5..e195976f1f8c53 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncTaskMethodBuilderT.cs @@ -60,7 +60,7 @@ public void AwaitOnCompleted( AwaitOnCompleted(ref awaiter, ref stateMachine, ref m_task); internal static void AwaitOnCompleted( - ref TAwaiter awaiter, ref TStateMachine stateMachine, [NotNull] ref Task? taskField) + ref TAwaiter awaiter, ref TStateMachine stateMachine, ref Task? taskField) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs index d2bd7ec111a4b4..c298c0533d57c7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilderT.cs @@ -150,7 +150,7 @@ public void AwaitOnCompleted(ref TAwaiter awaiter, ref } internal static void AwaitOnCompleted( - ref TAwaiter awaiter, ref TStateMachine stateMachine, [NotNull] ref StateMachineBox? box) + ref TAwaiter awaiter, ref TStateMachine stateMachine, ref StateMachineBox? box) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs index 78d70e7703c64b..bf5edf4774c9ea 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs @@ -105,7 +105,7 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b } else if (obj != null) { - Unsafe.As(obj).OnCompleted(ThreadPoolGlobals.s_invokeAsyncStateMachineBox, box, _value._token, + Unsafe.As(obj).OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token, _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); } else @@ -210,7 +210,7 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b } else if (obj != null) { - Unsafe.As>(obj).OnCompleted(ThreadPoolGlobals.s_invokeAsyncStateMachineBox, box, _value._token, + Unsafe.As>(obj).OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token, _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); } else diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/SkipLocalsInitAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/SkipLocalsInitAttribute.cs index fef7f11749863f..349c12ace69c43 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/SkipLocalsInitAttribute.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/SkipLocalsInitAttribute.cs @@ -21,6 +21,7 @@ namespace System.Runtime.CompilerServices [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct + | AttributeTargets.Interface | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property @@ -31,4 +32,4 @@ public SkipLocalsInitAttribute() { } } -} \ No newline at end of file +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs index 07f9441518584a..ca7a0a0ca742e3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs @@ -95,7 +95,7 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b } else if (obj != null) { - Unsafe.As(obj).OnCompleted(ThreadPoolGlobals.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + Unsafe.As(obj).OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); } else { @@ -177,7 +177,7 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b } else if (obj != null) { - Unsafe.As>(obj).OnCompleted(ThreadPoolGlobals.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + Unsafe.As>(obj).OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); } else { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ArrayWithOffset.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ArrayWithOffset.cs index 2413cacd01d02b..736259d2334f8a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ArrayWithOffset.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ArrayWithOffset.cs @@ -4,13 +4,6 @@ using System.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System.Runtime.InteropServices { public struct ArrayWithOffset diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CallingConvention.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CallingConvention.cs index 3b18fdee3a8b57..1b515eda819103 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CallingConvention.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/CallingConvention.cs @@ -4,7 +4,7 @@ namespace System.Runtime.InteropServices { - // Used for the CallingConvention named argument to the DllImport and NativeCallable attribute + // Used for the CallingConvention named argument to the DllImport and UnmanagedCallersOnly attribute public enum CallingConvention { Winapi = 1, diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.PlatformNotSupported.cs index 05764b08bac53c..d78f3d6681fac7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.PlatformNotSupported.cs @@ -62,7 +62,12 @@ public object GetOrRegisterObjectForComInstance(IntPtr externalComObject, Create protected abstract void ReleaseObjects(IEnumerable objects); - public void RegisterAsGlobalInstance() + public static void RegisterForTrackerSupport(ComWrappers instance) + { + throw new PlatformNotSupportedException(); + } + + public static void RegisterForMarshalling(ComWrappers instance) { throw new PlatformNotSupportedException(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.cs index b7bd0361d53cca..c163c364771d4b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.cs @@ -7,13 +7,6 @@ using System.Threading; using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nint = System.Int64; -#else -using nint = System.Int32; -#endif - namespace System.Runtime.InteropServices { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs index 227e84e71c2fac..76aab4ab2c4b18 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs @@ -10,13 +10,6 @@ using Internal.Runtime.CompilerServices; using System.Diagnostics.CodeAnalysis; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System.Runtime.InteropServices { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeCallableAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeCallableAttribute.cs deleted file mode 100644 index 459815f8e8ca70..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeCallableAttribute.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace System.Runtime.InteropServices -{ - /// - /// Any method marked with can be directly called from - /// native code. The function token can be loaded to a local variable using the address-of operator - /// in C# and passed as a callback to a native method. - /// - /// - /// Methods marked with this attribute have the following restrictions: - /// * Method must be marked "static". - /// * Must not be called from managed code. - /// * Must only have blittable arguments. - /// - [AttributeUsage(AttributeTargets.Method)] - public sealed class NativeCallableAttribute : Attribute - { - public NativeCallableAttribute() - { - } - - /// - /// Optional. If omitted, the runtime will use the default platform calling convention. - /// - public CallingConvention CallingConvention; - - /// - /// Optional. If omitted, then the method is native callable, but no export is emitted during compilation. - /// - public string? EntryPoint; - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/UnmanagedCallersOnlyAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/UnmanagedCallersOnlyAttribute.cs new file mode 100644 index 00000000000000..4acf93de994752 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/UnmanagedCallersOnlyAttribute.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Runtime.InteropServices +{ + /// + /// Any method marked with can be directly called from + /// native code. The function token can be loaded to a local variable using the address-of operator + /// in C# and passed as a callback to a native method. + /// + /// + /// Methods marked with this attribute have the following restrictions: + /// * Method must be marked "static". + /// * Must not be called from managed code. + /// * Must only have blittable arguments. + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class UnmanagedCallersOnlyAttribute : Attribute + { + public UnmanagedCallersOnlyAttribute() + { + } + + /// + /// Optional. If omitted, the runtime will use the default platform calling convention. + /// + public CallingConvention CallingConvention; + + /// + /// Optional. If omitted, no named export is emitted during compilation. + /// + public string? EntryPoint; + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs index 07c6b312336764..080c7b1f5d1fb2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs @@ -338,6 +338,42 @@ internal Arm64() { } /// public static Vector64 AddPairwiseScalar(Vector128 value) { throw new PlatformNotSupportedException(); } + /// + /// uint8_t vqaddb_u8 (uint8_t a, uint8_t b) + /// A64: UQADD Bd, Bn, Bm + /// + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16_t vqaddh_s16 (int16_t a, int16_t b) + /// A64: SQADD Hd, Hn, Hm + /// + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32_t vqadds_s32 (int32_t a, int32_t b) + /// A64: SQADD Sd, Sn, Sm + /// + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8_t vqaddb_s8 (int8_t a, int8_t b) + /// A64: SQADD Bd, Bn, Bm + /// + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vqaddh_u16 (uint16_t a, uint16_t b) + /// A64: UQADD Hd, Hn, Hm + /// + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vqadds_u32 (uint32_t a, uint32_t b) + /// A64: UQADD Sd, Sn, Sm + /// + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + /// /// uint64x2_t vceqq_f64 (float64x2_t a, float64x2_t b) /// A64: FCMEQ Vd.2D, Vn.2D, Vm.2D @@ -604,6 +640,42 @@ internal Arm64() { } /// public static Vector128 Divide(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// + /// float64x2_t vdupq_laneq_f64 (float64x2_t vec, const int lane) + /// A64: DUP Vd.2D, Vn.D[index] + /// + public static System.Runtime.Intrinsics.Vector128 DuplicateSelectedScalarToVector128(System.Runtime.Intrinsics.Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vdupq_laneq_s64 (int64x2_t vec, const int lane) + /// A64: DUP Vd.2D, Vn.D[index] + /// + public static System.Runtime.Intrinsics.Vector128 DuplicateSelectedScalarToVector128(System.Runtime.Intrinsics.Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vdupq_laneq_u64 (uint64x2_t vec, const int lane) + /// A64: DUP Vd.2D, Vn.D[index] + /// + public static System.Runtime.Intrinsics.Vector128 DuplicateSelectedScalarToVector128(System.Runtime.Intrinsics.Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vdupq_n_f64 (float64_t value) + /// A64: DUP Vd.2D, Vn.D[0] + /// + public static Vector128 DuplicateToVector128(double value) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vdupq_n_s64 (int64_t value) + /// A64: DUP Vd.2D, Rn + /// + public static Vector128 DuplicateToVector128(long value) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vdupq_n_s64 (uint64_t value) + /// A64: DUP Vd.2D, Rn + /// + public static Vector128 DuplicateToVector128(ulong value) { throw new PlatformNotSupportedException(); } + /// /// float64x2_t vfmaq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) /// A64: FMLA Vd.2D, Vn.2D, Vm.2D @@ -1128,6 +1200,312 @@ internal Arm64() { } /// public static Vector64 ReciprocalStepScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + /// + /// int16_t vqrshlh_s16 (int16_t a, int16_t b) + /// A64: SQRSHL Hd, Hn, Hm + /// + public static Vector64 ShiftArithmeticRoundedSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// int32_t vqrshls_s32 (int32_t a, int32_t b) + /// A64: SQRSHL Sd, Sn, Sm + /// + public static Vector64 ShiftArithmeticRoundedSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// int8_t vqrshlb_s8 (int8_t a, int8_t b) + /// A64: SQRSHL Bd, Bn, Bm + /// + public static Vector64 ShiftArithmeticRoundedSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// int16_t vqshlh_s16 (int16_t a, int16_t b) + /// A64: SQSHL Hd, Hn, Hm + /// + public static Vector64 ShiftArithmeticSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// int32_t vqshls_s32 (int32_t a, int32_t b) + /// A64: SQSHL Sd, Sn, Sm + /// + public static Vector64 ShiftArithmeticSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// int8_t vqshlb_s8 (int8_t a, int8_t b) + /// A64: SQSHL Bd, Bn, Bm + /// + public static Vector64 ShiftArithmeticSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vqshlb_n_u8 (uint8_t a, const int n) + /// A64: UQSHL Bd, Bn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// int16_t vqshlh_n_s16 (int16_t a, const int n) + /// A64: SQSHL Hd, Hn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// int32_t vqshls_n_s32 (int32_t a, const int n) + /// A64: SQSHL Sd, Sn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// int8_t vqshlb_n_s8 (int8_t a, const int n) + /// A64: SQSHL Bd, Bn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vqshlh_n_u16 (uint16_t a, const int n) + /// A64: UQSHL Hd, Hn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vqshls_n_u32 (uint32_t a, const int n) + /// A64: UQSHL Sd, Sn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vqshluh_n_s16 (int16_t a, const int n) + /// A64: SQSHLU Hd, Hn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateUnsignedScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vqshlus_n_s32 (int32_t a, const int n) + /// A64: SQSHLU Sd, Sn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateUnsignedScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vqshlub_n_s8 (int8_t a, const int n) + /// A64: SQSHLU Bd, Bn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateUnsignedScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vqrshlb_u8 (uint8_t a, int8_t b) + /// A64: UQRSHL Bd, Bn, Bm + /// + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vqrshlh_u16 (uint16_t a, int16_t b) + /// A64: UQRSHL Hd, Hn, Hm + /// + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vqrshls_u32 (uint32_t a, int32_t b) + /// A64: UQRSHL Sd, Sn, Sm + /// + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vqrshlb_u8 (uint8_t a, int8_t b) + /// A64: UQRSHL Bd, Bn, Bm + /// + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vqrshlh_u16 (uint16_t a, int16_t b) + /// A64: UQRSHL Hd, Hn, Hm + /// + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vqrshls_u32 (uint32_t a, int32_t b) + /// A64: UQRSHL Sd, Sn, Sm + /// + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vqshlb_u8 (uint8_t a, int8_t b) + /// A64: UQSHL Bd, Bn, Bm + /// + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vqshlh_u16 (uint16_t a, int16_t b) + /// A64: UQSHL Hd, Hn, Hm + /// + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vqshls_u32 (uint32_t a, int32_t b) + /// A64: UQSHL Sd, Sn, Sm + /// + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vqshlb_u8 (uint8_t a, int8_t b) + /// A64: UQSHL Bd, Bn, Bm + /// + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vqshlh_u16 (uint16_t a, int16_t b) + /// A64: UQSHL Hd, Hn, Hm + /// + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vqshls_u32 (uint32_t a, int32_t b) + /// A64: UQSHL Sd, Sn, Sm + /// + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } + + /// + /// int16_t vqshrns_n_s32 (int32_t a, const int n) + /// A64: SQSHRN Hd, Sn, #n + /// + public static Vector64 ShiftRightArithmeticNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// int32_t vqshrnd_n_s64 (int64_t a, const int n) + /// A64: SQSHRN Sd, Dn, #n + /// + public static Vector64 ShiftRightArithmeticNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// int8_t vqshrnh_n_s16 (int16_t a, const int n) + /// A64: SQSHRN Bd, Hn, #n + /// + public static Vector64 ShiftRightArithmeticNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vqshrunh_n_s16 (int16_t a, const int n) + /// A64: SQSHRUN Bd, Hn, #n + /// + public static Vector64 ShiftRightArithmeticNarrowingSaturateUnsignedScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vqshruns_n_s32 (int32_t a, const int n) + /// A64: SQSHRUN Hd, Sn, #n + /// + public static Vector64 ShiftRightArithmeticNarrowingSaturateUnsignedScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vqshrund_n_s64 (int64_t a, const int n) + /// A64: SQSHRUN Sd, Dn, #n + /// + public static Vector64 ShiftRightArithmeticNarrowingSaturateUnsignedScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// int16_t vqrshrns_n_s32 (int32_t a, const int n) + /// A64: SQRSHRN Hd, Sn, #n + /// + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// int32_t vqrshrnd_n_s64 (int64_t a, const int n) + /// A64: SQRSHRN Sd, Dn, #n + /// + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// int8_t vqrshrnh_n_s16 (int16_t a, const int n) + /// A64: SQRSHRN Bd, Hn, #n + /// + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vqrshrunh_n_s16 (int16_t a, const int n) + /// A64: SQRSHRUN Bd, Hn, #n + /// + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vqrshruns_n_s32 (int32_t a, const int n) + /// A64: SQRSHRUN Hd, Sn, #n + /// + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vqrshrund_n_s64 (int64_t a, const int n) + /// A64: SQRSHRUN Sd, Dn, #n + /// + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vqshrnh_n_u16 (uint16_t a, const int n) + /// A64: UQSHRN Bd, Hn, #n + /// + public static Vector64 ShiftRightLogicalNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vqshrns_n_u32 (uint32_t a, const int n) + /// A64: UQSHRN Hd, Sn, #n + /// + public static Vector64 ShiftRightLogicalNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vqshrnd_n_u64 (uint64_t a, const int n) + /// A64: UQSHRN Sd, Dn, #n + /// + public static Vector64 ShiftRightLogicalNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vqshrnh_n_u16 (uint16_t a, const int n) + /// A64: UQSHRN Bd, Hn, #n + /// + public static Vector64 ShiftRightLogicalNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vqshrns_n_u32 (uint32_t a, const int n) + /// A64: UQSHRN Hd, Sn, #n + /// + public static Vector64 ShiftRightLogicalNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vqshrnd_n_u64 (uint64_t a, const int n) + /// A64: UQSHRN Sd, Dn, #n + /// + public static Vector64 ShiftRightLogicalNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vqrshrnh_n_u16 (uint16_t a, const int n) + /// A64: UQRSHRN Bd, Hn, #n + /// + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vqrshrns_n_u32 (uint32_t a, const int n) + /// A64: UQRSHRN Hd, Sn, #n + /// + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vqrshrnd_n_u64 (uint64_t a, const int n) + /// A64: UQRSHRN Sd, Dn, #n + /// + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vqrshrnh_n_u16 (uint16_t a, const int n) + /// A64: UQRSHRN Bd, Hn, #n + /// + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vqrshrns_n_u32 (uint32_t a, const int n) + /// A64: UQRSHRN Hd, Sn, #n + /// + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vqrshrnd_n_u64 (uint64_t a, const int n) + /// A64: UQRSHRN Sd, Dn, #n + /// + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + /// /// float32x2_t vsqrt_f32 (float32x2_t a) /// A64: FSQRT Vd.2S, Vn.2S @@ -1152,6 +1530,42 @@ internal Arm64() { } /// public static Vector128 Subtract(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// + /// uint8_t vqsubb_u8 (uint8_t a, uint8_t b) + /// A64: UQSUB Bd, Bn, Bm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16_t vqsubh_s16 (int16_t a, int16_t b) + /// A64: SQSUB Hd, Hn, Hm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32_t vqsubs_s32 (int32_t a, int32_t b) + /// A64: SQSUB Sd, Sn, Sm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8_t vqsubb_s8 (int8_t a, int8_t b) + /// A64: SQSUB Bd, Bn, Bm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vqsubh_u16 (uint16_t a, uint16_t b) + /// A64: UQSUB Hd, Hn, Hm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vqsubs_u32 (uint32_t a, uint32_t b) + /// A64: UQSUB Sd, Sn, Sm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + /// /// uint8x8_t vrbit_u8 (uint8x8_t a) /// A64: RBIT Vd.8B, Vn.8B @@ -1584,6 +1998,30 @@ internal Arm64() { } /// public static Vector128 UnzipOdd(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// + /// uint8x16_t vqvtbl1q_u8(uint8x16_t t, uint8x16_t idx) + /// A64: TBL Vd.16B, {Vn.16B}, Vm.16B + /// + public static Vector128 VectorTableLookup(Vector128 table, Vector128 byteIndexes) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vqvtbl1q_s8(int8x16_t t, uint8x16_t idx) + /// A64: TBL Vd.16B, {Vn.16B}, Vm.16B + /// + public static Vector128 VectorTableLookup(Vector128 table, Vector128 byteIndexes) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vqvtbx1q_u8(uint8x16_t r, int8x16_t t, uint8x16_t idx) + /// A64: TBX Vd.16B, {Vn.16B}, Vm.16B + /// + public static Vector128 VectorTableLookupExtension(Vector128 defaultValues, Vector128 table, Vector128 byteIndexes) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vqvtbx1q_s8(int8x16_t r, int8x16_t t, uint8x16_t idx) + /// A64: TBX Vd.16B, {Vn.16B}, Vm.16B + /// + public static Vector128 VectorTableLookupExtension(Vector128 defaultValues, Vector128 table, Vector128 byteIndexes) { throw new PlatformNotSupportedException(); } + /// /// uint8x8_t vzip2_u8(uint8x8_t a, uint8x8_t b) /// A64: ZIP2 Vd.8B, Vn.8B, Vm.8B @@ -2099,70 +2537,238 @@ internal Arm64() { } public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vadd_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VADD.I8 Dd, Dn, Dm - /// A64: ADD Vd.8B, Vn.8B, Vm.8B + /// uint16x8_t vabdl_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VABDL.U8 Qd, Dn, Dm + /// A64: UABDL Vd.8H, Vn.8B, Vm.8B /// - public static Vector64 Add(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AbsoluteDifferenceWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vadd_s16 (int16x4_t a, int16x4_t b) - /// A32: VADD.I16 Dd, Dn, Dm - /// A64: ADD Vd.4H, Vn.4H, Vm.4H + /// int32x4_t vabdl_s16 (int16x4_t a, int16x4_t b) + /// A32: VABDL.S16 Qd, Dn, Dm + /// A64: SABDL Vd.4S, Vn.4H, Vm.4H /// - public static Vector64 Add(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AbsoluteDifferenceWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vadd_s32 (int32x2_t a, int32x2_t b) - /// A32: VADD.I32 Dd, Dn, Dm - /// A64: ADD Vd.2S, Vn.2S, Vm.2S + /// int64x2_t vabdl_s32 (int32x2_t a, int32x2_t b) + /// A32: VABDL.S32 Qd, Dn, Dm + /// A64: SABDL Vd.2D, Vn.2S, Vm.2S /// - public static Vector64 Add(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AbsoluteDifferenceWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vadd_s8 (int8x8_t a, int8x8_t b) - /// A32: VADD.I8 Dd, Dn, Dm - /// A64: ADD Vd.8B, Vn.8B, Vm.8B + /// int16x8_t vabdl_s8 (int8x8_t a, int8x8_t b) + /// A32: VABDL.S8 Qd, Dn, Dm + /// A64: SABDL Vd.8H, Vn.8B, Vm.8B /// - public static Vector64 Add(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AbsoluteDifferenceWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vadd_f32 (float32x2_t a, float32x2_t b) - /// A32: VADD.F32 Dd, Dn, Dm - /// A64: FADD Vd.2S, Vn.2S, Vm.2S + /// uint32x4_t vabdl_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VABDL.U16 Qd, Dn, Dm + /// A64: UABDL Vd.4S, Vn.4H, Vm.4H /// - public static Vector64 Add(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AbsoluteDifferenceWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vadd_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VADD.I16 Dd, Dn, Dm - /// A64: ADD Vd.4H, Vn.4H, Vm.4H + /// uint64x2_t vabdl_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VABDL.U32 Qd, Dn, Dm + /// A64: UABDL Vd.2D, Vn.2S, Vm.2S /// - public static Vector64 Add(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AbsoluteDifferenceWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vadd_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VADD.I32 Dd, Dn, Dm - /// A64: ADD Vd.2S, Vn.2S, Vm.2S + /// uint16x8_t vabal_u8 (uint16x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VABAL.U8 Qd, Dn, Dm + /// A64: UABAL Vd.8H, Vn.8B, Vm.8B /// - public static Vector64 Add(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AbsoluteDifferenceWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vaddq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VADD.I8 Qd, Qn, Qm - /// A64: ADD Vd.16B, Vn.16B, Vm.16B + /// int32x4_t vabal_s16 (int32x4_t a, int16x4_t b, int16x4_t c) + /// A32: VABAL.S16 Qd, Dn, Dm + /// A64: SABAL Vd.4S, Vn.4H, Vm.4H /// - public static Vector128 Add(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AbsoluteDifferenceWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vaddq_s16 (int16x8_t a, int16x8_t b) - /// A32: VADD.I16 Qd, Qn, Qm - /// A64: ADD Vd.8H, Vn.8H, Vm.8H + /// int64x2_t vabal_s32 (int64x2_t a, int32x2_t b, int32x2_t c) + /// A32: VABAL.S32 Qd, Dn, Dm + /// A64: SABAL Vd.2D, Vn.2S, Vm.2S /// - public static Vector128 Add(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AbsoluteDifferenceWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vaddq_s32 (int32x4_t a, int32x4_t b) + /// int16x8_t vabal_s8 (int16x8_t a, int8x8_t b, int8x8_t c) + /// A32: VABAL.S8 Qd, Dn, Dm + /// A64: SABAL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 AbsoluteDifferenceWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vabal_u16 (uint32x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VABAL.U16 Qd, Dn, Dm + /// A64: UABAL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 AbsoluteDifferenceWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vabal_u32 (uint64x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VABAL.U32 Qd, Dn, Dm + /// A64: UABAL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 AbsoluteDifferenceWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vabdl_high_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VABDL.U8 Qd, Dn+1, Dm+1 + /// A64: UABDL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vabdl_high_s16 (int16x8_t a, int16x8_t b) + /// A32: VABDL.S16 Qd, Dn+1, Dm+1 + /// A64: SABDL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vabdl_high_s32 (int32x4_t a, int32x4_t b) + /// A32: VABDL.S32 Qd, Dn+1, Dm+1 + /// A64: SABDL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vabdl_high_s8 (int8x16_t a, int8x16_t b) + /// A32: VABDL.S8 Qd, Dn+1, Dm+1 + /// A64: SABDL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vabdl_high_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VABDL.U16 Qd, Dn+1, Dm+1 + /// A64: UABDL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vabdl_high_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VABDL.U32 Qd, Dn+1, Dm+1 + /// A64: UABDL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vabal_high_u8 (uint16x8_t a, uint8x16_t b, uint8x16_t c) + /// A32: VABAL.U8 Qd, Dn+1, Dm+1 + /// A64: UABAL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vabal_high_s16 (int32x4_t a, int16x8_t b, int16x8_t c) + /// A32: VABAL.S16 Qd, Dn+1, Dm+1 + /// A64: SABAL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vabal_high_s32 (int64x2_t a, int32x4_t b, int32x4_t c) + /// A32: VABAL.S32 Qd, Dn+1, Dm+1 + /// A64: SABAL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vabal_high_s8 (int16x8_t a, int8x16_t b, int8x16_t c) + /// A32: VABAL.S8 Qd, Dn+1, Dm+1 + /// A64: SABAL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vabal_high_u16 (uint32x4_t a, uint16x8_t b, uint16x8_t c) + /// A32: VABAL.U16 Qd, Dn+1, Dm+1 + /// A64: UABAL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vabal_high_u32 (uint64x2_t a, uint32x4_t b, uint32x4_t c) + /// A32: VABAL.U32 Qd, Dn+1, Dm+1 + /// A64: UABAL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vadd_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VADD.I8 Dd, Dn, Dm + /// A64: ADD Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Add(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vadd_s16 (int16x4_t a, int16x4_t b) + /// A32: VADD.I16 Dd, Dn, Dm + /// A64: ADD Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Add(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vadd_s32 (int32x2_t a, int32x2_t b) + /// A32: VADD.I32 Dd, Dn, Dm + /// A64: ADD Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Add(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vadd_s8 (int8x8_t a, int8x8_t b) + /// A32: VADD.I8 Dd, Dn, Dm + /// A64: ADD Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Add(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vadd_f32 (float32x2_t a, float32x2_t b) + /// A32: VADD.F32 Dd, Dn, Dm + /// A64: FADD Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Add(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vadd_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VADD.I16 Dd, Dn, Dm + /// A64: ADD Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Add(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vadd_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VADD.I32 Dd, Dn, Dm + /// A64: ADD Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Add(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vaddq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VADD.I8 Qd, Qn, Qm + /// A64: ADD Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Add(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vaddq_s16 (int16x8_t a, int16x8_t b) + /// A32: VADD.I16 Qd, Qn, Qm + /// A64: ADD Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 Add(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vaddq_s32 (int32x4_t a, int32x4_t b) /// A32: VADD.I32 Qd, Qn, Qm /// A64: ADD Vd.4S, Vn.4S, Vm.4S /// @@ -2210,6 +2816,90 @@ internal Arm64() { } /// public static Vector128 Add(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// + /// uint8x8_t vaddhn_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VADDHN.I16 Dd, Qn, Qm + /// A64: ADDHN Vd.8B, Vn.8H, Vm.8H + /// + public static Vector64 AddHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vaddhn_s32 (int32x4_t a, int32x4_t b) + /// A32: VADDHN.I32 Dd, Qn, Qm + /// A64: ADDHN Vd.4H, Vn.4S, Vm.4S + /// + public static Vector64 AddHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vaddhn_s64 (int64x2_t a, int64x2_t b) + /// A32: VADDHN.I64 Dd, Qn, Qm + /// A64: ADDHN Vd.2S, Vn.2D, Vm.2D + /// + public static Vector64 AddHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vaddhn_s16 (int16x8_t a, int16x8_t b) + /// A32: VADDHN.I16 Dd, Qn, Qm + /// A64: ADDHN Vd.8B, Vn.8H, Vm.8H + /// + public static Vector64 AddHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vaddhn_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VADDHN.I32 Dd, Qn, Qm + /// A64: ADDHN Vd.4H, Vn.4S, Vm.4S + /// + public static Vector64 AddHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vaddhn_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VADDHN.I64 Dd, Qn, Qm + /// A64: ADDHN Vd.2S, Vn.2D, Vm.2D + /// + public static Vector64 AddHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vaddhn_high_u16 (uint8x8_t r, uint16x8_t a, uint16x8_t b) + /// A32: VADDHN.I16 Dd+1, Qn, Qm + /// A64: ADDHN2 Vd.16B, Vn.8H, Vm.8H + /// + public static Vector128 AddHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vaddhn_high_s32 (int16x4_t r, int32x4_t a, int32x4_t b) + /// A32: VADDHN.I32 Dd+1, Qn, Qm + /// A64: ADDHN2 Vd.8H, Vn.4S, Vm.4S + /// + public static Vector128 AddHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vaddhn_high_s64 (int32x2_t r, int64x2_t a, int64x2_t b) + /// A32: VADDHN.I64 Dd+1, Qn, Qm + /// A64: ADDHN2 Vd.4S, Vn.2D, Vm.2D + /// + public static Vector128 AddHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vaddhn_high_s16 (int8x8_t r, int16x8_t a, int16x8_t b) + /// A32: VADDHN.I16 Dd+1, Qn, Qm + /// A64: ADDHN2 Vd.16B, Vn.8H, Vm.8H + /// + public static Vector128 AddHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vaddhn_high_u32 (uint16x4_t r, uint32x4_t a, uint32x4_t b) + /// A32: VADDHN.I32 Dd+1, Qn, Qm + /// A64: ADDHN2 Vd.8H, Vn.4S, Vm.4S + /// + public static Vector128 AddHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vaddhn_high_u64 (uint32x2_t r, uint64x2_t a, uint64x2_t b) + /// A32: VADDHN.I64 Dd+1, Qn, Qm + /// A64: ADDHN2 Vd.4S, Vn.2D, Vm.2D + /// + public static Vector128 AddHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// /// uint8x8_t vpadd_u8 (uint8x8_t a, uint8x8_t b) /// A32: VPADD.I8 Dd, Dn, Dm @@ -2260,2780 +2950,6742 @@ internal Arm64() { } public static Vector64 AddPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vadd_f64 (float64x1_t a, float64x1_t b) - /// A32: VADD.F64 Dd, Dn, Dm - /// A64: FADD Dd, Dn, Dm + /// uint16x4_t vpaddl_u8 (uint8x8_t a) + /// A32: VPADDL.U8 Dd, Dm + /// A64: UADDLP Vd.4H, Vn.8B /// - public static Vector64 AddScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddPairwiseWidening(Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// int64x1_t vadd_s64 (int64x1_t a, int64x1_t b) - /// A32: VADD.I64 Dd, Dn, Dm - /// A64: ADD Dd, Dn, Dm + /// int32x2_t vpaddl_s16 (int16x4_t a) + /// A32: VPADDL.S16 Dd, Dm + /// A64: SADDLP Vd.2S, Vn.4H /// - public static Vector64 AddScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddPairwiseWidening(Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// float32_t vadds_f32 (float32_t a, float32_t b) - /// A32: VADD.F32 Sd, Sn, Sm - /// A64: FADD Sd, Sn, Sm - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// int16x4_t vpaddl_s8 (int8x8_t a) + /// A32: VPADDL.S8 Dd, Dm + /// A64: SADDLP Vd.4H, Vn.8B /// - public static Vector64 AddScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddPairwiseWidening(Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// uint64x1_t vadd_u64 (uint64x1_t a, uint64x1_t b) - /// A32: VADD.I64 Dd, Dn, Dm - /// A64: ADD Dd, Dn, Dm + /// uint32x2_t vpaddl_u16 (uint16x4_t a) + /// A32: VPADDL.U16 Dd, Dm + /// A64: UADDLP Vd.2S, Vn.4H /// - public static Vector64 AddScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddPairwiseWidening(Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vand_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// uint16x8_t vpaddlq_u8 (uint8x16_t a) + /// A32: VPADDL.U8 Qd, Qm + /// A64: UADDLP Vd.8H, Vn.16B /// - public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWidening(Vector128 value) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vand_f64 (float64x1_t a, float64x1_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// int32x4_t vpaddlq_s16 (int16x8_t a) + /// A32: VPADDL.S16 Qd, Qm + /// A64: SADDLP Vd.4S, Vn.8H /// - public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWidening(Vector128 value) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vand_s16 (int16x4_t a, int16x4_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// int64x2_t vpaddlq_s32 (int32x4_t a) + /// A32: VPADDL.S32 Qd, Qm + /// A64: SADDLP Vd.2D, Vn.4S /// - public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWidening(Vector128 value) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vand_s32 (int32x2_t a, int32x2_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// int16x8_t vpaddlq_s8 (int8x16_t a) + /// A32: VPADDL.S8 Qd, Qm + /// A64: SADDLP Vd.8H, Vn.16B /// - public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWidening(Vector128 value) { throw new PlatformNotSupportedException(); } /// - /// int64x1_t vand_s64 (int64x1_t a, int64x1_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// uint32x4_t vpaddlq_u16 (uint16x8_t a) + /// A32: VPADDL.U16 Qd, Qm + /// A64: UADDLP Vd.4S, Vn.8H /// - public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWidening(Vector128 value) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vand_s8 (int8x8_t a, int8x8_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// uint64x2_t vpaddlq_u32 (uint32x4_t a) + /// A32: VPADDL.U32 Qd, Qm + /// A64: UADDLP Vd.2D, Vn.4S /// - public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWidening(Vector128 value) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vand_f32 (float32x2_t a, float32x2_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x4_t vpadal_u8 (uint16x4_t a, uint8x8_t b) + /// A32: VPADAL.U8 Dd, Dm + /// A64: UADALP Vd.4H, Vn.8B /// - public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddPairwiseWideningAndAdd(Vector64 addend, Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vand_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// int32x2_t vpadal_s16 (int32x2_t a, int16x4_t b) + /// A32: VPADAL.S16 Dd, Dm + /// A64: SADALP Vd.2S, Vn.4H /// - public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddPairwiseWideningAndAdd(Vector64 addend, Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vand_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// int16x4_t vpadal_s8 (int16x4_t a, int8x8_t b) + /// A32: VPADAL.S8 Dd, Dm + /// A64: SADALP Vd.4H, Vn.8B /// - public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddPairwiseWideningAndAdd(Vector64 addend, Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// uint64x1_t vand_u64 (uint64x1_t a, uint64x1_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// uint32x2_t vpadal_u16 (uint32x2_t a, uint16x4_t b) + /// A32: VPADAL.U16 Dd, Dm + /// A64: UADALP Vd.2S, Vn.4H /// - public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddPairwiseWideningAndAdd(Vector64 addend, Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vandq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vpadalq_u8 (uint16x8_t a, uint8x16_t b) + /// A32: VPADAL.U8 Qd, Qm + /// A64: UADALP Vd.8H, Vn.16B /// - public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWideningAndAdd(Vector128 addend, Vector128 value) { throw new PlatformNotSupportedException(); } /// - /// float64x2_t vandq_f64 (float64x2_t a, float64x2_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// int32x4_t vpadalq_s16 (int32x4_t a, int16x8_t b) + /// A32: VPADAL.S16 Qd, Qm + /// A64: SADALP Vd.4S, Vn.8H /// - public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWideningAndAdd(Vector128 addend, Vector128 value) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vandq_s16 (int16x8_t a, int16x8_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// int64x2_t vpadalq_s32 (int64x2_t a, int32x4_t b) + /// A32: VPADAL.S32 Qd, Qm + /// A64: SADALP Vd.2D, Vn.4S /// - public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWideningAndAdd(Vector128 addend, Vector128 value) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vandq_s32 (int32x4_t a, int32x4_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// int16x8_t vpadalq_s8 (int16x8_t a, int8x16_t b) + /// A32: VPADAL.S8 Qd, Qm + /// A64: SADALP Vd.8H, Vn.16B /// - public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWideningAndAdd(Vector128 addend, Vector128 value) { throw new PlatformNotSupportedException(); } /// - /// int64x2_t vandq_s64 (int64x2_t a, int64x2_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// uint32x4_t vpadalq_u16 (uint32x4_t a, uint16x8_t b) + /// A32: VPADAL.U16 Qd, Qm + /// A64: UADALP Vd.4S, Vn.8H /// - public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWideningAndAdd(Vector128 addend, Vector128 value) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vandq_s8 (int8x16_t a, int8x16_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// uint64x2_t vpadalq_u32 (uint64x2_t a, uint32x4_t b) + /// A32: VPADAL.U32 Qd, Qm + /// A64: UADALP Vd.2D, Vn.4S /// - public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddPairwiseWideningAndAdd(Vector128 addend, Vector128 value) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vandq_f32 (float32x4_t a, float32x4_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// int64x1_t vpadal_s32 (int64x1_t a, int32x2_t b) + /// A32: VPADAL.S32 Dd, Dm + /// A64: SADALP Vd.1D, Vn.2S /// - public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddPairwiseWideningAndAddScalar(Vector64 addend, Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vandq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// uint64x1_t vpadal_u32 (uint64x1_t a, uint32x2_t b) + /// A32: VPADAL.U32 Dd, Dm + /// A64: UADALP Vd.1D, Vn.2S /// - public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddPairwiseWideningAndAddScalar(Vector64 addend, Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vandq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// int64x1_t vpaddl_s32 (int32x2_t a) + /// A32: VPADDL.S32 Dd, Dm + /// A64: SADDLP Dd, Vn.2S /// - public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddPairwiseWideningScalar(Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// uint64x2_t vandq_u64 (uint64x2_t a, uint64x2_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// uint64x1_t vpaddl_u32 (uint32x2_t a) + /// A32: VPADDL.U32 Dd, Dm + /// A64: UADDLP Dd, Vn.2S /// - public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddPairwiseWideningScalar(Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vbic_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// uint8x8_t vraddhn_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VRADDHN.I16 Dd, Qn, Qm + /// A64: RADDHN Vd.8B, Vn.8H, Vm.8H /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + public static Vector64 AddRoundedHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vbic_f64 (float64x1_t a, float64x1_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// int16x4_t vraddhn_s32 (int32x4_t a, int32x4_t b) + /// A32: VRADDHN.I32 Dd, Qn, Qm + /// A64: RADDHN Vd.4H, Vn.4S, Vm.4S /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + public static Vector64 AddRoundedHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vbic_s16 (int16x4_t a, int16x4_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// int32x2_t vraddhn_s64 (int64x2_t a, int64x2_t b) + /// A32: VRADDHN.I64 Dd, Qn, Qm + /// A64: RADDHN Vd.2S, Vn.2D, Vm.2D /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + public static Vector64 AddRoundedHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vbic_s32 (int32x2_t a, int32x2_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// int8x8_t vraddhn_s16 (int16x8_t a, int16x8_t b) + /// A32: VRADDHN.I16 Dd, Qn, Qm + /// A64: RADDHN Vd.8B, Vn.8H, Vm.8H /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + public static Vector64 AddRoundedHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// int64x1_t vbic_s64 (int64x1_t a, int64x1_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// uint16x4_t vraddhn_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VRADDHN.I32 Dd, Qn, Qm + /// A64: RADDHN Vd.4H, Vn.4S, Vm.4S /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + public static Vector64 AddRoundedHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vbic_s8 (int8x8_t a, int8x8_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// uint32x2_t vraddhn_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VRADDHN.I64 Dd, Qn, Qm + /// A64: RADDHN Vd.2S, Vn.2D, Vm.2D /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + public static Vector64 AddRoundedHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vbic_f32 (float32x2_t a, float32x2_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x16_t vraddhn_high_u16 (uint8x8_t r, uint16x8_t a, uint16x8_t b) + /// A32: VRADDHN.I16 Dd+1, Qn, Qm + /// A64: RADDHN2 Vd.16B, Vn.8H, Vm.8H /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + public static Vector128 AddRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vbic_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// int16x8_t vraddhn_high_s32 (int16x4_t r, int32x4_t a, int32x4_t b) + /// A32: VRADDHN.I32 Dd+1, Qn, Qm + /// A64: RADDHN2 Vd.8H, Vn.4S, Vm.4S /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + public static Vector128 AddRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vbic_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// int32x4_t vraddhn_high_s64 (int32x2_t r, int64x2_t a, int64x2_t b) + /// A32: VRADDHN.I64 Dd+1, Qn, Qm + /// A64: RADDHN2 Vd.4S, Vn.2D, Vm.2D /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + public static Vector128 AddRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// uint64x1_t vbic_u64 (uint64x1_t a, uint64x1_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// int8x16_t vraddhn_high_s16 (int8x8_t r, int16x8_t a, int16x8_t b) + /// A32: VRADDHN.I16 Dd+1, Qn, Qm + /// A64: RADDHN2 Vd.16B, Vn.8H, Vm.8H /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + public static Vector128 AddRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vbicq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vraddhn_high_u32 (uint16x4_t r, uint32x4_t a, uint32x4_t b) + /// A32: VRADDHN.I32 Dd+1, Qn, Qm + /// A64: RADDHN2 Vd.8H, Vn.4S, Vm.4S /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + public static Vector128 AddRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// float64x2_t vbicq_f64 (float64x2_t a, float64x2_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint32x4_t vraddhn_high_u64 (uint32x2_t r, uint64x2_t a, uint64x2_t b) + /// A32: VRADDHN.I64 Dd+1, Qn, Qm + /// A64: RADDHN2 Vd.4S, Vn.2D, Vm.2D /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + public static Vector128 AddRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vbicq_s16 (int16x8_t a, int16x8_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// uint8x8_t vqadd_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VQADD.U8 Dd, Dn, Dm + /// A64: UQADD Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + public static Vector64 AddSaturate(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vbicq_s32 (int32x4_t a, int32x4_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// int16x4_t vqadd_s16 (int16x4_t a, int16x4_t b) + /// A32: VQADD.S16 Dd, Dn, Dm + /// A64: SQADD Vd.4H, Vn.4H, Vm.4H /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + public static Vector64 AddSaturate(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// int64x2_t vbicq_s64 (int64x2_t a, int64x2_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// int32x2_t vqadd_s32 (int32x2_t a, int32x2_t b) + /// A32: VQADD.S32 Dd, Dn, Dm + /// A64: SQADD Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + public static Vector64 AddSaturate(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vbicq_s8 (int8x16_t a, int8x16_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// int8x8_t vqadd_s8 (int8x8_t a, int8x8_t b) + /// A32: VQADD.S8 Dd, Dn, Dm + /// A64: SQADD Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + public static Vector64 AddSaturate(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vbicq_f32 (float32x4_t a, float32x4_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x4_t vqadd_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VQADD.U16 Dd, Dn, Dm + /// A64: UQADD Vd.4H, Vn.4H, Vm.4H /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + public static Vector64 AddSaturate(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vbicq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// uint32x2_t vqadd_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VQADD.U32 Dd, Dn, Dm + /// A64: UQADD Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + public static Vector64 AddSaturate(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vbicq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// uint8x16_t vqaddq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VQADD.U8 Qd, Qn, Qm + /// A64: UQADD Vd.16B, Vn.16B, Vm.16B /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + public static Vector128 AddSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// uint64x2_t vbicq_u64 (uint64x2_t a, uint64x2_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// int16x8_t vqaddq_s16 (int16x8_t a, int16x8_t b) + /// A32: VQADD.S16 Qd, Qn, Qm + /// A64: SQADD Vd.8H, Vn.8H, Vm.8H /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + public static Vector128 AddSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vbsl_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// int32x4_t vqaddq_s32 (int32x4_t a, int32x4_t b) + /// A32: VQADD.S32 Qd, Qn, Qm + /// A64: SQADD Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vbsl_f64 (uint64x1_t a, float64x1_t b, float64x1_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// int64x2_t vqaddq_s64 (int64x2_t a, int64x2_t b) + /// A32: VQADD.S64 Qd, Qn, Qm + /// A64: SQADD Vd.2D, Vn.2D, Vm.2D /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vbsl_s16 (uint16x4_t a, int16x4_t b, int16x4_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// int8x16_t vqaddq_s8 (int8x16_t a, int8x16_t b) + /// A32: VQADD.S8 Qd, Qn, Qm + /// A64: SQADD Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vbsl_s32 (uint32x2_t a, int32x2_t b, int32x2_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// uint16x8_t vqaddq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VQADD.U16 Qd, Qn, Qm + /// A64: UQADD Vd.8H, Vn.8H, Vm.8H /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// int64x1_t vbsl_s64 (uint64x1_t a, int64x1_t b, int64x1_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// uint32x4_t vqaddq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VQADD.U32 Qd, Qn, Qm + /// A64: UQADD Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vbsl_s8 (uint8x8_t a, int8x8_t b, int8x8_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// uint64x2_t vqaddq_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VQADD.U64 Qd, Qn, Qm + /// A64: UQADD Vd.2D, Vn.2D, Vm.2D /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vbsl_f32 (uint32x2_t a, float32x2_t b, float32x2_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// int64x1_t vqadd_s64 (int64x1_t a, int64x1_t b) + /// A32: VQADD.S64 Dd, Dn, Dm + /// A64: SQADD Dd, Dn, Dm /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vbsl_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// uint64x1_t vqadd_u64 (uint64x1_t a, uint64x1_t b) + /// A32: VQADD.U64 Dd, Dn, Dm + /// A64: UQADD Dd, Dn, Dm /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vbsl_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// float64x1_t vadd_f64 (float64x1_t a, float64x1_t b) + /// A32: VADD.F64 Dd, Dn, Dm + /// A64: FADD Dd, Dn, Dm /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint64x1_t vbsl_u64 (uint64x1_t a, uint64x1_t b, uint64x1_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// int64x1_t vadd_s64 (int64x1_t a, int64x1_t b) + /// A32: VADD.I64 Dd, Dn, Dm + /// A64: ADD Dd, Dn, Dm /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vbslq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// float32_t vadds_f32 (float32_t a, float32_t b) + /// A32: VADD.F32 Sd, Sn, Sm + /// A64: FADD Sd, Sn, Sm + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// float64x2_t vbslq_f64 (uint64x2_t a, float64x2_t b, float64x2_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// uint64x1_t vadd_u64 (uint64x1_t a, uint64x1_t b) + /// A32: VADD.I64 Dd, Dn, Dm + /// A64: ADD Dd, Dn, Dm /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 AddScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vbslq_s16 (uint16x8_t a, int16x8_t b, int16x8_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vaddl_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VADDL.U8 Qd, Dn, Dm + /// A64: UADDL Vd.8H, Vn.8B, Vm.8B /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vbslq_s32 (uint32x4_t a, int32x4_t b, int32x4_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// int32x4_t vaddl_s16 (int16x4_t a, int16x4_t b) + /// A32: VADDL.S16 Qd, Dn, Dm + /// A64: SADDL Vd.4S, Vn.4H, Vm.4H /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// int64x2_t vbslq_s64 (uint64x2_t a, int64x2_t b, int64x2_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// int64x2_t vaddl_s32 (int32x2_t a, int32x2_t b) + /// A32: VADDL.S32 Qd, Dn, Dm + /// A64: SADDL Vd.2D, Vn.2S, Vm.2S /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vbslq_s8 (uint8x16_t a, int8x16_t b, int8x16_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// int16x8_t vaddl_s8 (int8x8_t a, int8x8_t b) + /// A32: VADDL.S8 Qd, Dn, Dm + /// A64: SADDL Vd.8H, Vn.8B, Vm.8B /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vbslq_f32 (uint32x4_t a, float32x4_t b, float32x4_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// uint32x4_t vaddl_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VADDL.U16 Qd, Dn, Dm + /// A64: UADDL Vd.4S, Vn.4H, Vm.4H /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vbslq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// uint64x2_t vaddl_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VADDL.U32 Qd, Dn, Dm + /// A64: UADDL Vd.2D, Vn.2S, Vm.2S /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vbslq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// int16x8_t vaddw_s8 (int16x8_t a, int8x8_t b) + /// A32: VADDW.S8 Qd, Qn, Dm + /// A64: SADDW Vd.8H, Vn.8H, Vm.8B /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningLower(Vector128 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint64x2_t vbslq_u64 (uint64x2_t a, uint64x2_t b, uint64x2_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// int32x4_t vaddw_s16 (int32x4_t a, int16x4_t b) + /// A32: VADDW.S16 Qd, Qn, Dm + /// A64: SADDW Vd.4S, Vn.4S, Vm.4H /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningLower(Vector128 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vceq_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VCEQ.I8 Dd, Dn, Dm - /// A64: CMEQ Vd.8B, Vn.8B, Vm.8B + /// int64x2_t vaddw_s32 (int64x2_t a, int32x2_t b) + /// A32: VADDW.S32 Qd, Qn, Dm + /// A64: SADDW Vd.2D, Vn.2D, Vm.2S /// - public static Vector64 CompareEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningLower(Vector128 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vceq_s16 (int16x4_t a, int16x4_t b) - /// A32: VCEQ.I16 Dd, Dn, Dm - /// A64: CMEQ Vd.4H, Vn.4H, Vm.4H + /// uint16x8_t vaddw_u8 (uint16x8_t a, uint8x8_t b) + /// A32: VADDW.U8 Qd, Qn, Dm + /// A64: UADDW Vd.8H, Vn.8H, Vm.8B /// - public static Vector64 CompareEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningLower(Vector128 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vceq_s32 (int32x2_t a, int32x2_t b) - /// A32: VCEQ.I32 Dd, Dn, Dm - /// A64: CMEQ Vd.2S, Vn.2S, Vm.2S + /// uint32x4_t vaddw_u16 (uint32x4_t a, uint16x4_t b) + /// A32: VADDW.U16 Qd, Qn, Dm + /// A64: UADDW Vd.4S, Vn.4S, Vm.4H /// - public static Vector64 CompareEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningLower(Vector128 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vceq_s8 (int8x8_t a, int8x8_t b) - /// A32: VCEQ.I8 Dd, Dn, Dm - /// A64: CMEQ Vd.8B, Vn.8B, Vm.8B + /// uint64x2_t vaddw_u32 (uint64x2_t a, uint32x2_t b) + /// A32: VADDW.U32 Qd, Qn, Dm + /// A64: UADDW Vd.2D, Vn.2D, Vm.2S /// - public static Vector64 CompareEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningLower(Vector128 left, Vector64 right) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vceq_f32 (float32x2_t a, float32x2_t b) - /// A32: VCEQ.F32 Dd, Dn, Dm - /// A64: FCMEQ Vd.2S, Vn.2S, Vm.2S + /// uint16x8_t vaddl_high_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VADDL.U8 Qd, Dn+1, Dm+1 + /// A64: UADDL2 Vd.8H, Vn.16B, Vm.16B /// - public static Vector64 CompareEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vceq_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VCEQ.I16 Dd, Dn, Dm - /// A64: CMEQ Vd.4H, Vn.4H, Vm.4H + /// int32x4_t vaddl_high_s16 (int16x8_t a, int16x8_t b) + /// A32: VADDL.S16 Qd, Dn+1, Dm+1 + /// A64: SADDL2 Vd.4S, Vn.8H, Vm.8H /// - public static Vector64 CompareEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vceq_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VCEQ.I32 Dd, Dn, Dm - /// A64: CMEQ Vd.2S, Vn.2S, Vm.2S + /// int16x8_t vaddw_high_s8 (int16x8_t a, int8x16_t b) + /// A32: VADDW.S8 Qd, Qn, Dm+1 + /// A64: SADDW2 Vd.8H, Vn.8H, Vm.16B /// - public static Vector64 CompareEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vceqq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VCEQ.I8 Qd, Qn, Qm - /// A64: CMEQ Vd.16B, Vn.16B, Vm.16B + /// int32x4_t vaddw_high_s16 (int32x4_t a, int16x8_t b) + /// A32: VADDW.S16 Qd, Qn, Dm+1 + /// A64: SADDW2 Vd.4S, Vn.4S, Vm.8H /// - public static Vector128 CompareEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vceqq_s16 (int16x8_t a, int16x8_t b) - /// A32: VCEQ.I16 Qd, Qn, Qm - /// A64: CMEQ Vd.8H, Vn.8H, Vm.8H + /// int64x2_t vaddl_high_s32 (int32x4_t a, int32x4_t b) + /// A32: VADDL.S32 Qd, Dn+1, Dm+1 + /// A64: SADDL2 Vd.2D, Vn.4S, Vm.4S /// - public static Vector128 CompareEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vceqq_s32 (int32x4_t a, int32x4_t b) - /// A32: VCEQ.I32 Qd, Qn, Qm - /// A64: CMEQ Vd.4S, Vn.4S, Vm.4S + /// int64x2_t vaddw_high_s32 (int64x2_t a, int32x4_t b) + /// A32: VADDW.S32 Qd, Qn, Dm+1 + /// A64: SADDW2 Vd.2D, Vn.2D, Vm.4S + /// + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vaddl_high_s8 (int8x16_t a, int8x16_t b) + /// A32: VADDL.S8 Qd, Dn+1, Dm+1 + /// A64: SADDL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vaddw_high_u8 (uint16x8_t a, uint8x16_t b) + /// A32: VADDW.U8 Qd, Qn, Dm+1 + /// A64: UADDW2 Vd.8H, Vn.8H, Vm.16B + /// + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vaddl_high_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VADDL.U16 Qd, Dn+1, Dm+1 + /// A64: UADDL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vaddw_high_u16 (uint32x4_t a, uint16x8_t b) + /// A32: VADDW.U16 Qd, Qn, Dm+1 + /// A64: UADDW2 Vd.4S, Vn.4S, Vm.8H + /// + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vaddl_high_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VADDL.U32 Qd, Dn+1, Dm+1 + /// A64: UADDL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vaddw_high_u32 (uint64x2_t a, uint32x4_t b) + /// A32: VADDW.U32 Qd, Qn, Dm+1 + /// A64: UADDW2 Vd.2D, Vn.2D, Vm.4S + /// + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vand_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vand_f64 (float64x1_t a, float64x1_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vand_s16 (int16x4_t a, int16x4_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vand_s32 (int32x2_t a, int32x2_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x1_t vand_s64 (int64x1_t a, int64x1_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vand_s8 (int8x8_t a, int8x8_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vand_f32 (float32x2_t a, float32x2_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vand_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vand_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x1_t vand_u64 (uint64x1_t a, uint64x1_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vandq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vandq_f64 (float64x2_t a, float64x2_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vandq_s16 (int16x8_t a, int16x8_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vandq_s32 (int32x4_t a, int32x4_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vandq_s64 (int64x2_t a, int64x2_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vandq_s8 (int8x16_t a, int8x16_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vandq_f32 (float32x4_t a, float32x4_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vandq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vandq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vandq_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vbic_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vbic_f64 (float64x1_t a, float64x1_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vbic_s16 (int16x4_t a, int16x4_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vbic_s32 (int32x2_t a, int32x2_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + + /// + /// int64x1_t vbic_s64 (int64x1_t a, int64x1_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vbic_s8 (int8x8_t a, int8x8_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vbic_f32 (float32x2_t a, float32x2_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vbic_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vbic_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x1_t vbic_u64 (uint64x1_t a, uint64x1_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vbicq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vbicq_f64 (float64x2_t a, float64x2_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vbicq_s16 (int16x8_t a, int16x8_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vbicq_s32 (int32x4_t a, int32x4_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vbicq_s64 (int64x2_t a, int64x2_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vbicq_s8 (int8x16_t a, int8x16_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vbicq_f32 (float32x4_t a, float32x4_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vbicq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vbicq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vbicq_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vbsl_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vbsl_f64 (uint64x1_t a, float64x1_t b, float64x1_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vbsl_s16 (uint16x4_t a, int16x4_t b, int16x4_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vbsl_s32 (uint32x2_t a, int32x2_t b, int32x2_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x1_t vbsl_s64 (uint64x1_t a, int64x1_t b, int64x1_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vbsl_s8 (uint8x8_t a, int8x8_t b, int8x8_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vbsl_f32 (uint32x2_t a, float32x2_t b, float32x2_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vbsl_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vbsl_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x1_t vbsl_u64 (uint64x1_t a, uint64x1_t b, uint64x1_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vbslq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vbslq_f64 (uint64x2_t a, float64x2_t b, float64x2_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vbslq_s16 (uint16x8_t a, int16x8_t b, int16x8_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vbslq_s32 (uint32x4_t a, int32x4_t b, int32x4_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vbslq_s64 (uint64x2_t a, int64x2_t b, int64x2_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vbslq_s8 (uint8x16_t a, int8x16_t b, int8x16_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vbslq_f32 (uint32x4_t a, float32x4_t b, float32x4_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vbslq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vbslq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vbslq_u64 (uint64x2_t a, uint64x2_t b, uint64x2_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vceq_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VCEQ.I8 Dd, Dn, Dm + /// A64: CMEQ Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vceq_s16 (int16x4_t a, int16x4_t b) + /// A32: VCEQ.I16 Dd, Dn, Dm + /// A64: CMEQ Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vceq_s32 (int32x2_t a, int32x2_t b) + /// A32: VCEQ.I32 Dd, Dn, Dm + /// A64: CMEQ Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vceq_s8 (int8x8_t a, int8x8_t b) + /// A32: VCEQ.I8 Dd, Dn, Dm + /// A64: CMEQ Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vceq_f32 (float32x2_t a, float32x2_t b) + /// A32: VCEQ.F32 Dd, Dn, Dm + /// A64: FCMEQ Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vceq_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VCEQ.I16 Dd, Dn, Dm + /// A64: CMEQ Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vceq_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VCEQ.I32 Dd, Dn, Dm + /// A64: CMEQ Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vceqq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VCEQ.I8 Qd, Qn, Qm + /// A64: CMEQ Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vceqq_s16 (int16x8_t a, int16x8_t b) + /// A32: VCEQ.I16 Qd, Qn, Qm + /// A64: CMEQ Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vceqq_s32 (int32x4_t a, int32x4_t b) + /// A32: VCEQ.I32 Qd, Qn, Qm + /// A64: CMEQ Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vceqq_s8 (int8x16_t a, int8x16_t b) + /// A32: VCEQ.I8 Qd, Qn, Qm + /// A64: CMEQ Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vceqq_f32 (float32x4_t a, float32x4_t b) + /// A32: VCEQ.F32 Qd, Qn, Qm + /// A64: FCMEQ Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vceqq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VCEQ.I16 Qd, Qn, Qm + /// A64: CMEQ Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vceqq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VCEQ.I32 Qd, Qn, Qm + /// A64: CMEQ Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vcgt_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VCGT.U8 Dd, Dn, Dm + /// A64: CMHI Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vcgt_s16 (int16x4_t a, int16x4_t b) + /// A32: VCGT.S16 Dd, Dn, Dm + /// A64: CMGT Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vcgt_s32 (int32x2_t a, int32x2_t b) + /// A32: VCGT.S32 Dd, Dn, Dm + /// A64: CMGT Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vcgt_s8 (int8x8_t a, int8x8_t b) + /// A32: VCGT.S8 Dd, Dn, Dm + /// A64: CMGT Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vcgt_f32 (float32x2_t a, float32x2_t b) + /// A32: VCGT.F32 Dd, Dn, Dm + /// A64: FCMGT Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vcgt_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VCGT.U16 Dd, Dn, Dm + /// A64: CMHI Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vcgt_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VCGT.U32 Dd, Dn, Dm + /// A64: CMHI Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vcgtq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VCGT.U8 Qd, Qn, Qm + /// A64: CMHI Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vcgtq_s16 (int16x8_t a, int16x8_t b) + /// A32: VCGT.S16 Qd, Qn, Qm + /// A64: CMGT Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vcgtq_s32 (int32x4_t a, int32x4_t b) + /// A32: VCGT.S32 Qd, Qn, Qm + /// A64: CMGT Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vcgtq_s8 (int8x16_t a, int8x16_t b) + /// A32: VCGT.S8 Qd, Qn, Qm + /// A64: CMGT Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vcgtq_f32 (float32x4_t a, float32x4_t b) + /// A32: VCGT.F32 Qd, Qn, Qm + /// A64: FCMGT Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vcgtq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VCGT.U16 Qd, Qn, Qm + /// A64: CMHI Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vcgtq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VCGT.U32 Qd, Qn, Qm + /// A64: CMHI Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vcge_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VCGE.U8 Dd, Dn, Dm + /// A64: CMHS Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vcge_s16 (int16x4_t a, int16x4_t b) + /// A32: VCGE.S16 Dd, Dn, Dm + /// A64: CMGE Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vcge_s32 (int32x2_t a, int32x2_t b) + /// A32: VCGE.S32 Dd, Dn, Dm + /// A64: CMGE Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vcge_s8 (int8x8_t a, int8x8_t b) + /// A32: VCGE.S8 Dd, Dn, Dm + /// A64: CMGE Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vcge_f32 (float32x2_t a, float32x2_t b) + /// A32: VCGE.F32 Dd, Dn, Dm + /// A64: FCMGE Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vcge_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VCGE.U16 Dd, Dn, Dm + /// A64: CMHS Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vcge_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VCGE.U32 Dd, Dn, Dm + /// A64: CMHS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vcgeq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VCGE.U8 Qd, Qn, Qm + /// A64: CMHS Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vcgeq_s16 (int16x8_t a, int16x8_t b) + /// A32: VCGE.S16 Qd, Qn, Qm + /// A64: CMGE Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vcgeq_s32 (int32x4_t a, int32x4_t b) + /// A32: VCGE.S32 Qd, Qn, Qm + /// A64: CMGE Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vcgeq_s8 (int8x16_t a, int8x16_t b) + /// A32: VCGE.S8 Qd, Qn, Qm + /// A64: CMGE Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vcgeq_f32 (float32x4_t a, float32x4_t b) + /// A32: VCGE.F32 Qd, Qn, Qm + /// A64: FCMGE Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vcgeq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VCGE.U16 Qd, Qn, Qm + /// A64: CMHS Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vcgeq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VCGE.U32 Qd, Qn, Qm + /// A64: CMHS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vclt_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VCLT.U8 Dd, Dn, Dm + /// A64: CMHI Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareLessThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vclt_s16 (int16x4_t a, int16x4_t b) + /// A32: VCLT.S16 Dd, Dn, Dm + /// A64: CMGT Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareLessThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vclt_s32 (int32x2_t a, int32x2_t b) + /// A32: VCLT.S32 Dd, Dn, Dm + /// A64: CMGT Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareLessThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vclt_s8 (int8x8_t a, int8x8_t b) + /// A32: VCLT.S8 Dd, Dn, Dm + /// A64: CMGT Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareLessThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vclt_f32 (float32x2_t a, float32x2_t b) + /// A32: VCLT.F32 Dd, Dn, Dm + /// A64: FCMGT Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareLessThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vclt_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VCLT.U16 Dd, Dn, Dm + /// A64: CMHI Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareLessThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vclt_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VCLT.U32 Dd, Dn, Dm + /// A64: CMHI Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareLessThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vcltq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VCLT.U8 Qd, Qn, Qm + /// A64: CMHI Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareLessThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vcltq_s16 (int16x8_t a, int16x8_t b) + /// A32: VCLT.S16 Qd, Qn, Qm + /// A64: CMGT Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareLessThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vcltq_s32 (int32x4_t a, int32x4_t b) + /// A32: VCLT.S32 Qd, Qn, Qm + /// A64: CMGT Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareLessThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vcltq_s8 (int8x16_t a, int8x16_t b) + /// A32: VCLT.S8 Qd, Qn, Qm + /// A64: CMGT Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareLessThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vcltq_f32 (float32x4_t a, float32x4_t b) + /// A32: VCLT.F32 Qd, Qn, Qm + /// A64: FCMGT Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareLessThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vcltq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VCLT.U16 Qd, Qn, Qm + /// A64: CMHI Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareLessThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vcltq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VCLT.U32 Qd, Qn, Qm + /// A64: CMHI Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareLessThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vcle_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VCLE.U8 Dd, Dn, Dm + /// A64: CMHS Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vcle_s16 (int16x4_t a, int16x4_t b) + /// A32: VCLE.S16 Dd, Dn, Dm + /// A64: CMGE Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vcle_s32 (int32x2_t a, int32x2_t b) + /// A32: VCLE.S32 Dd, Dn, Dm + /// A64: CMGE Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vcle_s8 (int8x8_t a, int8x8_t b) + /// A32: VCLE.S8 Dd, Dn, Dm + /// A64: CMGE Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vcle_f32 (float32x2_t a, float32x2_t b) + /// A32: VCLE.F32 Dd, Dn, Dm + /// A64: FCMGE Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vcle_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VCLE.U16 Dd, Dn, Dm + /// A64: CMHS Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vcle_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VCLE.U32 Dd, Dn, Dm + /// A64: CMHS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vcleq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VCLE.U8 Qd, Qn, Qm + /// A64: CMHS Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vcleq_s16 (int16x8_t a, int16x8_t b) + /// A32: VCLE.S16 Qd, Qn, Qm + /// A64: CMGE Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vcleq_s32 (int32x4_t a, int32x4_t b) + /// A32: VCLE.S32 Qd, Qn, Qm + /// A64: CMGE Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vcleq_s8 (int8x16_t a, int8x16_t b) + /// A32: VCLE.S8 Qd, Qn, Qm + /// A64: CMGE Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vcleq_f32 (float32x4_t a, float32x4_t b) + /// A32: VCLE.F32 Qd, Qn, Qm + /// A64: FCMGE Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vcleq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VCLE.U16 Qd, Qn, Qm + /// A64: CMHS Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vcleq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VCLE.U32 Qd, Qn, Qm + /// A64: CMHS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vtst_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VTST.8 Dd, Dn, Dm + /// A64: CMTST Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareTest(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vtst_s16 (int16x4_t a, int16x4_t b) + /// A32: VTST.16 Dd, Dn, Dm + /// A64: CMTST Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareTest(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vtst_s32 (int32x2_t a, int32x2_t b) + /// A32: VTST.32 Dd, Dn, Dm + /// A64: CMTST Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareTest(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vtst_s8 (int8x8_t a, int8x8_t b) + /// A32: VTST.8 Dd, Dn, Dm + /// A64: CMTST Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareTest(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vtst_f32 (float32x2_t a, float32x2_t b) + /// A32: VTST.32 Dd, Dn, Dm + /// A64: CMTST Vd.2S, Vn.2S, Vm.2S + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 CompareTest(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vtst_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VTST.16 Dd, Dn, Dm + /// A64: CMTST Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareTest(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vtst_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VTST.32 Dd, Dn, Dm + /// A64: CMTST Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareTest(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vtstq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VTST.8 Qd, Qn, Qm + /// A64: CMTST Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareTest(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vtstq_s16 (int16x8_t a, int16x8_t b) + /// A32: VTST.16 Qd, Qn, Qm + /// A64: CMTST Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareTest(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vtstq_s32 (int32x4_t a, int32x4_t b) + /// A32: VTST.32 Qd, Qn, Qm + /// A64: CMTST Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareTest(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vtstq_s8 (int8x16_t a, int8x16_t b) + /// A32: VTST.8 Qd, Qn, Qm + /// A64: CMTST Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareTest(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vtstq_f32 (float32x4_t a, float32x4_t b) + /// A32: VTST.32 Qd, Qn, Qm + /// A64: CMTST Vd.4S, Vn.4S, Vm.4S + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 CompareTest(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vtstq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VTST.16 Qd, Qn, Qm + /// A64: CMTST Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareTest(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vtstq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VTST.32 Qd, Qn, Qm + /// A64: CMTST Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareTest(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vdiv_f64 (float64x1_t a, float64x1_t b) + /// A32: VDIV.F64 Dd, Dn, Dm + /// A64: FDIV Dd, Dn, Dm + /// + public static Vector64 DivideScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vdivs_f32 (float32_t a, float32_t b) + /// A32: VDIV.F32 Sd, Sn, Sm + /// A64: FDIV Sd, Sn, Sm + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 DivideScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vdup_lane_u8 (uint8x8_t vec, const int lane) + /// A32: VDUP.8 Dd, Dm[index] + /// A64: DUP Vd.8B, Vn.B[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector64 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vdup_lane_s16 (int16x4_t vec, const int lane) + /// A32: VDUP.16 Dd, Dm[index] + /// A64: DUP Vd.4H, Vn.H[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector64 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vdup_lane_s32 (int32x2_t vec, const int lane) + /// A32: VDUP.32 Dd, Dm[index] + /// A64: DUP Vd.2S, Vn.S[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector64 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vdup_lane_f32 (float32x2_t vec, const int lane) + /// A32: VDUP.32 Dd, Dm[index] + /// A64: DUP Vd.2S, Vn.S[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector64 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vdup_lane_s8 (int8x8_t vec, const int lane) + /// A32: VDUP.8 Dd, Dm[index] + /// A64: DUP Vd.8B, Vn.B[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector64 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vdup_lane_u16 (uint16x4_t vec, const int lane) + /// A32: VDUP.16 Dd, Dm[index] + /// A64: DUP Vd.4H, Vn.H[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector64 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vdup_lane_u32 (uint32x2_t vec, const int lane) + /// A32: VDUP.32 Dd, Dm[index] + /// A64: DUP Vd.2S, Vn.S[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector64 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vdup_laneq_u8 (uint8x16_t vec, const int lane) + /// A32: VDUP.8 Dd, Dm[index] + /// A64: DUP Vd.8B, Vn.B[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vdup_laneq_s16 (int16x8_t vec, const int lane) + /// A32: VDUP.16 Dd, Dm[index] + /// A64: DUP Vd.4H, Vn.H[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vdup_laneq_s32 (int32x4_t vec, const int lane) + /// A32: VDUP.32 Dd, Dm[index] + /// A64: DUP Vd.2S, Vn.S[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vdup_laneq_f32 (float32x4_t vec, const int lane) + /// A32: VDUP.32 Dd, Dm[index] + /// A64: DUP Vd.2S, Vn.S[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vdup_laneq_s8 (int8x16_t vec, const int lane) + /// A32: VDUP.8 Dd, Dm[index] + /// A64: DUP Vd.8B, Vn.B[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vdup_laneq_u16 (uint16x8_t vec, const int lane) + /// A32: VDUP.16 Dd, Dm[index] + /// A64: DUP Vd.4H, Vn.H[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vdup_laneq_u32 (uint32x4_t vec, const int lane) + /// A32: VDUP.32 Dd, Dm[index] + /// A64: DUP Vd.2S, Vn.S[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vdupq_lane_u8 (uint8x8_t vec, const int lane) + /// A32: VDUP.8 Qd, Dm[index] + /// A64: DUP Vd.16B, Vn.B[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector64 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vdupq_lane_s16 (int16x4_t vec, const int lane) + /// A32: VDUP.16 Qd, Dm[index] + /// A64: DUP Vd.8H, Vn.H[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector64 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vdupq_lane_s32 (int32x2_t vec, const int lane) + /// A32: VDUP.32 Qd, Dm[index] + /// A64: DUP Vd.4S, Vn.S[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector64 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vdupq_lane_f32 (float32x2_t vec, const int lane) + /// A32: VDUP.32 Qd, Dm[index] + /// A64: DUP Vd.4S, Vn.S[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector64 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vdupq_lane_s8 (int8x8_t vec, const int lane) + /// A32: VDUP.8 Qd, Dm[index] + /// A64: DUP Vd.16B, Vn.B[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector64 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vdupq_lane_u16 (uint16x4_t vec, const int lane) + /// A32: VDUP.16 Qd, Dm[index] + /// A64: DUP Vd.8H, Vn.H[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector64 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vdupq_lane_u32 (uint32x2_t vec, const int lane) + /// A32: VDUP.32 Qd, Dm[index] + /// A64: DUP Vd.4S, Vn.S[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector64 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vdupq_lane_u8 (uint8x16_t vec, const int lane) + /// A32: VDUP.8 Qd, Dm[index] + /// A64: DUP Vd.16B, Vn.B[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vdupq_lane_s16 (int16x8_t vec, const int lane) + /// A32: VDUP.16 Qd, Dm[index] + /// A64: DUP Vd.8H, Vn.H[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vdupq_lane_s32 (int32x4_t vec, const int lane) + /// A32: VDUP.32 Qd, Dm[index] + /// A64: DUP Vd.4S, Vn.S[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vdupq_lane_f32 (float32x4_t vec, const int lane) + /// A32: VDUP.32 Qd, Dm[index] + /// A64: DUP Vd.4S, Vn.S[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vdupq_lane_s8 (int8x16_t vec, const int lane) + /// A32: VDUP.8 Qd, Dm[index] + /// A64: DUP Vd.16B, Vn.B[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vdupq_lane_u16 (uint16x8_t vec, const int lane) + /// A32: VDUP.16 Qd, Dm[index] + /// A64: DUP Vd.8H, Vn.H[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vdupq_lane_u32 (uint32x4_t vec, const int lane) + /// A32: VDUP.32 Qd, Dm[index] + /// A64: DUP Vd.4S, Vn.S[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector128 value, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vdup_n_u8 (uint8_t value) + /// A32: VDUP.8 Dd, Rt + /// A64: DUP Vd.8B, Rn + /// + public static Vector64 DuplicateToVector64(byte value) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vdup_n_s16 (int16_t value) + /// A32: VDUP.16 Dd, Rt + /// A64: DUP Vd.4H, Rn + /// + public static Vector64 DuplicateToVector64(short value) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vdup_n_s32 (int32_t value) + /// A32: VDUP.32 Dd, Rt + /// A64: DUP Vd.2S, Rn + /// + public static Vector64 DuplicateToVector64(int value) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vdup_n_s8 (int8_t value) + /// A32: VDUP.8 Dd, Rt + /// A64: DUP Vd.8B, Rn + /// + public static Vector64 DuplicateToVector64(sbyte value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vdup_n_f32 (float32_t value) + /// A32: VDUP Dd, Dm[0] + /// A64: DUP Vd.2S, Vn.S[0] + /// + public static Vector64 DuplicateToVector64(float value) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vdup_n_u16 (uint16_t value) + /// A32: VDUP.16 Dd, Rt + /// A64: DUP Vd.4H, Rn + /// + public static Vector64 DuplicateToVector64(ushort value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vdup_n_u32 (uint32_t value) + /// A32: VDUP.32 Dd, Rt + /// A64: DUP Vd.2S, Rn + /// + public static Vector64 DuplicateToVector64(uint value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vdupq_n_u8 (uint8_t value) + /// A32: VDUP.8 Qd, Rt + /// A64: DUP Vd.16B, Rn + /// + public static Vector128 DuplicateToVector128(byte value) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vdupq_n_s16 (int16_t value) + /// A32: VDUP.16 Qd, Rt + /// A64: DUP Vd.8H, Rn + /// + public static Vector128 DuplicateToVector128(short value) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vdupq_n_s32 (int32_t value) + /// A32: VDUP.32 Qd, Rt + /// A64: DUP Vd.4S, Rn + /// + public static Vector128 DuplicateToVector128(int value) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vdupq_n_s8 (int8_t value) + /// A32: VDUP.8 Qd, Rt + /// A64: DUP Vd.16B, Rn + /// + public static Vector128 DuplicateToVector128(sbyte value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vdupq_n_f32 (float32_t value) + /// A32: VDUP Qd, Dm[0] + /// A64: DUP Vd.4S, Vn.S[0] + /// + public static Vector128 DuplicateToVector128(float value) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vdupq_n_u16 (uint16_t value) + /// A32: VDUP.16 Qd, Rt + /// A64: DUP Vd.8H, Rn + /// + public static Vector128 DuplicateToVector128(ushort value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vdupq_n_u32 (uint32_t value) + /// A32: VDUP.32 Qd, Rt + /// A64: DUP Vd.4S, Rn + /// + public static Vector128 DuplicateToVector128(uint value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vget_lane_u8 (uint8x8_t v, const int lane) + /// A32: VMOV.U8 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.B[lane] + /// + public static byte Extract(Vector64 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int16_t vget_lane_s16 (int16x4_t v, const int lane) + /// A32: VMOV.S16 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.H[lane] + /// + public static short Extract(Vector64 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int32_t vget_lane_s32 (int32x2_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.S[lane] + /// + public static int Extract(Vector64 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int8_t vget_lane_s8 (int8x8_t v, const int lane) + /// A32: VMOV.S8 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.B[lane] + /// + public static sbyte Extract(Vector64 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vget_lane_f32 (float32x2_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: DUP Sd, Vn.S[lane] + /// + public static float Extract(Vector64 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vget_lane_u16 (uint16x4_t v, const int lane) + /// A32: VMOV.U16 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.H[lane] + /// + public static ushort Extract(Vector64 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vget_lane_u32 (uint32x2_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.S[lane] + /// + public static uint Extract(Vector64 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vgetq_lane_u8 (uint8x16_t v, const int lane) + /// A32: VMOV.U8 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.B[lane] + /// + public static byte Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float64_t vgetq_lane_f64 (float64x2_t v, const int lane) + /// A32: VMOV.F64 Dd, Dm + /// A64: DUP Dd, Vn.D[lane] + /// + public static double Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int16_t vgetq_lane_s16 (int16x8_t v, const int lane) + /// A32: VMOV.S16 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.H[lane] + /// + public static short Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int32_t vgetq_lane_s32 (int32x4_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.S[lane] + /// + public static int Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int64_t vgetq_lane_s64 (int64x2_t v, const int lane) + /// A32: VMOV Rt, Rt2, Dm + /// A64: UMOV Xd, Vn.D[lane] + /// + public static long Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int8_t vgetq_lane_s8 (int8x16_t v, const int lane) + /// A32: VMOV.S8 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.B[lane] + /// + public static sbyte Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vgetq_lane_f32 (float32x4_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: DUP Sd, Vn.S[lane] + /// + public static float Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vgetq_lane_u16 (uint16x8_t v, const int lane) + /// A32: VMOV.U16 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.H[lane] + /// + public static ushort Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vgetq_lane_u32 (uint32x4_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.S[lane] + /// + public static uint Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint64_t vgetq_lane_u64 (uint64x2_t v, const int lane) + /// A32: VMOV Rt, Rt2, Dm + /// A64: UMOV Xd, Vn.D[lane] + /// + public static ulong Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vmovn_high_s16 (int8x8_t r, int16x8_t a) + /// A32: VMOVN.I16 Dd+1, Qm + /// A64: XTN2 Vd.16B, Vn.8H + /// + public static Vector128 ExtractNarrowingUpper(Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vmovn_high_s32 (int16x4_t r, int32x4_t a) + /// A32: VMOVN.I32 Dd+1, Qm + /// A64: XTN2 Vd.8H, Vn.4S + /// + public static Vector128 ExtractNarrowingUpper(Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vmovn_high_s64 (int32x2_t r, int64x2_t a) + /// A32: VMOVN.I64 Dd+1, Qm + /// A64: XTN2 Vd.4S, Vn.2D + /// + public static Vector128 ExtractNarrowingUpper(Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vmovn_high_u16 (uint8x8_t r, uint16x8_t a) + /// A32: VMOVN.I16 Dd+1, Qm + /// A64: XTN2 Vd.16B, Vn.8H + /// + public static Vector128 ExtractNarrowingUpper(Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmovn_high_u32 (uint16x4_t r, uint32x4_t a) + /// A32: VMOVN.I32 Dd+1, Qm + /// A64: XTN2 Vd.8H, Vn.4S + /// + public static Vector128 ExtractNarrowingUpper(Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmovn_high_u64 (uint32x2_t r, uint64x2_t a) + /// A32: VMOVN.I64 Dd+1, Qm + /// A64: XTN2 Vd.4S, Vn.2D + /// + public static Vector128 ExtractNarrowingUpper(Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vmovn_s16 (int16x8_t a) + /// A32: VMOVN.I16 Dd, Qm + /// A64: XTN Vd.8B, Vn.8H + /// + public static Vector64 ExtractNarrowingLower(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vmovn_s32 (int32x4_t a) + /// A32: VMOVN.I32 Dd, Qm + /// A64: XTN Vd.4H, Vn.4S + /// + public static Vector64 ExtractNarrowingLower(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vmovn_s64 (int64x2_t a) + /// A32: VMOVN.I64 Dd, Qm + /// A64: XTN Vd.2S, Vn.2D + /// + public static Vector64 ExtractNarrowingLower(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vmovn_u16 (uint16x8_t a) + /// A32: VMOVN.I16 Dd, Qm + /// A64: XTN Vd.8B, Vn.8H + /// + public static Vector64 ExtractNarrowingLower(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vmovn_u32 (uint32x4_t a) + /// A32: VMOVN.I32 Dd, Qm + /// A64: XTN Vd.4H, Vn.4S + /// + public static Vector64 ExtractNarrowingLower(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vmovn_u64 (uint64x2_t a) + /// A32: VMOVN.I64 Dd, Qm + /// A64: XTN Vd.2S, Vn.2D + /// + public static Vector64 ExtractNarrowingLower(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vext_s8 (uint8x8_t a, uint8x8_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #n + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #n + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vext_s16 (int16x4_t a, int16x4_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*2) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*2) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vext_s32 (int32x2_t a, int32x2_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*4) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*4) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vext_s8 (int8x8_t a, int8x8_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #n + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #n + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vext_f32 (float32x2_t a, float32x2_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*4) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*4) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vext_s16 (uint16x4_t a, uint16x4_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*2) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*2) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vext_s32 (uint32x2_t a, uint32x2_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*4) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*4) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vextq_s8 (uint8x16_t a, uint8x16_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #n + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #n + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vextq_f64 (float64x2_t a, float64x2_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*8) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*8) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vextq_s16 (int16x8_t a, int16x8_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*2) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*2) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vextq_s32 (int32x4_t a, int32x4_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*4) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*4) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vextq_s64 (int64x2_t a, int64x2_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*8) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*8) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vextq_s8 (int8x16_t a, int8x16_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #n + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #n + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vextq_f32 (float32x4_t a, float32x4_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*4) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*4) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vextq_s16 (uint16x8_t a, uint16x8_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*2) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*2) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vextq_s32 (uint32x4_t a, uint32x4_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*4) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*4) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vextq_s64 (uint64x2_t a, uint64x2_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*8) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*8) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vhadd_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VHADD.U8 Dd, Dn, Dm + /// A64: UHADD Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 FusedAddHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vhadd_s16 (int16x4_t a, int16x4_t b) + /// A32: VHADD.S16 Dd, Dn, Dm + /// A64: SHADD Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 FusedAddHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vhadd_s32 (int32x2_t a, int32x2_t b) + /// A32: VHADD.S32 Dd, Dn, Dm + /// A64: SHADD Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedAddHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vhadd_s8 (int8x8_t a, int8x8_t b) + /// A32: VHADD.S8 Dd, Dn, Dm + /// A64: SHADD Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 FusedAddHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vhadd_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VHADD.U16 Dd, Dn, Dm + /// A64: UHADD Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 FusedAddHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vhadd_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VHADD.U32 Dd, Dn, Dm + /// A64: UHADD Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedAddHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vhaddq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VHADD.U8 Qd, Qn, Qm + /// A64: UHADD Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 FusedAddHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vhaddq_s16 (int16x8_t a, int16x8_t b) + /// A32: VHADD.S16 Qd, Qn, Qm + /// A64: SHADD Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 FusedAddHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vhaddq_s32 (int32x4_t a, int32x4_t b) + /// A32: VHADD.S32 Qd, Qn, Qm + /// A64: SHADD Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedAddHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vhaddq_s8 (int8x16_t a, int8x16_t b) + /// A32: VHADD.S8 Qd, Qn, Qm + /// A64: SHADD Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 FusedAddHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vhaddq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VHADD.U16 Qd, Qn, Qm + /// A64: UHADD Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 FusedAddHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vhaddq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VHADD.U32 Qd, Qn, Qm + /// A64: UHADD Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedAddHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vrhadd_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VRHADD.U8 Dd, Dn, Dm + /// A64: URHADD Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 FusedAddRoundedHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vrhadd_s16 (int16x4_t a, int16x4_t b) + /// A32: VRHADD.S16 Dd, Dn, Dm + /// A64: SRHADD Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 FusedAddRoundedHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vrhadd_s32 (int32x2_t a, int32x2_t b) + /// A32: VRHADD.S32 Dd, Dn, Dm + /// A64: SRHADD Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedAddRoundedHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vrhadd_s8 (int8x8_t a, int8x8_t b) + /// A32: VRHADD.S8 Dd, Dn, Dm + /// A64: SRHADD Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 FusedAddRoundedHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vrhadd_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VRHADD.U16 Dd, Dn, Dm + /// A64: URHADD Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 FusedAddRoundedHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vrhadd_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VRHADD.U32 Dd, Dn, Dm + /// A64: URHADD Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedAddRoundedHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vrhaddq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VRHADD.U8 Qd, Qn, Qm + /// A64: URHADD Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 FusedAddRoundedHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vrhaddq_s16 (int16x8_t a, int16x8_t b) + /// A32: VRHADD.S16 Qd, Qn, Qm + /// A64: SRHADD Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 FusedAddRoundedHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vrhaddq_s32 (int32x4_t a, int32x4_t b) + /// A32: VRHADD.S32 Qd, Qn, Qm + /// A64: SRHADD Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedAddRoundedHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vrhaddq_s8 (int8x16_t a, int8x16_t b) + /// A32: VRHADD.S8 Qd, Qn, Qm + /// A64: SRHADD Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 FusedAddRoundedHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vrhaddq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VRHADD.U16 Qd, Qn, Qm + /// A64: URHADD Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 FusedAddRoundedHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vrhaddq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VRHADD.U32 Qd, Qn, Qm + /// A64: URHADD Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedAddRoundedHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vfma_f32 (float32x2_t a, float32x2_t b, float32x2_t c) + /// A32: VFMA.F32 Dd, Dn, Dm + /// A64: FMLA Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedMultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vfmaq_f32 (float32x4_t a, float32x4_t b, float32x4_t c) + /// A32: VFMA.F32 Qd, Qn, Qm + /// A64: FMLA Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedMultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vfma_f64 (float64x1_t a, float64x1_t b, float64x1_t c) + /// A32: VFMA.F64 Dd, Dn, Dm + /// A64: FMADD Dd, Dn, Dm, Da + /// + public static Vector64 FusedMultiplyAddScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vfmas_f32 (float32_t a, float32_t b, float32_t c) + /// A32: VFMA.F32 Sd, Sn, Sm + /// A64: FMADD Sd, Sn, Sm, Sa + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 FusedMultiplyAddScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vfnma_f64 (float64x1_t a, float64x1_t b, float64x1_t c) + /// A32: VFNMA.F64 Dd, Dn, Dm + /// A64: FNMADD Dd, Dn, Dm, Da + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 FusedMultiplyAddNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vfnmas_f32 (float32_t a, float32_t b, float32_t c) + /// A32: VFNMA.F32 Sd, Sn, Sm + /// A64: FNMADD Sd, Sn, Sm, Sa + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 FusedMultiplyAddNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vfms_f32 (float32x2_t a, float32x2_t b, float32x2_t c) + /// A32: VFMS.F32 Dd, Dn, Dm + /// A64: FMLS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedMultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vfmsq_f32 (float32x4_t a, float32x4_t b, float32x4_t c) + /// A32: VFMS.F32 Qd, Qn, Qm + /// A64: FMLS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedMultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vfms_f64 (float64x1_t a, float64x1_t b, float64x1_t c) + /// A32: VFMS.F64 Dd, Dn, Dm + /// A64: FMSUB Dd, Dn, Dm, Da + /// + public static Vector64 FusedMultiplySubtractScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vfmss_f32 (float32_t a, float32_t b, float32_t c) + /// A32: VFMS.F32 Sd, Sn, Sm + /// A64: FMSUB Sd, Sn, Sm, Sa + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 FusedMultiplySubtractScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vfnms_f64 (float64x1_t a, float64x1_t b, float64x1_t c) + /// A32: VFNMS.F64 Dd, Dn, Dm + /// A64: FNMSUB Dd, Dn, Dm, Da + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 FusedMultiplySubtractNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vfnmss_f32 (float32_t a, float32_t b, float32_t c) + /// A32: VFNMS.F32 Sd, Sn, Sm + /// A64: FNMSUB Sd, Sn, Sm, Sa + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 FusedMultiplySubtractNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vhsub_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VHSUB.U8 Dd, Dn, Dm + /// A64: UHSUB Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 FusedSubtractHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vhsub_s16 (int16x4_t a, int16x4_t b) + /// A32: VHSUB.S16 Dd, Dn, Dm + /// A64: SHSUB Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 FusedSubtractHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vhsub_s32 (int32x2_t a, int32x2_t b) + /// A32: VHSUB.S32 Dd, Dn, Dm + /// A64: SHSUB Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedSubtractHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vhsub_s8 (int8x8_t a, int8x8_t b) + /// A32: VHSUB.S8 Dd, Dn, Dm + /// A64: SHSUB Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 FusedSubtractHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vhsub_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VHSUB.U16 Dd, Dn, Dm + /// A64: UHSUB Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 FusedSubtractHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vhsub_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VHSUB.U32 Dd, Dn, Dm + /// A64: UHSUB Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedSubtractHalving(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vhsubq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VHSUB.U8 Qd, Qn, Qm + /// A64: UHSUB Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 FusedSubtractHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vhsubq_s16 (int16x8_t a, int16x8_t b) + /// A32: VHSUB.S16 Qd, Qn, Qm + /// A64: SHSUB Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 FusedSubtractHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vhsubq_s32 (int32x4_t a, int32x4_t b) + /// A32: VHSUB.S32 Qd, Qn, Qm + /// A64: SHSUB Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedSubtractHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vhsubq_s8 (int8x16_t a, int8x16_t b) + /// A32: VHSUB.S8 Qd, Qn, Qm + /// A64: SHSUB Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 FusedSubtractHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vhsubq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VHSUB.U16 Qd, Qn, Qm + /// A64: UHSUB Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 FusedSubtractHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vhsubq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VHSUB.U32 Qd, Qn, Qm + /// A64: UHSUB Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedSubtractHalving(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vset_lane_u8 (uint8_t a, uint8x8_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, byte data) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vset_lane_s16 (int16_t a, int16x4_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, short data) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vset_lane_s32 (int32_t a, int32x2_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, int data) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vset_lane_s8 (int8_t a, int8x8_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, sbyte data) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vset_lane_f32 (float32_t a, float32x2_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: INS Vd.S[lane], Vn.S[0] + /// + public static Vector64 Insert(Vector64 vector, byte index, float data) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vset_lane_u16 (uint16_t a, uint16x4_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, ushort data) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vset_lane_u32 (uint32_t a, uint32x2_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, uint data) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vsetq_lane_u8 (uint8_t a, uint8x16_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, byte data) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vsetq_lane_f64 (float64_t a, float64x2_t v, const int lane) + /// A32: VMOV.F64 Dd, Dm + /// A64: INS Vd.D[lane], Vn.D[0] + /// + public static Vector128 Insert(Vector128 vector, byte index, double data) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vsetq_lane_s16 (int16_t a, int16x8_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, short data) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vsetq_lane_s32 (int32_t a, int32x4_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, int data) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vsetq_lane_s64 (int64_t a, int64x2_t v, const int lane) + /// A32: VMOV.64 Dd, Rt, Rt2 + /// A64: INS Vd.D[lane], Xn + /// + public static Vector128 Insert(Vector128 vector, byte index, long data) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vsetq_lane_s8 (int8_t a, int8x16_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, sbyte data) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vsetq_lane_f32 (float32_t a, float32x4_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: INS Vd.S[lane], Vn.S[0] + /// + public static Vector128 Insert(Vector128 vector, byte index, float data) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vsetq_lane_u16 (uint16_t a, uint16x8_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, ushort data) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vsetq_lane_u32 (uint32_t a, uint32x4_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, uint data) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vsetq_lane_u64 (uint64_t a, uint64x2_t v, const int lane) + /// A32: VMOV.64 Dd, Rt, Rt2 + /// A64: INS Vd.D[lane], Xn + /// + public static Vector128 Insert(Vector128 vector, byte index, ulong data) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vcls_s16 (int16x4_t a) + /// A32: VCLS.S16 Dd, Dm + /// A64: CLS Vd.4H, Vn.4H + /// + public static Vector64 LeadingSignCount(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vcls_s32 (int32x2_t a) + /// A32: VCLS.S32 Dd, Dm + /// A64: CLS Vd.2S, Vn.2S + /// + public static Vector64 LeadingSignCount(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vcls_s8 (int8x8_t a) + /// A32: VCLS.S8 Dd, Dm + /// A64: CLS Vd.8B, Vn.8B + /// + public static Vector64 LeadingSignCount(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vclsq_s16 (int16x8_t a) + /// A32: VCLS.S16 Qd, Qm + /// A64: CLS Vd.8H, Vn.8H + /// + public static Vector128 LeadingSignCount(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vclsq_s32 (int32x4_t a) + /// A32: VCLS.S32 Qd, Qm + /// A64: CLS Vd.4S, Vn.4S + /// + public static Vector128 LeadingSignCount(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vclsq_s8 (int8x16_t a) + /// A32: VCLS.S8 Qd, Qm + /// A64: CLS Vd.16B, Vn.16B + /// + public static Vector128 LeadingSignCount(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vclz_u8 (uint8x8_t a) + /// A32: VCLZ.I8 Dd, Dm + /// A64: CLZ Vd.8B, Vn.8B + /// + public static Vector64 LeadingZeroCount(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vclz_s16 (int16x4_t a) + /// A32: VCLZ.I16 Dd, Dm + /// A64: CLZ Vd.4H, Vn.4H + /// + public static Vector64 LeadingZeroCount(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vclz_s32 (int32x2_t a) + /// A32: VCLZ.I32 Dd, Dm + /// A64: CLZ Vd.2S, Vn.2S + /// + public static Vector64 LeadingZeroCount(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vclz_s8 (int8x8_t a) + /// A32: VCLZ.I8 Dd, Dm + /// A64: CLZ Vd.8B, Vn.8B + /// + public static Vector64 LeadingZeroCount(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vclz_u16 (uint16x4_t a) + /// A32: VCLZ.I16 Dd, Dm + /// A64: CLZ Vd.4H, Vn.4H + /// + public static Vector64 LeadingZeroCount(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vclz_u32 (uint32x2_t a) + /// A32: VCLZ.I32 Dd, Dm + /// A64: CLZ Vd.2S, Vn.2S + /// + public static Vector64 LeadingZeroCount(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vclzq_u8 (uint8x16_t a) + /// A32: VCLZ.I8 Qd, Qm + /// A64: CLZ Vd.16B, Vn.16B + /// + public static Vector128 LeadingZeroCount(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vclzq_s16 (int16x8_t a) + /// A32: VCLZ.I16 Qd, Qm + /// A64: CLZ Vd.8H, Vn.8H + /// + public static Vector128 LeadingZeroCount(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vclzq_s32 (int32x4_t a) + /// A32: VCLZ.I32 Qd, Qm + /// A64: CLZ Vd.4S, Vn.4S + /// + public static Vector128 LeadingZeroCount(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vclzq_s8 (int8x16_t a) + /// A32: VCLZ.I8 Qd, Qm + /// A64: CLZ Vd.16B, Vn.16B + /// + public static Vector128 LeadingZeroCount(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vclzq_u16 (uint16x8_t a) + /// A32: VCLZ.I16 Qd, Qm + /// A64: CLZ Vd.8H, Vn.8H + /// + public static Vector128 LeadingZeroCount(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vclzq_u32 (uint32x4_t a) + /// A32: VCLZ.I32 Qd, Qm + /// A64: CLZ Vd.4S, Vn.4S + /// + public static Vector128 LeadingZeroCount(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vld1_u8 (uint8_t const * ptr) + /// A32: VLD1.8 Dd, [Rn] + /// A64: LD1 Vt.8B, [Xn] + /// + public static unsafe Vector64 LoadVector64(byte* address) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vld1_f64 (float64_t const * ptr) + /// A32: VLD1.64 Dd, [Rn] + /// A64: LD1 Vt.1D, [Xn] + /// + public static unsafe Vector64 LoadVector64(double* address) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vld1_s16 (int16_t const * ptr) + /// A32: VLD1.16 Dd, [Rn] + /// A64: LD1 Vt.4H, [Xn] + /// + public static unsafe Vector64 LoadVector64(short* address) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vld1_s32 (int32_t const * ptr) + /// A32: VLD1.32 Dd, [Rn] + /// A64: LD1 Vt.2S, [Xn] + /// + public static unsafe Vector64 LoadVector64(int* address) { throw new PlatformNotSupportedException(); } + + /// + /// int64x1_t vld1_s64 (int64_t const * ptr) + /// A32: VLD1.64 Dd, [Rn] + /// A64: LD1 Vt.1D, [Xn] + /// + public static unsafe Vector64 LoadVector64(long* address) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vld1_s8 (int8_t const * ptr) + /// A32: VLD1.8 Dd, [Rn] + /// A64: LD1 Vt.8B, [Xn] + /// + public static unsafe Vector64 LoadVector64(sbyte* address) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vld1_f32 (float32_t const * ptr) + /// A32: VLD1.32 Dd, [Rn] + /// A64: LD1 Vt.2S, [Xn] + /// + public static unsafe Vector64 LoadVector64(float* address) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vld1_u16 (uint16_t const * ptr) + /// A32: VLD1.16 Dd, [Rn] + /// A64: LD1 Vt.4H, [Xn] + /// + public static unsafe Vector64 LoadVector64(ushort* address) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vld1_u32 (uint32_t const * ptr) + /// A32: VLD1.32 Dd, [Rn] + /// A64: LD1 Vt.2S, [Xn] + /// + public static unsafe Vector64 LoadVector64(uint* address) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x1_t vld1_u64 (uint64_t const * ptr) + /// A32: VLD1.64 Dd, [Rn] + /// A64: LD1 Vt.1D, [Xn] + /// + public static unsafe Vector64 LoadVector64(ulong* address) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vld1q_u8 (uint8_t const * ptr) + /// A32: VLD1.8 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.16B, [Xn] + /// + public static unsafe Vector128 LoadVector128(byte* address) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vld1q_f64 (float64_t const * ptr) + /// A32: VLD1.64 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.2D, [Xn] + /// + public static unsafe Vector128 LoadVector128(double* address) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vld1q_s16 (int16_t const * ptr) + /// A32: VLD1.16 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.8H, [Xn] + /// + public static unsafe Vector128 LoadVector128(short* address) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vld1q_s32 (int32_t const * ptr) + /// A32: VLD1.32 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.4S, [Xn] + /// + public static unsafe Vector128 LoadVector128(int* address) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vld1q_s64 (int64_t const * ptr) + /// A32: VLD1.64 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.2D, [Xn] + /// + public static unsafe Vector128 LoadVector128(long* address) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vld1q_s8 (int8_t const * ptr) + /// A32: VLD1.8 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.16B, [Xn] + /// + public static unsafe Vector128 LoadVector128(sbyte* address) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vld1q_f32 (float32_t const * ptr) + /// A32: VLD1.32 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.4S, [Xn] + /// + public static unsafe Vector128 LoadVector128(float* address) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vld1q_s16 (uint16_t const * ptr) + /// A32: VLD1.16 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.8H, [Xn] + /// + public static unsafe Vector128 LoadVector128(ushort* address) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vld1q_s32 (uint32_t const * ptr) + /// A32: VLD1.32 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.4S, [Xn] + /// + public static unsafe Vector128 LoadVector128(uint* address) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vld1q_u64 (uint64_t const * ptr) + /// A32: VLD1.64 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.2D, [Xn] + /// + public static unsafe Vector128 LoadVector128(ulong* address) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vmax_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VMAX.U8 Dd, Dn, Dm + /// A64: UMAX Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Max(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vmax_s16 (int16x4_t a, int16x4_t b) + /// A32: VMAX.S16 Dd, Dn, Dm + /// A64: SMAX Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Max(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vmax_s32 (int32x2_t a, int32x2_t b) + /// A32: VMAX.S32 Dd, Dn, Dm + /// A64: SMAX Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Max(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vmax_s8 (int8x8_t a, int8x8_t b) + /// A32: VMAX.S8 Dd, Dn, Dm + /// A64: SMAX Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Max(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vmax_f32 (float32x2_t a, float32x2_t b) + /// A32: VMAX.F32 Dd, Dn, Dm + /// A64: FMAX Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Max(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vmax_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VMAX.U16 Dd, Dn, Dm + /// A64: UMAX Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Max(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vmax_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VMAX.U32 Dd, Dn, Dm + /// A64: UMAX Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Max(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vmaxq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VMAX.U8 Qd, Qn, Qm + /// A64: UMAX Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Max(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vmaxq_s16 (int16x8_t a, int16x8_t b) + /// A32: VMAX.S16 Qd, Qn, Qm + /// A64: SMAX Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 Max(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vmaxq_s32 (int32x4_t a, int32x4_t b) + /// A32: VMAX.S32 Qd, Qn, Qm + /// A64: SMAX Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Max(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vmaxq_s8 (int8x16_t a, int8x16_t b) + /// A32: VMAX.S8 Qd, Qn, Qm + /// A64: SMAX Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Max(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vmaxq_f32 (float32x4_t a, float32x4_t b) + /// A32: VMAX.F32 Qd, Qn, Qm + /// A64: FMAX Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Max(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmaxq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VMAX.U16 Qd, Qn, Qm + /// A64: UMAX Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 Max(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmaxq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VMAX.U32 Qd, Qn, Qm + /// A64: UMAX Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Max(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vmaxnm_f32 (float32x2_t a, float32x2_t b) + /// A32: VMAXNM.F32 Dd, Dn, Dm + /// A64: FMAXNM Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MaxNumber(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vmaxnmq_f32 (float32x4_t a, float32x4_t b) + /// A32: VMAXNM.F32 Qd, Qn, Qm + /// A64: FMAXNM Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MaxNumber(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vmaxnm_f64 (float64x1_t a, float64x1_t b) + /// A32: VMAXNM.F64 Dd, Dn, Dm + /// A64: FMAXNM Dd, Dn, Dm + /// + public static Vector64 MaxNumberScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vmaxnms_f32 (float32_t a, float32_t b) + /// A32: VMAXNM.F32 Sd, Sn, Sm + /// A64: FMAXNM Sd, Sn, Sm + /// + public static Vector64 MaxNumberScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vpmax_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VPMAX.U8 Dd, Dn, Dm + /// A64: UMAXP Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MaxPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vpmax_s16 (int16x4_t a, int16x4_t b) + /// A32: VPMAX.S16 Dd, Dn, Dm + /// A64: SMAXP Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MaxPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vpmax_s32 (int32x2_t a, int32x2_t b) + /// A32: VPMAX.S32 Dd, Dn, Dm + /// A64: SMAXP Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MaxPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vpmax_s8 (int8x8_t a, int8x8_t b) + /// A32: VPMAX.S8 Dd, Dn, Dm + /// A64: SMAXP Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MaxPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vpmax_f32 (float32x2_t a, float32x2_t b) + /// A32: VPMAX.F32 Dd, Dn, Dm + /// A64: FMAXP Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MaxPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vpmax_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VPMAX.U16 Dd, Dn, Dm + /// A64: UMAXP Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MaxPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vpmax_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VPMAX.U32 Dd, Dn, Dm + /// A64: UMAXP Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MaxPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vmin_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VMIN.U8 Dd, Dn, Dm + /// A64: UMIN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Min(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vmin_s16 (int16x4_t a, int16x4_t b) + /// A32: VMIN.S16 Dd, Dn, Dm + /// A64: SMIN Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Min(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vmin_s32 (int32x2_t a, int32x2_t b) + /// A32: VMIN.S32 Dd, Dn, Dm + /// A64: SMIN Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Min(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vmin_s8 (int8x8_t a, int8x8_t b) + /// A32: VMIN.S8 Dd, Dn, Dm + /// A64: SMIN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Min(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vmin_f32 (float32x2_t a, float32x2_t b) + /// A32: VMIN.F32 Dd, Dn, Dm + /// A64: FMIN Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Min(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vmin_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VMIN.U16 Dd, Dn, Dm + /// A64: UMIN Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Min(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vmin_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VMIN.U32 Dd, Dn, Dm + /// A64: UMIN Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Min(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vminq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VMIN.U8 Qd, Qn, Qm + /// A64: UMIN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Min(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vminq_s16 (int16x8_t a, int16x8_t b) + /// A32: VMIN.S16 Qd, Qn, Qm + /// A64: SMIN Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 Min(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vminq_s32 (int32x4_t a, int32x4_t b) + /// A32: VMIN.S32 Qd, Qn, Qm + /// A64: SMIN Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Min(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vminq_s8 (int8x16_t a, int8x16_t b) + /// A32: VMIN.S8 Qd, Qn, Qm + /// A64: SMIN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Min(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vminq_f32 (float32x4_t a, float32x4_t b) + /// A32: VMIN.F32 Qd, Qn, Qm + /// A64: FMIN Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Min(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vminq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VMIN.U16 Qd, Qn, Qm + /// A64: UMIN Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 Min(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vminq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VMIN.U32 Qd, Qn, Qm + /// A64: UMIN Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Min(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vminnm_f32 (float32x2_t a, float32x2_t b) + /// A32: VMINNM.F32 Dd, Dn, Dm + /// A64: FMINNM Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MinNumber(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vminnmq_f32 (float32x4_t a, float32x4_t b) + /// A32: VMINNM.F32 Qd, Qn, Qm + /// A64: FMINNM Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MinNumber(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vminnm_f64 (float64x1_t a, float64x1_t b) + /// A32: VMINNM.F64 Dd, Dn, Dm + /// A64: FMINNM Dd, Dn, Dm + /// + public static Vector64 MinNumberScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vminnms_f32 (float32_t a, float32_t b) + /// A32: VMINNM.F32 Sd, Sn, Sm + /// A64: FMINNM Sd, Sn, Sm + /// + public static Vector64 MinNumberScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vpmin_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VPMIN.U8 Dd, Dn, Dm + /// A64: UMINP Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MinPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vpmin_s16 (int16x4_t a, int16x4_t b) + /// A32: VPMIN.S16 Dd, Dn, Dm + /// A64: SMINP Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MinPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vpmin_s32 (int32x2_t a, int32x2_t b) + /// A32: VPMIN.S32 Dd, Dn, Dm + /// A64: SMINP Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MinPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vpmin_s8 (int8x8_t a, int8x8_t b) + /// A32: VPMIN.S8 Dd, Dn, Dm + /// A64: SMINP Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MinPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vpmin_f32 (float32x2_t a, float32x2_t b) + /// A32: VPMIN.F32 Dd, Dn, Dm + /// A64: FMINP Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MinPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vpmin_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VPMIN.U16 Dd, Dn, Dm + /// A64: UMINP Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MinPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vpmin_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VPMIN.U32 Dd, Dn, Dm + /// A64: UMINP Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MinPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vmul_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VMUL.I8 Dd, Dn, Dm + /// A64: MUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Multiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vmul_s16 (int16x4_t a, int16x4_t b) + /// A32: VMUL.I16 Dd, Dn, Dm + /// A64: MUL Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Multiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vmul_s32 (int32x2_t a, int32x2_t b) + /// A32: VMUL.I32 Dd, Dn, Dm + /// A64: MUL Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Multiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vmul_s8 (int8x8_t a, int8x8_t b) + /// A32: VMUL.I8 Dd, Dn, Dm + /// A64: MUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Multiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vmul_f32 (float32x2_t a, float32x2_t b) + /// A32: VMUL.F32 Dd, Dn, Dm + /// A64: FMUL Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Multiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vmul_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VMUL.I16 Dd, Dn, Dm + /// A64: MUL Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Multiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vmul_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VMUL.I32 Dd, Dn, Dm + /// A64: MUL Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Multiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vmulq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VMUL.I8 Qd, Qn, Qm + /// A64: MUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vmulq_s16 (int16x8_t a, int16x8_t b) + /// A32: VMUL.I16 Qd, Qn, Qm + /// A64: MUL Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vmulq_s32 (int32x4_t a, int32x4_t b) + /// A32: VMUL.I32 Qd, Qn, Qm + /// A64: MUL Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vmulq_s8 (int8x16_t a, int8x16_t b) + /// A32: VMUL.I8 Qd, Qn, Qm + /// A64: MUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vmulq_f32 (float32x4_t a, float32x4_t b) + /// A32: VMUL.F32 Qd, Qn, Qm + /// A64: FMUL Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmulq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VMUL.I16 Qd, Qn, Qm + /// A64: MUL Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmulq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VMUL.I32 Qd, Qn, Qm + /// A64: MUL Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vmul_f64 (float64x1_t a, float64x1_t b) + /// A32: VMUL.F64 Dd, Dn, Dm + /// A64: FMUL Dd, Dn, Dm + /// + public static Vector64 MultiplyScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vmuls_f32 (float32_t a, float32_t b) + /// A32: VMUL.F32 Sd, Sn, Sm + /// A64: FMUL Sd, Sn, Sm + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 MultiplyScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vmla_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VMLA.I8 Dd, Dn, Dm + /// A64: MLA Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vmla_s16 (int16x4_t a, int16x4_t b, int16x4_t c) + /// A32: VMLA.I16 Dd, Dn, Dm + /// A64: MLA Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vmla_s32 (int32x2_t a, int32x2_t b, int32x2_t c) + /// A32: VMLA.I32 Dd, Dn, Dm + /// A64: MLA Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vmla_s8 (int8x8_t a, int8x8_t b, int8x8_t c) + /// A32: VMLA.I8 Dd, Dn, Dm + /// A64: MLA Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vmla_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VMLA.I16 Dd, Dn, Dm + /// A64: MLA Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vmla_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VMLA.I32 Dd, Dn, Dm + /// A64: MLA Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vmlaq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) + /// A32: VMLA.I8 Qd, Qn, Qm + /// A64: MLA Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vmlaq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) + /// A32: VMLA.I16 Qd, Qn, Qm + /// A64: MLA Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vmlaq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) + /// A32: VMLA.I32 Qd, Qn, Qm + /// A64: MLA Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vmlaq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) + /// A32: VMLA.I8 Qd, Qn, Qm + /// A64: MLA Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmlaq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) + /// A32: VMLA.I16 Qd, Qn, Qm + /// A64: MLA Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmlaq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) + /// A32: VMLA.I32 Qd, Qn, Qm + /// A64: MLA Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vmls_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VMLS.I8 Dd, Dn, Dm + /// A64: MLS Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vmls_s16 (int16x4_t a, int16x4_t b, int16x4_t c) + /// A32: VMLS.I16 Dd, Dn, Dm + /// A64: MLS Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vmls_s32 (int32x2_t a, int32x2_t b, int32x2_t c) + /// A32: VMLS.I32 Dd, Dn, Dm + /// A64: MLS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vmls_s8 (int8x8_t a, int8x8_t b, int8x8_t c) + /// A32: VMLS.I8 Dd, Dn, Dm + /// A64: MLS Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vmls_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VMLS.I16 Dd, Dn, Dm + /// A64: MLS Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vmls_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VMLS.I32 Dd, Dn, Dm + /// A64: MLS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vmlsq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) + /// A32: VMLS.I8 Qd, Qn, Qm + /// A64: MLS Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vmlsq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) + /// A32: VMLS.I16 Qd, Qn, Qm + /// A64: MLS Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vmlsq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) + /// A32: VMLS.I32 Qd, Qn, Qm + /// A64: MLS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vmlsq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) + /// A32: VMLS.I8 Qd, Qn, Qm + /// A64: MLS Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmlsq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) + /// A32: VMLS.I16 Qd, Qn, Qm + /// A64: MLS Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmlsq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) + /// A32: VMLS.I32 Qd, Qn, Qm + /// A64: MLS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmull_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VMULL.U8 Qd, Dn, Dm + /// A64: UMULL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 MultiplyWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vmull_s16 (int16x4_t a, int16x4_t b) + /// A32: VMULL.S16 Qd, Dn, Dm + /// A64: SMULL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 MultiplyWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vmull_s32 (int32x2_t a, int32x2_t b) + /// A32: VMULL.S32 Qd, Dn, Dm + /// A64: SMULL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 MultiplyWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vmull_s8 (int8x8_t a, int8x8_t b) + /// A32: VMULL.S8 Qd, Dn, Dm + /// A64: SMULL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 MultiplyWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmull_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VMULL.U16 Qd, Dn, Dm + /// A64: UMULL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 MultiplyWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vmull_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VMULL.U32 Qd, Dn, Dm + /// A64: UMULL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 MultiplyWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmlal_u8 (uint16x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VMLAL.U8 Qd, Dn, Dm + /// A64: UMLAL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 MultiplyWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vmlal_s16 (int32x4_t a, int16x4_t b, int16x4_t c) + /// A32: VMLAL.S16 Qd, Dn, Dm + /// A64: SMLAL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 MultiplyWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vmlal_s32 (int64x2_t a, int32x2_t b, int32x2_t c) + /// A32: VMLAL.S32 Qd, Dn, Dm + /// A64: SMLAL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 MultiplyWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vmlal_s8 (int16x8_t a, int8x8_t b, int8x8_t c) + /// A32: VMLAL.S8 Qd, Dn, Dm + /// A64: SMLAL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 MultiplyWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmlal_u16 (uint32x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VMLAL.U16 Qd, Dn, Dm + /// A64: UMLAL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 MultiplyWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vmlal_u32 (uint64x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VMLAL.U32 Qd, Dn, Dm + /// A64: UMLAL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 MultiplyWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmlsl_u8 (uint16x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VMLSL.U8 Qd, Dn, Dm + /// A64: UMLSL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 MultiplyWideningLowerAndSubtract(Vector128 minuend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vmlsl_s16 (int32x4_t a, int16x4_t b, int16x4_t c) + /// A32: VMLSL.S16 Qd, Dn, Dm + /// A64: SMLSL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 MultiplyWideningLowerAndSubtract(Vector128 minuend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vmlsl_s32 (int64x2_t a, int32x2_t b, int32x2_t c) + /// A32: VMLSL.S32 Qd, Dn, Dm + /// A64: SMLSL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 MultiplyWideningLowerAndSubtract(Vector128 minuend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vmlsl_s8 (int16x8_t a, int8x8_t b, int8x8_t c) + /// A32: VMLSL.S8 Qd, Dn, Dm + /// A64: SMLSL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 MultiplyWideningLowerAndSubtract(Vector128 minuend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmlsl_u16 (uint32x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VMLSL.U16 Qd, Dn, Dm + /// A64: UMLSL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 MultiplyWideningLowerAndSubtract(Vector128 minuend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vmlsl_u32 (uint64x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VMLSL.U32 Qd, Dn, Dm + /// A64: UMLSL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 MultiplyWideningLowerAndSubtract(Vector128 minuend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmull_high_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VMULL.U8 Qd, Dn+1, Dm+1 + /// A64: UMULL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vmull_high_s16 (int16x8_t a, int16x8_t b) + /// A32: VMULL.S16 Qd, Dn+1, Dm+1 + /// A64: SMULL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vmull_high_s32 (int32x4_t a, int32x4_t b) + /// A32: VMULL.S32 Qd, Dn+1, Dm+1 + /// A64: SMULL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vmull_high_s8 (int8x16_t a, int8x16_t b) + /// A32: VMULL.S8 Qd, Dn+1, Dm+1 + /// A64: SMULL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmull_high_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VMULL.U16 Qd, Dn+1, Dm+1 + /// A64: UMULL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vmull_high_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VMULL.U32 Qd, Dn+1, Dm+1 + /// A64: UMULL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmlal_high_u8 (uint16x8_t a, uint8x16_t b, uint8x16_t c) + /// A32: VMLAL.U8 Qd, Dn+1, Dm+1 + /// A64: UMLAL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vmlal_high_s16 (int32x4_t a, int16x8_t b, int16x8_t c) + /// A32: VMLAL.S16 Qd, Dn+1, Dm+1 + /// A64: SMLAL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vmlal_high_s32 (int64x2_t a, int32x4_t b, int32x4_t c) + /// A32: VMLAL.S32 Qd, Dn+1, Dm+1 + /// A64: SMLAL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vmlal_high_s8 (int16x8_t a, int8x16_t b, int8x16_t c) + /// A32: VMLAL.S8 Qd, Dn+1, Dm+1 + /// A64: SMLAL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmlal_high_u16 (uint32x4_t a, uint16x8_t b, uint16x8_t c) + /// A32: VMLAL.U16 Qd, Dn+1, Dm+1 + /// A64: UMLAL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vmlal_high_u32 (uint64x2_t a, uint32x4_t b, uint32x4_t c) + /// A32: VMLAL.U32 Qd, Dn+1, Dm+1 + /// A64: UMLAL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmlsl_high_u8 (uint16x8_t a, uint8x16_t b, uint8x16_t c) + /// A32: VMLSL.U8 Qd, Dn+1, Dm+1 + /// A64: UMLSL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyWideningUpperAndSubtract(Vector128 minuend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vmlsl_high_s16 (int32x4_t a, int16x8_t b, int16x8_t c) + /// A32: VMLSL.S16 Qd, Dn+1, Dm+1 + /// A64: SMLSL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyWideningUpperAndSubtract(Vector128 minuend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vmlsl_high_s32 (int64x2_t a, int32x4_t b, int32x4_t c) + /// A32: VMLSL.S32 Qd, Dn+1, Dm+1 + /// A64: SMLSL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyWideningUpperAndSubtract(Vector128 minuend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vmlsl_high_s8 (int16x8_t a, int8x16_t b, int8x16_t c) + /// A32: VMLSL.S8 Qd, Dn+1, Dm+1 + /// A64: SMLSL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyWideningUpperAndSubtract(Vector128 minuend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmlsl_high_u16 (uint32x4_t a, uint16x8_t b, uint16x8_t c) + /// A32: VMLSL.U16 Qd, Dn+1, Dm+1 + /// A64: UMLSL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyWideningUpperAndSubtract(Vector128 minuend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vmlsl_high_u32 (uint64x2_t a, uint32x4_t b, uint32x4_t c) + /// A32: VMLSL.U32 Qd, Dn+1, Dm+1 + /// A64: UMLSL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyWideningUpperAndSubtract(Vector128 minuend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vneg_s16 (int16x4_t a) + /// A32: VNEG.S16 Dd, Dm + /// A64: NEG Vd.4H, Vn.4H + /// + public static Vector64 Negate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vneg_s32 (int32x2_t a) + /// A32: VNEG.S32 Dd, Dm + /// A64: NEG Vd.2S, Vn.2S + /// + public static Vector64 Negate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vneg_s8 (int8x8_t a) + /// A32: VNEG.S8 Dd, Dm + /// A64: NEG Vd.8B, Vn.8B + /// + public static Vector64 Negate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vneg_f32 (float32x2_t a) + /// A32: VNEG.F32 Dd, Dm + /// A64: FNEG Vd.2S, Vn.2S + /// + public static Vector64 Negate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vnegq_s16 (int16x8_t a) + /// A32: VNEG.S16 Qd, Qm + /// A64: NEG Vd.8H, Vn.8H + /// + public static Vector128 Negate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vnegq_s32 (int32x4_t a) + /// A32: VNEG.S32 Qd, Qm + /// A64: NEG Vd.4S, Vn.4S + /// + public static Vector128 Negate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vnegq_s8 (int8x16_t a) + /// A32: VNEG.S8 Qd, Qm + /// A64: NEG Vd.16B, Vn.16B + /// + public static Vector128 Negate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vnegq_f32 (float32x4_t a) + /// A32: VNEG.F32 Qd, Qm + /// A64: FNEG Vd.4S, Vn.4S + /// + public static Vector128 Negate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vneg_f64 (float64x1_t a) + /// A32: VNEG.F64 Dd, Dm + /// A64: FNEG Dd, Dn + /// + public static Vector64 NegateScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vnegs_f32 (float32_t a) + /// A32: VNEG.F32 Sd, Sm + /// A64: FNEG Sd, Sn + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 NegateScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vmvn_u8 (uint8x8_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vmvn_f64 (float64x1_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vmvn_s16 (int16x4_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vmvn_s32 (int32x2_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// int64x1_t vmvn_s64 (int64x1_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vmvn_s8 (int8x8_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vmvn_f32 (float32x2_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vmvn_u16 (uint16x4_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vmvn_u32 (uint32x2_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x1_t vmvn_u64 (uint64x1_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vmvnq_u8 (uint8x16_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vmvnq_f64 (float64x2_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vmvnq_s16 (int16x8_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vmvnq_s32 (int32x4_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vmvnq_s64 (int64x2_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vmvnq_s8 (int8x16_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vmvnq_f32 (float32x4_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmvnq_u16 (uint16x8_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmvnq_u32 (uint32x4_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vmvnq_u64 (uint64x2_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vorr_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vorr_f64 (float64x1_t a, float64x1_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vorr_s16 (int16x4_t a, int16x4_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vorr_s32 (int32x2_t a, int32x2_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x1_t vorr_s64 (int64x1_t a, int64x1_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vorr_s8 (int8x8_t a, int8x8_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vorr_f32 (float32x2_t a, float32x2_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vorr_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vorr_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x1_t vorr_u64 (uint64x1_t a, uint64x1_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vorrq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vorrq_f64 (float64x2_t a, float64x2_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vorrq_s16 (int16x8_t a, int16x8_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vorrq_s32 (int32x4_t a, int32x4_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vorrq_s64 (int64x2_t a, int64x2_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vorrq_s8 (int8x16_t a, int8x16_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vorrq_f32 (float32x4_t a, float32x4_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vorrq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vorrq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vorrq_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vorn_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vorn_f64 (float64x1_t a, float64x1_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vorn_s16 (int16x4_t a, int16x4_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vorn_s32 (int32x2_t a, int32x2_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x1_t vorn_s64 (int64x1_t a, int64x1_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vorn_s8 (int8x8_t a, int8x8_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vorn_f32 (float32x2_t a, float32x2_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vorn_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vorn_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x1_t vorn_u64 (uint64x1_t a, uint64x1_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vornq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vornq_f64 (float64x2_t a, float64x2_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vornq_s16 (int16x8_t a, int16x8_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vornq_s32 (int32x4_t a, int32x4_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vornq_s64 (int64x2_t a, int64x2_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vornq_s8 (int8x16_t a, int8x16_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vornq_f32 (float32x4_t a, float32x4_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vornq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vornq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vornq_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMUL.P8 Dd, Dn, Dm + /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMUL.P8 Dd, Dn, Dm + /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMUL.P8 Qd, Qn, Qm + /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMUL.P8 Qd, Qn, Qm + /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly16x8_t vmull_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMULL.P8 Qd, Dn, Dm + /// A64: PMULL Vd.16B, Vn.8B, Vm.8B + /// + public static Vector128 PolynomialMultiplyWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly16x8_t vmull_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMULL.P8 Qd, Dn, Dm + /// A64: PMULL Vd.16B, Vn.8B, Vm.8B + /// + public static Vector128 PolynomialMultiplyWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly16x8_t vmull_high_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMULL.P8 Qd, Dn+1, Dm+1 + /// A64: PMULL2 Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly16x8_t vmull_high_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMULL.P8 Qd, Dn+1, Dm+1 + /// A64: PMULL2 Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vcnt_u8 (uint8x8_t a) + /// A32: VCNT.I8 Dd, Dm + /// A64: CNT Vd.8B, Vn.8B + /// + public static Vector64 PopCount(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vcnt_s8 (int8x8_t a) + /// A32: VCNT.I8 Dd, Dm + /// A64: CNT Vd.8B, Vn.8B + /// + public static Vector64 PopCount(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vcntq_u8 (uint8x16_t a) + /// A32: VCNT.I8 Qd, Qm + /// A64: CNT Vd.16B, Vn.16B + /// + public static Vector128 PopCount(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vcntq_s8 (int8x16_t a) + /// A32: VCNT.I8 Qd, Qm + /// A64: CNT Vd.16B, Vn.16B + /// + public static Vector128 PopCount(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vrecpe_f32 (float32x2_t a) + /// A32: VRECPE.F32 Dd, Dm + /// A64: FRECPE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vrecpe_u32 (uint32x2_t a) + /// A32: VRECPE.U32 Dd, Dm + /// A64: URECPE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vrecpeq_f32 (float32x4_t a) + /// A32: VRECPE.F32 Qd, Qm + /// A64: FRECPE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vrecpeq_u32 (uint32x4_t a) + /// A32: VRECPE.U32 Qd, Qm + /// A64: URECPE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vrsqrte_f32 (float32x2_t a) + /// A32: VRSQRTE.F32 Dd, Dm + /// A64: FRSQRTE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vrsqrte_u32 (uint32x2_t a) + /// A32: VRSQRTE.U32 Dd, Dm + /// A64: URSQRTE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vrsqrteq_f32 (float32x4_t a) + /// A32: VRSQRTE.F32 Qd, Qm + /// A64: FRSQRTE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vrsqrteq_u32 (uint32x4_t a) + /// A32: VRSQRTE.U32 Qd, Qm + /// A64: URSQRTE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vrsqrts_f32 (float32x2_t a, float32x2_t b) + /// A32: VRSQRTS.F32 Dd, Dn, Dm + /// A64: FRSQRTS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 ReciprocalSquareRootStep(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vrsqrtsq_f32 (float32x4_t a, float32x4_t b) + /// A32: VRSQRTS.F32 Qd, Qn, Qm + /// A64: FRSQRTS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 ReciprocalSquareRootStep(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vrecps_f32 (float32x2_t a, float32x2_t b) + /// A32: VRECPS.F32 Dd, Dn, Dm + /// A64: FRECPS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 ReciprocalStep(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vrecpsq_f32 (float32x4_t a, float32x4_t b) + /// A32: VRECPS.F32 Qd, Qn, Qm + /// A64: FRECPS Vd.4S, Vn.4S, Vm.4S /// - public static Vector128 CompareEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ReciprocalStep(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vceqq_s8 (int8x16_t a, int8x16_t b) - /// A32: VCEQ.I8 Qd, Qn, Qm - /// A64: CMEQ Vd.16B, Vn.16B, Vm.16B + /// int16x4_t vshl_s16 (int16x4_t a, int16x4_t b) + /// A32: VSHL.S16 Dd, Dn, Dm + /// A64: SSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector128 CompareEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmetic(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vceqq_f32 (float32x4_t a, float32x4_t b) - /// A32: VCEQ.F32 Qd, Qn, Qm - /// A64: FCMEQ Vd.4S, Vn.4S, Vm.4S + /// int32x2_t vshl_s32 (int32x2_t a, int32x2_t b) + /// A32: VSHL.S32 Dd, Dn, Dm + /// A64: SSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 CompareEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmetic(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vceqq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VCEQ.I16 Qd, Qn, Qm - /// A64: CMEQ Vd.8H, Vn.8H, Vm.8H + /// int8x8_t vshl_s8 (int8x8_t a, int8x8_t b) + /// A32: VSHL.S8 Dd, Dn, Dm + /// A64: SSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 CompareEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmetic(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vceqq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VCEQ.I32 Qd, Qn, Qm - /// A64: CMEQ Vd.4S, Vn.4S, Vm.4S + /// int16x8_t vshlq_s16 (int16x8_t a, int16x8_t b) + /// A32: VSHL.S16 Qd, Qn, Qm + /// A64: SSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector128 CompareEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmetic(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vcgt_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VCGT.U8 Dd, Dn, Dm - /// A64: CMHI Vd.8B, Vn.8B, Vm.8B + /// int32x4_t vshlq_s32 (int32x4_t a, int32x4_t b) + /// A32: VSHL.S32 Qd, Qn, Qm + /// A64: SSHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmetic(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vcgt_s16 (int16x4_t a, int16x4_t b) - /// A32: VCGT.S16 Dd, Dn, Dm - /// A64: CMGT Vd.4H, Vn.4H, Vm.4H + /// int64x2_t vshlq_s64 (int64x2_t a, int64x2_t b) + /// A32: VSHL.S64 Qd, Qn, Qm + /// A64: SSHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmetic(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vcgt_s32 (int32x2_t a, int32x2_t b) - /// A32: VCGT.S32 Dd, Dn, Dm - /// A64: CMGT Vd.2S, Vn.2S, Vm.2S + /// int8x16_t vshlq_s8 (int8x16_t a, int8x16_t b) + /// A32: VSHL.S8 Qd, Qn, Qm + /// A64: SSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmetic(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vcgt_s8 (int8x8_t a, int8x8_t b) - /// A32: VCGT.S8 Dd, Dn, Dm - /// A64: CMGT Vd.8B, Vn.8B, Vm.8B + /// int16x4_t vrshl_s16 (int16x4_t a, int16x4_t b) + /// A32: VRSHL.S16 Dd, Dn, Dm + /// A64: SRSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmeticRounded(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vcgt_f32 (float32x2_t a, float32x2_t b) - /// A32: VCGT.F32 Dd, Dn, Dm - /// A64: FCMGT Vd.2S, Vn.2S, Vm.2S + /// int32x2_t vrshl_s32 (int32x2_t a, int32x2_t b) + /// A32: VRSHL.S32 Dd, Dn, Dm + /// A64: SRSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmeticRounded(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vcgt_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VCGT.U16 Dd, Dn, Dm - /// A64: CMHI Vd.4H, Vn.4H, Vm.4H + /// int8x8_t vrshl_s8 (int8x8_t a, int8x8_t b) + /// A32: VRSHL.S8 Dd, Dn, Dm + /// A64: SRSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmeticRounded(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vcgt_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VCGT.U32 Dd, Dn, Dm - /// A64: CMHI Vd.2S, Vn.2S, Vm.2S + /// int16x8_t vrshlq_s16 (int16x8_t a, int16x8_t b) + /// A32: VRSHL.S16 Qd, Qn, Qm + /// A64: SRSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmeticRounded(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vcgtq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VCGT.U8 Qd, Qn, Qm - /// A64: CMHI Vd.16B, Vn.16B, Vm.16B + /// int32x4_t vrshlq_s32 (int32x4_t a, int32x4_t b) + /// A32: VRSHL.S32 Qd, Qn, Qm + /// A64: SRSHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmeticRounded(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vcgtq_s16 (int16x8_t a, int16x8_t b) - /// A32: VCGT.S16 Qd, Qn, Qm - /// A64: CMGT Vd.8H, Vn.8H, Vm.8H + /// int64x2_t vrshlq_s64 (int64x2_t a, int64x2_t b) + /// A32: VRSHL.S64 Qd, Qn, Qm + /// A64: SRSHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmeticRounded(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vcgtq_s32 (int32x4_t a, int32x4_t b) - /// A32: VCGT.S32 Qd, Qn, Qm - /// A64: CMGT Vd.4S, Vn.4S, Vm.4S + /// int8x16_t vrshlq_s8 (int8x16_t a, int8x16_t b) + /// A32: VRSHL.S8 Qd, Qn, Qm + /// A64: SRSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmeticRounded(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vcgtq_s8 (int8x16_t a, int8x16_t b) - /// A32: VCGT.S8 Qd, Qn, Qm - /// A64: CMGT Vd.16B, Vn.16B, Vm.16B + /// int16x4_t vqrshl_s16 (int16x4_t a, int16x4_t b) + /// A32: VQRSHL.S16 Dd, Dn, Dm + /// A64: SQRSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmeticRoundedSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vcgtq_f32 (float32x4_t a, float32x4_t b) - /// A32: VCGT.F32 Qd, Qn, Qm - /// A64: FCMGT Vd.4S, Vn.4S, Vm.4S + /// int32x2_t vqrshl_s32 (int32x2_t a, int32x2_t b) + /// A32: VQRSHL.S32 Dd, Dn, Dm + /// A64: SQRSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmeticRoundedSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vcgtq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VCGT.U16 Qd, Qn, Qm - /// A64: CMHI Vd.8H, Vn.8H, Vm.8H + /// int8x8_t vqrshl_s8 (int8x8_t a, int8x8_t b) + /// A32: VQRSHL.S8 Dd, Dn, Dm + /// A64: SQRSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmeticRoundedSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vcgtq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VCGT.U32 Qd, Qn, Qm - /// A64: CMHI Vd.4S, Vn.4S, Vm.4S + /// int16x8_t vqrshlq_s16 (int16x8_t a, int16x8_t b) + /// A32: VQRSHL.S16 Qd, Qn, Qm + /// A64: SQRSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmeticRoundedSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vcge_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VCGE.U8 Dd, Dn, Dm - /// A64: CMHS Vd.8B, Vn.8B, Vm.8B + /// int32x4_t vqrshlq_s32 (int32x4_t a, int32x4_t b) + /// A32: VQRSHL.S32 Qd, Qn, Qm + /// A64: SQRSHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmeticRoundedSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vcge_s16 (int16x4_t a, int16x4_t b) - /// A32: VCGE.S16 Dd, Dn, Dm - /// A64: CMGE Vd.4H, Vn.4H, Vm.4H + /// int64x2_t vqrshlq_s64 (int64x2_t a, int64x2_t b) + /// A32: VQRSHL.S64 Qd, Qn, Qm + /// A64: SQRSHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmeticRoundedSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vcge_s32 (int32x2_t a, int32x2_t b) - /// A32: VCGE.S32 Dd, Dn, Dm - /// A64: CMGE Vd.2S, Vn.2S, Vm.2S + /// int8x16_t vqrshlq_s8 (int8x16_t a, int8x16_t b) + /// A32: VQRSHL.S8 Qd, Qn, Qm + /// A64: SQRSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmeticRoundedSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vcge_s8 (int8x8_t a, int8x8_t b) - /// A32: VCGE.S8 Dd, Dn, Dm - /// A64: CMGE Vd.8B, Vn.8B, Vm.8B + /// int64x1_t vqrshl_s64 (int64x1_t a, int64x1_t b) + /// A32: VQRSHL.S64 Dd, Dn, Dm + /// A64: SQRSHL Dd, Dn, Dm /// - public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmeticRoundedSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vcge_f32 (float32x2_t a, float32x2_t b) - /// A32: VCGE.F32 Dd, Dn, Dm - /// A64: FCMGE Vd.2S, Vn.2S, Vm.2S + /// int64x1_t vrshl_s64 (int64x1_t a, int64x1_t b) + /// A32: VRSHL.S64 Dd, Dn, Dm + /// A64: SRSHL Dd, Dn, Dm /// - public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmeticRoundedScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vcge_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VCGE.U16 Dd, Dn, Dm - /// A64: CMHS Vd.4H, Vn.4H, Vm.4H + /// int16x4_t vqshl_s16 (int16x4_t a, int16x4_t b) + /// A32: VQSHL.S16 Dd, Dn, Dm + /// A64: SQSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmeticSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vcge_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VCGE.U32 Dd, Dn, Dm - /// A64: CMHS Vd.2S, Vn.2S, Vm.2S + /// int32x2_t vqshl_s32 (int32x2_t a, int32x2_t b) + /// A32: VQSHL.S32 Dd, Dn, Dm + /// A64: SQSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmeticSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vcgeq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VCGE.U8 Qd, Qn, Qm - /// A64: CMHS Vd.16B, Vn.16B, Vm.16B + /// int8x8_t vqshl_s8 (int8x8_t a, int8x8_t b) + /// A32: VQSHL.S8 Dd, Dn, Dm + /// A64: SQSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmeticSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vcgeq_s16 (int16x8_t a, int16x8_t b) - /// A32: VCGE.S16 Qd, Qn, Qm - /// A64: CMGE Vd.8H, Vn.8H, Vm.8H + /// int16x8_t vqshlq_s16 (int16x8_t a, int16x8_t b) + /// A32: VQSHL.S16 Qd, Qn, Qm + /// A64: SQSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmeticSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vcgeq_s32 (int32x4_t a, int32x4_t b) - /// A32: VCGE.S32 Qd, Qn, Qm - /// A64: CMGE Vd.4S, Vn.4S, Vm.4S + /// int32x4_t vqshlq_s32 (int32x4_t a, int32x4_t b) + /// A32: VQSHL.S32 Qd, Qn, Qm + /// A64: SQSHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmeticSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vcgeq_s8 (int8x16_t a, int8x16_t b) - /// A32: VCGE.S8 Qd, Qn, Qm - /// A64: CMGE Vd.16B, Vn.16B, Vm.16B + /// int64x2_t vqshlq_s64 (int64x2_t a, int64x2_t b) + /// A32: VQSHL.S64 Qd, Qn, Qm + /// A64: SQSHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmeticSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vcgeq_f32 (float32x4_t a, float32x4_t b) - /// A32: VCGE.F32 Qd, Qn, Qm - /// A64: FCMGE Vd.4S, Vn.4S, Vm.4S + /// int8x16_t vqshlq_s8 (int8x16_t a, int8x16_t b) + /// A32: VQSHL.S8 Qd, Qn, Qm + /// A64: SQSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftArithmeticSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vcgeq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VCGE.U16 Qd, Qn, Qm - /// A64: CMHS Vd.8H, Vn.8H, Vm.8H + /// int64x1_t vqshl_s64 (int64x1_t a, int64x1_t b) + /// A32: VQSHL.S64 Dd, Dn, Dm + /// A64: SQSHL Dd, Dn, Dm /// - public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmeticSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vcgeq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VCGE.U32 Qd, Qn, Qm - /// A64: CMHS Vd.4S, Vn.4S, Vm.4S + /// int64x1_t vshl_s64 (int64x1_t a, int64x1_t b) + /// A32: VSHL.S64 Dd, Dn, Dm + /// A64: SSHL Dd, Dn, Dm /// - public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftArithmeticScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vclt_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VCLT.U8 Dd, Dn, Dm - /// A64: CMHI Vd.8B, Vn.8B, Vm.8B + /// uint8x8_t vshl_n_u8 (uint8x8_t a, const int n) + /// A32: VSHL.I8 Dd, Dm, #n + /// A64: SHL Vd.8B, Vn.8B, #n /// - public static Vector64 CompareLessThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogical(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vclt_s16 (int16x4_t a, int16x4_t b) - /// A32: VCLT.S16 Dd, Dn, Dm - /// A64: CMGT Vd.4H, Vn.4H, Vm.4H + /// int16x4_t vshl_n_s16 (int16x4_t a, const int n) + /// A32: VSHL.I16 Dd, Dm, #n + /// A64: SHL Vd.4H, Vn.4H, #n /// - public static Vector64 CompareLessThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogical(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vclt_s32 (int32x2_t a, int32x2_t b) - /// A32: VCLT.S32 Dd, Dn, Dm - /// A64: CMGT Vd.2S, Vn.2S, Vm.2S + /// int32x2_t vshl_n_s32 (int32x2_t a, const int n) + /// A32: VSHL.I32 Dd, Dm, #n + /// A64: SHL Vd.2S, Vn.2S, #n /// - public static Vector64 CompareLessThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogical(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vclt_s8 (int8x8_t a, int8x8_t b) - /// A32: VCLT.S8 Dd, Dn, Dm - /// A64: CMGT Vd.8B, Vn.8B, Vm.8B + /// int8x8_t vshl_n_s8 (int8x8_t a, const int n) + /// A32: VSHL.I8 Dd, Dm, #n + /// A64: SHL Vd.8B, Vn.8B, #n /// - public static Vector64 CompareLessThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogical(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vclt_f32 (float32x2_t a, float32x2_t b) - /// A32: VCLT.F32 Dd, Dn, Dm - /// A64: FCMGT Vd.2S, Vn.2S, Vm.2S + /// uint16x4_t vshl_n_u16 (uint16x4_t a, const int n) + /// A32: VSHL.I16 Dd, Dm, #n + /// A64: SHL Vd.4H, Vn.4H, #n /// - public static Vector64 CompareLessThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogical(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vclt_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VCLT.U16 Dd, Dn, Dm - /// A64: CMHI Vd.4H, Vn.4H, Vm.4H + /// uint32x2_t vshl_n_u32 (uint32x2_t a, const int n) + /// A32: VSHL.I32 Dd, Dm, #n + /// A64: SHL Vd.2S, Vn.2S, #n /// - public static Vector64 CompareLessThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogical(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vclt_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VCLT.U32 Dd, Dn, Dm - /// A64: CMHI Vd.2S, Vn.2S, Vm.2S + /// uint8x16_t vshlq_n_u8 (uint8x16_t a, const int n) + /// A32: VSHL.I8 Qd, Qm, #n + /// A64: SHL Vd.16B, Vn.16B, #n /// - public static Vector64 CompareLessThan(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vcltq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VCLT.U8 Qd, Qn, Qm - /// A64: CMHI Vd.16B, Vn.16B, Vm.16B + /// int16x8_t vshlq_n_s16 (int16x8_t a, const int n) + /// A32: VSHL.I16 Qd, Qm, #n + /// A64: SHL Vd.8H, Vn.8H, #n /// - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vcltq_s16 (int16x8_t a, int16x8_t b) - /// A32: VCLT.S16 Qd, Qn, Qm - /// A64: CMGT Vd.8H, Vn.8H, Vm.8H + /// int64x2_t vshlq_n_s64 (int64x2_t a, const int n) + /// A32: VSHL.I64 Qd, Qm, #n + /// A64: SHL Vd.2D, Vn.2D, #n /// - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vcltq_s32 (int32x4_t a, int32x4_t b) - /// A32: VCLT.S32 Qd, Qn, Qm - /// A64: CMGT Vd.4S, Vn.4S, Vm.4S + /// int8x16_t vshlq_n_s8 (int8x16_t a, const int n) + /// A32: VSHL.I8 Qd, Qm, #n + /// A64: SHL Vd.16B, Vn.16B, #n /// - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vcltq_s8 (int8x16_t a, int8x16_t b) - /// A32: VCLT.S8 Qd, Qn, Qm - /// A64: CMGT Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vshlq_n_u16 (uint16x8_t a, const int n) + /// A32: VSHL.I16 Qd, Qm, #n + /// A64: SHL Vd.8H, Vn.8H, #n /// - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vcltq_f32 (float32x4_t a, float32x4_t b) - /// A32: VCLT.F32 Qd, Qn, Qm - /// A64: FCMGT Vd.4S, Vn.4S, Vm.4S + /// uint32x4_t vshlq_n_u32 (uint32x4_t a, const int n) + /// A32: VSHL.I32 Qd, Qm, #n + /// A64: SHL Vd.4S, Vn.4S, #n /// - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vcltq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VCLT.U16 Qd, Qn, Qm - /// A64: CMHI Vd.8H, Vn.8H, Vm.8H + /// uint64x2_t vshlq_n_u64 (uint64x2_t a, const int n) + /// A32: VSHL.I64 Qd, Qm, #n + /// A64: SHL Vd.2D, Vn.2D, #n /// - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vcltq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VCLT.U32 Qd, Qn, Qm - /// A64: CMHI Vd.4S, Vn.4S, Vm.4S + /// uint8x8_t vqshl_n_u8 (uint8x8_t a, const int n) + /// A32: VQSHL.U8 Dd, Dm, #n + /// A64: UQSHL Vd.8B, Vn.8B, #n /// - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogicalSaturate(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vcle_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VCLE.U8 Dd, Dn, Dm - /// A64: CMHS Vd.8B, Vn.8B, Vm.8B + /// int16x4_t vqshl_n_s16 (int16x4_t a, const int n) + /// A32: VQSHL.S16 Dd, Dm, #n + /// A64: SQSHL Vd.4H, Vn.4H, #n /// - public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogicalSaturate(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vcle_s16 (int16x4_t a, int16x4_t b) - /// A32: VCLE.S16 Dd, Dn, Dm - /// A64: CMGE Vd.4H, Vn.4H, Vm.4H + /// int32x2_t vqshl_n_s32 (int32x2_t a, const int n) + /// A32: VQSHL.S32 Dd, Dm, #n + /// A64: SQSHL Vd.2S, Vn.2S, #n /// - public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogicalSaturate(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vcle_s32 (int32x2_t a, int32x2_t b) - /// A32: VCLE.S32 Dd, Dn, Dm - /// A64: CMGE Vd.2S, Vn.2S, Vm.2S + /// int8x8_t vqshl_n_s8 (int8x8_t a, const int n) + /// A32: VQSHL.S8 Dd, Dm, #n + /// A64: SQSHL Vd.8B, Vn.8B, #n /// - public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogicalSaturate(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vcle_s8 (int8x8_t a, int8x8_t b) - /// A32: VCLE.S8 Dd, Dn, Dm - /// A64: CMGE Vd.8B, Vn.8B, Vm.8B + /// uint16x4_t vqshl_n_u16 (uint16x4_t a, const int n) + /// A32: VQSHL.U16 Dd, Dm, #n + /// A64: UQSHL Vd.4H, Vn.4H, #n /// - public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogicalSaturate(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vcle_f32 (float32x2_t a, float32x2_t b) - /// A32: VCLE.F32 Dd, Dn, Dm - /// A64: FCMGE Vd.2S, Vn.2S, Vm.2S + /// uint32x2_t vqshl_n_u32 (uint32x2_t a, const int n) + /// A32: VQSHL.U32 Dd, Dm, #n + /// A64: UQSHL Vd.2S, Vn.2S, #n /// - public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogicalSaturate(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vcle_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VCLE.U16 Dd, Dn, Dm - /// A64: CMHS Vd.4H, Vn.4H, Vm.4H + /// uint8x16_t vqshlq_n_u8 (uint8x16_t a, const int n) + /// A32: VQSHL.U8 Qd, Qm, #n + /// A64: UQSHL Vd.16B, Vn.16B, #n /// - public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vcle_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VCLE.U32 Dd, Dn, Dm - /// A64: CMHS Vd.2S, Vn.2S, Vm.2S + /// int16x8_t vqshlq_n_s16 (int16x8_t a, const int n) + /// A32: VQSHL.S16 Qd, Qm, #n + /// A64: SQSHL Vd.8H, Vn.8H, #n /// - public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vcleq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VCLE.U8 Qd, Qn, Qm - /// A64: CMHS Vd.16B, Vn.16B, Vm.16B + /// int32x4_t vqshlq_n_s32 (int32x4_t a, const int n) + /// A32: VQSHL.S32 Qd, Qm, #n + /// A64: SQSHL Vd.4S, Vn.4S, #n /// - public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vcleq_s16 (int16x8_t a, int16x8_t b) - /// A32: VCLE.S16 Qd, Qn, Qm - /// A64: CMGE Vd.8H, Vn.8H, Vm.8H + /// int64x2_t vqshlq_n_s64 (int64x2_t a, const int n) + /// A32: VQSHL.S64 Qd, Qm, #n + /// A64: SQSHL Vd.2D, Vn.2D, #n /// - public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vcleq_s32 (int32x4_t a, int32x4_t b) - /// A32: VCLE.S32 Qd, Qn, Qm - /// A64: CMGE Vd.4S, Vn.4S, Vm.4S + /// int8x16_t vqshlq_n_s8 (int8x16_t a, const int n) + /// A32: VQSHL.S8 Qd, Qm, #n + /// A64: SQSHL Vd.16B, Vn.16B, #n /// - public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vcleq_s8 (int8x16_t a, int8x16_t b) - /// A32: VCLE.S8 Qd, Qn, Qm - /// A64: CMGE Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vqshlq_n_u16 (uint16x8_t a, const int n) + /// A32: VQSHL.U16 Qd, Qm, #n + /// A64: UQSHL Vd.8H, Vn.8H, #n /// - public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vcleq_f32 (float32x4_t a, float32x4_t b) - /// A32: VCLE.F32 Qd, Qn, Qm - /// A64: FCMGE Vd.4S, Vn.4S, Vm.4S + /// uint32x4_t vqshlq_n_u32 (uint32x4_t a, const int n) + /// A32: VQSHL.U32 Qd, Qm, #n + /// A64: UQSHL Vd.4S, Vn.4S, #n /// - public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vcleq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VCLE.U16 Qd, Qn, Qm - /// A64: CMHS Vd.8H, Vn.8H, Vm.8H + /// uint64x2_t vqshlq_n_u64 (uint64x2_t a, const int n) + /// A32: VQSHL.U64 Qd, Qm, #n + /// A64: UQSHL Vd.2D, Vn.2D, #n /// - public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vcleq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VCLE.U32 Qd, Qn, Qm - /// A64: CMHS Vd.4S, Vn.4S, Vm.4S + /// int64x1_t vqshl_n_s64 (int64x1_t a, const int n) + /// A32: VQSHL.S64 Dd, Dm, #n + /// A64: SQSHL Dd, Dn, #n /// - public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vtst_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VTST.8 Dd, Dn, Dm - /// A64: CMTST Vd.8B, Vn.8B, Vm.8B + /// uint64x1_t vqshl_n_u64 (uint64x1_t a, const int n) + /// A32: VQSHL.U64 Dd, Dm, #n + /// A64: UQSHL Dd, Dn, #n /// - public static Vector64 CompareTest(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vtst_s16 (int16x4_t a, int16x4_t b) - /// A32: VTST.16 Dd, Dn, Dm - /// A64: CMTST Vd.4H, Vn.4H, Vm.4H + /// uint16x4_t vqshlu_n_s16 (int16x4_t a, const int n) + /// A32: VQSHLU.S16 Dd, Dm, #n + /// A64: SQSHLU Vd.4H, Vn.4H, #n /// - public static Vector64 CompareTest(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogicalSaturateUnsigned(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vtst_s32 (int32x2_t a, int32x2_t b) - /// A32: VTST.32 Dd, Dn, Dm - /// A64: CMTST Vd.2S, Vn.2S, Vm.2S + /// uint32x2_t vqshlu_n_s32 (int32x2_t a, const int n) + /// A32: VQSHLU.S32 Dd, Dm, #n + /// A64: SQSHLU Vd.2S, Vn.2S, #n + /// + public static Vector64 ShiftLeftLogicalSaturateUnsigned(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vqshlu_n_s8 (int8x8_t a, const int n) + /// A32: VQSHLU.S8 Dd, Dm, #n + /// A64: SQSHLU Vd.8B, Vn.8B, #n /// - public static Vector64 CompareTest(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogicalSaturateUnsigned(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vtst_s8 (int8x8_t a, int8x8_t b) - /// A32: VTST.8 Dd, Dn, Dm - /// A64: CMTST Vd.8B, Vn.8B, Vm.8B + /// uint16x8_t vqshluq_n_s16 (int16x8_t a, const int n) + /// A32: VQSHLU.S16 Qd, Qm, #n + /// A64: SQSHLU Vd.8H, Vn.8H, #n /// - public static Vector64 CompareTest(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalSaturateUnsigned(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vtst_f32 (float32x2_t a, float32x2_t b) - /// A32: VTST.32 Dd, Dn, Dm - /// A64: CMTST Vd.2S, Vn.2S, Vm.2S - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint32x4_t vqshluq_n_s32 (int32x4_t a, const int n) + /// A32: VQSHLU.S32 Qd, Qm, #n + /// A64: SQSHLU Vd.4S, Vn.4S, #n /// - public static Vector64 CompareTest(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalSaturateUnsigned(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vtst_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VTST.16 Dd, Dn, Dm - /// A64: CMTST Vd.4H, Vn.4H, Vm.4H + /// uint64x2_t vqshluq_n_s64 (int64x2_t a, const int n) + /// A32: VQSHLU.S64 Qd, Qm, #n + /// A64: SQSHLU Vd.2D, Vn.2D, #n /// - public static Vector64 CompareTest(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalSaturateUnsigned(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vtst_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VTST.32 Dd, Dn, Dm - /// A64: CMTST Vd.2S, Vn.2S, Vm.2S + /// uint8x16_t vqshluq_n_s8 (int8x16_t a, const int n) + /// A32: VQSHLU.S8 Qd, Qm, #n + /// A64: SQSHLU Vd.16B, Vn.16B, #n /// - public static Vector64 CompareTest(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalSaturateUnsigned(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vtstq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VTST.8 Qd, Qn, Qm - /// A64: CMTST Vd.16B, Vn.16B, Vm.16B + /// uint64x1_t vqshlu_n_s64 (int64x1_t a, const int n) + /// A32: VQSHLU.S64 Dd, Dm, #n + /// A64: SQSHLU Dd, Dn, #n /// - public static Vector128 CompareTest(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogicalSaturateUnsignedScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vtstq_s16 (int16x8_t a, int16x8_t b) - /// A32: VTST.16 Qd, Qn, Qm - /// A64: CMTST Vd.8H, Vn.8H, Vm.8H + /// int64x1_t vshl_n_s64 (int64x1_t a, const int n) + /// A32: VSHL.I64 Dd, Dm, #n + /// A64: SHL Dd, Dn, #n /// - public static Vector128 CompareTest(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogicalScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vtstq_s32 (int32x4_t a, int32x4_t b) - /// A32: VTST.32 Qd, Qn, Qm - /// A64: CMTST Vd.4S, Vn.4S, Vm.4S + /// uint64x1_t vshl_n_u64 (uint64x1_t a, const int n) + /// A32: VSHL.I64 Dd, Dm, #n + /// A64: SHL Dd, Dn, #n /// - public static Vector128 CompareTest(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLeftLogicalScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vtstq_s8 (int8x16_t a, int8x16_t b) - /// A32: VTST.8 Qd, Qn, Qm - /// A64: CMTST Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vshll_n_u8 (uint8x8_t a, const int n) + /// A32: VSHLL.U8 Qd, Dm, #n + /// A64: USHLL Vd.8H, Vn.8B, #n /// - public static Vector128 CompareTest(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalWideningLower(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vtstq_f32 (float32x4_t a, float32x4_t b) - /// A32: VTST.32 Qd, Qn, Qm - /// A64: CMTST Vd.4S, Vn.4S, Vm.4S - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// int32x4_t vshll_n_s16 (int16x4_t a, const int n) + /// A32: VSHLL.S16 Qd, Dm, #n + /// A64: SSHLL Vd.4S, Vn.4H, #n /// - public static Vector128 CompareTest(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalWideningLower(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vtstq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VTST.16 Qd, Qn, Qm - /// A64: CMTST Vd.8H, Vn.8H, Vm.8H + /// int64x2_t vshll_n_s32 (int32x2_t a, const int n) + /// A32: VSHLL.S32 Qd, Dm, #n + /// A64: SSHLL Vd.2D, Vn.2S, #n /// - public static Vector128 CompareTest(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalWideningLower(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vtstq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VTST.32 Qd, Qn, Qm - /// A64: CMTST Vd.4S, Vn.4S, Vm.4S + /// int16x8_t vshll_n_s8 (int8x8_t a, const int n) + /// A32: VSHLL.S8 Qd, Dm, #n + /// A64: SSHLL Vd.8H, Vn.8B, #n /// - public static Vector128 CompareTest(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalWideningLower(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vdiv_f64 (float64x1_t a, float64x1_t b) - /// A32: VDIV.F64 Dd, Dn, Dm - /// A64: FDIV Dd, Dn, Dm + /// uint32x4_t vshll_n_u16 (uint16x4_t a, const int n) + /// A32: VSHLL.U16 Qd, Dm, #n + /// A64: USHLL Vd.4S, Vn.4H, #n /// - public static Vector64 DivideScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalWideningLower(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32_t vdivs_f32 (float32_t a, float32_t b) - /// A32: VDIV.F32 Sd, Sn, Sm - /// A64: FDIV Sd, Sn, Sm - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint64x2_t vshll_n_u32 (uint32x2_t a, const int n) + /// A32: VSHLL.U32 Qd, Dm, #n + /// A64: USHLL Vd.2D, Vn.2S, #n /// - public static Vector64 DivideScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalWideningLower(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vmovn_s16 (int16x8_t a) - /// A32: VMOVN.I16 Dd, Qm - /// A64: XTN Vd.8B, Vn.8H + /// uint16x8_t vshll_high_n_u8 (uint8x16_t a, const int n) + /// A32: VSHLL.U8 Qd, Dm+1, #n + /// A64: USHLL2 Vd.8H, Vn.16B, #n /// - public static Vector64 ExtractAndNarrowLow (Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalWideningUpper(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vmovn_s32 (int32x4_t a) - /// A32: VMOVN.I32 Dd, Qm - /// A64: XTN Vd.4H, Vn.4S + /// int32x4_t vshll_high_n_s16 (int16x8_t a, const int n) + /// A32: VSHLL.S16 Qd, Dm+1, #n + /// A64: SSHLL2 Vd.4S, Vn.8H, #n /// - public static Vector64 ExtractAndNarrowLow (Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalWideningUpper(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vmovn_s64 (int64x2_t a) - /// A32: VMOVN.I64 Dd, Qm - /// A64: XTN Vd.2S, Vn.2D + /// int64x2_t vshll_high_n_s32 (int32x4_t a, const int n) + /// A32: VSHLL.S32 Qd, Dm+1, #n + /// A64: SSHLL2 Vd.2D, Vn.4S, #n /// - public static Vector64 ExtractAndNarrowLow (Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalWideningUpper(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vmovn_u16 (uint16x8_t a) - /// A32: VMOVN.I16 Dd, Qm - /// A64: XTN Vd.8B, Vn.8H + /// int16x8_t vshll_high_n_s8 (int8x16_t a, const int n) + /// A32: VSHLL.S8 Qd, Dm+1, #n + /// A64: SSHLL2 Vd.8H, Vn.16B, #n /// - public static Vector64 ExtractAndNarrowLow (Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalWideningUpper(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vmovn_u32 (uint32x4_t a) - /// A32: VMOVN.I32 Dd, Qm - /// A64: XTN Vd.4H, Vn.4S + /// uint32x4_t vshll_high_n_u16 (uint16x8_t a, const int n) + /// A32: VSHLL.U16 Qd, Dm+1, #n + /// A64: USHLL2 Vd.4S, Vn.8H, #n /// - public static Vector64 ExtractAndNarrowLow (Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalWideningUpper(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vmovn_u64 (uint64x2_t a) - /// A32: VMOVN.I64 Dd, Qm - /// A64: XTN Vd.2S, Vn.2D + /// uint64x2_t vshll_high_n_u32 (uint32x4_t a, const int n) + /// A32: VSHLL.U32 Qd, Dm+1, #n + /// A64: USHLL2 Vd.2D, Vn.4S, #n /// - public static Vector64 ExtractAndNarrowLow (Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLeftLogicalWideningUpper(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vmovn_high_s16 (int8x8_t r, int16x8_t a) - /// A32: VMOVN.I16 Dd+1, Qm - /// A64: XTN2 Vd.16B, Vn.8H + /// uint8x8_t vshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VSHL.U8 Dd, Dn, Dm + /// A64: USHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogical(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vmovn_high_s32 (int16x4_t r, int32x4_t a) - /// A32: VMOVN.I32 Dd+1, Qm - /// A64: XTN2 Vd.8H, Vn.4S + /// uint16x4_t vshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VSHL.U16 Dd, Dn, Dm + /// A64: USHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogical(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vmovn_high_s64 (int32x2_t r, int64x2_t a) - /// A32: VMOVN.I64 Dd+1, Qm - /// A64: XTN2 Vd.4S, Vn.2D + /// uint32x2_t vshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VSHL.U32 Dd, Dn, Dm + /// A64: USHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogical(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vmovn_high_u16 (uint8x8_t r, uint16x8_t a) - /// A32: VMOVN.I16 Dd+1, Qm - /// A64: XTN2 Vd.16B, Vn.8H + /// uint8x8_t vshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VSHL.U8 Dd, Dn, Dm + /// A64: USHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogical(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vmovn_high_u32 (uint16x4_t r, uint32x4_t a) - /// A32: VMOVN.I32 Dd+1, Qm - /// A64: XTN2 Vd.8H, Vn.4S + /// uint16x4_t vshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VSHL.U16 Dd, Dn, Dm + /// A64: USHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogical(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vmovn_high_u64 (uint32x2_t r, uint64x2_t a) - /// A32: VMOVN.I64 Dd+1, Qm - /// A64: XTN2 Vd.4S, Vn.2D + /// uint32x2_t vshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VSHL.U32 Dd, Dn, Dm + /// A64: USHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogical(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vfma_f32 (float32x2_t a, float32x2_t b, float32x2_t c) - /// A32: VFMA.F32 Dd, Dn, Dm - /// A64: FMLA Vd.2S, Vn.2S, Vm.2S + /// uint8x16_t vshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VSHL.U8 Qd, Qn, Qm + /// A64: USHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 FusedMultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vfmaq_f32 (float32x4_t a, float32x4_t b, float32x4_t c) - /// A32: VFMA.F32 Qd, Qn, Qm - /// A64: FMLA Vd.4S, Vn.4S, Vm.4S + /// uint16x8_t vshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VSHL.U16 Qd, Qn, Qm + /// A64: USHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector128 FusedMultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vfma_f64 (float64x1_t a, float64x1_t b, float64x1_t c) - /// A32: VFMA.F64 Dd, Dn, Dm - /// A64: FMADD Dd, Dn, Dm, Da + /// uint32x4_t vshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VSHL.U32 Qd, Qn, Qm + /// A64: USHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 FusedMultiplyAddScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// float32_t vfmas_f32 (float32_t a, float32_t b, float32_t c) - /// A32: VFMA.F32 Sd, Sn, Sm - /// A64: FMADD Sd, Sn, Sm, Sa - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint64x2_t vshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VSHL.U64 Qd, Qn, Qm + /// A64: USHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector64 FusedMultiplyAddScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vfnma_f64 (float64x1_t a, float64x1_t b, float64x1_t c) - /// A32: VFNMA.F64 Dd, Dn, Dm - /// A64: FNMADD Dd, Dn, Dm, Da - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x16_t vshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VSHL.U8 Qd, Qn, Qm + /// A64: USHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 FusedMultiplyAddNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// float32_t vfnmas_f32 (float32_t a, float32_t b, float32_t c) - /// A32: VFNMA.F32 Sd, Sn, Sm - /// A64: FNMADD Sd, Sn, Sm, Sa - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x8_t vshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VSHL.U16 Qd, Qn, Qm + /// A64: USHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector64 FusedMultiplyAddNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vfms_f32 (float32x2_t a, float32x2_t b, float32x2_t c) - /// A32: VFMS.F32 Dd, Dn, Dm - /// A64: FMLS Vd.2S, Vn.2S, Vm.2S + /// uint32x4_t vshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VSHL.U32 Qd, Qn, Qm + /// A64: USHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 FusedMultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vfmsq_f32 (float32x4_t a, float32x4_t b, float32x4_t c) - /// A32: VFMS.F32 Qd, Qn, Qm - /// A64: FMLS Vd.4S, Vn.4S, Vm.4S + /// uint64x2_t vshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VSHL.U64 Qd, Qn, Qm + /// A64: USHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector128 FusedMultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vfms_f64 (float64x1_t a, float64x1_t b, float64x1_t c) - /// A32: VFMS.F64 Dd, Dn, Dm - /// A64: FMSUB Dd, Dn, Dm, Da + /// uint8x8_t vrshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VRSHL.U8 Dd, Dn, Dm + /// A64: URSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector64 FusedMultiplySubtractScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRounded(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// float32_t vfmss_f32 (float32_t a, float32_t b, float32_t c) - /// A32: VFMS.F32 Sd, Sn, Sm - /// A64: FMSUB Sd, Sn, Sm, Sa - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x4_t vrshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VRSHL.U16 Dd, Dn, Dm + /// A64: URSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector64 FusedMultiplySubtractScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRounded(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vfnms_f64 (float64x1_t a, float64x1_t b, float64x1_t c) - /// A32: VFNMS.F64 Dd, Dn, Dm - /// A64: FNMSUB Dd, Dn, Dm, Da - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint32x2_t vrshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VRSHL.U32 Dd, Dn, Dm + /// A64: URSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector64 FusedMultiplySubtractNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRounded(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// float32_t vfnmss_f32 (float32_t a, float32_t b, float32_t c) - /// A32: VFNMS.F32 Sd, Sn, Sm - /// A64: FNMSUB Sd, Sn, Sm, Sa - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x8_t vrshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VRSHL.U8 Dd, Dn, Dm + /// A64: URSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector64 FusedMultiplySubtractNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRounded(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vcls_s16 (int16x4_t a) - /// A32: VCLS.S16 Dd, Dm - /// A64: CLS Vd.4H, Vn.4H + /// uint16x4_t vrshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VRSHL.U16 Dd, Dn, Dm + /// A64: URSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector64 LeadingSignCount(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRounded(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vcls_s32 (int32x2_t a) - /// A32: VCLS.S32 Dd, Dm - /// A64: CLS Vd.2S, Vn.2S + /// uint32x2_t vrshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VRSHL.U32 Dd, Dn, Dm + /// A64: URSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector64 LeadingSignCount(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRounded(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vcls_s8 (int8x8_t a) - /// A32: VCLS.S8 Dd, Dm - /// A64: CLS Vd.8B, Vn.8B + /// uint8x16_t vrshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VRSHL.U8 Qd, Qn, Qm + /// A64: URSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 LeadingSignCount(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vclsq_s16 (int16x8_t a) - /// A32: VCLS.S16 Qd, Qm - /// A64: CLS Vd.8H, Vn.8H + /// uint16x8_t vrshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VRSHL.U16 Qd, Qn, Qm + /// A64: URSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector128 LeadingSignCount(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vclsq_s32 (int32x4_t a) - /// A32: VCLS.S32 Qd, Qm - /// A64: CLS Vd.4S, Vn.4S + /// uint32x4_t vrshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VRSHL.U32 Qd, Qn, Qm + /// A64: URSHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector128 LeadingSignCount(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vclsq_s8 (int8x16_t a) - /// A32: VCLS.S8 Qd, Qm - /// A64: CLS Vd.16B, Vn.16B + /// uint64x2_t vrshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VRSHL.U64 Qd, Qn, Qm + /// A64: URSHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector128 LeadingSignCount(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vclz_u8 (uint8x8_t a) - /// A32: VCLZ.I8 Dd, Dm - /// A64: CLZ Vd.8B, Vn.8B + /// uint8x16_t vrshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VRSHL.U8 Qd, Qn, Qm + /// A64: URSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 LeadingZeroCount(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vclz_s16 (int16x4_t a) - /// A32: VCLZ.I16 Dd, Dm - /// A64: CLZ Vd.4H, Vn.4H + /// uint16x8_t vrshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VRSHL.U16 Qd, Qn, Qm + /// A64: URSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector64 LeadingZeroCount(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vclz_s32 (int32x2_t a) - /// A32: VCLZ.I32 Dd, Dm - /// A64: CLZ Vd.2S, Vn.2S + /// uint32x4_t vrshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VRSHL.U32 Qd, Qn, Qm + /// A64: URSHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 LeadingZeroCount(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vclz_s8 (int8x8_t a) - /// A32: VCLZ.I8 Dd, Dm - /// A64: CLZ Vd.8B, Vn.8B + /// uint64x2_t vrshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VRSHL.U64 Qd, Qn, Qm + /// A64: URSHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector64 LeadingZeroCount(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vclz_u16 (uint16x4_t a) - /// A32: VCLZ.I16 Dd, Dm - /// A64: CLZ Vd.4H, Vn.4H + /// uint8x8_t vqrshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VQRSHL.U8 Dd, Dn, Dm + /// A64: UQRSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector64 LeadingZeroCount(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRoundedSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vclz_u32 (uint32x2_t a) - /// A32: VCLZ.I32 Dd, Dm - /// A64: CLZ Vd.2S, Vn.2S + /// uint16x4_t vqrshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VQRSHL.U16 Dd, Dn, Dm + /// A64: UQRSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector64 LeadingZeroCount(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRoundedSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vclzq_u8 (uint8x16_t a) - /// A32: VCLZ.I8 Qd, Qm - /// A64: CLZ Vd.16B, Vn.16B + /// uint32x2_t vqrshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VQRSHL.U32 Dd, Dn, Dm + /// A64: UQRSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 LeadingZeroCount(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRoundedSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vclzq_s16 (int16x8_t a) - /// A32: VCLZ.I16 Qd, Qm - /// A64: CLZ Vd.8H, Vn.8H + /// uint8x8_t vqrshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VQRSHL.U8 Dd, Dn, Dm + /// A64: UQRSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 LeadingZeroCount(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRoundedSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vclzq_s32 (int32x4_t a) - /// A32: VCLZ.I32 Qd, Qm - /// A64: CLZ Vd.4S, Vn.4S + /// uint16x4_t vqrshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VQRSHL.U16 Dd, Dn, Dm + /// A64: UQRSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector128 LeadingZeroCount(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRoundedSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vclzq_s8 (int8x16_t a) - /// A32: VCLZ.I8 Qd, Qm - /// A64: CLZ Vd.16B, Vn.16B + /// uint32x2_t vqrshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VQRSHL.U32 Dd, Dn, Dm + /// A64: UQRSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 LeadingZeroCount(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRoundedSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vclzq_u16 (uint16x8_t a) - /// A32: VCLZ.I16 Qd, Qm - /// A64: CLZ Vd.8H, Vn.8H + /// uint8x16_t vqrshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VQRSHL.U8 Qd, Qn, Qm + /// A64: UQRSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector128 LeadingZeroCount(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vclzq_u32 (uint32x4_t a) - /// A32: VCLZ.I32 Qd, Qm - /// A64: CLZ Vd.4S, Vn.4S + /// uint16x8_t vqrshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VQRSHL.U16 Qd, Qn, Qm + /// A64: UQRSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector128 LeadingZeroCount(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vld1_u8 (uint8_t const * ptr) - /// A32: VLD1.8 Dd, [Rn] - /// A64: LD1 Vt.8B, [Xn] + /// uint32x4_t vqrshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VQRSHL.U32 Qd, Qn, Qm + /// A64: UQRSHL Vd.4S, Vn.4S, Vm.4S /// - public static unsafe Vector64 LoadVector64(byte* address) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vld1_f64 (float64_t const * ptr) - /// A32: VLD1.64 Dd, [Rn] - /// A64: LD1 Vt.1D, [Xn] + /// uint64x2_t vqrshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VQRSHL.U64 Qd, Qn, Qm + /// A64: UQRSHL Vd.2D, Vn.2D, Vm.2D /// - public static unsafe Vector64 LoadVector64(double* address) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vld1_s16 (int16_t const * ptr) - /// A32: VLD1.16 Dd, [Rn] - /// A64: LD1 Vt.4H, [Xn] + /// uint8x16_t vqrshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VQRSHL.U8 Qd, Qn, Qm + /// A64: UQRSHL Vd.16B, Vn.16B, Vm.16B /// - public static unsafe Vector64 LoadVector64(short* address) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vld1_s32 (int32_t const * ptr) - /// A32: VLD1.32 Dd, [Rn] - /// A64: LD1 Vt.2S, [Xn] + /// uint16x8_t vqrshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VQRSHL.U16 Qd, Qn, Qm + /// A64: UQRSHL Vd.8H, Vn.8H, Vm.8H /// - public static unsafe Vector64 LoadVector64(int* address) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// int64x1_t vld1_s64 (int64_t const * ptr) - /// A32: VLD1.64 Dd, [Rn] - /// A64: LD1 Vt.1D, [Xn] + /// uint32x4_t vqrshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VQRSHL.U32 Qd, Qn, Qm + /// A64: UQRSHL Vd.4S, Vn.4S, Vm.4S /// - public static unsafe Vector64 LoadVector64(long* address) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vld1_s8 (int8_t const * ptr) - /// A32: VLD1.8 Dd, [Rn] - /// A64: LD1 Vt.8B, [Xn] + /// uint64x2_t vqrshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VQRSHL.U64 Qd, Qn, Qm + /// A64: UQRSHL Vd.2D, Vn.2D, Vm.2D /// - public static unsafe Vector64 LoadVector64(sbyte* address) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vld1_f32 (float32_t const * ptr) - /// A32: VLD1.32 Dd, [Rn] - /// A64: LD1 Vt.2S, [Xn] + /// uint64x1_t vqrshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VQRSHL.U64 Dd, Dn, Dm + /// A64: UQRSHL Dd, Dn, Dm /// - public static unsafe Vector64 LoadVector64(float* address) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vld1_u16 (uint16_t const * ptr) - /// A32: VLD1.16 Dd, [Rn] - /// A64: LD1 Vt.4H, [Xn] + /// uint64x1_t vqrshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VQRSHL.U64 Dd, Dn, Dm + /// A64: UQRSHL Dd, Dn, Dm /// - public static unsafe Vector64 LoadVector64(ushort* address) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vld1_u32 (uint32_t const * ptr) - /// A32: VLD1.32 Dd, [Rn] - /// A64: LD1 Vt.2S, [Xn] + /// uint64x1_t vrshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VRSHL.U64 Dd, Dn, Dm + /// A64: URSHL Dd, Dn, Dm /// - public static unsafe Vector64 LoadVector64(uint* address) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRoundedScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint64x1_t vld1_u64 (uint64_t const * ptr) - /// A32: VLD1.64 Dd, [Rn] - /// A64: LD1 Vt.1D, [Xn] + /// uint64x1_t vrshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VRSHL.U64 Dd, Dn, Dm + /// A64: URSHL Dd, Dn, Dm /// - public static unsafe Vector64 LoadVector64(ulong* address) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalRoundedScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vld1q_u8 (uint8_t const * ptr) - /// A32: VLD1.8 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.16B, [Xn] + /// uint8x8_t vqshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VQSHL.U8 Dd, Dn, Dm + /// A64: UQSHL Vd.8B, Vn.8B, Vm.8B /// - public static unsafe Vector128 LoadVector128(byte* address) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// float64x2_t vld1q_f64 (float64_t const * ptr) - /// A32: VLD1.64 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.2D, [Xn] + /// uint16x4_t vqshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VQSHL.U16 Dd, Dn, Dm + /// A64: UQSHL Vd.4H, Vn.4H, Vm.4H /// - public static unsafe Vector128 LoadVector128(double* address) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vld1q_s16 (int16_t const * ptr) - /// A32: VLD1.16 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.8H, [Xn] + /// uint32x2_t vqshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VQSHL.U32 Dd, Dn, Dm + /// A64: UQSHL Vd.2S, Vn.2S, Vm.2S /// - public static unsafe Vector128 LoadVector128(short* address) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vld1q_s32 (int32_t const * ptr) - /// A32: VLD1.32 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.4S, [Xn] + /// uint8x8_t vqshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VQSHL.U8 Dd, Dn, Dm + /// A64: UQSHL Vd.8B, Vn.8B, Vm.8B /// - public static unsafe Vector128 LoadVector128(int* address) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// int64x2_t vld1q_s64 (int64_t const * ptr) - /// A32: VLD1.64 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.2D, [Xn] + /// uint16x4_t vqshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VQSHL.U16 Dd, Dn, Dm + /// A64: UQSHL Vd.4H, Vn.4H, Vm.4H /// - public static unsafe Vector128 LoadVector128(long* address) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vld1q_s8 (int8_t const * ptr) - /// A32: VLD1.8 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.16B, [Xn] + /// uint32x2_t vqshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VQSHL.U32 Dd, Dn, Dm + /// A64: UQSHL Vd.2S, Vn.2S, Vm.2S /// - public static unsafe Vector128 LoadVector128(sbyte* address) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalSaturate(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vld1q_f32 (float32_t const * ptr) - /// A32: VLD1.32 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.4S, [Xn] + /// uint8x16_t vqshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VQSHL.U8 Qd, Qn, Qm + /// A64: UQSHL Vd.16B, Vn.16B, Vm.16B /// - public static unsafe Vector128 LoadVector128(float* address) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vld1q_s16 (uint16_t const * ptr) - /// A32: VLD1.16 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.8H, [Xn] + /// uint16x8_t vqshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VQSHL.U16 Qd, Qn, Qm + /// A64: UQSHL Vd.8H, Vn.8H, Vm.8H /// - public static unsafe Vector128 LoadVector128(ushort* address) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vld1q_s32 (uint32_t const * ptr) - /// A32: VLD1.32 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.4S, [Xn] + /// uint32x4_t vqshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VQSHL.U32 Qd, Qn, Qm + /// A64: UQSHL Vd.4S, Vn.4S, Vm.4S /// - public static unsafe Vector128 LoadVector128(uint* address) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint64x2_t vld1q_u64 (uint64_t const * ptr) - /// A32: VLD1.64 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.2D, [Xn] + /// uint64x2_t vqshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VQSHL.U64 Qd, Qn, Qm + /// A64: UQSHL Vd.2D, Vn.2D, Vm.2D /// - public static unsafe Vector128 LoadVector128(ulong* address) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vmax_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VMAX.U8 Dd, Dn, Dm - /// A64: UMAX Vd.8B, Vn.8B, Vm.8B + /// uint8x16_t vqshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VQSHL.U8 Qd, Qn, Qm + /// A64: UQSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 Max(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vmax_s16 (int16x4_t a, int16x4_t b) - /// A32: VMAX.S16 Dd, Dn, Dm - /// A64: SMAX Vd.4H, Vn.4H, Vm.4H + /// uint16x8_t vqshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VQSHL.U16 Qd, Qn, Qm + /// A64: UQSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector64 Max(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vmax_s32 (int32x2_t a, int32x2_t b) - /// A32: VMAX.S32 Dd, Dn, Dm - /// A64: SMAX Vd.2S, Vn.2S, Vm.2S + /// uint32x4_t vqshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VQSHL.U32 Qd, Qn, Qm + /// A64: UQSHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 Max(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vmax_s8 (int8x8_t a, int8x8_t b) - /// A32: VMAX.S8 Dd, Dn, Dm - /// A64: SMAX Vd.8B, Vn.8B, Vm.8B + /// uint64x2_t vqshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VQSHL.U64 Qd, Qn, Qm + /// A64: UQSHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector64 Max(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vmax_f32 (float32x2_t a, float32x2_t b) - /// A32: VMAX.F32 Dd, Dn, Dm - /// A64: FMAX Vd.2S, Vn.2S, Vm.2S + /// uint64x1_t vqshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VQSHL.U64 Dd, Dn, Dm + /// A64: UQSHL Dd, Dn, Dm /// - public static Vector64 Max(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vmax_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VMAX.U16 Dd, Dn, Dm - /// A64: UMAX Vd.4H, Vn.4H, Vm.4H + /// uint64x1_t vqshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VQSHL.U64 Dd, Dn, Dm + /// A64: UQSHL Dd, Dn, Dm /// - public static Vector64 Max(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vmax_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VMAX.U32 Dd, Dn, Dm - /// A64: UMAX Vd.2S, Vn.2S, Vm.2S + /// uint64x1_t vshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VSHL.U64 Dd, Dn, Dm + /// A64: USHL Dd, Dn, Dm /// - public static Vector64 Max(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vmaxq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VMAX.U8 Qd, Qn, Qm - /// A64: UMAX Vd.16B, Vn.16B, Vm.16B + /// uint64x1_t vshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VSHL.U64 Dd, Dn, Dm + /// A64: USHL Dd, Dn, Dm /// - public static Vector128 Max(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftLogicalScalar(Vector64 value, Vector64 count) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vmaxq_s16 (int16x8_t a, int16x8_t b) - /// A32: VMAX.S16 Qd, Qn, Qm - /// A64: SMAX Vd.8H, Vn.8H, Vm.8H + /// int16x4_t vshr_n_s16 (int16x4_t a, const int n) + /// A32: VSHR.S16 Dd, Dm, #n + /// A64: SSHR Vd.4H, Vn.4H, #n /// - public static Vector128 Max(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmetic(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vmaxq_s32 (int32x4_t a, int32x4_t b) - /// A32: VMAX.S32 Qd, Qn, Qm - /// A64: SMAX Vd.4S, Vn.4S, Vm.4S + /// int32x2_t vshr_n_s32 (int32x2_t a, const int n) + /// A32: VSHR.S32 Dd, Dm, #n + /// A64: SSHR Vd.2S, Vn.2S, #n /// - public static Vector128 Max(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmetic(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vmaxq_s8 (int8x16_t a, int8x16_t b) - /// A32: VMAX.S8 Qd, Qn, Qm - /// A64: SMAX Vd.16B, Vn.16B, Vm.16B + /// int8x8_t vshr_n_s8 (int8x8_t a, const int n) + /// A32: VSHR.S8 Dd, Dm, #n + /// A64: SSHR Vd.8B, Vn.8B, #n /// - public static Vector128 Max(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmetic(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vmaxq_f32 (float32x4_t a, float32x4_t b) - /// A32: VMAX.F32 Qd, Qn, Qm - /// A64: FMAX Vd.4S, Vn.4S, Vm.4S + /// int16x8_t vshrq_n_s16 (int16x8_t a, const int n) + /// A32: VSHR.S16 Qd, Qm, #n + /// A64: SSHR Vd.8H, Vn.8H, #n /// - public static Vector128 Max(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmetic(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vmaxq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VMAX.U16 Qd, Qn, Qm - /// A64: UMAX Vd.8H, Vn.8H, Vm.8H + /// int32x4_t vshrq_n_s32 (int32x4_t a, const int n) + /// A32: VSHR.S32 Qd, Qm, #n + /// A64: SSHR Vd.4S, Vn.4S, #n /// - public static Vector128 Max(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmetic(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vmaxq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VMAX.U32 Qd, Qn, Qm - /// A64: UMAX Vd.4S, Vn.4S, Vm.4S + /// int64x2_t vshrq_n_s64 (int64x2_t a, const int n) + /// A32: VSHR.S64 Qd, Qm, #n + /// A64: SSHR Vd.2D, Vn.2D, #n /// - public static Vector128 Max(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmetic(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vmaxnm_f32 (float32x2_t a, float32x2_t b) - /// A32: VMAXNM.F32 Dd, Dn, Dm - /// A64: FMAXNM Vd.2S, Vn.2S, Vm.2S + /// int8x16_t vshrq_n_s8 (int8x16_t a, const int n) + /// A32: VSHR.S8 Qd, Qm, #n + /// A64: SSHR Vd.16B, Vn.16B, #n /// - public static Vector64 MaxNumber(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmetic(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vmaxnmq_f32 (float32x4_t a, float32x4_t b) - /// A32: VMAXNM.F32 Qd, Qn, Qm - /// A64: FMAXNM Vd.4S, Vn.4S, Vm.4S + /// int16x4_t vsra_n_s16 (int16x4_t a, int16x4_t b, const int n) + /// A32: VSRA.S16 Dd, Dm, #n + /// A64: SSRA Vd.4H, Vn.4H, #n /// - public static Vector128 MaxNumber(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vmaxnm_f64 (float64x1_t a, float64x1_t b) - /// A32: VMAXNM.F64 Dd, Dn, Dm - /// A64: FMAXNM Dd, Dn, Dm + /// int32x2_t vsra_n_s32 (int32x2_t a, int32x2_t b, const int n) + /// A32: VSRA.S32 Dd, Dm, #n + /// A64: SSRA Vd.2S, Vn.2S, #n /// - public static Vector64 MaxNumberScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32_t vmaxnms_f32 (float32_t a, float32_t b) - /// A32: VMAXNM.F32 Sd, Sn, Sm - /// A64: FMAXNM Sd, Sn, Sm + /// int8x8_t vsra_n_s8 (int8x8_t a, int8x8_t b, const int n) + /// A32: VSRA.S8 Dd, Dm, #n + /// A64: SSRA Vd.8B, Vn.8B, #n /// - public static Vector64 MaxNumberScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vpmax_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VPMAX.U8 Dd, Dn, Dm - /// A64: UMAXP Vd.8B, Vn.8B, Vm.8B + /// int16x8_t vsraq_n_s16 (int16x8_t a, int16x8_t b, const int n) + /// A32: VSRA.S16 Qd, Qm, #n + /// A64: SSRA Vd.8H, Vn.8H, #n /// - public static Vector64 MaxPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vpmax_s16 (int16x4_t a, int16x4_t b) - /// A32: VPMAX.S16 Dd, Dn, Dm - /// A64: SMAXP Vd.4H, Vn.4H, Vm.4H + /// int32x4_t vsraq_n_s32 (int32x4_t a, int32x4_t b, const int n) + /// A32: VSRA.S32 Qd, Qm, #n + /// A64: SSRA Vd.4S, Vn.4S, #n /// - public static Vector64 MaxPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vpmax_s32 (int32x2_t a, int32x2_t b) - /// A32: VPMAX.S32 Dd, Dn, Dm - /// A64: SMAXP Vd.2S, Vn.2S, Vm.2S + /// int64x2_t vsraq_n_s64 (int64x2_t a, int64x2_t b, const int n) + /// A32: VSRA.S64 Qd, Qm, #n + /// A64: SSRA Vd.2D, Vn.2D, #n /// - public static Vector64 MaxPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vpmax_s8 (int8x8_t a, int8x8_t b) - /// A32: VPMAX.S8 Dd, Dn, Dm - /// A64: SMAXP Vd.8B, Vn.8B, Vm.8B + /// int8x16_t vsraq_n_s8 (int8x16_t a, int8x16_t b, const int n) + /// A32: VSRA.S8 Qd, Qm, #n + /// A64: SSRA Vd.16B, Vn.16B, #n /// - public static Vector64 MaxPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vpmax_f32 (float32x2_t a, float32x2_t b) - /// A32: VPMAX.F32 Dd, Dn, Dm - /// A64: FMAXP Vd.2S, Vn.2S, Vm.2S + /// int64x1_t vsra_n_s64 (int64x1_t a, int64x1_t b, const int n) + /// A32: VSRA.S64 Dd, Dm, #n + /// A64: SSRA Dd, Dn, #n /// - public static Vector64 MaxPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticAddScalar(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vpmax_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VPMAX.U16 Dd, Dn, Dm - /// A64: UMAXP Vd.4H, Vn.4H, Vm.4H + /// int16x4_t vqshrn_n_s32 (int32x4_t a, const int n) + /// A32: VQSHRN.S32 Dd, Qm, #n + /// A64: SQSHRN Vd.4H, Vn.4S, #n /// - public static Vector64 MaxPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vpmax_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VPMAX.U32 Dd, Dn, Dm - /// A64: UMAXP Vd.2S, Vn.2S, Vm.2S + /// int32x2_t vqshrn_n_s64 (int64x2_t a, const int n) + /// A32: VQSHRN.S64 Dd, Qm, #n + /// A64: SQSHRN Vd.2S, Vn.2D, #n /// - public static Vector64 MaxPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vmin_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VMIN.U8 Dd, Dn, Dm - /// A64: UMIN Vd.8B, Vn.8B, Vm.8B + /// int8x8_t vqshrn_n_s16 (int16x8_t a, const int n) + /// A32: VQSHRN.S16 Dd, Qm, #n + /// A64: SQSHRN Vd.8B, Vn.8H, #n /// - public static Vector64 Min(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vmin_s16 (int16x4_t a, int16x4_t b) - /// A32: VMIN.S16 Dd, Dn, Dm - /// A64: SMIN Vd.4H, Vn.4H, Vm.4H + /// uint8x8_t vqshrun_n_s16 (int16x8_t a, const int n) + /// A32: VQSHRUN.S16 Dd, Qm, #n + /// A64: SQSHRUN Vd.8B, Vn.8H, #n /// - public static Vector64 Min(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticNarrowingSaturateUnsignedLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vmin_s32 (int32x2_t a, int32x2_t b) - /// A32: VMIN.S32 Dd, Dn, Dm - /// A64: SMIN Vd.2S, Vn.2S, Vm.2S + /// uint16x4_t vqshrun_n_s32 (int32x4_t a, const int n) + /// A32: VQSHRUN.S32 Dd, Qm, #n + /// A64: SQSHRUN Vd.4H, Vn.4S, #n /// - public static Vector64 Min(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticNarrowingSaturateUnsignedLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vmin_s8 (int8x8_t a, int8x8_t b) - /// A32: VMIN.S8 Dd, Dn, Dm - /// A64: SMIN Vd.8B, Vn.8B, Vm.8B + /// uint32x2_t vqshrun_n_s64 (int64x2_t a, const int n) + /// A32: VQSHRUN.S64 Dd, Qm, #n + /// A64: SQSHRUN Vd.2S, Vn.2D, #n /// - public static Vector64 Min(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticNarrowingSaturateUnsignedLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vmin_f32 (float32x2_t a, float32x2_t b) - /// A32: VMIN.F32 Dd, Dn, Dm - /// A64: FMIN Vd.2S, Vn.2S, Vm.2S + /// uint8x16_t vqshrun_high_n_s16 (uint8x8_t r, int16x8_t a, const int n) + /// A32: VQSHRUN.S16 Dd+1, Dn, #n + /// A64: SQSHRUN2 Vd.16B, Vn.8H, #n /// - public static Vector64 Min(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticNarrowingSaturateUnsignedUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vmin_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VMIN.U16 Dd, Dn, Dm - /// A64: UMIN Vd.4H, Vn.4H, Vm.4H + /// uint16x8_t vqshrun_high_n_s32 (uint16x4_t r, int32x4_t a, const int n) + /// A32: VQSHRUN.S32 Dd+1, Dn, #n + /// A64: SQSHRUN2 Vd.8H, Vn.4S, #n /// - public static Vector64 Min(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticNarrowingSaturateUnsignedUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vmin_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VMIN.U32 Dd, Dn, Dm - /// A64: UMIN Vd.2S, Vn.2S, Vm.2S + /// uint32x4_t vqshrun_high_n_s64 (uint32x2_t r, int64x2_t a, const int n) + /// A32: VQSHRUN.S64 Dd+1, Dn, #n + /// A64: SQSHRUN2 Vd.4S, Vn.2D, #n /// - public static Vector64 Min(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticNarrowingSaturateUnsignedUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vminq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VMIN.U8 Qd, Qn, Qm - /// A64: UMIN Vd.16B, Vn.16B, Vm.16B + /// int16x8_t vqshrn_high_n_s32 (int16x4_t r, int32x4_t a, const int n) + /// A32: VQSHRN.S32 Dd+1, Qm, #n + /// A64: SQSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector128 Min(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vminq_s16 (int16x8_t a, int16x8_t b) - /// A32: VMIN.S16 Qd, Qn, Qm - /// A64: SMIN Vd.8H, Vn.8H, Vm.8H + /// int32x4_t vqshrn_high_n_s64 (int32x2_t r, int64x2_t a, const int n) + /// A32: VQSHRN.S64 Dd+1, Qm, #n + /// A64: SQSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector128 Min(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vminq_s32 (int32x4_t a, int32x4_t b) - /// A32: VMIN.S32 Qd, Qn, Qm - /// A64: SMIN Vd.4S, Vn.4S, Vm.4S + /// int8x16_t vqshrn_high_n_s16 (int8x8_t r, int16x8_t a, const int n) + /// A32: VQSHRN.S16 Dd+1, Qm, #n + /// A64: SQSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector128 Min(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vminq_s8 (int8x16_t a, int8x16_t b) - /// A32: VMIN.S8 Qd, Qn, Qm - /// A64: SMIN Vd.16B, Vn.16B, Vm.16B + /// int16x4_t vrshr_n_s16 (int16x4_t a, const int n) + /// A32: VRSHR.S16 Dd, Dm, #n + /// A64: SRSHR Vd.4H, Vn.4H, #n /// - public static Vector128 Min(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticRounded(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vminq_f32 (float32x4_t a, float32x4_t b) - /// A32: VMIN.F32 Qd, Qn, Qm - /// A64: FMIN Vd.4S, Vn.4S, Vm.4S + /// int32x2_t vrshr_n_s32 (int32x2_t a, const int n) + /// A32: VRSHR.S32 Dd, Dm, #n + /// A64: SRSHR Vd.2S, Vn.2S, #n /// - public static Vector128 Min(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticRounded(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vminq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VMIN.U16 Qd, Qn, Qm - /// A64: UMIN Vd.8H, Vn.8H, Vm.8H + /// int8x8_t vrshr_n_s8 (int8x8_t a, const int n) + /// A32: VRSHR.S8 Dd, Dm, #n + /// A64: SRSHR Vd.8B, Vn.8B, #n /// - public static Vector128 Min(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticRounded(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vminq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VMIN.U32 Qd, Qn, Qm - /// A64: UMIN Vd.4S, Vn.4S, Vm.4S + /// int16x8_t vrshrq_n_s16 (int16x8_t a, const int n) + /// A32: VRSHR.S16 Qd, Qm, #n + /// A64: SRSHR Vd.8H, Vn.8H, #n /// - public static Vector128 Min(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticRounded(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vminnm_f32 (float32x2_t a, float32x2_t b) - /// A32: VMINNM.F32 Dd, Dn, Dm - /// A64: FMINNM Vd.2S, Vn.2S, Vm.2S + /// int32x4_t vrshrq_n_s32 (int32x4_t a, const int n) + /// A32: VRSHR.S32 Qd, Qm, #n + /// A64: SRSHR Vd.4S, Vn.4S, #n /// - public static Vector64 MinNumber(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticRounded(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vminnmq_f32 (float32x4_t a, float32x4_t b) - /// A32: VMINNM.F32 Qd, Qn, Qm - /// A64: FMINNM Vd.4S, Vn.4S, Vm.4S + /// int64x2_t vrshrq_n_s64 (int64x2_t a, const int n) + /// A32: VRSHR.S64 Qd, Qm, #n + /// A64: SRSHR Vd.2D, Vn.2D, #n /// - public static Vector128 MinNumber(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticRounded(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vminnm_f64 (float64x1_t a, float64x1_t b) - /// A32: VMINNM.F64 Dd, Dn, Dm - /// A64: FMINNM Dd, Dn, Dm + /// int8x16_t vrshrq_n_s8 (int8x16_t a, const int n) + /// A32: VRSHR.S8 Qd, Qm, #n + /// A64: SRSHR Vd.16B, Vn.16B, #n /// - public static Vector64 MinNumberScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticRounded(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32_t vminnms_f32 (float32_t a, float32_t b) - /// A32: VMINNM.F32 Sd, Sn, Sm - /// A64: FMINNM Sd, Sn, Sm + /// int16x4_t vrsra_n_s16 (int16x4_t a, int16x4_t b, const int n) + /// A32: VRSRA.S16 Dd, Dm, #n + /// A64: SRSRA Vd.4H, Vn.4H, #n /// - public static Vector64 MinNumberScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticRoundedAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vpmin_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VPMIN.U8 Dd, Dn, Dm - /// A64: UMINP Vd.8B, Vn.8B, Vm.8B + /// int32x2_t vrsra_n_s32 (int32x2_t a, int32x2_t b, const int n) + /// A32: VRSRA.S32 Dd, Dm, #n + /// A64: SRSRA Vd.2S, Vn.2S, #n /// - public static Vector64 MinPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticRoundedAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vpmin_s16 (int16x4_t a, int16x4_t b) - /// A32: VPMIN.S16 Dd, Dn, Dm - /// A64: SMINP Vd.4H, Vn.4H, Vm.4H + /// int8x8_t vrsra_n_s8 (int8x8_t a, int8x8_t b, const int n) + /// A32: VRSRA.S8 Dd, Dm, #n + /// A64: SRSRA Vd.8B, Vn.8B, #n /// - public static Vector64 MinPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticRoundedAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vpmin_s32 (int32x2_t a, int32x2_t b) - /// A32: VPMIN.S32 Dd, Dn, Dm - /// A64: SMINP Vd.2S, Vn.2S, Vm.2S + /// int16x8_t vrsraq_n_s16 (int16x8_t a, int16x8_t b, const int n) + /// A32: VRSRA.S16 Qd, Qm, #n + /// A64: SRSRA Vd.8H, Vn.8H, #n /// - public static Vector64 MinPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticRoundedAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vpmin_s8 (int8x8_t a, int8x8_t b) - /// A32: VPMIN.S8 Dd, Dn, Dm - /// A64: SMINP Vd.8B, Vn.8B, Vm.8B + /// int32x4_t vrsraq_n_s32 (int32x4_t a, int32x4_t b, const int n) + /// A32: VRSRA.S32 Qd, Qm, #n + /// A64: SRSRA Vd.4S, Vn.4S, #n /// - public static Vector64 MinPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticRoundedAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vpmin_f32 (float32x2_t a, float32x2_t b) - /// A32: VPMIN.F32 Dd, Dn, Dm - /// A64: FMINP Vd.2S, Vn.2S, Vm.2S + /// int64x2_t vrsraq_n_s64 (int64x2_t a, int64x2_t b, const int n) + /// A32: VRSRA.S64 Qd, Qm, #n + /// A64: SRSRA Vd.2D, Vn.2D, #n /// - public static Vector64 MinPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticRoundedAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vpmin_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VPMIN.U16 Dd, Dn, Dm - /// A64: UMINP Vd.4H, Vn.4H, Vm.4H + /// int8x16_t vrsraq_n_s8 (int8x16_t a, int8x16_t b, const int n) + /// A32: VRSRA.S8 Qd, Qm, #n + /// A64: SRSRA Vd.16B, Vn.16B, #n /// - public static Vector64 MinPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticRoundedAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vpmin_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VPMIN.U32 Dd, Dn, Dm - /// A64: UMINP Vd.2S, Vn.2S, Vm.2S + /// int64x1_t vrsra_n_s64 (int64x1_t a, int64x1_t b, const int n) + /// A32: VRSRA.S64 Dd, Dm, #n + /// A64: SRSRA Dd, Dn, #n /// - public static Vector64 MinPairwise(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticRoundedAddScalar(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vmul_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VMUL.I8 Dd, Dn, Dm - /// A64: MUL Vd.8B, Vn.8B, Vm.8B + /// int16x4_t vqrshrn_n_s32 (int32x4_t a, const int n) + /// A32: VQRSHRN.S32 Dd, Qm, #n + /// A64: SQRSHRN Vd.4H, Vn.4S, #n /// - public static Vector64 Multiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vmul_s16 (int16x4_t a, int16x4_t b) - /// A32: VMUL.I16 Dd, Dn, Dm - /// A64: MUL Vd.4H, Vn.4H, Vm.4H + /// int32x2_t vqrshrn_n_s64 (int64x2_t a, const int n) + /// A32: VQRSHRN.S64 Dd, Qm, #n + /// A64: SQRSHRN Vd.2S, Vn.2D, #n /// - public static Vector64 Multiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vmul_s32 (int32x2_t a, int32x2_t b) - /// A32: VMUL.I32 Dd, Dn, Dm - /// A64: MUL Vd.2S, Vn.2S, Vm.2S + /// int8x8_t vqrshrn_n_s16 (int16x8_t a, const int n) + /// A32: VQRSHRN.S16 Dd, Qm, #n + /// A64: SQRSHRN Vd.8B, Vn.8H, #n + /// + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vqrshrun_n_s16 (int16x8_t a, const int n) + /// A32: VQRSHRUN.S16 Dd, Qm, #n + /// A64: SQRSHRUN Vd.8B, Vn.8H, #n /// - public static Vector64 Multiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vmul_s8 (int8x8_t a, int8x8_t b) - /// A32: VMUL.I8 Dd, Dn, Dm - /// A64: MUL Vd.8B, Vn.8B, Vm.8B + /// uint16x4_t vqrshrun_n_s32 (int32x4_t a, const int n) + /// A32: VQRSHRUN.S32 Dd, Qm, #n + /// A64: SQRSHRUN Vd.4H, Vn.4S, #n /// - public static Vector64 Multiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vmul_f32 (float32x2_t a, float32x2_t b) - /// A32: VMUL.F32 Dd, Dn, Dm - /// A64: FMUL Vd.2S, Vn.2S, Vm.2S + /// uint32x2_t vqrshrun_n_s64 (int64x2_t a, const int n) + /// A32: VQRSHRUN.S64 Dd, Qm, #n + /// A64: SQRSHRUN Vd.2S, Vn.2D, #n /// - public static Vector64 Multiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vmul_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VMUL.I16 Dd, Dn, Dm - /// A64: MUL Vd.4H, Vn.4H, Vm.4H + /// uint8x16_t vqrshrun_high_n_s16 (uint8x8_t r, int16x8_t a, const int n) + /// A32: VQRSHRUN.S16 Dd+1, Dn, #n + /// A64: SQRSHRUN2 Vd.16B, Vn.8H, #n /// - public static Vector64 Multiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vmul_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VMUL.I32 Dd, Dn, Dm - /// A64: MUL Vd.2S, Vn.2S, Vm.2S + /// uint16x8_t vqrshrun_high_n_s32 (uint16x4_t r, int32x4_t a, const int n) + /// A32: VQRSHRUN.S32 Dd+1, Dn, #n + /// A64: SQRSHRUN2 Vd.8H, Vn.4S, #n /// - public static Vector64 Multiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vmulq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VMUL.I8 Qd, Qn, Qm - /// A64: MUL Vd.16B, Vn.16B, Vm.16B + /// uint32x4_t vqrshrun_high_n_s64 (uint32x2_t r, int64x2_t a, const int n) + /// A32: VQRSHRUN.S64 Dd+1, Dn, #n + /// A64: SQRSHRUN2 Vd.4S, Vn.2D, #n /// - public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vmulq_s16 (int16x8_t a, int16x8_t b) - /// A32: VMUL.I16 Qd, Qn, Qm - /// A64: MUL Vd.8H, Vn.8H, Vm.8H + /// int16x8_t vqrshrn_high_n_s32 (int16x4_t r, int32x4_t a, const int n) + /// A32: VQRSHRN.S32 Dd+1, Dn, #n + /// A64: SQRSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vmulq_s32 (int32x4_t a, int32x4_t b) - /// A32: VMUL.I32 Qd, Qn, Qm - /// A64: MUL Vd.4S, Vn.4S, Vm.4S + /// int32x4_t vqrshrn_high_n_s64 (int32x2_t r, int64x2_t a, const int n) + /// A32: VQRSHRN.S64 Dd+1, Dn, #n + /// A64: SQRSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vmulq_s8 (int8x16_t a, int8x16_t b) - /// A32: VMUL.I8 Qd, Qn, Qm - /// A64: MUL Vd.16B, Vn.16B, Vm.16B + /// int8x16_t vqrshrn_high_n_s16 (int8x8_t r, int16x8_t a, const int n) + /// A32: VQRSHRN.S16 Dd+1, Dn, #n + /// A64: SQRSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightArithmeticRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vmulq_f32 (float32x4_t a, float32x4_t b) - /// A32: VMUL.F32 Qd, Qn, Qm - /// A64: FMUL Vd.4S, Vn.4S, Vm.4S + /// int64x1_t vrshr_n_s64 (int64x1_t a, const int n) + /// A32: VRSHR.S64 Dd, Dm, #n + /// A64: SRSHR Dd, Dn, #n /// - public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticRoundedScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vmulq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VMUL.I16 Qd, Qn, Qm - /// A64: MUL Vd.8H, Vn.8H, Vm.8H + /// int64x1_t vshr_n_s64 (int64x1_t a, const int n) + /// A32: VSHR.S64 Dd, Dm, #n + /// A64: SSHR Dd, Dn, #n /// - public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightArithmeticScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vmulq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VMUL.I32 Qd, Qn, Qm - /// A64: MUL Vd.4S, Vn.4S, Vm.4S + /// uint8x8_t vshr_n_u8 (uint8x8_t a, const int n) + /// A32: VSHR.U8 Dd, Dm, #n + /// A64: USHR Vd.8B, Vn.8B, #n /// - public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogical(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vmul_f64 (float64x1_t a, float64x1_t b) - /// A32: VMUL.F64 Dd, Dn, Dm - /// A64: FMUL Dd, Dn, Dm + /// uint16x4_t vshr_n_u16 (uint16x4_t a, const int n) + /// A32: VSHR.U16 Dd, Dm, #n + /// A64: USHR Vd.4H, Vn.4H, #n /// - public static Vector64 MultiplyScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogical(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32_t vmuls_f32 (float32_t a, float32_t b) - /// A32: VMUL.F32 Sd, Sn, Sm - /// A64: FMUL Sd, Sn, Sm - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint32x2_t vshr_n_u32 (uint32x2_t a, const int n) + /// A32: VSHR.U32 Dd, Dm, #n + /// A64: USHR Vd.2S, Vn.2S, #n /// - public static Vector64 MultiplyScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogical(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vmla_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) - /// A32: VMLA.I8 Dd, Dn, Dm - /// A64: MLA Vd.8B, Vn.8B, Vm.8B + /// uint8x8_t vshr_n_u8 (uint8x8_t a, const int n) + /// A32: VSHR.U8 Dd, Dm, #n + /// A64: USHR Vd.8B, Vn.8B, #n /// - public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogical(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vmla_s16 (int16x4_t a, int16x4_t b, int16x4_t c) - /// A32: VMLA.I16 Dd, Dn, Dm - /// A64: MLA Vd.4H, Vn.4H, Vm.4H + /// uint16x4_t vshr_n_u16 (uint16x4_t a, const int n) + /// A32: VSHR.U16 Dd, Dm, #n + /// A64: USHR Vd.4H, Vn.4H, #n /// - public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogical(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vmla_s32 (int32x2_t a, int32x2_t b, int32x2_t c) - /// A32: VMLA.I32 Dd, Dn, Dm - /// A64: MLA Vd.2S, Vn.2S, Vm.2S + /// uint32x2_t vshr_n_u32 (uint32x2_t a, const int n) + /// A32: VSHR.U32 Dd, Dm, #n + /// A64: USHR Vd.2S, Vn.2S, #n /// - public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogical(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vmla_s8 (int8x8_t a, int8x8_t b, int8x8_t c) - /// A32: VMLA.I8 Dd, Dn, Dm - /// A64: MLA Vd.8B, Vn.8B, Vm.8B + /// uint8x16_t vshrq_n_u8 (uint8x16_t a, const int n) + /// A32: VSHR.U8 Qd, Qm, #n + /// A64: USHR Vd.16B, Vn.16B, #n /// - public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vmla_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) - /// A32: VMLA.I16 Dd, Dn, Dm - /// A64: MLA Vd.4H, Vn.4H, Vm.4H + /// uint16x8_t vshrq_n_u16 (uint16x8_t a, const int n) + /// A32: VSHR.U16 Qd, Qm, #n + /// A64: USHR Vd.8H, Vn.8H, #n /// - public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vmla_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) - /// A32: VMLA.I32 Dd, Dn, Dm - /// A64: MLA Vd.2S, Vn.2S, Vm.2S + /// uint32x4_t vshrq_n_u32 (uint32x4_t a, const int n) + /// A32: VSHR.U32 Qd, Qm, #n + /// A64: USHR Vd.4S, Vn.4S, #n /// - public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vmlaq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) - /// A32: VMLA.I8 Qd, Qn, Qm - /// A64: MLA Vd.16B, Vn.16B, Vm.16B + /// uint64x2_t vshrq_n_u64 (uint64x2_t a, const int n) + /// A32: VSHR.U64 Qd, Qm, #n + /// A64: USHR Vd.2D, Vn.2D, #n /// - public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vmlaq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) - /// A32: VMLA.I16 Qd, Qn, Qm - /// A64: MLA Vd.8H, Vn.8H, Vm.8H + /// uint8x16_t vshrq_n_u8 (uint8x16_t a, const int n) + /// A32: VSHR.U8 Qd, Qm, #n + /// A64: USHR Vd.16B, Vn.16B, #n /// - public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vmlaq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) - /// A32: VMLA.I32 Qd, Qn, Qm - /// A64: MLA Vd.4S, Vn.4S, Vm.4S + /// uint16x8_t vshrq_n_u16 (uint16x8_t a, const int n) + /// A32: VSHR.U16 Qd, Qm, #n + /// A64: USHR Vd.8H, Vn.8H, #n /// - public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vmlaq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) - /// A32: VMLA.I8 Qd, Qn, Qm - /// A64: MLA Vd.16B, Vn.16B, Vm.16B + /// uint32x4_t vshrq_n_u32 (uint32x4_t a, const int n) + /// A32: VSHR.U32 Qd, Qm, #n + /// A64: USHR Vd.4S, Vn.4S, #n /// - public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vmlaq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) - /// A32: VMLA.I16 Qd, Qn, Qm - /// A64: MLA Vd.8H, Vn.8H, Vm.8H + /// uint64x2_t vshrq_n_u64 (uint64x2_t a, const int n) + /// A32: VSHR.U64 Qd, Qm, #n + /// A64: USHR Vd.2D, Vn.2D, #n /// - public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogical(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vmlaq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) - /// A32: VMLA.I32 Qd, Qn, Qm - /// A64: MLA Vd.4S, Vn.4S, Vm.4S + /// uint8x8_t vsra_n_u8 (uint8x8_t a, uint8x8_t b, const int n) + /// A32: VSRA.U8 Dd, Dm, #n + /// A64: USRA Vd.8B, Vn.8B, #n /// - public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vmls_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) - /// A32: VMLS.I8 Dd, Dn, Dm - /// A64: MLS Vd.8B, Vn.8B, Vm.8B + /// uint16x4_t vsra_n_u16 (uint16x4_t a, uint16x4_t b, const int n) + /// A32: VSRA.U16 Dd, Dm, #n + /// A64: USRA Vd.4H, Vn.4H, #n /// - public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vmls_s16 (int16x4_t a, int16x4_t b, int16x4_t c) - /// A32: VMLS.I16 Dd, Dn, Dm - /// A64: MLS Vd.4H, Vn.4H, Vm.4H + /// uint32x2_t vsra_n_u32 (uint32x2_t a, uint32x2_t b, const int n) + /// A32: VSRA.U32 Dd, Dm, #n + /// A64: USRA Vd.2S, Vn.2S, #n /// - public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vmls_s32 (int32x2_t a, int32x2_t b, int32x2_t c) - /// A32: VMLS.I32 Dd, Dn, Dm - /// A64: MLS Vd.2S, Vn.2S, Vm.2S + /// uint8x8_t vsra_n_u8 (uint8x8_t a, uint8x8_t b, const int n) + /// A32: VSRA.U8 Dd, Dm, #n + /// A64: USRA Vd.8B, Vn.8B, #n /// - public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vmls_s8 (int8x8_t a, int8x8_t b, int8x8_t c) - /// A32: VMLS.I8 Dd, Dn, Dm - /// A64: MLS Vd.8B, Vn.8B, Vm.8B + /// uint16x4_t vsra_n_u16 (uint16x4_t a, uint16x4_t b, const int n) + /// A32: VSRA.U16 Dd, Dm, #n + /// A64: USRA Vd.4H, Vn.4H, #n /// - public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vmls_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) - /// A32: VMLS.I16 Dd, Dn, Dm - /// A64: MLS Vd.4H, Vn.4H, Vm.4H + /// uint32x2_t vsra_n_u32 (uint32x2_t a, uint32x2_t b, const int n) + /// A32: VSRA.U32 Dd, Dm, #n + /// A64: USRA Vd.2S, Vn.2S, #n /// - public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vmls_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) - /// A32: VMLS.I32 Dd, Dn, Dm - /// A64: MLS Vd.2S, Vn.2S, Vm.2S + /// uint8x16_t vsraq_n_u8 (uint8x16_t a, uint8x16_t b, const int n) + /// A32: VSRA.U8 Qd, Qm, #n + /// A64: USRA Vd.16B, Vn.16B, #n /// - public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vmlsq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) - /// A32: VMLS.I8 Qd, Qn, Qm - /// A64: MLS Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vsraq_n_u16 (uint16x8_t a, uint16x8_t b, const int n) + /// A32: VSRA.U16 Qd, Qm, #n + /// A64: USRA Vd.8H, Vn.8H, #n /// - public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vmlsq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) - /// A32: VMLS.I16 Qd, Qn, Qm - /// A64: MLS Vd.8H, Vn.8H, Vm.8H + /// uint32x4_t vsraq_n_u32 (uint32x4_t a, uint32x4_t b, const int n) + /// A32: VSRA.U32 Qd, Qm, #n + /// A64: USRA Vd.4S, Vn.4S, #n /// - public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vmlsq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) - /// A32: VMLS.I32 Qd, Qn, Qm - /// A64: MLS Vd.4S, Vn.4S, Vm.4S + /// uint64x2_t vsraq_n_u64 (uint64x2_t a, uint64x2_t b, const int n) + /// A32: VSRA.U64 Qd, Qm, #n + /// A64: USRA Vd.2D, Vn.2D, #n /// - public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vmlsq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) - /// A32: VMLS.I8 Qd, Qn, Qm - /// A64: MLS Vd.16B, Vn.16B, Vm.16B + /// uint8x16_t vsraq_n_u8 (uint8x16_t a, uint8x16_t b, const int n) + /// A32: VSRA.U8 Qd, Qm, #n + /// A64: USRA Vd.16B, Vn.16B, #n /// - public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vmlsq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) - /// A32: VMLS.I16 Qd, Qn, Qm - /// A64: MLS Vd.8H, Vn.8H, Vm.8H + /// uint16x8_t vsraq_n_u16 (uint16x8_t a, uint16x8_t b, const int n) + /// A32: VSRA.U16 Qd, Qm, #n + /// A64: USRA Vd.8H, Vn.8H, #n /// - public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vmlsq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) - /// A32: VMLS.I32 Qd, Qn, Qm - /// A64: MLS Vd.4S, Vn.4S, Vm.4S + /// uint32x4_t vsraq_n_u32 (uint32x4_t a, uint32x4_t b, const int n) + /// A32: VSRA.U32 Qd, Qm, #n + /// A64: USRA Vd.4S, Vn.4S, #n /// - public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vneg_s16 (int16x4_t a) - /// A32: VNEG.S16 Dd, Dm - /// A64: NEG Vd.4H, Vn.4H + /// uint64x2_t vsraq_n_u64 (uint64x2_t a, uint64x2_t b, const int n) + /// A32: VSRA.U64 Qd, Qm, #n + /// A64: USRA Vd.2D, Vn.2D, #n /// - public static Vector64 Negate(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vneg_s32 (int32x2_t a) - /// A32: VNEG.S32 Dd, Dm - /// A64: NEG Vd.2S, Vn.2S + /// uint64x1_t vsra_n_u64 (uint64x1_t a, uint64x1_t b, const int n) + /// A32: VSRA.U64 Dd, Dm, #n + /// A64: USRA Dd, Dn, #n /// - public static Vector64 Negate(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalAddScalar(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vneg_s8 (int8x8_t a) - /// A32: VNEG.S8 Dd, Dm - /// A64: NEG Vd.8B, Vn.8B + /// uint64x1_t vsra_n_u64 (uint64x1_t a, uint64x1_t b, const int n) + /// A32: VSRA.U64 Dd, Dm, #n + /// A64: USRA Dd, Dn, #n /// - public static Vector64 Negate(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalAddScalar(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vneg_f32 (float32x2_t a) - /// A32: VNEG.F32 Dd, Dm - /// A64: FNEG Vd.2S, Vn.2S + /// uint8x8_t vshrn_n_u16 (uint16x8_t a, const int n) + /// A32: VSHRN.I16 Dd, Qm, #n + /// A64: SHRN Vd.8B, Vn.8H, #n /// - public static Vector64 Negate(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalNarrowingLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vnegq_s16 (int16x8_t a) - /// A32: VNEG.S16 Qd, Qm - /// A64: NEG Vd.8H, Vn.8H + /// int16x4_t vshrn_n_s32 (int32x4_t a, const int n) + /// A32: VSHRN.I32 Dd, Qm, #n + /// A64: SHRN Vd.4H, Vn.4S, #n /// - public static Vector128 Negate(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalNarrowingLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vnegq_s32 (int32x4_t a) - /// A32: VNEG.S32 Qd, Qm - /// A64: NEG Vd.4S, Vn.4S + /// int32x2_t vshrn_n_s64 (int64x2_t a, const int n) + /// A32: VSHRN.I64 Dd, Qm, #n + /// A64: SHRN Vd.2S, Vn.2D, #n /// - public static Vector128 Negate(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalNarrowingLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vnegq_s8 (int8x16_t a) - /// A32: VNEG.S8 Qd, Qm - /// A64: NEG Vd.16B, Vn.16B + /// int8x8_t vshrn_n_s16 (int16x8_t a, const int n) + /// A32: VSHRN.I16 Dd, Qm, #n + /// A64: SHRN Vd.8B, Vn.8H, #n /// - public static Vector128 Negate(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalNarrowingLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vnegq_f32 (float32x4_t a) - /// A32: VNEG.F32 Qd, Qm - /// A64: FNEG Vd.4S, Vn.4S + /// uint16x4_t vshrn_n_u32 (uint32x4_t a, const int n) + /// A32: VSHRN.I32 Dd, Qm, #n + /// A64: SHRN Vd.4H, Vn.4S, #n /// - public static Vector128 Negate(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalNarrowingLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vneg_f64 (float64x1_t a) - /// A32: VNEG.F64 Dd, Dm - /// A64: FNEG Dd, Dn + /// uint32x2_t vshrn_n_u64 (uint64x2_t a, const int n) + /// A32: VSHRN.I64 Dd, Qm, #n + /// A64: SHRN Vd.2S, Vn.2D, #n /// - public static Vector64 NegateScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalNarrowingLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32_t vnegs_f32 (float32_t a) - /// A32: VNEG.F32 Sd, Sm - /// A64: FNEG Sd, Sn - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x8_t vqshrn_n_u16 (uint16x8_t a, const int n) + /// A32: VQSHRN.U16 Dd, Qm, #n + /// A64: UQSHRN Vd.8B, Vn.8H, #n /// - public static Vector64 NegateScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vmvn_u8 (uint8x8_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint16x4_t vqshrn_n_u32 (uint32x4_t a, const int n) + /// A32: VQSHRN.U32 Dd, Qm, #n + /// A64: UQSHRN Vd.4H, Vn.4S, #n /// - public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vmvn_f64 (float64x1_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint32x2_t vqshrn_n_u64 (uint64x2_t a, const int n) + /// A32: VQSHRN.U64 Dd, Qm, #n + /// A64: UQSHRN Vd.2S, Vn.2D, #n /// - public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vmvn_s16 (int16x4_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint8x8_t vqshrn_n_u16 (uint16x8_t a, const int n) + /// A32: VQSHRN.U16 Dd, Qm, #n + /// A64: UQSHRN Vd.8B, Vn.8H, #n /// - public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vmvn_s32 (int32x2_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint16x4_t vqshrn_n_u32 (uint32x4_t a, const int n) + /// A32: VQSHRN.U32 Dd, Qm, #n + /// A64: UQSHRN Vd.4H, Vn.4S, #n /// - public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int64x1_t vmvn_s64 (int64x1_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint32x2_t vqshrn_n_u64 (uint64x2_t a, const int n) + /// A32: VQSHRN.U64 Dd, Qm, #n + /// A64: UQSHRN Vd.2S, Vn.2D, #n /// - public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vmvn_s8 (int8x8_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint8x16_t vqshrn_high_n_u16 (uint8x8_t r, uint16x8_t a, const int n) + /// A32: VQSHRN.U16 Dd+1, Qm, #n + /// A64: UQSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vmvn_f32 (float32x2_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x8_t vqshrn_high_n_u32 (uint16x4_t r, uint32x4_t a, const int n) + /// A32: VQSHRN.U32 Dd+1, Qm, #n + /// A64: UQSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vmvn_u16 (uint16x4_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint32x4_t vqshrn_high_n_u64 (uint32x2_t r, uint64x2_t a, const int n) + /// A32: VQSHRN.U64 Dd+1, Qm, #n + /// A64: UQSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vmvn_u32 (uint32x2_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint8x16_t vqshrn_high_n_u16 (uint8x8_t r, uint16x8_t a, const int n) + /// A32: VQSHRN.U16 Dd+1, Qm, #n + /// A64: UQSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint64x1_t vmvn_u64 (uint64x1_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint16x8_t vqshrn_high_n_u32 (uint16x4_t r, uint32x4_t a, const int n) + /// A32: VQSHRN.U32 Dd+1, Qm, #n + /// A64: UQSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector64 Not(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vmvnq_u8 (uint8x16_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// uint32x4_t vqshrn_high_n_u64 (uint32x2_t r, uint64x2_t a, const int n) + /// A32: VQSHRN.U64 Dd+1, Qm, #n + /// A64: UQSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float64x2_t vmvnq_f64 (float64x2_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x16_t vshrn_high_n_u16 (uint8x8_t r, uint16x8_t a, const int n) + /// A32: VSHRN.I16 Dd+1, Qm, #n + /// A64: SHRN2 Vd.16B, Vn.8H, #n /// - public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalNarrowingUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vmvnq_s16 (int16x8_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// int16x8_t vshrn_high_n_s32 (int16x4_t r, int32x4_t a, const int n) + /// A32: VSHRN.I32 Dd+1, Qm, #n + /// A64: SHRN2 Vd.8H, Vn.4S, #n /// - public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalNarrowingUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vmvnq_s32 (int32x4_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// int32x4_t vshrn_high_n_s64 (int32x2_t r, int64x2_t a, const int n) + /// A32: VSHRN.I64 Dd+1, Qm, #n + /// A64: SHRN2 Vd.4S, Vn.2D, #n /// - public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalNarrowingUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int64x2_t vmvnq_s64 (int64x2_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// int8x16_t vshrn_high_n_s16 (int8x8_t r, int16x8_t a, const int n) + /// A32: VSHRN.I16 Dd+1, Qm, #n + /// A64: SHRN2 Vd.16B, Vn.8H, #n + /// + public static Vector128 ShiftRightLogicalNarrowingUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vshrn_high_n_u32 (uint16x4_t r, uint32x4_t a, const int n) + /// A32: VSHRN.I32 Dd+1, Qm, #n + /// A64: SHRN2 Vd.8H, Vn.4S, #n /// - public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalNarrowingUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vmvnq_s8 (int8x16_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// uint32x4_t vshrn_high_n_u64 (uint32x2_t r, uint64x2_t a, const int n) + /// A32: VSHRN.I64 Dd+1, Qm, #n + /// A64: SHRN2 Vd.4S, Vn.2D, #n /// - public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalNarrowingUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vmvnq_f32 (float32x4_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x8_t vrshr_n_u8 (uint8x8_t a, const int n) + /// A32: VRSHR.U8 Dd, Dm, #n + /// A64: URSHR Vd.8B, Vn.8B, #n /// - public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRounded(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vmvnq_u16 (uint16x8_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// uint16x4_t vrshr_n_u16 (uint16x4_t a, const int n) + /// A32: VRSHR.U16 Dd, Dm, #n + /// A64: URSHR Vd.4H, Vn.4H, #n /// - public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRounded(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vmvnq_u32 (uint32x4_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// uint32x2_t vrshr_n_u32 (uint32x2_t a, const int n) + /// A32: VRSHR.U32 Dd, Dm, #n + /// A64: URSHR Vd.2S, Vn.2S, #n /// - public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRounded(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint64x2_t vmvnq_u64 (uint64x2_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// uint8x8_t vrshr_n_u8 (uint8x8_t a, const int n) + /// A32: VRSHR.U8 Dd, Dm, #n + /// A64: URSHR Vd.8B, Vn.8B, #n /// - public static Vector128 Not(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRounded(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vorr_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint16x4_t vrshr_n_u16 (uint16x4_t a, const int n) + /// A32: VRSHR.U16 Dd, Dm, #n + /// A64: URSHR Vd.4H, Vn.4H, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRounded(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vorr_f64 (float64x1_t a, float64x1_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint32x2_t vrshr_n_u32 (uint32x2_t a, const int n) + /// A32: VRSHR.U32 Dd, Dm, #n + /// A64: URSHR Vd.2S, Vn.2S, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRounded(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vorr_s16 (int16x4_t a, int16x4_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint8x16_t vrshrq_n_u8 (uint8x16_t a, const int n) + /// A32: VRSHR.U8 Qd, Qm, #n + /// A64: URSHR Vd.16B, Vn.16B, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vorr_s32 (int32x2_t a, int32x2_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint16x8_t vrshrq_n_u16 (uint16x8_t a, const int n) + /// A32: VRSHR.U16 Qd, Qm, #n + /// A64: URSHR Vd.8H, Vn.8H, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int64x1_t vorr_s64 (int64x1_t a, int64x1_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint32x4_t vrshrq_n_u32 (uint32x4_t a, const int n) + /// A32: VRSHR.U32 Qd, Qm, #n + /// A64: URSHR Vd.4S, Vn.4S, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vorr_s8 (int8x8_t a, int8x8_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint64x2_t vrshrq_n_u64 (uint64x2_t a, const int n) + /// A32: VRSHR.U64 Qd, Qm, #n + /// A64: URSHR Vd.2D, Vn.2D, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vorr_f32 (float32x2_t a, float32x2_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x16_t vrshrq_n_u8 (uint8x16_t a, const int n) + /// A32: VRSHR.U8 Qd, Qm, #n + /// A64: URSHR Vd.16B, Vn.16B, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vorr_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint16x8_t vrshrq_n_u16 (uint16x8_t a, const int n) + /// A32: VRSHR.U16 Qd, Qm, #n + /// A64: URSHR Vd.8H, Vn.8H, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vorr_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint32x4_t vrshrq_n_u32 (uint32x4_t a, const int n) + /// A32: VRSHR.U32 Qd, Qm, #n + /// A64: URSHR Vd.4S, Vn.4S, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint64x1_t vorr_u64 (uint64x1_t a, uint64x1_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint64x2_t vrshrq_n_u64 (uint64x2_t a, const int n) + /// A32: VRSHR.U64 Qd, Qm, #n + /// A64: URSHR Vd.2D, Vn.2D, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vorrq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint8x8_t vrsra_n_u8 (uint8x8_t a, uint8x8_t b, const int n) + /// A32: VRSRA.U8 Dd, Dm, #n + /// A64: URSRA Vd.8B, Vn.8B, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float64x2_t vorrq_f64 (float64x2_t a, float64x2_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x4_t vrsra_n_u16 (uint16x4_t a, uint16x4_t b, const int n) + /// A32: VRSRA.U16 Dd, Dm, #n + /// A64: URSRA Vd.4H, Vn.4H, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vorrq_s16 (int16x8_t a, int16x8_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint32x2_t vrsra_n_u32 (uint32x2_t a, uint32x2_t b, const int n) + /// A32: VRSRA.U32 Dd, Dm, #n + /// A64: URSRA Vd.2S, Vn.2S, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vorrq_s32 (int32x4_t a, int32x4_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint8x8_t vrsra_n_u8 (uint8x8_t a, uint8x8_t b, const int n) + /// A32: VRSRA.U8 Dd, Dm, #n + /// A64: URSRA Vd.8B, Vn.8B, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int64x2_t vorrq_s64 (int64x2_t a, int64x2_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint16x4_t vrsra_n_u16 (uint16x4_t a, uint16x4_t b, const int n) + /// A32: VRSRA.U16 Dd, Dm, #n + /// A64: URSRA Vd.4H, Vn.4H, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vorrq_s8 (int8x16_t a, int8x16_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint32x2_t vrsra_n_u32 (uint32x2_t a, uint32x2_t b, const int n) + /// A32: VRSRA.U32 Dd, Dm, #n + /// A64: URSRA Vd.2S, Vn.2S, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedAdd(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vorrq_f32 (float32x4_t a, float32x4_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x16_t vrsraq_n_u8 (uint8x16_t a, uint8x16_t b, const int n) + /// A32: VRSRA.U8 Qd, Qm, #n + /// A64: URSRA Vd.16B, Vn.16B, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vorrq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vrsraq_n_u16 (uint16x8_t a, uint16x8_t b, const int n) + /// A32: VRSRA.U16 Qd, Qm, #n + /// A64: URSRA Vd.8H, Vn.8H, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vorrq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint32x4_t vrsraq_n_u32 (uint32x4_t a, uint32x4_t b, const int n) + /// A32: VRSRA.U32 Qd, Qm, #n + /// A64: URSRA Vd.4S, Vn.4S, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint64x2_t vorrq_u64 (uint64x2_t a, uint64x2_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint64x2_t vrsraq_n_u64 (uint64x2_t a, uint64x2_t b, const int n) + /// A32: VRSRA.U64 Qd, Qm, #n + /// A64: URSRA Vd.2D, Vn.2D, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vorn_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// uint8x16_t vrsraq_n_u8 (uint8x16_t a, uint8x16_t b, const int n) + /// A32: VRSRA.U8 Qd, Qm, #n + /// A64: URSRA Vd.16B, Vn.16B, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float64x1_t vorn_f64 (float64x1_t a, float64x1_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x8_t vrsraq_n_u16 (uint16x8_t a, uint16x8_t b, const int n) + /// A32: VRSRA.U16 Qd, Qm, #n + /// A64: URSRA Vd.8H, Vn.8H, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x4_t vorn_s16 (int16x4_t a, int16x4_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// uint32x4_t vrsraq_n_u32 (uint32x4_t a, uint32x4_t b, const int n) + /// A32: VRSRA.U32 Qd, Qm, #n + /// A64: URSRA Vd.4S, Vn.4S, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x2_t vorn_s32 (int32x2_t a, int32x2_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// uint64x2_t vrsraq_n_u64 (uint64x2_t a, uint64x2_t b, const int n) + /// A32: VRSRA.U64 Qd, Qm, #n + /// A64: URSRA Vd.2D, Vn.2D, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int64x1_t vorn_s64 (int64x1_t a, int64x1_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// uint64x1_t vrsra_n_u64 (uint64x1_t a, uint64x1_t b, const int n) + /// A32: VRSRA.U64 Dd, Dm, #n + /// A64: URSRA Dd, Dn, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedAddScalar(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vorn_s8 (int8x8_t a, int8x8_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// uint64x1_t vrsra_n_u64 (uint64x1_t a, uint64x1_t b, const int n) + /// A32: VRSRA.U64 Dd, Dm, #n + /// A64: URSRA Dd, Dn, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedAddScalar(Vector64 addend, Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vorn_f32 (float32x2_t a, float32x2_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x8_t vrshrn_n_u16 (uint16x8_t a, const int n) + /// A32: VRSHRN.I16 Dd, Qm, #n + /// A64: RSHRN Vd.8B, Vn.8H, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedNarrowingLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x4_t vorn_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// int16x4_t vrshrn_n_s32 (int32x4_t a, const int n) + /// A32: VRSHRN.I32 Dd, Qm, #n + /// A64: RSHRN Vd.4H, Vn.4S, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedNarrowingLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vorn_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// int32x2_t vrshrn_n_s64 (int64x2_t a, const int n) + /// A32: VRSHRN.I64 Dd, Qm, #n + /// A64: RSHRN Vd.2S, Vn.2D, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedNarrowingLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint64x1_t vorn_u64 (uint64x1_t a, uint64x1_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// int8x8_t vrshrn_n_s16 (int16x8_t a, const int n) + /// A32: VRSHRN.I16 Dd, Qm, #n + /// A64: RSHRN Vd.8B, Vn.8H, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedNarrowingLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vornq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint16x4_t vrshrn_n_u32 (uint32x4_t a, const int n) + /// A32: VRSHRN.I32 Dd, Qm, #n + /// A64: RSHRN Vd.4H, Vn.4S, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedNarrowingLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float64x2_t vornq_f64 (float64x2_t a, float64x2_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint32x2_t vrshrn_n_u64 (uint64x2_t a, const int n) + /// A32: VRSHRN.I64 Dd, Qm, #n + /// A64: RSHRN Vd.2S, Vn.2D, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedNarrowingLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int16x8_t vornq_s16 (int16x8_t a, int16x8_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint8x8_t vqrshrn_n_u16 (uint16x8_t a, const int n) + /// A32: VQRSHRN.U16 Dd, Qm, #n + /// A64: UQRSHRN Vd.8B, Vn.8H, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int32x4_t vornq_s32 (int32x4_t a, int32x4_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint16x4_t vqrshrn_n_u32 (uint32x4_t a, const int n) + /// A32: VQRSHRN.U32 Dd, Qm, #n + /// A64: UQRSHRN Vd.4H, Vn.4S, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int64x2_t vornq_s64 (int64x2_t a, int64x2_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint32x2_t vqrshrn_n_u64 (uint64x2_t a, const int n) + /// A32: VQRSHRN.U64 Dd, Qm, #n + /// A64: UQRSHRN Vd.2S, Vn.2D, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vornq_s8 (int8x16_t a, int8x16_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint8x8_t vqrshrn_n_u16 (uint16x8_t a, const int n) + /// A32: VQRSHRN.U16 Dd, Qm, #n + /// A64: UQRSHRN Vd.8B, Vn.8H, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vornq_f32 (float32x4_t a, float32x4_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x4_t vqrshrn_n_u32 (uint32x4_t a, const int n) + /// A32: VQRSHRN.U32 Dd, Qm, #n + /// A64: UQRSHRN Vd.4H, Vn.4S, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint16x8_t vornq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint32x2_t vqrshrn_n_u64 (uint64x2_t a, const int n) + /// A32: VQRSHRN.U64 Dd, Qm, #n + /// A64: UQRSHRN Vd.2S, Vn.2D, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vornq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint8x16_t vqrshrn_high_n_u16 (uint8x8_t r, uint16x8_t a, const int n) + /// A32: VQRSHRN.U16 Dd+1, Dn, #n + /// A64: UQRSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint64x2_t vornq_u64 (uint64x2_t a, uint64x2_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vqrshrn_high_n_u32 (uint16x4_t r, uint32x4_t a, const int n) + /// A32: VQRSHRN.U32 Dd+1, Dn, #n + /// A64: UQRSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) - /// A32: VMUL.P8 Dd, Dn, Dm - /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// uint32x4_t vqrshrn_high_n_u64 (uint32x2_t r, uint64x2_t a, const int n) + /// A32: VQRSHRN.U64 Dd+1, Dn, #n + /// A64: UQRSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) - /// A32: VMUL.P8 Dd, Dn, Dm - /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// uint8x16_t vqrshrn_high_n_u16 (uint8x8_t r, uint16x8_t a, const int n) + /// A32: VQRSHRN.U16 Dd+1, Dn, #n + /// A64: UQRSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) - /// A32: VMUL.P8 Qd, Qn, Qm - /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vqrshrn_high_n_u32 (uint16x4_t r, uint32x4_t a, const int n) + /// A32: VQRSHRN.U32 Dd+1, Dn, #n + /// A64: UQRSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) - /// A32: VMUL.P8 Qd, Qn, Qm - /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// uint32x4_t vqrshrn_high_n_u64 (uint32x2_t r, uint64x2_t a, const int n) + /// A32: VQRSHRN.U64 Dd+1, Dn, #n + /// A64: UQRSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x8_t vcnt_u8 (uint8x8_t a) - /// A32: VCNT.I8 Dd, Dm - /// A64: CNT Vd.8B, Vn.8B + /// uint8x16_t vrshrn_high_n_u16 (uint8x8_t r, uint16x8_t a, const int n) + /// A32: VRSHRN.I16 Dd+1, Qm, #n + /// A64: RSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector64 PopCount(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedNarrowingUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x8_t vcnt_s8 (int8x8_t a) - /// A32: VCNT.I8 Dd, Dm - /// A64: CNT Vd.8B, Vn.8B + /// int16x8_t vrshrn_high_n_s32 (int16x4_t r, int32x4_t a, const int n) + /// A32: VRSHRN.I32 Dd+1, Qm, #n + /// A64: RSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector64 PopCount(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedNarrowingUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint8x16_t vcntq_u8 (uint8x16_t a) - /// A32: VCNT.I8 Qd, Qm - /// A64: CNT Vd.16B, Vn.16B + /// int32x4_t vrshrn_high_n_s64 (int32x2_t r, int64x2_t a, const int n) + /// A32: VRSHRN.I64 Dd+1, Qm, #n + /// A64: RSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector128 PopCount(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedNarrowingUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// int8x16_t vcntq_s8 (int8x16_t a) - /// A32: VCNT.I8 Qd, Qm - /// A64: CNT Vd.16B, Vn.16B + /// int8x16_t vrshrn_high_n_s16 (int8x8_t r, int16x8_t a, const int n) + /// A32: VRSHRN.I16 Dd+1, Qm, #n + /// A64: RSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector128 PopCount(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedNarrowingUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vrecpe_f32 (float32x2_t a) - /// A32: VRECPE.F32 Dd, Dm - /// A64: FRECPE Vd.2S, Vn.2S + /// uint16x8_t vrshrn_high_n_u32 (uint16x4_t r, uint32x4_t a, const int n) + /// A32: VRSHRN.I32 Dd+1, Qm, #n + /// A64: RSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector64 ReciprocalEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedNarrowingUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vrecpe_u32 (uint32x2_t a) - /// A32: VRECPE.U32 Dd, Dm - /// A64: URECPE Vd.2S, Vn.2S + /// uint32x4_t vrshrn_high_n_u64 (uint32x2_t r, uint64x2_t a, const int n) + /// A32: VRSHRN.I64 Dd+1, Qm, #n + /// A64: RSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector64 ReciprocalEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector128 ShiftRightLogicalRoundedNarrowingUpper(Vector64 lower, Vector128 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vrecpeq_f32 (float32x4_t a) - /// A32: VRECPE.F32 Qd, Qm - /// A64: FRECPE Vd.4S, Vn.4S + /// uint64x1_t vrshr_n_u64 (uint64x1_t a, const int n) + /// A32: VRSHR.U64 Dd, Dm, #n + /// A64: URSHR Dd, Dn, #n /// - public static Vector128 ReciprocalEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vrecpeq_u32 (uint32x4_t a) - /// A32: VRECPE.U32 Qd, Qm - /// A64: URECPE Vd.4S, Vn.4S + /// uint64x1_t vrshr_n_u64 (uint64x1_t a, const int n) + /// A32: VRSHR.U64 Dd, Dm, #n + /// A64: URSHR Dd, Dn, #n /// - public static Vector128 ReciprocalEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalRoundedScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vrsqrte_f32 (float32x2_t a) - /// A32: VRSQRTE.F32 Dd, Dm - /// A64: FRSQRTE Vd.2S, Vn.2S + /// uint64x1_t vshr_n_u64 (uint64x1_t a, const int n) + /// A32: VSHR.U64 Dd, Dm, #n + /// A64: USHR Dd, Dn, #n /// - public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// uint32x2_t vrsqrte_u32 (uint32x2_t a) - /// A32: VRSQRTE.U32 Dd, Dm - /// A64: URSQRTE Vd.2S, Vn.2S + /// uint64x1_t vshr_n_u64 (uint64x1_t a, const int n) + /// A32: VSHR.U64 Dd, Dm, #n + /// A64: USHR Dd, Dn, #n /// - public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + public static Vector64 ShiftRightLogicalScalar(Vector64 value, byte count) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vrsqrteq_f32 (float32x4_t a) - /// A32: VRSQRTE.F32 Qd, Qm - /// A64: FRSQRTE Vd.4S, Vn.4S + /// int32x4_t vmovl_s16 (int16x4_t a) + /// A32: VMOVL.S16 Qd, Dm + /// A64: SXTL Vd.4S, Vn.4H /// - public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 SignExtendWideningLower(Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// uint32x4_t vrsqrteq_u32 (uint32x4_t a) - /// A32: VRSQRTE.U32 Qd, Qm - /// A64: URSQRTE Vd.4S, Vn.4S + /// int64x2_t vmovl_s32 (int32x2_t a) + /// A32: VMOVL.S32 Qd, Dm + /// A64: SXTL Vd.2D, Vn.2S /// - public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + public static Vector128 SignExtendWideningLower(Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vrsqrts_f32 (float32x2_t a, float32x2_t b) - /// A32: VRSQRTS.F32 Dd, Dn, Dm - /// A64: FRSQRTS Vd.2S, Vn.2S, Vm.2S + /// int16x8_t vmovl_s8 (int8x8_t a) + /// A32: VMOVL.S8 Qd, Dm + /// A64: SXTL Vd.8H, Vn.8B /// - public static Vector64 ReciprocalSquareRootStep(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 SignExtendWideningLower(Vector64 value) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vrsqrtsq_f32 (float32x4_t a, float32x4_t b) - /// A32: VRSQRTS.F32 Qd, Qn, Qm - /// A64: FRSQRTS Vd.4S, Vn.4S, Vm.4S + /// int32x4_t vmovl_high_s16 (int16x8_t a) + /// A32: VMOVL.S16 Qd, Dm+1 + /// A64: SXTL2 Vd.4S, Vn.8H /// - public static Vector128 ReciprocalSquareRootStep(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 SignExtendWideningUpper(Vector128 value) { throw new PlatformNotSupportedException(); } /// - /// float32x2_t vrecps_f32 (float32x2_t a, float32x2_t b) - /// A32: VRECPS.F32 Dd, Dn, Dm - /// A64: FRECPS Vd.2S, Vn.2S, Vm.2S + /// int64x2_t vmovl_high_s32 (int32x4_t a) + /// A32: VMOVL.S32 Qd, Dm+1 + /// A64: SXTL2 Vd.2D, Vn.4S /// - public static Vector64 ReciprocalStep(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + public static Vector128 SignExtendWideningUpper(Vector128 value) { throw new PlatformNotSupportedException(); } /// - /// float32x4_t vrecpsq_f32 (float32x4_t a, float32x4_t b) - /// A32: VRECPS.F32 Qd, Qn, Qm - /// A64: FRECPS Vd.4S, Vn.4S, Vm.4S + /// int16x8_t vmovl_high_s8 (int8x16_t a) + /// A32: VMOVL.S8 Qd, Dm+1 + /// A64: SXTL2 Vd.8H, Vn.16B /// - public static Vector128 ReciprocalStep(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + public static Vector128 SignExtendWideningUpper(Vector128 value) { throw new PlatformNotSupportedException(); } /// /// float64x1_t vsqrt_f64 (float64x1_t a) @@ -5302,6 +9954,286 @@ internal Arm64() { } /// public static Vector128 Subtract(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// + /// uint8x8_t vsubhn_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VSUBHN.I16 Dd, Qn, Qm + /// A64: SUBHN Vd.8B, Vn.8H, Vm.8H + /// + public static Vector64 SubtractHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vsubhn_s32 (int32x4_t a, int32x4_t b) + /// A32: VSUBHN.I32 Dd, Qn, Qm + /// A64: SUBHN Vd.4H, Vn.4S, Vm.4S + /// + public static Vector64 SubtractHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vsubhn_s64 (int64x2_t a, int64x2_t b) + /// A32: VSUBHN.I64 Dd, Qn, Qm + /// A64: SUBHN Vd.2S, Vn.2D, Vm.2D + /// + public static Vector64 SubtractHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vsubhn_s16 (int16x8_t a, int16x8_t b) + /// A32: VSUBHN.I16 Dd, Qn, Qm + /// A64: SUBHN Vd.8B, Vn.8H, Vm.8H + /// + public static Vector64 SubtractHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vsubhn_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VSUBHN.I32 Dd, Qn, Qm + /// A64: SUBHN Vd.4H, Vn.4S, Vm.4S + /// + public static Vector64 SubtractHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vsubhn_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VSUBHN.I64 Dd, Qn, Qm + /// A64: SUBHN Vd.2S, Vn.2D, Vm.2D + /// + public static Vector64 SubtractHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vsubhn_high_u16 (uint8x8_t r, uint16x8_t a, uint16x8_t b) + /// A32: VSUBHN.I16 Dd+1, Qn, Qm + /// A64: SUBHN2 Vd.16B, Vn.8H, Vm.8H + /// + public static Vector128 SubtractHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vsubhn_high_s32 (int16x4_t r, int32x4_t a, int32x4_t b) + /// A32: VSUBHN.I32 Dd+1, Qn, Qm + /// A64: SUBHN2 Vd.8H, Vn.4S, Vm.4S + /// + public static Vector128 SubtractHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vsubhn_high_s64 (int32x2_t r, int64x2_t a, int64x2_t b) + /// A32: VSUBHN.I64 Dd+1, Qn, Qm + /// A64: SUBHN2 Vd.4S, Vn.2D, Vm.2D + /// + public static Vector128 SubtractHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vsubhn_high_s16 (int8x8_t r, int16x8_t a, int16x8_t b) + /// A32: VSUBHN.I16 Dd+1, Qn, Qm + /// A64: SUBHN2 Vd.16B, Vn.8H, Vm.8H + /// + public static Vector128 SubtractHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vsubhn_high_u32 (uint16x4_t r, uint32x4_t a, uint32x4_t b) + /// A32: VSUBHN.I32 Dd+1, Qn, Qm + /// A64: SUBHN2 Vd.8H, Vn.4S, Vm.4S + /// + public static Vector128 SubtractHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vsubhn_high_u64 (uint32x2_t r, uint64x2_t a, uint64x2_t b) + /// A32: VSUBHN.I64 Dd+1, Qn, Qm + /// A64: SUBHN2 Vd.4S, Vn.2D, Vm.2D + /// + public static Vector128 SubtractHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vrsubhn_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VRSUBHN.I16 Dd, Qn, Qm + /// A64: RSUBHN Vd.8B, Vn.8H, Vm.8H + /// + public static Vector64 SubtractRoundedHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vrsubhn_s32 (int32x4_t a, int32x4_t b) + /// A32: VRSUBHN.I32 Dd, Qn, Qm + /// A64: RSUBHN Vd.4H, Vn.4S, Vm.4S + /// + public static Vector64 SubtractRoundedHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vrsubhn_s64 (int64x2_t a, int64x2_t b) + /// A32: VRSUBHN.I64 Dd, Qn, Qm + /// A64: RSUBHN Vd.2S, Vn.2D, Vm.2D + /// + public static Vector64 SubtractRoundedHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vrsubhn_s16 (int16x8_t a, int16x8_t b) + /// A32: VRSUBHN.I16 Dd, Qn, Qm + /// A64: RSUBHN Vd.8B, Vn.8H, Vm.8H + /// + public static Vector64 SubtractRoundedHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vrsubhn_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VRSUBHN.I32 Dd, Qn, Qm + /// A64: RSUBHN Vd.4H, Vn.4S, Vm.4S + /// + public static Vector64 SubtractRoundedHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vrsubhn_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VRSUBHN.I64 Dd, Qn, Qm + /// A64: RSUBHN Vd.2S, Vn.2D, Vm.2D + /// + public static Vector64 SubtractRoundedHighNarrowingLower(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vrsubhn_high_u16 (uint8x8_t r, uint16x8_t a, uint16x8_t b) + /// A32: VRSUBHN.I16 Dd+1, Qn, Qm + /// A64: RSUBHN2 Vd.16B, Vn.8H, Vm.8H + /// + public static Vector128 SubtractRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vrsubhn_high_s32 (int16x4_t r, int32x4_t a, int32x4_t b) + /// A32: VRSUBHN.I32 Dd+1, Qn, Qm + /// A64: RSUBHN2 Vd.8H, Vn.4S, Vm.4S + /// + public static Vector128 SubtractRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vrsubhn_high_s64 (int32x2_t r, int64x2_t a, int64x2_t b) + /// A32: VRSUBHN.I64 Dd+1, Qn, Qm + /// A64: RSUBHN2 Vd.4S, Vn.2D, Vm.2D + /// + public static Vector128 SubtractRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vrsubhn_high_s16 (int8x8_t r, int16x8_t a, int16x8_t b) + /// A32: VRSUBHN.I16 Dd+1, Qn, Qm + /// A64: RSUBHN2 Vd.16B, Vn.8H, Vm.8H + /// + public static Vector128 SubtractRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vrsubhn_high_u32 (uint16x4_t r, uint32x4_t a, uint32x4_t b) + /// A32: VRSUBHN.I32 Dd+1, Qn, Qm + /// A64: RSUBHN2 Vd.8H, Vn.4S, Vm.4S + /// + public static Vector128 SubtractRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vrsubhn_high_u64 (uint32x2_t r, uint64x2_t a, uint64x2_t b) + /// A32: VRSUBHN.I64 Dd+1, Qn, Qm + /// A64: RSUBHN2 Vd.4S, Vn.2D, Vm.2D + /// + public static Vector128 SubtractRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vqsub_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VQSUB.U8 Dd, Dn, Dm + /// A64: UQSUB Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 SubtractSaturate(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vqsub_s16 (int16x4_t a, int16x4_t b) + /// A32: VQSUB.S16 Dd, Dn, Dm + /// A64: SQSUB Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 SubtractSaturate(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vqsub_s32 (int32x2_t a, int32x2_t b) + /// A32: VQSUB.S32 Dd, Dn, Dm + /// A64: SQSUB Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 SubtractSaturate(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vqsub_s8 (int8x8_t a, int8x8_t b) + /// A32: VQSUB.S8 Dd, Dn, Dm + /// A64: SQSUB Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 SubtractSaturate(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vqsub_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VQSUB.U16 Dd, Dn, Dm + /// A64: UQSUB Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 SubtractSaturate(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vqsub_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VQSUB.U32 Dd, Dn, Dm + /// A64: UQSUB Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 SubtractSaturate(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vqsubq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VQSUB.U8 Qd, Qn, Qm + /// A64: UQSUB Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vqsubq_s16 (int16x8_t a, int16x8_t b) + /// A32: VQSUB.S16 Qd, Qn, Qm + /// A64: SQSUB Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vqsubq_s32 (int32x4_t a, int32x4_t b) + /// A32: VQSUB.S32 Qd, Qn, Qm + /// A64: SQSUB Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vqsubq_s64 (int64x2_t a, int64x2_t b) + /// A32: VQSUB.S64 Qd, Qn, Qm + /// A64: SQSUB Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vqsubq_s8 (int8x16_t a, int8x16_t b) + /// A32: VQSUB.S8 Qd, Qn, Qm + /// A64: SQSUB Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vqsubq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VQSUB.U16 Qd, Qn, Qm + /// A64: UQSUB Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vqsubq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VQSUB.U32 Qd, Qn, Qm + /// A64: UQSUB Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vqsubq_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VQSUB.U64 Qd, Qn, Qm + /// A64: UQSUB Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x1_t vqsub_s64 (int64x1_t a, int64x1_t b) + /// A32: VQSUB.S64 Dd, Dn, Dm + /// A64: SQSUB Dd, Dn, Dm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x1_t vqsub_u64 (uint64x1_t a, uint64x1_t b) + /// A32: VQSUB.U64 Dd, Dn, Dm + /// A64: UQSUB Dd, Dn, Dm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + /// /// float64x1_t vsub_f64 (float64x1_t a, float64x1_t b) /// A32: VSUB.F64 Dd, Dn, Dm @@ -5331,6 +10263,202 @@ internal Arm64() { } /// public static Vector64 SubtractScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + /// + /// uint16x8_t vsubl_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VSUBL.U8 Qd, Dn, Dm + /// A64: USUBL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 SubtractWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vsubl_s16 (int16x4_t a, int16x4_t b) + /// A32: VSUBL.S16 Qd, Dn, Dm + /// A64: SSUBL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 SubtractWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vsubl_s32 (int32x2_t a, int32x2_t b) + /// A32: VSUBL.S32 Qd, Dn, Dm + /// A64: SSUBL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 SubtractWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vsubl_s8 (int8x8_t a, int8x8_t b) + /// A32: VSUBL.S8 Qd, Dn, Dm + /// A64: SSUBL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 SubtractWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vsubl_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VSUBL.U16 Qd, Dn, Dm + /// A64: USUBL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 SubtractWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vsubl_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VSUBL.U32 Qd, Dn, Dm + /// A64: USUBL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 SubtractWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vsubw_s8 (int16x8_t a, int8x8_t b) + /// A32: VSUBW.S8 Qd, Qn, Dm + /// A64: SSUBW Vd.8H, Vn.8H, Vm.8B + /// + public static Vector128 SubtractWideningLower(Vector128 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vsubw_s16 (int32x4_t a, int16x4_t b) + /// A32: VSUBW.S16 Qd, Qn, Dm + /// A64: SSUBW Vd.4S, Vn.4S, Vm.4H + /// + public static Vector128 SubtractWideningLower(Vector128 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vsubw_s32 (int64x2_t a, int32x2_t b) + /// A32: VSUBW.S32 Qd, Qn, Dm + /// A64: SSUBW Vd.2D, Vn.2D, Vm.2S + /// + public static Vector128 SubtractWideningLower(Vector128 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vsubw_u8 (uint16x8_t a, uint8x8_t b) + /// A32: VSUBW.U8 Qd, Qn, Dm + /// A64: USUBW Vd.8H, Vn.8H, Vm.8B + /// + public static Vector128 SubtractWideningLower(Vector128 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vsubw_u16 (uint32x4_t a, uint16x4_t b) + /// A32: VSUBW.U16 Qd, Qn, Dm + /// A64: USUBW Vd.4S, Vn.4S, Vm.4H + /// + public static Vector128 SubtractWideningLower(Vector128 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vsubw_u32 (uint64x2_t a, uint32x2_t b) + /// A32: VSUBW.U32 Qd, Qn, Dm + /// A64: USUBW Vd.2D, Vn.2D, Vm.2S + /// + public static Vector128 SubtractWideningLower(Vector128 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vsubl_high_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VSUBL.U8 Qd, Dn+1, Dm+1 + /// A64: USUBL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vsubl_high_s16 (int16x8_t a, int16x8_t b) + /// A32: VSUBL.S16 Qd, Dn+1, Dm+1 + /// A64: SSUBL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vsubw_high_s8 (int16x8_t a, int8x16_t b) + /// A32: VSUBW.S8 Qd, Qn, Dm+1 + /// A64: SSUBW2 Vd.8H, Vn.8H, Vm.16B + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vsubw_high_s16 (int32x4_t a, int16x8_t b) + /// A32: VSUBW.S16 Qd, Qn, Dm+1 + /// A64: SSUBW2 Vd.4S, Vn.4S, Vm.8H + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vsubl_high_s32 (int32x4_t a, int32x4_t b) + /// A32: VSUBL.S32 Qd, Dn+1, Dm+1 + /// A64: SSUBL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vsubw_high_s32 (int64x2_t a, int32x4_t b) + /// A32: VSUBW.S32 Qd, Qn, Dm+1 + /// A64: SSUBW2 Vd.2D, Vn.2D, Vm.4S + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vsubl_high_s8 (int8x16_t a, int8x16_t b) + /// A32: VSUBL.S8 Qd, Dn+1, Dm+1 + /// A64: SSUBL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vsubw_high_u8 (uint16x8_t a, uint8x16_t b) + /// A32: VSUBW.U8 Qd, Qn, Dm+1 + /// A64: USUBW2 Vd.8H, Vn.8H, Vm.16B + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vsubl_high_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VSUBL.U16 Qd, Dn+1, Dm+1 + /// A64: USUBL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vsubw_high_u16 (uint32x4_t a, uint16x8_t b) + /// A32: VSUBW.U16 Qd, Qn, Dm+1 + /// A64: USUBW2 Vd.4S, Vn.4S, Vm.8H + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vsubl_high_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VSUBL.U32 Qd, Dn+1, Dm+1 + /// A64: USUBL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vsubw_high_u32 (uint64x2_t a, uint32x4_t b) + /// A32: VSUBW.U32 Qd, Qn, Dm+1 + /// A64: USUBW2 Vd.2D, Vn.2D, Vm.4S + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vqvtbl1_u8(uint8x16_t t, uint8x8_t idx) + /// A32: VTBL Dd, {Dn, Dn+1}, Dm + /// A64: TBL Vd.8B, {Vn.16B}, Vm.8B + /// + public static Vector64 VectorTableLookup(Vector128 table, Vector64 byteIndexes) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vqvtbl1_s8(int8x16_t t, uint8x8_t idx) + /// A32: VTBL Dd, {Dn, Dn+1}, Dm + /// A64: TBL Vd.8B, {Vn.16B}, Vm.8B + /// + public static Vector64 VectorTableLookup(Vector128 table, Vector64 byteIndexes) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vqvtbx1_u8(uint8x8_t r, uint8x16_t t, uint8x8_t idx) + /// A32: VTBX Dd, {Dn, Dn+1}, Dm + /// A64: TBX Vd.8B, {Vn.16B}, Vm.8B + /// + public static Vector64 VectorTableLookupExtension(Vector64 defaultValues, Vector128 table, Vector64 byteIndexes) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vqvtbx1_s8(int8x8_t r, int8x16_t t, uint8x8_t idx) + /// A32: VTBX Dd, {Dn, Dn+1}, Dm + /// A64: TBX Vd.8B, {Vn.16B}, Vm.8B + /// + public static Vector64 VectorTableLookupExtension(Vector64 defaultValues, Vector128 table, Vector64 byteIndexes) { throw new PlatformNotSupportedException(); } + /// /// uint8x8_t veor_u8 (uint8x8_t a, uint8x8_t b) /// A32: VEOR Dd, Dn, Dm @@ -5474,5 +10602,89 @@ internal Arm64() { } /// A64: EOR Vd.16B, Vn.16B, Vm.16B /// public static Vector128 Xor(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmovl_u8 (uint8x8_t a) + /// A32: VMOVL.U8 Qd, Dm + /// A64: UXTL Vd.8H, Vn.8B + /// + public static Vector128 ZeroExtendWideningLower(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmovl_u16 (uint16x4_t a) + /// A32: VMOVL.U16 Qd, Dm + /// A64: UXTL Vd.4S, Vn.4H + /// + public static Vector128 ZeroExtendWideningLower(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vmovl_u32 (uint32x2_t a) + /// A32: VMOVL.U32 Qd, Dm + /// A64: UXTL Vd.2D, Vn.2S + /// + public static Vector128 ZeroExtendWideningLower(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmovl_u8 (uint8x8_t a) + /// A32: VMOVL.U8 Qd, Dm + /// A64: UXTL Vd.8H, Vn.8B + /// + public static Vector128 ZeroExtendWideningLower(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmovl_u16 (uint16x4_t a) + /// A32: VMOVL.U16 Qd, Dm + /// A64: UXTL Vd.4S, Vn.4H + /// + public static Vector128 ZeroExtendWideningLower(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vmovl_u32 (uint32x2_t a) + /// A32: VMOVL.U32 Qd, Dm + /// A64: UXTL Vd.2D, Vn.2S + /// + public static Vector128 ZeroExtendWideningLower(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmovl_high_u8 (uint8x16_t a) + /// A32: VMOVL.U8 Qd, Dm+1 + /// A64: UXTL2 Vd.8H, Vn.16B + /// + public static Vector128 ZeroExtendWideningUpper(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmovl_high_u16 (uint16x8_t a) + /// A32: VMOVL.U16 Qd, Dm+1 + /// A64: UXTL2 Vd.4S, Vn.8H + /// + public static Vector128 ZeroExtendWideningUpper(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vmovl_high_u32 (uint32x4_t a) + /// A32: VMOVL.U32 Qd, Dm+1 + /// A64: UXTL2 Vd.2D, Vn.4S + /// + public static Vector128 ZeroExtendWideningUpper(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmovl_high_u8 (uint8x16_t a) + /// A32: VMOVL.U8 Qd, Dm+1 + /// A64: UXTL2 Vd.8H, Vn.16B + /// + public static Vector128 ZeroExtendWideningUpper(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmovl_high_u16 (uint16x8_t a) + /// A32: VMOVL.U16 Qd, Dm+1 + /// A64: UXTL2 Vd.4S, Vn.8H + /// + public static Vector128 ZeroExtendWideningUpper(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vmovl_high_u32 (uint32x4_t a) + /// A32: VMOVL.U32 Qd, Dm+1 + /// A64: UXTL2 Vd.2D, Vn.4S + /// + public static Vector128 ZeroExtendWideningUpper(Vector128 value) { throw new PlatformNotSupportedException(); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.cs index 686fc7ad832477..72233956e18299 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/AdvSimd.cs @@ -340,6 +340,42 @@ internal Arm64() { } /// public static Vector64 AddPairwiseScalar(Vector128 value) => AddPairwiseScalar(value); + /// + /// uint8_t vqaddb_u8 (uint8_t a, uint8_t b) + /// A64: UQADD Bd, Bn, Bm + /// + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) => AddSaturateScalar(left, right); + + /// + /// int16_t vqaddh_s16 (int16_t a, int16_t b) + /// A64: SQADD Hd, Hn, Hm + /// + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) => AddSaturateScalar(left, right); + + /// + /// int32_t vqadds_s32 (int32_t a, int32_t b) + /// A64: SQADD Sd, Sn, Sm + /// + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) => AddSaturateScalar(left, right); + + /// + /// int8_t vqaddb_s8 (int8_t a, int8_t b) + /// A64: SQADD Bd, Bn, Bm + /// + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) => AddSaturateScalar(left, right); + + /// + /// uint16_t vqaddh_u16 (uint16_t a, uint16_t b) + /// A64: UQADD Hd, Hn, Hm + /// + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) => AddSaturateScalar(left, right); + + /// + /// uint32_t vqadds_u32 (uint32_t a, uint32_t b) + /// A64: UQADD Sd, Sn, Sm + /// + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) => AddSaturateScalar(left, right); + /// /// uint64x2_t vceqq_f64 (float64x2_t a, float64x2_t b) /// A64: FCMEQ Vd.2D, Vn.2D, Vm.2D @@ -606,6 +642,42 @@ internal Arm64() { } /// public static Vector128 Divide(Vector128 left, Vector128 right) => Divide(left, right); + /// + /// float64x2_t vdupq_laneq_f64 (float64x2_t vec, const int lane) + /// A64: DUP Vd.2D, Vn.D[index] + /// + public static System.Runtime.Intrinsics.Vector128 DuplicateSelectedScalarToVector128(System.Runtime.Intrinsics.Vector128 value, byte index) => DuplicateSelectedScalarToVector128(value, index); + + /// + /// int64x2_t vdupq_laneq_s64 (int64x2_t vec, const int lane) + /// A64: DUP Vd.2D, Vn.D[index] + /// + public static System.Runtime.Intrinsics.Vector128 DuplicateSelectedScalarToVector128(System.Runtime.Intrinsics.Vector128 value, byte index) => DuplicateSelectedScalarToVector128(value, index); + + /// + /// uint64x2_t vdupq_laneq_u64 (uint64x2_t vec, const int lane) + /// A64: DUP Vd.2D, Vn.D[index] + /// + public static System.Runtime.Intrinsics.Vector128 DuplicateSelectedScalarToVector128(System.Runtime.Intrinsics.Vector128 value, byte index) => DuplicateSelectedScalarToVector128(value, index); + + /// + /// float64x2_t vdupq_n_f64 (float64_t value) + /// A64: DUP Vd.2D, Vn.D[0] + /// + public static Vector128 DuplicateToVector128(double value) => DuplicateToVector128(value); + + /// + /// int64x2_t vdupq_n_s64 (int64_t value) + /// A64: DUP Vd.2D, Rn + /// + public static Vector128 DuplicateToVector128(long value) => DuplicateToVector128(value); + + /// + /// uint64x2_t vdupq_n_s64 (uint64_t value) + /// A64: DUP Vd.2D, Rn + /// + public static Vector128 DuplicateToVector128(ulong value) => DuplicateToVector128(value); + /// /// float64x2_t vfmaq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) /// A64: FMLA Vd.2D, Vn.2D, Vm.2D @@ -1130,6 +1202,312 @@ internal Arm64() { } /// public static Vector64 ReciprocalStepScalar(Vector64 left, Vector64 right) => ReciprocalStepScalar(left, right); + /// + /// int16_t vqrshlh_s16 (int16_t a, int16_t b) + /// A64: SQRSHL Hd, Hn, Hm + /// + public static Vector64 ShiftArithmeticRoundedSaturateScalar(Vector64 value, Vector64 count) => ShiftArithmeticRoundedSaturateScalar(value, count); + + /// + /// int32_t vqrshls_s32 (int32_t a, int32_t b) + /// A64: SQRSHL Sd, Sn, Sm + /// + public static Vector64 ShiftArithmeticRoundedSaturateScalar(Vector64 value, Vector64 count) => ShiftArithmeticRoundedSaturateScalar(value, count); + + /// + /// int8_t vqrshlb_s8 (int8_t a, int8_t b) + /// A64: SQRSHL Bd, Bn, Bm + /// + public static Vector64 ShiftArithmeticRoundedSaturateScalar(Vector64 value, Vector64 count) => ShiftArithmeticRoundedSaturateScalar(value, count); + + /// + /// int16_t vqshlh_s16 (int16_t a, int16_t b) + /// A64: SQSHL Hd, Hn, Hm + /// + public static Vector64 ShiftArithmeticSaturateScalar(Vector64 value, Vector64 count) => ShiftArithmeticSaturateScalar(value, count); + + /// + /// int32_t vqshls_s32 (int32_t a, int32_t b) + /// A64: SQSHL Sd, Sn, Sm + /// + public static Vector64 ShiftArithmeticSaturateScalar(Vector64 value, Vector64 count) => ShiftArithmeticSaturateScalar(value, count); + + /// + /// int8_t vqshlb_s8 (int8_t a, int8_t b) + /// A64: SQSHL Bd, Bn, Bm + /// + public static Vector64 ShiftArithmeticSaturateScalar(Vector64 value, Vector64 count) => ShiftArithmeticSaturateScalar(value, count); + + /// + /// uint8_t vqshlb_n_u8 (uint8_t a, const int n) + /// A64: UQSHL Bd, Bn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) => ShiftLeftLogicalSaturateScalar(value, count); + + /// + /// int16_t vqshlh_n_s16 (int16_t a, const int n) + /// A64: SQSHL Hd, Hn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) => ShiftLeftLogicalSaturateScalar(value, count); + + /// + /// int32_t vqshls_n_s32 (int32_t a, const int n) + /// A64: SQSHL Sd, Sn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) => ShiftLeftLogicalSaturateScalar(value, count); + + /// + /// int8_t vqshlb_n_s8 (int8_t a, const int n) + /// A64: SQSHL Bd, Bn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) => ShiftLeftLogicalSaturateScalar(value, count); + + /// + /// uint16_t vqshlh_n_u16 (uint16_t a, const int n) + /// A64: UQSHL Hd, Hn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) => ShiftLeftLogicalSaturateScalar(value, count); + + /// + /// uint32_t vqshls_n_u32 (uint32_t a, const int n) + /// A64: UQSHL Sd, Sn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) => ShiftLeftLogicalSaturateScalar(value, count); + + /// + /// uint16_t vqshluh_n_s16 (int16_t a, const int n) + /// A64: SQSHLU Hd, Hn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateUnsignedScalar(Vector64 value, byte count) => ShiftLeftLogicalSaturateUnsignedScalar(value, count); + + /// + /// uint32_t vqshlus_n_s32 (int32_t a, const int n) + /// A64: SQSHLU Sd, Sn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateUnsignedScalar(Vector64 value, byte count) => ShiftLeftLogicalSaturateUnsignedScalar(value, count); + + /// + /// uint8_t vqshlub_n_s8 (int8_t a, const int n) + /// A64: SQSHLU Bd, Bn, #n + /// + public static Vector64 ShiftLeftLogicalSaturateUnsignedScalar(Vector64 value, byte count) => ShiftLeftLogicalSaturateUnsignedScalar(value, count); + + /// + /// uint8_t vqrshlb_u8 (uint8_t a, int8_t b) + /// A64: UQRSHL Bd, Bn, Bm + /// + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalRoundedSaturateScalar(value, count); + + /// + /// uint16_t vqrshlh_u16 (uint16_t a, int16_t b) + /// A64: UQRSHL Hd, Hn, Hm + /// + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalRoundedSaturateScalar(value, count); + + /// + /// uint32_t vqrshls_u32 (uint32_t a, int32_t b) + /// A64: UQRSHL Sd, Sn, Sm + /// + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalRoundedSaturateScalar(value, count); + + /// + /// uint8_t vqrshlb_u8 (uint8_t a, int8_t b) + /// A64: UQRSHL Bd, Bn, Bm + /// + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalRoundedSaturateScalar(value, count); + + /// + /// uint16_t vqrshlh_u16 (uint16_t a, int16_t b) + /// A64: UQRSHL Hd, Hn, Hm + /// + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalRoundedSaturateScalar(value, count); + + /// + /// uint32_t vqrshls_u32 (uint32_t a, int32_t b) + /// A64: UQRSHL Sd, Sn, Sm + /// + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalRoundedSaturateScalar(value, count); + + /// + /// uint8_t vqshlb_u8 (uint8_t a, int8_t b) + /// A64: UQSHL Bd, Bn, Bm + /// + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalSaturateScalar(value, count); + + /// + /// uint16_t vqshlh_u16 (uint16_t a, int16_t b) + /// A64: UQSHL Hd, Hn, Hm + /// + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalSaturateScalar(value, count); + + /// + /// uint32_t vqshls_u32 (uint32_t a, int32_t b) + /// A64: UQSHL Sd, Sn, Sm + /// + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalSaturateScalar(value, count); + + /// + /// uint8_t vqshlb_u8 (uint8_t a, int8_t b) + /// A64: UQSHL Bd, Bn, Bm + /// + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalSaturateScalar(value, count); + + /// + /// uint16_t vqshlh_u16 (uint16_t a, int16_t b) + /// A64: UQSHL Hd, Hn, Hm + /// + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalSaturateScalar(value, count); + + /// + /// uint32_t vqshls_u32 (uint32_t a, int32_t b) + /// A64: UQSHL Sd, Sn, Sm + /// + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalSaturateScalar(value, count); + + /// + /// int16_t vqshrns_n_s32 (int32_t a, const int n) + /// A64: SQSHRN Hd, Sn, #n + /// + public static Vector64 ShiftRightArithmeticNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightArithmeticNarrowingSaturateScalar(value, count); + + /// + /// int32_t vqshrnd_n_s64 (int64_t a, const int n) + /// A64: SQSHRN Sd, Dn, #n + /// + public static Vector64 ShiftRightArithmeticNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightArithmeticNarrowingSaturateScalar(value, count); + + /// + /// int8_t vqshrnh_n_s16 (int16_t a, const int n) + /// A64: SQSHRN Bd, Hn, #n + /// + public static Vector64 ShiftRightArithmeticNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightArithmeticNarrowingSaturateScalar(value, count); + + /// + /// uint8_t vqshrunh_n_s16 (int16_t a, const int n) + /// A64: SQSHRUN Bd, Hn, #n + /// + public static Vector64 ShiftRightArithmeticNarrowingSaturateUnsignedScalar(Vector64 value, byte count) => ShiftRightArithmeticNarrowingSaturateUnsignedScalar(value, count); + + /// + /// uint16_t vqshruns_n_s32 (int32_t a, const int n) + /// A64: SQSHRUN Hd, Sn, #n + /// + public static Vector64 ShiftRightArithmeticNarrowingSaturateUnsignedScalar(Vector64 value, byte count) => ShiftRightArithmeticNarrowingSaturateUnsignedScalar(value, count); + + /// + /// uint32_t vqshrund_n_s64 (int64_t a, const int n) + /// A64: SQSHRUN Sd, Dn, #n + /// + public static Vector64 ShiftRightArithmeticNarrowingSaturateUnsignedScalar(Vector64 value, byte count) => ShiftRightArithmeticNarrowingSaturateUnsignedScalar(value, count); + + /// + /// int16_t vqrshrns_n_s32 (int32_t a, const int n) + /// A64: SQRSHRN Hd, Sn, #n + /// + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateScalar(value, count); + + /// + /// int32_t vqrshrnd_n_s64 (int64_t a, const int n) + /// A64: SQRSHRN Sd, Dn, #n + /// + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateScalar(value, count); + + /// + /// int8_t vqrshrnh_n_s16 (int16_t a, const int n) + /// A64: SQRSHRN Bd, Hn, #n + /// + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateScalar(value, count); + + /// + /// uint8_t vqrshrunh_n_s16 (int16_t a, const int n) + /// A64: SQRSHRUN Bd, Hn, #n + /// + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(Vector64 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(value, count); + + /// + /// uint16_t vqrshruns_n_s32 (int32_t a, const int n) + /// A64: SQRSHRUN Hd, Sn, #n + /// + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(Vector64 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(value, count); + + /// + /// uint32_t vqrshrund_n_s64 (int64_t a, const int n) + /// A64: SQRSHRUN Sd, Dn, #n + /// + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(Vector64 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar(value, count); + + /// + /// uint8_t vqshrnh_n_u16 (uint16_t a, const int n) + /// A64: UQSHRN Bd, Hn, #n + /// + public static Vector64 ShiftRightLogicalNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightLogicalNarrowingSaturateScalar(value, count); + + /// + /// uint16_t vqshrns_n_u32 (uint32_t a, const int n) + /// A64: UQSHRN Hd, Sn, #n + /// + public static Vector64 ShiftRightLogicalNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightLogicalNarrowingSaturateScalar(value, count); + + /// + /// uint32_t vqshrnd_n_u64 (uint64_t a, const int n) + /// A64: UQSHRN Sd, Dn, #n + /// + public static Vector64 ShiftRightLogicalNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightLogicalNarrowingSaturateScalar(value, count); + + /// + /// uint8_t vqshrnh_n_u16 (uint16_t a, const int n) + /// A64: UQSHRN Bd, Hn, #n + /// + public static Vector64 ShiftRightLogicalNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightLogicalNarrowingSaturateScalar(value, count); + + /// + /// uint16_t vqshrns_n_u32 (uint32_t a, const int n) + /// A64: UQSHRN Hd, Sn, #n + /// + public static Vector64 ShiftRightLogicalNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightLogicalNarrowingSaturateScalar(value, count); + + /// + /// uint32_t vqshrnd_n_u64 (uint64_t a, const int n) + /// A64: UQSHRN Sd, Dn, #n + /// + public static Vector64 ShiftRightLogicalNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightLogicalNarrowingSaturateScalar(value, count); + + /// + /// uint8_t vqrshrnh_n_u16 (uint16_t a, const int n) + /// A64: UQRSHRN Bd, Hn, #n + /// + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateScalar(value, count); + + /// + /// uint16_t vqrshrns_n_u32 (uint32_t a, const int n) + /// A64: UQRSHRN Hd, Sn, #n + /// + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateScalar(value, count); + + /// + /// uint32_t vqrshrnd_n_u64 (uint64_t a, const int n) + /// A64: UQRSHRN Sd, Dn, #n + /// + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateScalar(value, count); + + /// + /// uint8_t vqrshrnh_n_u16 (uint16_t a, const int n) + /// A64: UQRSHRN Bd, Hn, #n + /// + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateScalar(value, count); + + /// + /// uint16_t vqrshrns_n_u32 (uint32_t a, const int n) + /// A64: UQRSHRN Hd, Sn, #n + /// + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateScalar(value, count); + + /// + /// uint32_t vqrshrnd_n_u64 (uint64_t a, const int n) + /// A64: UQRSHRN Sd, Dn, #n + /// + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateScalar(Vector64 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateScalar(value, count); + /// /// float32x2_t vsqrt_f32 (float32x2_t a) /// A64: FSQRT Vd.2S, Vn.2S @@ -1154,6 +1532,42 @@ internal Arm64() { } /// public static Vector128 Subtract(Vector128 left, Vector128 right) => Subtract(left, right); + /// + /// uint8_t vqsubb_u8 (uint8_t a, uint8_t b) + /// A64: UQSUB Bd, Bn, Bm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) => SubtractSaturateScalar(left, right); + + /// + /// int16_t vqsubh_s16 (int16_t a, int16_t b) + /// A64: SQSUB Hd, Hn, Hm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) => SubtractSaturateScalar(left, right); + + /// + /// int32_t vqsubs_s32 (int32_t a, int32_t b) + /// A64: SQSUB Sd, Sn, Sm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) => SubtractSaturateScalar(left, right); + + /// + /// int8_t vqsubb_s8 (int8_t a, int8_t b) + /// A64: SQSUB Bd, Bn, Bm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) => SubtractSaturateScalar(left, right); + + /// + /// uint16_t vqsubh_u16 (uint16_t a, uint16_t b) + /// A64: UQSUB Hd, Hn, Hm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) => SubtractSaturateScalar(left, right); + + /// + /// uint32_t vqsubs_u32 (uint32_t a, uint32_t b) + /// A64: UQSUB Sd, Sn, Sm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) => SubtractSaturateScalar(left, right); + /// /// uint8x8_t vrbit_u8 (uint8x8_t a) /// A64: RBIT Vd.8B, Vn.8B @@ -1586,6 +2000,30 @@ internal Arm64() { } /// public static Vector128 UnzipOdd(Vector128 left, Vector128 right) => UnzipOdd(left, right); + /// + /// uint8x16_t vqvtbl1q_u8(uint8x16_t t, uint8x16_t idx) + /// A64: TBL Vd.16B, {Vn.16B}, Vm.16B + /// + public static Vector128 VectorTableLookup(Vector128 table, Vector128 byteIndexes) => VectorTableLookup(table, byteIndexes); + + /// + /// int8x16_t vqvtbl1q_s8(int8x16_t t, uint8x16_t idx) + /// A64: TBL Vd.16B, {Vn.16B}, Vm.16B + /// + public static Vector128 VectorTableLookup(Vector128 table, Vector128 byteIndexes) => VectorTableLookup(table, byteIndexes); + + /// + /// uint8x16_t vqvtbx1q_u8(uint8x16_t r, int8x16_t t, uint8x16_t idx) + /// A64: TBX Vd.16B, {Vn.16B}, Vm.16B + /// + public static Vector128 VectorTableLookupExtension(Vector128 defaultValues, Vector128 table, Vector128 byteIndexes) => VectorTableLookupExtension(defaultValues, table, byteIndexes); + + /// + /// int8x16_t vqvtbx1q_s8(int8x16_t r, int8x16_t t, uint8x16_t idx) + /// A64: TBX Vd.16B, {Vn.16B}, Vm.16B + /// + public static Vector128 VectorTableLookupExtension(Vector128 defaultValues, Vector128 table, Vector128 byteIndexes) => VectorTableLookupExtension(defaultValues, table, byteIndexes); + /// /// uint8x8_t vzip2_u8(uint8x8_t a, uint8x8_t b) /// A64: ZIP2 Vd.8B, Vn.8B, Vm.8B @@ -2101,70 +2539,238 @@ internal Arm64() { } public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceAdd(addend, left, right); /// - /// uint8x8_t vadd_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VADD.I8 Dd, Dn, Dm - /// A64: ADD Vd.8B, Vn.8B, Vm.8B + /// uint16x8_t vabdl_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VABDL.U8 Qd, Dn, Dm + /// A64: UABDL Vd.8H, Vn.8B, Vm.8B /// - public static Vector64 Add(Vector64 left, Vector64 right) => Add(left, right); + public static Vector128 AbsoluteDifferenceWideningLower(Vector64 left, Vector64 right) => AbsoluteDifferenceWideningLower(left, right); /// - /// int16x4_t vadd_s16 (int16x4_t a, int16x4_t b) - /// A32: VADD.I16 Dd, Dn, Dm - /// A64: ADD Vd.4H, Vn.4H, Vm.4H + /// int32x4_t vabdl_s16 (int16x4_t a, int16x4_t b) + /// A32: VABDL.S16 Qd, Dn, Dm + /// A64: SABDL Vd.4S, Vn.4H, Vm.4H /// - public static Vector64 Add(Vector64 left, Vector64 right) => Add(left, right); + public static Vector128 AbsoluteDifferenceWideningLower(Vector64 left, Vector64 right) => AbsoluteDifferenceWideningLower(left, right); /// - /// int32x2_t vadd_s32 (int32x2_t a, int32x2_t b) - /// A32: VADD.I32 Dd, Dn, Dm - /// A64: ADD Vd.2S, Vn.2S, Vm.2S + /// int64x2_t vabdl_s32 (int32x2_t a, int32x2_t b) + /// A32: VABDL.S32 Qd, Dn, Dm + /// A64: SABDL Vd.2D, Vn.2S, Vm.2S /// - public static Vector64 Add(Vector64 left, Vector64 right) => Add(left, right); + public static Vector128 AbsoluteDifferenceWideningLower(Vector64 left, Vector64 right) => AbsoluteDifferenceWideningLower(left, right); /// - /// int8x8_t vadd_s8 (int8x8_t a, int8x8_t b) - /// A32: VADD.I8 Dd, Dn, Dm - /// A64: ADD Vd.8B, Vn.8B, Vm.8B + /// int16x8_t vabdl_s8 (int8x8_t a, int8x8_t b) + /// A32: VABDL.S8 Qd, Dn, Dm + /// A64: SABDL Vd.8H, Vn.8B, Vm.8B /// - public static Vector64 Add(Vector64 left, Vector64 right) => Add(left, right); + public static Vector128 AbsoluteDifferenceWideningLower(Vector64 left, Vector64 right) => AbsoluteDifferenceWideningLower(left, right); /// - /// float32x2_t vadd_f32 (float32x2_t a, float32x2_t b) - /// A32: VADD.F32 Dd, Dn, Dm - /// A64: FADD Vd.2S, Vn.2S, Vm.2S + /// uint32x4_t vabdl_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VABDL.U16 Qd, Dn, Dm + /// A64: UABDL Vd.4S, Vn.4H, Vm.4H /// - public static Vector64 Add(Vector64 left, Vector64 right) => Add(left, right); + public static Vector128 AbsoluteDifferenceWideningLower(Vector64 left, Vector64 right) => AbsoluteDifferenceWideningLower(left, right); /// - /// uint16x4_t vadd_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VADD.I16 Dd, Dn, Dm - /// A64: ADD Vd.4H, Vn.4H, Vm.4H + /// uint64x2_t vabdl_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VABDL.U32 Qd, Dn, Dm + /// A64: UABDL Vd.2D, Vn.2S, Vm.2S /// - public static Vector64 Add(Vector64 left, Vector64 right) => Add(left, right); + public static Vector128 AbsoluteDifferenceWideningLower(Vector64 left, Vector64 right) => AbsoluteDifferenceWideningLower(left, right); /// - /// uint32x2_t vadd_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VADD.I32 Dd, Dn, Dm - /// A64: ADD Vd.2S, Vn.2S, Vm.2S + /// uint16x8_t vabal_u8 (uint16x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VABAL.U8 Qd, Dn, Dm + /// A64: UABAL Vd.8H, Vn.8B, Vm.8B /// - public static Vector64 Add(Vector64 left, Vector64 right) => Add(left, right); + public static Vector128 AbsoluteDifferenceWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceWideningLowerAndAdd(addend, left, right); /// - /// uint8x16_t vaddq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VADD.I8 Qd, Qn, Qm - /// A64: ADD Vd.16B, Vn.16B, Vm.16B + /// int32x4_t vabal_s16 (int32x4_t a, int16x4_t b, int16x4_t c) + /// A32: VABAL.S16 Qd, Dn, Dm + /// A64: SABAL Vd.4S, Vn.4H, Vm.4H /// - public static Vector128 Add(Vector128 left, Vector128 right) => Add(left, right); + public static Vector128 AbsoluteDifferenceWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceWideningLowerAndAdd(addend, left, right); /// - /// int16x8_t vaddq_s16 (int16x8_t a, int16x8_t b) - /// A32: VADD.I16 Qd, Qn, Qm - /// A64: ADD Vd.8H, Vn.8H, Vm.8H + /// int64x2_t vabal_s32 (int64x2_t a, int32x2_t b, int32x2_t c) + /// A32: VABAL.S32 Qd, Dn, Dm + /// A64: SABAL Vd.2D, Vn.2S, Vm.2S /// - public static Vector128 Add(Vector128 left, Vector128 right) => Add(left, right); + public static Vector128 AbsoluteDifferenceWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceWideningLowerAndAdd(addend, left, right); /// - /// int32x4_t vaddq_s32 (int32x4_t a, int32x4_t b) + /// int16x8_t vabal_s8 (int16x8_t a, int8x8_t b, int8x8_t c) + /// A32: VABAL.S8 Qd, Dn, Dm + /// A64: SABAL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 AbsoluteDifferenceWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceWideningLowerAndAdd(addend, left, right); + + /// + /// uint32x4_t vabal_u16 (uint32x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VABAL.U16 Qd, Dn, Dm + /// A64: UABAL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 AbsoluteDifferenceWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceWideningLowerAndAdd(addend, left, right); + + /// + /// uint64x2_t vabal_u32 (uint64x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VABAL.U32 Qd, Dn, Dm + /// A64: UABAL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 AbsoluteDifferenceWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceWideningLowerAndAdd(addend, left, right); + + /// + /// uint16x8_t vabdl_high_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VABDL.U8 Qd, Dn+1, Dm+1 + /// A64: UABDL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceWideningUpper(Vector128 left, Vector128 right) => AbsoluteDifferenceWideningUpper(left, right); + + /// + /// int32x4_t vabdl_high_s16 (int16x8_t a, int16x8_t b) + /// A32: VABDL.S16 Qd, Dn+1, Dm+1 + /// A64: SABDL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceWideningUpper(Vector128 left, Vector128 right) => AbsoluteDifferenceWideningUpper(left, right); + + /// + /// int64x2_t vabdl_high_s32 (int32x4_t a, int32x4_t b) + /// A32: VABDL.S32 Qd, Dn+1, Dm+1 + /// A64: SABDL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceWideningUpper(Vector128 left, Vector128 right) => AbsoluteDifferenceWideningUpper(left, right); + + /// + /// int16x8_t vabdl_high_s8 (int8x16_t a, int8x16_t b) + /// A32: VABDL.S8 Qd, Dn+1, Dm+1 + /// A64: SABDL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceWideningUpper(Vector128 left, Vector128 right) => AbsoluteDifferenceWideningUpper(left, right); + + /// + /// uint32x4_t vabdl_high_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VABDL.U16 Qd, Dn+1, Dm+1 + /// A64: UABDL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceWideningUpper(Vector128 left, Vector128 right) => AbsoluteDifferenceWideningUpper(left, right); + + /// + /// uint64x2_t vabdl_high_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VABDL.U32 Qd, Dn+1, Dm+1 + /// A64: UABDL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceWideningUpper(Vector128 left, Vector128 right) => AbsoluteDifferenceWideningUpper(left, right); + + /// + /// uint16x8_t vabal_high_u8 (uint16x8_t a, uint8x16_t b, uint8x16_t c) + /// A32: VABAL.U8 Qd, Dn+1, Dm+1 + /// A64: UABAL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceWideningUpperAndAdd(addend, left, right); + + /// + /// int32x4_t vabal_high_s16 (int32x4_t a, int16x8_t b, int16x8_t c) + /// A32: VABAL.S16 Qd, Dn+1, Dm+1 + /// A64: SABAL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceWideningUpperAndAdd(addend, left, right); + + /// + /// int64x2_t vabal_high_s32 (int64x2_t a, int32x4_t b, int32x4_t c) + /// A32: VABAL.S32 Qd, Dn+1, Dm+1 + /// A64: SABAL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceWideningUpperAndAdd(addend, left, right); + + /// + /// int16x8_t vabal_high_s8 (int16x8_t a, int8x16_t b, int8x16_t c) + /// A32: VABAL.S8 Qd, Dn+1, Dm+1 + /// A64: SABAL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceWideningUpperAndAdd(addend, left, right); + + /// + /// uint32x4_t vabal_high_u16 (uint32x4_t a, uint16x8_t b, uint16x8_t c) + /// A32: VABAL.U16 Qd, Dn+1, Dm+1 + /// A64: UABAL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceWideningUpperAndAdd(addend, left, right); + + /// + /// uint64x2_t vabal_high_u32 (uint64x2_t a, uint32x4_t b, uint32x4_t c) + /// A32: VABAL.U32 Qd, Dn+1, Dm+1 + /// A64: UABAL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceWideningUpperAndAdd(addend, left, right); + + /// + /// uint8x8_t vadd_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VADD.I8 Dd, Dn, Dm + /// A64: ADD Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Add(Vector64 left, Vector64 right) => Add(left, right); + + /// + /// int16x4_t vadd_s16 (int16x4_t a, int16x4_t b) + /// A32: VADD.I16 Dd, Dn, Dm + /// A64: ADD Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Add(Vector64 left, Vector64 right) => Add(left, right); + + /// + /// int32x2_t vadd_s32 (int32x2_t a, int32x2_t b) + /// A32: VADD.I32 Dd, Dn, Dm + /// A64: ADD Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Add(Vector64 left, Vector64 right) => Add(left, right); + + /// + /// int8x8_t vadd_s8 (int8x8_t a, int8x8_t b) + /// A32: VADD.I8 Dd, Dn, Dm + /// A64: ADD Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Add(Vector64 left, Vector64 right) => Add(left, right); + + /// + /// float32x2_t vadd_f32 (float32x2_t a, float32x2_t b) + /// A32: VADD.F32 Dd, Dn, Dm + /// A64: FADD Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Add(Vector64 left, Vector64 right) => Add(left, right); + + /// + /// uint16x4_t vadd_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VADD.I16 Dd, Dn, Dm + /// A64: ADD Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Add(Vector64 left, Vector64 right) => Add(left, right); + + /// + /// uint32x2_t vadd_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VADD.I32 Dd, Dn, Dm + /// A64: ADD Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Add(Vector64 left, Vector64 right) => Add(left, right); + + /// + /// uint8x16_t vaddq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VADD.I8 Qd, Qn, Qm + /// A64: ADD Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Add(Vector128 left, Vector128 right) => Add(left, right); + + /// + /// int16x8_t vaddq_s16 (int16x8_t a, int16x8_t b) + /// A32: VADD.I16 Qd, Qn, Qm + /// A64: ADD Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 Add(Vector128 left, Vector128 right) => Add(left, right); + + /// + /// int32x4_t vaddq_s32 (int32x4_t a, int32x4_t b) /// A32: VADD.I32 Qd, Qn, Qm /// A64: ADD Vd.4S, Vn.4S, Vm.4S /// @@ -2212,6 +2818,90 @@ internal Arm64() { } /// public static Vector128 Add(Vector128 left, Vector128 right) => Add(left, right); + /// + /// uint8x8_t vaddhn_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VADDHN.I16 Dd, Qn, Qm + /// A64: ADDHN Vd.8B, Vn.8H, Vm.8H + /// + public static Vector64 AddHighNarrowingLower(Vector128 left, Vector128 right) => AddHighNarrowingLower(left, right); + + /// + /// int16x4_t vaddhn_s32 (int32x4_t a, int32x4_t b) + /// A32: VADDHN.I32 Dd, Qn, Qm + /// A64: ADDHN Vd.4H, Vn.4S, Vm.4S + /// + public static Vector64 AddHighNarrowingLower(Vector128 left, Vector128 right) => AddHighNarrowingLower(left, right); + + /// + /// int32x2_t vaddhn_s64 (int64x2_t a, int64x2_t b) + /// A32: VADDHN.I64 Dd, Qn, Qm + /// A64: ADDHN Vd.2S, Vn.2D, Vm.2D + /// + public static Vector64 AddHighNarrowingLower(Vector128 left, Vector128 right) => AddHighNarrowingLower(left, right); + + /// + /// int8x8_t vaddhn_s16 (int16x8_t a, int16x8_t b) + /// A32: VADDHN.I16 Dd, Qn, Qm + /// A64: ADDHN Vd.8B, Vn.8H, Vm.8H + /// + public static Vector64 AddHighNarrowingLower(Vector128 left, Vector128 right) => AddHighNarrowingLower(left, right); + + /// + /// uint16x4_t vaddhn_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VADDHN.I32 Dd, Qn, Qm + /// A64: ADDHN Vd.4H, Vn.4S, Vm.4S + /// + public static Vector64 AddHighNarrowingLower(Vector128 left, Vector128 right) => AddHighNarrowingLower(left, right); + + /// + /// uint32x2_t vaddhn_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VADDHN.I64 Dd, Qn, Qm + /// A64: ADDHN Vd.2S, Vn.2D, Vm.2D + /// + public static Vector64 AddHighNarrowingLower(Vector128 left, Vector128 right) => AddHighNarrowingLower(left, right); + + /// + /// uint8x16_t vaddhn_high_u16 (uint8x8_t r, uint16x8_t a, uint16x8_t b) + /// A32: VADDHN.I16 Dd+1, Qn, Qm + /// A64: ADDHN2 Vd.16B, Vn.8H, Vm.8H + /// + public static Vector128 AddHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => AddHighNarrowingUpper(lower, left, right); + + /// + /// int16x8_t vaddhn_high_s32 (int16x4_t r, int32x4_t a, int32x4_t b) + /// A32: VADDHN.I32 Dd+1, Qn, Qm + /// A64: ADDHN2 Vd.8H, Vn.4S, Vm.4S + /// + public static Vector128 AddHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => AddHighNarrowingUpper(lower, left, right); + + /// + /// int32x4_t vaddhn_high_s64 (int32x2_t r, int64x2_t a, int64x2_t b) + /// A32: VADDHN.I64 Dd+1, Qn, Qm + /// A64: ADDHN2 Vd.4S, Vn.2D, Vm.2D + /// + public static Vector128 AddHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => AddHighNarrowingUpper(lower, left, right); + + /// + /// int8x16_t vaddhn_high_s16 (int8x8_t r, int16x8_t a, int16x8_t b) + /// A32: VADDHN.I16 Dd+1, Qn, Qm + /// A64: ADDHN2 Vd.16B, Vn.8H, Vm.8H + /// + public static Vector128 AddHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => AddHighNarrowingUpper(lower, left, right); + + /// + /// uint16x8_t vaddhn_high_u32 (uint16x4_t r, uint32x4_t a, uint32x4_t b) + /// A32: VADDHN.I32 Dd+1, Qn, Qm + /// A64: ADDHN2 Vd.8H, Vn.4S, Vm.4S + /// + public static Vector128 AddHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => AddHighNarrowingUpper(lower, left, right); + + /// + /// uint32x4_t vaddhn_high_u64 (uint32x2_t r, uint64x2_t a, uint64x2_t b) + /// A32: VADDHN.I64 Dd+1, Qn, Qm + /// A64: ADDHN2 Vd.4S, Vn.2D, Vm.2D + /// + public static Vector128 AddHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => AddHighNarrowingUpper(lower, left, right); + /// /// uint8x8_t vpadd_u8 (uint8x8_t a, uint8x8_t b) /// A32: VPADD.I8 Dd, Dn, Dm @@ -2262,2780 +2952,6742 @@ internal Arm64() { } public static Vector64 AddPairwise(Vector64 left, Vector64 right) => AddPairwise(left, right); /// - /// float64x1_t vadd_f64 (float64x1_t a, float64x1_t b) - /// A32: VADD.F64 Dd, Dn, Dm - /// A64: FADD Dd, Dn, Dm + /// uint16x4_t vpaddl_u8 (uint8x8_t a) + /// A32: VPADDL.U8 Dd, Dm + /// A64: UADDLP Vd.4H, Vn.8B /// - public static Vector64 AddScalar(Vector64 left, Vector64 right) => AddScalar(left, right); + public static Vector64 AddPairwiseWidening(Vector64 value) => AddPairwiseWidening(value); /// - /// int64x1_t vadd_s64 (int64x1_t a, int64x1_t b) - /// A32: VADD.I64 Dd, Dn, Dm - /// A64: ADD Dd, Dn, Dm + /// int32x2_t vpaddl_s16 (int16x4_t a) + /// A32: VPADDL.S16 Dd, Dm + /// A64: SADDLP Vd.2S, Vn.4H /// - public static Vector64 AddScalar(Vector64 left, Vector64 right) => AddScalar(left, right); + public static Vector64 AddPairwiseWidening(Vector64 value) => AddPairwiseWidening(value); /// - /// float32_t vadds_f32 (float32_t a, float32_t b) - /// A32: VADD.F32 Sd, Sn, Sm - /// A64: FADD Sd, Sn, Sm - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// int16x4_t vpaddl_s8 (int8x8_t a) + /// A32: VPADDL.S8 Dd, Dm + /// A64: SADDLP Vd.4H, Vn.8B /// - public static Vector64 AddScalar(Vector64 left, Vector64 right) => AddScalar(left, right); + public static Vector64 AddPairwiseWidening(Vector64 value) => AddPairwiseWidening(value); /// - /// uint64x1_t vadd_u64 (uint64x1_t a, uint64x1_t b) - /// A32: VADD.I64 Dd, Dn, Dm - /// A64: ADD Dd, Dn, Dm + /// uint32x2_t vpaddl_u16 (uint16x4_t a) + /// A32: VPADDL.U16 Dd, Dm + /// A64: UADDLP Vd.2S, Vn.4H /// - public static Vector64 AddScalar(Vector64 left, Vector64 right) => AddScalar(left, right); + public static Vector64 AddPairwiseWidening(Vector64 value) => AddPairwiseWidening(value); /// - /// uint8x8_t vand_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// uint16x8_t vpaddlq_u8 (uint8x16_t a) + /// A32: VPADDL.U8 Qd, Qm + /// A64: UADDLP Vd.8H, Vn.16B /// - public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + public static Vector128 AddPairwiseWidening(Vector128 value) => AddPairwiseWidening(value); /// - /// float64x1_t vand_f64 (float64x1_t a, float64x1_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// int32x4_t vpaddlq_s16 (int16x8_t a) + /// A32: VPADDL.S16 Qd, Qm + /// A64: SADDLP Vd.4S, Vn.8H /// - public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + public static Vector128 AddPairwiseWidening(Vector128 value) => AddPairwiseWidening(value); /// - /// int16x4_t vand_s16 (int16x4_t a, int16x4_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// int64x2_t vpaddlq_s32 (int32x4_t a) + /// A32: VPADDL.S32 Qd, Qm + /// A64: SADDLP Vd.2D, Vn.4S /// - public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + public static Vector128 AddPairwiseWidening(Vector128 value) => AddPairwiseWidening(value); /// - /// int32x2_t vand_s32 (int32x2_t a, int32x2_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// int16x8_t vpaddlq_s8 (int8x16_t a) + /// A32: VPADDL.S8 Qd, Qm + /// A64: SADDLP Vd.8H, Vn.16B /// - public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + public static Vector128 AddPairwiseWidening(Vector128 value) => AddPairwiseWidening(value); /// - /// int64x1_t vand_s64 (int64x1_t a, int64x1_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// uint32x4_t vpaddlq_u16 (uint16x8_t a) + /// A32: VPADDL.U16 Qd, Qm + /// A64: UADDLP Vd.4S, Vn.8H /// - public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + public static Vector128 AddPairwiseWidening(Vector128 value) => AddPairwiseWidening(value); /// - /// int8x8_t vand_s8 (int8x8_t a, int8x8_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// uint64x2_t vpaddlq_u32 (uint32x4_t a) + /// A32: VPADDL.U32 Qd, Qm + /// A64: UADDLP Vd.2D, Vn.4S /// - public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + public static Vector128 AddPairwiseWidening(Vector128 value) => AddPairwiseWidening(value); /// - /// float32x2_t vand_f32 (float32x2_t a, float32x2_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x4_t vpadal_u8 (uint16x4_t a, uint8x8_t b) + /// A32: VPADAL.U8 Dd, Dm + /// A64: UADALP Vd.4H, Vn.8B /// - public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + public static Vector64 AddPairwiseWideningAndAdd(Vector64 addend, Vector64 value) => AddPairwiseWideningAndAdd(addend, value); /// - /// uint16x4_t vand_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// int32x2_t vpadal_s16 (int32x2_t a, int16x4_t b) + /// A32: VPADAL.S16 Dd, Dm + /// A64: SADALP Vd.2S, Vn.4H /// - public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + public static Vector64 AddPairwiseWideningAndAdd(Vector64 addend, Vector64 value) => AddPairwiseWideningAndAdd(addend, value); /// - /// uint32x2_t vand_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// int16x4_t vpadal_s8 (int16x4_t a, int8x8_t b) + /// A32: VPADAL.S8 Dd, Dm + /// A64: SADALP Vd.4H, Vn.8B /// - public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + public static Vector64 AddPairwiseWideningAndAdd(Vector64 addend, Vector64 value) => AddPairwiseWideningAndAdd(addend, value); /// - /// uint64x1_t vand_u64 (uint64x1_t a, uint64x1_t b) - /// A32: VAND Dd, Dn, Dm - /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// uint32x2_t vpadal_u16 (uint32x2_t a, uint16x4_t b) + /// A32: VPADAL.U16 Dd, Dm + /// A64: UADALP Vd.2S, Vn.4H /// - public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + public static Vector64 AddPairwiseWideningAndAdd(Vector64 addend, Vector64 value) => AddPairwiseWideningAndAdd(addend, value); /// - /// uint8x16_t vandq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vpadalq_u8 (uint16x8_t a, uint8x16_t b) + /// A32: VPADAL.U8 Qd, Qm + /// A64: UADALP Vd.8H, Vn.16B /// - public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + public static Vector128 AddPairwiseWideningAndAdd(Vector128 addend, Vector128 value) => AddPairwiseWideningAndAdd(addend, value); /// - /// float64x2_t vandq_f64 (float64x2_t a, float64x2_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// int32x4_t vpadalq_s16 (int32x4_t a, int16x8_t b) + /// A32: VPADAL.S16 Qd, Qm + /// A64: SADALP Vd.4S, Vn.8H /// - public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + public static Vector128 AddPairwiseWideningAndAdd(Vector128 addend, Vector128 value) => AddPairwiseWideningAndAdd(addend, value); /// - /// int16x8_t vandq_s16 (int16x8_t a, int16x8_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// int64x2_t vpadalq_s32 (int64x2_t a, int32x4_t b) + /// A32: VPADAL.S32 Qd, Qm + /// A64: SADALP Vd.2D, Vn.4S /// - public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + public static Vector128 AddPairwiseWideningAndAdd(Vector128 addend, Vector128 value) => AddPairwiseWideningAndAdd(addend, value); /// - /// int32x4_t vandq_s32 (int32x4_t a, int32x4_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// int16x8_t vpadalq_s8 (int16x8_t a, int8x16_t b) + /// A32: VPADAL.S8 Qd, Qm + /// A64: SADALP Vd.8H, Vn.16B /// - public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + public static Vector128 AddPairwiseWideningAndAdd(Vector128 addend, Vector128 value) => AddPairwiseWideningAndAdd(addend, value); /// - /// int64x2_t vandq_s64 (int64x2_t a, int64x2_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// uint32x4_t vpadalq_u16 (uint32x4_t a, uint16x8_t b) + /// A32: VPADAL.U16 Qd, Qm + /// A64: UADALP Vd.4S, Vn.8H /// - public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + public static Vector128 AddPairwiseWideningAndAdd(Vector128 addend, Vector128 value) => AddPairwiseWideningAndAdd(addend, value); /// - /// int8x16_t vandq_s8 (int8x16_t a, int8x16_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// uint64x2_t vpadalq_u32 (uint64x2_t a, uint32x4_t b) + /// A32: VPADAL.U32 Qd, Qm + /// A64: UADALP Vd.2D, Vn.4S /// - public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + public static Vector128 AddPairwiseWideningAndAdd(Vector128 addend, Vector128 value) => AddPairwiseWideningAndAdd(addend, value); /// - /// float32x4_t vandq_f32 (float32x4_t a, float32x4_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// int64x1_t vpadal_s32 (int64x1_t a, int32x2_t b) + /// A32: VPADAL.S32 Dd, Dm + /// A64: SADALP Vd.1D, Vn.2S /// - public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + public static Vector64 AddPairwiseWideningAndAddScalar(Vector64 addend, Vector64 value) => AddPairwiseWideningAndAddScalar(addend, value); /// - /// uint16x8_t vandq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// uint64x1_t vpadal_u32 (uint64x1_t a, uint32x2_t b) + /// A32: VPADAL.U32 Dd, Dm + /// A64: UADALP Vd.1D, Vn.2S /// - public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + public static Vector64 AddPairwiseWideningAndAddScalar(Vector64 addend, Vector64 value) => AddPairwiseWideningAndAddScalar(addend, value); /// - /// uint32x4_t vandq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// int64x1_t vpaddl_s32 (int32x2_t a) + /// A32: VPADDL.S32 Dd, Dm + /// A64: SADDLP Dd, Vn.2S /// - public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + public static Vector64 AddPairwiseWideningScalar(Vector64 value) => AddPairwiseWideningScalar(value); /// - /// uint64x2_t vandq_u64 (uint64x2_t a, uint64x2_t b) - /// A32: VAND Qd, Qn, Qm - /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// uint64x1_t vpaddl_u32 (uint32x2_t a) + /// A32: VPADDL.U32 Dd, Dm + /// A64: UADDLP Dd, Vn.2S /// - public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + public static Vector64 AddPairwiseWideningScalar(Vector64 value) => AddPairwiseWideningScalar(value); /// - /// uint8x8_t vbic_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// uint8x8_t vraddhn_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VRADDHN.I16 Dd, Qn, Qm + /// A64: RADDHN Vd.8B, Vn.8H, Vm.8H /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + public static Vector64 AddRoundedHighNarrowingLower(Vector128 left, Vector128 right) => AddRoundedHighNarrowingLower(left, right); /// - /// float64x1_t vbic_f64 (float64x1_t a, float64x1_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// int16x4_t vraddhn_s32 (int32x4_t a, int32x4_t b) + /// A32: VRADDHN.I32 Dd, Qn, Qm + /// A64: RADDHN Vd.4H, Vn.4S, Vm.4S /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + public static Vector64 AddRoundedHighNarrowingLower(Vector128 left, Vector128 right) => AddRoundedHighNarrowingLower(left, right); /// - /// int16x4_t vbic_s16 (int16x4_t a, int16x4_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// int32x2_t vraddhn_s64 (int64x2_t a, int64x2_t b) + /// A32: VRADDHN.I64 Dd, Qn, Qm + /// A64: RADDHN Vd.2S, Vn.2D, Vm.2D /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + public static Vector64 AddRoundedHighNarrowingLower(Vector128 left, Vector128 right) => AddRoundedHighNarrowingLower(left, right); /// - /// int32x2_t vbic_s32 (int32x2_t a, int32x2_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// int8x8_t vraddhn_s16 (int16x8_t a, int16x8_t b) + /// A32: VRADDHN.I16 Dd, Qn, Qm + /// A64: RADDHN Vd.8B, Vn.8H, Vm.8H /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + public static Vector64 AddRoundedHighNarrowingLower(Vector128 left, Vector128 right) => AddRoundedHighNarrowingLower(left, right); /// - /// int64x1_t vbic_s64 (int64x1_t a, int64x1_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// uint16x4_t vraddhn_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VRADDHN.I32 Dd, Qn, Qm + /// A64: RADDHN Vd.4H, Vn.4S, Vm.4S /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + public static Vector64 AddRoundedHighNarrowingLower(Vector128 left, Vector128 right) => AddRoundedHighNarrowingLower(left, right); /// - /// int8x8_t vbic_s8 (int8x8_t a, int8x8_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// uint32x2_t vraddhn_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VRADDHN.I64 Dd, Qn, Qm + /// A64: RADDHN Vd.2S, Vn.2D, Vm.2D /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + public static Vector64 AddRoundedHighNarrowingLower(Vector128 left, Vector128 right) => AddRoundedHighNarrowingLower(left, right); /// - /// float32x2_t vbic_f32 (float32x2_t a, float32x2_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x16_t vraddhn_high_u16 (uint8x8_t r, uint16x8_t a, uint16x8_t b) + /// A32: VRADDHN.I16 Dd+1, Qn, Qm + /// A64: RADDHN2 Vd.16B, Vn.8H, Vm.8H /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + public static Vector128 AddRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => AddRoundedHighNarrowingUpper(lower, left, right); /// - /// uint16x4_t vbic_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// int16x8_t vraddhn_high_s32 (int16x4_t r, int32x4_t a, int32x4_t b) + /// A32: VRADDHN.I32 Dd+1, Qn, Qm + /// A64: RADDHN2 Vd.8H, Vn.4S, Vm.4S /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + public static Vector128 AddRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => AddRoundedHighNarrowingUpper(lower, left, right); /// - /// uint32x2_t vbic_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// int32x4_t vraddhn_high_s64 (int32x2_t r, int64x2_t a, int64x2_t b) + /// A32: VRADDHN.I64 Dd+1, Qn, Qm + /// A64: RADDHN2 Vd.4S, Vn.2D, Vm.2D /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + public static Vector128 AddRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => AddRoundedHighNarrowingUpper(lower, left, right); /// - /// uint64x1_t vbic_u64 (uint64x1_t a, uint64x1_t b) - /// A32: VBIC Dd, Dn, Dm - /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// int8x16_t vraddhn_high_s16 (int8x8_t r, int16x8_t a, int16x8_t b) + /// A32: VRADDHN.I16 Dd+1, Qn, Qm + /// A64: RADDHN2 Vd.16B, Vn.8H, Vm.8H /// - public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + public static Vector128 AddRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => AddRoundedHighNarrowingUpper(lower, left, right); /// - /// uint8x16_t vbicq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vraddhn_high_u32 (uint16x4_t r, uint32x4_t a, uint32x4_t b) + /// A32: VRADDHN.I32 Dd+1, Qn, Qm + /// A64: RADDHN2 Vd.8H, Vn.4S, Vm.4S /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + public static Vector128 AddRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => AddRoundedHighNarrowingUpper(lower, left, right); /// - /// float64x2_t vbicq_f64 (float64x2_t a, float64x2_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint32x4_t vraddhn_high_u64 (uint32x2_t r, uint64x2_t a, uint64x2_t b) + /// A32: VRADDHN.I64 Dd+1, Qn, Qm + /// A64: RADDHN2 Vd.4S, Vn.2D, Vm.2D /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + public static Vector128 AddRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => AddRoundedHighNarrowingUpper(lower, left, right); /// - /// int16x8_t vbicq_s16 (int16x8_t a, int16x8_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// uint8x8_t vqadd_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VQADD.U8 Dd, Dn, Dm + /// A64: UQADD Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + public static Vector64 AddSaturate(Vector64 left, Vector64 right) => AddSaturate(left, right); /// - /// int32x4_t vbicq_s32 (int32x4_t a, int32x4_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// int16x4_t vqadd_s16 (int16x4_t a, int16x4_t b) + /// A32: VQADD.S16 Dd, Dn, Dm + /// A64: SQADD Vd.4H, Vn.4H, Vm.4H /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + public static Vector64 AddSaturate(Vector64 left, Vector64 right) => AddSaturate(left, right); /// - /// int64x2_t vbicq_s64 (int64x2_t a, int64x2_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// int32x2_t vqadd_s32 (int32x2_t a, int32x2_t b) + /// A32: VQADD.S32 Dd, Dn, Dm + /// A64: SQADD Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + public static Vector64 AddSaturate(Vector64 left, Vector64 right) => AddSaturate(left, right); /// - /// int8x16_t vbicq_s8 (int8x16_t a, int8x16_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// int8x8_t vqadd_s8 (int8x8_t a, int8x8_t b) + /// A32: VQADD.S8 Dd, Dn, Dm + /// A64: SQADD Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + public static Vector64 AddSaturate(Vector64 left, Vector64 right) => AddSaturate(left, right); /// - /// float32x4_t vbicq_f32 (float32x4_t a, float32x4_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x4_t vqadd_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VQADD.U16 Dd, Dn, Dm + /// A64: UQADD Vd.4H, Vn.4H, Vm.4H /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + public static Vector64 AddSaturate(Vector64 left, Vector64 right) => AddSaturate(left, right); /// - /// uint16x8_t vbicq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// uint32x2_t vqadd_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VQADD.U32 Dd, Dn, Dm + /// A64: UQADD Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + public static Vector64 AddSaturate(Vector64 left, Vector64 right) => AddSaturate(left, right); /// - /// uint32x4_t vbicq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// uint8x16_t vqaddq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VQADD.U8 Qd, Qn, Qm + /// A64: UQADD Vd.16B, Vn.16B, Vm.16B /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + public static Vector128 AddSaturate(Vector128 left, Vector128 right) => AddSaturate(left, right); /// - /// uint64x2_t vbicq_u64 (uint64x2_t a, uint64x2_t b) - /// A32: VBIC Qd, Qn, Qm - /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// int16x8_t vqaddq_s16 (int16x8_t a, int16x8_t b) + /// A32: VQADD.S16 Qd, Qn, Qm + /// A64: SQADD Vd.8H, Vn.8H, Vm.8H /// - public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + public static Vector128 AddSaturate(Vector128 left, Vector128 right) => AddSaturate(left, right); /// - /// uint8x8_t vbsl_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// int32x4_t vqaddq_s32 (int32x4_t a, int32x4_t b) + /// A32: VQADD.S32 Qd, Qn, Qm + /// A64: SQADD Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + public static Vector128 AddSaturate(Vector128 left, Vector128 right) => AddSaturate(left, right); /// - /// float64x1_t vbsl_f64 (uint64x1_t a, float64x1_t b, float64x1_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// int64x2_t vqaddq_s64 (int64x2_t a, int64x2_t b) + /// A32: VQADD.S64 Qd, Qn, Qm + /// A64: SQADD Vd.2D, Vn.2D, Vm.2D /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + public static Vector128 AddSaturate(Vector128 left, Vector128 right) => AddSaturate(left, right); /// - /// int16x4_t vbsl_s16 (uint16x4_t a, int16x4_t b, int16x4_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// int8x16_t vqaddq_s8 (int8x16_t a, int8x16_t b) + /// A32: VQADD.S8 Qd, Qn, Qm + /// A64: SQADD Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + public static Vector128 AddSaturate(Vector128 left, Vector128 right) => AddSaturate(left, right); /// - /// int32x2_t vbsl_s32 (uint32x2_t a, int32x2_t b, int32x2_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// uint16x8_t vqaddq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VQADD.U16 Qd, Qn, Qm + /// A64: UQADD Vd.8H, Vn.8H, Vm.8H /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + public static Vector128 AddSaturate(Vector128 left, Vector128 right) => AddSaturate(left, right); /// - /// int64x1_t vbsl_s64 (uint64x1_t a, int64x1_t b, int64x1_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// uint32x4_t vqaddq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VQADD.U32 Qd, Qn, Qm + /// A64: UQADD Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + public static Vector128 AddSaturate(Vector128 left, Vector128 right) => AddSaturate(left, right); /// - /// int8x8_t vbsl_s8 (uint8x8_t a, int8x8_t b, int8x8_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// uint64x2_t vqaddq_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VQADD.U64 Qd, Qn, Qm + /// A64: UQADD Vd.2D, Vn.2D, Vm.2D /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + public static Vector128 AddSaturate(Vector128 left, Vector128 right) => AddSaturate(left, right); /// - /// float32x2_t vbsl_f32 (uint32x2_t a, float32x2_t b, float32x2_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// int64x1_t vqadd_s64 (int64x1_t a, int64x1_t b) + /// A32: VQADD.S64 Dd, Dn, Dm + /// A64: SQADD Dd, Dn, Dm /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) => AddSaturateScalar(left, right); /// - /// uint16x4_t vbsl_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// uint64x1_t vqadd_u64 (uint64x1_t a, uint64x1_t b) + /// A32: VQADD.U64 Dd, Dn, Dm + /// A64: UQADD Dd, Dn, Dm /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + public static Vector64 AddSaturateScalar(Vector64 left, Vector64 right) => AddSaturateScalar(left, right); /// - /// uint32x2_t vbsl_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// float64x1_t vadd_f64 (float64x1_t a, float64x1_t b) + /// A32: VADD.F64 Dd, Dn, Dm + /// A64: FADD Dd, Dn, Dm /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + public static Vector64 AddScalar(Vector64 left, Vector64 right) => AddScalar(left, right); /// - /// uint64x1_t vbsl_u64 (uint64x1_t a, uint64x1_t b, uint64x1_t c) - /// A32: VBSL Dd, Dn, Dm - /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// int64x1_t vadd_s64 (int64x1_t a, int64x1_t b) + /// A32: VADD.I64 Dd, Dn, Dm + /// A64: ADD Dd, Dn, Dm /// - public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + public static Vector64 AddScalar(Vector64 left, Vector64 right) => AddScalar(left, right); /// - /// uint8x16_t vbslq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// float32_t vadds_f32 (float32_t a, float32_t b) + /// A32: VADD.F32 Sd, Sn, Sm + /// A64: FADD Sd, Sn, Sm + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + public static Vector64 AddScalar(Vector64 left, Vector64 right) => AddScalar(left, right); /// - /// float64x2_t vbslq_f64 (uint64x2_t a, float64x2_t b, float64x2_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// uint64x1_t vadd_u64 (uint64x1_t a, uint64x1_t b) + /// A32: VADD.I64 Dd, Dn, Dm + /// A64: ADD Dd, Dn, Dm /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + public static Vector64 AddScalar(Vector64 left, Vector64 right) => AddScalar(left, right); /// - /// int16x8_t vbslq_s16 (uint16x8_t a, int16x8_t b, int16x8_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vaddl_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VADDL.U8 Qd, Dn, Dm + /// A64: UADDL Vd.8H, Vn.8B, Vm.8B /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + public static Vector128 AddWideningLower(Vector64 left, Vector64 right) => AddWideningLower(left, right); /// - /// int32x4_t vbslq_s32 (uint32x4_t a, int32x4_t b, int32x4_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// int32x4_t vaddl_s16 (int16x4_t a, int16x4_t b) + /// A32: VADDL.S16 Qd, Dn, Dm + /// A64: SADDL Vd.4S, Vn.4H, Vm.4H /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + public static Vector128 AddWideningLower(Vector64 left, Vector64 right) => AddWideningLower(left, right); /// - /// int64x2_t vbslq_s64 (uint64x2_t a, int64x2_t b, int64x2_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// int64x2_t vaddl_s32 (int32x2_t a, int32x2_t b) + /// A32: VADDL.S32 Qd, Dn, Dm + /// A64: SADDL Vd.2D, Vn.2S, Vm.2S /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + public static Vector128 AddWideningLower(Vector64 left, Vector64 right) => AddWideningLower(left, right); /// - /// int8x16_t vbslq_s8 (uint8x16_t a, int8x16_t b, int8x16_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// int16x8_t vaddl_s8 (int8x8_t a, int8x8_t b) + /// A32: VADDL.S8 Qd, Dn, Dm + /// A64: SADDL Vd.8H, Vn.8B, Vm.8B /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + public static Vector128 AddWideningLower(Vector64 left, Vector64 right) => AddWideningLower(left, right); /// - /// float32x4_t vbslq_f32 (uint32x4_t a, float32x4_t b, float32x4_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// uint32x4_t vaddl_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VADDL.U16 Qd, Dn, Dm + /// A64: UADDL Vd.4S, Vn.4H, Vm.4H /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + public static Vector128 AddWideningLower(Vector64 left, Vector64 right) => AddWideningLower(left, right); /// - /// uint16x8_t vbslq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// uint64x2_t vaddl_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VADDL.U32 Qd, Dn, Dm + /// A64: UADDL Vd.2D, Vn.2S, Vm.2S /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + public static Vector128 AddWideningLower(Vector64 left, Vector64 right) => AddWideningLower(left, right); /// - /// uint32x4_t vbslq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// int16x8_t vaddw_s8 (int16x8_t a, int8x8_t b) + /// A32: VADDW.S8 Qd, Qn, Dm + /// A64: SADDW Vd.8H, Vn.8H, Vm.8B /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + public static Vector128 AddWideningLower(Vector128 left, Vector64 right) => AddWideningLower(left, right); /// - /// uint64x2_t vbslq_u64 (uint64x2_t a, uint64x2_t b, uint64x2_t c) - /// A32: VBSL Qd, Qn, Qm - /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// int32x4_t vaddw_s16 (int32x4_t a, int16x4_t b) + /// A32: VADDW.S16 Qd, Qn, Dm + /// A64: SADDW Vd.4S, Vn.4S, Vm.4H /// - public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + public static Vector128 AddWideningLower(Vector128 left, Vector64 right) => AddWideningLower(left, right); /// - /// uint8x8_t vceq_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VCEQ.I8 Dd, Dn, Dm - /// A64: CMEQ Vd.8B, Vn.8B, Vm.8B + /// int64x2_t vaddw_s32 (int64x2_t a, int32x2_t b) + /// A32: VADDW.S32 Qd, Qn, Dm + /// A64: SADDW Vd.2D, Vn.2D, Vm.2S /// - public static Vector64 CompareEqual(Vector64 left, Vector64 right) => CompareEqual(left, right); + public static Vector128 AddWideningLower(Vector128 left, Vector64 right) => AddWideningLower(left, right); /// - /// uint16x4_t vceq_s16 (int16x4_t a, int16x4_t b) - /// A32: VCEQ.I16 Dd, Dn, Dm - /// A64: CMEQ Vd.4H, Vn.4H, Vm.4H + /// uint16x8_t vaddw_u8 (uint16x8_t a, uint8x8_t b) + /// A32: VADDW.U8 Qd, Qn, Dm + /// A64: UADDW Vd.8H, Vn.8H, Vm.8B /// - public static Vector64 CompareEqual(Vector64 left, Vector64 right) => CompareEqual(left, right); + public static Vector128 AddWideningLower(Vector128 left, Vector64 right) => AddWideningLower(left, right); /// - /// uint32x2_t vceq_s32 (int32x2_t a, int32x2_t b) - /// A32: VCEQ.I32 Dd, Dn, Dm - /// A64: CMEQ Vd.2S, Vn.2S, Vm.2S + /// uint32x4_t vaddw_u16 (uint32x4_t a, uint16x4_t b) + /// A32: VADDW.U16 Qd, Qn, Dm + /// A64: UADDW Vd.4S, Vn.4S, Vm.4H /// - public static Vector64 CompareEqual(Vector64 left, Vector64 right) => CompareEqual(left, right); + public static Vector128 AddWideningLower(Vector128 left, Vector64 right) => AddWideningLower(left, right); /// - /// uint8x8_t vceq_s8 (int8x8_t a, int8x8_t b) - /// A32: VCEQ.I8 Dd, Dn, Dm - /// A64: CMEQ Vd.8B, Vn.8B, Vm.8B + /// uint64x2_t vaddw_u32 (uint64x2_t a, uint32x2_t b) + /// A32: VADDW.U32 Qd, Qn, Dm + /// A64: UADDW Vd.2D, Vn.2D, Vm.2S /// - public static Vector64 CompareEqual(Vector64 left, Vector64 right) => CompareEqual(left, right); + public static Vector128 AddWideningLower(Vector128 left, Vector64 right) => AddWideningLower(left, right); /// - /// uint32x2_t vceq_f32 (float32x2_t a, float32x2_t b) - /// A32: VCEQ.F32 Dd, Dn, Dm - /// A64: FCMEQ Vd.2S, Vn.2S, Vm.2S + /// uint16x8_t vaddl_high_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VADDL.U8 Qd, Dn+1, Dm+1 + /// A64: UADDL2 Vd.8H, Vn.16B, Vm.16B /// - public static Vector64 CompareEqual(Vector64 left, Vector64 right) => CompareEqual(left, right); + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) => AddWideningUpper(left, right); /// - /// uint16x4_t vceq_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VCEQ.I16 Dd, Dn, Dm - /// A64: CMEQ Vd.4H, Vn.4H, Vm.4H + /// int32x4_t vaddl_high_s16 (int16x8_t a, int16x8_t b) + /// A32: VADDL.S16 Qd, Dn+1, Dm+1 + /// A64: SADDL2 Vd.4S, Vn.8H, Vm.8H /// - public static Vector64 CompareEqual(Vector64 left, Vector64 right) => CompareEqual(left, right); + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) => AddWideningUpper(left, right); /// - /// uint32x2_t vceq_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VCEQ.I32 Dd, Dn, Dm - /// A64: CMEQ Vd.2S, Vn.2S, Vm.2S + /// int16x8_t vaddw_high_s8 (int16x8_t a, int8x16_t b) + /// A32: VADDW.S8 Qd, Qn, Dm+1 + /// A64: SADDW2 Vd.8H, Vn.8H, Vm.16B /// - public static Vector64 CompareEqual(Vector64 left, Vector64 right) => CompareEqual(left, right); + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) => AddWideningUpper(left, right); /// - /// uint8x16_t vceqq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VCEQ.I8 Qd, Qn, Qm - /// A64: CMEQ Vd.16B, Vn.16B, Vm.16B + /// int32x4_t vaddw_high_s16 (int32x4_t a, int16x8_t b) + /// A32: VADDW.S16 Qd, Qn, Dm+1 + /// A64: SADDW2 Vd.4S, Vn.4S, Vm.8H /// - public static Vector128 CompareEqual(Vector128 left, Vector128 right) => CompareEqual(left, right); + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) => AddWideningUpper(left, right); /// - /// uint16x8_t vceqq_s16 (int16x8_t a, int16x8_t b) - /// A32: VCEQ.I16 Qd, Qn, Qm - /// A64: CMEQ Vd.8H, Vn.8H, Vm.8H + /// int64x2_t vaddl_high_s32 (int32x4_t a, int32x4_t b) + /// A32: VADDL.S32 Qd, Dn+1, Dm+1 + /// A64: SADDL2 Vd.2D, Vn.4S, Vm.4S /// - public static Vector128 CompareEqual(Vector128 left, Vector128 right) => CompareEqual(left, right); + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) => AddWideningUpper(left, right); /// - /// uint32x4_t vceqq_s32 (int32x4_t a, int32x4_t b) - /// A32: VCEQ.I32 Qd, Qn, Qm - /// A64: CMEQ Vd.4S, Vn.4S, Vm.4S + /// int64x2_t vaddw_high_s32 (int64x2_t a, int32x4_t b) + /// A32: VADDW.S32 Qd, Qn, Dm+1 + /// A64: SADDW2 Vd.2D, Vn.2D, Vm.4S + /// + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) => AddWideningUpper(left, right); + + /// + /// int16x8_t vaddl_high_s8 (int8x16_t a, int8x16_t b) + /// A32: VADDL.S8 Qd, Dn+1, Dm+1 + /// A64: SADDL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) => AddWideningUpper(left, right); + + /// + /// uint16x8_t vaddw_high_u8 (uint16x8_t a, uint8x16_t b) + /// A32: VADDW.U8 Qd, Qn, Dm+1 + /// A64: UADDW2 Vd.8H, Vn.8H, Vm.16B + /// + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) => AddWideningUpper(left, right); + + /// + /// uint32x4_t vaddl_high_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VADDL.U16 Qd, Dn+1, Dm+1 + /// A64: UADDL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) => AddWideningUpper(left, right); + + /// + /// uint32x4_t vaddw_high_u16 (uint32x4_t a, uint16x8_t b) + /// A32: VADDW.U16 Qd, Qn, Dm+1 + /// A64: UADDW2 Vd.4S, Vn.4S, Vm.8H + /// + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) => AddWideningUpper(left, right); + + /// + /// uint64x2_t vaddl_high_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VADDL.U32 Qd, Dn+1, Dm+1 + /// A64: UADDL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) => AddWideningUpper(left, right); + + /// + /// uint64x2_t vaddw_high_u32 (uint64x2_t a, uint32x4_t b) + /// A32: VADDW.U32 Qd, Qn, Dm+1 + /// A64: UADDW2 Vd.2D, Vn.2D, Vm.4S + /// + public static Vector128 AddWideningUpper(Vector128 left, Vector128 right) => AddWideningUpper(left, right); + + /// + /// uint8x8_t vand_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + + /// + /// float64x1_t vand_f64 (float64x1_t a, float64x1_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + + /// + /// int16x4_t vand_s16 (int16x4_t a, int16x4_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + + /// + /// int32x2_t vand_s32 (int32x2_t a, int32x2_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + + /// + /// int64x1_t vand_s64 (int64x1_t a, int64x1_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + + /// + /// int8x8_t vand_s8 (int8x8_t a, int8x8_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + + /// + /// float32x2_t vand_f32 (float32x2_t a, float32x2_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + + /// + /// uint16x4_t vand_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + + /// + /// uint32x2_t vand_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + + /// + /// uint64x1_t vand_u64 (uint64x1_t a, uint64x1_t b) + /// A32: VAND Dd, Dn, Dm + /// A64: AND Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 And(Vector64 left, Vector64 right) => And(left, right); + + /// + /// uint8x16_t vandq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + + /// + /// float64x2_t vandq_f64 (float64x2_t a, float64x2_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + + /// + /// int16x8_t vandq_s16 (int16x8_t a, int16x8_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + + /// + /// int32x4_t vandq_s32 (int32x4_t a, int32x4_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + + /// + /// int64x2_t vandq_s64 (int64x2_t a, int64x2_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + + /// + /// int8x16_t vandq_s8 (int8x16_t a, int8x16_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + + /// + /// float32x4_t vandq_f32 (float32x4_t a, float32x4_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + + /// + /// uint16x8_t vandq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + + /// + /// uint32x4_t vandq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + + /// + /// uint64x2_t vandq_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VAND Qd, Qn, Qm + /// A64: AND Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 And(Vector128 left, Vector128 right) => And(left, right); + + /// + /// uint8x8_t vbic_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + + /// + /// float64x1_t vbic_f64 (float64x1_t a, float64x1_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + + /// + /// int16x4_t vbic_s16 (int16x4_t a, int16x4_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + + /// + /// int32x2_t vbic_s32 (int32x2_t a, int32x2_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + + /// + /// int64x1_t vbic_s64 (int64x1_t a, int64x1_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + + /// + /// int8x8_t vbic_s8 (int8x8_t a, int8x8_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + + /// + /// float32x2_t vbic_f32 (float32x2_t a, float32x2_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + + /// + /// uint16x4_t vbic_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + + /// + /// uint32x2_t vbic_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + + /// + /// uint64x1_t vbic_u64 (uint64x1_t a, uint64x1_t b) + /// A32: VBIC Dd, Dn, Dm + /// A64: BIC Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseClear(Vector64 value, Vector64 mask) => BitwiseClear(value, mask); + + /// + /// uint8x16_t vbicq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + + /// + /// float64x2_t vbicq_f64 (float64x2_t a, float64x2_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + + /// + /// int16x8_t vbicq_s16 (int16x8_t a, int16x8_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + + /// + /// int32x4_t vbicq_s32 (int32x4_t a, int32x4_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + + /// + /// int64x2_t vbicq_s64 (int64x2_t a, int64x2_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + + /// + /// int8x16_t vbicq_s8 (int8x16_t a, int8x16_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + + /// + /// float32x4_t vbicq_f32 (float32x4_t a, float32x4_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + + /// + /// uint16x8_t vbicq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + + /// + /// uint32x4_t vbicq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + + /// + /// uint64x2_t vbicq_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VBIC Qd, Qn, Qm + /// A64: BIC Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseClear(Vector128 value, Vector128 mask) => BitwiseClear(value, mask); + + /// + /// uint8x8_t vbsl_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + + /// + /// float64x1_t vbsl_f64 (uint64x1_t a, float64x1_t b, float64x1_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + + /// + /// int16x4_t vbsl_s16 (uint16x4_t a, int16x4_t b, int16x4_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + + /// + /// int32x2_t vbsl_s32 (uint32x2_t a, int32x2_t b, int32x2_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + + /// + /// int64x1_t vbsl_s64 (uint64x1_t a, int64x1_t b, int64x1_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + + /// + /// int8x8_t vbsl_s8 (uint8x8_t a, int8x8_t b, int8x8_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + + /// + /// float32x2_t vbsl_f32 (uint32x2_t a, float32x2_t b, float32x2_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + + /// + /// uint16x4_t vbsl_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + + /// + /// uint32x2_t vbsl_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + + /// + /// uint64x1_t vbsl_u64 (uint64x1_t a, uint64x1_t b, uint64x1_t c) + /// A32: VBSL Dd, Dn, Dm + /// A64: BSL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 BitwiseSelect(Vector64 select, Vector64 left, Vector64 right) => BitwiseSelect(select, left, right); + + /// + /// uint8x16_t vbslq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + + /// + /// float64x2_t vbslq_f64 (uint64x2_t a, float64x2_t b, float64x2_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + + /// + /// int16x8_t vbslq_s16 (uint16x8_t a, int16x8_t b, int16x8_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + + /// + /// int32x4_t vbslq_s32 (uint32x4_t a, int32x4_t b, int32x4_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + + /// + /// int64x2_t vbslq_s64 (uint64x2_t a, int64x2_t b, int64x2_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + + /// + /// int8x16_t vbslq_s8 (uint8x16_t a, int8x16_t b, int8x16_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + + /// + /// float32x4_t vbslq_f32 (uint32x4_t a, float32x4_t b, float32x4_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + + /// + /// uint16x8_t vbslq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + + /// + /// uint32x4_t vbslq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + + /// + /// uint64x2_t vbslq_u64 (uint64x2_t a, uint64x2_t b, uint64x2_t c) + /// A32: VBSL Qd, Qn, Qm + /// A64: BSL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 BitwiseSelect(Vector128 select, Vector128 left, Vector128 right) => BitwiseSelect(select, left, right); + + /// + /// uint8x8_t vceq_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VCEQ.I8 Dd, Dn, Dm + /// A64: CMEQ Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareEqual(Vector64 left, Vector64 right) => CompareEqual(left, right); + + /// + /// uint16x4_t vceq_s16 (int16x4_t a, int16x4_t b) + /// A32: VCEQ.I16 Dd, Dn, Dm + /// A64: CMEQ Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareEqual(Vector64 left, Vector64 right) => CompareEqual(left, right); + + /// + /// uint32x2_t vceq_s32 (int32x2_t a, int32x2_t b) + /// A32: VCEQ.I32 Dd, Dn, Dm + /// A64: CMEQ Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareEqual(Vector64 left, Vector64 right) => CompareEqual(left, right); + + /// + /// uint8x8_t vceq_s8 (int8x8_t a, int8x8_t b) + /// A32: VCEQ.I8 Dd, Dn, Dm + /// A64: CMEQ Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareEqual(Vector64 left, Vector64 right) => CompareEqual(left, right); + + /// + /// uint32x2_t vceq_f32 (float32x2_t a, float32x2_t b) + /// A32: VCEQ.F32 Dd, Dn, Dm + /// A64: FCMEQ Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareEqual(Vector64 left, Vector64 right) => CompareEqual(left, right); + + /// + /// uint16x4_t vceq_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VCEQ.I16 Dd, Dn, Dm + /// A64: CMEQ Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareEqual(Vector64 left, Vector64 right) => CompareEqual(left, right); + + /// + /// uint32x2_t vceq_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VCEQ.I32 Dd, Dn, Dm + /// A64: CMEQ Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareEqual(Vector64 left, Vector64 right) => CompareEqual(left, right); + + /// + /// uint8x16_t vceqq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VCEQ.I8 Qd, Qn, Qm + /// A64: CMEQ Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareEqual(Vector128 left, Vector128 right) => CompareEqual(left, right); + + /// + /// uint16x8_t vceqq_s16 (int16x8_t a, int16x8_t b) + /// A32: VCEQ.I16 Qd, Qn, Qm + /// A64: CMEQ Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareEqual(Vector128 left, Vector128 right) => CompareEqual(left, right); + + /// + /// uint32x4_t vceqq_s32 (int32x4_t a, int32x4_t b) + /// A32: VCEQ.I32 Qd, Qn, Qm + /// A64: CMEQ Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareEqual(Vector128 left, Vector128 right) => CompareEqual(left, right); + + /// + /// uint8x16_t vceqq_s8 (int8x16_t a, int8x16_t b) + /// A32: VCEQ.I8 Qd, Qn, Qm + /// A64: CMEQ Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareEqual(Vector128 left, Vector128 right) => CompareEqual(left, right); + + /// + /// uint32x4_t vceqq_f32 (float32x4_t a, float32x4_t b) + /// A32: VCEQ.F32 Qd, Qn, Qm + /// A64: FCMEQ Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareEqual(Vector128 left, Vector128 right) => CompareEqual(left, right); + + /// + /// uint16x8_t vceqq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VCEQ.I16 Qd, Qn, Qm + /// A64: CMEQ Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareEqual(Vector128 left, Vector128 right) => CompareEqual(left, right); + + /// + /// uint32x4_t vceqq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VCEQ.I32 Qd, Qn, Qm + /// A64: CMEQ Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareEqual(Vector128 left, Vector128 right) => CompareEqual(left, right); + + /// + /// uint8x8_t vcgt_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VCGT.U8 Dd, Dn, Dm + /// A64: CMHI Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) => CompareGreaterThan(left, right); + + /// + /// uint16x4_t vcgt_s16 (int16x4_t a, int16x4_t b) + /// A32: VCGT.S16 Dd, Dn, Dm + /// A64: CMGT Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) => CompareGreaterThan(left, right); + + /// + /// uint32x2_t vcgt_s32 (int32x2_t a, int32x2_t b) + /// A32: VCGT.S32 Dd, Dn, Dm + /// A64: CMGT Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) => CompareGreaterThan(left, right); + + /// + /// uint8x8_t vcgt_s8 (int8x8_t a, int8x8_t b) + /// A32: VCGT.S8 Dd, Dn, Dm + /// A64: CMGT Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) => CompareGreaterThan(left, right); + + /// + /// uint32x2_t vcgt_f32 (float32x2_t a, float32x2_t b) + /// A32: VCGT.F32 Dd, Dn, Dm + /// A64: FCMGT Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) => CompareGreaterThan(left, right); + + /// + /// uint16x4_t vcgt_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VCGT.U16 Dd, Dn, Dm + /// A64: CMHI Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) => CompareGreaterThan(left, right); + + /// + /// uint32x2_t vcgt_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VCGT.U32 Dd, Dn, Dm + /// A64: CMHI Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) => CompareGreaterThan(left, right); + + /// + /// uint8x16_t vcgtq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VCGT.U8 Qd, Qn, Qm + /// A64: CMHI Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); + + /// + /// uint16x8_t vcgtq_s16 (int16x8_t a, int16x8_t b) + /// A32: VCGT.S16 Qd, Qn, Qm + /// A64: CMGT Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); + + /// + /// uint32x4_t vcgtq_s32 (int32x4_t a, int32x4_t b) + /// A32: VCGT.S32 Qd, Qn, Qm + /// A64: CMGT Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); + + /// + /// uint8x16_t vcgtq_s8 (int8x16_t a, int8x16_t b) + /// A32: VCGT.S8 Qd, Qn, Qm + /// A64: CMGT Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); + + /// + /// uint32x4_t vcgtq_f32 (float32x4_t a, float32x4_t b) + /// A32: VCGT.F32 Qd, Qn, Qm + /// A64: FCMGT Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); + + /// + /// uint16x8_t vcgtq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VCGT.U16 Qd, Qn, Qm + /// A64: CMHI Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); + + /// + /// uint32x4_t vcgtq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VCGT.U32 Qd, Qn, Qm + /// A64: CMHI Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); + + /// + /// uint8x8_t vcge_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VCGE.U8 Dd, Dn, Dm + /// A64: CMHS Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) => CompareGreaterThanOrEqual(left, right); + + /// + /// uint16x4_t vcge_s16 (int16x4_t a, int16x4_t b) + /// A32: VCGE.S16 Dd, Dn, Dm + /// A64: CMGE Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) => CompareGreaterThanOrEqual(left, right); + + /// + /// uint32x2_t vcge_s32 (int32x2_t a, int32x2_t b) + /// A32: VCGE.S32 Dd, Dn, Dm + /// A64: CMGE Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) => CompareGreaterThanOrEqual(left, right); + + /// + /// uint8x8_t vcge_s8 (int8x8_t a, int8x8_t b) + /// A32: VCGE.S8 Dd, Dn, Dm + /// A64: CMGE Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) => CompareGreaterThanOrEqual(left, right); + + /// + /// uint32x2_t vcge_f32 (float32x2_t a, float32x2_t b) + /// A32: VCGE.F32 Dd, Dn, Dm + /// A64: FCMGE Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) => CompareGreaterThanOrEqual(left, right); + + /// + /// uint16x4_t vcge_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VCGE.U16 Dd, Dn, Dm + /// A64: CMHS Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) => CompareGreaterThanOrEqual(left, right); + + /// + /// uint32x2_t vcge_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VCGE.U32 Dd, Dn, Dm + /// A64: CMHS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) => CompareGreaterThanOrEqual(left, right); + + /// + /// uint8x16_t vcgeq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VCGE.U8 Qd, Qn, Qm + /// A64: CMHS Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); + + /// + /// uint16x8_t vcgeq_s16 (int16x8_t a, int16x8_t b) + /// A32: VCGE.S16 Qd, Qn, Qm + /// A64: CMGE Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); + + /// + /// uint32x4_t vcgeq_s32 (int32x4_t a, int32x4_t b) + /// A32: VCGE.S32 Qd, Qn, Qm + /// A64: CMGE Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); + + /// + /// uint8x16_t vcgeq_s8 (int8x16_t a, int8x16_t b) + /// A32: VCGE.S8 Qd, Qn, Qm + /// A64: CMGE Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); + + /// + /// uint32x4_t vcgeq_f32 (float32x4_t a, float32x4_t b) + /// A32: VCGE.F32 Qd, Qn, Qm + /// A64: FCMGE Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); + + /// + /// uint16x8_t vcgeq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VCGE.U16 Qd, Qn, Qm + /// A64: CMHS Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); + + /// + /// uint32x4_t vcgeq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VCGE.U32 Qd, Qn, Qm + /// A64: CMHS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); + + /// + /// uint8x8_t vclt_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VCLT.U8 Dd, Dn, Dm + /// A64: CMHI Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareLessThan(Vector64 left, Vector64 right) => CompareLessThan(left, right); + + /// + /// uint16x4_t vclt_s16 (int16x4_t a, int16x4_t b) + /// A32: VCLT.S16 Dd, Dn, Dm + /// A64: CMGT Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareLessThan(Vector64 left, Vector64 right) => CompareLessThan(left, right); + + /// + /// uint32x2_t vclt_s32 (int32x2_t a, int32x2_t b) + /// A32: VCLT.S32 Dd, Dn, Dm + /// A64: CMGT Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareLessThan(Vector64 left, Vector64 right) => CompareLessThan(left, right); + + /// + /// uint8x8_t vclt_s8 (int8x8_t a, int8x8_t b) + /// A32: VCLT.S8 Dd, Dn, Dm + /// A64: CMGT Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareLessThan(Vector64 left, Vector64 right) => CompareLessThan(left, right); + + /// + /// uint32x2_t vclt_f32 (float32x2_t a, float32x2_t b) + /// A32: VCLT.F32 Dd, Dn, Dm + /// A64: FCMGT Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareLessThan(Vector64 left, Vector64 right) => CompareLessThan(left, right); + + /// + /// uint16x4_t vclt_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VCLT.U16 Dd, Dn, Dm + /// A64: CMHI Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareLessThan(Vector64 left, Vector64 right) => CompareLessThan(left, right); + + /// + /// uint32x2_t vclt_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VCLT.U32 Dd, Dn, Dm + /// A64: CMHI Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareLessThan(Vector64 left, Vector64 right) => CompareLessThan(left, right); + + /// + /// uint8x16_t vcltq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VCLT.U8 Qd, Qn, Qm + /// A64: CMHI Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => CompareLessThan(left, right); + + /// + /// uint16x8_t vcltq_s16 (int16x8_t a, int16x8_t b) + /// A32: VCLT.S16 Qd, Qn, Qm + /// A64: CMGT Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => CompareLessThan(left, right); + + /// + /// uint32x4_t vcltq_s32 (int32x4_t a, int32x4_t b) + /// A32: VCLT.S32 Qd, Qn, Qm + /// A64: CMGT Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => CompareLessThan(left, right); + + /// + /// uint8x16_t vcltq_s8 (int8x16_t a, int8x16_t b) + /// A32: VCLT.S8 Qd, Qn, Qm + /// A64: CMGT Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => CompareLessThan(left, right); + + /// + /// uint32x4_t vcltq_f32 (float32x4_t a, float32x4_t b) + /// A32: VCLT.F32 Qd, Qn, Qm + /// A64: FCMGT Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => CompareLessThan(left, right); + + /// + /// uint16x8_t vcltq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VCLT.U16 Qd, Qn, Qm + /// A64: CMHI Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => CompareLessThan(left, right); + + /// + /// uint32x4_t vcltq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VCLT.U32 Qd, Qn, Qm + /// A64: CMHI Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => CompareLessThan(left, right); + + /// + /// uint8x8_t vcle_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VCLE.U8 Dd, Dn, Dm + /// A64: CMHS Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) => CompareLessThanOrEqual(left, right); + + /// + /// uint16x4_t vcle_s16 (int16x4_t a, int16x4_t b) + /// A32: VCLE.S16 Dd, Dn, Dm + /// A64: CMGE Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) => CompareLessThanOrEqual(left, right); + + /// + /// uint32x2_t vcle_s32 (int32x2_t a, int32x2_t b) + /// A32: VCLE.S32 Dd, Dn, Dm + /// A64: CMGE Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) => CompareLessThanOrEqual(left, right); + + /// + /// uint8x8_t vcle_s8 (int8x8_t a, int8x8_t b) + /// A32: VCLE.S8 Dd, Dn, Dm + /// A64: CMGE Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) => CompareLessThanOrEqual(left, right); + + /// + /// uint32x2_t vcle_f32 (float32x2_t a, float32x2_t b) + /// A32: VCLE.F32 Dd, Dn, Dm + /// A64: FCMGE Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) => CompareLessThanOrEqual(left, right); + + /// + /// uint16x4_t vcle_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VCLE.U16 Dd, Dn, Dm + /// A64: CMHS Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) => CompareLessThanOrEqual(left, right); + + /// + /// uint32x2_t vcle_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VCLE.U32 Dd, Dn, Dm + /// A64: CMHS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) => CompareLessThanOrEqual(left, right); + + /// + /// uint8x16_t vcleq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VCLE.U8 Qd, Qn, Qm + /// A64: CMHS Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) => CompareLessThanOrEqual(left, right); + + /// + /// uint16x8_t vcleq_s16 (int16x8_t a, int16x8_t b) + /// A32: VCLE.S16 Qd, Qn, Qm + /// A64: CMGE Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) => CompareLessThanOrEqual(left, right); + + /// + /// uint32x4_t vcleq_s32 (int32x4_t a, int32x4_t b) + /// A32: VCLE.S32 Qd, Qn, Qm + /// A64: CMGE Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) => CompareLessThanOrEqual(left, right); + + /// + /// uint8x16_t vcleq_s8 (int8x16_t a, int8x16_t b) + /// A32: VCLE.S8 Qd, Qn, Qm + /// A64: CMGE Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) => CompareLessThanOrEqual(left, right); + + /// + /// uint32x4_t vcleq_f32 (float32x4_t a, float32x4_t b) + /// A32: VCLE.F32 Qd, Qn, Qm + /// A64: FCMGE Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) => CompareLessThanOrEqual(left, right); + + /// + /// uint16x8_t vcleq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VCLE.U16 Qd, Qn, Qm + /// A64: CMHS Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) => CompareLessThanOrEqual(left, right); + + /// + /// uint32x4_t vcleq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VCLE.U32 Qd, Qn, Qm + /// A64: CMHS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) => CompareLessThanOrEqual(left, right); + + /// + /// uint8x8_t vtst_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VTST.8 Dd, Dn, Dm + /// A64: CMTST Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareTest(Vector64 left, Vector64 right) => CompareTest(left, right); + + /// + /// uint16x4_t vtst_s16 (int16x4_t a, int16x4_t b) + /// A32: VTST.16 Dd, Dn, Dm + /// A64: CMTST Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareTest(Vector64 left, Vector64 right) => CompareTest(left, right); + + /// + /// uint32x2_t vtst_s32 (int32x2_t a, int32x2_t b) + /// A32: VTST.32 Dd, Dn, Dm + /// A64: CMTST Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareTest(Vector64 left, Vector64 right) => CompareTest(left, right); + + /// + /// uint8x8_t vtst_s8 (int8x8_t a, int8x8_t b) + /// A32: VTST.8 Dd, Dn, Dm + /// A64: CMTST Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 CompareTest(Vector64 left, Vector64 right) => CompareTest(left, right); + + /// + /// uint32x2_t vtst_f32 (float32x2_t a, float32x2_t b) + /// A32: VTST.32 Dd, Dn, Dm + /// A64: CMTST Vd.2S, Vn.2S, Vm.2S + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 CompareTest(Vector64 left, Vector64 right) => CompareTest(left, right); + + /// + /// uint16x4_t vtst_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VTST.16 Dd, Dn, Dm + /// A64: CMTST Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 CompareTest(Vector64 left, Vector64 right) => CompareTest(left, right); + + /// + /// uint32x2_t vtst_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VTST.32 Dd, Dn, Dm + /// A64: CMTST Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 CompareTest(Vector64 left, Vector64 right) => CompareTest(left, right); + + /// + /// uint8x16_t vtstq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VTST.8 Qd, Qn, Qm + /// A64: CMTST Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareTest(Vector128 left, Vector128 right) => CompareTest(left, right); + + /// + /// uint16x8_t vtstq_s16 (int16x8_t a, int16x8_t b) + /// A32: VTST.16 Qd, Qn, Qm + /// A64: CMTST Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareTest(Vector128 left, Vector128 right) => CompareTest(left, right); + + /// + /// uint32x4_t vtstq_s32 (int32x4_t a, int32x4_t b) + /// A32: VTST.32 Qd, Qn, Qm + /// A64: CMTST Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareTest(Vector128 left, Vector128 right) => CompareTest(left, right); + + /// + /// uint8x16_t vtstq_s8 (int8x16_t a, int8x16_t b) + /// A32: VTST.8 Qd, Qn, Qm + /// A64: CMTST Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 CompareTest(Vector128 left, Vector128 right) => CompareTest(left, right); + + /// + /// uint32x4_t vtstq_f32 (float32x4_t a, float32x4_t b) + /// A32: VTST.32 Qd, Qn, Qm + /// A64: CMTST Vd.4S, Vn.4S, Vm.4S + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 CompareTest(Vector128 left, Vector128 right) => CompareTest(left, right); + + /// + /// uint16x8_t vtstq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VTST.16 Qd, Qn, Qm + /// A64: CMTST Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 CompareTest(Vector128 left, Vector128 right) => CompareTest(left, right); + + /// + /// uint32x4_t vtstq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VTST.32 Qd, Qn, Qm + /// A64: CMTST Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 CompareTest(Vector128 left, Vector128 right) => CompareTest(left, right); + + /// + /// float64x1_t vdiv_f64 (float64x1_t a, float64x1_t b) + /// A32: VDIV.F64 Dd, Dn, Dm + /// A64: FDIV Dd, Dn, Dm + /// + public static Vector64 DivideScalar(Vector64 left, Vector64 right) => DivideScalar(left, right); + + /// + /// float32_t vdivs_f32 (float32_t a, float32_t b) + /// A32: VDIV.F32 Sd, Sn, Sm + /// A64: FDIV Sd, Sn, Sm + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 DivideScalar(Vector64 left, Vector64 right) => DivideScalar(left, right); + + /// + /// uint8x8_t vdup_lane_u8 (uint8x8_t vec, const int lane) + /// A32: VDUP.8 Dd, Dm[index] + /// A64: DUP Vd.8B, Vn.B[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector64 value, byte index)=> DuplicateSelectedScalarToVector64(value, index); + + /// + /// int16x4_t vdup_lane_s16 (int16x4_t vec, const int lane) + /// A32: VDUP.16 Dd, Dm[index] + /// A64: DUP Vd.4H, Vn.H[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector64 value, byte index)=> DuplicateSelectedScalarToVector64(value, index); + + /// + /// int32x2_t vdup_lane_s32 (int32x2_t vec, const int lane) + /// A32: VDUP.32 Dd, Dm[index] + /// A64: DUP Vd.2S, Vn.S[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector64 value, byte index)=> DuplicateSelectedScalarToVector64(value, index); + + /// + /// float32x2_t vdup_lane_f32 (float32x2_t vec, const int lane) + /// A32: VDUP.32 Dd, Dm[index] + /// A64: DUP Vd.2S, Vn.S[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector64 value, byte index)=> DuplicateSelectedScalarToVector64(value, index); + + /// + /// int8x8_t vdup_lane_s8 (int8x8_t vec, const int lane) + /// A32: VDUP.8 Dd, Dm[index] + /// A64: DUP Vd.8B, Vn.B[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector64 value, byte index)=> DuplicateSelectedScalarToVector64(value, index); + + /// + /// uint16x4_t vdup_lane_u16 (uint16x4_t vec, const int lane) + /// A32: VDUP.16 Dd, Dm[index] + /// A64: DUP Vd.4H, Vn.H[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector64 value, byte index)=> DuplicateSelectedScalarToVector64(value, index); + + /// + /// uint32x2_t vdup_lane_u32 (uint32x2_t vec, const int lane) + /// A32: VDUP.32 Dd, Dm[index] + /// A64: DUP Vd.2S, Vn.S[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector64 value, byte index)=> DuplicateSelectedScalarToVector64(value, index); + + /// + /// uint8x8_t vdup_laneq_u8 (uint8x16_t vec, const int lane) + /// A32: VDUP.8 Dd, Dm[index] + /// A64: DUP Vd.8B, Vn.B[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector128 value, byte index)=> DuplicateSelectedScalarToVector64(value, index); + + /// + /// int16x4_t vdup_laneq_s16 (int16x8_t vec, const int lane) + /// A32: VDUP.16 Dd, Dm[index] + /// A64: DUP Vd.4H, Vn.H[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector128 value, byte index)=> DuplicateSelectedScalarToVector64(value, index); + + /// + /// int32x2_t vdup_laneq_s32 (int32x4_t vec, const int lane) + /// A32: VDUP.32 Dd, Dm[index] + /// A64: DUP Vd.2S, Vn.S[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector128 value, byte index)=> DuplicateSelectedScalarToVector64(value, index); + + /// + /// float32x2_t vdup_laneq_f32 (float32x4_t vec, const int lane) + /// A32: VDUP.32 Dd, Dm[index] + /// A64: DUP Vd.2S, Vn.S[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector128 value, byte index)=> DuplicateSelectedScalarToVector64(value, index); + + /// + /// int8x8_t vdup_laneq_s8 (int8x16_t vec, const int lane) + /// A32: VDUP.8 Dd, Dm[index] + /// A64: DUP Vd.8B, Vn.B[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector128 value, byte index)=> DuplicateSelectedScalarToVector64(value, index); + + /// + /// uint16x4_t vdup_laneq_u16 (uint16x8_t vec, const int lane) + /// A32: VDUP.16 Dd, Dm[index] + /// A64: DUP Vd.4H, Vn.H[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector128 value, byte index)=> DuplicateSelectedScalarToVector64(value, index); + + /// + /// uint32x2_t vdup_laneq_u32 (uint32x4_t vec, const int lane) + /// A32: VDUP.32 Dd, Dm[index] + /// A64: DUP Vd.2S, Vn.S[index] + /// + public static Vector64 DuplicateSelectedScalarToVector64(Vector128 value, byte index)=> DuplicateSelectedScalarToVector64(value, index); + + /// + /// uint8x16_t vdupq_lane_u8 (uint8x8_t vec, const int lane) + /// A32: VDUP.8 Qd, Dm[index] + /// A64: DUP Vd.16B, Vn.B[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector64 value, byte index)=> DuplicateSelectedScalarToVector128(value, index); + + /// + /// int16x8_t vdupq_lane_s16 (int16x4_t vec, const int lane) + /// A32: VDUP.16 Qd, Dm[index] + /// A64: DUP Vd.8H, Vn.H[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector64 value, byte index)=> DuplicateSelectedScalarToVector128(value, index); + + /// + /// int32x4_t vdupq_lane_s32 (int32x2_t vec, const int lane) + /// A32: VDUP.32 Qd, Dm[index] + /// A64: DUP Vd.4S, Vn.S[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector64 value, byte index)=> DuplicateSelectedScalarToVector128(value, index); + + /// + /// float32x4_t vdupq_lane_f32 (float32x2_t vec, const int lane) + /// A32: VDUP.32 Qd, Dm[index] + /// A64: DUP Vd.4S, Vn.S[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector64 value, byte index)=> DuplicateSelectedScalarToVector128(value, index); + + /// + /// int8x16_t vdupq_lane_s8 (int8x8_t vec, const int lane) + /// A32: VDUP.8 Qd, Dm[index] + /// A64: DUP Vd.16B, Vn.B[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector64 value, byte index)=> DuplicateSelectedScalarToVector128(value, index); + + /// + /// uint16x8_t vdupq_lane_u16 (uint16x4_t vec, const int lane) + /// A32: VDUP.16 Qd, Dm[index] + /// A64: DUP Vd.8H, Vn.H[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector64 value, byte index)=> DuplicateSelectedScalarToVector128(value, index); + + /// + /// uint32x4_t vdupq_lane_u32 (uint32x2_t vec, const int lane) + /// A32: VDUP.32 Qd, Dm[index] + /// A64: DUP Vd.4S, Vn.S[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector64 value, byte index)=> DuplicateSelectedScalarToVector128(value, index); + + /// + /// uint8x16_t vdupq_lane_u8 (uint8x16_t vec, const int lane) + /// A32: VDUP.8 Qd, Dm[index] + /// A64: DUP Vd.16B, Vn.B[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector128 value, byte index)=> DuplicateSelectedScalarToVector128(value, index); + + /// + /// int16x8_t vdupq_lane_s16 (int16x8_t vec, const int lane) + /// A32: VDUP.16 Qd, Dm[index] + /// A64: DUP Vd.8H, Vn.H[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector128 value, byte index)=> DuplicateSelectedScalarToVector128(value, index); + + /// + /// int32x4_t vdupq_lane_s32 (int32x4_t vec, const int lane) + /// A32: VDUP.32 Qd, Dm[index] + /// A64: DUP Vd.4S, Vn.S[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector128 value, byte index)=> DuplicateSelectedScalarToVector128(value, index); + + /// + /// float32x4_t vdupq_lane_f32 (float32x4_t vec, const int lane) + /// A32: VDUP.32 Qd, Dm[index] + /// A64: DUP Vd.4S, Vn.S[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector128 value, byte index)=> DuplicateSelectedScalarToVector128(value, index); + + /// + /// int8x16_t vdupq_lane_s8 (int8x16_t vec, const int lane) + /// A32: VDUP.8 Qd, Dm[index] + /// A64: DUP Vd.16B, Vn.B[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector128 value, byte index)=> DuplicateSelectedScalarToVector128(value, index); + + /// + /// uint16x8_t vdupq_lane_u16 (uint16x8_t vec, const int lane) + /// A32: VDUP.16 Qd, Dm[index] + /// A64: DUP Vd.8H, Vn.H[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector128 value, byte index)=> DuplicateSelectedScalarToVector128(value, index); + + /// + /// uint32x4_t vdupq_lane_u32 (uint32x4_t vec, const int lane) + /// A32: VDUP.32 Qd, Dm[index] + /// A64: DUP Vd.4S, Vn.S[index] + /// + public static Vector128 DuplicateSelectedScalarToVector128(Vector128 value, byte index)=> DuplicateSelectedScalarToVector128(value, index); + + /// + /// uint8x8_t vdup_n_u8 (uint8_t value) + /// A32: VDUP.8 Dd, Rt + /// A64: DUP Vd.8B, Rn + /// + public static Vector64 DuplicateToVector64(byte value) => DuplicateToVector64(value); + + /// + /// int16x4_t vdup_n_s16 (int16_t value) + /// A32: VDUP.16 Dd, Rt + /// A64: DUP Vd.4H, Rn + /// + public static Vector64 DuplicateToVector64(short value) => DuplicateToVector64(value); + + /// + /// int32x2_t vdup_n_s32 (int32_t value) + /// A32: VDUP.32 Dd, Rt + /// A64: DUP Vd.2S, Rn + /// + public static Vector64 DuplicateToVector64(int value) => DuplicateToVector64(value); + + /// + /// int8x8_t vdup_n_s8 (int8_t value) + /// A32: VDUP.8 Dd, Rt + /// A64: DUP Vd.8B, Rn + /// + public static Vector64 DuplicateToVector64(sbyte value) => DuplicateToVector64(value); + + /// + /// float32x2_t vdup_n_f32 (float32_t value) + /// A32: VDUP Dd, Dm[0] + /// A64: DUP Vd.2S, Vn.S[0] + /// + public static Vector64 DuplicateToVector64(float value) => DuplicateToVector64(value); + + /// + /// uint16x4_t vdup_n_u16 (uint16_t value) + /// A32: VDUP.16 Dd, Rt + /// A64: DUP Vd.4H, Rn + /// + public static Vector64 DuplicateToVector64(ushort value) => DuplicateToVector64(value); + + /// + /// uint32x2_t vdup_n_u32 (uint32_t value) + /// A32: VDUP.32 Dd, Rt + /// A64: DUP Vd.2S, Rn + /// + public static Vector64 DuplicateToVector64(uint value) => DuplicateToVector64(value); + + /// + /// uint8x16_t vdupq_n_u8 (uint8_t value) + /// A32: VDUP.8 Qd, Rt + /// A64: DUP Vd.16B, Rn + /// + public static Vector128 DuplicateToVector128(byte value) => DuplicateToVector128(value); + + /// + /// int16x8_t vdupq_n_s16 (int16_t value) + /// A32: VDUP.16 Qd, Rt + /// A64: DUP Vd.8H, Rn + /// + public static Vector128 DuplicateToVector128(short value) => DuplicateToVector128(value); + + /// + /// int32x4_t vdupq_n_s32 (int32_t value) + /// A32: VDUP.32 Qd, Rt + /// A64: DUP Vd.4S, Rn + /// + public static Vector128 DuplicateToVector128(int value) => DuplicateToVector128(value); + + /// + /// int8x16_t vdupq_n_s8 (int8_t value) + /// A32: VDUP.8 Qd, Rt + /// A64: DUP Vd.16B, Rn + /// + public static Vector128 DuplicateToVector128(sbyte value) => DuplicateToVector128(value); + + /// + /// float32x4_t vdupq_n_f32 (float32_t value) + /// A32: VDUP Qd, Dm[0] + /// A64: DUP Vd.4S, Vn.S[0] + /// + public static Vector128 DuplicateToVector128(float value) => DuplicateToVector128(value); + + /// + /// uint16x8_t vdupq_n_u16 (uint16_t value) + /// A32: VDUP.16 Qd, Rt + /// A64: DUP Vd.8H, Rn + /// + public static Vector128 DuplicateToVector128(ushort value) => DuplicateToVector128(value); + + /// + /// uint32x4_t vdupq_n_u32 (uint32_t value) + /// A32: VDUP.32 Qd, Rt + /// A64: DUP Vd.4S, Rn + /// + public static Vector128 DuplicateToVector128(uint value) => DuplicateToVector128(value); + + /// + /// uint8_t vget_lane_u8 (uint8x8_t v, const int lane) + /// A32: VMOV.U8 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.B[lane] + /// + public static byte Extract(Vector64 vector, byte index) => Extract(vector, index); + + /// + /// int16_t vget_lane_s16 (int16x4_t v, const int lane) + /// A32: VMOV.S16 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.H[lane] + /// + public static short Extract(Vector64 vector, byte index) => Extract(vector, index); + + /// + /// int32_t vget_lane_s32 (int32x2_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.S[lane] + /// + public static int Extract(Vector64 vector, byte index) => Extract(vector, index); + + /// + /// int8_t vget_lane_s8 (int8x8_t v, const int lane) + /// A32: VMOV.S8 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.B[lane] + /// + public static sbyte Extract(Vector64 vector, byte index) => Extract(vector, index); + + /// + /// float32_t vget_lane_f32 (float32x2_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: DUP Sd, Vn.S[lane] + /// + public static float Extract(Vector64 vector, byte index) => Extract(vector, index); + + /// + /// uint16_t vget_lane_u16 (uint16x4_t v, const int lane) + /// A32: VMOV.U16 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.H[lane] + /// + public static ushort Extract(Vector64 vector, byte index) => Extract(vector, index); + + /// + /// uint32_t vget_lane_u32 (uint32x2_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.S[lane] + /// + public static uint Extract(Vector64 vector, byte index) => Extract(vector, index); + + /// + /// uint8_t vgetq_lane_u8 (uint8x16_t v, const int lane) + /// A32: VMOV.U8 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.B[lane] + /// + public static byte Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// float64_t vgetq_lane_f64 (float64x2_t v, const int lane) + /// A32: VMOV.F64 Dd, Dm + /// A64: DUP Dd, Vn.D[lane] + /// + public static double Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// int16_t vgetq_lane_s16 (int16x8_t v, const int lane) + /// A32: VMOV.S16 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.H[lane] + /// + public static short Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// int32_t vgetq_lane_s32 (int32x4_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.S[lane] + /// + public static int Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// int64_t vgetq_lane_s64 (int64x2_t v, const int lane) + /// A32: VMOV Rt, Rt2, Dm + /// A64: UMOV Xd, Vn.D[lane] + /// + public static long Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// int8_t vgetq_lane_s8 (int8x16_t v, const int lane) + /// A32: VMOV.S8 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.B[lane] + /// + public static sbyte Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// float32_t vgetq_lane_f32 (float32x4_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: DUP Sd, Vn.S[lane] + /// + public static float Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// uint16_t vgetq_lane_u16 (uint16x8_t v, const int lane) + /// A32: VMOV.U16 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.H[lane] + /// + public static ushort Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// uint32_t vgetq_lane_u32 (uint32x4_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.S[lane] + /// + public static uint Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// uint64_t vgetq_lane_u64 (uint64x2_t v, const int lane) + /// A32: VMOV Rt, Rt2, Dm + /// A64: UMOV Xd, Vn.D[lane] + /// + public static ulong Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// int8x16_t vmovn_high_s16 (int8x8_t r, int16x8_t a) + /// A32: VMOVN.I16 Dd+1, Qm + /// A64: XTN2 Vd.16B, Vn.8H + /// + public static Vector128 ExtractNarrowingUpper(Vector64 lower, Vector128 value) => ExtractNarrowingUpper(lower, value); + + /// + /// int16x8_t vmovn_high_s32 (int16x4_t r, int32x4_t a) + /// A32: VMOVN.I32 Dd+1, Qm + /// A64: XTN2 Vd.8H, Vn.4S + /// + public static Vector128 ExtractNarrowingUpper(Vector64 lower, Vector128 value) => ExtractNarrowingUpper(lower, value); + + /// + /// int32x4_t vmovn_high_s64 (int32x2_t r, int64x2_t a) + /// A32: VMOVN.I64 Dd+1, Qm + /// A64: XTN2 Vd.4S, Vn.2D + /// + public static Vector128 ExtractNarrowingUpper(Vector64 lower, Vector128 value) => ExtractNarrowingUpper(lower, value); + + /// + /// uint8x16_t vmovn_high_u16 (uint8x8_t r, uint16x8_t a) + /// A32: VMOVN.I16 Dd+1, Qm + /// A64: XTN2 Vd.16B, Vn.8H + /// + public static Vector128 ExtractNarrowingUpper(Vector64 lower, Vector128 value) => ExtractNarrowingUpper(lower, value); + + /// + /// uint16x8_t vmovn_high_u32 (uint16x4_t r, uint32x4_t a) + /// A32: VMOVN.I32 Dd+1, Qm + /// A64: XTN2 Vd.8H, Vn.4S + /// + public static Vector128 ExtractNarrowingUpper(Vector64 lower, Vector128 value) => ExtractNarrowingUpper(lower, value); + + /// + /// uint32x4_t vmovn_high_u64 (uint32x2_t r, uint64x2_t a) + /// A32: VMOVN.I64 Dd+1, Qm + /// A64: XTN2 Vd.4S, Vn.2D + /// + public static Vector128 ExtractNarrowingUpper(Vector64 lower, Vector128 value) => ExtractNarrowingUpper(lower, value); + + /// + /// int8x8_t vmovn_s16 (int16x8_t a) + /// A32: VMOVN.I16 Dd, Qm + /// A64: XTN Vd.8B, Vn.8H + /// + public static Vector64 ExtractNarrowingLower(Vector128 value) => ExtractNarrowingLower(value); + + /// + /// int16x4_t vmovn_s32 (int32x4_t a) + /// A32: VMOVN.I32 Dd, Qm + /// A64: XTN Vd.4H, Vn.4S + /// + public static Vector64 ExtractNarrowingLower(Vector128 value) => ExtractNarrowingLower(value); + + /// + /// int32x2_t vmovn_s64 (int64x2_t a) + /// A32: VMOVN.I64 Dd, Qm + /// A64: XTN Vd.2S, Vn.2D + /// + public static Vector64 ExtractNarrowingLower(Vector128 value) => ExtractNarrowingLower(value); + + /// + /// uint8x8_t vmovn_u16 (uint16x8_t a) + /// A32: VMOVN.I16 Dd, Qm + /// A64: XTN Vd.8B, Vn.8H + /// + public static Vector64 ExtractNarrowingLower(Vector128 value) => ExtractNarrowingLower(value); + + /// + /// uint16x4_t vmovn_u32 (uint32x4_t a) + /// A32: VMOVN.I32 Dd, Qm + /// A64: XTN Vd.4H, Vn.4S + /// + public static Vector64 ExtractNarrowingLower(Vector128 value) => ExtractNarrowingLower(value); + + /// + /// uint32x2_t vmovn_u64 (uint64x2_t a) + /// A32: VMOVN.I64 Dd, Qm + /// A64: XTN Vd.2S, Vn.2D + /// + public static Vector64 ExtractNarrowingLower(Vector128 value) => ExtractNarrowingLower(value); + + /// + /// uint8x8_t vext_s8 (uint8x8_t a, uint8x8_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #n + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #n + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) => ExtractVector64(upper, lower, index); + + /// + /// int16x4_t vext_s16 (int16x4_t a, int16x4_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*2) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*2) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) => ExtractVector64(upper, lower, index); + + /// + /// int32x2_t vext_s32 (int32x2_t a, int32x2_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*4) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*4) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) => ExtractVector64(upper, lower, index); + + /// + /// int8x8_t vext_s8 (int8x8_t a, int8x8_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #n + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #n + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) => ExtractVector64(upper, lower, index); + + /// + /// float32x2_t vext_f32 (float32x2_t a, float32x2_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*4) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*4) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) => ExtractVector64(upper, lower, index); + + /// + /// uint16x4_t vext_s16 (uint16x4_t a, uint16x4_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*2) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*2) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) => ExtractVector64(upper, lower, index); + + /// + /// uint32x2_t vext_s32 (uint32x2_t a, uint32x2_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*4) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*4) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) => ExtractVector64(upper, lower, index); + + /// + /// uint8x16_t vextq_s8 (uint8x16_t a, uint8x16_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #n + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #n + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// float64x2_t vextq_f64 (float64x2_t a, float64x2_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*8) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*8) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// int16x8_t vextq_s16 (int16x8_t a, int16x8_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*2) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*2) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// int32x4_t vextq_s32 (int32x4_t a, int32x4_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*4) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*4) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// int64x2_t vextq_s64 (int64x2_t a, int64x2_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*8) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*8) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// int8x16_t vextq_s8 (int8x16_t a, int8x16_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #n + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #n + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// float32x4_t vextq_f32 (float32x4_t a, float32x4_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*4) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*4) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// uint16x8_t vextq_s16 (uint16x8_t a, uint16x8_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*2) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*2) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// uint32x4_t vextq_s32 (uint32x4_t a, uint32x4_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*4) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*4) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// uint64x2_t vextq_s64 (uint64x2_t a, uint64x2_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*8) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*8) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// uint8x8_t vhadd_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VHADD.U8 Dd, Dn, Dm + /// A64: UHADD Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 FusedAddHalving(Vector64 left, Vector64 right) => FusedAddHalving(left, right); + + /// + /// int16x4_t vhadd_s16 (int16x4_t a, int16x4_t b) + /// A32: VHADD.S16 Dd, Dn, Dm + /// A64: SHADD Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 FusedAddHalving(Vector64 left, Vector64 right) => FusedAddHalving(left, right); + + /// + /// int32x2_t vhadd_s32 (int32x2_t a, int32x2_t b) + /// A32: VHADD.S32 Dd, Dn, Dm + /// A64: SHADD Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedAddHalving(Vector64 left, Vector64 right) => FusedAddHalving(left, right); + + /// + /// int8x8_t vhadd_s8 (int8x8_t a, int8x8_t b) + /// A32: VHADD.S8 Dd, Dn, Dm + /// A64: SHADD Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 FusedAddHalving(Vector64 left, Vector64 right) => FusedAddHalving(left, right); + + /// + /// uint16x4_t vhadd_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VHADD.U16 Dd, Dn, Dm + /// A64: UHADD Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 FusedAddHalving(Vector64 left, Vector64 right) => FusedAddHalving(left, right); + + /// + /// uint32x2_t vhadd_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VHADD.U32 Dd, Dn, Dm + /// A64: UHADD Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedAddHalving(Vector64 left, Vector64 right) => FusedAddHalving(left, right); + + /// + /// uint8x16_t vhaddq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VHADD.U8 Qd, Qn, Qm + /// A64: UHADD Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 FusedAddHalving(Vector128 left, Vector128 right) => FusedAddHalving(left, right); + + /// + /// int16x8_t vhaddq_s16 (int16x8_t a, int16x8_t b) + /// A32: VHADD.S16 Qd, Qn, Qm + /// A64: SHADD Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 FusedAddHalving(Vector128 left, Vector128 right) => FusedAddHalving(left, right); + + /// + /// int32x4_t vhaddq_s32 (int32x4_t a, int32x4_t b) + /// A32: VHADD.S32 Qd, Qn, Qm + /// A64: SHADD Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedAddHalving(Vector128 left, Vector128 right) => FusedAddHalving(left, right); + + /// + /// int8x16_t vhaddq_s8 (int8x16_t a, int8x16_t b) + /// A32: VHADD.S8 Qd, Qn, Qm + /// A64: SHADD Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 FusedAddHalving(Vector128 left, Vector128 right) => FusedAddHalving(left, right); + + /// + /// uint16x8_t vhaddq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VHADD.U16 Qd, Qn, Qm + /// A64: UHADD Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 FusedAddHalving(Vector128 left, Vector128 right) => FusedAddHalving(left, right); + + /// + /// uint32x4_t vhaddq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VHADD.U32 Qd, Qn, Qm + /// A64: UHADD Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedAddHalving(Vector128 left, Vector128 right) => FusedAddHalving(left, right); + + /// + /// uint8x8_t vrhadd_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VRHADD.U8 Dd, Dn, Dm + /// A64: URHADD Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 FusedAddRoundedHalving(Vector64 left, Vector64 right) => FusedAddRoundedHalving(left, right); + + /// + /// int16x4_t vrhadd_s16 (int16x4_t a, int16x4_t b) + /// A32: VRHADD.S16 Dd, Dn, Dm + /// A64: SRHADD Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 FusedAddRoundedHalving(Vector64 left, Vector64 right) => FusedAddRoundedHalving(left, right); + + /// + /// int32x2_t vrhadd_s32 (int32x2_t a, int32x2_t b) + /// A32: VRHADD.S32 Dd, Dn, Dm + /// A64: SRHADD Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedAddRoundedHalving(Vector64 left, Vector64 right) => FusedAddRoundedHalving(left, right); + + /// + /// int8x8_t vrhadd_s8 (int8x8_t a, int8x8_t b) + /// A32: VRHADD.S8 Dd, Dn, Dm + /// A64: SRHADD Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 FusedAddRoundedHalving(Vector64 left, Vector64 right) => FusedAddRoundedHalving(left, right); + + /// + /// uint16x4_t vrhadd_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VRHADD.U16 Dd, Dn, Dm + /// A64: URHADD Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 FusedAddRoundedHalving(Vector64 left, Vector64 right) => FusedAddRoundedHalving(left, right); + + /// + /// uint32x2_t vrhadd_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VRHADD.U32 Dd, Dn, Dm + /// A64: URHADD Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedAddRoundedHalving(Vector64 left, Vector64 right) => FusedAddRoundedHalving(left, right); + + /// + /// uint8x16_t vrhaddq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VRHADD.U8 Qd, Qn, Qm + /// A64: URHADD Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 FusedAddRoundedHalving(Vector128 left, Vector128 right) => FusedAddRoundedHalving(left, right); + + /// + /// int16x8_t vrhaddq_s16 (int16x8_t a, int16x8_t b) + /// A32: VRHADD.S16 Qd, Qn, Qm + /// A64: SRHADD Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 FusedAddRoundedHalving(Vector128 left, Vector128 right) => FusedAddRoundedHalving(left, right); + + /// + /// int32x4_t vrhaddq_s32 (int32x4_t a, int32x4_t b) + /// A32: VRHADD.S32 Qd, Qn, Qm + /// A64: SRHADD Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedAddRoundedHalving(Vector128 left, Vector128 right) => FusedAddRoundedHalving(left, right); + + /// + /// int8x16_t vrhaddq_s8 (int8x16_t a, int8x16_t b) + /// A32: VRHADD.S8 Qd, Qn, Qm + /// A64: SRHADD Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 FusedAddRoundedHalving(Vector128 left, Vector128 right) => FusedAddRoundedHalving(left, right); + + /// + /// uint16x8_t vrhaddq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VRHADD.U16 Qd, Qn, Qm + /// A64: URHADD Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 FusedAddRoundedHalving(Vector128 left, Vector128 right) => FusedAddRoundedHalving(left, right); + + /// + /// uint32x4_t vrhaddq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VRHADD.U32 Qd, Qn, Qm + /// A64: URHADD Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedAddRoundedHalving(Vector128 left, Vector128 right) => FusedAddRoundedHalving(left, right); + + /// + /// float32x2_t vfma_f32 (float32x2_t a, float32x2_t b, float32x2_t c) + /// A32: VFMA.F32 Dd, Dn, Dm + /// A64: FMLA Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedMultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplyAdd(acc, left, right); + + /// + /// float32x4_t vfmaq_f32 (float32x4_t a, float32x4_t b, float32x4_t c) + /// A32: VFMA.F32 Qd, Qn, Qm + /// A64: FMLA Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedMultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => FusedMultiplyAdd(acc, left, right); + + /// + /// float64x1_t vfma_f64 (float64x1_t a, float64x1_t b, float64x1_t c) + /// A32: VFMA.F64 Dd, Dn, Dm + /// A64: FMADD Dd, Dn, Dm, Da + /// + public static Vector64 FusedMultiplyAddScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplyAddScalar(acc, left, right); + + /// + /// float32_t vfmas_f32 (float32_t a, float32_t b, float32_t c) + /// A32: VFMA.F32 Sd, Sn, Sm + /// A64: FMADD Sd, Sn, Sm, Sa + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 FusedMultiplyAddScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplyAddScalar(acc, left, right); + + /// + /// float64x1_t vfnma_f64 (float64x1_t a, float64x1_t b, float64x1_t c) + /// A32: VFNMA.F64 Dd, Dn, Dm + /// A64: FNMADD Dd, Dn, Dm, Da + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 FusedMultiplyAddNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplyAddNegatedScalar(acc, left, right); + + /// + /// float32_t vfnmas_f32 (float32_t a, float32_t b, float32_t c) + /// A32: VFNMA.F32 Sd, Sn, Sm + /// A64: FNMADD Sd, Sn, Sm, Sa + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 FusedMultiplyAddNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplyAddNegatedScalar(acc, left, right); + + /// + /// float32x2_t vfms_f32 (float32x2_t a, float32x2_t b, float32x2_t c) + /// A32: VFMS.F32 Dd, Dn, Dm + /// A64: FMLS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedMultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplySubtract(acc, left, right); + + /// + /// float32x4_t vfmsq_f32 (float32x4_t a, float32x4_t b, float32x4_t c) + /// A32: VFMS.F32 Qd, Qn, Qm + /// A64: FMLS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedMultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => FusedMultiplySubtract(acc, left, right); + + /// + /// float64x1_t vfms_f64 (float64x1_t a, float64x1_t b, float64x1_t c) + /// A32: VFMS.F64 Dd, Dn, Dm + /// A64: FMSUB Dd, Dn, Dm, Da + /// + public static Vector64 FusedMultiplySubtractScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplySubtractScalar(acc, left, right); + + /// + /// float32_t vfmss_f32 (float32_t a, float32_t b, float32_t c) + /// A32: VFMS.F32 Sd, Sn, Sm + /// A64: FMSUB Sd, Sn, Sm, Sa + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 FusedMultiplySubtractScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplySubtractScalar(acc, left, right); + + /// + /// float64x1_t vfnms_f64 (float64x1_t a, float64x1_t b, float64x1_t c) + /// A32: VFNMS.F64 Dd, Dn, Dm + /// A64: FNMSUB Dd, Dn, Dm, Da + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 FusedMultiplySubtractNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplySubtractNegatedScalar(acc, left, right); + + /// + /// float32_t vfnmss_f32 (float32_t a, float32_t b, float32_t c) + /// A32: VFNMS.F32 Sd, Sn, Sm + /// A64: FNMSUB Sd, Sn, Sm, Sa + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 FusedMultiplySubtractNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplySubtractNegatedScalar(acc, left, right); + + /// + /// uint8x8_t vhsub_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VHSUB.U8 Dd, Dn, Dm + /// A64: UHSUB Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 FusedSubtractHalving(Vector64 left, Vector64 right) => FusedSubtractHalving(left, right); + + /// + /// int16x4_t vhsub_s16 (int16x4_t a, int16x4_t b) + /// A32: VHSUB.S16 Dd, Dn, Dm + /// A64: SHSUB Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 FusedSubtractHalving(Vector64 left, Vector64 right) => FusedSubtractHalving(left, right); + + /// + /// int32x2_t vhsub_s32 (int32x2_t a, int32x2_t b) + /// A32: VHSUB.S32 Dd, Dn, Dm + /// A64: SHSUB Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedSubtractHalving(Vector64 left, Vector64 right) => FusedSubtractHalving(left, right); + + /// + /// int8x8_t vhsub_s8 (int8x8_t a, int8x8_t b) + /// A32: VHSUB.S8 Dd, Dn, Dm + /// A64: SHSUB Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 FusedSubtractHalving(Vector64 left, Vector64 right) => FusedSubtractHalving(left, right); + + /// + /// uint16x4_t vhsub_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VHSUB.U16 Dd, Dn, Dm + /// A64: UHSUB Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 FusedSubtractHalving(Vector64 left, Vector64 right) => FusedSubtractHalving(left, right); + + /// + /// uint32x2_t vhsub_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VHSUB.U32 Dd, Dn, Dm + /// A64: UHSUB Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 FusedSubtractHalving(Vector64 left, Vector64 right) => FusedSubtractHalving(left, right); + + /// + /// uint8x16_t vhsubq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VHSUB.U8 Qd, Qn, Qm + /// A64: UHSUB Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 FusedSubtractHalving(Vector128 left, Vector128 right) => FusedSubtractHalving(left, right); + + /// + /// int16x8_t vhsubq_s16 (int16x8_t a, int16x8_t b) + /// A32: VHSUB.S16 Qd, Qn, Qm + /// A64: SHSUB Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 FusedSubtractHalving(Vector128 left, Vector128 right) => FusedSubtractHalving(left, right); + + /// + /// int32x4_t vhsubq_s32 (int32x4_t a, int32x4_t b) + /// A32: VHSUB.S32 Qd, Qn, Qm + /// A64: SHSUB Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedSubtractHalving(Vector128 left, Vector128 right) => FusedSubtractHalving(left, right); + + /// + /// int8x16_t vhsubq_s8 (int8x16_t a, int8x16_t b) + /// A32: VHSUB.S8 Qd, Qn, Qm + /// A64: SHSUB Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 FusedSubtractHalving(Vector128 left, Vector128 right) => FusedSubtractHalving(left, right); + + /// + /// uint16x8_t vhsubq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VHSUB.U16 Qd, Qn, Qm + /// A64: UHSUB Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 FusedSubtractHalving(Vector128 left, Vector128 right) => FusedSubtractHalving(left, right); + + /// + /// uint32x4_t vhsubq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VHSUB.U32 Qd, Qn, Qm + /// A64: UHSUB Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 FusedSubtractHalving(Vector128 left, Vector128 right) => FusedSubtractHalving(left, right); + + /// + /// uint8x8_t vset_lane_u8 (uint8_t a, uint8x8_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, byte data) => Insert(vector, index, data); + + /// + /// int16x4_t vset_lane_s16 (int16_t a, int16x4_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, short data) => Insert(vector, index, data); + + /// + /// int32x2_t vset_lane_s32 (int32_t a, int32x2_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, int data) => Insert(vector, index, data); + + /// + /// int8x8_t vset_lane_s8 (int8_t a, int8x8_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, sbyte data) => Insert(vector, index, data); + + /// + /// float32x2_t vset_lane_f32 (float32_t a, float32x2_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: INS Vd.S[lane], Vn.S[0] + /// + public static Vector64 Insert(Vector64 vector, byte index, float data) => Insert(vector, index, data); + + /// + /// uint16x4_t vset_lane_u16 (uint16_t a, uint16x4_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, ushort data) => Insert(vector, index, data); + + /// + /// uint32x2_t vset_lane_u32 (uint32_t a, uint32x2_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, uint data) => Insert(vector, index, data); + + /// + /// uint8x16_t vsetq_lane_u8 (uint8_t a, uint8x16_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, byte data) => Insert(vector, index, data); + + /// + /// float64x2_t vsetq_lane_f64 (float64_t a, float64x2_t v, const int lane) + /// A32: VMOV.F64 Dd, Dm + /// A64: INS Vd.D[lane], Vn.D[0] + /// + public static Vector128 Insert(Vector128 vector, byte index, double data) => Insert(vector, index, data); + + /// + /// int16x8_t vsetq_lane_s16 (int16_t a, int16x8_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, short data) => Insert(vector, index, data); + + /// + /// int32x4_t vsetq_lane_s32 (int32_t a, int32x4_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, int data) => Insert(vector, index, data); + + /// + /// int64x2_t vsetq_lane_s64 (int64_t a, int64x2_t v, const int lane) + /// A32: VMOV.64 Dd, Rt, Rt2 + /// A64: INS Vd.D[lane], Xn + /// + public static Vector128 Insert(Vector128 vector, byte index, long data) => Insert(vector, index, data); + + /// + /// int8x16_t vsetq_lane_s8 (int8_t a, int8x16_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, sbyte data) => Insert(vector, index, data); + + /// + /// float32x4_t vsetq_lane_f32 (float32_t a, float32x4_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: INS Vd.S[lane], Vn.S[0] + /// + public static Vector128 Insert(Vector128 vector, byte index, float data) => Insert(vector, index, data); + + /// + /// uint16x8_t vsetq_lane_u16 (uint16_t a, uint16x8_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, ushort data) => Insert(vector, index, data); + + /// + /// uint32x4_t vsetq_lane_u32 (uint32_t a, uint32x4_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, uint data) => Insert(vector, index, data); + + /// + /// uint64x2_t vsetq_lane_u64 (uint64_t a, uint64x2_t v, const int lane) + /// A32: VMOV.64 Dd, Rt, Rt2 + /// A64: INS Vd.D[lane], Xn + /// + public static Vector128 Insert(Vector128 vector, byte index, ulong data) => Insert(vector, index, data); + + /// + /// int16x4_t vcls_s16 (int16x4_t a) + /// A32: VCLS.S16 Dd, Dm + /// A64: CLS Vd.4H, Vn.4H + /// + public static Vector64 LeadingSignCount(Vector64 value) => LeadingSignCount(value); + + /// + /// int32x2_t vcls_s32 (int32x2_t a) + /// A32: VCLS.S32 Dd, Dm + /// A64: CLS Vd.2S, Vn.2S + /// + public static Vector64 LeadingSignCount(Vector64 value) => LeadingSignCount(value); + + /// + /// int8x8_t vcls_s8 (int8x8_t a) + /// A32: VCLS.S8 Dd, Dm + /// A64: CLS Vd.8B, Vn.8B + /// + public static Vector64 LeadingSignCount(Vector64 value) => LeadingSignCount(value); + + /// + /// int16x8_t vclsq_s16 (int16x8_t a) + /// A32: VCLS.S16 Qd, Qm + /// A64: CLS Vd.8H, Vn.8H + /// + public static Vector128 LeadingSignCount(Vector128 value) => LeadingSignCount(value); + + /// + /// int32x4_t vclsq_s32 (int32x4_t a) + /// A32: VCLS.S32 Qd, Qm + /// A64: CLS Vd.4S, Vn.4S + /// + public static Vector128 LeadingSignCount(Vector128 value) => LeadingSignCount(value); + + /// + /// int8x16_t vclsq_s8 (int8x16_t a) + /// A32: VCLS.S8 Qd, Qm + /// A64: CLS Vd.16B, Vn.16B + /// + public static Vector128 LeadingSignCount(Vector128 value) => LeadingSignCount(value); + + /// + /// uint8x8_t vclz_u8 (uint8x8_t a) + /// A32: VCLZ.I8 Dd, Dm + /// A64: CLZ Vd.8B, Vn.8B + /// + public static Vector64 LeadingZeroCount(Vector64 value) => LeadingZeroCount(value); + + /// + /// int16x4_t vclz_s16 (int16x4_t a) + /// A32: VCLZ.I16 Dd, Dm + /// A64: CLZ Vd.4H, Vn.4H + /// + public static Vector64 LeadingZeroCount(Vector64 value) => LeadingZeroCount(value); + + /// + /// int32x2_t vclz_s32 (int32x2_t a) + /// A32: VCLZ.I32 Dd, Dm + /// A64: CLZ Vd.2S, Vn.2S + /// + public static Vector64 LeadingZeroCount(Vector64 value) => LeadingZeroCount(value); + + /// + /// int8x8_t vclz_s8 (int8x8_t a) + /// A32: VCLZ.I8 Dd, Dm + /// A64: CLZ Vd.8B, Vn.8B + /// + public static Vector64 LeadingZeroCount(Vector64 value) => LeadingZeroCount(value); + + /// + /// uint16x4_t vclz_u16 (uint16x4_t a) + /// A32: VCLZ.I16 Dd, Dm + /// A64: CLZ Vd.4H, Vn.4H + /// + public static Vector64 LeadingZeroCount(Vector64 value) => LeadingZeroCount(value); + + /// + /// uint32x2_t vclz_u32 (uint32x2_t a) + /// A32: VCLZ.I32 Dd, Dm + /// A64: CLZ Vd.2S, Vn.2S + /// + public static Vector64 LeadingZeroCount(Vector64 value) => LeadingZeroCount(value); + + /// + /// uint8x16_t vclzq_u8 (uint8x16_t a) + /// A32: VCLZ.I8 Qd, Qm + /// A64: CLZ Vd.16B, Vn.16B + /// + public static Vector128 LeadingZeroCount(Vector128 value) => LeadingZeroCount(value); + + /// + /// int16x8_t vclzq_s16 (int16x8_t a) + /// A32: VCLZ.I16 Qd, Qm + /// A64: CLZ Vd.8H, Vn.8H + /// + public static Vector128 LeadingZeroCount(Vector128 value) => LeadingZeroCount(value); + + /// + /// int32x4_t vclzq_s32 (int32x4_t a) + /// A32: VCLZ.I32 Qd, Qm + /// A64: CLZ Vd.4S, Vn.4S + /// + public static Vector128 LeadingZeroCount(Vector128 value) => LeadingZeroCount(value); + + /// + /// int8x16_t vclzq_s8 (int8x16_t a) + /// A32: VCLZ.I8 Qd, Qm + /// A64: CLZ Vd.16B, Vn.16B + /// + public static Vector128 LeadingZeroCount(Vector128 value) => LeadingZeroCount(value); + + /// + /// uint16x8_t vclzq_u16 (uint16x8_t a) + /// A32: VCLZ.I16 Qd, Qm + /// A64: CLZ Vd.8H, Vn.8H + /// + public static Vector128 LeadingZeroCount(Vector128 value) => LeadingZeroCount(value); + + /// + /// uint32x4_t vclzq_u32 (uint32x4_t a) + /// A32: VCLZ.I32 Qd, Qm + /// A64: CLZ Vd.4S, Vn.4S + /// + public static Vector128 LeadingZeroCount(Vector128 value) => LeadingZeroCount(value); + + /// + /// uint8x8_t vld1_u8 (uint8_t const * ptr) + /// A32: VLD1.8 Dd, [Rn] + /// A64: LD1 Vt.8B, [Xn] + /// + public static unsafe Vector64 LoadVector64(byte* address) => LoadVector64(address); + + /// + /// float64x1_t vld1_f64 (float64_t const * ptr) + /// A32: VLD1.64 Dd, [Rn] + /// A64: LD1 Vt.1D, [Xn] + /// + public static unsafe Vector64 LoadVector64(double* address) => LoadVector64(address); + + /// + /// int16x4_t vld1_s16 (int16_t const * ptr) + /// A32: VLD1.16 Dd, [Rn] + /// A64: LD1 Vt.4H, [Xn] + /// + public static unsafe Vector64 LoadVector64(short* address) => LoadVector64(address); + + /// + /// int32x2_t vld1_s32 (int32_t const * ptr) + /// A32: VLD1.32 Dd, [Rn] + /// A64: LD1 Vt.2S, [Xn] + /// + public static unsafe Vector64 LoadVector64(int* address) => LoadVector64(address); + + /// + /// int64x1_t vld1_s64 (int64_t const * ptr) + /// A32: VLD1.64 Dd, [Rn] + /// A64: LD1 Vt.1D, [Xn] + /// + public static unsafe Vector64 LoadVector64(long* address) => LoadVector64(address); + + /// + /// int8x8_t vld1_s8 (int8_t const * ptr) + /// A32: VLD1.8 Dd, [Rn] + /// A64: LD1 Vt.8B, [Xn] + /// + public static unsafe Vector64 LoadVector64(sbyte* address) => LoadVector64(address); + + /// + /// float32x2_t vld1_f32 (float32_t const * ptr) + /// A32: VLD1.32 Dd, [Rn] + /// A64: LD1 Vt.2S, [Xn] + /// + public static unsafe Vector64 LoadVector64(float* address) => LoadVector64(address); + + /// + /// uint16x4_t vld1_u16 (uint16_t const * ptr) + /// A32: VLD1.16 Dd, [Rn] + /// A64: LD1 Vt.4H, [Xn] + /// + public static unsafe Vector64 LoadVector64(ushort* address) => LoadVector64(address); + + /// + /// uint32x2_t vld1_u32 (uint32_t const * ptr) + /// A32: VLD1.32 Dd, [Rn] + /// A64: LD1 Vt.2S, [Xn] + /// + public static unsafe Vector64 LoadVector64(uint* address) => LoadVector64(address); + + /// + /// uint64x1_t vld1_u64 (uint64_t const * ptr) + /// A32: VLD1.64 Dd, [Rn] + /// A64: LD1 Vt.1D, [Xn] + /// + public static unsafe Vector64 LoadVector64(ulong* address) => LoadVector64(address); + + /// + /// uint8x16_t vld1q_u8 (uint8_t const * ptr) + /// A32: VLD1.8 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.16B, [Xn] + /// + public static unsafe Vector128 LoadVector128(byte* address) => LoadVector128(address); + + /// + /// float64x2_t vld1q_f64 (float64_t const * ptr) + /// A32: VLD1.64 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.2D, [Xn] + /// + public static unsafe Vector128 LoadVector128(double* address) => LoadVector128(address); + + /// + /// int16x8_t vld1q_s16 (int16_t const * ptr) + /// A32: VLD1.16 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.8H, [Xn] + /// + public static unsafe Vector128 LoadVector128(short* address) => LoadVector128(address); + + /// + /// int32x4_t vld1q_s32 (int32_t const * ptr) + /// A32: VLD1.32 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.4S, [Xn] + /// + public static unsafe Vector128 LoadVector128(int* address) => LoadVector128(address); + + /// + /// int64x2_t vld1q_s64 (int64_t const * ptr) + /// A32: VLD1.64 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.2D, [Xn] + /// + public static unsafe Vector128 LoadVector128(long* address) => LoadVector128(address); + + /// + /// int8x16_t vld1q_s8 (int8_t const * ptr) + /// A32: VLD1.8 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.16B, [Xn] + /// + public static unsafe Vector128 LoadVector128(sbyte* address) => LoadVector128(address); + + /// + /// float32x4_t vld1q_f32 (float32_t const * ptr) + /// A32: VLD1.32 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.4S, [Xn] + /// + public static unsafe Vector128 LoadVector128(float* address) => LoadVector128(address); + + /// + /// uint16x8_t vld1q_s16 (uint16_t const * ptr) + /// A32: VLD1.16 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.8H, [Xn] + /// + public static unsafe Vector128 LoadVector128(ushort* address) => LoadVector128(address); + + /// + /// uint32x4_t vld1q_s32 (uint32_t const * ptr) + /// A32: VLD1.32 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.4S, [Xn] + /// + public static unsafe Vector128 LoadVector128(uint* address) => LoadVector128(address); + + /// + /// uint64x2_t vld1q_u64 (uint64_t const * ptr) + /// A32: VLD1.64 Dd, Dd+1, [Rn] + /// A64: LD1 Vt.2D, [Xn] + /// + public static unsafe Vector128 LoadVector128(ulong* address) => LoadVector128(address); + + /// + /// uint8x8_t vmax_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VMAX.U8 Dd, Dn, Dm + /// A64: UMAX Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Max(Vector64 left, Vector64 right) => Max(left, right); + + /// + /// int16x4_t vmax_s16 (int16x4_t a, int16x4_t b) + /// A32: VMAX.S16 Dd, Dn, Dm + /// A64: SMAX Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Max(Vector64 left, Vector64 right) => Max(left, right); + + /// + /// int32x2_t vmax_s32 (int32x2_t a, int32x2_t b) + /// A32: VMAX.S32 Dd, Dn, Dm + /// A64: SMAX Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Max(Vector64 left, Vector64 right) => Max(left, right); + + /// + /// int8x8_t vmax_s8 (int8x8_t a, int8x8_t b) + /// A32: VMAX.S8 Dd, Dn, Dm + /// A64: SMAX Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Max(Vector64 left, Vector64 right) => Max(left, right); + + /// + /// float32x2_t vmax_f32 (float32x2_t a, float32x2_t b) + /// A32: VMAX.F32 Dd, Dn, Dm + /// A64: FMAX Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Max(Vector64 left, Vector64 right) => Max(left, right); + + /// + /// uint16x4_t vmax_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VMAX.U16 Dd, Dn, Dm + /// A64: UMAX Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Max(Vector64 left, Vector64 right) => Max(left, right); + + /// + /// uint32x2_t vmax_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VMAX.U32 Dd, Dn, Dm + /// A64: UMAX Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Max(Vector64 left, Vector64 right) => Max(left, right); + + /// + /// uint8x16_t vmaxq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VMAX.U8 Qd, Qn, Qm + /// A64: UMAX Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Max(Vector128 left, Vector128 right) => Max(left, right); + + /// + /// int16x8_t vmaxq_s16 (int16x8_t a, int16x8_t b) + /// A32: VMAX.S16 Qd, Qn, Qm + /// A64: SMAX Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 Max(Vector128 left, Vector128 right) => Max(left, right); + + /// + /// int32x4_t vmaxq_s32 (int32x4_t a, int32x4_t b) + /// A32: VMAX.S32 Qd, Qn, Qm + /// A64: SMAX Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Max(Vector128 left, Vector128 right) => Max(left, right); + + /// + /// int8x16_t vmaxq_s8 (int8x16_t a, int8x16_t b) + /// A32: VMAX.S8 Qd, Qn, Qm + /// A64: SMAX Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Max(Vector128 left, Vector128 right) => Max(left, right); + + /// + /// float32x4_t vmaxq_f32 (float32x4_t a, float32x4_t b) + /// A32: VMAX.F32 Qd, Qn, Qm + /// A64: FMAX Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Max(Vector128 left, Vector128 right) => Max(left, right); + + /// + /// uint16x8_t vmaxq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VMAX.U16 Qd, Qn, Qm + /// A64: UMAX Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 Max(Vector128 left, Vector128 right) => Max(left, right); + + /// + /// uint32x4_t vmaxq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VMAX.U32 Qd, Qn, Qm + /// A64: UMAX Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Max(Vector128 left, Vector128 right) => Max(left, right); + + /// + /// float32x2_t vmaxnm_f32 (float32x2_t a, float32x2_t b) + /// A32: VMAXNM.F32 Dd, Dn, Dm + /// A64: FMAXNM Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MaxNumber(Vector64 left, Vector64 right) => MaxNumber(left, right); + + /// + /// float32x4_t vmaxnmq_f32 (float32x4_t a, float32x4_t b) + /// A32: VMAXNM.F32 Qd, Qn, Qm + /// A64: FMAXNM Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MaxNumber(Vector128 left, Vector128 right) => MaxNumber(left, right); + + /// + /// float64x1_t vmaxnm_f64 (float64x1_t a, float64x1_t b) + /// A32: VMAXNM.F64 Dd, Dn, Dm + /// A64: FMAXNM Dd, Dn, Dm + /// + public static Vector64 MaxNumberScalar(Vector64 left, Vector64 right) => MaxNumberScalar(left, right); + + /// + /// float32_t vmaxnms_f32 (float32_t a, float32_t b) + /// A32: VMAXNM.F32 Sd, Sn, Sm + /// A64: FMAXNM Sd, Sn, Sm + /// + public static Vector64 MaxNumberScalar(Vector64 left, Vector64 right) => MaxNumberScalar(left, right); + + /// + /// uint8x8_t vpmax_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VPMAX.U8 Dd, Dn, Dm + /// A64: UMAXP Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MaxPairwise(Vector64 left, Vector64 right) => MaxPairwise(left, right); + + /// + /// int16x4_t vpmax_s16 (int16x4_t a, int16x4_t b) + /// A32: VPMAX.S16 Dd, Dn, Dm + /// A64: SMAXP Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MaxPairwise(Vector64 left, Vector64 right) => MaxPairwise(left, right); + + /// + /// int32x2_t vpmax_s32 (int32x2_t a, int32x2_t b) + /// A32: VPMAX.S32 Dd, Dn, Dm + /// A64: SMAXP Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MaxPairwise(Vector64 left, Vector64 right) => MaxPairwise(left, right); + + /// + /// int8x8_t vpmax_s8 (int8x8_t a, int8x8_t b) + /// A32: VPMAX.S8 Dd, Dn, Dm + /// A64: SMAXP Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MaxPairwise(Vector64 left, Vector64 right) => MaxPairwise(left, right); + + /// + /// float32x2_t vpmax_f32 (float32x2_t a, float32x2_t b) + /// A32: VPMAX.F32 Dd, Dn, Dm + /// A64: FMAXP Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MaxPairwise(Vector64 left, Vector64 right) => MaxPairwise(left, right); + + /// + /// uint16x4_t vpmax_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VPMAX.U16 Dd, Dn, Dm + /// A64: UMAXP Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MaxPairwise(Vector64 left, Vector64 right) => MaxPairwise(left, right); + + /// + /// uint32x2_t vpmax_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VPMAX.U32 Dd, Dn, Dm + /// A64: UMAXP Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MaxPairwise(Vector64 left, Vector64 right) => MaxPairwise(left, right); + + /// + /// uint8x8_t vmin_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VMIN.U8 Dd, Dn, Dm + /// A64: UMIN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Min(Vector64 left, Vector64 right) => Min(left, right); + + /// + /// int16x4_t vmin_s16 (int16x4_t a, int16x4_t b) + /// A32: VMIN.S16 Dd, Dn, Dm + /// A64: SMIN Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Min(Vector64 left, Vector64 right) => Min(left, right); + + /// + /// int32x2_t vmin_s32 (int32x2_t a, int32x2_t b) + /// A32: VMIN.S32 Dd, Dn, Dm + /// A64: SMIN Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Min(Vector64 left, Vector64 right) => Min(left, right); + + /// + /// int8x8_t vmin_s8 (int8x8_t a, int8x8_t b) + /// A32: VMIN.S8 Dd, Dn, Dm + /// A64: SMIN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Min(Vector64 left, Vector64 right) => Min(left, right); + + /// + /// float32x2_t vmin_f32 (float32x2_t a, float32x2_t b) + /// A32: VMIN.F32 Dd, Dn, Dm + /// A64: FMIN Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Min(Vector64 left, Vector64 right) => Min(left, right); + + /// + /// uint16x4_t vmin_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VMIN.U16 Dd, Dn, Dm + /// A64: UMIN Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Min(Vector64 left, Vector64 right) => Min(left, right); + + /// + /// uint32x2_t vmin_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VMIN.U32 Dd, Dn, Dm + /// A64: UMIN Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Min(Vector64 left, Vector64 right) => Min(left, right); + + /// + /// uint8x16_t vminq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VMIN.U8 Qd, Qn, Qm + /// A64: UMIN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Min(Vector128 left, Vector128 right) => Min(left, right); + + /// + /// int16x8_t vminq_s16 (int16x8_t a, int16x8_t b) + /// A32: VMIN.S16 Qd, Qn, Qm + /// A64: SMIN Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 Min(Vector128 left, Vector128 right) => Min(left, right); + + /// + /// int32x4_t vminq_s32 (int32x4_t a, int32x4_t b) + /// A32: VMIN.S32 Qd, Qn, Qm + /// A64: SMIN Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Min(Vector128 left, Vector128 right) => Min(left, right); + + /// + /// int8x16_t vminq_s8 (int8x16_t a, int8x16_t b) + /// A32: VMIN.S8 Qd, Qn, Qm + /// A64: SMIN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Min(Vector128 left, Vector128 right) => Min(left, right); + + /// + /// float32x4_t vminq_f32 (float32x4_t a, float32x4_t b) + /// A32: VMIN.F32 Qd, Qn, Qm + /// A64: FMIN Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Min(Vector128 left, Vector128 right) => Min(left, right); + + /// + /// uint16x8_t vminq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VMIN.U16 Qd, Qn, Qm + /// A64: UMIN Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 Min(Vector128 left, Vector128 right) => Min(left, right); + + /// + /// uint32x4_t vminq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VMIN.U32 Qd, Qn, Qm + /// A64: UMIN Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Min(Vector128 left, Vector128 right) => Min(left, right); + + /// + /// float32x2_t vminnm_f32 (float32x2_t a, float32x2_t b) + /// A32: VMINNM.F32 Dd, Dn, Dm + /// A64: FMINNM Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MinNumber(Vector64 left, Vector64 right) => MinNumber(left, right); + + /// + /// float32x4_t vminnmq_f32 (float32x4_t a, float32x4_t b) + /// A32: VMINNM.F32 Qd, Qn, Qm + /// A64: FMINNM Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MinNumber(Vector128 left, Vector128 right) => MinNumber(left, right); + + /// + /// float64x1_t vminnm_f64 (float64x1_t a, float64x1_t b) + /// A32: VMINNM.F64 Dd, Dn, Dm + /// A64: FMINNM Dd, Dn, Dm + /// + public static Vector64 MinNumberScalar(Vector64 left, Vector64 right) => MinNumberScalar(left, right); + + /// + /// float32_t vminnms_f32 (float32_t a, float32_t b) + /// A32: VMINNM.F32 Sd, Sn, Sm + /// A64: FMINNM Sd, Sn, Sm + /// + public static Vector64 MinNumberScalar(Vector64 left, Vector64 right) => MinNumberScalar(left, right); + + /// + /// uint8x8_t vpmin_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VPMIN.U8 Dd, Dn, Dm + /// A64: UMINP Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MinPairwise(Vector64 left, Vector64 right) => MinPairwise(left, right); + + /// + /// int16x4_t vpmin_s16 (int16x4_t a, int16x4_t b) + /// A32: VPMIN.S16 Dd, Dn, Dm + /// A64: SMINP Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MinPairwise(Vector64 left, Vector64 right) => MinPairwise(left, right); + + /// + /// int32x2_t vpmin_s32 (int32x2_t a, int32x2_t b) + /// A32: VPMIN.S32 Dd, Dn, Dm + /// A64: SMINP Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MinPairwise(Vector64 left, Vector64 right) => MinPairwise(left, right); + + /// + /// int8x8_t vpmin_s8 (int8x8_t a, int8x8_t b) + /// A32: VPMIN.S8 Dd, Dn, Dm + /// A64: SMINP Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MinPairwise(Vector64 left, Vector64 right) => MinPairwise(left, right); + + /// + /// float32x2_t vpmin_f32 (float32x2_t a, float32x2_t b) + /// A32: VPMIN.F32 Dd, Dn, Dm + /// A64: FMINP Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MinPairwise(Vector64 left, Vector64 right) => MinPairwise(left, right); + + /// + /// uint16x4_t vpmin_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VPMIN.U16 Dd, Dn, Dm + /// A64: UMINP Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MinPairwise(Vector64 left, Vector64 right) => MinPairwise(left, right); + + /// + /// uint32x2_t vpmin_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VPMIN.U32 Dd, Dn, Dm + /// A64: UMINP Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MinPairwise(Vector64 left, Vector64 right) => MinPairwise(left, right); + + /// + /// uint8x8_t vmul_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VMUL.I8 Dd, Dn, Dm + /// A64: MUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Multiply(Vector64 left, Vector64 right) => Multiply(left, right); + + /// + /// int16x4_t vmul_s16 (int16x4_t a, int16x4_t b) + /// A32: VMUL.I16 Dd, Dn, Dm + /// A64: MUL Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Multiply(Vector64 left, Vector64 right) => Multiply(left, right); + + /// + /// int32x2_t vmul_s32 (int32x2_t a, int32x2_t b) + /// A32: VMUL.I32 Dd, Dn, Dm + /// A64: MUL Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Multiply(Vector64 left, Vector64 right) => Multiply(left, right); + + /// + /// int8x8_t vmul_s8 (int8x8_t a, int8x8_t b) + /// A32: VMUL.I8 Dd, Dn, Dm + /// A64: MUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Multiply(Vector64 left, Vector64 right) => Multiply(left, right); + + /// + /// float32x2_t vmul_f32 (float32x2_t a, float32x2_t b) + /// A32: VMUL.F32 Dd, Dn, Dm + /// A64: FMUL Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Multiply(Vector64 left, Vector64 right) => Multiply(left, right); + + /// + /// uint16x4_t vmul_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VMUL.I16 Dd, Dn, Dm + /// A64: MUL Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 Multiply(Vector64 left, Vector64 right) => Multiply(left, right); + + /// + /// uint32x2_t vmul_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VMUL.I32 Dd, Dn, Dm + /// A64: MUL Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 Multiply(Vector64 left, Vector64 right) => Multiply(left, right); + + /// + /// uint8x16_t vmulq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VMUL.I8 Qd, Qn, Qm + /// A64: MUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + + /// + /// int16x8_t vmulq_s16 (int16x8_t a, int16x8_t b) + /// A32: VMUL.I16 Qd, Qn, Qm + /// A64: MUL Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + + /// + /// int32x4_t vmulq_s32 (int32x4_t a, int32x4_t b) + /// A32: VMUL.I32 Qd, Qn, Qm + /// A64: MUL Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + + /// + /// int8x16_t vmulq_s8 (int8x16_t a, int8x16_t b) + /// A32: VMUL.I8 Qd, Qn, Qm + /// A64: MUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + + /// + /// float32x4_t vmulq_f32 (float32x4_t a, float32x4_t b) + /// A32: VMUL.F32 Qd, Qn, Qm + /// A64: FMUL Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + + /// + /// uint16x8_t vmulq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VMUL.I16 Qd, Qn, Qm + /// A64: MUL Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + + /// + /// uint32x4_t vmulq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VMUL.I32 Qd, Qn, Qm + /// A64: MUL Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + + /// + /// float64x1_t vmul_f64 (float64x1_t a, float64x1_t b) + /// A32: VMUL.F64 Dd, Dn, Dm + /// A64: FMUL Dd, Dn, Dm + /// + public static Vector64 MultiplyScalar(Vector64 left, Vector64 right) => MultiplyScalar(left, right); + + /// + /// float32_t vmuls_f32 (float32_t a, float32_t b) + /// A32: VMUL.F32 Sd, Sn, Sm + /// A64: FMUL Sd, Sn, Sm + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 MultiplyScalar(Vector64 left, Vector64 right) => MultiplyScalar(left, right); + + /// + /// uint8x8_t vmla_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VMLA.I8 Dd, Dn, Dm + /// A64: MLA Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) => MultiplyAdd(acc, left, right); + + /// + /// int16x4_t vmla_s16 (int16x4_t a, int16x4_t b, int16x4_t c) + /// A32: VMLA.I16 Dd, Dn, Dm + /// A64: MLA Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) => MultiplyAdd(acc, left, right); + + /// + /// int32x2_t vmla_s32 (int32x2_t a, int32x2_t b, int32x2_t c) + /// A32: VMLA.I32 Dd, Dn, Dm + /// A64: MLA Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) => MultiplyAdd(acc, left, right); + + /// + /// int8x8_t vmla_s8 (int8x8_t a, int8x8_t b, int8x8_t c) + /// A32: VMLA.I8 Dd, Dn, Dm + /// A64: MLA Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) => MultiplyAdd(acc, left, right); + + /// + /// uint16x4_t vmla_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VMLA.I16 Dd, Dn, Dm + /// A64: MLA Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) => MultiplyAdd(acc, left, right); + + /// + /// uint32x2_t vmla_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VMLA.I32 Dd, Dn, Dm + /// A64: MLA Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) => MultiplyAdd(acc, left, right); + + /// + /// uint8x16_t vmlaq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) + /// A32: VMLA.I8 Qd, Qn, Qm + /// A64: MLA Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => MultiplyAdd(acc, left, right); + + /// + /// int16x8_t vmlaq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) + /// A32: VMLA.I16 Qd, Qn, Qm + /// A64: MLA Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => MultiplyAdd(acc, left, right); + + /// + /// int32x4_t vmlaq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) + /// A32: VMLA.I32 Qd, Qn, Qm + /// A64: MLA Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => MultiplyAdd(acc, left, right); + + /// + /// int8x16_t vmlaq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) + /// A32: VMLA.I8 Qd, Qn, Qm + /// A64: MLA Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => MultiplyAdd(acc, left, right); + + /// + /// uint16x8_t vmlaq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) + /// A32: VMLA.I16 Qd, Qn, Qm + /// A64: MLA Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => MultiplyAdd(acc, left, right); + + /// + /// uint32x4_t vmlaq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) + /// A32: VMLA.I32 Qd, Qn, Qm + /// A64: MLA Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => MultiplyAdd(acc, left, right); + + /// + /// uint8x8_t vmls_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VMLS.I8 Dd, Dn, Dm + /// A64: MLS Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) => MultiplySubtract(acc, left, right); + + /// + /// int16x4_t vmls_s16 (int16x4_t a, int16x4_t b, int16x4_t c) + /// A32: VMLS.I16 Dd, Dn, Dm + /// A64: MLS Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) => MultiplySubtract(acc, left, right); + + /// + /// int32x2_t vmls_s32 (int32x2_t a, int32x2_t b, int32x2_t c) + /// A32: VMLS.I32 Dd, Dn, Dm + /// A64: MLS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) => MultiplySubtract(acc, left, right); + + /// + /// int8x8_t vmls_s8 (int8x8_t a, int8x8_t b, int8x8_t c) + /// A32: VMLS.I8 Dd, Dn, Dm + /// A64: MLS Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) => MultiplySubtract(acc, left, right); + + /// + /// uint16x4_t vmls_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VMLS.I16 Dd, Dn, Dm + /// A64: MLS Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) => MultiplySubtract(acc, left, right); + + /// + /// uint32x2_t vmls_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VMLS.I32 Dd, Dn, Dm + /// A64: MLS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) => MultiplySubtract(acc, left, right); + + /// + /// uint8x16_t vmlsq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) + /// A32: VMLS.I8 Qd, Qn, Qm + /// A64: MLS Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => MultiplySubtract(acc, left, right); + + /// + /// int16x8_t vmlsq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) + /// A32: VMLS.I16 Qd, Qn, Qm + /// A64: MLS Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => MultiplySubtract(acc, left, right); + + /// + /// int32x4_t vmlsq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) + /// A32: VMLS.I32 Qd, Qn, Qm + /// A64: MLS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => MultiplySubtract(acc, left, right); + + /// + /// int8x16_t vmlsq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) + /// A32: VMLS.I8 Qd, Qn, Qm + /// A64: MLS Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => MultiplySubtract(acc, left, right); + + /// + /// uint16x8_t vmlsq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) + /// A32: VMLS.I16 Qd, Qn, Qm + /// A64: MLS Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => MultiplySubtract(acc, left, right); + + /// + /// uint32x4_t vmlsq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) + /// A32: VMLS.I32 Qd, Qn, Qm + /// A64: MLS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => MultiplySubtract(acc, left, right); + + /// + /// uint16x8_t vmull_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VMULL.U8 Qd, Dn, Dm + /// A64: UMULL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 MultiplyWideningLower(Vector64 left, Vector64 right) => MultiplyWideningLower(left, right); + + /// + /// int32x4_t vmull_s16 (int16x4_t a, int16x4_t b) + /// A32: VMULL.S16 Qd, Dn, Dm + /// A64: SMULL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 MultiplyWideningLower(Vector64 left, Vector64 right) => MultiplyWideningLower(left, right); + + /// + /// int64x2_t vmull_s32 (int32x2_t a, int32x2_t b) + /// A32: VMULL.S32 Qd, Dn, Dm + /// A64: SMULL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 MultiplyWideningLower(Vector64 left, Vector64 right) => MultiplyWideningLower(left, right); + + /// + /// int16x8_t vmull_s8 (int8x8_t a, int8x8_t b) + /// A32: VMULL.S8 Qd, Dn, Dm + /// A64: SMULL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 MultiplyWideningLower(Vector64 left, Vector64 right) => MultiplyWideningLower(left, right); + + /// + /// uint32x4_t vmull_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VMULL.U16 Qd, Dn, Dm + /// A64: UMULL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 MultiplyWideningLower(Vector64 left, Vector64 right) => MultiplyWideningLower(left, right); + + /// + /// uint64x2_t vmull_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VMULL.U32 Qd, Dn, Dm + /// A64: UMULL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 MultiplyWideningLower(Vector64 left, Vector64 right) => MultiplyWideningLower(left, right); + + /// + /// uint16x8_t vmlal_u8 (uint16x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VMLAL.U8 Qd, Dn, Dm + /// A64: UMLAL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 MultiplyWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) => MultiplyWideningLowerAndAdd(addend, left, right); + + /// + /// int32x4_t vmlal_s16 (int32x4_t a, int16x4_t b, int16x4_t c) + /// A32: VMLAL.S16 Qd, Dn, Dm + /// A64: SMLAL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 MultiplyWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) => MultiplyWideningLowerAndAdd(addend, left, right); + + /// + /// int64x2_t vmlal_s32 (int64x2_t a, int32x2_t b, int32x2_t c) + /// A32: VMLAL.S32 Qd, Dn, Dm + /// A64: SMLAL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 MultiplyWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) => MultiplyWideningLowerAndAdd(addend, left, right); + + /// + /// int16x8_t vmlal_s8 (int16x8_t a, int8x8_t b, int8x8_t c) + /// A32: VMLAL.S8 Qd, Dn, Dm + /// A64: SMLAL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 MultiplyWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) => MultiplyWideningLowerAndAdd(addend, left, right); + + /// + /// uint32x4_t vmlal_u16 (uint32x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VMLAL.U16 Qd, Dn, Dm + /// A64: UMLAL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 MultiplyWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) => MultiplyWideningLowerAndAdd(addend, left, right); + + /// + /// uint64x2_t vmlal_u32 (uint64x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VMLAL.U32 Qd, Dn, Dm + /// A64: UMLAL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 MultiplyWideningLowerAndAdd(Vector128 addend, Vector64 left, Vector64 right) => MultiplyWideningLowerAndAdd(addend, left, right); + + /// + /// uint16x8_t vmlsl_u8 (uint16x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VMLSL.U8 Qd, Dn, Dm + /// A64: UMLSL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 MultiplyWideningLowerAndSubtract(Vector128 minuend, Vector64 left, Vector64 right) => MultiplyWideningLowerAndSubtract(minuend, left, right); + + /// + /// int32x4_t vmlsl_s16 (int32x4_t a, int16x4_t b, int16x4_t c) + /// A32: VMLSL.S16 Qd, Dn, Dm + /// A64: SMLSL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 MultiplyWideningLowerAndSubtract(Vector128 minuend, Vector64 left, Vector64 right) => MultiplyWideningLowerAndSubtract(minuend, left, right); + + /// + /// int64x2_t vmlsl_s32 (int64x2_t a, int32x2_t b, int32x2_t c) + /// A32: VMLSL.S32 Qd, Dn, Dm + /// A64: SMLSL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 MultiplyWideningLowerAndSubtract(Vector128 minuend, Vector64 left, Vector64 right) => MultiplyWideningLowerAndSubtract(minuend, left, right); + + /// + /// int16x8_t vmlsl_s8 (int16x8_t a, int8x8_t b, int8x8_t c) + /// A32: VMLSL.S8 Qd, Dn, Dm + /// A64: SMLSL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 MultiplyWideningLowerAndSubtract(Vector128 minuend, Vector64 left, Vector64 right) => MultiplyWideningLowerAndSubtract(minuend, left, right); + + /// + /// uint32x4_t vmlsl_u16 (uint32x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VMLSL.U16 Qd, Dn, Dm + /// A64: UMLSL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 MultiplyWideningLowerAndSubtract(Vector128 minuend, Vector64 left, Vector64 right) => MultiplyWideningLowerAndSubtract(minuend, left, right); + + /// + /// uint64x2_t vmlsl_u32 (uint64x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VMLSL.U32 Qd, Dn, Dm + /// A64: UMLSL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 MultiplyWideningLowerAndSubtract(Vector128 minuend, Vector64 left, Vector64 right) => MultiplyWideningLowerAndSubtract(minuend, left, right); + + /// + /// uint16x8_t vmull_high_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VMULL.U8 Qd, Dn+1, Dm+1 + /// A64: UMULL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) => MultiplyWideningUpper(left, right); + + /// + /// int32x4_t vmull_high_s16 (int16x8_t a, int16x8_t b) + /// A32: VMULL.S16 Qd, Dn+1, Dm+1 + /// A64: SMULL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) => MultiplyWideningUpper(left, right); + + /// + /// int64x2_t vmull_high_s32 (int32x4_t a, int32x4_t b) + /// A32: VMULL.S32 Qd, Dn+1, Dm+1 + /// A64: SMULL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) => MultiplyWideningUpper(left, right); + + /// + /// int16x8_t vmull_high_s8 (int8x16_t a, int8x16_t b) + /// A32: VMULL.S8 Qd, Dn+1, Dm+1 + /// A64: SMULL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) => MultiplyWideningUpper(left, right); + + /// + /// uint32x4_t vmull_high_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VMULL.U16 Qd, Dn+1, Dm+1 + /// A64: UMULL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) => MultiplyWideningUpper(left, right); + + /// + /// uint64x2_t vmull_high_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VMULL.U32 Qd, Dn+1, Dm+1 + /// A64: UMULL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyWideningUpper(Vector128 left, Vector128 right) => MultiplyWideningUpper(left, right); + + /// + /// uint16x8_t vmlal_high_u8 (uint16x8_t a, uint8x16_t b, uint8x16_t c) + /// A32: VMLAL.U8 Qd, Dn+1, Dm+1 + /// A64: UMLAL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) => MultiplyWideningUpperAndAdd(addend, left, right); + + /// + /// int32x4_t vmlal_high_s16 (int32x4_t a, int16x8_t b, int16x8_t c) + /// A32: VMLAL.S16 Qd, Dn+1, Dm+1 + /// A64: SMLAL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) => MultiplyWideningUpperAndAdd(addend, left, right); + + /// + /// int64x2_t vmlal_high_s32 (int64x2_t a, int32x4_t b, int32x4_t c) + /// A32: VMLAL.S32 Qd, Dn+1, Dm+1 + /// A64: SMLAL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) => MultiplyWideningUpperAndAdd(addend, left, right); + + /// + /// int16x8_t vmlal_high_s8 (int16x8_t a, int8x16_t b, int8x16_t c) + /// A32: VMLAL.S8 Qd, Dn+1, Dm+1 + /// A64: SMLAL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) => MultiplyWideningUpperAndAdd(addend, left, right); + + /// + /// uint32x4_t vmlal_high_u16 (uint32x4_t a, uint16x8_t b, uint16x8_t c) + /// A32: VMLAL.U16 Qd, Dn+1, Dm+1 + /// A64: UMLAL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) => MultiplyWideningUpperAndAdd(addend, left, right); + + /// + /// uint64x2_t vmlal_high_u32 (uint64x2_t a, uint32x4_t b, uint32x4_t c) + /// A32: VMLAL.U32 Qd, Dn+1, Dm+1 + /// A64: UMLAL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyWideningUpperAndAdd(Vector128 addend, Vector128 left, Vector128 right) => MultiplyWideningUpperAndAdd(addend, left, right); + + /// + /// uint16x8_t vmlsl_high_u8 (uint16x8_t a, uint8x16_t b, uint8x16_t c) + /// A32: VMLSL.U8 Qd, Dn+1, Dm+1 + /// A64: UMLSL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyWideningUpperAndSubtract(Vector128 minuend, Vector128 left, Vector128 right) => MultiplyWideningUpperAndSubtract(minuend, left, right); + + /// + /// int32x4_t vmlsl_high_s16 (int32x4_t a, int16x8_t b, int16x8_t c) + /// A32: VMLSL.S16 Qd, Dn+1, Dm+1 + /// A64: SMLSL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyWideningUpperAndSubtract(Vector128 minuend, Vector128 left, Vector128 right) => MultiplyWideningUpperAndSubtract(minuend, left, right); + + /// + /// int64x2_t vmlsl_high_s32 (int64x2_t a, int32x4_t b, int32x4_t c) + /// A32: VMLSL.S32 Qd, Dn+1, Dm+1 + /// A64: SMLSL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyWideningUpperAndSubtract(Vector128 minuend, Vector128 left, Vector128 right) => MultiplyWideningUpperAndSubtract(minuend, left, right); + + /// + /// int16x8_t vmlsl_high_s8 (int16x8_t a, int8x16_t b, int8x16_t c) + /// A32: VMLSL.S8 Qd, Dn+1, Dm+1 + /// A64: SMLSL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 MultiplyWideningUpperAndSubtract(Vector128 minuend, Vector128 left, Vector128 right) => MultiplyWideningUpperAndSubtract(minuend, left, right); + + /// + /// uint32x4_t vmlsl_high_u16 (uint32x4_t a, uint16x8_t b, uint16x8_t c) + /// A32: VMLSL.U16 Qd, Dn+1, Dm+1 + /// A64: UMLSL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 MultiplyWideningUpperAndSubtract(Vector128 minuend, Vector128 left, Vector128 right) => MultiplyWideningUpperAndSubtract(minuend, left, right); + + /// + /// uint64x2_t vmlsl_high_u32 (uint64x2_t a, uint32x4_t b, uint32x4_t c) + /// A32: VMLSL.U32 Qd, Dn+1, Dm+1 + /// A64: UMLSL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyWideningUpperAndSubtract(Vector128 minuend, Vector128 left, Vector128 right) => MultiplyWideningUpperAndSubtract(minuend, left, right); + + /// + /// int16x4_t vneg_s16 (int16x4_t a) + /// A32: VNEG.S16 Dd, Dm + /// A64: NEG Vd.4H, Vn.4H + /// + public static Vector64 Negate(Vector64 value) => Negate(value); + + /// + /// int32x2_t vneg_s32 (int32x2_t a) + /// A32: VNEG.S32 Dd, Dm + /// A64: NEG Vd.2S, Vn.2S + /// + public static Vector64 Negate(Vector64 value) => Negate(value); + + /// + /// int8x8_t vneg_s8 (int8x8_t a) + /// A32: VNEG.S8 Dd, Dm + /// A64: NEG Vd.8B, Vn.8B + /// + public static Vector64 Negate(Vector64 value) => Negate(value); + + /// + /// float32x2_t vneg_f32 (float32x2_t a) + /// A32: VNEG.F32 Dd, Dm + /// A64: FNEG Vd.2S, Vn.2S + /// + public static Vector64 Negate(Vector64 value) => Negate(value); + + /// + /// int16x8_t vnegq_s16 (int16x8_t a) + /// A32: VNEG.S16 Qd, Qm + /// A64: NEG Vd.8H, Vn.8H + /// + public static Vector128 Negate(Vector128 value) => Negate(value); + + /// + /// int32x4_t vnegq_s32 (int32x4_t a) + /// A32: VNEG.S32 Qd, Qm + /// A64: NEG Vd.4S, Vn.4S + /// + public static Vector128 Negate(Vector128 value) => Negate(value); + + /// + /// int8x16_t vnegq_s8 (int8x16_t a) + /// A32: VNEG.S8 Qd, Qm + /// A64: NEG Vd.16B, Vn.16B + /// + public static Vector128 Negate(Vector128 value) => Negate(value); + + /// + /// float32x4_t vnegq_f32 (float32x4_t a) + /// A32: VNEG.F32 Qd, Qm + /// A64: FNEG Vd.4S, Vn.4S + /// + public static Vector128 Negate(Vector128 value) => Negate(value); + + /// + /// float64x1_t vneg_f64 (float64x1_t a) + /// A32: VNEG.F64 Dd, Dm + /// A64: FNEG Dd, Dn + /// + public static Vector64 NegateScalar(Vector64 value) => NegateScalar(value); + + /// + /// float32_t vnegs_f32 (float32_t a) + /// A32: VNEG.F32 Sd, Sm + /// A64: FNEG Sd, Sn + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 NegateScalar(Vector64 value) => NegateScalar(value); + + /// + /// uint8x8_t vmvn_u8 (uint8x8_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) => Not(value); + + /// + /// float64x1_t vmvn_f64 (float64x1_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 Not(Vector64 value) => Not(value); + + /// + /// int16x4_t vmvn_s16 (int16x4_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) => Not(value); + + /// + /// int32x2_t vmvn_s32 (int32x2_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) => Not(value); + + /// + /// int64x1_t vmvn_s64 (int64x1_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) => Not(value); + + /// + /// int8x8_t vmvn_s8 (int8x8_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) => Not(value); + + /// + /// float32x2_t vmvn_f32 (float32x2_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 Not(Vector64 value) => Not(value); + + /// + /// uint16x4_t vmvn_u16 (uint16x4_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) => Not(value); + + /// + /// uint32x2_t vmvn_u32 (uint32x2_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) => Not(value); + + /// + /// uint64x1_t vmvn_u64 (uint64x1_t a) + /// A32: VMVN Dd, Dm + /// A64: MVN Vd.8B, Vn.8B + /// + public static Vector64 Not(Vector64 value) => Not(value); + + /// + /// uint8x16_t vmvnq_u8 (uint8x16_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) => Not(value); + + /// + /// float64x2_t vmvnq_f64 (float64x2_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 Not(Vector128 value) => Not(value); + + /// + /// int16x8_t vmvnq_s16 (int16x8_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) => Not(value); + + /// + /// int32x4_t vmvnq_s32 (int32x4_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) => Not(value); + + /// + /// int64x2_t vmvnq_s64 (int64x2_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) => Not(value); + + /// + /// int8x16_t vmvnq_s8 (int8x16_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) => Not(value); + + /// + /// float32x4_t vmvnq_f32 (float32x4_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 Not(Vector128 value) => Not(value); + + /// + /// uint16x8_t vmvnq_u16 (uint16x8_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) => Not(value); + + /// + /// uint32x4_t vmvnq_u32 (uint32x4_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) => Not(value); + + /// + /// uint64x2_t vmvnq_u64 (uint64x2_t a) + /// A32: VMVN Qd, Qm + /// A64: MVN Vd.16B, Vn.16B + /// + public static Vector128 Not(Vector128 value) => Not(value); + + /// + /// uint8x8_t vorr_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + + /// + /// float64x1_t vorr_f64 (float64x1_t a, float64x1_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + + /// + /// int16x4_t vorr_s16 (int16x4_t a, int16x4_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + + /// + /// int32x2_t vorr_s32 (int32x2_t a, int32x2_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + + /// + /// int64x1_t vorr_s64 (int64x1_t a, int64x1_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + + /// + /// int8x8_t vorr_s8 (int8x8_t a, int8x8_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + + /// + /// float32x2_t vorr_f32 (float32x2_t a, float32x2_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + + /// + /// uint16x4_t vorr_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + + /// + /// uint32x2_t vorr_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + + /// + /// uint64x1_t vorr_u64 (uint64x1_t a, uint64x1_t b) + /// A32: VORR Dd, Dn, Dm + /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + + /// + /// uint8x16_t vorrq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + + /// + /// float64x2_t vorrq_f64 (float64x2_t a, float64x2_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + + /// + /// int16x8_t vorrq_s16 (int16x8_t a, int16x8_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + + /// + /// int32x4_t vorrq_s32 (int32x4_t a, int32x4_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + + /// + /// int64x2_t vorrq_s64 (int64x2_t a, int64x2_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + + /// + /// int8x16_t vorrq_s8 (int8x16_t a, int8x16_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + + /// + /// float32x4_t vorrq_f32 (float32x4_t a, float32x4_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + + /// + /// uint16x8_t vorrq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + + /// + /// uint32x4_t vorrq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + + /// + /// uint64x2_t vorrq_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VORR Qd, Qn, Qm + /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + + /// + /// uint8x8_t vorn_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + + /// + /// float64x1_t vorn_f64 (float64x1_t a, float64x1_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + + /// + /// int16x4_t vorn_s16 (int16x4_t a, int16x4_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + + /// + /// int32x2_t vorn_s32 (int32x2_t a, int32x2_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + + /// + /// int64x1_t vorn_s64 (int64x1_t a, int64x1_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + + /// + /// int8x8_t vorn_s8 (int8x8_t a, int8x8_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + + /// + /// float32x2_t vorn_f32 (float32x2_t a, float32x2_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + + /// + /// uint16x4_t vorn_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + + /// + /// uint32x2_t vorn_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + + /// + /// uint64x1_t vorn_u64 (uint64x1_t a, uint64x1_t b) + /// A32: VORN Dd, Dn, Dm + /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + + /// + /// uint8x16_t vornq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + + /// + /// float64x2_t vornq_f64 (float64x2_t a, float64x2_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + + /// + /// int16x8_t vornq_s16 (int16x8_t a, int16x8_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + + /// + /// int32x4_t vornq_s32 (int32x4_t a, int32x4_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + + /// + /// int64x2_t vornq_s64 (int64x2_t a, int64x2_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + + /// + /// int8x16_t vornq_s8 (int8x16_t a, int8x16_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + + /// + /// float32x4_t vornq_f32 (float32x4_t a, float32x4_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + + /// + /// uint16x8_t vornq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + + /// + /// uint32x4_t vornq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + + /// + /// uint64x2_t vornq_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VORN Qd, Qn, Qm + /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + + /// + /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMUL.P8 Dd, Dn, Dm + /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) => PolynomialMultiply(left, right); + + /// + /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMUL.P8 Dd, Dn, Dm + /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) => PolynomialMultiply(left, right); + + /// + /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMUL.P8 Qd, Qn, Qm + /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) => PolynomialMultiply(left, right); + + /// + /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMUL.P8 Qd, Qn, Qm + /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) => PolynomialMultiply(left, right); + + /// + /// poly16x8_t vmull_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMULL.P8 Qd, Dn, Dm + /// A64: PMULL Vd.16B, Vn.8B, Vm.8B + /// + public static Vector128 PolynomialMultiplyWideningLower(Vector64 left, Vector64 right) => PolynomialMultiplyWideningLower(left, right); + + /// + /// poly16x8_t vmull_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMULL.P8 Qd, Dn, Dm + /// A64: PMULL Vd.16B, Vn.8B, Vm.8B + /// + public static Vector128 PolynomialMultiplyWideningLower(Vector64 left, Vector64 right) => PolynomialMultiplyWideningLower(left, right); + + /// + /// poly16x8_t vmull_high_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMULL.P8 Qd, Dn+1, Dm+1 + /// A64: PMULL2 Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiplyWideningUpper(Vector128 left, Vector128 right) => PolynomialMultiplyWideningUpper(left, right); + + /// + /// poly16x8_t vmull_high_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMULL.P8 Qd, Dn+1, Dm+1 + /// A64: PMULL2 Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiplyWideningUpper(Vector128 left, Vector128 right) => PolynomialMultiplyWideningUpper(left, right); + + /// + /// uint8x8_t vcnt_u8 (uint8x8_t a) + /// A32: VCNT.I8 Dd, Dm + /// A64: CNT Vd.8B, Vn.8B + /// + public static Vector64 PopCount(Vector64 value) => PopCount(value); + + /// + /// int8x8_t vcnt_s8 (int8x8_t a) + /// A32: VCNT.I8 Dd, Dm + /// A64: CNT Vd.8B, Vn.8B + /// + public static Vector64 PopCount(Vector64 value) => PopCount(value); + + /// + /// uint8x16_t vcntq_u8 (uint8x16_t a) + /// A32: VCNT.I8 Qd, Qm + /// A64: CNT Vd.16B, Vn.16B + /// + public static Vector128 PopCount(Vector128 value) => PopCount(value); + + /// + /// int8x16_t vcntq_s8 (int8x16_t a) + /// A32: VCNT.I8 Qd, Qm + /// A64: CNT Vd.16B, Vn.16B + /// + public static Vector128 PopCount(Vector128 value) => PopCount(value); + + /// + /// float32x2_t vrecpe_f32 (float32x2_t a) + /// A32: VRECPE.F32 Dd, Dm + /// A64: FRECPE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalEstimate(Vector64 value) => ReciprocalEstimate(value); + + /// + /// uint32x2_t vrecpe_u32 (uint32x2_t a) + /// A32: VRECPE.U32 Dd, Dm + /// A64: URECPE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalEstimate(Vector64 value) => ReciprocalEstimate(value); + + /// + /// float32x4_t vrecpeq_f32 (float32x4_t a) + /// A32: VRECPE.F32 Qd, Qm + /// A64: FRECPE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalEstimate(Vector128 value) => ReciprocalEstimate(value); + + /// + /// uint32x4_t vrecpeq_u32 (uint32x4_t a) + /// A32: VRECPE.U32 Qd, Qm + /// A64: URECPE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalEstimate(Vector128 value) => ReciprocalEstimate(value); + + /// + /// float32x2_t vrsqrte_f32 (float32x2_t a) + /// A32: VRSQRTE.F32 Dd, Dm + /// A64: FRSQRTE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) => ReciprocalSquareRootEstimate(value); + + /// + /// uint32x2_t vrsqrte_u32 (uint32x2_t a) + /// A32: VRSQRTE.U32 Dd, Dm + /// A64: URSQRTE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) => ReciprocalSquareRootEstimate(value); + + /// + /// float32x4_t vrsqrteq_f32 (float32x4_t a) + /// A32: VRSQRTE.F32 Qd, Qm + /// A64: FRSQRTE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) => ReciprocalSquareRootEstimate(value); + + /// + /// uint32x4_t vrsqrteq_u32 (uint32x4_t a) + /// A32: VRSQRTE.U32 Qd, Qm + /// A64: URSQRTE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) => ReciprocalSquareRootEstimate(value); + + /// + /// float32x2_t vrsqrts_f32 (float32x2_t a, float32x2_t b) + /// A32: VRSQRTS.F32 Dd, Dn, Dm + /// A64: FRSQRTS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 ReciprocalSquareRootStep(Vector64 left, Vector64 right) => ReciprocalSquareRootStep(left, right); + + /// + /// float32x4_t vrsqrtsq_f32 (float32x4_t a, float32x4_t b) + /// A32: VRSQRTS.F32 Qd, Qn, Qm + /// A64: FRSQRTS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 ReciprocalSquareRootStep(Vector128 left, Vector128 right) => ReciprocalSquareRootStep(left, right); + + /// + /// float32x2_t vrecps_f32 (float32x2_t a, float32x2_t b) + /// A32: VRECPS.F32 Dd, Dn, Dm + /// A64: FRECPS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 ReciprocalStep(Vector64 left, Vector64 right) => ReciprocalStep(left, right); + + /// + /// float32x4_t vrecpsq_f32 (float32x4_t a, float32x4_t b) + /// A32: VRECPS.F32 Qd, Qn, Qm + /// A64: FRECPS Vd.4S, Vn.4S, Vm.4S /// - public static Vector128 CompareEqual(Vector128 left, Vector128 right) => CompareEqual(left, right); + public static Vector128 ReciprocalStep(Vector128 left, Vector128 right) => ReciprocalStep(left, right); /// - /// uint8x16_t vceqq_s8 (int8x16_t a, int8x16_t b) - /// A32: VCEQ.I8 Qd, Qn, Qm - /// A64: CMEQ Vd.16B, Vn.16B, Vm.16B + /// int16x4_t vshl_s16 (int16x4_t a, int16x4_t b) + /// A32: VSHL.S16 Dd, Dn, Dm + /// A64: SSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector128 CompareEqual(Vector128 left, Vector128 right) => CompareEqual(left, right); + public static Vector64 ShiftArithmetic(Vector64 value, Vector64 count) => ShiftArithmetic(value, count); /// - /// uint32x4_t vceqq_f32 (float32x4_t a, float32x4_t b) - /// A32: VCEQ.F32 Qd, Qn, Qm - /// A64: FCMEQ Vd.4S, Vn.4S, Vm.4S + /// int32x2_t vshl_s32 (int32x2_t a, int32x2_t b) + /// A32: VSHL.S32 Dd, Dn, Dm + /// A64: SSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 CompareEqual(Vector128 left, Vector128 right) => CompareEqual(left, right); + public static Vector64 ShiftArithmetic(Vector64 value, Vector64 count) => ShiftArithmetic(value, count); /// - /// uint16x8_t vceqq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VCEQ.I16 Qd, Qn, Qm - /// A64: CMEQ Vd.8H, Vn.8H, Vm.8H + /// int8x8_t vshl_s8 (int8x8_t a, int8x8_t b) + /// A32: VSHL.S8 Dd, Dn, Dm + /// A64: SSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 CompareEqual(Vector128 left, Vector128 right) => CompareEqual(left, right); + public static Vector64 ShiftArithmetic(Vector64 value, Vector64 count) => ShiftArithmetic(value, count); /// - /// uint32x4_t vceqq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VCEQ.I32 Qd, Qn, Qm - /// A64: CMEQ Vd.4S, Vn.4S, Vm.4S + /// int16x8_t vshlq_s16 (int16x8_t a, int16x8_t b) + /// A32: VSHL.S16 Qd, Qn, Qm + /// A64: SSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector128 CompareEqual(Vector128 left, Vector128 right) => CompareEqual(left, right); + public static Vector128 ShiftArithmetic(Vector128 value, Vector128 count) => ShiftArithmetic(value, count); /// - /// uint8x8_t vcgt_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VCGT.U8 Dd, Dn, Dm - /// A64: CMHI Vd.8B, Vn.8B, Vm.8B + /// int32x4_t vshlq_s32 (int32x4_t a, int32x4_t b) + /// A32: VSHL.S32 Qd, Qn, Qm + /// A64: SSHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) => CompareGreaterThan(left, right); + public static Vector128 ShiftArithmetic(Vector128 value, Vector128 count) => ShiftArithmetic(value, count); /// - /// uint16x4_t vcgt_s16 (int16x4_t a, int16x4_t b) - /// A32: VCGT.S16 Dd, Dn, Dm - /// A64: CMGT Vd.4H, Vn.4H, Vm.4H + /// int64x2_t vshlq_s64 (int64x2_t a, int64x2_t b) + /// A32: VSHL.S64 Qd, Qn, Qm + /// A64: SSHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) => CompareGreaterThan(left, right); + public static Vector128 ShiftArithmetic(Vector128 value, Vector128 count) => ShiftArithmetic(value, count); /// - /// uint32x2_t vcgt_s32 (int32x2_t a, int32x2_t b) - /// A32: VCGT.S32 Dd, Dn, Dm - /// A64: CMGT Vd.2S, Vn.2S, Vm.2S + /// int8x16_t vshlq_s8 (int8x16_t a, int8x16_t b) + /// A32: VSHL.S8 Qd, Qn, Qm + /// A64: SSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) => CompareGreaterThan(left, right); + public static Vector128 ShiftArithmetic(Vector128 value, Vector128 count) => ShiftArithmetic(value, count); /// - /// uint8x8_t vcgt_s8 (int8x8_t a, int8x8_t b) - /// A32: VCGT.S8 Dd, Dn, Dm - /// A64: CMGT Vd.8B, Vn.8B, Vm.8B + /// int16x4_t vrshl_s16 (int16x4_t a, int16x4_t b) + /// A32: VRSHL.S16 Dd, Dn, Dm + /// A64: SRSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) => CompareGreaterThan(left, right); + public static Vector64 ShiftArithmeticRounded(Vector64 value, Vector64 count) => ShiftArithmeticRounded(value, count); /// - /// uint32x2_t vcgt_f32 (float32x2_t a, float32x2_t b) - /// A32: VCGT.F32 Dd, Dn, Dm - /// A64: FCMGT Vd.2S, Vn.2S, Vm.2S + /// int32x2_t vrshl_s32 (int32x2_t a, int32x2_t b) + /// A32: VRSHL.S32 Dd, Dn, Dm + /// A64: SRSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) => CompareGreaterThan(left, right); + public static Vector64 ShiftArithmeticRounded(Vector64 value, Vector64 count) => ShiftArithmeticRounded(value, count); /// - /// uint16x4_t vcgt_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VCGT.U16 Dd, Dn, Dm - /// A64: CMHI Vd.4H, Vn.4H, Vm.4H + /// int8x8_t vrshl_s8 (int8x8_t a, int8x8_t b) + /// A32: VRSHL.S8 Dd, Dn, Dm + /// A64: SRSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) => CompareGreaterThan(left, right); + public static Vector64 ShiftArithmeticRounded(Vector64 value, Vector64 count) => ShiftArithmeticRounded(value, count); /// - /// uint32x2_t vcgt_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VCGT.U32 Dd, Dn, Dm - /// A64: CMHI Vd.2S, Vn.2S, Vm.2S + /// int16x8_t vrshlq_s16 (int16x8_t a, int16x8_t b) + /// A32: VRSHL.S16 Qd, Qn, Qm + /// A64: SRSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector64 CompareGreaterThan(Vector64 left, Vector64 right) => CompareGreaterThan(left, right); + public static Vector128 ShiftArithmeticRounded(Vector128 value, Vector128 count) => ShiftArithmeticRounded(value, count); /// - /// uint8x16_t vcgtq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VCGT.U8 Qd, Qn, Qm - /// A64: CMHI Vd.16B, Vn.16B, Vm.16B + /// int32x4_t vrshlq_s32 (int32x4_t a, int32x4_t b) + /// A32: VRSHL.S32 Qd, Qn, Qm + /// A64: SRSHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); + public static Vector128 ShiftArithmeticRounded(Vector128 value, Vector128 count) => ShiftArithmeticRounded(value, count); /// - /// uint16x8_t vcgtq_s16 (int16x8_t a, int16x8_t b) - /// A32: VCGT.S16 Qd, Qn, Qm - /// A64: CMGT Vd.8H, Vn.8H, Vm.8H + /// int64x2_t vrshlq_s64 (int64x2_t a, int64x2_t b) + /// A32: VRSHL.S64 Qd, Qn, Qm + /// A64: SRSHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); + public static Vector128 ShiftArithmeticRounded(Vector128 value, Vector128 count) => ShiftArithmeticRounded(value, count); /// - /// uint32x4_t vcgtq_s32 (int32x4_t a, int32x4_t b) - /// A32: VCGT.S32 Qd, Qn, Qm - /// A64: CMGT Vd.4S, Vn.4S, Vm.4S + /// int8x16_t vrshlq_s8 (int8x16_t a, int8x16_t b) + /// A32: VRSHL.S8 Qd, Qn, Qm + /// A64: SRSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); + public static Vector128 ShiftArithmeticRounded(Vector128 value, Vector128 count) => ShiftArithmeticRounded(value, count); /// - /// uint8x16_t vcgtq_s8 (int8x16_t a, int8x16_t b) - /// A32: VCGT.S8 Qd, Qn, Qm - /// A64: CMGT Vd.16B, Vn.16B, Vm.16B + /// int16x4_t vqrshl_s16 (int16x4_t a, int16x4_t b) + /// A32: VQRSHL.S16 Dd, Dn, Dm + /// A64: SQRSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); + public static Vector64 ShiftArithmeticRoundedSaturate(Vector64 value, Vector64 count) => ShiftArithmeticRoundedSaturate(value, count); /// - /// uint32x4_t vcgtq_f32 (float32x4_t a, float32x4_t b) - /// A32: VCGT.F32 Qd, Qn, Qm - /// A64: FCMGT Vd.4S, Vn.4S, Vm.4S + /// int32x2_t vqrshl_s32 (int32x2_t a, int32x2_t b) + /// A32: VQRSHL.S32 Dd, Dn, Dm + /// A64: SQRSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); + public static Vector64 ShiftArithmeticRoundedSaturate(Vector64 value, Vector64 count) => ShiftArithmeticRoundedSaturate(value, count); /// - /// uint16x8_t vcgtq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VCGT.U16 Qd, Qn, Qm - /// A64: CMHI Vd.8H, Vn.8H, Vm.8H + /// int8x8_t vqrshl_s8 (int8x8_t a, int8x8_t b) + /// A32: VQRSHL.S8 Dd, Dn, Dm + /// A64: SQRSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); + public static Vector64 ShiftArithmeticRoundedSaturate(Vector64 value, Vector64 count) => ShiftArithmeticRoundedSaturate(value, count); /// - /// uint32x4_t vcgtq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VCGT.U32 Qd, Qn, Qm - /// A64: CMHI Vd.4S, Vn.4S, Vm.4S + /// int16x8_t vqrshlq_s16 (int16x8_t a, int16x8_t b) + /// A32: VQRSHL.S16 Qd, Qn, Qm + /// A64: SQRSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); + public static Vector128 ShiftArithmeticRoundedSaturate(Vector128 value, Vector128 count) => ShiftArithmeticRoundedSaturate(value, count); /// - /// uint8x8_t vcge_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VCGE.U8 Dd, Dn, Dm - /// A64: CMHS Vd.8B, Vn.8B, Vm.8B + /// int32x4_t vqrshlq_s32 (int32x4_t a, int32x4_t b) + /// A32: VQRSHL.S32 Qd, Qn, Qm + /// A64: SQRSHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) => CompareGreaterThanOrEqual(left, right); + public static Vector128 ShiftArithmeticRoundedSaturate(Vector128 value, Vector128 count) => ShiftArithmeticRoundedSaturate(value, count); /// - /// uint16x4_t vcge_s16 (int16x4_t a, int16x4_t b) - /// A32: VCGE.S16 Dd, Dn, Dm - /// A64: CMGE Vd.4H, Vn.4H, Vm.4H + /// int64x2_t vqrshlq_s64 (int64x2_t a, int64x2_t b) + /// A32: VQRSHL.S64 Qd, Qn, Qm + /// A64: SQRSHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) => CompareGreaterThanOrEqual(left, right); + public static Vector128 ShiftArithmeticRoundedSaturate(Vector128 value, Vector128 count) => ShiftArithmeticRoundedSaturate(value, count); /// - /// uint32x2_t vcge_s32 (int32x2_t a, int32x2_t b) - /// A32: VCGE.S32 Dd, Dn, Dm - /// A64: CMGE Vd.2S, Vn.2S, Vm.2S + /// int8x16_t vqrshlq_s8 (int8x16_t a, int8x16_t b) + /// A32: VQRSHL.S8 Qd, Qn, Qm + /// A64: SQRSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) => CompareGreaterThanOrEqual(left, right); + public static Vector128 ShiftArithmeticRoundedSaturate(Vector128 value, Vector128 count) => ShiftArithmeticRoundedSaturate(value, count); /// - /// uint8x8_t vcge_s8 (int8x8_t a, int8x8_t b) - /// A32: VCGE.S8 Dd, Dn, Dm - /// A64: CMGE Vd.8B, Vn.8B, Vm.8B + /// int64x1_t vqrshl_s64 (int64x1_t a, int64x1_t b) + /// A32: VQRSHL.S64 Dd, Dn, Dm + /// A64: SQRSHL Dd, Dn, Dm /// - public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) => CompareGreaterThanOrEqual(left, right); + public static Vector64 ShiftArithmeticRoundedSaturateScalar(Vector64 value, Vector64 count) => ShiftArithmeticRoundedSaturateScalar(value, count); /// - /// uint32x2_t vcge_f32 (float32x2_t a, float32x2_t b) - /// A32: VCGE.F32 Dd, Dn, Dm - /// A64: FCMGE Vd.2S, Vn.2S, Vm.2S + /// int64x1_t vrshl_s64 (int64x1_t a, int64x1_t b) + /// A32: VRSHL.S64 Dd, Dn, Dm + /// A64: SRSHL Dd, Dn, Dm /// - public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) => CompareGreaterThanOrEqual(left, right); + public static Vector64 ShiftArithmeticRoundedScalar(Vector64 value, Vector64 count) => ShiftArithmeticRoundedScalar(value, count); /// - /// uint16x4_t vcge_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VCGE.U16 Dd, Dn, Dm - /// A64: CMHS Vd.4H, Vn.4H, Vm.4H + /// int16x4_t vqshl_s16 (int16x4_t a, int16x4_t b) + /// A32: VQSHL.S16 Dd, Dn, Dm + /// A64: SQSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) => CompareGreaterThanOrEqual(left, right); + public static Vector64 ShiftArithmeticSaturate(Vector64 value, Vector64 count) => ShiftArithmeticSaturate(value, count); /// - /// uint32x2_t vcge_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VCGE.U32 Dd, Dn, Dm - /// A64: CMHS Vd.2S, Vn.2S, Vm.2S + /// int32x2_t vqshl_s32 (int32x2_t a, int32x2_t b) + /// A32: VQSHL.S32 Dd, Dn, Dm + /// A64: SQSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector64 CompareGreaterThanOrEqual(Vector64 left, Vector64 right) => CompareGreaterThanOrEqual(left, right); + public static Vector64 ShiftArithmeticSaturate(Vector64 value, Vector64 count) => ShiftArithmeticSaturate(value, count); /// - /// uint8x16_t vcgeq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VCGE.U8 Qd, Qn, Qm - /// A64: CMHS Vd.16B, Vn.16B, Vm.16B + /// int8x8_t vqshl_s8 (int8x8_t a, int8x8_t b) + /// A32: VQSHL.S8 Dd, Dn, Dm + /// A64: SQSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); + public static Vector64 ShiftArithmeticSaturate(Vector64 value, Vector64 count) => ShiftArithmeticSaturate(value, count); /// - /// uint16x8_t vcgeq_s16 (int16x8_t a, int16x8_t b) - /// A32: VCGE.S16 Qd, Qn, Qm - /// A64: CMGE Vd.8H, Vn.8H, Vm.8H + /// int16x8_t vqshlq_s16 (int16x8_t a, int16x8_t b) + /// A32: VQSHL.S16 Qd, Qn, Qm + /// A64: SQSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); + public static Vector128 ShiftArithmeticSaturate(Vector128 value, Vector128 count) => ShiftArithmeticSaturate(value, count); /// - /// uint32x4_t vcgeq_s32 (int32x4_t a, int32x4_t b) - /// A32: VCGE.S32 Qd, Qn, Qm - /// A64: CMGE Vd.4S, Vn.4S, Vm.4S + /// int32x4_t vqshlq_s32 (int32x4_t a, int32x4_t b) + /// A32: VQSHL.S32 Qd, Qn, Qm + /// A64: SQSHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); + public static Vector128 ShiftArithmeticSaturate(Vector128 value, Vector128 count) => ShiftArithmeticSaturate(value, count); /// - /// uint8x16_t vcgeq_s8 (int8x16_t a, int8x16_t b) - /// A32: VCGE.S8 Qd, Qn, Qm - /// A64: CMGE Vd.16B, Vn.16B, Vm.16B + /// int64x2_t vqshlq_s64 (int64x2_t a, int64x2_t b) + /// A32: VQSHL.S64 Qd, Qn, Qm + /// A64: SQSHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); + public static Vector128 ShiftArithmeticSaturate(Vector128 value, Vector128 count) => ShiftArithmeticSaturate(value, count); /// - /// uint32x4_t vcgeq_f32 (float32x4_t a, float32x4_t b) - /// A32: VCGE.F32 Qd, Qn, Qm - /// A64: FCMGE Vd.4S, Vn.4S, Vm.4S + /// int8x16_t vqshlq_s8 (int8x16_t a, int8x16_t b) + /// A32: VQSHL.S8 Qd, Qn, Qm + /// A64: SQSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); + public static Vector128 ShiftArithmeticSaturate(Vector128 value, Vector128 count) => ShiftArithmeticSaturate(value, count); /// - /// uint16x8_t vcgeq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VCGE.U16 Qd, Qn, Qm - /// A64: CMHS Vd.8H, Vn.8H, Vm.8H + /// int64x1_t vqshl_s64 (int64x1_t a, int64x1_t b) + /// A32: VQSHL.S64 Dd, Dn, Dm + /// A64: SQSHL Dd, Dn, Dm /// - public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); + public static Vector64 ShiftArithmeticSaturateScalar(Vector64 value, Vector64 count) => ShiftArithmeticSaturateScalar(value, count); /// - /// uint32x4_t vcgeq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VCGE.U32 Qd, Qn, Qm - /// A64: CMHS Vd.4S, Vn.4S, Vm.4S + /// int64x1_t vshl_s64 (int64x1_t a, int64x1_t b) + /// A32: VSHL.S64 Dd, Dn, Dm + /// A64: SSHL Dd, Dn, Dm /// - public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); + public static Vector64 ShiftArithmeticScalar(Vector64 value, Vector64 count) => ShiftArithmeticScalar(value, count); /// - /// uint8x8_t vclt_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VCLT.U8 Dd, Dn, Dm - /// A64: CMHI Vd.8B, Vn.8B, Vm.8B + /// uint8x8_t vshl_n_u8 (uint8x8_t a, const int n) + /// A32: VSHL.I8 Dd, Dm, #n + /// A64: SHL Vd.8B, Vn.8B, #n /// - public static Vector64 CompareLessThan(Vector64 left, Vector64 right) => CompareLessThan(left, right); + public static Vector64 ShiftLeftLogical(Vector64 value, byte count) => ShiftLeftLogical(value, count); /// - /// uint16x4_t vclt_s16 (int16x4_t a, int16x4_t b) - /// A32: VCLT.S16 Dd, Dn, Dm - /// A64: CMGT Vd.4H, Vn.4H, Vm.4H + /// int16x4_t vshl_n_s16 (int16x4_t a, const int n) + /// A32: VSHL.I16 Dd, Dm, #n + /// A64: SHL Vd.4H, Vn.4H, #n /// - public static Vector64 CompareLessThan(Vector64 left, Vector64 right) => CompareLessThan(left, right); + public static Vector64 ShiftLeftLogical(Vector64 value, byte count) => ShiftLeftLogical(value, count); /// - /// uint32x2_t vclt_s32 (int32x2_t a, int32x2_t b) - /// A32: VCLT.S32 Dd, Dn, Dm - /// A64: CMGT Vd.2S, Vn.2S, Vm.2S + /// int32x2_t vshl_n_s32 (int32x2_t a, const int n) + /// A32: VSHL.I32 Dd, Dm, #n + /// A64: SHL Vd.2S, Vn.2S, #n /// - public static Vector64 CompareLessThan(Vector64 left, Vector64 right) => CompareLessThan(left, right); + public static Vector64 ShiftLeftLogical(Vector64 value, byte count) => ShiftLeftLogical(value, count); /// - /// uint8x8_t vclt_s8 (int8x8_t a, int8x8_t b) - /// A32: VCLT.S8 Dd, Dn, Dm - /// A64: CMGT Vd.8B, Vn.8B, Vm.8B + /// int8x8_t vshl_n_s8 (int8x8_t a, const int n) + /// A32: VSHL.I8 Dd, Dm, #n + /// A64: SHL Vd.8B, Vn.8B, #n /// - public static Vector64 CompareLessThan(Vector64 left, Vector64 right) => CompareLessThan(left, right); + public static Vector64 ShiftLeftLogical(Vector64 value, byte count) => ShiftLeftLogical(value, count); /// - /// uint32x2_t vclt_f32 (float32x2_t a, float32x2_t b) - /// A32: VCLT.F32 Dd, Dn, Dm - /// A64: FCMGT Vd.2S, Vn.2S, Vm.2S + /// uint16x4_t vshl_n_u16 (uint16x4_t a, const int n) + /// A32: VSHL.I16 Dd, Dm, #n + /// A64: SHL Vd.4H, Vn.4H, #n /// - public static Vector64 CompareLessThan(Vector64 left, Vector64 right) => CompareLessThan(left, right); + public static Vector64 ShiftLeftLogical(Vector64 value, byte count) => ShiftLeftLogical(value, count); /// - /// uint16x4_t vclt_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VCLT.U16 Dd, Dn, Dm - /// A64: CMHI Vd.4H, Vn.4H, Vm.4H + /// uint32x2_t vshl_n_u32 (uint32x2_t a, const int n) + /// A32: VSHL.I32 Dd, Dm, #n + /// A64: SHL Vd.2S, Vn.2S, #n /// - public static Vector64 CompareLessThan(Vector64 left, Vector64 right) => CompareLessThan(left, right); + public static Vector64 ShiftLeftLogical(Vector64 value, byte count) => ShiftLeftLogical(value, count); /// - /// uint32x2_t vclt_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VCLT.U32 Dd, Dn, Dm - /// A64: CMHI Vd.2S, Vn.2S, Vm.2S + /// uint8x16_t vshlq_n_u8 (uint8x16_t a, const int n) + /// A32: VSHL.I8 Qd, Qm, #n + /// A64: SHL Vd.16B, Vn.16B, #n /// - public static Vector64 CompareLessThan(Vector64 left, Vector64 right) => CompareLessThan(left, right); + public static Vector128 ShiftLeftLogical(Vector128 value, byte count) => ShiftLeftLogical(value, count); /// - /// uint8x16_t vcltq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VCLT.U8 Qd, Qn, Qm - /// A64: CMHI Vd.16B, Vn.16B, Vm.16B + /// int16x8_t vshlq_n_s16 (int16x8_t a, const int n) + /// A32: VSHL.I16 Qd, Qm, #n + /// A64: SHL Vd.8H, Vn.8H, #n /// - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => CompareLessThan(left, right); + public static Vector128 ShiftLeftLogical(Vector128 value, byte count) => ShiftLeftLogical(value, count); /// - /// uint16x8_t vcltq_s16 (int16x8_t a, int16x8_t b) - /// A32: VCLT.S16 Qd, Qn, Qm - /// A64: CMGT Vd.8H, Vn.8H, Vm.8H + /// int64x2_t vshlq_n_s64 (int64x2_t a, const int n) + /// A32: VSHL.I64 Qd, Qm, #n + /// A64: SHL Vd.2D, Vn.2D, #n /// - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => CompareLessThan(left, right); + public static Vector128 ShiftLeftLogical(Vector128 value, byte count) => ShiftLeftLogical(value, count); /// - /// uint32x4_t vcltq_s32 (int32x4_t a, int32x4_t b) - /// A32: VCLT.S32 Qd, Qn, Qm - /// A64: CMGT Vd.4S, Vn.4S, Vm.4S + /// int8x16_t vshlq_n_s8 (int8x16_t a, const int n) + /// A32: VSHL.I8 Qd, Qm, #n + /// A64: SHL Vd.16B, Vn.16B, #n /// - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => CompareLessThan(left, right); + public static Vector128 ShiftLeftLogical(Vector128 value, byte count) => ShiftLeftLogical(value, count); /// - /// uint8x16_t vcltq_s8 (int8x16_t a, int8x16_t b) - /// A32: VCLT.S8 Qd, Qn, Qm - /// A64: CMGT Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vshlq_n_u16 (uint16x8_t a, const int n) + /// A32: VSHL.I16 Qd, Qm, #n + /// A64: SHL Vd.8H, Vn.8H, #n /// - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => CompareLessThan(left, right); + public static Vector128 ShiftLeftLogical(Vector128 value, byte count) => ShiftLeftLogical(value, count); /// - /// uint32x4_t vcltq_f32 (float32x4_t a, float32x4_t b) - /// A32: VCLT.F32 Qd, Qn, Qm - /// A64: FCMGT Vd.4S, Vn.4S, Vm.4S + /// uint32x4_t vshlq_n_u32 (uint32x4_t a, const int n) + /// A32: VSHL.I32 Qd, Qm, #n + /// A64: SHL Vd.4S, Vn.4S, #n /// - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => CompareLessThan(left, right); + public static Vector128 ShiftLeftLogical(Vector128 value, byte count) => ShiftLeftLogical(value, count); /// - /// uint16x8_t vcltq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VCLT.U16 Qd, Qn, Qm - /// A64: CMHI Vd.8H, Vn.8H, Vm.8H + /// uint64x2_t vshlq_n_u64 (uint64x2_t a, const int n) + /// A32: VSHL.I64 Qd, Qm, #n + /// A64: SHL Vd.2D, Vn.2D, #n /// - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => CompareLessThan(left, right); + public static Vector128 ShiftLeftLogical(Vector128 value, byte count) => ShiftLeftLogical(value, count); /// - /// uint32x4_t vcltq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VCLT.U32 Qd, Qn, Qm - /// A64: CMHI Vd.4S, Vn.4S, Vm.4S + /// uint8x8_t vqshl_n_u8 (uint8x8_t a, const int n) + /// A32: VQSHL.U8 Dd, Dm, #n + /// A64: UQSHL Vd.8B, Vn.8B, #n /// - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => CompareLessThan(left, right); + public static Vector64 ShiftLeftLogicalSaturate(Vector64 value, byte count) => ShiftLeftLogicalSaturate(value, count); /// - /// uint8x8_t vcle_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VCLE.U8 Dd, Dn, Dm - /// A64: CMHS Vd.8B, Vn.8B, Vm.8B + /// int16x4_t vqshl_n_s16 (int16x4_t a, const int n) + /// A32: VQSHL.S16 Dd, Dm, #n + /// A64: SQSHL Vd.4H, Vn.4H, #n /// - public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) => CompareLessThanOrEqual(left, right); + public static Vector64 ShiftLeftLogicalSaturate(Vector64 value, byte count) => ShiftLeftLogicalSaturate(value, count); /// - /// uint16x4_t vcle_s16 (int16x4_t a, int16x4_t b) - /// A32: VCLE.S16 Dd, Dn, Dm - /// A64: CMGE Vd.4H, Vn.4H, Vm.4H + /// int32x2_t vqshl_n_s32 (int32x2_t a, const int n) + /// A32: VQSHL.S32 Dd, Dm, #n + /// A64: SQSHL Vd.2S, Vn.2S, #n /// - public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) => CompareLessThanOrEqual(left, right); + public static Vector64 ShiftLeftLogicalSaturate(Vector64 value, byte count) => ShiftLeftLogicalSaturate(value, count); /// - /// uint32x2_t vcle_s32 (int32x2_t a, int32x2_t b) - /// A32: VCLE.S32 Dd, Dn, Dm - /// A64: CMGE Vd.2S, Vn.2S, Vm.2S + /// int8x8_t vqshl_n_s8 (int8x8_t a, const int n) + /// A32: VQSHL.S8 Dd, Dm, #n + /// A64: SQSHL Vd.8B, Vn.8B, #n /// - public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) => CompareLessThanOrEqual(left, right); + public static Vector64 ShiftLeftLogicalSaturate(Vector64 value, byte count) => ShiftLeftLogicalSaturate(value, count); /// - /// uint8x8_t vcle_s8 (int8x8_t a, int8x8_t b) - /// A32: VCLE.S8 Dd, Dn, Dm - /// A64: CMGE Vd.8B, Vn.8B, Vm.8B + /// uint16x4_t vqshl_n_u16 (uint16x4_t a, const int n) + /// A32: VQSHL.U16 Dd, Dm, #n + /// A64: UQSHL Vd.4H, Vn.4H, #n /// - public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) => CompareLessThanOrEqual(left, right); + public static Vector64 ShiftLeftLogicalSaturate(Vector64 value, byte count) => ShiftLeftLogicalSaturate(value, count); /// - /// uint32x2_t vcle_f32 (float32x2_t a, float32x2_t b) - /// A32: VCLE.F32 Dd, Dn, Dm - /// A64: FCMGE Vd.2S, Vn.2S, Vm.2S + /// uint32x2_t vqshl_n_u32 (uint32x2_t a, const int n) + /// A32: VQSHL.U32 Dd, Dm, #n + /// A64: UQSHL Vd.2S, Vn.2S, #n /// - public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) => CompareLessThanOrEqual(left, right); + public static Vector64 ShiftLeftLogicalSaturate(Vector64 value, byte count) => ShiftLeftLogicalSaturate(value, count); /// - /// uint16x4_t vcle_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VCLE.U16 Dd, Dn, Dm - /// A64: CMHS Vd.4H, Vn.4H, Vm.4H + /// uint8x16_t vqshlq_n_u8 (uint8x16_t a, const int n) + /// A32: VQSHL.U8 Qd, Qm, #n + /// A64: UQSHL Vd.16B, Vn.16B, #n /// - public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) => CompareLessThanOrEqual(left, right); + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) => ShiftLeftLogicalSaturate(value, count); /// - /// uint32x2_t vcle_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VCLE.U32 Dd, Dn, Dm - /// A64: CMHS Vd.2S, Vn.2S, Vm.2S + /// int16x8_t vqshlq_n_s16 (int16x8_t a, const int n) + /// A32: VQSHL.S16 Qd, Qm, #n + /// A64: SQSHL Vd.8H, Vn.8H, #n /// - public static Vector64 CompareLessThanOrEqual(Vector64 left, Vector64 right) => CompareLessThanOrEqual(left, right); + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) => ShiftLeftLogicalSaturate(value, count); /// - /// uint8x16_t vcleq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VCLE.U8 Qd, Qn, Qm - /// A64: CMHS Vd.16B, Vn.16B, Vm.16B + /// int32x4_t vqshlq_n_s32 (int32x4_t a, const int n) + /// A32: VQSHL.S32 Qd, Qm, #n + /// A64: SQSHL Vd.4S, Vn.4S, #n /// - public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) => CompareLessThanOrEqual(left, right); + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) => ShiftLeftLogicalSaturate(value, count); /// - /// uint16x8_t vcleq_s16 (int16x8_t a, int16x8_t b) - /// A32: VCLE.S16 Qd, Qn, Qm - /// A64: CMGE Vd.8H, Vn.8H, Vm.8H + /// int64x2_t vqshlq_n_s64 (int64x2_t a, const int n) + /// A32: VQSHL.S64 Qd, Qm, #n + /// A64: SQSHL Vd.2D, Vn.2D, #n /// - public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) => CompareLessThanOrEqual(left, right); + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) => ShiftLeftLogicalSaturate(value, count); /// - /// uint32x4_t vcleq_s32 (int32x4_t a, int32x4_t b) - /// A32: VCLE.S32 Qd, Qn, Qm - /// A64: CMGE Vd.4S, Vn.4S, Vm.4S + /// int8x16_t vqshlq_n_s8 (int8x16_t a, const int n) + /// A32: VQSHL.S8 Qd, Qm, #n + /// A64: SQSHL Vd.16B, Vn.16B, #n /// - public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) => CompareLessThanOrEqual(left, right); + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) => ShiftLeftLogicalSaturate(value, count); /// - /// uint8x16_t vcleq_s8 (int8x16_t a, int8x16_t b) - /// A32: VCLE.S8 Qd, Qn, Qm - /// A64: CMGE Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vqshlq_n_u16 (uint16x8_t a, const int n) + /// A32: VQSHL.U16 Qd, Qm, #n + /// A64: UQSHL Vd.8H, Vn.8H, #n /// - public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) => CompareLessThanOrEqual(left, right); + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) => ShiftLeftLogicalSaturate(value, count); /// - /// uint32x4_t vcleq_f32 (float32x4_t a, float32x4_t b) - /// A32: VCLE.F32 Qd, Qn, Qm - /// A64: FCMGE Vd.4S, Vn.4S, Vm.4S + /// uint32x4_t vqshlq_n_u32 (uint32x4_t a, const int n) + /// A32: VQSHL.U32 Qd, Qm, #n + /// A64: UQSHL Vd.4S, Vn.4S, #n /// - public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) => CompareLessThanOrEqual(left, right); + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) => ShiftLeftLogicalSaturate(value, count); /// - /// uint16x8_t vcleq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VCLE.U16 Qd, Qn, Qm - /// A64: CMHS Vd.8H, Vn.8H, Vm.8H + /// uint64x2_t vqshlq_n_u64 (uint64x2_t a, const int n) + /// A32: VQSHL.U64 Qd, Qm, #n + /// A64: UQSHL Vd.2D, Vn.2D, #n /// - public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) => CompareLessThanOrEqual(left, right); + public static Vector128 ShiftLeftLogicalSaturate(Vector128 value, byte count) => ShiftLeftLogicalSaturate(value, count); /// - /// uint32x4_t vcleq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VCLE.U32 Qd, Qn, Qm - /// A64: CMHS Vd.4S, Vn.4S, Vm.4S + /// int64x1_t vqshl_n_s64 (int64x1_t a, const int n) + /// A32: VQSHL.S64 Dd, Dm, #n + /// A64: SQSHL Dd, Dn, #n /// - public static Vector128 CompareLessThanOrEqual(Vector128 left, Vector128 right) => CompareLessThanOrEqual(left, right); + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) => ShiftLeftLogicalSaturateScalar(value, count); /// - /// uint8x8_t vtst_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VTST.8 Dd, Dn, Dm - /// A64: CMTST Vd.8B, Vn.8B, Vm.8B + /// uint64x1_t vqshl_n_u64 (uint64x1_t a, const int n) + /// A32: VQSHL.U64 Dd, Dm, #n + /// A64: UQSHL Dd, Dn, #n /// - public static Vector64 CompareTest(Vector64 left, Vector64 right) => CompareTest(left, right); + public static Vector64 ShiftLeftLogicalSaturateScalar(Vector64 value, byte count) => ShiftLeftLogicalSaturateScalar(value, count); /// - /// uint16x4_t vtst_s16 (int16x4_t a, int16x4_t b) - /// A32: VTST.16 Dd, Dn, Dm - /// A64: CMTST Vd.4H, Vn.4H, Vm.4H + /// uint16x4_t vqshlu_n_s16 (int16x4_t a, const int n) + /// A32: VQSHLU.S16 Dd, Dm, #n + /// A64: SQSHLU Vd.4H, Vn.4H, #n /// - public static Vector64 CompareTest(Vector64 left, Vector64 right) => CompareTest(left, right); + public static Vector64 ShiftLeftLogicalSaturateUnsigned(Vector64 value, byte count) => ShiftLeftLogicalSaturateUnsigned(value, count); /// - /// uint32x2_t vtst_s32 (int32x2_t a, int32x2_t b) - /// A32: VTST.32 Dd, Dn, Dm - /// A64: CMTST Vd.2S, Vn.2S, Vm.2S + /// uint32x2_t vqshlu_n_s32 (int32x2_t a, const int n) + /// A32: VQSHLU.S32 Dd, Dm, #n + /// A64: SQSHLU Vd.2S, Vn.2S, #n + /// + public static Vector64 ShiftLeftLogicalSaturateUnsigned(Vector64 value, byte count) => ShiftLeftLogicalSaturateUnsigned(value, count); + + /// + /// uint8x8_t vqshlu_n_s8 (int8x8_t a, const int n) + /// A32: VQSHLU.S8 Dd, Dm, #n + /// A64: SQSHLU Vd.8B, Vn.8B, #n /// - public static Vector64 CompareTest(Vector64 left, Vector64 right) => CompareTest(left, right); + public static Vector64 ShiftLeftLogicalSaturateUnsigned(Vector64 value, byte count) => ShiftLeftLogicalSaturateUnsigned(value, count); /// - /// uint8x8_t vtst_s8 (int8x8_t a, int8x8_t b) - /// A32: VTST.8 Dd, Dn, Dm - /// A64: CMTST Vd.8B, Vn.8B, Vm.8B + /// uint16x8_t vqshluq_n_s16 (int16x8_t a, const int n) + /// A32: VQSHLU.S16 Qd, Qm, #n + /// A64: SQSHLU Vd.8H, Vn.8H, #n /// - public static Vector64 CompareTest(Vector64 left, Vector64 right) => CompareTest(left, right); + public static Vector128 ShiftLeftLogicalSaturateUnsigned(Vector128 value, byte count) => ShiftLeftLogicalSaturateUnsigned(value, count); /// - /// uint32x2_t vtst_f32 (float32x2_t a, float32x2_t b) - /// A32: VTST.32 Dd, Dn, Dm - /// A64: CMTST Vd.2S, Vn.2S, Vm.2S - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint32x4_t vqshluq_n_s32 (int32x4_t a, const int n) + /// A32: VQSHLU.S32 Qd, Qm, #n + /// A64: SQSHLU Vd.4S, Vn.4S, #n /// - public static Vector64 CompareTest(Vector64 left, Vector64 right) => CompareTest(left, right); + public static Vector128 ShiftLeftLogicalSaturateUnsigned(Vector128 value, byte count) => ShiftLeftLogicalSaturateUnsigned(value, count); /// - /// uint16x4_t vtst_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VTST.16 Dd, Dn, Dm - /// A64: CMTST Vd.4H, Vn.4H, Vm.4H + /// uint64x2_t vqshluq_n_s64 (int64x2_t a, const int n) + /// A32: VQSHLU.S64 Qd, Qm, #n + /// A64: SQSHLU Vd.2D, Vn.2D, #n /// - public static Vector64 CompareTest(Vector64 left, Vector64 right) => CompareTest(left, right); + public static Vector128 ShiftLeftLogicalSaturateUnsigned(Vector128 value, byte count) => ShiftLeftLogicalSaturateUnsigned(value, count); /// - /// uint32x2_t vtst_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VTST.32 Dd, Dn, Dm - /// A64: CMTST Vd.2S, Vn.2S, Vm.2S + /// uint8x16_t vqshluq_n_s8 (int8x16_t a, const int n) + /// A32: VQSHLU.S8 Qd, Qm, #n + /// A64: SQSHLU Vd.16B, Vn.16B, #n /// - public static Vector64 CompareTest(Vector64 left, Vector64 right) => CompareTest(left, right); + public static Vector128 ShiftLeftLogicalSaturateUnsigned(Vector128 value, byte count) => ShiftLeftLogicalSaturateUnsigned(value, count); /// - /// uint8x16_t vtstq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VTST.8 Qd, Qn, Qm - /// A64: CMTST Vd.16B, Vn.16B, Vm.16B + /// uint64x1_t vqshlu_n_s64 (int64x1_t a, const int n) + /// A32: VQSHLU.S64 Dd, Dm, #n + /// A64: SQSHLU Dd, Dn, #n /// - public static Vector128 CompareTest(Vector128 left, Vector128 right) => CompareTest(left, right); + public static Vector64 ShiftLeftLogicalSaturateUnsignedScalar(Vector64 value, byte count) => ShiftLeftLogicalSaturateUnsignedScalar(value, count); /// - /// uint16x8_t vtstq_s16 (int16x8_t a, int16x8_t b) - /// A32: VTST.16 Qd, Qn, Qm - /// A64: CMTST Vd.8H, Vn.8H, Vm.8H + /// int64x1_t vshl_n_s64 (int64x1_t a, const int n) + /// A32: VSHL.I64 Dd, Dm, #n + /// A64: SHL Dd, Dn, #n /// - public static Vector128 CompareTest(Vector128 left, Vector128 right) => CompareTest(left, right); + public static Vector64 ShiftLeftLogicalScalar(Vector64 value, byte count) => ShiftLeftLogicalScalar(value, count); /// - /// uint32x4_t vtstq_s32 (int32x4_t a, int32x4_t b) - /// A32: VTST.32 Qd, Qn, Qm - /// A64: CMTST Vd.4S, Vn.4S, Vm.4S + /// uint64x1_t vshl_n_u64 (uint64x1_t a, const int n) + /// A32: VSHL.I64 Dd, Dm, #n + /// A64: SHL Dd, Dn, #n /// - public static Vector128 CompareTest(Vector128 left, Vector128 right) => CompareTest(left, right); + public static Vector64 ShiftLeftLogicalScalar(Vector64 value, byte count) => ShiftLeftLogicalScalar(value, count); /// - /// uint8x16_t vtstq_s8 (int8x16_t a, int8x16_t b) - /// A32: VTST.8 Qd, Qn, Qm - /// A64: CMTST Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vshll_n_u8 (uint8x8_t a, const int n) + /// A32: VSHLL.U8 Qd, Dm, #n + /// A64: USHLL Vd.8H, Vn.8B, #n /// - public static Vector128 CompareTest(Vector128 left, Vector128 right) => CompareTest(left, right); + public static Vector128 ShiftLeftLogicalWideningLower(Vector64 value, byte count) => ShiftLeftLogicalWideningLower(value, count); /// - /// uint32x4_t vtstq_f32 (float32x4_t a, float32x4_t b) - /// A32: VTST.32 Qd, Qn, Qm - /// A64: CMTST Vd.4S, Vn.4S, Vm.4S - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// int32x4_t vshll_n_s16 (int16x4_t a, const int n) + /// A32: VSHLL.S16 Qd, Dm, #n + /// A64: SSHLL Vd.4S, Vn.4H, #n /// - public static Vector128 CompareTest(Vector128 left, Vector128 right) => CompareTest(left, right); + public static Vector128 ShiftLeftLogicalWideningLower(Vector64 value, byte count) => ShiftLeftLogicalWideningLower(value, count); /// - /// uint16x8_t vtstq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VTST.16 Qd, Qn, Qm - /// A64: CMTST Vd.8H, Vn.8H, Vm.8H + /// int64x2_t vshll_n_s32 (int32x2_t a, const int n) + /// A32: VSHLL.S32 Qd, Dm, #n + /// A64: SSHLL Vd.2D, Vn.2S, #n /// - public static Vector128 CompareTest(Vector128 left, Vector128 right) => CompareTest(left, right); + public static Vector128 ShiftLeftLogicalWideningLower(Vector64 value, byte count) => ShiftLeftLogicalWideningLower(value, count); /// - /// uint32x4_t vtstq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VTST.32 Qd, Qn, Qm - /// A64: CMTST Vd.4S, Vn.4S, Vm.4S + /// int16x8_t vshll_n_s8 (int8x8_t a, const int n) + /// A32: VSHLL.S8 Qd, Dm, #n + /// A64: SSHLL Vd.8H, Vn.8B, #n /// - public static Vector128 CompareTest(Vector128 left, Vector128 right) => CompareTest(left, right); + public static Vector128 ShiftLeftLogicalWideningLower(Vector64 value, byte count) => ShiftLeftLogicalWideningLower(value, count); /// - /// float64x1_t vdiv_f64 (float64x1_t a, float64x1_t b) - /// A32: VDIV.F64 Dd, Dn, Dm - /// A64: FDIV Dd, Dn, Dm + /// uint32x4_t vshll_n_u16 (uint16x4_t a, const int n) + /// A32: VSHLL.U16 Qd, Dm, #n + /// A64: USHLL Vd.4S, Vn.4H, #n /// - public static Vector64 DivideScalar(Vector64 left, Vector64 right) => DivideScalar(left, right); + public static Vector128 ShiftLeftLogicalWideningLower(Vector64 value, byte count) => ShiftLeftLogicalWideningLower(value, count); /// - /// float32_t vdivs_f32 (float32_t a, float32_t b) - /// A32: VDIV.F32 Sd, Sn, Sm - /// A64: FDIV Sd, Sn, Sm - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint64x2_t vshll_n_u32 (uint32x2_t a, const int n) + /// A32: VSHLL.U32 Qd, Dm, #n + /// A64: USHLL Vd.2D, Vn.2S, #n /// - public static Vector64 DivideScalar(Vector64 left, Vector64 right) => DivideScalar(left, right); + public static Vector128 ShiftLeftLogicalWideningLower(Vector64 value, byte count) => ShiftLeftLogicalWideningLower(value, count); /// - /// int8x8_t vmovn_s16 (int16x8_t a) - /// A32: VMOVN.I16 Dd, Qm - /// A64: XTN Vd.8B, Vn.8H + /// uint16x8_t vshll_high_n_u8 (uint8x16_t a, const int n) + /// A32: VSHLL.U8 Qd, Dm+1, #n + /// A64: USHLL2 Vd.8H, Vn.16B, #n /// - public static Vector64 ExtractAndNarrowLow (Vector128 value) => ExtractAndNarrowLow (value); + public static Vector128 ShiftLeftLogicalWideningUpper(Vector128 value, byte count) => ShiftLeftLogicalWideningUpper(value, count); /// - /// int16x4_t vmovn_s32 (int32x4_t a) - /// A32: VMOVN.I32 Dd, Qm - /// A64: XTN Vd.4H, Vn.4S + /// int32x4_t vshll_high_n_s16 (int16x8_t a, const int n) + /// A32: VSHLL.S16 Qd, Dm+1, #n + /// A64: SSHLL2 Vd.4S, Vn.8H, #n /// - public static Vector64 ExtractAndNarrowLow (Vector128 value) => ExtractAndNarrowLow (value); + public static Vector128 ShiftLeftLogicalWideningUpper(Vector128 value, byte count) => ShiftLeftLogicalWideningUpper(value, count); /// - /// int32x2_t vmovn_s64 (int64x2_t a) - /// A32: VMOVN.I64 Dd, Qm - /// A64: XTN Vd.2S, Vn.2D + /// int64x2_t vshll_high_n_s32 (int32x4_t a, const int n) + /// A32: VSHLL.S32 Qd, Dm+1, #n + /// A64: SSHLL2 Vd.2D, Vn.4S, #n /// - public static Vector64 ExtractAndNarrowLow (Vector128 value) => ExtractAndNarrowLow (value); + public static Vector128 ShiftLeftLogicalWideningUpper(Vector128 value, byte count) => ShiftLeftLogicalWideningUpper(value, count); /// - /// uint8x8_t vmovn_u16 (uint16x8_t a) - /// A32: VMOVN.I16 Dd, Qm - /// A64: XTN Vd.8B, Vn.8H + /// int16x8_t vshll_high_n_s8 (int8x16_t a, const int n) + /// A32: VSHLL.S8 Qd, Dm+1, #n + /// A64: SSHLL2 Vd.8H, Vn.16B, #n /// - public static Vector64 ExtractAndNarrowLow (Vector128 value) => ExtractAndNarrowLow (value); + public static Vector128 ShiftLeftLogicalWideningUpper(Vector128 value, byte count) => ShiftLeftLogicalWideningUpper(value, count); /// - /// uint16x4_t vmovn_u32 (uint32x4_t a) - /// A32: VMOVN.I32 Dd, Qm - /// A64: XTN Vd.4H, Vn.4S + /// uint32x4_t vshll_high_n_u16 (uint16x8_t a, const int n) + /// A32: VSHLL.U16 Qd, Dm+1, #n + /// A64: USHLL2 Vd.4S, Vn.8H, #n /// - public static Vector64 ExtractAndNarrowLow (Vector128 value) => ExtractAndNarrowLow (value); + public static Vector128 ShiftLeftLogicalWideningUpper(Vector128 value, byte count) => ShiftLeftLogicalWideningUpper(value, count); /// - /// uint32x2_t vmovn_u64 (uint64x2_t a) - /// A32: VMOVN.I64 Dd, Qm - /// A64: XTN Vd.2S, Vn.2D + /// uint64x2_t vshll_high_n_u32 (uint32x4_t a, const int n) + /// A32: VSHLL.U32 Qd, Dm+1, #n + /// A64: USHLL2 Vd.2D, Vn.4S, #n /// - public static Vector64 ExtractAndNarrowLow (Vector128 value) => ExtractAndNarrowLow (value); + public static Vector128 ShiftLeftLogicalWideningUpper(Vector128 value, byte count) => ShiftLeftLogicalWideningUpper(value, count); /// - /// int8x16_t vmovn_high_s16 (int8x8_t r, int16x8_t a) - /// A32: VMOVN.I16 Dd+1, Qm - /// A64: XTN2 Vd.16B, Vn.8H + /// uint8x8_t vshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VSHL.U8 Dd, Dn, Dm + /// A64: USHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) => ExtractAndNarrowHigh (lower, value); + public static Vector64 ShiftLogical(Vector64 value, Vector64 count) => ShiftLogical(value, count); /// - /// int16x8_t vmovn_high_s32 (int16x4_t r, int32x4_t a) - /// A32: VMOVN.I32 Dd+1, Qm - /// A64: XTN2 Vd.8H, Vn.4S + /// uint16x4_t vshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VSHL.U16 Dd, Dn, Dm + /// A64: USHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) => ExtractAndNarrowHigh (lower, value); + public static Vector64 ShiftLogical(Vector64 value, Vector64 count) => ShiftLogical(value, count); /// - /// int32x4_t vmovn_high_s64 (int32x2_t r, int64x2_t a) - /// A32: VMOVN.I64 Dd+1, Qm - /// A64: XTN2 Vd.4S, Vn.2D + /// uint32x2_t vshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VSHL.U32 Dd, Dn, Dm + /// A64: USHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) => ExtractAndNarrowHigh (lower, value); + public static Vector64 ShiftLogical(Vector64 value, Vector64 count) => ShiftLogical(value, count); /// - /// uint8x16_t vmovn_high_u16 (uint8x8_t r, uint16x8_t a) - /// A32: VMOVN.I16 Dd+1, Qm - /// A64: XTN2 Vd.16B, Vn.8H + /// uint8x8_t vshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VSHL.U8 Dd, Dn, Dm + /// A64: USHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) => ExtractAndNarrowHigh (lower, value); + public static Vector64 ShiftLogical(Vector64 value, Vector64 count) => ShiftLogical(value, count); /// - /// uint16x8_t vmovn_high_u32 (uint16x4_t r, uint32x4_t a) - /// A32: VMOVN.I32 Dd+1, Qm - /// A64: XTN2 Vd.8H, Vn.4S + /// uint16x4_t vshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VSHL.U16 Dd, Dn, Dm + /// A64: USHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) => ExtractAndNarrowHigh (lower, value); + public static Vector64 ShiftLogical(Vector64 value, Vector64 count) => ShiftLogical(value, count); /// - /// uint32x4_t vmovn_high_u64 (uint32x2_t r, uint64x2_t a) - /// A32: VMOVN.I64 Dd+1, Qm - /// A64: XTN2 Vd.4S, Vn.2D + /// uint32x2_t vshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VSHL.U32 Dd, Dn, Dm + /// A64: USHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) => ExtractAndNarrowHigh (lower, value); + public static Vector64 ShiftLogical(Vector64 value, Vector64 count) => ShiftLogical(value, count); /// - /// float32x2_t vfma_f32 (float32x2_t a, float32x2_t b, float32x2_t c) - /// A32: VFMA.F32 Dd, Dn, Dm - /// A64: FMLA Vd.2S, Vn.2S, Vm.2S + /// uint8x16_t vshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VSHL.U8 Qd, Qn, Qm + /// A64: USHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 FusedMultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplyAdd(acc, left, right); + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) => ShiftLogical(value, count); /// - /// float32x4_t vfmaq_f32 (float32x4_t a, float32x4_t b, float32x4_t c) - /// A32: VFMA.F32 Qd, Qn, Qm - /// A64: FMLA Vd.4S, Vn.4S, Vm.4S + /// uint16x8_t vshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VSHL.U16 Qd, Qn, Qm + /// A64: USHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector128 FusedMultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => FusedMultiplyAdd(acc, left, right); + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) => ShiftLogical(value, count); /// - /// float64x1_t vfma_f64 (float64x1_t a, float64x1_t b, float64x1_t c) - /// A32: VFMA.F64 Dd, Dn, Dm - /// A64: FMADD Dd, Dn, Dm, Da + /// uint32x4_t vshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VSHL.U32 Qd, Qn, Qm + /// A64: USHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 FusedMultiplyAddScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplyAddScalar(acc, left, right); + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) => ShiftLogical(value, count); /// - /// float32_t vfmas_f32 (float32_t a, float32_t b, float32_t c) - /// A32: VFMA.F32 Sd, Sn, Sm - /// A64: FMADD Sd, Sn, Sm, Sa - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint64x2_t vshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VSHL.U64 Qd, Qn, Qm + /// A64: USHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector64 FusedMultiplyAddScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplyAddScalar(acc, left, right); + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) => ShiftLogical(value, count); /// - /// float64x1_t vfnma_f64 (float64x1_t a, float64x1_t b, float64x1_t c) - /// A32: VFNMA.F64 Dd, Dn, Dm - /// A64: FNMADD Dd, Dn, Dm, Da - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x16_t vshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VSHL.U8 Qd, Qn, Qm + /// A64: USHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 FusedMultiplyAddNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplyAddNegatedScalar(acc, left, right); + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) => ShiftLogical(value, count); /// - /// float32_t vfnmas_f32 (float32_t a, float32_t b, float32_t c) - /// A32: VFNMA.F32 Sd, Sn, Sm - /// A64: FNMADD Sd, Sn, Sm, Sa - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x8_t vshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VSHL.U16 Qd, Qn, Qm + /// A64: USHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector64 FusedMultiplyAddNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplyAddNegatedScalar(acc, left, right); + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) => ShiftLogical(value, count); /// - /// float32x2_t vfms_f32 (float32x2_t a, float32x2_t b, float32x2_t c) - /// A32: VFMS.F32 Dd, Dn, Dm - /// A64: FMLS Vd.2S, Vn.2S, Vm.2S + /// uint32x4_t vshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VSHL.U32 Qd, Qn, Qm + /// A64: USHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 FusedMultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplySubtract(acc, left, right); + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) => ShiftLogical(value, count); /// - /// float32x4_t vfmsq_f32 (float32x4_t a, float32x4_t b, float32x4_t c) - /// A32: VFMS.F32 Qd, Qn, Qm - /// A64: FMLS Vd.4S, Vn.4S, Vm.4S + /// uint64x2_t vshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VSHL.U64 Qd, Qn, Qm + /// A64: USHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector128 FusedMultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => FusedMultiplySubtract(acc, left, right); + public static Vector128 ShiftLogical(Vector128 value, Vector128 count) => ShiftLogical(value, count); /// - /// float64x1_t vfms_f64 (float64x1_t a, float64x1_t b, float64x1_t c) - /// A32: VFMS.F64 Dd, Dn, Dm - /// A64: FMSUB Dd, Dn, Dm, Da + /// uint8x8_t vrshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VRSHL.U8 Dd, Dn, Dm + /// A64: URSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector64 FusedMultiplySubtractScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplySubtractScalar(acc, left, right); + public static Vector64 ShiftLogicalRounded(Vector64 value, Vector64 count) => ShiftLogicalRounded(value, count); /// - /// float32_t vfmss_f32 (float32_t a, float32_t b, float32_t c) - /// A32: VFMS.F32 Sd, Sn, Sm - /// A64: FMSUB Sd, Sn, Sm, Sa - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x4_t vrshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VRSHL.U16 Dd, Dn, Dm + /// A64: URSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector64 FusedMultiplySubtractScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplySubtractScalar(acc, left, right); + public static Vector64 ShiftLogicalRounded(Vector64 value, Vector64 count) => ShiftLogicalRounded(value, count); /// - /// float64x1_t vfnms_f64 (float64x1_t a, float64x1_t b, float64x1_t c) - /// A32: VFNMS.F64 Dd, Dn, Dm - /// A64: FNMSUB Dd, Dn, Dm, Da - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint32x2_t vrshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VRSHL.U32 Dd, Dn, Dm + /// A64: URSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector64 FusedMultiplySubtractNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplySubtractNegatedScalar(acc, left, right); + public static Vector64 ShiftLogicalRounded(Vector64 value, Vector64 count) => ShiftLogicalRounded(value, count); /// - /// float32_t vfnmss_f32 (float32_t a, float32_t b, float32_t c) - /// A32: VFNMS.F32 Sd, Sn, Sm - /// A64: FNMSUB Sd, Sn, Sm, Sa - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x8_t vrshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VRSHL.U8 Dd, Dn, Dm + /// A64: URSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector64 FusedMultiplySubtractNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplySubtractNegatedScalar(acc, left, right); + public static Vector64 ShiftLogicalRounded(Vector64 value, Vector64 count) => ShiftLogicalRounded(value, count); /// - /// int16x4_t vcls_s16 (int16x4_t a) - /// A32: VCLS.S16 Dd, Dm - /// A64: CLS Vd.4H, Vn.4H + /// uint16x4_t vrshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VRSHL.U16 Dd, Dn, Dm + /// A64: URSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector64 LeadingSignCount(Vector64 value) => LeadingSignCount(value); + public static Vector64 ShiftLogicalRounded(Vector64 value, Vector64 count) => ShiftLogicalRounded(value, count); /// - /// int32x2_t vcls_s32 (int32x2_t a) - /// A32: VCLS.S32 Dd, Dm - /// A64: CLS Vd.2S, Vn.2S + /// uint32x2_t vrshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VRSHL.U32 Dd, Dn, Dm + /// A64: URSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector64 LeadingSignCount(Vector64 value) => LeadingSignCount(value); + public static Vector64 ShiftLogicalRounded(Vector64 value, Vector64 count) => ShiftLogicalRounded(value, count); /// - /// int8x8_t vcls_s8 (int8x8_t a) - /// A32: VCLS.S8 Dd, Dm - /// A64: CLS Vd.8B, Vn.8B + /// uint8x16_t vrshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VRSHL.U8 Qd, Qn, Qm + /// A64: URSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 LeadingSignCount(Vector64 value) => LeadingSignCount(value); + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) => ShiftLogicalRounded(value, count); /// - /// int16x8_t vclsq_s16 (int16x8_t a) - /// A32: VCLS.S16 Qd, Qm - /// A64: CLS Vd.8H, Vn.8H + /// uint16x8_t vrshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VRSHL.U16 Qd, Qn, Qm + /// A64: URSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector128 LeadingSignCount(Vector128 value) => LeadingSignCount(value); + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) => ShiftLogicalRounded(value, count); /// - /// int32x4_t vclsq_s32 (int32x4_t a) - /// A32: VCLS.S32 Qd, Qm - /// A64: CLS Vd.4S, Vn.4S + /// uint32x4_t vrshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VRSHL.U32 Qd, Qn, Qm + /// A64: URSHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector128 LeadingSignCount(Vector128 value) => LeadingSignCount(value); + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) => ShiftLogicalRounded(value, count); /// - /// int8x16_t vclsq_s8 (int8x16_t a) - /// A32: VCLS.S8 Qd, Qm - /// A64: CLS Vd.16B, Vn.16B + /// uint64x2_t vrshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VRSHL.U64 Qd, Qn, Qm + /// A64: URSHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector128 LeadingSignCount(Vector128 value) => LeadingSignCount(value); + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) => ShiftLogicalRounded(value, count); /// - /// uint8x8_t vclz_u8 (uint8x8_t a) - /// A32: VCLZ.I8 Dd, Dm - /// A64: CLZ Vd.8B, Vn.8B + /// uint8x16_t vrshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VRSHL.U8 Qd, Qn, Qm + /// A64: URSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 LeadingZeroCount(Vector64 value) => LeadingZeroCount(value); + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) => ShiftLogicalRounded(value, count); /// - /// int16x4_t vclz_s16 (int16x4_t a) - /// A32: VCLZ.I16 Dd, Dm - /// A64: CLZ Vd.4H, Vn.4H + /// uint16x8_t vrshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VRSHL.U16 Qd, Qn, Qm + /// A64: URSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector64 LeadingZeroCount(Vector64 value) => LeadingZeroCount(value); + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) => ShiftLogicalRounded(value, count); /// - /// int32x2_t vclz_s32 (int32x2_t a) - /// A32: VCLZ.I32 Dd, Dm - /// A64: CLZ Vd.2S, Vn.2S + /// uint32x4_t vrshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VRSHL.U32 Qd, Qn, Qm + /// A64: URSHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 LeadingZeroCount(Vector64 value) => LeadingZeroCount(value); + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) => ShiftLogicalRounded(value, count); /// - /// int8x8_t vclz_s8 (int8x8_t a) - /// A32: VCLZ.I8 Dd, Dm - /// A64: CLZ Vd.8B, Vn.8B + /// uint64x2_t vrshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VRSHL.U64 Qd, Qn, Qm + /// A64: URSHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector64 LeadingZeroCount(Vector64 value) => LeadingZeroCount(value); + public static Vector128 ShiftLogicalRounded(Vector128 value, Vector128 count) => ShiftLogicalRounded(value, count); /// - /// uint16x4_t vclz_u16 (uint16x4_t a) - /// A32: VCLZ.I16 Dd, Dm - /// A64: CLZ Vd.4H, Vn.4H + /// uint8x8_t vqrshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VQRSHL.U8 Dd, Dn, Dm + /// A64: UQRSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector64 LeadingZeroCount(Vector64 value) => LeadingZeroCount(value); + public static Vector64 ShiftLogicalRoundedSaturate(Vector64 value, Vector64 count) => ShiftLogicalRoundedSaturate(value, count); /// - /// uint32x2_t vclz_u32 (uint32x2_t a) - /// A32: VCLZ.I32 Dd, Dm - /// A64: CLZ Vd.2S, Vn.2S + /// uint16x4_t vqrshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VQRSHL.U16 Dd, Dn, Dm + /// A64: UQRSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector64 LeadingZeroCount(Vector64 value) => LeadingZeroCount(value); + public static Vector64 ShiftLogicalRoundedSaturate(Vector64 value, Vector64 count) => ShiftLogicalRoundedSaturate(value, count); /// - /// uint8x16_t vclzq_u8 (uint8x16_t a) - /// A32: VCLZ.I8 Qd, Qm - /// A64: CLZ Vd.16B, Vn.16B + /// uint32x2_t vqrshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VQRSHL.U32 Dd, Dn, Dm + /// A64: UQRSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 LeadingZeroCount(Vector128 value) => LeadingZeroCount(value); + public static Vector64 ShiftLogicalRoundedSaturate(Vector64 value, Vector64 count) => ShiftLogicalRoundedSaturate(value, count); /// - /// int16x8_t vclzq_s16 (int16x8_t a) - /// A32: VCLZ.I16 Qd, Qm - /// A64: CLZ Vd.8H, Vn.8H + /// uint8x8_t vqrshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VQRSHL.U8 Dd, Dn, Dm + /// A64: UQRSHL Vd.8B, Vn.8B, Vm.8B /// - public static Vector128 LeadingZeroCount(Vector128 value) => LeadingZeroCount(value); + public static Vector64 ShiftLogicalRoundedSaturate(Vector64 value, Vector64 count) => ShiftLogicalRoundedSaturate(value, count); /// - /// int32x4_t vclzq_s32 (int32x4_t a) - /// A32: VCLZ.I32 Qd, Qm - /// A64: CLZ Vd.4S, Vn.4S + /// uint16x4_t vqrshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VQRSHL.U16 Dd, Dn, Dm + /// A64: UQRSHL Vd.4H, Vn.4H, Vm.4H /// - public static Vector128 LeadingZeroCount(Vector128 value) => LeadingZeroCount(value); + public static Vector64 ShiftLogicalRoundedSaturate(Vector64 value, Vector64 count) => ShiftLogicalRoundedSaturate(value, count); /// - /// int8x16_t vclzq_s8 (int8x16_t a) - /// A32: VCLZ.I8 Qd, Qm - /// A64: CLZ Vd.16B, Vn.16B + /// uint32x2_t vqrshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VQRSHL.U32 Dd, Dn, Dm + /// A64: UQRSHL Vd.2S, Vn.2S, Vm.2S /// - public static Vector128 LeadingZeroCount(Vector128 value) => LeadingZeroCount(value); + public static Vector64 ShiftLogicalRoundedSaturate(Vector64 value, Vector64 count) => ShiftLogicalRoundedSaturate(value, count); /// - /// uint16x8_t vclzq_u16 (uint16x8_t a) - /// A32: VCLZ.I16 Qd, Qm - /// A64: CLZ Vd.8H, Vn.8H + /// uint8x16_t vqrshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VQRSHL.U8 Qd, Qn, Qm + /// A64: UQRSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector128 LeadingZeroCount(Vector128 value) => LeadingZeroCount(value); + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) => ShiftLogicalRoundedSaturate(value, count); /// - /// uint32x4_t vclzq_u32 (uint32x4_t a) - /// A32: VCLZ.I32 Qd, Qm - /// A64: CLZ Vd.4S, Vn.4S + /// uint16x8_t vqrshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VQRSHL.U16 Qd, Qn, Qm + /// A64: UQRSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector128 LeadingZeroCount(Vector128 value) => LeadingZeroCount(value); + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) => ShiftLogicalRoundedSaturate(value, count); /// - /// uint8x8_t vld1_u8 (uint8_t const * ptr) - /// A32: VLD1.8 Dd, [Rn] - /// A64: LD1 Vt.8B, [Xn] + /// uint32x4_t vqrshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VQRSHL.U32 Qd, Qn, Qm + /// A64: UQRSHL Vd.4S, Vn.4S, Vm.4S /// - public static unsafe Vector64 LoadVector64(byte* address) => LoadVector64(address); + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) => ShiftLogicalRoundedSaturate(value, count); /// - /// float64x1_t vld1_f64 (float64_t const * ptr) - /// A32: VLD1.64 Dd, [Rn] - /// A64: LD1 Vt.1D, [Xn] + /// uint64x2_t vqrshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VQRSHL.U64 Qd, Qn, Qm + /// A64: UQRSHL Vd.2D, Vn.2D, Vm.2D /// - public static unsafe Vector64 LoadVector64(double* address) => LoadVector64(address); + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) => ShiftLogicalRoundedSaturate(value, count); /// - /// int16x4_t vld1_s16 (int16_t const * ptr) - /// A32: VLD1.16 Dd, [Rn] - /// A64: LD1 Vt.4H, [Xn] + /// uint8x16_t vqrshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VQRSHL.U8 Qd, Qn, Qm + /// A64: UQRSHL Vd.16B, Vn.16B, Vm.16B /// - public static unsafe Vector64 LoadVector64(short* address) => LoadVector64(address); + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) => ShiftLogicalRoundedSaturate(value, count); /// - /// int32x2_t vld1_s32 (int32_t const * ptr) - /// A32: VLD1.32 Dd, [Rn] - /// A64: LD1 Vt.2S, [Xn] + /// uint16x8_t vqrshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VQRSHL.U16 Qd, Qn, Qm + /// A64: UQRSHL Vd.8H, Vn.8H, Vm.8H /// - public static unsafe Vector64 LoadVector64(int* address) => LoadVector64(address); + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) => ShiftLogicalRoundedSaturate(value, count); /// - /// int64x1_t vld1_s64 (int64_t const * ptr) - /// A32: VLD1.64 Dd, [Rn] - /// A64: LD1 Vt.1D, [Xn] + /// uint32x4_t vqrshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VQRSHL.U32 Qd, Qn, Qm + /// A64: UQRSHL Vd.4S, Vn.4S, Vm.4S /// - public static unsafe Vector64 LoadVector64(long* address) => LoadVector64(address); + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) => ShiftLogicalRoundedSaturate(value, count); /// - /// int8x8_t vld1_s8 (int8_t const * ptr) - /// A32: VLD1.8 Dd, [Rn] - /// A64: LD1 Vt.8B, [Xn] + /// uint64x2_t vqrshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VQRSHL.U64 Qd, Qn, Qm + /// A64: UQRSHL Vd.2D, Vn.2D, Vm.2D /// - public static unsafe Vector64 LoadVector64(sbyte* address) => LoadVector64(address); + public static Vector128 ShiftLogicalRoundedSaturate(Vector128 value, Vector128 count) => ShiftLogicalRoundedSaturate(value, count); /// - /// float32x2_t vld1_f32 (float32_t const * ptr) - /// A32: VLD1.32 Dd, [Rn] - /// A64: LD1 Vt.2S, [Xn] + /// uint64x1_t vqrshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VQRSHL.U64 Dd, Dn, Dm + /// A64: UQRSHL Dd, Dn, Dm /// - public static unsafe Vector64 LoadVector64(float* address) => LoadVector64(address); + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalRoundedSaturateScalar(value, count); /// - /// uint16x4_t vld1_u16 (uint16_t const * ptr) - /// A32: VLD1.16 Dd, [Rn] - /// A64: LD1 Vt.4H, [Xn] + /// uint64x1_t vqrshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VQRSHL.U64 Dd, Dn, Dm + /// A64: UQRSHL Dd, Dn, Dm /// - public static unsafe Vector64 LoadVector64(ushort* address) => LoadVector64(address); + public static Vector64 ShiftLogicalRoundedSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalRoundedSaturateScalar(value, count); /// - /// uint32x2_t vld1_u32 (uint32_t const * ptr) - /// A32: VLD1.32 Dd, [Rn] - /// A64: LD1 Vt.2S, [Xn] + /// uint64x1_t vrshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VRSHL.U64 Dd, Dn, Dm + /// A64: URSHL Dd, Dn, Dm /// - public static unsafe Vector64 LoadVector64(uint* address) => LoadVector64(address); + public static Vector64 ShiftLogicalRoundedScalar(Vector64 value, Vector64 count) => ShiftLogicalRoundedScalar(value, count); /// - /// uint64x1_t vld1_u64 (uint64_t const * ptr) - /// A32: VLD1.64 Dd, [Rn] - /// A64: LD1 Vt.1D, [Xn] + /// uint64x1_t vrshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VRSHL.U64 Dd, Dn, Dm + /// A64: URSHL Dd, Dn, Dm /// - public static unsafe Vector64 LoadVector64(ulong* address) => LoadVector64(address); + public static Vector64 ShiftLogicalRoundedScalar(Vector64 value, Vector64 count) => ShiftLogicalRoundedScalar(value, count); /// - /// uint8x16_t vld1q_u8 (uint8_t const * ptr) - /// A32: VLD1.8 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.16B, [Xn] + /// uint8x8_t vqshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VQSHL.U8 Dd, Dn, Dm + /// A64: UQSHL Vd.8B, Vn.8B, Vm.8B /// - public static unsafe Vector128 LoadVector128(byte* address) => LoadVector128(address); + public static Vector64 ShiftLogicalSaturate(Vector64 value, Vector64 count) => ShiftLogicalSaturate(value, count); /// - /// float64x2_t vld1q_f64 (float64_t const * ptr) - /// A32: VLD1.64 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.2D, [Xn] + /// uint16x4_t vqshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VQSHL.U16 Dd, Dn, Dm + /// A64: UQSHL Vd.4H, Vn.4H, Vm.4H /// - public static unsafe Vector128 LoadVector128(double* address) => LoadVector128(address); + public static Vector64 ShiftLogicalSaturate(Vector64 value, Vector64 count) => ShiftLogicalSaturate(value, count); /// - /// int16x8_t vld1q_s16 (int16_t const * ptr) - /// A32: VLD1.16 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.8H, [Xn] + /// uint32x2_t vqshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VQSHL.U32 Dd, Dn, Dm + /// A64: UQSHL Vd.2S, Vn.2S, Vm.2S /// - public static unsafe Vector128 LoadVector128(short* address) => LoadVector128(address); + public static Vector64 ShiftLogicalSaturate(Vector64 value, Vector64 count) => ShiftLogicalSaturate(value, count); /// - /// int32x4_t vld1q_s32 (int32_t const * ptr) - /// A32: VLD1.32 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.4S, [Xn] + /// uint8x8_t vqshl_u8 (uint8x8_t a, int8x8_t b) + /// A32: VQSHL.U8 Dd, Dn, Dm + /// A64: UQSHL Vd.8B, Vn.8B, Vm.8B /// - public static unsafe Vector128 LoadVector128(int* address) => LoadVector128(address); + public static Vector64 ShiftLogicalSaturate(Vector64 value, Vector64 count) => ShiftLogicalSaturate(value, count); /// - /// int64x2_t vld1q_s64 (int64_t const * ptr) - /// A32: VLD1.64 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.2D, [Xn] + /// uint16x4_t vqshl_u16 (uint16x4_t a, int16x4_t b) + /// A32: VQSHL.U16 Dd, Dn, Dm + /// A64: UQSHL Vd.4H, Vn.4H, Vm.4H /// - public static unsafe Vector128 LoadVector128(long* address) => LoadVector128(address); + public static Vector64 ShiftLogicalSaturate(Vector64 value, Vector64 count) => ShiftLogicalSaturate(value, count); /// - /// int8x16_t vld1q_s8 (int8_t const * ptr) - /// A32: VLD1.8 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.16B, [Xn] + /// uint32x2_t vqshl_u32 (uint32x2_t a, int32x2_t b) + /// A32: VQSHL.U32 Dd, Dn, Dm + /// A64: UQSHL Vd.2S, Vn.2S, Vm.2S /// - public static unsafe Vector128 LoadVector128(sbyte* address) => LoadVector128(address); + public static Vector64 ShiftLogicalSaturate(Vector64 value, Vector64 count) => ShiftLogicalSaturate(value, count); /// - /// float32x4_t vld1q_f32 (float32_t const * ptr) - /// A32: VLD1.32 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.4S, [Xn] + /// uint8x16_t vqshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VQSHL.U8 Qd, Qn, Qm + /// A64: UQSHL Vd.16B, Vn.16B, Vm.16B /// - public static unsafe Vector128 LoadVector128(float* address) => LoadVector128(address); + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) => ShiftLogicalSaturate(value, count); /// - /// uint16x8_t vld1q_s16 (uint16_t const * ptr) - /// A32: VLD1.16 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.8H, [Xn] + /// uint16x8_t vqshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VQSHL.U16 Qd, Qn, Qm + /// A64: UQSHL Vd.8H, Vn.8H, Vm.8H /// - public static unsafe Vector128 LoadVector128(ushort* address) => LoadVector128(address); + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) => ShiftLogicalSaturate(value, count); /// - /// uint32x4_t vld1q_s32 (uint32_t const * ptr) - /// A32: VLD1.32 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.4S, [Xn] + /// uint32x4_t vqshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VQSHL.U32 Qd, Qn, Qm + /// A64: UQSHL Vd.4S, Vn.4S, Vm.4S /// - public static unsafe Vector128 LoadVector128(uint* address) => LoadVector128(address); + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) => ShiftLogicalSaturate(value, count); /// - /// uint64x2_t vld1q_u64 (uint64_t const * ptr) - /// A32: VLD1.64 Dd, Dd+1, [Rn] - /// A64: LD1 Vt.2D, [Xn] + /// uint64x2_t vqshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VQSHL.U64 Qd, Qn, Qm + /// A64: UQSHL Vd.2D, Vn.2D, Vm.2D /// - public static unsafe Vector128 LoadVector128(ulong* address) => LoadVector128(address); + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) => ShiftLogicalSaturate(value, count); /// - /// uint8x8_t vmax_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VMAX.U8 Dd, Dn, Dm - /// A64: UMAX Vd.8B, Vn.8B, Vm.8B + /// uint8x16_t vqshlq_u8 (uint8x16_t a, int8x16_t b) + /// A32: VQSHL.U8 Qd, Qn, Qm + /// A64: UQSHL Vd.16B, Vn.16B, Vm.16B /// - public static Vector64 Max(Vector64 left, Vector64 right) => Max(left, right); + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) => ShiftLogicalSaturate(value, count); /// - /// int16x4_t vmax_s16 (int16x4_t a, int16x4_t b) - /// A32: VMAX.S16 Dd, Dn, Dm - /// A64: SMAX Vd.4H, Vn.4H, Vm.4H + /// uint16x8_t vqshlq_u16 (uint16x8_t a, int16x8_t b) + /// A32: VQSHL.U16 Qd, Qn, Qm + /// A64: UQSHL Vd.8H, Vn.8H, Vm.8H /// - public static Vector64 Max(Vector64 left, Vector64 right) => Max(left, right); + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) => ShiftLogicalSaturate(value, count); /// - /// int32x2_t vmax_s32 (int32x2_t a, int32x2_t b) - /// A32: VMAX.S32 Dd, Dn, Dm - /// A64: SMAX Vd.2S, Vn.2S, Vm.2S + /// uint32x4_t vqshlq_u32 (uint32x4_t a, int32x4_t b) + /// A32: VQSHL.U32 Qd, Qn, Qm + /// A64: UQSHL Vd.4S, Vn.4S, Vm.4S /// - public static Vector64 Max(Vector64 left, Vector64 right) => Max(left, right); + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) => ShiftLogicalSaturate(value, count); /// - /// int8x8_t vmax_s8 (int8x8_t a, int8x8_t b) - /// A32: VMAX.S8 Dd, Dn, Dm - /// A64: SMAX Vd.8B, Vn.8B, Vm.8B + /// uint64x2_t vqshlq_u64 (uint64x2_t a, int64x2_t b) + /// A32: VQSHL.U64 Qd, Qn, Qm + /// A64: UQSHL Vd.2D, Vn.2D, Vm.2D /// - public static Vector64 Max(Vector64 left, Vector64 right) => Max(left, right); + public static Vector128 ShiftLogicalSaturate(Vector128 value, Vector128 count) => ShiftLogicalSaturate(value, count); /// - /// float32x2_t vmax_f32 (float32x2_t a, float32x2_t b) - /// A32: VMAX.F32 Dd, Dn, Dm - /// A64: FMAX Vd.2S, Vn.2S, Vm.2S + /// uint64x1_t vqshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VQSHL.U64 Dd, Dn, Dm + /// A64: UQSHL Dd, Dn, Dm /// - public static Vector64 Max(Vector64 left, Vector64 right) => Max(left, right); + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalSaturateScalar(value, count); /// - /// uint16x4_t vmax_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VMAX.U16 Dd, Dn, Dm - /// A64: UMAX Vd.4H, Vn.4H, Vm.4H + /// uint64x1_t vqshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VQSHL.U64 Dd, Dn, Dm + /// A64: UQSHL Dd, Dn, Dm /// - public static Vector64 Max(Vector64 left, Vector64 right) => Max(left, right); + public static Vector64 ShiftLogicalSaturateScalar(Vector64 value, Vector64 count) => ShiftLogicalSaturateScalar(value, count); /// - /// uint32x2_t vmax_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VMAX.U32 Dd, Dn, Dm - /// A64: UMAX Vd.2S, Vn.2S, Vm.2S + /// uint64x1_t vshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VSHL.U64 Dd, Dn, Dm + /// A64: USHL Dd, Dn, Dm /// - public static Vector64 Max(Vector64 left, Vector64 right) => Max(left, right); + public static Vector64 ShiftLogicalScalar(Vector64 value, Vector64 count) => ShiftLogicalScalar(value, count); /// - /// uint8x16_t vmaxq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VMAX.U8 Qd, Qn, Qm - /// A64: UMAX Vd.16B, Vn.16B, Vm.16B + /// uint64x1_t vshl_u64 (uint64x1_t a, int64x1_t b) + /// A32: VSHL.U64 Dd, Dn, Dm + /// A64: USHL Dd, Dn, Dm /// - public static Vector128 Max(Vector128 left, Vector128 right) => Max(left, right); + public static Vector64 ShiftLogicalScalar(Vector64 value, Vector64 count) => ShiftLogicalScalar(value, count); /// - /// int16x8_t vmaxq_s16 (int16x8_t a, int16x8_t b) - /// A32: VMAX.S16 Qd, Qn, Qm - /// A64: SMAX Vd.8H, Vn.8H, Vm.8H + /// int16x4_t vshr_n_s16 (int16x4_t a, const int n) + /// A32: VSHR.S16 Dd, Dm, #n + /// A64: SSHR Vd.4H, Vn.4H, #n /// - public static Vector128 Max(Vector128 left, Vector128 right) => Max(left, right); + public static Vector64 ShiftRightArithmetic(Vector64 value, byte count) => ShiftRightArithmetic(value, count); /// - /// int32x4_t vmaxq_s32 (int32x4_t a, int32x4_t b) - /// A32: VMAX.S32 Qd, Qn, Qm - /// A64: SMAX Vd.4S, Vn.4S, Vm.4S + /// int32x2_t vshr_n_s32 (int32x2_t a, const int n) + /// A32: VSHR.S32 Dd, Dm, #n + /// A64: SSHR Vd.2S, Vn.2S, #n /// - public static Vector128 Max(Vector128 left, Vector128 right) => Max(left, right); + public static Vector64 ShiftRightArithmetic(Vector64 value, byte count) => ShiftRightArithmetic(value, count); /// - /// int8x16_t vmaxq_s8 (int8x16_t a, int8x16_t b) - /// A32: VMAX.S8 Qd, Qn, Qm - /// A64: SMAX Vd.16B, Vn.16B, Vm.16B + /// int8x8_t vshr_n_s8 (int8x8_t a, const int n) + /// A32: VSHR.S8 Dd, Dm, #n + /// A64: SSHR Vd.8B, Vn.8B, #n /// - public static Vector128 Max(Vector128 left, Vector128 right) => Max(left, right); + public static Vector64 ShiftRightArithmetic(Vector64 value, byte count) => ShiftRightArithmetic(value, count); /// - /// float32x4_t vmaxq_f32 (float32x4_t a, float32x4_t b) - /// A32: VMAX.F32 Qd, Qn, Qm - /// A64: FMAX Vd.4S, Vn.4S, Vm.4S + /// int16x8_t vshrq_n_s16 (int16x8_t a, const int n) + /// A32: VSHR.S16 Qd, Qm, #n + /// A64: SSHR Vd.8H, Vn.8H, #n /// - public static Vector128 Max(Vector128 left, Vector128 right) => Max(left, right); + public static Vector128 ShiftRightArithmetic(Vector128 value, byte count) => ShiftRightArithmetic(value, count); /// - /// uint16x8_t vmaxq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VMAX.U16 Qd, Qn, Qm - /// A64: UMAX Vd.8H, Vn.8H, Vm.8H + /// int32x4_t vshrq_n_s32 (int32x4_t a, const int n) + /// A32: VSHR.S32 Qd, Qm, #n + /// A64: SSHR Vd.4S, Vn.4S, #n /// - public static Vector128 Max(Vector128 left, Vector128 right) => Max(left, right); + public static Vector128 ShiftRightArithmetic(Vector128 value, byte count) => ShiftRightArithmetic(value, count); /// - /// uint32x4_t vmaxq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VMAX.U32 Qd, Qn, Qm - /// A64: UMAX Vd.4S, Vn.4S, Vm.4S + /// int64x2_t vshrq_n_s64 (int64x2_t a, const int n) + /// A32: VSHR.S64 Qd, Qm, #n + /// A64: SSHR Vd.2D, Vn.2D, #n /// - public static Vector128 Max(Vector128 left, Vector128 right) => Max(left, right); + public static Vector128 ShiftRightArithmetic(Vector128 value, byte count) => ShiftRightArithmetic(value, count); /// - /// float32x2_t vmaxnm_f32 (float32x2_t a, float32x2_t b) - /// A32: VMAXNM.F32 Dd, Dn, Dm - /// A64: FMAXNM Vd.2S, Vn.2S, Vm.2S + /// int8x16_t vshrq_n_s8 (int8x16_t a, const int n) + /// A32: VSHR.S8 Qd, Qm, #n + /// A64: SSHR Vd.16B, Vn.16B, #n /// - public static Vector64 MaxNumber(Vector64 left, Vector64 right) => MaxNumber(left, right); + public static Vector128 ShiftRightArithmetic(Vector128 value, byte count) => ShiftRightArithmetic(value, count); /// - /// float32x4_t vmaxnmq_f32 (float32x4_t a, float32x4_t b) - /// A32: VMAXNM.F32 Qd, Qn, Qm - /// A64: FMAXNM Vd.4S, Vn.4S, Vm.4S + /// int16x4_t vsra_n_s16 (int16x4_t a, int16x4_t b, const int n) + /// A32: VSRA.S16 Dd, Dm, #n + /// A64: SSRA Vd.4H, Vn.4H, #n /// - public static Vector128 MaxNumber(Vector128 left, Vector128 right) => MaxNumber(left, right); + public static Vector64 ShiftRightArithmeticAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightArithmeticAdd(addend, value, count); /// - /// float64x1_t vmaxnm_f64 (float64x1_t a, float64x1_t b) - /// A32: VMAXNM.F64 Dd, Dn, Dm - /// A64: FMAXNM Dd, Dn, Dm + /// int32x2_t vsra_n_s32 (int32x2_t a, int32x2_t b, const int n) + /// A32: VSRA.S32 Dd, Dm, #n + /// A64: SSRA Vd.2S, Vn.2S, #n /// - public static Vector64 MaxNumberScalar(Vector64 left, Vector64 right) => MaxNumberScalar(left, right); + public static Vector64 ShiftRightArithmeticAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightArithmeticAdd(addend, value, count); /// - /// float32_t vmaxnms_f32 (float32_t a, float32_t b) - /// A32: VMAXNM.F32 Sd, Sn, Sm - /// A64: FMAXNM Sd, Sn, Sm + /// int8x8_t vsra_n_s8 (int8x8_t a, int8x8_t b, const int n) + /// A32: VSRA.S8 Dd, Dm, #n + /// A64: SSRA Vd.8B, Vn.8B, #n /// - public static Vector64 MaxNumberScalar(Vector64 left, Vector64 right) => MaxNumberScalar(left, right); + public static Vector64 ShiftRightArithmeticAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightArithmeticAdd(addend, value, count); /// - /// uint8x8_t vpmax_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VPMAX.U8 Dd, Dn, Dm - /// A64: UMAXP Vd.8B, Vn.8B, Vm.8B + /// int16x8_t vsraq_n_s16 (int16x8_t a, int16x8_t b, const int n) + /// A32: VSRA.S16 Qd, Qm, #n + /// A64: SSRA Vd.8H, Vn.8H, #n /// - public static Vector64 MaxPairwise(Vector64 left, Vector64 right) => MaxPairwise(left, right); + public static Vector128 ShiftRightArithmeticAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightArithmeticAdd(addend, value, count); /// - /// int16x4_t vpmax_s16 (int16x4_t a, int16x4_t b) - /// A32: VPMAX.S16 Dd, Dn, Dm - /// A64: SMAXP Vd.4H, Vn.4H, Vm.4H + /// int32x4_t vsraq_n_s32 (int32x4_t a, int32x4_t b, const int n) + /// A32: VSRA.S32 Qd, Qm, #n + /// A64: SSRA Vd.4S, Vn.4S, #n /// - public static Vector64 MaxPairwise(Vector64 left, Vector64 right) => MaxPairwise(left, right); + public static Vector128 ShiftRightArithmeticAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightArithmeticAdd(addend, value, count); /// - /// int32x2_t vpmax_s32 (int32x2_t a, int32x2_t b) - /// A32: VPMAX.S32 Dd, Dn, Dm - /// A64: SMAXP Vd.2S, Vn.2S, Vm.2S + /// int64x2_t vsraq_n_s64 (int64x2_t a, int64x2_t b, const int n) + /// A32: VSRA.S64 Qd, Qm, #n + /// A64: SSRA Vd.2D, Vn.2D, #n /// - public static Vector64 MaxPairwise(Vector64 left, Vector64 right) => MaxPairwise(left, right); + public static Vector128 ShiftRightArithmeticAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightArithmeticAdd(addend, value, count); /// - /// int8x8_t vpmax_s8 (int8x8_t a, int8x8_t b) - /// A32: VPMAX.S8 Dd, Dn, Dm - /// A64: SMAXP Vd.8B, Vn.8B, Vm.8B + /// int8x16_t vsraq_n_s8 (int8x16_t a, int8x16_t b, const int n) + /// A32: VSRA.S8 Qd, Qm, #n + /// A64: SSRA Vd.16B, Vn.16B, #n /// - public static Vector64 MaxPairwise(Vector64 left, Vector64 right) => MaxPairwise(left, right); + public static Vector128 ShiftRightArithmeticAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightArithmeticAdd(addend, value, count); /// - /// float32x2_t vpmax_f32 (float32x2_t a, float32x2_t b) - /// A32: VPMAX.F32 Dd, Dn, Dm - /// A64: FMAXP Vd.2S, Vn.2S, Vm.2S + /// int64x1_t vsra_n_s64 (int64x1_t a, int64x1_t b, const int n) + /// A32: VSRA.S64 Dd, Dm, #n + /// A64: SSRA Dd, Dn, #n /// - public static Vector64 MaxPairwise(Vector64 left, Vector64 right) => MaxPairwise(left, right); + public static Vector64 ShiftRightArithmeticAddScalar(Vector64 addend, Vector64 value, byte count) => ShiftRightArithmeticAddScalar(addend, value, count); /// - /// uint16x4_t vpmax_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VPMAX.U16 Dd, Dn, Dm - /// A64: UMAXP Vd.4H, Vn.4H, Vm.4H + /// int16x4_t vqshrn_n_s32 (int32x4_t a, const int n) + /// A32: VQSHRN.S32 Dd, Qm, #n + /// A64: SQSHRN Vd.4H, Vn.4S, #n /// - public static Vector64 MaxPairwise(Vector64 left, Vector64 right) => MaxPairwise(left, right); + public static Vector64 ShiftRightArithmeticNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightArithmeticNarrowingSaturateLower(value, count); /// - /// uint32x2_t vpmax_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VPMAX.U32 Dd, Dn, Dm - /// A64: UMAXP Vd.2S, Vn.2S, Vm.2S + /// int32x2_t vqshrn_n_s64 (int64x2_t a, const int n) + /// A32: VQSHRN.S64 Dd, Qm, #n + /// A64: SQSHRN Vd.2S, Vn.2D, #n /// - public static Vector64 MaxPairwise(Vector64 left, Vector64 right) => MaxPairwise(left, right); + public static Vector64 ShiftRightArithmeticNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightArithmeticNarrowingSaturateLower(value, count); /// - /// uint8x8_t vmin_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VMIN.U8 Dd, Dn, Dm - /// A64: UMIN Vd.8B, Vn.8B, Vm.8B + /// int8x8_t vqshrn_n_s16 (int16x8_t a, const int n) + /// A32: VQSHRN.S16 Dd, Qm, #n + /// A64: SQSHRN Vd.8B, Vn.8H, #n /// - public static Vector64 Min(Vector64 left, Vector64 right) => Min(left, right); + public static Vector64 ShiftRightArithmeticNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightArithmeticNarrowingSaturateLower(value, count); /// - /// int16x4_t vmin_s16 (int16x4_t a, int16x4_t b) - /// A32: VMIN.S16 Dd, Dn, Dm - /// A64: SMIN Vd.4H, Vn.4H, Vm.4H + /// uint8x8_t vqshrun_n_s16 (int16x8_t a, const int n) + /// A32: VQSHRUN.S16 Dd, Qm, #n + /// A64: SQSHRUN Vd.8B, Vn.8H, #n /// - public static Vector64 Min(Vector64 left, Vector64 right) => Min(left, right); + public static Vector64 ShiftRightArithmeticNarrowingSaturateUnsignedLower(Vector128 value, byte count) => ShiftRightArithmeticNarrowingSaturateUnsignedLower(value, count); /// - /// int32x2_t vmin_s32 (int32x2_t a, int32x2_t b) - /// A32: VMIN.S32 Dd, Dn, Dm - /// A64: SMIN Vd.2S, Vn.2S, Vm.2S + /// uint16x4_t vqshrun_n_s32 (int32x4_t a, const int n) + /// A32: VQSHRUN.S32 Dd, Qm, #n + /// A64: SQSHRUN Vd.4H, Vn.4S, #n /// - public static Vector64 Min(Vector64 left, Vector64 right) => Min(left, right); + public static Vector64 ShiftRightArithmeticNarrowingSaturateUnsignedLower(Vector128 value, byte count) => ShiftRightArithmeticNarrowingSaturateUnsignedLower(value, count); /// - /// int8x8_t vmin_s8 (int8x8_t a, int8x8_t b) - /// A32: VMIN.S8 Dd, Dn, Dm - /// A64: SMIN Vd.8B, Vn.8B, Vm.8B + /// uint32x2_t vqshrun_n_s64 (int64x2_t a, const int n) + /// A32: VQSHRUN.S64 Dd, Qm, #n + /// A64: SQSHRUN Vd.2S, Vn.2D, #n /// - public static Vector64 Min(Vector64 left, Vector64 right) => Min(left, right); + public static Vector64 ShiftRightArithmeticNarrowingSaturateUnsignedLower(Vector128 value, byte count) => ShiftRightArithmeticNarrowingSaturateUnsignedLower(value, count); /// - /// float32x2_t vmin_f32 (float32x2_t a, float32x2_t b) - /// A32: VMIN.F32 Dd, Dn, Dm - /// A64: FMIN Vd.2S, Vn.2S, Vm.2S + /// uint8x16_t vqshrun_high_n_s16 (uint8x8_t r, int16x8_t a, const int n) + /// A32: VQSHRUN.S16 Dd+1, Dn, #n + /// A64: SQSHRUN2 Vd.16B, Vn.8H, #n /// - public static Vector64 Min(Vector64 left, Vector64 right) => Min(left, right); + public static Vector128 ShiftRightArithmeticNarrowingSaturateUnsignedUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightArithmeticNarrowingSaturateUnsignedUpper(lower, value, count); /// - /// uint16x4_t vmin_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VMIN.U16 Dd, Dn, Dm - /// A64: UMIN Vd.4H, Vn.4H, Vm.4H + /// uint16x8_t vqshrun_high_n_s32 (uint16x4_t r, int32x4_t a, const int n) + /// A32: VQSHRUN.S32 Dd+1, Dn, #n + /// A64: SQSHRUN2 Vd.8H, Vn.4S, #n /// - public static Vector64 Min(Vector64 left, Vector64 right) => Min(left, right); + public static Vector128 ShiftRightArithmeticNarrowingSaturateUnsignedUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightArithmeticNarrowingSaturateUnsignedUpper(lower, value, count); /// - /// uint32x2_t vmin_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VMIN.U32 Dd, Dn, Dm - /// A64: UMIN Vd.2S, Vn.2S, Vm.2S + /// uint32x4_t vqshrun_high_n_s64 (uint32x2_t r, int64x2_t a, const int n) + /// A32: VQSHRUN.S64 Dd+1, Dn, #n + /// A64: SQSHRUN2 Vd.4S, Vn.2D, #n /// - public static Vector64 Min(Vector64 left, Vector64 right) => Min(left, right); + public static Vector128 ShiftRightArithmeticNarrowingSaturateUnsignedUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightArithmeticNarrowingSaturateUnsignedUpper(lower, value, count); /// - /// uint8x16_t vminq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VMIN.U8 Qd, Qn, Qm - /// A64: UMIN Vd.16B, Vn.16B, Vm.16B + /// int16x8_t vqshrn_high_n_s32 (int16x4_t r, int32x4_t a, const int n) + /// A32: VQSHRN.S32 Dd+1, Qm, #n + /// A64: SQSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector128 Min(Vector128 left, Vector128 right) => Min(left, right); + public static Vector128 ShiftRightArithmeticNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightArithmeticNarrowingSaturateUpper(lower, value, count); /// - /// int16x8_t vminq_s16 (int16x8_t a, int16x8_t b) - /// A32: VMIN.S16 Qd, Qn, Qm - /// A64: SMIN Vd.8H, Vn.8H, Vm.8H + /// int32x4_t vqshrn_high_n_s64 (int32x2_t r, int64x2_t a, const int n) + /// A32: VQSHRN.S64 Dd+1, Qm, #n + /// A64: SQSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector128 Min(Vector128 left, Vector128 right) => Min(left, right); + public static Vector128 ShiftRightArithmeticNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightArithmeticNarrowingSaturateUpper(lower, value, count); /// - /// int32x4_t vminq_s32 (int32x4_t a, int32x4_t b) - /// A32: VMIN.S32 Qd, Qn, Qm - /// A64: SMIN Vd.4S, Vn.4S, Vm.4S + /// int8x16_t vqshrn_high_n_s16 (int8x8_t r, int16x8_t a, const int n) + /// A32: VQSHRN.S16 Dd+1, Qm, #n + /// A64: SQSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector128 Min(Vector128 left, Vector128 right) => Min(left, right); + public static Vector128 ShiftRightArithmeticNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightArithmeticNarrowingSaturateUpper(lower, value, count); /// - /// int8x16_t vminq_s8 (int8x16_t a, int8x16_t b) - /// A32: VMIN.S8 Qd, Qn, Qm - /// A64: SMIN Vd.16B, Vn.16B, Vm.16B + /// int16x4_t vrshr_n_s16 (int16x4_t a, const int n) + /// A32: VRSHR.S16 Dd, Dm, #n + /// A64: SRSHR Vd.4H, Vn.4H, #n /// - public static Vector128 Min(Vector128 left, Vector128 right) => Min(left, right); + public static Vector64 ShiftRightArithmeticRounded(Vector64 value, byte count) => ShiftRightArithmeticRounded(value, count); /// - /// float32x4_t vminq_f32 (float32x4_t a, float32x4_t b) - /// A32: VMIN.F32 Qd, Qn, Qm - /// A64: FMIN Vd.4S, Vn.4S, Vm.4S + /// int32x2_t vrshr_n_s32 (int32x2_t a, const int n) + /// A32: VRSHR.S32 Dd, Dm, #n + /// A64: SRSHR Vd.2S, Vn.2S, #n /// - public static Vector128 Min(Vector128 left, Vector128 right) => Min(left, right); + public static Vector64 ShiftRightArithmeticRounded(Vector64 value, byte count) => ShiftRightArithmeticRounded(value, count); /// - /// uint16x8_t vminq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VMIN.U16 Qd, Qn, Qm - /// A64: UMIN Vd.8H, Vn.8H, Vm.8H + /// int8x8_t vrshr_n_s8 (int8x8_t a, const int n) + /// A32: VRSHR.S8 Dd, Dm, #n + /// A64: SRSHR Vd.8B, Vn.8B, #n /// - public static Vector128 Min(Vector128 left, Vector128 right) => Min(left, right); + public static Vector64 ShiftRightArithmeticRounded(Vector64 value, byte count) => ShiftRightArithmeticRounded(value, count); /// - /// uint32x4_t vminq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VMIN.U32 Qd, Qn, Qm - /// A64: UMIN Vd.4S, Vn.4S, Vm.4S + /// int16x8_t vrshrq_n_s16 (int16x8_t a, const int n) + /// A32: VRSHR.S16 Qd, Qm, #n + /// A64: SRSHR Vd.8H, Vn.8H, #n /// - public static Vector128 Min(Vector128 left, Vector128 right) => Min(left, right); + public static Vector128 ShiftRightArithmeticRounded(Vector128 value, byte count) => ShiftRightArithmeticRounded(value, count); /// - /// float32x2_t vminnm_f32 (float32x2_t a, float32x2_t b) - /// A32: VMINNM.F32 Dd, Dn, Dm - /// A64: FMINNM Vd.2S, Vn.2S, Vm.2S + /// int32x4_t vrshrq_n_s32 (int32x4_t a, const int n) + /// A32: VRSHR.S32 Qd, Qm, #n + /// A64: SRSHR Vd.4S, Vn.4S, #n /// - public static Vector64 MinNumber(Vector64 left, Vector64 right) => MinNumber(left, right); + public static Vector128 ShiftRightArithmeticRounded(Vector128 value, byte count) => ShiftRightArithmeticRounded(value, count); /// - /// float32x4_t vminnmq_f32 (float32x4_t a, float32x4_t b) - /// A32: VMINNM.F32 Qd, Qn, Qm - /// A64: FMINNM Vd.4S, Vn.4S, Vm.4S + /// int64x2_t vrshrq_n_s64 (int64x2_t a, const int n) + /// A32: VRSHR.S64 Qd, Qm, #n + /// A64: SRSHR Vd.2D, Vn.2D, #n /// - public static Vector128 MinNumber(Vector128 left, Vector128 right) => MinNumber(left, right); + public static Vector128 ShiftRightArithmeticRounded(Vector128 value, byte count) => ShiftRightArithmeticRounded(value, count); /// - /// float64x1_t vminnm_f64 (float64x1_t a, float64x1_t b) - /// A32: VMINNM.F64 Dd, Dn, Dm - /// A64: FMINNM Dd, Dn, Dm + /// int8x16_t vrshrq_n_s8 (int8x16_t a, const int n) + /// A32: VRSHR.S8 Qd, Qm, #n + /// A64: SRSHR Vd.16B, Vn.16B, #n /// - public static Vector64 MinNumberScalar(Vector64 left, Vector64 right) => MinNumberScalar(left, right); + public static Vector128 ShiftRightArithmeticRounded(Vector128 value, byte count) => ShiftRightArithmeticRounded(value, count); /// - /// float32_t vminnms_f32 (float32_t a, float32_t b) - /// A32: VMINNM.F32 Sd, Sn, Sm - /// A64: FMINNM Sd, Sn, Sm + /// int16x4_t vrsra_n_s16 (int16x4_t a, int16x4_t b, const int n) + /// A32: VRSRA.S16 Dd, Dm, #n + /// A64: SRSRA Vd.4H, Vn.4H, #n /// - public static Vector64 MinNumberScalar(Vector64 left, Vector64 right) => MinNumberScalar(left, right); + public static Vector64 ShiftRightArithmeticRoundedAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightArithmeticRoundedAdd(addend, value, count); /// - /// uint8x8_t vpmin_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VPMIN.U8 Dd, Dn, Dm - /// A64: UMINP Vd.8B, Vn.8B, Vm.8B + /// int32x2_t vrsra_n_s32 (int32x2_t a, int32x2_t b, const int n) + /// A32: VRSRA.S32 Dd, Dm, #n + /// A64: SRSRA Vd.2S, Vn.2S, #n /// - public static Vector64 MinPairwise(Vector64 left, Vector64 right) => MinPairwise(left, right); + public static Vector64 ShiftRightArithmeticRoundedAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightArithmeticRoundedAdd(addend, value, count); /// - /// int16x4_t vpmin_s16 (int16x4_t a, int16x4_t b) - /// A32: VPMIN.S16 Dd, Dn, Dm - /// A64: SMINP Vd.4H, Vn.4H, Vm.4H + /// int8x8_t vrsra_n_s8 (int8x8_t a, int8x8_t b, const int n) + /// A32: VRSRA.S8 Dd, Dm, #n + /// A64: SRSRA Vd.8B, Vn.8B, #n /// - public static Vector64 MinPairwise(Vector64 left, Vector64 right) => MinPairwise(left, right); + public static Vector64 ShiftRightArithmeticRoundedAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightArithmeticRoundedAdd(addend, value, count); /// - /// int32x2_t vpmin_s32 (int32x2_t a, int32x2_t b) - /// A32: VPMIN.S32 Dd, Dn, Dm - /// A64: SMINP Vd.2S, Vn.2S, Vm.2S + /// int16x8_t vrsraq_n_s16 (int16x8_t a, int16x8_t b, const int n) + /// A32: VRSRA.S16 Qd, Qm, #n + /// A64: SRSRA Vd.8H, Vn.8H, #n /// - public static Vector64 MinPairwise(Vector64 left, Vector64 right) => MinPairwise(left, right); + public static Vector128 ShiftRightArithmeticRoundedAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightArithmeticRoundedAdd(addend, value, count); /// - /// int8x8_t vpmin_s8 (int8x8_t a, int8x8_t b) - /// A32: VPMIN.S8 Dd, Dn, Dm - /// A64: SMINP Vd.8B, Vn.8B, Vm.8B + /// int32x4_t vrsraq_n_s32 (int32x4_t a, int32x4_t b, const int n) + /// A32: VRSRA.S32 Qd, Qm, #n + /// A64: SRSRA Vd.4S, Vn.4S, #n /// - public static Vector64 MinPairwise(Vector64 left, Vector64 right) => MinPairwise(left, right); + public static Vector128 ShiftRightArithmeticRoundedAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightArithmeticRoundedAdd(addend, value, count); /// - /// float32x2_t vpmin_f32 (float32x2_t a, float32x2_t b) - /// A32: VPMIN.F32 Dd, Dn, Dm - /// A64: FMINP Vd.2S, Vn.2S, Vm.2S + /// int64x2_t vrsraq_n_s64 (int64x2_t a, int64x2_t b, const int n) + /// A32: VRSRA.S64 Qd, Qm, #n + /// A64: SRSRA Vd.2D, Vn.2D, #n /// - public static Vector64 MinPairwise(Vector64 left, Vector64 right) => MinPairwise(left, right); + public static Vector128 ShiftRightArithmeticRoundedAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightArithmeticRoundedAdd(addend, value, count); /// - /// uint16x4_t vpmin_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VPMIN.U16 Dd, Dn, Dm - /// A64: UMINP Vd.4H, Vn.4H, Vm.4H + /// int8x16_t vrsraq_n_s8 (int8x16_t a, int8x16_t b, const int n) + /// A32: VRSRA.S8 Qd, Qm, #n + /// A64: SRSRA Vd.16B, Vn.16B, #n /// - public static Vector64 MinPairwise(Vector64 left, Vector64 right) => MinPairwise(left, right); + public static Vector128 ShiftRightArithmeticRoundedAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightArithmeticRoundedAdd(addend, value, count); /// - /// uint32x2_t vpmin_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VPMIN.U32 Dd, Dn, Dm - /// A64: UMINP Vd.2S, Vn.2S, Vm.2S + /// int64x1_t vrsra_n_s64 (int64x1_t a, int64x1_t b, const int n) + /// A32: VRSRA.S64 Dd, Dm, #n + /// A64: SRSRA Dd, Dn, #n /// - public static Vector64 MinPairwise(Vector64 left, Vector64 right) => MinPairwise(left, right); + public static Vector64 ShiftRightArithmeticRoundedAddScalar(Vector64 addend, Vector64 value, byte count) => ShiftRightArithmeticRoundedAddScalar(addend, value, count); /// - /// uint8x8_t vmul_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VMUL.I8 Dd, Dn, Dm - /// A64: MUL Vd.8B, Vn.8B, Vm.8B + /// int16x4_t vqrshrn_n_s32 (int32x4_t a, const int n) + /// A32: VQRSHRN.S32 Dd, Qm, #n + /// A64: SQRSHRN Vd.4H, Vn.4S, #n /// - public static Vector64 Multiply(Vector64 left, Vector64 right) => Multiply(left, right); + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateLower(value, count); /// - /// int16x4_t vmul_s16 (int16x4_t a, int16x4_t b) - /// A32: VMUL.I16 Dd, Dn, Dm - /// A64: MUL Vd.4H, Vn.4H, Vm.4H + /// int32x2_t vqrshrn_n_s64 (int64x2_t a, const int n) + /// A32: VQRSHRN.S64 Dd, Qm, #n + /// A64: SQRSHRN Vd.2S, Vn.2D, #n /// - public static Vector64 Multiply(Vector64 left, Vector64 right) => Multiply(left, right); + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateLower(value, count); /// - /// int32x2_t vmul_s32 (int32x2_t a, int32x2_t b) - /// A32: VMUL.I32 Dd, Dn, Dm - /// A64: MUL Vd.2S, Vn.2S, Vm.2S + /// int8x8_t vqrshrn_n_s16 (int16x8_t a, const int n) + /// A32: VQRSHRN.S16 Dd, Qm, #n + /// A64: SQRSHRN Vd.8B, Vn.8H, #n + /// + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateLower(value, count); + + /// + /// uint8x8_t vqrshrun_n_s16 (int16x8_t a, const int n) + /// A32: VQRSHRUN.S16 Dd, Qm, #n + /// A64: SQRSHRUN Vd.8B, Vn.8H, #n /// - public static Vector64 Multiply(Vector64 left, Vector64 right) => Multiply(left, right); + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(Vector128 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(value, count); /// - /// int8x8_t vmul_s8 (int8x8_t a, int8x8_t b) - /// A32: VMUL.I8 Dd, Dn, Dm - /// A64: MUL Vd.8B, Vn.8B, Vm.8B + /// uint16x4_t vqrshrun_n_s32 (int32x4_t a, const int n) + /// A32: VQRSHRUN.S32 Dd, Qm, #n + /// A64: SQRSHRUN Vd.4H, Vn.4S, #n /// - public static Vector64 Multiply(Vector64 left, Vector64 right) => Multiply(left, right); + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(Vector128 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(value, count); /// - /// float32x2_t vmul_f32 (float32x2_t a, float32x2_t b) - /// A32: VMUL.F32 Dd, Dn, Dm - /// A64: FMUL Vd.2S, Vn.2S, Vm.2S + /// uint32x2_t vqrshrun_n_s64 (int64x2_t a, const int n) + /// A32: VQRSHRUN.S64 Dd, Qm, #n + /// A64: SQRSHRUN Vd.2S, Vn.2D, #n /// - public static Vector64 Multiply(Vector64 left, Vector64 right) => Multiply(left, right); + public static Vector64 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(Vector128 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateUnsignedLower(value, count); /// - /// uint16x4_t vmul_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VMUL.I16 Dd, Dn, Dm - /// A64: MUL Vd.4H, Vn.4H, Vm.4H + /// uint8x16_t vqrshrun_high_n_s16 (uint8x8_t r, int16x8_t a, const int n) + /// A32: VQRSHRUN.S16 Dd+1, Dn, #n + /// A64: SQRSHRUN2 Vd.16B, Vn.8H, #n /// - public static Vector64 Multiply(Vector64 left, Vector64 right) => Multiply(left, right); + public static Vector128 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(lower, value, count); /// - /// uint32x2_t vmul_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VMUL.I32 Dd, Dn, Dm - /// A64: MUL Vd.2S, Vn.2S, Vm.2S + /// uint16x8_t vqrshrun_high_n_s32 (uint16x4_t r, int32x4_t a, const int n) + /// A32: VQRSHRUN.S32 Dd+1, Dn, #n + /// A64: SQRSHRUN2 Vd.8H, Vn.4S, #n /// - public static Vector64 Multiply(Vector64 left, Vector64 right) => Multiply(left, right); + public static Vector128 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(lower, value, count); /// - /// uint8x16_t vmulq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VMUL.I8 Qd, Qn, Qm - /// A64: MUL Vd.16B, Vn.16B, Vm.16B + /// uint32x4_t vqrshrun_high_n_s64 (uint32x2_t r, int64x2_t a, const int n) + /// A32: VQRSHRUN.S64 Dd+1, Dn, #n + /// A64: SQRSHRUN2 Vd.4S, Vn.2D, #n /// - public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + public static Vector128 ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateUnsignedUpper(lower, value, count); /// - /// int16x8_t vmulq_s16 (int16x8_t a, int16x8_t b) - /// A32: VMUL.I16 Qd, Qn, Qm - /// A64: MUL Vd.8H, Vn.8H, Vm.8H + /// int16x8_t vqrshrn_high_n_s32 (int16x4_t r, int32x4_t a, const int n) + /// A32: VQRSHRN.S32 Dd+1, Dn, #n + /// A64: SQRSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + public static Vector128 ShiftRightArithmeticRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateUpper(lower, value, count); /// - /// int32x4_t vmulq_s32 (int32x4_t a, int32x4_t b) - /// A32: VMUL.I32 Qd, Qn, Qm - /// A64: MUL Vd.4S, Vn.4S, Vm.4S + /// int32x4_t vqrshrn_high_n_s64 (int32x2_t r, int64x2_t a, const int n) + /// A32: VQRSHRN.S64 Dd+1, Dn, #n + /// A64: SQRSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + public static Vector128 ShiftRightArithmeticRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateUpper(lower, value, count); /// - /// int8x16_t vmulq_s8 (int8x16_t a, int8x16_t b) - /// A32: VMUL.I8 Qd, Qn, Qm - /// A64: MUL Vd.16B, Vn.16B, Vm.16B + /// int8x16_t vqrshrn_high_n_s16 (int8x8_t r, int16x8_t a, const int n) + /// A32: VQRSHRN.S16 Dd+1, Dn, #n + /// A64: SQRSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + public static Vector128 ShiftRightArithmeticRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightArithmeticRoundedNarrowingSaturateUpper(lower, value, count); /// - /// float32x4_t vmulq_f32 (float32x4_t a, float32x4_t b) - /// A32: VMUL.F32 Qd, Qn, Qm - /// A64: FMUL Vd.4S, Vn.4S, Vm.4S + /// int64x1_t vrshr_n_s64 (int64x1_t a, const int n) + /// A32: VRSHR.S64 Dd, Dm, #n + /// A64: SRSHR Dd, Dn, #n /// - public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + public static Vector64 ShiftRightArithmeticRoundedScalar(Vector64 value, byte count) => ShiftRightArithmeticRoundedScalar(value, count); /// - /// uint16x8_t vmulq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VMUL.I16 Qd, Qn, Qm - /// A64: MUL Vd.8H, Vn.8H, Vm.8H + /// int64x1_t vshr_n_s64 (int64x1_t a, const int n) + /// A32: VSHR.S64 Dd, Dm, #n + /// A64: SSHR Dd, Dn, #n /// - public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + public static Vector64 ShiftRightArithmeticScalar(Vector64 value, byte count) => ShiftRightArithmeticScalar(value, count); /// - /// uint32x4_t vmulq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VMUL.I32 Qd, Qn, Qm - /// A64: MUL Vd.4S, Vn.4S, Vm.4S + /// uint8x8_t vshr_n_u8 (uint8x8_t a, const int n) + /// A32: VSHR.U8 Dd, Dm, #n + /// A64: USHR Vd.8B, Vn.8B, #n /// - public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + public static Vector64 ShiftRightLogical(Vector64 value, byte count) => ShiftRightLogical(value, count); /// - /// float64x1_t vmul_f64 (float64x1_t a, float64x1_t b) - /// A32: VMUL.F64 Dd, Dn, Dm - /// A64: FMUL Dd, Dn, Dm + /// uint16x4_t vshr_n_u16 (uint16x4_t a, const int n) + /// A32: VSHR.U16 Dd, Dm, #n + /// A64: USHR Vd.4H, Vn.4H, #n /// - public static Vector64 MultiplyScalar(Vector64 left, Vector64 right) => MultiplyScalar(left, right); + public static Vector64 ShiftRightLogical(Vector64 value, byte count) => ShiftRightLogical(value, count); /// - /// float32_t vmuls_f32 (float32_t a, float32_t b) - /// A32: VMUL.F32 Sd, Sn, Sm - /// A64: FMUL Sd, Sn, Sm - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint32x2_t vshr_n_u32 (uint32x2_t a, const int n) + /// A32: VSHR.U32 Dd, Dm, #n + /// A64: USHR Vd.2S, Vn.2S, #n /// - public static Vector64 MultiplyScalar(Vector64 left, Vector64 right) => MultiplyScalar(left, right); + public static Vector64 ShiftRightLogical(Vector64 value, byte count) => ShiftRightLogical(value, count); /// - /// uint8x8_t vmla_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) - /// A32: VMLA.I8 Dd, Dn, Dm - /// A64: MLA Vd.8B, Vn.8B, Vm.8B + /// uint8x8_t vshr_n_u8 (uint8x8_t a, const int n) + /// A32: VSHR.U8 Dd, Dm, #n + /// A64: USHR Vd.8B, Vn.8B, #n /// - public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) => MultiplyAdd(acc, left, right); + public static Vector64 ShiftRightLogical(Vector64 value, byte count) => ShiftRightLogical(value, count); /// - /// int16x4_t vmla_s16 (int16x4_t a, int16x4_t b, int16x4_t c) - /// A32: VMLA.I16 Dd, Dn, Dm - /// A64: MLA Vd.4H, Vn.4H, Vm.4H + /// uint16x4_t vshr_n_u16 (uint16x4_t a, const int n) + /// A32: VSHR.U16 Dd, Dm, #n + /// A64: USHR Vd.4H, Vn.4H, #n /// - public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) => MultiplyAdd(acc, left, right); + public static Vector64 ShiftRightLogical(Vector64 value, byte count) => ShiftRightLogical(value, count); /// - /// int32x2_t vmla_s32 (int32x2_t a, int32x2_t b, int32x2_t c) - /// A32: VMLA.I32 Dd, Dn, Dm - /// A64: MLA Vd.2S, Vn.2S, Vm.2S + /// uint32x2_t vshr_n_u32 (uint32x2_t a, const int n) + /// A32: VSHR.U32 Dd, Dm, #n + /// A64: USHR Vd.2S, Vn.2S, #n /// - public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) => MultiplyAdd(acc, left, right); + public static Vector64 ShiftRightLogical(Vector64 value, byte count) => ShiftRightLogical(value, count); /// - /// int8x8_t vmla_s8 (int8x8_t a, int8x8_t b, int8x8_t c) - /// A32: VMLA.I8 Dd, Dn, Dm - /// A64: MLA Vd.8B, Vn.8B, Vm.8B + /// uint8x16_t vshrq_n_u8 (uint8x16_t a, const int n) + /// A32: VSHR.U8 Qd, Qm, #n + /// A64: USHR Vd.16B, Vn.16B, #n /// - public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) => MultiplyAdd(acc, left, right); + public static Vector128 ShiftRightLogical(Vector128 value, byte count) => ShiftRightLogical(value, count); /// - /// uint16x4_t vmla_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) - /// A32: VMLA.I16 Dd, Dn, Dm - /// A64: MLA Vd.4H, Vn.4H, Vm.4H + /// uint16x8_t vshrq_n_u16 (uint16x8_t a, const int n) + /// A32: VSHR.U16 Qd, Qm, #n + /// A64: USHR Vd.8H, Vn.8H, #n /// - public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) => MultiplyAdd(acc, left, right); + public static Vector128 ShiftRightLogical(Vector128 value, byte count) => ShiftRightLogical(value, count); /// - /// uint32x2_t vmla_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) - /// A32: VMLA.I32 Dd, Dn, Dm - /// A64: MLA Vd.2S, Vn.2S, Vm.2S + /// uint32x4_t vshrq_n_u32 (uint32x4_t a, const int n) + /// A32: VSHR.U32 Qd, Qm, #n + /// A64: USHR Vd.4S, Vn.4S, #n /// - public static Vector64 MultiplyAdd(Vector64 acc, Vector64 left, Vector64 right) => MultiplyAdd(acc, left, right); + public static Vector128 ShiftRightLogical(Vector128 value, byte count) => ShiftRightLogical(value, count); /// - /// uint8x16_t vmlaq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) - /// A32: VMLA.I8 Qd, Qn, Qm - /// A64: MLA Vd.16B, Vn.16B, Vm.16B + /// uint64x2_t vshrq_n_u64 (uint64x2_t a, const int n) + /// A32: VSHR.U64 Qd, Qm, #n + /// A64: USHR Vd.2D, Vn.2D, #n /// - public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => MultiplyAdd(acc, left, right); + public static Vector128 ShiftRightLogical(Vector128 value, byte count) => ShiftRightLogical(value, count); /// - /// int16x8_t vmlaq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) - /// A32: VMLA.I16 Qd, Qn, Qm - /// A64: MLA Vd.8H, Vn.8H, Vm.8H + /// uint8x16_t vshrq_n_u8 (uint8x16_t a, const int n) + /// A32: VSHR.U8 Qd, Qm, #n + /// A64: USHR Vd.16B, Vn.16B, #n /// - public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => MultiplyAdd(acc, left, right); + public static Vector128 ShiftRightLogical(Vector128 value, byte count) => ShiftRightLogical(value, count); /// - /// int32x4_t vmlaq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) - /// A32: VMLA.I32 Qd, Qn, Qm - /// A64: MLA Vd.4S, Vn.4S, Vm.4S + /// uint16x8_t vshrq_n_u16 (uint16x8_t a, const int n) + /// A32: VSHR.U16 Qd, Qm, #n + /// A64: USHR Vd.8H, Vn.8H, #n /// - public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => MultiplyAdd(acc, left, right); + public static Vector128 ShiftRightLogical(Vector128 value, byte count) => ShiftRightLogical(value, count); /// - /// int8x16_t vmlaq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) - /// A32: VMLA.I8 Qd, Qn, Qm - /// A64: MLA Vd.16B, Vn.16B, Vm.16B + /// uint32x4_t vshrq_n_u32 (uint32x4_t a, const int n) + /// A32: VSHR.U32 Qd, Qm, #n + /// A64: USHR Vd.4S, Vn.4S, #n /// - public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => MultiplyAdd(acc, left, right); + public static Vector128 ShiftRightLogical(Vector128 value, byte count) => ShiftRightLogical(value, count); /// - /// uint16x8_t vmlaq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) - /// A32: VMLA.I16 Qd, Qn, Qm - /// A64: MLA Vd.8H, Vn.8H, Vm.8H + /// uint64x2_t vshrq_n_u64 (uint64x2_t a, const int n) + /// A32: VSHR.U64 Qd, Qm, #n + /// A64: USHR Vd.2D, Vn.2D, #n /// - public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => MultiplyAdd(acc, left, right); + public static Vector128 ShiftRightLogical(Vector128 value, byte count) => ShiftRightLogical(value, count); /// - /// uint32x4_t vmlaq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) - /// A32: VMLA.I32 Qd, Qn, Qm - /// A64: MLA Vd.4S, Vn.4S, Vm.4S + /// uint8x8_t vsra_n_u8 (uint8x8_t a, uint8x8_t b, const int n) + /// A32: VSRA.U8 Dd, Dm, #n + /// A64: USRA Vd.8B, Vn.8B, #n /// - public static Vector128 MultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => MultiplyAdd(acc, left, right); + public static Vector64 ShiftRightLogicalAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalAdd(addend, value, count); /// - /// uint8x8_t vmls_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) - /// A32: VMLS.I8 Dd, Dn, Dm - /// A64: MLS Vd.8B, Vn.8B, Vm.8B + /// uint16x4_t vsra_n_u16 (uint16x4_t a, uint16x4_t b, const int n) + /// A32: VSRA.U16 Dd, Dm, #n + /// A64: USRA Vd.4H, Vn.4H, #n /// - public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) => MultiplySubtract(acc, left, right); + public static Vector64 ShiftRightLogicalAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalAdd(addend, value, count); /// - /// int16x4_t vmls_s16 (int16x4_t a, int16x4_t b, int16x4_t c) - /// A32: VMLS.I16 Dd, Dn, Dm - /// A64: MLS Vd.4H, Vn.4H, Vm.4H + /// uint32x2_t vsra_n_u32 (uint32x2_t a, uint32x2_t b, const int n) + /// A32: VSRA.U32 Dd, Dm, #n + /// A64: USRA Vd.2S, Vn.2S, #n /// - public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) => MultiplySubtract(acc, left, right); + public static Vector64 ShiftRightLogicalAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalAdd(addend, value, count); /// - /// int32x2_t vmls_s32 (int32x2_t a, int32x2_t b, int32x2_t c) - /// A32: VMLS.I32 Dd, Dn, Dm - /// A64: MLS Vd.2S, Vn.2S, Vm.2S + /// uint8x8_t vsra_n_u8 (uint8x8_t a, uint8x8_t b, const int n) + /// A32: VSRA.U8 Dd, Dm, #n + /// A64: USRA Vd.8B, Vn.8B, #n /// - public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) => MultiplySubtract(acc, left, right); + public static Vector64 ShiftRightLogicalAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalAdd(addend, value, count); /// - /// int8x8_t vmls_s8 (int8x8_t a, int8x8_t b, int8x8_t c) - /// A32: VMLS.I8 Dd, Dn, Dm - /// A64: MLS Vd.8B, Vn.8B, Vm.8B + /// uint16x4_t vsra_n_u16 (uint16x4_t a, uint16x4_t b, const int n) + /// A32: VSRA.U16 Dd, Dm, #n + /// A64: USRA Vd.4H, Vn.4H, #n /// - public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) => MultiplySubtract(acc, left, right); + public static Vector64 ShiftRightLogicalAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalAdd(addend, value, count); /// - /// uint16x4_t vmls_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) - /// A32: VMLS.I16 Dd, Dn, Dm - /// A64: MLS Vd.4H, Vn.4H, Vm.4H + /// uint32x2_t vsra_n_u32 (uint32x2_t a, uint32x2_t b, const int n) + /// A32: VSRA.U32 Dd, Dm, #n + /// A64: USRA Vd.2S, Vn.2S, #n /// - public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) => MultiplySubtract(acc, left, right); + public static Vector64 ShiftRightLogicalAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalAdd(addend, value, count); /// - /// uint32x2_t vmls_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) - /// A32: VMLS.I32 Dd, Dn, Dm - /// A64: MLS Vd.2S, Vn.2S, Vm.2S + /// uint8x16_t vsraq_n_u8 (uint8x16_t a, uint8x16_t b, const int n) + /// A32: VSRA.U8 Qd, Qm, #n + /// A64: USRA Vd.16B, Vn.16B, #n /// - public static Vector64 MultiplySubtract(Vector64 acc, Vector64 left, Vector64 right) => MultiplySubtract(acc, left, right); + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalAdd(addend, value, count); /// - /// uint8x16_t vmlsq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) - /// A32: VMLS.I8 Qd, Qn, Qm - /// A64: MLS Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vsraq_n_u16 (uint16x8_t a, uint16x8_t b, const int n) + /// A32: VSRA.U16 Qd, Qm, #n + /// A64: USRA Vd.8H, Vn.8H, #n /// - public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => MultiplySubtract(acc, left, right); + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalAdd(addend, value, count); /// - /// int16x8_t vmlsq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) - /// A32: VMLS.I16 Qd, Qn, Qm - /// A64: MLS Vd.8H, Vn.8H, Vm.8H + /// uint32x4_t vsraq_n_u32 (uint32x4_t a, uint32x4_t b, const int n) + /// A32: VSRA.U32 Qd, Qm, #n + /// A64: USRA Vd.4S, Vn.4S, #n /// - public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => MultiplySubtract(acc, left, right); + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalAdd(addend, value, count); /// - /// int32x4_t vmlsq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) - /// A32: VMLS.I32 Qd, Qn, Qm - /// A64: MLS Vd.4S, Vn.4S, Vm.4S + /// uint64x2_t vsraq_n_u64 (uint64x2_t a, uint64x2_t b, const int n) + /// A32: VSRA.U64 Qd, Qm, #n + /// A64: USRA Vd.2D, Vn.2D, #n /// - public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => MultiplySubtract(acc, left, right); + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalAdd(addend, value, count); /// - /// int8x16_t vmlsq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) - /// A32: VMLS.I8 Qd, Qn, Qm - /// A64: MLS Vd.16B, Vn.16B, Vm.16B + /// uint8x16_t vsraq_n_u8 (uint8x16_t a, uint8x16_t b, const int n) + /// A32: VSRA.U8 Qd, Qm, #n + /// A64: USRA Vd.16B, Vn.16B, #n /// - public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => MultiplySubtract(acc, left, right); + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalAdd(addend, value, count); /// - /// uint16x8_t vmlsq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) - /// A32: VMLS.I16 Qd, Qn, Qm - /// A64: MLS Vd.8H, Vn.8H, Vm.8H + /// uint16x8_t vsraq_n_u16 (uint16x8_t a, uint16x8_t b, const int n) + /// A32: VSRA.U16 Qd, Qm, #n + /// A64: USRA Vd.8H, Vn.8H, #n /// - public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => MultiplySubtract(acc, left, right); + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalAdd(addend, value, count); /// - /// uint32x4_t vmlsq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) - /// A32: VMLS.I32 Qd, Qn, Qm - /// A64: MLS Vd.4S, Vn.4S, Vm.4S + /// uint32x4_t vsraq_n_u32 (uint32x4_t a, uint32x4_t b, const int n) + /// A32: VSRA.U32 Qd, Qm, #n + /// A64: USRA Vd.4S, Vn.4S, #n /// - public static Vector128 MultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => MultiplySubtract(acc, left, right); + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalAdd(addend, value, count); /// - /// int16x4_t vneg_s16 (int16x4_t a) - /// A32: VNEG.S16 Dd, Dm - /// A64: NEG Vd.4H, Vn.4H + /// uint64x2_t vsraq_n_u64 (uint64x2_t a, uint64x2_t b, const int n) + /// A32: VSRA.U64 Qd, Qm, #n + /// A64: USRA Vd.2D, Vn.2D, #n /// - public static Vector64 Negate(Vector64 value) => Negate(value); + public static Vector128 ShiftRightLogicalAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalAdd(addend, value, count); /// - /// int32x2_t vneg_s32 (int32x2_t a) - /// A32: VNEG.S32 Dd, Dm - /// A64: NEG Vd.2S, Vn.2S + /// uint64x1_t vsra_n_u64 (uint64x1_t a, uint64x1_t b, const int n) + /// A32: VSRA.U64 Dd, Dm, #n + /// A64: USRA Dd, Dn, #n /// - public static Vector64 Negate(Vector64 value) => Negate(value); + public static Vector64 ShiftRightLogicalAddScalar(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalAddScalar(addend, value, count); /// - /// int8x8_t vneg_s8 (int8x8_t a) - /// A32: VNEG.S8 Dd, Dm - /// A64: NEG Vd.8B, Vn.8B + /// uint64x1_t vsra_n_u64 (uint64x1_t a, uint64x1_t b, const int n) + /// A32: VSRA.U64 Dd, Dm, #n + /// A64: USRA Dd, Dn, #n /// - public static Vector64 Negate(Vector64 value) => Negate(value); + public static Vector64 ShiftRightLogicalAddScalar(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalAddScalar(addend, value, count); /// - /// float32x2_t vneg_f32 (float32x2_t a) - /// A32: VNEG.F32 Dd, Dm - /// A64: FNEG Vd.2S, Vn.2S + /// uint8x8_t vshrn_n_u16 (uint16x8_t a, const int n) + /// A32: VSHRN.I16 Dd, Qm, #n + /// A64: SHRN Vd.8B, Vn.8H, #n /// - public static Vector64 Negate(Vector64 value) => Negate(value); + public static Vector64 ShiftRightLogicalNarrowingLower(Vector128 value, byte count) => ShiftRightLogicalNarrowingLower(value, count); /// - /// int16x8_t vnegq_s16 (int16x8_t a) - /// A32: VNEG.S16 Qd, Qm - /// A64: NEG Vd.8H, Vn.8H + /// int16x4_t vshrn_n_s32 (int32x4_t a, const int n) + /// A32: VSHRN.I32 Dd, Qm, #n + /// A64: SHRN Vd.4H, Vn.4S, #n /// - public static Vector128 Negate(Vector128 value) => Negate(value); + public static Vector64 ShiftRightLogicalNarrowingLower(Vector128 value, byte count) => ShiftRightLogicalNarrowingLower(value, count); /// - /// int32x4_t vnegq_s32 (int32x4_t a) - /// A32: VNEG.S32 Qd, Qm - /// A64: NEG Vd.4S, Vn.4S + /// int32x2_t vshrn_n_s64 (int64x2_t a, const int n) + /// A32: VSHRN.I64 Dd, Qm, #n + /// A64: SHRN Vd.2S, Vn.2D, #n /// - public static Vector128 Negate(Vector128 value) => Negate(value); + public static Vector64 ShiftRightLogicalNarrowingLower(Vector128 value, byte count) => ShiftRightLogicalNarrowingLower(value, count); /// - /// int8x16_t vnegq_s8 (int8x16_t a) - /// A32: VNEG.S8 Qd, Qm - /// A64: NEG Vd.16B, Vn.16B + /// int8x8_t vshrn_n_s16 (int16x8_t a, const int n) + /// A32: VSHRN.I16 Dd, Qm, #n + /// A64: SHRN Vd.8B, Vn.8H, #n /// - public static Vector128 Negate(Vector128 value) => Negate(value); + public static Vector64 ShiftRightLogicalNarrowingLower(Vector128 value, byte count) => ShiftRightLogicalNarrowingLower(value, count); /// - /// float32x4_t vnegq_f32 (float32x4_t a) - /// A32: VNEG.F32 Qd, Qm - /// A64: FNEG Vd.4S, Vn.4S + /// uint16x4_t vshrn_n_u32 (uint32x4_t a, const int n) + /// A32: VSHRN.I32 Dd, Qm, #n + /// A64: SHRN Vd.4H, Vn.4S, #n /// - public static Vector128 Negate(Vector128 value) => Negate(value); + public static Vector64 ShiftRightLogicalNarrowingLower(Vector128 value, byte count) => ShiftRightLogicalNarrowingLower(value, count); /// - /// float64x1_t vneg_f64 (float64x1_t a) - /// A32: VNEG.F64 Dd, Dm - /// A64: FNEG Dd, Dn + /// uint32x2_t vshrn_n_u64 (uint64x2_t a, const int n) + /// A32: VSHRN.I64 Dd, Qm, #n + /// A64: SHRN Vd.2S, Vn.2D, #n /// - public static Vector64 NegateScalar(Vector64 value) => NegateScalar(value); + public static Vector64 ShiftRightLogicalNarrowingLower(Vector128 value, byte count) => ShiftRightLogicalNarrowingLower(value, count); /// - /// float32_t vnegs_f32 (float32_t a) - /// A32: VNEG.F32 Sd, Sm - /// A64: FNEG Sd, Sn - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x8_t vqshrn_n_u16 (uint16x8_t a, const int n) + /// A32: VQSHRN.U16 Dd, Qm, #n + /// A64: UQSHRN Vd.8B, Vn.8H, #n /// - public static Vector64 NegateScalar(Vector64 value) => NegateScalar(value); + public static Vector64 ShiftRightLogicalNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightLogicalNarrowingSaturateLower(value, count); /// - /// uint8x8_t vmvn_u8 (uint8x8_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint16x4_t vqshrn_n_u32 (uint32x4_t a, const int n) + /// A32: VQSHRN.U32 Dd, Qm, #n + /// A64: UQSHRN Vd.4H, Vn.4S, #n /// - public static Vector64 Not(Vector64 value) => Not(value); + public static Vector64 ShiftRightLogicalNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightLogicalNarrowingSaturateLower(value, count); /// - /// float64x1_t vmvn_f64 (float64x1_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint32x2_t vqshrn_n_u64 (uint64x2_t a, const int n) + /// A32: VQSHRN.U64 Dd, Qm, #n + /// A64: UQSHRN Vd.2S, Vn.2D, #n /// - public static Vector64 Not(Vector64 value) => Not(value); + public static Vector64 ShiftRightLogicalNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightLogicalNarrowingSaturateLower(value, count); /// - /// int16x4_t vmvn_s16 (int16x4_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint8x8_t vqshrn_n_u16 (uint16x8_t a, const int n) + /// A32: VQSHRN.U16 Dd, Qm, #n + /// A64: UQSHRN Vd.8B, Vn.8H, #n /// - public static Vector64 Not(Vector64 value) => Not(value); + public static Vector64 ShiftRightLogicalNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightLogicalNarrowingSaturateLower(value, count); /// - /// int32x2_t vmvn_s32 (int32x2_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint16x4_t vqshrn_n_u32 (uint32x4_t a, const int n) + /// A32: VQSHRN.U32 Dd, Qm, #n + /// A64: UQSHRN Vd.4H, Vn.4S, #n /// - public static Vector64 Not(Vector64 value) => Not(value); + public static Vector64 ShiftRightLogicalNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightLogicalNarrowingSaturateLower(value, count); /// - /// int64x1_t vmvn_s64 (int64x1_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint32x2_t vqshrn_n_u64 (uint64x2_t a, const int n) + /// A32: VQSHRN.U64 Dd, Qm, #n + /// A64: UQSHRN Vd.2S, Vn.2D, #n /// - public static Vector64 Not(Vector64 value) => Not(value); + public static Vector64 ShiftRightLogicalNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightLogicalNarrowingSaturateLower(value, count); /// - /// int8x8_t vmvn_s8 (int8x8_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint8x16_t vqshrn_high_n_u16 (uint8x8_t r, uint16x8_t a, const int n) + /// A32: VQSHRN.U16 Dd+1, Qm, #n + /// A64: UQSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector64 Not(Vector64 value) => Not(value); + public static Vector128 ShiftRightLogicalNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalNarrowingSaturateUpper(lower, value, count); /// - /// float32x2_t vmvn_f32 (float32x2_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x8_t vqshrn_high_n_u32 (uint16x4_t r, uint32x4_t a, const int n) + /// A32: VQSHRN.U32 Dd+1, Qm, #n + /// A64: UQSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector64 Not(Vector64 value) => Not(value); + public static Vector128 ShiftRightLogicalNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalNarrowingSaturateUpper(lower, value, count); /// - /// uint16x4_t vmvn_u16 (uint16x4_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint32x4_t vqshrn_high_n_u64 (uint32x2_t r, uint64x2_t a, const int n) + /// A32: VQSHRN.U64 Dd+1, Qm, #n + /// A64: UQSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector64 Not(Vector64 value) => Not(value); + public static Vector128 ShiftRightLogicalNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalNarrowingSaturateUpper(lower, value, count); /// - /// uint32x2_t vmvn_u32 (uint32x2_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint8x16_t vqshrn_high_n_u16 (uint8x8_t r, uint16x8_t a, const int n) + /// A32: VQSHRN.U16 Dd+1, Qm, #n + /// A64: UQSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector64 Not(Vector64 value) => Not(value); + public static Vector128 ShiftRightLogicalNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalNarrowingSaturateUpper(lower, value, count); /// - /// uint64x1_t vmvn_u64 (uint64x1_t a) - /// A32: VMVN Dd, Dm - /// A64: MVN Vd.8B, Vn.8B + /// uint16x8_t vqshrn_high_n_u32 (uint16x4_t r, uint32x4_t a, const int n) + /// A32: VQSHRN.U32 Dd+1, Qm, #n + /// A64: UQSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector64 Not(Vector64 value) => Not(value); + public static Vector128 ShiftRightLogicalNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalNarrowingSaturateUpper(lower, value, count); /// - /// uint8x16_t vmvnq_u8 (uint8x16_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// uint32x4_t vqshrn_high_n_u64 (uint32x2_t r, uint64x2_t a, const int n) + /// A32: VQSHRN.U64 Dd+1, Qm, #n + /// A64: UQSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector128 Not(Vector128 value) => Not(value); + public static Vector128 ShiftRightLogicalNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalNarrowingSaturateUpper(lower, value, count); /// - /// float64x2_t vmvnq_f64 (float64x2_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x16_t vshrn_high_n_u16 (uint8x8_t r, uint16x8_t a, const int n) + /// A32: VSHRN.I16 Dd+1, Qm, #n + /// A64: SHRN2 Vd.16B, Vn.8H, #n /// - public static Vector128 Not(Vector128 value) => Not(value); + public static Vector128 ShiftRightLogicalNarrowingUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalNarrowingUpper(lower, value, count); /// - /// int16x8_t vmvnq_s16 (int16x8_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// int16x8_t vshrn_high_n_s32 (int16x4_t r, int32x4_t a, const int n) + /// A32: VSHRN.I32 Dd+1, Qm, #n + /// A64: SHRN2 Vd.8H, Vn.4S, #n /// - public static Vector128 Not(Vector128 value) => Not(value); + public static Vector128 ShiftRightLogicalNarrowingUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalNarrowingUpper(lower, value, count); /// - /// int32x4_t vmvnq_s32 (int32x4_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// int32x4_t vshrn_high_n_s64 (int32x2_t r, int64x2_t a, const int n) + /// A32: VSHRN.I64 Dd+1, Qm, #n + /// A64: SHRN2 Vd.4S, Vn.2D, #n /// - public static Vector128 Not(Vector128 value) => Not(value); + public static Vector128 ShiftRightLogicalNarrowingUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalNarrowingUpper(lower, value, count); /// - /// int64x2_t vmvnq_s64 (int64x2_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// int8x16_t vshrn_high_n_s16 (int8x8_t r, int16x8_t a, const int n) + /// A32: VSHRN.I16 Dd+1, Qm, #n + /// A64: SHRN2 Vd.16B, Vn.8H, #n + /// + public static Vector128 ShiftRightLogicalNarrowingUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalNarrowingUpper(lower, value, count); + + /// + /// uint16x8_t vshrn_high_n_u32 (uint16x4_t r, uint32x4_t a, const int n) + /// A32: VSHRN.I32 Dd+1, Qm, #n + /// A64: SHRN2 Vd.8H, Vn.4S, #n /// - public static Vector128 Not(Vector128 value) => Not(value); + public static Vector128 ShiftRightLogicalNarrowingUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalNarrowingUpper(lower, value, count); /// - /// int8x16_t vmvnq_s8 (int8x16_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// uint32x4_t vshrn_high_n_u64 (uint32x2_t r, uint64x2_t a, const int n) + /// A32: VSHRN.I64 Dd+1, Qm, #n + /// A64: SHRN2 Vd.4S, Vn.2D, #n /// - public static Vector128 Not(Vector128 value) => Not(value); + public static Vector128 ShiftRightLogicalNarrowingUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalNarrowingUpper(lower, value, count); /// - /// float32x4_t vmvnq_f32 (float32x4_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x8_t vrshr_n_u8 (uint8x8_t a, const int n) + /// A32: VRSHR.U8 Dd, Dm, #n + /// A64: URSHR Vd.8B, Vn.8B, #n /// - public static Vector128 Not(Vector128 value) => Not(value); + public static Vector64 ShiftRightLogicalRounded(Vector64 value, byte count) => ShiftRightLogicalRounded(value, count); /// - /// uint16x8_t vmvnq_u16 (uint16x8_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// uint16x4_t vrshr_n_u16 (uint16x4_t a, const int n) + /// A32: VRSHR.U16 Dd, Dm, #n + /// A64: URSHR Vd.4H, Vn.4H, #n /// - public static Vector128 Not(Vector128 value) => Not(value); + public static Vector64 ShiftRightLogicalRounded(Vector64 value, byte count) => ShiftRightLogicalRounded(value, count); /// - /// uint32x4_t vmvnq_u32 (uint32x4_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// uint32x2_t vrshr_n_u32 (uint32x2_t a, const int n) + /// A32: VRSHR.U32 Dd, Dm, #n + /// A64: URSHR Vd.2S, Vn.2S, #n /// - public static Vector128 Not(Vector128 value) => Not(value); + public static Vector64 ShiftRightLogicalRounded(Vector64 value, byte count) => ShiftRightLogicalRounded(value, count); /// - /// uint64x2_t vmvnq_u64 (uint64x2_t a) - /// A32: VMVN Qd, Qm - /// A64: MVN Vd.16B, Vn.16B + /// uint8x8_t vrshr_n_u8 (uint8x8_t a, const int n) + /// A32: VRSHR.U8 Dd, Dm, #n + /// A64: URSHR Vd.8B, Vn.8B, #n /// - public static Vector128 Not(Vector128 value) => Not(value); + public static Vector64 ShiftRightLogicalRounded(Vector64 value, byte count) => ShiftRightLogicalRounded(value, count); /// - /// uint8x8_t vorr_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint16x4_t vrshr_n_u16 (uint16x4_t a, const int n) + /// A32: VRSHR.U16 Dd, Dm, #n + /// A64: URSHR Vd.4H, Vn.4H, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + public static Vector64 ShiftRightLogicalRounded(Vector64 value, byte count) => ShiftRightLogicalRounded(value, count); /// - /// float64x1_t vorr_f64 (float64x1_t a, float64x1_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint32x2_t vrshr_n_u32 (uint32x2_t a, const int n) + /// A32: VRSHR.U32 Dd, Dm, #n + /// A64: URSHR Vd.2S, Vn.2S, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + public static Vector64 ShiftRightLogicalRounded(Vector64 value, byte count) => ShiftRightLogicalRounded(value, count); /// - /// int16x4_t vorr_s16 (int16x4_t a, int16x4_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint8x16_t vrshrq_n_u8 (uint8x16_t a, const int n) + /// A32: VRSHR.U8 Qd, Qm, #n + /// A64: URSHR Vd.16B, Vn.16B, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) => ShiftRightLogicalRounded(value, count); /// - /// int32x2_t vorr_s32 (int32x2_t a, int32x2_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint16x8_t vrshrq_n_u16 (uint16x8_t a, const int n) + /// A32: VRSHR.U16 Qd, Qm, #n + /// A64: URSHR Vd.8H, Vn.8H, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) => ShiftRightLogicalRounded(value, count); /// - /// int64x1_t vorr_s64 (int64x1_t a, int64x1_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint32x4_t vrshrq_n_u32 (uint32x4_t a, const int n) + /// A32: VRSHR.U32 Qd, Qm, #n + /// A64: URSHR Vd.4S, Vn.4S, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) => ShiftRightLogicalRounded(value, count); /// - /// int8x8_t vorr_s8 (int8x8_t a, int8x8_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint64x2_t vrshrq_n_u64 (uint64x2_t a, const int n) + /// A32: VRSHR.U64 Qd, Qm, #n + /// A64: URSHR Vd.2D, Vn.2D, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) => ShiftRightLogicalRounded(value, count); /// - /// float32x2_t vorr_f32 (float32x2_t a, float32x2_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x16_t vrshrq_n_u8 (uint8x16_t a, const int n) + /// A32: VRSHR.U8 Qd, Qm, #n + /// A64: URSHR Vd.16B, Vn.16B, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) => ShiftRightLogicalRounded(value, count); /// - /// uint16x4_t vorr_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint16x8_t vrshrq_n_u16 (uint16x8_t a, const int n) + /// A32: VRSHR.U16 Qd, Qm, #n + /// A64: URSHR Vd.8H, Vn.8H, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) => ShiftRightLogicalRounded(value, count); /// - /// uint32x2_t vorr_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint32x4_t vrshrq_n_u32 (uint32x4_t a, const int n) + /// A32: VRSHR.U32 Qd, Qm, #n + /// A64: URSHR Vd.4S, Vn.4S, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) => ShiftRightLogicalRounded(value, count); /// - /// uint64x1_t vorr_u64 (uint64x1_t a, uint64x1_t b) - /// A32: VORR Dd, Dn, Dm - /// A64: ORR Vd.8B, Vn.8B, Vm.8B + /// uint64x2_t vrshrq_n_u64 (uint64x2_t a, const int n) + /// A32: VRSHR.U64 Qd, Qm, #n + /// A64: URSHR Vd.2D, Vn.2D, #n /// - public static Vector64 Or(Vector64 left, Vector64 right) => Or(left, right); + public static Vector128 ShiftRightLogicalRounded(Vector128 value, byte count) => ShiftRightLogicalRounded(value, count); /// - /// uint8x16_t vorrq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint8x8_t vrsra_n_u8 (uint8x8_t a, uint8x8_t b, const int n) + /// A32: VRSRA.U8 Dd, Dm, #n + /// A64: URSRA Vd.8B, Vn.8B, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + public static Vector64 ShiftRightLogicalRoundedAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalRoundedAdd(addend, value, count); /// - /// float64x2_t vorrq_f64 (float64x2_t a, float64x2_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x4_t vrsra_n_u16 (uint16x4_t a, uint16x4_t b, const int n) + /// A32: VRSRA.U16 Dd, Dm, #n + /// A64: URSRA Vd.4H, Vn.4H, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + public static Vector64 ShiftRightLogicalRoundedAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalRoundedAdd(addend, value, count); /// - /// int16x8_t vorrq_s16 (int16x8_t a, int16x8_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint32x2_t vrsra_n_u32 (uint32x2_t a, uint32x2_t b, const int n) + /// A32: VRSRA.U32 Dd, Dm, #n + /// A64: URSRA Vd.2S, Vn.2S, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + public static Vector64 ShiftRightLogicalRoundedAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalRoundedAdd(addend, value, count); /// - /// int32x4_t vorrq_s32 (int32x4_t a, int32x4_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint8x8_t vrsra_n_u8 (uint8x8_t a, uint8x8_t b, const int n) + /// A32: VRSRA.U8 Dd, Dm, #n + /// A64: URSRA Vd.8B, Vn.8B, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + public static Vector64 ShiftRightLogicalRoundedAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalRoundedAdd(addend, value, count); /// - /// int64x2_t vorrq_s64 (int64x2_t a, int64x2_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint16x4_t vrsra_n_u16 (uint16x4_t a, uint16x4_t b, const int n) + /// A32: VRSRA.U16 Dd, Dm, #n + /// A64: URSRA Vd.4H, Vn.4H, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + public static Vector64 ShiftRightLogicalRoundedAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalRoundedAdd(addend, value, count); /// - /// int8x16_t vorrq_s8 (int8x16_t a, int8x16_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint32x2_t vrsra_n_u32 (uint32x2_t a, uint32x2_t b, const int n) + /// A32: VRSRA.U32 Dd, Dm, #n + /// A64: URSRA Vd.2S, Vn.2S, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + public static Vector64 ShiftRightLogicalRoundedAdd(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalRoundedAdd(addend, value, count); /// - /// float32x4_t vorrq_f32 (float32x4_t a, float32x4_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x16_t vrsraq_n_u8 (uint8x16_t a, uint8x16_t b, const int n) + /// A32: VRSRA.U8 Qd, Qm, #n + /// A64: URSRA Vd.16B, Vn.16B, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalRoundedAdd(addend, value, count); /// - /// uint16x8_t vorrq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vrsraq_n_u16 (uint16x8_t a, uint16x8_t b, const int n) + /// A32: VRSRA.U16 Qd, Qm, #n + /// A64: URSRA Vd.8H, Vn.8H, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalRoundedAdd(addend, value, count); /// - /// uint32x4_t vorrq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint32x4_t vrsraq_n_u32 (uint32x4_t a, uint32x4_t b, const int n) + /// A32: VRSRA.U32 Qd, Qm, #n + /// A64: URSRA Vd.4S, Vn.4S, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalRoundedAdd(addend, value, count); /// - /// uint64x2_t vorrq_u64 (uint64x2_t a, uint64x2_t b) - /// A32: VORR Qd, Qn, Qm - /// A64: ORR Vd.16B, Vn.16B, Vm.16B + /// uint64x2_t vrsraq_n_u64 (uint64x2_t a, uint64x2_t b, const int n) + /// A32: VRSRA.U64 Qd, Qm, #n + /// A64: URSRA Vd.2D, Vn.2D, #n /// - public static Vector128 Or(Vector128 left, Vector128 right) => Or(left, right); + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalRoundedAdd(addend, value, count); /// - /// uint8x8_t vorn_u8 (uint8x8_t a, uint8x8_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// uint8x16_t vrsraq_n_u8 (uint8x16_t a, uint8x16_t b, const int n) + /// A32: VRSRA.U8 Qd, Qm, #n + /// A64: URSRA Vd.16B, Vn.16B, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalRoundedAdd(addend, value, count); /// - /// float64x1_t vorn_f64 (float64x1_t a, float64x1_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x8_t vrsraq_n_u16 (uint16x8_t a, uint16x8_t b, const int n) + /// A32: VRSRA.U16 Qd, Qm, #n + /// A64: URSRA Vd.8H, Vn.8H, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalRoundedAdd(addend, value, count); /// - /// int16x4_t vorn_s16 (int16x4_t a, int16x4_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// uint32x4_t vrsraq_n_u32 (uint32x4_t a, uint32x4_t b, const int n) + /// A32: VRSRA.U32 Qd, Qm, #n + /// A64: URSRA Vd.4S, Vn.4S, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalRoundedAdd(addend, value, count); /// - /// int32x2_t vorn_s32 (int32x2_t a, int32x2_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// uint64x2_t vrsraq_n_u64 (uint64x2_t a, uint64x2_t b, const int n) + /// A32: VRSRA.U64 Qd, Qm, #n + /// A64: URSRA Vd.2D, Vn.2D, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + public static Vector128 ShiftRightLogicalRoundedAdd(Vector128 addend, Vector128 value, byte count) => ShiftRightLogicalRoundedAdd(addend, value, count); /// - /// int64x1_t vorn_s64 (int64x1_t a, int64x1_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// uint64x1_t vrsra_n_u64 (uint64x1_t a, uint64x1_t b, const int n) + /// A32: VRSRA.U64 Dd, Dm, #n + /// A64: URSRA Dd, Dn, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + public static Vector64 ShiftRightLogicalRoundedAddScalar(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalRoundedAddScalar(addend, value, count); /// - /// int8x8_t vorn_s8 (int8x8_t a, int8x8_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// uint64x1_t vrsra_n_u64 (uint64x1_t a, uint64x1_t b, const int n) + /// A32: VRSRA.U64 Dd, Dm, #n + /// A64: URSRA Dd, Dn, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + public static Vector64 ShiftRightLogicalRoundedAddScalar(Vector64 addend, Vector64 value, byte count) => ShiftRightLogicalRoundedAddScalar(addend, value, count); /// - /// float32x2_t vorn_f32 (float32x2_t a, float32x2_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint8x8_t vrshrn_n_u16 (uint16x8_t a, const int n) + /// A32: VRSHRN.I16 Dd, Qm, #n + /// A64: RSHRN Vd.8B, Vn.8H, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + public static Vector64 ShiftRightLogicalRoundedNarrowingLower(Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingLower(value, count); /// - /// uint16x4_t vorn_u16 (uint16x4_t a, uint16x4_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// int16x4_t vrshrn_n_s32 (int32x4_t a, const int n) + /// A32: VRSHRN.I32 Dd, Qm, #n + /// A64: RSHRN Vd.4H, Vn.4S, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + public static Vector64 ShiftRightLogicalRoundedNarrowingLower(Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingLower(value, count); /// - /// uint32x2_t vorn_u32 (uint32x2_t a, uint32x2_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// int32x2_t vrshrn_n_s64 (int64x2_t a, const int n) + /// A32: VRSHRN.I64 Dd, Qm, #n + /// A64: RSHRN Vd.2S, Vn.2D, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + public static Vector64 ShiftRightLogicalRoundedNarrowingLower(Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingLower(value, count); /// - /// uint64x1_t vorn_u64 (uint64x1_t a, uint64x1_t b) - /// A32: VORN Dd, Dn, Dm - /// A64: ORN Vd.8B, Vn.8B, Vm.8B + /// int8x8_t vrshrn_n_s16 (int16x8_t a, const int n) + /// A32: VRSHRN.I16 Dd, Qm, #n + /// A64: RSHRN Vd.8B, Vn.8H, #n /// - public static Vector64 OrNot(Vector64 left, Vector64 right) => OrNot(left, right); + public static Vector64 ShiftRightLogicalRoundedNarrowingLower(Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingLower(value, count); /// - /// uint8x16_t vornq_u8 (uint8x16_t a, uint8x16_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint16x4_t vrshrn_n_u32 (uint32x4_t a, const int n) + /// A32: VRSHRN.I32 Dd, Qm, #n + /// A64: RSHRN Vd.4H, Vn.4S, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + public static Vector64 ShiftRightLogicalRoundedNarrowingLower(Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingLower(value, count); /// - /// float64x2_t vornq_f64 (float64x2_t a, float64x2_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint32x2_t vrshrn_n_u64 (uint64x2_t a, const int n) + /// A32: VRSHRN.I64 Dd, Qm, #n + /// A64: RSHRN Vd.2S, Vn.2D, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + public static Vector64 ShiftRightLogicalRoundedNarrowingLower(Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingLower(value, count); /// - /// int16x8_t vornq_s16 (int16x8_t a, int16x8_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint8x8_t vqrshrn_n_u16 (uint16x8_t a, const int n) + /// A32: VQRSHRN.U16 Dd, Qm, #n + /// A64: UQRSHRN Vd.8B, Vn.8H, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateLower(value, count); /// - /// int32x4_t vornq_s32 (int32x4_t a, int32x4_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint16x4_t vqrshrn_n_u32 (uint32x4_t a, const int n) + /// A32: VQRSHRN.U32 Dd, Qm, #n + /// A64: UQRSHRN Vd.4H, Vn.4S, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateLower(value, count); /// - /// int64x2_t vornq_s64 (int64x2_t a, int64x2_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint32x2_t vqrshrn_n_u64 (uint64x2_t a, const int n) + /// A32: VQRSHRN.U64 Dd, Qm, #n + /// A64: UQRSHRN Vd.2S, Vn.2D, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateLower(value, count); /// - /// int8x16_t vornq_s8 (int8x16_t a, int8x16_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint8x8_t vqrshrn_n_u16 (uint16x8_t a, const int n) + /// A32: VQRSHRN.U16 Dd, Qm, #n + /// A64: UQRSHRN Vd.8B, Vn.8H, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateLower(value, count); /// - /// float32x4_t vornq_f32 (float32x4_t a, float32x4_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B - /// The above native signature does not exist. We provide this additional overload for consistency with the other scalar APIs. + /// uint16x4_t vqrshrn_n_u32 (uint32x4_t a, const int n) + /// A32: VQRSHRN.U32 Dd, Qm, #n + /// A64: UQRSHRN Vd.4H, Vn.4S, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateLower(value, count); /// - /// uint16x8_t vornq_u16 (uint16x8_t a, uint16x8_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint32x2_t vqrshrn_n_u64 (uint64x2_t a, const int n) + /// A32: VQRSHRN.U64 Dd, Qm, #n + /// A64: UQRSHRN Vd.2S, Vn.2D, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + public static Vector64 ShiftRightLogicalRoundedNarrowingSaturateLower(Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateLower(value, count); /// - /// uint32x4_t vornq_u32 (uint32x4_t a, uint32x4_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint8x16_t vqrshrn_high_n_u16 (uint8x8_t r, uint16x8_t a, const int n) + /// A32: VQRSHRN.U16 Dd+1, Dn, #n + /// A64: UQRSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + public static Vector128 ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateUpper(lower, value, count); /// - /// uint64x2_t vornq_u64 (uint64x2_t a, uint64x2_t b) - /// A32: VORN Qd, Qn, Qm - /// A64: ORN Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vqrshrn_high_n_u32 (uint16x4_t r, uint32x4_t a, const int n) + /// A32: VQRSHRN.U32 Dd+1, Dn, #n + /// A64: UQRSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + public static Vector128 ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateUpper(lower, value, count); /// - /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) - /// A32: VMUL.P8 Dd, Dn, Dm - /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// uint32x4_t vqrshrn_high_n_u64 (uint32x2_t r, uint64x2_t a, const int n) + /// A32: VQRSHRN.U64 Dd+1, Dn, #n + /// A64: UQRSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) => PolynomialMultiply(left, right); + public static Vector128 ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateUpper(lower, value, count); /// - /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) - /// A32: VMUL.P8 Dd, Dn, Dm - /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// uint8x16_t vqrshrn_high_n_u16 (uint8x8_t r, uint16x8_t a, const int n) + /// A32: VQRSHRN.U16 Dd+1, Dn, #n + /// A64: UQRSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) => PolynomialMultiply(left, right); + public static Vector128 ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateUpper(lower, value, count); /// - /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) - /// A32: VMUL.P8 Qd, Qn, Qm - /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// uint16x8_t vqrshrn_high_n_u32 (uint16x4_t r, uint32x4_t a, const int n) + /// A32: VQRSHRN.U32 Dd+1, Dn, #n + /// A64: UQRSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) => PolynomialMultiply(left, right); + public static Vector128 ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateUpper(lower, value, count); /// - /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) - /// A32: VMUL.P8 Qd, Qn, Qm - /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// uint32x4_t vqrshrn_high_n_u64 (uint32x2_t r, uint64x2_t a, const int n) + /// A32: VQRSHRN.U64 Dd+1, Dn, #n + /// A64: UQRSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) => PolynomialMultiply(left, right); + public static Vector128 ShiftRightLogicalRoundedNarrowingSaturateUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingSaturateUpper(lower, value, count); /// - /// uint8x8_t vcnt_u8 (uint8x8_t a) - /// A32: VCNT.I8 Dd, Dm - /// A64: CNT Vd.8B, Vn.8B + /// uint8x16_t vrshrn_high_n_u16 (uint8x8_t r, uint16x8_t a, const int n) + /// A32: VRSHRN.I16 Dd+1, Qm, #n + /// A64: RSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector64 PopCount(Vector64 value) => PopCount(value); + public static Vector128 ShiftRightLogicalRoundedNarrowingUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingUpper(lower, value, count); /// - /// int8x8_t vcnt_s8 (int8x8_t a) - /// A32: VCNT.I8 Dd, Dm - /// A64: CNT Vd.8B, Vn.8B + /// int16x8_t vrshrn_high_n_s32 (int16x4_t r, int32x4_t a, const int n) + /// A32: VRSHRN.I32 Dd+1, Qm, #n + /// A64: RSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector64 PopCount(Vector64 value) => PopCount(value); + public static Vector128 ShiftRightLogicalRoundedNarrowingUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingUpper(lower, value, count); /// - /// uint8x16_t vcntq_u8 (uint8x16_t a) - /// A32: VCNT.I8 Qd, Qm - /// A64: CNT Vd.16B, Vn.16B + /// int32x4_t vrshrn_high_n_s64 (int32x2_t r, int64x2_t a, const int n) + /// A32: VRSHRN.I64 Dd+1, Qm, #n + /// A64: RSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector128 PopCount(Vector128 value) => PopCount(value); + public static Vector128 ShiftRightLogicalRoundedNarrowingUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingUpper(lower, value, count); /// - /// int8x16_t vcntq_s8 (int8x16_t a) - /// A32: VCNT.I8 Qd, Qm - /// A64: CNT Vd.16B, Vn.16B + /// int8x16_t vrshrn_high_n_s16 (int8x8_t r, int16x8_t a, const int n) + /// A32: VRSHRN.I16 Dd+1, Qm, #n + /// A64: RSHRN2 Vd.16B, Vn.8H, #n /// - public static Vector128 PopCount(Vector128 value) => PopCount(value); + public static Vector128 ShiftRightLogicalRoundedNarrowingUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingUpper(lower, value, count); /// - /// float32x2_t vrecpe_f32 (float32x2_t a) - /// A32: VRECPE.F32 Dd, Dm - /// A64: FRECPE Vd.2S, Vn.2S + /// uint16x8_t vrshrn_high_n_u32 (uint16x4_t r, uint32x4_t a, const int n) + /// A32: VRSHRN.I32 Dd+1, Qm, #n + /// A64: RSHRN2 Vd.8H, Vn.4S, #n /// - public static Vector64 ReciprocalEstimate(Vector64 value) => ReciprocalEstimate(value); + public static Vector128 ShiftRightLogicalRoundedNarrowingUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingUpper(lower, value, count); /// - /// uint32x2_t vrecpe_u32 (uint32x2_t a) - /// A32: VRECPE.U32 Dd, Dm - /// A64: URECPE Vd.2S, Vn.2S + /// uint32x4_t vrshrn_high_n_u64 (uint32x2_t r, uint64x2_t a, const int n) + /// A32: VRSHRN.I64 Dd+1, Qm, #n + /// A64: RSHRN2 Vd.4S, Vn.2D, #n /// - public static Vector64 ReciprocalEstimate(Vector64 value) => ReciprocalEstimate(value); + public static Vector128 ShiftRightLogicalRoundedNarrowingUpper(Vector64 lower, Vector128 value, byte count) => ShiftRightLogicalRoundedNarrowingUpper(lower, value, count); /// - /// float32x4_t vrecpeq_f32 (float32x4_t a) - /// A32: VRECPE.F32 Qd, Qm - /// A64: FRECPE Vd.4S, Vn.4S + /// uint64x1_t vrshr_n_u64 (uint64x1_t a, const int n) + /// A32: VRSHR.U64 Dd, Dm, #n + /// A64: URSHR Dd, Dn, #n /// - public static Vector128 ReciprocalEstimate(Vector128 value) => ReciprocalEstimate(value); + public static Vector64 ShiftRightLogicalRoundedScalar(Vector64 value, byte count) => ShiftRightLogicalRoundedScalar(value, count); /// - /// uint32x4_t vrecpeq_u32 (uint32x4_t a) - /// A32: VRECPE.U32 Qd, Qm - /// A64: URECPE Vd.4S, Vn.4S + /// uint64x1_t vrshr_n_u64 (uint64x1_t a, const int n) + /// A32: VRSHR.U64 Dd, Dm, #n + /// A64: URSHR Dd, Dn, #n /// - public static Vector128 ReciprocalEstimate(Vector128 value) => ReciprocalEstimate(value); + public static Vector64 ShiftRightLogicalRoundedScalar(Vector64 value, byte count) => ShiftRightLogicalRoundedScalar(value, count); /// - /// float32x2_t vrsqrte_f32 (float32x2_t a) - /// A32: VRSQRTE.F32 Dd, Dm - /// A64: FRSQRTE Vd.2S, Vn.2S + /// uint64x1_t vshr_n_u64 (uint64x1_t a, const int n) + /// A32: VSHR.U64 Dd, Dm, #n + /// A64: USHR Dd, Dn, #n /// - public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) => ReciprocalSquareRootEstimate(value); + public static Vector64 ShiftRightLogicalScalar(Vector64 value, byte count) => ShiftRightLogicalScalar(value, count); /// - /// uint32x2_t vrsqrte_u32 (uint32x2_t a) - /// A32: VRSQRTE.U32 Dd, Dm - /// A64: URSQRTE Vd.2S, Vn.2S + /// uint64x1_t vshr_n_u64 (uint64x1_t a, const int n) + /// A32: VSHR.U64 Dd, Dm, #n + /// A64: USHR Dd, Dn, #n /// - public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) => ReciprocalSquareRootEstimate(value); + public static Vector64 ShiftRightLogicalScalar(Vector64 value, byte count) => ShiftRightLogicalScalar(value, count); /// - /// float32x4_t vrsqrteq_f32 (float32x4_t a) - /// A32: VRSQRTE.F32 Qd, Qm - /// A64: FRSQRTE Vd.4S, Vn.4S + /// int32x4_t vmovl_s16 (int16x4_t a) + /// A32: VMOVL.S16 Qd, Dm + /// A64: SXTL Vd.4S, Vn.4H /// - public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) => ReciprocalSquareRootEstimate(value); + public static Vector128 SignExtendWideningLower(Vector64 value) => SignExtendWideningLower(value); /// - /// uint32x4_t vrsqrteq_u32 (uint32x4_t a) - /// A32: VRSQRTE.U32 Qd, Qm - /// A64: URSQRTE Vd.4S, Vn.4S + /// int64x2_t vmovl_s32 (int32x2_t a) + /// A32: VMOVL.S32 Qd, Dm + /// A64: SXTL Vd.2D, Vn.2S /// - public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) => ReciprocalSquareRootEstimate(value); + public static Vector128 SignExtendWideningLower(Vector64 value) => SignExtendWideningLower(value); /// - /// float32x2_t vrsqrts_f32 (float32x2_t a, float32x2_t b) - /// A32: VRSQRTS.F32 Dd, Dn, Dm - /// A64: FRSQRTS Vd.2S, Vn.2S, Vm.2S + /// int16x8_t vmovl_s8 (int8x8_t a) + /// A32: VMOVL.S8 Qd, Dm + /// A64: SXTL Vd.8H, Vn.8B /// - public static Vector64 ReciprocalSquareRootStep(Vector64 left, Vector64 right) => ReciprocalSquareRootStep(left, right); + public static Vector128 SignExtendWideningLower(Vector64 value) => SignExtendWideningLower(value); /// - /// float32x4_t vrsqrtsq_f32 (float32x4_t a, float32x4_t b) - /// A32: VRSQRTS.F32 Qd, Qn, Qm - /// A64: FRSQRTS Vd.4S, Vn.4S, Vm.4S + /// int32x4_t vmovl_high_s16 (int16x8_t a) + /// A32: VMOVL.S16 Qd, Dm+1 + /// A64: SXTL2 Vd.4S, Vn.8H /// - public static Vector128 ReciprocalSquareRootStep(Vector128 left, Vector128 right) => ReciprocalSquareRootStep(left, right); + public static Vector128 SignExtendWideningUpper(Vector128 value) => SignExtendWideningUpper(value); /// - /// float32x2_t vrecps_f32 (float32x2_t a, float32x2_t b) - /// A32: VRECPS.F32 Dd, Dn, Dm - /// A64: FRECPS Vd.2S, Vn.2S, Vm.2S + /// int64x2_t vmovl_high_s32 (int32x4_t a) + /// A32: VMOVL.S32 Qd, Dm+1 + /// A64: SXTL2 Vd.2D, Vn.4S /// - public static Vector64 ReciprocalStep(Vector64 left, Vector64 right) => ReciprocalStep(left, right); + public static Vector128 SignExtendWideningUpper(Vector128 value) => SignExtendWideningUpper(value); /// - /// float32x4_t vrecpsq_f32 (float32x4_t a, float32x4_t b) - /// A32: VRECPS.F32 Qd, Qn, Qm - /// A64: FRECPS Vd.4S, Vn.4S, Vm.4S + /// int16x8_t vmovl_high_s8 (int8x16_t a) + /// A32: VMOVL.S8 Qd, Dm+1 + /// A64: SXTL2 Vd.8H, Vn.16B /// - public static Vector128 ReciprocalStep(Vector128 left, Vector128 right) => ReciprocalStep(left, right); + public static Vector128 SignExtendWideningUpper(Vector128 value) => SignExtendWideningUpper(value); /// /// float64x1_t vsqrt_f64 (float64x1_t a) @@ -5304,6 +9956,286 @@ internal Arm64() { } /// public static Vector128 Subtract(Vector128 left, Vector128 right) => Subtract(left, right); + /// + /// uint8x8_t vsubhn_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VSUBHN.I16 Dd, Qn, Qm + /// A64: SUBHN Vd.8B, Vn.8H, Vm.8H + /// + public static Vector64 SubtractHighNarrowingLower(Vector128 left, Vector128 right) => SubtractHighNarrowingLower(left, right); + + /// + /// int16x4_t vsubhn_s32 (int32x4_t a, int32x4_t b) + /// A32: VSUBHN.I32 Dd, Qn, Qm + /// A64: SUBHN Vd.4H, Vn.4S, Vm.4S + /// + public static Vector64 SubtractHighNarrowingLower(Vector128 left, Vector128 right) => SubtractHighNarrowingLower(left, right); + + /// + /// int32x2_t vsubhn_s64 (int64x2_t a, int64x2_t b) + /// A32: VSUBHN.I64 Dd, Qn, Qm + /// A64: SUBHN Vd.2S, Vn.2D, Vm.2D + /// + public static Vector64 SubtractHighNarrowingLower(Vector128 left, Vector128 right) => SubtractHighNarrowingLower(left, right); + + /// + /// int8x8_t vsubhn_s16 (int16x8_t a, int16x8_t b) + /// A32: VSUBHN.I16 Dd, Qn, Qm + /// A64: SUBHN Vd.8B, Vn.8H, Vm.8H + /// + public static Vector64 SubtractHighNarrowingLower(Vector128 left, Vector128 right) => SubtractHighNarrowingLower(left, right); + + /// + /// uint16x4_t vsubhn_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VSUBHN.I32 Dd, Qn, Qm + /// A64: SUBHN Vd.4H, Vn.4S, Vm.4S + /// + public static Vector64 SubtractHighNarrowingLower(Vector128 left, Vector128 right) => SubtractHighNarrowingLower(left, right); + + /// + /// uint32x2_t vsubhn_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VSUBHN.I64 Dd, Qn, Qm + /// A64: SUBHN Vd.2S, Vn.2D, Vm.2D + /// + public static Vector64 SubtractHighNarrowingLower(Vector128 left, Vector128 right) => SubtractHighNarrowingLower(left, right); + + /// + /// uint8x16_t vsubhn_high_u16 (uint8x8_t r, uint16x8_t a, uint16x8_t b) + /// A32: VSUBHN.I16 Dd+1, Qn, Qm + /// A64: SUBHN2 Vd.16B, Vn.8H, Vm.8H + /// + public static Vector128 SubtractHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => SubtractHighNarrowingUpper(lower, left, right); + + /// + /// int16x8_t vsubhn_high_s32 (int16x4_t r, int32x4_t a, int32x4_t b) + /// A32: VSUBHN.I32 Dd+1, Qn, Qm + /// A64: SUBHN2 Vd.8H, Vn.4S, Vm.4S + /// + public static Vector128 SubtractHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => SubtractHighNarrowingUpper(lower, left, right); + + /// + /// int32x4_t vsubhn_high_s64 (int32x2_t r, int64x2_t a, int64x2_t b) + /// A32: VSUBHN.I64 Dd+1, Qn, Qm + /// A64: SUBHN2 Vd.4S, Vn.2D, Vm.2D + /// + public static Vector128 SubtractHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => SubtractHighNarrowingUpper(lower, left, right); + + /// + /// int8x16_t vsubhn_high_s16 (int8x8_t r, int16x8_t a, int16x8_t b) + /// A32: VSUBHN.I16 Dd+1, Qn, Qm + /// A64: SUBHN2 Vd.16B, Vn.8H, Vm.8H + /// + public static Vector128 SubtractHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => SubtractHighNarrowingUpper(lower, left, right); + + /// + /// uint16x8_t vsubhn_high_u32 (uint16x4_t r, uint32x4_t a, uint32x4_t b) + /// A32: VSUBHN.I32 Dd+1, Qn, Qm + /// A64: SUBHN2 Vd.8H, Vn.4S, Vm.4S + /// + public static Vector128 SubtractHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => SubtractHighNarrowingUpper(lower, left, right); + + /// + /// uint32x4_t vsubhn_high_u64 (uint32x2_t r, uint64x2_t a, uint64x2_t b) + /// A32: VSUBHN.I64 Dd+1, Qn, Qm + /// A64: SUBHN2 Vd.4S, Vn.2D, Vm.2D + /// + public static Vector128 SubtractHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => SubtractHighNarrowingUpper(lower, left, right); + + /// + /// uint8x8_t vrsubhn_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VRSUBHN.I16 Dd, Qn, Qm + /// A64: RSUBHN Vd.8B, Vn.8H, Vm.8H + /// + public static Vector64 SubtractRoundedHighNarrowingLower(Vector128 left, Vector128 right) => SubtractRoundedHighNarrowingLower(left, right); + + /// + /// int16x4_t vrsubhn_s32 (int32x4_t a, int32x4_t b) + /// A32: VRSUBHN.I32 Dd, Qn, Qm + /// A64: RSUBHN Vd.4H, Vn.4S, Vm.4S + /// + public static Vector64 SubtractRoundedHighNarrowingLower(Vector128 left, Vector128 right) => SubtractRoundedHighNarrowingLower(left, right); + + /// + /// int32x2_t vrsubhn_s64 (int64x2_t a, int64x2_t b) + /// A32: VRSUBHN.I64 Dd, Qn, Qm + /// A64: RSUBHN Vd.2S, Vn.2D, Vm.2D + /// + public static Vector64 SubtractRoundedHighNarrowingLower(Vector128 left, Vector128 right) => SubtractRoundedHighNarrowingLower(left, right); + + /// + /// int8x8_t vrsubhn_s16 (int16x8_t a, int16x8_t b) + /// A32: VRSUBHN.I16 Dd, Qn, Qm + /// A64: RSUBHN Vd.8B, Vn.8H, Vm.8H + /// + public static Vector64 SubtractRoundedHighNarrowingLower(Vector128 left, Vector128 right) => SubtractRoundedHighNarrowingLower(left, right); + + /// + /// uint16x4_t vrsubhn_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VRSUBHN.I32 Dd, Qn, Qm + /// A64: RSUBHN Vd.4H, Vn.4S, Vm.4S + /// + public static Vector64 SubtractRoundedHighNarrowingLower(Vector128 left, Vector128 right) => SubtractRoundedHighNarrowingLower(left, right); + + /// + /// uint32x2_t vrsubhn_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VRSUBHN.I64 Dd, Qn, Qm + /// A64: RSUBHN Vd.2S, Vn.2D, Vm.2D + /// + public static Vector64 SubtractRoundedHighNarrowingLower(Vector128 left, Vector128 right) => SubtractRoundedHighNarrowingLower(left, right); + + /// + /// uint8x16_t vrsubhn_high_u16 (uint8x8_t r, uint16x8_t a, uint16x8_t b) + /// A32: VRSUBHN.I16 Dd+1, Qn, Qm + /// A64: RSUBHN2 Vd.16B, Vn.8H, Vm.8H + /// + public static Vector128 SubtractRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => SubtractRoundedHighNarrowingUpper(lower, left, right); + + /// + /// int16x8_t vrsubhn_high_s32 (int16x4_t r, int32x4_t a, int32x4_t b) + /// A32: VRSUBHN.I32 Dd+1, Qn, Qm + /// A64: RSUBHN2 Vd.8H, Vn.4S, Vm.4S + /// + public static Vector128 SubtractRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => SubtractRoundedHighNarrowingUpper(lower, left, right); + + /// + /// int32x4_t vrsubhn_high_s64 (int32x2_t r, int64x2_t a, int64x2_t b) + /// A32: VRSUBHN.I64 Dd+1, Qn, Qm + /// A64: RSUBHN2 Vd.4S, Vn.2D, Vm.2D + /// + public static Vector128 SubtractRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => SubtractRoundedHighNarrowingUpper(lower, left, right); + + /// + /// int8x16_t vrsubhn_high_s16 (int8x8_t r, int16x8_t a, int16x8_t b) + /// A32: VRSUBHN.I16 Dd+1, Qn, Qm + /// A64: RSUBHN2 Vd.16B, Vn.8H, Vm.8H + /// + public static Vector128 SubtractRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => SubtractRoundedHighNarrowingUpper(lower, left, right); + + /// + /// uint16x8_t vrsubhn_high_u32 (uint16x4_t r, uint32x4_t a, uint32x4_t b) + /// A32: VRSUBHN.I32 Dd+1, Qn, Qm + /// A64: RSUBHN2 Vd.8H, Vn.4S, Vm.4S + /// + public static Vector128 SubtractRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => SubtractRoundedHighNarrowingUpper(lower, left, right); + + /// + /// uint32x4_t vrsubhn_high_u64 (uint32x2_t r, uint64x2_t a, uint64x2_t b) + /// A32: VRSUBHN.I64 Dd+1, Qn, Qm + /// A64: RSUBHN2 Vd.4S, Vn.2D, Vm.2D + /// + public static Vector128 SubtractRoundedHighNarrowingUpper(Vector64 lower, Vector128 left, Vector128 right) => SubtractRoundedHighNarrowingUpper(lower, left, right); + + /// + /// uint8x8_t vqsub_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VQSUB.U8 Dd, Dn, Dm + /// A64: UQSUB Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 SubtractSaturate(Vector64 left, Vector64 right) => SubtractSaturate(left, right); + + /// + /// int16x4_t vqsub_s16 (int16x4_t a, int16x4_t b) + /// A32: VQSUB.S16 Dd, Dn, Dm + /// A64: SQSUB Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 SubtractSaturate(Vector64 left, Vector64 right) => SubtractSaturate(left, right); + + /// + /// int32x2_t vqsub_s32 (int32x2_t a, int32x2_t b) + /// A32: VQSUB.S32 Dd, Dn, Dm + /// A64: SQSUB Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 SubtractSaturate(Vector64 left, Vector64 right) => SubtractSaturate(left, right); + + /// + /// int8x8_t vqsub_s8 (int8x8_t a, int8x8_t b) + /// A32: VQSUB.S8 Dd, Dn, Dm + /// A64: SQSUB Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 SubtractSaturate(Vector64 left, Vector64 right) => SubtractSaturate(left, right); + + /// + /// uint16x4_t vqsub_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VQSUB.U16 Dd, Dn, Dm + /// A64: UQSUB Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 SubtractSaturate(Vector64 left, Vector64 right) => SubtractSaturate(left, right); + + /// + /// uint32x2_t vqsub_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VQSUB.U32 Dd, Dn, Dm + /// A64: UQSUB Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 SubtractSaturate(Vector64 left, Vector64 right) => SubtractSaturate(left, right); + + /// + /// uint8x16_t vqsubq_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VQSUB.U8 Qd, Qn, Qm + /// A64: UQSUB Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) => SubtractSaturate(left, right); + + /// + /// int16x8_t vqsubq_s16 (int16x8_t a, int16x8_t b) + /// A32: VQSUB.S16 Qd, Qn, Qm + /// A64: SQSUB Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) => SubtractSaturate(left, right); + + /// + /// int32x4_t vqsubq_s32 (int32x4_t a, int32x4_t b) + /// A32: VQSUB.S32 Qd, Qn, Qm + /// A64: SQSUB Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) => SubtractSaturate(left, right); + + /// + /// int64x2_t vqsubq_s64 (int64x2_t a, int64x2_t b) + /// A32: VQSUB.S64 Qd, Qn, Qm + /// A64: SQSUB Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) => SubtractSaturate(left, right); + + /// + /// int8x16_t vqsubq_s8 (int8x16_t a, int8x16_t b) + /// A32: VQSUB.S8 Qd, Qn, Qm + /// A64: SQSUB Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) => SubtractSaturate(left, right); + + /// + /// uint16x8_t vqsubq_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VQSUB.U16 Qd, Qn, Qm + /// A64: UQSUB Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) => SubtractSaturate(left, right); + + /// + /// uint32x4_t vqsubq_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VQSUB.U32 Qd, Qn, Qm + /// A64: UQSUB Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) => SubtractSaturate(left, right); + + /// + /// uint64x2_t vqsubq_u64 (uint64x2_t a, uint64x2_t b) + /// A32: VQSUB.U64 Qd, Qn, Qm + /// A64: UQSUB Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 SubtractSaturate(Vector128 left, Vector128 right) => SubtractSaturate(left, right); + + /// + /// int64x1_t vqsub_s64 (int64x1_t a, int64x1_t b) + /// A32: VQSUB.S64 Dd, Dn, Dm + /// A64: SQSUB Dd, Dn, Dm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) => SubtractSaturateScalar(left, right); + + /// + /// uint64x1_t vqsub_u64 (uint64x1_t a, uint64x1_t b) + /// A32: VQSUB.U64 Dd, Dn, Dm + /// A64: UQSUB Dd, Dn, Dm + /// + public static Vector64 SubtractSaturateScalar(Vector64 left, Vector64 right) => SubtractSaturateScalar(left, right); + /// /// float64x1_t vsub_f64 (float64x1_t a, float64x1_t b) /// A32: VSUB.F64 Dd, Dn, Dm @@ -5333,6 +10265,202 @@ internal Arm64() { } /// public static Vector64 SubtractScalar(Vector64 left, Vector64 right) => SubtractScalar(left, right); + /// + /// uint16x8_t vsubl_u8 (uint8x8_t a, uint8x8_t b) + /// A32: VSUBL.U8 Qd, Dn, Dm + /// A64: USUBL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 SubtractWideningLower(Vector64 left, Vector64 right) => SubtractWideningLower(left, right); + + /// + /// int32x4_t vsubl_s16 (int16x4_t a, int16x4_t b) + /// A32: VSUBL.S16 Qd, Dn, Dm + /// A64: SSUBL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 SubtractWideningLower(Vector64 left, Vector64 right) => SubtractWideningLower(left, right); + + /// + /// int64x2_t vsubl_s32 (int32x2_t a, int32x2_t b) + /// A32: VSUBL.S32 Qd, Dn, Dm + /// A64: SSUBL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 SubtractWideningLower(Vector64 left, Vector64 right) => SubtractWideningLower(left, right); + + /// + /// int16x8_t vsubl_s8 (int8x8_t a, int8x8_t b) + /// A32: VSUBL.S8 Qd, Dn, Dm + /// A64: SSUBL Vd.8H, Vn.8B, Vm.8B + /// + public static Vector128 SubtractWideningLower(Vector64 left, Vector64 right) => SubtractWideningLower(left, right); + + /// + /// uint32x4_t vsubl_u16 (uint16x4_t a, uint16x4_t b) + /// A32: VSUBL.U16 Qd, Dn, Dm + /// A64: USUBL Vd.4S, Vn.4H, Vm.4H + /// + public static Vector128 SubtractWideningLower(Vector64 left, Vector64 right) => SubtractWideningLower(left, right); + + /// + /// uint64x2_t vsubl_u32 (uint32x2_t a, uint32x2_t b) + /// A32: VSUBL.U32 Qd, Dn, Dm + /// A64: USUBL Vd.2D, Vn.2S, Vm.2S + /// + public static Vector128 SubtractWideningLower(Vector64 left, Vector64 right) => SubtractWideningLower(left, right); + + /// + /// int16x8_t vsubw_s8 (int16x8_t a, int8x8_t b) + /// A32: VSUBW.S8 Qd, Qn, Dm + /// A64: SSUBW Vd.8H, Vn.8H, Vm.8B + /// + public static Vector128 SubtractWideningLower(Vector128 left, Vector64 right) => SubtractWideningLower(left, right); + + /// + /// int32x4_t vsubw_s16 (int32x4_t a, int16x4_t b) + /// A32: VSUBW.S16 Qd, Qn, Dm + /// A64: SSUBW Vd.4S, Vn.4S, Vm.4H + /// + public static Vector128 SubtractWideningLower(Vector128 left, Vector64 right) => SubtractWideningLower(left, right); + + /// + /// int64x2_t vsubw_s32 (int64x2_t a, int32x2_t b) + /// A32: VSUBW.S32 Qd, Qn, Dm + /// A64: SSUBW Vd.2D, Vn.2D, Vm.2S + /// + public static Vector128 SubtractWideningLower(Vector128 left, Vector64 right) => SubtractWideningLower(left, right); + + /// + /// uint16x8_t vsubw_u8 (uint16x8_t a, uint8x8_t b) + /// A32: VSUBW.U8 Qd, Qn, Dm + /// A64: USUBW Vd.8H, Vn.8H, Vm.8B + /// + public static Vector128 SubtractWideningLower(Vector128 left, Vector64 right) => SubtractWideningLower(left, right); + + /// + /// uint32x4_t vsubw_u16 (uint32x4_t a, uint16x4_t b) + /// A32: VSUBW.U16 Qd, Qn, Dm + /// A64: USUBW Vd.4S, Vn.4S, Vm.4H + /// + public static Vector128 SubtractWideningLower(Vector128 left, Vector64 right) => SubtractWideningLower(left, right); + + /// + /// uint64x2_t vsubw_u32 (uint64x2_t a, uint32x2_t b) + /// A32: VSUBW.U32 Qd, Qn, Dm + /// A64: USUBW Vd.2D, Vn.2D, Vm.2S + /// + public static Vector128 SubtractWideningLower(Vector128 left, Vector64 right) => SubtractWideningLower(left, right); + + /// + /// uint16x8_t vsubl_high_u8 (uint8x16_t a, uint8x16_t b) + /// A32: VSUBL.U8 Qd, Dn+1, Dm+1 + /// A64: USUBL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) => SubtractWideningUpper(left, right); + + /// + /// int32x4_t vsubl_high_s16 (int16x8_t a, int16x8_t b) + /// A32: VSUBL.S16 Qd, Dn+1, Dm+1 + /// A64: SSUBL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) => SubtractWideningUpper(left, right); + + /// + /// int16x8_t vsubw_high_s8 (int16x8_t a, int8x16_t b) + /// A32: VSUBW.S8 Qd, Qn, Dm+1 + /// A64: SSUBW2 Vd.8H, Vn.8H, Vm.16B + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) => SubtractWideningUpper(left, right); + + /// + /// int32x4_t vsubw_high_s16 (int32x4_t a, int16x8_t b) + /// A32: VSUBW.S16 Qd, Qn, Dm+1 + /// A64: SSUBW2 Vd.4S, Vn.4S, Vm.8H + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) => SubtractWideningUpper(left, right); + + /// + /// int64x2_t vsubl_high_s32 (int32x4_t a, int32x4_t b) + /// A32: VSUBL.S32 Qd, Dn+1, Dm+1 + /// A64: SSUBL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) => SubtractWideningUpper(left, right); + + /// + /// int64x2_t vsubw_high_s32 (int64x2_t a, int32x4_t b) + /// A32: VSUBW.S32 Qd, Qn, Dm+1 + /// A64: SSUBW2 Vd.2D, Vn.2D, Vm.4S + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) => SubtractWideningUpper(left, right); + + /// + /// int16x8_t vsubl_high_s8 (int8x16_t a, int8x16_t b) + /// A32: VSUBL.S8 Qd, Dn+1, Dm+1 + /// A64: SSUBL2 Vd.8H, Vn.16B, Vm.16B + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) => SubtractWideningUpper(left, right); + + /// + /// uint16x8_t vsubw_high_u8 (uint16x8_t a, uint8x16_t b) + /// A32: VSUBW.U8 Qd, Qn, Dm+1 + /// A64: USUBW2 Vd.8H, Vn.8H, Vm.16B + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) => SubtractWideningUpper(left, right); + + /// + /// uint32x4_t vsubl_high_u16 (uint16x8_t a, uint16x8_t b) + /// A32: VSUBL.U16 Qd, Dn+1, Dm+1 + /// A64: USUBL2 Vd.4S, Vn.8H, Vm.8H + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) => SubtractWideningUpper(left, right); + + /// + /// uint32x4_t vsubw_high_u16 (uint32x4_t a, uint16x8_t b) + /// A32: VSUBW.U16 Qd, Qn, Dm+1 + /// A64: USUBW2 Vd.4S, Vn.4S, Vm.8H + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) => SubtractWideningUpper(left, right); + + /// + /// uint64x2_t vsubl_high_u32 (uint32x4_t a, uint32x4_t b) + /// A32: VSUBL.U32 Qd, Dn+1, Dm+1 + /// A64: USUBL2 Vd.2D, Vn.4S, Vm.4S + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) => SubtractWideningUpper(left, right); + + /// + /// uint64x2_t vsubw_high_u32 (uint64x2_t a, uint32x4_t b) + /// A32: VSUBW.U32 Qd, Qn, Dm+1 + /// A64: USUBW2 Vd.2D, Vn.2D, Vm.4S + /// + public static Vector128 SubtractWideningUpper(Vector128 left, Vector128 right) => SubtractWideningUpper(left, right); + + /// + /// uint8x8_t vqvtbl1_u8(uint8x16_t t, uint8x8_t idx) + /// A32: VTBL Dd, {Dn, Dn+1}, Dm + /// A64: TBL Vd.8B, {Vn.16B}, Vm.8B + /// + public static Vector64 VectorTableLookup(Vector128 table, Vector64 byteIndexes) => VectorTableLookup(table, byteIndexes); + + /// + /// int8x8_t vqvtbl1_s8(int8x16_t t, uint8x8_t idx) + /// A32: VTBL Dd, {Dn, Dn+1}, Dm + /// A64: TBL Vd.8B, {Vn.16B}, Vm.8B + /// + public static Vector64 VectorTableLookup(Vector128 table, Vector64 byteIndexes) => VectorTableLookup(table, byteIndexes); + + /// + /// uint8x8_t vqvtbx1_u8(uint8x8_t r, uint8x16_t t, uint8x8_t idx) + /// A32: VTBX Dd, {Dn, Dn+1}, Dm + /// A64: TBX Vd.8B, {Vn.16B}, Vm.8B + /// + public static Vector64 VectorTableLookupExtension(Vector64 defaultValues, Vector128 table, Vector64 byteIndexes) => VectorTableLookupExtension(defaultValues, table, byteIndexes); + + /// + /// int8x8_t vqvtbx1_s8(int8x8_t r, int8x16_t t, uint8x8_t idx) + /// A32: VTBX Dd, {Dn, Dn+1}, Dm + /// A64: TBX Vd.8B, {Vn.16B}, Vm.8B + /// + public static Vector64 VectorTableLookupExtension(Vector64 defaultValues, Vector128 table, Vector64 byteIndexes) => VectorTableLookupExtension(defaultValues, table, byteIndexes); + /// /// uint8x8_t veor_u8 (uint8x8_t a, uint8x8_t b) /// A32: VEOR Dd, Dn, Dm @@ -5476,5 +10604,89 @@ internal Arm64() { } /// A64: EOR Vd.16B, Vn.16B, Vm.16B /// public static Vector128 Xor(Vector128 left, Vector128 right) => Xor(left, right); + + /// + /// uint16x8_t vmovl_u8 (uint8x8_t a) + /// A32: VMOVL.U8 Qd, Dm + /// A64: UXTL Vd.8H, Vn.8B + /// + public static Vector128 ZeroExtendWideningLower(Vector64 value) => ZeroExtendWideningLower(value); + + /// + /// uint32x4_t vmovl_u16 (uint16x4_t a) + /// A32: VMOVL.U16 Qd, Dm + /// A64: UXTL Vd.4S, Vn.4H + /// + public static Vector128 ZeroExtendWideningLower(Vector64 value) => ZeroExtendWideningLower(value); + + /// + /// uint64x2_t vmovl_u32 (uint32x2_t a) + /// A32: VMOVL.U32 Qd, Dm + /// A64: UXTL Vd.2D, Vn.2S + /// + public static Vector128 ZeroExtendWideningLower(Vector64 value) => ZeroExtendWideningLower(value); + + /// + /// uint16x8_t vmovl_u8 (uint8x8_t a) + /// A32: VMOVL.U8 Qd, Dm + /// A64: UXTL Vd.8H, Vn.8B + /// + public static Vector128 ZeroExtendWideningLower(Vector64 value) => ZeroExtendWideningLower(value); + + /// + /// uint32x4_t vmovl_u16 (uint16x4_t a) + /// A32: VMOVL.U16 Qd, Dm + /// A64: UXTL Vd.4S, Vn.4H + /// + public static Vector128 ZeroExtendWideningLower(Vector64 value) => ZeroExtendWideningLower(value); + + /// + /// uint64x2_t vmovl_u32 (uint32x2_t a) + /// A32: VMOVL.U32 Qd, Dm + /// A64: UXTL Vd.2D, Vn.2S + /// + public static Vector128 ZeroExtendWideningLower(Vector64 value) => ZeroExtendWideningLower(value); + + /// + /// uint16x8_t vmovl_high_u8 (uint8x16_t a) + /// A32: VMOVL.U8 Qd, Dm+1 + /// A64: UXTL2 Vd.8H, Vn.16B + /// + public static Vector128 ZeroExtendWideningUpper(Vector128 value) => ZeroExtendWideningUpper(value); + + /// + /// uint32x4_t vmovl_high_u16 (uint16x8_t a) + /// A32: VMOVL.U16 Qd, Dm+1 + /// A64: UXTL2 Vd.4S, Vn.8H + /// + public static Vector128 ZeroExtendWideningUpper(Vector128 value) => ZeroExtendWideningUpper(value); + + /// + /// uint64x2_t vmovl_high_u32 (uint32x4_t a) + /// A32: VMOVL.U32 Qd, Dm+1 + /// A64: UXTL2 Vd.2D, Vn.4S + /// + public static Vector128 ZeroExtendWideningUpper(Vector128 value) => ZeroExtendWideningUpper(value); + + /// + /// uint16x8_t vmovl_high_u8 (uint8x16_t a) + /// A32: VMOVL.U8 Qd, Dm+1 + /// A64: UXTL2 Vd.8H, Vn.16B + /// + public static Vector128 ZeroExtendWideningUpper(Vector128 value) => ZeroExtendWideningUpper(value); + + /// + /// uint32x4_t vmovl_high_u16 (uint16x8_t a) + /// A32: VMOVL.U16 Qd, Dm+1 + /// A64: UXTL2 Vd.4S, Vn.8H + /// + public static Vector128 ZeroExtendWideningUpper(Vector128 value) => ZeroExtendWideningUpper(value); + + /// + /// uint64x2_t vmovl_high_u32 (uint32x4_t a) + /// A32: VMOVL.U32 Qd, Dm+1 + /// A64: UXTL2 Vd.2D, Vn.4S + /// + public static Vector128 ZeroExtendWideningUpper(Vector128 value) => ZeroExtendWideningUpper(value); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Aes.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Aes.PlatformNotSupported.cs index 8f62ae5fcbc948..de081c7e6e728a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Aes.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Aes.PlatformNotSupported.cs @@ -44,5 +44,34 @@ internal Aes() { } /// A64: AESMC V>.16B, Vn.16B /// public static Vector128 MixColumns(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// poly128_t vmull_p64 (poly64_t a, poly64_t b) + /// A32: VMULL.P8 Qd, Dn, Dm + /// A64: PMULL Vd.1Q, Vn.1D, Vm.1D + /// + public static Vector128 PolynomialMultiplyWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly128_t vmull_p64 (poly64_t a, poly64_t b) + /// A32: VMULL.P8 Qd, Dn, Dm + /// A64: PMULL Vd.1Q, Vn.1D, Vm.1D + /// + public static Vector128 PolynomialMultiplyWideningLower(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly128_t vmull_high_p64 (poly64x2_t a, poly64x2_t b) + /// A32: VMULL.P8 Qd, Dn+1, Dm+1 + /// A64: PMULL2 Vd.1Q, Vn.2D, Vm.2D + /// + public static Vector128 PolynomialMultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly128_t vmull_high_p64 (poly64x2_t a, poly64x2_t b) + /// A32: VMULL.P8 Qd, Dn+1, Dm+1 + /// A64: PMULL2 Vd.1Q, Vn.2D, Vm.2D + /// + public static Vector128 PolynomialMultiplyWideningUpper(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Aes.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Aes.cs index fb0a1c63975c39..97253b888eedce 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Aes.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Arm/Aes.cs @@ -44,5 +44,33 @@ internal Aes() { } /// A64: AESMC V>.16B, Vn.16B /// public static Vector128 MixColumns(Vector128 value) => MixColumns(value); + + /// + /// poly128_t vmull_p64 (poly64_t a, poly64_t b) + /// A32: VMULL.P8 Qd, Dn, Dm + /// A64: PMULL Vd.1Q, Vn.1D, Vm.1D + /// + public static Vector128 PolynomialMultiplyWideningLower(Vector64 left, Vector64 right) => PolynomialMultiplyWideningLower(left, right); + + /// + /// poly128_t vmull_p64 (poly64_t a, poly64_t b) + /// A32: VMULL.P8 Qd, Dn, Dm + /// A64: PMULL Vd.1Q, Vn.1D, Vm.1D + /// + public static Vector128 PolynomialMultiplyWideningLower(Vector64 left, Vector64 right) => PolynomialMultiplyWideningLower(left, right); + + /// + /// poly128_t vmull_high_p64 (poly64x2_t a, poly64x2_t b) + /// A32: VMULL.P8 Qd, Dn+1, Dm+1 + /// A64: PMULL2 Vd.1Q, Vn.2D, Vm.2D + /// + public static Vector128 PolynomialMultiplyWideningUpper(Vector128 left, Vector128 right) => PolynomialMultiplyWideningUpper(left, right); + + /// + /// poly128_t vmull_high_p64 (poly64x2_t a, poly64x2_t b) + /// A32: VMULL.P8 Qd, Dn+1, Dm+1 + /// A64: PMULL2 Vd.1Q, Vn.2D, Vm.2D + /// + public static Vector128 PolynomialMultiplyWideningUpper(Vector128 left, Vector128 right) => PolynomialMultiplyWideningUpper(left, right); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index e0b71116746dde..f2b4fe0ae6d9df 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; using Internal.Runtime.CompilerServices; @@ -258,30 +259,12 @@ public static Vector AsVector(this Vector128 value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m128i _mm_set1_epi8 /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector128 Create(byte value) { - if (Avx2.IsSupported) - { - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - return Avx2.BroadcastScalarToVector128(result); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v > - } - - if (Ssse3.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - return Ssse3.Shuffle(result, Vector128.Zero); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v > - } - - if (Sse2.IsSupported) - { - // We first unpack as bytes to duplicate value into the lower 2 bytes, then we treat it as a ushort and unpack again to duplicate those - // bits into the lower 2 words, we can finally treat it as a uint and shuffle the lower dword to duplicate value across the entire result - - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - result = Sse2.UnpackLow(result, result); // < v, v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - result = Sse2.UnpackLow(result.AsUInt16(), result.AsUInt16()).AsByte(); // < v, v, v, v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - return Sse2.Shuffle(result.AsUInt32(), 0x00).AsByte(); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -316,22 +299,12 @@ static Vector128 SoftwareFallback(byte value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m128d _mm_set1_pd /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector128 Create(double value) { - if (Sse3.IsSupported) - { - Vector128 result = CreateScalarUnsafe(value); // < v, ? > - return Sse3.MoveAndDuplicate(result); // < v, v > - } - - if (Sse2.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { - // Treating the value as a set of singles and emitting MoveLowToHigh is more efficient than dealing with the elements directly as double - // However, we still need to check if Sse2 is supported since CreateScalarUnsafe needs it to for movsd, when value is not already in register - - Vector128 result = CreateScalarUnsafe(value); // < v, ? > - return Sse.MoveLowToHigh(result.AsSingle(), result.AsSingle()).AsDouble(); // < v, v > + return Create(value); } return SoftwareFallback(value); @@ -352,23 +325,12 @@ static Vector128 SoftwareFallback(double value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m128i _mm_set1_epi16 /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector128 Create(short value) { - if (Avx2.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ? > - return Avx2.BroadcastScalarToVector128(result); // < v, v, v, v, v, v, v, v > - } - - if (Sse2.IsSupported) - { - // We first unpack as ushort to duplicate value into the lower 2 words, then we can treat it as a uint and shuffle the lower dword to - // duplicate value across the entire result - - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ? > - result = Sse2.UnpackLow(result, result); // < v, v, ?, ?, ?, ?, ?, ? > - return Sse2.Shuffle(result.AsInt32(), 0x00).AsInt16(); // < v, v, v, v, v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -395,19 +357,12 @@ static Vector128 SoftwareFallback(short value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m128i _mm_set1_epi32 /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector128 Create(int value) { - if (Avx2.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ? > - return Avx2.BroadcastScalarToVector128(result); // < v, v, v, v > - } - - if (Sse2.IsSupported) - { - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ? > - return Sse2.Shuffle(result, 0x00); // < v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -430,21 +385,12 @@ static Vector128 SoftwareFallback(int value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m128i _mm_set1_epi64x /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector128 Create(long value) { - if (Sse2.X64.IsSupported) + if (Sse2.X64.IsSupported || AdvSimd.Arm64.IsSupported) { - if (Avx2.IsSupported) - { - Vector128 result = CreateScalarUnsafe(value); // < v, ? > - return Avx2.BroadcastScalarToVector128(result); // < v, v > - } - else - { - Vector128 result = CreateScalarUnsafe(value); // < v, ? > - return Sse2.UnpackLow(result, result); // < v, v > - } + return Create(value); } return SoftwareFallback(value); @@ -465,31 +411,13 @@ static Vector128 SoftwareFallback(long value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m128i _mm_set1_epi8 /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector128 Create(sbyte value) { - if (Avx2.IsSupported) - { - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - return Avx2.BroadcastScalarToVector128(result); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v > - } - - if (Ssse3.IsSupported) - { - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - return Ssse3.Shuffle(result, Vector128.Zero); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v > - } - - if (Sse2.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { - // We first unpack as bytes to duplicate value into the lower 2 bytes, then we treat it as a ushort and unpack again to duplicate those - // bits into the lower 2 words, we can finally treat it as a uint and shuffle the lower dword to duplicate value across the entire result - - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - result = Sse2.UnpackLow(result, result); // < v, v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - result = Sse2.UnpackLow(result.AsInt16(), result.AsInt16()).AsSByte(); // < v, v, v, v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - return Sse2.Shuffle(result.AsInt32(), 0x00).AsSByte(); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -524,25 +452,12 @@ static Vector128 SoftwareFallback(sbyte value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m128 _mm_set1_ps /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector128 Create(float value) { - if (Avx2.IsSupported) - { - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ? > - return Avx2.BroadcastScalarToVector128(result); // < v, v, v, v > - } - - if (Avx.IsSupported) - { - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ? > - return Avx.Permute(result, 0x00); // < v, v, v, v > - } - - if (Sse.IsSupported) + if (Sse.IsSupported || AdvSimd.IsSupported) { - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ? > - return Sse.Shuffle(result, result, 0x00); // < v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -565,24 +480,13 @@ static Vector128 SoftwareFallback(float value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m128i _mm_set1_epi16 /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector128 Create(ushort value) { - if (Avx2.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ? > - return Avx2.BroadcastScalarToVector128(result); // < v, v, v, v, v, v, v, v > - } - - if (Sse2.IsSupported) - { - // We first unpack as ushort to duplicate value into the lower 2 words, then we can treat it as a uint and shuffle the lower dword to - // duplicate value across the entire result - - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ? > - result = Sse2.UnpackLow(result, result); // < v, v, ?, ?, ?, ?, ?, ? > - return Sse2.Shuffle(result.AsUInt32(), 0x00).AsUInt16(); // < v, v, v, v, v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -609,20 +513,13 @@ static Vector128 SoftwareFallback(ushort value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m128i _mm_set1_epi32 /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector128 Create(uint value) { - if (Avx2.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ? > - return Avx2.BroadcastScalarToVector128(result); // < v, v, v, v > - } - - if (Sse2.IsSupported) - { - Vector128 result = CreateScalarUnsafe(value); // < v, ?, ?, ? > - return Sse2.Shuffle(result, 0x00); // < v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -645,22 +542,13 @@ static Vector128 SoftwareFallback(uint value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m128i _mm_set1_epi64x /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector128 Create(ulong value) { - if (Sse2.X64.IsSupported) + if (Sse2.X64.IsSupported || AdvSimd.Arm64.IsSupported) { - if (Avx2.IsSupported) - { - Vector128 result = CreateScalarUnsafe(value); // < v, ? > - return Avx2.BroadcastScalarToVector128(result); // < v, v > - } - else - { - Vector128 result = CreateScalarUnsafe(value); // < v, ? > - return Sse2.UnpackLow(result, result); // < v, v > - } + return Create(value); } return SoftwareFallback(value); @@ -696,60 +584,12 @@ static Vector128 SoftwareFallback(ulong value) /// The value that element 15 will be initialized to. /// On x86, this method corresponds to __m128i _mm_setr_epi8 /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector128 Create(byte e0, byte e1, byte e2, byte e3, byte e4, byte e5, byte e6, byte e7, byte e8, byte e9, byte e10, byte e11, byte e12, byte e13, byte e14, byte e15) { - if (Sse41.IsSupported) - { - Vector128 result = CreateScalarUnsafe(e0); // < 0, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e1, 1); // < 0, 1, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e2, 2); // < 0, 1, 2, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e3, 3); // < 0, 1, 2, 3, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e4, 4); // < 0, 1, 2, 3, 4, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e5, 5); // < 0, 1, 2, 3, 4, 5, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e6, 6); // < 0, 1, 2, 3, 4, 5, 6, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e7, 7); // < 0, 1, 2, 3, 4, 5, 6, 7, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e8, 8); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e9, 9); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e10, 10); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e11, 11); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ??, ??, ??, ?? > - result = Sse41.Insert(result, e12, 12); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ??, ??, ?? > - result = Sse41.Insert(result, e13, 13); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, ??, ?? > - result = Sse41.Insert(result, e14, 14); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, ?? > - return Sse41.Insert(result, e15, 15); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 > - } - - if (Sse2.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { - // We deal with the elements in order, unpacking the ordered pairs of bytes into vectors. We then treat those vectors as ushort and - // unpack them again, then again treating those results as uint, and a final time treating them as ulong. This efficiently gets all - // bytes ordered into the result. - - Vector128 lo16, hi16; - Vector128 lo32, hi32; - Vector128 lo64, hi64; - - lo16 = Sse2.UnpackLow(CreateScalarUnsafe(e0), CreateScalarUnsafe(e1)).AsUInt16(); // < 0, 1, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - hi16 = Sse2.UnpackLow(CreateScalarUnsafe(e2), CreateScalarUnsafe(e3)).AsUInt16(); // < 2, 3, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - lo32 = Sse2.UnpackLow(lo16, hi16).AsUInt32(); // < 0, 1, 2, 3, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - - lo16 = Sse2.UnpackLow(CreateScalarUnsafe(e4), CreateScalarUnsafe(e5)).AsUInt16(); // < 4, 5, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - hi16 = Sse2.UnpackLow(CreateScalarUnsafe(e6), CreateScalarUnsafe(e7)).AsUInt16(); // < 6, 7, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - hi32 = Sse2.UnpackLow(lo16, hi16).AsUInt32(); // < 4, 5, 6, 7, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - - lo64 = Sse2.UnpackLow(lo32, hi32).AsUInt64(); // < 0, 1, 2, 3, 4, 5, 6, 7, ??, ??, ??, ??, ??, ??, ??, ?? > - - lo16 = Sse2.UnpackLow(CreateScalarUnsafe(e8), CreateScalarUnsafe(e9)).AsUInt16(); // < 8, 9, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - hi16 = Sse2.UnpackLow(CreateScalarUnsafe(e10), CreateScalarUnsafe(e11)).AsUInt16(); // < 10, 11, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - lo32 = Sse2.UnpackLow(lo16, hi16).AsUInt32(); // < 8, 9, 10, 11, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - - lo16 = Sse2.UnpackLow(CreateScalarUnsafe(e12), CreateScalarUnsafe(e13)).AsUInt16(); // < 12, 13, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - hi16 = Sse2.UnpackLow(CreateScalarUnsafe(e14), CreateScalarUnsafe(e15)).AsUInt16(); // < 14, 15, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - hi32 = Sse2.UnpackLow(lo16, hi16).AsUInt32(); // < 12, 13, 14, 15, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - - hi64 = Sse2.UnpackLow(lo32, hi32).AsUInt64(); // < 8, 9, 10, 11, 12, 13, 14, 15, ??, ??, ??, ??, ??, ??, ??, ?? > - - return Sse2.UnpackLow(lo64, hi64).AsByte(); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 > + return Create(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15); } return SoftwareFallback(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15); @@ -785,15 +625,12 @@ static Vector128 SoftwareFallback(byte e0, byte e1, byte e2, byte e3, byte /// The value that element 1 will be initialized to. /// On x86, this method corresponds to __m128d _mm_setr_pd /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector128 Create(double e0, double e1) { - if (Sse2.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { - // Treating the value as a set of singles and emitting MoveLowToHigh is more efficient than dealing with the elements directly as double - // However, we still need to check if Sse2 is supported since CreateScalarUnsafe needs it to for movsd, when value is not already in register - - return Sse.MoveLowToHigh(CreateScalarUnsafe(e0).AsSingle(), CreateScalarUnsafe(e1).AsSingle()).AsDouble(); + return Create(e0, e1); } return SoftwareFallback(e0, e1); @@ -821,19 +658,12 @@ static Vector128 SoftwareFallback(double e0, double e1) /// The value that element 7 will be initialized to. /// On x86, this method corresponds to __m128i _mm_setr_epi16 /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector128 Create(short e0, short e1, short e2, short e3, short e4, short e5, short e6, short e7) { - if (Sse2.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { - Vector128 result = CreateScalarUnsafe(e0); // < 0, ?, ?, ?, ?, ?, ?, ? > - result = Sse2.Insert(result, e1, 1); // < 0, 1, ?, ?, ?, ?, ?, ? > - result = Sse2.Insert(result, e2, 2); // < 0, 1, 2, ?, ?, ?, ?, ? > - result = Sse2.Insert(result, e3, 3); // < 0, 1, 2, 3, ?, ?, ?, ? > - result = Sse2.Insert(result, e4, 4); // < 0, 1, 2, 3, 4, ?, ?, ? > - result = Sse2.Insert(result, e5, 5); // < 0, 1, 2, 3, 4, 5, ?, ? > - result = Sse2.Insert(result, e6, 6); // < 0, 1, 2, 3, 4, 5, 6, ? > - return Sse2.Insert(result, e7, 7); // < 0, 1, 2, 3, 4, 5, 6, 7 > + return Create(e0, e1, e2, e3, e4, e5, e6, e7); } return SoftwareFallback(e0, e1, e2, e3, e4, e5, e6, e7); @@ -863,26 +693,12 @@ static Vector128 SoftwareFallback(short e0, short e1, short e2, short e3, /// The value that element 3 will be initialized to. /// On x86, this method corresponds to __m128i _mm_setr_epi32 /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector128 Create(int e0, int e1, int e2, int e3) { - if (Sse41.IsSupported) - { - Vector128 result = CreateScalarUnsafe(e0); // < 0, ?, ?, ? > - result = Sse41.Insert(result, e1, 1); // < 0, 1, ?, ? > - result = Sse41.Insert(result, e2, 2); // < 0, 1, 2, ? > - return Sse41.Insert(result, e3, 3); // < 0, 1, 2, 3 > - } - - if (Sse2.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { - // We deal with the elements in order, unpacking the ordered pairs of int into vectors. We then treat those vectors as ulong and - // unpack them again. This efficiently gets all ints ordered into the result. - - Vector128 lo64, hi64; - lo64 = Sse2.UnpackLow(CreateScalarUnsafe(e0), CreateScalarUnsafe(e1)).AsInt64(); // < 0, 1, ?, ? > - hi64 = Sse2.UnpackLow(CreateScalarUnsafe(e2), CreateScalarUnsafe(e3)).AsInt64(); // < 2, 3, ?, ? > - return Sse2.UnpackLow(lo64, hi64).AsInt32(); // < 0, 1, 2, 3 > + return Create(e0, e1, e2, e3); } return SoftwareFallback(e0, e1, e2, e3); @@ -906,18 +722,12 @@ static Vector128 SoftwareFallback(int e0, int e1, int e2, int e3) /// The value that element 1 will be initialized to. /// On x86, this method corresponds to __m128i _mm_setr_epi64x /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector128 Create(long e0, long e1) { - if (Sse41.X64.IsSupported) + if (Sse2.X64.IsSupported || AdvSimd.Arm64.IsSupported) { - Vector128 result = CreateScalarUnsafe(e0); // < 0, ? > - return Sse41.X64.Insert(result, e1, 1); // < 0, 1 > - } - - if (Sse2.X64.IsSupported) - { - return Sse2.UnpackLow(CreateScalarUnsafe(e0), CreateScalarUnsafe(e1)); // < 0, 1 > + return Create(e0, e1); } return SoftwareFallback(e0, e1); @@ -953,61 +763,13 @@ static Vector128 SoftwareFallback(long e0, long e1) /// The value that element 15 will be initialized to. /// On x86, this method corresponds to __m128i _mm_setr_epi8 /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector128 Create(sbyte e0, sbyte e1, sbyte e2, sbyte e3, sbyte e4, sbyte e5, sbyte e6, sbyte e7, sbyte e8, sbyte e9, sbyte e10, sbyte e11, sbyte e12, sbyte e13, sbyte e14, sbyte e15) { - if (Sse41.IsSupported) - { - Vector128 result = CreateScalarUnsafe(e0); // < 0, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e1, 1); // < 0, 1, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e2, 2); // < 0, 1, 2, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e3, 3); // < 0, 1, 2, 3, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e4, 4); // < 0, 1, 2, 3, 4, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e5, 5); // < 0, 1, 2, 3, 4, 5, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e6, 6); // < 0, 1, 2, 3, 4, 5, 6, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e7, 7); // < 0, 1, 2, 3, 4, 5, 6, 7, ??, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e8, 8); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, ??, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e9, 9); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ??, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e10, 10); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ??, ??, ??, ??, ?? > - result = Sse41.Insert(result, e11, 11); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ??, ??, ??, ?? > - result = Sse41.Insert(result, e12, 12); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ??, ??, ?? > - result = Sse41.Insert(result, e13, 13); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, ??, ?? > - result = Sse41.Insert(result, e14, 14); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, ?? > - return Sse41.Insert(result, e15, 15); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 > - } - - if (Sse2.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { - // We deal with the elements in order, unpacking the ordered pairs of bytes into vectors. We then treat those vectors as ushort and - // unpack them again, then again treating those results as uint, and a final time treating them as ulong. This efficiently gets all - // bytes ordered into the result. - - Vector128 lo16, hi16; - Vector128 lo32, hi32; - Vector128 lo64, hi64; - - lo16 = Sse2.UnpackLow(CreateScalarUnsafe(e0), CreateScalarUnsafe(e1)).AsInt16(); // < 0, 1, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - hi16 = Sse2.UnpackLow(CreateScalarUnsafe(e2), CreateScalarUnsafe(e3)).AsInt16(); // < 2, 3, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - lo32 = Sse2.UnpackLow(lo16, hi16).AsInt32(); // < 0, 1, 2, 3, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - - lo16 = Sse2.UnpackLow(CreateScalarUnsafe(e4), CreateScalarUnsafe(e5)).AsInt16(); // < 4, 5, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - hi16 = Sse2.UnpackLow(CreateScalarUnsafe(e6), CreateScalarUnsafe(e7)).AsInt16(); // < 6, 7, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - hi32 = Sse2.UnpackLow(lo16, hi16).AsInt32(); // < 4, 5, 6, 7, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - - lo64 = Sse2.UnpackLow(lo32, hi32).AsInt64(); // < 0, 1, 2, 3, 4, 5, 6, 7, ??, ??, ??, ??, ??, ??, ??, ?? > - - lo16 = Sse2.UnpackLow(CreateScalarUnsafe(e8), CreateScalarUnsafe(e9)).AsInt16(); // < 8, 9, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - hi16 = Sse2.UnpackLow(CreateScalarUnsafe(e10), CreateScalarUnsafe(e11)).AsInt16(); // < 10, 11, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - lo32 = Sse2.UnpackLow(lo16, hi16).AsInt32(); // < 8, 9, 10, 11, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - - lo16 = Sse2.UnpackLow(CreateScalarUnsafe(e12), CreateScalarUnsafe(e13)).AsInt16(); // < 12, 13, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - hi16 = Sse2.UnpackLow(CreateScalarUnsafe(e14), CreateScalarUnsafe(e15)).AsInt16(); // < 14, 15, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - hi32 = Sse2.UnpackLow(lo16, hi16).AsInt32(); // < 12, 13, 14, 15, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ??, ?? > - - hi64 = Sse2.UnpackLow(lo32, hi32).AsInt64(); // < 8, 9, 10, 11, 12, 13, 14, 15, ??, ??, ??, ??, ??, ??, ??, ?? > - - return Sse2.UnpackLow(lo64, hi64).AsSByte(); // < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 > + return Create(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15); } return SoftwareFallback(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15); @@ -1045,23 +807,12 @@ static Vector128 SoftwareFallback(sbyte e0, sbyte e1, sbyte e2, sbyte e3, /// The value that element 3 will be initialized to. /// On x86, this method corresponds to __m128 _mm_setr_ps /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector128 Create(float e0, float e1, float e2, float e3) { - if (Sse41.IsSupported) - { - Vector128 result = CreateScalarUnsafe(e0); // < 0, ?, ?, ? > - result = Sse41.Insert(result, CreateScalarUnsafe(e1), 0x10); // < 0, 1, ?, ? > - result = Sse41.Insert(result, CreateScalarUnsafe(e2), 0x20); // < 0, 1, 2, ? > - return Sse41.Insert(result, CreateScalarUnsafe(e3), 0x30); // < 0, 1, 2, 3 > - } - - if (Sse.IsSupported) + if (Sse.IsSupported || AdvSimd.IsSupported) { - Vector128 lo64, hi64; - lo64 = Sse.UnpackLow(CreateScalarUnsafe(e0), CreateScalarUnsafe(e1)); // < 0, 1, ?, ? > - hi64 = Sse.UnpackLow(CreateScalarUnsafe(e2), CreateScalarUnsafe(e3)); // < 2, 3, ?, ? > - return Sse.MoveLowToHigh(lo64, hi64); // < 0, 1, 2, 3 > + return Create(e0, e1, e2, e3); } return SoftwareFallback(e0, e1, e2, e3); @@ -1091,20 +842,13 @@ static Vector128 SoftwareFallback(float e0, float e1, float e2, float e3) /// The value that element 7 will be initialized to. /// On x86, this method corresponds to __m128i _mm_setr_epi16 /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector128 Create(ushort e0, ushort e1, ushort e2, ushort e3, ushort e4, ushort e5, ushort e6, ushort e7) { - if (Sse2.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { - Vector128 result = CreateScalarUnsafe(e0); // < 0, ?, ?, ?, ?, ?, ?, ? > - result = Sse2.Insert(result, e1, 1); // < 0, 1, ?, ?, ?, ?, ?, ? > - result = Sse2.Insert(result, e2, 2); // < 0, 1, 2, ?, ?, ?, ?, ? > - result = Sse2.Insert(result, e3, 3); // < 0, 1, 2, 3, ?, ?, ?, ? > - result = Sse2.Insert(result, e4, 4); // < 0, 1, 2, 3, 4, ?, ?, ? > - result = Sse2.Insert(result, e5, 5); // < 0, 1, 2, 3, 4, 5, ?, ? > - result = Sse2.Insert(result, e6, 6); // < 0, 1, 2, 3, 4, 5, 6, ? > - return Sse2.Insert(result, e7, 7); // < 0, 1, 2, 3, 4, 5, 6, 7 > + return Create(e0, e1, e2, e3, e4, e5, e6, e7); } return SoftwareFallback(e0, e1, e2, e3, e4, e5, e6, e7); @@ -1134,27 +878,13 @@ static Vector128 SoftwareFallback(ushort e0, ushort e1, ushort e2, ushor /// The value that element 3 will be initialized to. /// On x86, this method corresponds to __m128i _mm_setr_epi32 /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector128 Create(uint e0, uint e1, uint e2, uint e3) { - if (Sse41.IsSupported) + if (Sse2.IsSupported || AdvSimd.IsSupported) { - Vector128 result = CreateScalarUnsafe(e0); // < 0, ?, ?, ? > - result = Sse41.Insert(result, e1, 1); // < 0, 1, ?, ? > - result = Sse41.Insert(result, e2, 2); // < 0, 1, 2, ? > - return Sse41.Insert(result, e3, 3); // < 0, 1, 2, 3 > - } - - if (Sse2.IsSupported) - { - // We deal with the elements in order, unpacking the ordered pairs of int into vectors. We then treat those vectors as ulong and - // unpack them again. This efficiently gets all ints ordered into the result. - - Vector128 lo64, hi64; - lo64 = Sse2.UnpackLow(CreateScalarUnsafe(e0), CreateScalarUnsafe(e1)).AsUInt64(); // < 0, 1, ?, ? > - hi64 = Sse2.UnpackLow(CreateScalarUnsafe(e2), CreateScalarUnsafe(e3)).AsUInt64(); // < 2, 3, ?, ? > - return Sse2.UnpackLow(lo64, hi64).AsUInt32(); // < 0, 1, 2, 3 > + return Create(e0, e1, e2, e3); } return SoftwareFallback(e0, e1, e2, e3); @@ -1178,19 +908,13 @@ static Vector128 SoftwareFallback(uint e0, uint e1, uint e2, uint e3) /// The value that element 1 will be initialized to. /// On x86, this method corresponds to __m128i _mm_setr_epi64x /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector128 Create(ulong e0, ulong e1) { - if (Sse41.X64.IsSupported) - { - Vector128 result = CreateScalarUnsafe(e0); // < 0, ? > - return Sse41.X64.Insert(result, e1, 1); // < 0, 1 > - } - - if (Sse2.X64.IsSupported) + if (Sse2.X64.IsSupported || AdvSimd.Arm64.IsSupported) { - return Sse2.UnpackLow(CreateScalarUnsafe(e0), CreateScalarUnsafe(e1)); // < 0, 1 > + return Create(e0, e1); } return SoftwareFallback(e0, e1); @@ -1369,6 +1093,11 @@ public static unsafe Vector128 Create(Vector64 lower, Vector64 CreateScalar(byte value) { + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector128.Zero, 0, value); + } + if (Sse2.IsSupported) { // ConvertScalarToVector128 only deals with 32/64-bit inputs and we need to ensure all upper-bits are zeroed, so we call @@ -1392,6 +1121,11 @@ static Vector128 SoftwareFallback(byte value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe Vector128 CreateScalar(double value) { + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector128.Zero, 0, value); + } + if (Sse2.IsSupported) { return Sse2.MoveScalar(Vector128.Zero, CreateScalarUnsafe(value)); @@ -1413,6 +1147,11 @@ static Vector128 SoftwareFallback(double value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe Vector128 CreateScalar(short value) { + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector128.Zero, 0, value); + } + if (Sse2.IsSupported) { // ConvertScalarToVector128 only deals with 32/64-bit inputs and we need to ensure all upper-bits are zeroed, so we cast @@ -1436,6 +1175,11 @@ static Vector128 SoftwareFallback(short value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe Vector128 CreateScalar(int value) { + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector128.Zero, 0, value); + } + if (Sse2.IsSupported) { return Sse2.ConvertScalarToVector128Int32(value); @@ -1456,6 +1200,11 @@ static Vector128 SoftwareFallback(int value) /// A new instance with the first element initialized to and the remaining elements initialized to zero. public static unsafe Vector128 CreateScalar(long value) { + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector128.Zero, 0, value); + } + if (Sse2.X64.IsSupported) { return Sse2.X64.ConvertScalarToVector128Int64(value); @@ -1478,6 +1227,11 @@ static Vector128 SoftwareFallback(long value) [CLSCompliant(false)] public static unsafe Vector128 CreateScalar(sbyte value) { + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector128.Zero, 0, value); + } + if (Sse2.IsSupported) { // ConvertScalarToVector128 only deals with 32/64-bit inputs and we need to ensure all upper-bits are zeroed, so we cast @@ -1501,6 +1255,11 @@ static Vector128 SoftwareFallback(sbyte value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe Vector128 CreateScalar(float value) { + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector128.Zero, 0, value); + } + if (Sse.IsSupported) { return Sse.MoveScalar(Vector128.Zero, CreateScalarUnsafe(value)); @@ -1523,6 +1282,11 @@ static Vector128 SoftwareFallback(float value) [CLSCompliant(false)] public static unsafe Vector128 CreateScalar(ushort value) { + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector128.Zero, 0, value); + } + if (Sse2.IsSupported) { // ConvertScalarToVector128 only deals with 32/64-bit inputs and we need to ensure all upper-bits are zeroed, so we call @@ -1547,6 +1311,11 @@ static Vector128 SoftwareFallback(ushort value) [CLSCompliant(false)] public static unsafe Vector128 CreateScalar(uint value) { + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector128.Zero, 0, value); + } + if (Sse2.IsSupported) { return Sse2.ConvertScalarToVector128UInt32(value); @@ -1569,6 +1338,11 @@ static Vector128 SoftwareFallback(uint value) [CLSCompliant(false)] public static unsafe Vector128 CreateScalar(ulong value) { + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector128.Zero, 0, value); + } + if (Sse2.X64.IsSupported) { return Sse2.X64.ConvertScalarToVector128UInt64(value); @@ -1780,6 +1554,7 @@ public static Vector128 WithElement(this Vector128 vector, int index, T /// The vector to get the lower 64-bits from. /// The value of the lower 64-bits as a new . /// The type of () is not supported. + [Intrinsic] public static Vector64 GetLower(this Vector128 vector) where T : struct { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs index 1ca217b965c3d6..da6f16c126c26f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs @@ -59,6 +59,18 @@ public static Vector128 Zero } } + /// Gets a new with all bits set to 1. + /// The type of the current instance () is not supported. + public static Vector128 AllBitsSet + { + [Intrinsic] + get + { + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + return Vector128.Create(0xFFFFFFFF).As(); + } + } + internal unsafe string DisplayString { get diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index 2a123ab52099c3..ae4e95608b0336 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -208,19 +208,12 @@ public static Vector AsVector(this Vector256 value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m256i _mm256_set1_epi8 /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector256 Create(byte value) { - if (Avx2.IsSupported) - { - Vector128 result = Vector128.CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - return Avx2.BroadcastScalarToVector256(result); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v > - } - if (Avx.IsSupported) { - Vector128 result = Vector128.Create(value); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - return Avx.InsertVector128(result.ToVector256Unsafe(), result, 1); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -271,19 +264,12 @@ static Vector256 SoftwareFallback(byte value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m256d _mm256_set1_pd /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector256 Create(double value) { - if (Avx2.IsSupported) - { - Vector128 result = Vector128.CreateScalarUnsafe(value); // < v, ?, ?, ? > - return Avx2.BroadcastScalarToVector256(result); // < v, v, v, v > - } - if (Avx.IsSupported) { - Vector128 result = Vector128.Create(value); // < v, v, ?, ? > - return Avx.InsertVector128(result.ToVector256Unsafe(), result, 1); // < v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -306,19 +292,12 @@ static Vector256 SoftwareFallback(double value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m256i _mm256_set1_epi16 /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector256 Create(short value) { - if (Avx2.IsSupported) - { - Vector128 result = Vector128.CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - return Avx2.BroadcastScalarToVector256(result); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v > - } - if (Avx.IsSupported) { - Vector128 result = Vector128.Create(value); // < v, v, v, v, v, v, v, v, ?, ?, ?, ?, ?, ?, ?, ? > - return Avx.InsertVector128(result.ToVector256Unsafe(), result, 1); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -353,19 +332,12 @@ static Vector256 SoftwareFallback(short value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m256i _mm256_set1_epi32 /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector256 Create(int value) { - if (Avx2.IsSupported) - { - Vector128 result = Vector128.CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ? > - return Avx2.BroadcastScalarToVector256(result); // < v, v, v, v, v, v, v, v > - } - if (Avx.IsSupported) { - Vector128 result = Vector128.Create(value); // < v, v, v, v, ?, ?, ?, ? > - return Avx.InsertVector128(result.ToVector256Unsafe(), result, 1); // < v, v, v, v, v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -392,21 +364,12 @@ static Vector256 SoftwareFallback(int value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m256i _mm256_set1_epi64x /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector256 Create(long value) { - if (Sse2.X64.IsSupported) + if (Sse2.X64.IsSupported && Avx.IsSupported) { - if (Avx2.IsSupported) - { - Vector128 result = Vector128.CreateScalarUnsafe(value); // < v, ?, ?, ? > - return Avx2.BroadcastScalarToVector256(result); // < v, v, v, v > - } - else if (Avx.IsSupported) - { - Vector128 result = Vector128.Create(value); // < v, v, ?, ? > - return Avx.InsertVector128(result.ToVector256Unsafe(), result, 1); // < v, v, v, v > - } + return Create(value); } return SoftwareFallback(value); @@ -429,20 +392,13 @@ static Vector256 SoftwareFallback(long value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m256i _mm256_set1_epi8 /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector256 Create(sbyte value) { - if (Avx2.IsSupported) - { - Vector128 result = Vector128.CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - return Avx2.BroadcastScalarToVector256(result); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v > - } - if (Avx.IsSupported) { - Vector128 result = Vector128.Create(value); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - return Avx.InsertVector128(result.ToVector256Unsafe(), result, 1); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -493,19 +449,12 @@ static Vector256 SoftwareFallback(sbyte value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m256 _mm256_set1_ps /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector256 Create(float value) { - if (Avx2.IsSupported) - { - Vector128 result = Vector128.CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ? > - return Avx2.BroadcastScalarToVector256(result); // < v, v, v, v, v, v, v, v > - } - if (Avx.IsSupported) { - Vector128 result = Vector128.Create(value); // < v, v, v, v, ?, ?, ?, ? > - return Avx.InsertVector128(result.ToVector256Unsafe(), result, 1); // < v, v, v, v, v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -532,20 +481,13 @@ static Vector256 SoftwareFallback(float value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m256i _mm256_set1_epi16 /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector256 Create(ushort value) { - if (Avx2.IsSupported) - { - Vector128 result = Vector128.CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? > - return Avx2.BroadcastScalarToVector256(result); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v > - } - if (Avx.IsSupported) { - Vector128 result = Vector128.Create(value); // < v, v, v, v, v, v, v, v, ?, ?, ?, ?, ?, ?, ?, ? > - return Avx.InsertVector128(result.ToVector256Unsafe(), result, 1); // < v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -580,20 +522,13 @@ static Vector256 SoftwareFallback(ushort value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m256i _mm256_set1_epi32 /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector256 Create(uint value) { - if (Avx2.IsSupported) - { - Vector128 result = Vector128.CreateScalarUnsafe(value); // < v, ?, ?, ?, ?, ?, ?, ? > - return Avx2.BroadcastScalarToVector256(result); // < v, v, v, v, v, v, v, v > - } - if (Avx.IsSupported) { - Vector128 result = Vector128.Create(value); // < v, v, v, v, ?, ?, ?, ? > - return Avx.InsertVector128(result.ToVector256Unsafe(), result, 1); // < v, v, v, v, v, v, v, v > + return Create(value); } return SoftwareFallback(value); @@ -620,22 +555,13 @@ static Vector256 SoftwareFallback(uint value) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m256i _mm256_set1_epi64x /// A new with all elements initialized to . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector256 Create(ulong value) { - if (Sse2.X64.IsSupported) + if (Sse2.X64.IsSupported && Avx.IsSupported) { - if (Avx2.IsSupported) - { - Vector128 result = Vector128.CreateScalarUnsafe(value); // < v, ?, ?, ? > - return Avx2.BroadcastScalarToVector256(result); // < v, v, v, v > - } - else if (Avx.IsSupported) - { - Vector128 result = Vector128.Create(value); // < v, v, ?, ? > - return Avx.InsertVector128(result.ToVector256Unsafe(), result, 1); // < v, v, v, v > - } + return Create(value); } return SoftwareFallback(value); @@ -689,14 +615,12 @@ static Vector256 SoftwareFallback(ulong value) /// The value that element 31 will be initialized to. /// On x86, this method corresponds to __m256i _mm256_setr_epi8 /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector256 Create(byte e0, byte e1, byte e2, byte e3, byte e4, byte e5, byte e6, byte e7, byte e8, byte e9, byte e10, byte e11, byte e12, byte e13, byte e14, byte e15, byte e16, byte e17, byte e18, byte e19, byte e20, byte e21, byte e22, byte e23, byte e24, byte e25, byte e26, byte e27, byte e28, byte e29, byte e30, byte e31) { if (Avx.IsSupported) { - Vector128 lo128 = Vector128.Create(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15); - Vector128 hi128 = Vector128.Create(e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31); - return Create(lo128, hi128); + return Create(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31); } return SoftwareFallback(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31); @@ -750,14 +674,12 @@ static Vector256 SoftwareFallback(byte e0, byte e1, byte e2, byte e3, byte /// The value that element 3 will be initialized to. /// On x86, this method corresponds to __m256d _mm256_setr_pd /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector256 Create(double e0, double e1, double e2, double e3) { if (Avx.IsSupported) { - Vector128 lo128 = Vector128.Create(e0, e1); - Vector128 hi128 = Vector128.Create(e2, e3); - return Create(lo128, hi128); + return Create(e0, e1, e2, e3); } return SoftwareFallback(e0, e1, e2, e3); @@ -795,14 +717,12 @@ static Vector256 SoftwareFallback(double e0, double e1, double e2, doubl /// The value that element 15 will be initialized to. /// On x86, this method corresponds to __m256i _mm256_setr_epi16 /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector256 Create(short e0, short e1, short e2, short e3, short e4, short e5, short e6, short e7, short e8, short e9, short e10, short e11, short e12, short e13, short e14, short e15) { if (Avx.IsSupported) { - Vector128 lo128 = Vector128.Create(e0, e1, e2, e3, e4, e5, e6, e7); - Vector128 hi128 = Vector128.Create(e8, e9, e10, e11, e12, e13, e14, e15); - return Create(lo128, hi128); + return Create(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15); } return SoftwareFallback(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15); @@ -844,14 +764,12 @@ static Vector256 SoftwareFallback(short e0, short e1, short e2, short e3, /// The value that element 7 will be initialized to. /// On x86, this method corresponds to __m256i _mm256_setr_epi32 /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector256 Create(int e0, int e1, int e2, int e3, int e4, int e5, int e6, int e7) { if (Avx.IsSupported) { - Vector128 lo128 = Vector128.Create(e0, e1, e2, e3); - Vector128 hi128 = Vector128.Create(e4, e5, e6, e7); - return Create(lo128, hi128); + return Create(e0, e1, e2, e3, e4, e5, e6, e7); } return SoftwareFallback(e0, e1, e2, e3, e4, e5, e6, e7); @@ -881,14 +799,12 @@ static Vector256 SoftwareFallback(int e0, int e1, int e2, int e3, int e4, i /// The value that element 3 will be initialized to. /// On x86, this method corresponds to __m256i _mm256_setr_epi64x /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector256 Create(long e0, long e1, long e2, long e3) { if (Sse2.X64.IsSupported && Avx.IsSupported) { - Vector128 lo128 = Vector128.Create(e0, e1); - Vector128 hi128 = Vector128.Create(e2, e3); - return Create(lo128, hi128); + return Create(e0, e1, e2, e3); } return SoftwareFallback(e0, e1, e2, e3); @@ -942,15 +858,13 @@ static Vector256 SoftwareFallback(long e0, long e1, long e2, long e3) /// The value that element 31 will be initialized to. /// On x86, this method corresponds to __m256i _mm256_setr_epi8 /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector256 Create(sbyte e0, sbyte e1, sbyte e2, sbyte e3, sbyte e4, sbyte e5, sbyte e6, sbyte e7, sbyte e8, sbyte e9, sbyte e10, sbyte e11, sbyte e12, sbyte e13, sbyte e14, sbyte e15, sbyte e16, sbyte e17, sbyte e18, sbyte e19, sbyte e20, sbyte e21, sbyte e22, sbyte e23, sbyte e24, sbyte e25, sbyte e26, sbyte e27, sbyte e28, sbyte e29, sbyte e30, sbyte e31) { if (Avx.IsSupported) { - Vector128 lo128 = Vector128.Create(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15); - Vector128 hi128 = Vector128.Create(e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31); - return Create(lo128, hi128); + return Create(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31); } return SoftwareFallback(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31); @@ -1008,14 +922,12 @@ static Vector256 SoftwareFallback(sbyte e0, sbyte e1, sbyte e2, sbyte e3, /// The value that element 7 will be initialized to. /// On x86, this method corresponds to __m256 _mm256_setr_ps /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] public static unsafe Vector256 Create(float e0, float e1, float e2, float e3, float e4, float e5, float e6, float e7) { if (Avx.IsSupported) { - Vector128 lo128 = Vector128.Create(e0, e1, e2, e3); - Vector128 hi128 = Vector128.Create(e4, e5, e6, e7); - return Create(lo128, hi128); + return Create(e0, e1, e2, e3, e4, e5, e6, e7); } return SoftwareFallback(e0, e1, e2, e3, e4, e5, e6, e7); @@ -1057,15 +969,13 @@ static Vector256 SoftwareFallback(float e0, float e1, float e2, float e3, /// The value that element 15 will be initialized to. /// On x86, this method corresponds to __m256i _mm256_setr_epi16 /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector256 Create(ushort e0, ushort e1, ushort e2, ushort e3, ushort e4, ushort e5, ushort e6, ushort e7, ushort e8, ushort e9, ushort e10, ushort e11, ushort e12, ushort e13, ushort e14, ushort e15) { if (Avx.IsSupported) { - Vector128 lo128 = Vector128.Create(e0, e1, e2, e3, e4, e5, e6, e7); - Vector128 hi128 = Vector128.Create(e8, e9, e10, e11, e12, e13, e14, e15); - return Create(lo128, hi128); + return Create(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15); } return SoftwareFallback(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15); @@ -1107,15 +1017,13 @@ static Vector256 SoftwareFallback(ushort e0, ushort e1, ushort e2, ushor /// The value that element 7 will be initialized to. /// On x86, this method corresponds to __m256i _mm256_setr_epi32 /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector256 Create(uint e0, uint e1, uint e2, uint e3, uint e4, uint e5, uint e6, uint e7) { if (Avx.IsSupported) { - Vector128 lo128 = Vector128.Create(e0, e1, e2, e3); - Vector128 hi128 = Vector128.Create(e4, e5, e6, e7); - return Create(lo128, hi128); + return Create(e0, e1, e2, e3, e4, e5, e6, e7); } return SoftwareFallback(e0, e1, e2, e3, e4, e5, e6, e7); @@ -1145,15 +1053,13 @@ static Vector256 SoftwareFallback(uint e0, uint e1, uint e2, uint e3, uint /// The value that element 3 will be initialized to. /// On x86, this method corresponds to __m256i _mm256_setr_epi64x /// A new with each element initialized to corresponding specified value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector256 Create(ulong e0, ulong e1, ulong e2, ulong e3) { if (Sse2.X64.IsSupported && Avx.IsSupported) { - Vector128 lo128 = Vector128.Create(e0, e1); - Vector128 hi128 = Vector128.Create(e2, e3); - return Create(lo128, hi128); + return Create(e0, e1, e2, e3); } return SoftwareFallback(e0, e1, e2, e3); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs index e1c61e44df23c8..c92ffea3ab2652 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs @@ -61,6 +61,20 @@ public static Vector256 Zero } } + + /// Gets a new with all bits set to 1. + /// The type of the current instance () is not supported. + public static Vector256 AllBitsSet + { + [Intrinsic] + get + { + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + return Vector256.Create(0xFFFFFFFF).As(); + } + } + + internal unsafe string DisplayString { get diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs index b1f1645858dc2b..d370a622ae0018 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs @@ -2,8 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Runtime.CompilerServices; using Internal.Runtime.CompilerServices; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics.Arm; namespace System.Runtime.Intrinsics { @@ -156,148 +157,258 @@ public static Vector64 AsUInt64(this Vector64 vector) /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m64 _mm_set1_pi8 /// A new with all elements initialized to . + [Intrinsic] public static unsafe Vector64 Create(byte value) { - byte* pResult = stackalloc byte[8] + if (AdvSimd.IsSupported) { - value, - value, - value, - value, - value, - value, - value, - value, - }; + return Create(value); + } - return Unsafe.AsRef>(pResult); + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(byte value) + { + byte* pResult = stackalloc byte[8] + { + value, + value, + value, + value, + value, + value, + value, + value, + }; + + return Unsafe.AsRef>(pResult); + } } /// Creates a new instance with all elements initialized to the specified value. /// The value that all elements will be initialized to. /// A new with all elements initialized to . + [Intrinsic] public static unsafe Vector64 Create(double value) { - return Unsafe.As>(ref value); + if (AdvSimd.IsSupported) + { + return Create(value); + } + + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(double value) + { + return Unsafe.As>(ref value); + } } /// Creates a new instance with all elements initialized to the specified value. /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m64 _mm_set1_pi16 /// A new with all elements initialized to . + [Intrinsic] public static unsafe Vector64 Create(short value) { - short* pResult = stackalloc short[4] + if (AdvSimd.IsSupported) { - value, - value, - value, - value, - }; + return Create(value); + } - return Unsafe.AsRef>(pResult); + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(short value) + { + short* pResult = stackalloc short[4] + { + value, + value, + value, + value, + }; + + return Unsafe.AsRef>(pResult); + } } /// Creates a new instance with all elements initialized to the specified value. /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m64 _mm_set1_pi32 /// A new with all elements initialized to . + [Intrinsic] public static unsafe Vector64 Create(int value) { - int* pResult = stackalloc int[2] + if (AdvSimd.IsSupported) { - value, - value, - }; + return Create(value); + } - return Unsafe.AsRef>(pResult); + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(int value) + { + int* pResult = stackalloc int[2] + { + value, + value, + }; + + return Unsafe.AsRef>(pResult); + } } /// Creates a new instance with all elements initialized to the specified value. /// The value that all elements will be initialized to. /// A new with all elements initialized to . + [Intrinsic] public static unsafe Vector64 Create(long value) { - return Unsafe.As>(ref value); + if (AdvSimd.Arm64.IsSupported) + { + return Create(value); + } + + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(long value) + { + return Unsafe.As>(ref value); + } } /// Creates a new instance with all elements initialized to the specified value. /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m64 _mm_set1_pi8 /// A new with all elements initialized to . + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector64 Create(sbyte value) { - sbyte* pResult = stackalloc sbyte[8] + if (AdvSimd.IsSupported) { - value, - value, - value, - value, - value, - value, - value, - value, - }; + return Create(value); + } - return Unsafe.AsRef>(pResult); + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(sbyte value) + { + sbyte* pResult = stackalloc sbyte[8] + { + value, + value, + value, + value, + value, + value, + value, + value, + }; + + return Unsafe.AsRef>(pResult); + } } /// Creates a new instance with all elements initialized to the specified value. /// The value that all elements will be initialized to. /// A new with all elements initialized to . + [Intrinsic] public static unsafe Vector64 Create(float value) { - float* pResult = stackalloc float[2] + if (AdvSimd.IsSupported) { - value, - value, - }; + return Create(value); + } - return Unsafe.AsRef>(pResult); + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(float value) + { + float* pResult = stackalloc float[2] + { + value, + value, + }; + + return Unsafe.AsRef>(pResult); + } } /// Creates a new instance with all elements initialized to the specified value. /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m64 _mm_set1_pi16 /// A new with all elements initialized to . + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector64 Create(ushort value) { - ushort* pResult = stackalloc ushort[4] + if (AdvSimd.IsSupported) { - value, - value, - value, - value, - }; + return Create(value); + } - return Unsafe.AsRef>(pResult); + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(ushort value) + { + ushort* pResult = stackalloc ushort[4] + { + value, + value, + value, + value, + }; + + return Unsafe.AsRef>(pResult); + } } /// Creates a new instance with all elements initialized to the specified value. /// The value that all elements will be initialized to. /// On x86, this method corresponds to __m64 _mm_set1_pi32 /// A new with all elements initialized to . + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector64 Create(uint value) { - uint* pResult = stackalloc uint[2] + if (AdvSimd.IsSupported) { - value, - value, - }; + return Create(value); + } - return Unsafe.AsRef>(pResult); + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(uint value) + { + uint* pResult = stackalloc uint[2] + { + value, + value, + }; + + return Unsafe.AsRef>(pResult); + } } /// Creates a new instance with all elements initialized to the specified value. /// The value that all elements will be initialized to. /// A new with all elements initialized to . + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector64 Create(ulong value) { - return Unsafe.As>(ref value); + if (AdvSimd.Arm64.IsSupported) + { + return Create(value); + } + + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(ulong value) + { + return Unsafe.As>(ref value); + } } /// Creates a new instance with each element initialized to the corresponding specified value. @@ -311,21 +422,32 @@ public static unsafe Vector64 Create(ulong value) /// The value that element 7 will be initialized to. /// On x86, this method corresponds to __m64 _mm_setr_pi8 /// A new with each element initialized to corresponding specified value. + [Intrinsic] public static unsafe Vector64 Create(byte e0, byte e1, byte e2, byte e3, byte e4, byte e5, byte e6, byte e7) { - byte* pResult = stackalloc byte[8] + if (AdvSimd.IsSupported) { - e0, - e1, - e2, - e3, - e4, - e5, - e6, - e7, - }; + return Create(e0, e1, e2, e3, e4, e5, e6, e7); + } - return Unsafe.AsRef>(pResult); + return SoftwareFallback(e0, e1, e2, e3, e4, e5, e6, e7); + + static Vector64 SoftwareFallback(byte e0, byte e1, byte e2, byte e3, byte e4, byte e5, byte e6, byte e7) + { + byte* pResult = stackalloc byte[8] + { + e0, + e1, + e2, + e3, + e4, + e5, + e6, + e7, + }; + + return Unsafe.AsRef>(pResult); + } } /// Creates a new instance with each element initialized to the corresponding specified value. @@ -335,17 +457,28 @@ public static unsafe Vector64 Create(byte e0, byte e1, byte e2, byte e3, b /// The value that element 3 will be initialized to. /// On x86, this method corresponds to __m64 _mm_setr_pi16 /// A new with each element initialized to corresponding specified value. + [Intrinsic] public static unsafe Vector64 Create(short e0, short e1, short e2, short e3) { - short* pResult = stackalloc short[4] + if (AdvSimd.IsSupported) { - e0, - e1, - e2, - e3, - }; + return Create(e0, e1, e2, e3); + } - return Unsafe.AsRef>(pResult); + return SoftwareFallback(e0, e1, e2, e3); + + static Vector64 SoftwareFallback(short e0, short e1, short e2, short e3) + { + short* pResult = stackalloc short[4] + { + e0, + e1, + e2, + e3, + }; + + return Unsafe.AsRef>(pResult); + } } /// Creates a new instance with each element initialized to the corresponding specified value. @@ -353,15 +486,26 @@ public static unsafe Vector64 Create(short e0, short e1, short e2, short /// The value that element 1 will be initialized to. /// On x86, this method corresponds to __m64 _mm_setr_pi32 /// A new with each element initialized to corresponding specified value. + [Intrinsic] public static unsafe Vector64 Create(int e0, int e1) { - int* pResult = stackalloc int[2] + if (AdvSimd.IsSupported) + { + return Create(e0, e1); + } + + return SoftwareFallback(e0, e1); + + static Vector64 SoftwareFallback(int e0, int e1) { - e0, - e1, - }; + int* pResult = stackalloc int[2] + { + e0, + e1, + }; - return Unsafe.AsRef>(pResult); + return Unsafe.AsRef>(pResult); + } } /// Creates a new instance with each element initialized to the corresponding specified value. @@ -375,37 +519,59 @@ public static unsafe Vector64 Create(int e0, int e1) /// The value that element 7 will be initialized to. /// On x86, this method corresponds to __m64 _mm_setr_pi8 /// A new with each element initialized to corresponding specified value. + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector64 Create(sbyte e0, sbyte e1, sbyte e2, sbyte e3, sbyte e4, sbyte e5, sbyte e6, sbyte e7) { - sbyte* pResult = stackalloc sbyte[8] + if (AdvSimd.IsSupported) { - e0, - e1, - e2, - e3, - e4, - e5, - e6, - e7, - }; + return Create(e0, e1, e2, e3, e4, e5, e6, e7); + } - return Unsafe.AsRef>(pResult); + return SoftwareFallback(e0, e1, e2, e3, e4, e5, e6, e7); + + static Vector64 SoftwareFallback(sbyte e0, sbyte e1, sbyte e2, sbyte e3, sbyte e4, sbyte e5, sbyte e6, sbyte e7) + { + sbyte* pResult = stackalloc sbyte[8] + { + e0, + e1, + e2, + e3, + e4, + e5, + e6, + e7, + }; + + return Unsafe.AsRef>(pResult); + } } /// Creates a new instance with each element initialized to the corresponding specified value. /// The value that element 0 will be initialized to. /// The value that element 1 will be initialized to. /// A new with each element initialized to corresponding specified value. + [Intrinsic] public static unsafe Vector64 Create(float e0, float e1) { - float* pResult = stackalloc float[2] + if (AdvSimd.IsSupported) { - e0, - e1, - }; + return Create(e0, e1); + } - return Unsafe.AsRef>(pResult); + return SoftwareFallback(e0, e1); + + static Vector64 SoftwareFallback(float e0, float e1) + { + float* pResult = stackalloc float[2] + { + e0, + e1, + }; + + return Unsafe.AsRef>(pResult); + } } /// Creates a new instance with each element initialized to the corresponding specified value. @@ -415,18 +581,29 @@ public static unsafe Vector64 Create(float e0, float e1) /// The value that element 3 will be initialized to. /// On x86, this method corresponds to __m64 _mm_setr_pi16 /// A new with each element initialized to corresponding specified value. + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector64 Create(ushort e0, ushort e1, ushort e2, ushort e3) { - ushort* pResult = stackalloc ushort[4] + if (AdvSimd.IsSupported) { - e0, - e1, - e2, - e3, - }; + return Create(e0, e1, e2, e3); + } - return Unsafe.AsRef>(pResult); + return SoftwareFallback(e0, e1, e2, e3); + + static Vector64 SoftwareFallback(ushort e0, ushort e1, ushort e2, ushort e3) + { + ushort* pResult = stackalloc ushort[4] + { + e0, + e1, + e2, + e3, + }; + + return Unsafe.AsRef>(pResult); + } } /// Creates a new instance with each element initialized to the corresponding specified value. @@ -434,16 +611,27 @@ public static unsafe Vector64 Create(ushort e0, ushort e1, ushort e2, us /// The value that element 1 will be initialized to. /// On x86, this method corresponds to __m64 _mm_setr_pi32 /// A new with each element initialized to corresponding specified value. + [Intrinsic] [CLSCompliant(false)] public static unsafe Vector64 Create(uint e0, uint e1) { - uint* pResult = stackalloc uint[2] + if (AdvSimd.IsSupported) { - e0, - e1, - }; + return Create(e0, e1); + } - return Unsafe.AsRef>(pResult); + return SoftwareFallback(e0, e1); + + static Vector64 SoftwareFallback(uint e0, uint e1) + { + uint* pResult = stackalloc uint[2] + { + e0, + e1, + }; + + return Unsafe.AsRef>(pResult); + } } /// Creates a new instance with the first element initialized to the specified value and the remaining elements initialized to zero. @@ -451,9 +639,19 @@ public static unsafe Vector64 Create(uint e0, uint e1) /// A new instance with the first element initialized to and the remaining elements initialized to zero. public static unsafe Vector64 CreateScalar(byte value) { - var result = Vector64.Zero; - Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), value); - return result; + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector64.Zero, 0, value); + } + + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(byte value) + { + var result = Vector64.Zero; + Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), value); + return result; + } } /// Creates a new instance with the first element initialized to the specified value and the remaining elements initialized to zero. @@ -461,9 +659,19 @@ public static unsafe Vector64 CreateScalar(byte value) /// A new instance with the first element initialized to and the remaining elements initialized to zero. public static unsafe Vector64 CreateScalar(short value) { - var result = Vector64.Zero; - Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), value); - return result; + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector64.Zero, 0, value); + } + + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(short value) + { + var result = Vector64.Zero; + Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), value); + return result; + } } /// Creates a new instance with the first element initialized to the specified value and the remaining elements initialized to zero. @@ -471,9 +679,19 @@ public static unsafe Vector64 CreateScalar(short value) /// A new instance with the first element initialized to and the remaining elements initialized to zero. public static unsafe Vector64 CreateScalar(int value) { - var result = Vector64.Zero; - Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), value); - return result; + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector64.Zero, 0, value); + } + + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(int value) + { + var result = Vector64.Zero; + Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), value); + return result; + } } /// Creates a new instance with the first element initialized to the specified value and the remaining elements initialized to zero. @@ -482,9 +700,19 @@ public static unsafe Vector64 CreateScalar(int value) [CLSCompliant(false)] public static unsafe Vector64 CreateScalar(sbyte value) { - var result = Vector64.Zero; - Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), value); - return result; + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector64.Zero, 0, value); + } + + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(sbyte value) + { + var result = Vector64.Zero; + Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), value); + return result; + } } /// Creates a new instance with the first element initialized to the specified value and the remaining elements initialized to zero. @@ -492,9 +720,19 @@ public static unsafe Vector64 CreateScalar(sbyte value) /// A new instance with the first element initialized to and the remaining elements initialized to zero. public static unsafe Vector64 CreateScalar(float value) { - var result = Vector64.Zero; - Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), value); - return result; + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector64.Zero, 0, value); + } + + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(float value) + { + var result = Vector64.Zero; + Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), value); + return result; + } } /// Creates a new instance with the first element initialized to the specified value and the remaining elements initialized to zero. @@ -503,9 +741,19 @@ public static unsafe Vector64 CreateScalar(float value) [CLSCompliant(false)] public static unsafe Vector64 CreateScalar(ushort value) { - var result = Vector64.Zero; - Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), value); - return result; + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector64.Zero, 0, value); + } + + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(ushort value) + { + var result = Vector64.Zero; + Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), value); + return result; + } } /// Creates a new instance with the first element initialized to the specified value and the remaining elements initialized to zero. @@ -514,14 +762,25 @@ public static unsafe Vector64 CreateScalar(ushort value) [CLSCompliant(false)] public static unsafe Vector64 CreateScalar(uint value) { - var result = Vector64.Zero; - Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), value); - return result; + if (AdvSimd.IsSupported) + { + return AdvSimd.Insert(Vector64.Zero, 0, value); + } + + return SoftwareFallback(value); + + static Vector64 SoftwareFallback(uint value) + { + var result = Vector64.Zero; + Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), value); + return result; + } } /// Creates a new instance with the first element initialized to the specified value and the remaining elements left uninitialized. /// The value that element 0 will be initialized to. /// A new instance with the first element initialized to and the remaining elements left uninitialized. + [Intrinsic] public static unsafe Vector64 CreateScalarUnsafe(byte value) { // This relies on us stripping the "init" flag from the ".locals" @@ -535,6 +794,7 @@ public static unsafe Vector64 CreateScalarUnsafe(byte value) /// Creates a new instance with the first element initialized to the specified value and the remaining elements left uninitialized. /// The value that element 0 will be initialized to. /// A new instance with the first element initialized to and the remaining elements left uninitialized. + [Intrinsic] public static unsafe Vector64 CreateScalarUnsafe(short value) { // This relies on us stripping the "init" flag from the ".locals" @@ -548,6 +808,7 @@ public static unsafe Vector64 CreateScalarUnsafe(short value) /// Creates a new instance with the first element initialized to the specified value and the remaining elements left uninitialized. /// The value that element 0 will be initialized to. /// A new instance with the first element initialized to and the remaining elements left uninitialized. + [Intrinsic] public static unsafe Vector64 CreateScalarUnsafe(int value) { // This relies on us stripping the "init" flag from the ".locals" @@ -562,6 +823,7 @@ public static unsafe Vector64 CreateScalarUnsafe(int value) /// The value that element 0 will be initialized to. /// A new instance with the first element initialized to and the remaining elements left uninitialized. [CLSCompliant(false)] + [Intrinsic] public static unsafe Vector64 CreateScalarUnsafe(sbyte value) { // This relies on us stripping the "init" flag from the ".locals" @@ -575,6 +837,7 @@ public static unsafe Vector64 CreateScalarUnsafe(sbyte value) /// Creates a new instance with the first element initialized to the specified value and the remaining elements left uninitialized. /// The value that element 0 will be initialized to. /// A new instance with the first element initialized to and the remaining elements left uninitialized. + [Intrinsic] public static unsafe Vector64 CreateScalarUnsafe(float value) { // This relies on us stripping the "init" flag from the ".locals" @@ -589,6 +852,7 @@ public static unsafe Vector64 CreateScalarUnsafe(float value) /// The value that element 0 will be initialized to. /// A new instance with the first element initialized to and the remaining elements left uninitialized. [CLSCompliant(false)] + [Intrinsic] public static unsafe Vector64 CreateScalarUnsafe(ushort value) { // This relies on us stripping the "init" flag from the ".locals" @@ -603,6 +867,7 @@ public static unsafe Vector64 CreateScalarUnsafe(ushort value) /// The value that element 0 will be initialized to. /// A new instance with the first element initialized to and the remaining elements left uninitialized. [CLSCompliant(false)] + [Intrinsic] public static unsafe Vector64 CreateScalarUnsafe(uint value) { // This relies on us stripping the "init" flag from the ".locals" @@ -620,6 +885,7 @@ public static unsafe Vector64 CreateScalarUnsafe(uint value) /// The value of the element at . /// The type of () is not supported. /// was less than zero or greater than the number of elements. + [Intrinsic] public static T GetElement(this Vector64 vector, int index) where T : struct { @@ -663,6 +929,7 @@ public static Vector64 WithElement(this Vector64 vector, int index, T v /// The vector to get the first element from. /// A scalar containing the value of the first element. /// The type of () is not supported. + [Intrinsic] public static T ToScalar(this Vector64 vector) where T : struct { @@ -675,6 +942,7 @@ public static T ToScalar(this Vector64 vector) /// The vector to extend. /// A new with the lower 64-bits set to the value of and the upper 64-bits initialized to zero. /// The type of () is not supported. + [Intrinsic] public static Vector128 ToVector128(this Vector64 vector) where T : struct { @@ -690,6 +958,7 @@ public static Vector128 ToVector128(this Vector64 vector) /// The vector to extend. /// A new with the lower 64-bits set to the value of and the upper 64-bits left uninitialized. /// The type of () is not supported. + [Intrinsic] public static unsafe Vector128 ToVector128Unsafe(this Vector64 vector) where T : struct { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs index 2562f84930271b..c5c4f51ea688dc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs @@ -26,6 +26,7 @@ namespace System.Runtime.Intrinsics /// The type of the current instance () is not supported. public static int Count { + [Intrinsic] get { ThrowHelper.ThrowForUnsupportedVectorBaseType(); @@ -37,6 +38,7 @@ public static int Count /// The type of the current instance () is not supported. public static Vector64 Zero { + [Intrinsic] get { ThrowHelper.ThrowForUnsupportedVectorBaseType(); @@ -44,6 +46,20 @@ public static Vector64 Zero } } + + /// Gets a new with all bits set to 1. + /// The type of the current instance () is not supported. + public static Vector64 AllBitsSet + { + [Intrinsic] + get + { + ThrowHelper.ThrowForUnsupportedVectorBaseType(); + return Vector64.Create(0xFFFFFFFF).As(); + } + } + + internal unsafe string DisplayString { get diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse.PlatformNotSupported.cs index 23532b452978fc..f3a4201f26667b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse.PlatformNotSupported.cs @@ -96,7 +96,7 @@ internal X64() { } /// /// __m128 _mm_cmpgt_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(6) + /// CMPPS xmm, xmm/m128, imm8(1) with swapped operands /// public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } @@ -114,13 +114,13 @@ internal X64() { } /// /// __m128 _mm_cmpgt_ss (__m128 a, __m128 b) - /// CMPSS xmm, xmm/m32, imm8(6) + /// CMPSS xmm, xmm/m32, imm8(1) with swapped operands /// public static Vector128 CompareScalarGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128 _mm_cmpge_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(5) + /// CMPPS xmm, xmm/m128, imm8(2) with swapped operands /// public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } @@ -138,7 +138,7 @@ internal X64() { } /// /// __m128 _mm_cmpge_ss (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m32, imm8(5) + /// CMPPS xmm, xmm/m32, imm8(2) with swapped operands /// public static Vector128 CompareScalarGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } @@ -216,25 +216,25 @@ internal X64() { } /// /// __m128 _mm_cmpngt_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(2) + /// CMPPS xmm, xmm/m128, imm8(5) with swapped operands /// public static Vector128 CompareNotGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128 _mm_cmpngt_ss (__m128 a, __m128 b) - /// CMPSS xmm, xmm/m32, imm8(2) + /// CMPSS xmm, xmm/m32, imm8(5) with swapped operands /// public static Vector128 CompareScalarNotGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128 _mm_cmpnge_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(1) + /// CMPPS xmm, xmm/m128, imm8(6) with swapped operands /// public static Vector128 CompareNotGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128 _mm_cmpnge_ss (__m128 a, __m128 b) - /// CMPSS xmm, xmm/m32, imm8(1) + /// CMPSS xmm, xmm/m32, imm8(6) with swapped operands /// public static Vector128 CompareScalarNotGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse.cs index f5cf132e4bca88..b9e05621dae8b1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse.cs @@ -95,7 +95,7 @@ internal X64() { } /// /// __m128 _mm_cmpgt_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(6) + /// CMPPS xmm, xmm/m128, imm8(1) with swapped operands /// public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); @@ -113,13 +113,13 @@ internal X64() { } /// /// __m128 _mm_cmpgt_ss (__m128 a, __m128 b) - /// CMPSS xmm, xmm/m32, imm8(6) + /// CMPSS xmm, xmm/m32, imm8(1) with swapped operands /// public static Vector128 CompareScalarGreaterThan(Vector128 left, Vector128 right) => CompareScalarGreaterThan(left, right); /// /// __m128 _mm_cmpge_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(5) + /// CMPPS xmm, xmm/m128, imm8(2) with swapped operands /// public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); @@ -137,7 +137,7 @@ internal X64() { } /// /// __m128 _mm_cmpge_ss (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m32, imm8(5) + /// CMPPS xmm, xmm/m32, imm8(2) with swapped operands /// public static Vector128 CompareScalarGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareScalarGreaterThanOrEqual(left, right); @@ -215,25 +215,25 @@ internal X64() { } /// /// __m128 _mm_cmpngt_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(2) + /// CMPPS xmm, xmm/m128, imm8(5) with swapped operands /// public static Vector128 CompareNotGreaterThan(Vector128 left, Vector128 right) => CompareNotGreaterThan(left, right); /// /// __m128 _mm_cmpngt_ss (__m128 a, __m128 b) - /// CMPSS xmm, xmm/m32, imm8(2) + /// CMPSS xmm, xmm/m32, imm8(5) with swapped operands /// public static Vector128 CompareScalarNotGreaterThan(Vector128 left, Vector128 right) => CompareScalarNotGreaterThan(left, right); /// /// __m128 _mm_cmpnge_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(1) + /// CMPPS xmm, xmm/m128, imm8(6) with swapped operands /// public static Vector128 CompareNotGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareNotGreaterThanOrEqual(left, right); /// /// __m128 _mm_cmpnge_ss (__m128 a, __m128 b) - /// CMPSS xmm, xmm/m32, imm8(1) + /// CMPSS xmm, xmm/m32, imm8(6) with swapped operands /// public static Vector128 CompareScalarNotGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareScalarNotGreaterThanOrEqual(left, right); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse2.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse2.PlatformNotSupported.cs index d5ca19a2c21463..93e0fa38ad3356 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse2.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse2.PlatformNotSupported.cs @@ -333,7 +333,7 @@ internal X64() { } public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128d _mm_cmpgt_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(6) + /// CMPPD xmm, xmm/m128, imm8(1) with swapped operands /// public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } @@ -351,13 +351,13 @@ internal X64() { } /// /// __m128d _mm_cmpgt_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(6) + /// CMPSD xmm, xmm/m64, imm8(1) with swapped operands /// public static Vector128 CompareScalarGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128d _mm_cmpge_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(5) + /// CMPPD xmm, xmm/m128, imm8(2) with swapped operands /// public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } @@ -375,7 +375,7 @@ internal X64() { } /// /// __m128d _mm_cmpge_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(5) + /// CMPSD xmm, xmm/m64, imm8(2) with swapped operands /// public static Vector128 CompareScalarGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } @@ -468,25 +468,25 @@ internal X64() { } /// /// __m128d _mm_cmpngt_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(2) + /// CMPPD xmm, xmm/m128, imm8(5) with swapped operands /// public static Vector128 CompareNotGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128d _mm_cmpngt_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(2) + /// CMPSD xmm, xmm/m64, imm8(5) with swapped operands /// public static Vector128 CompareScalarNotGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128d _mm_cmpnge_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(1) + /// CMPPD xmm, xmm/m128, imm8(6) with swapped operands /// public static Vector128 CompareNotGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128d _mm_cmpnge_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(1) + /// CMPSD xmm, xmm/m64, imm8(6) with swapped operands /// public static Vector128 CompareScalarNotGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse2.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse2.cs index d4cf8a1ea2fcd1..343ca50d850815 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/Sse2.cs @@ -333,7 +333,7 @@ internal X64() { } public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); /// /// __m128d _mm_cmpgt_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(6) + /// CMPPD xmm, xmm/m128, imm8(1) with swapped operands /// public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); @@ -351,13 +351,13 @@ internal X64() { } /// /// __m128d _mm_cmpgt_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(6) + /// CMPSD xmm, xmm/m64, imm8(1) with swapped operands /// public static Vector128 CompareScalarGreaterThan(Vector128 left, Vector128 right) => CompareScalarGreaterThan(left, right); /// /// __m128d _mm_cmpge_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(5) + /// CMPPD xmm, xmm/m128, imm8(2) with swapped operands /// public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); @@ -375,7 +375,7 @@ internal X64() { } /// /// __m128d _mm_cmpge_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(5) + /// CMPSD xmm, xmm/m64, imm8(2) with swapped operands /// public static Vector128 CompareScalarGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareScalarGreaterThanOrEqual(left, right); @@ -468,25 +468,25 @@ internal X64() { } /// /// __m128d _mm_cmpngt_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(2) + /// CMPPD xmm, xmm/m128, imm8(5) with swapped operands /// public static Vector128 CompareNotGreaterThan(Vector128 left, Vector128 right) => CompareNotGreaterThan(left, right); /// /// __m128d _mm_cmpngt_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(2) + /// CMPSD xmm, xmm/m64, imm8(5) with swapped operands /// public static Vector128 CompareScalarNotGreaterThan(Vector128 left, Vector128 right) => CompareScalarNotGreaterThan(left, right); /// /// __m128d _mm_cmpnge_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(1) + /// CMPPD xmm, xmm/m128, imm8(6) with swapped operands /// public static Vector128 CompareNotGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareNotGreaterThanOrEqual(left, right); /// /// __m128d _mm_cmpnge_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(1) + /// CMPSD xmm, xmm/m64, imm8(6) with swapped operands /// public static Vector128 CompareScalarNotGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareScalarNotGreaterThanOrEqual(left, right); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs new file mode 100644 index 00000000000000..39ba429010cf90 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; + +namespace System.Runtime.Intrinsics.X86 +{ + /// + /// This class provides access to the x86 base hardware instructions via intrinsics + /// + internal static class X86Base + { + public static bool IsSupported { [Intrinsic] get => false; } + + internal static class X64 + { + public static bool IsSupported { [Intrinsic] get => false; } + + /// + /// unsigned char _BitScanForward64 (unsigned __int32* index, unsigned __int64 a) + /// BSF reg reg/m64 + /// The above native signature does not directly correspond to the managed signature. + /// + /// + /// This method is to remain internal. + /// Its functionality is exposed in the public class. + /// + internal static ulong BitScanForward(ulong value) { throw new PlatformNotSupportedException(); } + + /// + /// unsigned char _BitScanReverse64 (unsigned __int32* index, unsigned __int64 a) + /// BSR reg reg/m64 + /// The above native signature does not directly correspond to the managed signature. + /// + /// + /// This method is to remain internal. + /// Its functionality is exposed in the public class. + /// + internal static ulong BitScanReverse(ulong value) { throw new PlatformNotSupportedException(); } + } + + /// + /// unsigned char _BitScanForward (unsigned __int32* index, unsigned __int32 a) + /// BSF reg reg/m32 + /// The above native signature does not directly correspond to the managed signature. + /// + /// + /// This method is to remain internal. + /// Its functionality is exposed in the public class. + /// + internal static uint BitScanForward(uint value) { throw new PlatformNotSupportedException(); } + + /// + /// unsigned char _BitScanReverse (unsigned __int32* index, unsigned __int32 a) + /// BSR reg reg/m32 + /// The above native signature does not directly correspond to the managed signature. + /// + /// + /// This method is to remain internal. + /// Its functionality is exposed in the public class. + /// + internal static uint BitScanReverse(uint value) { throw new PlatformNotSupportedException(); } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs new file mode 100644 index 00000000000000..af2f5d3540addb --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs @@ -0,0 +1,67 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.CompilerServices; + +namespace System.Runtime.Intrinsics.X86 +{ + /// + /// This class provides access to the x86 base hardware instructions via intrinsics + /// + [Intrinsic] + internal static class X86Base + { + public static bool IsSupported { get => IsSupported; } + + [Intrinsic] + internal static class X64 + { + public static bool IsSupported { get => IsSupported; } + + /// + /// unsigned char _BitScanForward64 (unsigned __int32* index, unsigned __int64 a) + /// BSF reg reg/m64 + /// The above native signature does not directly correspond to the managed signature. + /// + /// + /// This method is to remain internal. + /// Its functionality is exposed in the public class. + /// + internal static ulong BitScanForward(ulong value) => BitScanForward(value); + + /// + /// unsigned char _BitScanReverse64 (unsigned __int32* index, unsigned __int64 a) + /// BSR reg reg/m64 + /// The above native signature does not directly correspond to the managed signature. + /// + /// + /// This method is to remain internal. + /// Its functionality is exposed in the public class. + /// + internal static ulong BitScanReverse(ulong value) => BitScanReverse(value); + } + + /// + /// unsigned char _BitScanForward (unsigned __int32* index, unsigned __int32 a) + /// BSF reg reg/m32 + /// The above native signature does not directly correspond to the managed signature. + /// + /// + /// This method is to remain internal. + /// Its functionality is exposed in the public class. + /// + internal static uint BitScanForward(uint value) => BitScanForward(value); + + /// + /// unsigned char _BitScanReverse (unsigned __int32* index, unsigned __int32 a) + /// BSR reg reg/m32 + /// The above native signature does not directly correspond to the managed signature. + /// + /// + /// This method is to remain internal. + /// Its functionality is exposed in the public class. + /// + internal static uint BitScanReverse(uint value) => BitScanReverse(value); + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs index 3795a5b4515770..80d7c00ea8d546 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.cs @@ -14,6 +14,7 @@ namespace System.Runtime.Loader { public partial class AssemblyLoadContext { + // Keep in sync with MonoManagedAssemblyLoadContextInternalState in object-internals.h private enum InternalState { /// @@ -34,6 +35,7 @@ private enum InternalState #region private data members // If you modify any of these fields, you must also update the // AssemblyLoadContextBaseObject structure in object.h + // and MonoManagedAssemblyLoadContext in object-internals.h // synchronization primitive to protect against usage of this instance while unloading private readonly object _unloadLock; @@ -562,26 +564,6 @@ public void Dispose() return context.ResolveUsingLoad(assemblyName); } - // This method is invoked by the VM to resolve an assembly reference using the Resolving event - // after trying assembly resolution via Load override and TPA load context without success. - private static Assembly? ResolveUsingResolvingEvent(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName) - { - AssemblyLoadContext context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchManagedAssemblyLoadContext).Target)!; - - // Invoke the AssemblyResolve event callbacks if wired up - return context.ResolveUsingEvent(assemblyName); - } - - // This method is invoked by the VM to resolve a satellite assembly reference - // after trying assembly resolution via Load override without success. - private static Assembly? ResolveSatelliteAssembly(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName) - { - AssemblyLoadContext context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchManagedAssemblyLoadContext).Target)!; - - // Invoke the ResolveSatelliteAssembly method - return context.ResolveSatelliteAssembly(assemblyName); - } - private Assembly? GetFirstResolvedAssemblyFromResolvingEvent(AssemblyName assemblyName) { Assembly? resolvedAssembly = null; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Versioning/FrameworkName.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Versioning/FrameworkName.cs index 92346d5e9ba531..a9a2225e206b0c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Versioning/FrameworkName.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Versioning/FrameworkName.cs @@ -19,8 +19,6 @@ public sealed class FrameworkName : IEquatable private const string VersionKey = "Version"; private const string ProfileKey = "Profile"; - private static readonly char[] s_componentSplitSeparator = { ComponentSeparator }; - public string Identifier { get @@ -146,7 +144,7 @@ public FrameworkName(string frameworkName) throw new ArgumentException(SR.Format(SR.net_emptystringcall, nameof(frameworkName)), nameof(frameworkName)); } - string[] components = frameworkName.Split(s_componentSplitSeparator); + string[] components = frameworkName.Split(ComponentSeparator); // Identifier and Version are required, Profile is optional. if (components.Length < 2 || components.Length > 3) diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index 010ca6c2ce34ff..c74821918b165b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -75,7 +75,7 @@ public override IList GetCustomAttributesData() public override MemberInfo[] GetDefaultMembers() { // See if we have cached the default member name - MemberInfo[] members = null!; + MemberInfo[]? members = null; string? defaultMemberName = GetDefaultMemberName(); if (defaultMemberName != null) @@ -237,6 +237,9 @@ public override bool IsEnumDefined(object value) if (value == null) throw new ArgumentNullException(nameof(value)); + if (!IsEnum) + throw new ArgumentException(SR.Arg_MustBeEnum, "enumType"); + // Check if both of them are of the same type RuntimeType valueType = (RuntimeType)value.GetType(); diff --git a/src/libraries/System.Private.CoreLib/src/System/SByte.cs b/src/libraries/System.Private.CoreLib/src/System/SByte.cs index effc14d26c520c..47d993e92c679d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SByte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SByte.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -150,7 +151,7 @@ private static sbyte Parse(ReadOnlySpan s, NumberStyles style, NumberForma return (sbyte)i; } - public static bool TryParse(string? s, out sbyte result) + public static bool TryParse([NotNullWhen(true)] string? s, out sbyte result) { if (s == null) { @@ -166,7 +167,7 @@ public static bool TryParse(ReadOnlySpan s, out sbyte result) return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out sbyte result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out sbyte result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/libraries/System.Private.CoreLib/src/System/SR.cs b/src/libraries/System.Private.CoreLib/src/System/SR.cs index fff60a9a02791e..73e7e0015526b4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SR.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SR.cs @@ -13,46 +13,23 @@ namespace System { internal static partial class SR { - // This method is used to decide if we need to append the exception message parameters to the message when calling SR.Format. - // by default it returns false. - [MethodImpl(MethodImplOptions.NoInlining)] - private static bool UsingResourceKeys() - { - return false; - } + private static readonly object _lock = new object(); + private static List? _currentlyLoading; + private static int _infinitelyRecursingCount; + private static bool _resourceManagerInited; // Needed for debugger integration - internal static string? GetResourceString(string resourceKey) + internal static string GetResourceString(string resourceKey) { return GetResourceString(resourceKey, string.Empty); } - internal static string GetResourceString(string resourceKey, string? defaultString) - { - string? resourceString = null; - try { resourceString = InternalGetResourceString(resourceKey); } - catch (MissingManifestResourceException) { } - - if (defaultString != null && resourceKey.Equals(resourceString, StringComparison.Ordinal)) - { - return defaultString; - } - - return resourceString!; // only null if missing resource - } - - private static readonly object _lock = new object(); - private static List? _currentlyLoading; - private static int _infinitelyRecursingCount; - private static bool _resourceManagerInited = false; - - [PreserveDependency(".cctor()", "System.Resources.ResourceManager")] - private static string? InternalGetResourceString(string? key) + private static string InternalGetResourceString(string key) { - if (string.IsNullOrEmpty(key)) + if (key.Length == 0) { - Debug.Fail("SR::GetResourceString with null or empty key. Bug in caller, or weird recursive loading problem?"); - return key!; + Debug.Fail("SR::GetResourceString with empty resourceKey. Bug in caller, or weird recursive loading problem?"); + return key; } // We have a somewhat common potential for infinite @@ -139,64 +116,5 @@ internal static string GetResourceString(string resourceKey, string? defaultStri } } } - - internal static string Format(IFormatProvider? provider, string resourceFormat, params object?[]? args) - { - if (args != null) - { - if (UsingResourceKeys()) - { - return resourceFormat + ", " + string.Join(", ", args); - } - - return string.Format(provider, resourceFormat, args); - } - - return resourceFormat; - } - - internal static string Format(string resourceFormat, params object?[]? args) - { - if (args != null) - { - if (UsingResourceKeys()) - { - return resourceFormat + ", " + string.Join(", ", args); - } - - return string.Format(resourceFormat, args); - } - - return resourceFormat; - } - - internal static string Format(string resourceFormat, object? p1) - { - if (UsingResourceKeys()) - { - return string.Join(", ", resourceFormat, p1); - } - - return string.Format(resourceFormat, p1); - } - - internal static string Format(string resourceFormat, object? p1, object? p2) - { - if (UsingResourceKeys()) - { - return string.Join(", ", resourceFormat, p1, p2); - } - - return string.Format(resourceFormat, p1, p2); - } - - internal static string Format(string resourceFormat, object? p1, object? p2, object? p3) - { - if (UsingResourceKeys()) - { - return string.Join(", ", resourceFormat, p1, p2, p3); - } - return string.Format(resourceFormat, p1, p2, p3); - } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs b/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs index 541f22dccdcb9a..ef0f7bbc00d071 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs @@ -10,7 +10,7 @@ namespace System.Security { public sealed class SecurityElement { - internal string _tag = null!; + internal string _tag; internal string? _text; private ArrayList? _children; internal ArrayList? _attributes; @@ -34,10 +34,6 @@ public sealed class SecurityElement //-------------------------- Constructors --------------------------- - internal SecurityElement() - { - } - public SecurityElement(string tag) { if (tag == null) diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index 157d57466e4ef8..3ad8a59bae8241 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -11,6 +11,7 @@ ** ===========================================================*/ +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -313,7 +314,7 @@ public static float Parse(ReadOnlySpan s, NumberStyles style = NumberStyle return Number.ParseSingle(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse(string? s, out float result) + public static bool TryParse([NotNullWhen(true)] string? s, out float result) { if (s == null) { @@ -329,7 +330,7 @@ public static bool TryParse(ReadOnlySpan s, out float result) return TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result); } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out float result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out float result) { NumberFormatInfo.ValidateParseStyleFloatingPoint(style); diff --git a/src/libraries/System.Private.CoreLib/src/System/Span.cs b/src/libraries/System.Private.CoreLib/src/System/Span.cs index 25bab98c889918..6016674dcdfdfd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Span.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Span.cs @@ -13,13 +13,6 @@ #pragma warning disable 0809 //warning CS0809: Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System { /// @@ -273,7 +266,7 @@ public ref T GetPinnableReference() /// Clears the contents of this span. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Clear() + public unsafe void Clear() { if (RuntimeHelpers.IsReferenceOrContainsReferences()) { diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Byte.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Byte.cs index 025d22e5d47d8f..5132148ae58325 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Byte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Byte.cs @@ -10,13 +10,6 @@ using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif // TARGET_64BIT - namespace System { internal static partial class SpanHelpers // .Byte @@ -103,13 +96,13 @@ public static int LastIndexOfAny(ref byte searchSpace, int searchSpaceLength, re // Adapted from IndexOf(...) [MethodImpl(MethodImplOptions.AggressiveOptimization)] - public static unsafe bool Contains(ref byte searchSpace, byte value, int length) + public static bool Contains(ref byte searchSpace, byte value, int length) { Debug.Assert(length >= 0); uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions - IntPtr offset = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations - IntPtr lengthToExamine = (IntPtr)length; + nuint offset = 0; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations + nuint lengthToExamine = (nuint)(uint)length; if (Vector.IsHardwareAccelerated && length >= Vector.Count * 2) { @@ -117,7 +110,7 @@ public static unsafe bool Contains(ref byte searchSpace, byte value, int length) } SequentialScan: - while ((byte*)lengthToExamine >= (byte*)8) + while (lengthToExamine >= 8) { lengthToExamine -= 8; @@ -136,7 +129,7 @@ public static unsafe bool Contains(ref byte searchSpace, byte value, int length) offset += 8; } - if ((byte*)lengthToExamine >= (byte*)4) + if (lengthToExamine >= 4) { lengthToExamine -= 4; @@ -151,7 +144,7 @@ public static unsafe bool Contains(ref byte searchSpace, byte value, int length) offset += 4; } - while ((byte*)lengthToExamine > (byte*)0) + while (lengthToExamine > 0) { lengthToExamine -= 1; @@ -161,27 +154,27 @@ public static unsafe bool Contains(ref byte searchSpace, byte value, int length) offset += 1; } - if (Vector.IsHardwareAccelerated && ((int)(byte*)offset < length)) + if (Vector.IsHardwareAccelerated && (offset < (nuint)(uint)length)) { - lengthToExamine = (IntPtr)((length - (int)(byte*)offset) & ~(Vector.Count - 1)); + lengthToExamine = (((nuint)(uint)length - offset) & (nuint)~(Vector.Count - 1)); Vector values = new Vector(value); - while ((byte*)lengthToExamine > (byte*)offset) + while (lengthToExamine > offset) { var matches = Vector.Equals(values, LoadVector(ref searchSpace, offset)); if (Vector.Zero.Equals(matches)) { - offset += Vector.Count; + offset += (nuint)Vector.Count; continue; } goto Found; } - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { - lengthToExamine = (IntPtr)(length - (int)(byte*)offset); + lengthToExamine = ((nuint)(uint)length - offset); goto SequentialScan; } } @@ -198,8 +191,8 @@ public static unsafe int IndexOf(ref byte searchSpace, byte value, int length) Debug.Assert(length >= 0); uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions - IntPtr offset = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations - IntPtr lengthToExamine = (IntPtr)length; + nuint offset = 0; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations + nuint lengthToExamine = (nuint)(uint)length; if (Avx2.IsSupported || Sse2.IsSupported) { @@ -217,7 +210,7 @@ public static unsafe int IndexOf(ref byte searchSpace, byte value, int length) } } SequentialScan: - while ((byte*)lengthToExamine >= (byte*)8) + while (lengthToExamine >= 8) { lengthToExamine -= 8; @@ -241,7 +234,7 @@ public static unsafe int IndexOf(ref byte searchSpace, byte value, int length) offset += 8; } - if ((byte*)lengthToExamine >= (byte*)4) + if (lengthToExamine >= 4) { lengthToExamine -= 4; @@ -257,7 +250,7 @@ public static unsafe int IndexOf(ref byte searchSpace, byte value, int length) offset += 4; } - while ((byte*)lengthToExamine > (byte*)0) + while (lengthToExamine > 0) { lengthToExamine -= 1; @@ -272,9 +265,9 @@ public static unsafe int IndexOf(ref byte searchSpace, byte value, int length) // have hardware accelerated. After processing Vector lengths we return to SequentialScan to finish any remaining. if (Avx2.IsSupported) { - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { - if ((((nuint)Unsafe.AsPointer(ref searchSpace) + (nuint)offset) & (nuint)(Vector256.Count - 1)) != 0) + if ((((nuint)(uint)Unsafe.AsPointer(ref searchSpace) + offset) & (nuint)(Vector256.Count - 1)) != 0) { // Not currently aligned to Vector256 (is aligned to Vector128); this can cause a problem for searches // with no upper bound e.g. String.strlen. @@ -288,17 +281,17 @@ public static unsafe int IndexOf(ref byte searchSpace, byte value, int length) if (matches == 0) { // Zero flags set so no matches - offset += Vector128.Count; + offset += (nuint)Vector128.Count; } else { // Find bitflag offset of first match and add to current offset - return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches); + return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches)); } } lengthToExamine = GetByteVector256SpanLength(offset, length); - if ((byte*)lengthToExamine > (byte*)offset) + if (lengthToExamine > offset) { Vector256 values = Vector256.Create(value); do @@ -310,17 +303,17 @@ public static unsafe int IndexOf(ref byte searchSpace, byte value, int length) if (matches == 0) { // Zero flags set so no matches - offset += Vector256.Count; + offset += (nuint)Vector256.Count; continue; } // Find bitflag offset of first match and add to current offset - return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches); - } while ((byte*)lengthToExamine > (byte*)offset); + return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches)); + } while (lengthToExamine > offset); } lengthToExamine = GetByteVector128SpanLength(offset, length); - if ((byte*)lengthToExamine > (byte*)offset) + if (lengthToExamine > offset) { Vector128 values = Vector128.Create(value); Vector128 search = LoadVector128(ref searchSpace, offset); @@ -330,30 +323,30 @@ public static unsafe int IndexOf(ref byte searchSpace, byte value, int length) if (matches == 0) { // Zero flags set so no matches - offset += Vector128.Count; + offset += (nuint)Vector128.Count; } else { // Find bitflag offset of first match and add to current offset - return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches); + return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches)); } } - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { - lengthToExamine = (IntPtr)(length - (int)(byte*)offset); + lengthToExamine = ((nuint)(uint)length - offset); goto SequentialScan; } } } else if (Sse2.IsSupported) { - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { lengthToExamine = GetByteVector128SpanLength(offset, length); Vector128 values = Vector128.Create(value); - while ((byte*)lengthToExamine > (byte*)offset) + while (lengthToExamine > offset) { Vector128 search = LoadVector128(ref searchSpace, offset); @@ -362,66 +355,66 @@ public static unsafe int IndexOf(ref byte searchSpace, byte value, int length) if (matches == 0) { // Zero flags set so no matches - offset += Vector128.Count; + offset += (nuint)Vector128.Count; continue; } // Find bitflag offset of first match and add to current offset - return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches); + return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches)); } - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { - lengthToExamine = (IntPtr)(length - (int)(byte*)offset); + lengthToExamine = ((nuint)(uint)length - offset); goto SequentialScan; } } } else if (Vector.IsHardwareAccelerated) { - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { lengthToExamine = GetByteVectorSpanLength(offset, length); Vector values = new Vector(value); - while ((byte*)lengthToExamine > (byte*)offset) + while (lengthToExamine > offset) { var matches = Vector.Equals(values, LoadVector(ref searchSpace, offset)); if (Vector.Zero.Equals(matches)) { - offset += Vector.Count; + offset += (nuint)Vector.Count; continue; } // Find offset of first match and add to current offset - return (int)(byte*)offset + LocateFirstFoundByte(matches); + return (int)offset + LocateFirstFoundByte(matches); } - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { - lengthToExamine = (IntPtr)(length - (int)(byte*)offset); + lengthToExamine = ((nuint)(uint)length - offset); goto SequentialScan; } } } return -1; Found: // Workaround for https://github.com/dotnet/runtime/issues/8795 - return (int)(byte*)offset; + return (int)offset; Found1: - return (int)(byte*)(offset + 1); + return (int)(offset + 1); Found2: - return (int)(byte*)(offset + 2); + return (int)(offset + 2); Found3: - return (int)(byte*)(offset + 3); + return (int)(offset + 3); Found4: - return (int)(byte*)(offset + 4); + return (int)(offset + 4); Found5: - return (int)(byte*)(offset + 5); + return (int)(offset + 5); Found6: - return (int)(byte*)(offset + 6); + return (int)(offset + 6); Found7: - return (int)(byte*)(offset + 7); + return (int)(offset + 7); } public static int LastIndexOf(ref byte searchSpace, int searchSpaceLength, ref byte value, int valueLength) @@ -450,7 +443,7 @@ public static int LastIndexOf(ref byte searchSpace, int searchSpaceLength, ref b break; // Found the first element of "value". See if the tail matches. - if (SequenceEqual(ref Unsafe.Add(ref searchSpace, relativeIndex + 1), ref valueTail, (nuint)valueTailLength)) // The (nunit)-cast is necessary to pick the correct overload + if (SequenceEqual(ref Unsafe.Add(ref searchSpace, relativeIndex + 1), ref valueTail, (nuint)(uint)valueTailLength)) // The (nunit)-cast is necessary to pick the correct overload return relativeIndex; // The tail matched. Return a successful find. offset += remainingSearchSpaceLength - relativeIndex; @@ -459,20 +452,20 @@ public static int LastIndexOf(ref byte searchSpace, int searchSpaceLength, ref b } [MethodImpl(MethodImplOptions.AggressiveOptimization)] - public static unsafe int LastIndexOf(ref byte searchSpace, byte value, int length) + public static int LastIndexOf(ref byte searchSpace, byte value, int length) { Debug.Assert(length >= 0); uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions - IntPtr offset = (IntPtr)length; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations - IntPtr lengthToExamine = (IntPtr)length; + nuint offset = (nuint)(uint)length; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations + nuint lengthToExamine = (nuint)(uint)length; if (Vector.IsHardwareAccelerated && length >= Vector.Count * 2) { lengthToExamine = UnalignedCountVectorFromEnd(ref searchSpace, length); } SequentialScan: - while ((byte*)lengthToExamine >= (byte*)8) + while (lengthToExamine >= 8) { lengthToExamine -= 8; offset -= 8; @@ -495,7 +488,7 @@ public static unsafe int LastIndexOf(ref byte searchSpace, byte value, int lengt goto Found; } - if ((byte*)lengthToExamine >= (byte*)4) + if (lengthToExamine >= 4) { lengthToExamine -= 4; offset -= 4; @@ -510,7 +503,7 @@ public static unsafe int LastIndexOf(ref byte searchSpace, byte value, int lengt goto Found; } - while ((byte*)lengthToExamine > (byte*)0) + while (lengthToExamine > 0) { lengthToExamine -= 1; offset -= 1; @@ -519,26 +512,26 @@ public static unsafe int LastIndexOf(ref byte searchSpace, byte value, int lengt goto Found; } - if (Vector.IsHardwareAccelerated && ((byte*)offset > (byte*)0)) + if (Vector.IsHardwareAccelerated && (offset > 0)) { - lengthToExamine = (IntPtr)((int)(byte*)offset & ~(Vector.Count - 1)); + lengthToExamine = (offset & (nuint)~(Vector.Count - 1)); Vector values = new Vector(value); - while ((byte*)lengthToExamine > (byte*)(Vector.Count - 1)) + while (lengthToExamine > (nuint)(Vector.Count - 1)) { - var matches = Vector.Equals(values, LoadVector(ref searchSpace, offset - Vector.Count)); + var matches = Vector.Equals(values, LoadVector(ref searchSpace, offset - (nuint)Vector.Count)); if (Vector.Zero.Equals(matches)) { - offset -= Vector.Count; - lengthToExamine -= Vector.Count; + offset -= (nuint)Vector.Count; + lengthToExamine -= (nuint)Vector.Count; continue; } // Find offset of first match and add to current offset return (int)(offset) - Vector.Count + LocateLastFoundByte(matches); } - if ((byte*)offset > (byte*)0) + if (offset > 0) { lengthToExamine = offset; goto SequentialScan; @@ -546,32 +539,32 @@ public static unsafe int LastIndexOf(ref byte searchSpace, byte value, int lengt } return -1; Found: // Workaround for https://github.com/dotnet/runtime/issues/8795 - return (int)(byte*)offset; + return (int)offset; Found1: - return (int)(byte*)(offset + 1); + return (int)(offset + 1); Found2: - return (int)(byte*)(offset + 2); + return (int)(offset + 2); Found3: - return (int)(byte*)(offset + 3); + return (int)(offset + 3); Found4: - return (int)(byte*)(offset + 4); + return (int)(offset + 4); Found5: - return (int)(byte*)(offset + 5); + return (int)(offset + 5); Found6: - return (int)(byte*)(offset + 6); + return (int)(offset + 6); Found7: - return (int)(byte*)(offset + 7); + return (int)(offset + 7); } [MethodImpl(MethodImplOptions.AggressiveOptimization)] - public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte value1, int length) + public static int IndexOfAny(ref byte searchSpace, byte value0, byte value1, int length) { Debug.Assert(length >= 0); uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions uint uValue1 = value1; // Use uint for comparisons to avoid unnecessary 8->32 extensions - IntPtr offset = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations - IntPtr lengthToExamine = (IntPtr)length; + nuint offset = 0; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations + nuint lengthToExamine = (nuint)(uint)length; if (Avx2.IsSupported || Sse2.IsSupported) { @@ -590,7 +583,7 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu } SequentialScan: uint lookUp; - while ((byte*)lengthToExamine >= (byte*)8) + while (lengthToExamine >= 8) { lengthToExamine -= 8; @@ -622,7 +615,7 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu offset += 8; } - if ((byte*)lengthToExamine >= (byte*)4) + if (lengthToExamine >= 4) { lengthToExamine -= 4; @@ -642,7 +635,7 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu offset += 4; } - while ((byte*)lengthToExamine > (byte*)0) + while (lengthToExamine > 0) { lengthToExamine -= 1; @@ -657,10 +650,10 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu // the JIT to see that the code is unreachable and eliminate it when the platform does not have hardware accelerated. if (Avx2.IsSupported) { - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { lengthToExamine = GetByteVector256SpanLength(offset, length); - if ((byte*)lengthToExamine > (byte*)offset) + if (lengthToExamine > offset) { Vector256 values0 = Vector256.Create(value0); Vector256 values1 = Vector256.Create(value1); @@ -677,17 +670,17 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu if (matches == 0) { // Zero flags set so no matches - offset += Vector256.Count; + offset += (nuint)Vector256.Count; continue; } // Find bitflag offset of first match and add to current offset - return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches); - } while ((byte*)lengthToExamine > (byte*)offset); + return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches)); + } while (lengthToExamine > offset); } lengthToExamine = GetByteVector128SpanLength(offset, length); - if ((byte*)lengthToExamine > (byte*)offset) + if (lengthToExamine > offset) { Vector128 values0 = Vector128.Create(value0); Vector128 values1 = Vector128.Create(value1); @@ -701,32 +694,32 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu if (matches == 0) { // Zero flags set so no matches - offset += Vector128.Count; + offset += (nuint)Vector128.Count; } else { // Find bitflag offset of first match and add to current offset - return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches); + return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches)); } } - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { - lengthToExamine = (IntPtr)(length - (int)(byte*)offset); + lengthToExamine = ((nuint)(uint)length - offset); goto SequentialScan; } } } else if (Sse2.IsSupported) { - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { lengthToExamine = GetByteVector128SpanLength(offset, length); Vector128 values0 = Vector128.Create(value0); Vector128 values1 = Vector128.Create(value1); - while ((byte*)lengthToExamine > (byte*)offset) + while (lengthToExamine > offset) { Vector128 search = LoadVector128(ref searchSpace, offset); // Same method as above @@ -737,31 +730,31 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu if (matches == 0) { // Zero flags set so no matches - offset += Vector128.Count; + offset += (nuint)Vector128.Count; continue; } // Find bitflag offset of first match and add to current offset - return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches); + return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches)); } - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { - lengthToExamine = (IntPtr)(length - (int)(byte*)offset); + lengthToExamine = ((nuint)(uint)length - offset); goto SequentialScan; } } } else if (Vector.IsHardwareAccelerated) { - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { lengthToExamine = GetByteVectorSpanLength(offset, length); Vector values0 = new Vector(value0); Vector values1 = new Vector(value1); - while ((byte*)lengthToExamine > (byte*)offset) + while (lengthToExamine > offset) { Vector search = LoadVector(ref searchSpace, offset); var matches = Vector.BitwiseOr( @@ -769,50 +762,50 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu Vector.Equals(search, values1)); if (Vector.Zero.Equals(matches)) { - offset += Vector.Count; + offset += (nuint)Vector.Count; continue; } // Find offset of first match and add to current offset - return (int)(byte*)offset + LocateFirstFoundByte(matches); + return (int)offset + LocateFirstFoundByte(matches); } - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { - lengthToExamine = (IntPtr)(length - (int)(byte*)offset); + lengthToExamine = ((nuint)(uint)length - offset); goto SequentialScan; } } } return -1; Found: // Workaround for https://github.com/dotnet/runtime/issues/8795 - return (int)(byte*)offset; + return (int)offset; Found1: - return (int)(byte*)(offset + 1); + return (int)(offset + 1); Found2: - return (int)(byte*)(offset + 2); + return (int)(offset + 2); Found3: - return (int)(byte*)(offset + 3); + return (int)(offset + 3); Found4: - return (int)(byte*)(offset + 4); + return (int)(offset + 4); Found5: - return (int)(byte*)(offset + 5); + return (int)(offset + 5); Found6: - return (int)(byte*)(offset + 6); + return (int)(offset + 6); Found7: - return (int)(byte*)(offset + 7); + return (int)(offset + 7); } [MethodImpl(MethodImplOptions.AggressiveOptimization)] - public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte value1, byte value2, int length) + public static int IndexOfAny(ref byte searchSpace, byte value0, byte value1, byte value2, int length) { Debug.Assert(length >= 0); uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions uint uValue1 = value1; uint uValue2 = value2; - IntPtr offset = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations - IntPtr lengthToExamine = (IntPtr)length; + nuint offset = 0; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations + nuint lengthToExamine = (nuint)(uint)length; if (Avx2.IsSupported || Sse2.IsSupported) { @@ -831,7 +824,7 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu } SequentialScan: uint lookUp; - while ((byte*)lengthToExamine >= (byte*)8) + while (lengthToExamine >= 8) { lengthToExamine -= 8; @@ -863,7 +856,7 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu offset += 8; } - if ((byte*)lengthToExamine >= (byte*)4) + if (lengthToExamine >= 4) { lengthToExamine -= 4; @@ -883,7 +876,7 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu offset += 4; } - while ((byte*)lengthToExamine > (byte*)0) + while (lengthToExamine > 0) { lengthToExamine -= 1; @@ -896,10 +889,10 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu if (Avx2.IsSupported) { - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { lengthToExamine = GetByteVector256SpanLength(offset, length); - if ((byte*)lengthToExamine > (byte*)offset) + if (lengthToExamine > offset) { Vector256 values0 = Vector256.Create(value0); Vector256 values1 = Vector256.Create(value1); @@ -918,17 +911,17 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu if (matches == 0) { // Zero flags set so no matches - offset += Vector256.Count; + offset += (nuint)Vector256.Count; continue; } // Find bitflag offset of first match and add to current offset - return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches); - } while ((byte*)lengthToExamine > (byte*)offset); + return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches)); + } while (lengthToExamine > offset); } lengthToExamine = GetByteVector128SpanLength(offset, length); - if ((byte*)lengthToExamine > (byte*)offset) + if (lengthToExamine > offset) { Vector128 values0 = Vector128.Create(value0); Vector128 values1 = Vector128.Create(value1); @@ -944,25 +937,25 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu if (matches == 0) { // Zero flags set so no matches - offset += Vector128.Count; + offset += (nuint)Vector128.Count; } else { // Find bitflag offset of first match and add to current offset - return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches); + return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches)); } } - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { - lengthToExamine = (IntPtr)(length - (int)(byte*)offset); + lengthToExamine = ((nuint)(uint)length - offset); goto SequentialScan; } } } else if (Sse2.IsSupported) { - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { lengthToExamine = GetByteVector128SpanLength(offset, length); @@ -970,7 +963,7 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu Vector128 values1 = Vector128.Create(value1); Vector128 values2 = Vector128.Create(value2); - while ((byte*)lengthToExamine > (byte*)offset) + while (lengthToExamine > offset) { Vector128 search = LoadVector128(ref searchSpace, offset); @@ -982,24 +975,24 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu if (matches == 0) { // Zero flags set so no matches - offset += Vector128.Count; + offset += (nuint)Vector128.Count; continue; } // Find bitflag offset of first match and add to current offset - return ((int)(byte*)offset) + BitOperations.TrailingZeroCount(matches); + return (int)(offset + (uint)BitOperations.TrailingZeroCount(matches)); } - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { - lengthToExamine = (IntPtr)(length - (int)(byte*)offset); + lengthToExamine = ((nuint)(uint)length - offset); goto SequentialScan; } } } else if (Vector.IsHardwareAccelerated) { - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { lengthToExamine = GetByteVectorSpanLength(offset, length); @@ -1007,7 +1000,7 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu Vector values1 = new Vector(value1); Vector values2 = new Vector(value2); - while ((byte*)lengthToExamine > (byte*)offset) + while (lengthToExamine > offset) { Vector search = LoadVector(ref searchSpace, offset); @@ -1019,48 +1012,48 @@ public static unsafe int IndexOfAny(ref byte searchSpace, byte value0, byte valu if (Vector.Zero.Equals(matches)) { - offset += Vector.Count; + offset += (nuint)Vector.Count; continue; } // Find offset of first match and add to current offset - return (int)(byte*)offset + LocateFirstFoundByte(matches); + return (int)offset + LocateFirstFoundByte(matches); } - if ((int)(byte*)offset < length) + if (offset < (nuint)(uint)length) { - lengthToExamine = (IntPtr)(length - (int)(byte*)offset); + lengthToExamine = ((nuint)(uint)length - offset); goto SequentialScan; } } } return -1; Found: // Workaround for https://github.com/dotnet/runtime/issues/8795 - return (int)(byte*)offset; + return (int)offset; Found1: - return (int)(byte*)(offset + 1); + return (int)(offset + 1); Found2: - return (int)(byte*)(offset + 2); + return (int)(offset + 2); Found3: - return (int)(byte*)(offset + 3); + return (int)(offset + 3); Found4: - return (int)(byte*)(offset + 4); + return (int)(offset + 4); Found5: - return (int)(byte*)(offset + 5); + return (int)(offset + 5); Found6: - return (int)(byte*)(offset + 6); + return (int)(offset + 6); Found7: - return (int)(byte*)(offset + 7); + return (int)(offset + 7); } - public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte value1, int length) + public static int LastIndexOfAny(ref byte searchSpace, byte value0, byte value1, int length) { Debug.Assert(length >= 0); uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions uint uValue1 = value1; - IntPtr offset = (IntPtr)length; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations - IntPtr lengthToExamine = (IntPtr)length; + nuint offset = (nuint)(uint)length; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations + nuint lengthToExamine = (nuint)(uint)length; if (Vector.IsHardwareAccelerated && length >= Vector.Count * 2) { @@ -1068,7 +1061,7 @@ public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte } SequentialScan: uint lookUp; - while ((byte*)lengthToExamine >= (byte*)8) + while (lengthToExamine >= 8) { lengthToExamine -= 8; offset -= 8; @@ -1099,7 +1092,7 @@ public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte goto Found; } - if ((byte*)lengthToExamine >= (byte*)4) + if (lengthToExamine >= 4) { lengthToExamine -= 4; offset -= 4; @@ -1118,7 +1111,7 @@ public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte goto Found; } - while ((byte*)lengthToExamine > (byte*)0) + while (lengthToExamine > 0) { lengthToExamine -= 1; offset -= 1; @@ -1128,23 +1121,23 @@ public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte goto Found; } - if (Vector.IsHardwareAccelerated && ((byte*)offset > (byte*)0)) + if (Vector.IsHardwareAccelerated && (offset > 0)) { - lengthToExamine = (IntPtr)((int)(byte*)offset & ~(Vector.Count - 1)); + lengthToExamine = (offset & (nuint)~(Vector.Count - 1)); Vector values0 = new Vector(value0); Vector values1 = new Vector(value1); - while ((byte*)lengthToExamine > (byte*)(Vector.Count - 1)) + while (lengthToExamine > (nuint)(Vector.Count - 1)) { - Vector search = LoadVector(ref searchSpace, offset - Vector.Count); + Vector search = LoadVector(ref searchSpace, offset - (nuint)Vector.Count); var matches = Vector.BitwiseOr( Vector.Equals(search, values0), Vector.Equals(search, values1)); if (Vector.Zero.Equals(matches)) { - offset -= Vector.Count; - lengthToExamine -= Vector.Count; + offset -= (nuint)Vector.Count; + lengthToExamine -= (nuint)Vector.Count; continue; } @@ -1152,7 +1145,7 @@ public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte return (int)(offset) - Vector.Count + LocateLastFoundByte(matches); } - if ((byte*)offset > (byte*)0) + if (offset > 0) { lengthToExamine = offset; goto SequentialScan; @@ -1160,32 +1153,32 @@ public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte } return -1; Found: // Workaround for https://github.com/dotnet/runtime/issues/8795 - return (int)(byte*)offset; + return (int)offset; Found1: - return (int)(byte*)(offset + 1); + return (int)(offset + 1); Found2: - return (int)(byte*)(offset + 2); + return (int)(offset + 2); Found3: - return (int)(byte*)(offset + 3); + return (int)(offset + 3); Found4: - return (int)(byte*)(offset + 4); + return (int)(offset + 4); Found5: - return (int)(byte*)(offset + 5); + return (int)(offset + 5); Found6: - return (int)(byte*)(offset + 6); + return (int)(offset + 6); Found7: - return (int)(byte*)(offset + 7); + return (int)(offset + 7); } - public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte value1, byte value2, int length) + public static int LastIndexOfAny(ref byte searchSpace, byte value0, byte value1, byte value2, int length) { Debug.Assert(length >= 0); uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions uint uValue1 = value1; uint uValue2 = value2; - IntPtr offset = (IntPtr)length; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations - IntPtr lengthToExamine = (IntPtr)length; + nuint offset = (nuint)(uint)length; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations + nuint lengthToExamine = (nuint)(uint)length; if (Vector.IsHardwareAccelerated && length >= Vector.Count * 2) { @@ -1193,7 +1186,7 @@ public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte } SequentialScan: uint lookUp; - while ((byte*)lengthToExamine >= (byte*)8) + while (lengthToExamine >= 8) { lengthToExamine -= 8; offset -= 8; @@ -1224,7 +1217,7 @@ public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte goto Found; } - if ((byte*)lengthToExamine >= (byte*)4) + if (lengthToExamine >= 4) { lengthToExamine -= 4; offset -= 4; @@ -1243,7 +1236,7 @@ public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte goto Found; } - while ((byte*)lengthToExamine > (byte*)0) + while (lengthToExamine > 0) { lengthToExamine -= 1; offset -= 1; @@ -1253,17 +1246,17 @@ public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte goto Found; } - if (Vector.IsHardwareAccelerated && ((byte*)offset > (byte*)0)) + if (Vector.IsHardwareAccelerated && (offset > 0)) { - lengthToExamine = (IntPtr)((int)(byte*)offset & ~(Vector.Count - 1)); + lengthToExamine = (offset & (nuint)~(Vector.Count - 1)); Vector values0 = new Vector(value0); Vector values1 = new Vector(value1); Vector values2 = new Vector(value2); - while ((byte*)lengthToExamine > (byte*)(Vector.Count - 1)) + while (lengthToExamine > (nuint)(Vector.Count - 1)) { - Vector search = LoadVector(ref searchSpace, offset - Vector.Count); + Vector search = LoadVector(ref searchSpace, offset - (nuint)Vector.Count); var matches = Vector.BitwiseOr( Vector.BitwiseOr( @@ -1273,8 +1266,8 @@ public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte if (Vector.Zero.Equals(matches)) { - offset -= Vector.Count; - lengthToExamine -= Vector.Count; + offset -= (nuint)Vector.Count; + lengthToExamine -= (nuint)Vector.Count; continue; } @@ -1282,7 +1275,7 @@ public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte return (int)(offset) - Vector.Count + LocateLastFoundByte(matches); } - if ((byte*)offset > (byte*)0) + if (offset > 0) { lengthToExamine = offset; goto SequentialScan; @@ -1290,104 +1283,229 @@ public static unsafe int LastIndexOfAny(ref byte searchSpace, byte value0, byte } return -1; Found: // Workaround for https://github.com/dotnet/runtime/issues/8795 - return (int)(byte*)offset; + return (int)offset; Found1: - return (int)(byte*)(offset + 1); + return (int)(offset + 1); Found2: - return (int)(byte*)(offset + 2); + return (int)(offset + 2); Found3: - return (int)(byte*)(offset + 3); + return (int)(offset + 3); Found4: - return (int)(byte*)(offset + 4); + return (int)(offset + 4); Found5: - return (int)(byte*)(offset + 5); + return (int)(offset + 5); Found6: - return (int)(byte*)(offset + 6); + return (int)(offset + 6); Found7: - return (int)(byte*)(offset + 7); + return (int)(offset + 7); } // Optimized byte-based SequenceEquals. The "length" parameter for this one is declared a nuint rather than int as we also use it for types other than byte // where the length can exceed 2Gb once scaled by sizeof(T). - [MethodImpl(MethodImplOptions.AggressiveOptimization)] public static unsafe bool SequenceEqual(ref byte first, ref byte second, nuint length) { - IntPtr offset = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations - IntPtr lengthToExamine = (IntPtr)(void*)length; + bool result; + // Use nint for arithmetic to avoid unnecessary 64->32->64 truncations + if (length >= (nuint)sizeof(nuint)) + { + // Conditional jmp foward to favor shorter lengths. (See comment at "Equal:" label) + // The longer lengths can make back the time due to branch misprediction + // better than shorter lengths. + goto Longer; + } - if ((byte*)lengthToExamine >= (byte*)sizeof(UIntPtr)) +#if TARGET_64BIT + // On 32-bit, this will always be true since sizeof(nuint) == 4 + if (length < sizeof(uint)) +#endif { - // Only check that the ref is the same if buffers are large, and hence - // its worth avoiding doing unnecessary comparisons - if (Unsafe.AreSame(ref first, ref second)) - goto Equal; + uint differentBits = 0; + nuint offset = (length & 2); + if (offset != 0) + { + differentBits = LoadUShort(ref first); + differentBits -= LoadUShort(ref second); + } + if ((length & 1) != 0) + { + differentBits |= (uint)Unsafe.AddByteOffset(ref first, offset) - (uint)Unsafe.AddByteOffset(ref second, offset); + } + result = (differentBits == 0); + goto Result; + } +#if TARGET_64BIT + else + { + nuint offset = length - sizeof(uint); + uint differentBits = LoadUInt(ref first) - LoadUInt(ref second); + differentBits |= LoadUInt(ref first, offset) - LoadUInt(ref second, offset); + result = (differentBits == 0); + goto Result; + } +#endif + Longer: + // Only check that the ref is the same if buffers are large, + // and hence its worth avoiding doing unnecessary comparisons + if (!Unsafe.AreSame(ref first, ref second)) + { + // C# compiler inverts this test, making the outer goto the conditional jmp. + goto Vector; + } + + // This becomes a conditional jmp foward to not favor it. + goto Equal; - if (Vector.IsHardwareAccelerated && (byte*)lengthToExamine >= (byte*)Vector.Count) + Result: + return result; + // When the sequence is equal; which is the longest execution, we want it to determine that + // as fast as possible so we do not want the early outs to be "predicted not taken" branches. + Equal: + return true; + + Vector: + if (Sse2.IsSupported) + { + if (Avx2.IsSupported && length >= (nuint)Vector256.Count) { - lengthToExamine -= Vector.Count; - while ((byte*)lengthToExamine > (byte*)offset) + Vector256 vecResult; + nuint offset = 0; + nuint lengthToExamine = length - (nuint)Vector256.Count; + // Unsigned, so it shouldn't have overflowed larger than length (rather than negative) + Debug.Assert(lengthToExamine < length); + if (lengthToExamine != 0) { - if (LoadVector(ref first, offset) != LoadVector(ref second, offset)) + do { - goto NotEqual; - } - offset += Vector.Count; + vecResult = Avx2.CompareEqual(LoadVector256(ref first, offset), LoadVector256(ref second, offset)); + if (Avx2.MoveMask(vecResult) != -1) + { + goto NotEqual; + } + offset += (nuint)Vector256.Count; + } while (lengthToExamine > offset); } - return LoadVector(ref first, lengthToExamine) == LoadVector(ref second, lengthToExamine); - } - Debug.Assert((byte*)lengthToExamine >= (byte*)sizeof(UIntPtr)); + // Do final compare as Vector256.Count from end rather than start + vecResult = Avx2.CompareEqual(LoadVector256(ref first, lengthToExamine), LoadVector256(ref second, lengthToExamine)); + if (Avx2.MoveMask(vecResult) == -1) + { + // C# compiler inverts this test, making the outer goto the conditional jmp. + goto Equal; + } - lengthToExamine -= sizeof(UIntPtr); - while ((byte*)lengthToExamine > (byte*)offset) + // This becomes a conditional jmp foward to not favor it. + goto NotEqual; + } + // Use Vector128.Size as Vector128.Count doesn't inline at R2R time + // https://github.com/dotnet/runtime/issues/32714 + else if (length >= Vector128.Size) { - if (LoadUIntPtr(ref first, offset) != LoadUIntPtr(ref second, offset)) + Vector128 vecResult; + nuint offset = 0; + nuint lengthToExamine = length - Vector128.Size; + // Unsigned, so it shouldn't have overflowed larger than length (rather than negative) + Debug.Assert(lengthToExamine < length); + if (lengthToExamine != 0) { - goto NotEqual; + do + { + // We use instrincs directly as .Equals calls .AsByte() which doesn't inline at R2R time + // https://github.com/dotnet/runtime/issues/32714 + vecResult = Sse2.CompareEqual(LoadVector128(ref first, offset), LoadVector128(ref second, offset)); + if (Sse2.MoveMask(vecResult) != 0xFFFF) + { + goto NotEqual; + } + offset += Vector128.Size; + } while (lengthToExamine > offset); } - offset += sizeof(UIntPtr); - } - return LoadUIntPtr(ref first, lengthToExamine) == LoadUIntPtr(ref second, lengthToExamine); - } - Debug.Assert((byte*)lengthToExamine < (byte*)sizeof(UIntPtr)); + // Do final compare as Vector128.Count from end rather than start + vecResult = Sse2.CompareEqual(LoadVector128(ref first, lengthToExamine), LoadVector128(ref second, lengthToExamine)); + if (Sse2.MoveMask(vecResult) == 0xFFFF) + { + // C# compiler inverts this test, making the outer goto the conditional jmp. + goto Equal; + } - // On 32-bit, this will never be true since sizeof(UIntPtr) == 4 -#if TARGET_64BIT - if ((byte*)lengthToExamine >= (byte*)sizeof(int)) - { - if (LoadInt(ref first, offset) != LoadInt(ref second, offset)) - { + // This becomes a conditional jmp foward to not favor it. goto NotEqual; } - offset += sizeof(int); - lengthToExamine -= sizeof(int); } -#endif - - if ((byte*)lengthToExamine >= (byte*)sizeof(short)) + else if (Vector.IsHardwareAccelerated && length >= (nuint)Vector.Count) { - if (LoadShort(ref first, offset) != LoadShort(ref second, offset)) + nuint offset = 0; + nuint lengthToExamine = length - (nuint)Vector.Count; + // Unsigned, so it shouldn't have overflowed larger than length (rather than negative) + Debug.Assert(lengthToExamine < length); + if (lengthToExamine > 0) { - goto NotEqual; + do + { + if (LoadVector(ref first, offset) != LoadVector(ref second, offset)) + { + goto NotEqual; + } + offset += (nuint)Vector.Count; + } while (lengthToExamine > offset); + } + + // Do final compare as Vector.Count from end rather than start + if (LoadVector(ref first, lengthToExamine) == LoadVector(ref second, lengthToExamine)) + { + // C# compiler inverts this test, making the outer goto the conditional jmp. + goto Equal; } - offset += sizeof(short); - lengthToExamine -= sizeof(short); + + // This becomes a conditional jmp foward to not favor it. + goto NotEqual; } - if (lengthToExamine != IntPtr.Zero) +#if TARGET_64BIT + if (Sse2.IsSupported) { - Debug.Assert((int)lengthToExamine == 1); + Debug.Assert(length <= (nuint)sizeof(nuint) * 2); - if (Unsafe.AddByteOffset(ref first, offset) != Unsafe.AddByteOffset(ref second, offset)) + nuint offset = length - (nuint)sizeof(nuint); + nuint differentBits = LoadNUInt(ref first) - LoadNUInt(ref second); + differentBits |= LoadNUInt(ref first, offset) - LoadNUInt(ref second, offset); + result = (differentBits == 0); + goto Result; + } + else +#endif + { + Debug.Assert(length >= (nuint)sizeof(nuint)); { - goto NotEqual; + nuint offset = 0; + nuint lengthToExamine = length - (nuint)sizeof(nuint); + // Unsigned, so it shouldn't have overflowed larger than length (rather than negative) + Debug.Assert(lengthToExamine < length); + if (lengthToExamine > 0) + { + do + { + // Compare unsigned so not do a sign extend mov on 64 bit + if (LoadNUInt(ref first, offset) != LoadNUInt(ref second, offset)) + { + goto NotEqual; + } + offset += (nuint)sizeof(nuint); + } while (lengthToExamine > offset); + } + + // Do final compare as sizeof(nuint) from end rather than start + result = (LoadNUInt(ref first, lengthToExamine) == LoadNUInt(ref second, lengthToExamine)); + goto Result; } } - Equal: - return true; - NotEqual: // Workaround for https://github.com/dotnet/runtime/issues/8795 + // As there are so many true/false exit points the Jit will coalesce them to one location. + // We want them at the end so the conditional early exit jmps are all jmp forwards so the + // branch predictor in a uninitialized state will not take them e.g. + // - loops are conditional jmps backwards and predicted + // - exceptions are conditional fowards jmps and not predicted + NotEqual: return false; } @@ -1421,18 +1539,18 @@ public static unsafe int SequenceCompareTo(ref byte first, int firstLength, ref if (Unsafe.AreSame(ref first, ref second)) goto Equal; - IntPtr minLength = (IntPtr)((firstLength < secondLength) ? firstLength : secondLength); + nuint minLength = (nuint)(((uint)firstLength < (uint)secondLength) ? (uint)firstLength : (uint)secondLength); - IntPtr offset = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations - IntPtr lengthToExamine = (IntPtr)(void*)minLength; + nuint offset = 0; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations + nuint lengthToExamine = minLength; if (Avx2.IsSupported) { - if ((byte*)lengthToExamine >= (byte*)Vector256.Count) + if (lengthToExamine >= (nuint)Vector256.Count) { - lengthToExamine -= Vector256.Count; + lengthToExamine -= (nuint)Vector256.Count; uint matches; - while ((byte*)lengthToExamine > (byte*)offset) + while (lengthToExamine > offset) { matches = (uint)Avx2.MoveMask(Avx2.CompareEqual(LoadVector256(ref first, offset), LoadVector256(ref second, offset))); // Note that MoveMask has converted the equal vector elements into a set of bit flags, @@ -1442,7 +1560,7 @@ public static unsafe int SequenceCompareTo(ref byte first, int firstLength, ref if (matches == uint.MaxValue) { // All matched - offset += Vector256.Count; + offset += (nuint)Vector256.Count; continue; } @@ -1461,7 +1579,7 @@ public static unsafe int SequenceCompareTo(ref byte first, int firstLength, ref // Invert matches to find differences uint differences = ~matches; // Find bitflag offset of first difference and add to current offset - offset = (IntPtr)((int)(byte*)offset + BitOperations.TrailingZeroCount((int)differences)); + offset += (uint)BitOperations.TrailingZeroCount(differences); int result = Unsafe.AddByteOffset(ref first, offset).CompareTo(Unsafe.AddByteOffset(ref second, offset)); Debug.Assert(result != 0); @@ -1469,11 +1587,11 @@ public static unsafe int SequenceCompareTo(ref byte first, int firstLength, ref return result; } - if ((byte*)lengthToExamine >= (byte*)Vector128.Count) + if (lengthToExamine >= (nuint)Vector128.Count) { - lengthToExamine -= Vector128.Count; + lengthToExamine -= (nuint)Vector128.Count; uint matches; - if ((byte*)lengthToExamine > (byte*)offset) + if (lengthToExamine > offset) { matches = (uint)Sse2.MoveMask(Sse2.CompareEqual(LoadVector128(ref first, offset), LoadVector128(ref second, offset))); // Note that MoveMask has converted the equal vector elements into a set of bit flags, @@ -1498,7 +1616,7 @@ public static unsafe int SequenceCompareTo(ref byte first, int firstLength, ref // Invert matches to find differences uint differences = ~matches; // Find bitflag offset of first difference and add to current offset - offset = (IntPtr)((int)(byte*)offset + BitOperations.TrailingZeroCount((int)differences)); + offset += (uint)BitOperations.TrailingZeroCount(differences); int result = Unsafe.AddByteOffset(ref first, offset).CompareTo(Unsafe.AddByteOffset(ref second, offset)); Debug.Assert(result != 0); @@ -1508,11 +1626,11 @@ public static unsafe int SequenceCompareTo(ref byte first, int firstLength, ref } else if (Sse2.IsSupported) { - if ((byte*)lengthToExamine >= (byte*)Vector128.Count) + if (lengthToExamine >= (nuint)Vector128.Count) { - lengthToExamine -= Vector128.Count; + lengthToExamine -= (nuint)Vector128.Count; uint matches; - while ((byte*)lengthToExamine > (byte*)offset) + while (lengthToExamine > offset) { matches = (uint)Sse2.MoveMask(Sse2.CompareEqual(LoadVector128(ref first, offset), LoadVector128(ref second, offset))); // Note that MoveMask has converted the equal vector elements into a set of bit flags, @@ -1522,7 +1640,7 @@ public static unsafe int SequenceCompareTo(ref byte first, int firstLength, ref if (matches == ushort.MaxValue) { // All matched - offset += Vector128.Count; + offset += (nuint)Vector128.Count; continue; } @@ -1541,7 +1659,7 @@ public static unsafe int SequenceCompareTo(ref byte first, int firstLength, ref // Invert matches to find differences uint differences = ~matches; // Find bitflag offset of first difference and add to current offset - offset = (IntPtr)((int)(byte*)offset + BitOperations.TrailingZeroCount((int)differences)); + offset += (uint)BitOperations.TrailingZeroCount(differences); int result = Unsafe.AddByteOffset(ref first, offset).CompareTo(Unsafe.AddByteOffset(ref second, offset)); Debug.Assert(result != 0); @@ -1551,36 +1669,36 @@ public static unsafe int SequenceCompareTo(ref byte first, int firstLength, ref } else if (Vector.IsHardwareAccelerated) { - if ((byte*)lengthToExamine > (byte*)Vector.Count) + if (lengthToExamine > (nuint)Vector.Count) { - lengthToExamine -= Vector.Count; - while ((byte*)lengthToExamine > (byte*)offset) + lengthToExamine -= (nuint)Vector.Count; + while (lengthToExamine > offset) { if (LoadVector(ref first, offset) != LoadVector(ref second, offset)) { goto BytewiseCheck; } - offset += Vector.Count; + offset += (nuint)Vector.Count; } goto BytewiseCheck; } } - if ((byte*)lengthToExamine > (byte*)sizeof(UIntPtr)) + if (lengthToExamine > (nuint)sizeof(nuint)) { - lengthToExamine -= sizeof(UIntPtr); - while ((byte*)lengthToExamine > (byte*)offset) + lengthToExamine -= (nuint)sizeof(nuint); + while (lengthToExamine > offset) { - if (LoadUIntPtr(ref first, offset) != LoadUIntPtr(ref second, offset)) + if (LoadNUInt(ref first, offset) != LoadNUInt(ref second, offset)) { goto BytewiseCheck; } - offset += sizeof(UIntPtr); + offset += (nuint)sizeof(nuint); } } BytewiseCheck: // Workaround for https://github.com/dotnet/runtime/issues/8795 - while ((byte*)minLength > (byte*)offset) + while (minLength > offset) { int result = Unsafe.AddByteOffset(ref first, offset).CompareTo(Unsafe.AddByteOffset(ref second, offset)); if (result != 0) @@ -1615,89 +1733,75 @@ private static int LocateLastFoundByte(Vector match) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int LocateFirstFoundByte(ulong match) - { - if (Bmi1.X64.IsSupported) - { - return (int)(Bmi1.X64.TrailingZeroCount(match) >> 3); - } - else - { - // Flag least significant power of two bit - ulong powerOfTwoFlag = match ^ (match - 1); - // Shift all powers of two into the high byte and extract - return (int)((powerOfTwoFlag * XorPowerOfTwoToHighByte) >> 57); - } - } + => BitOperations.TrailingZeroCount(match) >> 3; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int LocateLastFoundByte(ulong match) - { - return 7 - (BitOperations.LeadingZeroCount(match) >> 3); - } + => BitOperations.Log2(match) >> 3; - private const ulong XorPowerOfTwoToHighByte = (0x07ul | - 0x06ul << 8 | - 0x05ul << 16 | - 0x04ul << 24 | - 0x03ul << 32 | - 0x02ul << 40 | - 0x01ul << 48) + 1; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ushort LoadUShort(ref byte start) + => Unsafe.ReadUnaligned(ref start); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint LoadUInt(ref byte start) + => Unsafe.ReadUnaligned(ref start); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe short LoadShort(ref byte start, IntPtr offset) - => Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref start, offset)); + private static uint LoadUInt(ref byte start, nuint offset) + => Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref start, offset)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe int LoadInt(ref byte start, IntPtr offset) - => Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref start, offset)); + private static nuint LoadNUInt(ref byte start) + => Unsafe.ReadUnaligned(ref start); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe UIntPtr LoadUIntPtr(ref byte start, IntPtr offset) - => Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref start, offset)); + private static nuint LoadNUInt(ref byte start, nuint offset) + => Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref start, offset)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe Vector LoadVector(ref byte start, IntPtr offset) + private static Vector LoadVector(ref byte start, nuint offset) => Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref start, offset)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe Vector128 LoadVector128(ref byte start, IntPtr offset) + private static Vector128 LoadVector128(ref byte start, nuint offset) => Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref start, offset)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe Vector256 LoadVector256(ref byte start, IntPtr offset) + private static Vector256 LoadVector256(ref byte start, nuint offset) => Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref start, offset)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe IntPtr GetByteVectorSpanLength(IntPtr offset, int length) - => (IntPtr)((length - (int)(byte*)offset) & ~(Vector.Count - 1)); + private static nuint GetByteVectorSpanLength(nuint offset, int length) + => (nuint)(uint)((length - (int)offset) & ~(Vector.Count - 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe IntPtr GetByteVector128SpanLength(IntPtr offset, int length) - => (IntPtr)((length - (int)(byte*)offset) & ~(Vector128.Count - 1)); + private static nuint GetByteVector128SpanLength(nuint offset, int length) + => (nuint)(uint)((length - (int)offset) & ~(Vector128.Count - 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe IntPtr GetByteVector256SpanLength(IntPtr offset, int length) - => (IntPtr)((length - (int)(byte*)offset) & ~(Vector256.Count - 1)); + private static nuint GetByteVector256SpanLength(nuint offset, int length) + => (nuint)(uint)((length - (int)offset) & ~(Vector256.Count - 1)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe IntPtr UnalignedCountVector(ref byte searchSpace) + private static unsafe nuint UnalignedCountVector(ref byte searchSpace) { - int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector.Count - 1); - return (IntPtr)((Vector.Count - unaligned) & (Vector.Count - 1)); + nint unaligned = (nint)Unsafe.AsPointer(ref searchSpace) & (Vector.Count - 1); + return (nuint)((Vector.Count - unaligned) & (Vector.Count - 1)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe IntPtr UnalignedCountVector128(ref byte searchSpace) + private static unsafe nuint UnalignedCountVector128(ref byte searchSpace) { - int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector128.Count - 1); - return (IntPtr)((Vector128.Count - unaligned) & (Vector128.Count - 1)); + nint unaligned = (nint)Unsafe.AsPointer(ref searchSpace) & (Vector128.Count - 1); + return (nuint)(uint)((Vector128.Count - unaligned) & (Vector128.Count - 1)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe IntPtr UnalignedCountVectorFromEnd(ref byte searchSpace, int length) + private static unsafe nuint UnalignedCountVectorFromEnd(ref byte searchSpace, int length) { - int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector.Count - 1); - return (IntPtr)(((length & (Vector.Count - 1)) + unaligned) & (Vector.Count - 1)); + nint unaligned = (nint)Unsafe.AsPointer(ref searchSpace) & (Vector.Count - 1); + return (nuint)(uint)(((length & (Vector.Count - 1)) + unaligned) & (Vector.Count - 1)); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs index d0426d0889a2a2..02f0ba9920724f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs @@ -10,15 +10,6 @@ using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -using nint = System.Int64; -#else -using nuint = System.UInt32; -using nint = System.Int32; -#endif - namespace System { internal static partial class SpanHelpers // .Char @@ -54,7 +45,7 @@ public static int IndexOf(ref char searchSpace, int searchSpaceLength, ref char if (SequenceEqual( ref Unsafe.As(ref Unsafe.Add(ref searchSpace, index + 1)), ref Unsafe.As(ref valueTail), - (nuint)valueTailLength * 2)) + (nuint)(uint)valueTailLength * 2)) { return index; // The tail matched. Return a successful find. } @@ -76,51 +67,51 @@ public static unsafe int SequenceCompareTo(ref char first, int firstLength, ref if (Unsafe.AreSame(ref first, ref second)) goto Equal; - IntPtr minLength = (IntPtr)((firstLength < secondLength) ? firstLength : secondLength); - IntPtr i = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations + nuint minLength = (nuint)(((uint)firstLength < (uint)secondLength) ? (uint)firstLength : (uint)secondLength); + nuint i = 0; // Use nuint for arithmetic to avoid unnecessary 64->32->64 truncations - if ((byte*)minLength >= (byte*)(sizeof(UIntPtr) / sizeof(char))) + if (minLength >= (nuint)(sizeof(nuint) / sizeof(char))) { - if (Vector.IsHardwareAccelerated && (byte*)minLength >= (byte*)Vector.Count) + if (Vector.IsHardwareAccelerated && minLength >= (nuint)Vector.Count) { - IntPtr nLength = minLength - Vector.Count; + nuint nLength = minLength - (nuint)Vector.Count; do { - if (Unsafe.ReadUnaligned>(ref Unsafe.As(ref Unsafe.Add(ref first, i))) != - Unsafe.ReadUnaligned>(ref Unsafe.As(ref Unsafe.Add(ref second, i)))) + if (Unsafe.ReadUnaligned>(ref Unsafe.As(ref Unsafe.Add(ref first, (nint)i))) != + Unsafe.ReadUnaligned>(ref Unsafe.As(ref Unsafe.Add(ref second, (nint)i)))) { break; } - i += Vector.Count; + i += (nuint)Vector.Count; } - while ((byte*)nLength >= (byte*)i); + while (nLength >= i); } - while ((byte*)minLength >= (byte*)(i + sizeof(UIntPtr) / sizeof(char))) + while (minLength >= (i + (nuint)(sizeof(nuint) / sizeof(char)))) { - if (Unsafe.ReadUnaligned(ref Unsafe.As(ref Unsafe.Add(ref first, i))) != - Unsafe.ReadUnaligned(ref Unsafe.As(ref Unsafe.Add(ref second, i)))) + if (Unsafe.ReadUnaligned (ref Unsafe.As(ref Unsafe.Add(ref first, (nint)i))) != + Unsafe.ReadUnaligned(ref Unsafe.As(ref Unsafe.Add(ref second, (nint)i)))) { break; } - i += sizeof(UIntPtr) / sizeof(char); + i += (nuint)(sizeof(nuint) / sizeof(char)); } } #if TARGET_64BIT - if ((byte*)minLength >= (byte*)(i + sizeof(int) / sizeof(char))) + if (minLength >= (i + sizeof(int) / sizeof(char))) { - if (Unsafe.ReadUnaligned(ref Unsafe.As(ref Unsafe.Add(ref first, i))) == - Unsafe.ReadUnaligned(ref Unsafe.As(ref Unsafe.Add(ref second, i)))) + if (Unsafe.ReadUnaligned(ref Unsafe.As(ref Unsafe.Add(ref first, (nint)i))) == + Unsafe.ReadUnaligned(ref Unsafe.As(ref Unsafe.Add(ref second, (nint)i)))) { i += sizeof(int) / sizeof(char); } } #endif - while ((byte*)i < (byte*)minLength) + while (i < minLength) { - int result = Unsafe.Add(ref first, i).CompareTo(Unsafe.Add(ref second, i)); + int result = Unsafe.Add(ref first, (nint)i).CompareTo(Unsafe.Add(ref second, (nint)i)); if (result != 0) return result; i += 1; @@ -287,7 +278,7 @@ public static unsafe int IndexOf(ref char searchSpace, char value, int length) if (offset < length) { Debug.Assert(length - offset >= Vector128.Count); - if (((nint)Unsafe.AsPointer(ref Unsafe.Add(ref searchSpace, (IntPtr)offset)) & (nint)(Vector256.Count - 1)) != 0) + if (((nint)Unsafe.AsPointer(ref Unsafe.Add(ref searchSpace, (nint)offset)) & (nint)(Vector256.Count - 1)) != 0) { // Not currently aligned to Vector256 (is aligned to Vector128); this can cause a problem for searches // with no upper bound e.g. String.wcslen. Start with a check on Vector128 to align to Vector256, @@ -984,27 +975,7 @@ private static int LocateFirstFoundChar(Vector match) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int LocateFirstFoundChar(ulong match) - { - // TODO: Arm variants - if (Bmi1.X64.IsSupported) - { - return (int)(Bmi1.X64.TrailingZeroCount(match) >> 4); - } - else - { - unchecked - { - // Flag least significant power of two bit - ulong powerOfTwoFlag = match ^ (match - 1); - // Shift all powers of two into the high byte and extract - return (int)((powerOfTwoFlag * XorPowerOfTwoToHighChar) >> 49); - } - } - } - - private const ulong XorPowerOfTwoToHighChar = (0x03ul | - 0x02ul << 16 | - 0x01ul << 32) + 1; + => BitOperations.TrailingZeroCount(match) >> 4; // Vector sub-search adapted from https://github.com/aspnet/KestrelHttpServer/pull/1138 [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1029,28 +1000,26 @@ private static int LocateLastFoundChar(Vector match) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int LocateLastFoundChar(ulong match) - { - return 3 - (BitOperations.LeadingZeroCount(match) >> 4); - } + => BitOperations.Log2(match) >> 4; [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe Vector LoadVector(ref char start, nint offset) - => Unsafe.ReadUnaligned>(ref Unsafe.As(ref Unsafe.Add(ref start, (IntPtr)offset))); + private static Vector LoadVector(ref char start, nint offset) + => Unsafe.ReadUnaligned>(ref Unsafe.As(ref Unsafe.Add(ref start, offset))); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe Vector128 LoadVector128(ref char start, nint offset) - => Unsafe.ReadUnaligned>(ref Unsafe.As(ref Unsafe.Add(ref start, (IntPtr)offset))); + private static Vector128 LoadVector128(ref char start, nint offset) + => Unsafe.ReadUnaligned>(ref Unsafe.As(ref Unsafe.Add(ref start, offset))); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe Vector256 LoadVector256(ref char start, nint offset) - => Unsafe.ReadUnaligned>(ref Unsafe.As(ref Unsafe.Add(ref start, (IntPtr)offset))); + private static Vector256 LoadVector256(ref char start, nint offset) + => Unsafe.ReadUnaligned>(ref Unsafe.As(ref Unsafe.Add(ref start, offset))); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe nint GetCharVectorSpanLength(nint offset, nint length) + private static nint GetCharVectorSpanLength(nint offset, nint length) => (length - offset) & ~(Vector.Count - 1); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe nint GetCharVector128SpanLength(nint offset, nint length) + private static nint GetCharVector128SpanLength(nint offset, nint length) => (length - offset) & ~(Vector128.Count - 1); [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.cs index ddd2416eceaea0..24e82c21a8267e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.cs @@ -6,13 +6,6 @@ using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System { internal static partial class SpanHelpers @@ -348,14 +341,14 @@ public static unsafe void ClearWithReferences(ref IntPtr ip, nuint pointerSizeLe for (; pointerSizeLength >= 8; pointerSizeLength -= 8) { - Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -1) = default; - Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -2) = default; - Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -3) = default; - Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -4) = default; - Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -5) = default; - Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -6) = default; - Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -7) = default; - Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -8) = default; + Unsafe.Add(ref Unsafe.Add(ref ip, (nint)pointerSizeLength), -1) = default; + Unsafe.Add(ref Unsafe.Add(ref ip, (nint)pointerSizeLength), -2) = default; + Unsafe.Add(ref Unsafe.Add(ref ip, (nint)pointerSizeLength), -3) = default; + Unsafe.Add(ref Unsafe.Add(ref ip, (nint)pointerSizeLength), -4) = default; + Unsafe.Add(ref Unsafe.Add(ref ip, (nint)pointerSizeLength), -5) = default; + Unsafe.Add(ref Unsafe.Add(ref ip, (nint)pointerSizeLength), -6) = default; + Unsafe.Add(ref Unsafe.Add(ref ip, (nint)pointerSizeLength), -7) = default; + Unsafe.Add(ref Unsafe.Add(ref ip, (nint)pointerSizeLength), -8) = default; } Debug.Assert(pointerSizeLength <= 7); @@ -396,15 +389,15 @@ public static unsafe void ClearWithReferences(ref IntPtr ip, nuint pointerSizeLe // Write first four and last three. Unsafe.Add(ref ip, 2) = default; Unsafe.Add(ref ip, 3) = default; - Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -3) = default; - Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -2) = default; + Unsafe.Add(ref Unsafe.Add(ref ip, (nint)pointerSizeLength), -3) = default; + Unsafe.Add(ref Unsafe.Add(ref ip, (nint)pointerSizeLength), -2) = default; Write2To3: Debug.Assert(pointerSizeLength >= 2); // Write first two and last one. Unsafe.Add(ref ip, 1) = default; - Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -1) = default; + Unsafe.Add(ref Unsafe.Add(ref ip, (nint)pointerSizeLength), -1) = default; Write1: Debug.Assert(pointerSizeLength >= 1); diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs b/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs index 5ceed67a563a94..1708b2cb1e3289 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs @@ -10,13 +10,6 @@ using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System { public partial class String diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs index a15d9b99950248..2fe2781e2b71b8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs @@ -968,7 +968,7 @@ public string Remove(int startIndex) public string Replace(string oldValue, string? newValue, bool ignoreCase, CultureInfo? culture) { - return ReplaceCore(oldValue, newValue, culture, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None); + return ReplaceCore(oldValue, newValue, culture?.CompareInfo, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None); } public string Replace(string oldValue, string? newValue, StringComparison comparisonType) @@ -977,78 +977,92 @@ public string Replace(string oldValue, string? newValue, StringComparison compar { case StringComparison.CurrentCulture: case StringComparison.CurrentCultureIgnoreCase: - return ReplaceCore(oldValue, newValue, CultureInfo.CurrentCulture, GetCaseCompareOfComparisonCulture(comparisonType)); + return ReplaceCore(oldValue, newValue, CultureInfo.CurrentCulture.CompareInfo, GetCaseCompareOfComparisonCulture(comparisonType)); case StringComparison.InvariantCulture: case StringComparison.InvariantCultureIgnoreCase: - return ReplaceCore(oldValue, newValue, CultureInfo.InvariantCulture, GetCaseCompareOfComparisonCulture(comparisonType)); + return ReplaceCore(oldValue, newValue, CompareInfo.Invariant, GetCaseCompareOfComparisonCulture(comparisonType)); case StringComparison.Ordinal: return Replace(oldValue, newValue); case StringComparison.OrdinalIgnoreCase: - return ReplaceCore(oldValue, newValue, CultureInfo.InvariantCulture, CompareOptions.OrdinalIgnoreCase); + return ReplaceCore(oldValue, newValue, CompareInfo.Invariant, CompareOptions.OrdinalIgnoreCase); default: throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); } } - private unsafe string ReplaceCore(string oldValue, string? newValue, CultureInfo? culture, CompareOptions options) + private string ReplaceCore(string oldValue, string? newValue, CompareInfo? ci, CompareOptions options) { - if (oldValue == null) + if (oldValue is null) + { throw new ArgumentNullException(nameof(oldValue)); + } + if (oldValue.Length == 0) + { throw new ArgumentException(SR.Argument_StringZeroLength, nameof(oldValue)); + } // If they asked to replace oldValue with a null, replace all occurrences - // with the empty string. - newValue ??= string.Empty; + // with the empty string. AsSpan() will normalize appropriately. + // + // If inner ReplaceCore method returns null, it means no substitutions were + // performed, so as an optimization we'll return the original string. - CultureInfo referenceCulture = culture ?? CultureInfo.CurrentCulture; - var result = new ValueStringBuilder(stackalloc char[256]); - result.EnsureCapacity(this.Length); + return ReplaceCore(this, oldValue.AsSpan(), newValue.AsSpan(), ci ?? CultureInfo.CurrentCulture.CompareInfo, options) + ?? this; + } - int startIndex = 0; - int index = 0; + private static unsafe string? ReplaceCore(ReadOnlySpan searchSpace, ReadOnlySpan oldValue, ReadOnlySpan newValue, CompareInfo compareInfo, CompareOptions options) + { + Debug.Assert(!oldValue.IsEmpty); + Debug.Assert(compareInfo != null); - int matchLength = 0; + var result = new ValueStringBuilder(stackalloc char[256]); + result.EnsureCapacity(searchSpace.Length); + int matchLength = 0; bool hasDoneAnyReplacements = false; - CompareInfo ci = referenceCulture.CompareInfo; - do + while (true) { - index = ci.IndexOf(this, oldValue, startIndex, this.Length - startIndex, options, &matchLength); + int index = compareInfo.IndexOf(searchSpace, oldValue, &matchLength, options, fromBeginning: true); // There's the possibility that 'oldValue' has zero collation weight (empty string equivalent). // If this is the case, we behave as if there are no more substitutions to be made. - if (index >= 0 && matchLength > 0) + if (index < 0 || matchLength == 0) { - // append the unmodified portion of string - result.Append(this.AsSpan(startIndex, index - startIndex)); + break; + } - // append the replacement - result.Append(newValue); + // append the unmodified portion of search space + result.Append(searchSpace.Slice(0, index)); - startIndex = index + matchLength; - hasDoneAnyReplacements = true; - } - else if (!hasDoneAnyReplacements) - { - // small optimization, - // if we have not done any replacements, - // we will return the original string - result.Dispose(); - return this; - } - else - { - result.Append(this.AsSpan(startIndex, this.Length - startIndex)); - } - } while (index >= 0); + // append the replacement + result.Append(newValue); + + searchSpace = searchSpace.Slice(index + matchLength); + hasDoneAnyReplacements = true; + } + + // Didn't find 'oldValue' in the remaining search space, or the match + // consisted only of zero collation weight characters. As an optimization, + // if we have not yet performed any replacements, we'll save the + // allocation. + + if (!hasDoneAnyReplacements) + { + result.Dispose(); + return null; + } + + // Append what remains of the search space, then allocate the new string. + result.Append(searchSpace); return result.ToString(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Searching.cs b/src/libraries/System.Private.CoreLib/src/System/String.Searching.cs index 93de7fa440259b..77162ee23a61a5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Searching.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Searching.cs @@ -310,16 +310,6 @@ public int IndexOf(string value, int startIndex) public int IndexOf(string value, int startIndex, int count) { - if (startIndex < 0 || startIndex > this.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - - if (count < 0 || count > this.Length - startIndex) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - } - return IndexOf(value, startIndex, count, StringComparison.CurrentCulture); } @@ -335,26 +325,7 @@ public int IndexOf(string value, int startIndex, StringComparison comparisonType public int IndexOf(string value, int startIndex, int count, StringComparison comparisonType) { - // Validate inputs - if (value == null) - throw new ArgumentNullException(nameof(value)); - - if (startIndex < 0 || startIndex > this.Length) - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - - if (count < 0 || startIndex > this.Length - count) - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - - if (comparisonType == StringComparison.Ordinal) - { - int result = SpanHelpers.IndexOf( - ref Unsafe.Add(ref this._firstChar, startIndex), - count, - ref value._firstChar, - value.Length); - - return (result >= 0 ? startIndex : 0) + result; - } + // Parameter checking will be done by CompareInfo.IndexOf. switch (comparisonType) { @@ -366,11 +337,14 @@ ref Unsafe.Add(ref this._firstChar, startIndex), case StringComparison.InvariantCultureIgnoreCase: return CompareInfo.Invariant.IndexOf(this, value, startIndex, count, GetCaseCompareOfComparisonCulture(comparisonType)); + case StringComparison.Ordinal: case StringComparison.OrdinalIgnoreCase: - return CompareInfo.IndexOfOrdinal(this, value, startIndex, count, GetCaseCompareOfComparisonCulture(comparisonType) != CompareOptions.None); + return CompareInfo.Invariant.IndexOf(this, value, startIndex, count, GetCompareOptionsFromOrdinalStringComparison(comparisonType)); default: - throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); + throw (value is null) + ? new ArgumentNullException(nameof(value)) + : new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); } } @@ -498,11 +472,6 @@ public int LastIndexOf(string value, int startIndex) public int LastIndexOf(string value, int startIndex, int count) { - if (count < 0) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - } - return LastIndexOf(value, startIndex, count, StringComparison.CurrentCulture); } diff --git a/src/libraries/System.Private.CoreLib/src/System/String.cs b/src/libraries/System.Private.CoreLib/src/System/String.cs index f29d327a260d44..00582d5ebca437 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.cs @@ -378,6 +378,28 @@ public static string Create(int length, TState state, SpanAction(string? value) => value != null ? new ReadOnlySpan(ref value.GetRawStringData(), value.Length) : default; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal bool TryGetSpan(int startIndex, int count, out ReadOnlySpan slice) + { +#if TARGET_64BIT + // See comment in Span.Slice for how this works. + if ((ulong)(uint)startIndex + (ulong)(uint)count > (ulong)(uint)Length) + { + slice = default; + return false; + } +#else + if ((uint)startIndex > (uint)Length || (uint)count > (uint)(Length - startIndex)) + { + slice = default; + return false; + } +#endif + + slice = new ReadOnlySpan(ref Unsafe.Add(ref _firstChar, startIndex), count); + return true; + } + public object Clone() { return this; diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/ASCIIUtility.Helpers.cs b/src/libraries/System.Private.CoreLib/src/System/Text/ASCIIUtility.Helpers.cs index 731d52ab822cca..71f984bbd4cfd8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/ASCIIUtility.Helpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/ASCIIUtility.Helpers.cs @@ -44,44 +44,19 @@ internal static uint CountNumberOfLeadingAsciiBytesFromUInt32WithSomeNonAsciiDat { Debug.Assert(!AllBytesInUInt32AreAscii(value), "Caller shouldn't provide an all-ASCII value."); - // Use BMI1 directly rather than going through BitOperations. We only see a perf gain here - // if we're able to emit a real tzcnt instruction; the software fallback used by BitOperations - // is too slow for our purposes since we can provide our own faster, specialized software fallback. - - if (Bmi1.IsSupported) - { - Debug.Assert(BitConverter.IsLittleEndian); - return Bmi1.TrailingZeroCount(value & UInt32HighBitsOnlyMask) >> 3; - } - - // Couldn't emit tzcnt, use specialized software fallback. - // The 'allBytesUpToNowAreAscii' DWORD uses bit twiddling to hold a 1 or a 0 depending - // on whether all processed bytes were ASCII. Then we accumulate all of the - // results to calculate how many consecutive ASCII bytes are present. - - value = ~value; - if (BitConverter.IsLittleEndian) { - // Read first byte - value >>= 7; - uint allBytesUpToNowAreAscii = value & 1; - uint numAsciiBytes = allBytesUpToNowAreAscii; - - // Read second byte - value >>= 8; - allBytesUpToNowAreAscii &= value; - numAsciiBytes += allBytesUpToNowAreAscii; - - // Read third byte - value >>= 8; - allBytesUpToNowAreAscii &= value; - numAsciiBytes += allBytesUpToNowAreAscii; - - return numAsciiBytes; + return (uint)BitOperations.TrailingZeroCount(value & UInt32HighBitsOnlyMask) >> 3; } else { + // Couldn't use tzcnt, use specialized software fallback. + // The 'allBytesUpToNowAreAscii' DWORD uses bit twiddling to hold a 1 or a 0 depending + // on whether all processed bytes were ASCII. Then we accumulate all of the + // results to calculate how many consecutive ASCII bytes are present. + + value = ~value; + // BinaryPrimitives.ReverseEndianness is only implemented as an intrinsic on // little-endian platforms, so using it in this big-endian path would be too // expensive. Instead we'll just change how we perform the shifts. diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/ASCIIUtility.cs b/src/libraries/System.Private.CoreLib/src/System/Text/ASCIIUtility.cs index c0bdbf03f70599..57492533d199ad 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/ASCIIUtility.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/ASCIIUtility.cs @@ -12,32 +12,10 @@ using Internal.Runtime.CompilerServices; #endif -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if SYSTEM_PRIVATE_CORELIB -#if TARGET_64BIT -using nint = System.Int64; -using nuint = System.UInt64; -#else // TARGET_64BIT -using nint = System.Int32; -using nuint = System.UInt32; -#endif // TARGET_64BIT -#else -using nint = System.Int64; // https://github.com/dotnet/runtime/issues/33575 - use long/ulong outside of corelib until the compiler supports it -using nuint = System.UInt64; -#endif - namespace System.Text { internal static partial class ASCIIUtility { -#if DEBUG && SYSTEM_PRIVATE_CORELIB - static ASCIIUtility() - { - Debug.Assert(sizeof(nint) == IntPtr.Size && nint.MinValue < 0, "nint is defined incorrectly."); - Debug.Assert(sizeof(nuint) == IntPtr.Size && nuint.MinValue == 0, "nuint is defined incorrectly."); - } -#endif // DEBUG && SYSTEM_PRIVATE_CORELIB - [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool AllBytesInUInt64AreAscii(ulong value) { @@ -410,7 +388,7 @@ private static unsafe nuint GetIndexOfFirstNonAsciiByte_Sse2(byte* pBuffer, nuin if ((bufferLength & 8) != 0) { - if (Bmi1.X64.IsSupported) + if (UIntPtr.Size == sizeof(ulong)) { // If we can use 64-bit tzcnt to count the number of leading ASCII bytes, prefer it. @@ -418,10 +396,10 @@ private static unsafe nuint GetIndexOfFirstNonAsciiByte_Sse2(byte* pBuffer, nuin if (!AllBytesInUInt64AreAscii(candidateUInt64)) { // Clear everything but the high bit of each byte, then tzcnt. - // Remember the / 8 at the end to convert bit count to byte count. + // Remember to divide by 8 at the end to convert bit count to byte count. candidateUInt64 &= UInt64HighBitsOnlyMask; - pBuffer += (nuint)(Bmi1.X64.TrailingZeroCount(candidateUInt64) / 8); + pBuffer += (nuint)(BitOperations.TrailingZeroCount(candidateUInt64) >> 3); goto Finish; } } @@ -524,7 +502,9 @@ private static unsafe nuint GetIndexOfFirstNonAsciiChar_Default(char* pBuffer, n char* pOriginalBuffer = pBuffer; +#if SYSTEM_PRIVATE_CORELIB Debug.Assert(bufferLength <= nuint.MaxValue / sizeof(char)); +#endif // Before we drain off char-by-char, try a generic vectorized loop. // Only run the loop if we have at least two vectors we can pull out. @@ -687,7 +667,9 @@ private static unsafe nuint GetIndexOfFirstNonAsciiChar_Sse2(char* pBuffer, nuin Vector128 asciiMaskForPADDUSW = Vector128.Create((ushort)0x7F80); // used for PADDUSW const uint NonAsciiDataSeenMask = 0b_1010_1010_1010_1010; // used for determining whether 'currentMask' contains non-ASCII data +#if SYSTEM_PRIVATE_CORELIB Debug.Assert(bufferLength <= nuint.MaxValue / sizeof(char)); +#endif // Read the first vector unaligned. @@ -932,7 +914,7 @@ private static unsafe nuint GetIndexOfFirstNonAsciiChar_Sse2(char* pBuffer, nuin if ((bufferLength & 4) != 0) { - if (Bmi1.X64.IsSupported) + if (UIntPtr.Size == sizeof(ulong)) { // If we can use 64-bit tzcnt to count the number of leading ASCII chars, prefer it. @@ -940,12 +922,12 @@ private static unsafe nuint GetIndexOfFirstNonAsciiChar_Sse2(char* pBuffer, nuin if (!AllCharsInUInt64AreAscii(candidateUInt64)) { // Clear the low 7 bits (the ASCII bits) of each char, then tzcnt. - // Remember the / 8 at the end to convert bit count to byte count, + // Remember to divide by 8 at the end to convert bit count to byte count, // then the & ~1 at the end to treat a match in the high byte of // any char the same as a match in the low byte of that same char. candidateUInt64 &= 0xFF80FF80_FF80FF80ul; - pBuffer = (char*)((byte*)pBuffer + ((nuint)(Bmi1.X64.TrailingZeroCount(candidateUInt64) / 8) & ~(nuint)1)); + pBuffer = (char*)((byte*)pBuffer + ((nuint)(BitOperations.TrailingZeroCount(candidateUInt64) >> 3) & ~(nuint)1)); goto Finish; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/EncoderNLS.cs b/src/libraries/System.Private.CoreLib/src/System/Text/EncoderNLS.cs index 5135bc0be4d740..bea5bf2ce6685f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/EncoderNLS.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/EncoderNLS.cs @@ -366,27 +366,33 @@ internal bool TryDrainLeftoverDataForGetBytes(ReadOnlySpan chars, Span chars, Span _codePage + this.EncoderFallback.GetHashCode() + this.DecoderFallback.GetHashCode(); + /// + /// Creates a which serves to transcode data between an inner + /// and an outer , similar to . + /// + /// The to wrap. + /// The associated with . + /// The associated with the returned + /// by this method. + /// if disposing the returned by this method + /// should not dispose . + /// A which transcodes the contents of + /// as . + /// + /// The returned 's and properties + /// will reflect whether is readable or writable. If + /// is full-duplex, the returned will be as well. However, the returned + /// is not seekable, even if 's property returns . + /// + public static Stream CreateTranscodingStream(Stream innerStream, Encoding innerStreamEncoding, Encoding outerStreamEncoding, bool leaveOpen = false) + { + if (innerStream is null) + { + throw new ArgumentNullException(nameof(innerStream)); + } + + if (innerStreamEncoding is null) + { + throw new ArgumentNullException(nameof(innerStreamEncoding)); + } + + if (outerStreamEncoding is null) + { + throw new ArgumentNullException(nameof(outerStreamEncoding)); + } + + // We can't entirely optimize away the case where innerStreamEncoding == outerStreamEncoding. For example, + // the Encoding might perform a lossy conversion when it sees invalid data, so we still need to call it + // to perform basic validation. It's also possible that somebody subclassed one of the built-in types + // like ASCIIEncoding or UTF8Encoding and is running some non-standard logic. If this becomes a bottleneck + // we can consider targeted optimizations in a future release. + + return new TranscodingStream(innerStream, innerStreamEncoding, outerStreamEncoding, leaveOpen); + } + internal virtual char[] GetBestFitUnicodeToBytesData() => // Normally we don't have any best fit data. Array.Empty(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Rune.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Rune.cs index 3a703d661ff789..b2cbe18b02b902 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Rune.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Rune.cs @@ -20,6 +20,9 @@ namespace System.Text [DebuggerDisplay("{DebuggerDisplay,nq}")] public readonly struct Rune : IComparable, IEquatable { + internal const int MaxUtf16CharsPerRune = 2; // supplementary plane code points are encoded as 2 UTF-16 code units + internal const int MaxUtf8BytesPerRune = 4; // supplementary plane code points are encoded as 4 UTF-8 code units + private const char HighSurrogateStart = '\ud800'; private const char LowSurrogateStart = '\udc00'; private const int HighSurrogateRange = 0x3FF; @@ -163,7 +166,15 @@ private Rune(uint scalarValue, bool unused) /// /// The return value will be 1 or 2. /// - public int Utf16SequenceLength => UnicodeUtility.GetUtf16SequenceLength(_value); + public int Utf16SequenceLength + { + get + { + int codeUnitCount = UnicodeUtility.GetUtf16SequenceLength(_value); + Debug.Assert(codeUnitCount > 0 && codeUnitCount <= MaxUtf16CharsPerRune); + return codeUnitCount; + } + } /// /// Returns the length in code units of the @@ -172,7 +183,15 @@ private Rune(uint scalarValue, bool unused) /// /// The return value will be 1 through 4, inclusive. /// - public int Utf8SequenceLength => UnicodeUtility.GetUtf8SequenceLength(_value); + public int Utf8SequenceLength + { + get + { + int codeUnitCount = UnicodeUtility.GetUtf8SequenceLength(_value); + Debug.Assert(codeUnitCount > 0 && codeUnitCount <= MaxUtf8BytesPerRune); + return codeUnitCount; + } + } /// /// Returns the Unicode scalar value as an integer. @@ -185,8 +204,8 @@ private static Rune ChangeCaseCultureAware(Rune rune, TextInfo textInfo, bool to Debug.Assert(!GlobalizationMode.Invariant, "This should've been checked by the caller."); Debug.Assert(textInfo != null, "This should've been checked by the caller."); - Span original = stackalloc char[2]; // worst case scenario = 2 code units (for a surrogate pair) - Span modified = stackalloc char[2]; // case change should preserve UTF-16 code unit count + Span original = stackalloc char[MaxUtf16CharsPerRune]; + Span modified = stackalloc char[MaxUtf16CharsPerRune]; int charCount = rune.EncodeToUtf16(original); original = original.Slice(0, charCount); @@ -220,8 +239,8 @@ private static Rune ChangeCaseCultureAware(Rune rune, CultureInfo culture, bool Debug.Assert(!GlobalizationMode.Invariant, "This should've been checked by the caller."); Debug.Assert(culture != null, "This should've been checked by the caller."); - Span original = stackalloc char[2]; // worst case scenario = 2 code units (for a surrogate pair) - Span modified = stackalloc char[2]; // case change should preserve UTF-16 code unit count + Span original = stackalloc char[MaxUtf16CharsPerRune]; // worst case scenario = 2 code units (for a surrogate pair) + Span modified = stackalloc char[MaxUtf16CharsPerRune]; // case change should preserve UTF-16 code unit count int charCount = rune.EncodeToUtf16(original); original = original.Slice(0, charCount); @@ -885,7 +904,7 @@ public override string ToString() } else { - Span buffer = stackalloc char[2]; + Span buffer = stackalloc char[MaxUtf16CharsPerRune]; UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar(_value, out buffer[0], out buffer[1]); return buffer.ToString(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs index 1b18fd5eca51f1..bdff2d05df01e5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/StringBuilder.cs @@ -1144,7 +1144,9 @@ public StringBuilder Remove(int startIndex, int length) return this; } +#pragma warning disable CA1830 // Prefer strongly-typed Append and Insert method overloads on StringBuilder. No need to fix for the builder itself public StringBuilder Append(bool value) => Append(value.ToString()); +#pragma warning restore CA1830 public StringBuilder Append(char value) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/TranscodingStream.cs b/src/libraries/System.Private.CoreLib/src/System/Text/TranscodingStream.cs new file mode 100644 index 00000000000000..44f620635c131a --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Text/TranscodingStream.cs @@ -0,0 +1,598 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Text +{ + internal sealed class TranscodingStream : Stream + { + private const int DefaultReadByteBufferSize = 4 * 1024; // lifted from StreamReader.cs (FileStream) + + // We optimistically assume 1 byte ~ 1 char during transcoding. This is a good rule of thumb + // but isn't always appropriate: transcoding between single-byte and multi-byte encodings + // will violate this, as will any invalid data fixups performed by the transcoder itself. + // To account for these unknowns we have a minimum scratch buffer size we use during the + // transcoding process. This should be generous enough to account for even the largest + // fallback mechanism we're likely to see in the real world. + + private const int MinWriteRentedArraySize = 4 * 1024; + private const int MaxWriteRentedArraySize = 1024 * 1024; + + private readonly Encoding _innerEncoding; + private readonly Encoding _thisEncoding; + private Stream _innerStream; // null if the wrapper has been disposed + private readonly bool _leaveOpen; + + /* + * Fields used for writing bytes [this] -> chars -> bytes [inner] + * Lazily initialized the first time we need to write + */ + + private Encoder? _innerEncoder; + private Decoder? _thisDecoder; + + /* + * Fields used for reading bytes [inner] -> chars -> bytes [this] + * Lazily initialized the first time we need to read + */ + + private Encoder? _thisEncoder; + private Decoder? _innerDecoder; + private int _readCharBufferMaxSize; // the maximum number of characters _innerDecoder.ReadChars can return + private byte[]? _readBuffer; // contains the data that Read() should return + private int _readBufferOffset; + private int _readBufferCount; + + internal TranscodingStream(Stream innerStream, Encoding innerEncoding, Encoding thisEncoding, bool leaveOpen) + { + Debug.Assert(innerStream != null); + Debug.Assert(innerEncoding != null); + Debug.Assert(thisEncoding != null); + + _innerStream = innerStream; + _leaveOpen = leaveOpen; + + _innerEncoding = innerEncoding; + _thisEncoding = thisEncoding; + } + + /* + * Most CanXyz methods delegate to the inner stream, returning false + * if this instance has been disposed. CanSeek is always false. + */ + + public override bool CanRead => _innerStream?.CanRead ?? false; + + public override bool CanSeek => false; + + public override bool CanWrite => _innerStream?.CanWrite ?? false; + + public override long Length => throw new NotSupportedException(SR.NotSupported_UnseekableStream); + + public override long Position + { + get => throw new NotSupportedException(SR.NotSupported_UnseekableStream); + set => throw new NotSupportedException(SR.NotSupported_UnseekableStream); + } + + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) + => TaskToApm.Begin(ReadAsync(buffer, offset, count, CancellationToken.None), callback, state); + + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) + => TaskToApm.Begin(WriteAsync(buffer, offset, count, CancellationToken.None), callback, state); + + protected override void Dispose(bool disposing) + { + Debug.Assert(disposing, "This type isn't finalizable."); + + if (_innerStream is null) + { + return; // dispose called multiple times, ignore + } + + // First, flush any pending data to the inner stream. + + ArraySegment pendingData = FinalFlushWriteBuffers(); + if (pendingData.Count != 0) + { + _innerStream.Write(pendingData); + } + + // Mark our object as disposed + + Stream innerStream = _innerStream; + _innerStream = null!; + + // And dispose the inner stream if needed + + if (!_leaveOpen) + { + innerStream.Dispose(); + } + } + + public override ValueTask DisposeAsync() + { + if (_innerStream is null) + { + return default; // dispose called multiple times, ignore + } + + // First, get any pending data destined for the inner stream. + + ArraySegment pendingData = FinalFlushWriteBuffers(); + + if (pendingData.Count == 0) + { + // Fast path: just dispose of the object graph. + // No need to write anything to the stream first. + + Stream innerStream = _innerStream; + _innerStream = null!; + + return (_leaveOpen) + ? default /* no work to do */ + : innerStream.DisposeAsync(); + } + + // Slower path; need to perform an async write followed by an async dispose. + + return DisposeAsyncCore(pendingData); + async ValueTask DisposeAsyncCore(ArraySegment pendingData) + { + Debug.Assert(pendingData.Count != 0); + + Stream innerStream = _innerStream; + _innerStream = null!; + + await innerStream.WriteAsync(pendingData.AsMemory()).ConfigureAwait(false); + + if (!_leaveOpen) + { + await innerStream.DisposeAsync().ConfigureAwait(false); + } + } + } + + public override int EndRead(IAsyncResult asyncResult) + => TaskToApm.End(asyncResult); + + public override void EndWrite(IAsyncResult asyncResult) + => TaskToApm.End(asyncResult); + +#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant +#pragma warning disable CS8774 // Member must have a non-null value when exiting. + + // Sets up the data structures that are necessary before any read operation takes place, + // throwing if the object is in a state where reads are not possible. + [MemberNotNull(nameof(_innerDecoder), nameof(_thisEncoder), nameof(_readBuffer))] + private void EnsurePreReadConditions() + { + ThrowIfDisposed(); + if (_innerDecoder is null) + { + InitializeReadDataStructures(); + } + + void InitializeReadDataStructures() + { + if (!CanRead) + { + throw Error.GetReadNotSupported(); + } + + _innerDecoder = _innerEncoding.GetDecoder(); + _thisEncoder = _thisEncoding.GetEncoder(); + _readCharBufferMaxSize = _innerEncoding.GetMaxCharCount(DefaultReadByteBufferSize); + + // Can't use ArrayPool for the below array since it's an instance field of this object. + // But since we never expose the raw array contents to our callers we can get away + // with skipping the array zero-init during allocation. The segment points to the + // data which we haven't yet read; however, we own the entire backing array and can + // re-create the segment as needed once the array is repopulated. + + _readBuffer = GC.AllocateUninitializedArray(_thisEncoding.GetMaxByteCount(_readCharBufferMaxSize)); + } + } + + // Sets up the data structures that are necessary before any write operation takes place, + // throwing if the object is in a state where writes are not possible. + [MemberNotNull(nameof(_thisDecoder), nameof(_innerEncoder))] + private void EnsurePreWriteConditions() + { + ThrowIfDisposed(); + if (_innerEncoder is null) + { + InitializeReadDataStructures(); + } + + void InitializeReadDataStructures() + { + if (!CanWrite) + { + throw Error.GetWriteNotSupported(); + } + + _innerEncoder = _innerEncoding.GetEncoder(); + _thisDecoder = _thisEncoding.GetDecoder(); + } + } + +#pragma warning restore CS8774 // Member must have a non-null value when exiting. +#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant + + // returns any pending data that needs to be flushed to the inner stream before disposal + private ArraySegment FinalFlushWriteBuffers() + { + // If this stream was never used for writing, no-op. + + if (_thisDecoder is null || _innerEncoder is null) + { + return default; + } + + // convert bytes [this] -> chars + // Having leftover data in our buffers should be very rare since it should only + // occur if the end of the stream contains an incomplete multi-byte sequence. + // Let's not bother complicating this logic with array pool rentals or allocation- + // avoiding loops. + + + char[] chars = Array.Empty(); + int charCount = _thisDecoder.GetCharCount(Array.Empty(), 0, 0, flush: true); + if (charCount > 0) + { + chars = new char[charCount]; + charCount = _thisDecoder.GetChars(Array.Empty(), 0, 0, chars, 0, flush: true); + } + + // convert chars -> bytes [inner] + // It's possible that _innerEncoder might need to perform some end-of-text fixup + // (due to flush: true), even if _thisDecoder didn't need to do so. + + byte[] bytes = Array.Empty(); + int byteCount = _innerEncoder.GetByteCount(chars, 0, charCount, flush: true); + if (byteCount > 0) + { + bytes = new byte[byteCount]; + byteCount = _innerEncoder.GetBytes(chars, 0, charCount, bytes, 0, flush: true); + } + + return new ArraySegment(bytes, 0, byteCount); + } + + public override void Flush() + { + // Don't pass flush: true to our inner decoder + encoder here, since it could cause data + // corruption if a flush occurs mid-stream. Wait until the stream is being closed. + + ThrowIfDisposed(); + _innerStream.Flush(); + } + + public override Task FlushAsync(CancellationToken cancellationToken) + { + // Don't pass flush: true to our inner decoder + encoder here, since it could cause data + // corruption if a flush occurs mid-stream. Wait until the stream is being closed. + + ThrowIfDisposed(); + return _innerStream.FlushAsync(cancellationToken); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (buffer is null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + return Read(new Span(buffer, offset, count)); + } + + public override int Read(Span buffer) + { + EnsurePreReadConditions(); + + // If there's no data in our pending read buffer, we'll need to populate it from + // the inner stream. We read the inner stream's bytes, decode that to chars using + // the 'inner' encoding, then re-encode those chars under the 'this' encoding. + // We've already calculated the worst-case expansions for the intermediate buffers, + // so we use GetChars / GetBytes instead of Convert to simplify the below code + // and to ensure an exception is thrown if the Encoding reported an incorrect + // worst-case expansion. + + if (_readBufferCount == 0) + { + byte[] rentedBytes = ArrayPool.Shared.Rent(DefaultReadByteBufferSize); + char[] rentedChars = ArrayPool.Shared.Rent(_readCharBufferMaxSize); + + try + { + // Beware: Use our constant value instead of 'rentedBytes.Length' for the count + // parameter below. The reason for this is that the array pool could've returned + // a larger-than-expected array, but our worst-case expansion calculations + // performed earlier didn't take that into account. + + int innerBytesReadJustNow = _innerStream.Read(rentedBytes, 0, DefaultReadByteBufferSize); + bool isEofReached = (innerBytesReadJustNow == 0); + + // convert bytes [inner] -> chars, then convert chars -> bytes [this] + + int charsDecodedJustNow = _innerDecoder.GetChars(rentedBytes, 0, innerBytesReadJustNow, rentedChars, 0, flush: isEofReached); + int pendingReadDataPopulatedJustNow = _thisEncoder.GetBytes(rentedChars, 0, charsDecodedJustNow, _readBuffer, 0, flush: isEofReached); + + _readBufferOffset = 0; + _readBufferCount = pendingReadDataPopulatedJustNow; + } + finally + { + ArrayPool.Shared.Return(rentedBytes); + ArrayPool.Shared.Return(rentedChars); + } + } + + // At this point: (a) we've populated our pending read buffer and there's + // useful data to return to our caller; or (b) the pending read buffer is + // empty because the inner stream has reached EOF and all pending read data + // has already been flushed, and we should return 0. + + int bytesToReturn = Math.Min(_readBufferCount, buffer.Length); + _readBuffer.AsSpan(_readBufferOffset, bytesToReturn).CopyTo(buffer); + _readBufferOffset += bytesToReturn; + _readBufferCount -= bytesToReturn; + return bytesToReturn; + } + + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + if (buffer is null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + return ReadAsync(new Memory(buffer, offset, count), cancellationToken).AsTask(); + } + + public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken) + { + EnsurePreReadConditions(); + + if (cancellationToken.IsCancellationRequested) + { + return new ValueTask(Task.FromCanceled(cancellationToken)); + } + + return ReadAsyncCore(buffer, cancellationToken); + async ValueTask ReadAsyncCore(Memory buffer, CancellationToken cancellationToken) + { + // If there's no data in our pending read buffer, we'll need to populate it from + // the inner stream. We read the inner stream's bytes, decode that to chars using + // the 'inner' encoding, then re-encode those chars under the 'this' encoding. + // We've already calculated the worst-case expansions for the intermediate buffers, + // so we use GetChars / GetBytes instead of Convert to simplify the below code + // and to ensure an exception is thrown if the Encoding reported an incorrect + // worst-case expansion. + + if (_readBufferCount == 0) + { + byte[] rentedBytes = ArrayPool.Shared.Rent(DefaultReadByteBufferSize); + char[] rentedChars = ArrayPool.Shared.Rent(_readCharBufferMaxSize); + + try + { + // Beware: Use our constant value instead of 'rentedBytes.Length' when creating + // the Mem struct. The reason for this is that the array pool could've returned + // a larger-than-expected array, but our worst-case expansion calculations + // performed earlier didn't take that into account. + + int innerBytesReadJustNow = await _innerStream.ReadAsync(rentedBytes.AsMemory(0, DefaultReadByteBufferSize), cancellationToken).ConfigureAwait(false); + bool isEofReached = (innerBytesReadJustNow == 0); + + // convert bytes [inner] -> chars, then convert chars -> bytes [this] + + int charsDecodedJustNow = _innerDecoder.GetChars(rentedBytes, 0, innerBytesReadJustNow, rentedChars, 0, flush: isEofReached); + int pendingReadDataPopulatedJustNow = _thisEncoder.GetBytes(rentedChars, 0, charsDecodedJustNow, _readBuffer, 0, flush: isEofReached); + + _readBufferOffset = 0; + _readBufferCount = pendingReadDataPopulatedJustNow; + } + finally + { + ArrayPool.Shared.Return(rentedBytes); + ArrayPool.Shared.Return(rentedChars); + } + } + + // At this point: (a) we've populated our pending read buffer and there's + // useful data to return to our caller; or (b) the pending read buffer is + // empty because the inner stream has reached EOF and all pending read data + // has already been flushed, and we should return 0. + + int bytesToReturn = Math.Min(_readBufferCount, buffer.Length); + _readBuffer.AsSpan(_readBufferOffset, bytesToReturn).CopyTo(buffer.Span); + _readBufferOffset += bytesToReturn; + _readBufferCount -= bytesToReturn; + return bytesToReturn; + } + } + + public override int ReadByte() + { + Span buffer = stackalloc byte[1]; + int bytesRead = Read(buffer); + return (bytesRead == 0) ? -1 /* EOF */ : buffer[0]; + } + + public override long Seek(long offset, SeekOrigin origin) + => throw new NotSupportedException(SR.NotSupported_UnseekableStream); + + public override void SetLength(long value) + => throw new NotSupportedException(SR.NotSupported_UnseekableStream); + + [StackTraceHidden] + private void ThrowIfDisposed() + { + if (_innerStream is null) + { + ThrowObjectDisposedException(); + } + } + + [DoesNotReturn] + [StackTraceHidden] + private void ThrowObjectDisposedException() + { + throw new ObjectDisposedException( + objectName: GetType().Name, + message: SR.ObjectDisposed_StreamClosed); + } + + public override void Write(byte[] buffer, int offset, int count) + { + if (buffer is null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + Write(new ReadOnlySpan(buffer, offset, count)); + } + + public override void Write(ReadOnlySpan buffer) + { + EnsurePreWriteConditions(); + + int rentalLength = Math.Clamp(buffer.Length, MinWriteRentedArraySize, MaxWriteRentedArraySize); + + char[] scratchChars = ArrayPool.Shared.Rent(rentalLength); + byte[] scratchBytes = ArrayPool.Shared.Rent(rentalLength); + + try + { + bool decoderFinished, encoderFinished; + do + { + // convert bytes [this] -> chars + + _thisDecoder.Convert( + bytes: buffer, + chars: scratchChars, + flush: false, + out int bytesConsumed, + out int charsWritten, + out decoderFinished); + + buffer = buffer[bytesConsumed..]; + + // convert chars -> bytes [inner] + + Span decodedChars = scratchChars.AsSpan(..charsWritten); + + do + { + _innerEncoder.Convert( + chars: decodedChars, + bytes: scratchBytes, + flush: false, + out int charsConsumed, + out int bytesWritten, + out encoderFinished); + + decodedChars = decodedChars[charsConsumed..]; + + // It's more likely that the inner stream provides an optimized implementation of + // Write(byte[], ...) over Write(ROS), so we'll prefer the byte[]-based overloads. + + _innerStream.Write(scratchBytes, 0, bytesWritten); + } while (!encoderFinished); + } while (!decoderFinished); + } + finally + { + ArrayPool.Shared.Return(scratchChars); + ArrayPool.Shared.Return(scratchBytes); + } + } + + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + if (buffer is null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + return WriteAsync(new ReadOnlyMemory(buffer, offset, count), cancellationToken).AsTask(); + } + + public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken) + { + EnsurePreWriteConditions(); + + if (cancellationToken.IsCancellationRequested) + { + return new ValueTask(Task.FromCanceled(cancellationToken)); + } + + return WriteAsyncCore(buffer, cancellationToken); + async ValueTask WriteAsyncCore(ReadOnlyMemory remainingOuterEncodedBytes, CancellationToken cancellationToken) + { + int rentalLength = Math.Clamp(remainingOuterEncodedBytes.Length, MinWriteRentedArraySize, MaxWriteRentedArraySize); + + char[] scratchChars = ArrayPool.Shared.Rent(rentalLength); + byte[] scratchBytes = ArrayPool.Shared.Rent(rentalLength); + + try + { + bool decoderFinished, encoderFinished; + do + { + // convert bytes [this] -> chars + + _thisDecoder.Convert( + bytes: remainingOuterEncodedBytes.Span, + chars: scratchChars, + flush: false, + out int bytesConsumed, + out int charsWritten, + out decoderFinished); + + remainingOuterEncodedBytes = remainingOuterEncodedBytes[bytesConsumed..]; + + // convert chars -> bytes [inner] + + ArraySegment decodedChars = new ArraySegment(scratchChars, 0, charsWritten); + + do + { + _innerEncoder.Convert( + chars: decodedChars, + bytes: scratchBytes, + flush: false, + out int charsConsumed, + out int bytesWritten, + out encoderFinished); + + decodedChars = decodedChars[charsConsumed..]; + await _innerStream.WriteAsync(new ReadOnlyMemory(scratchBytes, 0, bytesWritten), cancellationToken).ConfigureAwait(false); + } while (!encoderFinished); + } while (!decoderFinished); + } + finally + { + ArrayPool.Shared.Return(scratchChars); + ArrayPool.Shared.Return(scratchBytes); + } + } + } + + public override void WriteByte(byte value) + => Write(MemoryMarshal.CreateReadOnlySpan(ref value, 1)); + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs b/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs index 3f697491d218f1..feb7a3114c30f6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/UTF7Encoding.cs @@ -7,6 +7,7 @@ // using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; namespace System.Text @@ -31,15 +32,15 @@ public class UTF7Encoding : Encoding internal static readonly UTF7Encoding s_default = new UTF7Encoding(); // The set of base 64 characters. - private byte[] _base64Bytes = null!; + private byte[] _base64Bytes; // The decoded bits for every base64 values. This array has a size of 128 elements. // The index is the code point value of the base 64 characters. The value is -1 if // the code point is not a valid base 64 character. Otherwise, the value is a value // from 0 ~ 63. - private sbyte[] _base64Values = null!; + private sbyte[] _base64Values; // The array to decide if a Unicode code point below 0x80 can be directly encoded in UTF7. // This array has a size of 128. - private bool[] _directEncode = null!; + private bool[] _directEncode; private readonly bool _allowOptionals; @@ -60,6 +61,9 @@ public UTF7Encoding(bool allowOptionals) MakeTables(); } + [MemberNotNull(nameof(_base64Bytes))] + [MemberNotNull(nameof(_base64Values))] + [MemberNotNull(nameof(_directEncode))] private void MakeTables() { // Build our tables diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf16Utility.Validation.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf16Utility.Validation.cs index 73bfa603f92528..c2b38f159d6aab 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf16Utility.Validation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf16Utility.Validation.cs @@ -15,15 +15,12 @@ #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types #if SYSTEM_PRIVATE_CORELIB #if TARGET_64BIT -using nint = System.Int64; -using nuint = System.UInt64; +using nuint_t = System.UInt64; #else // TARGET_64BIT -using nint = System.Int32; -using nuint = System.UInt32; +using nuint_t = System.UInt32; #endif // TARGET_64BIT #else -using nint = System.Int64; // https://github.com/dotnet/runtime/issues/33575 - use long/ulong outside of corelib until the compiler supports it -using nuint = System.UInt64; +using nuint_t = System.UInt64; #endif namespace System.Text.Unicode @@ -33,8 +30,7 @@ internal static unsafe partial class Utf16Utility #if DEBUG && SYSTEM_PRIVATE_CORELIB static Utf16Utility() { - Debug.Assert(sizeof(nint) == IntPtr.Size && nint.MinValue < 0, "nint is defined incorrectly."); - Debug.Assert(sizeof(nuint) == IntPtr.Size && nuint.MinValue == 0, "nuint is defined incorrectly."); + Debug.Assert(sizeof(nuint_t) == IntPtr.Size && nuint.MinValue == 0, "nuint_t is defined incorrectly."); } #endif // DEBUG && SYSTEM_PRIVATE_CORELIB @@ -291,15 +287,15 @@ static Utf16Utility() Vector utf16Data = Unsafe.ReadUnaligned>(pInputBuffer); Vector twoOrMoreUtf8Bytes = Vector.GreaterThanOrEqual(utf16Data, vector0080); Vector threeOrMoreUtf8Bytes = Vector.GreaterThanOrEqual(utf16Data, vector0800); - Vector sumVector = (Vector)(Vector.Zero - twoOrMoreUtf8Bytes - threeOrMoreUtf8Bytes); + Vector sumVector = (Vector)(Vector.Zero - twoOrMoreUtf8Bytes - threeOrMoreUtf8Bytes); // We'll try summing by a natural word (rather than a 16-bit word) at a time, // which should halve the number of operations we must perform. nuint popcnt = 0; - for (int i = 0; i < Vector.Count; i++) + for (int i = 0; i < Vector.Count; i++) { - popcnt += sumVector[i]; + popcnt += (nuint)sumVector[i]; } uint popcnt32 = (uint)popcnt; diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Transcoding.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Transcoding.cs index 64f76fec691474..201626fd6b876e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Transcoding.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Transcoding.cs @@ -13,34 +13,10 @@ using Internal.Runtime.CompilerServices; #endif -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if SYSTEM_PRIVATE_CORELIB -#if TARGET_64BIT -using nint = System.Int64; -using nuint = System.UInt64; -#else // TARGET_64BIT -using nint = System.Int32; -using nuint = System.UInt32; -#endif // TARGET_64BIT -#else -using nint = System.Int64; // https://github.com/dotnet/runtime/issues/33575 - use long/ulong outside of corelib until the compiler supports it -using nuint = System.UInt64; -#endif - namespace System.Text.Unicode { internal static unsafe partial class Utf8Utility { -#if DEBUG && SYSTEM_PRIVATE_CORELIB - static Utf8Utility() - { - Debug.Assert(sizeof(nint) == IntPtr.Size && nint.MinValue < 0, "nint is defined incorrectly."); - Debug.Assert(sizeof(nuint) == IntPtr.Size && nuint.MinValue == 0, "nuint is defined incorrectly."); - - _ValidateAdditionalNIntDefinitions(); - } -#endif // DEBUG && SYSTEM_PRIVATE_CORELIB - // On method return, pInputBufferRemaining and pOutputBufferRemaining will both point to where // the next byte would have been consumed from / the next char would have been written to. // inputLength in bytes, outputCharsRemaining in chars. diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Validation.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Validation.cs index 8284828d530436..a4a1932987fe39 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Validation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.Validation.cs @@ -11,32 +11,10 @@ using Internal.Runtime.CompilerServices; #endif -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if SYSTEM_PRIVATE_CORELIB -#if TARGET_64BIT -using nint = System.Int64; -using nuint = System.UInt64; -#else // TARGET_64BIT -using nint = System.Int32; -using nuint = System.UInt32; -#endif // TARGET_64BIT -#else -using nint = System.Int64; // https://github.com/dotnet/runtime/issues/33575 - use long/ulong outside of corelib until the compiler supports it -using nuint = System.UInt64; -#endif - namespace System.Text.Unicode { internal static unsafe partial class Utf8Utility { -#if DEBUG && SYSTEM_PRIVATE_CORELIB - private static void _ValidateAdditionalNIntDefinitions() - { - Debug.Assert(sizeof(nint) == IntPtr.Size && nint.MinValue < 0, "nint is defined incorrectly."); - Debug.Assert(sizeof(nuint) == IntPtr.Size && nuint.MinValue == 0, "nuint is defined incorrectly."); - } -#endif // DEBUG && SYSTEM_PRIVATE_CORELIB - // Returns &inputBuffer[inputLength] if the input buffer is valid. /// /// Given an input buffer of byte length , @@ -144,7 +122,7 @@ private static void _ValidateAdditionalNIntDefinitions() do { - if (Sse2.IsSupported && Bmi1.IsSupported) + if (Sse2.IsSupported) { // pInputBuffer is 32-bit aligned but not necessary 128-bit aligned, so we're // going to perform an unaligned load. We don't necessarily care about aligning @@ -180,7 +158,6 @@ private static void _ValidateAdditionalNIntDefinitions() Debug.Assert(BitConverter.IsLittleEndian); Debug.Assert(Sse2.IsSupported); - Debug.Assert(Bmi1.IsSupported); // The 'mask' value will have a 0 bit for each ASCII byte we saw and a 1 bit // for each non-ASCII byte we saw. We can count the number of ASCII bytes, @@ -189,7 +166,7 @@ private static void _ValidateAdditionalNIntDefinitions() Debug.Assert(mask != 0); - pInputBuffer += Bmi1.TrailingZeroCount(mask); + pInputBuffer += BitOperations.TrailingZeroCount(mask); if (pInputBuffer > pFinalPosWhereCanReadDWordFromInputBuffer) { goto ProcessRemainingBytesSlow; diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.WhiteSpace.CoreLib.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.WhiteSpace.CoreLib.cs index cf656bc1dc2d1c..6c34b06728dd93 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.WhiteSpace.CoreLib.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.WhiteSpace.CoreLib.cs @@ -5,14 +5,6 @@ using System.Runtime.InteropServices; using Internal.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nint = System.Int32; -using nuint = System.UInt32; -#endif - namespace System.Text.Unicode { internal static partial class Utf8Utility diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Searching.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Searching.cs index ea295dfa26c4d4..cfaaaf8663fffe 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Searching.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Searching.cs @@ -281,7 +281,7 @@ private unsafe bool TryFind(Utf8Span value, StringComparison comparisonType, out } else { - idx = compareInfo.IndexOf(thisTranscodedToUtf16, otherTranscodedToUtf16, 0, thisTranscodedToUtf16.Length, compareOptions, &matchLength, fromBeginning); + idx = compareInfo.IndexOf(thisTranscodedToUtf16, otherTranscodedToUtf16, &matchLength, compareOptions, fromBeginning); } #else Debug.Assert(comparisonType == StringComparison.OrdinalIgnoreCase); diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.cs index eb6cdb6527d416..3a90590bb6da76 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.cs @@ -15,20 +15,6 @@ #pragma warning disable 0809 //warning CS0809: Obsolete member 'Utf8Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if SYSTEM_PRIVATE_CORELIB -#if TARGET_64BIT -using nint = System.Int64; -using nuint = System.UInt64; -#else -using nint = System.Int32; -using nuint = System.UInt32; -#endif -#else -using nint = System.Int64; // https://github.com/dotnet/runtime/issues/33575 - use long/ulong outside of corelib until the compiler supports it -using nuint = System.UInt64; -#endif - namespace System.Text { [StructLayout(LayoutKind.Auto)] @@ -132,7 +118,7 @@ internal ref byte DangerousGetMutableReference(nuint index) #if SYSTEM_PRIVATE_CORELIB return ref Unsafe.AddByteOffset(ref DangerousGetMutableReference(), index); #else - return ref Unsafe.AddByteOffset(ref DangerousGetMutableReference(), (IntPtr)index); + return ref Unsafe.AddByteOffset(ref DangerousGetMutableReference(), (nint)index); #endif } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenRegistration.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenRegistration.cs index c078b7eb5c12fc..d8fc3e6859b0f1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenRegistration.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenRegistration.cs @@ -53,11 +53,12 @@ public ValueTask DisposeAsync() default; } - /// - /// Gets the with which this registration is associated. If the - /// registration isn't associated with a token (such as after the registration has been disposed), + /// Gets the with which this registration is associated. + /// + /// If the registration isn't associated with a token (such as for a registration returned from a call + /// to on a token that already had cancellation requested), /// this will return a default token. - /// + /// public CancellationToken Token { get diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs index 0e9ecac5877fb8..8e2e63c2d06705 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/LazyInitializer.cs @@ -49,7 +49,7 @@ public static class LazyInitializer /// /// public static T EnsureInitialized([NotNull] ref T? target) where T : class => - Volatile.Read(ref target) ?? EnsureInitializedCore(ref target); + Volatile.Read(ref target!) ?? EnsureInitializedCore(ref target); /// /// Initializes a target reference type with the type's default constructor (slow path) @@ -101,7 +101,7 @@ private static T EnsureInitializedCore([NotNull] ref T? target) where T : cla /// /// public static T EnsureInitialized([NotNull] ref T? target, Func valueFactory) where T : class => - Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, valueFactory); + Volatile.Read(ref target!) ?? EnsureInitializedCore(ref target, valueFactory); /// /// Initialize the target using the given delegate (slow path). @@ -133,9 +133,10 @@ private static T EnsureInitializedCore([NotNull] ref T? target, Func value /// A reference to a boolean that determines whether the target has already /// been initialized. /// A reference to an object used as the mutually exclusive lock for initializing - /// . If is null, a new object will be instantiated. + /// . If is null, and if the target hasn't already + /// been initialized, a new object will be instantiated. /// The initialized value of type . - public static T EnsureInitialized([AllowNull] ref T target, ref bool initialized, [NotNull] ref object? syncLock) + public static T EnsureInitialized([AllowNull] ref T target, ref bool initialized, [NotNullIfNotNull("syncLock")] ref object? syncLock) { // Fast path. if (Volatile.Read(ref initialized)) @@ -190,11 +191,12 @@ private static T EnsureInitializedCore([AllowNull] ref T target, ref bool ini /// A reference to a boolean that determines whether the target has already /// been initialized. /// A reference to an object used as the mutually exclusive lock for initializing - /// . If is null, a new object will be instantiated. + /// . If is null, and if the target hasn't already + /// been initialized, a new object will be instantiated. /// The invoked to initialize the /// reference or value. /// The initialized value of type . - public static T EnsureInitialized([AllowNull] ref T target, ref bool initialized, [NotNull] ref object? syncLock, Func valueFactory) + public static T EnsureInitialized([AllowNull] ref T target, ref bool initialized, [NotNullIfNotNull("syncLock")] ref object? syncLock, Func valueFactory) { // Fast path. if (Volatile.Read(ref initialized)) @@ -239,11 +241,12 @@ private static T EnsureInitializedCore([AllowNull] ref T target, ref bool ini /// The type of the reference to be initialized. Has to be reference type. /// A reference of type to initialize if it has not already been initialized. /// A reference to an object used as the mutually exclusive lock for initializing - /// . If is null, a new object will be instantiated. + /// . If is null, and if the target hasn't already + /// been initialized, a new object will be instantiated. /// The invoked to initialize the reference. /// The initialized value of type . - public static T EnsureInitialized([NotNull] ref T? target, [NotNull] ref object? syncLock, Func valueFactory) where T : class => - Volatile.Read(ref target) ?? EnsureInitializedCore(ref target, ref syncLock, valueFactory); + public static T EnsureInitialized([NotNull] ref T? target, [NotNullIfNotNull("syncLock")] ref object? syncLock, Func valueFactory) where T : class => + Volatile.Read(ref target!) ?? EnsureInitializedCore(ref target, ref syncLock, valueFactory); /// /// Ensure the target is initialized and return the value (slow path). This overload works only for reference type targets. @@ -272,7 +275,8 @@ private static T EnsureInitializedCore([NotNull] ref T? target, [NotNull] ref } } - return target!; // TODO-NULLABLE: Compiler can't infer target's non-nullness (https://github.com/dotnet/roslyn/issues/37300) + Debug.Assert(target != null); + return target; } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.HillClimbing.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.HillClimbing.cs index 0fa48e9d870fdc..377dc033f459f0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.HillClimbing.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.HillClimbing.cs @@ -185,8 +185,11 @@ public HillClimbing(int wavePeriod, int maxWaveMagnitude, double waveMagnitudeMu // Add the current thread count and throughput sample to our history // double throughput = numCompletions / sampleDurationSeconds; - - PortableThreadPoolEventSource.Log.WorkerThreadAdjustmentSample(throughput); + PortableThreadPoolEventSource log = PortableThreadPoolEventSource.Log; + if (log.IsEnabled()) + { + log.WorkerThreadAdjustmentSample(throughput); + } int sampleIndex = (int)(_totalSamples % _samplesToMeasure); _samples[sampleIndex] = throughput; @@ -356,8 +359,11 @@ public HillClimbing(int wavePeriod, int maxWaveMagnitude, double waveMagnitudeMu // Record these numbers for posterity // - PortableThreadPoolEventSource.Log.WorkerThreadAdjustmentStats(sampleDurationSeconds, throughput, threadWaveComponent.Real, throughputWaveComponent.Real, + if (log.IsEnabled()) + { + log.WorkerThreadAdjustmentStats(sampleDurationSeconds, throughput, threadWaveComponent.Real, throughputWaveComponent.Real, throughputErrorEstimate, _averageThroughputNoise, ratio.Real, confidence, _currentControlSetting, (ushort)newThreadWaveMagnitude); + } // @@ -414,7 +420,11 @@ private void LogTransition(int newThreadCount, double throughput, StateOrTransit _logSize++; - PortableThreadPoolEventSource.Log.WorkerThreadAdjustmentAdjustment(throughput, newThreadCount, (int)stateOrTransition); + PortableThreadPoolEventSource log = PortableThreadPoolEventSource.Log; + if (log.IsEnabled()) + { + log.WorkerThreadAdjustmentAdjustment(throughput, newThreadCount, (int)stateOrTransition); + } } public void ForceChange(int newThreadCount, StateOrTransition state) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs index b120265a05336b..bbc598683fc55a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.WorkerThread.cs @@ -26,7 +26,11 @@ private static int SemaphoreSpinCount private static void WorkerThreadStart() { - PortableThreadPoolEventSource.Log.WorkerThreadStart(ThreadCounts.VolatileReadCounts(ref ThreadPoolInstance._separated.counts).numExistingThreads); + PortableThreadPoolEventSource log = PortableThreadPoolEventSource.Log; + if (log.IsEnabled()) + { + log.WorkerThreadStart(ThreadCounts.VolatileReadCounts(ref ThreadPoolInstance._separated.counts).numExistingThreads); + } while (true) { @@ -71,7 +75,11 @@ private static void WorkerThreadStart() if (oldCounts == counts) { HillClimbing.ThreadPoolHillClimber.ForceChange(newCounts.numThreadsGoal, HillClimbing.StateOrTransition.ThreadTimedOut); - PortableThreadPoolEventSource.Log.WorkerThreadStop(newCounts.numExistingThreads); + + if (log.IsEnabled()) + { + log.WorkerThreadStop(newCounts.numExistingThreads); + } return; } } @@ -89,7 +97,11 @@ private static void WorkerThreadStart() /// If this thread was woken up before it timed out. private static bool WaitForRequest() { - PortableThreadPoolEventSource.Log.WorkerThreadWait(ThreadCounts.VolatileReadCounts(ref ThreadPoolInstance._separated.counts).numExistingThreads); + PortableThreadPoolEventSource log = PortableThreadPoolEventSource.Log; + if (log.IsEnabled()) + { + log.WorkerThreadWait(ThreadCounts.VolatileReadCounts(ref ThreadPoolInstance._separated.counts).numExistingThreads); + } return s_semaphore.Wait(ThreadPoolThreadTimeoutMs); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs index 229de2dfafaaf4..61f6e4a659869c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @@ -609,7 +609,7 @@ private void AssignCancellationToken(CancellationToken cancellationToken, Task? if (cancellationToken.IsCancellationRequested) { // Fast path for an already-canceled cancellationToken - this.InternalCancel(false); + InternalCancel(); } else { @@ -618,7 +618,7 @@ private void AssignCancellationToken(CancellationToken cancellationToken, Task? if (antecedent == null) { // if no antecedent was specified, use this task's reference as the cancellation state object - ctr = cancellationToken.UnsafeRegister(t => ((Task)t!).InternalCancel(false), this); + ctr = cancellationToken.UnsafeRegister(t => ((Task)t!).InternalCancel(), this); } else { @@ -635,7 +635,7 @@ private void AssignCancellationToken(CancellationToken cancellationToken, Task? Task antecedentTask = tuple.Item2; antecedentTask.RemoveContinuation(tuple.Item3); - targetTask.InternalCancel(false); + targetTask.InternalCancel(); }, new Tuple(this, antecedent, continuation)); } @@ -2896,98 +2896,86 @@ private bool SpinWait(int millisecondsTimeout) /// /// Cancels the . /// - /// - /// Indicates whether we should only cancel non-invoked tasks. - /// For the default scheduler this option will only be serviced through TryDequeue. - /// For custom schedulers we also attempt an atomic state transition. - /// - /// true if the task was successfully canceled; otherwise, false. - internal bool InternalCancel(bool bCancelNonExecutingOnly) + internal void InternalCancel() { Debug.Assert((Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) == 0, "Task.InternalCancel() did not expect promise-style task"); - bool bPopSucceeded = false; - bool mustCleanup = false; - TaskSchedulerException? tse = null; + bool popped = false; // If started, and running in a task context, we can try to pop the chore. if ((m_stateFlags & TASK_STATE_STARTED) != 0) { TaskScheduler? ts = m_taskScheduler; - try { - bPopSucceeded = (ts != null) && ts.TryDequeue(this); + popped = (ts != null) && ts.TryDequeue(this); } catch (Exception e) { // TryDequeue threw. We don't know whether the task was properly dequeued or not. So we must let the rest of // the cancellation logic run its course (record the request, attempt atomic state transition and do cleanup where appropriate) // Here we will only record a TaskSchedulerException, which will later be thrown at function exit. - tse = new TaskSchedulerException(e); } + } - bool bRequiresAtomicStartTransition = ts != null && ts.RequiresAtomicStartTransition; + // Record the cancellation request. + RecordInternalCancellationRequest(); - if (!bPopSucceeded && bCancelNonExecutingOnly && bRequiresAtomicStartTransition) - { - // The caller requested cancellation of non-invoked tasks only, and TryDequeue was one way of doing it... - // Since that seems to have failed, we should now try an atomic state transition (from non-invoked state to canceled) - // An atomic transition here is only safe if we know we're on a custom task scheduler, which also forces a CAS on ExecuteEntry - - // Even though this task can't have any children, we should be ready for handling any continuations that - // may be attached to it (although currently - // So we need to remeber whether we actually did the flip, so we can do clean up (finish continuations etc) - mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED, TASK_STATE_DELEGATE_INVOKED | TASK_STATE_CANCELED); - - // PS: This is slightly different from the regular cancellation codepath - // since we record the cancellation request *after* doing the state transition. - // However that shouldn't matter too much because the task was never invoked, thus can't have children - } + // Determine whether we need to clean up + // This will be the case + // 1) if we were able to pop, and we are able to update task state to TASK_STATE_CANCELED + // 2) if the task seems to be yet unstarted, and we can transition to + // TASK_STATE_CANCELED before anyone else can transition into _STARTED or _CANCELED or + // _RAN_TO_COMPLETION or _FAULTED + // Note that we do not check for TASK_STATE_COMPLETION_RESERVED. That only applies to promise-style + // tasks, and a promise-style task should not enter into this codepath. + bool mustCleanup = false; + if (popped) + { + // Include TASK_STATE_DELEGATE_INVOKED in "illegal" bits to protect against the situation where + // TS.TryDequeue() returns true but the task is still left on the queue. + mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED, TASK_STATE_CANCELED | TASK_STATE_DELEGATE_INVOKED); } - - if (!bCancelNonExecutingOnly || bPopSucceeded || mustCleanup) + else if ((m_stateFlags & TASK_STATE_STARTED) == 0) { - // Record the cancellation request. - RecordInternalCancellationRequest(); - - // Determine whether we need to clean up - // This will be the case - // 1) if we were able to pop, and we are able to update task state to TASK_STATE_CANCELED - // 2) if the task seems to be yet unstarted, and we can transition to - // TASK_STATE_CANCELED before anyone else can transition into _STARTED or _CANCELED or - // _RAN_TO_COMPLETION or _FAULTED - // Note that we do not check for TASK_STATE_COMPLETION_RESERVED. That only applies to promise-style - // tasks, and a promise-style task should not enter into this codepath. - if (bPopSucceeded) - { - // hitting this would mean something wrong with the AtomicStateUpdate above - Debug.Assert(!mustCleanup, "Possibly an invalid state transition call was made in InternalCancel()"); - - // Include TASK_STATE_DELEGATE_INVOKED in "illegal" bits to protect against the situation where - // TS.TryDequeue() returns true but the task is still left on the queue. - mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED, TASK_STATE_CANCELED | TASK_STATE_DELEGATE_INVOKED); - } - else if (!mustCleanup && (m_stateFlags & TASK_STATE_STARTED) == 0) - { - mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED, - TASK_STATE_CANCELED | TASK_STATE_STARTED | TASK_STATE_RAN_TO_COMPLETION | - TASK_STATE_FAULTED | TASK_STATE_DELEGATE_INVOKED); - } + mustCleanup = AtomicStateUpdate(TASK_STATE_CANCELED, + TASK_STATE_CANCELED | TASK_STATE_STARTED | TASK_STATE_RAN_TO_COMPLETION | + TASK_STATE_FAULTED | TASK_STATE_DELEGATE_INVOKED); + } - // do the cleanup (i.e. set completion event and finish continuations) - if (mustCleanup) - { - CancellationCleanupLogic(); - } + // do the cleanup (i.e. set completion event and finish continuations) + if (mustCleanup) + { + CancellationCleanupLogic(); } if (tse != null) + { throw tse; - else - return mustCleanup; + } + } + + /// + /// Cancels a ContinueWith task as part of determining to see whether the continuation should run. + /// This is only valid if the ContinueWith has a default token associated with it. + /// + internal void InternalCancelContinueWithInitialState() + { + // There isn't a cancellation token assigned to the task, which means the task is still going to be in its + // initial state. The only way it could have transitioned is if: + // - it was Start'd, which isn't valid for a continuation + // - it was canceled, which won't have happened without a token + // - it was run as a continuation, which won't have happened because this method is only invoked once + // As a result, we can take an optimized path that avoids inflating contingent properties. + const int IllegalFlags = TASK_STATE_STARTED | TASK_STATE_COMPLETED_MASK | TASK_STATE_DELEGATE_INVOKED; + Debug.Assert((m_stateFlags & IllegalFlags) == 0, "The continuation was in an invalid state."); + Debug.Assert((m_stateFlags & TASK_STATE_WAITINGFORACTIVATION) != 0, "Expected continuation to be waiting for activation"); + Debug.Assert(m_contingentProperties is null || m_contingentProperties.m_cancellationToken == default); + + m_stateFlags |= TASK_STATE_CANCELED; // no synchronization necessary, per above comment + CancellationCleanupLogic(); } // Breaks out logic for recording a cancellation request @@ -3000,11 +2988,11 @@ internal void RecordInternalCancellationRequest() // Breaks out logic for recording a cancellation request // This overload should only be used for promise tasks where no cancellation token // was supplied when the task was created. - internal void RecordInternalCancellationRequest(CancellationToken tokenToRecord) + internal void RecordInternalCancellationRequest(CancellationToken tokenToRecord, object? cancellationException) { - RecordInternalCancellationRequest(); - Debug.Assert((Options & (TaskCreationOptions)InternalTaskOptions.PromiseTask) != 0, "Task.RecordInternalCancellationRequest(CancellationToken) only valid for promise-style task"); + + RecordInternalCancellationRequest(); Debug.Assert(m_contingentProperties!.m_cancellationToken == default); // Store the supplied cancellation token as this task's token. @@ -3013,14 +3001,6 @@ internal void RecordInternalCancellationRequest(CancellationToken tokenToRecord) { m_contingentProperties.m_cancellationToken = tokenToRecord; } - } - - // Breaks out logic for recording a cancellation request - // This overload should only be used for promise tasks where no cancellation token - // was supplied when the task was created. - internal void RecordInternalCancellationRequest(CancellationToken tokenToRecord, object? cancellationException) - { - RecordInternalCancellationRequest(tokenToRecord); // Store the supplied cancellation exception if (cancellationException != null) @@ -3288,7 +3268,7 @@ private void RunContinuations(object continuationObject) // separated out of Fin // The continuation was unregistered and null'd out, so just skip it. continue; } - else if (currentContinuation is StandardTaskContinuation stc) + else if (currentContinuation is ContinueWithTaskContinuation stc) { if ((stc.m_options & TaskContinuationOptions.ExecuteSynchronously) == 0) { @@ -4226,7 +4206,7 @@ internal void ContinueWithCore(Task continuationTask, Debug.Assert(!continuationTask.IsCompleted, "Did not expect continuationTask to be completed"); // Create a TaskContinuation - TaskContinuation continuation = new StandardTaskContinuation(continuationTask, options, scheduler); + TaskContinuation continuation = new ContinueWithTaskContinuation(continuationTask, options, scheduler); // If cancellationToken is cancellable, then assign it. if (cancellationToken.CanBeCanceled) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs index e2cf8a4694c7cd..b4571cff6881a8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs @@ -257,10 +257,10 @@ protected static void InlineIfPossibleOrElseQueue(Task task, bool needsProtectio } /// Provides the standard implementation of a task continuation. - internal class StandardTaskContinuation : TaskContinuation + internal sealed class ContinueWithTaskContinuation : TaskContinuation { /// The unstarted continuation task. - internal readonly Task m_task; + internal Task? m_task; /// The options to use with the continuation task. internal readonly TaskContinuationOptions m_options; /// The task scheduler with which to run the continuation task. @@ -270,7 +270,7 @@ internal class StandardTaskContinuation : TaskContinuation /// The task to be activated. /// The continuation options. /// The scheduler to use for the continuation. - internal StandardTaskContinuation(Task task, TaskContinuationOptions options, TaskScheduler scheduler) + internal ContinueWithTaskContinuation(Task task, TaskContinuationOptions options, TaskScheduler scheduler) { Debug.Assert(task != null, "TaskContinuation ctor: task is null"); Debug.Assert(scheduler != null, "TaskContinuation ctor: scheduler is null"); @@ -292,6 +292,10 @@ internal override void Run(Task completedTask, bool canInlineContinuationTask) Debug.Assert(completedTask != null); Debug.Assert(completedTask.IsCompleted, "ContinuationTask.Run(): completedTask not completed"); + Task? continuationTask = m_task; + Debug.Assert(continuationTask != null); + m_task = null; + // Check if the completion status of the task works with the desired // activation criteria of the TaskContinuationOptions. TaskContinuationOptions options = m_options; @@ -303,7 +307,6 @@ internal override void Run(Task completedTask, bool canInlineContinuationTask) (options & TaskContinuationOptions.NotOnFaulted) == 0); // If the completion status is allowed, run the continuation. - Task continuationTask = m_task; if (isRightKind) { // If the task was cancel before running (e.g a ContinueWhenAll with a cancelled caancelation token) @@ -333,20 +336,29 @@ internal override void Run(Task completedTask, bool canInlineContinuationTask) } } } - // Otherwise, the final state of this task does not match the desired - // continuation activation criteria; cancel it to denote this. - else continuationTask.InternalCancel(false); - } - - internal override Delegate[]? GetDelegateContinuationsForDebugger() - { - if (m_task.m_action == null) + else { - return m_task.GetDelegateContinuationsForDebugger(); + // Otherwise, the final state of this task does not match the desired continuation activation criteria; cancel it to denote this. + Task.ContingentProperties? cp = continuationTask.m_contingentProperties; // no need to volatile read, as we only care about the token, which is only assignable at construction + if (cp is null || cp.m_cancellationToken == default) + { + // With no cancellation token, use an optimized path that doesn't need to account for concurrent completion. + // This is primarily valuable for continuations created with TaskContinuationOptions.NotOn* options, where + // we'll cancel the continuation if it's not needed. + continuationTask.InternalCancelContinueWithInitialState(); + } + else + { + // There's a non-default token. Follow the normal internal cancellation path. + continuationTask.InternalCancel(); + } } - - return new Delegate[] { m_task.m_action }; } + + internal override Delegate[]? GetDelegateContinuationsForDebugger() => + m_task is null ? null : + m_task.m_action is null ? m_task.GetDelegateContinuationsForDebugger() : + new Delegate[] { m_task.m_action }; } /// Task continuation for awaiting with a current synchronization context. diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs index 8bdf89070a9adc..9abd9ac2aa98a9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs @@ -243,7 +243,7 @@ public bool TrySetApartmentState(ApartmentState state) break; default: - throw new ArgumentOutOfRangeException(SR.ArgumentOutOfRange_Enum, nameof(state)); + throw new ArgumentOutOfRangeException(nameof(state), SR.ArgumentOutOfRange_Enum); } return TrySetApartmentStateUnchecked(state); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.cs index fe1021272a282e..de78cc1a7002fc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.cs @@ -22,26 +22,6 @@ namespace System.Threading { - internal static class ThreadPoolGlobals - { - public static volatile bool threadPoolInitialized; - public static bool enableWorkerTracking; - - public static readonly ThreadPoolWorkQueue workQueue = new ThreadPoolWorkQueue(); - - /// Shim used to invoke of the supplied . - internal static readonly Action s_invokeAsyncStateMachineBox = state => - { - if (!(state is IAsyncStateMachineBox box)) - { - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state); - return; - } - - box.MoveNext(); - }; - } - [StructLayout(LayoutKind.Sequential)] // enforce layout so that padding reduces false sharing internal sealed class ThreadPoolWorkQueue { @@ -552,7 +532,7 @@ public long LocalCount /// internal static bool Dispatch() { - ThreadPoolWorkQueue outerWorkQueue = ThreadPoolGlobals.workQueue; + ThreadPoolWorkQueue outerWorkQueue = ThreadPool.s_workQueue; // // Save the start time @@ -627,7 +607,7 @@ internal static bool Dispatch() // // Execute the workitem outside of any finally blocks, so that it can be aborted if needed. // - if (ThreadPoolGlobals.enableWorkerTracking) + if (ThreadPool.s_enableWorkerTracking) { bool reportedStatus = false; try @@ -954,6 +934,21 @@ internal static void PerformWaitOrTimerCallback(_ThreadPoolWaitOrTimerCallback h public static partial class ThreadPool { + internal static readonly ThreadPoolWorkQueue s_workQueue = new ThreadPoolWorkQueue(); + internal static readonly bool s_enableWorkerTracking = GetEnableWorkerTracking(); + + /// Shim used to invoke of the supplied . + internal static readonly Action s_invokeAsyncStateMachineBox = state => + { + if (!(state is IAsyncStateMachineBox box)) + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state); + return; + } + + box.MoveNext(); + }; + [CLSCompliant(false)] public static RegisteredWaitHandle RegisterWaitForSingleObject( WaitHandle waitObject, @@ -1080,15 +1075,13 @@ public static bool QueueUserWorkItem(WaitCallback callBack, object? state) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.callBack); } - EnsureInitialized(); - ExecutionContext? context = ExecutionContext.Capture(); object tpcallBack = (context == null || context.IsDefault) ? new QueueUserWorkItemCallbackDefaultContext(callBack!, state) : (object)new QueueUserWorkItemCallback(callBack!, state, context); - ThreadPoolGlobals.workQueue.Enqueue(tpcallBack, forceGlobal: true); + s_workQueue.Enqueue(tpcallBack, forceGlobal: true); return true; } @@ -1100,15 +1093,13 @@ public static bool QueueUserWorkItem(Action callBack, TState sta ThrowHelper.ThrowArgumentNullException(ExceptionArgument.callBack); } - EnsureInitialized(); - ExecutionContext? context = ExecutionContext.Capture(); object tpcallBack = (context == null || context.IsDefault) ? new QueueUserWorkItemCallbackDefaultContext(callBack!, state) : (object)new QueueUserWorkItemCallback(callBack!, state, context); - ThreadPoolGlobals.workQueue.Enqueue(tpcallBack, forceGlobal: !preferLocal); + s_workQueue.Enqueue(tpcallBack, forceGlobal: !preferLocal); return true; } @@ -1126,7 +1117,7 @@ public static bool UnsafeQueueUserWorkItem(Action callBack, TSta // // This occurs when user code queues its provided continuation to the ThreadPool; // internally we call UnsafeQueueUserWorkItemInternal directly for Tasks. - if (ReferenceEquals(callBack, ThreadPoolGlobals.s_invokeAsyncStateMachineBox)) + if (ReferenceEquals(callBack, ThreadPool.s_invokeAsyncStateMachineBox)) { if (!(state is IAsyncStateMachineBox)) { @@ -1138,9 +1129,7 @@ public static bool UnsafeQueueUserWorkItem(Action callBack, TSta return true; } - EnsureInitialized(); - - ThreadPoolGlobals.workQueue.Enqueue( + s_workQueue.Enqueue( new QueueUserWorkItemCallbackDefaultContext(callBack!, state), forceGlobal: !preferLocal); return true; @@ -1153,11 +1142,9 @@ public static bool UnsafeQueueUserWorkItem(WaitCallback callBack, object? state) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.callBack); } - EnsureInitialized(); - object tpcallBack = new QueueUserWorkItemCallbackDefaultContext(callBack!, state); - ThreadPoolGlobals.workQueue.Enqueue(tpcallBack, forceGlobal: true); + s_workQueue.Enqueue(tpcallBack, forceGlobal: true); return true; } @@ -1183,25 +1170,21 @@ internal static void UnsafeQueueUserWorkItemInternal(object callBack, bool prefe { Debug.Assert((callBack is IThreadPoolWorkItem) ^ (callBack is Task)); - EnsureInitialized(); - - ThreadPoolGlobals.workQueue.Enqueue(callBack, forceGlobal: !preferLocal); + s_workQueue.Enqueue(callBack, forceGlobal: !preferLocal); } // This method tries to take the target callback out of the current thread's queue. internal static bool TryPopCustomWorkItem(object workItem) { Debug.Assert(null != workItem); - return - ThreadPoolGlobals.threadPoolInitialized && // if not initialized, so there's no way this workitem was ever queued. - ThreadPoolGlobals.workQueue.LocalFindAndPop(workItem); + return s_workQueue.LocalFindAndPop(workItem); } // Get all workitems. Called by TaskScheduler in its debugger hooks. internal static IEnumerable GetQueuedWorkItems() { // Enumerate global queue - foreach (object workItem in ThreadPoolGlobals.workQueue.workItems) + foreach (object workItem in s_workQueue.workItems) { yield return workItem; } @@ -1239,7 +1222,7 @@ internal static IEnumerable GetLocallyQueuedWorkItems() } } - internal static IEnumerable GetGloballyQueuedWorkItems() => ThreadPoolGlobals.workQueue.workItems; + internal static IEnumerable GetGloballyQueuedWorkItems() => s_workQueue.workItems; private static object[] ToObjectArray(IEnumerable workitems) { @@ -1285,7 +1268,7 @@ public static long PendingWorkItemCount { get { - ThreadPoolWorkQueue workQueue = ThreadPoolGlobals.workQueue; + ThreadPoolWorkQueue workQueue = s_workQueue; return workQueue.LocalCount + workQueue.GlobalCount + PendingUnmanagedWorkItemCount; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs index 3b590ae7382806..98e65d497e92ba 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Timer.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Tracing; using System.Threading.Tasks; @@ -695,7 +696,7 @@ public sealed class Timer : MarshalByRefObject, IDisposable, IAsyncDisposable { private const uint MAX_SUPPORTED_TIMEOUT = (uint)0xfffffffe; - private TimerHolder _timer = null!; // initialized in helper called by ctors + private TimerHolder _timer; public Timer(TimerCallback callback, object? state, @@ -774,6 +775,7 @@ public Timer(TimerCallback callback) TimerSetup(callback, this, DueTime, Period); } + [MemberNotNull(nameof(_timer))] private void TimerSetup(TimerCallback callback, object? state, uint dueTime, diff --git a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs index 8ddc596a909fe6..30a11b61a0f552 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ThrowHelper.cs @@ -96,6 +96,12 @@ internal static void ThrowArgumentOutOfRange_IndexException() ExceptionResource.ArgumentOutOfRange_Index); } + [DoesNotReturn] + internal static void ThrowArgumentException_BadComparer(object? comparer) + { + throw new ArgumentException(SR.Format(SR.Arg_BogusIComparer, comparer)); + } + [DoesNotReturn] internal static void ThrowIndexArgumentOutOfRange_NeedNonNegNumException() { @@ -688,6 +694,12 @@ private static string GetArgumentName(ExceptionArgument argument) return "codePoint"; case ExceptionArgument.str: return "str"; + case ExceptionArgument.options: + return "options"; + case ExceptionArgument.prefix: + return "prefix"; + case ExceptionArgument.suffix: + return "suffix"; default: Debug.Fail("The enum value is not defined, please check the ExceptionArgument Enum."); return ""; @@ -840,6 +852,8 @@ private static string GetResourceString(ExceptionResource resource) return SR.Arg_TypeNotSupported; case ExceptionResource.Argument_SpansMustHaveSameLength: return SR.Argument_SpansMustHaveSameLength; + case ExceptionResource.Argument_InvalidFlag: + return SR.Argument_InvalidFlag; default: Debug.Fail("The enum value is not defined, please check the ExceptionResource Enum."); return ""; @@ -939,6 +953,9 @@ internal enum ExceptionArgument year, codePoint, str, + options, + prefix, + suffix, } // @@ -1011,5 +1028,6 @@ internal enum ExceptionResource Rank_MultiDimNotSupported, Arg_TypeNotSupported, Argument_SpansMustHaveSameLength, + Argument_InvalidFlag, } } diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeSpan.cs b/src/libraries/System.Private.CoreLib/src/System/TimeSpan.cs index b3a5f5217897eb..4b341799d29766 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeSpan.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeSpan.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; @@ -324,7 +325,7 @@ public static TimeSpan ParseExact(ReadOnlySpan input, string[] formats, IF ValidateStyles(styles, nameof(styles)); return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, styles); } - public static bool TryParse(string? s, out TimeSpan result) + public static bool TryParse([NotNullWhen(true)] string? s, out TimeSpan result) { if (s == null) { @@ -338,7 +339,7 @@ public static bool TryParse(ReadOnlySpan s, out TimeSpan result) return TimeSpanParse.TryParse(s, null, out result); } - public static bool TryParse(string? input, IFormatProvider? formatProvider, out TimeSpan result) + public static bool TryParse([NotNullWhen(true)] string? input, IFormatProvider? formatProvider, out TimeSpan result) { if (input == null) { @@ -351,7 +352,7 @@ public static bool TryParse(ReadOnlySpan input, IFormatProvider? formatPro { return TimeSpanParse.TryParse(input, formatProvider, out result); } - public static bool TryParseExact(string? input, string format, IFormatProvider? formatProvider, out TimeSpan result) + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string? format, IFormatProvider? formatProvider, out TimeSpan result) { if (input == null || format == null) { @@ -365,7 +366,7 @@ public static bool TryParseExact(ReadOnlySpan input, ReadOnlySpan fo { return TimeSpanParse.TryParseExact(input, format, formatProvider, TimeSpanStyles.None, out result); } - public static bool TryParseExact(string? input, string[] formats, IFormatProvider? formatProvider, out TimeSpan result) + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, out TimeSpan result) { if (input == null) { @@ -374,12 +375,12 @@ public static bool TryParseExact(string? input, string[] formats, IFormatProvide } return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None, out result); } - public static bool TryParseExact(ReadOnlySpan input, string[] formats, IFormatProvider? formatProvider, out TimeSpan result) + public static bool TryParseExact(ReadOnlySpan input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, out TimeSpan result) { return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None, out result); } - public static bool TryParseExact(string? input, string format, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string? format, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { ValidateStyles(styles, nameof(styles)); if (input == null || format == null) @@ -396,7 +397,7 @@ public static bool TryParseExact(ReadOnlySpan input, ReadOnlySpan fo ValidateStyles(styles, nameof(styles)); return TimeSpanParse.TryParseExact(input, format, formatProvider, styles, out result); } - public static bool TryParseExact(string? input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { ValidateStyles(styles, nameof(styles)); if (input == null) @@ -407,7 +408,7 @@ public static bool TryParseExact(string? input, string[] formats, IFormatProvide return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, styles, out result); } - public static bool TryParseExact(ReadOnlySpan input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) + public static bool TryParseExact(ReadOnlySpan input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { ValidateStyles(styles, nameof(styles)); return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, styles, out result); diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Type.Enum.cs index 59f244f6c3477f..d041c32b7b5349 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.Enum.cs @@ -23,7 +23,7 @@ public virtual bool IsEnumDefined(object value) throw new ArgumentNullException(nameof(value)); if (!IsEnum) - throw new ArgumentException(SR.Arg_MustBeEnum, "enumType"); + throw new ArgumentException(SR.Arg_MustBeEnum, nameof(value)); // Check if both of them are of the same type Type valueType = value.GetType(); @@ -70,7 +70,7 @@ public virtual bool IsEnumDefined(object value) throw new ArgumentNullException(nameof(value)); if (!IsEnum) - throw new ArgumentException(SR.Arg_MustBeEnum, "enumType"); + throw new ArgumentException(SR.Arg_MustBeEnum, nameof(value)); Type valueType = value.GetType(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.cs b/src/libraries/System.Private.CoreLib/src/System/Type.cs index aeb60457d9741f..76aa11bc20491e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.cs @@ -267,7 +267,7 @@ public static Type[] GetTypeArray(object[] args) for (int i = 0; i < cls.Length; i++) { if (args[i] == null) - throw new ArgumentNullException(); + throw new ArgumentException(SR.ArgumentNull_ArrayValue, nameof(args)); cls[i] = args[i].GetType(); } return cls; diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs index a0041bea683775..b33ea233696633 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -135,7 +136,7 @@ private static ushort Parse(ReadOnlySpan s, NumberStyles style, NumberForm return (ushort)i; } - public static bool TryParse(string? s, out ushort result) + public static bool TryParse([NotNullWhen(true)] string? s, out ushort result) { if (s == null) { @@ -151,7 +152,7 @@ public static bool TryParse(ReadOnlySpan s, out ushort result) return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out ushort result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out ushort result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt32.cs b/src/libraries/System.Private.CoreLib/src/System/UInt32.cs index aebd3e51217866..10247a8e93c323 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt32.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -133,7 +134,7 @@ public static uint Parse(ReadOnlySpan s, NumberStyles style = NumberStyles return Number.ParseUInt32(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse(string? s, out uint result) + public static bool TryParse([NotNullWhen(true)] string? s, out uint result) { if (s == null) { @@ -149,7 +150,7 @@ public static bool TryParse(ReadOnlySpan s, out uint result) return Number.TryParseUInt32IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out uint result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out uint result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs index dcb4141bd87345..a86a977936fb55 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -132,7 +133,7 @@ public static ulong Parse(ReadOnlySpan s, NumberStyles style = NumberStyle return Number.ParseUInt64(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse(string? s, out ulong result) + public static bool TryParse([NotNullWhen(true)] string? s, out ulong result) { if (s == null) { @@ -148,7 +149,7 @@ public static bool TryParse(ReadOnlySpan s, out ulong result) return Number.TryParseUInt64IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out ulong result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out ulong result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs b/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs index 217e1566cb3ab6..d28bd83c90a312 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs @@ -4,22 +4,25 @@ using System.Globalization; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; +using Internal.Runtime.CompilerServices; #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types #if TARGET_64BIT -using nuint = System.UInt64; +using nuint_t = System.UInt64; #else -using nuint = System.UInt32; +using nuint_t = System.UInt32; #endif namespace System { [Serializable] [CLSCompliant(false)] + [StructLayout(LayoutKind.Sequential)] [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public readonly struct UIntPtr : IEquatable, ISerializable + public readonly struct UIntPtr : IEquatable, IComparable, IComparable, IFormattable, ISerializable { private readonly unsafe void* _value; // Do not rename (binary serialization) @@ -75,9 +78,6 @@ public override unsafe bool Equals(object? obj) return false; } - unsafe bool IEquatable.Equals(UIntPtr other) => - _value == other._value; - public override unsafe int GetHashCode() { #if TARGET_64BIT @@ -156,13 +156,65 @@ public static UIntPtr Subtract(UIntPtr pointer, int offset) => public static int Size { [NonVersionable] - get => sizeof(nuint); + get => sizeof(nuint_t); } [NonVersionable] public unsafe void* ToPointer() => _value; - public override unsafe string ToString() => - ((nuint)_value).ToString(CultureInfo.InvariantCulture); + public static UIntPtr MaxValue + { + [NonVersionable] + get => (UIntPtr)nuint_t.MaxValue; + } + + public static UIntPtr MinValue + { + [NonVersionable] + get => (UIntPtr)nuint_t.MinValue; + } + + public unsafe int CompareTo(object? value) + { + if (value is null) + { + return 1; + } + if (value is nuint i) + { + if ((nuint)_value < i) return -1; + if ((nuint)_value > i) return 1; + return 0; + } + + throw new ArgumentException(SR.Arg_MustBeUIntPtr); + } + + public unsafe int CompareTo(UIntPtr value) => ((nuint_t)_value).CompareTo((nuint_t)value); + + [NonVersionable] + public unsafe bool Equals(UIntPtr other) => (nuint)_value == (nuint)other; + + public unsafe override string ToString() => ((nuint_t)_value).ToString(); + public unsafe string ToString(string? format) => ((nuint_t)_value).ToString(format); + public unsafe string ToString(IFormatProvider? provider) => ((nuint_t)_value).ToString(provider); + public unsafe string ToString(string? format, IFormatProvider? provider) => ((nuint_t)_value).ToString(format, provider); + + public static UIntPtr Parse(string s) => (UIntPtr)nuint_t.Parse(s); + public static UIntPtr Parse(string s, NumberStyles style) => (UIntPtr)nuint_t.Parse(s, style); + public static UIntPtr Parse(string s, IFormatProvider? provider) => (UIntPtr)nuint_t.Parse(s, provider); + public static UIntPtr Parse(string s, NumberStyles style, IFormatProvider? provider) => (UIntPtr)nuint_t.Parse(s, style, provider); + + public static bool TryParse(string? s, out UIntPtr result) + { + Unsafe.SkipInit(out result); + return nuint_t.TryParse(s, out Unsafe.As(ref result)); + } + + public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out UIntPtr result) + { + Unsafe.SkipInit(out result); + return nuint_t.TryParse(s, style, provider, out Unsafe.As(ref result)); + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Utf8String.cs b/src/libraries/System.Private.CoreLib/src/System/Utf8String.cs index e6cba4d2e4c2b1..0989371e22878e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Utf8String.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Utf8String.cs @@ -13,20 +13,6 @@ using Internal.Runtime.CompilerServices; #endif -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if SYSTEM_PRIVATE_CORELIB -#if TARGET_64BIT -using nint = System.Int64; -using nuint = System.UInt64; -#else -using nint = System.Int32; -using nuint = System.UInt32; -#endif -#else -using nint = System.Int64; // https://github.com/dotnet/runtime/issues/33575 - use long/ulong outside of corelib until the compiler supports it -using nuint = System.UInt64; -#endif - namespace System { /// @@ -133,7 +119,7 @@ internal ref byte DangerousGetMutableReference(nuint index) #if SYSTEM_PRIVATE_CORELIB return ref Unsafe.AddByteOffset(ref DangerousGetMutableReference(), index); #else - return ref Unsafe.AddByteOffset(ref DangerousGetMutableReference(), (IntPtr)index); + return ref Unsafe.AddByteOffset(ref DangerousGetMutableReference(), (nint)index); #endif } diff --git a/src/libraries/System.Private.CoreLib/src/System/Version.cs b/src/libraries/System.Private.CoreLib/src/System/Version.cs index 978e805cb30b88..8a354d40e80882 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Version.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Version.cs @@ -293,7 +293,7 @@ public static Version Parse(string input) public static Version Parse(ReadOnlySpan input) => ParseVersion(input, throwOnFailure: true)!; - public static bool TryParse(string? input, [NotNullWhen(true)] out Version? result) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out Version? result) { if (input == null) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/ILLinkTrim.xml b/src/libraries/System.Private.DataContractSerialization/src/ILLinkTrim.xml deleted file mode 100644 index e97b67c559e9ce..00000000000000 --- a/src/libraries/System.Private.DataContractSerialization/src/ILLinkTrim.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj b/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj index 951b7203269739..2252cd2cdc1216 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj +++ b/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj @@ -17,12 +17,10 @@ System\Text - - Common\System\NotImplemented.cs - - - Common\System\HexConverter.cs - + + diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs index 93a184123fb2ec..5d94795fcdd30b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs @@ -982,42 +982,7 @@ internal void Ldc(int intVar) { if (_codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldc.i4 " + intVar); - switch (intVar) - { - case -1: - _ilGen.Emit(OpCodes.Ldc_I4_M1); - break; - case 0: - _ilGen.Emit(OpCodes.Ldc_I4_0); - break; - case 1: - _ilGen.Emit(OpCodes.Ldc_I4_1); - break; - case 2: - _ilGen.Emit(OpCodes.Ldc_I4_2); - break; - case 3: - _ilGen.Emit(OpCodes.Ldc_I4_3); - break; - case 4: - _ilGen.Emit(OpCodes.Ldc_I4_4); - break; - case 5: - _ilGen.Emit(OpCodes.Ldc_I4_5); - break; - case 6: - _ilGen.Emit(OpCodes.Ldc_I4_6); - break; - case 7: - _ilGen.Emit(OpCodes.Ldc_I4_7); - break; - case 8: - _ilGen.Emit(OpCodes.Ldc_I4_8); - break; - default: - _ilGen.Emit(OpCodes.Ldc_I4, intVar); - break; - } + _ilGen.Emit(OpCodes.Ldc_I4, intVar); } internal void Ldc(long l) @@ -1103,37 +1068,16 @@ internal void Ldarg(int slot) { if (_codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldarg " + slot); - switch (slot) - { - case 0: - _ilGen.Emit(OpCodes.Ldarg_0); - break; - case 1: - _ilGen.Emit(OpCodes.Ldarg_1); - break; - case 2: - _ilGen.Emit(OpCodes.Ldarg_2); - break; - case 3: - _ilGen.Emit(OpCodes.Ldarg_3); - break; - default: - if (slot <= 255) - _ilGen.Emit(OpCodes.Ldarg_S, slot); - else - _ilGen.Emit(OpCodes.Ldarg, slot); - break; - } + + _ilGen.Emit(OpCodes.Ldarg, slot); } internal void Starg(int slot) { if (_codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Starg " + slot); - if (slot <= 255) - _ilGen.Emit(OpCodes.Starg_S, slot); - else - _ilGen.Emit(OpCodes.Starg, slot); + + _ilGen.Emit(OpCodes.Starg, slot); } internal void Ldarga(ArgBuilder argBuilder) @@ -1145,10 +1089,8 @@ internal void Ldarga(int slot) { if (_codeGenTrace != CodeGenTrace.None) EmitSourceInstruction("Ldarga " + slot); - if (slot <= 255) - _ilGen.Emit(OpCodes.Ldarga_S, slot); - else - _ilGen.Emit(OpCodes.Ldarga, slot); + + _ilGen.Emit(OpCodes.Ldarga, slot); } internal void Ldlen() diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonWriter.cs index 6f09bd393b63b6..2f0194b2334b67 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlJsonWriter.cs @@ -245,7 +245,7 @@ public override string LookupPrefix(string ns) { return JsonGlobals.xmlPrefix; } - if (ns == string.Empty) + if (ns.Length == 0) { return string.Empty; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs index d9d9277f334854..67f0afc57a0175 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs @@ -502,8 +502,8 @@ private CollectionSetItemDelegate GetCollectionSetItemDelegate(CollectionData { Type keyType = collectionContract.ItemType.GenericTypeArguments[0]; Type valueType = collectionContract.ItemType.GenericTypeArguments[1]; - Func objectToKeyValuePairGetKey = (Func)s_objectToKeyValuePairGetKey.MakeGenericMethod(keyType, valueType).CreateDelegate(typeof(Func)); - Func objectToKeyValuePairGetValue = (Func)s_objectToKeyValuePairGetValue.MakeGenericMethod(keyType, valueType).CreateDelegate(typeof(Func)); + Func objectToKeyValuePairGetKey = s_objectToKeyValuePairGetKey.MakeGenericMethod(keyType, valueType).CreateDelegate>(); + Func objectToKeyValuePairGetValue = s_objectToKeyValuePairGetValue.MakeGenericMethod(keyType, valueType).CreateDelegate>(); if (collectionContract.Kind == CollectionKind.GenericDictionary) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs index 6c10360268146a..3f9c5dc1e84f3e 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs @@ -55,7 +55,7 @@ protected override void ReflectionReadMembers(XmlReaderDelegator xmlReader, XmlO context.IncrementItemCount(memberCount); int memberIndex = -1; int firstRequiredMember; - bool[] requiredMembers = GetRequiredMembers(classContract, out firstRequiredMember); + _ = GetRequiredMembers(classContract, out firstRequiredMember); bool hasRequiredMembers = (firstRequiredMember < memberCount); int requiredIndex = hasRequiredMembers ? firstRequiredMember : -1; DataMember[] members = new DataMember[memberCount]; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs index f610d58635d4d0..b5de0afbeb7636 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs @@ -450,7 +450,7 @@ private void ExportISerializableDataContract(ClassDataContract dataContract, Xml XmlElement isValueTypeElement = null; if (dataContract.BaseContract != null) { - XmlSchemaComplexContentExtension extension = CreateTypeContent(type, dataContract.BaseContract.StableName, schema); + _ = CreateTypeContent(type, dataContract.BaseContract.StableName, schema); } else { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs index 8eb7f8ee8f6f3d..bd5f5d8e3b6c49 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs @@ -119,7 +119,7 @@ public XmlFormatClassReaderDelegate GenerateClassReader(ClassDataContract classC ReadClass(classContract); } - bool isFactoryType = InvokeFactoryMethod(classContract, objectId); + _ = InvokeFactoryMethod(classContract, objectId); if (Globals.TypeOfIDeserializationCallback.IsAssignableFrom(classContract.UnderlyingType)) { _ilg.Call(_objectLocal, XmlFormatGeneratorStatics.OnDeserializationMethod, null); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBufferReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBufferReader.cs index 64dbb9a7b9f405..43d74a87879fb7 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBufferReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBufferReader.cs @@ -213,28 +213,37 @@ private bool TryEnsureBytes(int count) { if (_stream == null) return false; - DiagnosticUtility.DebugAssert(_offset <= int.MaxValue - count, ""); - int newOffsetMax = _offset + count; - if (newOffsetMax < _offsetMax) - return true; - DiagnosticUtility.DebugAssert(newOffsetMax <= _windowOffsetMax, ""); - if (newOffsetMax > _buffer.Length) - { - byte[] newBuffer = new byte[Math.Max(newOffsetMax, _buffer.Length * 2)]; - System.Buffer.BlockCopy(_buffer, 0, newBuffer, 0, _offsetMax); - _buffer = newBuffer; - _streamBuffer = newBuffer; - } - int needed = newOffsetMax - _offsetMax; - while (needed > 0) + + // The data could be coming from an untrusted source, so we use a standard + // "multiply by 2" growth algorithm to avoid overly large memory utilization. + // Constant value of 256 comes from MemoryStream implementation. + + do { - int actual = _stream.Read(_buffer, _offsetMax, needed); - if (actual == 0) - return false; - _offsetMax += actual; - needed -= actual; - } - return true; + DiagnosticUtility.DebugAssert(_offset <= int.MaxValue - count, ""); + int newOffsetMax = _offset + count; + if (newOffsetMax <= _offsetMax) + return true; + DiagnosticUtility.DebugAssert(newOffsetMax <= _windowOffsetMax, ""); + if (newOffsetMax > _buffer.Length) + { + byte[] newBuffer = new byte[Math.Max(256, _buffer.Length * 2)]; + System.Buffer.BlockCopy(_buffer, 0, newBuffer, 0, _offsetMax); + newOffsetMax = Math.Min(newOffsetMax, newBuffer.Length); + _buffer = newBuffer; + _streamBuffer = newBuffer; + } + int needed = newOffsetMax - _offsetMax; + DiagnosticUtility.DebugAssert(needed > 0, ""); + do + { + int actual = _stream.Read(_buffer, _offsetMax, needed); + if (actual == 0) + return false; + _offsetMax += actual; + needed -= actual; + } while (needed > 0); + } while (true); } public void Advance(int count) @@ -491,7 +500,7 @@ public TimeSpan ReadTimeSpan() public Guid ReadGuid() { int offset; - byte[] buffer = GetBuffer(ValueHandleLength.Guid, out offset); + _ = GetBuffer(ValueHandleLength.Guid, out offset); Guid guid = GetGuid(offset); Advance(ValueHandleLength.Guid); return guid; @@ -500,7 +509,7 @@ public Guid ReadGuid() public string ReadUTF8String(int length) { int offset; - byte[] buffer = GetBuffer(length, out offset); + _ = GetBuffer(length, out offset); char[] chars = GetCharBuffer(length); int charCount = GetChars(offset, length, chars); string value = new string(chars, 0, charCount); @@ -844,7 +853,6 @@ public bool IsWhitespaceUTF8(int offset, int length) public bool IsWhitespaceUnicode(int offset, int length) { - byte[] buffer = _buffer; for (int i = 0; i < length; i += sizeof(char)) { char ch = (char)GetInt16(offset + i); diff --git a/src/libraries/System.Private.Uri/System.Private.Uri.sln b/src/libraries/System.Private.Uri/System.Private.Uri.sln index a802b272722615..3af73ec647fbe1 100644 --- a/src/libraries/System.Private.Uri/System.Private.Uri.sln +++ b/src/libraries/System.Private.Uri/System.Private.Uri.sln @@ -23,7 +23,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1A2F9F4A EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E893-4E87-987E-04EF0DCEAEFD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{CEFAB3B8-3B7F-4B6C-9A5F-2DCDD1A551B5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{CEFAB3B8-3B7F-4B6C-9A5F-2DCDD1A551B5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime", "..\System.Runtime\src\System.Runtime.csproj", "{375E5A4A-9026-411E-9CD8-606874CFF7F0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -51,6 +53,10 @@ Global {CEFAB3B8-3B7F-4B6C-9A5F-2DCDD1A551B5}.Debug|Any CPU.Build.0 = Debug|Any CPU {CEFAB3B8-3B7F-4B6C-9A5F-2DCDD1A551B5}.Release|Any CPU.ActiveCfg = Release|Any CPU {CEFAB3B8-3B7F-4B6C-9A5F-2DCDD1A551B5}.Release|Any CPU.Build.0 = Release|Any CPU + {375E5A4A-9026-411E-9CD8-606874CFF7F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {375E5A4A-9026-411E-9CD8-606874CFF7F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {375E5A4A-9026-411E-9CD8-606874CFF7F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {375E5A4A-9026-411E-9CD8-606874CFF7F0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -61,6 +67,7 @@ Global {96AF3242-A368-4F13-B006-A722CC3B8517} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} {4AC5343E-6E31-4BA5-A795-0493AE7E9008} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {CEFAB3B8-3B7F-4B6C-9A5F-2DCDD1A551B5} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} + {375E5A4A-9026-411E-9CD8-606874CFF7F0} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2151451C-8B2A-44DB-881E-B922A4795A30} diff --git a/src/libraries/System.Private.Uri/src/Resources/Strings.resx b/src/libraries/System.Private.Uri/src/Resources/Strings.resx index 655f2820692e2c..92a87cd44ccaa1 100644 --- a/src/libraries/System.Private.Uri/src/Resources/Strings.resx +++ b/src/libraries/System.Private.Uri/src/Resources/Strings.resx @@ -1,4 +1,5 @@ - + + -- suppress ws betw and comment - RawText(base.newLineChars); + RawText(base._newLineChars); for (int i = _indentLevel; i > 0; i--) { RawText(_indentChars); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/HtmlRawTextWriterGenerator.ttinclude b/src/libraries/System.Private.Xml/src/System/Xml/Core/HtmlRawTextWriterGenerator.ttinclude index f8101cbe653ae6..09cc00e36c08bb 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/HtmlRawTextWriterGenerator.ttinclude +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/HtmlRawTextWriterGenerator.ttinclude @@ -19,8 +19,8 @@ namespace System.Xml { internal class <#= ClassName #> : <#= BaseClassName #> { - protected ByteStack elementScope; - protected ElementProperties currentElementProperties; + protected ByteStack _elementScope; + protected ElementProperties _currentElementProperties; private AttributeProperties _currentAttributeProperties; private bool _endsWithAmpersand; @@ -29,8 +29,8 @@ namespace System.Xml private string _mediaType; private bool _doNotEscapeUriAttributes; - protected static TernaryTreeReadOnly elementPropertySearch; - protected static TernaryTreeReadOnly attributePropertySearch; + protected static TernaryTreeReadOnly _elementPropertySearch; + protected static TernaryTreeReadOnly _attributePropertySearch; private const int StackIncrement = 10; <# if (WriterType == RawTextWriterType.Encoded) { #> @@ -108,7 +108,7 @@ namespace System.Xml { Debug.Assert(localName != null && localName.Length != 0 && prefix != null && ns != null); - elementScope.Push((byte)currentElementProperties); + _elementScope.Push((byte)_currentElementProperties); if (ns.Length == 0) { @@ -116,7 +116,7 @@ namespace System.Xml #><#= SetTextContentMark(4, false) #> - currentElementProperties = (ElementProperties)elementPropertySearch.FindCaseInsensitiveString(localName); + _currentElementProperties = (ElementProperties)_elementPropertySearch.FindCaseInsensitiveString(localName); base.<#= BufferName #>[bufPos++] = (<#= BufferType #>)'<'; base.RawText(localName); base.attrEndPos = bufPos; @@ -125,7 +125,7 @@ namespace System.Xml { // Since the HAS_NS has no impact to the ElementTextBlock behavior, // we don't need to push it into the stack. - currentElementProperties = ElementProperties.HAS_NS; + _currentElementProperties = ElementProperties.HAS_NS; base.WriteStartElement(prefix, localName, ns); } } @@ -138,7 +138,7 @@ namespace System.Xml // Detect whether content is output contentPos = bufPos; - if ((currentElementProperties & ElementProperties.HEAD) != 0) + if ((_currentElementProperties & ElementProperties.HEAD) != 0) { WriteMetaElement(); } @@ -156,7 +156,7 @@ namespace System.Xml #><#= SetTextContentMark(4, false) #> - if ((currentElementProperties & ElementProperties.EMPTY) == 0) + if ((_currentElementProperties & ElementProperties.EMPTY) == 0) { <#= BufferName #>[base.bufPos++] = (<#= BufferType #>)'<'; <#= BufferName #>[base.bufPos++] = (<#= BufferType #>)'/'; @@ -170,7 +170,7 @@ namespace System.Xml base.WriteEndElement(prefix, localName, ns); } - currentElementProperties = (ElementProperties)elementScope.Pop(); + _currentElementProperties = (ElementProperties)_elementScope.Pop(); } internal override void WriteFullEndElement(string prefix, string localName, string ns) @@ -181,7 +181,7 @@ namespace System.Xml #><#= SetTextContentMark(4, false) #> - if ((currentElementProperties & ElementProperties.EMPTY) == 0) + if ((_currentElementProperties & ElementProperties.EMPTY) == 0) { <#= BufferName #>[base.bufPos++] = (<#= BufferType #>)'<'; <#= BufferName #>[base.bufPos++] = (<#= BufferType #>)'/'; @@ -195,7 +195,7 @@ namespace System.Xml base.WriteFullEndElement(prefix, localName, ns); } - currentElementProperties = (ElementProperties)elementScope.Pop(); + _currentElementProperties = (ElementProperties)_elementScope.Pop(); } // 1. How the outputBooleanAttribute(fBOOL) and outputHtmlUriText(fURI) being set? @@ -311,10 +311,10 @@ namespace System.Xml } base.RawText(localName); - if ((currentElementProperties & (ElementProperties.BOOL_PARENT | ElementProperties.URI_PARENT | ElementProperties.NAME_PARENT)) != 0) + if ((_currentElementProperties & (ElementProperties.BOOL_PARENT | ElementProperties.URI_PARENT | ElementProperties.NAME_PARENT)) != 0) { - _currentAttributeProperties = (AttributeProperties)attributePropertySearch.FindCaseInsensitiveString(localName) & - (AttributeProperties)currentElementProperties; + _currentAttributeProperties = (AttributeProperties)_attributePropertySearch.FindCaseInsensitiveString(localName) & + (AttributeProperties)_currentElementProperties; if ((_currentAttributeProperties & AttributeProperties.BOOLEAN) != 0) { @@ -451,16 +451,16 @@ namespace System.Xml Debug.Assert((int)ElementProperties.BOOL_PARENT == (int)AttributeProperties.BOOLEAN); Debug.Assert((int)ElementProperties.NAME_PARENT == (int)AttributeProperties.NAME); - if (elementPropertySearch == null) + if (_elementPropertySearch == null) { - //elementPropertySearch should be init last for the mutli thread safe situation. - attributePropertySearch = new TernaryTreeReadOnly(HtmlTernaryTree.htmlAttributes); - elementPropertySearch = new TernaryTreeReadOnly(HtmlTernaryTree.htmlElements); + //_elementPropertySearch should be init last for the mutli thread safe situation. + _attributePropertySearch = new TernaryTreeReadOnly(HtmlTernaryTree.htmlAttributes); + _elementPropertySearch = new TernaryTreeReadOnly(HtmlTernaryTree.htmlElements); } - elementScope = new ByteStack(StackIncrement); + _elementScope = new ByteStack(StackIncrement); _uriEscapingBuffer = new byte[5]; - currentElementProperties = ElementProperties.DEFAULT; + _currentElementProperties = ElementProperties.DEFAULT; _mediaType = settings.MediaType; _doNotEscapeUriAttributes = settings.DoNotEscapeUriAttributes; @@ -493,7 +493,7 @@ namespace System.Xml // only the top of the stack is the real E1 element properties. protected unsafe void WriteHtmlElementTextBlock(char* pSrc, char* pSrcEnd) { - if ((currentElementProperties & ElementProperties.NO_ENTITIES) != 0) + if ((_currentElementProperties & ElementProperties.NO_ENTITIES) != 0) { base.RawText(pSrc, pSrcEnd); } @@ -522,7 +522,7 @@ namespace System.Xml WriteHtmlAttributeText(pSrc, pSrcEnd); } } - else if ((currentElementProperties & ElementProperties.HAS_NS) != 0) + else if ((_currentElementProperties & ElementProperties.HAS_NS) != 0) { base.WriteAttributeTextBlock(pSrc, pSrcEnd); } @@ -844,15 +844,15 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - base.elementScope.Push((byte)base.currentElementProperties); + base._elementScope.Push((byte)base._currentElementProperties); if (ns.Length == 0) { Debug.Assert(prefix.Length == 0); - base.currentElementProperties = (ElementProperties)elementPropertySearch.FindCaseInsensitiveString(localName); + base._currentElementProperties = (ElementProperties)_elementPropertySearch.FindCaseInsensitiveString(localName); - if (_endBlockPos == base.bufPos && (base.currentElementProperties & ElementProperties.BLOCK_WS) != 0) + if (_endBlockPos == base.bufPos && (base._currentElementProperties & ElementProperties.BLOCK_WS) != 0) { WriteIndent(); } @@ -862,7 +862,7 @@ namespace System.Xml } else { - base.currentElementProperties = ElementProperties.HAS_NS | ElementProperties.BLOCK_WS; + base._currentElementProperties = ElementProperties.HAS_NS | ElementProperties.BLOCK_WS; if (_endBlockPos == base.bufPos) { @@ -888,13 +888,13 @@ namespace System.Xml // Detect whether content is output base.contentPos = base.bufPos; - if ((currentElementProperties & ElementProperties.HEAD) != 0) + if ((_currentElementProperties & ElementProperties.HEAD) != 0) { WriteIndent(); WriteMetaElement(); _endBlockPos = base.bufPos; } - else if ((base.currentElementProperties & ElementProperties.BLOCK_WS) != 0) + else if ((base._currentElementProperties & ElementProperties.BLOCK_WS) != 0) { // store the element block position _endBlockPos = base.bufPos; @@ -909,7 +909,7 @@ namespace System.Xml _indentLevel--; // If this element has block whitespace properties, - isBlockWs = (base.currentElementProperties & ElementProperties.BLOCK_WS) != 0; + isBlockWs = (base._currentElementProperties & ElementProperties.BLOCK_WS) != 0; if (isBlockWs) { // And if the last node to be output had block whitespace properties, diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/HtmlTernaryTree.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/HtmlTernaryTree.cs index 10dadafaa6da87..109687f59e2d6f 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/HtmlTernaryTree.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/HtmlTernaryTree.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable // This file is generated by TernaryTreeGenerator.cs, // and is used by the TernaryTreeRO class. diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/HtmlUtf8RawTextWriter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/HtmlUtf8RawTextWriter.cs index f9934ec9548d17..375a10747e6b09 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/HtmlUtf8RawTextWriter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/HtmlUtf8RawTextWriter.cs @@ -17,8 +17,8 @@ namespace System.Xml { internal class HtmlUtf8RawTextWriter : XmlUtf8RawTextWriter { - protected ByteStack elementScope; - protected ElementProperties currentElementProperties; + protected ByteStack _elementScope; + protected ElementProperties _currentElementProperties; private AttributeProperties _currentAttributeProperties; private bool _endsWithAmpersand; @@ -27,8 +27,8 @@ internal class HtmlUtf8RawTextWriter : XmlUtf8RawTextWriter private string _mediaType; private bool _doNotEscapeUriAttributes; - protected static TernaryTreeReadOnly elementPropertySearch; - protected static TernaryTreeReadOnly attributePropertySearch; + protected static TernaryTreeReadOnly _elementPropertySearch; + protected static TernaryTreeReadOnly _attributePropertySearch; private const int StackIncrement = 10; @@ -69,27 +69,27 @@ public override void WriteDocType(string name, string pubid, string sysid, strin RawText("\" \""); RawText(sysid); } - bufBytes[bufPos++] = (byte)'"'; + _bufBytes[_bufPos++] = (byte)'"'; } else if (sysid != null) { RawText(" SYSTEM \""); RawText(sysid); - bufBytes[bufPos++] = (byte)'"'; + _bufBytes[_bufPos++] = (byte)'"'; } else { - bufBytes[bufPos++] = (byte)' '; + _bufBytes[_bufPos++] = (byte)' '; } if (subset != null) { - bufBytes[bufPos++] = (byte)'['; + _bufBytes[_bufPos++] = (byte)'['; RawText(subset); - bufBytes[bufPos++] = (byte)']'; + _bufBytes[_bufPos++] = (byte)']'; } - bufBytes[bufPos++] = (byte)'>'; + _bufBytes[_bufPos++] = (byte)'>'; } // For the HTML element, it should call this method with ns and prefix as String.Empty @@ -97,22 +97,22 @@ public override void WriteStartElement(string prefix, string localName, string n { Debug.Assert(localName != null && localName.Length != 0 && prefix != null && ns != null); - elementScope.Push((byte)currentElementProperties); + _elementScope.Push((byte)_currentElementProperties); if (ns.Length == 0) { Debug.Assert(prefix.Length == 0); - currentElementProperties = (ElementProperties)elementPropertySearch.FindCaseInsensitiveString(localName); - base.bufBytes[bufPos++] = (byte)'<'; + _currentElementProperties = (ElementProperties)_elementPropertySearch.FindCaseInsensitiveString(localName); + base._bufBytes[_bufPos++] = (byte)'<'; base.RawText(localName); - base.attrEndPos = bufPos; + base._attrEndPos = _bufPos; } else { // Since the HAS_NS has no impact to the ElementTextBlock behavior, // we don't need to push it into the stack. - currentElementProperties = ElementProperties.HAS_NS; + _currentElementProperties = ElementProperties.HAS_NS; base.WriteStartElement(prefix, localName, ns); } } @@ -120,12 +120,12 @@ public override void WriteStartElement(string prefix, string localName, string n // Output >. For HTML needs to output META info internal override void StartElementContent() { - base.bufBytes[base.bufPos++] = (byte)'>'; + base._bufBytes[base._bufPos++] = (byte)'>'; // Detect whether content is output - contentPos = bufPos; + _contentPos = _bufPos; - if ((currentElementProperties & ElementProperties.HEAD) != 0) + if ((_currentElementProperties & ElementProperties.HEAD) != 0) { WriteMetaElement(); } @@ -141,12 +141,12 @@ internal override void WriteEndElement(string prefix, string localName, string n { Debug.Assert(prefix.Length == 0); - if ((currentElementProperties & ElementProperties.EMPTY) == 0) + if ((_currentElementProperties & ElementProperties.EMPTY) == 0) { - bufBytes[base.bufPos++] = (byte)'<'; - bufBytes[base.bufPos++] = (byte)'/'; + _bufBytes[base._bufPos++] = (byte)'<'; + _bufBytes[base._bufPos++] = (byte)'/'; base.RawText(localName); - bufBytes[base.bufPos++] = (byte)'>'; + _bufBytes[base._bufPos++] = (byte)'>'; } } else @@ -155,7 +155,7 @@ internal override void WriteEndElement(string prefix, string localName, string n base.WriteEndElement(prefix, localName, ns); } - currentElementProperties = (ElementProperties)elementScope.Pop(); + _currentElementProperties = (ElementProperties)_elementScope.Pop(); } internal override void WriteFullEndElement(string prefix, string localName, string ns) @@ -164,12 +164,12 @@ internal override void WriteFullEndElement(string prefix, string localName, stri { Debug.Assert(prefix.Length == 0); - if ((currentElementProperties & ElementProperties.EMPTY) == 0) + if ((_currentElementProperties & ElementProperties.EMPTY) == 0) { - bufBytes[base.bufPos++] = (byte)'<'; - bufBytes[base.bufPos++] = (byte)'/'; + _bufBytes[base._bufPos++] = (byte)'<'; + _bufBytes[base._bufPos++] = (byte)'/'; base.RawText(localName); - bufBytes[base.bufPos++] = (byte)'>'; + _bufBytes[base._bufPos++] = (byte)'>'; } } else @@ -178,7 +178,7 @@ internal override void WriteFullEndElement(string prefix, string localName, stri base.WriteFullEndElement(prefix, localName, ns); } - currentElementProperties = (ElementProperties)elementScope.Pop(); + _currentElementProperties = (ElementProperties)_elementScope.Pop(); } // 1. How the outputBooleanAttribute(fBOOL) and outputHtmlUriText(fURI) being set? @@ -286,20 +286,20 @@ public override void WriteStartAttribute(string prefix, string localName, string { Debug.Assert(prefix.Length == 0); - if (base.attrEndPos == bufPos) + if (base._attrEndPos == _bufPos) { - base.bufBytes[bufPos++] = (byte)' '; + base._bufBytes[_bufPos++] = (byte)' '; } base.RawText(localName); - if ((currentElementProperties & (ElementProperties.BOOL_PARENT | ElementProperties.URI_PARENT | ElementProperties.NAME_PARENT)) != 0) + if ((_currentElementProperties & (ElementProperties.BOOL_PARENT | ElementProperties.URI_PARENT | ElementProperties.NAME_PARENT)) != 0) { - _currentAttributeProperties = (AttributeProperties)attributePropertySearch.FindCaseInsensitiveString(localName) & - (AttributeProperties)currentElementProperties; + _currentAttributeProperties = (AttributeProperties)_attributePropertySearch.FindCaseInsensitiveString(localName) & + (AttributeProperties)_currentElementProperties; if ((_currentAttributeProperties & AttributeProperties.BOOLEAN) != 0) { - base.inAttributeValue = true; + base._inAttributeValue = true; return; } } @@ -308,8 +308,8 @@ public override void WriteStartAttribute(string prefix, string localName, string _currentAttributeProperties = AttributeProperties.DEFAULT; } - base.bufBytes[bufPos++] = (byte)'='; - base.bufBytes[bufPos++] = (byte)'"'; + base._bufBytes[_bufPos++] = (byte)'='; + base._bufBytes[_bufPos++] = (byte)'"'; } else { @@ -317,7 +317,7 @@ public override void WriteStartAttribute(string prefix, string localName, string _currentAttributeProperties = AttributeProperties.DEFAULT; } - base.inAttributeValue = true; + base._inAttributeValue = true; } // Output the amp; at end of EndAttribute @@ -325,7 +325,7 @@ public override void WriteEndAttribute() { if ((_currentAttributeProperties & AttributeProperties.BOOLEAN) != 0) { - base.attrEndPos = bufPos; + base._attrEndPos = _bufPos; } else { @@ -335,10 +335,10 @@ public override void WriteEndAttribute() _endsWithAmpersand = false; } - base.bufBytes[bufPos++] = (byte)'"'; + base._bufBytes[_bufPos++] = (byte)'"'; } - base.inAttributeValue = false; - base.attrEndPos = bufPos; + base._inAttributeValue = false; + base._attrEndPos = _bufPos; } // HTML PI's use ">" to terminate rather than "?>". @@ -346,16 +346,16 @@ public override void WriteProcessingInstruction(string target, string text) { Debug.Assert(target != null && target.Length != 0 && text != null); - bufBytes[base.bufPos++] = (byte)'<'; - bufBytes[base.bufPos++] = (byte)'?'; + _bufBytes[base._bufPos++] = (byte)'<'; + _bufBytes[base._bufPos++] = (byte)'?'; base.RawText(target); - bufBytes[base.bufPos++] = (byte)' '; + _bufBytes[base._bufPos++] = (byte)' '; base.WriteCommentOrPi(text, '?'); - base.bufBytes[base.bufPos++] = (byte)'>'; + base._bufBytes[base._bufPos++] = (byte)'>'; - if (base.bufPos > base.bufLen) + if (base._bufPos > base._bufLen) { FlushBuffer(); } @@ -369,7 +369,7 @@ public override unsafe void WriteString(string text) fixed (char* pSrc = text) { char* pSrcEnd = pSrc + text.Length; - if (base.inAttributeValue) + if (base._inAttributeValue) { WriteHtmlAttributeTextBlock(pSrc, pSrcEnd); } @@ -403,7 +403,7 @@ public override unsafe void WriteChars(char[] buffer, int index, int count) fixed (char* pSrcBegin = &buffer[index]) { - if (inAttributeValue) + if (_inAttributeValue) { WriteAttributeTextBlock(pSrcBegin, pSrcBegin + count); } @@ -424,16 +424,16 @@ private void Init(XmlWriterSettings settings) Debug.Assert((int)ElementProperties.BOOL_PARENT == (int)AttributeProperties.BOOLEAN); Debug.Assert((int)ElementProperties.NAME_PARENT == (int)AttributeProperties.NAME); - if (elementPropertySearch == null) + if (_elementPropertySearch == null) { //elementPropertySearch should be init last for the mutli thread safe situation. - attributePropertySearch = new TernaryTreeReadOnly(HtmlTernaryTree.htmlAttributes); - elementPropertySearch = new TernaryTreeReadOnly(HtmlTernaryTree.htmlElements); + _attributePropertySearch = new TernaryTreeReadOnly(HtmlTernaryTree.htmlAttributes); + _elementPropertySearch = new TernaryTreeReadOnly(HtmlTernaryTree.htmlElements); } - elementScope = new ByteStack(StackIncrement); + _elementScope = new ByteStack(StackIncrement); _uriEscapingBuffer = new byte[5]; - currentElementProperties = ElementProperties.DEFAULT; + _currentElementProperties = ElementProperties.DEFAULT; _mediaType = settings.MediaType; _doNotEscapeUriAttributes = settings.DoNotEscapeUriAttributes; @@ -451,7 +451,7 @@ protected void WriteMetaElement() base.RawText(" content=\""); base.RawText(_mediaType); base.RawText("; charset="); - base.RawText(base.encoding.WebName); + base.RawText(base._encoding.WebName); base.RawText("\">"); } @@ -466,7 +466,7 @@ protected void WriteMetaElement() // only the top of the stack is the real E1 element properties. protected unsafe void WriteHtmlElementTextBlock(char* pSrc, char* pSrcEnd) { - if ((currentElementProperties & ElementProperties.NO_ENTITIES) != 0) + if ((_currentElementProperties & ElementProperties.NO_ENTITIES) != 0) { base.RawText(pSrc, pSrcEnd); } @@ -495,7 +495,7 @@ protected unsafe void WriteHtmlAttributeTextBlock(char* pSrc, char* pSrcEnd) WriteHtmlAttributeText(pSrc, pSrcEnd); } } - else if ((currentElementProperties & ElementProperties.HAS_NS) != 0) + else if ((_currentElementProperties & ElementProperties.HAS_NS) != 0) { base.WriteAttributeTextBlock(pSrc, pSrcEnd); } @@ -536,20 +536,20 @@ private unsafe void WriteHtmlAttributeText(char* pSrc, char* pSrcEnd) _endsWithAmpersand = false; } - fixed (byte* pDstBegin = bufBytes) + fixed (byte* pDstBegin = _bufBytes) { - byte* pDst = pDstBegin + bufPos; + byte* pDst = pDstBegin + _bufPos; char ch = (char)0; while (true) { byte* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } - while (pDst < pDstEnd && (xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch <= 0x7F)) + while (pDst < pDstEnd && (_xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch <= 0x7F)) { *pDst++ = (byte)ch; pSrc++; @@ -565,7 +565,7 @@ private unsafe void WriteHtmlAttributeText(char* pSrc, char* pSrcEnd) // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; @@ -609,7 +609,7 @@ private unsafe void WriteHtmlAttributeText(char* pSrc, char* pSrcEnd) } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } } @@ -624,20 +624,20 @@ private unsafe void WriteUriAttributeText(char* pSrc, char* pSrcEnd) _endsWithAmpersand = false; } - fixed (byte* pDstBegin = bufBytes) + fixed (byte* pDstBegin = _bufBytes) { - byte* pDst = pDstBegin + bufPos; + byte* pDst = pDstBegin + _bufPos; char ch = (char)0; while (true) { byte* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } - while (pDst < pDstEnd && (xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch < 0x80)) + while (pDst < pDstEnd && (_xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch < 0x80)) { *pDst++ = (byte)ch; pSrc++; @@ -653,7 +653,7 @@ private unsafe void WriteUriAttributeText(char* pSrc, char* pSrcEnd) // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; @@ -712,17 +712,17 @@ private unsafe void WriteUriAttributeText(char* pSrc, char* pSrcEnd) } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } } // For handling &{ in Html text field. If & is not followed by {, it still needs to be escaped. private void OutputRestAmps() { - base.bufBytes[bufPos++] = (byte)'a'; - base.bufBytes[bufPos++] = (byte)'m'; - base.bufBytes[bufPos++] = (byte)'p'; - base.bufBytes[bufPos++] = (byte)';'; + base._bufBytes[_bufPos++] = (byte)'a'; + base._bufBytes[_bufPos++] = (byte)'m'; + base._bufBytes[_bufPos++] = (byte)'p'; + base._bufBytes[_bufPos++] = (byte)';'; } } @@ -797,67 +797,67 @@ public override void WriteDocType(string name, string pubid, string sysid, strin base.WriteDocType(name, pubid, sysid, subset); // Allow indentation after DocTypeDecl - _endBlockPos = base.bufPos; + _endBlockPos = base._bufPos; } public override void WriteStartElement(string prefix, string localName, string ns) { Debug.Assert(localName != null && localName.Length != 0 && prefix != null && ns != null); - base.elementScope.Push((byte)base.currentElementProperties); + base._elementScope.Push((byte)base._currentElementProperties); if (ns.Length == 0) { Debug.Assert(prefix.Length == 0); - base.currentElementProperties = (ElementProperties)elementPropertySearch.FindCaseInsensitiveString(localName); + base._currentElementProperties = (ElementProperties)_elementPropertySearch.FindCaseInsensitiveString(localName); - if (_endBlockPos == base.bufPos && (base.currentElementProperties & ElementProperties.BLOCK_WS) != 0) + if (_endBlockPos == base._bufPos && (base._currentElementProperties & ElementProperties.BLOCK_WS) != 0) { WriteIndent(); } _indentLevel++; - base.bufBytes[bufPos++] = (byte)'<'; + base._bufBytes[_bufPos++] = (byte)'<'; } else { - base.currentElementProperties = ElementProperties.HAS_NS | ElementProperties.BLOCK_WS; + base._currentElementProperties = ElementProperties.HAS_NS | ElementProperties.BLOCK_WS; - if (_endBlockPos == base.bufPos) + if (_endBlockPos == base._bufPos) { WriteIndent(); } _indentLevel++; - base.bufBytes[base.bufPos++] = (byte)'<'; + base._bufBytes[base._bufPos++] = (byte)'<'; if (prefix.Length != 0) { base.RawText(prefix); - base.bufBytes[base.bufPos++] = (byte)':'; + base._bufBytes[base._bufPos++] = (byte)':'; } } base.RawText(localName); - base.attrEndPos = bufPos; + base._attrEndPos = _bufPos; } internal override void StartElementContent() { - base.bufBytes[base.bufPos++] = (byte)'>'; + base._bufBytes[base._bufPos++] = (byte)'>'; // Detect whether content is output - base.contentPos = base.bufPos; + base._contentPos = base._bufPos; - if ((currentElementProperties & ElementProperties.HEAD) != 0) + if ((_currentElementProperties & ElementProperties.HEAD) != 0) { WriteIndent(); WriteMetaElement(); - _endBlockPos = base.bufPos; + _endBlockPos = base._bufPos; } - else if ((base.currentElementProperties & ElementProperties.BLOCK_WS) != 0) + else if ((base._currentElementProperties & ElementProperties.BLOCK_WS) != 0) { // store the element block position - _endBlockPos = base.bufPos; + _endBlockPos = base._bufPos; } } @@ -869,12 +869,12 @@ internal override void WriteEndElement(string prefix, string localName, string n _indentLevel--; // If this element has block whitespace properties, - isBlockWs = (base.currentElementProperties & ElementProperties.BLOCK_WS) != 0; + isBlockWs = (base._currentElementProperties & ElementProperties.BLOCK_WS) != 0; if (isBlockWs) { // And if the last node to be output had block whitespace properties, // And if content was output within this element, - if (_endBlockPos == base.bufPos && base.contentPos != base.bufPos) + if (_endBlockPos == base._bufPos && base._contentPos != base._bufPos) { // Then indent WriteIndent(); @@ -884,12 +884,12 @@ internal override void WriteEndElement(string prefix, string localName, string n base.WriteEndElement(prefix, localName, ns); // Reset contentPos in case of empty elements - base.contentPos = 0; + base._contentPos = 0; // Mark end of element in buffer for element's with block whitespace properties if (isBlockWs) { - _endBlockPos = base.bufPos; + _endBlockPos = base._bufPos; } } @@ -897,7 +897,7 @@ public override void WriteStartAttribute(string prefix, string localName, string { if (_newLineOnAttributes) { - RawText(base.newLineChars); + RawText(base._newLineChars); _indentLevel++; WriteIndent(); _indentLevel--; @@ -908,7 +908,7 @@ public override void WriteStartAttribute(string prefix, string localName, string protected override void FlushBuffer() { // Make sure the buffer will reset the block position - _endBlockPos = (_endBlockPos == base.bufPos) ? 1 : 0; + _endBlockPos = (_endBlockPos == base._bufPos) ? 1 : 0; base.FlushBuffer(); } @@ -936,7 +936,7 @@ private void WriteIndent() // -- suppress ws betw and PI // -- suppress ws betw and comment - RawText(base.newLineChars); + RawText(base._newLineChars); for (int i = _indentLevel; i > 0; i--) { RawText(_indentChars); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdInfo.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdInfo.cs index 21e345111768e6..2eb890599e6fae 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdInfo.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdInfo.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Collections.Generic; @@ -45,7 +46,7 @@ internal interface IDtdInfo /// The prefix of the attribute list to look for /// The local name of the attribute list to look for /// Interface representing an attribute list or null if none was found. - IDtdAttributeListInfo LookupAttributeList(string prefix, string localName); + IDtdAttributeListInfo? LookupAttributeList(string prefix, string localName); /// /// Returns an enumerator of all attribute lists defined in the DTD. diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParser.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParser.cs index 29cb22058e2b3f..062f9e8f30976d 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParser.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParser.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Xml; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParserAdapter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParserAdapter.cs index 634f939a2fac9f..0d9075f35f9e15 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParserAdapter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParserAdapter.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Text; using System.Xml.Schema; @@ -11,11 +12,11 @@ namespace System.Xml internal partial interface IDtdParserAdapter { XmlNameTable NameTable { get; } - IXmlNamespaceResolver NamespaceResolver { get; } + IXmlNamespaceResolver? NamespaceResolver { get; } - Uri BaseUri { get; } + Uri? BaseUri { get; } - char[] ParsingBuffer { get; } + char[]? ParsingBuffer { get; } int ParsingBufferLength { get; } int CurrentPosition { get; set; } int LineNo { get; } @@ -35,7 +36,7 @@ internal partial interface IDtdParserAdapter bool PushEntity(IDtdEntityInfo entity, out int entityId); - bool PopEntity(out IDtdEntityInfo oldEntity, out int newEntityId); + bool PopEntity(out IDtdEntityInfo? oldEntity, out int newEntityId); bool PushExternalSubset(string systemId, string publicId); @@ -49,7 +50,7 @@ internal partial interface IDtdParserAdapter internal interface IDtdParserAdapterWithValidation : IDtdParserAdapter { bool DtdValidation { get; } - IValidationEventHandling ValidationEventHandling { get; } + IValidationEventHandling? ValidationEventHandling { get; } } internal interface IDtdParserAdapterV1 : IDtdParserAdapterWithValidation diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParserAdapterAsync.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParserAdapterAsync.cs index 69ab5f38329d77..fbe5652d5fb2b0 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParserAdapterAsync.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParserAdapterAsync.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Text; using System.Xml.Schema; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParserAsync.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParserAsync.cs index 929a69f1f3ecfe..e9acacee7c4ce7 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParserAsync.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/IDtdParserAsync.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Xml; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/IRemovableWriter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/IRemovableWriter.cs index affd635ff1e77a..00666a5d344827 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/IRemovableWriter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/IRemovableWriter.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml { /// diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/IValidationEventHandling.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/IValidationEventHandling.cs index 528cad5a3f02bd..2b8f5d247b6e11 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/IValidationEventHandling.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/IValidationEventHandling.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Xml.Schema; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/IncrementalReadDecoders.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/IncrementalReadDecoders.cs index 912736c5081472..4cf58e2b3a9306 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/IncrementalReadDecoders.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/IncrementalReadDecoders.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; namespace System.Xml @@ -38,7 +39,7 @@ internal override void Reset() { } // internal class IncrementalReadCharsDecoder : IncrementalReadDecoder { - private char[] _buffer; + private char[]? _buffer; private int _startIndex; private int _curIndex; private int _endIndex; @@ -61,6 +62,7 @@ internal override bool IsFull internal override int Decode(char[] chars, int startPos, int len) { + Debug.Assert(_buffer != null); Debug.Assert(chars != null); Debug.Assert(len >= 0); Debug.Assert(startPos >= 0); @@ -73,6 +75,7 @@ internal override int Decode(char[] chars, int startPos, int len) { copyCount = len; } + Buffer.BlockCopy(chars, startPos * 2, _buffer, _curIndex * 2, copyCount * 2); _curIndex += copyCount; @@ -81,6 +84,7 @@ internal override int Decode(char[] chars, int startPos, int len) internal override int Decode(string str, int startPos, int len) { + Debug.Assert(_buffer != null); Debug.Assert(str != null); Debug.Assert(len >= 0); Debug.Assert(startPos >= 0); @@ -93,6 +97,7 @@ internal override int Decode(string str, int startPos, int len) { copyCount = len; } + str.CopyTo(startPos, _buffer, _curIndex, copyCount); _curIndex += copyCount; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/LocalAppContextSwitches.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/LocalAppContextSwitches.cs index a36958ec939014..f17a495025efb9 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/LocalAppContextSwitches.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/LocalAppContextSwitches.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Runtime.CompilerServices; namespace System diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/NamespaceHandling.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/NamespaceHandling.cs index 9fdb5af95a18bd..9627334206f0a0 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/NamespaceHandling.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/NamespaceHandling.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml { // diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/NewLineHandling.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/NewLineHandling.cs index eb387680844eb0..9ab4aeb40d5246 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/NewLineHandling.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/NewLineHandling.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml { // NewLineHandling specifies what will XmlWriter do with new line characters. The options are: diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/QueryOutputWriter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/QueryOutputWriter.cs index ea8030fe3f539c..9ab4c5b35bcf7f 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/QueryOutputWriter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/QueryOutputWriter.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml { using System; @@ -24,9 +25,9 @@ internal class QueryOutputWriter : XmlRawWriter { private readonly XmlRawWriter _wrapped; private bool _inCDataSection; - private readonly Dictionary _lookupCDataElems; - private readonly BitStack _bitsCData; - private readonly XmlQualifiedName _qnameCData; + private readonly Dictionary? _lookupCDataElems; + private readonly BitStack? _bitsCData; + private readonly XmlQualifiedName? _qnameCData; private bool _outputDocType; private readonly bool _checkWellFormedDoc; private bool _hasDocElem; @@ -86,15 +87,15 @@ public QueryOutputWriter(XmlRawWriter writer, XmlWriterSettings settings) /// /// Get and set the namespace resolver that's used by this RawWriter to resolve prefixes. /// - internal override IXmlNamespaceResolver NamespaceResolver + internal override IXmlNamespaceResolver? NamespaceResolver { get { - return this.resolver; + return this._resolver; } set { - this.resolver = value; + this._resolver = value; _wrapped.NamespaceResolver = value; } } @@ -119,7 +120,7 @@ public override XmlWriterSettings Settings { get { - XmlWriterSettings settings = _wrapped.Settings; + XmlWriterSettings settings = _wrapped.Settings!; settings.ReadOnly = false; settings.DocTypeSystem = _systemId; @@ -133,7 +134,7 @@ public override XmlWriterSettings Settings /// /// Suppress this explicit call to WriteDocType if information was provided by XmlWriterSettings. /// - public override void WriteDocType(string name, string pubid, string sysid, string subset) + public override void WriteDocType(string name, string? pubid, string? sysid, string? subset) { if (_publicId == null && _systemId == null) { @@ -146,7 +147,7 @@ public override void WriteDocType(string name, string pubid, string sysid, strin /// Check well-formedness, possibly output doc-type-decl, and determine whether this element is a /// CData section element. /// - public override void WriteStartElement(string prefix, string localName, string ns) + public override void WriteStartElement(string? prefix, string localName, string? ns) { EndCDataSection(); @@ -164,7 +165,7 @@ public override void WriteStartElement(string prefix, string localName, string n if (_outputDocType) { _wrapped.WriteDocType( - prefix.Length != 0 ? prefix + ":" + localName : localName, + string.IsNullOrEmpty(prefix) ? localName : prefix + ":" + localName, _publicId, _systemId, null); @@ -177,8 +178,8 @@ public override void WriteStartElement(string prefix, string localName, string n if (_lookupCDataElems != null) { // Determine whether this element is a CData section element - _qnameCData.Init(localName, ns); - _bitsCData.PushBit(_lookupCDataElems.ContainsKey(_qnameCData)); + _qnameCData!.Init(localName, ns); + _bitsCData!.PushBit(_lookupCDataElems.ContainsKey(_qnameCData)); } } @@ -192,7 +193,7 @@ internal override void WriteEndElement(string prefix, string localName, string n _depth--; if (_lookupCDataElems != null) - _bitsCData.PopBit(); + _bitsCData!.PopBit(); } internal override void WriteFullEndElement(string prefix, string localName, string ns) @@ -205,7 +206,7 @@ internal override void WriteFullEndElement(string prefix, string localName, stri _depth--; if (_lookupCDataElems != null) - _bitsCData.PopBit(); + _bitsCData!.PopBit(); } internal override void StartElementContent() @@ -213,7 +214,7 @@ internal override void StartElementContent() _wrapped.StartElementContent(); } - public override void WriteStartAttribute(string prefix, string localName, string ns) + public override void WriteStartAttribute(string? prefix, string localName, string? ns) { _inAttr = true; _wrapped.WriteStartAttribute(prefix, localName, ns); @@ -248,7 +249,7 @@ internal override void WriteEndNamespaceDeclaration() _wrapped.WriteEndNamespaceDeclaration(); } - public override void WriteCData(string text) + public override void WriteCData(string? text) { _wrapped.WriteCData(text); } @@ -273,7 +274,7 @@ public override void WriteWhitespace(string ws) _wrapped.WriteWhitespace(ws); } - public override void WriteString(string text) + public override void WriteString(string? text) { if (!_inAttr && (_inCDataSection || StartCDataSection())) _wrapped.WriteCData(text); @@ -351,7 +352,7 @@ public override void Flush() private bool StartCDataSection() { Debug.Assert(!_inCDataSection); - if (_lookupCDataElems != null && _bitsCData.PeekBit()) + if (_lookupCDataElems != null && _bitsCData!.PeekBit()) { _inCDataSection = true; return true; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/QueryOutputWriterV1.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/QueryOutputWriterV1.cs index 462854bc4c5548..4f6ea549c74593 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/QueryOutputWriterV1.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/QueryOutputWriterV1.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.IO; using System.Diagnostics; @@ -25,9 +26,9 @@ internal class QueryOutputWriterV1 : XmlWriter { private readonly XmlWriter _wrapped; private bool _inCDataSection; - private readonly Dictionary _lookupCDataElems; - private readonly BitStack _bitsCData; - private readonly XmlQualifiedName _qnameCData; + private readonly Dictionary? _lookupCDataElems; + private readonly BitStack? _bitsCData; + private readonly XmlQualifiedName? _qnameCData; private bool _outputDocType, _inAttr; private readonly string _systemId, _publicId; @@ -71,7 +72,7 @@ public QueryOutputWriterV1(XmlWriter writer, XmlWriterSettings settings) if (settings.CDataSectionElements != null && settings.CDataSectionElements.Count > 0) { _bitsCData = new BitStack(); - _lookupCDataElems = new Dictionary(); + _lookupCDataElems = new Dictionary(); _qnameCData = new XmlQualifiedName(); // Add each element name to the lookup table @@ -122,7 +123,7 @@ public override void WriteEndDocument() /// /// Suppress this explicit call to WriteDocType if information was provided by XmlWriterSettings. /// - public override void WriteDocType(string name, string pubid, string sysid, string subset) + public override void WriteDocType(string name, string? pubid, string? sysid, string? subset) { if (_publicId == null && _systemId == null) { @@ -135,7 +136,7 @@ public override void WriteDocType(string name, string pubid, string sysid, strin /// Output doc-type-decl on the first element, and determine whether this element is a /// CData section element. /// - public override void WriteStartElement(string prefix, string localName, string ns) + public override void WriteStartElement(string? prefix, string localName, string? ns) { EndCDataSection(); @@ -146,11 +147,12 @@ public override void WriteStartElement(string prefix, string localName, string n if (ws == WriteState.Start || ws == WriteState.Prolog) { _wrapped.WriteDocType( - prefix.Length != 0 ? prefix + ":" + localName : localName, + string.IsNullOrEmpty(prefix) ? localName : prefix + ":" + localName, _publicId, _systemId, null); } + _outputDocType = false; } @@ -158,6 +160,9 @@ public override void WriteStartElement(string prefix, string localName, string n if (_lookupCDataElems != null) { + Debug.Assert(_qnameCData != null); + Debug.Assert(_bitsCData != null); + // Determine whether this element is a CData section element _qnameCData.Init(localName, ns); _bitsCData.PushBit(_lookupCDataElems.ContainsKey(_qnameCData)); @@ -171,7 +176,10 @@ public override void WriteEndElement() _wrapped.WriteEndElement(); if (_lookupCDataElems != null) + { + Debug.Assert(_bitsCData != null); _bitsCData.PopBit(); + } } public override void WriteFullEndElement() @@ -181,10 +189,13 @@ public override void WriteFullEndElement() _wrapped.WriteFullEndElement(); if (_lookupCDataElems != null) + { + Debug.Assert(_bitsCData != null); _bitsCData.PopBit(); + } } - public override void WriteStartAttribute(string prefix, string localName, string ns) + public override void WriteStartAttribute(string? prefix, string localName, string? ns) { _inAttr = true; _wrapped.WriteStartAttribute(prefix, localName, ns); @@ -196,7 +207,7 @@ public override void WriteEndAttribute() _wrapped.WriteEndAttribute(); } - public override void WriteCData(string text) + public override void WriteCData(string? text) { _wrapped.WriteCData(text); } @@ -221,7 +232,7 @@ public override void WriteWhitespace(string ws) _wrapped.WriteWhitespace(ws); } - public override void WriteString(string text) + public override void WriteString(string? text) { if (!_inAttr && (_inCDataSection || StartCDataSection())) _wrapped.WriteCData(text); @@ -291,7 +302,7 @@ public override void Flush() _wrapped.Flush(); } - public override string LookupPrefix(string ns) + public override string? LookupPrefix(string ns) { return _wrapped.LookupPrefix(ns); } @@ -308,11 +319,12 @@ public override string LookupPrefix(string ns) private bool StartCDataSection() { Debug.Assert(!_inCDataSection); - if (_lookupCDataElems != null && _bitsCData.PeekBit()) + if (_lookupCDataElems != null && _bitsCData!.PeekBit()) { _inCDataSection = true; return true; } + return false; } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/RawTextWriterEncoded.ttinclude b/src/libraries/System.Private.Xml/src/System/Xml/Core/RawTextWriterEncoded.ttinclude index a3bd4d0b67053b..bfb440689a66e8 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/RawTextWriterEncoded.ttinclude +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/RawTextWriterEncoded.ttinclude @@ -5,7 +5,7 @@ WriterType = RawTextWriterType.Encoded; ClassName = "XmlEncodedRawTextWriter"; ClassNameIndent = "XmlEncodedRawTextWriterIndent"; - BufferName = "bufChars"; + BufferName = "_bufChars"; BufferType = "char"; EncodeCharBody = @"/* Surrogate character */ if (XmlCharType.IsSurrogate(ch)) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/ReadState.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/ReadState.cs index debd969070632b..b70702a2c9cf50 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/ReadState.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/ReadState.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml { // Specifies the state of the XmlReader. diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/TextEncodedRawTextWriter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/TextEncodedRawTextWriter.cs index 2059fc771e4953..bc9cbc38851eff 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/TextEncodedRawTextWriter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/TextEncodedRawTextWriter.cs @@ -67,12 +67,12 @@ internal override void StartElementContent() // Ignore attributes public override void WriteStartAttribute(string prefix, string localName, string ns) { - base.inAttributeValue = true; + base._inAttributeValue = true; } public override void WriteEndAttribute() { - base.inAttributeValue = false; + base._inAttributeValue = false; } // Ignore namespace declarations @@ -118,7 +118,7 @@ public override void WriteSurrogateCharEntity(char lowChar, char highChar) // Output text content without any escaping; ignore attribute values public override void WriteWhitespace(string ws) { - if (!base.inAttributeValue) + if (!base._inAttributeValue) { base.WriteRaw(ws); } @@ -127,7 +127,7 @@ public override void WriteWhitespace(string ws) // Output text content without any escaping; ignore attribute values public override void WriteString(string textBlock) { - if (!base.inAttributeValue) + if (!base._inAttributeValue) { base.WriteRaw(textBlock); } @@ -136,7 +136,7 @@ public override void WriteString(string textBlock) // Output text content without any escaping; ignore attribute values public override void WriteChars(char[] buffer, int index, int count) { - if (!base.inAttributeValue) + if (!base._inAttributeValue) { base.WriteRaw(buffer, index, count); } @@ -145,7 +145,7 @@ public override void WriteChars(char[] buffer, int index, int count) // Output text content without any escaping; ignore attribute values public override void WriteRaw(char[] buffer, int index, int count) { - if (!base.inAttributeValue) + if (!base._inAttributeValue) { base.WriteRaw(buffer, index, count); } @@ -154,7 +154,7 @@ public override void WriteRaw(char[] buffer, int index, int count) // Output text content without any escaping; ignore attribute values public override void WriteRaw(string data) { - if (!base.inAttributeValue) + if (!base._inAttributeValue) { base.WriteRaw(data); } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/TextUtf8RawTextWriter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/TextUtf8RawTextWriter.cs index 776f810949d276..b7df1c67074dcb 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/TextUtf8RawTextWriter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/TextUtf8RawTextWriter.cs @@ -62,12 +62,12 @@ internal override void StartElementContent() // Ignore attributes public override void WriteStartAttribute(string prefix, string localName, string ns) { - base.inAttributeValue = true; + base._inAttributeValue = true; } public override void WriteEndAttribute() { - base.inAttributeValue = false; + base._inAttributeValue = false; } // Ignore namespace declarations @@ -113,7 +113,7 @@ public override void WriteSurrogateCharEntity(char lowChar, char highChar) // Output text content without any escaping; ignore attribute values public override void WriteWhitespace(string ws) { - if (!base.inAttributeValue) + if (!base._inAttributeValue) { base.WriteRaw(ws); } @@ -122,7 +122,7 @@ public override void WriteWhitespace(string ws) // Output text content without any escaping; ignore attribute values public override void WriteString(string textBlock) { - if (!base.inAttributeValue) + if (!base._inAttributeValue) { base.WriteRaw(textBlock); } @@ -131,7 +131,7 @@ public override void WriteString(string textBlock) // Output text content without any escaping; ignore attribute values public override void WriteChars(char[] buffer, int index, int count) { - if (!base.inAttributeValue) + if (!base._inAttributeValue) { base.WriteRaw(buffer, index, count); } @@ -140,7 +140,7 @@ public override void WriteChars(char[] buffer, int index, int count) // Output text content without any escaping; ignore attribute values public override void WriteRaw(char[] buffer, int index, int count) { - if (!base.inAttributeValue) + if (!base._inAttributeValue) { base.WriteRaw(buffer, index, count); } @@ -149,7 +149,7 @@ public override void WriteRaw(char[] buffer, int index, int count) // Output text content without any escaping; ignore attribute values public override void WriteRaw(string data) { - if (!base.inAttributeValue) + if (!base._inAttributeValue) { base.WriteRaw(data); } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/ValidationType.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/ValidationType.cs index b3d10f3df2a1d9..a5c9f0f262cb86 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/ValidationType.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/ValidationType.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml { // Specifies the type of validation to perform in XmlValidatingReader or in XmlReaderSettings. diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/WhitespaceHandling.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/WhitespaceHandling.cs index fb2669117db356..650cbf2c1da0de 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/WhitespaceHandling.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/WhitespaceHandling.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml { // Specifies how whitespace is handled in XmlTextReader. diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlAsyncCheckWriter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlAsyncCheckWriter.cs index 0d7289e680c542..78dc6ac0bde4ed 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlAsyncCheckWriter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlAsyncCheckWriter.cs @@ -576,6 +576,13 @@ public override Task WriteNodeAsync(XPathNavigator navigator, bool defattr) _lastTask = task; return task; } + + protected override ValueTask DisposeAsyncCore() + { + CheckAsync(); + return _coreWriter.DisposeAsync(); + } + #endregion } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlAutoDetectWriter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlAutoDetectWriter.cs index dee8b8e5a6ffb7..62355d7b66b5f5 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlAutoDetectWriter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlAutoDetectWriter.cs @@ -277,11 +277,11 @@ internal override IXmlNamespaceResolver NamespaceResolver { get { - return this.resolver; + return this._resolver; } set { - this.resolver = value; + this._resolver = value; if (_wrapped == null) _eventCache.NamespaceResolver = value; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriter.cs index 5e170f0d817bf2..18d0cc012ba14b 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriter.cs @@ -31,60 +31,60 @@ internal partial class XmlEncodedRawTextWriter : XmlRawWriter private readonly bool _useAsync; // main buffer - protected byte[] bufBytes; + protected byte[] _bufBytes; // output stream - protected Stream stream; + protected Stream _stream; // encoding of the stream or text writer - protected Encoding encoding; + protected Encoding _encoding; // char type tables - protected XmlCharType xmlCharType = XmlCharType.Instance; + protected XmlCharType _xmlCharType = XmlCharType.Instance; // buffer positions - protected int bufPos = 1; // buffer position starts at 1, because we need to be able to safely step back -1 in case we need to - // close an empty element or in CDATA section detection of double ]; bufChars[0] will always be 0 - protected int textPos = 1; // text end position; don't indent first element, pi, or comment - protected int contentPos; // element content end position - protected int cdataPos; // cdata end position - protected int attrEndPos; // end of the last attribute - protected int bufLen = BUFSIZE; + protected int _bufPos = 1; // buffer position starts at 1, because we need to be able to safely step back -1 in case we need to + // close an empty element or in CDATA section detection of double ]; bufChars[0] will always be 0 + protected int _textPos = 1; // text end position; don't indent first element, pi, or comment + protected int _contentPos; // element content end position + protected int _cdataPos; // cdata end position + protected int _attrEndPos; // end of the last attribute + protected int _bufLen = BUFSIZE; // flags - protected bool writeToNull; - protected bool hadDoubleBracket; - protected bool inAttributeValue; + protected bool _writeToNull; + protected bool _hadDoubleBracket; + protected bool _inAttributeValue; - protected int bufBytesUsed; - protected char[] bufChars; + protected int _bufBytesUsed; + protected char[] _bufChars; // encoder for encoding chars in specified encoding when writing to stream - protected Encoder encoder; + protected Encoder _encoder; // output text writer - protected TextWriter writer; + protected TextWriter _writer; // escaping of characters invalid in the output encoding - protected bool trackTextContent; - protected bool inTextContent; + protected bool _trackTextContent; + protected bool _inTextContent; private int _lastMarkPos; private int[] _textContentMarks; // even indices contain text content start positions // odd indices contain markup start positions private readonly CharEntityEncoderFallback _charEntityFallback; // writer settings - protected NewLineHandling newLineHandling; - protected bool closeOutput; - protected bool omitXmlDeclaration; - protected string newLineChars; - protected bool checkCharacters; + protected NewLineHandling _newLineHandling; + protected bool _closeOutput; + protected bool _omitXmlDeclaration; + protected string _newLineChars; + protected bool _checkCharacters; - protected XmlStandalone standalone; - protected XmlOutputMethod outputMethod; + protected XmlStandalone _standalone; + protected XmlOutputMethod _outputMethod; - protected bool autoXmlDeclaration; - protected bool mergeCDataSections; + protected bool _autoXmlDeclaration; + protected bool _mergeCDataSections; // // Constants @@ -103,19 +103,19 @@ protected XmlEncodedRawTextWriter(XmlWriterSettings settings) _useAsync = settings.Async; // copy settings - newLineHandling = settings.NewLineHandling; - omitXmlDeclaration = settings.OmitXmlDeclaration; - newLineChars = settings.NewLineChars; - checkCharacters = settings.CheckCharacters; - closeOutput = settings.CloseOutput; + _newLineHandling = settings.NewLineHandling; + _omitXmlDeclaration = settings.OmitXmlDeclaration; + _newLineChars = settings.NewLineChars; + _checkCharacters = settings.CheckCharacters; + _closeOutput = settings.CloseOutput; - standalone = settings.Standalone; - outputMethod = settings.OutputMethod; - mergeCDataSections = settings.MergeCDataSections; + _standalone = settings.Standalone; + _outputMethod = settings.OutputMethod; + _mergeCDataSections = settings.MergeCDataSections; - if (checkCharacters && newLineHandling == NewLineHandling.Replace) + if (_checkCharacters && _newLineHandling == NewLineHandling.Replace) { - ValidateContentChars(newLineChars, "NewLineChars", false); + ValidateContentChars(_newLineChars, "NewLineChars", false); } } @@ -124,20 +124,20 @@ public XmlEncodedRawTextWriter(TextWriter writer, XmlWriterSettings settings) : { Debug.Assert(writer != null && settings != null); - this.writer = writer; - this.encoding = writer.Encoding; + this._writer = writer; + this._encoding = writer.Encoding; // the buffer is allocated will OVERFLOW in order to reduce checks when writing out constant size markup if (settings.Async) { - bufLen = ASYNCBUFSIZE; + _bufLen = ASYNCBUFSIZE; } - this.bufChars = new char[bufLen + OVERFLOW]; + this._bufChars = new char[_bufLen + OVERFLOW]; // Write the xml declaration if (settings.AutoXmlDeclaration) { - WriteXmlDeclaration(standalone); - autoXmlDeclaration = true; + WriteXmlDeclaration(_standalone); + _autoXmlDeclaration = true; } } @@ -146,22 +146,22 @@ public XmlEncodedRawTextWriter(Stream stream, XmlWriterSettings settings) : this { Debug.Assert(stream != null && settings != null); - this.stream = stream; - this.encoding = settings.Encoding; + this._stream = stream; + this._encoding = settings.Encoding; // the buffer is allocated will OVERFLOW in order to reduce checks when writing out constant size markup if (settings.Async) { - bufLen = ASYNCBUFSIZE; + _bufLen = ASYNCBUFSIZE; } - bufChars = new char[bufLen + OVERFLOW]; - bufBytes = new byte[bufChars.Length]; - bufBytesUsed = 0; + _bufChars = new char[_bufLen + OVERFLOW]; + _bufBytes = new byte[_bufChars.Length]; + _bufBytesUsed = 0; // Init escaping of characters not fitting into the target encoding - trackTextContent = true; - inTextContent = false; + _trackTextContent = true; + _inTextContent = false; _lastMarkPos = 0; _textContentMarks = new int[INIT_MARKS_COUNT]; _textContentMarks[0] = 1; @@ -169,29 +169,29 @@ public XmlEncodedRawTextWriter(Stream stream, XmlWriterSettings settings) : this _charEntityFallback = new CharEntityEncoderFallback(); // grab bom before possibly changing encoding settings - ReadOnlySpan bom = encoding.Preamble; + ReadOnlySpan bom = _encoding.Preamble; // the encoding instance this creates can differ from the one passed in - this.encoding = Encoding.GetEncoding( + this._encoding = Encoding.GetEncoding( settings.Encoding.CodePage, _charEntityFallback, settings.Encoding.DecoderFallback); - encoder = encoding.GetEncoder(); + _encoder = _encoding.GetEncoder(); if (!stream.CanSeek || stream.Position == 0) { if (bom.Length != 0) { - this.stream.Write(bom); + this._stream.Write(bom); } } // Write the xml declaration if (settings.AutoXmlDeclaration) { - WriteXmlDeclaration(standalone); - autoXmlDeclaration = true; + WriteXmlDeclaration(_standalone); + _autoXmlDeclaration = true; } } @@ -205,17 +205,17 @@ public override XmlWriterSettings Settings { XmlWriterSettings settings = new XmlWriterSettings(); - settings.Encoding = encoding; - settings.OmitXmlDeclaration = omitXmlDeclaration; - settings.NewLineHandling = newLineHandling; - settings.NewLineChars = newLineChars; - settings.CloseOutput = closeOutput; + settings.Encoding = _encoding; + settings.OmitXmlDeclaration = _omitXmlDeclaration; + settings.NewLineHandling = _newLineHandling; + settings.NewLineChars = _newLineChars; + settings.CloseOutput = _closeOutput; settings.ConformanceLevel = ConformanceLevel.Auto; - settings.CheckCharacters = checkCharacters; + settings.CheckCharacters = _checkCharacters; - settings.AutoXmlDeclaration = autoXmlDeclaration; - settings.Standalone = standalone; - settings.OutputMethod = outputMethod; + settings.AutoXmlDeclaration = _autoXmlDeclaration; + settings.Standalone = _standalone; + settings.OutputMethod = _outputMethod; settings.ReadOnly = true; return settings; @@ -226,9 +226,9 @@ public override XmlWriterSettings Settings internal override void WriteXmlDeclaration(XmlStandalone standalone) { // Output xml declaration only if user allows it and it was not already output - if (!omitXmlDeclaration && !autoXmlDeclaration) + if (!_omitXmlDeclaration && !_autoXmlDeclaration) { - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } RawText(" 0); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } RawText("'; + _bufChars[_bufPos++] = (char)'>'; } // Serialize the beginning of an element start tag: " 0); Debug.Assert(prefix != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - bufChars[bufPos++] = (char)'<'; + _bufChars[_bufPos++] = (char)'<'; if (prefix != null && prefix.Length != 0) { RawText(prefix); - bufChars[bufPos++] = (char)':'; + _bufChars[_bufPos++] = (char)':'; } RawText(localName); - attrEndPos = bufPos; + _attrEndPos = _bufPos; } // Serialize the end of an element start tag in preparation for content serialization: ">" internal override void StartElementContent() { - bufChars[bufPos++] = (char)'>'; + _bufChars[_bufPos++] = (char)'>'; // StartElementContent is always called; therefore, in order to allow shortcut syntax, we save the // position of the '>' character. If WriteEndElement is called and no other characters have been // output, then the '>' character can be overwritten with the shortcut syntax " />". - contentPos = bufPos; + _contentPos = _bufPos; } // Serialize an element end tag: "", if content was output. Otherwise, serialize @@ -341,29 +341,29 @@ internal override void WriteEndElement(string prefix, string localName, string n Debug.Assert(localName != null && localName.Length > 0); Debug.Assert(prefix != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - if (contentPos != bufPos) + if (_contentPos != _bufPos) { // Content has been output, so can't use shortcut syntax - bufChars[bufPos++] = (char)'<'; - bufChars[bufPos++] = (char)'/'; + _bufChars[_bufPos++] = (char)'<'; + _bufChars[_bufPos++] = (char)'/'; if (prefix != null && prefix.Length != 0) { RawText(prefix); - bufChars[bufPos++] = (char)':'; + _bufChars[_bufPos++] = (char)':'; } RawText(localName); - bufChars[bufPos++] = (char)'>'; + _bufChars[_bufPos++] = (char)'>'; } else { // Use shortcut syntax; overwrite the already output '>' character - bufPos--; - bufChars[bufPos++] = (char)' '; - bufChars[bufPos++] = (char)'/'; - bufChars[bufPos++] = (char)'>'; + _bufPos--; + _bufChars[_bufPos++] = (char)' '; + _bufChars[_bufPos++] = (char)'/'; + _bufChars[_bufPos++] = (char)'>'; } } @@ -373,18 +373,18 @@ internal override void WriteFullEndElement(string prefix, string localName, stri Debug.Assert(localName != null && localName.Length > 0); Debug.Assert(prefix != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - bufChars[bufPos++] = (char)'<'; - bufChars[bufPos++] = (char)'/'; + _bufChars[_bufPos++] = (char)'<'; + _bufChars[_bufPos++] = (char)'/'; if (prefix != null && prefix.Length != 0) { RawText(prefix); - bufChars[bufPos++] = (char)':'; + _bufChars[_bufPos++] = (char)':'; } RawText(localName); - bufChars[bufPos++] = (char)'>'; + _bufChars[_bufPos++] = (char)'>'; } // Serialize an attribute tag using double quotes around the attribute value: 'prefix:localName="' @@ -393,33 +393,33 @@ public override void WriteStartAttribute(string prefix, string localName, string Debug.Assert(localName != null && localName.Length > 0); Debug.Assert(prefix != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - if (attrEndPos == bufPos) + if (_attrEndPos == _bufPos) { - bufChars[bufPos++] = (char)' '; + _bufChars[_bufPos++] = (char)' '; } if (prefix != null && prefix.Length > 0) { RawText(prefix); - bufChars[bufPos++] = (char)':'; + _bufChars[_bufPos++] = (char)':'; } RawText(localName); - bufChars[bufPos++] = (char)'='; - bufChars[bufPos++] = (char)'"'; + _bufChars[_bufPos++] = (char)'='; + _bufChars[_bufPos++] = (char)'"'; - inAttributeValue = true; + _inAttributeValue = true; } // Serialize the end of an attribute value using double quotes: '"' public override void WriteEndAttribute() { - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - bufChars[bufPos++] = (char)'"'; - inAttributeValue = false; - attrEndPos = bufPos; + _bufChars[_bufPos++] = (char)'"'; + _inAttributeValue = false; + _attrEndPos = _bufPos; } internal override void WriteNamespaceDeclaration(string prefix, string namespaceName) @@ -443,7 +443,7 @@ internal override void WriteStartNamespaceDeclaration(string prefix) { Debug.Assert(prefix != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } if (prefix.Length == 0) { @@ -453,22 +453,22 @@ internal override void WriteStartNamespaceDeclaration(string prefix) { RawText(" xmlns:"); RawText(prefix); - bufChars[bufPos++] = (char)'='; - bufChars[bufPos++] = (char)'"'; + _bufChars[_bufPos++] = (char)'='; + _bufChars[_bufPos++] = (char)'"'; } - inAttributeValue = true; + _inAttributeValue = true; - if (trackTextContent && inTextContent != true) { ChangeTextContentMark(true); } + if (_trackTextContent && _inTextContent != true) { ChangeTextContentMark(true); } } internal override void WriteEndNamespaceDeclaration() { - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } - inAttributeValue = false; + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } + _inAttributeValue = false; - bufChars[bufPos++] = (char)'"'; - attrEndPos = bufPos; + _bufChars[_bufPos++] = (char)'"'; + _attrEndPos = _bufPos; } // Serialize a CData section. If the "]]>" pattern is found within @@ -477,36 +477,36 @@ public override void WriteCData(string text) { Debug.Assert(text != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - if (mergeCDataSections && bufPos == cdataPos) + if (_mergeCDataSections && _bufPos == _cdataPos) { // Merge adjacent cdata sections - overwrite the "]]>" characters - Debug.Assert(bufPos >= 4); - bufPos -= 3; + Debug.Assert(_bufPos >= 4); + _bufPos -= 3; } else { // Start a new cdata section - bufChars[bufPos++] = (char)'<'; - bufChars[bufPos++] = (char)'!'; - bufChars[bufPos++] = (char)'['; - bufChars[bufPos++] = (char)'C'; - bufChars[bufPos++] = (char)'D'; - bufChars[bufPos++] = (char)'A'; - bufChars[bufPos++] = (char)'T'; - bufChars[bufPos++] = (char)'A'; - bufChars[bufPos++] = (char)'['; + _bufChars[_bufPos++] = (char)'<'; + _bufChars[_bufPos++] = (char)'!'; + _bufChars[_bufPos++] = (char)'['; + _bufChars[_bufPos++] = (char)'C'; + _bufChars[_bufPos++] = (char)'D'; + _bufChars[_bufPos++] = (char)'A'; + _bufChars[_bufPos++] = (char)'T'; + _bufChars[_bufPos++] = (char)'A'; + _bufChars[_bufPos++] = (char)'['; } WriteCDataSection(text); - bufChars[bufPos++] = (char)']'; - bufChars[bufPos++] = (char)']'; - bufChars[bufPos++] = (char)'>'; + _bufChars[_bufPos++] = (char)']'; + _bufChars[_bufPos++] = (char)']'; + _bufChars[_bufPos++] = (char)'>'; - textPos = bufPos; - cdataPos = bufPos; + _textPos = _bufPos; + _cdataPos = _bufPos; } // Serialize a comment. @@ -514,18 +514,18 @@ public override void WriteComment(string text) { Debug.Assert(text != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - bufChars[bufPos++] = (char)'<'; - bufChars[bufPos++] = (char)'!'; - bufChars[bufPos++] = (char)'-'; - bufChars[bufPos++] = (char)'-'; + _bufChars[_bufPos++] = (char)'<'; + _bufChars[_bufPos++] = (char)'!'; + _bufChars[_bufPos++] = (char)'-'; + _bufChars[_bufPos++] = (char)'-'; WriteCommentOrPi(text, '-'); - bufChars[bufPos++] = (char)'-'; - bufChars[bufPos++] = (char)'-'; - bufChars[bufPos++] = (char)'>'; + _bufChars[_bufPos++] = (char)'-'; + _bufChars[_bufPos++] = (char)'-'; + _bufChars[_bufPos++] = (char)'>'; } // Serialize a processing instruction. @@ -534,20 +534,20 @@ public override void WriteProcessingInstruction(string name, string text) Debug.Assert(name != null && name.Length > 0); Debug.Assert(text != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - bufChars[bufPos++] = (char)'<'; - bufChars[bufPos++] = (char)'?'; + _bufChars[_bufPos++] = (char)'<'; + _bufChars[_bufPos++] = (char)'?'; RawText(name); if (text.Length > 0) { - bufChars[bufPos++] = (char)' '; + _bufChars[_bufPos++] = (char)' '; WriteCommentOrPi(text, '?'); } - bufChars[bufPos++] = (char)'?'; - bufChars[bufPos++] = (char)'>'; + _bufChars[_bufPos++] = (char)'?'; + _bufChars[_bufPos++] = (char)'>'; } // Serialize an entity reference. @@ -555,18 +555,18 @@ public override void WriteEntityRef(string name) { Debug.Assert(name != null && name.Length > 0); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - bufChars[bufPos++] = (char)'&'; + _bufChars[_bufPos++] = (char)'&'; RawText(name); - bufChars[bufPos++] = (char)';'; + _bufChars[_bufPos++] = (char)';'; - if (bufPos > bufLen) + if (_bufPos > _bufLen) { FlushBuffer(); } - textPos = bufPos; + _textPos = _bufPos; } // Serialize a character entity reference. @@ -574,26 +574,26 @@ public override void WriteCharEntity(char ch) { string strVal = ((int)ch).ToString("X", NumberFormatInfo.InvariantInfo); - if (checkCharacters && !xmlCharType.IsCharData(ch)) + if (_checkCharacters && !_xmlCharType.IsCharData(ch)) { // we just have a single char, not a surrogate, therefore we have to pass in '\0' for the second char throw XmlConvert.CreateInvalidCharException(ch, '\0'); } - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - bufChars[bufPos++] = (char)'&'; - bufChars[bufPos++] = (char)'#'; - bufChars[bufPos++] = (char)'x'; + _bufChars[_bufPos++] = (char)'&'; + _bufChars[_bufPos++] = (char)'#'; + _bufChars[_bufPos++] = (char)'x'; RawText(strVal); - bufChars[bufPos++] = (char)';'; + _bufChars[_bufPos++] = (char)';'; - if (bufPos > bufLen) + if (_bufPos > _bufLen) { FlushBuffer(); } - textPos = bufPos; + _textPos = _bufPos; } // Serialize a whitespace node. @@ -602,12 +602,12 @@ public override unsafe void WriteWhitespace(string ws) { Debug.Assert(ws != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } fixed (char* pSrc = ws) { char* pSrcEnd = pSrc + ws.Length; - if (inAttributeValue) + if (_inAttributeValue) { WriteAttributeTextBlock(pSrc, pSrcEnd); } @@ -624,12 +624,12 @@ public override unsafe void WriteString(string text) { Debug.Assert(text != null); - if (trackTextContent && inTextContent != true) { ChangeTextContentMark(true); } + if (_trackTextContent && _inTextContent != true) { ChangeTextContentMark(true); } fixed (char* pSrc = text) { char* pSrcEnd = pSrc + text.Length; - if (inAttributeValue) + if (_inAttributeValue) { WriteAttributeTextBlock(pSrc, pSrcEnd); } @@ -643,15 +643,15 @@ public override unsafe void WriteString(string text) // Serialize surrogate character entity. public override void WriteSurrogateCharEntity(char lowChar, char highChar) { - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } int surrogateChar = XmlCharType.CombineSurrogateChar(lowChar, highChar); - bufChars[bufPos++] = (char)'&'; - bufChars[bufPos++] = (char)'#'; - bufChars[bufPos++] = (char)'x'; + _bufChars[_bufPos++] = (char)'&'; + _bufChars[_bufPos++] = (char)'#'; + _bufChars[_bufPos++] = (char)'x'; RawText(surrogateChar.ToString("X", NumberFormatInfo.InvariantInfo)); - bufChars[bufPos++] = (char)';'; - textPos = bufPos; + _bufChars[_bufPos++] = (char)';'; + _textPos = _bufPos; } // Serialize either attribute or element text using XML rules. @@ -663,11 +663,11 @@ public override unsafe void WriteChars(char[] buffer, int index, int count) Debug.Assert(index >= 0); Debug.Assert(count >= 0 && index + count <= buffer.Length); - if (trackTextContent && inTextContent != true) { ChangeTextContentMark(true); } + if (_trackTextContent && _inTextContent != true) { ChangeTextContentMark(true); } fixed (char* pSrcBegin = &buffer[index]) { - if (inAttributeValue) + if (_inAttributeValue) { WriteAttributeTextBlock(pSrcBegin, pSrcBegin + count); } @@ -687,14 +687,14 @@ public override unsafe void WriteRaw(char[] buffer, int index, int count) Debug.Assert(index >= 0); Debug.Assert(count >= 0 && index + count <= buffer.Length); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } fixed (char* pSrcBegin = &buffer[index]) { WriteRawWithCharChecking(pSrcBegin, pSrcBegin + count); } - textPos = bufPos; + _textPos = _bufPos; } // Serialize raw data. @@ -703,14 +703,14 @@ public override unsafe void WriteRaw(string data) { Debug.Assert(data != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } fixed (char* pSrcBegin = data) { WriteRawWithCharChecking(pSrcBegin, pSrcBegin + data.Length); } - textPos = bufPos; + _textPos = _bufPos; } // Flush all bytes in the buffer to output and close the output stream or writer. @@ -724,47 +724,47 @@ public override void Close() finally { // Future calls to Close or Flush shouldn't write to Stream or Writer - writeToNull = true; + _writeToNull = true; - if (stream != null) + if (_stream != null) { try { - stream.Flush(); + _stream.Flush(); } finally { try { - if (closeOutput) + if (_closeOutput) { - stream.Dispose(); + _stream.Dispose(); } } finally { - stream = null; + _stream = null; } } } - else if (writer != null) + else if (_writer != null) { try { - writer.Flush(); + _writer.Flush(); } finally { try { - if (closeOutput) + if (_closeOutput) { - writer.Dispose(); + _writer.Dispose(); } } finally { - writer = null; + _writer = null; } } } @@ -776,13 +776,13 @@ public override void Flush() { FlushBuffer(); FlushEncoder(); - if (stream != null) + if (_stream != null) { - stream.Flush(); + _stream.Flush(); } - else if (writer != null) + else if (_writer != null) { - writer.Flush(); + _writer.Flush(); } } @@ -795,13 +795,13 @@ protected virtual void FlushBuffer() try { // Output all characters (except for previous characters stored at beginning of buffer) - if (!writeToNull) + if (!_writeToNull) { - Debug.Assert(stream != null || writer != null); + Debug.Assert(_stream != null || _writer != null); - if (stream != null) + if (_stream != null) { - if (trackTextContent) + if (_trackTextContent) { _charEntityFallback.Reset(_textContentMarks, _lastMarkPos); // reset text content tracking @@ -819,32 +819,35 @@ protected virtual void FlushBuffer() } Debug.Assert(_textContentMarks[0] == 1); } - EncodeChars(1, bufPos, true); + EncodeChars(1, _bufPos, true); } else { - // Write text to TextWriter - writer.Write(bufChars, 1, bufPos - 1); + if (_bufPos - 1 > 0) + { + // Write text to TextWriter + _writer.Write(_bufChars, 1, _bufPos - 1); + } } } } catch { // Future calls to flush (i.e. when Close() is called) don't attempt to write to stream - writeToNull = true; + _writeToNull = true; throw; } finally { // Move last buffer character to the beginning of the buffer (so that previous character can always be determined) - bufChars[0] = bufChars[bufPos - 1]; + _bufChars[0] = _bufChars[_bufPos - 1]; // Reset buffer position - textPos = (textPos == bufPos) ? 1 : 0; - attrEndPos = (attrEndPos == bufPos) ? 1 : 0; - contentPos = 0; // Needs to be zero, since overwriting '>' character is no longer possible - cdataPos = 0; // Needs to be zero, since overwriting ']]>' characters is no longer possible - bufPos = 1; // Buffer position starts at 1, because we need to be able to safely step back -1 in case we need to + _textPos = (_textPos == _bufPos) ? 1 : 0; + _attrEndPos = (_attrEndPos == _bufPos) ? 1 : 0; + _contentPos = 0; // Needs to be zero, since overwriting '>' character is no longer possible + _cdataPos = 0; // Needs to be zero, since overwriting ']]>' characters is no longer possible + _bufPos = 1; // Buffer position starts at 1, because we need to be able to safely step back -1 in case we need to // close an empty element or in CDATA section detection of double ]; bufChars[0] will always be 0 } } @@ -861,35 +864,35 @@ private void EncodeChars(int startOffset, int endOffset, bool writeAllToStream) { _charEntityFallback.StartOffset = startOffset; } - encoder.Convert(bufChars, startOffset, endOffset - startOffset, bufBytes, bufBytesUsed, bufBytes.Length - bufBytesUsed, false, out chEnc, out bEnc, out completed); + _encoder.Convert(_bufChars, startOffset, endOffset - startOffset, _bufBytes, _bufBytesUsed, _bufBytes.Length - _bufBytesUsed, false, out chEnc, out bEnc, out completed); startOffset += chEnc; - bufBytesUsed += bEnc; - if (bufBytesUsed >= (bufBytes.Length - 16)) + _bufBytesUsed += bEnc; + if (_bufBytesUsed >= (_bufBytes.Length - 16)) { - stream.Write(bufBytes, 0, bufBytesUsed); - bufBytesUsed = 0; + _stream.Write(_bufBytes, 0, _bufBytesUsed); + _bufBytesUsed = 0; } } - if (writeAllToStream && bufBytesUsed > 0) + if (writeAllToStream && _bufBytesUsed > 0) { - stream.Write(bufBytes, 0, bufBytesUsed); - bufBytesUsed = 0; + _stream.Write(_bufBytes, 0, _bufBytesUsed); + _bufBytesUsed = 0; } } private void FlushEncoder() { - Debug.Assert(bufPos == 1); - if (stream != null) + Debug.Assert(_bufPos == 1); + if (_stream != null) { int chEnc; int bEnc; bool completed; // decode no chars, just flush - encoder.Convert(bufChars, 1, 0, bufBytes, 0, bufBytes.Length, true, out chEnc, out bEnc, out completed); + _encoder.Convert(_bufChars, 1, 0, _bufBytes, 0, _bufBytes.Length, true, out chEnc, out bEnc, out completed); if (bEnc != 0) { - stream.Write(bufBytes, 0, bEnc); + _stream.Write(_bufBytes, 0, bEnc); } } } @@ -898,20 +901,20 @@ private void FlushEncoder() // are entitized. protected unsafe void WriteAttributeTextBlock(char* pSrc, char* pSrcEnd) { - fixed (char* pDstBegin = bufChars) + fixed (char* pDstBegin = _bufChars) { - char* pDst = pDstBegin + bufPos; + char* pDst = pDstBegin + _bufPos; int ch = 0; while (true) { char* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } - while (pDst < pDstEnd && xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) + while (pDst < pDstEnd && _xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) { *pDst = (char)ch; pDst++; @@ -928,7 +931,7 @@ protected unsafe void WriteAttributeTextBlock(char* pSrc, char* pSrcEnd) // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; @@ -954,7 +957,7 @@ protected unsafe void WriteAttributeTextBlock(char* pSrc, char* pSrcEnd) pDst++; break; case (char)0x9: - if (newLineHandling == NewLineHandling.None) + if (_newLineHandling == NewLineHandling.None) { *pDst = (char)ch; pDst++; @@ -966,7 +969,7 @@ protected unsafe void WriteAttributeTextBlock(char* pSrc, char* pSrcEnd) } break; case (char)0xD: - if (newLineHandling == NewLineHandling.None) + if (_newLineHandling == NewLineHandling.None) { *pDst = (char)ch; pDst++; @@ -978,7 +981,7 @@ protected unsafe void WriteAttributeTextBlock(char* pSrc, char* pSrcEnd) } break; case (char)0xA: - if (newLineHandling == NewLineHandling.None) + if (_newLineHandling == NewLineHandling.None) { *pDst = (char)ch; pDst++; @@ -1013,7 +1016,7 @@ protected unsafe void WriteAttributeTextBlock(char* pSrc, char* pSrcEnd) } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } } @@ -1021,20 +1024,20 @@ protected unsafe void WriteAttributeTextBlock(char* pSrc, char* pSrcEnd) // are entitized. protected unsafe void WriteElementTextBlock(char* pSrc, char* pSrcEnd) { - fixed (char* pDstBegin = bufChars) + fixed (char* pDstBegin = _bufChars) { - char* pDst = pDstBegin + bufPos; + char* pDst = pDstBegin + _bufPos; int ch = 0; while (true) { char* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } - while (pDst < pDstEnd && xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) + while (pDst < pDstEnd && _xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) { *pDst = (char)ch; pDst++; @@ -1051,7 +1054,7 @@ protected unsafe void WriteElementTextBlock(char* pSrc, char* pSrcEnd) // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; @@ -1076,7 +1079,7 @@ protected unsafe void WriteElementTextBlock(char* pSrc, char* pSrcEnd) pDst++; break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { pDst = WriteNewLine(pDst); } @@ -1087,7 +1090,7 @@ protected unsafe void WriteElementTextBlock(char* pSrc, char* pSrcEnd) } break; case (char)0xD: - switch (newLineHandling) + switch (_newLineHandling) { case NewLineHandling.Replace: // Replace "\r\n", or "\r" with NewLineChars @@ -1133,9 +1136,9 @@ protected unsafe void WriteElementTextBlock(char* pSrc, char* pSrcEnd) } pSrc++; } - bufPos = (int)(pDst - pDstBegin); - textPos = bufPos; - contentPos = 0; + _bufPos = (int)(pDst - pDstBegin); + _textPos = _bufPos; + _contentPos = 0; } } @@ -1151,18 +1154,18 @@ protected unsafe void RawText(string s) protected unsafe void RawText(char* pSrcBegin, char* pSrcEnd) { - fixed (char* pDstBegin = bufChars) + fixed (char* pDstBegin = _bufChars) { - char* pDst = pDstBegin + bufPos; + char* pDst = pDstBegin + _bufPos; char* pSrc = pSrcBegin; int ch = 0; while (true) { char* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } while (pDst < pDstEnd && ((ch = *pSrc) < XmlCharType.SurHighStart)) @@ -1182,7 +1185,7 @@ protected unsafe void RawText(char* pSrcBegin, char* pSrcEnd) // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; @@ -1209,27 +1212,27 @@ protected unsafe void RawText(char* pSrcBegin, char* pSrcEnd) } } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } } protected unsafe void WriteRawWithCharChecking(char* pSrcBegin, char* pSrcEnd) { - fixed (char* pDstBegin = bufChars) + fixed (char* pDstBegin = _bufChars) { char* pSrc = pSrcBegin; - char* pDst = pDstBegin + bufPos; + char* pDst = pDstBegin + _bufPos; int ch = 0; while (true) { char* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } - while (pDst < pDstEnd && xmlCharType.IsTextChar((char)(ch = *pSrc))) + while (pDst < pDstEnd && _xmlCharType.IsTextChar((char)(ch = *pSrc))) { *pDst = (char)ch; pDst++; @@ -1247,7 +1250,7 @@ protected unsafe void WriteRawWithCharChecking(char* pSrcBegin, char* pSrcEnd) // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; @@ -1264,7 +1267,7 @@ protected unsafe void WriteRawWithCharChecking(char* pSrcBegin, char* pSrcEnd) pDst++; break; case (char)0xD: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { // Normalize "\r\n", or "\r" to NewLineChars if (pSrc + 1 < pSrcEnd && pSrc[1] == '\n') @@ -1281,7 +1284,7 @@ protected unsafe void WriteRawWithCharChecking(char* pSrcBegin, char* pSrcEnd) } break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { pDst = WriteNewLine(pDst); } @@ -1315,7 +1318,7 @@ protected unsafe void WriteRawWithCharChecking(char* pSrcBegin, char* pSrcEnd) } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } } @@ -1323,7 +1326,7 @@ protected unsafe void WriteCommentOrPi(string text, int stopChar) { if (text.Length == 0) { - if (bufPos >= bufLen) + if (_bufPos >= _bufLen) { FlushBuffer(); } @@ -1332,24 +1335,24 @@ protected unsafe void WriteCommentOrPi(string text, int stopChar) // write text fixed (char* pSrcBegin = text) - fixed (char* pDstBegin = bufChars) + fixed (char* pDstBegin = _bufChars) { char* pSrc = pSrcBegin; char* pSrcEnd = pSrcBegin + text.Length; - char* pDst = pDstBegin + bufPos; + char* pDst = pDstBegin + _bufPos; int ch = 0; while (true) { char* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } - while (pDst < pDstEnd && (xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch != stopChar)) + while (pDst < pDstEnd && (_xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch != stopChar)) { *pDst = (char)ch; pDst++; @@ -1367,7 +1370,7 @@ protected unsafe void WriteCommentOrPi(string text, int stopChar) // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; @@ -1407,7 +1410,7 @@ protected unsafe void WriteCommentOrPi(string text, int stopChar) pDst++; break; case (char)0xD: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { // Normalize "\r\n", or "\r" to NewLineChars if (pSrc + 1 < pSrcEnd && pSrc[1] == '\n') @@ -1424,7 +1427,7 @@ protected unsafe void WriteCommentOrPi(string text, int stopChar) } break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { pDst = WriteNewLine(pDst); } @@ -1464,7 +1467,7 @@ protected unsafe void WriteCommentOrPi(string text, int stopChar) } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } } @@ -1472,7 +1475,7 @@ protected unsafe void WriteCDataSection(string text) { if (text.Length == 0) { - if (bufPos >= bufLen) + if (_bufPos >= _bufLen) { FlushBuffer(); } @@ -1483,24 +1486,24 @@ protected unsafe void WriteCDataSection(string text) fixed (char* pSrcBegin = text) - fixed (char* pDstBegin = bufChars) + fixed (char* pDstBegin = _bufChars) { char* pSrc = pSrcBegin; char* pSrcEnd = pSrcBegin + text.Length; - char* pDst = pDstBegin + bufPos; + char* pDst = pDstBegin + _bufPos; int ch = 0; while (true) { char* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } - while (pDst < pDstEnd && (xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch != ']')) + while (pDst < pDstEnd && (_xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch != ']')) { *pDst = (char)ch; pDst++; @@ -1518,7 +1521,7 @@ protected unsafe void WriteCDataSection(string text) // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; @@ -1528,7 +1531,7 @@ protected unsafe void WriteCDataSection(string text) switch (ch) { case '>': - if (hadDoubleBracket && pDst[-1] == (char)']') + if (_hadDoubleBracket && pDst[-1] == (char)']') { // pDst[-1] will always correct - there is a padding character at bufChars[0] // The characters "]]>" were found within the CData text pDst = RawEndCData(pDst); @@ -1540,17 +1543,17 @@ protected unsafe void WriteCDataSection(string text) case ']': if (pDst[-1] == (char)']') { // pDst[-1] will always correct - there is a padding character at bufChars[0] - hadDoubleBracket = true; + _hadDoubleBracket = true; } else { - hadDoubleBracket = false; + _hadDoubleBracket = false; } *pDst = (char)']'; pDst++; break; case (char)0xD: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { // Normalize "\r\n", or "\r" to NewLineChars if (pSrc + 1 < pSrcEnd && pSrc[1] == '\n') @@ -1567,7 +1570,7 @@ protected unsafe void WriteCDataSection(string text) } break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { pDst = WriteNewLine(pDst); } @@ -1609,7 +1612,7 @@ protected unsafe void WriteCDataSection(string text) } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } } @@ -1642,10 +1645,10 @@ protected unsafe void WriteCDataSection(string text) private unsafe char* InvalidXmlChar(int ch, char* pDst, bool entitize) { - Debug.Assert(!xmlCharType.IsWhiteSpace((char)ch)); - Debug.Assert(!xmlCharType.IsAttributeValueChar((char)ch)); + Debug.Assert(!_xmlCharType.IsWhiteSpace((char)ch)); + Debug.Assert(!_xmlCharType.IsAttributeValueChar((char)ch)); - if (checkCharacters) + if (_checkCharacters) { // This method will never be called on surrogates, so it is ok to pass in '\0' to the CreateInvalidCharException throw XmlConvert.CreateInvalidCharException((char)ch, '\0'); @@ -1692,14 +1695,14 @@ internal unsafe void EncodeChar(ref char* pSrc, char* pSrcEnd, ref char* pDst) protected void ChangeTextContentMark(bool value) { - Debug.Assert(inTextContent != value); - Debug.Assert(inTextContent || ((_lastMarkPos & 1) == 0)); - inTextContent = value; + Debug.Assert(_inTextContent != value); + Debug.Assert(_inTextContent || ((_lastMarkPos & 1) == 0)); + _inTextContent = value; if (_lastMarkPos + 1 == _textContentMarks.Length) { GrowTextContentMarks(); } - _textContentMarks[++_lastMarkPos] = bufPos; + _textContentMarks[++_lastMarkPos] = _bufPos; } private void GrowTextContentMarks() @@ -1712,12 +1715,12 @@ private void GrowTextContentMarks() // Write NewLineChars to the specified buffer position and return an updated position. protected unsafe char* WriteNewLine(char* pDst) { - fixed (char* pDstBegin = bufChars) + fixed (char* pDstBegin = _bufChars) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); // Let RawText do the real work - RawText(newLineChars); - return pDstBegin + bufPos; + RawText(_newLineChars); + return pDstBegin + _bufPos; } } @@ -1855,7 +1858,7 @@ protected unsafe void ValidateContentChars(string chars, string propertyName, bo { if (allowOnlyWhitespace) { - if (!xmlCharType.IsOnlyWhitespace(chars)) + if (!_xmlCharType.IsOnlyWhitespace(chars)) { throw new ArgumentException(SR.Format(SR.Xml_IndentCharsNotWhitespace, propertyName)); } @@ -1865,7 +1868,7 @@ protected unsafe void ValidateContentChars(string chars, string propertyName, bo string error = null; for (int i = 0; i < chars.Length; i++) { - if (!xmlCharType.IsTextChar(chars[i])) + if (!_xmlCharType.IsTextChar(chars[i])) { switch (chars[i]) { @@ -1915,14 +1918,14 @@ internal partial class XmlEncodedRawTextWriterIndent : XmlEncodedRawTextWriter // // Fields // - protected int indentLevel; - protected bool newLineOnAttributes; - protected string indentChars; + protected int _indentLevel; + protected bool _newLineOnAttributes; + protected string _indentChars; - protected bool mixedContent; + protected bool _mixedContent; private BitStack _mixedContentStack; - protected ConformanceLevel conformanceLevel = ConformanceLevel.Auto; + protected ConformanceLevel _conformanceLevel = ConformanceLevel.Auto; // // Constructors @@ -1948,8 +1951,8 @@ public override XmlWriterSettings Settings settings.ReadOnly = false; settings.Indent = true; - settings.IndentChars = indentChars; - settings.NewLineOnAttributes = newLineOnAttributes; + settings.IndentChars = _indentChars; + settings.NewLineOnAttributes = _newLineOnAttributes; settings.ReadOnly = true; return settings; @@ -1959,7 +1962,7 @@ public override XmlWriterSettings Settings public override void WriteDocType(string name, string pubid, string sysid, string subset) { // Add indentation - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { WriteIndent(); } @@ -1971,12 +1974,12 @@ public override void WriteStartElement(string prefix, string localName, string n Debug.Assert(localName != null && localName.Length != 0 && prefix != null && ns != null); // Add indentation - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { WriteIndent(); } - indentLevel++; - _mixedContentStack.PushBit(mixedContent); + _indentLevel++; + _mixedContentStack.PushBit(_mixedContent); base.WriteStartElement(prefix, localName, ns); } @@ -1984,16 +1987,16 @@ public override void WriteStartElement(string prefix, string localName, string n internal override void StartElementContent() { // If this is the root element and we're writing a document - // do not inherit the mixedContent flag into the root element. + // do not inherit the _mixedContent flag into the root element. // This is to allow for whitespace nodes on root level // without disabling indentation for the whole document. - if (indentLevel == 1 && conformanceLevel == ConformanceLevel.Document) + if (_indentLevel == 1 && _conformanceLevel == ConformanceLevel.Document) { - mixedContent = false; + _mixedContent = false; } else { - mixedContent = _mixedContentStack.PeekBit(); + _mixedContent = _mixedContentStack.PeekBit(); } base.StartElementContent(); } @@ -2001,22 +2004,22 @@ internal override void StartElementContent() internal override void OnRootElement(ConformanceLevel currentConformanceLevel) { // Just remember the current conformance level - conformanceLevel = currentConformanceLevel; + _conformanceLevel = currentConformanceLevel; } internal override void WriteEndElement(string prefix, string localName, string ns) { // Add indentation - indentLevel--; - if (!mixedContent && base.contentPos != base.bufPos) + _indentLevel--; + if (!_mixedContent && base._contentPos != base._bufPos) { // There was content, so try to indent - if (base.textPos != base.bufPos) + if (base._textPos != base._bufPos) { WriteIndent(); } } - mixedContent = _mixedContentStack.PopBit(); + _mixedContent = _mixedContentStack.PopBit(); base.WriteEndElement(prefix, localName, ns); } @@ -2024,16 +2027,16 @@ internal override void WriteEndElement(string prefix, string localName, string n internal override void WriteFullEndElement(string prefix, string localName, string ns) { // Add indentation - indentLevel--; - if (!mixedContent && base.contentPos != base.bufPos) + _indentLevel--; + if (!_mixedContent && base._contentPos != base._bufPos) { // There was content, so try to indent - if (base.textPos != base.bufPos) + if (base._textPos != base._bufPos) { WriteIndent(); } } - mixedContent = _mixedContentStack.PopBit(); + _mixedContent = _mixedContentStack.PopBit(); base.WriteFullEndElement(prefix, localName, ns); } @@ -2042,7 +2045,7 @@ internal override void WriteFullEndElement(string prefix, string localName, stri public override void WriteStartAttribute(string prefix, string localName, string ns) { // Add indentation - if (newLineOnAttributes) + if (_newLineOnAttributes) { WriteIndent(); } @@ -2052,13 +2055,13 @@ public override void WriteStartAttribute(string prefix, string localName, string public override void WriteCData(string text) { - mixedContent = true; + _mixedContent = true; base.WriteCData(text); } public override void WriteComment(string text) { - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { WriteIndent(); } @@ -2068,7 +2071,7 @@ public override void WriteComment(string text) public override void WriteProcessingInstruction(string target, string text) { - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { WriteIndent(); } @@ -2078,55 +2081,55 @@ public override void WriteProcessingInstruction(string target, string text) public override void WriteEntityRef(string name) { - mixedContent = true; + _mixedContent = true; base.WriteEntityRef(name); } public override void WriteCharEntity(char ch) { - mixedContent = true; + _mixedContent = true; base.WriteCharEntity(ch); } public override void WriteSurrogateCharEntity(char lowChar, char highChar) { - mixedContent = true; + _mixedContent = true; base.WriteSurrogateCharEntity(lowChar, highChar); } public override void WriteWhitespace(string ws) { - mixedContent = true; + _mixedContent = true; base.WriteWhitespace(ws); } public override void WriteString(string text) { - mixedContent = true; + _mixedContent = true; base.WriteString(text); } public override void WriteChars(char[] buffer, int index, int count) { - mixedContent = true; + _mixedContent = true; base.WriteChars(buffer, index, count); } public override void WriteRaw(char[] buffer, int index, int count) { - mixedContent = true; + _mixedContent = true; base.WriteRaw(buffer, index, count); } public override void WriteRaw(string data) { - mixedContent = true; + _mixedContent = true; base.WriteRaw(data); } public override void WriteBase64(byte[] buffer, int index, int count) { - mixedContent = true; + _mixedContent = true; base.WriteBase64(buffer, index, count); } @@ -2135,25 +2138,25 @@ public override void WriteBase64(byte[] buffer, int index, int count) // private void Init(XmlWriterSettings settings) { - indentLevel = 0; - indentChars = settings.IndentChars; - newLineOnAttributes = settings.NewLineOnAttributes; + _indentLevel = 0; + _indentChars = settings.IndentChars; + _newLineOnAttributes = settings.NewLineOnAttributes; _mixedContentStack = new BitStack(); // check indent characters that they are valid XML characters - if (base.checkCharacters) + if (base._checkCharacters) { - if (newLineOnAttributes) + if (_newLineOnAttributes) { - base.ValidateContentChars(indentChars, "IndentChars", true); - base.ValidateContentChars(newLineChars, "NewLineChars", true); + base.ValidateContentChars(_indentChars, "IndentChars", true); + base.ValidateContentChars(_newLineChars, "NewLineChars", true); } else { - base.ValidateContentChars(indentChars, "IndentChars", false); - if (base.newLineHandling != NewLineHandling.Replace) + base.ValidateContentChars(_indentChars, "IndentChars", false); + if (base._newLineHandling != NewLineHandling.Replace) { - base.ValidateContentChars(newLineChars, "NewLineChars", false); + base.ValidateContentChars(_newLineChars, "NewLineChars", false); } } } @@ -2162,10 +2165,10 @@ private void Init(XmlWriterSettings settings) // Add indentation to output. Write newline and then repeat IndentChars for each indent level. private void WriteIndent() { - RawText(base.newLineChars); - for (int i = indentLevel; i > 0; i--) + RawText(base._newLineChars); + for (int i = _indentLevel; i > 0; i--) { - RawText(indentChars); + RawText(_indentChars); } } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriterAsync.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriterAsync.cs index 3dd97591e12f98..cbdb13361dfe5e 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriterAsync.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriterAsync.cs @@ -35,19 +35,19 @@ internal override async Task WriteXmlDeclarationAsync(XmlStandalone standalone) { CheckAsyncCall(); // Output xml declaration only if user allows it and it was not already output - if (!omitXmlDeclaration && !autoXmlDeclaration) + if (!_omitXmlDeclaration && !_autoXmlDeclaration) { - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } await RawTextAsync(" 0); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } await RawTextAsync("'; + _bufChars[_bufPos++] = (char)'>'; } // Serialize the beginning of an element start tag: " 0); Debug.Assert(prefix != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } Task task; - bufChars[bufPos++] = (char)'<'; + _bufChars[_bufPos++] = (char)'<'; if (prefix != null && prefix.Length != 0) { task = RawTextAsync(prefix, ":", localName); @@ -139,7 +195,7 @@ public override Task WriteStartElementAsync(string prefix, string localName, str private void WriteStartElementAsync_SetAttEndPos() { - attrEndPos = bufPos; + _attrEndPos = _bufPos; } // Serialize an element end tag: "", if content was output. Otherwise, serialize @@ -150,13 +206,13 @@ internal override Task WriteEndElementAsync(string prefix, string localName, str Debug.Assert(localName != null && localName.Length > 0); Debug.Assert(prefix != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - if (contentPos != bufPos) + if (_contentPos != _bufPos) { // Content has been output, so can't use shortcut syntax - bufChars[bufPos++] = (char)'<'; - bufChars[bufPos++] = (char)'/'; + _bufChars[_bufPos++] = (char)'<'; + _bufChars[_bufPos++] = (char)'/'; if (prefix != null && prefix.Length != 0) { @@ -170,10 +226,10 @@ internal override Task WriteEndElementAsync(string prefix, string localName, str else { // Use shortcut syntax; overwrite the already output '>' character - bufPos--; - bufChars[bufPos++] = (char)' '; - bufChars[bufPos++] = (char)'/'; - bufChars[bufPos++] = (char)'>'; + _bufPos--; + _bufChars[_bufPos++] = (char)' '; + _bufChars[_bufPos++] = (char)'/'; + _bufChars[_bufPos++] = (char)'>'; } return Task.CompletedTask; } @@ -185,10 +241,10 @@ internal override Task WriteFullEndElementAsync(string prefix, string localName, Debug.Assert(localName != null && localName.Length > 0); Debug.Assert(prefix != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - bufChars[bufPos++] = (char)'<'; - bufChars[bufPos++] = (char)'/'; + _bufChars[_bufPos++] = (char)'<'; + _bufChars[_bufPos++] = (char)'/'; if (prefix != null && prefix.Length != 0) { @@ -207,11 +263,11 @@ protected internal override Task WriteStartAttributeAsync(string prefix, string Debug.Assert(localName != null && localName.Length > 0); Debug.Assert(prefix != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - if (attrEndPos == bufPos) + if (_attrEndPos == _bufPos) { - bufChars[bufPos++] = (char)' '; + _bufChars[_bufPos++] = (char)' '; } Task task; if (prefix != null && prefix.Length > 0) @@ -227,9 +283,9 @@ protected internal override Task WriteStartAttributeAsync(string prefix, string private void WriteStartAttribute_SetInAttribute() { - bufChars[bufPos++] = (char)'='; - bufChars[bufPos++] = (char)'"'; - inAttributeValue = true; + _bufChars[_bufPos++] = (char)'='; + _bufChars[_bufPos++] = (char)'"'; + _inAttributeValue = true; } // Serialize the end of an attribute value using double quotes: '"' @@ -237,11 +293,11 @@ protected internal override Task WriteEndAttributeAsync() { CheckAsyncCall(); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - bufChars[bufPos++] = (char)'"'; - inAttributeValue = false; - attrEndPos = bufPos; + _bufChars[_bufPos++] = (char)'"'; + _inAttributeValue = false; + _attrEndPos = _bufPos; return Task.CompletedTask; } @@ -261,7 +317,7 @@ internal override async Task WriteStartNamespaceDeclarationAsync(string prefix) CheckAsyncCall(); Debug.Assert(prefix != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } if (prefix.Length == 0) { @@ -271,25 +327,25 @@ internal override async Task WriteStartNamespaceDeclarationAsync(string prefix) { await RawTextAsync(" xmlns:").ConfigureAwait(false); await RawTextAsync(prefix).ConfigureAwait(false); - bufChars[bufPos++] = (char)'='; - bufChars[bufPos++] = (char)'"'; + _bufChars[_bufPos++] = (char)'='; + _bufChars[_bufPos++] = (char)'"'; } - inAttributeValue = true; + _inAttributeValue = true; - if (trackTextContent && inTextContent != true) { ChangeTextContentMark(true); } + if (_trackTextContent && _inTextContent != true) { ChangeTextContentMark(true); } } internal override Task WriteEndNamespaceDeclarationAsync() { CheckAsyncCall(); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - inAttributeValue = false; + _inAttributeValue = false; - bufChars[bufPos++] = (char)'"'; - attrEndPos = bufPos; + _bufChars[_bufPos++] = (char)'"'; + _attrEndPos = _bufPos; return Task.CompletedTask; } @@ -301,36 +357,36 @@ public override async Task WriteCDataAsync(string text) CheckAsyncCall(); Debug.Assert(text != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - if (mergeCDataSections && bufPos == cdataPos) + if (_mergeCDataSections && _bufPos == _cdataPos) { // Merge adjacent cdata sections - overwrite the "]]>" characters - Debug.Assert(bufPos >= 4); - bufPos -= 3; + Debug.Assert(_bufPos >= 4); + _bufPos -= 3; } else { // Start a new cdata section - bufChars[bufPos++] = (char)'<'; - bufChars[bufPos++] = (char)'!'; - bufChars[bufPos++] = (char)'['; - bufChars[bufPos++] = (char)'C'; - bufChars[bufPos++] = (char)'D'; - bufChars[bufPos++] = (char)'A'; - bufChars[bufPos++] = (char)'T'; - bufChars[bufPos++] = (char)'A'; - bufChars[bufPos++] = (char)'['; + _bufChars[_bufPos++] = (char)'<'; + _bufChars[_bufPos++] = (char)'!'; + _bufChars[_bufPos++] = (char)'['; + _bufChars[_bufPos++] = (char)'C'; + _bufChars[_bufPos++] = (char)'D'; + _bufChars[_bufPos++] = (char)'A'; + _bufChars[_bufPos++] = (char)'T'; + _bufChars[_bufPos++] = (char)'A'; + _bufChars[_bufPos++] = (char)'['; } await WriteCDataSectionAsync(text).ConfigureAwait(false); - bufChars[bufPos++] = (char)']'; - bufChars[bufPos++] = (char)']'; - bufChars[bufPos++] = (char)'>'; + _bufChars[_bufPos++] = (char)']'; + _bufChars[_bufPos++] = (char)']'; + _bufChars[_bufPos++] = (char)'>'; - textPos = bufPos; - cdataPos = bufPos; + _textPos = _bufPos; + _cdataPos = _bufPos; } // Serialize a comment. @@ -339,18 +395,18 @@ public override async Task WriteCommentAsync(string text) CheckAsyncCall(); Debug.Assert(text != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - bufChars[bufPos++] = (char)'<'; - bufChars[bufPos++] = (char)'!'; - bufChars[bufPos++] = (char)'-'; - bufChars[bufPos++] = (char)'-'; + _bufChars[_bufPos++] = (char)'<'; + _bufChars[_bufPos++] = (char)'!'; + _bufChars[_bufPos++] = (char)'-'; + _bufChars[_bufPos++] = (char)'-'; await WriteCommentOrPiAsync(text, '-').ConfigureAwait(false); - bufChars[bufPos++] = (char)'-'; - bufChars[bufPos++] = (char)'-'; - bufChars[bufPos++] = (char)'>'; + _bufChars[_bufPos++] = (char)'-'; + _bufChars[_bufPos++] = (char)'-'; + _bufChars[_bufPos++] = (char)'>'; } // Serialize a processing instruction. @@ -360,20 +416,20 @@ public override async Task WriteProcessingInstructionAsync(string name, string t Debug.Assert(name != null && name.Length > 0); Debug.Assert(text != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - bufChars[bufPos++] = (char)'<'; - bufChars[bufPos++] = (char)'?'; + _bufChars[_bufPos++] = (char)'<'; + _bufChars[_bufPos++] = (char)'?'; await RawTextAsync(name).ConfigureAwait(false); if (text.Length > 0) { - bufChars[bufPos++] = (char)' '; + _bufChars[_bufPos++] = (char)' '; await WriteCommentOrPiAsync(text, '?').ConfigureAwait(false); } - bufChars[bufPos++] = (char)'?'; - bufChars[bufPos++] = (char)'>'; + _bufChars[_bufPos++] = (char)'?'; + _bufChars[_bufPos++] = (char)'>'; } // Serialize an entity reference. @@ -382,18 +438,18 @@ public override async Task WriteEntityRefAsync(string name) CheckAsyncCall(); Debug.Assert(name != null && name.Length > 0); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - bufChars[bufPos++] = (char)'&'; + _bufChars[_bufPos++] = (char)'&'; await RawTextAsync(name).ConfigureAwait(false); - bufChars[bufPos++] = (char)';'; + _bufChars[_bufPos++] = (char)';'; - if (bufPos > bufLen) + if (_bufPos > _bufLen) { await FlushBufferAsync().ConfigureAwait(false); } - textPos = bufPos; + _textPos = _bufPos; } // Serialize a character entity reference. @@ -402,26 +458,26 @@ public override async Task WriteCharEntityAsync(char ch) CheckAsyncCall(); string strVal = ((int)ch).ToString("X", NumberFormatInfo.InvariantInfo); - if (checkCharacters && !xmlCharType.IsCharData(ch)) + if (_checkCharacters && !_xmlCharType.IsCharData(ch)) { // we just have a single char, not a surrogate, therefore we have to pass in '\0' for the second char throw XmlConvert.CreateInvalidCharException(ch, '\0'); } - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - bufChars[bufPos++] = (char)'&'; - bufChars[bufPos++] = (char)'#'; - bufChars[bufPos++] = (char)'x'; + _bufChars[_bufPos++] = (char)'&'; + _bufChars[_bufPos++] = (char)'#'; + _bufChars[_bufPos++] = (char)'x'; await RawTextAsync(strVal).ConfigureAwait(false); - bufChars[bufPos++] = (char)';'; + _bufChars[_bufPos++] = (char)';'; - if (bufPos > bufLen) + if (_bufPos > _bufLen) { await FlushBufferAsync().ConfigureAwait(false); } - textPos = bufPos; + _textPos = _bufPos; } // Serialize a whitespace node. @@ -431,9 +487,9 @@ public override Task WriteWhitespaceAsync(string ws) CheckAsyncCall(); Debug.Assert(ws != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } - if (inAttributeValue) + if (_inAttributeValue) { return WriteAttributeTextBlockAsync(ws); } @@ -450,9 +506,9 @@ public override Task WriteStringAsync(string text) CheckAsyncCall(); Debug.Assert(text != null); - if (trackTextContent && inTextContent != true) { ChangeTextContentMark(true); } + if (_trackTextContent && _inTextContent != true) { ChangeTextContentMark(true); } - if (inAttributeValue) + if (_inAttributeValue) { return WriteAttributeTextBlockAsync(text); } @@ -467,16 +523,16 @@ public override async Task WriteSurrogateCharEntityAsync(char lowChar, char high { CheckAsyncCall(); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } int surrogateChar = XmlCharType.CombineSurrogateChar(lowChar, highChar); - bufChars[bufPos++] = (char)'&'; - bufChars[bufPos++] = (char)'#'; - bufChars[bufPos++] = (char)'x'; + _bufChars[_bufPos++] = (char)'&'; + _bufChars[_bufPos++] = (char)'#'; + _bufChars[_bufPos++] = (char)'x'; await RawTextAsync(surrogateChar.ToString("X", NumberFormatInfo.InvariantInfo)).ConfigureAwait(false); - bufChars[bufPos++] = (char)';'; - textPos = bufPos; + _bufChars[_bufPos++] = (char)';'; + _textPos = _bufPos; } // Serialize either attribute or element text using XML rules. @@ -489,9 +545,9 @@ public override Task WriteCharsAsync(char[] buffer, int index, int count) Debug.Assert(index >= 0); Debug.Assert(count >= 0 && index + count <= buffer.Length); - if (trackTextContent && inTextContent != true) { ChangeTextContentMark(true); } + if (_trackTextContent && _inTextContent != true) { ChangeTextContentMark(true); } - if (inAttributeValue) + if (_inAttributeValue) { return WriteAttributeTextBlockAsync(buffer, index, count); } @@ -511,11 +567,11 @@ public override async Task WriteRawAsync(char[] buffer, int index, int count) Debug.Assert(index >= 0); Debug.Assert(count >= 0 && index + count <= buffer.Length); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } await WriteRawWithCharCheckingAsync(buffer, index, count).ConfigureAwait(false); - textPos = bufPos; + _textPos = _bufPos; } // Serialize raw data. @@ -525,11 +581,11 @@ public override async Task WriteRawAsync(string data) CheckAsyncCall(); Debug.Assert(data != null); - if (trackTextContent && inTextContent != false) { ChangeTextContentMark(false); } + if (_trackTextContent && _inTextContent != false) { ChangeTextContentMark(false); } await WriteRawWithCharCheckingAsync(data).ConfigureAwait(false); - textPos = bufPos; + _textPos = _bufPos; } // Flush all characters in the buffer to output and call Flush() on the output object. @@ -539,13 +595,13 @@ public override async Task FlushAsync() await FlushBufferAsync().ConfigureAwait(false); await FlushEncoderAsync().ConfigureAwait(false); - if (stream != null) + if (_stream != null) { - await stream.FlushAsync().ConfigureAwait(false); + await _stream.FlushAsync().ConfigureAwait(false); } - else if (writer != null) + else if (_writer != null) { - await writer.FlushAsync().ConfigureAwait(false); + await _writer.FlushAsync().ConfigureAwait(false); } } @@ -558,13 +614,13 @@ protected virtual async Task FlushBufferAsync() try { // Output all characters (except for previous characters stored at beginning of buffer) - if (!writeToNull) + if (!_writeToNull) { - Debug.Assert(stream != null || writer != null); + Debug.Assert(_stream != null || _writer != null); - if (stream != null) + if (_stream != null) { - if (trackTextContent) + if (_trackTextContent) { _charEntityFallback.Reset(_textContentMarks, _lastMarkPos); // reset text content tracking @@ -582,33 +638,36 @@ protected virtual async Task FlushBufferAsync() } Debug.Assert(_textContentMarks[0] == 1); } - await EncodeCharsAsync(1, bufPos, true).ConfigureAwait(false); + await EncodeCharsAsync(1, _bufPos, true).ConfigureAwait(false); } else { - // Write text to TextWriter - await writer.WriteAsync(bufChars, 1, bufPos - 1).ConfigureAwait(false); + if (_bufPos - 1 > 0) + { + // Write text to TextWriter + await _writer.WriteAsync(_bufChars.AsMemory(1, _bufPos - 1)).ConfigureAwait(false); + } } } } catch { // Future calls to flush (i.e. when Close() is called) don't attempt to write to stream - writeToNull = true; + _writeToNull = true; throw; } finally { // Move last buffer character to the beginning of the buffer (so that previous character can always be determined) - bufChars[0] = bufChars[bufPos - 1]; + _bufChars[0] = _bufChars[_bufPos - 1]; // Reset buffer position - textPos = (textPos == bufPos) ? 1 : 0; - attrEndPos = (attrEndPos == bufPos) ? 1 : 0; - contentPos = 0; // Needs to be zero, since overwriting '>' character is no longer possible - cdataPos = 0; // Needs to be zero, since overwriting ']]>' characters is no longer possible - bufPos = 1; // Buffer position starts at 1, because we need to be able to safely step back -1 in case we need to + _textPos = (_textPos == _bufPos) ? 1 : 0; + _attrEndPos = (_attrEndPos == _bufPos) ? 1 : 0; + _contentPos = 0; // Needs to be zero, since overwriting '>' character is no longer possible + _cdataPos = 0; // Needs to be zero, since overwriting ']]>' characters is no longer possible + _bufPos = 1; // Buffer position starts at 1, because we need to be able to safely step back -1 in case we need to // close an empty element or in CDATA section detection of double ]; _BUFFER[0] will always be 0 } } @@ -624,35 +683,35 @@ private async Task EncodeCharsAsync(int startOffset, int endOffset, bool writeAl { _charEntityFallback.StartOffset = startOffset; } - encoder.Convert(bufChars, startOffset, endOffset - startOffset, bufBytes, bufBytesUsed, bufBytes.Length - bufBytesUsed, false, out chEnc, out bEnc, out completed); + _encoder.Convert(_bufChars, startOffset, endOffset - startOffset, _bufBytes, _bufBytesUsed, _bufBytes.Length - _bufBytesUsed, false, out chEnc, out bEnc, out completed); startOffset += chEnc; - bufBytesUsed += bEnc; - if (bufBytesUsed >= (bufBytes.Length - 16)) + _bufBytesUsed += bEnc; + if (_bufBytesUsed >= (_bufBytes.Length - 16)) { - await stream.WriteAsync(bufBytes, 0, bufBytesUsed).ConfigureAwait(false); - bufBytesUsed = 0; + await _stream.WriteAsync(_bufBytes.AsMemory(0, _bufBytesUsed)).ConfigureAwait(false); + _bufBytesUsed = 0; } } - if (writeAllToStream && bufBytesUsed > 0) + if (writeAllToStream && _bufBytesUsed > 0) { - await stream.WriteAsync(bufBytes, 0, bufBytesUsed).ConfigureAwait(false); - bufBytesUsed = 0; + await _stream.WriteAsync(_bufBytes.AsMemory(0, _bufBytesUsed)).ConfigureAwait(false); + _bufBytesUsed = 0; } } private Task FlushEncoderAsync() { - Debug.Assert(bufPos == 1); - if (stream != null) + Debug.Assert(_bufPos == 1); + if (_stream != null) { int chEnc; int bEnc; bool completed; // decode no chars, just flush - encoder.Convert(bufChars, 1, 0, bufBytes, 0, bufBytes.Length, true, out chEnc, out bEnc, out completed); + _encoder.Convert(_bufChars, 1, 0, _bufBytes, 0, _bufBytes.Length, true, out chEnc, out bEnc, out completed); if (bEnc != 0) { - return stream.WriteAsync(bufBytes, 0, bEnc); + return _stream.WriteAsync(_bufBytes, 0, bEnc); } } @@ -665,20 +724,20 @@ protected unsafe int WriteAttributeTextBlockNoFlush(char* pSrc, char* pSrcEnd) { char* pRaw = pSrc; - fixed (char* pDstBegin = bufChars) + fixed (char* pDstBegin = _bufChars) { - char* pDst = pDstBegin + bufPos; + char* pDst = pDstBegin + _bufPos; int ch = 0; while (true) { char* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } - while (pDst < pDstEnd && xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) + while (pDst < pDstEnd && _xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) { *pDst = (char)ch; pDst++; @@ -695,7 +754,7 @@ protected unsafe int WriteAttributeTextBlockNoFlush(char* pSrc, char* pSrcEnd) // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); return (int)(pSrc - pRaw); } @@ -719,7 +778,7 @@ protected unsafe int WriteAttributeTextBlockNoFlush(char* pSrc, char* pSrcEnd) pDst++; break; case (char)0x9: - if (newLineHandling == NewLineHandling.None) + if (_newLineHandling == NewLineHandling.None) { *pDst = (char)ch; pDst++; @@ -731,7 +790,7 @@ protected unsafe int WriteAttributeTextBlockNoFlush(char* pSrc, char* pSrcEnd) } break; case (char)0xD: - if (newLineHandling == NewLineHandling.None) + if (_newLineHandling == NewLineHandling.None) { *pDst = (char)ch; pDst++; @@ -743,7 +802,7 @@ protected unsafe int WriteAttributeTextBlockNoFlush(char* pSrc, char* pSrcEnd) } break; case (char)0xA: - if (newLineHandling == NewLineHandling.None) + if (_newLineHandling == NewLineHandling.None) { *pDst = (char)ch; pDst++; @@ -778,7 +837,7 @@ protected unsafe int WriteAttributeTextBlockNoFlush(char* pSrc, char* pSrcEnd) } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } return -1; @@ -869,20 +928,20 @@ protected unsafe int WriteElementTextBlockNoFlush(char* pSrc, char* pSrcEnd, out needWriteNewLine = false; char* pRaw = pSrc; - fixed (char* pDstBegin = bufChars) + fixed (char* pDstBegin = _bufChars) { - char* pDst = pDstBegin + bufPos; + char* pDst = pDstBegin + _bufPos; int ch = 0; while (true) { char* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } - while (pDst < pDstEnd && xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) + while (pDst < pDstEnd && _xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) { *pDst = (char)ch; pDst++; @@ -899,7 +958,7 @@ protected unsafe int WriteElementTextBlockNoFlush(char* pSrc, char* pSrcEnd, out // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); return (int)(pSrc - pRaw); } @@ -922,9 +981,9 @@ protected unsafe int WriteElementTextBlockNoFlush(char* pSrc, char* pSrcEnd, out pDst++; break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); } @@ -935,7 +994,7 @@ protected unsafe int WriteElementTextBlockNoFlush(char* pSrc, char* pSrcEnd, out } break; case (char)0xD: - switch (newLineHandling) + switch (_newLineHandling) { case NewLineHandling.Replace: // Replace "\r\n", or "\r" with NewLineChars @@ -944,7 +1003,7 @@ protected unsafe int WriteElementTextBlockNoFlush(char* pSrc, char* pSrcEnd, out pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); @@ -982,9 +1041,9 @@ protected unsafe int WriteElementTextBlockNoFlush(char* pSrc, char* pSrcEnd, out } pSrc++; } - bufPos = (int)(pDst - pDstBegin); - textPos = bufPos; - contentPos = 0; + _bufPos = (int)(pDst - pDstBegin); + _textPos = _bufPos; + _contentPos = 0; } return -1; @@ -995,7 +1054,7 @@ protected unsafe int WriteElementTextBlockNoFlush(char[] chars, int index, int c needWriteNewLine = false; if (count == 0) { - contentPos = 0; + _contentPos = 0; return -1; } fixed (char* pSrc = &chars[index]) @@ -1011,7 +1070,7 @@ protected unsafe int WriteElementTextBlockNoFlush(string text, int index, int co needWriteNewLine = false; if (count == 0) { - contentPos = 0; + _contentPos = 0; return -1; } fixed (char* pSrc = text) @@ -1036,7 +1095,7 @@ protected async Task WriteElementTextBlockAsync(char[] chars, int index, int cou if (needWriteNewLine) { //hit WriteNewLine - await RawTextAsync(newLineChars).ConfigureAwait(false); + await RawTextAsync(_newLineChars).ConfigureAwait(false); curIndex++; leftCount--; } @@ -1076,7 +1135,7 @@ private async Task _WriteElementTextBlockAsync(bool newLine, string text, int cu if (newLine) { - await RawTextAsync(newLineChars).ConfigureAwait(false); + await RawTextAsync(_newLineChars).ConfigureAwait(false); curIndex++; leftCount--; } @@ -1093,7 +1152,7 @@ private async Task _WriteElementTextBlockAsync(bool newLine, string text, int cu if (needWriteNewLine) { //hit WriteNewLine - await RawTextAsync(newLineChars).ConfigureAwait(false); + await RawTextAsync(_newLineChars).ConfigureAwait(false); curIndex++; leftCount--; } @@ -1108,18 +1167,18 @@ protected unsafe int RawTextNoFlush(char* pSrcBegin, char* pSrcEnd) { char* pRaw = pSrcBegin; - fixed (char* pDstBegin = bufChars) + fixed (char* pDstBegin = _bufChars) { - char* pDst = pDstBegin + bufPos; + char* pDst = pDstBegin + _bufPos; char* pSrc = pSrcBegin; int ch = 0; while (true) { char* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } while (pDst < pDstEnd && ((ch = *pSrc) < XmlCharType.SurHighStart)) @@ -1139,7 +1198,7 @@ protected unsafe int RawTextNoFlush(char* pSrcBegin, char* pSrcEnd) // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); return (int)(pSrc - pRaw); } @@ -1164,7 +1223,7 @@ protected unsafe int RawTextNoFlush(char* pSrcBegin, char* pSrcEnd) } } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } return -1; @@ -1283,21 +1342,21 @@ protected unsafe int WriteRawWithCharCheckingNoFlush(char* pSrcBegin, char* pSrc needWriteNewLine = false; char* pRaw = pSrcBegin; - fixed (char* pDstBegin = bufChars) + fixed (char* pDstBegin = _bufChars) { char* pSrc = pSrcBegin; - char* pDst = pDstBegin + bufPos; + char* pDst = pDstBegin + _bufPos; int ch = 0; while (true) { char* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } - while (pDst < pDstEnd && xmlCharType.IsTextChar((char)(ch = *pSrc))) + while (pDst < pDstEnd && _xmlCharType.IsTextChar((char)(ch = *pSrc))) { *pDst = (char)ch; pDst++; @@ -1315,7 +1374,7 @@ protected unsafe int WriteRawWithCharCheckingNoFlush(char* pSrcBegin, char* pSrc // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); return (int)(pSrc - pRaw); } @@ -1330,7 +1389,7 @@ protected unsafe int WriteRawWithCharCheckingNoFlush(char* pSrcBegin, char* pSrc pDst++; break; case (char)0xD: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { // Normalize "\r\n", or "\r" to NewLineChars if (pSrc + 1 < pSrcEnd && pSrc[1] == '\n') @@ -1338,7 +1397,7 @@ protected unsafe int WriteRawWithCharCheckingNoFlush(char* pSrcBegin, char* pSrc pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); } @@ -1349,9 +1408,9 @@ protected unsafe int WriteRawWithCharCheckingNoFlush(char* pSrcBegin, char* pSrc } break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); } @@ -1385,7 +1444,7 @@ protected unsafe int WriteRawWithCharCheckingNoFlush(char* pSrcBegin, char* pSrc } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } return -1; @@ -1434,7 +1493,7 @@ protected async Task WriteRawWithCharCheckingAsync(char[] chars, int index, int leftCount -= writeLen; if (needWriteNewLine) { - await RawTextAsync(newLineChars).ConfigureAwait(false); + await RawTextAsync(_newLineChars).ConfigureAwait(false); curIndex++; leftCount--; } @@ -1458,7 +1517,7 @@ protected async Task WriteRawWithCharCheckingAsync(string text) leftCount -= writeLen; if (needWriteNewLine) { - await RawTextAsync(newLineChars).ConfigureAwait(false); + await RawTextAsync(_newLineChars).ConfigureAwait(false); curIndex++; leftCount--; } @@ -1480,7 +1539,7 @@ protected unsafe int WriteCommentOrPiNoFlush(string text, int index, int count, { char* pSrcBegin = pSrcText + index; - fixed (char* pDstBegin = bufChars) + fixed (char* pDstBegin = _bufChars) { char* pSrc = pSrcBegin; @@ -1488,18 +1547,18 @@ protected unsafe int WriteCommentOrPiNoFlush(string text, int index, int count, char* pSrcEnd = pSrcBegin + count; - char* pDst = pDstBegin + bufPos; + char* pDst = pDstBegin + _bufPos; int ch = 0; while (true) { char* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } - while (pDst < pDstEnd && (xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch != stopChar)) + while (pDst < pDstEnd && (_xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch != stopChar)) { *pDst = (char)ch; pDst++; @@ -1517,7 +1576,7 @@ protected unsafe int WriteCommentOrPiNoFlush(string text, int index, int count, // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); return (int)(pSrc - pRaw); } @@ -1555,7 +1614,7 @@ protected unsafe int WriteCommentOrPiNoFlush(string text, int index, int count, pDst++; break; case (char)0xD: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { // Normalize "\r\n", or "\r" to NewLineChars if (pSrc + 1 < pSrcEnd && pSrc[1] == '\n') @@ -1563,7 +1622,7 @@ protected unsafe int WriteCommentOrPiNoFlush(string text, int index, int count, pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); } @@ -1574,9 +1633,9 @@ protected unsafe int WriteCommentOrPiNoFlush(string text, int index, int count, } break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); } @@ -1616,7 +1675,7 @@ protected unsafe int WriteCommentOrPiNoFlush(string text, int index, int count, } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } return -1; @@ -1627,7 +1686,7 @@ protected async Task WriteCommentOrPiAsync(string text, int stopChar) { if (text.Length == 0) { - if (bufPos >= bufLen) + if (_bufPos >= _bufLen) { await FlushBufferAsync().ConfigureAwait(false); } @@ -1645,7 +1704,7 @@ protected async Task WriteCommentOrPiAsync(string text, int stopChar) leftCount -= writeLen; if (needWriteNewLine) { - await RawTextAsync(newLineChars).ConfigureAwait(false); + await RawTextAsync(_newLineChars).ConfigureAwait(false); curIndex++; leftCount--; } @@ -1670,7 +1729,7 @@ protected unsafe int WriteCDataSectionNoFlush(string text, int index, int count, { char* pSrcBegin = pSrcText + index; - fixed (char* pDstBegin = bufChars) + fixed (char* pDstBegin = _bufChars) { char* pSrc = pSrcBegin; @@ -1678,18 +1737,18 @@ protected unsafe int WriteCDataSectionNoFlush(string text, int index, int count, char* pRaw = pSrc; - char* pDst = pDstBegin + bufPos; + char* pDst = pDstBegin + _bufPos; int ch = 0; while (true) { char* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } - while (pDst < pDstEnd && (xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch != ']')) + while (pDst < pDstEnd && (_xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch != ']')) { *pDst = (char)ch; pDst++; @@ -1707,7 +1766,7 @@ protected unsafe int WriteCDataSectionNoFlush(string text, int index, int count, // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); return (int)(pSrc - pRaw); } @@ -1715,7 +1774,7 @@ protected unsafe int WriteCDataSectionNoFlush(string text, int index, int count, switch (ch) { case '>': - if (hadDoubleBracket && pDst[-1] == (char)']') + if (_hadDoubleBracket && pDst[-1] == (char)']') { // pDst[-1] will always correct - there is a padding character at _BUFFER[0] // The characters "]]>" were found within the CData text pDst = RawEndCData(pDst); @@ -1727,17 +1786,17 @@ protected unsafe int WriteCDataSectionNoFlush(string text, int index, int count, case ']': if (pDst[-1] == (char)']') { // pDst[-1] will always correct - there is a padding character at _BUFFER[0] - hadDoubleBracket = true; + _hadDoubleBracket = true; } else { - hadDoubleBracket = false; + _hadDoubleBracket = false; } *pDst = (char)']'; pDst++; break; case (char)0xD: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { // Normalize "\r\n", or "\r" to NewLineChars if (pSrc + 1 < pSrcEnd && pSrc[1] == '\n') @@ -1745,7 +1804,7 @@ protected unsafe int WriteCDataSectionNoFlush(string text, int index, int count, pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); } @@ -1756,9 +1815,9 @@ protected unsafe int WriteCDataSectionNoFlush(string text, int index, int count, } break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); } @@ -1800,7 +1859,7 @@ protected unsafe int WriteCDataSectionNoFlush(string text, int index, int count, } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } return -1; @@ -1811,7 +1870,7 @@ protected async Task WriteCDataSectionAsync(string text) { if (text.Length == 0) { - if (bufPos >= bufLen) + if (_bufPos >= _bufLen) { await FlushBufferAsync().ConfigureAwait(false); } @@ -1829,7 +1888,7 @@ protected async Task WriteCDataSectionAsync(string text) leftCount -= writeLen; if (needWriteNewLine) { - await RawTextAsync(newLineChars).ConfigureAwait(false); + await RawTextAsync(_newLineChars).ConfigureAwait(false); curIndex++; leftCount--; } @@ -1848,7 +1907,7 @@ public override async Task WriteDocTypeAsync(string name, string pubid, string s { CheckAsyncCall(); // Add indentation - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { await WriteIndentAsync().ConfigureAwait(false); } @@ -1861,12 +1920,12 @@ public override async Task WriteStartElementAsync(string prefix, string localNam Debug.Assert(localName != null && localName.Length != 0 && prefix != null && ns != null); // Add indentation - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { await WriteIndentAsync().ConfigureAwait(false); } - indentLevel++; - _mixedContentStack.PushBit(mixedContent); + _indentLevel++; + _mixedContentStack.PushBit(_mixedContent); await base.WriteStartElementAsync(prefix, localName, ns).ConfigureAwait(false); } @@ -1875,16 +1934,16 @@ internal override async Task WriteEndElementAsync(string prefix, string localNam { CheckAsyncCall(); // Add indentation - indentLevel--; - if (!mixedContent && base.contentPos != base.bufPos) + _indentLevel--; + if (!_mixedContent && base._contentPos != base._bufPos) { // There was content, so try to indent - if (base.textPos != base.bufPos) + if (base._textPos != base._bufPos) { await WriteIndentAsync().ConfigureAwait(false); } } - mixedContent = _mixedContentStack.PopBit(); + _mixedContent = _mixedContentStack.PopBit(); await base.WriteEndElementAsync(prefix, localName, ns).ConfigureAwait(false); } @@ -1893,16 +1952,16 @@ internal override async Task WriteFullEndElementAsync(string prefix, string loca { CheckAsyncCall(); // Add indentation - indentLevel--; - if (!mixedContent && base.contentPos != base.bufPos) + _indentLevel--; + if (!_mixedContent && base._contentPos != base._bufPos) { // There was content, so try to indent - if (base.textPos != base.bufPos) + if (base._textPos != base._bufPos) { await WriteIndentAsync().ConfigureAwait(false); } } - mixedContent = _mixedContentStack.PopBit(); + _mixedContent = _mixedContentStack.PopBit(); await base.WriteFullEndElementAsync(prefix, localName, ns).ConfigureAwait(false); } @@ -1912,7 +1971,7 @@ protected internal override async Task WriteStartAttributeAsync(string prefix, s { CheckAsyncCall(); // Add indentation - if (newLineOnAttributes) + if (_newLineOnAttributes) { await WriteIndentAsync().ConfigureAwait(false); } @@ -1923,14 +1982,14 @@ protected internal override async Task WriteStartAttributeAsync(string prefix, s public override Task WriteCDataAsync(string text) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteCDataAsync(text); } public override async Task WriteCommentAsync(string text) { CheckAsyncCall(); - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { await WriteIndentAsync().ConfigureAwait(false); } @@ -1941,7 +2000,7 @@ public override async Task WriteCommentAsync(string text) public override async Task WriteProcessingInstructionAsync(string target, string text) { CheckAsyncCall(); - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { await WriteIndentAsync().ConfigureAwait(false); } @@ -1952,63 +2011,63 @@ public override async Task WriteProcessingInstructionAsync(string target, string public override Task WriteEntityRefAsync(string name) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteEntityRefAsync(name); } public override Task WriteCharEntityAsync(char ch) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteCharEntityAsync(ch); } public override Task WriteSurrogateCharEntityAsync(char lowChar, char highChar) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteSurrogateCharEntityAsync(lowChar, highChar); } public override Task WriteWhitespaceAsync(string ws) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteWhitespaceAsync(ws); } public override Task WriteStringAsync(string text) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteStringAsync(text); } public override Task WriteCharsAsync(char[] buffer, int index, int count) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteCharsAsync(buffer, index, count); } public override Task WriteRawAsync(char[] buffer, int index, int count) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteRawAsync(buffer, index, count); } public override Task WriteRawAsync(string data) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteRawAsync(data); } public override Task WriteBase64Async(byte[] buffer, int index, int count) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteBase64Async(buffer, index, count); } @@ -2016,10 +2075,10 @@ public override Task WriteBase64Async(byte[] buffer, int index, int count) private async Task WriteIndentAsync() { CheckAsyncCall(); - await RawTextAsync(base.newLineChars).ConfigureAwait(false); - for (int i = indentLevel; i > 0; i--) + await RawTextAsync(base._newLineChars).ConfigureAwait(false); + for (int i = _indentLevel; i > 0; i--) { - await RawTextAsync(indentChars).ConfigureAwait(false); + await RawTextAsync(_indentChars).ConfigureAwait(false); } } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEventCache.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEventCache.cs index b036585efbb224..857f50f3c13af3 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEventCache.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEventCache.cs @@ -431,7 +431,7 @@ public override void Flush() /// public override void WriteValue(object value) { - WriteString(XmlUntypedConverter.Untyped.ToString(value, this.resolver)); + WriteString(XmlUntypedConverter.Untyped.ToString(value, this._resolver)); } public override void WriteValue(string value) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlParserContext.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlParserContext.cs index e6a6dd5a2be6dc..252d39c678fb25 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlParserContext.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlParserContext.cs @@ -2,17 +2,19 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Xml; using System.Text; using System; +using System.Diagnostics.CodeAnalysis; namespace System.Xml { // Specifies the context that the XmLReader will use for xml fragment public class XmlParserContext { - private XmlNameTable _nt = null; - private XmlNamespaceManager _nsMgr = null; + private XmlNameTable? _nt = null; + private XmlNamespaceManager? _nsMgr = null; private string _docTypeName = string.Empty; private string _pubId = string.Empty; private string _sysId = string.Empty; @@ -20,31 +22,31 @@ public class XmlParserContext private string _xmlLang = string.Empty; private XmlSpace _xmlSpace; private string _baseURI = string.Empty; - private Encoding _encoding = null; + private Encoding? _encoding = null; - public XmlParserContext(XmlNameTable nt, XmlNamespaceManager nsMgr, string xmlLang, XmlSpace xmlSpace) + public XmlParserContext(XmlNameTable? nt, XmlNamespaceManager? nsMgr, string? xmlLang, XmlSpace xmlSpace) : this(nt, nsMgr, null, null, null, null, string.Empty, xmlLang, xmlSpace) { // Intentionally Empty } - public XmlParserContext(XmlNameTable nt, XmlNamespaceManager nsMgr, string xmlLang, XmlSpace xmlSpace, Encoding enc) + public XmlParserContext(XmlNameTable? nt, XmlNamespaceManager? nsMgr, string? xmlLang, XmlSpace xmlSpace, Encoding? enc) : this(nt, nsMgr, null, null, null, null, string.Empty, xmlLang, xmlSpace, enc) { // Intentionally Empty } - public XmlParserContext(XmlNameTable nt, XmlNamespaceManager nsMgr, string docTypeName, - string pubId, string sysId, string internalSubset, string baseURI, - string xmlLang, XmlSpace xmlSpace) + public XmlParserContext(XmlNameTable? nt, XmlNamespaceManager? nsMgr, string? docTypeName, + string? pubId, string? sysId, string? internalSubset, string? baseURI, + string? xmlLang, XmlSpace xmlSpace) : this(nt, nsMgr, docTypeName, pubId, sysId, internalSubset, baseURI, xmlLang, xmlSpace, null) { // Intentionally Empty } - public XmlParserContext(XmlNameTable nt, XmlNamespaceManager nsMgr, string docTypeName, - string pubId, string sysId, string internalSubset, string baseURI, - string xmlLang, XmlSpace xmlSpace, Encoding enc) + public XmlParserContext(XmlNameTable? nt, XmlNamespaceManager? nsMgr, string? docTypeName, + string? pubId, string? sysId, string? internalSubset, string? baseURI, + string? xmlLang, XmlSpace xmlSpace, Encoding? enc) { if (nsMgr != null) { @@ -54,10 +56,11 @@ public XmlParserContext(XmlNameTable nt, XmlNamespaceManager nsMgr, string docTy } else { - if ((object)nt != (object)nsMgr.NameTable) + if ((object)nt != (object?)nsMgr.NameTable) { throw new XmlException(SR.Xml_NotSameNametable, string.Empty); } + _nt = nt; } } @@ -77,7 +80,7 @@ public XmlParserContext(XmlNameTable nt, XmlNamespaceManager nsMgr, string docTy _encoding = enc; } - public XmlNameTable NameTable + public XmlNameTable? NameTable { get { @@ -89,7 +92,7 @@ public XmlNameTable NameTable } } - public XmlNamespaceManager NamespaceManager + public XmlNamespaceManager? NamespaceManager { get { @@ -101,6 +104,7 @@ public XmlNamespaceManager NamespaceManager } } + [AllowNull] public string DocTypeName { get @@ -113,6 +117,7 @@ public string DocTypeName } } + [AllowNull] public string PublicId { get @@ -125,6 +130,7 @@ public string PublicId } } + [AllowNull] public string SystemId { get @@ -137,6 +143,7 @@ public string SystemId } } + [AllowNull] public string BaseURI { get @@ -149,6 +156,7 @@ public string BaseURI } } + [AllowNull] public string InternalSubset { get @@ -161,6 +169,7 @@ public string InternalSubset } } + [AllowNull] public string XmlLang { get @@ -185,7 +194,7 @@ public XmlSpace XmlSpace } } - public Encoding Encoding + public Encoding? Encoding { get { diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGenerator.ttinclude b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGenerator.ttinclude index 99c9681661fb76..f9704285b633f1 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGenerator.ttinclude +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGenerator.ttinclude @@ -28,44 +28,44 @@ namespace System.Xml private readonly bool _useAsync; // main buffer - protected byte[] bufBytes; + protected byte[] _bufBytes; // output stream - protected Stream stream; + protected Stream _stream; // encoding of the stream or text writer - protected Encoding encoding; + protected Encoding _encoding; // char type tables - protected XmlCharType xmlCharType = XmlCharType.Instance; + protected XmlCharType _xmlCharType = XmlCharType.Instance; // buffer positions - protected int bufPos = 1; // buffer position starts at 1, because we need to be able to safely step back -1 in case we need to - // close an empty element or in CDATA section detection of double ]; <#= BufferName #>[0] will always be 0 - protected int textPos = 1; // text end position; don't indent first element, pi, or comment - protected int contentPos; // element content end position - protected int cdataPos; // cdata end position - protected int attrEndPos; // end of the last attribute - protected int bufLen = BUFSIZE; + protected int _bufPos = 1; // buffer position starts at 1, because we need to be able to safely step back -1 in case we need to + // close an empty element or in CDATA section detection of double ]; <#= BufferName #>[0] will always be 0 + protected int _textPos = 1; // text end position; don't indent first element, pi, or comment + protected int _contentPos; // element content end position + protected int _cdataPos; // cdata end position + protected int _attrEndPos; // end of the last attribute + protected int _bufLen = BUFSIZE; // flags - protected bool writeToNull; - protected bool hadDoubleBracket; - protected bool inAttributeValue; + protected bool _writeToNull; + protected bool _hadDoubleBracket; + protected bool _inAttributeValue; <# if (WriterType == RawTextWriterType.Encoded) { #> - protected int bufBytesUsed; - protected char[] bufChars; + protected int _bufBytesUsed; + protected char[] _bufChars; // encoder for encoding chars in specified encoding when writing to stream - protected Encoder encoder; + protected Encoder _encoder; // output text writer - protected TextWriter writer; + protected TextWriter _writer; // escaping of characters invalid in the output encoding - protected bool trackTextContent; - protected bool inTextContent; + protected bool _trackTextContent; + protected bool _inTextContent; private int _lastMarkPos; private int[] _textContentMarks; // even indices contain text content start positions // odd indices contain markup start positions @@ -73,17 +73,17 @@ namespace System.Xml <# } #> // writer settings - protected NewLineHandling newLineHandling; - protected bool closeOutput; - protected bool omitXmlDeclaration; - protected string newLineChars; - protected bool checkCharacters; + protected NewLineHandling _newLineHandling; + protected bool _closeOutput; + protected bool _omitXmlDeclaration; + protected string _newLineChars; + protected bool _checkCharacters; - protected XmlStandalone standalone; - protected XmlOutputMethod outputMethod; + protected XmlStandalone _standalone; + protected XmlOutputMethod _outputMethod; - protected bool autoXmlDeclaration; - protected bool mergeCDataSections; + protected bool _autoXmlDeclaration; + protected bool _mergeCDataSections; // // Constants @@ -102,19 +102,19 @@ namespace System.Xml _useAsync = settings.Async; // copy settings - newLineHandling = settings.NewLineHandling; - omitXmlDeclaration = settings.OmitXmlDeclaration; - newLineChars = settings.NewLineChars; - checkCharacters = settings.CheckCharacters; - closeOutput = settings.CloseOutput; + _newLineHandling = settings.NewLineHandling; + _omitXmlDeclaration = settings.OmitXmlDeclaration; + _newLineChars = settings.NewLineChars; + _checkCharacters = settings.CheckCharacters; + _closeOutput = settings.CloseOutput; - standalone = settings.Standalone; - outputMethod = settings.OutputMethod; - mergeCDataSections = settings.MergeCDataSections; + _standalone = settings.Standalone; + _outputMethod = settings.OutputMethod; + _mergeCDataSections = settings.MergeCDataSections; - if (checkCharacters && newLineHandling == NewLineHandling.Replace) + if (_checkCharacters && _newLineHandling == NewLineHandling.Replace) { - ValidateContentChars(newLineChars, "NewLineChars", false); + ValidateContentChars(_newLineChars, "NewLineChars", false); } } <# if (WriterType == RawTextWriterType.Encoded) { #> @@ -124,20 +124,20 @@ namespace System.Xml { Debug.Assert(writer != null && settings != null); - this.writer = writer; - this.encoding = writer.Encoding; + this._writer = writer; + this._encoding = writer.Encoding; // the buffer is allocated will OVERFLOW in order to reduce checks when writing out constant size markup if (settings.Async) { - bufLen = ASYNCBUFSIZE; + _bufLen = ASYNCBUFSIZE; } - this.bufChars = new <#= BufferType #>[bufLen + OVERFLOW]; + this._bufChars = new <#= BufferType #>[_bufLen + OVERFLOW]; // Write the xml declaration if (settings.AutoXmlDeclaration) { - WriteXmlDeclaration(standalone); - autoXmlDeclaration = true; + WriteXmlDeclaration(_standalone); + _autoXmlDeclaration = true; } } <# } #> @@ -147,35 +147,35 @@ namespace System.Xml { Debug.Assert(stream != null && settings != null); - this.stream = stream; - this.encoding = settings.Encoding; + this._stream = stream; + this._encoding = settings.Encoding; // the buffer is allocated will OVERFLOW in order to reduce checks when writing out constant size markup if (settings.Async) { - bufLen = ASYNCBUFSIZE; + _bufLen = ASYNCBUFSIZE; } - <#= BufferName #> = new <#= BufferType #>[bufLen + OVERFLOW]; + <#= BufferName #> = new <#= BufferType #>[_bufLen + OVERFLOW]; <# if (WriterType == RawTextWriterType.Utf8) { #> // Output UTF-8 byte order mark if Encoding object wants it if (!stream.CanSeek || stream.Position == 0) { - ReadOnlySpan bom = encoding.Preamble; + ReadOnlySpan bom = _encoding.Preamble; if (bom.Length != 0) { - bom.CopyTo(new Span(bufBytes).Slice(1)); - bufPos += bom.Length; - textPos += bom.Length; + bom.CopyTo(new Span(_bufBytes).Slice(1)); + _bufPos += bom.Length; + _textPos += bom.Length; } } <# } else { #> - bufBytes = new byte[bufChars.Length]; - bufBytesUsed = 0; + _bufBytes = new byte[_bufChars.Length]; + _bufBytesUsed = 0; // Init escaping of characters not fitting into the target encoding - trackTextContent = true; - inTextContent = false; + _trackTextContent = true; + _inTextContent = false; _lastMarkPos = 0; _textContentMarks = new int[INIT_MARKS_COUNT]; _textContentMarks[0] = 1; @@ -183,21 +183,21 @@ namespace System.Xml _charEntityFallback = new CharEntityEncoderFallback(); // grab bom before possibly changing encoding settings - ReadOnlySpan bom = encoding.Preamble; + ReadOnlySpan bom = _encoding.Preamble; // the encoding instance this creates can differ from the one passed in - this.encoding = Encoding.GetEncoding( + this._encoding = Encoding.GetEncoding( settings.Encoding.CodePage, _charEntityFallback, settings.Encoding.DecoderFallback); - encoder = encoding.GetEncoder(); + _encoder = _encoding.GetEncoder(); - if (!stream.CanSeek || stream.Position == 0) + if (!_stream.CanSeek || _stream.Position == 0) { if (bom.Length != 0) { - this.stream.Write(bom); + this._stream.Write(bom); } } <# } #> @@ -205,8 +205,8 @@ namespace System.Xml // Write the xml declaration if (settings.AutoXmlDeclaration) { - WriteXmlDeclaration(standalone); - autoXmlDeclaration = true; + WriteXmlDeclaration(_standalone); + _autoXmlDeclaration = true; } } @@ -220,17 +220,17 @@ namespace System.Xml { XmlWriterSettings settings = new XmlWriterSettings(); - settings.Encoding = encoding; - settings.OmitXmlDeclaration = omitXmlDeclaration; - settings.NewLineHandling = newLineHandling; - settings.NewLineChars = newLineChars; - settings.CloseOutput = closeOutput; + settings.Encoding = _encoding; + settings.OmitXmlDeclaration = _omitXmlDeclaration; + settings.NewLineHandling = _newLineHandling; + settings.NewLineChars = _newLineChars; + settings.CloseOutput = _closeOutput; settings.ConformanceLevel = ConformanceLevel.Auto; - settings.CheckCharacters = checkCharacters; + settings.CheckCharacters = _checkCharacters; - settings.AutoXmlDeclaration = autoXmlDeclaration; - settings.Standalone = standalone; - settings.OutputMethod = outputMethod; + settings.AutoXmlDeclaration = _autoXmlDeclaration; + settings.Standalone = _standalone; + settings.OutputMethod = _outputMethod; settings.ReadOnly = true; return settings; @@ -241,7 +241,7 @@ namespace System.Xml internal override void WriteXmlDeclaration(XmlStandalone standalone) { // Output xml declaration only if user allows it and it was not already output - if (!omitXmlDeclaration && !autoXmlDeclaration) + if (!_omitXmlDeclaration && !_autoXmlDeclaration) {<# /* Code block is to squash extra line. */ #><#= SetTextContentMark(4, 1, false) #> RawText("[bufPos++] = (<#= BufferType #>)'"'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'"'; } else if (sysid != null) { RawText(" SYSTEM \""); RawText(sysid); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'"'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'"'; } else { - <#= BufferName #>[bufPos++] = (<#= BufferType #>)' '; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)' '; } if (subset != null) { - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'['; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'['; RawText(subset); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)']'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)']'; } - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'>'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'>'; } // Serialize the beginning of an element start tag: "<#= SetTextContentMark(3, false) #> - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'<'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'<'; if (prefix != null && prefix.Length != 0) { RawText(prefix); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)':'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)':'; } RawText(localName); - attrEndPos = bufPos; + _attrEndPos = _bufPos; } // Serialize the end of an element start tag in preparation for content serialization: ">" internal override void StartElementContent() { - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'>'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'>'; // StartElementContent is always called; therefore, in order to allow shortcut syntax, we save the // position of the '>' character. If WriteEndElement is called and no other characters have been // output, then the '>' character can be overwritten with the shortcut syntax " />". - contentPos = bufPos; + _contentPos = _bufPos; } // Serialize an element end tag: "", if content was output. Otherwise, serialize @@ -357,27 +357,27 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - if (contentPos != bufPos) + if (_contentPos != _bufPos) { // Content has been output, so can't use shortcut syntax - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'<'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'/'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'<'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'/'; if (prefix != null && prefix.Length != 0) { RawText(prefix); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)':'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)':'; } RawText(localName); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'>'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'>'; } else { // Use shortcut syntax; overwrite the already output '>' character - bufPos--; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)' '; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'/'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'>'; + _bufPos--; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)' '; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'/'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'>'; } } @@ -389,16 +389,16 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'<'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'/'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'<'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'/'; if (prefix != null && prefix.Length != 0) { RawText(prefix); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)':'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)':'; } RawText(localName); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'>'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'>'; } // Serialize an attribute tag using double quotes around the attribute value: 'prefix:localName="' @@ -409,21 +409,21 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - if (attrEndPos == bufPos) + if (_attrEndPos == _bufPos) { - <#= BufferName #>[bufPos++] = (<#= BufferType #>)' '; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)' '; } if (prefix != null && prefix.Length > 0) { RawText(prefix); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)':'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)':'; } RawText(localName); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'='; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'"'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'='; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'"'; - inAttributeValue = true; + _inAttributeValue = true; } // Serialize the end of an attribute value using double quotes: '"' @@ -431,9 +431,9 @@ namespace System.Xml {<# #><#= SetTextContentMark(3, 1, false) #> - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'"'; - inAttributeValue = false; - attrEndPos = bufPos; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'"'; + _inAttributeValue = false; + _attrEndPos = _bufPos; } internal override void WriteNamespaceDeclaration(string prefix, string namespaceName) @@ -467,21 +467,21 @@ namespace System.Xml { RawText(" xmlns:"); RawText(prefix); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'='; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'"'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'='; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'"'; } - inAttributeValue = true;<# + _inAttributeValue = true;<# #><#= SetTextContentMark(3, true) #> } internal override void WriteEndNamespaceDeclaration() {<# #><#= SetTextContentMark(3, 1, false) #> - inAttributeValue = false; + _inAttributeValue = false; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'"'; - attrEndPos = bufPos; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'"'; + _attrEndPos = _bufPos; } // Serialize a CData section. If the "]]>" pattern is found within @@ -492,34 +492,34 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - if (mergeCDataSections && bufPos == cdataPos) + if (_mergeCDataSections && _bufPos == _cdataPos) { // Merge adjacent cdata sections - overwrite the "]]>" characters - Debug.Assert(bufPos >= 4); - bufPos -= 3; + Debug.Assert(_bufPos >= 4); + _bufPos -= 3; } else { // Start a new cdata section - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'<'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'!'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'['; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'C'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'D'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'A'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'T'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'A'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'['; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'<'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'!'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'['; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'C'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'D'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'A'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'T'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'A'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'['; } WriteCDataSection(text); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)']'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)']'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'>'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)']'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)']'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'>'; - textPos = bufPos; - cdataPos = bufPos; + _textPos = _bufPos; + _cdataPos = _bufPos; } // Serialize a comment. @@ -529,16 +529,16 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'<'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'!'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'-'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'-'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'<'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'!'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'-'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'-'; WriteCommentOrPi(text, '-'); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'-'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'-'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'>'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'-'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'-'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'>'; } // Serialize a processing instruction. @@ -549,18 +549,18 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'<'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'?'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'<'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'?'; RawText(name); if (text.Length > 0) { - <#= BufferName #>[bufPos++] = (<#= BufferType #>)' '; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)' '; WriteCommentOrPi(text, '?'); } - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'?'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'>'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'?'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'>'; } // Serialize an entity reference. @@ -570,16 +570,16 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'&'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'&'; RawText(name); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)';'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)';'; - if (bufPos > bufLen) + if (_bufPos > _bufLen) { FlushBuffer(); } - textPos = bufPos; + _textPos = _bufPos; } // Serialize a character entity reference. @@ -587,7 +587,7 @@ namespace System.Xml { string strVal = ((int)ch).ToString("X", NumberFormatInfo.InvariantInfo); - if (checkCharacters && !xmlCharType.IsCharData(ch)) + if (_checkCharacters && !_xmlCharType.IsCharData(ch)) { // we just have a single char, not a surrogate, therefore we have to pass in '\0' for the second char throw XmlConvert.CreateInvalidCharException(ch, '\0'); @@ -595,18 +595,18 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'&'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'#'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'x'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'&'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'#'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'x'; RawText(strVal); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)';'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)';'; - if (bufPos > bufLen) + if (_bufPos > _bufLen) { FlushBuffer(); } - textPos = bufPos; + _textPos = _bufPos; } // Serialize a whitespace node. @@ -620,7 +620,7 @@ namespace System.Xml fixed (char* pSrc = ws) { char* pSrcEnd = pSrc + ws.Length; - if (inAttributeValue) + if (_inAttributeValue) { WriteAttributeTextBlock(pSrc, pSrcEnd); } @@ -642,7 +642,7 @@ namespace System.Xml fixed (char* pSrc = text) { char* pSrcEnd = pSrc + text.Length; - if (inAttributeValue) + if (_inAttributeValue) { WriteAttributeTextBlock(pSrc, pSrcEnd); } @@ -659,12 +659,12 @@ namespace System.Xml #><#= SetTextContentMark(3, 1, false) #> int surrogateChar = XmlCharType.CombineSurrogateChar(lowChar, highChar); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'&'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'#'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'x'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'&'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'#'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'x'; RawText(surrogateChar.ToString("X", NumberFormatInfo.InvariantInfo)); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)';'; - textPos = bufPos; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)';'; + _textPos = _bufPos; } // Serialize either attribute or element text using XML rules. @@ -680,7 +680,7 @@ namespace System.Xml fixed (char* pSrcBegin = &buffer[index]) { - if (inAttributeValue) + if (_inAttributeValue) { WriteAttributeTextBlock(pSrcBegin, pSrcBegin + count); } @@ -707,7 +707,7 @@ namespace System.Xml WriteRawWithCharChecking(pSrcBegin, pSrcBegin + count); } - textPos = bufPos; + _textPos = _bufPos; } // Serialize raw data. @@ -723,7 +723,7 @@ namespace System.Xml WriteRawWithCharChecking(pSrcBegin, pSrcBegin + data.Length); } - textPos = bufPos; + _textPos = _bufPos; } // Flush all bytes in the buffer to output and close the output stream or writer. @@ -737,48 +737,48 @@ namespace System.Xml finally { // Future calls to Close or Flush shouldn't write to Stream or Writer - writeToNull = true; + _writeToNull = true; - if (stream != null) + if (_stream != null) { try { - stream.Flush(); + _stream.Flush(); } finally { try { - if (closeOutput) + if (_closeOutput) { - stream.Dispose(); + _stream.Dispose(); } } finally { - stream = null; + _stream = null; } } } <# if (WriterType == RawTextWriterType.Encoded) { #> - else if (writer != null) + else if (_writer != null) { try { - writer.Flush(); + _writer.Flush(); } finally { try { - if (closeOutput) + if (_closeOutput) { - writer.Dispose(); + _writer.Dispose(); } } finally { - writer = null; + _writer = null; } } } @@ -792,18 +792,18 @@ namespace System.Xml FlushBuffer(); FlushEncoder(); <# if (WriterType == RawTextWriterType.Utf8) { #> - if (stream != null) + if (_stream != null) { - stream.Flush(); + _stream.Flush(); } <# } else { #> - if (stream != null) + if (_stream != null) { - stream.Flush(); + _stream.Flush(); } - else if (writer != null) + else if (_writer != null) { - writer.Flush(); + _writer.Flush(); } <# } #> } @@ -817,17 +817,20 @@ namespace System.Xml try { // Output all characters (except for previous characters stored at beginning of buffer) - if (!writeToNull) + if (!_writeToNull) { <# if (WriterType == RawTextWriterType.Utf8) { #> - Debug.Assert(stream != null); - stream.Write(<#= BufferName #>, 1, bufPos - 1); + if (_bufPos - 1 > 0) + { + Debug.Assert(_stream != null); + _stream.Write(<#= BufferName #>, 1, _bufPos - 1); + } <# } else { #> - Debug.Assert(stream != null || writer != null); + Debug.Assert(_stream != null || _writer != null); - if (stream != null) + if (_stream != null) { - if (trackTextContent) + if (_trackTextContent) { _charEntityFallback.Reset(_textContentMarks, _lastMarkPos); // reset text content tracking @@ -845,12 +848,15 @@ namespace System.Xml } Debug.Assert(_textContentMarks[0] == 1); } - EncodeChars(1, bufPos, true); + EncodeChars(1, _bufPos, true); } else { - // Write text to TextWriter - writer.Write(<#= BufferName #>, 1, bufPos - 1); + if (_bufPos - 1 > 0) + { + // Write text to TextWriter + _writer.Write(<#= BufferName #>, 1, _bufPos - 1); + } } <# } #> } @@ -858,30 +864,30 @@ namespace System.Xml catch { // Future calls to flush (i.e. when Close() is called) don't attempt to write to stream - writeToNull = true; + _writeToNull = true; throw; } finally { // Move last buffer character to the beginning of the buffer (so that previous character can always be determined) - <#= BufferName #>[0] = <#= BufferName #>[bufPos - 1]; + <#= BufferName #>[0] = <#= BufferName #>[_bufPos - 1]; <# if (WriterType == RawTextWriterType.Utf8) { #> if (IsSurrogateByte(<#= BufferName #>[0])) { // Last character was the first byte in a surrogate encoding, so move last three // bytes of encoding to the beginning of the buffer. - <#= BufferName #>[1] = <#= BufferName #>[bufPos]; - <#= BufferName #>[2] = <#= BufferName #>[bufPos + 1]; - <#= BufferName #>[3] = <#= BufferName #>[bufPos + 2]; + <#= BufferName #>[1] = <#= BufferName #>[_bufPos]; + <#= BufferName #>[2] = <#= BufferName #>[_bufPos + 1]; + <#= BufferName #>[3] = <#= BufferName #>[_bufPos + 2]; } <# } #> // Reset buffer position - textPos = (textPos == bufPos) ? 1 : 0; - attrEndPos = (attrEndPos == bufPos) ? 1 : 0; - contentPos = 0; // Needs to be zero, since overwriting '>' character is no longer possible - cdataPos = 0; // Needs to be zero, since overwriting ']]>' characters is no longer possible - bufPos = 1; // Buffer position starts at 1, because we need to be able to safely step back -1 in case we need to + _textPos = (_textPos == _bufPos) ? 1 : 0; + _attrEndPos = (_attrEndPos == _bufPos) ? 1 : 0; + _contentPos = 0; // Needs to be zero, since overwriting '>' character is no longer possible + _cdataPos = 0; // Needs to be zero, since overwriting ']]>' characters is no longer possible + _bufPos = 1; // Buffer position starts at 1, because we need to be able to safely step back -1 in case we need to // close an empty element or in CDATA section detection of double ]; <#= BufferName #>[0] will always be 0 } } @@ -905,35 +911,35 @@ namespace System.Xml { _charEntityFallback.StartOffset = startOffset; } - encoder.Convert(<#= BufferName #>, startOffset, endOffset - startOffset, bufBytes, bufBytesUsed, bufBytes.Length - bufBytesUsed, false, out chEnc, out bEnc, out completed); + _encoder.Convert(<#= BufferName #>, startOffset, endOffset - startOffset, _bufBytes, _bufBytesUsed, _bufBytes.Length - _bufBytesUsed, false, out chEnc, out bEnc, out completed); startOffset += chEnc; - bufBytesUsed += bEnc; - if (bufBytesUsed >= (bufBytes.Length - 16)) + _bufBytesUsed += bEnc; + if (_bufBytesUsed >= (_bufBytes.Length - 16)) { - stream.Write(bufBytes, 0, bufBytesUsed); - bufBytesUsed = 0; + _stream.Write(_bufBytes, 0, _bufBytesUsed); + _bufBytesUsed = 0; } } - if (writeAllToStream && bufBytesUsed > 0) + if (writeAllToStream && _bufBytesUsed > 0) { - stream.Write(bufBytes, 0, bufBytesUsed); - bufBytesUsed = 0; + _stream.Write(_bufBytes, 0, _bufBytesUsed); + _bufBytesUsed = 0; } } private void FlushEncoder() { - Debug.Assert(bufPos == 1); - if (stream != null) + Debug.Assert(_bufPos == 1); + if (_stream != null) { int chEnc; int bEnc; bool completed; // decode no chars, just flush - encoder.Convert(<#= BufferName #>, 1, 0, bufBytes, 0, bufBytes.Length, true, out chEnc, out bEnc, out completed); + _encoder.Convert(<#= BufferName #>, 1, 0, _bufBytes, 0, _bufBytes.Length, true, out chEnc, out bEnc, out completed); if (bEnc != 0) { - stream.Write(bufBytes, 0, bEnc); + _stream.Write(_bufBytes, 0, bEnc); } } } @@ -945,21 +951,21 @@ namespace System.Xml { fixed (<#= BufferType #>* pDstBegin = <#= BufferName #>) { - <#= BufferType #>* pDst = pDstBegin + bufPos; + <#= BufferType #>* pDst = pDstBegin + _bufPos; int ch = 0; for (;;) { <#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } <# if (WriterType == RawTextWriterType.Utf8) { #> - while (pDst < pDstEnd && (xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch <= 0x7F)) + while (pDst < pDstEnd && (_xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch <= 0x7F)) <# } else { #> - while (pDst < pDstEnd && xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) + while (pDst < pDstEnd && _xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) <# } #> { *pDst = (<#= BufferType #>)ch; @@ -977,7 +983,7 @@ namespace System.Xml // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; @@ -1003,7 +1009,7 @@ namespace System.Xml pDst++; break; case (char)0x9: - if (newLineHandling == NewLineHandling.None) + if (_newLineHandling == NewLineHandling.None) { *pDst = (<#= BufferType #>)ch; pDst++; @@ -1015,7 +1021,7 @@ namespace System.Xml } break; case (char)0xD: - if (newLineHandling == NewLineHandling.None) + if (_newLineHandling == NewLineHandling.None) { *pDst = (<#= BufferType #>)ch; pDst++; @@ -1027,7 +1033,7 @@ namespace System.Xml } break; case (char)0xA: - if (newLineHandling == NewLineHandling.None) + if (_newLineHandling == NewLineHandling.None) { *pDst = (<#= BufferType #>)ch; pDst++; @@ -1044,7 +1050,7 @@ namespace System.Xml } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } } @@ -1054,21 +1060,21 @@ namespace System.Xml { fixed (<#= BufferType #>* pDstBegin = <#= BufferName #>) { - <#= BufferType #>* pDst = pDstBegin + bufPos; + <#= BufferType #>* pDst = pDstBegin + _bufPos; int ch = 0; for (;;) { <#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } <# if (WriterType == RawTextWriterType.Utf8) { #> - while (pDst < pDstEnd && (xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch <= 0x7F)) + while (pDst < pDstEnd && (_xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch <= 0x7F)) <# } else { #> - while (pDst < pDstEnd && xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) + while (pDst < pDstEnd && _xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) <# } #> { *pDst = (<#= BufferType #>)ch; @@ -1086,7 +1092,7 @@ namespace System.Xml // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; @@ -1111,7 +1117,7 @@ namespace System.Xml pDst++; break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { pDst = WriteNewLine(pDst); } @@ -1122,7 +1128,7 @@ namespace System.Xml } break; case (char)0xD: - switch (newLineHandling) + switch (_newLineHandling) { case NewLineHandling.Replace: // Replace "\r\n", or "\r" with NewLineChars @@ -1150,9 +1156,9 @@ namespace System.Xml } pSrc++; } - bufPos = (int)(pDst - pDstBegin); - textPos = bufPos; - contentPos = 0; + _bufPos = (int)(pDst - pDstBegin); + _textPos = _bufPos; + _contentPos = 0; } } @@ -1170,16 +1176,16 @@ namespace System.Xml { fixed (<#= BufferType #>* pDstBegin = <#= BufferName #>) { - <#= BufferType #>* pDst = pDstBegin + bufPos; + <#= BufferType #>* pDst = pDstBegin + _bufPos; char* pSrc = pSrcBegin; int ch = 0; for (;;) { <#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } <# if (WriterType == RawTextWriterType.Utf8) { #> @@ -1203,7 +1209,7 @@ namespace System.Xml // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; @@ -1212,7 +1218,7 @@ namespace System.Xml <#= EncodeChar(5, false) #> } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } } @@ -1221,21 +1227,21 @@ namespace System.Xml fixed (<#= BufferType #>* pDstBegin = <#= BufferName #>) { char* pSrc = pSrcBegin; - <#= BufferType #>* pDst = pDstBegin + bufPos; + <#= BufferType #>* pDst = pDstBegin + _bufPos; int ch = 0; for (;;) { <#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } <# if (WriterType == RawTextWriterType.Utf8) { #> - while (pDst < pDstEnd && (xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch <= 0x7F)) + while (pDst < pDstEnd && (_xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch <= 0x7F)) <# } else { #> - while (pDst < pDstEnd && xmlCharType.IsTextChar((char)(ch = *pSrc))) + while (pDst < pDstEnd && _xmlCharType.IsTextChar((char)(ch = *pSrc))) <# } #> { *pDst = (<#= BufferType #>)ch; @@ -1254,7 +1260,7 @@ namespace System.Xml // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; @@ -1271,7 +1277,7 @@ namespace System.Xml pDst++; break; case (char)0xD: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { // Normalize "\r\n", or "\r" to NewLineChars if (pSrc + 1 < pSrcEnd && pSrc[1] == '\n') @@ -1288,7 +1294,7 @@ namespace System.Xml } break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { pDst = WriteNewLine(pDst); } @@ -1304,7 +1310,7 @@ namespace System.Xml } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } } @@ -1312,7 +1318,7 @@ namespace System.Xml { if (text.Length == 0) { - if (bufPos >= bufLen) + if (_bufPos >= _bufLen) { FlushBuffer(); } @@ -1327,21 +1333,21 @@ namespace System.Xml char* pSrcEnd = pSrcBegin + text.Length; - <#= BufferType #>* pDst = pDstBegin + bufPos; + <#= BufferType #>* pDst = pDstBegin + _bufPos; int ch = 0; for (;;) { <#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } <# if (WriterType == RawTextWriterType.Utf8) { #> - while (pDst < pDstEnd && (xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch != stopChar && ch <= 0x7F)) + while (pDst < pDstEnd && (_xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch != stopChar && ch <= 0x7F)) <# } else { #> - while (pDst < pDstEnd && (xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch != stopChar)) + while (pDst < pDstEnd && (_xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch != stopChar)) <# } #> { *pDst = (<#= BufferType #>)ch; @@ -1360,7 +1366,7 @@ namespace System.Xml // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; @@ -1400,7 +1406,7 @@ namespace System.Xml pDst++; break; case (char)0xD: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { // Normalize "\r\n", or "\r" to NewLineChars if (pSrc + 1 < pSrcEnd && pSrc[1] == '\n') @@ -1417,7 +1423,7 @@ namespace System.Xml } break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { pDst = WriteNewLine(pDst); } @@ -1439,7 +1445,7 @@ namespace System.Xml } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } } @@ -1447,7 +1453,7 @@ namespace System.Xml { if (text.Length == 0) { - if (bufPos >= bufLen) + if (_bufPos >= _bufLen) { FlushBuffer(); } @@ -1464,21 +1470,21 @@ namespace System.Xml char* pSrcEnd = pSrcBegin + text.Length; - <#= BufferType #>* pDst = pDstBegin + bufPos; + <#= BufferType #>* pDst = pDstBegin + _bufPos; int ch = 0; for (;;) { <#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } <# if (WriterType == RawTextWriterType.Utf8) { #> - while (pDst < pDstEnd && (xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch != ']' && ch <= 0x7F)) + while (pDst < pDstEnd && (_xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch != ']' && ch <= 0x7F)) <# } else { #> - while (pDst < pDstEnd && (xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch != ']')) + while (pDst < pDstEnd && (_xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch != ']')) <# } #> { *pDst = (<#= BufferType #>)ch; @@ -1497,7 +1503,7 @@ namespace System.Xml // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); FlushBuffer(); pDst = pDstBegin + 1; continue; @@ -1507,7 +1513,7 @@ namespace System.Xml switch (ch) { case '>': - if (hadDoubleBracket && pDst[-1] == (<#= BufferType #>)']') + if (_hadDoubleBracket && pDst[-1] == (<#= BufferType #>)']') { // pDst[-1] will always correct - there is a padding character at <#= BufferName #>[0] // The characters "]]>" were found within the CData text pDst = RawEndCData(pDst); @@ -1519,17 +1525,17 @@ namespace System.Xml case ']': if (pDst[-1] == (<#= BufferType #>)']') { // pDst[-1] will always correct - there is a padding character at <#= BufferName #>[0] - hadDoubleBracket = true; + _hadDoubleBracket = true; } else { - hadDoubleBracket = false; + _hadDoubleBracket = false; } *pDst = (<#= BufferType #>)']'; pDst++; break; case (char)0xD: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { // Normalize "\r\n", or "\r" to NewLineChars if (pSrc + 1 < pSrcEnd && pSrc[1] == '\n') @@ -1546,7 +1552,7 @@ namespace System.Xml } break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { pDst = WriteNewLine(pDst); } @@ -1570,7 +1576,7 @@ namespace System.Xml } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } } @@ -1624,10 +1630,10 @@ namespace System.Xml private unsafe <#= BufferType #>* InvalidXmlChar(int ch, <#= BufferType #>* pDst, bool entitize) { - Debug.Assert(!xmlCharType.IsWhiteSpace((char)ch)); - Debug.Assert(!xmlCharType.IsAttributeValueChar((char)ch)); + Debug.Assert(!_xmlCharType.IsWhiteSpace((char)ch)); + Debug.Assert(!_xmlCharType.IsAttributeValueChar((char)ch)); - if (checkCharacters) + if (_checkCharacters) { // This method will never be called on surrogates, so it is ok to pass in '\0' to the CreateInvalidCharException throw XmlConvert.CreateInvalidCharException((char)ch, '\0'); @@ -1718,14 +1724,14 @@ namespace System.Xml <# if (WriterType == RawTextWriterType.Encoded) { #> protected void ChangeTextContentMark(bool value) { - Debug.Assert(inTextContent != value); - Debug.Assert(inTextContent || ((_lastMarkPos & 1) == 0)); - inTextContent = value; + Debug.Assert(_inTextContent != value); + Debug.Assert(_inTextContent || ((_lastMarkPos & 1) == 0)); + _inTextContent = value; if (_lastMarkPos + 1 == _textContentMarks.Length) { GrowTextContentMarks(); } - _textContentMarks[++_lastMarkPos] = bufPos; + _textContentMarks[++_lastMarkPos] = _bufPos; } private void GrowTextContentMarks() @@ -1741,10 +1747,10 @@ namespace System.Xml { fixed (<#= BufferType #>* pDstBegin = <#= BufferName #>) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); // Let RawText do the real work - RawText(newLineChars); - return pDstBegin + bufPos; + RawText(_newLineChars); + return pDstBegin + _bufPos; } } @@ -1882,7 +1888,7 @@ namespace System.Xml { if (allowOnlyWhitespace) { - if (!xmlCharType.IsOnlyWhitespace(chars)) + if (!_xmlCharType.IsOnlyWhitespace(chars)) { throw new ArgumentException(SR.Format(SR.Xml_IndentCharsNotWhitespace, propertyName)); } @@ -1892,7 +1898,7 @@ namespace System.Xml string error = null; for (int i = 0; i < chars.Length; i++) { - if (!xmlCharType.IsTextChar(chars[i])) + if (!_xmlCharType.IsTextChar(chars[i])) { switch (chars[i]) { @@ -1942,14 +1948,14 @@ namespace System.Xml // // Fields // - protected int indentLevel; - protected bool newLineOnAttributes; - protected string indentChars; + protected int _indentLevel; + protected bool _newLineOnAttributes; + protected string _indentChars; - protected bool mixedContent; + protected bool _mixedContent; private BitStack _mixedContentStack; - protected ConformanceLevel conformanceLevel = ConformanceLevel.Auto; + protected ConformanceLevel _conformanceLevel = ConformanceLevel.Auto; // // Constructors @@ -1978,8 +1984,8 @@ namespace System.Xml settings.ReadOnly = false; settings.Indent = true; - settings.IndentChars = indentChars; - settings.NewLineOnAttributes = newLineOnAttributes; + settings.IndentChars = _indentChars; + settings.NewLineOnAttributes = _newLineOnAttributes; settings.ReadOnly = true; return settings; @@ -1989,7 +1995,7 @@ namespace System.Xml public override void WriteDocType(string name, string pubid, string sysid, string subset) { // Add indentation - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { WriteIndent(); } @@ -2001,12 +2007,12 @@ namespace System.Xml Debug.Assert(localName != null && localName.Length != 0 && prefix != null && ns != null); // Add indentation - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { WriteIndent(); } - indentLevel++; - _mixedContentStack.PushBit(mixedContent); + _indentLevel++; + _mixedContentStack.PushBit(_mixedContent); base.WriteStartElement(prefix, localName, ns); } @@ -2014,16 +2020,16 @@ namespace System.Xml internal override void StartElementContent() { // If this is the root element and we're writing a document - // do not inherit the mixedContent flag into the root element. + // do not inherit the _mixedContent flag into the root element. // This is to allow for whitespace nodes on root level // without disabling indentation for the whole document. - if (indentLevel == 1 && conformanceLevel == ConformanceLevel.Document) + if (_indentLevel == 1 && _conformanceLevel == ConformanceLevel.Document) { - mixedContent = false; + _mixedContent = false; } else { - mixedContent = _mixedContentStack.PeekBit(); + _mixedContent = _mixedContentStack.PeekBit(); } base.StartElementContent(); } @@ -2031,22 +2037,22 @@ namespace System.Xml internal override void OnRootElement(ConformanceLevel currentConformanceLevel) { // Just remember the current conformance level - conformanceLevel = currentConformanceLevel; + _conformanceLevel = currentConformanceLevel; } internal override void WriteEndElement(string prefix, string localName, string ns) { // Add indentation - indentLevel--; - if (!mixedContent && base.contentPos != base.bufPos) + _indentLevel--; + if (!_mixedContent && base._contentPos != base._bufPos) { // There was content, so try to indent - if (base.textPos != base.bufPos) + if (base._textPos != base._bufPos) { WriteIndent(); } } - mixedContent = _mixedContentStack.PopBit(); + _mixedContent = _mixedContentStack.PopBit(); base.WriteEndElement(prefix, localName, ns); } @@ -2054,16 +2060,16 @@ namespace System.Xml internal override void WriteFullEndElement(string prefix, string localName, string ns) { // Add indentation - indentLevel--; - if (!mixedContent && base.contentPos != base.bufPos) + _indentLevel--; + if (!_mixedContent && base._contentPos != base._bufPos) { // There was content, so try to indent - if (base.textPos != base.bufPos) + if (base._textPos != base._bufPos) { WriteIndent(); } } - mixedContent = _mixedContentStack.PopBit(); + _mixedContent = _mixedContentStack.PopBit(); base.WriteFullEndElement(prefix, localName, ns); } @@ -2072,7 +2078,7 @@ namespace System.Xml public override void WriteStartAttribute(string prefix, string localName, string ns) { // Add indentation - if (newLineOnAttributes) + if (_newLineOnAttributes) { WriteIndent(); } @@ -2082,13 +2088,13 @@ namespace System.Xml public override void WriteCData(string text) { - mixedContent = true; + _mixedContent = true; base.WriteCData(text); } public override void WriteComment(string text) { - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { WriteIndent(); } @@ -2098,7 +2104,7 @@ namespace System.Xml public override void WriteProcessingInstruction(string target, string text) { - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { WriteIndent(); } @@ -2108,55 +2114,55 @@ namespace System.Xml public override void WriteEntityRef(string name) { - mixedContent = true; + _mixedContent = true; base.WriteEntityRef(name); } public override void WriteCharEntity(char ch) { - mixedContent = true; + _mixedContent = true; base.WriteCharEntity(ch); } public override void WriteSurrogateCharEntity(char lowChar, char highChar) { - mixedContent = true; + _mixedContent = true; base.WriteSurrogateCharEntity(lowChar, highChar); } public override void WriteWhitespace(string ws) { - mixedContent = true; + _mixedContent = true; base.WriteWhitespace(ws); } public override void WriteString(string text) { - mixedContent = true; + _mixedContent = true; base.WriteString(text); } public override void WriteChars(char[] buffer, int index, int count) { - mixedContent = true; + _mixedContent = true; base.WriteChars(buffer, index, count); } public override void WriteRaw(char[] buffer, int index, int count) { - mixedContent = true; + _mixedContent = true; base.WriteRaw(buffer, index, count); } public override void WriteRaw(string data) { - mixedContent = true; + _mixedContent = true; base.WriteRaw(data); } public override void WriteBase64(byte[] buffer, int index, int count) { - mixedContent = true; + _mixedContent = true; base.WriteBase64(buffer, index, count); } @@ -2165,25 +2171,25 @@ namespace System.Xml // private void Init(XmlWriterSettings settings) { - indentLevel = 0; - indentChars = settings.IndentChars; - newLineOnAttributes = settings.NewLineOnAttributes; + _indentLevel = 0; + _indentChars = settings.IndentChars; + _newLineOnAttributes = settings.NewLineOnAttributes; _mixedContentStack = new BitStack(); // check indent characters that they are valid XML characters - if (base.checkCharacters) + if (base._checkCharacters) { - if (newLineOnAttributes) + if (_newLineOnAttributes) { - base.ValidateContentChars(indentChars, "IndentChars", true); - base.ValidateContentChars(newLineChars, "NewLineChars", true); + base.ValidateContentChars(_indentChars, "IndentChars", true); + base.ValidateContentChars(_newLineChars, "NewLineChars", true); } else { - base.ValidateContentChars(indentChars, "IndentChars", false); - if (base.newLineHandling != NewLineHandling.Replace) + base.ValidateContentChars(_indentChars, "IndentChars", false); + if (base._newLineHandling != NewLineHandling.Replace) { - base.ValidateContentChars(newLineChars, "NewLineChars", false); + base.ValidateContentChars(_newLineChars, "NewLineChars", false); } } } @@ -2192,10 +2198,10 @@ namespace System.Xml // Add indentation to output. Write newline and then repeat IndentChars for each indent level. private void WriteIndent() { - RawText(base.newLineChars); - for (int i = indentLevel; i > 0; i--) + RawText(base._newLineChars); + for (int i = _indentLevel; i > 0; i--) { - RawText(indentChars); + RawText(_indentChars); } } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGeneratorAsync.ttinclude b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGeneratorAsync.ttinclude index 772a269eb1cee7..f5ce13f0951978 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGeneratorAsync.ttinclude +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGeneratorAsync.ttinclude @@ -37,7 +37,7 @@ namespace System.Xml { CheckAsyncCall(); // Output xml declaration only if user allows it and it was not already output - if (!omitXmlDeclaration && !autoXmlDeclaration) + if (!_omitXmlDeclaration && !_autoXmlDeclaration) {<# /* Code block is to squash extra line. */ #><#= SetTextContentMark(4, 1, false) #> await RawTextAsync(" + else if (_writer != null) + { + try + { + await _writer.FlushAsync().ConfigureAwait(false); + } + finally + { + try + { + if (_closeOutput) + { + await _writer.DisposeAsync().ConfigureAwait(false); + } + } + finally + { + _writer = null; + } + } + } +<# } #> + } + } + // Serialize the document type declaration. public override async Task WriteDocTypeAsync(string name, string pubid, string sysid, string subset) { @@ -94,27 +152,27 @@ namespace System.Xml { await RawTextAsync(sysid).ConfigureAwait(false); } - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'"'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'"'; } else if (sysid != null) { await RawTextAsync(" SYSTEM \"").ConfigureAwait(false); await RawTextAsync(sysid).ConfigureAwait(false); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'"'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'"'; } else { - <#= BufferName #>[bufPos++] = (<#= BufferType #>)' '; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)' '; } if (subset != null) { - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'['; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'['; await RawTextAsync(subset).ConfigureAwait(false); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)']'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)']'; } - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'>'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'>'; } // Serialize the beginning of an element start tag: "<#= SetTextContentMark(3, false) #> Task task; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'<'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'<'; if (prefix != null && prefix.Length != 0) { task = RawTextAsync(prefix, ":", localName); @@ -141,7 +199,7 @@ namespace System.Xml private void WriteStartElementAsync_SetAttEndPos() { - attrEndPos = bufPos; + _attrEndPos = _bufPos; } // Serialize an element end tag: "", if content was output. Otherwise, serialize @@ -154,11 +212,11 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - if (contentPos != bufPos) + if (_contentPos != _bufPos) { // Content has been output, so can't use shortcut syntax - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'<'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'/'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'<'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'/'; if (prefix != null && prefix.Length != 0) { @@ -172,10 +230,10 @@ namespace System.Xml else { // Use shortcut syntax; overwrite the already output '>' character - bufPos--; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)' '; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'/'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'>'; + _bufPos--; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)' '; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'/'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'>'; } return Task.CompletedTask; } @@ -189,8 +247,8 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'<'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'/'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'<'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'/'; if (prefix != null && prefix.Length != 0) { @@ -211,9 +269,9 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - if (attrEndPos == bufPos) + if (_attrEndPos == _bufPos) { - <#= BufferName #>[bufPos++] = (<#= BufferType #>)' '; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)' '; } Task task; if (prefix != null && prefix.Length > 0) @@ -229,9 +287,9 @@ namespace System.Xml private void WriteStartAttribute_SetInAttribute() { - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'='; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'"'; - inAttributeValue = true; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'='; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'"'; + _inAttributeValue = true; } // Serialize the end of an attribute value using double quotes: '"' @@ -241,9 +299,9 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'"'; - inAttributeValue = false; - attrEndPos = bufPos; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'"'; + _inAttributeValue = false; + _attrEndPos = _bufPos; return Task.CompletedTask; } @@ -273,11 +331,11 @@ namespace System.Xml { await RawTextAsync(" xmlns:").ConfigureAwait(false); await RawTextAsync(prefix).ConfigureAwait(false); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'='; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'"'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'='; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'"'; } - inAttributeValue = true;<# + _inAttributeValue = true;<# #><#= SetTextContentMark(3, true) #> } @@ -287,10 +345,10 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - inAttributeValue = false; + _inAttributeValue = false; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'"'; - attrEndPos = bufPos; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'"'; + _attrEndPos = _bufPos; return Task.CompletedTask; } @@ -304,34 +362,34 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - if (mergeCDataSections && bufPos == cdataPos) + if (_mergeCDataSections && _bufPos == _cdataPos) { // Merge adjacent cdata sections - overwrite the "]]>" characters - Debug.Assert(bufPos >= 4); - bufPos -= 3; + Debug.Assert(_bufPos >= 4); + _bufPos -= 3; } else { // Start a new cdata section - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'<'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'!'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'['; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'C'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'D'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'A'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'T'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'A'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'['; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'<'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'!'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'['; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'C'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'D'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'A'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'T'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'A'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'['; } await WriteCDataSectionAsync(text).ConfigureAwait(false); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)']'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)']'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'>'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)']'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)']'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'>'; - textPos = bufPos; - cdataPos = bufPos; + _textPos = _bufPos; + _cdataPos = _bufPos; } // Serialize a comment. @@ -342,16 +400,16 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'<'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'!'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'-'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'-'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'<'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'!'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'-'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'-'; await WriteCommentOrPiAsync(text, '-').ConfigureAwait(false); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'-'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'-'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'>'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'-'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'-'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'>'; } // Serialize a processing instruction. @@ -363,18 +421,18 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'<'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'?'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'<'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'?'; await RawTextAsync(name).ConfigureAwait(false); if (text.Length > 0) { - <#= BufferName #>[bufPos++] = (<#= BufferType #>)' '; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)' '; await WriteCommentOrPiAsync(text, '?').ConfigureAwait(false); } - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'?'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'>'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'?'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'>'; } // Serialize an entity reference. @@ -385,16 +443,16 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'&'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'&'; await RawTextAsync(name).ConfigureAwait(false); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)';'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)';'; - if (bufPos > bufLen) + if (_bufPos > _bufLen) { await FlushBufferAsync().ConfigureAwait(false); } - textPos = bufPos; + _textPos = _bufPos; } // Serialize a character entity reference. @@ -403,7 +461,7 @@ namespace System.Xml CheckAsyncCall(); string strVal = ((int)ch).ToString("X", NumberFormatInfo.InvariantInfo); - if (checkCharacters && !xmlCharType.IsCharData(ch)) + if (_checkCharacters && !_xmlCharType.IsCharData(ch)) { // we just have a single char, not a surrogate, therefore we have to pass in '\0' for the second char throw XmlConvert.CreateInvalidCharException(ch, '\0'); @@ -411,18 +469,18 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'&'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'#'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'x'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'&'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'#'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'x'; await RawTextAsync(strVal).ConfigureAwait(false); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)';'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)';'; - if (bufPos > bufLen) + if (_bufPos > _bufLen) { await FlushBufferAsync().ConfigureAwait(false); } - textPos = bufPos; + _textPos = _bufPos; } // Serialize a whitespace node. @@ -433,7 +491,7 @@ namespace System.Xml Debug.Assert(ws != null);<# #><#= SetTextContentMark(3, false) #> - if (inAttributeValue) + if (_inAttributeValue) { return WriteAttributeTextBlockAsync(ws); } @@ -451,7 +509,7 @@ namespace System.Xml Debug.Assert(text != null);<# #><#= SetTextContentMark(3, true) #> - if (inAttributeValue) + if (_inAttributeValue) { return WriteAttributeTextBlockAsync(text); } @@ -469,12 +527,12 @@ namespace System.Xml int surrogateChar = XmlCharType.CombineSurrogateChar(lowChar, highChar); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'&'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'#'; - <#= BufferName #>[bufPos++] = (<#= BufferType #>)'x'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'&'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'#'; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'x'; await RawTextAsync(surrogateChar.ToString("X", NumberFormatInfo.InvariantInfo)).ConfigureAwait(false); - <#= BufferName #>[bufPos++] = (<#= BufferType #>)';'; - textPos = bufPos; + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)';'; + _textPos = _bufPos; } // Serialize either attribute or element text using XML rules. @@ -489,7 +547,7 @@ namespace System.Xml #><#= SetTextContentMark(3, true) #> - if (inAttributeValue) + if (_inAttributeValue) { return WriteAttributeTextBlockAsync(buffer, index, count); } @@ -513,7 +571,7 @@ namespace System.Xml await WriteRawWithCharCheckingAsync(buffer, index, count).ConfigureAwait(false); - textPos = bufPos; + _textPos = _bufPos; } // Serialize raw data. @@ -527,7 +585,7 @@ namespace System.Xml await WriteRawWithCharCheckingAsync(data).ConfigureAwait(false); - textPos = bufPos; + _textPos = _bufPos; } // Flush all characters in the buffer to output and call Flush() on the output object. @@ -539,14 +597,14 @@ namespace System.Xml await FlushEncoderAsync().ConfigureAwait(false); <# } #> - if (stream != null) + if (_stream != null) { - await stream.FlushAsync().ConfigureAwait(false); + await _stream.FlushAsync().ConfigureAwait(false); } <# if (WriterType == RawTextWriterType.Encoded) { #> - else if (writer != null) + else if (_writer != null) { - await writer.FlushAsync().ConfigureAwait(false); + await _writer.FlushAsync().ConfigureAwait(false); } <# } #> } @@ -560,17 +618,20 @@ namespace System.Xml try { // Output all characters (except for previous characters stored at beginning of buffer) - if (!writeToNull) + if (!_writeToNull) { <# if (WriterType == RawTextWriterType.Utf8) { #> - Debug.Assert(stream != null); - await stream.WriteAsync(bufBytes, 1, bufPos - 1).ConfigureAwait(false); + if (_bufPos - 1 > 0) + { + Debug.Assert(_stream != null); + await _stream.WriteAsync(_bufBytes.AsMemory(1, _bufPos - 1)).ConfigureAwait(false); + } <# } else { #> - Debug.Assert(stream != null || writer != null); + Debug.Assert(_stream != null || _writer != null); - if (stream != null) + if (_stream != null) { - if (trackTextContent) + if (_trackTextContent) { _charEntityFallback.Reset(_textContentMarks, _lastMarkPos); // reset text content tracking @@ -588,12 +649,15 @@ namespace System.Xml } Debug.Assert(_textContentMarks[0] == 1); } - await EncodeCharsAsync(1, bufPos, true).ConfigureAwait(false); + await EncodeCharsAsync(1, _bufPos, true).ConfigureAwait(false); } else { - // Write text to TextWriter - await writer.WriteAsync(<#= BufferName #>, 1, bufPos - 1).ConfigureAwait(false); + if (_bufPos - 1 > 0) + { + // Write text to TextWriter + await _writer.WriteAsync(<#= BufferName #>.AsMemory(1, _bufPos - 1)).ConfigureAwait(false); + } } <# } #> } @@ -601,31 +665,31 @@ namespace System.Xml catch { // Future calls to flush (i.e. when Close() is called) don't attempt to write to stream - writeToNull = true; + _writeToNull = true; throw; } finally { // Move last buffer character to the beginning of the buffer (so that previous character can always be determined) - <#= BufferName #>[0] = <#= BufferName #>[bufPos - 1]; + <#= BufferName #>[0] = <#= BufferName #>[_bufPos - 1]; <# if (WriterType == RawTextWriterType.Utf8) { #> - if (IsSurrogateByte(bufBytes[0])) + if (IsSurrogateByte(_bufBytes[0])) { // Last character was the first byte in a surrogate encoding, so move last three // bytes of encoding to the beginning of the buffer. - bufBytes[1] = bufBytes[bufPos]; - bufBytes[2] = bufBytes[bufPos + 1]; - bufBytes[3] = bufBytes[bufPos + 2]; + _bufBytes[1] = _bufBytes[_bufPos]; + _bufBytes[2] = _bufBytes[_bufPos + 1]; + _bufBytes[3] = _bufBytes[_bufPos + 2]; } <# } #> // Reset buffer position - textPos = (textPos == bufPos) ? 1 : 0; - attrEndPos = (attrEndPos == bufPos) ? 1 : 0; - contentPos = 0; // Needs to be zero, since overwriting '>' character is no longer possible - cdataPos = 0; // Needs to be zero, since overwriting ']]>' characters is no longer possible - bufPos = 1; // Buffer position starts at 1, because we need to be able to safely step back -1 in case we need to + _textPos = (_textPos == _bufPos) ? 1 : 0; + _attrEndPos = (_attrEndPos == _bufPos) ? 1 : 0; + _contentPos = 0; // Needs to be zero, since overwriting '>' character is no longer possible + _cdataPos = 0; // Needs to be zero, since overwriting ']]>' characters is no longer possible + _bufPos = 1; // Buffer position starts at 1, because we need to be able to safely step back -1 in case we need to // close an empty element or in CDATA section detection of double ]; _BUFFER[0] will always be 0 } } @@ -642,35 +706,35 @@ namespace System.Xml { _charEntityFallback.StartOffset = startOffset; } - encoder.Convert(<#= BufferName #>, startOffset, endOffset - startOffset, bufBytes, bufBytesUsed, bufBytes.Length - bufBytesUsed, false, out chEnc, out bEnc, out completed); + _encoder.Convert(<#= BufferName #>, startOffset, endOffset - startOffset, _bufBytes, _bufBytesUsed, _bufBytes.Length - _bufBytesUsed, false, out chEnc, out bEnc, out completed); startOffset += chEnc; - bufBytesUsed += bEnc; - if (bufBytesUsed >= (bufBytes.Length - 16)) + _bufBytesUsed += bEnc; + if (_bufBytesUsed >= (_bufBytes.Length - 16)) { - await stream.WriteAsync(bufBytes, 0, bufBytesUsed).ConfigureAwait(false); - bufBytesUsed = 0; + await _stream.WriteAsync(_bufBytes.AsMemory(0, _bufBytesUsed)).ConfigureAwait(false); + _bufBytesUsed = 0; } } - if (writeAllToStream && bufBytesUsed > 0) + if (writeAllToStream && _bufBytesUsed > 0) { - await stream.WriteAsync(bufBytes, 0, bufBytesUsed).ConfigureAwait(false); - bufBytesUsed = 0; + await _stream.WriteAsync(_bufBytes.AsMemory(0, _bufBytesUsed)).ConfigureAwait(false); + _bufBytesUsed = 0; } } private Task FlushEncoderAsync() { - Debug.Assert(bufPos == 1); - if (stream != null) + Debug.Assert(_bufPos == 1); + if (_stream != null) { int chEnc; int bEnc; bool completed; // decode no chars, just flush - encoder.Convert(<#= BufferName #>, 1, 0, bufBytes, 0, bufBytes.Length, true, out chEnc, out bEnc, out completed); + _encoder.Convert(<#= BufferName #>, 1, 0, _bufBytes, 0, _bufBytes.Length, true, out chEnc, out bEnc, out completed); if (bEnc != 0) { - return stream.WriteAsync(bufBytes, 0, bEnc); + return _stream.WriteAsync(_bufBytes, 0, bEnc); } } @@ -686,21 +750,21 @@ namespace System.Xml fixed (<#= BufferType #>* pDstBegin = <#= BufferName #>) { - <#= BufferType #>* pDst = pDstBegin + bufPos; + <#= BufferType #>* pDst = pDstBegin + _bufPos; int ch = 0; - for (;;) + while (true) { <#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } <# if (WriterType == RawTextWriterType.Utf8) { #> - while (pDst < pDstEnd && (xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch <= 0x7F)) + while (pDst < pDstEnd && (_xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch <= 0x7F)) <# } else { #> - while (pDst < pDstEnd && xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) + while (pDst < pDstEnd && _xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) <# } #> { *pDst = (<#= BufferType #>)ch; @@ -718,7 +782,7 @@ namespace System.Xml // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); return (int)(pSrc - pRaw); } @@ -742,7 +806,7 @@ namespace System.Xml pDst++; break; case (char)0x9: - if (newLineHandling == NewLineHandling.None) + if (_newLineHandling == NewLineHandling.None) { *pDst = (<#= BufferType #>)ch; pDst++; @@ -754,7 +818,7 @@ namespace System.Xml } break; case (char)0xD: - if (newLineHandling == NewLineHandling.None) + if (_newLineHandling == NewLineHandling.None) { *pDst = (<#= BufferType #>)ch; pDst++; @@ -766,7 +830,7 @@ namespace System.Xml } break; case (char)0xA: - if (newLineHandling == NewLineHandling.None) + if (_newLineHandling == NewLineHandling.None) { *pDst = (<#= BufferType #>)ch; pDst++; @@ -783,7 +847,7 @@ namespace System.Xml } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } return -1; @@ -876,21 +940,21 @@ namespace System.Xml fixed (<#= BufferType #>* pDstBegin = <#= BufferName #>) { - <#= BufferType #>* pDst = pDstBegin + bufPos; + <#= BufferType #>* pDst = pDstBegin + _bufPos; int ch = 0; - for (;;) + while (true) { <#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } <# if (WriterType == RawTextWriterType.Utf8) { #> - while (pDst < pDstEnd && (xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch <= 0x7F)) + while (pDst < pDstEnd && (_xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch <= 0x7F)) <# } else { #> - while (pDst < pDstEnd && xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) + while (pDst < pDstEnd && _xmlCharType.IsAttributeValueChar((char)(ch = *pSrc))) <# } #> { *pDst = (<#= BufferType #>)ch; @@ -908,7 +972,7 @@ namespace System.Xml // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); return (int)(pSrc - pRaw); } @@ -931,9 +995,9 @@ namespace System.Xml pDst++; break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); } @@ -944,7 +1008,7 @@ namespace System.Xml } break; case (char)0xD: - switch (newLineHandling) + switch (_newLineHandling) { case NewLineHandling.Replace: // Replace "\r\n", or "\r" with NewLineChars @@ -953,7 +1017,7 @@ namespace System.Xml pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); @@ -973,9 +1037,9 @@ namespace System.Xml } pSrc++; } - bufPos = (int)(pDst - pDstBegin); - textPos = bufPos; - contentPos = 0; + _bufPos = (int)(pDst - pDstBegin); + _textPos = _bufPos; + _contentPos = 0; } return -1; @@ -986,7 +1050,7 @@ namespace System.Xml needWriteNewLine = false; if (count == 0) { - contentPos = 0; + _contentPos = 0; return -1; } fixed (char* pSrc = &chars[index]) @@ -1002,7 +1066,7 @@ namespace System.Xml needWriteNewLine = false; if (count == 0) { - contentPos = 0; + _contentPos = 0; return -1; } fixed (char* pSrc = text) @@ -1027,7 +1091,7 @@ namespace System.Xml if (needWriteNewLine) { //hit WriteNewLine - await RawTextAsync(newLineChars).ConfigureAwait(false); + await RawTextAsync(_newLineChars).ConfigureAwait(false); curIndex++; leftCount--; } @@ -1067,7 +1131,7 @@ namespace System.Xml if (newLine) { - await RawTextAsync(newLineChars).ConfigureAwait(false); + await RawTextAsync(_newLineChars).ConfigureAwait(false); curIndex++; leftCount--; } @@ -1084,7 +1148,7 @@ namespace System.Xml if (needWriteNewLine) { //hit WriteNewLine - await RawTextAsync(newLineChars).ConfigureAwait(false); + await RawTextAsync(_newLineChars).ConfigureAwait(false); curIndex++; leftCount--; } @@ -1101,16 +1165,16 @@ namespace System.Xml fixed (<#= BufferType #>* pDstBegin = <#= BufferName #>) { - <#= BufferType #>* pDst = pDstBegin + bufPos; + <#= BufferType #>* pDst = pDstBegin + _bufPos; char* pSrc = pSrcBegin; int ch = 0; - for (;;) + while (true) { <#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } <# if (WriterType == RawTextWriterType.Utf8) { #> @@ -1134,14 +1198,14 @@ namespace System.Xml // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); return (int)(pSrc - pRaw); } <#= EncodeChar(5, false) #> } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } return -1; @@ -1263,21 +1327,21 @@ namespace System.Xml fixed (<#= BufferType #>* pDstBegin = <#= BufferName #>) { char* pSrc = pSrcBegin; - <#= BufferType #>* pDst = pDstBegin + bufPos; + <#= BufferType #>* pDst = pDstBegin + _bufPos; int ch = 0; - for (;;) + while (true) { <#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } <# if (WriterType == RawTextWriterType.Utf8) { #> - while (pDst < pDstEnd && (xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch <= 0x7F)) + while (pDst < pDstEnd && (_xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch <= 0x7F)) <# } else { #> - while (pDst < pDstEnd && xmlCharType.IsTextChar((char)(ch = *pSrc))) + while (pDst < pDstEnd && _xmlCharType.IsTextChar((char)(ch = *pSrc))) <# } #> { *pDst = (<#= BufferType #>)ch; @@ -1296,7 +1360,7 @@ namespace System.Xml // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); return (int)(pSrc - pRaw); } @@ -1311,7 +1375,7 @@ namespace System.Xml pDst++; break; case (char)0xD: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { // Normalize "\r\n", or "\r" to NewLineChars if (pSrc + 1 < pSrcEnd && pSrc[1] == '\n') @@ -1319,7 +1383,7 @@ namespace System.Xml pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); } @@ -1330,9 +1394,9 @@ namespace System.Xml } break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); } @@ -1348,7 +1412,7 @@ namespace System.Xml } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } return -1; @@ -1397,7 +1461,7 @@ namespace System.Xml leftCount -= writeLen; if (needWriteNewLine) { - await RawTextAsync(newLineChars).ConfigureAwait(false); + await RawTextAsync(_newLineChars).ConfigureAwait(false); curIndex++; leftCount--; } @@ -1421,7 +1485,7 @@ namespace System.Xml leftCount -= writeLen; if (needWriteNewLine) { - await RawTextAsync(newLineChars).ConfigureAwait(false); + await RawTextAsync(_newLineChars).ConfigureAwait(false); curIndex++; leftCount--; } @@ -1451,21 +1515,21 @@ namespace System.Xml char* pSrcEnd = pSrcBegin + count; - <#= BufferType #>* pDst = pDstBegin + bufPos; + <#= BufferType #>* pDst = pDstBegin + _bufPos; int ch = 0; - for (;;) + while (true) { <#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } <# if (WriterType == RawTextWriterType.Utf8) { #> - while (pDst < pDstEnd && (xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch != stopChar && ch <= 0x7F)) + while (pDst < pDstEnd && (_xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch != stopChar && ch <= 0x7F)) <# } else { #> - while (pDst < pDstEnd && (xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch != stopChar)) + while (pDst < pDstEnd && (_xmlCharType.IsTextChar((char)(ch = *pSrc)) && ch != stopChar)) <# } #> { *pDst = (<#= BufferType #>)ch; @@ -1484,7 +1548,7 @@ namespace System.Xml // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); return (int)(pSrc - pRaw); } @@ -1522,7 +1586,7 @@ namespace System.Xml pDst++; break; case (char)0xD: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { // Normalize "\r\n", or "\r" to NewLineChars if (pSrc + 1 < pSrcEnd && pSrc[1] == '\n') @@ -1530,7 +1594,7 @@ namespace System.Xml pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); } @@ -1541,9 +1605,9 @@ namespace System.Xml } break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); } @@ -1565,7 +1629,7 @@ namespace System.Xml } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } return -1; @@ -1576,7 +1640,7 @@ namespace System.Xml { if (text.Length == 0) { - if (bufPos >= bufLen) + if (_bufPos >= _bufLen) { await FlushBufferAsync().ConfigureAwait(false); } @@ -1594,7 +1658,7 @@ namespace System.Xml leftCount -= writeLen; if (needWriteNewLine) { - await RawTextAsync(newLineChars).ConfigureAwait(false); + await RawTextAsync(_newLineChars).ConfigureAwait(false); curIndex++; leftCount--; } @@ -1627,21 +1691,21 @@ namespace System.Xml char* pRaw = pSrc; - <#= BufferType #>* pDst = pDstBegin + bufPos; + <#= BufferType #>* pDst = pDstBegin + _bufPos; int ch = 0; - for (;;) + while (true) { <#= BufferType #>* pDstEnd = pDst + (pSrcEnd - pSrc); - if (pDstEnd > pDstBegin + bufLen) + if (pDstEnd > pDstBegin + _bufLen) { - pDstEnd = pDstBegin + bufLen; + pDstEnd = pDstBegin + _bufLen; } <# if (WriterType == RawTextWriterType.Utf8) { #> - while (pDst < pDstEnd && (xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch != ']' && ch <= 0x7F)) + while (pDst < pDstEnd && (_xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch != ']' && ch <= 0x7F)) <# } else { #> - while (pDst < pDstEnd && (xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch != ']')) + while (pDst < pDstEnd && (_xmlCharType.IsAttributeValueChar((char)(ch = *pSrc)) && ch != ']')) <# } #> { *pDst = (<#= BufferType #>)ch; @@ -1660,7 +1724,7 @@ namespace System.Xml // end of buffer if (pDst >= pDstEnd) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); return (int)(pSrc - pRaw); } @@ -1668,7 +1732,7 @@ namespace System.Xml switch (ch) { case '>': - if (hadDoubleBracket && pDst[-1] == (<#= BufferType #>)']') + if (_hadDoubleBracket && pDst[-1] == (<#= BufferType #>)']') { // pDst[-1] will always correct - there is a padding character at _BUFFER[0] // The characters "]]>" were found within the CData text pDst = RawEndCData(pDst); @@ -1680,17 +1744,17 @@ namespace System.Xml case ']': if (pDst[-1] == (<#= BufferType #>)']') { // pDst[-1] will always correct - there is a padding character at _BUFFER[0] - hadDoubleBracket = true; + _hadDoubleBracket = true; } else { - hadDoubleBracket = false; + _hadDoubleBracket = false; } *pDst = (<#= BufferType #>)']'; pDst++; break; case (char)0xD: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { // Normalize "\r\n", or "\r" to NewLineChars if (pSrc + 1 < pSrcEnd && pSrc[1] == '\n') @@ -1698,7 +1762,7 @@ namespace System.Xml pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); } @@ -1709,9 +1773,9 @@ namespace System.Xml } break; case (char)0xA: - if (newLineHandling == NewLineHandling.Replace) + if (_newLineHandling == NewLineHandling.Replace) { - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); needWriteNewLine = true; return (int)(pSrc - pRaw); } @@ -1735,7 +1799,7 @@ namespace System.Xml } pSrc++; } - bufPos = (int)(pDst - pDstBegin); + _bufPos = (int)(pDst - pDstBegin); } return -1; @@ -1746,7 +1810,7 @@ namespace System.Xml { if (text.Length == 0) { - if (bufPos >= bufLen) + if (_bufPos >= _bufLen) { await FlushBufferAsync().ConfigureAwait(false); } @@ -1764,7 +1828,7 @@ namespace System.Xml leftCount -= writeLen; if (needWriteNewLine) { - await RawTextAsync(newLineChars).ConfigureAwait(false); + await RawTextAsync(_newLineChars).ConfigureAwait(false); curIndex++; leftCount--; } @@ -1783,7 +1847,7 @@ namespace System.Xml { CheckAsyncCall(); // Add indentation - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { await WriteIndentAsync().ConfigureAwait(false); } @@ -1796,12 +1860,12 @@ namespace System.Xml Debug.Assert(localName != null && localName.Length != 0 && prefix != null && ns != null); // Add indentation - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { await WriteIndentAsync().ConfigureAwait(false); } - indentLevel++; - _mixedContentStack.PushBit(mixedContent); + _indentLevel++; + _mixedContentStack.PushBit(_mixedContent); await base.WriteStartElementAsync(prefix, localName, ns).ConfigureAwait(false); } @@ -1810,16 +1874,16 @@ namespace System.Xml { CheckAsyncCall(); // Add indentation - indentLevel--; - if (!mixedContent && base.contentPos != base.bufPos) + _indentLevel--; + if (!_mixedContent && base._contentPos != base._bufPos) { // There was content, so try to indent - if (base.textPos != base.bufPos) + if (base._textPos != base._bufPos) { await WriteIndentAsync().ConfigureAwait(false); } } - mixedContent = _mixedContentStack.PopBit(); + _mixedContent = _mixedContentStack.PopBit(); await base.WriteEndElementAsync(prefix, localName, ns).ConfigureAwait(false); } @@ -1828,16 +1892,16 @@ namespace System.Xml { CheckAsyncCall(); // Add indentation - indentLevel--; - if (!mixedContent && base.contentPos != base.bufPos) + _indentLevel--; + if (!_mixedContent && base._contentPos != base._bufPos) { // There was content, so try to indent - if (base.textPos != base.bufPos) + if (base._textPos != base._bufPos) { await WriteIndentAsync().ConfigureAwait(false); } } - mixedContent = _mixedContentStack.PopBit(); + _mixedContent = _mixedContentStack.PopBit(); await base.WriteFullEndElementAsync(prefix, localName, ns).ConfigureAwait(false); } @@ -1847,7 +1911,7 @@ namespace System.Xml { CheckAsyncCall(); // Add indentation - if (newLineOnAttributes) + if (_newLineOnAttributes) { await WriteIndentAsync().ConfigureAwait(false); } @@ -1858,14 +1922,14 @@ namespace System.Xml public override Task WriteCDataAsync(string text) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteCDataAsync(text); } public override async Task WriteCommentAsync(string text) { CheckAsyncCall(); - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { await WriteIndentAsync().ConfigureAwait(false); } @@ -1876,7 +1940,7 @@ namespace System.Xml public override async Task WriteProcessingInstructionAsync(string target, string text) { CheckAsyncCall(); - if (!mixedContent && base.textPos != base.bufPos) + if (!_mixedContent && base._textPos != base._bufPos) { await WriteIndentAsync().ConfigureAwait(false); } @@ -1887,63 +1951,63 @@ namespace System.Xml public override Task WriteEntityRefAsync(string name) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteEntityRefAsync(name); } public override Task WriteCharEntityAsync(char ch) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteCharEntityAsync(ch); } public override Task WriteSurrogateCharEntityAsync(char lowChar, char highChar) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteSurrogateCharEntityAsync(lowChar, highChar); } public override Task WriteWhitespaceAsync(string ws) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteWhitespaceAsync(ws); } public override Task WriteStringAsync(string text) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteStringAsync(text); } public override Task WriteCharsAsync(char[] buffer, int index, int count) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteCharsAsync(buffer, index, count); } public override Task WriteRawAsync(char[] buffer, int index, int count) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteRawAsync(buffer, index, count); } public override Task WriteRawAsync(string data) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteRawAsync(data); } public override Task WriteBase64Async(byte[] buffer, int index, int count) { CheckAsyncCall(); - mixedContent = true; + _mixedContent = true; return base.WriteBase64Async(buffer, index, count); } @@ -1951,10 +2015,10 @@ namespace System.Xml private async Task WriteIndentAsync() { CheckAsyncCall(); - await RawTextAsync(base.newLineChars).ConfigureAwait(false); - for (int i = indentLevel; i > 0; i--) + await RawTextAsync(base._newLineChars).ConfigureAwait(false); + for (int i = _indentLevel; i > 0; i--) { - await RawTextAsync(indentChars).ConfigureAwait(false); + await RawTextAsync(_indentChars).ConfigureAwait(false); } } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawWriter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawWriter.cs index 952c3d2348e999..e9d8937b349131 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawWriter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawWriter.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.IO; using System.Diagnostics; @@ -43,10 +44,10 @@ internal abstract partial class XmlRawWriter : XmlWriter // Fields // // base64 converter - protected XmlRawWriterBase64Encoder base64Encoder; + protected XmlRawWriterBase64Encoder? _base64Encoder; // namespace resolver - protected IXmlNamespaceResolver resolver; + protected IXmlNamespaceResolver? _resolver; // // XmlWriter implementation @@ -68,7 +69,7 @@ public override void WriteEndDocument() throw new InvalidOperationException(SR.Xml_InvalidOperation); } - public override void WriteDocType(string name, string pubid, string sysid, string subset) + public override void WriteDocType(string name, string? pubid, string? sysid, string? subset) { } @@ -87,12 +88,13 @@ public override void WriteFullEndElement() // By default, convert base64 value to string and call WriteString. public override void WriteBase64(byte[] buffer, int index, int count) { - if (base64Encoder == null) + if (_base64Encoder == null) { - base64Encoder = new XmlRawWriterBase64Encoder(this); + _base64Encoder = new XmlRawWriterBase64Encoder(this); } + // Encode will call WriteRaw to write out the encoded characters - base64Encoder.Encode(buffer, index, count); + _base64Encoder.Encode(buffer, index, count); } // Raw writers do not have to keep track of namespaces. @@ -135,13 +137,13 @@ public override void WriteName(string name) } // Raw writers do not have to verify QName values. - public override void WriteQualifiedName(string localName, string ns) + public override void WriteQualifiedName(string localName, string? ns) { throw new InvalidOperationException(SR.Xml_InvalidOperation); } // Forward call to WriteString(string). - public override void WriteCData(string text) + public override void WriteCData(string? text) { WriteString(text); } @@ -184,17 +186,18 @@ public override void WriteRaw(string data) } // Override in order to handle Xml simple typed values and to pass resolver for QName values - public override void WriteValue(object value) + public override void WriteValue(object? value) { if (value == null) { throw new ArgumentNullException(nameof(value)); } - WriteString(XmlUntypedConverter.Untyped.ToString(value, resolver)); + + WriteString(XmlUntypedConverter.Untyped.ToString(value, _resolver)); } // Override in order to handle Xml simple typed values and to pass resolver for QName values - public override void WriteValue(string value) + public override void WriteValue(string? value) { WriteString(value); } @@ -227,15 +230,15 @@ public override void WriteNode(System.Xml.XPath.XPathNavigator navigator, bool d // // Get and set the namespace resolver that's used by this RawWriter to resolve prefixes. - internal virtual IXmlNamespaceResolver NamespaceResolver + internal virtual IXmlNamespaceResolver? NamespaceResolver { get { - return resolver; + return _resolver; } set { - resolver = value; + _resolver = value; } } @@ -275,6 +278,7 @@ internal virtual void WriteQualifiedName(string prefix, string localName, string WriteString(prefix); WriteString(":"); } + WriteString(localName); } @@ -311,7 +315,8 @@ internal virtual void WriteEndNamespaceDeclaration() internal virtual void WriteEndBase64() { // The Flush will call WriteRaw to write out the rest of the encoded characters - base64Encoder.Flush(); + Debug.Assert(_base64Encoder != null); + _base64Encoder.Flush(); } internal virtual void Close(WriteState currentState) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawWriterAsync.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawWriterAsync.cs index 77ebbf5034a94c..c668e07932fb7d 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawWriterAsync.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawWriterAsync.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.IO; using System.Diagnostics; @@ -60,7 +61,7 @@ public override Task WriteEndDocumentAsync() throw new InvalidOperationException(SR.Xml_InvalidOperation); } - public override Task WriteDocTypeAsync(string name, string pubid, string sysid, string subset) + public override Task WriteDocTypeAsync(string name, string? pubid, string? sysid, string subset) { return Task.CompletedTask; } @@ -80,12 +81,12 @@ public override Task WriteFullEndElementAsync() // By default, convert base64 value to string and call WriteString. public override Task WriteBase64Async(byte[] buffer, int index, int count) { - if (base64Encoder == null) + if (_base64Encoder == null) { - base64Encoder = new XmlRawWriterBase64Encoder(this); + _base64Encoder = new XmlRawWriterBase64Encoder(this); } // Encode will call WriteRaw to write out the encoded characters - return base64Encoder.EncodeAsync(buffer, index, count); + return _base64Encoder.EncodeAsync(buffer, index, count); } // Raw writers do not have to verify NmToken values. @@ -101,7 +102,7 @@ public override Task WriteNameAsync(string name) } // Raw writers do not have to verify QName values. - public override Task WriteQualifiedNameAsync(string localName, string ns) + public override Task WriteQualifiedNameAsync(string localName, string? ns) { throw new InvalidOperationException(SR.Xml_InvalidOperation); } @@ -200,6 +201,7 @@ internal virtual async Task WriteQualifiedNameAsync(string prefix, string localN await WriteStringAsync(prefix).ConfigureAwait(false); await WriteStringAsync(":").ConfigureAwait(false); } + await WriteStringAsync(localName).ConfigureAwait(false); } @@ -224,7 +226,13 @@ internal virtual Task WriteEndNamespaceDeclarationAsync() internal virtual Task WriteEndBase64Async() { // The Flush will call WriteRaw to write out the rest of the encoded characters - return base64Encoder.FlushAsync(); + Debug.Assert(_base64Encoder != null); + return _base64Encoder.FlushAsync(); + } + + internal virtual ValueTask DisposeAsyncCore(WriteState currentState) + { + return DisposeAsyncCore(); } } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReader.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReader.cs index 8809d5ffd4a8ce..dfbf9cce8a4213 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReader.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReader.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Collections; using System.Diagnostics; using System.Globalization; @@ -88,7 +89,7 @@ public abstract partial class XmlReader : IDisposable internal const int AsyncBufferSize = 64 * 1024; //64KB // Settings - public virtual XmlReaderSettings Settings + public virtual XmlReaderSettings? Settings { get { @@ -141,7 +142,7 @@ public virtual bool HasValue public abstract int Depth { get; } // Gets the base URI of the current node. - public abstract string BaseURI { get; } + public abstract string? BaseURI { get; } // Gets a value indicating whether the current node is an empty element (for example, ). public abstract bool IsEmptyElement { get; } @@ -184,7 +185,7 @@ public virtual string XmlLang } // returns the schema info interface of the reader - public virtual IXmlSchemaInfo SchemaInfo + public virtual IXmlSchemaInfo? SchemaInfo { get { @@ -220,6 +221,7 @@ public virtual bool ReadContentAsBoolean() { throw CreateReadContentAsException(nameof(ReadContentAsBoolean)); } + try { return XmlConvert.ToBoolean(InternalReadContentAsString()); @@ -238,6 +240,7 @@ public virtual DateTime ReadContentAsDateTime() { throw CreateReadContentAsException(nameof(ReadContentAsDateTime)); } + try { return XmlConvert.ToDateTime(InternalReadContentAsString(), XmlDateTimeSerializationMode.RoundtripKind); @@ -256,6 +259,7 @@ public virtual DateTimeOffset ReadContentAsDateTimeOffset() { throw CreateReadContentAsException(nameof(ReadContentAsDateTimeOffset)); } + try { return XmlConvert.ToDateTimeOffset(InternalReadContentAsString()); @@ -274,6 +278,7 @@ public virtual double ReadContentAsDouble() { throw CreateReadContentAsException(nameof(ReadContentAsDouble)); } + try { return XmlConvert.ToDouble(InternalReadContentAsString()); @@ -292,6 +297,7 @@ public virtual float ReadContentAsFloat() { throw CreateReadContentAsException(nameof(ReadContentAsFloat)); } + try { return XmlConvert.ToSingle(InternalReadContentAsString()); @@ -310,6 +316,7 @@ public virtual decimal ReadContentAsDecimal() { throw CreateReadContentAsException(nameof(ReadContentAsDecimal)); } + try { return XmlConvert.ToDecimal(InternalReadContentAsString()); @@ -328,6 +335,7 @@ public virtual int ReadContentAsInt() { throw CreateReadContentAsException(nameof(ReadContentAsInt)); } + try { return XmlConvert.ToInt32(InternalReadContentAsString()); @@ -346,6 +354,7 @@ public virtual long ReadContentAsLong() { throw CreateReadContentAsException(nameof(ReadContentAsLong)); } + try { return XmlConvert.ToInt64(InternalReadContentAsString()); @@ -364,6 +373,7 @@ public virtual string ReadContentAsString() { throw CreateReadContentAsException(nameof(ReadContentAsString)); } + return InternalReadContentAsString(); } @@ -407,6 +417,7 @@ public virtual object ReadElementContentAsObject() FinishReadElementContentAsXxx(); return value; } + return string.Empty; } @@ -426,6 +437,7 @@ public virtual bool ReadElementContentAsBoolean() FinishReadElementContentAsXxx(); return value; } + return XmlConvert.ToBoolean(string.Empty); } @@ -445,6 +457,7 @@ public virtual DateTime ReadElementContentAsDateTime() FinishReadElementContentAsXxx(); return value; } + return XmlConvert.ToDateTime(string.Empty, XmlDateTimeSerializationMode.RoundtripKind); } @@ -465,6 +478,7 @@ public virtual double ReadElementContentAsDouble() FinishReadElementContentAsXxx(); return value; } + return XmlConvert.ToDouble(string.Empty); } @@ -485,6 +499,7 @@ public virtual float ReadElementContentAsFloat() FinishReadElementContentAsXxx(); return value; } + return XmlConvert.ToSingle(string.Empty); } @@ -565,6 +580,7 @@ public virtual string ReadElementContentAsString() FinishReadElementContentAsXxx(); return value; } + return string.Empty; } @@ -585,6 +601,7 @@ public virtual object ReadElementContentAs(Type returnType, IXmlNamespaceResolve FinishReadElementContentAsXxx(); return value; } + return (returnType == typeof(string)) ? string.Empty : XmlUntypedStringConverter.Instance.FromString(string.Empty, returnType, namespaceResolver); } @@ -601,10 +618,10 @@ public virtual object ReadElementContentAs(Type returnType, IXmlNamespaceResolve public abstract int AttributeCount { get; } // Gets the value of the attribute with the specified Name - public abstract string GetAttribute(string name); + public abstract string? GetAttribute(string name); // Gets the value of the attribute with the LocalName and NamespaceURI - public abstract string GetAttribute(string name, string namespaceURI); + public abstract string? GetAttribute(string name, string namespaceURI); // Gets the value of the attribute with the specified index. public abstract string GetAttribute(int i); @@ -619,7 +636,7 @@ public virtual string this[int i] } // Gets the value of the attribute with the specified Name. - public virtual string this[string name] + public virtual string? this[string name] { get { @@ -628,7 +645,7 @@ public virtual string this[string name] } // Gets the value of the attribute with the LocalName and NamespaceURI - public virtual string this[string name, string namespaceURI] + public virtual string? this[string name, string namespaceURI] { get { @@ -700,7 +717,7 @@ public virtual void Skip() public abstract XmlNameTable NameTable { get; } // Resolves a namespace prefix in the current element's scope. - public abstract string LookupNamespace(string prefix); + public abstract string? LookupNamespace(string prefix); // Returns true if the XmlReader can expand general entities. public virtual bool CanResolveEntity @@ -1365,15 +1382,14 @@ private XmlWriter CreateWriterForInnerOuterXml(StringWriter sw) private void SetNamespacesFlag(XmlTextWriter xtw) { - XmlTextReader tr = this as XmlTextReader; - if (tr != null) + if (this is XmlTextReader tr) { xtw.Namespaces = tr.Namespaces; } else { #pragma warning disable 618 - XmlValidatingReader vr = this as XmlValidatingReader; + XmlValidatingReader? vr = this as XmlValidatingReader; if (vr != null) { xtw.Namespaces = vr.Namespaces; @@ -1389,6 +1405,7 @@ public virtual XmlReader ReadSubtree() { throw new InvalidOperationException(SR.Xml_ReadSubtreeNotOnElement); } + return new XmlSubtreeReader(this); } @@ -1421,7 +1438,7 @@ protected virtual void Dispose(bool disposing) // Internal methods // // Validation support - internal virtual XmlNamespaceManager NamespaceManager + internal virtual XmlNamespaceManager? NamespaceManager { get { @@ -1573,17 +1590,17 @@ internal bool CanReadContentAs() return CanReadContentAs(this.NodeType); } - internal static Exception CreateReadContentAsException(string methodName, XmlNodeType nodeType, IXmlLineInfo lineInfo) + internal static Exception CreateReadContentAsException(string methodName, XmlNodeType nodeType, IXmlLineInfo? lineInfo) { return new InvalidOperationException(AddLineInfo(SR.Format(SR.Xml_InvalidReadContentAs, methodName, nodeType), lineInfo)); } - internal static Exception CreateReadElementContentAsException(string methodName, XmlNodeType nodeType, IXmlLineInfo lineInfo) + internal static Exception CreateReadElementContentAsException(string methodName, XmlNodeType nodeType, IXmlLineInfo? lineInfo) { return new InvalidOperationException(AddLineInfo(SR.Format(SR.Xml_InvalidReadElementContentAs, methodName, nodeType), lineInfo)); } - private static string AddLineInfo(string message, IXmlLineInfo lineInfo) + private static string AddLineInfo(string message, IXmlLineInfo? lineInfo) { if (lineInfo != null) { @@ -1598,7 +1615,7 @@ private static string AddLineInfo(string message, IXmlLineInfo lineInfo) internal string InternalReadContentAsString() { string value = string.Empty; - StringBuilder sb = null; + StringBuilder? sb = null; do { switch (this.NodeType) @@ -1673,6 +1690,7 @@ private bool SetupReadElementContentAsXxx(string methodName) { throw new XmlException(SR.Xml_MixedReadElementContentAs, string.Empty, this as IXmlLineInfo); } + return true; } @@ -1682,6 +1700,7 @@ private void FinishReadElementContentAsXxx() { throw new XmlException(SR.Xml_InvalidNodeType, this.NodeType.ToString()); } + this.Read(); } @@ -1693,16 +1712,18 @@ internal bool IsDefaultInternal { return true; } - IXmlSchemaInfo schemaInfo = this.SchemaInfo; + + IXmlSchemaInfo? schemaInfo = this.SchemaInfo; if (schemaInfo != null && schemaInfo.IsDefault) { return true; } + return false; } } - internal virtual IDtdInfo DtdInfo + internal virtual IDtdInfo? DtdInfo { get { @@ -1712,33 +1733,30 @@ internal virtual IDtdInfo DtdInfo internal static ConformanceLevel GetV1ConformanceLevel(XmlReader reader) { - XmlTextReaderImpl tri = GetXmlTextReaderImpl(reader); + XmlTextReaderImpl? tri = GetXmlTextReaderImpl(reader); return tri != null ? tri.V1ComformanceLevel : ConformanceLevel.Document; } - private static XmlTextReaderImpl GetXmlTextReaderImpl(XmlReader reader) + private static XmlTextReaderImpl? GetXmlTextReaderImpl(XmlReader reader) { - XmlTextReaderImpl tri = reader as XmlTextReaderImpl; - if (tri != null) + if (reader is XmlTextReaderImpl tri) { return tri; } - XmlTextReader tr = reader as XmlTextReader; - if (tr != null) + if (reader is XmlTextReader tr) { return tr.Impl; } - XmlValidatingReaderImpl vri = reader as XmlValidatingReaderImpl; - if (vri != null) + if (reader is XmlValidatingReaderImpl vri) { return vri.ReaderImpl; } + #pragma warning disable 618 - XmlValidatingReader vr = reader as XmlValidatingReader; + if (reader is XmlValidatingReader vr) #pragma warning restore 618 - if (vr != null) { return vr.Impl.ReaderImpl; } @@ -1768,13 +1786,13 @@ public static XmlReader Create(string inputUri) } // Creates an XmlReader according to the settings for parsing XML from the given Uri. - public static XmlReader Create(string inputUri, XmlReaderSettings settings) + public static XmlReader Create(string inputUri, XmlReaderSettings? settings) { - return XmlReader.Create(inputUri, settings, (XmlParserContext)null); + return XmlReader.Create(inputUri, settings, (XmlParserContext?)null); } // Creates an XmlReader according to the settings and parser context for parsing XML from the given Uri. - public static XmlReader Create(string inputUri, XmlReaderSettings settings, XmlParserContext inputContext) + public static XmlReader Create(string inputUri, XmlReaderSettings? settings, XmlParserContext? inputContext) { settings ??= XmlReaderSettings.s_defaultReaderSettings; return settings.CreateReader(inputUri, inputContext); @@ -1794,20 +1812,20 @@ public static XmlReader Create(Stream input) } // Creates an XmlReader according to the settings for parsing XML from the given stream. - public static XmlReader Create(Stream input, XmlReaderSettings settings) + public static XmlReader Create(Stream input, XmlReaderSettings? settings) { return Create(input, settings, string.Empty); } // Creates an XmlReader according to the settings and base Uri for parsing XML from the given stream. - public static XmlReader Create(Stream input, XmlReaderSettings settings, string baseUri) + public static XmlReader Create(Stream input, XmlReaderSettings? settings, string? baseUri) { settings ??= XmlReaderSettings.s_defaultReaderSettings; - return settings.CreateReader(input, null, (string)baseUri, null); + return settings.CreateReader(input, null, baseUri, null); } // Creates an XmlReader according to the settings and parser context for parsing XML from the given stream. - public static XmlReader Create(Stream input, XmlReaderSettings settings, XmlParserContext inputContext) + public static XmlReader Create(Stream input, XmlReaderSettings? settings, XmlParserContext? inputContext) { settings ??= XmlReaderSettings.s_defaultReaderSettings; return settings.CreateReader(input, null, (string)string.Empty, inputContext); @@ -1827,27 +1845,27 @@ public static XmlReader Create(TextReader input) } // Creates an XmlReader according to the settings for parsing XML from the given TextReader. - public static XmlReader Create(TextReader input, XmlReaderSettings settings) + public static XmlReader Create(TextReader input, XmlReaderSettings? settings) { return Create(input, settings, string.Empty); } // Creates an XmlReader according to the settings and baseUri for parsing XML from the given TextReader. - public static XmlReader Create(TextReader input, XmlReaderSettings settings, string baseUri) + public static XmlReader Create(TextReader input, XmlReaderSettings? settings, string? baseUri) { settings ??= XmlReaderSettings.s_defaultReaderSettings; return settings.CreateReader(input, baseUri, null); } // Creates an XmlReader according to the settings and parser context for parsing XML from the given TextReader. - public static XmlReader Create(TextReader input, XmlReaderSettings settings, XmlParserContext inputContext) + public static XmlReader Create(TextReader input, XmlReaderSettings? settings, XmlParserContext? inputContext) { settings ??= XmlReaderSettings.s_defaultReaderSettings; return settings.CreateReader(input, string.Empty, inputContext); } // Creates an XmlReader according to the settings wrapped over the given reader. - public static XmlReader Create(XmlReader reader, XmlReaderSettings settings) + public static XmlReader Create(XmlReader reader, XmlReaderSettings? settings) { settings ??= XmlReaderSettings.s_defaultReaderSettings; return settings.CreateReader(reader); @@ -1856,12 +1874,13 @@ public static XmlReader Create(XmlReader reader, XmlReaderSettings settings) // !!!!!! // NOTE: This method is called via reflection from System.Data.Common.dll. // !!!!!! - internal static XmlReader CreateSqlReader(Stream input, XmlReaderSettings settings, XmlParserContext inputContext) + internal static XmlReader CreateSqlReader(Stream input, XmlReaderSettings? settings, XmlParserContext inputContext) { if (input == null) { throw new ArgumentNullException(nameof(input)); } + settings ??= XmlReaderSettings.s_defaultReaderSettings; XmlReader reader; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReaderAsync.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReaderAsync.cs index 098d3671a5919b..ceefc44f1e3c57 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReaderAsync.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReaderAsync.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.IO; using System.Text; using System.Security; @@ -340,7 +341,7 @@ private async Task SkipSubtreeAsync() internal async Task InternalReadContentAsStringAsync() { string value = string.Empty; - StringBuilder sb = null; + StringBuilder? sb = null; do { switch (this.NodeType) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReaderSettings.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReaderSettings.cs index e74adf0f36773c..67d70187bd0a80 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReaderSettings.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReaderSettings.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.IO; using System.Diagnostics; using System.Globalization; @@ -23,10 +24,10 @@ public sealed class XmlReaderSettings // Nametable - private XmlNameTable _nameTable; + private XmlNameTable? _nameTable; // XmlResolver - private XmlResolver _xmlResolver = null; + private XmlResolver? _xmlResolver = null; // Text settings private int _lineNumberOffset; @@ -50,8 +51,8 @@ public sealed class XmlReaderSettings //Validation settings private ValidationType _validationType; private XmlSchemaValidationFlags _validationFlags; - private XmlSchemaSet _schemas; - private ValidationEventHandler _valEventHandler; + private XmlSchemaSet? _schemas; + private ValidationEventHandler? _valEventHandler; // other settings private bool _closeInput; @@ -62,8 +63,8 @@ public sealed class XmlReaderSettings // Creation of validating readers is hidden behind a delegate which is only initialized if the ValidationType // property is set. This is for AOT builds where the tree shaker can reduce the validating readers away // if nobody calls the ValidationType setter. Might also help with non-AOT build when ILLinker is used. - private delegate XmlReader AddValidationFunc(XmlReader reader, XmlResolver resolver, bool addConformanceWrapper); - private AddValidationFunc _addValidationFunc; + private delegate XmlReader AddValidationFunc(XmlReader reader, XmlResolver? resolver, bool addConformanceWrapper); + private AddValidationFunc? _addValidationFunc; // // Constructor @@ -91,7 +92,7 @@ public bool Async } // Nametable - public XmlNameTable NameTable + public XmlNameTable? NameTable { get { @@ -111,7 +112,7 @@ internal bool IsXmlResolverSet set; // keep set internal as we need to call it from the schema validation code } - public XmlResolver XmlResolver + public XmlResolver? XmlResolver { set { @@ -121,7 +122,7 @@ public XmlResolver XmlResolver } } - internal XmlResolver GetXmlResolver() + internal XmlResolver? GetXmlResolver() { return _xmlResolver; } @@ -129,7 +130,7 @@ internal XmlResolver GetXmlResolver() //This is used by get XmlResolver in Xsd. //Check if the config set to prohibit default resovler //notice we must keep GetXmlResolver() to avoid dead lock when init System.Config.ConfigurationManager - internal XmlResolver GetXmlResolver_CheckConfig() + internal XmlResolver? GetXmlResolver_CheckConfig() { if (!LocalAppContextSwitches.AllowDefaultResolver && !IsXmlResolverSet) return null; @@ -401,7 +402,7 @@ public void Reset() public XmlReaderSettings Clone() { - XmlReaderSettings clonedSettings = this.MemberwiseClone() as XmlReaderSettings; + XmlReaderSettings clonedSettings = (this.MemberwiseClone() as XmlReaderSettings)!; clonedSettings.ReadOnly = false; return clonedSettings; } @@ -409,12 +410,12 @@ public XmlReaderSettings Clone() // // Internal methods // - internal ValidationEventHandler GetEventHandler() + internal ValidationEventHandler? GetEventHandler() { return _valEventHandler; } - internal XmlReader CreateReader(string inputUri, XmlParserContext inputContext) + internal XmlReader CreateReader(string inputUri, XmlParserContext? inputContext) { if (inputUri == null) { @@ -445,12 +446,13 @@ internal XmlReader CreateReader(string inputUri, XmlParserContext inputContext) return reader; } - internal XmlReader CreateReader(Stream input, Uri baseUri, string baseUriString, XmlParserContext inputContext) + internal XmlReader CreateReader(Stream input, Uri? baseUri, string? baseUriString, XmlParserContext? inputContext) { if (input == null) { throw new ArgumentNullException(nameof(input)); } + if (baseUriString == null) { if (baseUri == null) @@ -480,12 +482,13 @@ internal XmlReader CreateReader(Stream input, Uri baseUri, string baseUriString, return reader; } - internal XmlReader CreateReader(TextReader input, string baseUriString, XmlParserContext inputContext) + internal XmlReader CreateReader(TextReader input, string? baseUriString, XmlParserContext? inputContext) { if (input == null) { throw new ArgumentNullException(nameof(input)); } + if (baseUriString == null) { baseUriString = string.Empty; @@ -514,6 +517,7 @@ internal XmlReader CreateReader(XmlReader reader) { throw new ArgumentNullException(nameof(reader)); } + return AddValidationAndConformanceWrapper(reader); } @@ -545,7 +549,7 @@ private void Initialize() Initialize(null); } - private void Initialize(XmlResolver resolver) + private void Initialize(XmlResolver? resolver) { _nameTable = null; _xmlResolver = resolver; @@ -579,7 +583,7 @@ private void Initialize(XmlResolver resolver) internal XmlReader AddValidation(XmlReader reader) { - XmlResolver resolver = null; + XmlResolver? resolver = null; if (_validationType == ValidationType.Schema) { resolver = GetXmlResolver_CheckConfig(); @@ -596,7 +600,7 @@ internal XmlReader AddValidation(XmlReader reader) private XmlReader AddValidationAndConformanceWrapper(XmlReader reader) { - XmlResolver resolver = null; + XmlResolver? resolver = null; if (_validationType == ValidationType.Schema) { resolver = GetXmlResolver_CheckConfig(); @@ -605,7 +609,7 @@ private XmlReader AddValidationAndConformanceWrapper(XmlReader reader) return AddValidationAndConformanceInternal(reader, resolver, addConformanceWrapper: true); } - private XmlReader AddValidationAndConformanceInternal(XmlReader reader, XmlResolver resolver, bool addConformanceWrapper) + private XmlReader AddValidationAndConformanceInternal(XmlReader reader, XmlResolver? resolver, bool addConformanceWrapper) { // We have to avoid calling the _addValidationFunc delegate if there's no validation to setup // since it would not be initialized (to allow AOT compilers to reduce it away). @@ -621,13 +625,14 @@ private XmlReader AddValidationAndConformanceInternal(XmlReader reader, XmlResol } else { + Debug.Assert(_addValidationFunc != null); reader = _addValidationFunc(reader, resolver, addConformanceWrapper); } return reader; } - private XmlReader AddValidationInternal(XmlReader reader, XmlResolver resolver, bool addConformanceWrapper) + private XmlReader AddValidationInternal(XmlReader reader, XmlResolver? resolver, bool addConformanceWrapper) { // wrap with DTD validating reader if (_validationType == ValidationType.DTD) @@ -646,6 +651,7 @@ private XmlReader AddValidationInternal(XmlReader reader, XmlResolver resolver, { reader = new XsdValidatingReader(reader, GetXmlResolver_CheckConfig(), this); } + return reader; } @@ -656,7 +662,7 @@ private XmlValidatingReaderImpl CreateDtdValidatingReader(XmlReader baseReader) internal XmlReader AddConformanceWrapper(XmlReader baseReader) { - XmlReaderSettings baseReaderSettings = baseReader.Settings; + XmlReaderSettings? baseReaderSettings = baseReader.Settings; bool checkChars = false; bool noWhitespace = false; bool noComments = false; @@ -674,10 +680,10 @@ internal XmlReader AddConformanceWrapper(XmlReader baseReader) } // get the V1 XmlTextReader ref - XmlTextReader v1XmlTextReader = baseReader as XmlTextReader; + XmlTextReader? v1XmlTextReader = baseReader as XmlTextReader; if (v1XmlTextReader == null) { - XmlValidatingReader vr = baseReader as XmlValidatingReader; + XmlValidatingReader? vr = baseReader as XmlValidatingReader; if (vr != null) { v1XmlTextReader = (XmlTextReader)vr.Reader; @@ -762,7 +768,7 @@ internal XmlReader AddConformanceWrapper(XmlReader baseReader) if (needWrap) { - IXmlNamespaceResolver readerAsNSResolver = baseReader as IXmlNamespaceResolver; + IXmlNamespaceResolver? readerAsNSResolver = baseReader as IXmlNamespaceResolver; if (readerAsNSResolver != null) { return new XmlCharCheckingReaderWithNS(baseReader, readerAsNSResolver, checkChars, noWhitespace, noComments, noPIs, dtdProc); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlSpace.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlSpace.cs index 7d6541c96dc0c5..c8f594b4b0ffff 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlSpace.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlSpace.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml { // An enumeration for the xml:space scope used in XmlReader and XmlWriter. diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlSubtreeReader.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlSubtreeReader.cs index 82876f5df9cab4..9432bb5d9cdaae 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlSubtreeReader.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlSubtreeReader.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Xml; using System.Diagnostics; @@ -25,8 +26,14 @@ private class NodeData internal string namespaceUri; internal string value; - internal NodeData() + internal NodeData(XmlNodeType nodeType, string localName, string prefix, string name, string namespaceUri, string value) { + this.type = nodeType; + this.localName = localName; + this.prefix = prefix; + this.name = name; + this.namespaceUri = namespaceUri; + this.value = value; } internal void Set(XmlNodeType nodeType, string localName, string prefix, string name, string namespaceUri, string value) @@ -66,7 +73,7 @@ private enum State // namespace management private readonly XmlNamespaceManager _nsManager; - private NodeData[] _nsAttributes; + private NodeData[]? _nsAttributes; private int _nsAttrCount; private int _curNsAttr = -1; @@ -75,11 +82,11 @@ private enum State // incremental reading of added xmlns nodes (ReadValueChunk, ReadContentAsBase64, ReadContentAsBinHex) private int _nsIncReadOffset; - private IncrementalReadDecoder _binDecoder; + private IncrementalReadDecoder? _binDecoder; // cached nodes private bool _useCurNode; - private NodeData _curNode; + private NodeData _curNode = null!; // node used for a text node of ReadAttributeValue or as Initial or EOF node private readonly NodeData _tmpNode; @@ -99,8 +106,7 @@ internal XmlSubtreeReader(XmlReader reader) : base(reader) _xmlns = reader.NameTable.Add("xmlns"); _xmlnsUri = reader.NameTable.Add(XmlReservedNs.NsXmlNs); - _tmpNode = new NodeData(); - _tmpNode.Set(XmlNodeType.None, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty); + _tmpNode = new NodeData(XmlNodeType.None, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty); SetCurrentNode(_tmpNode); } @@ -112,7 +118,7 @@ public override XmlNodeType NodeType { get { - return (_useCurNode) ? _curNode.type : reader.NodeType; + return _useCurNode ? _curNode.type : reader.NodeType; } } @@ -120,7 +126,7 @@ public override string Name { get { - return (_useCurNode) ? _curNode.name : reader.Name; + return _useCurNode ? _curNode.name : reader.Name; } } @@ -128,7 +134,7 @@ public override string LocalName { get { - return (_useCurNode) ? _curNode.localName : reader.LocalName; + return _useCurNode ? _curNode.localName : reader.LocalName; } } @@ -136,7 +142,7 @@ public override string NamespaceURI { get { - return (_useCurNode) ? _curNode.namespaceUri : reader.NamespaceURI; + return _useCurNode ? _curNode.namespaceUri : reader.NamespaceURI; } } @@ -144,7 +150,7 @@ public override string Prefix { get { - return (_useCurNode) ? _curNode.prefix : reader.Prefix; + return _useCurNode ? _curNode.prefix : reader.Prefix; } } @@ -152,7 +158,7 @@ public override string Value { get { - return (_useCurNode) ? _curNode.value : reader.Value; + return _useCurNode ? _curNode.value : reader.Value; } } @@ -176,7 +182,7 @@ public override int Depth } } - public override string BaseURI + public override string? BaseURI { get { @@ -238,45 +244,51 @@ public override int AttributeCount } } - public override string GetAttribute(string name) + public override string? GetAttribute(string name) { if (!InAttributeActiveState) { return null; } - string attr = reader.GetAttribute(name); + string? attr = reader.GetAttribute(name); if (attr != null) { return attr; } + for (int i = 0; i < _nsAttrCount; i++) { - if (name == _nsAttributes[i].name) + if (name == _nsAttributes![i].name) { + // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 return _nsAttributes[i].value; } } return null; } - public override string GetAttribute(string name, string namespaceURI) + public override string? GetAttribute(string name, string namespaceURI) { if (!InAttributeActiveState) { return null; } - string attr = reader.GetAttribute(name, namespaceURI); + + string? attr = reader.GetAttribute(name, namespaceURI); if (attr != null) { return attr; } + for (int i = 0; i < _nsAttrCount; i++) { - if (name == _nsAttributes[i].localName && namespaceURI == _xmlnsUri) + if (name == _nsAttributes![i].localName && namespaceURI == _xmlnsUri) { + // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 return _nsAttributes[i].value; } } + return null; } @@ -293,7 +305,7 @@ public override string GetAttribute(int i) } else if (i - n < _nsAttrCount) { - return _nsAttributes[i - n].value; + return _nsAttributes![i - n].value; } else { @@ -313,9 +325,10 @@ public override bool MoveToAttribute(string name) _useCurNode = false; return true; } + for (int i = 0; i < _nsAttrCount; i++) { - if (name == _nsAttributes[i].name) + if (name == _nsAttributes![i].name) { MoveToNsAttribute(i); return true; @@ -336,9 +349,10 @@ public override bool MoveToAttribute(string name, string ns) _useCurNode = false; return true; } + for (int i = 0; i < _nsAttrCount; i++) { - if (name == _nsAttributes[i].localName && ns == _xmlnsUri) + if (name == _nsAttributes![i].localName && ns == _xmlnsUri) { MoveToNsAttribute(i); return true; @@ -854,6 +868,8 @@ public override int ReadContentAsBase64(byte[] buffer, int index, int count) { return 0; } + + Debug.Assert(_binDecoder != null); _binDecoder.SetNextOutputBuffer(buffer, index, count); _nsIncReadOffset += _binDecoder.Decode(_curNode.value, _nsIncReadOffset, _curNode.value.Length - _nsIncReadOffset); return _binDecoder.DecodedCount; @@ -990,6 +1006,8 @@ public override int ReadContentAsBinHex(byte[] buffer, int index, int count) { return 0; } + + Debug.Assert(_binDecoder != null); _binDecoder.SetNextOutputBuffer(buffer, index, count); _nsIncReadOffset += _binDecoder.Decode(_curNode.value, _nsIncReadOffset, _curNode.value.Length - _nsIncReadOffset); return _binDecoder.DecodedCount; @@ -1142,7 +1160,7 @@ public override int ReadValueChunk(char[] buffer, int index, int count) } } - public override string LookupNamespace(string prefix) + public override string? LookupNamespace(string prefix) { return ((IXmlNamespaceResolver)this).LookupNamespace(prefix); } @@ -1165,8 +1183,7 @@ int IXmlLineInfo.LineNumber { if (!_useCurNode) { - IXmlLineInfo lineInfo = reader as IXmlLineInfo; - if (lineInfo != null) + if (reader is IXmlLineInfo lineInfo) { return lineInfo.LineNumber; } @@ -1181,8 +1198,7 @@ int IXmlLineInfo.LinePosition { if (!_useCurNode) { - IXmlLineInfo lineInfo = reader as IXmlLineInfo; - if (lineInfo != null) + if (reader is IXmlLineInfo lineInfo) { return lineInfo.LinePosition; } @@ -1208,7 +1224,7 @@ IDictionary IXmlNamespaceResolver.GetNamespacesInScope(XmlNamesp return _nsManager.GetNamespacesInScope(scope); } - string IXmlNamespaceResolver.LookupNamespace(string prefix) + string? IXmlNamespaceResolver.LookupNamespace(string prefix) { if (!InNamespaceActiveState) { @@ -1217,7 +1233,7 @@ string IXmlNamespaceResolver.LookupNamespace(string prefix) return _nsManager.LookupNamespace(prefix); } - string IXmlNamespaceResolver.LookupPrefix(string namespaceName) + string? IXmlNamespaceResolver.LookupPrefix(string namespaceName) { if (!InNamespaceActiveState) { @@ -1292,6 +1308,7 @@ private void AddNamespace(string prefix, string ns) { _nsAttributes = new NodeData[InitialNamespaceAttributeCount]; } + if (index == _nsAttributes.Length) { NodeData[] newNsAttrs = new NodeData[_nsAttributes.Length * 2]; @@ -1299,17 +1316,30 @@ private void AddNamespace(string prefix, string ns) _nsAttributes = newNsAttrs; } - if (_nsAttributes[index] == null) + string localName; + string attrPrefix; + string name; + + if (prefix.Length == 0) { - _nsAttributes[index] = new NodeData(); + localName = _xmlns; + attrPrefix = string.Empty; + name = _xmlns; } - if (prefix.Length == 0) + else + { + localName = prefix; + attrPrefix = _xmlns; + name = reader.NameTable.Add(string.Concat(_xmlns, ":", prefix)); + } + + if (_nsAttributes[index] == null) { - _nsAttributes[index].Set(XmlNodeType.Attribute, _xmlns, string.Empty, _xmlns, _xmlnsUri, ns); + _nsAttributes[index] = new NodeData(XmlNodeType.Attribute, localName, attrPrefix, name, _xmlnsUri, ns); } else { - _nsAttributes[index].Set(XmlNodeType.Attribute, prefix, _xmlns, reader.NameTable.Add(string.Concat(_xmlns, ":", prefix)), _xmlnsUri, ns); + _nsAttributes[index].Set(XmlNodeType.Attribute, localName, attrPrefix, name, _xmlnsUri, ns); } Debug.Assert(_state == State.ClearNsAttributes || _state == State.Interactive || _state == State.PopNamespaceScope); @@ -1322,13 +1352,13 @@ private void RemoveNamespace(string prefix, string localName) { for (int i = 0; i < _nsAttrCount; i++) { - if (Ref.Equal(prefix, _nsAttributes[i].prefix) && - Ref.Equal(localName, _nsAttributes[i].localName)) + if (Ref.Equal(prefix, _nsAttributes![i].prefix) && + Ref.Equal(localName, _nsAttributes![i].localName)) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 { if (i < _nsAttrCount - 1) { // swap - NodeData tmpNodeData = _nsAttributes[i]; + NodeData tmpNodeData = _nsAttributes![i]; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/34644 _nsAttributes[i] = _nsAttributes[_nsAttrCount - 1]; _nsAttributes[_nsAttrCount - 1] = tmpNodeData; } @@ -1344,7 +1374,7 @@ private void MoveToNsAttribute(int index) reader.MoveToElement(); _curNsAttr = index; _nsIncReadOffset = 0; - SetCurrentNode(_nsAttributes[index]); + SetCurrentNode(_nsAttributes![index]); } private bool InitReadElementContentAsBinary(State binaryState) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlSubtreeReaderAsync.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlSubtreeReaderAsync.cs index d722745a8c4f1f..ecbff268c53d5f 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlSubtreeReaderAsync.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlSubtreeReaderAsync.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Xml; using System.Diagnostics; @@ -272,6 +273,8 @@ public override async Task ReadContentAsBase64Async(byte[] buffer, int inde { return 0; } + + Debug.Assert(_binDecoder != null); _binDecoder.SetNextOutputBuffer(buffer, index, count); _nsIncReadOffset += _binDecoder.Decode(_curNode.value, _nsIncReadOffset, _curNode.value.Length - _nsIncReadOffset); return _binDecoder.DecodedCount; @@ -408,6 +411,8 @@ public override async Task ReadContentAsBinHexAsync(byte[] buffer, int inde { return 0; } + + Debug.Assert(_binDecoder != null); _binDecoder.SetNextOutputBuffer(buffer, index, count); _nsIncReadOffset += _binDecoder.Decode(_curNode.value, _nsIncReadOffset, _curNode.value.Length - _nsIncReadOffset); return _binDecoder.DecodedCount; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextEncoder.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextEncoder.cs index 912615c9a16620..2e69660d785a38 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextEncoder.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextEncoder.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.IO; using System.Text; @@ -29,7 +30,7 @@ internal class XmlTextEncoder private char _quoteChar; // caching of attribute value - private StringBuilder _attrValue; + private StringBuilder? _attrValue; private bool _cacheAttrValue; // XmlCharType @@ -77,8 +78,10 @@ internal void EndAttribute() { if (_cacheAttrValue) { + Debug.Assert(_attrValue != null); _attrValue.Length = 0; } + _inAttribute = false; _cacheAttrValue = false; } @@ -89,6 +92,7 @@ internal string AttributeValue { if (_cacheAttrValue) { + Debug.Assert(_attrValue != null); return _attrValue.ToString(); } else @@ -134,6 +138,7 @@ internal void Write(char[] array, int offset, int count) if (_cacheAttrValue) { + Debug.Assert(_attrValue != null); _attrValue.Append(array, offset, count); } @@ -241,6 +246,7 @@ internal void WriteSurrogateCharEntity(char lowChar, char highChar) if (_cacheAttrValue) { + Debug.Assert(_attrValue != null); _attrValue.Append(highChar); _attrValue.Append(lowChar); } @@ -259,6 +265,7 @@ internal void Write(string text) if (_cacheAttrValue) { + Debug.Assert(_attrValue != null); _attrValue.Append(text); } @@ -395,8 +402,10 @@ internal void WriteRawWithSurrogateChecking(string text) { return; } + if (_cacheAttrValue) { + Debug.Assert(_attrValue != null); _attrValue.Append(text); } @@ -469,8 +478,10 @@ internal void WriteRaw(char[] array, int offset, int count) if (_cacheAttrValue) { + Debug.Assert(_attrValue != null); _attrValue.Append(array, offset, count); } + _textWriter.Write(array, offset, count); } @@ -486,10 +497,12 @@ internal void WriteCharEntity(char ch) string strVal = ((int)ch).ToString("X", NumberFormatInfo.InvariantInfo); if (_cacheAttrValue) { + Debug.Assert(_attrValue != null); _attrValue.Append("&#x"); _attrValue.Append(strVal); _attrValue.Append(';'); } + WriteCharEntityImpl(strVal); } @@ -497,10 +510,12 @@ internal void WriteEntityRef(string name) { if (_cacheAttrValue) { + Debug.Assert(_attrValue != null); _attrValue.Append('&'); _attrValue.Append(name); _attrValue.Append(';'); } + WriteEntityRefImpl(name); } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReader.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReader.cs index b51c0fb9e891b7..b8a45ad5532cfc 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReader.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReader.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.IO; using System.Text; @@ -149,7 +150,7 @@ public override int Depth get { return _impl.Depth; } } - public override string BaseURI + public override string? BaseURI { get { return _impl.BaseURI; } } @@ -183,12 +184,12 @@ public override string XmlLang public override int AttributeCount { get { return _impl.AttributeCount; } } - public override string GetAttribute(string name) + public override string? GetAttribute(string name) { return _impl.GetAttribute(name); } - public override string GetAttribute(string localName, string namespaceURI) + public override string? GetAttribute(string localName, string? namespaceURI) { return _impl.GetAttribute(localName, namespaceURI); } @@ -263,9 +264,9 @@ public override XmlNameTable NameTable get { return _impl.NameTable; } } - public override string LookupNamespace(string prefix) + public override string? LookupNamespace(string prefix) { - string ns = _impl.LookupNamespace(prefix); + string? ns = _impl.LookupNamespace(prefix); if (ns != null && ns.Length == 0) { ns = null; @@ -342,12 +343,12 @@ IDictionary IXmlNamespaceResolver.GetNamespacesInScope(XmlNamesp return _impl.GetNamespacesInScope(scope); } - string IXmlNamespaceResolver.LookupNamespace(string prefix) + string? IXmlNamespaceResolver.LookupNamespace(string prefix) { return _impl.LookupNamespace(prefix); } - string IXmlNamespaceResolver.LookupPrefix(string namespaceName) + string? IXmlNamespaceResolver.LookupPrefix(string namespaceName) { return _impl.LookupPrefix(namespaceName); } @@ -377,7 +378,7 @@ public bool Normalization set { _impl.Normalization = value; } } - public Encoding Encoding + public Encoding? Encoding { get { return _impl.Encoding; } } @@ -444,7 +445,7 @@ internal XmlTextReaderImpl Impl get { return _impl; } } - internal override XmlNamespaceManager NamespaceManager + internal override XmlNamespaceManager? NamespaceManager { get { return _impl.NamespaceManager; } } @@ -455,7 +456,7 @@ internal bool XmlValidatingReaderCompatibilityMode set { _impl.XmlValidatingReaderCompatibilityMode = value; } } - internal override IDtdInfo DtdInfo + internal override IDtdInfo? DtdInfo { get { return _impl.DtdInfo; } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReaderImpl.Unix.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReaderImpl.Unix.cs index 96e32fd9d3a1da..bc856150e13048 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReaderImpl.Unix.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReaderImpl.Unix.cs @@ -2,11 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml { internal partial class XmlTextReaderImpl { - static partial void ConvertAbsoluteUnixPathToAbsoluteUri(ref string url, XmlResolver resolver) + static partial void ConvertAbsoluteUnixPathToAbsoluteUri(ref string url, XmlResolver? resolver) { // new Uri(uri, UriKind.RelativeOrAbsolute) returns a Relative Uri for absolute unix paths (e.g. /tmp). // We convert the native unix path to a 'file://' uri string to make it an Absolute Uri. @@ -27,4 +28,4 @@ static partial void ConvertAbsoluteUnixPathToAbsoluteUri(ref string url, XmlReso } } } -} \ No newline at end of file +} diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReaderImpl.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReaderImpl.cs index 491d76aaf2e48c..7b181e4b798bbd 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReaderImpl.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReaderImpl.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.IO; using System.Text; using System.Xml.Schema; @@ -11,12 +12,13 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading.Tasks; +using System.Diagnostics.CodeAnalysis; namespace System.Xml { internal partial class XmlTextReaderImpl : XmlReader, IXmlLineInfo, IXmlNamespaceResolver { - private static UTF8Encoding s_utf8BomThrowing; + private static UTF8Encoding? s_utf8BomThrowing; private static UTF8Encoding UTF8BomThrowing => s_utf8BomThrowing ?? (s_utf8BomThrowing = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true, throwOnInvalidBytes: true)); @@ -119,19 +121,19 @@ private class LaterInitParam { public bool useAsync = false; - public Stream inputStream; - public byte[] inputBytes; + public Stream? inputStream; + public byte[]? inputBytes; public int inputByteCount; - public Uri inputbaseUri; - public string inputUriStr; - public XmlResolver inputUriResolver; - public XmlParserContext inputContext; - public TextReader inputTextReader; + public Uri? inputbaseUri; + public string? inputUriStr; + public XmlResolver? inputUriResolver; + public XmlParserContext? inputContext; + public TextReader? inputTextReader; public InitInputType initType = InitInputType.Invalid; } - private LaterInitParam _laterInitParam = null; + private LaterInitParam? _laterInitParam = null; private enum InitInputType { @@ -170,14 +172,14 @@ private enum InitInputType private int _attrDuplWalkCount; private bool _attrNeedNamespaceLookup; private bool _fullAttrCleanup; - private NodeData[] _attrDuplSortingArray; + private NodeData[]? _attrDuplSortingArray; // name table - private XmlNameTable _nameTable; + private XmlNameTable _nameTable = null!; // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/43523 private bool _nameTableFromSettings; // resolver - private XmlResolver _xmlResolver; + private XmlResolver? _xmlResolver; // this is only for constructors that takes url private readonly string _url = string.Empty; @@ -202,46 +204,46 @@ private enum InitInputType private readonly bool _v1Compat; // namespace handling - private XmlNamespaceManager _namespaceManager; + private XmlNamespaceManager? _namespaceManager; private string _lastPrefix = string.Empty; // xml context (xml:space, xml:lang, default namespace) private XmlContext _xmlContext; // stack of parsing states (=stack of entities) - private ParsingState[] _parsingStatesStack; + private ParsingState[]? _parsingStatesStack; private int _parsingStatesStackTop = -1; // current node base uri and encoding - private string _reportedBaseUri; - private Encoding _reportedEncoding; + private string? _reportedBaseUri; + private Encoding? _reportedEncoding; // DTD - private IDtdInfo _dtdInfo; + private IDtdInfo? _dtdInfo; // fragment parsing private XmlNodeType _fragmentType = XmlNodeType.Document; - private XmlParserContext _fragmentParserContext; + private XmlParserContext? _fragmentParserContext; private bool _fragment; // incremental read - private IncrementalReadDecoder _incReadDecoder; + private IncrementalReadDecoder? _incReadDecoder; private IncrementalReadState _incReadState; private LineInfo _incReadLineInfo; - private BinHexDecoder _binHexDecoder; - private Base64Decoder _base64Decoder; + private BinHexDecoder? _binHexDecoder; + private Base64Decoder? _base64Decoder; private int _incReadDepth; private int _incReadLeftStartPos; private int _incReadLeftEndPos; - private IncrementalReadCharsDecoder _readCharsDecoder; + private IncrementalReadCharsDecoder? _readCharsDecoder; // ReadAttributeValue helpers private int _attributeValueBaseEntityId; private bool _emptyEntityInAttributeResolved; // Validation helpers - private IValidationEventHandling _validationEventHandling; - private OnDefaultAttributeUseDelegate _onDefaultAttributeUse; + private IValidationEventHandling? _validationEventHandling; + private OnDefaultAttributeUseDelegate? _onDefaultAttributeUse; private bool _validatingReaderCompatFlag; @@ -253,7 +255,7 @@ private enum InitInputType private int _nextEntityId = 1; private ParsingMode _parsingMode; private ReadState _readState = ReadState.Initial; - private IDtdEntityInfo _lastEntity; + private IDtdEntityInfo? _lastEntity; private bool _afterResetState; private int _documentStartBytePos; private int _readValueOffset; @@ -263,7 +265,7 @@ private enum InitInputType private long _charactersFromEntities; // All entities that are currently being processed - private Dictionary _currentEntities; + private Dictionary? _currentEntities; // DOM helpers private bool _disableUndeclaredEntityCheck; @@ -301,8 +303,16 @@ private enum InitInputType internal XmlTextReaderImpl() { - _curNode = new NodeData(); _parsingFunction = ParsingFunction.NoData; + _outerReader = this; + _xmlContext = new XmlContext(); + _nameTable = new NameTable(); + _nodes = new NodeData[NodesInitialSize]; + _nodes[0] = new NodeData(); + _curNode = _nodes[0]; + _stringBuilder = new StringBuilder(); + _xml = _nameTable.Add("xml"); + _xmlNs = _nameTable.Add("xmlns"); } // Initializes a new instance of the XmlTextReaderImpl class with the specified XmlNameTable. @@ -348,7 +358,7 @@ internal XmlTextReaderImpl(XmlNameTable nt) } // This constructor is used when creating XmlTextReaderImpl reader via "XmlReader.Create(..)" - private XmlTextReaderImpl(XmlResolver resolver, XmlReaderSettings settings, XmlParserContext context) + private XmlTextReaderImpl(XmlResolver? resolver, XmlReaderSettings settings, XmlParserContext? context) { _useAsync = settings.Async; _v1Compat = false; @@ -357,7 +367,7 @@ private XmlTextReaderImpl(XmlResolver resolver, XmlReaderSettings settings, XmlP _xmlContext = new XmlContext(); // create or get nametable and namespace manager from XmlParserContext - XmlNameTable nt = settings.NameTable; + XmlNameTable? nt = settings.NameTable; if (context == null) { if (nt == null) @@ -369,6 +379,7 @@ private XmlTextReaderImpl(XmlResolver resolver, XmlReaderSettings settings, XmlP { _nameTableFromSettings = true; } + _nameTable = nt; _namespaceManager = new XmlNamespaceManager(nt); } @@ -443,16 +454,20 @@ private XmlTextReaderImpl(XmlResolver resolver, XmlReaderSettings settings, XmlP internal XmlTextReaderImpl(Stream input) : this(string.Empty, input, new NameTable()) { } + internal XmlTextReaderImpl(Stream input, XmlNameTable nt) : this(string.Empty, input, nt) { } + internal XmlTextReaderImpl(string url, Stream input) : this(url, input, new NameTable()) { } + internal XmlTextReaderImpl(string url, Stream input, XmlNameTable nt) : this(nt) { ConvertAbsoluteUnixPathToAbsoluteUri(ref url, resolver: null); _namespaceManager = new XmlNamespaceManager(nt); + if (url == null || url.Length == 0) { InitStreamInput(input, null); @@ -461,6 +476,7 @@ internal XmlTextReaderImpl(string url, Stream input, XmlNameTable nt) : this(nt) { InitStreamInput(url, input, null); } + _reportedBaseUri = _ps.baseUriStr; _reportedEncoding = _ps.encoding; } @@ -470,12 +486,15 @@ internal XmlTextReaderImpl(string url, Stream input, XmlNameTable nt) : this(nt) internal XmlTextReaderImpl(TextReader input) : this(string.Empty, input, new NameTable()) { } + internal XmlTextReaderImpl(TextReader input, XmlNameTable nt) : this(string.Empty, input, nt) { } + internal XmlTextReaderImpl(string url, TextReader input) : this(url, input, new NameTable()) { } + internal XmlTextReaderImpl(string url, TextReader input, XmlNameTable nt) : this(nt) { ConvertAbsoluteUnixPathToAbsoluteUri(ref url, resolver: null); @@ -491,7 +510,7 @@ internal XmlTextReaderImpl(string url, TextReader input, XmlNameTable nt) : this internal XmlTextReaderImpl(Stream xmlFragment, XmlNodeType fragType, XmlParserContext context) : this((context != null && context.NameTable != null) ? context.NameTable : new NameTable()) { - Encoding enc = (context != null) ? context.Encoding : null; + Encoding? enc = (context != null) ? context.Encoding : null; if (context == null || context.BaseURI == null || context.BaseURI.Length == 0) { InitStreamInput(xmlFragment, enc); @@ -502,6 +521,7 @@ internal XmlTextReaderImpl(Stream xmlFragment, XmlNodeType fragType, XmlParserCo // it is safe as this resolver will not be used to resolve DTD url's InitStreamInput(GetTempResolver().ResolveUri(null, context.BaseURI), xmlFragment, enc); } + InitFragmentReader(fragType, context, false); _reportedBaseUri = _ps.baseUriStr; @@ -527,6 +547,7 @@ internal XmlTextReaderImpl(string xmlFragment, XmlNodeType fragType, XmlParserCo _reportedBaseUri = context.BaseURI; InitStringInput(context.BaseURI, Encoding.Unicode, xmlFragment); } + InitFragmentReader(fragType, context, false); _reportedEncoding = _ps.encoding; } @@ -555,10 +576,12 @@ public XmlTextReaderImpl(string url, XmlNameTable nt) : this(nt) { throw new ArgumentNullException(nameof(url)); } + if (url.Length == 0) { throw new ArgumentException(SR.Xml_EmptyUrl, nameof(url)); } + _namespaceManager = new XmlNamespaceManager(nt); _url = url; @@ -575,7 +598,7 @@ public XmlTextReaderImpl(string url, XmlNameTable nt) : this(nt) // Initializes a new instance of the XmlTextReaderImpl class with the specified arguments. // This constructor is used when creating XmlTextReaderImpl via XmlReader.Create - internal XmlTextReaderImpl(string uriStr, XmlReaderSettings settings, XmlParserContext context, XmlResolver uriResolver) + internal XmlTextReaderImpl(string uriStr, XmlReaderSettings settings, XmlParserContext? context, XmlResolver uriResolver) : this(settings.GetXmlResolver(), settings, context) { Uri baseUri = uriResolver.ResolveUri(null, uriStr); @@ -604,6 +627,7 @@ internal XmlTextReaderImpl(string uriStr, XmlReaderSettings settings, XmlParserC _laterInitParam.inputContext = context; _laterInitParam.inputUriResolver = uriResolver; _laterInitParam.initType = InitInputType.UriString; + if (!settings.Async) { //if not set Async flag, finish the init in create stage. @@ -617,18 +641,22 @@ internal XmlTextReaderImpl(string uriStr, XmlReaderSettings settings, XmlParserC private void FinishInitUriString() { - Stream stream = null; + Stream? stream = null; + Debug.Assert(_laterInitParam != null); + Debug.Assert(_laterInitParam.inputUriResolver != null); + Debug.Assert(_laterInitParam.inputbaseUri != null); + Debug.Assert(_reportedBaseUri != null); if (_laterInitParam.useAsync) { - //this will be hit when user create a XmlReader by setting Async, but the first call is Read() instead of ReadAsync(), - //then we still should create an async stream here. And wait for the method finish. + // this will be hit when user create a XmlReader by setting Async, but the first call is Read() instead of ReadAsync(), + // then we still should create an async stream here. And wait for the method finish. Task t = _laterInitParam.inputUriResolver.GetEntityAsync(_laterInitParam.inputbaseUri, string.Empty, typeof(Stream)); stream = (Stream)t.GetAwaiter().GetResult(); } else { - stream = (Stream)_laterInitParam.inputUriResolver.GetEntity(_laterInitParam.inputbaseUri, string.Empty, typeof(Stream)); + stream = (Stream?)_laterInitParam.inputUriResolver.GetEntity(_laterInitParam.inputbaseUri, string.Empty, typeof(Stream)); } if (stream == null) @@ -636,7 +664,7 @@ private void FinishInitUriString() throw new XmlException(SR.Xml_CannotResolveUrl, _laterInitParam.inputUriStr); } - Encoding enc = null; + Encoding? enc = null; // get Encoding from XmlParserContext if (_laterInitParam.inputContext != null) { @@ -661,16 +689,18 @@ private void FinishInitUriString() stream.Dispose(); throw; } + _laterInitParam = null; } // Initializes a new instance of the XmlTextReaderImpl class with the specified arguments. // This constructor is used when creating XmlTextReaderImpl via XmlReader.Create - internal XmlTextReaderImpl(Stream stream, byte[] bytes, int byteCount, XmlReaderSettings settings, Uri baseUri, string baseUriStr, - XmlParserContext context, bool closeInput) + internal XmlTextReaderImpl(Stream stream, byte[]? bytes, int byteCount, XmlReaderSettings settings, Uri? baseUri, string baseUriStr, + XmlParserContext? context, bool closeInput) : this(settings.GetXmlResolver(), settings, context) { ConvertAbsoluteUnixPathToAbsoluteUri(ref baseUriStr, settings.GetXmlResolver()); + // get BaseUri from XmlParserContext if (context != null) { @@ -681,6 +711,7 @@ internal XmlTextReaderImpl(Stream stream, byte[] bytes, int byteCount, XmlReader { Throw(SR.Xml_DoubleBaseUri); } + Debug.Assert(baseUri == null); baseUriStr = context.BaseURI; } @@ -710,7 +741,11 @@ internal XmlTextReaderImpl(Stream stream, byte[] bytes, int byteCount, XmlReader private void FinishInitStream() { - Encoding enc = null; + Encoding? enc = null; + + Debug.Assert(_laterInitParam != null); + Debug.Assert(_laterInitParam.inputStream != null); + Debug.Assert(_reportedBaseUri != null); // get Encoding from XmlParserContext if (_laterInitParam.inputContext != null) @@ -728,12 +763,13 @@ private void FinishInitStream() { ProcessDtdFromParserContext(_laterInitParam.inputContext); } + _laterInitParam = null; } // Initializes a new instance of the XmlTextReaderImpl class with the specified arguments. // This constructor is used when creating XmlTextReaderImpl via XmlReader.Create - internal XmlTextReaderImpl(TextReader input, XmlReaderSettings settings, string baseUriStr, XmlParserContext context) + internal XmlTextReaderImpl(TextReader input, XmlReaderSettings settings, string baseUriStr, XmlParserContext? context) : this(settings.GetXmlResolver(), settings, context) { ConvertAbsoluteUnixPathToAbsoluteUri(ref baseUriStr, settings.GetXmlResolver()); @@ -766,6 +802,10 @@ internal XmlTextReaderImpl(TextReader input, XmlReaderSettings settings, string private void FinishInitTextReader() { + Debug.Assert(_laterInitParam != null); + Debug.Assert(_laterInitParam.inputTextReader != null); + Debug.Assert(_reportedBaseUri != null); + // init ParsingState InitTextReaderInput(_reportedBaseUri, _laterInitParam.inputTextReader); @@ -813,6 +853,7 @@ public override XmlReaderSettings Settings case XmlNodeType.Document: settings.ConformanceLevel = ConformanceLevel.Document; break; default: Debug.Fail($"Unexpected fragment type {_fragmentType}"); goto case XmlNodeType.None; } + settings.CheckCharacters = _checkCharacters; settings.LineNumberOffset = _lineNumberOffset; settings.LinePositionOffset = _linePositionOffset; @@ -860,7 +901,7 @@ public override string NamespaceURI { get { - return _curNode.ns; + return _curNode.ns ?? string.Empty; } } @@ -890,6 +931,7 @@ public override string Value FinishOtherValueIterator(); } } + return _curNode.StringValue; } } @@ -904,7 +946,7 @@ public override int Depth } // Returns the base URI of the current node. - public override string BaseURI + public override string? BaseURI { get { @@ -1003,7 +1045,7 @@ public override int AttributeCount } // Returns value of an attribute with the specified Name - public override string GetAttribute(string name) + public override string? GetAttribute(string name) { int i; if (!name.Contains(':')) @@ -1014,21 +1056,24 @@ public override string GetAttribute(string name) { i = GetIndexOfAttributeWithPrefix(name); } + return (i >= 0) ? _nodes[i].StringValue : null; } // Returns value of an attribute with the specified LocalName and NamespaceURI - public override string GetAttribute(string localName, string namespaceURI) + public override string? GetAttribute(string localName, string? namespaceURI) { namespaceURI = (namespaceURI == null) ? string.Empty : _nameTable.Get(namespaceURI); - localName = _nameTable.Get(localName); + string? localNameAtomized = _nameTable.Get(localName); + for (int i = _index + 1; i < _index + _attrCount + 1; i++) { - if (Ref.Equal(_nodes[i].localName, localName) && Ref.Equal(_nodes[i].ns, namespaceURI)) + if (Ref.Equal(_nodes[i].localName, localNameAtomized) && Ref.Equal(_nodes[i].ns, namespaceURI)) { return _nodes[i].StringValue; } } + return null; } @@ -1039,6 +1084,7 @@ public override string GetAttribute(int i) { throw new ArgumentOutOfRangeException(nameof(i)); } + return _nodes[_index + i + 1].StringValue; } @@ -1072,14 +1118,14 @@ public override bool MoveToAttribute(string name) } // Moves to an attribute with the specified LocalName and NamespceURI - public override bool MoveToAttribute(string localName, string namespaceURI) + public override bool MoveToAttribute(string localName, string? namespaceURI) { - namespaceURI = (namespaceURI == null) ? string.Empty : _nameTable.Get(namespaceURI); - localName = _nameTable.Get(localName); + string? namespaceURIAtomized = (namespaceURI == null) ? string.Empty : _nameTable.Get(namespaceURI); + string? localNameAtomized = _nameTable.Get(localName); for (int i = _index + 1; i < _index + _attrCount + 1; i++) { - if (Ref.Equal(_nodes[i].localName, localName) && - Ref.Equal(_nodes[i].ns, namespaceURI)) + if (Ref.Equal(_nodes[i].localName, localNameAtomized) && + Ref.Equal(_nodes[i].ns, namespaceURIAtomized)) { _curAttrIndex = i - _index - 1; _curNode = _nodes[i]; @@ -1091,6 +1137,7 @@ public override bool MoveToAttribute(string localName, string namespaceURI) return true; } } + return false; } @@ -1106,6 +1153,7 @@ public override void MoveToAttribute(int i) { FinishAttributeValueIterator(); } + _curAttrIndex = i; _curNode = _nodes[_index + 1 + _curAttrIndex]; } @@ -1164,6 +1212,8 @@ public override bool MoveToElement() private void FinishInit() { + Debug.Assert(_laterInitParam != null); + switch (_laterInitParam.initType) { case InitInputType.UriString: @@ -1375,13 +1425,14 @@ public override void Skip() } // Returns NamespaceURI associated with the specified prefix in the current namespace scope. - public override string LookupNamespace(string prefix) + public override string? LookupNamespace(string prefix) { if (!_supportNamespaces) { return null; } + Debug.Assert(_namespaceManager != null); return _namespaceManager.LookupNamespace(prefix); } @@ -1495,7 +1546,7 @@ public override void ResolveEntity() case EntityType.ExpandedInAttribute: case EntityType.Expanded: _nextParsingFunction = _parsingFunction; - if (_ps.charsUsed - _ps.charPos == 0 && !_ps.entity.IsExternal) + if (_ps.charsUsed - _ps.charPos == 0 && !_ps.entity!.IsExternal) { // empty internal entity value _parsingFunction = ParsingFunction.AfterResolveEmptyEntityInContent; } @@ -1897,6 +1948,8 @@ public override int ReadValueChunk(char[] buffer, int index, int count) { copyCount = endPos - startPos; } + + Debug.Assert(_ps.chars != null); BlockCopyChars(_ps.chars, startPos, buffer, (index + readCount), copyCount); readCount += copyCount; @@ -1920,6 +1973,7 @@ public override int ReadValueChunk(char[] buffer, int index, int count) } _readValueOffset = 0; + Debug.Assert(_ps.chars != null); _curNode.SetValue(_ps.chars, startPos, endPos - startPos); } return readCount; @@ -1959,12 +2013,12 @@ IDictionary IXmlNamespaceResolver.GetNamespacesInScope(XmlNamesp return this.GetNamespacesInScope(scope); } - string IXmlNamespaceResolver.LookupNamespace(string prefix) + string? IXmlNamespaceResolver.LookupNamespace(string prefix) { return this.LookupNamespace(prefix); } - string IXmlNamespaceResolver.LookupPrefix(string namespaceName) + string? IXmlNamespaceResolver.LookupPrefix(string namespaceName) { return this.LookupPrefix(namespaceName); } @@ -1972,13 +2026,15 @@ string IXmlNamespaceResolver.LookupPrefix(string namespaceName) // Internal IXmlNamespaceResolver methods internal IDictionary GetNamespacesInScope(XmlNamespaceScope scope) { + Debug.Assert(_namespaceManager != null); return _namespaceManager.GetNamespacesInScope(scope); } // NOTE: there already is virtual method for "string LookupNamespace(string prefix)" - internal string LookupPrefix(string namespaceName) + internal string? LookupPrefix(string namespaceName) { + Debug.Assert(_namespaceManager != null); return _namespaceManager.LookupPrefix(namespaceName); } @@ -1998,6 +2054,7 @@ internal bool Namespaces { throw new InvalidOperationException(SR.Xml_InvalidOperation); } + _supportNamespaces = value; if (value) { @@ -2012,7 +2069,9 @@ internal bool Namespaces _namespaceManager = new XmlNamespaceManager(_nameTable); } } - _xmlContext.defaultNamespace = _namespaceManager.LookupNamespace(string.Empty); + + Debug.Assert(_namespaceManager != null); + _xmlContext.defaultNamespace = _namespaceManager.LookupNamespace(string.Empty)!; } else { @@ -2020,6 +2079,7 @@ internal bool Namespaces { _namespaceManager = new NoNamespaceManager(); } + _xmlContext.defaultNamespace = string.Empty; } } @@ -2050,7 +2110,7 @@ internal bool Normalization } // Returns the Encoding of the XML document - internal Encoding Encoding + internal Encoding? Encoding { get { @@ -2078,6 +2138,7 @@ internal WhitespaceHandling WhitespaceHandling { throw new XmlException(SR.Xml_WhitespaceHandling, string.Empty); } + _whitespaceHandling = value; } } @@ -2098,6 +2159,7 @@ internal DtdProcessing DtdProcessing { throw new ArgumentOutOfRangeException(nameof(value)); } + _dtdProcessing = value; } } @@ -2115,6 +2177,7 @@ internal EntityHandling EntityHandling { throw new XmlException(SR.Xml_EntityHandling, string.Empty); } + _entityHandling = value; } } @@ -2134,9 +2197,10 @@ internal XmlResolver XmlResolver _xmlResolverIsSet = true; // invalidate all baseUris on the stack _ps.baseUri = null; + for (int i = 0; i <= _parsingStatesStackTop; i++) { - _parsingStatesStack[i].baseUri = null; + _parsingStatesStack![i].baseUri = null; } } } @@ -2158,6 +2222,7 @@ internal void ResetState() // Clear ResetAttributes(); + Debug.Assert(_namespaceManager != null); while (_namespaceManager.PopScope()) ; while (InEntity) @@ -2186,7 +2251,6 @@ internal void ResetState() internal TextReader GetRemainder() { Debug.Assert(_v1Compat, "XmlTextReaderImpl.GetRemainder cannot be called on reader created via XmlReader.Create."); - Debug.Assert(_stringBuilder.Length == 0); switch (_parsingFunction) { @@ -2350,7 +2414,7 @@ internal XmlNameTable DtdParserProxy_NameTable } } - internal IXmlNamespaceResolver DtdParserProxy_NamespaceResolver + internal IXmlNamespaceResolver? DtdParserProxy_NamespaceResolver { get { @@ -2390,7 +2454,7 @@ internal bool DtdParserProxy_V1CompatibilityMode } } - internal Uri DtdParserProxy_BaseUri + internal Uri? DtdParserProxy_BaseUri { // SxS: ps.baseUri may be initialized in the constructor (public XmlTextReaderImpl( string url, XmlNameTable nt )) based on // url provided by the user. Here the property returns ps.BaseUri - so it may expose a path. @@ -2400,6 +2464,7 @@ internal Uri DtdParserProxy_BaseUri { _ps.baseUri = _xmlResolver.ResolveUri(null, _ps.baseUriStr); } + return _ps.baseUri; } } @@ -2412,7 +2477,7 @@ internal bool DtdParserProxy_IsEof } } - internal char[] DtdParserProxy_ParsingBuffer + internal char[]? DtdParserProxy_ParsingBuffer { get { @@ -2457,7 +2522,7 @@ internal bool DtdParserProxy_IsEntityEolNormalized } } - internal IValidationEventHandling DtdParserProxy_ValidationEventHandling + internal IValidationEventHandling? DtdParserProxy_ValidationEventHandling { get { @@ -2592,7 +2657,7 @@ internal bool DtdParserProxy_PushEntity(IDtdEntityInfo entity, out int entityId) return retValue; } - internal bool DtdParserProxy_PopEntity(out IDtdEntityInfo oldEntity, out int newEntityId) + internal bool DtdParserProxy_PopEntity(out IDtdEntityInfo? oldEntity, out int newEntityId) { if (_parsingStatesStackTop == -1) { @@ -2600,6 +2665,7 @@ internal bool DtdParserProxy_PopEntity(out IDtdEntityInfo oldEntity, out int new newEntityId = -1; return false; } + oldEntity = _ps.entity; PopEntity(); newEntityId = _ps.entityId; @@ -2608,7 +2674,7 @@ internal bool DtdParserProxy_PopEntity(out IDtdEntityInfo oldEntity, out int new // SxS: The caller did not provide any SxS sensitive name or resource. No resource is being exposed either. // It is OK to suppress SxS warning. - internal bool DtdParserProxy_PushExternalSubset(string systemId, string publicId) + internal bool DtdParserProxy_PushExternalSubset(string? systemId, string? publicId) { Debug.Assert(_parsingStatesStackTop == -1); Debug.Assert((systemId != null && systemId.Length > 0) || (publicId != null && publicId.Length > 0)); @@ -2617,10 +2683,14 @@ internal bool DtdParserProxy_PushExternalSubset(string systemId, string publicId { return false; } + + Debug.Assert(_xmlResolver != null); + if (_ps.baseUri == null && !string.IsNullOrEmpty(_ps.baseUriStr)) { _ps.baseUri = _xmlResolver.ResolveUri(null, _ps.baseUriStr); } + PushExternalEntityOrSubset(publicId, systemId, _ps.baseUri, null); _ps.entity = null; @@ -2679,90 +2749,108 @@ internal void DtdParserProxy_OnPublicId(string publicId, LineInfo keywordLineInf // // Throw methods: Sets the reader current position to pos, sets the error state and throws exception // + [DoesNotReturn] private void Throw(int pos, string res, string arg) { _ps.charPos = pos; Throw(res, arg); } + [DoesNotReturn] private void Throw(int pos, string res, string[] args) { _ps.charPos = pos; Throw(res, args); } + [DoesNotReturn] private void Throw(int pos, string res) { _ps.charPos = pos; Throw(res, string.Empty); } + [DoesNotReturn] private void Throw(string res) { Throw(res, string.Empty); } + [DoesNotReturn] private void Throw(string res, int lineNo, int linePos) { Throw(new XmlException(res, string.Empty, lineNo, linePos, _ps.baseUriStr)); } - private void Throw(string res, string arg) + [DoesNotReturn] + private void Throw(string res, string? arg) { Throw(new XmlException(res, arg, _ps.LineNo, _ps.LinePos, _ps.baseUriStr)); } - private void Throw(string res, string arg, int lineNo, int linePos) + [DoesNotReturn] + private void Throw(string res, string? arg, int lineNo, int linePos) { Throw(new XmlException(res, arg, lineNo, linePos, _ps.baseUriStr)); } - private void Throw(string res, string[] args) + [DoesNotReturn] + private void Throw(string res, string?[] args) { Throw(new XmlException(res, args, _ps.LineNo, _ps.LinePos, _ps.baseUriStr)); } - private void Throw(string res, string arg, Exception innerException) + [DoesNotReturn] + private void Throw(string res, string? arg, Exception innerException) { - Throw(res, new string[] { arg }, innerException); + Throw(res, new string?[] { arg }, innerException); } - private void Throw(string res, string[] args, Exception innerException) + [DoesNotReturn] + private void Throw(string res, string?[] args, Exception innerException) { Throw(new XmlException(res, args, innerException, _ps.LineNo, _ps.LinePos, _ps.baseUriStr)); } + [DoesNotReturn] private void Throw(Exception e) { SetErrorState(); - XmlException xmlEx = e as XmlException; + XmlException? xmlEx = e as XmlException; + if (xmlEx != null) { _curNode.SetLineInfo(xmlEx.LineNumber, xmlEx.LinePosition); } + throw e; } + [DoesNotReturn] private void ReThrow(Exception e, int lineNo, int linePos) { - Throw(new XmlException(e.Message, (Exception)null, lineNo, linePos, _ps.baseUriStr)); + Throw(new XmlException(e.Message, (Exception?)null, lineNo, linePos, _ps.baseUriStr)); } + [DoesNotReturn] private void ThrowWithoutLineInfo(string res) { Throw(new XmlException(res, string.Empty, _ps.baseUriStr)); } + [DoesNotReturn] private void ThrowWithoutLineInfo(string res, string arg) { Throw(new XmlException(res, arg, _ps.baseUriStr)); } - private void ThrowWithoutLineInfo(string res, string[] args, Exception innerException) + [DoesNotReturn] + private void ThrowWithoutLineInfo(string res, string?[] args, Exception? innerException) { Throw(new XmlException(res, args, innerException, 0, 0, _ps.baseUriStr)); } + [DoesNotReturn] private void ThrowInvalidChar(char[] data, int length, int invCharPos) { Throw(invCharPos, SR.Xml_InvalidCharacter, XmlException.BuildCharExceptionArgs(data, length, invCharPos)); @@ -2774,7 +2862,7 @@ private void SetErrorState() _readState = ReadState.Error; } - private void SendValidationEvent(XmlSeverityType severity, string code, string arg, int lineNo, int linePos) + private void SendValidationEvent(XmlSeverityType severity, string code, string? arg, int lineNo, int linePos) { SendValidationEvent(severity, new XmlSchemaException(code, arg, _ps.baseUriStr, lineNo, linePos)); } @@ -2809,6 +2897,7 @@ private void FinishAttributeValueIterator() { FinishReadContentAsBinary(); } + if (_parsingFunction == ParsingFunction.InReadAttributeValue) { while (_ps.entityId != _attributeValueBaseEntityId) @@ -2829,29 +2918,29 @@ private bool DtdValidation } } - private void InitStreamInput(Stream stream, Encoding encoding) + private void InitStreamInput(Stream stream, Encoding? encoding) { InitStreamInput(null, string.Empty, stream, null, 0, encoding); } - private void InitStreamInput(string baseUriStr, Stream stream, Encoding encoding) + private void InitStreamInput(string baseUriStr, Stream stream, Encoding? encoding) { Debug.Assert(baseUriStr != null); InitStreamInput(null, baseUriStr, stream, null, 0, encoding); } - private void InitStreamInput(Uri baseUri, Stream stream, Encoding encoding) + private void InitStreamInput(Uri? baseUri, Stream stream, Encoding? encoding) { Debug.Assert(baseUri != null); InitStreamInput(baseUri, baseUri.ToString(), stream, null, 0, encoding); } - private void InitStreamInput(Uri baseUri, string baseUriStr, Stream stream, Encoding encoding) + private void InitStreamInput(Uri? baseUri, string baseUriStr, Stream stream, Encoding? encoding) { InitStreamInput(baseUri, baseUriStr, stream, null, 0, encoding); } - private void InitStreamInput(Uri baseUri, string baseUriStr, Stream stream, byte[] bytes, int byteCount, Encoding encoding) + private void InitStreamInput(Uri? baseUri, string baseUriStr, Stream stream, byte[]? bytes, int byteCount, Encoding? encoding) { Debug.Assert(_ps.charPos == 0 && _ps.charsUsed == 0 && _ps.textReader == null); Debug.Assert(baseUriStr != null); @@ -2910,6 +2999,7 @@ private void InitStreamInput(Uri baseUri, string baseUriStr, Stream stream, byte { encoding = DetectEncoding(); } + SetupEncoding(encoding); // eat preamble @@ -2929,7 +3019,7 @@ private void InitTextReaderInput(string baseUriStr, TextReader input) InitTextReaderInput(baseUriStr, null, input); } - private void InitTextReaderInput(string baseUriStr, Uri baseUri, TextReader input) + private void InitTextReaderInput(string baseUriStr, Uri? baseUri, TextReader input) { Debug.Assert(_ps.charPos == 0 && _ps.charsUsed == 0 && _ps.stream == null); Debug.Assert(baseUriStr != null); @@ -2958,7 +3048,7 @@ private void InitTextReaderInput(string baseUriStr, Uri baseUri, TextReader inpu ReadData(); } - private void InitStringInput(string baseUriStr, Encoding originalEncoding, string str) + private void InitStringInput(string baseUriStr, Encoding? originalEncoding, string str) { Debug.Assert(_ps.stream == null && _ps.textReader == null); Debug.Assert(_ps.charPos == 0 && _ps.charsUsed == 0); @@ -2980,7 +3070,7 @@ private void InitStringInput(string baseUriStr, Encoding originalEncoding, strin _ps.isEof = true; } - private void InitFragmentReader(XmlNodeType fragmentType, XmlParserContext parserContext, bool allowXmlDeclFragment) + private void InitFragmentReader(XmlNodeType fragmentType, XmlParserContext? parserContext, bool allowXmlDeclFragment) { _fragmentParserContext = parserContext; @@ -2989,7 +3079,7 @@ private void InitFragmentReader(XmlNodeType fragmentType, XmlParserContext parse if (parserContext.NamespaceManager != null) { _namespaceManager = parserContext.NamespaceManager; - _xmlContext.defaultNamespace = _namespaceManager.LookupNamespace(string.Empty); + _xmlContext.defaultNamespace = _namespaceManager.LookupNamespace(string.Empty)!; } else { @@ -3041,6 +3131,7 @@ private void InitFragmentReader(XmlNodeType fragmentType, XmlParserContext parse Throw(SR.Xml_PartialContentNodeTypeNotSupportedEx, fragmentType.ToString()); return; } + _fragmentType = fragmentType; _fragment = true; } @@ -3081,7 +3172,7 @@ private void OpenUrl() try { - _ps.stream = (Stream)tmpResolver.GetEntity(_ps.baseUri, null, typeof(Stream)); + _ps.stream = (Stream?)tmpResolver.GetEntity(_ps.baseUri, null, typeof(Stream)); } catch { @@ -3094,12 +3185,13 @@ private void OpenUrl() ThrowWithoutLineInfo(SR.Xml_CannotResolveUrl, _ps.baseUriStr); } + Debug.Assert(_ps.stream != null); InitStreamInput(_ps.baseUri, _ps.baseUriStr, _ps.stream, null); _reportedEncoding = _ps.encoding; } // Stream input only: detect encoding from the first 4 bytes of the byte buffer starting at ps.bytes[ps.bytePos] - private Encoding DetectEncoding() + private Encoding? DetectEncoding() { Debug.Assert(_ps.bytes != null); Debug.Assert(_ps.bytePos == 0); @@ -3108,6 +3200,7 @@ private Encoding DetectEncoding() { return null; } + int first2Bytes = _ps.bytes[0] << 8 | _ps.bytes[1]; int next2Bytes = (_ps.bytesUsed >= 4) ? (_ps.bytes[2] << 8 | _ps.bytes[3]) : 0; @@ -3183,7 +3276,7 @@ private Encoding DetectEncoding() return null; } - private void SetupEncoding(Encoding encoding) + private void SetupEncoding(Encoding? encoding) { if (encoding == null) { @@ -3205,6 +3298,8 @@ private void SetupEncoding(Encoding encoding) private void EatPreamble() { + Debug.Assert(_ps.encoding != null); + Debug.Assert(_ps.bytes != null); ReadOnlySpan preamble = _ps.encoding.Preamble; int preambleLen = preamble.Length; int i; @@ -3224,6 +3319,7 @@ private void EatPreamble() // Switches the reader's encoding private void SwitchEncoding(Encoding newEncoding) { + Debug.Assert(_ps.encoding != null); if ((newEncoding.WebName != _ps.encoding.WebName || _ps.decoder is SafeAsciiDecoder) && !_afterResetState) { Debug.Assert(_ps.stream != null); @@ -3238,6 +3334,8 @@ private void SwitchEncoding(Encoding newEncoding) // Performs checks whether switching from current encoding to specified encoding is allowed. private Encoding CheckEncoding(string newEncodingName) { + Debug.Assert(_ps.encoding != null); + // encoding can be switched on stream input only if (_ps.stream == null) { @@ -3265,7 +3363,7 @@ private Encoding CheckEncoding(string newEncodingName) return _ps.encoding; } - Encoding newEncoding = null; + Encoding? newEncoding = null; if (string.Equals(newEncodingName, "utf-8", StringComparison.OrdinalIgnoreCase)) { newEncoding = UTF8BomThrowing; @@ -3284,6 +3382,8 @@ private Encoding CheckEncoding(string newEncodingName) { Throw(SR.Xml_UnknownEncoding, newEncodingName, innerEx); } + + Debug.Assert(newEncoding != null); Debug.Assert(newEncoding.EncodingName != "UTF-8"); } @@ -3313,6 +3413,7 @@ private void UnDecodeChars() "We didn't correctly count some of the decoded characters against the MaxCharactersInDocument."); _charactersInDocument -= _ps.charsUsed - _ps.charPos; } + if (_maxCharactersFromEntities > 0) { if (InEntity) @@ -3326,8 +3427,11 @@ private void UnDecodeChars() _ps.bytePos = _documentStartBytePos; // byte position after preamble if (_ps.charPos > 0) { + Debug.Assert(_ps.encoding != null); + Debug.Assert(_ps.chars != null); _ps.bytePos += _ps.encoding.GetByteCount(_ps.chars, 0, _ps.charPos); } + _ps.charsUsed = _ps.charPos; _ps.isEof = false; } @@ -3350,6 +3454,7 @@ private int ReadData() return 0; } + Debug.Assert(_ps.chars != null); int charsRead; if (_ps.appendMode) { @@ -3372,6 +3477,7 @@ private int ReadData() // the byte buffer is full -> allocate a new one if (_ps.bytesUsed - _ps.bytePos < MaxByteSequenceLen) { + Debug.Assert(_ps.bytes != null); if (_ps.bytes.Length - _ps.bytesUsed < MaxByteSequenceLen) { byte[] newBytes = new byte[_ps.bytes.Length * 2]; @@ -3430,9 +3536,11 @@ private int ReadData() } else { + Debug.Assert(_ps.bytes != null); BlockCopy(_ps.bytes, _ps.bytePos, _ps.bytes, 0, bytesLeft); _ps.bytesUsed = bytesLeft; } + _ps.bytePos = 0; } } @@ -3443,6 +3551,8 @@ private int ReadData() { if (!_ps.isStreamEof) { + Debug.Assert(_ps.bytes != null); + // read new bytes if (_ps.bytePos == _ps.bytesUsed && _ps.bytes.Length - _ps.bytesUsed > 0) { @@ -3483,6 +3593,7 @@ private int ReadData() Debug.Assert(_ps.charsUsed < _ps.chars.Length); _ps.isEof = true; } + _ps.chars[_ps.charsUsed] = (char)0; return charsRead; } @@ -3491,6 +3602,7 @@ private int ReadData() private int GetChars(int maxCharsCount) { Debug.Assert(_ps.stream != null && _ps.decoder != null && _ps.bytes != null); + Debug.Assert(_ps.chars != null); Debug.Assert(maxCharsCount <= _ps.chars.Length - _ps.charsUsed - 1); // determine the maximum number of bytes we can pass to the decoder @@ -3530,10 +3642,14 @@ private void InvalidCharRecovery(ref int bytesCount, out int charsCount) int chDec; int bDec; bool completed; + Debug.Assert(_ps.decoder != null); + Debug.Assert(_ps.bytes != null); + Debug.Assert(_ps.chars != null); _ps.decoder.Convert(_ps.bytes, _ps.bytePos + bytesDecoded, 1, _ps.chars, _ps.charsUsed + charsDecoded, 2, false, out bDec, out chDec, out completed); charsDecoded += chDec; bytesDecoded += bDec; } + Debug.Fail("We should get an exception again."); } catch (ArgumentException) @@ -3544,6 +3660,7 @@ private void InvalidCharRecovery(ref int bytesCount, out int charsCount) { Throw(_ps.charsUsed, SR.Xml_InvalidCharInThisEncoding); } + charsCount = charsDecoded; bytesCount = bytesDecoded; } @@ -3575,6 +3692,7 @@ internal void Close(bool closeInput) private void ShiftBuffer(int sourcePos, int destPos, int count) { + Debug.Assert(_ps.chars != null); BlockCopyChars(_ps.chars, sourcePos, _ps.chars, destPos, count); } @@ -3590,7 +3708,7 @@ private bool ParseXmlDeclaration(bool isTextDecl) } if (!XmlConvert.StrEqual(_ps.chars, _ps.charPos, 5, XmlDeclarationBeginning) || - _xmlCharType.IsNameSingleChar(_ps.chars[_ps.charPos + 5]) + _xmlCharType.IsNameSingleChar(_ps.chars![_ps.charPos + 5]) #if XML10_FIFTH_EDITION || xmlCharType.IsNCNameHighSurrogateChar( ps.chars[ps.charPos + 5] ) #endif @@ -3604,6 +3722,7 @@ private bool ParseXmlDeclaration(bool isTextDecl) _curNode.SetLineInfo(_ps.LineNo, _ps.LinePos + 2); _curNode.SetNamedNode(XmlNodeType.XmlDeclaration, _xml); } + _ps.charPos += 5; // parsing of text declarations cannot change global stringBuidler or curNode as we may be in the middle of a text node @@ -3612,7 +3731,7 @@ private bool ParseXmlDeclaration(bool isTextDecl) // parse version, encoding & standalone attributes int xmlDeclState = 0; // - Encoding encoding = null; + Encoding? encoding = null; while (true) { @@ -3651,6 +3770,7 @@ private bool ParseXmlDeclaration(bool isTextDecl) if (_afterResetState) { // check for invalid encoding switches to default encoding + Debug.Assert(_ps.encoding != null); string encodingName = _ps.encoding.WebName; if (encodingName != "utf-8" && encodingName != "utf-16" && encodingName != "utf-16BE" && !(_ps.encoding is Ucs4Encoding)) @@ -3688,7 +3808,7 @@ private bool ParseXmlDeclaration(bool isTextDecl) // read attribute name int nameEndPos = ParseName(); - NodeData attr = null; + NodeData? attr = null; switch (_ps.chars[_ps.charPos]) { case 'v': @@ -3729,8 +3849,10 @@ private bool ParseXmlDeclaration(bool isTextDecl) Throw(isTextDecl ? SR.Xml_InvalidTextDecl : SR.Xml_InvalidXmlDecl); break; } + if (!isTextDecl) { + Debug.Assert(attr != null); attr.SetLineInfo(_ps.LineNo, _ps.LinePos); } sb.Append(_ps.chars, _ps.charPos, nameEndPos - _ps.charPos); @@ -3762,6 +3884,7 @@ private bool ParseXmlDeclaration(bool isTextDecl) _ps.charPos++; if (!isTextDecl) { + Debug.Assert(attr != null); attr.quoteChar = quoteChar; attr.SetLineInfo2(_ps.LineNo, _ps.LinePos); } @@ -3796,6 +3919,7 @@ private bool ParseXmlDeclaration(bool isTextDecl) #endif if (!isTextDecl) { + Debug.Assert(attr != null); attr.SetValue(_ps.chars, _ps.charPos, pos - _ps.charPos); } xmlDeclState = 1; @@ -3811,6 +3935,7 @@ private bool ParseXmlDeclaration(bool isTextDecl) encoding = CheckEncoding(encName); if (!isTextDecl) { + Debug.Assert(attr != null); attr.SetValue(encName); } xmlDeclState = 2; @@ -3831,6 +3956,7 @@ private bool ParseXmlDeclaration(bool isTextDecl) } if (!isTextDecl) { + Debug.Assert(attr != null); attr.SetValue(_ps.chars, _ps.charPos, pos - _ps.charPos); } xmlDeclState = 3; @@ -3876,6 +4002,7 @@ private bool ParseXmlDeclaration(bool isTextDecl) if (_afterResetState) { // check for invalid encoding switches to default encoding + Debug.Assert(_ps.encoding != null); string encodingName = _ps.encoding.WebName; if (encodingName != "utf-8" && encodingName != "utf-16" && encodingName != "utf-16BE" && !(_ps.encoding is Ucs4Encoding)) @@ -3907,6 +4034,7 @@ private bool ParseDocumentContent() { bool needMoreChars = false; int pos = _ps.charPos; + Debug.Assert(_ps.chars != null); char[] chars = _ps.chars; // some tag @@ -4141,6 +4269,7 @@ private bool ParseElementContent() while (true) { int pos = _ps.charPos; + Debug.Assert(_ps.chars != null); char[] chars = _ps.chars; switch (chars[pos]) @@ -4305,6 +4434,7 @@ private void ThrowUnclosedElements() _stringBuilder.Append('.'); } } + Throw(_ps.charsUsed, SR.Xml_UnexpectedEOFInElementContent, _stringBuilder.ToString()); } } @@ -4313,6 +4443,7 @@ private void ThrowUnclosedElements() private void ParseElement() { int pos = _ps.charPos; + Debug.Assert(_ps.chars != null); char[] chars = _ps.chars; int colonPos = -1; @@ -4390,6 +4521,7 @@ private void ParseElement() SetElement: // push namespace context + Debug.Assert(_namespaceManager != null); _namespaceManager.PushScope(); // init the NodeData class @@ -4482,8 +4614,9 @@ private void ParseElement() private void AddDefaultAttributesAndNormalize() { Debug.Assert(_curNode.type == XmlNodeType.Element); + Debug.Assert(_dtdInfo != null); + IDtdAttributeListInfo? attlistInfo = _dtdInfo.LookupAttributeList(_curNode.localName, _curNode.prefix); - IDtdAttributeListInfo attlistInfo = _dtdInfo.LookupAttributeList(_curNode.localName, _curNode.prefix); if (attlistInfo == null) { return; @@ -4525,7 +4658,7 @@ private void AddDefaultAttributesAndNormalize() if (defaultAttributes != null) { int originalAttrCount = _attrCount; - NodeData[] nameSortedAttributes = null; + NodeData[]? nameSortedAttributes = null; if (_attrCount >= MaxAttrDuplWalkCount) { @@ -4573,6 +4706,7 @@ private void ParseEndElement() } int nameLen; + Debug.Assert(_ps.chars != null); char[] chars = _ps.chars; if (startTagNode.prefix.Length == 0) { @@ -4688,6 +4822,7 @@ private void ThrowTagMismatch(NodeData startTag) int colonPos; int endPos = ParseQName(out colonPos); + Debug.Assert(_ps.chars != null); string[] args = new string[4]; args[0] = startTag.GetNameWPrefix(_nameTable); args[1] = startTag.lineInfo.lineNo.ToString(CultureInfo.InvariantCulture); @@ -4706,8 +4841,9 @@ private void ThrowTagMismatch(NodeData startTag) private void ParseAttributes() { int pos = _ps.charPos; + Debug.Assert(_ps.chars != null); char[] chars = _ps.chars; - NodeData attr = null; + NodeData? attr = null; Debug.Assert(_attrCount == 0); @@ -5085,6 +5221,7 @@ private void OnDefaultNamespaceDecl(NodeData attr) { PushXmlContext(); } + _xmlContext.defaultNamespace = ns; AddNamespace(string.Empty, ns, attr); @@ -5114,6 +5251,7 @@ private void OnXmlReservedAttribute(NodeData attr) { PushXmlContext(); } + switch (XmlConvert.TrimString(attr.StringValue)) { case "preserve": @@ -5133,6 +5271,7 @@ private void OnXmlReservedAttribute(NodeData attr) { PushXmlContext(); } + _xmlContext.xmlLang = attr.StringValue; break; } @@ -5141,11 +5280,12 @@ private void OnXmlReservedAttribute(NodeData attr) private void ParseAttributeValueSlow(int curPos, char quoteChar, NodeData attr) { int pos = curPos; + Debug.Assert(_ps.chars != null); char[] chars = _ps.chars; int attributeBaseEntityId = _ps.entityId; int valueChunkStartPos = 0; LineInfo valueChunkLineInfo = new LineInfo(_ps.lineNo, _ps.LinePos); - NodeData lastChunk = null; + NodeData? lastChunk = null; Debug.Assert(_stringBuilder.Length == 0); @@ -5302,6 +5442,7 @@ private void ParseAttributeValueSlow(int curPos, char quoteChar, NodeData attr) NodeData entityChunk = new NodeData(); entityChunk.lineInfo = entityLineInfo; entityChunk.depth = attr.depth + 1; + Debug.Assert(_ps.entity != null); entityChunk.SetNamedNode(XmlNodeType.EntityReference, _ps.entity.Name); AddAttributeChunkToList(attr, entityChunk, ref lastChunk); @@ -5412,7 +5553,7 @@ private void ParseAttributeValueSlow(int curPos, char quoteChar, NodeData attr) _stringBuilder.Length = 0; } - private void AddAttributeChunkToList(NodeData attr, NodeData chunk, ref NodeData lastChunk) + private void AddAttributeChunkToList(NodeData attr, NodeData chunk, ref NodeData? lastChunk) { if (lastChunk == null) { @@ -5454,12 +5595,15 @@ private bool ParseText() { goto IgnoredNode; } + XmlNodeType nodeType = GetTextNodeType(orChars); if (nodeType == XmlNodeType.None) { goto IgnoredNode; } + Debug.Assert(endPos - startPos > 0); + Debug.Assert(_ps.chars != null); _curNode.SetValueNode(nodeType, _ps.chars, startPos, endPos - startPos); return true; } @@ -5504,6 +5648,7 @@ private bool ParseText() if (orChars > 0x20) { Debug.Assert(endPos - startPos > 0); + Debug.Assert(_ps.chars != null); _curNode.SetValueNode(XmlNodeType.Text, _ps.chars, startPos, endPos - startPos); _nextParsingFunction = _parsingFunction; _parsingFunction = ParsingFunction.PartialTextValue; @@ -5536,6 +5681,7 @@ private bool ParseText() } goto IgnoredNode; } + // set value to curNode _curNode.SetValueNode(nodeType, _stringBuilder.ToString()); _stringBuilder.Length = 0; @@ -5546,6 +5692,7 @@ private bool ParseText() _nextParsingFunction = _parsingFunction; _parsingFunction = ParsingFunction.PartialTextValue; } + return true; } } @@ -5576,6 +5723,7 @@ private bool ParseText() // Returns true when the whole value has been parsed. Return false when it needs to be called again to get a next chunk of value. private bool ParseText(out int startPos, out int endPos, ref int outOrChars) { + Debug.Assert(_ps.chars != null); char[] chars = _ps.chars; int pos = _ps.charPos; int rcount = 0; @@ -5943,6 +6091,7 @@ private bool ParseRootLevelWhitespace() XmlNodeType nodeType = GetWhitespaceType(); + Debug.Assert(_ps.chars != null); if (nodeType == XmlNodeType.None) { EatWhitespaces(null); @@ -5980,6 +6129,7 @@ private bool ParseRootLevelWhitespace() private void ParseEntityReference() { + Debug.Assert(_ps.chars != null); Debug.Assert(_ps.chars[_ps.charPos] == '&'); _ps.charPos++; @@ -5989,6 +6139,7 @@ private void ParseEntityReference() private EntityType HandleEntityReference(bool isInAttributeValue, EntityExpandType expandType, out int charRefEndPos) { + Debug.Assert(_ps.chars != null); Debug.Assert(_ps.chars[_ps.charPos] == '&'); if (_ps.charPos + 1 == _ps.charsUsed) @@ -6062,7 +6213,7 @@ private EntityType HandleEntityReference(bool isInAttributeValue, EntityExpandTy // return false == unexpanded external entity, stop parsing and return private EntityType HandleGeneralEntityReference(string name, bool isInAttributeValue, bool pushFakeEntityIfNullResolver, int entityStartLinePos) { - IDtdEntityInfo entity = null; + IDtdEntityInfo? entity = null; if (_dtdInfo == null && _fragmentParserContext != null && _fragmentParserContext.HasDtdInfo && _dtdProcessing == DtdProcessing.Parse) { @@ -6082,6 +6233,8 @@ private EntityType HandleGeneralEntityReference(string name, bool isInAttributeV Throw(SR.Xml_UndeclaredEntity, name, _ps.LineNo, entityStartLinePos); } + Debug.Assert(entity != null); + if (entity.IsUnparsedEntity) { if (_disableUndeclaredEntityCheck) @@ -6217,6 +6370,7 @@ private void SetupEndEntityNodeInAttribute() { _curNode = _nodes[_index + _attrCount + 1]; Debug.Assert(_curNode.type == XmlNodeType.EntityReference); + Debug.Assert(_lastEntity != null); Debug.Assert(Ref.Equal(_lastEntity.Name, _curNode.localName)); _curNode.lineInfo.linePos += _curNode.localName.Length; _curNode.type = XmlNodeType.EndEntity; @@ -6229,7 +6383,7 @@ private bool ParsePI() // Parses processing instruction; if piInDtdStringBuilder != null, the processing instruction is in DTD and // it will be saved in the passed string builder (target, whitespace & value). - private bool ParsePI(StringBuilder piInDtdStringBuilder) + private bool ParsePI(StringBuilder? piInDtdStringBuilder) { if (_parsingMode == ParsingMode.Full) { @@ -6240,6 +6394,7 @@ private bool ParsePI(StringBuilder piInDtdStringBuilder) // parse target name int nameEndPos = ParseName(); + Debug.Assert(_ps.chars != null); string target = _nameTable.Add(_ps.chars, _ps.charPos, nameEndPos - _ps.charPos); if (string.Equals(target, "xml", StringComparison.OrdinalIgnoreCase)) @@ -6325,6 +6480,7 @@ private bool ParsePI(StringBuilder piInDtdStringBuilder) _stringBuilder.Length = 0; } } + return true; } @@ -6339,6 +6495,7 @@ private bool ParsePIValue(out int outStartPos, out int outEndPos) } } + Debug.Assert(_ps.chars != null); int pos = _ps.charPos; char[] chars = _ps.chars; int rcount = 0; @@ -6510,6 +6667,7 @@ private void ParseCDataOrComment(XmlNodeType type) Debug.Assert(_stringBuilder.Length == 0); if (ParseCDataOrComment(type, out startPos, out endPos)) { + Debug.Assert(_ps.chars != null); _curNode.SetValueNode(type, _ps.chars, startPos, endPos - startPos); } else @@ -6518,6 +6676,7 @@ private void ParseCDataOrComment(XmlNodeType type) { _stringBuilder.Append(_ps.chars, startPos, endPos - startPos); } while (!ParseCDataOrComment(type, out startPos, out endPos)); + _stringBuilder.Append(_ps.chars, startPos, endPos - startPos); _curNode.SetValueNode(type, _stringBuilder.ToString()); _stringBuilder.Length = 0; @@ -6541,6 +6700,7 @@ private bool ParseCDataOrComment(XmlNodeType type, out int outStartPos, out int } } + Debug.Assert(_ps.chars != null); int pos = _ps.charPos; char[] chars = _ps.chars; int rcount = 0; @@ -6707,10 +6867,13 @@ private bool ParseDoctypeDecl() Throw(SR.Xml_UnexpectedEOF, "DOCTYPE"); } } + if (!XmlConvert.StrEqual(_ps.chars, _ps.charPos, 7, "DOCTYPE")) { ThrowUnexpectedToken((!_rootElementParsed && _dtdInfo == null) ? "DOCTYPE" : "; containing the specified text. @@ -169,7 +170,7 @@ public void WriteStartAttribute(string localName) // Writes out the specified text content. - public abstract void WriteString(string text); + public abstract void WriteString(string? text); // Write out the given surrogate pair as an entity reference. @@ -208,7 +209,7 @@ public virtual void Close() { } public abstract void Flush(); // Returns the closest prefix defined in the current namespace scope for the specified namespace URI. - public abstract string LookupPrefix(string ns); + public abstract string? LookupPrefix(string ns); // Gets an XmlSpace representing the current xml:space scope. public virtual XmlSpace XmlSpace @@ -220,7 +221,7 @@ public virtual XmlSpace XmlSpace } // Gets the current xml:lang scope. - public virtual string XmlLang + public virtual string? XmlLang { get { @@ -249,11 +250,11 @@ public virtual void WriteName(string name) } // Writes out the specified namespace-qualified name by looking up the prefix that is in scope for the given namespace. - public virtual void WriteQualifiedName(string localName, string ns) + public virtual void WriteQualifiedName(string localName, string? ns) { if (ns != null && ns.Length > 0) { - string prefix = LookupPrefix(ns); + string? prefix = LookupPrefix(ns); if (prefix == null) { throw new ArgumentException(SR.Format(SR.Xml_UndefNamespace, ns)); @@ -275,12 +276,13 @@ public virtual void WriteValue(object value) } // Writes out the specified value. - public virtual void WriteValue(string value) + public virtual void WriteValue(string? value) { if (value == null) { return; } + WriteString(value); } @@ -590,30 +592,32 @@ public virtual void WriteNode(XPathNavigator navigator, bool defattr) // Element Helper Methods // Writes out an element with the specified name containing the specified string value. - public void WriteElementString(string localName, string value) + public void WriteElementString(string localName, string? value) { WriteElementString(localName, null, value); } // Writes out an attribute with the specified name, namespace URI and string value. - public void WriteElementString(string localName, string ns, string value) + public void WriteElementString(string localName, string? ns, string? value) { WriteStartElement(localName, ns); if (null != value && 0 != value.Length) { WriteString(value); } + WriteEndElement(); } // Writes out an attribute with the specified name, namespace URI, and string value. - public void WriteElementString(string prefix, string localName, string ns, string value) + public void WriteElementString(string? prefix, string localName, string? ns, string? value) { WriteStartElement(prefix, localName, ns); if (null != value && 0 != value.Length) { WriteString(value); } + WriteEndElement(); } @@ -681,7 +685,7 @@ public static XmlWriter Create(string outputFileName) } // Creates an XmlWriter for writing into the provided file with the specified settings. - public static XmlWriter Create(string outputFileName, XmlWriterSettings settings) + public static XmlWriter Create(string outputFileName, XmlWriterSettings? settings) { settings ??= XmlWriterSettings.s_defaultWriterSettings; return settings.CreateWriter(outputFileName); @@ -703,7 +707,7 @@ public static XmlWriter Create(Stream output) } // Creates an XmlWriter for writing into the provided stream with the specified settings. - public static XmlWriter Create(Stream output, XmlWriterSettings settings) + public static XmlWriter Create(Stream output, XmlWriterSettings? settings) { settings ??= XmlWriterSettings.s_defaultWriterSettings; return settings.CreateWriter(output); @@ -725,7 +729,7 @@ public static XmlWriter Create(TextWriter output) } // Creates an XmlWriter for writing into the provided TextWriter with the specified settings. - public static XmlWriter Create(TextWriter output, XmlWriterSettings settings) + public static XmlWriter Create(TextWriter output, XmlWriterSettings? settings) { settings ??= XmlWriterSettings.s_defaultWriterSettings; return settings.CreateWriter(output); @@ -745,7 +749,7 @@ public static XmlWriter Create(StringBuilder output) } // Creates an XmlWriter for writing into the provided StringBuilder with the specified settings. - public static XmlWriter Create(StringBuilder output, XmlWriterSettings settings) + public static XmlWriter Create(StringBuilder output, XmlWriterSettings? settings) { if (output == null) { @@ -763,7 +767,7 @@ public static XmlWriter Create(XmlWriter output) } // Creates an XmlWriter wrapped around the provided XmlWriter with the specified settings. - public static XmlWriter Create(XmlWriter output, XmlWriterSettings settings) + public static XmlWriter Create(XmlWriter output, XmlWriterSettings? settings) { settings ??= XmlWriterSettings.s_defaultWriterSettings; return settings.CreateWriter(output); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlWriterAsync.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlWriterAsync.cs index 961be36f42f314..e5e14a63b8ea77 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlWriterAsync.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlWriterAsync.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Threading.Tasks; using System; @@ -18,7 +19,7 @@ namespace System.Xml { // Represents a writer that provides fast non-cached forward-only way of generating XML streams containing XML documents // that conform to the W3C Extensible Markup Language (XML) 1.0 specification and the Namespaces in XML specification. - public abstract partial class XmlWriter : IDisposable + public abstract partial class XmlWriter : IDisposable, IAsyncDisposable { // Write methods // Writes out the XML declaration with the version "1.0". @@ -44,14 +45,14 @@ public virtual Task WriteEndDocumentAsync() // Writes out the DOCTYPE declaration with the specified name and optional attributes. - public virtual Task WriteDocTypeAsync(string name, string pubid, string sysid, string subset) + public virtual Task WriteDocTypeAsync(string name, string? pubid, string? sysid, string subset) { throw new NotImplementedException(); } // Writes out the specified start tag and associates it with the given namespace and prefix. - public virtual Task WriteStartElementAsync(string prefix, string localName, string ns) + public virtual Task WriteStartElementAsync(string? prefix, string localName, string? ns) { throw new NotImplementedException(); } @@ -70,9 +71,8 @@ public virtual Task WriteFullEndElementAsync() throw new NotImplementedException(); } - // Writes out the attribute with the specified LocalName, value, and NamespaceURI. // Writes out the attribute with the specified prefix, LocalName, NamespaceURI and value. - public Task WriteAttributeStringAsync(string prefix, string localName, string ns, string value) + public Task WriteAttributeStringAsync(string? prefix, string localName, string? ns, string value) { Task task = WriteStartAttributeAsync(prefix, localName, ns); if (task.IsSuccess()) @@ -94,7 +94,7 @@ private async Task WriteAttributeStringAsyncHelper(Task task, string value) // Writes the start of an attribute. - protected internal virtual Task WriteStartAttributeAsync(string prefix, string localName, string ns) + protected internal virtual Task WriteStartAttributeAsync(string? prefix, string localName, string? ns) { throw new NotImplementedException(); } @@ -224,11 +224,11 @@ public virtual Task WriteNameAsync(string name) } // Writes out the specified namespace-qualified name by looking up the prefix that is in scope for the given namespace. - public virtual async Task WriteQualifiedNameAsync(string localName, string ns) + public virtual async Task WriteQualifiedNameAsync(string localName, string? ns) { if (ns != null && ns.Length > 0) { - string prefix = LookupPrefix(ns); + string? prefix = LookupPrefix(ns); if (prefix == null) { throw new ArgumentException(SR.Format(SR.Xml_UndefNamespace, ns)); @@ -568,7 +568,7 @@ public virtual async Task WriteNodeAsync(XPathNavigator navigator, bool defattr) // Element Helper Methods // Writes out an attribute with the specified name, namespace URI, and string value. - public async Task WriteElementStringAsync(string prefix, string localName, string ns, string value) + public async Task WriteElementStringAsync(string? prefix, string localName, string? ns, string value) { await WriteStartElementAsync(prefix, localName, ns).ConfigureAwait(false); if (null != value && 0 != value.Length) @@ -599,5 +599,21 @@ private async Task WriteLocalNamespacesAsync(XPathNavigator nsNav) await WriteAttributeStringAsync("xmlns", prefix, XmlReservedNs.NsXmlNs, ns).ConfigureAwait(false); } } + + public async ValueTask DisposeAsync() + { + await DisposeAsyncCore().ConfigureAwait(false); + Dispose(false); + GC.SuppressFinalize(this); + } + + protected virtual ValueTask DisposeAsyncCore() + { + if (WriteState != WriteState.Closed) + { + Dispose(true); + } + return default; + } } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XsdValidatingReader.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XsdValidatingReader.cs index 7a6b5928b545f7..2115a780f0dd92 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XsdValidatingReader.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XsdValidatingReader.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.IO; using System.Text; using System.Xml.Schema; @@ -11,6 +12,7 @@ using System.Collections; using System.Collections.Generic; using System.Runtime.Versioning; +using System.Diagnostics.CodeAnalysis; namespace System.Xml { @@ -18,9 +20,9 @@ namespace System.Xml internal class AttributePSVIInfo { - internal string localName; - internal string namespaceUri; - internal object typedAttributeValue; + internal string? localName; + internal string? namespaceUri; + internal object? typedAttributeValue; internal XmlSchemaInfo attributeSchemaInfo; internal AttributePSVIInfo() @@ -55,51 +57,52 @@ private enum ValidatingReaderState EOF = 9, Error = 10, } - //Validation + + // Validation private XmlReader _coreReader; - private readonly IXmlNamespaceResolver _coreReaderNSResolver; + private readonly IXmlNamespaceResolver? _coreReaderNSResolver; private readonly IXmlNamespaceResolver _thisNSResolver; - private XmlSchemaValidator _validator; - private readonly XmlResolver _xmlResolver; - private readonly ValidationEventHandler _validationEvent; + private XmlSchemaValidator _validator = null!; + private readonly XmlResolver? _xmlResolver; + private readonly ValidationEventHandler? _validationEvent; private ValidatingReaderState _validationState; private XmlValueGetter _valueGetter; // namespace management - private readonly XmlNamespaceManager _nsManager; + private readonly XmlNamespaceManager? _nsManager; private readonly bool _manageNamespaces; private readonly bool _processInlineSchema; private bool _replayCache; - //Current Node handling - private ValidatingReaderNodeData _cachedNode; //Used to cache current node when looking ahead or default attributes - private AttributePSVIInfo _attributePSVI; + // Current Node handling + private ValidatingReaderNodeData? _cachedNode; // Used to cache current node when looking ahead or default attributes + private AttributePSVIInfo? _attributePSVI; - //Attributes - private int _attributeCount; //Total count of attributes including default + // Attributes + private int _attributeCount; // Total count of attributes including default private int _coreReaderAttributeCount; private int _currentAttrIndex; private AttributePSVIInfo[] _attributePSVINodes; private ArrayList _defaultAttributes; - //Inline Schema - private Parser _inlineSchemaParser = null; + // Inline Schema + private Parser? _inlineSchemaParser = null; - //Typed Value & PSVI - private object _atomicValue; + // Typed Value & PSVI + private object? _atomicValue; private XmlSchemaInfo _xmlSchemaInfo; // original string of the atomic value - private string _originalAtomicValueString; + private string? _originalAtomicValueString; - //cached coreReader information + // cached coreReader information private readonly XmlNameTable _coreReaderNameTable; - private XsdCachingReader _cachingReader; + private XsdCachingReader? _cachingReader; - //ReadAttributeValue TextNode - private ValidatingReaderNodeData _textNode; + // ReadAttributeValue TextNode + private ValidatingReaderNodeData? _textNode; - //To avoid SchemaNames creation + // To avoid SchemaNames creation private string _nsXmlNs; private string _nsXs; private string _nsXsi; @@ -109,20 +112,20 @@ private enum ValidatingReaderState private string _xsiSchemaLocation; private string _xsiNoNamespaceSchemaLocation; - //Underlying reader's IXmlLineInfo - private IXmlLineInfo _lineInfo; + // Underlying reader's IXmlLineInfo + private IXmlLineInfo? _lineInfo; // helpers for Read[Element]ContentAs{Base64,BinHex} methods - private ReadContentAsBinaryHelper _readBinaryHelper; + private ReadContentAsBinaryHelper? _readBinaryHelper; private ValidatingReaderState _savedState; - //Constants + // Constants private const int InitialAttributeCount = 8; - private static volatile Type s_typeOfString; + private static volatile Type s_typeOfString = null!; - //Constructor - internal XsdValidatingReader(XmlReader reader, XmlResolver xmlResolver, XmlReaderSettings readerSettings, XmlSchemaObject partialValidationType) + // Constructor + internal XsdValidatingReader(XmlReader reader, XmlResolver? xmlResolver, XmlReaderSettings readerSettings, XmlSchemaObject? partialValidationType) { _coreReader = reader; _coreReaderNSResolver = reader as IXmlNamespaceResolver; @@ -133,21 +136,11 @@ internal XsdValidatingReader(XmlReader reader, XmlResolver xmlResolver, XmlReade _nsManager = new XmlNamespaceManager(_coreReaderNameTable); _manageNamespaces = true; } + _thisNSResolver = this as IXmlNamespaceResolver; _xmlResolver = xmlResolver; _processInlineSchema = (readerSettings.ValidationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0; - Init(); - SetupValidator(readerSettings, reader, partialValidationType); - _validationEvent = readerSettings.GetEventHandler(); - } - - internal XsdValidatingReader(XmlReader reader, XmlResolver xmlResolver, XmlReaderSettings readerSettings) - : - this(reader, xmlResolver, readerSettings, null) - { } - private void Init() - { _validationState = ValidatingReaderState.Init; _defaultAttributes = new ArrayList(); _currentAttrIndex = -1; @@ -156,7 +149,7 @@ private void Init() s_typeOfString = typeof(string); _xmlSchemaInfo = new XmlSchemaInfo(); - //Add common strings to be compared to NameTable + // Add common strings to be compared to NameTable _nsXmlNs = _coreReaderNameTable.Add(XmlReservedNs.NsXmlNs); _nsXs = _coreReaderNameTable.Add(XmlReservedNs.NsXs); _nsXsi = _coreReaderNameTable.Add(XmlReservedNs.NsXsi); @@ -165,20 +158,30 @@ private void Init() _xsiSchemaLocation = _coreReaderNameTable.Add("schemaLocation"); _xsiNoNamespaceSchemaLocation = _coreReaderNameTable.Add("noNamespaceSchemaLocation"); _xsdSchema = _coreReaderNameTable.Add("schema"); + + SetupValidator(readerSettings, reader, partialValidationType); + _validationEvent = readerSettings.GetEventHandler(); } - private void SetupValidator(XmlReaderSettings readerSettings, XmlReader reader, XmlSchemaObject partialValidationType) + internal XsdValidatingReader(XmlReader reader, XmlResolver? xmlResolver, XmlReaderSettings readerSettings) + : this(reader, xmlResolver, readerSettings, null) + { } + + [MemberNotNull("_validator")] + private void SetupValidator(XmlReaderSettings readerSettings, XmlReader reader, XmlSchemaObject? partialValidationType) { _validator = new XmlSchemaValidator(_coreReaderNameTable, readerSettings.Schemas, _thisNSResolver, readerSettings.ValidationFlags); _validator.XmlResolver = _xmlResolver; - _validator.SourceUri = XmlConvert.ToUri(reader.BaseURI); //Not using XmlResolver.ResolveUri as it checks for relative Uris,reader.BaseURI will be absolute file paths or string.Empty + _validator.SourceUri = XmlConvert.ToUri(reader.BaseURI); // Not using XmlResolver.ResolveUri as it checks for relative Uris,reader.BaseURI will be absolute file paths or string.Empty _validator.ValidationEventSender = this; _validator.ValidationEventHandler += readerSettings.GetEventHandler(); _validator.LineInfoProvider = _lineInfo; + if (_validator.ProcessSchemaHints) { _validator.SchemaSet.ReaderSettings.DtdProcessing = readerSettings.DtdProcessing; } + _validator.SetDtdSchemaInfo(reader.DtdInfo); if (partialValidationType != null) { @@ -195,13 +198,9 @@ public override XmlReaderSettings Settings { get { - XmlReaderSettings settings = _coreReader.Settings; - if (null != settings) - settings = settings.Clone(); - if (settings == null) - { - settings = new XmlReaderSettings(); - } + XmlReaderSettings? settings = _coreReader.Settings; + settings = settings != null ? settings.Clone() : new XmlReaderSettings(); + settings.Schemas = _validator.SchemaSet; settings.ValidationType = ValidationType.Schema; settings.ValidationFlags = _validator.ValidationFlags; @@ -219,16 +218,18 @@ public override XmlNodeType NodeType { if ((int)_validationState < 0) { + Debug.Assert(_cachedNode != null); return _cachedNode.NodeType; } else { XmlNodeType nodeType = _coreReader.NodeType; - //Check for significant whitespace + // Check for significant whitespace if (nodeType == XmlNodeType.Whitespace && (_validator.CurrentContentType == XmlSchemaContentType.TextOnly || _validator.CurrentContentType == XmlSchemaContentType.Mixed)) { return XmlNodeType.SignificantWhitespace; } + return nodeType; } } @@ -241,13 +242,16 @@ public override string Name { if (_validationState == ValidatingReaderState.OnDefaultAttribute) { + Debug.Assert(_cachedNode != null); string prefix = _validator.GetDefaultAttributePrefix(_cachedNode.Namespace); if (prefix != null && prefix.Length != 0) { return prefix + ":" + _cachedNode.LocalName; } + return _cachedNode.LocalName; } + return _coreReader.Name; } } @@ -259,8 +263,10 @@ public override string LocalName { if ((int)_validationState < 0) { + Debug.Assert(_cachedNode != null); return _cachedNode.LocalName; } + return _coreReader.LocalName; } } @@ -272,8 +278,10 @@ public override string NamespaceURI { if ((int)_validationState < 0) { + Debug.Assert(_cachedNode != null); return _cachedNode.Namespace; } + return _coreReader.NamespaceURI; } } @@ -285,8 +293,10 @@ public override string Prefix { if ((int)_validationState < 0) { + Debug.Assert(_cachedNode != null); return _cachedNode.Prefix; } + return _coreReader.Prefix; } } @@ -300,6 +310,7 @@ public override bool HasValue { return true; } + return _coreReader.HasValue; } } @@ -311,8 +322,10 @@ public override string Value { if ((int)_validationState < 0) { + Debug.Assert(_cachedNode != null); return _cachedNode.RawValue; } + return _coreReader.Value; } } @@ -324,14 +337,16 @@ public override int Depth { if ((int)_validationState < 0) { + Debug.Assert(_cachedNode != null); return _cachedNode.Depth; } + return _coreReader.Depth; } } // Gets the base URI of the current node. - public override string BaseURI + public override string? BaseURI { get { @@ -355,10 +370,12 @@ public override bool IsDefault get { if (_validationState == ValidatingReaderState.OnDefaultAttribute) - { //XSD default attributes + { + // XSD default attributes return true; } - return _coreReader.IsDefault; //This is DTD Default attribute + + return _coreReader.IsDefault; // This is DTD Default attribute } } @@ -407,15 +424,19 @@ public override System.Type ValueType case XmlNodeType.EndElement: if (_xmlSchemaInfo.ContentType == XmlSchemaContentType.TextOnly) { + Debug.Assert(_xmlSchemaInfo.SchemaType.Datatype != null); return _xmlSchemaInfo.SchemaType.Datatype.ValueType; } + goto default; case XmlNodeType.Attribute: if (_attributePSVI != null && AttributeSchemaInfo.ContentType == XmlSchemaContentType.TextOnly) { + Debug.Assert(AttributeSchemaInfo.SchemaType.Datatype != null); return AttributeSchemaInfo.SchemaType.Datatype.ValueType; } + goto default; default: @@ -440,8 +461,9 @@ public override bool ReadContentAsBoolean() { throw CreateReadContentAsException(nameof(ReadContentAsBoolean)); } + object typedValue = InternalReadContentAsObject(); - XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; + XmlSchemaType? xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) @@ -473,8 +495,9 @@ public override DateTime ReadContentAsDateTime() { throw CreateReadContentAsException(nameof(ReadContentAsDateTime)); } + object typedValue = InternalReadContentAsObject(); - XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; + XmlSchemaType? xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) @@ -506,8 +529,9 @@ public override double ReadContentAsDouble() { throw CreateReadContentAsException(nameof(ReadContentAsDouble)); } - object typedValue = InternalReadContentAsObject(); - XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; + + object? typedValue = InternalReadContentAsObject(); + XmlSchemaType? xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) @@ -539,8 +563,9 @@ public override float ReadContentAsFloat() { throw CreateReadContentAsException(nameof(ReadContentAsFloat)); } + object typedValue = InternalReadContentAsObject(); - XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; + XmlSchemaType? xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) @@ -572,8 +597,9 @@ public override decimal ReadContentAsDecimal() { throw CreateReadContentAsException(nameof(ReadContentAsDecimal)); } + object typedValue = InternalReadContentAsObject(); - XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; + XmlSchemaType? xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) @@ -605,8 +631,9 @@ public override int ReadContentAsInt() { throw CreateReadContentAsException(nameof(ReadContentAsInt)); } + object typedValue = InternalReadContentAsObject(); - XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; + XmlSchemaType? xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) @@ -638,8 +665,10 @@ public override long ReadContentAsLong() { throw CreateReadContentAsException(nameof(ReadContentAsLong)); } + object typedValue = InternalReadContentAsObject(); - XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; + XmlSchemaType? xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; + try { if (xmlType != null) @@ -671,8 +700,10 @@ public override string ReadContentAsString() { throw CreateReadContentAsException(nameof(ReadContentAsString)); } + object typedValue = InternalReadContentAsObject(); - XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; + XmlSchemaType? xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; + try { if (xmlType != null) @@ -681,7 +712,7 @@ public override string ReadContentAsString() } else { - return typedValue as string; + return (typedValue as string)!; } } catch (InvalidCastException e) @@ -704,11 +735,10 @@ public override object ReadContentAs(Type returnType, IXmlNamespaceResolver name { throw CreateReadContentAsException(nameof(ReadContentAs)); } - string originalStringValue; + string originalStringValue; object typedValue = InternalReadContentAsObject(false, out originalStringValue); - - XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; + XmlSchemaType? xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) @@ -717,8 +747,9 @@ public override object ReadContentAs(Type returnType, IXmlNamespaceResolver name // which cannot preserve time zone, so we need to convert from the original string if (returnType == typeof(DateTimeOffset) && xmlType.Datatype is Datatype_dateTimeBase) { - typedValue = originalStringValue; + typedValue = originalStringValue!; } + return xmlType.ValueConverter.ChangeType(typedValue, returnType); } else @@ -746,9 +777,9 @@ public override object ReadElementContentAsObject() { throw CreateReadElementContentAsException(nameof(ReadElementContentAsObject)); } - XmlSchemaType xmlType; - return InternalReadElementContentAsObject(out xmlType, true); + XmlSchemaType? xmlType; + return InternalReadElementContentAsObject(out xmlType, true)!; } public override bool ReadElementContentAsBoolean() @@ -757,9 +788,9 @@ public override bool ReadElementContentAsBoolean() { throw CreateReadElementContentAsException(nameof(ReadElementContentAsBoolean)); } - XmlSchemaType xmlType; - object typedValue = InternalReadElementContentAsObject(out xmlType); + XmlSchemaType? xmlType; + object? typedValue = InternalReadElementContentAsObject(out xmlType); try { @@ -792,9 +823,9 @@ public override DateTime ReadElementContentAsDateTime() { throw CreateReadElementContentAsException(nameof(ReadElementContentAsDateTime)); } - XmlSchemaType xmlType; - object typedValue = InternalReadElementContentAsObject(out xmlType); + XmlSchemaType? xmlType; + object? typedValue = InternalReadElementContentAsObject(out xmlType); try { @@ -827,9 +858,9 @@ public override double ReadElementContentAsDouble() { throw CreateReadElementContentAsException(nameof(ReadElementContentAsDouble)); } - XmlSchemaType xmlType; - object typedValue = InternalReadElementContentAsObject(out xmlType); + XmlSchemaType? xmlType; + object? typedValue = InternalReadElementContentAsObject(out xmlType); try { @@ -862,9 +893,9 @@ public override float ReadElementContentAsFloat() { throw CreateReadElementContentAsException(nameof(ReadElementContentAsFloat)); } - XmlSchemaType xmlType; - object typedValue = InternalReadElementContentAsObject(out xmlType); + XmlSchemaType? xmlType; + object? typedValue = InternalReadElementContentAsObject(out xmlType); try { @@ -897,9 +928,9 @@ public override decimal ReadElementContentAsDecimal() { throw CreateReadElementContentAsException(nameof(ReadElementContentAsDecimal)); } - XmlSchemaType xmlType; - object typedValue = InternalReadElementContentAsObject(out xmlType); + XmlSchemaType? xmlType; + object? typedValue = InternalReadElementContentAsObject(out xmlType); try { @@ -932,9 +963,9 @@ public override int ReadElementContentAsInt() { throw CreateReadElementContentAsException(nameof(ReadElementContentAsInt)); } - XmlSchemaType xmlType; - object typedValue = InternalReadElementContentAsObject(out xmlType); + XmlSchemaType? xmlType; + object? typedValue = InternalReadElementContentAsObject(out xmlType); try { @@ -967,9 +998,9 @@ public override long ReadElementContentAsLong() { throw CreateReadElementContentAsException(nameof(ReadElementContentAsLong)); } - XmlSchemaType xmlType; - object typedValue = InternalReadElementContentAsObject(out xmlType); + XmlSchemaType? xmlType; + object? typedValue = InternalReadElementContentAsObject(out xmlType); try { @@ -1002,9 +1033,9 @@ public override string ReadElementContentAsString() { throw CreateReadElementContentAsException(nameof(ReadElementContentAsString)); } - XmlSchemaType xmlType; - object typedValue = InternalReadElementContentAsObject(out xmlType); + XmlSchemaType? xmlType; + object? typedValue = InternalReadElementContentAsObject(out xmlType); try { @@ -1037,10 +1068,10 @@ public override object ReadElementContentAs(Type returnType, IXmlNamespaceResolv { throw CreateReadElementContentAsException(nameof(ReadElementContentAs)); } - XmlSchemaType xmlType; - string originalStringValue; - object typedValue = InternalReadElementContentAsObject(out xmlType, false, out originalStringValue); + XmlSchemaType? xmlType; + string? originalStringValue; + object? typedValue = InternalReadElementContentAsObject(out xmlType, false, out originalStringValue); try { @@ -1052,6 +1083,7 @@ public override object ReadElementContentAs(Type returnType, IXmlNamespaceResolv { typedValue = originalStringValue; } + return xmlType.ValueConverter.ChangeType(typedValue, returnType, namespaceResolver); } else @@ -1085,50 +1117,59 @@ public override int AttributeCount } // Gets the value of the attribute with the specified Name. - public override string GetAttribute(string name) + public override string? GetAttribute(string name) { - string attValue = _coreReader.GetAttribute(name); + string? attValue = _coreReader.GetAttribute(name); if (attValue == null && _attributeCount > 0) - { //Could be default attribute - ValidatingReaderNodeData defaultNode = GetDefaultAttribute(name, false); + { + // Could be default attribute + ValidatingReaderNodeData? defaultNode = GetDefaultAttribute(name, false); if (defaultNode != null) - { //Default found + { + // Default found attValue = defaultNode.RawValue; } } + return attValue; } // Gets the value of the attribute with the specified LocalName and NamespaceURI. - public override string GetAttribute(string name, string namespaceURI) + public override string? GetAttribute(string name, string namespaceURI) { - string attValue = _coreReader.GetAttribute(name, namespaceURI); + string? attValue = _coreReader.GetAttribute(name, namespaceURI); if (attValue == null && _attributeCount > 0) - { //Could be default attribute - namespaceURI = (namespaceURI == null) ? string.Empty : _coreReaderNameTable.Get(namespaceURI); - name = _coreReaderNameTable.Get(name); - if (name == null || namespaceURI == null) - { //Attribute not present since we did not see it + { + // Could be default attribute + string? atomizedNamespaceURI = (namespaceURI == null) ? string.Empty : _coreReaderNameTable.Get(namespaceURI); + string? atomizedName = _coreReaderNameTable.Get(name); + + if (atomizedName == null || atomizedNamespaceURI == null) + { + // Attribute not present since we did not see it return null; } - ValidatingReaderNodeData attNode = GetDefaultAttribute(name, namespaceURI, false); + + ValidatingReaderNodeData? attNode = GetDefaultAttribute(atomizedName, atomizedNamespaceURI, false); if (attNode != null) { return attNode.RawValue; } } + return attValue; } // Gets the value of the attribute with the specified index. public override string GetAttribute(int i) { - if (_attributeCount == 0) + if (i < 0 || i >= _attributeCount) { - return null; + throw new ArgumentOutOfRangeException(nameof(i)); } + if (i < _coreReaderAttributeCount) { return _coreReader.GetAttribute(i); @@ -1136,7 +1177,7 @@ public override string GetAttribute(int i) else { int defaultIndex = i - _coreReaderAttributeCount; - ValidatingReaderNodeData attNode = (ValidatingReaderNodeData)_defaultAttributes[defaultIndex]; + ValidatingReaderNodeData attNode = (ValidatingReaderNodeData)_defaultAttributes[defaultIndex]!; Debug.Assert(attNode != null); return attNode.RawValue; } @@ -1152,8 +1193,9 @@ public override bool MoveToAttribute(string name) goto Found; } else if (_attributeCount > 0) - { //Default attribute - ValidatingReaderNodeData defaultNode = GetDefaultAttribute(name, true); + { + // Default attribute + ValidatingReaderNodeData? defaultNode = GetDefaultAttribute(name, true); if (defaultNode != null) { _validationState = ValidatingReaderState.OnDefaultAttribute; @@ -1162,43 +1204,52 @@ public override bool MoveToAttribute(string name) goto Found; } } + return false; Found: if (_validationState == ValidatingReaderState.OnReadBinaryContent) { + Debug.Assert(_readBinaryHelper != null); _readBinaryHelper.Finish(); _validationState = _savedState; } + return true; } // Moves to the attribute with the specified LocalName and NamespaceURI - public override bool MoveToAttribute(string name, string ns) + public override bool MoveToAttribute(string name, string? ns) { - //Check atomized local name and ns - name = _coreReaderNameTable.Get(name); + // Check atomized local name and ns + string? atomizedName = _coreReaderNameTable.Get(name); ns = ns != null ? _coreReaderNameTable.Get(ns) : string.Empty; - if (name == null || ns == null) - { //Name or ns not found in the nameTable, then attribute is not found + + if (atomizedName == null || ns == null) + { + // Name or ns not found in the nameTable, then attribute is not found return false; } - if (_coreReader.MoveToAttribute(name, ns)) + + if (_coreReader.MoveToAttribute(atomizedName, ns)) { _validationState = ValidatingReaderState.OnAttribute; if (_inlineSchemaParser == null) { - _attributePSVI = GetAttributePSVI(name, ns); + _attributePSVI = GetAttributePSVI(atomizedName, ns); Debug.Assert(_attributePSVI != null); } else - { //Parsing inline schema, no PSVI for schema attributes + { + // Parsing inline schema, no PSVI for schema attributes _attributePSVI = null; } + goto Found; } else - { //Default attribute - ValidatingReaderNodeData defaultNode = GetDefaultAttribute(name, ns, true); + { + // Default attribute + ValidatingReaderNodeData? defaultNode = GetDefaultAttribute(atomizedName, ns, true); if (defaultNode != null) { _attributePSVI = defaultNode.AttInfo; @@ -1207,13 +1258,17 @@ public override bool MoveToAttribute(string name, string ns) goto Found; } } + return false; + Found: if (_validationState == ValidatingReaderState.OnReadBinaryContent) { + Debug.Assert(_readBinaryHelper != null); _readBinaryHelper.Finish(); _validationState = _savedState; } + return true; } @@ -1224,9 +1279,11 @@ public override void MoveToAttribute(int i) { throw new ArgumentOutOfRangeException(nameof(i)); } + _currentAttrIndex = i; if (i < _coreReaderAttributeCount) - { //reader attribute + { + // reader attribute _coreReader.MoveToAttribute(i); if (_inlineSchemaParser == null) { @@ -1236,17 +1293,21 @@ public override void MoveToAttribute(int i) { _attributePSVI = null; } + _validationState = ValidatingReaderState.OnAttribute; } else - { //default attribute + { + // default attribute int defaultIndex = i - _coreReaderAttributeCount; - _cachedNode = (ValidatingReaderNodeData)_defaultAttributes[defaultIndex]; + _cachedNode = (ValidatingReaderNodeData)_defaultAttributes[defaultIndex]!; _attributePSVI = _cachedNode.AttInfo; _validationState = ValidatingReaderState.OnDefaultAttribute; } + if (_validationState == ValidatingReaderState.OnReadBinaryContent) { + Debug.Assert(_readBinaryHelper != null); _readBinaryHelper.Finish(); _validationState = _savedState; } @@ -1266,24 +1327,29 @@ public override bool MoveToFirstAttribute() { _attributePSVI = null; } + _validationState = ValidatingReaderState.OnAttribute; goto Found; } else if (_defaultAttributes.Count > 0) - { //check for default - _cachedNode = (ValidatingReaderNodeData)_defaultAttributes[0]; + { + // check for default + _cachedNode = (ValidatingReaderNodeData)_defaultAttributes[0]!; _attributePSVI = _cachedNode.AttInfo; _currentAttrIndex = 0; _validationState = ValidatingReaderState.OnDefaultAttribute; goto Found; } + return false; Found: if (_validationState == ValidatingReaderState.OnReadBinaryContent) { + Debug.Assert(_readBinaryHelper != null); _readBinaryHelper.Finish(); _validationState = _savedState; } + return true; } @@ -1303,24 +1369,29 @@ public override bool MoveToNextAttribute() { _attributePSVI = null; } + _validationState = ValidatingReaderState.OnAttribute; goto Found; } else if (_currentAttrIndex + 1 < _attributeCount) - { //default attribute + { + // default attribute int defaultIndex = ++_currentAttrIndex - _coreReaderAttributeCount; - _cachedNode = (ValidatingReaderNodeData)_defaultAttributes[defaultIndex]; + _cachedNode = (ValidatingReaderNodeData)_defaultAttributes[defaultIndex]!; _attributePSVI = _cachedNode.AttInfo; _validationState = ValidatingReaderState.OnDefaultAttribute; goto Found; } + return false; Found: if (_validationState == ValidatingReaderState.OnReadBinaryContent) { + Debug.Assert(_readBinaryHelper != null); _readBinaryHelper.Finish(); _validationState = _savedState; } + return true; } @@ -1328,11 +1399,13 @@ public override bool MoveToNextAttribute() public override bool MoveToElement() { if (_coreReader.MoveToElement() || (int)_validationState < 0) - { //states OnDefaultAttribute or OnReadAttributeValue + { + // states OnDefaultAttribute or OnReadAttributeValue _currentAttrIndex = -1; _validationState = ValidatingReaderState.ClearAttributes; return true; } + return false; } @@ -1354,6 +1427,7 @@ public override bool Read() { _validationState = ValidatingReaderState.EOF; } + return false; } @@ -1377,7 +1451,7 @@ public override bool Read() goto case ValidatingReaderState.Read; } - case ValidatingReaderState.ReadAhead: //Will enter here on calling Skip() + case ValidatingReaderState.ReadAhead: // Will enter here on calling Skip() ClearAttributesInfo(); ProcessReaderEvent(); _validationState = ValidatingReaderState.Read; @@ -1385,13 +1459,15 @@ public override bool Read() case ValidatingReaderState.OnReadBinaryContent: _validationState = _savedState; + Debug.Assert(_readBinaryHelper != null); _readBinaryHelper.Finish(); return Read(); case ValidatingReaderState.Init: _validationState = ValidatingReaderState.Read; if (_coreReader.ReadState == ReadState.Interactive) - { //If the underlying reader is already positioned on a ndoe, process it + { + // If the underlying reader is already positioned on a ndoe, process it ProcessReaderEvent(); return true; } @@ -1445,26 +1521,29 @@ public override void Skip() { break; } + bool callSkipToEndElem = true; - //If union and unionValue has been parsed till EndElement, then validator.ValidateEndElement has been called - //Hence should not call SkipToEndElement as the current context has already been popped in the validator + // If union and unionValue has been parsed till EndElement, then validator.ValidateEndElement has been called + // Hence should not call SkipToEndElement as the current context has already been popped in the validator if ((_xmlSchemaInfo.IsUnionType || _xmlSchemaInfo.IsDefault) && _coreReader is XsdCachingReader) { callSkipToEndElem = false; } + _coreReader.Skip(); _validationState = ValidatingReaderState.ReadAhead; if (callSkipToEndElem) { _validator.SkipToEndElement(_xmlSchemaInfo); } + break; case XmlNodeType.Attribute: MoveToElement(); goto case XmlNodeType.Element; } - //For all other NodeTypes Skip() same as Read() + // For all other NodeTypes Skip() same as Read() Read(); return; } @@ -1479,7 +1558,7 @@ public override XmlNameTable NameTable } // Resolves a namespace prefix in the current element's scope. - public override string LookupNamespace(string prefix) + public override string? LookupNamespace(string prefix) { return _thisNSResolver.LookupNamespace(prefix); } @@ -1495,19 +1574,24 @@ public override bool ReadAttributeValue() { if (_validationState == ValidatingReaderState.OnReadBinaryContent) { + Debug.Assert(_readBinaryHelper != null); _readBinaryHelper.Finish(); _validationState = _savedState; } + if (NodeType == XmlNodeType.Attribute) { if (_validationState == ValidatingReaderState.OnDefaultAttribute) { + Debug.Assert(_cachedNode != null); _cachedNode = CreateDummyTextNode(_cachedNode.RawValue, _cachedNode.Depth + 1); _validationState = ValidatingReaderState.OnReadAttributeValue; return true; } + return _coreReader.ReadAttributeValue(); } + return false; } @@ -1537,6 +1621,7 @@ public override int ReadContentAsBase64(byte[] buffer, int index, int count) _validationState = _savedState; // call to the helper + Debug.Assert(_readBinaryHelper != null); int readCount = _readBinaryHelper.ReadContentAsBase64(buffer, index, count); // set OnReadBinaryContent state again and return @@ -1563,6 +1648,7 @@ public override int ReadContentAsBinHex(byte[] buffer, int index, int count) _validationState = _savedState; // call to the helper + Debug.Assert(_readBinaryHelper != null); int readCount = _readBinaryHelper.ReadContentAsBinHex(buffer, index, count); // set OnReadBinaryContent state again and return @@ -1589,6 +1675,7 @@ public override int ReadElementContentAsBase64(byte[] buffer, int index, int cou _validationState = _savedState; // call to the helper + Debug.Assert(_readBinaryHelper != null); int readCount = _readBinaryHelper.ReadElementContentAsBase64(buffer, index, count); // set OnReadBinaryContent state again and return @@ -1615,6 +1702,7 @@ public override int ReadElementContentAsBinHex(byte[] buffer, int index, int cou _validationState = _savedState; // call to the helper + Debug.Assert(_readBinaryHelper != null); int readCount = _readBinaryHelper.ReadElementContentAsBinHex(buffer, index, count); // set OnReadBinaryContent state again and return @@ -1637,6 +1725,7 @@ bool IXmlSchemaInfo.IsDefault { GetIsDefault(); } + return _xmlSchemaInfo.IsDefault; case XmlNodeType.EndElement: @@ -1647,11 +1736,13 @@ bool IXmlSchemaInfo.IsDefault { return AttributeSchemaInfo.IsDefault; } + break; default: break; } + return false; } } @@ -1669,6 +1760,7 @@ bool IXmlSchemaInfo.IsNil default: break; } + return false; } } @@ -1684,10 +1776,13 @@ XmlSchemaValidity IXmlSchemaInfo.Validity { return _xmlSchemaInfo.Validity; } + if (_xmlSchemaInfo.Validity == XmlSchemaValidity.Valid) - { //It might be valid for unions since we read ahead, but report notknown for consistency + { + // It might be valid for unions since we read ahead, but report notknown for consistency return XmlSchemaValidity.NotKnown; } + return _xmlSchemaInfo.Validity; case XmlNodeType.EndElement: @@ -1698,13 +1793,15 @@ XmlSchemaValidity IXmlSchemaInfo.Validity { return AttributeSchemaInfo.Validity; } + break; } + return XmlSchemaValidity.NotKnown; } } - XmlSchemaSimpleType IXmlSchemaInfo.MemberType + XmlSchemaSimpleType? IXmlSchemaInfo.MemberType { get { @@ -1715,6 +1812,7 @@ XmlSchemaSimpleType IXmlSchemaInfo.MemberType { GetMemberType(); } + return _xmlSchemaInfo.MemberType; case XmlNodeType.EndElement: @@ -1725,15 +1823,16 @@ XmlSchemaSimpleType IXmlSchemaInfo.MemberType { return AttributeSchemaInfo.MemberType; } + return null; default: - return null; //Text, PI, Comment etc + return null; // Text, PI, Comment etc } } } - XmlSchemaType IXmlSchemaInfo.SchemaType + XmlSchemaType? IXmlSchemaInfo.SchemaType { get { @@ -1748,14 +1847,16 @@ XmlSchemaType IXmlSchemaInfo.SchemaType { return AttributeSchemaInfo.SchemaType; } + return null; default: - return null; //Text, PI, Comment etc + return null; // Text, PI, Comment etc } } } - XmlSchemaElement IXmlSchemaInfo.SchemaElement + + XmlSchemaElement? IXmlSchemaInfo.SchemaElement { get { @@ -1763,11 +1864,12 @@ XmlSchemaElement IXmlSchemaInfo.SchemaElement { return _xmlSchemaInfo.SchemaElement; } + return null; } } - XmlSchemaAttribute IXmlSchemaInfo.SchemaAttribute + XmlSchemaAttribute? IXmlSchemaInfo.SchemaAttribute { get { @@ -1778,6 +1880,7 @@ XmlSchemaAttribute IXmlSchemaInfo.SchemaAttribute return AttributeSchemaInfo.SchemaAttribute; } } + return null; } } @@ -1799,6 +1902,7 @@ public int LineNumber { return _lineInfo.LineNumber; } + return 0; } } @@ -1811,6 +1915,7 @@ public int LinePosition { return _lineInfo.LinePosition; } + return 0; } } @@ -1826,11 +1931,12 @@ IDictionary IXmlNamespaceResolver.GetNamespacesInScope(XmlNamesp } else { + Debug.Assert(_nsManager != null); return _nsManager.GetNamespacesInScope(scope); } } - string IXmlNamespaceResolver.LookupNamespace(string prefix) + string? IXmlNamespaceResolver.LookupNamespace(string prefix) { if (_coreReaderNSResolver != null) { @@ -1838,11 +1944,12 @@ string IXmlNamespaceResolver.LookupNamespace(string prefix) } else { + Debug.Assert(_nsManager != null); return _nsManager.LookupNamespace(prefix); } } - string IXmlNamespaceResolver.LookupPrefix(string namespaceName) + string? IXmlNamespaceResolver.LookupPrefix(string namespaceName) { if (_coreReaderNSResolver != null) { @@ -1850,11 +1957,12 @@ string IXmlNamespaceResolver.LookupPrefix(string namespaceName) } else { + Debug.Assert(_nsManager != null); return _nsManager.LookupPrefix(namespaceName); } } - //Internal / Private methods + // Internal / Private methods private object GetStringValue() { @@ -1869,7 +1977,7 @@ private XmlSchemaType ElementXmlType } } - private XmlSchemaType AttributeXmlType + private XmlSchemaType? AttributeXmlType { get { @@ -1877,6 +1985,7 @@ private XmlSchemaType AttributeXmlType { return AttributeSchemaInfo.XmlType; } + return null; } } @@ -1893,11 +2002,13 @@ private XmlSchemaInfo AttributeSchemaInfo private void ProcessReaderEvent() { if (_replayCache) - { //if in replay mode, do nothing since nodes have been validated already - //If NodeType == XmlNodeType.EndElement && if manageNamespaces, may need to pop namespace scope, since scope is not popped in ReadAheadForMemberType + { + // if in replay mode, do nothing since nodes have been validated already + // If NodeType == XmlNodeType.EndElement && if manageNamespaces, may need to pop namespace scope, since scope is not popped in ReadAheadForMemberType return; } + switch (_coreReader.NodeType) { case XmlNodeType.Element: @@ -1943,7 +2054,8 @@ private void ProcessElementEvent() _xmlSchemaInfo.Clear(); _attributeCount = _coreReaderAttributeCount = _coreReader.AttributeCount; if (!_coreReader.IsEmptyElement) - { //If its not empty schema, then parse else ignore + { + // If its not empty schema, then parse else ignore _inlineSchemaParser = new Parser(SchemaType.XSD, _coreReaderNameTable, _validator.SchemaSet.GetSchemaNames(_coreReaderNameTable), _validationEvent); _inlineSchemaParser.StartParsing(_coreReader, null); _inlineSchemaParser.ParseReaderNode(); @@ -1955,27 +2067,32 @@ private void ProcessElementEvent() } } else - { //Validate element - //Clear previous data + { + // Validate element + // Clear previous data _atomicValue = null; _originalAtomicValueString = null; _xmlSchemaInfo.Clear(); if (_manageNamespaces) { + Debug.Assert(_nsManager != null); _nsManager.PushScope(); } - //Find Xsi attributes that need to be processed before validating the element - string xsiSchemaLocation = null; - string xsiNoNamespaceSL = null; - string xsiNil = null; - string xsiType = null; + + // Find Xsi attributes that need to be processed before validating the element + string? xsiSchemaLocation = null; + string? xsiNoNamespaceSL = null; + string? xsiNil = null; + string? xsiType = null; + if (_coreReader.MoveToFirstAttribute()) { do { string objectNs = _coreReader.NamespaceURI; string objectName = _coreReader.LocalName; + if (Ref.Equal(objectNs, _nsXsi)) { if (Ref.Equal(objectName, _xsiSchemaLocation)) @@ -1995,13 +2112,16 @@ private void ProcessElementEvent() xsiNil = _coreReader.Value; } } + if (_manageNamespaces && Ref.Equal(_coreReader.NamespaceURI, _nsXmlNs)) { + Debug.Assert(_nsManager != null); _nsManager.AddNamespace(_coreReader.Prefix.Length == 0 ? string.Empty : _coreReader.LocalName, _coreReader.Value); } } while (_coreReader.MoveToNextAttribute()); _coreReader.MoveToElement(); } + _validator.ValidateElement(_coreReader.LocalName, _coreReader.NamespaceURI, _xmlSchemaInfo, xsiType, xsiNil, xsiSchemaLocation, xsiNoNamespaceSL); ValidateAttributes(); _validator.ValidateEndOfAttributes(_xmlSchemaInfo); @@ -2009,6 +2129,7 @@ private void ProcessElementEvent() { ProcessEndElementEvent(); } + _validationState = ValidatingReaderState.ClearAttributes; } } @@ -2018,10 +2139,12 @@ private void ProcessEndElementEvent() _atomicValue = _validator.ValidateEndElement(_xmlSchemaInfo); _originalAtomicValueString = GetOriginalAtomicValueStringOfElement(); if (_xmlSchemaInfo.IsDefault) - { //The atomicValue returned is a default value + { + // The atomicValue returned is a default value Debug.Assert(_atomicValue != null); int depth = _coreReader.Depth; _coreReader = GetCachingReader(); + Debug.Assert(_cachingReader != null); _cachingReader.RecordTextNode(_xmlSchemaInfo.XmlType.ValueConverter.ToString(_atomicValue), _originalAtomicValueString, depth + 1, 0, 0); _cachingReader.RecordEndElementNode(); _cachingReader.SetToReplayMode(); @@ -2029,6 +2152,7 @@ private void ProcessEndElementEvent() } else if (_manageNamespaces) { + Debug.Assert(_nsManager != null); _nsManager.PopScope(); } } @@ -2055,19 +2179,24 @@ private void ValidateAttributes() attIndex++; continue; } + attributePSVI.typedAttributeValue = _validator.ValidateAttribute(localName, ns, _valueGetter, attributePSVI.attributeSchemaInfo); if (!attributeInvalid) { attributeInvalid = attributePSVI.attributeSchemaInfo.Validity == XmlSchemaValidity.Invalid; } + attIndex++; } while (_coreReader.MoveToNextAttribute()); } + _coreReader.MoveToElement(); if (attributeInvalid) - { //If any of the attributes are invalid, Need to report element's validity as invalid + { + // If any of the attributes are invalid, Need to report element's validity as invalid _xmlSchemaInfo.Validity = XmlSchemaValidity.Invalid; } + _validator.GetUnspecifiedDefaultAttributes(_defaultAttributes, true); _attributeCount += _defaultAttributes.Count; } @@ -2081,12 +2210,14 @@ private void ClearAttributesInfo() _attributePSVI = null; } - private AttributePSVIInfo GetAttributePSVI(string name) + private AttributePSVIInfo? GetAttributePSVI(string name) { if (_inlineSchemaParser != null) - { //Parsing inline schema, no PSVI for schema attributes + { + // Parsing inline schema, no PSVI for schema attributes return null; } + string attrLocalName; string attrPrefix; string ns; @@ -2095,27 +2226,30 @@ private AttributePSVIInfo GetAttributePSVI(string name) attrLocalName = _coreReaderNameTable.Add(attrLocalName); if (attrPrefix.Length == 0) - { //empty prefix, not qualified + { + // empty prefix, not qualified ns = string.Empty; } else { - ns = _thisNSResolver.LookupNamespace(attrPrefix); + ns = _thisNSResolver.LookupNamespace(attrPrefix)!; } + return GetAttributePSVI(attrLocalName, ns); } - private AttributePSVIInfo GetAttributePSVI(string localName, string ns) + private AttributePSVIInfo? GetAttributePSVI(string localName, string ns) { Debug.Assert(_coreReaderNameTable.Get(localName) != null); Debug.Assert(_coreReaderNameTable.Get(ns) != null); - AttributePSVIInfo attInfo = null; + AttributePSVIInfo? attInfo = null; for (int i = 0; i < _coreReaderAttributeCount; i++) { attInfo = _attributePSVINodes[i]; if (attInfo != null) - { //Will be null for invalid attributes + { + // Will be null for invalid attributes if (Ref.Equal(localName, attInfo.localName) && Ref.Equal(ns, attInfo.namespaceUri)) { _currentAttrIndex = i; @@ -2123,16 +2257,17 @@ private AttributePSVIInfo GetAttributePSVI(string localName, string ns) } } } + return null; } - private ValidatingReaderNodeData GetDefaultAttribute(string name, bool updatePosition) + private ValidatingReaderNodeData? GetDefaultAttribute(string name, bool updatePosition) { string attrLocalName; string attrPrefix; ValidateNames.SplitQName(name, out attrPrefix, out attrLocalName); - //Atomize + // Atomize attrPrefix = _coreReaderNameTable.Add(attrPrefix); attrLocalName = _coreReaderNameTable.Add(attrLocalName); string ns; @@ -2142,29 +2277,32 @@ private ValidatingReaderNodeData GetDefaultAttribute(string name, bool updatePos } else { - ns = _thisNSResolver.LookupNamespace(attrPrefix); + ns = _thisNSResolver.LookupNamespace(attrPrefix)!; } + return GetDefaultAttribute(attrLocalName, ns, updatePosition); } - private ValidatingReaderNodeData GetDefaultAttribute(string attrLocalName, string ns, bool updatePosition) + private ValidatingReaderNodeData? GetDefaultAttribute(string attrLocalName, string ns, bool updatePosition) { Debug.Assert(_coreReaderNameTable.Get(attrLocalName) != null); Debug.Assert(_coreReaderNameTable.Get(ns) != null); - ValidatingReaderNodeData defaultNode = null; + ValidatingReaderNodeData? defaultNode = null; for (int i = 0; i < _defaultAttributes.Count; i++) { - defaultNode = (ValidatingReaderNodeData)_defaultAttributes[i]; + defaultNode = (ValidatingReaderNodeData)_defaultAttributes[i]!; if (Ref.Equal(defaultNode.LocalName, attrLocalName) && Ref.Equal(defaultNode.Namespace, ns)) { if (updatePosition) { _currentAttrIndex = _coreReader.AttributeCount + i; } + return defaultNode; } } + return null; } @@ -2177,18 +2315,22 @@ private AttributePSVIInfo AddAttributePSVI(int attIndex) attInfo.Reset(); return attInfo; } + if (attIndex >= _attributePSVINodes.Length - 1) - { //reached capacity of PSVIInfo array, Need to increase capacity to twice the initial + { + // reached capacity of PSVIInfo array, Need to increase capacity to twice the initial AttributePSVIInfo[] newPSVINodes = new AttributePSVIInfo[_attributePSVINodes.Length * 2]; Array.Copy(_attributePSVINodes, newPSVINodes, _attributePSVINodes.Length); _attributePSVINodes = newPSVINodes; } + attInfo = _attributePSVINodes[attIndex]; if (attInfo == null) { attInfo = new AttributePSVIInfo(); _attributePSVINodes[attIndex] = attInfo; } + return attInfo; } @@ -2207,9 +2349,11 @@ private void ProcessInlineSchema() _attributeCount = _coreReaderAttributeCount = _coreReader.AttributeCount; } else - { //Clear attributes info if nodeType is not element + { + // Clear attributes info if nodeType is not element ClearAttributesInfo(); } + if (!_inlineSchemaParser.ParseReaderNode()) { _inlineSchemaParser.FinishParsing(); @@ -2228,8 +2372,7 @@ private object InternalReadContentAsObject() private object InternalReadContentAsObject(bool unwrapTypedValue) { - string str; - return InternalReadContentAsObject(unwrapTypedValue, out str); + return InternalReadContentAsObject(unwrapTypedValue, out _); } private object InternalReadContentAsObject(bool unwrapTypedValue, out string originalStringValue) @@ -2246,10 +2389,11 @@ private object InternalReadContentAsObject(bool unwrapTypedValue, out string ori originalStringValue = (schemaAttr.DefaultValue != null) ? schemaAttr.DefaultValue : schemaAttr.FixedValue; } - return ReturnBoxedValue(_attributePSVI.typedAttributeValue, AttributeSchemaInfo.XmlType, unwrapTypedValue); + return ReturnBoxedValue(_attributePSVI.typedAttributeValue, AttributeSchemaInfo.XmlType, unwrapTypedValue)!; } else - { //return string value + { + // return string value return this.Value; } } @@ -2257,7 +2401,7 @@ private object InternalReadContentAsObject(bool unwrapTypedValue, out string ori { if (_atomicValue != null) { - originalStringValue = _originalAtomicValueString; + originalStringValue = _originalAtomicValueString!; return _atomicValue; } @@ -2269,18 +2413,19 @@ private object InternalReadContentAsObject(bool unwrapTypedValue, out string ori } } else - { //Positioned on text, CDATA, PI, Comment etc + { + // Positioned on text, CDATA, PI, Comment etc if (_validator.CurrentContentType == XmlSchemaContentType.TextOnly) - { //if current element is of simple type - object value = ReturnBoxedValue(ReadTillEndElement(), _xmlSchemaInfo.XmlType, unwrapTypedValue); - originalStringValue = _originalAtomicValueString; + { + // if current element is of simple type + object? value = ReturnBoxedValue(ReadTillEndElement(), _xmlSchemaInfo.XmlType, unwrapTypedValue)!; + originalStringValue = _originalAtomicValueString!; return value; } else { - XsdCachingReader cachingReader = _coreReader as XsdCachingReader; - if (cachingReader != null) + if (_coreReader is XsdCachingReader cachingReader) { originalStringValue = cachingReader.ReadOriginalContentAsString(); } @@ -2294,23 +2439,23 @@ private object InternalReadContentAsObject(bool unwrapTypedValue, out string ori } } - private object InternalReadElementContentAsObject(out XmlSchemaType xmlType) + private object? InternalReadElementContentAsObject(out XmlSchemaType? xmlType) { return InternalReadElementContentAsObject(out xmlType, false); } - private object InternalReadElementContentAsObject(out XmlSchemaType xmlType, bool unwrapTypedValue) + private object? InternalReadElementContentAsObject(out XmlSchemaType? xmlType, bool unwrapTypedValue) { - string tmpString; - return InternalReadElementContentAsObject(out xmlType, unwrapTypedValue, out tmpString); + return InternalReadElementContentAsObject(out xmlType, unwrapTypedValue, out _); } - private object InternalReadElementContentAsObject(out XmlSchemaType xmlType, bool unwrapTypedValue, out string originalString) + private object? InternalReadElementContentAsObject(out XmlSchemaType? xmlType, bool unwrapTypedValue, out string? originalString) { Debug.Assert(this.NodeType == XmlNodeType.Element); - object typedValue = null; + object? typedValue = null; xmlType = null; - //If its an empty element, can have default/fixed value + + // If its an empty element, can have default/fixed value if (this.IsEmptyElement) { if (_xmlSchemaInfo.ContentType == XmlSchemaContentType.TextOnly) @@ -2321,17 +2466,20 @@ private object InternalReadElementContentAsObject(out XmlSchemaType xmlType, boo { typedValue = _atomicValue; } + originalString = _originalAtomicValueString; - xmlType = ElementXmlType; //Set this for default values + xmlType = ElementXmlType; // Set this for default values this.Read(); return typedValue; } + // move to content and read typed value this.Read(); if (this.NodeType == XmlNodeType.EndElement) - { //If IsDefault is true, the next node will be EndElement + { + // If IsDefault is true, the next node will be EndElement if (_xmlSchemaInfo.IsDefault) { if (_xmlSchemaInfo.ContentType == XmlSchemaContentType.TextOnly) @@ -2339,19 +2487,23 @@ private object InternalReadElementContentAsObject(out XmlSchemaType xmlType, boo typedValue = ReturnBoxedValue(_atomicValue, _xmlSchemaInfo.XmlType, unwrapTypedValue); } else - { //anyType has default value + { + // anyType has default value typedValue = _atomicValue; } + originalString = _originalAtomicValueString; } else - { //Empty content + { + // Empty content typedValue = string.Empty; originalString = string.Empty; } } else if (this.NodeType == XmlNodeType.Element) - { //the first child is again element node + { + // the first child is again element node throw new XmlException(SR.Xml_MixedReadElementContentAs, string.Empty, this as IXmlLineInfo); } else @@ -2364,7 +2516,8 @@ private object InternalReadElementContentAsObject(out XmlSchemaType xmlType, boo throw new XmlException(SR.Xml_MixedReadElementContentAs, string.Empty, this as IXmlLineInfo); } } - xmlType = ElementXmlType; //Set this as we are moving ahead to the next node + + xmlType = ElementXmlType; // Set this as we are moving ahead to the next node // move to next node this.Read(); @@ -2372,16 +2525,18 @@ private object InternalReadElementContentAsObject(out XmlSchemaType xmlType, boo return typedValue; } - private object ReadTillEndElement() + private object? ReadTillEndElement() { if (_atomicValue == null) { while (_coreReader.Read()) { if (_replayCache) - { //If replaying nodes in the cache, they have already been validated + { + // If replaying nodes in the cache, they have already been validated continue; } + switch (_coreReader.NodeType) { case XmlNodeType.Element: @@ -2407,33 +2562,41 @@ private object ReadTillEndElement() _originalAtomicValueString = GetOriginalAtomicValueStringOfElement(); if (_manageNamespaces) { + Debug.Assert(_nsManager != null); _nsManager.PopScope(); } + goto breakWhile; } + continue; breakWhile: break; } } else - { //atomicValue != null, meaning already read ahead - Switch reader + { + // atomicValue != null, meaning already read ahead - Switch reader if (_atomicValue == this) - { //switch back invalid marker; dont need it since coreReader moved to endElement + { + // switch back invalid marker; dont need it since coreReader moved to endElement _atomicValue = null; } + SwitchReader(); } + return _atomicValue; } private void SwitchReader() { - XsdCachingReader cachingReader = _coreReader as XsdCachingReader; - if (cachingReader != null) - { //Switch back without going over the cached contents again. + if (_coreReader is XsdCachingReader cachingReader) + { + // Switch back without going over the cached contents again. _coreReader = cachingReader.GetCoreReader(); } + Debug.Assert(_coreReader.NodeType == XmlNodeType.EndElement); _replayCache = false; } @@ -2466,15 +2629,20 @@ private void ReadAheadForMemberType() _atomicValue = _validator.ValidateEndElement(_xmlSchemaInfo); //?? pop namespaceManager scope _originalAtomicValueString = GetOriginalAtomicValueStringOfElement(); if (_atomicValue == null) - { //Invalid marker + { + // Invalid marker _atomicValue = this; } else if (_xmlSchemaInfo.IsDefault) - { //The atomicValue returned is a default value + { + // The atomicValue returned is a default value + Debug.Assert(_cachingReader != null); _cachingReader.SwitchTextNodeAndEndElement(_xmlSchemaInfo.XmlType.ValueConverter.ToString(_atomicValue), _originalAtomicValueString); } + goto breakWhile; } + continue; breakWhile: break; @@ -2483,12 +2651,15 @@ private void ReadAheadForMemberType() private void GetIsDefault() { - XsdCachingReader cachedReader = _coreReader as XsdCachingReader; + XsdCachingReader? cachedReader = _coreReader as XsdCachingReader; if (cachedReader == null && _xmlSchemaInfo.HasDefaultValue) - { //Get Isdefault + { + // Get Isdefault _coreReader = GetCachingReader(); + Debug.Assert(_cachingReader != null); if (_xmlSchemaInfo.IsUnionType && !_xmlSchemaInfo.IsNil) - { //If it also union, get the memberType as well + { + // If it also union, get the memberType as well ReadAheadForMemberType(); } else @@ -2519,9 +2690,11 @@ private void GetIsDefault() _atomicValue = _validator.ValidateEndElement(_xmlSchemaInfo); //?? pop namespaceManager scope _originalAtomicValueString = GetOriginalAtomicValueStringOfElement(); if (_xmlSchemaInfo.IsDefault) - { //The atomicValue returned is a default value + { + // The atomicValue returned is a default value _cachingReader.SwitchTextNodeAndEndElement(_xmlSchemaInfo.XmlType.ValueConverter.ToString(_atomicValue), _originalAtomicValueString); } + break; default: @@ -2529,6 +2702,7 @@ private void GetIsDefault() } } } + _cachingReader.SetToReplayMode(); _replayCache = true; } @@ -2540,39 +2714,46 @@ private void GetMemberType() { return; } - XsdCachingReader cachedReader = _coreReader as XsdCachingReader; + + XsdCachingReader? cachedReader = _coreReader as XsdCachingReader; if (cachedReader == null && _xmlSchemaInfo.IsUnionType && !_xmlSchemaInfo.IsNil) { _coreReader = GetCachingReader(); + Debug.Assert(_cachingReader != null); ReadAheadForMemberType(); _cachingReader.SetToReplayMode(); _replayCache = true; } } - private object ReturnBoxedValue(object typedValue, XmlSchemaType xmlType, bool unWrap) + private object? ReturnBoxedValue(object? typedValue, XmlSchemaType xmlType, bool unWrap) { if (typedValue != null) { if (unWrap) - { //convert XmlAtomicValue[] to object[] for list of unions; The other cases return typed value of the valueType anyway + { + // convert XmlAtomicValue[] to object[] for list of unions; The other cases return typed value of the valueType anyway Debug.Assert(xmlType != null && xmlType.Datatype != null); if (xmlType.Datatype.Variety == XmlSchemaDatatypeVariety.List) { - Datatype_List listType = xmlType.Datatype as Datatype_List; + Datatype_List? listType = xmlType.Datatype as Datatype_List; + Debug.Assert(listType != null); if (listType.ItemType.Variety == XmlSchemaDatatypeVariety.Union) { typedValue = xmlType.ValueConverter.ChangeType(typedValue, xmlType.Datatype.ValueType, _thisNSResolver); } } } + return typedValue; } else - { //return the original string value of the element or attribute + { + // return the original string value of the element or attribute Debug.Assert(NodeType != XmlNodeType.Attribute); typedValue = _validator.GetConcatenatedValue(); } + return typedValue; } @@ -2586,6 +2767,7 @@ private XsdCachingReader GetCachingReader() { _cachingReader.Reset(_coreReader); } + _lineInfo = _cachingReader as IXmlLineInfo; return _cachingReader; } @@ -2596,6 +2778,7 @@ internal ValidatingReaderNodeData CreateDummyTextNode(string attributeValue, int { _textNode = new ValidatingReaderNodeData(XmlNodeType.Text); } + _textNode.Depth = depth; _textNode.RawValue = attributeValue; return _textNode; @@ -2603,7 +2786,7 @@ internal ValidatingReaderNodeData CreateDummyTextNode(string attributeValue, int internal void CachingCallBack(XsdCachingReader cachingReader) { - _coreReader = cachingReader.GetCoreReader(); //re-switch the core-reader after caching reader is done + _coreReader = cachingReader.GetCoreReader(); // re-switch the core-reader after caching reader is done _lineInfo = cachingReader.GetLineInfo(); _replayCache = false; } @@ -2622,6 +2805,7 @@ private string GetOriginalAtomicValueStringOfElement() { return _validator.GetConcatenatedValue(); } + return string.Empty; } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XsdValidatingReaderAsync.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XsdValidatingReaderAsync.cs index 24b68ff01ddbad..a9953d2873af45 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XsdValidatingReaderAsync.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XsdValidatingReaderAsync.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.IO; using System.Text; using System.Xml.Schema; @@ -23,8 +24,10 @@ public override Task GetValueAsync() { if ((int)_validationState < 0) { + Debug.Assert(_cachedNode != null); return Task.FromResult(_cachedNode.RawValue); } + return _coreReader.GetValueAsync(); } @@ -44,8 +47,9 @@ public override async Task ReadContentAsStringAsync() { throw CreateReadContentAsException(nameof(ReadContentAsString)); } + object typedValue = await InternalReadContentAsObjectAsync().ConfigureAwait(false); - XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; + XmlSchemaType? xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) @@ -54,7 +58,7 @@ public override async Task ReadContentAsStringAsync() } else { - return typedValue as string; + return (typedValue as string)!; } } catch (InvalidCastException e) @@ -77,6 +81,7 @@ public override async Task ReadContentAsAsync(Type returnType, IXmlNames { throw CreateReadContentAsException(nameof(ReadContentAs)); } + string originalStringValue; var tuple_0 = await InternalReadContentAsObjectTupleAsync(false).ConfigureAwait(false); @@ -84,7 +89,7 @@ public override async Task ReadContentAsAsync(Type returnType, IXmlNames object typedValue = tuple_0.Item2; - XmlSchemaType xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; + XmlSchemaType? xmlType = NodeType == XmlNodeType.Attribute ? AttributeXmlType : ElementXmlType; try { if (xmlType != null) @@ -95,6 +100,7 @@ public override async Task ReadContentAsAsync(Type returnType, IXmlNames { typedValue = originalStringValue; } + return xmlType.ValueConverter.ChangeType(typedValue, returnType); } else @@ -134,12 +140,13 @@ public override async Task ReadElementContentAsStringAsync() { throw CreateReadElementContentAsException(nameof(ReadElementContentAsString)); } + XmlSchemaType xmlType; - var tuple_9 = await InternalReadElementContentAsObjectAsync().ConfigureAwait(false); - xmlType = tuple_9.Item1; + var content = await InternalReadElementContentAsObjectAsync().ConfigureAwait(false); + xmlType = content.Item1; - object typedValue = tuple_9.Item2; + object typedValue = content.Item2; try { @@ -149,6 +156,7 @@ public override async Task ReadElementContentAsStringAsync() } else { + Debug.Assert(false, $"{nameof(typedValue)} should never be null"); return typedValue as string; } } @@ -172,14 +180,15 @@ public override async Task ReadElementContentAsAsync(Type returnType, IX { throw CreateReadElementContentAsException(nameof(ReadElementContentAs)); } + XmlSchemaType xmlType; string originalStringValue; - var tuple_10 = await InternalReadElementContentAsObjectTupleAsync(false).ConfigureAwait(false); - xmlType = tuple_10.Item1; - originalStringValue = tuple_10.Item2; + var content = await InternalReadElementContentAsObjectTupleAsync(false).ConfigureAwait(false); + xmlType = content.Item1; + originalStringValue = content.Item2; - object typedValue = tuple_10.Item3; + object typedValue = content.Item3; try { @@ -191,6 +200,7 @@ public override async Task ReadElementContentAsAsync(Type returnType, IX { typedValue = originalStringValue; } + return xmlType.ValueConverter.ChangeType(typedValue, returnType, namespaceResolver); } else @@ -227,6 +237,7 @@ private Task ReadAsync_Read(Task task) { _validationState = ValidatingReaderState.EOF; } + return AsyncHelper.DoneTaskFalse; } } @@ -250,6 +261,7 @@ private async Task _ReadAsync_Read(Task task) { _validationState = ValidatingReaderState.EOF; } + return false; } } @@ -302,19 +314,21 @@ public override Task ReadAsync() goto case ValidatingReaderState.Read; } - case ValidatingReaderState.ReadAhead: //Will enter here on calling Skip() + case ValidatingReaderState.ReadAhead: // Will enter here on calling Skip() ClearAttributesInfo(); Task task = ProcessReaderEventAsync(); return ReadAsync_ReadAhead(task); case ValidatingReaderState.OnReadBinaryContent: _validationState = _savedState; + Debug.Assert(_readBinaryHelper != null); return _readBinaryHelper.FinishAsync().CallBoolTaskFuncWhenFinishAsync(thisRef => thisRef.ReadAsync(), this); case ValidatingReaderState.Init: _validationState = ValidatingReaderState.Read; if (_coreReader.ReadState == ReadState.Interactive) - { //If the underlying reader is already positioned on a ndoe, process it + { + // If the underlying reader is already positioned on a ndoe, process it return ProcessReaderEventAsync().ReturnTrueTaskWhenFinishAsync(); } else @@ -342,26 +356,29 @@ public override async Task SkipAsync() { break; } + bool callSkipToEndElem = true; - //If union and unionValue has been parsed till EndElement, then validator.ValidateEndElement has been called - //Hence should not call SkipToEndElement as the current context has already been popped in the validator + // If union and unionValue has been parsed till EndElement, then validator.ValidateEndElement has been called + // Hence should not call SkipToEndElement as the current context has already been popped in the validator if ((_xmlSchemaInfo.IsUnionType || _xmlSchemaInfo.IsDefault) && _coreReader is XsdCachingReader) { callSkipToEndElem = false; } + await _coreReader.SkipAsync().ConfigureAwait(false); _validationState = ValidatingReaderState.ReadAhead; if (callSkipToEndElem) { _validator.SkipToEndElement(_xmlSchemaInfo); } + break; case XmlNodeType.Attribute: MoveToElement(); goto case XmlNodeType.Element; } - //For all other NodeTypes Skip() same as Read() + // For all other NodeTypes Skip() same as Read() await ReadAsync().ConfigureAwait(false); return; } @@ -384,6 +401,7 @@ public override async Task ReadContentAsBase64Async(byte[] buffer, int inde _validationState = _savedState; // call to the helper + Debug.Assert(_readBinaryHelper != null); int readCount = await _readBinaryHelper.ReadContentAsBase64Async(buffer, index, count).ConfigureAwait(false); // set OnReadBinaryContent state again and return @@ -410,6 +428,7 @@ public override async Task ReadContentAsBinHexAsync(byte[] buffer, int inde _validationState = _savedState; // call to the helper + Debug.Assert(_readBinaryHelper != null); int readCount = await _readBinaryHelper.ReadContentAsBinHexAsync(buffer, index, count).ConfigureAwait(false); // set OnReadBinaryContent state again and return @@ -436,6 +455,7 @@ public override async Task ReadElementContentAsBase64Async(byte[] buffer, i _validationState = _savedState; // call to the helper + Debug.Assert(_readBinaryHelper != null); int readCount = await _readBinaryHelper.ReadElementContentAsBase64Async(buffer, index, count).ConfigureAwait(false); // set OnReadBinaryContent state again and return @@ -462,6 +482,7 @@ public override async Task ReadElementContentAsBinHexAsync(byte[] buffer, i _validationState = _savedState; // call to the helper + Debug.Assert(_readBinaryHelper != null); int readCount = await _readBinaryHelper.ReadElementContentAsBinHexAsync(buffer, index, count).ConfigureAwait(false); // set OnReadBinaryContent state again and return @@ -473,11 +494,13 @@ public override async Task ReadElementContentAsBinHexAsync(byte[] buffer, i private Task ProcessReaderEventAsync() { if (_replayCache) - { //if in replay mode, do nothing since nodes have been validated already - //If NodeType == XmlNodeType.EndElement && if manageNamespaces, may need to pop namespace scope, since scope is not popped in ReadAheadForMemberType + { + // if in replay mode, do nothing since nodes have been validated already + // If NodeType == XmlNodeType.EndElement && if manageNamespaces, may need to pop namespace scope, since scope is not popped in ReadAheadForMemberType return Task.CompletedTask; } + switch (_coreReader.NodeType) { case XmlNodeType.Element: @@ -523,7 +546,8 @@ private async Task ProcessElementEventAsync() _xmlSchemaInfo.Clear(); _attributeCount = _coreReaderAttributeCount = _coreReader.AttributeCount; if (!_coreReader.IsEmptyElement) - { //If its not empty schema, then parse else ignore + { + // If its not empty schema, then parse else ignore _inlineSchemaParser = new Parser(SchemaType.XSD, _coreReaderNameTable, _validator.SchemaSet.GetSchemaNames(_coreReaderNameTable), _validationEvent); await _inlineSchemaParser.StartParsingAsync(_coreReader, null).ConfigureAwait(false); _inlineSchemaParser.ParseReaderNode(); @@ -535,21 +559,25 @@ private async Task ProcessElementEventAsync() } } else - { //Validate element - //Clear previous data + { + // Validate element + // Clear previous data _atomicValue = null; _originalAtomicValueString = null; _xmlSchemaInfo.Clear(); if (_manageNamespaces) { + Debug.Assert(_nsManager != null); _nsManager.PushScope(); } - //Find Xsi attributes that need to be processed before validating the element - string xsiSchemaLocation = null; - string xsiNoNamespaceSL = null; - string xsiNil = null; - string xsiType = null; + + // Find Xsi attributes that need to be processed before validating the element + string? xsiSchemaLocation = null; + string? xsiNoNamespaceSL = null; + string? xsiNil = null; + string? xsiType = null; + if (_coreReader.MoveToFirstAttribute()) { do @@ -575,13 +603,16 @@ private async Task ProcessElementEventAsync() xsiNil = _coreReader.Value; } } + if (_manageNamespaces && Ref.Equal(_coreReader.NamespaceURI, _nsXmlNs)) { + Debug.Assert(_nsManager != null); _nsManager.AddNamespace(_coreReader.Prefix.Length == 0 ? string.Empty : _coreReader.LocalName, _coreReader.Value); } } while (_coreReader.MoveToNextAttribute()); _coreReader.MoveToElement(); } + _validator.ValidateElement(_coreReader.LocalName, _coreReader.NamespaceURI, _xmlSchemaInfo, xsiType, xsiNil, xsiSchemaLocation, xsiNoNamespaceSL); ValidateAttributes(); _validator.ValidateEndOfAttributes(_xmlSchemaInfo); @@ -589,6 +620,7 @@ private async Task ProcessElementEventAsync() { await ProcessEndElementEventAsync().ConfigureAwait(false); } + _validationState = ValidatingReaderState.ClearAttributes; } } @@ -598,10 +630,12 @@ private async Task ProcessEndElementEventAsync() _atomicValue = _validator.ValidateEndElement(_xmlSchemaInfo); _originalAtomicValueString = GetOriginalAtomicValueStringOfElement(); if (_xmlSchemaInfo.IsDefault) - { //The atomicValue returned is a default value + { + // The atomicValue returned is a default value Debug.Assert(_atomicValue != null); int depth = _coreReader.Depth; _coreReader = GetCachingReader(); + Debug.Assert(_cachingReader != null); _cachingReader.RecordTextNode(_xmlSchemaInfo.XmlType.ValueConverter.ToString(_atomicValue), _originalAtomicValueString, depth + 1, 0, 0); _cachingReader.RecordEndElementNode(); await _cachingReader.SetToReplayModeAsync().ConfigureAwait(false); @@ -609,6 +643,7 @@ private async Task ProcessEndElementEventAsync() } else if (_manageNamespaces) { + Debug.Assert(_nsManager != null); _nsManager.PopScope(); } } @@ -623,9 +658,11 @@ private async Task ProcessInlineSchemaAsync() _attributeCount = _coreReaderAttributeCount = _coreReader.AttributeCount; } else - { //Clear attributes info if nodeType is not element + { + // Clear attributes info if nodeType is not element ClearAttributesInfo(); } + if (!_inlineSchemaParser.ParseReaderNode()) { _inlineSchemaParser.FinishParsing(); @@ -644,9 +681,8 @@ private Task InternalReadContentAsObjectAsync() private async Task InternalReadContentAsObjectAsync(bool unwrapTypedValue) { - var tuple_11 = await InternalReadContentAsObjectTupleAsync(unwrapTypedValue).ConfigureAwait(false); - - return tuple_11.Item2; + var content = await InternalReadContentAsObjectTupleAsync(unwrapTypedValue).ConfigureAwait(false); + return content.Item2; } private async Task> InternalReadContentAsObjectTupleAsync(bool unwrapTypedValue) @@ -666,11 +702,12 @@ private async Task> InternalReadContentAsObjectTupleAsync( originalStringValue = (schemaAttr.DefaultValue != null) ? schemaAttr.DefaultValue : schemaAttr.FixedValue; } - tuple = new Tuple(originalStringValue, ReturnBoxedValue(_attributePSVI.typedAttributeValue, AttributeSchemaInfo.XmlType, unwrapTypedValue)); + tuple = new Tuple(originalStringValue, ReturnBoxedValue(_attributePSVI.typedAttributeValue, AttributeSchemaInfo.XmlType, unwrapTypedValue)!); return tuple; } else - { //return string value + { + // return string value tuple = new Tuple(originalStringValue, this.Value); return tuple; } @@ -679,6 +716,7 @@ private async Task> InternalReadContentAsObjectTupleAsync( { if (_atomicValue != null) { + Debug.Assert(_originalAtomicValueString != null); originalStringValue = _originalAtomicValueString; tuple = new Tuple(originalStringValue, _atomicValue); @@ -693,10 +731,15 @@ private async Task> InternalReadContentAsObjectTupleAsync( } } else - { //Positioned on text, CDATA, PI, Comment etc + { + // Positioned on text, CDATA, PI, Comment etc if (_validator.CurrentContentType == XmlSchemaContentType.TextOnly) - { //if current element is of simple type - object value = ReturnBoxedValue(await ReadTillEndElementAsync().ConfigureAwait(false), _xmlSchemaInfo.XmlType, unwrapTypedValue); + { + // if current element is of simple type + object? value = ReturnBoxedValue(await ReadTillEndElementAsync().ConfigureAwait(false), _xmlSchemaInfo.XmlType, unwrapTypedValue)!; + Debug.Assert(value != null); + + Debug.Assert(_originalAtomicValueString != null); originalStringValue = _originalAtomicValueString; tuple = new Tuple(originalStringValue, value); @@ -704,7 +747,7 @@ private async Task> InternalReadContentAsObjectTupleAsync( } else { - XsdCachingReader cachingReader = _coreReader as XsdCachingReader; + XsdCachingReader? cachingReader = _coreReader as XsdCachingReader; if (cachingReader != null) { originalStringValue = cachingReader.ReadOriginalContentAsString(); @@ -727,71 +770,77 @@ private Task> InternalReadElementContentAsObjectAsy private async Task> InternalReadElementContentAsObjectAsync(bool unwrapTypedValue) { - var tuple_13 = await InternalReadElementContentAsObjectTupleAsync(unwrapTypedValue).ConfigureAwait(false); + var content = await InternalReadElementContentAsObjectTupleAsync(unwrapTypedValue).ConfigureAwait(false); - return new Tuple(tuple_13.Item1, tuple_13.Item3); + return new Tuple(content.Item1, content.Item3); } private async Task> InternalReadElementContentAsObjectTupleAsync(bool unwrapTypedValue) { - Tuple tuple; - XmlSchemaType xmlType; + XmlSchemaType? xmlType = null; string originalString; Debug.Assert(this.NodeType == XmlNodeType.Element); - object typedValue = null; - xmlType = null; - //If its an empty element, can have default/fixed value + object typedValue; + // If its an empty element, can have default/fixed value if (this.IsEmptyElement) { if (_xmlSchemaInfo.ContentType == XmlSchemaContentType.TextOnly) { - typedValue = ReturnBoxedValue(_atomicValue, _xmlSchemaInfo.XmlType, unwrapTypedValue); + typedValue = ReturnBoxedValue(_atomicValue, _xmlSchemaInfo.XmlType, unwrapTypedValue)!; } else { - typedValue = _atomicValue; + typedValue = _atomicValue!; } + + Debug.Assert(_originalAtomicValueString != null); originalString = _originalAtomicValueString; - xmlType = ElementXmlType; //Set this for default values + xmlType = ElementXmlType; // Set this for default values await this.ReadAsync().ConfigureAwait(false); - tuple = new Tuple(xmlType, originalString, typedValue); - return tuple; + return new Tuple(xmlType, originalString, typedValue); } + // move to content and read typed value await this.ReadAsync().ConfigureAwait(false); if (this.NodeType == XmlNodeType.EndElement) - { //If IsDefault is true, the next node will be EndElement + { + // If IsDefault is true, the next node will be EndElement if (_xmlSchemaInfo.IsDefault) { if (_xmlSchemaInfo.ContentType == XmlSchemaContentType.TextOnly) { - typedValue = ReturnBoxedValue(_atomicValue, _xmlSchemaInfo.XmlType, unwrapTypedValue); + typedValue = ReturnBoxedValue(_atomicValue, _xmlSchemaInfo.XmlType, unwrapTypedValue)!; } else - { //anyType has default value - typedValue = _atomicValue; + { + // anyType has default value + typedValue = _atomicValue!; } + + Debug.Assert(_originalAtomicValueString != null); originalString = _originalAtomicValueString; } else - { //Empty content + { + // Empty content typedValue = string.Empty; originalString = string.Empty; } } else if (this.NodeType == XmlNodeType.Element) - { //the first child is again element node + { + // the first child is again element node throw new XmlException(SR.Xml_MixedReadElementContentAs, string.Empty, this as IXmlLineInfo); } else { - var tuple_14 = await InternalReadContentAsObjectTupleAsync(unwrapTypedValue).ConfigureAwait(false); - originalString = tuple_14.Item1; + var content = await InternalReadContentAsObjectTupleAsync(unwrapTypedValue).ConfigureAwait(false); + originalString = content.Item1; - typedValue = tuple_14.Item2; + typedValue = content.Item2; // ReadElementContentAsXXX cannot be called on mixed content, if positioned on node other than EndElement, Error if (this.NodeType != XmlNodeType.EndElement) @@ -799,25 +848,27 @@ private async Task> InternalReadElementCont throw new XmlException(SR.Xml_MixedReadElementContentAs, string.Empty, this as IXmlLineInfo); } } - xmlType = ElementXmlType; //Set this as we are moving ahead to the next node + + xmlType = ElementXmlType; // Set this as we are moving ahead to the next node // move to next node await this.ReadAsync().ConfigureAwait(false); - tuple = new Tuple(xmlType, originalString, typedValue); - return tuple; + return new Tuple(xmlType, originalString, typedValue); } - private async Task ReadTillEndElementAsync() + private async Task ReadTillEndElementAsync() { if (_atomicValue == null) { while (await _coreReader.ReadAsync().ConfigureAwait(false)) { if (_replayCache) - { //If replaying nodes in the cache, they have already been validated + { + // If replaying nodes in the cache, they have already been validated continue; } + switch (_coreReader.NodeType) { case XmlNodeType.Element: @@ -843,23 +894,30 @@ private async Task ReadTillEndElementAsync() _originalAtomicValueString = GetOriginalAtomicValueStringOfElement(); if (_manageNamespaces) { + Debug.Assert(_nsManager != null); _nsManager.PopScope(); } + goto breakWhile; } + continue; breakWhile: break; } } else - { //atomicValue != null, meaning already read ahead - Switch reader + { + // atomicValue != null, meaning already read ahead - Switch reader if (_atomicValue == this) - { //switch back invalid marker; dont need it since coreReader moved to endElement + { + // switch back invalid marker; dont need it since coreReader moved to endElement _atomicValue = null; } + SwitchReader(); } + return _atomicValue; } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Dom/XmlNodeReader.cs b/src/libraries/System.Private.Xml/src/System/Xml/Dom/XmlNodeReader.cs index e8290112ad0985..9d73bfa51103a8 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Dom/XmlNodeReader.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Dom/XmlNodeReader.cs @@ -919,7 +919,7 @@ internal string LookupPrefix(string namespaceName) { return _nameTable.Add("xml"); } - if (namespaceName == string.Empty) + if (namespaceName.Length == 0) { return string.Empty; } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/IXmlLineInfo.cs b/src/libraries/System.Private.Xml/src/System/Xml/IXmlLineInfo.cs index 3519ce454c523d..d1e7e15c7bdc93 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/IXmlLineInfo.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/IXmlLineInfo.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml { public interface IXmlLineInfo @@ -19,7 +20,7 @@ internal class PositionInfo : IXmlLineInfo public static PositionInfo GetPositionInfo(object o) { - IXmlLineInfo li = o as IXmlLineInfo; + IXmlLineInfo? li = o as IXmlLineInfo; if (li != null) { return new ReaderPositionInfo(li); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/IXmlNamespaceResolver.cs b/src/libraries/System.Private.Xml/src/System/Xml/IXmlNamespaceResolver.cs index 5b15ea77db09ff..83ff8c30b5bca7 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/IXmlNamespaceResolver.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/IXmlNamespaceResolver.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Collections; using System.Collections.Generic; @@ -23,7 +24,7 @@ public interface IXmlNamespaceResolver // The "xml" prefix is always mapped to the "http://www.w3.org/XML/1998/namespace" namespace. // The "xmlns" prefix is always mapped to the "http://www.w3.org/2000/xmlns/" namespace. // If the default namespace has not been defined, then the "" prefix is mapped to "" (the empty namespace). - string LookupNamespace(string prefix); + string? LookupNamespace(string prefix); // Return a prefix which is mapped to the specified namespace. Multiple prefixes can be mapped to the // same namespace, and it is undefined which prefix will be returned. Returns null if no prefixes are @@ -31,6 +32,6 @@ public interface IXmlNamespaceResolver // The "xml" prefix is always mapped to the "http://www.w3.org/XML/1998/namespace" namespace. // The "xmlns" prefix is always mapped to the "http://www.w3.org/2000/xmlns/" namespace. // If the default namespace has not been defined, then the "" prefix is mapped to "" (the empty namespace). - string LookupPrefix(string namespaceName); + string? LookupPrefix(string namespaceName); } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/NameTable.cs b/src/libraries/System.Private.Xml/src/System/Xml/NameTable.cs index cd2d200c1ae60c..0ee36591cc7d79 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/NameTable.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/NameTable.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Runtime.InteropServices; namespace System.Xml @@ -60,6 +61,7 @@ public override string Add(string key) { throw new ArgumentNullException(nameof(key)); } + int len = key.Length; if (len == 0) { @@ -75,6 +77,7 @@ public override string Add(string key) return e.str; } } + return AddEntry(key, hashCode); } @@ -100,7 +103,7 @@ public override string Add(char[] key, int start, int len) // Compatibility check for len < 0, just throw the same exception as new string(key, start, len) if (len < 0) { - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(len)); } int hashCode = ComputeHash32(key, start, len); @@ -112,18 +115,20 @@ public override string Add(char[] key, int start, int len) return e.str; } } + return AddEntry(new string(key, start, len), hashCode); } /// /// Find the matching string in the NameTable. /// - public override string Get(string value) + public override string? Get(string value) { if (value == null) { throw new ArgumentNullException(nameof(value)); } + if (value.Length == 0) { return string.Empty; @@ -138,6 +143,7 @@ public override string Get(string value) return e.str; } } + return null; } @@ -145,7 +151,7 @@ public override string Get(string value) /// Find the matching string atom given a range of /// characters. /// - public override string Get(char[] key, int start, int len) + public override string? Get(char[] key, int start, int len) { if (len == 0) { @@ -172,6 +178,7 @@ public override string Get(char[] key, int start, int len) return e.str; } } + return null; } @@ -203,10 +210,12 @@ private string AddEntry(string str, int hashCode) int index = hashCode & _mask; Entry e = new Entry(str, hashCode, _entries[index]); _entries[index] = e; + if (_count++ == _mask) { Grow(); } + return e.str; } @@ -240,6 +249,7 @@ private static bool TextEquals(string str1, char[] str2, int str2Start, int str2 { return false; } + // use array.Length to eliminate the range check for (int i = 0; i < str1.Length; i++) { @@ -250,6 +260,7 @@ private static bool TextEquals(string str1, char[] str2, int str2Start, int str2 } return true; } + private static int ComputeHash32(char[] key, int start, int len) { ReadOnlySpan bytes = MemoryMarshal.AsBytes(new ReadOnlySpan(key, start, len)); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/AutoValidator.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/AutoValidator.cs index 4ae13d948b8178..70f9dfa5833f36 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/AutoValidator.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/AutoValidator.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml.Schema { using System.Diagnostics; @@ -43,7 +44,7 @@ public override void Validate() public override void CompleteValidation() { } - public override object FindId(string name) + public override object? FindId(string name) { return null; } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/BaseValidator.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/BaseValidator.cs index c9f730028286fe..237d7639608851 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/BaseValidator.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/BaseValidator.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml.Schema { using System.IO; @@ -9,25 +10,26 @@ namespace System.Xml.Schema using System.Xml; using System.Text; using System.Collections; + using System.Diagnostics.CodeAnalysis; #pragma warning disable 618 internal class BaseValidator { - private readonly XmlSchemaCollection _schemaCollection; + private readonly XmlSchemaCollection? _schemaCollection; private readonly IValidationEventHandling _eventHandling; private readonly XmlNameTable _nameTable; - private SchemaNames _schemaNames; + private SchemaNames? _schemaNames; private readonly PositionInfo _positionInfo; - private XmlResolver _xmlResolver; - private Uri _baseUri; + private XmlResolver? _xmlResolver; + private Uri? _baseUri; - protected SchemaInfo schemaInfo; + protected SchemaInfo? schemaInfo; protected XmlValidatingReaderImpl reader; protected XmlQualifiedName elementName; - protected ValidationState context; - protected StringBuilder textValue; - protected string textString; + protected ValidationState? context; + protected StringBuilder? textValue; + protected string? textString; protected bool hasSibling; protected bool checkDatatype; @@ -44,7 +46,7 @@ public BaseValidator(BaseValidator other) elementName = other.elementName; } - public BaseValidator(XmlValidatingReaderImpl reader, XmlSchemaCollection schemaCollection, IValidationEventHandling eventHandling) + public BaseValidator(XmlValidatingReaderImpl reader, XmlSchemaCollection? schemaCollection, IValidationEventHandling eventHandling) { Debug.Assert(schemaCollection == null || schemaCollection.NameTable == reader.NameTable); this.reader = reader; @@ -60,7 +62,7 @@ public XmlValidatingReaderImpl Reader get { return reader; } } - public XmlSchemaCollection SchemaCollection + public XmlSchemaCollection? SchemaCollection { get { return _schemaCollection; } } @@ -78,6 +80,7 @@ public SchemaNames SchemaNames { return _schemaNames; } + if (_schemaCollection != null) { _schemaNames = _schemaCollection.GetSchemaNames(_nameTable); @@ -86,6 +89,7 @@ public SchemaNames SchemaNames { _schemaNames = new SchemaNames(_nameTable); } + return _schemaNames; } } @@ -95,13 +99,13 @@ public PositionInfo PositionInfo get { return _positionInfo; } } - public XmlResolver XmlResolver + public XmlResolver? XmlResolver { get { return _xmlResolver; } set { _xmlResolver = value; } } - public Uri BaseUri + public Uri? BaseUri { get { return _baseUri; } set { _baseUri = value; } @@ -112,7 +116,7 @@ public ValidationEventHandler EventHandler get { return (ValidationEventHandler)_eventHandling.EventHandler; } } - public SchemaInfo SchemaInfo + public SchemaInfo? SchemaInfo { get { @@ -124,7 +128,8 @@ public SchemaInfo SchemaInfo } } - public IDtdInfo DtdInfo + [DisallowNull] + public IDtdInfo? DtdInfo { get { @@ -132,11 +137,12 @@ public IDtdInfo DtdInfo } set { - SchemaInfo tmpSchemaInfo = value as SchemaInfo; + SchemaInfo? tmpSchemaInfo = value as SchemaInfo; if (tmpSchemaInfo == null) { throw new XmlException(SR.Xml_InternalError, string.Empty); } + this.schemaInfo = tmpSchemaInfo; } } @@ -157,13 +163,14 @@ public virtual void CompleteValidation() { } - public virtual object FindId(string name) + public virtual object? FindId(string name) { return null; } public void ValidateText() { + Debug.Assert(context != null); if (context.NeedValidateChildren) { if (context.IsNill) @@ -171,6 +178,7 @@ public void ValidateText() SendValidationEvent(SR.Sch_ContentInNill, XmlSchemaValidator.QNameString(context.LocalName, context.Namespace)); return; } + ContentValidator contentValidator = context.ElementDecl.ContentValidator; XmlSchemaContentType contentType = contentValidator.ContentType; if (contentType == XmlSchemaContentType.ElementOnly) @@ -190,6 +198,7 @@ public void ValidateText() { SendValidationEvent(SR.Sch_InvalidTextInEmpty, string.Empty); } + if (checkDatatype) { SaveTextValue(reader.Value); @@ -199,6 +208,7 @@ public void ValidateText() public void ValidateWhitespace() { + Debug.Assert(context != null); if (context.NeedValidateChildren) { XmlSchemaContentType contentType = context.ElementDecl.ContentValidator.ContentType; @@ -206,10 +216,12 @@ public void ValidateWhitespace() { SendValidationEvent(SR.Sch_ContentInNill, XmlSchemaValidator.QNameString(context.LocalName, context.Namespace)); } + if (contentType == XmlSchemaContentType.Empty) { SendValidationEvent(SR.Sch_InvalidWhitespaceInEmpty, string.Empty); } + if (checkDatatype) { SaveTextValue(reader.Value); @@ -219,17 +231,20 @@ public void ValidateWhitespace() private void SaveTextValue(string value) { + Debug.Assert(textString != null); if (textString.Length == 0) { textString = value; } else { + Debug.Assert(textValue != null); if (!hasSibling) { textValue.Append(textString); hasSibling = true; } + textValue.Append(value); } } @@ -278,8 +293,8 @@ protected void SendValidationEvent(XmlSchemaException e, XmlSeverityType severit protected static void ProcessEntity(SchemaInfo sinfo, string name, object sender, ValidationEventHandler eventhandler, string baseUri, int lineNumber, int linePosition) { - SchemaEntity en; - XmlSchemaException e = null; + SchemaEntity? en; + XmlSchemaException? e = null; if (!sinfo.GeneralEntities.TryGetValue(new XmlQualifiedName(name), out en)) { // validation error, see xml spec [68] @@ -289,6 +304,7 @@ protected static void ProcessEntity(SchemaInfo sinfo, string name, object sender { e = new XmlSchemaException(SR.Sch_UnparsedEntityRef, name, baseUri, lineNumber, linePosition); } + if (e != null) { if (eventhandler != null) @@ -304,8 +320,8 @@ protected static void ProcessEntity(SchemaInfo sinfo, string name, object sender protected static void ProcessEntity(SchemaInfo sinfo, string name, IValidationEventHandling eventHandling, string baseUriStr, int lineNumber, int linePosition) { - SchemaEntity en; - string errorResId = null; + SchemaEntity? en; + string? errorResId = null; if (!sinfo.GeneralEntities.TryGetValue(new XmlQualifiedName(name), out en)) { // validation error, see xml spec [68] @@ -330,7 +346,7 @@ protected static void ProcessEntity(SchemaInfo sinfo, string name, IValidationEv } } - public static BaseValidator CreateInstance(ValidationType valType, XmlValidatingReaderImpl reader, XmlSchemaCollection schemaCollection, IValidationEventHandling eventHandling, bool processIdentityConstraints) + public static BaseValidator? CreateInstance(ValidationType valType, XmlValidatingReaderImpl reader, XmlSchemaCollection schemaCollection, IValidationEventHandling eventHandling, bool processIdentityConstraints) { switch (valType) { @@ -352,6 +368,7 @@ public static BaseValidator CreateInstance(ValidationType valType, XmlValidating default: break; } + return null; } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/FacetChecker.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/FacetChecker.cs index fd0cffa6bc35dd..7be724ebc779b5 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/FacetChecker.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/FacetChecker.cs @@ -309,7 +309,7 @@ internal void CompileTotalDigitsFacet(XmlSchemaFacet facet) if ((_baseFixedFlags & RestrictionFlags.TotalDigits) != 0) { - if (!_datatype.IsEqual(_datatype.Restriction.TotalDigits, _derivedRestriction.TotalDigits)) + if (_datatype.Restriction.TotalDigits != _derivedRestriction.TotalDigits) { throw new XmlSchemaException(SR.Sch_FacetBaseFixed, facet); } @@ -334,11 +334,18 @@ internal void CompileFractionDigitsFacet(XmlSchemaFacet facet) { throw new XmlSchemaException(SR.Sch_FractionDigitsFacetInvalid, SR.Sch_FractionDigitsNotOnDecimal, facet); } + if ((_baseFixedFlags & RestrictionFlags.FractionDigits) != 0) + { + if (_datatype.Restriction.FractionDigits != _derivedRestriction.FractionDigits) + { + throw new XmlSchemaException(SR.Sch_FacetBaseFixed, facet); + } + } if ((_baseFlags & RestrictionFlags.FractionDigits) != 0) { if (_derivedRestriction.FractionDigits > _datatype.Restriction.FractionDigits) { - throw new XmlSchemaException(SR.Sch_TotalDigitsMismatch, string.Empty); + throw new XmlSchemaException(SR.Sch_FractionDigitsMismatch, string.Empty); } } SetFlag(facet, RestrictionFlags.FractionDigits); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/Inference/XmlSchemaInferenceException.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/Inference/XmlSchemaInferenceException.cs index cdcf3fec2d59bc..6a93ab03653667 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/Inference/XmlSchemaInferenceException.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/Inference/XmlSchemaInferenceException.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.IO; using System.Resources; @@ -29,15 +30,15 @@ public XmlSchemaInferenceException() : base(null) { } - public XmlSchemaInferenceException(string message) : base(message, ((Exception)null), 0, 0) + public XmlSchemaInferenceException(string message) : base(message, ((Exception?)null), 0, 0) { } - public XmlSchemaInferenceException(string message, Exception innerException) : base(message, innerException, 0, 0) + public XmlSchemaInferenceException(string message, Exception? innerException) : base(message, innerException, 0, 0) { } - public XmlSchemaInferenceException(string message, Exception innerException, int lineNumber, int linePosition) : + public XmlSchemaInferenceException(string message, Exception? innerException, int lineNumber, int linePosition) : base(message, innerException, lineNumber, linePosition) { } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/SchemaCollectionCompiler.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/SchemaCollectionCompiler.cs index 079a6e20f13430..56766e67a3d9f6 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/SchemaCollectionCompiler.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/SchemaCollectionCompiler.cs @@ -437,7 +437,7 @@ private void CompileSubstitutionGroup(XmlSchemaSubstitutionGroupV1Compat substit { if (examplar.FinalResolved == XmlSchemaDerivationMethod.All) { - SendValidationEvent(SR.Sch_InvalidExamplar, examplar); + SendValidationEvent(SR.Sch_InvalidExamplar, examplar.Name, examplar); } for (int i = 0; i < substitutionGroup.Members.Count; ++i) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/SchemaSetCompiler.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/SchemaSetCompiler.cs index db6b8b075f6b31..3f794a9dc54908 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/SchemaSetCompiler.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/SchemaSetCompiler.cs @@ -487,7 +487,7 @@ private void CompileSubstitutionGroup(XmlSchemaSubstitutionGroup substitutionGro { if (examplar.FinalResolved == XmlSchemaDerivationMethod.All) { - SendValidationEvent(SR.Sch_InvalidExamplar, examplar); + SendValidationEvent(SR.Sch_InvalidExamplar, examplar.Name, examplar); } //Build transitive members ArrayList newMembers = null; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaSet.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaSet.cs index c071cdaf6a699a..e9d9f7e9ad91f6 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaSet.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaSet.cs @@ -958,7 +958,7 @@ internal XmlSchema FindSchemaByNSAndUrl(Uri schemaUri, string ns, DictionaryEntr { return schema; } - else if (tns == string.Empty) + else if (tns.Length == 0) { //There could be a chameleon for same ns // It is OK to pass in the schema we have found so far, since it must have the schemaUri we're looking for // (we found it that way above) and it must be the original chameleon schema (the one without target ns) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaType.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaType.cs index 50e33a20c76256..c70077e05c69df 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaType.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaType.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Collections; using System.ComponentModel; using System.Xml.Serialization; @@ -13,15 +14,15 @@ namespace System.Xml.Schema /// public class XmlSchemaType : XmlSchemaAnnotated { - private string _name; + private string? _name; private XmlSchemaDerivationMethod _final = XmlSchemaDerivationMethod.None; private XmlSchemaDerivationMethod _derivedBy; - private XmlSchemaType _baseSchemaType; - private XmlSchemaDatatype _datatype; + private XmlSchemaType? _baseSchemaType; + private XmlSchemaDatatype? _datatype; private XmlSchemaDerivationMethod _finalResolved; - private volatile SchemaElementDecl _elementDecl; + private volatile SchemaElementDecl? _elementDecl; private volatile XmlQualifiedName _qname = XmlQualifiedName.Empty; - private XmlSchemaType _redefined; + private XmlSchemaType? _redefined; //compiled information private XmlSchemaContentType _contentType; @@ -35,6 +36,7 @@ public static XmlSchemaSimpleType GetBuiltInSimpleType(XmlQualifiedName qualifie { throw new ArgumentNullException(nameof(qualifiedName)); } + return DatatypeImplementation.GetSimpleTypeFromXsdType(qualifiedName); } @@ -49,32 +51,36 @@ public static XmlSchemaSimpleType GetBuiltInSimpleType(XmlTypeCode typeCode) /// /// [To be supplied.] /// - public static XmlSchemaComplexType GetBuiltInComplexType(XmlTypeCode typeCode) + public static XmlSchemaComplexType? GetBuiltInComplexType(XmlTypeCode typeCode) { if (typeCode == XmlTypeCode.Item) { return XmlSchemaComplexType.AnyType; } + return null; } /// /// [To be supplied.] /// - public static XmlSchemaComplexType GetBuiltInComplexType(XmlQualifiedName qualifiedName) + public static XmlSchemaComplexType? GetBuiltInComplexType(XmlQualifiedName qualifiedName) { if (qualifiedName == null) { throw new ArgumentNullException(nameof(qualifiedName)); } + if (qualifiedName.Equals(XmlSchemaComplexType.AnyType.QualifiedName)) { return XmlSchemaComplexType.AnyType; } + if (qualifiedName.Equals(XmlSchemaComplexType.UntypedAnyType.QualifiedName)) { return XmlSchemaComplexType.UntypedAnyType; } + return null; } @@ -82,7 +88,7 @@ public static XmlSchemaComplexType GetBuiltInComplexType(XmlQualifiedName qualif /// [To be supplied.] /// [XmlAttribute("name")] - public string Name + public string? Name { get { return _name; } set { _name = value; } @@ -121,7 +127,7 @@ public XmlSchemaDerivationMethod FinalResolved /// [XmlIgnore] [Obsolete("This property has been deprecated. Please use BaseXmlSchemaType property that returns a strongly typed base schema type. https://go.microsoft.com/fwlink/?linkid=14202")] - public object BaseSchemaType + public object? BaseSchemaType { get { @@ -132,6 +138,7 @@ public object BaseSchemaType { return _baseSchemaType.Datatype; } + return _baseSchemaType; } } @@ -140,7 +147,7 @@ public object BaseSchemaType /// [To be supplied.] /// [XmlIgnore] - public XmlSchemaType BaseXmlSchemaType + public XmlSchemaType? BaseXmlSchemaType { get { return _baseSchemaType; } } @@ -158,7 +165,7 @@ public XmlSchemaDerivationMethod DerivedBy /// [To be supplied.] /// [XmlIgnore] - public XmlSchemaDatatype Datatype + public XmlSchemaDatatype? Datatype { get { return _datatype; } } @@ -203,7 +210,7 @@ internal XmlValueConverter ValueConverter } } - internal XmlReader Validate(XmlReader reader, XmlResolver resolver, XmlSchemaSet schemaSet, ValidationEventHandler valEventHandler) + internal XmlReader? Validate(XmlReader reader, XmlResolver resolver, XmlSchemaSet schemaSet, ValidationEventHandler valEventHandler) { if (schemaSet != null) { @@ -213,6 +220,7 @@ internal XmlReader Validate(XmlReader reader, XmlResolver resolver, XmlSchemaSet readerSettings.ValidationEventHandler += valEventHandler; return new XsdValidatingReader(reader, resolver, readerSettings, this); } + return null; } @@ -249,14 +257,14 @@ internal void SetDatatype(XmlSchemaDatatype value) _datatype = value; } - internal SchemaElementDecl ElementDecl + internal SchemaElementDecl? ElementDecl { get { return _elementDecl; } set { _elementDecl = value; } } [XmlIgnore] - internal XmlSchemaType Redefined + internal XmlSchemaType? Redefined { get { return _redefined; } set { _redefined = value; } @@ -272,7 +280,7 @@ internal void SetContentType(XmlSchemaContentType value) _contentType = value; } - public static bool IsDerivedFrom(XmlSchemaType derivedType, XmlSchemaType baseType, XmlSchemaDerivationMethod except) + public static bool IsDerivedFrom(XmlSchemaType? derivedType, XmlSchemaType? baseType, XmlSchemaDerivationMethod except) { if (derivedType == null || baseType == null) { @@ -288,17 +296,19 @@ public static bool IsDerivedFrom(XmlSchemaType derivedType, XmlSchemaType baseTy { //Not checking for restriction blocked since all types are implicitly derived by restriction from xs:anyType return true; } + do { - XmlSchemaSimpleType dt = derivedType as XmlSchemaSimpleType; - XmlSchemaSimpleType bt = baseType as XmlSchemaSimpleType; + XmlSchemaSimpleType? dt = derivedType as XmlSchemaSimpleType; + XmlSchemaSimpleType? bt = baseType as XmlSchemaSimpleType; if (bt != null && dt != null) { //SimpleTypes if (bt == DatatypeImplementation.AnySimpleType) { //Not checking block=restriction return true; } - if ((except & derivedType.DerivedBy) != 0 || !dt.Datatype.IsDerivedFrom(bt.Datatype)) + + if ((except & derivedType.DerivedBy) != 0 || !dt.Datatype!.IsDerivedFrom(bt.Datatype)) { return false; } @@ -310,6 +320,7 @@ public static bool IsDerivedFrom(XmlSchemaType derivedType, XmlSchemaType baseTy { return false; } + derivedType = derivedType.BaseXmlSchemaType; if (derivedType == baseType) { @@ -332,7 +343,7 @@ internal static bool IsDerivedFromDatatype(XmlSchemaDatatype derivedDataType, Xm } [XmlIgnore] - internal override string NameAttribute + internal override string? NameAttribute { get { return Name; } set { Name = value; } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaUse.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaUse.cs index b39996f93f58b3..3f320dfdd36990 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaUse.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaUse.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml.Schema { using System.Xml.Serialization; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaValidator.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaValidator.cs index c94e06ccbd75a2..00f3c76b63e998 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaValidator.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaValidator.cs @@ -139,7 +139,7 @@ public sealed class XmlSchemaValidator private static readonly XmlSchemaDatatype s_dtStringArray = s_dtCDATA.DeriveByList(null); //Error message constants - private const string Quote = "'"; + private const char Quote = '\''; //Empty arrays private static readonly XmlSchemaParticle[] s_emptyParticleArray = Array.Empty(); @@ -735,6 +735,7 @@ public void GetUnspecifiedDefaultAttributes(ArrayList defaultAttributes) { throw new ArgumentNullException(nameof(defaultAttributes)); } + CheckStateTransition(ValidatorState.Attribute, "GetUnspecifiedDefaultAttributes"); GetUnspecifiedDefaultAttributes(defaultAttributes, false); } @@ -1066,6 +1067,7 @@ internal void GetUnspecifiedDefaultAttributes(ArrayList defaultAttributes, bool continue; } } + XmlSchemaDatatype datatype = attdef.Datatype; if (createNodeData) { @@ -1090,6 +1092,7 @@ internal void GetUnspecifiedDefaultAttributes(ArrayList defaultAttributes, bool { attrValidInfo.typedAttributeValue = attdef.DefaultValueTyped; } + attSchemaInfo.IsDefault = true; attSchemaInfo.Validity = XmlSchemaValidity.Valid; attSchemaInfo.SchemaType = attdef.SchemaType; @@ -1103,6 +1106,7 @@ internal void GetUnspecifiedDefaultAttributes(ArrayList defaultAttributes, bool { defaultAttributes.Add(attdef.SchemaAttribute); } + CheckTokenizedTypes(datatype, attdef.DefaultValueTyped, true); if (HasIdentityConstraints) { @@ -1111,7 +1115,6 @@ internal void GetUnspecifiedDefaultAttributes(ArrayList defaultAttributes, bool } } } - return; } internal XmlSchemaSet SchemaSet diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaValidity.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaValidity.cs index 6c3aaa9c82c276..2902fee222562c 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaValidity.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaValidity.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml.Schema { public enum XmlSchemaValidity diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSeverityType.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSeverityType.cs index d5d74ec1ab1904..2fc305eff8e0d9 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSeverityType.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSeverityType.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml.Schema { //UE Atention diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlTokenizedType.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlTokenizedType.cs index 9277fd46ce54cf..26c3b874d8a500 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlTokenizedType.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlTokenizedType.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml { // NOTE: Absolute numbering is utilized in DtdParser. -HelenaK diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlTypeCode.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlTypeCode.cs index 43ad4c8e3c98db..c39a138c968c51 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlTypeCode.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlTypeCode.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml.Schema { public enum XmlTypeCode diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdDuration.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdDuration.cs index 9a73084017a7c0..4567d8d1199118 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdDuration.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdDuration.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml.Schema { using System; @@ -40,7 +41,7 @@ public enum DurationType Duration, YearMonthDuration, DayTimeDuration, - }; + } /// /// Construct an XsdDuration from component parts. @@ -143,11 +144,12 @@ public XsdDuration(string s) : this(s, DurationType.Duration) public XsdDuration(string s, DurationType durationType) { XsdDuration result; - Exception exception = TryParse(s, durationType, out result); + Exception? exception = TryParse(s, durationType, out result); if (exception != null) { throw exception; } + _years = result.Years; _months = result.Months; _days = result.Days; @@ -159,6 +161,7 @@ public XsdDuration(string s, DurationType durationType) { _nanoseconds |= NegativeBit; } + return; } @@ -242,22 +245,23 @@ public TimeSpan ToTimeSpan() public TimeSpan ToTimeSpan(DurationType durationType) { TimeSpan result; - Exception exception = TryToTimeSpan(durationType, out result); + Exception? exception = TryToTimeSpan(durationType, out result); if (exception != null) { throw exception; } + return result; } - internal Exception TryToTimeSpan(out TimeSpan result) + internal Exception? TryToTimeSpan(out TimeSpan result) { return TryToTimeSpan(DurationType.Duration, out result); } - internal Exception TryToTimeSpan(DurationType durationType, out TimeSpan result) + internal Exception? TryToTimeSpan(DurationType durationType, out TimeSpan result) { - Exception exception = null; + Exception? exception = null; ulong ticks = 0; // Throw error if result cannot fit into a long @@ -426,14 +430,14 @@ internal string ToString(DurationType durationType) return sb.ToString(); } - internal static Exception TryParse(string s, out XsdDuration result) + internal static Exception? TryParse(string s, out XsdDuration result) { return TryParse(s, DurationType.Duration, out result); } - internal static Exception TryParse(string s, DurationType durationType, out XsdDuration result) + internal static Exception? TryParse(string s, DurationType durationType, out XsdDuration result) { - string errorCode; + string? errorCode; int length; int value, pos, numDigits; Parts parts = Parts.HasNone; @@ -605,6 +609,7 @@ internal static Exception TryParse(string s, DurationType durationType, out XsdD if ((parts & ~(XsdDuration.Parts.HasYears | XsdDuration.Parts.HasMonths)) != 0) goto InvalidFormat; } + return null; InvalidFormat: @@ -619,7 +624,7 @@ internal static Exception TryParse(string s, DurationType durationType, out XsdD /// cntDigits. The integer is returned (0 if no digits). If the digits cannot fit into an Int32: /// 1. If eatDigits is true, then additional digits will be silently discarded (don't count towards numDigits) /// 2. If eatDigits is false, an overflow exception is thrown - private static string TryParseDigits(string s, ref int offset, bool eatDigits, out int result, out int numDigits) + private static string? TryParseDigits(string s, ref int offset, bool eatDigits, out int result, out int numDigits) { int offsetStart = offset; int offsetEnd = s.Length; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/CodeGenerator.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/CodeGenerator.cs index f6f3bdd2140709..134812f5b80652 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/CodeGenerator.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/CodeGenerator.cs @@ -870,42 +870,7 @@ internal void Ldc(bool boolVar) internal void Ldc(int intVar) { - switch (intVar) - { - case -1: - _ilGen.Emit(OpCodes.Ldc_I4_M1); - break; - case 0: - _ilGen.Emit(OpCodes.Ldc_I4_0); - break; - case 1: - _ilGen.Emit(OpCodes.Ldc_I4_1); - break; - case 2: - _ilGen.Emit(OpCodes.Ldc_I4_2); - break; - case 3: - _ilGen.Emit(OpCodes.Ldc_I4_3); - break; - case 4: - _ilGen.Emit(OpCodes.Ldc_I4_4); - break; - case 5: - _ilGen.Emit(OpCodes.Ldc_I4_5); - break; - case 6: - _ilGen.Emit(OpCodes.Ldc_I4_6); - break; - case 7: - _ilGen.Emit(OpCodes.Ldc_I4_7); - break; - case 8: - _ilGen.Emit(OpCodes.Ldc_I4_8); - break; - default: - _ilGen.Emit(OpCodes.Ldc_I4, intVar); - break; - } + _ilGen.Emit(OpCodes.Ldc_I4, intVar); } internal void Ldc(long l) @@ -1000,27 +965,7 @@ internal void Ldarg(ArgBuilder arg) internal void Ldarg(int slot) { - switch (slot) - { - case 0: - _ilGen.Emit(OpCodes.Ldarg_0); - break; - case 1: - _ilGen.Emit(OpCodes.Ldarg_1); - break; - case 2: - _ilGen.Emit(OpCodes.Ldarg_2); - break; - case 3: - _ilGen.Emit(OpCodes.Ldarg_3); - break; - default: - if (slot <= 255) - _ilGen.Emit(OpCodes.Ldarg_S, slot); - else - _ilGen.Emit(OpCodes.Ldarg, slot); - break; - } + _ilGen.Emit(OpCodes.Ldarg, slot); } internal void Ldarga(ArgBuilder argBuilder) @@ -1030,10 +975,7 @@ internal void Ldarga(ArgBuilder argBuilder) internal void Ldarga(int slot) { - if (slot <= 255) - _ilGen.Emit(OpCodes.Ldarga_S, slot); - else - _ilGen.Emit(OpCodes.Ldarga, slot); + _ilGen.Emit(OpCodes.Ldarga, slot); } internal void Ldlen() diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManager.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManager.cs index 8ee06b15755d28..4cfd49358d8ac8 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManager.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManager.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.IO; using System.Net; @@ -10,7 +11,7 @@ namespace System.Xml { internal partial class XmlDownloadManager { - internal Stream GetStream(Uri uri, ICredentials credentials, IWebProxy proxy) + internal Stream GetStream(Uri uri, ICredentials? credentials, IWebProxy? proxy) { if (uri.Scheme == "file") { diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManagerAsync.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManagerAsync.cs index 4c51ff1e514f24..694ae92498859e 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManagerAsync.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManagerAsync.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.IO; using System.Net; @@ -12,7 +13,7 @@ namespace System.Xml { internal partial class XmlDownloadManager { - internal Task GetStreamAsync(Uri uri, ICredentials credentials, IWebProxy proxy) + internal Task GetStreamAsync(Uri uri, ICredentials? credentials, IWebProxy? proxy) { if (uri.Scheme == "file") { @@ -25,7 +26,7 @@ internal Task GetStreamAsync(Uri uri, ICredentials credentials, IWebProx } } - private async Task GetNonFileStreamAsync(Uri uri, ICredentials credentials, IWebProxy proxy) + private async Task GetNonFileStreamAsync(Uri uri, ICredentials? credentials, IWebProxy? proxy) { var handler = new HttpClientHandler(); using (var client = new HttpClient(handler)) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlException.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlException.cs index 96f0daf7bb5707..7e098be1f651cf 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/XmlException.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlException.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Resources; using System.Text; @@ -21,35 +22,35 @@ namespace System.Xml public class XmlException : SystemException { private readonly string _res; - private readonly string[] _args; // this field is not used, it's here just V1.1 serialization compatibility + private readonly string?[]? _args; // this field is not used, it's here just V1.1 serialization compatibility private readonly int _lineNumber; private readonly int _linePosition; - private readonly string _sourceUri; + private readonly string? _sourceUri; // message != null for V1 exceptions deserialized in Whidbey // message == null for V2 or higher exceptions; the exception message is stored on the base class (Exception._message) - private readonly string _message; + private readonly string? _message; protected XmlException(SerializationInfo info, StreamingContext context) : base(info, context) { - _res = (string)info.GetValue("res", typeof(string)); - _args = (string[])info.GetValue("args", typeof(string[])); - _lineNumber = (int)info.GetValue("lineNumber", typeof(int)); - _linePosition = (int)info.GetValue("linePosition", typeof(int)); + _res = (string)info.GetValue("res", typeof(string))!; + _args = (string?[])info.GetValue("args", typeof(string[]))!; + _lineNumber = (int)info.GetValue("lineNumber", typeof(int))!; + _linePosition = (int)info.GetValue("linePosition", typeof(int))!; // deserialize optional members _sourceUri = string.Empty; - string version = null; + string? version = null; foreach (SerializationEntry e in info) { switch (e.Name) { case "sourceUri": - _sourceUri = (string)e.Value; + _sourceUri = (string?)e.Value; break; case "version": - version = (string)e.Value; + version = (string?)e.Value; break; } } @@ -83,85 +84,83 @@ public XmlException() : this(null) } //provided to meet the ECMA standards - public XmlException(string message) : this(message, ((Exception)null), 0, 0) + public XmlException(string? message) : this(message, ((Exception?)null), 0, 0) { -#if DEBUG Debug.Assert(message == null || !message.StartsWith("Xml_", StringComparison.Ordinal), "Do not pass a resource here!"); -#endif } //provided to meet ECMA standards - public XmlException(string message, Exception innerException) : this(message, innerException, 0, 0) + public XmlException(string? message, Exception? innerException) : this(message, innerException, 0, 0) { } //provided to meet ECMA standards - public XmlException(string message, Exception innerException, int lineNumber, int linePosition) : + public XmlException(string? message, Exception? innerException, int lineNumber, int linePosition) : this(message, innerException, lineNumber, linePosition, null) { } - internal XmlException(string message, Exception innerException, int lineNumber, int linePosition, string sourceUri) : + internal XmlException(string? message, Exception? innerException, int lineNumber, int linePosition, string? sourceUri) : base(FormatUserMessage(message, lineNumber, linePosition), innerException) { HResult = HResults.Xml; _res = (message == null ? SR.Xml_DefaultException : SR.Xml_UserException); - _args = new string[] { message }; + _args = new string?[] { message }; _sourceUri = sourceUri; _lineNumber = lineNumber; _linePosition = linePosition; } - internal XmlException(string res, string[] args) : + internal XmlException(string res, string?[]? args) : this(res, args, null, 0, 0, null) { } - internal XmlException(string res, string arg) : - this(res, new string[] { arg }, null, 0, 0, null) + internal XmlException(string res, string? arg) : + this(res, new string?[] { arg }, null, 0, 0, null) { } - internal XmlException(string res, string arg, string sourceUri) : - this(res, new string[] { arg }, null, 0, 0, sourceUri) + internal XmlException(string res, string? arg, string? sourceUri) : + this(res, new string?[] { arg }, null, 0, 0, sourceUri) { } - internal XmlException(string res, string arg, IXmlLineInfo lineInfo) : - this(res, new string[] { arg }, lineInfo, null) + internal XmlException(string res, string? arg, IXmlLineInfo? lineInfo) : + this(res, new string?[] { arg }, lineInfo, null) { } - internal XmlException(string res, string arg, Exception innerException, IXmlLineInfo lineInfo) : - this(res, new string[] { arg }, innerException, (lineInfo == null ? 0 : lineInfo.LineNumber), (lineInfo == null ? 0 : lineInfo.LinePosition), null) + internal XmlException(string res, string? arg, Exception? innerException, IXmlLineInfo? lineInfo) : + this(res, new string?[] { arg }, innerException, (lineInfo == null ? 0 : lineInfo.LineNumber), (lineInfo == null ? 0 : lineInfo.LinePosition), null) { } - internal XmlException(string res, string[] args, IXmlLineInfo lineInfo) : + internal XmlException(string res, string?[]? args, IXmlLineInfo? lineInfo) : this(res, args, lineInfo, null) { } - internal XmlException(string res, string[] args, IXmlLineInfo lineInfo, string sourceUri) : + internal XmlException(string res, string?[]? args, IXmlLineInfo? lineInfo, string? sourceUri) : this(res, args, null, (lineInfo == null ? 0 : lineInfo.LineNumber), (lineInfo == null ? 0 : lineInfo.LinePosition), sourceUri) { } - internal XmlException(string res, string arg, int lineNumber, int linePosition) : - this(res, new string[] { arg }, null, lineNumber, linePosition, null) + internal XmlException(string res, string? arg, int lineNumber, int linePosition) : + this(res, new string?[] { arg }, null, lineNumber, linePosition, null) { } - internal XmlException(string res, string arg, int lineNumber, int linePosition, string sourceUri) : - this(res, new string[] { arg }, null, lineNumber, linePosition, sourceUri) + internal XmlException(string res, string? arg, int lineNumber, int linePosition, string? sourceUri) : + this(res, new string?[] { arg }, null, lineNumber, linePosition, sourceUri) { } - internal XmlException(string res, string[] args, int lineNumber, int linePosition) : + internal XmlException(string res, string?[]? args, int lineNumber, int linePosition) : this(res, args, null, lineNumber, linePosition, null) { } - internal XmlException(string res, string[] args, int lineNumber, int linePosition, string sourceUri) : + internal XmlException(string res, string?[]? args, int lineNumber, int linePosition, string? sourceUri) : this(res, args, null, lineNumber, linePosition, sourceUri) { } - internal XmlException(string res, string[] args, Exception innerException, int lineNumber, int linePosition) : + internal XmlException(string res, string?[]? args, Exception? innerException, int lineNumber, int linePosition) : this(res, args, innerException, lineNumber, linePosition, null) { } - internal XmlException(string res, string[] args, Exception innerException, int lineNumber, int linePosition, string sourceUri) : + internal XmlException(string res, string?[]? args, Exception? innerException, int lineNumber, int linePosition, string? sourceUri) : base(CreateMessage(res, args, lineNumber, linePosition), innerException) { HResult = HResults.Xml; @@ -172,7 +171,7 @@ internal XmlException(string res, string[] args, Exception innerException, int l _linePosition = linePosition; } - private static string FormatUserMessage(string message, int lineNumber, int linePosition) + private static string FormatUserMessage(string? message, int lineNumber, int linePosition) { if (message == null) { @@ -193,24 +192,18 @@ private static string FormatUserMessage(string message, int lineNumber, int line } } - private static string CreateMessage(string res, string[] args, int lineNumber, int linePosition) + private static string CreateMessage(string res, string?[]? args, int lineNumber, int linePosition) { try { - string message; + string message = (args == null) ? res : string.Format(res, args); - // No line information -> get resource string and return - if (lineNumber == 0) - { - message = (args == null) ? res : string.Format(res, args); - } // Line information is available -> we need to append it to the error message - else + if (lineNumber != 0) { string lineNumberStr = lineNumber.ToString(CultureInfo.InvariantCulture); string linePositionStr = linePosition.ToString(CultureInfo.InvariantCulture); - message = string.Format(res, args); message = SR.Format(SR.Xml_MessageWithErrorPosition, new string[] { message, lineNumberStr, linePositionStr }); } return message; @@ -273,7 +266,7 @@ public int LinePosition get { return _linePosition; } } - public string SourceUri + public string? SourceUri { get { return _sourceUri; } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlNameTable.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlNameTable.cs index 780707c57491b5..12a839ec29583f 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/XmlNameTable.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlNameTable.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml { /// @@ -17,7 +18,7 @@ public abstract class XmlNameTable /// Gets the atomized String object containing the same /// chars as the specified range of chars in the given char array. /// - public abstract string Get(char[] array, int offset, int length); + public abstract string? Get(char[] array, int offset, int length); /// /// @@ -25,7 +26,7 @@ public abstract class XmlNameTable /// value as the specified string. /// /// - public abstract string Get(string array); + public abstract string? Get(string array); /// /// Creates a new atom for the characters at the specified range diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlNamespacemanager.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlNamespacemanager.cs index 567bccca5d577d..3f1ff9f282ada0 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/XmlNamespacemanager.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlNamespacemanager.cs @@ -2,10 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Collections; using System.Diagnostics; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace System.Xml { @@ -14,7 +16,7 @@ public class XmlNamespaceManager : IXmlNamespaceResolver, IEnumerable private struct NamespaceDeclaration { public string prefix; - public string uri; + public string? uri; public int scopeId; public int previousNsIndex; @@ -28,24 +30,24 @@ public void Set(string prefix, string uri, int scopeId, int previousNsIndex) } // array with namespace declarations - private NamespaceDeclaration[] _nsdecls; + private NamespaceDeclaration[]? _nsdecls; // index of last declaration private int _lastDecl = 0; // name table - private readonly XmlNameTable _nameTable; + private readonly XmlNameTable? _nameTable; // ID (depth) of the current scope private int _scopeId; // hash table for faster lookup when there is lots of namespaces - private Dictionary _hashTable; + private Dictionary? _hashTable; private bool _useHashtable; // atomized prefixes for "xml" and "xmlns" - private readonly string _xml; - private readonly string _xmlNs; + private readonly string? _xml; + private readonly string? _xmlNs; // Constants private const int MinDeclsCountForHashtable = 16; @@ -69,7 +71,7 @@ public XmlNamespaceManager(XmlNameTable nameTable) _scopeId = 1; } - public virtual XmlNameTable NameTable + public virtual XmlNameTable? NameTable { get { @@ -81,7 +83,7 @@ public virtual string DefaultNamespace { get { - string defaultNs = LookupNamespace(string.Empty); + string? defaultNs = LookupNamespace(string.Empty); return (defaultNs == null) ? string.Empty : defaultNs; } } @@ -98,15 +100,21 @@ public virtual bool PopScope() { return false; } + + Debug.Assert(_nsdecls != null); + while (_nsdecls[decl].scopeId == _scopeId) { if (_useHashtable) { + Debug.Assert(_hashTable != null); _hashTable[_nsdecls[decl].prefix] = _nsdecls[decl].previousNsIndex; } + decl--; Debug.Assert(decl >= 2); } + _lastDecl = decl; _scopeId--; return true; @@ -120,6 +128,8 @@ public virtual void AddNamespace(string prefix, string uri) if (prefix == null) throw new ArgumentNullException(nameof(prefix)); + Debug.Assert(_nameTable != null); + Debug.Assert(_nsdecls != null); prefix = _nameTable.Add(prefix); uri = _nameTable.Add(uri); @@ -162,6 +172,7 @@ public virtual void AddNamespace(string prefix, string uri) // add to hashTable if (_useHashtable) { + Debug.Assert(_hashTable != null); _hashTable[prefix] = _lastDecl; } // or create a new hashTable if the threshold has been reached @@ -174,6 +185,7 @@ public virtual void AddNamespace(string prefix, string uri) { _hashTable[_nsdecls[i].prefix] = i; } + _useHashtable = true; } } @@ -189,6 +201,8 @@ public virtual void RemoveNamespace(string prefix, string uri) throw new ArgumentNullException(nameof(prefix)); } + Debug.Assert(_nsdecls != null); + int declIndex = LookupNamespaceDecl(prefix); while (declIndex != -1) { @@ -202,6 +216,8 @@ public virtual void RemoveNamespace(string prefix, string uri) public virtual IEnumerator GetEnumerator() { + Debug.Assert(_nsdecls != null); + Dictionary prefixes = new Dictionary(_lastDecl + 1); for (int thisDecl = 0; thisDecl <= _lastDecl; thisDecl++) { @@ -216,8 +232,10 @@ public virtual IEnumerator GetEnumerator() // This pragma disables a warning that the return type is not CLS-compliant, but generics are part of CLS in Whidbey. #pragma warning disable 3002 public virtual IDictionary GetNamespacesInScope(XmlNamespaceScope scope) - { #pragma warning restore 3002 + { + Debug.Assert(_nsdecls != null); + int i = 0; switch (scope) { @@ -241,8 +259,8 @@ public virtual IDictionary GetNamespacesInScope(XmlNamespaceScop Dictionary dict = new Dictionary(_lastDecl - i + 1); for (; i <= _lastDecl; i++) { - string prefix = _nsdecls[i].prefix; - string uri = _nsdecls[i].uri; + string? prefix = _nsdecls[i].prefix; + string? uri = _nsdecls[i].uri; Debug.Assert(prefix != null); if (uri != null) @@ -258,19 +276,24 @@ public virtual IDictionary GetNamespacesInScope(XmlNamespaceScop } } } + return dict; } - public virtual string LookupNamespace(string prefix) + public virtual string? LookupNamespace(string prefix) { + Debug.Assert(_nsdecls != null); int declIndex = LookupNamespaceDecl(prefix); return (declIndex == -1) ? null : _nsdecls[declIndex].uri; } private int LookupNamespaceDecl(string prefix) { + Debug.Assert(_nsdecls != null); + if (_useHashtable) { + Debug.Assert(_hashTable != null); int declIndex; if (_hashTable.TryGetValue(prefix, out declIndex)) { @@ -305,8 +328,10 @@ private int LookupNamespaceDecl(string prefix) return -1; } - public virtual string LookupPrefix(string uri) + public virtual string? LookupPrefix(string uri) { + Debug.Assert(_nsdecls != null); + // Don't assume that prefix is atomized for (int thisDecl = _lastDecl; thisDecl >= 0; thisDecl--) { @@ -324,12 +349,14 @@ public virtual string LookupPrefix(string uri) public virtual bool HasNamespace(string prefix) { + Debug.Assert(_nsdecls != null); + // Don't assume that prefix is atomized for (int thisDecl = _lastDecl; _nsdecls[thisDecl].scopeId == _scopeId; thisDecl--) { if (string.Equals(_nsdecls[thisDecl].prefix, prefix) && _nsdecls[thisDecl].uri != null) { - if (prefix.Length > 0 || _nsdecls[thisDecl].uri.Length > 0) + if (prefix.Length > 0 || _nsdecls[thisDecl].uri!.Length > 0) { return true; } @@ -339,7 +366,7 @@ public virtual bool HasNamespace(string prefix) return false; } - internal bool GetNamespaceDeclaration(int idx, out string prefix, out string uri) + internal bool GetNamespaceDeclaration(int idx, [NotNullWhen(true)] out string? prefix, out string? uri) { idx = _lastDecl - idx; if (idx < 0) @@ -348,6 +375,7 @@ internal bool GetNamespaceDeclaration(int idx, out string prefix, out string uri return false; } + Debug.Assert(_nsdecls != null); prefix = _nsdecls[idx].prefix; uri = _nsdecls[idx].uri; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlResolver.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlResolver.cs index 86e1c1a003b3f1..c54d7e687fa58c 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/XmlResolver.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlResolver.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Xml { using System; @@ -11,6 +12,7 @@ namespace System.Xml using System.Net; using System.Threading.Tasks; using System.Runtime.Versioning; + using System.Diagnostics; /// /// Resolves external XML resources named by a Uniform @@ -24,24 +26,25 @@ public abstract partial class XmlResolver /// URI to an Object containing the actual resource. /// - public abstract object GetEntity(Uri absoluteUri, - string role, - Type ofObjectToReturn); + public abstract object? GetEntity(Uri absoluteUri, + string? role, + Type? ofObjectToReturn); /// /// [To be supplied.] /// - public virtual Uri ResolveUri(Uri baseUri, string relativeUri) + public virtual Uri ResolveUri(Uri? baseUri, string? relativeUri) { if (baseUri == null || (!baseUri.IsAbsoluteUri && baseUri.OriginalString.Length == 0)) { - Uri uri = new Uri(relativeUri, UriKind.RelativeOrAbsolute); + Uri uri = new Uri(relativeUri!, UriKind.RelativeOrAbsolute); if (!uri.IsAbsoluteUri && uri.OriginalString.Length > 0) { - uri = new Uri(Path.GetFullPath(relativeUri)); + uri = new Uri(Path.GetFullPath(relativeUri!)); } + return uri; } else @@ -50,11 +53,13 @@ public virtual Uri ResolveUri(Uri baseUri, string relativeUri) { return baseUri; } + // relative base Uri if (!baseUri.IsAbsoluteUri) { throw new NotSupportedException(SR.Xml_RelativeUriNotSupported); } + return new Uri(baseUri, relativeUri); } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlUrlResolver.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlUrlResolver.cs index d2537bd5fb6471..83c8eccc4030c2 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/XmlUrlResolver.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlUrlResolver.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Threading; using System.Net; using System.Net.Cache; @@ -12,9 +13,9 @@ namespace System.Xml // Resolves external XML resources named by a Uniform Resource Identifier (URI). public partial class XmlUrlResolver : XmlResolver { - private static XmlDownloadManager s_downloadManager; - private ICredentials _credentials; - private IWebProxy _proxy; + private static XmlDownloadManager? s_downloadManager; + private ICredentials? _credentials; + private IWebProxy? _proxy; private static XmlDownloadManager DownloadManager => s_downloadManager ?? @@ -23,12 +24,12 @@ public partial class XmlUrlResolver : XmlResolver public XmlUrlResolver() { } - public override ICredentials Credentials + public override ICredentials? Credentials { set { _credentials = value; } } - public IWebProxy Proxy + public IWebProxy? Proxy { set { _proxy = value; } } @@ -39,7 +40,7 @@ public RequestCachePolicy CachePolicy } // Maps a URI to an Object containing the actual resource. - public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) + public override object? GetEntity(Uri absoluteUri, string? role, Type? ofObjectToReturn) { if (ofObjectToReturn is null || ofObjectToReturn == typeof(System.IO.Stream) || ofObjectToReturn == typeof(object)) { @@ -49,7 +50,7 @@ public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToRe throw new XmlException(SR.Xml_UnsupportedClass, string.Empty); } - public override Uri ResolveUri(Uri baseUri, string relativeUri) => + public override Uri ResolveUri(Uri? baseUri, string? relativeUri) => base.ResolveUri(baseUri, relativeUri); } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlUrlResolverAsync.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlUrlResolverAsync.cs index 53e3c97af007bd..290825d23c6a89 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/XmlUrlResolverAsync.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlUrlResolverAsync.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Runtime.Versioning; using System.Threading.Tasks; @@ -10,7 +11,7 @@ namespace System.Xml public partial class XmlUrlResolver : XmlResolver { // Maps a URI to an Object containing the actual resource. - public override async Task GetEntityAsync(Uri absoluteUri, string role, Type ofObjectToReturn) + public override async Task GetEntityAsync(Uri absoluteUri, string role, Type? ofObjectToReturn) { if (ofObjectToReturn == null || ofObjectToReturn == typeof(System.IO.Stream) || ofObjectToReturn == typeof(object)) { diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/GenerateHelper.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/GenerateHelper.cs index f8469b8c00831e..ab9890ee90ac48 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/GenerateHelper.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/GenerateHelper.cs @@ -609,30 +609,7 @@ public StaticDataManager StaticData /// public void LoadInteger(int intVal) { - OpCode opcode; - - if (intVal >= -1 && intVal < 9) - { - switch (intVal) - { - case -1: opcode = OpCodes.Ldc_I4_M1; break; - case 0: opcode = OpCodes.Ldc_I4_0; break; - case 1: opcode = OpCodes.Ldc_I4_1; break; - case 2: opcode = OpCodes.Ldc_I4_2; break; - case 3: opcode = OpCodes.Ldc_I4_3; break; - case 4: opcode = OpCodes.Ldc_I4_4; break; - case 5: opcode = OpCodes.Ldc_I4_5; break; - case 6: opcode = OpCodes.Ldc_I4_6; break; - case 7: opcode = OpCodes.Ldc_I4_7; break; - case 8: opcode = OpCodes.Ldc_I4_8; break; - default: Debug.Fail($"Unexpected int val {intVal}"); return; - } - Emit(opcode); - } - else if (intVal >= -128 && intVal <= 127) - Emit(OpCodes.Ldc_I4_S, (sbyte)intVal); - else - Emit(OpCodes.Ldc_I4, intVal); + Emit(OpCodes.Ldc_I4, intVal); } public void LoadBoolean(bool boolVal) @@ -697,26 +674,13 @@ public void LoadQueryOutput() public void LoadParameter(int paramPos) { - switch (paramPos) + if (paramPos <= ushort.MaxValue) { - case 0: Emit(OpCodes.Ldarg_0); break; - case 1: Emit(OpCodes.Ldarg_1); break; - case 2: Emit(OpCodes.Ldarg_2); break; - case 3: Emit(OpCodes.Ldarg_3); break; - default: - if (paramPos <= 255) - { - Emit(OpCodes.Ldarg_S, (byte)paramPos); - } - else if (paramPos <= ushort.MaxValue) - { - Emit(OpCodes.Ldarg, paramPos); - } - else - { - throw new XslTransformException(SR.XmlIl_TooManyParameters); - } - break; + Emit(OpCodes.Ldarg, paramPos); + } + else + { + throw new XslTransformException(SR.XmlIl_TooManyParameters); } } @@ -724,11 +688,7 @@ public void SetParameter(object paramId) { int paramPos = (int)paramId; - if (paramPos <= 255) - { - Emit(OpCodes.Starg_S, (byte)paramPos); - } - else if (paramPos <= ushort.MaxValue) + if (paramPos <= ushort.MaxValue) { Emit(OpCodes.Starg, (int)paramPos); } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryStaticData.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryStaticData.cs index df9cbd576e3c65..ec198b8c118604 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryStaticData.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryStaticData.cs @@ -82,7 +82,7 @@ public XmlQueryStaticData(byte[] data, Type[] ebTypes) int length; // Read a format version - int formatVersion = dataReader.ReadInt32Encoded(); + int formatVersion = dataReader.Read7BitEncodedInt(); // Changes in the major part of version are not supported if ((formatVersion & ~0xff) > CurrentFormatVersion) @@ -136,7 +136,7 @@ public XmlQueryStaticData(byte[] data, Type[] ebTypes) _filters = new Int32Pair[length]; for (int idx = 0; idx < length; idx++) { - _filters[idx] = new Int32Pair(dataReader.ReadInt32Encoded(), dataReader.ReadInt32Encoded()); + _filters[idx] = new Int32Pair(dataReader.Read7BitEncodedInt(), dataReader.Read7BitEncodedInt()); } } @@ -197,7 +197,7 @@ public void GetObjectData(out byte[] data, out Type[] ebTypes) XmlQueryDataWriter dataWriter = new XmlQueryDataWriter(dataStream); // First put the format version - dataWriter.WriteInt32Encoded(CurrentFormatVersion); + dataWriter.Write7BitEncodedInt(CurrentFormatVersion); // XmlWriterSettings defaultWriterSettings; _defaultWriterSettings.GetObjectData(dataWriter); @@ -259,8 +259,8 @@ public void GetObjectData(out byte[] data, out Type[] ebTypes) dataWriter.Write(_filters.Length); foreach (Int32Pair filter in _filters) { - dataWriter.WriteInt32Encoded(filter.Left); - dataWriter.WriteInt32Encoded(filter.Right); + dataWriter.Write7BitEncodedInt(filter.Left); + dataWriter.Write7BitEncodedInt(filter.Right); } } @@ -408,14 +408,6 @@ internal class XmlQueryDataReader : BinaryReader { public XmlQueryDataReader(Stream input) : base(input) { } - /// - /// Read in a 32-bit integer in compressed format. - /// - public int ReadInt32Encoded() - { - return Read7BitEncodedInt(); - } - /// /// Read a string value from the stream. Value can be null. /// @@ -446,14 +438,6 @@ internal class XmlQueryDataWriter : BinaryWriter { public XmlQueryDataWriter(Stream output) : base(output) { } - /// - /// Write a 32-bit integer in a compressed format. - /// - public void WriteInt32Encoded(int value) - { - Write7BitEncodedInt(value); - } - /// /// Write a string value to the stream. Value can be null. /// diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XsltOld/RecordBuilder.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XsltOld/RecordBuilder.cs index 4591f48c312779..a062c6adaebd38 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XsltOld/RecordBuilder.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XsltOld/RecordBuilder.cs @@ -43,7 +43,7 @@ internal sealed class RecordBuilder private const int HaveRecord = 2; // Record was fully generated private const char s_Minus = '-'; - private const string s_Space = " "; + private const char s_Space = ' '; private const string s_SpaceMinus = " -"; private const char s_Question = '?'; private const char s_Greater = '>'; @@ -655,7 +655,7 @@ private void AnalyzeComment() } else if (minus) { - _mainNode.ValueAppend(s_Space, false); + _mainNode.ValueAppend(" ", false); } } diff --git a/src/libraries/System.Private.Xml/tests/XmlDocument/System.Xml.XmlDocument.Tests.csproj b/src/libraries/System.Private.Xml/tests/XmlDocument/System.Xml.XmlDocument.Tests.csproj index a3beda715d3df9..b04baf688a7e0f 100644 --- a/src/libraries/System.Private.Xml/tests/XmlDocument/System.Xml.XmlDocument.Tests.csproj +++ b/src/libraries/System.Private.Xml/tests/XmlDocument/System.Xml.XmlDocument.Tests.csproj @@ -3,9 +3,8 @@ $(NetCoreAppCurrent) - - Common\System\ShouldNotBeInvokedException.cs - + diff --git a/src/libraries/System.Private.Xml/tests/XmlReader/Tests/System.Xml.RW.XmlReader.Tests.csproj b/src/libraries/System.Private.Xml/tests/XmlReader/Tests/System.Xml.RW.XmlReader.Tests.csproj index b28cbb68ef06ea..d14c1e04b7e7a5 100644 --- a/src/libraries/System.Private.Xml/tests/XmlReader/Tests/System.Xml.RW.XmlReader.Tests.csproj +++ b/src/libraries/System.Private.Xml/tests/XmlReader/Tests/System.Xml.RW.XmlReader.Tests.csproj @@ -7,8 +7,7 @@ - - Common\System\Threading\TrackingSynchronizationContext.cs - + \ No newline at end of file diff --git a/src/libraries/System.Private.Xml/tests/XmlSchema/XmlSchemaSet/System.Xml.XmlSchemaSet.Tests.csproj b/src/libraries/System.Private.Xml/tests/XmlSchema/XmlSchemaSet/System.Xml.XmlSchemaSet.Tests.csproj index c7b6e43f2f4ab6..4e06985c52e555 100644 --- a/src/libraries/System.Private.Xml/tests/XmlSchema/XmlSchemaSet/System.Xml.XmlSchemaSet.Tests.csproj +++ b/src/libraries/System.Private.Xml/tests/XmlSchema/XmlSchemaSet/System.Xml.XmlSchemaSet.Tests.csproj @@ -34,9 +34,8 @@ - - Common\System\IO\TempDirectory.cs - + + + + + + + + + + + + + +"; + + XmlSchemaSet ss = new XmlSchemaSet(); + ss.Add(null, XmlReader.Create(new StringReader(schema))); + + Exception ex = Assert.Throws(() => ss.Compile()); + Assert.Contains("fractionDigits", ex.Message); + Assert.DoesNotContain("totalDigits", ex.Message); + } + + [Fact] + [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] + public void FractionDigitsFacetBaseFixed_Throws() + { + string schema = @" + + + + + + + + + + + + +"; + XmlSchemaSet ss = new XmlSchemaSet(); + ss.Add(null, XmlReader.Create(new StringReader(schema))); + + Exception ex = Assert.Throws(() => ss.Compile()); + Assert.Contains("fixed", ex.Message); + } + + [Fact] + public void MinLengthLtBaseMinLength_Throws() + { + string schema = @" + + + + + + + + + + + + +"; + + XmlSchemaSet ss = new XmlSchemaSet(); + ss.Add(null, XmlReader.Create(new StringReader(schema))); + + Exception ex = Assert.Throws(() => ss.Compile()); + Assert.Contains("minLength", ex.Message); + } + + [Fact] + public void MaxLengthGtBaseMaxLength_Throws() + { + string schema = @" + + + + + + + + + + + + +"; + + XmlSchemaSet ss = new XmlSchemaSet(); + ss.Add(null, XmlReader.Create(new StringReader(schema))); + + Exception ex = Assert.Throws(() => ss.Compile()); + Assert.Contains("maxLength", ex.Message); + } + + #region "Testing presence of minLength or maxLength and Length" + + public static IEnumerable MaxMinLengthBaseLength_ThrowsData + { + get + { + return new List() + { + new object[] + { // minLength and length specified in same derivation step. + @" + + + + + + + + +" + }, + new object[] + { // maxLength and length specified in same derivation step. + @" + + + + + + + + +" + }, + new object[] + { // base type has minLength; derived type has lesser length + @" + + + + + + + + + + + + +" + }, + new object[] + { // base type has maxLength; derived type has greater length + @" + + + + + + + + + + + + +" + }, + new object[] + { // base type has length; derived type has lesser maxLength + @" + + + + + + + + + + + + +" + }, + new object[] + { // base type has length; derived type has greater minLength + @" + + + + + + + + + + + + +" + }, + new object[] + { // base type has maxLength; derived type has greater length + @" + + + + + + + + + + + + +" + } + }; + } + } + + [Theory] + [MemberData(nameof(MaxMinLengthBaseLength_ThrowsData))] + public void MaxMinLengthBaseLength_Throws(string schema) + { + XmlSchemaSet ss = new XmlSchemaSet(); + ss.Add(null, XmlReader.Create(new StringReader(schema))); + + Exception ex = Assert.Throws(() => ss.Compile()); + + Assert.Contains("length", ex.Message); + Assert.Contains("minLength", ex.Message); + Assert.Contains("maxLength", ex.Message); + } + + [Fact] + public void MinLengthGtMaxLength_Throws() + { + string schema = @" + + + + + + + + +"; + XmlSchemaSet ss = new XmlSchemaSet(); + ss.Add(null, XmlReader.Create(new StringReader(schema))); + + Exception ex = Assert.Throws(() => ss.Compile()); + + Assert.Contains("minLength", ex.Message); + Assert.Contains("maxLength", ex.Message); + } + + public static IEnumerable MaxMinLengthBaseLength_Success_TestData + { + get + { + return new List() + { + new object[] + { // base type has length; derived type has equal maxLength + @" + + + + + + + + + + + + +" + }, + new object[] + { // base type has length; derived type has greater maxLength + @" + + + + + + + + + + + + +" + }, + new object[] + { // base type has length; derived type has equal minLength + @" + + + + + + + + + + + + +" + }, + new object[] + { // base type has length; derived type has lesser minLength + @" + + + + + + + + + + + + +" + }, + new object[] + { // base type has minLength; derived type has equal length + @" + + + + + + + + + + + + +" + }, + new object[] + { // base type has minLength; derived type has greater length + @" + + + + + + + + + + + + +" + }, + new object[] + { // base type has maxLength; derived type has equal length + @" + + + + + + + + + + + + +" + }, + new object[] + { // base type has maxLength; derived type has lesser length + @" + + + + + + + + + + + + +" + }, + new object[] + { // minLength is equal to maxLength + @" + + + + + + + + +" + }, + new object[] + { // minLength is less than maxLength + @" + + + + + + + + +" + } + }; + } + } + + [Theory] + [MemberData(nameof(MaxMinLengthBaseLength_Success_TestData))] + public void MaxMinLengthBaseLength_Test(string schema) + { + XmlSchemaSet ss = new XmlSchemaSet(); + ss.Add(null, XmlReader.Create(new StringReader(schema))); + + ss.Compile(); + + Assert.True(true); + } + #endregion + + [Fact] + public void LengthGtBaseLength_Throws() + { + string schema = @" + + + + + + + + + + + + +"; + + XmlSchemaSet ss = new XmlSchemaSet(); + ss.Add(null, XmlReader.Create(new StringReader(schema))); + + Exception ex = Assert.Throws(() => ss.Compile()); + + Assert.Contains("length", ex.Message); + } + + #region FacetBaseFixed tests + public static IEnumerable FacetBaseFixed_Throws_TestData + { + get{ + return new List() + { + new object[] + { // length, derived type has larger value. + @" + + + + + + + + + + + + +" + }, + new object[] + { // length, derived type has smaller value + @" + + + + + + + + + + + + +" + }, + new object[] + { // minLength, derived type has larger value. + @" + + + + + + + + + + + + +" + }, + new object[] + { // minLength, derived type has smaller value. + @" + + + + + + + + + + + + +" + }, + new object[] + { // maxLength, derived type has lower value. + @" + + + + + + + + + + + + +" + }, + new object[] + { // maxLength, derived type has larger value. + @" + + + + + + + + + + + + +" + }, + new object[] + { // whiteSpace + @" + + + + + + + + + + + + +" + }, + new object[] + { // maxInclusive, derived type with larger value + @" + + + + + + + + + + + + +" + }, + new object[] + { // maxInclusive, derived type with smaller value + @" + + + + + + + + + + + + +" + }, + new object[] + { // maxExclusive, derived type has larger value + @" + + + + + + + + + + + + +" + }, + new object[] + { // maxExclusive, derived type has smaller value + @" + + + + + + + + + + + + +" + }, + new object[] + { // minExclusive, derived type has larger value + @" + + + + + + + + + + + + +" + }, + new object[] + { // minExclusive, derived type has smaller value + @" + + + + + + + + + + + + +" + }, + new object[] + { // minInclusive, derived type has larger value + @" + + + + + + + + + + + + +" + }, + new object[] + { // minInclusive, derived type has smaller value + @" + + + + + + + + + + + + +" + } + }; + } + } + + [Theory] + [MemberData(nameof(FacetBaseFixed_Throws_TestData))] + public void FacetBaseFixed_Throws(string schema) + { + XmlSchemaSet ss = new XmlSchemaSet(); + ss.Add(null, XmlReader.Create(new StringReader(schema))); + + Exception ex = Assert.Throws(() => ss.Compile()); + Assert.Contains("fixed='true'", ex.Message); + } + #endregion + + [Fact] + public void InvalidAllMax_Throws() + { + string schema = @" + + + + + + + + +"; + XmlReader xr; + xr = XmlReader.Create(new StringReader(schema)); + XmlSchemaSet ss = new XmlSchemaSet(); + + Exception ex = Assert.Throws(() => ss.Add(null, xr)); + + Assert.Contains("all", ex.Message); + } + + [Fact] + public void InvalidAllElementMax_Throws() + { + string schema = @" + + + + + + + + +"; + XmlReader xr; + xr = XmlReader.Create(new StringReader(schema)); + XmlSchemaSet ss = new XmlSchemaSet(); + + Exception ex = Assert.Throws(() => ss.Add(null, xr)); + + Assert.Contains("all", ex.Message); + Assert.Contains("maxOccurs", ex.Message); + } + + [Fact] + public void InvalidExemplar_Throws() + { + string schema = @" + + + + + + + + + + +"; + + XmlReader xr; + xr = XmlReader.Create(new StringReader(schema)); + XmlSchemaSet ss = new XmlSchemaSet(); + ss.Add(null, xr); + + Exception ex = Assert.Throws(() => ss.Compile()); + + Assert.Contains("substitutionGroup", ex.Message); + Assert.Contains("person", ex.Message); + } + + [Fact] + public void GroupBaseRestNotEmptiable_Throws() + { + string schema = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + XmlSchemaSet ss = new XmlSchemaSet(); + ss.Add(null, XmlReader.Create(new StringReader(schema))); + + Exception ex = Assert.Throws(() => ss.Compile()); + + Assert.Contains("particle", ex.Message); + } + + #region test throwing of XmlSchemaException with message Sch_AllRefMinMax + public static IEnumerable AllRefMinMax_Throws_TestData + { + get + { + return new List() + { + new object[] + { // invalid value for minOccurs and maxOccurs +@" + + + + + + + + + + + + + +" + }, + new object[] + { // maxOccurs too large +@" + + + + + + + + + + + + + +" + } + }; + } + } + + [Theory] + [MemberData(nameof(AllRefMinMax_Throws_TestData))] + public void AllRefMinMax_Throws(string schema) + { + XmlSchemaSet ss = new XmlSchemaSet(); + ss.Add(null, XmlReader.Create(new StringReader(schema))); + + Exception ex = Assert.Throws(() => ss.Compile()); + + Assert.Contains("all", ex.Message); + Assert.Contains("minOccurs", ex.Message); + Assert.Contains("maxOccurs", ex.Message); + } + #endregion + + [Fact] + [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] + public void TotalDigitsParseValue_Succeeds() + { + string schema = @" + + + + + + + + + + + + +"; + using (StringReader srdr = new StringReader(schema)) + using (XmlReader xmlrdr = XmlReader.Create(srdr)) + { + XmlSchemaSet ss = new XmlSchemaSet(); + + ss.Add(null, xmlrdr); + + // Assert does not throw (Regression test for issue #34426) + ss.Compile(); + } + } + + #region tests causing XmlSchemaException with Sch_WhiteSpaceRestriction1 + public static IEnumerable WhiteSpaceRestriction1_Throws_TestData + { + get + { + return new List() + { + new object[] + { +@" + + + + + + + + + + + + +" + }, + new object[] + { +@" + + + + + + + + + + + + +" + } + }; + } + } + + [Theory] + [MemberData(nameof(WhiteSpaceRestriction1_Throws_TestData))] + public void WhiteSpaceRestriction1_Throws(string schema) + { + XmlSchemaSet ss = new XmlSchemaSet(); + using (StringReader sr = new StringReader(schema)) + using (XmlReader xmlrdr = XmlReader.Create(sr)) + { + ss.Add(null, xmlrdr); + } + + Exception ex = Assert.Throws(() => ss.Compile()); + + Assert.Contains("whiteSpace", ex.Message); + Assert.Contains("collapse", ex.Message); + Assert.Contains("preserve", ex.Message); + Assert.Contains("replace", ex.Message); + } + #endregion + + #region tests causing XmlSchemaException with Sch_WhiteSpaceRestriction2 + public static IEnumerable WhiteSpaceRestriction2_Throws_TestData + { + get + { + return new List() + { + new object[] + { +@" + + + + + + + + + + + + +" + } + }; + } + } + + [Theory] + [MemberData(nameof(WhiteSpaceRestriction2_Throws_TestData))] + public void WhiteSpaceRestriction2_Throws(string schema) + { + XmlSchemaSet ss = new XmlSchemaSet(); + using (StringReader sr = new StringReader(schema)) + using (XmlReader xmlrdr = XmlReader.Create(sr)) + { + ss.Add(null, xmlrdr); + } + + Exception ex = Assert.Throws(() => ss.Compile()); + + Assert.Contains("whiteSpace", ex.Message); + Assert.DoesNotContain("collapse", ex.Message); + Assert.Contains("preserve", ex.Message); + Assert.Contains("replace", ex.Message); + } + #endregion + + #region Attribute Restriction Invalid From WildCard tests + + public static IEnumerable AttributeRestrictionInvalidFromWildCard_Throws_TestData + { + get + { + return new List() + { + new object[] + { + @" + + + + + + + + + + + +" + }, + new object[] + { + @" + + + + + + + + + + + +" + } + }; + } + } + + [Theory] + [MemberData(nameof(AttributeRestrictionInvalidFromWildCard_Throws_TestData))] + public void AttributeRestrictionInvalidFromWildCard_Throws(string schema) + { + XmlSchemaSet ss = new XmlSchemaSet(); + ss.XmlResolver = new FakeXmlResolverAttributeRestriction(); + using (StringReader sr = new StringReader(schema)) + using (XmlReader xmlrdr = XmlReader.Create(sr)) + { + ss.Add(null, xmlrdr); + } + + Exception ex = Assert.Throws(() => ss.Compile()); + + Assert.Contains("wildcard", ex.Message); + Assert.Contains("redefine", ex.Message); + } + + private class FakeXmlResolverAttributeRestriction : XmlResolver + { + public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) + { + int uriIndex = int.Parse(absoluteUri.Host); + string[] schema = { @" + + + + + + + +", +@" + + + + + + + + +" + }; + + return new MemoryStream(Encoding.UTF8.GetBytes(schema[uriIndex])); + } + } + #endregion } } diff --git a/src/libraries/System.Private.Xml/tests/XmlSchema/XmlSchemaValidatorApi/System.Xml.XmlSchema.XmlSchemaValidatorApi.Tests.csproj b/src/libraries/System.Private.Xml/tests/XmlSchema/XmlSchemaValidatorApi/System.Xml.XmlSchema.XmlSchemaValidatorApi.Tests.csproj index b79f7360072da4..044af4bed95eba 100644 --- a/src/libraries/System.Private.Xml/tests/XmlSchema/XmlSchemaValidatorApi/System.Xml.XmlSchema.XmlSchemaValidatorApi.Tests.csproj +++ b/src/libraries/System.Private.Xml/tests/XmlSchema/XmlSchemaValidatorApi/System.Xml.XmlSchema.XmlSchemaValidatorApi.Tests.csproj @@ -20,9 +20,8 @@ - - Common\System\IO\TempDirectory.cs - + ", ReadAsString(stream1.GetBuffer(), stream1.Length)); + Assert.Equal(@"", ReadAsString(stream2.GetBuffer(), stream2.Length)); + Assert.Equal(@"", ReadAsString(stream3.GetBuffer(), stream3.Length)); + } + } + + private static string ReadAsString(byte[] bytes, long length) => Encoding.UTF8.GetString(bytes, 0, (int)length); + + [Fact] + public static async Task AsyncWriterDispose_ShouldCall_FlushAsyncWriteAsyncOnly_TextWriter() + { + using (var sw = new AsyncOnlyWriter()) + await using (var writer = XmlWriter.Create(sw, new XmlWriterSettings() { Async = true })) + { + await writer.WriteStartElementAsync(null, "book", null); + await writer.WriteElementStringAsync(null, "price", null, "19.95"); + await writer.WriteEndElementAsync(); + } + } + + [Fact] + public static async Task XmlWriter_AsyncSyncResult_ShouldBeSame_AfterDispose_TextWriter() + { + using (var sw1 = new StringWriter()) + using (var sw2 = new StringWriter()) + using (var sw3 = new StringWriter()) + { + using (var asyncWriter = XmlWriter.Create(sw1, new XmlWriterSettings() { Async = true })) + { + await asyncWriter.WriteStartElementAsync(null, "book", null); + await asyncWriter.WriteElementStringAsync(null, "price", null, "19.95"); + await asyncWriter.WriteEndElementAsync(); + } + + await using (var asyncWriter = XmlWriter.Create(sw2, new XmlWriterSettings() { Async = true })) + { + await asyncWriter.WriteStartElementAsync(null, "book", null); + await asyncWriter.WriteElementStringAsync(null, "price", null, "19.95"); + await asyncWriter.WriteEndElementAsync(); + } + + using (var syncWriter = XmlWriter.Create(sw3, new XmlWriterSettings() { Async = false })) + { + syncWriter.WriteStartElement(null, "book", null); + syncWriter.WriteElementString(null, "price", null, "19.95"); + syncWriter.WriteEndElement(); + } + + Assert.Equal(sw1.ToString(), sw2.ToString()); + Assert.Equal(sw1.ToString(), sw3.ToString()); + } + } + + internal class AsyncOnlyWriter : StringWriter + { + public override void Flush() + { + throw new InvalidOperationException("Sync operations are not allowed."); + } + + public override Task FlushAsync() + { + return Task.CompletedTask; + } + + public override void Write(char[] buffer, int offset, int count) + { + throw new InvalidOperationException("Sync operations are not allowed."); + } + + public override Task WriteAsync(char[] buffer, int offset, int count) + { + return Task.CompletedTask; + } + + public override Task WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + return Task.CompletedTask; + } + } + + internal class AsyncOnlyStream : MemoryStream + { + public override void Flush() + { + throw new InvalidOperationException("Sync operations are not allowed."); + } + + public override Task FlushAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new InvalidOperationException("Sync operations are not allowed."); + } + + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) + { + return default; + } + } } } diff --git a/src/libraries/System.Private.Xml/tests/XmlWriter/WriteWithEncoding.cs b/src/libraries/System.Private.Xml/tests/XmlWriter/WriteWithEncoding.cs index b764701630e652..549e714246d38c 100644 --- a/src/libraries/System.Private.Xml/tests/XmlWriter/WriteWithEncoding.cs +++ b/src/libraries/System.Private.Xml/tests/XmlWriter/WriteWithEncoding.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Text; +using System.Threading.Tasks; using System.Xml.Xsl; using Xunit; @@ -71,5 +72,37 @@ public void WriteWithUtf32EncodingNoBom() // Then, last '>' will be cut off in resulting string if BOM is present Assert.Equal("", string.Concat(resultString.Take(39))); } + + [Fact] + public static async Task AsyncSyncWrite_StreamResult_ShouldMatch() + { + using (var syncStream = new MemoryStream()) + using (var asyncStream = new MemoryStream()) + { + await using (var writer = XmlWriter.Create(asyncStream, new XmlWriterSettings() { Async = true })) + { + await writer.WriteStartDocumentAsync(); + await writer.WriteStartElementAsync(string.Empty, "root", null); + await writer.WriteStartElementAsync(null, "test", null); + await writer.WriteAttributeStringAsync(string.Empty, "abc", string.Empty, "1"); + await writer.WriteStringAsync("value"); + await writer.WriteEndElementAsync(); + await writer.WriteEndElementAsync(); + } + + using (var writer = XmlWriter.Create(syncStream, new XmlWriterSettings() { Async = false })) + { + writer.WriteStartDocument(); + writer.WriteStartElement("root"); + writer.WriteStartElement("test"); + writer.WriteAttributeString("abc", "1"); + writer.WriteString("value"); + writer.WriteEndElement(); + writer.WriteEndElement(); + } + + Assert.Equal(syncStream.ToArray(), asyncStream.ToArray()); + } + } } } diff --git a/src/libraries/System.Reflection.Context/src/System.Reflection.Context.csproj b/src/libraries/System.Reflection.Context/src/System.Reflection.Context.csproj index daeb3ca8b239b9..c48dcba4484789 100644 --- a/src/libraries/System.Reflection.Context/src/System.Reflection.Context.csproj +++ b/src/libraries/System.Reflection.Context/src/System.Reflection.Context.csproj @@ -1,9 +1,11 @@ - Library - SR.PlatformNotSupported_ReflectionContext netstandard2.0;netstandard1.1;netstandard2.1 + + + SR.PlatformNotSupported_ReflectionContext + diff --git a/src/libraries/System.Reflection.DispatchProxy/ref/System.Reflection.DispatchProxy.csproj b/src/libraries/System.Reflection.DispatchProxy/ref/System.Reflection.DispatchProxy.csproj index d18b6af46b5669..4478a1e5b98bba 100644 --- a/src/libraries/System.Reflection.DispatchProxy/ref/System.Reflection.DispatchProxy.csproj +++ b/src/libraries/System.Reflection.DispatchProxy/ref/System.Reflection.DispatchProxy.csproj @@ -7,7 +7,7 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Reflection.DispatchProxy/src/System.Reflection.DispatchProxy.csproj b/src/libraries/System.Reflection.DispatchProxy/src/System.Reflection.DispatchProxy.csproj index b57517632ecaeb..93cbb7fb64f949 100644 --- a/src/libraries/System.Reflection.DispatchProxy/src/System.Reflection.DispatchProxy.csproj +++ b/src/libraries/System.Reflection.DispatchProxy/src/System.Reflection.DispatchProxy.csproj @@ -2,25 +2,27 @@ true - SR.PlatformNotSupported_ReflectionDispatchProxy $(NetCoreAppCurrent);net461;netstandard2.0;netcoreapp2.0;$(NetFrameworkCurrent) true true enable - + + + SR.PlatformNotSupported_ReflectionDispatchProxy + + - - Common\System\Reflection\Emit\IgnoreAccessChecksToAttributeBuilder.cs - + - + - + @@ -33,4 +35,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.csproj b/src/libraries/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.csproj index e117a9b0619979..48837d6105f259 100644 --- a/src/libraries/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.csproj +++ b/src/libraries/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/libraries/System.Reflection.Emit.Lightweight/tests/DynamicMethodDefineParameter.cs b/src/libraries/System.Reflection.Emit.Lightweight/tests/DynamicMethodDefineParameter.cs index ad32c3d0bdfca9..6334f8c62b7f52 100644 --- a/src/libraries/System.Reflection.Emit.Lightweight/tests/DynamicMethodDefineParameter.cs +++ b/src/libraries/System.Reflection.Emit.Lightweight/tests/DynamicMethodDefineParameter.cs @@ -43,6 +43,15 @@ public void DefineParameter_SetsParameterCorrectly() Assert.Equal(ParameterAttributes.In, parameters[0].Attributes); Assert.Equal(ParameterAttributes.Out, parameters[1].Attributes); + + if (!PlatformDetection.IsMonoRuntime) // [ActiveIssue("https://github.com/dotnet/runtime/issues/36271")] + { + Assert.Empty(parameters[0].GetRequiredCustomModifiers()); + Assert.Empty(parameters[1].GetRequiredCustomModifiers()); + + Assert.Empty(parameters[0].GetOptionalCustomModifiers()); + Assert.Empty(parameters[1].GetOptionalCustomModifiers()); + } } } } diff --git a/src/libraries/System.Reflection.Emit/tests/ConstructorBuilder/ConstructorBuilderToString.cs b/src/libraries/System.Reflection.Emit/tests/ConstructorBuilder/ConstructorBuilderToString.cs index a00d42e12c25fe..22ef09f782522f 100644 --- a/src/libraries/System.Reflection.Emit/tests/ConstructorBuilder/ConstructorBuilderToString.cs +++ b/src/libraries/System.Reflection.Emit/tests/ConstructorBuilder/ConstructorBuilderToString.cs @@ -9,7 +9,6 @@ namespace System.Reflection.Emit.Tests public class ConstructorBuilderToString { [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/2389", TestRuntimes.Mono)] public void ToString_NullRequiredOptionalCustomModifiers() { TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); diff --git a/src/libraries/System.Reflection.Emit/tests/EnumBuilder/EnumBuilder.Properties.Tests.cs b/src/libraries/System.Reflection.Emit/tests/EnumBuilder/EnumBuilder.Properties.Tests.cs index e13310eae52656..2e349c9c3184bd 100644 --- a/src/libraries/System.Reflection.Emit/tests/EnumBuilder/EnumBuilder.Properties.Tests.cs +++ b/src/libraries/System.Reflection.Emit/tests/EnumBuilder/EnumBuilder.Properties.Tests.cs @@ -55,5 +55,12 @@ public void IsArray() Assert.True(arrType.IsArray); Assert.False(arrType.IsSZArray); } + + [Fact] + public void IsByRefLikeReturnsFalse() + { + EnumBuilder enumBuilder = Helpers.DynamicEnum(TypeAttributes.Public, typeof(int)); + Assert.False(enumBuilder.IsByRefLike); + } } } diff --git a/src/libraries/System.Reflection.Emit/tests/GenericTypeParameterBuilder/GenericTypeParameterBuilderIsByRefLike.cs b/src/libraries/System.Reflection.Emit/tests/GenericTypeParameterBuilder/GenericTypeParameterBuilderIsByRefLike.cs new file mode 100644 index 00000000000000..5274332d0c3eb1 --- /dev/null +++ b/src/libraries/System.Reflection.Emit/tests/GenericTypeParameterBuilder/GenericTypeParameterBuilderIsByRefLike.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.Reflection.Emit.Tests +{ + public class GenericTypeParameterBuilderIsByRefLike + { + [Fact] + public void IsByRefLikeReturnsFalse() + { + TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); + var typeParamNames = new string[] { "TFirst" }; + GenericTypeParameterBuilder[] typeParams = type.DefineGenericParameters(typeParamNames); + Assert.False(typeParams[0].IsByRefLike); + } + } +} diff --git a/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineEnum.cs b/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineEnum.cs index 920dc871b58673..5e2b570c2bbc71 100644 --- a/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineEnum.cs +++ b/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineEnum.cs @@ -161,7 +161,6 @@ public void DefineEnum_VoidUnderlyingType_ThrowsArgumentException() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/2389", TestRuntimes.Mono)] public void DefineEnum_ByRefUnderlyingType_ThrowsCOMExceptionOnCreation() { ModuleBuilder module = Helpers.DynamicModule(); diff --git a/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineType.cs b/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineType.cs index fe52f133e5b5c2..844dcb8d181192 100644 --- a/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineType.cs +++ b/src/libraries/System.Reflection.Emit/tests/ModuleBuilder/ModuleBuilderDefineType.cs @@ -33,7 +33,6 @@ public static IEnumerable TestData() } [Theory] - [ActiveIssue("https://github.com/dotnet/runtime/issues/2389", TestRuntimes.Mono)] [MemberData(nameof(TestData))] public void DefineType(string name, TypeAttributes attributes, Type parent, PackingSize packingSize, int typesize, Type[] implementedInterfaces) { diff --git a/src/libraries/System.Reflection.Emit/tests/System.Reflection.Emit.Tests.csproj b/src/libraries/System.Reflection.Emit/tests/System.Reflection.Emit.Tests.csproj index 651e9b6959c89c..e5d46e991da82f 100644 --- a/src/libraries/System.Reflection.Emit/tests/System.Reflection.Emit.Tests.csproj +++ b/src/libraries/System.Reflection.Emit/tests/System.Reflection.Emit.Tests.csproj @@ -25,6 +25,7 @@ + @@ -95,6 +96,7 @@ + @@ -111,4 +113,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderIsByRefLike.cs b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderIsByRefLike.cs new file mode 100644 index 00000000000000..ab69a26c0bbd46 --- /dev/null +++ b/src/libraries/System.Reflection.Emit/tests/TypeBuilder/TypeBuilderIsByRefLike.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. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.Reflection.Emit.Tests +{ + public class TypeBuilderIsByRefLike + { + [Fact] + public void IsByRefLikeReturnsFalse() + { + TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public); + Assert.False(type.IsByRefLike); + } + } +} diff --git a/src/libraries/System.Reflection.Extensions/tests/RuntimeReflectionExtensionTests.cs b/src/libraries/System.Reflection.Extensions/tests/RuntimeReflectionExtensionTests.cs index f3ca59bbca6871..5464877b54c542 100644 --- a/src/libraries/System.Reflection.Extensions/tests/RuntimeReflectionExtensionTests.cs +++ b/src/libraries/System.Reflection.Extensions/tests/RuntimeReflectionExtensionTests.cs @@ -165,7 +165,7 @@ public void GetRuntimeEvent() }); - Assert.Throws(null, () => + Assert.Throws("name", () => { typeof(RuntimeReflectionExtensionsTests).GetRuntimeEvent(null); }); diff --git a/src/libraries/System.Reflection.Metadata/System.Reflection.Metadata.sln b/src/libraries/System.Reflection.Metadata/System.Reflection.Metadata.sln index 220a77fc5b9048..ca14e0d2744fee 100644 --- a/src/libraries/System.Reflection.Metadata/System.Reflection.Metadata.sln +++ b/src/libraries/System.Reflection.Metadata/System.Reflection.Metadata.sln @@ -20,7 +20,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{CCCF36A6-276A-480E-B558-0BEF01ECD74B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{CCCF36A6-276A-480E-B558-0BEF01ECD74B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Collections.Immutable", "..\System.Collections.Immutable\src\System.Collections.Immutable.csproj", "{2E24036E-7AFA-4C91-B6B5-BAA919B3BA74}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -44,6 +46,10 @@ Global {CCCF36A6-276A-480E-B558-0BEF01ECD74B}.Debug|Any CPU.Build.0 = Debug|Any CPU {CCCF36A6-276A-480E-B558-0BEF01ECD74B}.Release|Any CPU.ActiveCfg = Release|Any CPU {CCCF36A6-276A-480E-B558-0BEF01ECD74B}.Release|Any CPU.Build.0 = Release|Any CPU + {2E24036E-7AFA-4C91-B6B5-BAA919B3BA74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2E24036E-7AFA-4C91-B6B5-BAA919B3BA74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2E24036E-7AFA-4C91-B6B5-BAA919B3BA74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2E24036E-7AFA-4C91-B6B5-BAA919B3BA74}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -53,6 +59,7 @@ Global {F3E433C8-352F-4944-BF7F-765CE435370D} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {69B25962-B4C2-4295-8809-5653CD03FC75} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} {CCCF36A6-276A-480E-B558-0BEF01ECD74B} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} + {2E24036E-7AFA-4C91-B6B5-BAA919B3BA74} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F6593193-C664-402E-987E-54EDBA862D77} diff --git a/src/libraries/System.Reflection.Metadata/ref/System.Reflection.Metadata.csproj b/src/libraries/System.Reflection.Metadata/ref/System.Reflection.Metadata.csproj index 99032afef309f6..33546830d98fc0 100644 --- a/src/libraries/System.Reflection.Metadata/ref/System.Reflection.Metadata.csproj +++ b/src/libraries/System.Reflection.Metadata/ref/System.Reflection.Metadata.csproj @@ -1,4 +1,4 @@ - + true false @@ -11,9 +11,8 @@ - + - @@ -21,7 +20,7 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Reflection.Metadata/specs/Ecma-335-Issues.md b/src/libraries/System.Reflection.Metadata/specs/Ecma-335-Issues.md deleted file mode 100644 index ba7b9350681660..00000000000000 --- a/src/libraries/System.Reflection.Metadata/specs/Ecma-335-Issues.md +++ /dev/null @@ -1,331 +0,0 @@ -# Known Issues in ECMA-335 CLI Specification - -This is an informal list of notes on issues that have been encountered -with the ECMA-335 CLI specification, primarily during development, -testing, and support of System.Reflection.Metadata. - -Some of these are definite spec errors while others could be reasoned -as Microsoft implementation quirks. - -## Signatures - -There is a general philosophical issue whereby the spec defines the -*syntax* of signatures to exclude errors such as: - - * using void outside of return types or pointer element types - * instantiating a generic with a byref type - * having a field of byref type - * etc. - -Another approach is to syntactically treat `VOID`, `TYPEDBYREF`, -`BYREF Type`, `CMOD_OPT Type`, `CMOD_REQ Type` as the other `Type`s -and then deal with the cases like those above as semantic errors in their use. -That is closer to how many implementations work. It is also how type syntax -is defined in the grammar for IL, with many of the semantic errors -deferred to peverify and/or runtime checking rather than being checked -during assembly. - -The spec is also not entirely consistent in its use of the first -approach. Some errors, such as instantiating a generic with an -unmanaged pointer type, are not excluded from the spec's signature -grammars and diagrams. - -Many of the specific issues below arise from the tension between these -two approaches. - - -### 1. `(CLASS | VALUETYPE)` cannot be followed by TypeSpec in practice - -In II.23.2.12 and II.23.2.14, it is implied that the token in `(CLASS -| VALUETYPE) TypeDefOrRefOrSpecEncoded` can be a `TypeSpec`, when in -fact it must be a `TypeDef` or `TypeRef`. - -peverify gives the following error: -``` -[MD]: Error: Signature has token following ELEMENT_TYPE_CLASS -(_VALUETYPE) that is not a TypeDef or TypeRef -``` -An insightful comment in CLR source code notes that this rule prevents -cycles in signatures, but see #2 below. - -Related issue: -* https://github.com/dotnet/roslyn/issues/7970 - -#### Proposed specification change - -a) Rename section II.23.2.8 from "TypeDefOrRefOrSpecEncoded" to "TypeDefOrRefEncoded and TypeDefOrRefOrSpecEncoded" - -b) Replace - -> These items are compact ways to store a TypeDef, TypeRef, or TypeSpec token in a Signature (§II.23.2.12). - -with - -> TypeDefOrRefEncoded is a compact representation of either TypeDef or TypeRef token in a Signature (§II.23.2.12). TypeDefOrRefOrSpecEncoded is a compact representation of either TypeDef, TypeRef or TypeSpec token in a Signature. - -Also correct - -> The encoded version of this TypeRef token is made up as follows: - -to - -> The compact representation of a TypeDef, TypeRef or TypeSpec token is made up as follows: - -c) In section II.23.2.12 replace - -``` -Type ::= - ... - CLASS TypeDefOrRefOrSpecEncoded - ... - GENERICINST (CLASS | VALUETYPE) TypeDefOrRefOrSpecEncoded GenArgCount Type* - ... - VALUETYPE TypeDefOrRefOrSpecEncoded - ... -``` - -with - -``` -Type ::= - ... - (CLASS | VALUETYPE) TypeDefOrRefEncoded - GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type+ - ... -``` - -Note also the correction of ```Type*``` to ```Type+```. A generic type instantiation shall have at least one type argument. - -d) In section II.23.2.14 replace - -``` -TypeSpecBlob ::= - ... - GENERICINST (CLASS | VALUETYPE) TypeDefOrRefOrSpecEncoded GenArgCount Type Type* - ... -``` - -with - -``` -TypeSpecBlob ::= - ... - GENERICINST (CLASS | VALUETYPE) TypeDefOrRefEncoded GenArgCount Type+ - ... -``` - -```Type Type*``` is simplified to ```Type+```. - -#### Rationale of the proposal - -1. The proposal removes the possibility of representing the same type via two different encodings. This approach is consistent with II.23.2.16: "Short form signatures" where a short form of a primitive type is preferred over the corresponding long form. - -2. Potential TypeSpec recursion is prevented. - -3. PEVerify, the CLR runtime and C# compiler prior to VS 2015 report an error when encountering an encoded TypeSpec in the positions decribed above. - -### 2. `(CMOD_OPT | CMOD_REQ) ` is permitted in practice - -In II.23.2.7, it is noted that CMOD_OPT or CMOD_REQD is followed -by a TypeRef or TypeDef metadata token, but TypeSpec tokens are -also allowed by ilasm, csc, peverify, and the CLR. - -Note, in particular, that TypeSpecs are used there by C++/CLI to -represent strongly-typed boxing in C++/CLI. e.g. `Nullable^` -in C++/CLI becomes `[mscorlib]System.ValueType -modopt([mscorlib]System.Nulllable`1) -modopt([mscorlib]System.Runtime.CompilerServices.IsBoxed)` -in IL. - -This tolerance adds a loophole to the rule above whereby cyclical -signatures are in fact possible, e.g.: - -* `TypeSpec #1: PTR CMOD_OPT I4` - -Such signatures can currently cause crashes in the runtime and various -tools, so if the spec is amended to permit TypeSpecs as modifiers, -then there should be a clarification that cycles are nonetheless not -permitted, and ideally readers would detect such cycles and handle the -error with a suitable message rather than a stack overflow. - -Related issues: -* https://github.com/dotnet/roslyn/issues/7971 -* https://github.com/dotnet/coreclr/issues/2674 - -#### Proposed specification change - -In section II.23.2.7, replace - -> The CMOD_OPT or CMOD_REQD is followed by a metadata token that indexes a row in the TypeDef - table or the TypeRef table. However, these tokens are encoded and compressed – see §II.23.2.8 -for details - -with - -> The CMOD_OPT or CMOD_REQD is followed by a metadata token that indexes a row in the TypeDef -table, TypeRef table, or TypeSpec table. However, these tokens are encoded and compressed – -see §II.23.2.8 for details. Furthermore, if a row in the TypeSpec table is indicated, -it must not create cycle. - -### 3. Custom modifiers can go in more places than specified - -Most notably, II.23.2.14 and II.23.21.12 (`Type` and `TypeSpec` grammars) -are missing custom modifiers for the element type of `ARRAY` and the -type arguments of `GENERICINST`. - -Also, `LocalVarSig` as specified does not allow modifiers on -`TYPEDBYREF`, and that seems arbitrary since it is allowed on parameter -and return types. - -#### Proposed specification change - -a) In section II.23.2.4 FieldSig, replace the diagram with a production rule: - -``` -FieldSig ::= FIELD Type -``` - -b) In section II.23.2.5 PropertySig, replace the diagram with a production rule: - -``` -PropertySig ::= PROPERTY HASTHIS? ParamCount RetType Param* -``` - -Note that this change also allows properties to have BYREF type. - -c) In section II.23.2.6 LocalVarSig, replace the diagram with production rules: - -``` -LocalVarSig ::= - LOCAL_SIG Count LocalVarType+ - -LocalVarType ::= - Type - CustomMod* Constraint BYREF? Type - CustomMod* BYREF Type - CustomMod* TYPEDBYREF - -``` - -d) In section II.23.2.10 Param, replace the diagram with production rules: - -``` -Param ::= - Type - CustomMod* BYREF Type - CustomMod* TYPEDBYREF -``` - -e) In section II.23.2.11 RetType, replace the diagram with production rules: - -``` -RetType ::= - Type - CustomMod* BYREF Type - CustomMod* TYPEDBYREF - CustomMod* VOID -``` - -f) In section II.23.2.12 Type, add a production rule to the definition of ```Type```: - -``` -Type ::= CustomMod* Type - -``` - -g) In sections II.23.2.12 Type and II.23.2.14 TypeSpec replace production rule - -``` -PTR CustomMod* Type -``` - -with - -``` -PTR Type -``` - -and replace production rule - -``` -SZARRAY CustomMod* Type -``` - -with - -``` -SZARRAY Type -``` - -### 4. BYREF can come before custom modifiers - -Everywhere `BYREF` appears in the spec's box and pointer diagrams, it -comes after any custom modifiers, but the C++/CLI declaration `const -int&` is emitted as `BYREF CMOD_OPT IsConst I4`, and a call-site using -`CMOD_OPT IsConst BYREF I4` will not match. - -Under the interpretation that `BYREF` is just a managed pointer type, it -makes sense that there should be parity between `PTR` and `BYREF` with -respect to modifiers. Consider, `const int*` vs. `int* const` in -C++. The former (pointer to constant int) is `PTR CMOD_OPT IsConst I4` -and the latter (constant pointer to int) is `CMOD_OPT IsConst PTR -I4`. The analogy from `const int*` to `const int&` justifies C++'s -encoding of `BYREF` before `CMOD_OPT` in defiance of the spec. - -#### Proposed specification change - -Already addressed by changes in proposal #3 above. - -### 5. TypeSpecs can encode more than specified - -In II.23.2.14, the grammar for a `TypeSpec` blob is a subset of the -`Type` grammar defined in II.23.21.12. However, in practice, it is -possible to have other types than what is listed. - -Most notably, the important use of the `constrained.` IL prefix with -type parameters is not representable as specified since `MVAR` and `VAR` -are excluded from II.23.2.14. - -More obscurely, the constrained. prefix also works with primitives, -e.g: - -``` -constrained. int32 -callvirt instance string [mscorlib]System.Object::ToString() -``` - -which opens the door to `TypeSpec`s with I4, I8, etc. signatures. - -It then follows that the only productions in `Type` that do not make -sense in `TypeSpec` are `(CLASS | VALUETYPE) TypeDefOrRef` since -`TypeDefOrRef` tokens can be used directly and the indirection through -a `TypeSpec` would serve no purpose. - -In the same way as `constrained.`, (assuming #2 is a spec bug and not -an ilasm/peverify/CLR quirk), custom modifiers can beget `TypeSpec`s -beyond what is allowed by II.23.2.14, e.g. `modopt(int32)` creates a -typespec with signature I4. - -Even more obscurely, this gives us a way to use `VOID`, `TYPEDBYREF`, -`CMOD_OPT`, and `CMOD_REQ` at the root of a `TypeSpec`, which are not even -specified as valid at the root of a `Type`: `modopt(int32 -modopt(int32))`, `modopt(void)`, and `modopt(typedref)` all work in -practice. `CMOD_OPT` and `CMOD_REQ` at the root can also be otained by putting -a modifier on the type used with `constrained.`. - -## Heap sizes - -The ECMA-335-II specification isn't clear on the maximum sizes of #String, #Blob and #GUID heaps. - -#### Proposed specification change - -We propose the limit on #String and #Blob heap size is 2^29 (0.5 GB), that is any index to these heaps fits into 29 bits. - -#### Rationale of the proposal - -1) 2^29 is the maximum value representable by a compressed integer as defined elsewhere in the spec. Currently the metadata don't encode heap indices anywhere using compressed integers. However the Portable PDB specification uses compressed integers for efficient encoding of heap indices. We could extend the definition of compressed integer to cover all 32 bit integers, but it would be simpler if we could leave it as is. - -2) 0.5 GB is a very large heap. Having such a big PE file seems unreasonable and very rare scenario (if it exists at all). - -3) Having 3 spare bits available is very beneficial for the implementation. It allows to represent WinRT projected strings, namespaces, etc. in very efficient way. If we had to represent heap indices with all 32 bits it would bloat various structures and increase memory pressure. PE files over 0.5 GB of size are very rare, but the overhead would affect all compilers and tools working with the metadata reader. - diff --git a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj index e2054078129e74..a60521d62461b0 100644 --- a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj +++ b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj @@ -3,18 +3,19 @@ true en-US false - netstandard1.1;portable-net45+win8 $(NetCoreAppCurrent);netstandard1.1;netstandard2.0 true enable + + + + netstandard1.1;portable-net45+win8 - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\kernel32\Interop.ReadFile_SafeHandle_IntPtr.cs - + + @@ -97,14 +98,14 @@ - - + + - + @@ -263,6 +264,6 @@ - + diff --git a/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj b/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj index 73119be2190f9d..e3d82ffed0a331 100644 --- a/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj +++ b/src/libraries/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj @@ -6,24 +6,18 @@ $(NetCoreAppCurrent);$(NetFrameworkCurrent) - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.FreeLibrary.cs - - - Common\Interop\Windows\Interop.GetModuleHandle.cs - - - Common\Interop\Windows\Interop.LoadLibraryEx.cs - - - Common\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs - - - Common\System\IO\TempFile.cs - + + + + + + diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj index 2bd0a5ecedbd8f..e200da5e032833 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System.Reflection.MetadataLoadContext.csproj @@ -1,11 +1,10 @@ - System.Reflection.MetadataLoadContext System.Reflection true $(NoWarn);CS1573 - netcoreapp3.0;netstandard2.0;$(NetCoreAppCurrent) + $(NetCoreAppCurrent);netcoreapp3.0;netstandard2.0 true enable @@ -79,8 +78,8 @@ - - + + diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs index ea73a31460503d..b88f8a42fc3e89 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Types/RoType.cs @@ -192,9 +192,14 @@ private RoType[] ComputeInterfaceClosure() } } - // todo: use IEnumerable extension: return ifcs.ToArray() - List list = new List(ifcs); - return list.ToArray(); + if (ifcs.Count == 0) + { + return Array.Empty(); + } + + var arr = new RoType[ifcs.Count]; + ifcs.CopyTo(arr); + return arr; } private volatile RoType[]? _lazyInterfaces; diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj index 346761c5ded63f..2c3eb7011daa84 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/System.Reflection.MetadataLoadContext.Tests.csproj @@ -4,12 +4,10 @@ $(NetCoreAppCurrent);$(NetFrameworkCurrent) - - Common\System\IO\TempDirectory.cs - - - Common\System\IO\TempFile.cs - + + @@ -71,4 +69,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Reflection/tests/AssemblyNameTests.cs b/src/libraries/System.Reflection/tests/AssemblyNameTests.cs index ec11240ab0d2d3..827da95641e0bf 100644 --- a/src/libraries/System.Reflection/tests/AssemblyNameTests.cs +++ b/src/libraries/System.Reflection/tests/AssemblyNameTests.cs @@ -392,6 +392,14 @@ public static void FullName_WithPublicKey() Assert.Equal("MyAssemblyName, Version=1.0.0.0, PublicKeyToken=b03f5f7f11d50a3a", assemblyName.FullName); } + [Fact] + public static void Name_WithNullPublicKey() + { + AssemblyName assemblyName = new AssemblyName("noname,PublicKeyToken=null"); + Assert.Equal(0, assemblyName.GetPublicKeyToken().Length); + Assert.Equal("noname, PublicKeyToken=null", assemblyName.FullName); + } + public static IEnumerable Version_TestData() { yield return new object[] { new Version(255, 1), "255.1" }; diff --git a/src/libraries/System.Reflection/tests/AssemblyVersion/System.Reflection.Tests.Assembly_1_0_0_0.csproj b/src/libraries/System.Reflection/tests/AssemblyVersion/System.Reflection.Tests.Assembly_1_0_0_0.csproj index 01ffdc56b2f153..dd86f5dce03438 100644 --- a/src/libraries/System.Reflection/tests/AssemblyVersion/System.Reflection.Tests.Assembly_1_0_0_0.csproj +++ b/src/libraries/System.Reflection/tests/AssemblyVersion/System.Reflection.Tests.Assembly_1_0_0_0.csproj @@ -1,4 +1,4 @@ - + 1.0.0.0 netstandard2.0 diff --git a/src/libraries/System.Reflection/tests/MethodInfoTests.cs b/src/libraries/System.Reflection/tests/MethodInfoTests.cs index 9906b28601ffcc..37e16ac8748cf1 100644 --- a/src/libraries/System.Reflection/tests/MethodInfoTests.cs +++ b/src/libraries/System.Reflection/tests/MethodInfoTests.cs @@ -26,21 +26,41 @@ public void CreateDelegate_PublicMethod() object returnValue = ((Delegate_TC_Int)methodDelegate).DynamicInvoke(new object[] { baseClass }); Assert.Equal(baseClass.VirtualMethod(), returnValue); + Delegate genMethodDelegate = virtualMethodInfo.CreateDelegate(); + object genReturnValue = genMethodDelegate.DynamicInvoke(new object[] { baseClass }); + Assert.Equal(returnValue, genReturnValue); + methodDelegate = privateInstanceMethodInfo.CreateDelegate(typeof(Delegate_TC_Int)); returnValue = ((Delegate_TC_Int)methodDelegate).DynamicInvoke(new object[] { baseClass }); Assert.Equal(21, returnValue); + genMethodDelegate = privateInstanceMethodInfo.CreateDelegate(); + genReturnValue = genMethodDelegate.DynamicInvoke(new object[] { baseClass }); + Assert.Equal(returnValue, genReturnValue); + methodDelegate = virtualMethodInfo.CreateDelegate(typeof(Delegate_Void_Int), baseClass); returnValue = ((Delegate_Void_Int)methodDelegate).DynamicInvoke(null); Assert.Equal(baseClass.VirtualMethod(), returnValue); + genMethodDelegate = virtualMethodInfo.CreateDelegate(baseClass); + genReturnValue = genMethodDelegate.DynamicInvoke(null); + Assert.Equal(returnValue, genReturnValue); + methodDelegate = publicStaticMethodInfo.CreateDelegate(typeof(Delegate_Str_Str)); returnValue = ((Delegate_Str_Str)methodDelegate).DynamicInvoke(new object[] { "85" }); Assert.Equal("85", returnValue); + genMethodDelegate = publicStaticMethodInfo.CreateDelegate(); + genReturnValue = genMethodDelegate.DynamicInvoke(new object[] { "85" }); + Assert.Equal(returnValue, genReturnValue); + methodDelegate = publicStaticMethodInfo.CreateDelegate(typeof(Delegate_Void_Str), "93"); returnValue = ((Delegate_Void_Str)methodDelegate).DynamicInvoke(null); Assert.Equal("93", returnValue); + + genMethodDelegate = publicStaticMethodInfo.CreateDelegate("93"); + genReturnValue = genMethodDelegate.DynamicInvoke(null); + Assert.Equal(returnValue, genReturnValue); } [Fact] @@ -57,9 +77,17 @@ public void CreateDelegate_InheritedMethod() object returnValue = ((Delegate_TC_Int)methodDelegate).DynamicInvoke(new object[] { testSubClass }); Assert.Equal(testSubClass.VirtualMethod(), returnValue); + Delegate genMethodDelegate = virtualMethodInfo.CreateDelegate(); + object genReturnValue = genMethodDelegate.DynamicInvoke(new object[] { testSubClass }); + Assert.Equal(returnValue, genReturnValue); + methodDelegate = virtualMethodInfo.CreateDelegate(typeof(Delegate_Void_Int), testSubClass); returnValue = ((Delegate_Void_Int)methodDelegate).DynamicInvoke(); Assert.Equal(testSubClass.VirtualMethod(), returnValue); + + genMethodDelegate = virtualMethodInfo.CreateDelegate(testSubClass); + genReturnValue = genMethodDelegate.DynamicInvoke(); + Assert.Equal(returnValue, genReturnValue); } [Fact] @@ -78,17 +106,33 @@ public void CreateDelegate_GenericMethod() object returnValue = ((Delegate_GC_T_T)methodDelegate).DynamicInvoke(new object[] { genericClass, "TestGeneric" }); Assert.Equal(genericClass.GenericMethod1("TestGeneric"), returnValue); + Delegate genMethodDelegate = miMethod1String.CreateDelegate>(); + object genReturnValue = genMethodDelegate.DynamicInvoke(new object[] { genericClass, "TestGeneric" }); + Assert.Equal(returnValue, genReturnValue); + methodDelegate = miMethod1String.CreateDelegate(typeof(Delegate_T_T), genericClass); returnValue = ((Delegate_T_T)methodDelegate).DynamicInvoke(new object[] { "TestGeneric" }); Assert.Equal(genericClass.GenericMethod1("TestGeneric"), returnValue); + genMethodDelegate = miMethod1String.CreateDelegate>(genericClass); + genReturnValue = genMethodDelegate.DynamicInvoke(new object[] { "TestGeneric" }); + Assert.Equal(returnValue, genReturnValue); + methodDelegate = miMethod2IntGeneric.CreateDelegate(typeof(Delegate_T_T)); returnValue = ((Delegate_T_T)methodDelegate).DynamicInvoke(new object[] { 58 }); Assert.Equal(58, returnValue); + genMethodDelegate = miMethod2IntGeneric.CreateDelegate>(); + genReturnValue = genMethodDelegate.DynamicInvoke(new object[] { 58 }); + Assert.Equal(returnValue, genReturnValue); + methodDelegate = miMethod2StringGeneric.CreateDelegate(typeof(Delegate_Void_T), "firstArg"); returnValue = ((Delegate_Void_T)methodDelegate).DynamicInvoke(); Assert.Equal("firstArg", returnValue); + + genMethodDelegate = miMethod2StringGeneric.CreateDelegate>("firstArg"); + genReturnValue = genMethodDelegate.DynamicInvoke(); + Assert.Equal(returnValue, genReturnValue); } [Fact] @@ -100,6 +144,10 @@ public void CreateDelegate_ValueTypeParameters() Delegate methodDelegate = miPublicStructMethod.CreateDelegate(typeof(Delegate_DateTime_Str)); object returnValue = ((Delegate_DateTime_Str)methodDelegate).DynamicInvoke(new object[] { testClass, null }); Assert.Equal(testClass.PublicStructMethod(new DateTime()), returnValue); + + Delegate genMethodDelegate = miPublicStructMethod.CreateDelegate(); + object genReturnValue = genMethodDelegate.DynamicInvoke(new object[] { testClass, null }); + Assert.Equal(returnValue, genReturnValue); } [Theory] diff --git a/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj b/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj index bc9f91e515bcd0..f96a3551aa4b82 100644 --- a/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj +++ b/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj @@ -7,13 +7,12 @@ true - - Common\System\Reflection\MockParameterInfo.cs - - - - Common\System\IO\TempFile.cs - + + + @@ -65,4 +64,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Reflection/tests/TypeInfoTests.cs b/src/libraries/System.Reflection/tests/TypeInfoTests.cs index 9d6d9fdbb88908..40c484c13381a8 100644 --- a/src/libraries/System.Reflection/tests/TypeInfoTests.cs +++ b/src/libraries/System.Reflection/tests/TypeInfoTests.cs @@ -471,10 +471,10 @@ public static void IsEnumDefined(object value, bool expected) } [Fact] - [ActiveIssue("https://github.com/mono/mono/issues/15028", TestRuntimes.Mono)] public void IsEnumDefined_Invalid() { - AssertExtensions.Throws("", () => typeof(NonGenericClassWithNoInterfaces).GetTypeInfo().IsEnumDefined(10)); + AssertExtensions.Throws("enumType", () => typeof(NonGenericClassWithNoInterfaces).GetTypeInfo().IsEnumDefined(10)); + AssertExtensions.Throws("enumType", () => typeof(NonGenericClassWithNoInterfaces).GetTypeInfo().IsEnumDefined("10")); Assert.Throws(() => typeof(IntEnum).GetTypeInfo().IsEnumDefined(null)); Assert.Throws(() => typeof(IntEnum).GetTypeInfo().IsEnumDefined(new NonGenericClassWithNoInterfaces())); } diff --git a/src/libraries/System.Resources.Extensions/src/BinaryWriterExtensions.cs b/src/libraries/System.Resources.Extensions/src/BinaryWriterExtensions.cs new file mode 100644 index 00000000000000..3ad99398faae45 --- /dev/null +++ b/src/libraries/System.Resources.Extensions/src/BinaryWriterExtensions.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.IO +{ + internal static class BinaryWriterExtensions + { + public static void Write7BitEncodedInt(this BinaryWriter writer, int value) + { + // Write out an int 7 bits at a time. The high bit of the byte, + // when on, tells reader to continue reading more bytes. + uint v = (uint)value; // support negative numbers + while (v >= 0x80) + { + writer.Write((byte)(v | 0x80)); + v >>= 7; + } + writer.Write((byte)v); + } + } +} diff --git a/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj b/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj index e28f9cb4804277..100a496b86af78 100644 --- a/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj +++ b/src/libraries/System.Resources.Extensions/src/System.Resources.Extensions.csproj @@ -8,22 +8,28 @@ - - - - - - + + + + + + + - - System\Numerics\Hashing\HashHelpers.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/PreserializedResourceWriter.cs b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/PreserializedResourceWriter.cs index 84cb500cc766b8..5eba6fb9faa22f 100644 --- a/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/PreserializedResourceWriter.cs +++ b/src/libraries/System.Resources.Extensions/src/System/Resources/Extensions/PreserializedResourceWriter.cs @@ -213,7 +213,7 @@ private void WriteData(BinaryWriter writer, object dataContext) // Only write the format if we resources are in DeserializingResourceReader format if (_requiresDeserializingResourceReader) { - Write7BitEncodedInt(writer, (int)record.Format); + writer.Write7BitEncodedInt((int)record.Format); } try @@ -228,7 +228,7 @@ private void WriteData(BinaryWriter writer, object dataContext) // doesn't constrain binaryFormatter if (_requiresDeserializingResourceReader) { - Write7BitEncodedInt(writer, data.Length); + writer.Write7BitEncodedInt(data.Length); } writer.Write(data); @@ -243,7 +243,7 @@ private void WriteData(BinaryWriter writer, object dataContext) stream.Position = 0; - Write7BitEncodedInt(writer, (int)stream.Length); + writer.Write7BitEncodedInt((int)stream.Length); stream.CopyTo(writer.BaseStream); @@ -252,7 +252,7 @@ private void WriteData(BinaryWriter writer, object dataContext) case SerializationFormat.TypeConverterByteArray: { byte[] data = (byte[])record.Data; - Write7BitEncodedInt(writer, data.Length); + writer.Write7BitEncodedInt(data.Length); writer.Write(data); break; } diff --git a/src/libraries/System.Resources.Extensions/tests/System.Resources.Extensions.Tests.csproj b/src/libraries/System.Resources.Extensions/tests/System.Resources.Extensions.Tests.csproj index 42835e7473b689..8bed771d651251 100644 --- a/src/libraries/System.Resources.Extensions/tests/System.Resources.Extensions.Tests.csproj +++ b/src/libraries/System.Resources.Extensions/tests/System.Resources.Extensions.Tests.csproj @@ -7,12 +7,10 @@ - - System\Numerics\Hashing\HashHelpers.cs - - - TypeNameComparer.cs - + + diff --git a/src/libraries/System.Resources.ResourceManager/tests/System.Resources.ResourceManager.Tests.csproj b/src/libraries/System.Resources.ResourceManager/tests/System.Resources.ResourceManager.Tests.csproj index 87e65b381d4651..5e102a633daeff 100644 --- a/src/libraries/System.Resources.ResourceManager/tests/System.Resources.ResourceManager.Tests.csproj +++ b/src/libraries/System.Resources.ResourceManager/tests/System.Resources.ResourceManager.Tests.csproj @@ -18,9 +18,8 @@ - - Common\System\Drawing\Helpers.cs - + @@ -55,7 +54,7 @@ + Visible="false" /> + + SR.PlatformNotSupported_WindowsRuntime + true + 4.0.1.0 + + @@ -25,17 +26,16 @@ - - Common\System\Runtime\InteropServices\WindowsRuntime\WindowsRuntimeImportAttribute.cs - + - + - + diff --git a/src/libraries/System.Runtime.WindowsRuntime/System.Runtime.WindowsRuntime.sln b/src/libraries/System.Runtime.WindowsRuntime/System.Runtime.WindowsRuntime.sln index 7e3ed1c706c72d..d5377c97ccc51b 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/System.Runtime.WindowsRuntime.sln +++ b/src/libraries/System.Runtime.WindowsRuntime/System.Runtime.WindowsRuntime.sln @@ -20,7 +20,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{A6BDC72A-9423-4A0D-915F-996A8951EAC9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{A6BDC72A-9423-4A0D-915F-996A8951EAC9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime", "..\System.Runtime\src\System.Runtime.csproj", "{BF53DBB0-B4DF-49B2-8D86-EEEB484CC3C2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.Extensions", "..\System.Runtime.Extensions\src\System.Runtime.Extensions.csproj", "{BC43843F-659C-4128-B78D-323BCD9B861D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.InteropServices.WindowsRuntime", "..\System.Runtime.InteropServices.WindowsRuntime\src\System.Runtime.InteropServices.WindowsRuntime.csproj", "{B4D3A07A-9DD1-4C2F-9F4F-729A95F0F8A0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.ObjectModel", "..\System.ObjectModel\src\System.ObjectModel.csproj", "{7E205DA8-F34E-4995-A902-79B5107674DC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -44,6 +52,22 @@ Global {A6BDC72A-9423-4A0D-915F-996A8951EAC9}.Debug|Any CPU.Build.0 = Debug|Any CPU {A6BDC72A-9423-4A0D-915F-996A8951EAC9}.Release|Any CPU.ActiveCfg = Release|Any CPU {A6BDC72A-9423-4A0D-915F-996A8951EAC9}.Release|Any CPU.Build.0 = Release|Any CPU + {BF53DBB0-B4DF-49B2-8D86-EEEB484CC3C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF53DBB0-B4DF-49B2-8D86-EEEB484CC3C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF53DBB0-B4DF-49B2-8D86-EEEB484CC3C2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF53DBB0-B4DF-49B2-8D86-EEEB484CC3C2}.Release|Any CPU.Build.0 = Release|Any CPU + {BC43843F-659C-4128-B78D-323BCD9B861D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC43843F-659C-4128-B78D-323BCD9B861D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC43843F-659C-4128-B78D-323BCD9B861D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC43843F-659C-4128-B78D-323BCD9B861D}.Release|Any CPU.Build.0 = Release|Any CPU + {B4D3A07A-9DD1-4C2F-9F4F-729A95F0F8A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B4D3A07A-9DD1-4C2F-9F4F-729A95F0F8A0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B4D3A07A-9DD1-4C2F-9F4F-729A95F0F8A0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B4D3A07A-9DD1-4C2F-9F4F-729A95F0F8A0}.Release|Any CPU.Build.0 = Release|Any CPU + {7E205DA8-F34E-4995-A902-79B5107674DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7E205DA8-F34E-4995-A902-79B5107674DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7E205DA8-F34E-4995-A902-79B5107674DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7E205DA8-F34E-4995-A902-79B5107674DC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -53,6 +77,10 @@ Global {844A2A0B-4169-49C3-B367-AFDC4894E487} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {FDDA3E4A-B182-4CD1-B624-EBD72D8A05DA} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} {A6BDC72A-9423-4A0D-915F-996A8951EAC9} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} + {BF53DBB0-B4DF-49B2-8D86-EEEB484CC3C2} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {BC43843F-659C-4128-B78D-323BCD9B861D} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {B4D3A07A-9DD1-4C2F-9F4F-729A95F0F8A0} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {7E205DA8-F34E-4995-A902-79B5107674DC} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {61FA1A49-D9AA-4129-AFD5-9951C32B2CF5} diff --git a/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.csproj b/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.csproj index a04068f7e4cf09..93a7d07d648cff 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.csproj +++ b/src/libraries/System.Runtime.WindowsRuntime/ref/System.Runtime.WindowsRuntime.csproj @@ -18,13 +18,13 @@ - + - + diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System.Runtime.WindowsRuntime.csproj b/src/libraries/System.Runtime.WindowsRuntime/src/System.Runtime.WindowsRuntime.csproj index 5b03245ecc137a..6dae361dbffcd6 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System.Runtime.WindowsRuntime.csproj +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System.Runtime.WindowsRuntime.csproj @@ -5,18 +5,19 @@ $(NoWarn);1698;0436 - 4.0.0.0 - 4.0.11.0 - $(DefineConstants);FEATURE_APPX $(NetCoreAppCurrent)-Windows_NT;netstandard1.0;netstandard1.2;netstandard2.0 true enable - + + SR.PlatformNotSupported_WindowsRuntime true + 4.0.0.0 + 4.0.11.0 + $(DefineConstants);FEATURE_APPX - + @@ -55,47 +56,38 @@ - - Common\Interop\Windows\Mincore\Interop.RoGetActivationFactory.cs - - - Common\System\Runtime\InteropServices\WindowsRuntime\WindowsRuntimeImportAttribute.cs - - - Common\Interop\Windows\kernel32\Interop.ResolveLocaleName.cs - - - Common\Interop\Windows\kernel32\Interop.FormatMessage.cs - - - Common\Interop\Windows\Mincore\Interop.RoGetBufferMarshaler.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.Errors.cs - - - Common\System\IO\Win32Marshal.cs - - - Common\System\HexConverter.cs - + + + + + + + + + - + - + - + diff --git a/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/StreamOperationsImplementation.cs b/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/StreamOperationsImplementation.cs index 9414d9f042cc2b..5fd829c8ed9490 100644 --- a/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/StreamOperationsImplementation.cs +++ b/src/libraries/System.Runtime.WindowsRuntime/src/System/IO/StreamOperationsImplementation.cs @@ -111,7 +111,7 @@ internal static IAsyncOperationWithProgress ReadAsync_AbstractStr try { // Read asynchronously: - bytesRead = await stream.ReadAsync(data!, offset + bytesCompleted, bytesRequested - bytesCompleted, cancelToken) + bytesRead = await stream.ReadAsync(data!.AsMemory(offset + bytesCompleted, bytesRequested - bytesCompleted), cancelToken) .ConfigureAwait(continueOnCapturedContext: false); // We will continue here on a different thread when read async completed: @@ -181,7 +181,7 @@ internal static IAsyncOperationWithProgress WriteAsync_AbstractStrea int bytesToWrite = (int)buffer.Length; - await stream.WriteAsync(data, offset, bytesToWrite, cancelToken).ConfigureAwait(continueOnCapturedContext: false); + await stream.WriteAsync(data.AsMemory(offset, bytesToWrite), cancelToken).ConfigureAwait(continueOnCapturedContext: false); if (progressListener != null) progressListener.Report((uint)bytesToWrite); diff --git a/src/libraries/System.Runtime/System.Runtime.sln b/src/libraries/System.Runtime/System.Runtime.sln index 1fad2177e6341f..d5992a5981a20e 100644 --- a/src/libraries/System.Runtime/System.Runtime.sln +++ b/src/libraries/System.Runtime/System.Runtime.sln @@ -7,6 +7,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.Tests", "tes {56B9D0A9-44D3-488E-8B42-C14A6E30CAB2} = {56B9D0A9-44D3-488E-8B42-C14A6E30CAB2} EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.Nls.Tests", "tests\NlsTests\System.Runtime.Nls.Tests.csproj", "{F6ED1D9D-DBF6-420A-9710-672BF78A00E4}" + ProjectSection(ProjectDependencies) = postProject + {56B9D0A9-44D3-488E-8B42-C14A6E30CAB2} = {56B9D0A9-44D3-488E-8B42-C14A6E30CAB2} + EndProjectSection +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestCollectibleAssembly", "tests\TestCollectibleAssembly\TestCollectibleAssembly.csproj", "{F9C30DC5-30C1-45DA-9336-F7BE358C367C}" ProjectSection(ProjectDependencies) = postProject {56B9D0A9-44D3-488E-8B42-C14A6E30CAB2} = {56B9D0A9-44D3-488E-8B42-C14A6E30CAB2} @@ -54,6 +59,10 @@ Global {B1BF7CE0-CAB5-4FA2-A39C-450B05D5DB1C}.Debug|Any CPU.Build.0 = Debug|Any CPU {B1BF7CE0-CAB5-4FA2-A39C-450B05D5DB1C}.Release|Any CPU.ActiveCfg = Release|Any CPU {B1BF7CE0-CAB5-4FA2-A39C-450B05D5DB1C}.Release|Any CPU.Build.0 = Release|Any CPU + {F6ED1D9D-DBF6-420A-9710-672BF78A00E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F6ED1D9D-DBF6-420A-9710-672BF78A00E4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6ED1D9D-DBF6-420A-9710-672BF78A00E4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F6ED1D9D-DBF6-420A-9710-672BF78A00E4}.Release|Any CPU.Build.0 = Release|Any CPU {F9C30DC5-30C1-45DA-9336-F7BE358C367C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F9C30DC5-30C1-45DA-9336-F7BE358C367C}.Debug|Any CPU.Build.0 = Debug|Any CPU {F9C30DC5-30C1-45DA-9336-F7BE358C367C}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -92,6 +101,7 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {B1BF7CE0-CAB5-4FA2-A39C-450B05D5DB1C} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} + {F6ED1D9D-DBF6-420A-9710-672BF78A00E4} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} {F9C30DC5-30C1-45DA-9336-F7BE358C367C} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} {71DE1A1F-F8E2-452A-9D54-0385F6099DD3} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} {3B7489C4-65DB-4E69-BE01-F6234133400C} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 52b631512e1da7..2aac15f3deca6e 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -354,7 +354,7 @@ public void Initialize() { } public static int LastIndexOf(T[] array, T value) { throw null; } public static int LastIndexOf(T[] array, T value, int startIndex) { throw null; } public static int LastIndexOf(T[] array, T value, int startIndex, int count) { throw null; } - public static void Resize([System.Diagnostics.CodeAnalysis.NotNullAttribute] ref T[]? array, int newSize) { } + public static void Resize([System.Diagnostics.CodeAnalysis.NotNullAttribute] ref T[]? array, int newSize) { throw null; } public static void Reverse(System.Array array) { } public static void Reverse(System.Array array, int index, int length) { } public static void Reverse(T[] array) { } @@ -384,15 +384,15 @@ public static void Sort(TKey[] keys, TValue[]? items) { } public static void Sort(TKey[] keys, TValue[]? items, System.Collections.Generic.IComparer? comparer) { } public static void Sort(TKey[] keys, TValue[]? items, int index, int length) { } public static void Sort(TKey[] keys, TValue[]? items, int index, int length, System.Collections.Generic.IComparer? comparer) { } - int System.Collections.IList.Add(object value) { throw null; } + int System.Collections.IList.Add(object? value) { throw null; } void System.Collections.IList.Clear() { } - bool System.Collections.IList.Contains(object value) { throw null; } - int System.Collections.IList.IndexOf(object value) { throw null; } - void System.Collections.IList.Insert(int index, object value) { } - void System.Collections.IList.Remove(object value) { } + bool System.Collections.IList.Contains(object? value) { throw null; } + int System.Collections.IList.IndexOf(object? value) { throw null; } + void System.Collections.IList.Insert(int index, object? value) { } + void System.Collections.IList.Remove(object? value) { } void System.Collections.IList.RemoveAt(int index) { } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } public static bool TrueForAll(T[] array, System.Predicate match) { throw null; } } @@ -625,26 +625,26 @@ public static partial class BitConverter public System.TypeCode GetTypeCode() { throw null; } public static System.Boolean Parse(System.ReadOnlySpan value) { throw null; } public static System.Boolean Parse(string value) { throw null; } - System.Boolean System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + System.Boolean System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public System.Boolean TryFormat(System.Span destination, out int charsWritten) { throw null; } public static System.Boolean TryParse(System.ReadOnlySpan value, out System.Boolean result) { throw null; } - public static System.Boolean TryParse(string? value, out System.Boolean result) { throw null; } + public static System.Boolean TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? value, out System.Boolean result) { throw null; } } public static partial class Buffer { @@ -673,21 +673,21 @@ public static void SetByte(System.Array array, int index, byte value) { } public static System.Byte Parse(string s, System.Globalization.NumberStyles style) { throw null; } public static System.Byte Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } public static System.Byte Parse(string s, System.IFormatProvider? provider) { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - System.Byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + System.Byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString(string? format) { throw null; } @@ -695,8 +695,8 @@ public static void SetByte(System.Array array, int index, byte value) { } public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.Byte result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Byte result) { throw null; } - public static bool TryParse(string? s, out System.Byte result) { throw null; } - public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Byte result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.Byte result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Byte result) { throw null; } } public partial class CannotUnloadAppDomainException : System.SystemException { @@ -754,21 +754,21 @@ public CannotUnloadAppDomainException(string? message, System.Exception? innerEx public static bool IsWhiteSpace(System.Char c) { throw null; } public static bool IsWhiteSpace(string s, int index) { throw null; } public static System.Char Parse(string s) { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - System.Char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + System.Char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public static System.Char ToLower(System.Char c) { throw null; } public static System.Char ToLower(System.Char c, System.Globalization.CultureInfo culture) { throw null; } public static System.Char ToLowerInvariant(System.Char c) { throw null; } @@ -778,7 +778,7 @@ public CannotUnloadAppDomainException(string? message, System.Exception? innerEx public static System.Char ToUpper(System.Char c) { throw null; } public static System.Char ToUpper(System.Char c, System.Globalization.CultureInfo culture) { throw null; } public static System.Char ToUpperInvariant(System.Char c) { throw null; } - public static bool TryParse(string? s, out System.Char result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.Char result) { throw null; } } public sealed partial class CharEnumerator : System.Collections.Generic.IEnumerator, System.Collections.IEnumerator, System.ICloneable, System.IDisposable { @@ -1344,21 +1344,21 @@ public static partial class Convert public static System.DateTime SpecifyKind(System.DateTime value, System.DateTimeKind kind) { throw null; } public System.TimeSpan Subtract(System.DateTime value) { throw null; } public System.DateTime Subtract(System.TimeSpan value) { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } public long ToBinary() { throw null; } public long ToFileTime() { throw null; } @@ -1377,12 +1377,12 @@ void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Ser public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.DateTime result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.IFormatProvider? provider, System.Globalization.DateTimeStyles styles, out System.DateTime result) { throw null; } - public static bool TryParse(string? s, out System.DateTime result) { throw null; } - public static bool TryParse(string? s, System.IFormatProvider? provider, System.Globalization.DateTimeStyles styles, out System.DateTime result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.DateTime result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.IFormatProvider? provider, System.Globalization.DateTimeStyles styles, out System.DateTime result) { throw null; } public static bool TryParseExact(System.ReadOnlySpan s, System.ReadOnlySpan format, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } - public static bool TryParseExact(System.ReadOnlySpan s, string?[]? formats, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } - public static bool TryParseExact(string? s, string? format, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } - public static bool TryParseExact(string? s, string?[]? formats, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } + public static bool TryParseExact(System.ReadOnlySpan s, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string?[]? formats, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } + public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? format, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } + public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string?[]? formats, System.IFormatProvider? provider, System.Globalization.DateTimeStyles style, out System.DateTime result) { throw null; } } public enum DateTimeKind { @@ -1461,8 +1461,8 @@ public enum DateTimeKind public static System.DateTimeOffset ParseExact(string input, string[] formats, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles) { throw null; } public System.TimeSpan Subtract(System.DateTimeOffset value) { throw null; } public System.DateTimeOffset Subtract(System.TimeSpan value) { throw null; } - int System.IComparable.CompareTo(object obj) { throw null; } - void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object sender) { } + int System.IComparable.CompareTo(object? obj) { throw null; } + void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object? sender) { } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } public long ToFileTime() { throw null; } public System.DateTimeOffset ToLocalTime() { throw null; } @@ -1477,12 +1477,12 @@ void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Ser public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? formatProvider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan input, out System.DateTimeOffset result) { throw null; } public static bool TryParse(System.ReadOnlySpan input, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } - public static bool TryParse(string? input, out System.DateTimeOffset result) { throw null; } - public static bool TryParse(string? input, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, out System.DateTimeOffset result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } public static bool TryParseExact(System.ReadOnlySpan input, System.ReadOnlySpan format, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } - public static bool TryParseExact(System.ReadOnlySpan input, string?[]? formats, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } - public static bool TryParseExact(string? input, string? format, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } - public static bool TryParseExact(string? input, string?[]? formats, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } + public static bool TryParseExact(System.ReadOnlySpan input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string?[]? formats, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } + public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? format, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } + public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string?[]? formats, System.IFormatProvider? formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; } } public enum DayOfWeek { @@ -1500,21 +1500,21 @@ internal DBNull() { } public static readonly System.DBNull Value; public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } public System.TypeCode GetTypeCode() { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } } @@ -1615,22 +1615,22 @@ public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, S public static System.Decimal Round(System.Decimal d, int decimals, System.MidpointRounding mode) { throw null; } public static System.Decimal Round(System.Decimal d, System.MidpointRounding mode) { throw null; } public static System.Decimal Subtract(System.Decimal d1, System.Decimal d2) { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } - void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object sender) { } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } + void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object? sender) { } public static byte ToByte(System.Decimal value) { throw null; } public static double ToDouble(System.Decimal d) { throw null; } public static short ToInt16(System.Decimal value) { throw null; } @@ -1655,8 +1655,8 @@ void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(obj public static bool TryGetBits(System.Decimal d, System.Span destination, out int valuesWritten) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.Decimal result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Decimal result) { throw null; } - public static bool TryParse(string? s, out System.Decimal result) { throw null; } - public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Decimal result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.Decimal result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Decimal result) { throw null; } } public abstract partial class Delegate : System.ICloneable, System.Runtime.Serialization.ISerializable { @@ -1734,21 +1734,21 @@ public DivideByZeroException(string? message, System.Exception? innerException) public static System.Double Parse(string s, System.Globalization.NumberStyles style) { throw null; } public static System.Double Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } public static System.Double Parse(string s, System.IFormatProvider? provider) { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - System.Double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + System.Double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString(string? format) { throw null; } @@ -1756,8 +1756,8 @@ public DivideByZeroException(string? message, System.Exception? innerException) public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.Double result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Double result) { throw null; } - public static bool TryParse(string? s, out System.Double result) { throw null; } - public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Double result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.Double result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Double result) { throw null; } } public partial class DuplicateWaitObjectException : System.ArgumentException { @@ -1792,21 +1792,21 @@ protected Enum() { } public static object Parse(System.Type enumType, string value, bool ignoreCase) { throw null; } public static TEnum Parse(string value) where TEnum : struct { throw null; } public static TEnum Parse(string value, bool ignoreCase) where TEnum : struct { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public static object ToObject(System.Type enumType, byte value) { throw null; } public static object ToObject(System.Type enumType, short value) { throw null; } public static object ToObject(System.Type enumType, int value) { throw null; } @@ -2000,7 +2000,7 @@ protected FormattableString() { } public abstract object? GetArgument(int index); public abstract object?[] GetArguments(); public static string Invariant(System.FormattableString formattable) { throw null; } - string System.IFormattable.ToString(string ignored, System.IFormatProvider formatProvider) { throw null; } + string System.IFormattable.ToString(string? ignored, System.IFormatProvider? formatProvider) { throw null; } public override string ToString() { throw null; } public abstract string ToString(System.IFormatProvider? formatProvider); } @@ -2136,9 +2136,9 @@ public partial struct Guid : System.IComparable, System.IComparable public string ToString(string? format, System.IFormatProvider? provider) { throw null; } public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan)) { throw null; } public static bool TryParse(System.ReadOnlySpan input, out System.Guid result) { throw null; } - public static bool TryParse(string? input, out System.Guid result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, out System.Guid result) { throw null; } public static bool TryParseExact(System.ReadOnlySpan input, System.ReadOnlySpan format, out System.Guid result) { throw null; } - public static bool TryParseExact(string? input, string? format, out System.Guid result) { throw null; } + public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? format, out System.Guid result) { throw null; } public bool TryWriteBytes(System.Span destination) { throw null; } } public partial struct HashCode @@ -2281,21 +2281,21 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep public static System.Int16 Parse(string s, System.Globalization.NumberStyles style) { throw null; } public static System.Int16 Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } public static System.Int16 Parse(string s, System.IFormatProvider? provider) { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - System.Int16 System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + System.Int16 System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString(string? format) { throw null; } @@ -2303,8 +2303,8 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Int16 result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.Int16 result) { throw null; } - public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Int16 result) { throw null; } - public static bool TryParse(string? s, out System.Int16 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Int16 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.Int16 result) { throw null; } } public readonly partial struct Int32 : System.IComparable, System.IComparable, System.IConvertible, System.IEquatable, System.IFormattable { @@ -2322,21 +2322,21 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep public static System.Int32 Parse(string s, System.Globalization.NumberStyles style) { throw null; } public static System.Int32 Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } public static System.Int32 Parse(string s, System.IFormatProvider? provider) { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - System.Int32 System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + System.Int32 System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString(string? format) { throw null; } @@ -2344,8 +2344,8 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep public bool TryFormat(System.Span destination, out System.Int32 charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Int32 result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.Int32 result) { throw null; } - public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Int32 result) { throw null; } - public static bool TryParse(string? s, out System.Int32 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Int32 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.Int32 result) { throw null; } } public readonly partial struct Int64 : System.IComparable, System.IComparable, System.IConvertible, System.IEquatable, System.IFormattable { @@ -2363,21 +2363,21 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep public static System.Int64 Parse(string s, System.Globalization.NumberStyles style) { throw null; } public static System.Int64 Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } public static System.Int64 Parse(string s, System.IFormatProvider? provider) { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - System.Int64 System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + System.Int64 System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString(string? format) { throw null; } @@ -2385,10 +2385,10 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Int64 result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.Int64 result) { throw null; } - public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Int64 result) { throw null; } - public static bool TryParse(string? s, out System.Int64 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Int64 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.Int64 result) { throw null; } } - public readonly partial struct IntPtr : System.IEquatable, System.Runtime.Serialization.ISerializable + public readonly partial struct IntPtr : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.Runtime.Serialization.ISerializable { private readonly int _dummyPrimitive; public static readonly System.IntPtr Zero; @@ -2396,8 +2396,13 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep public IntPtr(long value) { throw null; } [System.CLSCompliantAttribute(false)] public unsafe IntPtr(void* value) { throw null; } + public static System.IntPtr MaxValue { get { throw null; } } + public static System.IntPtr MinValue { get { throw null; } } public static int Size { get { throw null; } } public static System.IntPtr Add(System.IntPtr pointer, int offset) { throw null; } + public int CompareTo(System.IntPtr value) { throw null; } + public int CompareTo(object? value) { throw null; } + public bool Equals(System.IntPtr other) { throw null; } public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } public static System.IntPtr operator +(System.IntPtr pointer, int offset) { throw null; } @@ -2412,15 +2417,22 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep public unsafe static explicit operator System.IntPtr (void* value) { throw null; } public static bool operator !=(System.IntPtr value1, System.IntPtr value2) { throw null; } public static System.IntPtr operator -(System.IntPtr pointer, int offset) { throw null; } + public static System.IntPtr Parse(string s) { throw null; } + public static System.IntPtr Parse(string s, System.Globalization.NumberStyles style) { throw null; } + public static System.IntPtr Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } + public static System.IntPtr Parse(string s, System.IFormatProvider? provider) { throw null; } public static System.IntPtr Subtract(System.IntPtr pointer, int offset) { throw null; } - bool System.IEquatable.Equals(System.IntPtr other) { throw null; } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } public int ToInt32() { throw null; } public long ToInt64() { throw null; } [System.CLSCompliantAttribute(false)] public unsafe void* ToPointer() { throw null; } public override string ToString() { throw null; } - public string ToString(string format) { throw null; } + public string ToString(System.IFormatProvider? provider) { throw null; } + public string ToString(string? format) { throw null; } + public string ToString(string? format, System.IFormatProvider? provider) { throw null; } + public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.IntPtr result) { throw null; } + public static bool TryParse(string? s, out System.IntPtr result) { throw null; } } public partial class InvalidCastException : System.SystemException { @@ -2536,6 +2548,9 @@ public static partial class Math public static double Atan2(double y, double x) { throw null; } public static double Atanh(double d) { throw null; } public static long BigMul(int a, int b) { throw null; } + [System.CLSCompliantAttribute(false)] + public static ulong BigMul(ulong a, ulong b, out ulong low) { throw null; } + public static long BigMul(long a, long b, out long low) { throw null; } public static double BitDecrement(double x) { throw null; } public static double BitIncrement(double x) { throw null; } public static double Cbrt(double d) { throw null; } @@ -3138,21 +3153,21 @@ public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, S public static System.SByte Parse(string s, System.Globalization.NumberStyles style) { throw null; } public static System.SByte Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } public static System.SByte Parse(string s, System.IFormatProvider? provider) { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - System.SByte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + System.SByte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString(string? format) { throw null; } @@ -3160,8 +3175,8 @@ public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, S public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.SByte result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.SByte result) { throw null; } - public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.SByte result) { throw null; } - public static bool TryParse(string? s, out System.SByte result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.SByte result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.SByte result) { throw null; } } [System.AttributeUsageAttribute(System.AttributeTargets.Class | System.AttributeTargets.Delegate | System.AttributeTargets.Enum | System.AttributeTargets.Struct, Inherited=false)] public sealed partial class SerializableAttribute : System.Attribute @@ -3202,21 +3217,21 @@ public SerializableAttribute() { } public static System.Single Parse(string s, System.Globalization.NumberStyles style) { throw null; } public static System.Single Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } public static System.Single Parse(string s, System.IFormatProvider? provider) { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - System.Single System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + System.Single System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString(string? format) { throw null; } @@ -3224,8 +3239,8 @@ public SerializableAttribute() { } public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Single result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.Single result) { throw null; } - public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Single result) { throw null; } - public static bool TryParse(string? s, out System.Single result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.Single result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.Single result) { throw null; } } public readonly ref partial struct Span { @@ -3437,21 +3452,21 @@ public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, in public System.String Substring(int startIndex, int length) { throw null; } System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public char[] ToCharArray() { throw null; } public char[] ToCharArray(int startIndex, int length) { throw null; } public System.String ToLower() { throw null; } @@ -3609,16 +3624,16 @@ public TimeoutException(string? message, System.Exception? innerException) { } public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? formatProvider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan input, System.IFormatProvider? formatProvider, out System.TimeSpan result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.TimeSpan result) { throw null; } - public static bool TryParse(string? input, System.IFormatProvider? formatProvider, out System.TimeSpan result) { throw null; } - public static bool TryParse(string? s, out System.TimeSpan result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, System.IFormatProvider? formatProvider, out System.TimeSpan result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.TimeSpan result) { throw null; } public static bool TryParseExact(System.ReadOnlySpan input, System.ReadOnlySpan format, System.IFormatProvider? formatProvider, System.Globalization.TimeSpanStyles styles, out System.TimeSpan result) { throw null; } public static bool TryParseExact(System.ReadOnlySpan input, System.ReadOnlySpan format, System.IFormatProvider? formatProvider, out System.TimeSpan result) { throw null; } - public static bool TryParseExact(System.ReadOnlySpan input, string[] formats, System.IFormatProvider? formatProvider, System.Globalization.TimeSpanStyles styles, out System.TimeSpan result) { throw null; } - public static bool TryParseExact(System.ReadOnlySpan input, string[] formats, System.IFormatProvider? formatProvider, out System.TimeSpan result) { throw null; } - public static bool TryParseExact(string? input, string format, System.IFormatProvider? formatProvider, System.Globalization.TimeSpanStyles styles, out System.TimeSpan result) { throw null; } - public static bool TryParseExact(string? input, string format, System.IFormatProvider? formatProvider, out System.TimeSpan result) { throw null; } - public static bool TryParseExact(string? input, string[] formats, System.IFormatProvider? formatProvider, System.Globalization.TimeSpanStyles styles, out System.TimeSpan result) { throw null; } - public static bool TryParseExact(string? input, string[] formats, System.IFormatProvider? formatProvider, out System.TimeSpan result) { throw null; } + public static bool TryParseExact(System.ReadOnlySpan input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string?[]? formats, System.IFormatProvider? formatProvider, System.Globalization.TimeSpanStyles styles, out System.TimeSpan result) { throw null; } + public static bool TryParseExact(System.ReadOnlySpan input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string?[]? formats, System.IFormatProvider? formatProvider, out System.TimeSpan result) { throw null; } + public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? format, System.IFormatProvider? formatProvider, System.Globalization.TimeSpanStyles styles, out System.TimeSpan result) { throw null; } + public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? format, System.IFormatProvider? formatProvider, out System.TimeSpan result) { throw null; } + public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string?[]? formats, System.IFormatProvider? formatProvider, System.Globalization.TimeSpanStyles styles, out System.TimeSpan result) { throw null; } + public static bool TryParseExact([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string?[]? formats, System.IFormatProvider? formatProvider, out System.TimeSpan result) { throw null; } } [System.ObsoleteAttribute("System.TimeZone has been deprecated. Please investigate the use of System.TimeZoneInfo instead.")] public abstract partial class TimeZone @@ -3675,7 +3690,7 @@ public static void ClearCachedData() { } public bool IsDaylightSavingTime(System.DateTime dateTime) { throw null; } public bool IsDaylightSavingTime(System.DateTimeOffset dateTimeOffset) { throw null; } public bool IsInvalidTime(System.DateTime dateTime) { throw null; } - void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object sender) { } + void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object? sender) { } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } public string ToSerializedString() { throw null; } public override string ToString() { throw null; } @@ -3690,7 +3705,7 @@ internal AdjustmentRule() { } public static System.TimeZoneInfo.AdjustmentRule CreateAdjustmentRule(System.DateTime dateStart, System.DateTime dateEnd, System.TimeSpan daylightDelta, System.TimeZoneInfo.TransitionTime daylightTransitionStart, System.TimeZoneInfo.TransitionTime daylightTransitionEnd) { throw null; } public bool Equals(System.TimeZoneInfo.AdjustmentRule? other) { throw null; } public override int GetHashCode() { throw null; } - void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object sender) { } + void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object? sender) { } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } } public readonly partial struct TransitionTime : System.IEquatable, System.Runtime.Serialization.IDeserializationCallback, System.Runtime.Serialization.ISerializable @@ -3709,7 +3724,7 @@ void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Ser public override int GetHashCode() { throw null; } public static bool operator ==(System.TimeZoneInfo.TransitionTime t1, System.TimeZoneInfo.TransitionTime t2) { throw null; } public static bool operator !=(System.TimeZoneInfo.TransitionTime t1, System.TimeZoneInfo.TransitionTime t2) { throw null; } - void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object sender) { } + void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object? sender) { } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } } } @@ -3826,10 +3841,10 @@ public Tuple(T1 item1) { } int System.Runtime.CompilerServices.ITuple.Length { get { throw null; } } public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object obj) { throw null; } + int System.IComparable.CompareTo(object? obj) { throw null; } public override string ToString() { throw null; } } public partial class Tuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.Runtime.CompilerServices.ITuple @@ -3841,10 +3856,10 @@ public Tuple(T1 item1, T2 item2) { } int System.Runtime.CompilerServices.ITuple.Length { get { throw null; } } public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object obj) { throw null; } + int System.IComparable.CompareTo(object? obj) { throw null; } public override string ToString() { throw null; } } public partial class Tuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.Runtime.CompilerServices.ITuple @@ -3857,10 +3872,10 @@ public Tuple(T1 item1, T2 item2, T3 item3) { } int System.Runtime.CompilerServices.ITuple.Length { get { throw null; } } public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object obj) { throw null; } + int System.IComparable.CompareTo(object? obj) { throw null; } public override string ToString() { throw null; } } public partial class Tuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.Runtime.CompilerServices.ITuple @@ -3874,10 +3889,10 @@ public Tuple(T1 item1, T2 item2, T3 item3, T4 item4) { } int System.Runtime.CompilerServices.ITuple.Length { get { throw null; } } public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object obj) { throw null; } + int System.IComparable.CompareTo(object? obj) { throw null; } public override string ToString() { throw null; } } public partial class Tuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.Runtime.CompilerServices.ITuple @@ -3892,10 +3907,10 @@ public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) { } int System.Runtime.CompilerServices.ITuple.Length { get { throw null; } } public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object obj) { throw null; } + int System.IComparable.CompareTo(object? obj) { throw null; } public override string ToString() { throw null; } } public partial class Tuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.Runtime.CompilerServices.ITuple @@ -3911,10 +3926,10 @@ public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) { } int System.Runtime.CompilerServices.ITuple.Length { get { throw null; } } public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object obj) { throw null; } + int System.IComparable.CompareTo(object? obj) { throw null; } public override string ToString() { throw null; } } public partial class Tuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.Runtime.CompilerServices.ITuple @@ -3931,10 +3946,10 @@ public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item int System.Runtime.CompilerServices.ITuple.Length { get { throw null; } } public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object obj) { throw null; } + int System.IComparable.CompareTo(object? obj) { throw null; } public override string ToString() { throw null; } } public partial class Tuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.Runtime.CompilerServices.ITuple where TRest : notnull @@ -3952,10 +3967,10 @@ public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item int System.Runtime.CompilerServices.ITuple.Length { get { throw null; } } public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object obj) { throw null; } + int System.IComparable.CompareTo(object? obj) { throw null; } public override string ToString() { throw null; } } public abstract partial class Type : System.Reflection.MemberInfo, System.Reflection.IReflect @@ -4232,21 +4247,21 @@ public TypeUnloadedException(string? message, System.Exception? innerException) public static System.UInt16 Parse(string s, System.Globalization.NumberStyles style) { throw null; } public static System.UInt16 Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } public static System.UInt16 Parse(string s, System.IFormatProvider? provider) { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - System.UInt16 System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + System.UInt16 System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString(string? format) { throw null; } @@ -4254,8 +4269,8 @@ public TypeUnloadedException(string? message, System.Exception? innerException) public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.UInt16 result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.UInt16 result) { throw null; } - public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.UInt16 result) { throw null; } - public static bool TryParse(string? s, out System.UInt16 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.UInt16 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.UInt16 result) { throw null; } } [System.CLSCompliantAttribute(false)] public readonly partial struct UInt32 : System.IComparable, System.IComparable, System.IConvertible, System.IEquatable, System.IFormattable @@ -4274,21 +4289,21 @@ public TypeUnloadedException(string? message, System.Exception? innerException) public static System.UInt32 Parse(string s, System.Globalization.NumberStyles style) { throw null; } public static System.UInt32 Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } public static System.UInt32 Parse(string s, System.IFormatProvider? provider) { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - System.UInt32 System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + System.UInt32 System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + ulong System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString(string? format) { throw null; } @@ -4296,8 +4311,8 @@ public TypeUnloadedException(string? message, System.Exception? innerException) public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.UInt32 result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.UInt32 result) { throw null; } - public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.UInt32 result) { throw null; } - public static bool TryParse(string? s, out System.UInt32 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.UInt32 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.UInt32 result) { throw null; } } [System.CLSCompliantAttribute(false)] public readonly partial struct UInt64 : System.IComparable, System.IComparable, System.IConvertible, System.IEquatable, System.IFormattable @@ -4316,21 +4331,21 @@ public TypeUnloadedException(string? message, System.Exception? innerException) public static System.UInt64 Parse(string s, System.Globalization.NumberStyles style) { throw null; } public static System.UInt64 Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } public static System.UInt64 Parse(string s, System.IFormatProvider? provider) { throw null; } - bool System.IConvertible.ToBoolean(System.IFormatProvider provider) { throw null; } - byte System.IConvertible.ToByte(System.IFormatProvider provider) { throw null; } - char System.IConvertible.ToChar(System.IFormatProvider provider) { throw null; } - System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) { throw null; } - decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) { throw null; } - double System.IConvertible.ToDouble(System.IFormatProvider provider) { throw null; } - short System.IConvertible.ToInt16(System.IFormatProvider provider) { throw null; } - int System.IConvertible.ToInt32(System.IFormatProvider provider) { throw null; } - long System.IConvertible.ToInt64(System.IFormatProvider provider) { throw null; } - sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) { throw null; } - float System.IConvertible.ToSingle(System.IFormatProvider provider) { throw null; } - object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) { throw null; } - ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) { throw null; } - uint System.IConvertible.ToUInt32(System.IFormatProvider provider) { throw null; } - System.UInt64 System.IConvertible.ToUInt64(System.IFormatProvider provider) { throw null; } + bool System.IConvertible.ToBoolean(System.IFormatProvider? provider) { throw null; } + byte System.IConvertible.ToByte(System.IFormatProvider? provider) { throw null; } + char System.IConvertible.ToChar(System.IFormatProvider? provider) { throw null; } + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider? provider) { throw null; } + decimal System.IConvertible.ToDecimal(System.IFormatProvider? provider) { throw null; } + double System.IConvertible.ToDouble(System.IFormatProvider? provider) { throw null; } + short System.IConvertible.ToInt16(System.IFormatProvider? provider) { throw null; } + int System.IConvertible.ToInt32(System.IFormatProvider? provider) { throw null; } + long System.IConvertible.ToInt64(System.IFormatProvider? provider) { throw null; } + sbyte System.IConvertible.ToSByte(System.IFormatProvider? provider) { throw null; } + float System.IConvertible.ToSingle(System.IFormatProvider? provider) { throw null; } + object System.IConvertible.ToType(System.Type type, System.IFormatProvider? provider) { throw null; } + ushort System.IConvertible.ToUInt16(System.IFormatProvider? provider) { throw null; } + uint System.IConvertible.ToUInt32(System.IFormatProvider? provider) { throw null; } + System.UInt64 System.IConvertible.ToUInt64(System.IFormatProvider? provider) { throw null; } public override string ToString() { throw null; } public string ToString(System.IFormatProvider? provider) { throw null; } public string ToString(string? format) { throw null; } @@ -4338,20 +4353,25 @@ public TypeUnloadedException(string? message, System.Exception? innerException) public bool TryFormat(System.Span destination, out int charsWritten, System.ReadOnlySpan format = default(System.ReadOnlySpan), System.IFormatProvider? provider = null) { throw null; } public static bool TryParse(System.ReadOnlySpan s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.UInt64 result) { throw null; } public static bool TryParse(System.ReadOnlySpan s, out System.UInt64 result) { throw null; } - public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.UInt64 result) { throw null; } - public static bool TryParse(string? s, out System.UInt64 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.UInt64 result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? s, out System.UInt64 result) { throw null; } } [System.CLSCompliantAttribute(false)] - public readonly partial struct UIntPtr : System.IEquatable, System.Runtime.Serialization.ISerializable + public readonly partial struct UIntPtr : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.Runtime.Serialization.ISerializable { private readonly int _dummyPrimitive; public static readonly System.UIntPtr Zero; public UIntPtr(uint value) { throw null; } public UIntPtr(ulong value) { throw null; } public unsafe UIntPtr(void* value) { throw null; } + public static System.UIntPtr MaxValue { get { throw null; } } + public static System.UIntPtr MinValue { get { throw null; } } public static int Size { get { throw null; } } public static System.UIntPtr Add(System.UIntPtr pointer, int offset) { throw null; } + public int CompareTo(object? value) { throw null; } + public int CompareTo(System.UIntPtr value) { throw null; } public override bool Equals(object? obj) { throw null; } + public bool Equals(System.UIntPtr other) { throw null; } public override int GetHashCode() { throw null; } public static System.UIntPtr operator +(System.UIntPtr pointer, int offset) { throw null; } public static bool operator ==(System.UIntPtr value1, System.UIntPtr value2) { throw null; } @@ -4363,13 +4383,21 @@ public TypeUnloadedException(string? message, System.Exception? innerException) public unsafe static explicit operator System.UIntPtr (void* value) { throw null; } public static bool operator !=(System.UIntPtr value1, System.UIntPtr value2) { throw null; } public static System.UIntPtr operator -(System.UIntPtr pointer, int offset) { throw null; } + public static System.UIntPtr Parse(string s) { throw null; } + public static System.UIntPtr Parse(string s, System.Globalization.NumberStyles style) { throw null; } + public static System.UIntPtr Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider? provider) { throw null; } + public static System.UIntPtr Parse(string s, System.IFormatProvider? provider) { throw null; } public static System.UIntPtr Subtract(System.UIntPtr pointer, int offset) { throw null; } - bool System.IEquatable.Equals(System.UIntPtr other) { throw null; } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } public unsafe void* ToPointer() { throw null; } public override string ToString() { throw null; } + public string ToString(System.IFormatProvider? provider) { throw null; } + public string ToString(string? format) { throw null; } + public string ToString(string? format, System.IFormatProvider? provider) { throw null; } public uint ToUInt32() { throw null; } public ulong ToUInt64() { throw null; } + public static bool TryParse(string? s, System.Globalization.NumberStyles style, System.IFormatProvider? provider, out System.UIntPtr result) { throw null; } + public static bool TryParse(string? s, out System.UIntPtr result) { throw null; } } public partial class UnauthorizedAccessException : System.SystemException { @@ -4592,10 +4620,10 @@ public partial struct ValueTuple : System.Collections.IStructuralComparable, Sys public override bool Equals(object? obj) { throw null; } public bool Equals(System.ValueTuple other) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object other) { throw null; } + int System.IComparable.CompareTo(object? other) { throw null; } public override string ToString() { throw null; } } public partial struct ValueTuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.IComparable>, System.IEquatable>, System.Runtime.CompilerServices.ITuple @@ -4608,10 +4636,10 @@ public partial struct ValueTuple : System.Collections.IStructuralComparable, public override bool Equals(object? obj) { throw null; } public bool Equals(System.ValueTuple other) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object other) { throw null; } + int System.IComparable.CompareTo(object? other) { throw null; } public override string ToString() { throw null; } } public partial struct ValueTuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.IComparable<(T1, T2)>, System.IEquatable<(T1, T2)>, System.Runtime.CompilerServices.ITuple @@ -4625,10 +4653,10 @@ public partial struct ValueTuple : System.Collections.IStructuralCompara public override bool Equals(object? obj) { throw null; } public bool Equals((T1, T2) other) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object other) { throw null; } + int System.IComparable.CompareTo(object? other) { throw null; } public override string ToString() { throw null; } } public partial struct ValueTuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.IComparable<(T1, T2, T3)>, System.IEquatable<(T1, T2, T3)>, System.Runtime.CompilerServices.ITuple @@ -4643,10 +4671,10 @@ public partial struct ValueTuple : System.Collections.IStructuralCom public override bool Equals(object? obj) { throw null; } public bool Equals((T1, T2, T3) other) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object other) { throw null; } + int System.IComparable.CompareTo(object? other) { throw null; } public override string ToString() { throw null; } } public partial struct ValueTuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.IComparable<(T1, T2, T3, T4)>, System.IEquatable<(T1, T2, T3, T4)>, System.Runtime.CompilerServices.ITuple @@ -4662,10 +4690,10 @@ public partial struct ValueTuple : System.Collections.IStructura public override bool Equals(object? obj) { throw null; } public bool Equals((T1, T2, T3, T4) other) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object other) { throw null; } + int System.IComparable.CompareTo(object? other) { throw null; } public override string ToString() { throw null; } } public partial struct ValueTuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.IComparable<(T1, T2, T3, T4, T5)>, System.IEquatable<(T1, T2, T3, T4, T5)>, System.Runtime.CompilerServices.ITuple @@ -4682,10 +4710,10 @@ public partial struct ValueTuple : System.Collections.IStruc public override bool Equals(object? obj) { throw null; } public bool Equals((T1, T2, T3, T4, T5) other) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object other) { throw null; } + int System.IComparable.CompareTo(object? other) { throw null; } public override string ToString() { throw null; } } public partial struct ValueTuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.IComparable<(T1, T2, T3, T4, T5, T6)>, System.IEquatable<(T1, T2, T3, T4, T5, T6)>, System.Runtime.CompilerServices.ITuple @@ -4703,10 +4731,10 @@ public partial struct ValueTuple : System.Collections.IS public override bool Equals(object? obj) { throw null; } public bool Equals((T1, T2, T3, T4, T5, T6) other) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object other) { throw null; } + int System.IComparable.CompareTo(object? other) { throw null; } public override string ToString() { throw null; } } public partial struct ValueTuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.IComparable<(T1, T2, T3, T4, T5, T6, T7)>, System.IEquatable<(T1, T2, T3, T4, T5, T6, T7)>, System.Runtime.CompilerServices.ITuple @@ -4725,10 +4753,10 @@ public partial struct ValueTuple : System.Collection public override bool Equals(object? obj) { throw null; } public bool Equals((T1, T2, T3, T4, T5, T6, T7) other) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object other) { throw null; } + int System.IComparable.CompareTo(object? other) { throw null; } public override string ToString() { throw null; } } public partial struct ValueTuple : System.Collections.IStructuralComparable, System.Collections.IStructuralEquatable, System.IComparable, System.IComparable>, System.IEquatable>, System.Runtime.CompilerServices.ITuple where TRest : struct @@ -4748,10 +4776,10 @@ public partial struct ValueTuple : System.Col public override bool Equals(object? obj) { throw null; } public bool Equals(System.ValueTuple other) { throw null; } public override int GetHashCode() { throw null; } - int System.Collections.IStructuralComparable.CompareTo(object other, System.Collections.IComparer comparer) { throw null; } - bool System.Collections.IStructuralEquatable.Equals(object other, System.Collections.IEqualityComparer comparer) { throw null; } + int System.Collections.IStructuralComparable.CompareTo(object? other, System.Collections.IComparer comparer) { throw null; } + bool System.Collections.IStructuralEquatable.Equals(object? other, System.Collections.IEqualityComparer comparer) { throw null; } int System.Collections.IStructuralEquatable.GetHashCode(System.Collections.IEqualityComparer comparer) { throw null; } - int System.IComparable.CompareTo(object other) { throw null; } + int System.IComparable.CompareTo(object? other) { throw null; } public override string ToString() { throw null; } } public abstract partial class ValueType @@ -4793,7 +4821,7 @@ public Version(string version) { } public bool TryFormat(System.Span destination, int fieldCount, out int charsWritten) { throw null; } public bool TryFormat(System.Span destination, out int charsWritten) { throw null; } public static bool TryParse(System.ReadOnlySpan input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Version? result) { throw null; } - public static bool TryParse(string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Version? result) { throw null; } + public static bool TryParse([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? input, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Version? result) { throw null; } } public partial struct Void { @@ -5275,11 +5303,11 @@ protected virtual void RemoveItem(int index) { } protected virtual void SetItem(int index, T item) { } void System.Collections.ICollection.CopyTo(System.Array array, int index) { } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - int System.Collections.IList.Add(object value) { throw null; } - bool System.Collections.IList.Contains(object value) { throw null; } - int System.Collections.IList.IndexOf(object value) { throw null; } - void System.Collections.IList.Insert(int index, object value) { } - void System.Collections.IList.Remove(object value) { } + int System.Collections.IList.Add(object? value) { throw null; } + bool System.Collections.IList.Contains(object? value) { throw null; } + int System.Collections.IList.IndexOf(object? value) { throw null; } + void System.Collections.IList.Insert(int index, object? value) { } + void System.Collections.IList.Remove(object? value) { } } public partial class ReadOnlyCollection : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.IList, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IReadOnlyList, System.Collections.ICollection, System.Collections.IEnumerable, System.Collections.IList { @@ -5305,12 +5333,12 @@ void System.Collections.Generic.IList.Insert(int index, T value) { } void System.Collections.Generic.IList.RemoveAt(int index) { } void System.Collections.ICollection.CopyTo(System.Array array, int index) { } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - int System.Collections.IList.Add(object value) { throw null; } + int System.Collections.IList.Add(object? value) { throw null; } void System.Collections.IList.Clear() { } - bool System.Collections.IList.Contains(object value) { throw null; } - int System.Collections.IList.IndexOf(object value) { throw null; } - void System.Collections.IList.Insert(int index, object value) { } - void System.Collections.IList.Remove(object value) { } + bool System.Collections.IList.Contains(object? value) { throw null; } + int System.Collections.IList.IndexOf(object? value) { throw null; } + void System.Collections.IList.Insert(int index, object? value) { } + void System.Collections.IList.Remove(object? value) { } void System.Collections.IList.RemoveAt(int index) { } } } @@ -5402,10 +5430,10 @@ public static void Assert([System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttrib public static void Close() { } [System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] [System.Diagnostics.ConditionalAttribute("DEBUG")] - public static void Fail(string? message) => throw null; + public static void Fail(string? message) => throw null; [System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] [System.Diagnostics.ConditionalAttribute("DEBUG")] - public static void Fail(string? message, string? detailMessage) => throw null; + public static void Fail(string? message, string? detailMessage) => throw null; [System.Diagnostics.ConditionalAttribute("DEBUG")] public static void Flush() { } [System.Diagnostics.ConditionalAttribute("DEBUG")] @@ -5585,6 +5613,46 @@ public sealed partial class DoesNotReturnIfAttribute : System.Attribute public DoesNotReturnIfAttribute(bool parameterValue) { } public bool ParameterValue { get { throw null; } } } + [System.AttributeUsageAttribute(System.AttributeTargets.Constructor | System.AttributeTargets.Field | System.AttributeTargets.Method, AllowMultiple = true, Inherited = false)] + public sealed class DynamicDependencyAttribute : System.Attribute + { + public DynamicDependencyAttribute(string memberSignature) { } + public DynamicDependencyAttribute(string memberSignature, Type type) { } + public DynamicDependencyAttribute(string memberSignature, string typeName, string assemblyName) { } + public DynamicDependencyAttribute(DynamicallyAccessedMemberTypes memberTypes, Type type) { } + public DynamicDependencyAttribute(DynamicallyAccessedMemberTypes memberTypes, string typeName, string assemblyName) { } + public DynamicallyAccessedMemberTypes MemberTypes { get { throw null; } } + public string? MemberSignature { get { throw null; } } + public Type? Type { get { throw null; } } + public string? TypeName { get { throw null; } } + public string? AssemblyName { get { throw null; } } + public string? Condition { get { throw null; } set { } } + } + [System.AttributeUsageAttribute(System.AttributeTargets.Field | System.AttributeTargets.GenericParameter | System.AttributeTargets.Parameter | System.AttributeTargets.Property | System.AttributeTargets.ReturnValue, Inherited = false)] + public sealed class DynamicallyAccessedMembersAttribute : System.Attribute + { + public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes) { } + public DynamicallyAccessedMemberTypes MemberTypes { get { throw null; } } + } + [System.FlagsAttribute] + public enum DynamicallyAccessedMemberTypes + { + All = -1, + None = 0, + DefaultConstructor = 1, + PublicConstructors = 3, + NonPublicConstructors = 4, + PublicMethods = 8, + NonPublicMethods = 16, + PublicFields = 32, + NonPublicFields = 64, + PublicNestedTypes = 128, + NonPublicNestedTypes = 256, + PublicProperties = 512, + NonPublicProperties = 1024, + PublicEvents = 2048, + NonPublicEvents = 4096, + } [System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Constructor | System.AttributeTargets.Event | System.AttributeTargets.Method | System.AttributeTargets.Property | System.AttributeTargets.Struct, Inherited=false, AllowMultiple=false)] public sealed partial class ExcludeFromCodeCoverageAttribute : System.Attribute { @@ -5633,6 +5701,13 @@ public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { } public bool ReturnValue { get { throw null; } } public string[] Members { get { throw null; } } } + [System.AttributeUsageAttribute(System.AttributeTargets.Method | System.AttributeTargets.Constructor, Inherited = false)] + public sealed class RequiresUnreferencedCodeAttribute : System.Attribute + { + public RequiresUnreferencedCodeAttribute(string message) { } + public string Message { get { throw null; } } + public string? Url { get { throw null; } set { } } + } [System.AttributeUsageAttribute(System.AttributeTargets.All, Inherited=false, AllowMultiple=true)] [System.Diagnostics.ConditionalAttribute("CODE_ANALYSIS")] public sealed partial class SuppressMessageAttribute : System.Attribute @@ -5645,6 +5720,17 @@ public SuppressMessageAttribute(string category, string checkId) { } public string? Scope { get { throw null; } set { } } public string? Target { get { throw null; } set { } } } + [System.AttributeUsageAttribute(System.AttributeTargets.All, Inherited=false, AllowMultiple=true)] + public sealed class UnconditionalSuppressMessageAttribute : System.Attribute + { + public UnconditionalSuppressMessageAttribute(string category, string checkId) { } + public string Category { get { throw null; } } + public string CheckId { get { throw null; } } + public string? Justification { get { throw null; } set { } } + public string? MessageId { get { throw null; } set { } } + public string? Scope { get { throw null; } set { } } + public string? Target { get { throw null; } set { } } + } } namespace System.Globalization { @@ -5739,6 +5825,7 @@ internal CompareInfo() { } public int LCID { get { throw null; } } public string Name { get { throw null; } } public System.Globalization.SortVersion Version { get { throw null; } } + public int Compare(System.ReadOnlySpan string1, System.ReadOnlySpan string2, System.Globalization.CompareOptions options = System.Globalization.CompareOptions.None) { throw null; } public int Compare(string? string1, int offset1, int length1, string? string2, int offset2, int length2) { throw null; } public int Compare(string? string1, int offset1, int length1, string? string2, int offset2, int length2, System.Globalization.CompareOptions options) { throw null; } public int Compare(string? string1, int offset1, string? string2, int offset2) { throw null; } @@ -5755,6 +5842,8 @@ internal CompareInfo() { } public int GetHashCode(string source, System.Globalization.CompareOptions options) { throw null; } public System.Globalization.SortKey GetSortKey(string source) { throw null; } public System.Globalization.SortKey GetSortKey(string source, System.Globalization.CompareOptions options) { throw null; } + public int GetSortKey(System.ReadOnlySpan source, System.Span destination, System.Globalization.CompareOptions options = System.Globalization.CompareOptions.None) { throw null; } + public int GetSortKeyLength(System.ReadOnlySpan source, System.Globalization.CompareOptions options = System.Globalization.CompareOptions.None) { throw null; } public int IndexOf(string source, char value) { throw null; } public int IndexOf(string source, char value, System.Globalization.CompareOptions options) { throw null; } public int IndexOf(string source, char value, int startIndex) { throw null; } @@ -5767,12 +5856,18 @@ internal CompareInfo() { } public int IndexOf(string source, string value, int startIndex, System.Globalization.CompareOptions options) { throw null; } public int IndexOf(string source, string value, int startIndex, int count) { throw null; } public int IndexOf(string source, string value, int startIndex, int count, System.Globalization.CompareOptions options) { throw null; } + public int IndexOf(System.ReadOnlySpan source, System.ReadOnlySpan value, System.Globalization.CompareOptions options = System.Globalization.CompareOptions.None) { throw null; } + public int IndexOf(System.ReadOnlySpan source, System.Text.Rune value, System.Globalization.CompareOptions options = System.Globalization.CompareOptions.None) { throw null; } public bool IsPrefix(string source, string prefix) { throw null; } public bool IsPrefix(string source, string prefix, System.Globalization.CompareOptions options) { throw null; } + public bool IsPrefix(System.ReadOnlySpan source, System.ReadOnlySpan prefix, System.Globalization.CompareOptions options = System.Globalization.CompareOptions.None) { throw null; } public static bool IsSortable(char ch) { throw null; } + public static bool IsSortable(System.ReadOnlySpan text) { throw null; } public static bool IsSortable(string text) { throw null; } + public static bool IsSortable(System.Text.Rune value) { throw null; } public bool IsSuffix(string source, string suffix) { throw null; } public bool IsSuffix(string source, string suffix, System.Globalization.CompareOptions options) { throw null; } + public bool IsSuffix(System.ReadOnlySpan source, System.ReadOnlySpan suffix, System.Globalization.CompareOptions options = System.Globalization.CompareOptions.None) { throw null; } public int LastIndexOf(string source, char value) { throw null; } public int LastIndexOf(string source, char value, System.Globalization.CompareOptions options) { throw null; } public int LastIndexOf(string source, char value, int startIndex) { throw null; } @@ -5785,7 +5880,9 @@ internal CompareInfo() { } public int LastIndexOf(string source, string value, int startIndex, System.Globalization.CompareOptions options) { throw null; } public int LastIndexOf(string source, string value, int startIndex, int count) { throw null; } public int LastIndexOf(string source, string value, int startIndex, int count, System.Globalization.CompareOptions options) { throw null; } - void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object sender) { } + public int LastIndexOf(System.ReadOnlySpan source, System.ReadOnlySpan value, System.Globalization.CompareOptions options = System.Globalization.CompareOptions.None) { throw null; } + public int LastIndexOf(System.ReadOnlySpan source, System.Text.Rune value, System.Globalization.CompareOptions options = System.Globalization.CompareOptions.None) { throw null; } + void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object? sender) { } public override string ToString() { throw null; } } [System.FlagsAttribute] @@ -6408,7 +6505,7 @@ internal TextInfo() { } public override bool Equals(object? obj) { throw null; } public override int GetHashCode() { throw null; } public static System.Globalization.TextInfo ReadOnly(System.Globalization.TextInfo textInfo) { throw null; } - void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object sender) { } + void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object? sender) { } public char ToLower(char c) { throw null; } public string ToLower(string str) { throw null; } public override string ToString() { throw null; } @@ -6530,7 +6627,8 @@ protected virtual void FillBuffer(int numBytes) { } public virtual int Read(char[] buffer, int index, int count) { throw null; } public virtual int Read(System.Span buffer) { throw null; } public virtual int Read(System.Span buffer) { throw null; } - protected internal int Read7BitEncodedInt() { throw null; } + public int Read7BitEncodedInt() { throw null; } + public long Read7BitEncodedInt64() { throw null; } public virtual bool ReadBoolean() { throw null; } public virtual byte ReadByte() { throw null; } public virtual byte[] ReadBytes(int count) { throw null; } @@ -6591,7 +6689,8 @@ public virtual void Write(ushort value) { } public virtual void Write(uint value) { } [System.CLSCompliantAttribute(false)] public virtual void Write(ulong value) { } - protected void Write7BitEncodedInt(int value) { } + public void Write7BitEncodedInt(int value) { } + public void Write7BitEncodedInt64(long value) { } } public sealed partial class BufferedStream : System.IO.Stream { @@ -8028,6 +8127,8 @@ protected MethodInfo() { } public abstract System.Reflection.ICustomAttributeProvider ReturnTypeCustomAttributes { get; } public virtual System.Delegate CreateDelegate(System.Type delegateType) { throw null; } public virtual System.Delegate CreateDelegate(System.Type delegateType, object? target) { throw null; } + public T CreateDelegate() where T : System.Delegate { throw null; } + public T CreateDelegate(object? target) where T : System.Delegate { throw null; } public override bool Equals(object? obj) { throw null; } public abstract System.Reflection.MethodInfo GetBaseDefinition(); public override System.Type[] GetGenericArguments() { throw null; } @@ -8290,7 +8391,7 @@ public StrongNameKeyPair(System.IO.FileStream keyPairFile) { } protected StrongNameKeyPair(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } public StrongNameKeyPair(string keyPairContainer) { } public byte[] PublicKey { get { throw null; } } - void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object sender) { } + void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object? sender) { } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } } public partial class TargetException : System.ApplicationException @@ -9035,7 +9136,7 @@ public RuntimeWrappedException(object thrownObject) { } public object WrappedException { get { throw null; } } public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } } - [System.AttributeUsageAttribute(System.AttributeTargets.Class | System.AttributeTargets.Constructor | System.AttributeTargets.Event | System.AttributeTargets.Method | System.AttributeTargets.Module | System.AttributeTargets.Property | System.AttributeTargets.Struct, Inherited=false)] + [System.AttributeUsageAttribute(System.AttributeTargets.Class | System.AttributeTargets.Constructor | System.AttributeTargets.Event | System.AttributeTargets.Method | System.AttributeTargets.Module | System.AttributeTargets.Property | System.AttributeTargets.Struct | System.AttributeTargets.Interface, Inherited=false)] public sealed partial class SkipLocalsInitAttribute : System.Attribute { public SkipLocalsInitAttribute() { } @@ -9196,7 +9297,7 @@ internal ExceptionDispatchInfo() { } [System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] public void Throw() => throw null; [System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] - public static void Throw(System.Exception source) => throw null; + public static void Throw(System.Exception source) => throw null; } public partial class FirstChanceExceptionEventArgs : System.EventArgs { @@ -10104,6 +10205,7 @@ protected Encoding(int codePage, System.Text.EncoderFallback? encoderFallback, S public virtual object Clone() { throw null; } public static byte[] Convert(System.Text.Encoding srcEncoding, System.Text.Encoding dstEncoding, byte[] bytes) { throw null; } public static byte[] Convert(System.Text.Encoding srcEncoding, System.Text.Encoding dstEncoding, byte[] bytes, int index, int count) { throw null; } + public static System.IO.Stream CreateTranscodingStream(System.IO.Stream innerStream, System.Text.Encoding innerStreamEncoding, System.Text.Encoding outerStreamEncoding, bool leaveOpen = false) { throw null; } public override bool Equals(object? value) { throw null; } [System.CLSCompliantAttribute(false)] public unsafe virtual int GetByteCount(char* chars, int count) { throw null; } diff --git a/src/libraries/System.Runtime/tests/NlsTests/System.Runtime.Nls.Tests.csproj b/src/libraries/System.Runtime/tests/NlsTests/System.Runtime.Nls.Tests.csproj new file mode 100644 index 00000000000000..25dd476280c8a2 --- /dev/null +++ b/src/libraries/System.Runtime/tests/NlsTests/System.Runtime.Nls.Tests.csproj @@ -0,0 +1,45 @@ + + + true + true + true + $(NetCoreAppCurrent)-Windows_NT + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Runtime/tests/NlsTests/runtimeconfig.template.json b/src/libraries/System.Runtime/tests/NlsTests/runtimeconfig.template.json new file mode 100644 index 00000000000000..f93c6039127bd1 --- /dev/null +++ b/src/libraries/System.Runtime/tests/NlsTests/runtimeconfig.template.json @@ -0,0 +1,5 @@ +{ + "configProperties": { + "System.Globalization.UseNls": true + } +} diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj index bff03ab27acf5b..69f4de93591a8a 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj @@ -7,45 +7,32 @@ $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix - - Common\System\EnumTypes.cs - - - Common\System\MockType.cs - - - Common\System\Collections\CollectionAsserts.cs - - - Common\System\Collections\ICollection.Generic.Tests.cs - - - Common\System\Collections\IEnumerable.Generic.Tests.cs - - - Common\System\Collections\IList.Generic.Tests.cs - - - Common\System\Collections\TestBase.Generic.cs - - - Common\System\Collections\TestBase.NonGeneric.cs - - - System\StringTests.cs - - - Common\System\Collections\IDictionary.NonGeneric.Tests.cs - - - Common\System\Collections\IList.NonGeneric.Tests.cs - - - Common\System\Collections\ICollection.NonGeneric.Tests.cs - - - Common\System\Collections\IEnumerable.NonGeneric.Tests.cs - + + + + + + + + + + + + + @@ -76,13 +63,14 @@ + - + @@ -167,6 +155,9 @@ + + + @@ -235,9 +226,8 @@ - - Common\System\RandomDataGenerator.cs - + @@ -256,24 +246,24 @@ - + - + - - Common\System\Collections\IEnumerable.Generic.Serialization.Tests.cs - + System.Reflection.Tests.EmbeddedImage.png System.Reflection.Tests.EmbeddedTextFile.txt - - Common\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs - + diff --git a/src/libraries/System.Runtime/tests/System/ArgIteratorTests.cs b/src/libraries/System.Runtime/tests/System/ArgIteratorTests.cs index 1ad30e5c861750..5508c1330ccc51 100644 --- a/src/libraries/System.Runtime/tests/System/ArgIteratorTests.cs +++ b/src/libraries/System.Runtime/tests/System/ArgIteratorTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.DotNet.XUnitExtensions; using System.Globalization; using System.Reflection; using Xunit; @@ -90,6 +91,12 @@ private static void VerifyTypes(Type[] types, __arglist) [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsArgIteratorNotSupported))] public static unsafe void ArgIterator_Throws_PlatformNotSupportedException() { + if (PlatformDetection.IsWindows && PlatformDetection.IsArmProcess) + { + // Active Issue: https://github.com/dotnet/runtime/issues/35754 + throw new SkipTestException("ArgIterator doesn't throw not supported in ArmProcess"); + } + Assert.Throws(() => new ArgIterator(new RuntimeArgumentHandle())); Assert.Throws(() => { fixed (void* p = "test") diff --git a/src/libraries/System.Runtime/tests/System/ArgumentExceptionTests.cs b/src/libraries/System.Runtime/tests/System/ArgumentExceptionTests.cs index c0832946be83e2..d93235c1299299 100644 --- a/src/libraries/System.Runtime/tests/System/ArgumentExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/ArgumentExceptionTests.cs @@ -14,7 +14,7 @@ public static class ArgumentExceptionTests public static void Ctor_Empty() { var exception = new ArgumentException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENT, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENT, validateMessage: false); Assert.Null(exception.ParamName); } @@ -23,7 +23,7 @@ public static void Ctor_String() { string message = "the argument is wrong"; var exception = new ArgumentException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENT, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENT, message: message); Assert.Null(exception.ParamName); } @@ -33,7 +33,7 @@ public static void Ctor_String_Exception() string message = "the argument is wrong"; var innerException = new Exception("Inner exception"); var exception = new ArgumentException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENT, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENT, innerException: innerException, message: message); Assert.Null(exception.ParamName); } @@ -43,7 +43,7 @@ public static void Ctor_String_String() string message = "the argument is wrong"; string argumentName = "theArgument"; var exception = new ArgumentException(message, argumentName); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENT, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENT, validateMessage: false); Assert.Equal(argumentName, exception.ParamName); Assert.Contains(message, exception.Message); Assert.Contains(argumentName, exception.Message); @@ -56,7 +56,7 @@ public static void Ctor_String_String_Exception() string argumentName = "theArgument"; var innerException = new Exception("Inner exception"); var exception = new ArgumentException(message, argumentName, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENT, innerException: innerException, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENT, innerException: innerException, validateMessage: false); Assert.Equal(argumentName, exception.ParamName); Assert.Contains(message, exception.Message); Assert.Contains(argumentName, exception.Message); diff --git a/src/libraries/System.Runtime/tests/System/ArgumentNullExceptionTests.cs b/src/libraries/System.Runtime/tests/System/ArgumentNullExceptionTests.cs index f872b36d441dc3..91520e0a93669f 100644 --- a/src/libraries/System.Runtime/tests/System/ArgumentNullExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/ArgumentNullExceptionTests.cs @@ -14,7 +14,7 @@ public static class ArgumentNullExceptionTests public static void Ctor_Empty() { var exception = new ArgumentNullException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: E_POINTER, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: E_POINTER, validateMessage: false); Assert.Null(exception.ParamName); } @@ -23,7 +23,7 @@ public static void Ctor_String() { string argumentName = "theNullArgument"; var exception = new ArgumentNullException(argumentName); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: E_POINTER, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: E_POINTER, validateMessage: false); Assert.Contains(argumentName, exception.Message); } @@ -33,7 +33,7 @@ public static void Ctor_String_Exception() string message = "the argument is null"; var innerException = new Exception("Inner exception"); var exception = new ArgumentNullException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: E_POINTER, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: E_POINTER, innerException: innerException, message: message); Assert.Null(exception.ParamName); } @@ -43,7 +43,7 @@ public static void Ctor_String_String() string message = "the argument is null"; string argumentName = "theNullArgument"; var exception = new ArgumentNullException(argumentName, message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: E_POINTER, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: E_POINTER, validateMessage: false); Assert.Equal(argumentName, exception.ParamName); Assert.Contains(message, exception.Message); Assert.Contains(argumentName, exception.Message); diff --git a/src/libraries/System.Runtime/tests/System/ArgumentOutOfRangeExceptionTests.cs b/src/libraries/System.Runtime/tests/System/ArgumentOutOfRangeExceptionTests.cs index d3785552eb3908..ba14619ae82f12 100644 --- a/src/libraries/System.Runtime/tests/System/ArgumentOutOfRangeExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/ArgumentOutOfRangeExceptionTests.cs @@ -14,7 +14,7 @@ public static class ArgumentOutOfRangeExceptionTests public static void Ctor_Empty() { var exception = new ArgumentOutOfRangeException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENTOUTOFRANGE, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENTOUTOFRANGE, validateMessage: false); Assert.Null(exception.ParamName); Assert.Null(exception.ActualValue); } @@ -24,7 +24,7 @@ public static void Ctor_String() { string argumentName = "theArgument"; var exception = new ArgumentOutOfRangeException(argumentName); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENTOUTOFRANGE, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENTOUTOFRANGE, validateMessage: false); Assert.Equal(argumentName, exception.ParamName); Assert.Null(exception.ActualValue); } @@ -35,7 +35,7 @@ public static void Ctor_String_Exception() string message = "the argument is out of range"; var innerException = new Exception("Inner exception"); var exception = new ArgumentOutOfRangeException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENTOUTOFRANGE, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENTOUTOFRANGE, innerException: innerException, message: message); Assert.Null(exception.ParamName); Assert.Null(exception.ActualValue); } @@ -46,7 +46,7 @@ public static void Ctor_String_String() string message = "the argument is out of range"; string argumentName = "theArgument"; var exception = new ArgumentOutOfRangeException(argumentName, message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENTOUTOFRANGE, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENTOUTOFRANGE, validateMessage: false); Assert.Equal(argumentName, exception.ParamName); Assert.Null(exception.ActualValue); Assert.Contains(message, exception.Message); @@ -60,7 +60,7 @@ public static void Ctor_String_Object_String() string argumentName = "theArgument"; int argumentValue = Int32.MaxValue; var exception = new ArgumentOutOfRangeException(argumentName, argumentValue, message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENTOUTOFRANGE, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARGUMENTOUTOFRANGE, validateMessage: false); Assert.Equal(argumentName, exception.ParamName); Assert.Contains(message, exception.Message); Assert.Contains(argumentName, exception.Message); diff --git a/src/libraries/System.Runtime/tests/System/ArithmeticExceptionTests.cs b/src/libraries/System.Runtime/tests/System/ArithmeticExceptionTests.cs index bd1ede2f2656e5..7a8eb22dc97bb7 100644 --- a/src/libraries/System.Runtime/tests/System/ArithmeticExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/ArithmeticExceptionTests.cs @@ -14,7 +14,7 @@ public static class ArithmeticExceptionTests public static void Ctor_Empty() { var exception = new ArithmeticException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARITHMETIC, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARITHMETIC, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "arithmetic operation error"; var exception = new ArithmeticException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARITHMETIC, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARITHMETIC, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "arithmetic operation error"; var innerException = new Exception("Inner exception"); var exception = new ArithmeticException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARITHMETIC, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARITHMETIC, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/ArrayTests.cs b/src/libraries/System.Runtime/tests/System/ArrayTests.cs index b3e350af78a4b6..d18f0e5a2a9894 100644 --- a/src/libraries/System.Runtime/tests/System/ArrayTests.cs +++ b/src/libraries/System.Runtime/tests/System/ArrayTests.cs @@ -264,6 +264,39 @@ public static IEnumerable BinarySearch_SZArray_TestData() yield return new object[] { new ulong[0], 0, 0, (ulong)0, null, -1 }; + // // [ActiveIssue("https://github.com/xunit/xunit/issues/1771")] + // // IntPtr + + // IntPtr[] intPtrArray = new IntPtr[] { IntPtr.MinValue, (IntPtr)0, (IntPtr)0, IntPtr.MaxValue }; + + // yield return new object[] { intPtrArray, 0, 4, IntPtr.MinValue, null, 0 }; + // yield return new object[] { intPtrArray, 0, 4, (IntPtr)0, null, 1 }; + // yield return new object[] { intPtrArray, 0, 4, IntPtr.MaxValue, null, 3 }; + // yield return new object[] { intPtrArray, 0, 4, (IntPtr)1, null, -4 }; + + // yield return new object[] { intPtrArray, 0, 1, IntPtr.MinValue, null, 0 }; + // yield return new object[] { intPtrArray, 1, 3, IntPtr.MaxValue, null, 3 }; + // yield return new object[] { intPtrArray, 1, 3, IntPtr.MinValue, null, -2 }; + // yield return new object[] { intPtrArray, 1, 0, (IntPtr)0, null, -2 }; + + // yield return new object[] { new IntPtr[0], 0, 0, (IntPtr)0, null, -1 }; + + // // UIntPtr + + // UIntPtr[] uintPtrArray = new UIntPtr[] { UIntPtr.MinValue, (UIntPtr)5, (UIntPtr)5, UIntPtr.MaxValue }; + + // yield return new object[] { uintPtrArray, 0, 4, UIntPtr.MinValue, null, 0 }; + // yield return new object[] { uintPtrArray, 0, 4, (UIntPtr)5, null, 1 }; + // yield return new object[] { uintPtrArray, 0, 4, UIntPtr.MaxValue, null, 3 }; + // yield return new object[] { uintPtrArray, 0, 4, (UIntPtr)1, null, -2 }; + + // yield return new object[] { uintPtrArray, 0, 1, UIntPtr.MinValue, null, 0 }; + // yield return new object[] { uintPtrArray, 1, 3, UIntPtr.MaxValue, null, 3 }; + // yield return new object[] { uintPtrArray, 1, 3, UIntPtr.MinValue, null, -2 }; + // yield return new object[] { uintPtrArray, 1, 0, (UIntPtr)5, null, -2 }; + + // yield return new object[] { new UIntPtr[0], 0, 0, (UIntPtr)0, null, -1 }; + // Char char[] charArray = new char[] { char.MinValue, (char)5, (char)5, char.MaxValue }; @@ -440,10 +473,6 @@ public static IEnumerable BinarySearch_TypesNotComparable_TestData() // Type does not implement IComparable yield return new object[] { new object[] { new object() }, new object() }; - // IntPtr and UIntPtr are not supported - yield return new object[] { new IntPtr[] { IntPtr.Zero }, IntPtr.Zero }; - yield return new object[] { new UIntPtr[] { UIntPtr.Zero }, UIntPtr.Zero }; - // Conversion between primitives is not allowed yield return new object[] { new sbyte[] { 0 }, 0 }; yield return new object[] { new char[] { '\0' }, (ushort)0 }; @@ -3326,6 +3355,24 @@ public static IEnumerable Sort_SZArray_TestData() yield return new object[] { new ulong[1], 0, 1, null, new ulong[1] }; yield return new object[] { new ulong[0], 0, 0, null, new ulong[0] }; + // IntPtr + yield return new object[] { new IntPtr[] { (IntPtr)3, (IntPtr)5, (IntPtr)6, (IntPtr)6 }, 0, 4, null, new IntPtr[] { (IntPtr)3, (IntPtr)5, (IntPtr)6, (IntPtr)6 } }; + yield return new object[] { new IntPtr[] { (IntPtr)5, (IntPtr)6, (IntPtr)3, (IntPtr)6 }, 0, 4, null, new IntPtr[] { (IntPtr)3, (IntPtr)5, (IntPtr)6, (IntPtr)6 } }; + yield return new object[] { new IntPtr[] { (IntPtr)5, (IntPtr)6, (IntPtr)3, (IntPtr)6 }, 0, 4, null, new IntPtr[] { (IntPtr)3, (IntPtr)5, (IntPtr)6, (IntPtr)6 } }; + yield return new object[] { new IntPtr[] { (IntPtr)5, (IntPtr)6, (IntPtr)3, (IntPtr)6 }, 1, 2, null, new IntPtr[] { (IntPtr)5, (IntPtr)3, (IntPtr)6, (IntPtr)6 } }; + yield return new object[] { new IntPtr[] { (IntPtr)5, (IntPtr)6, (IntPtr)3, (IntPtr)6 }, 0, 0, null, new IntPtr[] { (IntPtr)5, (IntPtr)6, (IntPtr)3, (IntPtr)6 } }; + yield return new object[] { new IntPtr[1], 0, 1, null, new IntPtr[1] }; + yield return new object[] { new IntPtr[0], 0, 0, null, new IntPtr[0] }; + + // UIntPtr + yield return new object[] { new UIntPtr[] { (UIntPtr)3, (UIntPtr)5, (UIntPtr)6, (UIntPtr)6 }, 0, 4, null, new UIntPtr[] { (UIntPtr)3, (UIntPtr)5, (UIntPtr)6, (UIntPtr)6 } }; + yield return new object[] { new UIntPtr[] { (UIntPtr)5, (UIntPtr)6, (UIntPtr)3, (UIntPtr)6 }, 0, 4, null, new UIntPtr[] { (UIntPtr)3, (UIntPtr)5, (UIntPtr)6, (UIntPtr)6 } }; + yield return new object[] { new UIntPtr[] { (UIntPtr)5, (UIntPtr)6, (UIntPtr)3, (UIntPtr)6 }, 0, 4, null, new UIntPtr[] { (UIntPtr)3, (UIntPtr)5, (UIntPtr)6, (UIntPtr)6 } }; + yield return new object[] { new UIntPtr[] { (UIntPtr)5, (UIntPtr)6, (UIntPtr)3, (UIntPtr)6 }, 1, 2, null, new UIntPtr[] { (UIntPtr)5, (UIntPtr)3, (UIntPtr)6, (UIntPtr)6 } }; + yield return new object[] { new UIntPtr[] { (UIntPtr)5, (UIntPtr)6, (UIntPtr)3, (UIntPtr)6 }, 0, 0, null, new UIntPtr[] { (UIntPtr)5, (UIntPtr)6, (UIntPtr)3, (UIntPtr)6 } }; + yield return new object[] { new UIntPtr[1], 0, 1, null, new UIntPtr[1] }; + yield return new object[] { new UIntPtr[0], 0, 0, null, new UIntPtr[0] }; + // Int64 yield return new object[] { new long[] { 3, 5, 6, 6 }, 0, 4, null, new long[] { 3, 5, 6, 6 } }; yield return new object[] { new long[] { 5, 6, 3, 6 }, 0, 4, null, new long[] { 3, 5, 6, 6 } }; @@ -3493,8 +3540,6 @@ public void Sort_MultidimensionalArray_ThrowsRankException() public static IEnumerable Sort_NotComparable_TestData() { yield return new object[] { new object[] { "1", 2, new object() } }; - yield return new object[] { new IntPtr[2] }; - yield return new object[] { new UIntPtr[2] }; } [Theory] diff --git a/src/libraries/System.Runtime/tests/System/ArrayTypeMismatchExceptionTests.cs b/src/libraries/System.Runtime/tests/System/ArrayTypeMismatchExceptionTests.cs index d017250e387118..d59b91470d3ade 100644 --- a/src/libraries/System.Runtime/tests/System/ArrayTypeMismatchExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/ArrayTypeMismatchExceptionTests.cs @@ -14,7 +14,7 @@ public static class ArrayTypeMismatchExceptionTests public static void Ctor_Empty() { var exception = new ArrayTypeMismatchException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARRAYTYPEMISMATCH, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARRAYTYPEMISMATCH, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "array type mismatch"; var exception = new ArrayTypeMismatchException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARRAYTYPEMISMATCH, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARRAYTYPEMISMATCH, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "array type mismatch"; var innerException = new Exception("Inner exception"); var exception = new ArrayTypeMismatchException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_ARRAYTYPEMISMATCH, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_ARRAYTYPEMISMATCH, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/Attributes.cs b/src/libraries/System.Runtime/tests/System/Attributes.cs index d56a39850df296..f30464ca65ae62 100644 --- a/src/libraries/System.Runtime/tests/System/Attributes.cs +++ b/src/libraries/System.Runtime/tests/System/Attributes.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. // -// AttributeTest.cs - NUnit Test Cases for the System.Attribute class +// AttributeTest.cs - Unit Test Cases for the System.Attribute class // // Authors: // Duco Fijma (duco@lorentz.xs4all.nl) @@ -81,6 +81,12 @@ public void IsDefined_PropertyInfo_Override() Assert.False(Attribute.IsDefined(pi, typeof(ComVisibleAttribute), false)); Assert.False(Attribute.IsDefined(pi, typeof(ComVisibleAttribute), true)); } + + [Fact] + public void IsDefined_Interface() + { + Assert.True(typeof(ExampleWithAttribute).IsDefined(typeof(INameable), false)); + } } public static class AttributeGetCustomAttributes @@ -206,6 +212,12 @@ public static void MultipleAttributesTest() Assert.Equal("System.Tests.MyCustomAttribute System.Tests.MyCustomAttribute", string.Join(" ", typeof(MultipleAttributes).GetCustomAttributes(inherit: false))); Assert.Equal("System.Tests.MyCustomAttribute System.Tests.MyCustomAttribute", string.Join(" ", typeof(MultipleAttributes).GetCustomAttributes(inherit: true))); } + + [Fact] + public static void GetCustomAttributes_Interface() + { + Assert.True(typeof(ExampleWithAttribute).GetCustomAttributes(typeof(INameable), inherit: false)[0] is NameableAttribute); + } } public static class GetCustomAttribute @@ -798,4 +810,18 @@ public override string PropBase3 class MultipleAttributes { } + + public interface INameable + { + string Name { get; } + } + + [AttributeUsage (AttributeTargets.All, AllowMultiple = true)] + public class NameableAttribute : Attribute, INameable + { + string INameable.Name => "Nameable"; + } + + [Nameable] + public class ExampleWithAttribute { } } diff --git a/src/libraries/System.Runtime/tests/System/BadImageFormatExceptionTests.cs b/src/libraries/System.Runtime/tests/System/BadImageFormatExceptionTests.cs index 497f515f6e1cb9..70be2d06778994 100644 --- a/src/libraries/System.Runtime/tests/System/BadImageFormatExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/BadImageFormatExceptionTests.cs @@ -14,7 +14,7 @@ public static class BadImageFormatExceptionTests public static void Ctor_Empty() { var exception = new BadImageFormatException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_BADIMAGEFORMAT, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_BADIMAGEFORMAT, validateMessage: false); Assert.Null(exception.FileName); } @@ -23,7 +23,7 @@ public static void Ctor_String() { string message = "this is not the file you're looking for"; var exception = new BadImageFormatException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_BADIMAGEFORMAT, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_BADIMAGEFORMAT, message: message); Assert.Null(exception.FileName); } @@ -33,7 +33,7 @@ public static void Ctor_String_Exception() string message = "this is not the file you're looking for"; var innerException = new Exception("Inner exception"); var exception = new BadImageFormatException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_BADIMAGEFORMAT, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_BADIMAGEFORMAT, innerException: innerException, message: message); Assert.Null(exception.FileName); } @@ -43,7 +43,7 @@ public static void Ctor_String_String() string message = "this is not the file you're looking for"; string fileName = "file.txt"; var exception = new BadImageFormatException(message, fileName); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_BADIMAGEFORMAT, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_BADIMAGEFORMAT, message: message); Assert.Equal(fileName, exception.FileName); } @@ -54,7 +54,7 @@ public static void Ctor_String_String_Exception() string fileName = "file.txt"; var innerException = new Exception("Inner exception"); var exception = new BadImageFormatException(message, fileName, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_BADIMAGEFORMAT, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_BADIMAGEFORMAT, innerException: innerException, message: message); Assert.Equal(fileName, exception.FileName); } diff --git a/src/libraries/System.Runtime/tests/System/Collections/Generic/KeyNotFoundExceptionTests.cs b/src/libraries/System.Runtime/tests/System/Collections/Generic/KeyNotFoundExceptionTests.cs index c3cf6a6c4e491b..e3013ab165a33b 100644 --- a/src/libraries/System.Runtime/tests/System/Collections/Generic/KeyNotFoundExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/Collections/Generic/KeyNotFoundExceptionTests.cs @@ -16,7 +16,7 @@ public static class KeyNotFoundExceptionTests public static void Ctor_Empty() { var exception = new KeyNotFoundException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_KEYNOTFOUND, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_KEYNOTFOUND, validateMessage: false); } [Fact] @@ -24,7 +24,7 @@ public static void Ctor_String() { string message = "this is not the key you're looking for"; var exception = new KeyNotFoundException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_KEYNOTFOUND, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_KEYNOTFOUND, message: message); } [Fact] @@ -33,7 +33,7 @@ public static void Ctor_String_Exception() string message = "this is not the key you're looking for"; var innerException = new Exception("Inner exception"); var exception = new KeyNotFoundException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_KEYNOTFOUND, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_KEYNOTFOUND, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.cs b/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.cs index d62cb75547c155..0d146b4cd2c6ff 100644 --- a/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.cs +++ b/src/libraries/System.Runtime/tests/System/DateTimeOffsetTests.cs @@ -357,8 +357,8 @@ public static void AddYears(DateTimeOffset dateTimeOffset, int years, DateTimeOf [Fact] public static void AddYears_NewDateOutOfRange_ThrowsArgumentOutOfRangeException() { - AssertExtensions.Throws("years", () => DateTimeOffset.Now.AddYears(10001)); - AssertExtensions.Throws("years", () => DateTimeOffset.Now.AddYears(-10001)); + AssertExtensions.Throws("value", () => DateTimeOffset.Now.AddYears(10001)); + AssertExtensions.Throws("value", () => DateTimeOffset.Now.AddYears(-10001)); AssertExtensions.Throws("months", () => DateTimeOffset.MaxValue.AddYears(1)); AssertExtensions.Throws("months", () => DateTimeOffset.MinValue.AddYears(-1)); diff --git a/src/libraries/System.Runtime/tests/System/DateTimeTests.cs b/src/libraries/System.Runtime/tests/System/DateTimeTests.cs index 654a103cc9af0c..c1d68a264deec2 100644 --- a/src/libraries/System.Runtime/tests/System/DateTimeTests.cs +++ b/src/libraries/System.Runtime/tests/System/DateTimeTests.cs @@ -383,8 +383,8 @@ public void AddYears_Invoke_ReturnsExpected(DateTime dateTime, int years, DateTi public static IEnumerable AddYears_OutOfRange_TestData() { - yield return new object[] { DateTime.Now, 10001, "years" }; - yield return new object[] { DateTime.Now, -10001, "years" }; + yield return new object[] { DateTime.Now, 10001, "value" }; + yield return new object[] { DateTime.Now, -10001, "value" }; yield return new object[] { DateTime.MaxValue, 1, "months" }; yield return new object[] { DateTime.MinValue, -1, "months" }; } diff --git a/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/DynamicDependencyAttributeTests.cs b/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/DynamicDependencyAttributeTests.cs new file mode 100644 index 00000000000000..337af64fdd3420 --- /dev/null +++ b/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/DynamicDependencyAttributeTests.cs @@ -0,0 +1,104 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.Diagnostics.CodeAnalysis.Tests +{ + public class DynamicDependencyAttributeTests + { + [Theory] + [InlineData("Foo()")] + [InlineData(null)] + [InlineData("")] + public void TestConstructorSignature(string memberSignature) + { + var dda = new DynamicDependencyAttribute(memberSignature); + + Assert.Equal(memberSignature, dda.MemberSignature); + Assert.Equal(DynamicallyAccessedMemberTypes.None, dda.MemberTypes); + Assert.Null(dda.Type); + Assert.Null(dda.TypeName); + Assert.Null(dda.AssemblyName); + Assert.Null(dda.Condition); + } + + [Theory] + [InlineData("Foo()", typeof(string))] + [InlineData(null, null)] + [InlineData("", typeof(void))] + public void TestConstructorSignatureType(string memberSignature, Type type) + { + var dda = new DynamicDependencyAttribute(memberSignature, type); + + Assert.Equal(memberSignature, dda.MemberSignature); + Assert.Equal(DynamicallyAccessedMemberTypes.None, dda.MemberTypes); + Assert.Equal(type, dda.Type); + Assert.Null(dda.TypeName); + Assert.Null(dda.AssemblyName); + Assert.Null(dda.Condition); + } + + [Theory] + [InlineData("Foo()", "System.String", "System.Runtime")] + [InlineData(null, null, null)] + [InlineData("", "", "")] + public void TestConstructorSignatureTypeNameAssemblyName(string memberSignature, string typeName, string assemblyName) + { + var dda = new DynamicDependencyAttribute(memberSignature, typeName, assemblyName); + + Assert.Equal(memberSignature, dda.MemberSignature); + Assert.Equal(DynamicallyAccessedMemberTypes.None, dda.MemberTypes); + Assert.Null(dda.Type); + Assert.Equal(typeName, dda.TypeName); + Assert.Equal(assemblyName, dda.AssemblyName); + Assert.Null(dda.Condition); + } + + [Theory] + [InlineData(DynamicallyAccessedMemberTypes.PublicMethods, typeof(string))] + [InlineData(DynamicallyAccessedMemberTypes.None, null)] + [InlineData(DynamicallyAccessedMemberTypes.All, typeof(void))] + public void TestConstructorMemberTypes(DynamicallyAccessedMemberTypes memberTypes, Type type) + { + var dda = new DynamicDependencyAttribute(memberTypes, type); + + Assert.Null(dda.MemberSignature); + Assert.Equal(memberTypes, dda.MemberTypes); + Assert.Equal(type, dda.Type); + Assert.Null(dda.TypeName); + Assert.Null(dda.AssemblyName); + Assert.Null(dda.Condition); + } + + [Theory] + [InlineData(DynamicallyAccessedMemberTypes.PublicMethods, "System.String", "System.Runtime")] + [InlineData(DynamicallyAccessedMemberTypes.None, null, null)] + [InlineData(DynamicallyAccessedMemberTypes.All, "", "")] + public void TestConstructorMemberTypesTypeNameAssemblyName(DynamicallyAccessedMemberTypes memberTypes, string typeName, string assemblyName) + { + var dda = new DynamicDependencyAttribute(memberTypes, typeName, assemblyName); + + Assert.Null(dda.MemberSignature); + Assert.Equal(memberTypes, dda.MemberTypes); + Assert.Null(dda.Type); + Assert.Equal(typeName, dda.TypeName); + Assert.Equal(assemblyName, dda.AssemblyName); + Assert.Null(dda.Condition); + } + + [Fact] + public void TestCondition() + { + var dda = new DynamicDependencyAttribute("Foo()"); + Assert.Null(dda.Condition); + + dda.Condition = "DEBUG"; + Assert.Equal("DEBUG", dda.Condition); + + dda.Condition = null; + Assert.Null(dda.Condition); + } + } +} diff --git a/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/DynamicallyAccessedMembersAttributeTests.cs b/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/DynamicallyAccessedMembersAttributeTests.cs new file mode 100644 index 00000000000000..ccb5b097dc8dee --- /dev/null +++ b/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/DynamicallyAccessedMembersAttributeTests.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.Diagnostics.CodeAnalysis.Tests +{ + public class DynamicallyAccessedMembersAttributeTests + { + [Theory] + [InlineData(DynamicallyAccessedMemberTypes.None)] + [InlineData(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties)] + [InlineData(DynamicallyAccessedMemberTypes.All)] + public void TestConstructor(DynamicallyAccessedMemberTypes memberTypes) + { + var dama = new DynamicallyAccessedMembersAttribute(memberTypes); + + Assert.Equal(memberTypes, dama.MemberTypes); + } + } +} diff --git a/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/RequiresUnreferencedCodeAttributeTests.cs b/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/RequiresUnreferencedCodeAttributeTests.cs new file mode 100644 index 00000000000000..044fc78deec0b0 --- /dev/null +++ b/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/RequiresUnreferencedCodeAttributeTests.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.Diagnostics.CodeAnalysis.Tests +{ + public class RequiresUnreferencedCodeAttributeTests + { + [Fact] + public void TestConstructor() + { + var attr = new RequiresUnreferencedCodeAttribute("User Message"); + + Assert.Equal("User Message", attr.Message); + Assert.Null(attr.Url); + } + + [Theory] + [InlineData("https://dot.net")] + [InlineData("")] + [InlineData(null)] + public void TestSetUrl(string url) + { + var attr = new RequiresUnreferencedCodeAttribute("User Message") + { + Url = url + }; + + Assert.Equal("User Message", attr.Message); + Assert.Equal(url, attr.Url); + } + } +} diff --git a/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttributeTests.cs b/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttributeTests.cs new file mode 100644 index 00000000000000..542d053c33f112 --- /dev/null +++ b/src/libraries/System.Runtime/tests/System/Diagnostics/CodeAnalysis/UnconditionalSuppressMessageAttributeTests.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.Diagnostics.CodeAnalysis.Tests +{ + public class UnconditionalSuppressMessageAttributeTests + { + [Theory] + [InlineData("Category", "CheckId", "Justification", "MessageId", "Scope", "Target")] + [InlineData("", "", "", "", "", "")] + [InlineData(null, null, null, null, null, null)] + [InlineData("", null, "Justification", null, "Scope", "")] + public void TestConstructor(string category, string id, string justification, string messageId, string scope, string target) + { + var usma = new UnconditionalSuppressMessageAttribute(category, id) + { + Justification = justification, + MessageId = messageId, + Scope = scope, + Target = target + }; + + Assert.Equal(category, usma.Category); + Assert.Equal(id, usma.CheckId); + Assert.Equal(justification, usma.Justification); + Assert.Equal(messageId, usma.MessageId); + Assert.Equal(scope, usma.Scope); + Assert.Equal(target, usma.Target); + } + } +} diff --git a/src/libraries/System.Runtime/tests/System/DivideByZeroExceptionTests.cs b/src/libraries/System.Runtime/tests/System/DivideByZeroExceptionTests.cs index 0e86ae49b4b86a..a9117b70833387 100644 --- a/src/libraries/System.Runtime/tests/System/DivideByZeroExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/DivideByZeroExceptionTests.cs @@ -14,7 +14,7 @@ public static class DivideByZeroExceptionTests public static void Ctor_Empty() { var exception = new DivideByZeroException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_DIVIDEBYZERO, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_DIVIDEBYZERO, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "divide by zero"; var exception = new DivideByZeroException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_DIVIDEBYZERO, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_DIVIDEBYZERO, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "divide by zero"; var innerException = new Exception("Inner exception"); var exception = new DivideByZeroException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_DIVIDEBYZERO, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_DIVIDEBYZERO, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/Exception.Helpers.cs b/src/libraries/System.Runtime/tests/System/Exception.Helpers.cs new file mode 100644 index 00000000000000..a39cd049988284 --- /dev/null +++ b/src/libraries/System.Runtime/tests/System/Exception.Helpers.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. +// See the LICENSE file in the project root for more information. + +using System; +using Xunit; + +namespace System.Tests +{ + public static class ExceptionHelpers + { + public static void ValidateExceptionProperties(Exception e, + int hResult, + int dataCount = 0, + string helpLink = null, + Exception innerException = null, + string message = null, + string source = null, + string stackTrace = null, + bool validateMessage = true) + { + Assert.Equal(dataCount, e.Data.Count); + Assert.Equal(helpLink, e.HelpLink); + Assert.Equal(hResult, e.HResult); + Assert.Equal(innerException, e.InnerException); + if (validateMessage) + { + Assert.Equal(message, e.Message); + } + else + { + Assert.NotNull(e.Message); + } + Assert.Equal(source, e.Source); + Assert.Equal(stackTrace, e.StackTrace); + } + } +} diff --git a/src/libraries/System.Runtime/tests/System/ExceptionTests.cs b/src/libraries/System.Runtime/tests/System/ExceptionTests.cs index 6d663486205a3d..4704368e6b9a51 100644 --- a/src/libraries/System.Runtime/tests/System/ExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/ExceptionTests.cs @@ -21,7 +21,7 @@ public static class ExceptionTests public static void Ctor_Empty() { var exception = new Exception(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_EXCEPTION, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_EXCEPTION, validateMessage: false); } [Fact] @@ -29,7 +29,7 @@ public static void Ctor_String() { string message = "something went wrong"; var exception = new Exception(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_EXCEPTION, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_EXCEPTION, message: message); } [Fact] @@ -38,7 +38,7 @@ public static void Ctor_String_Exception() string message = "something went wrong"; var innerException = new Exception("Inner exception"); var exception = new Exception(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_EXCEPTION, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_EXCEPTION, innerException: innerException, message: message); } [Fact] diff --git a/src/libraries/System.Runtime/tests/System/Exceptions.Utility.cs b/src/libraries/System.Runtime/tests/System/Exceptions.Utility.cs deleted file mode 100644 index d7d0967c94dcae..00000000000000 --- a/src/libraries/System.Runtime/tests/System/Exceptions.Utility.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using Xunit; - -namespace System.Tests -{ - public static class ExceptionUtility - { - public static void ValidateExceptionProperties(Exception e, - int hResult, - int dataCount = 0, - string helpLink = null, - Exception innerException = null, - string message = null, - string source = null, - string stackTrace = null, - bool validateMessage = true) - { - Assert.Equal(dataCount, e.Data.Count); - Assert.Equal(helpLink, e.HelpLink); - Assert.Equal(hResult, e.HResult); - Assert.Equal(innerException, e.InnerException); - if (validateMessage) - { - Assert.Equal(message, e.Message); - } - else - { - Assert.NotNull(e.Message); - } - Assert.Equal(source, e.Source); - Assert.Equal(stackTrace, e.StackTrace); - } - } -} diff --git a/src/libraries/System.Runtime/tests/System/FormatExceptionTests.cs b/src/libraries/System.Runtime/tests/System/FormatExceptionTests.cs index 79924d6b53b5b5..a5f78ae97a36e2 100644 --- a/src/libraries/System.Runtime/tests/System/FormatExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/FormatExceptionTests.cs @@ -14,7 +14,7 @@ public static class FormatExceptionTests public static void Ctor_Empty() { var exception = new FormatException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_FORMAT, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_FORMAT, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "bad format"; var exception = new FormatException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_FORMAT, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_FORMAT, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "bad format"; var innerException = new Exception("Inner exception"); var exception = new FormatException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_FORMAT, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_FORMAT, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/GCTests.cs b/src/libraries/System.Runtime/tests/System/GCTests.cs index 097f2dcac805bd..4c8c3091677351 100644 --- a/src/libraries/System.Runtime/tests/System/GCTests.cs +++ b/src/libraries/System.Runtime/tests/System/GCTests.cs @@ -25,7 +25,7 @@ public static void AddMemoryPressure_InvalidBytesAllocated_ThrowsArgumentOutOfRa if (s_is32Bits) { - AssertExtensions.Throws("pressure", () => GC.AddMemoryPressure((long)int.MaxValue + 1)); // Bytes allocated > int.MaxValue on 32 bit platforms + AssertExtensions.Throws("bytesAllocated", () => GC.AddMemoryPressure((long)int.MaxValue + 1)); // Bytes allocated > int.MaxValue on 32 bit platforms } } diff --git a/src/libraries/System.Runtime/tests/System/IO/DirectoryNotFoundException.InteropTests.cs b/src/libraries/System.Runtime/tests/System/IO/DirectoryNotFoundException.InteropTests.cs index 37c4c89c4ba93b..5a1a533ba07023 100644 --- a/src/libraries/System.Runtime/tests/System/IO/DirectoryNotFoundException.InteropTests.cs +++ b/src/libraries/System.Runtime/tests/System/IO/DirectoryNotFoundException.InteropTests.cs @@ -19,7 +19,7 @@ public static void From_HR(int hr) DirectoryNotFoundException exception = Assert.IsAssignableFrom(Marshal.GetExceptionForHR(hr, new IntPtr(-1))); // Don't validate the message. Currently .NET Native does not produce HR-specific messages - ExceptionUtility.ValidateExceptionProperties(exception, hResult: hr, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: hr, validateMessage: false); } } } diff --git a/src/libraries/System.Runtime/tests/System/IO/DirectoryNotFoundExceptionTests.cs b/src/libraries/System.Runtime/tests/System/IO/DirectoryNotFoundExceptionTests.cs index 229acd4b0d2d4c..f510afd9d1ca01 100644 --- a/src/libraries/System.Runtime/tests/System/IO/DirectoryNotFoundExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/IO/DirectoryNotFoundExceptionTests.cs @@ -15,7 +15,7 @@ public static class DirectoryNotFoundExceptionTests public static void Ctor_Empty() { var exception = new DirectoryNotFoundException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_DIRECTORYNOTFOUND, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_DIRECTORYNOTFOUND, validateMessage: false); } [Fact] @@ -23,7 +23,7 @@ public static void Ctor_String() { string message = "That page was missing from the directory."; var exception = new DirectoryNotFoundException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_DIRECTORYNOTFOUND, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_DIRECTORYNOTFOUND, message: message); } [Fact] @@ -32,7 +32,7 @@ public static void Ctor_String_Exception() string message = "That page was missing from the directory."; var innerException = new Exception("Inner exception"); var exception = new DirectoryNotFoundException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_DIRECTORYNOTFOUND, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_DIRECTORYNOTFOUND, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/IO/FileLoadException.InteropTests.cs b/src/libraries/System.Runtime/tests/System/IO/FileLoadException.InteropTests.cs index 6cb7e62e7542dc..4072851e06706e 100644 --- a/src/libraries/System.Runtime/tests/System/IO/FileLoadException.InteropTests.cs +++ b/src/libraries/System.Runtime/tests/System/IO/FileLoadException.InteropTests.cs @@ -44,7 +44,7 @@ public static void Fom_HR(int hr) Assert.NotNull(fileLoadException); // Don't validate the message. Currently .NET Native does not produce HR-specific messages - ExceptionUtility.ValidateExceptionProperties(fileLoadException, hResult: hr, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(fileLoadException, hResult: hr, validateMessage: false); Assert.Null(fileLoadException.FileName); } } diff --git a/src/libraries/System.Runtime/tests/System/IO/FileLoadExceptionTests.cs b/src/libraries/System.Runtime/tests/System/IO/FileLoadExceptionTests.cs index 9d4549742e8a14..b7479e868daddd 100644 --- a/src/libraries/System.Runtime/tests/System/IO/FileLoadExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/IO/FileLoadExceptionTests.cs @@ -13,7 +13,7 @@ public static class FileLoadExceptionTests public static void Ctor_Empty() { var exception = new FileLoadException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILELOAD, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILELOAD, validateMessage: false); Assert.Null(exception.FileName); } @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "this is not the file you're looking for"; var exception = new FileLoadException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILELOAD, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILELOAD, message: message); Assert.Null(exception.FileName); } @@ -32,7 +32,7 @@ public static void Ctor_String_Exception() string message = "this is not the file you're looking for"; var innerException = new Exception("Inner exception"); var exception = new FileLoadException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILELOAD, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILELOAD, innerException: innerException, message: message); Assert.Null(exception.FileName); } @@ -42,7 +42,7 @@ public static void Ctor_String_String() string message = "this is not the file you're looking for"; string fileName = "file.txt"; var exception = new FileLoadException(message, fileName); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILELOAD, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILELOAD, message: message); Assert.Equal(fileName, exception.FileName); } @@ -53,7 +53,7 @@ public static void Ctor_String_String_Exception() string fileName = "file.txt"; var innerException = new Exception("Inner exception"); var exception = new FileLoadException(message, fileName, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILELOAD, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILELOAD, innerException: innerException, message: message); Assert.Equal(fileName, exception.FileName); } diff --git a/src/libraries/System.Runtime/tests/System/IO/FileNotFoundException.InteropTests.cs b/src/libraries/System.Runtime/tests/System/IO/FileNotFoundException.InteropTests.cs index bd6887359f06a1..5ccc505f93a163 100644 --- a/src/libraries/System.Runtime/tests/System/IO/FileNotFoundException.InteropTests.cs +++ b/src/libraries/System.Runtime/tests/System/IO/FileNotFoundException.InteropTests.cs @@ -18,7 +18,7 @@ public static void From_HR(int hr) FileNotFoundException exception = Assert.IsAssignableFrom(Marshal.GetExceptionForHR(hr, new IntPtr(-1))); // Don't validate the message. Currently .NET Native does not produce HR-specific messages - ExceptionUtility.ValidateExceptionProperties(exception, hResult: hr, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: hr, validateMessage: false); } } } diff --git a/src/libraries/System.Runtime/tests/System/IO/FileNotFoundExceptionTests.cs b/src/libraries/System.Runtime/tests/System/IO/FileNotFoundExceptionTests.cs index c9e8ae9368f9c8..73f39702f1655f 100644 --- a/src/libraries/System.Runtime/tests/System/IO/FileNotFoundExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/IO/FileNotFoundExceptionTests.cs @@ -13,7 +13,7 @@ public static class FileNotFoundExceptionTests public static void Ctor_Empty() { var exception = new FileNotFoundException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILENOTFOUND, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILENOTFOUND, validateMessage: false); Assert.Null(exception.FileName); } @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "this is not the file you're looking for"; var exception = new FileNotFoundException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILENOTFOUND, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILENOTFOUND, message: message); Assert.Null(exception.FileName); } @@ -32,7 +32,7 @@ public static void Ctor_String_Exception() string message = "this is not the file you're looking for"; var innerException = new Exception("Inner exception"); var exception = new FileNotFoundException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILENOTFOUND, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILENOTFOUND, innerException: innerException, message: message); Assert.Null(exception.FileName); } @@ -42,7 +42,7 @@ public static void Ctor_String_String() string message = "this is not the file you're looking for"; string fileName = "file.txt"; var exception = new FileNotFoundException(message, fileName); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILENOTFOUND, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILENOTFOUND, message: message); Assert.Equal(fileName, exception.FileName); } @@ -53,7 +53,7 @@ public static void Ctor_String_String_Exception() string fileName = "file.txt"; var innerException = new Exception("Inner exception"); var exception = new FileNotFoundException(message, fileName, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILENOTFOUND, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_FILENOTFOUND, innerException: innerException, message: message); Assert.Equal(fileName, exception.FileName); } diff --git a/src/libraries/System.Runtime/tests/System/IO/IOExceptionTests.cs b/src/libraries/System.Runtime/tests/System/IO/IOExceptionTests.cs index ab5258c2668579..14b769eb1f3601 100644 --- a/src/libraries/System.Runtime/tests/System/IO/IOExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/IO/IOExceptionTests.cs @@ -16,7 +16,7 @@ public static class IOExceptionTests public static void Ctor_Empty() { var exception = new IOException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_IO, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_IO, validateMessage: false); } [Fact] @@ -24,7 +24,7 @@ public static void Ctor_String() { string message = "IO failure"; var exception = new IOException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_IO, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_IO, message: message); } [Fact] @@ -33,7 +33,7 @@ public static void Ctor_String_Exception() string message = "IO failure"; var innerException = new Exception("Inner exception"); var exception = new IOException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_IO, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_IO, innerException: innerException, message: message); } [Fact] @@ -42,7 +42,7 @@ public static void Ctor_String_Int32() string message = "IO failure"; int hResult = unchecked((int)0x80424242); var exception = new IOException(message, hResult); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: hResult, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: hResult, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/IO/PathTooLongException.InteropTests.cs b/src/libraries/System.Runtime/tests/System/IO/PathTooLongException.InteropTests.cs index 1a21cad4a34edd..11c93f5fcf54de 100644 --- a/src/libraries/System.Runtime/tests/System/IO/PathTooLongException.InteropTests.cs +++ b/src/libraries/System.Runtime/tests/System/IO/PathTooLongException.InteropTests.cs @@ -15,7 +15,7 @@ public static void From_HR() { int hr = HResults.COR_E_PATHTOOLONG; PathTooLongException exception = Assert.IsAssignableFrom(Marshal.GetExceptionForHR(hr, new IntPtr(-1))); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: hr, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: hr, validateMessage: false); } } } diff --git a/src/libraries/System.Runtime/tests/System/IO/PathTooLongExceptionTests.cs b/src/libraries/System.Runtime/tests/System/IO/PathTooLongExceptionTests.cs index 8bf3dd2ab5f1f8..5d05b283cbedb5 100644 --- a/src/libraries/System.Runtime/tests/System/IO/PathTooLongExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/IO/PathTooLongExceptionTests.cs @@ -16,7 +16,7 @@ public static class PathTooLongExceptionTests public static void Ctor_Empty() { var exception = new PathTooLongException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_PATHTOOLONG, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_PATHTOOLONG, validateMessage: false); } [Fact] @@ -24,7 +24,7 @@ public static void Ctor_String() { string message = "This path is too long to hike in a single day."; var exception = new PathTooLongException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_PATHTOOLONG, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_PATHTOOLONG, message: message); } [Fact] @@ -33,7 +33,7 @@ public static void Ctor_String_Exception() string message = "This path is too long to hike in a single day."; var innerException = new Exception("Inner exception"); var exception = new PathTooLongException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: HResults.COR_E_PATHTOOLONG, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: HResults.COR_E_PATHTOOLONG, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/IndexOutOfRangeExceptionTests.cs b/src/libraries/System.Runtime/tests/System/IndexOutOfRangeExceptionTests.cs index 69d83851efcdaf..98314f591f5010 100644 --- a/src/libraries/System.Runtime/tests/System/IndexOutOfRangeExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/IndexOutOfRangeExceptionTests.cs @@ -14,7 +14,7 @@ public static class IndexOutOfRangeExceptionTests public static void Ctor_Empty() { var exception = new IndexOutOfRangeException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_INDEXOUTOFRANGE, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_INDEXOUTOFRANGE, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "out of range"; var exception = new IndexOutOfRangeException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_INDEXOUTOFRANGE, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_INDEXOUTOFRANGE, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "out of range"; var innerException = new Exception("Inner exception"); var exception = new IndexOutOfRangeException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_INDEXOUTOFRANGE, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_INDEXOUTOFRANGE, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/IntPtrTests.cs b/src/libraries/System.Runtime/tests/System/IntPtrTests.cs index 90bdf0c8e89d54..2744e8dd886a75 100644 --- a/src/libraries/System.Runtime/tests/System/IntPtrTests.cs +++ b/src/libraries/System.Runtime/tests/System/IntPtrTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using Xunit; namespace System.Tests @@ -177,5 +178,718 @@ private static void VerifyPointer(IntPtr ptr, long expected) Assert.False(ptr == new IntPtr(expected + 1)); Assert.True(ptr != new IntPtr(expected + 1)); } + + + public static IntPtr RealMax => Is64Bit ? (IntPtr)long.MaxValue : (IntPtr)int.MaxValue; + public static IntPtr RealMin => Is64Bit ? (IntPtr)long.MinValue : (IntPtr)int.MinValue; + + [Fact] + public static void Ctor_Empty() + { + var i = new IntPtr(); + Assert.Equal(default, i); + } + + [Fact] + public static void Ctor_Value() + { + IntPtr i = (IntPtr)41; + Assert.Equal((IntPtr)041, i); + } + + [Fact] + public static void MaxValue() + { + Assert.Equal(RealMax, IntPtr.MaxValue); + } + + [Fact] + public static void MinValue() + { + Assert.Equal(RealMin, IntPtr.MinValue); + } + + [Theory] + [InlineData(234, 234, 0)] + [InlineData(234, int.MinValue, 1)] + [InlineData(-234, int.MinValue, 1)] + [InlineData(int.MinValue, int.MinValue, 0)] + [InlineData(234, -123, 1)] + [InlineData(234, 0, 1)] + [InlineData(234, 123, 1)] + [InlineData(234, 456, -1)] + [InlineData(234, int.MaxValue, -1)] + [InlineData(-234, int.MaxValue, -1)] + [InlineData(int.MaxValue, int.MaxValue, 0)] + [InlineData(-234, -234, 0)] + [InlineData(-234, 234, -1)] + [InlineData(-234, -432, 1)] + [InlineData(234, null, 1)] + public static void CompareTo_Other_ReturnsExpected(int l, object value, int expected) + { + var i = (IntPtr)l; + if (value is int intValue) + { + var intPtrValue = (IntPtr)intValue; + Assert.Equal(expected, Math.Sign(i.CompareTo(intPtrValue))); + Assert.Equal(-expected, Math.Sign(intPtrValue.CompareTo(i))); + + Assert.Equal(expected, Math.Sign(i.CompareTo((object)intPtrValue))); + } + else + { + Assert.Equal(expected, Math.Sign(i.CompareTo(value))); + } + } + + [Theory] + [InlineData("a")] + [InlineData((long)234)] + public static void CompareTo_ObjectNotIntPtr_ThrowsArgumentException(object value) + { + AssertExtensions.Throws(null, () => ((IntPtr)123).CompareTo(value)); + } + + public static IEnumerable ToString_TestData() + { + foreach (NumberFormatInfo defaultFormat in new[] { null, NumberFormatInfo.CurrentInfo }) + { + foreach (string defaultSpecifier in new[] { "G", "G\0", "\0N222", "\0", "" }) + { + yield return new object[] { IntPtr.MinValue, defaultSpecifier, defaultFormat, Is64Bit ? "-9223372036854775808" : "-2147483648" }; + yield return new object[] { (IntPtr)(-4567), defaultSpecifier, defaultFormat, "-4567" }; + yield return new object[] { (IntPtr)0, defaultSpecifier, defaultFormat, "0" }; + yield return new object[] { (IntPtr)4567, defaultSpecifier, defaultFormat, "4567" }; + yield return new object[] { IntPtr.MaxValue, defaultSpecifier, defaultFormat, Is64Bit ? "9223372036854775807" : "2147483647" }; + } + + yield return new object[] { (IntPtr)4567, "D", defaultFormat, "4567" }; + yield return new object[] { (IntPtr)4567, "D99", defaultFormat, "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" }; + yield return new object[] { (IntPtr)4567, "D99\09", defaultFormat, "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" }; + yield return new object[] { (IntPtr)(-4567), "D99\09", defaultFormat, "-000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004567" }; + + yield return new object[] { (IntPtr)0x2468, "x", defaultFormat, "2468" }; + yield return new object[] { (IntPtr)(-0x2468), "x", defaultFormat, Is64Bit ? "ffffffffffffdb98" : "ffffdb98" }; + yield return new object[] { (IntPtr)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; + } + + var customFormat = new NumberFormatInfo() + { + NegativeSign = "#", + NumberDecimalSeparator = "~", + NumberGroupSeparator = "*", + PositiveSign = "&", + NumberDecimalDigits = 2, + PercentSymbol = "@", + PercentGroupSeparator = ",", + PercentDecimalSeparator = ".", + PercentDecimalDigits = 5 + }; + yield return new object[] { (IntPtr)(-2468), "N", customFormat, "#2*468~00" }; + yield return new object[] { (IntPtr)2468, "N", customFormat, "2*468~00" }; + yield return new object[] { (IntPtr)123, "E", customFormat, "1~230000E&002" }; + yield return new object[] { (IntPtr)123, "F", customFormat, "123~00" }; + yield return new object[] { (IntPtr)123, "P", customFormat, "12,300.00000 @" }; + } + + [Theory] + [MemberData(nameof(ToString_TestData))] + public static void ToStringTest(IntPtr i, string format, IFormatProvider provider, string expected) + { + // Format is case insensitive + string upperFormat = format.ToUpperInvariant(); + string lowerFormat = format.ToLowerInvariant(); + + string upperExpected = expected.ToUpperInvariant(); + string lowerExpected = expected.ToLowerInvariant(); + + bool isDefaultProvider = (provider == null || provider == NumberFormatInfo.CurrentInfo); + if (string.IsNullOrEmpty(format) || format.ToUpperInvariant() == "G") + { + if (isDefaultProvider) + { + Assert.Equal(upperExpected, i.ToString()); + Assert.Equal(upperExpected, i.ToString((IFormatProvider)null)); + } + Assert.Equal(upperExpected, i.ToString(provider)); + } + if (isDefaultProvider) + { + Assert.Equal(upperExpected, i.ToString(upperFormat)); + Assert.Equal(lowerExpected, i.ToString(lowerFormat)); + Assert.Equal(upperExpected, i.ToString(upperFormat, null)); + Assert.Equal(lowerExpected, i.ToString(lowerFormat, null)); + } + Assert.Equal(upperExpected, i.ToString(upperFormat, provider)); + Assert.Equal(lowerExpected, i.ToString(lowerFormat, provider)); + } + + [Fact] + public static void ToString_InvalidFormat_ThrowsFormatException() + { + IntPtr i = (IntPtr)123; + Assert.Throws(() => i.ToString("r")); // Invalid format + Assert.Throws(() => i.ToString("r", null)); // Invalid format + Assert.Throws(() => i.ToString("R")); // Invalid format + Assert.Throws(() => i.ToString("R", null)); // Invalid format + Assert.Throws(() => i.ToString("Y")); // Invalid format + Assert.Throws(() => i.ToString("Y", null)); // Invalid format + } + + public static IEnumerable Parse_Valid_TestData() + { + NumberFormatInfo samePositiveNegativeFormat = new NumberFormatInfo() + { + PositiveSign = "|", + NegativeSign = "|" + }; + + NumberFormatInfo emptyPositiveFormat = new NumberFormatInfo() { PositiveSign = "" }; + NumberFormatInfo emptyNegativeFormat = new NumberFormatInfo() { NegativeSign = "" }; + + // None + yield return new object[] { "0", NumberStyles.None, null, (IntPtr)0 }; + yield return new object[] { "0000000000000000000000000000000000000000000000000000000000", NumberStyles.None, null, (IntPtr)0 }; + yield return new object[] { "0000000000000000000000000000000000000000000000000000000001", NumberStyles.None, null, (IntPtr)1 }; + yield return new object[] { "2147483647", NumberStyles.None, null, (IntPtr)2147483647 }; + yield return new object[] { "02147483647", NumberStyles.None, null, (IntPtr)2147483647 }; + yield return new object[] { "00000000000000000000000000000000000000000000000002147483647", NumberStyles.None, null, (IntPtr)2147483647 }; + yield return new object[] { "123\0\0", NumberStyles.None, null, (IntPtr)123 }; + + // All lengths decimal + foreach (bool neg in new[] { false, true }) + { + string s = neg ? "-" : ""; + var result = 0; + for (var i = 1; i <= 10; i++) + { + result = result * 10 + (i % 10); + s += (i % 10).ToString(); + yield return new object[] { s, NumberStyles.Integer, null, (IntPtr)(neg ? result * -1 : result) }; + } + } + + // All lengths hexadecimal + { + string s = ""; + var result = 0; + for (var i = 1; i <= 8; i++) + { + result = (result * 16) + (i % 16); + s += (i % 16).ToString("X"); + yield return new object[] { s, NumberStyles.HexNumber, null, (IntPtr)result }; + } + } + + // HexNumber + yield return new object[] { "123", NumberStyles.HexNumber, null, (IntPtr)0x123 }; + yield return new object[] { "abc", NumberStyles.HexNumber, null, (IntPtr)0xabc }; + yield return new object[] { "ABC", NumberStyles.HexNumber, null, (IntPtr)0xabc }; + yield return new object[] { "12", NumberStyles.HexNumber, null, (IntPtr)0x12 }; + + + if (Is64Bit) + { + yield return new object[] { "8000000000000000", NumberStyles.HexNumber, null, IntPtr.MinValue }; + yield return new object[] { "7FFFFFFFFFFFFFFF", NumberStyles.HexNumber, null, IntPtr.MaxValue }; + } + else + { + yield return new object[] { "80000000", NumberStyles.HexNumber, null, IntPtr.MinValue }; + yield return new object[] { "7FFFFFFF", NumberStyles.HexNumber, null, IntPtr.MaxValue }; + } + + // Currency + NumberFormatInfo currencyFormat = new NumberFormatInfo() + { + CurrencySymbol = "$", + CurrencyGroupSeparator = "|", + NumberGroupSeparator = "/" + }; + yield return new object[] { "$1|000", NumberStyles.Currency, currencyFormat, (IntPtr)1000 }; + yield return new object[] { "$1000", NumberStyles.Currency, currencyFormat, (IntPtr)1000 }; + yield return new object[] { "$ 1000", NumberStyles.Currency, currencyFormat, (IntPtr)1000 }; + yield return new object[] { "1000", NumberStyles.Currency, currencyFormat, (IntPtr)1000 }; + yield return new object[] { "$(1000)", NumberStyles.Currency, currencyFormat, (IntPtr)(-1000) }; + yield return new object[] { "($1000)", NumberStyles.Currency, currencyFormat, (IntPtr)(-1000) }; + yield return new object[] { "$-1000", NumberStyles.Currency, currencyFormat, (IntPtr)(-1000) }; + yield return new object[] { "-$1000", NumberStyles.Currency, currencyFormat, (IntPtr)(-1000) }; + + NumberFormatInfo emptyCurrencyFormat = new NumberFormatInfo() { CurrencySymbol = "" }; + yield return new object[] { "100", NumberStyles.Currency, emptyCurrencyFormat, (IntPtr)100 }; + + // If CurrencySymbol and Negative are the same, NegativeSign is preferred + NumberFormatInfo sameCurrencyNegativeSignFormat = new NumberFormatInfo() + { + NegativeSign = "|", + CurrencySymbol = "|" + }; + yield return new object[] { "|1000", NumberStyles.AllowCurrencySymbol | NumberStyles.AllowLeadingSign, sameCurrencyNegativeSignFormat, (IntPtr)(-1000) }; + + // Any + yield return new object[] { "123", NumberStyles.Any, null, (IntPtr)123 }; + + // AllowLeadingSign + yield return new object[] { "-2147483648", NumberStyles.AllowLeadingSign, null, (IntPtr)(-2147483648) }; + yield return new object[] { "-123", NumberStyles.AllowLeadingSign, null, (IntPtr)(-123) }; + yield return new object[] { "+0", NumberStyles.AllowLeadingSign, null, (IntPtr)0 }; + yield return new object[] { "-0", NumberStyles.AllowLeadingSign, null, (IntPtr)0 }; + yield return new object[] { "+123", NumberStyles.AllowLeadingSign, null, (IntPtr)123 }; + + // If PositiveSign and NegativeSign are the same, PositiveSign is preferred + yield return new object[] { "|123", NumberStyles.AllowLeadingSign, samePositiveNegativeFormat, (IntPtr)123 }; + + // Empty PositiveSign or NegativeSign + yield return new object[] { "100", NumberStyles.AllowLeadingSign, emptyPositiveFormat, (IntPtr)100 }; + yield return new object[] { "100", NumberStyles.AllowLeadingSign, emptyNegativeFormat, (IntPtr)100 }; + + // AllowTrailingSign + yield return new object[] { "123", NumberStyles.AllowTrailingSign, null, (IntPtr)123 }; + yield return new object[] { "123+", NumberStyles.AllowTrailingSign, null, (IntPtr)123 }; + yield return new object[] { "123-", NumberStyles.AllowTrailingSign, null, (IntPtr)(-123) }; + + // If PositiveSign and NegativeSign are the same, PositiveSign is preferred + yield return new object[] { "123|", NumberStyles.AllowTrailingSign, samePositiveNegativeFormat, (IntPtr)123 }; + + // Empty PositiveSign or NegativeSign + yield return new object[] { "100", NumberStyles.AllowTrailingSign, emptyPositiveFormat, (IntPtr)100 }; + yield return new object[] { "100", NumberStyles.AllowTrailingSign, emptyNegativeFormat, (IntPtr)100 }; + + // AllowLeadingWhite and AllowTrailingWhite + yield return new object[] { " 123", NumberStyles.AllowLeadingWhite, null, (IntPtr)123 }; + yield return new object[] { " 123 ", NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, null, (IntPtr)123 }; + yield return new object[] { "123 ", NumberStyles.AllowTrailingWhite, null, (IntPtr)123 }; + yield return new object[] { "123 \0\0", NumberStyles.AllowTrailingWhite, null, (IntPtr)123 }; + yield return new object[] { " 2147483647 ", NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, null, (IntPtr)2147483647 }; + yield return new object[] { " -2147483648 ", NumberStyles.Integer, null, (IntPtr)(-2147483648) }; + foreach (char c in new[] { (char)0x9, (char)0xA, (char)0xB, (char)0xC, (char)0xD }) + { + string cs = c.ToString(); + yield return new object[] { cs + cs + "123" + cs + cs, NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, null, (IntPtr)123 }; + } + yield return new object[] { " 0 ", NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, null, (IntPtr)0 }; + yield return new object[] { " 000000000 ", NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, null, (IntPtr)0 }; + + // AllowThousands + NumberFormatInfo thousandsFormat = new NumberFormatInfo() { NumberGroupSeparator = "|" }; + yield return new object[] { "1000", NumberStyles.AllowThousands, thousandsFormat, (IntPtr)1000 }; + yield return new object[] { "1|0|0|0", NumberStyles.AllowThousands, thousandsFormat, (IntPtr)1000 }; + yield return new object[] { "1|||", NumberStyles.AllowThousands, thousandsFormat, (IntPtr)1 }; + + NumberFormatInfo IntegerNumberSeparatorFormat = new NumberFormatInfo() { NumberGroupSeparator = "1" }; + yield return new object[] { "1111", NumberStyles.AllowThousands, IntegerNumberSeparatorFormat, (IntPtr)1111 }; + + // AllowExponent + yield return new object[] { "1E2", NumberStyles.AllowExponent, null, (IntPtr)100 }; + yield return new object[] { "1E+2", NumberStyles.AllowExponent, null, (IntPtr)100 }; + yield return new object[] { "1e2", NumberStyles.AllowExponent, null, (IntPtr)100 }; + yield return new object[] { "1E0", NumberStyles.AllowExponent, null, (IntPtr)1 }; + yield return new object[] { "(1E2)", NumberStyles.AllowExponent | NumberStyles.AllowParentheses, null, (IntPtr)(-100) }; + yield return new object[] { "-1E2", NumberStyles.AllowExponent | NumberStyles.AllowLeadingSign, null, (IntPtr)(-100) }; + + NumberFormatInfo negativeFormat = new NumberFormatInfo() { PositiveSign = "|" }; + yield return new object[] { "1E|2", NumberStyles.AllowExponent, negativeFormat, (IntPtr)100 }; + + // AllowParentheses + yield return new object[] { "123", NumberStyles.AllowParentheses, null, (IntPtr)123 }; + yield return new object[] { "(123)", NumberStyles.AllowParentheses, null, (IntPtr)(-123) }; + + // AllowDecimalPoint + NumberFormatInfo decimalFormat = new NumberFormatInfo() { NumberDecimalSeparator = "|" }; + yield return new object[] { "67|", NumberStyles.AllowDecimalPoint, decimalFormat, (IntPtr)67 }; + + // NumberFormatInfo has a custom property with length > (IntPtr)1 + NumberFormatInfo IntegerCurrencyFormat = new NumberFormatInfo() { CurrencySymbol = "123" }; + yield return new object[] { "123123", NumberStyles.AllowCurrencySymbol, IntegerCurrencyFormat, (IntPtr)123 }; + + yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { PositiveSign = "1" }, (IntPtr)23123 }; + yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { NegativeSign = "1" }, (IntPtr)(-23123) }; + yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { PositiveSign = "123" }, (IntPtr)123 }; + yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { NegativeSign = "123" }, (IntPtr)(-123) }; + yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { PositiveSign = "12312" }, (IntPtr)3 }; + yield return new object[] { "123123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { NegativeSign = "12312" }, (IntPtr)(-3) }; + } + + [Theory] + [MemberData(nameof(Parse_Valid_TestData))] + public static void Parse_Valid(string value, NumberStyles style, IFormatProvider provider, IntPtr expected) + { + IntPtr result; + + // Default style and provider + if (style == NumberStyles.Integer && provider == null) + { + Assert.True(IntPtr.TryParse(value, out result)); + Assert.Equal(expected, result); + Assert.Equal(expected, IntPtr.Parse(value)); + } + + // Default provider + if (provider == null) + { + Assert.Equal(expected, IntPtr.Parse(value, style)); + + // Substitute default NumberFormatInfo + Assert.True(IntPtr.TryParse(value, style, new NumberFormatInfo(), out result)); + Assert.Equal(expected, result); + Assert.Equal(expected, IntPtr.Parse(value, style, new NumberFormatInfo())); + } + + // Default style + if (style == NumberStyles.Integer) + { + Assert.Equal(expected, IntPtr.Parse(value, provider)); + } + + // Full overloads + Assert.True(IntPtr.TryParse(value, style, provider, out result)); + Assert.Equal(expected, result); + Assert.Equal(expected, IntPtr.Parse(value, style, provider)); + } + + public static IEnumerable Parse_Invalid_TestData() + { + // String is null, empty or entirely whitespace + yield return new object[] { null, NumberStyles.Integer, null, typeof(ArgumentNullException) }; + yield return new object[] { null, NumberStyles.Any, null, typeof(ArgumentNullException) }; + + // String contains is null, empty or enitrely whitespace. + foreach (NumberStyles style in new[] { NumberStyles.Integer, NumberStyles.HexNumber, NumberStyles.Any }) + { + yield return new object[] { null, style, null, typeof(ArgumentNullException) }; + yield return new object[] { "", style, null, typeof(FormatException) }; + yield return new object[] { " \t \n \r ", style, null, typeof(FormatException) }; + yield return new object[] { " \0\0", style, null, typeof(FormatException) }; + } + + // Leading or trailing chars for which char.IsWhiteSpace is true but that's not valid for leading/trailing whitespace + foreach (string c in new[] { "\x0085", "\x00A0", "\x1680", "\x2000", "\x2001", "\x2002", "\x2003", "\x2004", "\x2005", "\x2006", "\x2007", "\x2008", "\x2009", "\x200A", "\x2028", "\x2029", "\x202F", "\x205F", "\x3000" }) + { + yield return new object[] { c + "123", NumberStyles.Integer, null, typeof(FormatException) }; + yield return new object[] { "123" + c, NumberStyles.Integer, null, typeof(FormatException) }; + } + + // String contains garbage + foreach (NumberStyles style in new[] { NumberStyles.Integer, NumberStyles.HexNumber, NumberStyles.Any }) + { + yield return new object[] { "Garbage", style, null, typeof(FormatException) }; + yield return new object[] { "g", style, null, typeof(FormatException) }; + yield return new object[] { "g1", style, null, typeof(FormatException) }; + yield return new object[] { "1g", style, null, typeof(FormatException) }; + yield return new object[] { "123g", style, null, typeof(FormatException) }; + yield return new object[] { "g123", style, null, typeof(FormatException) }; + yield return new object[] { "214748364g", style, null, typeof(FormatException) }; + } + + // String has leading zeros + yield return new object[] { "\0\0123", NumberStyles.Integer, null, typeof(FormatException) }; + yield return new object[] { "\0\0123", NumberStyles.Any, null, typeof(FormatException) }; + + // String has IntPtrernal zeros + yield return new object[] { "1\023", NumberStyles.Integer, null, typeof(FormatException) }; + yield return new object[] { "1\023", NumberStyles.Any, null, typeof(FormatException) }; + + // String has trailing zeros but with whitespace after + yield return new object[] { "123\0\0 ", NumberStyles.Integer, null, typeof(FormatException) }; + + // Integer doesn't allow hex, exponents, paretheses, currency, thousands, decimal + yield return new object[] { "abc", NumberStyles.Integer, null, typeof(FormatException) }; + yield return new object[] { "1E23", NumberStyles.Integer, null, typeof(FormatException) }; + yield return new object[] { "(123)", NumberStyles.Integer, null, typeof(FormatException) }; + yield return new object[] { 1000.ToString("C0"), NumberStyles.Integer, null, typeof(FormatException) }; + yield return new object[] { 1000.ToString("N0"), NumberStyles.Integer, null, typeof(FormatException) }; + yield return new object[] { 678.90.ToString("F2"), NumberStyles.Integer, null, typeof(FormatException) }; + + // HexNumber + yield return new object[] { "0xabc", NumberStyles.HexNumber, null, typeof(FormatException) }; + yield return new object[] { "&habc", NumberStyles.HexNumber, null, typeof(FormatException) }; + yield return new object[] { "G1", NumberStyles.HexNumber, null, typeof(FormatException) }; + yield return new object[] { "g1", NumberStyles.HexNumber, null, typeof(FormatException) }; + yield return new object[] { "+abc", NumberStyles.HexNumber, null, typeof(FormatException) }; + yield return new object[] { "-abc", NumberStyles.HexNumber, null, typeof(FormatException) }; + + // None doesn't allow hex or leading or trailing whitespace + yield return new object[] { "abc", NumberStyles.None, null, typeof(FormatException) }; + yield return new object[] { "123 ", NumberStyles.None, null, typeof(FormatException) }; + yield return new object[] { " 123", NumberStyles.None, null, typeof(FormatException) }; + yield return new object[] { " 123 ", NumberStyles.None, null, typeof(FormatException) }; + + // AllowLeadingSign + yield return new object[] { "+", NumberStyles.AllowLeadingSign, null, typeof(FormatException) }; + yield return new object[] { "-", NumberStyles.AllowLeadingSign, null, typeof(FormatException) }; + yield return new object[] { "+-123", NumberStyles.AllowLeadingSign, null, typeof(FormatException) }; + yield return new object[] { "-+123", NumberStyles.AllowLeadingSign, null, typeof(FormatException) }; + yield return new object[] { "- 123", NumberStyles.AllowLeadingSign, null, typeof(FormatException) }; + yield return new object[] { "+ 123", NumberStyles.AllowLeadingSign, null, typeof(FormatException) }; + + // AllowTrailingSign + yield return new object[] { "123-+", NumberStyles.AllowTrailingSign, null, typeof(FormatException) }; + yield return new object[] { "123+-", NumberStyles.AllowTrailingSign, null, typeof(FormatException) }; + yield return new object[] { "123 -", NumberStyles.AllowTrailingSign, null, typeof(FormatException) }; + yield return new object[] { "123 +", NumberStyles.AllowTrailingSign, null, typeof(FormatException) }; + + // Parentheses has priority over CurrencySymbol and PositiveSign + NumberFormatInfo currencyNegativeParenthesesFormat = new NumberFormatInfo() + { + CurrencySymbol = "(", + PositiveSign = "))" + }; + yield return new object[] { "(100))", NumberStyles.AllowParentheses | NumberStyles.AllowCurrencySymbol | NumberStyles.AllowTrailingSign, currencyNegativeParenthesesFormat, typeof(FormatException) }; + + // AllowTrailingSign and AllowLeadingSign + yield return new object[] { "+123+", NumberStyles.AllowLeadingSign | NumberStyles.AllowTrailingSign, null, typeof(FormatException) }; + yield return new object[] { "+123-", NumberStyles.AllowLeadingSign | NumberStyles.AllowTrailingSign, null, typeof(FormatException) }; + yield return new object[] { "-123+", NumberStyles.AllowLeadingSign | NumberStyles.AllowTrailingSign, null, typeof(FormatException) }; + yield return new object[] { "-123-", NumberStyles.AllowLeadingSign | NumberStyles.AllowTrailingSign, null, typeof(FormatException) }; + + // AllowLeadingSign and AllowParentheses + yield return new object[] { "-(1000)", NumberStyles.AllowLeadingSign | NumberStyles.AllowParentheses, null, typeof(FormatException) }; + yield return new object[] { "(-1000)", NumberStyles.AllowLeadingSign | NumberStyles.AllowParentheses, null, typeof(FormatException) }; + + // AllowLeadingWhite + yield return new object[] { "1 ", NumberStyles.AllowLeadingWhite, null, typeof(FormatException) }; + yield return new object[] { " 1 ", NumberStyles.AllowLeadingWhite, null, typeof(FormatException) }; + + // AllowTrailingWhite + yield return new object[] { " 1 ", NumberStyles.AllowTrailingWhite, null, typeof(FormatException) }; + yield return new object[] { " 1", NumberStyles.AllowTrailingWhite, null, typeof(FormatException) }; + + // AllowThousands + NumberFormatInfo thousandsFormat = new NumberFormatInfo() { NumberGroupSeparator = "|" }; + yield return new object[] { "|||1", NumberStyles.AllowThousands, null, typeof(FormatException) }; + + // AllowExponent + yield return new object[] { "65E", NumberStyles.AllowExponent, null, typeof(FormatException) }; + yield return new object[] { "65E19", NumberStyles.AllowExponent, null, typeof(OverflowException) }; + yield return new object[] { "65E+19", NumberStyles.AllowExponent, null, typeof(OverflowException) }; + yield return new object[] { "65E-1", NumberStyles.AllowExponent, null, typeof(OverflowException) }; + + // AllowDecimalPoint + NumberFormatInfo decimalFormat = new NumberFormatInfo() { NumberDecimalSeparator = "." }; + yield return new object[] { "67.9", NumberStyles.AllowDecimalPoint, decimalFormat, typeof(OverflowException) }; + + // Parsing Integers doesn't allow NaN, PositiveInfinity or NegativeInfinity + NumberFormatInfo doubleFormat = new NumberFormatInfo() + { + NaNSymbol = "NaN", + PositiveInfinitySymbol = "Infinity", + NegativeInfinitySymbol = "-Infinity" + }; + yield return new object[] { "NaN", NumberStyles.Any, doubleFormat, typeof(FormatException) }; + yield return new object[] { "Infinity", NumberStyles.Any, doubleFormat, typeof(FormatException) }; + yield return new object[] { "-Infinity", NumberStyles.Any, doubleFormat, typeof(FormatException) }; + + // Only has a leading sign + yield return new object[] { "+", NumberStyles.AllowLeadingSign, null, typeof(FormatException) }; + yield return new object[] { "-", NumberStyles.AllowLeadingSign, null, typeof(FormatException) }; + yield return new object[] { " +", NumberStyles.Integer, null, typeof(FormatException) }; + yield return new object[] { " -", NumberStyles.Integer, null, typeof(FormatException) }; + yield return new object[] { "+ ", NumberStyles.Integer, null, typeof(FormatException) }; + yield return new object[] { "- ", NumberStyles.Integer, null, typeof(FormatException) }; + + // NumberFormatInfo has a custom property with length > (IntPtr)1 + NumberFormatInfo IntegerCurrencyFormat = new NumberFormatInfo() { CurrencySymbol = "123" }; + yield return new object[] { "123", NumberStyles.AllowCurrencySymbol, IntegerCurrencyFormat, typeof(FormatException) }; + yield return new object[] { "123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { PositiveSign = "123" }, typeof(FormatException) }; + yield return new object[] { "123", NumberStyles.AllowLeadingSign, new NumberFormatInfo() { NegativeSign = "123" }, typeof(FormatException) }; + + // Decimals not in range of IntPtr32 + foreach (string s in new[] + { + + "9223372036854775808", // long.MaxValue + 1 + "9223372036854775810", // 10s digit incremented above long.MaxValue + "10000000000000000000", // extra digit after long.MaxValue + + "18446744073709551616", // ulong.MaxValue + 1 + "18446744073709551620", // 10s digit incremented above ulong.MaxValue + "100000000000000000000", // extra digit after ulong.MaxValue + + "-9223372036854775809", // long.MinValue - 1 + "-9223372036854775810", // 10s digit decremented below long.MinValue + "-10000000000000000000", // extra digit after long.MinValue + + "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000", // really big + "-100000000000000000000000000000000000000000000000000000000000000000000000000000000000000" // really small + }) + { + foreach (NumberStyles styles in new[] { NumberStyles.Any, NumberStyles.Integer }) + { + yield return new object[] { s, styles, null, typeof(OverflowException) }; + yield return new object[] { s + " ", styles, null, typeof(OverflowException) }; + yield return new object[] { s + " " + "\0\0\0", styles, null, typeof(OverflowException) }; + + yield return new object[] { s + "g", styles, null, typeof(FormatException) }; + yield return new object[] { s + "\0g", styles, null, typeof(FormatException) }; + yield return new object[] { s + " g", styles, null, typeof(FormatException) }; + } + } + + // Hexadecimals not in range of IntPtr32 + foreach (string s in new[] + { + "10000000000000000", // ulong.MaxValue + (IntPtr)1 + "FFFFFFFFFFFFFFFF0", // extra digit after ulong.MaxValue + + "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000" // really big + }) + { + yield return new object[] { s, NumberStyles.HexNumber, null, typeof(OverflowException) }; + yield return new object[] { s + " ", NumberStyles.HexNumber, null, typeof(OverflowException) }; + yield return new object[] { s + " " + "\0\0", NumberStyles.HexNumber, null, typeof(OverflowException) }; + + yield return new object[] { s + "g", NumberStyles.HexNumber, null, typeof(FormatException) }; + yield return new object[] { s + "\0g", NumberStyles.HexNumber, null, typeof(FormatException) }; + yield return new object[] { s + " g", NumberStyles.HexNumber, null, typeof(FormatException) }; + } + + yield return new object[] { "9223372036854775809-", NumberStyles.AllowTrailingSign, null, typeof(OverflowException) }; + yield return new object[] { "(9223372036854775809)", NumberStyles.AllowParentheses, null, typeof(OverflowException) }; + yield return new object[] { "2E19", NumberStyles.AllowExponent, null, typeof(OverflowException) }; + } + + [Theory] + [MemberData(nameof(Parse_Invalid_TestData))] + public static void Parse_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType) + { + if (2 == 2E10) { } + IntPtr result; + + // Default style and provider + if (style == NumberStyles.Integer && provider == null) + { + Assert.False(IntPtr.TryParse(value, out result)); + Assert.Equal(default, result); + Assert.Throws(exceptionType, () => IntPtr.Parse(value)); + } + + // Default provider + if (provider == null) + { + Assert.Throws(exceptionType, () => IntPtr.Parse(value, style)); + + // Substitute default NumberFormatInfo + Assert.False(IntPtr.TryParse(value, style, new NumberFormatInfo(), out result)); + Assert.Equal(default, result); + Assert.Throws(exceptionType, () => IntPtr.Parse(value, style, new NumberFormatInfo())); + } + + // Default style + if (style == NumberStyles.Integer) + { + Assert.Throws(exceptionType, () => IntPtr.Parse(value, provider)); + } + + // Full overloads + Assert.False(IntPtr.TryParse(value, style, provider, out result)); + Assert.Equal(default, result); + Assert.Throws(exceptionType, () => IntPtr.Parse(value, style, provider)); + } + + [Theory] + [InlineData(NumberStyles.HexNumber | NumberStyles.AllowParentheses, null)] + [InlineData(unchecked((NumberStyles)0xFFFFFC00), "style")] + public static void TryParse_InvalidNumberStyle_ThrowsArgumentException(NumberStyles style, string paramName) + { + IntPtr result = (IntPtr)0; + AssertExtensions.Throws(paramName, () => IntPtr.TryParse("1", style, null, out result)); + Assert.Equal(default(IntPtr), result); + + AssertExtensions.Throws(paramName, () => IntPtr.Parse("1", style)); + AssertExtensions.Throws(paramName, () => IntPtr.Parse("1", style, null)); + } + + [Theory] + [InlineData("N")] + [InlineData("F")] + public static void ToString_N_F_EmptyNumberGroup_Success(string specifier) + { + var nfi = (NumberFormatInfo)NumberFormatInfo.InvariantInfo.Clone(); + nfi.NumberGroupSizes = new int[0]; + nfi.NumberGroupSeparator = ","; + Assert.Equal("1234", ((IntPtr)1234).ToString($"{specifier}0", nfi)); + } + + [Fact] + public static void ToString_P_EmptyPercentGroup_Success() + { + var nfi = (NumberFormatInfo)NumberFormatInfo.InvariantInfo.Clone(); + nfi.PercentGroupSizes = new int[0]; + nfi.PercentSymbol = "%"; + Assert.Equal("123400 %", ((IntPtr)1234).ToString("P0", nfi)); + } + + [Fact] + public static void ToString_C_EmptyPercentGroup_Success() + { + var nfi = (NumberFormatInfo)NumberFormatInfo.InvariantInfo.Clone(); + nfi.CurrencyGroupSizes = new int[0]; + nfi.CurrencySymbol = "$"; + Assert.Equal("$1234", ((IntPtr)1234).ToString("C0", nfi)); + } + + public static IEnumerable Parse_ValidWithOffsetCount_TestData() + { + foreach (object[] inputs in Parse_Valid_TestData()) + { + yield return new object[] { inputs[0], (IntPtr)0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] }; + } + + NumberFormatInfo samePositiveNegativeFormat = new NumberFormatInfo() + { + PositiveSign = "|", + NegativeSign = "|" + }; + + NumberFormatInfo emptyPositiveFormat = new NumberFormatInfo() { PositiveSign = "" }; + NumberFormatInfo emptyNegativeFormat = new NumberFormatInfo() { NegativeSign = "" }; + + // None + yield return new object[] { "2147483647", (IntPtr)1, (IntPtr)9, NumberStyles.None, null, (IntPtr)147483647 }; + yield return new object[] { "2147483647", (IntPtr)1, (IntPtr)1, NumberStyles.None, null, (IntPtr)1 }; + yield return new object[] { "123\0\0", (IntPtr)2, (IntPtr)2, NumberStyles.None, null, (IntPtr)3 }; + + // Hex + yield return new object[] { "abc", (IntPtr)0, (IntPtr)1, NumberStyles.HexNumber, null, (IntPtr)0xa }; + yield return new object[] { "ABC", (IntPtr)1, (IntPtr)1, NumberStyles.HexNumber, null, (IntPtr)0xB }; + yield return new object[] { "FFFFFFFF", (IntPtr)6, (IntPtr)2, NumberStyles.HexNumber, null, (IntPtr)0xFF }; + yield return new object[] { "FFFFFFFF", (IntPtr)0, (IntPtr)1, NumberStyles.HexNumber, null, (IntPtr)0xF }; + + // Currency + yield return new object[] { "-$1000", (IntPtr)1, (IntPtr)5, NumberStyles.Currency, new NumberFormatInfo() + { + CurrencySymbol = "$", + CurrencyGroupSeparator = "|", + NumberGroupSeparator = "/" + }, (IntPtr)1000 }; + + NumberFormatInfo emptyCurrencyFormat = new NumberFormatInfo() { CurrencySymbol = "" }; + yield return new object[] { "100", (IntPtr)1, (IntPtr)2, NumberStyles.Currency, emptyCurrencyFormat, (IntPtr)0 }; + yield return new object[] { "100", (IntPtr)0, (IntPtr)1, NumberStyles.Currency, emptyCurrencyFormat, (IntPtr)1 }; + + // If CurrencySymbol and Negative are the same, NegativeSign is preferred + NumberFormatInfo sameCurrencyNegativeSignFormat = new NumberFormatInfo() + { + NegativeSign = "|", + CurrencySymbol = "|" + }; + yield return new object[] { "1000", (IntPtr)1, (IntPtr)3, NumberStyles.AllowCurrencySymbol | NumberStyles.AllowLeadingSign, sameCurrencyNegativeSignFormat, (IntPtr)0 }; + yield return new object[] { "|1000", (IntPtr)0, (IntPtr)2, NumberStyles.AllowCurrencySymbol | NumberStyles.AllowLeadingSign, sameCurrencyNegativeSignFormat, -1 }; + + // Any + yield return new object[] { "123", (IntPtr)0, (IntPtr)2, NumberStyles.Any, null, (IntPtr)12 }; + + // AllowLeadingSign + yield return new object[] { "-2147483648", (IntPtr)0, (IntPtr)10, NumberStyles.AllowLeadingSign, null, -214748364 }; + + // AllowTrailingSign + yield return new object[] { "123-", (IntPtr)0, (IntPtr)3, NumberStyles.AllowTrailingSign, null, (IntPtr)123 }; + + // AllowExponent + yield return new object[] { "1E2", (IntPtr)0, (IntPtr)1, NumberStyles.AllowExponent, null, (IntPtr)1 }; + yield return new object[] { "1E+2", (IntPtr)3, (IntPtr)1, NumberStyles.AllowExponent, null, (IntPtr)2 }; + yield return new object[] { "(1E2)", (IntPtr)1, (IntPtr)3, NumberStyles.AllowExponent | NumberStyles.AllowParentheses, null, (IntPtr)1E2 }; + yield return new object[] { "-1E2", (IntPtr)1, (IntPtr)3, NumberStyles.AllowExponent | NumberStyles.AllowLeadingSign, null, (IntPtr)1E2 }; + } } } diff --git a/src/libraries/System.Runtime/tests/System/InvalidCastExceptionTests.cs b/src/libraries/System.Runtime/tests/System/InvalidCastExceptionTests.cs index ac0bb5ae408f6d..291d5137a7e2be 100644 --- a/src/libraries/System.Runtime/tests/System/InvalidCastExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/InvalidCastExceptionTests.cs @@ -14,7 +14,7 @@ public static class InvalidCastExceptionTests public static void Ctor_Empty() { var exception = new InvalidCastException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDCAST, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDCAST, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "wrong type"; var exception = new InvalidCastException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDCAST, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDCAST, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "wrong type"; var innerException = new Exception("Inner exception"); var exception = new InvalidCastException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDCAST, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDCAST, innerException: innerException, message: message); } [Fact] @@ -40,7 +40,7 @@ public static void Ctor_String_Int32() string message = "wrong type"; int errorCode = unchecked((int)0x80424242); var exception = new InvalidCastException(message, errorCode); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: errorCode, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: errorCode, message: message); } } diff --git a/src/libraries/System.Runtime/tests/System/InvalidOperationExceptionTests.cs b/src/libraries/System.Runtime/tests/System/InvalidOperationExceptionTests.cs index d1a877aca25167..7448b5bb8e25e5 100644 --- a/src/libraries/System.Runtime/tests/System/InvalidOperationExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/InvalidOperationExceptionTests.cs @@ -14,7 +14,7 @@ public static class InvalidOperationExceptionTests public static void Ctor_Empty() { var exception = new InvalidOperationException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDOPERATION, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDOPERATION, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "invalid operation"; var exception = new InvalidOperationException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDOPERATION, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDOPERATION, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "invalid operation"; var innerException = new Exception("Inner exception"); var exception = new InvalidOperationException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDOPERATION, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDOPERATION, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/InvalidProgramExceptionTests.cs b/src/libraries/System.Runtime/tests/System/InvalidProgramExceptionTests.cs index 17488ceb1e40ef..98ae359537af28 100644 --- a/src/libraries/System.Runtime/tests/System/InvalidProgramExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/InvalidProgramExceptionTests.cs @@ -14,7 +14,7 @@ public static class InvalidProgramExceptionTests public static void Ctor_Empty() { var exception = new InvalidProgramException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDPROGRAM, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDPROGRAM, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "bad program"; var exception = new InvalidProgramException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDPROGRAM, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDPROGRAM, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "bad program"; var innerException = new Exception("Inner exception"); var exception = new InvalidProgramException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDPROGRAM, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_INVALIDPROGRAM, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/MemberAccessExceptionTests.cs b/src/libraries/System.Runtime/tests/System/MemberAccessExceptionTests.cs index 6ffc2912009f69..46b268ff311e4f 100644 --- a/src/libraries/System.Runtime/tests/System/MemberAccessExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/MemberAccessExceptionTests.cs @@ -14,7 +14,7 @@ public static class MemberAccessExceptionTests public static void Ctor_Empty() { var exception = new MemberAccessException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_MEMBERACCESS, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_MEMBERACCESS, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "you cannot access this member"; var exception = new MemberAccessException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_MEMBERACCESS, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_MEMBERACCESS, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "you cannot access this member"; var innerException = new Exception("Inner exception"); var exception = new MemberAccessException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_MEMBERACCESS, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_MEMBERACCESS, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/NotImplementedExceptionTests.cs b/src/libraries/System.Runtime/tests/System/NotImplementedExceptionTests.cs index f2a19dddafedfe..dfc8ab299a9f0a 100644 --- a/src/libraries/System.Runtime/tests/System/NotImplementedExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/NotImplementedExceptionTests.cs @@ -14,7 +14,7 @@ public static class NotImplementedExceptionTests public static void Ctor_Empty() { var exception = new NotImplementedException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: E_NOTIMPL, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: E_NOTIMPL, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "not implemented"; var exception = new NotImplementedException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: E_NOTIMPL, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: E_NOTIMPL, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "not implemented"; var innerException = new Exception("Inner exception"); var exception = new NotImplementedException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: E_NOTIMPL, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: E_NOTIMPL, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/NotSupportedExceptionTests.cs b/src/libraries/System.Runtime/tests/System/NotSupportedExceptionTests.cs index a5aa0905d74b0d..6aa28beffbd871 100644 --- a/src/libraries/System.Runtime/tests/System/NotSupportedExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/NotSupportedExceptionTests.cs @@ -14,7 +14,7 @@ public static class NotSupportedExceptionTests public static void Ctor_Empty() { var exception = new NotSupportedException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_NOTSUPPORTED, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_NOTSUPPORTED, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "not supported"; var exception = new NotSupportedException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_NOTSUPPORTED, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_NOTSUPPORTED, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "not supported"; var innerException = new Exception("Inner exception"); var exception = new NotSupportedException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_NOTSUPPORTED, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_NOTSUPPORTED, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/ObjectDisposedExceptionTests.cs b/src/libraries/System.Runtime/tests/System/ObjectDisposedExceptionTests.cs index 8345a782fe7bc2..4334b9f29c690c 100644 --- a/src/libraries/System.Runtime/tests/System/ObjectDisposedExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/ObjectDisposedExceptionTests.cs @@ -15,7 +15,7 @@ public static void Ctor_String() { string objectName = "theObject"; var exception = new ObjectDisposedException(objectName); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_OBJECTDISPOSED, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_OBJECTDISPOSED, validateMessage: false); Assert.Contains(objectName, exception.Message); var exceptionNullObjectName = new ObjectDisposedException(null); @@ -28,7 +28,7 @@ public static void Ctor_String_Exception() string message = "object disposed"; var innerException = new Exception("Inner exception"); var exception = new ObjectDisposedException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_OBJECTDISPOSED, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_OBJECTDISPOSED, innerException: innerException, message: message); Assert.Equal("", exception.ObjectName); } @@ -38,7 +38,7 @@ public static void Ctor_String_String() string message = "object disposed"; string objectName = "theObject"; var exception = new ObjectDisposedException(objectName, message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_OBJECTDISPOSED, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_OBJECTDISPOSED, validateMessage: false); Assert.Equal(objectName, exception.ObjectName); Assert.Contains(message, exception.Message); Assert.Contains(objectName, exception.Message); diff --git a/src/libraries/System.Runtime/tests/System/OutOfMemoryExceptionTests.cs b/src/libraries/System.Runtime/tests/System/OutOfMemoryExceptionTests.cs index 39c3fd1e9b6a2b..7585bceb305283 100644 --- a/src/libraries/System.Runtime/tests/System/OutOfMemoryExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/OutOfMemoryExceptionTests.cs @@ -14,7 +14,7 @@ public static class OutOfMemoryExceptionTests public static void Ctor_Empty() { var exception = new OutOfMemoryException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_OUTOFMEMORY, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_OUTOFMEMORY, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "out of memory"; var exception = new OutOfMemoryException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_OUTOFMEMORY, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_OUTOFMEMORY, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "out of memory"; var innerException = new Exception("Inner exception"); var exception = new OutOfMemoryException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_OUTOFMEMORY, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_OUTOFMEMORY, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/OverflowExceptionTests.cs b/src/libraries/System.Runtime/tests/System/OverflowExceptionTests.cs index 2c239b180c6a30..348fc7b15aa99e 100644 --- a/src/libraries/System.Runtime/tests/System/OverflowExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/OverflowExceptionTests.cs @@ -14,7 +14,7 @@ public static class OverflowExceptionTests public static void Ctor_Empty() { var exception = new OverflowException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_OVERFLOW, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_OVERFLOW, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "overflow"; var exception = new OverflowException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_OVERFLOW, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_OVERFLOW, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "overflow"; var innerException = new Exception("Inner exception"); var exception = new OverflowException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_OVERFLOW, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_OVERFLOW, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/PlatformNotSupportedExceptionTests.cs b/src/libraries/System.Runtime/tests/System/PlatformNotSupportedExceptionTests.cs index 1e0fc9452e9690..0897004bd2ccec 100644 --- a/src/libraries/System.Runtime/tests/System/PlatformNotSupportedExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/PlatformNotSupportedExceptionTests.cs @@ -14,7 +14,7 @@ public static class PlatformNotSupportedExceptionTests public static void Ctor_Empty() { var exception = new PlatformNotSupportedException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_PLATFORMNOTSUPPORTED, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_PLATFORMNOTSUPPORTED, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "platform not supported"; var exception = new PlatformNotSupportedException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_PLATFORMNOTSUPPORTED, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_PLATFORMNOTSUPPORTED, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "platform not supported"; var innerException = new Exception("Inner exception"); var exception = new PlatformNotSupportedException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_PLATFORMNOTSUPPORTED, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_PLATFORMNOTSUPPORTED, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/RankExceptionTests.cs b/src/libraries/System.Runtime/tests/System/RankExceptionTests.cs index 6a3bad220dcddd..6da6e3f614f587 100644 --- a/src/libraries/System.Runtime/tests/System/RankExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/RankExceptionTests.cs @@ -14,7 +14,7 @@ public static class RankExceptionTests public static void Ctor_Empty() { var exception = new RankException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_RANK, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_RANK, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "bad rank"; var exception = new RankException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_RANK, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_RANK, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "bad rank"; var innerException = new Exception("Inner exception"); var exception = new RankException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_RANK, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_RANK, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/Runtime/MemoryFailPointTests.cs b/src/libraries/System.Runtime/tests/System/Runtime/MemoryFailPointTests.cs index 9c17bc610763b1..6f82da16329fbc 100644 --- a/src/libraries/System.Runtime/tests/System/Runtime/MemoryFailPointTests.cs +++ b/src/libraries/System.Runtime/tests/System/Runtime/MemoryFailPointTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.DotNet.XUnitExtensions; using Xunit; namespace System.Runtime.Tests @@ -26,10 +27,15 @@ public void Ctor_Negative_ThrowsArgumentOutOfRangeException(int sizeInMegabytes) AssertExtensions.Throws("sizeInMegabytes", () => new MemoryFailPoint(sizeInMegabytes)); } - [Fact] + [ConditionalFact] [PlatformSpecific(TestPlatforms.Windows)] //https://github.com/dotnet/runtime/issues/6879 public void Ctor_LargeSizeInMegabytes_ThrowsInsufficientMemoryException() { + if (PlatformDetection.IsArmProcess) + { + throw new SkipTestException("[ActiveIssue: https://github.com/dotnet/runtime/issues/35805]"); + } + Assert.Throws(() => new MemoryFailPoint(int.MaxValue)); } } diff --git a/src/libraries/System.Runtime/tests/System/Security/SecurityExceptionTests.cs b/src/libraries/System.Runtime/tests/System/Security/SecurityExceptionTests.cs index 57596cb863b8bc..f6462cb5ca3323 100644 --- a/src/libraries/System.Runtime/tests/System/Security/SecurityExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/Security/SecurityExceptionTests.cs @@ -17,7 +17,7 @@ public static class SecurityExceptionTests public static void Ctor_Empty() { var exception = new SecurityException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_SECURITY, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_SECURITY, validateMessage: false); } [Fact] @@ -25,7 +25,7 @@ public static void Ctor_String() { string message = "security problem"; var exception = new SecurityException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_SECURITY, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_SECURITY, message: message); } [Fact] @@ -34,7 +34,7 @@ public static void Ctor_String_Exception() string message = "security problem"; var innerException = new Exception("Inner exception"); var exception = new SecurityException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_SECURITY, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_SECURITY, innerException: innerException, message: message); } [Fact] @@ -42,7 +42,7 @@ public static void Ctor_String_Type() { string message = "security problem"; var exception = new SecurityException(message, typeof(SecurityExceptionTests)); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_SECURITY, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_SECURITY, message: message); Assert.Equal(typeof(SecurityExceptionTests), exception.PermissionType); } @@ -51,7 +51,7 @@ public static void Ctor_String_Type_String() { string message = "security problem"; var exception = new SecurityException(message, typeof(SecurityExceptionTests), "permission state"); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_SECURITY, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_SECURITY, message: message); Assert.Equal(typeof(SecurityExceptionTests), exception.PermissionType); Assert.Equal("permission state", exception.PermissionState); } diff --git a/src/libraries/System.Runtime/tests/System/Text/RuneTests.cs b/src/libraries/System.Runtime/tests/System/Text/RuneTests.cs index 6772d7438c34de..e22f802fc07ef4 100644 --- a/src/libraries/System.Runtime/tests/System/Text/RuneTests.cs +++ b/src/libraries/System.Runtime/tests/System/Text/RuneTests.cs @@ -12,7 +12,7 @@ namespace System.Text.Tests { public static partial class RuneTests { - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows8xOrLater))] // the localization tables used by our test data only exist on Win8+ + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows8xOrLater), nameof(PlatformDetection.IsNlsGlobalization))] // the localization tables used by our test data only exist on Win8+ [PlatformSpecific(TestPlatforms.Windows)] [InlineData('0', '0', '0', "en-US")] [InlineData('a', 'A', 'a', "en-US")] @@ -38,7 +38,7 @@ public static void Casing_CultureAware(int original, int upper, int lower, strin } // Invariant ToUpper / ToLower doesn't modify Turkish I or majuscule Eszett - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows8xOrLater))] // the localization tables used by our test data only exist on Win8+ + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows8xOrLater), nameof(PlatformDetection.IsNlsGlobalization))] // the localization tables used by our test data only exist on Win8+ [PlatformSpecific(TestPlatforms.Windows)] [InlineData('0', '0', '0')] [InlineData('a', 'A', 'a')] diff --git a/src/libraries/System.Runtime/tests/System/TimeoutExceptionTests.cs b/src/libraries/System.Runtime/tests/System/TimeoutExceptionTests.cs index 652fe1f0b238e6..3a4a9722441b88 100644 --- a/src/libraries/System.Runtime/tests/System/TimeoutExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/TimeoutExceptionTests.cs @@ -14,7 +14,7 @@ public static class TimeoutExceptionTests public static void Ctor_Empty() { var exception = new TimeoutException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_TIMEOUT, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_TIMEOUT, validateMessage: false); } [Fact] @@ -22,7 +22,7 @@ public static void Ctor_String() { string message = "timeout"; var exception = new TimeoutException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_TIMEOUT, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_TIMEOUT, message: message); } [Fact] @@ -31,7 +31,7 @@ public static void Ctor_String_Exception() string message = "timeout"; var innerException = new Exception("Inner exception"); var exception = new TimeoutException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_TIMEOUT, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_TIMEOUT, innerException: innerException, message: message); } } } diff --git a/src/libraries/System.Runtime/tests/System/Type/TypeTests.Get.cs b/src/libraries/System.Runtime/tests/System/Type/TypeTests.Get.cs index 124687962d0f0f..9e3e3d2c2372dd 100644 --- a/src/libraries/System.Runtime/tests/System/Type/TypeTests.Get.cs +++ b/src/libraries/System.Runtime/tests/System/Type/TypeTests.Get.cs @@ -71,7 +71,7 @@ public void GetInterface_Invoke_ReturnsExpected(Type type, string name, bool ign [Fact] public void GetInterface_NullName_ThrowsArgumentNullException() { - AssertExtensions.Throws(null, () => typeof(int).GetInterface(null)); + AssertExtensions.Throws("fullname", () => typeof(int).GetInterface(null)); } [Fact] @@ -91,12 +91,6 @@ public void GetInterface_MixedCaseAmbiguity_ThrowsAmbiguousMatchException() { Assert.Throws(() => typeof(ClassWithMixedCaseInterfaces).GetInterface("mixedinterface", ignoreCase: true)); } - - [Fact] - public void GetCustomAttributes_Interface() - { - Assert.True(typeof(ExampleWithAttribute).GetCustomAttributes(typeof(INameable), inherit: false)[0] is NameableAttribute); - } } public class ClassWithNoInterfaces { } @@ -122,20 +116,6 @@ public interface Interface1 { } public interface Interface2 { } public interface Interface3 { } } - - public interface INameable - { - string Name { get; } - } - - [AttributeUsage (AttributeTargets.All, AllowMultiple=true)] - public class NameableAttribute : Attribute, INameable - { - string INameable.Name => "Nameable"; - } - - [Nameable] - public class ExampleWithAttribute { } } public interface Interface1 { } diff --git a/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs b/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs index 7f8cd6368d03cb..d45b52c90c57c0 100644 --- a/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs +++ b/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs @@ -688,6 +688,8 @@ public static IEnumerable GetInterfaceMap_TestData() [Theory] [MemberData(nameof(GetInterfaceMap_TestData))] + // Android-only, change to TestPlatforms.Android once arcade dependency is updated + [ActiveIssue("https://github.com/dotnet/runtime/issues/36653", TestRuntimes.Mono)] public void GetInterfaceMap(Type interfaceType, Type classType, Tuple[] expectedMap) { InterfaceMapping actualMapping = classType.GetInterfaceMap(interfaceType); diff --git a/src/libraries/System.Runtime/tests/System/TypeLoadExceptionTests.cs b/src/libraries/System.Runtime/tests/System/TypeLoadExceptionTests.cs index 2fe5e13fd7649c..31e80b39ef20e4 100644 --- a/src/libraries/System.Runtime/tests/System/TypeLoadExceptionTests.cs +++ b/src/libraries/System.Runtime/tests/System/TypeLoadExceptionTests.cs @@ -15,7 +15,7 @@ public static class TypeLoadExceptionTests public static void Ctor_Empty() { var exception = new TypeLoadException(); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_TYPELOAD, validateMessage: false); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_TYPELOAD, validateMessage: false); Assert.Equal("", exception.TypeName); } @@ -24,7 +24,7 @@ public static void Ctor_String() { string message = "type failed to load"; var exception = new TypeLoadException(message); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_TYPELOAD, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_TYPELOAD, message: message); Assert.Equal("", exception.TypeName); } @@ -34,7 +34,7 @@ public static void Ctor_String_Exception() string message = "type failed to load"; var innerException = new Exception("Inner exception"); var exception = new TypeLoadException(message, innerException); - ExceptionUtility.ValidateExceptionProperties(exception, hResult: COR_E_TYPELOAD, innerException: innerException, message: message); + ExceptionHelpers.ValidateExceptionProperties(exception, hResult: COR_E_TYPELOAD, innerException: innerException, message: message); Assert.Equal("", exception.TypeName); } } diff --git a/src/libraries/System.Runtime/tests/System/UInt64Tests.cs b/src/libraries/System.Runtime/tests/System/UInt64Tests.cs index fac4535217cca1..0cb48dfeb5bd4d 100644 --- a/src/libraries/System.Runtime/tests/System/UInt64Tests.cs +++ b/src/libraries/System.Runtime/tests/System/UInt64Tests.cs @@ -120,6 +120,7 @@ public static IEnumerable ToString_TestData() yield return new object[] { (ulong)123, "E", customFormat, "1~230000E&002" }; yield return new object[] { (ulong)123, "F", customFormat, "123~00" }; yield return new object[] { (ulong)123, "P", customFormat, "12,300.00000 @" }; + yield return new object[] { ulong.MaxValue, "n5", customFormat, "18*446*744*073*709*551*615~00000" }; } [Theory] diff --git a/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs b/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs index 5881af789888a1..07b3532f5dd320 100644 --- a/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs +++ b/src/libraries/System.Runtime/tests/System/UIntPtrTests.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; +using System.Globalization; +using System.Runtime.CompilerServices; using Xunit; namespace System.Tests @@ -172,5 +174,294 @@ private static void VerifyPointer(UIntPtr ptr, ulong expected) Assert.False(ptr == new UIntPtr(expected + 1)); Assert.True(ptr != new UIntPtr(expected + 1)); } + + [Fact] + public static void Ctor_Empty() + { + var i = new UIntPtr(); + Assert.Equal((UIntPtr)0, i); + } + + [Fact] + public static void Ctor_Value() + { + UIntPtr i = (UIntPtr)41; + Assert.Equal((UIntPtr)41, i); + } + + [Fact] + public static void MaxValue() + { + Assert.Equal(UIntPtr.Size == 4 ? (UIntPtr)uint.MaxValue : (UIntPtr)ulong.MaxValue, UIntPtr.MaxValue); + } + + [Fact] + public static void MinValue() + { + Assert.Equal((UIntPtr)0, UIntPtr.MinValue); + } + + [Theory] + [InlineData(234u, 234u, 0)] + [InlineData(234u, uint.MinValue, 1)] + [InlineData(234u, 123u, 1)] + [InlineData(234u, 456u, -1)] + [InlineData(234u, uint.MaxValue, -1)] + [InlineData(234u, null, 1)] + public static void CompareTo_Other_ReturnsExpected(uint i0, object value, int expected) + { + var i = (UIntPtr)i0; + if (value is uint uintValue) + { + var uintPtrValue = (UIntPtr)uintValue; + Assert.Equal(expected, Math.Sign(i.CompareTo(uintPtrValue))); + + Assert.Equal(expected, Math.Sign(i.CompareTo((object)uintPtrValue))); + } + else + { + Assert.Equal(expected, Math.Sign(i.CompareTo(value))); + } + } + + [Theory] + [InlineData("a")] + [InlineData(234)] + public static void CompareTo_ObjectNotUIntPtr_ThrowsArgumentException(object value) + { + AssertExtensions.Throws(null, () => ((UIntPtr)123).CompareTo(value)); + } + + public static IEnumerable ToString_TestData() + { + foreach (NumberFormatInfo defaultFormat in new[] { null, NumberFormatInfo.CurrentInfo }) + { + foreach (string defaultSpecifier in new[] { "G", "G\0", "\0N222", "\0", "" }) + { + yield return new object[] { (UIntPtr)0, defaultSpecifier, defaultFormat, "0" }; + yield return new object[] { (UIntPtr)4567, defaultSpecifier, defaultFormat, "4567" }; + yield return new object[] { UIntPtr.MaxValue, defaultSpecifier, defaultFormat, Is64Bit ? "18446744073709551615" : "4294967295" }; + } + + yield return new object[] { (UIntPtr)4567, "D", defaultFormat, "4567" }; + yield return new object[] { (UIntPtr)4567, "D18", defaultFormat, "000000000000004567" }; + + yield return new object[] { (UIntPtr)0x2468, "x", defaultFormat, "2468" }; + yield return new object[] { (UIntPtr)2468, "N", defaultFormat, string.Format("{0:N}", 2468.00) }; + } + + var customFormat = new NumberFormatInfo() + { + NegativeSign = "#", + NumberDecimalSeparator = "~", + NumberGroupSeparator = "*", + PositiveSign = "&", + NumberDecimalDigits = 2, + PercentSymbol = "@", + PercentGroupSeparator = ",", + PercentDecimalSeparator = ".", + PercentDecimalDigits = 5 + }; + yield return new object[] { (UIntPtr)2468, "N", customFormat, "2*468~00" }; + yield return new object[] { (UIntPtr)123, "E", customFormat, "1~230000E&002" }; + yield return new object[] { (UIntPtr)123, "F", customFormat, "123~00" }; + yield return new object[] { (UIntPtr)123, "P", customFormat, "12,300.00000 @" }; + } + + [Theory] + [MemberData(nameof(ToString_TestData))] + public static void ToStringTest(UIntPtr i, string format, IFormatProvider provider, string expected) + { + // Format is case insensitive + string upperFormat = format.ToUpperInvariant(); + string lowerFormat = format.ToLowerInvariant(); + + string upperExpected = expected.ToUpperInvariant(); + string lowerExpected = expected.ToLowerInvariant(); + + bool isDefaultProvider = (provider == null || provider == NumberFormatInfo.CurrentInfo); + if (string.IsNullOrEmpty(format) || format.ToUpperInvariant() == "G") + { + if (isDefaultProvider) + { + Assert.Equal(upperExpected, i.ToString()); + Assert.Equal(upperExpected, i.ToString((IFormatProvider)null)); + } + Assert.Equal(upperExpected, i.ToString(provider)); + } + if (isDefaultProvider) + { + Assert.Equal(upperExpected, i.ToString(upperFormat)); + Assert.Equal(lowerExpected, i.ToString(lowerFormat)); + Assert.Equal(upperExpected, i.ToString(upperFormat, null)); + Assert.Equal(lowerExpected, i.ToString(lowerFormat, null)); + } + Assert.Equal(upperExpected, i.ToString(upperFormat, provider)); + Assert.Equal(lowerExpected, i.ToString(lowerFormat, provider)); + } + + [Fact] + public static void ToString_InvalidFormat_ThrowsFormatException() + { + UIntPtr i = (UIntPtr)123; + Assert.Throws(() => i.ToString("r")); // Invalid format + Assert.Throws(() => i.ToString("r", null)); // Invalid format + Assert.Throws(() => i.ToString("R")); // Invalid format + Assert.Throws(() => i.ToString("R", null)); // Invalid format + Assert.Throws(() => i.ToString("Y")); // Invalid format + Assert.Throws(() => i.ToString("Y", null)); // Invalid format + } + + public static IEnumerable Parse_Valid_TestData() + { + // Reuse all IntPtr test data that's relevant + foreach (object[] objs in IntPtrTests.Parse_Valid_TestData()) + { + if ((long)(IntPtr)objs[3] < 0) continue; + var intPtr = (IntPtr)objs[3]; + yield return new object[] { objs[0], objs[1], objs[2], Unsafe.As(ref intPtr) }; + } + + // All lengths decimal + { + string s = ""; + uint result = 0; + for (int i = 1; i <= 10; i++) + { + result = (uint)(result * 10 + (i % 10)); + s += (i % 10).ToString(); + yield return new object[] { s, NumberStyles.Integer, null, (UIntPtr)result }; + } + } + + // All lengths hexadecimal + { + string s = ""; + uint result = 0; + for (uint i = 1; i <= 8; i++) + { + result = ((result * 16) + (i % 16)); + s += (i % 16).ToString("X"); + yield return new object[] { s, NumberStyles.HexNumber, null, result }; + } + } + + // And test boundary conditions for IntPtr + yield return new object[] { Is64Bit ? "18446744073709551615" : "4294967295", NumberStyles.Integer, null, UIntPtr.MaxValue }; + yield return new object[] { Is64Bit ? "+18446744073709551615" : "+4294967295", NumberStyles.Integer, null, UIntPtr.MaxValue }; + yield return new object[] { Is64Bit ? " +18446744073709551615 " : " +4294967295 ", NumberStyles.Integer, null, UIntPtr.MaxValue }; + yield return new object[] { Is64Bit ? "FFFFFFFFFFFFFFFF" : "FFFFFFFF", NumberStyles.HexNumber, null, UIntPtr.MaxValue }; + yield return new object[] { Is64Bit ? " FFFFFFFFFFFFFFFF " : " FFFFFFFF ", NumberStyles.HexNumber, null, UIntPtr.MaxValue }; + } + + [Theory] + [MemberData(nameof(Parse_Valid_TestData))] + public static void Parse_Valid(string value, NumberStyles style, IFormatProvider provider, UIntPtr expected) + { + UIntPtr result; + + // Default style and provider + if (style == NumberStyles.Integer && provider == null) + { + Assert.True(UIntPtr.TryParse(value, out result)); + Assert.Equal(expected, result); + Assert.Equal(expected, UIntPtr.Parse(value)); + } + + // Default provider + if (provider == null) + { + Assert.Equal(expected, UIntPtr.Parse(value, style)); + + // Substitute default NumberFormatInfo + Assert.True(UIntPtr.TryParse(value, style, new NumberFormatInfo(), out result)); + Assert.Equal(expected, result); + Assert.Equal(expected, UIntPtr.Parse(value, style, new NumberFormatInfo())); + } + + // Default style + if (style == NumberStyles.Integer) + { + Assert.Equal(expected, UIntPtr.Parse(value, provider)); + } + + // Full overloads + Assert.True(UIntPtr.TryParse(value, style, provider, out result)); + Assert.Equal(expected, result); + Assert.Equal(expected, UIntPtr.Parse(value, style, provider)); + } + + public static IEnumerable Parse_Invalid_TestData() + { + // > max value + yield return new object[] { "18446744073709551616", NumberStyles.Integer, null, typeof(OverflowException) }; + yield return new object[] { "10000000000000000", NumberStyles.HexNumber, null, typeof(OverflowException) }; + } + + [Theory] + [MemberData(nameof(Parse_Invalid_TestData))] + public static void Parse_Invalid(string value, NumberStyles style, IFormatProvider provider, Type exceptionType) + { + UIntPtr result; + + // Default style and provider + if (style == NumberStyles.Integer && provider == null) + { + Assert.False(UIntPtr.TryParse(value, out result)); + Assert.Equal(default, result); + Assert.Throws(exceptionType, () => UIntPtr.Parse(value)); + } + + // Default provider + if (provider == null) + { + Assert.Throws(exceptionType, () => UIntPtr.Parse(value, style)); + + // Substitute default NumberFormatInfo + Assert.False(UIntPtr.TryParse(value, style, new NumberFormatInfo(), out result)); + Assert.Equal(default, result); + Assert.Throws(exceptionType, () => UIntPtr.Parse(value, style, new NumberFormatInfo())); + } + + // Default style + if (style == NumberStyles.Integer) + { + Assert.Throws(exceptionType, () => UIntPtr.Parse(value, provider)); + } + + // Full overloads + Assert.False(UIntPtr.TryParse(value, style, provider, out result)); + Assert.Equal(default, result); + Assert.Throws(exceptionType, () => UIntPtr.Parse(value, style, provider)); + } + + [Theory] + [InlineData(NumberStyles.HexNumber | NumberStyles.AllowParentheses, null)] + [InlineData(unchecked((NumberStyles)0xFFFFFC00), "style")] + public static void TryParse_InvalidNumberStyle_ThrowsArgumentException(NumberStyles style, string paramName) + { + UIntPtr result = (UIntPtr)0; + AssertExtensions.Throws(paramName, () => UIntPtr.TryParse("1", style, null, out result)); + Assert.Equal(default(UIntPtr), result); + + AssertExtensions.Throws(paramName, () => UIntPtr.Parse("1", style)); + AssertExtensions.Throws(paramName, () => UIntPtr.Parse("1", style, null)); + } + + public static IEnumerable Parse_ValidWithOffsetCount_TestData() + { + foreach (object[] inputs in Parse_Valid_TestData()) + { + yield return new object[] { inputs[0], 0, ((string)inputs[0]).Length, inputs[1], inputs[2], inputs[3] }; + } + + yield return new object[] { "123", 0, 2, NumberStyles.Integer, null, (UIntPtr)12 }; + yield return new object[] { "123", 1, 2, NumberStyles.Integer, null, (UIntPtr)23 }; + yield return new object[] { "4294967295", 0, 1, NumberStyles.Integer, null, 4 }; + yield return new object[] { "4294967295", 9, 1, NumberStyles.Integer, null, 5 }; + yield return new object[] { "12", 0, 1, NumberStyles.HexNumber, null, (UIntPtr)0x1 }; + yield return new object[] { "12", 1, 1, NumberStyles.HexNumber, null, (UIntPtr)0x2 }; + yield return new object[] { "$1,000", 1, 3, NumberStyles.Currency, new NumberFormatInfo() { CurrencySymbol = "$" }, (UIntPtr)10 }; + } } } diff --git a/src/libraries/System.Runtime/tests/System/Uri.MethodsTests.cs b/src/libraries/System.Runtime/tests/System/Uri.MethodsTests.cs index 444aca48cfa63f..f2bb8db383081c 100644 --- a/src/libraries/System.Runtime/tests/System/Uri.MethodsTests.cs +++ b/src/libraries/System.Runtime/tests/System/Uri.MethodsTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Runtime.InteropServices; using Xunit; @@ -389,15 +390,17 @@ public static IEnumerable Equals_TestData() public void EqualsTest(Uri uri1, object obj, bool expected) { Uri uri2 = obj as Uri; + if (uri1 != null) { Assert.Equal(expected, uri1.Equals(obj)); - if (uri2 != null) + + if (uri2 != null && expected) { - bool onlyCaseDifference = string.Equals(uri1.OriginalString, uri2.OriginalString, StringComparison.OrdinalIgnoreCase); - Assert.Equal(expected || onlyCaseDifference, uri1.GetHashCode().Equals(uri2.GetHashCode())); + Assert.Equal(uri1.GetHashCode(), uri2.GetHashCode()); } } + if (!(obj is string)) { Assert.Equal(expected, uri1 == uri2); @@ -536,7 +539,7 @@ public static IEnumerable GetComponents_Basic_TestData() Uri invalidPunicodeUri = new Uri("http://xn--\u1234pck.com"); yield return new object[] { invalidPunicodeUri, UriComponents.Host, "xn--\u1234pck.com" }; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // expected platform differences, see https://github.com/dotnet/runtime/issues/17190 + if (PlatformDetection.IsNlsGlobalization) // expected platform differences, see https://github.com/dotnet/runtime/issues/17190 { yield return new object[] { invalidPunicodeUri, UriComponents.NormalizedHost, "xn--\u1234pck.com" }; } diff --git a/src/libraries/System.Security.AccessControl/ref/System.Security.AccessControl.csproj b/src/libraries/System.Security.AccessControl/ref/System.Security.AccessControl.csproj index de3bd911227bb9..d5c601747004d8 100644 --- a/src/libraries/System.Security.AccessControl/ref/System.Security.AccessControl.csproj +++ b/src/libraries/System.Security.AccessControl/ref/System.Security.AccessControl.csproj @@ -1,21 +1,24 @@ - true $(NetCoreAppCurrent);netstandard2.0;net461;$(NetFrameworkCurrent) true true enable + + + true + - + - + - + diff --git a/src/libraries/System.Security.AccessControl/src/System.Security.AccessControl.csproj b/src/libraries/System.Security.AccessControl/src/System.Security.AccessControl.csproj index 4d82b1a50595d9..5218ab9aa1ae9d 100644 --- a/src/libraries/System.Security.AccessControl/src/System.Security.AccessControl.csproj +++ b/src/libraries/System.Security.AccessControl/src/System.Security.AccessControl.csproj @@ -1,17 +1,20 @@ true - true - SR.PlatformNotSupported_AccessControl $(NetCoreAppCurrent)-Windows_NT;net461-Windows_NT;netcoreapp2.0-Windows_NT;netstandard2.0;$(NetFrameworkCurrent)-Windows_NT true true enable - + + + true + SR.PlatformNotSupported_AccessControl + + - + @@ -26,92 +29,66 @@ - - Common\System\NotImplemented.cs - - - Microsoft\Win32\SafeHandles\SafeTokenHandle.cs - - - Common\Interop\Interop.Libraries.cs - - - Common\Interop\Interop.LUID.cs - - - Common\Interop\Interop.LUID_AND_ATTRIBUTES.cs - - - Common\Interop\Interop.TOKEN_PRIVILEGE.cs - - - Common\Interop\Interop.SecurityImpersonationLevel.cs - - - Common\Interop\Interop.Errors.cs - - - Common\Interop\Interop.ProcessOptions.cs - - - Common\Interop\Interop.LookupPrivilegeValue.cs - - - Common\Interop\Interop.RevertToSelf.cs - - - Common\Interop\Interop.ConvertSdToStringSd.cs - - - Common\Interop\Interop.ConvertStringSdToSd.cs - - - Common\Interop\Interop.GetSecurityInfoByHandle.cs - - - Common\Interop\Interop.SetSecurityInfoByHandle.cs - - - Common\Interop\Interop.GetSecurityInfoByName.cs - - - Common\Interop\Interop.SetSecurityInfoByName.cs - - - Common\Interop\Interop.GetSecurityDescriptorLength.cs - - - Common\Interop\Interop.CloseHandle.cs - - - Common\Interop\Interop.OpenThreadToken_SafeTokenHandle.cs - - - Common\Interop\Interop.OpenProcessToken_IntPtrs.cs - - - Common\Interop\Interop.GetCurrentProcess_IntPtr.cs - - - Common\Interop\Interop.SetThreadToken.cs - - - Common\Interop\Interop.GetCurrentThread.cs - - - Common\Interop\Interop.AdjustTokenPrivileges.cs - - - Common\Interop\Interop.DuplicateTokenEx_SafeTokenHandle.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + @@ -120,4 +97,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Security.AccessControl/src/System/Security/AccessControl/CommonObjectSecurity.cs b/src/libraries/System.Security.AccessControl/src/System/Security/AccessControl/CommonObjectSecurity.cs index 1ff7c7c416486d..a1665aa92070c7 100644 --- a/src/libraries/System.Security.AccessControl/src/System/Security/AccessControl/CommonObjectSecurity.cs +++ b/src/libraries/System.Security.AccessControl/src/System/Security/AccessControl/CommonObjectSecurity.cs @@ -336,7 +336,7 @@ protected override bool ModifyAccess(AccessControlModification modification, Acc else { Debug.Fail("rule.AccessControlType unrecognized"); - throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, (int)rule.AccessControlType), "rule.AccessControlType"); + throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, (int)rule.AccessControlType), nameof(rule)); } modified = result; diff --git a/src/libraries/System.Security.Claims/src/ILLinkTrim.xml b/src/libraries/System.Security.Claims/src/ILLinkTrim_LibraryBuild.xml similarity index 100% rename from src/libraries/System.Security.Claims/src/ILLinkTrim.xml rename to src/libraries/System.Security.Claims/src/ILLinkTrim_LibraryBuild.xml diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/Helpers.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/Helpers.cs index 5ca3a10cf788f3..1d3c1db2b877c5 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/Helpers.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/Helpers.cs @@ -39,21 +39,6 @@ public static byte[] GenerateRandom(int count) return buffer; } - // encodes the integer i into a 4-byte array, in big endian. - public static void WriteInt(uint i, byte[] arr, int offset) - { - unchecked - { - Debug.Assert(arr != null); - Debug.Assert(arr.Length >= offset + sizeof(uint)); - - arr[offset] = (byte)(i >> 24); - arr[offset + 1] = (byte)(i >> 16); - arr[offset + 2] = (byte)(i >> 8); - arr[offset + 3] = (byte)i; - } - } - public static byte[] FixupKeyParity(this byte[] key) { byte[] oddParityKey = new byte[key.Length]; diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography.Algorithms/src/Resources/Strings.resx index 76aed28615e9ae..6e731527ea2328 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/Resources/Strings.resx @@ -199,10 +199,10 @@ Input string does not contain a valid encoding of the '{0}' '{1}' parameter. - The specified Characteristic2 curve parameters are not valid. Polynomial, A, B, G.X, G.Y, and Order are required. A, B, G.X, G.Y must be the same length, and the same length as Q.X, Q.Y and D if those are specified. Seed, Cofactor and Hash are optional. Other parameters are not allowed. + The specified Characteristic2 curve parameters are not valid. Polynomial, A, B, G.X, G.Y, and Order are required. A, B, G.X, G.Y must be the same length, and the same length as Q.X, Q.Y and D if those are specified. Cofactor is required. Seed and Hash are optional. Other parameters are not allowed. - The specified prime curve parameters are not valid. Prime, A, B, G.X, G.Y and Order are required and must be the same length, and the same length as Q.X, Q.Y and D if those are specified. Seed, Cofactor and Hash are optional. Other parameters are not allowed. + The specified prime curve parameters are not valid. Prime, A, B, G.X, G.Y and Order are required and must be the same length, and the same length as Q.X, Q.Y and D if those are specified. Cofactor is required. Seed and Hash are optional. Other parameters are not allowed. The specified named curve parameters are not valid. Only the Oid parameter must be set. diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj b/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj index 485f96ce4cf4a8..da598436fea91c 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj @@ -86,69 +86,48 @@ - - Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs - - - Internal\Cryptography\BasicSymmetricCipher.cs - - - Internal\Cryptography\Helpers.cs - - - Internal\Cryptography\HashProvider.cs - - - Common\Internal\Cryptography\PemKeyImportHelpers.cs - - - Internal\Cryptography\UniversalCryptoTransform.cs - - - Internal\Cryptography\UniversalCryptoEncryptor.cs - - - Internal\Cryptography\UniversalCryptoDecryptor.cs - - - Common\System\Memory\PointerMemoryManager.cs - - - Common\System\Security\Cryptography\CryptoPool.cs - - - Common\System\Security\Cryptography\DSAKeyFormatHelper.cs - - - Common\System\Security\Cryptography\EccKeyFormatHelper.cs - - - Common\System\Security\Cryptography\KeyBlobHelpers.cs - - - Common\System\Security\Cryptography\KeyFormatHelper.cs - - - Common\System\Security\Cryptography\KeySizeHelpers.cs - - - Common\System\Security\Cryptography\Oids.cs - - - Common\System\Security\Cryptography\PasswordBasedEncryption.cs - - - Common\System\Security\Cryptography\PemLabels.cs - - - Common\System\Security\Cryptography\Pkcs12Kdf.cs - - - Common\System\Security\Cryptography\RSAKeyFormatHelper.cs - - - Common\System\Security\Cryptography\RsaPaddingProcessor.cs - + + + + + + + + + + + + + + + + + + + + + Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml @@ -306,294 +285,200 @@ - - Internal\Cryptography\BasicSymmetricCipherBCrypt.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\BCrypt\AesBCryptModes.cs - - - Common\Interop\Windows\BCrypt\Cng.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptImportKey.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptEncryptDecrypt.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptGenRandom.cs - - - Common\Interop\Windows\BCrypt\Interop.NTSTATUS.cs - - - Common\Interop\Windows\BCrypt\Interop.AsymmetricEncryption.Types.cs - - - Common\Interop\Windows\BCrypt\Interop.Blobs.cs - - - Common\Interop\Windows\BCrypt\Interop.CreateCryptographicException.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptOpenAlgorithmProvider.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptCloseAlgorithmProvider.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptDestroyHash.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptCreateHash.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptHashData.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptFinishHash.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptGetProperty.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptPropertyStrings.cs - - - Internal\Windows\NCrypt\Interop.NCryptDeriveKeyMaterial.cs - - - Internal\Windows\NCrypt\Interop.NCryptDeriveSecretAgreement.cs - - - Internal\Windows\NCrypt\Interop.NCryptBuffer.cs - - - Internal\Windows\BCrypt\BCryptAlgorithmCache.cs - - - Common\Interop\Windows\BCrypt\DESBCryptModes.cs - - - Common\Interop\Windows\BCrypt\RC2BCryptModes.cs - - - Common\Interop\Windows\BCrypt\TripleDesBCryptModes.cs - - - Common\Interop\Windows\Crypt32\Interop.FindOidInfo.cs - - - Common\Interop\Windows\Crypt32\Interop.HashIdAlg.cs - - - Common\Interop\Windows\NCrypt\Interop.AsymmetricPaddingMode.cs - - - Common\Interop\Windows\NCrypt\Interop.ErrorCode.cs - - - Common\Interop\Windows\NCrypt\Interop.EncryptDecrypt.cs - - - Common\Interop\Windows\NCrypt\Interop.Keys.cs - - - Common\Interop\Windows\NCrypt\Interop.NCryptFreeObject.cs - - - Common\Interop\Windows\NCrypt\Interop.NCryptOpenStorageProvider.cs - - - Common\Interop\Windows\NCrypt\Interop.ErrorCode.cs - - - Common\Interop\Windows\NCrypt\Interop.SignVerify.cs - - - Microsoft\Win32\SafeHandles\SafeBCryptHandle.cs - - - Microsoft\Win32\SafeHandles\SafeBCryptAlgorithmHandle.cs - - - Microsoft\Win32\SafeHandles\SafeBCryptHashHandle.cs - - - Microsoft\Win32\SafeHandles\SafeUnicodeStringHandle.cs - - - Internal\Cryptography\CngCommon.Hash.cs - - - Internal\Cryptography\CngCommon.SignVerify.cs - - - Internal\Cryptography\HashProviderCng.cs - - - Internal\Cryptography\Windows\CryptoThrowHelper.cs - - - Internal\Cryptography\Windows\ErrorCodeHelper.cs - - - Internal\Windows\kernel32\Interop.FormatMessage.cs - - - Common\System\Security\Cryptography\CngPkcs8.cs - - - Common\System\Security\Cryptography\DSACng.cs - - - Common\System\Security\Cryptography\DSACng.ImportExport.cs - - - Common\System\Security\Cryptography\DSACng.SignVerify.cs - - - Common\System\Security\Cryptography\ECCng.HashAlgorithm.cs - - - Common\System\Security\Cryptography\ECCng.ImportExport.cs - - - Common\System\Security\Cryptography\ECDsaCng.cs - - - Common\System\Security\Cryptography\ECDsaCng.ImportExport.cs - - - Common\System\Security\Cryptography\ECDsaCng.cs - - - Common\System\Security\Cryptography\ECDsaCng.HashData.cs - - - Common\System\Security\Cryptography\ECDsaCng.ImportExport.cs - - - Common\System\Security\Cryptography\ECDsaCng.SignVerify.cs - - - Common\System\Security\Cryptography\RSACng.cs - - - Common\System\Security\Cryptography\RSACng.EncryptDecrypt.cs - - - Common\System\Security\Cryptography\RSACng.ImportExport.cs - - - Common\System\Security\Cryptography\RSACng.SignVerify.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ASN1.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ASN1.Nid.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Bignum.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EcDsa.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Dsa.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EcDsa.ImportExport.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EcKey.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.EcKey.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Ecdh.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Hmac.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.RAND.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Rsa.cs - - - Common\Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeBignumHandle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeDsaHandle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeEcKeyHandle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeEvpMdCtxHandle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeEvpPkeyCtxHandle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeHmacCtxHandle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeInteriorHandle.cs - - - Common\Microsoft\Win32\SafeHandles\SafeEvpPKeyHandle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeRsaHandle.Unix.cs - - - Common\System\Security\Cryptography\DSAOpenSsl.cs - - - Common\System\Security\Cryptography\ECDiffieHellmanOpenSsl.cs - - - Common\System\Security\Cryptography\ECDiffieHellmanOpenSsl.Derive.cs - - - Common\System\Security\Cryptography\ECDiffieHellmanOpenSslPublicKey.cs - - - Common\System\Security\Cryptography\ECDsaOpenSsl.cs - - - Common\System\Security\Cryptography\ECOpenSsl.cs - - - Common\System\Security\Cryptography\ECOpenSsl.ImportExport.cs - - - Common\System\Security\Cryptography\RSAOpenSsl.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + @@ -602,90 +487,62 @@ - - Common\Interop\OSX\Interop.CoreFoundation.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFArray.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFData.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFError.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFString.cs - - - Common\Interop\OSX\Interop.Libraries.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Digest.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Ecc.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Err.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Hmac.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.KeyAgree.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Keychain.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.PAL_HashAlgorithm.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Random.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.RSA.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.SecErr.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.SecErrMessage.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.SecKeyRef.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.SecKeyRef.Export.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Symmetric.cs - - - Common\Microsoft\Win32\SafeHandles\SafeCreateHandle.OSX.cs - - - Common\Microsoft\Win32\SafeHandles\SafeHandleCache.cs - - - Common\System\Security\Cryptography\DSASecurityTransforms.cs - - - Common\System\Security\Cryptography\EccSecurityTransforms.cs - - - Common\System\Security\Cryptography\ECDiffieHellmanSecurityTransforms.cs - - - Common\System\Security\Cryptography\ECDsaSecurityTransforms.cs - - - Common\System\Security\Cryptography\RSASecurityTransforms.cs - - - Common\System\Security\Cryptography\SecKeyPair.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -696,27 +553,20 @@ - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.Cipher.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Initialization.cs - - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Hash.cs - - - Common\Microsoft\Win32\SafeHandles\SafeEvpCipherCtxHandle.Unix.cs - - - Common\System\Security\Cryptography\ECDiffieHellmanDerivation.cs - + + + + + + + diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CryptoConfig.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CryptoConfig.cs index 3d9583c02f76f5..3614db56554898 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CryptoConfig.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CryptoConfig.cs @@ -38,8 +38,6 @@ public class CryptoConfig private static readonly ConcurrentDictionary appNameHT = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); private static readonly ConcurrentDictionary appOidHT = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - private static readonly char[] SepArray = { '.' }; // valid ASN.1 separators - // .NET Core does not support AllowOnlyFipsAlgorithms public static bool AllowOnlyFipsAlgorithms => false; @@ -503,7 +501,7 @@ public static byte[] EncodeOID(string str) if (str == null) throw new ArgumentNullException(nameof(str)); - string[] oidString = str.Split(SepArray); + string[] oidString = str.Split('.'); // valid ASN.1 separator uint[] oidNums = new uint[oidString.Length]; for (int i = 0; i < oidString.Length; i++) { diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DES.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DES.cs index 443cc84d79b757..8ad67820c8fde1 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DES.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DES.cs @@ -4,6 +4,7 @@ using Internal.Cryptography; using System.ComponentModel; +using System.Buffers.Binary; namespace System.Security.Cryptography { @@ -65,7 +66,7 @@ public static bool IsWeakKey(byte[] rgbKey) throw new CryptographicException(SR.Cryptography_InvalidKeySize); byte[] rgbOddParityKey = rgbKey.FixupKeyParity(); - ulong key = QuadWordFromBigEndian(rgbOddParityKey); + ulong key = BinaryPrimitives.ReadUInt64BigEndian(rgbOddParityKey); if ((key == 0x0101010101010101) || (key == 0xfefefefefefefefe) || (key == 0x1f1f1f1f0e0e0e0e) || @@ -83,7 +84,7 @@ public static bool IsSemiWeakKey(byte[] rgbKey) throw new CryptographicException(SR.Cryptography_InvalidKeySize); byte[] rgbOddParityKey = rgbKey.FixupKeyParity(); - ulong key = QuadWordFromBigEndian(rgbOddParityKey); + ulong key = BinaryPrimitives.ReadUInt64BigEndian(rgbOddParityKey); if ((key == 0x01fe01fe01fe01fe) || (key == 0xfe01fe01fe01fe01) || (key == 0x1fe01fe00ef10ef1) || @@ -111,17 +112,6 @@ private static bool IsLegalKeySize(byte[]? rgbKey) return false; } - private static ulong QuadWordFromBigEndian(byte[] block) - { - ulong x = ( - (((ulong)block[0]) << 56) | (((ulong)block[1]) << 48) | - (((ulong)block[2]) << 40) | (((ulong)block[3]) << 32) | - (((ulong)block[4]) << 24) | (((ulong)block[5]) << 16) | - (((ulong)block[6]) << 8) | ((ulong)block[7]) - ); - return x; - } - private static readonly KeySizes[] s_legalBlockSizes = { new KeySizes(minSize: 64, maxSize: 64, skipSize: 0) diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.Xml.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.Xml.cs index cfa242d50fb96c..f32e384c70e94a 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.Xml.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.Xml.cs @@ -127,10 +127,12 @@ public override string ToXmlString(bool includePrivateParameters) { if (keyParameters.X == null) { +#pragma warning disable CA2208 // Instantiate argument exceptions correctly // .NET Framework compat when a 3rd party type lets X be null when // includePrivateParameters is true // (the exception would have been from Convert.ToBase64String) throw new ArgumentNullException("inArray"); +#pragma warning restore CA2208 } XmlKeyHelper.WriteCryptoBinary(nameof(DSAParameters.X), keyParameters.X, builder); diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs index 61c4fa1bd8dc6b..42c67d78f91b8d 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Buffers; +using System.Buffers.Binary; using System.Text; using System.Diagnostics; @@ -258,7 +259,7 @@ private void Initialize() // where i is the block number. private void Func() { - Helpers.WriteInt(_block, _salt, _salt.Length - sizeof(uint)); + BinaryPrimitives.WriteUInt32BigEndian(_salt.AsSpan(_salt.Length - sizeof(uint)), _block); Debug.Assert(_blockSize == _buffer.Length); // The biggest _blockSize we have is from SHA512, which is 64 bytes. diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/XmlKeyHelper.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/XmlKeyHelper.cs index 9012886b3ed084..a8d3460c1369bb 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/XmlKeyHelper.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/XmlKeyHelper.cs @@ -267,12 +267,12 @@ private static class Functions { private static readonly Type s_xDocument = Type.GetType("System.Xml.Linq.XDocument, System.Private.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51")!; private static readonly Func s_xDocumentCreate = - (Func)s_xDocument.GetMethod( + s_xDocument.GetMethod( "Parse", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string) }, - null)!.CreateDelegate(typeof(Func)); + null)!.CreateDelegate>(); private static readonly PropertyInfo s_docRootProperty = s_xDocument.GetProperty("Root")!; private static readonly MethodInfo s_getElementsMethod = s_docRootProperty.PropertyType.GetMethod( "Elements", diff --git a/src/libraries/System.Security.Cryptography.Algorithms/tests/BlockSizeValueTests.cs b/src/libraries/System.Security.Cryptography.Algorithms/tests/BlockSizeValueTests.cs index 775ecf486145db..b0c2351424b9b2 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/tests/BlockSizeValueTests.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/tests/BlockSizeValueTests.cs @@ -9,23 +9,44 @@ namespace System.Security.Cryptography.Hashing.Algorithms.Tests { public class BlockSizeValueTests { - public static IEnumerable GetBlockSizeValue() + [Fact] + public static void BlockSizeValueTest_HMACMD5() { - return new[] - { - new object[] { new HMACMD5Test().GetBlockSizeValue(), 64 }, - new object[] { new HMACSHA1Test().GetBlockSizeValue(), 64 }, - new object[] { new HMACSHA256Test().GetBlockSizeValue(), 64 }, - new object[] { new HMACSHA384Test().GetBlockSizeValue(), 128 }, - new object[] { new HMACSHA512Test().GetBlockSizeValue(), 128 }, - }; + int hmacBlockSizeValue = new HMACMD5Test().GetBlockSizeValue(); + const int ExpectedBlockSize = 64; + Assert.Equal(ExpectedBlockSize, hmacBlockSizeValue); } - [Theory] - [MemberData(nameof(GetBlockSizeValue))] - public static void BlockSizeValueTest(int hmacBlockSizeValue, int expectedBlockSizeValue) + [Fact] + public static void BlockSizeValueTest_HMACSHA1() { - Assert.Equal(expectedBlockSizeValue, hmacBlockSizeValue); + int hmacBlockSizeValue = new HMACSHA1Test().GetBlockSizeValue(); + const int ExpectedBlockSize = 64; + Assert.Equal(ExpectedBlockSize, hmacBlockSizeValue); + } + + [Fact] + public static void BlockSizeValueTest_HMACSHA256() + { + int hmacBlockSizeValue = new HMACSHA256Test().GetBlockSizeValue(); + const int ExpectedBlockSize = 64; + Assert.Equal(ExpectedBlockSize, hmacBlockSizeValue); + } + + [Fact] + public static void BlockSizeValueTest_HMACSHA384() + { + int hmacBlockSizeValue = new HMACSHA384Test().GetBlockSizeValue(); + const int ExpectedBlockSize = 128; + Assert.Equal(ExpectedBlockSize, hmacBlockSizeValue); + } + + [Fact] + public static void BlockSizeValueTest_HMACSHA512() + { + int hmacBlockSizeValue = new HMACSHA512Test().GetBlockSizeValue(); + const int ExpectedBlockSize = 128; + Assert.Equal(ExpectedBlockSize, hmacBlockSizeValue); } } diff --git a/src/libraries/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj b/src/libraries/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj index 8b648f3cc436c2..5f3e261e923027 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj @@ -3,99 +3,68 @@ $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix - - CommonTest\System\IO\PositionValueStream.cs - - - CommonTest\System\RandomDataGenerator.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\AES\AesCipherTests.Data.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\AES\AesCipherTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\AES\AesContractTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\AES\AesCornerTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\AES\AesModeTests.cs - - - CommonTest\System\Security\Cryptography\ByteUtils.cs - - - CommonTest\System\Security\Cryptography\CryptoUtils.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\AES\DecryptorReusability.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\AES\AesFactory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\CurveDef.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestBase.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestData.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaFactory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaImportExport.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaSignatureFormatTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaStub.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTests.NistValidation.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTestsBase.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\EncryptDecrypt.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\ImportExport.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\KeyGeneration.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAFactory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAXml.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\SignVerify.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\TestData.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\TripleDES\TripleDESCipherTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\TripleDES\TripleDESFactory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\TripleDES\TripleDESReusabilityTests.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -125,76 +94,56 @@ - + - - Common\Interop\Unix\Interop.Libraries.cs - + - + - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyFileTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyPemTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyFileTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyFileTests.LimitedPrivate.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyPemTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDhKeyFileTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanKeyPemTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanFactory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hash.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hmac.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.ImportExport.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.NistValidation.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Tls.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Xml.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyFileTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyPemTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyFileTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyPemTests.cs - + + + + + + + + + + + + + + + + + + + @@ -224,75 +173,52 @@ - - CommonTest\System\Security\Cryptography\AsymmetricSignatureFormatter.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DES\DESCipherTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DES\DESFactory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DES\DesTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAFactory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DsaFamilySignatureFormatTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatter.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAImportExport.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyGeneration.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignVerify.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignVerify.NistValidation.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSATestData.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAXml.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTests.netcoreapp.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaXml.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RC2\RC2CipherTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RC2\RC2Factory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RC2\RC2Tests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\EncryptDecrypt.netcoreapp.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyExchangeFormatter.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSASignatureFormatter.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\SignVerify.netcoreapp.cs - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.csproj b/src/libraries/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.csproj index 4459f6064d5f07..6650cbce60e9d9 100644 --- a/src/libraries/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.csproj +++ b/src/libraries/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.csproj @@ -1,16 +1,19 @@ - $(DefineConstants);FEATURE_ECPARAMETERS - - $(DefineConstants);FEATURE_DSA_HASHDATA - - $(DefineConstants);FEATURE_ECDH_DERIVEFROM - true - netcoreapp3.0;netstandard2.1;net461;net462;net47;$(NetCoreAppCurrent);$(NetFrameworkCurrent) + $(NetCoreAppCurrent);netcoreapp3.0;netstandard2.1;net461;net462;net47;$(NetFrameworkCurrent) true true enable + + + + $(DefineConstants);FEATURE_DSA_HASHDATA + + $(DefineConstants);FEATURE_ECDH_DERIVEFROM + $(DefineConstants);FEATURE_ECPARAMETERS + true + @@ -30,4 +33,4 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj b/src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj index 0aae024d50dde9..046835f221bc72 100644 --- a/src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj +++ b/src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj @@ -2,14 +2,17 @@ true $(NoWarn);CS1573;CS3016;CA5379 - true - true true $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent);netstandard2.0;netstandard2.1;net461-Windows_NT;netcoreapp3.0-Windows_NT;netcoreapp3.0;net462-Windows_NT;net47-Windows_NT;$(NetFrameworkCurrent)-Windows_NT true true enable + + + true + true + SR.PlatformNotSupported_CryptographyCng 4.3.0.0 @@ -70,249 +73,168 @@ - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\BCrypt\AesBCryptModes.cs - - - Common\Interop\Windows\BCrypt\Cng.cs - - - Interop\Windows\BCrypt\Interop.BCryptImportKey.cs - - - Interop\Windows\BCrypt\Interop.BCryptEncryptDecrypt.cs - - - Common\Interop\Windows\BCrypt\Interop.NTSTATUS.cs - - - Common\Interop\Windows\BCrypt\Interop.AsymmetricEncryption.Types.cs - - - Common\Interop\Windows\BCrypt\Interop.Blobs.cs - - - Common\Interop\Windows\BCrypt\Interop.CreateCryptographicException.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptOpenAlgorithmProvider.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptCloseAlgorithmProvider.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptDestroyHash.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptCreateHash.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptHashData.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptFinishHash.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptGetProperty.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptPropertyStrings.cs - - - Internal\Windows\BCrypt\BCryptAlgorithmCache.cs - - - Internal\Windows\BCrypt\Interop.BCryptChainingModes.cs - - - Internal\Windows\BCrypt\Interop.BCryptKeyDataBlob.cs - - - Common\Interop\Windows\BCrypt\TripleDesBCryptModes.cs - - - Internal\Windows\Crypt32\Interop.FindOidInfo.cs - - - Common\Interop\Windows\Crypt32\Interop.HashIdAlg.cs - - - Internal\Windows\NCrypt\Interop.AsymmetricPaddingMode.cs - - - Internal\Windows\NCrypt\Interop.EncryptDecrypt.cs - - - Internal\Windows\NCrypt\Interop.ErrorCode.cs - - - Internal\Windows\NCrypt\Interop.Keys.cs - - - Internal\Windows\NCrypt\Interop.NCryptAlgorithms.cs - - - Internal\Windows\NCrypt\Interop.NCryptFreeObject.cs - - - Internal\Windows\NCrypt\Interop.NCryptCipherKeyBlob.cs - - - Internal\Windows\NCrypt\Interop.NCryptPropertyNames.cs - - - Internal\Windows\NCrypt\Interop.NCryptOpenStorageProvider.cs - - - Internal\Windows\NCrypt\Interop.NCryptDeriveKeyMaterial.cs - - - Internal\Windows\NCrypt\Interop.NCryptDeriveSecretAgreement.cs - - - Internal\Windows\NCrypt\Interop.NCryptBuffer.cs - - - Internal\Windows\NCrypt\Interop.Properties.cs - - - Internal\Windows\NCrypt\Interop.SignVerify.cs - - - Internal\Windows\NCrypt\Interop.UiPolicy.cs - - - Internal\Windows\kernel32\Interop.FormatMessage.cs - - - Microsoft\Win32\SafeHandles\SafeBCryptHandle.cs - - - Microsoft\Win32\SafeHandles\SafeBCryptHashHandle.cs - - - Microsoft\Win32\SafeHandles\SafeBCryptAlgorithmHandle.cs - - - Microsoft\Win32\SafeHandles\SafeUnicodeStringHandle.cs - - - Internal\Cryptography\Windows\CryptoThrowHelper.cs - - - Internal\Cryptography\Windows\ErrorCodeHelper.cs - - - Internal\Cryptography\CngCommon.Hash.cs - - - Internal\Cryptography\CngCommon.SignVerify.cs - - - Internal\Cryptography\HashProvider.cs - - - Internal\Cryptography\HashProviderCng.cs - - - Internal\Cryptography\Helpers.cs - - - Internal\Cryptography\BasicSymmetricCipher.cs - - - Internal\Cryptography\BasicSymmetricCipherBCrypt.cs - - - Internal\Cryptography\UniversalCryptoTransform.cs - - - Internal\Cryptography\UniversalCryptoEncryptor.cs - - - Internal\Cryptography\UniversalCryptoDecryptor.cs - - - Common\System\Memory\PointerMemoryManager.cs - - - Common\System\Security\Cryptography\CryptoPool.cs - - - Common\System\Security\Cryptography\CngPkcs8.cs - - - Common\System\Security\Cryptography\DSACng.cs - - - Common\System\Security\Cryptography\DSACng.ImportExport.cs - - - Common\System\Security\Cryptography\DSACng.SignVerify.cs - - - Common\System\Security\Cryptography\EccKeyFormatHelper.cs - - - Common\System\Security\Cryptography\ECCng.ImportExport.cs - - - Common\System\Security\Cryptography\ECDiffieHellmanCng.cs - - - Common\System\Security\Cryptography\ECDiffieHellmanCng.ImportExport.cs - - - Common\System\Security\Cryptography\ECDsaCng.ImportExport.cs - - - Common\System\Security\Cryptography\ECCng.HashAlgorithm.cs - - - Common\System\Security\Cryptography\ECDsaCng.cs - - - Common\System\Security\Cryptography\ECDsaCng.HashData.cs - - - Common\System\Security\Cryptography\ECDsaCng.SignVerify.cs - - - Common\System\Security\Cryptography\KeyBlobHelpers.cs - - - Common\System\Security\Cryptography\KeyFormatHelper.cs - - - Common\System\Security\Cryptography\KeySizeHelpers.cs - - - Common\System\Security\Cryptography\Oids.cs - - - Common\System\Security\Cryptography\PasswordBasedEncryption.cs - - - Common\System\Security\Cryptography\Pkcs12Kdf.cs - - - Common\System\Security\Cryptography\RSACng.cs - - - Common\System\Security\Cryptography\RSACng.EncryptDecrypt.cs - - - Common\System\Security\Cryptography\RSACng.ImportExport.cs - - - Common\System\Security\Cryptography\RSACng.SignVerify.cs - - - Common\System\Security\Cryptography\RsaPaddingProcessor.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml @@ -454,4 +376,4 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj b/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj index a5d72223d47015..395f9a3db84454 100644 --- a/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj @@ -15,83 +15,60 @@ - - CommonTest\AlgorithmImplementations\AES\AesCipherTests.Data.cs - - - CommonTest\AlgorithmImplementations\AES\AesCornerTests.cs - - - CommonTest\AlgorithmImplementations\AES\DecryptorReusability.cs - - - CommonTest\AlgorithmImplementations\AES\AesFactory.cs - + + + + - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\TripleDES\TripleDESFactory.cs - + - - CommonTest\System\Security\Cryptography\ByteUtils.cs - - - CommonTest\System\Security\Cryptography\CryptoUtils.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\CurveDef.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestBase.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestData.cs - + + + + + - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaFactory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaImportExport.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaStub.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTestsBase.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTests.NistValidation.cs - + + + + + + - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\EncryptDecrypt.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\ImportExport.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\KeyGeneration.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAFactory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\SignVerify.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\TestData.cs - - - CommonTest\System\IO\PositionValueStream.cs - + + + + + + + - + @@ -99,135 +76,93 @@ - - CommonTest\System\Security\Cryptography\AsymmetricSignatureFormatter.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAFactory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DsaFamilySignatureFormatTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAImportExport.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyGeneration.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyFileTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyPemTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatter.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignVerify.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSATestData.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAXml.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyFileTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyFileTests.LimitedPrivate.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\ECKeyPemTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDhKeyFileTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanKeyPemTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTests.netcoreapp.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyFileTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaKeyPemTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaSignatureFormatTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaXml.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\EncryptDecrypt.netcoreapp.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyExchangeFormatter.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyFileTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyPemTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSASignatureFormatter.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAXml.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\SignVerify.netcoreapp.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - CommonTest\AlgorithmImplementations\AES\AesContractTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\TripleDES\TripleDESCipherTests.cs - - - CommonTest\AlgorithmImplementations\AES\AesModeTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\TripleDES\TripleDESReusabilityTests.cs - - - CommonTest\AlgorithmImplementations\AES\AesCipherTests.cs - + + + + + - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanFactory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hash.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hmac.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.ImportExport.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.NistValidation.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Tls.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Xml.cs - + + + + + + + + diff --git a/src/libraries/System.Security.Cryptography.Csp/src/System.Security.Cryptography.Csp.csproj b/src/libraries/System.Security.Cryptography.Csp/src/System.Security.Cryptography.Csp.csproj index 85f5b05c2e6f6d..f495318ac1968c 100644 --- a/src/libraries/System.Security.Cryptography.Csp/src/System.Security.Cryptography.Csp.csproj +++ b/src/libraries/System.Security.Cryptography.Csp/src/System.Security.Cryptography.Csp.csproj @@ -24,12 +24,10 @@ - - Internal\Cryptography\Helpers.cs - - - Common\System\Security\Cryptography\KeySizeHelpers.cs - + + @@ -40,9 +38,8 @@ - - Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Hash.cs - + @@ -56,99 +53,68 @@ - - Internal\Cryptography\BasicSymmetricCipher.cs - - - Internal\Cryptography\UniversalCryptoTransform.cs - - - Internal\Cryptography\UniversalCryptoEncryptor.cs - - - Internal\Cryptography\UniversalCryptoDecryptor.cs - - - Internal\Cryptography\Windows\CryptoThrowHelper.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptAcquireContext.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptCreateHash.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptDecrypt.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptDeriveKey.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptDestroyHash.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptDestroyKey.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptEncrypt.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptExportKey.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptGenKey.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptGetDefaultProvider.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptGetHashParam.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptGetKeyParam.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptGetProvParam.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptGetUserKey.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptHashData.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptImportKey.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptReleaseContext.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptSetKeyParam.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptSignHash.cs - - - Common\Interop\Windows\Advapi32\SafeHashHandle.cs - - - Common\Interop\Windows\Advapi32\SafeKeyHandle.cs - - - Common\Interop\Windows\Advapi32\SafeProvHandle.cs - - - Common\Interop\Windows\Crypt32\Interop.FindOidInfo.cs - - - Common\Interop\Windows\kernel32\Interop.FormatMessage.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Microsoft\Win32\SafeHandles\SafeHandleCache.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -162,4 +128,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/CapiHelper.Windows.cs b/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/CapiHelper.Windows.cs index d4ca1674b22381..983fbd9ac26f85 100644 --- a/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/CapiHelper.Windows.cs +++ b/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/CapiHelper.Windows.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Buffers.Binary; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; @@ -20,7 +21,7 @@ namespace Internal.NativeCrypto /// internal static partial class CapiHelper { - private static readonly byte[] s_RgbPubKey = + private static ReadOnlySpan RgbPubKey => new byte[] { 0x06, 0x02, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x02, 0x00, 0x00, @@ -750,7 +751,7 @@ internal static SafeKeyHandle GetKeyPairHelper( // check that this is indeed an RSA/DSS key. byte[] algid = CapiHelper.GetKeyParameter(hKey, Constants.CLR_ALGID); - int dwAlgId = (algid[0] | (algid[1] << 8) | (algid[2] << 16) | (algid[3] << 24)); + int dwAlgId = BinaryPrimitives.ReadInt32LittleEndian(algid); if ((keyType == CspAlgorithmType.Rsa && dwAlgId != CALG_RSA_KEYX && dwAlgId != CALG_RSA_SIGN) || (keyType == CspAlgorithmType.Dss && dwAlgId != CALG_DSS_SIGN)) @@ -1022,7 +1023,7 @@ internal static void ImportKeyBlob(SafeProvHandle saveProvHandle, CspProviderFla } SafeKeyHandle hKey; - if (!CryptImportKey(saveProvHandle, keyBlob, keyBlob.Length, SafeKeyHandle.InvalidHandle, dwCapiFlags, out hKey)) + if (!CryptImportKey(saveProvHandle, keyBlob, SafeKeyHandle.InvalidHandle, dwCapiFlags, out hKey)) { int hr = Marshal.GetHRForLastWin32Error(); @@ -1330,7 +1331,7 @@ private static void UnloadKey(SafeProvHandle hProv, SafeKeyHandle hKey, [NotNull try { // Import the public key - if (!CryptImportKey(hProv, s_RgbPubKey, s_RgbPubKey.Length, SafeKeyHandle.InvalidHandle, 0, out hPubKey)) + if (!CryptImportKey(hProv, RgbPubKey, SafeKeyHandle.InvalidHandle, 0, out hPubKey)) { int hr = Marshal.GetHRForLastWin32Error(); throw hr.ToCryptographicException(); @@ -1469,19 +1470,21 @@ public static bool CryptGenKey( return response; } - public static bool CryptImportKey( + public static unsafe bool CryptImportKey( SafeProvHandle hProv, - byte[] pbData, - int dwDataLen, + ReadOnlySpan pbData, SafeKeyHandle hPubKey, int dwFlags, out SafeKeyHandle phKey) { - bool response = Interop.Advapi32.CryptImportKey(hProv, pbData, dwDataLen, hPubKey, dwFlags, out phKey); + fixed (byte* pbDataPtr = pbData) + { + bool response = Interop.Advapi32.CryptImportKey(hProv, pbDataPtr, pbData.Length, hPubKey, dwFlags, out phKey); - phKey.SetParent(hProv); + phKey.SetParent(hProv); - return response; + return response; + } } public static bool CryptCreateHash( diff --git a/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DSACryptoServiceProvider.Windows.cs b/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DSACryptoServiceProvider.Windows.cs index ed51902db8a0fe..567ce989bd7a56 100644 --- a/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DSACryptoServiceProvider.Windows.cs +++ b/src/libraries/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DSACryptoServiceProvider.Windows.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Buffers.Binary; using System.Diagnostics; using System.IO; using Internal.NativeCrypto; @@ -200,7 +201,7 @@ public override int KeySize get { byte[] keySize = CapiHelper.GetKeyParameter(SafeKeyHandle, Constants.CLR_KEYLEN); - _keySize = (keySize[0] | (keySize[1] << 8) | (keySize[2] << 16) | (keySize[3] << 24)); + _keySize = BinaryPrimitives.ReadInt32LittleEndian(keySize); return _keySize; } } diff --git a/src/libraries/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj b/src/libraries/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj index 887d4a3e1f2055..838235ca5248e1 100644 --- a/src/libraries/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj @@ -10,35 +10,24 @@ - - CommonTest\System\Security\Cryptography\ByteUtils.cs - - - CommonTest\System\Security\Cryptography\CryptoUtils.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\EncryptDecrypt.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\ImportExport.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\KeyGeneration.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAFactory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\SignVerify.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\TestData.cs - - - CommonTest\System\IO\PositionValueStream.cs - - - + + + + + + + + + @@ -51,80 +40,55 @@ - - CommonTest\System\Security\Cryptography\AsymmetricSignatureFormatter.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DES\DESCipherTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DES\DESFactory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DES\DesTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAFactory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DsaFamilySignatureFormatTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAImportExport.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyFileTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyPemTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAKeyGeneration.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatter.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignatureFormatTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSASignVerify.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSATestData.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\DSA\DSAXml.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RC2\RC2CipherTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RC2\RC2Factory.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RC2\RC2Tests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\EncryptDecrypt.netcoreapp.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyExchangeFormatter.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSASignatureFormatter.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAXml.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyFileTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\RSAKeyPemTests.cs - - - CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\SignVerify.netcoreapp.cs - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.OSX.cs b/src/libraries/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.OSX.cs index ee9cbb6c5b9a9d..fb055ca797c130 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.OSX.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.OSX.cs @@ -67,6 +67,16 @@ private static bool ShouldUseCache(OidGroup oidGroup) private static readonly Dictionary s_extraOidToFriendlyName = InvertWithDefaultComparer(s_extraFriendlyNameToOid); + private static Dictionary InvertWithDefaultComparer(Dictionary source) + { + var result = new Dictionary(source.Count); + foreach (KeyValuePair item in source) + { + result.Add(item.Value, item.Key); + } + return result; + } + #if DEBUG static partial void ExtraStaticDebugValidation() { diff --git a/src/libraries/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.cs b/src/libraries/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.cs index ca743d28adbcf9..e852b14a020ad0 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/src/Internal/Cryptography/OidLookup.cs @@ -94,132 +94,16 @@ internal static partial class OidLookup } /// Expected size of . - private const int FriendlyNameToOidCount = 103; + private const int FriendlyNameToOidCount = 110; + + /// Expected size of . + private const int OidToFriendlyNameCount = 103; - // This table was originally built by extracting every szOID #define out of wincrypt.h, - // and running them through new Oid(string) on Windows 10. Then, take the list of everything - // which produced a FriendlyName value, and run it through two other languages. If all 3 agree - // on the mapping, consider the value to be non-localized. - // - // This original list was produced on English (Win10), cross-checked with Spanish (Win8.1) and - // Japanese (Win10). - // - // Sometimes wincrypt.h has more than one OID which results in the same name. The OIDs whose value - // doesn't roundtrip (new Oid(new Oid(value).FriendlyName).Value) are contained in s_compatOids. - // - // X-Plat: The names (and casing) in this table come from Windows. Part of the intent of this table - // is to prevent issues wherein an identifier is different between Windows and Unix; - // since any existing code would be using the Windows identifier, it is the de facto standard. private static readonly Dictionary s_friendlyNameToOid = - new Dictionary(FriendlyNameToOidCount, StringComparer.OrdinalIgnoreCase) - { - { "3des", "1.2.840.113549.3.7" }, - { "aes128", "2.16.840.1.101.3.4.1.2" }, - { "aes128wrap", "2.16.840.1.101.3.4.1.5" }, - { "aes192", "2.16.840.1.101.3.4.1.22" }, - { "aes192wrap", "2.16.840.1.101.3.4.1.25" }, - { "aes256", "2.16.840.1.101.3.4.1.42" }, - { "aes256wrap", "2.16.840.1.101.3.4.1.45" }, - { "brainpoolP160r1", "1.3.36.3.3.2.8.1.1.1" }, - { "brainpoolP160t1", "1.3.36.3.3.2.8.1.1.2" }, - { "brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3" }, - { "brainpoolP192t1", "1.3.36.3.3.2.8.1.1.4" }, - { "brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5" }, - { "brainpoolP224t1", "1.3.36.3.3.2.8.1.1.6" }, - { "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7" }, - { "brainpoolP256t1", "1.3.36.3.3.2.8.1.1.8" }, - { "brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9" }, - { "brainpoolP320t1", "1.3.36.3.3.2.8.1.1.10" }, - { "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11" }, - { "brainpoolP384t1", "1.3.36.3.3.2.8.1.1.12" }, - { "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13" }, - { "brainpoolP512t1", "1.3.36.3.3.2.8.1.1.14" }, - { "C", "2.5.4.6" }, - { "CMS3DESwrap", "1.2.840.113549.1.9.16.3.6" }, - { "CMSRC2wrap", "1.2.840.113549.1.9.16.3.7" }, - { "CN", "2.5.4.3" }, - { "CPS", "1.3.6.1.5.5.7.2.1" }, - { "DC", "0.9.2342.19200300.100.1.25" }, - { "des", "1.3.14.3.2.7" }, - { "Description", "2.5.4.13" }, - { "DH", "1.2.840.10046.2.1" }, - { "dnQualifier", "2.5.4.46" }, - { "DSA", "1.2.840.10040.4.1" }, - { "dsaSHA1", "1.3.14.3.2.27" }, - { "E", "1.2.840.113549.1.9.1" }, - { "ec192wapi", "1.2.156.11235.1.1.2.1" }, - { "ECC", "1.2.840.10045.2.1" }, - { "ECDH_STD_SHA1_KDF", "1.3.133.16.840.63.0.2" }, - { "ECDH_STD_SHA256_KDF", "1.3.132.1.11.1" }, - { "ECDH_STD_SHA384_KDF", "1.3.132.1.11.2" }, - { "ECDSA_P256", "1.2.840.10045.3.1.7" }, - { "ECDSA_P384", "1.3.132.0.34" }, - { "ECDSA_P521", "1.3.132.0.35" }, - { "ESDH", "1.2.840.113549.1.9.16.3.5" }, - { "G", "2.5.4.42" }, - { "I", "2.5.4.43" }, - { "L", "2.5.4.7" }, - { "md2", "1.2.840.113549.2.2" }, - { "md2RSA", "1.2.840.113549.1.1.2" }, - { "md4", "1.2.840.113549.2.4" }, - { "md4RSA", "1.2.840.113549.1.1.3" }, - { "md5", "1.2.840.113549.2.5" }, - { "md5RSA", "1.2.840.113549.1.1.4" }, - { "mgf1", "1.2.840.113549.1.1.8" }, - { "mosaicKMandUpdSig", "2.16.840.1.101.2.1.1.20" }, - { "mosaicUpdatedSig", "2.16.840.1.101.2.1.1.19" }, - { "nistP192", "1.2.840.10045.3.1.1" }, - { "nistP224", "1.3.132.0.33" }, - { "NO_SIGN", "1.3.6.1.5.5.7.6.2" }, - { "O", "2.5.4.10" }, - { "OU", "2.5.4.11" }, - { "Phone", "2.5.4.20" }, - { "POBox", "2.5.4.18" }, - { "PostalCode", "2.5.4.17" }, - { "rc2", "1.2.840.113549.3.2" }, - { "rc4", "1.2.840.113549.3.4" }, - { "RSA", "1.2.840.113549.1.1.1" }, - { "RSAES_OAEP", "1.2.840.113549.1.1.7" }, - { "RSASSA-PSS", "1.2.840.113549.1.1.10" }, - { "S", "2.5.4.8" }, - { "secP160k1", "1.3.132.0.9" }, - { "secP160r1", "1.3.132.0.8" }, - { "secP160r2", "1.3.132.0.30" }, - { "secP192k1", "1.3.132.0.31" }, - { "secP224k1", "1.3.132.0.32" }, - { "secP256k1", "1.3.132.0.10" }, - { "SERIALNUMBER", "2.5.4.5" }, - { "sha1", "1.3.14.3.2.26" }, - { "sha1DSA", "1.2.840.10040.4.3" }, - { "sha1ECDSA", "1.2.840.10045.4.1" }, - { "sha1RSA", "1.2.840.113549.1.1.5" }, - { "sha256", "2.16.840.1.101.3.4.2.1" }, - { "sha256ECDSA", "1.2.840.10045.4.3.2" }, - { "sha256RSA", "1.2.840.113549.1.1.11" }, - { "sha384", "2.16.840.1.101.3.4.2.2" }, - { "sha384ECDSA", "1.2.840.10045.4.3.3" }, - { "sha384RSA", "1.2.840.113549.1.1.12" }, - { "sha512", "2.16.840.1.101.3.4.2.3" }, - { "sha512ECDSA", "1.2.840.10045.4.3.4" }, - { "sha512RSA", "1.2.840.113549.1.1.13" }, - { "SN", "2.5.4.4" }, - { "specifiedECDSA", "1.2.840.10045.4.3" }, - { "STREET", "2.5.4.9" }, - { "T", "2.5.4.12" }, - { "TPMManufacturer", "2.23.133.2.1" }, - { "TPMModel", "2.23.133.2.2" }, - { "TPMVersion", "2.23.133.2.3" }, - { "wtls9", "2.23.43.1.4.9" }, - { "X21Address", "2.5.4.24" }, - { "x962P192v2", "1.2.840.10045.3.1.2" }, - { "x962P192v3", "1.2.840.10045.3.1.3" }, - { "x962P239v1", "1.2.840.10045.3.1.4" }, - { "x962P239v2", "1.2.840.10045.3.1.5" }, - { "x962P239v3", "1.2.840.10045.3.1.6" }, - }; + new Dictionary(FriendlyNameToOidCount, StringComparer.OrdinalIgnoreCase); private static readonly Dictionary s_oidToFriendlyName = - InvertWithDefaultComparer(s_friendlyNameToOid); + new Dictionary(OidToFriendlyNameCount, StringComparer.Ordinal); private static readonly Dictionary s_compatOids = new Dictionary @@ -237,29 +121,155 @@ internal static partial class OidLookup { "1.3.14.7.2.3.1", "md2RSA" }, }; - private static Dictionary InvertWithDefaultComparer(Dictionary source) - { - var result = new Dictionary(source.Count); - foreach (KeyValuePair item in source) - { - result.Add(item.Value, item.Key); - } - return result; - } - -#if DEBUG static OidLookup() { + InitializeLookupDictionaries(); +#if DEBUG // Validate we hardcoded the right dictionary size Debug.Assert(s_friendlyNameToOid.Count == FriendlyNameToOidCount, $"Expected {nameof(s_friendlyNameToOid)}.{nameof(s_friendlyNameToOid.Count)} == {FriendlyNameToOidCount}, got {s_friendlyNameToOid.Count}"); - Debug.Assert(s_oidToFriendlyName.Count == FriendlyNameToOidCount, - $"Expected {nameof(s_oidToFriendlyName)}.{nameof(s_oidToFriendlyName.Count)} == {FriendlyNameToOidCount}, got {s_oidToFriendlyName.Count}"); + Debug.Assert(s_oidToFriendlyName.Count == OidToFriendlyNameCount, + $"Expected {nameof(s_oidToFriendlyName)}.{nameof(s_oidToFriendlyName.Count)} == {OidToFriendlyNameCount}, got {s_oidToFriendlyName.Count}"); ExtraStaticDebugValidation(); +#endif + } + + private static void InitializeLookupDictionaries() + { + void AddEntry(string oid, string primaryFriendlyName, string[]? additionalFriendlyNames = null) + { + s_oidToFriendlyName.Add(oid, primaryFriendlyName); + s_friendlyNameToOid.Add(primaryFriendlyName, oid); + + if (additionalFriendlyNames != null) + { + foreach (var additionalName in additionalFriendlyNames) + { + s_friendlyNameToOid.Add(additionalName, oid); + } + } + } + + // This lookup was originally built by extracting every szOID #define out of wincrypt.h, + // and running them through new Oid(string) on Windows 10. Then, take the list of everything + // which produced a FriendlyName value, and run it through two other languages. If all 3 agree + // on the mapping, consider the value to be non-localized. + // + // This original list was produced on English (Win10), cross-checked with Spanish (Win8.1) and + // Japanese (Win10). + // + // Sometimes wincrypt.h has more than one OID which results in the same name. The OIDs whose value + // doesn't roundtrip (new Oid(new Oid(value).FriendlyName).Value) are contained in s_compatOids. + // + // X-Plat: The names (and casing) in this table come from Windows. Part of the intent of this table + // is to prevent issues wherein an identifier is different between Windows and Unix; + // since any existing code would be using the Windows identifier, it is the de facto standard. + AddEntry("1.2.840.113549.3.7", "3des"); + AddEntry("2.16.840.1.101.3.4.1.2", "aes128"); + AddEntry("2.16.840.1.101.3.4.1.5", "aes128wrap"); + AddEntry("2.16.840.1.101.3.4.1.22", "aes192"); + AddEntry("2.16.840.1.101.3.4.1.25", "aes192wrap"); + AddEntry("2.16.840.1.101.3.4.1.42", "aes256"); + AddEntry("2.16.840.1.101.3.4.1.45", "aes256wrap"); + AddEntry("1.3.36.3.3.2.8.1.1.1", "brainpoolP160r1"); + AddEntry("1.3.36.3.3.2.8.1.1.2", "brainpoolP160t1"); + AddEntry("1.3.36.3.3.2.8.1.1.3", "brainpoolP192r1"); + AddEntry("1.3.36.3.3.2.8.1.1.4", "brainpoolP192t1"); + AddEntry("1.3.36.3.3.2.8.1.1.5", "brainpoolP224r1"); + AddEntry("1.3.36.3.3.2.8.1.1.6", "brainpoolP224t1"); + AddEntry("1.3.36.3.3.2.8.1.1.7", "brainpoolP256r1"); + AddEntry("1.3.36.3.3.2.8.1.1.8", "brainpoolP256t1"); + AddEntry("1.3.36.3.3.2.8.1.1.9", "brainpoolP320r1"); + AddEntry("1.3.36.3.3.2.8.1.1.10", "brainpoolP320t1"); + AddEntry("1.3.36.3.3.2.8.1.1.11", "brainpoolP384r1"); + AddEntry("1.3.36.3.3.2.8.1.1.12", "brainpoolP384t1"); + AddEntry("1.3.36.3.3.2.8.1.1.13", "brainpoolP512r1"); + AddEntry("1.3.36.3.3.2.8.1.1.14", "brainpoolP512t1"); + AddEntry("2.5.4.6", "C"); + AddEntry("1.2.840.113549.1.9.16.3.6", "CMS3DESwrap"); + AddEntry("1.2.840.113549.1.9.16.3.7", "CMSRC2wrap"); + AddEntry("2.5.4.3", "CN"); + AddEntry("1.3.6.1.5.5.7.2.1", "CPS"); + AddEntry("0.9.2342.19200300.100.1.25", "DC"); + AddEntry("1.3.14.3.2.7", "des"); + AddEntry("2.5.4.13", "Description"); + AddEntry("1.2.840.10046.2.1", "DH"); + AddEntry("2.5.4.46", "dnQualifier"); + AddEntry("1.2.840.10040.4.1", "DSA"); + AddEntry("1.3.14.3.2.27", "dsaSHA1"); + AddEntry("1.2.840.113549.1.9.1", "E"); + AddEntry("1.2.156.11235.1.1.2.1", "ec192wapi"); + AddEntry("1.2.840.10045.2.1", "ECC"); + AddEntry("1.3.133.16.840.63.0.2", "ECDH_STD_SHA1_KDF"); + AddEntry("1.3.132.1.11.1", "ECDH_STD_SHA256_KDF"); + AddEntry("1.3.132.1.11.2", "ECDH_STD_SHA384_KDF"); + AddEntry("1.2.840.10045.3.1.7", "ECDSA_P256", new[] { "nistP256", "secP256r1", "x962P256v1" } ); + AddEntry("1.3.132.0.34", "ECDSA_P384", new[] { "nistP384", "secP384r1" }); + AddEntry("1.3.132.0.35", "ECDSA_P521", new[] { "nistP521", "secP521r1" }); + AddEntry("1.2.840.113549.1.9.16.3.5", "ESDH"); + AddEntry("2.5.4.42", "G"); + AddEntry("2.5.4.43", "I"); + AddEntry("2.5.4.7", "L"); + AddEntry("1.2.840.113549.2.2", "md2"); + AddEntry("1.2.840.113549.1.1.2", "md2RSA"); + AddEntry("1.2.840.113549.2.4", "md4"); + AddEntry("1.2.840.113549.1.1.3", "md4RSA"); + AddEntry("1.2.840.113549.2.5", "md5"); + AddEntry("1.2.840.113549.1.1.4", "md5RSA"); + AddEntry("1.2.840.113549.1.1.8", "mgf1"); + AddEntry("2.16.840.1.101.2.1.1.20", "mosaicKMandUpdSig"); + AddEntry("2.16.840.1.101.2.1.1.19", "mosaicUpdatedSig"); + AddEntry("1.2.840.10045.3.1.1", "nistP192"); + AddEntry("1.3.132.0.33", "nistP224"); + AddEntry("1.3.6.1.5.5.7.6.2", "NO_SIGN"); + AddEntry("2.5.4.10", "O"); + AddEntry("2.5.4.11", "OU"); + AddEntry("2.5.4.20", "Phone"); + AddEntry("2.5.4.18", "POBox"); + AddEntry("2.5.4.17", "PostalCode"); + AddEntry("1.2.840.113549.3.2", "rc2"); + AddEntry("1.2.840.113549.3.4", "rc4"); + AddEntry("1.2.840.113549.1.1.1", "RSA"); + AddEntry("1.2.840.113549.1.1.7", "RSAES_OAEP"); + AddEntry("1.2.840.113549.1.1.10", "RSASSA-PSS"); + AddEntry("2.5.4.8", "S"); + AddEntry("1.3.132.0.9", "secP160k1"); + AddEntry("1.3.132.0.8", "secP160r1"); + AddEntry("1.3.132.0.30", "secP160r2"); + AddEntry("1.3.132.0.31", "secP192k1"); + AddEntry("1.3.132.0.32", "secP224k1"); + AddEntry("1.3.132.0.10", "secP256k1"); + AddEntry("2.5.4.5", "SERIALNUMBER"); + AddEntry("1.3.14.3.2.26", "sha1"); + AddEntry("1.2.840.10040.4.3", "sha1DSA"); + AddEntry("1.2.840.10045.4.1", "sha1ECDSA"); + AddEntry("1.2.840.113549.1.1.5", "sha1RSA"); + AddEntry("2.16.840.1.101.3.4.2.1", "sha256"); + AddEntry("1.2.840.10045.4.3.2", "sha256ECDSA"); + AddEntry("1.2.840.113549.1.1.11", "sha256RSA"); + AddEntry("2.16.840.1.101.3.4.2.2", "sha384"); + AddEntry("1.2.840.10045.4.3.3", "sha384ECDSA"); + AddEntry("1.2.840.113549.1.1.12", "sha384RSA"); + AddEntry("2.16.840.1.101.3.4.2.3", "sha512"); + AddEntry("1.2.840.10045.4.3.4", "sha512ECDSA"); + AddEntry("1.2.840.113549.1.1.13", "sha512RSA"); + AddEntry("2.5.4.4", "SN"); + AddEntry("1.2.840.10045.4.3", "specifiedECDSA"); + AddEntry("2.5.4.9", "STREET"); + AddEntry("2.5.4.12", "T"); + AddEntry("2.23.133.2.1", "TPMManufacturer"); + AddEntry("2.23.133.2.2", "TPMModel"); + AddEntry("2.23.133.2.3", "TPMVersion"); + AddEntry("2.23.43.1.4.9", "wtls9"); + AddEntry("2.5.4.24", "X21Address"); + AddEntry("1.2.840.10045.3.1.2", "x962P192v2"); + AddEntry("1.2.840.10045.3.1.3", "x962P192v3"); + AddEntry("1.2.840.10045.3.1.4", "x962P239v1"); + AddEntry("1.2.840.10045.3.1.5", "x962P239v2"); + AddEntry("1.2.840.10045.3.1.6", "x962P239v3"); } static partial void ExtraStaticDebugValidation(); -#endif } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/src/System.Security.Cryptography.Encoding.csproj b/src/libraries/System.Security.Cryptography.Encoding/src/System.Security.Cryptography.Encoding.csproj index 19f6ae909d28fe..5c496e61e53674 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/src/System.Security.Cryptography.Encoding.csproj +++ b/src/libraries/System.Security.Cryptography.Encoding/src/System.Security.Cryptography.Encoding.csproj @@ -20,90 +20,66 @@ - - Internal\Cryptography\Helpers.cs - - - System\Security\Cryptography\CryptoPool.cs - - - Common\System\HexConverter.cs - + + + - - Common\Interop\Windows\BCrypt\Interop.NTSTATUS.cs - - - Microsoft\Win32\SafeHandles\SafeBCryptHandle.cs - - - Common\Interop\Windows\BCrypt\Cng.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptPropertyStrings.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptFormatObject.cs - - - Common\Interop\Windows\Crypt32\Interop.FindOidInfo.cs - - - Internal\Cryptography\Windows\CryptoThrowHelper.cs - - - Internal\Windows\kernel32\Interop.FormatMessage.cs - - - Common\Interop\Windows\Interop.Libraries.cs - + + + + + + + + + - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ASN1.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.BIO.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Initialization.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.LookupFriendlyNameByOid.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509Ext.cs - - - Common\Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeBioHandle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeInteriorHandle.cs - - - Common\Microsoft\Win32\SafeHandles\X509ExtensionSafeHandles.Unix.cs - + + + + + + + + + + + - - Common\System\Memory\PointerMemoryManager.cs - + Common\System\Security\Cryptography\Asn1\DirectoryStringAsn.xml diff --git a/src/libraries/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/PemEncoding.cs b/src/libraries/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/PemEncoding.cs index 7232a72205c9c2..711b323136b08f 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/PemEncoding.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/src/System/Security/Cryptography/PemEncoding.cs @@ -88,7 +88,7 @@ public static bool TryFind(ReadOnlySpan pemData, out PemFields fields) // must be a white space character. if (preebIndex > 0 && !IsWhiteSpaceCharacter(pemData[preebIndex - 1])) { - areaOffset += labelStartIndex; + areaOffset = labelStartIndex; continue; } @@ -150,16 +150,16 @@ public static bool TryFind(ReadOnlySpan pemData, out PemFields fields) return true; NextAfterLabel: - if (preebEndIndex <= 0) + if (preebEndIndex <= areaOffset) { // We somehow ended up in a situation where we will advance - // 0 or -1 characters, which means we'll probably end up here again, - // advancing 0 or -1 characters, in a loop. To avoid getting stuck, + // backward or not at all, which means we'll probably end up here again, + // advancing backward, in a loop. To avoid getting stuck, // detect this situation and return. fields = default; return false; } - areaOffset += preebEndIndex; + areaOffset = preebEndIndex; } fields = default; @@ -178,6 +178,7 @@ static ReadOnlySpan WritePostEB(ReadOnlySpan label, Span desti private static int IndexOfByOffset(this ReadOnlySpan str, ReadOnlySpan value, int startPosition) { + Debug.Assert(startPosition <= str.Length); int index = str.Slice(startPosition).IndexOf(value); return index == -1 ? -1 : index + startPosition; } @@ -438,7 +439,7 @@ static int WriteBase64(ReadOnlySpan bytes, Span dest, int offset) if (!success) { Debug.Fail("Convert.TryToBase64Chars failed with a pre-sized buffer"); - throw new ArgumentException(); + throw new ArgumentException(null, nameof(destination)); } return base64Written; @@ -528,7 +529,7 @@ public static char[] Write(ReadOnlySpan label, ReadOnlySpan data) if (!TryWrite(label, data, buffer, out int charsWritten)) { Debug.Fail("TryWrite failed with a pre-sized buffer"); - throw new ArgumentException(); + throw new ArgumentException(null, nameof(data)); } Debug.Assert(charsWritten == encodedSize); diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Array.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Array.cs index 5f479b6a085641..95d272c15dd41a 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Array.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Array.cs @@ -7,7 +7,7 @@ using Test.Cryptography; using Xunit; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor.Tests { public partial class CborReaderTests { @@ -27,7 +27,7 @@ public static void ReadArray_SimpleValues_HappyPath(object[] expectedValues, str byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); Helpers.VerifyArray(reader, expectedValues); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -39,7 +39,7 @@ public static void ReadArray_NestedValues_HappyPath(object[] expectedValues, str byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); Helpers.VerifyArray(reader, expectedValues); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -55,7 +55,64 @@ public static void ReadArray_IndefiniteLength_HappyPath(object[] expectedValues, byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); Helpers.VerifyArray(reader, expectedValues, expectDefiniteLengthCollections: false); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData(CborConformanceLevel.Lax, "9800")] + [InlineData(CborConformanceLevel.Lax, "990000")] + [InlineData(CborConformanceLevel.Lax, "9a00000000")] + [InlineData(CborConformanceLevel.Lax, "9b0000000000000000")] + [InlineData(CborConformanceLevel.Strict, "9800")] + [InlineData(CborConformanceLevel.Strict, "990000")] + [InlineData(CborConformanceLevel.Strict, "9a00000000")] + [InlineData(CborConformanceLevel.Strict, "9b0000000000000000")] + public static void ReadArray_NonCanonicalLengths_SupportedConformanceLevel_ShouldSucceed(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + int? length = reader.ReadStartArray(); + Assert.NotNull(length); + Assert.Equal(0, length!.Value); + } + + [Theory] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "9800")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "990000")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "9a00000000")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "9b0000000000000000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "9800")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "990000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "9a00000000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "9b0000000000000000")] + public static void ReadArray_NonCanonicalLengths_UnSupportedConformanceLevel_ShouldThrowFormatException(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + Assert.Throws(() => reader.ReadStartArray()); + Assert.Equal(0, reader.BytesRead); + } + + [Theory] + [InlineData(CborConformanceLevel.Lax, "9fff")] + [InlineData(CborConformanceLevel.Strict, "9fff")] + public static void ReadArray_IndefiniteLength_SupportedConformanceLevel_ShouldSucceed(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + int? length = reader.ReadStartArray(); + Assert.Null(length); + } + + [Theory] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "9fff")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "9fff")] + public static void ReadArray_IndefiniteLength_UnSupportedConformanceLevel_ShouldThrowFormatException(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + Assert.Throws(() => reader.ReadStartArray()); + Assert.Equal(0, reader.BytesRead); } [Theory] @@ -67,7 +124,7 @@ public static void ReadArray_DefiniteLengthExceeded_ShouldThrowInvalidOperationE byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - ulong? length = reader.ReadStartArray(); + int? length = reader.ReadStartArray(); Assert.Equal(expectedLength, (int)length!.Value); for (int i = 0; i < expectedLength; i++) @@ -75,7 +132,9 @@ public static void ReadArray_DefiniteLengthExceeded_ShouldThrowInvalidOperationE reader.ReadInt64(); } + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadInt64()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Theory] @@ -86,13 +145,13 @@ public static void ReadArray_DefiniteLengthExceeded_WithNestedData_ShouldThrowIn byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - ulong? length = reader.ReadStartArray(); + int? length = reader.ReadStartArray(); Assert.Equal(expectedLength, (int)length!.Value); for (int i = 0; i < expectedLength; i++) { - ulong? nestedLength = reader.ReadStartArray(); - Assert.Equal(1, (int)nestedLength!.Value); + int? nestedLength = reader.ReadStartArray(); + Assert.Equal(1, nestedLength!.Value); reader.ReadInt64(); reader.ReadEndArray(); } @@ -109,12 +168,12 @@ public static void ReadArray_IndefiniteLength_MissingBreakByte_ShouldReportEndOf byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); reader.ReadStartArray(); - while (reader.Peek() == CborReaderState.UnsignedInteger) + while (reader.PeekState() == CborReaderState.UnsignedInteger) { reader.ReadInt64(); } - Assert.Equal(CborReaderState.EndOfData, reader.Peek()); + Assert.Equal(CborReaderState.EndOfData, reader.PeekState()); } [Theory] @@ -131,7 +190,9 @@ public static void ReadArray_IndefiniteLength_PrematureEndArrayCall_ShouldThrowI reader.ReadInt64(); } + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadEndArray()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Theory] @@ -142,7 +203,7 @@ public static void EndReadArray_DefiniteLengthNotMet_ShouldThrowInvalidOperation byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - ulong? length = reader.ReadStartArray(); + int? length = reader.ReadStartArray(); Assert.Equal(expectedLength, (int)length!.Value); for (int i = 1; i < expectedLength; i++) @@ -150,7 +211,9 @@ public static void EndReadArray_DefiniteLengthNotMet_ShouldThrowInvalidOperation reader.ReadInt64(); } + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadEndArray()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Theory] @@ -161,18 +224,20 @@ public static void EndReadArray_DefiniteLengthNotMet_WithNestedData_ShouldThrowI byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - ulong? length = reader.ReadStartArray(); + int? length = reader.ReadStartArray(); Assert.Equal(expectedLength, (int)length!.Value); for (int i = 1; i < expectedLength; i++) { - ulong? nestedLength = reader.ReadStartArray(); - Assert.Equal(1, (int)nestedLength!.Value); + int? nestedLength = reader.ReadStartArray(); + Assert.Equal(1, nestedLength!.Value); reader.ReadInt64(); reader.ReadEndArray(); } + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadEndArray()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Fact] @@ -191,7 +256,7 @@ public static void ReadArray_IncorrectDefiniteLength_ShouldThrowFormatException( byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - ulong? length = reader.ReadStartArray(); + int? length = reader.ReadStartArray(); Assert.Equal(expectedLength, (int)length!.Value); for (int i = 0; i < actualLength; i++) @@ -199,7 +264,9 @@ public static void ReadArray_IncorrectDefiniteLength_ShouldThrowFormatException( reader.ReadInt64(); } + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadInt64()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Theory] @@ -210,18 +277,20 @@ public static void ReadArray_IncorrectDefiniteLength_NestedValues_ShouldThrowFor byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - ulong? length = reader.ReadStartArray(); + int? length = reader.ReadStartArray(); Assert.Equal(expectedLength, (int)length!.Value); for (int i = 0; i < actualLength; i++) { - ulong? innerLength = reader.ReadStartArray(); - Assert.Equal(1, (int)innerLength!.Value); + int? innerLength = reader.ReadStartArray(); + Assert.Equal(1, innerLength!.Value); reader.ReadInt64(); reader.ReadEndArray(); } + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadInt64()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Fact] @@ -231,6 +300,7 @@ public static void ReadStartArray_EmptyBuffer_ShouldThrowFormatException() var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadStartArray()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -244,9 +314,11 @@ public static void ReadStartArray_EmptyBuffer_ShouldThrowFormatException() [InlineData("fb3ff199999999999a")] // 1.1 public static void ReadStartArray_InvalidType_ShouldThrowInvalidOperationException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Throws(() => reader.ReadStartArray()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -261,22 +333,24 @@ public static void ReadStartArray_InvalidType_ShouldThrowInvalidOperationExcepti [InlineData("9b00000000000000")] public static void ReadStartArray_InvalidData_ShouldThrowFormatException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadStartArray()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] - [InlineData("81")] - [InlineData("830102")] + [InlineData("82")] + [InlineData("870102")] [InlineData("9b7fffffffffffffff")] // long.MaxValue public static void ReadStartArray_BufferTooSmall_ShouldThrowFormatException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadStartArray()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Helpers.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Helpers.cs index 6c09b4a6c8ce35..04fd91a2c60705 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Helpers.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Helpers.cs @@ -4,10 +4,11 @@ #nullable enable using System.Linq; +using System.Numerics; using Test.Cryptography; using Xunit; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor.Tests { public partial class CborReaderTests { @@ -18,80 +19,129 @@ public static void VerifyValue(CborReader reader, object expectedValue, bool exp switch (expectedValue) { case null: - Assert.Equal(CborReaderState.Null, reader.Peek()); + Assert.Equal(CborReaderState.Null, reader.PeekState()); reader.ReadNull(); break; + case bool expected: - Assert.Equal(CborReaderState.Boolean, reader.Peek()); + Assert.Equal(CborReaderState.Boolean, reader.PeekState()); bool b = reader.ReadBoolean(); Assert.Equal(expected, b); break; + case int expected: VerifyPeekInteger(reader, isUnsignedInteger: expected >= 0); - long i = reader.ReadInt64(); - Assert.Equal(expected, (int)i); + int i = reader.ReadInt32(); + Assert.Equal(expected, i); break; + case long expected: VerifyPeekInteger(reader, isUnsignedInteger: expected >= 0); long l = reader.ReadInt64(); Assert.Equal(expected, l); break; + case ulong expected: VerifyPeekInteger(reader, isUnsignedInteger: true); ulong u = reader.ReadUInt64(); Assert.Equal(expected, u); break; + case float expected: - Assert.Equal(CborReaderState.SinglePrecisionFloat, reader.Peek()); + Assert.Equal(CborReaderState.SinglePrecisionFloat, reader.PeekState()); float f = reader.ReadSingle(); Assert.Equal(expected, f); break; + case double expected: - Assert.Equal(CborReaderState.DoublePrecisionFloat, reader.Peek()); + Assert.Equal(CborReaderState.DoublePrecisionFloat, reader.PeekState()); double d = reader.ReadDouble(); Assert.Equal(expected, d); break; + + case decimal expected: + Assert.Equal(CborReaderState.Tag, reader.PeekState()); + decimal dec = reader.ReadDecimal(); + Assert.Equal(expected, dec); + break; + + case BigInteger expected: + Assert.Equal(CborReaderState.Tag, reader.PeekState()); + BigInteger bigint = reader.ReadBigInteger(); + Assert.Equal(expected, bigint); + break; + + case DateTimeOffset expected: + Assert.Equal(CborReaderState.Tag, reader.PeekState()); + DateTimeOffset dto = reader.ReadDateTimeOffset(); + Assert.Equal(expected, dto); + break; + case string expected: - Assert.Equal(CborReaderState.TextString, reader.Peek()); + Assert.Equal(CborReaderState.TextString, reader.PeekState()); string s = reader.ReadTextString(); Assert.Equal(expected, s); break; + case byte[] expected: - Assert.Equal(CborReaderState.ByteString, reader.Peek()); + Assert.Equal(CborReaderState.ByteString, reader.PeekState()); byte[] bytes = reader.ReadByteString(); Assert.Equal(expected.ByteArrayToHex(), bytes.ByteArrayToHex()); break; + + case string[] expectedChunks when CborWriterTests.Helpers.IsIndefiniteLengthByteString(expectedChunks): + byte[][] expectedByteChunks = expectedChunks.Skip(1).Select(ch => ch.HexToByteArray()).ToArray(); + VerifyValue(reader, expectedByteChunks, expectDefiniteLengthCollections); + break; + case string[] expectedChunks: - Assert.Equal(CborReaderState.StartTextString, reader.Peek()); + Assert.Equal(CborReaderState.StartTextString, reader.PeekState()); reader.ReadStartTextStringIndefiniteLength(); foreach(string expectedChunk in expectedChunks) { - Assert.Equal(CborReaderState.TextString, reader.Peek()); + Assert.Equal(CborReaderState.TextString, reader.PeekState()); string chunk = reader.ReadTextString(); Assert.Equal(expectedChunk, chunk); } - Assert.Equal(CborReaderState.EndTextString, reader.Peek()); + Assert.Equal(CborReaderState.EndTextString, reader.PeekState()); reader.ReadEndTextStringIndefiniteLength(); break; + case byte[][] expectedChunks: - Assert.Equal(CborReaderState.StartByteString, reader.Peek()); + Assert.Equal(CborReaderState.StartByteString, reader.PeekState()); reader.ReadStartByteStringIndefiniteLength(); foreach (byte[] expectedChunk in expectedChunks) { - Assert.Equal(CborReaderState.ByteString, reader.Peek()); + Assert.Equal(CborReaderState.ByteString, reader.PeekState()); byte[] chunk = reader.ReadByteString(); Assert.Equal(expectedChunk.ByteArrayToHex(), chunk.ByteArrayToHex()); } - Assert.Equal(CborReaderState.EndByteString, reader.Peek()); + Assert.Equal(CborReaderState.EndByteString, reader.PeekState()); reader.ReadEndByteStringIndefiniteLength(); break; case object[] nested when CborWriterTests.Helpers.IsCborMapRepresentation(nested): VerifyMap(reader, nested, expectDefiniteLengthCollections); break; + + case object[] nested when CborWriterTests.Helpers.IsEncodedValueRepresentation(nested): + string expectedHexEncoding = (string)nested[1]; + string actualHexEncoding = reader.ReadEncodedValue().ByteArrayToHex(); + Assert.Equal(expectedHexEncoding, actualHexEncoding); + break; + + case object[] nested when CborWriterTests.Helpers.IsTaggedValueRepresentation(nested): + CborTag expectedTag = (CborTag)nested[0]; + object expectedNestedValue = nested[1]; + Assert.Equal(CborReaderState.Tag, reader.PeekState()); + Assert.Equal(expectedTag, reader.ReadTag()); + VerifyValue(reader, expectedNestedValue, expectDefiniteLengthCollections); + break; + case object[] nested: VerifyArray(reader, nested, expectDefiniteLengthCollections); break; + default: throw new ArgumentException($"Unrecognized argument type {expectedValue.GetType()}"); } @@ -99,15 +149,15 @@ public static void VerifyValue(CborReader reader, object expectedValue, bool exp static void VerifyPeekInteger(CborReader reader, bool isUnsignedInteger) { CborReaderState expectedState = isUnsignedInteger ? CborReaderState.UnsignedInteger : CborReaderState.NegativeInteger; - Assert.Equal(expectedState, reader.Peek()); + Assert.Equal(expectedState, reader.PeekState()); } } public static void VerifyArray(CborReader reader, object[] expectedValues, bool expectDefiniteLengthCollections = true) { - Assert.Equal(CborReaderState.StartArray, reader.Peek()); + Assert.Equal(CborReaderState.StartArray, reader.PeekState()); - ulong? length = reader.ReadStartArray(); + int? length = reader.ReadStartArray(); if (expectDefiniteLengthCollections) { @@ -124,7 +174,7 @@ public static void VerifyArray(CborReader reader, object[] expectedValues, bool VerifyValue(reader, value); } - Assert.Equal(CborReaderState.EndArray, reader.Peek()); + Assert.Equal(CborReaderState.EndArray, reader.PeekState()); reader.ReadEndArray(); } @@ -135,9 +185,9 @@ public static void VerifyMap(CborReader reader, object[] expectedValues, bool ex throw new ArgumentException($"cbor map expected values missing '{CborWriterTests.Helpers.MapPrefixIdentifier}' prefix."); } - Assert.Equal(CborReaderState.StartMap, reader.Peek()); + Assert.Equal(CborReaderState.StartMap, reader.PeekState()); - ulong? length = reader.ReadStartMap(); + int? length = reader.ReadStartMap(); if (expectDefiniteLengthCollections) { @@ -151,10 +201,10 @@ public static void VerifyMap(CborReader reader, object[] expectedValues, bool ex foreach (object value in expectedValues.Skip(1)) { - VerifyValue(reader, value); + VerifyValue(reader, value, expectDefiniteLengthCollections); } - Assert.Equal(CborReaderState.EndMap, reader.Peek()); + Assert.Equal(CborReaderState.EndMap, reader.PeekState()); reader.ReadEndMap(); } } @@ -217,9 +267,6 @@ public static void VerifyMap(CborReader reader, object[] expectedValues, bool ex "4201", "61", "6261", - // invalid utf8 strings - "61ff", - "62f090", // indefinite-length strings with missing break byte "5f41ab40", "7f62616260", diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Integer.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Integer.cs index 3542d3412ec00c..87ae7d7d402a41 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Integer.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Integer.cs @@ -7,7 +7,7 @@ using Test.Cryptography; using Xunit; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor.Tests { public partial class CborReaderTests { @@ -50,7 +50,40 @@ public static void ReadInt64_SingleValue_HappyPath(long expectedResult, string h var reader = new CborReader(data); long actualResult = reader.ReadInt64(); Assert.Equal(expectedResult, actualResult); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData(0, "00")] + [InlineData(1, "01")] + [InlineData(10, "0a")] + [InlineData(23, "17")] + [InlineData(24, "1818")] + [InlineData(25, "1819")] + [InlineData(100, "1864")] + [InlineData(1000, "1903e8")] + [InlineData(1000000, "1a000f4240")] + [InlineData(-1, "20")] + [InlineData(-10, "29")] + [InlineData(-100, "3863")] + [InlineData(-1000, "3903e7")] + [InlineData(byte.MaxValue, "18ff")] + [InlineData(byte.MaxValue + 1, "190100")] + [InlineData(-1 - byte.MaxValue, "38ff")] + [InlineData(-2 - byte.MaxValue, "390100")] + [InlineData(ushort.MaxValue, "19ffff")] + [InlineData(ushort.MaxValue + 1, "1a00010000")] + [InlineData(-1 - ushort.MaxValue, "39ffff")] + [InlineData(-2 - ushort.MaxValue, "3a00010000")] + [InlineData(int.MaxValue, "1a7fffffff")] + [InlineData(int.MinValue, "3a7fffffff")] + public static void ReadInt32_SingleValue_HappyPath(int expectedResult, string hexEncoding) + { + byte[] data = hexEncoding.HexToByteArray(); + var reader = new CborReader(data); + long actualResult = reader.ReadInt32(); + Assert.Equal(expectedResult, actualResult); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -78,7 +111,32 @@ public static void ReadUInt64_SingleValue_HappyPath(ulong expectedResult, string var reader = new CborReader(data); ulong actualResult = reader.ReadUInt64(); Assert.Equal(expectedResult, actualResult); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData(0, "00")] + [InlineData(1, "01")] + [InlineData(10, "0a")] + [InlineData(23, "17")] + [InlineData(24, "1818")] + [InlineData(25, "1819")] + [InlineData(100, "1864")] + [InlineData(1000, "1903e8")] + [InlineData(1000000, "1a000f4240")] + [InlineData(byte.MaxValue, "18ff")] + [InlineData(byte.MaxValue + 1, "190100")] + [InlineData(ushort.MaxValue, "19ffff")] + [InlineData(ushort.MaxValue + 1, "1a00010000")] + [InlineData(int.MaxValue, "1a7fffffff")] + [InlineData(uint.MaxValue, "1affffffff")] + public static void ReadUInt32_SingleValue_HappyPath(uint expectedResult, string hexEncoding) + { + byte[] data = hexEncoding.HexToByteArray(); + var reader = new CborReader(data); + uint actualResult = reader.ReadUInt32(); + Assert.Equal(expectedResult, actualResult); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -97,82 +155,85 @@ public static void ReadCborNegativeIntegerEncoding_SingleValue_HappyPath(ulong e var reader = new CborReader(data); ulong actualResult = reader.ReadCborNegativeIntegerEncoding(); Assert.Equal(expectedResult, actualResult); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] - [InlineData(2, 2, "c202")] - [InlineData(0, "2013-03-21T20:04:00Z", "c074323031332d30332d32315432303a30343a30305a")] - [InlineData(1, 1363896240, "c11a514b67b0")] - [InlineData(23, new byte[] { 1, 2, 3, 4 }, "d74401020304")] - [InlineData(32, "http://www.example.com", "d82076687474703a2f2f7777772e6578616d706c652e636f6d")] - [InlineData(int.MaxValue, 2, "da7fffffff02")] - [InlineData(ulong.MaxValue, new object[] { 1, 2 }, "dbffffffffffffffff820102")] - public static void ReadTag_SingleValue_HappyPath(ulong expectedTag, object expectedValue, string hexEncoding) + [InlineData(CborConformanceLevel.Lax, "1817", 23)] + [InlineData(CborConformanceLevel.Lax, "1900ff", byte.MaxValue)] + [InlineData(CborConformanceLevel.Lax, "1a0000ffff", ushort.MaxValue)] + [InlineData(CborConformanceLevel.Lax, "1b00000000ffffffff", uint.MaxValue)] + [InlineData(CborConformanceLevel.Lax, "1b0000000000000001", 1)] + [InlineData(CborConformanceLevel.Strict, "1817", 23)] + [InlineData(CborConformanceLevel.Strict, "1900ff", byte.MaxValue)] + [InlineData(CborConformanceLevel.Strict, "1a0000ffff", ushort.MaxValue)] + [InlineData(CborConformanceLevel.Strict, "1b00000000ffffffff", uint.MaxValue)] + [InlineData(CborConformanceLevel.Strict, "1b0000000000000001", 1)] + public static void ReadUInt64_NonCanonicalEncodings_SupportedConformanceLevel_ShouldSucceed(CborConformanceLevel level, string hexEncoding, ulong expectedValue) { - byte[] encoding = hexEncoding.HexToByteArray(); - var reader = new CborReader(encoding); - - Assert.Equal(CborReaderState.Tag, reader.Peek()); - CborTag tag = reader.ReadTag(); - Assert.Equal(expectedTag, (ulong)tag); - - Helpers.VerifyValue(reader, expectedValue); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + byte[] data = hexEncoding.HexToByteArray(); + var reader = new CborReader(data, level); + ulong result = reader.ReadUInt64(); + Assert.Equal(expectedValue, result); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] - [InlineData(new ulong[] { 1, 2, 3 }, 2, "c1c2c302")] - [InlineData(new ulong[] { 0, 0, 0 }, "2013-03-21T20:04:00Z", "c0c0c074323031332d30332d32315432303a30343a30305a")] - [InlineData(new ulong[] { int.MaxValue, ulong.MaxValue }, 1363896240, "da7fffffffdbffffffffffffffff1a514b67b0")] - [InlineData(new ulong[] { 23, 24, 100 }, new byte[] { 1, 2, 3, 4 }, "d7d818d8644401020304")] - [InlineData(new ulong[] { 32, 1, 1 }, new object[] { 1, "lorem ipsum" }, "d820c1c182016b6c6f72656d20697073756d")] - public static void ReadTag_NestedTags_HappyPath(ulong[] expectedTags, object expectedValue, string hexEncoding) + [InlineData(CborConformanceLevel.Rfc7049Canonical, "1817")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "1900ff")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "1a0000ffff")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "1b00000000ffffffff")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "1b0000000000000001")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "1817")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "1900ff")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "1a0000ffff")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "1b00000000ffffffff")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "1b0000000000000001")] + public static void ReadUInt64_NonCanonicalEncodings_UnSupportedConformanceLevel_ShouldThrowFormatException(CborConformanceLevel level, string hexEncoding) { - byte[] encoding = hexEncoding.HexToByteArray(); - var reader = new CborReader(encoding); - - foreach (ulong expectedTag in expectedTags) - { - Assert.Equal(CborReaderState.Tag, reader.Peek()); - CborTag tag = reader.ReadTag(); - Assert.Equal(expectedTag, (ulong)tag); - } - - Helpers.VerifyValue(reader, expectedValue); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + byte[] data = hexEncoding.HexToByteArray(); + var reader = new CborReader(data, level); + Assert.Throws(() => reader.ReadUInt64()); + Assert.Equal(0, reader.BytesRead); } [Theory] - // all possible definite-length encodings for the value 23 - [InlineData("17")] - [InlineData("1817")] - [InlineData("190017")] - [InlineData("1a00000017")] - [InlineData("1b0000000000000017")] - public static void ReadUInt64_SingleValue_ShouldSupportNonCanonicalEncodings(string hexEncoding) + [InlineData(CborConformanceLevel.Lax, "3817", -24)] + [InlineData(CborConformanceLevel.Lax, "3900ff", -1 - byte.MaxValue)] + [InlineData(CborConformanceLevel.Lax, "3a0000ffff", -1 - ushort.MaxValue)] + [InlineData(CborConformanceLevel.Lax, "3b00000000ffffffff", -1 - uint.MaxValue)] + [InlineData(CborConformanceLevel.Lax, "3b0000000000000000", -1)] + [InlineData(CborConformanceLevel.Strict, "3817", -24)] + [InlineData(CborConformanceLevel.Strict, "3900ff", -1 - byte.MaxValue)] + [InlineData(CborConformanceLevel.Strict, "3a0000ffff", -1 - ushort.MaxValue)] + [InlineData(CborConformanceLevel.Strict, "3b00000000ffffffff", -1 - uint.MaxValue)] + [InlineData(CborConformanceLevel.Strict, "3b0000000000000000", -1)] + public static void ReadInt64_NonCanonicalEncodings_SupportedConformanceLevel_ShouldSucceed(CborConformanceLevel level, string hexEncoding, long expectedValue) { byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); - ulong result = reader.ReadUInt64(); - Assert.Equal(23ul, result); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + var reader = new CborReader(data, level); + long result = reader.ReadInt64(); + Assert.Equal(expectedValue, result); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] - // all possible definite-length encodings for the value -24 - [InlineData("37")] - [InlineData("3817")] - [InlineData("390017")] - [InlineData("3a00000017")] - [InlineData("3b0000000000000017")] - public static void ReadInt64_SingleValue_ShouldSupportNonCanonicalEncodings(string hexEncoding) + [InlineData(CborConformanceLevel.Rfc7049Canonical, "3817")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "3900ff")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "3a0000ffff")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "3b00000000ffffffff")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "3b0000000000000001")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "3817")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "3900ff")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "3a0000ffff")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "3b00000000ffffffff")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "3b0000000000000001")] + public static void ReadInt64_NonCanonicalEncodings_UnSupportedConformanceLevel_ShouldThrowFormatException(CborConformanceLevel level, string hexEncoding) { byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); - long result = reader.ReadInt64(); - Assert.Equal(-24, result); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + var reader = new CborReader(data, level); + Assert.Throws(() => reader.ReadInt64()); + Assert.Equal(0, reader.BytesRead); } @@ -182,10 +243,38 @@ public static void ReadInt64_SingleValue_ShouldSupportNonCanonicalEncodings(stri [InlineData("1bffffffffffffffff")] // ulong.MaxValue public static void ReadInt64_OutOfRangeValues_ShouldThrowOverflowException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadInt64()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("1a80000000")] // int.MaxValue + 1 + [InlineData("3a80000000")] // int.MinValue - 1 + [InlineData("1b8000000000000000")] // long.MaxValue + 1 + [InlineData("3a8000000000000000")] // long.MinValue - 1 + [InlineData("1bffffffffffffffff")] // ulong.MaxValue + public static void ReadInt32_OutOfRangeValues_ShouldThrowOverflowException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Throws(() => reader.ReadInt32()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("20")] + [InlineData("1b0000000100000000")] // uint.MaxValue + 1 + public static void ReadUInt32_OutOfRangeValues_ShouldThrowOverflowException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Throws(() => reader.ReadUInt32()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -194,19 +283,10 @@ public static void ReadInt64_OutOfRangeValues_ShouldThrowOverflowException(strin [InlineData("3b7fffffffffffffff")] // long.MinValue public static void ReadUInt64_OutOfRangeValues_ShouldThrowOverflowException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadUInt64()); - } - - [Theory] - [InlineData("c2")] - public static void ReadTag_NoSubsequentData_ShouldPeekEndOfData(string hexEncoding) - { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); - reader.ReadTag(); - Assert.Equal(CborReaderState.EndOfData, reader.Peek()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -219,11 +299,13 @@ public static void ReadTag_NoSubsequentData_ShouldPeekEndOfData(string hexEncodi [InlineData("fb3ff199999999999a")] // 1.1 public static void ReadInt64_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); - InvalidOperationException exn = Assert.Throws(() => reader.ReadInt64()); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + InvalidOperationException exn = Assert.Throws(() => reader.ReadInt64()); Assert.Equal("Data item major type mismatch.", exn.Message); + + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -234,57 +316,34 @@ public static void ReadInt64_InvalidTypes_ShouldThrowInvalidOperationException(s [InlineData("a0")] // {} [InlineData("f97e00")] // NaN [InlineData("fb3ff199999999999a")] // 1.1 - public static void ReadTag_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) + public static void ReadInt32_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); - InvalidOperationException exn = Assert.Throws(() => reader.ReadTag()); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + InvalidOperationException exn = Assert.Throws(() => reader.ReadInt32()); Assert.Equal("Data item major type mismatch.", exn.Message); - } - - [Fact] - public static void ReadTag_NestedTagWithMissingPayload_ShouldThrowFormatException() - { - byte[] data = "9fc2ff".HexToByteArray(); - var reader = new CborReader(data); - reader.ReadStartArray(); - reader.ReadTag(); - Assert.Equal(CborReaderState.FormatError, reader.Peek()); - Assert.Throws(() => reader.ReadEndArray()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] - [InlineData("8201c202")] // definite length array - [InlineData("9f01c202ff")] // equivalent indefinite-length array - public static void ReadTag_CallingEndReadArrayPrematurely_ShouldThrowInvalidOperationException(string hexEncoding) + [InlineData("40")] // empty text string + [InlineData("60")] // empty byte string + [InlineData("f6")] // null + [InlineData("80")] // [] + [InlineData("a0")] // {} + [InlineData("f97e00")] // NaN + [InlineData("fb3ff199999999999a")] // 1.1 + public static void ReadUInt32_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) { - // encoding is valid CBOR, so should not throw FormatException - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); - - reader.ReadStartArray(); - reader.ReadInt64(); - reader.ReadTag(); - Assert.Equal(CborReaderState.UnsignedInteger, reader.Peek()); - Assert.Throws(() => reader.ReadEndArray()); - } + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); - [Theory] - [InlineData("a102c202")] // definite length map - [InlineData("bf02c202ff")] // equivalent indefinite-length map - public static void ReadTag_CallingEndReadMapPrematurely_ShouldThrowInvalidOperationException(string hexEncoding) - { - // encoding is valid CBOR, so should not throw FormatException - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + InvalidOperationException exn = Assert.Throws(() => reader.ReadUInt32()); + Assert.Equal("Data item major type mismatch.", exn.Message); - reader.ReadStartMap(); - reader.ReadInt64(); - reader.ReadTag(); - Assert.Equal(CborReaderState.UnsignedInteger, reader.Peek()); - Assert.Throws(() => reader.ReadEndArray()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -297,12 +356,13 @@ public static void ReadTag_CallingEndReadMapPrematurely_ShouldThrowInvalidOperat [InlineData("fb3ff199999999999a")] // 1.1 public static void ReadUInt64_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); InvalidOperationException exn = Assert.Throws(() => reader.ReadUInt64()); - Assert.Equal("Data item major type mismatch.", exn.Message); + + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -317,12 +377,13 @@ public static void ReadUInt64_InvalidTypes_ShouldThrowInvalidOperationException( [InlineData("fb3ff199999999999a")] // 1.1 public static void ReadCborNegativeIntegerEncoding_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); InvalidOperationException exn = Assert.Throws(() => reader.ReadCborNegativeIntegerEncoding()); - Assert.Equal("Data item major type mismatch.", exn.Message); + + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -344,9 +405,11 @@ public static void ReadCborNegativeIntegerEncoding_InvalidTypes_ShouldThrowInval [InlineData("3b00000000000000")] public static void ReadInt64_InvalidData_ShouldThrowFormatException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadInt64()); + + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -361,10 +424,11 @@ public static void ReadInt64_InvalidData_ShouldThrowFormatException(string hexEn [InlineData("3b00000000000000")] public static void ReadCborNegativeIntegerEncoding_InvalidData_ShouldThrowFormatException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadCborNegativeIntegerEncoding()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -372,10 +436,11 @@ public static void ReadCborNegativeIntegerEncoding_InvalidData_ShouldThrowFormat [InlineData("3f")] public static void ReadInt64_IndefiniteLengthIntegers_ShouldThrowFormatException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadInt64()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Fact] @@ -385,6 +450,7 @@ public static void ReadUInt64_EmptyBuffer_ShouldThrowFormatException() var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadUInt64()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Fact] @@ -394,6 +460,7 @@ public static void ReadCborNegativeIntegerEncoding_EmptyBuffer_ShouldThrowFormat var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadCborNegativeIntegerEncoding()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Map.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Map.cs index 8c90149c5c91fe..565f443c34d069 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Map.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Map.cs @@ -4,10 +4,11 @@ #nullable enable using System; +using System.Linq; using Test.Cryptography; using Xunit; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor.Tests { public partial class CborReaderTests { @@ -26,7 +27,7 @@ public static void ReadMap_SimpleValues_HappyPath(object[] expectedValues, strin byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); Helpers.VerifyMap(reader, expectedValues); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -38,7 +39,7 @@ public static void ReadMap_NestedValues_HappyPath(object[] expectedValues, strin byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); Helpers.VerifyMap(reader, expectedValues); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -51,7 +52,7 @@ public static void ReadMap_NestedListValues_HappyPath(object expectedValue, stri byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); Helpers.VerifyValue(reader, expectedValue); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -59,14 +60,110 @@ public static void ReadMap_NestedListValues_HappyPath(object expectedValue, stri [InlineData(new object[] { Map, 1, 2, 3, 4 }, "bf01020304ff")] [InlineData(new object[] { Map, "a", "A", "b", "B", "c", "C", "d", "D", "e", "E" }, "bf6161614161626142616361436164614461656145ff")] [InlineData(new object[] { Map, "a", "A", -1, 2, new byte[] { }, new byte[] { 1 } }, "bf616161412002404101ff")] - public static void ReadMap_IndefiniteLength_SimpleValues_HappyPath(object[] exoectedValues, string hexEncoding) + public static void ReadMap_IndefiniteLength_SimpleValues_HappyPath(object[] expectedValues, string hexEncoding) { byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - Helpers.VerifyMap(reader, exoectedValues, expectDefiniteLengthCollections: false); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Helpers.VerifyMap(reader, expectedValues, expectDefiniteLengthCollections: false); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } + [Theory] + [InlineData(CborConformanceLevel.Lax, "bfff")] + [InlineData(CborConformanceLevel.Strict, "bfff")] + public static void ReadMap_IndefiniteLength_SupportedConformanceLevel_ShouldSucceed(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + int? length = reader.ReadStartMap(); + Assert.Null(length); + } + + [Theory] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "bfff")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "bfff")] + public static void ReadMap_IndefiniteLength_UnSupportedConformanceLevel_ShouldThrowFormatException(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + Assert.Throws(() => reader.ReadStartMap()); + Assert.Equal(0, reader.BytesRead); + } + + [Theory] + [InlineData(CborConformanceLevel.Lax, "b800")] + [InlineData(CborConformanceLevel.Lax, "b90000")] + [InlineData(CborConformanceLevel.Lax, "ba00000000")] + [InlineData(CborConformanceLevel.Lax, "bb0000000000000000")] + [InlineData(CborConformanceLevel.Strict, "b800")] + [InlineData(CborConformanceLevel.Strict, "b90000")] + [InlineData(CborConformanceLevel.Strict, "ba00000000")] + [InlineData(CborConformanceLevel.Strict, "bb0000000000000000")] + public static void ReadMap_NonCanonicalLengths_SupportedConformanceLevel_ShouldSucceed(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + int? length = reader.ReadStartMap(); + Assert.NotNull(length); + Assert.Equal(0, length!.Value); + reader.ReadEndMap(); + } + + [Theory] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "b800")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "b90000")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "ba00000000")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "bb0000000000000000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "b800")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "b90000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "ba00000000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "bb0000000000000000")] + public static void ReadMap_NonCanonicalLengths_UnSupportedConformanceLevel_ShouldThrowFormatException(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + Assert.Throws(() => reader.ReadStartMap()); + Assert.Equal(0, reader.BytesRead); + } + + [Theory] + [InlineData(CborConformanceLevel.Lax, new object[] { Map, 3, 3, 2, 2, 1, 1 }, "a3030302020101")] + [InlineData(CborConformanceLevel.Strict, new object[] { Map, 3, 3, 2, 2, 1, 1 }, "a3030302020101")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, new object[] { Map, 1, 1, 2, 2, 3, 3 }, "a3010102020303")] + [InlineData(CborConformanceLevel.Ctap2Canonical, new object[] { Map, 1, 1, 2, 2, 3, 3 }, "a3010102020303")] + // indefinite length string payload + [InlineData(CborConformanceLevel.Lax, new object[] { Map, "b", 0, 2, 0, "a", 0, new object[] { "c", "" }, 0, 1, 0 }, "a5616200020061610082616360000100")] + [InlineData(CborConformanceLevel.Strict, new object[] { Map, "b", 0, 2, 0, "a", 0, new object[] { "c", "" }, 0, 1, 0 }, "a5616200020061610082616360000100")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, new object[] { Map, 1, 0, 2, 0, "a", 0, "b", 0, new object[] { "c", "" }, 0 }, "a5010002006161006162008261636000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, new object[] { Map, 1, 0, 2, 0, "a", 0, "b", 0, new object[] { "c", "" }, 0 }, "a5010002006161006162008261636000")] + // CBOR sorting rules do not match canonical string sorting + [InlineData(CborConformanceLevel.Lax, new object[] { Map, "aa", 0, "z", 0 }, "a262616100617a00")] + [InlineData(CborConformanceLevel.Strict, new object[] { Map, "aa", 0, "z", 0 }, "a262616100617a00")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, new object[] { Map, "z", 0, "aa", 0 }, "a2617a0062616100")] + [InlineData(CborConformanceLevel.Ctap2Canonical, new object[] { Map, "z", 0, "aa", 0 }, "a2617a0062616100")] + // Test case distinguishing between RFC7049 and CTAP2 sorting rules + [InlineData(CborConformanceLevel.Lax, new object[] { Map, "", 0, 255, 0 }, "a2600018ff00")] + [InlineData(CborConformanceLevel.Strict, new object[] { Map, "", 0, 255, 0 }, "a2600018ff00")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, new object[] { Map, "", 0, 255, 0 }, "a2600018ff00")] + [InlineData(CborConformanceLevel.Ctap2Canonical, new object[] { Map, 255, 0, "", 0 }, "a218ff006000")] + public static void ReadMap_SimpleValues_ShouldAcceptKeysSortedAccordingToConformanceLevel(CborConformanceLevel level, object expectedValue, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + Helpers.VerifyValue(reader, expectedValue); + } + + [Theory] + [InlineData(CborConformanceLevel.Lax, new object[] { Map, -1, 0, new object[] { Map, 3, 3, 2, 2, 1, 1 }, 0, "a", 0, 256, 0, new object[] { Map, 2, 2, 1, 1 }, 0 }, "a52000a30303020201010061610019010000a20202010100")] + [InlineData(CborConformanceLevel.Strict, new object[] { Map, -1, 0, new object[] { Map, 3, 3, 2, 2, 1, 1 }, 0, "a", 0, 256, 0, new object[] { Map, 2, 2, 1, 1 }, 0 }, "a52000a30303020201010061610019010000a20202010100")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, new object[] { Map, -1, 0, "a", 0, 256, 0, new object[] { Map, 1, 1, 2, 2 }, 0, new object[] { Map, 1, 1, 2, 2, 3, 3 }, 0 }, "a5200061610019010000a20101020200a301010202030300")] + [InlineData(CborConformanceLevel.Ctap2Canonical, new object[] { Map, 256, 0, -1, 0, "a", 0, new object[] { Map, 1, 1, 2, 2 }, 0, new object[] { Map, 1, 1, 2, 2, 3, 3 }, 0 }, "a5190100002000616100a20101020200a301010202030300")] + public static void ReadMap_NestedValues_ShouldAcceptKeysSortedAccordingToConformanceLevel(CborConformanceLevel level, object expectedValue, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + Helpers.VerifyValue(reader, expectedValue); + } [Theory] [InlineData(new object[] { Map, "a", 1, "a", 2 }, "a2616101616102")] @@ -75,7 +172,82 @@ public static void ReadMap_DuplicateKeys_ShouldSucceed(object[] values, string h byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); Helpers.VerifyMap(reader, values); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData(CborConformanceLevel.Strict, 42, "a2182a01182a02")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, 42, "a2182a01182a02")] + [InlineData(CborConformanceLevel.Ctap2Canonical, 42, "a2182a01182a02")] + [InlineData(CborConformanceLevel.Strict, "foobar", "a266666f6f6261720166666f6f62617202")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "foobar", "a266666f6f6261720166666f6f62617202")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "foobar", "a266666f6f6261720166666f6f62617202")] + [InlineData(CborConformanceLevel.Strict, new object[] { new object[] { "x", "y" } }, "a28182617861790181826178617902")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, new object[] { new object[] { "x", "y" } }, "a28182617861790181826178617902")] + [InlineData(CborConformanceLevel.Ctap2Canonical, new object[] { new object[] { "x", "y" } }, "a28182617861790181826178617902")] + public static void ReadMap_DuplicateKeys_StrictConformance_ShouldThrowFormatException(CborConformanceLevel level, object dupeKey, string hexEncoding) + { + var reader = new CborReader(hexEncoding.HexToByteArray(), level); + reader.ReadStartMap(); + Helpers.VerifyValue(reader, dupeKey); + reader.ReadInt32(); + + int bytesRead = reader.BytesRead; + int bytesRemaining = reader.BytesRemaining; + CborReaderState state = reader.PeekState(); + + Assert.Throws(() => Helpers.VerifyValue(reader, dupeKey)); + + // ensure reader state is preserved + Assert.Equal(bytesRead, reader.BytesRead); + Assert.Equal(bytesRemaining, reader.BytesRemaining); + Assert.Equal(state, reader.PeekState()); + } + + [Theory] + [InlineData(CborConformanceLevel.Lax, new object[] { 1, 2, 3, 0 }, "a40101020203030000")] + [InlineData(CborConformanceLevel.Strict, new object[] { 1, 2, 3, 0 }, "a40101020203030000")] + [InlineData(CborConformanceLevel.Lax, new object[] { 1, "", 25, "a", 2 }, "a5010060001819006161000200")] + [InlineData(CborConformanceLevel.Strict, new object[] { 1, 25, "", "a", 2 }, "a5010018190060006161000200")] + public static void ReadMap_UnsortedKeys_ConformanceNotRequiringSortedKeys_ShouldSucceed(CborConformanceLevel level, object[] keySequence, string hexEncoding) + { + var reader = new CborReader(hexEncoding.HexToByteArray(), level); + reader.ReadStartMap(); + foreach (object key in keySequence) + { + Helpers.VerifyValue(reader, key); // verify key + reader.ReadInt32(); // value is always an integer + } + + reader.ReadEndMap(); + } + + [Theory] + [InlineData(CborConformanceLevel.Rfc7049Canonical, new object[] { 1, 2, 3, 0 }, "a40101020203030000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, new object[] { 1, 2, 3, 0 }, "a40101020203030000")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, new object[] { 1, "", 25, "a", 2 }, "a5010060001819006161000200")] + [InlineData(CborConformanceLevel.Ctap2Canonical, new object[] { 1, 25, "", "a", 2 }, "a5010018190060006161000200")] + public static void ReadMap_UnsortedKeys_ConformanceRequiringSortedKeys_ShouldThrowFormatException(CborConformanceLevel level, object[] keySequence, string hexEncoding) + { + var reader = new CborReader(hexEncoding.HexToByteArray(), level); + reader.ReadStartMap(); + foreach (object key in keySequence.SkipLast(1)) + { + Helpers.VerifyValue(reader, key); // verify key + reader.ReadInt32(); // value is always an integer + } + + int bytesRead = reader.BytesRead; + int bytesRemaining = reader.BytesRemaining; + CborReaderState state = reader.PeekState(); + + // the final element violates sorting invariant + Assert.Throws(() => Helpers.VerifyValue(reader, keySequence.Last())); + + // ensure reader state is preserved + Assert.Equal(bytesRead, reader.BytesRead); + Assert.Equal(bytesRemaining, reader.BytesRemaining); + Assert.Equal(state, reader.PeekState()); } [Theory] @@ -87,7 +259,7 @@ public static void ReadMap_DefiniteLengthExceeded_ShouldThrowInvalidOperationExc byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - ulong? length = reader.ReadStartMap(); + int? length = reader.ReadStartMap(); Assert.Equal(expectedLength, (int)length!.Value); for (int i = 0; i < expectedLength; i++) @@ -96,7 +268,9 @@ public static void ReadMap_DefiniteLengthExceeded_ShouldThrowInvalidOperationExc reader.ReadInt64(); // value } + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadInt64()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Theory] @@ -107,7 +281,7 @@ public static void ReadMap_DefiniteLengthExceeded_WithNestedData_ShouldThrowInva byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - ulong? length = reader.ReadStartMap(); + int? length = reader.ReadStartMap(); Assert.Equal(expectedLength, (int)length!.Value); for (int i = 0; i < expectedLength; i++) @@ -115,14 +289,16 @@ public static void ReadMap_DefiniteLengthExceeded_WithNestedData_ShouldThrowInva reader.ReadInt64(); // key // value - ulong? nestedLength = reader.ReadStartMap(); + int? nestedLength = reader.ReadStartMap(); Assert.Equal(1, (int)nestedLength!.Value); reader.ReadInt64(); reader.ReadInt64(); reader.ReadEndMap(); } + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadInt64()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Theory] @@ -133,8 +309,8 @@ public static void ReadEndMap_DefiniteLengthNotMet_ShouldThrowInvalidOperationEx byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - ulong? length = reader.ReadStartMap(); - Assert.Equal(expectedLength, (int)length!.Value); + int? length = reader.ReadStartMap(); + Assert.Equal(expectedLength, length!.Value); for (int i = 1; i < expectedLength; i++) { @@ -142,7 +318,9 @@ public static void ReadEndMap_DefiniteLengthNotMet_ShouldThrowInvalidOperationEx reader.ReadInt64(); // value } + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadEndMap()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Theory] @@ -153,21 +331,23 @@ public static void ReadEndMap_DefiniteLengthNotMet_WithNestedData_ShouldThrowInv byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - ulong? length = reader.ReadStartMap(); + int? length = reader.ReadStartMap(); Assert.Equal(expectedLength, (int)length!.Value); for (int i = 1; i < expectedLength; i++) { reader.ReadInt64(); // key - ulong? nestedLength = reader.ReadStartMap(); - Assert.Equal(1, (int)nestedLength!.Value); + int? nestedLength = reader.ReadStartMap(); + Assert.Equal(1, nestedLength!.Value); reader.ReadInt64(); reader.ReadInt64(); reader.ReadEndMap(); } + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadEndMap()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Theory] @@ -183,7 +363,9 @@ public static void ReadEndMap_ImbalancedCall_ShouldThrowInvalidOperationExceptio reader.ReadStartArray(); } + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadEndMap()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Theory] @@ -194,7 +376,7 @@ public static void ReadMap_IncorrectDefiniteLength_ShouldThrowFormatException(st byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - ulong? length = reader.ReadStartMap(); + int? length = reader.ReadStartMap(); Assert.Equal(expectedLength, (int)length!.Value); for (int i = 0; i < actualLength; i++) @@ -203,7 +385,9 @@ public static void ReadMap_IncorrectDefiniteLength_ShouldThrowFormatException(st reader.ReadInt64(); // value } + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadInt64()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Theory] @@ -215,12 +399,12 @@ public static void ReadMap_IndefiniteLength_MissingBreakByte_ShouldReportEndOfDa byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); reader.ReadStartMap(); - while (reader.Peek() == CborReaderState.UnsignedInteger) + while (reader.PeekState() == CborReaderState.UnsignedInteger) { reader.ReadInt64(); } - Assert.Equal(CborReaderState.EndOfData, reader.Peek()); + Assert.Equal(CborReaderState.EndOfData, reader.PeekState()); } [Theory] @@ -237,8 +421,12 @@ public static void ReadMap_IndefiniteLength_PrematureEndArrayCall_ShouldThrowInv reader.ReadInt64(); } - Assert.Equal(CborReaderState.UnsignedInteger, reader.Peek()); + int bytesRemaining = reader.BytesRemaining; + + Assert.Equal(CborReaderState.UnsignedInteger, reader.PeekState()); Assert.Throws(() => reader.ReadEndMap()); + + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Theory] @@ -255,8 +443,12 @@ public static void ReadMap_IndefiniteLength_OddKeyValuePairs_ShouldThrowFormatEx reader.ReadInt64(); } - Assert.Equal(CborReaderState.FormatError, reader.Peek()); // don't want this to fail + int bytesRemaining = reader.BytesRemaining; + + Assert.Equal(CborReaderState.FormatError, reader.PeekState()); // don't want this to fail Assert.Throws(() => reader.ReadEndMap()); + + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Theory] @@ -267,20 +459,22 @@ public static void ReadMap_IncorrectDefiniteLength_NestedValues_ShouldThrowForma byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - ulong? length = reader.ReadStartMap(); + int? length = reader.ReadStartMap(); Assert.Equal(expectedLength, (int)length!.Value); for (int i = 0; i < actualLength; i++) { reader.ReadInt64(); // key - ulong? innerLength = reader.ReadStartArray(); - Assert.Equal(1, (int)innerLength!.Value); + int? innerLength = reader.ReadStartArray(); + Assert.Equal(1, innerLength!.Value); reader.ReadInt64(); reader.ReadEndArray(); } + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadInt64()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Fact] @@ -289,7 +483,9 @@ public static void ReadStartMap_EmptyBuffer_ShouldThrowFormatException() byte[] encoding = Array.Empty(); var reader = new CborReader(encoding); + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadStartMap()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Theory] @@ -303,9 +499,11 @@ public static void ReadStartMap_EmptyBuffer_ShouldThrowFormatException() [InlineData("fb3ff199999999999a")] // 1.1 public static void ReadStartMap_InvalidType_ShouldThrowInvalidOperationException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Throws(() => reader.ReadStartMap()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -320,33 +518,25 @@ public static void ReadStartMap_InvalidType_ShouldThrowInvalidOperationException [InlineData("bb00000000000000")] public static void ReadStartMap_InvalidData_ShouldThrowFormatException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadStartMap()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] [InlineData("b1")] [InlineData("b20101")] - [InlineData("bb7fffffffffffffff")] // long.MaxValue - public static void ReadStartMap_BufferTooSmall_ShouldThrowFormatException(string hexEncoding) - { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); - - Assert.Throws(() => reader.ReadStartMap()); - } - - [Theory] [InlineData("bb8000000000000000")] // long.MaxValue + 1 [InlineData("bbffffffffffffffff")] // ulong.MaxValue - public static void ReadStartMap_LargeFieldCount_ShouldThrowOverflowException(string hexEncoding) + public static void ReadStartMap_BufferTooSmall_ShouldThrowFormatException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); - Assert.Throws(() => reader.ReadStartMap()); + Assert.Throws(() => reader.ReadStartMap()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Simple.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Simple.cs new file mode 100644 index 00000000000000..6a9f50aebb04a5 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Simple.cs @@ -0,0 +1,237 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable +using System; +using Test.Cryptography; +using Xunit; + +namespace System.Formats.Cbor.Tests +{ + public partial class CborReaderTests + { + // Data points taken from https://tools.ietf.org/html/rfc7049#appendix-A + // Additional pairs generated using http://cbor.me/ + + [Theory] + [InlineData(100000.0, "fa47c35000")] + [InlineData(3.4028234663852886e+38, "fa7f7fffff")] + [InlineData(float.PositiveInfinity, "fa7f800000")] + [InlineData(float.NegativeInfinity, "faff800000")] + [InlineData(float.NaN, "fa7fc00000")] + public static void ReadSingle_SingleValue_HappyPath(float expectedResult, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Equal(CborReaderState.SinglePrecisionFloat, reader.PeekState()); + float actualResult = reader.ReadSingle(); + Assert.Equal(expectedResult, actualResult); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData(1.1, "fb3ff199999999999a")] + [InlineData(1.0e+300, "fb7e37e43c8800759c")] + [InlineData(-4.1, "fbc010666666666666")] + [InlineData(3.1415926, "fb400921fb4d12d84a")] + [InlineData(double.PositiveInfinity, "fb7ff0000000000000")] + [InlineData(double.NegativeInfinity, "fbfff0000000000000")] + [InlineData(double.NaN, "fb7ff8000000000000")] + public static void ReadDouble_SingleValue_HappyPath(double expectedResult, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Equal(CborReaderState.DoublePrecisionFloat, reader.PeekState()); + double actualResult = reader.ReadDouble(); + Assert.Equal(expectedResult, actualResult); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData(100000.0, "fa47c35000")] + [InlineData(3.4028234663852886e+38, "fa7f7fffff")] + [InlineData(double.PositiveInfinity, "fa7f800000")] + [InlineData(double.NegativeInfinity, "faff800000")] + [InlineData(double.NaN, "fa7fc00000")] + public static void ReadDouble_SinglePrecisionValue_ShouldCoerceToDouble(double expectedResult, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Equal(CborReaderState.SinglePrecisionFloat, reader.PeekState()); + double actualResult = reader.ReadDouble(); + Assert.Equal(expectedResult, actualResult); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData(0.0, "f90000")] + [InlineData(-0.0, "f98000")] + [InlineData(1.0, "f93c00")] + [InlineData(1.5, "f93e00")] + [InlineData(65504.0, "f97bff")] + [InlineData(5.960464477539063e-8, "f90001")] + [InlineData(0.00006103515625, "f90400")] + [InlineData(-4.0, "f9c400")] + [InlineData(double.PositiveInfinity, "f97c00")] + [InlineData(double.NaN, "f97e00")] + [InlineData(double.NegativeInfinity, "f9fc00")] + public static void ReadDouble_HalfPrecisionValue_ShouldCoerceToDouble(double expectedResult, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Equal(CborReaderState.HalfPrecisionFloat, reader.PeekState()); + double actualResult = reader.ReadDouble(); + Assert.Equal(expectedResult, actualResult); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData(0.0, "f90000")] + [InlineData(-0.0, "f98000")] + [InlineData(1.0, "f93c00")] + [InlineData(1.5, "f93e00")] + [InlineData(65504.0, "f97bff")] + [InlineData(5.960464477539063e-8, "f90001")] + [InlineData(0.00006103515625, "f90400")] + [InlineData(-4.0, "f9c400")] + [InlineData(float.PositiveInfinity, "f97c00")] + [InlineData(float.NaN, "f97e00")] + [InlineData(float.NegativeInfinity, "f9fc00")] + public static void ReadSingle_HalfPrecisionValue_ShouldCoerceToSingle(float expectedResult, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Equal(CborReaderState.HalfPrecisionFloat, reader.PeekState()); + float actualResult = reader.ReadSingle(); + Assert.Equal(expectedResult, actualResult); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Fact] + public static void ReadNull_SingleValue_HappyPath() + { + byte[] encoding = "f6".HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Equal(CborReaderState.Null, reader.PeekState()); + reader.ReadNull(); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData(false, "f4")] + [InlineData(true, "f5")] + public static void ReadBoolean_SingleValue_HappyPath(bool expectedResult, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Equal(CborReaderState.Boolean, reader.PeekState()); + bool actualResult = reader.ReadBoolean(); + Assert.Equal(expectedResult, actualResult); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData((CborSimpleValue)0, "e0")] + [InlineData(CborSimpleValue.False, "f4")] + [InlineData(CborSimpleValue.True, "f5")] + [InlineData(CborSimpleValue.Null, "f6")] + [InlineData(CborSimpleValue.Undefined, "f7")] + [InlineData((CborSimpleValue)32, "f820")] + [InlineData((CborSimpleValue)255, "f8ff")] + public static void ReadSimpleValue_SingleValue_HappyPath(CborSimpleValue expectedResult, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + CborSimpleValue actualResult = reader.ReadSimpleValue(); + Assert.Equal(expectedResult, actualResult); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData("01")] // integer + [InlineData("40")] // empty text string + [InlineData("60")] // empty byte string + [InlineData("80")] // [] + [InlineData("a0")] // {} + [InlineData("c202")] // tagged value + public static void ReadSimpleValue_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Throws(() => reader.ReadSimpleValue()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("01")] // integer + [InlineData("40")] // empty text string + [InlineData("60")] // empty byte string + [InlineData("80")] // [] + [InlineData("a0")] // {} + [InlineData("f97e00")] // NaN + [InlineData("f6")] // null + [InlineData("fb3ff199999999999a")] // 1.1 + [InlineData("c202")] // tagged value + public static void ReadBoolean_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Throws(() => reader.ReadBoolean()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("01")] // integer + [InlineData("40")] // empty text string + [InlineData("60")] // empty byte string + [InlineData("80")] // [] + [InlineData("a0")] // {} + [InlineData("f4")] // false + [InlineData("f97e00")] // NaN + [InlineData("fb3ff199999999999a")] // 1.1 + [InlineData("c202")] // tagged value + public static void ReadNull_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Throws(() => reader.ReadNull()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("01")] // integer + [InlineData("40")] // empty text string + [InlineData("60")] // empty byte string + [InlineData("80")] // [] + [InlineData("a0")] // {} + [InlineData("f6")] // null + [InlineData("f4")] // false + [InlineData("c202")] // tagged value + public static void ReadSingle_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Throws(() => reader.ReadSingle()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("01")] // integer + [InlineData("40")] // empty text string + [InlineData("60")] // empty byte string + [InlineData("80")] // [] + [InlineData("a0")] // {} + [InlineData("f6")] // null + [InlineData("f4")] // false + [InlineData("c202")] // tagged value + public static void ReadDouble_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Throws(() => reader.ReadDouble()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + } +} diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.SkipValue.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.SkipValue.cs index 5bd163de8b995d..0f84dbfc406c3c 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.SkipValue.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.SkipValue.cs @@ -10,7 +10,7 @@ using Test.Cryptography; using Xunit; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor.Tests { public partial class CborReaderTests { @@ -22,7 +22,7 @@ public static void SkipValue_RootValue_HappyPath(string hexEncoding) var reader = new CborReader(encoding); reader.SkipValue(); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -37,7 +37,7 @@ public static void SkipValue_NestedValue_HappyPath(string hexEncoding) reader.SkipValue(); reader.ReadInt64(); reader.ReadEndArray(); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -49,7 +49,7 @@ public static void SkipValue_TaggedValue_HappyPath(string hexEncoding) reader.ReadTag(); reader.SkipValue(); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Fact] @@ -59,7 +59,10 @@ public static void SkipValue_NotAtValue_ShouldThrowInvalidOperationException() var reader = new CborReader(encoding); reader.ReadStartArray(); + + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.SkipValue()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Theory] @@ -70,19 +73,184 @@ public static void SkipValue_InvalidFormat_ShouldThrowFormatException(string hex var reader = new CborReader(encoding); Assert.Throws(() => reader.SkipValue()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("61ff")] + [InlineData("62f090")] + public static void SkipValue_InvalidUtf8_ShouldSucceed(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + reader.SkipValue(); + + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] [InlineData("61ff")] [InlineData("62f090")] - public static void SkipValue_InvalidUtf8_ShouldThrowFormatException(string hexEncoding) + public static void SkipValue_ValidationEnabled_InvalidUtf8_ShouldThrowFormatException(string hexEncoding) { byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - FormatException exn = Assert.Throws(() => reader.SkipValue()); + FormatException exn = Assert.Throws(() => reader.SkipValue(validateConformance: true)); Assert.NotNull(exn.InnerException); Assert.IsType(exn.InnerException); + + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [MemberData(nameof(NonConformingSkipValueEncodings))] + public static void SkipValue_NonConformingValues_ShouldSucceed(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + + reader.SkipValue(); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [MemberData(nameof(NonConformingSkipValueEncodings))] + public static void SkipValue_ValidationEnabled_NonConformingValues_ShouldThrowFormatException(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + + Assert.Throws(() => reader.SkipValue(validateConformance: true)); + } + + public static IEnumerable NonConformingSkipValueEncodings => + new (CborConformanceLevel Level, string Encoding)[] + { + (CborConformanceLevel.Ctap2Canonical, "1801"), // non-canonical integer representation + (CborConformanceLevel.Rfc7049Canonical, "5fff"), // indefinite-length byte string + (CborConformanceLevel.Rfc7049Canonical, "7fff"), // indefinite-length text string + (CborConformanceLevel.Rfc7049Canonical, "9fff"), // indefinite-length array + (CborConformanceLevel.Rfc7049Canonical, "bfff"), // indefinite-length map + (CborConformanceLevel.Strict, "a201020103"), // duplicate keys in map + (CborConformanceLevel.Rfc7049Canonical, "a201020103"), // duplicate keys in map + (CborConformanceLevel.Ctap2Canonical, "a202020101"), // unsorted keys in map + (CborConformanceLevel.Ctap2Canonical, "c001"), // tagged value + }.Select(l => new object[] { l.Level, l.Encoding }); + + [Fact] + public static void SkipValue_SkippedValueFollowedByNonConformingValue_ShouldThrowFormatException() + { + byte[] encoding = "827fff7fff".HexToByteArray(); + var reader = new CborReader(encoding, CborConformanceLevel.Ctap2Canonical); + + reader.ReadStartArray(); + reader.SkipValue(); + Assert.Throws(() => reader.ReadTextString()); + } + + [Fact] + public static void SkipValue_NestedFormatException_ShouldPreserveOriginalReaderState() + { + string hexEncoding = "820181bf01ff"; // [1, [ {_ 1 : } ]] + var reader = new CborReader(hexEncoding.HexToByteArray()); + + reader.ReadStartArray(); + reader.ReadInt64(); + + // capture current state + int currentBytesRead = reader.BytesRead; + int currentBytesRemaining = reader.BytesRemaining; + + // make failing call + int bytesRemaining = reader.BytesRemaining; + Assert.Throws(() => reader.SkipValue()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); + + // ensure reader state has reverted to original + Assert.Equal(reader.BytesRead, currentBytesRead); + Assert.Equal(reader.BytesRemaining, currentBytesRemaining); + + // ensure we can read every value up to the format error + Assert.Equal(CborReaderState.StartArray, reader.PeekState()); + reader.ReadStartArray(); + Assert.Equal(CborReaderState.StartMap, reader.PeekState()); + reader.ReadStartMap(); + Assert.Equal(CborReaderState.UnsignedInteger, reader.PeekState()); + reader.ReadUInt64(); + Assert.Equal(CborReaderState.FormatError, reader.PeekState()); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + public static void SkipToParent_SimpleArray_HappyPath(int skipOffset) + { + byte[] encoding = "83010203".HexToByteArray(); // [1, 2, 3] + var reader = new CborReader(encoding); + + reader.ReadStartArray(); + for (int i = 0; i < skipOffset; i++) + { + reader.ReadInt32(); + } + + reader.SkipToParent(); + + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + public static void SkipToParent_NestedArray_HappyPath(int skipOffset) + { + byte[] encoding = "8283010203a0".HexToByteArray(); // [[1, 2, 3], { }] + var reader = new CborReader(encoding); + + reader.ReadStartArray(); + reader.ReadStartArray(); + for (int i = 0; i < skipOffset; i++) + { + reader.ReadInt32(); + } + + reader.SkipToParent(); + Assert.Equal(CborReaderState.StartMap, reader.PeekState()); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + public static void SkipToParent_NestedKey_HappyPath(int skipOffset) + { + byte[] encoding = "a17f616161626163ff80".HexToByteArray(); // { (_ "a", "b", "c") : [] } + var reader = new CborReader(encoding); + + reader.ReadStartMap(); + reader.ReadStartTextStringIndefiniteLength(); + for (int i = 0; i < skipOffset; i++) + { + reader.ReadTextString(); + } + + reader.SkipToParent(); + Assert.Equal(CborReaderState.StartArray, reader.PeekState()); + } + + [Fact] + public static void SkipToParent_RootContext_ShouldThrowInvalidOperationException() + { + byte[] encoding = "01".HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Throws(() => reader.SkipToParent()); + reader.ReadInt32(); + Assert.Throws(() => reader.SkipToParent()); } [Theory] @@ -99,7 +267,7 @@ public static void SkipValue_ExtremelyNestedValues_ShouldNotStackOverflow(int de var reader = new CborReader(encoding); reader.SkipValue(); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } public static IEnumerable SkipTestInputs => SampleCborValues.Select(x => new [] { x }); diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Special.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Special.cs deleted file mode 100644 index f33caae979f9d3..00000000000000 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Special.cs +++ /dev/null @@ -1,233 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable enable -using System; -using Test.Cryptography; -using Xunit; - -namespace System.Security.Cryptography.Encoding.Tests.Cbor -{ - public partial class CborReaderTests - { - // Data points taken from https://tools.ietf.org/html/rfc7049#appendix-A - // Additional pairs generated using http://cbor.me/ - - [Theory] - [InlineData(100000.0, "fa47c35000")] - [InlineData(3.4028234663852886e+38, "fa7f7fffff")] - [InlineData(float.PositiveInfinity, "fa7f800000")] - [InlineData(float.NegativeInfinity, "faff800000")] - [InlineData(float.NaN, "fa7fc00000")] - internal static void ReadSingle_SingleValue_HappyPath(float expectedResult, string hexEncoding) - { - byte[] encoding = hexEncoding.HexToByteArray(); - var reader = new CborReader(encoding); - Assert.Equal(CborReaderState.SinglePrecisionFloat, reader.Peek()); - float actualResult = reader.ReadSingle(); - Assert.Equal(expectedResult, actualResult); - Assert.Equal(CborReaderState.Finished, reader.Peek()); - } - - [Theory] - [InlineData(1.1, "fb3ff199999999999a")] - [InlineData(1.0e+300, "fb7e37e43c8800759c")] - [InlineData(-4.1, "fbc010666666666666")] - [InlineData(3.1415926, "fb400921fb4d12d84a")] - [InlineData(double.PositiveInfinity, "fb7ff0000000000000")] - [InlineData(double.NegativeInfinity, "fbfff0000000000000")] - [InlineData(double.NaN, "fb7ff8000000000000")] - internal static void ReadDouble_SingleValue_HappyPath(double expectedResult, string hexEncoding) - { - byte[] encoding = hexEncoding.HexToByteArray(); - var reader = new CborReader(encoding); - Assert.Equal(CborReaderState.DoublePrecisionFloat, reader.Peek()); - double actualResult = reader.ReadDouble(); - Assert.Equal(expectedResult, actualResult); - Assert.Equal(CborReaderState.Finished, reader.Peek()); - } - - [Theory] - [InlineData(100000.0, "fa47c35000")] - [InlineData(3.4028234663852886e+38, "fa7f7fffff")] - [InlineData(double.PositiveInfinity, "fa7f800000")] - [InlineData(double.NegativeInfinity, "faff800000")] - [InlineData(double.NaN, "fa7fc00000")] - internal static void ReadDouble_SinglePrecisionValue_ShouldCoerceToDouble(double expectedResult, string hexEncoding) - { - byte[] encoding = hexEncoding.HexToByteArray(); - var reader = new CborReader(encoding); - Assert.Equal(CborReaderState.SinglePrecisionFloat, reader.Peek()); - double actualResult = reader.ReadDouble(); - Assert.Equal(expectedResult, actualResult); - Assert.Equal(CborReaderState.Finished, reader.Peek()); - } - - [Theory] - [InlineData(0.0, "f90000")] - [InlineData(-0.0, "f98000")] - [InlineData(1.0, "f93c00")] - [InlineData(1.5, "f93e00")] - [InlineData(65504.0, "f97bff")] - [InlineData(5.960464477539063e-8, "f90001")] - [InlineData(0.00006103515625, "f90400")] - [InlineData(-4.0, "f9c400")] - [InlineData(double.PositiveInfinity, "f97c00")] - [InlineData(double.NaN, "f97e00")] - [InlineData(double.NegativeInfinity, "f9fc00")] - internal static void ReadDouble_HalfPrecisionValue_ShouldCoerceToDouble(double expectedResult, string hexEncoding) - { - byte[] encoding = hexEncoding.HexToByteArray(); - var reader = new CborReader(encoding); - Assert.Equal(CborReaderState.HalfPrecisionFloat, reader.Peek()); - double actualResult = reader.ReadDouble(); - Assert.Equal(expectedResult, actualResult); - Assert.Equal(CborReaderState.Finished, reader.Peek()); - } - - [Theory] - [InlineData(0.0, "f90000")] - [InlineData(-0.0, "f98000")] - [InlineData(1.0, "f93c00")] - [InlineData(1.5, "f93e00")] - [InlineData(65504.0, "f97bff")] - [InlineData(5.960464477539063e-8, "f90001")] - [InlineData(0.00006103515625, "f90400")] - [InlineData(-4.0, "f9c400")] - [InlineData(float.PositiveInfinity, "f97c00")] - [InlineData(float.NaN, "f97e00")] - [InlineData(float.NegativeInfinity, "f9fc00")] - internal static void ReadSingle_HalfPrecisionValue_ShouldCoerceToSingle(float expectedResult, string hexEncoding) - { - byte[] encoding = hexEncoding.HexToByteArray(); - var reader = new CborReader(encoding); - Assert.Equal(CborReaderState.HalfPrecisionFloat, reader.Peek()); - float actualResult = reader.ReadSingle(); - Assert.Equal(expectedResult, actualResult); - Assert.Equal(CborReaderState.Finished, reader.Peek()); - } - - [Fact] - internal static void ReadNull_SingleValue_HappyPath() - { - byte[] encoding = "f6".HexToByteArray(); - var reader = new CborReader(encoding); - Assert.Equal(CborReaderState.Null, reader.Peek()); - reader.ReadNull(); - Assert.Equal(CborReaderState.Finished, reader.Peek()); - } - - [Theory] - [InlineData(false, "f4")] - [InlineData(true, "f5")] - internal static void ReadBoolean_SingleValue_HappyPath(bool expectedResult, string hexEncoding) - { - byte[] encoding = hexEncoding.HexToByteArray(); - var reader = new CborReader(encoding); - Assert.Equal(CborReaderState.Boolean, reader.Peek()); - bool actualResult = reader.ReadBoolean(); - Assert.Equal(expectedResult, actualResult); - Assert.Equal(CborReaderState.Finished, reader.Peek()); - } - - [Theory] - [InlineData((CborSpecialValue)0, "e0")] - [InlineData(CborSpecialValue.False, "f4")] - [InlineData(CborSpecialValue.True, "f5")] - [InlineData(CborSpecialValue.Null, "f6")] - [InlineData(CborSpecialValue.Undefined, "f7")] - [InlineData((CborSpecialValue)32, "f820")] - [InlineData((CborSpecialValue)255, "f8ff")] - internal static void ReadSpecialValue_SingleValue_HappyPath(CborSpecialValue expectedResult, string hexEncoding) - { - byte[] encoding = hexEncoding.HexToByteArray(); - var reader = new CborReader(encoding); - CborSpecialValue actualResult = reader.ReadSpecialValue(); - Assert.Equal(expectedResult, actualResult); - Assert.Equal(CborReaderState.Finished, reader.Peek()); - } - - [Theory] - [InlineData("01")] // integer - [InlineData("40")] // empty text string - [InlineData("60")] // empty byte string - [InlineData("80")] // [] - [InlineData("a0")] // {} - [InlineData("c202")] // tagged value - public static void ReadSpecialValue_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) - { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); - InvalidOperationException exn = Assert.Throws(() => reader.ReadSpecialValue()); - - Assert.Equal("Data item major type mismatch.", exn.Message); - } - - [Theory] - [InlineData("01")] // integer - [InlineData("40")] // empty text string - [InlineData("60")] // empty byte string - [InlineData("80")] // [] - [InlineData("a0")] // {} - [InlineData("f97e00")] // NaN - [InlineData("f6")] // null - [InlineData("fb3ff199999999999a")] // 1.1 - [InlineData("c202")] // tagged value - public static void ReadBoolean_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) - { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); - Assert.Throws(() => reader.ReadBoolean()); - } - - [Theory] - [InlineData("01")] // integer - [InlineData("40")] // empty text string - [InlineData("60")] // empty byte string - [InlineData("80")] // [] - [InlineData("a0")] // {} - [InlineData("f4")] // false - [InlineData("f97e00")] // NaN - [InlineData("fb3ff199999999999a")] // 1.1 - [InlineData("c202")] // tagged value - public static void ReadNull_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) - { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); - Assert.Throws(() => reader.ReadNull()); - } - - [Theory] - [InlineData("01")] // integer - [InlineData("40")] // empty text string - [InlineData("60")] // empty byte string - [InlineData("80")] // [] - [InlineData("a0")] // {} - [InlineData("f6")] // null - [InlineData("f4")] // false - [InlineData("c202")] // tagged value - public static void ReadSingle_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) - { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); - Assert.Throws(() => reader.ReadSingle()); - } - - [Theory] - [InlineData("01")] // integer - [InlineData("40")] // empty text string - [InlineData("60")] // empty byte string - [InlineData("80")] // [] - [InlineData("a0")] // {} - [InlineData("f6")] // null - [InlineData("f4")] // false - [InlineData("c202")] // tagged value - public static void ReadDouble_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) - { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); - Assert.Throws(() => reader.ReadDouble()); - } - } -} diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.String.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.String.cs index 50ad86d04c78fb..45c1bb1eecde9a 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.String.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.String.cs @@ -9,7 +9,7 @@ using Test.Cryptography; using Xunit; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor.Tests { public partial class CborReaderTests { @@ -26,7 +26,7 @@ public static void ReadByteString_SingleValue_HappyPath(string hexExpectedValue, var reader = new CborReader(encoding); byte[] output = reader.ReadByteString(); Assert.Equal(expectedValue, output); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -43,7 +43,7 @@ public static void TryReadByteString_SingleValue_HappyPath(string hexExpectedVal Assert.True(result); Assert.Equal(expectedValue.Length, bytesWritten); Assert.Equal(expectedValue, buffer[..bytesWritten]); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -61,7 +61,7 @@ public static void ReadTextString_SingleValue_HappyPath(string expectedValue, st var reader = new CborReader(data); string actualResult = reader.ReadTextString(); Assert.Equal(expectedValue, actualResult); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -82,7 +82,7 @@ public static void TryReadTextString_SingleValue_HappyPath(string expectedValue, Assert.True(result); Assert.Equal(expectedValue.Length, charsWritten); Assert.Equal(expectedValue.ToCharArray(), buffer[..charsWritten]); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -107,10 +107,10 @@ public static void ReadByteString_IndefiniteLengthConcatenated_SingleValue_Happy { byte[] data = hexEncoding.HexToByteArray(); var reader = new CborReader(data); - Assert.Equal(CborReaderState.StartByteString, reader.Peek()); + Assert.Equal(CborReaderState.StartByteString, reader.PeekState()); byte[] actualValue = reader.ReadByteString(); Assert.Equal(expectedHexValue.ToUpper(), actualValue.ByteArrayToHex()); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -122,7 +122,7 @@ public static void TryReadByteString_IndefiniteLengthConcatenated_SingleValue_Ha { byte[] data = hexEncoding.HexToByteArray(); var reader = new CborReader(data); - Assert.Equal(CborReaderState.StartByteString, reader.Peek()); + Assert.Equal(CborReaderState.StartByteString, reader.PeekState()); Span buffer = new byte[32]; bool result = reader.TryReadByteString(buffer, out int bytesWritten); @@ -130,7 +130,7 @@ public static void TryReadByteString_IndefiniteLengthConcatenated_SingleValue_Ha Assert.True(result); Assert.Equal(expectedHexValue.Length / 2, bytesWritten); Assert.Equal(expectedHexValue.ToUpper(), buffer.Slice(0, bytesWritten).ByteArrayToHex()); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Fact] @@ -143,7 +143,7 @@ public static void ReadByteString_IndefiniteLengthConcatenated_NestedValues_Happ Assert.Equal("AB", reader.ReadByteString().ByteArrayToHex()); Assert.Equal("AB", reader.ReadByteString().ByteArrayToHex()); reader.ReadEndArray(); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -167,10 +167,10 @@ public static void ReadTextString_IndefiniteLengthConcatenated_SingleValue_Happy { byte[] data = hexEncoding.HexToByteArray(); var reader = new CborReader(data); - Assert.Equal(CborReaderState.StartTextString, reader.Peek()); + Assert.Equal(CborReaderState.StartTextString, reader.PeekState()); string actualValue = reader.ReadTextString(); Assert.Equal(expectedValue, actualValue); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Fact] @@ -183,7 +183,7 @@ public static void ReadTextString_IndefiniteLengthConcatenated_NestedValues_Happ Assert.Equal("ab", reader.ReadTextString()); Assert.Equal("ab", reader.ReadTextString()); reader.ReadEndArray(); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -195,7 +195,7 @@ public static void TryReadTextString_IndefiniteLengthConcatenated_SingleValue__H { byte[] data = hexEncoding.HexToByteArray(); var reader = new CborReader(data); - Assert.Equal(CborReaderState.StartTextString, reader.Peek()); + Assert.Equal(CborReaderState.StartTextString, reader.PeekState()); Span buffer = new char[32]; bool result = reader.TryReadTextString(buffer, out int charsWritten); @@ -203,7 +203,7 @@ public static void TryReadTextString_IndefiniteLengthConcatenated_SingleValue__H Assert.True(result); Assert.Equal(expectedValue.Length, charsWritten); Assert.Equal(expectedValue, new string(buffer.Slice(0, charsWritten))); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); } [Theory] @@ -295,6 +295,164 @@ public static void TryReadTextString_IndefiniteLengthConcatenated_BufferTooSmall Assert.Equal(expectedValue, new string(buffer.AsSpan(0, charsWritten))); } + [Theory] + [InlineData(CborConformanceLevel.Lax, "5800")] + [InlineData(CborConformanceLevel.Lax, "590000")] + [InlineData(CborConformanceLevel.Lax, "5a00000000")] + [InlineData(CborConformanceLevel.Lax, "5b0000000000000000")] + [InlineData(CborConformanceLevel.Strict, "5800")] + [InlineData(CborConformanceLevel.Strict, "590000")] + [InlineData(CborConformanceLevel.Strict, "5a00000000")] + [InlineData(CborConformanceLevel.Strict, "5b0000000000000000")] + public static void ReadByteString_NonCanonicalLengths_SupportedConformanceLevel_ShouldSucceed(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + byte[] value = reader.ReadByteString(); + Assert.Equal(Array.Empty(), value); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "5800")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "590000")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "5a00000000")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "5b0000000000000000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "5800")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "590000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "5a00000000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "5b0000000000000000")] + public static void ReadByteString_NonCanonicalLengths_UnSupportedConformanceLevel_ShouldThrowFormatException(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + Assert.Throws(() => reader.ReadByteString()); + Assert.Equal(0, reader.BytesRead); + } + + [Theory] + [InlineData(CborConformanceLevel.Lax, "7800")] + [InlineData(CborConformanceLevel.Lax, "790000")] + [InlineData(CborConformanceLevel.Lax, "7a00000000")] + [InlineData(CborConformanceLevel.Lax, "7b0000000000000000")] + [InlineData(CborConformanceLevel.Strict, "7800")] + [InlineData(CborConformanceLevel.Strict, "790000")] + [InlineData(CborConformanceLevel.Strict, "7a00000000")] + [InlineData(CborConformanceLevel.Strict, "7b0000000000000000")] + public static void ReadTextString_NonCanonicalLengths_SupportedConformanceLevel_ShouldSucceed(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + string value = reader.ReadTextString(); + Assert.Equal("", value); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "7800")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "790000")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "7a00000000")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "7b0000000000000000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "7800")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "790000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "7a00000000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "7b0000000000000000")] + public static void ReadTextString_NonCanonicalLengths_UnSupportedConformanceLevel_ShouldThrowFormatException(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + Assert.Throws(() => reader.ReadTextString()); + Assert.Equal(0, reader.BytesRead); + } + + [Theory] + [InlineData(CborConformanceLevel.Lax, "5f40ff")] + [InlineData(CborConformanceLevel.Strict, "5f40ff")] + public static void ReadByteString_IndefiniteLength_SupportedConformanceLevel_ShouldSucceed(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + reader.ReadStartByteStringIndefiniteLength(); + reader.ReadByteString(); + reader.ReadEndByteStringIndefiniteLength(); + } + + [Theory] + [InlineData(CborConformanceLevel.Lax, "5f40ff")] + [InlineData(CborConformanceLevel.Strict, "5f40ff")] + public static void ReadByteString_IndefiniteLength_AsSingleItem_SupportedConformanceLevel_ShouldSucceed(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + reader.ReadByteString(); + } + + [Theory] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "5f40ff")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "5f40ff")] + public static void ReadByteString_IndefiniteLength_UnSupportedConformanceLevel_ShouldThrowFormatExceptoin(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + Assert.Throws(() => reader.ReadStartByteStringIndefiniteLength()); + Assert.Equal(0, reader.BytesRead); + } + + [Theory] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "5f40ff")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "5f40ff")] + public static void ReadByteString_IndefiniteLength_AsSingleItem_UnSupportedConformanceLevel_ShouldThrowFormatException(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + Assert.Throws(() => reader.ReadByteString()); + Assert.Equal(0, reader.BytesRead); + } + + [Theory] + [InlineData(CborConformanceLevel.Lax, "7f60ff")] + [InlineData(CborConformanceLevel.Strict, "7f60ff")] + public static void ReadTextString_IndefiniteLength_SupportedConformanceLevel_ShouldSucceed(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + reader.ReadStartTextStringIndefiniteLength(); + reader.ReadTextString(); + reader.ReadEndTextStringIndefiniteLength(); + } + + [Theory] + [InlineData(CborConformanceLevel.Lax, "7f60ff")] + [InlineData(CborConformanceLevel.Strict, "7f60ff")] + public static void ReadTextString_IndefiniteLength_AsSingleItem_SupportedConformanceLevel_ShouldSucceed(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + reader.ReadTextString(); + } + + [Theory] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "7f60ff")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "7f60ff")] + public static void ReadTextString_IndefiniteLength_UnSupportedConformanceLevel_ShouldThrowFormatExceptoin(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + Assert.Throws(() => reader.ReadStartTextStringIndefiniteLength()); + Assert.Equal(0, reader.BytesRead); + } + + [Theory] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "7f60ff")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "7f60ff")] + public static void ReadTextString_IndefiniteLength_AsSingleItem_UnSupportedConformanceLevel_ShouldThrowFormatException(CborConformanceLevel level, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding, level); + Assert.Throws(() => reader.ReadTextString()); + Assert.Equal(0, reader.BytesRead); + } + [Theory] [InlineData("00")] // 0 [InlineData("20")] // -1 @@ -306,10 +464,11 @@ public static void TryReadTextString_IndefiniteLengthConcatenated_BufferTooSmall [InlineData("fb3ff199999999999a")] // 1.1 public static void ReadByteString_InvalidType_ShouldThrowInvalidOperationException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadByteString()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -323,10 +482,11 @@ public static void ReadByteString_InvalidType_ShouldThrowInvalidOperationExcepti [InlineData("fb3ff199999999999a")] // 1.1 public static void ReadTextString_InvalidType_ShouldThrowInvalidOperationException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadTextString()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -340,11 +500,12 @@ public static void ReadTextString_InvalidType_ShouldThrowInvalidOperationExcepti [InlineData("fb3ff199999999999a")] // 1.1 public static void TryReadByteString_InvalidType_ShouldThrowInvalidOperationException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); + byte[] encoding = hexEncoding.HexToByteArray(); byte[] buffer = new byte[32]; - var reader = new CborReader(data); + var reader = new CborReader(encoding); Assert.Throws(() => reader.TryReadByteString(buffer, out int _)); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -358,11 +519,12 @@ public static void TryReadByteString_InvalidType_ShouldThrowInvalidOperationExce [InlineData("fb3ff199999999999a")] // 1.1 public static void TryReadTextString_InvalidType_ShouldThrowInvalidOperationException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); + byte[] encoding = hexEncoding.HexToByteArray(); char[] buffer = new char[32]; - var reader = new CborReader(data); + var reader = new CborReader(encoding); Assert.Throws(() => reader.TryReadTextString(buffer, out int _)); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -383,9 +545,10 @@ public static void TryReadTextString_InvalidType_ShouldThrowInvalidOperationExce [InlineData("5a00010000ff")] public static void ReadByteString_InvalidData_ShouldThrowFormatException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadByteString()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -406,9 +569,10 @@ public static void ReadByteString_InvalidData_ShouldThrowFormatException(string [InlineData("7a00010000ff")] public static void ReadTextString_InvalidData_ShouldThrowFormatException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadTextString()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -429,11 +593,12 @@ public static void ReadTextString_InvalidData_ShouldThrowFormatException(string [InlineData("5a00010000ff")] public static void TryReadByteString_InvalidData_ShouldThrowFormatException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); + byte[] encoding = hexEncoding.HexToByteArray(); byte[] buffer = new byte[32]; - var reader = new CborReader(data); + var reader = new CborReader(encoding); Assert.Throws(() => reader.TryReadByteString(buffer, out int _)); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -467,9 +632,10 @@ public static void TryReadTextString_InvalidData_ShouldThrowFormatException(stri [InlineData("5bffffffffffffffff")] public static void ReadByteString_StringLengthTooLarge_ShouldThrowOverflowException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadByteString()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -478,9 +644,10 @@ public static void ReadByteString_StringLengthTooLarge_ShouldThrowOverflowExcept [InlineData("7bffffffffffffffff")] public static void ReadTextString_StringLengthTooLarge_ShouldThrowOverflowException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadTextString()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -488,11 +655,12 @@ public static void ReadTextString_StringLengthTooLarge_ShouldThrowOverflowExcept [InlineData("62f090")] public static void ReadTextString_InvalidUnicode_ShouldThrowFormatException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); FormatException exn = Assert.Throws(() => reader.ReadTextString()); Assert.NotNull(exn.InnerException); Assert.IsType(exn.InnerException); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Theory] @@ -500,13 +668,14 @@ public static void ReadTextString_InvalidUnicode_ShouldThrowFormatException(stri [InlineData("62f090")] public static void TryReadTextString_InvalidUnicode_ShouldThrowFormatException(string hexEncoding) { - byte[] data = hexEncoding.HexToByteArray(); + byte[] encoding = hexEncoding.HexToByteArray(); char[] buffer = new char[32]; - var reader = new CborReader(data); + var reader = new CborReader(encoding); FormatException exn = Assert.Throws(() => reader.TryReadTextString(buffer, out int _)); Assert.NotNull(exn.InnerException); Assert.IsType(exn.InnerException); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Fact] @@ -516,6 +685,7 @@ public static void ReadTextString_EmptyBuffer_ShouldThrowFormatException() var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadTextString()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Fact] @@ -525,96 +695,109 @@ public static void ReadByteString_EmptyBuffer_ShouldThrowFormatException() var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadByteString()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Fact] public static void ReadByteString_IndefiniteLength_ContainingInvalidMajorTypes_ShouldThrowFormatException() { string hexEncoding = "5f4001ff"; - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); reader.ReadStartByteStringIndefiniteLength(); reader.ReadByteString(); - Assert.Equal(CborReaderState.FormatError, reader.Peek()); + int bytesRemaining = reader.BytesRemaining; + Assert.Equal(CborReaderState.FormatError, reader.PeekState()); // throws FormatException even if it's the right major type we're trying to read Assert.Throws(() => reader.ReadInt64()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Fact] public static void ReadTextString_IndefiniteLength_ContainingInvalidMajorTypes_ShouldThrowFormatException() { string hexEncoding = "7f6001ff"; - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); reader.ReadStartTextStringIndefiniteLength(); reader.ReadTextString(); - Assert.Equal(CborReaderState.FormatError, reader.Peek()); + int bytesRemaining = reader.BytesRemaining; + Assert.Equal(CborReaderState.FormatError, reader.PeekState()); // throws FormatException even if it's the right major type we're trying to read Assert.Throws(() => reader.ReadInt64()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Fact] public static void ReadByteString_IndefiniteLength_ContainingNestedIndefiniteLengthStrings_ShouldThrowFormatException() { string hexEncoding = "5f5fffff"; - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); reader.ReadStartByteStringIndefiniteLength(); + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadStartByteStringIndefiniteLength()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Fact] public static void ReadByteString_IndefiniteLengthConcatenated_ContainingNestedIndefiniteLengthStrings_ShouldThrowFormatException() { string hexEncoding = "5f5fffff"; - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadByteString()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Fact] public static void ReadTextString_IndefiniteLength_ContainingNestedIndefiniteLengthStrings_ShouldThrowFormatException() { string hexEncoding = "7f7fffff"; - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); reader.ReadStartTextStringIndefiniteLength(); + int bytesRemaining = reader.BytesRemaining; Assert.Throws(() => reader.ReadStartTextStringIndefiniteLength()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); } [Fact] public static void ReadTextString_IndefiniteLengthConcatenated_ContainingNestedIndefiniteLengthStrings_ShouldThrowFormatException() { string hexEncoding = "7f7fffff"; - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadTextString()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Fact] public static void ReadByteString_IndefiniteLengthConcatenated_ContainingInvalidMajorTypes_ShouldThrowFormatException() { string hexEncoding = "5f4001ff"; - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadByteString()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Fact] public static void ReadTextString_IndefiniteLengthConcatenated_ContainingInvalidMajorTypes_ShouldThrowFormatException() { string hexEncoding = "7f6001ff"; - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadTextString()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } [Fact] @@ -624,9 +807,10 @@ public static void ReadTextString_IndefiniteLengthConcatenated_InvalidUtf8Chunks // which is in violation of the CBOR format. string hexEncoding = "7f62f090628591ff"; - byte[] data = hexEncoding.HexToByteArray(); - var reader = new CborReader(data); + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); Assert.Throws(() => reader.ReadTextString()); + Assert.Equal(encoding.Length, reader.BytesRemaining); } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Tag.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Tag.cs new file mode 100644 index 00000000000000..f1e2c21bf0fc7f --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.Tag.cs @@ -0,0 +1,540 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Test.Cryptography; +using Xunit; + +namespace System.Formats.Cbor.Tests +{ + public partial class CborReaderTests + { + // Data points taken from https://tools.ietf.org/html/rfc7049#appendix-A + // Additional pairs generated using http://cbor.me/ + + [Theory] + [InlineData(2, 2, "c202")] + [InlineData(0, "2013-03-21T20:04:00Z", "c074323031332d30332d32315432303a30343a30305a")] + [InlineData(1, 1363896240, "c11a514b67b0")] + [InlineData(23, new byte[] { 1, 2, 3, 4 }, "d74401020304")] + [InlineData(32, "http://www.example.com", "d82076687474703a2f2f7777772e6578616d706c652e636f6d")] + [InlineData(int.MaxValue, 2, "da7fffffff02")] + [InlineData(ulong.MaxValue, new object[] { 1, 2 }, "dbffffffffffffffff820102")] + public static void ReadTag_SingleValue_HappyPath(ulong expectedTag, object expectedValue, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Equal(CborReaderState.Tag, reader.PeekState()); + CborTag tag = reader.ReadTag(); + Assert.Equal(expectedTag, (ulong)tag); + + Helpers.VerifyValue(reader, expectedValue); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData(new ulong[] { 1, 2, 3 }, 2, "c1c2c302")] + [InlineData(new ulong[] { 0, 0, 0 }, "2013-03-21T20:04:00Z", "c0c0c074323031332d30332d32315432303a30343a30305a")] + [InlineData(new ulong[] { int.MaxValue, ulong.MaxValue }, 1363896240, "da7fffffffdbffffffffffffffff1a514b67b0")] + [InlineData(new ulong[] { 23, 24, 100 }, new byte[] { 1, 2, 3, 4 }, "d7d818d8644401020304")] + [InlineData(new ulong[] { 32, 1, 1 }, new object[] { 1, "lorem ipsum" }, "d820c1c182016b6c6f72656d20697073756d")] + public static void ReadTag_NestedTags_HappyPath(ulong[] expectedTags, object expectedValue, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + foreach (ulong expectedTag in expectedTags) + { + Assert.Equal(CborReaderState.Tag, reader.PeekState()); + CborTag tag = reader.ReadTag(); + Assert.Equal(expectedTag, (ulong)tag); + } + + Helpers.VerifyValue(reader, expectedValue); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Theory] + [InlineData("c2")] + public static void ReadTag_NoSubsequentData_ShouldPeekEndOfData(string hexEncoding) + { + byte[] data = hexEncoding.HexToByteArray(); + var reader = new CborReader(data); + reader.ReadTag(); + Assert.Equal(CborReaderState.EndOfData, reader.PeekState()); + } + + [Theory] + [InlineData("40")] // empty text string + [InlineData("60")] // empty byte string + [InlineData("f6")] // null + [InlineData("80")] // [] + [InlineData("a0")] // {} + [InlineData("f97e00")] // NaN + [InlineData("fb3ff199999999999a")] // 1.1 + public static void ReadTag_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Throws(() => reader.ReadTag()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData(2, "c202")] + [InlineData(0, "c074323031332d30332d32315432303a30343a30305a")] + [InlineData(1, "c11a514b67b0")] + [InlineData(23, "d74401020304")] + [InlineData(32, "d82076687474703a2f2f7777772e6578616d706c652e636f6d")] + [InlineData(int.MaxValue, "da7fffffff02")] + [InlineData(ulong.MaxValue, "dbffffffffffffffff820102")] + public static void PeekTag_SingleValue_HappyPath(ulong expectedTag, string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Equal(CborReaderState.Tag, reader.PeekState()); + CborTag tag = reader.PeekTag(); + Assert.Equal(expectedTag, (ulong)tag); + Assert.Equal(CborReaderState.Tag, reader.PeekState()); + Assert.Equal(0, reader.BytesRead); + } + + [Theory] + [InlineData("40")] // empty text string + [InlineData("60")] // empty byte string + [InlineData("f6")] // null + [InlineData("80")] // [] + [InlineData("a0")] // {} + [InlineData("f97e00")] // NaN + [InlineData("fb3ff199999999999a")] // 1.1 + public static void PeekTag_InvalidTypes_ShouldThrowInvalidOperationException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Throws(() => reader.PeekTag()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Fact] + public static void ReadTag_NestedTagWithMissingPayload_ShouldThrowFormatException() + { + byte[] encoding = "9fc2ff".HexToByteArray(); + var reader = new CborReader(encoding); + + reader.ReadStartArray(); + reader.ReadTag(); + + int bytesRemaining = reader.BytesRemaining; + + Assert.Equal(CborReaderState.FormatError, reader.PeekState()); + Assert.Throws(() => reader.ReadEndArray()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); + } + + [Theory] + [InlineData("8201c202")] // definite length array + [InlineData("9f01c202ff")] // equivalent indefinite-length array + public static void ReadTag_CallingEndReadArrayPrematurely_ShouldThrowInvalidOperationException(string hexEncoding) + { + // encoding is valid CBOR, so should not throw FormatException + byte[] data = hexEncoding.HexToByteArray(); + var reader = new CborReader(data); + + reader.ReadStartArray(); + reader.ReadInt64(); + reader.ReadTag(); + + int bytesRemaining = reader.BytesRemaining; + Assert.Equal(CborReaderState.UnsignedInteger, reader.PeekState()); + Assert.Throws(() => reader.ReadEndArray()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); + } + + [Theory] + [InlineData("a102c202")] // definite length map + [InlineData("bf02c202ff")] // equivalent indefinite-length map + public static void ReadTag_CallingEndReadMapPrematurely_ShouldThrowInvalidOperationException(string hexEncoding) + { + // encoding is valid CBOR, so should not throw FormatException + byte[] data = hexEncoding.HexToByteArray(); + var reader = new CborReader(data); + + reader.ReadStartMap(); + reader.ReadInt64(); + reader.ReadTag(); + + int bytesRemaining = reader.BytesRemaining; + Assert.Equal(CborReaderState.UnsignedInteger, reader.PeekState()); + Assert.Throws(() => reader.ReadEndArray()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); + } + + [Theory] + [InlineData("2013-03-21T20:04:00Z", "c074323031332d30332d32315432303a30343a30305a")] + [InlineData("2020-04-09T14:31:21.3535941+01:00", "c07821323032302d30342d30395431343a33313a32312e333533353934312b30313a3030")] + [InlineData("2020-04-09T11:41:19.12-08:00", "c0781c323032302d30342d30395431313a34313a31392e31322d30383a3030")] + [InlineData("2020-04-09T11:41:19.12-08:00", "c07f781c323032302d30342d30395431313a34313a31392e31322d30383a3030ff")] // indefinite-length date string + public static void ReadDateTimeOffset_SingleValue_HappyPath(string expectedValueString, string hexEncoding) + { + DateTimeOffset expectedValue = DateTimeOffset.Parse(expectedValueString); + byte[] data = hexEncoding.HexToByteArray(); + + var reader = new CborReader(data); + + DateTimeOffset result = reader.ReadDateTimeOffset(); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + Assert.Equal(expectedValue, result); + Assert.Equal(expectedValue.Offset, result.Offset); + } + + [Theory] + [InlineData("c01a514b67b0")] // string datetime tag with unix time payload + public static void ReadDateTimeOffset_InvalidTagPayload_ShouldThrowFormatException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Throws(() => reader.ReadDateTimeOffset()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("c07330392f30342f323032302031393a35313a3530")] // 0("09/04/2020 19:51:50") + [InlineData("c06e4c617374204368726973746d6173")] // 0("Last Christmas") + public static void ReadDateTimeOffset_InvalidDateString_ShouldThrowFormatException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Throws(() => reader.ReadDateTimeOffset()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("01")] // numeric value without tag + [InlineData("c301")] // non-datetime tag + public static void ReadDateTimeOffset_InvalidTag_ShouldThrowInvalidOperationxception(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Throws(() => reader.ReadDateTimeOffset()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("81c07330392f30342f323032302031393a35313a3530")] // [0("09/04/2020 19:51:50")] + [InlineData("81c06e4c617374204368726973746d6173")] // [0("Last Christmas")] + public static void ReadDateTimeOffset_InvalidFormat_ShouldRollbackToInitialState(string hexEncoding) + { + var reader = new CborReader(hexEncoding.HexToByteArray()); + + reader.ReadStartArray(); + int bytesRead = reader.BytesRead; + int bytesRemaining = reader.BytesRemaining; + Assert.Throws(() => reader.ReadDateTimeOffset()); + + Assert.Equal(bytesRead, reader.BytesRead); + Assert.Equal(bytesRemaining, reader.BytesRemaining); + Assert.Equal(CborReaderState.Tag, reader.PeekState()); + Assert.Equal(CborTag.DateTimeString, reader.ReadTag()); + } + + [Theory] + [InlineData("2013-03-21T20:04:00Z", "c11a514b67b0")] + [InlineData("2013-03-21T20:04:00.5Z", "c1fb41d452d9ec200000")] + [InlineData("2020-04-09T13:31:21Z", "c11a5e8f23a9")] + [InlineData("1970-01-01T00:00:00Z", "c100")] + [InlineData("1969-12-31T23:59:59Z", "c120")] + [InlineData("1960-01-01T00:00:00Z", "c13a12cff77f")] + public static void ReadUnixTimeSeconds_SingleValue_HappyPath(string expectedValueString, string hexEncoding) + { + DateTimeOffset expectedValue = DateTimeOffset.Parse(expectedValueString); + byte[] data = hexEncoding.HexToByteArray(); + + var reader = new CborReader(data); + + DateTimeOffset result = reader.ReadUnixTimeSeconds(); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + Assert.Equal(expectedValue, result); + Assert.Equal(TimeSpan.Zero, result.Offset); + } + + [Theory] + [InlineData("c174323031332d30332d32315432303a30343a30305a")] // epoch datetime tag with string payload + public static void ReadUnixTimeSeconds_InvalidTagPayload_ShouldThrowFormatException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Throws(() => reader.ReadUnixTimeSeconds()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("c1f97e00")] // 0(NaN) + [InlineData("c1f9fc00")] // 0(-Infinity) + public static void ReadUnixTimeSeconds_InvalidFloatPayload_ShouldThrowFormatException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Throws(() => reader.ReadUnixTimeSeconds()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("01")] // numeric value without tag + [InlineData("c301")] // non-datetime tag + public static void ReadUnixTimeSeconds_InvalidTag_ShouldThrowInvalidOperationxception(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Throws(() => reader.ReadUnixTimeSeconds()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("81c17330392f30342f323032302031393a35313a3530")] // [1("09/04/2020 19:51:50")] + [InlineData("81c16e4c617374204368726973746d6173")] // [1("Last Christmas")] + public static void ReadUnixTimeSeconds_InvalidFormat_ShouldRollbackToInitialState(string hexEncoding) + { + var reader = new CborReader(hexEncoding.HexToByteArray()); + + reader.ReadStartArray(); + int bytesRead = reader.BytesRead; + int bytesRemaining = reader.BytesRemaining; + Assert.Throws(() => reader.ReadUnixTimeSeconds()); + + Assert.Equal(bytesRead, reader.BytesRead); + Assert.Equal(bytesRemaining, reader.BytesRemaining); + Assert.Equal(CborReaderState.Tag, reader.PeekState()); + Assert.Equal(CborTag.UnixTimeSeconds, reader.ReadTag()); + } + + [Theory] + [InlineData("0", "c240")] + [InlineData("0", "c24100")] + [InlineData("1", "c24101")] + [InlineData("1", "c2420001")] // should recognize leading zeroes in buffer + [InlineData("-1", "c34100")] + [InlineData("255", "c241ff")] + [InlineData("-256", "c341ff")] + [InlineData("256", "c2420100")] + [InlineData("-257", "c3420100")] + [InlineData("9223372036854775807", "c2487fffffffffffffff")] + [InlineData("-9223372036854775808", "c3487fffffffffffffff")] + [InlineData("18446744073709551616", "c249010000000000000000")] + [InlineData("-18446744073709551617", "c349010000000000000000")] + [InlineData("1", "c25f4101ff")] // indefinite-length buffer + public static void ReadBigInteger_SingleValue_HappyPath(string expectedValueString, string hexEncoding) + { + BigInteger expectedValue = BigInteger.Parse(expectedValueString); + byte[] data = hexEncoding.HexToByteArray(); + + var reader = new CborReader(data); + + BigInteger result = reader.ReadBigInteger(); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + Assert.Equal(expectedValue, result); + } + + + [Theory] + [InlineData("01")] + [InlineData("c001")] + public static void ReadBigInteger_InvalidCborTag_ShouldThrowInvalidOperationException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Throws(() => reader.ReadBigInteger()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("c280")] + [InlineData("c301")] + public static void ReadBigInteger_InvalidTagPayload_ShouldThrowFormatException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + + Assert.Throws(() => reader.ReadBigInteger()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("81c280")] + [InlineData("81c301")] + public static void ReadBigInteger_InvalidTagPayload_ShouldRollbackToInitialState(string hexEncoding) + { + var reader = new CborReader(hexEncoding.HexToByteArray()); + + reader.ReadStartArray(); + int bytesRead = reader.BytesRead; + int bytesRemaining = reader.BytesRemaining; + Assert.Throws(() => reader.ReadBigInteger()); + + Assert.Equal(bytesRead, reader.BytesRead); + Assert.Equal(bytesRemaining, reader.BytesRemaining); + Assert.Equal(CborReaderState.Tag, reader.PeekState()); + } + + [Theory] + [InlineData("0", "c4820000")] + [InlineData("1", "c4820001")] + [InlineData("-1", "c4820020")] + [InlineData("1.1", "c482200b")] + [InlineData("1.000", "c482221903e8")] + [InlineData("273.15", "c48221196ab3")] + [InlineData("79228162514264337593543950335", "c48200c24cffffffffffffffffffffffff")] // decimal.MaxValue + [InlineData("7922816251426433759354395033.5", "c48220c24cffffffffffffffffffffffff")] + [InlineData("-79228162514264337593543950335", "c48200c34cfffffffffffffffffffffffe")] // decimal.MinValue + [InlineData("3.9614081247908796757769715711", "c482381bc24c7fffffff7fffffff7fffffff")] // maximal number of fractional digits + [InlineData("2000000000", "c4820902")] // encoding with positive exponent representation in payload (2 * 10^9) + public static void ReadDecimal_SingleValue_HappyPath(string expectedStringValue, string hexEncoding) + { + decimal expectedValue = decimal.Parse(expectedStringValue, Globalization.CultureInfo.InvariantCulture); + byte[] data = hexEncoding.HexToByteArray(); + + var reader = new CborReader(data); + + decimal result = reader.ReadDecimal(); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + Assert.Equal(expectedValue, result); + } + + [Theory] + [InlineData("c482181d02")] // 2 * 10^29 + [InlineData("c482381c02")] // 2 * 10^-29 + [InlineData("c48201c24cffffffffffffffffffffffff")] // decimal.MaxValue * 10^1 + [InlineData("c48200c24d01000000000000000000000000")] // (decimal.MaxValue + 1) * 10^0 + [InlineData("c48200c34cffffffffffffffffffffffff")] // (decimal.MinValue - 1) * 10^0 + public static void ReadDecimal_LargeValues_ShouldThrowOverflowException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Throws(() => reader.ReadDecimal()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("c201")] + public static void ReadDecimal_InvalidTag_ShouldThrowInvalidOperationException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Throws(() => reader.ReadDecimal()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("c401")] // 4(1) + [InlineData("c480")] // 4([]) + [InlineData("c48101")] // 4([1]) + [InlineData("c4820160")] // 4([1, ""]) + [InlineData("c4826001")] // 4(["", 1]) + public static void ReadDecimal_InvalidFormat_ShouldThrowFormatException(string hexEncoding) + { + byte[] encoding = hexEncoding.HexToByteArray(); + var reader = new CborReader(encoding); + Assert.Throws(() => reader.ReadDecimal()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData("81c401")] // 4(1) + [InlineData("81c480")] // [4([])] + [InlineData("81c4826001")] // [4(["", 1])] + // decimal using an invalid biginteger encoding, + // in this case two nested state rollbacks will take place + [InlineData("81c48201c260")] // [4([1, 2("")])] + public static void ReadDecimal_InvalidTagPayload_ShouldRollbackToInitialState(string hexEncoding) + { + var reader = new CborReader(hexEncoding.HexToByteArray()); + + reader.ReadStartArray(); + + int bytesRead = reader.BytesRead; + int bytesRemaining = reader.BytesRemaining; + Assert.Throws(() => reader.ReadDecimal()); + + Assert.Equal(bytesRead, reader.BytesRead); + Assert.Equal(bytesRemaining, reader.BytesRemaining); + Assert.Equal(CborReaderState.Tag, reader.PeekState()); + Assert.Equal(CborTag.DecimalFraction, reader.ReadTag()); + } + + [Theory] + [MemberData(nameof(SupportedConformanceTaggedValues))] + public static void ReadTaggedValue_SupportedConformance_ShouldSucceed(CborConformanceLevel level, object expectedValue, string hexEncoding) + { + var reader = new CborReader(hexEncoding.HexToByteArray(), level); + Helpers.VerifyValue(reader, expectedValue); + } + + public static IEnumerable SupportedConformanceTaggedValues => + from l in new[] { CborConformanceLevel.Lax, CborConformanceLevel.Strict, CborConformanceLevel.Rfc7049Canonical } + from v in TaggedValues + select new object[] { l, v.value, v.hexEncoding }; + + [Theory] + [MemberData(nameof(UnsupportedConformanceTaggedValues))] + public static void ReadTaggedValue_UnsupportedConformance_ShouldThrowFormatException(CborConformanceLevel level, object expectedValue, string hexEncoding) + { + var reader = new CborReader(hexEncoding.HexToByteArray(), level); + Assert.Throws(() => Helpers.VerifyValue(reader, expectedValue)); + Assert.Equal(0, reader.BytesRead); + } + + public static IEnumerable UnsupportedConformanceTaggedValues => + from l in new[] { CborConformanceLevel.Ctap2Canonical } + from v in TaggedValues + select new object[] { l, v.value, v.hexEncoding }; + + [Theory] + [MemberData(nameof(TaggedValuesAnyConformance))] + public static void PeekTag_UnsupportedConformanceLevel_ShouldSucceed(CborConformanceLevel level, string hexEncoding) + { + var reader = new CborReader(hexEncoding.HexToByteArray(), level); + reader.PeekTag(); + } + + public static IEnumerable TaggedValuesAnyConformance => + from l in new[] { CborConformanceLevel.Ctap2Canonical } + from v in TaggedValues + select new object[] { l, v.hexEncoding }; + + [Theory] + [MemberData(nameof(UnsupportedConformanceInvalidTypes))] + public static void PeekTag_InvalidType_UnsupportedConformanceLevel_ShouldThrowInvalidOperationException(CborConformanceLevel level, string hexEncoding) + { + var reader = new CborReader(hexEncoding.HexToByteArray(), level); + Assert.Throws(() => reader.PeekTag()); + } + + public static IEnumerable UnsupportedConformanceInvalidTypes => + from l in new[] { CborConformanceLevel.Ctap2Canonical } + from e in new[] { "01", "40", "60" } + select new object[] { l, e }; + + private static (object value, string hexEncoding)[] TaggedValues => + new (object, string)[] + { + (new object[] { CborTag.MimeMessage, 42 }, "d824182a"), + (42.0m, "c482201901a4"), + ((BigInteger)1, "c24101"), + (DateTimeOffset.UnixEpoch, "c0781c313937302d30312d30315430303a30303a30302e303030303030305a"), + }; + } +} diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.cs index c7d36376f535ca..1dbb67d6fe1cf1 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborReaderTests.cs @@ -6,10 +6,11 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Cryptography; using Test.Cryptography; using Xunit; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor.Tests { public partial class CborReaderTests { @@ -17,7 +18,7 @@ public partial class CborReaderTests public static void Peek_EmptyBuffer_ShouldReturnEof() { var reader = new CborReader(ReadOnlyMemory.Empty); - Assert.Equal(CborReaderState.EndOfData, reader.Peek()); + Assert.Equal(CborReaderState.EndOfData, reader.PeekState()); } [Fact] @@ -51,30 +52,90 @@ public static void BytesRemaining_SingleRead_ShouldReturnRemainingBytes() Assert.Equal(0, reader.BytesRemaining); } + [Fact] + public static void ConformanceLevel_DefaultValue_ShouldEqualLax() + { + var reader = new CborReader(Array.Empty()); + Assert.Equal(CborConformanceLevel.Lax, reader.ConformanceLevel); + } + [Theory] - [InlineData(CborMajorType.UnsignedInteger, CborReaderState.UnsignedInteger)] - [InlineData(CborMajorType.NegativeInteger, CborReaderState.NegativeInteger)] - [InlineData(CborMajorType.ByteString, CborReaderState.ByteString)] - [InlineData(CborMajorType.TextString, CborReaderState.TextString)] - [InlineData(CborMajorType.Array, CborReaderState.StartArray)] - [InlineData(CborMajorType.Map, CborReaderState.StartMap)] - [InlineData(CborMajorType.Tag, CborReaderState.Tag)] - [InlineData(CborMajorType.Special, CborReaderState.SpecialValue)] - internal static void Peek_SingleByteBuffer_ShouldReturnExpectedState(CborMajorType majorType, CborReaderState expectedResult) - { - ReadOnlyMemory buffer = new byte[] { (byte)((byte)majorType << 5) }; + [InlineData(0, CborReaderState.UnsignedInteger)] + [InlineData(1, CborReaderState.NegativeInteger)] + [InlineData(2, CborReaderState.ByteString)] + [InlineData(3, CborReaderState.TextString)] + [InlineData(4, CborReaderState.StartArray)] + [InlineData(5, CborReaderState.StartMap)] + [InlineData(6, CborReaderState.Tag)] + [InlineData(7, CborReaderState.SpecialValue)] + public static void Peek_SingleByteBuffer_ShouldReturnExpectedState(byte majorType, CborReaderState expectedResult) + { + ReadOnlyMemory buffer = new byte[] { (byte)(majorType << 5) }; var reader = new CborReader(buffer); - Assert.Equal(expectedResult, reader.Peek()); + Assert.Equal(expectedResult, reader.PeekState()); + } + + [Fact] + public static void Read_EmptyBuffer_ShouldThrowFormatException() + { + var reader = new CborReader(ReadOnlyMemory.Empty); + Assert.Throws(() => reader.ReadInt64()); } [Fact] - public static void CborReader_ReadingTwoPrimitiveValues_ShouldThrowInvalidOperationException() + public static void Read_BeyondEndOfFirstValue_ShouldThrowInvalidOperationException() + { + var reader = new CborReader("01".HexToByteArray()); + reader.ReadInt64(); + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + Assert.Throws(() => reader.ReadInt64()); + } + + [Fact] + public static void CborReader_ReadingTwoRootLevelValues_ShouldThrowInvalidOperationException() { ReadOnlyMemory buffer = new byte[] { 0, 0 }; var reader = new CborReader(buffer); reader.ReadInt64(); - Assert.Equal(CborReaderState.Finished, reader.Peek()); + + int bytesRemaining = reader.BytesRemaining; + Assert.Equal(CborReaderState.FinishedWithTrailingBytes, reader.PeekState()); Assert.Throws(() => reader.ReadInt64()); + Assert.Equal(bytesRemaining, reader.BytesRemaining); + } + + [Theory] + [InlineData(1, 2, "0101")] + [InlineData(10, 10, "0a0a0a0a0a0a0a0a0a0a")] + [InlineData(new object[] { 1, 2 }, 3, "820102820102820102")] + public static void CborReader_MultipleRootValuesAllowed_ReadingMultipleValues_HappyPath(object expectedValue, int repetitions, string hexEncoding) + { + var reader = new CborReader(hexEncoding.HexToByteArray(), allowMultipleRootLevelValues: true); + + for (int i = 0; i < repetitions; i++) + { + Helpers.VerifyValue(reader, expectedValue); + } + + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + } + + [Fact] + public static void CborReader_MultipleRootValuesAllowed_ReadingBeyondEndOfBuffer_ShouldThrowInvalidOperationException() + { + string hexEncoding = "810102"; + var reader = new CborReader(hexEncoding.HexToByteArray(), allowMultipleRootLevelValues: true); + + Assert.Equal(CborReaderState.StartArray, reader.PeekState()); + reader.ReadStartArray(); + reader.ReadInt32(); + reader.ReadEndArray(); + + Assert.Equal(CborReaderState.UnsignedInteger, reader.PeekState()); + reader.ReadInt32(); + + Assert.Equal(CborReaderState.Finished, reader.PeekState()); + Assert.Throws(() => reader.ReadInt32()); } [Theory] @@ -109,11 +170,61 @@ public static void ReadEncodedValue_InvalidCbor_ShouldThrowFormatException(strin { byte[] encoding = hexEncoding.HexToByteArray(); var reader = new CborReader(encoding); - Assert.Throws(() => reader.ReadEncodedValue()); + Assert.Equal(encoding.Length, reader.BytesRemaining); + } + + [Theory] + [InlineData((CborConformanceLevel)(-1))] + public static void InvalidConformanceLevel_ShouldThrowArgumentOutOfRangeException(CborConformanceLevel level) + { + Assert.Throws(() => new CborReader(Array.Empty(), conformanceLevel: level)); } public static IEnumerable EncodedValueInputs => CborReaderTests.SampleCborValues.Select(x => new[] { x }); public static IEnumerable EncodedValueInvalidInputs => CborReaderTests.InvalidCborValues.Select(x => new[] { x }); + + [Theory] + [InlineData("a501020326200121582065eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d2258201e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c", + "65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d", + "1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c", + "SHA256", "ECDSA_P256")] + [InlineData("a501020338222002215830ed57d8608c5734a5ed5d22026bad8700636823e45297306479beb61a5bd6b04688c34a2f0de51d91064355eef7548bdd22583024376b4fee60ba65db61de54234575eec5d37e1184fbafa1f49d71e1795bba6bda9cbe2ebb815f9b49b371486b38fa1b", + "ed57d8608c5734a5ed5d22026bad8700636823e45297306479beb61a5bd6b04688c34a2f0de51d91064355eef7548bdd", + "24376b4fee60ba65db61de54234575eec5d37e1184fbafa1f49d71e1795bba6bda9cbe2ebb815f9b49b371486b38fa1b", + "SHA384", "ECDSA_P384")] + [InlineData("a50102033823200321584200b03811bef65e330bb974224ec3ab0a5469f038c92177b4171f6f66f91244d4476e016ee77cf7e155a4f73567627b5d72eaf0cb4a6036c6509a6432d7cd6a3b325c2258420114b597b6c271d8435cfa02e890608c93f5bc118ca7f47bf191e9f9e49a22f8a15962315f0729781e1d78b302970c832db2fa8f7f782a33f8e1514950dc7499035f", + "00b03811bef65e330bb974224ec3ab0a5469f038c92177b4171f6f66f91244d4476e016ee77cf7e155a4f73567627b5d72eaf0cb4a6036c6509a6432d7cd6a3b325c", + "0114b597b6c271d8435cfa02e890608c93f5bc118ca7f47bf191e9f9e49a22f8a15962315f0729781e1d78b302970c832db2fa8f7f782a33f8e1514950dc7499035f", + "SHA512", "ECDSA_P521")] + [InlineData("a40102200121582065eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d2258201e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c", + "65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d", + "1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c", + null, "ECDSA_P256")] + public static void CoseKeyHelpers_ECDsaParseCosePublicKey_HappyPath(string hexEncoding, string hexExpectedQx, string hexExpectedQy, string? expectedHashAlgorithmName, string curveFriendlyName) + { + ECPoint q = new ECPoint() { X = hexExpectedQx.HexToByteArray(), Y = hexExpectedQy.HexToByteArray() }; + (ECDsa ecDsa, HashAlgorithmName? name) = CborCoseKeyHelpers.ParseECDsaPublicKey(hexEncoding.HexToByteArray()); + + using ECDsa _ = ecDsa; + + ECParameters ecParams = ecDsa.ExportParameters(includePrivateParameters: false); + + string? expectedCurveFriendlyName = NormalizeCurveForPlatform(curveFriendlyName).Oid.FriendlyName; + + Assert.True(ecParams.Curve.IsNamed); + Assert.Equal(expectedCurveFriendlyName, ecParams.Curve.Oid.FriendlyName); + Assert.Equal(q.X, ecParams.Q.X); + Assert.Equal(q.Y, ecParams.Q.Y); + Assert.Equal(expectedHashAlgorithmName, name?.Name); + + static ECCurve NormalizeCurveForPlatform(string friendlyName) + { + ECCurve namedCurve = ECCurve.CreateFromFriendlyName(friendlyName); + using ECDsa ecDsa = ECDsa.Create(namedCurve); + ECParameters platformParams = ecDsa.ExportParameters(includePrivateParameters: false); + return platformParams.Curve; + } + } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborRoundtripTests.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborRoundtripTests.cs index fa402ba7c05d5a..6f4233300ecbf2 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborRoundtripTests.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborRoundtripTests.cs @@ -11,7 +11,7 @@ using FsCheck.Xunit; #endif -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor.Tests { public partial class CborRoundtripTests { @@ -58,7 +58,7 @@ public static void Roundtrip_Int64(long input) { using var writer = new CborWriter(); writer.WriteInt64(input); - byte[] encoding = writer.ToArray(); + byte[] encoding = writer.GetEncoding(); var reader = new CborReader(encoding); long result = reader.ReadInt64(); @@ -92,7 +92,7 @@ public static void Roundtrip_UInt64(ulong input) { using var writer = new CborWriter(); writer.WriteUInt64(input); - byte[] encoding = writer.ToArray(); + byte[] encoding = writer.GetEncoding(); var reader = new CborReader(encoding); ulong result = reader.ReadUInt64(); @@ -115,7 +115,7 @@ public static void Roundtrip_ByteString(string? hexInput) #endif using var writer = new CborWriter(); writer.WriteByteString(input); - byte[] encoding = writer.ToArray(); + byte[] encoding = writer.GetEncoding(); var reader = new CborReader(encoding); byte[] result = reader.ReadByteString(); @@ -139,7 +139,7 @@ public static void Roundtrip_TextString(string? input) { using var writer = new CborWriter(); writer.WriteTextString(input); - byte[] encoding = writer.ToArray(); + byte[] encoding = writer.GetEncoding(); var reader = new CborReader(encoding); string result = reader.ReadTextString(); @@ -162,7 +162,7 @@ public static void ByteString_Encoding_ShouldContainInputBytes(string? hexInput) #endif using var writer = new CborWriter(); writer.WriteByteString(input); - byte[] encoding = writer.ToArray(); + byte[] encoding = writer.GetEncoding(); int length = input?.Length ?? 0; int lengthEncodingLength = GetLengthEncodingLength(length); diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Array.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Array.cs index c9529164982f29..e43bffb043c8d3 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Array.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Array.cs @@ -7,7 +7,7 @@ using Test.Cryptography; using Xunit; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor.Tests { public partial class CborWriterTests { @@ -27,7 +27,7 @@ public static void WriteArray_SimpleValues_HappyPath(object[] values, string exp byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); using var writer = new CborWriter(); Helpers.WriteArray(writer, values); - byte[] actualEncoding = writer.ToArray(); + byte[] actualEncoding = writer.GetEncoding(); AssertHelper.HexEqual(expectedEncoding, actualEncoding); } @@ -40,7 +40,7 @@ public static void WriteArray_NestedValues_HappyPath(object[] values, string exp byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); using var writer = new CborWriter(); Helpers.WriteArray(writer, values); - byte[] actualEncoding = writer.ToArray(); + byte[] actualEncoding = writer.GetEncoding(); AssertHelper.HexEqual(expectedEncoding, actualEncoding); } @@ -52,14 +52,14 @@ public static void WriteArray_NestedValues_HappyPath(object[] values, string exp [InlineData(new object[] { 1, -1, "", new byte[] { 7 } }, "9f0120604107ff")] [InlineData(new object[] { "lorem", "ipsum", "dolor" }, "9f656c6f72656d65697073756d65646f6c6f72ff")] [InlineData(new object?[] { false, null, float.NaN, double.PositiveInfinity }, "9ff4f6faffc00000fb7ff0000000000000ff")] - public static void WriteArray_IndefiniteLength_HappyPath(object[] values, string expectedHexEncoding) + public static void WriteArray_IndefiniteLength_NoPatching_HappyPath(object[] values, string expectedHexEncoding) { byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); - using var writer = new CborWriter(); + using var writer = new CborWriter(encodeIndefiniteLengths: true); Helpers.WriteArray(writer, values, useDefiniteLengthCollections: false); - byte[] actualEncoding = writer.ToArray(); + byte[] actualEncoding = writer.GetEncoding(); AssertHelper.HexEqual(expectedEncoding, actualEncoding); } @@ -67,14 +67,48 @@ public static void WriteArray_IndefiniteLength_HappyPath(object[] values, string [InlineData(new object[] { new object[] { } }, "9f9fffff")] [InlineData(new object[] { 1, new object[] { 2, 3 }, new object[] { 4, 5 } }, "9f019f0203ff9f0405ffff")] [InlineData(new object[] { "", new object[] { new object[] { }, new object[] { 1, new byte[] { 10 } } } }, "9f609f9fff9f01410affffff")] - public static void WriteArray_IndefiniteLength_NestedValues_HappyPath(object[] values, string expectedHexEncoding) + public static void WriteArray_IndefiniteLength_NoPatching_NestedValues_HappyPath(object[] values, string expectedHexEncoding) + { + byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); + + using var writer = new CborWriter(encodeIndefiniteLengths: true); + Helpers.WriteArray(writer, values, useDefiniteLengthCollections: false); + + byte[] actualEncoding = writer.GetEncoding(); + AssertHelper.HexEqual(expectedEncoding, actualEncoding); + } + + [Theory] + [InlineData(new object[] { }, "80")] + [InlineData(new object[] { 42 }, "81182a")] + [InlineData(new object[] { 1, 2, 3 }, "83010203")] + [InlineData(new object[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }, "98190102030405060708090a0b0c0d0e0f101112131415161718181819")] + [InlineData(new object[] { 1, -1, "", new byte[] { 7 } }, "840120604107")] + [InlineData(new object[] { "lorem", "ipsum", "dolor" }, "83656c6f72656d65697073756d65646f6c6f72")] + [InlineData(new object?[] { false, null, float.NaN, double.PositiveInfinity }, "84f4f6faffc00000fb7ff0000000000000")] + public static void WriteArray_IndefiniteLength_WithPatching_HappyPath(object[] values, string expectedHexEncoding) + { + byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); + + using var writer = new CborWriter(); + Helpers.WriteArray(writer, values, useDefiniteLengthCollections: false); + + byte[] actualEncoding = writer.GetEncoding(); + AssertHelper.HexEqual(expectedEncoding, actualEncoding); + } + + [Theory] + [InlineData(new object[] { new object[] { } }, "8180")] + [InlineData(new object[] { 1, new object[] { 2, 3 }, new object[] { 4, 5 } }, "8301820203820405")] + [InlineData(new object[] { "", new object[] { new object[] { }, new object[] { 1, new byte[] { 10 } } } }, "826082808201410a")] + public static void WriteArray_IndefiniteLength_WithPatching_NestedValues_HappyPath(object[] values, string expectedHexEncoding) { byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); using var writer = new CborWriter(); Helpers.WriteArray(writer, values, useDefiniteLengthCollections: false); - byte[] actualEncoding = writer.ToArray(); + byte[] actualEncoding = writer.GetEncoding(); AssertHelper.HexEqual(expectedEncoding, actualEncoding); } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Helpers.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Helpers.cs index c88944e4b27dd8..9b6530f7e2f44b 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Helpers.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Helpers.cs @@ -5,10 +5,11 @@ #nullable enable using System.Linq; +using System.Numerics; using Test.Cryptography; using Xunit; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor.Tests { public partial class CborWriterTests { @@ -18,6 +19,8 @@ internal static class Helpers public const string EncodedPrefixIdentifier = "_encodedValue"; + public const string HexByteStringIdentifier = "_hex"; + // Since we inject test data using attributes, meed to represent both arrays and maps using object arrays. // To distinguish between the two types, we prepend map representations using a string constant. public static bool IsCborMapRepresentation(object[] values) @@ -32,20 +35,38 @@ public static bool IsEncodedValueRepresentation(object[] values) values[1] is string; } + public static bool IsTaggedValueRepresentation(object[] values) + { + return values.Length == 2 && values[0] is CborTag; + } + + public static bool IsIndefiniteLengthByteString(string[] values) + { + return values.Length % 2 == 1 && values[0] == HexByteStringIdentifier; + } + public static void WriteValue(CborWriter writer, object value, bool useDefiniteLengthCollections = true) { switch (value) { case null: writer.WriteNull(); break; case bool b: writer.WriteBoolean(b); break; - case int i: writer.WriteInt64(i); break; + case int i: writer.WriteInt32(i); break; case long i: writer.WriteInt64(i); break; case ulong i: writer.WriteUInt64(i); break; case float f: writer.WriteSingle(f); break; case double d: writer.WriteDouble(d); break; + case decimal d: writer.WriteDecimal(d); break; case string s: writer.WriteTextString(s); break; + case BigInteger i: writer.WriteBigInteger(i); break; + case DateTimeOffset d: writer.WriteDateTimeOffset(d); break; case byte[] b: writer.WriteByteString(b); break; case byte[][] chunks: WriteChunkedByteString(writer, chunks); break; + case string[] chunks when IsIndefiniteLengthByteString(chunks): + byte[][] byteChunks = chunks.Skip(1).Select(ch => ch.HexToByteArray()).ToArray(); + WriteChunkedByteString(writer, byteChunks); + break; + case string[] chunks: WriteChunkedTextString(writer, chunks); break; case object[] nested when IsCborMapRepresentation(nested): WriteMap(writer, nested, useDefiniteLengthCollections); break; case object[] nested when IsEncodedValueRepresentation(nested): @@ -53,6 +74,11 @@ public static void WriteValue(CborWriter writer, object value, bool useDefiniteL writer.WriteEncodedValue(encodedValue); break; + case object[] nested when IsTaggedValueRepresentation(nested): + writer.WriteTag((CborTag)nested[0]); + WriteValue(writer, nested[1]); + break; + case object[] nested: WriteArray(writer, nested, useDefiniteLengthCollections); break; default: throw new ArgumentException($"Unrecognized argument type {value.GetType()}"); }; @@ -66,7 +92,7 @@ public static void WriteArray(CborWriter writer, object[] values, bool useDefini } else { - writer.WriteStartArrayIndefiniteLength(); + writer.WriteStartArray(); } foreach (object value in values) @@ -90,7 +116,7 @@ public static void WriteMap(CborWriter writer, object[] keyValuePairs, bool useD } else { - writer.WriteStartMapIndefiniteLength(); + writer.WriteStartMap(); } foreach (object value in keyValuePairs.Skip(1)) @@ -103,22 +129,22 @@ public static void WriteMap(CborWriter writer, object[] keyValuePairs, bool useD public static void WriteChunkedByteString(CborWriter writer, byte[][] chunks) { - writer.WriteStartByteStringIndefiniteLength(); + writer.WriteStartByteString(); foreach (byte[] chunk in chunks) { writer.WriteByteString(chunk); } - writer.WriteEndByteStringIndefiniteLength(); + writer.WriteEndByteString(); } public static void WriteChunkedTextString(CborWriter writer, string[] chunks) { - writer.WriteStartTextStringIndefiniteLength(); + writer.WriteStartTextString(); foreach (string chunk in chunks) { writer.WriteTextString(chunk); } - writer.WriteEndTextStringIndefiniteLength(); + writer.WriteEndTextString(); } public static void ExecOperation(CborWriter writer, string op) @@ -128,12 +154,12 @@ public static void ExecOperation(CborWriter writer, string op) case nameof(writer.WriteInt64): writer.WriteInt64(42); break; case nameof(writer.WriteByteString): writer.WriteByteString(Array.Empty()); break; case nameof(writer.WriteTextString): writer.WriteTextString(""); break; - case nameof(writer.WriteStartTextStringIndefiniteLength): writer.WriteStartTextStringIndefiniteLength(); break; - case nameof(writer.WriteStartByteStringIndefiniteLength): writer.WriteStartByteStringIndefiniteLength(); break; - case nameof(writer.WriteStartArray): writer.WriteStartArrayIndefiniteLength(); break; - case nameof(writer.WriteStartMap): writer.WriteStartMapIndefiniteLength(); break; - case nameof(writer.WriteEndByteStringIndefiniteLength): writer.WriteEndByteStringIndefiniteLength(); break; - case nameof(writer.WriteEndTextStringIndefiniteLength): writer.WriteEndTextStringIndefiniteLength(); break; + case nameof(writer.WriteStartTextString): writer.WriteStartTextString(); break; + case nameof(writer.WriteStartByteString): writer.WriteStartByteString(); break; + case nameof(writer.WriteStartArray): writer.WriteStartArray(); break; + case nameof(writer.WriteStartMap): writer.WriteStartMap(); break; + case nameof(writer.WriteEndByteString): writer.WriteEndByteString(); break; + case nameof(writer.WriteEndTextString): writer.WriteEndTextString(); break; case nameof(writer.WriteEndArray): writer.WriteEndArray(); break; case nameof(writer.WriteEndMap): writer.WriteEndMap(); break; default: throw new Exception($"Unrecognized CborWriter operation name {op}"); diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Integer.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Integer.cs index 1996e9e0adc25b..01ed2625a971b9 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Integer.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Integer.cs @@ -7,7 +7,7 @@ using Test.Cryptography; using Xunit; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor.Tests { public partial class CborWriterTests { @@ -48,7 +48,39 @@ public static void WriteInt64_SingleValue_HappyPath(long input, string hexExpect byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); using var writer = new CborWriter(); writer.WriteInt64(input); - AssertHelper.HexEqual(expectedEncoding, writer.ToArray()); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); + } + + [Theory] + [InlineData(0, "00")] + [InlineData(1, "01")] + [InlineData(10, "0a")] + [InlineData(23, "17")] + [InlineData(24, "1818")] + [InlineData(25, "1819")] + [InlineData(100, "1864")] + [InlineData(1000, "1903e8")] + [InlineData(1000000, "1a000f4240")] + [InlineData(-1, "20")] + [InlineData(-10, "29")] + [InlineData(-100, "3863")] + [InlineData(-1000, "3903e7")] + [InlineData(byte.MaxValue, "18ff")] + [InlineData(byte.MaxValue + 1, "190100")] + [InlineData(-1 - byte.MaxValue, "38ff")] + [InlineData(-2 - byte.MaxValue, "390100")] + [InlineData(ushort.MaxValue, "19ffff")] + [InlineData(ushort.MaxValue + 1, "1a00010000")] + [InlineData(-1 - ushort.MaxValue, "39ffff")] + [InlineData(-2 - ushort.MaxValue, "3a00010000")] + [InlineData(int.MaxValue, "1a7fffffff")] + [InlineData(int.MinValue, "3a7fffffff")] + public static void WriteInt32_SingleValue_HappyPath(int input, string hexExpectedEncoding) + { + byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); + using var writer = new CborWriter(); + writer.WriteInt32(input); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); } [Theory] @@ -75,69 +107,49 @@ public static void WriteUInt64_SingleValue_HappyPath(ulong input, string hexExpe byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); using var writer = new CborWriter(); writer.WriteUInt64(input); - AssertHelper.HexEqual(expectedEncoding, writer.ToArray()); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); } [Theory] - [InlineData(2, 2, "c202")] - [InlineData(0, "2013-03-21T20:04:00Z", "c074323031332d30332d32315432303a30343a30305a")] - [InlineData(1, 1363896240, "c11a514b67b0")] - [InlineData(23, new byte[] { 1, 2, 3, 4 }, "d74401020304")] - [InlineData(32, "http://www.example.com", "d82076687474703a2f2f7777772e6578616d706c652e636f6d")] - [InlineData(int.MaxValue, 2, "da7fffffff02")] - [InlineData(ulong.MaxValue, new object[] { 1, 2 }, "dbffffffffffffffff820102")] - public static void WriteTag_SingleValue_HappyPath(ulong tag, object value, string hexExpectedEncoding) + [InlineData(0, "00")] + [InlineData(1, "01")] + [InlineData(10, "0a")] + [InlineData(23, "17")] + [InlineData(24, "1818")] + [InlineData(25, "1819")] + [InlineData(100, "1864")] + [InlineData(1000, "1903e8")] + [InlineData(1000000, "1a000f4240")] + [InlineData(byte.MaxValue, "18ff")] + [InlineData(byte.MaxValue + 1, "190100")] + [InlineData(ushort.MaxValue, "19ffff")] + [InlineData(ushort.MaxValue + 1, "1a00010000")] + [InlineData(int.MaxValue, "1a7fffffff")] + [InlineData(uint.MaxValue, "1affffffff")] + public static void WriteUInt32_SingleValue_HappyPath(uint input, string hexExpectedEncoding) { byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); using var writer = new CborWriter(); - writer.WriteTag((CborTag)tag); - Helpers.WriteValue(writer, value); - AssertHelper.HexEqual(expectedEncoding, writer.ToArray()); + writer.WriteUInt32(input); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); } [Theory] - [InlineData(new ulong[] { 1, 2, 3 }, 2, "c1c2c302")] - [InlineData(new ulong[] { 0, 0, 0 }, "2013-03-21T20:04:00Z", "c0c0c074323031332d30332d32315432303a30343a30305a")] - [InlineData(new ulong[] { int.MaxValue, ulong.MaxValue }, 1363896240, "da7fffffffdbffffffffffffffff1a514b67b0")] - [InlineData(new ulong[] { 23, 24, 100 }, new byte[] { 1, 2, 3, 4 }, "d7d818d8644401020304")] - [InlineData(new ulong[] { 32, 1, 1 }, new object[] { 1, "lorem ipsum" }, "d820c1c182016b6c6f72656d20697073756d")] - public static void WriteTag_NestedTags_HappyPath(ulong[] tags, object value, string hexExpectedEncoding) + [InlineData(0, "20")] + [InlineData(9, "29")] + [InlineData(23, "37")] + [InlineData(99, "3863")] + [InlineData(999, "3903e7")] + [InlineData(byte.MaxValue, "38ff")] + [InlineData(ushort.MaxValue, "39ffff")] + [InlineData(uint.MaxValue, "3affffffff")] + [InlineData(ulong.MaxValue, "3bffffffffffffffff")] + public static void WriteCborNegativeIntegerEncoding_SingleValue_HappyPath(ulong input, string hexExpectedEncoding) { byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); using var writer = new CborWriter(); - foreach (var tag in tags) - { - writer.WriteTag((CborTag)tag); - } - Helpers.WriteValue(writer, value); - AssertHelper.HexEqual(expectedEncoding, writer.ToArray()); - } - - [Theory] - [InlineData(new ulong[] { 2 })] - [InlineData(new ulong[] { 1, 2, 3 })] - public static void WriteTag_NoValue_ShouldThrowInvalidOperationException(ulong[] tags) - { - using var writer = new CborWriter(); - - foreach (ulong tag in tags) - { - writer.WriteTag((CborTag)tag); - } - - InvalidOperationException exn = Assert.Throws(() => writer.ToArray()); - - Assert.Equal("Buffer contains incomplete CBOR document.", exn.Message); - } - - [Fact] - public static void WriteTag_NoValueInNestedContext_ShouldThrowInvalidOperationException() - { - using var writer = new CborWriter(); - - writer.WriteStartArrayIndefiniteLength(); - writer.WriteTag(CborTag.Uri); - Assert.Throws(() => writer.WriteEndArray()); + writer.WriteCborNegativeIntegerEncoding(input); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Map.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Map.cs index a23ddcb68984a9..04755b4dc5ef15 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Map.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Map.cs @@ -6,9 +6,9 @@ using System; using Test.Cryptography; using Xunit; -//using static W = System.Security.Cryptography.Encoding.Tests.Cbor.CborWriterHelpers; +//using static W = System.Formats.Cbor.Tests.CborWriterHelpers; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor.Tests { public partial class CborWriterTests { @@ -16,6 +16,7 @@ public partial class CborWriterTests // Additional pairs generated using http://cbor.me/ public const string Map = Helpers.MapPrefixIdentifier; + public const string Hex = Helpers.HexByteStringIdentifier; [Theory] [InlineData(new object[] { Map }, "a0")] @@ -27,7 +28,7 @@ public static void WriteMap_SimpleValues_HappyPath(object[] values, string expec byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); using var writer = new CborWriter(); Helpers.WriteMap(writer, values); - byte[] actualEncoding = writer.ToArray(); + byte[] actualEncoding = writer.GetEncoding(); AssertHelper.HexEqual(expectedEncoding, actualEncoding); } @@ -40,7 +41,7 @@ public static void WriteMap_NestedValues_HappyPath(object[] values, string expec byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); using var writer = new CborWriter(); Helpers.WriteMap(writer, values); - byte[] actualEncoding = writer.ToArray(); + byte[] actualEncoding = writer.GetEncoding(); AssertHelper.HexEqual(expectedEncoding, actualEncoding); } @@ -49,12 +50,12 @@ public static void WriteMap_NestedValues_HappyPath(object[] values, string expec [InlineData(new object[] { Map, 1, 2, 3, 4 }, "bf01020304ff")] [InlineData(new object[] { Map, "a", "A", "b", "B", "c", "C", "d", "D", "e", "E" }, "bf6161614161626142616361436164614461656145ff")] [InlineData(new object[] { Map, "a", "A", -1, 2, new byte[] { }, new byte[] { 1 } }, "bf616161412002404101ff")] - public static void WriteMap_IndefiniteLength_SimpleValues_HappyPath(object[] values, string expectedHexEncoding) + public static void WriteMap_IndefiniteLength_NoPatching_SimpleValues_HappyPath(object[] values, string expectedHexEncoding) { byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); - using var writer = new CborWriter(); + using var writer = new CborWriter(encodeIndefiniteLengths: true); Helpers.WriteMap(writer, values, useDefiniteLengthCollections: false); - byte[] actualEncoding = writer.ToArray(); + byte[] actualEncoding = writer.GetEncoding(); AssertHelper.HexEqual(expectedEncoding, actualEncoding); } @@ -62,16 +63,57 @@ public static void WriteMap_IndefiniteLength_SimpleValues_HappyPath(object[] val [InlineData(new object[] { Map, "a", 1, "b", new object[] { Map, 2, 3 } }, "bf6161016162bf0203ffff")] [InlineData(new object[] { Map, "a", new object[] { Map, 2, 3 }, "b", new object[] { Map, "x", -1, "y", new object[] { Map, "z", 0 } } }, "bf6161bf0203ff6162bf6178206179bf617a00ffffff")] [InlineData(new object[] { Map, new object[] { Map, "x", 2 }, 42 }, "bfbf617802ff182aff")] // using maps as keys - public static void WriteMap_IndefiniteLength_NestedValues_HappyPath(object[] values, string expectedHexEncoding) + public static void WriteMap_IndefiniteLength_NoPatching_NestedValues_HappyPath(object[] values, string expectedHexEncoding) + { + byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); + using var writer = new CborWriter(encodeIndefiniteLengths: true); + Helpers.WriteMap(writer, values, useDefiniteLengthCollections: false); + byte[] actualEncoding = writer.GetEncoding(); + AssertHelper.HexEqual(expectedEncoding, actualEncoding); + } + + [Theory] + [InlineData(new object[] { Map }, "a0")] + [InlineData(new object[] { Map, 1, 2, 3, 4 }, "a201020304")] + [InlineData(new object[] { Map, "a", "A", "b", "B", "c", "C", "d", "D", "e", "E" }, "a56161614161626142616361436164614461656145")] + [InlineData(new object[] { Map, "a", "A", -1, 2, new byte[] { }, new byte[] { 1 } }, "a3616161412002404101")] + public static void WriteMap_IndefiniteLength_WithPatching_SimpleValues_HappyPath(object[] values, string expectedHexEncoding) { byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); using var writer = new CborWriter(); Helpers.WriteMap(writer, values, useDefiniteLengthCollections: false); - byte[] actualEncoding = writer.ToArray(); + byte[] actualEncoding = writer.GetEncoding(); AssertHelper.HexEqual(expectedEncoding, actualEncoding); } [Theory] + [InlineData(new object[] { Map, "a", 1, "b", new object[] { Map, 2, 3 } }, "a26161016162a10203")] + [InlineData(new object[] { Map, "a", new object[] { Map, 2, 3 }, "b", new object[] { Map, "x", -1, "y", new object[] { Map, "z", 0 } } }, "a26161a102036162a26178206179a1617a00")] + [InlineData(new object[] { Map, new object[] { Map, "x", 2 }, 42 }, "a1a1617802182a")] // using maps as keys + public static void WriteMap_IndefiniteLength_WithPatching_NestedValues_HappyPath(object[] values, string expectedHexEncoding) + { + byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); + using var writer = new CborWriter(); + Helpers.WriteMap(writer, values, useDefiniteLengthCollections: false); + byte[] actualEncoding = writer.GetEncoding(); + AssertHelper.HexEqual(expectedEncoding, actualEncoding); + } + + [Theory] + [InlineData(new object[] { Map, 3, 4, 1, 2 }, "a201020304")] + [InlineData(new object[] { Map, "d", "D", "e", "E", "a", "A", "b", "B", "c", "C" }, "a56161614161626142616361436164614461656145")] + [InlineData(new object[] { Map, "a", "A", -1, 2, new byte[] { }, new byte[] { 1 } }, "a3200240410161616141")] + [InlineData(new object[] { Map, new object[] { Map, 3, 4, 1, 2 }, 0, new object[] { 1, 2, 3 }, 0, new string[] { "a", "b" }, 0, new string[] { Hex, "ab", "" }, 00 }, "a441ab00626162008301020300a20102030400")] + public static void WriteMap_IndefiniteLength_WithPatching_Ctap2Sorting_HappyPath(object[] values, string expectedHexEncoding) + { + byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); + using var writer = new CborWriter(CborConformanceLevel.Ctap2Canonical); + Helpers.WriteMap(writer, values, useDefiniteLengthCollections: false); + byte[] actualEncoding = writer.GetEncoding(); + AssertHelper.HexEqual(expectedEncoding, actualEncoding); + } + + [Theory] [InlineData(new object[] { Map, "a", 1, "b", new object[] { 2, 3 } }, "a26161016162820203")] [InlineData(new object[] { Map, "a", new object[] { 2, 3, "b", new object[] { Map, "x", -1, "y", new object[] { "z", 0 } } } }, "a161618402036162a2617820617982617a00")] [InlineData(new object[] { "a", new object[] { Map, "b", "c" } }, "826161a161626163")] @@ -81,7 +123,51 @@ public static void WriteMap_NestedListValues_HappyPath(object value, string expe byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); using var writer = new CborWriter(); Helpers.WriteValue(writer, value); - byte[] actualEncoding = writer.ToArray(); + byte[] actualEncoding = writer.GetEncoding(); + AssertHelper.HexEqual(expectedEncoding, actualEncoding); + } + + [Theory] + [InlineData(CborConformanceLevel.Lax, new object[] { Map, 3, 3, 2, 2, 1, 1 }, "a3030302020101")] + [InlineData(CborConformanceLevel.Strict, new object[] { Map, 3, 3, 2, 2, 1, 1 }, "a3030302020101")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, new object[] { Map, 3, 3, 2, 2, 1, 1 }, "a3010102020303")] + [InlineData(CborConformanceLevel.Ctap2Canonical, new object[] { Map, 3, 3, 2, 2, 1, 1 }, "a3010102020303")] + // nested array payload + [InlineData(CborConformanceLevel.Lax, new object[] { Map, "b", 0, 2, 0, "a", 0, new object[] { "c", "" }, 0, 1, 0 }, "a5616200020061610082616360000100")] + [InlineData(CborConformanceLevel.Strict, new object[] { Map, "b", 0, 2, 0, "a", 0, new object[] { "c", "" }, 0, 1, 0 }, "a5616200020061610082616360000100")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, new object[] { Map, "b", 0, 2, 0, "a", 0, new object[] { "c", "" }, 0, 1, 0 }, "a5010002006161006162008261636000")] + [InlineData(CborConformanceLevel.Ctap2Canonical, new object[] { Map, "b", 0, 2, 0, "a", 0, new object[] { "c", "" }, 0, 1, 0 }, "a5010002006161006162008261636000")] + // CBOR sorting rules do not match canonical string sorting + [InlineData(CborConformanceLevel.Lax, new object[] { Map, "aa", 0, "z", 0 }, "a262616100617a00")] + [InlineData(CborConformanceLevel.Strict, new object[] { Map, "aa", 0, "z", 0 }, "a262616100617a00")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, new object[] { Map, "aa", 0, "z", 0 }, "a2617a0062616100")] + [InlineData(CborConformanceLevel.Ctap2Canonical, new object[] { Map, "aa", 0, "z", 0 }, "a2617a0062616100")] + // Test case distinguishing between RFC7049 and CTAP2 sorting rules + [InlineData(CborConformanceLevel.Lax, new object[] { Map, "", 0, 255, 0 }, "a2600018ff00")] + [InlineData(CborConformanceLevel.Strict, new object[] { Map, "", 0, 255, 0 }, "a2600018ff00")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, new object[] { Map, "", 0, 255, 0 }, "a2600018ff00")] + [InlineData(CborConformanceLevel.Ctap2Canonical, new object[] { Map, "", 0, 255, 0 }, "a218ff006000")] + public static void WriteMap_SimpleValues_ShouldSortKeysAccordingToConformanceLevel(CborConformanceLevel level, object value, string expectedHexEncoding) + { + byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); + using var writer = new CborWriter(level); + Helpers.WriteValue(writer, value); + byte[] actualEncoding = writer.GetEncoding(); + AssertHelper.HexEqual(expectedEncoding, actualEncoding); + } + + [Theory] + [InlineData("a52000a30303020201010061610019010000a20202010100", CborConformanceLevel.Lax)] + [InlineData("a52000a30303020201010061610019010000a20202010100", CborConformanceLevel.Strict)] + [InlineData("a5200061610019010000a20101020200a301010202030300", CborConformanceLevel.Rfc7049Canonical)] + [InlineData("a5190100002000616100a20101020200a301010202030300", CborConformanceLevel.Ctap2Canonical)] + public static void WriteMap_NestedValues_ShouldSortKeysAccordingToConformanceLevel(string expectedHexEncoding, CborConformanceLevel level) + { + object[] value = new object[] { Map, -1, 0, new object[] { Map, 3, 3, 2, 2, 1, 1 }, 0, "a", 0, 256, 0, new object[] { Map, 2, 2, 1, 1 }, 0 }; + byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); + using var writer = new CborWriter(level); + Helpers.WriteValue(writer, value); + byte[] actualEncoding = writer.GetEncoding(); AssertHelper.HexEqual(expectedEncoding, actualEncoding); } @@ -92,10 +178,66 @@ public static void WriteMap_DuplicateKeys_ShouldSucceed(object[] values, string byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); using var writer = new CborWriter(); Helpers.WriteMap(writer, values); - byte[] actualEncoding = writer.ToArray(); + byte[] actualEncoding = writer.GetEncoding(); AssertHelper.HexEqual(expectedEncoding, actualEncoding); } + [Theory] + [InlineData(CborConformanceLevel.Strict, 42)] + [InlineData(CborConformanceLevel.Rfc7049Canonical, 42)] + [InlineData(CborConformanceLevel.Ctap2Canonical, 42)] + [InlineData(CborConformanceLevel.Strict, "foobar")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "foobar")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "foobar")] + [InlineData(CborConformanceLevel.Strict, new object[] { new object[] { "x", "y" } })] + [InlineData(CborConformanceLevel.Rfc7049Canonical, new object[] { new object[] { "x", "y" } })] + [InlineData(CborConformanceLevel.Ctap2Canonical, new object[] { new object[] { "x", "y" } })] + public static void WriteMap_DuplicateKeys_StrictConformance_ShouldFail(CborConformanceLevel level, object dupeKey) + { + using var writer = new CborWriter(level); + writer.WriteStartMap(2); + Helpers.WriteValue(writer, dupeKey); + writer.WriteInt32(0); + Assert.Throws(() => Helpers.WriteValue(writer, dupeKey)); + } + + [Theory] + [InlineData(CborConformanceLevel.Strict, 42)] + [InlineData(CborConformanceLevel.Rfc7049Canonical, 42)] + [InlineData(CborConformanceLevel.Ctap2Canonical, 42)] + [InlineData(CborConformanceLevel.Strict, "foobar")] + [InlineData(CborConformanceLevel.Rfc7049Canonical, "foobar")] + [InlineData(CborConformanceLevel.Ctap2Canonical, "foobar")] + [InlineData(CborConformanceLevel.Strict, new object[] { new object[] { "x", "y" } })] + [InlineData(CborConformanceLevel.Rfc7049Canonical, new object[] { new object[] { "x", "y" } })] + [InlineData(CborConformanceLevel.Ctap2Canonical, new object[] { new object[] { "x", "y" } })] + public static void WriteMap_DuplicateKeys_StrictConformance_ShouldBeRecoverableError(CborConformanceLevel level, object dupeKey) + { + byte[] expected = PerformWrite(attemptDuplicateWrite: false); + byte[] actual = PerformWrite(attemptDuplicateWrite: true); + Assert.Equal(expected.ByteArrayToHex(), actual.ByteArrayToHex()); + + byte[] PerformWrite(bool attemptDuplicateWrite) + { + using var writer = new CborWriter(level); + writer.WriteStartMap(2); + Helpers.WriteValue(writer, dupeKey); + writer.WriteInt32(0); + + if (attemptDuplicateWrite) + { + Assert.Throws(() => Helpers.WriteValue(writer, dupeKey)); + } + + // wrap dupe key in an array to satisfy key sorting & uniqueness constraints + Helpers.WriteValue(writer, new object[] { dupeKey }); + writer.WriteInt32(0); + writer.WriteEndMap(); + + return writer.GetEncoding(); + } + } + [Theory] [InlineData(0)] [InlineData(1)] @@ -176,10 +318,10 @@ public static void EndWriteMap_DefiniteLengthNotMet_WithNestedData_ShouldThrowIn [InlineData(0)] [InlineData(3)] [InlineData(10)] - public static void EndWriteMap_IndefiniteLength_EvenItems_ShouldThrowInvalidOperationException(int length) + public static void EndWriteMap_IndefiniteLength_OddItems_ShouldThrowInvalidOperationException(int length) { using var writer = new CborWriter(); - writer.WriteStartMapIndefiniteLength(); + writer.WriteStartMap(); for (int i = 1; i < length; i++) { diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Simple.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Simple.cs new file mode 100644 index 00000000000000..7788416fdc35cb --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Simple.cs @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable +using System; +using Test.Cryptography; +using Xunit; + +namespace System.Formats.Cbor.Tests +{ + public partial class CborWriterTests + { + // Data points taken from https://tools.ietf.org/html/rfc7049#appendix-A + // Additional pairs generated using http://cbor.me/ + + [Theory] + [InlineData(100000.0, "fa47c35000")] + [InlineData(3.4028234663852886e+38, "fa7f7fffff")] + [InlineData(float.PositiveInfinity, "fa7f800000")] + [InlineData(float.NegativeInfinity, "faff800000")] + [InlineData(float.NaN, "faffc00000")] + public static void WriteSingle_SingleValue_HappyPath(float input, string hexExpectedEncoding) + { + byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); + using var writer = new CborWriter(); + writer.WriteSingle(input); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); + } + + [Theory] + [InlineData(1.1, "fb3ff199999999999a")] + [InlineData(1.0e+300, "fb7e37e43c8800759c")] + [InlineData(-4.1, "fbc010666666666666")] + [InlineData(3.1415926, "fb400921fb4d12d84a")] + [InlineData(double.PositiveInfinity, "fb7ff0000000000000")] + [InlineData(double.NegativeInfinity, "fbfff0000000000000")] + [InlineData(double.NaN, "fbfff8000000000000")] + public static void WriteDouble_SingleValue_HappyPath(double input, string hexExpectedEncoding) + { + byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); + using var writer = new CborWriter(); + writer.WriteDouble(input); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); + } + + [Fact] + public static void WriteNull_SingleValue_HappyPath() + { + byte[] expectedEncoding = "f6".HexToByteArray(); + using var writer = new CborWriter(); + writer.WriteNull(); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); + } + + [Theory] + [InlineData(false, "f4")] + [InlineData(true, "f5")] + public static void WriteBoolean_SingleValue_HappyPath(bool input, string hexExpectedEncoding) + { + byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); + using var writer = new CborWriter(); + writer.WriteBoolean(input); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); + } + + [Theory] + [InlineData((CborSimpleValue)0, "e0")] + [InlineData(CborSimpleValue.False, "f4")] + [InlineData(CborSimpleValue.True, "f5")] + [InlineData(CborSimpleValue.Null, "f6")] + [InlineData(CborSimpleValue.Undefined, "f7")] + [InlineData((CborSimpleValue)32, "f820")] + [InlineData((CborSimpleValue)255, "f8ff")] + public static void WriteSimpleValue_SingleValue_HappyPath(CborSimpleValue input, string hexExpectedEncoding) + { + byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); + using var writer = new CborWriter(); + writer.WriteSimpleValue(input); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); + } + } +} diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Special.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Special.cs deleted file mode 100644 index 8b228267cb6c25..00000000000000 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Special.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable enable -using System; -using Test.Cryptography; -using Xunit; - -namespace System.Security.Cryptography.Encoding.Tests.Cbor -{ - public partial class CborWriterTests - { - // Data points taken from https://tools.ietf.org/html/rfc7049#appendix-A - // Additional pairs generated using http://cbor.me/ - - [Theory] - [InlineData(100000.0, "fa47c35000")] - [InlineData(3.4028234663852886e+38, "fa7f7fffff")] - [InlineData(float.PositiveInfinity, "fa7f800000")] - [InlineData(float.NegativeInfinity, "faff800000")] - [InlineData(float.NaN, "faffc00000")] - internal static void WriteSingle_SingleValue_HappyPath(float input, string hexExpectedEncoding) - { - byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); - using var writer = new CborWriter(); - writer.WriteSingle(input); - AssertHelper.HexEqual(expectedEncoding, writer.ToArray()); - } - - [Theory] - [InlineData(1.1, "fb3ff199999999999a")] - [InlineData(1.0e+300, "fb7e37e43c8800759c")] - [InlineData(-4.1, "fbc010666666666666")] - [InlineData(3.1415926, "fb400921fb4d12d84a")] - [InlineData(double.PositiveInfinity, "fb7ff0000000000000")] - [InlineData(double.NegativeInfinity, "fbfff0000000000000")] - [InlineData(double.NaN, "fbfff8000000000000")] - internal static void WriteDouble_SingleValue_HappyPath(double input, string hexExpectedEncoding) - { - byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); - using var writer = new CborWriter(); - writer.WriteDouble(input); - AssertHelper.HexEqual(expectedEncoding, writer.ToArray()); - } - - [Fact] - internal static void WriteNull_SingleValue_HappyPath() - { - byte[] expectedEncoding = "f6".HexToByteArray(); - using var writer = new CborWriter(); - writer.WriteNull(); - AssertHelper.HexEqual(expectedEncoding, writer.ToArray()); - } - - [Theory] - [InlineData(false, "f4")] - [InlineData(true, "f5")] - internal static void WriteBoolean_SingleValue_HappyPath(bool input, string hexExpectedEncoding) - { - byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); - using var writer = new CborWriter(); - writer.WriteBoolean(input); - AssertHelper.HexEqual(expectedEncoding, writer.ToArray()); - } - - [Theory] - [InlineData((CborSpecialValue)0, "e0")] - [InlineData(CborSpecialValue.False, "f4")] - [InlineData(CborSpecialValue.True, "f5")] - [InlineData(CborSpecialValue.Null, "f6")] - [InlineData(CborSpecialValue.Undefined, "f7")] - [InlineData((CborSpecialValue)32, "f820")] - [InlineData((CborSpecialValue)255, "f8ff")] - internal static void WriteSpecialValue_SingleValue_HappyPath(CborSpecialValue input, string hexExpectedEncoding) - { - byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); - using var writer = new CborWriter(); - writer.WriteSpecialValue(input); - AssertHelper.HexEqual(expectedEncoding, writer.ToArray()); - } - } -} diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.String.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.String.cs index ea7465f778890f..ba23aba739f76f 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.String.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.String.cs @@ -8,7 +8,7 @@ using Test.Cryptography; using Xunit; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor.Tests { public partial class CborWriterTests { @@ -24,7 +24,7 @@ public static void WriteByteString_SingleValue_HappyPath(string hexInput, string byte[] input = hexInput.HexToByteArray(); using var writer = new CborWriter(); writer.WriteByteString(input); - AssertHelper.HexEqual(expectedEncoding, writer.ToArray()); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); } [Theory] @@ -32,14 +32,29 @@ public static void WriteByteString_SingleValue_HappyPath(string hexInput, string [InlineData(new string[] { "" }, "5f40ff")] [InlineData(new string[] { "ab", "" }, "5f41ab40ff")] [InlineData(new string[] { "ab", "bc", "" }, "5f41ab41bc40ff")] - public static void WriteByteString_IndefiteLength_SingleValue_HappyPath(string[] hexChunkInputs, string hexExpectedEncoding) + public static void WriteByteString_IndefiniteLength_NoPatching_SingleValue_HappyPath(string[] hexChunkInputs, string hexExpectedEncoding) + { + byte[][] chunkInputs = hexChunkInputs.Select(ch => ch.HexToByteArray()).ToArray(); + byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); + + using var writer = new CborWriter(encodeIndefiniteLengths: true); + Helpers.WriteChunkedByteString(writer, chunkInputs); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); + } + + [Theory] + [InlineData(new string[] { }, "40")] + [InlineData(new string[] { "" }, "40")] + [InlineData(new string[] { "ab", "" }, "41ab")] + [InlineData(new string[] { "ab", "bc", "" }, "42abbc")] + public static void WriteByteString_IndefiniteLength_WithPatching_SingleValue_HappyPath(string[] hexChunkInputs, string hexExpectedEncoding) { byte[][] chunkInputs = hexChunkInputs.Select(ch => ch.HexToByteArray()).ToArray(); byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); using var writer = new CborWriter(); Helpers.WriteChunkedByteString(writer, chunkInputs); - AssertHelper.HexEqual(expectedEncoding, writer.ToArray()); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); } [Theory] @@ -55,7 +70,7 @@ public static void WriteTextString_SingleValue_HappyPath(string input, string he byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); using var writer = new CborWriter(); writer.WriteTextString(input); - AssertHelper.HexEqual(expectedEncoding, writer.ToArray()); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); } [Theory] @@ -63,12 +78,25 @@ public static void WriteTextString_SingleValue_HappyPath(string input, string he [InlineData(new string[] { "" }, "7f60ff")] [InlineData(new string[] { "ab", "" }, "7f62616260ff")] [InlineData(new string[] { "ab", "bc", "" }, "7f62616262626360ff")] - public static void WriteTextString_IndefiniteLength_SingleValue_HappyPath(string[] chunkInputs, string hexExpectedEncoding) + public static void WriteTextString_IndefiniteLength_NoPatching_SingleValue_HappyPath(string[] chunkInputs, string hexExpectedEncoding) { byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); - using var writer = new CborWriter(); + using var writer = new CborWriter(encodeIndefiniteLengths: true); + Helpers.WriteChunkedTextString(writer, chunkInputs); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); + } + + [Theory] + [InlineData(new string[] { }, "60")] + [InlineData(new string[] { "" }, "60")] + [InlineData(new string[] { "ab", "" }, "626162")] + [InlineData(new string[] { "ab", "bc", "" }, "6461626263")] + public static void WriteTextString_IndefiniteLength_WithPatching_SingleValue_HappyPath(string[] chunkInputs, string hexExpectedEncoding) + { + byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); + using var writer = new CborWriter(encodeIndefiniteLengths: false); Helpers.WriteChunkedTextString(writer, chunkInputs); - AssertHelper.HexEqual(expectedEncoding, writer.ToArray()); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); } [Fact] @@ -85,53 +113,53 @@ public static void WriteTextString_InvalidUnicodeString_ShouldThrowArgumentExcep [Theory] [InlineData(nameof(CborWriter.WriteInt64))] [InlineData(nameof(CborWriter.WriteByteString))] - [InlineData(nameof(CborWriter.WriteStartTextStringIndefiniteLength))] - [InlineData(nameof(CborWriter.WriteStartByteStringIndefiniteLength))] + [InlineData(nameof(CborWriter.WriteStartTextString))] + [InlineData(nameof(CborWriter.WriteStartByteString))] [InlineData(nameof(CborWriter.WriteStartArray))] [InlineData(nameof(CborWriter.WriteStartMap))] public static void WriteTextString_IndefiniteLength_NestedWrites_ShouldThrowInvalidOperationException(string opName) { using var writer = new CborWriter(); - writer.WriteStartTextStringIndefiniteLength(); + writer.WriteStartTextString(); Assert.Throws(() => Helpers.ExecOperation(writer, opName)); } [Theory] - [InlineData(nameof(CborWriter.WriteEndByteStringIndefiniteLength))] + [InlineData(nameof(CborWriter.WriteEndByteString))] [InlineData(nameof(CborWriter.WriteEndArray))] [InlineData(nameof(CborWriter.WriteEndMap))] public static void WriteTextString_IndefiniteLength_ImbalancedWrites_ShouldThrowInvalidOperationException(string opName) { using var writer = new CborWriter(); - writer.WriteStartTextStringIndefiniteLength(); + writer.WriteStartTextString(); Assert.Throws(() => Helpers.ExecOperation(writer, opName)); } [Theory] [InlineData(nameof(CborWriter.WriteInt64))] [InlineData(nameof(CborWriter.WriteTextString))] - [InlineData(nameof(CborWriter.WriteStartTextStringIndefiniteLength))] - [InlineData(nameof(CborWriter.WriteStartByteStringIndefiniteLength))] + [InlineData(nameof(CborWriter.WriteStartTextString))] + [InlineData(nameof(CborWriter.WriteStartByteString))] [InlineData(nameof(CborWriter.WriteStartArray))] [InlineData(nameof(CborWriter.WriteStartMap))] - [InlineData(nameof(CborWriter.WriteEndTextStringIndefiniteLength))] + [InlineData(nameof(CborWriter.WriteEndTextString))] [InlineData(nameof(CborWriter.WriteEndArray))] [InlineData(nameof(CborWriter.WriteEndMap))] - public static void WriteByteString_IndefiteLength_NestedWrites_ShouldThrowInvalidOperationException(string opName) + public static void WriteByteString_IndefiniteLength_NestedWrites_ShouldThrowInvalidOperationException(string opName) { using var writer = new CborWriter(); - writer.WriteStartByteStringIndefiniteLength(); + writer.WriteStartByteString(); Assert.Throws(() => Helpers.ExecOperation(writer, opName)); } [Theory] - [InlineData(nameof(CborWriter.WriteEndTextStringIndefiniteLength))] + [InlineData(nameof(CborWriter.WriteEndTextString))] [InlineData(nameof(CborWriter.WriteEndArray))] [InlineData(nameof(CborWriter.WriteEndMap))] - public static void WriteByteString_IndefiteLength_ImbalancedWrites_ShouldThrowInvalidOperationException(string opName) + public static void WriteByteString_IndefiniteLength_ImbalancedWrites_ShouldThrowInvalidOperationException(string opName) { using var writer = new CborWriter(); - writer.WriteStartByteStringIndefiniteLength(); + writer.WriteStartByteString(); Assert.Throws(() => Helpers.ExecOperation(writer, opName)); } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Tag.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Tag.cs new file mode 100644 index 00000000000000..8c9e20d7210f8f --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.Tag.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. +// See the LICENSE file in the project root for more information. + +#nullable enable +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Test.Cryptography; +using Xunit; + +namespace System.Formats.Cbor.Tests +{ + public partial class CborWriterTests + { + // Data points taken from https://tools.ietf.org/html/rfc7049#appendix-A + // Additional pairs generated using http://cbor.me/ + + [Theory] + [InlineData(2, 2, "c202")] + [InlineData(0, "2013-03-21T20:04:00Z", "c074323031332d30332d32315432303a30343a30305a")] + [InlineData(1, 1363896240, "c11a514b67b0")] + [InlineData(23, new byte[] { 1, 2, 3, 4 }, "d74401020304")] + [InlineData(32, "http://www.example.com", "d82076687474703a2f2f7777772e6578616d706c652e636f6d")] + [InlineData(int.MaxValue, 2, "da7fffffff02")] + [InlineData(ulong.MaxValue, new object[] { 1, 2 }, "dbffffffffffffffff820102")] + public static void WriteTag_SingleValue_HappyPath(ulong tag, object value, string hexExpectedEncoding) + { + byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); + using var writer = new CborWriter(); + writer.WriteTag((CborTag)tag); + Helpers.WriteValue(writer, value); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); + } + + [Theory] + [InlineData(new ulong[] { 1, 2, 3 }, 2, "c1c2c302")] + [InlineData(new ulong[] { 0, 0, 0 }, "2013-03-21T20:04:00Z", "c0c0c074323031332d30332d32315432303a30343a30305a")] + [InlineData(new ulong[] { int.MaxValue, ulong.MaxValue }, 1363896240, "da7fffffffdbffffffffffffffff1a514b67b0")] + [InlineData(new ulong[] { 23, 24, 100 }, new byte[] { 1, 2, 3, 4 }, "d7d818d8644401020304")] + [InlineData(new ulong[] { 32, 1, 1 }, new object[] { 1, "lorem ipsum" }, "d820c1c182016b6c6f72656d20697073756d")] + public static void WriteTag_NestedTags_HappyPath(ulong[] tags, object value, string hexExpectedEncoding) + { + byte[] expectedEncoding = hexExpectedEncoding.HexToByteArray(); + using var writer = new CborWriter(); + foreach (ulong tag in tags) + { + writer.WriteTag((CborTag)tag); + } + Helpers.WriteValue(writer, value); + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); + } + + [Theory] + [InlineData(new ulong[] { 2 })] + [InlineData(new ulong[] { 1, 2, 3 })] + public static void WriteTag_NoValue_ShouldThrowInvalidOperationException(ulong[] tags) + { + using var writer = new CborWriter(); + + foreach (ulong tag in tags) + { + writer.WriteTag((CborTag)tag); + } + + InvalidOperationException exn = Assert.Throws(() => writer.GetEncoding()); + + Assert.Equal("Buffer contains incomplete CBOR document.", exn.Message); + } + + [Fact] + public static void WriteTag_NoValueInNestedContext_ShouldThrowInvalidOperationException() + { + using var writer = new CborWriter(); + + writer.WriteStartArray(); + writer.WriteTag(CborTag.Uri); + Assert.Throws(() => writer.WriteEndArray()); + } + + [Theory] + [InlineData("2013-03-21T20:04:00Z", "c074323031332d30332d32315432303a30343a30305a")] + [InlineData("2020-04-09T14:31:21.3535941+01:00", "c07821323032302d30342d30395431343a33313a32312e333533353934312b30313a3030")] + [InlineData("2020-04-09T11:41:19.12-08:00", "c0781c323032302d30342d30395431313a34313a31392e31322d30383a3030")] + public static void WriteDateTimeOffset_SingleValue_HappyPath(string valueString, string expectedHexEncoding) + { + DateTimeOffset value = DateTimeOffset.Parse(valueString); + using var writer = new CborWriter(); + writer.WriteDateTimeOffset(value); + + byte[] encoding = writer.GetEncoding(); + AssertHelper.HexEqual(expectedHexEncoding.HexToByteArray(), encoding); + } + + [Theory] + [InlineData(1363896240, "c11a514b67b0")] + [InlineData(1586439081, "c11a5e8f23a9")] + [InlineData(0, "c100")] + [InlineData(-1, "c120")] + [InlineData(-315619200, "c13a12cff77f")] + public static void WriteUnixTimeSeconds_Long_SingleValue_HappyPath(long value, string expectedHexEncoding) + { + using var writer = new CborWriter(); + writer.WriteUnixTimeSeconds(value); + + byte[] encoding = writer.GetEncoding(); + AssertHelper.HexEqual(expectedHexEncoding.HexToByteArray(), encoding); + } + + [Theory] + [InlineData(1363896240, "c1fb41d452d9ec000000")] + [InlineData(1586439081, "c1fb41d7a3c8ea400000")] + [InlineData(0, "c1fb0000000000000000")] + [InlineData(-1, "c1fbbff0000000000000")] + [InlineData(-315619200, "c1fbc1b2cff780000000")] + [InlineData(1363896240.5, "c1fb41d452d9ec200000")] + [InlineData(15870467036.15, "c1fb420d8fa0dee13333")] + public static void WriteUnixTimeSeconds_Double_SingleValue_HappyPath(double value, string expectedHexEncoding) + { + using var writer = new CborWriter(); + writer.WriteUnixTimeSeconds(value); + + byte[] encoding = writer.GetEncoding(); + AssertHelper.HexEqual(expectedHexEncoding.HexToByteArray(), encoding); + } + + [Theory] + [InlineData(double.NaN)] + [InlineData(double.PositiveInfinity)] + [InlineData(double.NegativeInfinity)] + public static void WriteUnixTimeSeconds_Double_InvalidInput_ShouldThrowArgumentException(double value) + { + using var writer = new CborWriter(); + Assert.Throws(() => writer.WriteUnixTimeSeconds(value)); + } + + [Theory] + [InlineData("0", "c24100")] + [InlineData("1", "c24101")] + [InlineData("-1", "c34100")] + [InlineData("255", "c241ff")] + [InlineData("-256", "c341ff")] + [InlineData("256", "c2420100")] + [InlineData("-257", "c3420100")] + [InlineData("9223372036854775807", "c2487fffffffffffffff")] + [InlineData("-9223372036854775808", "c3487fffffffffffffff")] + [InlineData("18446744073709551616", "c249010000000000000000")] + [InlineData("-18446744073709551617", "c349010000000000000000")] + public static void WriteInteger_SingleValue_HappyPath(string valueString, string expectedHexEncoding) + { + BigInteger value = BigInteger.Parse(valueString); + + using var writer = new CborWriter(); + writer.WriteBigInteger(value); + + byte[] encoding = writer.GetEncoding(); + AssertHelper.HexEqual(expectedHexEncoding.HexToByteArray(), encoding); + } + + [Theory] + [InlineData("0", "c4820000")] + [InlineData("1", "c4820001")] + [InlineData("-1", "c4820020")] + [InlineData("1.1", "c482200b")] + [InlineData("1.000", "c482221903e8")] + [InlineData("273.15", "c48221196ab3")] + [InlineData("79228162514264337593543950335", "c48200c24cffffffffffffffffffffffff")] // decimal.MaxValue + [InlineData("7922816251426433759354395033.5", "c48220c24cffffffffffffffffffffffff")] + [InlineData("-79228162514264337593543950335", "c48200c34cfffffffffffffffffffffffe")] // decimal.MinValue + [InlineData("3.9614081247908796757769715711", "c482381bc24c7fffffff7fffffff7fffffff")] // maximal number of fractional digits + public static void WriteDecimal_SingleValue_HappyPath(string stringValue, string expectedHexEncoding) + { + decimal value = decimal.Parse(stringValue, Globalization.CultureInfo.InvariantCulture); + using var writer = new CborWriter(); + writer.WriteDecimal(value); + byte[] encoding = writer.GetEncoding(); + AssertHelper.HexEqual(expectedHexEncoding.HexToByteArray(), encoding); + } + + [Theory] + [MemberData(nameof(UnsupportedConformanceTaggedValues))] + public static void WriteTaggedValue_UnsupportedConformance_ShouldThrowInvalidOperationException(CborConformanceLevel level, object value) + { + using var writer = new CborWriter(level); + Assert.Throws(() => Helpers.WriteValue(writer, value)); + Assert.Equal(0, writer.BytesWritten); + } + + public static IEnumerable UnsupportedConformanceTaggedValues => + from l in new[] { CborConformanceLevel.Ctap2Canonical } + from v in TaggedValues + select new object[] { l, v }; + + [Theory] + [MemberData(nameof(SupportedConformanceTaggedValues))] + public static void WriteTaggedValue_SupportedConformance_ShouldSucceed(CborConformanceLevel level, object value) + { + using var writer = new CborWriter(level); + Helpers.WriteValue(writer, value); + } + + public static IEnumerable SupportedConformanceTaggedValues => + from l in new[] { CborConformanceLevel.Lax, CborConformanceLevel.Strict, CborConformanceLevel.Rfc7049Canonical } + from v in TaggedValues + select new object[] { l, v }; + + private static object[] TaggedValues => + new object[] + { + new object[] { CborTag.MimeMessage, 42 }, + 42.0m, + (BigInteger)1, + DateTimeOffset.UnixEpoch, + }; + } +} diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.cs index daa42a9a6bbf2a..50999b4f8e1be9 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CborWriterTests.cs @@ -6,10 +6,11 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Cryptography; using Test.Cryptography; using Xunit; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor.Tests { public partial class CborWriterTests { @@ -23,10 +24,10 @@ public static void IsWriteCompleted_OnWrittenPrimitive_ShouldBeTrue() } [Fact] - public static void ToArray_OnInCompleteValue_ShouldThrowInvalidOperationExceptoin() + public static void GetEncoding_OnInCompleteValue_ShouldThrowInvalidOperationExceptoin() { using var writer = new CborWriter(); - Assert.Throws(() => writer.ToArray()); + Assert.Throws(() => writer.GetEncoding()); } [Fact] @@ -34,7 +35,41 @@ public static void CborWriter_WritingTwoPrimitiveValues_ShouldThrowInvalidOperat { using var writer = new CborWriter(); writer.WriteInt64(42); + int bytesWritten = writer.BytesWritten; Assert.Throws(() => writer.WriteTextString("lorem ipsum")); + Assert.Equal(bytesWritten, writer.BytesWritten); + } + + [Theory] + [InlineData(1, 2, "0101")] + [InlineData(10, 10, "0a0a0a0a0a0a0a0a0a0a")] + [InlineData(new object[] { 1, 2 }, 3, "820102820102820102")] + public static void CborWriter_MultipleRootLevelValuesAllowed_WritingMultipleRootValues_HappyPath(object value, int repetitions, string expectedHexEncoding) + { + byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); + using var writer = new CborWriter(allowMultipleRootLevelValues: true); + + for (int i = 0; i < repetitions; i++) + { + Helpers.WriteValue(writer, value); + } + + AssertHelper.HexEqual(expectedEncoding, writer.GetEncoding()); + } + + [Fact] + public static void GetEncoding_MultipleRootLevelValuesAllowed_PartialRootValue_ShouldThrowInvalidOperationException() + { + using var writer = new CborWriter(allowMultipleRootLevelValues: true); + + writer.WriteStartArray(1); + writer.WriteDouble(3.14); + writer.WriteEndArray(); + writer.WriteStartArray(1); + writer.WriteDouble(3.14); + // misses writer.WriteEndArray(); + + Assert.Throws(() => writer.GetEncoding()); } [Fact] @@ -46,6 +81,13 @@ public static void BytesWritten_SingleValue_ShouldReturnBytesWritten() Assert.Equal(5, writer.BytesWritten); } + [Fact] + public static void ConformanceLevel_DefaultValue_ShouldEqualLax() + { + using var writer = new CborWriter(); + Assert.Equal(CborConformanceLevel.Lax, writer.ConformanceLevel); + } + [Theory] [MemberData(nameof(EncodedValueInputs))] public static void WriteEncodedValue_RootValue_HappyPath(string hexEncodedValue) @@ -55,10 +97,49 @@ public static void WriteEncodedValue_RootValue_HappyPath(string hexEncodedValue) using var writer = new CborWriter(); writer.WriteEncodedValue(encodedValue); - string hexResult = writer.ToArray().ByteArrayToHex(); + string hexResult = writer.GetEncoding().ByteArrayToHex(); Assert.Equal(hexEncodedValue, hexResult.ToLower()); } + + [Theory] + [InlineData(42)] + [InlineData("value1")] + [InlineData(new object[] { new object[] { 1, 2, 3 } })] + public static void TryWriteEncoding_HappyPath(object value) + { + using var writer = new CborWriter(); + Helpers.WriteValue(writer, value); + + byte[] encoding = writer.GetEncoding(); + byte[] target = new byte[encoding.Length]; + + bool result = writer.TryWriteEncoding(target, out int bytesWritten); + + Assert.True(result); + Assert.Equal(encoding.Length, bytesWritten); + Assert.Equal(encoding, target); + } + + [Theory] + [InlineData(42)] + [InlineData("value1")] + [InlineData(new object[] { new object[] { 1, 2, 3 } })] + public static void TryWriteEncoding_DestinationTooSmall_ShouldReturnFalse(object value) + { + using var writer = new CborWriter(); + Helpers.WriteValue(writer, value); + + byte[] encoding = writer.GetEncoding(); + byte[] target = new byte[encoding.Length - 1]; + + bool result = writer.TryWriteEncoding(target, out int bytesWritten); + + Assert.False(result); + Assert.Equal(0, bytesWritten); + Assert.All(target, b => Assert.Equal(0, b)); + } + [Theory] [MemberData(nameof(EncodedValueInputs))] public static void WriteEncodedValue_NestedValue_HappyPath(string hexEncodedValue) @@ -72,7 +153,7 @@ public static void WriteEncodedValue_NestedValue_HappyPath(string hexEncodedValu writer.WriteTextString(""); writer.WriteEndArray(); - string hexResult = writer.ToArray().ByteArrayToHex(); + string hexResult = writer.GetEncoding().ByteArrayToHex(); Assert.Equal("8301" + hexEncodedValue + "60", hexResult.ToLower()); } @@ -88,39 +169,39 @@ public static void WriteEncodedValue_NestedValue_HappyPath(string hexEncodedValu public static void WriteEncodedValue_ContextScenaria_HappyPath(object value, bool useDefiniteLength, string hexExpectedEncoding) { - using var writer = new CborWriter(); + using var writer = new CborWriter(encodeIndefiniteLengths: !useDefiniteLength); Helpers.WriteValue(writer, value, useDefiniteLengthCollections: useDefiniteLength); - string hexEncoding = writer.ToArray().ByteArrayToHex().ToLower(); + string hexEncoding = writer.GetEncoding().ByteArrayToHex().ToLower(); Assert.Equal(hexExpectedEncoding, hexEncoding); } [Fact] public static void WriteEncodedValue_IndefiniteLengthTextString_HappyPath() { - using var writer = new CborWriter(); + using var writer = new CborWriter(encodeIndefiniteLengths: true); - writer.WriteStartTextStringIndefiniteLength(); + writer.WriteStartTextString(); writer.WriteTextString("foo"); writer.WriteEncodedValue("63626172".HexToByteArray()); - writer.WriteEndTextStringIndefiniteLength(); + writer.WriteEndTextString(); - byte[] encoding = writer.ToArray(); + byte[] encoding = writer.GetEncoding(); Assert.Equal("7f63666f6f63626172ff", encoding.ByteArrayToHex().ToLower()); } [Fact] public static void WriteEncodedValue_IndefiniteLengthByteString_HappyPath() { - using var writer = new CborWriter(); + using var writer = new CborWriter(encodeIndefiniteLengths: true); - writer.WriteStartByteStringIndefiniteLength(); + writer.WriteStartByteString(); writer.WriteByteString(new byte[] { 1, 1, 1 }); writer.WriteEncodedValue("43020202".HexToByteArray()); - writer.WriteEndByteStringIndefiniteLength(); + writer.WriteEndByteString(); - byte[] encoding = writer.ToArray(); + byte[] encoding = writer.GetEncoding(); Assert.Equal("5f4301010143020202ff", encoding.ByteArrayToHex().ToLower()); } @@ -128,7 +209,7 @@ public static void WriteEncodedValue_IndefiniteLengthByteString_HappyPath() public static void WriteEncodedValue_BadIndefiniteLengthStringValue_ShouldThrowInvalidOperationException() { using var writer = new CborWriter(); - writer.WriteStartTextStringIndefiniteLength(); + writer.WriteStartTextString(); Assert.Throws(() => writer.WriteEncodedValue(new byte[] { 0x01 })); } @@ -156,7 +237,55 @@ public static void WriteEncodedValue_ValidPayloadWithTrailingBytes_ShouldThrowAr Assert.Throws(() => writer.WriteEncodedValue(new byte[] { 0x01, 0x01 })); } + [Theory] + [InlineData((CborConformanceLevel)(-1))] + public static void InvalidConformanceLevel_ShouldThrowArgumentOutOfRangeException(CborConformanceLevel level) + { + Assert.Throws(() => new CborWriter(conformanceLevel: level)); + } + + [Theory] + [InlineData(CborConformanceLevel.Rfc7049Canonical)] + [InlineData(CborConformanceLevel.Ctap2Canonical)] + public static void EncodeIndefiniteLengths_UnsupportedConformanceLevel_ShouldThrowArgumentException(CborConformanceLevel level) + { + Assert.Throws(() => new CborWriter(level, encodeIndefiniteLengths: true)); + } + public static IEnumerable EncodedValueInputs => CborReaderTests.SampleCborValues.Select(x => new [] { x }); public static IEnumerable EncodedValueBadInputs => CborReaderTests.InvalidCborValues.Select(x => new[] { x }); + + [Theory] + [InlineData("a501020326200121582065eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d2258201e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c", + "65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d", + "1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c", + "SHA256", "ECDSA_P256")] + [InlineData("a501020338222002215830ed57d8608c5734a5ed5d22026bad8700636823e45297306479beb61a5bd6b04688c34a2f0de51d91064355eef7548bdd22583024376b4fee60ba65db61de54234575eec5d37e1184fbafa1f49d71e1795bba6bda9cbe2ebb815f9b49b371486b38fa1b", + "ed57d8608c5734a5ed5d22026bad8700636823e45297306479beb61a5bd6b04688c34a2f0de51d91064355eef7548bdd", + "24376b4fee60ba65db61de54234575eec5d37e1184fbafa1f49d71e1795bba6bda9cbe2ebb815f9b49b371486b38fa1b", + "SHA384", "ECDSA_P384")] + [InlineData("a50102033823200321584200b03811bef65e330bb974224ec3ab0a5469f038c92177b4171f6f66f91244d4476e016ee77cf7e155a4f73567627b5d72eaf0cb4a6036c6509a6432d7cd6a3b325c2258420114b597b6c271d8435cfa02e890608c93f5bc118ca7f47bf191e9f9e49a22f8a15962315f0729781e1d78b302970c832db2fa8f7f782a33f8e1514950dc7499035f", + "00b03811bef65e330bb974224ec3ab0a5469f038c92177b4171f6f66f91244d4476e016ee77cf7e155a4f73567627b5d72eaf0cb4a6036c6509a6432d7cd6a3b325c", + "0114b597b6c271d8435cfa02e890608c93f5bc118ca7f47bf191e9f9e49a22f8a15962315f0729781e1d78b302970c832db2fa8f7f782a33f8e1514950dc7499035f", + "SHA512", "ECDSA_P521")] + [InlineData("a40102200121582065eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d2258201e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c", + "65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d", + "1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c", + null, "ECDSA_P256")] + public static void CoseKeyHelpers_ECDsaExportCosePublicKey_HappyPath(string expectedHexEncoding, string hexQx, string hexQy, string? hashAlgorithmName, string curveFriendlyName) + { + byte[] expectedEncoding = expectedHexEncoding.HexToByteArray(); + var hashAlgName = hashAlgorithmName != null ? new HashAlgorithmName(hashAlgorithmName) : (HashAlgorithmName?)null; + var ecParameters = new ECParameters() + { + Curve = ECCurve.CreateFromFriendlyName(curveFriendlyName), + Q = new ECPoint() { X = hexQx.HexToByteArray(), Y = hexQy.HexToByteArray() }, + }; + + using ECDsa ecDsa = ECDsa.Create(ecParameters); + + byte[] coseKeyEncoding = CborCoseKeyHelpers.ExportECDsaPublicKey(ecDsa, hashAlgName); + AssertHelper.HexEqual(expectedEncoding, coseKeyEncoding); + } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CoseKeyHelpers.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CoseKeyHelpers.cs new file mode 100644 index 00000000000000..a87d7c7706478f --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor.Tests/CoseKeyHelpers.cs @@ -0,0 +1,319 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable enable +using System.Diagnostics; +using System.Security.Cryptography; + +// Provides a reference implementation for serializing ECDsa public keys to the COSE_Key format +// according to https://tools.ietf.org/html/rfc8152#section-8.1 + +namespace System.Formats.Cbor.Tests +{ + public static class CborCoseKeyHelpers + { + public static byte[] ExportECDsaPublicKey(ECDsa ecDsa, HashAlgorithmName? hashAlgName) + { + ECParameters ecParams = ecDsa.ExportParameters(includePrivateParameters: false); + using var writer = new CborWriter(CborConformanceLevel.Ctap2Canonical); + WriteECParametersAsCosePublicKey(writer, ecParams, hashAlgName); + return writer.GetEncoding(); + } + + public static (ECDsa ecDsa, HashAlgorithmName? hashAlgName) ParseECDsaPublicKey(byte[] coseKey) + { + var reader = new CborReader(coseKey, CborConformanceLevel.Ctap2Canonical); + (ECParameters ecParams, HashAlgorithmName? hashAlgName) = ReadECParametersAsCosePublicKey(reader); + return (ECDsa.Create(ecParams), hashAlgName); + } + + private static void WriteECParametersAsCosePublicKey(CborWriter writer, ECParameters ecParams, HashAlgorithmName? algorithmName) + { + Debug.Assert(writer.ConformanceLevel == CborConformanceLevel.Ctap2Canonical); + + if (ecParams.Q.X is null || ecParams.Q.Y is null) + { + throw new ArgumentException("does not specify a public key point.", nameof(ecParams)); + } + + // run these first to perform necessary validation + (CoseKeyType kty, CoseCrvId crv) = MapECCurveToCoseKtyAndCrv(ecParams.Curve); + CoseKeyAlgorithm? alg = (algorithmName != null) ? MapHashAlgorithmNameToCoseKeyAlg(algorithmName.Value) : (CoseKeyAlgorithm?)null; + + // Begin writing a CBOR object + writer.WriteStartMap(); + + // NB labels should be sorted according to CTAP2 canonical encoding rules. + // While the CborWriter will attempt to sort the encodings on its own, + // it is generally more efficient if keys are written in sorted order to begin with. + + WriteCoseKeyLabel(writer, CoseKeyLabel.Kty); + writer.WriteInt32((int)kty); + + if (alg != null) + { + WriteCoseKeyLabel(writer, CoseKeyLabel.Alg); + writer.WriteInt32((int)alg); + } + + WriteCoseKeyLabel(writer, CoseKeyLabel.EcCrv); + writer.WriteInt32((int)crv); + + WriteCoseKeyLabel(writer, CoseKeyLabel.EcX); + writer.WriteByteString(ecParams.Q.X); + + WriteCoseKeyLabel(writer, CoseKeyLabel.EcY); + writer.WriteByteString(ecParams.Q.Y); + + writer.WriteEndMap(); + + static (CoseKeyType, CoseCrvId) MapECCurveToCoseKtyAndCrv(ECCurve curve) + { + if (!curve.IsNamed) + { + throw new ArgumentException("EC COSE keys only support named curves.", nameof(curve)); + } + + if (MatchesOid(ECCurve.NamedCurves.nistP256)) + { + return (CoseKeyType.EC2, CoseCrvId.P256); + } + + if (MatchesOid(ECCurve.NamedCurves.nistP384)) + { + return (CoseKeyType.EC2, CoseCrvId.P384); + } + + if (MatchesOid(ECCurve.NamedCurves.nistP521)) + { + return (CoseKeyType.EC2, CoseCrvId.P521); + } + + throw new ArgumentException("Unrecognized named curve", curve.Oid.Value); + + bool MatchesOid(ECCurve namedCurve) => curve.Oid.Value == namedCurve.Oid.Value; + } + + static CoseKeyAlgorithm MapHashAlgorithmNameToCoseKeyAlg(HashAlgorithmName name) + { + if (MatchesName(HashAlgorithmName.SHA256)) + { + return CoseKeyAlgorithm.ES256; + } + + if (MatchesName(HashAlgorithmName.SHA384)) + { + return CoseKeyAlgorithm.ES384; + } + + if (MatchesName(HashAlgorithmName.SHA512)) + { + return CoseKeyAlgorithm.ES512; + } + + throw new ArgumentException("Unrecognized hash algorithm name.", nameof(HashAlgorithmName)); + + bool MatchesName(HashAlgorithmName candidate) => name.Name == candidate.Name; + } + + static void WriteCoseKeyLabel(CborWriter writer, CoseKeyLabel label) + { + writer.WriteInt32((int)label); + } + } + + private static (ECParameters, HashAlgorithmName?) ReadECParametersAsCosePublicKey(CborReader reader) + { + Debug.Assert(reader.ConformanceLevel == CborConformanceLevel.Ctap2Canonical); + + // CTAP2 conformance mode requires that fields are sorted by key encoding. + // We take advantage of this by reading keys in that order. + // NB1. COSE labels are not sorted according to canonical integer ordering, + // negative labels must always follow positive labels. + // NB2. Any unrecognized keys will result in the reader failing. + // NB3. in order to support optional fields, we need to store the latest read label. + CoseKeyLabel? latestReadLabel = null; + + int? remainingKeys = reader.ReadStartMap(); + Debug.Assert(remainingKeys != null); // guaranteed by CTAP2 conformance + + try + { + var ecParams = new ECParameters(); + + ReadCoseKeyLabel(CoseKeyLabel.Kty); + CoseKeyType kty = (CoseKeyType)reader.ReadInt32(); + + HashAlgorithmName? algName = null; + if (TryReadCoseKeyLabel(CoseKeyLabel.Alg)) + { + CoseKeyAlgorithm alg = (CoseKeyAlgorithm)reader.ReadInt32(); + algName = MapCoseKeyAlgToHashAlgorithmName(alg); + } + + if (TryReadCoseKeyLabel(CoseKeyLabel.KeyOps)) + { + // No-op, simply tolerate potential key_ops labels + reader.SkipValue(validateConformance: true); + } + + ReadCoseKeyLabel(CoseKeyLabel.EcCrv); + CoseCrvId crv = (CoseCrvId)reader.ReadInt32(); + + if (IsValidKtyCrvCombination(kty, crv)) + { + ecParams.Curve = MapCoseCrvToECCurve(crv); + } + else + { + throw new FormatException("Invalid kty/crv combination in COSE key."); + } + + ReadCoseKeyLabel(CoseKeyLabel.EcX); + ecParams.Q.X = reader.ReadByteString(); + + ReadCoseKeyLabel(CoseKeyLabel.EcY); + ecParams.Q.Y = reader.ReadByteString(); + + if (TryReadCoseKeyLabel(CoseKeyLabel.EcD)) + { + throw new FormatException("COSE key encodes a private key."); + } + + if (remainingKeys > 0) + { + throw new FormatException("COSE_key contains unrecognized trailing data."); + } + + reader.ReadEndMap(); + + return (ecParams, algName); + } + catch (InvalidOperationException e) + { + throw new FormatException("Invalid COSE_key format in CBOR document", e); + } + + static bool IsValidKtyCrvCombination(CoseKeyType kty, CoseCrvId crv) + { + return (kty, crv) switch + { + (CoseKeyType.EC2, CoseCrvId.P256 or CoseCrvId.P384 or CoseCrvId.P521) => true, + (CoseKeyType.OKP, CoseCrvId.X255519 or CoseCrvId.X448 or CoseCrvId.Ed25519 or CoseCrvId.Ed448) => true, + _ => false, + }; + ; + } + + static ECCurve MapCoseCrvToECCurve(CoseCrvId crv) + { + return crv switch + { + CoseCrvId.P256 => ECCurve.NamedCurves.nistP256, + CoseCrvId.P384 => ECCurve.NamedCurves.nistP384, + CoseCrvId.P521 => ECCurve.NamedCurves.nistP521, + CoseCrvId.X255519 or + CoseCrvId.X448 or + CoseCrvId.Ed25519 or + CoseCrvId.Ed448 => throw new NotImplementedException("OKP type curves not implemented."), + _ => throw new FormatException("Unrecognized COSE crv value."), + }; + } + + static HashAlgorithmName MapCoseKeyAlgToHashAlgorithmName(CoseKeyAlgorithm alg) + { + return alg switch + { + CoseKeyAlgorithm.ES256 => HashAlgorithmName.SHA256, + CoseKeyAlgorithm.ES384 => HashAlgorithmName.SHA384, + CoseKeyAlgorithm.ES512 => HashAlgorithmName.SHA512, + _ => throw new FormatException("Unrecognized COSE alg value."), + }; + } + + // Handles optional labels + bool TryReadCoseKeyLabel(CoseKeyLabel expectedLabel) + { + // The `currentLabel` parameter can hold a label that + // was read when handling a previous optional field. + // We only need to read the next label if uninhabited. + if (latestReadLabel == null) + { + // check that we have not reached the end of the COSE key object + if (remainingKeys == 0) + { + return false; + } + + latestReadLabel = (CoseKeyLabel)reader.ReadInt32(); + } + + if (expectedLabel != latestReadLabel.Value) + { + return false; + } + + // read was successful, vacate the `currentLabel` parameter to advance reads. + latestReadLabel = null; + remainingKeys--; + return true; + } + + // Handles required labels + void ReadCoseKeyLabel(CoseKeyLabel expectedLabel) + { + if (!TryReadCoseKeyLabel(expectedLabel)) + { + throw new FormatException("Unexpected COSE key label."); + } + } + } + + private enum CoseKeyLabel : int + { + // cf. https://tools.ietf.org/html/rfc8152#section-7.1 table 3 + Kty = 1, + Kid = 2, + Alg = 3, + KeyOps = 4, + BaseIv = 5, + + // cf. https://tools.ietf.org/html/rfc8152#section-13.1.1 table 23 + EcCrv = -1, + EcX = -2, + EcY = -3, + EcD = -4, + }; + + private enum CoseCrvId : int + { + // cf. https://tools.ietf.org/html/rfc8152#section-13.1 table 22 + P256 = 1, + P384 = 2, + P521 = 3, + X255519 = 4, + X448 = 5, + Ed25519 = 6, + Ed448 = 7, + } + + private enum CoseKeyType : int + { + // cf. https://tools.ietf.org/html/rfc8152#section-13 table 21 + OKP = 1, + EC2 = 2, + + Symmetric = 4, + Reserved = 0, + } + + private enum CoseKeyAlgorithm : int + { + // cf. https://tools.ietf.org/html/rfc8152#section-8.1 table 5 + ES256 = -7, + ES384 = -35, + ES512 = -36, + } + } +} diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborConformanceLevel.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborConformanceLevel.cs new file mode 100644 index 00000000000000..4a6fa86c457719 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborConformanceLevel.cs @@ -0,0 +1,165 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; + +namespace System.Formats.Cbor +{ + public enum CborConformanceLevel + { + Lax = 0, + Strict = 1, + Rfc7049Canonical = 2, + Ctap2Canonical = 3, + } + + internal static class CborConformanceLevelHelpers + { + public static void Validate(CborConformanceLevel conformanceLevel) + { + if (conformanceLevel < CborConformanceLevel.Lax || + conformanceLevel > CborConformanceLevel.Ctap2Canonical) + { + throw new ArgumentOutOfRangeException(nameof(conformanceLevel)); + } + } + + public static bool RequiresMinimalIntegerRepresentation(CborConformanceLevel conformanceLevel) + { + switch (conformanceLevel) + { + case CborConformanceLevel.Lax: + case CborConformanceLevel.Strict: + return false; + + case CborConformanceLevel.Rfc7049Canonical: + case CborConformanceLevel.Ctap2Canonical: + return true; + + default: + throw new ArgumentOutOfRangeException(nameof(conformanceLevel)); + }; + } + + public static bool RequiresDefiniteLengthItems(CborConformanceLevel conformanceLevel) + { + switch (conformanceLevel) + { + case CborConformanceLevel.Lax: + case CborConformanceLevel.Strict: + return false; + + case CborConformanceLevel.Rfc7049Canonical: + case CborConformanceLevel.Ctap2Canonical: + return true; + + default: + throw new ArgumentOutOfRangeException(nameof(conformanceLevel)); + }; + } + + public static bool AllowsTags(CborConformanceLevel conformanceLevel) + { + switch (conformanceLevel) + { + case CborConformanceLevel.Lax: + case CborConformanceLevel.Strict: + case CborConformanceLevel.Rfc7049Canonical: + return true; + + case CborConformanceLevel.Ctap2Canonical: + return false; + + default: + throw new ArgumentOutOfRangeException(nameof(conformanceLevel)); + }; + } + + public static bool RequiresUniqueKeys(CborConformanceLevel conformanceLevel) + { + switch (conformanceLevel) + { + case CborConformanceLevel.Lax: + return false; + + case CborConformanceLevel.Strict: + case CborConformanceLevel.Rfc7049Canonical: + case CborConformanceLevel.Ctap2Canonical: + return true; + + default: + throw new ArgumentOutOfRangeException(nameof(conformanceLevel)); + }; + } + + public static bool RequiresSortedKeys(CborConformanceLevel conformanceLevel) + { + switch (conformanceLevel) + { + case CborConformanceLevel.Strict: + case CborConformanceLevel.Lax: + return false; + + case CborConformanceLevel.Rfc7049Canonical: + case CborConformanceLevel.Ctap2Canonical: + return true; + + default: + throw new ArgumentOutOfRangeException(nameof(conformanceLevel)); + }; + } + + public static int GetKeyEncodingHashCode(ReadOnlySpan encoding) + { + return System.Marvin.ComputeHash32(encoding, System.Marvin.DefaultSeed); + } + + public static bool AreEqualKeyEncodings(ReadOnlySpan left, ReadOnlySpan right) + { + return left.SequenceEqual(right); + } + + public static int CompareKeyEncodings(ReadOnlySpan left, ReadOnlySpan right, CborConformanceLevel level) + { + Debug.Assert(!left.IsEmpty && !right.IsEmpty); + + switch (level) + { + case CborConformanceLevel.Rfc7049Canonical: + // Implements key sorting according to + // https://tools.ietf.org/html/rfc7049#section-3.9 + + if (left.Length != right.Length) + { + return left.Length - right.Length; + } + + return left.SequenceCompareTo(right); + + case CborConformanceLevel.Ctap2Canonical: + // Implements key sorting according to + // https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#message-encoding + + int leftMt = (int)new CborInitialByte(left[0]).MajorType; + int rightMt = (int)new CborInitialByte(right[0]).MajorType; + + if (leftMt != rightMt) + { + return leftMt - rightMt; + } + + if (left.Length != right.Length) + { + return left.Length - right.Length; + } + + return left.SequenceCompareTo(right); + + default: + Debug.Fail("Invalid conformance level used in encoding sort."); + throw new Exception("Invalid conformance level used in encoding sort."); + } + } + } +} diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborInitialByte.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborInitialByte.cs index 772f2ee384e223..c99a8381cacef8 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborInitialByte.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborInitialByte.cs @@ -4,7 +4,7 @@ using System.Diagnostics; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor { internal enum CborMajorType : byte { @@ -15,14 +15,14 @@ internal enum CborMajorType : byte Array = 4, Map = 5, Tag = 6, - Special = 7, + Simple = 7, } internal enum CborAdditionalInfo : byte { - SpecialValueFalse = 20, - SpecialValueTrue = 21, - SpecialValueNull = 22, + SimpleValueFalse = 20, + SimpleValueTrue = 21, + SimpleValueNull = 22, Additional8BitData = 24, Additional16BitData = 25, diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Array.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Array.cs index bfa415a7f38204..22ba36322ae3f4 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Array.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Array.cs @@ -3,30 +3,38 @@ // See the LICENSE file in the project root for more information. #nullable enable -using System.Buffers.Binary; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor { - internal partial class CborReader + public partial class CborReader { - public ulong? ReadStartArray() + public int? ReadStartArray() { CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Array); if (header.AdditionalInfo == CborAdditionalInfo.IndefiniteLength) { + if (_isConformanceLevelCheckEnabled && CborConformanceLevelHelpers.RequiresDefiniteLengthItems(ConformanceLevel)) + { + throw new FormatException("Indefinite-length items are not supported under the current conformance level."); + } + AdvanceBuffer(1); - AdvanceDataItemCounters(); PushDataItem(CborMajorType.Array, null); return null; } else { ulong arrayLength = ReadUnsignedInteger(_buffer.Span, header, out int additionalBytes); + + if (arrayLength > (ulong)_buffer.Length) + { + throw new FormatException("Insufficient buffer size for declared definite length in CBOR data item."); + } + AdvanceBuffer(1 + additionalBytes); - AdvanceDataItemCounters(); - PushDataItem(CborMajorType.Array, arrayLength); - return arrayLength; + PushDataItem(CborMajorType.Array, (int)arrayLength); + return (int)arrayLength; } } @@ -42,11 +50,13 @@ public void ReadEndArray() } PopDataItem(expectedType: CborMajorType.Array); + AdvanceDataItemCounters(); AdvanceBuffer(1); } else { PopDataItem(expectedType: CborMajorType.Array); + AdvanceDataItemCounters(); } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Integer.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Integer.cs index d3f3cc91eba501..d1f4546f26336a 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Integer.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Integer.cs @@ -3,22 +3,65 @@ // See the LICENSE file in the project root for more information. using System.Buffers.Binary; +using System.Xml; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor { - internal partial class CborReader + public partial class CborReader { - // Implements major type 0 decoding per https://tools.ietf.org/html/rfc7049#section-2.1 + // Implements major type 0,1 decoding per https://tools.ietf.org/html/rfc7049#section-2.1 + + public long ReadInt64() + { + long value = PeekSignedInteger(out int additionalBytes); + AdvanceBuffer(1 + additionalBytes); + AdvanceDataItemCounters(); + return value; + } + public ulong ReadUInt64() + { + ulong value = PeekUnsignedInteger(out int additionalBytes); + AdvanceBuffer(1 + additionalBytes); + AdvanceDataItemCounters(); + return value; + } + + public int ReadInt32() + { + int value = checked((int)PeekSignedInteger(out int additionalBytes)); + AdvanceBuffer(1 + additionalBytes); + AdvanceDataItemCounters(); + return value; + } + + public uint ReadUInt32() + { + uint value = checked((uint)PeekUnsignedInteger(out int additionalBytes)); + AdvanceBuffer(1 + additionalBytes); + AdvanceDataItemCounters(); + return value; + } + + // Returns the next CBOR negative integer encoding according to + // https://tools.ietf.org/html/rfc7049#section-2.1 + public ulong ReadCborNegativeIntegerEncoding() + { + CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.NegativeInteger); + ulong value = ReadUnsignedInteger(_buffer.Span, header, out int additionalBytes); + AdvanceBuffer(1 + additionalBytes); + AdvanceDataItemCounters(); + return value; + } + + private ulong PeekUnsignedInteger(out int additionalBytes) { CborInitialByte header = PeekInitialByte(); switch (header.MajorType) { case CborMajorType.UnsignedInteger: - ulong value = ReadUnsignedInteger(_buffer.Span, header, out int additionalBytes); - AdvanceBuffer(1 + additionalBytes); - AdvanceDataItemCounters(); + ulong value = ReadUnsignedInteger(_buffer.Span, header, out additionalBytes); return value; case CborMajorType.NegativeInteger: @@ -29,26 +72,19 @@ public ulong ReadUInt64() } } - // Implements major type 0,1 decoding per https://tools.ietf.org/html/rfc7049#section-2.1 - public long ReadInt64() + private long PeekSignedInteger(out int additionalBytes) { - long value; - int additionalBytes; - CborInitialByte header = PeekInitialByte(); + long value; switch (header.MajorType) { case CborMajorType.UnsignedInteger: value = checked((long)ReadUnsignedInteger(_buffer.Span, header, out additionalBytes)); - AdvanceBuffer(1 + additionalBytes); - AdvanceDataItemCounters(); return value; case CborMajorType.NegativeInteger: value = checked(-1 - (long)ReadUnsignedInteger(_buffer.Span, header, out additionalBytes)); - AdvanceBuffer(1 + additionalBytes); - AdvanceDataItemCounters(); return value; default: @@ -56,30 +92,11 @@ public long ReadInt64() } } - public CborTag ReadTag() - { - CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Tag); - ulong tag = ReadUnsignedInteger(_buffer.Span, header, out int additionalBytes); - AdvanceBuffer(1 + additionalBytes); - // NB tag reads do not advance data item counters - _isTagContext = true; - return (CborTag)tag; - } - - // Returns the next CBOR negative integer encoding according to - // https://tools.ietf.org/html/rfc7049#section-2.1 - public ulong ReadCborNegativeIntegerEncoding() - { - CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.NegativeInteger); - ulong value = ReadUnsignedInteger(_buffer.Span, header, out int additionalBytes); - AdvanceBuffer(1 + additionalBytes); - AdvanceDataItemCounters(); - return value; - } - // Unsigned integer decoding https://tools.ietf.org/html/rfc7049#section-2.1 - private static ulong ReadUnsignedInteger(ReadOnlySpan buffer, CborInitialByte header, out int additionalBytes) + private ulong ReadUnsignedInteger(ReadOnlySpan buffer, CborInitialByte header, out int additionalBytes) { + ulong result; + switch (header.AdditionalInfo) { case CborAdditionalInfo x when (x < CborAdditionalInfo.Additional8BitData): @@ -88,26 +105,62 @@ private static ulong ReadUnsignedInteger(ReadOnlySpan buffer, CborInitialB case CborAdditionalInfo.Additional8BitData: EnsureBuffer(buffer, 2); + result = buffer[1]; + + if (result < (int)CborAdditionalInfo.Additional8BitData) + { + ValidateIsNonStandardIntegerRepresentationSupported(); + } + additionalBytes = 1; - return buffer[1]; + return result; case CborAdditionalInfo.Additional16BitData: EnsureBuffer(buffer, 3); + result = BinaryPrimitives.ReadUInt16BigEndian(buffer.Slice(1)); + + if (result <= byte.MaxValue) + { + ValidateIsNonStandardIntegerRepresentationSupported(); + } + additionalBytes = 2; - return BinaryPrimitives.ReadUInt16BigEndian(buffer.Slice(1)); + return result; case CborAdditionalInfo.Additional32BitData: EnsureBuffer(buffer, 5); + result = BinaryPrimitives.ReadUInt32BigEndian(buffer.Slice(1)); + + if (result <= ushort.MaxValue) + { + ValidateIsNonStandardIntegerRepresentationSupported(); + } + additionalBytes = 4; - return BinaryPrimitives.ReadUInt32BigEndian(buffer.Slice(1)); + return result; case CborAdditionalInfo.Additional64BitData: EnsureBuffer(buffer, 9); + result = BinaryPrimitives.ReadUInt64BigEndian(buffer.Slice(1)); + + if (result <= uint.MaxValue) + { + ValidateIsNonStandardIntegerRepresentationSupported(); + } + additionalBytes = 8; - return BinaryPrimitives.ReadUInt64BigEndian(buffer.Slice(1)); + return result; default: - throw new FormatException("initial byte contains invalid integer encoding data"); + throw new FormatException("initial byte contains invalid integer encoding data."); + } + + void ValidateIsNonStandardIntegerRepresentationSupported() + { + if (_isConformanceLevelCheckEnabled && CborConformanceLevelHelpers.RequiresMinimalIntegerRepresentation(ConformanceLevel)) + { + throw new FormatException("Non-minimal integer representations are not permitted under the current conformance level."); + } } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Map.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Map.cs index 7d18195bb5821c..dfd15bf13aca63 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Map.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Map.cs @@ -3,37 +3,51 @@ // See the LICENSE file in the project root for more information. #nullable enable -using System.Buffers.Binary; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Threading; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor { - internal partial class CborReader + public partial class CborReader { - public ulong? ReadStartMap() + private KeyEncodingComparer? _keyEncodingComparer; + private Stack>? _pooledKeyEncodingRangeSets; + + public int? ReadStartMap() { + int? length; CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Map); if (header.AdditionalInfo == CborAdditionalInfo.IndefiniteLength) { + if (_isConformanceLevelCheckEnabled && CborConformanceLevelHelpers.RequiresDefiniteLengthItems(ConformanceLevel)) + { + throw new FormatException("Indefinite-length items not supported under the current conformance level."); + } + AdvanceBuffer(1); - AdvanceDataItemCounters(); PushDataItem(CborMajorType.Map, null); - return null; + length = null; } else { ulong mapSize = ReadUnsignedInteger(_buffer.Span, header, out int additionalBytes); - if (mapSize > long.MaxValue) + if (mapSize > int.MaxValue || 2 * mapSize > (ulong)_buffer.Length) { - throw new OverflowException("Read CBOR map field count exceeds supported size."); + throw new FormatException("Insufficient buffer size for declared definite length in CBOR data item."); } AdvanceBuffer(1 + additionalBytes); - AdvanceDataItemCounters(); - PushDataItem(CborMajorType.Map, 2 * mapSize); - return mapSize; + PushDataItem(CborMajorType.Map, 2 * (int)mapSize); + length = (int)mapSize; } + + _currentKeyOffset = _bytesRead; + _currentItemIsKey = true; + return length; } public void ReadEndMap() @@ -47,17 +61,146 @@ public void ReadEndMap() throw new InvalidOperationException("Not at end of indefinite-length map."); } - if (!_isEvenNumberOfDataItemsRead) + if (!_currentItemIsKey) { - throw new FormatException("CBOR Map types require an even number of key/value combinations"); + throw new FormatException("CBOR map key is missing a value."); } PopDataItem(expectedType: CborMajorType.Map); + AdvanceDataItemCounters(); AdvanceBuffer(1); } else { PopDataItem(expectedType: CborMajorType.Map); + AdvanceDataItemCounters(); + } + } + + // + // Map decoding conformance + // + + private void HandleMapKeyRead() + { + Debug.Assert(_currentKeyOffset != null && _currentItemIsKey); + + (int Offset, int Length) currentKeyRange = (_currentKeyOffset.Value, _bytesRead - _currentKeyOffset.Value); + + if (_isConformanceLevelCheckEnabled) + { + if (CborConformanceLevelHelpers.RequiresSortedKeys(ConformanceLevel)) + { + ValidateSortedKeyEncoding(currentKeyRange); + } + else if (CborConformanceLevelHelpers.RequiresUniqueKeys(ConformanceLevel)) + { + ValidateKeyUniqueness(currentKeyRange); + } + } + + _currentItemIsKey = false; + } + + private void HandleMapValueRead() + { + Debug.Assert(_currentKeyOffset != null && !_currentItemIsKey); + + _currentKeyOffset = _bytesRead; + _currentItemIsKey = true; + } + + private void ValidateSortedKeyEncoding((int Offset, int Length) currentKeyRange) + { + Debug.Assert(_currentKeyOffset != null); + + if (_previousKeyRange != null) + { + (int Offset, int Length) previousKeyRange = _previousKeyRange.Value; + + ReadOnlySpan originalBuffer = _originalBuffer.Span; + ReadOnlySpan previousKeyEncoding = originalBuffer.Slice(previousKeyRange.Offset, previousKeyRange.Length); + ReadOnlySpan currentKeyEncoding = originalBuffer.Slice(currentKeyRange.Offset, currentKeyRange.Length); + + int cmp = CborConformanceLevelHelpers.CompareKeyEncodings(previousKeyEncoding, currentKeyEncoding, ConformanceLevel); + if (cmp > 0) + { + ResetBuffer(currentKeyRange.Offset); + throw new FormatException("CBOR map keys are not in sorted encoding order."); + } + else if (cmp == 0 && CborConformanceLevelHelpers.RequiresUniqueKeys(ConformanceLevel)) + { + ResetBuffer(currentKeyRange.Offset); + throw new FormatException("CBOR map contains duplicate keys."); + } + } + + _previousKeyRange = currentKeyRange; + } + + private void ValidateKeyUniqueness((int Offset, int Length) currentKeyRange) + { + Debug.Assert(_currentKeyOffset != null); + + HashSet<(int Offset, int Length)> previousKeys = GetKeyEncodingRanges(); + + if (!previousKeys.Add(currentKeyRange)) + { + ResetBuffer(currentKeyRange.Offset); + throw new FormatException("CBOR map contains duplicate keys."); + } + } + + private HashSet<(int Offset, int Length)> GetKeyEncodingRanges() + { + if (_keyEncodingRanges != null) + { + return _keyEncodingRanges; + } + + if (_pooledKeyEncodingRangeSets != null && + _pooledKeyEncodingRangeSets.TryPop(out HashSet<(int Offset, int Length)>? result)) + { + result.Clear(); + return _keyEncodingRanges = result; + } + + _keyEncodingComparer ??= new KeyEncodingComparer(this); + return _keyEncodingRanges = new HashSet<(int Offset, int Length)>(_keyEncodingComparer); + } + + private void ReturnKeyEncodingRangeAllocation() + { + if (_keyEncodingRanges != null) + { + _pooledKeyEncodingRangeSets ??= new Stack>(); + _pooledKeyEncodingRangeSets.Push(_keyEncodingRanges); + _keyEncodingRanges = null; + } + } + + private class KeyEncodingComparer : IEqualityComparer<(int Offset, int Length)> + { + private readonly CborReader _reader; + + public KeyEncodingComparer(CborReader reader) + { + _reader = reader; + } + + private ReadOnlySpan GetKeyEncoding((int Offset, int Length) range) + { + return _reader._originalBuffer.Span.Slice(range.Offset, range.Length); + } + + public int GetHashCode((int Offset, int Length) value) + { + return CborConformanceLevelHelpers.GetKeyEncodingHashCode(GetKeyEncoding(value)); + } + + public bool Equals((int Offset, int Length) x, (int Offset, int Length) y) + { + return CborConformanceLevelHelpers.AreEqualKeyEncodings(GetKeyEncoding(x), GetKeyEncoding(y)); } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Simple.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Simple.cs new file mode 100644 index 00000000000000..f98b55a8ddd7fe --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Simple.cs @@ -0,0 +1,159 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers.Binary; + +namespace System.Formats.Cbor +{ + public partial class CborReader + { + public float ReadSingle() + { + CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Simple); + ReadOnlySpan buffer = _buffer.Span; + float result; + + switch (header.AdditionalInfo) + { + case CborAdditionalInfo.Additional16BitData: + EnsureBuffer(buffer, 3); + result = (float)ReadHalfBigEndian(buffer.Slice(1)); + AdvanceBuffer(3); + AdvanceDataItemCounters(); + return result; + + case CborAdditionalInfo.Additional32BitData: + EnsureBuffer(buffer, 5); + result = BinaryPrimitives.ReadSingleBigEndian(buffer.Slice(1)); + AdvanceBuffer(5); + AdvanceDataItemCounters(); + return result; + + case CborAdditionalInfo.Additional64BitData: + throw new InvalidOperationException("Attempting to read double-precision floating point encoding as single-precision."); + + default: + throw new InvalidOperationException("CBOR data item does not encode a floating point number."); + + } + } + + public double ReadDouble() + { + CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Simple); + ReadOnlySpan buffer = _buffer.Span; + double result; + + switch (header.AdditionalInfo) + { + case CborAdditionalInfo.Additional16BitData: + EnsureBuffer(buffer, 3); + result = ReadHalfBigEndian(buffer.Slice(1)); + AdvanceBuffer(3); + AdvanceDataItemCounters(); + return result; + + case CborAdditionalInfo.Additional32BitData: + EnsureBuffer(buffer, 5); + result = BinaryPrimitives.ReadSingleBigEndian(buffer.Slice(1)); + AdvanceBuffer(5); + AdvanceDataItemCounters(); + return result; + + case CborAdditionalInfo.Additional64BitData: + EnsureBuffer(buffer, 9); + result = BinaryPrimitives.ReadDoubleBigEndian(buffer.Slice(1)); + AdvanceBuffer(9); + AdvanceDataItemCounters(); + return result; + + default: + throw new InvalidOperationException("CBOR data item does not encode a floating point number."); + } + } + + public bool ReadBoolean() + { + CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Simple); + + bool result = header.AdditionalInfo switch + { + CborAdditionalInfo.SimpleValueFalse => false, + CborAdditionalInfo.SimpleValueTrue => true, + _ => throw new InvalidOperationException("CBOR data item does not encode a boolean value."), + }; + + AdvanceBuffer(1); + AdvanceDataItemCounters(); + return result; + } + + public void ReadNull() + { + CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Simple); + + switch (header.AdditionalInfo) + { + case CborAdditionalInfo.SimpleValueNull: + AdvanceBuffer(1); + AdvanceDataItemCounters(); + return; + default: + throw new InvalidOperationException("CBOR data item does not encode a null value."); + } + } + + public CborSimpleValue ReadSimpleValue() + { + CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Simple); + + switch (header.AdditionalInfo) + { + case CborAdditionalInfo info when (byte)info < 24: + AdvanceBuffer(1); + AdvanceDataItemCounters(); + return (CborSimpleValue)header.AdditionalInfo; + case CborAdditionalInfo.Additional8BitData: + EnsureBuffer(2); + byte value = _buffer.Span[1]; + + if (value < 32) + { + throw new FormatException("Two-byte CBOR simple value must be between 32 and 255."); + } + + AdvanceBuffer(2); + AdvanceDataItemCounters(); + return (CborSimpleValue)value; + default: + throw new InvalidOperationException("CBOR data item does not encode a simple value."); + } + } + + // half-precision float decoder adapted from https://tools.ietf.org/html/rfc7049#appendix-D + private static double ReadHalfBigEndian(ReadOnlySpan buffer) + { + int half = (buffer[0] << 8) + buffer[1]; + bool isNegative = (half >> 15) != 0; + int exp = (half >> 10) & 0x1f; + int mant = half & 0x3ff; + double value; + + if (exp == 0) + { + value = mant * 5.9604644775390625e-08 /* precomputed 2^-24 */; + } + else if (exp != 31) + { + value = (mant + 1024) * Math.Pow(2, exp - 25); + } + else + { + value = (mant == 0) ? double.PositiveInfinity : double.NaN; + } + + return isNegative ? -value : value; + } + } +} diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.SkipValue.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.SkipValue.cs index 6cdb8bfc2d47dc..d497f71a4cf7a0 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.SkipValue.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.SkipValue.cs @@ -2,18 +2,46 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace System.Security.Cryptography.Encoding.Tests.Cbor +#nullable enable +using System.Diagnostics; + +namespace System.Formats.Cbor { - internal partial class CborReader + public partial class CborReader { - public void SkipValue() + public void SkipValue(bool validateConformance = false) => SkipToAncestor(0, validateConformance); + public void SkipToParent(bool validateConformance = false) + { + if (_currentMajorType is null) + { + throw new InvalidOperationException("CBOR reader is at the root context."); + } + + SkipToAncestor(1, validateConformance); + } + + private void SkipToAncestor(int depth, bool validateConformance) { - int depth = 0; + Debug.Assert(0 <= depth && depth <= Depth); + Checkpoint checkpoint = CreateCheckpoint(); + _isConformanceLevelCheckEnabled = validateConformance; - do + try { - SkipNextNode(ref depth); - } while (depth > 0); + do + { + SkipNextNode(ref depth); + } while (depth > 0); + } + catch + { + RestoreCheckpoint(in checkpoint); + throw; + } + finally + { + _isConformanceLevelCheckEnabled = true; + } } private void SkipNextNode(ref int depth) @@ -21,7 +49,7 @@ private void SkipNextNode(ref int depth) CborReaderState state; // peek, skipping any tags we might encounter - while ((state = Peek()) == CborReaderState.Tag) + while ((state = PeekState()) == CborReaderState.Tag) { ReadTag(); } @@ -97,7 +125,7 @@ private void SkipNextNode(ref int depth) case CborReaderState.Null: case CborReaderState.Boolean: case CborReaderState.SpecialValue: - ReadSpecialValue(); + ReadSimpleValue(); break; case CborReaderState.EndOfData: diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Special.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Special.cs deleted file mode 100644 index adbc97752d1a1f..00000000000000 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Special.cs +++ /dev/null @@ -1,162 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Buffers.Binary; - -namespace System.Security.Cryptography.Encoding.Tests.Cbor -{ - internal partial class CborReader - { - public float ReadSingle() - { - CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Special); - ReadOnlySpan buffer = _buffer.Span; - float result; - - switch (header.AdditionalInfo) - { - case CborAdditionalInfo.Additional16BitData: - EnsureBuffer(buffer, 3); - result = (float)ReadHalfBigEndian(buffer.Slice(1)); - AdvanceBuffer(3); - AdvanceDataItemCounters(); - return result; - - case CborAdditionalInfo.Additional32BitData: - EnsureBuffer(buffer, 5); - result = BinaryPrimitives.ReadSingleBigEndian(buffer.Slice(1)); - AdvanceBuffer(5); - AdvanceDataItemCounters(); - return result; - - case CborAdditionalInfo.Additional64BitData: - throw new InvalidOperationException("Attempting to read double-precision floating point encoding as single-precision."); - - default: - throw new InvalidOperationException("CBOR data item does not encode a floating point number."); - - } - } - - public double ReadDouble() - { - CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Special); - ReadOnlySpan buffer = _buffer.Span; - double result; - - switch (header.AdditionalInfo) - { - case CborAdditionalInfo.Additional16BitData: - EnsureBuffer(buffer, 3); - result = ReadHalfBigEndian(buffer.Slice(1)); - AdvanceBuffer(3); - AdvanceDataItemCounters(); - return result; - - case CborAdditionalInfo.Additional32BitData: - EnsureBuffer(buffer, 5); - result = BinaryPrimitives.ReadSingleBigEndian(buffer.Slice(1)); - AdvanceBuffer(5); - AdvanceDataItemCounters(); - return result; - - case CborAdditionalInfo.Additional64BitData: - EnsureBuffer(buffer, 9); - result = BinaryPrimitives.ReadDoubleBigEndian(buffer.Slice(1)); - AdvanceBuffer(9); - AdvanceDataItemCounters(); - return result; - - default: - throw new InvalidOperationException("CBOR data item does not encode a floating point number."); - } - } - - public bool ReadBoolean() - { - CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Special); - - switch (header.AdditionalInfo) - { - case CborAdditionalInfo.SpecialValueFalse: - AdvanceBuffer(1); - AdvanceDataItemCounters(); - return false; - case CborAdditionalInfo.SpecialValueTrue: - AdvanceBuffer(1); - AdvanceDataItemCounters(); - return true; - default: - throw new InvalidOperationException("CBOR data item does not encode a boolean value."); - } - } - - public void ReadNull() - { - CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Special); - - switch (header.AdditionalInfo) - { - case CborAdditionalInfo.SpecialValueNull: - AdvanceBuffer(1); - AdvanceDataItemCounters(); - return; - default: - throw new InvalidOperationException("CBOR data item does not encode a null value."); - } - } - - public CborSpecialValue ReadSpecialValue() - { - CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Special); - - switch (header.AdditionalInfo) - { - case CborAdditionalInfo info when (byte)info < 24: - AdvanceBuffer(1); - AdvanceDataItemCounters(); - return (CborSpecialValue)header.AdditionalInfo; - case CborAdditionalInfo.Additional8BitData: - EnsureBuffer(2); - byte value = _buffer.Span[1]; - - if (value < 32) - { - throw new FormatException("Two-byte CBOR special value must be between 32 and 255."); - } - - AdvanceBuffer(2); - AdvanceDataItemCounters(); - return (CborSpecialValue)value; - default: - throw new InvalidOperationException("CBOR data item does not encode a special value."); - } - } - - // half-precision float decoder adapted from https://tools.ietf.org/html/rfc7049#appendix-D - private static double ReadHalfBigEndian(ReadOnlySpan buffer) - { - int half = (buffer[0] << 8) + buffer[1]; - bool isNegative = (half >> 15) != 0; - int exp = (half >> 10) & 0x1f; - int mant = half & 0x3ff; - double value; - - if (exp == 0) - { - value = mant * 5.9604644775390625e-08 /* precomputed 2^-24 */; - } - else if (exp != 31) - { - value = (mant + 1024) * Math.Pow(2, exp - 25); - } - else - { - value = (mant == 0) ? double.PositiveInfinity : double.NaN; - } - - return isNegative ? -value : value; - } - } -} diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.String.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.String.cs index 6d39c7b0f2c9fe..5dbf0d5f3f807e 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.String.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.String.cs @@ -6,13 +6,17 @@ using System.Collections.Generic; using System.Diagnostics; using System.Text; +using System.Threading; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor { - internal partial class CborReader + public partial class CborReader { private static readonly System.Text.Encoding s_utf8Encoding = new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); + // stores a reusable List allocation for keeping ranges in the buffer + private List<(int Offset, int Length)>? _indefiniteLengthStringRangeAllocation = null; + // Implements major type 2 decoding per https://tools.ietf.org/html/rfc7049#section-2.1 public byte[] ReadByteString() { @@ -20,6 +24,11 @@ public byte[] ReadByteString() if (header.AdditionalInfo == CborAdditionalInfo.IndefiniteLength) { + if (_isConformanceLevelCheckEnabled && CborConformanceLevelHelpers.RequiresDefiniteLengthItems(ConformanceLevel)) + { + throw new FormatException("Indefinite-length items not supported under the current conformance level."); + } + return ReadChunkedByteStringConcatenated(); } @@ -38,6 +47,11 @@ public bool TryReadByteString(Span destination, out int bytesWritten) if (header.AdditionalInfo == CborAdditionalInfo.IndefiniteLength) { + if (_isConformanceLevelCheckEnabled && CborConformanceLevelHelpers.RequiresDefiniteLengthItems(ConformanceLevel)) + { + throw new FormatException("Indefinite-length items not supported under the current conformance level."); + } + return TryReadChunkedByteStringConcatenated(destination, out bytesWritten); } @@ -65,6 +79,11 @@ public string ReadTextString() if (header.AdditionalInfo == CborAdditionalInfo.IndefiniteLength) { + if (_isConformanceLevelCheckEnabled && CborConformanceLevelHelpers.RequiresDefiniteLengthItems(ConformanceLevel)) + { + throw new FormatException("Indefinite-length items not supported under the current conformance level."); + } + return ReadChunkedTextStringConcatenated(); } @@ -93,6 +112,11 @@ public bool TryReadTextString(Span destination, out int charsWritten) if (header.AdditionalInfo == CborAdditionalInfo.IndefiniteLength) { + if (_isConformanceLevelCheckEnabled && CborConformanceLevelHelpers.RequiresDefiniteLengthItems(ConformanceLevel)) + { + throw new FormatException("Indefinite-length items not supported under the current conformance level."); + } + return TryReadChunkedTextStringConcatenated(destination, out charsWritten); } @@ -125,9 +149,12 @@ public void ReadStartTextStringIndefiniteLength() throw new InvalidOperationException("CBOR text string is not of indefinite length."); } - AdvanceDataItemCounters(); - AdvanceBuffer(1); + if (_isConformanceLevelCheckEnabled && CborConformanceLevelHelpers.RequiresDefiniteLengthItems(ConformanceLevel)) + { + throw new FormatException("Indefinite-length items not supported under the current conformance level."); + } + AdvanceBuffer(1); PushDataItem(CborMajorType.TextString, expectedNestedItems: null); } @@ -135,6 +162,7 @@ public void ReadEndTextStringIndefiniteLength() { ReadNextIndefiniteLengthBreakByte(); PopDataItem(CborMajorType.TextString); + AdvanceDataItemCounters(); AdvanceBuffer(1); } @@ -147,9 +175,12 @@ public void ReadStartByteStringIndefiniteLength() throw new InvalidOperationException("CBOR text string is not of indefinite length."); } - AdvanceDataItemCounters(); - AdvanceBuffer(1); + if (_isConformanceLevelCheckEnabled && CborConformanceLevelHelpers.RequiresDefiniteLengthItems(ConformanceLevel)) + { + throw new FormatException("Indefinite-length items not supported under the current conformance level."); + } + AdvanceBuffer(1); PushDataItem(CborMajorType.ByteString, expectedNestedItems: null); } @@ -157,12 +188,13 @@ public void ReadEndByteStringIndefiniteLength() { ReadNextIndefiniteLengthBreakByte(); PopDataItem(CborMajorType.ByteString); + AdvanceDataItemCounters(); AdvanceBuffer(1); } private bool TryReadChunkedByteStringConcatenated(Span destination, out int bytesWritten) { - List<(int offset, int length)> ranges = ReadChunkedStringRanges(CborMajorType.ByteString, out int encodingLength, out int concatenatedBufferSize); + List<(int Offset, int Length)> ranges = ReadChunkedStringRanges(CborMajorType.ByteString, out int encodingLength, out int concatenatedBufferSize); if (concatenatedBufferSize > destination.Length) { @@ -181,13 +213,13 @@ private bool TryReadChunkedByteStringConcatenated(Span destination, out in bytesWritten = concatenatedBufferSize; AdvanceBuffer(encodingLength); AdvanceDataItemCounters(); - ReturnRangeList(ranges); + ReturnIndefiniteLengthStringRangeList(ranges); return true; } private bool TryReadChunkedTextStringConcatenated(Span destination, out int charsWritten) { - List<(int offset, int length)> ranges = ReadChunkedStringRanges(CborMajorType.TextString, out int encodingLength, out int _); + List<(int Offset, int Length)> ranges = ReadChunkedStringRanges(CborMajorType.TextString, out int encodingLength, out int _); ReadOnlySpan buffer = _buffer.Span; int concatenatedStringSize = 0; @@ -211,13 +243,13 @@ private bool TryReadChunkedTextStringConcatenated(Span destination, out in charsWritten = concatenatedStringSize; AdvanceBuffer(encodingLength); AdvanceDataItemCounters(); - ReturnRangeList(ranges); + ReturnIndefiniteLengthStringRangeList(ranges); return true; } private byte[] ReadChunkedByteStringConcatenated() { - List<(int offset, int length)> ranges = ReadChunkedStringRanges(CborMajorType.ByteString, out int encodingLength, out int concatenatedBufferSize); + List<(int Offset, int Length)> ranges = ReadChunkedStringRanges(CborMajorType.ByteString, out int encodingLength, out int concatenatedBufferSize); var output = new byte[concatenatedBufferSize]; ReadOnlySpan source = _buffer.Span; @@ -232,13 +264,13 @@ private byte[] ReadChunkedByteStringConcatenated() Debug.Assert(target.IsEmpty); AdvanceBuffer(encodingLength); AdvanceDataItemCounters(); - ReturnRangeList(ranges); + ReturnIndefiniteLengthStringRangeList(ranges); return output; } private string ReadChunkedTextStringConcatenated() { - List<(int offset, int length)> ranges = ReadChunkedStringRanges(CborMajorType.TextString, out int encodingLength, out int concatenatedBufferSize); + List<(int Offset, int Length)> ranges = ReadChunkedStringRanges(CborMajorType.TextString, out int encodingLength, out int concatenatedBufferSize); ReadOnlySpan buffer = _buffer.Span; int concatenatedStringSize = 0; @@ -251,10 +283,10 @@ private string ReadChunkedTextStringConcatenated() AdvanceBuffer(encodingLength); AdvanceDataItemCounters(); - ReturnRangeList(ranges); + ReturnIndefiniteLengthStringRangeList(ranges); return output; - static void BuildString(Span target, (List<(int offset, int length)> ranges, ReadOnlyMemory source) input) + static void BuildString(Span target, (List<(int Offset, int Length)> ranges, ReadOnlyMemory source) input) { ReadOnlySpan source = input.source.Span; @@ -270,9 +302,9 @@ static void BuildString(Span target, (List<(int offset, int length)> range // reads a buffer starting with an indefinite-length string, // performing validation and returning a list of ranges containing the individual chunk payloads - private List<(int offset, int length)> ReadChunkedStringRanges(CborMajorType type, out int encodingLength, out int concatenatedBufferSize) + private List<(int Offset, int Length)> ReadChunkedStringRanges(CborMajorType type, out int encodingLength, out int concatenatedBufferSize) { - var ranges = AcquireRangeList(); + List<(int Offset, int Length)> ranges = AcquireIndefiniteLengthStringRangeList(); ReadOnlySpan buffer = _buffer.Span; concatenatedBufferSize = 0; @@ -319,8 +351,8 @@ private void SkipString(CborMajorType type) int byteLength = checked((int)ReadUnsignedInteger(buffer, header, out int additionalBytes)); EnsureBuffer(1 + additionalBytes + byteLength); - // force any utf8 decoding errors if text string - if (type == CborMajorType.TextString) + // Force any UTF8 decoding errors if text string + if (_isConformanceLevelCheckEnabled && type == CborMajorType.TextString) { ReadOnlySpan encodedSlice = buffer.Slice(1 + additionalBytes, byteLength); ValidateUtf8AndGetCharCount(encodedSlice); @@ -341,5 +373,23 @@ private int ValidateUtf8AndGetCharCount(ReadOnlySpan buffer) throw new FormatException("Text string payload is not a valid UTF8 string.", e); } } + + private List<(int Offset, int Length)> AcquireIndefiniteLengthStringRangeList() + { + List<(int Offset, int Length)>? ranges = Interlocked.Exchange(ref _indefiniteLengthStringRangeAllocation, null); + + if (ranges != null) + { + ranges.Clear(); + return ranges; + } + + return new List<(int Offset, int Length)>(); + } + + private void ReturnIndefiniteLengthStringRangeList(List<(int Offset, int Length)> ranges) + { + _indefiniteLengthStringRangeAllocation = ranges; + } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Tag.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Tag.cs new file mode 100644 index 00000000000000..26b2f8d8ed8a34 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.Tag.cs @@ -0,0 +1,233 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Globalization; +using System.Numerics; + +namespace System.Formats.Cbor +{ + public partial class CborReader + { + public CborTag ReadTag() + { + CborTag tag = PeekTagCore(out int additionalBytes); + + if (_isConformanceLevelCheckEnabled && !CborConformanceLevelHelpers.AllowsTags(ConformanceLevel)) + { + throw new FormatException("Tagged items are not permitted under the current conformance level."); + } + + AdvanceBuffer(1 + additionalBytes); + _isTagContext = true; + return tag; + } + + public void ReadTag(CborTag expectedTag) + { + CborTag tag = PeekTagCore(out int additionalBytes); + + if (_isConformanceLevelCheckEnabled && !CborConformanceLevelHelpers.AllowsTags(ConformanceLevel)) + { + throw new FormatException("Tagged items are not permitted under the current conformance level."); + } + + if (expectedTag != tag) + { + throw new InvalidOperationException("CBOR tag mismatch."); + } + + AdvanceBuffer(1 + additionalBytes); + _isTagContext = true; + } + + public CborTag PeekTag() => PeekTagCore(out int _); + + private CborTag PeekTagCore(out int additionalBytes) + { + CborInitialByte header = PeekInitialByte(expectedType: CborMajorType.Tag); + return (CborTag)ReadUnsignedInteger(_buffer.Span, header, out additionalBytes); + } + + // Additional tagged type support + + public DateTimeOffset ReadDateTimeOffset() + { + // implements https://tools.ietf.org/html/rfc7049#section-2.4.1 + + Checkpoint checkpoint = CreateCheckpoint(); + + try + { + ReadTag(expectedTag: CborTag.DateTimeString); + + switch (PeekState()) + { + case CborReaderState.TextString: + case CborReaderState.StartTextString: + break; + default: + throw new FormatException("String DateTime semantic tag should annotate string value."); + } + + string dateString = ReadTextString(); + + // TODO determine if conformance levels should allow inexact date sting parsing + if (!DateTimeOffset.TryParseExact(dateString, CborWriter.Rfc3339FormatString, null, DateTimeStyles.RoundtripKind, out DateTimeOffset result)) + { + throw new FormatException("DateTime string is not valid RFC3339 format."); + } + + return result; + } + catch + { + RestoreCheckpoint(in checkpoint); + throw; + } + } + + public DateTimeOffset ReadUnixTimeSeconds() + { + // implements https://tools.ietf.org/html/rfc7049#section-2.4.1 + + Checkpoint checkpoint = CreateCheckpoint(); + + try + { + ReadTag(expectedTag: CborTag.UnixTimeSeconds); + + switch (PeekState()) + { + case CborReaderState.UnsignedInteger: + case CborReaderState.NegativeInteger: + return DateTimeOffset.FromUnixTimeSeconds(ReadInt64()); + + case CborReaderState.HalfPrecisionFloat: + case CborReaderState.SinglePrecisionFloat: + case CborReaderState.DoublePrecisionFloat: + double seconds = ReadDouble(); + + if (double.IsNaN(seconds) || double.IsInfinity(seconds)) + { + throw new FormatException("Unix time representation cannot be infinity or NaN."); + } + + TimeSpan timespan = TimeSpan.FromSeconds(seconds); + return DateTimeOffset.UnixEpoch + timespan; + + default: + throw new FormatException("UnixDateTime tag should annotate a numeric value."); + } + } + catch + { + RestoreCheckpoint(in checkpoint); + throw; + } + } + + public BigInteger ReadBigInteger() + { + // implements https://tools.ietf.org/html/rfc7049#section-2.4.2 + + Checkpoint checkpoint = CreateCheckpoint(); + + try + { + bool isNegative = ReadTag() switch + { + CborTag.UnsignedBigNum => false, + CborTag.NegativeBigNum => true, + _ => throw new InvalidOperationException("CBOR tag is not a recognized Bignum value."), + }; + + switch (PeekState()) + { + case CborReaderState.ByteString: + case CborReaderState.StartByteString: + break; + default: + throw new FormatException("BigNum semantic tag should annotate byte string value."); + } + + byte[] unsignedBigEndianEncoding = ReadByteString(); + BigInteger unsignedValue = new BigInteger(unsignedBigEndianEncoding, isUnsigned: true, isBigEndian: true); + return isNegative ? -1 - unsignedValue : unsignedValue; + } + catch + { + RestoreCheckpoint(in checkpoint); + throw; + } + } + + public decimal ReadDecimal() + { + // implements https://tools.ietf.org/html/rfc7049#section-2.4.3 + + Checkpoint checkpoint = CreateCheckpoint(); + + try + { + ReadTag(expectedTag: CborTag.DecimalFraction); + + if (PeekState() != CborReaderState.StartArray || ReadStartArray() != 2) + { + throw new FormatException("DecimalFraction tag should annotate a list of two numeric elements."); + } + + decimal mantissa; // signed integral component of the decimal value + long exponent; // base-10 exponent + + switch (PeekState()) + { + case CborReaderState.UnsignedInteger: + case CborReaderState.NegativeInteger: + exponent = ReadInt64(); + break; + + default: + throw new FormatException("DecimalFraction tag should annotate a list of two numeric elements."); + } + + switch (PeekState()) + { + case CborReaderState.UnsignedInteger: + mantissa = ReadUInt64(); + break; + + case CborReaderState.NegativeInteger: + mantissa = -1m - ReadCborNegativeIntegerEncoding(); + break; + + case CborReaderState.Tag: + switch (PeekTag()) + { + case CborTag.UnsignedBigNum: + case CborTag.NegativeBigNum: + mantissa = (decimal)ReadBigInteger(); + break; + + default: + throw new FormatException("DecimalFraction tag should annotate a list of two numeric elements."); + } + + break; + + default: + throw new FormatException("DecimalFraction tag should annotate a list of two numeric elements."); + } + + ReadEndArray(); + + return DecimalHelpers.Reconstruct(mantissa, exponent); + } + catch + { + RestoreCheckpoint(in checkpoint); + throw; + } + } + } +} diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.cs index f55a1d050f673a..eddb5f2f9697c2 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborReader.cs @@ -5,11 +5,10 @@ #nullable enable using System.Collections.Generic; using System.Diagnostics; -using System.Threading; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor { - internal enum CborReaderState + public enum CborReaderState { Unknown = 0, UnsignedInteger, @@ -32,55 +31,94 @@ internal enum CborReaderState DoublePrecisionFloat, SpecialValue, Finished, + FinishedWithTrailingBytes, EndOfData, FormatError, } - internal partial class CborReader + public partial class CborReader { + private readonly ReadOnlyMemory _originalBuffer; private ReadOnlyMemory _buffer; private int _bytesRead = 0; - // remaining number of data items in current cbor context - // with null representing indefinite length data items. - // The root context ony permits one data item to be read. - private ulong? _remainingDataItems = 1; - private bool _isEvenNumberOfDataItemsRead = true; // required for indefinite-length map writes - private Stack<(CborMajorType type, bool isEvenNumberOfDataItemsWritten, ulong? remainingDataItems)>? _nestedDataItemStack; + private Stack? _nestedDataItems; + private CborMajorType? _currentMajorType = null; // major type of the currently written data item. Null iff at the root context + private int? _remainingDataItems; // remaining data items to read if context is definite-length collection + private int _frameOffset = 0; // buffer offset particular to the current data item context private bool _isTagContext = false; // true if reader is expecting a tagged value - // stores a reusable List allocation for keeping ranges in the buffer - private List<(int offset, int length)>? _rangeListAllocation = null; + // Map-specific book keeping + private int? _currentKeyOffset = null; + private bool _currentItemIsKey = false; + private (int Offset, int Length)? _previousKeyRange; + private HashSet<(int Offset, int Length)>? _keyEncodingRanges; - internal CborReader(ReadOnlyMemory buffer) + // flag used to temporarily disable conformance level checks, + // e.g. during a skip operation over nonconforming encodings. + private bool _isConformanceLevelCheckEnabled = true; + + // keeps a cached copy of the reader state; 'Unknown' denotes uncomputed state + private CborReaderState _cachedState = CborReaderState.Unknown; + + public CborReader(ReadOnlyMemory buffer, CborConformanceLevel conformanceLevel = CborConformanceLevel.Lax, bool allowMultipleRootLevelValues = false) { + CborConformanceLevelHelpers.Validate(conformanceLevel); + + _originalBuffer = buffer; _buffer = buffer; + ConformanceLevel = conformanceLevel; + AllowMultipleRootLevelValues = allowMultipleRootLevelValues; + _remainingDataItems = allowMultipleRootLevelValues ? null : (int?)1; } + public CborConformanceLevel ConformanceLevel { get; } + public bool AllowMultipleRootLevelValues { get; } + public int Depth => _nestedDataItems is null ? 0 : _nestedDataItems.Count; public int BytesRead => _bytesRead; public int BytesRemaining => _buffer.Length; - public CborReaderState Peek() + public CborReaderState PeekState() + { + if (_cachedState == CborReaderState.Unknown) + { + _cachedState = PeekStateCore(); + } + + return _cachedState; + } + + private CborReaderState PeekStateCore() { if (_remainingDataItems == 0) { - if (_nestedDataItemStack?.Count > 0) + if (_currentMajorType != null) { - return _nestedDataItemStack.Peek().type switch + // is at the end of a definite-length collection + switch (_currentMajorType.Value) { - CborMajorType.Array => CborReaderState.EndArray, - CborMajorType.Map => CborReaderState.EndMap, - _ => throw new Exception("CborReader internal error. Invalid CBOR major type pushed to stack."), + case CborMajorType.Array: return CborReaderState.EndArray; + case CborMajorType.Map: return CborReaderState.EndMap; + default: + Debug.Fail("CborReader internal error. Invalid CBOR major type pushed to stack."); + throw new Exception("CborReader internal error. Invalid CBOR major type pushed to stack."); }; } else { - return CborReaderState.Finished; + // is at the end of the root value + return _buffer.IsEmpty ? CborReaderState.Finished : CborReaderState.FinishedWithTrailingBytes; } } if (_buffer.IsEmpty) { + if (_currentMajorType is null && _remainingDataItems is null) + { + // is at the end of a well-defined sequence of root-level values + return CborReaderState.Finished; + } + return CborReaderState.EndOfData; } @@ -94,19 +132,21 @@ public CborReaderState Peek() return CborReaderState.FormatError; } - if (_remainingDataItems == null) + if (_remainingDataItems is null) { - // stack guaranteed to be populated since root context cannot be indefinite-length - Debug.Assert(_nestedDataItemStack != null && _nestedDataItemStack.Count > 0); + // root context cannot be indefinite-length + Debug.Assert(_currentMajorType != null); - return _nestedDataItemStack.Peek().type switch + switch (_currentMajorType.Value) { - CborMajorType.ByteString => CborReaderState.EndByteString, - CborMajorType.TextString => CborReaderState.EndTextString, - CborMajorType.Array => CborReaderState.EndArray, - CborMajorType.Map when !_isEvenNumberOfDataItemsRead => CborReaderState.FormatError, - CborMajorType.Map => CborReaderState.EndMap, - _ => throw new Exception("CborReader internal error. Invalid CBOR major type pushed to stack."), + case CborMajorType.ByteString: return CborReaderState.EndByteString; + case CborMajorType.TextString: return CborReaderState.EndTextString; + case CborMajorType.Array: return CborReaderState.EndArray; + case CborMajorType.Map when !_currentItemIsKey: return CborReaderState.FormatError; + case CborMajorType.Map: return CborReaderState.EndMap; + default: + Debug.Fail("CborReader internal error. Invalid CBOR major type pushed to stack."); + throw new Exception("CborReader internal error. Invalid CBOR major type pushed to stack."); }; } else @@ -115,19 +155,14 @@ public CborReaderState Peek() } } - if (_remainingDataItems == null) + if (_remainingDataItems is null && _currentMajorType != null) { - // stack guaranteed to be populated since root context cannot be indefinite-length - Debug.Assert(_nestedDataItemStack != null && _nestedDataItemStack.Count > 0); - - CborMajorType parentType = _nestedDataItemStack.Peek().type; - - switch (parentType) + switch (_currentMajorType.Value) { case CborMajorType.ByteString: case CborMajorType.TextString: // indefinite length string contexts can only contain data items of same major type - if (initialByte.MajorType != parentType) + if (initialByte.MajorType != _currentMajorType.Value) { return CborReaderState.FormatError; } @@ -136,19 +171,27 @@ public CborReaderState Peek() } } - return initialByte.MajorType switch + switch (initialByte.MajorType) { - CborMajorType.UnsignedInteger => CborReaderState.UnsignedInteger, - CborMajorType.NegativeInteger => CborReaderState.NegativeInteger, - CborMajorType.ByteString when initialByte.AdditionalInfo == CborAdditionalInfo.IndefiniteLength => CborReaderState.StartByteString, - CborMajorType.ByteString => CborReaderState.ByteString, - CborMajorType.TextString when initialByte.AdditionalInfo == CborAdditionalInfo.IndefiniteLength => CborReaderState.StartTextString, - CborMajorType.TextString => CborReaderState.TextString, - CborMajorType.Array => CborReaderState.StartArray, - CborMajorType.Map => CborReaderState.StartMap, - CborMajorType.Tag => CborReaderState.Tag, - CborMajorType.Special => MapSpecialValueTagToReaderState(initialByte.AdditionalInfo), - _ => throw new Exception("CborReader internal error. Invalid major type."), + case CborMajorType.UnsignedInteger: return CborReaderState.UnsignedInteger; + case CborMajorType.NegativeInteger: return CborReaderState.NegativeInteger; + case CborMajorType.ByteString: + return (initialByte.AdditionalInfo == CborAdditionalInfo.IndefiniteLength) ? + CborReaderState.StartByteString : + CborReaderState.ByteString; + + case CborMajorType.TextString: + return (initialByte.AdditionalInfo == CborAdditionalInfo.IndefiniteLength) ? + CborReaderState.StartTextString : + CborReaderState.TextString; + + case CborMajorType.Array: return CborReaderState.StartArray; + case CborMajorType.Map: return CborReaderState.StartMap; + case CborMajorType.Tag: return CborReaderState.Tag; + case CborMajorType.Simple: return MapSpecialValueTagToReaderState(initialByte.AdditionalInfo); + default: + Debug.Fail("CborReader internal error. Invalid major type."); + throw new Exception("CborReader internal error. Invalid major type."); }; static CborReaderState MapSpecialValueTagToReaderState (CborAdditionalInfo value) @@ -157,10 +200,10 @@ static CborReaderState MapSpecialValueTagToReaderState (CborAdditionalInfo value switch (value) { - case CborAdditionalInfo.SpecialValueNull: + case CborAdditionalInfo.SimpleValueNull: return CborReaderState.Null; - case CborAdditionalInfo.SpecialValueFalse: - case CborAdditionalInfo.SpecialValueTrue: + case CborAdditionalInfo.SimpleValueFalse: + case CborAdditionalInfo.SimpleValueTrue: return CborReaderState.Boolean; case CborAdditionalInfo.Additional16BitData: return CborReaderState.HalfPrecisionFloat; @@ -196,24 +239,25 @@ private CborInitialByte PeekInitialByte() if (_buffer.IsEmpty) { - throw new FormatException("unexpected end of buffer."); + if (_currentMajorType is null && _remainingDataItems is null && _bytesRead > 0) + { + throw new InvalidOperationException("No remaining root-level CBOR data items in the buffer."); + } + + throw new FormatException("Unexpected end of buffer."); } var result = new CborInitialByte(_buffer.Span[0]); - // TODO check for tag state - - if (_nestedDataItemStack != null && _nestedDataItemStack.Count > 0) + if (_currentMajorType != null) { - CborMajorType parentType = _nestedDataItemStack.Peek().type; - - switch (parentType) + switch (_currentMajorType.Value) { // indefinite-length string contexts do not permit nesting case CborMajorType.ByteString: case CborMajorType.TextString: if (result.InitialByte == CborInitialByte.IndefiniteLengthBreakByte || - result.MajorType == parentType && + result.MajorType == _currentMajorType.Value && result.AdditionalInfo != CborAdditionalInfo.IndefiniteLength) { break; @@ -248,29 +292,42 @@ private void ReadNextIndefiniteLengthBreakByte() } } - private void PushDataItem(CborMajorType type, ulong? expectedNestedItems) + private void PushDataItem(CborMajorType majorType, int? expectedNestedItems) { - if (expectedNestedItems > (ulong)_buffer.Length) - { - throw new FormatException("Insufficient buffer size for declared definite length in CBOR data item."); - } + _nestedDataItems ??= new Stack(); + + var frame = new StackFrame( + type: _currentMajorType, + frameOffset: _frameOffset, + remainingDataItems: _remainingDataItems, + currentKeyOffset: _currentKeyOffset, + currentItemIsKey: _currentItemIsKey, + previousKeyRange: _previousKeyRange, + previousKeyRanges: _keyEncodingRanges + ); + + _nestedDataItems.Push(frame); - _nestedDataItemStack ??= new Stack<(CborMajorType, bool, ulong?)>(); - _nestedDataItemStack.Push((type, _isEvenNumberOfDataItemsRead, _remainingDataItems)); + _currentMajorType = majorType; _remainingDataItems = expectedNestedItems; - _isEvenNumberOfDataItemsRead = true; + _frameOffset = _bytesRead; + _isTagContext = false; + _currentKeyOffset = null; + _currentItemIsKey = false; + _previousKeyRange = null; + _keyEncodingRanges = null; } private void PopDataItem(CborMajorType expectedType) { - if (_nestedDataItemStack is null || _nestedDataItemStack.Count == 0) + if (_currentMajorType is null) { - throw new InvalidOperationException("No active CBOR nested data item to pop"); + throw new InvalidOperationException("No active CBOR nested data item to pop."); } - (CborMajorType actualType, bool isEvenNumberOfDataItemsWritten, ulong? remainingItems) = _nestedDataItemStack.Peek(); + Debug.Assert(_nestedDataItems?.Count > 0); - if (expectedType != actualType) + if (expectedType != _currentMajorType) { throw new InvalidOperationException("Unexpected major type in nested CBOR data item."); } @@ -285,15 +342,42 @@ private void PopDataItem(CborMajorType expectedType) throw new FormatException("CBOR tag should be followed by a data item."); } - _nestedDataItemStack.Pop(); - _remainingDataItems = remainingItems; - _isEvenNumberOfDataItemsRead = isEvenNumberOfDataItemsWritten; + if (_currentMajorType == CborMajorType.Map) + { + ReturnKeyEncodingRangeAllocation(); + } + + StackFrame frame = _nestedDataItems.Pop(); + + _currentMajorType = frame.MajorType; + _frameOffset = frame.FrameOffset; + _remainingDataItems = frame.RemainingDataItems; + _currentKeyOffset = frame.CurrentKeyOffset; + _currentItemIsKey = frame.CurrentItemIsKey; + _previousKeyRange = frame.PreviousKeyRange; + _keyEncodingRanges = frame.PreviousKeyRanges; + // Popping items from the stack can change the reader state + // without necessarily needing to advance the buffer + // (e.g. we're at the end of a definite-length collection). + // We therefore need to invalidate the cache here. + _cachedState = CborReaderState.Unknown; } private void AdvanceDataItemCounters() { + if (_currentKeyOffset != null) // is map context + { + if (_currentItemIsKey) + { + HandleMapKeyRead(); + } + else + { + HandleMapValueRead(); + } + } + _remainingDataItems--; - _isEvenNumberOfDataItemsRead = !_isEvenNumberOfDataItemsRead; _isTagContext = false; } @@ -301,6 +385,16 @@ private void AdvanceBuffer(int length) { _buffer = _buffer.Slice(length); _bytesRead += length; + // invalidate the state cache + _cachedState = CborReaderState.Unknown; + } + + private void ResetBuffer(int position) + { + _buffer = _originalBuffer.Slice(position); + _bytesRead = position; + // invalidate the state cache + _cachedState = CborReaderState.Unknown; } private void EnsureBuffer(int length) @@ -319,22 +413,118 @@ private static void EnsureBuffer(ReadOnlySpan buffer, int requiredLength) } } - private List<(int offset, int length)> AcquireRangeList() + private readonly struct StackFrame { - List<(int offset, int length)>? ranges = Interlocked.Exchange(ref _rangeListAllocation, null); + public StackFrame( + CborMajorType? type, + int frameOffset, + int? remainingDataItems, + int? currentKeyOffset, + bool currentItemIsKey, + (int Offset, int Length)? previousKeyRange, + HashSet<(int Offset, int Length)>? previousKeyRanges) + { + MajorType = type; + FrameOffset = frameOffset; + RemainingDataItems = remainingDataItems; + + CurrentKeyOffset = currentKeyOffset; + CurrentItemIsKey = currentItemIsKey; + PreviousKeyRange = previousKeyRange; + PreviousKeyRanges = previousKeyRanges; + } + + public CborMajorType? MajorType { get; } + public int FrameOffset { get; } + public int? RemainingDataItems { get; } - if (ranges != null) + public int? CurrentKeyOffset { get; } + public bool CurrentItemIsKey { get; } + public (int Offset, int Length)? PreviousKeyRange { get; } + public HashSet<(int Offset, int Length)>? PreviousKeyRanges { get; } + } + + // Struct containing checkpoint data for rolling back reader state in the event of a failure + // NB checkpoints do not contain stack information, so we can only roll back provided that the + // reader is within the original context in which the checkpoint was created + private readonly struct Checkpoint + { + public Checkpoint( + int bytesRead, + int stackDepth, + int frameOffset, + int? remainingDataItems, + int? currentKeyOffset, + bool currentItemIsKey, + (int Offset, int Length)? previousKeyRange, + HashSet<(int Offset, int Length)>? previousKeyRanges) { - ranges.Clear(); - return ranges; + BytesRead = bytesRead; + StackDepth = stackDepth; + FrameOffset = frameOffset; + RemainingDataItems = remainingDataItems; + + CurrentKeyOffset = currentKeyOffset; + CurrentItemIsKey = currentItemIsKey; + PreviousKeyRange = previousKeyRange; + PreviousKeyRanges = previousKeyRanges; } - return new List<(int, int)>(); + public int BytesRead { get; } + public int StackDepth { get; } + public int FrameOffset { get; } + public int? RemainingDataItems { get; } + + public int? CurrentKeyOffset { get; } + public bool CurrentItemIsKey { get; } + public (int Offset, int Length)? PreviousKeyRange { get; } + public HashSet<(int Offset, int Length)>? PreviousKeyRanges { get; } + } + + private Checkpoint CreateCheckpoint() + { + return new Checkpoint( + bytesRead: _bytesRead, + stackDepth: Depth, + frameOffset: _frameOffset, + remainingDataItems: _remainingDataItems, + currentKeyOffset: _currentKeyOffset, + currentItemIsKey: _currentItemIsKey, + previousKeyRange: _previousKeyRange, + previousKeyRanges: _keyEncodingRanges); } - private void ReturnRangeList(List<(int offset, int length)> ranges) + private void RestoreCheckpoint(in Checkpoint checkpoint) { - _rangeListAllocation = ranges; + if (_nestedDataItems != null) + { + int stackOffset = _nestedDataItems.Count - checkpoint.StackDepth; + + Debug.Assert(stackOffset >= 0, "Attempting to restore checkpoint outside of its original context."); + Debug.Assert( + (stackOffset == 0) ? + _frameOffset == checkpoint.FrameOffset : + _nestedDataItems.ToArray()[stackOffset - 1].FrameOffset == checkpoint.FrameOffset, + "Attempting to restore checkpoint outside of its original context."); + + // pop any nested data items introduced after the checkpoint + for (int i = 0; i < stackOffset; i++) + { + _nestedDataItems.Pop(); + } + } + + _buffer = _originalBuffer.Slice(checkpoint.BytesRead); + _bytesRead = checkpoint.BytesRead; + _frameOffset = checkpoint.FrameOffset; + _remainingDataItems = checkpoint.RemainingDataItems; + _currentKeyOffset = checkpoint.CurrentKeyOffset; + _currentItemIsKey = checkpoint.CurrentItemIsKey; + _previousKeyRange = checkpoint.PreviousKeyRange; + _keyEncodingRanges = checkpoint.PreviousKeyRanges; + + // invalidate the state cache + _cachedState = CborReaderState.Unknown; } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborTag.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborTag.cs index f7d4ca1f270e76..23cafd21a3e85b 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborTag.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborTag.cs @@ -2,14 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace System.Security.Cryptography.Encoding.Tests +namespace System.Formats.Cbor { // https://tools.ietf.org/html/rfc7049#section-2.4 - internal enum CborTag : ulong + public enum CborTag : ulong { DateTimeString = 0, - EpochDateTime = 1, - PositiveBigNum = 2, + UnixTimeSeconds = 1, + UnsignedBigNum = 2, NegativeBigNum = 3, DecimalFraction = 4, BigFloat = 5, @@ -29,7 +29,7 @@ internal enum CborTag : ulong } // https://tools.ietf.org/html/rfc7049#section-2.3 - internal enum CborSpecialValue : byte + public enum CborSimpleValue : byte { False = 20, True = 21, diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Array.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Array.cs index 39b54f28460b81..d2d8f139011f3a 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Array.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Array.cs @@ -3,12 +3,11 @@ // See the LICENSE file in the project root for more information. #nullable enable -using System.Buffers.Binary; -using System.Text; +using System.Diagnostics; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor { - internal partial class CborWriter + public partial class CborWriter { public void WriteStartArray(int definiteLength) { @@ -18,29 +17,43 @@ public void WriteStartArray(int definiteLength) } WriteUnsignedInteger(CborMajorType.Array, (ulong)definiteLength); - AdvanceDataItemCounters(); - PushDataItem(CborMajorType.Array, (uint)definiteLength); + PushDataItem(CborMajorType.Array, definiteLength); + } + + public void WriteStartArray() + { + EnsureWriteCapacity(1); + WriteInitialByte(new CborInitialByte(CborMajorType.Array, CborAdditionalInfo.IndefiniteLength)); + PushDataItem(CborMajorType.Array, definiteLength: null); } public void WriteEndArray() { - bool isDefiniteLengthArray = _remainingDataItems.HasValue; PopDataItem(CborMajorType.Array); + AdvanceDataItemCounters(); + } - if (!isDefiniteLengthArray) + private void PatchIndefiniteLengthCollection(CborMajorType majorType, int count) + { + Debug.Assert(majorType == CborMajorType.Array || majorType == CborMajorType.Map); + + int currentOffset = _offset; + int bytesToShift = GetIntegerEncodingLength((ulong)count) - 1; + + if (bytesToShift > 0) { - // append break byte for indefinite-length arrays - EnsureWriteCapacity(1); - _buffer[_offset++] = CborInitialByte.IndefiniteLengthBreakByte; + // length encoding requires more than 1 byte, need to shift encoded elements to the right + EnsureWriteCapacity(bytesToShift); + + ReadOnlySpan elementEncoding = _buffer.AsSpan(_frameOffset, currentOffset - _frameOffset); + Span target = _buffer.AsSpan(_frameOffset + bytesToShift, currentOffset - _frameOffset); + elementEncoding.CopyTo(target); } - } - public void WriteStartArrayIndefiniteLength() - { - EnsureWriteCapacity(1); - WriteInitialByte(new CborInitialByte(CborMajorType.Array, CborAdditionalInfo.IndefiniteLength)); - AdvanceDataItemCounters(); - PushDataItem(CborMajorType.Array, expectedNestedItems: null); + // rewind to the start of the collection and write a new initial byte + _offset = _frameOffset - 1; + WriteUnsignedInteger(majorType, (ulong)count); + _offset = currentOffset + bytesToShift; } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Integer.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Integer.cs index 6351306183840c..626a699a48edfe 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Integer.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Integer.cs @@ -4,9 +4,9 @@ using System.Buffers.Binary; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor { - internal partial class CborWriter + public partial class CborWriter { // Implements major type 0 encoding per https://tools.ietf.org/html/rfc7049#section-2.1 public void WriteUInt64(ulong value) @@ -31,47 +31,75 @@ public void WriteInt64(long value) AdvanceDataItemCounters(); } - public void WriteTag(CborTag tag) + public void WriteInt32(int value) => WriteInt64(value); + public void WriteUInt32(uint value) => WriteUInt64(value); + + // Writes a CBOR negative integer encoding according to + // https://tools.ietf.org/html/rfc7049#section-2.1 + public void WriteCborNegativeIntegerEncoding(ulong value) { - WriteUnsignedInteger(CborMajorType.Tag, (ulong)tag); - // NB tag writes do not advance data item counters - _isTagContext = true; + WriteUnsignedInteger(CborMajorType.NegativeInteger, value); + AdvanceDataItemCounters(); } // Unsigned integer encoding https://tools.ietf.org/html/rfc7049#section-2.1 private void WriteUnsignedInteger(CborMajorType type, ulong value) { - if (value < 24) + if (value < (byte)CborAdditionalInfo.Additional8BitData) { EnsureWriteCapacity(1); WriteInitialByte(new CborInitialByte(type, (CborAdditionalInfo)value)); } else if (value <= byte.MaxValue) { - EnsureWriteCapacity(2); + EnsureWriteCapacity(1 + sizeof(byte)); WriteInitialByte(new CborInitialByte(type, CborAdditionalInfo.Additional8BitData)); _buffer[_offset++] = (byte)value; } else if (value <= ushort.MaxValue) { - EnsureWriteCapacity(3); + EnsureWriteCapacity(1 + sizeof(ushort)); WriteInitialByte(new CborInitialByte(type, CborAdditionalInfo.Additional16BitData)); BinaryPrimitives.WriteUInt16BigEndian(_buffer.AsSpan(_offset), (ushort)value); - _offset += 2; + _offset += sizeof(ushort); } else if (value <= uint.MaxValue) { - EnsureWriteCapacity(5); + EnsureWriteCapacity(1 + sizeof(uint)); WriteInitialByte(new CborInitialByte(type, CborAdditionalInfo.Additional32BitData)); BinaryPrimitives.WriteUInt32BigEndian(_buffer.AsSpan(_offset), (uint)value); - _offset += 4; + _offset += sizeof(uint); } else { - EnsureWriteCapacity(9); + EnsureWriteCapacity(1 + sizeof(ulong)); WriteInitialByte(new CborInitialByte(type, CborAdditionalInfo.Additional64BitData)); BinaryPrimitives.WriteUInt64BigEndian(_buffer.AsSpan(_offset), value); - _offset += 8; + _offset += sizeof(ulong); + } + } + + private int GetIntegerEncodingLength(ulong value) + { + if (value < (byte)CborAdditionalInfo.Additional8BitData) + { + return 1; + } + else if (value <= byte.MaxValue) + { + return 1 + sizeof(byte); + } + else if (value <= ushort.MaxValue) + { + return 1 + sizeof(ushort); + } + else if (value <= uint.MaxValue) + { + return 1 + sizeof(uint); + } + else + { + return 1 + sizeof(ulong); } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Map.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Map.cs index 2ebe21918578cf..75c2497d1bce4f 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Map.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Map.cs @@ -3,49 +3,253 @@ // See the LICENSE file in the project root for more information. #nullable enable -using System.Text; +using System.Collections.Generic; +using System.Diagnostics; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor { - internal partial class CborWriter + public partial class CborWriter { + private KeyEncodingComparer? _keyEncodingComparer; + private Stack>? _pooledKeyEncodingRangeSets; + private Stack>? _pooledKeyValueEncodingRangeLists; + public void WriteStartMap(int definiteLength) { - if (definiteLength < 0) + if (definiteLength < 0 || definiteLength > int.MaxValue / 2) { - throw new ArgumentOutOfRangeException(nameof(definiteLength), "must be non-negative integer."); + throw new ArgumentOutOfRangeException(nameof(definiteLength)); } WriteUnsignedInteger(CborMajorType.Map, (ulong)definiteLength); - AdvanceDataItemCounters(); - PushDataItem(CborMajorType.Map, 2 * (uint)definiteLength); + PushDataItem(CborMajorType.Map, definiteLength: checked(2 * definiteLength)); + _currentKeyOffset = _offset; + } + + public void WriteStartMap() + { + EnsureWriteCapacity(1); + WriteInitialByte(new CborInitialByte(CborMajorType.Map, CborAdditionalInfo.IndefiniteLength)); + PushDataItem(CborMajorType.Map, definiteLength: null); + _currentKeyOffset = _offset; } public void WriteEndMap() { - if (!_isEvenNumberOfDataItemsWritten) + if (_itemsWritten % 2 == 1) { throw new InvalidOperationException("CBOR Map types require an even number of key/value combinations"); } - bool isDefiniteLengthMap = _remainingDataItems.HasValue; - PopDataItem(CborMajorType.Map); + AdvanceDataItemCounters(); + } + + // + // Map encoding conformance + // + + private void HandleKeyWritten() + { + Debug.Assert(_currentKeyOffset != null && _currentValueOffset == null); - if (!isDefiniteLengthMap) + if (CborConformanceLevelHelpers.RequiresUniqueKeys(ConformanceLevel)) { - // append break byte - EnsureWriteCapacity(1); - _buffer[_offset++] = CborInitialByte.IndefiniteLengthBreakByte; + HashSet<(int Offset, int Length)> keyEncodingRanges = GetKeyEncodingRanges(); + + (int Offset, int Length) currentKey = (_currentKeyOffset.Value, _offset - _currentKeyOffset.Value); + + if (!keyEncodingRanges.Add(currentKey)) + { + // reset writer state to right before the offending key write + _buffer.AsSpan(currentKey.Offset, _offset).Fill(0); + _offset = currentKey.Offset; + + throw new InvalidOperationException("Duplicate key encoding in CBOR map."); + } } + + // record the value buffer offset + _currentValueOffset = _offset; } - public void WriteStartMapIndefiniteLength() + private void HandleValueWritten() { - EnsureWriteCapacity(1); - WriteInitialByte(new CborInitialByte(CborMajorType.Map, CborAdditionalInfo.IndefiniteLength)); - AdvanceDataItemCounters(); - PushDataItem(CborMajorType.Map, expectedNestedItems: null); + Debug.Assert(_currentKeyOffset != null && _currentValueOffset != null); + + if (CborConformanceLevelHelpers.RequiresSortedKeys(ConformanceLevel)) + { + List keyValueRanges = GetKeyValueEncodingRanges(); + + var currentKeyValueRange = new KeyValueEncodingRange( + offset: _currentKeyOffset.Value, + keyLength: _currentValueOffset.Value - _currentKeyOffset.Value, + totalLength: _offset - _currentKeyOffset.Value); + + // Check that the keys are written in sorted order. + // Once invalidated, declare that the map requires sorting, + // which will prompt a sorting of the encodings once map writes have completed. + if (!_keysRequireSorting && keyValueRanges.Count > 0) + { + KeyEncodingComparer comparer = GetKeyEncodingComparer(); + KeyValueEncodingRange previousKeyValueRange = keyValueRanges[keyValueRanges.Count - 1]; + _keysRequireSorting = comparer.Compare(previousKeyValueRange, currentKeyValueRange) > 0; + } + + keyValueRanges.Add(currentKeyValueRange); + } + + // update offset state to the next key + _currentKeyOffset = _offset; + _currentValueOffset = null; + } + + private void CompleteMapWrite() + { + if (_keysRequireSorting) + { + Debug.Assert(_keyValueEncodingRanges != null); + + // sort the key/value ranges in-place + _keyValueEncodingRanges.Sort(GetKeyEncodingComparer()); + + // copy sorted ranges to temporary buffer + int totalMapPayloadEncodingLength = _offset - _frameOffset; + Span source = _buffer.AsSpan(); + + byte[] tempBuffer = s_bufferPool.Rent(totalMapPayloadEncodingLength); + Span tmpSpan = tempBuffer.AsSpan(0, totalMapPayloadEncodingLength); + + Span s = tmpSpan; + foreach (KeyValueEncodingRange range in _keyValueEncodingRanges) + { + ReadOnlySpan keyValueEncoding = source.Slice(range.Offset, range.TotalLength); + keyValueEncoding.CopyTo(s); + s = s.Slice(keyValueEncoding.Length); + } + Debug.Assert(s.IsEmpty); + + // now copy back to the original buffer segment & clean up + tmpSpan.CopyTo(source.Slice(_frameOffset, totalMapPayloadEncodingLength)); + s_bufferPool.Return(tempBuffer, clearArray: true); + } + + ReturnKeyEncodingRangeAllocation(); + ReturnKeyValueEncodingRangeAllocation(); + } + + // Gets or initializes a hashset containing all key encoding ranges for the current CBOR map context + // Equality of the HashSet is determined up to key encoding equality. + private HashSet<(int Offset, int Length)> GetKeyEncodingRanges() + { + if (_keyEncodingRanges != null) + { + return _keyEncodingRanges; + } + + if (_pooledKeyEncodingRangeSets != null && + _pooledKeyEncodingRangeSets.TryPop(out HashSet<(int Offset, int Length)>? result)) + { + result.Clear(); + return _keyEncodingRanges = result; + } + + return _keyEncodingRanges = new HashSet<(int Offset, int Length)>(GetKeyEncodingComparer()); + } + + + // Gets or initializes a list containing all key/value encoding ranges for the current CBOR map context + private void ReturnKeyEncodingRangeAllocation() + { + if (_keyEncodingRanges != null) + { + _pooledKeyEncodingRangeSets ??= new Stack>(); + _pooledKeyEncodingRangeSets.Push(_keyEncodingRanges); + _keyEncodingRanges = null; + } + } + + private List GetKeyValueEncodingRanges() + { + if (_keyValueEncodingRanges != null) + { + return _keyValueEncodingRanges; + } + + if (_pooledKeyValueEncodingRangeLists != null && + _pooledKeyValueEncodingRangeLists.TryPop(out List? result)) + { + result.Clear(); + return _keyValueEncodingRanges = result; + } + + return _keyValueEncodingRanges = new List(); + } + + private void ReturnKeyValueEncodingRangeAllocation() + { + if (_keyValueEncodingRanges != null) + { + _pooledKeyValueEncodingRangeLists ??= new Stack>(); + _pooledKeyValueEncodingRangeLists.Push(_keyValueEncodingRanges); + _keyValueEncodingRanges = null; + } + } + + private KeyEncodingComparer GetKeyEncodingComparer() + { + return _keyEncodingComparer ??= new KeyEncodingComparer(this); + } + + private readonly struct KeyValueEncodingRange + { + public KeyValueEncodingRange(int offset, int keyLength, int totalLength) + { + Offset = offset; + KeyLength = keyLength; + TotalLength = totalLength; + } + + public int Offset { get; } + public int KeyLength { get; } + public int TotalLength { get; } + } + + // Defines order and equality semantics for a key/value encoding range pair up to key encoding + private class KeyEncodingComparer : IComparer, + IEqualityComparer<(int Offset, int Length)> + { + private readonly CborWriter _writer; + + public KeyEncodingComparer(CborWriter writer) + { + _writer = writer; + } + + private Span GetKeyEncoding((int Offset, int Length) range) + { + return _writer._buffer.AsSpan(range.Offset, range.Length); + } + + private Span GetKeyEncoding(in KeyValueEncodingRange range) + { + return _writer._buffer.AsSpan(range.Offset, range.KeyLength); + } + + public int GetHashCode((int Offset, int Length) range) + { + return CborConformanceLevelHelpers.GetKeyEncodingHashCode(GetKeyEncoding(range)); + } + + public bool Equals((int Offset, int Length) x, (int Offset, int Length) y) + { + return CborConformanceLevelHelpers.AreEqualKeyEncodings(GetKeyEncoding(x), GetKeyEncoding(y)); + } + + public int Compare(KeyValueEncodingRange x, KeyValueEncodingRange y) + { + return CborConformanceLevelHelpers.CompareKeyEncodings(GetKeyEncoding(in x), GetKeyEncoding(in y), _writer.ConformanceLevel); + } } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Simple.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Simple.cs new file mode 100644 index 00000000000000..56d8133d69a367 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Simple.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers.Binary; + +namespace System.Formats.Cbor +{ + public partial class CborWriter + { + // Implements https://tools.ietf.org/html/rfc7049#section-2.3 + + public void WriteSingle(float value) + { + EnsureWriteCapacity(5); + WriteInitialByte(new CborInitialByte(CborMajorType.Simple, CborAdditionalInfo.Additional32BitData)); + BinaryPrimitives.WriteSingleBigEndian(_buffer.AsSpan(_offset), value); + _offset += 4; + AdvanceDataItemCounters(); + } + + public void WriteDouble(double value) + { + EnsureWriteCapacity(9); + WriteInitialByte(new CborInitialByte(CborMajorType.Simple, CborAdditionalInfo.Additional64BitData)); + BinaryPrimitives.WriteDoubleBigEndian(_buffer.AsSpan(_offset), value); + _offset += 8; + AdvanceDataItemCounters(); + } + + public void WriteBoolean(bool value) + { + WriteSimpleValue(value ? CborSimpleValue.True : CborSimpleValue.False); + } + + public void WriteNull() + { + WriteSimpleValue(CborSimpleValue.Null); + } + + public void WriteSimpleValue(CborSimpleValue value) + { + if ((byte)value < 24) + { + EnsureWriteCapacity(1); + WriteInitialByte(new CborInitialByte(CborMajorType.Simple, (CborAdditionalInfo)value)); + } + else + { + EnsureWriteCapacity(2); + WriteInitialByte(new CborInitialByte(CborMajorType.Simple, CborAdditionalInfo.Additional8BitData)); + _buffer[_offset++] = (byte)value; + } + + AdvanceDataItemCounters(); + } + } +} diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Special.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Special.cs deleted file mode 100644 index 20184b5b1f6f0f..00000000000000 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Special.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Buffers.Binary; - -namespace System.Security.Cryptography.Encoding.Tests.Cbor -{ - internal partial class CborWriter - { - // Implements https://tools.ietf.org/html/rfc7049#section-2.3 - - public void WriteSingle(float value) - { - EnsureWriteCapacity(5); - WriteInitialByte(new CborInitialByte(CborMajorType.Special, CborAdditionalInfo.Additional32BitData)); - BinaryPrimitives.WriteSingleBigEndian(_buffer.AsSpan(_offset), value); - _offset += 4; - AdvanceDataItemCounters(); - } - - public void WriteDouble(double value) - { - EnsureWriteCapacity(9); - WriteInitialByte(new CborInitialByte(CborMajorType.Special, CborAdditionalInfo.Additional64BitData)); - BinaryPrimitives.WriteDoubleBigEndian(_buffer.AsSpan(_offset), value); - _offset += 8; - AdvanceDataItemCounters(); - } - - public void WriteBoolean(bool value) - { - WriteSpecialValue(value ? CborSpecialValue.True : CborSpecialValue.False); - } - - public void WriteNull() - { - WriteSpecialValue(CborSpecialValue.Null); - } - - public void WriteSpecialValue(CborSpecialValue value) - { - if ((byte)value < 24) - { - EnsureWriteCapacity(1); - WriteInitialByte(new CborInitialByte(CborMajorType.Special, (CborAdditionalInfo)value)); - } - else - { - EnsureWriteCapacity(2); - WriteInitialByte(new CborInitialByte(CborMajorType.Special, CborAdditionalInfo.Additional8BitData)); - _buffer[_offset++] = (byte)value; - } - - AdvanceDataItemCounters(); - } - } -} diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.String.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.String.cs index 733b281f109b36..ca7cbc84d9a7a7 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.String.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.String.cs @@ -4,19 +4,33 @@ #nullable enable using System.Buffers.Binary; +using System.Collections.Generic; +using System.Diagnostics; using System.Text; +using System.Threading; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor { - internal partial class CborWriter + public partial class CborWriter { private static readonly System.Text.Encoding s_utf8Encoding = new System.Text.UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); + // keeps track of chunk offsets for written indefinite-length string ranges + private List<(int Offset, int Length)>? _currentIndefiniteLengthStringRanges = null; + // Implements major type 2 encoding per https://tools.ietf.org/html/rfc7049#section-2.1 public void WriteByteString(ReadOnlySpan value) { WriteUnsignedInteger(CborMajorType.ByteString, (ulong)value.Length); EnsureWriteCapacity(value.Length); + + if (!EncodeIndefiniteLengths && _currentMajorType == CborMajorType.ByteString) + { + // operation is writing chunk of an indefinite-length string + Debug.Assert(_currentIndefiniteLengthStringRanges != null); + _currentIndefiniteLengthStringRanges.Add((_offset, value.Length)); + } + value.CopyTo(_buffer.AsSpan(_offset)); _offset += value.Length; AdvanceDataItemCounters(); @@ -37,41 +51,97 @@ public void WriteTextString(ReadOnlySpan value) WriteUnsignedInteger(CborMajorType.TextString, (ulong)length); EnsureWriteCapacity(length); - s_utf8Encoding.GetBytes(value, _buffer.AsSpan(_offset)); + + if (!EncodeIndefiniteLengths && _currentMajorType == CborMajorType.TextString) + { + // operation is writing chunk of an indefinite-length string + Debug.Assert(_currentIndefiniteLengthStringRanges != null); + _currentIndefiniteLengthStringRanges.Add((_offset, value.Length)); + } + + s_utf8Encoding.GetBytes(value, _buffer.AsSpan(_offset, length)); _offset += length; AdvanceDataItemCounters(); } - public void WriteStartByteStringIndefiniteLength() + public void WriteStartByteString() { + if (!EncodeIndefiniteLengths) + { + // Writer does not allow indefinite-length encodings. + // We need to keep track of chunk offsets to convert to + // a definite-length encoding once writing is complete. + _currentIndefiniteLengthStringRanges ??= new List<(int, int)>(); + } + EnsureWriteCapacity(1); WriteInitialByte(new CborInitialByte(CborMajorType.ByteString, CborAdditionalInfo.IndefiniteLength)); - AdvanceDataItemCounters(); - PushDataItem(CborMajorType.ByteString, expectedNestedItems: null); + PushDataItem(CborMajorType.ByteString, definiteLength: null); } - public void WriteEndByteStringIndefiniteLength() + public void WriteEndByteString() { PopDataItem(CborMajorType.ByteString); - // append break byte - EnsureWriteCapacity(1); - _buffer[_offset++] = CborInitialByte.IndefiniteLengthBreakByte; + AdvanceDataItemCounters(); } - public void WriteStartTextStringIndefiniteLength() + public void WriteStartTextString() { + if (!EncodeIndefiniteLengths) + { + // Writer does not allow indefinite-length encodings. + // We need to keep track of chunk offsets to convert to + // a definite-length encoding once writing is complete. + _currentIndefiniteLengthStringRanges ??= new List<(int, int)>(); + } + EnsureWriteCapacity(1); WriteInitialByte(new CborInitialByte(CborMajorType.TextString, CborAdditionalInfo.IndefiniteLength)); - AdvanceDataItemCounters(); - PushDataItem(CborMajorType.TextString, expectedNestedItems: null); + PushDataItem(CborMajorType.TextString, definiteLength: null); } - public void WriteEndTextStringIndefiniteLength() + public void WriteEndTextString() { PopDataItem(CborMajorType.TextString); - // append break byte - EnsureWriteCapacity(1); - _buffer[_offset++] = CborInitialByte.IndefiniteLengthBreakByte; + AdvanceDataItemCounters(); + } + + private void PatchIndefiniteLengthString(CborMajorType type) + { + Debug.Assert(type == CborMajorType.ByteString || type == CborMajorType.TextString); + Debug.Assert(_currentIndefiniteLengthStringRanges != null); + + int currentOffset = _offset; + + // calculate the definite length of the concatenated string + int definiteLength = 0; + foreach ((int _, int length) in _currentIndefiniteLengthStringRanges) + { + definiteLength += length; + } + + // copy chunks to a temporary buffer + byte[] tempBuffer = s_bufferPool.Rent(definiteLength); + Span tempSpan = tempBuffer.AsSpan(0, definiteLength); + + Span s = tempSpan; + foreach ((int offset, int length) in _currentIndefiniteLengthStringRanges) + { + _buffer.AsSpan(offset, length).CopyTo(s); + s = s.Slice(length); + } + Debug.Assert(s.IsEmpty); + + // write back to the original buffer + _offset = _frameOffset - 1; + WriteUnsignedInteger(type, (ulong)definiteLength); + tempSpan.CopyTo(_buffer.AsSpan(_offset, definiteLength)); + _offset += definiteLength; + + // zero out excess bytes & other cleanups + _buffer.AsSpan(_offset, currentOffset - _offset).Fill(0); + s_bufferPool.Return(tempBuffer, clearArray: true); + _currentIndefiniteLengthStringRanges.Clear(); } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Tag.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Tag.cs new file mode 100644 index 00000000000000..39980cee3a7f6e --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.Tag.cs @@ -0,0 +1,168 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Numerics; + +namespace System.Formats.Cbor +{ + public partial class CborWriter + { + public void WriteTag(CborTag tag) + { + if (!CborConformanceLevelHelpers.AllowsTags(ConformanceLevel)) + { + throw new InvalidOperationException("Tagged items are not permitted under the current conformance level."); + } + + WriteUnsignedInteger(CborMajorType.Tag, (ulong)tag); + _isTagContext = true; + } + + // Additional tagged type support + + internal const string Rfc3339FormatString = "yyyy-MM-ddTHH:mm:ss.FFFFFFFK"; + + public void WriteDateTimeOffset(DateTimeOffset value) + { + string dateString = + value.Offset == TimeSpan.Zero ? + value.UtcDateTime.ToString(Rfc3339FormatString) : // prefer 'Z' over '+00:00' + value.ToString(Rfc3339FormatString); + + WriteTag(CborTag.DateTimeString); + WriteTextString(dateString); + } + + public void WriteUnixTimeSeconds(long seconds) + { + WriteTag(CborTag.UnixTimeSeconds); + WriteInt64(seconds); + } + + public void WriteUnixTimeSeconds(double seconds) + { + if (double.IsInfinity(seconds) || double.IsNaN(seconds)) + { + throw new ArgumentException("Value cannot be infinite or NaN.", nameof(seconds)); + } + + WriteTag(CborTag.UnixTimeSeconds); + WriteDouble(seconds); + } + + public void WriteBigInteger(BigInteger value) + { + bool isUnsigned = value.Sign >= 0; + BigInteger unsignedValue = isUnsigned ? value : -1 - value; + byte[] unsignedBigEndianEncoding = unsignedValue.ToByteArray(isUnsigned: true, isBigEndian: true); + + WriteTag(isUnsigned ? CborTag.UnsignedBigNum : CborTag.NegativeBigNum); + WriteByteString(unsignedBigEndianEncoding); + } + + public void WriteDecimal(decimal value) + { + // implements https://tools.ietf.org/html/rfc7049#section-2.4.3 + DecimalHelpers.Deconstruct(value, out decimal mantissa, out byte scale); + + WriteTag(CborTag.DecimalFraction); + WriteStartArray(2); + WriteInt64(-(long)scale); + + if (-1m - ulong.MinValue <= mantissa && mantissa <= ulong.MaxValue) + { + if (mantissa >= 0m) + { + WriteUInt64((ulong)mantissa); + } + else + { + WriteCborNegativeIntegerEncoding((ulong)(-1m - mantissa)); + } + } + else + { + // the mantissa can also be a BigNum + WriteBigInteger((BigInteger)mantissa); + } + + WriteEndArray(); + } + } + + internal static class DecimalHelpers + { + private const int SignMask = unchecked((int)0x80000000); + private const int ScaleMask = 0x00ff0000; + private const int ScaleShift = 16; + private const int ExponentUpperBound = 28; + + /// deconstructs a decimal value into its signed integral component and negative base-10 exponent + public static void Deconstruct(decimal value, out decimal mantissa, out byte scale) + { + Span buf = stackalloc int[4]; + decimal.GetBits(value, buf); + + int flags = buf[3]; + bool isNegative = (flags & SignMask) == SignMask; + mantissa = new decimal(lo: buf[0], mid: buf[1], hi: buf[2], isNegative: isNegative, scale: 0); + scale = (byte)((flags & ScaleMask) >> ScaleShift); + } + + /// reconstructs a decimal value out of a signed integral component and a negative base-10 exponent + public static decimal Reconstruct(decimal mantissa, byte scale) + { + Span buf = stackalloc int[4]; + decimal.GetBits(mantissa, buf); + + int flags = buf[3]; + bool isNegative = (flags & SignMask) == SignMask; + Debug.Assert((flags & ScaleMask) == 0, "mantissa argument should be integral."); + return new decimal(lo: buf[0], mid: buf[1], hi: buf[2], isNegative: isNegative, scale: scale); + } + + public static decimal Reconstruct(decimal mantissa, long exponent) + { + if (mantissa == 0) + { + return mantissa; + } + else if (exponent > ExponentUpperBound) + { + throw new OverflowException("Value was either too large or too small for a Decimal."); + } + else if (exponent >= 0) + { + // for positive exponents attempt to compute its decimal representation, + // with risk of throwing OverflowException + for (; exponent >= 5; exponent -= 5) + { + mantissa *= 100_000m; + } + + switch (exponent) + { + case 0: return mantissa; + case 1: return mantissa * 10m; + case 2: return mantissa * 100m; + case 3: return mantissa * 1000m; + case 4: return mantissa * 10000m; + default: + Debug.Fail("Unreachable code in decimal exponentiation logic"); + throw new Exception("Unreachable code in decimal exponentiation logic"); + } + } + else if (exponent >= -ExponentUpperBound) + { + // exponent falls within range of decimal normal-form representation + return Reconstruct(mantissa, (byte)(-exponent)); + } + else + { + throw new OverflowException("Value was either too large or too small for a Decimal."); + } + } + } +} diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.cs index ff2d81f33910bd..2b77f2d7cc78f4 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/CborWriter.cs @@ -5,11 +5,12 @@ #nullable enable using System.Buffers; using System.Collections.Generic; +using System.Diagnostics; using System.Threading; -namespace System.Security.Cryptography.Encoding.Tests.Cbor +namespace System.Formats.Cbor { - internal partial class CborWriter : IDisposable + public partial class CborWriter : IDisposable { // TODO : determine if CryptoPool is more appropriate private static readonly ArrayPool s_bufferPool = ArrayPool.Create(); @@ -17,26 +18,48 @@ internal partial class CborWriter : IDisposable private byte[] _buffer = null!; private int _offset = 0; - // remaining number of data items in current cbor context - // with null representing indefinite length data items. - // The root context ony permits one data item to be written. - private uint? _remainingDataItems = 1; - private bool _isEvenNumberOfDataItemsWritten = true; // required for indefinite-length map writes - private Stack<(CborMajorType type, bool isEvenNumberOfDataItemsWritten, uint? remainingDataItems)>? _nestedDataItemStack; + private Stack? _nestedDataItems; + private CborMajorType? _currentMajorType = null; // major type of the current data item context + private int? _definiteLength; // predetermined definite-length of current data item context + private int _itemsWritten = 0; // number of items written in the current context + private int _frameOffset = 0; // buffer offset particular to the current data item context private bool _isTagContext = false; // true if writer is expecting a tagged value - public CborWriter() + // Map-specific conformance book-keeping + private int? _currentKeyOffset = null; + private int? _currentValueOffset = null; + // State required for sorting map keys + private bool _keysRequireSorting = false; + private List? _keyValueEncodingRanges = null; + // State required for checking key uniqueness + private HashSet<(int Offset, int Length)>? _keyEncodingRanges = null; + + public CborWriter(CborConformanceLevel conformanceLevel = CborConformanceLevel.Lax, bool encodeIndefiniteLengths = false, bool allowMultipleRootLevelValues = false) { + CborConformanceLevelHelpers.Validate(conformanceLevel); + + if (encodeIndefiniteLengths && CborConformanceLevelHelpers.RequiresDefiniteLengthItems(conformanceLevel)) + { + throw new ArgumentException($"Conformance level {conformanceLevel} does not allow indefinite length encodings.", nameof(encodeIndefiniteLengths)); + } + ConformanceLevel = conformanceLevel; + EncodeIndefiniteLengths = encodeIndefiniteLengths; + AllowMultipleRootLevelValues = allowMultipleRootLevelValues; + _definiteLength = allowMultipleRootLevelValues ? null : (int?)1; } + public CborConformanceLevel ConformanceLevel { get; } + public bool EncodeIndefiniteLengths { get; } + public bool AllowMultipleRootLevelValues { get; } + public int Depth => _nestedDataItems is null ? 0 : _nestedDataItems.Count; public int BytesWritten => _offset; // Returns true iff a complete CBOR document has been written to buffer - public bool IsWriteCompleted => _remainingDataItems == 0 && (_nestedDataItemStack?.Count ?? 0) == 0; + public bool IsWriteCompleted => _currentMajorType is null && _itemsWritten > 0; public void WriteEncodedValue(ReadOnlyMemory encodedValue) { - ValidateEncoding(encodedValue); + ValidateEncoding(encodedValue, ConformanceLevel); ReadOnlySpan encodedValueSpan = encodedValue.Span; EnsureWriteCapacity(encodedValueSpan.Length); @@ -57,13 +80,13 @@ public void WriteEncodedValue(ReadOnlyMemory encodedValue) AdvanceDataItemCounters(); - static void ValidateEncoding(ReadOnlyMemory encodedValue) + static void ValidateEncoding(ReadOnlyMemory encodedValue, CborConformanceLevel conformanceLevel) { - var reader = new CborReader(encodedValue); + var reader = new CborReader(encodedValue, conformanceLevel: conformanceLevel); try { - reader.SkipValue(); + reader.SkipValue(validateConformance: true); } catch (FormatException e) { @@ -77,6 +100,35 @@ static void ValidateEncoding(ReadOnlyMemory encodedValue) } } + public byte[] GetEncoding() => GetSpanEncoding().ToArray(); + + public bool TryWriteEncoding(Span destination, out int bytesWritten) + { + ReadOnlySpan encoding = GetSpanEncoding(); + + if (encoding.Length > destination.Length) + { + bytesWritten = 0; + return false; + } + + encoding.CopyTo(destination); + bytesWritten = encoding.Length; + return true; + } + + private ReadOnlySpan GetSpanEncoding() + { + CheckDisposed(); + + if (!IsWriteCompleted) + { + throw new InvalidOperationException("Buffer contains incomplete CBOR document."); + } + + return (_offset == 0) ? ReadOnlySpan.Empty : new ReadOnlySpan(_buffer, 0, _offset); + } + private void EnsureWriteCapacity(int pendingCount) { CheckDisposed(); @@ -103,67 +155,115 @@ private void EnsureWriteCapacity(int pendingCount) } } - private void PushDataItem(CborMajorType type, uint? expectedNestedItems) + private void PushDataItem(CborMajorType majorType, int? definiteLength) { - _nestedDataItemStack ??= new Stack<(CborMajorType, bool, uint?)>(); - _nestedDataItemStack.Push((type, _isEvenNumberOfDataItemsWritten, _remainingDataItems)); - _remainingDataItems = expectedNestedItems; - _isEvenNumberOfDataItemsWritten = true; + _nestedDataItems ??= new Stack(); + + var frame = new StackFrame( + type: _currentMajorType, + frameOffset: _frameOffset, + definiteLength: _definiteLength, + itemsWritten: _itemsWritten, + currentKeyOffset: _currentKeyOffset, + currentValueOffset: _currentValueOffset, + keysRequireSorting: _keysRequireSorting, + keyValueEncodingRanges: _keyValueEncodingRanges, + keyEncodingRanges: _keyEncodingRanges + ); + + _nestedDataItems.Push(frame); + + _currentMajorType = majorType; + _frameOffset = _offset; + _definiteLength = definiteLength; + _itemsWritten = 0; + _currentKeyOffset = null; + _currentValueOffset = null; + _keysRequireSorting = false; + _keyEncodingRanges = null; + _keyValueEncodingRanges = null; } private void PopDataItem(CborMajorType expectedType) { - if (_nestedDataItemStack is null || _nestedDataItemStack.Count == 0) - { - throw new InvalidOperationException("No active CBOR nested data item to pop"); - } - - (CborMajorType actualType, bool isEvenNumberOfDataItemsWritten, uint? remainingItems) = _nestedDataItemStack.Peek(); + // Validate that the pop operation can be performed - if (expectedType != actualType) + if (expectedType != _currentMajorType) { throw new InvalidOperationException("Unexpected major type in nested CBOR data item."); } + Debug.Assert(_nestedDataItems?.Count > 0); + if (_isTagContext) { throw new InvalidOperationException("Tagged CBOR value context is incomplete."); } - if (_remainingDataItems > 0) + if (_definiteLength - _itemsWritten > 0) { throw new InvalidOperationException("Definite-length nested CBOR data item is incomplete."); } - _nestedDataItemStack.Pop(); - _remainingDataItems = remainingItems; - _isEvenNumberOfDataItemsWritten = isEvenNumberOfDataItemsWritten; + // Perform encoding fixups that require the current context and must be done before popping + // NB map key sorting must happen before indefinite-length patching + + if (expectedType == CborMajorType.Map) + { + CompleteMapWrite(); + } + + if (_definiteLength == null) + { + CompleteIndefiniteLengthWrite(expectedType); + } + + // pop writer state + StackFrame frame = _nestedDataItems.Pop(); + _currentMajorType = frame.MajorType; + _frameOffset = frame.FrameOffset; + _definiteLength = frame.DefiniteLength; + _itemsWritten = frame.ItemsWritten; + _currentKeyOffset = frame.CurrentKeyOffset; + _currentValueOffset = frame.CurrentValueOffset; + _keysRequireSorting = frame.KeysRequireSorting; + _keyValueEncodingRanges = frame.KeyValueEncodingRanges; + _keyEncodingRanges = frame.KeyEncodingRanges; } private void AdvanceDataItemCounters() { - _remainingDataItems--; + if (_currentMajorType == CborMajorType.Map) + { + if (_itemsWritten % 2 == 0) + { + HandleKeyWritten(); + } + else + { + HandleValueWritten(); + } + } + + _itemsWritten++; _isTagContext = false; - _isEvenNumberOfDataItemsWritten = !_isEvenNumberOfDataItemsWritten; } private void WriteInitialByte(CborInitialByte initialByte) { - if (_remainingDataItems == 0) + if (_definiteLength - _itemsWritten == 0) { throw new InvalidOperationException("Adding a CBOR data item to the current context exceeds its definite length."); } - if (_nestedDataItemStack != null && _nestedDataItemStack.Count > 0) + if (_currentMajorType != null) { - CborMajorType parentType = _nestedDataItemStack.Peek().type; - - switch (parentType) + switch (_currentMajorType.Value) { // indefinite-length string contexts do not permit nesting case CborMajorType.ByteString: case CborMajorType.TextString: - if (initialByte.MajorType == parentType && + if (initialByte.MajorType == _currentMajorType && initialByte.AdditionalInfo != CborAdditionalInfo.IndefiniteLength) { break; @@ -195,16 +295,73 @@ public void Dispose() } } - public byte[] ToArray() + private void CompleteIndefiniteLengthWrite(CborMajorType type) { - CheckDisposed(); + Debug.Assert(_definiteLength == null); - if (!IsWriteCompleted) + if (EncodeIndefiniteLengths) { - throw new InvalidOperationException("Buffer contains incomplete CBOR document."); + // using indefinite-length encoding, append a break byte to the existing encoding + EnsureWriteCapacity(1); + _buffer[_offset++] = CborInitialByte.IndefiniteLengthBreakByte; + } + else + { + // indefinite-length not allowed, convert the encoding into definite-length + switch (type) + { + case CborMajorType.ByteString: + case CborMajorType.TextString: + PatchIndefiniteLengthString(type); + break; + case CborMajorType.Array: + PatchIndefiniteLengthCollection(CborMajorType.Array, _itemsWritten); + break; + case CborMajorType.Map: + Debug.Assert(_itemsWritten % 2 == 0); + PatchIndefiniteLengthCollection(CborMajorType.Map, _itemsWritten / 2); + break; + default: + Debug.Fail("Invalid CBOR major type pushed to stack."); + throw new Exception("CborReader internal error. Invalid CBOR major type pushed to stack."); + } } + } + + private readonly struct StackFrame + { + public StackFrame( + CborMajorType? type, + int frameOffset, + int? definiteLength, + int itemsWritten, + int? currentKeyOffset, + int? currentValueOffset, + bool keysRequireSorting, + List? keyValueEncodingRanges, + HashSet<(int Offset, int Length)>? keyEncodingRanges) + { + MajorType = type; + FrameOffset = frameOffset; + DefiniteLength = definiteLength; + ItemsWritten = itemsWritten; + CurrentKeyOffset = currentKeyOffset; + CurrentValueOffset = currentValueOffset; + KeysRequireSorting = keysRequireSorting; + KeyValueEncodingRanges = keyValueEncodingRanges; + KeyEncodingRanges = keyEncodingRanges; + } + + public CborMajorType? MajorType { get; } + public int FrameOffset { get; } + public int? DefiniteLength { get; } + public int ItemsWritten { get; } - return (_offset == 0) ? Array.Empty() : _buffer.AsSpan(0, _offset).ToArray(); + public int? CurrentKeyOffset { get; } + public int? CurrentValueOffset { get; } + public bool KeysRequireSorting { get; } + public List? KeyValueEncodingRanges { get; } + public HashSet<(int Offset, int Length)>? KeyEncodingRanges { get; } } } } diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/System.Formats.Cbor.Shared.projitems b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/System.Formats.Cbor.Shared.projitems new file mode 100644 index 00000000000000..e557599560c806 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Cbor/System.Formats.Cbor.Shared.projitems @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/Oid.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/Oid.cs index 6e6b04f6549df3..cafaa03caed90a 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/Oid.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/Oid.cs @@ -330,6 +330,21 @@ public static void LookupOidByFriendlyName_Method_UnixOnly() Assert.Equal(ObsoleteSmime3desWrap_Name, oid.FriendlyName); } + [Theory] + [InlineData("nistP256", "1.2.840.10045.3.1.7")] + [InlineData("secP256r1", "1.2.840.10045.3.1.7")] + [InlineData("x962P256v1", "1.2.840.10045.3.1.7")] + [InlineData("nistP384", "1.3.132.0.34")] + [InlineData("secP384r1", "1.3.132.0.34")] + [InlineData("nistP521", "1.3.132.0.35")] + [InlineData("secP521r1", "1.3.132.0.35")] + public static void LookupOidByFriendlyName_AdditionalNames(string friendlyName, string expectedOid) + { + Oid oid = Oid.FromFriendlyName(friendlyName, OidGroup.All); + Assert.Equal(friendlyName, oid.FriendlyName); + Assert.Equal(expectedOid, oid.Value); + } + public static IEnumerable ValidOidFriendlyNamePairs { get diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/PemEncodingFindTests.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/PemEncodingFindTests.cs index 874b862cd4cf80..fe9e3723672f11 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/PemEncodingFindTests.cs +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/PemEncodingFindTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Security.Cryptography; +using System.Text; using Xunit; namespace System.Security.Cryptography.Encoding.Tests @@ -260,12 +261,46 @@ public void Find_Success_FindsPemAfterPemWithInvalidLabel() Assert.Equal("Zm9v", content[fields.Base64Data]); } + [Fact] + public void TryFind_Success_AfterSuccessiveInvalidBase64() + { + StringBuilder builder = new StringBuilder(); + + for (int i = 0; i < 100; i++) + { + builder.Append($"-----BEGIN CERTIFICATE-----\n${i:000}\n-----END CERTIFICATE-----\n"); + } + + builder.Append($"-----BEGIN CERTIFICATE-----\nZm9v\n-----END CERTIFICATE-----"); + + AssertPemFound(builder.ToString(), + expectedLocation: 5900..5958, + expectedBase64: 5928..5932, + expectedLabel: 5911..5922); + } + [Fact] public void Find_Fail_Empty() { AssertNoPemFound(string.Empty); } + [Fact] + public void Find_Fail_InvalidBase64_MultipleInvalid_WithSurroundingText() + { + string content = @" +CN=Intermediate1 +-----BEGIN CERTIFICATE----- +MII +-----END CERTIFICATE----- +CN=Intermediate2 +-----BEGIN CERTIFICATE----- +MII +-----END CERTIFICATE----- +"; + AssertNoPemFound(content); + } + [Fact] public void Find_Fail_PostEbBeforePreEb() { diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj b/src/libraries/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj index 5e0e4749d0896f..e89c8cf8318ff4 100644 --- a/src/libraries/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj @@ -1,13 +1,11 @@ - + true $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix - - Common\System\Security\Cryptography\CryptoPool.cs - + @@ -48,49 +46,36 @@ + + + + + + + + + + + + + + + - - + + + - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - CommonTest\System\Security\Cryptography\ByteUtils.cs - - - Common\System\Memory\PointerMemoryManager.cs - + diff --git a/src/libraries/System.Security.Cryptography.OpenSsl/ref/System.Security.Cryptography.OpenSsl.csproj b/src/libraries/System.Security.Cryptography.OpenSsl/ref/System.Security.Cryptography.OpenSsl.csproj index 0f70b59154c8e9..cc4944963eddde 100644 --- a/src/libraries/System.Security.Cryptography.OpenSsl/ref/System.Security.Cryptography.OpenSsl.csproj +++ b/src/libraries/System.Security.Cryptography.OpenSsl/ref/System.Security.Cryptography.OpenSsl.csproj @@ -1,6 +1,6 @@ - netcoreapp3.0;$(NetCoreAppCurrent) + $(NetCoreAppCurrent);netcoreapp3.0 true enable diff --git a/src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj b/src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj index 6f9f04c70d5743..03996c4a2fbdfa 100644 --- a/src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj +++ b/src/libraries/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj @@ -1,11 +1,14 @@ true - 4.1.0.0 - netcoreapp3.0-Unix;netcoreapp3.0;netstandard2.0;$(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent) + $(NetCoreAppCurrent)-Unix;$(NetCoreAppCurrent);netcoreapp3.0-Unix;netcoreapp3.0;netstandard2.0 true enable + + + 4.1.0.0 + SR.PlatformNotSupported_CryptographyOpenSSL - 4.0.4.0 Microsoft diff --git a/src/libraries/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.csproj b/src/libraries/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.csproj index 3755542fba331e..07a5f1e62c2207 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.csproj +++ b/src/libraries/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.csproj @@ -1,16 +1,21 @@ - true - netcoreapp3.0;netstandard2.1;net461;$(NetFrameworkCurrent);$(NetCoreAppCurrent) + $(NetCoreAppCurrent);netcoreapp3.0;netstandard2.1;net461;$(NetFrameworkCurrent) true true enable + + + true + + 4.0.4.0 + - + - + diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs index 4521098338058c..9e59207b5902aa 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs @@ -21,8 +21,6 @@ namespace Internal.Cryptography { internal static partial class PkcsHelpers { - private static readonly byte[] s_pSpecifiedDefaultParameters = { 0x04, 0x00 }; - #if !NETCOREAPP && !NETSTANDARD2_1 // Compatibility API. internal static void AppendData(this IncrementalHash hasher, ReadOnlySpan data) @@ -532,8 +530,6 @@ public static byte[] EncodeOctetString(byte[] octets) } } - private static readonly byte[] s_invalidEmptyOid = { 0x06, 0x00 }; - public static byte[] EncodeUtcTime(DateTime utcTime) { const int maxLegalYear = 2049; @@ -573,16 +569,16 @@ public static DateTime DecodeUtcTime(byte[] encodedUtcTime) return value.UtcDateTime; } - public static string DecodeOid(byte[] encodedOid) + public static string DecodeOid(ReadOnlySpan encodedOid) { - // Windows compat. - if (s_invalidEmptyOid.AsSpan().SequenceEqual(encodedOid)) + // Windows compat for a zero length OID. + if (encodedOid.Length == 2 && encodedOid[0] == 0x06 && encodedOid[1] == 0x00) { return string.Empty; } // Read using BER because the CMS specification says the encoding is BER. - AsnReader reader = new AsnReader(encodedOid, AsnEncodingRules.BER); + AsnValueReader reader = new AsnValueReader(encodedOid, AsnEncodingRules.BER); string value = reader.ReadObjectIdentifierAsString(); reader.ThrowIfNotEmpty(); return value; @@ -623,8 +619,10 @@ public static bool TryGetRsaOaepEncryptionPadding( return false; } + ReadOnlySpan pSpecifiedDefaultParameters = new byte[] { 0x04, 0x00 }; + if (oaepParameters.PSourceFunc.Parameters != null && - !oaepParameters.PSourceFunc.Parameters.Value.Span.SequenceEqual(s_pSpecifiedDefaultParameters)) + !oaepParameters.PSourceFunc.Parameters.Value.Span.SequenceEqual(pSpecifiedDefaultParameters)) { exception = new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); return false; diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography.Pkcs/src/Resources/Strings.resx index 117980b01ba6e5..aa366d559ef7d6 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/Resources/Strings.resx @@ -1,4 +1,5 @@ - + + @@ -57,8 +58,8 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - String cannot be empty or null. + + The `{0}` string cannot be empty or null. Only single dimensional arrays are supported for the requested action. @@ -214,10 +215,10 @@ New Pkcs12SafeBag values cannot be added to a Pkcs12SafeContents that was read from existing data. - This decryption operation applies to 'Pkcs12ConfidentialityMode.{0}', but the target object is in 'Pkcs12ConfidentialityMode.{1}'. + This decryption operation applies to 'Pkcs12ConfidentialityMode.{0}', but the target object is in 'Pkcs12ConfidentialityMode.{1}'. - This verification operation applies to 'Pkcs12IntegrityMode.{0}', but the target object is in 'Pkcs12IntegrityMode.{1}'. + This verification operation applies to 'Pkcs12IntegrityMode.{0}', but the target object is in 'Pkcs12IntegrityMode.{1}'. Invalid signature paramters. @@ -294,4 +295,4 @@ Certificate already present in the collection. - + \ No newline at end of file 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 8f3d58028081ee..d6fc49b30ecc8d 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 @@ -1,8 +1,6 @@ true - true - true true true $(NoWarn);CS1574;CS3016;CA5379;CA5384 @@ -11,6 +9,13 @@ true true + + + true + true + + 4.0.4.0 + @@ -160,225 +163,153 @@ - - Common\Interop\Windows\Advapi32\Interop.CryptAcquireContext.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptDestroyHash.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptDestroyKey.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptGetProvParam.cs - - - Common\Interop\Windows\Advapi32\Interop.CryptReleaseContext.cs - - - Common\Interop\Windows\Advapi32\SafeHashHandle.cs - - - Common\Interop\Windows\Advapi32\SafeKeyHandle.cs - - - Common\Interop\Windows\Advapi32\SafeProvHandle.cs - - - Common\Interop\Windows\Crypt32\Interop.CERT_CONTEXT.cs - - - Common\Interop\Windows\Crypt32\Interop.CERT_ID.cs - - - Common\Interop\Windows\Crypt32\Interop.CERT_INFO.cs - - - Common\Interop\Windows\Crypt32\Interop.CERT_ISSUER_SERIAL_NUMBER.cs - - - Common\Interop\Windows\Crypt32\Interop.CERT_PUBLIC_KEY_INFO.cs - - - Common\Interop\Windows\Crypt32\Interop.CertContextPropId.cs - - - Common\Interop\Windows\Crypt32\Interop.CertCreateCertificateContext.cs - - - Common\Interop\Windows\Crypt32\Interop.CertFreeCertificateContext.cs - - - Common\Interop\Windows\Crypt32\Interop.CertGetCertificateContextProperty.cs - - - Common\Interop\Windows\Crypt32\Interop.CertGetPublicKeyLength.cs - - - Common\Interop\Windows\Crypt32\Interop.CertIdChoice.cs - - - Common\Interop\Windows\Crypt32\Interop.CertNameStrTypeAndFlags.cs - - - Common\Interop\Windows\Crypt32\Interop.CertNameToStr.cs - - - Common\Interop\Windows\Crypt32\Interop.CMSG_CMS_RECIPIENT_INFO.cs - - - Common\Interop\Windows\Crypt32\Interop.CMSG_CTRL_DECRYPT_PARA.cs - - - Common\Interop\Windows\Crypt32\Interop.CMSG_CTRL_KEY_AGREE_DECRYPT_PARA.cs - - - Common\Interop\Windows\Crypt32\Interop.CMSG_ENVELOPED_ENCODE_INFO.cs - - - Common\Interop\Windows\Crypt32\Interop.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO.cs - - - Common\Interop\Windows\Crypt32\Interop.CMSG_KEY_AGREE_RECIPIENT_INFO.cs - - - Common\Interop\Windows\Crypt32\Interop.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO.cs - - - Common\Interop\Windows\Crypt32\Interop.CMSG_KEY_TRANS_RECIPIENT_INFO.cs - - - Common\Interop\Windows\Crypt32\Interop.CMSG_RC2_AUX_INFO.cs - - - Common\Interop\Windows\Crypt32\Interop.CMSG_RECIPIENT_ENCODE_INFO.cs - - - Common\Interop\Windows\Crypt32\Interop.CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO.cs - - - Common\Interop\Windows\Crypt32\Interop.CMSG_RECIPIENT_ENCRYPTED_KEY_INFO.cs - - - Common\Interop\Windows\Crypt32\Interop.CMsgCmsRecipientChoice.cs - - - Common\Interop\Windows\Crypt32\Interop.CMsgKeyAgreeOriginatorChoice.cs - - - Common\Interop\Windows\Crypt32\Interop.CmsKeyAgreeKeyChoice.cs - - - Common\Interop\Windows\Crypt32\Interop.CRYPT_ALGORITHM_IDENTIFIER.cs - - - Common\Interop\Windows\Crypt32\Interop.CRYPT_ATTRIBUTE.cs - - - Common\Interop\Windows\Crypt32\Interop.CRYPT_ATTRIBUTE_TYPE_VALUE.cs - - - Common\Interop\Windows\Crypt32\Interop.CRYPT_ATTRIBUTES.cs - - - Common\Interop\Windows\Crypt32\Interop.CRYPT_BIT_BLOB.cs - - - Common\Interop\Windows\Crypt32\Interop.CRYPT_KEY_PROV_INFO.cs - - - Common\Interop\Windows\Crypt32\Interop.CRYPT_RC2_CBC_PARAMETERS.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptAcquireCertificatePrivateKey.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptAcquireCertificatePrivateKeyFlags.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptDecodeObject.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptDecodeObjectStructType.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptEncodeDecodeWrappers.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptEncodeObject.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptKeySpec.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptMsgClose.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptMsgControl.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptMsgGetParam.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptMsgOpenToDecode.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptMsgOpenToEncode.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptMsgParamType.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptMsgType.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptMsgUpdate.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptRc2Version.cs - - - Common\Interop\Windows\Crypt32\Interop.DATA_BLOB.cs - - - Common\Interop\Windows\Crypt32\Interop.ErrorCode.cs - - - Common\Interop\Windows\Crypt32\Interop.FindOidInfo.cs - - - Common\Interop\Windows\Crypt32\Interop.MsgControlType.cs - - - Common\Interop\Windows\Crypt32\Interop.MsgEncodingType.cs - - - Common\Interop\Windows\kernel32\Interop.FormatMessage.cs - - - Common\Interop\Windows\kernel32\Interop.Heap.cs - - - Common\Interop\Windows\NCrypt\Interop.ErrorCode.cs - - - Common\Interop\Windows\NCrypt\Interop.Properties.cs - - - Common\Interop\Windows\NCrypt\Interop.NCryptFreeObject.cs - - - Common\Interop\Windows\Interop.Libraries.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - Common\Internal\Cryptography\Windows\CryptoThrowHelper.cs - - - Common\Microsoft\Win32\SafeHandles\SafeHandleCache.cs - + + @@ -388,7 +319,7 @@ - + @@ -417,15 +348,12 @@ - - Common\System\Memory\PointerMemoryManager.cs - - - Common\System\Security\Cryptography\CryptoPool.cs - - - Common\System\Security\Cryptography\Oids.cs - + + + Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml @@ -654,10 +582,9 @@ - - - Common\System\Security\Cryptography\KeyFormatHelper.cs - + + Common\System\Security\Cryptography\Asn1\DigestInfoAsn.xml @@ -704,12 +631,10 @@ Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedDataAsn.xml.cs Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedDataAsn.xml - - Common\System\Security\Cryptography\PasswordBasedEncryption.cs - - - Common\System\Security\Cryptography\Pkcs12Kdf.cs - + + System\Security\Cryptography\Pkcs\Asn1\SecretBagAsn.xml diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Pkcs12Builder.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Pkcs12Builder.cs index 4290deb59336b6..be3874b32d4bb1 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Pkcs12Builder.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Pkcs12Builder.cs @@ -41,7 +41,7 @@ public void AddSafeContentsEncrypted( if (pbeParameters == null) throw new ArgumentNullException(nameof(pbeParameters)); if (pbeParameters.IterationCount < 1) - throw new ArgumentOutOfRangeException(nameof(pbeParameters.IterationCount)); + throw new ArgumentOutOfRangeException(nameof(pbeParameters)); if (safeContents.ConfidentialityMode != Pkcs12ConfidentialityMode.None) throw new ArgumentException(SR.Cryptography_Pkcs12_CannotProcessEncryptedSafeContents, nameof(safeContents)); if (IsSealed) @@ -89,7 +89,7 @@ public void AddSafeContentsEncrypted( if (pbeParameters == null) throw new ArgumentNullException(nameof(pbeParameters)); if (pbeParameters.IterationCount < 1) - throw new ArgumentOutOfRangeException(nameof(pbeParameters.IterationCount)); + throw new ArgumentOutOfRangeException(nameof(pbeParameters)); if (safeContents.ConfidentialityMode != Pkcs12ConfidentialityMode.None) throw new ArgumentException(SR.Cryptography_Pkcs12_CannotProcessEncryptedSafeContents, nameof(safeContents)); if (IsSealed) diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Pkcs9AttributeObject.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Pkcs9AttributeObject.cs index 11bb644cafa871..cb86b388484eaa 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Pkcs9AttributeObject.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Pkcs9AttributeObject.cs @@ -32,12 +32,12 @@ public Pkcs9AttributeObject(AsnEncodedData asnEncodedData) : base(asnEncodedData) { if (asnEncodedData.Oid == null) - throw new ArgumentNullException(nameof(asnEncodedData.Oid)); + throw new ArgumentException(SR.Format(SR.Arg_EmptyOrNullString_Named, "asnEncodedData.Oid"), nameof(asnEncodedData)); string? szOid = base.Oid!.Value; if (szOid == null) - throw new ArgumentNullException("oid.Value"); + throw new ArgumentException(SR.Format(SR.Arg_EmptyOrNullString_Named, "oid.Value"), nameof(asnEncodedData)); if (szOid.Length == 0) - throw new ArgumentException(SR.Arg_EmptyOrNullString, "oid.Value"); + throw new ArgumentException(SR.Format(SR.Arg_EmptyOrNullString_Named, "oid.Value"), nameof(asnEncodedData)); } internal Pkcs9AttributeObject(Oid oid) diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignedCms.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignedCms.cs index d45d274e7639bd..74646c7186cd3a 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignedCms.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignedCms.cs @@ -45,7 +45,7 @@ public SignedCms(SubjectIdentifierType signerIdentifierType, ContentInfo content if (contentInfo == null) throw new ArgumentNullException(nameof(contentInfo)); if (contentInfo.Content == null) - throw new ArgumentNullException("contentInfo.Content"); + throw new ArgumentException(SR.Format(SR.Arg_EmptyOrNullString_Named, "contentInfo.Content"), nameof(contentInfo)); // Normalize the subject identifier type the same way as .NET Framework. // This value is only used in the zero-argument ComputeSignature overload, diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignerInfo.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignerInfo.cs index 9247ae50b14bf8..3d1e349f529857 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignerInfo.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignerInfo.cs @@ -358,9 +358,7 @@ public void RemoveCounterSignature(int index) { if (index < 0) { - // In .NET Framework RemoveCounterSignature doesn't bounds check, but the helper it calls does. - // In the helper the argument is called "childIndex". - throw new ArgumentOutOfRangeException("childIndex"); + throw new ArgumentOutOfRangeException(nameof(index)); } // The SignerInfo class is a projection of data contained within the SignedCms. diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/Pkcs9AttributeTests.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/Pkcs9AttributeTests.cs index 9591a1bce1a5b3..79aa1a42805f5d 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/tests/Pkcs9AttributeTests.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/Pkcs9AttributeTests.cs @@ -24,7 +24,7 @@ public static void Pkcs9AttributeAsnEncodedDataCtorNullOid() { AsnEncodedData a = new AsnEncodedData(new byte[3]); object ign; - Assert.Throws(() => ign = new Pkcs9AttributeObject(a)); + AssertExtensions.Throws("asnEncodedData", "asnEncodedData.Oid", () => ign = new Pkcs9AttributeObject(a)); } [Fact] @@ -112,7 +112,7 @@ public static void Pkcs9AttributeAsnEncodedDataCtorNullOidValue() AsnEncodedData a = new AsnEncodedData(oid, new byte[3]); object ign; - Assert.Throws(() => ign = new Pkcs9AttributeObject(a)); + AssertExtensions.Throws("asnEncodedData", "oid.Value", () => ign = new Pkcs9AttributeObject(a)); } [Fact] @@ -123,7 +123,7 @@ public static void Pkcs9AttributeAsnEncodedDataCtorEmptyOidValue() AsnEncodedData a = new AsnEncodedData(oid, new byte[3]); object ign; - AssertExtensions.Throws("oid.Value", () => ign = new Pkcs9AttributeObject(a)); + AssertExtensions.Throws("asnEncodedData", "oid.Value", () => ign = new Pkcs9AttributeObject(a)); } [Fact] diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignerInfoTests.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignerInfoTests.cs index 34a48544a868b9..ddfa1dd7f7976d 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignerInfoTests.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/SignedCms/SignerInfoTests.cs @@ -481,6 +481,7 @@ public static void RemoveCounterSignature_Negative() SignerInfo signer = cms.SignerInfos[0]; ArgumentOutOfRangeException ex = AssertExtensions.Throws( + "index", "childIndex", () => signer.RemoveCounterSignature(-1)); diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/System.Security.Cryptography.Pkcs.Tests.csproj b/src/libraries/System.Security.Cryptography.Pkcs/tests/System.Security.Cryptography.Pkcs.Tests.csproj index 6ec360c29c787c..24e7d29d0ae398 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/tests/System.Security.Cryptography.Pkcs.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/System.Security.Cryptography.Pkcs.Tests.csproj @@ -4,9 +4,8 @@ $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent);$(NetFrameworkCurrent)-Windows_NT - - CommonTest\System\Security\Cryptography\ByteUtils.cs - + @@ -32,10 +31,11 @@ - + + @@ -62,10 +62,7 @@ - - - - + \ No newline at end of file diff --git a/src/libraries/System.Security.Cryptography.Primitives/src/System.Security.Cryptography.Primitives.csproj b/src/libraries/System.Security.Cryptography.Primitives/src/System.Security.Cryptography.Primitives.csproj index df10307ed42440..908b170d33d579 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/src/System.Security.Cryptography.Primitives.csproj +++ b/src/libraries/System.Security.Cryptography.Primitives/src/System.Security.Cryptography.Primitives.csproj @@ -24,28 +24,22 @@ - - Common\System\Threading\Tasks\ForceAsyncAwaiter.cs - - - Internal\Cryptography\Helpers.cs - - - Common\System\Security\Cryptography\CryptoPool.cs - - - Common\System\Security\Cryptography\KeySizeHelpers.cs - - - Common\System\Security\Cryptography\Oids.cs - - - Common\System\Threading\Tasks\TaskToApm.cs - + + + + + + - \ No newline at end of file + diff --git a/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoConfigForwarder.cs b/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoConfigForwarder.cs index c42440669f4b4d..9e1055857753a3 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoConfigForwarder.cs +++ b/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoConfigForwarder.cs @@ -25,7 +25,7 @@ internal static class CryptoConfigForwarder throw new MissingMethodException(t.FullName, CreateFromNameMethodName); } - return (Func)createFromName.CreateDelegate(typeof(Func)); + return createFromName.CreateDelegate>(); } internal static object? CreateFromName(string name) => s_createFromName(name); diff --git a/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HashAlgorithmName.cs b/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HashAlgorithmName.cs index b76655a555a295..f921b2f5c5ca04 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HashAlgorithmName.cs +++ b/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HashAlgorithmName.cs @@ -105,6 +105,21 @@ public override int GetHashCode() return !(left == right); } + /// + /// Tries to convert the specified OID to a hash algorithm name. + /// + /// The OID of the hash algorithm. + /// + /// When this method returns true, the hash algorithm. When this + /// method returns false, contains default. + /// + /// + /// true if the OID was successfully mapped to a hash + /// algorithm; otherwise false. + /// + /// + /// is null. + /// public static bool TryFromOid(string oidValue, out HashAlgorithmName value) { if (oidValue is null) @@ -135,6 +150,19 @@ public static bool TryFromOid(string oidValue, out HashAlgorithmName value) } } + /// + /// Converts the specified OID to a hash algorithm name. + /// + /// The OID of the hash algorithm. + /// + /// The hash algorithm name identified by the OID. + /// + /// + /// is null. + /// + /// + /// does not represent a known hash algorithm. + /// public static HashAlgorithmName FromOid(string oidValue) { if (TryFromOid(oidValue, out HashAlgorithmName value)) diff --git a/src/libraries/System.Security.Cryptography.Primitives/tests/System.Security.Cryptography.Primitives.Tests.csproj b/src/libraries/System.Security.Cryptography.Primitives/tests/System.Security.Cryptography.Primitives.Tests.csproj index 6a871d86030580..02859eff46c5c9 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/tests/System.Security.Cryptography.Primitives.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Primitives/tests/System.Security.Cryptography.Primitives.Tests.csproj @@ -3,9 +3,8 @@ $(NetCoreAppCurrent) - - CommonTest\System\IO\PositionValueStream.cs - + @@ -23,4 +22,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Security.Cryptography.ProtectedData/ref/System.Security.Cryptography.ProtectedData.csproj b/src/libraries/System.Security.Cryptography.ProtectedData/ref/System.Security.Cryptography.ProtectedData.csproj index 4bd7dc1cbc791c..e01f4e1577f900 100644 --- a/src/libraries/System.Security.Cryptography.ProtectedData/ref/System.Security.Cryptography.ProtectedData.csproj +++ b/src/libraries/System.Security.Cryptography.ProtectedData/ref/System.Security.Cryptography.ProtectedData.csproj @@ -1,13 +1,16 @@ - true netstandard2.0;net461;$(NetFrameworkCurrent) true + + + true + - + diff --git a/src/libraries/System.Security.Cryptography.ProtectedData/src/System.Security.Cryptography.ProtectedData.csproj b/src/libraries/System.Security.Cryptography.ProtectedData/src/System.Security.Cryptography.ProtectedData.csproj index 08baa54b43202a..02bf06853e93b5 100644 --- a/src/libraries/System.Security.Cryptography.ProtectedData/src/System.Security.Cryptography.ProtectedData.csproj +++ b/src/libraries/System.Security.Cryptography.ProtectedData/src/System.Security.Cryptography.ProtectedData.csproj @@ -1,52 +1,46 @@ true - true - true - SR.PlatformNotSupported_CryptographyProtectedData netstandard2.0-Windows_NT;net461-Windows_NT;netstandard2.0;$(NetFrameworkCurrent)-Windows_NT true - + + + true + true + SR.PlatformNotSupported_CryptographyProtectedData + + - - Common\Interop\Windows\Crypt32\Interop.CryptProtectData.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptUnprotectData.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptProtectDataFlags.cs - - - Common\Interop\Windows\Crypt32\Interop.DATA_BLOB.cs - - - Common\Interop\Windows\Interop.Errors.cs - - - Internal\Cryptography\Windows\CryptoThrowHelper.cs - - - Internal\Windows\kernel32\Interop.FormatMessage.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\System\HResults.cs - + + + + + + + + + - + - + - + \ No newline at end of file diff --git a/src/libraries/System.Security.Cryptography.ProtectedData/tests/System.Security.Cryptography.ProtectedData.Tests.csproj b/src/libraries/System.Security.Cryptography.ProtectedData/tests/System.Security.Cryptography.ProtectedData.Tests.csproj index 412b5dd0ac0621..2d90d9b44f076b 100644 --- a/src/libraries/System.Security.Cryptography.ProtectedData/tests/System.Security.Cryptography.ProtectedData.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.ProtectedData/tests/System.Security.Cryptography.ProtectedData.Tests.csproj @@ -5,8 +5,7 @@ - - CommonTest\System\Security\Cryptography\ByteUtils.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/CertificatePal.PrivateKey.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/CertificatePal.PrivateKey.cs index 5ba5eb0a55c26b..2baabf516b3258 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/CertificatePal.PrivateKey.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/CertificatePal.PrivateKey.cs @@ -215,8 +215,9 @@ public ICertificatePal CopyWithPrivateKey(RSA rsa) IntPtr privateKeyPtr; - // If the certificate has a key handle instead of a key prov info, return the + // If the certificate has a key handle without a key prov info, return the // ephemeral key + if (!certificateContext.HasPersistedPrivateKey) { int cbData = IntPtr.Size; diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx index 37fc7642786bc6..d5e8ac308897f7 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx @@ -1,4 +1,5 @@ - + + @@ -66,6 +67,9 @@ String cannot be empty or null. + + The '{0}' string cannot be empty or null. + Illegal enum value: {0}. @@ -74,7 +78,7 @@ Invalid type. - + Non-negative number required. @@ -223,7 +227,7 @@ The provided hash value is not the expected size for the specified hash algorithm. - The Disallowed store is not supported on this platform, but already has data. All files under '{0}' must be removed. + The Disallowed store is not supported on this platform, but already has data. All files under '{0}' must be removed. Unix LocalMachine X509Stores are read-only for all users. @@ -235,7 +239,7 @@ The Disallowed store is not supported on this platform. - The {0} value cannot be set on Unix. + The {0} value cannot be set on Unix. '{0}' is not a known hash algorithm. @@ -286,7 +290,7 @@ The X509 certificate store is read-only. - The platform does not have a definition for an X509 certificate store named '{0}' with a StoreLocation of '{1}', and does not support creating it. + The platform does not have a definition for an X509 certificate store named '{0}' with a StoreLocation of '{1}', and does not support creating it. Enumeration has not started. Call MoveNext. @@ -417,4 +421,4 @@ Key is not a valid private key. - + \ No newline at end of file diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj b/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj index 1d0586c53367d6..d1de01a95e8c81 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj @@ -12,24 +12,18 @@ - - Common\Microsoft\Win32\SafeHandles\SafeHandleCache.cs - - - Common\System\Memory\PointerMemoryManager.cs - - - Common\System\Security\Cryptography\CryptoPool.cs - - - Common\System\Security\Cryptography\Oids.cs - - - Common\System\Security\Cryptography\KeyBlobHelpers.cs - - - Common\System\Security\Cryptography\KeySizeHelpers.cs - + + + + + + Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml @@ -105,15 +99,12 @@ Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.manual.cs Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.xml - - Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs - - - Internal\Cryptography\Helpers.cs - - - Common\System\HexConverter.cs - + + + @@ -250,54 +241,38 @@ - - Common\Interop\Windows\Crypt32\Interop.CertCloseStore.cs - - - Common\Interop\Windows\Crypt32\Interop.CertNameToStr.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptMsgClose.cs - - - Common\Interop\Windows\Crypt32\Interop.CertFreeCertificateContext.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptFormatObject.cs - - - Common\Interop\Windows\Crypt32\Interop.FindOidInfo.cs - - - Common\Internal\Cryptography\Windows\CryptoThrowHelper.cs - - - Common\Internal\Windows\kernel32\Interop.FormatMessage.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptDestroyKey.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptExportKey.cs - - - Common\Interop\Windows\BCrypt\Interop.BCryptGetProperty.cs - - - Common\Interop\Windows\BCrypt\Interop.Blobs.cs - - - Common\Interop\Windows\BCrypt\Interop.NTSTATUS.cs - - - Common\Microsoft\Win32\SafeHandles\SafeBCryptHandle.cs - - - Common\Microsoft\Win32\SafeHandles\SafeBCryptKeyHandle.cs - + + + + + + + + + + + + + + + + @@ -308,15 +283,12 @@ System\Security\Cryptography\X509Certificates\Asn1\DistributionPointNameAsn.xml - - Common\System\Security\Cryptography\KeyFormatHelper.cs - - - Common\System\Security\Cryptography\PasswordBasedEncryption.cs - - - Common\System\Security\Cryptography\Pkcs12Kdf.cs - + + + @@ -338,224 +310,152 @@ - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\Interop.Errors.cs - - - Common\Interop\Unix\System.Native\Interop.Permissions.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ASN1.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ASN1.GetIntegerBytes.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ASN1.Nid.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Bignum.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.BIO.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Encode.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Initialization.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.OCSP.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Pkcs12.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Pkcs7.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Rsa.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509Ext.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509Name.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509Stack.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.X509StoreCtx.cs - - - Common\Interop\Unix\Interop.Close.cs - - - Common\Interop\Unix\System.Native\Interop.FChMod.cs - - - Common\Interop\Unix\Interop.GetEUid.cs - - - Common\Interop\Unix\Interop.GetPwUid.cs - - - Common\Interop\Unix\System.Native\Interop.Stat.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Crypto.cs - - - Common\Interop\Unix\System.Security.Cryptography.Native\Interop.PooledCrypto.cs - - - Common\Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeBignumHandle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeBioHandle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeInteriorHandle.cs - - - Common\Microsoft\Win32\SafeHandles\SafePkcs12Handle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafePkcs7Handle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeRsaHandle.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\SafeX509Handles.Unix.cs - - - Common\Microsoft\Win32\SafeHandles\X509ExtensionSafeHandles.Unix.cs - - - Common\System\IO\PersistedFiles.Unix.cs - - - Common\System\IO\PersistedFiles.Names.Unix.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Hash.cs - - - Common\Interop\OSX\Interop.CoreFoundation.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFArray.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFData.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFDate.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFError.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFString.cs - - - Common\Interop\OSX\Interop.Libraries.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Ecc.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Err.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Keychain.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.PAL_HashAlgorithm.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.RSA.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.SecErr.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.SecErrMessage.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.SecKeyRef.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.SecKeyRef.Export.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Trust.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.X509.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.X509Chain.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.X509Store.cs - - - Common\Microsoft\Win32\SafeHandles\SafeCreateHandle.OSX.cs - - - Common\System\Security\Cryptography\DSAKeyFormatHelper.cs - - - Common\System\Security\Cryptography\DSASecurityTransforms.cs - - - Common\System\Security\Cryptography\EccKeyFormatHelper.cs - - - Common\System\Security\Cryptography\EccSecurityTransforms.cs - - - Common\System\Security\Cryptography\ECDsaSecurityTransforms.cs - - - Common\System\Security\Cryptography\KeyFormatHelper.cs - - - Common\System\Security\Cryptography\PasswordBasedEncryption.cs - - - Common\System\Security\Cryptography\Pkcs12Kdf.cs - - - Common\System\Security\Cryptography\RSAKeyFormatHelper.cs - - - Common\System\Security\Cryptography\RsaPaddingProcessor.cs - - - Common\System\Security\Cryptography\RSASecurityTransforms.cs - - - Common\System\Security\Cryptography\SecKeyPair.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Common\System\Security\Cryptography\Asn1\CurveAsn.xml diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Extension.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Extension.cs index af338130269227..84d5cb3eae3e97 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Extension.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Extension.cs @@ -31,7 +31,7 @@ public X509Extension(Oid oid, byte[] rawData, bool critical) if (base.Oid == null || base.Oid.Value == null) throw new ArgumentNullException(nameof(oid)); if (base.Oid.Value.Length == 0) - throw new ArgumentException(SR.Arg_EmptyOrNullString, "oid.Value"); + throw new ArgumentException(SR.Format(SR.Arg_EmptyOrNullString_Named, "oid.Value"), nameof(oid)); Critical = critical; } diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/ChainTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/ChainTests.cs index b6a0367c2a9084..6ed015272b4a9a 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/ChainTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/ChainTests.cs @@ -1063,6 +1063,209 @@ void CheckChain() } } + [Fact] + [PlatformSpecific(~TestPlatforms.Linux)] + public static void BuildChainForFraudulentCertificate() + { + // This certificate is a misissued certificate for a "high-value" + // domain, mail.google.com. Windows and macOS give this certificate + // special distrust treatment beyond normal revocation, resulting + // in ExplicitDistrust. OpenSSL relies on normal revocation routines + // to distrust this certificate, so we skip this test on Linux. + + byte[] certBytes = Convert.FromBase64String(@" +MIIF7jCCBNagAwIBAgIQBH7L6fylX3vQnq424QyuHjANBgkqhkiG9w0BAQUFADCB +lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt +SGFyZHdhcmUwHhcNMTEwMzE1MDAwMDAwWhcNMTQwMzE0MjM1OTU5WjCB3zELMAkG +A1UEBhMCVVMxDjAMBgNVBBETBTM4NDc3MRAwDgYDVQQIEwdGbG9yaWRhMRAwDgYD +VQQHEwdFbmdsaXNoMRcwFQYDVQQJEw5TZWEgVmlsbGFnZSAxMDEUMBIGA1UEChML +R29vZ2xlIEx0ZC4xEzARBgNVBAsTClRlY2ggRGVwdC4xKDAmBgNVBAsTH0hvc3Rl +ZCBieSBHVEkgR3JvdXAgQ29ycG9yYXRpb24xFDASBgNVBAsTC1BsYXRpbnVtU1NM +MRgwFgYDVQQDEw9tYWlsLmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQCwc/DyBO7CokbKNCqqu2Aj0RF2Hx860GWDTppFqENwhXbwH4cA +Ah9uOxcXxLXpGUaikiWNYiq0YzAfuYX4NeEWWnZJzFBIUzlZidaEAvua7BvHUdV2 +lZDUOiq4pt4CTQb7ze2lRkFfVXTl7H5A3FCcteQ1XR5oIPjp3qNqKL9B0qGz4iWN +DBvKPZMMGK7fxbz9vIK6aADXFjJxn2W1EdpoWdCmV2Qbyf6Y5fWlZerh2+70s52z +juqHrhbSHqB8fGk/KRaFAVOnbPFgq92i/CVH1DLREt33SBLg/Jyid5jpiZm4+Djx +jAbCeiM2bZudzTDIxzQXHrt9Qsir5xUW9nO1AgMBAAGjggHqMIIB5jAfBgNVHSME +GDAWgBShcl8mGyiYQ5VdBzfVhZadS9LDRTAdBgNVHQ4EFgQUGCqiyNR6P3utBIu9 +b54QRhN4cZ0wDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYw +FAYIKwYBBQUHAwEGCCsGAQUFBwMCMEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQME +MCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5jb20vQ1BTMHsG +A1UdHwR0MHIwOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1VUTi1VU0VS +Rmlyc3QtSGFyZHdhcmUuY3JsMDagNKAyhjBodHRwOi8vY3JsLmNvbW9kby5uZXQv +VVROLVVTRVJGaXJzdC1IYXJkd2FyZS5jcmwwcQYIKwYBBQUHAQEEZTBjMDsGCCsG +AQUFBzAChi9odHRwOi8vY3J0LmNvbW9kb2NhLmNvbS9VVE5BZGRUcnVzdFNlcnZl +ckNBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMC8G +A1UdEQQoMCaCD21haWwuZ29vZ2xlLmNvbYITd3d3Lm1haWwuZ29vZ2xlLmNvbTAN +BgkqhkiG9w0BAQUFAAOCAQEAZwYICifFk24C8t4XP9DTG3z/tc16x3fHvt8Syhne +sBNXDAORxHlSz3+3XlUghEnd9dApLw4E2lmeDhOf9MAym/+hESQql6PyPz0qa6it +jBl1lQ4dJf1PxHoVwx3HE0DIDb6XYHKm/iW+j+zVpobDIVxZUtlqC1yfS961+ezi +9MXMYlN2iWXkKdq3v5bgYI0NtwlV1kBVHcHyliF1r4mGH12BlykoHinXlsEgAzJ7 +ADtqNxdao7MabzI7bvGjXaurzCrLMAwfNSOLaURc6qwoYO2ra2Oe9pK8vZpaJkzF +mLgOGT78BTHjFtn9kAUDhsZXAR9/eKDPM2qqZmsi0KdJIw=="); + + using (X509Certificate2 cert = new X509Certificate2(certBytes)) + using (ChainHolder chainHolder = new ChainHolder()) + { + X509Chain chain = chainHolder.Chain; + chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + chain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2); + Assert.False(chain.Build(cert)); + + X509ChainElement certElement = chain.ChainElements + .OfType() + .Single(e => e.Certificate.Subject == cert.Subject); + + const X509ChainStatusFlags ExpectedFlag = X509ChainStatusFlags.ExplicitDistrust; + X509ChainStatusFlags actualFlags = certElement.AllStatusFlags(); + Assert.True((actualFlags & ExpectedFlag) == ExpectedFlag, $"Has expected flag {ExpectedFlag} but was {actualFlags}"); + } + } + + [Fact] + [PlatformSpecific(~TestPlatforms.Linux)] + public static void BuildChainForCertificateSignedWithDisallowedKey() + { + // The intermediate certificate is from the now defunct CA DigiNotar. + // This intermediate is disallowed on the macOS on Windows platforms + // which result in an ExplicitDistrust result. OpenSSL does not treat + // this intermediate differently, and distributions have removed the + // root CA from the trust store anyway, resulting in a partial chain. + // Since OpenSSL isn't going out of its way to give the CA or its + // intermediates any special distrust, we skip this test on Linux. + + byte[] intermediateBytes = Convert.FromBase64String(@" +MIIDzTCCAzagAwIBAgIERpwssDANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC +VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u +ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc +KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u +ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNzA3 +MjYxNTU5MDBaFw0xMzA4MjYxNjI5MDBaMGgxCzAJBgNVBAYTAk5MMRIwEAYDVQQK +EwlEaWdpTm90YXIxIzAhBgNVBAMTGkRpZ2lOb3RhciBTZXJ2aWNlcyAxMDI0IENB +MSAwHgYJKoZIhvcNAQkBFhFpbmZvQGRpZ2lub3Rhci5ubDCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEA2ptNXTz50eKLxsYIIMXZHkjsZlhneWIrQWP0iY1o2q+4 +lDaLGSSkoJPSmQ+yrS01Tc0vauH5mxkrvAQafi09UmTN8T5nD4ku6PJPrqYIoYX+ +oakJ5sarPkP8r3oDkdqmOaZh7phPGKjTs69mgumfvN1y+QYEvRLZGCTnq5NTi1kC +AwEAAaOCASYwggEiMBIGA1UdEwEB/wQIMAYBAf8CAQAwJwYDVR0lBCAwHgYIKwYB +BQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDBDARBgNVHSAECjAIMAYGBFUdIAAwMwYI +KwYBBQUHAQEEJzAlMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5lbnRydXN0Lm5l +dDAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmVudHJ1c3QubmV0L3NlcnZl +cjEuY3JsMB0GA1UdDgQWBBT+3JRJDG/vXH/G8RKZTxZJrfuCZTALBgNVHQ8EBAMC +AQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0BowGQYJKoZIhvZ9B0EA +BAwwChsEVjcuMQMCAIEwDQYJKoZIhvcNAQEFBQADgYEAY3RqN6k/lpxmyFisCcnv +9WWUf6MCxDgxvV0jh+zUVrLJsm7kBQb87PX6iHBZ1O7m3bV6oKNgLwIMq94SXa/w +NUuqikeRGvWFLELHHe+VQ7NeuJWTpdrFKKqtci0xrZlrbP+MISevrZqRK8fdWMNu +B8WfedLHjFW/TMcnXlEWKz4="); + byte[] leafBytes = Convert.FromBase64String(@" +MIID3zCCA0igAwIBAgIRAK91OcqDBdcxtsg6T03CzCQwDQYJKoZIhvcNAQEFBQAw +aDELMAkGA1UEBhMCTkwxEjAQBgNVBAoTCURpZ2lOb3RhcjEjMCEGA1UEAxMaRGln +aU5vdGFyIFNlcnZpY2VzIDEwMjQgQ0ExIDAeBgkqhkiG9w0BCQEWEWluZm9AZGln +aW5vdGFyLm5sMB4XDTA5MDQyNDExMTUyNVoXDTEzMDQyMzExMTUyNVowgckxCzAJ +BgNVBAYTAk5MMSwwKgYDVQQKEyNDdXJyZW5jZSBTZXJ2aWNlcyBCLlYuICgwMDMw +MTkzNjE0KTEuMCwGA1UEBxMlQW1zdGVyZGFtIEJlZXRob3ZlbnN0cmFhdCAzMDAg +ICgwMDAwKTEoMCYGA1UECxMfU1NMIFNlcnZlcmNlcnRpZmljYWF0IC0gWmllIENQ +UzEaMBgGA1UEBRMRUlAwNzAwMDEwMDIyOTkxNjExFjAUBgNVBAMTDSouY3VycmVu +Y2UubmwwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAK7b2TiO+0EuQnHlFl8Z +h2R6yEUIhvnpjQOHLnvN+7QicZ2Qe44sMk1hWdxvILwtdBBRN1jBkQh2zcB17fqm +bbGEb6E/i1sN1w1cFs3M1PJ+zTdgRACZ9yUl2Yh3C0PQqgI6tDmONvb1hqAdKgU4 +dlFwUK1cz/YAzgg3HkEi2eB3AgMBAAGjggElMIIBITAfBgNVHSMEGDAWgBT+3JRJ +DG/vXH/G8RKZTxZJrfuCZTAJBgNVHRMEAjAAMIHDBgNVHSAEgbswgbgwgbUGC2CE +EAGHaQEBAQoBMIGlMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2lub3Rhci5u +bC9jcHMwegYIKwYBBQUHAgIwbhpsQ29uZGl0aW9ucywgYXMgbWVudGlvbmVkIG9u +IG91ciB3ZWJzaXRlICh3d3cuZGlnaW5vdGFyLm5sKSwgYXJlIGFwcGxpY2FibGUg +dG8gYWxsIG91ciBwcm9kdWN0cyBhbmQgc2VydmljZXMuMA4GA1UdDwEB/wQEAwIE +sDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDQYJKoZIhvcNAQEFBQAD +gYEAGZH8mFA+TMlGMqXifNKs713LQ8bWv4j7bNNBsySUROa0+uhhKtGhh8089Cnn +lWOt5PxA7mHNbkGVwPbvPwg32LedZ6nRgpjHE8BJe57z2YmoawxLhxtzLyhOzfe8 +yY1kePIfwE+GFWvagZ2ehANB/6LgBTT8jFhR95Tw2oE3N0I="); + + using (X509Certificate2 intermediateCert = new X509Certificate2(intermediateBytes)) + using (X509Certificate2 cert = new X509Certificate2(leafBytes)) + using (ChainHolder chainHolder = new ChainHolder()) + { + X509Chain chain = chainHolder.Chain; + chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + chain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2); + chain.ChainPolicy.ExtraStore.Add(intermediateCert); + Assert.False(chain.Build(cert)); + + X509ChainElement certElement = chain.ChainElements + .OfType() + .Single(e => e.Certificate.Subject == intermediateCert.Subject); + + const X509ChainStatusFlags ExpectedFlag = X509ChainStatusFlags.ExplicitDistrust; + X509ChainStatusFlags actualFlags = certElement.AllStatusFlags(); + Assert.True((actualFlags & ExpectedFlag) == ExpectedFlag, $"Has expected flag {ExpectedFlag} but was {actualFlags}"); + } + } + + [Fact] + public static void BuildChainForCertificateWithMD5Signature() + { + byte[] issuerCert = Convert.FromBase64String(@" +MIIDgzCCAmsCFGTFpNWP/ick4s4VCF1MafVWpWr+MA0GCSqGSIb3DQEBCwUAMH0x +CzAJBgNVBAYTAlVTMR0wGwYDVQQIDBREaXN0cmljdCBvZiBDb2x1bWJpYTETMBEG +A1UEBwwKV2FzaGluZ3RvbjEQMA4GA1UECgwHVGVzdCBDQTEUMBIGA1UECwwLRGV2 +ZWxvcG1lbnQxEjAQBgNVBAMMCVRlc3QgUm9vdDAgFw0yMDA0MjgwMDQwNDZaGA8y +MTIwMDQwNDAwNDA0NlowfTELMAkGA1UEBhMCVVMxHTAbBgNVBAgMFERpc3RyaWN0 +IG9mIENvbHVtYmlhMRMwEQYDVQQHDApXYXNoaW5ndG9uMRAwDgYDVQQKDAdUZXN0 +IENBMRQwEgYDVQQLDAtEZXZlbG9wbWVudDESMBAGA1UEAwwJVGVzdCBSb290MIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsUBPPdECxj8DWbmjkhtnjxjd +LZluHyRpb0+favXLuXHeFtTy/92wuHUSHTr45TGKDxI0qevMLaNqEiy9yBkjNPTz +ctjZTHwbOhxuGEz3Mv2n3IJ7XoIPcn2ZQbhEcTDI/FeF06B+OQKNLigYMHR+L/qd +KlNBpaUaGG0FNpZ0zGJl1n+CizECWOh3PYaVLKmIS9RjEmNmOMqP737u8W6d3sRZ +vb6etsNKRmwRjpWUdk4/LzjSJSiNbIQv5c/cGSv6sXFKDixXxIugwreQ/F/JwJ3/ +x2xTIJt0nHSKbK8zVKIGkSmZ3+bdeve889Mjwu0kN7EW+labAuf8VwzQ0c9qUQID +AQABMA0GCSqGSIb3DQEBCwUAA4IBAQAjGr0pZOxiCa+52S94WvR0WQVNMje3ZL+m +f4/FyaaDUCqrNv8Tt4m3vYtr8bkT+0uC4rcYx5/9iwLzI6oK1+JddoprAQ+17ZPw +Cg8ISgn8PuBzvaOQJxpc1nvWvvQpOiYxpsZPWABdE4xl3YAdcuu43x1mtFphn7Aw +KFTcvxF03RVZPSuZ0k6l1WBRNZFJFoTo2XlhUiLXN4vjxIEDXTCyi/kOzlYu98kZ +pzDlSoMBAu6CHSBygS51IaimM48qtdQjxZIYVZhFL9QaBa2zQ+qsEF0gz+mG0an9 +0BMCvSA9GZA0VBrQJjQLQLjv0rpZkw0i9FypOicu2Zv9d5UF+IXZ"); + + byte[] md5SignedLeafCert = Convert.FromBase64String(@" +MIIEezCCA2OgAwIBAgIUf1ubwalzwcn4DQ2X5hUbYPqateowDQYJKoZIhvcNAQEE +BQAwfTELMAkGA1UEBhMCVVMxHTAbBgNVBAgMFERpc3RyaWN0IG9mIENvbHVtYmlh +MRMwEQYDVQQHDApXYXNoaW5ndG9uMRAwDgYDVQQKDAdUZXN0IENBMRQwEgYDVQQL +DAtEZXZlbG9wbWVudDESMBAGA1UEAwwJVGVzdCBSb290MCAXDTIwMDQyODAwNDI1 +OFoYDzIxMTYwMjI1MDA0MjU4WjBoMQswCQYDVQQGEwJVUzEdMBsGA1UECAwURGlz +dHJpY3Qgb2YgQ29sdW1iaWExEDAOBgNVBAoMB1Rlc3QgQ0ExFDASBgNVBAsMC0Rl +dmVsb3BtZW50MRIwEAYDVQQDDAlUZXN0IExlYWYwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDGHz60IeCSpN1qQbdLHO2VSlQbOn2fBV5qGK/82+a4xiZf +xO0wZ6p9Tb7/rOnF7P7YlaOrY9zc6O5vPxatcv2FcZxwrR8zDnslWUg39WzFnz4M +8eiiGBpxlbUfcUq8FvqfGQ6MxMAwA0kgUjegaVXN1Zgq+J+HcLSJm8EADNOD46nS +TkTVXvEMCBmrl17LyYEnxLogUgWve9QMNz0+XpJq90MlygPmxuvUnWduDGnVgrJq +blkwFqaLIh94vmc8rQJ9WSy+1FRknDoDcy3KveYW3ii9uD9B7YvXdmFVEjGXPcUv +9aFoRiqq/E8oYUhWJXTr9omyA3iJawcn0Kkl3IT7AgMBAAGjggEEMIIBADAJBgNV +HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp +Y2F0ZTAdBgNVHQ4EFgQUE9CCY2wzRzuH3lvEENkvBxDRFx8wgaUGA1UdIwSBnTCB +mqGBgaR/MH0xCzAJBgNVBAYTAlVTMR0wGwYDVQQIDBREaXN0cmljdCBvZiBDb2x1 +bWJpYTETMBEGA1UEBwwKV2FzaGluZ3RvbjEQMA4GA1UECgwHVGVzdCBDQTEUMBIG +A1UECwwLRGV2ZWxvcG1lbnQxEjAQBgNVBAMMCVRlc3QgUm9vdIIUZMWk1Y/+JyTi +zhUIXUxp9Valav4wDQYJKoZIhvcNAQEEBQADggEBAGbrB50Gf9FQ1lTbtKQBlrpF +M01/mHvqDioqjP6hcvDRMvxWcnX8kIq7Idb2uv1fByBPQdBTH2yzGc1adCXtBqrb +ueIjvYVDoXZMqRa7vZjaMA+8szK9lgm2dzSfa3xFKCIT7Twfq6FKGJ7o4TRbopmr +3MsjTMLjfGUnKdxtcYb/FGxB4NRdIyCaaRgtYOIFkOGgA3UTEAJuOAqwY8RdQywR +lHBlkA0wrbydD3FzxYHUJgx0HGO6CcyAzXJLhZVbuBW4expq4Qhi0jDV4d8Otskv +LjCvFGJ+RiZCbxIZfUZEuJ5vAH5WOa2S0tYoEAeyfzuLMIqY9xK74nlZ/vzz1cY="); + + using (X509Certificate2 issuer = new X509Certificate2(issuerCert)) + using (X509Certificate2 cert = new X509Certificate2(md5SignedLeafCert)) + using (ChainHolder chainHolder = new ChainHolder()) + { + X509Chain chain = chainHolder.Chain; + chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + chain.ChainPolicy.VerificationTime = cert.NotBefore.AddHours(2); + chain.ChainPolicy.ExtraStore.Add(issuer); + + // Should not throw, don't care about the validity of the chain. + chain.Build(cert); + } + } + internal static X509ChainStatusFlags AllStatusFlags(this X509Chain chain) { return chain.ChainStatus.Aggregate( diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/DynamicChainTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/DynamicChainTests.cs index d6acb4c035691f..0c494a17038be0 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/DynamicChainTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/DynamicChainTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Linq; using System.Runtime.InteropServices; using Test.Cryptography; using Xunit; @@ -201,6 +202,122 @@ void CheckChain() } } + [Fact] + public static void BasicConstraints_ExceedMaximumPathLength() + { + X509Extension[] rootExtensions = new [] { + new X509BasicConstraintsExtension( + certificateAuthority: true, + hasPathLengthConstraint: true, + pathLengthConstraint: 0, + critical: true) + }; + + X509Extension[] intermediateExtensions = new [] { + new X509BasicConstraintsExtension( + certificateAuthority: true, + hasPathLengthConstraint: true, + pathLengthConstraint: 0, + critical: true) + }; + + TestDataGenerator.MakeTestChain4( + out X509Certificate2 endEntityCert, + out X509Certificate2 intermediateCert1, + out X509Certificate2 intermediateCert2, + out X509Certificate2 rootCert, + rootExtensions: rootExtensions, + intermediateExtensions: intermediateExtensions); + + using (endEntityCert) + using (intermediateCert1) + using (intermediateCert2) + using (rootCert) + using (ChainHolder chainHolder = new ChainHolder()) + { + X509Chain chain = chainHolder.Chain; + chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + chain.ChainPolicy.VerificationTime = endEntityCert.NotBefore.AddSeconds(1); + chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; + chain.ChainPolicy.CustomTrustStore.Add(rootCert); + chain.ChainPolicy.ExtraStore.Add(intermediateCert1); + chain.ChainPolicy.ExtraStore.Add(intermediateCert2); + + Assert.False(chain.Build(endEntityCert)); + Assert.Equal(X509ChainStatusFlags.InvalidBasicConstraints, chain.AllStatusFlags()); + } + } + + [Fact] + public static void BasicConstraints_ViolatesCaFalse() + { + X509Extension[] intermediateExtensions = new [] { + new X509BasicConstraintsExtension( + certificateAuthority: false, + hasPathLengthConstraint: false, + pathLengthConstraint: 0, + critical: true) + }; + + TestDataGenerator.MakeTestChain3( + out X509Certificate2 endEntityCert, + out X509Certificate2 intermediateCert, + out X509Certificate2 rootCert, + intermediateExtensions: intermediateExtensions); + + using (endEntityCert) + using (intermediateCert) + using (rootCert) + using (ChainHolder chainHolder = new ChainHolder()) + { + X509Chain chain = chainHolder.Chain; + chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + chain.ChainPolicy.VerificationTime = endEntityCert.NotBefore.AddSeconds(1); + chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; + chain.ChainPolicy.CustomTrustStore.Add(rootCert); + chain.ChainPolicy.ExtraStore.Add(intermediateCert); + + Assert.False(chain.Build(endEntityCert)); + Assert.Equal(X509ChainStatusFlags.InvalidBasicConstraints, chain.AllStatusFlags()); + } + } + + [Fact] + public static void TestLeafCertificateWithUnknownCriticalExtension() + { + using (RSA key = RSA.Create()) + { + CertificateRequest certReq = new CertificateRequest( + new X500DistinguishedName("CN=Cert"), + key, + HashAlgorithmName.SHA256, + RSASignaturePadding.Pkcs1); + + const string PrecertificatePoisonExtensionOid = "1.3.6.1.4.1.11129.2.4.3"; + certReq.CertificateExtensions.Add(new X509Extension( + new AsnEncodedData( + new Oid(PrecertificatePoisonExtensionOid), + new byte[] { 5, 0 }), + critical: true)); + + DateTimeOffset notBefore = DateTimeOffset.UtcNow.AddDays(-1); + DateTimeOffset notAfter = notBefore.AddDays(30); + + using (X509Certificate2 cert = certReq.CreateSelfSigned(notBefore, notAfter)) + using (ChainHolder holder = new ChainHolder()) + { + X509Chain chain = holder.Chain; + chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + Assert.False(chain.Build(cert)); + + X509ChainElement certElement = chain.ChainElements.OfType().Single(); + const X509ChainStatusFlags ExpectedFlag = X509ChainStatusFlags.HasNotSupportedCriticalExtension; + X509ChainStatusFlags actualFlags = certElement.AllStatusFlags(); + Assert.True((actualFlags & ExpectedFlag) == ExpectedFlag, $"Has expected flag {ExpectedFlag} but was {actualFlags}"); + } + } + } + [Fact] public static void TestInvalidAia() { diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/ExportTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/ExportTests.cs index c473d80895fa8a..30a1b19bb6893b 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/ExportTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/ExportTests.cs @@ -157,5 +157,131 @@ public static void ExportAsPfxWithPrivateKey() } } } + + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + [OuterLoop("Modifies user-persisted state")] + public static void ExportDoesNotCorruptPrivateKeyMethods() + { + string keyName = $"clrtest.{Guid.NewGuid():D}"; + X509Store cuMy = new X509Store(StoreName.My, StoreLocation.CurrentUser); + cuMy.Open(OpenFlags.ReadWrite); + X509Certificate2 createdCert = null; + X509Certificate2 foundCert = null; + X509Certificate2 foundCert2 = null; + + try + { + string commonName = nameof(ExportDoesNotCorruptPrivateKeyMethods); + string subject = $"CN={commonName},OU=.NET"; + + using (ImportedCollection toClean = new ImportedCollection(cuMy.Certificates)) + { + X509Certificate2Collection coll = toClean.Collection; + + using (ImportedCollection matches = + new ImportedCollection(coll.Find(X509FindType.FindBySubjectName, commonName, false))) + { + foreach (X509Certificate2 cert in matches.Collection) + { + cuMy.Remove(cert); + } + } + } + + foreach (X509Certificate2 cert in cuMy.Certificates) + { + if (subject.Equals(cert.Subject)) + { + cuMy.Remove(cert); + } + + cert.Dispose(); + } + + CngKeyCreationParameters options = new CngKeyCreationParameters + { + ExportPolicy = CngExportPolicies.AllowExport | CngExportPolicies.AllowPlaintextExport, + }; + + using (CngKey key = CngKey.Create(CngAlgorithm.Rsa, keyName, options)) + using (RSACng rsaCng = new RSACng(key)) + { + CertificateRequest certReq = new CertificateRequest( + subject, + rsaCng, + HashAlgorithmName.SHA256, + RSASignaturePadding.Pkcs1); + + DateTimeOffset now = DateTimeOffset.UtcNow.AddMinutes(-5); + createdCert = certReq.CreateSelfSigned(now, now.AddDays(1)); + } + + cuMy.Add(createdCert); + + using (ImportedCollection toClean = new ImportedCollection(cuMy.Certificates)) + { + X509Certificate2Collection matches = toClean.Collection.Find( + X509FindType.FindBySubjectName, + commonName, + validOnly: false); + + Assert.Equal(1, matches.Count); + foundCert = matches[0]; + } + + Assert.False(HasEphemeralKey(foundCert)); + foundCert.Export(X509ContentType.Pfx, ""); + Assert.False(HasEphemeralKey(foundCert)); + + using (ImportedCollection toClean = new ImportedCollection(cuMy.Certificates)) + { + X509Certificate2Collection matches = toClean.Collection.Find( + X509FindType.FindBySubjectName, + commonName, + validOnly: false); + + Assert.Equal(1, matches.Count); + foundCert2 = matches[0]; + } + + Assert.False(HasEphemeralKey(foundCert2)); + } + finally + { + if (createdCert != null) + { + cuMy.Remove(createdCert); + createdCert.Dispose(); + } + + cuMy.Dispose(); + + foundCert?.Dispose(); + foundCert2?.Dispose(); + + try + { + CngKey key = CngKey.Open(keyName); + key.Delete(); + key.Dispose(); + } + catch (Exception) + { + } + } + + bool HasEphemeralKey(X509Certificate2 c) + { + using (RSA key = c.GetRSAPrivateKey()) + { + // This code is not defensive against the type changing, because it + // is in the source tree with the code that produces the value. + // Don't blind-cast like this in library or application code. + RSACng rsaCng = (RSACng)key; + return rsaCng.Key.IsEphemeral; + } + } + } } } diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/System.Security.Cryptography.X509Certificates.Tests.csproj b/src/libraries/System.Security.Cryptography.X509Certificates/tests/System.Security.Cryptography.X509Certificates.Tests.csproj index 3f129ff6efe9a7..8b6a83aeef8880 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/System.Security.Cryptography.X509Certificates.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/System.Security.Cryptography.X509Certificates.Tests.csproj @@ -8,12 +8,10 @@ - - Common\System\Memory\PointerMemoryManager.cs - - - Common\System\Security\Cryptography\CryptoPool.cs - + + @@ -40,9 +38,8 @@ - - CommonTest\System\Security\Cryptography\ByteUtils.cs - + @@ -65,73 +62,52 @@ - - Common\Interop\Unix\Interop.Libraries.cs - - - Common\Interop\Unix\Interop.Errors.cs - - - Common\Interop\Unix\Interop.GetEUid.cs - - - Common\Interop\Unix\Interop.GetPwUid.cs - - - Common\Interop\Unix\System.Native\Interop.FChMod.cs - - - Common\Interop\Unix\System.Native\Interop.Permissions.cs - - - Common\Interop\Unix\System.Native\Interop.Stat.cs - - - Common\System\IO\PersistedFiles.Unix.cs - - - Common\System\IO\PersistedFiles.Names.Unix.cs - + + + + + + + + + - - Common\Interop\OSX\Interop.CoreFoundation.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFArray.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFData.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFError.cs - - - Common\Interop\OSX\Interop.CoreFoundation.CFString.cs - - - Common\Interop\OSX\Interop.Libraries.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Err.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.SecErr.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.SecErrMessage.cs - - - Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Keychain.cs - - - Common\Microsoft\Win32\SafeHandles\SafeCreateHandle.OSX.cs - - - Common\Microsoft\Win32\SafeHandles\SafeHandleCache.cs - + + + + + + + + + + + + diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/TestDataGenerator.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/TestDataGenerator.cs index 40412515dc7bc7..4e972ae3ea5b8f 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/TestDataGenerator.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/TestDataGenerator.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; + namespace System.Security.Cryptography.X509Certificates.Tests { internal static class TestDataGenerator @@ -9,7 +11,10 @@ internal static class TestDataGenerator internal static void MakeTestChain3( out X509Certificate2 endEntityCert, out X509Certificate2 intermediateCert, - out X509Certificate2 rootCert) + out X509Certificate2 rootCert, + IEnumerable endEntityExtensions = null, + IEnumerable intermediateExtensions = null, + IEnumerable rootExtensions = null) { using (RSA rootKey = RSA.Create()) using (RSA intermediateKey = RSA.Create()) @@ -23,7 +28,12 @@ internal static void MakeTestChain3( }; Span certs = new X509Certificate2[keys.Length]; - MakeTestChain(keys, certs); + MakeTestChain( + keys, + certs, + endEntityExtensions, + intermediateExtensions, + rootExtensions); endEntityCert = certs[0]; intermediateCert = certs[1]; @@ -31,33 +41,81 @@ internal static void MakeTestChain3( } } + + internal static void MakeTestChain4( + out X509Certificate2 endEntityCert, + out X509Certificate2 intermediateCert1, + out X509Certificate2 intermediateCert2, + out X509Certificate2 rootCert, + IEnumerable endEntityExtensions = null, + IEnumerable intermediateExtensions = null, + IEnumerable rootExtensions = null) + { + using (RSA rootKey = RSA.Create()) + using (RSA intermediateKey = RSA.Create()) + using (RSA endEntityKey = RSA.Create()) + { + ReadOnlySpan keys = new[] + { + rootKey, + intermediateKey, + intermediateKey, + endEntityKey, + }; + + Span certs = new X509Certificate2[keys.Length]; + MakeTestChain( + keys, + certs, + endEntityExtensions, + intermediateExtensions, + rootExtensions); + + endEntityCert = certs[0]; + intermediateCert1 = certs[1]; + intermediateCert2 = certs[2]; + rootCert = certs[3]; + } + } + internal static void MakeTestChain( ReadOnlySpan keys, Span certs, - string eeName = "CN=End-Entity", - OidCollection eeEku = null) + IEnumerable endEntityExtensions, + IEnumerable intermediateExtensions, + IEnumerable rootExtensions) { if (keys.Length < 2) throw new ArgumentException(nameof(keys)); if (keys.Length != certs.Length) throw new ArgumentException(nameof(certs)); - if (string.IsNullOrEmpty(eeName)) - throw new ArgumentOutOfRangeException(nameof(eeName)); - - var caUnlimited = new X509BasicConstraintsExtension(true, false, 0, true); - var eeConstraint = new X509BasicConstraintsExtension(false, false, 0, true); - var caUsage = new X509KeyUsageExtension( - X509KeyUsageFlags.CrlSign | - X509KeyUsageFlags.KeyCertSign | - X509KeyUsageFlags.DigitalSignature, - false); - - var eeUsage = new X509KeyUsageExtension( + rootExtensions ??= new X509Extension[] { + new X509BasicConstraintsExtension(true, false, 0, true), + new X509KeyUsageExtension( + X509KeyUsageFlags.CrlSign | + X509KeyUsageFlags.KeyCertSign | + X509KeyUsageFlags.DigitalSignature, + false) + }; + + intermediateExtensions ??= new X509Extension[] { + new X509BasicConstraintsExtension(true, false, 0, true), + new X509KeyUsageExtension( + X509KeyUsageFlags.CrlSign | + X509KeyUsageFlags.KeyCertSign | + X509KeyUsageFlags.DigitalSignature, + false) + }; + + endEntityExtensions ??= new X509Extension[] { + new X509BasicConstraintsExtension(false, false, 0, true), + new X509KeyUsageExtension( X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation | X509KeyUsageFlags.KeyEncipherment, - false); + false) + }; TimeSpan notBeforeInterval = TimeSpan.FromDays(30); TimeSpan notAfterInterval = TimeSpan.FromDays(90); @@ -76,14 +134,20 @@ internal static void MakeTestChain( hashAlgorithm, signaturePadding); - rootReq.CertificateExtensions.Add(caUnlimited); - rootReq.CertificateExtensions.Add(caUsage); + foreach (X509Extension extension in rootExtensions) + { + rootReq.CertificateExtensions.Add(extension); + } + + X509SignatureGenerator lastGenerator = X509SignatureGenerator.CreateForRSA(keys[rootIndex], RSASignaturePadding.Pkcs1); + X500DistinguishedName lastSubject = rootReq.SubjectName; - X509Certificate2 lastWithKey = rootReq.CreateSelfSigned( + certs[rootIndex] = rootReq.Create( + lastSubject, + lastGenerator, eeStart - (notBeforeInterval * rootIndex), - eeEnd + (notAfterInterval * rootIndex)); - - certs[rootIndex] = new X509Certificate2(lastWithKey.RawData); + eeEnd + (notAfterInterval * rootIndex), + CreateSerial()); int presentationNumber = 0; @@ -97,41 +161,41 @@ internal static void MakeTestChain( hashAlgorithm, signaturePadding); - intermediateReq.CertificateExtensions.Add(caUnlimited); - intermediateReq.CertificateExtensions.Add(caUsage); - - // Leave serialBuf[0] as 0 to avoid a realloc in the signer - RandomNumberGenerator.Fill(serialBuf.AsSpan(1)); + foreach (X509Extension extension in intermediateExtensions) + { + intermediateReq.CertificateExtensions.Add(extension); + } certs[i] = intermediateReq.Create( - lastWithKey, + lastSubject, + lastGenerator, eeStart - (notBeforeInterval * i), eeEnd + (notAfterInterval * i), - serialBuf); + CreateSerial()); - lastWithKey.Dispose(); - lastWithKey = certs[i].CopyWithPrivateKey(keys[i]); + lastSubject = intermediateReq.SubjectName; + lastGenerator = X509SignatureGenerator.CreateForRSA(keys[i], RSASignaturePadding.Pkcs1); } CertificateRequest eeReq = new CertificateRequest( - eeName, + "CN=End-Entity", keys[0], hashAlgorithm, signaturePadding); - eeReq.CertificateExtensions.Add(eeConstraint); - eeReq.CertificateExtensions.Add(eeUsage); - - if (eeEku != null) + foreach (X509Extension extension in endEntityExtensions) { - eeReq.CertificateExtensions.Add(new X509EnhancedKeyUsageExtension(eeEku, false)); + eeReq.CertificateExtensions.Add(extension); } - // Leave serialBuf[0] as 0 to avoid a realloc in the signer - RandomNumberGenerator.Fill(serialBuf.AsSpan(1)); + certs[0] = eeReq.Create(lastSubject, lastGenerator, eeStart, eeEnd, CreateSerial()); + } - certs[0] = eeReq.Create(lastWithKey, eeStart, eeEnd, serialBuf); - lastWithKey.Dispose(); + private static byte[] CreateSerial() + { + byte[] bytes = new byte[8]; + RandomNumberGenerator.Fill(bytes); + return bytes; } } } diff --git a/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.csproj b/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.csproj index 2a87099dbfa12a..43030e53132c4f 100644 --- a/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.csproj +++ b/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.csproj @@ -1,9 +1,12 @@ - true netstandard2.0;net461;$(NetFrameworkCurrent) true + + + true + diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System.Security.Cryptography.Xml.csproj b/src/libraries/System.Security.Cryptography.Xml/src/System.Security.Cryptography.Xml.csproj index 44784da1fb405c..03fb204f490640 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System.Security.Cryptography.Xml.csproj +++ b/src/libraries/System.Security.Cryptography.Xml/src/System.Security.Cryptography.Xml.csproj @@ -1,11 +1,14 @@ true - true $(NoWarn);CA5384;CA5385 netstandard2.0;net461;$(NetFrameworkCurrent) true + + + true + @@ -83,9 +86,8 @@ - - Common\System\HexConverter.cs - + @@ -115,4 +117,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Security.Cryptography.Xml/tests/System.Security.Cryptography.Xml.Tests.csproj b/src/libraries/System.Security.Cryptography.Xml/tests/System.Security.Cryptography.Xml.Tests.csproj index 3b30fcd3f1a5ea..3cee8fe74f360e 100644 --- a/src/libraries/System.Security.Cryptography.Xml/tests/System.Security.Cryptography.Xml.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Xml/tests/System.Security.Cryptography.Xml.Tests.csproj @@ -1,11 +1,7 @@ - Library $(NetCoreAppCurrent);$(NetFrameworkCurrent) - - System.Security.Cryptography.Xml.Tests - @@ -53,7 +49,7 @@ - + diff --git a/src/libraries/System.Security.Permissions/ref/System.Security.Permissions.csproj b/src/libraries/System.Security.Permissions/ref/System.Security.Permissions.csproj index 75637a5dd7cca0..7d70b43e941c5a 100644 --- a/src/libraries/System.Security.Permissions/ref/System.Security.Permissions.csproj +++ b/src/libraries/System.Security.Permissions/ref/System.Security.Permissions.csproj @@ -1,18 +1,21 @@ - true $(NetCoreAppCurrent);netstandard2.0;net461;netcoreapp3.0;$(NetFrameworkCurrent) true true + + + true + - + - + @@ -26,7 +29,7 @@ - + @@ -56,7 +59,7 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Security.Permissions/src/System.Security.Permissions.csproj b/src/libraries/System.Security.Permissions/src/System.Security.Permissions.csproj index 4a7ef1ddb9bc40..174f60d9b0688f 100644 --- a/src/libraries/System.Security.Permissions/src/System.Security.Permissions.csproj +++ b/src/libraries/System.Security.Permissions/src/System.Security.Permissions.csproj @@ -1,11 +1,11 @@ true - netcoreapp3.0;netstandard2.0;net461;$(NetCoreAppCurrent);$(NetFrameworkCurrent) + $(NetCoreAppCurrent);netcoreapp3.0;netstandard2.0;net461;$(NetFrameworkCurrent) true true - + @@ -178,24 +178,21 @@ - + - - - System\Security\IStackWalk.cs - - - System\Security\PermissionSet.cs - - - System\Security\Permissions\PermissionState.cs - + + + + - + @@ -211,7 +208,7 @@ - + diff --git a/src/libraries/System.Security.Principal.Windows/ref/System.Security.Principal.Windows.csproj b/src/libraries/System.Security.Principal.Windows/ref/System.Security.Principal.Windows.csproj index 4831140cad5db3..a469aff9a6178c 100644 --- a/src/libraries/System.Security.Principal.Windows/ref/System.Security.Principal.Windows.csproj +++ b/src/libraries/System.Security.Principal.Windows/ref/System.Security.Principal.Windows.csproj @@ -1,15 +1,18 @@ - true $(NetCoreAppCurrent);netstandard2.0;netcoreapp3.0;net461;$(NetFrameworkCurrent) true true enable + + + true + - + diff --git a/src/libraries/System.Security.Principal.Windows/src/ILLinkTrim.xml b/src/libraries/System.Security.Principal.Windows/src/ILLinkTrim_LibraryBuild.xml similarity index 100% rename from src/libraries/System.Security.Principal.Windows/src/ILLinkTrim.xml rename to src/libraries/System.Security.Principal.Windows/src/ILLinkTrim_LibraryBuild.xml diff --git a/src/libraries/System.Security.Principal.Windows/src/System.Security.Principal.Windows.csproj b/src/libraries/System.Security.Principal.Windows/src/System.Security.Principal.Windows.csproj index 17bbfa7f04173d..d4f8f3eac3d17a 100644 --- a/src/libraries/System.Security.Principal.Windows/src/System.Security.Principal.Windows.csproj +++ b/src/libraries/System.Security.Principal.Windows/src/System.Security.Principal.Windows.csproj @@ -1,14 +1,16 @@ - System.Security.Principal.Windows true - true - true $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix;netstandard2.0;netcoreapp2.0-Windows_NT;netcoreapp2.0-Unix;netcoreapp2.1-Windows_NT;netcoreapp2.1-Unix;net461-Windows_NT;$(NetFrameworkCurrent)-Windows_NT true true enable + + + true + true + @@ -17,7 +19,7 @@ annotations - + @@ -28,166 +30,115 @@ - - Common\Interop\Interop.Libraries.cs - - - Common\Interop\Windows\Advapi32\Interop.UNICODE_STRING.cs - - - Common\Interop\Windows\Advapi32\Interop.OBJECT_ATTRIBUTES.cs - - - Common\Interop\Interop.TOKENS.cs - - - Common\Interop\Interop.WinError.cs - - - Common\Interop\Interop.Winnt.cs - - - Common\Interop\Interop.NtStatus.cs - - - Common\Interop\Interop.LSAStructs.cs - - - Common\Interop\Interop.SECURITY_LOGON_SESSION_DATA.cs - - - Common\Interop\Interop.GetCurrentProcess.cs - - - Common\Interop\Interop.GetCurrentThread.cs - - - Common\Interop\Interop.ClaimSecurityAttributes.cs - - - Common\Interop\Interop.OpenProcessToken.cs - - - Common\Interop\Interop.GetTokenInformation.cs - - - Common\Interop\Interop.DuplicateTokenEx.cs - - - Common\Interop\Interop.DuplicateHandle.cs - - - Common\Interop\Interop.CloseHandle.cs - - - Common\Interop\Interop.LsaGetLogonSessionData.cs - - - Common\Interop\Interop.LsaFreeReturnBuffer.cs - - - Common\Interop\Interop.LsaLookupNames2.cs - - - Common\Interop\Interop.LsaLookupSids.cs - - - Common\Interop\Interop.LsaClose.cs - - - Common\Interop\Interop.LsaFreeMemory.cs - - - Common\Interop\Interop.LsaOpenPolicy.cs - - - Common\Interop\Interop.ConvertStringSidToSid.cs - - - Common\Interop\Interop.CreateWellKnownSid.cs - - - Common\Interop\Interop.GetWindowsAccountDomainSid.cs - - - Common\Interop\Interop.IsWellKnownSid.cs - - - Common\Interop\Interop.IsEqualDomainSid.cs - - - Common\Interop\Interop.OpenThreadToken.cs - - - Common\Interop\Interop.RevertToSelf.cs - - - Common\Interop\Interop.ImpersonateLoggedOnUser.cs - - - Common\Interop\Interop.LsaNtStatusToWinError.cs - - - Common\Interop\Windows\Advapi32\Interop.LSA_STRING.cs - - - Common\Interop\Windows\SspiCli\Interop.AuthenticationPackageNames.cs - - - Common\Interop\Windows\SspiCli\Interop.KerbLogonSubmitType.cs - - - Common\Interop\Windows\SspiCli\Interop.KerbS4uLogin.cs - - - Common\Interop\Windows\SspiCli\Interop.LsaConnectUntrusted.cs - - - Common\Interop\Windows\SspiCli\Interop.LsaDeregisterLogonProcess.cs - - - Common\Interop\Windows\SspiCli\Interop.LsaLogonUser.cs - - - Common\Interop\Windows\SspiCli\Interop.LsaLookupAuthenticationPackage.cs - - - Common\Interop\Windows\SspiCli\Interop.QuotaLimits.cs - - - Common\Interop\Windows\SspiCli\Interop.SecurityLogonType.cs - - - Common\Interop\Windows\SspiCli\Interop.TokenSource.cs - - - Common\Interop\Windows\Advapi32\Interop.AllocateLocallyUniqueId.cs - - - Common\Microsoft\Win32\SafeHandles\SafeLocalAllocHandle.cs - - - Common\Microsoft\Win32\SafeHandles\SafeLsaHandle.cs - - - Common\Microsoft\Win32\SafeHandles\SafeLsaMemoryHandle.cs - - - Common\Microsoft\Win32\SafeHandles\SafeLsaPolicyHandle.cs - - - Common\Microsoft\Win32\SafeHandles\SafeLsaReturnBufferHandle.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - Common\Interop\Interop.CheckTokenMembership.cs - + + - + - + @@ -200,4 +151,4 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Security.Principal.Windows/src/System/Security/Principal/SID.cs b/src/libraries/System.Security.Principal.Windows/src/System/Security/Principal/SID.cs index 81da0b439bb038..19782152c0169d 100644 --- a/src/libraries/System.Security.Principal.Windows/src/System/Security/Principal/SID.cs +++ b/src/libraries/System.Security.Principal.Windows/src/System/Security/Principal/SID.cs @@ -640,7 +640,9 @@ public SecurityIdentifier(WellKnownSidType sidType, SecurityIdentifier? domainSi if (error == Interop.Errors.ERROR_INVALID_PARAMETER) { +#pragma warning disable CA2208 // Instantiate argument exceptions correctly, combination of arguments used throw new ArgumentException(new Win32Exception(error).Message, "sidType/domainSid"); +#pragma warning restore CS2208 } else if (error != Interop.Errors.ERROR_SUCCESS) { diff --git a/src/libraries/System.Security.Principal.Windows/src/System/Security/Principal/WindowsIdentity.cs b/src/libraries/System.Security.Principal.Windows/src/System/Security/Principal/WindowsIdentity.cs index be5c623b29967e..0c4e03d627194d 100644 --- a/src/libraries/System.Security.Principal.Windows/src/System/Security/Principal/WindowsIdentity.cs +++ b/src/libraries/System.Security.Principal.Windows/src/System/Security/Principal/WindowsIdentity.cs @@ -134,11 +134,8 @@ public WindowsIdentity(string sUserPrincipalName) sourceContext.SourceName = new byte[TOKEN_SOURCE.TOKEN_SOURCE_LENGTH]; Buffer.BlockCopy(sourceName, 0, sourceContext.SourceName, 0, sourceName.Length); - // .NET Framework compat: Desktop never null-checks sUserPrincipalName. Actual behavior is that the null makes it down to Encoding.Unicode.GetBytes() which then throws - // the ArgumentNullException (provided that the prior LSA calls didn't fail first.) To make this compat decision explicit, we'll null check ourselves - // and simulate the exception from Encoding.Unicode.GetBytes(). if (sUserPrincipalName == null) - throw new ArgumentNullException("s"); + throw new ArgumentNullException(nameof(sUserPrincipalName)); byte[] upnBytes = Encoding.Unicode.GetBytes(sUserPrincipalName); if (upnBytes.Length > ushort.MaxValue) diff --git a/src/libraries/System.Security.Principal.Windows/tests/System.Security.Principal.Windows.Tests.csproj b/src/libraries/System.Security.Principal.Windows/tests/System.Security.Principal.Windows.Tests.csproj index 1607b7dbbce2bb..8a99afb50bf19c 100644 --- a/src/libraries/System.Security.Principal.Windows/tests/System.Security.Principal.Windows.Tests.csproj +++ b/src/libraries/System.Security.Principal.Windows/tests/System.Security.Principal.Windows.Tests.csproj @@ -7,13 +7,12 @@ - + - - Common\System\Threading\ThreadTestHelpers.cs - + \ No newline at end of file diff --git a/src/libraries/System.ServiceModel.Syndication/ref/System.ServiceModel.Syndication.csproj b/src/libraries/System.ServiceModel.Syndication/ref/System.ServiceModel.Syndication.csproj index 171b91be3e7475..bca4baa304a216 100644 --- a/src/libraries/System.ServiceModel.Syndication/ref/System.ServiceModel.Syndication.csproj +++ b/src/libraries/System.ServiceModel.Syndication/ref/System.ServiceModel.Syndication.csproj @@ -1,14 +1,17 @@ - true $(NetCoreAppCurrent);net461;netcoreapp2.1;netstandard2.0;$(NetFrameworkCurrent) true true + + + true + - + @@ -27,7 +30,7 @@ - + diff --git a/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj b/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj index 64d15f9b613484..bb632167aab074 100644 --- a/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj +++ b/src/libraries/System.ServiceModel.Syndication/src/System.ServiceModel.Syndication.csproj @@ -1,12 +1,15 @@ $(NoWarn);1634;1691;649 - true - true netstandard2.0;net461-Windows_NT;$(NetFrameworkCurrent)-Windows_NT true - + + + true + true + + @@ -50,7 +53,7 @@ - + diff --git a/src/libraries/System.ServiceModel.Syndication/tests/System.ServiceModel.Syndication.Tests.csproj b/src/libraries/System.ServiceModel.Syndication/tests/System.ServiceModel.Syndication.Tests.csproj index b71c0542b31c91..8ff16d90065e7f 100644 --- a/src/libraries/System.ServiceModel.Syndication/tests/System.ServiceModel.Syndication.Tests.csproj +++ b/src/libraries/System.ServiceModel.Syndication/tests/System.ServiceModel.Syndication.Tests.csproj @@ -38,23 +38,23 @@ - - + + - + PreserveNewest - + PreserveNewest - + PreserveNewest diff --git a/src/libraries/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.csproj b/src/libraries/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.csproj index ab91c549ac2967..7b789f38b26114 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.csproj +++ b/src/libraries/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.csproj @@ -1,12 +1,15 @@ - true netstandard2.0;$(NetFrameworkCurrent);net461 + + + true + - + diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj b/src/libraries/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj index 6c47b7598ab68a..7950efff6aae2d 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj +++ b/src/libraries/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj @@ -1,86 +1,65 @@ true - true - true - SR.PlatformNotSupported_ServiceController $(NetCoreAppCurrent)-Windows_NT;netstandard2.0;netstandard2.0-Windows_NT;net461-Windows_NT;$(NetFrameworkCurrent)-Windows_NT true true - - - Common\System\Text\ValueStringBuilder.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.Errors.cs - - - Common\Interop\Windows\Interop.ServiceProcessOptions.cs - - - Common\Interop\Windows\Interop.CloseServiceHandle.cs - - - Common\Interop\Windows\Interop.ControlService.cs - - - Common\Interop\Windows\Interop.EnumDependentServices.cs - - - Common\Interop\Windows\Interop.EnumServicesStatusEx.cs - - - Common\Interop\Windows\Interop.GetServiceDisplayName.cs - - - Common\Interop\Windows\Interop.GetServiceKeyName.cs - - - Common\Interop\Windows\Interop.OpenSCManager.cs - - - Common\Interop\Windows\Interop.OpenService.cs - - - Common\Interop\Windows\Interop.QueryServiceConfig.cs - - - Common\Interop\Windows\Interop.QueryServiceStatus.cs - - - Common\Interop\Windows\Interop.StartService.cs - - - Common\Interop\Windows\Interop.ENUM_SERVICE_STATUS.cs - - - Common\Interop\Windows\Interop.ENUM_SERVICE_STATUS_PROCESS.cs - - - Common\Interop\Windows\Interop.QUERY_SERVICE_CONFIG.cs - - - Common\Interop\Windows\Interop.SERVICE_STATUS.cs - - - Common\Interop\Windows\Interop.SERVICE_TABLE_ENTRY.cs - - - Common\Interop\Windows\Interop.SetServiceStatus.cs - - - Common\Interop\Windows\Interop.WTSSESSION_NOTIFICATION.cs - - - Common\Interop\Windows\Interop.RegisterServiceCtrlHandlerEx.cs - - - Common\Interop\Windows\Interop.StartServiceCtrlDispatcher.cs - + + + true + true + SR.PlatformNotSupported_ServiceController + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -96,11 +75,11 @@ - + - + @@ -117,4 +96,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs b/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs index b472dd970977eb..f000baf317ce67 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs +++ b/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs @@ -81,7 +81,6 @@ public void TestOnStartThenStop() controller.WaitForStatus(ServiceControllerStatus.Stopped); } - [ActiveIssue("https://github.com/dotnet/runtime/issues/34801")] [ConditionalFact(nameof(IsProcessElevated))] public void TestOnStartWithArgsThenStop() { @@ -94,10 +93,9 @@ public void TestOnStartWithArgsThenStop() controller.Start(new string[] { "StartWithArguments", "a", "b", "c" }); _testService.Client = null; _testService.Client.Connect(); + Assert.Equal((int)(PipeMessageByteCode.Connected), _testService.GetByte()); - // There is no definite order between start and connected when tests are running on multiple threads. - // In this case we dont care much about the order, so we are just checking whether the appropiate bytes have been sent. - Assert.Equal((int)(PipeMessageByteCode.Connected | PipeMessageByteCode.Start), _testService.GetByte() | _testService.GetByte()); + Assert.Equal((int)(PipeMessageByteCode.Start), _testService.GetByte()); controller.WaitForStatus(ServiceControllerStatus.Running); controller.Stop(); diff --git a/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/System.ServiceProcess.ServiceController.TestService.csproj b/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/System.ServiceProcess.ServiceController.TestService.csproj index a93989888aa84a..cc521a253c4983 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/System.ServiceProcess.ServiceController.TestService.csproj +++ b/src/libraries/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/System.ServiceProcess.ServiceController.TestService.csproj @@ -11,41 +11,29 @@ Component - - Microsoft\Win32\SafeHandles\SafeServiceHandle.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.ServiceProcessOptions.cs - - - Common\Interop\Windows\Interop.CloseServiceHandle.cs - - - Common\Interop\Windows\Interop.OpenSCManager.cs - - - Common\Interop\Windows\Interop.OpenService.cs - - - Common\Interop\Windows\Interop.CreateService.cs - - - Common\Interop\Windows\Interop.SERVICE_DESCRIPTION.cs - - - Common\Interop\Windows\Interop.ChangeServiceConfig2.cs - - - Common\Interop\Windows\Interop.SERVICE_DELAYED_AUTOSTART_INFO.cs - - - Common\Interop\Windows\Interop.DeleteService.cs - - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - + + + + + + + + + + + + \ No newline at end of file diff --git a/src/libraries/System.Text.Encoding.CodePages/src/System.Text.Encoding.CodePages.csproj b/src/libraries/System.Text.Encoding.CodePages/src/System.Text.Encoding.CodePages.csproj index 54071d3f8948f3..778cc8effa9e53 100644 --- a/src/libraries/System.Text.Encoding.CodePages/src/System.Text.Encoding.CodePages.csproj +++ b/src/libraries/System.Text.Encoding.CodePages/src/System.Text.Encoding.CodePages.csproj @@ -2,11 +2,14 @@ true enable - - netstandard2.0;net461 $(NetCoreAppCurrent)-Windows_NT;netstandard2.0;netcoreapp2.0-Windows_NT;netstandard2.0-Windows_NT true + + + + netstandard2.0;net461 + @@ -31,23 +34,18 @@ - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Interop\Windows\Interop.BOOL.cs - - - Common\Interop\Windows\Interop.GetCPInfoEx.cs - - - Common\Interop\Windows\Interop.MAX_PATH.cs - - - Common\Interop\Windows\Kernel32\Interop.WideCharToMultiByte.cs - + + + + + - + @@ -79,4 +77,4 @@ Data\PreferredCodePageNames.csv System\Text\EncodingTable.Data.cs - \ No newline at end of file + diff --git a/src/libraries/System.Text.Encoding/tests/CustomEncoderReplacementFallback.cs b/src/libraries/System.Text.Encoding/tests/CustomEncoderReplacementFallback.cs new file mode 100644 index 00000000000000..df1b33d5384523 --- /dev/null +++ b/src/libraries/System.Text.Encoding/tests/CustomEncoderReplacementFallback.cs @@ -0,0 +1,59 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Xunit; + +namespace System.Text.Encodings.Tests +{ + // A custom encoder fallback which substitutes unknown chars with "[xxxx]" (the code point as hex) + internal sealed class CustomEncoderReplacementFallback : EncoderFallback + { + public override int MaxCharCount => 8; // = "[10FFFF]".Length + + public override EncoderFallbackBuffer CreateFallbackBuffer() + { + return new CustomEncoderFallbackBuffer(); + } + + private sealed class CustomEncoderFallbackBuffer : EncoderFallbackBuffer + { + private string _remaining = string.Empty; + private int _remainingIdx = 0; + + public override int Remaining => _remaining.Length - _remainingIdx; + + public override bool Fallback(char charUnknownHigh, char charUnknownLow, int index) + => FallbackCommon((uint)char.ConvertToUtf32(charUnknownHigh, charUnknownLow)); + + public override bool Fallback(char charUnknown, int index) + => FallbackCommon(charUnknown); + + private bool FallbackCommon(uint codePoint) + { + Assert.True(codePoint <= 0x10FFFF); + _remaining = FormattableString.Invariant($"[{codePoint:X4}]"); + _remainingIdx = 0; + return true; + } + + public override char GetNextChar() + { + return (_remainingIdx < _remaining.Length) + ? _remaining[_remainingIdx++] + : '\0' /* end of string reached */; + } + + public override bool MovePrevious() + { + if (_remainingIdx == 0) + { + return false; + } + + _remainingIdx--; + return true; + } + } + } +} diff --git a/src/libraries/System.Text.Encoding/tests/Decoder/Decoder.cs b/src/libraries/System.Text.Encoding/tests/Decoder/Decoder.cs index e264679b119c4d..f33bd1e04115fb 100644 --- a/src/libraries/System.Text.Encoding/tests/Decoder/Decoder.cs +++ b/src/libraries/System.Text.Encoding/tests/Decoder/Decoder.cs @@ -276,5 +276,78 @@ public static void DecoderReplacementFallbackBufferTest() Assert.Equal('\u0000', fallbackBuffer.GetNextChar()); Assert.False(fallbackBuffer.MovePrevious(), "Expected we cannot move back on the replacement buffer as we are rest the buffer"); } + + [Fact] + public void DecoderConvertSplitAcrossInvalidMultiByteSequenceTests() + { + // Input = [ C2 58 59 5A ] + // Expected output = [ FFFD 0058 0059 005A ] + + Decoder decoder = Encoding.UTF8.GetDecoder(); + char[] destBuffer = new char[100]; + + int bytesConsumed, charsWritten; + bool completed; + + decoder.Convert(new byte[] { 0xC2 }, destBuffer, flush: false, out bytesConsumed, out charsWritten, out completed); + Assert.Equal(1, bytesConsumed); + Assert.Equal(0, charsWritten); // waiting for more bytes in multi-byte sequence + Assert.True(completed); + + decoder.Convert(new byte[] { (byte)'X' }, destBuffer, flush: false, out bytesConsumed, out charsWritten, out completed); + Assert.Equal(1, bytesConsumed); + Assert.Equal(2, charsWritten); // U+FFFD + 'X' + Assert.True(completed); // no internal state + Assert.Equal(new char[] { '\uFFFD', 'X' }, destBuffer[0..2]); + + decoder.Convert(new byte[] { (byte)'Y' }, destBuffer, flush: false, out bytesConsumed, out charsWritten, out completed); + Assert.Equal(1, bytesConsumed); + Assert.Equal(1, charsWritten); + Assert.True(completed); // no internal state + Assert.Equal('Y', destBuffer[0]); + + decoder.Convert(new byte[] { (byte)'Z' }, destBuffer, flush: true, out bytesConsumed, out charsWritten, out completed); + Assert.Equal(1, bytesConsumed); + Assert.Equal(1, charsWritten); + Assert.True(completed); // no internal state + Assert.Equal('Z', destBuffer[0]); + } + + [Fact] + public void DecoderGetBytesSplitAcrossInvalidMultiByteSequenceTests() + { + // Input = [ C2 58 59 5A ] + // Expected output = [ FFFD 0058 0059 005A ] + + Decoder decoder = Encoding.UTF8.GetDecoder(); + char[] destBuffer = new char[100]; + + int charCount = decoder.GetCharCount(new byte[] { 0xC2 }, flush: false); + Assert.Equal(0, charCount); // waiting for more bytes in multi-byte sequence + + charCount = decoder.GetChars(new byte[] { 0xC2 }, destBuffer, flush: false); + Assert.Equal(0, charCount); + + charCount = decoder.GetCharCount(new byte[] { (byte)'X' }, flush: false); + Assert.Equal(2, charCount); // U+FFFD + 'X' + + charCount = decoder.GetChars(new byte[] { (byte)'X' }, destBuffer, flush: false); + Assert.Equal(2, charCount); + Assert.Equal(new char[] { '\uFFFD', 'X' }, destBuffer[0..2]); + + charCount = decoder.GetCharCount(new byte[] { (byte)'Y' }, flush: false); + Assert.Equal(1, charCount); // 'Y' + + charCount = decoder.GetChars(new byte[] { (byte)'Y' }, destBuffer, flush: false); + Assert.Equal(1, charCount); + Assert.Equal('Y', destBuffer[0]); + + charCount = decoder.GetCharCount(new byte[] { (byte)'Z' }, flush: true); + Assert.Equal(1, charCount); // 'Z' + + charCount = decoder.GetChars(new byte[] { (byte)'Z' }, destBuffer, flush: true); + Assert.Equal(1, charCount); + Assert.Equal('Z', destBuffer[0]); + } } } diff --git a/src/libraries/System.Text.Encoding/tests/Encoder/Encoder.cs b/src/libraries/System.Text.Encoding/tests/Encoder/Encoder.cs index ee556e4b843ff4..6082433ee4ccd7 100644 --- a/src/libraries/System.Text.Encoding/tests/Encoder/Encoder.cs +++ b/src/libraries/System.Text.Encoding/tests/Encoder/Encoder.cs @@ -268,5 +268,157 @@ public static void EncoderReplacementFallbackBufferTest() Assert.Equal('\u0000', fallbackBuffer.GetNextChar()); Assert.False(fallbackBuffer.MovePrevious(), "Expected we cannot move back on the replacement buffer as we are rest the buffer"); } + + [Fact] + public void EncoderConvertSplitAcrossInvalidSurrogateTests() + { + // Input = [ D800 0058 0059 005A ] + // Expected output = [ EF BF BD 58 59 5A ] + + Encoder encoder = Encoding.UTF8.GetEncoder(); + byte[] destBuffer = new byte[100]; + + int charsConsumed, bytesWritten; + bool completed; + + encoder.Convert(new char[] { '\uD800' }, destBuffer, flush: false, out charsConsumed, out bytesWritten, out completed); + Assert.Equal(1, charsConsumed); + Assert.Equal(0, bytesWritten); // waiting for second half of surrogate pair + Assert.True(completed); + + encoder.Convert(new char[] { 'X' }, destBuffer, flush: false, out charsConsumed, out bytesWritten, out completed); + Assert.Equal(1, charsConsumed); + Assert.Equal(4, bytesWritten); // U+FFFD bytes + ASCII 'X' + Assert.True(completed); // no internal state + Assert.Equal(new byte[] { 0xEF, 0xBF, 0xBD, (byte)'X' }, destBuffer[0..4]); + + encoder.Convert(new char[] { 'Y' }, destBuffer, flush: false, out charsConsumed, out bytesWritten, out completed); + Assert.Equal(1, charsConsumed); + Assert.Equal(1, bytesWritten); // ASCII 'Y' + Assert.True(completed); // no internal state + Assert.Equal((byte)'Y', destBuffer[0]); + + encoder.Convert(new char[] { 'Z' }, destBuffer, flush: true, out charsConsumed, out bytesWritten, out completed); + Assert.Equal(1, charsConsumed); + Assert.Equal(1, bytesWritten); // ASCII 'Z' + Assert.True(completed); // no internal state + Assert.Equal((byte)'Z', destBuffer[0]); + } + + [Fact] + public void EncoderConvertSplitAcrossUnencodableSurrogatePairTests() + { + // Input = [ D83C DF32 0058 0059 005A ] + // Expected output = "[1F332]XYZ" (as ASCII bytes) + + Encoder encoder = Encoding.GetEncoding( + "ascii", + new CustomEncoderReplacementFallback(), + DecoderFallback.ExceptionFallback).GetEncoder(); + byte[] destBuffer = new byte[100]; + + int charsConsumed, bytesWritten; + bool completed; + + encoder.Convert(new char[] { '\uD83C' }, destBuffer, flush: false, out charsConsumed, out bytesWritten, out completed); + Assert.Equal(1, charsConsumed); + Assert.Equal(0, bytesWritten); // waiting for second half of surrogate pair + Assert.True(completed); + + encoder.Convert(new char[] { '\uDF32', 'X' }, destBuffer, flush: false, out charsConsumed, out bytesWritten, out completed); + Assert.Equal(2, charsConsumed); + Assert.Equal(8, bytesWritten); // ASCII "[1F332]X" + Assert.True(completed); // no internal state + Assert.Equal(Encoding.ASCII.GetBytes("[1F332]X"), destBuffer[0..8]); + + encoder.Convert(new char[] { 'Y' }, destBuffer, flush: false, out charsConsumed, out bytesWritten, out completed); + Assert.Equal(1, charsConsumed); + Assert.Equal(1, bytesWritten); // ASCII 'Y' + Assert.True(completed); // no internal state + Assert.Equal((byte)'Y', destBuffer[0]); + + encoder.Convert(new char[] { 'Z' }, destBuffer, flush: true, out charsConsumed, out bytesWritten, out completed); + Assert.Equal(1, charsConsumed); + Assert.Equal(1, bytesWritten); // ASCII 'Z' + Assert.True(completed); // no internal state + Assert.Equal((byte)'Z', destBuffer[0]); + } + + [Fact] + public void EncoderGetBytesSplitAcrossInvalidSurrogateTests() + { + // Input = [ D800 0058 0059 005A ] + // Expected output = [ EF BF BD 58 59 5A ] + + Encoder encoder = Encoding.UTF8.GetEncoder(); + byte[] destBuffer = new byte[100]; + + int byteCount = encoder.GetByteCount(new char[] { '\uD800' }, flush: false); + Assert.Equal(0, byteCount); // waiting for second half of surrogate pair + + byteCount = encoder.GetBytes(new char[] { '\uD800' }, destBuffer, flush: false); + Assert.Equal(0, byteCount); + + byteCount = encoder.GetByteCount(new char[] { 'X' }, flush: false); + Assert.Equal(4, byteCount); // U+FFFD bytes + ASCII 'X' + + byteCount = encoder.GetBytes(new char[] { 'X' }, destBuffer, flush: false); + Assert.Equal(4, byteCount); + Assert.Equal(new byte[] { 0xEF, 0xBF, 0xBD, (byte)'X' }, destBuffer[0..4]); + + byteCount = encoder.GetBytes(new char[] { 'Y' }, destBuffer, flush: false); + Assert.Equal(1, byteCount); // ASCII 'Y' + + byteCount = encoder.GetBytes(new char[] { 'Y' }, destBuffer, flush: false); + Assert.Equal(1, byteCount); + Assert.Equal((byte)'Y', destBuffer[0]); + + byteCount = encoder.GetBytes(new char[] { 'Z' }, destBuffer, flush: true); + Assert.Equal(1, byteCount); // ASCII 'Z' + + byteCount = encoder.GetBytes(new char[] { 'Z' }, destBuffer, flush: true); + Assert.Equal(1, byteCount); + Assert.Equal((byte)'Z', destBuffer[0]); + } + + [Fact] + public void EncoderGetBytesSplitAcrossUnencodableSurrogatePairTests() + { + // Input = [ D83C DF32 0058 0059 005A ] + // Expected output = "[1F332]XYZ" (as ASCII bytes) + + Encoder encoder = Encoding.GetEncoding( + "ascii", + new CustomEncoderReplacementFallback(), + DecoderFallback.ExceptionFallback).GetEncoder(); + byte[] destBuffer = new byte[100]; + + int byteCount = encoder.GetByteCount(new char[] { '\uD83C' }, flush: false); + Assert.Equal(0, byteCount); // waiting for second half of surrogate pair + + byteCount = encoder.GetBytes(new char[] { '\uD83C' }, destBuffer, flush: false); + Assert.Equal(0, byteCount); + + byteCount = encoder.GetByteCount(new char[] { '\uDF32', 'X' }, flush: false); + Assert.Equal(8, byteCount); // ASCII "[1F332]X" + + byteCount = encoder.GetBytes(new char[] { '\uDF32', 'X' }, destBuffer, flush: false); + Assert.Equal(8, byteCount); + Assert.Equal(Encoding.ASCII.GetBytes("[1F332]X"), destBuffer[0..8]); + + byteCount = encoder.GetBytes(new char[] { 'Y' }, destBuffer, flush: false); + Assert.Equal(1, byteCount); // ASCII 'Y' + + byteCount = encoder.GetBytes(new char[] { 'Y' }, destBuffer, flush: false); + Assert.Equal(1, byteCount); + Assert.Equal((byte)'Y', destBuffer[0]); + + byteCount = encoder.GetBytes(new char[] { 'Z' }, destBuffer, flush: true); + Assert.Equal(1, byteCount); // ASCII 'Z' + + byteCount = encoder.GetBytes(new char[] { 'Z' }, destBuffer, flush: true); + Assert.Equal(1, byteCount); + Assert.Equal((byte)'Z', destBuffer[0]); + } } } diff --git a/src/libraries/System.Text.Encoding/tests/Encoding/TranscodingStreamTests.cs b/src/libraries/System.Text.Encoding/tests/Encoding/TranscodingStreamTests.cs new file mode 100644 index 00000000000000..ae121d4c1d9232 --- /dev/null +++ b/src/libraries/System.Text.Encoding/tests/Encoding/TranscodingStreamTests.cs @@ -0,0 +1,897 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Moq; +using Xunit; + +namespace System.Text.Tests +{ + public class TranscodingStreamTests + { + public static IEnumerable ReadWriteTestBufferLengths + { + get + { + yield return new object[] { 1 }; + yield return new object[] { 4 * 1024 }; + yield return new object[] { 128 * 1024 }; + yield return new object[] { 2 * 1024 * 1024 }; + } + } + + [Fact] + public void AsyncMethods_ReturnCanceledTaskIfCancellationTokenTripped() + { + // Arrange + + CancellationTokenSource cts = new CancellationTokenSource(); + CancellationToken expectedCancellationToken = cts.Token; + cts.Cancel(); + + var innerStreamMock = new Mock(MockBehavior.Strict); // only CanRead/CanWrite should ever be invoked + innerStreamMock.Setup(o => o.CanRead).Returns(true); + innerStreamMock.Setup(o => o.CanWrite).Returns(true); + + Stream transcodingStream = Encoding.CreateTranscodingStream(innerStreamMock.Object, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + + // Act & assert + + RunTest(() => transcodingStream.ReadAsync(new byte[0], 0, 0, expectedCancellationToken)); + RunTest(() => transcodingStream.ReadAsync(Memory.Empty, expectedCancellationToken).AsTask()); + RunTest(() => transcodingStream.WriteAsync(new byte[0], 0, 0, expectedCancellationToken)); + RunTest(() => transcodingStream.WriteAsync(ReadOnlyMemory.Empty, expectedCancellationToken).AsTask()); + + void RunTest(Func callback) + { + Task task = callback(); + Assert.True(task.IsCanceled); + Assert.Equal(expectedCancellationToken, Assert.Throws(() => task.GetAwaiter().GetResult()).CancellationToken); + } + } + + [Fact] + public void CreateTranscodingStream_InvalidArgs() + { + Assert.Throws("innerStream", () => Encoding.CreateTranscodingStream(null, Encoding.UTF8, Encoding.UTF8)); + Assert.Throws("innerStreamEncoding", () => Encoding.CreateTranscodingStream(Stream.Null, null, Encoding.UTF8)); + Assert.Throws("outerStreamEncoding", () => Encoding.CreateTranscodingStream(Stream.Null, Encoding.UTF8, null)); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void CanRead_DelegatesToInnerStream(bool expectedCanRead) + { + // Arrange + + var innerStreamMock = new Mock(); + innerStreamMock.Setup(o => o.CanRead).Returns(expectedCanRead); + Stream transcodingStream = Encoding.CreateTranscodingStream(innerStreamMock.Object, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + + // Act + + bool actualCanReadBeforeDispose = transcodingStream.CanRead; + transcodingStream.Dispose(); + bool actualCanReadAfterDispose = transcodingStream.CanRead; + + // Assert + + Assert.Equal(expectedCanRead, actualCanReadBeforeDispose); + Assert.False(actualCanReadAfterDispose); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void CanWrite_DelegatesToInnerStream(bool expectedCanWrite) + { + // Arrange + + var innerStreamMock = new Mock(); + innerStreamMock.Setup(o => o.CanWrite).Returns(expectedCanWrite); + Stream transcodingStream = Encoding.CreateTranscodingStream(innerStreamMock.Object, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + + // Act + + bool actualCanWriteBeforeDispose = transcodingStream.CanWrite; + transcodingStream.Dispose(); + bool actualCanWriteAfterDispose = transcodingStream.CanWrite; + + // Assert + + Assert.Equal(expectedCanWrite, actualCanWriteBeforeDispose); + Assert.False(actualCanWriteAfterDispose); + } + + [Fact] + public void Dispose_MakesMostSubsequentOperationsThrow() + { + // Arrange + + MemoryStream innerStream = new MemoryStream(); + Stream transcodingStream = Encoding.CreateTranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + + // Act + + transcodingStream.Dispose(); + + // Assert + // For Task/ValueTask-returning methods, we want the exception to be thrown synchronously. + + Assert.False(transcodingStream.CanRead); + Assert.False(transcodingStream.CanSeek); + Assert.False(transcodingStream.CanWrite); + + Assert.Throws(() => (object)transcodingStream.BeginRead(new byte[0], 0, 0, null, null)); + Assert.Throws(() => (object)transcodingStream.BeginWrite(new byte[0], 0, 0, null, null)); + Assert.Throws(() => transcodingStream.Flush()); + Assert.Throws(() => (object)transcodingStream.FlushAsync()); + Assert.Throws(() => (object)transcodingStream.Read(new byte[0], 0, 0)); + Assert.Throws(() => (object)transcodingStream.Read(Span.Empty)); + Assert.Throws(() => (object)transcodingStream.ReadAsync(new byte[0], 0, 0)); + Assert.Throws(() => (object)transcodingStream.ReadAsync(Memory.Empty)); + Assert.Throws(() => (object)transcodingStream.ReadByte()); + Assert.Throws(() => transcodingStream.Write(new byte[0], 0, 0)); + Assert.Throws(() => transcodingStream.Write(ReadOnlySpan.Empty)); + Assert.Throws(() => (object)transcodingStream.WriteAsync(new byte[0], 0, 0)); + Assert.Throws(() => (object)transcodingStream.WriteAsync(ReadOnlyMemory.Empty)); + Assert.Throws(() => transcodingStream.WriteByte((byte)'x')); + } + + [Fact] + public void Dispose_WithLeaveOpenFalse_DisposesInnerStream() + { + // Sync + + MemoryStream innerStream = new MemoryStream(); + Stream transcodingStream = Encoding.CreateTranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8, leaveOpen: false); + transcodingStream.Dispose(); + transcodingStream.Dispose(); // calling it a second time should no-op + Assert.Throws(() => innerStream.Read(Span.Empty)); + + // Async + + innerStream = new MemoryStream(); + transcodingStream = Encoding.CreateTranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8, leaveOpen: false); + transcodingStream.DisposeAsync().GetAwaiter().GetResult(); + transcodingStream.DisposeAsync().GetAwaiter().GetResult(); // calling it a second time should no-op + Assert.Throws(() => innerStream.Read(Span.Empty)); + } + + [Fact] + public void Dispose_WithLeaveOpenTrue_DoesNotDisposeInnerStream() + { + // Sync + + MemoryStream innerStream = new MemoryStream(); + Stream transcodingStream = Encoding.CreateTranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + transcodingStream.Dispose(); + transcodingStream.Dispose(); // calling it a second time should no-op + innerStream.Read(Span.Empty); // shouldn't throw + + // Async + + innerStream = new MemoryStream(); + transcodingStream = Encoding.CreateTranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + transcodingStream.DisposeAsync().GetAwaiter().GetResult(); + transcodingStream.DisposeAsync().GetAwaiter().GetResult(); // calling it a second time should no-op + innerStream.Read(Span.Empty); // shouldn't throw + } + + [Fact] + public void Flush_FlushesInnerStreamButNotDecodedState() + { + // Arrange + + CancellationToken expectedCancellationToken = new CancellationTokenSource().Token; + Task expectedFlushAsyncTask = Task.FromResult("just some task"); + + var innerStreamMock = new Mock() { CallBase = true }; + innerStreamMock.Setup(o => o.FlushAsync(expectedCancellationToken)).Returns(expectedFlushAsyncTask); + Stream transcodingStream = Encoding.CreateTranscodingStream(innerStreamMock.Object, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + + transcodingStream.Write(new byte[] { 0x7A, 0xE0 }); + innerStreamMock.Verify(o => o.Flush(), Times.Never); + innerStreamMock.Verify(o => o.FlushAsync(It.IsAny()), Times.Never); + + // Act & assert - sync flush + + transcodingStream.Flush(); + innerStreamMock.Verify(o => o.Flush(), Times.Once); + innerStreamMock.Verify(o => o.FlushAsync(It.IsAny()), Times.Never); + + // Act & assert - async flush + // This also validates that we flowed the CancellationToken as expected + + Task actualFlushAsyncReturnedTask = transcodingStream.FlushAsync(expectedCancellationToken); + Assert.Same(expectedFlushAsyncTask, actualFlushAsyncReturnedTask); + innerStreamMock.Verify(o => o.Flush(), Times.Once); + innerStreamMock.Verify(o => o.FlushAsync(expectedCancellationToken), Times.Once); + + Assert.Equal("z", Encoding.UTF8.GetString(innerStreamMock.Object.ToArray())); // [ E0 ] shouldn't have been flushed + } + + [Fact] + public void IdenticalInnerAndOuterEncodings_DoesNotActAsPassthrough() + { + // Test read + // [ C0 ] is never a valid UTF-8 byte, should be replaced with U+FFFD + + MemoryStream innerStream = new MemoryStream(new byte[] { 0xC0 }); + Stream transcodingStream = Encoding.CreateTranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8); + + Assert.Equal(0xEF, transcodingStream.ReadByte()); + Assert.Equal(0xBF, transcodingStream.ReadByte()); + Assert.Equal(0xBD, transcodingStream.ReadByte()); + Assert.Equal(-1 /* eof */, transcodingStream.ReadByte()); + + // Test write + + innerStream = new MemoryStream(); + transcodingStream = Encoding.CreateTranscodingStream(innerStream, Encoding.UTF8, Encoding.UTF8); + transcodingStream.WriteByte(0xC0); + Assert.Equal(new byte[] { 0xEF, 0xBF, 0xBD }, innerStream.ToArray()); + } + + [Theory] + [MemberData(nameof(ReadWriteTestBufferLengths))] + public void Read_ByteArray(int bufferLength) + { + // Tests TranscodingStream.Read(byte[], int, int) + + byte[] buffer = new byte[bufferLength + 3]; + + RunReadTest((transcodingStream, sink) => + { + int numBytesRead = transcodingStream.Read(buffer, 1, bufferLength); + Assert.True(numBytesRead >= 0); + Assert.True(numBytesRead <= bufferLength); + + sink.Write(buffer, 1, numBytesRead); + return numBytesRead; + }); + } + + [Fact] + public void Read_ByteArray_WithInvalidArgs_Throws() + { + Stream transcodingStream = Encoding.CreateTranscodingStream(new MemoryStream(), Encoding.UTF8, Encoding.UTF8); + + Assert.Throws("buffer", () => transcodingStream.Read(null, 0, 0)); + Assert.Throws(() => transcodingStream.Read(new byte[5], -1, -1)); + Assert.Throws(() => transcodingStream.Read(new byte[5], 3, -1)); + Assert.Throws(() => transcodingStream.Read(new byte[5], 5, 1)); + Assert.Throws(() => transcodingStream.Read(new byte[5], 6, -1)); + Assert.Throws(() => transcodingStream.Read(new byte[5], 6, 0)); + } + + [Fact] + public void Read_ByteByByte() + { + // Tests TranscodingStream.ReadByte + + RunReadTest((transcodingStream, sink) => + { + int value = transcodingStream.ReadByte(); + if (value < 0) + { + return 0; + } + + sink.WriteByte(checked((byte)value)); + return 1; + }); + } + + [Theory] + [MemberData(nameof(ReadWriteTestBufferLengths))] + public void Read_Span(int bufferLength) + { + // Tests TranscodingStream.Read(Span) + + byte[] buffer = new byte[bufferLength]; + + RunReadTest((transcodingStream, sink) => + { + int numBytesRead = transcodingStream.Read(buffer.AsSpan()); + Assert.True(numBytesRead >= 0); + Assert.True(numBytesRead <= bufferLength); + + sink.Write(buffer.AsSpan(0..numBytesRead)); + return numBytesRead; + }); + } + + private void RunReadTest(Func callback) + { + MemoryStream sink = new MemoryStream(); + + MemoryStream innerStream = new MemoryStream(); + Stream transcodingStream = Encoding.CreateTranscodingStream(innerStream, + innerStreamEncoding: Encoding.UTF8, + outerStreamEncoding: CustomAsciiEncoding); + + // Test with a small string, then test with a large string + + RunOneTestIteration(128); + RunOneTestIteration(10 * 1024 * 1024); + + Assert.Equal(-1, transcodingStream.ReadByte()); // should've reached EOF + + // Now put some invalid data into the inner stream as EOF. + + innerStream.SetLength(0); // reset + innerStream.WriteByte(0xC0); + innerStream.Position = 0; + + sink.SetLength(0); // reset + int numBytesReadJustNow; + do + { + numBytesReadJustNow = callback(transcodingStream, sink); + Assert.True(numBytesReadJustNow >= 0); + } while (numBytesReadJustNow > 0); + + Assert.Equal("[FFFD]", ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + Assert.Equal(-1, transcodingStream.ReadByte()); // should've reached EOF + + void RunOneTestIteration(int stringLength) + { + sink.SetLength(0); // reset + + string expectedStringContents = GetVeryLongAsciiString(stringLength); + innerStream.SetLength(0); // reset + innerStream.Write(Encoding.UTF8.GetBytes(expectedStringContents)); + innerStream.Position = 0; + + int numBytesReadJustNow; + do + { + numBytesReadJustNow = callback(transcodingStream, sink); + Assert.True(numBytesReadJustNow >= 0); + } while (numBytesReadJustNow > 0); + + Assert.Equal(expectedStringContents, ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + } + } + + [Fact] + public Task ReadApm() + { + // Tests TranscodingStream.BeginRead / EndRead + + byte[] buffer = new byte[1024 * 1024]; + + return RunReadTestAsync((transcodingStream, cancellationToken, sink) => + { + TaskCompletionSource tcs = new TaskCompletionSource(); + object expectedState = new object(); + + try + { + IAsyncResult asyncResult = transcodingStream.BeginRead(buffer, 1, buffer.Length - 2, (asyncResult) => + { + try + { + int numBytesReadJustNow = transcodingStream.EndRead(asyncResult); + Assert.True(numBytesReadJustNow >= 0); + Assert.True(numBytesReadJustNow < buffer.Length - 3); + sink.Write(buffer, 1, numBytesReadJustNow); + tcs.SetResult(numBytesReadJustNow); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }, expectedState); + Assert.Same(expectedState, asyncResult.AsyncState); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + + return new ValueTask(tcs.Task); + }, + suppressExpectedCancellationTokenAsserts: true); // APM pattern doesn't allow flowing CancellationToken + } + + [Theory] + [MemberData(nameof(ReadWriteTestBufferLengths))] + public Task ReadAsync_ByteArray(int bufferLength) + { + // Tests TranscodingStream.ReadAsync(byte[], int, int, CancellationToken) + + byte[] buffer = new byte[bufferLength + 3]; + + return RunReadTestAsync(async (transcodingStream, cancellationToken, sink) => + { + int numBytesRead = await transcodingStream.ReadAsync(buffer, 1, bufferLength, cancellationToken); + Assert.True(numBytesRead >= 0); + Assert.True(numBytesRead <= bufferLength); + + sink.Write(buffer, 1, numBytesRead); + return numBytesRead; + }); + } + + [Theory] + [MemberData(nameof(ReadWriteTestBufferLengths))] + public async Task ReadAsync_Memory(int bufferLength) + { + // Tests TranscodingStream.ReadAsync(Memory, CancellationToken) + + byte[] buffer = new byte[bufferLength]; + + await RunReadTestAsync(async (transcodingStream, cancellationToken, sink) => + { + int numBytesRead = await transcodingStream.ReadAsync(buffer.AsMemory(), cancellationToken); + Assert.True(numBytesRead >= 0); + Assert.True(numBytesRead <= bufferLength); + + sink.Write(buffer.AsSpan(0..numBytesRead)); + return numBytesRead; + }); + } + + [Fact] + public void ReadAsync_WithInvalidArgs_Throws() + { + Stream transcodingStream = Encoding.CreateTranscodingStream(new MemoryStream(), Encoding.UTF8, Encoding.UTF8); + + Assert.Throws("buffer", () => (object)transcodingStream.ReadAsync(null, 0, 0)); + Assert.Throws(() => (object)transcodingStream.ReadAsync(new byte[5], -1, -1)); + Assert.Throws(() => (object)transcodingStream.ReadAsync(new byte[5], 3, -1)); + Assert.Throws(() => (object)transcodingStream.ReadAsync(new byte[5], 5, 1)); + Assert.Throws(() => (object)transcodingStream.ReadAsync(new byte[5], 6, -1)); + Assert.Throws(() => (object)transcodingStream.ReadAsync(new byte[5], 6, 0)); + } + + [Fact] + public void ReadApm_WithInvalidArgs_Throws() + { + Stream transcodingStream = Encoding.CreateTranscodingStream(new MemoryStream(), Encoding.UTF8, Encoding.UTF8); + + Assert.Throws("buffer", () => transcodingStream.BeginRead(null, 0, 0, null, null)); + Assert.Throws(() => transcodingStream.BeginRead(new byte[5], -1, -1, null, null)); + Assert.Throws(() => transcodingStream.BeginRead(new byte[5], 3, -1, null, null)); + Assert.Throws(() => transcodingStream.BeginRead(new byte[5], 5, 1, null, null)); + Assert.Throws(() => transcodingStream.BeginRead(new byte[5], 6, -1, null, null)); + Assert.Throws(() => transcodingStream.BeginRead(new byte[5], 6, 0, null, null)); + } + + private async Task RunReadTestAsync(Func> callback, bool suppressExpectedCancellationTokenAsserts = false) + { + CancellationToken expectedCancellationToken = new CancellationTokenSource().Token; + MemoryStream sink = new MemoryStream(); + MemoryStream innerStream = new MemoryStream(); + + var delegatingInnerStreamMock = new Mock(MockBehavior.Strict); + delegatingInnerStreamMock.Setup(o => o.CanRead).Returns(true); + + if (suppressExpectedCancellationTokenAsserts) + { + delegatingInnerStreamMock.Setup(o => o.ReadAsync(It.IsAny>(), It.IsAny())) + .Returns, CancellationToken>(innerStream.ReadAsync); + } + else + { + delegatingInnerStreamMock.Setup(o => o.ReadAsync(It.IsAny>(), expectedCancellationToken)) + .Returns, CancellationToken>(innerStream.ReadAsync); + } + + Stream transcodingStream = Encoding.CreateTranscodingStream( + innerStream: delegatingInnerStreamMock.Object, + innerStreamEncoding: Encoding.UTF8, + outerStreamEncoding: CustomAsciiEncoding); + + // Test with a small string, then test with a large string + + await RunOneTestIteration(128); + await RunOneTestIteration(10 * 1024 * 1024); + + Assert.Equal(-1, await transcodingStream.ReadByteAsync(expectedCancellationToken)); // should've reached EOF + + // Now put some invalid data into the inner stream as EOF. + + innerStream.SetLength(0); // reset + innerStream.WriteByte(0xC0); + innerStream.Position = 0; + + sink.SetLength(0); // reset + int numBytesReadJustNow; + do + { + numBytesReadJustNow = await callback(transcodingStream, expectedCancellationToken, sink); + Assert.True(numBytesReadJustNow >= 0); + } while (numBytesReadJustNow > 0); + + Assert.Equal("[FFFD]", ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + Assert.Equal(-1, await transcodingStream.ReadByteAsync(expectedCancellationToken)); // should've reached EOF + + async Task RunOneTestIteration(int stringLength) + { + sink.SetLength(0); // reset + + string expectedStringContents = GetVeryLongAsciiString(stringLength); + innerStream.SetLength(0); // reset + innerStream.Write(Encoding.UTF8.GetBytes(expectedStringContents)); + innerStream.Position = 0; + + int numBytesReadJustNow; + do + { + numBytesReadJustNow = await callback(transcodingStream, expectedCancellationToken, sink); + Assert.True(numBytesReadJustNow >= 0); + } while (numBytesReadJustNow > 0); + + Assert.Equal(expectedStringContents, ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + } + } + + [Fact] + public void ReadTimeout_WriteTimeout_NotSupported() + { + // Arrange - allow inner stream to support ReadTimeout + WriteTimeout + + var innerStreamMock = new Mock(); + innerStreamMock.SetupProperty(o => o.ReadTimeout); + innerStreamMock.SetupProperty(o => o.WriteTimeout); + Stream transcodingStream = Encoding.CreateTranscodingStream(Stream.Null, Encoding.UTF8, Encoding.UTF8, leaveOpen: true); + + // Act & assert - TranscodingStream shouldn't support ReadTimeout + WriteTimeout + + Assert.False(transcodingStream.CanTimeout); + Assert.Throws(() => transcodingStream.ReadTimeout); + Assert.Throws(() => transcodingStream.ReadTimeout = 42); + Assert.Throws(() => transcodingStream.WriteTimeout); + Assert.Throws(() => transcodingStream.WriteTimeout = 42); + } + + [Fact] + public void Seek_AlwaysThrows() + { + // MemoryStream is seekable, but we're not + Stream transcodingStream = Encoding.CreateTranscodingStream(new MemoryStream(), Encoding.UTF8, Encoding.UTF8); + + Assert.False(transcodingStream.CanSeek); + Assert.Throws(() => transcodingStream.Length); + Assert.Throws(() => transcodingStream.Position); + Assert.Throws(() => transcodingStream.Position = 0); + Assert.Throws(() => transcodingStream.Seek(0, SeekOrigin.Current)); + Assert.Throws(() => transcodingStream.SetLength(0)); + } + + [Fact] + public void Write() + { + MemoryStream innerStream = new MemoryStream(); + Stream transcodingStream = Encoding.CreateTranscodingStream( + innerStream, + innerStreamEncoding: ErrorCheckingUnicodeEncoding /* throws on error */, + outerStreamEncoding: Encoding.UTF8 /* performs substition */, + leaveOpen: true); + + // First, test Write(byte[], int, int) + + transcodingStream.Write(Encoding.UTF8.GetBytes("abcdefg"), 2, 3); + Assert.Equal("cde", ErrorCheckingUnicodeEncoding.GetString(innerStream.ToArray())); + + // Then test WriteByte(byte) + + transcodingStream.WriteByte((byte)'z'); + Assert.Equal("cdez", ErrorCheckingUnicodeEncoding.GetString(innerStream.ToArray())); + + // We'll write U+00E0 (utf-8: [C3 A0]) byte-by-byte. + // We shouldn't flush any intermediate bytes. + + transcodingStream.WriteByte((byte)0xC3); + Assert.Equal("cdez", ErrorCheckingUnicodeEncoding.GetString(innerStream.ToArray())); + + transcodingStream.WriteByte((byte)0xA0); + Assert.Equal("cdez\u00E0", ErrorCheckingUnicodeEncoding.GetString(innerStream.ToArray())); + + innerStream.SetLength(0); // reset inner stream + + // Then test Write(ROS), once with a short string and once with a long string + + string asciiString = GetVeryLongAsciiString(128); + byte[] asciiBytesAsUtf8 = Encoding.UTF8.GetBytes(asciiString); + transcodingStream.Write(asciiBytesAsUtf8.AsSpan()); + Assert.Equal(asciiString, ErrorCheckingUnicodeEncoding.GetString(innerStream.ToArray())); + + innerStream.SetLength(0); // reset inner stream + + asciiString = GetVeryLongAsciiString(16 * 1024 * 1024); + asciiBytesAsUtf8 = Encoding.UTF8.GetBytes(asciiString); + transcodingStream.Write(asciiBytesAsUtf8.AsSpan()); + Assert.Equal(asciiString, ErrorCheckingUnicodeEncoding.GetString(innerStream.ToArray())); + + innerStream.SetLength(0); // reset inner stream + + // Close the outer stream and ensure no leftover data was written to the inner stream + + transcodingStream.Close(); + Assert.Equal(0, innerStream.Position); + } + + [Fact] + public void Write_WithPartialData() + { + MemoryStream innerStream = new MemoryStream(); + Stream transcodingStream = Encoding.CreateTranscodingStream( + innerStream, + innerStreamEncoding: CustomAsciiEncoding /* performs custom substitution */, + outerStreamEncoding: Encoding.UTF8 /* performs U+FFFD substition */, + leaveOpen: true); + + // First, write some incomplete data + + transcodingStream.Write(new byte[] { 0x78, 0x79, 0x7A, 0xC3 }); // [C3] shouldn't be flushed yet + Assert.Equal("xyz", ErrorCheckingAsciiEncoding.GetString(innerStream.ToArray())); + + // Flushing should have no effect + + transcodingStream.Flush(); + Assert.Equal("xyz", ErrorCheckingAsciiEncoding.GetString(innerStream.ToArray())); + + // Provide the second byte of the multi-byte sequence + + transcodingStream.WriteByte(0xA0); // [C3 A0] = U+00E0 + Assert.Equal("xyz[00E0]", ErrorCheckingAsciiEncoding.GetString(innerStream.ToArray())); + + // Provide an incomplete sequence, then close the stream. + // Closing the stream should flush the underlying buffers and write the replacement char. + + transcodingStream.Write(new byte[] { 0xE0, 0xBF }); // first 2 bytes of incomplete 3-byte sequence + Assert.Equal("xyz[00E0]", ErrorCheckingAsciiEncoding.GetString(innerStream.ToArray())); // wasn't flushed yet + + transcodingStream.Close(); + Assert.Equal("xyz[00E0][FFFD]", ErrorCheckingAsciiEncoding.GetString(innerStream.ToArray())); + } + + [Fact] + public void Write_WithInvalidArgs_Throws() + { + Stream transcodingStream = Encoding.CreateTranscodingStream(new MemoryStream(), Encoding.UTF8, Encoding.UTF8); + + Assert.Throws("buffer", () => transcodingStream.Write(null, 0, 0)); + Assert.Throws(() => transcodingStream.Write(new byte[5], -1, -1)); + Assert.Throws(() => transcodingStream.Write(new byte[5], 3, -1)); + Assert.Throws(() => transcodingStream.Write(new byte[5], 5, 1)); + Assert.Throws(() => transcodingStream.Write(new byte[5], 6, -1)); + Assert.Throws(() => transcodingStream.Write(new byte[5], 6, 0)); + } + + [Fact] + public async Task WriteAsync() + { + MemoryStream sink = new MemoryStream(); + CancellationToken expectedFlushAsyncCancellationToken = new CancellationTokenSource().Token; + CancellationToken expectedWriteAsyncCancellationToken = new CancellationTokenSource().Token; + + var innerStreamMock = new Mock(MockBehavior.Strict); + innerStreamMock.Setup(o => o.CanWrite).Returns(true); + innerStreamMock.Setup(o => o.WriteAsync(It.IsAny>(), expectedWriteAsyncCancellationToken)) + .Returns, CancellationToken>(sink.WriteAsync); + innerStreamMock.Setup(o => o.FlushAsync(expectedFlushAsyncCancellationToken)).Returns(Task.CompletedTask); + + Stream transcodingStream = Encoding.CreateTranscodingStream( + innerStreamMock.Object, + innerStreamEncoding: ErrorCheckingUnicodeEncoding, + outerStreamEncoding: Encoding.UTF8 /* performs U+FFFD substition */, + leaveOpen: true); + + // First, test WriteAsync(byte[], int, int, CancellationToken) + + await transcodingStream.WriteAsync(Encoding.UTF8.GetBytes("abcdefg"), 2, 3, expectedWriteAsyncCancellationToken); + Assert.Equal("cde", ErrorCheckingUnicodeEncoding.GetString(sink.ToArray())); + + // We'll write U+00E0 (utf-8: [C3 A0]) byte-by-byte. + // We shouldn't flush any intermediate bytes. + + await transcodingStream.WriteAsync(new byte[] { 0xC3, 0xA0 }, 0, 1, expectedWriteAsyncCancellationToken); + await transcodingStream.FlushAsync(expectedFlushAsyncCancellationToken); + Assert.Equal("cde", ErrorCheckingUnicodeEncoding.GetString(sink.ToArray())); + + await transcodingStream.WriteAsync(new byte[] { 0xC3, 0xA0 }, 1, 1, expectedWriteAsyncCancellationToken); + Assert.Equal("cde\u00E0", ErrorCheckingUnicodeEncoding.GetString(sink.ToArray())); + + sink.SetLength(0); // reset sink + + // Then test WriteAsync(ROM, CancellationToken), once with a short string and once with a long string + + string asciiString = GetVeryLongAsciiString(128); + byte[] asciiBytesAsUtf8 = Encoding.UTF8.GetBytes(asciiString); + await transcodingStream.WriteAsync(asciiBytesAsUtf8.AsMemory(), expectedWriteAsyncCancellationToken); + Assert.Equal(asciiString, ErrorCheckingUnicodeEncoding.GetString(sink.ToArray())); + + sink.SetLength(0); // reset sink + + asciiString = GetVeryLongAsciiString(16 * 1024 * 1024); + asciiBytesAsUtf8 = Encoding.UTF8.GetBytes(asciiString); + await transcodingStream.WriteAsync(asciiBytesAsUtf8.AsMemory(), expectedWriteAsyncCancellationToken); + Assert.Equal(asciiString, ErrorCheckingUnicodeEncoding.GetString(sink.ToArray())); + + sink.SetLength(0); // reset sink + + // Close the outer stream and ensure no leftover data was written to the inner stream + + ValueTask actualDisposeTask = transcodingStream.DisposeAsync(); + Assert.Equal(default(ValueTask), actualDisposeTask); // should've completed synchronously + Assert.Equal(0, sink.Position); + } + + [Fact] + public async Task WriteAsync_WithPartialData() + { + MemoryStream sink = new MemoryStream(); + CancellationToken expectedCancellationToken = new CancellationTokenSource().Token; + + var innerStreamMock = new Mock(MockBehavior.Strict); + innerStreamMock.Setup(o => o.CanWrite).Returns(true); + innerStreamMock.Setup(o => o.WriteAsync(It.IsAny>(), expectedCancellationToken)) + .Returns, CancellationToken>(sink.WriteAsync); + + Stream transcodingStream = Encoding.CreateTranscodingStream( + innerStreamMock.Object, + innerStreamEncoding: CustomAsciiEncoding /* performs custom substitution */, + outerStreamEncoding: Encoding.UTF8 /* performs U+FFFD substition */, + leaveOpen: true); + + // First, write some incomplete data + + await transcodingStream.WriteAsync(new byte[] { 0x78, 0x79, 0x7A, 0xC3 }, expectedCancellationToken); // [C3] shouldn't be flushed yet + Assert.Equal("xyz", ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + + // Provide the second byte of the multi-byte sequence + + await transcodingStream.WriteAsync(new byte[] { 0xA0 }, expectedCancellationToken); // [C3 A0] = U+00E0 + Assert.Equal("xyz[00E0]", ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + + // Provide an incomplete sequence, then close the stream. + // Closing the stream should flush the underlying buffers and write the replacement char. + + await transcodingStream.WriteAsync(new byte[] { 0xE0, 0xBF }, expectedCancellationToken); // first 2 bytes of incomplete 3-byte sequence + Assert.Equal("xyz[00E0]", ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); // wasn't flushed yet + + // The call to DisposeAsync() will call innerStream.WriteAsync without a CancellationToken. + + innerStreamMock.Setup(o => o.WriteAsync(It.IsAny>(), CancellationToken.None)) + .Returns, CancellationToken>(sink.WriteAsync); + + await transcodingStream.DisposeAsync(); + Assert.Equal("xyz[00E0][FFFD]", ErrorCheckingAsciiEncoding.GetString(sink.ToArray())); + } + + [Fact] + public void WriteAsync_WithInvalidArgs_Throws() + { + Stream transcodingStream = Encoding.CreateTranscodingStream(new MemoryStream(), Encoding.UTF8, Encoding.UTF8); + + Assert.Throws("buffer", () => (object)transcodingStream.WriteAsync(null, 0, 0)); + Assert.Throws(() => (object)transcodingStream.WriteAsync(new byte[5], -1, -1)); + Assert.Throws(() => (object)transcodingStream.WriteAsync(new byte[5], 3, -1)); + Assert.Throws(() => (object)transcodingStream.WriteAsync(new byte[5], 5, 1)); + Assert.Throws(() => (object)transcodingStream.WriteAsync(new byte[5], 6, -1)); + Assert.Throws(() => (object)transcodingStream.WriteAsync(new byte[5], 6, 0)); + } + + [Fact] + public void WriteApm() + { + // Arrange + + MemoryStream sink = new MemoryStream(); + object expectedState = new object(); + + var innerStreamMock = new Mock(MockBehavior.Strict); + innerStreamMock.Setup(o => o.CanWrite).Returns(true); + innerStreamMock.Setup(o => o.WriteAsync(It.IsAny>(), CancellationToken.None)) + .Returns, CancellationToken>(sink.WriteAsync); + + Stream transcodingStream = Encoding.CreateTranscodingStream(innerStreamMock.Object, Encoding.UTF8, Encoding.UTF8); + + // Act + + IAsyncResult asyncResult = transcodingStream.BeginWrite(Encoding.UTF8.GetBytes("abcdefg"), 1, 3, null, expectedState); + transcodingStream.EndWrite(asyncResult); + + // Assert + + Assert.Equal(expectedState, asyncResult.AsyncState); + Assert.Equal("bcd", Encoding.UTF8.GetString(sink.ToArray())); + } + + [Fact] + public void WriteApm_WithInvalidArgs_Throws() + { + Stream transcodingStream = Encoding.CreateTranscodingStream(new MemoryStream(), Encoding.UTF8, Encoding.UTF8); + + Assert.Throws("buffer", () => transcodingStream.BeginWrite(null, 0, 0, null, null)); + Assert.Throws(() => transcodingStream.BeginWrite(new byte[5], -1, -1, null, null)); + Assert.Throws(() => transcodingStream.BeginWrite(new byte[5], 3, -1, null, null)); + Assert.Throws(() => transcodingStream.BeginWrite(new byte[5], 5, 1, null, null)); + Assert.Throws(() => transcodingStream.BeginWrite(new byte[5], 6, -1, null, null)); + Assert.Throws(() => transcodingStream.BeginWrite(new byte[5], 6, 0, null, null)); + } + + // returns "abc...xyzabc...xyzabc..." + private static string GetVeryLongAsciiString(int length) + { + return string.Create(length, (object)null, (buffer, _) => + { + for (int i = 0; i < buffer.Length; i++) + { + buffer[i] = (char)('a' + (i % 26)); + } + }); + } + + // A custom ASCIIEncoding where both encoder + decoder fallbacks have been specified + private static readonly Encoding CustomAsciiEncoding = Encoding.GetEncoding( + "ascii", new CustomEncoderFallback(), new DecoderReplacementFallback("\uFFFD")); + + private static readonly Encoding ErrorCheckingAsciiEncoding + = Encoding.GetEncoding("ascii", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback); + + private static readonly UnicodeEncoding ErrorCheckingUnicodeEncoding + = new UnicodeEncoding(bigEndian: false, byteOrderMark: false, throwOnInvalidBytes: true); + + // A custom encoder fallback which substitutes unknown chars with "[xxxx]" (the code point as hex) + private sealed class CustomEncoderFallback : EncoderFallback + { + public override int MaxCharCount => 8; // = "[10FFFF]".Length + + public override EncoderFallbackBuffer CreateFallbackBuffer() + { + return new CustomEncoderFallbackBuffer(); + } + + private sealed class CustomEncoderFallbackBuffer : EncoderFallbackBuffer + { + private string _remaining = string.Empty; + private int _remainingIdx = 0; + + public override int Remaining => _remaining.Length - _remainingIdx; + + public override bool Fallback(char charUnknownHigh, char charUnknownLow, int index) + => FallbackCommon((uint)char.ConvertToUtf32(charUnknownHigh, charUnknownLow)); + + public override bool Fallback(char charUnknown, int index) + => FallbackCommon(charUnknown); + + private bool FallbackCommon(uint codePoint) + { + Assert.True(codePoint <= 0x10FFFF); + _remaining = FormattableString.Invariant($"[{codePoint:X4}]"); + _remainingIdx = 0; + return true; + } + + public override char GetNextChar() + { + return (_remainingIdx < _remaining.Length) + ? _remaining[_remainingIdx++] + : '\0' /* end of string reached */; + } + + public override bool MovePrevious() + { + if (_remainingIdx == 0) + { + return false; + } + + _remainingIdx--; + return true; + } + } + } + } +} diff --git a/src/libraries/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj b/src/libraries/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj index e30fdcac586139..7b990f30a054cb 100644 --- a/src/libraries/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj +++ b/src/libraries/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj @@ -13,6 +13,7 @@ + @@ -33,6 +34,7 @@ + @@ -76,4 +78,7 @@ + + + \ No newline at end of file diff --git a/src/libraries/System.Text.Encodings.Web/ref/System.Text.Encodings.Web.csproj b/src/libraries/System.Text.Encodings.Web/ref/System.Text.Encodings.Web.csproj index 2f4b2ad7c9ab2a..a587f8acf98914 100644 --- a/src/libraries/System.Text.Encodings.Web/ref/System.Text.Encodings.Web.csproj +++ b/src/libraries/System.Text.Encodings.Web/ref/System.Text.Encodings.Web.csproj @@ -8,12 +8,12 @@ - + - + \ No newline at end of file diff --git a/src/libraries/System.Text.Encodings.Web/src/System.Text.Encodings.Web.csproj b/src/libraries/System.Text.Encodings.Web/src/System.Text.Encodings.Web.csproj index 176198fafdd570..bc4e58f83b3205 100644 --- a/src/libraries/System.Text.Encodings.Web/src/System.Text.Encodings.Web.csproj +++ b/src/libraries/System.Text.Encodings.Web/src/System.Text.Encodings.Web.csproj @@ -1,7 +1,7 @@ true - netcoreapp3.0;netstandard2.1;netstandard2.0;$(NetCoreAppCurrent) + $(NetCoreAppCurrent);netcoreapp3.0;netstandard2.1;netstandard2.0 true enable @@ -22,30 +22,27 @@ - + - - System\Text\UnicodeDebug.cs - - - System\Text\UnicodeUtility.cs - - - Common\System\HexConverter.cs - + + + - + - \ No newline at end of file + diff --git a/src/libraries/System.Text.Encodings.Web/tests/System.Text.Encodings.Web.Tests.csproj b/src/libraries/System.Text.Encodings.Web/tests/System.Text.Encodings.Web.Tests.csproj index 5c821348d95b40..26f3b0dd17c6d3 100644 --- a/src/libraries/System.Text.Encodings.Web/tests/System.Text.Encodings.Web.Tests.csproj +++ b/src/libraries/System.Text.Encodings.Web/tests/System.Text.Encodings.Web.Tests.csproj @@ -46,14 +46,11 @@ CharUnicodeInfo\UnicodeData.$(UnicodeUcdVersion).txt UnicodeData.txt - - System\Text\UnicodeDebug.cs - - - System\Text\UnicodeUtility.cs - - - Common\System\HexConverter.cs - + + + diff --git a/src/libraries/System.Text.Encodings.Web/tools/GenDefinedCharList/GenDefinedCharList.csproj b/src/libraries/System.Text.Encodings.Web/tools/GenDefinedCharList/GenDefinedCharList.csproj index 70145d7d7c48c3..da2080cc5e87a6 100644 --- a/src/libraries/System.Text.Encodings.Web/tools/GenDefinedCharList/GenDefinedCharList.csproj +++ b/src/libraries/System.Text.Encodings.Web/tools/GenDefinedCharList/GenDefinedCharList.csproj @@ -1,4 +1,4 @@ - + Exe netcoreapp3.1 diff --git a/src/libraries/System.Text.Encodings.Web/tools/GenUnicodeRanges/GenUnicodeRanges.csproj b/src/libraries/System.Text.Encodings.Web/tools/GenUnicodeRanges/GenUnicodeRanges.csproj index 70145d7d7c48c3..da2080cc5e87a6 100644 --- a/src/libraries/System.Text.Encodings.Web/tools/GenUnicodeRanges/GenUnicodeRanges.csproj +++ b/src/libraries/System.Text.Encodings.Web/tools/GenUnicodeRanges/GenUnicodeRanges.csproj @@ -1,4 +1,4 @@ - + Exe netcoreapp3.1 diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index f206b3af9462f4..4aa8377c12746c 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -209,9 +209,11 @@ public sealed partial class JsonSerializerOptions { public JsonSerializerOptions() { } public JsonSerializerOptions(System.Text.Json.JsonSerializerOptions options) { } + public JsonSerializerOptions(System.Text.Json.JsonSerializerDefaults defaults) { } public bool AllowTrailingCommas { get { throw null; } set { } } public System.Collections.Generic.IList Converters { get { throw null; } } public int DefaultBufferSize { get { throw null; } set { } } + public System.Text.Json.Serialization.JsonIgnoreCondition DefaultIgnoreCondition { get { throw null; } set { } } public System.Text.Json.JsonNamingPolicy? DictionaryKeyPolicy { get { throw null; } set { } } public System.Text.Encodings.Web.JavaScriptEncoder? Encoder { get { throw null; } set { } } public bool IgnoreNullValues { get { throw null; } set { } } @@ -224,6 +226,11 @@ public JsonSerializerOptions(System.Text.Json.JsonSerializerOptions options) { } public bool WriteIndented { get { throw null; } set { } } public System.Text.Json.Serialization.JsonConverter GetConverter(System.Type typeToConvert) { throw null; } } + public enum JsonSerializerDefaults + { + General = 0, + Web = 1, + } public enum JsonTokenType : byte { None = (byte)0, @@ -459,9 +466,9 @@ namespace System.Text.Json.Serialization { public enum JsonIgnoreCondition { - Always = 0, - WhenNull = 1, - Never = 2, + Never = 0, + Always = 1, + WhenWritingDefault = 2, } public abstract partial class JsonAttribute : System.Attribute { @@ -489,8 +496,10 @@ public abstract partial class JsonConverter : System.Text.Json.Serialization. { protected internal JsonConverter() { } public override bool CanConvert(System.Type typeToConvert) { throw null; } + public virtual bool HandleNull { get { throw null; } } + [return: System.Diagnostics.CodeAnalysis.MaybeNull] public abstract T Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options); - public abstract void Write(System.Text.Json.Utf8JsonWriter writer, [System.Diagnostics.CodeAnalysis.DisallowNull] T value, System.Text.Json.JsonSerializerOptions options); + public abstract void Write(System.Text.Json.Utf8JsonWriter writer, T value, System.Text.Json.JsonSerializerOptions options); } [System.AttributeUsageAttribute(System.AttributeTargets.Constructor, AllowMultiple = false)] public sealed partial class JsonConstructorAttribute : System.Text.Json.Serialization.JsonAttribute @@ -508,6 +517,11 @@ public sealed partial class JsonIgnoreAttribute : System.Text.Json.Serialization public JsonIgnoreAttribute() { } public System.Text.Json.Serialization.JsonIgnoreCondition Condition { get { throw null; } set { } } } + [System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple = false)] + public sealed partial class JsonIncludeAttribute : System.Text.Json.Serialization.JsonAttribute + { + public JsonIncludeAttribute() { } + } [System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false)] public sealed partial class JsonPropertyNameAttribute : System.Text.Json.Serialization.JsonAttribute { diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.csproj b/src/libraries/System.Text.Json/ref/System.Text.Json.csproj index a42fb3c3613eac..b06efdcf9ac2ed 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);netstandard2.0;$(NetFrameworkCurrent) enable @@ -6,11 +6,11 @@ - + - + diff --git a/src/libraries/System.Text.Json/src/Resources/Strings.resx b/src/libraries/System.Text.Json/src/Resources/Strings.resx index c4dc9b09039ad1..44de8a1f85fb79 100644 --- a/src/libraries/System.Text.Json/src/Resources/Strings.resx +++ b/src/libraries/System.Text.Json/src/Resources/Strings.resx @@ -375,11 +375,11 @@ Comments cannot be stored when deserializing objects, only the Skip and Disallow comment handling modes are supported. - - Deserialization of reference types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with '{0}' is not supported. Type '{1}' + + Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with '{0}' is not supported. Type '{1}'. - Deserialization of interface types is not supported. Type '{0}' + Deserialization of interface types is not supported. Type '{0}'. The converter specified on '{0}' is not compatible with the type '{1}'. @@ -396,8 +396,8 @@ The converter '{0}' wrote too much or not enough. - - The dictionary key policy '{0}' cannot return a null key. + + The naming policy '{0}' cannot return null. The attribute '{0}' cannot exist more than once on '{1}'. @@ -506,10 +506,25 @@ Cannot allocate a buffer of size {0}. - - The type '{0}' has generic parameters that have not been replaced by specific types, which is not valid during serialization or deserialization. + + The type '{0}' is invalid for serialization or deserialization because it is a pointer type, is a ref struct, or contains generic parameters that have not been replaced by specific types. Serialization and deserialization of 'System.Type' instances are not supported and should be avoided since they can lead to security issues. - + + The non-public property '{0}' on type '{1}' is annotated with 'JsonIncludeAttribute' which is invalid. + + + The type '{0}' of property '{1}' on type '{2}' is invalid for serialization or deserialization because it is a pointer type, is a ref struct, or contains generic parameters that have not been replaced by specific types. + + + The collection type '{0}' is abstract, an interface, or is read only, and could not be instantiated and populated. + + + 'IgnoreNullValues' and 'DefaultIgnoreCondition' cannot both be set to non-default values. + + + The value cannot be 'JsonIgnoreCondition.Always'. + + \ No newline at end of file diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index 82d1d7f94b40ed..7fcf718583ae6b 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -1,26 +1,27 @@ - + true $(NetCoreAppCurrent);netstandard2.0;netcoreapp3.0;net461;$(NetFrameworkCurrent) true true - - - $(DefineConstants);BUILDING_INBOX_LIBRARY - $(NoWarn);nullable enable + + + + + $(DefineConstants);BUILDING_INBOX_LIBRARY + $(NoWarn);nullable + - - Common\System\Runtime\CompilerServices\PreserveDependencyAttribute.cs - - - Common\System\HexConverter.cs - + + @@ -53,8 +54,15 @@ - + + + + + + + + @@ -76,9 +84,12 @@ + + + @@ -99,8 +110,8 @@ - + @@ -115,31 +126,22 @@ - - - - - + - - - - - - + @@ -154,14 +156,15 @@ + - + @@ -209,12 +212,11 @@ - + - - Common\System\Buffers\ArrayBufferWriter.cs - + @@ -222,12 +224,11 @@ - - - Common\System\Collections\Generic\ReferenceEqualityComparer.cs - + + - + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.Parse.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.Parse.cs index 2c305e0d7dd81e..49770ef3f5f673 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.Parse.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.Parse.cs @@ -380,31 +380,18 @@ private static bool TryParseValue(ref Utf8JsonReader reader, [NotNullWhen(true)] { long startingOffset = reader.TokenStartIndex; - // Placeholder until reader.Skip() is written (https://github.com/dotnet/runtime/issues/27838) + if (!reader.TrySkip()) { - int depth = reader.CurrentDepth; - - // CurrentDepth rises late and falls fast, - // a payload of "[ 1, 2, 3, 4 ]" will report post-Read() - // CurrentDepth values of { 0, 1, 1, 1, 1, 0 }, - // Since we're logically at 0 ([), Read() once and keep - // reading until we've come back down to 0 (]). - do + if (shouldThrow) { - if (!reader.Read()) - { - if (shouldThrow) - { - ThrowHelper.ThrowJsonReaderException( - ref reader, - ExceptionResource.ExpectedJsonTokens); - } - - reader = restore; - document = null; - return false; - } - } while (reader.CurrentDepth > depth); + ThrowHelper.ThrowJsonReaderException( + ref reader, + ExceptionResource.ExpectedJsonTokens); + } + + reader = restore; + document = null; + return false; } long totalLength = reader.BytesConsumed - startingOffset; @@ -688,9 +675,13 @@ private static async Debug.Assert(rented.Length >= JsonConstants.Utf8Bom.Length); lastRead = await stream.ReadAsync( +#if BUILDING_INBOX_LIBRARY + rented.AsMemory(written, utf8BomLength - written), +#else rented, written, utf8BomLength - written, +#endif cancellationToken).ConfigureAwait(false); written += lastRead; @@ -715,9 +706,13 @@ private static async } lastRead = await stream.ReadAsync( +#if BUILDING_INBOX_LIBRARY + rented.AsMemory(written), +#else rented, written, rented.Length - written, +#endif cancellationToken).ConfigureAwait(false); written += lastRead; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/JsonEncodedText.cs b/src/libraries/System.Text.Json/src/System/Text/Json/JsonEncodedText.cs index 2993fac38ab548..023fa4b1342afc 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/JsonEncodedText.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/JsonEncodedText.cs @@ -32,6 +32,15 @@ private JsonEncodedText(byte[] utf8Value) _utf8Value = utf8Value; } + private JsonEncodedText(string stringValue, byte[] utf8Value) + { + Debug.Assert(stringValue != null); + Debug.Assert(utf8Value != null); + + _value = stringValue; + _utf8Value = utf8Value; + } + /// /// Encodes the string text value as a JSON string. /// @@ -125,6 +134,37 @@ private static JsonEncodedText EncodeHelper(ReadOnlySpan utf8Value, JavaSc } } + /// + /// Internal version that keeps the existing string and byte[] references if there is no escaping required. + /// + internal static JsonEncodedText Encode(string stringValue, byte[] utf8Value, JavaScriptEncoder? encoder = null) + { + Debug.Assert(stringValue.Equals(JsonHelpers.Utf8GetString(utf8Value))); + + if (utf8Value.Length == 0) + { + return new JsonEncodedText(stringValue, utf8Value); + } + + JsonWriterHelper.ValidateValue(utf8Value); + return EncodeHelper(stringValue, utf8Value, encoder); + } + + private static JsonEncodedText EncodeHelper(string stringValue, byte[] utf8Value, JavaScriptEncoder? encoder) + { + int idx = JsonWriterHelper.NeedsEscaping(utf8Value, encoder); + + if (idx != -1) + { + return new JsonEncodedText(GetEscapedString(utf8Value, idx, encoder)); + } + else + { + // Encoding is not necessary; use the same stringValue and utf8Value references. + return new JsonEncodedText(stringValue, utf8Value); + } + } + private static byte[] GetEscapedString(ReadOnlySpan utf8Value, int firstEscapeIndexVal, JavaScriptEncoder? encoder) { Debug.Assert(int.MaxValue / JsonConstants.MaxExpansionFactorWhileEscaping >= utf8Value.Length); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonAttribute.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonAttribute.cs similarity index 100% rename from src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonAttribute.cs rename to src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonAttribute.cs diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConstructorAttribute.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonConstructorAttribute.cs similarity index 100% rename from src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConstructorAttribute.cs rename to src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonConstructorAttribute.cs diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterAttribute.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonConverterAttribute.cs similarity index 100% rename from src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterAttribute.cs rename to src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonConverterAttribute.cs diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonExtensionDataAttribute.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonExtensionDataAttribute.cs similarity index 100% rename from src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonExtensionDataAttribute.cs rename to src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonExtensionDataAttribute.cs diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonIgnoreAttribute.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonIgnoreAttribute.cs similarity index 100% rename from src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonIgnoreAttribute.cs rename to src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonIgnoreAttribute.cs diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonIncludeAttribute.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonIncludeAttribute.cs new file mode 100644 index 00000000000000..0e1727d683a56e --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonIncludeAttribute.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Text.Json.Serialization +{ + /// + /// Indicates that the member should be included for serialization and deserialization. + /// + /// + /// When applied to a property, indicates that non-public getters and setters can be used for serialization and deserialization. + /// + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] + public sealed class JsonIncludeAttribute : JsonAttribute + { + /// + /// Initializes a new instance of . + /// + public JsonIncludeAttribute() { } + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyNameAttribute.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonPropertyNameAttribute.cs similarity index 100% rename from src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyNameAttribute.cs rename to src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Attributes/JsonPropertyNameAttribute.cs diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ArrayConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ArrayConverter.cs index 67b5fd417aa14b..70d0c611dd5ba3 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ArrayConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ArrayConverter.cs @@ -4,7 +4,6 @@ using System.Collections; using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -19,25 +18,22 @@ internal sealed class ArrayConverter protected override void Add(TElement value, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is List); ((List)state.Current.ReturnValue!).Add(value); } - protected override void CreateCollection(ref ReadStack state, JsonSerializerOptions options) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { state.Current.ReturnValue = new List(); } protected override void ConvertCollection(ref ReadStack state, JsonSerializerOptions options) { - Debug.Assert(state.Current.ReturnValue is List); List list = (List)state.Current.ReturnValue!; state.Current.ReturnValue = list.ToArray(); } protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, ref WriteStack state) { - Debug.Assert(value is TElement[]); TElement[] array = (TElement[])(IEnumerable)value; int index = state.Current.EnumeratorIndex; @@ -48,8 +44,7 @@ protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, // Fast path that avoids validation and extra indirection. for (; index < array.Length; index++) { - // TODO: https://github.com/dotnet/runtime/issues/32523 - elementConverter.Write(writer, array[index]!, options); + elementConverter.Write(writer, array[index], options); } } else diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ConcurrentQueueOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ConcurrentQueueOfTConverter.cs index f6673fb23c580e..aa54f0956e41e5 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ConcurrentQueueOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ConcurrentQueueOfTConverter.cs @@ -4,7 +4,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -14,11 +13,10 @@ internal sealed class ConcurrentQueueOfTConverter { protected override void Add(TElement value, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is TCollection); ((TCollection)state.Current.ReturnValue!).Enqueue(value); } - protected override void CreateCollection(ref ReadStack state, JsonSerializerOptions options) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { if (state.Current.JsonClassInfo.CreateObject == null) { @@ -41,7 +39,6 @@ protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, } else { - Debug.Assert(state.Current.CollectionEnumerator is IEnumerator); enumerator = (IEnumerator)state.Current.CollectionEnumerator; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ConcurrentStackOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ConcurrentStackOfTConverter.cs index c7b173dd158666..9ba01b68df2ddf 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ConcurrentStackOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ConcurrentStackOfTConverter.cs @@ -4,7 +4,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -14,11 +13,10 @@ internal sealed class ConcurrentStackOfTConverter { protected override void Add(TElement value, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is TCollection); ((TCollection)state.Current.ReturnValue!).Push(value); } - protected override void CreateCollection(ref ReadStack state, JsonSerializerOptions options) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { if (state.Current.JsonClassInfo.CreateObject == null) { @@ -41,7 +39,6 @@ protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, } else { - Debug.Assert(state.Current.CollectionEnumerator is IEnumerator); enumerator = (IEnumerator)state.Current.CollectionEnumerator; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/DictionaryDefaultConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/DictionaryDefaultConverter.cs index fe842d4d4582ef..4603b59c82f960 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/DictionaryDefaultConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/DictionaryDefaultConverter.cs @@ -27,7 +27,7 @@ protected virtual void ConvertCollection(ref ReadStack state, JsonSerializerOpti /// /// When overridden, create the collection. It may be a temporary collection or the final collection. /// - protected virtual void CreateCollection(ref ReadStack state) { } + protected virtual void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state) { } internal override Type ElementType => typeof(TValue); @@ -47,7 +47,7 @@ protected string GetKeyName(string key, ref WriteStack state, JsonSerializerOpti if (key == null) { - ThrowHelper.ThrowInvalidOperationException_SerializerDictionaryKeyNull(options.DictionaryKeyPolicy.GetType()); + ThrowHelper.ThrowInvalidOperationException_NamingPolicyReturnNull(options.DictionaryKeyPolicy); } } @@ -80,7 +80,7 @@ internal sealed override bool OnTryRead( ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); } - CreateCollection(ref state); + CreateCollection(ref reader, ref state); JsonConverter elementConverter = GetElementConverter(ref state); if (elementConverter.CanUseDirectReadOrWrite) @@ -96,17 +96,15 @@ internal sealed override bool OnTryRead( break; } - if (reader.TokenType != JsonTokenType.PropertyName) - { - ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); - } + // Read method would have thrown if otherwise. + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); state.Current.JsonPropertyNameAsString = reader.GetString(); // Read the value and add. reader.ReadWithVerify(); TValue element = elementConverter.Read(ref reader, typeof(TValue), options); - Add(element, options, ref state); + Add(element!, options, ref state); } } else @@ -122,10 +120,8 @@ internal sealed override bool OnTryRead( break; } - if (reader.TokenType != JsonTokenType.PropertyName) - { - ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); - } + // Read method would have thrown if otherwise. + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); state.Current.JsonPropertyNameAsString = reader.GetString(); @@ -133,7 +129,7 @@ internal sealed override bool OnTryRead( // Get the value from the converter and add it. elementConverter.TryRead(ref reader, typeof(TValue), options, ref state, out TValue element); - Add(element, options, ref state); + Add(element!, options, ref state); } } } @@ -152,11 +148,11 @@ internal sealed override bool OnTryRead( } // Handle the metadata properties. - if (shouldReadPreservedReferences && state.Current.ObjectState < StackFrameObjectState.MetadataPropertyValue) + if (shouldReadPreservedReferences && state.Current.ObjectState < StackFrameObjectState.PropertyValue) { if (JsonSerializer.ResolveMetadata(this, ref reader, ref state)) { - if (state.Current.ObjectState == StackFrameObjectState.MetadataRefPropertyEndObject) + if (state.Current.ObjectState == StackFrameObjectState.ReadRefEndObject) { value = (TCollection)state.Current.ReturnValue!; return true; @@ -172,7 +168,7 @@ internal sealed override bool OnTryRead( // Create the dictionary. if (state.Current.ObjectState < StackFrameObjectState.CreatedObject) { - CreateCollection(ref state); + CreateCollection(ref reader, ref state); if (state.Current.MetadataId != null) { @@ -212,10 +208,8 @@ internal sealed override bool OnTryRead( break; } - if (reader.TokenType != JsonTokenType.PropertyName) - { - ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); - } + // Read method would have thrown if otherwise. + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); state.Current.PropertyState = StackFramePropertyState.Name; @@ -253,7 +247,7 @@ internal sealed override bool OnTryRead( return false; } - Add(element, options, ref state); + Add(element!, options, ref state); state.Current.EndElement(); } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/DictionaryOfStringTValueConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/DictionaryOfStringTValueConverter.cs index 19c781187e1055..14ecb4526999cc 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/DictionaryOfStringTValueConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/DictionaryOfStringTValueConverter.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -17,13 +16,11 @@ internal sealed class DictionaryOfStringTValueConverter { protected override void Add(TValue value, JsonSerializerOptions options, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is TCollection); - string key = state.Current.JsonPropertyNameAsString!; ((TCollection)state.Current.ReturnValue!)[key] = value; } - protected override void CreateCollection(ref ReadStack state) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state) { if (state.Current.JsonClassInfo.CreateObject == null) { @@ -50,7 +47,6 @@ protected internal override bool OnWriteResume( } else { - Debug.Assert(state.Current.CollectionEnumerator is Dictionary.Enumerator); enumerator = (Dictionary.Enumerator)state.Current.CollectionEnumerator; } @@ -62,8 +58,7 @@ protected internal override bool OnWriteResume( { string key = GetKeyName(enumerator.Current.Key, ref state, options); writer.WritePropertyName(key); - // TODO: https://github.com/dotnet/runtime/issues/32523 - converter.Write(writer, enumerator.Current.Value!, options); + converter.Write(writer, enumerator.Current.Value, options); } while (enumerator.MoveNext()); } else @@ -76,7 +71,6 @@ protected internal override bool OnWriteResume( return false; } - TValue element = enumerator.Current.Value; if (state.Current.PropertyState < StackFramePropertyState.Name) { state.Current.PropertyState = StackFramePropertyState.Name; @@ -84,6 +78,7 @@ protected internal override bool OnWriteResume( writer.WritePropertyName(key); } + TValue element = enumerator.Current.Value; if (!converter.TryWrite(writer, element, options, ref state)) { state.Current.CollectionEnumerator = enumerator; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ICollectionOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ICollectionOfTConverter.cs index 7fb4f32449d584..cb1b66ac18371f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ICollectionOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ICollectionOfTConverter.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -16,11 +15,10 @@ internal sealed class ICollectionOfTConverter { protected override void Add(TElement value, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is ICollection); ((ICollection)state.Current.ReturnValue!).Add(value); } - protected override void CreateCollection(ref ReadStack state, JsonSerializerOptions options) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { JsonClassInfo classInfo = state.Current.JsonClassInfo; @@ -28,7 +26,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = new List(); @@ -37,14 +35,14 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (classInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(TypeToConvert, ref reader, ref state); } TCollection returnValue = (TCollection)classInfo.CreateObject()!; if (returnValue.IsReadOnly) { - ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = returnValue; @@ -68,7 +66,6 @@ protected override bool OnWriteResume( } else { - Debug.Assert(state.Current.CollectionEnumerator is IEnumerator); enumerator = (IEnumerator)state.Current.CollectionEnumerator; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryConverter.cs index 6bc612fdf1af38..6ef56753427f4e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryConverter.cs @@ -4,7 +4,6 @@ using System.Collections; using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -18,13 +17,11 @@ internal sealed class IDictionaryConverter { protected override void Add(object? value, JsonSerializerOptions options, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is IDictionary); - string key = state.Current.JsonPropertyNameAsString!; ((IDictionary)state.Current.ReturnValue!)[key] = value; } - protected override void CreateCollection(ref ReadStack state) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state) { JsonClassInfo classInfo = state.Current.JsonClassInfo; @@ -32,7 +29,7 @@ protected override void CreateCollection(ref ReadStack state) { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = new Dictionary(); @@ -41,14 +38,14 @@ protected override void CreateCollection(ref ReadStack state) { if (classInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(TypeToConvert, ref reader, ref state); } TCollection returnValue = (TCollection)classInfo.CreateObject()!; if (returnValue.IsReadOnly) { - ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = returnValue; @@ -68,31 +65,41 @@ protected internal override bool OnWriteResume(Utf8JsonWriter writer, TCollectio } else { - Debug.Assert(state.Current.CollectionEnumerator is IDictionaryEnumerator); enumerator = (IDictionaryEnumerator)state.Current.CollectionEnumerator; } JsonConverter converter = GetValueConverter(ref state); do { - if (enumerator.Key is string key) + if (ShouldFlush(writer, ref state)) { - key = GetKeyName(key, ref state, options); - writer.WritePropertyName(key); + state.Current.CollectionEnumerator = enumerator; + return false; + } - object? element = enumerator.Value; - if (!converter.TryWrite(writer, element, options, ref state)) + if (state.Current.PropertyState < StackFramePropertyState.Name) + { + state.Current.PropertyState = StackFramePropertyState.Name; + + if (enumerator.Key is string key) { - state.Current.CollectionEnumerator = enumerator; - return false; + key = GetKeyName(key, ref state, options); + writer.WritePropertyName(key); + } + else + { + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.DeclaredJsonPropertyInfo!.RuntimePropertyType!); } - - state.Current.EndDictionaryElement(); } - else + + object? element = enumerator.Value; + if (!converter.TryWrite(writer, element, options, ref state)) { - ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.DeclaredJsonPropertyInfo!.RuntimePropertyType!); + state.Current.CollectionEnumerator = enumerator; + return false; } + + state.Current.EndDictionaryElement(); } while (enumerator.MoveNext()); return true; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryOfStringTValueConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryOfStringTValueConverter.cs index 63c329e1ed3de1..6115fada07decf 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryOfStringTValueConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IDictionaryOfStringTValueConverter.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -17,13 +16,11 @@ internal sealed class IDictionaryOfStringTValueConverter { protected override void Add(TValue value, JsonSerializerOptions options, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is TCollection); - string key = state.Current.JsonPropertyNameAsString!; ((TCollection)state.Current.ReturnValue!)[key] = value; } - protected override void CreateCollection(ref ReadStack state) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state) { JsonClassInfo classInfo = state.Current.JsonClassInfo; @@ -31,7 +28,7 @@ protected override void CreateCollection(ref ReadStack state) { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = new Dictionary(); @@ -40,14 +37,14 @@ protected override void CreateCollection(ref ReadStack state) { if (classInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(TypeToConvert, ref reader, ref state); } TCollection returnValue = (TCollection)classInfo.CreateObject()!; if (returnValue.IsReadOnly) { - ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = returnValue; @@ -71,7 +68,6 @@ protected internal override bool OnWriteResume( } else { - Debug.Assert(state.Current.CollectionEnumerator is IEnumerator>); enumerator = (IEnumerator>)state.Current.CollectionEnumerator; } @@ -84,8 +80,12 @@ protected internal override bool OnWriteResume( return false; } - string key = GetKeyName(enumerator.Current.Key, ref state, options); - writer.WritePropertyName(key); + if (state.Current.PropertyState < StackFramePropertyState.Name) + { + state.Current.PropertyState = StackFramePropertyState.Name; + string key = GetKeyName(enumerator.Current.Key, ref state, options); + writer.WritePropertyName(key); + } TValue element = enumerator.Current.Value; if (!converter.TryWrite(writer, element, options, ref state)) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverter.cs index 72db89fa02c950..52da1f4e0d0e5f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverter.cs @@ -4,7 +4,6 @@ using System.Collections; using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -18,15 +17,14 @@ internal sealed class IEnumerableConverter { protected override void Add(object? value, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is List); ((List)state.Current.ReturnValue!).Add(value); } - protected override void CreateCollection(ref ReadStack state, JsonSerializerOptions options) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = new List(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactory.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactory.cs index 27214b3c10a2b7..1a58ed83cda94e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactory.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactory.cs @@ -28,7 +28,6 @@ public override bool CanConvert(Type typeToConvert) [PreserveDependency(".ctor", "System.Text.Json.Serialization.Converters.ArrayConverter`2")] [PreserveDependency(".ctor", "System.Text.Json.Serialization.Converters.ConcurrentQueueOfTConverter`2")] [PreserveDependency(".ctor", "System.Text.Json.Serialization.Converters.ConcurrentStackOfTConverter`2")] - [PreserveDependency(".ctor", "System.Text.Json.Serialization.Converters.DefaultArrayConverter`2")] [PreserveDependency(".ctor", "System.Text.Json.Serialization.Converters.DictionaryOfStringTValueConverter`2")] [PreserveDependency(".ctor", "System.Text.Json.Serialization.Converters.ICollectionOfTConverter`2")] [PreserveDependency(".ctor", "System.Text.Json.Serialization.Converters.IDictionaryOfStringTValueConverter`2")] diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableDefaultConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableDefaultConverter.cs index b76f08f2ae4fac..6803e9d58454fc 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableDefaultConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableDefaultConverter.cs @@ -14,7 +14,7 @@ internal abstract class IEnumerableDefaultConverter : JsonCollectionConverter { protected abstract void Add(TElement value, ref ReadStack state); - protected abstract void CreateCollection(ref ReadStack state, JsonSerializerOptions options); + protected abstract void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options); protected virtual void ConvertCollection(ref ReadStack state, JsonSerializerOptions options) { } protected static JsonConverter GetElementConverter(ref ReadStack state) @@ -51,7 +51,7 @@ internal override bool OnTryRead( ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); } - CreateCollection(ref state, options); + CreateCollection(ref reader, ref state, options); JsonConverter elementConverter = GetElementConverter(ref state); if (elementConverter.CanUseDirectReadOrWrite) @@ -67,7 +67,7 @@ internal override bool OnTryRead( // Obtain the CLR value from the JSON and apply to the object. TElement element = elementConverter.Read(ref reader, elementConverter.TypeToConvert, options); - Add(element, ref state); + Add(element!, ref state); } } else @@ -83,7 +83,7 @@ internal override bool OnTryRead( // Get the value from the converter and add it. elementConverter.TryRead(ref reader, typeof(TElement), options, ref state, out TElement element); - Add(element, ref state); + Add(element!, ref state); } } } @@ -95,7 +95,7 @@ internal override bool OnTryRead( { if (reader.TokenType == JsonTokenType.StartArray) { - state.Current.ObjectState = StackFrameObjectState.MetadataPropertyValue; + state.Current.ObjectState = StackFrameObjectState.PropertyValue; } else if (shouldReadPreservedReferences) { @@ -113,11 +113,11 @@ internal override bool OnTryRead( } // Handle the metadata properties. - if (shouldReadPreservedReferences && state.Current.ObjectState < StackFrameObjectState.MetadataPropertyValue) + if (shouldReadPreservedReferences && state.Current.ObjectState < StackFrameObjectState.PropertyValue) { if (JsonSerializer.ResolveMetadata(this, ref reader, ref state)) { - if (state.Current.ObjectState == StackFrameObjectState.MetadataRefPropertyEndObject) + if (state.Current.ObjectState == StackFrameObjectState.ReadRefEndObject) { value = (TCollection)state.Current.ReturnValue!; return true; @@ -132,7 +132,7 @@ internal override bool OnTryRead( if (state.Current.ObjectState < StackFrameObjectState.CreatedObject) { - CreateCollection(ref state, options); + CreateCollection(ref reader, ref state, options); if (state.Current.MetadataId != null) { @@ -184,7 +184,7 @@ internal override bool OnTryRead( return false; } - Add(element, ref state); + Add(element!, ref state); // No need to set PropertyState to TryRead since we're done with this element now. state.Current.EndElement(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableOfTConverter.cs index 8dd71331bdb6e6..26e83873ec24dd 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableOfTConverter.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Reflection; namespace System.Text.Json.Serialization.Converters { @@ -17,15 +16,14 @@ internal sealed class IEnumerableOfTConverter { protected override void Add(TElement value, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is List); ((List)state.Current.ReturnValue!).Add(value); } - protected override void CreateCollection(ref ReadStack state, JsonSerializerOptions options) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = new List(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableWithAddMethodConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableWithAddMethodConverter.cs index cff243c13fbea3..b3121146d449f4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableWithAddMethodConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableWithAddMethodConverter.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -13,18 +12,16 @@ internal sealed class IEnumerableWithAddMethodConverter { protected override void Add(object? value, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is TCollection); - Debug.Assert(state.Current.AddMethodDelegate != null); - ((Action)state.Current.AddMethodDelegate)((TCollection)state.Current.ReturnValue!, value); + ((Action)state.Current.AddMethodDelegate!)((TCollection)state.Current.ReturnValue!, value); } - protected override void CreateCollection(ref ReadStack state, JsonSerializerOptions options) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { JsonClassInfo.ConstructorDelegate? constructorDelegate = state.Current.JsonClassInfo.CreateObject; if (constructorDelegate == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = constructorDelegate(); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListConverter.cs index cee12dc48df44e..b9131d7a2cfc2e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListConverter.cs @@ -4,7 +4,6 @@ using System.Collections; using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -15,11 +14,10 @@ internal sealed class IListConverter { protected override void Add(object? value, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is IList); - ((IList)state.Current.ReturnValue).Add(value); + ((IList)state.Current.ReturnValue!).Add(value); } - protected override void CreateCollection(ref ReadStack state, JsonSerializerOptions options) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { JsonClassInfo classInfo = state.Current.JsonClassInfo; @@ -27,7 +25,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = new List(); @@ -36,14 +34,14 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (classInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(TypeToConvert, ref reader, ref state); } TCollection returnValue = (TCollection)classInfo.CreateObject()!; if (returnValue.IsReadOnly) { - ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = returnValue; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListOfTConverter.cs index fa61b4abd88147..c349280bbb4e4e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IListOfTConverter.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -16,11 +15,10 @@ internal sealed class IListOfTConverter { protected override void Add(TElement value, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is TCollection); ((TCollection)state.Current.ReturnValue!).Add(value); } - protected override void CreateCollection(ref ReadStack state, JsonSerializerOptions options) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { JsonClassInfo classInfo = state.Current.JsonClassInfo; @@ -28,7 +26,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = new List(); @@ -37,14 +35,14 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (classInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(TypeToConvert, ref reader, ref state); } TCollection returnValue = (TCollection)classInfo.CreateObject()!; if (returnValue.IsReadOnly) { - ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = returnValue; @@ -64,7 +62,6 @@ protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, } else { - Debug.Assert(state.Current.CollectionEnumerator is IEnumerator); enumerator = (IEnumerator)state.Current.CollectionEnumerator; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IReadOnlyDictionaryOfStringTValueConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IReadOnlyDictionaryOfStringTValueConverter.cs index 0517525343c5fb..a4552cba9a2713 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IReadOnlyDictionaryOfStringTValueConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IReadOnlyDictionaryOfStringTValueConverter.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -13,17 +12,15 @@ internal sealed class IReadOnlyDictionaryOfStringTValueConverter); - string key = state.Current.JsonPropertyNameAsString!; ((Dictionary)state.Current.ReturnValue!)[key] = value; } - protected override void CreateCollection(ref ReadStack state) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state) { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = new Dictionary(); @@ -42,7 +39,6 @@ protected internal override bool OnWriteResume(Utf8JsonWriter writer, TCollectio } else { - Debug.Assert(state.Current.CollectionEnumerator is Dictionary.Enumerator); enumerator = (Dictionary.Enumerator)state.Current.CollectionEnumerator; } @@ -55,8 +51,12 @@ protected internal override bool OnWriteResume(Utf8JsonWriter writer, TCollectio return false; } - string key = GetKeyName(enumerator.Current.Key, ref state, options); - writer.WritePropertyName(key); + if (state.Current.PropertyState < StackFramePropertyState.Name) + { + state.Current.PropertyState = StackFramePropertyState.Name; + string key = GetKeyName(enumerator.Current.Key, ref state, options); + writer.WritePropertyName(key); + } TValue element = enumerator.Current.Value; if (!converter.TryWrite(writer, element, options, ref state)) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ISetOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ISetOfTConverter.cs index f0fcd783e04f6c..29645584b3536d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ISetOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ISetOfTConverter.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -13,11 +12,10 @@ internal sealed class ISetOfTConverter { protected override void Add(TElement value, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is TCollection); ((TCollection)state.Current.ReturnValue!).Add(value); } - protected override void CreateCollection(ref ReadStack state, JsonSerializerOptions options) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { JsonClassInfo classInfo = state.Current.JsonClassInfo; @@ -25,7 +23,7 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (!TypeToConvert.IsAssignableFrom(RuntimeType)) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = new HashSet(); @@ -34,14 +32,14 @@ protected override void CreateCollection(ref ReadStack state, JsonSerializerOpti { if (classInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(TypeToConvert, ref reader, ref state); } TCollection returnValue = (TCollection)classInfo.CreateObject()!; if (returnValue.IsReadOnly) { - ThrowHelper.ThrowNotSupportedException_SerializationNotSupported(TypeToConvert); + ThrowHelper.ThrowNotSupportedException_CannotPopulateCollection(TypeToConvert, ref reader, ref state); } state.Current.ReturnValue = returnValue; @@ -61,7 +59,6 @@ protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, } else { - Debug.Assert(state.Current.CollectionEnumerator is IEnumerator); enumerator = (IEnumerator)state.Current.CollectionEnumerator; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableDictionaryOfStringTValueConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableDictionaryOfStringTValueConverter.cs index 145b304eb2b5bc..9cde8e4233f283 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableDictionaryOfStringTValueConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableDictionaryOfStringTValueConverter.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -13,22 +12,29 @@ internal sealed class ImmutableDictionaryOfStringTValueConverter); - string key = state.Current.JsonPropertyNameAsString!; ((Dictionary)state.Current.ReturnValue!)[key] = value; } internal override bool CanHaveIdMetadata => false; - protected override void CreateCollection(ref ReadStack state) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state) { state.Current.ReturnValue = new Dictionary(); } protected override void ConvertCollection(ref ReadStack state, JsonSerializerOptions options) { - state.Current.ReturnValue = GetCreatorDelegate(options)((Dictionary)state.Current.ReturnValue!); + JsonClassInfo classInfo = state.Current.JsonClassInfo; + + Func>, TCollection>? creator = (Func>, TCollection>?)classInfo.CreateObjectWithArgs; + if (creator == null) + { + creator = options.MemberAccessorStrategy.CreateImmutableDictionaryCreateRangeDelegate(); + classInfo.CreateObjectWithArgs = creator; + } + + state.Current.ReturnValue = creator((Dictionary)state.Current.ReturnValue!); } protected internal override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, ref WriteStack state) @@ -44,8 +50,7 @@ protected internal override bool OnWriteResume(Utf8JsonWriter writer, TCollectio } else { - Debug.Assert(state.Current.CollectionEnumerator is Dictionary.Enumerator); - enumerator = (Dictionary.Enumerator)state.Current.CollectionEnumerator; + enumerator = (IEnumerator>)state.Current.CollectionEnumerator; } JsonConverter converter = GetValueConverter(ref state); @@ -57,8 +62,12 @@ protected internal override bool OnWriteResume(Utf8JsonWriter writer, TCollectio return false; } - string key = GetKeyName(enumerator.Current.Key, ref state, options); - writer.WritePropertyName(key); + if (state.Current.PropertyState < StackFramePropertyState.Name) + { + state.Current.PropertyState = StackFramePropertyState.Name; + string key = GetKeyName(enumerator.Current.Key, ref state, options); + writer.WritePropertyName(key); + } TValue element = enumerator.Current.Value; if (!converter.TryWrite(writer, element, options, ref state)) @@ -72,17 +81,5 @@ protected internal override bool OnWriteResume(Utf8JsonWriter writer, TCollectio return true; } - - private Func>, TCollection>? _creatorDelegate; - - private Func>, TCollection> GetCreatorDelegate(JsonSerializerOptions options) - { - if (_creatorDelegate == null) - { - _creatorDelegate = options.MemberAccessorStrategy.CreateImmutableDictionaryCreateRangeDelegate(); - } - - return _creatorDelegate; - } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableEnumerableOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableEnumerableOfTConverter.cs index 70438a939e1209..cfa1f0bf3d60f4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableEnumerableOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableEnumerableOfTConverter.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -13,20 +12,28 @@ internal sealed class ImmutableEnumerableOfTConverter { protected override void Add(TElement value, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is List); ((List)state.Current.ReturnValue!).Add(value); } internal override bool CanHaveIdMetadata => false; - protected override void CreateCollection(ref ReadStack state, JsonSerializerOptions options) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { state.Current.ReturnValue = new List(); } protected override void ConvertCollection(ref ReadStack state, JsonSerializerOptions options) { - state.Current.ReturnValue = GetCreatorDelegate(options)((List)state.Current.ReturnValue!); + JsonClassInfo classInfo = state.Current.JsonClassInfo; + + Func, TCollection>? creator = (Func, TCollection>?)classInfo.CreateObjectWithArgs; + if (creator == null) + { + creator = options.MemberAccessorStrategy.CreateImmutableEnumerableCreateRangeDelegate(); + classInfo.CreateObjectWithArgs = creator; + } + + state.Current.ReturnValue = creator((List)state.Current.ReturnValue!); } protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, ref WriteStack state) @@ -42,7 +49,6 @@ protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, } else { - Debug.Assert(state.Current.CollectionEnumerator is IEnumerator); enumerator = (IEnumerator)state.Current.CollectionEnumerator; } @@ -65,17 +71,5 @@ protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, return true; } - - private Func, TCollection>? _creatorDelegate; - - private Func, TCollection> GetCreatorDelegate(JsonSerializerOptions options) - { - if (_creatorDelegate == null) - { - _creatorDelegate = options.MemberAccessorStrategy.CreateImmutableEnumerableCreateRangeDelegate(); - } - - return _creatorDelegate; - } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonCollectionConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/JsonCollectionConverter.cs similarity index 100% rename from src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonCollectionConverter.cs rename to src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/JsonCollectionConverter.cs diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonDictionaryConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/JsonDictionaryConverter.cs similarity index 100% rename from src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonDictionaryConverter.cs rename to src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/JsonDictionaryConverter.cs diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ListOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ListOfTConverter.cs index d5531435d8abe5..a977fededc3ae6 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ListOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ListOfTConverter.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -14,11 +13,10 @@ internal sealed class ListOfTConverter { protected override void Add(TElement value, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is TCollection); ((TCollection)state.Current.ReturnValue!).Add(value); } - protected override void CreateCollection(ref ReadStack state, JsonSerializerOptions options) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { if (state.Current.JsonClassInfo.CreateObject == null) { @@ -41,8 +39,7 @@ protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, // Fast path that avoids validation and extra indirection. for (; index < list.Count; index++) { - // TODO: https://github.com/dotnet/runtime/issues/32523 - elementConverter.Write(writer, list[index]!, options); + elementConverter.Write(writer, list[index], options); } } else diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/QueueOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/QueueOfTConverter.cs index 64feb599be5523..dfea6e14808441 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/QueueOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/QueueOfTConverter.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -13,11 +12,10 @@ internal sealed class QueueOfTConverter { protected override void Add(TElement value, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is TCollection); ((TCollection)state.Current.ReturnValue!).Enqueue(value); } - protected override void CreateCollection(ref ReadStack state, JsonSerializerOptions options) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { if (state.Current.JsonClassInfo.CreateObject == null) { @@ -40,7 +38,6 @@ protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, } else { - Debug.Assert(state.Current.CollectionEnumerator is IEnumerator); enumerator = (IEnumerator)state.Current.CollectionEnumerator; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/StackOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/StackOfTConverter.cs index dc3502de0d4989..5725e7f1a04f47 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/StackOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/StackOfTConverter.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics; namespace System.Text.Json.Serialization.Converters { @@ -13,11 +12,10 @@ internal sealed class StackOfTConverter { protected override void Add(TElement value, ref ReadStack state) { - Debug.Assert(state.Current.ReturnValue is TCollection); ((TCollection)state.Current.ReturnValue!).Push(value); } - protected override void CreateCollection(ref ReadStack state, JsonSerializerOptions options) + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { if (state.Current.JsonClassInfo.CreateObject == null) { @@ -40,7 +38,6 @@ protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, } else { - Debug.Assert(state.Current.CollectionEnumerator is IEnumerator); enumerator = (IEnumerator)state.Current.CollectionEnumerator; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonObjectConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/JsonObjectConverter.cs similarity index 100% rename from src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonObjectConverter.cs rename to src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/JsonObjectConverter.cs diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs index 640088d64e2bb6..10327bc0438b28 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectDefaultConverter.cs @@ -28,7 +28,7 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, if (state.Current.JsonClassInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(state.Current.JsonClassInfo.Type); + ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(state.Current.JsonClassInfo.Type, ref reader, ref state); } obj = state.Current.JsonClassInfo.CreateObject!()!; @@ -74,13 +74,13 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, } // Handle the metadata properties. - if (state.Current.ObjectState < StackFrameObjectState.MetadataPropertyValue) + if (state.Current.ObjectState < StackFrameObjectState.PropertyValue) { if (shouldReadPreservedReferences) { if (JsonSerializer.ResolveMetadata(this, ref reader, ref state)) { - if (state.Current.ObjectState == StackFrameObjectState.MetadataRefPropertyEndObject) + if (state.Current.ObjectState == StackFrameObjectState.ReadRefEndObject) { value = (T)state.Current.ReturnValue!; return true; @@ -93,14 +93,14 @@ internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, } } - state.Current.ObjectState = StackFrameObjectState.MetadataPropertyValue; + state.Current.ObjectState = StackFrameObjectState.PropertyValue; } if (state.Current.ObjectState < StackFrameObjectState.CreatedObject) { if (state.Current.JsonClassInfo.CreateObject == null) { - ThrowHelper.ThrowNotSupportedException_DeserializeNoDeserializationConstructor(state.Current.JsonClassInfo.Type); + ThrowHelper.ThrowNotSupportedException_DeserializeNoConstructor(state.Current.JsonClassInfo.Type, ref reader, ref state); } obj = state.Current.JsonClassInfo.CreateObject!()!; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.Large.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.Large.cs index 7444bd28ecb2ca..a89d1910c365b1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.Large.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.Large.cs @@ -14,11 +14,11 @@ internal sealed class LargeObjectWithParameterizedConstructorConverter : Obje { protected override bool ReadAndCacheConstructorArgument(ref ReadStack state, ref Utf8JsonReader reader, JsonParameterInfo jsonParameterInfo) { - bool success = jsonParameterInfo.ReadJson(ref state, ref reader, out object? arg0); + bool success = jsonParameterInfo.ReadJson(ref state, ref reader, out object? arg); if (success) { - ((object[])state.Current.CtorArgumentState!.Arguments)[jsonParameterInfo.Position] = arg0!; + ((object[])state.Current.CtorArgumentState!.Arguments)[jsonParameterInfo.Position] = arg!; } return success; @@ -28,7 +28,7 @@ protected override object CreateObject(ref ReadStackFrame frame) { object[] arguments = (object[])frame.CtorArgumentState!.Arguments; - var createObject = (JsonClassInfo.ParameterizedConstructorDelegate?)frame.JsonClassInfo.CreateObjectWithParameterizedCtor; + var createObject = (JsonClassInfo.ParameterizedConstructorDelegate?)frame.JsonClassInfo.CreateObjectWithArgs; if (createObject == null) { @@ -46,9 +46,9 @@ protected override void InitializeConstructorArgumentCaches(ref ReadStack state, { JsonClassInfo classInfo = state.Current.JsonClassInfo; - if (classInfo.CreateObjectWithParameterizedCtor == null) + if (classInfo.CreateObjectWithArgs == null) { - classInfo.CreateObjectWithParameterizedCtor = options.MemberAccessorStrategy.CreateParameterizedConstructor(ConstructorInfo!); + classInfo.CreateObjectWithArgs = options.MemberAccessorStrategy.CreateParameterizedConstructor(ConstructorInfo!); } object[] arguments = ArrayPool.Shared.Rent(classInfo.ParameterCount); diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.Small.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.Small.cs index 97ed0414b0fc2f..1e98384d117c64 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.Small.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.Small.cs @@ -15,7 +15,7 @@ internal sealed class SmallObjectWithParameterizedConstructorConverter) - frame.JsonClassInfo.CreateObjectWithParameterizedCtor!; + frame.JsonClassInfo.CreateObjectWithArgs!; var arguments = (Arguments)frame.CtorArgumentState!.Arguments; return createObject!(arguments.Arg0, arguments.Arg1, arguments.Arg2, arguments.Arg3); } @@ -33,32 +33,32 @@ protected override bool ReadAndCacheConstructorArgument(ref ReadStack state, ref success = ((JsonParameterInfo)jsonParameterInfo).ReadJsonTyped(ref state, ref reader, out TArg0 arg0); if (success) { - arguments.Arg0 = arg0; + arguments.Arg0 = arg0!; } break; case 1: success = ((JsonParameterInfo)jsonParameterInfo).ReadJsonTyped(ref state, ref reader, out TArg1 arg1); if (success) { - arguments.Arg1 = arg1; + arguments.Arg1 = arg1!; } break; case 2: success = ((JsonParameterInfo)jsonParameterInfo).ReadJsonTyped(ref state, ref reader, out TArg2 arg2); if (success) { - arguments.Arg2 = arg2; + arguments.Arg2 = arg2!; } break; case 3: success = ((JsonParameterInfo)jsonParameterInfo).ReadJsonTyped(ref state, ref reader, out TArg3 arg3); if (success) { - arguments.Arg3 = arg3; + arguments.Arg3 = arg3!; } break; default: - Debug.Fail("This should never happen."); + Debug.Fail("More than 4 params: we should be in override for LargeObjectWithParameterizedConstructorConverter."); throw new InvalidOperationException(); } @@ -69,9 +69,9 @@ protected override void InitializeConstructorArgumentCaches(ref ReadStack state, { JsonClassInfo classInfo = state.Current.JsonClassInfo; - if (classInfo.CreateObjectWithParameterizedCtor == null) + if (classInfo.CreateObjectWithArgs == null) { - classInfo.CreateObjectWithParameterizedCtor = + classInfo.CreateObjectWithArgs = options.MemberAccessorStrategy.CreateParameterizedConstructor(ConstructorInfo!); } @@ -98,8 +98,8 @@ protected override void InitializeConstructorArgumentCaches(ref ReadStack state, arguments.Arg3 = ((JsonParameterInfo)parameterInfo).TypedDefaultValue!; break; default: - Debug.Fail("We should never get here."); - break; + Debug.Fail("More than 4 params: we should be in override for LargeObjectWithParameterizedConstructorConverter."); + throw new InvalidOperationException(); } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.cs index 751361d55ef0f7..54e49b3d5dba2c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/ObjectWithParameterizedConstructorConverter.cs @@ -26,7 +26,7 @@ internal sealed override bool OnTryRead(ref Utf8JsonReader reader, Type typeToCo if (!state.SupportContinuation && !shouldReadPreservedReferences) { - // Fast path that avoids maintaining state variables and dealing with preserved references. + // Fast path that avoids maintaining state variables. ReadOnlySpan originalSpan = reader.OriginalSpan; @@ -72,7 +72,7 @@ internal sealed override bool OnTryRead(ref Utf8JsonReader reader, Type typeToCo } else { - // Slower path that supports continuation and preserved references. + // Slower path that supports continuation. if (state.Current.ObjectState == StackFrameObjectState.None) { @@ -99,7 +99,7 @@ internal sealed override bool OnTryRead(ref Utf8JsonReader reader, Type typeToCo if (dataExtKey == null) { - jsonPropertyInfo.SetValueAsObject(obj, propValue); + jsonPropertyInfo.SetExtensionDictionaryAsObject(obj, propValue); } else { @@ -176,7 +176,7 @@ private void ReadConstructorArguments(ref ReadStack state, ref Utf8JsonReader re if (!(jsonParameterInfo!.ShouldDeserialize)) { - reader.TrySkip(); + reader.Skip(); state.Current.EndConstructorParameter(); continue; } @@ -454,41 +454,19 @@ private bool TryLookupConstructorParameter( ReadOnlySpan unescapedPropertyName = JsonSerializer.GetPropertyName(ref state, ref reader, options); - if (!state.Current.JsonClassInfo.TryGetParameter(unescapedPropertyName, ref state.Current, out jsonParameterInfo)) - { - return false; - } - - Debug.Assert(jsonParameterInfo != null); + jsonParameterInfo = state.Current.JsonClassInfo.GetParameter( + unescapedPropertyName, + ref state.Current, + out byte[] utf8PropertyName); - // Increment ConstructorParameterIndex so GetProperty() starts with the next parameter the next time this function is called. + // Increment ConstructorParameterIndex so GetParameter() checks the next parameter first when called again. state.Current.CtorArgumentState!.ParameterIndex++; - // Support JsonException.Path. - Debug.Assert( - jsonParameterInfo.JsonPropertyName == null || - options.PropertyNameCaseInsensitive || - unescapedPropertyName.SequenceEqual(jsonParameterInfo.JsonPropertyName)); - - if (jsonParameterInfo.JsonPropertyName == null) - { - byte[] propertyNameArray = unescapedPropertyName.ToArray(); - if (options.PropertyNameCaseInsensitive) - { - // Each payload can have a different name here; remember the value on the temporary stack. - state.Current.JsonPropertyName = propertyNameArray; - } - else - { - //Prevent future allocs by caching globally on the JsonPropertyInfo which is specific to a Type+PropertyName - // so it will match the incoming payload except when case insensitivity is enabled(which is handled above). - jsonParameterInfo.JsonPropertyName = propertyNameArray; - } - } + // For case insensitive and missing property support of JsonPath, remember the value on the temporary stack. + state.Current.JsonPropertyName = utf8PropertyName; state.Current.CtorArgumentState.JsonParameterInfo = jsonParameterInfo; - - return true; + return jsonParameterInfo != null; } internal override bool ConstructorIsParameterized => true; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/KeyValuePairConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/KeyValuePairConverter.cs index fc5035deeb78ef..08e790738f62fa 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/KeyValuePairConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/KeyValuePairConverter.cs @@ -3,23 +3,52 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using System.Text.Encodings.Web; namespace System.Text.Json.Serialization.Converters { internal sealed class KeyValuePairConverter : JsonValueConverter> { - private const string KeyName = "Key"; - private const string ValueName = "Value"; + private const string KeyNameCLR = "Key"; + private const string ValueNameCLR = "Value"; - // todo: https://github.com/dotnet/runtime/issues/1197 - // move these to JsonSerializerOptions and use the proper encoding. - private static readonly JsonEncodedText _keyName = JsonEncodedText.Encode(KeyName, encoder: null); - private static readonly JsonEncodedText _valueName = JsonEncodedText.Encode(ValueName, encoder: null); + // Property name for "Key" and "Value" with Options.PropertyNamingPolicy applied. + private string _keyName = null!; + private string _valueName = null!; + + // _keyName and _valueName as JsonEncodedText. + private JsonEncodedText _keyNameEncoded; + private JsonEncodedText _valueNameEncoded; // todo: https://github.com/dotnet/runtime/issues/32352 // it is possible to cache the underlying converters since this is an internal converter and // an instance is created only once for each JsonSerializerOptions instance. + internal override void Initialize(JsonSerializerOptions options) + { + JsonNamingPolicy? namingPolicy = options.PropertyNamingPolicy; + + if (namingPolicy == null) + { + _keyName = KeyNameCLR; + _valueName = ValueNameCLR; + } + else + { + _keyName = namingPolicy.ConvertName(KeyNameCLR); + _valueName = namingPolicy.ConvertName(ValueNameCLR); + + if (_keyName == null || _valueName == null) + { + ThrowHelper.ThrowInvalidOperationException_NamingPolicyReturnNull(namingPolicy); + } + } + + JavaScriptEncoder? encoder = options.Encoder; + _keyNameEncoded = JsonEncodedText.Encode(_keyName, encoder); + _valueNameEncoded = JsonEncodedText.Encode(_valueName, encoder); + } + internal override bool OnTryRead( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, @@ -44,17 +73,19 @@ internal override bool OnTryRead( ThrowHelper.ThrowJsonException(); } + bool caseInsensitiveMatch = options.PropertyNameCaseInsensitive; + string propertyName = reader.GetString()!; - if (propertyName == KeyName) + if (FoundKeyProperty(propertyName, caseInsensitiveMatch)) { reader.ReadWithVerify(); - k = JsonSerializer.Deserialize(ref reader, options, ref state, KeyName); + k = JsonSerializer.Deserialize(ref reader, options, ref state, _keyName); keySet = true; } - else if (propertyName == ValueName) + else if (FoundValueProperty(propertyName, caseInsensitiveMatch)) { reader.ReadWithVerify(); - v = JsonSerializer.Deserialize(ref reader, options, ref state, ValueName); + v = JsonSerializer.Deserialize(ref reader, options, ref state, _valueName); valueSet = true; } else @@ -70,28 +101,21 @@ internal override bool OnTryRead( } propertyName = reader.GetString()!; - if (propertyName == KeyName) + if (!keySet && FoundKeyProperty(propertyName, caseInsensitiveMatch)) { reader.ReadWithVerify(); - k = JsonSerializer.Deserialize(ref reader, options, ref state, KeyName); - keySet = true; + k = JsonSerializer.Deserialize(ref reader, options, ref state, _keyName); } - else if (propertyName == ValueName) + else if (!valueSet && FoundValueProperty(propertyName, caseInsensitiveMatch)) { reader.ReadWithVerify(); - v = JsonSerializer.Deserialize(ref reader, options, ref state, ValueName); - valueSet = true; + v = JsonSerializer.Deserialize(ref reader, options, ref state, _valueName); } else { ThrowHelper.ThrowJsonException(); } - if (!keySet || !valueSet) - { - ThrowHelper.ThrowJsonException(); - } - reader.ReadWithVerify(); if (reader.TokenType != JsonTokenType.EndObject) @@ -99,7 +123,7 @@ internal override bool OnTryRead( ThrowHelper.ThrowJsonException(); } - value = new KeyValuePair(k, v); + value = new KeyValuePair(k!, v!); return true; } @@ -107,14 +131,28 @@ internal override bool OnTryWrite(Utf8JsonWriter writer, KeyValuePair converter) public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { + // We do not check _converter.HandleNull, as the underlying struct cannot be null. + // A custom converter for some type T? can handle null. if (reader.TokenType == JsonTokenType.Null) { return null; @@ -30,6 +32,8 @@ public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOption { if (!value.HasValue) { + // We do not check _converter.HandleNull, as the underlying struct cannot be null. + // A custom converter for some type T? can handle null. writer.WriteNullValue(); } else diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.Cache.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.Cache.cs index 22848697381d24..0e88b3fb048c31 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.Cache.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.Cache.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -49,22 +48,6 @@ internal sealed partial class JsonClassInfo // Use an array (instead of List) for highest performance. private volatile PropertyRef[]? _propertyRefsSorted; - private Dictionary CreatePropertyCache(int capacity) - { - StringComparer comparer; - - if (Options.PropertyNameCaseInsensitive) - { - comparer = StringComparer.OrdinalIgnoreCase; - } - else - { - comparer = StringComparer.Ordinal; - } - - return new Dictionary(capacity, comparer); - } - public Dictionary CreateParameterCache(int capacity, JsonSerializerOptions options) { if (options.PropertyNameCaseInsensitive) @@ -77,7 +60,7 @@ public Dictionary CreateParameterCache(int capacity, } } - public static JsonPropertyInfo AddProperty(Type propertyType, PropertyInfo propertyInfo, Type parentClassType, JsonSerializerOptions options) + public static JsonPropertyInfo AddProperty(PropertyInfo propertyInfo, Type parentClassType, JsonSerializerOptions options) { JsonIgnoreCondition? ignoreCondition = JsonPropertyInfo.GetAttribute(propertyInfo)?.Condition; @@ -86,6 +69,8 @@ public static JsonPropertyInfo AddProperty(Type propertyType, PropertyInfo prope return JsonPropertyInfo.CreateIgnoredPropertyPlaceholder(propertyInfo, options); } + Type propertyType = propertyInfo.PropertyType; + JsonConverter converter = GetConverter( propertyType, parentClassType, @@ -143,21 +128,24 @@ internal static JsonPropertyInfo CreatePropertyInfoForClassInfo( runtimePropertyType: runtimePropertyType, propertyInfo: null, // Not a real property so this is null. parentClassType: typeof(object), // a dummy value (not used) - converter : converter, + converter: converter, options); } // AggressiveInlining used although a large method it is only called from one location and is on a hot path. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public JsonPropertyInfo GetProperty(ReadOnlySpan propertyName, ref ReadStackFrame frame) + public JsonPropertyInfo GetProperty( + ReadOnlySpan propertyName, + ref ReadStackFrame frame, + out byte[] utf8PropertyName) { - JsonPropertyInfo? info = null; + PropertyRef propertyRef; + + ulong key = GetKey(propertyName); // Keep a local copy of the cache in case it changes by another thread. PropertyRef[]? localPropertyRefsSorted = _propertyRefsSorted; - ulong key = GetKey(propertyName); - // If there is an existing cache, then use it. if (localPropertyRefsSorted != null) { @@ -172,10 +160,11 @@ public JsonPropertyInfo GetProperty(ReadOnlySpan propertyName, ref ReadSta { if (iForward < count) { - PropertyRef propertyRef = localPropertyRefsSorted[iForward]; - if (TryIsPropertyRefEqual(propertyRef, propertyName, key, ref info)) + propertyRef = localPropertyRefsSorted[iForward]; + if (IsPropertyRefEqual(propertyRef, propertyName, key)) { - return info; + utf8PropertyName = propertyRef.NameFromJson; + return propertyRef.Info; } ++iForward; @@ -183,9 +172,10 @@ public JsonPropertyInfo GetProperty(ReadOnlySpan propertyName, ref ReadSta if (iBackward >= 0) { propertyRef = localPropertyRefsSorted[iBackward]; - if (TryIsPropertyRefEqual(propertyRef, propertyName, key, ref info)) + if (IsPropertyRefEqual(propertyRef, propertyName, key)) { - return info; + utf8PropertyName = propertyRef.NameFromJson; + return propertyRef.Info; } --iBackward; @@ -193,10 +183,11 @@ public JsonPropertyInfo GetProperty(ReadOnlySpan propertyName, ref ReadSta } else if (iBackward >= 0) { - PropertyRef propertyRef = localPropertyRefsSorted[iBackward]; - if (TryIsPropertyRefEqual(propertyRef, propertyName, key, ref info)) + propertyRef = localPropertyRefsSorted[iBackward]; + if (IsPropertyRefEqual(propertyRef, propertyName, key)) { - return info; + utf8PropertyName = propertyRef.NameFromJson; + return propertyRef.Info; } --iBackward; @@ -209,24 +200,39 @@ public JsonPropertyInfo GetProperty(ReadOnlySpan propertyName, ref ReadSta } } - // No cached item was found. Try the main list which has all of the properties. - - string stringPropertyName = JsonHelpers.Utf8GetString(propertyName); - + // No cached item was found. Try the main dictionary which has all of the properties. Debug.Assert(PropertyCache != null); - if (!PropertyCache.TryGetValue(stringPropertyName, out info)) + if (PropertyCache.TryGetValue(JsonHelpers.Utf8GetString(propertyName), out JsonPropertyInfo? info)) { - info = JsonPropertyInfo.s_missingProperty; - } + if (Options.PropertyNameCaseInsensitive) + { + if (propertyName.SequenceEqual(info.NameAsUtf8Bytes)) + { + Debug.Assert(key == GetKey(info.NameAsUtf8Bytes.AsSpan())); - Debug.Assert(info != null); + // Use the existing byte[] reference instead of creating another one. + utf8PropertyName = info.NameAsUtf8Bytes!; + } + else + { + // Make a copy of the original Span. + utf8PropertyName = propertyName.ToArray(); + } + } + else + { + Debug.Assert(key == GetKey(info.NameAsUtf8Bytes!.AsSpan())); + utf8PropertyName = info.NameAsUtf8Bytes!; + } + } + else + { + info = JsonPropertyInfo.s_missingProperty; - // Three code paths to get here: - // 1) info == s_missingProperty. Property not found. - // 2) key == info.PropertyNameKey. Exact match found. - // 3) key != info.PropertyNameKey. Match found due to case insensitivity. - Debug.Assert(info == JsonPropertyInfo.s_missingProperty || key == info.PropertyNameKey || Options.PropertyNameCaseInsensitive); + // Make a copy of the original Span. + utf8PropertyName = propertyName.ToArray(); + } // Check if we should add this to the cache. // Only cache up to a threshold length and then just use the dictionary when an item is not found in the cache. @@ -253,7 +259,9 @@ public JsonPropertyInfo GetProperty(ReadOnlySpan propertyName, ref ReadSta frame.PropertyRefCache = new List(); } - PropertyRef propertyRef = new PropertyRef(key, info); + Debug.Assert(info != null); + + propertyRef = new PropertyRef(key, info, utf8PropertyName); frame.PropertyRefCache.Add(propertyRef); } } @@ -263,18 +271,18 @@ public JsonPropertyInfo GetProperty(ReadOnlySpan propertyName, ref ReadSta // AggressiveInlining used although a large method it is only called from one location and is on a hot path. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetParameter( + public JsonParameterInfo? GetParameter( ReadOnlySpan propertyName, ref ReadStackFrame frame, - out JsonParameterInfo? jsonParameterInfo) + out byte[] utf8PropertyName) { - JsonParameterInfo? info = null; + ParameterRef parameterRef; + + ulong key = GetKey(propertyName); // Keep a local copy of the cache in case it changes by another thread. ParameterRef[]? localParameterRefsSorted = _parameterRefsSorted; - ulong key = GetKey(propertyName); - // If there is an existing cache, then use it. if (localParameterRefsSorted != null) { @@ -289,11 +297,11 @@ public bool TryGetParameter( { if (iForward < count) { - ParameterRef parameterRef = localParameterRefsSorted[iForward]; - if (TryIsParameterRefEqual(parameterRef, propertyName, key, ref info)) + parameterRef = localParameterRefsSorted[iForward]; + if (IsParameterRefEqual(parameterRef, propertyName, key)) { - jsonParameterInfo = info; - return true; + utf8PropertyName = parameterRef.NameFromJson; + return parameterRef.Info; } ++iForward; @@ -301,10 +309,10 @@ public bool TryGetParameter( if (iBackward >= 0) { parameterRef = localParameterRefsSorted[iBackward]; - if (TryIsParameterRefEqual(parameterRef, propertyName, key, ref info)) + if (IsParameterRefEqual(parameterRef, propertyName, key)) { - jsonParameterInfo = info; - return true; + utf8PropertyName = parameterRef.NameFromJson; + return parameterRef.Info; } --iBackward; @@ -312,11 +320,11 @@ public bool TryGetParameter( } else if (iBackward >= 0) { - ParameterRef parameterRef = localParameterRefsSorted[iBackward]; - if (TryIsParameterRefEqual(parameterRef, propertyName, key, ref info)) + parameterRef = localParameterRefsSorted[iBackward]; + if (IsParameterRefEqual(parameterRef, propertyName, key)) { - jsonParameterInfo = info; - return true; + utf8PropertyName = parameterRef.NameFromJson; + return parameterRef.Info; } --iBackward; @@ -329,26 +337,39 @@ public bool TryGetParameter( } } - string propertyNameAsString = JsonHelpers.Utf8GetString(propertyName); - + // No cached item was found. Try the main dictionary which has all of the parameters. Debug.Assert(ParameterCache != null); - if (!ParameterCache.TryGetValue(propertyNameAsString, out info)) + if (ParameterCache.TryGetValue(JsonHelpers.Utf8GetString(propertyName), out JsonParameterInfo? info)) { - // Constructor parameter not found. We'll check if it's a property next. - jsonParameterInfo = null; - return false; - } + if (Options.PropertyNameCaseInsensitive) + { + if (propertyName.SequenceEqual(info.NameAsUtf8Bytes)) + { + Debug.Assert(key == GetKey(info.NameAsUtf8Bytes.AsSpan())); - jsonParameterInfo = info; - Debug.Assert(info != null); + // Use the existing byte[] reference instead of creating another one. + utf8PropertyName = info.NameAsUtf8Bytes!; + } + else + { + // Make a copy of the original Span. + utf8PropertyName = propertyName.ToArray(); + } + } + else + { + Debug.Assert(key == GetKey(info.NameAsUtf8Bytes!.AsSpan())); + utf8PropertyName = info.NameAsUtf8Bytes!; + } + } + else + { + Debug.Assert(info == null); - // Two code paths to get here: - // 1) key == info.PropertyNameKey. Exact match found. - // 2) key != info.PropertyNameKey. Match found due to case insensitivity. - // TODO: recheck these conditions - Debug.Assert(key == info.ParameterNameKey || - propertyNameAsString.Equals(info.NameAsString, StringComparison.OrdinalIgnoreCase)); + // Make a copy of the original Span. + utf8PropertyName = propertyName.ToArray(); + } // Check if we should add this to the cache. // Only cache up to a threshold length and then just use the dictionary when an item is not found in the cache. @@ -375,24 +396,23 @@ public bool TryGetParameter( frame.CtorArgumentState.ParameterRefCache = new List(); } - ParameterRef parameterRef = new ParameterRef(key, jsonParameterInfo); + parameterRef = new ParameterRef(key, info!, utf8PropertyName); frame.CtorArgumentState.ParameterRefCache.Add(parameterRef); } } - return true; + return info; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryIsPropertyRefEqual(in PropertyRef propertyRef, ReadOnlySpan propertyName, ulong key, [NotNullWhen(true)] ref JsonPropertyInfo? info) + private static bool IsPropertyRefEqual(in PropertyRef propertyRef, ReadOnlySpan propertyName, ulong key) { if (key == propertyRef.Key) { // We compare the whole name, although we could skip the first 7 bytes (but it's not any faster) if (propertyName.Length <= PropertyNameKeyLength || - propertyName.SequenceEqual(propertyRef.Info.Name)) + propertyName.SequenceEqual(propertyRef.NameFromJson)) { - info = propertyRef.Info; return true; } } @@ -401,15 +421,14 @@ private static bool TryIsPropertyRefEqual(in PropertyRef propertyRef, ReadOnlySp } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryIsParameterRefEqual(in ParameterRef parameterRef, ReadOnlySpan parameterName, ulong key, [NotNullWhen(true)] ref JsonParameterInfo? info) + private static bool IsParameterRefEqual(in ParameterRef parameterRef, ReadOnlySpan parameterName, ulong key) { if (key == parameterRef.Key) { // We compare the whole name, although we could skip the first 7 bytes (but it's not any faster) if (parameterName.Length <= PropertyNameKeyLength || - parameterName.SequenceEqual(parameterRef.Info.ParameterName)) + parameterName.SequenceEqual(parameterRef.NameFromJson)) { - info = parameterRef.Info; return true; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs index 362614918cdcd4..7c24c672dcaf72 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs @@ -20,7 +20,7 @@ internal sealed partial class JsonClassInfo public ConstructorDelegate? CreateObject { get; private set; } - public object? CreateObjectWithParameterizedCtor { get; set; } + public object? CreateObjectWithArgs { get; set; } public ClassType ClassType { get; private set; } @@ -95,45 +95,73 @@ public JsonClassInfo(Type type, JsonSerializerOptions options) { case ClassType.Object: { - // Create the policy property. - PropertyInfoForClassInfo = CreatePropertyInfoForClassInfo(type, runtimeType, converter!, options); - CreateObject = options.MemberAccessorStrategy.CreateConstructor(type); + Dictionary cache = new Dictionary( + Options.PropertyNameCaseInsensitive + ? StringComparer.OrdinalIgnoreCase + : StringComparer.Ordinal); - PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); - - Dictionary cache = CreatePropertyCache(properties.Length); + HashSet? ignoredProperties = null; - foreach (PropertyInfo propertyInfo in properties) + // We start from the most derived type and ascend to the base type. + for (Type? currentType = type; currentType != null; currentType = currentType.BaseType) { - // Ignore indexers - if (propertyInfo.GetIndexParameters().Length > 0) - { - continue; - } - - // For now we only support public getters\setters - if (propertyInfo.GetMethod?.IsPublic == true || - propertyInfo.SetMethod?.IsPublic == true) + foreach (PropertyInfo propertyInfo in currentType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) { - JsonPropertyInfo jsonPropertyInfo = AddProperty(propertyInfo.PropertyType, propertyInfo, type, options); - Debug.Assert(jsonPropertyInfo != null && jsonPropertyInfo.NameAsString != null); + // Ignore indexers + if (propertyInfo.GetIndexParameters().Length > 0) + { + continue; + } - // If the JsonPropertyNameAttribute or naming policy results in collisions, throw an exception. - if (!JsonHelpers.TryAdd(cache, jsonPropertyInfo.NameAsString, jsonPropertyInfo)) + // For now we only support public properties (i.e. setter and/or getter is public). + if (propertyInfo.GetMethod?.IsPublic == true || + propertyInfo.SetMethod?.IsPublic == true) { - JsonPropertyInfo other = cache[jsonPropertyInfo.NameAsString]; + JsonPropertyInfo jsonPropertyInfo = AddProperty(propertyInfo, currentType, options); + Debug.Assert(jsonPropertyInfo != null && jsonPropertyInfo.NameAsString != null); + + string propertyName = propertyInfo.Name; - if (other.ShouldDeserialize == false && other.ShouldSerialize == false) + // The JsonPropertyNameAttribute or naming policy resulted in a collision. + if (!JsonHelpers.TryAdd(cache, jsonPropertyInfo.NameAsString, jsonPropertyInfo)) { - // Overwrite the one just added since it has [JsonIgnore]. - cache[jsonPropertyInfo.NameAsString] = jsonPropertyInfo; + JsonPropertyInfo other = cache[jsonPropertyInfo.NameAsString]; + + if (other.IsIgnored) + { + // Overwrite previously cached property since it has [JsonIgnore]. + cache[jsonPropertyInfo.NameAsString] = jsonPropertyInfo; + } + else if ( + // Does the current property have `JsonIgnoreAttribute`? + !jsonPropertyInfo.IsIgnored && + // Is the current property hidden by the previously cached property + // (with `new` keyword, or by overriding)? + other.PropertyInfo!.Name != propertyName && + // Was a property with the same CLR name was ignored? That property hid the current property, + // thus, if it was ignored, the current property should be ignored too. + ignoredProperties?.Contains(propertyName) != true) + { + // We throw if we have two public properties that have the same JSON property name, and neither have been ignored. + ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(Type, jsonPropertyInfo); + } + // Ignore the current property. } - else if (jsonPropertyInfo.ShouldDeserialize == true || jsonPropertyInfo.ShouldSerialize == true) + + if (jsonPropertyInfo.IsIgnored) { - ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(Type, jsonPropertyInfo); + (ignoredProperties ??= new HashSet()).Add(propertyName); } - // else ignore jsonPropertyInfo since it has [JsonIgnore]. + } + else + { + if (JsonPropertyInfo.GetAttribute(propertyInfo) != null) + { + ThrowHelper.ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(propertyInfo, currentType); + } + + // Non-public properties should not be included for (de)serialization. } } } @@ -154,15 +182,23 @@ public JsonClassInfo(Type type, JsonSerializerOptions options) cacheArray = new JsonPropertyInfo[cache.Count]; } - // Set fields when finished to avoid concurrency issues. - PropertyCache = cache; + // Copy the dictionary cache to the array cache. cache.Values.CopyTo(cacheArray, 0); + + // Set the array cache field at this point since it is completely initialized. + // It can now be safely accessed by other threads. PropertyCacheArray = cacheArray; + // Allow constructor parameter logic to remove items from the dictionary since the JSON + // property values will be passed to the constructor and do not call a property setter. if (converter.ConstructorIsParameterized) { - InitializeConstructorParameters(converter.ConstructorInfo!); + InitializeConstructorParameters(cache, converter.ConstructorInfo!); } + + // Set the dictionary cache field at this point since it is completely initialized. + // It can now be safely accessed by other threads. + PropertyCache = cache; } break; case ClassType.Enumerable: @@ -189,13 +225,11 @@ public JsonClassInfo(Type type, JsonSerializerOptions options) } } - private void InitializeConstructorParameters(ConstructorInfo constructorInfo) + private void InitializeConstructorParameters(Dictionary propertyCache, ConstructorInfo constructorInfo) { ParameterInfo[] parameters = constructorInfo!.GetParameters(); Dictionary parameterCache = CreateParameterCache(parameters.Length, Options); - Dictionary propertyCache = PropertyCache!; - foreach (ParameterInfo parameterInfo in parameters) { PropertyInfo? firstMatch = null; @@ -230,7 +264,7 @@ private void InitializeConstructorParameters(ConstructorInfo constructorInfo) // One object property cannot map to multiple constructor // parameters (ConvertName above can't return multiple strings). - parameterCache.Add(jsonParameterInfo.NameAsString, jsonParameterInfo); + parameterCache.Add(jsonPropertyInfo.NameAsString!, jsonParameterInfo); // Remove property from deserialization cache to reduce the number of JsonPropertyInfos considered during JSON matching. propertyCache.Remove(jsonPropertyInfo.NameAsString!); @@ -337,6 +371,7 @@ public static JsonConverter GetConverter( JsonSerializerOptions options) { Debug.Assert(type != null); + ValidateType(type, parentClassType, propertyInfo, options); JsonConverter converter = options.DetermineConverter(parentClassType, type, propertyInfo)!; @@ -380,7 +415,46 @@ public static JsonConverter GetConverter( } } + Debug.Assert(!IsInvalidForSerialization(runtimeType)); + return converter; } + + private static void ValidateType(Type type, Type? parentClassType, PropertyInfo? propertyInfo, JsonSerializerOptions options) + { + if (!options.TypeIsCached(type) && IsInvalidForSerialization(type)) + { + ThrowHelper.ThrowInvalidOperationException_CannotSerializeInvalidType(type, parentClassType, propertyInfo); + } + } + + private static bool IsInvalidForSerialization(Type type) + { + return type.IsPointer || IsByRefLike(type) || type.ContainsGenericParameters; + } + + private static bool IsByRefLike(Type type) + { +#if BUILDING_INBOX_LIBRARY + return type.IsByRefLike; +#else + if (!type.IsValueType) + { + return false; + } + + object[] attributes = type.GetCustomAttributes(inherit: false); + + for (int i = 0; i < attributes.Length; i++) + { + if (attributes[i].GetType().FullName == "System.Runtime.CompilerServices.IsByRefLikeAttribute") + { + return true; + } + } + + return false; +#endif + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs index 9b7a706678c367..361236c42d60b6 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs @@ -40,12 +40,6 @@ internal JsonConverter() { } internal abstract Type? ElementType { get; } - /// - /// Cached value of ShouldHandleNullValue. It is cached since the converter should never - /// change the value depending on state and because it may contain non-trival logic. - /// - internal bool HandleNullValue { get; set; } - /// /// Cached value of TypeToConvert.IsValueType, which is an expensive call. /// @@ -79,5 +73,7 @@ internal bool ShouldFlush(Utf8JsonWriter writer, ref WriteStack state) internal virtual bool ConstructorIsParameterized => false; internal ConstructorInfo? ConstructorInfo { get; set; } + + internal virtual void Initialize(JsonSerializerOptions options) { } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterFactory.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterFactory.cs index caea89aa57450e..4a26cdaab2d80a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterFactory.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterFactory.cs @@ -40,14 +40,15 @@ internal sealed override ClassType ClassType internal override JsonPropertyInfo CreateJsonPropertyInfo() { - // We should never get here. - Debug.Assert(false); + Debug.Fail("We should never get here."); throw new InvalidOperationException(); } internal override JsonParameterInfo CreateJsonParameterInfo() { + Debug.Fail("We should never get here."); + throw new InvalidOperationException(); } @@ -71,8 +72,7 @@ internal sealed override object ReadCoreAsObject( JsonSerializerOptions options, ref ReadStack state) { - // We should never get here. - Debug.Assert(false); + Debug.Fail("We should never get here."); throw new InvalidOperationException(); } @@ -83,8 +83,7 @@ internal sealed override bool TryWriteAsObject( JsonSerializerOptions options, ref WriteStack state) { - // We should never get here. - Debug.Assert(false); + Debug.Fail("We should never get here."); throw new InvalidOperationException(); } @@ -97,8 +96,7 @@ internal sealed override bool WriteCoreAsObject( JsonSerializerOptions options, ref WriteStack state) { - // We should never get here. - Debug.Assert(false); + Debug.Fail("We should never get here."); throw new InvalidOperationException(); } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.ReadCore.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.ReadCore.cs index 1785b669b2552c..c49fd0d7947db1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.ReadCore.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.ReadCore.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; + namespace System.Text.Json.Serialization { public partial class JsonConverter @@ -14,6 +16,7 @@ public partial class JsonConverter return ReadCore(ref reader, options, ref state); } + [return: MaybeNull] internal T ReadCore( ref Utf8JsonReader reader, JsonSerializerOptions options, diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs index be4350cbd3c9b0..bce4c1224ced71 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverterOfT.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -22,7 +23,8 @@ protected internal JsonConverter() // In the future, this will be check for !IsSealed (and excluding value types). CanBePolymorphic = TypeToConvert == typeof(object); IsValueType = TypeToConvert.IsValueType; - HandleNullValue = ShouldHandleNullValue; + HandleNull = IsValueType; + CanBeNull = !IsValueType || Nullable.GetUnderlyingType(TypeToConvert) != null; IsInternalConverter = GetType().Assembly == typeof(JsonConverter).Assembly; CanUseDirectReadOrWrite = !CanBePolymorphic && IsInternalConverter && ClassType == ClassType.Value; } @@ -54,16 +56,27 @@ internal override sealed JsonParameterInfo CreateJsonParameterInfo() internal override Type? ElementType => null; - // Allow a converter that can't be null to return a null value representation, such as JsonElement or Nullable<>. - // In other cases, this will likely cause an JsonException in the converter. - // Do not call this directly; it is cached in HandleNullValue. - internal virtual bool ShouldHandleNullValue => IsValueType; + /// + /// Indicates whether should be passed to the converter on serialization, + /// and whether should be passed on deserialization. + /// + /// + /// The default value is for converters for value types, and for converters for reference types. + /// + public virtual bool HandleNull { get; } + + /// + /// Can be assigned to ? + /// + internal bool CanBeNull { get; } /// /// Is the converter built-in. /// internal bool IsInternalConverter { get; set; } + internal readonly EqualityComparer _defaultComparer = EqualityComparer.Default; + // This non-generic API is sealed as it just forwards to the generic version. internal sealed override bool TryWriteAsObject(Utf8JsonWriter writer, object? value, JsonSerializerOptions options, ref WriteStack state) { @@ -74,13 +87,12 @@ internal sealed override bool TryWriteAsObject(Utf8JsonWriter writer, object? va // Provide a default implementation for value converters. internal virtual bool OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, ref WriteStack state) { - // TODO: https://github.com/dotnet/runtime/issues/32523 - Write(writer, value!, options); + Write(writer, value, options); return true; } // Provide a default implementation for value converters. - internal virtual bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, [MaybeNullWhen(false)] out T value) + internal virtual bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, [MaybeNull] out T value) { value = Read(ref reader, typeToConvert, options); return true; @@ -96,9 +108,10 @@ internal virtual bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, J /// The being converted. /// The being used. /// The value that was converted. + [return: MaybeNull] public abstract T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options); - internal bool TryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, out T value) + internal bool TryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, ref ReadStack state, [MaybeNull] out T value) { if (ClassType == ClassType.Value) { @@ -106,9 +119,14 @@ internal bool TryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSeriali Debug.Assert(!state.IsContinuation); // For perf and converter simplicity, handle null here instead of forwarding to the converter. - if (reader.TokenType == JsonTokenType.Null && !HandleNullValue) + if (reader.TokenType == JsonTokenType.Null && !HandleNull) { - value = default!; + if (!CanBeNull) + { + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); + } + + value = default; return true; } @@ -148,10 +166,15 @@ internal bool TryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSeriali // For performance, only perform validation on internal converters on debug builds. if (IsInternalConverter) { - if (reader.TokenType == JsonTokenType.Null && !HandleNullValue && !wasContinuation) + if (reader.TokenType == JsonTokenType.Null && !HandleNull && !wasContinuation) { + if (!CanBeNull) + { + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); + } + // For perf and converter simplicity, handle null here instead of forwarding to the converter. - value = default!; + value = default; success = true; } else @@ -165,9 +188,14 @@ internal bool TryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSeriali if (!wasContinuation) { // For perf and converter simplicity, handle null here instead of forwarding to the converter. - if (reader.TokenType == JsonTokenType.Null && !HandleNullValue) + if (reader.TokenType == JsonTokenType.Null && !HandleNull) { - value = default!; + if (!CanBeNull) + { + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(TypeToConvert); + } + + value = default; state.Pop(true); return true; } @@ -214,7 +242,20 @@ internal bool TryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions opt { if (value == null) { - writer.WriteNullValue(); + if (!HandleNull) + { + writer.WriteNullValue(); + } + else + { + Debug.Assert(ClassType == ClassType.Value); + Debug.Assert(!state.IsContinuation); + + int originalPropertyDepth = writer.CurrentDepth; + Write(writer, value, options); + VerifyWrite(originalPropertyDepth, writer); + } + return true; } @@ -237,15 +278,12 @@ internal bool TryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions opt } } } - else + else if (value == null && !HandleNull) { - // We do not pass null values to converters unless HandleNullValue is true. Null values for properties were + // We do not pass null values to converters unless HandleNull is true. Null values for properties were // already handled in GetMemberAndWriteJson() so we don't need to check for IgnoreNullValues here. - if (value == null && !HandleNullValue) - { - writer.WriteNullValue(); - return true; - } + writer.WriteNullValue(); + return true; } if (ClassType == ClassType.Value) @@ -254,10 +292,8 @@ internal bool TryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions opt int originalPropertyDepth = writer.CurrentDepth; - // TODO: https://github.com/dotnet/runtime/issues/32523 - Write(writer, value!, options); + Write(writer, value, options); VerifyWrite(originalPropertyDepth, writer); - return true; } @@ -285,55 +321,46 @@ internal bool TryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions opt internal bool TryWriteDataExtensionProperty(Utf8JsonWriter writer, T value, JsonSerializerOptions options, ref WriteStack state) { + Debug.Assert(value != null); + + if (!IsInternalConverter) + { + return TryWrite(writer, value, options, ref state); + } + Debug.Assert(this is JsonDictionaryConverter); + state.Current.PolymorphicJsonPropertyInfo = state.Current.DeclaredJsonPropertyInfo!.RuntimeClassInfo.ElementClassInfo!.PropertyInfoForClassInfo; + if (writer.CurrentDepth >= options.EffectiveMaxDepth) { ThrowHelper.ThrowJsonException_SerializerCycleDetected(options.EffectiveMaxDepth); } - bool success; JsonDictionaryConverter dictionaryConverter = (JsonDictionaryConverter)this; - if (ClassType == ClassType.Value) - { - Debug.Assert(!state.IsContinuation); - - int originalPropertyDepth = writer.CurrentDepth; + bool isContinuation = state.IsContinuation; + bool success; - // Ignore the naming policy for extension data. - state.Current.IgnoreDictionaryKeyPolicy = true; + state.Push(); - success = dictionaryConverter.OnWriteResume(writer, value, options, ref state); - if (success) - { - VerifyWrite(originalPropertyDepth, writer); - } - } - else + if (!isContinuation) { - bool isContinuation = state.IsContinuation; - - state.Push(); - - if (!isContinuation) - { - Debug.Assert(state.Current.OriginalDepth == 0); - state.Current.OriginalDepth = writer.CurrentDepth; - } - - // Ignore the naming policy for extension data. - state.Current.IgnoreDictionaryKeyPolicy = true; + Debug.Assert(state.Current.OriginalDepth == 0); + state.Current.OriginalDepth = writer.CurrentDepth; + } - success = dictionaryConverter.OnWriteResume(writer, value, options, ref state); - if (success) - { - VerifyWrite(state.Current.OriginalDepth, writer); - } + // Ignore the naming policy for extension data. + state.Current.IgnoreDictionaryKeyPolicy = true; - state.Pop(success); + success = dictionaryConverter.OnWriteResume(writer, value, options, ref state); + if (success) + { + VerifyWrite(state.Current.OriginalDepth, writer); } + state.Pop(success); + return success; } @@ -400,6 +427,6 @@ internal void VerifyWrite(int originalDepth, Utf8JsonWriter writer) /// The to write to. /// The value to convert. /// The being used. - public abstract void Write(Utf8JsonWriter writer, [DisallowNull] T value, JsonSerializerOptions options); + public abstract void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options); } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonIgnoreCondition.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonIgnoreCondition.cs index 70a8bca3ad3784..93239931addbb6 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonIgnoreCondition.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonIgnoreCondition.cs @@ -5,21 +5,24 @@ namespace System.Text.Json.Serialization { /// - /// Controls how the ignores properties on serialization and deserialization. + /// When specified on , + /// specifies that properties with default values are ignored during serialization. + /// When specified on , controls whether + /// a property is ignored during serialization and deserialization. /// public enum JsonIgnoreCondition { /// - /// Property will always be ignored. + /// Property is never ignored during serialization or deserialization. /// - Always = 0, + Never = 0, /// - /// Property will only be ignored if it is null. + /// Property is always ignored during serialization and deserialization. /// - WhenNull = 1, + Always = 1, /// - /// Property will always be serialized and deserialized, regardless of configuration. + /// If the value is the default, the property is ignored during serialization. /// - Never = 2 + WhenWritingDefault = 2, } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonParameterInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonParameterInfo.cs index d531d9f9c2d279..f2d8408205d312 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonParameterInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonParameterInfo.cs @@ -22,22 +22,13 @@ internal abstract class JsonParameterInfo // The default value of the parameter. This is `DefaultValue` of the `ParameterInfo`, if specified, or the CLR `default` for the `ParameterType`. public object? DefaultValue { get; protected set; } - // The name from a Json value. This is cached for performance on first deserialize. - public byte[]? JsonPropertyName { get; set; } - // Options can be referenced here since all JsonPropertyInfos originate from a JsonClassInfo that is cached on JsonSerializerOptions. protected JsonSerializerOptions Options { get; set; } = null!; // initialized in Init method public ParameterInfo ParameterInfo { get; private set; } = null!; // The name of the parameter as UTF-8 bytes. - public byte[] ParameterName { get; private set; } = null!; - - // The name of the parameter. - public string NameAsString { get; private set; } = null!; - - // Key for fast property name lookup. - public ulong ParameterNameKey { get; private set; } + public byte[] NameAsUtf8Bytes { get; private set; } = null!; // The zero-based position of the parameter in the formal parameter list. public int Position { get; private set; } @@ -77,12 +68,7 @@ public virtual void Initialize( private void DetermineParameterName(JsonPropertyInfo matchingProperty) { - NameAsString = matchingProperty.NameAsString!; - - // `NameAsString` is valid UTF16, so just call the simple UTF16->UTF8 encoder. - ParameterName = Encoding.UTF8.GetBytes(NameAsString); - - ParameterNameKey = JsonClassInfo.GetKey(ParameterName); + NameAsUtf8Bytes = matchingProperty.NameAsUtf8Bytes!; } // Create a parameter that is ignored at run-time. It uses the same type (typeof(sbyte)) to help diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonParameterInfoOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonParameterInfoOfT.cs index 398e0dedc3a0c0..a03982f4e40d8f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonParameterInfoOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonParameterInfoOfT.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text.Json.Serialization; @@ -14,7 +15,6 @@ namespace System.Text.Json internal class JsonParameterInfo : JsonParameterInfo { private JsonConverter _converter = null!; - private bool _ignoreNullValues; private Type _runtimePropertyType = null!; public override JsonConverter ConverterBase => _converter; @@ -36,7 +36,6 @@ public override void Initialize( options); _converter = (JsonConverter)matchingProperty.ConverterBase; - _ignoreNullValues = matchingProperty.IgnoreNullValues; _runtimePropertyType = runtimePropertyType; if (parameterInfo.HasDefaultValue) @@ -55,9 +54,14 @@ public override bool ReadJson(ref ReadStack state, ref Utf8JsonReader reader, ou bool success; bool isNullToken = reader.TokenType == JsonTokenType.Null; - if (isNullToken && !_converter.HandleNullValue && !state.IsContinuation) + if (isNullToken && !_converter.HandleNull && !state.IsContinuation) { - // Don't have to check for IgnoreNullValue option here because we set the default value (likely null) regardless + if (!_converter.CanBeNull) + { + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(_converter.TypeToConvert); + } + + // Don't have to check for IgnoreNullValue option here because we set the default value regardless. value = DefaultValue; return true; } @@ -79,13 +83,19 @@ public override bool ReadJson(ref ReadStack state, ref Utf8JsonReader reader, ou return success; } - public bool ReadJsonTyped(ref ReadStack state, ref Utf8JsonReader reader, out T value) + public bool ReadJsonTyped(ref ReadStack state, ref Utf8JsonReader reader, [MaybeNull] out T value) { bool success; bool isNullToken = reader.TokenType == JsonTokenType.Null; - if (isNullToken && !_converter.HandleNullValue && !state.IsContinuation) + if (isNullToken && !_converter.HandleNull && !state.IsContinuation) { + if (!_converter.CanBeNull) + { + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(_converter.TypeToConvert); + } + + // Don't have to check for IgnoreNullValue option here because we set the default value regardless. value = TypedDefaultValue; return true; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs index 549f93a4d87ef1..4e345309e244c8 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs @@ -83,13 +83,10 @@ private void DeterminePropertyName() Debug.Assert(NameAsString != null); // At this point propertyName is valid UTF16, so just call the simple UTF16->UTF8 encoder. - Name = Encoding.UTF8.GetBytes(NameAsString); + NameAsUtf8Bytes = Encoding.UTF8.GetBytes(NameAsString); // Cache the escaped property name. - EscapedName = JsonEncodedText.Encode(Name, Options.Encoder); - - ulong key = JsonClassInfo.GetKey(Name); - PropertyNameKey = key; + EscapedName = JsonEncodedText.Encode(NameAsString, NameAsUtf8Bytes, Options.Encoder); } private void DetermineSerializationCapabilities(JsonIgnoreCondition? ignoreCondition) @@ -135,20 +132,25 @@ private void DetermineIgnoreCondition(JsonIgnoreCondition? ignoreCondition) if (ignoreCondition != JsonIgnoreCondition.Never) { - Debug.Assert(ignoreCondition == JsonIgnoreCondition.WhenNull); - IgnoreNullValues = true; + Debug.Assert(ignoreCondition == JsonIgnoreCondition.WhenWritingDefault); + IgnoreDefaultValuesOnWrite = true; } } - else +#pragma warning disable CS0618 // IgnoreNullValues is obsolete + else if (Options.IgnoreNullValues) + { + Debug.Assert(Options.DefaultIgnoreCondition == JsonIgnoreCondition.Never); + IgnoreDefaultValuesOnRead = true; + IgnoreDefaultValuesOnWrite = true; + } + else if (Options.DefaultIgnoreCondition == JsonIgnoreCondition.WhenWritingDefault) { - IgnoreNullValues = Options.IgnoreNullValues; + Debug.Assert(!Options.IgnoreNullValues); + IgnoreDefaultValuesOnWrite = true; } +#pragma warning restore CS0618 // IgnoreNullValues is obsolete } - // The escaped name passed to the writer. - // Use a field here (not a property) to avoid value semantics. - public JsonEncodedText? EscapedName; - public static TAttribute? GetAttribute(PropertyInfo propertyInfo) where TAttribute : Attribute { return (TAttribute?)propertyInfo.GetCustomAttribute(typeof(TAttribute), inherit: false); @@ -190,19 +192,37 @@ public virtual void Initialize( Options = options; } - public bool IgnoreNullValues { get; private set; } + public bool IgnoreDefaultValuesOnRead { get; private set; } + public bool IgnoreDefaultValuesOnWrite { get; private set; } public bool IsPropertyPolicy { get; protected set; } - // The name from a Json value. This is cached for performance on first deserialize. - public byte[]? JsonPropertyName { get; set; } - - // The name of the property with any casing policy or the name specified from JsonPropertyNameAttribute. - public byte[]? Name { get; private set; } + // There are 3 copies of the property name: + // 1) NameAsString. The unescaped property name. + // 2) NameAsUtf8Bytes. The Utf8 version of NameAsString. Used during during deserialization for property lookup. + // 3) EscapedName. The escaped verson of NameAsString and NameAsUtf8Bytes written during serialization. Internally shares + // the same instances of NameAsString and NameAsUtf8Bytes if there is no escaping. + + /// + /// The unescaped name of the property. + /// Is either the actual CLR property name, + /// the value specified in JsonPropertyNameAttribute, + /// or the value returned from PropertyNamingPolicy(clrPropertyName). + /// public string? NameAsString { get; private set; } - // Key for fast property name lookup. - public ulong PropertyNameKey { get; set; } + /// + /// Utf8 version of NameAsString. + /// + public byte[]? NameAsUtf8Bytes { get; private set; } + + /// + /// The escaped name passed to the writer. + /// + /// + /// JsonEncodedText is a value type so a field is used (not a property) to avoid unnecessary copies. + /// + public JsonEncodedText? EscapedName; // Options can be referenced here since all JsonPropertyInfos originate from a JsonClassInfo that is cached on JsonSerializerOptions. protected JsonSerializerOptions Options { get; set; } = null!; // initialized in Init method @@ -222,8 +242,7 @@ public bool ReadJsonAndAddExtensionProperty(object obj, ref ReadStack state, ref } else { - JsonConverter converter = (JsonConverter) - state.Current.JsonPropertyInfo!.RuntimeClassInfo.ElementClassInfo!.PropertyInfoForClassInfo.ConverterBase; + JsonConverter converter = (JsonConverter)Options.GetConverter(typeof(object)); if (!converter.TryRead(ref reader, typeof(JsonElement), Options, ref state, out object? value)) { @@ -240,8 +259,7 @@ public bool ReadJsonAndAddExtensionProperty(object obj, ref ReadStack state, ref Debug.Assert(propValue is IDictionary); IDictionary dictionaryJsonElement = (IDictionary)propValue; - JsonConverter converter = (JsonConverter) - state.Current.JsonPropertyInfo!.RuntimeClassInfo.ElementClassInfo!.PropertyInfoForClassInfo.ConverterBase; + JsonConverter converter = (JsonConverter)Options.GetConverter(typeof(JsonElement)); if (!converter.TryRead(ref reader, typeof(JsonElement), Options, ref state, out JsonElement value)) { @@ -299,7 +317,7 @@ public JsonClassInfo RuntimeClassInfo public Type? RuntimePropertyType { get; private set; } = null; - public abstract void SetValueAsObject(object obj, object? value); + public abstract void SetExtensionDictionaryAsObject(object obj, object? extensionDict); public bool ShouldSerialize { get; private set; } public bool ShouldDeserialize { get; private set; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfT.cs new file mode 100644 index 00000000000000..648158cd6d703e --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfT.cs @@ -0,0 +1,261 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text.Json.Serialization; + +namespace System.Text.Json +{ + /// + /// Represents a strongly-typed property to prevent boxing and to create a direct delegate to the getter\setter. + /// + /// is the for either the property's converter, + /// or a type's converter, if the current instance is a . + internal sealed class JsonPropertyInfo : JsonPropertyInfo + { + private static readonly T s_defaultValue = default!; + + public Func? Get { get; private set; } + public Action? Set { get; private set; } + + public JsonConverter Converter { get; internal set; } = null!; + + public override void Initialize( + Type parentClassType, + Type declaredPropertyType, + Type? runtimePropertyType, + ClassType runtimeClassType, + PropertyInfo? propertyInfo, + JsonConverter converter, + JsonIgnoreCondition? ignoreCondition, + JsonSerializerOptions options) + { + base.Initialize( + parentClassType, + declaredPropertyType, + runtimePropertyType, + runtimeClassType, + propertyInfo, + converter, + ignoreCondition, + options); + + if (propertyInfo != null) + { + bool useNonPublicAccessors = GetAttribute(propertyInfo) != null; + + MethodInfo? getMethod = propertyInfo.GetMethod; + if (getMethod != null && (getMethod.IsPublic || useNonPublicAccessors)) + { + HasGetter = true; + Get = options.MemberAccessorStrategy.CreatePropertyGetter(propertyInfo); + } + + MethodInfo? setMethod = propertyInfo.SetMethod; + if (setMethod != null && (setMethod.IsPublic || useNonPublicAccessors)) + { + HasSetter = true; + Set = options.MemberAccessorStrategy.CreatePropertySetter(propertyInfo); + } + } + else + { + IsPropertyPolicy = true; + HasGetter = true; + HasSetter = true; + } + + GetPolicies(ignoreCondition); + } + + public override JsonConverter ConverterBase + { + get + { + return Converter; + } + set + { + Debug.Assert(value is JsonConverter); + Converter = (JsonConverter)value; + } + } + + public override object? GetValueAsObject(object obj) + { + if (IsPropertyPolicy) + { + return obj; + } + + Debug.Assert(HasGetter); + return Get!(obj); + } + + public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer) + { + Debug.Assert(EscapedName.HasValue); + + bool success; + T value = Get!(obj); + + if (value == null) + { + Debug.Assert(s_defaultValue == null && Converter.CanBeNull); + + success = true; + if (!IgnoreDefaultValuesOnWrite) + { + if (!Converter.HandleNull) + { + writer.WriteNull(EscapedName.Value); + } + else + { + // No object, collection, or re-entrancy converter handles null. + Debug.Assert(Converter.ClassType == ClassType.Value); + + if (state.Current.PropertyState < StackFramePropertyState.Name) + { + state.Current.PropertyState = StackFramePropertyState.Name; + writer.WritePropertyName(EscapedName.Value); + } + + int originalDepth = writer.CurrentDepth; + Converter.Write(writer, value, Options); + if (originalDepth != writer.CurrentDepth) + { + ThrowHelper.ThrowJsonException_SerializationConverterWrite(Converter); + } + } + } + } + else if (IgnoreDefaultValuesOnWrite && Converter._defaultComparer.Equals(s_defaultValue, value)) + { + Debug.Assert(s_defaultValue != null && !Converter.CanBeNull); + success = true; + } + else + { + if (state.Current.PropertyState < StackFramePropertyState.Name) + { + state.Current.PropertyState = StackFramePropertyState.Name; + writer.WritePropertyName(EscapedName.Value); + } + + success = Converter.TryWrite(writer, value, Options, ref state); + } + + return success; + } + + public override bool GetMemberAndWriteJsonExtensionData(object obj, ref WriteStack state, Utf8JsonWriter writer) + { + bool success; + T value = Get!(obj); + + if (value == null) + { + success = true; + } + else + { + success = Converter.TryWriteDataExtensionProperty(writer, value, Options, ref state); + } + + return success; + } + + public override bool ReadJsonAndSetMember(object obj, ref ReadStack state, ref Utf8JsonReader reader) + { + bool success; + + bool isNullToken = reader.TokenType == JsonTokenType.Null; + if (isNullToken && !Converter.HandleNull && !state.IsContinuation) + { + if (!Converter.CanBeNull) + { + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Converter.TypeToConvert); + } + + Debug.Assert(s_defaultValue == null); + + if (!IgnoreDefaultValuesOnRead) + { + T value = default; + Set!(obj, value!); + } + + success = true; + } + else if (Converter.CanUseDirectReadOrWrite) + { + if (!(isNullToken && IgnoreDefaultValuesOnRead && Converter.CanBeNull)) + { + // Optimize for internal converters by avoiding the extra call to TryRead. + T fastvalue = Converter.Read(ref reader, RuntimePropertyType!, Options); + Set!(obj, fastvalue!); + } + + success = true; + } + else + { + success = true; + + if (!(isNullToken && IgnoreDefaultValuesOnRead && Converter.CanBeNull)) + { + success = Converter.TryRead(ref reader, RuntimePropertyType!, Options, ref state, out T value); + if (success) + { + Set!(obj, value!); + } + } + } + + return success; + } + + public override bool ReadJsonAsObject(ref ReadStack state, ref Utf8JsonReader reader, out object? value) + { + bool success; + bool isNullToken = reader.TokenType == JsonTokenType.Null; + if (isNullToken && !Converter.HandleNull && !state.IsContinuation) + { + if (!Converter.CanBeNull) + { + ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Converter.TypeToConvert); + } + + value = default(T)!; + success = true; + } + else + { + // Optimize for internal converters by avoiding the extra call to TryRead. + if (Converter.CanUseDirectReadOrWrite) + { + value = Converter.Read(ref reader, RuntimePropertyType!, Options); + success = true; + } + else + { + success = Converter.TryRead(ref reader, RuntimePropertyType!, Options, ref state, out T typedValue); + value = typedValue; + } + } + + return success; + } + + public override void SetExtensionDictionaryAsObject(object obj, object? extensionDict) + { + Debug.Assert(HasSetter); + T typedValue = (T)extensionDict!; + Set!(obj, typedValue); + } + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfTTypeToConvert.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfTTypeToConvert.cs deleted file mode 100644 index 5e5f219fedcfd2..00000000000000 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoOfTTypeToConvert.cs +++ /dev/null @@ -1,218 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.Reflection; -using System.Text.Json.Serialization; - -namespace System.Text.Json -{ - /// - /// Represents a strongly-typed property to prevent boxing and to create a direct delegate to the getter\setter. - /// - internal sealed class JsonPropertyInfo : JsonPropertyInfo - { - public Func? Get { get; private set; } - public Action? Set { get; private set; } - - public JsonConverter Converter { get; internal set; } = null!; - - public override void Initialize( - Type parentClassType, - Type declaredPropertyType, - Type? runtimePropertyType, - ClassType runtimeClassType, - PropertyInfo? propertyInfo, - JsonConverter converter, - JsonIgnoreCondition? ignoreCondition, - JsonSerializerOptions options) - { - base.Initialize( - parentClassType, - declaredPropertyType, - runtimePropertyType, - runtimeClassType, - propertyInfo, - converter, - ignoreCondition, - options); - - if (propertyInfo != null) - { - if (propertyInfo.GetMethod?.IsPublic == true) - { - HasGetter = true; - Get = options.MemberAccessorStrategy.CreatePropertyGetter(propertyInfo); - } - - if (propertyInfo.SetMethod?.IsPublic == true) - { - HasSetter = true; - Set = options.MemberAccessorStrategy.CreatePropertySetter(propertyInfo); - } - } - else - { - IsPropertyPolicy = true; - HasGetter = true; - HasSetter = true; - } - - GetPolicies(ignoreCondition); - } - - public override JsonConverter ConverterBase - { - get - { - return Converter; - } - set - { - Debug.Assert(value is JsonConverter); - Converter = (JsonConverter)value; - } - } - - public override object? GetValueAsObject(object obj) - { - if (IsPropertyPolicy) - { - return obj; - } - - Debug.Assert(HasGetter); - return Get!(obj); - } - - public override bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer) - { - Debug.Assert(EscapedName.HasValue); - - bool success; - TTypeToConvert value = Get!(obj); - if (value == null) - { - if (!IgnoreNullValues) - { - writer.WriteNull(EscapedName.Value); - } - - success = true; - } - else - { - if (state.Current.PropertyState < StackFramePropertyState.Name) - { - state.Current.PropertyState = StackFramePropertyState.Name; - writer.WritePropertyName(EscapedName.Value); - } - - success = Converter.TryWrite(writer, value, Options, ref state); - } - - return success; - } - - public override bool GetMemberAndWriteJsonExtensionData(object obj, ref WriteStack state, Utf8JsonWriter writer) - { - bool success; - TTypeToConvert value = Get!(obj); - - if (value == null) - { - success = true; - } - else - { - state.Current.PolymorphicJsonPropertyInfo = state.Current.DeclaredJsonPropertyInfo!.RuntimeClassInfo.ElementClassInfo!.PropertyInfoForClassInfo; - success = Converter.TryWriteDataExtensionProperty(writer, value, Options, ref state); - } - - return success; - } - - public override bool ReadJsonAndSetMember(object obj, ref ReadStack state, ref Utf8JsonReader reader) - { - bool success; - bool isNullToken = reader.TokenType == JsonTokenType.Null; - if (isNullToken && !Converter.HandleNullValue && !state.IsContinuation) - { - if (!IgnoreNullValues) - { - TTypeToConvert value = default; - Set!(obj, value!); - } - - success = true; - } - else - { - // Get the value from the converter and set the property. - if (Converter.CanUseDirectReadOrWrite) - { - // Optimize for internal converters by avoiding the extra call to TryRead. - TTypeToConvert fastvalue = Converter.Read(ref reader, RuntimePropertyType!, Options); - if (!IgnoreNullValues || (!isNullToken && fastvalue != null)) - { - Set!(obj, fastvalue); - } - - return true; - } - else - { - success = Converter.TryRead(ref reader, RuntimePropertyType!, Options, ref state, out TTypeToConvert value); - if (success) - { - if (!IgnoreNullValues || (!isNullToken && value != null)) - { - Set!(obj, value); - } - } - } - } - - return success; - } - - public override bool ReadJsonAsObject(ref ReadStack state, ref Utf8JsonReader reader, out object? value) - { - bool success; - bool isNullToken = reader.TokenType == JsonTokenType.Null; - if (isNullToken && !Converter.HandleNullValue && !state.IsContinuation) - { - value = default(TTypeToConvert)!; - success = true; - } - else - { - // Optimize for internal converters by avoiding the extra call to TryRead. - if (Converter.CanUseDirectReadOrWrite) - { - value = Converter.Read(ref reader, RuntimePropertyType!, Options); - return true; - } - else - { - success = Converter.TryRead(ref reader, RuntimePropertyType!, Options, ref state, out TTypeToConvert typedValue); - value = typedValue; - } - } - - return success; - } - - public override void SetValueAsObject(object obj, object? value) - { - Debug.Assert(HasSetter); - TTypeToConvert typedValue = (TTypeToConvert)value!; - - if (typedValue != null || !IgnoreNullValues) - { - Set!(obj, typedValue); - } - } - } -} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonResumableConverterOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonResumableConverterOfT.cs index e2aabd2ceacb97..9d25d2f38fceb9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonResumableConverterOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonResumableConverterOfT.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; + namespace System.Text.Json.Serialization { /// @@ -11,7 +13,8 @@ namespace System.Text.Json.Serialization /// internal abstract class JsonResumableConverter : JsonConverter { - public override sealed T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + [return: MaybeNull] + public sealed override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // Bridge from resumable to value converters. if (options == null) @@ -25,7 +28,7 @@ public override sealed T Read(ref Utf8JsonReader reader, Type typeToConvert, Jso return value; } - public override sealed void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + public sealed override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { // Bridge from resumable to value converters. if (options == null) @@ -37,5 +40,7 @@ public override sealed void Write(Utf8JsonWriter writer, T value, JsonSerializer state.Initialize(typeof(T), options, supportContinuation: false); TryWrite(writer, value, options, ref state); } + + public sealed override bool HandleNull => false; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleMetadata.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleMetadata.cs index 0e08de715bf7ad..edb6aebf97bd03 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleMetadata.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleMetadata.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Text.Json.Serialization; namespace System.Text.Json @@ -18,14 +19,17 @@ internal static bool ResolveMetadata( ref Utf8JsonReader reader, ref ReadStack state) { - if (state.Current.ObjectState < StackFrameObjectState.MetadataPropertyName) + if (state.Current.ObjectState < StackFrameObjectState.ReadAheadNameOrEndObject) { // Read the first metadata property name. - if (!reader.Read()) + if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadNameOrEndObject)) { return false; } + } + if (state.Current.ObjectState == StackFrameObjectState.ReadNameOrEndObject) + { if (reader.TokenType != JsonTokenType.PropertyName) { // An enumerable needs metadata since it starts with StartObject. @@ -53,7 +57,7 @@ internal static bool ResolveMetadata( ThrowHelper.ThrowJsonException_MetadataCannotParsePreservedObjectIntoImmutable(converter.TypeToConvert); } - state.Current.ObjectState = StackFrameObjectState.MetadataIdProperty; + state.Current.ObjectState = StackFrameObjectState.ReadAheadIdValue; } else if (metadata == MetadataPropertyName.Ref) { @@ -63,7 +67,7 @@ internal static bool ResolveMetadata( ThrowHelper.ThrowJsonException_MetadataInvalidReferenceToValueType(converter.TypeToConvert); } - state.Current.ObjectState = StackFrameObjectState.MetadataRefProperty; + state.Current.ObjectState = StackFrameObjectState.ReadAheadRefValue; } else if (metadata == MetadataPropertyName.Values) { @@ -94,13 +98,23 @@ internal static bool ResolveMetadata( } } - if (state.Current.ObjectState == StackFrameObjectState.MetadataRefProperty) + if (state.Current.ObjectState == StackFrameObjectState.ReadAheadRefValue) { - if (!reader.Read()) + if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadRefValue)) { return false; } + } + else if (state.Current.ObjectState == StackFrameObjectState.ReadAheadIdValue) + { + if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadIdValue)) + { + return false; + } + } + if (state.Current.ObjectState == StackFrameObjectState.ReadRefValue) + { if (reader.TokenType != JsonTokenType.String) { ThrowHelper.ThrowJsonException_MetadataValueWasNotString(reader.TokenType); @@ -110,15 +124,10 @@ internal static bool ResolveMetadata( // todo: https://github.com/dotnet/runtime/issues/32354 state.Current.ReturnValue = state.ReferenceResolver.ResolveReferenceOnDeserialize(key); - state.Current.ObjectState = StackFrameObjectState.MetadataRefPropertyEndObject; + state.Current.ObjectState = StackFrameObjectState.ReadAheadRefEndObject; } - else if (state.Current.ObjectState == StackFrameObjectState.MetadataIdProperty) + else if (state.Current.ObjectState == StackFrameObjectState.ReadIdValue) { - if (!reader.Read()) - { - return false; - } - if (reader.TokenType != JsonTokenType.String) { ThrowHelper.ThrowJsonException_MetadataValueWasNotString(reader.TokenType); @@ -132,23 +141,26 @@ internal static bool ResolveMetadata( if (converter.ClassType == ClassType.Enumerable) { // Need to Read $values property name. - state.Current.ObjectState = StackFrameObjectState.MetadataValuesPropertyName; + state.Current.ObjectState = StackFrameObjectState.ReadAheadValuesName; } else { // We are done reading metadata. - state.Current.ObjectState = StackFrameObjectState.MetadataPropertyValue; + state.Current.ObjectState = StackFrameObjectState.PropertyValue; return true; } } - if (state.Current.ObjectState == StackFrameObjectState.MetadataRefPropertyEndObject) + if (state.Current.ObjectState == StackFrameObjectState.ReadAheadRefEndObject) { - if (!reader.Read()) + if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadRefEndObject)) { return false; } + } + if (state.Current.ObjectState == StackFrameObjectState.ReadRefEndObject) + { if (reader.TokenType != JsonTokenType.EndObject) { // We just read a property. The only valid next tokens are EndObject and PropertyName. @@ -160,13 +172,16 @@ internal static bool ResolveMetadata( return true; } - if (state.Current.ObjectState == StackFrameObjectState.MetadataValuesPropertyName) + if (state.Current.ObjectState == StackFrameObjectState.ReadAheadValuesName) { - if (!reader.Read()) + if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadValuesName)) { return false; } + } + if (state.Current.ObjectState == StackFrameObjectState.ReadValuesName) + { if (reader.TokenType != JsonTokenType.PropertyName) { ThrowHelper.ThrowJsonException_MetadataPreservedArrayValuesNotFound(converter.TypeToConvert); @@ -182,27 +197,39 @@ internal static bool ResolveMetadata( ThrowHelper.ThrowJsonException_MetadataPreservedArrayInvalidProperty(converter.TypeToConvert, reader); } - state.Current.ObjectState = StackFrameObjectState.MetadataValuesPropertyStartArray; + state.Current.ObjectState = StackFrameObjectState.ReadAheadValuesStartArray; } - if (state.Current.ObjectState == StackFrameObjectState.MetadataValuesPropertyStartArray) + if (state.Current.ObjectState == StackFrameObjectState.ReadAheadValuesStartArray) { - if (!reader.Read()) + if (!TryReadAheadMetadataAndSetState(ref reader, ref state, StackFrameObjectState.ReadValuesStartArray)) { return false; } + } + if (state.Current.ObjectState == StackFrameObjectState.ReadValuesStartArray) + { if (reader.TokenType != JsonTokenType.StartArray) { ThrowHelper.ThrowJsonException_MetadataValuesInvalidToken(reader.TokenType); } - state.Current.ObjectState = StackFrameObjectState.MetadataPropertyValue; + state.Current.ObjectState = StackFrameObjectState.PropertyValue; } return true; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryReadAheadMetadataAndSetState(ref Utf8JsonReader reader, ref ReadStack state, StackFrameObjectState nextState) + { + // If we can't read here, the read will be completed at the root API by asking the stream for more data. + // Set the state so we know where to resume on re-entry. + state.Current.ObjectState = nextState; + return reader.Read(); + } + internal static MetadataPropertyName GetMetadataPropertyName(ReadOnlySpan propertyName) { if (propertyName.Length > 0 && propertyName[0] == '$') diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs index 3def5052f81910..b7b4db728865a4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs @@ -27,18 +27,26 @@ internal static JsonPropertyInfo LookupProperty( { Debug.Assert(state.Current.JsonClassInfo.ClassType == ClassType.Object); + useExtensionProperty = false; + ReadOnlySpan unescapedPropertyName = GetPropertyName(ref state, ref reader, options); - JsonPropertyInfo jsonPropertyInfo = state.Current.JsonClassInfo.GetProperty(unescapedPropertyName, ref state.Current); + JsonPropertyInfo jsonPropertyInfo = state.Current.JsonClassInfo.GetProperty( + unescapedPropertyName, + ref state.Current, + out byte[] utf8PropertyName); - // Increment PropertyIndex so GetProperty() starts with the next property the next time this function is called. + // Increment PropertyIndex so GetProperty() checks the next property first when called again. state.Current.PropertyIndex++; + // For case insensitive and missing property support of JsonPath, remember the value on the temporary stack. + state.Current.JsonPropertyName = utf8PropertyName; + // Determine if we should use the extension property. if (jsonPropertyInfo == JsonPropertyInfo.s_missingProperty) { JsonPropertyInfo? dataExtProperty = state.Current.JsonClassInfo.DataExtensionProperty; - if (dataExtProperty != null) + if (dataExtProperty != null && dataExtProperty.HasGetter && dataExtProperty.HasSetter) { state.Current.JsonPropertyNameAsString = JsonHelpers.Utf8GetString(unescapedPropertyName); @@ -50,41 +58,9 @@ internal static JsonPropertyInfo LookupProperty( jsonPropertyInfo = dataExtProperty; useExtensionProperty = true; } - else - { - useExtensionProperty = false; - } - - state.Current.JsonPropertyInfo = jsonPropertyInfo; - return jsonPropertyInfo; } - // Support JsonException.Path. - Debug.Assert( - jsonPropertyInfo.JsonPropertyName == null || - options.PropertyNameCaseInsensitive || - unescapedPropertyName.SequenceEqual(jsonPropertyInfo.JsonPropertyName)); - state.Current.JsonPropertyInfo = jsonPropertyInfo; - - if (jsonPropertyInfo.JsonPropertyName == null) - { - byte[] propertyNameArray = unescapedPropertyName.ToArray(); - if (options.PropertyNameCaseInsensitive) - { - // Each payload can have a different name here; remember the value on the temporary stack. - state.Current.JsonPropertyName = propertyNameArray; - } - else - { - // Prevent future allocs by caching globally on the JsonPropertyInfo which is specific to a Type+PropertyName - // so it will match the incoming payload except when case insensitivity is enabled (which is handled above). - state.Current.JsonPropertyInfo.JsonPropertyName = propertyNameArray; - } - } - - state.Current.JsonPropertyInfo = jsonPropertyInfo; - useExtensionProperty = false; return jsonPropertyInfo; } @@ -146,7 +122,7 @@ internal static void CreateDataExtensionProperty( } extensionData = jsonPropertyInfo.RuntimeClassInfo.CreateObject(); - jsonPropertyInfo.SetValueAsObject(obj, extensionData); + jsonPropertyInfo.SetExtensionDictionaryAsObject(obj, extensionData); } // We don't add the value to the dictionary here because we need to support the read-ahead functionality for Streams. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Helpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Helpers.cs index bfda0563165d3e..bfdbd5993c65b4 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Helpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Helpers.cs @@ -3,13 +3,14 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; -using System.Text.Json.Serialization.Converters; namespace System.Text.Json { public static partial class JsonSerializer { + [return: MaybeNull] private static TValue ReadCore(ref Utf8JsonReader reader, Type returnType, JsonSerializerOptions options) { ReadStack state = default; @@ -18,6 +19,7 @@ private static TValue ReadCore(ref Utf8JsonReader reader, Type returnTyp return ReadCore(jsonConverter, ref reader, options, ref state); } + [return: MaybeNull] private static TValue ReadCore(JsonConverter jsonConverter, ref Utf8JsonReader reader, JsonSerializerOptions options, ref ReadStack state) { if (jsonConverter is JsonConverter converter) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs index 4fbc8f5e37caef..3aacdc8839b403 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Span.cs @@ -2,9 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Text.Json.Serialization; namespace System.Text.Json { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs index c4006a77270213..082c49645379ea 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.String.cs @@ -5,7 +5,6 @@ using System.Buffers; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Text.Json.Serialization; namespace System.Text.Json { @@ -44,7 +43,7 @@ public static TValue Deserialize(string json, JsonSerializerOptions? opt throw new ArgumentNullException(nameof(json)); } - return Deserialize(json, typeof(TValue), options)!; + return Deserialize(json, typeof(TValue), options); } /// @@ -86,6 +85,7 @@ public static TValue Deserialize(string json, JsonSerializerOptions? opt return value; } + [return: MaybeNull] private static TValue Deserialize(string json, Type returnType, JsonSerializerOptions? options) { const long ArrayPoolMaxSizeBeforeUsingNormalAlloc = 1024 * 1024; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Utf8JsonReader.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Utf8JsonReader.cs index b7182ede223aa2..666a6847094a30 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Utf8JsonReader.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Utf8JsonReader.cs @@ -14,6 +14,7 @@ public static partial class JsonSerializer /// /// Internal version that allows re-entry with preserving ReadStack so that JsonPath works correctly. /// + [return: MaybeNull] internal static TValue Deserialize(ref Utf8JsonReader reader, JsonSerializerOptions options, ref ReadStack state, string? propertyName = null) { if (options == null) @@ -162,6 +163,7 @@ private static void CheckSupportedOptions(JsonReaderOptions readerOptions, strin } } + [return: MaybeNull] private static TValue ReadValueCore(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack state) { JsonReaderState readerState = reader.CurrentState; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerDefaults.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerDefaults.cs new file mode 100644 index 00000000000000..7df69c390daa7b --- /dev/null +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerDefaults.cs @@ -0,0 +1,27 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Text.Json +{ + /// + /// Signifies what default options are used by . + /// + public enum JsonSerializerDefaults + { + /// + /// Specifies that general-purpose values should be used. These are the same settings applied if a isn't specified. + /// + /// + /// This option implies that property names are treated as case-sensitive and that "PascalCase" name formatting should be employed. + /// + General = 0, + /// + /// Specifies that values should be used more appropriate to web-based scenarios. + /// + /// + /// This option implies that property names are treated as case-insensitive and that "camelCase" name formatting should be employed. + /// + Web = 1 + } +} diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 7d4c82beb69db6..05b2aec0a2faa3 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Concurrent; +using System.ComponentModel; using System.Diagnostics; using System.Text.Json.Serialization; using System.Text.Encodings.Web; @@ -28,6 +29,7 @@ public sealed partial class JsonSerializerOptions private JsonCommentHandling _readCommentHandling; private ReferenceHandling _referenceHandling = ReferenceHandling.Default; private JavaScriptEncoder? _encoder = null; + private JsonIgnoreCondition _defaultIgnoreCondition; private int _defaultBufferSize = BufferSizeDefault; private int _maxDepth; @@ -60,12 +62,13 @@ public JsonSerializerOptions(JsonSerializerOptions options) throw new ArgumentNullException(nameof(options)); } - _memberAccessorStrategy = options.MemberAccessorStrategy; + _memberAccessorStrategy = options._memberAccessorStrategy; _dictionaryKeyPolicy = options._dictionaryKeyPolicy; _jsonPropertyNamingPolicy = options._jsonPropertyNamingPolicy; _readCommentHandling = options._readCommentHandling; _referenceHandling = options._referenceHandling; _encoder = options._encoder; + _defaultIgnoreCondition = options._defaultIgnoreCondition; _defaultBufferSize = options._defaultBufferSize; _maxDepth = options._maxDepth; @@ -81,7 +84,24 @@ public JsonSerializerOptions(JsonSerializerOptions options) // _classes is not copied as sharing the JsonClassInfo and JsonPropertyInfo caches can result in // unnecessary references to type metadata, potentially hindering garbage collection on the source options. - // _haveTypesBeenCreated is not copied; it's okay to make changes to this options instance as (de)serialization has not occured. + // _haveTypesBeenCreated is not copied; it's okay to make changes to this options instance as (de)serialization has not occurred. + } + + /// + /// Constructs a new instance with a predefined set of options determined by the specified . + /// + /// The to reason about. + public JsonSerializerOptions(JsonSerializerDefaults defaults) : this() + { + if (defaults == JsonSerializerDefaults.Web) + { + _propertyNameCaseInsensitive = true; + _jsonPropertyNamingPolicy = JsonNamingPolicy.CamelCase; + } + else if (defaults != JsonSerializerDefaults.General) + { + throw new ArgumentOutOfRangeException(nameof(defaults)); + } } /// @@ -177,7 +197,10 @@ public JsonNamingPolicy? DictionaryKeyPolicy /// /// /// Thrown if this property is set after serialization or deserialization has occurred. + /// or has been set to a non-default value. These properties cannot be used together. /// + [Obsolete("To ignore null values when serializing, set DefaultIgnoreCondition to JsonIgnoreCondition.WhenWritingDefault.", error: false)] + [EditorBrowsable(EditorBrowsableState.Never)] public bool IgnoreNullValues { get @@ -187,10 +210,52 @@ public bool IgnoreNullValues set { VerifyMutable(); + + if (value && _defaultIgnoreCondition != JsonIgnoreCondition.Never) + { + Debug.Assert(_defaultIgnoreCondition == JsonIgnoreCondition.WhenWritingDefault); + throw new InvalidOperationException(SR.DefaultIgnoreConditionAlreadySpecified); + } + _ignoreNullValues = value; } } + /// + /// Specifies a condition to determine when properties with default values are ignored during serialization or deserialization. + /// The default value is . + /// + /// + /// Thrown if this property is set to . + /// + /// + /// Thrown if this property is set after serialization or deserialization has occurred, + /// or has been set to . These properties cannot be used together. + /// + public JsonIgnoreCondition DefaultIgnoreCondition + { + get + { + return _defaultIgnoreCondition; + } + set + { + VerifyMutable(); + + if (value == JsonIgnoreCondition.Always) + { + throw new ArgumentException(SR.DefaultIgnoreConditionInvalid); + } + + if (value != JsonIgnoreCondition.Never && _ignoreNullValues) + { + throw new InvalidOperationException(SR.DefaultIgnoreConditionAlreadySpecified); + } + + _defaultIgnoreCondition = value; + } + } + /// /// Determines whether read-only properties are ignored during serialization. /// A property is read-only if it contains a public getter but not a public setter. @@ -377,17 +442,17 @@ internal JsonClassInfo GetOrAddClass(Type type) // https://github.com/dotnet/runtime/issues/32357 if (!_classes.TryGetValue(type, out JsonClassInfo? result)) { - if (type.ContainsGenericParameters) - { - ThrowHelper.ThrowInvalidOperationException_CannotSerializeOpenGeneric(type); - } - result = _classes.GetOrAdd(type, new JsonClassInfo(type, this)); } return result; } + internal bool TypeIsCached(Type type) + { + return _classes.ContainsKey(type); + } + internal JsonReaderOptions GetReaderOptions() { return new JsonReaderOptions diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonValueConverterOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonValueConverterOfT.cs index 5332509163f1dc..67fa8c46bfeee6 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonValueConverterOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonValueConverterOfT.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics.CodeAnalysis; + namespace System.Text.Json.Serialization { // Used for value converters that need to re-enter the serializer since it will support JsonPath @@ -10,7 +12,10 @@ internal abstract class JsonValueConverter : JsonConverter { internal sealed override ClassType ClassType => ClassType.NewValue; - public override sealed T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public sealed override bool HandleNull => false; + + [return: MaybeNull] + public sealed override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // Bridge from resumable to value converters. if (options == null) @@ -24,7 +29,7 @@ public override sealed T Read(ref Utf8JsonReader reader, Type typeToConvert, Jso return value; } - public override sealed void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + public sealed override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { // Bridge from resumable to value converters. if (options == null) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ParameterRef.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ParameterRef.cs index 9f2c654b5a9134..f0ee05b6436ae6 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ParameterRef.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ParameterRef.cs @@ -6,15 +6,18 @@ namespace System.Text.Json { internal readonly struct ParameterRef { - public ParameterRef(ulong key, JsonParameterInfo info) + public ParameterRef(ulong key, JsonParameterInfo info, byte[] nameFromJson) { Key = key; Info = info; + NameFromJson = nameFromJson; } - // The first 6 bytes are the first part of the name and last 2 bytes are the name's length. public readonly ulong Key; public readonly JsonParameterInfo Info; + + // NameFromJson may be different than Info.NameAsUtf8Bytes when case insensitive is enabled. + public readonly byte[] NameFromJson; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/PropertyRef.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/PropertyRef.cs index 41dbbe5e411e26..e092a7cfe5cdde 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/PropertyRef.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/PropertyRef.cs @@ -6,15 +6,17 @@ namespace System.Text.Json { internal readonly struct PropertyRef { - public PropertyRef(ulong key, JsonPropertyInfo info) + public PropertyRef(ulong key, JsonPropertyInfo info, byte[] nameFromJson) { Key = key; Info = info; + NameFromJson = nameFromJson; } - // The first 6 bytes are the first part of the name and last 2 bytes are the name's length. public readonly ulong Key; - public readonly JsonPropertyInfo Info; + + // NameFromJson may be different than Info.NameAsUtf8Bytes when case insensitive is enabled. + public readonly byte[] NameFromJson; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStack.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStack.cs index 3a9e0dddf145dd..7e7f497a536cb9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStack.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReadStack.cs @@ -298,8 +298,9 @@ static void AppendPropertyName(StringBuilder sb, string? propertyName) if (utf8PropertyName == null) { // Attempt to get the JSON property name from the JsonPropertyInfo or JsonParameterInfo. - utf8PropertyName = frame.JsonPropertyInfo?.JsonPropertyName ?? - frame.CtorArgumentState?.JsonParameterInfo?.JsonPropertyName; + utf8PropertyName = frame.JsonPropertyInfo?.NameAsUtf8Bytes ?? + frame.CtorArgumentState?.JsonParameterInfo?.NameAsUtf8Bytes; + if (utf8PropertyName == null) { // Attempt to get the JSON property name set manually for dictionary diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReferenceHandling.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReferenceHandling.cs index 2928b0f2758141..269e0cb84b1bb1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReferenceHandling.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReferenceHandling.cs @@ -53,8 +53,8 @@ public sealed class ReferenceHandling /// public static ReferenceHandling Preserve { get; } = new ReferenceHandling(PreserveReferencesHandling.All); - private readonly PreserveReferencesHandling _preserveHandlingOnSerialize; - private readonly PreserveReferencesHandling _preserveHandlingOnDeserialize; + private readonly bool _shouldReadPreservedReferences; + private readonly bool _shouldWritePreservedReferences; /// /// Creates a new instance of using the specified @@ -65,18 +65,18 @@ private ReferenceHandling(PreserveReferencesHandling handling) : this(handling, // For future, someone may want to define their own custom Handler with different behaviors of PreserveReferenceHandling on Serialize vs Deserialize. private ReferenceHandling(PreserveReferencesHandling preserveHandlingOnSerialize, PreserveReferencesHandling preserveHandlingOnDeserialize) { - _preserveHandlingOnSerialize = preserveHandlingOnSerialize; - _preserveHandlingOnDeserialize = preserveHandlingOnDeserialize; + _shouldReadPreservedReferences = preserveHandlingOnDeserialize == PreserveReferencesHandling.All; + _shouldWritePreservedReferences = preserveHandlingOnSerialize == PreserveReferencesHandling.All; } internal bool ShouldReadPreservedReferences() { - return _preserveHandlingOnDeserialize == PreserveReferencesHandling.All; + return _shouldReadPreservedReferences; } internal bool ShouldWritePreservedReferences() { - return _preserveHandlingOnSerialize == PreserveReferencesHandling.All; + return _shouldWritePreservedReferences; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs index 3e34ada077cdaf..a5d53eee033c13 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs @@ -5,6 +5,7 @@ #if NETFRAMEWORK || NETCOREAPP using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Reflection.Emit; @@ -56,14 +57,16 @@ internal sealed class ReflectionEmitMemberAccessor : MemberAccessor return (JsonClassInfo.ConstructorDelegate)dynamicMethod.CreateDelegate(typeof(JsonClassInfo.ConstructorDelegate)); } - public override JsonClassInfo.ParameterizedConstructorDelegate? CreateParameterizedConstructor(ConstructorInfo constructor) + public override JsonClassInfo.ParameterizedConstructorDelegate? CreateParameterizedConstructor(ConstructorInfo constructor) => + CreateDelegate>(CreateParameterizedConstructor(constructor)); + + private static DynamicMethod? CreateParameterizedConstructor(ConstructorInfo constructor) { - Type type = typeof(T); + Type? type = constructor.DeclaringType; + Debug.Assert(type != null); Debug.Assert(!type.IsAbstract); - // If ctor is non-public, we've verified upstream that it has the [JsonConstructorAttribute]. - Debug.Assert(type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) - .Contains(constructor)); + Debug.Assert(type.GetConstructors(BindingFlags.Public | BindingFlags.Instance).Contains(constructor)); ParameterInfo[] parameters = constructor.GetParameters(); int parameterCount = parameters.Length; @@ -89,42 +92,35 @@ internal sealed class ReflectionEmitMemberAccessor : MemberAccessor generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldc_I4_S, i); generator.Emit(OpCodes.Ldelem_Ref); - - if (paramType.IsValueType) - { - generator.Emit(OpCodes.Unbox_Any, paramType); - } - else - { - generator.Emit(OpCodes.Castclass, paramType); - }; + generator.Emit(OpCodes.Unbox_Any, paramType); } generator.Emit(OpCodes.Newobj, constructor); generator.Emit(OpCodes.Ret); - return (JsonClassInfo.ParameterizedConstructorDelegate)dynamicMethod.CreateDelegate(typeof(JsonClassInfo.ParameterizedConstructorDelegate)); + return dynamicMethod; } public override JsonClassInfo.ParameterizedConstructorDelegate? - CreateParameterizedConstructor(ConstructorInfo constructor) + CreateParameterizedConstructor(ConstructorInfo constructor) => + CreateDelegate>( + CreateParameterizedConstructor(constructor, typeof(TArg0), typeof(TArg1), typeof(TArg2), typeof(TArg3))); + + private static DynamicMethod? CreateParameterizedConstructor(ConstructorInfo constructor, Type parameterType1, Type parameterType2, Type parameterType3, Type parameterType4) { - Type type = typeof(T); + Type? type = constructor.DeclaringType; + Debug.Assert(type != null); Debug.Assert(!type.IsAbstract); - // If ctor is non-public, we've verified upstream that it has the [JsonConstructorAttribute]. - Debug.Assert(type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) - .Contains(constructor)); + Debug.Assert(type.GetConstructors(BindingFlags.Public | BindingFlags.Instance).Contains(constructor)); ParameterInfo[] parameters = constructor.GetParameters(); int parameterCount = parameters.Length; - Debug.Assert(parameterCount <= JsonConstants.UnboxedParameterCountThreshold); - var dynamicMethod = new DynamicMethod( ConstructorInfo.ConstructorName, type, - new[] { typeof(TArg0), typeof(TArg1), typeof(TArg2), typeof(TArg3) }, + new[] { parameterType1, parameterType2, parameterType3, parameterType4 }, typeof(ReflectionEmitMemberAccessor).Module, skipVisibility: true); @@ -132,46 +128,37 @@ public override JsonClassInfo.ParameterizedConstructorDelegate OpCodes.Ldarg_0, + 1 => OpCodes.Ldarg_1, + 2 => OpCodes.Ldarg_2, + 3 => OpCodes.Ldarg_3, + _ => throw new InvalidOperationException() + }); } generator.Emit(OpCodes.Newobj, constructor); generator.Emit(OpCodes.Ret); - return (JsonClassInfo.ParameterizedConstructorDelegate) - dynamicMethod.CreateDelegate( - typeof(JsonClassInfo.ParameterizedConstructorDelegate)); + return dynamicMethod; } - public override Action CreateAddMethodDelegate() - { - Type collectionType = typeof(TCollection); - Type elementType = typeof(object); + public override Action CreateAddMethodDelegate() => + CreateDelegate>(CreateAddMethodDelegate(typeof(TCollection))); + private static DynamicMethod CreateAddMethodDelegate(Type collectionType) + { // We verified this won't be null when we created the converter that calls this method. MethodInfo realMethod = (collectionType.GetMethod("Push") ?? collectionType.GetMethod("Enqueue"))!; var dynamicMethod = new DynamicMethod( realMethod.Name, typeof(void), - new[] { collectionType, elementType }, + new[] { collectionType, typeof(object) }, typeof(ReflectionEmitMemberAccessor).Module, skipVisibility: true); @@ -182,18 +169,21 @@ public override JsonClassInfo.ParameterizedConstructorDelegate)dynamicMethod.CreateDelegate(typeof(Action)); + return dynamicMethod; } - public override Func, TCollection> CreateImmutableEnumerableCreateRangeDelegate() + public override Func, TCollection> CreateImmutableEnumerableCreateRangeDelegate() => + CreateDelegate, TCollection>>( + CreateImmutableEnumerableCreateRangeDelegate(typeof(TCollection), typeof(TElement), typeof(IEnumerable))); + + private static DynamicMethod CreateImmutableEnumerableCreateRangeDelegate(Type collectionType, Type elementType, Type enumerableType) { - Type collectionType = typeof(TCollection); - MethodInfo realMethod = collectionType.GetImmutableEnumerableCreateRangeMethod(typeof(TElement)); + MethodInfo realMethod = collectionType.GetImmutableEnumerableCreateRangeMethod(elementType); var dynamicMethod = new DynamicMethod( realMethod.Name, collectionType, - new[] { typeof(IEnumerable) }, + new[] { enumerableType }, typeof(ReflectionEmitMemberAccessor).Module, skipVisibility: true); @@ -203,18 +193,21 @@ public override Func, TCollection> CreateImmutableEnumerab generator.Emit(OpCodes.Call, realMethod); generator.Emit(OpCodes.Ret); - return (Func, TCollection>)dynamicMethod.CreateDelegate(typeof(Func, TCollection>)); + return dynamicMethod; } - public override Func>, TCollection> CreateImmutableDictionaryCreateRangeDelegate() + public override Func>, TCollection> CreateImmutableDictionaryCreateRangeDelegate() => + CreateDelegate>, TCollection>>( + CreateImmutableDictionaryCreateRangeDelegate(typeof(TCollection), typeof(TElement), typeof(IEnumerable>))); + + private static DynamicMethod CreateImmutableDictionaryCreateRangeDelegate(Type collectionType, Type elementType, Type enumerableType) { - Type collectionType = typeof(TCollection); - MethodInfo realMethod = collectionType.GetImmutableDictionaryCreateRangeMethod(typeof(TElement)); + MethodInfo realMethod = collectionType.GetImmutableDictionaryCreateRangeMethod(elementType); var dynamicMethod = new DynamicMethod( realMethod.Name, collectionType, - new[] { typeof(IEnumerable>) }, + new[] { enumerableType }, typeof(ReflectionEmitMemberAccessor).Module, skipVisibility: true); @@ -224,15 +217,15 @@ public override Func>, TCollection> C generator.Emit(OpCodes.Call, realMethod); generator.Emit(OpCodes.Ret); - return (Func>, TCollection>)dynamicMethod.CreateDelegate(typeof(Func>, TCollection>)); + return dynamicMethod; } public override Func CreatePropertyGetter(PropertyInfo propertyInfo) => - (Func)CreatePropertyGetter(propertyInfo, propertyInfo.DeclaringType!, typeof(TProperty)); + CreateDelegate>(CreatePropertyGetter(propertyInfo, propertyInfo.DeclaringType!, typeof(TProperty))); - private static Delegate CreatePropertyGetter(PropertyInfo propertyInfo, Type classType, Type propertyType) + private static DynamicMethod CreatePropertyGetter(PropertyInfo propertyInfo, Type classType, Type propertyType) { - MethodInfo? realMethod = propertyInfo.GetGetMethod(); + MethodInfo? realMethod = propertyInfo.GetMethod; Type objectType = typeof(object); Debug.Assert(realMethod != null); @@ -260,15 +253,15 @@ private static Delegate CreatePropertyGetter(PropertyInfo propertyInfo, Type cla generator.Emit(OpCodes.Ret); - return dynamicMethod.CreateDelegate(typeof(Func<,>).MakeGenericType(objectType, propertyType)); + return dynamicMethod; } public override Action CreatePropertySetter(PropertyInfo propertyInfo) => - (Action)CreatePropertySetter(propertyInfo, propertyInfo.DeclaringType!, typeof(TProperty)); + CreateDelegate>(CreatePropertySetter(propertyInfo, propertyInfo.DeclaringType!, typeof(TProperty))); - private static Delegate CreatePropertySetter(PropertyInfo propertyInfo, Type classType, Type propertyType) + private static DynamicMethod CreatePropertySetter(PropertyInfo propertyInfo, Type classType, Type propertyType) { - MethodInfo? realMethod = propertyInfo.GetSetMethod(); + MethodInfo? realMethod = propertyInfo.SetMethod; Type objectType = typeof(object); Debug.Assert(realMethod != null); @@ -298,8 +291,12 @@ private static Delegate CreatePropertySetter(PropertyInfo propertyInfo, Type cla generator.Emit(OpCodes.Ret); - return dynamicMethod.CreateDelegate(typeof(Action<,>).MakeGenericType(objectType, propertyType)); + return dynamicMethod; } + + [return: NotNullIfNotNull("method")] + private static T? CreateDelegate(DynamicMethod? method) where T : Delegate => + (T?)method?.CreateDelegate(typeof(T)); } } #endif diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionMemberAccessor.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionMemberAccessor.cs index db8e8573b39353..b8295c5b300a5f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionMemberAccessor.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionMemberAccessor.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Globalization; using System.Linq; using System.Reflection; @@ -35,9 +34,7 @@ internal sealed class ReflectionMemberAccessor : MemberAccessor Type type = typeof(T); Debug.Assert(!type.IsAbstract); - // If ctor is non-public, we've verified upstream that it has the [JsonConstructorAttribute]. - Debug.Assert(type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) - .Contains(constructor)); + Debug.Assert(type.GetConstructors(BindingFlags.Public | BindingFlags.Instance).Contains(constructor)); int parameterCount = constructor.GetParameters().Length; @@ -77,9 +74,7 @@ public override JsonClassInfo.ParameterizedConstructorDelegate>, TCollection> C public override Func CreatePropertyGetter(PropertyInfo propertyInfo) { - MethodInfo getMethodInfo = propertyInfo.GetGetMethod()!; + MethodInfo getMethodInfo = propertyInfo.GetMethod!; return delegate (object obj) { @@ -155,7 +150,7 @@ public override Func CreatePropertyGetter(Property public override Action CreatePropertySetter(PropertyInfo propertyInfo) { - MethodInfo setMethodInfo = propertyInfo.GetSetMethod()!; + MethodInfo setMethodInfo = propertyInfo.SetMethod!; return delegate (object obj, TProperty value) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/StackFrameObjectState.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/StackFrameObjectState.cs index a1530ab5621d98..c99492fad3d75a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/StackFrameObjectState.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/StackFrameObjectState.cs @@ -14,13 +14,22 @@ internal enum StackFrameObjectState : byte StartToken, - MetadataPropertyName, // Read the first $id or $ref. - MetadataIdProperty, // Read value for $id. - MetadataRefProperty, // Read value for $ref. - MetadataRefPropertyEndObject, // Read EndObject for $ref. - MetadataValuesPropertyName, // Read $values property name. - MetadataValuesPropertyStartArray, // Read StartArray for $values. - MetadataPropertyValue, // Whether all metadata properties has been read. + ReadAheadNameOrEndObject, // Try to move the reader to the the first $id, $ref, or the EndObject token. + ReadNameOrEndObject, // Read the first $id, $ref, or the EndObject token. + + ReadAheadIdValue, // Try to move the reader to the value for $id. + ReadAheadRefValue, // Try to move the reader to the value for $ref. + ReadIdValue, // Read value for $id. + ReadRefValue, // Read value for $ref. + ReadAheadRefEndObject, // Try to move the reader to the EndObject for $ref. + ReadRefEndObject, // Read the EndObject for $ref. + + ReadAheadValuesName, // Try to move the reader to the $values property name. + ReadValuesName, // Read $values property name. + ReadAheadValuesStartArray, // Try to move the reader to the StartArray for $values. + ReadValuesStartArray, // Read the StartArray for $values. + + PropertyValue, // Whether all metadata properties has been read. CreatedObject, ReadElements, diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs index f643ffbff8f63a..0d7bd68400ee44 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs @@ -94,9 +94,16 @@ public static void ThrowJsonException(string? message = null) [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] - public static void ThrowInvalidOperationException_CannotSerializeOpenGeneric(Type type) + public static void ThrowInvalidOperationException_CannotSerializeInvalidType(Type type, Type? parentClassType, PropertyInfo? propertyInfo) { - throw new InvalidOperationException(SR.Format(SR.CannotSerializeOpenGeneric, type)); + if (parentClassType == null) + { + Debug.Assert(propertyInfo == null); + throw new InvalidOperationException(SR.Format(SR.CannotSerializeInvalidType, type)); + } + + Debug.Assert(propertyInfo != null); + throw new InvalidOperationException(SR.Format(SR.CannotSerializeInvalidMember, type, propertyInfo.Name, parentClassType)); } [DoesNotReturn] @@ -156,9 +163,9 @@ public static void ThrowInvalidOperationException_SerializerPropertyNameNull(Typ [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] - public static void ThrowInvalidOperationException_SerializerDictionaryKeyNull(Type policyType) + public static void ThrowInvalidOperationException_NamingPolicyReturnNull(JsonNamingPolicy namingPolicy) { - throw new InvalidOperationException(SR.Format(SR.SerializerDictionaryKeyNull, policyType)); + throw new InvalidOperationException(SR.Format(SR.NamingPolicyReturnNull, namingPolicy)); } [DoesNotReturn] @@ -203,6 +210,13 @@ public static void ThrowInvalidOperationException_ExtensionDataCannotBindToCtorP throw new InvalidOperationException(SR.Format(SR.ExtensionDataCannotBindToCtorParam, propertyInfo, classType, constructorInfo)); } + [DoesNotReturn] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(PropertyInfo propertyInfo, Type parentType) + { + throw new InvalidOperationException(SR.Format(SR.JsonIncludeOnNonPublicInvalid, propertyInfo.Name, parentType)); + } + [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowNotSupportedException_ObjectWithParameterizedCtorRefMetadataNotHonored( @@ -409,16 +423,27 @@ public static void ThrowNotSupportedException(in WriteStack state, NotSupportedE [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] - public static void ThrowNotSupportedException_DeserializeNoDeserializationConstructor(Type invalidType) + public static void ThrowNotSupportedException_DeserializeNoConstructor(Type type, ref Utf8JsonReader reader, ref ReadStack state) { - if (invalidType.IsInterface) + string message; + + if (type.IsInterface) { - throw new NotSupportedException(SR.Format(SR.DeserializePolymorphicInterface, invalidType)); + message = SR.Format(SR.DeserializePolymorphicInterface, type); } else { - throw new NotSupportedException(SR.Format(SR.DeserializeMissingDeserializationConstructor, nameof(JsonConstructorAttribute), invalidType)); + message = SR.Format(SR.DeserializeNoConstructor, nameof(JsonConstructorAttribute), type); } + + ThrowNotSupportedException(state, reader, new NotSupportedException(message)); + } + + [DoesNotReturn] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void ThrowNotSupportedException_CannotPopulateCollection(Type type, ref Utf8JsonReader reader, ref ReadStack state) + { + ThrowNotSupportedException(state, reader, new NotSupportedException(SR.Format(SR.CannotPopulateCollection, type))); } [DoesNotReturn] diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.cs index 9ba41e024b4b35..16c00a80f8f210 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/Utf8JsonWriter.cs @@ -78,13 +78,7 @@ public sealed partial class Utf8JsonWriter : IDisposable, IAsyncDisposable /// the which indicates whether to format the output /// while writing and whether to skip structural JSON validation or not. /// - public JsonWriterOptions Options - { - get - { - return _options; - } - } + public JsonWriterOptions Options => _options; private int Indentation => CurrentDepth * JsonConstants.SpacesPerIndent; @@ -107,21 +101,7 @@ public JsonWriterOptions Options public Utf8JsonWriter(IBufferWriter bufferWriter, JsonWriterOptions options = default) { _output = bufferWriter ?? throw new ArgumentNullException(nameof(bufferWriter)); - _stream = default; - _arrayBufferWriter = default; - - BytesPending = default; - BytesCommitted = default; - _memory = default; - - _inObject = default; - _tokenType = default; - _currentDepth = default; _options = options; - - // Only allocate if the user writes a JSON payload beyond the depth that the _allocationFreeContainer can handle. - // This way we avoid allocations in the common, default cases, and allocate lazily. - _bitStack = default; } /// @@ -142,21 +122,8 @@ public Utf8JsonWriter(Stream utf8Json, JsonWriterOptions options = default) throw new ArgumentException(SR.StreamNotWritable); _stream = utf8Json; - _arrayBufferWriter = new ArrayBufferWriter(); - _output = default; - - BytesPending = default; - BytesCommitted = default; - _memory = default; - - _inObject = default; - _tokenType = default; - _currentDepth = default; _options = options; - - // Only allocate if the user writes a JSON payload beyond the depth that the _allocationFreeContainer can handle. - // This way we avoid allocations in the common, default cases, and allocate lazily. - _bitStack = default; + _arrayBufferWriter = new ArrayBufferWriter(); } /// @@ -249,8 +216,6 @@ private void ResetHelper() _tokenType = default; _currentDepth = default; - // Only allocate if the user writes a JSON payload beyond the depth that the _allocationFreeContainer can handle. - // This way we avoid allocations in the common, default cases, and allocate lazily. _bitStack = default; } diff --git a/src/libraries/System.Text.Json/tests/JsonDateTimeTestData.cs b/src/libraries/System.Text.Json/tests/JsonDateTimeTestData.cs index 7ff20c7e1c1257..d172726159a2d0 100644 --- a/src/libraries/System.Text.Json/tests/JsonDateTimeTestData.cs +++ b/src/libraries/System.Text.Json/tests/JsonDateTimeTestData.cs @@ -42,7 +42,6 @@ public static IEnumerable ValidISO8601Tests() yield return new object[] { "\"1997-07-16T19:20:30.6666660\"", "1997-07-16T19:20:30.666666" }; // Test fraction truncation. - yield return new object[] { "\"1997-07-16T19:20:30.0000000\"", "1997-07-16T19:20:30" }; yield return new object[] { "\"1997-07-16T19:20:30.00000001\"", "1997-07-16T19:20:30" }; yield return new object[] { "\"1997-07-16T19:20:30.000000001\"", "1997-07-16T19:20:30" }; yield return new object[] { "\"1997-07-16T19:20:30.77777770\"", "1997-07-16T19:20:30.7777777" }; @@ -153,7 +152,6 @@ public static IEnumerable InvalidISO8601Tests() // Invalid fractions. yield return new object[] { "\"1997-07-16T19.45\"" }; yield return new object[] { "\"1997-07-16T19:20.45\"" }; - yield return new object[] { "\"1997-07-16T19:20:30a\"" }; yield return new object[] { "\"1997-07-16T19:20:30,45\"" }; yield return new object[] { "\"1997-07-16T19:20:30.\"" }; yield return new object[] { "\"1997-07-16T19:20:30.a\"" }; @@ -168,7 +166,6 @@ public static IEnumerable InvalidISO8601Tests() yield return new object[] { "\"1997-07-16T19:20:30.4555555+01Z\"" }; yield return new object[] { "\"1997-07-16T19:20:30.4555555+01:\"" }; yield return new object[] { "\"1997-07-16T19:20:30.4555555 +01:00\"" }; - yield return new object[] { "\"1997-07-16T19:20:30.4555555+01:\"" }; yield return new object[] { "\"1997-07-16T19:20:30.4555555- 01:00\"" }; yield return new object[] { "\"1997-07-16T19:20:30.4555555+04 :30\"" }; yield return new object[] { "\"1997-07-16T19:20:30.4555555-04: 30\"" }; diff --git a/src/libraries/System.Text.Json/tests/JsonDocumentTests.cs b/src/libraries/System.Text.Json/tests/JsonDocumentTests.cs index 74bf86077850bf..e7437c3c5fdf0e 100644 --- a/src/libraries/System.Text.Json/tests/JsonDocumentTests.cs +++ b/src/libraries/System.Text.Json/tests/JsonDocumentTests.cs @@ -2229,6 +2229,24 @@ public static void TestDepthInvalid(int depth) }); } + [Theory] + [InlineData("{ \"object\": { \"1-1\": null, \"1-2\": \"12\", }, \"array\": [ 4, 8, 1, 9, 2 ] }")] + [InlineData("[ 5, 4, 3, 2, 1, ]")] + [InlineData("{ \"shape\": \"square\", \"size\": 10, \"color\": \"green\", }")] + public static void TrailingCommas(string json) + { + var options = new JsonDocumentOptions + { + AllowTrailingCommas = true + }; + + using (JsonDocument doc = JsonDocument.Parse(json, options)) + { + Assert.Equal(json, doc.RootElement.GetRawText()); + } + Assert.ThrowsAny(() => JsonDocument.Parse(json)); + } + [Fact] public static void GetPropertyByNullName() { diff --git a/src/libraries/System.Text.Json/tests/JsonGuidTestData.cs b/src/libraries/System.Text.Json/tests/JsonGuidTestData.cs index 26fd675487085e..bb74e59511b340 100644 --- a/src/libraries/System.Text.Json/tests/JsonGuidTestData.cs +++ b/src/libraries/System.Text.Json/tests/JsonGuidTestData.cs @@ -35,16 +35,40 @@ public static IEnumerable ValidHexGuidTests() public static IEnumerable InvalidGuidTests() { + // Invalid formats + Guid testGuid = new Guid(s_guidStr); + yield return new object[] { testGuid.ToString("B", CultureInfo.InvariantCulture) }; + yield return new object[] { testGuid.ToString("P", CultureInfo.InvariantCulture) }; + yield return new object[] { testGuid.ToString("N", CultureInfo.InvariantCulture) }; + + yield return new object[] { new string('$', 1) }; + yield return new object[] { new string(' ', 1) }; + yield return new object[] { new string('$', s_guidStr.Length) }; + yield return new object[] { new string(' ', s_guidStr.Length) }; + + for (int truncationPoint = 1; truncationPoint < s_guidStr.Length - 1; truncationPoint++) + { + string truncatedText = s_guidStr.Substring(0, truncationPoint); + + // Stop short + yield return new object[] { truncatedText }; + + // Append junk + yield return new object[] { truncatedText.PadRight(s_guidStr.Length, '$') }; + yield return new object[] { truncatedText.PadRight(s_guidStr.Length, ' ') }; + yield return new object[] { truncatedText.PadRight(truncatedText.Length + 1, '$') }; + yield return new object[] { truncatedText.PadRight(truncatedText.Length + 1, ' ') }; + // Prepend junk + yield return new object[] { truncatedText.PadLeft(s_guidStr.Length, '$') }; + yield return new object[] { truncatedText.PadLeft(s_guidStr.Length, ' ') }; + yield return new object[] { truncatedText.PadLeft(truncatedText.Length + 1, '$') }; + yield return new object[] { truncatedText.PadLeft(truncatedText.Length + 1, ' ') }; + } + foreach (object[] guid in ValidGuidTests()) { string guidStr = (string)guid[0]; - // Invalid formats - Guid testGuid = new Guid(guidStr); - yield return new object[] { testGuid.ToString("B", CultureInfo.InvariantCulture) }; - yield return new object[] { testGuid.ToString("P", CultureInfo.InvariantCulture) }; - yield return new object[] { testGuid.ToString("N", CultureInfo.InvariantCulture) }; - for (int i = 0; i < guidStr.Length; i++) { // Corrupt one character @@ -72,25 +96,6 @@ public static IEnumerable InvalidGuidTests() } } - for (int truncationPoint = 0; truncationPoint < guidStr.Length; truncationPoint++) - { - string truncatedText = guidStr.Substring(0, truncationPoint); - - // Stop short - yield return new object[] { truncatedText }; - - // Append junk - yield return new object[] { truncatedText.PadRight(guidStr.Length, '$') }; - yield return new object[] { truncatedText.PadRight(guidStr.Length, ' ') }; - yield return new object[] { truncatedText.PadRight(truncatedText.Length + 1, '$') }; - yield return new object[] { truncatedText.PadRight(truncatedText.Length + 1, ' ') }; - // Prepend junk - yield return new object[] { truncatedText.PadLeft(guidStr.Length, '$') }; - yield return new object[] { truncatedText.PadLeft(guidStr.Length, ' ') }; - yield return new object[] { truncatedText.PadLeft(truncatedText.Length + 1, '$') }; - yield return new object[] { truncatedText.PadLeft(truncatedText.Length + 1, ' ') }; - } - // Too long yield return new object[] { $"{guidStr} " }; yield return new object[] { $"{guidStr}$" }; diff --git a/src/libraries/System.Text.Json/tests/JsonTestHelper.cs b/src/libraries/System.Text.Json/tests/JsonTestHelper.cs index 06ab14adf457aa..1f31adc4915ea3 100644 --- a/src/libraries/System.Text.Json/tests/JsonTestHelper.cs +++ b/src/libraries/System.Text.Json/tests/JsonTestHelper.cs @@ -718,17 +718,14 @@ public static void AssertContents(string expectedValue, ArrayBufferWriter #endif ); - // Temporary hack until we can use the same escape algorithm on both sides and make sure we want uppercase hex. - // Todo: https://github.com/dotnet/runtime/issues/32351 - Assert.Equal(expectedValue.NormalizeToJsonNetFormat(), value.NormalizeToJsonNetFormat()); + AssertContentsAgainstJsonNet(expectedValue, value); } public static void AssertContents(string expectedValue, MemoryStream stream) { string value = Encoding.UTF8.GetString(stream.ToArray()); - // Temporary hack until we can use the same escape algorithm on both sides and make sure we want uppercase hex. - Assert.Equal(expectedValue.NormalizeToJsonNetFormat(), value.NormalizeToJsonNetFormat()); + AssertContentsAgainstJsonNet(expectedValue, value); } public static void AssertContentsNotEqual(string expectedValue, ArrayBufferWriter buffer) @@ -740,8 +737,16 @@ public static void AssertContentsNotEqual(string expectedValue, ArrayBufferWrite #endif ); - // Temporary hack until we can use the same escape algorithm on both sides and make sure we want uppercase hex. - // Todo: https://github.com/dotnet/runtime/issues/32351 + AssertContentsNotEqualAgainstJsonNet(expectedValue, value); + } + + public static void AssertContentsAgainstJsonNet(string expectedValue, string value) + { + Assert.Equal(expectedValue.NormalizeToJsonNetFormat(), value.NormalizeToJsonNetFormat()); + } + + public static void AssertContentsNotEqualAgainstJsonNet(string expectedValue, string value) + { Assert.NotEqual(expectedValue.NormalizeToJsonNetFormat(), value.NormalizeToJsonNetFormat()); } @@ -814,5 +819,64 @@ public static string NormalizeLineEndings(this string value) => s_replaceNewlines ? value.Replace(CompiledNewline, Environment.NewLine) : value; + + public static void AssertJsonEqual(string expected, string actual) + { + using JsonDocument expectedDom = JsonDocument.Parse(expected); + using JsonDocument actualDom = JsonDocument.Parse(actual); + AssertJsonEqual(expectedDom.RootElement, actualDom.RootElement); + } + + private static void AssertJsonEqual(JsonElement expected, JsonElement actual) + { + JsonValueKind valueKind = expected.ValueKind; + Assert.Equal(valueKind, actual.ValueKind); + + switch (valueKind) + { + case JsonValueKind.Object: + var propertyNames = new HashSet(); + + foreach (JsonProperty property in expected.EnumerateObject()) + { + propertyNames.Add(property.Name); + } + + foreach (JsonProperty property in actual.EnumerateObject()) + { + propertyNames.Add(property.Name); + } + + foreach (string name in propertyNames) + { + AssertJsonEqual(expected.GetProperty(name), actual.GetProperty(name)); + } + break; + case JsonValueKind.Array: + JsonElement.ArrayEnumerator expectedEnumerator = actual.EnumerateArray(); + JsonElement.ArrayEnumerator actualEnumerator = expected.EnumerateArray(); + + while (expectedEnumerator.MoveNext()) + { + Assert.True(actualEnumerator.MoveNext()); + AssertJsonEqual(expectedEnumerator.Current, actualEnumerator.Current); + } + + Assert.False(actualEnumerator.MoveNext()); + break; + case JsonValueKind.String: + Assert.Equal(expected.GetString(), actual.GetString()); + break; + case JsonValueKind.Number: + case JsonValueKind.True: + case JsonValueKind.False: + case JsonValueKind.Null: + Assert.Equal(expected.GetRawText(), actual.GetRawText()); + break; + default: + Debug.Fail($"Unexpected JsonValueKind: JsonValueKind.{valueKind}."); + break; + } + } } } diff --git a/src/libraries/System.Text.Json/tests/Serialization/CamelCaseUnitTests.cs b/src/libraries/System.Text.Json/tests/Serialization/CamelCaseUnitTests.cs index caf42d23e3b7d9..dbf4f86b7756d0 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/CamelCaseUnitTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/CamelCaseUnitTests.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Reflection; using Xunit; namespace System.Text.Json.Serialization.Tests diff --git a/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Concurrent.Write.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Concurrent.Write.cs new file mode 100644 index 00000000000000..2e42fc674197a5 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Concurrent.Write.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Concurrent; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CollectionTests + { + [Fact] + public static void Write_ConcurrentCollection() + { + Assert.Equal(@"[""1""]", JsonSerializer.Serialize(new BlockingCollection { "1" })); + + Assert.Equal(@"[""1""]", JsonSerializer.Serialize(new ConcurrentBag { "1" })); + + Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new ConcurrentDictionary { ["key"] = "value" })); + + ConcurrentQueue qc = new ConcurrentQueue(); + qc.Enqueue("1"); + Assert.Equal(@"[""1""]", JsonSerializer.Serialize(qc)); + + ConcurrentStack qs = new ConcurrentStack(); + qs.Push("1"); + Assert.Equal(@"[""1""]", JsonSerializer.Serialize(qs)); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Concurrent.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Concurrent.cs new file mode 100644 index 00000000000000..b4976ba357d28d --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Concurrent.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Concurrent; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CollectionTests + { + [Fact] + public static void Read_ConcurrentCollection() + { + ConcurrentDictionary cd = JsonSerializer.Deserialize>(@"{""key"":""value""}"); + Assert.Equal(1, cd.Count); + Assert.Equal("value", cd["key"]); + + ConcurrentQueue qc = JsonSerializer.Deserialize>(@"[""1""]"); + Assert.Equal(1, qc.Count); + bool found = qc.TryPeek(out string val); + Assert.True(found); + Assert.Equal("1", val); + + ConcurrentStack qs = JsonSerializer.Deserialize>(@"[""1""]"); + Assert.Equal(1, qs.Count); + found = qs.TryPeek(out val); + Assert.True(found); + Assert.Equal("1", val); + } + + [Theory] + [InlineData(typeof(BlockingCollection), @"[""1""]")] // Not supported. Not IList, and we don't detect the add method for this collection. + [InlineData(typeof(ConcurrentBag), @"[""1""]")] // Not supported. Not IList, and we don't detect the add method for this collection. + public static void Read_ConcurrentCollection_Throws(Type type, string json) + { + NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); + Assert.Contains(type.ToString(), ex.Message); + } + + [Theory] + [InlineData(typeof(GenericConcurrentQueuePrivateConstructor), @"[""1""]")] + [InlineData(typeof(GenericConcurrentQueueInternalConstructor), @"[""1""]")] + [InlineData(typeof(GenericConcurrentStackPrivateConstructor), @"[""1""]")] + [InlineData(typeof(GenericConcurrentStackInternalConstructor), @"[""1""]")] + public static void Read_ConcurrentCollection_NoPublicConstructor_Throws(Type type, string json) + { + NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); + Assert.Contains(type.ToString(), ex.Message); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.KeyPolicy.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Dictionary.KeyPolicy.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.KeyPolicy.cs rename to src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Dictionary.KeyPolicy.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Dictionary.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Dictionary.cs new file mode 100644 index 00000000000000..bf1fb5a1587aa4 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Dictionary.cs @@ -0,0 +1,2214 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Collections.Specialized; +using System.Reflection; +using System.Text.Encodings.Web; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class DictionaryTests + { + [Fact] + public static void DictionaryOfString() + { + const string JsonString = @"{""Hello"":""World"",""Hello2"":""World2""}"; + const string ReorderedJsonString = @"{""Hello2"":""World2"",""Hello"":""World""}"; + + { + IDictionary obj = JsonSerializer.Deserialize(JsonString); + Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); + Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + { + Dictionary obj = JsonSerializer.Deserialize>(JsonString); + Assert.Equal("World", obj["Hello"]); + Assert.Equal("World2", obj["Hello2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + { + SortedDictionary obj = JsonSerializer.Deserialize>(JsonString); + Assert.Equal("World", obj["Hello"]); + Assert.Equal("World2", obj["Hello2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + { + IDictionary obj = JsonSerializer.Deserialize>(JsonString); + Assert.Equal("World", obj["Hello"]); + Assert.Equal("World2", obj["Hello2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + { + IReadOnlyDictionary obj = JsonSerializer.Deserialize>(JsonString); + Assert.Equal("World", obj["Hello"]); + Assert.Equal("World2", obj["Hello2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + { + ImmutableDictionary obj = JsonSerializer.Deserialize>(JsonString); + Assert.Equal("World", obj["Hello"]); + Assert.Equal("World2", obj["Hello2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.True(JsonString == json || ReorderedJsonString == json); + + json = JsonSerializer.Serialize(obj); + Assert.True(JsonString == json || ReorderedJsonString == json); + } + + { + IImmutableDictionary obj = JsonSerializer.Deserialize>(JsonString); + Assert.Equal("World", obj["Hello"]); + Assert.Equal("World2", obj["Hello2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.True(JsonString == json || ReorderedJsonString == json); + + json = JsonSerializer.Serialize(obj); + Assert.True(JsonString == json || ReorderedJsonString == json); + } + + { + ImmutableSortedDictionary obj = JsonSerializer.Deserialize>(JsonString); + Assert.Equal("World", obj["Hello"]); + Assert.Equal("World2", obj["Hello2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.True(JsonString == json); + + json = JsonSerializer.Serialize(obj); + Assert.True(JsonString == json); + } + + { + Hashtable obj = JsonSerializer.Deserialize(JsonString); + Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); + Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); + + string json = JsonSerializer.Serialize(obj); + Assert.True(JsonString == json || ReorderedJsonString == json); + + json = JsonSerializer.Serialize(obj); + Assert.True(JsonString == json || ReorderedJsonString == json); + } + + { + SortedList obj = JsonSerializer.Deserialize(JsonString); + Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); + Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + } + + [Fact] + public static void ImplementsDictionary_DictionaryOfString() + { + const string JsonString = @"{""Hello"":""World"",""Hello2"":""World2""}"; + const string ReorderedJsonString = @"{""Hello2"":""World2"",""Hello"":""World""}"; + + { + WrapperForIDictionary obj = JsonSerializer.Deserialize(JsonString); + Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); + Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + { + StringToStringDictionaryWrapper obj = JsonSerializer.Deserialize(JsonString); + Assert.Equal("World", obj["Hello"]); + Assert.Equal("World2", obj["Hello2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + { + StringToStringSortedDictionaryWrapper obj = JsonSerializer.Deserialize(JsonString); + Assert.Equal("World", obj["Hello"]); + Assert.Equal("World2", obj["Hello2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + { + GenericIDictionaryWrapper obj = JsonSerializer.Deserialize>(JsonString); + Assert.Equal("World", obj["Hello"]); + Assert.Equal("World2", obj["Hello2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + { + Assert.Throws(() => JsonSerializer.Deserialize>(JsonString)); + + GenericIReadOnlyDictionaryWrapper obj = new GenericIReadOnlyDictionaryWrapper(new Dictionary() + { + { "Hello", "World" }, + { "Hello2", "World2" }, + }); + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + { + Assert.Throws(() => JsonSerializer.Deserialize(JsonString)); + + StringToStringIImmutableDictionaryWrapper obj = new StringToStringIImmutableDictionaryWrapper(new Dictionary() + { + { "Hello", "World" }, + { "Hello2", "World2" }, + }); + + string json = JsonSerializer.Serialize(obj); + Assert.True(JsonString == json || ReorderedJsonString == json); + + json = JsonSerializer.Serialize(obj); + Assert.True(JsonString == json || ReorderedJsonString == json); + } + + { + HashtableWrapper obj = JsonSerializer.Deserialize(JsonString); + Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); + Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); + + string json = JsonSerializer.Serialize(obj); + Assert.True(JsonString == json || ReorderedJsonString == json); + + json = JsonSerializer.Serialize(obj); + Assert.True(JsonString == json || ReorderedJsonString == json); + } + + { + SortedListWrapper obj = JsonSerializer.Deserialize(JsonString); + Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); + Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + } + + [Fact] + public static void DictionaryOfObject() + { + { + Dictionary obj = JsonSerializer.Deserialize>(@"{""Key1"":1}"); + Assert.Equal(1, obj.Count); + JsonElement element = (JsonElement)obj["Key1"]; + Assert.Equal(JsonValueKind.Number, element.ValueKind); + Assert.Equal(1, element.GetInt32()); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(@"{""Key1"":1}", json); + } + + { + IDictionary obj = JsonSerializer.Deserialize>(@"{""Key1"":1}"); + Assert.Equal(1, obj.Count); + JsonElement element = (JsonElement)obj["Key1"]; + Assert.Equal(JsonValueKind.Number, element.ValueKind); + Assert.Equal(1, element.GetInt32()); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(@"{""Key1"":1}", json); + } + } + + [Fact] + public static void ImplementsIDictionaryOfObject() + { + var input = new GenericIDictionaryWrapper(new Dictionary + { + { "Name", "David" }, + { "Age", 32 } + }); + + string json = JsonSerializer.Serialize(input, typeof(IDictionary)); + Assert.Equal(@"{""Name"":""David"",""Age"":32}", json); + + IDictionary obj = JsonSerializer.Deserialize>(json); + Assert.Equal(2, obj.Count); + Assert.Equal("David", ((JsonElement)obj["Name"]).GetString()); + Assert.Equal(32, ((JsonElement)obj["Age"]).GetInt32()); + } + + [Fact] + public static void ImplementsIDictionaryOfString() + { + var input = new GenericIDictionaryWrapper(new Dictionary + { + { "Name", "David" }, + { "Job", "Software Architect" } + }); + + string json = JsonSerializer.Serialize(input, typeof(IDictionary)); + Assert.Equal(@"{""Name"":""David"",""Job"":""Software Architect""}", json); + + IDictionary obj = JsonSerializer.Deserialize>(json); + Assert.Equal(2, obj.Count); + Assert.Equal("David", obj["Name"]); + Assert.Equal("Software Architect", obj["Job"]); + } + + [Theory] + [InlineData(typeof(ImmutableDictionary), "\"headers\"")] + [InlineData(typeof(Dictionary), "\"headers\"")] + [InlineData(typeof(PocoDictionary), "\"headers\"")] + public static void InvalidJsonForValueShouldFail(Type type, string json) + { + Assert.Throws(() => JsonSerializer.Deserialize(json, type)); + } + + public static IEnumerable InvalidJsonForIntValue() + { + yield return @"""1"""; + yield return "["; + yield return "}"; + yield return @"[""1""]"; + yield return "[true]"; + } + + public static IEnumerable InvalidJsonForPoco() + { + foreach (string value in InvalidJsonForIntValue()) + { + yield return value; + yield return "[" + value + "]"; + yield return "{" + value + "}"; + yield return @"{""Id"":" + value + "}"; + } + } + + public class ClassWithInt + { + public int Obj { get; set; } + } + + public class ClassWithIntList + { + public List Obj { get; set; } + } + + public class ClassWithIntArray + { + public int[] Obj { get; set; } + } + + public class ClassWithPoco + { + public Poco Obj { get; set; } + } + + public class ClassWithPocoArray + { + public Poco[] Obj { get; set; } + } + + public class ClassWithDictionaryOfIntArray + { + public Dictionary Obj { get; set; } + } + + public class ClassWithDictionaryOfPoco + { + public Dictionary Obj { get; set; } + } + + public class ClassWithDictionaryOfPocoList + { + public Dictionary> Obj { get; set; } + } + + public static IEnumerable TypesForInvalidJsonForCollectionTests() + { + static Type MakeClosedCollectionType(Type openCollectionType, Type elementType) + { + if (openCollectionType == typeof(Dictionary<,>)) + { + return typeof(Dictionary<,>).MakeGenericType(typeof(string), elementType); + } + else + { + return openCollectionType.MakeGenericType(elementType); + } + } + + Type[] elementTypes = new Type[] + { + typeof(int), + typeof(Poco), + typeof(ClassWithInt), + typeof(ClassWithIntList), + typeof(ClassWithPoco), + typeof(ClassWithPocoArray), + typeof(ClassWithDictionaryOfIntArray), + typeof(ClassWithDictionaryOfPoco), + typeof(ClassWithDictionaryOfPocoList), + }; + + Type[] collectionTypes = new Type[] + { + typeof(List<>), + typeof(Dictionary<,>), + }; + + foreach (Type type in elementTypes) + { + yield return type; + } + + List innerTypes = new List(elementTypes); + + // Create permutations of collections with 1 and 2 levels of nesting. + for (int i = 0; i < 2; i++) + { + foreach (Type collectionType in collectionTypes) + { + List newInnerTypes = new List(); + + foreach (Type elementType in innerTypes) + { + Type newCollectionType = MakeClosedCollectionType(collectionType, elementType); + newInnerTypes.Add(newCollectionType); + yield return newCollectionType; + } + + innerTypes = newInnerTypes; + } + } + } + + static IEnumerable GetInvalidJsonStringsForType(Type type) + { + if (type == typeof(int)) + { + foreach (string json in InvalidJsonForIntValue()) + { + yield return json; + } + yield break; + } + + if (type == typeof(Poco)) + { + foreach (string json in InvalidJsonForPoco()) + { + yield return json; + } + yield break; + } + + Type elementType; + + if (!typeof(IEnumerable).IsAssignableFrom(type)) + { + // Get type of "Obj" property. + elementType = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)[0].PropertyType; + } + else if (type.IsArray) + { + elementType = type.GetElementType(); + } + else if (!type.IsGenericType) + { + Assert.True(false, "Expected generic type"); + yield break; + } + else + { + Type genericTypeDef = type.GetGenericTypeDefinition(); + + if (genericTypeDef == typeof(List<>)) + { + elementType = type.GetGenericArguments()[0]; + } + else if (genericTypeDef == typeof(Dictionary<,>)) + { + elementType = type.GetGenericArguments()[1]; + } + else + { + Assert.True(false, "Expected List or Dictionary type"); + yield break; + } + } + + foreach (string invalidJson in GetInvalidJsonStringsForType(elementType)) + { + yield return "[" + invalidJson + "]"; + yield return "{" + invalidJson + "}"; + yield return @"{""Obj"":" + invalidJson + "}"; + } + } + + public static IEnumerable DataForInvalidJsonForTypeTests() + { + foreach (Type type in TypesForInvalidJsonForCollectionTests()) + { + foreach (string invalidJson in GetInvalidJsonStringsForType(type)) + { + yield return new object[] { type, invalidJson }; + } + } + + yield return new object[] { typeof(int[]), @"""test""" }; + yield return new object[] { typeof(int[]), @"1" }; + yield return new object[] { typeof(int[]), @"false" }; + yield return new object[] { typeof(int[]), @"{}" }; + yield return new object[] { typeof(int[]), @"{""test"": 1}" }; + yield return new object[] { typeof(int[]), @"[""test""" }; + yield return new object[] { typeof(int[]), @"[""test""]" }; + yield return new object[] { typeof(int[]), @"[true]" }; + yield return new object[] { typeof(int[]), @"[{}]" }; + yield return new object[] { typeof(int[]), @"[[]]" }; + yield return new object[] { typeof(int[]), @"[{""test"": 1}]" }; + yield return new object[] { typeof(int[]), @"[[true]]" }; + yield return new object[] { typeof(Dictionary), @"{""test"": {}}" }; + yield return new object[] { typeof(Dictionary), @"{""test"": {""test"": 1}}" }; + yield return new object[] { typeof(Dictionary), @"{""test"": ""test""}" }; + yield return new object[] { typeof(Dictionary), @"{""test"": 1}" }; + yield return new object[] { typeof(Dictionary), @"{""test"": true}" }; + yield return new object[] { typeof(Dictionary), @"{""test"": [""test""}" }; + yield return new object[] { typeof(Dictionary), @"{""test"": [""test""]}" }; + yield return new object[] { typeof(Dictionary), @"{""test"": [[]]}" }; + yield return new object[] { typeof(Dictionary), @"{""test"": [true]}" }; + yield return new object[] { typeof(Dictionary), @"{""test"": [{}]}" }; + yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": ""test""}" }; + yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": 1}" }; + yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": false}" }; + yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": {}}" }; + yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": {""test"": 1}}" }; + yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [""test""}" }; + yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [""test""]}" }; + yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [true]}" }; + yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [{}]}" }; + yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [[]]}" }; + yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [{""test"": 1}]}" }; + yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [[true]]}" }; + yield return new object[] { typeof(Dictionary), @"""test""" }; + yield return new object[] { typeof(Dictionary), @"1" }; + yield return new object[] { typeof(Dictionary), @"false" }; + yield return new object[] { typeof(Dictionary), @"{"""": 1}" }; + yield return new object[] { typeof(Dictionary), @"{"""": {}}" }; + yield return new object[] { typeof(Dictionary), @"{"""": {"""":""""}}" }; + yield return new object[] { typeof(Dictionary), @"[""test""" }; + yield return new object[] { typeof(Dictionary), @"[""test""]" }; + yield return new object[] { typeof(Dictionary), @"[true]" }; + yield return new object[] { typeof(Dictionary), @"[{}]" }; + yield return new object[] { typeof(Dictionary), @"[[]]" }; + yield return new object[] { typeof(Dictionary), @"[{""test"": 1}]" }; + yield return new object[] { typeof(Dictionary), @"[[true]]" }; + yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":""test""}" }; + yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":1}" }; + yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":false}" }; + yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":{"""": 1}}" }; + yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":{"""": {}}}" }; + yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":{"""": {"""":""""}}}" }; + yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[""test""}" }; + yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[""test""]}" }; + yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[true]}" }; + yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[{}]}" }; + yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[[]]}" }; + yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[{""test"": 1}]}" }; + yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[[true]]}" }; + yield return new object[] { typeof(Dictionary), @"{""key"":[{""Id"":3}]}" }; + yield return new object[] { typeof(Dictionary), @"{""key"":[""test""]}" }; + yield return new object[] { typeof(Dictionary), @"{""key"":[1]}" }; + yield return new object[] { typeof(Dictionary), @"{""key"":[false]}" }; + yield return new object[] { typeof(Dictionary), @"{""key"":[]}" }; + yield return new object[] { typeof(Dictionary), @"{""key"":1}" }; + yield return new object[] { typeof(Dictionary>), @"{""key"":{""Id"":3}}" }; + yield return new object[] { typeof(Dictionary>), @"{""key"":{}}" }; + yield return new object[] { typeof(Dictionary>), @"{""key"":[[]]}" }; + yield return new object[] { typeof(Dictionary>), @"{""key"":[]}" }; + yield return new object[] { typeof(Dictionary>), @"{""key"":1}" }; + } + + [Fact] + public static void InvalidJsonForTypeShouldFail() + { + foreach (object[] args in DataForInvalidJsonForTypeTests()) // ~140K tests, too many for theory to handle well with our infrastructure + { + var type = (Type)args[0]; + var invalidJson = (string)args[1]; + Assert.Throws(() => JsonSerializer.Deserialize(invalidJson, type)); + } + } + + [Fact] + public static void InvalidEmptyDictionaryInput() + { + Assert.Throws(() => JsonSerializer.Deserialize("{}")); + } + + [Fact] + public static void PocoWithDictionaryObject() + { + PocoDictionary dict = JsonSerializer.Deserialize("{\n\t\"key\" : {\"a\" : \"b\", \"c\" : \"d\"}}"); + Assert.Equal("b", dict.key["a"]); + Assert.Equal("d", dict.key["c"]); + } + + public class PocoDictionary + { + public Dictionary key { get; set; } + } + + [Fact] + public static void DictionaryOfObject_NonPrimitiveTypes() + { + // https://github.com/dotnet/runtime/issues/29504 + Dictionary dictionary = new Dictionary + { + ["key"] = new Poco { Id = 10 }, + }; + + string json = JsonSerializer.Serialize(dictionary); + Assert.Equal(@"{""key"":{""Id"":10}}", json); + + dictionary = JsonSerializer.Deserialize>(json); + Assert.Equal(1, dictionary.Count); + JsonElement element = (JsonElement)dictionary["key"]; + Assert.Equal(@"{""Id"":10}", element.ToString()); + } + + public class Poco + { + public int Id { get; set; } + } + + [Fact] + public static void FirstGenericArgNotStringFail() + { + Assert.Throws(() => JsonSerializer.Deserialize>(@"{1:1}")); + Assert.Throws(() => JsonSerializer.Deserialize>(@"{1:1}")); + } + + [Fact] + public static void DictionaryOfList() + { + const string JsonString = @"{""Key1"":[1,2],""Key2"":[3,4]}"; + + { + IDictionary obj = JsonSerializer.Deserialize(JsonString); + + Assert.Equal(2, obj.Count); + + int expectedNumber = 1; + + JsonElement element = (JsonElement)obj["Key1"]; + foreach (JsonElement value in element.EnumerateArray()) + { + Assert.Equal(expectedNumber++, value.GetInt32()); + } + + element = (JsonElement)obj["Key2"]; + foreach (JsonElement value in element.EnumerateArray()) + { + Assert.Equal(expectedNumber++, value.GetInt32()); + } + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + { + IDictionary> obj = JsonSerializer.Deserialize>>(JsonString); + + Assert.Equal(2, obj.Count); + Assert.Equal(2, obj["Key1"].Count); + Assert.Equal(1, obj["Key1"][0]); + Assert.Equal(2, obj["Key1"][1]); + Assert.Equal(2, obj["Key2"].Count); + Assert.Equal(3, obj["Key2"][0]); + Assert.Equal(4, obj["Key2"][1]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + { + ImmutableDictionary> obj = JsonSerializer.Deserialize>>(JsonString); + + Assert.Equal(2, obj.Count); + Assert.Equal(2, obj["Key1"].Count); + Assert.Equal(1, obj["Key1"][0]); + Assert.Equal(2, obj["Key1"][1]); + Assert.Equal(2, obj["Key2"].Count); + Assert.Equal(3, obj["Key2"][0]); + Assert.Equal(4, obj["Key2"][1]); + + string json = JsonSerializer.Serialize(obj); + const string ReorderedJsonString = @"{""Key2"":[3,4],""Key1"":[1,2]}"; + Assert.True(JsonString == json || ReorderedJsonString == json); + } + + { + IImmutableDictionary> obj = JsonSerializer.Deserialize>>(JsonString); + + Assert.Equal(2, obj.Count); + Assert.Equal(2, obj["Key1"].Count); + Assert.Equal(1, obj["Key1"][0]); + Assert.Equal(2, obj["Key1"][1]); + Assert.Equal(2, obj["Key2"].Count); + Assert.Equal(3, obj["Key2"][0]); + Assert.Equal(4, obj["Key2"][1]); + + + string json = JsonSerializer.Serialize(obj); + const string ReorderedJsonString = @"{""Key2"":[3,4],""Key1"":[1,2]}"; + Assert.True(JsonString == json || ReorderedJsonString == json); + } + } + + [Fact] + public static void DictionaryOfArray() + { + const string JsonString = @"{""Key1"":[1,2],""Key2"":[3,4]}"; + Dictionary obj = JsonSerializer.Deserialize>(JsonString); + + Assert.Equal(2, obj.Count); + Assert.Equal(2, obj["Key1"].Length); + Assert.Equal(1, obj["Key1"][0]); + Assert.Equal(2, obj["Key1"][1]); + Assert.Equal(2, obj["Key2"].Length); + Assert.Equal(3, obj["Key2"][0]); + Assert.Equal(4, obj["Key2"][1]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + [Fact] + public static void ListOfDictionary() + { + const string JsonString = @"[{""Key1"":1,""Key2"":2},{""Key1"":3,""Key2"":4}]"; + + { + List> obj = JsonSerializer.Deserialize>>(JsonString); + + Assert.Equal(2, obj.Count); + Assert.Equal(2, obj[0].Count); + Assert.Equal(1, obj[0]["Key1"]); + Assert.Equal(2, obj[0]["Key2"]); + Assert.Equal(2, obj[1].Count); + Assert.Equal(3, obj[1]["Key1"]); + Assert.Equal(4, obj[1]["Key2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + { + List> obj = JsonSerializer.Deserialize>>(JsonString); + + Assert.Equal(2, obj.Count); + Assert.Equal(2, obj[0].Count); + Assert.Equal(1, obj[0]["Key1"]); + Assert.Equal(2, obj[0]["Key2"]); + Assert.Equal(2, obj[1].Count); + Assert.Equal(3, obj[1]["Key1"]); + Assert.Equal(4, obj[1]["Key2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + } + + [Fact] + public static void ArrayOfDictionary() + { + const string JsonString = @"[{""Key1"":1,""Key2"":2},{""Key1"":3,""Key2"":4}]"; + + { + Dictionary[] obj = JsonSerializer.Deserialize[]>(JsonString); + + Assert.Equal(2, obj.Length); + Assert.Equal(2, obj[0].Count); + Assert.Equal(1, obj[0]["Key1"]); + Assert.Equal(2, obj[0]["Key2"]); + Assert.Equal(2, obj[1].Count); + Assert.Equal(3, obj[1]["Key1"]); + Assert.Equal(4, obj[1]["Key2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + { + ImmutableSortedDictionary[] obj = JsonSerializer.Deserialize[]>(JsonString); + + Assert.Equal(2, obj.Length); + Assert.Equal(2, obj[0].Count); + Assert.Equal(1, obj[0]["Key1"]); + Assert.Equal(2, obj[0]["Key2"]); + Assert.Equal(2, obj[1].Count); + Assert.Equal(3, obj[1]["Key1"]); + Assert.Equal(4, obj[1]["Key2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + } + + [Fact] + public static void DictionaryOfDictionary() + { + const string JsonString = @"{""Key1"":{""Key1a"":1,""Key1b"":2},""Key2"":{""Key2a"":3,""Key2b"":4}}"; + + { + Dictionary> obj = JsonSerializer.Deserialize>>(JsonString); + + Assert.Equal(2, obj.Count); + Assert.Equal(2, obj["Key1"].Count); + Assert.Equal(1, obj["Key1"]["Key1a"]); + Assert.Equal(2, obj["Key1"]["Key1b"]); + Assert.Equal(2, obj["Key2"].Count); + Assert.Equal(3, obj["Key2"]["Key2a"]); + Assert.Equal(4, obj["Key2"]["Key2b"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + { + ImmutableSortedDictionary> obj = JsonSerializer.Deserialize>>(JsonString); + + Assert.Equal(2, obj.Count); + Assert.Equal(2, obj["Key1"].Count); + Assert.Equal(1, obj["Key1"]["Key1a"]); + Assert.Equal(2, obj["Key1"]["Key1b"]); + Assert.Equal(2, obj["Key2"].Count); + Assert.Equal(3, obj["Key2"]["Key2a"]); + Assert.Equal(4, obj["Key2"]["Key2b"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + } + + [Fact] + public static void DictionaryOfDictionaryOfDictionary() + { + const string JsonString = @"{""Key1"":{""Key1"":{""Key1"":1,""Key2"":2},""Key2"":{""Key1"":3,""Key2"":4}},""Key2"":{""Key1"":{""Key1"":5,""Key2"":6},""Key2"":{""Key1"":7,""Key2"":8}}}"; + Dictionary>> obj = JsonSerializer.Deserialize>>>(JsonString); + + Assert.Equal(2, obj.Count); + Assert.Equal(2, obj["Key1"].Count); + Assert.Equal(2, obj["Key1"]["Key1"].Count); + Assert.Equal(2, obj["Key1"]["Key2"].Count); + + Assert.Equal(1, obj["Key1"]["Key1"]["Key1"]); + Assert.Equal(2, obj["Key1"]["Key1"]["Key2"]); + Assert.Equal(3, obj["Key1"]["Key2"]["Key1"]); + Assert.Equal(4, obj["Key1"]["Key2"]["Key2"]); + + Assert.Equal(2, obj["Key2"].Count); + Assert.Equal(2, obj["Key2"]["Key1"].Count); + Assert.Equal(2, obj["Key2"]["Key2"].Count); + + Assert.Equal(5, obj["Key2"]["Key1"]["Key1"]); + Assert.Equal(6, obj["Key2"]["Key1"]["Key2"]); + Assert.Equal(7, obj["Key2"]["Key2"]["Key1"]); + Assert.Equal(8, obj["Key2"]["Key2"]["Key2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + // Verify that typeof(object) doesn't interfere. + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + [Fact] + public static void DictionaryOfArrayOfDictionary() + { + const string JsonString = @"{""Key1"":[{""Key1"":1,""Key2"":2},{""Key1"":3,""Key2"":4}],""Key2"":[{""Key1"":5,""Key2"":6},{""Key1"":7,""Key2"":8}]}"; + Dictionary[]> obj = JsonSerializer.Deserialize[]>>(JsonString); + + Assert.Equal(2, obj.Count); + Assert.Equal(2, obj["Key1"].Length); + Assert.Equal(2, obj["Key1"][0].Count); + Assert.Equal(2, obj["Key1"][1].Count); + + Assert.Equal(1, obj["Key1"][0]["Key1"]); + Assert.Equal(2, obj["Key1"][0]["Key2"]); + Assert.Equal(3, obj["Key1"][1]["Key1"]); + Assert.Equal(4, obj["Key1"][1]["Key2"]); + + Assert.Equal(2, obj["Key2"].Length); + Assert.Equal(2, obj["Key2"][0].Count); + Assert.Equal(2, obj["Key2"][1].Count); + + Assert.Equal(5, obj["Key2"][0]["Key1"]); + Assert.Equal(6, obj["Key2"][0]["Key2"]); + Assert.Equal(7, obj["Key2"][1]["Key1"]); + Assert.Equal(8, obj["Key2"][1]["Key2"]); + + string json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + + // Verify that typeof(object) doesn't interfere. + json = JsonSerializer.Serialize(obj); + Assert.Equal(JsonString, json); + } + + private interface IClass { } + + private class MyClass : IClass { } + + private class MyNonGenericDictionary : Dictionary { } + + private class MyFactory : JsonConverterFactory + { + public override bool CanConvert(Type typeToConvert) + { + return typeToConvert == typeof(IClass) || typeToConvert == typeof(MyClass); + } + + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + if (typeToConvert == typeof(IClass)) + { + return new MyStuffConverterForIClass(); + } + else if (typeToConvert == typeof(MyClass)) + { + return new MyStuffConverterForMyClass(); + } + else + { + throw new InvalidOperationException(); + } + } + } + + private class MyStuffConverterForIClass : JsonConverter + { + public override IClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new MyClass(); + } + + public override void Write(Utf8JsonWriter writer, IClass value, JsonSerializerOptions options) + { + writer.WriteNumberValue(1); + } + } + + private class MyStuffConverterForMyClass : JsonConverter + { + public override MyClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new MyClass(); + } + + public override void Write(Utf8JsonWriter writer, MyClass value, JsonSerializerOptions options) + { + writer.WriteNumberValue(1); + } + } + + // This method generates 316 unique test cases for nested dictionaries up to 4 + // levels deep, along with matching JSON, encompassing the various planes of + // dictionaries that can be combined: generic, non-generic, BCL, user-derived, + // immutable, mutable, readonly, concurrent, specialized. + private static IEnumerable<(Type, string)> NestedDictionaryTypeData() + { + string testJson = @"{""Key"":1}"; + + List genericDictTypes = new List() + { + typeof(IDictionary<,>), + typeof(ConcurrentDictionary<,>), + typeof(GenericIDictionaryWrapper<,>), + }; + + List nonGenericDictTypes = new List() + { + typeof(Hashtable), + typeof(OrderedDictionary), + }; + + List baseDictionaryTypes = new List + { + typeof(MyNonGenericDictionary), + typeof(IReadOnlyDictionary), + typeof(ConcurrentDictionary), + typeof(ImmutableDictionary), + typeof(GenericIDictionaryWrapper), + }; + baseDictionaryTypes.AddRange(nonGenericDictTypes); + + // This method has exponential behavior which this depth value significantly impacts. + // Don't change this value without checking how many test cases are generated and + // how long the tests run for. + int maxTestDepth = 4; + + HashSet<(Type, string)> tests = new HashSet<(Type, string)>(); + + for (int i = 0; i < maxTestDepth; i++) + { + List newBaseTypes = new List(); + + foreach (Type testType in baseDictionaryTypes) + { + tests.Add((testType, testJson)); + + foreach (Type genericType in genericDictTypes) + { + newBaseTypes.Add(genericType.MakeGenericType(typeof(string), testType)); + } + + newBaseTypes.AddRange(nonGenericDictTypes); + } + + baseDictionaryTypes = newBaseTypes; + testJson = @"{""Key"":" + testJson + "}"; + } + + return tests; + } + + [Fact] + public static void NestedDictionariesRoundtrip() + { + JsonSerializerOptions options = new JsonSerializerOptions(); + options.Converters.Add(new MyFactory()); + + foreach ((Type dictionaryType, string testJson) in NestedDictionaryTypeData()) + { + object dict = JsonSerializer.Deserialize(testJson, dictionaryType, options); + Assert.Equal(testJson, JsonSerializer.Serialize(dict, options)); + } + } + + [Fact] + public static void DictionaryOfClasses() + { + { + IDictionary obj; + + { + string json = @"{""Key1"":" + SimpleTestClass.s_json + @",""Key2"":" + SimpleTestClass.s_json + "}"; + obj = JsonSerializer.Deserialize(json); + Assert.Equal(2, obj.Count); + + if (obj["Key1"] is JsonElement element) + { + SimpleTestClass result = JsonSerializer.Deserialize(element.GetRawText()); + result.Verify(); + } + else + { + ((SimpleTestClass)obj["Key1"]).Verify(); + ((SimpleTestClass)obj["Key2"]).Verify(); + } + } + + { + // We can't compare against the json string above because property ordering is not deterministic (based on reflection order) + // so just round-trip the json and compare. + string json = JsonSerializer.Serialize(obj); + obj = JsonSerializer.Deserialize(json); + Assert.Equal(2, obj.Count); + + if (obj["Key1"] is JsonElement element) + { + SimpleTestClass result = JsonSerializer.Deserialize(element.GetRawText()); + result.Verify(); + } + else + { + ((SimpleTestClass)obj["Key1"]).Verify(); + ((SimpleTestClass)obj["Key2"]).Verify(); + } + } + + { + string json = JsonSerializer.Serialize(obj); + obj = JsonSerializer.Deserialize(json); + Assert.Equal(2, obj.Count); + + if (obj["Key1"] is JsonElement element) + { + SimpleTestClass result = JsonSerializer.Deserialize(element.GetRawText()); + result.Verify(); + } + else + { + ((SimpleTestClass)obj["Key1"]).Verify(); + ((SimpleTestClass)obj["Key2"]).Verify(); + } + } + } + + { + Dictionary obj; + + { + string json = @"{""Key1"":" + SimpleTestClass.s_json + @",""Key2"":" + SimpleTestClass.s_json + "}"; + obj = JsonSerializer.Deserialize>(json); + Assert.Equal(2, obj.Count); + obj["Key1"].Verify(); + obj["Key2"].Verify(); + } + + { + // We can't compare against the json string above because property ordering is not deterministic (based on reflection order) + // so just round-trip the json and compare. + string json = JsonSerializer.Serialize(obj); + obj = JsonSerializer.Deserialize>(json); + Assert.Equal(2, obj.Count); + obj["Key1"].Verify(); + obj["Key2"].Verify(); + } + + { + string json = JsonSerializer.Serialize(obj); + obj = JsonSerializer.Deserialize>(json); + Assert.Equal(2, obj.Count); + obj["Key1"].Verify(); + obj["Key2"].Verify(); + } + } + + { + ImmutableSortedDictionary obj; + + { + string json = @"{""Key1"":" + SimpleTestClass.s_json + @",""Key2"":" + SimpleTestClass.s_json + "}"; + obj = JsonSerializer.Deserialize>(json); + Assert.Equal(2, obj.Count); + obj["Key1"].Verify(); + obj["Key2"].Verify(); + } + + { + // We can't compare against the json string above because property ordering is not deterministic (based on reflection order) + // so just round-trip the json and compare. + string json = JsonSerializer.Serialize(obj); + obj = JsonSerializer.Deserialize>(json); + Assert.Equal(2, obj.Count); + obj["Key1"].Verify(); + obj["Key2"].Verify(); + } + + { + string json = JsonSerializer.Serialize(obj); + obj = JsonSerializer.Deserialize>(json); + Assert.Equal(2, obj.Count); + obj["Key1"].Verify(); + obj["Key2"].Verify(); + } + } + } + + [Fact] + public static void UnicodePropertyNames() + { + var options = new JsonSerializerOptions(); + options.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping; + + { + Dictionary obj; + + obj = JsonSerializer.Deserialize>(@"{""A\u0467"":1}"); + Assert.Equal(1, obj["A\u0467"]); + + // Specifying encoder on options does not impact deserialize. + obj = JsonSerializer.Deserialize>(@"{""A\u0467"":1}", options); + Assert.Equal(1, obj["A\u0467"]); + + string json; + // Verify the name is escaped after serialize. + json = JsonSerializer.Serialize(obj); + Assert.Equal(@"{""A\u0467"":1}", json); + + // Verify with encoder. + json = JsonSerializer.Serialize(obj, options); + Assert.Equal("{\"A\u0467\":1}", json); + } + + { + // We want to go over StackallocThreshold=256 to force a pooled allocation, so this property is 200 chars and 400 bytes. + const int charsInProperty = 200; + + string longPropertyName = new string('\u0467', charsInProperty); + + Dictionary obj = JsonSerializer.Deserialize>($"{{\"{longPropertyName}\":1}}"); + Assert.Equal(1, obj[longPropertyName]); + + // Verify the name is escaped after serialize. + string json = JsonSerializer.Serialize(obj); + + // Duplicate the unicode character 'charsInProperty' times. + string longPropertyNameEscaped = new StringBuilder().Insert(0, @"\u0467", charsInProperty).ToString(); + + string expectedJson = $"{{\"{longPropertyNameEscaped}\":1}}"; + Assert.Equal(expectedJson, json); + + // Verify the name is unescaped after deserialize. + obj = JsonSerializer.Deserialize>(json); + Assert.Equal(1, obj[longPropertyName]); + } + } + + [Fact] + public static void CustomEscapingOnPropertyNameAndValue() + { + var dict = new Dictionary(); + dict.Add("A\u046701", "Value\u0467"); + + // Baseline with no escaping. + var json = JsonSerializer.Serialize(dict); + Assert.Equal("{\"A\\u046701\":\"Value\\u0467\"}", json); + + // Enable escaping. + var options = new JsonSerializerOptions(); + options.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping; + + json = JsonSerializer.Serialize(dict, options); + Assert.Equal("{\"A\u046701\":\"Value\u0467\"}", json); + } + + [Fact] + public static void ObjectToStringFail() + { + // Baseline + string json = @"{""MyDictionary"":{""Key"":""Value""}}"; + JsonSerializer.Deserialize>(json); + + Assert.Throws(() => JsonSerializer.Deserialize>(json)); + } + + [Fact] + public static void ObjectToJsonElement() + { + string json = @"{""MyDictionary"":{""Key"":""Value""}}"; + Dictionary result = JsonSerializer.Deserialize>(json); + JsonElement element = result["MyDictionary"]; + Assert.Equal(JsonValueKind.Object, element.ValueKind); + Assert.Equal("Value", element.GetProperty("Key").GetString()); + } + + [Fact] + public static void Hashtable() + { + const string Json = @"{""Key"":""Value""}"; + + IDictionary ht = new Hashtable(); + ht.Add("Key", "Value"); + string json = JsonSerializer.Serialize(ht); + + Assert.Equal(Json, json); + + ht = JsonSerializer.Deserialize(json); + Assert.IsType(ht["Key"]); + Assert.Equal("Value", ((JsonElement)ht["Key"]).GetString()); + + // Verify round-tripped JSON. + json = JsonSerializer.Serialize(ht); + Assert.Equal(Json, json); + } + + [Fact] + public static void DeserializeDictionaryWithDuplicateKeys() + { + // Non-generic IDictionary case. + IDictionary iDictionary = JsonSerializer.Deserialize(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); + Assert.Equal("NewValue", iDictionary["Hello"].ToString()); + + // Generic IDictionary case. + IDictionary iNonGenericDictionary = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); + Assert.Equal("NewValue", iNonGenericDictionary["Hello"]); + + IDictionary iNonGenericObjectDictionary = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); + Assert.Equal("NewValue", iNonGenericObjectDictionary["Hello"].ToString()); + + // Strongly-typed IDictionary<,> case. + Dictionary dictionary = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); + Assert.Equal("NewValue", dictionary["Hello"]); + + dictionary = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""myKey"" : ""myValue"", ""Hello"":""NewValue""}"); + Assert.Equal("NewValue", dictionary["Hello"]); + + // Weakly-typed IDictionary case. + Dictionary dictionaryObject = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""Hello"": null}"); + Assert.Null(dictionaryObject["Hello"]); + } + + [Fact] + public static void DeserializeDictionaryWithDuplicateProperties() + { + PocoDuplicate foo = JsonSerializer.Deserialize(@"{""BoolProperty"": false, ""BoolProperty"": true}"); + Assert.True(foo.BoolProperty); + + foo = JsonSerializer.Deserialize(@"{""BoolProperty"": false, ""IntProperty"" : 1, ""BoolProperty"": true , ""IntProperty"" : 2}"); + Assert.True(foo.BoolProperty); + Assert.Equal(2, foo.IntProperty); + + foo = JsonSerializer.Deserialize(@"{""DictProperty"" : {""a"" : ""b"", ""c"" : ""d""},""DictProperty"" : {""b"" : ""b"", ""c"" : ""e""}}"); + Assert.Equal(2, foo.DictProperty.Count); // We don't concat. + Assert.Equal("e", foo.DictProperty["c"]); + } + + public class PocoDuplicate + { + public bool BoolProperty { get; set; } + public int IntProperty { get; set; } + public Dictionary DictProperty { get; set; } + } + + public class ClassWithPopulatedDictionaryAndNoSetter + { + public ClassWithPopulatedDictionaryAndNoSetter() + { + MyImmutableDictionary = MyImmutableDictionary.Add("Key", "Value"); + } + + public Dictionary MyDictionary { get; } = new Dictionary() { { "Key", "Value" } }; + public ImmutableDictionary MyImmutableDictionary { get; } = ImmutableDictionary.Create(); + } + + [Fact] + public static void ClassWithNoSetterAndDictionary() + { + // We don't attempt to deserialize into dictionaries without a setter. + string json = @"{""MyDictionary"":{""Key1"":""Value1"", ""Key2"":""Value2""}}"; + ClassWithPopulatedDictionaryAndNoSetter obj = JsonSerializer.Deserialize(json); + Assert.Equal(1, obj.MyDictionary.Count); + } + + [Fact] + public static void ClassWithNoSetterAndImmutableDictionary() + { + // We don't attempt to deserialize into dictionaries without a setter. + string json = @"{""MyImmutableDictionary"":{""Key1"":""Value1"", ""Key2"":""Value2""}}"; + ClassWithPopulatedDictionaryAndNoSetter obj = JsonSerializer.Deserialize(json); + Assert.Equal(1, obj.MyImmutableDictionary.Count); + } + + public class ClassWithIgnoredDictionary1 + { + public Dictionary Parsed1 { get; set; } + public Dictionary Parsed2 { get; set; } + public Dictionary Skipped3 { get; } + } + + public class ClassWithIgnoredDictionary2 + { + public IDictionary Parsed1 { get; set; } + public IDictionary Skipped2 { get; } + public IDictionary Parsed3 { get; set; } + } + + public class ClassWithIgnoredDictionary3 + { + public Dictionary Parsed1 { get; set; } + public Dictionary Skipped2 { get; } + public Dictionary Skipped3 { get; } + } + + public class ClassWithIgnoredDictionary4 + { + public Dictionary Skipped1 { get; } + public Dictionary Parsed2 { get; set; } + public Dictionary Parsed3 { get; set; } + } + + public class ClassWithIgnoredDictionary5 + { + public Dictionary Skipped1 { get; } + public Dictionary Parsed2 { get; set; } + public Dictionary Skipped3 { get; } + } + + public class ClassWithIgnoredDictionary6 + { + public Dictionary Skipped1 { get; } + public Dictionary Skipped2 { get; } + public Dictionary Parsed3 { get; set; } + } + + public class ClassWithIgnoredDictionary7 + { + public Dictionary Skipped1 { get; } + public Dictionary Skipped2 { get; } + public Dictionary Skipped3 { get; } + } + + public class ClassWithIgnoredIDictionary + { + public IDictionary Parsed1 { get; set; } + public IDictionary Skipped2 { get; } + public IDictionary Parsed3 { get; set; } + } + + public class ClassWithIgnoreAttributeDictionary + { + public Dictionary Parsed1 { get; set; } + [JsonIgnore] public Dictionary Skipped2 { get; set; } // Note this has a setter. + public Dictionary Parsed3 { get; set; } + } + + public class ClassWithIgnoredImmutableDictionary + { + public ImmutableDictionary Parsed1 { get; set; } + public ImmutableDictionary Skipped2 { get; } + public ImmutableDictionary Parsed3 { get; set; } + } + + [Theory] + [InlineData(@"{""Parsed1"":{""Key"":1},""Parsed3"":{""Key"":2}}")] // No value for skipped property + [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":{}, ""Parsed3"":{""Key"":2}}")] // Empty object {} skipped + [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":null, ""Parsed3"":{""Key"":2}}")] // null object skipped + [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":{""Key"":9}, ""Parsed3"":{""Key"":2}}")] // Valid "int" values skipped + // Invalid "int" values: + [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":{""Key"":[1,2,3]}, ""Parsed3"":{""Key"":2}}")] + [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":{""Key"":{}}, ""Parsed3"":{""Key"":2}}")] + [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":{""Key"":null}, ""Parsed3"":{""Key"":2}}")] + public static void IgnoreDictionaryProperty(string json) + { + // Verify deserialization + ClassWithIgnoredDictionary2 obj = JsonSerializer.Deserialize(json); + Assert.Equal(1, obj.Parsed1.Count); + Assert.Equal(1, obj.Parsed1["Key"]); + Assert.Null(obj.Skipped2); + Assert.Equal(1, obj.Parsed3.Count); + Assert.Equal(2, obj.Parsed3["Key"]); + + // Round-trip and verify. + string jsonRoundTripped = JsonSerializer.Serialize(obj); + ClassWithIgnoredDictionary2 objRoundTripped = JsonSerializer.Deserialize(jsonRoundTripped); + Assert.Equal(1, objRoundTripped.Parsed1.Count); + Assert.Equal(1, objRoundTripped.Parsed1["Key"]); + Assert.Null(objRoundTripped.Skipped2); + Assert.Equal(1, objRoundTripped.Parsed3.Count); + Assert.Equal(2, objRoundTripped.Parsed3["Key"]); + } + + [Fact] + public static void IgnoreDictionaryPropertyWithDifferentOrdering() + { + // Verify all combinations of 3 properties with at least one ignore. + VerifyIgnore(false, false, true); + VerifyIgnore(false, true, false); + VerifyIgnore(false, true, true); + VerifyIgnore(true, false, false); + VerifyIgnore(true, false, true); + VerifyIgnore(true, true, false); + VerifyIgnore(true, true, true); + + // Verify single case for IDictionary, [Ignore] and ImmutableDictionary. + // Also specify addMissing to add additional skipped JSON that does not have a corresponding property. + VerifyIgnore(false, true, false, addMissing: true); + VerifyIgnore(false, true, false, addMissing: true); + VerifyIgnore(false, true, false, addMissing: true); + } + + private static void VerifyIgnore(bool skip1, bool skip2, bool skip3, bool addMissing = false) + { + static IDictionary GetProperty(T objectToVerify, string propertyName) + { + return (IDictionary)objectToVerify.GetType().GetProperty(propertyName).GetValue(objectToVerify); + } + + void Verify(T objectToVerify) + { + if (skip1) + { + Assert.Null(GetProperty(objectToVerify, "Skipped1")); + } + else + { + Assert.Equal(1, GetProperty(objectToVerify, "Parsed1")["Key"]); + } + + if (skip2) + { + Assert.Null(GetProperty(objectToVerify, "Skipped2")); + } + else + { + Assert.Equal(2, GetProperty(objectToVerify, "Parsed2")["Key"]); + } + + if (skip3) + { + Assert.Null(GetProperty(objectToVerify, "Skipped3")); + } + else + { + Assert.Equal(3, GetProperty(objectToVerify, "Parsed3")["Key"]); + } + } + + // Tests that the parser picks back up after skipping/draining ignored elements. + StringBuilder json = new StringBuilder(@"{"); + + if (addMissing) + { + json.Append(@"""MissingProp1"": {},"); + } + + if (skip1) + { + json.Append(@"""Skipped1"":{},"); + } + else + { + json.Append(@"""Parsed1"":{""Key"":1},"); + } + + if (addMissing) + { + json.Append(@"""MissingProp2"": null,"); + } + + if (skip2) + { + json.Append(@"""Skipped2"":{},"); + } + else + { + json.Append(@"""Parsed2"":{""Key"":2},"); + } + + if (addMissing) + { + json.Append(@"""MissingProp3"": {""ABC"":{}},"); + } + + if (skip3) + { + json.Append(@"""Skipped3"":{}}"); + } + else + { + json.Append(@"""Parsed3"":{""Key"":3}}"); + } + + // Deserialize and verify. + string jsonString = json.ToString(); + T obj = JsonSerializer.Deserialize(jsonString); + Verify(obj); + + // Round-trip and verify. + // Any skipped properties due to lack of a setter will now be "null" when serialized instead of "{}". + string jsonStringRoundTripped = JsonSerializer.Serialize(obj); + T objRoundTripped = JsonSerializer.Deserialize(jsonStringRoundTripped); + Verify(objRoundTripped); + } + + public class ClassWithPopulatedDictionaryAndSetter + { + public ClassWithPopulatedDictionaryAndSetter() + { + MyImmutableDictionary = MyImmutableDictionary.Add("Key", "Value"); + } + + public Dictionary MyDictionary { get; set; } = new Dictionary() { { "Key", "Value" } }; + public ImmutableDictionary MyImmutableDictionary { get; set; } = ImmutableDictionary.Create(); + } + + [Fact] + public static void ClassWithPopulatedDictionary() + { + // We replace the contents. + string json = @"{""MyDictionary"":{""Key1"":""Value1"", ""Key2"":""Value2""}}"; + ClassWithPopulatedDictionaryAndSetter obj = JsonSerializer.Deserialize(json); + Assert.Equal(2, obj.MyDictionary.Count); + } + + [Fact] + public static void ClassWithPopulatedImmutableDictionary() + { + // We replace the contents. + string json = @"{""MyImmutableDictionary"":{""Key1"":""Value1"", ""Key2"":""Value2""}}"; + ClassWithPopulatedDictionaryAndSetter obj = JsonSerializer.Deserialize(json); + Assert.Equal(2, obj.MyImmutableDictionary.Count); + } + + [Fact] + public static void DictionaryNotSupported() + { + string json = @"{""MyDictionary"":{""Key"":""Value""}}"; + + NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json)); + + // The exception contains the type. + Assert.Contains(typeof(Dictionary).ToString(), ex.Message); + Assert.DoesNotContain("Path: ", ex.Message); + } + + [Fact] + public static void DictionaryNotSupportedButIgnored() + { + string json = @"{""MyDictionary"":{""Key"":1}}"; + ClassWithNotSupportedDictionaryButIgnored obj = JsonSerializer.Deserialize(json); + Assert.Null(obj.MyDictionary); + } + + // https://github.com/dotnet/runtime/issues/29933 + [Fact] + public static void Serialize_IDictionaryOfPoco() + { + // Arrange + var value = new AllSingleUpperPropertiesParent() + { + Child = new Dictionary() + { + ["1"] = new AllSingleUpperProperties_Child() + { + A = "1", + B = string.Empty, + C = Array.Empty(), + D = Array.Empty(), + F = Array.Empty(), + K = Array.Empty(), + } + } + }; + + var actual = JsonSerializer.Serialize(value, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + + // Assert + Assert.NotNull(actual); + Assert.NotEmpty(actual); + } + + // https://github.com/dotnet/runtime/issues/29933 + [Fact] + public static void Deserialize_IDictionaryOfPoco() + { + // Arrange + string json = "{\"child\":{\"1\":{\"a\":\"1\",\"b\":\"\",\"c\":[],\"d\":[],\"e\":null,\"f\":[],\"g\":null,\"h\":null,\"i\":null,\"j\":null,\"k\":[]}}}"; + + var actual = JsonSerializer.Deserialize(json, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + + // Assert + Assert.NotNull(actual); + Assert.NotNull(actual.Child); + Assert.Equal(1, actual.Child.Count); + Assert.True(actual.Child.ContainsKey("1")); + Assert.Equal("1", actual.Child["1"].A); + } + + // https://github.com/dotnet/runtime/issues/29893 + [Fact] + public static void ShouldHandleNullInDictionaries_Serialize() + { + var value = new ClassWithDictionaryOfString_ChildWithDictionaryOfString() + { + Test = "value1", + Child = new ClassWithDictionaryOfString() + }; + + var actual = JsonSerializer.Serialize(value); + Assert.Equal("{\"Test\":\"value1\",\"Dict\":null,\"Child\":{\"Test\":null,\"Dict\":null}}", actual); + } + + // https://github.com/dotnet/runtime/issues/29893 + [Fact] + public static void ShouldHandleNullInDictionaries_Deserialize() + { + var json = "{\"Test\":\"value1\",\"Dict\":null,\"Child\":{\"Test\":null,\"Dict\":null}}"; + ClassWithDictionaryOfString_ChildWithDictionaryOfString actual = JsonSerializer.Deserialize(json); + + Assert.Equal("value1", actual.Test); + Assert.Null(actual.Dict); + Assert.NotNull(actual.Child); + Assert.Null(actual.Child.Dict); + Assert.Null(actual.Child.Test); + } + + // https://github.com/dotnet/runtime/issues/29893 + [Fact] + public static void ShouldHandleNullInDictionaries_Serialize_IgnoreNullValues() + { + var value = new ClassWithDictionaryOfString_ChildWithDictionaryOfString() + { + Test = "value1", + Child = new ClassWithDictionaryOfString() + }; + + var actual = JsonSerializer.Serialize(value, new JsonSerializerOptions { IgnoreNullValues = true }); + Assert.Equal("{\"Test\":\"value1\",\"Child\":{}}", actual); + } + + // https://github.com/dotnet/runtime/issues/29893 + [Fact] + public static void ShouldHandleNullInDictionaries_Deserialize_IgnoreNullValues() + { + var json = "{\"Test\":\"value1\",\"Child\":{}}"; + ClassWithDictionaryOfString_ChildWithDictionaryOfString actual = JsonSerializer.Deserialize(json); + + Assert.Equal("value1", actual.Test); + Assert.Null(actual.Dict); + Assert.NotNull(actual.Child); + Assert.Null(actual.Child.Dict); + Assert.Null(actual.Child.Test); + } + + // https://github.com/dotnet/runtime/issues/29888 + [Fact] + public static void DictionaryWithNullShouldPreserveOrder_Serialize() + { + var dictionaryFirst = new ClassWithDictionaryAndProperty_DictionaryFirst() + { + Test = "value1" + }; + + var actual = JsonSerializer.Serialize(dictionaryFirst); + Assert.Equal("{\"Dict\":null,\"Test\":\"value1\"}", actual); + + var dictionaryLast = new ClassWithDictionaryAndProperty_DictionaryLast() + { + Test = "value1" + }; + + actual = JsonSerializer.Serialize(dictionaryLast); + Assert.Equal("{\"Test\":\"value1\",\"Dict\":null}", actual); + } + + // https://github.com/dotnet/runtime/issues/29888 + [Fact] + public static void DictionaryWithNullShouldPreserveOrder_Deserialize() + { + var json = "{\"Dict\":null,\"Test\":\"value1\"}"; + ClassWithDictionaryAndProperty_DictionaryFirst dictionaryFirst = JsonSerializer.Deserialize(json); + + Assert.Equal("value1", dictionaryFirst.Test); + Assert.Null(dictionaryFirst.Dict); + + json = "{\"Test\":\"value1\",\"Dict\":null}"; + ClassWithDictionaryAndProperty_DictionaryLast dictionaryLast = JsonSerializer.Deserialize(json); + + Assert.Equal("value1", dictionaryLast.Test); + Assert.Null(dictionaryLast.Dict); + } + + // https://github.com/dotnet/runtime/issues/29888 + [Fact] + public static void DictionaryWithNullShouldPreserveOrder_Serialize_IgnoreNullValues() + { + var dictionaryFirst = new ClassWithDictionaryAndProperty_DictionaryFirst() + { + Test = "value1" + }; + + var actual = JsonSerializer.Serialize(dictionaryFirst, new JsonSerializerOptions { IgnoreNullValues = true }); + Assert.Equal("{\"Test\":\"value1\"}", actual); + + var dictionaryLast = new ClassWithDictionaryAndProperty_DictionaryLast() + { + Test = "value1" + }; + + actual = JsonSerializer.Serialize(dictionaryLast, new JsonSerializerOptions { IgnoreNullValues = true }); + Assert.Equal("{\"Test\":\"value1\"}", actual); + } + + // https://github.com/dotnet/runtime/issues/29888 + [Fact] + public static void DictionaryWithNullShouldPreserveOrder_Deserialize_IgnoreNullValues() + { + var json = "{\"Test\":\"value1\"}"; + ClassWithDictionaryAndProperty_DictionaryFirst dictionaryFirst = JsonSerializer.Deserialize(json); + + Assert.Equal("value1", dictionaryFirst.Test); + Assert.Null(dictionaryFirst.Dict); + + json = "{\"Test\":\"value1\"}"; + ClassWithDictionaryAndProperty_DictionaryLast dictionaryLast = JsonSerializer.Deserialize(json); + + Assert.Equal("value1", dictionaryLast.Test); + Assert.Null(dictionaryLast.Dict); + } + + [Fact] + public static void NullDictionaryValuesShouldDeserializeAsNull() + { + const string json = + @"{" + + @"""StringVals"":{" + + @"""key"":null" + + @"}," + + @"""ObjectVals"":{" + + @"""key"":null" + + @"}," + + @"""StringDictVals"":{" + + @"""key"":null" + + @"}," + + @"""ObjectDictVals"":{" + + @"""key"":null" + + @"}," + + @"""ClassVals"":{" + + @"""key"":null" + + @"}" + + @"}"; + + SimpleClassWithDictionaries obj = JsonSerializer.Deserialize(json); + Assert.Null(obj.StringVals["key"]); + Assert.Null(obj.ObjectVals["key"]); + Assert.Null(obj.StringDictVals["key"]); + Assert.Null(obj.ObjectDictVals["key"]); + Assert.Null(obj.ClassVals["key"]); + } + + public class ClassWithNotSupportedDictionary + { + public Dictionary MyDictionary { get; set; } + } + + public class ClassWithNotSupportedDictionaryButIgnored + { + [JsonIgnore] public Dictionary MyDictionary { get; set; } + } + + public class AllSingleUpperPropertiesParent + { + public IDictionary Child { get; set; } + } + + public class AllSingleUpperProperties_Child + { + public string A { get; set; } + public string B { get; set; } + public string[] C { get; set; } + public string[] D { get; set; } + public bool? E { get; set; } + public string[] F { get; set; } + public DateTimeOffset? G { get; set; } + public DateTimeOffset? H { get; set; } + public int? I { get; set; } + public int? J { get; set; } + public string[] K { get; set; } + } + + public class ClassWithDictionaryOfString_ChildWithDictionaryOfString + { + public string Test { get; set; } + public Dictionary Dict { get; set; } + public ClassWithDictionaryOfString Child { get; set; } + } + + public class ClassWithDictionaryOfString + { + public string Test { get; set; } + public Dictionary Dict { get; set; } + } + + public class ClassWithDictionaryAndProperty_DictionaryLast + { + public string Test { get; set; } + public Dictionary Dict { get; set; } + } + + public class ClassWithDictionaryAndProperty_DictionaryFirst + { + public Dictionary Dict { get; set; } + public string Test { get; set; } + } + + public class SimpleClassWithDictionaries + { + public Dictionary StringVals { get; set; } + public Dictionary ObjectVals { get; set; } + public Dictionary> StringDictVals { get; set; } + public Dictionary> ObjectDictVals { get; set; } + public Dictionary ClassVals { get; set; } + } + + public class DictionaryThatOnlyImplementsIDictionaryOfStringTValue : IDictionary + { + IDictionary _inner = new Dictionary(); + + public TValue this[string key] + { + get + { + return _inner[key]; + } + set + { + _inner[key] = value; + } + } + + public ICollection Keys => _inner.Keys; + + public ICollection Values => _inner.Values; + + public int Count => _inner.Count; + + public bool IsReadOnly => _inner.IsReadOnly; + + public void Add(string key, TValue value) + { + _inner.Add(key, value); + } + + public void Add(KeyValuePair item) + { + _inner.Add(item); + } + + public void Clear() + { + throw new NotImplementedException(); + } + + public bool Contains(KeyValuePair item) + { + return _inner.Contains(item); + } + + public bool ContainsKey(string key) + { + return _inner.ContainsKey(key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + // CopyTo should not be called. + throw new NotImplementedException(); + } + + public IEnumerator> GetEnumerator() + { + // Don't return results directly from _inner since that will return an enumerator that returns + // IDictionaryEnumerator which should not require. + foreach (KeyValuePair keyValuePair in _inner) + { + yield return keyValuePair; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + // This GetEnumerator() should not be called. + throw new NotImplementedException(); + } + + public bool Remove(string key) + { + // Remove should not be called. + throw new NotImplementedException(); + } + + public bool Remove(KeyValuePair item) + { + // Remove should not be called. + throw new NotImplementedException(); + } + + public bool TryGetValue(string key, out TValue value) + { + return _inner.TryGetValue(key, out value); + } + } + + [Fact] + public static void DictionaryOfTOnlyWithStringTValueAsInt() + { + const string Json = @"{""One"":1,""Two"":2}"; + + DictionaryThatOnlyImplementsIDictionaryOfStringTValue dictionary; + + dictionary = JsonSerializer.Deserialize>(Json); + Assert.Equal(1, dictionary["One"]); + Assert.Equal(2, dictionary["Two"]); + + string json = JsonSerializer.Serialize(dictionary); + Assert.Equal(Json, json); + } + + [Fact] + public static void DictionaryOfTOnlyWithStringTValueAsPoco() + { + const string Json = @"{""One"":{""Id"":1},""Two"":{""Id"":2}}"; + + DictionaryThatOnlyImplementsIDictionaryOfStringTValue dictionary; + + dictionary = JsonSerializer.Deserialize>(Json); + Assert.Equal(1, dictionary["One"].Id); + Assert.Equal(2, dictionary["Two"].Id); + + string json = JsonSerializer.Serialize(dictionary); + Assert.Equal(Json, json); + } + + public class DictionaryThatOnlyImplementsIDictionaryOfStringPoco : DictionaryThatOnlyImplementsIDictionaryOfStringTValue + { + } + + [Fact] + public static void DictionaryOfTOnlyWithStringPoco() + { + const string Json = @"{""One"":{""Id"":1},""Two"":{""Id"":2}}"; + + DictionaryThatOnlyImplementsIDictionaryOfStringPoco dictionary; + + dictionary = JsonSerializer.Deserialize(Json); + Assert.Equal(1, dictionary["One"].Id); + Assert.Equal(2, dictionary["Two"].Id); + + string json = JsonSerializer.Serialize(dictionary); + Assert.Equal(Json, json); + } + + public class DictionaryThatHasIncompatibleEnumerator : IDictionary + { + Hashtable _inner = new Hashtable(); + + public object this[string key] + { + get + { + return _inner[key]; + } + set + { + _inner[key] = value; + } + } + + public ICollection Keys => _inner.Keys; + + public ICollection Values => _inner.Values; + + public int Count => _inner.Count; + + public bool IsReadOnly => _inner.IsReadOnly; + + public bool IsFixedSize => _inner.IsFixedSize; + + public bool IsSynchronized => throw new NotImplementedException(); + + public object SyncRoot => throw new NotImplementedException(); + + public object this[object key] + { + get + { + return _inner[key]; + } + set + { + _inner[key] = value; + } + } + + public void Add(object key, object value) + { + _inner.Add(key, value); + } + + public void Clear() + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + + public bool Contains(object key) + { + throw new NotImplementedException(); + } + + public IDictionaryEnumerator GetEnumerator() + { + // Throw NotSupportedException so we can detect this GetEnumerator was called. + throw new NotSupportedException(); + } + + public void Remove(object key) + { + throw new NotImplementedException(); + } + + public void CopyTo(Array array, int index) + { + throw new NotImplementedException(); + } + } + + [Fact] + public static void VerifyDictionaryThatHasIncomatibleEnumeratorWithInt() + { + const string Json = @"{""One"":1,""Two"":2}"; + + DictionaryThatHasIncompatibleEnumerator dictionary; + dictionary = JsonSerializer.Deserialize(Json); + Assert.Equal(1, ((JsonElement)dictionary["One"]).GetInt32()); + Assert.Equal(2, ((JsonElement)dictionary["Two"]).GetInt32()); + Assert.Throws(() => JsonSerializer.Serialize(dictionary)); + } + + [Fact] + public static void VerifyDictionaryThatHasIncomatibleEnumeratorWithPoco() + { + const string Json = @"{""One"":{""Id"":1},""Two"":{""Id"":2}}"; + + DictionaryThatHasIncompatibleEnumerator dictionary; + dictionary = JsonSerializer.Deserialize(Json); + Assert.Equal(1, ((JsonElement)dictionary["One"]).GetProperty("Id").GetInt32()); + Assert.Equal(2, ((JsonElement)dictionary["Two"]).GetProperty("Id").GetInt32()); + Assert.Throws(() => JsonSerializer.Serialize(dictionary)); + } + + + [Fact] + public static void VerifyIDictionaryWithNonStringKey() + { + IDictionary dictionary = new Hashtable(); + dictionary.Add(1, "value"); + Assert.Throws(() => JsonSerializer.Serialize(dictionary)); + } + + private class ClassWithoutParameterlessCtor + { + public ClassWithoutParameterlessCtor(int num) { } + public string Name { get; set; } + } + + private class ClassWithInternalParameterlessConstructor + { + internal ClassWithInternalParameterlessConstructor() { } + public string Name { get; set; } + } + + private class ClassWithPrivateParameterlessConstructor + { + private ClassWithPrivateParameterlessConstructor() { } + public string Name { get; set; } + } + + [Fact] + public static void DictionaryWith_ObjectWithNoParameterlessCtor_AsValue_Throws() + { + Assert.Throws(() => JsonSerializer.Deserialize>(@"{""key"":{}}")); + Assert.Throws(() => JsonSerializer.Deserialize>(@"{""key"":{}}")); + } + + [Fact] + public static void DictionaryWith_ObjectWithNoParameterlessCtor_Serialize_Works() + { + var noParameterless = new Dictionary() + { + ["key"] = new ClassWithoutParameterlessCtor(5) + { + Name = "parameterless" + } + }; + + string json = JsonSerializer.Serialize(noParameterless); + Assert.Equal("{\"key\":{\"Name\":\"parameterless\"}}", json); + + var onlyInternal = new Dictionary() + { + ["key"] = new ClassWithInternalParameterlessConstructor() + { + Name = "internal" + } + }; + + json = JsonSerializer.Serialize(onlyInternal); + Assert.Equal("{\"key\":{\"Name\":\"internal\"}}", json); + + var onlyPrivate = new Dictionary() + { + ["key"] = null + }; + + json = JsonSerializer.Serialize(onlyPrivate); + Assert.Equal("{\"key\":null}", json); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Generic.Read.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Generic.Read.cs new file mode 100644 index 00000000000000..3e9eae828e837e --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Generic.Read.cs @@ -0,0 +1,1157 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CollectionTests + { + [Fact] + public static void ReadListOfList() + { + List> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + + Assert.Equal(1, result[0][0]); + Assert.Equal(2, result[0][1]); + Assert.Equal(3, result[1][0]); + Assert.Equal(4, result[1][1]); + + GenericListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + + Assert.Equal("1", result2[0][0]); + Assert.Equal("2", result2[0][1]); + Assert.Equal("3", result2[1][0]); + Assert.Equal("4", result2[1][1]); + } + + [Fact] + public static void ReadListOfArray() + { + List result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + + Assert.Equal(1, result[0][0]); + Assert.Equal(2, result[0][1]); + Assert.Equal(3, result[1][0]); + Assert.Equal(4, result[1][1]); + + GenericListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + + Assert.Equal("1", result2[0][0]); + Assert.Equal("2", result2[0][1]); + Assert.Equal("3", result2[1][0]); + Assert.Equal("4", result2[1][1]); + } + + [Fact] + public static void ReadArrayOfList() + { + List[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + + Assert.Equal(1, result[0][0]); + Assert.Equal(2, result[0][1]); + Assert.Equal(3, result[1][0]); + Assert.Equal(4, result[1][1]); + + StringListWrapper[] result2 = JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]"); + Assert.Equal("1", result2[0][0]); + Assert.Equal("2", result2[0][1]); + Assert.Equal("3", result2[1][0]); + Assert.Equal("4", result2[1][1]); + } + + [Fact] + public static void ReadSimpleList() + { + List i = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + Assert.Equal(1, i[0]); + Assert.Equal(2, i[1]); + + i = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, i.Count); + + StringListWrapper i2 = JsonSerializer.Deserialize(@"[""1"",""2""]"); + Assert.Equal("1", i2[0]); + Assert.Equal("2", i2[1]); + + i2 = JsonSerializer.Deserialize(@"[]"); + Assert.Equal(0, i2.Count); + } + + [Fact] + public static void ReadGenericIEnumerableOfGenericIEnumerable() + { + IEnumerable> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IEnumerable ie in result) + { + foreach (int i in ie) + { + Assert.Equal(expected++, i); + } + } + + // No way to populate this collection. + Assert.Throws(() => JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]")); + } + + [Fact] + public static void ReadIEnumerableTOfArray() + { + IEnumerable result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + + // No way to populate this collection. + Assert.Throws(() => JsonSerializer.Deserialize>(@"[[1,2],[3, 4]]")); + } + + [Fact] + public static void ReadArrayOfIEnumerableT() + { + IEnumerable[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IEnumerable arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + + // No way to populate this collection. + Assert.Throws(() => JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]")); + } + + [Fact] + public static void ReadSimpleGenericIEnumerable() + { + IEnumerable result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + + // There is no way to populate this collection. + Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); + Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); + } + + [Fact] + public static void ReadIListTOfIListT() + { + IList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IList ie in result) + { + foreach (int i in ie) + { + Assert.Equal(expected++, i); + } + } + + GenericIListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + expected = 1; + + foreach (StringIListWrapper il in result2) + { + foreach (string str in il) + { + Assert.Equal($"{expected++}", str); + } + } + } + + [Fact] + public static void ReadGenericIListOfArray() + { + IList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + + GenericIListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + expected = 1; + + foreach (string[] arr in result2) + { + foreach (string str in arr) + { + Assert.Equal($"{expected++}", str); + } + } + } + + [Fact] + public static void ReadArrayOfIListT() + { + IList[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IList arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + + StringIListWrapper[] result2 = JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]"); + expected = 1; + + foreach (StringIListWrapper il in result2) + { + foreach (string str in il) + { + Assert.Equal($"{expected++}", str); + } + } + } + + [Fact] + public static void ReadSimpleGenericIList() + { + IList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + + StringIListWrapper result2 = JsonSerializer.Deserialize(@"[""1"",""2""]"); + expected = 1; + + foreach (string str in result2) + { + Assert.Equal($"{expected++}", str); + } + + result2 = JsonSerializer.Deserialize(@"[]"); + Assert.Equal(0, result2.Count()); + } + + [Fact] + public static void ReadGenericICollectionOfGenericICollection() + { + ICollection> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (ICollection ie in result) + { + foreach (int i in ie) + { + Assert.Equal(expected++, i); + } + } + + GenericICollectionWrapper> result2 = + JsonSerializer.Deserialize>>(@"[[""1"",""2""],[""3"",""4""]]"); + expected = 1; + + foreach (GenericICollectionWrapper ic in result2) + { + foreach (string str in ic) + { + Assert.Equal($"{expected++}", str); + } + } + } + + [Fact] + public static void ReadGenericICollectionOfArray() + { + ICollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + + GenericICollectionWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + expected = 1; + + foreach (string[] arr in result2) + { + foreach (string str in arr) + { + Assert.Equal($"{expected++}", str); + } + } + } + + [Fact] + public static void ReadArrayOfGenericICollection() + { + ICollection[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (ICollection arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadSimpleGenericICollection() + { + ICollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + + GenericICollectionWrapper result2 = JsonSerializer.Deserialize>(@"[""1"",""2""]"); + expected = 1; + + foreach (string str in result2) + { + Assert.Equal($"{expected++}", str); + } + + result2 = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result2.Count()); + } + + [Fact] + public static void ReadGenericIReadOnlyCollectionOfGenericIReadOnlyCollection() + { + IReadOnlyCollection> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IReadOnlyCollection ie in result) + { + foreach (int i in ie) + { + Assert.Equal(expected++, i); + } + } + + // There's no way to populate this collection. + Assert.Throws( + () => JsonSerializer.Deserialize>>(@"[[""1"",""2""],[""3"",""4""]]")); + } + + [Fact] + public static void ReadGenericIReadOnlyCollectionOfArray() + { + IReadOnlyCollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + + Assert.Throws(() => JsonSerializer.Deserialize>(@"[[1,2],[3,4]]")); + } + + [Fact] + public static void ReadArrayOfIReadOnlyCollectionT() + { + IReadOnlyCollection[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IReadOnlyCollection arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + + // No way to populate this collection. + Assert.Throws(() => JsonSerializer.Deserialize[]>(@"[[""1"",""2""],[""3"",""4""]]")); + } + + [Fact] + public static void ReadGenericSimpleIReadOnlyCollection() + { + IReadOnlyCollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + + // No way to populate this collection. + Assert.Throws(() => JsonSerializer.Deserialize>(@"[""1"",""2""]")); + } + + [Fact] + public static void ReadGenericIReadOnlyListOfGenericIReadOnlyList() + { + IReadOnlyList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IReadOnlyList ie in result) + { + foreach (int i in ie) + { + Assert.Equal(expected++, i); + } + } + + Assert.Throws(() => JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]")); + } + + [Fact] + public static void ReadGenericIReadOnlyListOfArray() + { + IReadOnlyList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + + // No way to populate this collection. + Assert.Throws(() => JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]")); + } + + [Fact] + public static void ReadArrayOfGenericIReadOnlyList() + { + IReadOnlyList[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IReadOnlyList arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + + // No way to populate this collection. + Assert.Throws(() => JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]")); + } + + [Fact] + public static void ReadSimpleGenericIReadOnlyList() + { + IReadOnlyList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + + // No way to populate this collection. + Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); + } + + [Fact] + public static void ReadGenericISetOfGenericISet() + { + ISet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + + if (result.First().Contains(1)) + { + Assert.Equal(new HashSet { 1, 2 }, result.First()); + Assert.Equal(new HashSet { 3, 4 }, result.Last()); + } + else + { + Assert.Equal(new HashSet { 3, 4 }, result.First()); + Assert.Equal(new HashSet { 1, 2 }, result.Last()); + } + + GenericISetWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + + if (result2.First().Contains("1")) + { + Assert.Equal(new HashSet { "1", "2" }, (ISet)result2.First()); + Assert.Equal(new HashSet { "3", "4" }, (ISet)result2.Last()); + } + else + { + Assert.Equal(new HashSet { "3", "4" }, (ISet)result.First()); + Assert.Equal(new HashSet { "1", "2" }, (ISet)result.Last()); + } + } + + [Fact] + public static void ReadISetTOfHashSetT() + { + ISet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + + if (result.First().Contains(1)) + { + Assert.Equal(new HashSet { 1, 2 }, result.First()); + Assert.Equal(new HashSet { 3, 4 }, result.Last()); + } + else + { + Assert.Equal(new HashSet { 3, 4 }, result.First()); + Assert.Equal(new HashSet { 1, 2 }, result.Last()); + } + } + + [Fact] + public static void ReadHashSetTOfISetT() + { + HashSet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + + if (result.First().Contains(1)) + { + Assert.Equal(new HashSet { 1, 2 }, result.First()); + Assert.Equal(new HashSet { 3, 4 }, result.Last()); + } + else + { + Assert.Equal(new HashSet { 3, 4 }, result.First()); + Assert.Equal(new HashSet { 1, 2 }, result.Last()); + } + } + + [Fact] + public static void ReadISetTOfArray() + { + ISet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + + if (result.First().Contains(1)) + { + Assert.Equal(new HashSet { 1, 2 }, result.First()); + Assert.Equal(new HashSet { 3, 4 }, result.Last()); + } + else + { + Assert.Equal(new HashSet { 3, 4 }, result.First()); + Assert.Equal(new HashSet { 1, 2 }, result.Last()); + } + } + + [Fact] + public static void ReadArrayOfISetT() + { + ISet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + + Assert.Equal(new HashSet { 1, 2 }, result.First()); + Assert.Equal(new HashSet { 3, 4 }, result.Last()); + } + + [Fact] + public static void ReadSimpleISetT() + { + ISet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + + Assert.Equal(new HashSet { 1, 2 }, result); + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + } + + [Fact] + public static void StackTOfStackT() + { + Stack> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 4; + + foreach (Stack st in result) + { + foreach (int i in st) + { + Assert.Equal(expected--, i); + } + } + + GenericStackWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + expected = 4; + + foreach (StringStackWrapper st in result2) + { + foreach (string str in st) + { + Assert.Equal($"{expected--}", str); + } + } + } + + [Fact] + public static void ReadGenericStackOfArray() + { + Stack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 3; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + + expected = 1; + } + + GenericStackWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + expected = 3; + + foreach (string[] arr in result2) + { + foreach (string str in arr) + { + Assert.Equal($"{expected++}", str); + } + + expected = 1; + } + } + + [Fact] + public static void ReadArrayOfGenericStack() + { + Stack[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 2; + + foreach (Stack st in result) + { + foreach (int i in st) + { + Assert.Equal(expected--, i); + } + + expected = 4; + } + + StringStackWrapper[] result2 = JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]"); + expected = 2; + + foreach (StringStackWrapper st in result2) + { + foreach (string str in st) + { + Assert.Equal($"{expected--}", str); + } + + expected = 4; + } + } + + [Fact] + public static void ReadSimpleGenericStack() + { + Stack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 2; + + foreach (int i in result) + { + Assert.Equal(expected--, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + + StringStackWrapper result2 = JsonSerializer.Deserialize(@"[""1"",""2""]"); + expected = 2; + + foreach (string str in result2) + { + Assert.Equal($"{expected--}", str); + } + + result2 = JsonSerializer.Deserialize(@"[]"); + Assert.Equal(0, result2.Count()); + } + + [Fact] + public static void ReadQueueTOfQueueT() + { + Queue> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (Queue q in result) + { + foreach (int i in q) + { + Assert.Equal(expected++, i); + } + } + + GenericQueueWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + expected = 1; + + foreach (StringQueueWrapper q in result2) + { + foreach (string str in q) + { + Assert.Equal($"{expected++}", str); + } + } + } + + [Fact] + public static void ReadQueueTOfArray() + { + Queue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadArrayOfIQueueT() + { + Queue[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (Queue q in result) + { + foreach (int i in q) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadSimpleQueueT() + { + Queue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + + } + + [Fact] + public static void ReadHashSetTOfHashSetT() + { + HashSet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (HashSet hs in result) + { + foreach (int i in hs) + { + Assert.Equal(expected++, i); + } + } + + GenericHashSetWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + expected = 1; + + foreach (StringHashSetWrapper hs in result2) + { + foreach (string str in hs) + { + Assert.Equal($"{expected++}", str); + } + } + } + + [Fact] + public static void ReadHashSetTOfArray() + { + HashSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadArrayOfIHashSetT() + { + HashSet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (HashSet hs in result) + { + foreach (int i in hs) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadSimpleHashSetT() + { + HashSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + } + + [Fact] + public static void ReadGenericLinkedListOfGenericLinkedList() + { + LinkedList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (LinkedList l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + + GenericLinkedListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + expected = 1; + + foreach (StringLinkedListWrapper l in result2) + { + foreach (string str in l) + { + Assert.Equal($"{expected++}", str); + } + } + } + + [Fact] + public static void ReadLinkedListTOfArray() + { + LinkedList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadArrayOfILinkedListT() + { + LinkedList[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (LinkedList l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadSimpleLinkedListT() + { + LinkedList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + } + + [Fact] + public static void ReadArrayOfSortedSetT() + { + SortedSet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (SortedSet s in result) + { + foreach (int i in s) + { + Assert.Equal(expected++, i); + } + } + + StringSortedSetWrapper[] result2 = JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]"); + expected = 1; + + foreach (StringSortedSetWrapper s in result2) + { + foreach (string str in s) + { + Assert.Equal($"{expected++}", str); + } + } + } + + [Fact] + public static void ReadSimpleSortedSetT() + { + SortedSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + } + + [Fact] + public static void ReadSimpleTestClass_GenericCollectionWrappers() + { + SimpleTestClassWithGenericCollectionWrappers obj = JsonSerializer.Deserialize(SimpleTestClassWithGenericCollectionWrappers.s_json); + obj.Verify(); + } + + [Theory] + [MemberData(nameof(ReadSimpleTestClass_GenericWrappers_NoAddMethod))] + public static void ReadSimpleTestClass_GenericWrappers_NoAddMethod_Throws(Type type, string json, Type exceptionMessageType) + { + NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); + Assert.Contains(exceptionMessageType.ToString(), ex.Message); + } + + public static IEnumerable ReadSimpleTestClass_GenericWrappers_NoAddMethod + { + get + { + yield return new object[] + { + typeof(SimpleTestClassWithStringIEnumerableWrapper), + SimpleTestClassWithStringIEnumerableWrapper.s_json, + typeof(StringIEnumerableWrapper) + }; + yield return new object[] + { + typeof(SimpleTestClassWithStringIReadOnlyCollectionWrapper), + SimpleTestClassWithStringIReadOnlyCollectionWrapper.s_json, + typeof(WrapperForIReadOnlyCollectionOfT) + }; + yield return new object[] + { + typeof(SimpleTestClassWithStringIReadOnlyListWrapper), + SimpleTestClassWithStringIReadOnlyListWrapper.s_json, + typeof(StringIReadOnlyListWrapper) + }; + yield return new object[] + { + typeof(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper), + SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper.s_json, + typeof(GenericIReadOnlyDictionaryWrapper) + }; + } + } + + [Theory] + [InlineData(typeof(ReadOnlyWrapperForIList), @"[""1"", ""2""]")] + [InlineData(typeof(ReadOnlyStringIListWrapper), @"[""1"", ""2""]")] + [InlineData(typeof(ReadOnlyStringICollectionWrapper), @"[""1"", ""2""]")] + [InlineData(typeof(ReadOnlyStringISetWrapper), @"[""1"", ""2""]")] + [InlineData(typeof(ReadOnlyWrapperForIDictionary), @"{""Key"":""key"",""Value"":""value""}")] + [InlineData(typeof(ReadOnlyStringToStringIDictionaryWrapper), @"{""Key"":""key"",""Value"":""value""}")] + public static void ReadReadOnlyCollections_Throws(Type type, string json) + { + NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); + Assert.Contains(type.ToString(), ex.Message); + } + + [Fact] + public static void Read_HigherOrderCollectionInheritance_Works() + { + const string json = "[\"test\"]"; + Assert.Equal("test", JsonSerializer.Deserialize(json)[0]); + Assert.Equal("test", JsonSerializer.Deserialize>(json).First()); + Assert.Equal("test", JsonSerializer.Deserialize(json).First()); + Assert.Equal("test", JsonSerializer.Deserialize>(json).First()); + Assert.Equal("test", JsonSerializer.Deserialize>(json).First()); + Assert.Equal("test", JsonSerializer.Deserialize(json).First()); + } + + [Theory] + [InlineData(typeof(GenericIEnumerableWrapperPrivateConstructor), @"[""1""]")] + [InlineData(typeof(GenericIEnumerableWrapperInternalConstructor), @"[""1""]")] + [InlineData(typeof(GenericICollectionWrapperPrivateConstructor), @"[""1""]")] + [InlineData(typeof(GenericICollectionWrapperInternalConstructor), @"[""1""]")] + [InlineData(typeof(GenericIListWrapperPrivateConstructor), @"[""1""]")] + [InlineData(typeof(GenericIListWrapperInternalConstructor), @"[""1""]")] + [InlineData(typeof(GenericISetWrapperPrivateConstructor), @"[""1""]")] + [InlineData(typeof(GenericISetWrapperInternalConstructor), @"[""1""]")] + [InlineData(typeof(GenericIDictionaryWrapperPrivateConstructor), @"{""Key"":""Value""}")] + [InlineData(typeof(GenericIDictionaryWrapperInternalConstructor), @"{""Key"":""Value""}")] + [InlineData(typeof(StringToStringIReadOnlyDictionaryWrapperPrivateConstructor), @"{""Key"":""Value""}")] + [InlineData(typeof(StringToStringIReadOnlyDictionaryWrapperInternalConstructor), @"{""Key"":""Value""}")] + [InlineData(typeof(GenericListWrapperPrivateConstructor), @"[""1""]")] + [InlineData(typeof(GenericListWrapperInternalConstructor), @"[""1""]")] + [InlineData(typeof(GenericQueueWrapperPrivateConstructor), @"[""1""]")] + [InlineData(typeof(GenericQueueWrapperInternalConstructor), @"[""1""]")] + [InlineData(typeof(GenericStackWrapperPrivateConstructor), @"[""1""]")] + [InlineData(typeof(GenericStackWrapperInternalConstructor), @"[""1""]")] + [InlineData(typeof(StringToGenericDictionaryWrapperPrivateConstructor), @"{""Key"":""Value""}")] + [InlineData(typeof(StringToGenericDictionaryWrapperInternalConstructor), @"{""Key"":""Value""}")] + public static void Read_Generic_NoPublicConstructor_Throws(Type type, string json) + { + NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); + Assert.Contains(type.ToString(), ex.Message); + } + + [Fact] + public static void DoesNotCall_CollectionPropertyGetter_EveryTimeElementIsAdded() + { + var networkList = new List { "Network1", "Network2" }; + + string serialized = JsonSerializer.Serialize(new NetworkWrapper { NetworkList = networkList }); + Assert.Equal(@"{""NetworkList"":[""Network1"",""Network2""]}", serialized); + + NetworkWrapper obj = JsonSerializer.Deserialize(serialized); + + int i = 0; + foreach (string network in obj.NetworkList) + { + Assert.Equal(networkList[i], network); + i++; + } + } + + public class NetworkWrapper + { + private string _Networks = string.Empty; + + [JsonIgnore] + public string Networks + { + get => _Networks; + set => _Networks = value ?? string.Empty; + } + + public IEnumerable NetworkList + { + get => Networks.Split(','); + set => Networks = value != null ? string.Join(",", value) : ""; + } + } + + [Fact] + public static void CollectionWith_BackingField_CanRoundtrip() + { + string json = "{\"AllowedGrantTypes\":[\"client_credentials\"]}"; + + Client obj = JsonSerializer.Deserialize(json); + Assert.Equal("client_credentials", obj.AllowedGrantTypes.First()); + + string serialized = JsonSerializer.Serialize(obj); + Assert.Equal(json, serialized); + } + + private class Client + { + private ICollection _allowedGrantTypes = new HashSetWithBackingCollection(); + + public ICollection AllowedGrantTypes + { + get { return _allowedGrantTypes; } + set { _allowedGrantTypes = new HashSetWithBackingCollection(value); } + } + } + + [Theory] + [MemberData(nameof(CustomInterfaces_Enumerables))] + public static void CustomInterfacesNotSupported_Enumerables(Type type) + { + NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize("[]", type)); + Assert.Contains(type.ToString(), ex.ToString()); + } + + [Theory] + [MemberData(nameof(CustomInterfaces_Dictionaries))] + public static void CustomInterfacesNotSupported_Dictionaries(Type type) + { + NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize("{}", type)); + Assert.Contains(type.ToString(), ex.ToString()); + } + + private static IEnumerable CustomInterfaces_Enumerables() + { + yield return new object[] { typeof(IDerivedICollectionOfT) }; + yield return new object[] { typeof(IDerivedIList) }; + yield return new object[] { typeof(IDerivedISetOfT) }; + } + + private static IEnumerable CustomInterfaces_Dictionaries() + { + yield return new object[] { typeof(IDerivedIDictionaryOfTKeyTValue) }; + } + + [Fact] + public static void IReadOnlyDictionary_NonStringKey_NotSupported() + { + Assert.Throws(() => JsonSerializer.Deserialize>("")); + Assert.Throws(() => JsonSerializer.Serialize(new GenericIReadOnlyDictionaryWrapper())); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Generic.Write.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Generic.Write.cs new file mode 100644 index 00000000000000..2c2c61819d1ac6 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Generic.Write.cs @@ -0,0 +1,814 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CollectionTests + { + [Fact] + public static void WriteListOfList() + { + var input = new List> + { + new List() { 1, 2 }, + new List() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + + var input2 = new GenericListWrapper + { + new StringListWrapper() { "1", "2" }, + new StringListWrapper() { "3", "4" } + }; + + json = JsonSerializer.Serialize(input2); + Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); + } + + [Fact] + public static void WriteListOfArray() + { + var input = new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfList() + { + var input = new List[2]; + input[0] = new List() { 1, 2 }; + input[1] = new List() { 3, 4 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveList() + { + var input = new List { 1, 2 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteGenericIEnumerableOfGenericIEnumerable() + { + IEnumerable> input = new List> + { + new List() { 1, 2 }, + new List() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + + GenericIEnumerableWrapper input2 = new GenericIEnumerableWrapper(new List + { + new StringIEnumerableWrapper(new List { "1", "2" }), + new StringIEnumerableWrapper(new List { "3", "4" }), + }); + + json = JsonSerializer.Serialize(input2); + Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); + } + + [Fact] + public static void WriteIEnumerableTOfArray() + { + IEnumerable input = new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfIEnumerableT() + { + IEnumerable[] input = new List[2]; + input[0] = new List() { 1, 2 }; + input[1] = new List() { 3, 4 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveIEnumerableT() + { + IEnumerable input = new List { 1, 2 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteGenericIListOfGenericIList() + { + IList> input = new List> + { + new List() { 1, 2 }, + new List() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + + GenericIListWrapper input2 = new GenericIListWrapper + { + new StringIListWrapper() { "1", "2" }, + new StringIListWrapper() { "3", "4" } + }; + + json = JsonSerializer.Serialize(input2); + Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); + } + + [Fact] + public static void WriteIListTOfArray() + { + IList input = new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfIListT() + { + IList[] input = new List[2]; + input[0] = new List() { 1, 2 }; + input[1] = new List() { 3, 4 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveIListT() + { + IList input = new List { 1, 2 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteGenericICollectionOfGenericICollection() + { + ICollection> input = new List> + { + new List() { 1, 2 }, + new List() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + + GenericICollectionWrapper> input2 = new GenericICollectionWrapper> + { + new GenericICollectionWrapper() { "1", "2" }, + new GenericICollectionWrapper() { "3", "4" } + }; + + json = JsonSerializer.Serialize(input2); + Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); + } + + [Fact] + public static void WriteICollectionTOfArray() + { + ICollection input = new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfICollectionT() + { + ICollection[] input = new List[2]; + input[0] = new List() { 1, 2 }; + input[1] = new List() { 3, 4 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveICollectionT() + { + ICollection input = new List { 1, 2 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteGenericIReadOnlyCollectionOfGenericIReadOnlyCollection() + { + IReadOnlyCollection> input = new List> + { + new List() { 1, 2 }, + new List() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + + GenericIReadOnlyCollectionWrapper> input2 = + new GenericIReadOnlyCollectionWrapper>(new List> + { + new WrapperForIReadOnlyCollectionOfT(new List { "1", "2" }), + new WrapperForIReadOnlyCollectionOfT(new List { "3", "4" }) + }); + + json = JsonSerializer.Serialize(input2); + Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); + } + + [Fact] + public static void WriteIReadOnlyCollectionTOfArray() + { + IReadOnlyCollection input = new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfIReadOnlyCollectionT() + { + IReadOnlyCollection[] input = new List[2]; + input[0] = new List() { 1, 2 }; + input[1] = new List() { 3, 4 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveIReadOnlyCollectionT() + { + IReadOnlyCollection input = new List { 1, 2 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteIReadOnlyListTOfIReadOnlyListT() + { + IReadOnlyList> input = new List> + { + new List() { 1, 2 }, + new List() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + + GenericIReadOnlyListWrapper input2 = new GenericIReadOnlyListWrapper(new List + { + new StringIReadOnlyListWrapper(new List { "1", "2" }), + new StringIReadOnlyListWrapper(new List { "3", "4" }) + }); + + json = JsonSerializer.Serialize(input2); + Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); + } + + [Fact] + public static void WriteIReadOnlyListTOfArray() + { + IReadOnlyList input = new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfIReadOnlyListT() + { + IReadOnlyList[] input = new List[2]; + input[0] = new List() { 1, 2 }; + input[1] = new List() { 3, 4 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveIReadOnlyListT() + { + IReadOnlyList input = new List { 1, 2 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteISetTOfISetT() + { + ISet> input = new HashSet> + { + new HashSet() { 1, 2 }, + new HashSet() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + + // Because order isn't guaranteed, roundtrip data to ensure write was accurate. + input = JsonSerializer.Deserialize>>(json); + + if (input.First().Contains(1)) + { + Assert.Equal(new HashSet { 1, 2 }, input.First()); + Assert.Equal(new HashSet { 3, 4 }, input.Last()); + } + else + { + Assert.Equal(new HashSet { 3, 4 }, input.First()); + Assert.Equal(new HashSet { 1, 2 }, input.Last()); + } + + GenericISetWrapper input2 = new GenericISetWrapper + { + new StringISetWrapper() { "1", "2" }, + new StringISetWrapper() { "3", "4" }, + }; + + json = JsonSerializer.Serialize(input2); + + // Because order isn't guaranteed, roundtrip data to ensure write was accurate. + input2 = JsonSerializer.Deserialize>(json); + + if (input2.First().Contains("1")) + { + Assert.Equal(new StringISetWrapper() { "1", "2" }, input2.First()); + Assert.Equal(new StringISetWrapper() { "3", "4" }, input2.Last()); + } + else + { + Assert.Equal(new StringISetWrapper() { "3", "4" }, input2.First()); + Assert.Equal(new StringISetWrapper() { "1", "2" }, input2.Last()); + } + } + + [Fact] + public static void WriteISetTOfHashSetT() + { + ISet> input = new HashSet> + { + new HashSet() { 1, 2 }, + new HashSet() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + + // Because order isn't guaranteed, roundtrip data to ensure write was accurate. + input = JsonSerializer.Deserialize>>(json); + + if (input.First().Contains(1)) + { + Assert.Equal(new HashSet { 1, 2 }, input.First()); + Assert.Equal(new HashSet { 3, 4 }, input.Last()); + } + else + { + Assert.Equal(new HashSet { 3, 4 }, input.First()); + Assert.Equal(new HashSet { 1, 2 }, input.Last()); + } + } + + [Fact] + public static void WriteHashSetTOfISetT() + { + HashSet> input = new HashSet> + { + new HashSet() { 1, 2 }, + new HashSet() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + + // Because order isn't guaranteed, roundtrip data to ensure write was accurate. + input = JsonSerializer.Deserialize>>(json); + + if (input.First().Contains(1)) + { + Assert.Equal(new HashSet { 1, 2 }, input.First()); + Assert.Equal(new HashSet { 3, 4 }, input.Last()); + } + else + { + Assert.Equal(new HashSet { 3, 4 }, input.First()); + Assert.Equal(new HashSet { 1, 2 }, input.Last()); + } + } + + [Fact] + public static void WriteISetTOfArray() + { + ISet input = new HashSet + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Contains("[1,2]", json); + Assert.Contains("[3,4]", json); + } + + [Fact] + public static void WriteArrayOfISetT() + { + ISet[] input = new HashSet[2]; + input[0] = new HashSet() { 1, 2 }; + input[1] = new HashSet() { 3, 4 }; + + string json = JsonSerializer.Serialize(input); + + // Because order isn't guaranteed, roundtrip data to ensure write was accurate. + input = JsonSerializer.Deserialize[]>(json); + Assert.Equal(new HashSet { 1, 2 }, input.First()); + Assert.Equal(new HashSet { 3, 4 }, input.Last()); + } + + [Fact] + public static void WritePrimitiveISetT() + { + ISet input = new HashSet { 1, 2 }; + + string json = JsonSerializer.Serialize(input); + Assert.True(json == "[1,2]" || json == "[2,1]"); + } + + [Fact] + public static void WriteStackTOfStackT() + { + Stack> input = new Stack>(new List> + { + new Stack(new List() { 1, 2 }), + new Stack(new List() { 3, 4 }) + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[4,3],[2,1]]", json); + + GenericStackWrapper input2 = new GenericStackWrapper(new List + { + new StringStackWrapper(new List() { "1", "2" }), + new StringStackWrapper(new List() { "3", "4" }) + }); + + json = JsonSerializer.Serialize(input2); + Assert.Equal(@"[[""4"",""3""],[""2"",""1""]]", json); + } + + [Fact] + public static void WriteStackTOfArray() + { + Stack input = new Stack(new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[3,4],[1,2]]", json); + } + + [Fact] + public static void WriteArrayOfStackT() + { + Stack[] input = new Stack[2]; + input[0] = new Stack(new List { 1, 2 }); + input[1] = new Stack(new List { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[2,1],[4,3]]", json); + } + + [Fact] + public static void WritePrimitiveStackT() + { + Stack input = new Stack(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[2,1]", json); + } + + [Fact] + public static void WriteQueueTOfQueueT() + { + Queue> input = new Queue>(new List> + { + new Queue(new List() { 1, 2 }), + new Queue(new List() { 3, 4 }) + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + + GenericQueueWrapper input2 = new GenericQueueWrapper(new List + { + new StringQueueWrapper(new List() { "1", "2" }), + new StringQueueWrapper(new List() { "3", "4" }) + }); + + json = JsonSerializer.Serialize(input2); + Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); + } + + [Fact] + public static void WriteQueueTOfArray() + { + Queue input = new Queue(new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfQueueT() + { + Queue[] input = new Queue[2]; + input[0] = new Queue(new List { 1, 2 }); + input[1] = new Queue(new List { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveQueueT() + { + Queue input = new Queue(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteHashSetTOfHashSetT() + { + HashSet> input = new HashSet>(new List> + { + new HashSet(new List() { 1, 2 }), + new HashSet(new List() { 3, 4 }) + }); + + string json = JsonSerializer.Serialize(input); + + // Because order isn't guaranteed, roundtrip data to ensure write was accurate. + input = JsonSerializer.Deserialize>>(json); + + if (input.First().Contains(1)) + { + Assert.Equal(new HashSet { 1, 2 }, input.First()); + Assert.Equal(new HashSet { 3, 4 }, input.Last()); + } + else + { + Assert.Equal(new HashSet { 3, 4 }, input.First()); + Assert.Equal(new HashSet { 1, 2 }, input.Last()); + } + + GenericHashSetWrapper input2 = new GenericHashSetWrapper(new List + { + new StringHashSetWrapper(new List() { "1", "2" }), + new StringHashSetWrapper(new List() { "3", "4" }) + }); + + json = JsonSerializer.Serialize(input2); + + // Because order isn't guaranteed, roundtrip data to ensure write was accurate. + input2 = JsonSerializer.Deserialize>(json); + + if (input2.First().Contains("1")) + { + Assert.Equal(new StringHashSetWrapper(new List { "1", "2" }), input2.First()); + Assert.Equal(new StringHashSetWrapper(new List { "3", "4" }), input2.Last()); + } + else + { + Assert.Equal(new StringHashSetWrapper(new List { "3", "4" }), input2.First()); + Assert.Equal(new StringHashSetWrapper(new List { "1", "2" }), input2.Last()); + } + } + + [Fact] + public static void WriteHashSetTOfArray() + { + HashSet input = new HashSet(new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }); + + string json = JsonSerializer.Serialize(input); + Assert.Contains("[1,2]", json); + Assert.Contains("[3,4]", json); + } + + [Fact] + public static void WriteArrayOfHashSetT() + { + HashSet[] input = new HashSet[2]; + input[0] = new HashSet(new List { 1, 2 }); + input[1] = new HashSet(new List { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + + // Because order isn't guaranteed, roundtrip data to ensure write was accurate. + input = JsonSerializer.Deserialize[]>(json); + Assert.Equal(new HashSet { 1, 2 }, input.First()); + Assert.Equal(new HashSet { 3, 4 }, input.Last()); + } + + [Fact] + public static void WritePrimitiveHashSetT() + { + HashSet input = new HashSet(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.True(json == "[1,2]" || json == "[2,1]"); + } + + [Fact] + public static void WriteLinkedListTOfLinkedListT() + { + LinkedList> input = new LinkedList>(new List> + { + new LinkedList(new List() { 1, 2 }), + new LinkedList(new List() { 3, 4 }) + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + + GenericLinkedListWrapper input2 = new GenericLinkedListWrapper(new List + { + new StringLinkedListWrapper(new List() { "1", "2" }), + new StringLinkedListWrapper(new List() { "3", "4" }), + }); + + json = JsonSerializer.Serialize(input2); + Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); + } + + [Fact] + public static void WriteLinkedListTOfArray() + { + LinkedList input = new LinkedList(new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfLinkedListT() + { + LinkedList[] input = new LinkedList[2]; + input[0] = new LinkedList(new List { 1, 2 }); + input[1] = new LinkedList(new List { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveLinkedListT() + { + LinkedList input = new LinkedList(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteArrayOfSortedSetT() + { + SortedSet[] input = new SortedSet[2]; + input[0] = new SortedSet(new List { 1, 2 }); + input[1] = new SortedSet(new List { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveSortedSetT() + { + SortedSet input = new SortedSet(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteGenericCollectionWrappers() + { + SimpleTestClassWithGenericCollectionWrappers obj1 = new SimpleTestClassWithGenericCollectionWrappers(); + SimpleTestClassWithStringIEnumerableWrapper obj2 = new SimpleTestClassWithStringIEnumerableWrapper(); + SimpleTestClassWithStringIReadOnlyCollectionWrapper obj3 = new SimpleTestClassWithStringIReadOnlyCollectionWrapper(); + SimpleTestClassWithStringIReadOnlyListWrapper obj4 = new SimpleTestClassWithStringIReadOnlyListWrapper(); + SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper obj5 = new SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper(); + + obj1.Initialize(); + obj2.Initialize(); + obj3.Initialize(); + obj4.Initialize(); + obj5.Initialize(); + + Assert.Equal(SimpleTestClassWithGenericCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); + Assert.Equal(SimpleTestClassWithGenericCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); + + Assert.Equal(SimpleTestClassWithStringIEnumerableWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); + Assert.Equal(SimpleTestClassWithStringIEnumerableWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); + + Assert.Equal(SimpleTestClassWithStringIReadOnlyCollectionWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); + Assert.Equal(SimpleTestClassWithStringIReadOnlyCollectionWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); + + Assert.Equal(SimpleTestClassWithStringIReadOnlyListWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); + Assert.Equal(SimpleTestClassWithStringIReadOnlyListWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); + + Assert.Equal(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); + Assert.Equal(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); + } + + [Fact] + public static void ConvertIEnumerableValueTypesThenSerialize() + { + IEnumerable valueAs = Enumerable.Range(0, 5).Select(x => new ValueA { Value = x }).ToList(); + IEnumerable valueBs = valueAs.Select(x => new ValueB { Value = x.Value }); + + string expectedJson = @"[{""Value"":0},{""Value"":1},{""Value"":2},{""Value"":3},{""Value"":4}]"; + Assert.Equal(expectedJson, JsonSerializer.Serialize>(valueBs)); + } + + public class SimpleClassWithKeyValuePairs + { + public KeyValuePair KvpWStrVal { get; set; } + public KeyValuePair KvpWObjVal { get; set; } + public KeyValuePair KvpWClassVal { get; set; } + public KeyValuePair> KvpWStrKvpVal { get; set; } + public KeyValuePair> KvpWObjKvpVal { get; set; } + public KeyValuePair> KvpWClassKvpVal { get; set; } + } + + public class ValueA + { + public int Value { get; set; } + } + + public class ValueB + { + public int Value { get; set; } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Immutable.Read.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Immutable.Read.cs new file mode 100644 index 00000000000000..6330c1dede6a47 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Immutable.Read.cs @@ -0,0 +1,637 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CollectionTests + { + [Fact] + public static void ReadImmutableArrayOfImmutableArray() + { + ImmutableArray> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (ImmutableArray l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadImmutableArrayOfArray() + { + ImmutableArray result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadArrayOfImmutableArray() + { + ImmutableArray[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (ImmutableArray l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadSimpleImmutableArray() + { + ImmutableArray result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + } + + [Fact] + public static void ReadSimpleClassWithImmutableArray() + { + SimpleTestClassWithImmutableArray obj = JsonSerializer.Deserialize(SimpleTestClassWithImmutableArray.s_json); + obj.Verify(); + } + + [Fact] + public static void ReadIImmutableListTOfIImmutableListT() + { + IImmutableList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IImmutableList l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadIImmutableListTOfArray() + { + IImmutableList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadArrayOfIIImmutableListT() + { + IImmutableList[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IImmutableList l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadPrimitiveIImmutableListT() + { + IImmutableList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + + Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); + Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); + } + + [Fact] + public static void ReadIImmutableStackTOfIImmutableStackT() + { + IImmutableStack> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 4; + + foreach (IImmutableStack l in result) + { + foreach (int i in l) + { + Assert.Equal(expected--, i); + } + } + } + + [Fact] + public static void ReadIImmutableStackTOfArray() + { + IImmutableStack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 3; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + + expected = 1; + } + } + + [Fact] + public static void ReadArrayOfIIImmutableStackT() + { + IImmutableStack[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 2; + + foreach (IImmutableStack l in result) + { + foreach (int i in l) + { + Assert.Equal(expected--, i); + } + + expected = 4; + } + } + + [Fact] + public static void ReadPrimitiveIImmutableStackT() + { + IImmutableStack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 2; + + foreach (int i in result) + { + Assert.Equal(expected--, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + + Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); + Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); + } + + [Fact] + public static void ReadIImmutableQueueTOfIImmutableQueueT() + { + IImmutableQueue> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IImmutableQueue l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadIImmutableQueueTOfArray() + { + IImmutableQueue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadArrayOfIImmutableQueueT() + { + IImmutableQueue[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IImmutableQueue l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadPrimitiveIImmutableQueueT() + { + IImmutableQueue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + + Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); + Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); + } + + [Fact] + public static void ReadIImmutableSetTOfIImmutableSetT() + { + IImmutableSet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + List expected = new List { 1, 2, 3, 4 }; + + foreach (IImmutableSet l in result) + { + foreach (int i in l) + { + expected.Remove(i); + } + } + + Assert.Equal(0, expected.Count); + } + + [Fact] + public static void ReadIImmutableSetTOfArray() + { + IImmutableSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + List expected = new List { 1, 2, 3, 4 }; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + expected.Remove(i); + } + } + + Assert.Equal(0, expected.Count); + } + + [Fact] + public static void ReadArrayOfIImmutableSetT() + { + IImmutableSet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + List expected = new List { 1, 2, 3, 4 }; + + foreach (IImmutableSet l in result) + { + foreach (int i in l) + { + expected.Remove(i); + } + } + + Assert.Equal(0, expected.Count); + } + + [Fact] + public static void ReadPrimitiveIImmutableSetT() + { + IImmutableSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + List expected = new List { 1, 2 }; + + foreach (int i in result) + { + expected.Remove(i); + } + + Assert.Equal(0, expected.Count); + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + + Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); + Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); + } + + [Fact] + public static void ReadImmutableHashSetTOfImmutableHashSetT() + { + ImmutableHashSet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + List expected = new List { 1, 2, 3, 4 }; + + foreach (ImmutableHashSet l in result) + { + foreach (int i in l) + { + expected.Remove(i); + } + } + + Assert.Equal(0, expected.Count); + } + + [Fact] + public static void ReadImmutableHashSetTOfArray() + { + ImmutableHashSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + List expected = new List { 1, 2, 3, 4 }; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + expected.Remove(i); + } + } + + Assert.Equal(0, expected.Count); + } + + [Fact] + public static void ReadArrayOfIImmutableHashSetT() + { + ImmutableHashSet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + List expected = new List { 1, 2, 3, 4 }; + + foreach (ImmutableHashSet l in result) + { + foreach (int i in l) + { + expected.Remove(i); + } + } + + Assert.Equal(0, expected.Count); + } + + [Fact] + public static void ReadPrimitiveImmutableHashSetT() + { + ImmutableHashSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + List expected = new List { 1, 2 }; + + foreach (int i in result) + { + expected.Remove(i); + } + + Assert.Equal(0, expected.Count); + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + } + + [Fact] + public static void ReadImmutableListTOfImmutableListT() + { + ImmutableList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (ImmutableList l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadImmutableListTOfArray() + { + ImmutableList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadArrayOfIImmutableListT() + { + ImmutableList[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (ImmutableList l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadPrimitiveImmutableListT() + { + ImmutableList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + } + + [Fact] + public static void ReadImmutableStackTOfImmutableStackT() + { + ImmutableStack> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 4; + + foreach (ImmutableStack l in result) + { + foreach (int i in l) + { + Assert.Equal(expected--, i); + } + } + } + + [Fact] + public static void ReadImmutableStackTOfArray() + { + ImmutableStack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 3; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + + expected = 1; + } + } + + [Fact] + public static void ReadArrayOfIImmutableStackT() + { + ImmutableStack[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 2; + + foreach (ImmutableStack l in result) + { + foreach (int i in l) + { + Assert.Equal(expected--, i); + } + + expected = 4; + } + } + + [Fact] + public static void ReadPrimitiveImmutableStackT() + { + ImmutableStack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 2; + + foreach (int i in result) + { + Assert.Equal(expected--, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + } + + [Fact] + public static void ReadImmutableQueueTOfImmutableQueueT() + { + ImmutableQueue> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (ImmutableQueue l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadImmutableQueueTOfArray() + { + ImmutableQueue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadArrayOfImmutableQueueT() + { + ImmutableQueue[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (ImmutableQueue l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadPrimitiveImmutableQueueT() + { + ImmutableQueue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + } + + [Fact] + public static void ReadArrayOfIImmutableSortedSetT() + { + ImmutableSortedSet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (ImmutableSortedSet l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public static void ReadPrimitiveImmutableSortedSetT() + { + ImmutableSortedSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + Assert.Equal(0, result.Count()); + } + + [Fact] + public static void ReadSimpleTestClass_ImmutableCollectionWrappers_Throws() + { + Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithIImmutableDictionaryWrapper.s_json)); + Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithImmutableListWrapper.s_json)); + Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithImmutableStackWrapper.s_json)); + Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithImmutableQueueWrapper.s_json)); + Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithImmutableSetWrapper.s_json)); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Immutable.Write.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Immutable.Write.cs new file mode 100644 index 00000000000000..8fa60e5aeb2e2a --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Immutable.Write.cs @@ -0,0 +1,511 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CollectionTests + { + [Fact] + public static void WriteImmutableArrayOfImmutableArray() + { + ImmutableArray> input = ImmutableArray.CreateRange(new List>{ + ImmutableArray.CreateRange(new List() { 1, 2 }), + ImmutableArray.CreateRange(new List() { 3, 4 }) + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteImmutableArrayOfArray() + { + ImmutableArray input = ImmutableArray.CreateRange(new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfImmutableArray() + { + ImmutableArray[] input = new ImmutableArray[2]; + input[0] = ImmutableArray.CreateRange(new List() { 1, 2 }); + input[1] = ImmutableArray.CreateRange(new List() { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteSimpleImmutableArray() + { + ImmutableArray input = ImmutableArray.CreateRange(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteIImmutableListTOfIImmutableListT() + { + IImmutableList> input = ImmutableList.CreateRange(new List>{ + ImmutableList.CreateRange(new List() { 1, 2 }), + ImmutableList.CreateRange(new List() { 3, 4 }) + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteIImmutableListTOfArray() + { + IImmutableList input = ImmutableList.CreateRange(new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteSimpleClassWithImmutableArray() + { + SimpleTestClassWithImmutableArray obj = new SimpleTestClassWithImmutableArray(); + obj.Initialize(); + + Assert.Equal(SimpleTestClassWithImmutableArray.s_json, JsonSerializer.Serialize(obj)); + } + + [Fact] + public static void WriteSimpleClassWithObjectImmutableArray() + { + SimpleTestClassWithObjectImmutableArray obj = new SimpleTestClassWithObjectImmutableArray(); + obj.Initialize(); + + Assert.Equal(SimpleTestClassWithObjectImmutableArray.s_json, JsonSerializer.Serialize(obj)); + } + + [Fact] + public static void WriteArrayOfIImmutableListT() + { + IImmutableList[] input = new IImmutableList[2]; + input[0] = ImmutableList.CreateRange(new List() { 1, 2 }); + input[1] = ImmutableList.CreateRange(new List() { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveIImmutableListT() + { + IImmutableList input = ImmutableList.CreateRange(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + + StringIImmutableListWrapper input2 = new StringIImmutableListWrapper(new List { "1", "2" }); + + json = JsonSerializer.Serialize(input2); + Assert.Equal(@"[""1"",""2""]", json); + } + + [Fact] + public static void WriteIImmutableStackTOfIImmutableStackT() + { + IImmutableStack> input = ImmutableStack.CreateRange(new List>{ + ImmutableStack.CreateRange(new List() { 1, 2 }), + ImmutableStack.CreateRange(new List() { 3, 4 }) + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[4,3],[2,1]]", json); + } + + [Fact] + public static void WriteIImmutableStackTOfArray() + { + IImmutableStack input = ImmutableStack.CreateRange(new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[3,4],[1,2]]", json); + } + + [Fact] + public static void WriteArrayOfIImmutableStackT() + { + IImmutableStack[] input = new IImmutableStack[2]; + input[0] = ImmutableStack.CreateRange(new List() { 1, 2 }); + input[1] = ImmutableStack.CreateRange(new List() { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[2,1],[4,3]]", json); + } + + [Fact] + public static void WritePrimitiveIImmutableStackT() + { + IImmutableStack input = ImmutableStack.CreateRange(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[2,1]", json); + + StringIImmutableStackWrapper input2 = new StringIImmutableStackWrapper(new List { "1", "2" }); + + json = JsonSerializer.Serialize(input2); + Assert.Equal(@"[""2"",""1""]", json); + } + + [Fact] + public static void WriteIImmutableQueueTOfIImmutableQueueT() + { + IImmutableQueue> input = ImmutableQueue.CreateRange(new List>{ + ImmutableQueue.CreateRange(new List() { 1, 2 }), + ImmutableQueue.CreateRange(new List() { 3, 4 }) + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteIImmutableQueueTOfArray() + { + IImmutableQueue input = ImmutableQueue.CreateRange(new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfIImmutableQueueT() + { + IImmutableQueue[] input = new IImmutableQueue[2]; + input[0] = ImmutableQueue.CreateRange(new List() { 1, 2 }); + input[1] = ImmutableQueue.CreateRange(new List() { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveIImmutableQueueT() + { + IImmutableQueue input = ImmutableQueue.CreateRange(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + + StringIImmutableQueueWrapper input2 = new StringIImmutableQueueWrapper(new List { "1", "2" }); + + json = JsonSerializer.Serialize(input2); + Assert.Equal(@"[""1"",""2""]", json); + } + + [Fact] + public static void WriteIImmutableSetTOfIImmutableSetT() + { + IImmutableSet> input = ImmutableHashSet.CreateRange(new List>{ + ImmutableHashSet.CreateRange(new List() { 1, 2 }), + ImmutableHashSet.CreateRange(new List() { 3, 4 }) + }); + + string json = JsonSerializer.Serialize(input); + Assert.Contains("[1,2]", json); + Assert.Contains("[3,4]", json); + } + + [Fact] + public static void WriteIImmutableSetTOfArray() + { + IImmutableSet input = ImmutableHashSet.CreateRange(new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }); + + string json = JsonSerializer.Serialize(input); + Assert.Contains("[1,2]", json); + Assert.Contains("[3,4]", json); + } + + [Fact] + public static void WriteArrayOfIImmutableSetT() + { + IImmutableSet[] input = new IImmutableSet[2]; + input[0] = ImmutableHashSet.CreateRange(new List() { 1, 2 }); + input[1] = ImmutableHashSet.CreateRange(new List() { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveIImmutableSetT() + { + IImmutableSet input = ImmutableHashSet.CreateRange(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + + StringIImmutableSetWrapper input2 = new StringIImmutableSetWrapper(new List { "1", "2" }); + + json = JsonSerializer.Serialize(input2); + Assert.True(json == @"[""1"",""2""]" || json == @"[""2"",""1""]"); + } + + [Fact] + public static void WriteImmutableHashSetTOfImmutableHashSetT() + { + ImmutableHashSet> input = ImmutableHashSet.CreateRange(new List>{ + ImmutableHashSet.CreateRange(new List() { 1, 2 }), + ImmutableHashSet.CreateRange(new List() { 3, 4 }) + }); + + string json = JsonSerializer.Serialize(input); + Assert.Contains("[1,2]", json); + Assert.Contains("[3,4]", json); + } + + [Fact] + public static void WriteImmutableHashSetTOfArray() + { + ImmutableHashSet input = ImmutableHashSet.CreateRange(new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }); + + string json = JsonSerializer.Serialize(input); + Assert.Contains("[1,2]", json); + Assert.Contains("[3,4]", json); + } + + [Fact] + public static void WriteArrayOfImmutableHashSetT() + { + ImmutableHashSet[] input = new ImmutableHashSet[2]; + input[0] = ImmutableHashSet.CreateRange(new List() { 1, 2 }); + input[1] = ImmutableHashSet.CreateRange(new List() { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveImmutableHashSetT() + { + ImmutableHashSet input = ImmutableHashSet.CreateRange(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteImmutableListTOfImmutableListT() + { + ImmutableList> input = ImmutableList.CreateRange(new List>{ + ImmutableList.CreateRange(new List() { 1, 2 }), + ImmutableList.CreateRange(new List() { 3, 4 }) + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteImmutableListTOfArray() + { + ImmutableList input = ImmutableList.CreateRange(new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfImmutableListT() + { + ImmutableList[] input = new ImmutableList[2]; + input[0] = ImmutableList.CreateRange(new List() { 1, 2 }); + input[1] = ImmutableList.CreateRange(new List() { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveImmutableListT() + { + ImmutableList input = ImmutableList.CreateRange(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteImmutableStackTOfImmutableStackT() + { + ImmutableStack> input = ImmutableStack.CreateRange(new List>{ + ImmutableStack.CreateRange(new List() { 1, 2 }), + ImmutableStack.CreateRange(new List() { 3, 4 }) + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[4,3],[2,1]]", json); + } + + [Fact] + public static void WriteImmutableStackTOfArray() + { + ImmutableStack input = ImmutableStack.CreateRange(new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[3,4],[1,2]]", json); + } + + [Fact] + public static void WriteArrayOfImmutableStackT() + { + ImmutableStack[] input = new ImmutableStack[2]; + input[0] = ImmutableStack.CreateRange(new List() { 1, 2 }); + input[1] = ImmutableStack.CreateRange(new List() { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[2,1],[4,3]]", json); + } + + [Fact] + public static void WritePrimitiveImmutableStackT() + { + ImmutableStack input = ImmutableStack.CreateRange(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[2,1]", json); + } + + [Fact] + public static void WriteImmutableQueueTOfImmutableQueueT() + { + ImmutableQueue> input = ImmutableQueue.CreateRange(new List>{ + ImmutableQueue.CreateRange(new List() { 1, 2 }), + ImmutableQueue.CreateRange(new List() { 3, 4 }) + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteImmutableQueueTOfArray() + { + ImmutableQueue input = ImmutableQueue.CreateRange(new List + { + new int[] { 1, 2 }, + new int[] { 3, 4 } + }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfImmutableQueueT() + { + ImmutableQueue[] input = new ImmutableQueue[2]; + input[0] = ImmutableQueue.CreateRange(new List() { 1, 2 }); + input[1] = ImmutableQueue.CreateRange(new List() { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveImmutableQueueT() + { + ImmutableQueue input = ImmutableQueue.CreateRange(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteArrayOfImmutableSortedSetT() + { + ImmutableSortedSet[] input = new ImmutableSortedSet[2]; + input[0] = ImmutableSortedSet.CreateRange(new List() { 1, 2 }); + input[1] = ImmutableSortedSet.CreateRange(new List() { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveImmutableSortedSetT() + { + ImmutableSortedSet input = ImmutableSortedSet.CreateRange(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteImmutableCollectionWrappers() + { + SimpleTestClassWithIImmutableDictionaryWrapper obj1 = new SimpleTestClassWithIImmutableDictionaryWrapper(); + SimpleTestClassWithImmutableListWrapper obj2 = new SimpleTestClassWithImmutableListWrapper(); + SimpleTestClassWithImmutableStackWrapper obj3 = new SimpleTestClassWithImmutableStackWrapper(); + SimpleTestClassWithImmutableQueueWrapper obj4 = new SimpleTestClassWithImmutableQueueWrapper(); + SimpleTestClassWithImmutableSetWrapper obj5 = new SimpleTestClassWithImmutableSetWrapper(); + + obj1.Initialize(); + obj2.Initialize(); + obj3.Initialize(); + obj4.Initialize(); + obj5.Initialize(); + + Assert.Equal(SimpleTestClassWithIImmutableDictionaryWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); + Assert.Equal(SimpleTestClassWithIImmutableDictionaryWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); + + Assert.Equal(SimpleTestClassWithImmutableListWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); + Assert.Equal(SimpleTestClassWithImmutableListWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); + + Assert.Equal(SimpleTestClassWithImmutableStackWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); + Assert.Equal(SimpleTestClassWithImmutableStackWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); + + Assert.Equal(SimpleTestClassWithImmutableQueueWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); + Assert.Equal(SimpleTestClassWithImmutableQueueWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); + + Assert.Equal(SimpleTestClassWithImmutableSetWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); + Assert.Equal(SimpleTestClassWithImmutableSetWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.KeyValuePair.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.KeyValuePair.cs new file mode 100644 index 00000000000000..868167086cfa9c --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.KeyValuePair.cs @@ -0,0 +1,438 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Text.Encodings.Web; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CollectionTests + { + [Fact] + public static void ReadSimpleKeyValuePairFail() + { + // Invalid form: no Value + Assert.Throws(() => JsonSerializer.Deserialize>(@"{""Key"": 123}")); + + // Invalid form: extra property + Assert.Throws(() => JsonSerializer.Deserialize>(@"{""Key"": ""Key"", ""Value"": 123, ""Value2"": 456}")); + + // Invalid form: does not contain both Key and Value properties + Assert.Throws(() => JsonSerializer.Deserialize>(@"{""Key"": ""Key"", ""Val"": 123")); + } + + [Fact] + public static void ReadListOfKeyValuePair() + { + List> input = JsonSerializer.Deserialize>>(@"[{""Key"": ""123"", ""Value"": 123},{""Key"": ""456"", ""Value"": 456}]"); + + Assert.Equal(2, input.Count); + Assert.Equal("123", input[0].Key); + Assert.Equal(123, input[0].Value); + Assert.Equal("456", input[1].Key); + Assert.Equal(456, input[1].Value); + } + + [Fact] + public static void ReadKeyValuePairOfList() + { + KeyValuePair> input = JsonSerializer.Deserialize>>(@"{""Key"":""Key"", ""Value"":[1, 2, 3]}"); + + Assert.Equal("Key", input.Key); + Assert.Equal(3, input.Value.Count); + Assert.Equal(1, input.Value[0]); + Assert.Equal(2, input.Value[1]); + Assert.Equal(3, input.Value[2]); + } + + [Theory] + [InlineData(@"{""Key"":""Key"", ""Value"":{""Key"":1, ""Value"":2}}")] + [InlineData(@"{""Key"":""Key"", ""Value"":{""Value"":2, ""Key"":1}}")] + [InlineData(@"{""Value"":{""Key"":1, ""Value"":2}, ""Key"":""Key""}")] + [InlineData(@"{""Value"":{""Value"":2, ""Key"":1}, ""Key"":""Key""}")] + public static void ReadKeyValuePairOfKeyValuePair(string json) + { + KeyValuePair> input = JsonSerializer.Deserialize>>(json); + + Assert.Equal("Key", input.Key); + Assert.Equal(1, input.Value.Key); + Assert.Equal(2, input.Value.Value); + } + + [Fact] + public static void ReadKeyValuePairWithNullValues() + { + { + KeyValuePair kvp = JsonSerializer.Deserialize>(@"{""Key"":""key"",""Value"":null}"); + Assert.Equal("key", kvp.Key); + Assert.Null(kvp.Value); + } + + { + KeyValuePair kvp = JsonSerializer.Deserialize>(@"{""Key"":""key"",""Value"":null}"); + Assert.Equal("key", kvp.Key); + Assert.Null(kvp.Value); + } + + { + KeyValuePair kvp = JsonSerializer.Deserialize>(@"{""Key"":""key"",""Value"":null}"); + Assert.Equal("key", kvp.Key); + Assert.Null(kvp.Value); + } + + { + KeyValuePair> kvp = JsonSerializer.Deserialize>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}"); + Assert.Equal("key", kvp.Key); + Assert.Equal("key", kvp.Value.Key); + Assert.Null(kvp.Value.Value); + } + + { + KeyValuePair> kvp = JsonSerializer.Deserialize>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}"); + Assert.Equal("key", kvp.Key); + Assert.Equal("key", kvp.Value.Key); + Assert.Null(kvp.Value.Value); + } + + { + KeyValuePair> kvp = JsonSerializer.Deserialize>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}"); + Assert.Equal("key", kvp.Key); + Assert.Equal("key", kvp.Value.Key); + Assert.Null(kvp.Value.Value); + } + } + + [Fact] + public static void ReadClassWithNullKeyValuePairValues() + { + string json = + @"{" + + @"""KvpWStrVal"":{" + + @"""Key"":""key""," + + @"""Value"":null" + + @"}," + + @"""KvpWObjVal"":{" + + @"""Key"":""key""," + + @"""Value"":null" + + @"}," + + @"""KvpWClassVal"":{" + + @"""Key"":""key""," + + @"""Value"":null" + + @"}," + + @"""KvpWStrKvpVal"":{" + + @"""Key"":""key""," + + @"""Value"":{" + + @"""Key"":""key""," + + @"""Value"":null" + + @"}" + + @"}," + + @"""KvpWObjKvpVal"":{" + + @"""Key"":""key""," + + @"""Value"":{" + + @"""Key"":""key""," + + @"""Value"":null" + + @"}" + + @"}," + + @"""KvpWClassKvpVal"":{" + + @"""Key"":""key""," + + @"""Value"":{" + + @"""Key"":""key""," + + @"""Value"":null" + + @"}" + + @"}" + + @"}"; + SimpleClassWithKeyValuePairs obj = JsonSerializer.Deserialize(json); + + Assert.Equal("key", obj.KvpWStrVal.Key); + Assert.Equal("key", obj.KvpWObjVal.Key); + Assert.Equal("key", obj.KvpWClassVal.Key); + Assert.Equal("key", obj.KvpWStrKvpVal.Key); + Assert.Equal("key", obj.KvpWObjKvpVal.Key); + Assert.Equal("key", obj.KvpWClassKvpVal.Key); + Assert.Equal("key", obj.KvpWStrKvpVal.Value.Key); + Assert.Equal("key", obj.KvpWObjKvpVal.Value.Key); + Assert.Equal("key", obj.KvpWClassKvpVal.Value.Key); + + Assert.Null(obj.KvpWStrVal.Value); + Assert.Null(obj.KvpWObjVal.Value); + Assert.Null(obj.KvpWClassVal.Value); + Assert.Null(obj.KvpWStrKvpVal.Value.Value); + Assert.Null(obj.KvpWObjKvpVal.Value.Value); + Assert.Null(obj.KvpWClassKvpVal.Value.Value); + } + + [Fact] + public static void Kvp_NullKeyIsFine() + { + KeyValuePair kvp = JsonSerializer.Deserialize>(@"{""Key"":null,""Value"":null}"); + Assert.Null(kvp.Key); + Assert.Null(kvp.Value); + } + + [Fact] + public static void WritePrimitiveKeyValuePair() + { + KeyValuePair input = new KeyValuePair("Key", 123); + + string json = JsonSerializer.Serialize(input); + Assert.Equal(@"{""Key"":""Key"",""Value"":123}", json); + } + + [Fact] + public static void WriteListOfKeyValuePair() + { + List> input = new List> + { + new KeyValuePair("123", 123), + new KeyValuePair("456", 456) + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal(@"[{""Key"":""123"",""Value"":123},{""Key"":""456"",""Value"":456}]", json); + } + + [Fact] + public static void WriteKeyValuePairOfList() + { + KeyValuePair> input = new KeyValuePair>("Key", new List { 1, 2, 3 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal(@"{""Key"":""Key"",""Value"":[1,2,3]}", json); + } + + [Fact] + public static void WriteKeyValuePairOfKeyValuePair() + { + KeyValuePair> input = new KeyValuePair>( + "Key", new KeyValuePair("Key", 1)); + + string json = JsonSerializer.Serialize(input); + Assert.Equal(@"{""Key"":""Key"",""Value"":{""Key"":""Key"",""Value"":1}}", json); + } + + [Fact] + public static void WriteKeyValuePairWithNullValues() + { + { + KeyValuePair kvp = new KeyValuePair("key", null); + Assert.Equal(@"{""Key"":""key"",""Value"":null}", JsonSerializer.Serialize(kvp)); + } + + { + KeyValuePair kvp = new KeyValuePair("key", null); + Assert.Equal(@"{""Key"":""key"",""Value"":null}", JsonSerializer.Serialize(kvp)); + } + + { + KeyValuePair kvp = new KeyValuePair("key", null); + Assert.Equal(@"{""Key"":""key"",""Value"":null}", JsonSerializer.Serialize(kvp)); + } + + { + KeyValuePair> kvp = new KeyValuePair>("key", new KeyValuePair("key", null)); + Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", JsonSerializer.Serialize(kvp)); + } + + { + KeyValuePair> kvp = new KeyValuePair>("key", new KeyValuePair("key", null)); + Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", JsonSerializer.Serialize(kvp)); + } + + { + KeyValuePair> kvp = new KeyValuePair>("key", new KeyValuePair("key", null)); + Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", JsonSerializer.Serialize(kvp)); + } + } + + [Fact] + public static void WriteClassWithNullKeyValuePairValues_NullWrittenAsEmptyObject() + { + var value = new SimpleClassWithKeyValuePairs() + { + KvpWStrVal = new KeyValuePair("key", null), + KvpWObjVal = new KeyValuePair("key", null), + KvpWClassVal = new KeyValuePair("key", null), + KvpWStrKvpVal = new KeyValuePair>("key", new KeyValuePair("key", null)), + KvpWObjKvpVal = new KeyValuePair>("key", new KeyValuePair("key", null)), + KvpWClassKvpVal = new KeyValuePair>("key", new KeyValuePair("key", null)), + }; + + string result = JsonSerializer.Serialize(value); + + // Roundtrip to ensure serialize was correct. + value = JsonSerializer.Deserialize(result); + Assert.Equal("key", value.KvpWStrVal.Key); + Assert.Equal("key", value.KvpWObjVal.Key); + Assert.Equal("key", value.KvpWClassVal.Key); + Assert.Equal("key", value.KvpWStrKvpVal.Key); + Assert.Equal("key", value.KvpWObjKvpVal.Key); + Assert.Equal("key", value.KvpWClassKvpVal.Key); + Assert.Equal("key", value.KvpWStrKvpVal.Value.Key); + Assert.Equal("key", value.KvpWObjKvpVal.Value.Key); + Assert.Equal("key", value.KvpWClassKvpVal.Value.Key); + + Assert.Null(value.KvpWStrVal.Value); + Assert.Null(value.KvpWObjVal.Value); + Assert.Null(value.KvpWClassVal.Value); + Assert.Null(value.KvpWStrKvpVal.Value.Value); + Assert.Null(value.KvpWObjKvpVal.Value.Value); + Assert.Null(value.KvpWClassKvpVal.Value.Value); + } + + [Fact] + public static void HonorNamingPolicy() + { + var kvp = new KeyValuePair("Hello, World!", 1); + + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = new LeadingUnderscorePolicy() + }; + + string serialized = JsonSerializer.Serialize(kvp, options); + // We know serializer writes the key first. + Assert.Equal(@"{""_Key"":""Hello, World!"",""_Value"":1}", serialized); + + kvp = JsonSerializer.Deserialize>(serialized, options); + Assert.Equal("Hello, World!", kvp.Key); + Assert.Equal(1, kvp.Value); + } + + [Fact] + public static void HonorNamingPolicy_CaseInsensitive() + { + const string json = @"{""key"":""Hello, World!"",""value"":1}"; + + // Baseline - with case-sensitive matching, the payload doesn't have mapping properties. + Assert.Throws(() => JsonSerializer.Deserialize>(json)); + + // Test - with case-insensitivity on, we have property matches. + var options = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true + }; + + KeyValuePair kvp = JsonSerializer.Deserialize>(json, options); + Assert.Equal("Hello, World!", kvp.Key); + Assert.Equal(1, kvp.Value); + } + + [Fact] + public static void HonorCLRProperties() + { + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = new LeadingUnderscorePolicy() // Key -> _Key, Value -> _Value + }; + + // Although policy won't produce this JSON string, the serializer parses the properties + // as "Key" and "Value" are special cased to accomodate content serialized with previous + // versions of the serializer (.NET Core 3.x/System.Text.Json 4.7.x). + string json = @"{""Key"":""Hello, World!"",""Value"":1}"; + KeyValuePair kvp = JsonSerializer.Deserialize>(json, options); + Assert.Equal("Hello, World!", kvp.Key); + Assert.Equal(1, kvp.Value); + + // "Key" and "Value" matching is case sensitive. + json = @"{""key"":""Hello, World!"",""value"":1}"; + Assert.Throws(() => JsonSerializer.Deserialize>(json, options)); + + // "Key" and "Value" matching is case sensitive, even when case sensitivity is on. + // Case sensitivity only applies to the result of converting the CLR property names + // (Key -> _Key, Value -> _Value) with the naming policy. + options = new JsonSerializerOptions + { + PropertyNamingPolicy = new LeadingUnderscorePolicy(), + PropertyNameCaseInsensitive = true + }; + + Assert.Throws(() => JsonSerializer.Deserialize>(json, options)); + } + + private class LeadingUnderscorePolicy : JsonNamingPolicy + { + public override string ConvertName(string name) => "_" + name; + } + + [Fact] + public static void HonorCustomEncoder() + { + var kvp = new KeyValuePair(1, 2); + + JsonNamingPolicy namingPolicy = new TrailingAngleBracketPolicy(); + + // Baseline - properties serialized with default encoder if none specified. + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = namingPolicy, + }; + + Assert.Equal(@"{""Key\u003C"":1,""Value\u003C"":2}", JsonSerializer.Serialize(kvp, options)); + + // Test - serializer honors custom encoder. + options = new JsonSerializerOptions + { + PropertyNamingPolicy = namingPolicy, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + + Assert.Equal(@"{""Key<"":1,""Value<"":2}", JsonSerializer.Serialize(kvp, options)); + } + + private class TrailingAngleBracketPolicy : JsonNamingPolicy + { + public override string ConvertName(string name) => name + "<"; + } + + [Theory] + [InlineData(typeof(KeyNameNullPolicy))] + [InlineData(typeof(ValueNameNullPolicy))] + public static void InvalidPropertyNameFail(Type policyType) + { + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = (JsonNamingPolicy)Activator.CreateInstance(policyType) + }; + + InvalidOperationException ex = Assert.Throws(() => JsonSerializer.Deserialize>("", options)); + string exAsStr = ex.ToString(); + Assert.Contains(policyType.ToString(), exAsStr); + + Assert.Throws(() => JsonSerializer.Serialize(new KeyValuePair("", ""), options)); + } + + private class KeyNameNullPolicy : JsonNamingPolicy + { + public override string ConvertName(string name) => name == "Key" ? null : name; + } + + private class ValueNameNullPolicy : JsonNamingPolicy + { + public override string ConvertName(string name) => name == "Value" ? null : name; + } + + [Theory] + [InlineData("")] + [InlineData("1")] + [InlineData("[")] + [InlineData("}")] + [InlineData("{")] + [InlineData("{}")] + [InlineData("{Key")] + [InlineData("{0")] + [InlineData(@"{""Random"":")] + [InlineData(@"{""Value"":1}")] + [InlineData(@"{""Value"":1,2")] + [InlineData(@"{""Value"":1,""Random"":")] + [InlineData(@"{""Key"":1,""Key"":1}")] + [InlineData(@"{""Key"":1,""Key"":2}")] + [InlineData(@"{""Value"":1,""Value"":1}")] + [InlineData(@"{""Value"":1,""Value"":2}")] + public static void InvalidJsonFail(string json) + { + Assert.Throws(() => JsonSerializer.Deserialize>(json)); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.NonGeneric.Read.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.NonGeneric.Read.cs new file mode 100644 index 00000000000000..3455a3e38f32b7 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.NonGeneric.Read.cs @@ -0,0 +1,503 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections; +using System.Collections.Generic; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CollectionTests + { + [Fact] + public static void ReadGenericIEnumerableOfIEnumerable() + { + IEnumerable result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IEnumerable ie in result) + { + foreach (JsonElement i in ie) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + + // No way to populate this collection. + Assert.Throws(() => JsonSerializer.Deserialize>(@"[[1,2],[3,4]]")); + } + + [Fact] + public static void ReadIEnumerableOfArray() + { + IEnumerable result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (JsonElement arr in result) + { + foreach (JsonElement i in arr.EnumerateArray()) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + } + + [Fact] + public static void ReadArrayOfIEnumerable() + { + IEnumerable[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IEnumerable arr in result) + { + foreach (JsonElement i in arr) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + } + + [Fact] + public static void ReadPrimitiveIEnumerable() + { + IEnumerable result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (JsonElement i in result) + { + Assert.Equal(expected++, i.GetInt32()); + } + + result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); + + int count = 0; + IEnumerator e = result.GetEnumerator(); + while (e.MoveNext()) + { + count++; + } + Assert.Equal(0, count); + } + + [Fact] + public static void ReadGenericIListOfIList() + { + IList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IList list in result) + { + foreach (JsonElement i in list) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + + GenericIListWrapper result2 = JsonSerializer.Deserialize>(@"[[1,2],[3,4]]"); + expected = 1; + + foreach (WrapperForIList list in result2) + { + foreach (JsonElement i in list) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + } + + [Fact] + public static void ReadIListOfArray() + { + IList result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (JsonElement arr in result) + { + foreach (JsonElement i in arr.EnumerateArray()) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + } + + [Fact] + public static void ReadArrayOfIList() + { + IList[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (IList arr in result) + { + foreach (JsonElement i in arr) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + } + + [Fact] + public static void ReadPrimitiveIList() + { + IList result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (JsonElement i in result) + { + Assert.Equal(expected++, i.GetInt32()); + } + + result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); + + int count = 0; + IEnumerator e = result.GetEnumerator(); + while (e.MoveNext()) + { + count++; + } + Assert.Equal(0, count); + + WrapperForIList result2 = JsonSerializer.Deserialize(@"[1,2]"); + expected = 1; + + foreach (JsonElement i in result2) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + + [Fact] + public static void ReadGenericICollectionOfICollection() + { + ICollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (ICollection ie in result) + { + foreach (JsonElement i in ie) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + + // No way to populate this collection. + Assert.Throws(() => JsonSerializer.Deserialize>(@"[[1,2],[3,4]]")); + } + + [Fact] + public static void ReadICollectionOfArray() + { + ICollection result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (JsonElement arr in result) + { + foreach (JsonElement i in arr.EnumerateArray()) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + } + + [Fact] + public static void ReadArrayOfICollection() + { + ICollection[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (ICollection arr in result) + { + foreach (JsonElement i in arr) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + } + + [Fact] + public static void ReadPrimitiveICollection() + { + ICollection result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (JsonElement i in result) + { + Assert.Equal(expected++, i.GetInt32()); + } + + result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); + + int count = 0; + IEnumerator e = result.GetEnumerator(); + while (e.MoveNext()) + { + count++; + } + Assert.Equal(0, count); + } + + [Fact] + public static void ReadGenericStackOfStack() + { + Stack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 4; + + foreach (Stack stack in result) + { + foreach (JsonElement i in stack) + { + Assert.Equal(expected--, i.GetInt32()); + } + } + } + + [Fact] + public static void ReadStackOfArray() + { + Stack result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 3; + + foreach (JsonElement arr in result) + { + foreach (JsonElement i in arr.EnumerateArray()) + { + Assert.Equal(expected++, i.GetInt32()); + } + expected = 1; + } + } + + [Fact] + public static void ReadArrayOfStack() + { + Stack[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 2; + + foreach (Stack arr in result) + { + foreach (JsonElement i in arr) + { + Assert.Equal(expected--, i.GetInt32()); + } + expected = 4; + } + } + + [Fact] + public static void ReadPrimitiveStack() + { + Stack result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 2; + + foreach (JsonElement i in result) + { + Assert.Equal(expected--, i.GetInt32()); + } + + result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); + + int count = 0; + IEnumerator e = result.GetEnumerator(); + while (e.MoveNext()) + { + count++; + } + Assert.Equal(0, count); + + StackWrapper wrapper = JsonSerializer.Deserialize(@"[1,2]"); + expected = 2; + + foreach (JsonElement i in wrapper) + { + Assert.Equal(expected--, i.GetInt32()); + } + } + + [Fact] + public static void ReadGenericQueueOfQueue() + { + Queue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (Queue ie in result) + { + foreach (JsonElement i in ie) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + } + + [Fact] + public static void ReadQueueOfArray() + { + Queue result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (JsonElement arr in result) + { + foreach (JsonElement i in arr.EnumerateArray()) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + } + + [Fact] + public static void ReadArrayOfQueue() + { + Queue[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (Queue arr in result) + { + foreach (JsonElement i in arr) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + } + + [Fact] + public static void ReadPrimitiveQueue() + { + Queue result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (JsonElement i in result) + { + Assert.Equal(expected++, i.GetInt32()); + } + + result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); + + int count = 0; + IEnumerator e = result.GetEnumerator(); + while (e.MoveNext()) + { + count++; + } + Assert.Equal(0, count); + + QueueWrapper wrapper = JsonSerializer.Deserialize(@"[1,2]"); + expected = 1; + + foreach (JsonElement i in wrapper) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + + [Fact] + public static void ReadArrayListOfArray() + { + ArrayList result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (JsonElement arr in result) + { + foreach (JsonElement i in arr.EnumerateArray()) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + + ArrayListWrapper result2 = JsonSerializer.Deserialize(@"[[1,2],[3,4]]"); + expected = 1; + + foreach (JsonElement arr in result2) + { + foreach (JsonElement i in arr.EnumerateArray()) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + } + + [Fact] + public static void ReadArrayOfArrayList() + { + ArrayList[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + int expected = 1; + + foreach (ArrayList arr in result) + { + foreach (JsonElement i in arr) + { + Assert.Equal(expected++, i.GetInt32()); + } + } + } + + [Fact] + public static void ReadPrimitiveArrayList() + { + ArrayList result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); + int expected = 1; + + foreach (JsonElement i in result) + { + Assert.Equal(expected++, i.GetInt32()); + } + + result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); + + int count = 0; + IEnumerator e = result.GetEnumerator(); + while (e.MoveNext()) + { + count++; + } + Assert.Equal(0, count); + } + + [Fact] + public static void ReadSimpleTestClass_NonGenericCollectionWrappers() + { + SimpleTestClassWithNonGenericCollectionWrappers obj = JsonSerializer.Deserialize(SimpleTestClassWithNonGenericCollectionWrappers.s_json); + obj.Verify(); + } + + [Theory] + [MemberData(nameof(ReadSimpleTestClass_NonGenericWrappers_NoAddMethod))] + public static void ReadSimpleTestClass_NonGenericWrappers_NoAddMethod_Throws(Type type, string json, Type exceptionMessageType) + { + NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); + Assert.Contains(exceptionMessageType.ToString(), ex.Message); + } + + public static IEnumerable ReadSimpleTestClass_NonGenericWrappers_NoAddMethod + { + get + { + yield return new object[] + { + typeof(SimpleTestClassWithIEnumerableWrapper), + SimpleTestClassWithIEnumerableWrapper.s_json, + typeof(WrapperForIEnumerable) + }; + yield return new object[] + { + typeof(SimpleTestClassWithICollectionWrapper), + SimpleTestClassWithICollectionWrapper.s_json, + typeof(WrapperForICollection) + }; + } + } + + [Theory] + [InlineData(typeof(WrapperForIEnumerablePrivateConstructor), @"[""1""]")] + [InlineData(typeof(WrapperForIEnumerableInternalConstructor), @"[""1""]")] + [InlineData(typeof(WrapperForICollectionPrivateConstructor), @"[""1""]")] + [InlineData(typeof(WrapperForICollectionInternalConstructor), @"[""1""]")] + [InlineData(typeof(WrapperForIListPrivateConstructor), @"[""1""]")] + [InlineData(typeof(WrapperForIListInternalConstructor), @"[""1""]")] + [InlineData(typeof(WrapperForIDictionaryPrivateConstructor), @"{""Key"":""Value""}")] + [InlineData(typeof(WrapperForIDictionaryInternalConstructor), @"{""Key"":""Value""}")] + public static void Read_NonGeneric_NoPublicConstructor_Throws(Type type, string json) + { + NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); + Assert.Contains(type.ToString(), ex.Message); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.NonGeneric.Write.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.NonGeneric.Write.cs new file mode 100644 index 00000000000000..b21ae5d177fb39 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.NonGeneric.Write.cs @@ -0,0 +1,349 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections; +using System.Collections.Generic; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CollectionTests + { + [Fact] + public static void WriteIEnumerableOfIEnumerable() + { + IEnumerable input = new List> + { + new List() { 1, 2 }, + new List() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + + WrapperForIEnumerable input2 = new WrapperForIEnumerable(new List + { + new List() { 1, 2 }, + new List() { 3, 4 }, + }); + + json = JsonSerializer.Serialize(input2); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteGenericIEnumerableOfIEnumerable() + { + IEnumerable input = new List + { + new List() { 1, 2 }, + new List() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfIEnumerable() + { + IEnumerable[] input = new IEnumerable[2]; + input[0] = new List() { 1, 2 }; + input[1] = new List() { 3, 4 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveIEnumerable() + { + IEnumerable input = new List { 1, 2 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteIListOfIList() + { + IList input = new List + { + new List() { 1, 2 }, + new List() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + + WrapperForIList input2 = new WrapperForIList + { + new List() { 1, 2 }, + new List() { 3, 4 }, + }; + + json = JsonSerializer.Serialize(input2); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteIListGenericOfIList() + { + IList input = new List + { + new List() { 1, 2 }, + new List() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfIList() + { + IList[] input = new IList[2]; + input[0] = new List() { 1, 2 }; + input[1] = new List() { 3, 4 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveIList() + { + IList input = new List { 1, 2 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteICollectionOfICollection() + { + ICollection input = new List + { + new List() { 1, 2 }, + new List() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteGenericICollectionOfICollection() + { + ICollection input = new List + { + new List() { 1, 2 }, + new List() { 3, 4 } + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + + GenericICollectionWrapper input2 = new GenericICollectionWrapper + { + new WrapperForICollection(new List { 1, 2 }), + new WrapperForICollection(new List { 3, 4 }), + }; + + json = JsonSerializer.Serialize(input2); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfICollection() + { + ICollection[] input = new List[2]; + input[0] = new List() { 1, 2 }; + input[1] = new List() { 3, 4 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveICollection() + { + ICollection input = new List { 1, 2 }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteStackOfStack() + { + Stack input = new Stack(); + input.Push(new Stack(new List() { 1, 2 })); + input.Push(new Stack(new List() { 3, 4 })); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[4,3],[2,1]]", json); + } + + [Fact] + public static void WriteGenericStackOfStack() + { + Stack input = new Stack(); + input.Push(new Stack(new List() { 1, 2 })); + input.Push(new Stack(new List() { 3, 4 })); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[4,3],[2,1]]", json); + + GenericStackWrapper input2 = new GenericStackWrapper(); + input2.Push(new StackWrapper(new List { 1, 2 })); + input2.Push(new StackWrapper(new List { 3, 4 })); + + json = JsonSerializer.Serialize(input2); + Assert.Equal("[[4,3],[2,1]]", json); + } + + [Fact] + public static void WriteArrayOfStack() + { + Stack[] input = new Stack[2]; + input[0] = new Stack(new List() { 1, 2 }); + input[1] = new Stack(new List() { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[2,1],[4,3]]", json); + } + + [Fact] + public static void WritePrimitiveStack() + { + Stack input = new Stack( new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[2,1]", json); + } + + [Fact] + public static void WriteQueueOfQueue() + { + Queue input = new Queue(); + input.Enqueue(new Queue(new List() { 1, 2 })); + input.Enqueue(new Queue(new List() { 3, 4 })); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteGenericQueueOfQueue() + { + Queue input = new Queue(); + input.Enqueue(new Queue(new List() { 1, 2 })); + input.Enqueue(new Queue(new List() { 3, 4 })); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + + GenericQueueWrapper input2 = new GenericQueueWrapper(); + input2.Enqueue(new QueueWrapper(new List() { 1, 2 })); + input2.Enqueue(new QueueWrapper(new List() { 3, 4 })); + + json = JsonSerializer.Serialize(input2); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfQueue() + { + Queue[] input = new Queue[2]; + input[0] = new Queue(new List() { 1, 2 }); + input[1] = new Queue(new List() { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveQueue() + { + Queue input = new Queue(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteArrayListOfArrayList() + { + ArrayList input = new ArrayList + { + new ArrayList(new List() { 1, 2 }), + new ArrayList(new List() { 3, 4 }) + }; + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + + ArrayListWrapper input2 = new ArrayListWrapper(new List + { + new ArrayListWrapper(new List() { 1, 2 }), + new ArrayListWrapper(new List() { 3, 4 }) + }); + + json = JsonSerializer.Serialize(input2); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WriteArrayOfArrayList() + { + ArrayList[] input = new ArrayList[2]; + input[0] = new ArrayList(new List() { 1, 2 }); + input[1] = new ArrayList(new List() { 3, 4 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[[1,2],[3,4]]", json); + } + + [Fact] + public static void WritePrimitiveArrayList() + { + ArrayList input = new ArrayList(new List { 1, 2 }); + + string json = JsonSerializer.Serialize(input); + Assert.Equal("[1,2]", json); + } + + [Fact] + public static void WriteNonGenericCollectionWrappers() + { + SimpleTestClassWithNonGenericCollectionWrappers obj1 = new SimpleTestClassWithNonGenericCollectionWrappers(); + SimpleTestClassWithIEnumerableWrapper obj2 = new SimpleTestClassWithIEnumerableWrapper(); + SimpleTestClassWithICollectionWrapper obj3 = new SimpleTestClassWithICollectionWrapper(); + SimpleTestClassWithStackWrapper obj4 = new SimpleTestClassWithStackWrapper(); + SimpleTestClassWithQueueWrapper obj5 = new SimpleTestClassWithQueueWrapper(); + + obj1.Initialize(); + obj2.Initialize(); + obj3.Initialize(); + obj4.Initialize(); + obj5.Initialize(); + + Assert.Equal(SimpleTestClassWithNonGenericCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); + Assert.Equal(SimpleTestClassWithNonGenericCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); + + Assert.Equal(SimpleTestClassWithIEnumerableWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); + Assert.Equal(SimpleTestClassWithIEnumerableWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); + + Assert.Equal(SimpleTestClassWithICollectionWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); + Assert.Equal(SimpleTestClassWithICollectionWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); + + Assert.Equal(SimpleTestClassWithStackWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); + Assert.Equal(SimpleTestClassWithStackWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); + + Assert.Equal(SimpleTestClassWithQueueWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); + Assert.Equal(SimpleTestClassWithQueueWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.ObjectModel.Read.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.ObjectModel.Read.cs new file mode 100644 index 00000000000000..b37c12d1724ffa --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.ObjectModel.Read.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.ObjectModel; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CollectionTests + { + [Fact] + public static void Read_ObjectModelCollection() + { + Collection c = JsonSerializer.Deserialize>("[true,false]"); + Assert.Equal(2, c.Count); + Assert.True(c[0]); + Assert.False(c[1]); + + // Regression test for https://github.com/dotnet/runtime/issues/30686. + ObservableCollection oc = JsonSerializer.Deserialize>("[true,false]"); + Assert.Equal(2, oc.Count); + Assert.True(oc[0]); + Assert.False(oc[1]); + + SimpleKeyedCollection kc = JsonSerializer.Deserialize("[true]"); + Assert.Equal(1, kc.Count); + Assert.True(kc[0]); + } + + [Fact] + public static void Read_ObjectModelCollection_Throws() + { + // No default constructor. + Assert.Throws(() => JsonSerializer.Deserialize>("[true,false]")); + // No default constructor. + Assert.Throws(() => JsonSerializer.Deserialize>("[true,false]")); + // No default constructor. + Assert.Throws(() => JsonSerializer.Deserialize>(@"{""true"":false}")); + + // Abstract types can't be instantiated. This means there's no default constructor, so the type is not supported for deserialization. + Assert.Throws(() => JsonSerializer.Deserialize>("[true]")); + } + + public class SimpleKeyedCollection : KeyedCollection + { + protected override string GetKeyForItem(bool item) + { + return item.ToString(); + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.ObjectModel.Write.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.ObjectModel.Write.cs new file mode 100644 index 00000000000000..e8916e4744e070 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.ObjectModel.Write.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CollectionTests + { + [Fact] + public static void Write_ObjectModelCollection() + { + Collection c = new Collection() { true, false }; + Assert.Equal("[true,false]", JsonSerializer.Serialize(c)); + + ObservableCollection oc = new ObservableCollection() { true, false }; + Assert.Equal("[true,false]", JsonSerializer.Serialize(oc)); + + SimpleKeyedCollection kc = new SimpleKeyedCollection() { true, false }; + Assert.Equal("[true,false]", JsonSerializer.Serialize(kc)); + Assert.Equal("[true,false]", JsonSerializer.Serialize>(kc)); + + ReadOnlyCollection roc = new ReadOnlyCollection(new List { true, false }); + Assert.Equal("[true,false]", JsonSerializer.Serialize(roc)); + + ReadOnlyObservableCollection rooc = new ReadOnlyObservableCollection(oc); + Assert.Equal("[true,false]", JsonSerializer.Serialize(rooc)); + + ReadOnlyDictionary rod = new ReadOnlyDictionary(new Dictionary { ["true"] = false }); + Assert.Equal(@"{""true"":false}", JsonSerializer.Serialize(rod)); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Specialized.Read.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Specialized.Read.cs new file mode 100644 index 00000000000000..28625c909848dc --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Specialized.Read.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Specialized; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CollectionTests + { + [Fact] + public static void Read_SpecializedCollection() + { + BitVector32 bv32 = JsonSerializer.Deserialize(@"{""Data"":4}"); + // Data property is skipped because it doesn't have a setter. + Assert.Equal(0, bv32.Data); + + HybridDictionary hd = JsonSerializer.Deserialize(@"{""key"":""value""}"); + Assert.Equal(1, hd.Count); + Assert.Equal("value", ((JsonElement)hd["key"]).GetString()); + + IOrderedDictionary iod = JsonSerializer.Deserialize(@"{""key"":""value""}"); + Assert.Equal(1, iod.Count); + Assert.Equal("value", ((JsonElement)iod["key"]).GetString()); + + ListDictionary ld = JsonSerializer.Deserialize(@"{""key"":""value""}"); + Assert.Equal(1, ld.Count); + Assert.Equal("value", ((JsonElement)ld["key"]).GetString()); + } + + [Fact] + public static void Read_SpecializedCollection_Throws() + { + // Add method for this collection only accepts strings, even though it only implements IList which usually + // indicates that the element type is typeof(object). + Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"", ""2""]")); + + // Not supported. Not IList, and we don't detect the add method for this collection. + Assert.Throws(() => JsonSerializer.Deserialize(@"[{""Key"": ""key"",""Value"":""value""}]")); + + // Int key is not allowed. + Assert.Throws(() => JsonSerializer.Deserialize(@"{1:""value""}")); + + // Runtime type in this case is IOrderedDictionary (we don't replace with concrete type), which we can't instantiate. + Assert.Throws(() => JsonSerializer.Deserialize(@"{""first"":""John"",""second"":""Jane"",""third"":""Jet""}")); + + // Not supported. Not IList, and we don't detect the add method for this collection. + Assert.Throws(() => JsonSerializer.Deserialize(@"[""NameValueCollection""]")); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Specialized.Write.cs b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Specialized.Write.cs new file mode 100644 index 00000000000000..74240e7541dbc0 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Specialized.Write.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. +// See the LICENSE file in the project root for more information. + +using System.Collections.Specialized; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CollectionTests + { + [Fact] + public static void Write_SpecializedCollection() + { + Assert.Equal(@"{""Data"":4}", JsonSerializer.Serialize(new BitVector32(4))); + Assert.Equal(@"{""Data"":4}", JsonSerializer.Serialize(new BitVector32(4))); + + Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new HybridDictionary { ["key"] = "value" })); + Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new HybridDictionary { ["key"] = "value" })); + + Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new OrderedDictionary { ["key"] = "value" })); + Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new OrderedDictionary { ["key"] = "value" })); + Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new OrderedDictionary { ["key"] = "value" })); + + Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new ListDictionary { ["key"] = "value" })); + Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new ListDictionary { ["key"] = "value" })); + + Assert.Equal(@"[""1"",""2""]", JsonSerializer.Serialize(new StringCollection { "1", "2" })); + Assert.Equal(@"[""1"",""2""]", JsonSerializer.Serialize(new StringCollection { "1", "2" })); + + Assert.Equal(@"[{""Key"":""key"",""Value"":""value""}]", JsonSerializer.Serialize(new StringDictionary { ["key"] = "value" })); + Assert.Equal(@"[{""Key"":""key"",""Value"":""value""}]", JsonSerializer.Serialize(new StringDictionary { ["key"] = "value" })); + + // Element type returned by .GetEnumerator for this type is string, specifically the key. + Assert.Equal(@"[""key""]", JsonSerializer.Serialize(new NameValueCollection { ["key"] = "value" })); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.AttributePresence.cs b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests/ConstructorTests.AttributePresence.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.AttributePresence.cs rename to src/libraries/System.Text.Json/tests/Serialization/ConstructorTests/ConstructorTests.AttributePresence.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Cache.cs b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests/ConstructorTests.Cache.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Cache.cs rename to src/libraries/System.Text.Json/tests/Serialization/ConstructorTests/ConstructorTests.Cache.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Exceptions.cs b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests/ConstructorTests.Exceptions.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Exceptions.cs rename to src/libraries/System.Text.Json/tests/Serialization/ConstructorTests/ConstructorTests.Exceptions.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.ParameterMatching.cs b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests/ConstructorTests.ParameterMatching.cs similarity index 96% rename from src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.ParameterMatching.cs rename to src/libraries/System.Text.Json/tests/Serialization/ConstructorTests/ConstructorTests.ParameterMatching.cs index f6979cf22c9674..a69c9ad6b9a585 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.ParameterMatching.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests/ConstructorTests.ParameterMatching.cs @@ -339,19 +339,35 @@ public void PropertiesNotSet_WhenJSON_MapsToConstructorParameters() [Fact] public void IgnoreNullValues_DontSetNull_ToConstructorArguments_ThatCantBeNull() { - // Throw JsonException when null applied to types that can't be null. + // Throw JsonException when null applied to types that can't be null. Behavior should align with properties deserialized with setters. + Assert.Throws(() => Serializer.Deserialize(@"{""Point3DStruct"":null,""Int"":null,""ImmutableArray"":null}")); + Assert.Throws(() => Serializer.Deserialize(@"{""Point3DStruct"":null,""Int"":null,""ImmutableArray"":null}")); + Assert.Throws(() => Serializer.Deserialize(@"{""Point3DStruct"":null}")); + Assert.Throws(() => Serializer.Deserialize(@"{""Point3DStruct"":null}")); + Assert.Throws(() => Serializer.Deserialize(@"{""Int"":null}")); + Assert.Throws(() => Serializer.Deserialize(@"{""Int"":null}")); + Assert.Throws(() => Serializer.Deserialize(@"{""ImmutableArray"":null}")); + Assert.Throws(() => Serializer.Deserialize(@"{""ImmutableArray"":null}")); // Throw even when IgnoreNullValues is true for symmetry with property deserialization, // until https://github.com/dotnet/runtime/issues/30795 is addressed. + var options = new JsonSerializerOptions { IgnoreNullValues = true }; Assert.Throws(() => Serializer.Deserialize(@"{""Point3DStruct"":null,""Int"":null,""ImmutableArray"":null}", options)); + Assert.Throws(() => Serializer.Deserialize(@"{""Point3DStruct"":null,""Int"":null,""ImmutableArray"":null}", options)); + Assert.Throws(() => Serializer.Deserialize(@"{""Point3DStruct"":null}", options)); + Assert.Throws(() => Serializer.Deserialize(@"{""Point3DStruct"":null,""Int"":null,""ImmutableArray"":null}", options)); + Assert.Throws(() => Serializer.Deserialize(@"{""Int"":null}", options)); + Assert.Throws(() => Serializer.Deserialize(@"{""Point3DStruct"":null,""Int"":null,""ImmutableArray"":null}", options)); + Assert.Throws(() => Serializer.Deserialize(@"{""ImmutableArray"":null}", options)); + Assert.Throws(() => Serializer.Deserialize(@"{""Point3DStruct"":null,""Int"":null,""ImmutableArray"":null}", options)); } [Fact] diff --git a/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Stream.cs b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests/ConstructorTests.Stream.cs similarity index 99% rename from src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Stream.cs rename to src/libraries/System.Text.Json/tests/Serialization/ConstructorTests/ConstructorTests.Stream.cs index 6872cd50ebb346..d2d6380d6e73d5 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests.Stream.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/ConstructorTests/ConstructorTests.Stream.cs @@ -52,6 +52,8 @@ async Task RunTest(byte[] testData) tasks[11] = Task.Run(async () => await RunTest(Point_With_Array.s_data)); tasks[12] = Task.Run(async () => await RunTest(Point_With_Dictionary.s_data)); tasks[13] = Task.Run(async () => await RunTest(Point_With_Object.s_data)); + + Task.WaitAll(tasks); } [Fact] diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.NullableTypes.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.NullableTypes.cs deleted file mode 100644 index ffc7c4569263d9..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.NullableTypes.cs +++ /dev/null @@ -1,129 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class CustomConverterTests - { - private class JsonTestStructConverter : JsonConverter - { - public override TestStruct Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new TestStruct - { - InnerValue = reader.GetInt32() - }; - } - - public override void Write(Utf8JsonWriter writer, TestStruct value, JsonSerializerOptions options) - { - writer.WriteNumberValue(value.InnerValue); - } - } - - private class JsonTestStructThrowingConverter : JsonConverter - { - public override TestStruct Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - throw new NotSupportedException(); - } - - public override void Write(Utf8JsonWriter writer, TestStruct value, JsonSerializerOptions options) - { - throw new NotSupportedException(); - } - } - - private struct TestStruct - { - public int InnerValue { get; set; } - } - - private class TestStructClass - { - [JsonConverter(typeof(JsonTestStructConverter))] - public TestStruct? MyStruct { get; set; } - } - - private class TestStructInvalidClass - { - // Note: JsonTestStructConverter does not convert int, this is for negative testing. - [JsonConverter(typeof(JsonTestStructConverter))] - public int? MyInt { get; set; } - } - - [Fact] - public static void NullableCustomValueTypeUsingOptions() - { - var options = new JsonSerializerOptions(); - options.Converters.Add(new JsonTestStructConverter()); - - { - TestStruct myStruct = JsonSerializer.Deserialize("1", options); - Assert.Equal(1, myStruct.InnerValue); - } - - { - TestStruct? myStruct = JsonSerializer.Deserialize("null", options); - Assert.False(myStruct.HasValue); - } - - { - TestStruct? myStruct = JsonSerializer.Deserialize("1", options); - Assert.Equal(1, myStruct.Value.InnerValue); - } - } - - [Fact] - public static void NullableCustomValueTypeUsingAttributes() - { - { - TestStructClass myStructClass = JsonSerializer.Deserialize(@"{""MyStruct"":null}"); - Assert.False(myStructClass.MyStruct.HasValue); - } - - { - TestStructClass myStructClass = JsonSerializer.Deserialize(@"{""MyStruct"":1}"); - Assert.True(myStructClass.MyStruct.HasValue); - Assert.Equal(1, myStructClass.MyStruct.Value.InnerValue); - } - } - - [Fact] - public static void NullableCustomValueTypeChoosesAttributeOverOptions() - { - var options = new JsonSerializerOptions(); - options.Converters.Add(new JsonTestStructThrowingConverter()); - - // Chooses JsonTestStructThrowingConverter on options, which will throw. - Assert.Throws(() => JsonSerializer.Deserialize("1", options)); - - // Chooses JsonTestStructConverter on attribute, which will not throw. - TestStructClass myStructClass = JsonSerializer.Deserialize(@"{""MyStruct"":null}", options); - Assert.False(myStructClass.MyStruct.HasValue); - } - - [Fact] - public static void NullableCustomValueTypeNegativeTest() - { - Assert.Throws(() => JsonSerializer.Deserialize(@"{""MyInt"":null}")); - Assert.Throws(() => JsonSerializer.Deserialize(@"{""MyInt"":1}")); - } - - [Fact] - public static void NullableStandardValueTypeTest() - { - { - int? myInt = JsonSerializer.Deserialize("null"); - Assert.False(myInt.HasValue); - } - - { - int? myInt = JsonSerializer.Deserialize("1"); - Assert.Equal(1, myInt.Value); - } - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Array.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Array.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Array.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Array.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Attribute.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Attribute.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Attribute.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Attribute.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.BadConverters.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.BadConverters.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.BadConverters.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.BadConverters.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Callback.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Callback.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Callback.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Callback.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.ContravariantDictionaryConverter.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.ContravariantDictionaryConverter.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.ContravariantDictionaryConverter.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.ContravariantDictionaryConverter.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.DerivedTypes.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.DerivedTypes.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.DerivedTypes.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.DerivedTypes.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.DictionaryEnumConverter.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.DictionaryEnumConverter.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.DictionaryEnumConverter.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.DictionaryEnumConverter.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.DictionaryGuidConverter.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.DictionaryGuidConverter.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.DictionaryGuidConverter.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.DictionaryGuidConverter.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.DictionaryInt32StringConverter.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.DictionaryInt32StringConverter.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.DictionaryInt32StringConverter.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.DictionaryInt32StringConverter.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.DictionaryInt32StringKeyValueConverter.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.DictionaryInt32StringKeyValueConverter.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.DictionaryInt32StringKeyValueConverter.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.DictionaryInt32StringKeyValueConverter.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.DictionaryKeyValueConverter.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.DictionaryKeyValueConverter.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.DictionaryKeyValueConverter.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.DictionaryKeyValueConverter.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Enum.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Enum.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Enum.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Enum.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Exceptions.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Exceptions.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Exceptions.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Exceptions.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.HandleNull.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.HandleNull.cs new file mode 100644 index 00000000000000..fd30dab7475215 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.HandleNull.cs @@ -0,0 +1,546 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Buffers; +using System.Collections.Generic; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CustomConverterTests + { + [Fact] + public static void ValueTypeConverter_NoOverride() + { + // Baseline + Assert.Throws(() => JsonSerializer.Deserialize("null")); + + // Per null handling default value for value types (true), converter handles null. + var options = new JsonSerializerOptions(); + options.Converters.Add(new Int32NullConverter_SpecialCaseNull()); + + Assert.Equal(-1, JsonSerializer.Deserialize("null", options)); + } + + private class Int32NullConverter_SpecialCaseNull : JsonConverter + { + public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return -1; + } + + throw new JsonException(); + } + + public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + } + + [Fact] + public static void ValueTypeConverter_OptOut() + { + // Per null handling opt-out, serializer handles null. + var options = new JsonSerializerOptions(); + options.Converters.Add(new Int32NullConverter_OptOut()); + + // Serializer throws JsonException if null is assigned to value that can't be null. + Assert.Throws(() => JsonSerializer.Deserialize("null", options)); + Assert.Throws(() => JsonSerializer.Deserialize(@"{""MyInt"":null}", options)); + Assert.Throws(() => JsonSerializer.Deserialize>("[null]", options)); + Assert.Throws(() => JsonSerializer.Deserialize>(@"{""MyInt"":null}", options)); + } + + private class Int32NullConverter_OptOut : Int32NullConverter_SpecialCaseNull + { + public override bool HandleNull => false; + } + + private class ClassWithInt + { + public int MyInt { get; set; } + } + + [Fact] + public static void ValueTypeConverter_NullOptIn() + { + // Per null handling opt-in, converter handles null. + var options = new JsonSerializerOptions(); + options.Converters.Add(new Int32NullConverter_NullOptIn()); + + Assert.Equal(-1, JsonSerializer.Deserialize("null", options)); + } + + private class Int32NullConverter_NullOptIn : Int32NullConverter_SpecialCaseNull + { + public override bool HandleNull => true; + } + + [Fact] + public static void ComplexValueTypeConverter_NoOverride() + { + // Baseline + Assert.Throws(() => JsonSerializer.Deserialize("null")); + + var options = new JsonSerializerOptions(); + options.Converters.Add(new PointStructConverter_SpecialCaseNull()); + + // Per null handling default value for value types (true), converter handles null. + var obj = JsonSerializer.Deserialize("null", options); + Assert.Equal(-1, obj.X); + Assert.Equal(-1, obj.Y); + } + + private class PointStructConverter_SpecialCaseNull : JsonConverter + { + public override Point_2D_Struct Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return new Point_2D_Struct(-1, -1); + } + + throw new JsonException(); + } + + public override void Write(Utf8JsonWriter writer, Point_2D_Struct value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + } + + [Fact] + public static void ComplexValueTypeConverter_OptOut() + { + // Per null handling opt-out, serializer handles null. + var options = new JsonSerializerOptions(); + options.Converters.Add(new PointStructConverter_OptOut()); + + // Serializer throws JsonException if null is assigned to value that can't be null. + Assert.Throws(() => JsonSerializer.Deserialize("null", options)); + Assert.Throws(() => JsonSerializer.Deserialize(@"{""MyPoint"":null}", options)); + Assert.Throws(() => JsonSerializer.Deserialize(@"{""MyPoint"":null}", options)); + Assert.Throws(() => JsonSerializer.Deserialize>("[null]", options)); + Assert.Throws(() => JsonSerializer.Deserialize>(@"{""MyPoint"":null}", options)); + } + + private class PointStructConverter_OptOut : PointStructConverter_SpecialCaseNull + { + public override bool HandleNull => false; + } + + private class ClassWithPoint + { + public Point_2D_Struct MyPoint { get; set; } + } + + private class ImmutableClassWithPoint + { + public Point_2D_Struct MyPoint { get; } + + public ImmutableClassWithPoint(Point_2D_Struct myPoint) => MyPoint = myPoint; + } + + [Fact] + public static void ComplexValueTypeConverter_NullOptIn() + { + // Baseline + Assert.Throws(() => JsonSerializer.Deserialize("null")); + + // Per null handling opt-in, converter handles null. + var options = new JsonSerializerOptions(); + options.Converters.Add(new PointStructConverter_NullOptIn()); + + var obj = JsonSerializer.Deserialize("null", options); + Assert.Equal(-1, obj.X); + Assert.Equal(-1, obj.Y); + } + + private class PointStructConverter_NullOptIn : PointStructConverter_SpecialCaseNull + { + public override bool HandleNull => true; + } + + [Fact] + public static void NullableValueTypeConverter_NoOverride() + { + // Baseline + int? val = JsonSerializer.Deserialize("null"); + Assert.Null(val); + Assert.Equal("null", JsonSerializer.Serialize(val)); + + // Per null handling default value for value types (true), converter handles null. + var options = new JsonSerializerOptions(); + options.Converters.Add(new NullableInt32NullConverter_SpecialCaseNull()); + + val = JsonSerializer.Deserialize("null", options); + Assert.Equal(-1, val); + + val = null; + Assert.Equal("-1", JsonSerializer.Serialize(val, options)); + } + + private class NullableInt32NullConverter_SpecialCaseNull : JsonConverter + { + public override int? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return -1; + } + + throw new JsonException(); + } + + public override void Write(Utf8JsonWriter writer, int? value, JsonSerializerOptions options) + { + if (!value.HasValue) + { + writer.WriteNumberValue(-1); + return; + } + + throw new NotSupportedException(); + } + } + + [Fact] + public static void NullableValueTypeConverter_OptOut() + { + // Baseline + int? val = JsonSerializer.Deserialize("null"); + Assert.Null(val); + Assert.Equal("null", JsonSerializer.Serialize(val)); + + // Per null handling opt-out, serializer handles null. + var options = new JsonSerializerOptions(); + options.Converters.Add(new NullableInt32NullConverter_NullOptOut()); + + val = JsonSerializer.Deserialize("null", options); + Assert.Null(val); + Assert.Equal("null", JsonSerializer.Serialize(val, options)); + } + + private class NullableInt32NullConverter_NullOptOut : NullableInt32NullConverter_SpecialCaseNull + { + public override bool HandleNull => false; + } + + [Fact] + public static void ReferenceTypeConverter_NoOverride() + { + // Baseline + Uri val = JsonSerializer.Deserialize("null"); + Assert.Null(val); + Assert.Equal("null", JsonSerializer.Serialize(val)); + + // Per null handling default value for reference types (false), serializer handles null. + var options = new JsonSerializerOptions(); + options.Converters.Add(new UriNullConverter_SpecialCaseNull()); + + // Serializer sets default value. + val = JsonSerializer.Deserialize("null", options); + Assert.Null(val); + + // Serializer serializes null. + Assert.Equal("null", JsonSerializer.Serialize(val, options)); + } + + private class UriNullConverter_SpecialCaseNull : JsonConverter + { + public override Uri Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return new Uri("https://default"); + } + + throw new JsonException(); + } + + public override void Write(Utf8JsonWriter writer, Uri value, JsonSerializerOptions options) + { + if (value == null) + { + writer.WriteStringValue("https://default"); + return; + } + + throw new NotSupportedException(); + } + } + + [Fact] + public static void ReferenceTypeConverter_OptOut() + { + // Per null handling opt-out, serializer handles null. + var options = new JsonSerializerOptions(); + options.Converters.Add(new UriNullConverter_OptOut()); + + Uri val = JsonSerializer.Deserialize("null", options); + Assert.Null(val); + Assert.Equal("null", JsonSerializer.Serialize(val, options)); + } + + private class UriNullConverter_OptOut : UriNullConverter_SpecialCaseNull + { + public override bool HandleNull => false; + } + + [Fact] + public static void ReferenceTypeConverter_NullOptIn() + { + // Per null handling opt-in, converter handles null. + var options = new JsonSerializerOptions(); + options.Converters.Add(new UriNullConverter_NullOptIn()); + + Uri val = JsonSerializer.Deserialize("null", options); + Assert.Equal(new Uri("https://default"), val); + + val = null; + Assert.Equal(@"""https://default""", JsonSerializer.Serialize(val, options)); + } + + private class UriNullConverter_NullOptIn : UriNullConverter_SpecialCaseNull + { + public override bool HandleNull => true; + } + + [Fact] + public static void ComplexReferenceTypeConverter_NoOverride() + { + // Baseline + Point_2D obj = JsonSerializer.Deserialize("null"); + Assert.Null(obj); + Assert.Equal("null", JsonSerializer.Serialize(obj)); + + // Per null handling default value for reference types (false), serializer handles null. + var options = new JsonSerializerOptions(); + options.Converters.Add(new PointClassConverter_SpecialCaseNull()); + + obj = JsonSerializer.Deserialize("null", options); + Assert.Null(obj); + Assert.Equal("null", JsonSerializer.Serialize(obj)); + } + + private class PointClassConverter_SpecialCaseNull : JsonConverter + { + public override Point_2D Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return new Point_2D(-1, -1); + } + + throw new JsonException(); + } + + public override void Write(Utf8JsonWriter writer, Point_2D value, JsonSerializerOptions options) + { + if (value == null) + { + writer.WriteStartObject(); + writer.WriteNumber("X", -1); + writer.WriteNumber("Y", -1); + writer.WriteEndObject(); + return; + } + + throw new JsonException(); + } + } + + [Fact] + public static void ComplexReferenceTypeConverter_NullOptIn() + { + // Per null handling opt-in, converter handles null. + var options = new JsonSerializerOptions(); + options.Converters.Add(new PointClassConverter_NullOptIn()); + + Point_2D obj = JsonSerializer.Deserialize("null", options); + Assert.Equal(-1, obj.X); + Assert.Equal(-1, obj.Y); + + obj = null; + JsonTestHelper.AssertJsonEqual(@"{""X"":-1,""Y"":-1}", JsonSerializer.Serialize(obj, options)); + } + + private class PointClassConverter_NullOptIn : PointClassConverter_SpecialCaseNull + { + public override bool HandleNull => true; + } + + [Fact] + public static void ConverterNotCalled_IgnoreNullValues() + { + var options = new JsonSerializerOptions(); + options.Converters.Add(new UriNullConverter_NullOptIn()); + + // Converter is called - JsonIgnoreCondition.WhenWritingDefault does not apply to deserialization. + ClassWithIgnoredUri obj = JsonSerializer.Deserialize(@"{""MyUri"":null}", options); + Assert.Equal(new Uri("https://default"), obj.MyUri); + + obj.MyUri = null; + // Converter is not called - value is ignored on serialization. + Assert.Equal("{}", JsonSerializer.Serialize(obj, options)); + } + + private class ClassWithIgnoredUri + { + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Uri MyUri { get; set; } = new Uri("https://microsoft.com"); + } + + [Fact] + public static void ConverterWritesBadAmount() + { + var options = new JsonSerializerOptions(); + options.Converters.Add(new BadUriConverter()); + options.Converters.Add(new BadObjectConverter()); + + // Using serializer overload in Release mode uses a writer with SkipValidation = true. + var writerOptions = new JsonWriterOptions { SkipValidation = false }; + using (Utf8JsonWriter writer = new Utf8JsonWriter(new ArrayBufferWriter(), writerOptions)) + { + Assert.Throws(() => JsonSerializer.Serialize(writer, new ClassWithUri(), options)); + } + + using (Utf8JsonWriter writer = new Utf8JsonWriter(new ArrayBufferWriter(), writerOptions)) + { + Assert.Throws(() => JsonSerializer.Serialize(new StructWithObject(), options)); + } + } + + private class BadUriConverter : UriNullConverter_NullOptIn + { + public override void Write(Utf8JsonWriter writer, Uri value, JsonSerializerOptions options) { } + } + + private class BadObjectConverter : JsonConverter + { + public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + + public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) + { + writer.WriteStartObject(); + writer.WritePropertyName("hello"); + writer.WriteNullValue(); + } + + public override bool HandleNull => true; + } + + private class ClassWithUri + { + public Uri MyUri { get; set; } + } + + + private class StructWithObject + { + public object MyObj { get; set; } + } + + [Fact] + public static void ObjectAsRootValue() + { + var options = new JsonSerializerOptions(); + options.Converters.Add(new ObjectConverter()); + + object obj = null; + Assert.Equal(@"""NullObject""", JsonSerializer.Serialize(obj, options)); + Assert.Equal("NullObject", JsonSerializer.Deserialize("null", options)); + + options = new JsonSerializerOptions(); + options.Converters.Add(new BadObjectConverter()); + Assert.Throws(() => JsonSerializer.Serialize(obj, options)); + } + + [Fact] + public static void ObjectAsCollectionElement() + { + var options = new JsonSerializerOptions(); + options.Converters.Add(new ObjectConverter()); + + List list = new List { null }; + Assert.Equal(@"[""NullObject""]", JsonSerializer.Serialize(list, options)); + + list = JsonSerializer.Deserialize>("[null]", options); + Assert.Equal("NullObject", list[0]); + + options = new JsonSerializerOptions(); + options.Converters.Add(new BadObjectConverter()); + + list[0] = null; + Assert.Throws(() => JsonSerializer.Serialize(list, options)); + } + + public class ObjectConverter : JsonConverter + { + public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return "NullObject"; + } + + throw new NotSupportedException(); + } + + public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) + { + if (value == null) + { + writer.WriteStringValue("NullObject"); + return; + } + + throw new NotSupportedException(); + } + + public override bool HandleNull => true; + } + + [Fact] + public static void SetterCalledWhenConverterReturnsNull() + { + var options = new JsonSerializerOptions + { + IgnoreNullValues = true, + Converters = { new UriToNullConverter() } + }; + + // Baseline - null values ignored, converter is not called. + string json = @"{""MyUri"":null}"; + + ClassWithInitializedUri obj = JsonSerializer.Deserialize(json, options); + Assert.Equal(new Uri("https://microsoft.com"), obj.MyUri); + + // Test - setter is called if payload is not null and converter returns null. + json = @"{""MyUri"":""https://default""}"; + obj = JsonSerializer.Deserialize(json, options); + Assert.Null(obj.MyUri); + } + + private class ClassWithInitializedUri + { + public Uri MyUri { get; set; } = new Uri("https://microsoft.com"); + } + + public class UriToNullConverter : JsonConverter + { + public override Uri Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => null; + + public override void Write(Utf8JsonWriter writer, Uri value, JsonSerializerOptions options) => throw new NotImplementedException(); + + public override bool HandleNull => true; + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Int32.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Int32.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Int32.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Int32.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.List.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.List.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.List.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.List.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.NullValueType.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.NullValueType.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.NullValueType.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.NullValueType.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.NullableTypes.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.NullableTypes.cs new file mode 100644 index 00000000000000..f8f0691ba516f6 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.NullableTypes.cs @@ -0,0 +1,282 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System.Diagnostics; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class CustomConverterTests + { + private class JsonTestStructConverter : JsonConverter + { + public override TestStruct Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return new TestStruct + { + InnerValue = reader.GetInt32() + }; + } + + public override void Write(Utf8JsonWriter writer, TestStruct value, JsonSerializerOptions options) + { + writer.WriteNumberValue(value.InnerValue); + } + } + + private class JsonTestStructThrowingConverter : JsonConverter + { + public override TestStruct Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new NotSupportedException(); + } + + public override void Write(Utf8JsonWriter writer, TestStruct value, JsonSerializerOptions options) + { + throw new NotSupportedException(); + } + } + + private struct TestStruct + { + public int InnerValue { get; set; } + } + + private class TestStructClass + { + [JsonConverter(typeof(JsonTestStructConverter))] + public TestStruct? MyStruct { get; set; } + } + + private class TestStructInvalidClass + { + // Note: JsonTestStructConverter does not convert int, this is for negative testing. + [JsonConverter(typeof(JsonTestStructConverter))] + public int? MyInt { get; set; } + } + + [Fact] + public static void NullableCustomValueTypeUsingOptions() + { + var options = new JsonSerializerOptions(); + options.Converters.Add(new JsonTestStructConverter()); + + { + TestStruct myStruct = JsonSerializer.Deserialize("1", options); + Assert.Equal(1, myStruct.InnerValue); + } + + { + TestStruct? myStruct = JsonSerializer.Deserialize("null", options); + Assert.False(myStruct.HasValue); + } + + { + TestStruct? myStruct = JsonSerializer.Deserialize("1", options); + Assert.Equal(1, myStruct.Value.InnerValue); + } + } + + [Fact] + public static void NullableCustomValueTypeUsingAttributes() + { + { + TestStructClass myStructClass = JsonSerializer.Deserialize(@"{""MyStruct"":null}"); + Assert.False(myStructClass.MyStruct.HasValue); + } + + { + TestStructClass myStructClass = JsonSerializer.Deserialize(@"{""MyStruct"":1}"); + Assert.True(myStructClass.MyStruct.HasValue); + Assert.Equal(1, myStructClass.MyStruct.Value.InnerValue); + } + } + + [Fact] + public static void NullableCustomValueTypeChoosesAttributeOverOptions() + { + var options = new JsonSerializerOptions(); + options.Converters.Add(new JsonTestStructThrowingConverter()); + + // Chooses JsonTestStructThrowingConverter on options, which will throw. + Assert.Throws(() => JsonSerializer.Deserialize("1", options)); + + // Chooses JsonTestStructConverter on attribute, which will not throw. + TestStructClass myStructClass = JsonSerializer.Deserialize(@"{""MyStruct"":null}", options); + Assert.False(myStructClass.MyStruct.HasValue); + } + + [Fact] + public static void NullableCustomValueTypeNegativeTest() + { + Assert.Throws(() => JsonSerializer.Deserialize(@"{""MyInt"":null}")); + Assert.Throws(() => JsonSerializer.Deserialize(@"{""MyInt"":1}")); + } + + [Fact] + public static void NullableStandardValueTypeTest() + { + { + int? myInt = JsonSerializer.Deserialize("null"); + Assert.False(myInt.HasValue); + } + + { + int? myInt = JsonSerializer.Deserialize("1"); + Assert.Equal(1, myInt.Value); + } + } + + /// + /// Used to verify a converter for Nullable is called for null values. Converters are passed + /// null when {T} is a value type including when {T}=Nullable{int?}. + /// + private class NullIntTo42Converter : JsonConverter + { + public override int? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + // Use literal value to differ from the default converter's behavior. + return 42; + } + + Debug.Assert(false); + throw new Exception("not expected"); + } + + public override void Write(Utf8JsonWriter writer, int? value, JsonSerializerOptions options) + { + if (value == null) + { + // Use literal value to differ from the default converter's behavior. + writer.WriteNumberValue(42); + } + else + { + Debug.Assert(false); + throw new Exception("not expected"); + } + } + } + + [Fact] + public static void NullableConverterIsPassedNull() + { + var options = new JsonSerializerOptions(); + options.Converters.Add(new NullIntTo42Converter()); + + { + int? myInt = JsonSerializer.Deserialize("null", options); + Assert.True(myInt.HasValue); + Assert.Equal(42, myInt.Value); + } + + { + string json = JsonSerializer.Serialize(null, options); + Assert.Equal("42", json); + } + + { + int?[] ints = JsonSerializer.Deserialize("[null, null]", options); + Assert.Equal(2, ints.Length); + Assert.Equal(42, ints[0]); + Assert.Equal(42, ints[1]); + } + + { + string json = JsonSerializer.Serialize(new int?[] { null, null }, options); + Assert.Equal("[42,42]", json); + } + } + + private class PocoSingleInt + { + public int MyInt; + } + + /// + /// Used to verify a converter for a reference type is not called for null values. + /// + private class PocoFailOnNullConverter : JsonConverter + { + public override PocoSingleInt Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + Debug.Assert(false); + throw new Exception(); + } + + reader.Skip(); + + return new PocoSingleInt() + { + // Use literal value to differ from the default converter's behavior. + MyInt = 42 + }; + } + + public override void Write(Utf8JsonWriter writer, PocoSingleInt value, JsonSerializerOptions options) + { + if (value == null) + { + Debug.Assert(false); + throw new Exception(); + } + + writer.WriteStartObject(); + + // Use literal value to differ from the default converter's behavior. + writer.WriteNumber("MyInt", 42); + + writer.WriteEndObject(); + } + } + + [Fact] + public static void ReferenceTypeConverterDoesntGetPassedNull() + { + var options = new JsonSerializerOptions(); + options.Converters.Add(new PocoFailOnNullConverter()); + + { + PocoSingleInt poco = JsonSerializer.Deserialize("null", options); + Assert.Null(poco); + + poco = JsonSerializer.Deserialize("{}", options); + Assert.Equal(42, poco.MyInt); + } + + { + PocoSingleInt[] pocos = JsonSerializer.Deserialize("[null, null]", options); + Assert.Equal(2, pocos.Length); + Assert.Null(pocos[0]); + Assert.Null(pocos[1]); + + pocos = JsonSerializer.Deserialize("[{}, {}]", options); + Assert.Equal(2, pocos.Length); + Assert.Equal(42, pocos[0].MyInt); + Assert.Equal(42, pocos[1].MyInt); + } + + { + string json = JsonSerializer.Serialize(null, options); + Assert.Equal(@"null", json); + + PocoSingleInt poco = new PocoSingleInt(); + json = JsonSerializer.Serialize(poco, options); + Assert.Equal(@"{""MyInt"":42}", json); + } + + { + string json = JsonSerializer.Serialize(new PocoSingleInt[] { null, null }, options); + Assert.Equal(@"[null,null]", json); + + PocoSingleInt poco = new PocoSingleInt(); + json = JsonSerializer.Serialize(new PocoSingleInt[] { poco, poco }, options); + Assert.Equal(@"[{""MyInt"":42},{""MyInt"":42}]", json); + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Object.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Object.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Object.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Object.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Point.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Point.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Point.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Point.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Polymorphic.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Polymorphic.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Polymorphic.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Polymorphic.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.ReadAhead.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.ReadAhead.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.ReadAhead.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.ReadAhead.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.cs rename to src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs b/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs deleted file mode 100644 index 0613262e6325da..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/DictionaryTests.cs +++ /dev/null @@ -1,2214 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Collections.Specialized; -using System.Reflection; -using System.Text.Encodings.Web; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class DictionaryTests - { - [Fact] - public static void DictionaryOfString() - { - const string JsonString = @"{""Hello"":""World"",""Hello2"":""World2""}"; - const string ReorderedJsonString = @"{""Hello2"":""World2"",""Hello"":""World""}"; - - { - IDictionary obj = JsonSerializer.Deserialize(JsonString); - Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); - Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - { - Dictionary obj = JsonSerializer.Deserialize>(JsonString); - Assert.Equal("World", obj["Hello"]); - Assert.Equal("World2", obj["Hello2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - { - SortedDictionary obj = JsonSerializer.Deserialize>(JsonString); - Assert.Equal("World", obj["Hello"]); - Assert.Equal("World2", obj["Hello2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - { - IDictionary obj = JsonSerializer.Deserialize>(JsonString); - Assert.Equal("World", obj["Hello"]); - Assert.Equal("World2", obj["Hello2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - { - IReadOnlyDictionary obj = JsonSerializer.Deserialize>(JsonString); - Assert.Equal("World", obj["Hello"]); - Assert.Equal("World2", obj["Hello2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - { - ImmutableDictionary obj = JsonSerializer.Deserialize>(JsonString); - Assert.Equal("World", obj["Hello"]); - Assert.Equal("World2", obj["Hello2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.True(JsonString == json || ReorderedJsonString == json); - - json = JsonSerializer.Serialize(obj); - Assert.True(JsonString == json || ReorderedJsonString == json); - } - - { - IImmutableDictionary obj = JsonSerializer.Deserialize>(JsonString); - Assert.Equal("World", obj["Hello"]); - Assert.Equal("World2", obj["Hello2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.True(JsonString == json || ReorderedJsonString == json); - - json = JsonSerializer.Serialize(obj); - Assert.True(JsonString == json || ReorderedJsonString == json); - } - - { - ImmutableSortedDictionary obj = JsonSerializer.Deserialize>(JsonString); - Assert.Equal("World", obj["Hello"]); - Assert.Equal("World2", obj["Hello2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.True(JsonString == json); - - json = JsonSerializer.Serialize(obj); - Assert.True(JsonString == json); - } - - { - Hashtable obj = JsonSerializer.Deserialize(JsonString); - Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); - Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); - - string json = JsonSerializer.Serialize(obj); - Assert.True(JsonString == json || ReorderedJsonString == json); - - json = JsonSerializer.Serialize(obj); - Assert.True(JsonString == json || ReorderedJsonString == json); - } - - { - SortedList obj = JsonSerializer.Deserialize(JsonString); - Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); - Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - } - - [Fact] - public static void ImplementsDictionary_DictionaryOfString() - { - const string JsonString = @"{""Hello"":""World"",""Hello2"":""World2""}"; - const string ReorderedJsonString = @"{""Hello2"":""World2"",""Hello"":""World""}"; - - { - WrapperForIDictionary obj = JsonSerializer.Deserialize(JsonString); - Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); - Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - { - StringToStringDictionaryWrapper obj = JsonSerializer.Deserialize(JsonString); - Assert.Equal("World", obj["Hello"]); - Assert.Equal("World2", obj["Hello2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - { - StringToStringSortedDictionaryWrapper obj = JsonSerializer.Deserialize(JsonString); - Assert.Equal("World", obj["Hello"]); - Assert.Equal("World2", obj["Hello2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - { - StringToStringIDictionaryWrapper obj = JsonSerializer.Deserialize(JsonString); - Assert.Equal("World", obj["Hello"]); - Assert.Equal("World2", obj["Hello2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - { - Assert.Throws(() => JsonSerializer.Deserialize(JsonString)); - - StringToStringIReadOnlyDictionaryWrapper obj = new StringToStringIReadOnlyDictionaryWrapper(new Dictionary() - { - { "Hello", "World" }, - { "Hello2", "World2" }, - }); - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - { - Assert.Throws(() => JsonSerializer.Deserialize(JsonString)); - - StringToStringIImmutableDictionaryWrapper obj = new StringToStringIImmutableDictionaryWrapper(new Dictionary() - { - { "Hello", "World" }, - { "Hello2", "World2" }, - }); - - string json = JsonSerializer.Serialize(obj); - Assert.True(JsonString == json || ReorderedJsonString == json); - - json = JsonSerializer.Serialize(obj); - Assert.True(JsonString == json || ReorderedJsonString == json); - } - - { - HashtableWrapper obj = JsonSerializer.Deserialize(JsonString); - Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); - Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); - - string json = JsonSerializer.Serialize(obj); - Assert.True(JsonString == json || ReorderedJsonString == json); - - json = JsonSerializer.Serialize(obj); - Assert.True(JsonString == json || ReorderedJsonString == json); - } - - { - SortedListWrapper obj = JsonSerializer.Deserialize(JsonString); - Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); - Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - } - - [Fact] - public static void DictionaryOfObject() - { - { - Dictionary obj = JsonSerializer.Deserialize>(@"{""Key1"":1}"); - Assert.Equal(1, obj.Count); - JsonElement element = (JsonElement)obj["Key1"]; - Assert.Equal(JsonValueKind.Number, element.ValueKind); - Assert.Equal(1, element.GetInt32()); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(@"{""Key1"":1}", json); - } - - { - IDictionary obj = JsonSerializer.Deserialize>(@"{""Key1"":1}"); - Assert.Equal(1, obj.Count); - JsonElement element = (JsonElement)obj["Key1"]; - Assert.Equal(JsonValueKind.Number, element.ValueKind); - Assert.Equal(1, element.GetInt32()); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(@"{""Key1"":1}", json); - } - } - - [Fact] - public static void ImplementsIDictionaryOfObject() - { - var input = new StringToObjectIDictionaryWrapper(new Dictionary - { - { "Name", "David" }, - { "Age", 32 } - }); - - string json = JsonSerializer.Serialize(input, typeof(IDictionary)); - Assert.Equal(@"{""Name"":""David"",""Age"":32}", json); - - IDictionary obj = JsonSerializer.Deserialize>(json); - Assert.Equal(2, obj.Count); - Assert.Equal("David", ((JsonElement)obj["Name"]).GetString()); - Assert.Equal(32, ((JsonElement)obj["Age"]).GetInt32()); - } - - [Fact] - public static void ImplementsIDictionaryOfString() - { - var input = new StringToStringIDictionaryWrapper(new Dictionary - { - { "Name", "David" }, - { "Job", "Software Architect" } - }); - - string json = JsonSerializer.Serialize(input, typeof(IDictionary)); - Assert.Equal(@"{""Name"":""David"",""Job"":""Software Architect""}", json); - - IDictionary obj = JsonSerializer.Deserialize>(json); - Assert.Equal(2, obj.Count); - Assert.Equal("David", obj["Name"]); - Assert.Equal("Software Architect", obj["Job"]); - } - - [Theory] - [InlineData(typeof(ImmutableDictionary), "\"headers\"")] - [InlineData(typeof(Dictionary), "\"headers\"")] - [InlineData(typeof(PocoDictionary), "\"headers\"")] - public static void InvalidJsonForValueShouldFail(Type type, string json) - { - Assert.Throws(() => JsonSerializer.Deserialize(json, type)); - } - - public static IEnumerable InvalidJsonForIntValue() - { - yield return @"""1"""; - yield return "["; - yield return "}"; - yield return @"[""1""]"; - yield return "[true]"; - } - - public static IEnumerable InvalidJsonForPoco() - { - foreach (string value in InvalidJsonForIntValue()) - { - yield return value; - yield return "[" + value + "]"; - yield return "{" + value + "}"; - yield return @"{""Id"":" + value + "}"; - } - } - - public class ClassWithInt - { - public int Obj { get; set; } - } - - public class ClassWithIntList - { - public List Obj { get; set; } - } - - public class ClassWithIntArray - { - public int[] Obj { get; set; } - } - - public class ClassWithPoco - { - public Poco Obj { get; set; } - } - - public class ClassWithPocoArray - { - public Poco[] Obj { get; set; } - } - - public class ClassWithDictionaryOfIntArray - { - public Dictionary Obj { get; set; } - } - - public class ClassWithDictionaryOfPoco - { - public Dictionary Obj { get; set; } - } - - public class ClassWithDictionaryOfPocoList - { - public Dictionary> Obj { get; set; } - } - - public static IEnumerable TypesForInvalidJsonForCollectionTests() - { - static Type MakeClosedCollectionType(Type openCollectionType, Type elementType) - { - if (openCollectionType == typeof(Dictionary<,>)) - { - return typeof(Dictionary<,>).MakeGenericType(typeof(string), elementType); - } - else - { - return openCollectionType.MakeGenericType(elementType); - } - } - - Type[] elementTypes = new Type[] - { - typeof(int), - typeof(Poco), - typeof(ClassWithInt), - typeof(ClassWithIntList), - typeof(ClassWithPoco), - typeof(ClassWithPocoArray), - typeof(ClassWithDictionaryOfIntArray), - typeof(ClassWithDictionaryOfPoco), - typeof(ClassWithDictionaryOfPocoList), - }; - - Type[] collectionTypes = new Type[] - { - typeof(List<>), - typeof(Dictionary<,>), - }; - - foreach (Type type in elementTypes) - { - yield return type; - } - - List innerTypes = new List(elementTypes); - - // Create permutations of collections with 1 and 2 levels of nesting. - for (int i = 0; i < 2; i++) - { - foreach (Type collectionType in collectionTypes) - { - List newInnerTypes = new List(); - - foreach (Type elementType in innerTypes) - { - Type newCollectionType = MakeClosedCollectionType(collectionType, elementType); - newInnerTypes.Add(newCollectionType); - yield return newCollectionType; - } - - innerTypes = newInnerTypes; - } - } - } - - static IEnumerable GetInvalidJsonStringsForType(Type type) - { - if (type == typeof(int)) - { - foreach (string json in InvalidJsonForIntValue()) - { - yield return json; - } - yield break; - } - - if (type == typeof(Poco)) - { - foreach (string json in InvalidJsonForPoco()) - { - yield return json; - } - yield break; - } - - Type elementType; - - if (!typeof(IEnumerable).IsAssignableFrom(type)) - { - // Get type of "Obj" property. - elementType = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)[0].PropertyType; - } - else if (type.IsArray) - { - elementType = type.GetElementType(); - } - else if (!type.IsGenericType) - { - Assert.True(false, "Expected generic type"); - yield break; - } - else - { - Type genericTypeDef = type.GetGenericTypeDefinition(); - - if (genericTypeDef == typeof(List<>)) - { - elementType = type.GetGenericArguments()[0]; - } - else if (genericTypeDef == typeof(Dictionary<,>)) - { - elementType = type.GetGenericArguments()[1]; - } - else - { - Assert.True(false, "Expected List or Dictionary type"); - yield break; - } - } - - foreach (string invalidJson in GetInvalidJsonStringsForType(elementType)) - { - yield return "[" + invalidJson + "]"; - yield return "{" + invalidJson + "}"; - yield return @"{""Obj"":" + invalidJson + "}"; - } - } - - public static IEnumerable DataForInvalidJsonForTypeTests() - { - foreach (Type type in TypesForInvalidJsonForCollectionTests()) - { - foreach (string invalidJson in GetInvalidJsonStringsForType(type)) - { - yield return new object[] { type, invalidJson }; - } - } - - yield return new object[] { typeof(int[]), @"""test""" }; - yield return new object[] { typeof(int[]), @"1" }; - yield return new object[] { typeof(int[]), @"false" }; - yield return new object[] { typeof(int[]), @"{}" }; - yield return new object[] { typeof(int[]), @"{""test"": 1}" }; - yield return new object[] { typeof(int[]), @"[""test""" }; - yield return new object[] { typeof(int[]), @"[""test""]" }; - yield return new object[] { typeof(int[]), @"[true]" }; - yield return new object[] { typeof(int[]), @"[{}]" }; - yield return new object[] { typeof(int[]), @"[[]]" }; - yield return new object[] { typeof(int[]), @"[{""test"": 1}]" }; - yield return new object[] { typeof(int[]), @"[[true]]" }; - yield return new object[] { typeof(Dictionary), @"{""test"": {}}" }; - yield return new object[] { typeof(Dictionary), @"{""test"": {""test"": 1}}" }; - yield return new object[] { typeof(Dictionary), @"{""test"": ""test""}" }; - yield return new object[] { typeof(Dictionary), @"{""test"": 1}" }; - yield return new object[] { typeof(Dictionary), @"{""test"": true}" }; - yield return new object[] { typeof(Dictionary), @"{""test"": [""test""}" }; - yield return new object[] { typeof(Dictionary), @"{""test"": [""test""]}" }; - yield return new object[] { typeof(Dictionary), @"{""test"": [[]]}" }; - yield return new object[] { typeof(Dictionary), @"{""test"": [true]}" }; - yield return new object[] { typeof(Dictionary), @"{""test"": [{}]}" }; - yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": ""test""}" }; - yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": 1}" }; - yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": false}" }; - yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": {}}" }; - yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": {""test"": 1}}" }; - yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [""test""}" }; - yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [""test""]}" }; - yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [true]}" }; - yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [{}]}" }; - yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [[]]}" }; - yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [{""test"": 1}]}" }; - yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [[true]]}" }; - yield return new object[] { typeof(Dictionary), @"""test""" }; - yield return new object[] { typeof(Dictionary), @"1" }; - yield return new object[] { typeof(Dictionary), @"false" }; - yield return new object[] { typeof(Dictionary), @"{"""": 1}" }; - yield return new object[] { typeof(Dictionary), @"{"""": {}}" }; - yield return new object[] { typeof(Dictionary), @"{"""": {"""":""""}}" }; - yield return new object[] { typeof(Dictionary), @"[""test""" }; - yield return new object[] { typeof(Dictionary), @"[""test""]" }; - yield return new object[] { typeof(Dictionary), @"[true]" }; - yield return new object[] { typeof(Dictionary), @"[{}]" }; - yield return new object[] { typeof(Dictionary), @"[[]]" }; - yield return new object[] { typeof(Dictionary), @"[{""test"": 1}]" }; - yield return new object[] { typeof(Dictionary), @"[[true]]" }; - yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":""test""}" }; - yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":1}" }; - yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":false}" }; - yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":{"""": 1}}" }; - yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":{"""": {}}}" }; - yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":{"""": {"""":""""}}}" }; - yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[""test""}" }; - yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[""test""]}" }; - yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[true]}" }; - yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[{}]}" }; - yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[[]]}" }; - yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[{""test"": 1}]}" }; - yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[[true]]}" }; - yield return new object[] { typeof(Dictionary), @"{""key"":[{""Id"":3}]}" }; - yield return new object[] { typeof(Dictionary), @"{""key"":[""test""]}" }; - yield return new object[] { typeof(Dictionary), @"{""key"":[1]}" }; - yield return new object[] { typeof(Dictionary), @"{""key"":[false]}" }; - yield return new object[] { typeof(Dictionary), @"{""key"":[]}" }; - yield return new object[] { typeof(Dictionary), @"{""key"":1}" }; - yield return new object[] { typeof(Dictionary>), @"{""key"":{""Id"":3}}" }; - yield return new object[] { typeof(Dictionary>), @"{""key"":{}}" }; - yield return new object[] { typeof(Dictionary>), @"{""key"":[[]]}" }; - yield return new object[] { typeof(Dictionary>), @"{""key"":[]}" }; - yield return new object[] { typeof(Dictionary>), @"{""key"":1}" }; - } - - [Fact] - public static void InvalidJsonForTypeShouldFail() - { - foreach (object[] args in DataForInvalidJsonForTypeTests()) // ~140K tests, too many for theory to handle well with our infrastructure - { - var type = (Type)args[0]; - var invalidJson = (string)args[1]; - Assert.Throws(() => JsonSerializer.Deserialize(invalidJson, type)); - } - } - - [Fact] - public static void InvalidEmptyDictionaryInput() - { - Assert.Throws(() => JsonSerializer.Deserialize("{}")); - } - - [Fact] - public static void PocoWithDictionaryObject() - { - PocoDictionary dict = JsonSerializer.Deserialize("{\n\t\"key\" : {\"a\" : \"b\", \"c\" : \"d\"}}"); - Assert.Equal("b", dict.key["a"]); - Assert.Equal("d", dict.key["c"]); - } - - public class PocoDictionary - { - public Dictionary key { get; set; } - } - - [Fact] - public static void DictionaryOfObject_NonPrimitiveTypes() - { - // https://github.com/dotnet/runtime/issues/29504 - Dictionary dictionary = new Dictionary - { - ["key"] = new Poco { Id = 10 }, - }; - - string json = JsonSerializer.Serialize(dictionary); - Assert.Equal(@"{""key"":{""Id"":10}}", json); - - dictionary = JsonSerializer.Deserialize>(json); - Assert.Equal(1, dictionary.Count); - JsonElement element = (JsonElement)dictionary["key"]; - Assert.Equal(@"{""Id"":10}", element.ToString()); - } - - public class Poco - { - public int Id { get; set; } - } - - [Fact] - public static void FirstGenericArgNotStringFail() - { - Assert.Throws(() => JsonSerializer.Deserialize>(@"{1:1}")); - Assert.Throws(() => JsonSerializer.Deserialize>(@"{1:1}")); - } - - [Fact] - public static void DictionaryOfList() - { - const string JsonString = @"{""Key1"":[1,2],""Key2"":[3,4]}"; - - { - IDictionary obj = JsonSerializer.Deserialize(JsonString); - - Assert.Equal(2, obj.Count); - - int expectedNumber = 1; - - JsonElement element = (JsonElement)obj["Key1"]; - foreach (JsonElement value in element.EnumerateArray()) - { - Assert.Equal(expectedNumber++, value.GetInt32()); - } - - element = (JsonElement)obj["Key2"]; - foreach (JsonElement value in element.EnumerateArray()) - { - Assert.Equal(expectedNumber++, value.GetInt32()); - } - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - { - IDictionary> obj = JsonSerializer.Deserialize>>(JsonString); - - Assert.Equal(2, obj.Count); - Assert.Equal(2, obj["Key1"].Count); - Assert.Equal(1, obj["Key1"][0]); - Assert.Equal(2, obj["Key1"][1]); - Assert.Equal(2, obj["Key2"].Count); - Assert.Equal(3, obj["Key2"][0]); - Assert.Equal(4, obj["Key2"][1]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - { - ImmutableDictionary> obj = JsonSerializer.Deserialize>>(JsonString); - - Assert.Equal(2, obj.Count); - Assert.Equal(2, obj["Key1"].Count); - Assert.Equal(1, obj["Key1"][0]); - Assert.Equal(2, obj["Key1"][1]); - Assert.Equal(2, obj["Key2"].Count); - Assert.Equal(3, obj["Key2"][0]); - Assert.Equal(4, obj["Key2"][1]); - - string json = JsonSerializer.Serialize(obj); - const string ReorderedJsonString = @"{""Key2"":[3,4],""Key1"":[1,2]}"; - Assert.True(JsonString == json || ReorderedJsonString == json); - } - - { - IImmutableDictionary> obj = JsonSerializer.Deserialize>>(JsonString); - - Assert.Equal(2, obj.Count); - Assert.Equal(2, obj["Key1"].Count); - Assert.Equal(1, obj["Key1"][0]); - Assert.Equal(2, obj["Key1"][1]); - Assert.Equal(2, obj["Key2"].Count); - Assert.Equal(3, obj["Key2"][0]); - Assert.Equal(4, obj["Key2"][1]); - - - string json = JsonSerializer.Serialize(obj); - const string ReorderedJsonString = @"{""Key2"":[3,4],""Key1"":[1,2]}"; - Assert.True(JsonString == json || ReorderedJsonString == json); - } - } - - [Fact] - public static void DictionaryOfArray() - { - const string JsonString = @"{""Key1"":[1,2],""Key2"":[3,4]}"; - Dictionary obj = JsonSerializer.Deserialize>(JsonString); - - Assert.Equal(2, obj.Count); - Assert.Equal(2, obj["Key1"].Length); - Assert.Equal(1, obj["Key1"][0]); - Assert.Equal(2, obj["Key1"][1]); - Assert.Equal(2, obj["Key2"].Length); - Assert.Equal(3, obj["Key2"][0]); - Assert.Equal(4, obj["Key2"][1]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - [Fact] - public static void ListOfDictionary() - { - const string JsonString = @"[{""Key1"":1,""Key2"":2},{""Key1"":3,""Key2"":4}]"; - - { - List> obj = JsonSerializer.Deserialize>>(JsonString); - - Assert.Equal(2, obj.Count); - Assert.Equal(2, obj[0].Count); - Assert.Equal(1, obj[0]["Key1"]); - Assert.Equal(2, obj[0]["Key2"]); - Assert.Equal(2, obj[1].Count); - Assert.Equal(3, obj[1]["Key1"]); - Assert.Equal(4, obj[1]["Key2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - { - List> obj = JsonSerializer.Deserialize>>(JsonString); - - Assert.Equal(2, obj.Count); - Assert.Equal(2, obj[0].Count); - Assert.Equal(1, obj[0]["Key1"]); - Assert.Equal(2, obj[0]["Key2"]); - Assert.Equal(2, obj[1].Count); - Assert.Equal(3, obj[1]["Key1"]); - Assert.Equal(4, obj[1]["Key2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - } - - [Fact] - public static void ArrayOfDictionary() - { - const string JsonString = @"[{""Key1"":1,""Key2"":2},{""Key1"":3,""Key2"":4}]"; - - { - Dictionary[] obj = JsonSerializer.Deserialize[]>(JsonString); - - Assert.Equal(2, obj.Length); - Assert.Equal(2, obj[0].Count); - Assert.Equal(1, obj[0]["Key1"]); - Assert.Equal(2, obj[0]["Key2"]); - Assert.Equal(2, obj[1].Count); - Assert.Equal(3, obj[1]["Key1"]); - Assert.Equal(4, obj[1]["Key2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - { - ImmutableSortedDictionary[] obj = JsonSerializer.Deserialize[]>(JsonString); - - Assert.Equal(2, obj.Length); - Assert.Equal(2, obj[0].Count); - Assert.Equal(1, obj[0]["Key1"]); - Assert.Equal(2, obj[0]["Key2"]); - Assert.Equal(2, obj[1].Count); - Assert.Equal(3, obj[1]["Key1"]); - Assert.Equal(4, obj[1]["Key2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - } - - [Fact] - public static void DictionaryOfDictionary() - { - const string JsonString = @"{""Key1"":{""Key1a"":1,""Key1b"":2},""Key2"":{""Key2a"":3,""Key2b"":4}}"; - - { - Dictionary> obj = JsonSerializer.Deserialize>>(JsonString); - - Assert.Equal(2, obj.Count); - Assert.Equal(2, obj["Key1"].Count); - Assert.Equal(1, obj["Key1"]["Key1a"]); - Assert.Equal(2, obj["Key1"]["Key1b"]); - Assert.Equal(2, obj["Key2"].Count); - Assert.Equal(3, obj["Key2"]["Key2a"]); - Assert.Equal(4, obj["Key2"]["Key2b"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - { - ImmutableSortedDictionary> obj = JsonSerializer.Deserialize>>(JsonString); - - Assert.Equal(2, obj.Count); - Assert.Equal(2, obj["Key1"].Count); - Assert.Equal(1, obj["Key1"]["Key1a"]); - Assert.Equal(2, obj["Key1"]["Key1b"]); - Assert.Equal(2, obj["Key2"].Count); - Assert.Equal(3, obj["Key2"]["Key2a"]); - Assert.Equal(4, obj["Key2"]["Key2b"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - } - - [Fact] - public static void DictionaryOfDictionaryOfDictionary() - { - const string JsonString = @"{""Key1"":{""Key1"":{""Key1"":1,""Key2"":2},""Key2"":{""Key1"":3,""Key2"":4}},""Key2"":{""Key1"":{""Key1"":5,""Key2"":6},""Key2"":{""Key1"":7,""Key2"":8}}}"; - Dictionary>> obj = JsonSerializer.Deserialize>>>(JsonString); - - Assert.Equal(2, obj.Count); - Assert.Equal(2, obj["Key1"].Count); - Assert.Equal(2, obj["Key1"]["Key1"].Count); - Assert.Equal(2, obj["Key1"]["Key2"].Count); - - Assert.Equal(1, obj["Key1"]["Key1"]["Key1"]); - Assert.Equal(2, obj["Key1"]["Key1"]["Key2"]); - Assert.Equal(3, obj["Key1"]["Key2"]["Key1"]); - Assert.Equal(4, obj["Key1"]["Key2"]["Key2"]); - - Assert.Equal(2, obj["Key2"].Count); - Assert.Equal(2, obj["Key2"]["Key1"].Count); - Assert.Equal(2, obj["Key2"]["Key2"].Count); - - Assert.Equal(5, obj["Key2"]["Key1"]["Key1"]); - Assert.Equal(6, obj["Key2"]["Key1"]["Key2"]); - Assert.Equal(7, obj["Key2"]["Key2"]["Key1"]); - Assert.Equal(8, obj["Key2"]["Key2"]["Key2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - // Verify that typeof(object) doesn't interfere. - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - [Fact] - public static void DictionaryOfArrayOfDictionary() - { - const string JsonString = @"{""Key1"":[{""Key1"":1,""Key2"":2},{""Key1"":3,""Key2"":4}],""Key2"":[{""Key1"":5,""Key2"":6},{""Key1"":7,""Key2"":8}]}"; - Dictionary[]> obj = JsonSerializer.Deserialize[]>>(JsonString); - - Assert.Equal(2, obj.Count); - Assert.Equal(2, obj["Key1"].Length); - Assert.Equal(2, obj["Key1"][0].Count); - Assert.Equal(2, obj["Key1"][1].Count); - - Assert.Equal(1, obj["Key1"][0]["Key1"]); - Assert.Equal(2, obj["Key1"][0]["Key2"]); - Assert.Equal(3, obj["Key1"][1]["Key1"]); - Assert.Equal(4, obj["Key1"][1]["Key2"]); - - Assert.Equal(2, obj["Key2"].Length); - Assert.Equal(2, obj["Key2"][0].Count); - Assert.Equal(2, obj["Key2"][1].Count); - - Assert.Equal(5, obj["Key2"][0]["Key1"]); - Assert.Equal(6, obj["Key2"][0]["Key2"]); - Assert.Equal(7, obj["Key2"][1]["Key1"]); - Assert.Equal(8, obj["Key2"][1]["Key2"]); - - string json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - - // Verify that typeof(object) doesn't interfere. - json = JsonSerializer.Serialize(obj); - Assert.Equal(JsonString, json); - } - - private interface IClass { } - - private class MyClass : IClass { } - - private class MyNonGenericDictionary : Dictionary { } - - private class MyFactory : JsonConverterFactory - { - public override bool CanConvert(Type typeToConvert) - { - return typeToConvert == typeof(IClass) || typeToConvert == typeof(MyClass); - } - - public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) - { - if (typeToConvert == typeof(IClass)) - { - return new MyStuffConverterForIClass(); - } - else if (typeToConvert == typeof(MyClass)) - { - return new MyStuffConverterForMyClass(); - } - else - { - throw new InvalidOperationException(); - } - } - } - - private class MyStuffConverterForIClass : JsonConverter - { - public override IClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new MyClass(); - } - - public override void Write(Utf8JsonWriter writer, IClass value, JsonSerializerOptions options) - { - writer.WriteNumberValue(1); - } - } - - private class MyStuffConverterForMyClass : JsonConverter - { - public override MyClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return new MyClass(); - } - - public override void Write(Utf8JsonWriter writer, MyClass value, JsonSerializerOptions options) - { - writer.WriteNumberValue(1); - } - } - - // This method generates 316 unique test cases for nested dictionaries up to 4 - // levels deep, along with matching JSON, encompassing the various planes of - // dictionaries that can be combined: generic, non-generic, BCL, user-derived, - // immutable, mutable, readonly, concurrent, specialized. - private static IEnumerable<(Type, string)> NestedDictionaryTypeData() - { - string testJson = @"{""Key"":1}"; - - List genericDictTypes = new List() - { - typeof(IDictionary<,>), - typeof(ConcurrentDictionary<,>), - typeof(GenericIDictionaryWrapper<,>), - }; - - List nonGenericDictTypes = new List() - { - typeof(Hashtable), - typeof(OrderedDictionary), - }; - - List baseDictionaryTypes = new List - { - typeof(MyNonGenericDictionary), - typeof(IReadOnlyDictionary), - typeof(ConcurrentDictionary), - typeof(ImmutableDictionary), - typeof(GenericIDictionaryWrapper), - }; - baseDictionaryTypes.AddRange(nonGenericDictTypes); - - // This method has exponential behavior which this depth value significantly impacts. - // Don't change this value without checking how many test cases are generated and - // how long the tests run for. - int maxTestDepth = 4; - - HashSet<(Type, string)> tests = new HashSet<(Type, string)>(); - - for (int i = 0; i < maxTestDepth; i++) - { - List newBaseTypes = new List(); - - foreach (Type testType in baseDictionaryTypes) - { - tests.Add((testType, testJson)); - - foreach (Type genericType in genericDictTypes) - { - newBaseTypes.Add(genericType.MakeGenericType(typeof(string), testType)); - } - - newBaseTypes.AddRange(nonGenericDictTypes); - } - - baseDictionaryTypes = newBaseTypes; - testJson = @"{""Key"":" + testJson + "}"; - } - - return tests; - } - - [Fact] - public static void NestedDictionariesRoundtrip() - { - JsonSerializerOptions options = new JsonSerializerOptions(); - options.Converters.Add(new MyFactory()); - - foreach ((Type dictionaryType, string testJson) in NestedDictionaryTypeData()) - { - object dict = JsonSerializer.Deserialize(testJson, dictionaryType, options); - Assert.Equal(testJson, JsonSerializer.Serialize(dict, options)); - } - } - - [Fact] - public static void DictionaryOfClasses() - { - { - IDictionary obj; - - { - string json = @"{""Key1"":" + SimpleTestClass.s_json + @",""Key2"":" + SimpleTestClass.s_json + "}"; - obj = JsonSerializer.Deserialize(json); - Assert.Equal(2, obj.Count); - - if (obj["Key1"] is JsonElement element) - { - SimpleTestClass result = JsonSerializer.Deserialize(element.GetRawText()); - result.Verify(); - } - else - { - ((SimpleTestClass)obj["Key1"]).Verify(); - ((SimpleTestClass)obj["Key2"]).Verify(); - } - } - - { - // We can't compare against the json string above because property ordering is not deterministic (based on reflection order) - // so just round-trip the json and compare. - string json = JsonSerializer.Serialize(obj); - obj = JsonSerializer.Deserialize(json); - Assert.Equal(2, obj.Count); - - if (obj["Key1"] is JsonElement element) - { - SimpleTestClass result = JsonSerializer.Deserialize(element.GetRawText()); - result.Verify(); - } - else - { - ((SimpleTestClass)obj["Key1"]).Verify(); - ((SimpleTestClass)obj["Key2"]).Verify(); - } - } - - { - string json = JsonSerializer.Serialize(obj); - obj = JsonSerializer.Deserialize(json); - Assert.Equal(2, obj.Count); - - if (obj["Key1"] is JsonElement element) - { - SimpleTestClass result = JsonSerializer.Deserialize(element.GetRawText()); - result.Verify(); - } - else - { - ((SimpleTestClass)obj["Key1"]).Verify(); - ((SimpleTestClass)obj["Key2"]).Verify(); - } - } - } - - { - Dictionary obj; - - { - string json = @"{""Key1"":" + SimpleTestClass.s_json + @",""Key2"":" + SimpleTestClass.s_json + "}"; - obj = JsonSerializer.Deserialize>(json); - Assert.Equal(2, obj.Count); - obj["Key1"].Verify(); - obj["Key2"].Verify(); - } - - { - // We can't compare against the json string above because property ordering is not deterministic (based on reflection order) - // so just round-trip the json and compare. - string json = JsonSerializer.Serialize(obj); - obj = JsonSerializer.Deserialize>(json); - Assert.Equal(2, obj.Count); - obj["Key1"].Verify(); - obj["Key2"].Verify(); - } - - { - string json = JsonSerializer.Serialize(obj); - obj = JsonSerializer.Deserialize>(json); - Assert.Equal(2, obj.Count); - obj["Key1"].Verify(); - obj["Key2"].Verify(); - } - } - - { - ImmutableSortedDictionary obj; - - { - string json = @"{""Key1"":" + SimpleTestClass.s_json + @",""Key2"":" + SimpleTestClass.s_json + "}"; - obj = JsonSerializer.Deserialize>(json); - Assert.Equal(2, obj.Count); - obj["Key1"].Verify(); - obj["Key2"].Verify(); - } - - { - // We can't compare against the json string above because property ordering is not deterministic (based on reflection order) - // so just round-trip the json and compare. - string json = JsonSerializer.Serialize(obj); - obj = JsonSerializer.Deserialize>(json); - Assert.Equal(2, obj.Count); - obj["Key1"].Verify(); - obj["Key2"].Verify(); - } - - { - string json = JsonSerializer.Serialize(obj); - obj = JsonSerializer.Deserialize>(json); - Assert.Equal(2, obj.Count); - obj["Key1"].Verify(); - obj["Key2"].Verify(); - } - } - } - - [Fact] - public static void UnicodePropertyNames() - { - var options = new JsonSerializerOptions(); - options.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping; - - { - Dictionary obj; - - obj = JsonSerializer.Deserialize>(@"{""A\u0467"":1}"); - Assert.Equal(1, obj["A\u0467"]); - - // Specifying encoder on options does not impact deserialize. - obj = JsonSerializer.Deserialize>(@"{""A\u0467"":1}", options); - Assert.Equal(1, obj["A\u0467"]); - - string json; - // Verify the name is escaped after serialize. - json = JsonSerializer.Serialize(obj); - Assert.Equal(@"{""A\u0467"":1}", json); - - // Verify with encoder. - json = JsonSerializer.Serialize(obj, options); - Assert.Equal("{\"A\u0467\":1}", json); - } - - { - // We want to go over StackallocThreshold=256 to force a pooled allocation, so this property is 200 chars and 400 bytes. - const int charsInProperty = 200; - - string longPropertyName = new string('\u0467', charsInProperty); - - Dictionary obj = JsonSerializer.Deserialize>($"{{\"{longPropertyName}\":1}}"); - Assert.Equal(1, obj[longPropertyName]); - - // Verify the name is escaped after serialize. - string json = JsonSerializer.Serialize(obj); - - // Duplicate the unicode character 'charsInProperty' times. - string longPropertyNameEscaped = new StringBuilder().Insert(0, @"\u0467", charsInProperty).ToString(); - - string expectedJson = $"{{\"{longPropertyNameEscaped}\":1}}"; - Assert.Equal(expectedJson, json); - - // Verify the name is unescaped after deserialize. - obj = JsonSerializer.Deserialize>(json); - Assert.Equal(1, obj[longPropertyName]); - } - } - - [Fact] - public static void CustomEscapingOnPropertyNameAndValue() - { - var dict = new Dictionary(); - dict.Add("A\u046701", "Value\u0467"); - - // Baseline with no escaping. - var json = JsonSerializer.Serialize(dict); - Assert.Equal("{\"A\\u046701\":\"Value\\u0467\"}", json); - - // Enable escaping. - var options = new JsonSerializerOptions(); - options.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping; - - json = JsonSerializer.Serialize(dict, options); - Assert.Equal("{\"A\u046701\":\"Value\u0467\"}", json); - } - - [Fact] - public static void ObjectToStringFail() - { - // Baseline - string json = @"{""MyDictionary"":{""Key"":""Value""}}"; - JsonSerializer.Deserialize>(json); - - Assert.Throws(() => JsonSerializer.Deserialize>(json)); - } - - [Fact] - public static void ObjectToJsonElement() - { - string json = @"{""MyDictionary"":{""Key"":""Value""}}"; - Dictionary result = JsonSerializer.Deserialize>(json); - JsonElement element = result["MyDictionary"]; - Assert.Equal(JsonValueKind.Object, element.ValueKind); - Assert.Equal("Value", element.GetProperty("Key").GetString()); - } - - [Fact] - public static void Hashtable() - { - const string Json = @"{""Key"":""Value""}"; - - IDictionary ht = new Hashtable(); - ht.Add("Key", "Value"); - string json = JsonSerializer.Serialize(ht); - - Assert.Equal(Json, json); - - ht = JsonSerializer.Deserialize(json); - Assert.IsType(ht["Key"]); - Assert.Equal("Value", ((JsonElement)ht["Key"]).GetString()); - - // Verify round-tripped JSON. - json = JsonSerializer.Serialize(ht); - Assert.Equal(Json, json); - } - - [Fact] - public static void DeserializeDictionaryWithDuplicateKeys() - { - // Non-generic IDictionary case. - IDictionary iDictionary = JsonSerializer.Deserialize(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); - Assert.Equal("NewValue", iDictionary["Hello"].ToString()); - - // Generic IDictionary case. - IDictionary iNonGenericDictionary = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); - Assert.Equal("NewValue", iNonGenericDictionary["Hello"]); - - IDictionary iNonGenericObjectDictionary = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); - Assert.Equal("NewValue", iNonGenericObjectDictionary["Hello"].ToString()); - - // Strongly-typed IDictionary<,> case. - Dictionary dictionary = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); - Assert.Equal("NewValue", dictionary["Hello"]); - - dictionary = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""myKey"" : ""myValue"", ""Hello"":""NewValue""}"); - Assert.Equal("NewValue", dictionary["Hello"]); - - // Weakly-typed IDictionary case. - Dictionary dictionaryObject = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""Hello"": null}"); - Assert.Null(dictionaryObject["Hello"]); - } - - [Fact] - public static void DeserializeDictionaryWithDuplicateProperties() - { - PocoDuplicate foo = JsonSerializer.Deserialize(@"{""BoolProperty"": false, ""BoolProperty"": true}"); - Assert.True(foo.BoolProperty); - - foo = JsonSerializer.Deserialize(@"{""BoolProperty"": false, ""IntProperty"" : 1, ""BoolProperty"": true , ""IntProperty"" : 2}"); - Assert.True(foo.BoolProperty); - Assert.Equal(2, foo.IntProperty); - - foo = JsonSerializer.Deserialize(@"{""DictProperty"" : {""a"" : ""b"", ""c"" : ""d""},""DictProperty"" : {""b"" : ""b"", ""c"" : ""e""}}"); - Assert.Equal(2, foo.DictProperty.Count); // We don't concat. - Assert.Equal("e", foo.DictProperty["c"]); - } - - public class PocoDuplicate - { - public bool BoolProperty { get; set; } - public int IntProperty { get; set; } - public Dictionary DictProperty { get; set; } - } - - public class ClassWithPopulatedDictionaryAndNoSetter - { - public ClassWithPopulatedDictionaryAndNoSetter() - { - MyImmutableDictionary = MyImmutableDictionary.Add("Key", "Value"); - } - - public Dictionary MyDictionary { get; } = new Dictionary() { { "Key", "Value" } }; - public ImmutableDictionary MyImmutableDictionary { get; } = ImmutableDictionary.Create(); - } - - [Fact] - public static void ClassWithNoSetterAndDictionary() - { - // We don't attempt to deserialize into dictionaries without a setter. - string json = @"{""MyDictionary"":{""Key1"":""Value1"", ""Key2"":""Value2""}}"; - ClassWithPopulatedDictionaryAndNoSetter obj = JsonSerializer.Deserialize(json); - Assert.Equal(1, obj.MyDictionary.Count); - } - - [Fact] - public static void ClassWithNoSetterAndImmutableDictionary() - { - // We don't attempt to deserialize into dictionaries without a setter. - string json = @"{""MyImmutableDictionary"":{""Key1"":""Value1"", ""Key2"":""Value2""}}"; - ClassWithPopulatedDictionaryAndNoSetter obj = JsonSerializer.Deserialize(json); - Assert.Equal(1, obj.MyImmutableDictionary.Count); - } - - public class ClassWithIgnoredDictionary1 - { - public Dictionary Parsed1 { get; set; } - public Dictionary Parsed2 { get; set; } - public Dictionary Skipped3 { get; } - } - - public class ClassWithIgnoredDictionary2 - { - public IDictionary Parsed1 { get; set; } - public IDictionary Skipped2 { get; } - public IDictionary Parsed3 { get; set; } - } - - public class ClassWithIgnoredDictionary3 - { - public Dictionary Parsed1 { get; set; } - public Dictionary Skipped2 { get; } - public Dictionary Skipped3 { get; } - } - - public class ClassWithIgnoredDictionary4 - { - public Dictionary Skipped1 { get; } - public Dictionary Parsed2 { get; set; } - public Dictionary Parsed3 { get; set; } - } - - public class ClassWithIgnoredDictionary5 - { - public Dictionary Skipped1 { get; } - public Dictionary Parsed2 { get; set; } - public Dictionary Skipped3 { get; } - } - - public class ClassWithIgnoredDictionary6 - { - public Dictionary Skipped1 { get; } - public Dictionary Skipped2 { get; } - public Dictionary Parsed3 { get; set; } - } - - public class ClassWithIgnoredDictionary7 - { - public Dictionary Skipped1 { get; } - public Dictionary Skipped2 { get; } - public Dictionary Skipped3 { get; } - } - - public class ClassWithIgnoredIDictionary - { - public IDictionary Parsed1 { get; set; } - public IDictionary Skipped2 { get; } - public IDictionary Parsed3 { get; set; } - } - - public class ClassWithIgnoreAttributeDictionary - { - public Dictionary Parsed1 { get; set; } - [JsonIgnore] public Dictionary Skipped2 { get; set; } // Note this has a setter. - public Dictionary Parsed3 { get; set; } - } - - public class ClassWithIgnoredImmutableDictionary - { - public ImmutableDictionary Parsed1 { get; set; } - public ImmutableDictionary Skipped2 { get; } - public ImmutableDictionary Parsed3 { get; set; } - } - - [Theory] - [InlineData(@"{""Parsed1"":{""Key"":1},""Parsed3"":{""Key"":2}}")] // No value for skipped property - [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":{}, ""Parsed3"":{""Key"":2}}")] // Empty object {} skipped - [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":null, ""Parsed3"":{""Key"":2}}")] // null object skipped - [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":{""Key"":9}, ""Parsed3"":{""Key"":2}}")] // Valid "int" values skipped - // Invalid "int" values: - [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":{""Key"":[1,2,3]}, ""Parsed3"":{""Key"":2}}")] - [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":{""Key"":{}}, ""Parsed3"":{""Key"":2}}")] - [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":{""Key"":null}, ""Parsed3"":{""Key"":2}}")] - public static void IgnoreDictionaryProperty(string json) - { - // Verify deserialization - ClassWithIgnoredDictionary2 obj = JsonSerializer.Deserialize(json); - Assert.Equal(1, obj.Parsed1.Count); - Assert.Equal(1, obj.Parsed1["Key"]); - Assert.Null(obj.Skipped2); - Assert.Equal(1, obj.Parsed3.Count); - Assert.Equal(2, obj.Parsed3["Key"]); - - // Round-trip and verify. - string jsonRoundTripped = JsonSerializer.Serialize(obj); - ClassWithIgnoredDictionary2 objRoundTripped = JsonSerializer.Deserialize(jsonRoundTripped); - Assert.Equal(1, objRoundTripped.Parsed1.Count); - Assert.Equal(1, objRoundTripped.Parsed1["Key"]); - Assert.Null(objRoundTripped.Skipped2); - Assert.Equal(1, objRoundTripped.Parsed3.Count); - Assert.Equal(2, objRoundTripped.Parsed3["Key"]); - } - - [Fact] - public static void IgnoreDictionaryPropertyWithDifferentOrdering() - { - // Verify all combinations of 3 properties with at least one ignore. - VerifyIgnore(false, false, true); - VerifyIgnore(false, true, false); - VerifyIgnore(false, true, true); - VerifyIgnore(true, false, false); - VerifyIgnore(true, false, true); - VerifyIgnore(true, true, false); - VerifyIgnore(true, true, true); - - // Verify single case for IDictionary, [Ignore] and ImmutableDictionary. - // Also specify addMissing to add additional skipped JSON that does not have a corresponding property. - VerifyIgnore(false, true, false, addMissing: true); - VerifyIgnore(false, true, false, addMissing: true); - VerifyIgnore(false, true, false, addMissing: true); - } - - private static void VerifyIgnore(bool skip1, bool skip2, bool skip3, bool addMissing = false) - { - static IDictionary GetProperty(T objectToVerify, string propertyName) - { - return (IDictionary)objectToVerify.GetType().GetProperty(propertyName).GetValue(objectToVerify); - } - - void Verify(T objectToVerify) - { - if (skip1) - { - Assert.Null(GetProperty(objectToVerify, "Skipped1")); - } - else - { - Assert.Equal(1, GetProperty(objectToVerify, "Parsed1")["Key"]); - } - - if (skip2) - { - Assert.Null(GetProperty(objectToVerify, "Skipped2")); - } - else - { - Assert.Equal(2, GetProperty(objectToVerify, "Parsed2")["Key"]); - } - - if (skip3) - { - Assert.Null(GetProperty(objectToVerify, "Skipped3")); - } - else - { - Assert.Equal(3, GetProperty(objectToVerify, "Parsed3")["Key"]); - } - } - - // Tests that the parser picks back up after skipping/draining ignored elements. - StringBuilder json = new StringBuilder(@"{"); - - if (addMissing) - { - json.Append(@"""MissingProp1"": {},"); - } - - if (skip1) - { - json.Append(@"""Skipped1"":{},"); - } - else - { - json.Append(@"""Parsed1"":{""Key"":1},"); - } - - if (addMissing) - { - json.Append(@"""MissingProp2"": null,"); - } - - if (skip2) - { - json.Append(@"""Skipped2"":{},"); - } - else - { - json.Append(@"""Parsed2"":{""Key"":2},"); - } - - if (addMissing) - { - json.Append(@"""MissingProp3"": {""ABC"":{}},"); - } - - if (skip3) - { - json.Append(@"""Skipped3"":{}}"); - } - else - { - json.Append(@"""Parsed3"":{""Key"":3}}"); - } - - // Deserialize and verify. - string jsonString = json.ToString(); - T obj = JsonSerializer.Deserialize(jsonString); - Verify(obj); - - // Round-trip and verify. - // Any skipped properties due to lack of a setter will now be "null" when serialized instead of "{}". - string jsonStringRoundTripped = JsonSerializer.Serialize(obj); - T objRoundTripped = JsonSerializer.Deserialize(jsonStringRoundTripped); - Verify(objRoundTripped); - } - - public class ClassWithPopulatedDictionaryAndSetter - { - public ClassWithPopulatedDictionaryAndSetter() - { - MyImmutableDictionary = MyImmutableDictionary.Add("Key", "Value"); - } - - public Dictionary MyDictionary { get; set; } = new Dictionary() { { "Key", "Value" } }; - public ImmutableDictionary MyImmutableDictionary { get; set; } = ImmutableDictionary.Create(); - } - - [Fact] - public static void ClassWithPopulatedDictionary() - { - // We replace the contents. - string json = @"{""MyDictionary"":{""Key1"":""Value1"", ""Key2"":""Value2""}}"; - ClassWithPopulatedDictionaryAndSetter obj = JsonSerializer.Deserialize(json); - Assert.Equal(2, obj.MyDictionary.Count); - } - - [Fact] - public static void ClassWithPopulatedImmutableDictionary() - { - // We replace the contents. - string json = @"{""MyImmutableDictionary"":{""Key1"":""Value1"", ""Key2"":""Value2""}}"; - ClassWithPopulatedDictionaryAndSetter obj = JsonSerializer.Deserialize(json); - Assert.Equal(2, obj.MyImmutableDictionary.Count); - } - - [Fact] - public static void DictionaryNotSupported() - { - string json = @"{""MyDictionary"":{""Key"":""Value""}}"; - - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json)); - - // The exception contains the type. - Assert.Contains(typeof(Dictionary).ToString(), ex.Message); - Assert.DoesNotContain("Path: ", ex.Message); - } - - [Fact] - public static void DictionaryNotSupportedButIgnored() - { - string json = @"{""MyDictionary"":{""Key"":1}}"; - ClassWithNotSupportedDictionaryButIgnored obj = JsonSerializer.Deserialize(json); - Assert.Null(obj.MyDictionary); - } - - // https://github.com/dotnet/runtime/issues/29933 - [Fact] - public static void Serialize_IDictionaryOfPoco() - { - // Arrange - var value = new AllSingleUpperPropertiesParent() - { - Child = new Dictionary() - { - ["1"] = new AllSingleUpperProperties_Child() - { - A = "1", - B = string.Empty, - C = Array.Empty(), - D = Array.Empty(), - F = Array.Empty(), - K = Array.Empty(), - } - } - }; - - var actual = JsonSerializer.Serialize(value, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); - - // Assert - Assert.NotNull(actual); - Assert.NotEmpty(actual); - } - - // https://github.com/dotnet/runtime/issues/29933 - [Fact] - public static void Deserialize_IDictionaryOfPoco() - { - // Arrange - string json = "{\"child\":{\"1\":{\"a\":\"1\",\"b\":\"\",\"c\":[],\"d\":[],\"e\":null,\"f\":[],\"g\":null,\"h\":null,\"i\":null,\"j\":null,\"k\":[]}}}"; - - var actual = JsonSerializer.Deserialize(json, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); - - // Assert - Assert.NotNull(actual); - Assert.NotNull(actual.Child); - Assert.Equal(1, actual.Child.Count); - Assert.True(actual.Child.ContainsKey("1")); - Assert.Equal("1", actual.Child["1"].A); - } - - // https://github.com/dotnet/runtime/issues/29893 - [Fact] - public static void ShouldHandleNullInDictionaries_Serialize() - { - var value = new ClassWithDictionaryOfString_ChildWithDictionaryOfString() - { - Test = "value1", - Child = new ClassWithDictionaryOfString() - }; - - var actual = JsonSerializer.Serialize(value); - Assert.Equal("{\"Test\":\"value1\",\"Dict\":null,\"Child\":{\"Test\":null,\"Dict\":null}}", actual); - } - - // https://github.com/dotnet/runtime/issues/29893 - [Fact] - public static void ShouldHandleNullInDictionaries_Deserialize() - { - var json = "{\"Test\":\"value1\",\"Dict\":null,\"Child\":{\"Test\":null,\"Dict\":null}}"; - ClassWithDictionaryOfString_ChildWithDictionaryOfString actual = JsonSerializer.Deserialize(json); - - Assert.Equal("value1", actual.Test); - Assert.Null(actual.Dict); - Assert.NotNull(actual.Child); - Assert.Null(actual.Child.Dict); - Assert.Null(actual.Child.Test); - } - - // https://github.com/dotnet/runtime/issues/29893 - [Fact] - public static void ShouldHandleNullInDictionaries_Serialize_IgnoreNullValues() - { - var value = new ClassWithDictionaryOfString_ChildWithDictionaryOfString() - { - Test = "value1", - Child = new ClassWithDictionaryOfString() - }; - - var actual = JsonSerializer.Serialize(value, new JsonSerializerOptions { IgnoreNullValues = true }); - Assert.Equal("{\"Test\":\"value1\",\"Child\":{}}", actual); - } - - // https://github.com/dotnet/runtime/issues/29893 - [Fact] - public static void ShouldHandleNullInDictionaries_Deserialize_IgnoreNullValues() - { - var json = "{\"Test\":\"value1\",\"Child\":{}}"; - ClassWithDictionaryOfString_ChildWithDictionaryOfString actual = JsonSerializer.Deserialize(json); - - Assert.Equal("value1", actual.Test); - Assert.Null(actual.Dict); - Assert.NotNull(actual.Child); - Assert.Null(actual.Child.Dict); - Assert.Null(actual.Child.Test); - } - - // https://github.com/dotnet/runtime/issues/29888 - [Fact] - public static void DictionaryWithNullShouldPreserveOrder_Serialize() - { - var dictionaryFirst = new ClassWithDictionaryAndProperty_DictionaryFirst() - { - Test = "value1" - }; - - var actual = JsonSerializer.Serialize(dictionaryFirst); - Assert.Equal("{\"Dict\":null,\"Test\":\"value1\"}", actual); - - var dictionaryLast = new ClassWithDictionaryAndProperty_DictionaryLast() - { - Test = "value1" - }; - - actual = JsonSerializer.Serialize(dictionaryLast); - Assert.Equal("{\"Test\":\"value1\",\"Dict\":null}", actual); - } - - // https://github.com/dotnet/runtime/issues/29888 - [Fact] - public static void DictionaryWithNullShouldPreserveOrder_Deserialize() - { - var json = "{\"Dict\":null,\"Test\":\"value1\"}"; - ClassWithDictionaryAndProperty_DictionaryFirst dictionaryFirst = JsonSerializer.Deserialize(json); - - Assert.Equal("value1", dictionaryFirst.Test); - Assert.Null(dictionaryFirst.Dict); - - json = "{\"Test\":\"value1\",\"Dict\":null}"; - ClassWithDictionaryAndProperty_DictionaryLast dictionaryLast = JsonSerializer.Deserialize(json); - - Assert.Equal("value1", dictionaryLast.Test); - Assert.Null(dictionaryLast.Dict); - } - - // https://github.com/dotnet/runtime/issues/29888 - [Fact] - public static void DictionaryWithNullShouldPreserveOrder_Serialize_IgnoreNullValues() - { - var dictionaryFirst = new ClassWithDictionaryAndProperty_DictionaryFirst() - { - Test = "value1" - }; - - var actual = JsonSerializer.Serialize(dictionaryFirst, new JsonSerializerOptions { IgnoreNullValues = true }); - Assert.Equal("{\"Test\":\"value1\"}", actual); - - var dictionaryLast = new ClassWithDictionaryAndProperty_DictionaryLast() - { - Test = "value1" - }; - - actual = JsonSerializer.Serialize(dictionaryLast, new JsonSerializerOptions { IgnoreNullValues = true }); - Assert.Equal("{\"Test\":\"value1\"}", actual); - } - - // https://github.com/dotnet/runtime/issues/29888 - [Fact] - public static void DictionaryWithNullShouldPreserveOrder_Deserialize_IgnoreNullValues() - { - var json = "{\"Test\":\"value1\"}"; - ClassWithDictionaryAndProperty_DictionaryFirst dictionaryFirst = JsonSerializer.Deserialize(json); - - Assert.Equal("value1", dictionaryFirst.Test); - Assert.Null(dictionaryFirst.Dict); - - json = "{\"Test\":\"value1\"}"; - ClassWithDictionaryAndProperty_DictionaryLast dictionaryLast = JsonSerializer.Deserialize(json); - - Assert.Equal("value1", dictionaryLast.Test); - Assert.Null(dictionaryLast.Dict); - } - - [Fact] - public static void NullDictionaryValuesShouldDeserializeAsNull() - { - const string json = - @"{" + - @"""StringVals"":{" + - @"""key"":null" + - @"}," + - @"""ObjectVals"":{" + - @"""key"":null" + - @"}," + - @"""StringDictVals"":{" + - @"""key"":null" + - @"}," + - @"""ObjectDictVals"":{" + - @"""key"":null" + - @"}," + - @"""ClassVals"":{" + - @"""key"":null" + - @"}" + - @"}"; - - SimpleClassWithDictionaries obj = JsonSerializer.Deserialize(json); - Assert.Null(obj.StringVals["key"]); - Assert.Null(obj.ObjectVals["key"]); - Assert.Null(obj.StringDictVals["key"]); - Assert.Null(obj.ObjectDictVals["key"]); - Assert.Null(obj.ClassVals["key"]); - } - - public class ClassWithNotSupportedDictionary - { - public Dictionary MyDictionary { get; set; } - } - - public class ClassWithNotSupportedDictionaryButIgnored - { - [JsonIgnore] public Dictionary MyDictionary { get; set; } - } - - public class AllSingleUpperPropertiesParent - { - public IDictionary Child { get; set; } - } - - public class AllSingleUpperProperties_Child - { - public string A { get; set; } - public string B { get; set; } - public string[] C { get; set; } - public string[] D { get; set; } - public bool? E { get; set; } - public string[] F { get; set; } - public DateTimeOffset? G { get; set; } - public DateTimeOffset? H { get; set; } - public int? I { get; set; } - public int? J { get; set; } - public string[] K { get; set; } - } - - public class ClassWithDictionaryOfString_ChildWithDictionaryOfString - { - public string Test { get; set; } - public Dictionary Dict { get; set; } - public ClassWithDictionaryOfString Child { get; set; } - } - - public class ClassWithDictionaryOfString - { - public string Test { get; set; } - public Dictionary Dict { get; set; } - } - - public class ClassWithDictionaryAndProperty_DictionaryLast - { - public string Test { get; set; } - public Dictionary Dict { get; set; } - } - - public class ClassWithDictionaryAndProperty_DictionaryFirst - { - public Dictionary Dict { get; set; } - public string Test { get; set; } - } - - public class SimpleClassWithDictionaries - { - public Dictionary StringVals { get; set; } - public Dictionary ObjectVals { get; set; } - public Dictionary> StringDictVals { get; set; } - public Dictionary> ObjectDictVals { get; set; } - public Dictionary ClassVals { get; set; } - } - - public class DictionaryThatOnlyImplementsIDictionaryOfStringTValue : IDictionary - { - IDictionary _inner = new Dictionary(); - - public TValue this[string key] - { - get - { - return _inner[key]; - } - set - { - _inner[key] = value; - } - } - - public ICollection Keys => _inner.Keys; - - public ICollection Values => _inner.Values; - - public int Count => _inner.Count; - - public bool IsReadOnly => _inner.IsReadOnly; - - public void Add(string key, TValue value) - { - _inner.Add(key, value); - } - - public void Add(KeyValuePair item) - { - _inner.Add(item); - } - - public void Clear() - { - throw new NotImplementedException(); - } - - public bool Contains(KeyValuePair item) - { - return _inner.Contains(item); - } - - public bool ContainsKey(string key) - { - return _inner.ContainsKey(key); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - // CopyTo should not be called. - throw new NotImplementedException(); - } - - public IEnumerator> GetEnumerator() - { - // Don't return results directly from _inner since that will return an enumerator that returns - // IDictionaryEnumerator which should not require. - foreach (KeyValuePair keyValuePair in _inner) - { - yield return keyValuePair; - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - // This GetEnumerator() should not be called. - throw new NotImplementedException(); - } - - public bool Remove(string key) - { - // Remove should not be called. - throw new NotImplementedException(); - } - - public bool Remove(KeyValuePair item) - { - // Remove should not be called. - throw new NotImplementedException(); - } - - public bool TryGetValue(string key, out TValue value) - { - return _inner.TryGetValue(key, out value); - } - } - - [Fact] - public static void DictionaryOfTOnlyWithStringTValueAsInt() - { - const string Json = @"{""One"":1,""Two"":2}"; - - DictionaryThatOnlyImplementsIDictionaryOfStringTValue dictionary; - - dictionary = JsonSerializer.Deserialize>(Json); - Assert.Equal(1, dictionary["One"]); - Assert.Equal(2, dictionary["Two"]); - - string json = JsonSerializer.Serialize(dictionary); - Assert.Equal(Json, json); - } - - [Fact] - public static void DictionaryOfTOnlyWithStringTValueAsPoco() - { - const string Json = @"{""One"":{""Id"":1},""Two"":{""Id"":2}}"; - - DictionaryThatOnlyImplementsIDictionaryOfStringTValue dictionary; - - dictionary = JsonSerializer.Deserialize>(Json); - Assert.Equal(1, dictionary["One"].Id); - Assert.Equal(2, dictionary["Two"].Id); - - string json = JsonSerializer.Serialize(dictionary); - Assert.Equal(Json, json); - } - - public class DictionaryThatOnlyImplementsIDictionaryOfStringPoco : DictionaryThatOnlyImplementsIDictionaryOfStringTValue - { - } - - [Fact] - public static void DictionaryOfTOnlyWithStringPoco() - { - const string Json = @"{""One"":{""Id"":1},""Two"":{""Id"":2}}"; - - DictionaryThatOnlyImplementsIDictionaryOfStringPoco dictionary; - - dictionary = JsonSerializer.Deserialize(Json); - Assert.Equal(1, dictionary["One"].Id); - Assert.Equal(2, dictionary["Two"].Id); - - string json = JsonSerializer.Serialize(dictionary); - Assert.Equal(Json, json); - } - - public class DictionaryThatHasIncompatibleEnumerator : IDictionary - { - Hashtable _inner = new Hashtable(); - - public object this[string key] - { - get - { - return _inner[key]; - } - set - { - _inner[key] = value; - } - } - - public ICollection Keys => _inner.Keys; - - public ICollection Values => _inner.Values; - - public int Count => _inner.Count; - - public bool IsReadOnly => _inner.IsReadOnly; - - public bool IsFixedSize => _inner.IsFixedSize; - - public bool IsSynchronized => throw new NotImplementedException(); - - public object SyncRoot => throw new NotImplementedException(); - - public object this[object key] - { - get - { - return _inner[key]; - } - set - { - _inner[key] = value; - } - } - - public void Add(object key, object value) - { - _inner.Add(key, value); - } - - public void Clear() - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - public bool Contains(object key) - { - throw new NotImplementedException(); - } - - public IDictionaryEnumerator GetEnumerator() - { - // Throw NotSupportedException so we can detect this GetEnumerator was called. - throw new NotSupportedException(); - } - - public void Remove(object key) - { - throw new NotImplementedException(); - } - - public void CopyTo(Array array, int index) - { - throw new NotImplementedException(); - } - } - - [Fact] - public static void VerifyDictionaryThatHasIncomatibleEnumeratorWithInt() - { - const string Json = @"{""One"":1,""Two"":2}"; - - DictionaryThatHasIncompatibleEnumerator dictionary; - dictionary = JsonSerializer.Deserialize(Json); - Assert.Equal(1, ((JsonElement)dictionary["One"]).GetInt32()); - Assert.Equal(2, ((JsonElement)dictionary["Two"]).GetInt32()); - Assert.Throws(() => JsonSerializer.Serialize(dictionary)); - } - - [Fact] - public static void VerifyDictionaryThatHasIncomatibleEnumeratorWithPoco() - { - const string Json = @"{""One"":{""Id"":1},""Two"":{""Id"":2}}"; - - DictionaryThatHasIncompatibleEnumerator dictionary; - dictionary = JsonSerializer.Deserialize(Json); - Assert.Equal(1, ((JsonElement)dictionary["One"]).GetProperty("Id").GetInt32()); - Assert.Equal(2, ((JsonElement)dictionary["Two"]).GetProperty("Id").GetInt32()); - Assert.Throws(() => JsonSerializer.Serialize(dictionary)); - } - - - [Fact] - public static void VerifyIDictionaryWithNonStringKey() - { - IDictionary dictionary = new Hashtable(); - dictionary.Add(1, "value"); - Assert.Throws(() => JsonSerializer.Serialize(dictionary)); - } - - private class ClassWithoutParameterlessCtor - { - public ClassWithoutParameterlessCtor(int num) { } - public string Name { get; set; } - } - - private class ClassWithInternalParameterlessConstructor - { - internal ClassWithInternalParameterlessConstructor() { } - public string Name { get; set; } - } - - private class ClassWithPrivateParameterlessConstructor - { - private ClassWithPrivateParameterlessConstructor() { } - public string Name { get; set; } - } - - [Fact] - public static void DictionaryWith_ObjectWithNoParameterlessCtor_AsValue_Throws() - { - Assert.Throws(() => JsonSerializer.Deserialize>(@"{""key"":{}}")); - Assert.Throws(() => JsonSerializer.Deserialize>(@"{""key"":{}}")); - } - - [Fact] - public static void DictionaryWith_ObjectWithNoParameterlessCtor_Serialize_Works() - { - var noParameterless = new Dictionary() - { - ["key"] = new ClassWithoutParameterlessCtor(5) - { - Name = "parameterless" - } - }; - - string json = JsonSerializer.Serialize(noParameterless); - Assert.Equal("{\"key\":{\"Name\":\"parameterless\"}}", json); - - var onlyInternal = new Dictionary() - { - ["key"] = new ClassWithInternalParameterlessConstructor() - { - Name = "internal" - } - }; - - json = JsonSerializer.Serialize(onlyInternal); - Assert.Equal("{\"key\":{\"Name\":\"internal\"}}", json); - - var onlyPrivate = new Dictionary() - { - ["key"] = null - }; - - json = JsonSerializer.Serialize(onlyPrivate); - Assert.Equal("{\"key\":null}", json); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/ExtensionDataTests.cs b/src/libraries/System.Text.Json/tests/Serialization/ExtensionDataTests.cs index a43c7069933df0..8c95c471e509e4 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/ExtensionDataTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/ExtensionDataTests.cs @@ -2,11 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Linq; +using System.Reflection; using Xunit; namespace System.Text.Json.Serialization.Tests @@ -57,7 +56,7 @@ void Verify() } [Fact] - public static void ExtensionPropertyIgnoredWhenNull() + public static void ExtensionPropertyIgnoredWhenWritingDefault() { string expected = @"{}"; string actual = JsonSerializer.Serialize(new ClassWithExtensionPropertyAsObject()); @@ -65,7 +64,7 @@ public static void ExtensionPropertyIgnoredWhenNull() } [Fact] - public static void MultipleExtensionPropertyIgnoredWhenNull() + public static void MultipleExtensionPropertyIgnoredWhenWritingDefault() { var obj = new ClassWithMultipleDictionaries(); string actual = JsonSerializer.Serialize(obj); @@ -100,6 +99,18 @@ public static void MultipleExtensionPropertyIgnoredWhenNull() Assert.Equal("{\"ActualDictionary\":{},\"test\":\"value\"}", actual); } + [Fact] + public static void ExtensionPropertyInvalidJsonFail() + { + const string BadJson = @"{""Good"":""OK"",""Bad"":!}"; + + JsonException jsonException = Assert.Throws(() => JsonSerializer.Deserialize(BadJson)); + Assert.Contains("Path: $.Bad | LineNumber: 0 | BytePositionInLine: 19.", jsonException.ToString()); + Assert.NotNull(jsonException.InnerException); + Assert.IsAssignableFrom(jsonException.InnerException); + Assert.Contains("!", jsonException.InnerException.ToString()); + } + [Fact] public static void ExtensionPropertyAlreadyInstantiated() { @@ -250,6 +261,205 @@ public static void IgnoredDataShouldNotBeExtensionData() Assert.Null(obj.MyOverflow); } + private class ClassWithExtensionData + { + [JsonExtensionData] + public T Overflow { get; set; } + } + + public class CustomOverflowDictionary : Dictionary + { + } + + public class DictionaryOverflowConverter : JsonConverter> + { + public override Dictionary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + + public override void Write(Utf8JsonWriter writer, Dictionary value, JsonSerializerOptions options) + { + writer.WriteString("MyCustomOverflowWrite", "OverflowValueWrite"); + } + } + + public class JsonElementOverflowConverter : JsonConverter> + { + public override Dictionary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + + public override void Write(Utf8JsonWriter writer, Dictionary value, JsonSerializerOptions options) + { + writer.WriteString("MyCustomOverflowWrite", "OverflowValueWrite"); + } + } + + public class CustomObjectDictionaryOverflowConverter : JsonConverter> + { + public override CustomOverflowDictionary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + + public override void Write(Utf8JsonWriter writer, CustomOverflowDictionary value, JsonSerializerOptions options) + { + writer.WriteString("MyCustomOverflowWrite", "OverflowValueWrite"); + } + } + + public class CustomJsonElementDictionaryOverflowConverter : JsonConverter> + { + public override CustomOverflowDictionary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + + public override void Write(Utf8JsonWriter writer, CustomOverflowDictionary value, JsonSerializerOptions options) + { + writer.WriteString("MyCustomOverflowWrite", "OverflowValueWrite"); + } + } + + [Theory] + [InlineData(typeof(Dictionary), typeof(DictionaryOverflowConverter))] + [InlineData(typeof(Dictionary), typeof(JsonElementOverflowConverter))] + [InlineData(typeof(CustomOverflowDictionary), typeof(CustomObjectDictionaryOverflowConverter))] + [InlineData(typeof(CustomOverflowDictionary), typeof(CustomJsonElementDictionaryOverflowConverter))] + public static void ExtensionProperty_SupportsWritingToCustomSerializerWithOptions(Type overflowType, Type converterType) + { + typeof(ExtensionDataTests) + .GetMethod(nameof(ExtensionProperty_SupportsWritingToCustomSerializerWithOptionsInternal), BindingFlags.Static | BindingFlags.NonPublic) + .MakeGenericMethod(overflowType, converterType) + .Invoke(null, null); + } + + private static void ExtensionProperty_SupportsWritingToCustomSerializerWithOptionsInternal() + where TDictionary : new() + where TConverter : JsonConverter, new() + { + var root = new ClassWithExtensionData() + { + Overflow = new TDictionary() + }; + + var options = new JsonSerializerOptions(); + options.Converters.Add(new TConverter()); + + string json = JsonSerializer.Serialize(root, options); + Assert.Equal(@"{""MyCustomOverflowWrite"":""OverflowValueWrite""}", json); + } + + private interface IClassWithOverflow + { + public T Overflow { get; set; } + } + + private class ClassWithExtensionDataWithAttributedConverter : IClassWithOverflow> + { + [JsonExtensionData] + [JsonConverter(typeof(DictionaryOverflowConverter))] + public Dictionary Overflow { get; set; } + } + + private class ClassWithJsonElementExtensionDataWithAttributedConverter : IClassWithOverflow> + { + [JsonExtensionData] + [JsonConverter(typeof(JsonElementOverflowConverter))] + public Dictionary Overflow { get; set; } + } + + private class ClassWithCustomElementExtensionDataWithAttributedConverter : IClassWithOverflow> + { + [JsonExtensionData] + [JsonConverter(typeof(CustomObjectDictionaryOverflowConverter))] + public CustomOverflowDictionary Overflow { get; set; } + } + + private class ClassWithCustomJsonElementExtensionDataWithAttributedConverter : IClassWithOverflow> + { + [JsonExtensionData] + [JsonConverter(typeof(CustomJsonElementDictionaryOverflowConverter))] + public CustomOverflowDictionary Overflow { get; set; } + } + + [Theory] + [InlineData(typeof(ClassWithExtensionDataWithAttributedConverter), typeof(Dictionary))] + [InlineData(typeof(ClassWithJsonElementExtensionDataWithAttributedConverter), typeof(Dictionary))] + [InlineData(typeof(ClassWithCustomElementExtensionDataWithAttributedConverter), typeof(CustomOverflowDictionary))] + [InlineData(typeof(ClassWithCustomJsonElementExtensionDataWithAttributedConverter), typeof(CustomOverflowDictionary))] + public static void ExtensionProperty_SupportsWritingToCustomSerializerWithExplicitConverter(Type attributedType, Type dictionaryType) + { + typeof(ExtensionDataTests) + .GetMethod(nameof(ExtensionProperty_SupportsWritingToCustomSerializerWithExplicitConverterInternal), BindingFlags.Static | BindingFlags.NonPublic) + .MakeGenericMethod(attributedType, dictionaryType) + .Invoke(null, null); + } + + private static void ExtensionProperty_SupportsWritingToCustomSerializerWithExplicitConverterInternal() + where TRoot : IClassWithOverflow, new() + where TDictionary : new() + { + var root = new TRoot() + { + Overflow = new TDictionary() + }; + + string json = JsonSerializer.Serialize(root); + Assert.Equal(@"{""MyCustomOverflowWrite"":""OverflowValueWrite""}", json); + } + + [Theory] + [InlineData(typeof(Dictionary), typeof(DictionaryOverflowConverter), typeof(object))] + [InlineData(typeof(Dictionary), typeof(JsonElementOverflowConverter), typeof(JsonElement))] + [InlineData(typeof(CustomOverflowDictionary), typeof(CustomObjectDictionaryOverflowConverter), typeof(object))] + [InlineData(typeof(CustomOverflowDictionary), typeof(CustomJsonElementDictionaryOverflowConverter), typeof(JsonElement))] + public static void ExtensionProperty_IgnoresCustomSerializerWithOptions(Type overflowType, Type converterType, Type elementType) + { + typeof(ExtensionDataTests) + .GetMethod(nameof(ExtensionProperty_IgnoresCustomSerializerWithOptionsInternal), BindingFlags.Static | BindingFlags.NonPublic) + .MakeGenericMethod(overflowType, elementType, converterType) + .Invoke(null, null); + } + + private static void ExtensionProperty_IgnoresCustomSerializerWithOptionsInternal() + where TConverter : JsonConverter, new() + where TDictionary : IDictionary + { + var options = new JsonSerializerOptions(); + options.Converters.Add(new TConverter()); + + ClassWithExtensionData obj + = JsonSerializer.Deserialize>(@"{""TestKey"":""TestValue""}", options); + + Assert.Equal("TestValue", ((JsonElement)(object)obj.Overflow["TestKey"]).GetString()); + } + + [Theory] + [InlineData(typeof(ClassWithExtensionDataWithAttributedConverter), typeof(Dictionary), typeof(object))] + [InlineData(typeof(ClassWithJsonElementExtensionDataWithAttributedConverter), typeof(Dictionary), typeof(JsonElement))] + [InlineData(typeof(ClassWithCustomElementExtensionDataWithAttributedConverter), typeof(CustomOverflowDictionary), typeof(object))] + [InlineData(typeof(ClassWithCustomJsonElementExtensionDataWithAttributedConverter), typeof(CustomOverflowDictionary), typeof(JsonElement))] + public static void ExtensionProperty_IgnoresCustomSerializerWithExplicitConverter(Type attributedType, Type dictionaryType, Type elementType) + { + typeof(ExtensionDataTests) + .GetMethod(nameof(ExtensionProperty_IgnoresCustomSerializerWithExplicitConverterInternal), BindingFlags.Static | BindingFlags.NonPublic) + .MakeGenericMethod(attributedType, dictionaryType, elementType) + .Invoke(null, null); + } + + private static void ExtensionProperty_IgnoresCustomSerializerWithExplicitConverterInternal() + where TRoot : IClassWithOverflow, new() + where TDictionary : IDictionary + { + ClassWithExtensionData obj + = JsonSerializer.Deserialize>(@"{""TestKey"":""TestValue""}"); + + Assert.Equal("TestValue", ((JsonElement)(object)obj.Overflow["TestKey"]).GetString()); + } + [Fact] public static void ExtensionPropertyObjectValue_Empty() { diff --git a/src/libraries/System.Text.Json/tests/Serialization/InvalidTypeTests.cs b/src/libraries/System.Text.Json/tests/Serialization/InvalidTypeTests.cs new file mode 100644 index 00000000000000..edad8a0dc0614e --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/InvalidTypeTests.cs @@ -0,0 +1,167 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public class InvalidTypeTests_Span : InvalidTypeTests + { + public InvalidTypeTests_Span() : base(SerializationWrapper.SpanSerializer) { } + } + + public class InvalidTypeTests_String : InvalidTypeTests + { + public InvalidTypeTests_String() : base(SerializationWrapper.StringSerializer) { } + } + + public class InvalidTypeTests_Stream : InvalidTypeTests + { + public InvalidTypeTests_Stream() : base(SerializationWrapper.StreamSerializer) { } + } + + public class InvalidTypeTests_StreamWithSmallBuffer : InvalidTypeTests + { + public InvalidTypeTests_StreamWithSmallBuffer() : base(SerializationWrapper.StreamSerializerWithSmallBuffer) { } + } + + public class InvalidTypeTests_Writer : InvalidTypeTests + { + public InvalidTypeTests_Writer() : base(SerializationWrapper.WriterSerializer) { } + } + + public abstract class InvalidTypeTests + { + private SerializationWrapper Serializer { get; } + + public InvalidTypeTests(SerializationWrapper serializer) + { + Serializer = serializer; + } + + [Theory] + [MemberData(nameof(OpenGenericTypes))] + [MemberData(nameof(RefStructTypes))] + [MemberData(nameof(PointerTypes))] + public void DeserializeInvalidType(Type type) + { + InvalidOperationException ex = Assert.Throws(() => JsonSerializer.Deserialize("", type)); + Assert.Contains(type.ToString(), ex.ToString()); + } + + [Theory] + [MemberData(nameof(TypesWithInvalidMembers_WithMembers))] + public void TypeWithInvalidMember(Type classType, Type invalidMemberType, string invalidMemberName) + { + static void ValidateException(InvalidOperationException ex, Type classType, Type invalidMemberType, string invalidMemberName) + { + string exAsStr = ex.ToString(); + Assert.Contains(invalidMemberType.ToString(), exAsStr); + Assert.Contains(invalidMemberName, exAsStr); + Assert.Contains(classType.ToString(), exAsStr); + } + + object obj = Activator.CreateInstance(classType); + InvalidOperationException ex = Assert.Throws(() => Serializer.Serialize(obj, classType)); + ValidateException(ex, classType, invalidMemberType, invalidMemberName); + + ex = Assert.Throws(() => Serializer.Serialize(null, classType)); + ValidateException(ex, classType, invalidMemberType, invalidMemberName); + + ex = Assert.Throws(() => JsonSerializer.Deserialize("", classType)); + ValidateException(ex, classType, invalidMemberType, invalidMemberName); + } + + [Theory] + [MemberData(nameof(OpenGenericTypes_ToSerialize))] + public void SerializeOpenGeneric(Type type) + { + object obj; + + if (type.GetGenericArguments().Length == 1) + { + obj = Activator.CreateInstance(type.MakeGenericType(typeof(int))); + } + else + { + obj = Activator.CreateInstance(type.MakeGenericType(typeof(string), typeof(int))); + } + + Assert.Throws(() => Serializer.Serialize(obj, type)); + } + + [Theory] + [MemberData(nameof(OpenGenericTypes))] + public void SerializeInvalidTypes_NullValue(Type type) + { + InvalidOperationException ex = Assert.Throws(() => Serializer.Serialize(null, type)); + Assert.Contains(type.ToString(), ex.ToString()); + } + + [Fact] + public void SerializeOpenGeneric_NullableOfT() + { + Type openNullableType = typeof(Nullable<>); + object obj = Activator.CreateInstance(openNullableType.MakeGenericType(typeof(int))); + + InvalidOperationException ex = Assert.Throws(() => Serializer.Serialize(obj, openNullableType)); + Assert.Contains(openNullableType.ToString(), ex.ToString()); + } + + private class Test { } + + private static IEnumerable OpenGenericTypes() + { + yield return new object[] { typeof(Test<>) }; + yield return new object[] { typeof(Nullable<>) }; + yield return new object[] { typeof(IList<>) }; + yield return new object[] { typeof(List<>) }; + yield return new object[] { typeof(List<>).MakeGenericType(typeof(Test<>)) }; + yield return new object[] { typeof(Test<>).MakeGenericType(typeof(List<>)) }; + yield return new object[] { typeof(Dictionary<,>) }; + yield return new object[] { typeof(Dictionary<,>).MakeGenericType(typeof(string), typeof(Nullable<>)) }; + yield return new object[] { typeof(Dictionary<,>).MakeGenericType(typeof(Nullable<>), typeof(string)) }; + } + + private static IEnumerable OpenGenericTypes_ToSerialize() + { + yield return new object[] { typeof(Test<>) }; + yield return new object[] { typeof(List<>) }; + yield return new object[] { typeof(Dictionary<,>) }; + } + + private static IEnumerable RefStructTypes() + { + yield return new object[] { typeof(Span) }; + yield return new object[] { typeof(Utf8JsonReader) }; + yield return new object[] { typeof(MyRefStruct) }; + } + + private static readonly Type s_intPtrType = typeof(int*); // Unsafe code may not appear in iterators. + + private static IEnumerable PointerTypes() + { + yield return new object[] { s_intPtrType }; + } + + // Instances of the types of the invalid members cannot be passed directly + // to the serializer on serialization due to type constraints, + // e.g. int* can't be boxed and passed to the non-generic overload, + // and typeof(int*) can't be a generic parameter to the generic overload. + private static IEnumerable TypesWithInvalidMembers_WithMembers() + { + yield return new object[] { typeof(Memory), typeof(Span), "Span" }; // Contains Span property. + + yield return new object[] { typeof(ClassWithIntPtr), s_intPtrType, "IntPtr" }; + } + + private class ClassWithIntPtr + { + public unsafe int* IntPtr { get; } + } + + private ref struct MyRefStruct { } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/Null.ReadTests.cs b/src/libraries/System.Text.Json/tests/Serialization/Null.ReadTests.cs index 84b81684781a91..682ef427237c24 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/Null.ReadTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/Null.ReadTests.cs @@ -3,11 +3,9 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using Newtonsoft.Json; -using Xunit; -using Xunit.Sdk; using System.Threading.Tasks; using System.IO; +using Xunit; namespace System.Text.Json.Serialization.Tests { diff --git a/src/libraries/System.Text.Json/tests/Serialization/Null.WriteTests.cs b/src/libraries/System.Text.Json/tests/Serialization/Null.WriteTests.cs index f85564a212c1c9..530a8edb4ed452 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/Null.WriteTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/Null.WriteTests.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using Xunit; namespace System.Text.Json.Serialization.Tests diff --git a/src/libraries/System.Text.Json/tests/Serialization/OpenGenericTests.cs b/src/libraries/System.Text.Json/tests/Serialization/OpenGenericTests.cs deleted file mode 100644 index 15351f75014239..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/OpenGenericTests.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public class OpenGenericTests_Span : OpenGenericTests - { - public OpenGenericTests_Span() : base(SerializationWrapper.SpanSerializer) { } - } - - public class OpenGenericTests_String : OpenGenericTests - { - public OpenGenericTests_String() : base(SerializationWrapper.StringSerializer) { } - } - - public class OpenGenericTests_Stream : OpenGenericTests - { - public OpenGenericTests_Stream() : base(SerializationWrapper.StreamSerializer) { } - } - - public class OpenGenericTests_StreamWithSmallBuffer : OpenGenericTests - { - public OpenGenericTests_StreamWithSmallBuffer() : base(SerializationWrapper.StreamSerializerWithSmallBuffer) { } - } - - public class OpenGenericTests_Writer : OpenGenericTests - { - public OpenGenericTests_Writer() : base(SerializationWrapper.WriterSerializer) { } - } - - public abstract class OpenGenericTests - { - private SerializationWrapper Serializer { get; } - - public OpenGenericTests(SerializationWrapper serializer) - { - Serializer = serializer; - } - - [Theory] - [MemberData(nameof(TypesWithOpenGenerics))] - public void DeserializeOpenGeneric(Type type) - { - InvalidOperationException ex = Assert.Throws(() => JsonSerializer.Deserialize("", type)); - Assert.Contains(type.ToString(), ex.ToString()); - } - - [Theory] - [MemberData(nameof(TypesWithOpenGenerics_ToSerialize))] - public void SerializeOpenGeneric(Type type) - { - object obj; - - if (type.GetGenericArguments().Length == 1) - { - obj = Activator.CreateInstance(type.MakeGenericType(typeof(int))); - } - else - { - obj = Activator.CreateInstance(type.MakeGenericType(typeof(string), typeof(int))); - } - - Assert.Throws(() => Serializer.Serialize(obj, type)); - } - - [Theory] - [MemberData(nameof(TypesWithOpenGenerics))] - public void SerializeOpenGeneric_NullValue(Type type) - { - InvalidOperationException ex = Assert.Throws(() => Serializer.Serialize(null, type)); - Assert.Contains(type.ToString(), ex.ToString()); - } - - [Fact] - public void SerializeOpenGeneric_NullableOfT() - { - Type openNullableType = typeof(Nullable<>); - object obj = Activator.CreateInstance(openNullableType.MakeGenericType(typeof(int))); - - InvalidOperationException ex = Assert.Throws(() => Serializer.Serialize(obj, openNullableType)); - Assert.Contains(openNullableType.ToString(), ex.ToString()); - } - - private class Test { } - - private static IEnumerable TypesWithOpenGenerics() - { - yield return new object[] { typeof(Test<>) }; - yield return new object[] { typeof(Nullable<>) }; - yield return new object[] { typeof(List<>) }; - yield return new object[] { typeof(List<>).MakeGenericType(typeof(Test<>)) }; - yield return new object[] { typeof(Test<>).MakeGenericType(typeof(List<>)) }; - yield return new object[] { typeof(Dictionary<,>) }; - yield return new object[] { typeof(Dictionary<,>).MakeGenericType(typeof(string), typeof(Nullable<>)) }; - yield return new object[] { typeof(Dictionary<,>).MakeGenericType(typeof(Nullable<>), typeof(string)) }; - } - - private static IEnumerable TypesWithOpenGenerics_ToSerialize() - { - yield return new object[] { typeof(Test<>) }; - yield return new object[] { typeof(List<>) }; - yield return new object[] { typeof(Dictionary<,>) }; - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/OptionsTests.cs b/src/libraries/System.Text.Json/tests/Serialization/OptionsTests.cs index aedd10bf6b876d..c4fe9c48bb7571 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/OptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/OptionsTests.cs @@ -340,7 +340,7 @@ private static void GenericObjectOrJsonElementConverterTestHelper(string conv JsonConverter converter = (JsonConverter)options.GetConverter(typeof(T)); Assert.Equal(converterName, converter.GetType().Name); - + ReadOnlySpan data = Encoding.UTF8.GetBytes(stringValue); Utf8JsonReader reader = new Utf8JsonReader(data); reader.Read(); @@ -406,7 +406,6 @@ public static void Options_GetConverter_GivesCorrectDefaultConverterAndReadWrite GenericConverterTestHelper("GuidConverter", testGuid, $"\"{testGuid.ToString()}\"", options); GenericConverterTestHelper>("KeyValuePairConverter`2", new KeyValuePair("key", "value"), @"{""Key"":""key"",""Value"":""value""}", options); GenericConverterTestHelper("UriConverter", new Uri("http://test.com"), "\"http://test.com\"", options); - } [Fact] @@ -452,35 +451,9 @@ private static void GenericConverterTestHelper(string converterName, object o } [Fact] - public static void CopyConstructorTest_OriginalMutable() + public static void CopyConstructor_OriginalLocked() { - JsonSerializerOptions options = CreateOptionsInstance(); - var newOptions = new JsonSerializerOptions(options); - VerifyOptionsEqual(options, newOptions); - - // No exception is thrown on mutating the new options instance because it is "unlocked". - newOptions.ReferenceHandling = ReferenceHandling.Preserve; - newOptions.Converters.Add(new JsonStringEnumConverter()); - newOptions.Converters.Add(new JsonStringEnumConverter()); - - // Changes to new options don't affect old options. - Assert.Equal(ReferenceHandling.Default, options.ReferenceHandling); - Assert.Equal(2, options.Converters.Count); - Assert.Equal(4, newOptions.Converters.Count); - - // Changes to old options don't affect new options. - options.DefaultBufferSize = 2; - options.Converters.Add(new ConverterForInt32()); - - Assert.Equal(20, newOptions.DefaultBufferSize); - Assert.Equal(3, options.Converters.Count); - Assert.Equal(4, newOptions.Converters.Count); - } - - [Fact] - public static void CopyConstructorTest_OriginalLocked() - { - JsonSerializerOptions options = CreateOptionsInstance(); + JsonSerializerOptions options = new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; // Perform serialization with options, after which it will be locked. JsonSerializer.Serialize("1", options); @@ -494,7 +467,7 @@ public static void CopyConstructorTest_OriginalLocked() } [Fact] - public static void CopyConstructorTest_MaxDepth() + public static void CopyConstructor_MaxDepth() { static void RunTest(int maxDepth, int effectiveMaxDepth) { @@ -525,20 +498,46 @@ static void RunTest(int maxDepth, int effectiveMaxDepth) } [Fact] - public static void CopyConstructorTest_CopiesAllPublicProperties() + public static void CopyConstructor_CopiesAllPublicProperties() { JsonSerializerOptions options = GetFullyPopulatedOptionsInstance(); var newOptions = new JsonSerializerOptions(options); - VerifyOptionsEqual_WithReflection(options, newOptions); + VerifyOptionsEqual(options, newOptions); } [Fact] - public static void CopyConstructorTest_NullInput() + public static void CopyConstructor_NullInput() { ArgumentNullException ex = Assert.Throws(() => new JsonSerializerOptions(null)); Assert.Contains("options", ex.ToString()); } + [Fact] + public static void DefaultSerializerOptions_General() + { + var options = new JsonSerializerOptions(); + var newOptions = new JsonSerializerOptions(JsonSerializerDefaults.General); + VerifyOptionsEqual(options, newOptions); + } + + [Fact] + public static void PredefinedSerializerOptions_Web() + { + var options = new JsonSerializerOptions(JsonSerializerDefaults.Web); + JsonNamingPolicy policy = options.PropertyNamingPolicy; + Assert.True(options.PropertyNameCaseInsensitive); + Assert.Same(JsonNamingPolicy.CamelCase, policy); + } + + [Theory] + [InlineData(-1)] + [InlineData(2)] + public static void PredefinedSerializerOptions_UnhandledDefaults(int enumValue) + { + var outOfRangeSerializerDefaults = (JsonSerializerDefaults)enumValue; + Assert.Throws(() => new JsonSerializerOptions(outOfRangeSerializerDefaults)); + } + private static JsonSerializerOptions CreateOptionsInstance() { var options = new JsonSerializerOptions @@ -563,28 +562,6 @@ private static JsonSerializerOptions CreateOptionsInstance() return options; } - private static void VerifyOptionsEqual(JsonSerializerOptions options, JsonSerializerOptions newOptions) - { - Assert.Equal(options.AllowTrailingCommas, newOptions.AllowTrailingCommas); - Assert.Equal(options.DefaultBufferSize, newOptions.DefaultBufferSize); - Assert.Equal(options.IgnoreNullValues, newOptions.IgnoreNullValues); - Assert.Equal(options.IgnoreReadOnlyProperties, newOptions.IgnoreReadOnlyProperties); - Assert.Equal(options.MaxDepth, newOptions.MaxDepth); - Assert.Equal(options.PropertyNameCaseInsensitive, newOptions.PropertyNameCaseInsensitive); - Assert.Equal(options.ReadCommentHandling, newOptions.ReadCommentHandling); - Assert.Equal(options.WriteIndented, newOptions.WriteIndented); - - Assert.Same(options.DictionaryKeyPolicy, newOptions.DictionaryKeyPolicy); - Assert.Same(options.Encoder, newOptions.Encoder); - Assert.Same(options.PropertyNamingPolicy, newOptions.PropertyNamingPolicy); - - Assert.Equal(options.Converters.Count, newOptions.Converters.Count); - for (int i = 0; i < options.Converters.Count; i++) - { - Assert.Same(options.Converters[i], newOptions.Converters[i]); - } - } - private static JsonSerializerOptions GetFullyPopulatedOptionsInstance() { var options = new JsonSerializerOptions(); @@ -595,7 +572,11 @@ private static JsonSerializerOptions GetFullyPopulatedOptionsInstance() if (propertyType == typeof(bool)) { - property.SetValue(options, true); + // IgnoreNullValues and DefaultIgnoreCondition cannot be active at the same time. + if (property.Name != "IgnoreNullValues") + { + property.SetValue(options, true); + } } if (propertyType == typeof(int)) { @@ -622,6 +603,7 @@ private static JsonSerializerOptions GetFullyPopulatedOptionsInstance() else if (propertyType.IsValueType) { options.ReadCommentHandling = JsonCommentHandling.Disallow; + options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault; } else { @@ -634,7 +616,7 @@ private static JsonSerializerOptions GetFullyPopulatedOptionsInstance() return options; } - private static void VerifyOptionsEqual_WithReflection(JsonSerializerOptions options, JsonSerializerOptions newOptions) + private static void VerifyOptionsEqual(JsonSerializerOptions options, JsonSerializerOptions newOptions) { foreach (PropertyInfo property in typeof(JsonSerializerOptions).GetProperties()) { @@ -642,12 +624,10 @@ private static void VerifyOptionsEqual_WithReflection(JsonSerializerOptions opti if (propertyType == typeof(bool)) { - Assert.True((bool)property.GetValue(options)); Assert.Equal((bool)property.GetValue(options), (bool)property.GetValue(newOptions)); } else if (propertyType == typeof(int)) { - Assert.Equal(32, (int)property.GetValue(options)); Assert.Equal((int)property.GetValue(options), (int)property.GetValue(newOptions)); } else if (typeof(IEnumerable).IsAssignableFrom(propertyType)) @@ -667,6 +647,10 @@ private static void VerifyOptionsEqual_WithReflection(JsonSerializerOptions opti { Assert.Equal(options.ReadCommentHandling, newOptions.ReadCommentHandling); } + else if (property.Name == "DefaultIgnoreCondition") + { + Assert.Equal(options.DefaultIgnoreCondition, newOptions.DefaultIgnoreCondition); + } else { Assert.True(false, $"Public option was added to JsonSerializerOptions but not copied in the copy ctor: {property.Name}"); @@ -678,5 +662,46 @@ private static void VerifyOptionsEqual_WithReflection(JsonSerializerOptions opti } } } + + [Fact] + public static void CopyConstructor_IgnoreNullValuesCopied() + { + var options = new JsonSerializerOptions { IgnoreNullValues = true }; + var newOptions = new JsonSerializerOptions(options); + VerifyOptionsEqual(options, newOptions); + } + + [Fact] + public static void CannotSetBoth_IgnoreNullValues_And_DefaultIgnoreCondition() + { + // Set IgnoreNullValues first. + JsonSerializerOptions options = new JsonSerializerOptions { IgnoreNullValues = true }; + + InvalidOperationException ex = Assert.Throws( + () => options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault); + string exAsStr = ex.ToString(); + Assert.Contains("IgnoreNullValues", exAsStr); + Assert.Contains("DefaultIgnoreCondition", exAsStr); + + options.IgnoreNullValues = false; + // We can set the property now. + options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault; + + // Set DefaultIgnoreCondition first. + + options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault }; + Assert.Throws( + () => options.IgnoreNullValues = true); + + options.DefaultIgnoreCondition = JsonIgnoreCondition.Never; + // We can set the property now. + options.IgnoreNullValues = true; + } + + [Fact] + public static void CannotSet_DefaultIgnoreCondition_To_Always() + { + Assert.Throws(() => new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.Always }); + } } } diff --git a/src/libraries/System.Text.Json/tests/Serialization/PropertyNameTests.cs b/src/libraries/System.Text.Json/tests/Serialization/PropertyNameTests.cs index a13f36661798b4..1b0ff3e70ae12b 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/PropertyNameTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/PropertyNameTests.cs @@ -231,6 +231,89 @@ public static void EmptyPropertyName() } } + [Fact] + public static void EmptyPropertyNameInExtensionData() + { + { + string json = @"{"""":42}"; + EmptyClassWithExtensionProperty obj = JsonSerializer.Deserialize(json); + Assert.Equal(1, obj.MyOverflow.Count); + Assert.Equal(42, obj.MyOverflow[""].GetInt32()); + } + + { + // Verify that last-in wins. + string json = @"{"""":42, """":43}"; + EmptyClassWithExtensionProperty obj = JsonSerializer.Deserialize(json); + Assert.Equal(1, obj.MyOverflow.Count); + Assert.Equal(43, obj.MyOverflow[""].GetInt32()); + } + } + + [Fact] + public static void EmptyPropertyName_WinsOver_ExtensionDataEmptyPropertyName() + { + string json = @"{"""":1}"; + + ClassWithEmptyPropertyNameAndExtensionProperty obj; + + // Create a new options instances to re-set any caches. + JsonSerializerOptions options = new JsonSerializerOptions(); + + // Verify the real property wins over the extension data property. + obj = JsonSerializer.Deserialize(json, options); + Assert.Equal(1, obj.MyInt1); + Assert.Null(obj.MyOverflow); + } + + [Fact] + public static void EmptyPropertyNameAndExtensionData_ExtDataFirst() + { + // Verify any caching treats real property (with empty name) differently than a missing property. + + ClassWithEmptyPropertyNameAndExtensionProperty obj; + + // Create a new options instances to re-set any caches. + JsonSerializerOptions options = new JsonSerializerOptions(); + + // First populate cache with a missing property name. + string json = @"{""DoesNotExist"":42}"; + obj = JsonSerializer.Deserialize(json, options); + Assert.Equal(0, obj.MyInt1); + Assert.Equal(1, obj.MyOverflow.Count); + Assert.Equal(42, obj.MyOverflow["DoesNotExist"].GetInt32()); + + // Then use an empty property. + json = @"{"""":43}"; + obj = JsonSerializer.Deserialize(json, options); + Assert.Equal(43, obj.MyInt1); + Assert.Null(obj.MyOverflow); + } + + [Fact] + public static void EmptyPropertyAndExtensionData_PropertyFirst() + { + // Verify any caching treats real property (with empty name) differently than a missing property. + + ClassWithEmptyPropertyNameAndExtensionProperty obj; + + // Create a new options instances to re-set any caches. + JsonSerializerOptions options = new JsonSerializerOptions(); + + // First use an empty property. + string json = @"{"""":43}"; + obj = JsonSerializer.Deserialize(json, options); + Assert.Equal(43, obj.MyInt1); + Assert.Null(obj.MyOverflow); + + // Then populate cache with a missing property name. + json = @"{""DoesNotExist"":42}"; + obj = JsonSerializer.Deserialize(json, options); + Assert.Equal(0, obj.MyInt1); + Assert.Equal(1, obj.MyOverflow.Count); + Assert.Equal(42, obj.MyOverflow["DoesNotExist"].GetInt32()); + } + [Fact] public static void UnicodePropertyNames() { @@ -515,4 +598,13 @@ public class EmptyClassWithExtensionProperty [JsonExtensionData] public IDictionary MyOverflow { get; set; } } + + public class ClassWithEmptyPropertyNameAndExtensionProperty + { + [JsonPropertyName("")] + public int MyInt1 { get; set; } + + [JsonExtensionData] + public IDictionary MyOverflow { get; set; } + } } diff --git a/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.NonPublicAccessors.cs b/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.NonPublicAccessors.cs new file mode 100644 index 00000000000000..4385cd6fae5194 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.NonPublicAccessors.cs @@ -0,0 +1,332 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class PropertyVisibilityTests + { + [Fact] + public static void NonPublic_AccessorsNotSupported_WithoutAttribute() + { + string json = @"{ + ""MyInt"":1, + ""MyString"":""Hello"", + ""MyFloat"":2, + ""MyUri"":""https://microsoft.com"" + }"; + + var obj = JsonSerializer.Deserialize(json); + Assert.Equal(0, obj.MyInt); + Assert.Null(obj.MyString); + Assert.Equal(2f, obj.GetMyFloat); + Assert.Equal(new Uri("https://microsoft.com"), obj.MyUri); + + json = JsonSerializer.Serialize(obj); + Assert.Contains(@"""MyInt"":0", json); + Assert.Contains(@"""MyString"":null", json); + Assert.DoesNotContain(@"""MyFloat"":", json); + Assert.DoesNotContain(@"""MyUri"":", json); + } + + private class MyClass_WithNonPublicAccessors + { + public int MyInt { get; private set; } + public string MyString { get; internal set; } + public float MyFloat { private get; set; } + public Uri MyUri { internal get; set; } + + // For test validation. + internal float GetMyFloat => MyFloat; + } + + [Fact] + public static void Honor_JsonSerializablePropertyAttribute_OnProperties() + { + string json = @"{ + ""MyInt"":1, + ""MyString"":""Hello"", + ""MyFloat"":2, + ""MyUri"":""https://microsoft.com"" + }"; + + var obj = JsonSerializer.Deserialize(json); + Assert.Equal(1, obj.MyInt); + Assert.Equal("Hello", obj.MyString); + Assert.Equal(2f, obj.GetMyFloat); + Assert.Equal(new Uri("https://microsoft.com"), obj.MyUri); + + json = JsonSerializer.Serialize(obj); + Assert.Contains(@"""MyInt"":1", json); + Assert.Contains(@"""MyString"":""Hello""", json); + Assert.Contains(@"""MyFloat"":2", json); + Assert.Contains(@"""MyUri"":""https://microsoft.com""", json); + } + + private class MyClass_WithNonPublicAccessors_WithPropertyAttributes + { + [JsonInclude] + public int MyInt { get; private set; } + [JsonInclude] + public string MyString { get; internal set; } + [JsonInclude] + public float MyFloat { private get; set; } + [JsonInclude] + public Uri MyUri { internal get; set; } + + // For test validation. + internal float GetMyFloat => MyFloat; + } + + private class MyClass_WithNonPublicAccessors_WithPropertyAttributes_And_PropertyIgnore + { + [JsonInclude] + [JsonIgnore] + public int MyInt { get; private set; } + + [JsonInclude] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string MyString { get; internal set; } = "DefaultString"; + + [JsonInclude] + [JsonIgnore(Condition = JsonIgnoreCondition.Always)] + public float MyFloat { private get; set; } + + [JsonInclude] + [JsonIgnore(Condition = JsonIgnoreCondition.Never)] + public Uri MyUri { internal get; set; } + + // For test validation. + internal float GetMyFloat => MyFloat; + } + + [Fact] + public static void ExtensionDataCanHaveNonPublicSetter() + { + string json = @"{""Key"":""Value""}"; + + // Baseline + var obj1 = JsonSerializer.Deserialize(json); + Assert.Null(obj1.ExtensionData); + Assert.Equal("{}", JsonSerializer.Serialize(obj1)); + + // With attribute + var obj2 = JsonSerializer.Deserialize(json); + Assert.Equal("Value", obj2.ExtensionData["Key"].GetString()); + Assert.Equal(json, JsonSerializer.Serialize(obj2)); + } + + private class ClassWithExtensionData_NonPublicSetter + { + [JsonExtensionData] + public Dictionary ExtensionData { get; private set; } + } + + private class ClassWithExtensionData_NonPublicSetter_WithAttribute + { + [JsonExtensionData] + [JsonInclude] + public Dictionary ExtensionData { get; private set; } + } + + private class ClassWithExtensionData_NonPublicGetter + { + [JsonExtensionData] + public Dictionary ExtensionData { internal get; set; } + } + + [Fact] + public static void HonorCustomConverter() + { + var options = new JsonSerializerOptions(); + options.Converters.Add(new JsonStringEnumConverter()); + + string json = @"{""MyEnum"":""AnotherValue"",""MyInt"":2}"; + + // Deserialization baseline, without enum converter, we get JsonException. + Assert.Throws(() => JsonSerializer.Deserialize(json)); + + var obj = JsonSerializer.Deserialize(json, options); + Assert.Equal(MySmallEnum.AnotherValue, obj.GetMyEnum); + Assert.Equal(25, obj.MyInt); + + // ConverterForInt32 throws this exception. + Assert.Throws(() => JsonSerializer.Serialize(obj, options)); + } + + private struct StructWithPropertiesWithConverter + { + [JsonInclude] + public MySmallEnum MyEnum { private get; set; } + + [JsonInclude] + [JsonConverter(typeof(ConverterForInt32))] + public int MyInt { get; private set; } + + // For test validation. + internal MySmallEnum GetMyEnum => MyEnum; + } + + private enum MySmallEnum + { + DefaultValue = 0, + AnotherValue = 1 + } + + [Fact] + public static void HonorCaseInsensitivity() + { + var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + + string json = @"{""MYSTRING"":""Hello""}"; + Assert.Null(JsonSerializer.Deserialize(json).MyString); + Assert.Equal("Hello", JsonSerializer.Deserialize(json, options).MyString); + } + + private struct MyStruct_WithNonPublicAccessors_WithTypeAttribute + { + [JsonInclude] + public int MyInt { get; private set; } + [JsonInclude] + public string MyString { get; internal set; } + [JsonInclude] + public float MyFloat { private get; set; } + [JsonInclude] + public Uri MyUri { internal get; set; } + + // For test validation. + internal float GetMyFloat => MyFloat; + } + + [Fact] + public static void HonorNamingPolicy() + { + var options = new JsonSerializerOptions { PropertyNamingPolicy = new SimpleSnakeCasePolicy() }; + + string json = @"{""my_string"":""Hello""}"; + Assert.Null(JsonSerializer.Deserialize(json).MyString); + Assert.Equal("Hello", JsonSerializer.Deserialize(json, options).MyString); + } + + [Fact] + public static void HonorJsonPropertyName() + { + string json = @"{""prop1"":1,""prop2"":2}"; + + var obj = JsonSerializer.Deserialize(json); + Assert.Equal(MySmallEnum.AnotherValue, obj.GetMyEnum); + Assert.Equal(2, obj.MyInt); + + json = JsonSerializer.Serialize(obj); + Assert.Contains(@"""prop1"":1", json); + Assert.Contains(@"""prop2"":2", json); + } + + private struct StructWithPropertiesWithJsonPropertyName + { + [JsonInclude] + [JsonPropertyName("prop1")] + public MySmallEnum MyEnum { private get; set; } + + [JsonInclude] + [JsonPropertyName("prop2")] + public int MyInt { get; private set; } + + // For test validation. + internal MySmallEnum GetMyEnum => MyEnum; + } + + [Fact] + public static void Map_JsonSerializableProperties_ToCtorArgs() + { + var obj = JsonSerializer.Deserialize(@"{""X"":1,""Y"":2}"); + Assert.Equal(1, obj.X); + Assert.Equal(2, obj.GetY); + } + + private struct PointWith_JsonSerializableProperties + { + [JsonInclude] + public int X { get; internal set; } + [JsonInclude] + public int Y { internal get; set; } + + internal int GetY => Y; + + [JsonConstructor] + public PointWith_JsonSerializableProperties(int x, int y) => (X, Y) = (x, y); + } + + [Fact] + public static void Public_And_NonPublicPropertyAccessors_PropertyAttributes() + { + string json = @"{""W"":1,""X"":2,""Y"":3,""Z"":4}"; + + var obj = JsonSerializer.Deserialize(json); + Assert.Equal(1, obj.W); + Assert.Equal(2, obj.X); + Assert.Equal(3, obj.Y); + Assert.Equal(4, obj.GetZ); + + json = JsonSerializer.Serialize(obj); + Assert.Contains(@"""W"":1", json); + Assert.Contains(@"""X"":2", json); + Assert.Contains(@"""Y"":3", json); + Assert.Contains(@"""Z"":4", json); + } + + private class ClassWithMixedPropertyAccessors_PropertyAttributes + { + [JsonInclude] + public int W { get; set; } + [JsonInclude] + public int X { get; internal set; } + [JsonInclude] + public int Y { get; set; } + [JsonInclude] + public int Z { private get; set; } + + internal int GetZ => Z; + } + + [Theory] + [InlineData(typeof(ClassWithPrivateProperty_WithJsonIncludeProperty))] + [InlineData(typeof(ClassWithInternalProperty_WithJsonIncludeProperty))] + [InlineData(typeof(ClassWithProtectedProperty_WithJsonIncludeProperty))] + public static void NonPublicProperty_WithJsonInclude_Invalid(Type type) + { + InvalidOperationException ex = Assert.Throws(() => JsonSerializer.Deserialize("", type)); + string exAsStr = ex.ToString(); + Assert.Contains("MyString", exAsStr); + Assert.Contains(type.ToString(), exAsStr); + Assert.Contains("JsonIncludeAttribute", exAsStr); + + ex = Assert.Throws(() => JsonSerializer.Serialize(Activator.CreateInstance(type), type)); + exAsStr = ex.ToString(); + Assert.Contains("MyString", exAsStr); + Assert.Contains(type.ToString(), exAsStr); + Assert.Contains("JsonIncludeAttribute", exAsStr); + } + + private class ClassWithPrivateProperty_WithJsonIncludeProperty + { + [JsonInclude] + private string MyString { get; set; } + } + + private class ClassWithInternalProperty_WithJsonIncludeProperty + { + [JsonInclude] + internal string MyString { get; } + } + + private class ClassWithProtectedProperty_WithJsonIncludeProperty + { + [JsonInclude] + protected string MyString { get; private set; } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.cs b/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.cs index 800e2114155f8d..f3a20ca5d9b187 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/PropertyVisibilityTests.cs @@ -9,8 +9,583 @@ namespace System.Text.Json.Serialization.Tests { - public static class PropertyVisibilityTests + public static partial class PropertyVisibilityTests { + [Fact] + public static void Serialize_NewSlotPublicProperty() + { + // Serialize + var obj = new ClassWithNewSlotProperty(); + string json = JsonSerializer.Serialize(obj); + + Assert.Equal(@"{""MyString"":""NewDefaultValue""}", json); + + // Deserialize + json = @"{""MyString"":""NewValue""}"; + obj = JsonSerializer.Deserialize(json); + + Assert.Equal("NewValue", ((ClassWithNewSlotProperty)obj).MyString); + Assert.Equal("DefaultValue", ((ClassWithInternalProperty)obj).MyString); + } + + [Fact] + public static void Serialize_BasePublicProperty_ConflictWithDerivedPrivate() + { + // Serialize + var obj = new ClassWithNewSlotInternalProperty(); + string json = JsonSerializer.Serialize(obj); + + Assert.Equal(@"{""MyString"":""DefaultValue""}", json); + + // Deserialize + json = @"{""MyString"":""NewValue""}"; + obj = JsonSerializer.Deserialize(json); + + Assert.Equal("NewValue", ((ClassWithPublicProperty)obj).MyString); + Assert.Equal("NewDefaultValue", ((ClassWithNewSlotInternalProperty)obj).MyString); + } + + [Fact] + public static void Serialize_PublicProperty_ConflictWithPrivateDueAttributes() + { + // Serialize + var obj = new ClassWithPropertyNamingConflict(); + string json = JsonSerializer.Serialize(obj); + + Assert.Equal(@"{""MyString"":""DefaultValue""}", json); + + // Deserialize + json = @"{""MyString"":""NewValue""}"; + obj = JsonSerializer.Deserialize(json); + + Assert.Equal("NewValue", obj.MyString); + Assert.Equal("ConflictingValue", obj.ConflictingString); + } + + [Fact] + public static void Serialize_PublicProperty_ConflictWithPrivateDuePolicy() + { + var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; + + // Serialize + var obj = new ClassWithPropertyPolicyConflict(); + string json = JsonSerializer.Serialize(obj, options); + + Assert.Equal(@"{""myString"":""DefaultValue""}", json); + + // Deserialize + json = @"{""myString"":""NewValue""}"; + obj = JsonSerializer.Deserialize(json, options); + + Assert.Equal("NewValue", obj.MyString); + Assert.Equal("ConflictingValue", obj.myString); + } + + [Fact] + public static void Serealize_NewSlotPublicProperty_ConflictWithBasePublicProperty() + { + // Serialize + var obj = new ClassWithNewSlotDecimalProperty(); + string json = JsonSerializer.Serialize(obj); + + Assert.Equal(@"{""MyNumeric"":1.5}", json); + + // Deserialize + json = @"{""MyNumeric"":2.5}"; + obj = JsonSerializer.Deserialize(json); + + Assert.Equal(2.5M, obj.MyNumeric); + } + + [Fact] + public static void Serealize_NewSlotPublicProperty_SpecifiedJsonPropertyName() + { + // Serialize + var obj = new ClassWithNewSlotAttributedDecimalProperty(); + string json = JsonSerializer.Serialize(obj); + + Assert.Contains(@"""MyNewNumeric"":1.5", json); + Assert.Contains(@"""MyNumeric"":1", json); + + // Deserialize + json = @"{""MyNewNumeric"":2.5,""MyNumeric"":4}"; + obj = JsonSerializer.Deserialize(json); + + Assert.Equal(4, ((ClassWithHiddenByNewSlotIntProperty)obj).MyNumeric); + Assert.Equal(2.5M, ((ClassWithNewSlotAttributedDecimalProperty)obj).MyNumeric); + } + + [Fact] + public static void Ignore_NonPublicProperty() + { + // Serialize + var obj = new ClassWithInternalProperty(); + string json = JsonSerializer.Serialize(obj); + + Assert.Equal(@"{}", json); + + // Deserialize + json = @"{""MyString"":""NewValue""}"; + obj = JsonSerializer.Deserialize(json); + + Assert.Equal("DefaultValue", obj.MyString); + } + + [Fact] + public static void Ignore_NewSlotPublicPropertyIgnored() + { + // Serialize + var obj = new ClassWithIgnoredNewSlotProperty(); + string json = JsonSerializer.Serialize(obj); + + Assert.Equal(@"{}", json); + + // Deserialize + json = @"{""MyString"":""NewValue""}"; + obj = JsonSerializer.Deserialize(json); + + Assert.Equal("NewDefaultValue", ((ClassWithIgnoredNewSlotProperty)obj).MyString); + Assert.Equal("DefaultValue", ((ClassWithInternalProperty)obj).MyString); + } + + [Fact] + public static void Ignore_BasePublicPropertyIgnored_ConflictWithDerivedPrivate() + { + // Serialize + var obj = new ClassWithIgnoredPublicPropertyAndNewSlotPrivate(); + string json = JsonSerializer.Serialize(obj); + + Assert.Equal(@"{}", json); + + // Deserialize + json = @"{""MyString"":""NewValue""}"; + obj = JsonSerializer.Deserialize(json); + + Assert.Equal("DefaultValue", ((ClassWithIgnoredPublicProperty)obj).MyString); + Assert.Equal("NewDefaultValue", ((ClassWithIgnoredPublicPropertyAndNewSlotPrivate)obj).MyString); + } + + [Fact] + public static void Ignore_PublicProperty_ConflictWithPrivateDueAttributes() + { + // Serialize + var obj = new ClassWithIgnoredPropertyNamingConflictPrivate(); + string json = JsonSerializer.Serialize(obj); + + Assert.Equal(@"{}", json); + + // Deserialize + json = @"{""MyString"":""NewValue""}"; + obj = JsonSerializer.Deserialize(json); + + Assert.Equal("DefaultValue", obj.MyString); + Assert.Equal("ConflictingValue", obj.ConflictingString); + } + + [Fact] + public static void Ignore_PublicProperty_ConflictWithPrivateDuePolicy() + { + var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; + + // Serialize + var obj = new ClassWithIgnoredPropertyPolicyConflictPrivate(); + string json = JsonSerializer.Serialize(obj, options); + + Assert.Equal(@"{}", json); + + // Deserialize + json = @"{""myString"":""NewValue""}"; + obj = JsonSerializer.Deserialize(json, options); + + Assert.Equal("DefaultValue", obj.MyString); + Assert.Equal("ConflictingValue", obj.myString); + } + + [Fact] + public static void Ignore_PublicProperty_ConflictWithPublicDueAttributes() + { + // Serialize + var obj = new ClassWithIgnoredPropertyNamingConflictPublic(); + string json = JsonSerializer.Serialize(obj); + + Assert.Equal(@"{""MyString"":""ConflictingValue""}", json); + + // Deserialize + json = @"{""MyString"":""NewValue""}"; + obj = JsonSerializer.Deserialize(json); + + Assert.Equal("DefaultValue", obj.MyString); + Assert.Equal("NewValue", obj.ConflictingString); + } + + [Fact] + public static void Ignore_PublicProperty_ConflictWithPublicDuePolicy() + { + var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; + + // Serialize + var obj = new ClassWithIgnoredPropertyPolicyConflictPublic(); + string json = JsonSerializer.Serialize(obj, options); + + Assert.Equal(@"{""myString"":""ConflictingValue""}", json); + + // Deserialize + json = @"{""myString"":""NewValue""}"; + obj = JsonSerializer.Deserialize(json, options); + + Assert.Equal("DefaultValue", obj.MyString); + Assert.Equal("NewValue", obj.myString); + } + + [Fact] + public static void Throw_PublicProperty_ConflictDueAttributes() + { + // Serialize + var obj = new ClassWithPropertyNamingConflictWhichThrows(); + Assert.Throws( + () => JsonSerializer.Serialize(obj)); + + // Deserialize + string json = @"{""MyString"":""NewValue""}"; + Assert.Throws( + () => JsonSerializer.Deserialize(json)); + } + + [Fact] + public static void Throw_PublicProperty_ConflictDueAttributes_SingleInheritance() + { + // Serialize + var obj = new ClassInheritedWithPropertyNamingConflictWhichThrows(); + Assert.Throws( + () => JsonSerializer.Serialize(obj)); + + // Deserialize + string json = @"{""MyString"":""NewValue""}"; + Assert.Throws( + () => JsonSerializer.Deserialize(json)); + } + + [Fact] + public static void Throw_PublicProperty_ConflictDueAttributes_DoubleInheritance() + { + // Serialize + var obj = new ClassTwiceInheritedWithPropertyNamingConflictWhichThrows(); + Assert.Throws( + () => JsonSerializer.Serialize(obj)); + + // Deserialize + string json = @"{""MyString"":""NewValue""}"; + Assert.Throws( + () => JsonSerializer.Deserialize(json)); + } + + [Fact] + public static void Throw_PublicProperty_ConflictDuePolicy() + { + var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; + + // Serialize + var obj = new ClassWithPropertyPolicyConflictWhichThrows(); + Assert.Throws( + () => JsonSerializer.Serialize(obj, options)); + + // Deserialize + string json = @"{""MyString"":""NewValue""}"; + Assert.Throws( + () => JsonSerializer.Deserialize(json, options)); + } + + [Fact] + public static void Throw_PublicProperty_ConflictDuePolicy_SingleInheritance() + { + var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; + + // Serialize + var obj = new ClassInheritedWithPropertyPolicyConflictWhichThrows(); + Assert.Throws( + () => JsonSerializer.Serialize(obj, options)); + + // Deserialize + string json = @"{""MyString"":""NewValue""}"; + Assert.Throws( + () => JsonSerializer.Deserialize(json, options)); + } + + [Fact] + public static void Throw_PublicProperty_ConflictDuePolicy_DobuleInheritance() + { + var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; + + // Serialize + var obj = new ClassTwiceInheritedWithPropertyPolicyConflictWhichThrows(); + Assert.Throws( + () => JsonSerializer.Serialize(obj, options)); + + // Deserialize + string json = @"{""MyString"":""NewValue""}"; + Assert.Throws( + () => JsonSerializer.Deserialize(json, options)); + } + + [Fact] + public static void HiddenPropertiesIgnored_WhenOverridesIgnored_AndPropertyNameConflicts() + { + string serialized = JsonSerializer.Serialize(new DerivedClass_With_IgnoredOverride()); + Assert.Equal(@"{""MyProp"":false}", serialized); + + serialized = JsonSerializer.Serialize(new DerivedClass_With_IgnoredOverride_And_ConflictingPropertyName()); + Assert.Equal(@"{""MyProp"":null}", serialized); + + serialized = JsonSerializer.Serialize(new DerivedClass_With_NewProperty()); + Assert.Equal(@"{""MyProp"":false}", serialized); + + serialized = JsonSerializer.Serialize(new DerivedClass_With_NewProperty_And_ConflictingPropertyName()); + Assert.Equal(@"{""MyProp"":null}", serialized); + + serialized = JsonSerializer.Serialize(new DerivedClass_WithNewProperty_Of_DifferentType()); + Assert.Equal(@"{""MyProp"":false}", serialized); + + serialized = JsonSerializer.Serialize(new DerivedClass_WithNewProperty_Of_DifferentType_And_ConflictingPropertyName()); + Assert.Equal(@"{""MyProp"":null}", serialized); + + serialized = JsonSerializer.Serialize(new DerivedClass_WithIgnoredOverride()); + Assert.Equal(@"{""MyProp"":false}", serialized); + + serialized = JsonSerializer.Serialize(new FurtherDerivedClass_With_ConflictingPropertyName()); + Assert.Equal(@"{""MyProp"":null}", serialized); + + Assert.Throws(() => JsonSerializer.Serialize(new DerivedClass_WithConflictingPropertyName())); + + serialized = JsonSerializer.Serialize(new FurtherDerivedClass_With_IgnoredOverride()); + Assert.Equal(@"{""MyProp"":null}", serialized); + } + + public class ClassWithInternalProperty + { + internal string MyString { get; set; } = "DefaultValue"; + } + + public class ClassWithNewSlotProperty : ClassWithInternalProperty + { + public new string MyString { get; set; } = "NewDefaultValue"; + } + + public class ClassWithPublicProperty + { + public string MyString { get; set; } = "DefaultValue"; + } + + public class ClassWithNewSlotInternalProperty : ClassWithPublicProperty + { + internal new string MyString { get; set; } = "NewDefaultValue"; + } + + public class ClassWithPropertyNamingConflict + { + public string MyString { get; set; } = "DefaultValue"; + + [JsonPropertyName(nameof(MyString))] + internal string ConflictingString { get; set; } = "ConflictingValue"; + } + + public class ClassWithPropertyNamingConflictWhichThrows + { + public string MyString { get; set; } = "DefaultValue"; + + [JsonPropertyName(nameof(MyString))] + public string ConflictingString { get; set; } = "ConflictingValue"; + } + + public class ClassInheritedWithPropertyNamingConflictWhichThrows : ClassWithPublicProperty + { + [JsonPropertyName(nameof(MyString))] + public string ConflictingString { get; set; } = "ConflictingValue"; + } + + public class ClassTwiceInheritedWithPropertyNamingConflictWhichThrowsDummy : ClassWithPublicProperty + { + } + + public class ClassTwiceInheritedWithPropertyNamingConflictWhichThrows : ClassTwiceInheritedWithPropertyNamingConflictWhichThrowsDummy + { + [JsonPropertyName(nameof(MyString))] + public string ConflictingString { get; set; } = "ConflictingValue"; + } + + public class ClassWithPropertyPolicyConflict + { + public string MyString { get; set; } = "DefaultValue"; + + internal string myString { get; set; } = "ConflictingValue"; + } + + public class ClassWithPropertyPolicyConflictWhichThrows + { + public string MyString { get; set; } = "DefaultValue"; + + public string myString { get; set; } = "ConflictingValue"; + } + + public class ClassInheritedWithPropertyPolicyConflictWhichThrows : ClassWithPublicProperty + { + public string myString { get; set; } = "ConflictingValue"; + } + + public class ClassInheritedWithPropertyPolicyConflictWhichThrowsDummy : ClassWithPublicProperty + { + } + + public class ClassTwiceInheritedWithPropertyPolicyConflictWhichThrows : ClassInheritedWithPropertyPolicyConflictWhichThrowsDummy + { + public string myString { get; set; } = "ConflictingValue"; + } + + public class ClassWithIgnoredNewSlotProperty : ClassWithInternalProperty + { + [JsonIgnore] + public new string MyString { get; set; } = "NewDefaultValue"; + } + + public class ClassWithIgnoredPublicProperty + { + [JsonIgnore] + public string MyString { get; set; } = "DefaultValue"; + } + + public class ClassWithIgnoredPublicPropertyAndNewSlotPrivate : ClassWithIgnoredPublicProperty + { + internal new string MyString { get; set; } = "NewDefaultValue"; + } + + public class ClassWithIgnoredPropertyNamingConflictPrivate + { + [JsonIgnore] + public string MyString { get; set; } = "DefaultValue"; + + [JsonPropertyName(nameof(MyString))] + internal string ConflictingString { get; set; } = "ConflictingValue"; + } + + public class ClassWithIgnoredPropertyPolicyConflictPrivate + { + [JsonIgnore] + public string MyString { get; set; } = "DefaultValue"; + + internal string myString { get; set; } = "ConflictingValue"; + } + + public class ClassWithIgnoredPropertyNamingConflictPublic + { + [JsonIgnore] + public string MyString { get; set; } = "DefaultValue"; + + [JsonPropertyName(nameof(MyString))] + public string ConflictingString { get; set; } = "ConflictingValue"; + } + + public class ClassWithIgnoredPropertyPolicyConflictPublic + { + [JsonIgnore] + public string MyString { get; set; } = "DefaultValue"; + + public string myString { get; set; } = "ConflictingValue"; + } + + public class ClassWithHiddenByNewSlotIntProperty + { + public int MyNumeric { get; set; } = 1; + } + + public class ClassWithNewSlotDecimalProperty : ClassWithHiddenByNewSlotIntProperty + { + public new decimal MyNumeric { get; set; } = 1.5M; + } + + public class ClassWithNewSlotAttributedDecimalProperty : ClassWithHiddenByNewSlotIntProperty + { + [JsonPropertyName("MyNewNumeric")] + public new decimal MyNumeric { get; set; } = 1.5M; + } + + private class Class_With_VirtualProperty + { + public virtual bool MyProp { get; set; } + } + + private class DerivedClass_With_IgnoredOverride : Class_With_VirtualProperty + { + [JsonIgnore] + public override bool MyProp { get; set; } + } + + private class DerivedClass_With_IgnoredOverride_And_ConflictingPropertyName : Class_With_VirtualProperty + { + [JsonPropertyName("MyProp")] + public string MyString { get; set; } + + [JsonIgnore] + public override bool MyProp { get; set; } + } + + private class Class_With_Property + { + public bool MyProp { get; set; } + } + + private class DerivedClass_With_NewProperty : Class_With_Property + { + [JsonIgnore] + public new bool MyProp { get; set; } + } + + private class DerivedClass_With_NewProperty_And_ConflictingPropertyName : Class_With_Property + { + [JsonPropertyName("MyProp")] + public string MyString { get; set; } + + [JsonIgnore] + public new bool MyProp { get; set; } + } + + private class DerivedClass_WithNewProperty_Of_DifferentType : Class_With_Property + { + [JsonIgnore] + public new int MyProp { get; set; } + } + + private class DerivedClass_WithNewProperty_Of_DifferentType_And_ConflictingPropertyName : Class_With_Property + { + [JsonPropertyName("MyProp")] + public string MyString { get; set; } + + [JsonIgnore] + public new int MyProp { get; set; } + } + + private class DerivedClass_WithIgnoredOverride : Class_With_VirtualProperty + { + [JsonIgnore] + public override bool MyProp { get; set; } + } + + private class FurtherDerivedClass_With_ConflictingPropertyName : DerivedClass_WithIgnoredOverride + { + [JsonPropertyName("MyProp")] + public string MyString { get; set; } + } + + private class DerivedClass_WithConflictingPropertyName : Class_With_VirtualProperty + { + [JsonPropertyName("MyProp")] + public string MyString { get; set; } + } + + private class FurtherDerivedClass_With_IgnoredOverride : DerivedClass_WithConflictingPropertyName + { + [JsonIgnore] + public override bool MyProp { get; set; } + } + [Fact] public static void NoSetter() { @@ -524,8 +1099,8 @@ public ClassWithProperty_IgnoreConditionAlways_Ctor(DateTime myDateTime, int myI } [Theory] - [MemberData(nameof(JsonIgnoreConditionWhenNull_ClassProperty_TestData))] - public static void JsonIgnoreConditionWhenNull_ClassProperty(Type type, JsonSerializerOptions options) + [MemberData(nameof(JsonIgnoreConditionWhenWritingDefault_ClassProperty_TestData))] + public static void JsonIgnoreConditionWhenWritingDefault_ClassProperty(Type type, JsonSerializerOptions options) { // Property shouldn't be ignored if it isn't null. string json = @"{""Int1"":1,""MyString"":""Random"",""Int2"":2}"; @@ -545,7 +1120,17 @@ public static void JsonIgnoreConditionWhenNull_ClassProperty(Type type, JsonSeri obj = JsonSerializer.Deserialize(json, type, options); Assert.Equal(1, (int)type.GetProperty("Int1").GetValue(obj)); - Assert.Equal("DefaultString", (string)type.GetProperty("MyString").GetValue(obj)); + + if (options.IgnoreNullValues) + { + // Null values can be ignored on deserialization using IgnoreNullValues. + Assert.Equal("DefaultString", (string)type.GetProperty("MyString").GetValue(obj)); + } + else + { + Assert.Null((string)type.GetProperty("MyString").GetValue(obj)); + } + Assert.Equal(2, (int)type.GetProperty("Int2").GetValue(obj)); // Set property to be ignored to null. @@ -557,22 +1142,22 @@ public static void JsonIgnoreConditionWhenNull_ClassProperty(Type type, JsonSeri Assert.DoesNotContain(@"""MyString"":", serialized); } - private class ClassWithClassProperty_IgnoreConditionWhenNull + private class ClassWithClassProperty_IgnoreConditionWhenWritingDefault { public int Int1 { get; set; } - [JsonIgnore(Condition = JsonIgnoreCondition.WhenNull)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string MyString { get; set; } = "DefaultString"; public int Int2 { get; set; } } - private class ClassWithClassProperty_IgnoreConditionWhenNull_Ctor + private class ClassWithClassProperty_IgnoreConditionWhenWritingDefault_Ctor { public int Int1 { get; set; } - [JsonIgnore(Condition = JsonIgnoreCondition.WhenNull)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string MyString { get; set; } = "DefaultString"; public int Int2 { get; set; } - public ClassWithClassProperty_IgnoreConditionWhenNull_Ctor(string myString) + public ClassWithClassProperty_IgnoreConditionWhenWritingDefault_Ctor(string myString) { if (myString != null) { @@ -581,15 +1166,15 @@ public ClassWithClassProperty_IgnoreConditionWhenNull_Ctor(string myString) } } - private static IEnumerable JsonIgnoreConditionWhenNull_ClassProperty_TestData() + private static IEnumerable JsonIgnoreConditionWhenWritingDefault_ClassProperty_TestData() { - yield return new object[] { typeof(ClassWithClassProperty_IgnoreConditionWhenNull), new JsonSerializerOptions() }; - yield return new object[] { typeof(ClassWithClassProperty_IgnoreConditionWhenNull_Ctor), new JsonSerializerOptions { IgnoreNullValues = true } }; + yield return new object[] { typeof(ClassWithClassProperty_IgnoreConditionWhenWritingDefault), new JsonSerializerOptions() }; + yield return new object[] { typeof(ClassWithClassProperty_IgnoreConditionWhenWritingDefault_Ctor), new JsonSerializerOptions { IgnoreNullValues = true } }; } [Theory] - [MemberData(nameof(JsonIgnoreConditionWhenNull_StructProperty_TestData))] - public static void JsonIgnoreConditionWhenNull_StructProperty(Type type, JsonSerializerOptions options) + [MemberData(nameof(JsonIgnoreConditionWhenWritingDefault_StructProperty_TestData))] + public static void JsonIgnoreConditionWhenWritingDefault_StructProperty(Type type, JsonSerializerOptions options) { // Property shouldn't be ignored if it isn't null. string json = @"{""Int1"":1,""MyInt"":3,""Int2"":2}"; @@ -609,23 +1194,23 @@ public static void JsonIgnoreConditionWhenNull_StructProperty(Type type, JsonSer Assert.Throws(() => JsonSerializer.Deserialize(json, type, options)); } - private class ClassWithStructProperty_IgnoreConditionWhenNull + private class ClassWithStructProperty_IgnoreConditionWhenWritingDefault { public int Int1 { get; set; } - [JsonIgnore(Condition = JsonIgnoreCondition.WhenNull)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public int MyInt { get; set; } public int Int2 { get; set; } } - private struct StructWithStructProperty_IgnoreConditionWhenNull_Ctor + private struct StructWithStructProperty_IgnoreConditionWhenWritingDefault_Ctor { public int Int1 { get; set; } - [JsonIgnore(Condition = JsonIgnoreCondition.WhenNull)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public int MyInt { get; } public int Int2 { get; set; } [JsonConstructor] - public StructWithStructProperty_IgnoreConditionWhenNull_Ctor(int myInt) + public StructWithStructProperty_IgnoreConditionWhenWritingDefault_Ctor(int myInt) { Int1 = 0; MyInt = myInt; @@ -633,10 +1218,10 @@ public StructWithStructProperty_IgnoreConditionWhenNull_Ctor(int myInt) } } - private static IEnumerable JsonIgnoreConditionWhenNull_StructProperty_TestData() + private static IEnumerable JsonIgnoreConditionWhenWritingDefault_StructProperty_TestData() { - yield return new object[] { typeof(ClassWithStructProperty_IgnoreConditionWhenNull), new JsonSerializerOptions() }; - yield return new object[] { typeof(StructWithStructProperty_IgnoreConditionWhenNull_Ctor), new JsonSerializerOptions { IgnoreNullValues = true } }; + yield return new object[] { typeof(ClassWithStructProperty_IgnoreConditionWhenWritingDefault), new JsonSerializerOptions() }; + yield return new object[] { typeof(StructWithStructProperty_IgnoreConditionWhenWritingDefault_Ctor), new JsonSerializerOptions { IgnoreNullValues = true } }; } [Theory] @@ -745,33 +1330,30 @@ public static void JsonIgnoreCondition_LastOneWins() } [Fact] - public static void ClassWithComplexObjectsUsingIgnoreWhenNullAttribute() + public static void ClassWithComplexObjectsUsingIgnoreWhenWritingDefaultAttribute() { string json = @"{""Class"":{""MyInt16"":18}, ""Dictionary"":null}"; - ClassUsingIgnoreWhenNullAttribute obj = JsonSerializer.Deserialize(json); + ClassUsingIgnoreWhenWritingDefaultAttribute obj = JsonSerializer.Deserialize(json); - // Class is deserialized because it is not null in json. + // Class is deserialized. Assert.NotNull(obj.Class); Assert.Equal(18, obj.Class.MyInt16); - // Dictionary is left alone because it is null in json. - Assert.NotNull(obj.Dictionary); - Assert.Equal(1, obj.Dictionary.Count); - Assert.Equal("Value", obj.Dictionary["Key"]); - + // Dictionary is deserialized as JsonIgnoreCondition.WhenWritingDefault only applies to deserialization. + Assert.Null(obj.Dictionary); - obj = new ClassUsingIgnoreWhenNullAttribute(); + obj = new ClassUsingIgnoreWhenWritingDefaultAttribute(); json = JsonSerializer.Serialize(obj); Assert.Equal(@"{""Dictionary"":{""Key"":""Value""}}", json); } - public class ClassUsingIgnoreWhenNullAttribute + public class ClassUsingIgnoreWhenWritingDefaultAttribute { - [JsonIgnore(Condition = JsonIgnoreCondition.WhenNull)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public SimpleTestClass Class { get; set; } - [JsonIgnore(Condition = JsonIgnoreCondition.WhenNull)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public Dictionary Dictionary { get; set; } = new Dictionary { ["Key"] = "Value" }; } @@ -827,7 +1409,7 @@ public static void IgnoreConditionNever_WinsOver_IgnoreReadOnlyValues() } [Fact] - public static void IgnoreConditionWhenNull_WinsOver_IgnoreReadOnlyValues() + public static void IgnoreConditionWhenWritingDefault_WinsOver_IgnoreReadOnlyValues() { var options = new JsonSerializerOptions { IgnoreReadOnlyProperties = true }; @@ -836,10 +1418,10 @@ public static void IgnoreConditionWhenNull_WinsOver_IgnoreReadOnlyValues() Assert.Equal("{}", json); // With condition to ignore when null - json = JsonSerializer.Serialize(new ClassWithReadOnlyString_IgnoreWhenNull("Hello"), options); + json = JsonSerializer.Serialize(new ClassWithReadOnlyString_IgnoreWhenWritingDefault("Hello"), options); Assert.Equal(@"{""MyString"":""Hello""}", json); - json = JsonSerializer.Serialize(new ClassWithReadOnlyString_IgnoreWhenNull(null), options); + json = JsonSerializer.Serialize(new ClassWithReadOnlyString_IgnoreWhenWritingDefault(null), options); Assert.Equal(@"{}", json); } @@ -858,12 +1440,112 @@ private class ClassWithReadOnlyString_IgnoreNever public ClassWithReadOnlyString_IgnoreNever(string myString) => MyString = myString; } - private class ClassWithReadOnlyString_IgnoreWhenNull + private class ClassWithReadOnlyString_IgnoreWhenWritingDefault { - [JsonIgnore(Condition = JsonIgnoreCondition.WhenNull)] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public string MyString { get; } - public ClassWithReadOnlyString_IgnoreWhenNull(string myString) => MyString = myString; + public ClassWithReadOnlyString_IgnoreWhenWritingDefault(string myString) => MyString = myString; + } + + [Fact] + public static void NonPublicMembersAreNotIncluded() + { + Assert.Equal("{}", JsonSerializer.Serialize(new ClassWithNonPublicProperties())); + + string json = @"{""MyInt"":1,""MyString"":""Hello"",""MyFloat"":2,""MyDouble"":3}"; + var obj = JsonSerializer.Deserialize(json); + Assert.Equal(0, obj.MyInt); + Assert.Null(obj.MyString); + Assert.Equal(0, obj.GetMyFloat); + Assert.Equal(0, obj.GetMyDouble); + } + + private class ClassWithNonPublicProperties + { + internal int MyInt { get; set; } + internal string MyString { get; private set; } + internal float MyFloat { private get; set; } + private double MyDouble { get; set; } + + internal float GetMyFloat => MyFloat; + internal double GetMyDouble => MyDouble; + } + + [Fact] + public static void IgnoreCondition_WhenWritingDefault_Globally_Works() + { + // Baseline - default values written. + string expected = @"{""MyString"":null,""MyInt"":0,""MyPoint"":{""X"":0,""Y"":0}}"; + var obj = new ClassWithProps(); + JsonTestHelper.AssertJsonEqual(expected, JsonSerializer.Serialize(obj)); + + // Default values ignored when specified. + Assert.Equal("{}", JsonSerializer.Serialize(obj, new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault })); + } + + private class ClassWithProps + { + public string MyString { get; set; } + public int MyInt { get; set; } + public Point_2D_Struct MyPoint { get; set; } + } + + [Fact] + public static void IgnoreCondition_WhenWritingDefault_PerProperty_Works() + { + // Default values ignored when specified. + Assert.Equal(@"{""MyInt"":0}", JsonSerializer.Serialize(new ClassWithPropsAndIgnoreAttributes())); + } + + private class ClassWithPropsAndIgnoreAttributes + { + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string MyString { get; set; } + public int MyInt { get; set; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Point_2D_Struct MyPoint { get; set; } + } + + [Fact] + public static void IgnoreCondition_WhenWritingDefault_DoesNotApplyToCollections() + { + var list = new List { false, true }; + + var options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault }; + Assert.Equal("[false,true]", JsonSerializer.Serialize(list, options)); + } + + [Fact] + public static void IgnoreCondition_WhenWritingDefault_DoesNotApplyToDeserialization() + { + // Baseline - null values are ignored on deserialization when using IgnoreNullValues (for compat with initial support). + string json = @"{""MyString"":null,""MyInt"":0,""MyPoint"":{""X"":0,""Y"":0}}"; + + var options = new JsonSerializerOptions { IgnoreNullValues = true }; + ClassWithInitializedProps obj = JsonSerializer.Deserialize(json, options); + + Assert.Equal("Default", obj.MyString); + // Value types are not ignored. + Assert.Equal(0, obj.MyInt); + Assert.Equal(0, obj.MyPoint.X); + Assert.Equal(0, obj.MyPoint.X); + + // Test - default values (both null and default for value types) are not ignored when using + // JsonIgnoreCondition.WhenWritingDefault (as the option name implies) + options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault }; + obj = JsonSerializer.Deserialize(json, options); + Assert.Null(obj.MyString); + Assert.Equal(0, obj.MyInt); + Assert.Equal(0, obj.MyPoint.X); + Assert.Equal(0, obj.MyPoint.X); + } + + private class ClassWithInitializedProps + { + public string MyString { get; set; } = "Default"; + public int MyInt { get; set; } = -1; + public Point_2D_Struct MyPoint { get; set; } = new Point_2D_Struct(-1, -1); } } } diff --git a/src/libraries/System.Text.Json/tests/Serialization/ReadValueTests.cs b/src/libraries/System.Text.Json/tests/Serialization/ReadValueTests.cs index 7328788731ebcc..1d754a544bf97c 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/ReadValueTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/ReadValueTests.cs @@ -3,10 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Buffers; -using System.Collections.Generic; using System.IO; -using System.Reflection; -using System.Threading.Tasks; using Xunit; namespace System.Text.Json.Serialization.Tests diff --git a/src/libraries/System.Text.Json/tests/Serialization/ReferenceHandlingTests.Deserialize.cs b/src/libraries/System.Text.Json/tests/Serialization/ReferenceHandlingTests.Deserialize.cs index ed774a8359d026..a20b2e1580e536 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/ReferenceHandlingTests.Deserialize.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/ReferenceHandlingTests.Deserialize.cs @@ -920,7 +920,6 @@ public static void InvalidMetadataPropertyNameWithSameLengthIsNotRecognized(stri JsonException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, s_deserializerOptionsPreserve)); Assert.Equal(expectedPath, ex.Path); } - #endregion #region Throw on immutables diff --git a/src/libraries/System.Text.Json/tests/Serialization/Stream.Collections.cs b/src/libraries/System.Text.Json/tests/Serialization/Stream.Collections.cs new file mode 100644 index 00000000000000..8ea7c33cf186c9 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/Stream.Collections.cs @@ -0,0 +1,396 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static partial class StreamTests + { + [Fact] + public static async Task HandleCollectionsAsync() + { + await RunTest(); + await RunTest(); + await RunTest(); + } + + private static async Task RunTest() + { + foreach ((Type, int) pair in CollectionTestData()) + { + Type type = pair.Item1; + int bufferSize = pair.Item2; + + // bufferSize * 0.9 is the threshold size from codebase, subtract 2 for [ or { characters, then create a + // string containing (threshold - 2) amount of char 'a' which when written into output buffer produces buffer + // which size equal to or very close to threshold size, then adding the string to the list, then adding a big + // object to the list which changes depth of written json and should cause buffer flush. + int thresholdSize = (int)(bufferSize * 0.9 - 2); + + var options = new JsonSerializerOptions + { + DefaultBufferSize = bufferSize, + WriteIndented = true + }; + + var optionsWithPreservedReferenceHandling = new JsonSerializerOptions(options) + { + ReferenceHandling = ReferenceHandling.Preserve + }; + + object obj = GetPopulatedCollection(type, thresholdSize); + await PerformSerialization(obj, type, options); + await PerformSerialization(obj, type, optionsWithPreservedReferenceHandling); + } + } + + private static async Task PerformSerialization(object obj, Type type, JsonSerializerOptions options) + { + string expectedjson = JsonSerializer.Serialize(obj, options); + + using (var memoryStream = new MemoryStream()) + { + await JsonSerializer.SerializeAsync(memoryStream, obj, options); + string serialized = Encoding.UTF8.GetString(memoryStream.ToArray()); + JsonTestHelper.AssertJsonEqual(expectedjson, serialized); + + memoryStream.Position = 0; + await TestDeserialization(memoryStream, expectedjson, type, options); + } + + // Deserialize with extra whitespace + string jsonWithWhiteSpace = GetPayloadWithWhiteSpace(expectedjson); + using (var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(jsonWithWhiteSpace))) + { + await TestDeserialization(memoryStream, expectedjson, type, options); + } + } + + private static async Task TestDeserialization( + Stream memoryStream, + string expectedJson, + Type type, + JsonSerializerOptions options) + { + try + { + object deserialized = await JsonSerializer.DeserializeAsync(memoryStream, type, options); + string serialized = JsonSerializer.Serialize(deserialized, options); + + // Stack elements reversed during serialization. + if (StackTypes().Contains(type)) + { + deserialized = JsonSerializer.Deserialize(serialized, type, options); + serialized = JsonSerializer.Serialize(deserialized, options); + } + + // TODO: https://github.com/dotnet/runtime/issues/35611. + // Can't control order of dictionary elements when serializing, so reference metadata might not match up. + if (!(DictionaryTypes().Contains(type) && options.ReferenceHandling == ReferenceHandling.Preserve)) + { + JsonTestHelper.AssertJsonEqual(expectedJson, serialized); + } + } + catch (NotSupportedException ex) + { + Assert.True(GetTypesNotSupportedForDeserialization().Contains(type)); + Assert.Contains(type.ToString(), ex.ToString()); + } + } + + private static object GetPopulatedCollection(Type type, int stringLength) + { + if (type == typeof(TElement[])) + { + return GetArr_TypedElements(stringLength); + } + else if (type == typeof(ImmutableList)) + { + return ImmutableList.CreateRange(GetArr_TypedElements(stringLength)); + } + else if (type == typeof(ImmutableStack)) + { + return ImmutableStack.CreateRange(GetArr_TypedElements(stringLength)); + } + else if (type == typeof(ImmutableDictionary)) + { + return ImmutableDictionary.CreateRange(GetDict_TypedElements(stringLength)); + } + else if ( + typeof(IDictionary).IsAssignableFrom(type) || + typeof(IReadOnlyDictionary).IsAssignableFrom(type) || + typeof(IDictionary).IsAssignableFrom(type)) + { + return Activator.CreateInstance(type, new object[] { GetDict_TypedElements(stringLength) }); + } + else if (typeof(IEnumerable).IsAssignableFrom(type)) + { + return Activator.CreateInstance(type, new object[] { GetArr_TypedElements(stringLength) }); + } + else + { + return Activator.CreateInstance(type, new object[] { GetArr_BoxedElements(stringLength) }); + } + } + + private static object GetEmptyCollection(Type type) + { + if (type == typeof(TElement[])) + { + return Array.Empty(); + } + else if (type == typeof(ImmutableList)) + { + return ImmutableList.CreateRange(Array.Empty()); + } + else if (type == typeof(ImmutableStack)) + { + return ImmutableStack.CreateRange(Array.Empty()); + } + else if (type == typeof(ImmutableDictionary)) + { + return ImmutableDictionary.CreateRange(new Dictionary()); + } + else + { + return Activator.CreateInstance(type); + } + } + + private static string GetPayloadWithWhiteSpace(string json) => json.Replace(" ", new string(' ', 4)); + + private const int NumElements = 15; + + private static TElement[] GetArr_TypedElements(int stringLength) + { + Debug.Assert(NumElements > 2); + var arr = new TElement[NumElements]; + + TElement item = GetCollectionElement(stringLength); + arr[0] = item; + + for (int i = 1; i < NumElements - 1; i++) + { + arr[i] = GetCollectionElement(stringLength); + } + + arr[NumElements - 1] = item; + + return arr; + } + + private static object[] GetArr_BoxedElements(int stringLength) + { + Debug.Assert(NumElements > 2); + var arr = new object[NumElements]; + + TElement item = GetCollectionElement(stringLength); + arr[0] = item; + + for (int i = 1; i < NumElements - 1; i++) + { + arr[i] = GetCollectionElement(stringLength); + } + + arr[NumElements - 1] = item; + + return arr; + } + + private static Dictionary GetDict_TypedElements(int stringLength) + { + Debug.Assert(NumElements > 2); + + TElement item = GetCollectionElement(stringLength); + + var dict = new Dictionary(); + + dict[$"{item}0"] = item; + + for (int i = 1; i < NumElements - 1; i++) + { + TElement newItem = GetCollectionElement(stringLength); + dict[$"{newItem}{i}"] = newItem; + } + + dict[$"{item}{NumElements - 1}"] = item; + + return dict; + } + + private static TElement GetCollectionElement(int stringLength) + { + Type type = typeof(TElement); + + Random rand = new Random(); + char randomChar = (char)rand.Next('a', 'z'); + + string value = new string(randomChar, stringLength); + + if (type == typeof(string)) + { + return (TElement)(object)value; + } + else if (type == typeof(ClassWithString)) + { + return (TElement)(object)new ClassWithString + { + MyFirstString = value + }; + } + else + { + return (TElement)(object)new ImmutableStructWithString(value, value); + } + + throw new NotImplementedException(); + } + + private static IEnumerable<(Type, int)> CollectionTestData() + { + foreach (Type type in CollectionTypes()) + { + foreach (int bufferSize in BufferSizes()) + { + yield return (type, bufferSize); + } + } + } + + private static IEnumerable BufferSizes() + { + yield return 128; + yield return 1024; + yield return 4096; + yield return 8192; + yield return 16384; + yield return 65536; + } + + private static IEnumerable CollectionTypes() + { + foreach (Type type in EnumerableTypes()) + { + yield return type; + } + // Stack types + foreach (Type type in StackTypes()) + { + yield return type; + } + // Dictionary types + foreach (Type type in DictionaryTypes()) + { + yield return type; + } + } + + private static IEnumerable EnumerableTypes() + { + yield return typeof(TElement[]); // ArrayConverter + yield return typeof(ConcurrentQueue); // ConcurrentQueueOfTConverter + yield return typeof(GenericICollectionWrapper); // ICollectionOfTConverter + yield return typeof(WrapperForIEnumerable); // IEnumerableConverter + yield return typeof(WrapperForIReadOnlyCollectionOfT); // IEnumerableOfTConverter + yield return typeof(Queue); // IEnumerableWithAddMethodConverter + yield return typeof(WrapperForIList); // IListConverter + yield return typeof(Collection); // IListOfTConverter + yield return typeof(ImmutableList); // ImmutableEnumerableOfTConverter + yield return typeof(HashSet); // ISetOfTConverter + yield return typeof(List); // ListOfTConverter + yield return typeof(Queue); // QueueOfTConverter + } + + private static IEnumerable DictionaryTypes() + { + yield return typeof(Dictionary); // DictionaryOfStringTValueConverter + yield return typeof(Hashtable); // IDictionaryConverter + yield return typeof(ConcurrentDictionary); // IDictionaryOfStringTValueConverter + yield return typeof(GenericIDictionaryWrapper); // IDictionaryOfStringTValueConverter + yield return typeof(ImmutableDictionary); // ImmutableDictionaryOfStringTValueConverter + yield return typeof(GenericIReadOnlyDictionaryWrapper); // IReadOnlyDictionaryOfStringTValueConverter + } + + private static HashSet StackTypes() => new HashSet + { + typeof(ConcurrentStack), // ConcurrentStackOfTConverter + typeof(Stack), // IEnumerableWithAddMethodConverter + typeof(Stack), // StackOfTConverter + typeof(ImmutableStack) // ImmutableEnumerableOfTConverter + }; + + private static HashSet GetTypesNotSupportedForDeserialization() => new HashSet + { + typeof(WrapperForIEnumerable), + typeof(WrapperForIReadOnlyCollectionOfT), + typeof(GenericIReadOnlyDictionaryWrapper) + }; + + private class ClassWithString + { + public string MyFirstString { get; set; } + } + + private struct ImmutableStructWithString + { + public string MyFirstString { get; } + public string MySecondString { get; } + + [JsonConstructor] + public ImmutableStructWithString(string myFirstString, string mySecondString) + { + MyFirstString = myFirstString; + MySecondString = mySecondString; + } + } + + [Theory] + [InlineData("")] + [InlineData("}")] + [InlineData("[")] + [InlineData("]")] + public static void DeserializeDictionaryStartsWithInvalidJson(string json) + { + foreach (Type type in DictionaryTypes()) + { + Assert.ThrowsAsync(async () => + { + using (var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(json))) + { + await JsonSerializer.DeserializeAsync(memoryStream, type); + } + }); + } + } + + [Fact] + public static void SerializeEmptyCollection() + { + foreach (Type type in EnumerableTypes()) + { + Assert.Equal("[]", JsonSerializer.Serialize(GetEmptyCollection(type))); + } + + foreach (Type type in StackTypes()) + { + Assert.Equal("[]", JsonSerializer.Serialize(GetEmptyCollection(type))); + } + + foreach (Type type in DictionaryTypes()) + { + Assert.Equal("{}", JsonSerializer.Serialize(GetEmptyCollection(type))); + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.GenericCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.GenericCollections.cs deleted file mode 100644 index f428afbb797156..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.GenericCollections.cs +++ /dev/null @@ -1,1405 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public class SimpleTestClassWithGenericCollectionWrappers : ITestClass - { - public StringICollectionWrapper MyStringICollectionWrapper { get; set; } - public StringIListWrapper MyStringIListWrapper { get; set; } - public StringISetWrapper MyStringISetWrapper { get; set; } - public StringToStringIDictionaryWrapper MyStringToStringIDictionaryWrapper { get; set; } - public StringListWrapper MyStringListWrapper { get; set; } - public StringStackWrapper MyStringStackWrapper { get; set; } - public StringQueueWrapper MyStringQueueWrapper { get; set; } - public StringHashSetWrapper MyStringHashSetWrapper { get; set; } - public StringLinkedListWrapper MyStringLinkedListWrapper { get; set; } - public StringSortedSetWrapper MyStringSortedSetWrapper { get; set; } - public StringToStringDictionaryWrapper MyStringToStringDictionaryWrapper { get; set; } - public StringToStringSortedDictionaryWrapper MyStringToStringSortedDictionaryWrapper { get; set; } - public StringToGenericDictionaryWrapper> MyStringToGenericDictionaryWrapper { get; set; } - - public static readonly string s_json = - @"{" + - @"""MyStringICollectionWrapper"" : [""Hello""]," + - @"""MyStringIListWrapper"" : [""Hello""]," + - @"""MyStringISetWrapper"" : [""Hello""]," + - @"""MyStringToStringIDictionaryWrapper"" : {""key"" : ""value""}," + - @"""MyStringListWrapper"" : [""Hello""]," + - @"""MyStringStackWrapper"" : [""Hello""]," + - @"""MyStringQueueWrapper"" : [""Hello""]," + - @"""MyStringHashSetWrapper"" : [""Hello""]," + - @"""MyStringLinkedListWrapper"" : [""Hello""]," + - @"""MyStringSortedSetWrapper"" : [""Hello""]," + - @"""MyStringToStringDictionaryWrapper"" : {""key"" : ""value""}," + - @"""MyStringToStringSortedDictionaryWrapper"" : {""key"" : ""value""}," + - @"""MyStringToGenericDictionaryWrapper"" : {""key"" : {""key"" : ""value""}}" + - @"}"; - - public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); - - public void Initialize() - { - MyStringICollectionWrapper = new StringICollectionWrapper() { "Hello" }; - MyStringIListWrapper = new StringIListWrapper() { "Hello" }; - MyStringISetWrapper = new StringISetWrapper() { "Hello" }; - MyStringToStringIDictionaryWrapper = new StringToStringIDictionaryWrapper() { { "key", "value" } }; - MyStringListWrapper = new StringListWrapper() { "Hello" }; - MyStringStackWrapper = new StringStackWrapper(new List { "Hello" }); - MyStringQueueWrapper = new StringQueueWrapper(new List { "Hello" }); - MyStringHashSetWrapper = new StringHashSetWrapper() { "Hello" }; - MyStringLinkedListWrapper = new StringLinkedListWrapper(new List { "Hello" }); - MyStringSortedSetWrapper = new StringSortedSetWrapper() { "Hello" }; - MyStringToStringDictionaryWrapper = new StringToStringDictionaryWrapper() { { "key", "value" } }; - MyStringToStringSortedDictionaryWrapper = new StringToStringSortedDictionaryWrapper() { { "key", "value" } }; - MyStringToGenericDictionaryWrapper = new StringToGenericDictionaryWrapper>() { { "key", new StringToGenericDictionaryWrapper() { { "key", "value" } } } }; - } - - public void Verify() - { - Assert.Equal("Hello", MyStringICollectionWrapper.First()); - Assert.Equal("Hello", MyStringIListWrapper[0]); - Assert.Equal("Hello", MyStringISetWrapper.First()); - Assert.Equal("value", MyStringToStringIDictionaryWrapper["key"]); - Assert.Equal("Hello", MyStringListWrapper[0]); - Assert.Equal("Hello", MyStringStackWrapper.First()); - Assert.Equal("Hello", MyStringQueueWrapper.First()); - Assert.Equal("Hello", MyStringHashSetWrapper.First()); - Assert.Equal("Hello", MyStringLinkedListWrapper.First()); - Assert.Equal("Hello", MyStringSortedSetWrapper.First()); - Assert.Equal("value", MyStringToStringDictionaryWrapper["key"]); - Assert.Equal("value", MyStringToStringSortedDictionaryWrapper["key"]); - Assert.Equal("value", MyStringToGenericDictionaryWrapper["key"]["key"]); - } - } - - public class SimpleTestClassWithStringIEnumerableWrapper - { - public StringIEnumerableWrapper MyStringIEnumerableWrapper { get; set; } - - public static readonly string s_json = - @"{" + - @"""MyStringIEnumerableWrapper"" : [""Hello""]" + - @"}"; - - public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); - - // Call only when testing serialization. - public void Initialize() - { - MyStringIEnumerableWrapper = new StringIEnumerableWrapper(new List{ "Hello" }); - } - } - - public class SimpleTestClassWithStringIReadOnlyCollectionWrapper - { - public StringIReadOnlyCollectionWrapper MyStringIReadOnlyCollectionWrapper { get; set; } - - public static readonly string s_json = - @"{" + - @"""MyStringIReadOnlyCollectionWrapper"" : [""Hello""]" + - @"}"; - - public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); - - // Call only when testing serialization. - public void Initialize() - { - MyStringIReadOnlyCollectionWrapper = new StringIReadOnlyCollectionWrapper(new List { "Hello" }); - } - } - - public class SimpleTestClassWithStringIReadOnlyListWrapper - { - public StringIReadOnlyListWrapper MyStringIReadOnlyListWrapper { get; set; } - - public static readonly string s_json = - @"{" + - @"""MyStringIReadOnlyListWrapper"" : [""Hello""]" + - @"}"; - - public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); - - // Call only when testing serialization. - public void Initialize() - { - MyStringIReadOnlyListWrapper = new StringIReadOnlyListWrapper(new List { "Hello" }); - } - } - - public class SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper - { - public StringToStringIReadOnlyDictionaryWrapper MyStringToStringIReadOnlyDictionaryWrapper { get; set; } - - public static readonly string s_json = - @"{" + - @"""MyStringToStringIReadOnlyDictionaryWrapper"" : {""key"" : ""value""}" + - @"}"; - - public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); - - // Call only when testing serialization. - public void Initialize() - { - MyStringToStringIReadOnlyDictionaryWrapper = new StringToStringIReadOnlyDictionaryWrapper( - new Dictionary() { { "key", "value" } }); - } - } - - public class StringIEnumerableWrapper : IEnumerable - { - private readonly List _list = new List(); - - public StringIEnumerableWrapper() { } - - public StringIEnumerableWrapper(List items) - { - _list = items; - } - - public IEnumerator GetEnumerator() - { - return _list.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return _list.GetEnumerator(); - } - } - - public class GenericIEnumerableWrapper : IEnumerable - { - private readonly List _list = new List(); - - public GenericIEnumerableWrapper() { } - - public GenericIEnumerableWrapper(List items) - { - _list = items; - } - - public IEnumerator GetEnumerator() - { - return ((IEnumerable)_list).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable)_list).GetEnumerator(); - } - } - - public class GenericIEnumerableWrapperPrivateConstructor : GenericIEnumerableWrapper - { - private GenericIEnumerableWrapperPrivateConstructor() { } - } - - public class GenericIEnumerableWrapperInternalConstructor : GenericIEnumerableWrapper - { - internal GenericIEnumerableWrapperInternalConstructor() { } - } - - public class StringICollectionWrapper : ICollection - { - private readonly List _list = new List(); - - public int Count => _list.Count; - - public virtual bool IsReadOnly => ((ICollection)_list).IsReadOnly; - - public virtual void Add(string item) - { - _list.Add(item); - } - - public void Clear() - { - _list.Clear(); - } - - public bool Contains(string item) - { - return _list.Contains(item); - } - - public void CopyTo(string[] array, int arrayIndex) - { - _list.CopyTo(array, arrayIndex); - } - - public IEnumerator GetEnumerator() - { - return ((ICollection)_list).GetEnumerator(); - } - - public bool Remove(string item) - { - return _list.Remove(item); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((ICollection)_list).GetEnumerator(); - } - } - - public class ReadOnlyStringICollectionWrapper : StringICollectionWrapper - { - public override bool IsReadOnly => true; - } - - public class StringIListWrapper : IList - { - private readonly List _list = new List(); - - public string this[int index] { get => _list[index]; set => _list[index] = value; } - - public int Count => _list.Count; - - public virtual bool IsReadOnly => ((IList)_list).IsReadOnly; - - public virtual void Add(string item) - { - _list.Add(item); - } - - public void Clear() - { - _list.Clear(); - } - - public bool Contains(string item) - { - return _list.Contains(item); - } - - public void CopyTo(string[] array, int arrayIndex) - { - _list.CopyTo(array, arrayIndex); - } - - public IEnumerator GetEnumerator() - { - return ((IList)_list).GetEnumerator(); - } - - public int IndexOf(string item) - { - return _list.IndexOf(item); - } - - public void Insert(int index, string item) - { - _list.Insert(index, item); - } - - public bool Remove(string item) - { - return _list.Remove(item); - } - - public void RemoveAt(int index) - { - _list.RemoveAt(index); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IList)_list).GetEnumerator(); - } - } - - public class ReadOnlyStringIListWrapper : StringIListWrapper - { - public override bool IsReadOnly => true; - } - - public class GenericIListWrapper : IList - { - private readonly List _list = new List(); - - public T this[int index] { get => _list[index]; set => _list[index] = value; } - - public int Count => _list.Count; - - public bool IsReadOnly => ((IList)_list).IsReadOnly; - - public void Add(T item) - { - _list.Add(item); - } - - public void Clear() - { - _list.Clear(); - } - - public bool Contains(T item) - { - return _list.Contains(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - _list.CopyTo(array, arrayIndex); - } - - public IEnumerator GetEnumerator() - { - return ((IList)_list).GetEnumerator(); - } - - public int IndexOf(T item) - { - return _list.IndexOf(item); - } - - public void Insert(int index, T item) - { - _list.Insert(index, item); - } - - public bool Remove(T item) - { - return _list.Remove(item); - } - - public void RemoveAt(int index) - { - _list.RemoveAt(index); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IList)_list).GetEnumerator(); - } - } - - public class GenericIListWrapperPrivateConstructor : GenericIListWrapper - { - private GenericIListWrapperPrivateConstructor() { } - } - - public class GenericIListWrapperInternalConstructor : GenericIListWrapper - { - internal GenericIListWrapperInternalConstructor() { } - } - - public class GenericICollectionWrapper : ICollection - { - private readonly List _list = new List(); - - public int Count => _list.Count; - - public bool IsReadOnly => ((ICollection)_list).IsReadOnly; - - public void Add(T item) - { - _list.Add(item); - } - - public void Clear() - { - _list.Clear(); - } - - public bool Contains(T item) - { - return _list.Contains(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - _list.CopyTo(array, arrayIndex); - } - - public IEnumerator GetEnumerator() - { - return ((ICollection)_list).GetEnumerator(); - } - - public bool Remove(T item) - { - return _list.Remove(item); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((ICollection)_list).GetEnumerator(); - } - } - - public class GenericICollectionWrapperPrivateConstructor : GenericICollectionWrapper - { - private GenericICollectionWrapperPrivateConstructor() { } - } - - public class GenericICollectionWrapperInternalConstructor : GenericICollectionWrapper - { - internal GenericICollectionWrapperInternalConstructor() { } - } - - public class StringIReadOnlyCollectionWrapper : IReadOnlyCollection - { - private readonly List _list = new List(); - - public StringIReadOnlyCollectionWrapper() { } - - public StringIReadOnlyCollectionWrapper(List list) - { - _list = list; - } - - public int Count => _list.Count; - - public IEnumerator GetEnumerator() - { - return ((IReadOnlyCollection)_list).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IReadOnlyCollection)_list).GetEnumerator(); - } - } - - public class GenericIReadOnlyCollectionWrapper : IReadOnlyCollection - { - private readonly List _list = new List(); - - public GenericIReadOnlyCollectionWrapper() { } - - public GenericIReadOnlyCollectionWrapper(List list) - { - _list = list; - } - - public int Count => _list.Count; - - public IEnumerator GetEnumerator() - { - return ((IReadOnlyCollection)_list).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IReadOnlyCollection)_list).GetEnumerator(); - } - } - - public class StringIReadOnlyListWrapper : IReadOnlyList - { - private readonly List _list = new List(); - - public StringIReadOnlyListWrapper() { } - - public StringIReadOnlyListWrapper(List list) - { - _list = list; - } - - public string this[int index] => _list[index]; - - public int Count => _list.Count; - - public IEnumerator GetEnumerator() - { - return ((IReadOnlyList)_list).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IReadOnlyList)_list).GetEnumerator(); - } - } - - public class GenericIReadOnlyListWrapper : IReadOnlyList - { - private readonly List _list = new List(); - - public GenericIReadOnlyListWrapper() { } - - public GenericIReadOnlyListWrapper(List list) - { - _list = list; - } - - public T this[int index] => _list[index]; - - public int Count => _list.Count; - - public IEnumerator GetEnumerator() - { - return ((IReadOnlyList)_list).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IReadOnlyList)_list).GetEnumerator(); - } - } - - public class StringISetWrapper : ISet - { - private readonly HashSet _hashset = new HashSet(); - - public int Count => _hashset.Count; - - public bool IsReadOnly => ((ISet)_hashset).IsReadOnly; - - public bool Add(string item) - { - return _hashset.Add(item); - } - - public void Clear() - { - _hashset.Clear(); - } - - public bool Contains(string item) - { - return _hashset.Contains(item); - } - - public void CopyTo(string[] array, int arrayIndex) - { - _hashset.CopyTo(array, arrayIndex); - } - - public void ExceptWith(IEnumerable other) - { - _hashset.ExceptWith(other); - } - - public IEnumerator GetEnumerator() - { - return ((ISet)_hashset).GetEnumerator(); - } - - public void IntersectWith(IEnumerable other) - { - _hashset.IntersectWith(other); - } - - public bool IsProperSubsetOf(IEnumerable other) - { - return _hashset.IsProperSubsetOf(other); - } - - public bool IsProperSupersetOf(IEnumerable other) - { - return _hashset.IsProperSupersetOf(other); - } - - public bool IsSubsetOf(IEnumerable other) - { - return _hashset.IsSubsetOf(other); - } - - public bool IsSupersetOf(IEnumerable other) - { - return _hashset.IsSupersetOf(other); - } - - public bool Overlaps(IEnumerable other) - { - return _hashset.Overlaps(other); - } - - public bool Remove(string item) - { - return _hashset.Remove(item); - } - - public bool SetEquals(IEnumerable other) - { - return _hashset.SetEquals(other); - } - - public void SymmetricExceptWith(IEnumerable other) - { - _hashset.SymmetricExceptWith(other); - } - - public void UnionWith(IEnumerable other) - { - _hashset.UnionWith(other); - } - - void ICollection.Add(string item) - { - _hashset.Add(item); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((ISet)_hashset).GetEnumerator(); - } - } - - public class GenericISetWrapper : ISet - { - private readonly HashSet _hashset = new HashSet(); - - public int Count => _hashset.Count; - - public bool IsReadOnly => ((ISet)_hashset).IsReadOnly; - - public bool Add(T item) - { - return _hashset.Add(item); - } - - public void Clear() - { - _hashset.Clear(); - } - - public bool Contains(T item) - { - return _hashset.Contains(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - _hashset.CopyTo(array, arrayIndex); - } - - public void ExceptWith(IEnumerable other) - { - _hashset.ExceptWith(other); - } - - public IEnumerator GetEnumerator() - { - return ((ISet)_hashset).GetEnumerator(); - } - - public void IntersectWith(IEnumerable other) - { - _hashset.IntersectWith(other); - } - - public bool IsProperSubsetOf(IEnumerable other) - { - return _hashset.IsProperSubsetOf(other); - } - - public bool IsProperSupersetOf(IEnumerable other) - { - return _hashset.IsProperSupersetOf(other); - } - - public bool IsSubsetOf(IEnumerable other) - { - return _hashset.IsSubsetOf(other); - } - - public bool IsSupersetOf(IEnumerable other) - { - return _hashset.IsSupersetOf(other); - } - - public bool Overlaps(IEnumerable other) - { - return _hashset.Overlaps(other); - } - - public bool Remove(T item) - { - return _hashset.Remove(item); - } - - public bool SetEquals(IEnumerable other) - { - return _hashset.SetEquals(other); - } - - public void SymmetricExceptWith(IEnumerable other) - { - _hashset.SymmetricExceptWith(other); - } - - public void UnionWith(IEnumerable other) - { - _hashset.UnionWith(other); - } - - void ICollection.Add(T item) - { - _hashset.Add(item); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((ISet)_hashset).GetEnumerator(); - } - } - - public class GenericISetWrapperPrivateConstructor : GenericISetWrapper - { - private GenericISetWrapperPrivateConstructor() { } - } - - public class GenericISetWrapperInternalConstructor : GenericISetWrapper - { - internal GenericISetWrapperInternalConstructor() { } - } - - public class StringToStringIDictionaryWrapper : IDictionary - { - private Dictionary _dictionary = new Dictionary(); - - public StringToStringIDictionaryWrapper() { } - - public StringToStringIDictionaryWrapper(Dictionary dictionary) - { - _dictionary = dictionary; - } - - public string this[string key] { get => ((IDictionary)_dictionary)[key]; set => ((IDictionary)_dictionary)[key] = value; } - - public ICollection Keys => ((IDictionary)_dictionary).Keys; - - public ICollection Values => ((IDictionary)_dictionary).Values; - - public int Count => ((IDictionary)_dictionary).Count; - - public virtual bool IsReadOnly => ((IDictionary)_dictionary).IsReadOnly; - - public virtual void Add(string key, string value) - { - ((IDictionary)_dictionary).Add(key, value); - } - - public void Add(KeyValuePair item) - { - ((IDictionary)_dictionary).Add(item); - } - - public void Clear() - { - ((IDictionary)_dictionary).Clear(); - } - - public bool Contains(KeyValuePair item) - { - return ((IDictionary)_dictionary).Contains(item); - } - - public bool ContainsKey(string key) - { - return ((IDictionary)_dictionary).ContainsKey(key); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - ((IDictionary)_dictionary).CopyTo(array, arrayIndex); - } - - public IEnumerator> GetEnumerator() - { - return ((IDictionary)_dictionary).GetEnumerator(); - } - - public bool Remove(string key) - { - return ((IDictionary)_dictionary).Remove(key); - } - - public bool Remove(KeyValuePair item) - { - return ((IDictionary)_dictionary).Remove(item); - } - - public bool TryGetValue(string key, out string value) - { - return ((IDictionary)_dictionary).TryGetValue(key, out value); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IDictionary)_dictionary).GetEnumerator(); - } - } - - public class GenericIDictionaryWrapper : IDictionary - { - private Dictionary _dict = new Dictionary(); - - public TValue this[TKey key] { get => ((IDictionary)_dict)[key]; set => ((IDictionary)_dict)[key] = value; } - - public ICollection Keys => ((IDictionary)_dict).Keys; - - public ICollection Values => ((IDictionary)_dict).Values; - - public int Count => ((IDictionary)_dict).Count; - - public bool IsReadOnly => ((IDictionary)_dict).IsReadOnly; - - public void Add(TKey key, TValue value) - { - ((IDictionary)_dict).Add(key, value); - } - - public void Add(KeyValuePair item) - { - ((IDictionary)_dict).Add(item); - } - - public void Clear() - { - ((IDictionary)_dict).Clear(); - } - - public bool Contains(KeyValuePair item) - { - return ((IDictionary)_dict).Contains(item); - } - - public bool ContainsKey(TKey key) - { - return ((IDictionary)_dict).ContainsKey(key); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - ((IDictionary)_dict).CopyTo(array, arrayIndex); - } - - public IEnumerator> GetEnumerator() - { - return ((IDictionary)_dict).GetEnumerator(); - } - - public bool Remove(TKey key) - { - return ((IDictionary)_dict).Remove(key); - } - - public bool Remove(KeyValuePair item) - { - return ((IDictionary)_dict).Remove(item); - } - - public bool TryGetValue(TKey key, out TValue value) - { - return ((IDictionary)_dict).TryGetValue(key, out value); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IDictionary)_dict).GetEnumerator(); - } - } - - public class GenericIDictionaryWrapperPrivateConstructor : GenericIDictionaryWrapper - { - private GenericIDictionaryWrapperPrivateConstructor() { } - } - - public class GenericIDictionaryWrapperInternalConstructor : GenericIDictionaryWrapper - { - internal GenericIDictionaryWrapperInternalConstructor() { } - } - - public class GenericIDictonaryWrapperThreeGenericParameters : GenericIDictionaryWrapper { } - - public class ReadOnlyStringToStringIDictionaryWrapper : StringToStringIDictionaryWrapper - { - public override bool IsReadOnly => true; - } - - public class StringToObjectIDictionaryWrapper : IDictionary - { - private Dictionary _dictionary = new Dictionary(); - - public StringToObjectIDictionaryWrapper() { } - - public StringToObjectIDictionaryWrapper(Dictionary dictionary) - { - _dictionary = dictionary; - } - - public object this[string key] { get => ((IDictionary)_dictionary)[key]; set => ((IDictionary)_dictionary)[key] = value; } - - public ICollection Keys => ((IDictionary)_dictionary).Keys; - - public ICollection Values => ((IDictionary)_dictionary).Values; - - public int Count => ((IDictionary)_dictionary).Count; - - public bool IsReadOnly => ((IDictionary)_dictionary).IsReadOnly; - - public void Add(string key, object value) - { - ((IDictionary)_dictionary).Add(key, value); - } - - public void Add(KeyValuePair item) - { - ((IDictionary)_dictionary).Add(item); - } - - public void Clear() - { - ((IDictionary)_dictionary).Clear(); - } - - public bool Contains(KeyValuePair item) - { - return ((IDictionary)_dictionary).Contains(item); - } - - public bool ContainsKey(string key) - { - return ((IDictionary)_dictionary).ContainsKey(key); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - ((IDictionary)_dictionary).CopyTo(array, arrayIndex); - } - - public IEnumerator> GetEnumerator() - { - return ((IDictionary)_dictionary).GetEnumerator(); - } - - public bool Remove(string key) - { - return ((IDictionary)_dictionary).Remove(key); - } - - public bool Remove(KeyValuePair item) - { - return ((IDictionary)_dictionary).Remove(item); - } - - public bool TryGetValue(string key, out object value) - { - return ((IDictionary)_dictionary).TryGetValue(key, out value); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IDictionary)_dictionary).GetEnumerator(); - } - } - - public class StringToGenericIDictionaryWrapper : IDictionary - { - private Dictionary _dictionary = new Dictionary(); - - public TValue this[string key] { get => ((IDictionary)_dictionary)[key]; set => ((IDictionary)_dictionary)[key] = value; } - - public ICollection Keys => ((IDictionary)_dictionary).Keys; - - public ICollection Values => ((IDictionary)_dictionary).Values; - - public int Count => ((IDictionary)_dictionary).Count; - - public bool IsReadOnly => ((IDictionary)_dictionary).IsReadOnly; - - public void Add(string key, TValue value) - { - ((IDictionary)_dictionary).Add(key, value); - } - - public void Add(KeyValuePair item) - { - ((IDictionary)_dictionary).Add(item); - } - - public void Clear() - { - ((IDictionary)_dictionary).Clear(); - } - - public bool Contains(KeyValuePair item) - { - return ((IDictionary)_dictionary).Contains(item); - } - - public bool ContainsKey(string key) - { - return ((IDictionary)_dictionary).ContainsKey(key); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - ((IDictionary)_dictionary).CopyTo(array, arrayIndex); - } - - public IEnumerator> GetEnumerator() - { - return ((IDictionary)_dictionary).GetEnumerator(); - } - - public bool Remove(string key) - { - return ((IDictionary)_dictionary).Remove(key); - } - - public bool Remove(KeyValuePair item) - { - return ((IDictionary)_dictionary).Remove(item); - } - - public bool TryGetValue(string key, out TValue value) - { - return ((IDictionary)_dictionary).TryGetValue(key, out value); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IDictionary)_dictionary).GetEnumerator(); - } - } - - public class StringToStringIReadOnlyDictionaryWrapper : IReadOnlyDictionary - { - private Dictionary _dictionary = new Dictionary(); - - public StringToStringIReadOnlyDictionaryWrapper() { } - - public StringToStringIReadOnlyDictionaryWrapper(Dictionary items) - { - _dictionary = items; - } - - public string this[string key] => ((IReadOnlyDictionary)_dictionary)[key]; - - public IEnumerable Keys => ((IReadOnlyDictionary)_dictionary).Keys; - - public IEnumerable Values => ((IReadOnlyDictionary)_dictionary).Values; - - public int Count => ((IReadOnlyDictionary)_dictionary).Count; - - public bool ContainsKey(string key) - { - return ((IReadOnlyDictionary)_dictionary).ContainsKey(key); - } - - public IEnumerator> GetEnumerator() - { - return ((IReadOnlyDictionary)_dictionary).GetEnumerator(); - } - - public bool TryGetValue(string key, out string value) - { - return ((IReadOnlyDictionary)_dictionary).TryGetValue(key, out value); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IReadOnlyDictionary)_dictionary).GetEnumerator(); - } - } - - public class StringToStringIReadOnlyDictionaryWrapperPrivateConstructor : StringToStringIReadOnlyDictionaryWrapper - { - private StringToStringIReadOnlyDictionaryWrapperPrivateConstructor() { } - } - - public class StringToStringIReadOnlyDictionaryWrapperInternalConstructor : StringToStringIReadOnlyDictionaryWrapper - { - internal StringToStringIReadOnlyDictionaryWrapperInternalConstructor() { } - } - - public class StringListWrapper : List { } - - class MyMyList : GenericListWrapper - { - } - - class MyListString : GenericListWrapper - { - } - - public class GenericListWrapper : List { } - - public class GenericListWrapperPrivateConstructor : GenericListWrapper - { - private GenericListWrapperPrivateConstructor() { } - } - - public class GenericListWrapperInternalConstructor : GenericListWrapper - { - internal GenericListWrapperInternalConstructor() { } - } - - public class StringStackWrapper : Stack - { - public StringStackWrapper() { } - - // For populating test data only. We cannot assume actual input will have this method. - public StringStackWrapper(IList items) - { - foreach (string item in items) - { - Push(item); - } - } - } - - public class GenericStackWrapper : Stack - { - public GenericStackWrapper() { } - - // For populating test data only. We cannot assume actual input will have this method. - public GenericStackWrapper(IList items) - { - foreach (T item in items) - { - Push(item); - } - } - } - - public class GenericStackWrapperPrivateConstructor : GenericStackWrapper - { - private GenericStackWrapperPrivateConstructor() { } - } - - public class GenericStackWrapperInternalConstructor : GenericStackWrapper - { - internal GenericStackWrapperInternalConstructor() { } - } - - public class StringQueueWrapper : Queue - { - public StringQueueWrapper() { } - - // For populating test data only. We cannot assume actual input will have this method. - public StringQueueWrapper(IList items) - { - foreach (string item in items) - { - Enqueue(item); - } - } - } - - public class GenericQueueWrapper : Queue - { - public GenericQueueWrapper() { } - - // For populating test data only. We cannot assume actual input will have this method. - public GenericQueueWrapper(IList items) - { - foreach (T item in items) - { - Enqueue(item); - } - } - } - - public class GenericQueueWrapperPrivateConstructor : GenericQueueWrapper - { - private GenericQueueWrapperPrivateConstructor() { } - } - - public class GenericQueueWrapperInternalConstructor : GenericQueueWrapper - { - internal GenericQueueWrapperInternalConstructor() { } - } - - public class StringHashSetWrapper : HashSet - { - public StringHashSetWrapper() { } - - // For populating test data only. We cannot assume actual input will have this method. - public StringHashSetWrapper(IList items) - { - foreach (string item in items) - { - Add(item); - } - } - } - - public class GenericHashSetWrapper : HashSet - { - public GenericHashSetWrapper() { } - - // For populating test data only. We cannot assume actual input will have this method. - public GenericHashSetWrapper(IList items) - { - foreach (T item in items) - { - Add(item); - } - } - } - - public class StringLinkedListWrapper : LinkedList - { - public StringLinkedListWrapper() { } - - // For populating test data only. We cannot assume actual input will have this method. - public StringLinkedListWrapper(IList items) - { - foreach (string item in items) - { - AddLast(item); - } - } - } - - public class GenericLinkedListWrapper : LinkedList - { - public GenericLinkedListWrapper() { } - - // For populating test data only. We cannot assume actual input will have this method. - public GenericLinkedListWrapper(IList items) - { - foreach (T item in items) - { - AddLast(item); - } - } - } - - public class StringSortedSetWrapper : SortedSet - { - public StringSortedSetWrapper() { } - - // For populating test data only. We cannot assume actual input will have this method. - public StringSortedSetWrapper(IList items) - { - foreach (string item in items) - { - Add(item); - } - } - } - - public class GenericSortedSetWrapper : SortedSet - { - public GenericSortedSetWrapper() { } - - // For populating test data only. We cannot assume actual input will have this method. - public GenericSortedSetWrapper(IList items) - { - foreach (T item in items) - { - Add(item); - } - } - } - - public class StringToStringDictionaryWrapper : Dictionary - { - public StringToStringDictionaryWrapper() { } - - // For populating test data only. We cannot assume actual input will have this method. - public StringToStringDictionaryWrapper(IList> items) - { - foreach (KeyValuePair item in items) - { - Add(item.Key, item.Value); - } - } - } - - public class StringToGenericDictionaryWrapper : Dictionary - { - public StringToGenericDictionaryWrapper() { } - - // For populating test data only. We cannot assume actual input will have this method. - public StringToGenericDictionaryWrapper(IList> items) - { - foreach (KeyValuePair item in items) - { - Add(item.Key, item.Value); - } - } - } - - public class StringToGenericDictionaryWrapperPrivateConstructor : StringToGenericDictionaryWrapper - { - private StringToGenericDictionaryWrapperPrivateConstructor() { } - } - - public class StringToGenericDictionaryWrapperInternalConstructor : StringToGenericDictionaryWrapper - { - internal StringToGenericDictionaryWrapperInternalConstructor() { } - } - - public class StringToStringSortedDictionaryWrapper : SortedDictionary - { - public StringToStringSortedDictionaryWrapper() { } - - // For populating test data only. We cannot assume actual input will have this method. - public StringToStringSortedDictionaryWrapper(IList> items) - { - foreach (KeyValuePair item in items) - { - Add(item.Key, item.Value); - } - } - } - - public class HashSetWithBackingCollection : ICollection - { - private readonly ICollection _inner; - - public HashSetWithBackingCollection() - { - _inner = new HashSet(); - } - - public HashSetWithBackingCollection(IEnumerable values) - { - _inner = new HashSet(values); - } - - public int Count => _inner.Count; - - public bool IsReadOnly => _inner.IsReadOnly; - - public void Add(string item) - { - _inner.Add(item); - } - - public void Clear() - { - _inner.Clear(); - } - - public bool Contains(string item) - { - return _inner.Contains(item); - } - - public void CopyTo(string[] array, int arrayIndex) - { - _inner.CopyTo(array, arrayIndex); - } - - public IEnumerator GetEnumerator() - { - return _inner.GetEnumerator(); - } - - public bool Remove(string item) - { - return _inner.Remove(item); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return _inner.GetEnumerator(); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.ConcurrentCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.ConcurrentCollections.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/TestClasses.ConcurrentCollections.cs rename to src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.ConcurrentCollections.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.Constructor.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.Constructor.cs similarity index 99% rename from src/libraries/System.Text.Json/tests/Serialization/TestClasses.Constructor.cs rename to src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.Constructor.cs index 5358f7e61501ba..1d02e33d7f6a09 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.Constructor.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.Constructor.cs @@ -917,6 +917,13 @@ public NullArgTester(Point_3D_Struct point3DStruct, ImmutableArray immutabl } } + public class NullArgTester_Mutable + { + public Point_3D_Struct Point3DStruct { get; set; } + public ImmutableArray ImmutableArray { get; set; } + public int Int { get; set; } + } + public class ClassWithConstructor_SimpleAndComplexParameters : ITestClassWithParameterizedCtor { public byte MyByte { get; } @@ -1215,18 +1222,6 @@ public override void Write(Utf8JsonWriter writer, Point_3D value, JsonSerializer throw new NotImplementedException(); } } - public class ConverterForInt32 : JsonConverter - { - public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return 25; - } - - public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options) - { - throw new NotImplementedException(); - } - } public class Class_With_Ctor_With_64_Params : ITestClass { @@ -2124,14 +2119,6 @@ public override string ConvertName(string name) } } - public class SimpleSnakeCasePolicy : JsonNamingPolicy - { - public override string ConvertName(string name) - { - return string.Concat(name.Select((x, i) => i > 0 && char.IsUpper(x) ? "_" + x.ToString() : x.ToString())).ToLower(); - } - } - public class Point_With_Array : ITestClass { public int X { get; } diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.GenericCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.GenericCollections.cs new file mode 100644 index 00000000000000..dac260ca6599a4 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.GenericCollections.cs @@ -0,0 +1,1178 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public class SimpleTestClassWithGenericCollectionWrappers : ITestClass + { + public GenericICollectionWrapper MyStringICollectionWrapper { get; set; } + public StringIListWrapper MyStringIListWrapper { get; set; } + public StringISetWrapper MyStringISetWrapper { get; set; } + public GenericIDictionaryWrapper MyStringToStringIDictionaryWrapper { get; set; } + public StringListWrapper MyStringListWrapper { get; set; } + public StringStackWrapper MyStringStackWrapper { get; set; } + public StringQueueWrapper MyStringQueueWrapper { get; set; } + public StringHashSetWrapper MyStringHashSetWrapper { get; set; } + public StringLinkedListWrapper MyStringLinkedListWrapper { get; set; } + public StringSortedSetWrapper MyStringSortedSetWrapper { get; set; } + public StringToStringDictionaryWrapper MyStringToStringDictionaryWrapper { get; set; } + public StringToStringSortedDictionaryWrapper MyStringToStringSortedDictionaryWrapper { get; set; } + public StringToGenericDictionaryWrapper> MyStringToGenericDictionaryWrapper { get; set; } + + public static readonly string s_json = + @"{" + + @"""MyStringICollectionWrapper"" : [""Hello""]," + + @"""MyStringIListWrapper"" : [""Hello""]," + + @"""MyStringISetWrapper"" : [""Hello""]," + + @"""MyStringToStringIDictionaryWrapper"" : {""key"" : ""value""}," + + @"""MyStringListWrapper"" : [""Hello""]," + + @"""MyStringStackWrapper"" : [""Hello""]," + + @"""MyStringQueueWrapper"" : [""Hello""]," + + @"""MyStringHashSetWrapper"" : [""Hello""]," + + @"""MyStringLinkedListWrapper"" : [""Hello""]," + + @"""MyStringSortedSetWrapper"" : [""Hello""]," + + @"""MyStringToStringDictionaryWrapper"" : {""key"" : ""value""}," + + @"""MyStringToStringSortedDictionaryWrapper"" : {""key"" : ""value""}," + + @"""MyStringToGenericDictionaryWrapper"" : {""key"" : {""key"" : ""value""}}" + + @"}"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + public void Initialize() + { + MyStringICollectionWrapper = new GenericICollectionWrapper() { "Hello" }; + MyStringIListWrapper = new StringIListWrapper() { "Hello" }; + MyStringISetWrapper = new StringISetWrapper() { "Hello" }; + MyStringToStringIDictionaryWrapper = new GenericIDictionaryWrapper() { { "key", "value" } }; + MyStringListWrapper = new StringListWrapper() { "Hello" }; + MyStringStackWrapper = new StringStackWrapper(new List { "Hello" }); + MyStringQueueWrapper = new StringQueueWrapper(new List { "Hello" }); + MyStringHashSetWrapper = new StringHashSetWrapper() { "Hello" }; + MyStringLinkedListWrapper = new StringLinkedListWrapper(new List { "Hello" }); + MyStringSortedSetWrapper = new StringSortedSetWrapper() { "Hello" }; + MyStringToStringDictionaryWrapper = new StringToStringDictionaryWrapper() { { "key", "value" } }; + MyStringToStringSortedDictionaryWrapper = new StringToStringSortedDictionaryWrapper() { { "key", "value" } }; + MyStringToGenericDictionaryWrapper = new StringToGenericDictionaryWrapper>() { { "key", new StringToGenericDictionaryWrapper() { { "key", "value" } } } }; + } + + public void Verify() + { + Assert.Equal("Hello", MyStringICollectionWrapper.First()); + Assert.Equal("Hello", MyStringIListWrapper[0]); + Assert.Equal("Hello", MyStringISetWrapper.First()); + Assert.Equal("value", MyStringToStringIDictionaryWrapper["key"]); + Assert.Equal("Hello", MyStringListWrapper[0]); + Assert.Equal("Hello", MyStringStackWrapper.First()); + Assert.Equal("Hello", MyStringQueueWrapper.First()); + Assert.Equal("Hello", MyStringHashSetWrapper.First()); + Assert.Equal("Hello", MyStringLinkedListWrapper.First()); + Assert.Equal("Hello", MyStringSortedSetWrapper.First()); + Assert.Equal("value", MyStringToStringDictionaryWrapper["key"]); + Assert.Equal("value", MyStringToStringSortedDictionaryWrapper["key"]); + Assert.Equal("value", MyStringToGenericDictionaryWrapper["key"]["key"]); + } + } + + public class SimpleTestClassWithStringIEnumerableWrapper + { + public StringIEnumerableWrapper MyStringIEnumerableWrapper { get; set; } + + public static readonly string s_json = + @"{" + + @"""MyStringIEnumerableWrapper"" : [""Hello""]" + + @"}"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + // Call only when testing serialization. + public void Initialize() + { + MyStringIEnumerableWrapper = new StringIEnumerableWrapper(new List{ "Hello" }); + } + } + + public class SimpleTestClassWithStringIReadOnlyCollectionWrapper + { + public WrapperForIReadOnlyCollectionOfT MyStringIReadOnlyCollectionWrapper { get; set; } + + public static readonly string s_json = + @"{" + + @"""MyStringIReadOnlyCollectionWrapper"" : [""Hello""]" + + @"}"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + // Call only when testing serialization. + public void Initialize() + { + MyStringIReadOnlyCollectionWrapper = new WrapperForIReadOnlyCollectionOfT(new List { "Hello" }); + } + } + + public class SimpleTestClassWithStringIReadOnlyListWrapper + { + public StringIReadOnlyListWrapper MyStringIReadOnlyListWrapper { get; set; } + + public static readonly string s_json = + @"{" + + @"""MyStringIReadOnlyListWrapper"" : [""Hello""]" + + @"}"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + // Call only when testing serialization. + public void Initialize() + { + MyStringIReadOnlyListWrapper = new StringIReadOnlyListWrapper(new List { "Hello" }); + } + } + + public class SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper + { + public GenericIReadOnlyDictionaryWrapper MyStringToStringIReadOnlyDictionaryWrapper { get; set; } + + public static readonly string s_json = + @"{" + + @"""MyStringToStringIReadOnlyDictionaryWrapper"" : {""key"" : ""value""}" + + @"}"; + + public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json); + + // Call only when testing serialization. + public void Initialize() + { + MyStringToStringIReadOnlyDictionaryWrapper = new GenericIReadOnlyDictionaryWrapper( + new Dictionary() { { "key", "value" } }); + } + } + + public class StringIEnumerableWrapper : IEnumerable + { + private readonly List _list = new List(); + + public StringIEnumerableWrapper() { } + + public StringIEnumerableWrapper(List items) + { + _list = items; + } + + public IEnumerator GetEnumerator() + { + return _list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _list.GetEnumerator(); + } + } + + public class GenericIEnumerableWrapper : IEnumerable + { + private readonly List _list = new List(); + + public GenericIEnumerableWrapper() { } + + public GenericIEnumerableWrapper(List items) + { + _list = items; + } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)_list).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)_list).GetEnumerator(); + } + } + + public class GenericIEnumerableWrapperPrivateConstructor : GenericIEnumerableWrapper + { + private GenericIEnumerableWrapperPrivateConstructor() { } + } + + public class GenericIEnumerableWrapperInternalConstructor : GenericIEnumerableWrapper + { + internal GenericIEnumerableWrapperInternalConstructor() { } + } + + public class ReadOnlyStringICollectionWrapper : GenericICollectionWrapper + { + public override bool IsReadOnly => true; + } + + public class StringIListWrapper : IList + { + private readonly List _list = new List(); + + public string this[int index] { get => _list[index]; set => _list[index] = value; } + + public int Count => _list.Count; + + public virtual bool IsReadOnly => ((IList)_list).IsReadOnly; + + public virtual void Add(string item) + { + _list.Add(item); + } + + public void Clear() + { + _list.Clear(); + } + + public bool Contains(string item) + { + return _list.Contains(item); + } + + public void CopyTo(string[] array, int arrayIndex) + { + _list.CopyTo(array, arrayIndex); + } + + public IEnumerator GetEnumerator() + { + return ((IList)_list).GetEnumerator(); + } + + public int IndexOf(string item) + { + return _list.IndexOf(item); + } + + public void Insert(int index, string item) + { + _list.Insert(index, item); + } + + public bool Remove(string item) + { + return _list.Remove(item); + } + + public void RemoveAt(int index) + { + _list.RemoveAt(index); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IList)_list).GetEnumerator(); + } + } + + public class ReadOnlyStringIListWrapper : StringIListWrapper + { + public override bool IsReadOnly => true; + } + + public class GenericIListWrapper : IList + { + private readonly List _list = new List(); + + public T this[int index] { get => _list[index]; set => _list[index] = value; } + + public int Count => _list.Count; + + public bool IsReadOnly => ((IList)_list).IsReadOnly; + + public void Add(T item) + { + _list.Add(item); + } + + public void Clear() + { + _list.Clear(); + } + + public bool Contains(T item) + { + return _list.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + _list.CopyTo(array, arrayIndex); + } + + public IEnumerator GetEnumerator() + { + return ((IList)_list).GetEnumerator(); + } + + public int IndexOf(T item) + { + return _list.IndexOf(item); + } + + public void Insert(int index, T item) + { + _list.Insert(index, item); + } + + public bool Remove(T item) + { + return _list.Remove(item); + } + + public void RemoveAt(int index) + { + _list.RemoveAt(index); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IList)_list).GetEnumerator(); + } + } + + public class GenericIListWrapperPrivateConstructor : GenericIListWrapper + { + private GenericIListWrapperPrivateConstructor() { } + } + + public class GenericIListWrapperInternalConstructor : GenericIListWrapper + { + internal GenericIListWrapperInternalConstructor() { } + } + + public class GenericICollectionWrapper : ICollection + { + private readonly List _list; + + public GenericICollectionWrapper() + { + _list = new List(); + } + + public GenericICollectionWrapper(IEnumerable items) + { + _list = new List(items); + } + + public int Count => _list.Count; + + public virtual bool IsReadOnly => ((ICollection)_list).IsReadOnly; + + public void Add(T item) + { + _list.Add(item); + } + + public void Clear() + { + _list.Clear(); + } + + public bool Contains(T item) + { + return _list.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + _list.CopyTo(array, arrayIndex); + } + + public IEnumerator GetEnumerator() + { + return ((ICollection)_list).GetEnumerator(); + } + + public bool Remove(T item) + { + return _list.Remove(item); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((ICollection)_list).GetEnumerator(); + } + } + + public class GenericICollectionWrapperPrivateConstructor : GenericICollectionWrapper + { + private GenericICollectionWrapperPrivateConstructor() { } + } + + public class GenericICollectionWrapperInternalConstructor : GenericICollectionWrapper + { + internal GenericICollectionWrapperInternalConstructor() { } + } + + public class WrapperForIReadOnlyCollectionOfT : IReadOnlyCollection + { + private readonly List _list; + + public WrapperForIReadOnlyCollectionOfT() + { + _list = new List(); + } + + public WrapperForIReadOnlyCollectionOfT(IEnumerable items) + { + _list = new List(items); + } + + public int Count => _list.Count; + + public IEnumerator GetEnumerator() + { + return ((IReadOnlyCollection)_list).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IReadOnlyCollection)_list).GetEnumerator(); + } + } + + public class GenericIReadOnlyCollectionWrapper : IReadOnlyCollection + { + private readonly List _list = new List(); + + public GenericIReadOnlyCollectionWrapper() { } + + public GenericIReadOnlyCollectionWrapper(List list) + { + _list = list; + } + + public int Count => _list.Count; + + public IEnumerator GetEnumerator() + { + return ((IReadOnlyCollection)_list).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IReadOnlyCollection)_list).GetEnumerator(); + } + } + + public class StringIReadOnlyListWrapper : IReadOnlyList + { + private readonly List _list = new List(); + + public StringIReadOnlyListWrapper() { } + + public StringIReadOnlyListWrapper(List list) + { + _list = list; + } + + public string this[int index] => _list[index]; + + public int Count => _list.Count; + + public IEnumerator GetEnumerator() + { + return ((IReadOnlyList)_list).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IReadOnlyList)_list).GetEnumerator(); + } + } + + public class GenericIReadOnlyListWrapper : IReadOnlyList + { + private readonly List _list = new List(); + + public GenericIReadOnlyListWrapper() { } + + public GenericIReadOnlyListWrapper(List list) + { + _list = list; + } + + public T this[int index] => _list[index]; + + public int Count => _list.Count; + + public IEnumerator GetEnumerator() + { + return ((IReadOnlyList)_list).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IReadOnlyList)_list).GetEnumerator(); + } + } + + public class ReadOnlyStringISetWrapper: StringISetWrapper + { + public override bool IsReadOnly => true; + } + + public class StringISetWrapper : ISet + { + private readonly HashSet _hashset = new HashSet(); + + public int Count => _hashset.Count; + + public virtual bool IsReadOnly => ((ISet)_hashset).IsReadOnly; + + public bool Add(string item) + { + return _hashset.Add(item); + } + + public void Clear() + { + _hashset.Clear(); + } + + public bool Contains(string item) + { + return _hashset.Contains(item); + } + + public void CopyTo(string[] array, int arrayIndex) + { + _hashset.CopyTo(array, arrayIndex); + } + + public void ExceptWith(IEnumerable other) + { + _hashset.ExceptWith(other); + } + + public IEnumerator GetEnumerator() + { + return ((ISet)_hashset).GetEnumerator(); + } + + public void IntersectWith(IEnumerable other) + { + _hashset.IntersectWith(other); + } + + public bool IsProperSubsetOf(IEnumerable other) + { + return _hashset.IsProperSubsetOf(other); + } + + public bool IsProperSupersetOf(IEnumerable other) + { + return _hashset.IsProperSupersetOf(other); + } + + public bool IsSubsetOf(IEnumerable other) + { + return _hashset.IsSubsetOf(other); + } + + public bool IsSupersetOf(IEnumerable other) + { + return _hashset.IsSupersetOf(other); + } + + public bool Overlaps(IEnumerable other) + { + return _hashset.Overlaps(other); + } + + public bool Remove(string item) + { + return _hashset.Remove(item); + } + + public bool SetEquals(IEnumerable other) + { + return _hashset.SetEquals(other); + } + + public void SymmetricExceptWith(IEnumerable other) + { + _hashset.SymmetricExceptWith(other); + } + + public void UnionWith(IEnumerable other) + { + _hashset.UnionWith(other); + } + + void ICollection.Add(string item) + { + _hashset.Add(item); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((ISet)_hashset).GetEnumerator(); + } + } + + public class GenericISetWrapper : ISet + { + private readonly HashSet _hashset = new HashSet(); + + public int Count => _hashset.Count; + + public bool IsReadOnly => ((ISet)_hashset).IsReadOnly; + + public bool Add(T item) + { + return _hashset.Add(item); + } + + public void Clear() + { + _hashset.Clear(); + } + + public bool Contains(T item) + { + return _hashset.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + _hashset.CopyTo(array, arrayIndex); + } + + public void ExceptWith(IEnumerable other) + { + _hashset.ExceptWith(other); + } + + public IEnumerator GetEnumerator() + { + return ((ISet)_hashset).GetEnumerator(); + } + + public void IntersectWith(IEnumerable other) + { + _hashset.IntersectWith(other); + } + + public bool IsProperSubsetOf(IEnumerable other) + { + return _hashset.IsProperSubsetOf(other); + } + + public bool IsProperSupersetOf(IEnumerable other) + { + return _hashset.IsProperSupersetOf(other); + } + + public bool IsSubsetOf(IEnumerable other) + { + return _hashset.IsSubsetOf(other); + } + + public bool IsSupersetOf(IEnumerable other) + { + return _hashset.IsSupersetOf(other); + } + + public bool Overlaps(IEnumerable other) + { + return _hashset.Overlaps(other); + } + + public bool Remove(T item) + { + return _hashset.Remove(item); + } + + public bool SetEquals(IEnumerable other) + { + return _hashset.SetEquals(other); + } + + public void SymmetricExceptWith(IEnumerable other) + { + _hashset.SymmetricExceptWith(other); + } + + public void UnionWith(IEnumerable other) + { + _hashset.UnionWith(other); + } + + void ICollection.Add(T item) + { + _hashset.Add(item); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((ISet)_hashset).GetEnumerator(); + } + } + + public class GenericISetWrapperPrivateConstructor : GenericISetWrapper + { + private GenericISetWrapperPrivateConstructor() { } + } + + public class GenericISetWrapperInternalConstructor : GenericISetWrapper + { + internal GenericISetWrapperInternalConstructor() { } + } + + public class GenericIDictionaryWrapper : IDictionary + { + private readonly Dictionary _dict; + + public GenericIDictionaryWrapper() + { + _dict = new Dictionary(); + } + + public GenericIDictionaryWrapper(IDictionary items) + { + _dict = new Dictionary(items); + } + + public TValue this[TKey key] { get => ((IDictionary)_dict)[key]; set => ((IDictionary)_dict)[key] = value; } + + public ICollection Keys => ((IDictionary)_dict).Keys; + + public ICollection Values => ((IDictionary)_dict).Values; + + public int Count => ((IDictionary)_dict).Count; + + public virtual bool IsReadOnly => ((IDictionary)_dict).IsReadOnly; + + public void Add(TKey key, TValue value) + { + ((IDictionary)_dict).Add(key, value); + } + + public void Add(KeyValuePair item) + { + ((IDictionary)_dict).Add(item); + } + + public void Clear() + { + ((IDictionary)_dict).Clear(); + } + + public bool Contains(KeyValuePair item) + { + return ((IDictionary)_dict).Contains(item); + } + + public bool ContainsKey(TKey key) + { + return ((IDictionary)_dict).ContainsKey(key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + ((IDictionary)_dict).CopyTo(array, arrayIndex); + } + + public IEnumerator> GetEnumerator() + { + return ((IDictionary)_dict).GetEnumerator(); + } + + public bool Remove(TKey key) + { + return ((IDictionary)_dict).Remove(key); + } + + public bool Remove(KeyValuePair item) + { + return ((IDictionary)_dict).Remove(item); + } + + public bool TryGetValue(TKey key, out TValue value) + { + return ((IDictionary)_dict).TryGetValue(key, out value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IDictionary)_dict).GetEnumerator(); + } + } + + public class GenericIDictionaryWrapperPrivateConstructor : GenericIDictionaryWrapper + { + private GenericIDictionaryWrapperPrivateConstructor() { } + } + + public class GenericIDictionaryWrapperInternalConstructor : GenericIDictionaryWrapper + { + internal GenericIDictionaryWrapperInternalConstructor() { } + } + + public class GenericIDictonaryWrapperThreeGenericParameters : GenericIDictionaryWrapper { } + + public class ReadOnlyStringToStringIDictionaryWrapper : GenericIDictionaryWrapper + { + public override bool IsReadOnly => true; + } + + public class StringToObjectIDictionaryWrapper : GenericIDictionaryWrapper { } + + public class StringToGenericIDictionaryWrapper : GenericIDictionaryWrapper { } + + public class GenericIReadOnlyDictionaryWrapper : IReadOnlyDictionary + { + private readonly Dictionary _dictionary; + + public GenericIReadOnlyDictionaryWrapper() + { + _dictionary = new Dictionary(); + } + + public GenericIReadOnlyDictionaryWrapper(IDictionary items) + { + _dictionary = new Dictionary(items); + } + + public TValue this[TKey key] => ((IReadOnlyDictionary)_dictionary)[key]; + + public IEnumerable Keys => ((IReadOnlyDictionary)_dictionary).Keys; + + public IEnumerable Values => ((IReadOnlyDictionary)_dictionary).Values; + + public int Count => ((IReadOnlyDictionary)_dictionary).Count; + + public bool ContainsKey(TKey key) + { + return ((IReadOnlyDictionary)_dictionary).ContainsKey(key); + } + + public IEnumerator> GetEnumerator() + { + return ((IReadOnlyDictionary)_dictionary).GetEnumerator(); + } + + public bool TryGetValue(TKey key, out TValue value) + { + return ((IReadOnlyDictionary)_dictionary).TryGetValue(key, out value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IReadOnlyDictionary)_dictionary).GetEnumerator(); + } + } + + public class StringToStringIReadOnlyDictionaryWrapperPrivateConstructor : GenericIReadOnlyDictionaryWrapper + { + private StringToStringIReadOnlyDictionaryWrapperPrivateConstructor() { } + } + + public class StringToStringIReadOnlyDictionaryWrapperInternalConstructor : GenericIReadOnlyDictionaryWrapper + { + internal StringToStringIReadOnlyDictionaryWrapperInternalConstructor() { } + } + + public class StringListWrapper : List { } + + class MyMyList : GenericListWrapper + { + } + + class MyListString : GenericListWrapper + { + } + + public class GenericListWrapper : List { } + + public class GenericListWrapperPrivateConstructor : GenericListWrapper + { + private GenericListWrapperPrivateConstructor() { } + } + + public class GenericListWrapperInternalConstructor : GenericListWrapper + { + internal GenericListWrapperInternalConstructor() { } + } + + public class StringStackWrapper : Stack + { + public StringStackWrapper() { } + + // For populating test data only. We cannot assume actual input will have this method. + public StringStackWrapper(IList items) + { + foreach (string item in items) + { + Push(item); + } + } + } + + public class GenericStackWrapper : Stack + { + public GenericStackWrapper() { } + + // For populating test data only. We cannot assume actual input will have this method. + public GenericStackWrapper(IList items) + { + foreach (T item in items) + { + Push(item); + } + } + } + + public class GenericStackWrapperPrivateConstructor : GenericStackWrapper + { + private GenericStackWrapperPrivateConstructor() { } + } + + public class GenericStackWrapperInternalConstructor : GenericStackWrapper + { + internal GenericStackWrapperInternalConstructor() { } + } + + public class StringQueueWrapper : Queue + { + public StringQueueWrapper() { } + + // For populating test data only. We cannot assume actual input will have this method. + public StringQueueWrapper(IList items) + { + foreach (string item in items) + { + Enqueue(item); + } + } + } + + public class GenericQueueWrapper : Queue + { + public GenericQueueWrapper() { } + + // For populating test data only. We cannot assume actual input will have this method. + public GenericQueueWrapper(IList items) + { + foreach (T item in items) + { + Enqueue(item); + } + } + } + + public class GenericQueueWrapperPrivateConstructor : GenericQueueWrapper + { + private GenericQueueWrapperPrivateConstructor() { } + } + + public class GenericQueueWrapperInternalConstructor : GenericQueueWrapper + { + internal GenericQueueWrapperInternalConstructor() { } + } + + public class StringHashSetWrapper : HashSet + { + public StringHashSetWrapper() { } + + // For populating test data only. We cannot assume actual input will have this method. + public StringHashSetWrapper(IList items) + { + foreach (string item in items) + { + Add(item); + } + } + } + + public class GenericHashSetWrapper : HashSet + { + public GenericHashSetWrapper() { } + + // For populating test data only. We cannot assume actual input will have this method. + public GenericHashSetWrapper(IList items) + { + foreach (T item in items) + { + Add(item); + } + } + } + + public class StringLinkedListWrapper : LinkedList + { + public StringLinkedListWrapper() { } + + // For populating test data only. We cannot assume actual input will have this method. + public StringLinkedListWrapper(IList items) + { + foreach (string item in items) + { + AddLast(item); + } + } + } + + public class GenericLinkedListWrapper : LinkedList + { + public GenericLinkedListWrapper() { } + + // For populating test data only. We cannot assume actual input will have this method. + public GenericLinkedListWrapper(IList items) + { + foreach (T item in items) + { + AddLast(item); + } + } + } + + public class StringSortedSetWrapper : SortedSet + { + public StringSortedSetWrapper() { } + + // For populating test data only. We cannot assume actual input will have this method. + public StringSortedSetWrapper(IList items) + { + foreach (string item in items) + { + Add(item); + } + } + } + + public class GenericSortedSetWrapper : SortedSet + { + public GenericSortedSetWrapper() { } + + // For populating test data only. We cannot assume actual input will have this method. + public GenericSortedSetWrapper(IList items) + { + foreach (T item in items) + { + Add(item); + } + } + } + + public class StringToStringDictionaryWrapper : Dictionary + { + public StringToStringDictionaryWrapper() { } + + // For populating test data only. We cannot assume actual input will have this method. + public StringToStringDictionaryWrapper(IList> items) + { + foreach (KeyValuePair item in items) + { + Add(item.Key, item.Value); + } + } + } + + public class StringToGenericDictionaryWrapper : Dictionary + { + public StringToGenericDictionaryWrapper() { } + + // For populating test data only. We cannot assume actual input will have this method. + public StringToGenericDictionaryWrapper(IList> items) + { + foreach (KeyValuePair item in items) + { + Add(item.Key, item.Value); + } + } + } + + public class StringToGenericDictionaryWrapperPrivateConstructor : StringToGenericDictionaryWrapper + { + private StringToGenericDictionaryWrapperPrivateConstructor() { } + } + + public class StringToGenericDictionaryWrapperInternalConstructor : StringToGenericDictionaryWrapper + { + internal StringToGenericDictionaryWrapperInternalConstructor() { } + } + + public class StringToStringSortedDictionaryWrapper : SortedDictionary + { + public StringToStringSortedDictionaryWrapper() { } + + // For populating test data only. We cannot assume actual input will have this method. + public StringToStringSortedDictionaryWrapper(IList> items) + { + foreach (KeyValuePair item in items) + { + Add(item.Key, item.Value); + } + } + } + + public class HashSetWithBackingCollection : ICollection + { + private readonly ICollection _inner; + + public HashSetWithBackingCollection() + { + _inner = new HashSet(); + } + + public HashSetWithBackingCollection(IEnumerable values) + { + _inner = new HashSet(values); + } + + public int Count => _inner.Count; + + public bool IsReadOnly => _inner.IsReadOnly; + + public void Add(string item) + { + _inner.Add(item); + } + + public void Clear() + { + _inner.Clear(); + } + + public bool Contains(string item) + { + return _inner.Contains(item); + } + + public void CopyTo(string[] array, int arrayIndex) + { + _inner.CopyTo(array, arrayIndex); + } + + public IEnumerator GetEnumerator() + { + return _inner.GetEnumerator(); + } + + public bool Remove(string item) + { + return _inner.Remove(item); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _inner.GetEnumerator(); + } + } + + public interface IDerivedICollectionOfT : ICollection { } + + public interface IDerivedIDictionaryOfTKeyTValue : IDictionary { } + + public interface IDerivedISetOfT : ISet { } +} diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.ImmutableCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.ImmutableCollections.cs similarity index 99% rename from src/libraries/System.Text.Json/tests/Serialization/TestClasses.ImmutableCollections.cs rename to src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.ImmutableCollections.cs index e28c63d43df527..8296225d4855da 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.ImmutableCollections.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.ImmutableCollections.cs @@ -5,7 +5,6 @@ using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using Xunit; namespace System.Text.Json.Serialization.Tests diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.NonGenericCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.NonGenericCollections.cs similarity index 93% rename from src/libraries/System.Text.Json/tests/Serialization/TestClasses.NonGenericCollections.cs rename to src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.NonGenericCollections.cs index e8bfcbaa5f63b0..ed30039b2b6cfa 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.NonGenericCollections.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.NonGenericCollections.cs @@ -131,16 +131,16 @@ public void Initialize() public class WrapperForIEnumerable : IEnumerable { - private readonly List _list = new List(); + private readonly List _list; - public WrapperForIEnumerable() { } + public WrapperForIEnumerable() + { + _list = new List(); + } - public WrapperForIEnumerable(List items) + public WrapperForIEnumerable(IEnumerable items) { - foreach (object item in items) - { - _list.Add(item); - } + _list = new List(items); } public IEnumerator GetEnumerator() @@ -207,7 +207,17 @@ public class ReadOnlyWrapperForIList : WrapperForIList public class WrapperForIList : IList { - private readonly List _list = new List(); + private readonly List _list; + + public WrapperForIList() + { + _list = new List(); + } + + public WrapperForIList(IEnumerable items) + { + _list = new List(items); + } public object this[int index] { get => ((IList)_list)[index]; set => ((IList)_list)[index] = value; } @@ -276,6 +286,11 @@ public class WrapperForIListInternalConstructor : WrapperForIList internal WrapperForIListInternalConstructor() { } } + public class ReadOnlyWrapperForIDictionary : WrapperForIDictionary + { + public override bool IsReadOnly => true; + } + public class WrapperForIDictionary : IDictionary { private readonly Dictionary _dictionary = new Dictionary(); @@ -284,7 +299,7 @@ public class WrapperForIDictionary : IDictionary public bool IsFixedSize => ((IDictionary)_dictionary).IsFixedSize; - public bool IsReadOnly => ((IDictionary)_dictionary).IsReadOnly; + public virtual bool IsReadOnly => ((IDictionary)_dictionary).IsReadOnly; public ICollection Keys => ((IDictionary)_dictionary).Keys; @@ -406,4 +421,6 @@ public SortedListWrapper(List> items) } } } + + public interface IDerivedIList : IList { } } diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.Polymorphic.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.Polymorphic.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/TestClasses.Polymorphic.cs rename to src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.Polymorphic.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClass.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.SimpleTestClass.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClass.cs rename to src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.SimpleTestClass.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithNullables.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.SimpleTestClassWithNullables.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithNullables.cs rename to src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.SimpleTestClassWithNullables.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithObject.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.SimpleTestClassWithObject.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithObject.cs rename to src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.SimpleTestClassWithObject.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithObjectArrays.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.SimpleTestClassWithObjectArrays.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithObjectArrays.cs rename to src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.SimpleTestClassWithObjectArrays.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithSimpleObject.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.SimpleTestClassWithSimpleObject.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithSimpleObject.cs rename to src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.SimpleTestClassWithSimpleObject.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestStruct.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.SimpleTestStruct.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestStruct.cs rename to src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.SimpleTestStruct.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.cs similarity index 98% rename from src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs rename to src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.cs index 9be040589afe29..0eca0ba16706fc 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/TestClasses/TestClasses.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using Xunit; namespace System.Text.Json.Serialization.Tests @@ -1858,4 +1859,25 @@ public class ClassWithType { public Type Type { get; set; } } + + public class ConverterForInt32 : JsonConverter + { + public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return 25; + } + + public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + } + + public class SimpleSnakeCasePolicy : JsonNamingPolicy + { + public override string ConvertName(string name) + { + return string.Concat(name.Select((x, i) => i > 0 && char.IsUpper(x) ? "_" + x.ToString() : x.ToString())).ToLower(); + } + } } diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.ConcurrentCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.ConcurrentCollections.cs deleted file mode 100644 index cb7947ae640570..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.ConcurrentCollections.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Concurrent; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class ValueTests - { - [Fact] - public static void Read_ConcurrentCollection() - { - ConcurrentDictionary cd = JsonSerializer.Deserialize>(@"{""key"":""value""}"); - Assert.Equal(1, cd.Count); - Assert.Equal("value", cd["key"]); - - ConcurrentQueue qc = JsonSerializer.Deserialize>(@"[""1""]"); - Assert.Equal(1, qc.Count); - bool found = qc.TryPeek(out string val); - Assert.True(found); - Assert.Equal("1", val); - - ConcurrentStack qs = JsonSerializer.Deserialize>(@"[""1""]"); - Assert.Equal(1, qs.Count); - found = qs.TryPeek(out val); - Assert.True(found); - Assert.Equal("1", val); - } - - [Theory] - [InlineData(typeof(BlockingCollection), @"[""1""]")] // Not supported. Not IList, and we don't detect the add method for this collection. - [InlineData(typeof(ConcurrentBag), @"[""1""]")] // Not supported. Not IList, and we don't detect the add method for this collection. - public static void Read_ConcurrentCollection_Throws(Type type, string json) - { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); - Assert.Contains(type.ToString(), ex.Message); - } - - [Theory] - [InlineData(typeof(GenericConcurrentQueuePrivateConstructor), @"[""1""]")] - [InlineData(typeof(GenericConcurrentQueueInternalConstructor), @"[""1""]")] - [InlineData(typeof(GenericConcurrentStackPrivateConstructor), @"[""1""]")] - [InlineData(typeof(GenericConcurrentStackInternalConstructor), @"[""1""]")] - public static void Read_ConcurrentCollection_NoPublicConstructor_Throws(Type type, string json) - { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); - Assert.Contains(type.ToString(), ex.Message); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.GenericCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.GenericCollections.cs deleted file mode 100644 index 84df389d1e76d4..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.GenericCollections.cs +++ /dev/null @@ -1,1271 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Linq; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class ValueTests - { - [Fact] - public static void ReadListOfList() - { - List> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - - Assert.Equal(1, result[0][0]); - Assert.Equal(2, result[0][1]); - Assert.Equal(3, result[1][0]); - Assert.Equal(4, result[1][1]); - - GenericListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); - - Assert.Equal("1", result2[0][0]); - Assert.Equal("2", result2[0][1]); - Assert.Equal("3", result2[1][0]); - Assert.Equal("4", result2[1][1]); - } - - [Fact] - public static void ReadListOfArray() - { - List result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - - Assert.Equal(1, result[0][0]); - Assert.Equal(2, result[0][1]); - Assert.Equal(3, result[1][0]); - Assert.Equal(4, result[1][1]); - - GenericListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); - - Assert.Equal("1", result2[0][0]); - Assert.Equal("2", result2[0][1]); - Assert.Equal("3", result2[1][0]); - Assert.Equal("4", result2[1][1]); - } - - [Fact] - public static void ReadArrayOfList() - { - List[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - - Assert.Equal(1, result[0][0]); - Assert.Equal(2, result[0][1]); - Assert.Equal(3, result[1][0]); - Assert.Equal(4, result[1][1]); - - StringListWrapper[] result2 = JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]"); - Assert.Equal("1", result2[0][0]); - Assert.Equal("2", result2[0][1]); - Assert.Equal("3", result2[1][0]); - Assert.Equal("4", result2[1][1]); - } - - [Fact] - public static void ReadSimpleList() - { - List i = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - Assert.Equal(1, i[0]); - Assert.Equal(2, i[1]); - - i = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, i.Count); - - StringListWrapper i2 = JsonSerializer.Deserialize(@"[""1"",""2""]"); - Assert.Equal("1", i2[0]); - Assert.Equal("2", i2[1]); - - i2 = JsonSerializer.Deserialize(@"[]"); - Assert.Equal(0, i2.Count); - } - - [Fact] - public static void ReadGenericIEnumerableOfGenericIEnumerable() - { - IEnumerable> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IEnumerable ie in result) - { - foreach (int i in ie) - { - Assert.Equal(expected++, i); - } - } - - // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]")); - } - - [Fact] - public static void ReadIEnumerableTOfArray() - { - IEnumerable result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - - // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[1,2],[3, 4]]")); - } - - [Fact] - public static void ReadArrayOfIEnumerableT() - { - IEnumerable[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IEnumerable arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - - // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]")); - } - - [Fact] - public static void ReadSimpleGenericIEnumerable() - { - IEnumerable result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - // There is no way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); - Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); - } - - [Fact] - public static void ReadIListTOfIListT() - { - IList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IList ie in result) - { - foreach (int i in ie) - { - Assert.Equal(expected++, i); - } - } - - GenericIListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); - expected = 1; - - foreach (StringIListWrapper il in result2) - { - foreach (string str in il) - { - Assert.Equal($"{expected++}", str); - } - } - } - - [Fact] - public static void ReadGenericIListOfArray() - { - IList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - - GenericIListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); - expected = 1; - - foreach (string[] arr in result2) - { - foreach (string str in arr) - { - Assert.Equal($"{expected++}", str); - } - } - } - - [Fact] - public static void ReadArrayOfIListT() - { - IList[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IList arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - - StringIListWrapper[] result2 = JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]"); - expected = 1; - - foreach (StringIListWrapper il in result2) - { - foreach (string str in il) - { - Assert.Equal($"{expected++}", str); - } - } - } - - [Fact] - public static void ReadSimpleGenericIList() - { - IList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - StringIListWrapper result2 = JsonSerializer.Deserialize(@"[""1"",""2""]"); - expected = 1; - - foreach (string str in result2) - { - Assert.Equal($"{expected++}", str); - } - - result2 = JsonSerializer.Deserialize(@"[]"); - Assert.Equal(0, result2.Count()); - } - - [Fact] - public static void ReadGenericICollectionOfGenericICollection() - { - ICollection> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ICollection ie in result) - { - foreach (int i in ie) - { - Assert.Equal(expected++, i); - } - } - - GenericICollectionWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); - expected = 1; - - foreach (StringICollectionWrapper ic in result2) - { - foreach (string str in ic) - { - Assert.Equal($"{expected++}", str); - } - } - } - - [Fact] - public static void ReadGenericICollectionOfArray() - { - ICollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - - GenericICollectionWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); - expected = 1; - - foreach (string[] arr in result2) - { - foreach (string str in arr) - { - Assert.Equal($"{expected++}", str); - } - } - } - - [Fact] - public static void ReadArrayOfGenericICollection() - { - ICollection[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ICollection arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadSimpleGenericICollection() - { - ICollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - StringICollectionWrapper result2 = JsonSerializer.Deserialize(@"[""1"",""2""]"); - expected = 1; - - foreach (string str in result2) - { - Assert.Equal($"{expected++}", str); - } - - result2 = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result2.Count()); - } - - [Fact] - public static void ReadGenericIReadOnlyCollectionOfGenericIReadOnlyCollection() - { - IReadOnlyCollection> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IReadOnlyCollection ie in result) - { - foreach (int i in ie) - { - Assert.Equal(expected++, i); - } - } - - // There's no way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]")); - } - - [Fact] - public static void ReadGenericIReadOnlyCollectionOfArray() - { - IReadOnlyCollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[1,2],[3,4]]")); - } - - [Fact] - public static void ReadArrayOfIReadOnlyCollectionT() - { - IReadOnlyCollection[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IReadOnlyCollection arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - - // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]")); - } - - [Fact] - public static void ReadGenericSimpleIReadOnlyCollection() - { - IReadOnlyCollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); - } - - [Fact] - public static void ReadGenericIReadOnlyListOfGenericIReadOnlyList() - { - IReadOnlyList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IReadOnlyList ie in result) - { - foreach (int i in ie) - { - Assert.Equal(expected++, i); - } - } - - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]")); - } - - [Fact] - public static void ReadGenericIReadOnlyListOfArray() - { - IReadOnlyList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - - // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]")); - } - - [Fact] - public static void ReadArrayOfGenericIReadOnlyList() - { - IReadOnlyList[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IReadOnlyList arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - - // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]")); - } - - [Fact] - public static void ReadSimpleGenericIReadOnlyList() - { - IReadOnlyList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); - } - - [Fact] - public static void ReadGenericISetOfGenericISet() - { - ISet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - - if (result.First().Contains(1)) - { - Assert.Equal(new HashSet { 1, 2 }, result.First()); - Assert.Equal(new HashSet { 3, 4 }, result.Last()); - } - else - { - Assert.Equal(new HashSet { 3, 4 }, result.First()); - Assert.Equal(new HashSet { 1, 2 }, result.Last()); - } - - GenericISetWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); - - if (result2.First().Contains("1")) - { - Assert.Equal(new HashSet { "1", "2" }, (ISet)result2.First()); - Assert.Equal(new HashSet { "3", "4" }, (ISet)result2.Last()); - } - else - { - Assert.Equal(new HashSet { "3", "4" }, (ISet)result.First()); - Assert.Equal(new HashSet { "1", "2" }, (ISet)result.Last()); - } - } - - [Fact] - public static void ReadISetTOfHashSetT() - { - ISet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - - if (result.First().Contains(1)) - { - Assert.Equal(new HashSet { 1, 2 }, result.First()); - Assert.Equal(new HashSet { 3, 4 }, result.Last()); - } - else - { - Assert.Equal(new HashSet { 3, 4 }, result.First()); - Assert.Equal(new HashSet { 1, 2 }, result.Last()); - } - } - - [Fact] - public static void ReadHashSetTOfISetT() - { - HashSet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - - if (result.First().Contains(1)) - { - Assert.Equal(new HashSet { 1, 2 }, result.First()); - Assert.Equal(new HashSet { 3, 4 }, result.Last()); - } - else - { - Assert.Equal(new HashSet { 3, 4 }, result.First()); - Assert.Equal(new HashSet { 1, 2 }, result.Last()); - } - } - - [Fact] - public static void ReadISetTOfArray() - { - ISet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - - if (result.First().Contains(1)) - { - Assert.Equal(new HashSet { 1, 2 }, result.First()); - Assert.Equal(new HashSet { 3, 4 }, result.Last()); - } - else - { - Assert.Equal(new HashSet { 3, 4 }, result.First()); - Assert.Equal(new HashSet { 1, 2 }, result.Last()); - } - } - - [Fact] - public static void ReadArrayOfISetT() - { - ISet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - - Assert.Equal(new HashSet { 1, 2 }, result.First()); - Assert.Equal(new HashSet { 3, 4 }, result.Last()); - } - - [Fact] - public static void ReadSimpleISetT() - { - ISet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - - Assert.Equal(new HashSet { 1, 2 }, result); - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void StackTOfStackT() - { - Stack> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 4; - - foreach (Stack st in result) - { - foreach (int i in st) - { - Assert.Equal(expected--, i); - } - } - - GenericStackWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); - expected = 4; - - foreach (StringStackWrapper st in result2) - { - foreach (string str in st) - { - Assert.Equal($"{expected--}", str); - } - } - } - - [Fact] - public static void ReadGenericStackOfArray() - { - Stack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 3; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - - expected = 1; - } - - GenericStackWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); - expected = 3; - - foreach (string[] arr in result2) - { - foreach (string str in arr) - { - Assert.Equal($"{expected++}", str); - } - - expected = 1; - } - } - - [Fact] - public static void ReadArrayOfGenericStack() - { - Stack[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 2; - - foreach (Stack st in result) - { - foreach (int i in st) - { - Assert.Equal(expected--, i); - } - - expected = 4; - } - - StringStackWrapper[] result2 = JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]"); - expected = 2; - - foreach (StringStackWrapper st in result2) - { - foreach (string str in st) - { - Assert.Equal($"{expected--}", str); - } - - expected = 4; - } - } - - [Fact] - public static void ReadSimpleGenericStack() - { - Stack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 2; - - foreach (int i in result) - { - Assert.Equal(expected--, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - StringStackWrapper result2 = JsonSerializer.Deserialize(@"[""1"",""2""]"); - expected = 2; - - foreach (string str in result2) - { - Assert.Equal($"{expected--}", str); - } - - result2 = JsonSerializer.Deserialize(@"[]"); - Assert.Equal(0, result2.Count()); - } - - [Fact] - public static void ReadQueueTOfQueueT() - { - Queue> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (Queue q in result) - { - foreach (int i in q) - { - Assert.Equal(expected++, i); - } - } - - GenericQueueWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); - expected = 1; - - foreach (StringQueueWrapper q in result2) - { - foreach (string str in q) - { - Assert.Equal($"{expected++}", str); - } - } - } - - [Fact] - public static void ReadQueueTOfArray() - { - Queue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadArrayOfIQueueT() - { - Queue[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (Queue q in result) - { - foreach (int i in q) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadSimpleQueueT() - { - Queue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - } - - [Fact] - public static void ReadHashSetTOfHashSetT() - { - HashSet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (HashSet hs in result) - { - foreach (int i in hs) - { - Assert.Equal(expected++, i); - } - } - - GenericHashSetWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); - expected = 1; - - foreach (StringHashSetWrapper hs in result2) - { - foreach (string str in hs) - { - Assert.Equal($"{expected++}", str); - } - } - } - - [Fact] - public static void ReadHashSetTOfArray() - { - HashSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadArrayOfIHashSetT() - { - HashSet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (HashSet hs in result) - { - foreach (int i in hs) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadSimpleHashSetT() - { - HashSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadGenericLinkedListOfGenericLinkedList() - { - LinkedList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (LinkedList l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - - GenericLinkedListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); - expected = 1; - - foreach (StringLinkedListWrapper l in result2) - { - foreach (string str in l) - { - Assert.Equal($"{expected++}", str); - } - } - } - - [Fact] - public static void ReadLinkedListTOfArray() - { - LinkedList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadArrayOfILinkedListT() - { - LinkedList[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (LinkedList l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadSimpleLinkedListT() - { - LinkedList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadArrayOfSortedSetT() - { - SortedSet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (SortedSet s in result) - { - foreach (int i in s) - { - Assert.Equal(expected++, i); - } - } - - StringSortedSetWrapper[] result2 = JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]"); - expected = 1; - - foreach (StringSortedSetWrapper s in result2) - { - foreach (string str in s) - { - Assert.Equal($"{expected++}", str); - } - } - } - - [Fact] - public static void ReadSimpleSortedSetT() - { - SortedSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadSimpleKeyValuePairFail() - { - // Invalid form: no Value - Assert.Throws(() => JsonSerializer.Deserialize>(@"{""Key"": 123}")); - - // Invalid form: extra property - Assert.Throws(() => JsonSerializer.Deserialize>(@"{""Key"": ""Key"", ""Value"": 123, ""Value2"": 456}")); - - // Invalid form: does not contain both Key and Value properties - Assert.Throws(() => JsonSerializer.Deserialize>(@"{""Key"": ""Key"", ""Val"": 123")); - } - - [Fact] - public static void ReadListOfKeyValuePair() - { - List> input = JsonSerializer.Deserialize>>(@"[{""Key"": ""123"", ""Value"": 123},{""Key"": ""456"", ""Value"": 456}]"); - - Assert.Equal(2, input.Count); - Assert.Equal("123", input[0].Key); - Assert.Equal(123, input[0].Value); - Assert.Equal("456", input[1].Key); - Assert.Equal(456, input[1].Value); - } - - [Fact] - public static void ReadKeyValuePairOfList() - { - KeyValuePair> input = JsonSerializer.Deserialize>>(@"{""Key"":""Key"", ""Value"":[1, 2, 3]}"); - - Assert.Equal("Key", input.Key); - Assert.Equal(3, input.Value.Count); - Assert.Equal(1, input.Value[0]); - Assert.Equal(2, input.Value[1]); - Assert.Equal(3, input.Value[2]); - } - - [Theory] - [InlineData(@"{""Key"":""Key"", ""Value"":{""Key"":1, ""Value"":2}}")] - [InlineData(@"{""Key"":""Key"", ""Value"":{""Value"":2, ""Key"":1}}")] - [InlineData(@"{""Value"":{""Key"":1, ""Value"":2}, ""Key"":""Key""}")] - [InlineData(@"{""Value"":{""Value"":2, ""Key"":1}, ""Key"":""Key""}")] - public static void ReadKeyValuePairOfKeyValuePair(string json) - { - KeyValuePair> input = JsonSerializer.Deserialize>>(json); - - Assert.Equal("Key", input.Key); - Assert.Equal(1, input.Value.Key); - Assert.Equal(2, input.Value.Value); - } - - [Fact] - public static void ReadKeyValuePairWithNullValues() - { - { - KeyValuePair kvp = JsonSerializer.Deserialize>(@"{""Key"":""key"",""Value"":null}"); - Assert.Equal("key", kvp.Key); - Assert.Null(kvp.Value); - } - - { - KeyValuePair kvp = JsonSerializer.Deserialize>(@"{""Key"":""key"",""Value"":null}"); - Assert.Equal("key", kvp.Key); - Assert.Null(kvp.Value); - } - - { - KeyValuePair kvp = JsonSerializer.Deserialize>(@"{""Key"":""key"",""Value"":null}"); - Assert.Equal("key", kvp.Key); - Assert.Null(kvp.Value); - } - - { - KeyValuePair> kvp = JsonSerializer.Deserialize>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}"); - Assert.Equal("key", kvp.Key); - Assert.Equal("key", kvp.Value.Key); - Assert.Null(kvp.Value.Value); - } - - { - KeyValuePair> kvp = JsonSerializer.Deserialize>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}"); - Assert.Equal("key", kvp.Key); - Assert.Equal("key", kvp.Value.Key); - Assert.Null(kvp.Value.Value); - } - - { - KeyValuePair> kvp = JsonSerializer.Deserialize>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}"); - Assert.Equal("key", kvp.Key); - Assert.Equal("key", kvp.Value.Key); - Assert.Null(kvp.Value.Value); - } - } - - [Fact] - public static void ReadClassWithNullKeyValuePairValues() - { - string json = - @"{" + - @"""KvpWStrVal"":{" + - @"""Key"":""key""," + - @"""Value"":null" + - @"}," + - @"""KvpWObjVal"":{" + - @"""Key"":""key""," + - @"""Value"":null" + - @"}," + - @"""KvpWClassVal"":{" + - @"""Key"":""key""," + - @"""Value"":null" + - @"}," + - @"""KvpWStrKvpVal"":{" + - @"""Key"":""key""," + - @"""Value"":{" + - @"""Key"":""key""," + - @"""Value"":null" + - @"}" + - @"}," + - @"""KvpWObjKvpVal"":{" + - @"""Key"":""key""," + - @"""Value"":{" + - @"""Key"":""key""," + - @"""Value"":null" + - @"}" + - @"}," + - @"""KvpWClassKvpVal"":{" + - @"""Key"":""key""," + - @"""Value"":{" + - @"""Key"":""key""," + - @"""Value"":null" + - @"}" + - @"}" + - @"}"; - SimpleClassWithKeyValuePairs obj = JsonSerializer.Deserialize(json); - - Assert.Equal("key", obj.KvpWStrVal.Key); - Assert.Equal("key", obj.KvpWObjVal.Key); - Assert.Equal("key", obj.KvpWClassVal.Key); - Assert.Equal("key", obj.KvpWStrKvpVal.Key); - Assert.Equal("key", obj.KvpWObjKvpVal.Key); - Assert.Equal("key", obj.KvpWClassKvpVal.Key); - Assert.Equal("key", obj.KvpWStrKvpVal.Value.Key); - Assert.Equal("key", obj.KvpWObjKvpVal.Value.Key); - Assert.Equal("key", obj.KvpWClassKvpVal.Value.Key); - - Assert.Null(obj.KvpWStrVal.Value); - Assert.Null(obj.KvpWObjVal.Value); - Assert.Null(obj.KvpWClassVal.Value); - Assert.Null(obj.KvpWStrKvpVal.Value.Value); - Assert.Null(obj.KvpWObjKvpVal.Value.Value); - Assert.Null(obj.KvpWClassKvpVal.Value.Value); - } - - [Fact] - public static void ReadSimpleTestClass_GenericCollectionWrappers() - { - SimpleTestClassWithGenericCollectionWrappers obj = JsonSerializer.Deserialize(SimpleTestClassWithGenericCollectionWrappers.s_json); - obj.Verify(); - } - - [Theory] - [MemberData(nameof(ReadSimpleTestClass_GenericWrappers_NoAddMethod))] - public static void ReadSimpleTestClass_GenericWrappers_NoAddMethod_Throws(Type type, string json, Type exceptionMessageType) - { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); - Assert.Contains(exceptionMessageType.ToString(), ex.Message); - } - - public static IEnumerable ReadSimpleTestClass_GenericWrappers_NoAddMethod - { - get - { - yield return new object[] - { - typeof(SimpleTestClassWithStringIEnumerableWrapper), - SimpleTestClassWithStringIEnumerableWrapper.s_json, - typeof(StringIEnumerableWrapper) - }; - yield return new object[] - { - typeof(SimpleTestClassWithStringIReadOnlyCollectionWrapper), - SimpleTestClassWithStringIReadOnlyCollectionWrapper.s_json, - typeof(StringIReadOnlyCollectionWrapper) - }; - yield return new object[] - { - typeof(SimpleTestClassWithStringIReadOnlyListWrapper), - SimpleTestClassWithStringIReadOnlyListWrapper.s_json, - typeof(StringIReadOnlyListWrapper) - }; - yield return new object[] - { - typeof(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper), - SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper.s_json, - typeof(StringToStringIReadOnlyDictionaryWrapper) - }; - } - } - - [Theory] - [InlineData(typeof(ReadOnlyWrapperForIList), @"[""1"", ""2""]")] - [InlineData(typeof(ReadOnlyStringIListWrapper), @"[""1"", ""2""]")] - [InlineData(typeof(ReadOnlyStringICollectionWrapper), @"[""1"", ""2""]")] - [InlineData(typeof(ReadOnlyStringToStringIDictionaryWrapper), @"{""Key"":""key"",""Value"":""value""}")] - public static void ReadReadOnlyCollections_Throws(Type type, string json) - { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); - Assert.Contains(type.ToString(), ex.Message); - } - - [Fact] - public static void Read_HigherOrderCollectionInheritance_Works() - { - const string json = "[\"test\"]"; - Assert.Equal("test", JsonSerializer.Deserialize(json)[0]); - Assert.Equal("test", JsonSerializer.Deserialize>(json).First()); - Assert.Equal("test", JsonSerializer.Deserialize(json).First()); - Assert.Equal("test", JsonSerializer.Deserialize>(json).First()); - Assert.Equal("test", JsonSerializer.Deserialize>(json).First()); - Assert.Equal("test", JsonSerializer.Deserialize(json).First()); - } - - [Theory] - [InlineData(typeof(GenericIEnumerableWrapperPrivateConstructor), @"[""1""]")] - [InlineData(typeof(GenericIEnumerableWrapperInternalConstructor), @"[""1""]")] - [InlineData(typeof(GenericICollectionWrapperPrivateConstructor), @"[""1""]")] - [InlineData(typeof(GenericICollectionWrapperInternalConstructor), @"[""1""]")] - [InlineData(typeof(GenericIListWrapperPrivateConstructor), @"[""1""]")] - [InlineData(typeof(GenericIListWrapperInternalConstructor), @"[""1""]")] - [InlineData(typeof(GenericISetWrapperPrivateConstructor), @"[""1""]")] - [InlineData(typeof(GenericISetWrapperInternalConstructor), @"[""1""]")] - [InlineData(typeof(GenericIDictionaryWrapperPrivateConstructor), @"{""Key"":""Value""}")] - [InlineData(typeof(GenericIDictionaryWrapperInternalConstructor), @"{""Key"":""Value""}")] - [InlineData(typeof(StringToStringIReadOnlyDictionaryWrapperPrivateConstructor), @"{""Key"":""Value""}")] - [InlineData(typeof(StringToStringIReadOnlyDictionaryWrapperInternalConstructor), @"{""Key"":""Value""}")] - [InlineData(typeof(GenericListWrapperPrivateConstructor), @"[""1""]")] - [InlineData(typeof(GenericListWrapperInternalConstructor), @"[""1""]")] - [InlineData(typeof(GenericQueueWrapperPrivateConstructor), @"[""1""]")] - [InlineData(typeof(GenericQueueWrapperInternalConstructor), @"[""1""]")] - [InlineData(typeof(GenericStackWrapperPrivateConstructor), @"[""1""]")] - [InlineData(typeof(GenericStackWrapperInternalConstructor), @"[""1""]")] - [InlineData(typeof(StringToGenericDictionaryWrapperPrivateConstructor), @"{""Key"":""Value""}")] - [InlineData(typeof(StringToGenericDictionaryWrapperInternalConstructor), @"{""Key"":""Value""}")] - public static void Read_Generic_NoPublicConstructor_Throws(Type type, string json) - { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); - Assert.Contains(type.ToString(), ex.Message); - } - - [Fact] - public static void DoesNotCall_CollectionPropertyGetter_EveryTimeElementIsAdded() - { - var networkList = new List { "Network1", "Network2" }; - - string serialized = JsonSerializer.Serialize(new NetworkWrapper { NetworkList = networkList }); - Assert.Equal(@"{""NetworkList"":[""Network1"",""Network2""]}", serialized); - - NetworkWrapper obj = JsonSerializer.Deserialize(serialized); - - int i = 0; - foreach (string network in obj.NetworkList) - { - Assert.Equal(networkList[i], network); - i++; - } - } - - public class NetworkWrapper - { - private string _Networks = string.Empty; - - [JsonIgnore] - public string Networks - { - get => _Networks; - set => _Networks = value ?? string.Empty; - } - - public IEnumerable NetworkList - { - get => Networks.Split(','); - set => Networks = value != null ? string.Join(",", value) : ""; - } - } - - [Fact] - public static void CollectionWith_BackingField_CanRoundtrip() - { - string json = "{\"AllowedGrantTypes\":[\"client_credentials\"]}"; - - Client obj = JsonSerializer.Deserialize(json); - Assert.Equal("client_credentials", obj.AllowedGrantTypes.First()); - - string serialized = JsonSerializer.Serialize(obj); - Assert.Equal(json, serialized); - } - - private class Client - { - private ICollection _allowedGrantTypes = new HashSetWithBackingCollection(); - - public ICollection AllowedGrantTypes - { - get { return _allowedGrantTypes; } - set { _allowedGrantTypes = new HashSetWithBackingCollection(value); } - } - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.ImmutableCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.ImmutableCollections.cs deleted file mode 100644 index b02c1e0b995fe4..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.ImmutableCollections.cs +++ /dev/null @@ -1,638 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Text.Json.Tests; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class ValueTests - { - [Fact] - public static void ReadImmutableArrayOfImmutableArray() - { - ImmutableArray> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ImmutableArray l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadImmutableArrayOfArray() - { - ImmutableArray result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadArrayOfImmutableArray() - { - ImmutableArray[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ImmutableArray l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadSimpleImmutableArray() - { - ImmutableArray result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadSimpleClassWithImmutableArray() - { - SimpleTestClassWithImmutableArray obj = JsonSerializer.Deserialize(SimpleTestClassWithImmutableArray.s_json); - obj.Verify(); - } - - [Fact] - public static void ReadIImmutableListTOfIImmutableListT() - { - IImmutableList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IImmutableList l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadIImmutableListTOfArray() - { - IImmutableList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadArrayOfIIImmutableListT() - { - IImmutableList[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IImmutableList l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadPrimitiveIImmutableListT() - { - IImmutableList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); - Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); - } - - [Fact] - public static void ReadIImmutableStackTOfIImmutableStackT() - { - IImmutableStack> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 4; - - foreach (IImmutableStack l in result) - { - foreach (int i in l) - { - Assert.Equal(expected--, i); - } - } - } - - [Fact] - public static void ReadIImmutableStackTOfArray() - { - IImmutableStack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 3; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - - expected = 1; - } - } - - [Fact] - public static void ReadArrayOfIIImmutableStackT() - { - IImmutableStack[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 2; - - foreach (IImmutableStack l in result) - { - foreach (int i in l) - { - Assert.Equal(expected--, i); - } - - expected = 4; - } - } - - [Fact] - public static void ReadPrimitiveIImmutableStackT() - { - IImmutableStack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 2; - - foreach (int i in result) - { - Assert.Equal(expected--, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); - Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); - } - - [Fact] - public static void ReadIImmutableQueueTOfIImmutableQueueT() - { - IImmutableQueue> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IImmutableQueue l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadIImmutableQueueTOfArray() - { - IImmutableQueue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadArrayOfIImmutableQueueT() - { - IImmutableQueue[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IImmutableQueue l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadPrimitiveIImmutableQueueT() - { - IImmutableQueue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); - Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); - } - - [Fact] - public static void ReadIImmutableSetTOfIImmutableSetT() - { - IImmutableSet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - List expected = new List { 1, 2, 3, 4 }; - - foreach (IImmutableSet l in result) - { - foreach (int i in l) - { - expected.Remove(i); - } - } - - Assert.Equal(0, expected.Count); - } - - [Fact] - public static void ReadIImmutableSetTOfArray() - { - IImmutableSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - List expected = new List { 1, 2, 3, 4 }; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - expected.Remove(i); - } - } - - Assert.Equal(0, expected.Count); - } - - [Fact] - public static void ReadArrayOfIImmutableSetT() - { - IImmutableSet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - List expected = new List { 1, 2, 3, 4 }; - - foreach (IImmutableSet l in result) - { - foreach (int i in l) - { - expected.Remove(i); - } - } - - Assert.Equal(0, expected.Count); - } - - [Fact] - public static void ReadPrimitiveIImmutableSetT() - { - IImmutableSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - List expected = new List { 1, 2 }; - - foreach (int i in result) - { - expected.Remove(i); - } - - Assert.Equal(0, expected.Count); - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); - Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); - } - - [Fact] - public static void ReadImmutableHashSetTOfImmutableHashSetT() - { - ImmutableHashSet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - List expected = new List { 1, 2, 3, 4 }; - - foreach (ImmutableHashSet l in result) - { - foreach (int i in l) - { - expected.Remove(i); - } - } - - Assert.Equal(0, expected.Count); - } - - [Fact] - public static void ReadImmutableHashSetTOfArray() - { - ImmutableHashSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - List expected = new List { 1, 2, 3, 4 }; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - expected.Remove(i); - } - } - - Assert.Equal(0, expected.Count); - } - - [Fact] - public static void ReadArrayOfIImmutableHashSetT() - { - ImmutableHashSet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - List expected = new List { 1, 2, 3, 4 }; - - foreach (ImmutableHashSet l in result) - { - foreach (int i in l) - { - expected.Remove(i); - } - } - - Assert.Equal(0, expected.Count); - } - - [Fact] - public static void ReadPrimitiveImmutableHashSetT() - { - ImmutableHashSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - List expected = new List { 1, 2 }; - - foreach (int i in result) - { - expected.Remove(i); - } - - Assert.Equal(0, expected.Count); - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadImmutableListTOfImmutableListT() - { - ImmutableList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ImmutableList l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadImmutableListTOfArray() - { - ImmutableList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadArrayOfIImmutableListT() - { - ImmutableList[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ImmutableList l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadPrimitiveImmutableListT() - { - ImmutableList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadImmutableStackTOfImmutableStackT() - { - ImmutableStack> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 4; - - foreach (ImmutableStack l in result) - { - foreach (int i in l) - { - Assert.Equal(expected--, i); - } - } - } - - [Fact] - public static void ReadImmutableStackTOfArray() - { - ImmutableStack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 3; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - - expected = 1; - } - } - - [Fact] - public static void ReadArrayOfIImmutableStackT() - { - ImmutableStack[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 2; - - foreach (ImmutableStack l in result) - { - foreach (int i in l) - { - Assert.Equal(expected--, i); - } - - expected = 4; - } - } - - [Fact] - public static void ReadPrimitiveImmutableStackT() - { - ImmutableStack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 2; - - foreach (int i in result) - { - Assert.Equal(expected--, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadImmutableQueueTOfImmutableQueueT() - { - ImmutableQueue> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ImmutableQueue l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadImmutableQueueTOfArray() - { - ImmutableQueue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (int[] arr in result) - { - foreach (int i in arr) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadArrayOfImmutableQueueT() - { - ImmutableQueue[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ImmutableQueue l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadPrimitiveImmutableQueueT() - { - ImmutableQueue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadArrayOfIImmutableSortedSetT() - { - ImmutableSortedSet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ImmutableSortedSet l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadPrimitiveImmutableSortedSetT() - { - ImmutableSortedSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadSimpleTestClass_ImmutableCollectionWrappers_Throws() - { - Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithIImmutableDictionaryWrapper.s_json)); - Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithImmutableListWrapper.s_json)); - Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithImmutableStackWrapper.s_json)); - Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithImmutableQueueWrapper.s_json)); - Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithImmutableSetWrapper.s_json)); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.NonGenericCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.NonGenericCollections.cs deleted file mode 100644 index 4d758ad69ec3f9..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.NonGenericCollections.cs +++ /dev/null @@ -1,503 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections; -using System.Collections.Generic; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class ValueTests - { - [Fact] - public static void ReadGenericIEnumerableOfIEnumerable() - { - IEnumerable result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IEnumerable ie in result) - { - foreach (JsonElement i in ie) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - - // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[1,2],[3,4]]")); - } - - [Fact] - public static void ReadIEnumerableOfArray() - { - IEnumerable result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (JsonElement arr in result) - { - foreach (JsonElement i in arr.EnumerateArray()) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - } - - [Fact] - public static void ReadArrayOfIEnumerable() - { - IEnumerable[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IEnumerable arr in result) - { - foreach (JsonElement i in arr) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - } - - [Fact] - public static void ReadPrimitiveIEnumerable() - { - IEnumerable result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (JsonElement i in result) - { - Assert.Equal(expected++, i.GetInt32()); - } - - result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); - - int count = 0; - IEnumerator e = result.GetEnumerator(); - while (e.MoveNext()) - { - count++; - } - Assert.Equal(0, count); - } - - [Fact] - public static void ReadGenericIListOfIList() - { - IList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IList list in result) - { - foreach (JsonElement i in list) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - - GenericIListWrapper result2 = JsonSerializer.Deserialize>(@"[[1,2],[3,4]]"); - expected = 1; - - foreach (WrapperForIList list in result2) - { - foreach (JsonElement i in list) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - } - - [Fact] - public static void ReadIListOfArray() - { - IList result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (JsonElement arr in result) - { - foreach (JsonElement i in arr.EnumerateArray()) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - } - - [Fact] - public static void ReadArrayOfIList() - { - IList[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IList arr in result) - { - foreach (JsonElement i in arr) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - } - - [Fact] - public static void ReadPrimitiveIList() - { - IList result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (JsonElement i in result) - { - Assert.Equal(expected++, i.GetInt32()); - } - - result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); - - int count = 0; - IEnumerator e = result.GetEnumerator(); - while (e.MoveNext()) - { - count++; - } - Assert.Equal(0, count); - - WrapperForIList result2 = JsonSerializer.Deserialize(@"[1,2]"); - expected = 1; - - foreach (JsonElement i in result2) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - - [Fact] - public static void ReadGenericICollectionOfICollection() - { - ICollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ICollection ie in result) - { - foreach (JsonElement i in ie) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - - // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[1,2],[3,4]]")); - } - - [Fact] - public static void ReadICollectionOfArray() - { - ICollection result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (JsonElement arr in result) - { - foreach (JsonElement i in arr.EnumerateArray()) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - } - - [Fact] - public static void ReadArrayOfICollection() - { - ICollection[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ICollection arr in result) - { - foreach (JsonElement i in arr) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - } - - [Fact] - public static void ReadPrimitiveICollection() - { - ICollection result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (JsonElement i in result) - { - Assert.Equal(expected++, i.GetInt32()); - } - - result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); - - int count = 0; - IEnumerator e = result.GetEnumerator(); - while (e.MoveNext()) - { - count++; - } - Assert.Equal(0, count); - } - - [Fact] - public static void ReadGenericStackOfStack() - { - Stack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 4; - - foreach (Stack stack in result) - { - foreach (JsonElement i in stack) - { - Assert.Equal(expected--, i.GetInt32()); - } - } - } - - [Fact] - public static void ReadStackOfArray() - { - Stack result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 3; - - foreach (JsonElement arr in result) - { - foreach (JsonElement i in arr.EnumerateArray()) - { - Assert.Equal(expected++, i.GetInt32()); - } - expected = 1; - } - } - - [Fact] - public static void ReadArrayOfStack() - { - Stack[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 2; - - foreach (Stack arr in result) - { - foreach (JsonElement i in arr) - { - Assert.Equal(expected--, i.GetInt32()); - } - expected = 4; - } - } - - [Fact] - public static void ReadPrimitiveStack() - { - Stack result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 2; - - foreach (JsonElement i in result) - { - Assert.Equal(expected--, i.GetInt32()); - } - - result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); - - int count = 0; - IEnumerator e = result.GetEnumerator(); - while (e.MoveNext()) - { - count++; - } - Assert.Equal(0, count); - - StackWrapper wrapper = JsonSerializer.Deserialize(@"[1,2]"); - expected = 2; - - foreach (JsonElement i in wrapper) - { - Assert.Equal(expected--, i.GetInt32()); - } - } - - [Fact] - public static void ReadGenericQueueOfQueue() - { - Queue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (Queue ie in result) - { - foreach (JsonElement i in ie) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - } - - [Fact] - public static void ReadQueueOfArray() - { - Queue result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (JsonElement arr in result) - { - foreach (JsonElement i in arr.EnumerateArray()) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - } - - [Fact] - public static void ReadArrayOfQueue() - { - Queue[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (Queue arr in result) - { - foreach (JsonElement i in arr) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - } - - [Fact] - public static void ReadPrimitiveQueue() - { - Queue result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (JsonElement i in result) - { - Assert.Equal(expected++, i.GetInt32()); - } - - result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); - - int count = 0; - IEnumerator e = result.GetEnumerator(); - while (e.MoveNext()) - { - count++; - } - Assert.Equal(0, count); - - QueueWrapper wrapper = JsonSerializer.Deserialize(@"[1,2]"); - expected = 1; - - foreach (JsonElement i in wrapper) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - - [Fact] - public static void ReadArrayListOfArray() - { - ArrayList result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (JsonElement arr in result) - { - foreach (JsonElement i in arr.EnumerateArray()) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - - ArrayListWrapper result2 = JsonSerializer.Deserialize(@"[[1,2],[3,4]]"); - expected = 1; - - foreach (JsonElement arr in result2) - { - foreach (JsonElement i in arr.EnumerateArray()) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - } - - [Fact] - public static void ReadArrayOfArrayList() - { - ArrayList[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ArrayList arr in result) - { - foreach (JsonElement i in arr) - { - Assert.Equal(expected++, i.GetInt32()); - } - } - } - - [Fact] - public static void ReadPrimitiveArrayList() - { - ArrayList result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (JsonElement i in result) - { - Assert.Equal(expected++, i.GetInt32()); - } - - result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); - - int count = 0; - IEnumerator e = result.GetEnumerator(); - while (e.MoveNext()) - { - count++; - } - Assert.Equal(0, count); - } - - [Fact] - public static void ReadSimpleTestClass_NonGenericCollectionWrappers() - { - SimpleTestClassWithNonGenericCollectionWrappers obj = JsonSerializer.Deserialize(SimpleTestClassWithNonGenericCollectionWrappers.s_json); - obj.Verify(); - } - - [Theory] - [MemberData(nameof(ReadSimpleTestClass_NonGenericWrappers_NoAddMethod))] - public static void ReadSimpleTestClass_NonGenericWrappers_NoAddMethod_Throws(Type type, string json, Type exceptionMessageType) - { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); - Assert.Contains(exceptionMessageType.ToString(), ex.Message); - } - - public static IEnumerable ReadSimpleTestClass_NonGenericWrappers_NoAddMethod - { - get - { - yield return new object[] - { - typeof(SimpleTestClassWithIEnumerableWrapper), - SimpleTestClassWithIEnumerableWrapper.s_json, - typeof(WrapperForIEnumerable) - }; - yield return new object[] - { - typeof(SimpleTestClassWithICollectionWrapper), - SimpleTestClassWithICollectionWrapper.s_json, - typeof(WrapperForICollection) - }; - } - } - - [Theory] - [InlineData(typeof(WrapperForIEnumerablePrivateConstructor), @"[""1""]")] - [InlineData(typeof(WrapperForIEnumerableInternalConstructor), @"[""1""]")] - [InlineData(typeof(WrapperForICollectionPrivateConstructor), @"[""1""]")] - [InlineData(typeof(WrapperForICollectionInternalConstructor), @"[""1""]")] - [InlineData(typeof(WrapperForIListPrivateConstructor), @"[""1""]")] - [InlineData(typeof(WrapperForIListInternalConstructor), @"[""1""]")] - [InlineData(typeof(WrapperForIDictionaryPrivateConstructor), @"{""Key"":""Value""}")] - [InlineData(typeof(WrapperForIDictionaryInternalConstructor), @"{""Key"":""Value""}")] - public static void Read_NonGeneric_NoPublicConstructor_Throws(Type type, string json) - { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); - Assert.Contains(type.ToString(), ex.Message); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.ObjectModelCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.ObjectModelCollections.cs deleted file mode 100644 index 722b5f27e95031..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.ObjectModelCollections.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.ObjectModel; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class ValueTests - { - [Fact] - public static void Read_ObjectModelCollection() - { - Collection c = JsonSerializer.Deserialize>("[true,false]"); - Assert.Equal(2, c.Count); - Assert.True(c[0]); - Assert.False(c[1]); - - // Regression test for https://github.com/dotnet/runtime/issues/30686. - ObservableCollection oc = JsonSerializer.Deserialize>("[true,false]"); - Assert.Equal(2, oc.Count); - Assert.True(oc[0]); - Assert.False(oc[1]); - - SimpleKeyedCollection kc = JsonSerializer.Deserialize("[true]"); - Assert.Equal(1, kc.Count); - Assert.True(kc[0]); - } - - [Fact] - public static void Read_ObjectModelCollection_Throws() - { - // No default constructor. - Assert.Throws(() => JsonSerializer.Deserialize>("[true,false]")); - // No default constructor. - Assert.Throws(() => JsonSerializer.Deserialize>("[true,false]")); - // No default constructor. - Assert.Throws(() => JsonSerializer.Deserialize>(@"{""true"":false}")); - - // Abstract types can't be instantiated. This means there's no default constructor, so the type is not supported for deserialization. - Assert.Throws(() => JsonSerializer.Deserialize>("[true]")); - } - - public class SimpleKeyedCollection : KeyedCollection - { - protected override string GetKeyForItem(bool item) - { - return item.ToString(); - } - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.SpecializedCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.SpecializedCollections.cs deleted file mode 100644 index 57c6902471071e..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.SpecializedCollections.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Specialized; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class ValueTests - { - [Fact] - public static void Read_SpecializedCollection() - { - BitVector32 bv32 = JsonSerializer.Deserialize(@"{""Data"":4}"); - // Data property is skipped because it doesn't have a setter. - Assert.Equal(0, bv32.Data); - - HybridDictionary hd = JsonSerializer.Deserialize(@"{""key"":""value""}"); - Assert.Equal(1, hd.Count); - Assert.Equal("value", ((JsonElement)hd["key"]).GetString()); - - IOrderedDictionary iod = JsonSerializer.Deserialize(@"{""key"":""value""}"); - Assert.Equal(1, iod.Count); - Assert.Equal("value", ((JsonElement)iod["key"]).GetString()); - - ListDictionary ld = JsonSerializer.Deserialize(@"{""key"":""value""}"); - Assert.Equal(1, ld.Count); - Assert.Equal("value", ((JsonElement)ld["key"]).GetString()); - } - - [Fact] - public static void Read_SpecializedCollection_Throws() - { - // Add method for this collection only accepts strings, even though it only implements IList which usually - // indicates that the element type is typeof(object). - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"", ""2""]")); - - // Not supported. Not IList, and we don't detect the add method for this collection. - Assert.Throws(() => JsonSerializer.Deserialize(@"[{""Key"": ""key"",""Value"":""value""}]")); - - // Int key is not allowed. - Assert.Throws(() => JsonSerializer.Deserialize(@"{1:""value""}")); - - // Runtime type in this case is IOrderedDictionary (we don't replace with concrete type), which we can't instantiate. - Assert.Throws(() => JsonSerializer.Deserialize(@"{""first"":""John"",""second"":""Jane"",""third"":""Jet""}")); - - // Not supported. Not IList, and we don't detect the add method for this collection. - Assert.Throws(() => JsonSerializer.Deserialize(@"[""NameValueCollection""]")); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.ConcurrentCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.ConcurrentCollections.cs deleted file mode 100644 index cb78774b831d19..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.ConcurrentCollections.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Concurrent; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class ValueTests - { - [Fact] - public static void Write_ConcurrentCollection() - { - Assert.Equal(@"[""1""]", JsonSerializer.Serialize(new BlockingCollection { "1" })); - - Assert.Equal(@"[""1""]", JsonSerializer.Serialize(new ConcurrentBag { "1" })); - - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new ConcurrentDictionary { ["key"] = "value" })); - - ConcurrentQueue qc = new ConcurrentQueue(); - qc.Enqueue("1"); - Assert.Equal(@"[""1""]", JsonSerializer.Serialize(qc)); - - ConcurrentStack qs = new ConcurrentStack(); - qs.Push("1"); - Assert.Equal(@"[""1""]", JsonSerializer.Serialize(qs)); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.GenericCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.GenericCollections.cs deleted file mode 100644 index 327d5a6bab91e6..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.GenericCollections.cs +++ /dev/null @@ -1,924 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Linq; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class ValueTests - { - [Fact] - public static void WriteListOfList() - { - var input = new List> - { - new List() { 1, 2 }, - new List() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - - var input2 = new GenericListWrapper - { - new StringListWrapper() { "1", "2" }, - new StringListWrapper() { "3", "4" } - }; - - json = JsonSerializer.Serialize(input2); - Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); - } - - [Fact] - public static void WriteListOfArray() - { - var input = new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfList() - { - var input = new List[2]; - input[0] = new List() { 1, 2 }; - input[1] = new List() { 3, 4 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveList() - { - var input = new List { 1, 2 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteGenericIEnumerableOfGenericIEnumerable() - { - IEnumerable> input = new List> - { - new List() { 1, 2 }, - new List() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - - GenericIEnumerableWrapper input2 = new GenericIEnumerableWrapper(new List - { - new StringIEnumerableWrapper(new List { "1", "2" }), - new StringIEnumerableWrapper(new List { "3", "4" }), - }); - - json = JsonSerializer.Serialize(input2); - Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); - } - - [Fact] - public static void WriteIEnumerableTOfArray() - { - IEnumerable input = new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfIEnumerableT() - { - IEnumerable[] input = new List[2]; - input[0] = new List() { 1, 2 }; - input[1] = new List() { 3, 4 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveIEnumerableT() - { - IEnumerable input = new List { 1, 2 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteGenericIListOfGenericIList() - { - IList> input = new List> - { - new List() { 1, 2 }, - new List() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - - GenericIListWrapper input2 = new GenericIListWrapper - { - new StringIListWrapper() { "1", "2" }, - new StringIListWrapper() { "3", "4" } - }; - - json = JsonSerializer.Serialize(input2); - Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); - } - - [Fact] - public static void WriteIListTOfArray() - { - IList input = new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfIListT() - { - IList[] input = new List[2]; - input[0] = new List() { 1, 2 }; - input[1] = new List() { 3, 4 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveIListT() - { - IList input = new List { 1, 2 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteGenericICollectionOfGenericICollection() - { - ICollection> input = new List> - { - new List() { 1, 2 }, - new List() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - - GenericICollectionWrapper input2 = new GenericICollectionWrapper - { - new StringICollectionWrapper() { "1", "2" }, - new StringICollectionWrapper() { "3", "4" } - }; - - json = JsonSerializer.Serialize(input2); - Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); - } - - [Fact] - public static void WriteICollectionTOfArray() - { - ICollection input = new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfICollectionT() - { - ICollection[] input = new List[2]; - input[0] = new List() { 1, 2 }; - input[1] = new List() { 3, 4 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveICollectionT() - { - ICollection input = new List { 1, 2 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteGenericIReadOnlyCollectionOfGenericIReadOnlyCollection() - { - IReadOnlyCollection> input = new List> - { - new List() { 1, 2 }, - new List() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - - GenericIReadOnlyCollectionWrapper input2 = new GenericIReadOnlyCollectionWrapper(new List - { - new StringIReadOnlyCollectionWrapper(new List { "1", "2" }), - new StringIReadOnlyCollectionWrapper(new List { "3", "4" }) - }); - - json = JsonSerializer.Serialize(input2); - Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); - } - - [Fact] - public static void WriteIReadOnlyCollectionTOfArray() - { - IReadOnlyCollection input = new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfIReadOnlyCollectionT() - { - IReadOnlyCollection[] input = new List[2]; - input[0] = new List() { 1, 2 }; - input[1] = new List() { 3, 4 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveIReadOnlyCollectionT() - { - IReadOnlyCollection input = new List { 1, 2 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteIReadOnlyListTOfIReadOnlyListT() - { - IReadOnlyList> input = new List> - { - new List() { 1, 2 }, - new List() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - - GenericIReadOnlyListWrapper input2 = new GenericIReadOnlyListWrapper(new List - { - new StringIReadOnlyListWrapper(new List { "1", "2" }), - new StringIReadOnlyListWrapper(new List { "3", "4" }) - }); - - json = JsonSerializer.Serialize(input2); - Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); - } - - [Fact] - public static void WriteIReadOnlyListTOfArray() - { - IReadOnlyList input = new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfIReadOnlyListT() - { - IReadOnlyList[] input = new List[2]; - input[0] = new List() { 1, 2 }; - input[1] = new List() { 3, 4 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveIReadOnlyListT() - { - IReadOnlyList input = new List { 1, 2 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteISetTOfISetT() - { - ISet> input = new HashSet> - { - new HashSet() { 1, 2 }, - new HashSet() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - - // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input = JsonSerializer.Deserialize>>(json); - - if (input.First().Contains(1)) - { - Assert.Equal(new HashSet { 1, 2 }, input.First()); - Assert.Equal(new HashSet { 3, 4 }, input.Last()); - } - else - { - Assert.Equal(new HashSet { 3, 4 }, input.First()); - Assert.Equal(new HashSet { 1, 2 }, input.Last()); - } - - GenericISetWrapper input2 = new GenericISetWrapper - { - new StringISetWrapper() { "1", "2" }, - new StringISetWrapper() { "3", "4" }, - }; - - json = JsonSerializer.Serialize(input2); - - // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input2 = JsonSerializer.Deserialize>(json); - - if (input2.First().Contains("1")) - { - Assert.Equal(new StringISetWrapper() { "1", "2" }, input2.First()); - Assert.Equal(new StringISetWrapper() { "3", "4" }, input2.Last()); - } - else - { - Assert.Equal(new StringISetWrapper() { "3", "4" }, input2.First()); - Assert.Equal(new StringISetWrapper() { "1", "2" }, input2.Last()); - } - } - - [Fact] - public static void WriteISetTOfHashSetT() - { - ISet> input = new HashSet> - { - new HashSet() { 1, 2 }, - new HashSet() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - - // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input = JsonSerializer.Deserialize>>(json); - - if (input.First().Contains(1)) - { - Assert.Equal(new HashSet { 1, 2 }, input.First()); - Assert.Equal(new HashSet { 3, 4 }, input.Last()); - } - else - { - Assert.Equal(new HashSet { 3, 4 }, input.First()); - Assert.Equal(new HashSet { 1, 2 }, input.Last()); - } - } - - [Fact] - public static void WriteHashSetTOfISetT() - { - HashSet> input = new HashSet> - { - new HashSet() { 1, 2 }, - new HashSet() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - - // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input = JsonSerializer.Deserialize>>(json); - - if (input.First().Contains(1)) - { - Assert.Equal(new HashSet { 1, 2 }, input.First()); - Assert.Equal(new HashSet { 3, 4 }, input.Last()); - } - else - { - Assert.Equal(new HashSet { 3, 4 }, input.First()); - Assert.Equal(new HashSet { 1, 2 }, input.Last()); - } - } - - [Fact] - public static void WriteISetTOfArray() - { - ISet input = new HashSet - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Contains("[1,2]", json); - Assert.Contains("[3,4]", json); - } - - [Fact] - public static void WriteArrayOfISetT() - { - ISet[] input = new HashSet[2]; - input[0] = new HashSet() { 1, 2 }; - input[1] = new HashSet() { 3, 4 }; - - string json = JsonSerializer.Serialize(input); - - // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input = JsonSerializer.Deserialize[]>(json); - Assert.Equal(new HashSet { 1, 2 }, input.First()); - Assert.Equal(new HashSet { 3, 4 }, input.Last()); - } - - [Fact] - public static void WritePrimitiveISetT() - { - ISet input = new HashSet { 1, 2 }; - - string json = JsonSerializer.Serialize(input); - Assert.True(json == "[1,2]" || json == "[2,1]"); - } - - [Fact] - public static void WriteStackTOfStackT() - { - Stack> input = new Stack>(new List> - { - new Stack(new List() { 1, 2 }), - new Stack(new List() { 3, 4 }) - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[4,3],[2,1]]", json); - - GenericStackWrapper input2 = new GenericStackWrapper(new List - { - new StringStackWrapper(new List() { "1", "2" }), - new StringStackWrapper(new List() { "3", "4" }) - }); - - json = JsonSerializer.Serialize(input2); - Assert.Equal(@"[[""4"",""3""],[""2"",""1""]]", json); - } - - [Fact] - public static void WriteStackTOfArray() - { - Stack input = new Stack(new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[3,4],[1,2]]", json); - } - - [Fact] - public static void WriteArrayOfStackT() - { - Stack[] input = new Stack[2]; - input[0] = new Stack(new List { 1, 2 }); - input[1] = new Stack(new List { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[2,1],[4,3]]", json); - } - - [Fact] - public static void WritePrimitiveStackT() - { - Stack input = new Stack(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[2,1]", json); - } - - [Fact] - public static void WriteQueueTOfQueueT() - { - Queue> input = new Queue>(new List> - { - new Queue(new List() { 1, 2 }), - new Queue(new List() { 3, 4 }) - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - - GenericQueueWrapper input2 = new GenericQueueWrapper(new List - { - new StringQueueWrapper(new List() { "1", "2" }), - new StringQueueWrapper(new List() { "3", "4" }) - }); - - json = JsonSerializer.Serialize(input2); - Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); - } - - [Fact] - public static void WriteQueueTOfArray() - { - Queue input = new Queue(new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfQueueT() - { - Queue[] input = new Queue[2]; - input[0] = new Queue(new List { 1, 2 }); - input[1] = new Queue(new List { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveQueueT() - { - Queue input = new Queue(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteHashSetTOfHashSetT() - { - HashSet> input = new HashSet>(new List> - { - new HashSet(new List() { 1, 2 }), - new HashSet(new List() { 3, 4 }) - }); - - string json = JsonSerializer.Serialize(input); - - // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input = JsonSerializer.Deserialize>>(json); - - if (input.First().Contains(1)) - { - Assert.Equal(new HashSet { 1, 2 }, input.First()); - Assert.Equal(new HashSet { 3, 4 }, input.Last()); - } - else - { - Assert.Equal(new HashSet { 3, 4 }, input.First()); - Assert.Equal(new HashSet { 1, 2 }, input.Last()); - } - - GenericHashSetWrapper input2 = new GenericHashSetWrapper(new List - { - new StringHashSetWrapper(new List() { "1", "2" }), - new StringHashSetWrapper(new List() { "3", "4" }) - }); - - json = JsonSerializer.Serialize(input2); - - // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input2 = JsonSerializer.Deserialize>(json); - - if (input2.First().Contains("1")) - { - Assert.Equal(new StringHashSetWrapper(new List { "1", "2" }), input2.First()); - Assert.Equal(new StringHashSetWrapper(new List { "3", "4" }), input2.Last()); - } - else - { - Assert.Equal(new StringHashSetWrapper(new List { "3", "4" }), input2.First()); - Assert.Equal(new StringHashSetWrapper(new List { "1", "2" }), input2.Last()); - } - } - - [Fact] - public static void WriteHashSetTOfArray() - { - HashSet input = new HashSet(new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }); - - string json = JsonSerializer.Serialize(input); - Assert.Contains("[1,2]", json); - Assert.Contains("[3,4]", json); - } - - [Fact] - public static void WriteArrayOfHashSetT() - { - HashSet[] input = new HashSet[2]; - input[0] = new HashSet(new List { 1, 2 }); - input[1] = new HashSet(new List { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - - // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input = JsonSerializer.Deserialize[]>(json); - Assert.Equal(new HashSet { 1, 2 }, input.First()); - Assert.Equal(new HashSet { 3, 4 }, input.Last()); - } - - [Fact] - public static void WritePrimitiveHashSetT() - { - HashSet input = new HashSet(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.True(json == "[1,2]" || json == "[2,1]"); - } - - [Fact] - public static void WriteLinkedListTOfLinkedListT() - { - LinkedList> input = new LinkedList>(new List> - { - new LinkedList(new List() { 1, 2 }), - new LinkedList(new List() { 3, 4 }) - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - - GenericLinkedListWrapper input2 = new GenericLinkedListWrapper(new List - { - new StringLinkedListWrapper(new List() { "1", "2" }), - new StringLinkedListWrapper(new List() { "3", "4" }), - }); - - json = JsonSerializer.Serialize(input2); - Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); - } - - [Fact] - public static void WriteLinkedListTOfArray() - { - LinkedList input = new LinkedList(new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfLinkedListT() - { - LinkedList[] input = new LinkedList[2]; - input[0] = new LinkedList(new List { 1, 2 }); - input[1] = new LinkedList(new List { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveLinkedListT() - { - LinkedList input = new LinkedList(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteArrayOfSortedSetT() - { - SortedSet[] input = new SortedSet[2]; - input[0] = new SortedSet(new List { 1, 2 }); - input[1] = new SortedSet(new List { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveSortedSetT() - { - SortedSet input = new SortedSet(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WritePrimitiveKeyValuePair() - { - KeyValuePair input = new KeyValuePair("Key", 123) ; - - string json = JsonSerializer.Serialize(input); - Assert.Equal(@"{""Key"":""Key"",""Value"":123}", json); - } - - [Fact] - public static void WriteListOfKeyValuePair() - { - List> input = new List> - { - new KeyValuePair("123", 123), - new KeyValuePair("456", 456) - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal(@"[{""Key"":""123"",""Value"":123},{""Key"":""456"",""Value"":456}]", json); - } - - [Fact] - public static void WriteKeyValuePairOfList() - { - KeyValuePair> input = new KeyValuePair>("Key", new List { 1, 2, 3 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal(@"{""Key"":""Key"",""Value"":[1,2,3]}", json); - } - - [Fact] - public static void WriteKeyValuePairOfKeyValuePair() - { - KeyValuePair> input = new KeyValuePair>( - "Key", new KeyValuePair("Key", 1)); - - string json = JsonSerializer.Serialize(input); - Assert.Equal(@"{""Key"":""Key"",""Value"":{""Key"":""Key"",""Value"":1}}", json); - } - - [Fact] - public static void WriteKeyValuePairWithNullValues() - { - { - KeyValuePair kvp = new KeyValuePair("key", null); - Assert.Equal(@"{""Key"":""key"",""Value"":null}", JsonSerializer.Serialize(kvp)); - } - - { - KeyValuePair kvp = new KeyValuePair("key", null); - Assert.Equal(@"{""Key"":""key"",""Value"":null}", JsonSerializer.Serialize(kvp)); - } - - { - KeyValuePair kvp = new KeyValuePair("key", null); - Assert.Equal(@"{""Key"":""key"",""Value"":null}", JsonSerializer.Serialize(kvp)); - } - - { - KeyValuePair> kvp = new KeyValuePair>("key", new KeyValuePair("key", null)); - Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", JsonSerializer.Serialize(kvp)); - } - - { - KeyValuePair> kvp = new KeyValuePair>("key", new KeyValuePair("key", null)); - Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", JsonSerializer.Serialize(kvp)); - } - - { - KeyValuePair> kvp = new KeyValuePair>("key", new KeyValuePair("key", null)); - Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", JsonSerializer.Serialize(kvp)); - } - } - - // https://github.com/dotnet/runtime/issues/30388 - [Fact] - public static void WriteClassWithNullKeyValuePairValues_NullWrittenAsEmptyObject() - { - var value = new SimpleClassWithKeyValuePairs() - { - KvpWStrVal = new KeyValuePair("key", null), - KvpWObjVal = new KeyValuePair("key", null), - KvpWClassVal = new KeyValuePair("key", null), - KvpWStrKvpVal = new KeyValuePair>("key", new KeyValuePair("key", null)), - KvpWObjKvpVal = new KeyValuePair>("key", new KeyValuePair("key", null)), - KvpWClassKvpVal = new KeyValuePair>("key", new KeyValuePair("key", null)), - }; - - string result = JsonSerializer.Serialize(value); - - // Roundtrip to ensure serialize was correct. - value = JsonSerializer.Deserialize(result); - Assert.Equal("key", value.KvpWStrVal.Key); - Assert.Equal("key", value.KvpWObjVal.Key); - Assert.Equal("key", value.KvpWClassVal.Key); - Assert.Equal("key", value.KvpWStrKvpVal.Key); - Assert.Equal("key", value.KvpWObjKvpVal.Key); - Assert.Equal("key", value.KvpWClassKvpVal.Key); - Assert.Equal("key", value.KvpWStrKvpVal.Value.Key); - Assert.Equal("key", value.KvpWObjKvpVal.Value.Key); - Assert.Equal("key", value.KvpWClassKvpVal.Value.Key); - - Assert.Null(value.KvpWStrVal.Value); - Assert.Null(value.KvpWObjVal.Value); - Assert.Null(value.KvpWClassVal.Value); - Assert.Null(value.KvpWStrKvpVal.Value.Value); - Assert.Null(value.KvpWObjKvpVal.Value.Value); - Assert.Null(value.KvpWClassKvpVal.Value.Value); - } - - [Fact] - public static void WriteGenericCollectionWrappers() - { - SimpleTestClassWithGenericCollectionWrappers obj1 = new SimpleTestClassWithGenericCollectionWrappers(); - SimpleTestClassWithStringIEnumerableWrapper obj2 = new SimpleTestClassWithStringIEnumerableWrapper(); - SimpleTestClassWithStringIReadOnlyCollectionWrapper obj3 = new SimpleTestClassWithStringIReadOnlyCollectionWrapper(); - SimpleTestClassWithStringIReadOnlyListWrapper obj4 = new SimpleTestClassWithStringIReadOnlyListWrapper(); - SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper obj5 = new SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper(); - - obj1.Initialize(); - obj2.Initialize(); - obj3.Initialize(); - obj4.Initialize(); - obj5.Initialize(); - - Assert.Equal(SimpleTestClassWithGenericCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); - Assert.Equal(SimpleTestClassWithGenericCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); - - Assert.Equal(SimpleTestClassWithStringIEnumerableWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); - Assert.Equal(SimpleTestClassWithStringIEnumerableWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); - - Assert.Equal(SimpleTestClassWithStringIReadOnlyCollectionWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); - Assert.Equal(SimpleTestClassWithStringIReadOnlyCollectionWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); - - Assert.Equal(SimpleTestClassWithStringIReadOnlyListWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); - Assert.Equal(SimpleTestClassWithStringIReadOnlyListWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); - - Assert.Equal(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); - Assert.Equal(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); - } - - [Fact] - public static void ConvertIEnumerableValueTypesThenSerialize() - { - IEnumerable valueAs = Enumerable.Range(0, 5).Select(x => new ValueA { Value = x }).ToList(); - IEnumerable valueBs = valueAs.Select(x => new ValueB { Value = x.Value }); - - string expectedJson = @"[{""Value"":0},{""Value"":1},{""Value"":2},{""Value"":3},{""Value"":4}]"; - Assert.Equal(expectedJson, JsonSerializer.Serialize>(valueBs)); - } - - public class SimpleClassWithKeyValuePairs - { - public KeyValuePair KvpWStrVal { get; set; } - public KeyValuePair KvpWObjVal { get; set; } - public KeyValuePair KvpWClassVal { get; set; } - public KeyValuePair> KvpWStrKvpVal { get; set; } - public KeyValuePair> KvpWObjKvpVal { get; set; } - public KeyValuePair> KvpWClassKvpVal { get; set; } - } - - public class ValueA - { - public int Value { get; set; } - } - - public class ValueB - { - public int Value { get; set; } - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.ImmutableCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.ImmutableCollections.cs deleted file mode 100644 index 3a7be82e8bd5f9..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.ImmutableCollections.cs +++ /dev/null @@ -1,512 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Text.Json.Tests; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class ValueTests - { - [Fact] - public static void WriteImmutableArrayOfImmutableArray() - { - ImmutableArray> input = ImmutableArray.CreateRange(new List>{ - ImmutableArray.CreateRange(new List() { 1, 2 }), - ImmutableArray.CreateRange(new List() { 3, 4 }) - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteImmutableArrayOfArray() - { - ImmutableArray input = ImmutableArray.CreateRange(new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfImmutableArray() - { - ImmutableArray[] input = new ImmutableArray[2]; - input[0] = ImmutableArray.CreateRange(new List() { 1, 2 }); - input[1] = ImmutableArray.CreateRange(new List() { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteSimpleImmutableArray() - { - ImmutableArray input = ImmutableArray.CreateRange(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteIImmutableListTOfIImmutableListT() - { - IImmutableList> input = ImmutableList.CreateRange(new List>{ - ImmutableList.CreateRange(new List() { 1, 2 }), - ImmutableList.CreateRange(new List() { 3, 4 }) - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteIImmutableListTOfArray() - { - IImmutableList input = ImmutableList.CreateRange(new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteSimpleClassWithImmutableArray() - { - SimpleTestClassWithImmutableArray obj = new SimpleTestClassWithImmutableArray(); - obj.Initialize(); - - Assert.Equal(SimpleTestClassWithImmutableArray.s_json, JsonSerializer.Serialize(obj)); - } - - [Fact] - public static void WriteSimpleClassWithObjectImmutableArray() - { - SimpleTestClassWithObjectImmutableArray obj = new SimpleTestClassWithObjectImmutableArray(); - obj.Initialize(); - - Assert.Equal(SimpleTestClassWithObjectImmutableArray.s_json, JsonSerializer.Serialize(obj)); - } - - [Fact] - public static void WriteArrayOfIImmutableListT() - { - IImmutableList[] input = new IImmutableList[2]; - input[0] = ImmutableList.CreateRange(new List() { 1, 2 }); - input[1] = ImmutableList.CreateRange(new List() { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveIImmutableListT() - { - IImmutableList input = ImmutableList.CreateRange(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - - StringIImmutableListWrapper input2 = new StringIImmutableListWrapper(new List { "1", "2" }); - - json = JsonSerializer.Serialize(input2); - Assert.Equal(@"[""1"",""2""]", json); - } - - [Fact] - public static void WriteIImmutableStackTOfIImmutableStackT() - { - IImmutableStack> input = ImmutableStack.CreateRange(new List>{ - ImmutableStack.CreateRange(new List() { 1, 2 }), - ImmutableStack.CreateRange(new List() { 3, 4 }) - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[4,3],[2,1]]", json); - } - - [Fact] - public static void WriteIImmutableStackTOfArray() - { - IImmutableStack input = ImmutableStack.CreateRange(new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[3,4],[1,2]]", json); - } - - [Fact] - public static void WriteArrayOfIImmutableStackT() - { - IImmutableStack[] input = new IImmutableStack[2]; - input[0] = ImmutableStack.CreateRange(new List() { 1, 2 }); - input[1] = ImmutableStack.CreateRange(new List() { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[2,1],[4,3]]", json); - } - - [Fact] - public static void WritePrimitiveIImmutableStackT() - { - IImmutableStack input = ImmutableStack.CreateRange(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[2,1]", json); - - StringIImmutableStackWrapper input2 = new StringIImmutableStackWrapper(new List { "1", "2" }); - - json = JsonSerializer.Serialize(input2); - Assert.Equal(@"[""2"",""1""]", json); - } - - [Fact] - public static void WriteIImmutableQueueTOfIImmutableQueueT() - { - IImmutableQueue> input = ImmutableQueue.CreateRange(new List>{ - ImmutableQueue.CreateRange(new List() { 1, 2 }), - ImmutableQueue.CreateRange(new List() { 3, 4 }) - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteIImmutableQueueTOfArray() - { - IImmutableQueue input = ImmutableQueue.CreateRange(new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfIImmutableQueueT() - { - IImmutableQueue[] input = new IImmutableQueue[2]; - input[0] = ImmutableQueue.CreateRange(new List() { 1, 2 }); - input[1] = ImmutableQueue.CreateRange(new List() { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveIImmutableQueueT() - { - IImmutableQueue input = ImmutableQueue.CreateRange(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - - StringIImmutableQueueWrapper input2 = new StringIImmutableQueueWrapper(new List { "1", "2" }); - - json = JsonSerializer.Serialize(input2); - Assert.Equal(@"[""1"",""2""]", json); - } - - [Fact] - public static void WriteIImmutableSetTOfIImmutableSetT() - { - IImmutableSet> input = ImmutableHashSet.CreateRange(new List>{ - ImmutableHashSet.CreateRange(new List() { 1, 2 }), - ImmutableHashSet.CreateRange(new List() { 3, 4 }) - }); - - string json = JsonSerializer.Serialize(input); - Assert.Contains("[1,2]", json); - Assert.Contains("[3,4]", json); - } - - [Fact] - public static void WriteIImmutableSetTOfArray() - { - IImmutableSet input = ImmutableHashSet.CreateRange(new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }); - - string json = JsonSerializer.Serialize(input); - Assert.Contains("[1,2]", json); - Assert.Contains("[3,4]", json); - } - - [Fact] - public static void WriteArrayOfIImmutableSetT() - { - IImmutableSet[] input = new IImmutableSet[2]; - input[0] = ImmutableHashSet.CreateRange(new List() { 1, 2 }); - input[1] = ImmutableHashSet.CreateRange(new List() { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveIImmutableSetT() - { - IImmutableSet input = ImmutableHashSet.CreateRange(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - - StringIImmutableSetWrapper input2 = new StringIImmutableSetWrapper(new List { "1", "2" }); - - json = JsonSerializer.Serialize(input2); - Assert.True(json == @"[""1"",""2""]" || json == @"[""2"",""1""]"); - } - - [Fact] - public static void WriteImmutableHashSetTOfImmutableHashSetT() - { - ImmutableHashSet> input = ImmutableHashSet.CreateRange(new List>{ - ImmutableHashSet.CreateRange(new List() { 1, 2 }), - ImmutableHashSet.CreateRange(new List() { 3, 4 }) - }); - - string json = JsonSerializer.Serialize(input); - Assert.Contains("[1,2]", json); - Assert.Contains("[3,4]", json); - } - - [Fact] - public static void WriteImmutableHashSetTOfArray() - { - ImmutableHashSet input = ImmutableHashSet.CreateRange(new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }); - - string json = JsonSerializer.Serialize(input); - Assert.Contains("[1,2]", json); - Assert.Contains("[3,4]", json); - } - - [Fact] - public static void WriteArrayOfImmutableHashSetT() - { - ImmutableHashSet[] input = new ImmutableHashSet[2]; - input[0] = ImmutableHashSet.CreateRange(new List() { 1, 2 }); - input[1] = ImmutableHashSet.CreateRange(new List() { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveImmutableHashSetT() - { - ImmutableHashSet input = ImmutableHashSet.CreateRange(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteImmutableListTOfImmutableListT() - { - ImmutableList> input = ImmutableList.CreateRange(new List>{ - ImmutableList.CreateRange(new List() { 1, 2 }), - ImmutableList.CreateRange(new List() { 3, 4 }) - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteImmutableListTOfArray() - { - ImmutableList input = ImmutableList.CreateRange(new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfImmutableListT() - { - ImmutableList[] input = new ImmutableList[2]; - input[0] = ImmutableList.CreateRange(new List() { 1, 2 }); - input[1] = ImmutableList.CreateRange(new List() { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveImmutableListT() - { - ImmutableList input = ImmutableList.CreateRange(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteImmutableStackTOfImmutableStackT() - { - ImmutableStack> input = ImmutableStack.CreateRange(new List>{ - ImmutableStack.CreateRange(new List() { 1, 2 }), - ImmutableStack.CreateRange(new List() { 3, 4 }) - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[4,3],[2,1]]", json); - } - - [Fact] - public static void WriteImmutableStackTOfArray() - { - ImmutableStack input = ImmutableStack.CreateRange(new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[3,4],[1,2]]", json); - } - - [Fact] - public static void WriteArrayOfImmutableStackT() - { - ImmutableStack[] input = new ImmutableStack[2]; - input[0] = ImmutableStack.CreateRange(new List() { 1, 2 }); - input[1] = ImmutableStack.CreateRange(new List() { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[2,1],[4,3]]", json); - } - - [Fact] - public static void WritePrimitiveImmutableStackT() - { - ImmutableStack input = ImmutableStack.CreateRange(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[2,1]", json); - } - - [Fact] - public static void WriteImmutableQueueTOfImmutableQueueT() - { - ImmutableQueue> input = ImmutableQueue.CreateRange(new List>{ - ImmutableQueue.CreateRange(new List() { 1, 2 }), - ImmutableQueue.CreateRange(new List() { 3, 4 }) - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteImmutableQueueTOfArray() - { - ImmutableQueue input = ImmutableQueue.CreateRange(new List - { - new int[] { 1, 2 }, - new int[] { 3, 4 } - }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfImmutableQueueT() - { - ImmutableQueue[] input = new ImmutableQueue[2]; - input[0] = ImmutableQueue.CreateRange(new List() { 1, 2 }); - input[1] = ImmutableQueue.CreateRange(new List() { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveImmutableQueueT() - { - ImmutableQueue input = ImmutableQueue.CreateRange(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteArrayOfImmutableSortedSetT() - { - ImmutableSortedSet[] input = new ImmutableSortedSet[2]; - input[0] = ImmutableSortedSet.CreateRange(new List() { 1, 2 }); - input[1] = ImmutableSortedSet.CreateRange(new List() { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveImmutableSortedSetT() - { - ImmutableSortedSet input = ImmutableSortedSet.CreateRange(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteImmutableCollectionWrappers() - { - SimpleTestClassWithIImmutableDictionaryWrapper obj1 = new SimpleTestClassWithIImmutableDictionaryWrapper(); - SimpleTestClassWithImmutableListWrapper obj2 = new SimpleTestClassWithImmutableListWrapper(); - SimpleTestClassWithImmutableStackWrapper obj3 = new SimpleTestClassWithImmutableStackWrapper(); - SimpleTestClassWithImmutableQueueWrapper obj4 = new SimpleTestClassWithImmutableQueueWrapper(); - SimpleTestClassWithImmutableSetWrapper obj5 = new SimpleTestClassWithImmutableSetWrapper(); - - obj1.Initialize(); - obj2.Initialize(); - obj3.Initialize(); - obj4.Initialize(); - obj5.Initialize(); - - Assert.Equal(SimpleTestClassWithIImmutableDictionaryWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); - Assert.Equal(SimpleTestClassWithIImmutableDictionaryWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); - - Assert.Equal(SimpleTestClassWithImmutableListWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); - Assert.Equal(SimpleTestClassWithImmutableListWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); - - Assert.Equal(SimpleTestClassWithImmutableStackWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); - Assert.Equal(SimpleTestClassWithImmutableStackWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); - - Assert.Equal(SimpleTestClassWithImmutableQueueWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); - Assert.Equal(SimpleTestClassWithImmutableQueueWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); - - Assert.Equal(SimpleTestClassWithImmutableSetWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); - Assert.Equal(SimpleTestClassWithImmutableSetWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.NonGenericCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.NonGenericCollections.cs deleted file mode 100644 index 32f75c4a160a47..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.NonGenericCollections.cs +++ /dev/null @@ -1,349 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections; -using System.Collections.Generic; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class ValueTests - { - [Fact] - public static void WriteIEnumerableOfIEnumerable() - { - IEnumerable input = new List> - { - new List() { 1, 2 }, - new List() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - - WrapperForIEnumerable input2 = new WrapperForIEnumerable(new List - { - new List() { 1, 2 }, - new List() { 3, 4 }, - }); - - json = JsonSerializer.Serialize(input2); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteGenericIEnumerableOfIEnumerable() - { - IEnumerable input = new List - { - new List() { 1, 2 }, - new List() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfIEnumerable() - { - IEnumerable[] input = new IEnumerable[2]; - input[0] = new List() { 1, 2 }; - input[1] = new List() { 3, 4 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveIEnumerable() - { - IEnumerable input = new List { 1, 2 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteIListOfIList() - { - IList input = new List - { - new List() { 1, 2 }, - new List() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - - WrapperForIList input2 = new WrapperForIList - { - new List() { 1, 2 }, - new List() { 3, 4 }, - }; - - json = JsonSerializer.Serialize(input2); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteIListGenericOfIList() - { - IList input = new List - { - new List() { 1, 2 }, - new List() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfIList() - { - IList[] input = new IList[2]; - input[0] = new List() { 1, 2 }; - input[1] = new List() { 3, 4 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveIList() - { - IList input = new List { 1, 2 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteICollectionOfICollection() - { - ICollection input = new List - { - new List() { 1, 2 }, - new List() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteGenericICollectionOfICollection() - { - ICollection input = new List - { - new List() { 1, 2 }, - new List() { 3, 4 } - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - - GenericICollectionWrapper input2 = new GenericICollectionWrapper - { - new WrapperForICollection(new List { 1, 2 }), - new WrapperForICollection(new List { 3, 4 }), - }; - - json = JsonSerializer.Serialize(input2); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfICollection() - { - ICollection[] input = new List[2]; - input[0] = new List() { 1, 2 }; - input[1] = new List() { 3, 4 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveICollection() - { - ICollection input = new List { 1, 2 }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteStackOfStack() - { - Stack input = new Stack(); - input.Push(new Stack(new List() { 1, 2 })); - input.Push(new Stack(new List() { 3, 4 })); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[4,3],[2,1]]", json); - } - - [Fact] - public static void WriteGenericStackOfStack() - { - Stack input = new Stack(); - input.Push(new Stack(new List() { 1, 2 })); - input.Push(new Stack(new List() { 3, 4 })); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[4,3],[2,1]]", json); - - GenericStackWrapper input2 = new GenericStackWrapper(); - input2.Push(new StackWrapper(new List { 1, 2 })); - input2.Push(new StackWrapper(new List { 3, 4 })); - - json = JsonSerializer.Serialize(input2); - Assert.Equal("[[4,3],[2,1]]", json); - } - - [Fact] - public static void WriteArrayOfStack() - { - Stack[] input = new Stack[2]; - input[0] = new Stack(new List() { 1, 2 }); - input[1] = new Stack(new List() { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[2,1],[4,3]]", json); - } - - [Fact] - public static void WritePrimitiveStack() - { - Stack input = new Stack( new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[2,1]", json); - } - - [Fact] - public static void WriteQueueOfQueue() - { - Queue input = new Queue(); - input.Enqueue(new Queue(new List() { 1, 2 })); - input.Enqueue(new Queue(new List() { 3, 4 })); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteGenericQueueOfQueue() - { - Queue input = new Queue(); - input.Enqueue(new Queue(new List() { 1, 2 })); - input.Enqueue(new Queue(new List() { 3, 4 })); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - - GenericQueueWrapper input2 = new GenericQueueWrapper(); - input2.Enqueue(new QueueWrapper(new List() { 1, 2 })); - input2.Enqueue(new QueueWrapper(new List() { 3, 4 })); - - json = JsonSerializer.Serialize(input2); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfQueue() - { - Queue[] input = new Queue[2]; - input[0] = new Queue(new List() { 1, 2 }); - input[1] = new Queue(new List() { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveQueue() - { - Queue input = new Queue(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteArrayListOfArrayList() - { - ArrayList input = new ArrayList - { - new ArrayList(new List() { 1, 2 }), - new ArrayList(new List() { 3, 4 }) - }; - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - - ArrayListWrapper input2 = new ArrayListWrapper(new List - { - new ArrayListWrapper(new List() { 1, 2 }), - new ArrayListWrapper(new List() { 3, 4 }) - }); - - json = JsonSerializer.Serialize(input2); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WriteArrayOfArrayList() - { - ArrayList[] input = new ArrayList[2]; - input[0] = new ArrayList(new List() { 1, 2 }); - input[1] = new ArrayList(new List() { 3, 4 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[[1,2],[3,4]]", json); - } - - [Fact] - public static void WritePrimitiveArrayList() - { - ArrayList input = new ArrayList(new List { 1, 2 }); - - string json = JsonSerializer.Serialize(input); - Assert.Equal("[1,2]", json); - } - - [Fact] - public static void WriteNonGenericCollectionWrappers() - { - SimpleTestClassWithNonGenericCollectionWrappers obj1 = new SimpleTestClassWithNonGenericCollectionWrappers(); - SimpleTestClassWithIEnumerableWrapper obj2 = new SimpleTestClassWithIEnumerableWrapper(); - SimpleTestClassWithICollectionWrapper obj3 = new SimpleTestClassWithICollectionWrapper(); - SimpleTestClassWithStackWrapper obj4 = new SimpleTestClassWithStackWrapper(); - SimpleTestClassWithQueueWrapper obj5 = new SimpleTestClassWithQueueWrapper(); - - obj1.Initialize(); - obj2.Initialize(); - obj3.Initialize(); - obj4.Initialize(); - obj5.Initialize(); - - Assert.Equal(SimpleTestClassWithNonGenericCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); - Assert.Equal(SimpleTestClassWithNonGenericCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); - - Assert.Equal(SimpleTestClassWithIEnumerableWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); - Assert.Equal(SimpleTestClassWithIEnumerableWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); - - Assert.Equal(SimpleTestClassWithICollectionWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); - Assert.Equal(SimpleTestClassWithICollectionWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); - - Assert.Equal(SimpleTestClassWithStackWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); - Assert.Equal(SimpleTestClassWithStackWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); - - Assert.Equal(SimpleTestClassWithQueueWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); - Assert.Equal(SimpleTestClassWithQueueWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.ObjectModelCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.ObjectModelCollections.cs deleted file mode 100644 index d1559ef1f9a028..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.ObjectModelCollections.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Collections.ObjectModel; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class ValueTests - { - [Fact] - public static void Write_ObjectModelCollection() - { - Collection c = new Collection() { true, false }; - Assert.Equal("[true,false]", JsonSerializer.Serialize(c)); - - ObservableCollection oc = new ObservableCollection() { true, false }; - Assert.Equal("[true,false]", JsonSerializer.Serialize(oc)); - - SimpleKeyedCollection kc = new SimpleKeyedCollection() { true, false }; - Assert.Equal("[true,false]", JsonSerializer.Serialize(kc)); - Assert.Equal("[true,false]", JsonSerializer.Serialize>(kc)); - - ReadOnlyCollection roc = new ReadOnlyCollection(new List { true, false }); - Assert.Equal("[true,false]", JsonSerializer.Serialize(roc)); - - ReadOnlyObservableCollection rooc = new ReadOnlyObservableCollection(oc); - Assert.Equal("[true,false]", JsonSerializer.Serialize(rooc)); - - ReadOnlyDictionary rod = new ReadOnlyDictionary(new Dictionary { ["true"] = false }); - Assert.Equal(@"{""true"":false}", JsonSerializer.Serialize(rod)); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.SpecializedCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.SpecializedCollections.cs deleted file mode 100644 index 2b88bbbff7c810..00000000000000 --- a/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.SpecializedCollections.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Specialized; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class ValueTests - { - [Fact] - public static void Write_SpecializedCollection() - { - Assert.Equal(@"{""Data"":4}", JsonSerializer.Serialize(new BitVector32(4))); - Assert.Equal(@"{""Data"":4}", JsonSerializer.Serialize(new BitVector32(4))); - - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new HybridDictionary { ["key"] = "value" })); - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new HybridDictionary { ["key"] = "value" })); - - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new OrderedDictionary { ["key"] = "value" })); - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new OrderedDictionary { ["key"] = "value" })); - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new OrderedDictionary { ["key"] = "value" })); - - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new ListDictionary { ["key"] = "value" })); - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new ListDictionary { ["key"] = "value" })); - - Assert.Equal(@"[""1"",""2""]", JsonSerializer.Serialize(new StringCollection { "1", "2" })); - Assert.Equal(@"[""1"",""2""]", JsonSerializer.Serialize(new StringCollection { "1", "2" })); - - Assert.Equal(@"[{""Key"":""key"",""Value"":""value""}]", JsonSerializer.Serialize(new StringDictionary { ["key"] = "value" })); - Assert.Equal(@"[{""Key"":""key"",""Value"":""value""}]", JsonSerializer.Serialize(new StringDictionary { ["key"] = "value" })); - - // Element type returned by .GetEnumerator for this type is string, specifically the key. - Assert.Equal(@"[""key""]", JsonSerializer.Serialize(new NameValueCollection { ["key"] = "value" })); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj index 15566344a8e86f..2693078629bfcb 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj @@ -1,13 +1,14 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) - $(DefineConstants);BUILDING_INBOX_LIBRARY true + + + $(DefineConstants);BUILDING_INBOX_LIBRARY + - - CommonTest\System\IO\WrappedMemoryStream.cs - + @@ -36,53 +37,69 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + - + + @@ -90,37 +107,25 @@ + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - @@ -134,10 +139,8 @@ - - - CommonTest\System\Buffers\ArrayBufferWriter.cs - + + diff --git a/src/libraries/System.Text.Json/tests/Utf8JsonReaderTests.cs b/src/libraries/System.Text.Json/tests/Utf8JsonReaderTests.cs index 392eeb1cc9dd12..3b80897e1ed94d 100644 --- a/src/libraries/System.Text.Json/tests/Utf8JsonReaderTests.cs +++ b/src/libraries/System.Text.Json/tests/Utf8JsonReaderTests.cs @@ -4380,7 +4380,6 @@ public static IEnumerable InvalidJsonStrings new object[] {"+0", 0, 0}, new object[] {"+1", 0, 0}, new object[] {"0e", 0, 2}, - new object[] {"0.", 0, 2}, new object[] {"0.1e", 0, 4}, new object[] {"01", 0, 1}, new object[] {"1a", 0, 1}, diff --git a/src/libraries/System.Text.Json/tests/Utf8JsonWriterTests.cs b/src/libraries/System.Text.Json/tests/Utf8JsonWriterTests.cs index 82ab7224874152..5ead06b20c4bc7 100644 --- a/src/libraries/System.Text.Json/tests/Utf8JsonWriterTests.cs +++ b/src/libraries/System.Text.Json/tests/Utf8JsonWriterTests.cs @@ -2982,6 +2982,16 @@ public void WritingTooLargeBase64Bytes(bool formatted, bool skipValidation) Assert.Throws(() => jsonUtf8.WriteBase64StringValue(value.AsSpan(0, 125_000_001))); } + using (var jsonUtf8 = new Utf8JsonWriter(output, options)) + { + Assert.Throws(() => jsonUtf8.WriteBase64String(value.AsSpan(0, 166_666_667), value.AsSpan(0, 1))); + } + + using (var jsonUtf8 = new Utf8JsonWriter(output, options)) + { + Assert.Throws(() => jsonUtf8.WriteBase64String(Encoding.UTF8.GetString(value).ToCharArray().AsSpan(0, 166_666_667), value.AsSpan(0, 1))); + } + using (var jsonUtf8 = new Utf8JsonWriter(output, options)) { Assert.Throws(() => jsonUtf8.WriteBase64StringValue(value)); diff --git a/src/libraries/System.Text.RegularExpressions/ref/System.Text.RegularExpressions.cs b/src/libraries/System.Text.RegularExpressions/ref/System.Text.RegularExpressions.cs index f97324489a8bf5..c063564dd4244a 100644 --- a/src/libraries/System.Text.RegularExpressions/ref/System.Text.RegularExpressions.cs +++ b/src/libraries/System.Text.RegularExpressions/ref/System.Text.RegularExpressions.cs @@ -37,12 +37,12 @@ public void CopyTo(System.Text.RegularExpressions.Capture[] array, int arrayInde int System.Collections.Generic.IList.IndexOf(System.Text.RegularExpressions.Capture item) { throw null; } void System.Collections.Generic.IList.Insert(int index, System.Text.RegularExpressions.Capture item) { } void System.Collections.Generic.IList.RemoveAt(int index) { } - int System.Collections.IList.Add(object value) { throw null; } + int System.Collections.IList.Add(object? value) { throw null; } void System.Collections.IList.Clear() { } - bool System.Collections.IList.Contains(object value) { throw null; } - int System.Collections.IList.IndexOf(object value) { throw null; } - void System.Collections.IList.Insert(int index, object value) { } - void System.Collections.IList.Remove(object value) { } + bool System.Collections.IList.Contains(object? value) { throw null; } + int System.Collections.IList.IndexOf(object? value) { throw null; } + void System.Collections.IList.Insert(int index, object? value) { } + void System.Collections.IList.Remove(object? value) { } void System.Collections.IList.RemoveAt(int index) { } } public partial class Group : System.Text.RegularExpressions.Capture @@ -80,12 +80,12 @@ public void CopyTo(System.Text.RegularExpressions.Group[] array, int arrayIndex) int System.Collections.Generic.IList.IndexOf(System.Text.RegularExpressions.Group item) { throw null; } void System.Collections.Generic.IList.Insert(int index, System.Text.RegularExpressions.Group item) { } void System.Collections.Generic.IList.RemoveAt(int index) { } - int System.Collections.IList.Add(object value) { throw null; } + int System.Collections.IList.Add(object? value) { throw null; } void System.Collections.IList.Clear() { } - bool System.Collections.IList.Contains(object value) { throw null; } - int System.Collections.IList.IndexOf(object value) { throw null; } - void System.Collections.IList.Insert(int index, object value) { } - void System.Collections.IList.Remove(object value) { } + bool System.Collections.IList.Contains(object? value) { throw null; } + int System.Collections.IList.IndexOf(object? value) { throw null; } + void System.Collections.IList.Insert(int index, object? value) { } + void System.Collections.IList.Remove(object? value) { } void System.Collections.IList.RemoveAt(int index) { } #pragma warning disable CS8614 // Nullability of reference types in type of parameter doesn't match implicitly implemented member. public bool TryGetValue(string key, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Text.RegularExpressions.Group? value) { throw null; } @@ -122,12 +122,12 @@ public void CopyTo(System.Text.RegularExpressions.Match[] array, int arrayIndex) int System.Collections.Generic.IList.IndexOf(System.Text.RegularExpressions.Match item) { throw null; } void System.Collections.Generic.IList.Insert(int index, System.Text.RegularExpressions.Match item) { } void System.Collections.Generic.IList.RemoveAt(int index) { } - int System.Collections.IList.Add(object value) { throw null; } + int System.Collections.IList.Add(object? value) { throw null; } void System.Collections.IList.Clear() { } - bool System.Collections.IList.Contains(object value) { throw null; } - int System.Collections.IList.IndexOf(object value) { throw null; } - void System.Collections.IList.Insert(int index, object value) { } - void System.Collections.IList.Remove(object value) { } + bool System.Collections.IList.Contains(object? value) { throw null; } + int System.Collections.IList.IndexOf(object? value) { throw null; } + void System.Collections.IList.Insert(int index, object? value) { } + void System.Collections.IList.Remove(object? value) { } void System.Collections.IList.RemoveAt(int index) { } } public delegate string MatchEvaluator(System.Text.RegularExpressions.Match match); diff --git a/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj b/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj index f3a73189a0b72c..f323acb4be5010 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj +++ b/src/libraries/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj @@ -1,4 +1,4 @@ - + System.Text.RegularExpressions true @@ -47,18 +47,14 @@ - - Common\System\NotImplemented.cs - - - Common\System\HexConverter.cs - - - Common\System\Collections\Generic\ValueListBuilder.cs - - - Common\System\Text\ValueStringBuilder.cs - + + + + @@ -73,4 +69,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunnerFactory.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunnerFactory.cs index 2d2d930e975481..e025fdf69f080e 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunnerFactory.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunnerFactory.cs @@ -25,8 +25,8 @@ public CompiledRegexRunnerFactory(DynamicMethod goMethod, DynamicMethod findFirs protected internal override RegexRunner CreateInstance() => new CompiledRegexRunner( - _go ??= (Action)_goMethod.CreateDelegate(typeof(Action)), - _findFirstChar ??= (Func)_findFirstCharMethod.CreateDelegate(typeof(Func)), + _go ??= _goMethod.CreateDelegate>(), + _findFirstChar ??= _findFirstCharMethod.CreateDelegate>(), _trackcount); } } diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs index 8df7e0676361a8..f327e8c2f0afe3 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs @@ -85,6 +85,7 @@ internal sealed class RegexCode public const int Oneloopatomic = 43; // lef,back char,min,max (?> a {,n} ) public const int Notoneloopatomic = 44; // lef,back set,min,max (?> . {,n} ) public const int Setloopatomic = 45; // lef,back set,min,max (?> [\d]{,n} ) + public const int UpdateBumpalong = 46; // updates the bumpalong position to the current position // Modifiers for alternate modes public const int Mask = 63; // Mask to get unmodified ordinary operator @@ -184,6 +185,7 @@ public static int OpcodeSize(int opcode) case Backjump: case Forejump: case Stop: + case UpdateBumpalong: return 1; case One: @@ -273,6 +275,7 @@ private static string OperatorDescription(int Opcode) Oneloopatomic => nameof(Oneloopatomic), Notoneloopatomic => nameof(Notoneloopatomic), Setloopatomic => nameof(Setloopatomic), + UpdateBumpalong => nameof(UpdateBumpalong), _ => "(unknown)" }; diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs index 4f07dfca187869..e3d87bfc5c3dce 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs @@ -49,9 +49,9 @@ internal abstract class RegexCompiler private static readonly MethodInfo s_charIsDigitMethod = typeof(char).GetMethod("IsDigit", new Type[] { typeof(char) })!; private static readonly MethodInfo s_charIsWhiteSpaceMethod = typeof(char).GetMethod("IsWhiteSpace", new Type[] { typeof(char) })!; private static readonly MethodInfo s_charGetUnicodeInfo = typeof(char).GetMethod("GetUnicodeCategory", new Type[] { typeof(char) })!; - private static readonly MethodInfo s_charToLowerMethod = typeof(char).GetMethod("ToLower", new Type[] { typeof(char), typeof(CultureInfo) })!; private static readonly MethodInfo s_charToLowerInvariantMethod = typeof(char).GetMethod("ToLowerInvariant", new Type[] { typeof(char) })!; private static readonly MethodInfo s_cultureInfoGetCurrentCultureMethod = typeof(CultureInfo).GetMethod("get_CurrentCulture")!; + private static readonly MethodInfo s_cultureInfoGetTextInfoMethod = typeof(CultureInfo).GetMethod("get_TextInfo")!; #if DEBUG private static readonly MethodInfo s_debugWriteLine = typeof(Debug).GetMethod("WriteLine", new Type[] { typeof(string) })!; #endif @@ -68,6 +68,7 @@ internal abstract class RegexCompiler private static readonly MethodInfo s_stringAsSpanIntIntMethod = typeof(MemoryExtensions).GetMethod("AsSpan", new Type[] { typeof(string), typeof(int), typeof(int) })!; private static readonly MethodInfo s_stringGetCharsMethod = typeof(string).GetMethod("get_Chars", new Type[] { typeof(int) })!; private static readonly MethodInfo s_stringIndexOfCharInt = typeof(string).GetMethod("IndexOf", new Type[] { typeof(char), typeof(int) })!; + private static readonly MethodInfo s_textInfoToLowerMethod = typeof(TextInfo).GetMethod("ToLower", new Type[] { typeof(char) })!; /// /// The max recursion depth used for computations that can recover for not walking the entire node tree. @@ -88,10 +89,7 @@ internal abstract class RegexCompiler private LocalBuilder? _runtrackLocal; private LocalBuilder? _runstackposLocal; private LocalBuilder? _runstackLocal; - private LocalBuilder? _temp1Local; - private LocalBuilder? _temp2Local; - private LocalBuilder? _temp3Local; - private LocalBuilder? _cultureLocal; // current culture is cached in local variable to prevent many thread local storage accesses for CultureInfo.CurrentCulture + private LocalBuilder? _textInfoLocal; // cached to avoid extraneous TLS hits from CurrentCulture and virtual calls to TextInfo private LocalBuilder? _loopTimeoutCounterLocal; // timeout counter for setrep and setloop protected RegexOptions _options; // options @@ -103,11 +101,13 @@ internal abstract class RegexCompiler protected int _leadingAnchor; // the set of anchors protected bool _hasTimeout; // whether the regex has a non-infinite timeout - private Label[]? _labels; // a label for every operation in _codes - private BacktrackNote[]? _notes; // a list of the backtracking states to be generated - private int _notecount; // true count of _notes (allocation grows exponentially) - protected int _trackcount; // count of backtracking states (used to reduce allocations) - private Label _backtrack; // label for backtracking + private Label[]? _labels; // a label for every operation in _codes + private BacktrackNote[]? _notes; // a list of the backtracking states to be generated + private int _notecount; // true count of _notes (allocation grows exponentially) + protected int _trackcount; // count of backtracking states (used to reduce allocations) + private Label _backtrack; // label for backtracking + private Stack? _int32LocalsPool; // pool of Int32 local variables + private Stack? _readOnlySpanCharLocalsPool; // pool of ReadOnlySpan local variables private int _regexopcode; // the current opcode being processed private int _codepos; // the current code being translated @@ -289,46 +289,20 @@ private int AddUniqueTrack(int i, int flags) protected void Ldstr(string str) => _ilg!.Emit(OpCodes.Ldstr, str); /// A macro for the various forms of Ldc. - protected void Ldc(int i) - { - Debug.Assert(_ilg != null); - - if ((uint)i < 8) - { - _ilg.Emit(i switch - { - 0 => OpCodes.Ldc_I4_0, - 1 => OpCodes.Ldc_I4_1, - 2 => OpCodes.Ldc_I4_2, - 3 => OpCodes.Ldc_I4_3, - 4 => OpCodes.Ldc_I4_4, - 5 => OpCodes.Ldc_I4_5, - 6 => OpCodes.Ldc_I4_6, - _ => OpCodes.Ldc_I4_7, - }); - } - else if (i <= 127 && i >= -128) - { - _ilg.Emit(OpCodes.Ldc_I4_S, (byte)i); - } - else - { - _ilg.Emit(OpCodes.Ldc_I4, i); - } - } + protected void Ldc(int i) => _ilg!.Emit(OpCodes.Ldc_I4, i); /// A macro for _ilg.Emit(OpCodes.Ldc_I8). protected void LdcI8(long i) => _ilg!.Emit(OpCodes.Ldc_I8, i); - /// A macro for _ilg.Emit(OpCodes.Dup). - private void Dup() => _ilg!.Emit(OpCodes.Dup); - /// A macro for _ilg.Emit(OpCodes.Ret). protected void Ret() => _ilg!.Emit(OpCodes.Ret); /// A macro for _ilg.Emit(OpCodes.Newobj, constructor). protected void Newobj(ConstructorInfo constructor) => _ilg!.Emit(OpCodes.Newobj, constructor); + /// A macro for _ilg.Emit(OpCodes.Dup). + protected void Dup() => _ilg!.Emit(OpCodes.Dup); + /// A macro for _ilg.Emit(OpCodes.Rem_Un). private void RemUn() => _ilg!.Emit(OpCodes.Rem_Un); @@ -374,10 +348,12 @@ protected void Ldc(int i) /// A macro for _ilg.Emit(OpCodes.Shr). private void Shr() => _ilg!.Emit(OpCodes.Shr); - /// A macro for _ilg.Emit(OpCodes.Ldloc_S). - private void Ldloc(LocalBuilder lt) => _ilg!.Emit(OpCodes.Ldloc_S, lt); + /// A macro for _ilg.Emit(OpCodes.Ldloc). + /// ILGenerator will switch to the optimal form based on the local's index. + private void Ldloc(LocalBuilder lt) => _ilg!.Emit(OpCodes.Ldloc, lt); /// A macro for _ilg.Emit(OpCodes.Ldloca). + /// ILGenerator will switch to the optimal form based on the local's index. private void Ldloca(LocalBuilder lt) => _ilg!.Emit(OpCodes.Ldloca, lt); /// A macro for _ilg.Emit(OpCodes.Ldind_U2). @@ -392,8 +368,9 @@ protected void Ldc(int i) /// A macro for _ilg.Emit(OpCodes.Unaligned). private void Unaligned(byte alignment) => _ilg!.Emit(OpCodes.Unaligned, alignment); - /// A macro for _ilg.Emit(OpCodes.Stloc_S). - private void Stloc(LocalBuilder lt) => _ilg!.Emit(OpCodes.Stloc_S, lt); + /// A macro for _ilg.Emit(OpCodes.Stloc). + /// ILGenerator will switch to the optimal form based on the local's index. + private void Stloc(LocalBuilder lt) => _ilg!.Emit(OpCodes.Stloc, lt); /// A macro for _ilg.Emit(OpCodes.Ldarg_0). protected void Ldthis() => _ilg!.Emit(OpCodes.Ldarg_0); @@ -483,6 +460,9 @@ private void Mvlocfld(LocalBuilder lt, FieldInfo ft) /// A macro for _ilg.Emit(OpCodes.Bge_S) (short jump). private void Bge(Label l) => _ilg!.Emit(OpCodes.Bge_S, l); + /// A macro for _ilg.Emit(OpCodes.Bge_Un_S) (short jump). + private void BgeUn(Label l) => _ilg!.Emit(OpCodes.Bge_Un_S, l); + /// A macro for _ilg.Emit(OpCodes.Bgt_S) (short jump). private void Bgt(Label l) => _ilg!.Emit(OpCodes.Bgt_S, l); @@ -510,7 +490,7 @@ private void Mvlocfld(LocalBuilder lt, FieldInfo ft) private LocalBuilder DeclareInt32() => _ilg!.DeclareLocal(typeof(int)); /// Declares a local CultureInfo. - private LocalBuilder? DeclareCultureInfo() => _ilg!.DeclareLocal(typeof(CultureInfo)); // cache local variable to avoid unnecessary TLS + private LocalBuilder? DeclareTextInfo() => _ilg!.DeclareLocal(typeof(TextInfo)); /// Declares a local int[]. private LocalBuilder DeclareInt32Array() => _ilg!.DeclareLocal(typeof(int[])); @@ -520,12 +500,54 @@ private void Mvlocfld(LocalBuilder lt, FieldInfo ft) private LocalBuilder DeclareReadOnlySpanChar() => _ilg!.DeclareLocal(typeof(ReadOnlySpan)); + /// Rents an Int32 local variable slot from the pool of locals. + /// + /// Care must be taken to Dispose of the returned when it's no longer needed, + /// and also not to jump into the middle of a block involving a rented local from outside of that block. + /// + private RentedLocalBuilder RentInt32Local() => new RentedLocalBuilder( + _int32LocalsPool ??= new Stack(), + _int32LocalsPool.TryPop(out LocalBuilder? iterationLocal) ? iterationLocal : DeclareInt32()); + + /// Rents a ReadOnlySpan(char) local variable slot from the pool of locals. + /// + /// Care must be taken to Dispose of the returned when it's no longer needed, + /// and also not to jump into the middle of a block involving a rented local from outside of that block. + /// + private RentedLocalBuilder RentReadOnlySpanCharLocal() => new RentedLocalBuilder( + _readOnlySpanCharLocalsPool ??= new Stack(1), // capacity == 1 as we currently don't expect overlapping instances + _readOnlySpanCharLocalsPool.TryPop(out LocalBuilder? iterationLocal) ? iterationLocal : DeclareReadOnlySpanChar()); + + /// Returned a rented local to the pool. + private struct RentedLocalBuilder : IDisposable + { + private Stack _pool; + private LocalBuilder _local; + + internal RentedLocalBuilder(Stack pool, LocalBuilder local) + { + _local = local; + _pool = pool; + } + + public static implicit operator LocalBuilder(RentedLocalBuilder local) => local._local; + + public void Dispose() + { + Debug.Assert(_pool != null); + Debug.Assert(_local != null); + Debug.Assert(!_pool.Contains(_local)); + _pool.Push(_local); + this = default; + } + } + /// Loads the char to the right of the current position. private void Rightchar() { Ldloc(_runtextLocal!); Ldloc(_runtextposLocal!); - Callvirt(s_stringGetCharsMethod); + Call(s_stringGetCharsMethod); } /// Loads the char to the right of the current position and advances the current position. @@ -533,7 +555,7 @@ private void Rightcharnext() { Ldloc(_runtextLocal!); Ldloc(_runtextposLocal!); - Callvirt(s_stringGetCharsMethod); + Call(s_stringGetCharsMethod); Ldloc(_runtextposLocal!); Ldc(1); Add(); @@ -547,19 +569,19 @@ private void Leftchar() Ldloc(_runtextposLocal!); Ldc(1); Sub(); - Callvirt(s_stringGetCharsMethod); + Call(s_stringGetCharsMethod); } /// Loads the char to the left of the current position and advances (leftward). private void Leftcharnext() { - Ldloc(_runtextLocal!); Ldloc(_runtextposLocal!); Ldc(1); Sub(); - Dup(); Stloc(_runtextposLocal!); - Callvirt(s_stringGetCharsMethod); + Ldloc(_runtextLocal!); + Ldloc(_runtextposLocal!); + Call(s_stringGetCharsMethod); } /// Creates a backtrack note and pushes the switch index it on the tracking stack. @@ -615,12 +637,12 @@ private void TrackUnique2(int i) /// Prologue to code that will push an element on the tracking stack. private void ReadyPushTrack() { - Ldloc(_runtrackLocal!); Ldloc(_runtrackposLocal!); Ldc(1); Sub(); - Dup(); Stloc(_runtrackposLocal!); + Ldloc(_runtrackLocal!); + Ldloc(_runtrackposLocal!); } /// Pops an element off the tracking stack (leave it on the operand stack). @@ -629,10 +651,13 @@ private void PopTrack() Ldloc(_runtrackLocal!); Ldloc(_runtrackposLocal!); LdelemI4(); + using RentedLocalBuilder tmp = RentInt32Local(); + Stloc(tmp); Ldloc(_runtrackposLocal!); Ldc(1); Add(); Stloc(_runtrackposLocal!); + Ldloc(tmp); } /// Retrieves the top entry on the tracking stack without popping. @@ -666,12 +691,12 @@ internal void ReadyReplaceStack(int i) /// Prologue to code that will push an element on the grouping stack. private void ReadyPushStack() { - Ldloc(_runstackLocal!); Ldloc(_runstackposLocal!); Ldc(1); Sub(); - Dup(); Stloc(_runstackposLocal!); + Ldloc(_runstackLocal!); + Ldloc(_runstackposLocal!); } /// Retrieves the top entry on the stack without popping. @@ -685,13 +710,16 @@ private void TopStack() /// Pops an element off the grouping stack (leave it on the operand stack). private void PopStack() { + using RentedLocalBuilder elementLocal = RentInt32Local(); Ldloc(_runstackLocal!); Ldloc(_runstackposLocal!); LdelemI4(); + Stloc(elementLocal); Ldloc(_runstackposLocal!); Ldc(1); Add(); Stloc(_runstackposLocal!); + Ldloc(elementLocal); } /// Pops 1 element off the grouping stack and discards it. @@ -771,15 +799,16 @@ private void Goto(int i) /// Sets the culture local to CultureInfo.CurrentCulture. private void InitLocalCultureInfo() { - Debug.Assert(_cultureLocal != null); + Debug.Assert(_textInfoLocal != null); Call(s_cultureInfoGetCurrentCultureMethod); - Stloc(_cultureLocal); + Callvirt(s_cultureInfoGetTextInfoMethod); + Stloc(_textInfoLocal); } - /// Whether ToLower operations should be performed with the invariant culture as opposed to the one in . - private bool UseToLowerInvariant => _cultureLocal == null || (_options & RegexOptions.CultureInvariant) != 0; + /// Whether ToLower operations should be performed with the invariant culture as opposed to the one in . + private bool UseToLowerInvariant => _textInfoLocal == null || (_options & RegexOptions.CultureInvariant) != 0; - /// Invokes either char.ToLower(..., _culture) or char.ToLowerInvariant(...). + /// Invokes either char.ToLowerInvariant(c) or _textInfo.ToLower(c). private void CallToLower() { if (UseToLowerInvariant) @@ -788,8 +817,48 @@ private void CallToLower() } else { - Ldloc(_cultureLocal!); - Call(s_charToLowerMethod); + using RentedLocalBuilder currentCharLocal = RentInt32Local(); + Stloc(currentCharLocal); + Ldloc(_textInfoLocal!); + Ldloc(currentCharLocal); + Callvirt(s_textInfoToLowerMethod); + } + } + + /// Gets whether the specified character participates in case conversion. + /// + /// This method is used to perform operations as if they were case-sensitive even if they're + /// specified as being case-insensitive. Such a reduction can be applied when the only character + /// that would lower-case to the one being searched for / compared against is that character itself. + /// + private static bool ParticipatesInCaseConversion(int comparison) + { + Debug.Assert((uint)comparison <= char.MaxValue); + + switch (char.GetUnicodeCategory((char)comparison)) + { + case UnicodeCategory.ClosePunctuation: + case UnicodeCategory.ConnectorPunctuation: + case UnicodeCategory.Control: + case UnicodeCategory.DashPunctuation: + case UnicodeCategory.DecimalDigitNumber: + case UnicodeCategory.FinalQuotePunctuation: + case UnicodeCategory.InitialQuotePunctuation: + case UnicodeCategory.LineSeparator: + case UnicodeCategory.OpenPunctuation: + case UnicodeCategory.OtherNumber: + case UnicodeCategory.OtherPunctuation: + case UnicodeCategory.ParagraphSeparator: + case UnicodeCategory.SpaceSeparator: + // All chars in these categories meet the criteria that the only way + // `char.ToLower(toTest, AnyCulture) == charInAboveCategory` is when + // toTest == charInAboveCategory. + return false; + + default: + // We don't know (without testing the character against every other + // character), so assume it does. + return true; } } @@ -843,7 +912,7 @@ private void GenerateForwardSection() /// private void GenerateMiddleSection() { - LocalBuilder limitLocal = _temp1Local!; + using RentedLocalBuilder limitLocal = RentInt32Local(); Label afterDoubleStack = DefineLabel(); Label afterDoubleTrack = DefineLabel(); @@ -870,7 +939,7 @@ private void GenerateMiddleSection() Bge(afterDoubleStack); Mvlocfld(_runstackposLocal!, s_runstackposField); Ldthis(); - Callvirt(s_doubleStackMethod); + Call(s_doubleStackMethod); Mvfldloc(s_runstackposField, _runstackposLocal!); Mvfldloc(s_runstackField, _runstackLocal!); MarkLabel(afterDoubleStack); @@ -887,7 +956,7 @@ private void GenerateMiddleSection() Bge(afterDoubleTrack); Mvlocfld(_runtrackposLocal!, s_runtrackposField); Ldthis(); - Callvirt(s_doubleTrackMethod); + Call(s_doubleTrackMethod); Mvfldloc(s_runtrackposField, _runtrackposLocal!); Mvfldloc(s_runtrackField, _runtrackLocal!); MarkLabel(afterDoubleTrack); @@ -930,6 +999,8 @@ private void GenerateBacktrackSection() protected void GenerateFindFirstChar() { Debug.Assert(_code != null); + _int32LocalsPool?.Clear(); + _readOnlySpanCharLocalsPool?.Clear(); _runtextposLocal = DeclareInt32(); _runtextendLocal = DeclareInt32(); @@ -938,9 +1009,7 @@ protected void GenerateFindFirstChar() _runtextbegLocal = DeclareInt32(); } _runtextLocal = DeclareString(); - _temp1Local = DeclareInt32(); - _temp2Local = DeclareInt32(); - _cultureLocal = null; + _textInfoLocal = null; if (!_options.HasFlag(RegexOptions.CultureInvariant)) { bool needsCulture = _options.HasFlag(RegexOptions.IgnoreCase) || _boyerMoorePrefix?.CaseInsensitive == true; @@ -958,7 +1027,7 @@ protected void GenerateFindFirstChar() if (needsCulture) { - _cultureLocal = DeclareCultureInfo(); + _textInfoLocal = DeclareTextInfo(); InitLocalCultureInfo(); } } @@ -1104,7 +1173,7 @@ protected void GenerateFindFirstChar() Beq(l2); Ldthisfld(s_runtextField); Ldloc(_runtextposLocal); - Callvirt(s_stringGetCharsMethod); + Call(s_stringGetCharsMethod); Ldc('\n'); Beq(l2); MarkLabel(l1); @@ -1152,40 +1221,44 @@ protected void GenerateFindFirstChar() // if (runtextpos > runtextbeg... Ldloc(_runtextposLocal!); Ldthisfld(s_runtextbegField); - BleFar(atBeginningOfLine); + Ble(atBeginningOfLine); // ... && runtext[runtextpos - 1] != '\n') { ... } Ldthisfld(s_runtextField); Ldloc(_runtextposLocal); Ldc(1); Sub(); - Callvirt(s_stringGetCharsMethod); + Call(s_stringGetCharsMethod); Ldc('\n'); - BeqFar(atBeginningOfLine); + Beq(atBeginningOfLine); // int tmp = runtext.IndexOf('\n', runtextpos); Ldthisfld(s_runtextField); Ldc('\n'); Ldloc(_runtextposLocal); Call(s_stringIndexOfCharInt); - Dup(); - - // if (tmp == -1) - // { - // runtextpos = runtextend; - // return false; - // } - Label foundNextLine = DefineLabel(); - Ldc(-1); - BneFar(foundNextLine); - Pop(); - BrFar(returnFalse); + using (RentedLocalBuilder newlinePos = RentInt32Local()) + { + Stloc(newlinePos); + + // if (newlinePos == -1) + // { + // runtextpos = runtextend; + // return false; + // } + Label foundNextLine = DefineLabel(); + Ldloc(newlinePos); + Ldc(-1); + Bne(foundNextLine); + BrFar(returnFalse); - // runtextpos = tmp + 1; - MarkLabel(foundNextLine); - Ldc(1); - Add(); - Stloc(_runtextposLocal); + // runtextpos = newlinePos + 1; + MarkLabel(foundNextLine); + Ldloc(newlinePos); + Ldc(1); + Add(); + Stloc(_runtextposLocal); + } MarkLabel(atBeginningOfLine); } @@ -1196,8 +1269,6 @@ protected void GenerateFindFirstChar() if (_boyerMoorePrefix != null && _boyerMoorePrefix.NegativeUnicode == null) { // Compiled Boyer-Moore string matching - LocalBuilder chLocal = _temp1Local; - LocalBuilder testLocal = _temp1Local; LocalBuilder limitLocal; int beforefirst; int last; @@ -1267,135 +1338,142 @@ protected void GenerateFindFirstChar() // ch = runtext[runtextpos]; // if (ch == lastChar) goto partialMatch; Rightchar(); - if (_boyerMoorePrefix.CaseInsensitive) + if (_boyerMoorePrefix.CaseInsensitive && ParticipatesInCaseConversion(chLast)) { CallToLower(); } - Dup(); - Stloc(chLocal); - Ldc(chLast); Label lPartialMatch = DefineLabel(); - BeqFar(lPartialMatch); - - // ch -= lowAscii; - // if (ch > (highAscii - lowAscii)) goto defaultAdvance; - Ldloc(chLocal); - Ldc(_boyerMoorePrefix.LowASCII); - Sub(); - Dup(); - Stloc(chLocal); - Ldc(_boyerMoorePrefix.HighASCII - _boyerMoorePrefix.LowASCII); - BgtUn(lDefaultAdvance); - - // int offset = "lookupstring"[num]; - // goto advance; - int negativeRange = _boyerMoorePrefix.HighASCII - _boyerMoorePrefix.LowASCII + 1; - if (negativeRange > 1) + using (RentedLocalBuilder chLocal = RentInt32Local()) { - // Create a string to store the lookup table we use to find the offset. - Debug.Assert(_boyerMoorePrefix.Pattern.Length <= char.MaxValue, "RegexBoyerMoore should have limited the size allowed."); - string negativeLookup = string.Create(negativeRange, (thisRef: this, beforefirst), (span, state) => + Stloc(chLocal); + Ldloc(chLocal); + Ldc(chLast); + + BeqFar(lPartialMatch); + + // ch -= lowAscii; + // if (ch > (highAscii - lowAscii)) goto defaultAdvance; + Ldloc(chLocal); + Ldc(_boyerMoorePrefix.LowASCII); + Sub(); + Stloc(chLocal); + Ldloc(chLocal); + Ldc(_boyerMoorePrefix.HighASCII - _boyerMoorePrefix.LowASCII); + BgtUn(lDefaultAdvance); + + // int offset = "lookupstring"[num]; + // goto advance; + int negativeRange = _boyerMoorePrefix.HighASCII - _boyerMoorePrefix.LowASCII + 1; + if (negativeRange > 1) { - // Store the offsets into the string. RightToLeft has negative offsets, so to support it with chars (unsigned), we negate - // the values to be stored in the string, and then at run time after looking up the offset in the string, negate it again. - for (int i = 0; i < span.Length; i++) + // Create a string to store the lookup table we use to find the offset. + Debug.Assert(_boyerMoorePrefix.Pattern.Length <= char.MaxValue, "RegexBoyerMoore should have limited the size allowed."); + string negativeLookup = string.Create(negativeRange, (thisRef: this, beforefirst), (span, state) => { - int offset = state.thisRef._boyerMoorePrefix!.NegativeASCII[i + state.thisRef._boyerMoorePrefix.LowASCII]; - if (offset == state.beforefirst) + // Store the offsets into the string. RightToLeft has negative offsets, so to support it with chars (unsigned), we negate + // the values to be stored in the string, and then at run time after looking up the offset in the string, negate it again. + for (int i = 0; i < span.Length; i++) { - offset = state.thisRef._boyerMoorePrefix.Pattern.Length; - } - else if (state.thisRef._code!.RightToLeft) - { - offset = -offset; + int offset = state.thisRef._boyerMoorePrefix!.NegativeASCII[i + state.thisRef._boyerMoorePrefix.LowASCII]; + if (offset == state.beforefirst) + { + offset = state.thisRef._boyerMoorePrefix.Pattern.Length; + } + else if (state.thisRef._code!.RightToLeft) + { + offset = -offset; + } + Debug.Assert(offset >= 0 && offset <= char.MaxValue); + span[i] = (char)offset; } - Debug.Assert(offset >= 0 && offset <= char.MaxValue); - span[i] = (char)offset; + }); + + // offset = lookupString[ch]; + // goto Advance; + Ldstr(negativeLookup); + Ldloc(chLocal); + Call(s_stringGetCharsMethod); + if (_code.RightToLeft) + { + Neg(); } - }); - - // offset = lookupString[ch]; - // goto Advance; - Ldstr(negativeLookup); - Ldloc(chLocal); - Callvirt(s_stringGetCharsMethod); - if (_code.RightToLeft) - { - Neg(); } - } - else - { - // offset = value; - Debug.Assert(negativeRange == 1); - int offset = _boyerMoorePrefix.NegativeASCII[_boyerMoorePrefix.LowASCII]; - if (offset == beforefirst) + else { - offset = _code.RightToLeft ? -_boyerMoorePrefix.Pattern.Length : _boyerMoorePrefix.Pattern.Length; + // offset = value; + Debug.Assert(negativeRange == 1); + int offset = _boyerMoorePrefix.NegativeASCII[_boyerMoorePrefix.LowASCII]; + if (offset == beforefirst) + { + offset = _code.RightToLeft ? -_boyerMoorePrefix.Pattern.Length : _boyerMoorePrefix.Pattern.Length; + } + Ldc(offset); } - Ldc(offset); + BrFar(lAdvance); } - BrFar(lAdvance); // Emit a check for each character from the next to last down to the first. MarkLabel(lPartialMatch); Ldloc(_runtextposLocal); - Stloc(testLocal); - - int prevLabelOffset = int.MaxValue; - Label prevLabel = default; - for (int i = _boyerMoorePrefix.Pattern.Length - 2; i >= 0; i--) + using (RentedLocalBuilder testLocal = RentInt32Local()) { - int charindex = _code.RightToLeft ? _boyerMoorePrefix.Pattern.Length - 1 - i : i; - - // if (runtext[--test] == pattern[index]) goto lNext; - Ldloc(_runtextLocal); - Ldloc(testLocal); - Ldc(1); - Sub(_code.RightToLeft); - Dup(); Stloc(testLocal); - Callvirt(s_stringGetCharsMethod); - if (_boyerMoorePrefix.CaseInsensitive) - { - CallToLower(); - } - Ldc(_boyerMoorePrefix.Pattern[charindex]); - if (prevLabelOffset == _boyerMoorePrefix.Positive[charindex]) + int prevLabelOffset = int.MaxValue; + Label prevLabel = default; + for (int i = _boyerMoorePrefix.Pattern.Length - 2; i >= 0; i--) { - BneFar(prevLabel); + int charindex = _code.RightToLeft ? _boyerMoorePrefix.Pattern.Length - 1 - i : i; + + // if (runtext[--test] == pattern[index]) goto lNext; + Ldloc(_runtextLocal); + Ldloc(testLocal); + Ldc(1); + Sub(_code.RightToLeft); + Stloc(testLocal); + Ldloc(testLocal); + Call(s_stringGetCharsMethod); + if (_boyerMoorePrefix.CaseInsensitive && ParticipatesInCaseConversion(_boyerMoorePrefix.Pattern[charindex])) + { + CallToLower(); + } + Ldc(_boyerMoorePrefix.Pattern[charindex]); + + if (prevLabelOffset == _boyerMoorePrefix.Positive[charindex]) + { + BneFar(prevLabel); + } + else + { + Label lNext = DefineLabel(); + Beq(lNext); + + // offset = positive[ch]; + // goto advance; + prevLabel = DefineLabel(); + prevLabelOffset = _boyerMoorePrefix.Positive[charindex]; + MarkLabel(prevLabel); + Ldc(prevLabelOffset); + BrFar(lAdvance); + + MarkLabel(lNext); + } } - else + + // this.runtextpos = test; + // return true; + Ldthis(); + Ldloc(testLocal); + if (_code.RightToLeft) { - Label lNext = DefineLabel(); - Beq(lNext); - - // offset = positive[ch]; - // goto advance; - prevLabel = DefineLabel(); - prevLabelOffset = _boyerMoorePrefix.Positive[charindex]; - MarkLabel(prevLabel); - Ldc(prevLabelOffset); - BrFar(lAdvance); - - MarkLabel(lNext); + Ldc(1); + Add(); } - } - - // this.runtextpos = test; - // return true; - Ldthis(); - Ldloc(testLocal); - if (_code.RightToLeft) - { + Stfld(s_runtextposField); Ldc(1); - Add(); + Ret(); } - Stfld(s_runtextposField); - Ldc(1); - Ret(); } else if (_leadingCharClasses is null) { @@ -1407,8 +1485,7 @@ protected void GenerateFindFirstChar() { Debug.Assert(_leadingCharClasses.Length == 1, "Only the FirstChars and not MultiFirstChars computation is supported for RightToLeft"); - LocalBuilder charInClassLocal = _temp1Local; - LocalBuilder cLocal = _temp2Local; + using RentedLocalBuilder cLocal = RentInt32Local(); Label l1 = DefineLabel(); Label l2 = DefineLabel(); @@ -1440,8 +1517,8 @@ protected void GenerateFindFirstChar() if (!RegexCharClass.IsSingleton(_leadingCharClasses[0].CharClass)) { - EmitMatchCharacterClass(_leadingCharClasses[0].CharClass, _leadingCharClasses[0].CaseInsensitive, charInClassLocal); - BrtrueFar(l2); + EmitMatchCharacterClass(_leadingCharClasses[0].CharClass, _leadingCharClasses[0].CaseInsensitive); + Brtrue(l2); } else { @@ -1463,7 +1540,7 @@ protected void GenerateFindFirstChar() } Ldc(0); - BrFar(l3); + Br(l3); MarkLabel(l2); @@ -1486,8 +1563,6 @@ protected void GenerateFindFirstChar() { Debug.Assert(_leadingCharClasses != null && _leadingCharClasses.Length > 0); - LocalBuilder iLocal = _temp2Local; - // If minRequiredLength > 0, we already output a more stringent check. In the rare case // where we were unable to get an accurate enough min required length to ensure it's larger // than the prefixes we calculated, we also need to ensure we have enough spaces for those, @@ -1505,9 +1580,8 @@ protected void GenerateFindFirstChar() BleFar(returnFalse); } - LocalBuilder charInClassLocal = _temp1Local; - _temp3Local = DeclareReadOnlySpanChar(); - LocalBuilder textSpanLocal = _temp3Local; + using RentedLocalBuilder iLocal = RentInt32Local(); + using RentedLocalBuilder textSpanLocal = RentReadOnlySpanCharLocal(); // ReadOnlySpan span = this.runtext.AsSpan(runtextpos, runtextend - runtextpos); Ldthisfld(s_runtextField); @@ -1586,17 +1660,31 @@ protected void GenerateFindFirstChar() break; } - // i = tmp; // or i += tmp if there's a loop - // if (tmp < 0) goto returnFalse; - Dup(); if (needLoop) { + // i += tmp; + // if (tmp < 0) goto returnFalse; + using (RentedLocalBuilder tmp = RentInt32Local()) + { + Stloc(tmp); + Ldloc(iLocal); + Ldloc(tmp); + Add(); + Stloc(iLocal); + Ldloc(tmp); + Ldc(0); + BltFar(returnFalse); + } + } + else + { + // i = tmp; + // if (i < 0) goto returnFalse; + Stloc(iLocal); Ldloc(iLocal); - Add(); + Ldc(0); + BltFar(returnFalse); } - Stloc(iLocal); - Ldc(0); - BltFar(returnFalse); // if (i >= textSpan.Length - (_leadingCharClasses.Length - 1)) goto returnFalse; if (_leadingCharClasses.Length > 1) @@ -1628,7 +1716,7 @@ protected void GenerateFindFirstChar() } Call(s_spanGetItemMethod); LdindU2(); - EmitMatchCharacterClass(_leadingCharClasses[charClassIndex].CharClass, _leadingCharClasses[charClassIndex].CaseInsensitive, charInClassLocal); + EmitMatchCharacterClass(_leadingCharClasses[charClassIndex].CharClass, _leadingCharClasses[charClassIndex].CaseInsensitive); BrfalseFar(charNotInClassLabel); } @@ -1707,8 +1795,6 @@ private bool TryGenerateNonBacktrackingGo(RegexNode node) LocalBuilder runtextposLocal = DeclareInt32(); LocalBuilder textSpanLocal = DeclareReadOnlySpanChar(); LocalBuilder runtextendLocal = DeclareInt32(); - Stack? iterationLocals = null; - Stack? spanLocals = null; Label stopSuccessLabel = DefineLabel(); Label doneLabel = DefineLabel(); if (_hasTimeout) @@ -1724,11 +1810,11 @@ private bool TryGenerateNonBacktrackingGo(RegexNode node) Mvfldloc(s_runtextField, runtextLocal); Mvfldloc(s_runtextendField, runtextendLocal); - // int runtextpos; - // int originalruntextpos = runtextpos = this.runtextpos; + // int runtextpos = this.runtextpos; + // int originalruntextpos = this.runtextpos; Ldthisfld(s_runtextposField); - Dup(); Stloc(runtextposLocal); + Ldloc(runtextposLocal); Stloc(originalruntextposLocal); // The implementation tries to use const indexes into the span wherever possible, which we can do @@ -1762,7 +1848,7 @@ private bool TryGenerateNonBacktrackingGo(RegexNode node) Ldc(0); Ldloc(originalruntextposLocal); Ldloc(runtextposLocal); - Callvirt(s_captureMethod); + Call(s_captureMethod); // If the graph contained captures, undo any remaining to handle failed matches. if ((node.Options & HasCapturesFlag) != 0) @@ -1778,10 +1864,10 @@ private bool TryGenerateNonBacktrackingGo(RegexNode node) Br(condition); MarkLabel(body); Ldthis(); - Callvirt(s_uncaptureMethod); + Call(s_uncaptureMethod); MarkLabel(condition); Ldthis(); - Callvirt(s_crawlposMethod); + Call(s_crawlposMethod); Brtrue(body); // Done: @@ -1841,8 +1927,10 @@ static bool NodeSupportsNonBacktrackingImplementation(RegexNode node, int maxDep case RegexNode.Setloopatomic: // "Empty" is easy: nothing is emitted for it. // "Nothing" is also easy: it doesn't match anything. + // "UpdateBumpalong" doesn't match anything, it's just an optional directive to the engine. case RegexNode.Empty: case RegexNode.Nothing: + case RegexNode.UpdateBumpalong: supported = true; break; @@ -1976,36 +2064,6 @@ void LoadTextSpanLocal() Stloc(textSpanLocal); } - // Rents an Int32 local. We want to minimize the number of locals we create, so we maintain - // a pool of them, only adding when needing, and nested constructs that each need their own - // independent local can use this to get one. - LocalBuilder RentInt32Local() - { - iterationLocals ??= new Stack(1); - return iterationLocals.TryPop(out LocalBuilder? iterationLocal) ? iterationLocal : DeclareInt32(); - } - - // Returns a rented Int32 local. - void ReturnInt32Local(LocalBuilder int32Local) - { - Debug.Assert(iterationLocals != null); - Debug.Assert(int32Local.LocalType == typeof(int)); - iterationLocals.Push(int32Local); - } - - LocalBuilder RentReadOnlySpanCharLocal() - { - spanLocals ??= new Stack(1); - return spanLocals.TryPop(out LocalBuilder? iterationLocal) ? iterationLocal : DeclareReadOnlySpanChar(); - } - - void ReturnReadOnlySpanCharLocal(LocalBuilder spanLocal) - { - Debug.Assert(spanLocals != null); - Debug.Assert(spanLocal.LocalType == typeof(ReadOnlySpan)); - spanLocals.Push(spanLocal); - } - // Emits the sum of a constant and a value from a local. void EmitSum(int constant, LocalBuilder? local) { @@ -2098,7 +2156,7 @@ void EmitAtomicAlternate(RegexNode node) // BranchN(); // jumps to Done on failure // Save off runtextpos. We'll need to reset this each time a branch fails. - LocalBuilder startingRunTextPos = RentInt32Local(); + using RentedLocalBuilder startingRunTextPos = RentInt32Local(); Ldloc(runtextposLocal); Stloc(startingRunTextPos); int startingTextSpanPos = textSpanPos; @@ -2107,12 +2165,12 @@ void EmitAtomicAlternate(RegexNode node) // state. Note that this is only about subexpressions within the alternation, // as the alternation is atomic, so we're not concerned about captures after // the alternation. - LocalBuilder? startingCrawlpos = null; + RentedLocalBuilder? startingCrawlpos = null; if ((node.Options & HasCapturesFlag) != 0) { startingCrawlpos = RentInt32Local(); Ldthis(); - Callvirt(s_crawlposMethod); + Call(s_crawlposMethod); Stloc(startingCrawlpos); } @@ -2179,12 +2237,8 @@ void EmitAtomicAlternate(RegexNode node) // Successfully completed the alternate. MarkLabel(doneAlternate); - ReturnInt32Local(startingRunTextPos); - if (startingCrawlpos != null) - { - ReturnInt32Local(startingCrawlpos); - } + startingCrawlpos?.Dispose(); Debug.Assert(textSpanPos == 0); } @@ -2193,6 +2247,7 @@ void EmitAtomicAlternate(RegexNode node) void EmitCapture(RegexNode node) { Debug.Assert(node.N == -1); + using RentedLocalBuilder startingRunTextPos = RentInt32Local(); // Get the capture number. This needs to be kept // in sync with MapCapNum in RegexWriter. @@ -2208,7 +2263,6 @@ void EmitCapture(RegexNode node) // textSpan = textSpan.Slice(textSpanPos); // startingRunTextPos = runtextpos; TransferTextSpanPosToRunTextPos(); - LocalBuilder startingRunTextPos = RentInt32Local(); Ldloc(runtextposLocal); Stloc(startingRunTextPos); @@ -2223,9 +2277,7 @@ void EmitCapture(RegexNode node) Ldc(capnum); Ldloc(startingRunTextPos); Ldloc(runtextposLocal); - Callvirt(s_captureMethod); - - ReturnInt32Local(startingRunTextPos); + Call(s_captureMethod); } // Emits code to unwind the capture stack until the crawl position specified in the provided local. @@ -2239,10 +2291,10 @@ void EmitUncaptureUntil(LocalBuilder startingCrawlpos) Br(condition); MarkLabel(body); Ldthis(); - Callvirt(s_uncaptureMethod); + Call(s_uncaptureMethod); MarkLabel(condition); Ldthis(); - Callvirt(s_crawlposMethod); + Call(s_crawlposMethod); Ldloc(startingCrawlpos); Bne(body); } @@ -2251,7 +2303,7 @@ void EmitUncaptureUntil(LocalBuilder startingCrawlpos) void EmitPositiveLookaheadAssertion(RegexNode node) { // Save off runtextpos. We'll need to reset this upon successful completion of the lookahead. - LocalBuilder startingRunTextPos = RentInt32Local(); + using RentedLocalBuilder startingRunTextPos = RentInt32Local(); Ldloc(runtextposLocal); Stloc(startingRunTextPos); int startingTextSpanPos = textSpanPos; @@ -2265,15 +2317,13 @@ void EmitPositiveLookaheadAssertion(RegexNode node) Stloc(runtextposLocal); LoadTextSpanLocal(); textSpanPos = startingTextSpanPos; - - ReturnInt32Local(startingRunTextPos); } // Emits the code to handle a negative lookahead assertion. void EmitNegativeLookaheadAssertion(RegexNode node) { // Save off runtextpos. We'll need to reset this upon successful completion of the lookahead. - LocalBuilder startingRunTextPos = RentInt32Local(); + using RentedLocalBuilder startingRunTextPos = RentInt32Local(); Ldloc(runtextposLocal); Stloc(startingRunTextPos); int startingTextSpanPos = textSpanPos; @@ -2297,8 +2347,6 @@ void EmitNegativeLookaheadAssertion(RegexNode node) Stloc(runtextposLocal); LoadTextSpanLocal(); textSpanPos = startingTextSpanPos; - - ReturnInt32Local(startingRunTextPos); } // Emits the code for the node. @@ -2398,12 +2446,28 @@ void EmitNode(RegexNode node) // Emit nothing. break; + case RegexNode.UpdateBumpalong: + EmitUpdateBumpalong(); + break; + default: Debug.Fail($"Unexpected node type: {node.Type}"); break; } } + // Emits the code to handle updating base.runtextpos to runtextpos in response to + // an UpdateBumpalong node. This is used when we want to inform the scan loop that + // it should bump from this location rather than from the original location. + void EmitUpdateBumpalong() + { + // base.runtextpos = runtextpos; + TransferTextSpanPosToRunTextPos(); + Ldthis(); + Ldloc(runtextposLocal); + Stfld(s_runtextposField); + } + // Emits the code to handle a single-character match. void EmitSingleChar(RegexNode node, bool emitLengthCheck = true, LocalBuilder? offset = null) { @@ -2426,9 +2490,7 @@ void EmitSingleChar(RegexNode node, bool emitLengthCheck = true, LocalBuilder? o case RegexNode.Setlazy: case RegexNode.Setloop: case RegexNode.Setloopatomic: - LocalBuilder setScratchLocal = RentInt32Local(); - EmitMatchCharacterClass(node.Str!, IsCaseInsensitive(node), setScratchLocal); - ReturnInt32Local(setScratchLocal); + EmitMatchCharacterClass(node.Str!, IsCaseInsensitive(node)); BrfalseFar(doneLabel); break; @@ -2436,14 +2498,20 @@ void EmitSingleChar(RegexNode node, bool emitLengthCheck = true, LocalBuilder? o case RegexNode.Onelazy: case RegexNode.Oneloop: case RegexNode.Oneloopatomic: - if (IsCaseInsensitive(node)) CallToLower(); + if (IsCaseInsensitive(node) && ParticipatesInCaseConversion(node.Ch)) + { + CallToLower(); + } Ldc(node.Ch); BneFar(doneLabel); break; default: Debug.Assert(node.Type == RegexNode.Notone || node.Type == RegexNode.Notonelazy || node.Type == RegexNode.Notoneloop || node.Type == RegexNode.Notoneloopatomic); - if (IsCaseInsensitive(node)) CallToLower(); + if (IsCaseInsensitive(node) && ParticipatesInCaseConversion(node.Ch)) + { + CallToLower(); + } Ldc(node.Ch); BeqFar(doneLabel); break; @@ -2468,23 +2536,23 @@ void EmitBoundary(RegexNode node) switch (node.Type) { case RegexNode.Boundary: - Callvirt(s_isBoundaryMethod); + Call(s_isBoundaryMethod); BrfalseFar(doneLabel); break; case RegexNode.NonBoundary: - Callvirt(s_isBoundaryMethod); + Call(s_isBoundaryMethod); BrtrueFar(doneLabel); break; case RegexNode.ECMABoundary: - Callvirt(s_isECMABoundaryMethod); + Call(s_isECMABoundaryMethod); BrfalseFar(doneLabel); break; default: Debug.Assert(node.Type == RegexNode.NonECMABoundary); - Callvirt(s_isECMABoundaryMethod); + Call(s_isECMABoundaryMethod); BrtrueFar(doneLabel); break; } @@ -2536,7 +2604,7 @@ void EmitAnchors(RegexNode node) Ldloc(runtextposLocal); Ldc(1); Sub(); - Callvirt(s_stringGetCharsMethod); + Call(s_stringGetCharsMethod); Ldc('\n'); BneFar(doneLabel); MarkLabel(success); @@ -2568,7 +2636,7 @@ void EmitAnchors(RegexNode node) Ldc(textSpanPos); Ldloca(textSpanLocal); Call(s_spanGetLengthMethod); - BgeUnFar(success); + BgeUn(success); Ldloca(textSpanLocal); Ldc(textSpanPos); Call(s_spanGetItemMethod); @@ -2664,7 +2732,10 @@ void EmitMultiChar(RegexNode node) EmitTextSpanOffset(); textSpanPos++; LdindU2(); - if (caseInsensitive) CallToLower(); + if (caseInsensitive && ParticipatesInCaseConversion(s[i])) + { + CallToLower(); + } Ldc(s[i]); BneFar(doneLabel); } @@ -2712,15 +2783,15 @@ void EmitSingleCharRepeater(RegexNode node) Label conditionLabel = DefineLabel(); Label bodyLabel = DefineLabel(); - LocalBuilder iterationLocal = RentInt32Local(); - LocalBuilder spanLocal = RentReadOnlySpanCharLocal(); + using RentedLocalBuilder spanLocal = RentReadOnlySpanCharLocal(); Ldloca(textSpanLocal); Ldc(textSpanPos); Ldc(iterations); Call(s_spanSliceIntIntMethod); Stloc(spanLocal); + using RentedLocalBuilder iterationLocal = RentInt32Local(); Ldc(0); Stloc(iterationLocal); BrFar(conditionLabel); @@ -2747,9 +2818,6 @@ void EmitSingleCharRepeater(RegexNode node) Call(s_spanGetLengthMethod); BltFar(bodyLabel); - ReturnReadOnlySpanCharLocal(spanLocal); - ReturnInt32Local(iterationLocal); - textSpanPos += iterations; } } @@ -2781,8 +2849,8 @@ void EmitNodeRepeater(RegexNode node) Label conditionLabel = DefineLabel(); Label bodyLabel = DefineLabel(); - LocalBuilder iterationLocal = RentInt32Local(); + using RentedLocalBuilder iterationLocal = RentInt32Local(); Ldc(0); Stloc(iterationLocal); BrFar(conditionLabel); @@ -2804,8 +2872,6 @@ void EmitNodeRepeater(RegexNode node) Ldloc(iterationLocal); Ldc(iterations); BltFar(bodyLabel); - - ReturnInt32Local(iterationLocal); } // Emits the code to handle a non-backtracking, variable-length loop around a single character comparison. @@ -2834,7 +2900,7 @@ void EmitSingleCharAtomicLoop(RegexNode node) int minIterations = node.M; int maxIterations = node.N; - LocalBuilder iterationLocal = RentInt32Local(); + using RentedLocalBuilder iterationLocal = RentInt32Local(); Label originalDoneLabel = doneLabel; doneLabel = DefineLabel(); @@ -2844,7 +2910,7 @@ void EmitSingleCharAtomicLoop(RegexNode node) if (node.Type == RegexNode.Notoneloopatomic && maxIterations == int.MaxValue && - !IsCaseInsensitive(node)) + (!IsCaseInsensitive(node) || !ParticipatesInCaseConversion(node.Ch))) { // For Notoneloopatomic, we're looking for a specific character, as everything until we find // it is consumed by the loop. If we're unbounded, such as with ".*" and if we're case-sensitive, @@ -2978,19 +3044,23 @@ void EmitSingleCharAtomicLoop(RegexNode node) switch (node.Type) { case RegexNode.Oneloopatomic: - if (IsCaseInsensitive(node)) CallToLower(); + if (IsCaseInsensitive(node) && ParticipatesInCaseConversion(node.Ch)) + { + CallToLower(); + } Ldc(node.Ch); BneFar(doneLabel); break; case RegexNode.Notoneloopatomic: - if (IsCaseInsensitive(node)) CallToLower(); + if (IsCaseInsensitive(node) && ParticipatesInCaseConversion(node.Ch)) + { + CallToLower(); + } Ldc(node.Ch); BeqFar(doneLabel); break; case RegexNode.Setloopatomic: - LocalBuilder setScratchLocal = RentInt32Local(); - EmitMatchCharacterClass(node.Str!, IsCaseInsensitive(node), setScratchLocal); - ReturnInt32Local(setScratchLocal); + EmitMatchCharacterClass(node.Str!, IsCaseInsensitive(node)); BrfalseFar(doneLabel); break; } @@ -3041,8 +3111,6 @@ void EmitSingleCharAtomicLoop(RegexNode node) Ldloc(iterationLocal); Add(); Stloc(runtextposLocal); - - ReturnInt32Local(iterationLocal); } // Emits the code to handle a non-backtracking optional zero-or-one loop. @@ -3070,19 +3138,23 @@ void EmitAtomicSingleCharZeroOrOne(RegexNode node) switch (node.Type) { case RegexNode.Oneloopatomic: - if (IsCaseInsensitive(node)) CallToLower(); + if (IsCaseInsensitive(node) && ParticipatesInCaseConversion(node.Ch)) + { + CallToLower(); + } Ldc(node.Ch); BneFar(skipUpdatesLabel); break; case RegexNode.Notoneloopatomic: - if (IsCaseInsensitive(node)) CallToLower(); + if (IsCaseInsensitive(node) && ParticipatesInCaseConversion(node.Ch)) + { + CallToLower(); + } Ldc(node.Ch); BeqFar(skipUpdatesLabel); break; case RegexNode.Setloopatomic: - LocalBuilder setScratchLocal = RentInt32Local(); - EmitMatchCharacterClass(node.Str!, IsCaseInsensitive(node), setScratchLocal); - ReturnInt32Local(setScratchLocal); + EmitMatchCharacterClass(node.Str!, IsCaseInsensitive(node)); BrfalseFar(skipUpdatesLabel); break; } @@ -3116,7 +3188,8 @@ void EmitAtomicNodeLoop(RegexNode node) return; } - LocalBuilder iterationLocal = RentInt32Local(); + using RentedLocalBuilder iterationLocal = RentInt32Local(); + using RentedLocalBuilder startingRunTextPosLocal = RentInt32Local(); Label originalDoneLabel = doneLabel; doneLabel = DefineLabel(); @@ -3153,7 +3226,6 @@ void EmitAtomicNodeLoop(RegexNode node) doneLabel = DefineLabel(); // Save off runtextpos. - LocalBuilder startingRunTextPosLocal = RentInt32Local(); Ldloc(runtextposLocal); Stloc(startingRunTextPosLocal); @@ -3169,7 +3241,6 @@ void EmitAtomicNodeLoop(RegexNode node) doneLabel = prevDone; // reset done label Ldloc(startingRunTextPosLocal); Stloc(runtextposLocal); - ReturnInt32Local(startingRunTextPosLocal); BrFar(doneLabel); // Successful iteration. @@ -3205,8 +3276,6 @@ void EmitAtomicNodeLoop(RegexNode node) Ldc(minIterations); BltFar(doneLabel); } - - ReturnInt32Local(iterationLocal); } } @@ -3214,6 +3283,8 @@ void EmitAtomicNodeLoop(RegexNode node) protected void GenerateGo() { Debug.Assert(_code != null); + _int32LocalsPool?.Clear(); + _readOnlySpanCharLocalsPool?.Clear(); // Generate backtrack-free code when we're dealing with simpler regexes. if (TryGenerateNonBacktrackingGo(_code.Tree.Root)) @@ -3232,9 +3303,6 @@ protected void GenerateGo() _runtrackLocal = DeclareInt32Array(); _runstackposLocal = DeclareInt32(); _runstackLocal = DeclareInt32Array(); - _temp1Local = DeclareInt32(); - _temp2Local = DeclareInt32(); - _temp3Local = DeclareInt32(); if (_hasTimeout) { _loopTimeoutCounterLocal = DeclareInt32(); @@ -3263,7 +3331,7 @@ protected void GenerateGo() private void InitializeCultureForGoIfNecessary() { - _cultureLocal = null; + _textInfoLocal = null; if ((_options & RegexOptions.CultureInvariant) == 0) { bool needsCulture = (_options & RegexOptions.IgnoreCase) != 0; @@ -3282,7 +3350,7 @@ private void InitializeCultureForGoIfNecessary() if (needsCulture) { // cache CultureInfo in local variable which saves excessive thread local storage accesses - _cultureLocal = DeclareCultureInfo(); + _textInfoLocal = DeclareTextInfo(); InitLocalCultureInfo(); } } @@ -3308,15 +3376,13 @@ private void GenerateOneCode() DumpBacktracking(); #endif - LocalBuilder charInClassLocal; - // Before executing any RegEx code in the unrolled loop, // we try checking for the match timeout: if (_hasTimeout) { Ldthis(); - Callvirt(s_checkTimeoutMethod); + Call(s_checkTimeoutMethod); } // Now generate the IL for the RegEx code saved in _regexopcode. @@ -3336,6 +3402,20 @@ private void GenerateOneCode() Back(); break; + case RegexCode.UpdateBumpalong: + // UpdateBumpalong should only exist in the code stream at such a point where the root + // of the backtracking stack contains the runtextpos from the start of this Go call. Replace + // that tracking value with the current runtextpos value. + //: base.runtrack[base.runtrack.Length - 1] = runtextpos; + Ldloc(_runtrackLocal!); + Dup(); + Ldlen(); + Ldc(1); + Sub(); + Ldloc(_runtextposLocal!); + StelemI4(); + break; + case RegexCode.Goto: //: Goto(Operand(0)); Goto(Operand(0)); @@ -3346,7 +3426,7 @@ private void GenerateOneCode() //: break Backward; Ldthis(); Ldc(Operand(0)); - Callvirt(s_isMatchedMethod); + Call(s_isMatchedMethod); BrfalseFar(_backtrack); break; @@ -3395,8 +3475,8 @@ private void GenerateOneCode() //: Textto(Stacked(0)); ReadyPushTrack(); PopStack(); - Dup(); Stloc(_runtextposLocal!); + Ldloc(_runtextposLocal!); DoPush(); Track(); @@ -3430,32 +3510,35 @@ private void GenerateOneCode() { Ldthis(); Ldc(Operand(1)); - Callvirt(s_isMatchedMethod); + Call(s_isMatchedMethod); BrfalseFar(_backtrack); } - PopStack(); - Stloc(_temp1Local!); - - if (Operand(1) != -1) + using (RentedLocalBuilder stackedLocal = RentInt32Local()) { - Ldthis(); - Ldc(Operand(0)); - Ldc(Operand(1)); - Ldloc(_temp1Local!); - Ldloc(_runtextposLocal!); - Callvirt(s_transferCaptureMethod); - } - else - { - Ldthis(); - Ldc(Operand(0)); - Ldloc(_temp1Local!); - Ldloc(_runtextposLocal!); - Callvirt(s_captureMethod); - } + PopStack(); + Stloc(stackedLocal); - PushTrack(_temp1Local!); + if (Operand(1) != -1) + { + Ldthis(); + Ldc(Operand(0)); + Ldc(Operand(1)); + Ldloc(stackedLocal); + Ldloc(_runtextposLocal!); + Call(s_transferCaptureMethod); + } + else + { + Ldthis(); + Ldc(Operand(0)); + Ldloc(stackedLocal); + Ldloc(_runtextposLocal!); + Call(s_captureMethod); + } + + PushTrack(stackedLocal); + } TrackUnique(Operand(0) != -1 && Operand(1) != -1 ? Capback2 : Capback); break; @@ -3472,11 +3555,11 @@ private void GenerateOneCode() PopTrack(); DoPush(); Ldthis(); - Callvirt(s_uncaptureMethod); + Call(s_uncaptureMethod); if (Operand(0) != -1 && Operand(1) != -1) { Ldthis(); - Callvirt(s_uncaptureMethod); + Call(s_uncaptureMethod); } Back(); break; @@ -3497,13 +3580,15 @@ private void GenerateOneCode() //: } //: continue Forward; { - LocalBuilder mark = _temp1Local!; Label l1 = DefineLabel(); PopStack(); - Dup(); - Stloc(mark!); // Stacked(0) -> temp - PushTrack(mark!); + using (RentedLocalBuilder mark = RentInt32Local()) + { + Stloc(mark); // Stacked(0) -> temp + PushTrack(mark); + Ldloc(mark); + } Ldloc(_runtextposLocal!); Beq(l1); // mark == textpos -> branch @@ -3564,37 +3649,38 @@ private void GenerateOneCode() //: Advance(1); //: continue Forward; { - LocalBuilder mark = _temp1Local!; - Label l1 = DefineLabel(); - Label l2 = DefineLabel(); - Label l3 = DefineLabel(); - - PopStack(); - Dup(); - Stloc(mark!); // Stacked(0) -> temp - - // if (oldMarkPos != -1) - Ldloc(mark); - Ldc(-1); - Beq(l2); // mark == -1 -> branch - PushTrack(mark); - Br(l3); - // else - MarkLabel(l2); - PushTrack(_runtextposLocal!); - MarkLabel(l3); + using (RentedLocalBuilder mark = RentInt32Local()) + { + PopStack(); + Stloc(mark); // Stacked(0) -> temp - // if (Textpos() != mark) - Ldloc(_runtextposLocal!); - Beq(l1); // mark == textpos -> branch - PushTrack(_runtextposLocal!); - Track(); - Br(AdvanceLabel()); // Advance (near) - // else - MarkLabel(l1); - ReadyPushStack(); // push the current textPos on the stack. - // May be ignored by 'back2' or used by a true empty match. - Ldloc(mark); + // if (oldMarkPos != -1) + Label l2 = DefineLabel(); + Label l3 = DefineLabel(); + Ldloc(mark); + Ldc(-1); + Beq(l2); // mark == -1 -> branch + PushTrack(mark); + Br(l3); + // else + MarkLabel(l2); + PushTrack(_runtextposLocal!); + MarkLabel(l3); + + // if (Textpos() != mark) + Label l1 = DefineLabel(); + Ldloc(_runtextposLocal!); + Ldloc(mark); + Beq(l1); // mark == textpos -> branch + PushTrack(_runtextposLocal!); + Track(); + Br(AdvanceLabel()); // Advance (near) + // else + MarkLabel(l1); + ReadyPushStack(); // push the current textPos on the stack. + // May be ignored by 'back2' or used by a true empty match. + Ldloc(mark); + } DoPush(); TrackUnique2(Lazybranchmarkback2); @@ -3675,42 +3761,45 @@ private void GenerateOneCode() //: } //: continue Forward; { - LocalBuilder count = _temp1Local!; - LocalBuilder mark = _temp2Local!; - Label l1 = DefineLabel(); - Label l2 = DefineLabel(); - - PopStack(); - Stloc(count); // count -> temp - PopStack(); - Dup(); - Stloc(mark); // mark -> temp2 - PushTrack(mark); - - Ldloc(_runtextposLocal!); - Bne(l1); // mark != textpos -> l1 - Ldloc(count); - Ldc(0); - Bge(l2); // count >= 0 && mark == textpos -> l2 + using (RentedLocalBuilder count = RentInt32Local()) + { + PopStack(); + Stloc(count); // count -> temp + PopStack(); + using (RentedLocalBuilder mark = RentInt32Local()) + { + Stloc(mark); // mark -> temp2 + PushTrack(mark); + Ldloc(mark); + } - MarkLabel(l1); - Ldloc(count); - Ldc(Operand(1)); - Bge(l2); // count >= Operand(1) -> l2 + Label l1 = DefineLabel(); + Label l2 = DefineLabel(); + Ldloc(_runtextposLocal!); + Bne(l1); // mark != textpos -> l1 + Ldloc(count); + Ldc(0); + Bge(l2); // count >= 0 && mark == textpos -> l2 - // else - PushStack(_runtextposLocal!); - ReadyPushStack(); - Ldloc(count); // mark already on track - Ldc(1); - Add(); - DoPush(); - Track(); - Goto(Operand(0)); + MarkLabel(l1); + Ldloc(count); + Ldc(Operand(1)); + Bge(l2); // count >= Operand(1) -> l2 + + // else + PushStack(_runtextposLocal!); + ReadyPushStack(); + Ldloc(count); // mark already on track + Ldc(1); + Add(); + DoPush(); + Track(); + Goto(Operand(0)); - // if (count >= Operand(1) || Textpos() == mark) - MarkLabel(l2); - PushTrack(count); // mark already on track + // if (count >= Operand(1) || Textpos() == mark) + MarkLabel(l2); + PushTrack(count); // mark already on track + } TrackUnique2(Branchcountback2); break; } @@ -3728,30 +3817,31 @@ private void GenerateOneCode() //: Stack(Tracked(0), Stacked(1) - 1); // recall old mark, old count //: break Backward; { + using (RentedLocalBuilder count = RentInt32Local()) + { + Label l1 = DefineLabel(); + PopStack(); + Ldc(1); + Sub(); + Stloc(count); + Ldloc(count); + Ldc(0); + Blt(l1); - LocalBuilder count = _temp1Local!; - Label l1 = DefineLabel(); - PopStack(); - Ldc(1); - Sub(); - Dup(); - Stloc(count!); - Ldc(0); - Blt(l1); - - // if (count >= 0) - PopStack(); - Stloc(_runtextposLocal!); - PushTrack(count); // Tracked(0) is alredy on the track - TrackUnique2(Branchcountback2); - Advance(); + // if (count >= 0) + PopStack(); + Stloc(_runtextposLocal!); + PushTrack(count); // Tracked(0) is alredy on the track + TrackUnique2(Branchcountback2); + Advance(); - // else - MarkLabel(l1); - ReadyReplaceStack(0); - PopTrack(); - DoReplace(); - PushStack(count); + // else + MarkLabel(l1); + ReadyReplaceStack(0); + PopTrack(); + DoReplace(); + PushStack(count); + } Back(); break; } @@ -3762,11 +3852,14 @@ private void GenerateOneCode() //: break Backward; // Backtrack PopTrack(); - Stloc(_temp1Local!); - ReadyPushStack(); - PopTrack(); - DoPush(); - PushStack(_temp1Local!); + using (RentedLocalBuilder tmp = RentInt32Local()) + { + Stloc(tmp); + ReadyPushStack(); + PopTrack(); + DoPush(); + PushStack(tmp); + } Back(); break; @@ -3786,34 +3879,37 @@ private void GenerateOneCode() //: Track(mark, count, Textpos()); // Save mark, count, position //: } { - LocalBuilder count = _temp1Local!; - LocalBuilder mark = _temp2Local!; - Label l1 = DefineLabel(); - - PopStack(); - Stloc(count); // count -> temp PopStack(); - Stloc(mark); // mark -> temp2 - - Ldloc(count); - Ldc(0); - Bge(l1); // count >= 0 -> l1 - - // if (count < 0) - PushTrack(mark); - PushStack(_runtextposLocal!); - ReadyPushStack(); - Ldloc(count); - Ldc(1); - Add(); - DoPush(); - TrackUnique2(Lazybranchcountback2); - Goto(Operand(0)); + using (RentedLocalBuilder count = RentInt32Local()) + { + Stloc(count); // count -> temp + PopStack(); + using (RentedLocalBuilder mark = RentInt32Local()) + { + Stloc(mark); // mark -> temp2 + + Label l1 = DefineLabel(); + Ldloc(count); + Ldc(0); + Bge(l1); // count >= 0 -> l1 + + // if (count < 0) + PushTrack(mark); + PushStack(_runtextposLocal!); + ReadyPushStack(); + Ldloc(count); + Ldc(1); + Add(); + DoPush(); + TrackUnique2(Lazybranchcountback2); + Goto(Operand(0)); - // else - MarkLabel(l1); - PushTrack(mark); - PushTrack(count); + // else + MarkLabel(l1); + PushTrack(mark); + } + PushTrack(count); + } PushTrack(_runtextposLocal!); Track(); break; @@ -3837,34 +3933,37 @@ private void GenerateOneCode() //: break Backward; // backtrack //: } { - Label l1 = DefineLabel(); - LocalBuilder cLocal = _temp1Local!; - PopTrack(); - Stloc(_runtextposLocal!); - PopTrack(); - Dup(); - Stloc(cLocal); - Ldc(Operand(1)); - Bge(l1); // Tracked(1) >= Operand(1) -> l1 + using (RentedLocalBuilder cLocal = RentInt32Local()) + { + Label l1 = DefineLabel(); - Ldloc(_runtextposLocal!); - TopTrack(); - Beq(l1); // textpos == mark -> l1 + PopTrack(); + Stloc(_runtextposLocal!); + PopTrack(); + Stloc(cLocal); + Ldloc(cLocal); + Ldc(Operand(1)); + Bge(l1); // Tracked(1) >= Operand(1) -> l1 - PushStack(_runtextposLocal!); - ReadyPushStack(); - Ldloc(cLocal); - Ldc(1); - Add(); - DoPush(); - TrackUnique2(Lazybranchcountback2); - Goto(Operand(0)); + Ldloc(_runtextposLocal!); + TopTrack(); + Beq(l1); // textpos == mark -> l1 - MarkLabel(l1); - ReadyPushStack(); - PopTrack(); - DoPush(); - PushStack(cLocal); + PushStack(_runtextposLocal!); + ReadyPushStack(); + Ldloc(cLocal); + Ldc(1); + Add(); + DoPush(); + TrackUnique2(Lazybranchcountback2); + Goto(Operand(0)); + + MarkLabel(l1); + ReadyPushStack(); + PopTrack(); + DoPush(); + PushStack(cLocal); + } Back(); break; } @@ -3893,7 +3992,7 @@ private void GenerateOneCode() DoPush(); ReadyPushStack(); Ldthis(); - Callvirt(s_crawlposMethod); + Call(s_crawlposMethod); DoPush(); TrackUnique(Stackpop2); break; @@ -3914,27 +4013,27 @@ private void GenerateOneCode() Label l1 = DefineLabel(); Label l2 = DefineLabel(); - PopStack(); - Ldthisfld(s_runtrackField); - Ldlen(); - PopStack(); - Sub(); - Stloc(_runtrackposLocal!); - Dup(); - Ldthis(); - Callvirt(s_crawlposMethod); - Beq(l2); + using (RentedLocalBuilder stackedLocal = RentInt32Local()) + { + PopStack(); + Stloc(stackedLocal); + Ldthisfld(s_runtrackField); + Ldlen(); + PopStack(); + Sub(); + Stloc(_runtrackposLocal!); - MarkLabel(l1); - Ldthis(); - Callvirt(s_uncaptureMethod); - Dup(); - Ldthis(); - Callvirt(s_crawlposMethod); - Bne(l1); + MarkLabel(l1); + Ldthis(); + Call(s_crawlposMethod); + Ldloc(stackedLocal); + Beq(l2); + Ldthis(); + Call(s_uncaptureMethod); + Br(l1); + } MarkLabel(l2); - Pop(); Back(); break; } @@ -3944,13 +4043,16 @@ private void GenerateOneCode() //: Trackto(Stacked(0)); //: Track(Stacked(1)); PopStack(); - Stloc(_temp1Local!); - Ldthisfld(s_runtrackField); - Ldlen(); - PopStack(); - Sub(); - Stloc(_runtrackposLocal!); - PushTrack(_temp1Local!); + using (RentedLocalBuilder tmp = RentInt32Local()) + { + Stloc(tmp); + Ldthisfld(s_runtrackField); + Ldlen(); + PopStack(); + Sub(); + Stloc(_runtrackposLocal!); + PushTrack(tmp); + } TrackUnique(Forejumpback); break; @@ -3963,23 +4065,22 @@ private void GenerateOneCode() Label l1 = DefineLabel(); Label l2 = DefineLabel(); - PopTrack(); - - Dup(); - Ldthis(); - Callvirt(s_crawlposMethod); - Beq(l2); + using (RentedLocalBuilder trackedLocal = RentInt32Local()) + { + PopTrack(); + Stloc(trackedLocal); - MarkLabel(l1); - Ldthis(); - Callvirt(s_uncaptureMethod); - Dup(); - Ldthis(); - Callvirt(s_crawlposMethod); - Bne(l1); + MarkLabel(l1); + Ldthis(); + Call(s_crawlposMethod); + Ldloc(trackedLocal); + Beq(l2); + Ldthis(); + Call(s_uncaptureMethod); + Br(l1); + } MarkLabel(l2); - Pop(); Back(); break; } @@ -4020,7 +4121,7 @@ private void GenerateOneCode() Ldloc(_runtextposLocal!); Ldloc(_runtextbegLocal!); Ldloc(_runtextendLocal!); - Callvirt(s_isBoundaryMethod); + Call(s_isBoundaryMethod); if (Code() == RegexCode.Boundary) { BrfalseFar(_backtrack); @@ -4039,7 +4140,7 @@ private void GenerateOneCode() Ldloc(_runtextposLocal!); Ldloc(_runtextbegLocal!); Ldloc(_runtextendLocal!); - Callvirt(s_isECMABoundaryMethod); + Call(s_isECMABoundaryMethod); if (Code() == RegexCode.ECMABoundary) { BrfalseFar(_backtrack); @@ -4106,8 +4207,6 @@ private void GenerateOneCode() //: if (Rightchars() < 1 || Rightcharnext() != (char)Operand(0)) //: break Backward; - charInClassLocal = _temp1Local!; - Ldloc(_runtextposLocal!); if (!IsRightToLeft()) @@ -4125,12 +4224,12 @@ private void GenerateOneCode() if (Code() == RegexCode.Set) { - EmitMatchCharacterClass(_strings![Operand(0)], IsCaseInsensitive(), charInClassLocal); + EmitMatchCharacterClass(_strings![Operand(0)], IsCaseInsensitive()); BrfalseFar(_backtrack); } else { - if (IsCaseInsensitive()) + if (IsCaseInsensitive() && ParticipatesInCaseConversion(Operand(0))) { CallToLower(); } @@ -4175,8 +4274,8 @@ private void GenerateOneCode() Ldc(i); Add(); } - Callvirt(s_stringGetCharsMethod); - if (IsCaseInsensitive()) + Call(s_stringGetCharsMethod); + if (IsCaseInsensitive() && ParticipatesInCaseConversion(str[i])) { CallToLower(); } @@ -4218,8 +4317,8 @@ private void GenerateOneCode() Ldloc(_runtextposLocal!); Ldc(str.Length - i); Sub(); - Callvirt(s_stringGetCharsMethod); - if (IsCaseInsensitive()) + Call(s_stringGetCharsMethod); + if (IsCaseInsensitive() && ParticipatesInCaseConversion(str[i])) { CallToLower(); } @@ -4252,13 +4351,13 @@ private void GenerateOneCode() //: break Backward; //: } { - LocalBuilder lenLocal = _temp1Local!; - LocalBuilder indexLocal = _temp2Local!; + using RentedLocalBuilder lenLocal = RentInt32Local(); + using RentedLocalBuilder indexLocal = RentInt32Local(); Label l1 = DefineLabel(); Ldthis(); Ldc(Operand(0)); - Callvirt(s_isMatchedMethod); + Call(s_isMatchedMethod); if ((_options & RegexOptions.ECMAScript) != 0) { Brfalse(AdvanceLabel()); @@ -4270,9 +4369,9 @@ private void GenerateOneCode() Ldthis(); Ldc(Operand(0)); - Callvirt(s_matchLengthMethod); - Dup(); + Call(s_matchLengthMethod); Stloc(lenLocal); + Ldloc(lenLocal); if (!IsRightToLeft()) { Ldloc(_runtextendLocal!); @@ -4288,7 +4387,7 @@ private void GenerateOneCode() Ldthis(); Ldc(Operand(0)); - Callvirt(s_matchIndexMethod); + Call(s_matchIndexMethod); if (!IsRightToLeft()) { Ldloc(lenLocal); @@ -4312,11 +4411,11 @@ private void GenerateOneCode() { Ldc(1); Sub(); - Dup(); Stloc(lenLocal); + Ldloc(lenLocal); } Sub(IsRightToLeft()); - Callvirt(s_stringGetCharsMethod); + Call(s_stringGetCharsMethod); if (IsCaseInsensitive()) { CallToLower(); @@ -4327,13 +4426,13 @@ private void GenerateOneCode() Ldloc(lenLocal); if (!IsRightToLeft()) { - Dup(); + Ldloc(lenLocal); Ldc(1); Sub(); Stloc(lenLocal); } Sub(IsRightToLeft()); - Callvirt(s_stringGetCharsMethod); + Call(s_stringGetCharsMethod); if (IsCaseInsensitive()) { CallToLower(); @@ -4364,12 +4463,7 @@ private void GenerateOneCode() //: if (Rightcharnext() != ch) //: break Backward; { - LocalBuilder lenLocal = _temp1Local!; - charInClassLocal = _temp2Local!; - Label l1 = DefineLabel(); - int c = Operand(1); - if (c == 0) break; @@ -4392,6 +4486,8 @@ private void GenerateOneCode() Add(IsRightToLeft()); Stloc(_runtextposLocal!); // texpos += len + using RentedLocalBuilder lenLocal = RentInt32Local(); + Label l1 = DefineLabel(); Ldc(c); Stloc(lenLocal); @@ -4403,29 +4499,29 @@ private void GenerateOneCode() { Ldc(1); Sub(); - Dup(); Stloc(lenLocal); + Ldloc(lenLocal); Add(); } else { - Dup(); + Ldloc(lenLocal); Ldc(1); Sub(); Stloc(lenLocal); Sub(); } - Callvirt(s_stringGetCharsMethod); + Call(s_stringGetCharsMethod); if (Code() == RegexCode.Setrep) { EmitTimeoutCheck(); - EmitMatchCharacterClass(_strings![Operand(0)], IsCaseInsensitive(), charInClassLocal); + EmitMatchCharacterClass(_strings![Operand(0)], IsCaseInsensitive()); BrfalseFar(_backtrack); } else { - if (IsCaseInsensitive()) + if (IsCaseInsensitive() && ParticipatesInCaseConversion(Operand(0))) { CallToLower(); } @@ -4493,17 +4589,15 @@ private void GenerateOneCode() //: if (len > i) //: Track(len - i - 1, Textpos() - 1); { - LocalBuilder lenLocal = _temp2Local!; - LocalBuilder iLocal = _temp1Local!; - charInClassLocal = _temp3Local!; - Label loopEnd = DefineLabel(); - int c = Operand(1); if (c == 0) { break; } + using RentedLocalBuilder lenLocal = RentInt32Local(); + using RentedLocalBuilder iLocal = RentInt32Local(); + if (!IsRightToLeft()) { Ldloc(_runtextendLocal!); @@ -4515,18 +4609,19 @@ private void GenerateOneCode() Ldloc(_runtextbegLocal!); } Sub(); + Stloc(lenLocal); if (c != int.MaxValue) { Label l4 = DefineLabel(); - Dup(); + Ldloc(lenLocal); Ldc(c); Blt(l4); - Pop(); Ldc(c); + Stloc(lenLocal); MarkLabel(l4); } - Stloc(lenLocal); + Label loopEnd = DefineLabel(); string? set = Code() == RegexCode.Setloop || Code() == RegexCode.Setloopatomic ? _strings![Operand(0)] : null; Span setChars = stackalloc char[3]; int numSetChars; @@ -4535,7 +4630,7 @@ private void GenerateOneCode() // we can use the vectorized IndexOf to search for the target character. if ((Code() == RegexCode.Notoneloop || Code() == RegexCode.Notoneloopatomic) && !IsRightToLeft() && - !IsCaseInsensitive()) + (!IsCaseInsensitive() || !ParticipatesInCaseConversion(Operand(0)))) { // i = runtext.AsSpan(runtextpos, len).IndexOf(ch); Ldloc(_runtextLocal!); @@ -4674,8 +4769,8 @@ private void GenerateOneCode() Ldloc(iLocal); Ldc(1); Sub(); - Dup(); Stloc(iLocal); + Ldloc(iLocal); Ldc(0); if (Code() == RegexCode.Setloop || Code() == RegexCode.Setloopatomic) { @@ -4698,12 +4793,12 @@ private void GenerateOneCode() if (Code() == RegexCode.Setloop || Code() == RegexCode.Setloopatomic) { EmitTimeoutCheck(); - EmitMatchCharacterClass(_strings![Operand(0)], IsCaseInsensitive(), charInClassLocal); + EmitMatchCharacterClass(_strings![Operand(0)], IsCaseInsensitive()); BrtrueFar(loopCondition); } else { - if (IsCaseInsensitive()) + if (IsCaseInsensitive() && ParticipatesInCaseConversion(Operand(0))) { CallToLower(); } @@ -4777,12 +4872,15 @@ private void GenerateOneCode() PopTrack(); Stloc(_runtextposLocal!); PopTrack(); - Stloc(_temp1Local!); - Ldloc(_temp1Local!); - Ldc(0); - BleFar(AdvanceLabel()); - ReadyPushTrack(); - Ldloc(_temp1Local!); + using (RentedLocalBuilder posLocal = RentInt32Local()) + { + Stloc(posLocal); + Ldloc(posLocal); + Ldc(0); + BleFar(AdvanceLabel()); + ReadyPushTrack(); + Ldloc(posLocal); + } Ldc(1); Sub(); DoPush(); @@ -4813,8 +4911,6 @@ private void GenerateOneCode() //: if (c > 0) //: Track(c - 1, Textpos()); { - LocalBuilder cLocal = _temp1Local!; - int c = Operand(1); if (c == 0) { @@ -4832,22 +4928,25 @@ private void GenerateOneCode() Ldloc(_runtextbegLocal!); } Sub(); - if (c != int.MaxValue) + using (RentedLocalBuilder cLocal = RentInt32Local()) { - Label l4 = DefineLabel(); - Dup(); - Ldc(c); - Blt(l4); - Pop(); - Ldc(c); - MarkLabel(l4); + Stloc(cLocal); + if (c != int.MaxValue) + { + Label l4 = DefineLabel(); + Ldloc(cLocal); + Ldc(c); + Blt(l4); + Ldc(c); + Stloc(cLocal); + MarkLabel(l4); + } + Ldloc(cLocal); + Ldc(0); + Ble(AdvanceLabel()); + ReadyPushTrack(); + Ldloc(cLocal); } - Dup(); - Stloc(cLocal); - Ldc(0); - Ble(AdvanceLabel()); - ReadyPushTrack(); - Ldloc(cLocal); Ldc(1); Sub(); DoPush(); @@ -4877,50 +4976,51 @@ private void GenerateOneCode() //: if (i > 0) //: Track(i - 1, pos + 1); - charInClassLocal = _temp1Local!; - PopTrack(); Stloc(_runtextposLocal!); PopTrack(); - Stloc(_temp2Local!); - - if (!IsRightToLeft()) - { - Rightcharnext(); - } - else + using (RentedLocalBuilder iLocal = RentInt32Local()) { - Leftcharnext(); - } + Stloc(iLocal); - if (Code() == RegexCode.Setlazy) - { - EmitMatchCharacterClass(_strings![Operand(0)], IsCaseInsensitive(), charInClassLocal); - BrfalseFar(_backtrack); - } - else - { - if (IsCaseInsensitive()) + if (!IsRightToLeft()) { - CallToLower(); + Rightcharnext(); + } + else + { + Leftcharnext(); } - Ldc(Operand(0)); - if (Code() == RegexCode.Onelazy) + if (Code() == RegexCode.Setlazy) { - BneFar(_backtrack); + EmitMatchCharacterClass(_strings![Operand(0)], IsCaseInsensitive()); + BrfalseFar(_backtrack); } else { - BeqFar(_backtrack); + if (IsCaseInsensitive() && ParticipatesInCaseConversion(Operand(0))) + { + CallToLower(); + } + + Ldc(Operand(0)); + if (Code() == RegexCode.Onelazy) + { + BneFar(_backtrack); + } + else + { + BeqFar(_backtrack); + } } - } - Ldloc(_temp2Local!); - Ldc(0); - BleFar(AdvanceLabel()); - ReadyPushTrack(); - Ldloc(_temp2Local!); + Ldloc(iLocal); + Ldc(0); + BleFar(AdvanceLabel()); + ReadyPushTrack(); + Ldloc(iLocal); + } Ldc(1); Sub(); DoPush(); @@ -4937,7 +5037,7 @@ private void GenerateOneCode() /// Emits a a check for whether the character is in the specified character class. /// The character to be checked has already been loaded onto the stack. - private void EmitMatchCharacterClass(string charClass, bool caseInsensitive, LocalBuilder tempLocal) + private void EmitMatchCharacterClass(string charClass, bool caseInsensitive) { // We need to perform the equivalent of calling RegexRunner.CharInClass(ch, charClass), // but that call is relatively expensive. Before we fall back to it, we try to optimize @@ -5044,6 +5144,7 @@ private void EmitMatchCharacterClass(string charClass, bool caseInsensitive, Loc // All checks after this point require reading the input character multiple times, // so we store it into a temporary local. + using RentedLocalBuilder tempLocal = RentInt32Local(); Stloc(tempLocal); // Next, if there's only 2 or 3 chars in the set (fairly common due to the sets we create for prefixes), @@ -5075,6 +5176,8 @@ private void EmitMatchCharacterClass(string charClass, bool caseInsensitive, Loc } } + using RentedLocalBuilder resultLocal = RentInt32Local(); + // Analyze the character set more to determine what code to generate. RegexCharClass.CharClassAnalysisResults analysis = RegexCharClass.Analyze(charClass); @@ -5088,6 +5191,7 @@ void EmitCharInClass() } Ldstr(charClass); Call(s_charInClassMethod); + Stloc(resultLocal); } Label doneLabel = DefineLabel(); @@ -5111,7 +5215,9 @@ void EmitCharInClass() Br(doneLabel); MarkLabel(comparisonLabel); Ldc(0); + Stloc(resultLocal); MarkLabel(doneLabel); + Ldloc(resultLocal); return; } @@ -5129,7 +5235,9 @@ void EmitCharInClass() Br(doneLabel); MarkLabel(comparisonLabel); Ldc(1); + Stloc(resultLocal); MarkLabel(doneLabel); + Ldloc(resultLocal); return; } } @@ -5186,6 +5294,7 @@ void EmitCharInClass() And(); Ldc(0); CgtUn(); + Stloc(resultLocal); Br(doneLabel); MarkLabel(comparisonLabel); @@ -5195,6 +5304,7 @@ void EmitCharInClass() // character class were [A-Za-z0-9], so since the ch is now known to be >= 128, we // can just fail the comparison. Ldc(0); + Stloc(resultLocal); } else if (analysis.AllNonAsciiContained) { @@ -5202,6 +5312,7 @@ void EmitCharInClass() // class were [^\r\n], so since we just determined the ch to be >= 128, we can just // give back success. Ldc(1); + Stloc(resultLocal); } else { @@ -5211,6 +5322,7 @@ void EmitCharInClass() EmitCharInClass(); } MarkLabel(doneLabel); + Ldloc(resultLocal); } /// Emits a timeout check. @@ -5236,7 +5348,7 @@ private void EmitTimeoutCheck() RemUn(); Brtrue(label); Ldthis(); - Callvirt(s_checkTimeoutMethod); + Call(s_checkTimeoutMethod); MarkLabel(label); } @@ -5249,7 +5361,7 @@ private void DumpBacktracking() Mvlocfld(_runtrackposLocal!, s_runtrackposField); Mvlocfld(_runstackposLocal!, s_runstackposField); Ldthis(); - Callvirt(s_dumpStateM); + Call(s_dumpStateM); var sb = new StringBuilder(); if (_backpos > 0) diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexInterpreter.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexInterpreter.cs index 2de366b9a34f88..e479b3720f9b6e 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexInterpreter.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexInterpreter.cs @@ -1345,6 +1345,14 @@ protected override void Go() advance = 2; continue; + case RegexCode.UpdateBumpalong: + // UpdateBumpalong should only exist in the code stream at such a point where the root + // of the backtracking stack contains the runtextpos from the start of this Go call. Replace + // that tracking value with the current runtextpos value. + runtrack![runtrack.Length - 1] = runtextpos; + advance = 0; + continue; + default: Debug.Fail($"Unimplemented state: {_operator:X8}"); break; diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs index 64d7052da7a034..79f352130f5d71 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs @@ -80,6 +80,7 @@ internal sealed class RegexNode public const int Oneloopatomic = RegexCode.Oneloopatomic; // c,n (?> a*) public const int Notoneloopatomic = RegexCode.Notoneloopatomic; // c,n (?> .*) public const int Setloopatomic = RegexCode.Setloopatomic; // set,n (?> \d*) + public const int UpdateBumpalong = RegexCode.UpdateBumpalong; // Interior nodes do not correspond to primitive operations, but // control structures compositing other operations @@ -235,6 +236,7 @@ private void ValidateFinalTreeInvariants() case Setloop: case Setloopatomic: case Start: + case UpdateBumpalong: Debug.Assert(childCount == 0, $"Expected zero children for {node.TypeName}, got {childCount}."); break; @@ -308,6 +310,47 @@ internal RegexNode FinalOptimize() // to implementations that don't support backtracking. EliminateEndingBacktracking(rootNode.Child(0), DefaultMaxRecursionDepth); + // Optimization: unnecessary re-processing of starting loops. + // If an expression is guaranteed to begin with a single-character unbounded loop that isn't part of an alternation (in which case it + // wouldn't be guaranteed to be at the beginning) or a capture (in which case a back reference could be influenced by its length), then we + // can update the tree with a temporary node to indicate that the implementation should use that node's ending position in the input text + // as the next starting position at which to start the next match. This avoids redoing matches we've already performed, e.g. matching + // "\w+@dot.net" against "is this a valid address@dot.net", the \w+ will initially match the "is" and then will fail to match the "@". + // Rather than bumping the scan loop by 1 and trying again to match at the "s", we can instead start at the " ". For functional correctness + // we can only consider unbounded loops, as to be able to start at the end of the loop we need the loop to have consumed all possible matches; + // otherwise, you could end up with a pattern like "a{1,3}b" matching against "aaaabc", which should match, but if we pre-emptively stop consuming + // after the first three a's and re-start from that position, we'll end up failing the match even though it should have succeeded. We can also + // apply this optimization to non-atomic loops. Even though backtracking could be necessary, such backtracking would be handled within the processing + // of a single starting position. + { + RegexNode node = rootNode.Child(0); // skip implicit root capture node + while (true) + { + switch (node.Type) + { + case Atomic: + case Concatenate: + node = node.Child(0); + continue; + + case Oneloop when node.N == int.MaxValue: + case Oneloopatomic when node.N == int.MaxValue: + case Notoneloop when node.N == int.MaxValue: + case Notoneloopatomic when node.N == int.MaxValue: + case Setloop when node.N == int.MaxValue: + case Setloopatomic when node.N == int.MaxValue: + RegexNode? parent = node.Next; + if (parent != null && parent.Type == Concatenate) + { + parent.InsertChild(1, new RegexNode(UpdateBumpalong, node.Options)); + } + break; + } + + break; + } + } + // Optimization: implicit anchoring. // If the expression begins with a .* loop, add an anchor to the beginning: // - If Singleline is set such that '.' eats anything, the .* will zip to the end of the string and then backtrack through @@ -1603,7 +1646,7 @@ static int ComputeMinLength(RegexNode node, uint maxDepth) case Lazyloop: case Loop: // A node graph repeated at least M times. - return node.M * ComputeMinLength(node.Child(0), maxDepth - 1); + return (int)Math.Min(int.MaxValue, (long)node.M * ComputeMinLength(node.Child(0), maxDepth - 1)); case Alternate: // The minimum required length for any of the alternation's branches. @@ -1621,13 +1664,13 @@ static int ComputeMinLength(RegexNode node, uint maxDepth) case Concatenate: // The sum of all of the concatenation's children. { - int sum = 0; + long sum = 0; int childCount = node.ChildCount(); for (int i = 0; i < childCount; i++) { sum += ComputeMinLength(node.Child(i), maxDepth - 1); } - return sum; + return (int)Math.Min(int.MaxValue, sum); } case Atomic: @@ -1639,8 +1682,9 @@ static int ComputeMinLength(RegexNode node, uint maxDepth) case Empty: case Nothing: + case UpdateBumpalong: // Nothing to match. In the future, we could potentially use Nothing to say that the min length - // is infinite, but that would require a different structure, as that would only applies if the + // is infinite, but that would require a different structure, as that would only apply if the // Nothing match is required in all cases (rather than, say, as one branch of an alternation). case Beginning: case Bol: @@ -1668,7 +1712,7 @@ static int ComputeMinLength(RegexNode node, uint maxDepth) #if DEBUG Debug.Fail($"Unknown node: {node.TypeName}"); #endif - return 0; + goto case Empty; } } } @@ -1716,6 +1760,17 @@ public void AddChild(RegexNode newChild) } } + public void InsertChild(int index, RegexNode newChild) + { + Debug.Assert(Children is List); + + newChild.Next = this; // so that the child can see its parent while being reduced + newChild = newChild.Reduce(); + newChild.Next = this; // in case Reduce returns a different node that needs to be reparented + + ((List)Children).Insert(index, newChild); + } + public void ReplaceChild(int index, RegexNode newChild) { Debug.Assert(Children != null); @@ -1799,6 +1854,7 @@ public int ChildCount() Atomic => nameof(Atomic), Testref => nameof(Testref), Testgroup => nameof(Testgroup), + UpdateBumpalong => nameof(UpdateBumpalong), _ => $"(unknown {Type})" }; diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs index 627a4850c1ca62..21e3856571cc88 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefixAnalyzer.cs @@ -608,6 +608,7 @@ private void CalculateFC(int NodeType, RegexNode node, int CurIndex) case RegexNode.Start: case RegexNode.EndZ: case RegexNode.End: + case RegexNode.UpdateBumpalong: PushFC(new RegexFC(true)); break; diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs index 33fe44fec090b7..f09b3836ebc0dc 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs @@ -518,6 +518,7 @@ private void EmitFragment(int nodetype, RegexNode node, int curIndex) case RegexNode.Start: case RegexNode.EndZ: case RegexNode.End: + case RegexNode.UpdateBumpalong: Emit(node.Type); break; diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Groups.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/Regex.Groups.Tests.cs index 60537db3f3ba0f..827f66421d6266 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/Regex.Groups.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/Regex.Groups.Tests.cs @@ -391,7 +391,6 @@ public static IEnumerable Groups_Basic_TestData() if (!PlatformDetection.IsNetFramework) // missing fix for https://github.com/dotnet/runtime/issues/24759 { yield return new object[] { null, @"(cat)(\c[*)(dog)", "asdlkcat\u001bdogiwod", RegexOptions.None, new string[] { "cat\u001bdog", "cat", "\u001b", "dog" } }; - yield return new object[] { null, @"(cat)(\c[*)(dog)", "asdlkcat\u001Bdogiwod", RegexOptions.None, new string[] { "cat\u001Bdog", "cat", "\u001B", "dog" } }; } // Atomic Zero-Width Assertions \A \G ^ \Z \z \b \B diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs index 1f027233ed5943..efd7b3cc7d8cc1 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs @@ -96,6 +96,37 @@ public static IEnumerable Match_Basic_TestData() yield return new object[] { Case(@"a[^wyz]*w"), "abczw", RegexOptions.IgnoreCase, 0, 0, false, string.Empty }; } + // Loops at beginning of expressions + yield return new object[] { @"a+", "aaa", RegexOptions.None, 0, 3, true, "aaa" }; + yield return new object[] { @"a+\d+", "a1", RegexOptions.None, 0, 2, true, "a1" }; + yield return new object[] { @".+\d+", "a1", RegexOptions.None, 0, 2, true, "a1" }; + yield return new object[] { ".+\nabc", "a\nabc", RegexOptions.None, 0, 5, true, "a\nabc" }; + yield return new object[] { @"\d+", "abcd123efg", RegexOptions.None, 0, 10, true, "123" }; + yield return new object[] { @"\d+\d+", "abcd123efg", RegexOptions.None, 0, 10, true, "123" }; + yield return new object[] { @"\w+123\w+", "abcd123efg", RegexOptions.None, 0, 10, true, "abcd123efg" }; + yield return new object[] { @"\d+\w+", "abcd123efg", RegexOptions.None, 0, 10, true, "123efg" }; + yield return new object[] { @"\w+@\w+.com", "abc@def.com", RegexOptions.None, 0, 11, true, "abc@def.com" }; + yield return new object[] { @"\w{3,}@\w+.com", "abc@def.com", RegexOptions.None, 0, 11, true, "abc@def.com" }; + yield return new object[] { @"\w{4,}@\w+.com", "abc@def.com", RegexOptions.None, 0, 11, false, string.Empty }; + yield return new object[] { @"\w{2,5}@\w+.com", "abc@def.com", RegexOptions.None, 0, 11, true, "abc@def.com" }; + yield return new object[] { @"\w{3}@\w+.com", "abc@def.com", RegexOptions.None, 0, 11, true, "abc@def.com" }; + yield return new object[] { @"\w{0,3}@\w+.com", "abc@def.com", RegexOptions.None, 0, 11, true, "abc@def.com" }; + yield return new object[] { @"\w{0,2}c@\w+.com", "abc@def.com", RegexOptions.None, 0, 11, true, "abc@def.com" }; + yield return new object[] { @"\w*@\w+.com", "abc@def.com", RegexOptions.None, 0, 11, true, "abc@def.com" }; + yield return new object[] { @"(\w+)@\w+.com", "abc@def.com", RegexOptions.None, 0, 11, true, "abc@def.com" }; + yield return new object[] { @"((\w+))@\w+.com", "abc@def.com", RegexOptions.None, 0, 11, true, "abc@def.com" }; + yield return new object[] { @"(\w+)c@\w+.com", "abc@def.comabcdef", RegexOptions.None, 0, 17, true, "abc@def.com" }; + yield return new object[] { @"(\w+)c@\w+.com\1", "abc@def.comabcdef", RegexOptions.None, 0, 17, true, "abc@def.comab" }; + yield return new object[] { @"(\w+)@def.com\1", "abc@def.comab", RegexOptions.None, 0, 13, false, string.Empty }; + yield return new object[] { @"(\w+)@def.com\1", "abc@def.combc", RegexOptions.None, 0, 13, true, "bc@def.combc" }; + yield return new object[] { @"(\w*)@def.com\1", "abc@def.com", RegexOptions.None, 0, 11, true, "@def.com" }; + yield return new object[] { @"\w+(?\w+)(?\w+)(?() + { + UnicodeCategory.ClosePunctuation, + UnicodeCategory.ConnectorPunctuation, + UnicodeCategory.Control, + UnicodeCategory.DashPunctuation, + UnicodeCategory.DecimalDigitNumber, + UnicodeCategory.FinalQuotePunctuation, + UnicodeCategory.InitialQuotePunctuation, + UnicodeCategory.LineSeparator, + UnicodeCategory.OpenPunctuation, + UnicodeCategory.OtherNumber, + UnicodeCategory.OtherPunctuation, + UnicodeCategory.ParagraphSeparator, + UnicodeCategory.SpaceSeparator, + }; + + foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.AllCultures)) + { + using (new ThreadCultureChange(ci)) + { + for (int i = 0; i <= char.MaxValue; i++) + { + char ch = (char)i; + char upper = char.ToUpper(ch); + char lower = char.ToLower(ch); + + if (nonParticipatingCategories.Contains(char.GetUnicodeCategory(ch))) + { + // If this character is in one of these categories, make sure it doesn't change case. + Assert.Equal(ch, upper); + Assert.Equal(ch, lower); + } + else + { + // If it's not in one of these categories, make sure it doesn't change case to + // something in one of these categories. + UnicodeCategory upperCategory = char.GetUnicodeCategory(upper); + UnicodeCategory lowerCategory = char.GetUnicodeCategory(lower); + Assert.False(nonParticipatingCategories.Contains(upperCategory)); + Assert.False(nonParticipatingCategories.Contains(lowerCategory)); + } + } + } + } + } } } diff --git a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs index a4fd8028ac1ec6..1c416b83a1ed6d 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/RegexReductionTests.cs @@ -495,6 +495,8 @@ public void PatternsReduceDifferently(string pattern1, string pattern2) [InlineData(@"abcd(?<=cd)efgh", 8)] [InlineData(@"abcd(?!ab)efgh", 8)] [InlineData(@"abcd(?$(NoWarn);xUnit2008 $(NetCoreAppCurrent);$(NetFrameworkCurrent) - - @@ -31,11 +29,10 @@ - - System\Text\RegularExpressions\RegexParseError.cs - + - + @@ -43,8 +40,7 @@ - - Common\System\Diagnostics\DebuggerAttributes.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Threading.AccessControl/ref/System.Threading.AccessControl.csproj b/src/libraries/System.Threading.AccessControl/ref/System.Threading.AccessControl.csproj index ebfcb7b72d3b38..cf6065780fc0bf 100644 --- a/src/libraries/System.Threading.AccessControl/ref/System.Threading.AccessControl.csproj +++ b/src/libraries/System.Threading.AccessControl/ref/System.Threading.AccessControl.csproj @@ -1,17 +1,20 @@ - true netstandard2.0;net461;$(NetFrameworkCurrent) true + + + true + - + - + diff --git a/src/libraries/System.Threading.AccessControl/src/System.Threading.AccessControl.csproj b/src/libraries/System.Threading.AccessControl/src/System.Threading.AccessControl.csproj index 3ad5f73d3e1741..0b52003d96fe07 100644 --- a/src/libraries/System.Threading.AccessControl/src/System.Threading.AccessControl.csproj +++ b/src/libraries/System.Threading.AccessControl/src/System.Threading.AccessControl.csproj @@ -1,25 +1,39 @@ - SR.PlatformNotSupported_AccessControl - true netstandard2.0-Windows_NT;net461-Windows_NT;netstandard2.0;$(NetFrameworkCurrent)-Windows_NT true true + + + SR.PlatformNotSupported_AccessControl + true + - + - - - - - - - - - - - + + + + + + + + + + + @@ -28,7 +42,7 @@ - + @@ -36,9 +50,9 @@ - + - \ No newline at end of file + diff --git a/src/libraries/System.Threading.AccessControl/tests/System.Threading.AccessControl.Tests.csproj b/src/libraries/System.Threading.AccessControl/tests/System.Threading.AccessControl.Tests.csproj index d5d815abc08a78..c60e1d656cd047 100644 --- a/src/libraries/System.Threading.AccessControl/tests/System.Threading.AccessControl.Tests.csproj +++ b/src/libraries/System.Threading.AccessControl/tests/System.Threading.AccessControl.Tests.csproj @@ -3,8 +3,10 @@ $(NetCoreAppCurrent)-Windows_NT;$(NetFrameworkCurrent)-Windows_NT - - + + @@ -12,4 +14,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Threading.Channels/ref/System.Threading.Channels.csproj b/src/libraries/System.Threading.Channels/ref/System.Threading.Channels.csproj index d20343465933a6..658b5221eade3c 100644 --- a/src/libraries/System.Threading.Channels/ref/System.Threading.Channels.csproj +++ b/src/libraries/System.Threading.Channels/ref/System.Threading.Channels.csproj @@ -1,16 +1,16 @@ - netcoreapp3.0;netstandard1.3;netstandard2.0;$(NetCoreAppCurrent) + $(NetCoreAppCurrent);netcoreapp3.0;netstandard1.3;netstandard2.0 true enable - + - + diff --git a/src/libraries/System.Threading.Channels/src/System.Threading.Channels.csproj b/src/libraries/System.Threading.Channels/src/System.Threading.Channels.csproj index bc603a3817baec..f6f466c6260210 100644 --- a/src/libraries/System.Threading.Channels/src/System.Threading.Channels.csproj +++ b/src/libraries/System.Threading.Channels/src/System.Threading.Channels.csproj @@ -8,16 +8,16 @@ - - + + - + - + @@ -25,8 +25,10 @@ - - + + @@ -36,8 +38,8 @@ - + - \ No newline at end of file + diff --git a/src/libraries/System.Threading.Channels/tests/System.Threading.Channels.Tests.csproj b/src/libraries/System.Threading.Channels/tests/System.Threading.Channels.Tests.csproj index 46c9198e3b0d63..a2811146aa12f7 100644 --- a/src/libraries/System.Threading.Channels/tests/System.Threading.Channels.Tests.csproj +++ b/src/libraries/System.Threading.Channels/tests/System.Threading.Channels.Tests.csproj @@ -5,16 +5,17 @@ - - - - Common\System\Diagnostics\DebuggerAttributes.cs - + - \ No newline at end of file + + + + + diff --git a/src/libraries/System.Threading.Overlapped/tests/System.Threading.Overlapped.Tests.csproj b/src/libraries/System.Threading.Overlapped/tests/System.Threading.Overlapped.Tests.csproj index 495e5054c7ca56..9b8f3480190fd3 100644 --- a/src/libraries/System.Threading.Overlapped/tests/System.Threading.Overlapped.Tests.csproj +++ b/src/libraries/System.Threading.Overlapped/tests/System.Threading.Overlapped.Tests.csproj @@ -23,8 +23,7 @@ - - CommonTest\System\Threading\ThreadTestHelpers.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Threading.Tasks.Dataflow/src/System.Threading.Tasks.Dataflow.csproj b/src/libraries/System.Threading.Tasks.Dataflow/src/System.Threading.Tasks.Dataflow.csproj index 9e20116e0ba468..2af9d7adad7f4a 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/src/System.Threading.Tasks.Dataflow.csproj +++ b/src/libraries/System.Threading.Tasks.Dataflow/src/System.Threading.Tasks.Dataflow.csproj @@ -1,11 +1,14 @@ - + + + netstandard2.0;netstandard1.0;netstandard1.1 + enable + + $(DefineConstants);FEATURE_TRACING $(DefineConstants);USE_INTERNAL_CONCURRENT_COLLECTIONS $(DefineConstants);USE_INTERNAL_THREADING netstandard1.1;portable-net45+win8+wpa81 - netstandard2.0;netstandard1.0;netstandard1.1 - enable @@ -41,9 +44,8 @@ - - Common\Internal\Padding.cs - + @@ -76,4 +78,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Threading.Tasks.Dataflow/tests/System.Threading.Tasks.Dataflow.Tests.csproj b/src/libraries/System.Threading.Tasks.Dataflow/tests/System.Threading.Tasks.Dataflow.Tests.csproj index 1b02b25a8553c3..64d15af718d8e9 100644 --- a/src/libraries/System.Threading.Tasks.Dataflow/tests/System.Threading.Tasks.Dataflow.Tests.csproj +++ b/src/libraries/System.Threading.Tasks.Dataflow/tests/System.Threading.Tasks.Dataflow.Tests.csproj @@ -21,11 +21,9 @@ - - Common\System\Diagnostics\Tracing\TestEventListener.cs - - - Common\System\Diagnostics\DebuggerAttributes.cs - + + - \ No newline at end of file + diff --git a/src/libraries/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj b/src/libraries/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj index 65d89caaf8e729..6a7215d2b5cb57 100644 --- a/src/libraries/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj +++ b/src/libraries/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj @@ -9,14 +9,11 @@ - - Common\System\Threading\Tasks\Sources\ManualResetValueTaskSource.cs - - - Common\System\Threading\Tasks\Sources\ManualResetValueTaskSourceFactory.cs - - - Common\System\Threading\Tasks\GetStateMachineData.cs - + + + - \ No newline at end of file + diff --git a/src/libraries/System.Threading.Tasks.Parallel/tests/System.Threading.Tasks.Parallel.Tests.csproj b/src/libraries/System.Threading.Tasks.Parallel/tests/System.Threading.Tasks.Parallel.Tests.csproj index 0c93e3a41ffa05..b758ad3f2f258b 100644 --- a/src/libraries/System.Threading.Tasks.Parallel/tests/System.Threading.Tasks.Parallel.Tests.csproj +++ b/src/libraries/System.Threading.Tasks.Parallel/tests/System.Threading.Tasks.Parallel.Tests.csproj @@ -7,9 +7,8 @@ - - Common\System\Diagnostics\Tracing\TestEventListener.cs - + @@ -25,8 +24,7 @@ - - CommonTest\System\Threading\ThreadPoolHelpers.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj b/src/libraries/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj index d05826479b00d1..d123c71e67a98d 100644 --- a/src/libraries/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj +++ b/src/libraries/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj @@ -48,15 +48,12 @@ - - Common\System\Diagnostics\Tracing\TestEventListener.cs - - - CommonTest\System\Threading\ThreadPoolHelpers.cs - - - Common\System\Threading\Tasks\TaskTimeoutExtensions.cs - + + + - \ No newline at end of file + diff --git a/src/libraries/System.Threading.Thread/tests/System.Threading.Thread.Tests.csproj b/src/libraries/System.Threading.Thread/tests/System.Threading.Thread.Tests.csproj index 5834cb689cb113..5f4448b2bc4fb7 100644 --- a/src/libraries/System.Threading.Thread/tests/System.Threading.Thread.Tests.csproj +++ b/src/libraries/System.Threading.Thread/tests/System.Threading.Thread.Tests.csproj @@ -12,9 +12,8 @@ - - CommonTest\System\Threading\ThreadTestHelpers.cs - + diff --git a/src/libraries/System.Threading.Thread/tests/ThreadTests.cs b/src/libraries/System.Threading.Thread/tests/ThreadTests.cs index 846602b863b3bf..97356a400e7f38 100644 --- a/src/libraries/System.Threading.Thread/tests/ThreadTests.cs +++ b/src/libraries/System.Threading.Thread/tests/ThreadTests.cs @@ -651,6 +651,20 @@ public static void NameTest() }); } + [Fact] + public static void ThreadNameDoesNotAffectProcessName() + { + // On Linux, changing the main thread name affects ProcessName. + // To avoid that, .NET ignores requests to change the main thread name. + RemoteExecutor.Invoke(() => + { + const string ThreadName = "my-thread"; + Thread.CurrentThread.Name = ThreadName; + Assert.Equal(ThreadName, Thread.CurrentThread.Name); + Assert.NotEqual(ThreadName, Process.GetCurrentProcess().ProcessName); + }).Dispose(); + } + [Fact] public static void PriorityTest() { diff --git a/src/libraries/System.Threading.ThreadPool/tests/System.Threading.ThreadPool.Tests.csproj b/src/libraries/System.Threading.ThreadPool/tests/System.Threading.ThreadPool.Tests.csproj index c178d826b6809d..f4741b497460e7 100644 --- a/src/libraries/System.Threading.ThreadPool/tests/System.Threading.ThreadPool.Tests.csproj +++ b/src/libraries/System.Threading.ThreadPool/tests/System.Threading.ThreadPool.Tests.csproj @@ -8,8 +8,7 @@ - - CommonTest\System\Threading\ThreadTestHelpers.cs - + - \ No newline at end of file + diff --git a/src/libraries/System.Threading.Timer/tests/System.Threading.Timer.Tests.csproj b/src/libraries/System.Threading.Timer/tests/System.Threading.Timer.Tests.csproj index ed2ea9ccca87b9..30d9b8f8a207f0 100644 --- a/src/libraries/System.Threading.Timer/tests/System.Threading.Timer.Tests.csproj +++ b/src/libraries/System.Threading.Timer/tests/System.Threading.Timer.Tests.csproj @@ -10,8 +10,7 @@ - - CommonTest\System\Threading\ThreadTestHelpers.cs - + \ No newline at end of file diff --git a/src/libraries/System.Threading/System.Threading.sln b/src/libraries/System.Threading/System.Threading.sln index ec1bcd94e864c5..9a376c5998cf0d 100644 --- a/src/libraries/System.Threading/System.Threading.sln +++ b/src/libraries/System.Threading/System.Threading.sln @@ -20,7 +20,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{7B12728C-1240-44E4-9989-439925F464D3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{7B12728C-1240-44E4-9989-439925F464D3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.Extensions", "..\System.Runtime.Extensions\src\System.Runtime.Extensions.csproj", "{81A726B8-EB35-4762-8B5E-C88F7FD0AE7E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -44,6 +46,10 @@ Global {7B12728C-1240-44E4-9989-439925F464D3}.Debug|Any CPU.Build.0 = Debug|Any CPU {7B12728C-1240-44E4-9989-439925F464D3}.Release|Any CPU.ActiveCfg = Release|Any CPU {7B12728C-1240-44E4-9989-439925F464D3}.Release|Any CPU.Build.0 = Release|Any CPU + {81A726B8-EB35-4762-8B5E-C88F7FD0AE7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {81A726B8-EB35-4762-8B5E-C88F7FD0AE7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {81A726B8-EB35-4762-8B5E-C88F7FD0AE7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {81A726B8-EB35-4762-8B5E-C88F7FD0AE7E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -53,6 +59,7 @@ Global {604027F5-1DFC-42F4-B4FE-61F8789BA647} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {F59F13CA-829A-4D02-9A1D-E40E61257177} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} {7B12728C-1240-44E4-9989-439925F464D3} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} + {81A726B8-EB35-4762-8B5E-C88F7FD0AE7E} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6CD053C6-9C97-470C-AD05-3EDD28D57C55} diff --git a/src/libraries/System.Threading/ref/System.Threading.cs b/src/libraries/System.Threading/ref/System.Threading.cs index 4c8dabcf6c621e..719a4c35d1b0ad 100644 --- a/src/libraries/System.Threading/ref/System.Threading.cs +++ b/src/libraries/System.Threading/ref/System.Threading.cs @@ -216,10 +216,10 @@ public static void MemoryBarrierProcessWide() { } public static partial class LazyInitializer { public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.NotNullAttribute] ref T? target) where T : class { throw null; } - public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.AllowNullAttribute] ref T target, ref bool initialized, [System.Diagnostics.CodeAnalysis.NotNullAttribute] ref object? syncLock) { throw null; } - public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.AllowNullAttribute] ref T target, ref bool initialized, [System.Diagnostics.CodeAnalysis.NotNullAttribute] ref object? syncLock, System.Func valueFactory) { throw null; } + public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.AllowNullAttribute] ref T target, ref bool initialized, [System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("syncLock")] ref object? syncLock) { throw null; } + public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.AllowNullAttribute] ref T target, ref bool initialized, [System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("syncLock")] ref object? syncLock, System.Func valueFactory) { throw null; } public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.NotNullAttribute] ref T? target, System.Func valueFactory) where T : class { throw null; } - public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.NotNullAttribute] ref T? target, [System.Diagnostics.CodeAnalysis.NotNullAttribute] ref object? syncLock, System.Func valueFactory) where T : class { throw null; } + public static T EnsureInitialized([System.Diagnostics.CodeAnalysis.NotNullAttribute] ref T? target, [System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute("syncLock")] ref object? syncLock, System.Func valueFactory) where T : class { throw null; } } public partial struct LockCookie { diff --git a/src/libraries/System.Threading/src/System.Threading.csproj b/src/libraries/System.Threading/src/System.Threading.csproj index 6401755e4cdbc0..dbe7a3df3fbdd4 100644 --- a/src/libraries/System.Threading/src/System.Threading.csproj +++ b/src/libraries/System.Threading/src/System.Threading.csproj @@ -14,9 +14,8 @@ - - Common\System\HResults.cs - + diff --git a/src/libraries/System.Threading/tests/InterlockedTests.cs b/src/libraries/System.Threading/tests/InterlockedTests.cs index 5d7b053b838384..1b66dff0b1bd91 100644 --- a/src/libraries/System.Threading/tests/InterlockedTests.cs +++ b/src/libraries/System.Threading/tests/InterlockedTests.cs @@ -302,7 +302,7 @@ public void InterlockedOr_UInt64() Assert.Equal(0x17755771u, value); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotArm64Process))] // [ActiveIssue("https://github.com/dotnet/runtime/issues/11177")] + [Fact] public void MemoryBarrierProcessWide() { // Stress MemoryBarrierProcessWide correctness using a simple AsymmetricLock @@ -356,8 +356,6 @@ private static T VolatileReadWithoutBarrier(ref T location) return location; } - // Returning LockCookie to call Exit on is the fastest implementation because of it works naturally with the RCU pattern. - // The traditional Enter/Exit lock interface would require thread local storage or some other scheme to reclaim the cookie. // Returning LockCookie to call Exit on is the fastest implementation because of it works naturally with the RCU pattern. // The traditional Enter/Exit lock interface would require thread local storage or some other scheme to reclaim the cookie. public LockCookie Enter() @@ -380,6 +378,7 @@ public LockCookie Enter() // if (VolatileReadWithoutBarrier(ref _current) == entry) { + // at this point we know for sure that we own the lock. return entry; } @@ -398,8 +397,13 @@ private LockCookie EnterSlow() var oldEntry = _current; _current = new LockCookie(Environment.CurrentManagedThreadId); - // After MemoryBarrierProcessWide, we can be sure that the Volatile.Read done by the fast thread will see that it is not a fast - // thread anymore, and thus it will not attempt to enter the lock. + // MemoryBarrierProcessWide ensures, process-wide, that our write to _current becomes visible + // to every thread, and all writes by other threads become visible to us before we can continue. + // As a result any other thread that sets Taken to true either: + // a) made it past the read of _current and owns the lock OR + // b) will see that _current has changed and will revert Taken without taking the lock + // Thus we only need to wait for 'Taken' to become false and claim the lock for ourselves. + // 'Taken' may yet switch to true after that, but that cannot result in other thread owning the lock. Interlocked.MemoryBarrierProcessWide(); // Keep looping as long as the lock is taken by other thread diff --git a/src/libraries/System.Threading/tests/MutexTests.cs b/src/libraries/System.Threading/tests/MutexTests.cs index 79de3ee2be4f9f..1557a24f8a0da8 100644 --- a/src/libraries/System.Threading/tests/MutexTests.cs +++ b/src/libraries/System.Threading/tests/MutexTests.cs @@ -394,46 +394,60 @@ public void AbandonExisting( public static IEnumerable CrossProcess_NamedMutex_ProtectedFileAccessAtomic_MemberData() { - var nameGuidStr = Guid.NewGuid().ToString("N"); foreach (var namePrefix in GetNamePrefixes()) { - yield return new object[] { namePrefix + nameGuidStr }; + yield return new object[] { namePrefix }; } } - [ActiveIssue("https://github.com/dotnet/runtime/issues/28449")] [Theory] + [ActiveIssue("https://github.com/dotnet/runtime/issues/36307", TestRuntimes.Mono)] [MemberData(nameof(CrossProcess_NamedMutex_ProtectedFileAccessAtomic_MemberData))] public void CrossProcess_NamedMutex_ProtectedFileAccessAtomic(string prefix) { - ThreadTestHelpers.RunTestInBackgroundThread(() => + string fileName = GetTestFilePath(); + try { - string mutexName = prefix + Guid.NewGuid().ToString("N"); - string fileName = GetTestFilePath(); - - Action otherProcess = (m, f) => + ThreadTestHelpers.RunTestInBackgroundThread(() => { - using (var mutex = Mutex.OpenExisting(m)) - { - mutex.CheckedWait(); - try - { File.WriteAllText(f, "0"); } - finally { mutex.ReleaseMutex(); } + string mutexName = prefix + Guid.NewGuid().ToString("N"); - IncrementValueInFileNTimes(mutex, f, 10); - } - }; + Action otherProcess = (m, f) => + { + using (var mutex = Mutex.OpenExisting(m)) + { + mutex.CheckedWait(); + try + { File.WriteAllText(f, "0"); } + finally { mutex.ReleaseMutex(); } - using (var mutex = new Mutex(false, mutexName)) - using (var remote = RemoteExecutor.Invoke(otherProcess, mutexName, fileName)) - { - SpinWait.SpinUntil(() => File.Exists(fileName), ThreadTestHelpers.UnexpectedTimeoutMilliseconds); + IncrementValueInFileNTimes(mutex, f, 10); + } + }; - IncrementValueInFileNTimes(mutex, fileName, 10); - } + using (var mutex = new Mutex(false, mutexName)) + using (var remote = RemoteExecutor.Invoke(otherProcess, mutexName, fileName)) + { + SpinWait.SpinUntil( + () => + { + mutex.CheckedWait(); + try + { return File.Exists(fileName) && int.TryParse(File.ReadAllText(fileName), out _); } + finally { mutex.ReleaseMutex(); } + }, + ThreadTestHelpers.UnexpectedTimeoutMilliseconds); + + IncrementValueInFileNTimes(mutex, fileName, 10); + } - Assert.Equal(20, int.Parse(File.ReadAllText(fileName))); - }); + Assert.Equal(20, int.Parse(File.ReadAllText(fileName))); + }); + } + catch (Exception ex) when (File.Exists(fileName)) + { + throw new AggregateException($"File contents: {File.ReadAllText(fileName)}", ex); + } } private static void IncrementValueInFileNTimes(Mutex mutex, string fileName, int n) @@ -451,6 +465,103 @@ private static void IncrementValueInFileNTimes(Mutex mutex, string fileName, int } } + [Fact] + public void NamedMutex_ThreadExitDisposeRaceTest() + { + var mutexName = Guid.NewGuid().ToString("N"); + + for (int i = 0; i < 1000; ++i) + { + var m = new Mutex(false, mutexName); + var startParallelTest = new ManualResetEvent(false); + + var t0Ready = new AutoResetEvent(false); + Thread t0 = ThreadTestHelpers.CreateGuardedThread(out Action waitForT0, () => + { + m.CheckedWait(); + t0Ready.Set(); + startParallelTest.CheckedWait(); // after this, exit T0 + }); + t0.IsBackground = true; + + var t1Ready = new AutoResetEvent(false); + Thread t1 = ThreadTestHelpers.CreateGuardedThread(out Action waitForT1, () => + { + using (var m2 = Mutex.OpenExisting(mutexName)) + { + m.Dispose(); + t1Ready.Set(); + startParallelTest.CheckedWait(); // after this, close last handle to named mutex, exit T1 + } + }); + t1.IsBackground = true; + + t0.Start(); + t0Ready.CheckedWait(); // wait for T0 to acquire the mutex + t1.Start(); + t1Ready.CheckedWait(); // wait for T1 to open the existing mutex in a new mutex object and dispose one of the two + + // Release both threads at the same time. T0 will be exiting the thread, perhaps trying to abandon the mutex + // that is still locked by it. In parallel, T1 will be disposing the last mutex instance, which would try to + // destroy the mutex. + startParallelTest.Set(); + waitForT0(); + waitForT1(); + + // Create a new mutex object with the same name and acquire it. There can be a delay between Thread.Join() above + // returning and for T0 to abandon its mutex, keep trying to also verify that the mutex object is actually + // destroyed and created new again. + SpinWait.SpinUntil(() => + { + using (m = new Mutex(true, mutexName, out bool createdNew)) + { + if (createdNew) + { + m.ReleaseMutex(); + } + return createdNew; + } + }); + } + } + + [Fact] + public void NamedMutex_DisposeWhenLockedRaceTest() + { + var mutexName = Guid.NewGuid().ToString("N"); + var mutex2Name = mutexName + "_2"; + + var waitsForThread = new Action[Environment.ProcessorCount]; + for (int i = 0; i < waitsForThread.Length; ++i) + { + var t = ThreadTestHelpers.CreateGuardedThread(out waitsForThread[i], () => + { + for (int i = 0; i < 1000; ++i) + { + // Create or open two mutexes with different names, acquire the lock if created, and dispose without + // releasing the lock. What may occasionally happen is, one thread T0 will acquire the lock, another + // thread T1 will open the same mutex, T0 will dispose its mutex while the lock is held, and T1 will + // then release the last reference to the mutex. On some implementations T1 may not be able to destroy + // the mutex when it is still locked by T0, or there may be potential for races in the sequence. This + // test only looks for errors from race conditions. + using (var mutex = new Mutex(true, mutexName)) + { + } + using (var mutex = new Mutex(true, mutex2Name)) + { + } + } + }); + t.IsBackground = true; + t.Start(); + } + + foreach (var waitForThread in waitsForThread) + { + waitForThread(); + } + } + public static TheoryData GetValidNames() { var names = new TheoryData() { Guid.NewGuid().ToString("N") }; diff --git a/src/libraries/System.Threading/tests/System.Threading.Tests.csproj b/src/libraries/System.Threading/tests/System.Threading.Tests.csproj index 4e27b5fc95d26b..5b1b5b087b2a2d 100644 --- a/src/libraries/System.Threading/tests/System.Threading.Tests.csproj +++ b/src/libraries/System.Threading/tests/System.Threading.Tests.csproj @@ -32,11 +32,9 @@ - - CommonTest\System\Diagnostics\Tracing\TestEventListener.cs - - - CommonTest\System\Threading\ThreadTestHelpers.cs - + + \ No newline at end of file diff --git a/src/libraries/System.Threading/tests/ThreadLocalTests.cs b/src/libraries/System.Threading/tests/ThreadLocalTests.cs index 58b56aecc8c0a7..70a4a5430223c8 100644 --- a/src/libraries/System.Threading/tests/ThreadLocalTests.cs +++ b/src/libraries/System.Threading/tests/ThreadLocalTests.cs @@ -217,7 +217,7 @@ public void Run() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsPreciseGcSupported))] public static void RunThreadLocalTest7_WeakReference() { var threadLocalWeakReferenceTest = new ThreadLocalWeakReferenceTest(); diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionScope.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionScope.cs index 71e2285e792a5f..acd51f7c186fc6 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionScope.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionScope.cs @@ -211,7 +211,7 @@ TransactionScopeAsyncFlowOption asyncFlowOption // If the requested IsolationLevel is stronger than that of the specified transaction, throw. if ((IsolationLevel.Unspecified != transactionOptions.IsolationLevel) && (_expectedCurrent.IsolationLevel != transactionOptions.IsolationLevel)) { - throw new ArgumentException(SR.TransactionScopeIsolationLevelDifferentFromTransaction, "transactionOptions.IsolationLevel"); + throw new ArgumentException(SR.TransactionScopeIsolationLevelDifferentFromTransaction, nameof(transactionOptions)); } } } @@ -293,7 +293,7 @@ public TransactionScope( // If the requested IsolationLevel is stronger than that of the specified transaction, throw. if ((IsolationLevel.Unspecified != transactionOptions.IsolationLevel) && (_expectedCurrent.IsolationLevel != transactionOptions.IsolationLevel)) { - throw new ArgumentException(SR.TransactionScopeIsolationLevelDifferentFromTransaction, "transactionOptions.IsolationLevel"); + throw new ArgumentException(SR.TransactionScopeIsolationLevelDifferentFromTransaction, nameof(transactionOptions)); } } } diff --git a/src/libraries/System.Transactions.Local/tests/System.Transactions.Local.Tests.csproj b/src/libraries/System.Transactions.Local/tests/System.Transactions.Local.Tests.csproj index 750635dac0a537..97efb68bab6ad5 100644 --- a/src/libraries/System.Transactions.Local/tests/System.Transactions.Local.Tests.csproj +++ b/src/libraries/System.Transactions.Local/tests/System.Transactions.Local.Tests.csproj @@ -1,6 +1,5 @@ - false true $(NetCoreAppCurrent) diff --git a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.csproj b/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.csproj index 7932a85d40138d..4ef79b71fc4671 100644 --- a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.csproj +++ b/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.csproj @@ -1,4 +1,4 @@ - + true @@ -18,7 +18,7 @@ - + diff --git a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.netcoreapp5.0.cs b/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.net5.0.cs similarity index 100% rename from src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.netcoreapp5.0.cs rename to src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.net5.0.cs diff --git a/src/libraries/System.Utf8String.Experimental/src/System.Utf8String.Experimental.csproj b/src/libraries/System.Utf8String.Experimental/src/System.Utf8String.Experimental.csproj index dd5adc8a691957..8c12e127139639 100644 --- a/src/libraries/System.Utf8String.Experimental/src/System.Utf8String.Experimental.csproj +++ b/src/libraries/System.Utf8String.Experimental/src/System.Utf8String.Experimental.csproj @@ -1,48 +1,42 @@ - + true + $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix;netstandard2.0;netstandard2.1;netcoreapp3.0 + enable + $(DefineContants);FEATURE_UTF8STRING + + + $(NoWarn);CS3019;CS0162 true - netstandard2.0;netstandard2.1;netcoreapp3.0;$(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix - enable - $(DefineContants);FEATURE_UTF8STRING - - System\Index.cs - - - System\Numerics\BitOperations.cs - - - System\Numerics\Hashing\HashHelpers.cs - - - System\Range.cs - - - System\Text\Rune.cs - - - System\Text\Unicode\Utf8.cs - + + + + + + - - System\Numerics\BitOperations.cs - - - System\Text\Rune.cs - - - System\Text\Unicode\Utf8.cs - + + + @@ -50,99 +44,68 @@ - - Common\System\Marvin.cs - - - Common\System\NotImplemented.cs - - - System\Char8.cs - - - System\Text\TrimType.cs - - - System\Text\UnicodeDebug.cs - - - System\Text\UnicodeUtility.cs - - - System\Text\Unicode\Utf16Utility.cs - - - System\Text\Unicode\Utf16Utility.Validation.cs - - - System\Text\Utf8StringComparer.cs - - - System\Text\ASCIIUtility.cs - - - System\Text\ASCIIUtility.Helpers.cs - - - System\Text\Unicode\Utf8Utility.cs - - - System\Text\Unicode\Utf8Utility.Helpers.cs - - - System\Text\Unicode\Utf8Utility.Validation.cs - - - System\Text\Unicode\Utf8Utility.Transcoding.cs - - - System\Text\Unicode\Utf8Utility.WhiteSpace.NonCoreLib.cs - - - System\Utf8StringSplitOptions.cs - - - System\Utf8Extensions.cs - - - System\Utf8String.cs - - - System\Utf8String.Comparison.cs - - - System\Utf8String.Construction.cs - - - System\Utf8String.Conversion.cs - - - System\Utf8String.Enumeration.cs - - - System\Utf8String.Manipulation.cs - - - System\Utf8String.Searching.cs - - - System\Text\Utf8Span.cs - - - System\Text\Utf8Span.Comparison.cs - - - System\Text\Utf8Span.Conversion.cs - - - System\Text\Utf8Span.Enumeration.cs - - - System\Text\Utf8Span.Manipulation.cs - - - System\Text\Utf8Span.Searching.cs - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -174,4 +137,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Utf8String.Experimental/src/System/Runtime/Intrinsics/Intrinsics.Shims.cs b/src/libraries/System.Utf8String.Experimental/src/System/Runtime/Intrinsics/Intrinsics.Shims.cs index 33c59a3f122db9..38e129a08022ca 100644 --- a/src/libraries/System.Utf8String.Experimental/src/System/Runtime/Intrinsics/Intrinsics.Shims.cs +++ b/src/libraries/System.Utf8String.Experimental/src/System/Runtime/Intrinsics/Intrinsics.Shims.cs @@ -4,6 +4,16 @@ namespace System.Runtime.Intrinsics { + internal static class Vector64 + { + public static Vector64 Create(ulong value) => throw new PlatformNotSupportedException(); + public static Vector64 AsByte(this Vector64 vector) where T : struct => throw new PlatformNotSupportedException(); + } + internal readonly struct Vector64 + where T : struct + { + } + internal static class Vector128 { public static Vector128 Create(short value) => throw new PlatformNotSupportedException(); @@ -15,6 +25,7 @@ internal static class Vector128 public static Vector128 AsUInt32(this Vector128 vector) where T : struct => throw new PlatformNotSupportedException(); public static Vector128 AsUInt64(this Vector128 vector) where T : struct => throw new PlatformNotSupportedException(); public static T GetElement(this Vector128 vector, int index) where T : struct => throw new PlatformNotSupportedException(); + public static T ToScalar(this Vector64 vector) where T : struct => throw new PlatformNotSupportedException(); } internal readonly struct Vector128 where T : struct @@ -26,6 +37,18 @@ internal readonly struct Vector128 namespace System.Runtime.Intrinsics.X86 { + internal static class X86Base + { + internal static class X64 + { + public const bool IsSupported = false; + internal static ulong BitScanForward(ulong value) => throw new PlatformNotSupportedException(); + internal static ulong BitScanReverse(ulong value) => throw new PlatformNotSupportedException(); + } + public const bool IsSupported = false; + internal static uint BitScanForward(uint value) => throw new PlatformNotSupportedException(); + internal static uint BitScanReverse(uint value) => throw new PlatformNotSupportedException(); + } internal abstract class Bmi1 { public abstract class X64 @@ -118,4 +141,13 @@ public abstract class Arm64 public static int LeadingZeroCount(uint value) => throw new PlatformNotSupportedException(); public static uint ReverseElementBits(uint value) => throw new PlatformNotSupportedException(); } + + internal abstract class AdvSimd : ArmBase + { + public new abstract class Arm64 : ArmBase.Arm64 + { + public static Vector64 AddAcross(Vector64 value) => throw new PlatformNotSupportedException(); + } + public static Vector64 PopCount(Vector64 value) => throw new PlatformNotSupportedException(); + } } diff --git a/src/libraries/System.Utf8String.Experimental/tests/System.Utf8String.Experimental.Tests.csproj b/src/libraries/System.Utf8String.Experimental/tests/System.Utf8String.Experimental.Tests.csproj index e571bbc5877b69..73e52762cdf013 100644 --- a/src/libraries/System.Utf8String.Experimental/tests/System.Utf8String.Experimental.Tests.csproj +++ b/src/libraries/System.Utf8String.Experimental/tests/System.Utf8String.Experimental.Tests.csproj @@ -1,12 +1,10 @@ - + true true $(NetCoreAppCurrent);$(NetFrameworkCurrent) true true - - true @@ -38,13 +36,13 @@ - + - + \ No newline at end of file diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Comparison.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Comparison.cs index 8e139fb63312f4..7d0c5bad6141e3 100644 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Comparison.cs +++ b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Comparison.cs @@ -47,8 +47,8 @@ public static void Equals_Ordinal() AssertEqualOrdinal(Utf8Span.Empty, u8("")); } - [Theory] [PlatformSpecific(TestPlatforms.Windows)] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] [InlineData(null, null, StringComparison.OrdinalIgnoreCase, null, true)] [InlineData("encyclopaedia", "encyclopædia", StringComparison.OrdinalIgnoreCase, null, false)] [InlineData("encyclopaedia", "encyclopædia", StringComparison.InvariantCulture, null, true)] diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Searching.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Searching.cs index 36b1842f48a7e1..a9c4102b11dd4b 100644 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Searching.cs +++ b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Searching.cs @@ -80,8 +80,8 @@ public static void TryFind_Char_Ordinal(ustring source, char searchTerm, Range? } } - [Theory] [PlatformSpecific(TestPlatforms.Windows)] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] [MemberData(nameof(TryFindData_Char_WithComparison))] public static void TryFind_Char_WithComparison(ustring source, char searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch) { @@ -227,8 +227,8 @@ public static void TryFind_Rune_Ordinal(ustring source, Rune searchTerm, Range? } } - [Theory] [PlatformSpecific(TestPlatforms.Windows)] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] [MemberData(nameof(TryFindData_Rune_WithComparison))] public static void TryFind_Rune_WithComparison(ustring source, Rune searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch) { @@ -374,8 +374,8 @@ public static void TryFind_Utf8Span_Ordinal(ustring source, ustring searchTerm, } } - [Theory] [PlatformSpecific(TestPlatforms.Windows)] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] [MemberData(nameof(TryFindData_Utf8Span_WithComparison))] public static void TryFind_Utf8Span_WithComparison(ustring source, ustring searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch) { diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.cs index ab1b528d49674f..cb169fd2423b07 100644 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.cs +++ b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.cs @@ -76,8 +76,8 @@ public static void GetHashCode_Ordinal() } } - [Fact] [PlatformSpecific(TestPlatforms.Windows)] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] public static void GetHashCode_WithComparison() { // Since hash code generation is randomized, it's possible (though unlikely) that diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Searching.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Searching.cs index 245877de18b0dc..f25d0e90699df4 100644 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Searching.cs +++ b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Searching.cs @@ -87,8 +87,8 @@ public static void TryFind_Char_Ordinal(ustring source, char searchTerm, Range? public static IEnumerable TryFindData_Char_WithComparison() => Utf8SpanTests.TryFindData_Char_WithComparison(); - [Theory] [PlatformSpecific(TestPlatforms.Windows)] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] [MemberData(nameof(TryFindData_Char_WithComparison))] public static void TryFind_Char_WithComparison(ustring source, char searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch) { @@ -240,8 +240,8 @@ public static void TryFind_Rune_Ordinal(ustring source, Rune searchTerm, Range? public static IEnumerable TryFindData_Rune_WithComparison() => Utf8SpanTests.TryFindData_Rune_WithComparison(); - [Theory] [PlatformSpecific(TestPlatforms.Windows)] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] [MemberData(nameof(TryFindData_Rune_WithComparison))] public static void TryFind_Rune_WithComparison(ustring source, Rune searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch) { @@ -393,8 +393,8 @@ public static void TryFind_Utf8String_Ordinal(ustring source, ustring searchTerm public static IEnumerable TryFindData_Utf8String_WithComparison() => Utf8SpanTests.TryFindData_Utf8Span_WithComparison(); - [Theory] [PlatformSpecific(TestPlatforms.Windows)] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] [MemberData(nameof(TryFindData_Utf8String_WithComparison))] public static void TryFind_Utf8String_WithComparison(ustring source, ustring searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch) { diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.cs index 260382383a68a7..773dea57bf9cec 100644 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.cs +++ b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.cs @@ -78,8 +78,8 @@ public static void GetHashCode_Ordinal() } } - [Fact] [PlatformSpecific(TestPlatforms.Windows)] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] public static void GetHashCode_WithComparison() { // Since hash code generation is randomized, it's possible (though unlikely) that diff --git a/src/libraries/System.ValueTuple/tests/System.ValueTuple.Tests.csproj b/src/libraries/System.ValueTuple/tests/System.ValueTuple.Tests.csproj index 9a1c5c1455f0c3..f0ec4ac41eb927 100644 --- a/src/libraries/System.ValueTuple/tests/System.ValueTuple.Tests.csproj +++ b/src/libraries/System.ValueTuple/tests/System.ValueTuple.Tests.csproj @@ -6,7 +6,7 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Web.HttpUtility/src/System.Web.HttpUtility.csproj b/src/libraries/System.Web.HttpUtility/src/System.Web.HttpUtility.csproj index 8779e2c76d94b5..2b5750a3707838 100644 --- a/src/libraries/System.Web.HttpUtility/src/System.Web.HttpUtility.csproj +++ b/src/libraries/System.Web.HttpUtility/src/System.Web.HttpUtility.csproj @@ -10,9 +10,8 @@ - - Common\System\HexConverter.cs - + diff --git a/src/libraries/System.Windows.Extensions/ref/System.Windows.Extensions.csproj b/src/libraries/System.Windows.Extensions/ref/System.Windows.Extensions.csproj index ac9792c7a5d076..ebbd3e46f7670e 100644 --- a/src/libraries/System.Windows.Extensions/ref/System.Windows.Extensions.csproj +++ b/src/libraries/System.Windows.Extensions/ref/System.Windows.Extensions.csproj @@ -1,6 +1,6 @@ - netcoreapp3.0;$(NetCoreAppCurrent) + $(NetCoreAppCurrent);netcoreapp3.0 true diff --git a/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj b/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj index 5608db2ffe1501..ea77d6793f77fc 100644 --- a/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj +++ b/src/libraries/System.Windows.Extensions/src/System.Windows.Extensions.csproj @@ -2,64 +2,46 @@ SR.PlatformNotSupported_System_Windows_Extensions true - netcoreapp3.0-Windows_NT;netcoreapp3.0;$(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent) + $(NetCoreAppCurrent)-Windows_NT;netcoreapp3.0-Windows_NT;netcoreapp3.0;$(NetCoreAppCurrent) true - - Common\Interop\Windows\Crypt32\Interop.CertAddCertificateLinkToStore.cs - - - Common\Interop\Windows\Crypt32\Interop.CertCloseStore.cs - - - Common\Interop\Windows\Crypt32\Interop.CertDuplicateCertificateContext.cs - - - Common\Interop\Windows\Crypt32\Interop.CertEnumCertificatesInStore_IntPtr.cs - - - Common\Interop\Windows\Crypt32\Interop.CertFreeCertificateContext.cs - - - Common\Interop\Windows\Crypt32\Interop.CertOpenStore.cs - - - Common\Interop\Windows\Crypt32\Interop.CryptUIDlgCertificate.cs - - - Common\Interop\Windows\User32\Interop.MessageBeep.cs - - - Common\Interop\Windows\WinMm\Interop.MMCKINFO.cs - - - Common\Interop\Windows\WinMm\Interop.mmioAscend.cs - - - Common\Interop\Windows\WinMm\Interop.mmioClose.cs - - - Common\Interop\Windows\WinMm\Interop.mmioDescend.cs - - - Common\Interop\Windows\WinMm\Interop.mmioRead.cs - - - Common\Interop\Windows\WinMm\Interop.mmioOpen.cs - - - Common\Interop\Windows\WinMm\Interop.PlaySound.cs - - - Common\Interop\Windows\Interop.Libraries.cs - - - Common\Microsoft\Win32\SafeHandles\SafeHandleCache.cs - - - Common\System\Text\ValueStringBuilder.cs - + + + + + + + + + + + + + + + + + + @@ -73,7 +55,7 @@ - + diff --git a/src/libraries/System.Windows.Extensions/src/System/Drawing/FontConverter.cs b/src/libraries/System.Windows.Extensions/src/System/Drawing/FontConverter.cs index aaea6553cf5983..af1308e860eacd 100644 --- a/src/libraries/System.Windows.Extensions/src/System/Drawing/FontConverter.cs +++ b/src/libraries/System.Windows.Extensions/src/System/Drawing/FontConverter.cs @@ -173,7 +173,7 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c catch { // Exception from converter is too generic. - throw new ArgumentException(SR.Format(SR.TextParseFailedFormat, font, $"name{separator} size[units[{separator} style=style1[{separator} style2{separator} ...]]]"), nameof(sizeStr)); + throw new ArgumentException(SR.Format(SR.TextParseFailedFormat, font, $"name{separator} size[units[{separator} style=style1[{separator} style2{separator} ...]]]"), nameof(value)); } } diff --git a/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs b/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs index 69d474b8803a1b..ae9cd72ae2e241 100644 --- a/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs +++ b/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs @@ -489,7 +489,7 @@ private async Task CopyStreamAsync(CancellationToken cancellationToken) _streamData = new byte[BlockSize]; - int readBytes = await _stream.ReadAsync(_streamData, _currentPos, BlockSize, cancellationToken).ConfigureAwait(false); + int readBytes = await _stream.ReadAsync(_streamData.AsMemory(_currentPos, BlockSize), cancellationToken).ConfigureAwait(false); int totalBytes = readBytes; while (readBytes > 0) @@ -501,7 +501,7 @@ private async Task CopyStreamAsync(CancellationToken cancellationToken) Array.Copy(_streamData, newData, _streamData.Length); _streamData = newData; } - readBytes = await _stream.ReadAsync(_streamData, _currentPos, BlockSize, cancellationToken).ConfigureAwait(false); + readBytes = await _stream.ReadAsync(_streamData.AsMemory(_currentPos, BlockSize), cancellationToken).ConfigureAwait(false); totalBytes += readBytes; } diff --git a/src/libraries/System.Windows.Extensions/tests/System.Windows.Extensions.Tests.csproj b/src/libraries/System.Windows.Extensions/tests/System.Windows.Extensions.Tests.csproj index ebd9e736f130ac..7396a53455fe91 100644 --- a/src/libraries/System.Windows.Extensions/tests/System.Windows.Extensions.Tests.csproj +++ b/src/libraries/System.Windows.Extensions/tests/System.Windows.Extensions.Tests.csproj @@ -8,9 +8,8 @@ - - Common\System\Drawing\Helpers.cs - + @@ -27,4 +26,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Windows.Extensions/tests/System/Drawing/FontConverterTests.cs b/src/libraries/System.Windows.Extensions/tests/System/Drawing/FontConverterTests.cs index 02a01346d208ff..951ccfaeb9193e 100644 --- a/src/libraries/System.Windows.Extensions/tests/System/Drawing/FontConverterTests.cs +++ b/src/libraries/System.Windows.Extensions/tests/System/Drawing/FontConverterTests.cs @@ -131,7 +131,7 @@ private static bool EmptyFontPresent public static TheoryData ArgumentExceptionFontConverterData() => new TheoryData() { { $"Courier New{s_Separator} 11 px{s_Separator} type=Bold{s_Separator} Italic", "units", null }, - { $"Courier New{s_Separator} {s_Separator} Style=Bold", "sizeStr", null }, + { $"Courier New{s_Separator} {s_Separator} Style=Bold", "value", null }, { $"Courier New{s_Separator} 11{s_Separator} Style=", "value", null }, { $"Courier New{s_Separator} 11{s_Separator} Style=RandomEnum", null, null }, { $"Arial{s_Separator} 10{s_Separator} style=bold{s_Separator}", "value", null }, diff --git a/src/libraries/System.Xml.ReaderWriter/System.Xml.ReaderWriter.sln b/src/libraries/System.Xml.ReaderWriter/System.Xml.ReaderWriter.sln index 9c718e59575a8d..bda1c0aff3f676 100644 --- a/src/libraries/System.Xml.ReaderWriter/System.Xml.ReaderWriter.sln +++ b/src/libraries/System.Xml.ReaderWriter/System.Xml.ReaderWriter.sln @@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.Xml", "..\System.Private.Xml\src\System.Private.Xml.csproj", "{6BF38109-85EC-4409-BFEA-7B2DAB946024}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +29,10 @@ Global {6F785D18-A969-4DB9-AB45-DD294839087D}.Debug|Any CPU.Build.0 = Debug|Any CPU {6F785D18-A969-4DB9-AB45-DD294839087D}.Release|Any CPU.ActiveCfg = Release|Any CPU {6F785D18-A969-4DB9-AB45-DD294839087D}.Release|Any CPU.Build.0 = Release|Any CPU + {6BF38109-85EC-4409-BFEA-7B2DAB946024}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6BF38109-85EC-4409-BFEA-7B2DAB946024}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6BF38109-85EC-4409-BFEA-7B2DAB946024}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6BF38109-85EC-4409-BFEA-7B2DAB946024}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -34,6 +40,7 @@ Global GlobalSection(NestedProjects) = preSolution {C559743A-762E-4D9D-B986-E77BDB97652E} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {6F785D18-A969-4DB9-AB45-DD294839087D} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} + {6BF38109-85EC-4409-BFEA-7B2DAB946024} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D394A911-8F2F-446B-B9F2-6B075160DF6A} diff --git a/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs b/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs index 83fa6c584289c5..8eab71f3d42518 100644 --- a/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs +++ b/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs @@ -1201,7 +1201,7 @@ public partial class XmlWhitespace : System.Xml.XmlCharacterData public override void WriteContentTo(System.Xml.XmlWriter w) { } public override void WriteTo(System.Xml.XmlWriter w) { } } - public abstract partial class XmlWriter : System.IDisposable + public abstract partial class XmlWriter : System.IDisposable, System.IAsyncDisposable { protected XmlWriter() { } public virtual System.Xml.XmlWriterSettings Settings { get { throw null; } } @@ -1306,6 +1306,8 @@ public virtual void WriteValue(float value) { } public virtual void WriteValue(string value) { } public abstract void WriteWhitespace(string ws); public virtual System.Threading.Tasks.Task WriteWhitespaceAsync(string ws) { throw null; } + public System.Threading.Tasks.ValueTask DisposeAsync() { throw null; } + protected virtual System.Threading.Tasks.ValueTask DisposeAsyncCore() { throw null; } } public sealed partial class XmlWriterSettings { diff --git a/src/libraries/System.Xml.XDocument/System.Xml.XDocument.sln b/src/libraries/System.Xml.XDocument/System.Xml.XDocument.sln index 8ef2fedcdc738e..f76ae08202fc71 100644 --- a/src/libraries/System.Xml.XDocument/System.Xml.XDocument.sln +++ b/src/libraries/System.Xml.XDocument/System.Xml.XDocument.sln @@ -13,6 +13,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.Xml.Linq", "..\System.Private.Xml.Linq\src\System.Private.Xml.Linq.csproj", "{C5273844-69B0-429C-92B8-0BBDC5C7562F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.Xml", "..\System.Private.Xml\src\System.Private.Xml.csproj", "{B31AAA00-76C3-45EA-9B6F-5996EAFCE73B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +31,14 @@ Global {506A8ECB-E5B4-4F10-8419-26A0EC7AB225}.Debug|Any CPU.Build.0 = Debug|Any CPU {506A8ECB-E5B4-4F10-8419-26A0EC7AB225}.Release|Any CPU.ActiveCfg = Release|Any CPU {506A8ECB-E5B4-4F10-8419-26A0EC7AB225}.Release|Any CPU.Build.0 = Release|Any CPU + {C5273844-69B0-429C-92B8-0BBDC5C7562F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C5273844-69B0-429C-92B8-0BBDC5C7562F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5273844-69B0-429C-92B8-0BBDC5C7562F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C5273844-69B0-429C-92B8-0BBDC5C7562F}.Release|Any CPU.Build.0 = Release|Any CPU + {B31AAA00-76C3-45EA-9B6F-5996EAFCE73B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B31AAA00-76C3-45EA-9B6F-5996EAFCE73B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B31AAA00-76C3-45EA-9B6F-5996EAFCE73B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B31AAA00-76C3-45EA-9B6F-5996EAFCE73B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -34,6 +46,8 @@ Global GlobalSection(NestedProjects) = preSolution {442C5A88-29C2-4B00-B1DF-730D646D3861} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {506A8ECB-E5B4-4F10-8419-26A0EC7AB225} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} + {C5273844-69B0-429C-92B8-0BBDC5C7562F} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {B31AAA00-76C3-45EA-9B6F-5996EAFCE73B} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7D65CA50-781D-47DB-B000-870C0E0ED32E} diff --git a/src/libraries/System.Xml.XPath.XDocument/System.Xml.XPath.XDocument.sln b/src/libraries/System.Xml.XPath.XDocument/System.Xml.XPath.XDocument.sln index cf5cb4bbdb39c9..f5f7c70e845ad0 100644 --- a/src/libraries/System.Xml.XPath.XDocument/System.Xml.XPath.XDocument.sln +++ b/src/libraries/System.Xml.XPath.XDocument/System.Xml.XPath.XDocument.sln @@ -13,6 +13,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.Xml", "..\System.Private.Xml\src\System.Private.Xml.csproj", "{E0E66923-602E-4629-8886-3C8118644D09}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.Xml.Linq", "..\System.Private.Xml.Linq\src\System.Private.Xml.Linq.csproj", "{0E7066DB-D05A-48C5-ADDD-027FEB658D9C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +31,14 @@ Global {F44BEAB4-EDDB-497B-B15C-11E8DFB94092}.Debug|Any CPU.Build.0 = Debug|Any CPU {F44BEAB4-EDDB-497B-B15C-11E8DFB94092}.Release|Any CPU.ActiveCfg = Release|Any CPU {F44BEAB4-EDDB-497B-B15C-11E8DFB94092}.Release|Any CPU.Build.0 = Release|Any CPU + {E0E66923-602E-4629-8886-3C8118644D09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0E66923-602E-4629-8886-3C8118644D09}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0E66923-602E-4629-8886-3C8118644D09}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0E66923-602E-4629-8886-3C8118644D09}.Release|Any CPU.Build.0 = Release|Any CPU + {0E7066DB-D05A-48C5-ADDD-027FEB658D9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E7066DB-D05A-48C5-ADDD-027FEB658D9C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E7066DB-D05A-48C5-ADDD-027FEB658D9C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E7066DB-D05A-48C5-ADDD-027FEB658D9C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -34,6 +46,8 @@ Global GlobalSection(NestedProjects) = preSolution {DAA1EA56-C318-4D2E-AB8D-1AB87D9F98F5} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {F44BEAB4-EDDB-497B-B15C-11E8DFB94092} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} + {E0E66923-602E-4629-8886-3C8118644D09} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} + {0E7066DB-D05A-48C5-ADDD-027FEB658D9C} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {895DF830-8667-4661-9AA4-E7F9E6C34D73} diff --git a/src/libraries/System.Xml.XPath.XDocument/src/System.Xml.XPath.XDocument.csproj b/src/libraries/System.Xml.XPath.XDocument/src/System.Xml.XPath.XDocument.csproj index 632d0aa9d5839b..330eda4f580be6 100644 --- a/src/libraries/System.Xml.XPath.XDocument/src/System.Xml.XPath.XDocument.csproj +++ b/src/libraries/System.Xml.XPath.XDocument/src/System.Xml.XPath.XDocument.csproj @@ -1,6 +1,5 @@ - System.Xml.XPath.XDocument true true $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix @@ -8,7 +7,7 @@ - + diff --git a/src/libraries/System.Xml.XPath/System.Xml.XPath.sln b/src/libraries/System.Xml.XPath/System.Xml.XPath.sln index 2e31b91e99a45b..7d64e68551107b 100644 --- a/src/libraries/System.Xml.XPath/System.Xml.XPath.sln +++ b/src/libraries/System.Xml.XPath/System.Xml.XPath.sln @@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.Xml", "..\System.Private.Xml\src\System.Private.Xml.csproj", "{A7BF3BB6-1D0A-431F-A4E6-135E6257EDCE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +29,10 @@ Global {A3B3FF23-D123-4F5A-8618-5128B18987C5}.Debug|Any CPU.Build.0 = Debug|Any CPU {A3B3FF23-D123-4F5A-8618-5128B18987C5}.Release|Any CPU.ActiveCfg = Release|Any CPU {A3B3FF23-D123-4F5A-8618-5128B18987C5}.Release|Any CPU.Build.0 = Release|Any CPU + {A7BF3BB6-1D0A-431F-A4E6-135E6257EDCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A7BF3BB6-1D0A-431F-A4E6-135E6257EDCE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A7BF3BB6-1D0A-431F-A4E6-135E6257EDCE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A7BF3BB6-1D0A-431F-A4E6-135E6257EDCE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -34,6 +40,7 @@ Global GlobalSection(NestedProjects) = preSolution {783F801D-50DE-45B1-B8BE-C36A1F5049F1} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {A3B3FF23-D123-4F5A-8618-5128B18987C5} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} + {A7BF3BB6-1D0A-431F-A4E6-135E6257EDCE} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D9A010CC-3ADD-49CA-8F5B-93D3B4C48E97} diff --git a/src/libraries/System.Xml.XmlDocument/System.Xml.XmlDocument.sln b/src/libraries/System.Xml.XmlDocument/System.Xml.XmlDocument.sln index 75da4f3f3d28e9..186be500ee2f85 100644 --- a/src/libraries/System.Xml.XmlDocument/System.Xml.XmlDocument.sln +++ b/src/libraries/System.Xml.XmlDocument/System.Xml.XmlDocument.sln @@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.Xml", "..\System.Private.Xml\src\System.Private.Xml.csproj", "{7ECF0E1E-ABCA-4E1A-9353-C311279DA82F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +29,10 @@ Global {DFF03D7C-82DF-4E4C-A722-2EFFD844DA7E}.Debug|Any CPU.Build.0 = Debug|Any CPU {DFF03D7C-82DF-4E4C-A722-2EFFD844DA7E}.Release|Any CPU.ActiveCfg = Release|Any CPU {DFF03D7C-82DF-4E4C-A722-2EFFD844DA7E}.Release|Any CPU.Build.0 = Release|Any CPU + {7ECF0E1E-ABCA-4E1A-9353-C311279DA82F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7ECF0E1E-ABCA-4E1A-9353-C311279DA82F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7ECF0E1E-ABCA-4E1A-9353-C311279DA82F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7ECF0E1E-ABCA-4E1A-9353-C311279DA82F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -34,6 +40,7 @@ Global GlobalSection(NestedProjects) = preSolution {EC0F9F33-3D4E-470A-90E6-AE9D005F023A} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {DFF03D7C-82DF-4E4C-A722-2EFFD844DA7E} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} + {7ECF0E1E-ABCA-4E1A-9353-C311279DA82F} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6A00ACB9-4345-4301-9AEE-A34D09CB1E42} diff --git a/src/libraries/System.Xml.XmlSerializer/System.Xml.XmlSerializer.sln b/src/libraries/System.Xml.XmlSerializer/System.Xml.XmlSerializer.sln index 8e566aef767d0a..66c1ae3cef2316 100644 --- a/src/libraries/System.Xml.XmlSerializer/System.Xml.XmlSerializer.sln +++ b/src/libraries/System.Xml.XmlSerializer/System.Xml.XmlSerializer.sln @@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E89 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.Xml", "..\System.Private.Xml\src\System.Private.Xml.csproj", "{D8D6D6CD-3014-4D0D-8DD7-DFCFB49FE58E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +29,10 @@ Global {3F7C5D50-7CDA-44EF-BB05-912D496BAA46}.Debug|Any CPU.Build.0 = Debug|Any CPU {3F7C5D50-7CDA-44EF-BB05-912D496BAA46}.Release|Any CPU.ActiveCfg = Release|Any CPU {3F7C5D50-7CDA-44EF-BB05-912D496BAA46}.Release|Any CPU.Build.0 = Release|Any CPU + {D8D6D6CD-3014-4D0D-8DD7-DFCFB49FE58E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D8D6D6CD-3014-4D0D-8DD7-DFCFB49FE58E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D8D6D6CD-3014-4D0D-8DD7-DFCFB49FE58E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D8D6D6CD-3014-4D0D-8DD7-DFCFB49FE58E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -34,6 +40,7 @@ Global GlobalSection(NestedProjects) = preSolution {D62A6082-5229-4845-8BE9-75753E08C65A} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} {3F7C5D50-7CDA-44EF-BB05-912D496BAA46} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} + {D8D6D6CD-3014-4D0D-8DD7-DFCFB49FE58E} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5E74729B-F552-4E3F-9B11-3E121D6A83A0} diff --git a/src/libraries/intellisense.targets b/src/libraries/intellisense.targets deleted file mode 100644 index 3e932f99ec621b..00000000000000 --- a/src/libraries/intellisense.targets +++ /dev/null @@ -1,88 +0,0 @@ - - - - <_UnsupportedTargetFrameworkError> - - - - - - - - <_OriginalTargetFramework>$(TargetFramework) - $(TargetFramework.SubString($([MSBuild]::Add($(TargetFramework.IndexOf('-')), 1)))) - $(TargetFramework.SubString(0, $(TargetFramework.IndexOf('-')))) - - - - $([MSBuild]::NormalizeDirectory('$(RefRootPath)', '$(TargetFramework)')) - - - - - <_ShortFrameworkIdentifier>$(TargetFramework.TrimEnd('.0123456789')) - <_ShortFrameworkVersion>$(TargetFramework.Substring($(_ShortFrameworkIdentifier.Length))) - - - - - v$(_ShortFrameworkVersion) - - - - - v$(_ShortFrameworkVersion[0]).0 - v$(_ShortFrameworkVersion[0]).$(_ShortFrameworkVersion[1]) - v$(_ShortFrameworkVersion[0]).$(_ShortFrameworkVersion[1]).$(_ShortFrameworkVersion[2]) - - - - - .NETStandard - .NETCoreApp - - - .NETFramework - .NETCoreApp - - - - - <_UnsupportedTargetFrameworkError>true - - - - - - $(IntermediateOutputPath)$(MSBuildProjectName).AssemblyInfo$(DefaultLanguageSourceExtension) - - - - $(TargetFrameworkIdentifier),Version=$(TargetFrameworkVersion),Profile=$(TargetFrameworkProfile) - $(TargetFrameworkIdentifier),Version=$(TargetFrameworkVersion) - - - - - $(IntermediateOutputPath)$(MSBuildProjectName).assets.cache - $([MSBuild]::NormalizePath($(MSBuildProjectDirectory), $(ProjectAssetsCacheFile))) - $(TargetFrameworkMoniker) - - $(OutputPath)$(TargetFileName) - - - diff --git a/src/libraries/mscorlib.WinRT-Facade/ref/mscorlib.WinRT-Facade.csproj b/src/libraries/mscorlib.WinRT-Facade/ref/mscorlib.WinRT-Facade.csproj index ce1228b2cfb040..4d92c6378f4079 100644 --- a/src/libraries/mscorlib.WinRT-Facade/ref/mscorlib.WinRT-Facade.csproj +++ b/src/libraries/mscorlib.WinRT-Facade/ref/mscorlib.WinRT-Facade.csproj @@ -11,10 +11,10 @@ - + - + \ No newline at end of file diff --git a/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/Microsoft.NETCore.Platforms.Future.pkgproj b/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/Microsoft.NETCore.Platforms.Future.pkgproj deleted file mode 100644 index be13ea21ac2329..00000000000000 --- a/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/Microsoft.NETCore.Platforms.Future.pkgproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - true - - false - - - - - - lib/netstandard1.0 - - - - - - diff --git a/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/Microsoft.NETCore.Platforms.Future.proj b/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/Microsoft.NETCore.Platforms.Future.proj deleted file mode 100644 index 24c9f63af136b3..00000000000000 --- a/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/Microsoft.NETCore.Platforms.Future.proj +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/readme.md b/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/readme.md deleted file mode 100644 index 1e8e216fd6409d..00000000000000 --- a/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/readme.md +++ /dev/null @@ -1 +0,0 @@ -see ..\Microsoft.NETCore.Platforms\readme.md \ No newline at end of file diff --git a/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/runtime.compatibility.json b/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/runtime.compatibility.json deleted file mode 100644 index 278b1bcc7e614e..00000000000000 --- a/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/runtime.compatibility.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "unix-wasm": [ - "unix-wasm" - ], - "webassembly": [ - "webassembly", - "unix" - ], - "webassembly-wasm": [ - "webassembly-wasm", - "webassembly", - "unix-wasm", - "unix" - ] -} \ No newline at end of file diff --git a/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/runtime.json b/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/runtime.json deleted file mode 100644 index 07393a3db820f2..00000000000000 --- a/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/runtime.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "runtimes": { - "unix-wasm": { - "#import": [] - }, - "webassembly": { - "#import": [ - "unix" - ] - }, - "webassembly-wasm": { - "#import": [ - "webassembly", - "unix-wasm" - ] - } - } -} \ No newline at end of file diff --git a/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/runtimeGroups.props b/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/runtimeGroups.props deleted file mode 100644 index ff4c96a23b8298..00000000000000 --- a/src/libraries/pkg/Microsoft.NETCore.Platforms.Future/runtimeGroups.props +++ /dev/null @@ -1,26 +0,0 @@ - - - - wasm - - unix - - - unix - wasm - - - - - - - - - diff --git a/src/libraries/pkg/Microsoft.NETCore.Platforms/runtime.compatibility.json b/src/libraries/pkg/Microsoft.NETCore.Platforms/runtime.compatibility.json index d40d1e1ac5a1ad..ca8d8b4493f6a9 100644 --- a/src/libraries/pkg/Microsoft.NETCore.Platforms/runtime.compatibility.json +++ b/src/libraries/pkg/Microsoft.NETCore.Platforms/runtime.compatibility.json @@ -92,6 +92,47 @@ "any", "base" ], + "alpine.3.12": [ + "alpine.3.12", + "alpine.3.11", + "alpine.3.10", + "alpine.3.9", + "alpine.3.8", + "alpine.3.7", + "alpine.3.6", + "alpine", + "linux-musl", + "linux", + "unix", + "any", + "base" + ], + "alpine.3.12-x64": [ + "alpine.3.12-x64", + "alpine.3.12", + "alpine.3.11-x64", + "alpine.3.11", + "alpine.3.10-x64", + "alpine.3.10", + "alpine.3.9-x64", + "alpine.3.9", + "alpine.3.8-x64", + "alpine.3.8", + "alpine.3.7-x64", + "alpine.3.7", + "alpine.3.6-x64", + "alpine.3.6", + "alpine-x64", + "alpine", + "linux-musl-x64", + "linux-musl", + "linux-x64", + "linux", + "unix-x64", + "unix", + "any", + "base" + ], "alpine.3.6": [ "alpine.3.6", "alpine", @@ -1106,6 +1147,17 @@ "base": [ "base" ], + "browser": [ + "browser", + "any", + "base" + ], + "browser-wasm": [ + "browser-wasm", + "browser", + "any", + "base" + ], "centos": [ "centos", "rhel", @@ -1114,6 +1166,18 @@ "any", "base" ], + "centos-arm64": [ + "centos-arm64", + "centos", + "rhel-arm64", + "rhel", + "linux-arm64", + "linux", + "unix-arm64", + "unix", + "any", + "base" + ], "centos-x64": [ "centos-x64", "centos", @@ -1162,6 +1226,22 @@ "any", "base" ], + "centos.8-arm64": [ + "centos.8-arm64", + "centos.8", + "centos-arm64", + "rhel.8-arm64", + "centos", + "rhel.8", + "rhel-arm64", + "rhel", + "linux-arm64", + "linux", + "unix-arm64", + "unix", + "any", + "base" + ], "centos.8-x64": [ "centos.8-x64", "centos.8", @@ -1178,6 +1258,48 @@ "any", "base" ], + "centos.9": [ + "centos.9", + "centos", + "rhel.9", + "rhel", + "linux", + "unix", + "any", + "base" + ], + "centos.9-arm64": [ + "centos.9-arm64", + "centos.9", + "centos-arm64", + "rhel.9-arm64", + "centos", + "rhel.9", + "rhel-arm64", + "rhel", + "linux-arm64", + "linux", + "unix-arm64", + "unix", + "any", + "base" + ], + "centos.9-x64": [ + "centos.9-x64", + "centos.9", + "centos-x64", + "rhel.9-x64", + "centos", + "rhel.9", + "rhel-x64", + "rhel", + "linux-x64", + "linux", + "unix-x64", + "unix", + "any", + "base" + ], "debian": [ "debian", "linux", @@ -1818,6 +1940,38 @@ "any", "base" ], + "fedora.34": [ + "fedora.34", + "fedora", + "linux", + "unix", + "any", + "base" + ], + "fedora.34-arm64": [ + "fedora.34-arm64", + "fedora.34", + "fedora-arm64", + "fedora", + "linux-arm64", + "linux", + "unix-arm64", + "unix", + "any", + "base" + ], + "fedora.34-x64": [ + "fedora.34-x64", + "fedora.34", + "fedora-x64", + "fedora", + "linux-x64", + "linux", + "unix-x64", + "unix", + "any", + "base" + ], "freebsd": [ "freebsd", "unix", @@ -1939,6 +2093,14 @@ "any", "base" ], + "ios-x86": [ + "ios-x86", + "ios", + "unix-x86", + "unix", + "any", + "base" + ], "ios.10": [ "ios.10", "ios.9", @@ -1990,6 +2152,20 @@ "any", "base" ], + "ios.10-x86": [ + "ios.10-x86", + "ios.10", + "ios.9-x86", + "ios.9", + "ios.8-x86", + "ios.8", + "ios-x86", + "ios", + "unix-x86", + "unix", + "any", + "base" + ], "ios.11": [ "ios.11", "ios.10", @@ -2168,6 +2344,16 @@ "any", "base" ], + "ios.8-x86": [ + "ios.8-x86", + "ios.8", + "ios-x86", + "ios", + "unix-x86", + "unix", + "any", + "base" + ], "ios.9": [ "ios.9", "ios.8", @@ -2212,6 +2398,18 @@ "any", "base" ], + "ios.9-x86": [ + "ios.9-x86", + "ios.9", + "ios.8-x86", + "ios.8", + "ios-x86", + "ios", + "unix-x86", + "unix", + "any", + "base" + ], "linux": [ "linux", "unix", @@ -3800,6 +3998,38 @@ "any", "base" ], + "rhel.9": [ + "rhel.9", + "rhel", + "linux", + "unix", + "any", + "base" + ], + "rhel.9-arm64": [ + "rhel.9-arm64", + "rhel.9", + "rhel-arm64", + "rhel", + "linux-arm64", + "linux", + "unix-arm64", + "unix", + "any", + "base" + ], + "rhel.9-x64": [ + "rhel.9-x64", + "rhel.9", + "rhel-x64", + "rhel", + "linux-x64", + "linux", + "unix-x64", + "unix", + "any", + "base" + ], "sles": [ "sles", "linux", @@ -5145,6 +5375,266 @@ "any", "base" ], + "ubuntu.20.04": [ + "ubuntu.20.04", + "ubuntu", + "debian", + "linux", + "unix", + "any", + "base" + ], + "ubuntu.20.04-arm": [ + "ubuntu.20.04-arm", + "ubuntu.20.04", + "ubuntu-arm", + "ubuntu", + "debian-arm", + "debian", + "linux-arm", + "linux", + "unix-arm", + "unix", + "any", + "base" + ], + "ubuntu.20.04-arm64": [ + "ubuntu.20.04-arm64", + "ubuntu.20.04", + "ubuntu-arm64", + "ubuntu", + "debian-arm64", + "debian", + "linux-arm64", + "linux", + "unix-arm64", + "unix", + "any", + "base" + ], + "ubuntu.20.04-x64": [ + "ubuntu.20.04-x64", + "ubuntu.20.04", + "ubuntu-x64", + "ubuntu", + "debian-x64", + "debian", + "linux-x64", + "linux", + "unix-x64", + "unix", + "any", + "base" + ], + "ubuntu.20.04-x86": [ + "ubuntu.20.04-x86", + "ubuntu.20.04", + "ubuntu-x86", + "ubuntu", + "debian-x86", + "debian", + "linux-x86", + "linux", + "unix-x86", + "unix", + "any", + "base" + ], + "ubuntu.20.10": [ + "ubuntu.20.10", + "ubuntu", + "debian", + "linux", + "unix", + "any", + "base" + ], + "ubuntu.20.10-arm": [ + "ubuntu.20.10-arm", + "ubuntu.20.10", + "ubuntu-arm", + "ubuntu", + "debian-arm", + "debian", + "linux-arm", + "linux", + "unix-arm", + "unix", + "any", + "base" + ], + "ubuntu.20.10-arm64": [ + "ubuntu.20.10-arm64", + "ubuntu.20.10", + "ubuntu-arm64", + "ubuntu", + "debian-arm64", + "debian", + "linux-arm64", + "linux", + "unix-arm64", + "unix", + "any", + "base" + ], + "ubuntu.20.10-x64": [ + "ubuntu.20.10-x64", + "ubuntu.20.10", + "ubuntu-x64", + "ubuntu", + "debian-x64", + "debian", + "linux-x64", + "linux", + "unix-x64", + "unix", + "any", + "base" + ], + "ubuntu.20.10-x86": [ + "ubuntu.20.10-x86", + "ubuntu.20.10", + "ubuntu-x86", + "ubuntu", + "debian-x86", + "debian", + "linux-x86", + "linux", + "unix-x86", + "unix", + "any", + "base" + ], + "ubuntu.21.04": [ + "ubuntu.21.04", + "ubuntu", + "debian", + "linux", + "unix", + "any", + "base" + ], + "ubuntu.21.04-arm": [ + "ubuntu.21.04-arm", + "ubuntu.21.04", + "ubuntu-arm", + "ubuntu", + "debian-arm", + "debian", + "linux-arm", + "linux", + "unix-arm", + "unix", + "any", + "base" + ], + "ubuntu.21.04-arm64": [ + "ubuntu.21.04-arm64", + "ubuntu.21.04", + "ubuntu-arm64", + "ubuntu", + "debian-arm64", + "debian", + "linux-arm64", + "linux", + "unix-arm64", + "unix", + "any", + "base" + ], + "ubuntu.21.04-x64": [ + "ubuntu.21.04-x64", + "ubuntu.21.04", + "ubuntu-x64", + "ubuntu", + "debian-x64", + "debian", + "linux-x64", + "linux", + "unix-x64", + "unix", + "any", + "base" + ], + "ubuntu.21.04-x86": [ + "ubuntu.21.04-x86", + "ubuntu.21.04", + "ubuntu-x86", + "ubuntu", + "debian-x86", + "debian", + "linux-x86", + "linux", + "unix-x86", + "unix", + "any", + "base" + ], + "ubuntu.21.10": [ + "ubuntu.21.10", + "ubuntu", + "debian", + "linux", + "unix", + "any", + "base" + ], + "ubuntu.21.10-arm": [ + "ubuntu.21.10-arm", + "ubuntu.21.10", + "ubuntu-arm", + "ubuntu", + "debian-arm", + "debian", + "linux-arm", + "linux", + "unix-arm", + "unix", + "any", + "base" + ], + "ubuntu.21.10-arm64": [ + "ubuntu.21.10-arm64", + "ubuntu.21.10", + "ubuntu-arm64", + "ubuntu", + "debian-arm64", + "debian", + "linux-arm64", + "linux", + "unix-arm64", + "unix", + "any", + "base" + ], + "ubuntu.21.10-x64": [ + "ubuntu.21.10-x64", + "ubuntu.21.10", + "ubuntu-x64", + "ubuntu", + "debian-x64", + "debian", + "linux-x64", + "linux", + "unix-x64", + "unix", + "any", + "base" + ], + "ubuntu.21.10-x86": [ + "ubuntu.21.10-x86", + "ubuntu.21.10", + "ubuntu-x86", + "ubuntu", + "debian-x86", + "debian", + "linux-x86", + "linux", + "unix-x86", + "unix", + "any", + "base" + ], "unix": [ "unix", "any", diff --git a/src/libraries/pkg/Microsoft.NETCore.Platforms/runtime.json b/src/libraries/pkg/Microsoft.NETCore.Platforms/runtime.json index 0b368beb36e6f1..aa9f28ca15d338 100644 --- a/src/libraries/pkg/Microsoft.NETCore.Platforms/runtime.json +++ b/src/libraries/pkg/Microsoft.NETCore.Platforms/runtime.json @@ -33,6 +33,17 @@ "alpine.3.10-x64" ] }, + "alpine.3.12": { + "#import": [ + "alpine.3.11" + ] + }, + "alpine.3.12-x64": { + "#import": [ + "alpine.3.12", + "alpine.3.11-x64" + ] + }, "alpine.3.6": { "#import": [ "alpine" @@ -391,11 +402,27 @@ "base": { "#import": [] }, + "browser": { + "#import": [ + "any" + ] + }, + "browser-wasm": { + "#import": [ + "browser" + ] + }, "centos": { "#import": [ "rhel" ] }, + "centos-arm64": { + "#import": [ + "centos", + "rhel-arm64" + ] + }, "centos-x64": { "#import": [ "centos", @@ -421,6 +448,13 @@ "rhel.8" ] }, + "centos.8-arm64": { + "#import": [ + "centos.8", + "centos-arm64", + "rhel.8-arm64" + ] + }, "centos.8-x64": { "#import": [ "centos.8", @@ -428,6 +462,26 @@ "rhel.8-x64" ] }, + "centos.9": { + "#import": [ + "centos", + "rhel.9" + ] + }, + "centos.9-arm64": { + "#import": [ + "centos.9", + "centos-arm64", + "rhel.9-arm64" + ] + }, + "centos.9-x64": { + "#import": [ + "centos.9", + "centos-x64", + "rhel.9-x64" + ] + }, "debian": { "#import": [ "linux" @@ -772,6 +826,23 @@ "fedora-x64" ] }, + "fedora.34": { + "#import": [ + "fedora" + ] + }, + "fedora.34-arm64": { + "#import": [ + "fedora.34", + "fedora-arm64" + ] + }, + "fedora.34-x64": { + "#import": [ + "fedora.34", + "fedora-x64" + ] + }, "freebsd": { "#import": [ "unix" @@ -850,6 +921,12 @@ "unix-x64" ] }, + "ios-x86": { + "#import": [ + "ios", + "unix-x86" + ] + }, "ios.10": { "#import": [ "ios.9" @@ -873,6 +950,12 @@ "ios.9-x64" ] }, + "ios.10-x86": { + "#import": [ + "ios.10", + "ios.9-x86" + ] + }, "ios.11": { "#import": [ "ios.10" @@ -947,6 +1030,12 @@ "ios-x64" ] }, + "ios.8-x86": { + "#import": [ + "ios.8", + "ios-x86" + ] + }, "ios.9": { "#import": [ "ios.8" @@ -970,6 +1059,12 @@ "ios.8-x64" ] }, + "ios.9-x86": { + "#import": [ + "ios.9", + "ios.8-x86" + ] + }, "linux": { "#import": [ "unix" @@ -1623,6 +1718,23 @@ "rhel.8.0-x64" ] }, + "rhel.9": { + "#import": [ + "rhel" + ] + }, + "rhel.9-arm64": { + "#import": [ + "rhel.9", + "rhel-arm64" + ] + }, + "rhel.9-x64": { + "#import": [ + "rhel.9", + "rhel-x64" + ] + }, "sles": { "#import": [ "linux" @@ -2234,6 +2346,122 @@ "ubuntu-x86" ] }, + "ubuntu.20.04": { + "#import": [ + "ubuntu" + ] + }, + "ubuntu.20.04-arm": { + "#import": [ + "ubuntu.20.04", + "ubuntu-arm" + ] + }, + "ubuntu.20.04-arm64": { + "#import": [ + "ubuntu.20.04", + "ubuntu-arm64" + ] + }, + "ubuntu.20.04-x64": { + "#import": [ + "ubuntu.20.04", + "ubuntu-x64" + ] + }, + "ubuntu.20.04-x86": { + "#import": [ + "ubuntu.20.04", + "ubuntu-x86" + ] + }, + "ubuntu.20.10": { + "#import": [ + "ubuntu" + ] + }, + "ubuntu.20.10-arm": { + "#import": [ + "ubuntu.20.10", + "ubuntu-arm" + ] + }, + "ubuntu.20.10-arm64": { + "#import": [ + "ubuntu.20.10", + "ubuntu-arm64" + ] + }, + "ubuntu.20.10-x64": { + "#import": [ + "ubuntu.20.10", + "ubuntu-x64" + ] + }, + "ubuntu.20.10-x86": { + "#import": [ + "ubuntu.20.10", + "ubuntu-x86" + ] + }, + "ubuntu.21.04": { + "#import": [ + "ubuntu" + ] + }, + "ubuntu.21.04-arm": { + "#import": [ + "ubuntu.21.04", + "ubuntu-arm" + ] + }, + "ubuntu.21.04-arm64": { + "#import": [ + "ubuntu.21.04", + "ubuntu-arm64" + ] + }, + "ubuntu.21.04-x64": { + "#import": [ + "ubuntu.21.04", + "ubuntu-x64" + ] + }, + "ubuntu.21.04-x86": { + "#import": [ + "ubuntu.21.04", + "ubuntu-x86" + ] + }, + "ubuntu.21.10": { + "#import": [ + "ubuntu" + ] + }, + "ubuntu.21.10-arm": { + "#import": [ + "ubuntu.21.10", + "ubuntu-arm" + ] + }, + "ubuntu.21.10-arm64": { + "#import": [ + "ubuntu.21.10", + "ubuntu-arm64" + ] + }, + "ubuntu.21.10-x64": { + "#import": [ + "ubuntu.21.10", + "ubuntu-x64" + ] + }, + "ubuntu.21.10-x86": { + "#import": [ + "ubuntu.21.10", + "ubuntu-x86" + ] + }, "unix": { "#import": [ "any" diff --git a/src/libraries/pkg/Microsoft.NETCore.Platforms/runtimeGroups.props b/src/libraries/pkg/Microsoft.NETCore.Platforms/runtimeGroups.props index 4d7d03bf1d3ed2..1cb561273e87a7 100644 --- a/src/libraries/pkg/Microsoft.NETCore.Platforms/runtimeGroups.props +++ b/src/libraries/pkg/Microsoft.NETCore.Platforms/runtimeGroups.props @@ -16,7 +16,7 @@ linux-musl x64 - 3.6;3.7;3.8;3.9;3.10;3.11 + 3.6;3.7;3.8;3.9;3.10;3.11;3.12 @@ -30,10 +30,22 @@ x64 + + any + wasm + + rhel x64 - 7;8 + 7 + true + false + + + rhel + x64;arm64 + 8;9 true false @@ -48,7 +60,7 @@ linux x64;arm64 - 23;24;25;26;27;28;29;30;31;32;33 + 23;24;25;26;27;28;29;30;31;32;33;34 false @@ -59,7 +71,7 @@ unix - arm + arm;x86 8;9;10 @@ -135,6 +147,11 @@ x64;arm64 8;8.0;8.1 + + linux + x64;arm64 + 9 + linux @@ -163,7 +180,7 @@ debian x64;x86;arm;arm64 - 16.04;16.10;17.04;17.10;18.04;18.10;19.04;19.10 + 16.04;16.10;17.04;17.10;18.04;18.10;19.04;19.10;20.04;20.10;21.04;21.10 false diff --git a/src/libraries/pkg/baseline/packageIndex.json b/src/libraries/pkg/baseline/packageIndex.json index 66a985414d5112..d3fffa85b3feb7 100644 --- a/src/libraries/pkg/baseline/packageIndex.json +++ b/src/libraries/pkg/baseline/packageIndex.json @@ -87,7 +87,7 @@ "InboxOn": { "netcoreapp2.0": "4.0.3.0", "netcoreapp2.1": "4.0.4.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", @@ -543,12 +543,14 @@ "3.1.0", "3.1.1", "3.1.2", - "3.1.3" + "3.1.3", + "3.1.4" ], "BaselineVersion": "5.0.0", "InboxOn": {}, "AssemblyVersionInPackageVersion": { - "3.1.3.0": "5.0.0", + "3.1.3.0": "3.1.3", + "3.1.4.0": "3.1.4", "5.0.0.0": "5.0.0" } }, @@ -1119,7 +1121,7 @@ "InboxOn": { "netcoreapp2.0": "10.0.3.0", "netcoreapp2.1": "10.0.4.0", - "netcoreapp5.0": "10.0.6.0", + "net5.0": "10.0.6.0", "net45": "10.0.0.0", "portable45-net45+win8+wpa81": "10.0.0.0", "portable46-net451+win81+wpa81": "10.0.0.0", @@ -1152,7 +1154,7 @@ "BaselineVersion": "11.0.0", "InboxOn": { "netcoreapp3.0": "10.0.4.0", - "netcoreapp5.0": "10.0.6.0" + "net5.0": "10.0.6.0" } }, "Microsoft.VisualC": { @@ -1175,7 +1177,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -1536,7 +1538,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.1.0.0", "netstandard2.0": "4.1.0.0", "monoandroid10": "Any", @@ -1565,7 +1567,7 @@ "netcoreapp2.0": "4.0.2.0", "netcoreapp2.1": "4.0.3.0", "netcoreapp3.0": "4.0.4.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "uap10.0.16299": "4.0.3.0" }, "AssemblyVersionInPackageVersion": { @@ -1601,7 +1603,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -1644,7 +1646,7 @@ "BaselineVersion": "4.3.0", "InboxOn": { "netcoreapp2.0": "4.0.14.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -1687,7 +1689,7 @@ "netcoreapp2.0": "1.2.2.0", "netcoreapp2.1": "1.2.3.0", "netcoreapp3.0": "1.2.4.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "uap10.0.16299": "1.2.3.0" }, "AssemblyVersionInPackageVersion": { @@ -1711,7 +1713,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -1738,7 +1740,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -1764,7 +1766,7 @@ "BaselineVersion": "4.3.0", "InboxOn": { "netcoreapp2.0": "4.0.3.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", @@ -1811,7 +1813,7 @@ "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", "netcoreapp3.0": "4.3.0.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable46-net451+win81": "4.0.0.0", @@ -1896,7 +1898,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -1939,7 +1941,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.1.0.0", "netstandard2.0": "4.1.0.0", "monoandroid10": "Any", @@ -1966,7 +1968,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.1.0.0", "netstandard2.0": "4.1.0.0", "monoandroid10": "Any", @@ -2117,7 +2119,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -2185,7 +2187,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.1.0.0", "netstandard2.0": "4.1.0.0", "monoandroid10": "Any", @@ -2209,7 +2211,7 @@ "BaselineVersion": "4.5.0", "InboxOn": { "netcoreapp3.0": "4.0.0.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0" }, "AssemblyVersionInPackageVersion": { @@ -2352,7 +2354,7 @@ "BaselineVersion": "4.3.0", "InboxOn": { "netcoreapp2.0": "4.0.3.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", @@ -2394,7 +2396,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -2443,7 +2445,7 @@ "netcoreapp2.0": "4.0.2.1", "netcoreapp2.1": "4.0.3.1", "netcoreapp3.0": "4.0.4.0", - "netcoreapp5.0": "5.0.0.0" + "net5.0": "5.0.0.0" }, "AssemblyVersionInPackageVersion": { "4.0.0.0": "4.0.0", @@ -2478,7 +2480,7 @@ "InboxOn": { "netcoreapp2.0": "4.0.2.0", "netcoreapp2.1": "4.0.3.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -2523,7 +2525,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.1.0.0", "netstandard2.0": "4.1.0.0", "monoandroid10": "Any", @@ -2551,7 +2553,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.2.0", "netstandard2.0": "4.0.2.0", "monoandroid10": "Any", @@ -2578,7 +2580,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -2604,7 +2606,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", @@ -2654,7 +2656,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -2682,7 +2684,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net451": "4.0.10.0", "net46": "4.0.20.0", @@ -2799,7 +2801,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.2.0.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -2832,7 +2834,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -2882,7 +2884,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -2925,7 +2927,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -2952,7 +2954,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -2995,7 +2997,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "net461": "4.1.0.0", @@ -3040,7 +3042,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net461": "4.1.1.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -3069,7 +3071,7 @@ "System.IO.Compression.Brotli": { "InboxOn": { "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0" + "net5.0": "5.0.0.0" }, "AssemblyVersionInPackageVersion": { "4.2.0.0": "4.4.0", @@ -3079,7 +3081,7 @@ "System.IO.Compression.FileSystem": { "InboxOn": { "netcoreapp2.0": "4.0.0.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -3101,7 +3103,7 @@ "InboxOn": { "netcoreapp2.0": "4.0.3.0", "netcoreapp2.1": "4.0.4.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -3128,7 +3130,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -3175,7 +3177,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -3201,7 +3203,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -3227,7 +3229,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -3253,7 +3255,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -3284,7 +3286,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -3346,7 +3348,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "uap10.0.16299": "4.1.1.0" @@ -3398,7 +3400,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -3446,7 +3448,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net461": "4.1.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -3490,7 +3492,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "net461": "4.1.0.0", @@ -3533,7 +3535,7 @@ "BaselineVersion": "4.3.0", "InboxOn": { "netcoreapp2.0": "4.0.3.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", @@ -3566,7 +3568,7 @@ "BaselineVersion": "5.0.0", "InboxOn": { "netcoreapp2.0": "4.0.3.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", @@ -3626,7 +3628,7 @@ "InboxOn": { "netcoreapp2.1": "4.1.0.0", "netcoreapp3.0": "4.2.0.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "monoandroid10": "Any", "monotouch10": "Any", "xamarinios10": "Any", @@ -3714,7 +3716,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net461": "4.1.1.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -3817,7 +3819,7 @@ "InboxOn": { "netcoreapp2.0": "4.0.0.0", "netcoreapp2.1": "4.0.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "monoandroid10": "Any", "monotouch10": "Any", "uap10.0.16299": "4.0.1.0", @@ -3831,7 +3833,7 @@ "InboxOn": { "netcoreapp2.0": "4.0.0.0", "netcoreapp2.1": "4.0.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "monoandroid10": "Any", "monotouch10": "Any", "uap10.0.16299": "4.0.1.0", @@ -3850,7 +3852,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -3876,7 +3878,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "net461": "4.1.0.0", @@ -3918,7 +3920,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -3948,7 +3950,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -3999,7 +4001,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -4046,7 +4048,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -4066,7 +4068,7 @@ "InboxOn": { "netcoreapp2.0": "4.0.0.0", "netcoreapp2.1": "4.0.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "monoandroid10": "Any", "monotouch10": "Any", "uap10.0.16299": "4.0.1.0", @@ -4086,7 +4088,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.1.0.0", "netstandard2.0": "4.1.0.0", "monoandroid10": "Any", @@ -4118,7 +4120,7 @@ "InboxOn": { "netcoreapp2.0": "4.0.0.0", "netcoreapp2.1": "4.0.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "uap10.0.16299": "4.0.1.0" } }, @@ -4132,7 +4134,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net46": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -4153,7 +4155,7 @@ "InboxOn": { "netcoreapp2.0": "4.0.0.0", "netcoreapp2.1": "4.0.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "uap10.0.16299": "4.0.1.0" } }, @@ -4166,7 +4168,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -4195,7 +4197,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -4276,7 +4278,7 @@ "netcoreapp2.0": "4.1.3.0", "netcoreapp2.1": "4.1.4.0", "netcoreapp3.0": "4.1.5.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net46": "4.0.0.0", "net461": "4.1.2.0", "monoandroid10": "Any", @@ -4324,7 +4326,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -4411,7 +4413,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "net461": "4.1.0.0", @@ -4482,7 +4484,7 @@ "netcoreapp2.0": "4.0.3.0", "netcoreapp2.1": "4.0.4.0", "netcoreapp3.0": "4.0.5.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "monoandroid10": "Any", "monotouch10": "Any", "uap10.0.16299": "4.0.4.0", @@ -4513,7 +4515,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "netstandard2.1": "4.0.0.0", "monoandroid10": "Any", @@ -4542,7 +4544,7 @@ "InboxOn": { "netcoreapp2.0": "4.0.3.0", "netcoreapp3.0": "4.1.0.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+wp8": "4.0.0.0", "netstandard2.1": "4.0.0.0", @@ -4572,7 +4574,7 @@ "InboxOn": { "netcoreapp2.0": "4.0.3.0", "netcoreapp3.0": "4.1.0.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+wp8": "4.0.0.0", "netstandard2.1": "4.0.0.0", @@ -4600,7 +4602,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", @@ -4650,7 +4652,7 @@ "netcoreapp2.0": "1.4.2.0", "netcoreapp2.1": "1.4.3.0", "netcoreapp3.0": "1.4.4.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "uap10.0.16299": "1.4.3.0" }, "AssemblyVersionInPackageVersion": { @@ -4686,7 +4688,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", @@ -4732,7 +4734,7 @@ "netcoreapp2.0": "4.1.2.0", "netcoreapp2.1": "4.1.3.0", "netcoreapp3.0": "4.1.4.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "monoandroid10": "Any", "monotouch10": "Any", "uap10.0.16299": "4.1.3.0", @@ -4771,7 +4773,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "uap10.0.16299": "4.1.1.0" @@ -4801,7 +4803,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", @@ -4841,7 +4843,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "uap10.0.16299": "4.1.1.0" @@ -4866,7 +4868,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net451": "4.0.10.0", "net46": "4.0.20.0", @@ -4936,7 +4938,7 @@ "BaselineVersion": "5.0.0", "InboxOn": { "netcoreapp3.0": "4.0.5.0", - "netcoreapp5.0": "5.0.0.0" + "net5.0": "5.0.0.0" }, "AssemblyVersionInPackageVersion": { "4.0.3.0": "4.4.0", @@ -4955,7 +4957,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -4990,7 +4992,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "net461": "4.1.0.0", @@ -5034,7 +5036,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net46": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -5063,7 +5065,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net451": "4.0.10.0", "net46": "4.0.20.0", @@ -5102,7 +5104,7 @@ "InboxOn": { "netcoreapp2.0": "4.0.2.0", "netcoreapp2.1": "4.0.3.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "monoandroid10": "Any", "monotouch10": "Any", "uap10.0.16299": "4.0.3.0", @@ -5126,7 +5128,7 @@ "BaselineVersion": "5.0.0", "InboxOn": { "netcoreapp2.0": "4.0.3.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", @@ -5159,7 +5161,7 @@ "System.Runtime.Intrinsics": { "InboxOn": { "netcoreapp3.0": "4.0.0.0", - "netcoreapp5.0": "5.0.0.0" + "net5.0": "5.0.0.0" } }, "System.Runtime.Intrinsics.Experimental": { @@ -5180,7 +5182,7 @@ "netcoreapp2.0": "4.0.2.0", "netcoreapp2.1": "4.0.3.0", "netcoreapp3.0": "4.1.0.0", - "netcoreapp5.0": "5.0.0.0" + "net5.0": "5.0.0.0" }, "AssemblyVersionInPackageVersion": { "4.0.0.0": "4.0.0", @@ -5198,7 +5200,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", @@ -5263,7 +5265,7 @@ "InboxOn": { "netcoreapp2.0": "4.0.2.0", "netcoreapp2.1": "4.0.3.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -5294,7 +5296,7 @@ "BaselineVersion": "4.3.0", "InboxOn": { "netcoreapp2.0": "4.0.4.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", @@ -5338,7 +5340,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "net461": "4.1.1.0", @@ -5387,7 +5389,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.3.0", "netcoreapp2.1": "4.1.4.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "net461": "4.1.1.0", @@ -5515,7 +5517,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -5543,7 +5545,7 @@ "InboxOn": { "netcoreapp2.0": "4.3.0.0", "netcoreapp2.1": "4.3.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.2.0.0", "netstandard2.0": "4.2.0.0", "monoandroid10": "Any", @@ -5601,7 +5603,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -5626,7 +5628,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -5698,7 +5700,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -5753,7 +5755,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.1.0.0", "netstandard2.0": "4.1.0.0", "monoandroid10": "Any", @@ -5813,7 +5815,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", @@ -5877,7 +5879,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -6111,7 +6113,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -6157,7 +6159,7 @@ "BaselineVersion": "5.0.0", "InboxOn": { "netcoreapp3.0": "4.1.2.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "monoandroid10": "Any", "monotouch10": "Any", "uap10.0.16299": "4.1.1.0", @@ -6187,7 +6189,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -6233,7 +6235,7 @@ "BaselineVersion": "5.0.0", "InboxOn": { "netcoreapp3.0": "4.0.4.0", - "netcoreapp5.0": "5.0.0.0" + "net5.0": "5.0.0.0" }, "AssemblyVersionInPackageVersion": { "4.0.0.0": "4.0.0", @@ -6251,7 +6253,7 @@ "BaselineVersion": "5.0.0", "InboxOn": { "netcoreapp3.0": "4.0.0.0", - "netcoreapp5.0": "5.0.0.0" + "net5.0": "5.0.0.0" }, "AssemblyVersionInPackageVersion": { "4.0.0.0": "4.6.0", @@ -6271,7 +6273,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "net461": "4.1.0.0", @@ -6316,7 +6318,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -6376,7 +6378,7 @@ "BaselineVersion": "5.0.0", "InboxOn": { "netcoreapp3.0": "4.0.1.0", - "netcoreapp5.0": "5.0.0.0" + "net5.0": "5.0.0.0" }, "AssemblyVersionInPackageVersion": { "4.0.0.0": "4.5.0", @@ -6394,7 +6396,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "uap10.0.16299": "4.1.1.0" @@ -6424,7 +6426,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -6472,7 +6474,7 @@ "netcoreapp2.0": "4.6.2.0", "netcoreapp2.1": "4.6.3.0", "netcoreapp3.0": "4.6.4.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "uap10.0.16299": "4.6.3.0" }, "AssemblyVersionInPackageVersion": { @@ -6499,7 +6501,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.1.0", "netcoreapp2.1": "4.3.0.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "monoandroid10": "Any", "monotouch10": "Any", "xamarinios10": "Any", @@ -6524,7 +6526,7 @@ "BaselineVersion": "4.3.0", "InboxOn": { "netcoreapp2.0": "4.0.3.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "portable45-net45+win8+wpa81": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", @@ -6557,7 +6559,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.0.0", "netstandard2.0": "4.0.0.0", "monoandroid10": "Any", @@ -6582,7 +6584,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.10.0", "netstandard2.0": "4.0.10.0", "monoandroid10": "Any", @@ -6608,7 +6610,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net451": "4.0.0.0", "portable46-net451+win81+wpa81": "4.0.0.0", "portable46-win81+wpa81": "4.0.0.0", @@ -6648,7 +6650,7 @@ "InboxOn": { "netcoreapp2.0": "4.0.0.0", "netcoreapp2.1": "4.0.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "uap10.0.16299": "4.0.1.0" } }, @@ -6672,7 +6674,7 @@ "netcoreapp2.0": "4.0.2.0", "netcoreapp2.1": "4.0.3.0", "netcoreapp3.0": "4.0.4.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "netstandard2.0": "4.0.2.0", "monoandroid10": "Any", "monotouch10": "Any", @@ -6751,7 +6753,7 @@ "InboxOn": { "netcoreapp2.0": "4.0.0.0", "netcoreapp2.1": "4.0.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "uap10.0.16299": "4.0.1.0" } }, @@ -6943,7 +6945,7 @@ "InboxOn": { "netcoreapp2.0": "4.2.0.0", "netcoreapp2.1": "4.2.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "net461": "4.1.0.0", @@ -7015,7 +7017,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -7058,7 +7060,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -7086,7 +7088,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net45": "4.0.0.0", "net46": "4.0.10.0", "portable45-net45+win8+wpa81": "4.0.0.0", @@ -7129,7 +7131,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -7156,7 +7158,7 @@ "InboxOn": { "netcoreapp2.0": "4.1.0.0", "netcoreapp2.1": "4.1.1.0", - "netcoreapp5.0": "5.0.0.0", + "net5.0": "5.0.0.0", "net461": "4.0.1.0", "netstandard2.0": "4.0.1.0", "monoandroid10": "Any", @@ -7244,7 +7246,7 @@ }, "ModulesToPackages": { "sni.dll": "runtime.native.System.Data.SqlClient.sni", - "System.IO.Ports.Native": "runtime.native.System.IO.Ports" + "libSystem.IO.Ports.Native": "runtime.native.System.IO.Ports" }, "MetaPackages": { "NETStandard.Library": [ diff --git a/src/libraries/pkg/descriptions.json b/src/libraries/pkg/descriptions.json index 87b23a37dad8c7..6d2b58594de826 100644 --- a/src/libraries/pkg/descriptions.json +++ b/src/libraries/pkg/descriptions.json @@ -260,11 +260,6 @@ "Description": "Provides runtime information required to resolve target framework, platform, and runtime specific implementations of .NETCore packages.", "CommonTypes": [] }, - { - "Name": "Microsoft.NETCore.Platforms.Future", - "Description": "Provides runtime information required to resolve target framework, platform, and runtime specific implementations of .NETCore packages. This package represents future platforms not yet supported in .NETCore stable release and is subject to change.", - "CommonTypes": [] - }, { "Name": "Microsoft.NETCore.Portable.Compatibility", "Description": "Enables compatibility with portable libraries targeting previous .NET releases like .NET Framework 4.0 and Silverlight.\nThis package supports retargeting references to classic reference assemblies (mscorlib.dll, system.dll, etc) to new contract assemblies (System.Runtime.dll, System.IO, etc). It does this in a pay-for-play way to prevent consuming assemblies from having to reference all of the contracts that happen to overlap with mscorlib. As such, when using this package you may encounter errors like\n\terror CS0012: The type 'WebRequest' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Net.Requests, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.\nTo resolve these errors install the package with the same name as the missing assembly.", diff --git a/src/libraries/pkg/test/frameworkSettings/net5.0/settings.targets b/src/libraries/pkg/test/frameworkSettings/net5.0/settings.targets new file mode 100644 index 00000000000000..a8fa34134f4350 --- /dev/null +++ b/src/libraries/pkg/test/frameworkSettings/net5.0/settings.targets @@ -0,0 +1,11 @@ + + + $(MicrosoftNETCoreAppVersion) + + + + + + + + \ No newline at end of file diff --git a/src/libraries/pkg/test/frameworkSettings/netcoreapp5.0/settings.targets b/src/libraries/pkg/test/frameworkSettings/netcoreapp5.0/settings.targets deleted file mode 100644 index 6652c6d907de2e..00000000000000 --- a/src/libraries/pkg/test/frameworkSettings/netcoreapp5.0/settings.targets +++ /dev/null @@ -1,16 +0,0 @@ - - - $(MicrosoftNETCoreAppVersion) - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/libraries/pkg/test/testPackages.proj b/src/libraries/pkg/test/testPackages.proj index 556872dc0b6f71..ea3cb98e3a7d9a 100644 --- a/src/libraries/pkg/test/testPackages.proj +++ b/src/libraries/pkg/test/testPackages.proj @@ -177,7 +177,7 @@ Condition="'$(ArchiveTests)' != 'true'"> - $(TestDotNetPath) + "$(TestDotNetPath)" $(TestRestoreCommand) restore $(TestRestoreCommand) --packages "$(TestPackageDir)" $(TestRestoreCommand) /p:LocalPackagesPath=$(PackageOutputPath) @@ -195,7 +195,7 @@ Condition="'$(ArchiveTests)' != 'true'"> - $(TestDotNetPath) + "$(TestDotNetPath)" $(TestBuildCommand) msbuild $(TestBuildCommand) /t:Test $(TestBuildCommand) /nr:false diff --git a/src/libraries/pretest.proj b/src/libraries/pretest.proj index 74931a96ee8313..7b8e5f9f9f38b1 100644 --- a/src/libraries/pretest.proj +++ b/src/libraries/pretest.proj @@ -1,13 +1,24 @@ + BuildAllProjects=true + + + true + true + + + + + + + + @@ -58,4 +74,38 @@ RuntimeGraphFiles="$(RuntimeIdGraphDefinitionFile)" TargetRuntimeIdentifier="$(PackageRID)" /> + + + + + RuntimeList.xml + $(RuntimePackDir)/data/$(FrameworkListFilename) + + + + <_runtimePackLibFiles Include="$(RuntimePackLibDir)*.*"> + $(RuntimePackTargetFrameworkPath)/lib/$(NetCoreAppCurrent) + true + + <_runtimePackNativeFiles Include="$(RuntimePackNativeDir)*.*"> + $(RuntimePackTargetFrameworkPath)/native + true + + + + + + + + + + + + diff --git a/src/libraries/restore/Directory.Build.props b/src/libraries/restore/Directory.Build.props index 059f4b48d8ca2a..359dfd63da6af8 100644 --- a/src/libraries/restore/Directory.Build.props +++ b/src/libraries/restore/Directory.Build.props @@ -2,10 +2,13 @@ - + + $([MSBuild]::NormalizeDirectory('$(BaseIntermediateOutputPath)', '$(TargetFramework)-$(TargetFrameworkSuffix)-$(Configuration)')) + $([MSBuild]::NormalizeDirectory('$(BaseIntermediateOutputPath)', '$(TargetFramework)-$(Configuration)')) $(IntermediateOutputPath) $(RestoreOutputPath)/project.assets.json $(IntermediateOutputPath) + true false netstandard2.0 @@ -18,4 +21,4 @@ Build - \ No newline at end of file + diff --git a/src/libraries/restore/binplacePackages/binplacePackages.depproj b/src/libraries/restore/binplacePackages/binplacePackages.depproj index d97b5b59e59dec..5b7928b270cec4 100644 --- a/src/libraries/restore/binplacePackages/binplacePackages.depproj +++ b/src/libraries/restore/binplacePackages/binplacePackages.depproj @@ -2,10 +2,10 @@ true true - $(TargetFramework.SubString(11)) + $(TargetFramework.SubString(11)) Reference - true - net461;net472;netstandard1.1;netstandard1.2;netstandard1.3;netstandard1.4;netstandard1.5;netstandard1.6;netstandard2.0;netstandard2.0;netcoreapp2.0;netcoreapp3.0;$(netcoreappCurrent) + true + net461;net472;netstandard1.1;netstandard1.2;netstandard1.3;netstandard1.4;netstandard1.5;netstandard1.6;netstandard2.0;netstandard2.0;netcoreapp2.0;netcoreapp3.0;$(NetCoreAppCurrent) @@ -16,7 +16,7 @@ - + BinPlaceLib $(RuntimePath) @@ -30,22 +30,22 @@ - - - + + + - - + + - + + Condition="!$(TargetFramework.StartsWith('netstandard'))"> diff --git a/src/libraries/restore/netfx/netfx.depproj b/src/libraries/restore/netfx/netfx.depproj index ec59cfba4464a7..7fcdb7329068fa 100644 --- a/src/libraries/restore/netfx/netfx.depproj +++ b/src/libraries/restore/netfx/netfx.depproj @@ -23,13 +23,6 @@ <_ShortFrameworkIdentifier>$(TargetFramework.TrimEnd('.0123456789')) <_ShortFrameworkVersion>$(TargetFramework.Substring($(_ShortFrameworkIdentifier.Length))) - - - - .NETStandard - .NETCoreApp - .NETFramework - @@ -43,18 +36,32 @@ v$(_ShortFrameworkVersion[0]).$(_ShortFrameworkVersion[1]).$(_ShortFrameworkVersion[2]) - + + + .NETStandard + .NETCoreApp + + + .NETFramework + .NETCoreApp + + + Microsoft.TargetingPack.NETFramework.$(TargetFrameworkVersion) - + $(NetFxRefPath) - + $(RefPath) diff --git a/src/libraries/restore/netstandard/external.netstandard.depproj b/src/libraries/restore/netstandard/external.netstandard.depproj index 6ecf6cb0ee7866..1d80925bf1734e 100644 --- a/src/libraries/restore/netstandard/external.netstandard.depproj +++ b/src/libraries/restore/netstandard/external.netstandard.depproj @@ -1,6 +1,6 @@  - $(TargetFramework.SubString(11)) + $(TargetFramework.SubString(11)) true true true diff --git a/src/libraries/restore/runtime/runtime.depproj b/src/libraries/restore/runtime/runtime.depproj index 0546f2f6c8ec38..10fc51ca950277 100644 --- a/src/libraries/restore/runtime/runtime.depproj +++ b/src/libraries/restore/runtime/runtime.depproj @@ -1,14 +1,8 @@  $(PackageRID) - - $(ToolRuntimeRID) $(NoWarn);NU1603;NU1605 true - $(TargetOS) - $(Configuration) - $(TargetOS) - $(Configuration) false netcoreapp3.0-Windows_NT;netcoreapp3.0-Unix;$(netcoreappCurrent)-Windows_NT;$(netcoreappCurrent)-Unix @@ -17,16 +11,14 @@ - + - - @@ -42,20 +34,26 @@ - $([System.IO.File]::ReadAllText('$(RepoRoot)global.json')) - $([System.Text.RegularExpressions.Regex]::Match($(GlobalJsonContent), '(%3F<="dotnet": ").*(%3F=")')) - hostfxr libhostfxr + hostpolicy + libhostpolicy true false - + + + + + + + @@ -70,9 +68,32 @@ SkipUnchangedFiles="true" UseHardlinksIfPossible="$(UseHardlink)" /> + + + + + + + cross/ + + + include/%(RecursiveDir) + + + + + + + - + + diff --git a/src/libraries/sendtohelix.proj b/src/libraries/sendtohelix.proj index b62ca7e716148b..aba5711af78844 100644 --- a/src/libraries/sendtohelix.proj +++ b/src/libraries/sendtohelix.proj @@ -76,6 +76,10 @@ <_RuntimeInputs Include="$(TestHostRootPath)**/*.dll" /> + + + + - + $(BuildTargetFramework) - - - - $(TargetFramework) - netcoreapp - $(IntermediateOutputPath)/apicompat.rsp - $(MSBuildThisFileDirectory)ApiCompatBaseline.$(ApiCompatTarget).netfx461.txt - $(MSBuildThisFileDirectory)ApiCompatBaseline.$(ApiCompatTarget).netfx461.ignore.txt - $(MSBuildThisFileDirectory)ApiCompatBaseline.$(ApiCompatTarget).netstandard.txt - $(MSBuildThisFileDirectory)ApiCompatBaseline.$(ApiCompatTarget).netstandardOnly.txt - $(BuildTargetFrameworkRefPath.TrimEnd('\/')) false <_RunApiCompat>true @@ -26,13 +14,28 @@ + + + + $(IntermediateOutputPath)apicompat.rsp + $(TargetFrameworkIdentifier.Substring(1).ToLower()) + $(MSBuildThisFileDirectory)ApiCompatBaseline.$(ApiCompatTarget).netfx461.txt + $(MSBuildThisFileDirectory)ApiCompatBaseline.$(ApiCompatTarget).netfx461.ignore.txt + $(MSBuildThisFileDirectory)ApiCompatBaseline.$(ApiCompatTarget).netstandard.txt + $(MSBuildThisFileDirectory)ApiCompatBaseline.$(ApiCompatTarget).netstandardOnly.txt + + + + $(BuildTargetFrameworkRefPath.TrimEnd('\/')) $(ApiCompatArgs) --exclude-attributes "$(ApiCompatExcludeAttributeList)" $(ApiCompatArgs) --impl-dirs "$(ApiCompatImplementationDirs)" --baseline "$(ApiCompatBaselineIgnoreFile)" @@ -46,8 +49,7 @@ Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)' and '$(BaselineApiCompat)' == 'true'" CustomErrorRegularExpression="^[a-zA-Z]+ :" StandardOutputImportance="Low" - IgnoreExitCode="true" - > + IgnoreExitCode="true"> @@ -81,8 +83,7 @@ + IgnoreExitCode="true"> @@ -92,8 +93,7 @@ + IgnoreExitCode="true"> @@ -107,13 +107,12 @@ <_previousNetCoreAppBaselineParam Condition="'$(UpdatePreviousNetCoreAppBaseline)' == 'true'">> "$(_previousNetCoreAppBaselineFile)" - + + IgnoreExitCode="true"> @@ -124,8 +123,4 @@ - - - - diff --git a/src/libraries/shims/manual/Directory.Build.props b/src/libraries/shims/manual/Directory.Build.props index 3b6d8565f47996..e227dbfe58c938 100644 --- a/src/libraries/shims/manual/Directory.Build.props +++ b/src/libraries/shims/manual/Directory.Build.props @@ -13,8 +13,6 @@ true $([MSBuild]::NormalizeDirectory('$(ArtifactsObjDir)', '$(OutDirName)')) $(BaseIntermediateOutputPath)$(TargetFramework)-$(Configuration) - $(TargetOS) - $(TargetOS) $(NetCoreAppCurrent) diff --git a/src/libraries/src.proj b/src/libraries/src.proj index b3b5f8504fc6e5..91225466df0112 100644 --- a/src/libraries/src.proj +++ b/src/libraries/src.proj @@ -2,6 +2,7 @@ BuildAllProjects=true + BuildWasmRuntimes @@ -24,8 +25,11 @@ + + + AfterTargets="Build" + DependsOnTargets="$(NativeBinPlaceDependsOnTargets)"> @@ -45,5 +49,4 @@ Projects="@(ApiCompatProject)" Properties="$(TraversalGlobalProperties)" /> - diff --git a/src/libraries/targetframework.props b/src/libraries/targetframework.props deleted file mode 100644 index 6f55f1411fd081..00000000000000 --- a/src/libraries/targetframework.props +++ /dev/null @@ -1,92 +0,0 @@ - - - - - true - win - - - - - true - unix - - - - - true - true - linux - - - - - true - true - true - android - - - - - true - true - osx - - - - - true - true - tvos - - - - - true - true - ios - - - - - true - true - freebsd - - - - - true - true - netbsd - - - - - true - true - - - - - true - - - - - - true - true - true - - - - $(BaseIntermediateOutputPath)$(TargetFramework)-$(TargetFrameworkSuffix)-$(Configuration)\ - $(BaseIntermediateOutputPath)$(TargetFramework)-$(Configuration)\ - - $(BaseOutputPath)$(TargetFramework)-$(TargetFrameworkSuffix)-$(Configuration)\ - $(BaseOutputPath)$(TargetFramework)-$(Configuration)\ - - - diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index f2e7cb3a071528..6e92a434cf559d 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -1,15 +1,21 @@ - - - true + false ErrorAndContinue BuildAllProjects=true - $(ArtifactsBinDir)*.Tests/**/coverage.xml + $(ArtifactsBinDir)\*.Tests\**\coverage.opencover.xml $(ArtifactsDir)coverage + true + + + + + + + @@ -20,14 +26,9 @@ Condition="'$(BuildAllConfigurations)' == 'true'" /> - - - - - + DependsOnTargets="GenerateCoverageReport" /> diff --git a/src/mono/Directory.Build.props b/src/mono/Directory.Build.props index fed776d063ff34..baa3cfc4c5dd12 100644 --- a/src/mono/Directory.Build.props +++ b/src/mono/Directory.Build.props @@ -39,12 +39,12 @@ true true true - true + true true true - true + true true - true + true @@ -99,6 +99,15 @@ $(ArtifactsObjDir)mono/$(PlatformConfigPathPart)/ - $(MonoObjDir)llvm + $(MonoObjDir)llvm + + + + + $([MSBuild]::NormalizeDirectory('$(RepoTasksDir)', 'mobile.tasks', 'AppleAppBuilder')) + $([MSBuild]::NormalizeDirectory('$(LibrariesProjectRoot)', 'Common', tests, 'AppleTestRunner')) + $([MSBuild]::NormalizeDirectory('$(RepoTasksDir)', 'mobile.tasks', 'AndroidAppBuilder')) + $([MSBuild]::NormalizeDirectory('$(LibrariesProjectRoot)', 'Common', tests, 'AndroidTestRunner')) + $([MSBuild]::NormalizeDirectory('$(RepoTasksDir)', 'mobile.tasks', 'AotCompilerTask')) diff --git a/src/mono/cmake/config.h.in b/src/mono/cmake/config.h.in index b5754a613a8776..e89b59c5f71009 100644 --- a/src/mono/cmake/config.h.in +++ b/src/mono/cmake/config.h.in @@ -1647,6 +1647,9 @@ /* Enable private types checked build */ #cmakedefine ENABLE_CHECKED_BUILD_CRASH_REPORTING 1 +/* Enable EventPipe library support */ +#cmakedefine ENABLE_PERFTRACING 1 + /* Define to 1 if you have /usr/include/malloc.h. */ #cmakedefine HAVE_USR_INCLUDE_MALLOC_H 1 diff --git a/src/mono/configure.ac b/src/mono/configure.ac index 22c584cf76fd4c..6eb961f9dda000 100644 --- a/src/mono/configure.ac +++ b/src/mono/configure.ac @@ -943,6 +943,16 @@ if test x$with_core = xonly; then fi AM_CONDITIONAL(ENABLE_NETCORE, test x$with_core = xonly) +if test x$with_core = xonly; then + if test -f $srcdir/mono/eventpipe/ep.h; then + enable_perftracing=yes + fi + if test x$enable_perftracing = xyes; then + AC_DEFINE(ENABLE_PERFTRACING,1,[Enables support for eventpipe library]) + fi +fi +AM_CONDITIONAL(ENABLE_PERFTRACING, test x$enable_perftracing = xyes) + # # A sanity check to catch cases where the package was unpacked # with an ancient tar program (Solaris) @@ -3921,6 +3931,8 @@ else AC_CHECK_LIB(advapi32, main, LIBS="$LIBS -ladvapi32", AC_ERROR(bad mingw install?)) AC_CHECK_LIB(version, main, LIBS="$LIBS -lversion", AC_ERROR(bad mingw install?)) + AC_CHECK_TYPES([struct sockaddr_in6], [AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6)], , [#include ]) + dnl ********************************* dnl *** Check for struct ip_mreqn *** dnl ********************************* @@ -6765,6 +6777,18 @@ if test x"$GCC" = xyes; then CFLAGS="$CFLAGS -Werror-implicit-function-declaration" # jay has a lot of implicit declarations JAY_CFLAGS="-Wno-implicit-function-declaration" + + ORIG_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -Wsometimes-uninitialized -Werror" + AC_MSG_CHECKING(for -Wsometimes-uninitialized option to gcc) + AC_TRY_COMPILE([],[ + ], [ + AC_MSG_RESULT(yes) + CFLAGS="$ORIG_CFLAGS -Werror=sometimes-uninitialized" + ], [ + AC_MSG_RESULT(no) + CFLAGS=$ORIG_CFLAGS + ]) fi # zlib/configure checks if this program compiles and if so @@ -6783,6 +6807,46 @@ AC_COMPILE_IFELSE( AC_MSG_RESULT(no) ]) +# for icu shim +ICU_SHIM_PATH=. +if test x$with_core = xonly; then + if test x$cross_compiling = xno; then + AC_CHECK_FILE($srcdir/../libraries/Native/Unix/System.Globalization.Native/pal_icushim.h, [have_shim_globalization=yes], [have_shim_globalization=no]) + fi + if test x$have_shim_globalization = xyes || test x$cross_compiling = xyes; then + ICU_SHIM_PATH=../../../libraries/Native/Unix/System.Globalization.Native + if test x$target_osx = xyes; then + ORIG_CPPFLAGS=$CPPFLAGS + # adding icu path to pkg_config_path + PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/local/opt/icu4c/lib/pkgconfig + export PKG_CONFIG_PATH + CPPFLAGS="`pkg-config --cflags-only-I icu-uc`" + AC_CHECK_LIB(icucore, ucol_open, LIBS=$LIBS, + [AC_MSG_ERROR([Cannot find libicucore, skipping build for System.Globalization.Native. .NET globalization is not expected to function.])]) + AC_CHECK_HEADER(unicode/utypes.h, [have_sys_icu=yes], [have_sys_icu=no]) + if test x$have_sys_icu = xyes; then + ICU_CFLAGS="$CPPFLAGS -DOSX_ICU_LIBRARY_PATH=AS_ESCAPE(\"/usr/lib/libicucore.dylib\", '\"') -DTARGET_UNIX -DU_DISABLE_RENAMING -Wno-reserved-id-macro -Wno-documentation -Wno-documentation-unknown-command -Wno-switch-enum -Wno-covered-switch-default -Wno-covered-switch-default -Wno-extra-semi-stmt -Wno-unknown-warning-option -Wno-deprecated-declarations" + fi + CPPFLAGS=$ORIG_CPPFLAGS + elif test x$platform_android = xyes; then + ICU_CFLAGS="-DHAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS -DHAVE_SET_MAX_VARIABLE -DTARGET_UNIX -DTARGET_ANDROID -Wno-reserved-id-macro -Wno-documentation -Wno-documentation-unknown-command -Wno-switch-enum -Wno-covered-switch-default -Wno-covered-switch-default -Wno-extra-semi-stmt -Wno-unknown-warning-option" + have_sys_icu=yes + elif test x$host_linux = xyes; then + AC_CHECK_LIB(icuuc, main, LIBS=$LIBS, + [AC_MSG_ERROR([Cannot find libicuuc, try installing libicu-dev (or the appropriate package for your platform).])]) + AC_CHECK_LIB(icui18n, main, LIBS=$LIBS, + [AC_MSG_ERROR([Cannot find libicui18n, try installing libicu-dev (or the appropriate package for your platform).])]) + AC_CHECK_HEADER(unicode/utypes.h, [have_sys_icu=yes], [have_sys_icu=no]) + if test x$have_sys_icu = xyes; then + ICU_CFLAGS="-DTARGET_UNIX -Wno-reserved-id-macro -Wno-documentation -Wno-documentation-unknown-command -Wno-switch-enum -Wno-covered-switch-default -Wno-covered-switch-default -Wno-extra-semi-stmt -Wno-unknown-warning-option" + fi + fi + AC_SUBST(ICU_CFLAGS) + fi +fi +AC_SUBST(ICU_SHIM_PATH) +AM_CONDITIONAL(HAVE_SYS_ICU, test x$have_sys_icu = xyes) + AC_SUBST(CFLAGS) AC_SUBST(CPPFLAGS) AC_SUBST(LDFLAGS) diff --git a/src/mono/llvm/llvm-init.proj b/src/mono/llvm/llvm-init.proj index a43b35b917bc99..52227cc8454144 100644 --- a/src/mono/llvm/llvm-init.proj +++ b/src/mono/llvm/llvm-init.proj @@ -1,26 +1,30 @@ - netcoreapp5.0 + $(NetCoreAppCurrent) + + + + linux + osx.10.12 + win + $(runtimelinuxx64MicrosoftNETCoreRuntimeMonoLLVMSdkVersion) + $(runtimewinx64MicrosoftNETCoreRuntimeMonoLLVMSdkVersion) + $(runtimeosx1012x64MicrosoftNETCoreRuntimeMonoLLVMSdkVersion) + $(runtimelinuxx64MicrosoftNETCoreRuntimeMonoLLVMToolsVersion) + $(runtimewinx64MicrosoftNETCoreRuntimeMonoLLVMToolsVersion) + $(runtimeosx1012x64MicrosoftNETCoreRuntimeMonoLLVMToolsVersion) - - - - - - + + - - - - - - + + diff --git a/src/mono/m4/mono-output.m4 b/src/mono/m4/mono-output.m4 index 40d72ea7d6d144..128c16f33633ef 100644 --- a/src/mono/m4/mono-output.m4 +++ b/src/mono/m4/mono-output.m4 @@ -12,6 +12,8 @@ AC_DEFUN([AC_MONO_OUTPUT], [ mono/utils/Makefile mono/metadata/Makefile mono/zlib/Makefile + mono/eventpipe/Makefile + mono/eventpipe/test/Makefile mono/arch/Makefile mono/arch/x86/Makefile mono/arch/amd64/Makefile diff --git a/src/mono/mono.proj b/src/mono/mono.proj index 8f2ee648712f03..446b216b77c93d 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -14,34 +14,33 @@ coreclr.dll libcoreclr.dylib libcoreclr.so - libmono.dylib - libmono.dylib + libmonosgen-2.0.dylib libmonosgen-2.0.so - libmono.a - libmono.a - libmonosgen-2.0.a - libmono.a - libmono.a + libmonosgen-2.0.a $(CoreClrFileName) + libmonosgen-2.0.a $(Configuration) $(Configuration) $(ArtifactsDir)tests\coreclr\$(TargetOS).$(Platform).$(CoreClrTestConfig)\Tests\Core_Root $(ArtifactsDir)bin\testhost\$(NetCoreAppCurrent)-$(TargetOS)-$(LibrariesTestConfig)-$(Platform)\ $(LibrariesTesthostRoot)shared\Microsoft.NETCore.App\$(ProductVersion)\ /Applications/Xcode.app/Contents/Developer - true - true + true + true + true + $(MonoObjDir)cross\config.h + true - + - + - + @@ -49,7 +48,7 @@ <_MonoConfigureParams Include="--enable-maintainer-mode" /> <_MonoConfigureParams Include="--enable-compile-warnings" /> <_MonoConfigureParams Include="--prefix=$(MonoObjDir)out" /> - <_MonoConfigureParams Condition="'$(MonoEnableLLVM)' == 'true'" Include="--with-llvm=$(MonoLLVMDir)" /> + <_MonoConfigureParams Condition="'$(MonoEnableLLVM)' == 'true'" Include="--with-llvm=$(MonoLLVMDir)" /> <_MonoConfigureParams Condition="'$(MonoEnableCXX)' == 'true'" Include="--enable-cxx" /> @@ -68,10 +67,13 @@ - <_MonoCFLAGS Include="-O2" /> + <_MonoCFLAGS Include="-O2" Condition="'$(TargetsMobile)' != 'true'" /> + <_MonoCFLAGS Include="-Os" Condition="'$(TargetsMobile)' == 'true'" /> <_MonoCFLAGS Include="-g" /> + <_MonoCFLAGS Include="-Wl,-s" Condition="'$(TargetsAndroid)' == 'true'" /> - <_MonoCXXFLAGS Include="-O2" /> + <_MonoCXXFLAGS Include="-O2" Condition="'$(TargetsMobile)' != 'true'" /> + <_MonoCXXFLAGS Include="-Os" Condition="'$(TargetsMobile)' == 'true'" /> <_MonoCXXFLAGS Include="-g" /> @@ -132,6 +134,7 @@ <_MonoCFLAGS Condition="'$(Platform)' == 'arm64'" Include="-arch arm64" /> <_MonoCFLAGS Include="-isysroot $(XcodeDir)/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS$(tvOSVersion).sdk" /> <_MonoCFLAGS Include="-mtvos-version-min=$(tvOSVersionMin)" /> + <_MonoCFLAGS Include="-Werror=partial-availability" /> <_MonoCFLAGS Include="-Wl,-application_extension" /> <_MonoCFLAGS Include="-fexceptions" /> <_MonoCFLAGS Include="-fembed-bitcode" /> @@ -156,69 +159,11 @@ <_MonoCPPFLAGS Include="-DHAVE_LARGE_FILE_SUPPORT=1" /> <_MonoLDFLAGS Condition="'$(Platform)' == 'arm64'" Include="-arch arm64" /> - <_MonoLDFLAGS Include="-Wl,-no_weak_imports" /> + <_MonoLDFLAGS Include="-Wl,-bitcode_bundle" /> <_MonoLDFLAGS Include="-framework CoreFoundation" /> <_MonoLDFLAGS Include="-lobjc" /> <_MonoLDFLAGS Include="-lc++" /> - - - - <_MonoAotCrossConfigureParams Include="--host=x86_64-apple-darwin10" /> - <_MonoAotCrossConfigureParams Condition="'$(Platform)' == 'arm64'" Include="--target=aarch64-darwin" /> - <_MonoAotCrossConfigureParams Include="--with-cross-offsets=$(MonoObjDir)cross/offsets-$(Platform)-darwin.h" /> - <_MonoAotCrossConfigureParams Include="--with-core=only" /> - <_MonoAotCrossConfigureParams Include="--enable-maintainer-mode" /> - <_MonoAotCrossConfigureParams Include="--enable-compile-warnings" /> - <_MonoAotCrossConfigureParams Include="--prefix=$(MonoObjDir)cross/out" /> - <_MonoAotCrossConfigureParams Include="--disable-boehm" /> - <_MonoAotCrossConfigureParams Include="--disable-btls" /> - <_MonoAotCrossConfigureParams Include="--disable-iconv" /> - <_MonoAotCrossConfigureParams Include="--disable-libraries" /> - <_MonoAotCrossConfigureParams Include="--disable-mcs-build" /> - <_MonoAotCrossConfigureParams Include="--disable-nls" /> - <_MonoAotCrossConfigureParams Include="--enable-dtrace=no" /> - <_MonoAotCrossConfigureParams Include="--enable-icall-symbol-map" /> - <_MonoAotCrossConfigureParams Include="--enable-minimal=com,remoting" /> - <_MonoAotCrossConfigureParams Include="--enable-monotouch" /> - <_MonoAotCrossConfigureParams Include="--disable-crash-reporting" /> - - - <_MonoAotCrossAC_VARS Include="ac_cv_func_shm_open_working_with_mmap=no" /> - - <_MonoAotCrossCFLAGS Include="-O2" /> - <_MonoAotCrossCFLAGS Include="-g" /> - <_MonoAotCrossCFLAGS Include="-isysroot $(XcodeDir)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX$(macOSVersion).sdk" /> - <_MonoAotCrossCFLAGS Include="-mmacosx-version-min=$(macOSVersionMin)" /> - <_MonoAotCrossCFLAGS Include="-Qunused-arguments" /> - <_MonoAotCrossCFLAGS Include="-m64" /> - - <_MonoAotCrossCXXFLAGS Include="-O2" /> - <_MonoAotCrossCXXFLAGS Include="-g" /> - <_MonoAotCrossCXXFLAGS Include="-isysroot $(XcodeDir)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX$(macOSVersion).sdk" /> - <_MonoAotCrossCXXFLAGS Include="-mmacosx-version-min=$(macOSVersionMin)" /> - <_MonoAotCrossCXXFLAGS Include="-Qunused-arguments" /> - <_MonoAotCrossCXXFLAGS Include="-stdlib=libc++" /> - <_MonoAotCrossCXXFLAGS Include="-m64" /> - - <_MonoAotCrossCPPFLAGS Include="-O2" /> - <_MonoAotCrossCPPFLAGS Include="-g" /> - <_MonoAotCrossCPPFLAGS Include="-DMONOTOUCH=1" /> - <_MonoAotCrossCPPFLAGS Include="-m64" /> - - <_MonoAotCrossCXXPPFLAGS Include="-O2" /> - <_MonoAotCrossCXXPPFLAGS Include="-g" /> - <_MonoAotCrossCXXPPFLAGS Include="-m64" /> - - <_MonoAotCrossLDFLAGS Include="-stdlib=libc++" /> - - <_MonoAotCrossOffsetsToolParams Condition="'$(Platform)' == 'arm64'" Include="--abi=aarch64-apple-darwin10" /> - <_MonoAotCrossOffsetsToolParams Include="--netcore" /> - <_MonoAotCrossOffsetsToolParams Include="--targetdir="$(MonoObjDir)"" /> - <_MonoAotCrossOffsetsToolParams Include="--monodir="$(MonoProjectRoot)"" /> - <_MonoAotCrossOffsetsToolParams Include="--outfile="$(MonoObjDir)cross/offsets-$(Platform)-darwin.h"" /> - <_MonoAotCrossOffsetsToolParams Include="--libclang="$(XcodeDir)/Toolchains/XcodeDefault.xctoolchain/usr/lib/libclang.dylib"" /> - <_MonoAotCrossOffsetsToolParams Include="--sysroot="$(XcodeDir)/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS$(tvOSVersion).sdk"" /> @@ -325,6 +270,7 @@ <_MonoCFLAGS Condition="'$(Platform)' == 'arm'" Include="-arch armv7s" /> <_MonoCFLAGS Include="-isysroot $(XcodeDir)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS$(iOSVersion).sdk" /> <_MonoCFLAGS Include="-miphoneos-version-min=$(iOSVersionMin)" /> + <_MonoCFLAGS Include="-Werror=partial-availability" /> <_MonoCFLAGS Include="-Wl,-application_extension" /> <_MonoCFLAGS Include="-fexceptions" /> @@ -350,17 +296,78 @@ <_MonoLDFLAGS Condition="'$(Platform)' == 'arm64'" Include="-arch arm64" /> <_MonoLDFLAGS Condition="'$(Platform)' == 'arm'" Include="-arch armv7" /> <_MonoLDFLAGS Condition="'$(Platform)' == 'arm'" Include="-arch armv7s" /> - <_MonoLDFLAGS Include="-Wl,-no_weak_imports" /> + <_MonoLDFLAGS Include="-framework CoreFoundation" /> <_MonoLDFLAGS Include="-lobjc" /> <_MonoLDFLAGS Include="-lc++" /> + + + + + <_MonoConfigureParams Condition="'$(Platform)' == 'x64'" Include="--host=x86_64-apple-darwin10" /> + <_MonoConfigureParams Condition="'$(Platform)' == 'x86'" Include="--host=i386-apple-darwin10" /> + <_MonoConfigureParams Include="--disable-boehm" /> + <_MonoConfigureParams Include="--disable-btls" /> + <_MonoConfigureParams Include="--disable-executables" /> + <_MonoConfigureParams Include="--disable-iconv" /> + <_MonoConfigureParams Include="--disable-mcs-build" /> + <_MonoConfigureParams Include="--disable-nls" /> + <_MonoConfigureParams Include="--disable-visibility-hidden" /> + <_MonoConfigureParams Include="--enable-maintainer-mode" /> + <_MonoConfigureParams Include="--enable-minimal=com,remoting,shared_perfcounters,gac" /> + <_MonoConfigureParams Include="--enable-monotouch" /> + <_MonoConfigureParams Include="--with-tls=pthread" /> + <_MonoConfigureParams Include="--without-ikvm-native" /> + <_MonoConfigureParams Include="--disable-cooperative-suspend" /> + <_MonoConfigureParams Include="--disable-hybrid-suspend" /> + <_MonoConfigureParams Include="--disable-crash-reporting" /> + + <_MonoAC_VARS Include="ac_cv_func_clock_nanosleep=no" /> + <_MonoAC_VARS Include="ac_cv_func_fstatat=no" /> + <_MonoAC_VARS Include="ac_cv_func_readlinkat=no" /> + <_MonoAC_VARS Include="ac_cv_func_system=no" /> + <_MonoAC_VARS Include="ac_cv_func_getentropy=no" /> + <_MonoAC_VARS Include="ac_cv_func_futimens=no" /> + <_MonoAC_VARS Include="ac_cv_func_utimensat=no" /> + <_MonoAC_VARS Include="ac_cv_func_shm_open_working_with_mmap=no" /> + <_MonoAC_VARS Include="mono_cv_uscore=yes" /> + + <_MonoCFLAGS Condition="'$(Platform)' == 'x64'" Include="-arch x86_64" /> + <_MonoCFLAGS Condition="'$(Platform)' == 'x64'" Include="-m64" /> + <_MonoCFLAGS Condition="'$(Platform)' == 'x86'" Include="-arch i386" /> + <_MonoCFLAGS Condition="'$(Platform)' == 'x86'" Include="-m32" /> + <_MonoCFLAGS Include="-isysroot $(XcodeDir)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator$(iOSVersion).sdk" /> + <_MonoCFLAGS Include="-mios-simulator-version-min=$(iOSVersionMin)" /> + <_MonoCFLAGS Include="-Wl,-application_extension" /> + + <_MonoCXXFLAGS Condition="'$(Platform)' == 'x64'" Include="-arch x86_64" /> + <_MonoCXXFLAGS Condition="'$(Platform)' == 'x64'" Include="-m64" /> + <_MonoCXXFLAGS Condition="'$(Platform)' == 'x86'" Include="-arch i386" /> + <_MonoCXXFLAGS Condition="'$(Platform)' == 'x86'" Include="-m32" /> + <_MonoCXXFLAGS Include="-isysroot $(XcodeDir)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator$(iOSVersion).sdk" /> + <_MonoCXXFLAGS Include="-mios-simulator-version-min=$(iOSVersionMin)" /> + <_MonoCXXFLAGS Include="-Wl,-application_extension" /> + + <_MonoCPPFLAGS Condition="'$(Platform)' == 'x64'" Include="-arch x86_64" /> + <_MonoCPPFLAGS Condition="'$(Platform)' == 'x64'" Include="-m64" /> + <_MonoCPPFLAGS Condition="'$(Platform)' == 'x86'" Include="-arch i386" /> + <_MonoCPPFLAGS Condition="'$(Platform)' == 'x86'" Include="-m32" /> + <_MonoCPPFLAGS Include="-isysroot $(XcodeDir)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator$(iOSVersion).sdk" /> + <_MonoCPPFLAGS Include="-mios-simulator-version-min=$(iOSVersionMin)" /> + <_MonoCPPFLAGS Include="-Wl,-application_extension" /> + <_MonoCPPFLAGS Include="-DMONOTOUCH=1" /> + <_MonoCPPFLAGS Include="-DHOST_IOS" /> + + + <_MonoAotCrossConfigureParams Include="--host=x86_64-apple-darwin10" /> - <_MonoAotCrossConfigureParams Condition="'$(Platform)' == 'arm64'" Include="--target=aarch64-darwin" /> - <_MonoAotCrossConfigureParams Condition="'$(Platform)' == 'arm'" Include="--target=arm-darwin" /> - <_MonoAotCrossConfigureParams Include="--with-cross-offsets=$(MonoObjDir)cross/offsets-$(Platform)-darwin.h" /> + <_MonoAotCrossConfigureParams Condition="'$(Platform)' == 'arm64'" Include="--target=aarch64-apple-darwin10" /> + <_MonoAotCrossConfigureParams Condition="'$(Platform)' == 'arm'" Include="--target=arm-apple-darwin10" /> + <_MonoAotCrossConfigureParams Condition="'$(Platform)' == 'x86'" Include="--target=i386-apple-darwin10" /> + <_MonoAotCrossConfigureParams Condition="'$(Platform)' == 'arm64' or '$(Platform)' == 'arm' or '$(Platform)' == 'x86'" Include="--with-cross-offsets=$(MonoObjDir)cross/offsets-$(Platform)-darwin.h" /> <_MonoAotCrossConfigureParams Include="--with-core=only" /> <_MonoAotCrossConfigureParams Include="--enable-maintainer-mode" /> <_MonoAotCrossConfigureParams Include="--enable-compile-warnings" /> @@ -376,7 +383,7 @@ <_MonoAotCrossConfigureParams Include="--enable-minimal=com,remoting" /> <_MonoAotCrossConfigureParams Include="--enable-monotouch" /> <_MonoAotCrossConfigureParams Include="--disable-crash-reporting" /> - + <_MonoAotCrossConfigureParams Include="--with-llvm=$(MonoLLVMDir)" /> <_MonoAotCrossAC_VARS Include="ac_cv_func_shm_open_working_with_mmap=no" /> @@ -406,64 +413,18 @@ <_MonoAotCrossLDFLAGS Include="-stdlib=libc++" /> + <_MonoAotCrossOffsetsToolParams Condition="'$(Platform)' == 'arm64'" Include="--abi=aarch64-apple-darwin10" /> <_MonoAotCrossOffsetsToolParams Condition="'$(Platform)' == 'arm'" Include="--abi=arm-apple-darwin10" /> - <_MonoAotCrossOffsetsToolParams Include="--netcore" /> - <_MonoAotCrossOffsetsToolParams Include="--targetdir="$(MonoObjDir)"" /> - <_MonoAotCrossOffsetsToolParams Include="--monodir="$(MonoProjectRoot)"" /> - <_MonoAotCrossOffsetsToolParams Include="--outfile="$(MonoObjDir)cross/offsets-$(Platform)-darwin.h"" /> - <_MonoAotCrossOffsetsToolParams Include="--libclang="$(XcodeDir)/Toolchains/XcodeDefault.xctoolchain/usr/lib/libclang.dylib"" /> - <_MonoAotCrossOffsetsToolParams Include="--sysroot="$(XcodeDir)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS$(iOSVersion).sdk"" /> - - - - - <_MonoConfigureParams Include="--host=x86_64-apple-darwin10" /> - <_MonoConfigureParams Include="--disable-boehm" /> - <_MonoConfigureParams Include="--disable-btls" /> - <_MonoConfigureParams Include="--disable-executables" /> - <_MonoConfigureParams Include="--disable-iconv" /> - <_MonoConfigureParams Include="--disable-mcs-build" /> - <_MonoConfigureParams Include="--disable-nls" /> - <_MonoConfigureParams Include="--disable-visibility-hidden" /> - <_MonoConfigureParams Include="--enable-maintainer-mode" /> - <_MonoConfigureParams Include="--enable-minimal=com,remoting,shared_perfcounters,gac" /> - <_MonoConfigureParams Include="--enable-monotouch" /> - <_MonoConfigureParams Include="--with-tls=pthread" /> - <_MonoConfigureParams Include="--without-ikvm-native" /> - <_MonoConfigureParams Include="--disable-cooperative-suspend" /> - <_MonoConfigureParams Include="--disable-hybrid-suspend" /> - <_MonoConfigureParams Include="--disable-crash-reporting" /> - - <_MonoAC_VARS Include="ac_cv_func_clock_nanosleep=no" /> - <_MonoAC_VARS Include="ac_cv_func_fstatat=no" /> - <_MonoAC_VARS Include="ac_cv_func_readlinkat=no" /> - <_MonoAC_VARS Include="ac_cv_func_system=no" /> - <_MonoAC_VARS Include="ac_cv_func_getentropy=no" /> - <_MonoAC_VARS Include="ac_cv_func_futimens=no" /> - <_MonoAC_VARS Include="ac_cv_func_utimensat=no" /> - <_MonoAC_VARS Include="ac_cv_func_shm_open_working_with_mmap=no" /> - <_MonoAC_VARS Include="mono_cv_uscore=yes" /> - - <_MonoCFLAGS Include="-arch x86_64" /> - <_MonoCFLAGS Include="-m64" /> - <_MonoCFLAGS Include="-isysroot $(XcodeDir)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator$(iOSVersion).sdk" /> - <_MonoCFLAGS Include="-mios-simulator-version-min=$(iOSVersionMin)" /> - <_MonoCFLAGS Include="-Wl,-application_extension" /> - - <_MonoCXXFLAGS Include="-arch x86_64" /> - <_MonoCXXFLAGS Include="-m64" /> - <_MonoCXXFLAGS Include="-isysroot $(XcodeDir)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator$(iOSVersion).sdk" /> - <_MonoCXXFLAGS Include="-mios-simulator-version-min=$(iOSVersionMin)" /> - <_MonoCXXFLAGS Include="-Wl,-application_extension" /> - - <_MonoCPPFLAGS Include="-arch x86_64" /> - <_MonoCPPFLAGS Include="-m64" /> - <_MonoCPPFLAGS Include="-isysroot $(XcodeDir)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator$(iOSVersion).sdk" /> - <_MonoCPPFLAGS Include="-mios-simulator-version-min=$(iOSVersionMin)" /> - <_MonoCPPFLAGS Include="-Wl,-application_extension" /> - <_MonoCPPFLAGS Include="-DMONOTOUCH=1" /> - <_MonoCPPFLAGS Include="-DHOST_IOS" /> + <_MonoAotCrossOffsetsToolParams Condition="'$(Platform)' == 'x86'" Include="--abi=i386-apple-darwin10" /> + <_MonoAotCrossOffsetsToolParams Condition="'$(Platform)' != 'x64'" Include="--netcore" /> + <_MonoAotCrossOffsetsToolParams Condition="'$(Platform)' != 'x64'" Include="--targetdir="$(MonoObjDir)"" /> + <_MonoAotCrossOffsetsToolParams Condition="'$(Platform)' != 'x64'" Include="--monodir="$(MonoProjectRoot)"" /> + <_MonoAotCrossOffsetsToolParams Condition="'$(Platform)' != 'x64'" Include="--outfile="$(MonoObjDir)cross/offsets-$(Platform)-darwin.h"" /> + <_MonoAotCrossOffsetsToolParams Condition="'$(Platform)' != 'x64'" Include="--libclang="$(XcodeDir)/Toolchains/XcodeDefault.xctoolchain/usr/lib/libclang.dylib"" /> + <_MonoAotCrossOffsetsToolParams Condition="'$(Platform)' != 'x64' and '$(TargetsiOS)' == 'true' and '$(TargetsiOSSimulator)' != 'true'" Include="--sysroot="$(XcodeDir)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS$(iOSVersion).sdk"" /> + <_MonoAotCrossOffsetsToolParams Condition="'$(Platform)' != 'x64' and '$(TargetsiOS)' == 'true' and '$(TargetsiOSSimulator)' == 'true'" Include="--sysroot="$(XcodeDir)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator$(iOSVersion).sdk"" /> + <_MonoAotCrossOffsetsToolParams Condition="'$(Platform)' != 'x64' and '$(TargetstvOS)' == 'true'" Include="--sysroot="$(XcodeDir)/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS$(tvOSVersion).sdk"" /> @@ -481,10 +442,10 @@ <_MonoConfigureParams Include="--enable-minimal=ssa,portability,attach,verifier,full_messages,sgen_remset,sgen_marksweep_par,sgen_marksweep_fixed,sgen_marksweep_fixed_par,sgen_copying,logging,security,shared_handles,interpreter,,gac,cfgdir_config" /> <_MonoConfigureParams Include="--enable-monodroid" /> <_MonoConfigureParams Include="--enable-dynamic-btls" /> - <_MonoConfigureParams Include="--with-btls-android-ndk=$(ANDROID_NDK_HOME)" /> + <_MonoConfigureParams Include="--with-btls-android-ndk=$(ANDROID_NDK_ROOT)" /> <_MonoConfigureParams Include="--with-btls-android-api=$(AndroidApiVersion)" /> <_MonoConfigureParams Include="--with-btls-android-ndk-asm-workaround" /> - <_MonoConfigureParams Include="--with-btls-android-cmake-toolchain=$(ANDROID_NDK_HOME)/build/cmake/android.toolchain.cmake" /> + <_MonoConfigureParams Include="--with-btls-android-cmake-toolchain=$(ANDROID_NDK_ROOT)/build/cmake/android.toolchain.cmake" /> <_MonoConfigureParams Include="--with-sigaltstack=yes" /> <_MonoConfigureParams Include="--with-tls=pthread" /> <_MonoConfigureParams Include="--without-ikvm-native" /> @@ -512,10 +473,10 @@ <_MonoCXXFLAGS Include="-fstack-protector" /> <_MonoCPPFLAGS Condition="'$(Platform)' == 'arm64'" Include="-DANDROID64" /> - <_MonoCPPFLAGS Condition="'$(Platform)' == 'arm64'" Include="-I$(ANDROID_NDK_HOME)/sysroot/usr/include/aarch64-linux-android" /> - <_MonoCPPFLAGS Condition="'$(Platform)' == 'arm'" Include="-I$(ANDROID_NDK_HOME)/sysroot/usr/include/arm-linux-androideabi" /> - <_MonoCPPFLAGS Condition="'$(Platform)' == 'x64'" Include="-I$(ANDROID_NDK_HOME)/sysroot/usr/include/x86_64-linux-android" /> - <_MonoCPPFLAGS Condition="'$(Platform)' == 'x86'" Include="-I$(ANDROID_NDK_HOME)/sysroot/usr/include/i686-linux-android" /> + <_MonoCPPFLAGS Condition="'$(Platform)' == 'arm64'" Include="-I$(ANDROID_NDK_ROOT)/sysroot/usr/include/aarch64-linux-android" /> + <_MonoCPPFLAGS Condition="'$(Platform)' == 'arm'" Include="-I$(ANDROID_NDK_ROOT)/sysroot/usr/include/arm-linux-androideabi" /> + <_MonoCPPFLAGS Condition="'$(Platform)' == 'x64'" Include="-I$(ANDROID_NDK_ROOT)/sysroot/usr/include/x86_64-linux-android" /> + <_MonoCPPFLAGS Condition="'$(Platform)' == 'x86'" Include="-I$(ANDROID_NDK_ROOT)/sysroot/usr/include/i686-linux-android" /> <_MonoCPPFLAGS Condition="'$(Platform)' == 'x64'" Include="-m64" /> <_MonoCPPFLAGS Condition="'$(Platform)' == 'x86'" Include="-m32" /> <_MonoCPPFLAGS Condition="'$(Platform)' == 'arm64' or '$(Platform)' == 'x64'" Include="-DL_cuserid=9" /> @@ -523,15 +484,15 @@ <_MonoCPPFLAGS Condition="'$(Platform)' == 'arm64' or '$(Platform)' == 'arm'" Include="-DSK_RELEASE" /> <_MonoCPPFLAGS Condition="'$(Platform)' == 'arm64' or '$(Platform)' == 'arm'" Include="-DNDEBUG" /> <_MonoCPPFLAGS Condition="'$(Platform)' == 'arm64' or '$(Platform)' == 'arm'" Include="-UDEBUG" /> - <_MonoCPPFLAGS Include="-I$(ANDROID_NDK_HOME)/sysroot/usr/include" /> + <_MonoCPPFLAGS Include="-I$(ANDROID_NDK_ROOT)/sysroot/usr/include" /> <_MonoCPPFLAGS Include="-DMONODROID=1" /> <_MonoCPPFLAGS Include="-D__ANDROID_API__=$(AndroidApiVersion)" /> <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'arm64'" Include="-DANDROID64" /> - <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'arm64'" Include="-I$(ANDROID_NDK_HOME)/sysroot/usr/include/aarch64-linux-android" /> - <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'arm'" Include="-I$(ANDROID_NDK_HOME)/sysroot/usr/include/arm-linux-androideabi" /> - <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'x64'" Include="-I$(ANDROID_NDK_HOME)/sysroot/usr/include/x86_64-linux-android" /> - <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'x86'" Include="-I$(ANDROID_NDK_HOME)/sysroot/usr/include/i686-linux-android" /> + <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'arm64'" Include="-I$(ANDROID_NDK_ROOT)/sysroot/usr/include/aarch64-linux-android" /> + <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'arm'" Include="-I$(ANDROID_NDK_ROOT)/sysroot/usr/include/arm-linux-androideabi" /> + <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'x64'" Include="-I$(ANDROID_NDK_ROOT)/sysroot/usr/include/x86_64-linux-android" /> + <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'x86'" Include="-I$(ANDROID_NDK_ROOT)/sysroot/usr/include/i686-linux-android" /> <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'x64'" Include="-m64" /> <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'x86'" Include="-m32" /> <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'arm64' or '$(Platform)' == 'x64'" Include="-DL_cuserid=9" /> @@ -539,19 +500,19 @@ <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'arm64' or '$(Platform)' == 'arm'" Include="-DSK_RELEASE" /> <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'arm64' or '$(Platform)' == 'arm'" Include="-DNDEBUG" /> <_MonoCXXCPPFLAGS Condition="'$(Platform)' == 'arm64' or '$(Platform)' == 'arm'" Include="-UDEBUG" /> - <_MonoCXXCPPFLAGS Include="-I$(ANDROID_NDK_HOME)/sysroot/usr/include" /> + <_MonoCXXCPPFLAGS Include="-I$(ANDROID_NDK_ROOT)/sysroot/usr/include" /> <_MonoCXXCPPFLAGS Include="-DMONODROID=1" /> <_MonoCXXCPPFLAGS Include="-D__ANDROID_API__=$(AndroidApiVersion)" /> - <_MonoLDFLAGS Condition="'$(Platform)' == 'arm64'" Include="-L$(ANDROID_NDK_HOME)/platforms/android-$(AndroidApiVersion)/arch-arm64/usr/lib" /> - <_MonoLDFLAGS Condition="'$(Platform)' == 'arm64'" Include="-Wl,-rpath-link=$(ANDROID_NDK_HOME)/platforms/android-$(AndroidApiVersion)/arch-arm64/usr/lib,-dynamic-linker=/system/bin/linker" /> - <_MonoLDFLAGS Condition="'$(Platform)' == 'arm'" Include="-L$(ANDROID_NDK_HOME)/platforms/android-$(AndroidApiVersion)/arch-arm/usr/lib" /> - <_MonoLDFLAGS Condition="'$(Platform)' == 'arm'" Include="-Wl,-rpath-link=$(ANDROID_NDK_HOME)/platforms/android-$(AndroidApiVersion)/arch-arm/usr/lib,-dynamic-linker=/system/bin/linker" /> + <_MonoLDFLAGS Condition="'$(Platform)' == 'arm64'" Include="-L$(ANDROID_NDK_ROOT)/platforms/android-$(AndroidApiVersion)/arch-arm64/usr/lib" /> + <_MonoLDFLAGS Condition="'$(Platform)' == 'arm64'" Include="-Wl,-rpath-link=$(ANDROID_NDK_ROOT)/platforms/android-$(AndroidApiVersion)/arch-arm64/usr/lib,-dynamic-linker=/system/bin/linker" /> + <_MonoLDFLAGS Condition="'$(Platform)' == 'arm'" Include="-L$(ANDROID_NDK_ROOT)/platforms/android-$(AndroidApiVersion)/arch-arm/usr/lib" /> + <_MonoLDFLAGS Condition="'$(Platform)' == 'arm'" Include="-Wl,-rpath-link=$(ANDROID_NDK_ROOT)/platforms/android-$(AndroidApiVersion)/arch-arm/usr/lib,-dynamic-linker=/system/bin/linker" /> <_MonoLDFLAGS Condition="'$(Platform)' == 'arm'" Include="-Wl,--fix-cortex-a8" /> - <_MonoLDFLAGS Condition="'$(Platform)' == 'x86'" Include="-L$(ANDROID_NDK_HOME)/platforms/android-$(AndroidApiVersion)/arch-x86/usr/lib" /> - <_MonoLDFLAGS Condition="'$(Platform)' == 'x86'" Include="-Wl,-rpath-link=$(ANDROID_NDK_HOME)/platforms/android-$(AndroidApiVersion)/arch-x86/usr/lib,-dynamic-linker=/system/bin/linker" /> - <_MonoLDFLAGS Condition="'$(Platform)' == 'x64'" Include="-L$(ANDROID_NDK_HOME)/platforms/android-$(AndroidApiVersion)/arch-x86_64/usr/lib" /> - <_MonoLDFLAGS Condition="'$(Platform)' == 'x64'" Include="-Wl,-rpath-link=$(ANDROID_NDK_HOME)/platforms/android-$(AndroidApiVersion)/arch-x86_64/usr/lib,-dynamic-linker=/system/bin/linker" /> + <_MonoLDFLAGS Condition="'$(Platform)' == 'x86'" Include="-L$(ANDROID_NDK_ROOT)/platforms/android-$(AndroidApiVersion)/arch-x86/usr/lib" /> + <_MonoLDFLAGS Condition="'$(Platform)' == 'x86'" Include="-Wl,-rpath-link=$(ANDROID_NDK_ROOT)/platforms/android-$(AndroidApiVersion)/arch-x86/usr/lib,-dynamic-linker=/system/bin/linker" /> + <_MonoLDFLAGS Condition="'$(Platform)' == 'x64'" Include="-L$(ANDROID_NDK_ROOT)/platforms/android-$(AndroidApiVersion)/arch-x86_64/usr/lib" /> + <_MonoLDFLAGS Condition="'$(Platform)' == 'x64'" Include="-Wl,-rpath-link=$(ANDROID_NDK_ROOT)/platforms/android-$(AndroidApiVersion)/arch-x86_64/usr/lib,-dynamic-linker=/system/bin/linker" /> <_MonoLDFLAGS Include="-z now" /> <_MonoLDFLAGS Include="-z relro" /> <_MonoLDFLAGS Include="-z noexecstack" /> @@ -588,8 +549,8 @@ <_MonoAndroidBuildHost Condition="$([MSBuild]::IsOSPlatform('OSX'))">darwin-x86_64 <_MonoAndroidBuildHost Condition="$([MSBuild]::IsOSPlatform('Linux'))">linux-x86_64 - <_MonoAndroidToolchainPrefix>$(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(_MonoAndroidBuildHost)/bin/$(_MonoAndroidTargetTuple) - <_MonoAndroidToolchainPrefixClang Condition="'$(Platform)' == 'arm'">$(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(_MonoAndroidBuildHost)/bin/armv7a-linux-androideabi$(AndroidApiVersion) + <_MonoAndroidToolchainPrefix>$(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/$(_MonoAndroidBuildHost)/bin/$(_MonoAndroidTargetTuple) + <_MonoAndroidToolchainPrefixClang Condition="'$(Platform)' == 'arm'">$(ANDROID_NDK_ROOT)/toolchains/llvm/prebuilt/$(_MonoAndroidBuildHost)/bin/armv7a-linux-androideabi$(AndroidApiVersion) <_MonoAndroidToolchainPrefixClang Condition="'$(Platform)' != 'arm'">$(_MonoAndroidToolchainPrefix)$(AndroidApiVersion) <_MonoCCOption>CC="$(_MonoAndroidToolchainPrefixClang)-clang" @@ -618,10 +579,10 @@ <_MonoSTRIPOption>STRIP="$(_MonoTuple)-strip" - + - + <_MonoConfigureParams Include="--host=wasm32"/> <_MonoConfigureParams Include="--disable-boehm" /> <_MonoConfigureParams Include="--disable-btls" /> @@ -642,12 +603,46 @@ <_MonoCFLAGS Include="-fexceptions" /> <_MonoCXXFLAGS Include="-fexceptions -s DISABLE_EXCEPTION_CATCHING=0" /> <_MonoAC_VARS Include="ac_cv_func_shm_open_working_with_mmap=no" /> + + + <_MonoAotCrossConfigureParams Include="--with-core=only" /> + <_MonoAotCrossConfigureParams Include="--enable-maintainer-mode" /> + <_MonoAotCrossConfigureParams Include="--enable-compile-warnings" /> + <_MonoAotCrossConfigureParams Include="--prefix=$(MonoObjDir)cross/out" /> + <_MonoAotCrossConfigureParams Include="--disable-boehm" /> + <_MonoAotCrossConfigureParams Include="--disable-btls" /> + <_MonoAotCrossConfigureParams Include="--disable-iconv" /> + <_MonoAotCrossConfigureParams Include="--disable-libraries" /> + <_MonoAotCrossConfigureParams Include="--disable-mcs-build" /> + <_MonoAotCrossConfigureParams Include="--disable-nls" /> + <_MonoAotCrossConfigureParams Include="--enable-dtrace=no" /> + <_MonoAotCrossConfigureParams Include="--enable-icall-symbol-map" /> + <_MonoAotCrossConfigureParams Include="--enable-minimal=com,remoting" /> + <_MonoAotCrossConfigureParams Include="--disable-crash-reporting" /> + <_MonoAotCrossConfigureParams Include="--with-cooperative-gc=no" /> + <_MonoAotCrossConfigureParams Include="--enable-hybrid-suspend=no" /> + <_MonoAotCrossConfigureParams Include="--target=wasm32-unknown-none" /> + <_MonoAotCrossConfigureParams Include="--with-cross-offsets=$(MonoObjDir)cross/offsets-wasm32-unknown-none.h" /> + <_MonoAotCrossConfigureParams Include="--with-llvm=$(MonoLLVMDir)" /> + + <_MonoAotCrossCFLAGS Include="-O2" /> + <_MonoAotCrossCFLAGS Include="-g" /> + <_MonoAotCrossCFLAGS Include="-m64" /> + + <_MonoAotCrossOffsetsToolParams Include="--netcore" /> + <_MonoAotCrossOffsetsToolParams Include="--abi=wasm32-unknown-unknown" /> + <_MonoAotCrossOffsetsToolParams Include="--targetdir="$(MonoObjDir)"" /> + <_MonoAotCrossOffsetsToolParams Include="--monodir="$(MonoProjectRoot)"" /> + <_MonoAotCrossOffsetsToolParams Include="--outfile="$(MonoObjDir)cross/offsets-wasm32-unknown-none.h"" /> + <_MonoAotCrossOffsetsToolParams Include="--emscripten-sdk="$(EMSDK_PATH)/upstream/emscripten"" /> + <_MonoAotCrossOffsetsToolParams Include="--libclang="$(EMSDK_PATH)/upstream/lib/libclang.dylib"" Condition="$([MSBuild]::IsOSPlatform('OSX'))" /> + <_MonoAotCrossOffsetsToolParams Include="--libclang="$(EMSDK_PATH)/upstream/lib/libclang.so"" Condition="!$([MSBuild]::IsOSPlatform('OSX'))" /> - <_MonoCFLAGS Include="-Wl,--build-id" /> - <_MonoCXXFLAGS Include="-Wl,--build-id" /> + <_MonoCFLAGS Include="-Wl,--build-id=sha1" /> + <_MonoCXXFLAGS Include="-Wl,--build-id=sha1" /> @@ -679,7 +674,7 @@ <_MonoConfigureOptions>@(_MonoConfigureParams, ' ') @(_MonoAC_VARS, ' ') $(_MonoCFLAGSOption) $(_MonoCXXFLAGSOption) $(_MonoCPPFLAGSOption) $(_MonoCXXCPPFLAGSOption) $(_MonoLDFLAGSOption) $(_MonoCCLDFLAGSOption) $(_MonoCCOption) $(_MonoCXXOption) $(_MonoAROption) $(_MonoASOption) $(_MonoCPPOption) $(_MonoCXXCPPOption) $(_MonoDLLTOOLOption) $(_MonoLDOption) $(_MonoOBJDUMPOption) $(_MonoRANLIBOption) $(_MonoCMAKEOption) $(_MonoSTRIPOption) <_MonoConfigureCommand Condition="'$(_MonoCCOption)' == '' and '$(_MonoCXXOption)' == ''">bash -c 'source $(RepositoryEngineeringDir)native/init-compiler.sh $(Platform) clang && $(MonoProjectRoot)configure $(_MonoConfigureOptions)' <_MonoConfigureCommand Condition="'$(_MonoCCOption)' != '' and '$(_MonoCXXOption)' != ''">$(MonoProjectRoot)configure $(_MonoConfigureOptions) - <_MonoConfigureCommand Condition="'$(TargetsWASM)' == 'true'">bash -c 'source $(EMSDK_PATH)/emsdk_env.sh && emconfigure $(MonoProjectRoot)configure $(_MonoConfigureOptions)' + <_MonoConfigureCommand Condition="'$(TargetsBrowser)' == 'true'">bash -c 'source $(EMSDK_PATH)/emsdk_env.sh && emconfigure $(MonoProjectRoot)configure $(_MonoConfigureOptions)' @@ -692,7 +687,7 @@ <_MonoAotCrossCCLDFLAGSOption Condition="@(_MonoAotCrossCCLDFLAGS->Count()) > 0">CCLDFLAGS="@(_MonoAotCrossCCLDFLAGS, ' ')" <_MonoAotCrossConfigureCommand>$(MonoProjectRoot)configure @(_MonoAotCrossConfigureParams, ' ') @(_MonoAotCrossAC_VARS, ' ') $(_MonoAotCrossCFLAGSOption) $(_MonoAotCrossCXXFLAGSOption) $(_MonoAotCrossCPPFLAGSOption) $(_MonoAotCrossCXXCPPFLAGSOption) $(_MonoAotCrossLDFLAGSOption) $(_MonoAotCrossCCLDFLAGSOption) $(_MonoCCOption) $(_MonoCXXOption) $(_MonoAROption) $(_MonoASOption) $(_MonoCPPOption) $(_MonoCXXCPPOption) $(_MonoDLLTOOLOption) $(_MonoLDOption) $(_MonoOBJDUMPOption) $(_MonoRANLIBOption) $(_MonoCMAKEOption) $(_MonoSTRIPOption) - <_MonoAotCrossOffsetsCommand>python3 $(MonoProjectRoot)mono/tools/offsets-tool/offsets-tool.py @(_MonoAotCrossOffsetsToolParams, ' ') + <_MonoAotCrossOffsetsCommand Condition="@(_MonoAotCrossOffsetsToolParams->Count()) > 0">python3 $(MonoProjectRoot)mono/tools/offsets-tool/offsets-tool.py @(_MonoAotCrossOffsetsToolParams, ' ') @@ -714,9 +709,10 @@ - - + + + @@ -732,6 +728,7 @@ <_MonoBuildParams Include="/p:MONO_BUILD_DIR_PREFIX=""$(MonoObjDir)""" /> <_MonoBuildParams Include="/p:MONO_ENABLE_NETCORE=true" /> + <_MonoBuildParams Include="/p:MONO_ENABLE_PERFTRACING=true" /> <_MonoBuildParams Include="/p:MONO_USE_STATIC_C_RUNTIME=true" /> <_MonoBuildParams Include="/p:CL_MPCount=$([System.Environment]::ProcessorCount)" /> <_MonoBuildParams Include="/v:minimal" /> @@ -900,12 +897,16 @@ <_MonoRuntimeFilePath Condition="'$(TargetsiOS)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.dylib <_MonoRuntimeFilePath Condition="'$(TargetstvOS)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.dylib <_MonoRuntimeFilePath Condition="'$(TargetsAndroid)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.so - <_MonoRuntimeFilePath Condition="'$(TargetsWASM)' == 'true'">$(MonoObjDir)mono\mini\.libs\libmonosgen-2.0.a + <_MonoRuntimeFilePath Condition="'$(TargetsBrowser)' == 'true'">$(MonoObjDir)mono\mini\.libs\libmonosgen-2.0.a <_MonoRuntimeFilePath Condition="'$(_MonoRuntimeFilePath)' == ''">$(MonoObjDir)mono\mini\.libs\libmonosgen-2.0.so <_MonoRuntimeStaticFilePath Condition="'$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true' or '$(TargetsAndroid)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.a - <_MonoAotCrossFilePath Condition="'$(TargetsiOS)' == 'true' and '$(Platform)' == 'arm64'">$(MonoObjDir)cross\out\bin\aarch64-darwin-mono-sgen - <_MonoAotCrossFilePath Condition="'$(TargetsiOS)' == 'true' and '$(Platform)' == 'arm'">$(MonoObjDir)cross\out\bin\arm-darwin-mono-sgen - <_MonoAotCrossFilePath Condition="'$(TargetstvOS)' == 'true' and '$(Platform)' == 'arm64'">$(MonoObjDir)cross\out\bin\aarch64-darwin-mono-sgen + <_MonoAotCrossFilePath Condition="'$(TargetsiOS)' == 'true' and '$(Platform)' == 'arm64'">$(MonoObjDir)cross\out\bin\aarch64-apple-darwin10-mono-sgen + <_MonoAotCrossFilePath Condition="'$(TargetsiOS)' == 'true' and '$(Platform)' == 'arm'">$(MonoObjDir)cross\out\bin\arm-apple-darwin10-mono-sgen + <_MonoAotCrossFilePath Condition="'$(TargetsiOS)' == 'true' and '$(Platform)' == 'x86'">$(MonoObjDir)cross\out\bin\i386-apple-darwin10-mono-sgen + <_MonoAotCrossFilePath Condition="'$(TargetsiOS)' == 'true' and '$(Platform)' == 'x64'">$(MonoObjDir)cross\out\bin\mono-sgen + <_MonoAotCrossFilePath Condition="'$(TargetstvOS)' == 'true' and '$(Platform)' == 'arm64'">$(MonoObjDir)cross\out\bin\aarch64-apple-darwin10-mono-sgen + <_MonoAotCrossFilePath Condition="'$(TargetstvOS)' == 'true' and '$(Platform)' == 'x64'">$(MonoObjDir)cross\out\bin\mono-sgen + <_MonoAotCrossFilePath Condition="'$(TargetsBrowser)' == 'true'">$(MonoObjDir)cross\out\bin\wasm32-unknown-none-mono-sgen @@ -919,7 +920,31 @@ <_MonoRuntimeArtifacts Include="$(_MonoAotCrossFilePath)"> $(BinDir)cross\mono-aot-cross + <_MonoRuntimeArtifacts Condition="'$(MonoBundleLLVMOptimizer)' == 'true'" Include="$(MonoLLVMDir)\bin\llc"> + $(BinDir)\llc + + <_MonoRuntimeArtifacts Condition="'$(MonoBundleLLVMOptimizer)' == 'true'" Include="$(MonoLLVMDir)\bin\opt"> + $(BinDir)\opt + + <_MonoRuntimeArtifacts Condition="'$(TargetOS)' == 'iOS' or '$(TargetOS)' == 'tvOS'" Include="$(MonoLLVMDir)\bin\llc"> + $(BinDir)cross\llc + + <_MonoRuntimeArtifacts Condition="'$(TargetOS)' == 'iOS' or '$(TargetOS)' == 'tvOS'" Include="$(MonoLLVMDir)\bin\opt"> + $(BinDir)cross\opt + <_MonoIncludeArtifacts Include="$(MonoObjDir)out\include\**" /> + <_MonoRuntimeArtifacts Condition="'$(TargetsBrowser)' == 'true'" Include="$(MonoObjDir)out\lib\libmono-ee-interp.a"> + $(BinDir)libmono-ee-interp.a + + <_MonoRuntimeArtifacts Condition="'$(TargetsBrowser)' == 'true'" Include="$(MonoObjDir)out\lib\libmono-icall-table.a"> + $(BinDir)libmono-icall-table.a + + <_MonoRuntimeArtifacts Condition="'$(TargetsBrowser)' == 'true'" Include="$(MonoObjDir)out\lib\libmono-ilgen.a"> + $(BinDir)libmono-ilgen.a + + <_MonoRuntimeArtifacts Condition="'$(TargetsBrowser)' == 'true'" Include="$(MonoObjDir)out\lib\libmono-profiler-aot.a"> + $(BinDir)libmono-profiler-aot.a + + Condition="'$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true' or '$(TargetsAndroid)' == 'true' or '$(TargetsBrowser)' == 'true'"/> diff --git a/src/mono/mono/Makefile.am b/src/mono/mono/Makefile.am index 226b8cab868544..fa19a4c0018dc4 100644 --- a/src/mono/mono/Makefile.am +++ b/src/mono/mono/Makefile.am @@ -13,11 +13,20 @@ native_dirs = native endif if ENABLE_NETCORE -btls_dirs = +btls_dirs = +managed_unit_test_dirs = +native_unit_test_dirs = +else +managed_unit_test_dirs = tests +native_unit_test_dirs = unit-tests +endif + +if ENABLE_PERFTRACING +eventpipe_dirs = eventpipe endif if ENABLE_NETCORE -SUBDIRS = eglib arch utils sgen zlib metadata mini profiler +SUBDIRS = eglib arch utils sgen zlib $(eventpipe_dirs) metadata mini profiler $(native_unit_test_dirs) else if CROSS_COMPILING @@ -26,9 +35,9 @@ else if INSTALL_MONOTOUCH SUBDIRS = $(btls_dirs) eglib arch utils zlib $(sgen_dirs) metadata mini profiler $(native_dirs) else -SUBDIRS = $(btls_dirs) eglib arch utils cil zlib $(sgen_dirs) metadata mini dis tests unit-tests benchmark profiler $(native_dirs) +SUBDIRS = $(btls_dirs) eglib arch utils cil zlib $(sgen_dirs) metadata mini dis $(managed_unit_test_dirs) $(native_unit_test_dirs) benchmark profiler $(native_dirs) endif endif endif -DIST_SUBDIRS = btls native eglib arch utils cil zlib $(sgen_dirs) metadata mini dis tests unit-tests benchmark profiler +DIST_SUBDIRS = btls native eglib arch utils cil zlib $(sgen_dirs) metadata mini dis $(managed_unit_test_dirs) $(native_unit_test_dirs) benchmark profiler diff --git a/src/mono/mono/arch/s390x/s390x-codegen.h b/src/mono/mono/arch/s390x/s390x-codegen.h index 0980327127ff46..e621c52252949c 100644 --- a/src/mono/mono/arch/s390x/s390x-codegen.h +++ b/src/mono/mono/arch/s390x/s390x-codegen.h @@ -191,6 +191,7 @@ typedef enum { #define S390_FP s390_r11 #define S390_MINIMAL_STACK_SIZE 160 #define S390_REG_SAVE_OFFSET 48 +#define S390_NONPARM_SAVE_OFFSET 56 #define S390_PARM_SAVE_OFFSET 16 #define S390_RET_ADDR_OFFSET 112 #define S390_FLOAT_SAVE_OFFSET 128 @@ -1339,7 +1340,6 @@ typedef struct { #define s390_ldeb(c, r, x, b, d) S390_RXE(c, 0xed04, r, x, b, d) #define s390_ldebr(c, r1, r2) S390_RRE(c, 0xb304, r1, r2) #define s390_ldgr(c, r1, r2) S390_RRE(c, 0xb3c1, r1, r2) -#define s390_ldgr(c, r1, r2) S390_RRE(c, 0xb3c1, r1, r2) #define s390_ldxbr(c, r1, r2) S390_RRE(c, 0xb345, r1, r2) #define s390_ldr(c, r1, r2) S390_RR(c, 0x28, r1, r2) #define s390_le(c, f, x, b, d) S390_RX(c, 0x78, f, x, b, d) @@ -1384,6 +1384,7 @@ typedef struct { #define s390_lm(c, r1, r2, b, d) S390_RS_1(c, 0x98, r1, r2, b, d) #define s390_lmg(c, r1, r2, b, d) S390_RSY_1(c, 0xeb04, r1, r2, b, d) #define s390_lndbr(c, r1, r2) S390_RRE(c, 0xb311, r1, r2) +#define s390_lnebr(c, r1, r2) S390_RRE(c, 0xb301, r1, r2) #define s390_lngr(c, r1, r2) S390_RRE(c, 0xb901, r1, r2) #define s390_lnr(c, r1, r2) S390_RR(c, 0x11, r1, r2) #define s390_lpdbr(c, r1, r2) S390_RRE(c, 0xb310, r1, r2) @@ -1489,6 +1490,7 @@ typedef struct { #define s390_srlg(c, r1, r2, b, d) S390_RSY_1(c, 0xeb0c, r1, r2, b, d) #define s390_st(c, r, x, b, d) S390_RX(c, 0x50, r, x, b, d) #define s390_stam(c, r1, r2, b, d) S390_RS_1(c, 0x9b, r1, r2, b, d) +#define s390_stamy(c, r1, r2, b, d) S390_RSY_1(c, 0xeb9b, r1, r2, b, d) #define s390_stc(c, r, x, b, d) S390_RX(c, 0x42, r, x, b, d) #define s390_stcm(c, r, m, b, d) S390_RX(c, 0xbe, r, m, b, d) #define s390_stcmy(c, r, x, b, d) S390_RXY(c, 0xeb2d, r, x, b, d) diff --git a/src/mono/mono/eglib/gfile-posix.c b/src/mono/mono/eglib/gfile-posix.c index c18850a8626261..5bda34cdfc8291 100644 --- a/src/mono/mono/eglib/gfile-posix.c +++ b/src/mono/mono/eglib/gfile-posix.c @@ -179,7 +179,7 @@ g_get_current_dir (void) } while (fail); /* On amd64 sometimes the bottom 32-bits of r == the bottom 32-bits of buffer - * but the top 32-bits of r have overflown to 0xffffffff (seriously wtf getcwd + * but the top 32-bits of r have overflown to 0xffffffff (seriously, getcwd * so we return the buffer here since it has a pointer to the valid string */ return buffer; diff --git a/src/mono/mono/eventpipe/Makefile.am b/src/mono/mono/eventpipe/Makefile.am new file mode 100644 index 00000000000000..63d2edd8cf9dd3 --- /dev/null +++ b/src/mono/mono/eventpipe/Makefile.am @@ -0,0 +1,71 @@ +MAKEFLAGS := $(MAKEFLAGS) --no-builtin-rules + +if !ENABLE_MSVC_ONLY +if ENABLE_PERFTRACING + +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/mono $(GLIB_CFLAGS) $(SHARED_CFLAGS) + +noinst_LTLIBRARIES = libeventpipe.la + +eventpipe_sources = \ + ep.c \ + ep.h \ + ep-block.c \ + ep-block.h \ + ep-block-internals.c \ + ep-buffer.h \ + ep-buffer-manager.c \ + ep-buffer-manager.h \ + ep-buffer-manager-internals.c \ + ep-config.c \ + ep-config.h \ + ep-config-internals.c \ + ep-event.h \ + ep-event-instance.h \ + ep-event-instance.c \ + ep-event-instance-internals.c \ + ep-event-internals.c \ + ep-event-payload-internals.c \ + ep-event-payload.h \ + ep-event-source.c \ + ep-event-source.h \ + ep-event-source-internals.c \ + ep-file.c \ + ep-file.h \ + ep-file-internals.c \ + ep-internals.c \ + ep-metadata-generator.c \ + ep-metadata-generator.h \ + ep-metadata-generator-internals.c \ + ep-provider.c \ + ep-provider.h \ + ep-provider-internals.c \ + ep-rt.h \ + ep-rt-config.h \ + ep-rt-config-mono.h \ + ep-rt-mono.c \ + ep-rt-mono.h \ + ep-rt-types.h \ + ep-rt-types-mono.h \ + ep-thread.c \ + ep-thread.h \ + ep-thread-internals.c \ + ep-types.h \ + ep-session.c \ + ep-session.h \ + ep-session-internals.c \ + ep-session-provider.c \ + ep-session-provider-internals.h \ + ep-session-provider-internals.c \ + ep-stream.c \ + ep-stream.h \ + ep-stream-internals.c \ + ep-stack-contents.h + + +libeventpipe_la_SOURCES = $(eventpipe_sources) + +endif # ENABLE_PERFTRACING +endif # !ENABLE_MSVC_ONLY + +CFLAGS := $(filter-out @CXX_REMOVE_CFLAGS@, @CFLAGS@) @CXX_ADD_CFLAGS@ diff --git a/src/mono/mono/eventpipe/ep-block-internals.c b/src/mono/mono/eventpipe/ep-block-internals.c new file mode 100644 index 00000000000000..3d3f6477226710 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-block-internals.c @@ -0,0 +1,595 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#define EP_IMPL_GETTER_SETTER +#include "ep.h" + +/* + * Forward declares of all static functions. + */ + +static +void +block_base_fast_serialize_func ( + void *object, + FastSerializer *fast_serializer); + +static +void +block_base_clear_func (void *object); + +static +void +block_base_serialize_header_func ( + void *object, + FastSerializer *fast_serializer); + +static +uint32_t +block_base_get_header_size_func (void *object); + +static +const ep_char8_t * +event_block_get_type_name_func (void *object); + +static +void +event_block_free_func (void *object); + +static +void +metadata_block_free_func (void *object); + +static +const ep_char8_t * +metadata_block_get_type_name_func (void *object); + +static +int32_t +sequence_point_get_block_size (EventPipeSequencePoint *sequence_point); + +static +void +sequence_point_block_free_func (void *object); + +static +const ep_char8_t * +sequence_point_block_get_type_name_func (void *object); + +static +void +stack_block_free_func (void *object); + +static +const ep_char8_t * +stack_block_get_type_name_func (void *object); + +static +void +stack_block_clear_func (void *object); + +static +uint32_t +stack_block_get_header_size_func (void *object); + +static +void +stack_block_serialize_header_func (void *object, FastSerializer *fast_serializer); + +/* + * EventPipeBlock + */ + +EventPipeBlock * +ep_block_init ( + EventPipeBlock *block, + EventPipeBlockVtable *vtable, + uint32_t max_block_size, + EventPipeSerializationFormat format) +{ + EP_ASSERT (block != NULL && vtable != NULL); + + ep_raise_error_if_nok (ep_fast_serializable_object_init ( + &block->fast_serializer_object, + (FastSerializableObjectVtable *)vtable, + ep_file_get_file_version (format), + ep_file_get_file_minimum_version (format), + format >= EP_SERIALIZATION_FORMAT_NETTRACE_V4) != NULL); + + block->block = ep_rt_byte_array_alloc (max_block_size); + ep_raise_error_if_nok (block->block != NULL); + + memset (block->block, 0, max_block_size); + block->write_pointer = block->block; + block->end_of_the_buffer = block->block + max_block_size; + block->format = format; + +ep_on_exit: + return block; + +ep_on_error: + block = NULL; + ep_exit_error_handler (); +} + +void +ep_block_fini (EventPipeBlock *block) +{ + ep_return_void_if_nok (block != NULL); + ep_rt_byte_array_free (block->block); +} + +void +ep_block_clear_vcall (EventPipeBlock *block) +{ + EP_ASSERT (block != NULL && block->fast_serializer_object.vtable != NULL); + EventPipeBlockVtable *vtable = (EventPipeBlockVtable *)block->fast_serializer_object.vtable; + + EP_ASSERT (vtable->clear_func != NULL); + vtable->clear_func (block); +} + +uint32_t +ep_block_get_header_size_vcall (EventPipeBlock *block) +{ + EP_ASSERT (block != NULL && block->fast_serializer_object.vtable != NULL); + EventPipeBlockVtable *vtable = (EventPipeBlockVtable *)block->fast_serializer_object.vtable; + + EP_ASSERT (vtable->get_header_size_func != NULL); + return vtable->get_header_size_func (block); +} + +void +ep_block_serialize_header_vcall ( + EventPipeBlock *block, + FastSerializer *fast_serializer) +{ + EP_ASSERT (block != NULL && block->fast_serializer_object.vtable != NULL); + EventPipeBlockVtable *vtable = (EventPipeBlockVtable *)block->fast_serializer_object.vtable; + + EP_ASSERT (vtable->serialize_header_func != NULL); + vtable->serialize_header_func (block, fast_serializer); +} + +void +ep_block_fast_serialize_vcall ( + EventPipeBlock *block, + FastSerializer *fast_serializer) +{ + EP_ASSERT (block != NULL); + ep_fast_serializable_object_fast_serialize_vcall (&block->fast_serializer_object, fast_serializer); +} + +/* + * EventPipeEventBlockBase + */ + +static +void +block_base_fast_serialize_func ( + void *object, + FastSerializer *fast_serializer) +{ + EP_ASSERT (object != NULL && fast_serializer != NULL); + ep_block_fast_serialize (&((EventPipeEventBlockBase *)object)->block, fast_serializer); +} + +static +void +block_base_clear_func (void *object) +{ + EP_ASSERT (object != NULL); + ep_event_block_base_clear ((EventPipeEventBlockBase *)object); +} + +static +void +block_base_serialize_header_func ( + void *object, + FastSerializer *fast_serializer) +{ + EP_ASSERT (object != NULL && fast_serializer != NULL); + ep_event_block_base_serialize_header ((EventPipeEventBlockBase *)object, fast_serializer); +} + +static +uint32_t +block_base_get_header_size_func (void *object) +{ + EP_ASSERT (object != NULL); + return ep_event_block_base_get_header_size ((EventPipeEventBlockBase *)object); +} + +EventPipeEventBlockBase * +ep_event_block_base_init ( + EventPipeEventBlockBase *event_block_base, + EventPipeBlockVtable *vtable, + uint32_t max_block_size, + EventPipeSerializationFormat format, + bool use_header_compression) +{ + EP_ASSERT (event_block_base != NULL && vtable != NULL); + + ep_raise_error_if_nok (ep_block_init ( + &event_block_base->block, + vtable, + max_block_size, + format) != NULL); + + event_block_base->use_header_compression = use_header_compression; + + memset (event_block_base->compressed_header, 0, EP_ARRAY_SIZE (event_block_base->compressed_header)); + ep_event_block_base_clear (event_block_base); + +ep_on_exit: + return event_block_base; + +ep_on_error: + event_block_base = NULL; + ep_exit_error_handler (); +} + +void +ep_event_block_base_fini (EventPipeEventBlockBase *event_block_base) +{ + ep_return_void_if_nok (event_block_base != NULL); + ep_block_fini (&event_block_base->block); +} + +/* + * EventPipeEventBlock + */ + +static +const ep_char8_t * +event_block_get_type_name_func (void *object) +{ + EP_ASSERT (object != NULL); + return "EventBlock"; +} + +static +void +event_block_free_func (void *object) +{ + ep_event_block_free ((EventPipeEventBlock *)object); +} + +static EventPipeBlockVtable event_block_vtable = { + { + event_block_free_func, + block_base_fast_serialize_func, + event_block_get_type_name_func }, + block_base_clear_func, + block_base_get_header_size_func, + block_base_serialize_header_func }; + +EventPipeEventBlock * +ep_event_block_alloc ( + uint32_t max_block_size, + EventPipeSerializationFormat format) +{ + EventPipeEventBlock *instance = ep_rt_object_alloc (EventPipeEventBlock); + ep_raise_error_if_nok (instance != NULL); + + ep_raise_error_if_nok (ep_event_block_base_init ( + &instance->event_block_base, + &event_block_vtable, + max_block_size, + format, + format >= EP_SERIALIZATION_FORMAT_NETTRACE_V4) != NULL); + +ep_on_exit: + return instance; + +ep_on_error: + ep_event_block_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_event_block_free (EventPipeEventBlock *event_block) +{ + ep_return_void_if_nok (event_block != NULL); + + ep_event_block_base_fini (&event_block->event_block_base); + ep_rt_object_free (event_block); +} + +/* + * EventPipeMetadataBlock + */ + +static +void +metadata_block_free_func (void *object) +{ + ep_metadata_block_free ((EventPipeMetadataBlock *)object); +} + +static +const ep_char8_t * +metadata_block_get_type_name_func (void *object) +{ + EP_ASSERT (object != NULL); + return "MetadataBlock"; +} + +static EventPipeBlockVtable metadata_block_vtable = { + { + metadata_block_free_func, + block_base_fast_serialize_func, + metadata_block_get_type_name_func }, + block_base_clear_func, + block_base_get_header_size_func, + block_base_serialize_header_func }; + +EventPipeMetadataBlock * +ep_metadata_block_alloc (uint32_t max_block_size) +{ + EventPipeMetadataBlock *instance = ep_rt_object_alloc (EventPipeMetadataBlock); + ep_raise_error_if_nok (instance != NULL); + + ep_raise_error_if_nok (ep_event_block_base_init ( + &instance->event_block_base, + &metadata_block_vtable, + max_block_size, + EP_SERIALIZATION_FORMAT_NETTRACE_V4, + true) != NULL); + +ep_on_exit: + return instance; + +ep_on_error: + ep_metadata_block_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_metadata_block_free (EventPipeMetadataBlock *metadata_block) +{ + ep_return_void_if_nok (metadata_block != NULL); + + ep_event_block_base_fini (&metadata_block->event_block_base); + ep_rt_object_free (metadata_block); +} + +/* + * EventPipeSequencePointBlock. + */ + +static +int32_t +sequence_point_get_block_size (EventPipeSequencePoint *sequence_point) +{ + EP_ASSERT (sequence_point != NULL); + + const uint32_t size_of_sequence_number = + sizeof (uint64_t) + //thread id + sizeof (uint32_t); //sequence number + + const uint32_t thread_count = ep_rt_thread_sequence_number_map_count (ep_sequence_point_get_thread_sequence_numbers_cref (sequence_point)); + + return sizeof (sequence_point->timestamp) + + sizeof (uint32_t) + //thread count + thread_count * size_of_sequence_number; +} + +static +void +sequence_point_block_free_func (void *object) +{ + ep_sequence_point_block_free ((EventPipeSequencePointBlock *)object); +} + +static +const ep_char8_t * +sequence_point_block_get_type_name_func (void *object) +{ + EP_ASSERT (object != NULL); + return "SPBlock"; +} + +static EventPipeBlockVtable sequence_point_block_vtable = { + { + sequence_point_block_free_func, + block_base_fast_serialize_func, + sequence_point_block_get_type_name_func }, + block_base_clear_func, + block_base_get_header_size_func, + block_base_serialize_header_func }; + +EventPipeSequencePointBlock * +ep_sequence_point_block_alloc (EventPipeSequencePoint *sequence_point) +{ + ep_return_null_if_nok (sequence_point != NULL); + + EventPipeSequencePointBlock *instance = ep_rt_object_alloc (EventPipeSequencePointBlock); + ep_raise_error_if_nok (instance != NULL); + + ep_raise_error_if_nok (ep_sequence_point_block_init (instance, sequence_point) != NULL); + +ep_on_exit: + return instance; + +ep_on_error: + ep_sequence_point_block_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +EventPipeSequencePointBlock * +ep_sequence_point_block_init ( + EventPipeSequencePointBlock *sequence_point_block, + EventPipeSequencePoint *sequence_point) +{ + EP_ASSERT (sequence_point_block != NULL); + ep_return_null_if_nok (sequence_point != NULL); + + ep_raise_error_if_nok (ep_event_block_base_init ( + &sequence_point_block->event_block_base, + &sequence_point_block_vtable, + sequence_point_get_block_size (sequence_point), + EP_SERIALIZATION_FORMAT_NETTRACE_V4, + true) != NULL); + + const int64_t timestamp = sequence_point->timestamp; + memcpy (sequence_point_block->event_block_base.block.write_pointer, ×tamp, sizeof (timestamp)); + sequence_point_block->event_block_base.block.write_pointer += sizeof (timestamp); + + const uint32_t thread_count = ep_rt_thread_sequence_number_map_count (ep_sequence_point_get_thread_sequence_numbers_cref (sequence_point)); + memcpy (sequence_point_block->event_block_base.block.write_pointer, &thread_count, sizeof (thread_count)); + sequence_point_block->event_block_base.block.write_pointer += sizeof (thread_count); + + ep_rt_thread_sequence_number_hash_map_iterator_t iterator; + for (ep_rt_thread_sequence_number_map_iterator_begin (&sequence_point->thread_sequence_numbers, &iterator); + !ep_rt_thread_sequence_number_map_iterator_end (&sequence_point->thread_sequence_numbers, &iterator); + ep_rt_thread_sequence_number_map_iterator_next (&sequence_point->thread_sequence_numbers, &iterator)) { + + const EventPipeThreadSessionState *key = ep_rt_thread_sequence_number_map_iterator_key (&iterator); + + const uint64_t thread_id = ep_thread_get_os_thread_id (ep_thread_session_state_get_thread (key)); + memcpy (sequence_point_block->event_block_base.block.write_pointer, &thread_id, sizeof (thread_id)); + sequence_point_block->event_block_base.block.write_pointer += sizeof (thread_id); + + const uint32_t sequence_number = ep_rt_thread_sequence_number_map_iterator_value (&iterator); + memcpy (sequence_point_block->event_block_base.block.write_pointer, &sequence_number, sizeof (sequence_number)); + sequence_point_block->event_block_base.block.write_pointer += sizeof (sequence_number); + } + +ep_on_exit: + return sequence_point_block; + +ep_on_error: + sequence_point_block = NULL; + ep_exit_error_handler (); +} + +void +ep_sequence_point_block_fini (EventPipeSequencePointBlock *sequence_point_block) +{ + ep_return_void_if_nok (sequence_point_block != NULL); + ep_event_block_base_fini (&sequence_point_block->event_block_base); +} + +void +ep_sequence_point_block_free (EventPipeSequencePointBlock *sequence_point_block) +{ + ep_return_void_if_nok (sequence_point_block != NULL); + + ep_sequence_point_block_fini (sequence_point_block); + ep_rt_object_free (sequence_point_block); +} + +/* + * EventPipeStackBlock. + */ + +static +void +stack_block_free_func (void *object) +{ + ep_stack_block_free ((EventPipeStackBlock *)object); +} + +static +const ep_char8_t * +stack_block_get_type_name_func (void *object) +{ + EP_ASSERT (object != NULL); + return "StackBlock"; +} + +static +void +stack_block_clear_func (void *object) +{ + EP_ASSERT (object != NULL); + + EventPipeStackBlock *stack_block = (EventPipeStackBlock *)object; + + stack_block->has_initial_index = false; + stack_block->has_initial_index = 0; + stack_block->count = 0; + + ep_block_clear (&stack_block->event_block_base.block); +} + +static +uint32_t +stack_block_get_header_size_func (void *object) +{ + EP_ASSERT (object != NULL); + return sizeof (uint32_t) + // start index + sizeof (uint32_t); // count of indices +} + +static +void +stack_block_serialize_header_func (void *object, FastSerializer *fast_serializer) +{ + EP_ASSERT (object != NULL && fast_serializer != NULL); + + EventPipeStackBlock *stack_block = (EventPipeStackBlock *)object; + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&stack_block->initial_index, sizeof (stack_block->initial_index)); + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&stack_block->count, sizeof (stack_block->count)); +} + +static EventPipeBlockVtable stack_block_vtable = { + { + stack_block_free_func, + block_base_fast_serialize_func, + stack_block_get_type_name_func }, + stack_block_clear_func, + stack_block_get_header_size_func, + stack_block_serialize_header_func }; + +EventPipeStackBlock * +ep_stack_block_alloc (uint32_t max_block_size) +{ + EventPipeStackBlock *instance = ep_rt_object_alloc (EventPipeStackBlock); + ep_raise_error_if_nok (instance != NULL); + + ep_raise_error_if_nok (ep_event_block_base_init ( + &instance->event_block_base, + &stack_block_vtable, + max_block_size, + EP_SERIALIZATION_FORMAT_NETTRACE_V4, + true) != NULL); + + stack_block_clear_func (instance); + +ep_on_exit: + return instance; + +ep_on_error: + ep_stack_block_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_stack_block_free (EventPipeStackBlock *stack_block) +{ + ep_return_void_if_nok (stack_block != NULL); + + ep_event_block_base_fini (&stack_block->event_block_base); + ep_rt_object_free (stack_block); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_block_internals; +const char quiet_linker_empty_file_warning_eventpipe_block_internals = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-block.c b/src/mono/mono/eventpipe/ep-block.c new file mode 100644 index 00000000000000..214d3817fa645c --- /dev/null +++ b/src/mono/mono/eventpipe/ep-block.c @@ -0,0 +1,398 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#include "ep.h" + +/* + * Forward declares of all static functions. + */ + +static +uint8_t * +event_block_base_write_var_uint32 ( + uint8_t * write_pointer, + uint32_t value); + +static +uint8_t * +event_block_base_write_var_uint64 ( + uint8_t * write_pointer, + uint64_t value); + +/* + * EventPipeBlock + */ + +void +ep_block_clear (EventPipeBlock *block) +{ + ep_return_void_if_nok (block != NULL); + ep_return_void_if_nok (ep_block_get_block (block) != NULL); + + EP_ASSERT (ep_block_get_write_pointer (block) <= ep_block_get_end_of_the_buffer (block)); + + memset (ep_block_get_block (block), 0, ep_block_get_end_of_the_buffer (block) - ep_block_get_block (block)); + ep_block_set_write_pointer (block, ep_block_get_block (block)); +} + +uint32_t +ep_block_get_header_size (EventPipeBlock *block) +{ + return 0; +} + +void +ep_block_serialize_header ( + EventPipeBlock *block, + FastSerializer *fast_serializer) +{ + ; +} + +void +ep_block_fast_serialize ( + EventPipeBlock *block, + FastSerializer *fast_serializer) +{ + ep_return_void_if_nok (block != NULL && fast_serializer != NULL && ep_block_get_block (block) != NULL); + + uint32_t data_size = ep_block_get_bytes_written (block); + EP_ASSERT (data_size != 0); + + uint32_t header_size = ep_block_get_header_size_vcall (block); + uint32_t total_size = data_size + header_size; + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&total_size, sizeof (total_size)); + + uint32_t required_padding = ep_fast_serializer_get_required_padding (fast_serializer); + if (required_padding != 0) { + uint8_t max_padding [FAST_SERIALIZER_ALIGNMENT_SIZE - 1] = { 0 }; // it's longest possible padding, we are going to use only part of it + + EP_ASSERT (required_padding <= FAST_SERIALIZER_ALIGNMENT_SIZE - 1); + ep_fast_serializer_write_buffer (fast_serializer, max_padding, required_padding); // we write zeros here, the reader is going to always read from the first aligned address of the serialized content + + EP_ASSERT (ep_fast_serializer_get_write_error_encountered (fast_serializer) || ep_fast_serializer_get_required_padding (fast_serializer)); + } + + ep_block_serialize_header_vcall (block, fast_serializer); + ep_fast_serializer_write_buffer (fast_serializer, ep_block_get_block (block), data_size); +} + +/* + * EventPipeEventBlockBase + */ + +static +uint8_t * +event_block_base_write_var_uint32 ( + uint8_t * write_pointer, + uint32_t value) +{ + while (value >= 0x80) { + *write_pointer = (uint8_t)(value | 0x80); + write_pointer++; + value >>= 7; + } + *write_pointer = (uint8_t)value; + write_pointer++; + return write_pointer; +} + +static +uint8_t * +event_block_base_write_var_uint64 ( + uint8_t * write_pointer, + uint64_t value) +{ + while (value >= 0x80) { + *write_pointer = (uint8_t)(value | 0x80); + write_pointer++; + value >>= 7; + } + *write_pointer = (uint8_t)value; + write_pointer++; + return write_pointer; +} + +void +ep_event_block_base_clear (EventPipeEventBlockBase *event_block_base) +{ + ep_return_void_if_nok (event_block_base != NULL); + + ep_block_clear (ep_event_block_base_get_block_ref (event_block_base)); + memset (ep_event_block_base_get_last_header_ref (event_block_base), 0, sizeof (EventPipeEventHeader)); + ep_event_block_base_set_min_timestamp (event_block_base, INT64_MAX); + ep_event_block_base_set_max_timestamp (event_block_base, INT64_MIN); +} + +uint32_t +ep_event_block_base_get_header_size (const EventPipeEventBlockBase *event_block_base) +{ + ep_return_zero_if_nok (event_block_base != NULL && ep_block_get_format ((EventPipeBlock *)event_block_base) != EP_SERIALIZATION_FORMAT_NETPERF_V3); + + return sizeof(uint16_t) + // header size + sizeof(uint16_t) + // flags + sizeof(int64_t) + // min timestamp + sizeof(int64_t); // max timestamp +} + +void +ep_event_block_base_serialize_header ( + EventPipeEventBlockBase *event_block_base, + FastSerializer *fast_serializer) +{ + ep_return_void_if_nok (event_block_base != NULL && ep_block_get_format ((EventPipeBlock *)event_block_base) != EP_SERIALIZATION_FORMAT_NETPERF_V3 && fast_serializer != NULL); + + const uint16_t header_size = (uint16_t)ep_block_get_header_size_vcall ((EventPipeBlock *)event_block_base); + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&header_size, sizeof (header_size)); + + const uint16_t flags = ep_event_block_base_get_use_header_compression (event_block_base) ? 1 : 0; + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&flags, sizeof (flags)); + + uint64_t min_timestamp = ep_event_block_base_get_min_timestamp (event_block_base); + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&min_timestamp, sizeof (min_timestamp)); + + uint64_t max_timestamp = ep_event_block_base_get_max_timestamp (event_block_base); + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&max_timestamp, sizeof (max_timestamp)); +} + +bool +ep_event_block_base_write_event ( + EventPipeEventBlockBase *event_block_base, + EventPipeEventInstance *event_instance, + uint64_t capture_thread_id, + uint32_t sequence_number, + int32_t stack_id, + bool is_sorted_event) +{ + ep_return_false_if_nok (event_block_base != NULL && event_instance != NULL); + + EventPipeBlock *block = ep_event_block_base_get_block_ref (event_block_base); + ep_raise_error_if_nok (ep_block_get_block (block) != NULL); + + uint32_t data_len = 0; + uint8_t * aligned_end = NULL; + uint32_t capture_proc_number = ep_event_instance_get_proc_num (event_instance); + uint8_t * write_pointer = ep_block_get_write_pointer (block); + + if (!ep_event_block_base_get_use_header_compression (event_block_base)) { + uint32_t total_size = ep_event_instance_get_aligned_total_size (event_instance, ep_block_get_format (block)); + ep_raise_error_if_nok (write_pointer + total_size < ep_block_get_end_of_the_buffer (block)); + + aligned_end = write_pointer + total_size + sizeof (total_size); + + memcpy (write_pointer, &total_size, sizeof (total_size)); + write_pointer += sizeof (total_size); + + uint32_t metadata_id = ep_event_instance_get_metadata_id (event_instance); + EP_ASSERT ((metadata_id & (1 << 31)) == 0); + + metadata_id |= (!is_sorted_event ? 1 << 31 : 0); + memcpy (write_pointer, &metadata_id, sizeof (metadata_id)); + write_pointer += sizeof (metadata_id); + + if (ep_block_get_format (block) == EP_SERIALIZATION_FORMAT_NETPERF_V3) { + int32_t thread_id = (int32_t)ep_event_instance_get_thread_id (event_instance); + memcpy (write_pointer, &thread_id, sizeof (thread_id)); + write_pointer += sizeof (thread_id); + } else if (ep_block_get_format (block) == EP_SERIALIZATION_FORMAT_NETTRACE_V4) { + memcpy (write_pointer, &sequence_number, sizeof (sequence_number)); + write_pointer += sizeof (sequence_number); + + uint64_t thread_id = ep_event_instance_get_thread_id (event_instance); + memcpy (write_pointer, &thread_id, sizeof (thread_id)); + write_pointer += sizeof (thread_id); + + memcpy (write_pointer, &capture_thread_id, sizeof (capture_thread_id)); + write_pointer += sizeof (capture_thread_id); + + memcpy (write_pointer, &capture_proc_number, sizeof (capture_proc_number)); + write_pointer += sizeof (capture_proc_number); + + memcpy (write_pointer, &stack_id, sizeof (stack_id)); + write_pointer += sizeof (stack_id); + } + + int64_t timestamp = ep_event_instance_get_timestamp (event_instance); + memcpy (write_pointer, ×tamp, sizeof (timestamp)); + write_pointer += sizeof (timestamp); + + const uint8_t *activity_id = ep_event_instance_get_activity_id_cref (event_instance); + memcpy (write_pointer, activity_id, EP_ACTIVITY_ID_SIZE); + write_pointer += EP_ACTIVITY_ID_SIZE; + + const uint8_t *relative_activity_id = ep_event_instance_get_related_activity_id_cref (event_instance); + memcpy (write_pointer, relative_activity_id, EP_ACTIVITY_ID_SIZE); + write_pointer += EP_ACTIVITY_ID_SIZE; + + data_len = ep_event_instance_get_data_len (event_instance); + memcpy (write_pointer, &data_len, sizeof (data_len)); + write_pointer += sizeof (data_len); + } else { // using header compression + uint8_t flags = 0; + uint8_t *header_write_pointer = ep_event_block_base_get_compressed_header_ref (event_block_base); + EventPipeEventHeader *last_header = ep_event_block_base_get_last_header_ref (event_block_base); + + if (ep_event_instance_get_metadata_id (event_instance) != last_header->metadata_id) { + header_write_pointer = event_block_base_write_var_uint32 (header_write_pointer, ep_event_instance_get_metadata_id (event_instance)); + flags |= 1; + } + + if (is_sorted_event) { + flags |= (1 << 6); + } + + if (last_header->sequence_number + (ep_event_instance_get_metadata_id (event_instance) != 0 ? 1 : 0) != sequence_number || + last_header->capture_thread_id != capture_thread_id || last_header->capture_proc_number != capture_proc_number) { + header_write_pointer = event_block_base_write_var_uint32 (header_write_pointer, sequence_number - last_header->sequence_number - 1); + header_write_pointer = event_block_base_write_var_uint32 (header_write_pointer, (uint32_t)capture_thread_id); + header_write_pointer = event_block_base_write_var_uint32 (header_write_pointer, capture_proc_number); + flags |= (1 << 1); + } + + if (last_header->thread_id != ep_event_instance_get_thread_id (event_instance)) { + header_write_pointer = event_block_base_write_var_uint64 (header_write_pointer, ep_event_instance_get_thread_id (event_instance)); + flags |= (1 << 2); + } + + if (last_header->stack_id != stack_id) { + header_write_pointer = event_block_base_write_var_uint32 (header_write_pointer, stack_id); + flags |= (1 << 3); + } + + int64_t timestamp = ep_event_instance_get_timestamp (event_instance); + header_write_pointer = event_block_base_write_var_uint64 (header_write_pointer, timestamp - last_header->timestamp); + + if (memcmp (&last_header->activity_id, ep_event_instance_get_activity_id_cref (event_instance), EP_ACTIVITY_ID_SIZE) != 0) { + memcpy (header_write_pointer, ep_event_instance_get_activity_id_cref (event_instance), EP_ACTIVITY_ID_SIZE ); + header_write_pointer += EP_ACTIVITY_ID_SIZE; + flags |= (1 << 4); + } + + if (memcmp (&last_header->related_activity_id, ep_event_instance_get_related_activity_id_cref (event_instance), EP_ACTIVITY_ID_SIZE) != 0) { + memcpy (header_write_pointer, ep_event_instance_get_related_activity_id_cref (event_instance), EP_ACTIVITY_ID_SIZE ); + header_write_pointer += EP_ACTIVITY_ID_SIZE; + flags |= (1 << 5); + } + + data_len = ep_event_instance_get_data_len (event_instance); + if (last_header->data_len != data_len) { + header_write_pointer = event_block_base_write_var_uint32 (header_write_pointer, data_len); + flags |= (1 << 7); + } + + uint32_t bytes_written = (uint32_t)(header_write_pointer - ep_event_block_base_get_compressed_header_cref (event_block_base)); + uint32_t total_size = 1 + bytes_written + data_len; + + if (write_pointer + total_size >= ep_block_get_end_of_the_buffer (block)) { + //TODO: Orignal EP updates blocks write pointer continiously, doing the same here before + //bailing out. Question is if that is intentional or just a side effect of directly updating + //the member. + ep_block_set_write_pointer (block, write_pointer); + ep_raise_error (); + } + + last_header->metadata_id = ep_event_instance_get_metadata_id (event_instance); + last_header->sequence_number = sequence_number; + last_header->thread_id = ep_event_instance_get_thread_id (event_instance); + last_header->capture_thread_id = capture_thread_id; + last_header->capture_proc_number = capture_proc_number; + last_header->stack_id = stack_id; + last_header->timestamp = timestamp; + memcpy (&last_header->activity_id, ep_event_instance_get_activity_id_cref (event_instance), EP_ACTIVITY_ID_SIZE); + memcpy (&last_header->related_activity_id, ep_event_instance_get_related_activity_id_cref (event_instance), EP_ACTIVITY_ID_SIZE); + last_header->data_len = data_len; + + aligned_end = write_pointer + total_size; + *write_pointer = flags; + write_pointer++; + memcpy (write_pointer, ep_event_block_base_get_compressed_header_cref (event_block_base), bytes_written); + write_pointer += bytes_written; + } + + if (data_len > 0) { + memcpy (write_pointer, ep_event_instance_get_data (event_instance), data_len); + write_pointer += data_len; + } + + if (ep_block_get_format (block) == EP_SERIALIZATION_FORMAT_NETPERF_V3) { + uint32_t stack_size = ep_stack_contents_get_size (ep_event_instance_get_stack_contents_ref (event_instance)); + memcpy (write_pointer, &stack_size, sizeof (stack_size)); + write_pointer += sizeof (stack_size); + + if (stack_size > 0) { + memcpy (write_pointer, ep_event_instance_get_stack_contents_ref (event_instance), stack_size); + write_pointer += stack_size; + } + } + + while (write_pointer < aligned_end) + *write_pointer++ = (uint8_t)0; // put padding at the end to get 4 bytes alignment of the payload + + EP_ASSERT (write_pointer == aligned_end); + + int64_t instance_timestamp = ep_event_instance_get_timestamp (event_instance); + if (ep_event_block_base_get_min_timestamp (event_block_base) > instance_timestamp) + ep_event_block_base_set_min_timestamp (event_block_base, instance_timestamp); + if (ep_event_block_base_get_max_timestamp (event_block_base) > instance_timestamp) + ep_event_block_base_set_max_timestamp (event_block_base, instance_timestamp); + + ep_block_set_write_pointer (block, write_pointer); + return true; + +ep_on_error: + return false; +} + +/* + * EventPipeStackBlock. + */ + +bool +ep_stack_block_write_stack ( + EventPipeStackBlock *stack_block, + int32_t stack_id, + EventPipeStackContents *stack) +{ + ep_return_false_if_nok (stack_block != NULL); + + EventPipeBlock *block = ep_event_block_base_get_block_ref (ep_stack_block_get_event_block_base_ref (stack_block)); + ep_raise_error_if_nok (block != NULL && ep_block_get_block (block) != NULL); + + uint32_t stack_size = ep_stack_contents_get_size (stack); + uint32_t total_size = sizeof (stack_size) + stack_size; + uint8_t *write_pointer = ep_block_get_write_pointer (block); + + ep_raise_error_if_nok (write_pointer + total_size < ep_block_get_end_of_the_buffer (block)); + + if (!ep_stack_block_get_has_initial_index (stack_block)) { + ep_stack_block_set_has_initial_index (stack_block, true); + ep_stack_block_set_initial_index (stack_block, stack_id); + } + + ep_stack_block_set_count (stack_block, ep_stack_block_get_count (stack_block) + 1); + + memcpy (write_pointer, &stack_size, sizeof (stack_size)); + write_pointer += sizeof (stack_size); + + if (stack_size > 0) { + memcpy (write_pointer, ep_stack_contents_get_pointer (stack), stack_size); + write_pointer += stack_size; + } + + ep_block_set_write_pointer (block, write_pointer); + return true; + +ep_on_error: + return false; +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_block; +const char quiet_linker_empty_file_warning_eventpipe_block = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-block.h b/src/mono/mono/eventpipe/ep-block.h new file mode 100644 index 00000000000000..f114cfd4eabba1 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-block.h @@ -0,0 +1,375 @@ +#ifndef __EVENTPIPE_BLOCK_H__ +#define __EVENTPIPE_BLOCK_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +/* + * EventPipeBlock + */ + +typedef void (*EventPipeBlockClearFunc)(void *object); +typedef uint32_t (*EventPipeBlockGetHeaderSizeFunc)(void *object); +typedef void (*EventPipeBlockSerializeHeaderFunc)(void *object, FastSerializer *fast_serializer); + +struct _EventPipeBlockVtable { + FastSerializableObjectVtable fast_serializable_object_vtable; + EventPipeBlockClearFunc clear_func; + EventPipeBlockGetHeaderSizeFunc get_header_size_func; + EventPipeBlockSerializeHeaderFunc serialize_header_func; +}; + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeBlock { +#else +struct _EventPipeBlock_Internal { +#endif + FastSerializableObject fast_serializer_object; + uint8_t *block; + uint8_t *write_pointer; + uint8_t *end_of_the_buffer; + EventPipeSerializationFormat format; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeBlock { + uint8_t _internal [sizeof (struct _EventPipeBlock_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventPipeBlock *, block, uint8_t*, block) +EP_DEFINE_GETTER(EventPipeBlock *, block, uint8_t*, write_pointer) +EP_DEFINE_SETTER(EventPipeBlock *, block, uint8_t*, write_pointer) +EP_DEFINE_GETTER(EventPipeBlock *, block, uint8_t*, end_of_the_buffer) +EP_DEFINE_GETTER(EventPipeBlock *, block, EventPipeSerializationFormat, format) + +static +inline +uint32_t +ep_block_get_bytes_written (const EventPipeBlock *block) +{ + return block == NULL ? 0 : (uint32_t)(ep_block_get_write_pointer (block) - ep_block_get_block (block)); +} + +EventPipeBlock * +ep_block_init ( + EventPipeBlock *block, + EventPipeBlockVtable *vtable, + uint32_t max_block_size, + EventPipeSerializationFormat format); + +void +ep_block_fini (EventPipeBlock *block); + +void +ep_block_clear (EventPipeBlock *block); + +uint32_t +ep_block_get_header_size (EventPipeBlock *block); + +void +ep_block_serialize_header ( + EventPipeBlock *block, + FastSerializer *fast_serializer); + +void +ep_block_fast_serialize ( + EventPipeBlock *block, + FastSerializer *fast_serializer); + +void +ep_block_clear_vcall (EventPipeBlock *block); + +uint32_t +ep_block_get_header_size_vcall (EventPipeBlock *block); + +void +ep_block_serialize_header_vcall ( + EventPipeBlock *block, + FastSerializer *fast_serializer); + +void +ep_block_fast_serialize_vcall ( + EventPipeBlock *block, + FastSerializer *fast_serializer); + +/* + * EventPipeEventHeader. + */ + +struct _EventPipeEventHeader { + int32_t metadata_id; + int32_t sequence_number; + uint64_t thread_id; + uint64_t capture_thread_id; + int32_t capture_proc_number; + int32_t stack_id; + uint64_t timestamp; + uint8_t activity_id [EP_ACTIVITY_ID_SIZE]; + uint8_t related_activity_id [EP_ACTIVITY_ID_SIZE]; + int32_t data_len; +}; + +/* + * EventPipeEventBlockBase + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeEventBlockBase { +#else +struct _EventPipeEventBlockBase_Internal { +#endif + EventPipeBlock block; + EventPipeEventHeader last_header; + uint8_t compressed_header [100]; + bool use_header_compression; + uint64_t min_timestamp; + uint64_t max_timestamp; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeEventBlockBase { + uint8_t _internal [sizeof (struct _EventPipeEventBlockBase_Internal)]; +}; +#endif + +EP_DEFINE_GETTER_REF(EventPipeEventBlockBase *, event_block_base, EventPipeBlock *, block) +EP_DEFINE_GETTER_REF(EventPipeEventBlockBase *, event_block_base, EventPipeEventHeader *, last_header) +EP_DEFINE_GETTER(EventPipeEventBlockBase *, event_block_base, bool, use_header_compression) +EP_DEFINE_GETTER_ARRAY_REF(EventPipeEventBlockBase *, event_block_base, uint8_t *, const uint8_t *, compressed_header, compressed_header[0]) +EP_DEFINE_GETTER(EventPipeEventBlockBase *, event_block_base, uint64_t, min_timestamp) +EP_DEFINE_SETTER(EventPipeEventBlockBase *, event_block_base, uint64_t, min_timestamp) +EP_DEFINE_GETTER(EventPipeEventBlockBase *, event_block_base, uint64_t, max_timestamp) +EP_DEFINE_SETTER(EventPipeEventBlockBase *, event_block_base, uint64_t, max_timestamp) + +EventPipeEventBlockBase * +ep_event_block_base_init ( + EventPipeEventBlockBase *event_block_base, + EventPipeBlockVtable *vtable, + uint32_t max_block_size, + EventPipeSerializationFormat format, + bool use_header_compression); + +void +ep_event_block_base_fini (EventPipeEventBlockBase *event_block_base); + +void +ep_event_block_base_clear (EventPipeEventBlockBase *event_block_base); + +uint32_t +ep_event_block_base_get_header_size (const EventPipeEventBlockBase *event_block_base); + +void +ep_event_block_base_serialize_header ( + EventPipeEventBlockBase *event_block_base, + FastSerializer *fast_serializer); + +bool +ep_event_block_base_write_event ( + EventPipeEventBlockBase *event_block_base, + EventPipeEventInstance *event_instance, + uint64_t capture_thread_id, + uint32_t sequence_number, + int32_t stack_id, + bool is_sorted_event); + +/* + * EventPipeEventBlock. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeEventBlock { +#else +struct _EventPipeEventBlock_Internal { +#endif + EventPipeEventBlockBase event_block_base; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeEventBlock { + uint8_t _internal [sizeof (struct _EventPipeEventBlock_Internal)]; +}; +#endif + +EventPipeEventBlock * +ep_event_block_alloc ( + uint32_t max_block_size, + EventPipeSerializationFormat format); + +void +ep_event_block_free (EventPipeEventBlock *event_block); + +static +inline +uint32_t +ep_event_block_get_bytes_written (EventPipeEventBlock *event_block) +{ + return ep_block_get_bytes_written ((const EventPipeBlock *)event_block); +} + +static +inline +void +ep_event_block_serialize (EventPipeEventBlock *event_block, FastSerializer *fast_serializer) +{ + ep_fast_serializer_write_object (fast_serializer, (FastSerializableObject*)event_block); +} + +static +inline +void +ep_event_block_clear (EventPipeEventBlock *event_block) +{ + ep_block_clear_vcall ((EventPipeBlock *)event_block); +} + +/* + * EventPipeMetadataBlock. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeMetadataBlock { +#else +struct _EventPipeMetadataBlock_Internal { +#endif + EventPipeEventBlockBase event_block_base; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeMetadataBlock { + uint8_t _internal [sizeof (struct _EventPipeMetadataBlock_Internal)]; +}; +#endif + +EventPipeMetadataBlock * +ep_metadata_block_alloc (uint32_t max_block_size); + +void +ep_metadata_block_free (EventPipeMetadataBlock *metadata_block); + +static +inline +uint32_t +ep_metadata_block_get_bytes_written (EventPipeMetadataBlock *metadata_block) +{ + return ep_block_get_bytes_written ((const EventPipeBlock *)metadata_block); +} + +static +inline +void +ep_metadata_block_serialize (EventPipeMetadataBlock *metadata_block, FastSerializer *fast_serializer) +{ + ep_fast_serializer_write_object (fast_serializer, (FastSerializableObject *)metadata_block); +} + +static +inline +void +ep_metadata_block_clear (EventPipeMetadataBlock *metadata_block) +{ + ep_block_clear_vcall ((EventPipeBlock *)metadata_block); +} + +/* + * EventPipeSequencePointBlock. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeSequencePointBlock { +#else +struct _EventPipeSequencePointBlock_Internal { +#endif + EventPipeEventBlockBase event_block_base; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeSequencePointBlock { + uint8_t _internal [sizeof (struct _EventPipeSequencePointBlock_Internal)]; +}; +#endif + +EventPipeSequencePointBlock * +ep_sequence_point_block_alloc (EventPipeSequencePoint *sequence_point); + +EventPipeSequencePointBlock * +ep_sequence_point_block_init ( + EventPipeSequencePointBlock *sequence_point_block, + EventPipeSequencePoint *sequence_point); + +void +ep_sequence_point_block_fini (EventPipeSequencePointBlock *sequence_point_block); + +void +ep_sequence_point_block_free (EventPipeSequencePointBlock *sequence_point_block); + +/* + * EventPipeStackBlock. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeStackBlock { +#else +struct _EventPipeStackBlock_Internal { +#endif + EventPipeEventBlockBase event_block_base; + uint32_t initial_index; + uint32_t count; + bool has_initial_index; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeStackBlock { + uint8_t _internal [sizeof (struct _EventPipeStackBlock_Internal)]; +}; +#endif + +EP_DEFINE_GETTER_REF(EventPipeStackBlock *, stack_block, EventPipeEventBlockBase *, event_block_base) +EP_DEFINE_GETTER(EventPipeStackBlock *, stack_block, uint32_t, initial_index) +EP_DEFINE_SETTER(EventPipeStackBlock *, stack_block, uint32_t, initial_index) +EP_DEFINE_GETTER(EventPipeStackBlock *, stack_block, uint32_t, count) +EP_DEFINE_SETTER(EventPipeStackBlock *, stack_block, uint32_t, count) +EP_DEFINE_GETTER(EventPipeStackBlock *, stack_block, bool, has_initial_index) +EP_DEFINE_SETTER(EventPipeStackBlock *, stack_block, bool, has_initial_index) + +EventPipeStackBlock * +ep_stack_block_alloc (uint32_t max_block_size); + +void +ep_stack_block_free (EventPipeStackBlock *stack_block); + +bool +ep_stack_block_write_stack ( + EventPipeStackBlock *stack_block, + int32_t stack_id, + EventPipeStackContents *stack); + +static +inline +uint32_t +ep_stack_block_get_bytes_written (EventPipeStackBlock *stack_block) +{ + return ep_block_get_bytes_written ((const EventPipeBlock *)stack_block); +} + +static +inline +void +ep_stack_block_serialize (EventPipeStackBlock *stack_block, FastSerializer *fast_serializer) +{ + ep_fast_serializer_write_object (fast_serializer, (FastSerializableObject *)stack_block); +} + +static +inline +void +ep_stack_block_clear (EventPipeStackBlock *stack_block) +{ + ep_block_clear_vcall ((EventPipeBlock *)stack_block); +} + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_BLOCK_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-buffer-manager-internals.c b/src/mono/mono/eventpipe/ep-buffer-manager-internals.c new file mode 100644 index 00000000000000..aabec9ad60379d --- /dev/null +++ b/src/mono/mono/eventpipe/ep-buffer-manager-internals.c @@ -0,0 +1,38 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#define EP_IMPL_GETTER_SETTER +#include "ep.h" + +/* + * EventPipeBufferManager. + */ + +EventPipeBufferManager * +ep_buffer_manager_alloc ( + EventPipeSession *session, + size_t max_size_of_all_buffers, + size_t sequence_point_allocation_budget) +{ + //TODO: Implement. + return ep_rt_object_alloc (EventPipeBufferManager); +} + +void +ep_buffer_manager_free (EventPipeBufferManager * buffer_manager) +{ + //TODO: Implement. + ep_return_void_if_nok (buffer_manager != NULL); + ep_rt_object_free (buffer_manager); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_buffer_manager_internals; +const char quiet_linker_empty_file_warning_eventpipe_buffer_manager_internals = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-buffer-manager.c b/src/mono/mono/eventpipe/ep-buffer-manager.c new file mode 100644 index 00000000000000..3e151790d6afbb --- /dev/null +++ b/src/mono/mono/eventpipe/ep-buffer-manager.c @@ -0,0 +1,28 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#include "ep.h" + +/* + * EventPipeBufferManager. + */ + +#ifdef EP_CHECKED_BUILD +void +ep_buffer_manager_requires_lock_held (const EventPipeBufferManager *buffer_manager) +{ + EP_ASSERT (buffer_manager != NULL); + ep_rt_spin_lock_requires_lock_held (ep_buffer_manager_get_rt_lock_cref (buffer_manager)); +} +#endif + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_buffer_manager; +const char quiet_linker_empty_file_warning_eventpipe_buffer_manager = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-buffer-manager.h b/src/mono/mono/eventpipe/ep-buffer-manager.h new file mode 100644 index 00000000000000..2676114076bf43 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-buffer-manager.h @@ -0,0 +1,69 @@ +#ifndef __EVENTPIPE_BUFFERMANAGER_H__ +#define __EVENTPIPE_BUFFERMANAGER_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +/* + * EventPipeBufferList. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +//TODO: Implement. +struct _EventPipeBufferList { +#else +struct _EventPipeBufferList_Internal { +#endif + uint8_t x; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeBufferList { + uint8_t _internal [sizeof (struct _EventPipeBufferList_Internal)]; +}; +#endif + +/* + * EventPipeBufferManager. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +//TODO: Implement. +struct _EventPipeBufferManager { +#else +struct _EventPipeBufferManager_Internal { +#endif + ep_rt_wait_event_handle_t rt_wait_event; + ep_rt_spin_lock_handle_t rt_lock; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeBufferManager { + uint8_t _internal [sizeof (struct _EventPipeBufferManager_Internal)]; +}; +#endif + +EP_DEFINE_GETTER_REF(EventPipeBufferManager *, buffer_manager, ep_rt_wait_event_handle_t *, rt_wait_event) +EP_DEFINE_GETTER_REF(EventPipeBufferManager *, buffer_manager, ep_rt_spin_lock_handle_t *, rt_lock); + +EventPipeBufferManager * +ep_buffer_manager_alloc ( + EventPipeSession *session, + size_t max_size_of_all_buffers, + size_t sequence_point_allocation_budget); + +void +ep_buffer_manager_free (EventPipeBufferManager *buffer_manager); + +#ifdef EP_CHECKED_BUILD +void +ep_buffer_manager_requires_lock_held (const EventPipeBufferManager *buffer_manager); +#else +#define ep_buffer_manager_requires_lock_held(x) +#endif + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_BUFFERMANAGER_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-buffer.h b/src/mono/mono/eventpipe/ep-buffer.h new file mode 100644 index 00000000000000..cfc5f66c3e1937 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-buffer.h @@ -0,0 +1,40 @@ +#ifndef __EVENTPIPE_BUFFER_H__ +#define __EVENTPIPE_BUFFER_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +/* + * EventPipeBuffer. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +//TODO: Implement. +struct _EventPipeBuffer { +#else +struct _EventPipeBuffer_Internal { +#endif + volatile uint32_t state; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeBuffer { + uint8_t _internal [sizeof (struct _EventPipeBuffer_Internal)]; +}; +#endif + +EP_DEFINE_GETTER_REF(EventPipeBuffer *, buffer, volatile uint32_t *, state) + +static +inline +void +ep_buffer_convert_to_read_only (EventPipeBuffer *buffer) +{ + //TODO: Implement. +} + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_BUFFER_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-config-internals.c b/src/mono/mono/eventpipe/ep-config-internals.c new file mode 100644 index 00000000000000..a26d76a7c0ac99 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-config-internals.c @@ -0,0 +1,68 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#define EP_IMPL_GETTER_SETTER +#include "ep.h" + +EventPipeConfiguration _ep_config = { { 0 }, 0 }; + +/* + * EventPipeEventMetadataEvent. + */ + +EventPipeEventMetadataEvent * +ep_event_metdata_event_alloc ( + EventPipeEvent *ep_event, + uint32_t proc_num, + uint64_t thread_id, + uint8_t *data, + uint32_t data_len, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + EventPipeEventMetadataEvent *instance = ep_rt_object_alloc (EventPipeEventMetadataEvent); + ep_raise_error_if_nok (instance != NULL); + + ep_raise_error_if_nok (ep_event_instance_init ( + &instance->event_instance, + ep_event, + proc_num, + thread_id, + data, + data_len, + activity_id, + related_activity_id) != NULL); + + instance->payload_buffer = data; + instance->payload_buffer_len = data_len; + +ep_on_exit: + return instance; + +ep_on_error: + ep_event_metdata_event_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_event_metdata_event_free (EventPipeEventMetadataEvent *metadata_event) +{ + ep_return_void_if_nok (metadata_event != NULL); + + ep_event_instance_fini (&metadata_event->event_instance); + ep_rt_byte_array_free (metadata_event->payload_buffer); + ep_rt_object_free (metadata_event); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_configuration_internals; +const char quiet_linker_empty_file_warning_eventpipe_configuration_internals = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-config.c b/src/mono/mono/eventpipe/ep-config.c new file mode 100644 index 00000000000000..24b6461adfed00 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-config.c @@ -0,0 +1,553 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#include "ep.h" + +/* + * Forward declares of all static functions. + */ + +static +void +config_compute_keyword_and_level_lock_held ( + const EventPipeConfiguration *config, + const EventPipeProvider *provider, + int64_t *keyword_for_all_sessions, + EventPipeEventLevel *level_for_all_sessions); + +static +bool +config_register_provider_lock_held ( + EventPipeConfiguration *config, + EventPipeProvider *provider, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue); + +static +bool +config_unregister_provider_lock_held ( + EventPipeConfiguration *config, + EventPipeProvider *provider); + +/* + * EventPipeConfiguration. + */ + +static +void +config_compute_keyword_and_level_lock_held ( + const EventPipeConfiguration *config, + const EventPipeProvider *provider, + int64_t *keyword_for_all_sessions, + EventPipeEventLevel *level_for_all_sessions) +{ + ep_rt_config_requires_lock_held (); + EP_ASSERT (provider != NULL); + EP_ASSERT (keyword_for_all_sessions != NULL); + EP_ASSERT (level_for_all_sessions != NULL); + + *keyword_for_all_sessions = 0; + *level_for_all_sessions = EP_EVENT_LEVEL_LOG_ALWAYS; + + for (int i = 0; i < EP_MAX_NUMBER_OF_SESSIONS; i++) { + // Entering EventPipe lock gave us a barrier, we don't need more of them. + EventPipeSession *session = ep_volatile_load_session_without_barrier (i); + if (session) { + EventPipeSessionProviderList *providers = ep_session_get_providers (session); + EP_ASSERT (providers != NULL); + + EventPipeSessionProvider *session_provider = ep_rt_session_provider_list_find_by_name (ep_session_provider_list_get_providers_cref (providers), ep_provider_get_provider_name (provider)); + if (session_provider) { + *keyword_for_all_sessions = *keyword_for_all_sessions | ep_session_provider_get_keywords (session_provider); + *level_for_all_sessions = (ep_session_provider_get_logging_level (session_provider) > *level_for_all_sessions) ? ep_session_provider_get_logging_level (session_provider) : *level_for_all_sessions; + } + } + } + + ep_rt_config_requires_lock_held (); + return; +} + +static +bool +config_register_provider_lock_held ( + EventPipeConfiguration *config, + EventPipeProvider *provider, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue) +{ + ep_rt_config_requires_lock_held (); + EP_ASSERT (config != NULL); + EP_ASSERT (provider != NULL); + + // See if we've already registered this provider. + EventPipeProvider *existing_provider = ep_config_get_provider_lock_held (config, ep_provider_get_provider_name (provider)); + if (existing_provider) + return false; + + // The provider has not been registered, so register it. + ep_rt_provider_list_append (ep_config_get_provider_list_ref (config), provider); + + int64_t keyword_for_all_sessions; + EventPipeEventLevel level_for_all_sessions; + config_compute_keyword_and_level_lock_held (config, provider, &keyword_for_all_sessions, &level_for_all_sessions); + + for (int i = 0; i < EP_MAX_NUMBER_OF_SESSIONS; i++) { + // Entering EventPipe lock gave us a barrier, we don't need more of them. + EventPipeSession *session = ep_volatile_load_session_without_barrier (i); + if (session) { + EventPipeSessionProviderList *providers = ep_session_get_providers (session); + EP_ASSERT (providers != NULL); + + EventPipeSessionProvider *session_provider = ep_rt_session_provider_list_find_by_name (ep_session_provider_list_get_providers_cref (providers), ep_provider_get_provider_name (provider)); + if (session_provider) { + EventPipeProviderCallbackData provider_callback_data; + ep_provider_set_config_lock_held ( + provider, + keyword_for_all_sessions, + level_for_all_sessions, + ((uint64_t)1 << ep_session_get_index (session)), + ep_session_provider_get_keywords (session_provider), + ep_session_provider_get_logging_level (session_provider), + ep_session_provider_get_filter_data (session_provider), + &provider_callback_data); + ep_provider_callback_data_queue_enqueue (provider_callback_data_queue, &provider_callback_data); + } + } + } + + ep_rt_config_requires_lock_held (); + return true; +} + +static +bool +config_unregister_provider_lock_held ( + EventPipeConfiguration *config, + EventPipeProvider *provider) +{ + ep_rt_config_requires_lock_held (); + EP_ASSERT (config != NULL); + + EventPipeProvider *existing_provider = NULL; + ep_rt_provider_list_t *provider_list = ep_config_get_provider_list_ref (config); + + // The provider list should be non-NULL, but can be NULL on shutdown. + if (!ep_rt_provider_list_is_empty (provider_list)) { + // If we found the provider, remove it. + if (ep_rt_provider_list_find (provider_list, provider, &existing_provider)) + ep_rt_provider_list_remove (provider_list, existing_provider); + } + + ep_rt_config_requires_lock_held (); + return (existing_provider != NULL); +} + +EventPipeConfiguration * +ep_config_init (EventPipeConfiguration *config) +{ + ep_rt_config_requires_lock_not_held (); + + ep_return_false_if_nok (config != NULL); + + ep_config_set_config_provider (config, ep_create_provider (ep_config_get_default_provider_name_utf8 (), NULL, NULL)); + ep_raise_error_if_nok (ep_config_get_config_provider (config) != NULL); + + // Create the metadata event. + ep_config_set_metadata_event (config, ep_provider_add_event ( + ep_config_get_config_provider (config), + 0, /* event_id */ + 0, /* keywords */ + 0, /* event_version */ + EP_EVENT_LEVEL_LOG_ALWAYS, + false, /* need_stack */ + NULL, /* meatadata */ + 0)); /* metadata_len */ + ep_raise_error_if_nok (ep_config_get_metadata_event (config) != NULL); + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return config; + +ep_on_error: + ep_config_shutdown (config); + + config = NULL; + ep_exit_error_handler (); +} + +void +ep_config_shutdown (EventPipeConfiguration *config) +{ + ep_rt_config_requires_lock_not_held (); + + ep_event_free (ep_config_get_metadata_event (config)); + ep_config_set_metadata_event (config, NULL); + + ep_delete_provider (ep_config_get_config_provider (config)); + ep_config_set_config_provider (config, NULL); + + // Take the lock before manipulating the list. + EP_CONFIG_LOCK_ENTER + // We don't delete provider itself because it can be in-use + ep_rt_provider_list_free (ep_config_get_provider_list_ref (config), NULL); + EP_CONFIG_LOCK_EXIT + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return; + +ep_on_error: + ep_exit_error_handler (); +} + +EventPipeProvider * +ep_config_create_provider ( + EventPipeConfiguration *config, + const ep_char8_t *provider_name, + EventPipeCallback callback_func, + void *callback_data, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue) +{ + ep_rt_config_requires_lock_not_held (); + + ep_return_null_if_nok (config != NULL && provider_name != NULL); + + EventPipeProvider *provider = NULL; + EP_CONFIG_LOCK_ENTER + provider = ep_config_create_provider_lock_held (config, provider_name, callback_func, callback_data, provider_callback_data_queue); + ep_raise_error_if_nok_holding_lock (provider != NULL); + EP_CONFIG_LOCK_EXIT + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return provider; + +ep_on_error: + ep_config_delete_provider (config, provider); + + provider = NULL; + ep_exit_error_handler (); +} + +void +ep_config_delete_provider ( + EventPipeConfiguration *config, + EventPipeProvider *provider) +{ + ep_rt_config_requires_lock_not_held (); + + ep_return_void_if_nok (config != NULL && provider != NULL); + + EP_CONFIG_LOCK_ENTER + ep_config_delete_provider_lock_held (config, provider); + EP_CONFIG_LOCK_EXIT + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return; + +ep_on_error: + ep_exit_error_handler (); +} + +void +ep_config_enable ( + EventPipeConfiguration *config, + const EventPipeSession *session, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue) +{ + ep_rt_config_requires_lock_not_held (); + + ep_return_void_if_nok (config != NULL && session != NULL); + + EP_CONFIG_LOCK_ENTER + ep_config_enable_disable_lock_held (config, session, provider_callback_data_queue, true); + EP_CONFIG_LOCK_EXIT + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return; + +ep_on_error: + ep_exit_error_handler (); +} + +void +ep_config_disable ( + EventPipeConfiguration *config, + const EventPipeSession *session, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue) +{ + ep_rt_config_requires_lock_not_held (); + + ep_return_void_if_nok (config != NULL && session != NULL); + + EP_CONFIG_LOCK_ENTER + ep_config_enable_disable_lock_held (config, session, provider_callback_data_queue, false); + EP_CONFIG_LOCK_EXIT + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return; + +ep_on_error: + ep_exit_error_handler (); +} + +EventPipeEventMetadataEvent * +ep_config_build_event_metadata_event ( + EventPipeConfiguration *config, + const EventPipeEventInstance *source_instance, + uint32_t metadata_id) +{ + ep_return_null_if_nok (config != NULL && source_instance != NULL); + + // The payload of the event should contain: + // - Metadata ID + // - GUID ProviderID. + // - Optional event description payload. + + uint8_t *instance_payload = NULL; + + // Calculate the size of the event. + EventPipeEvent *source_event = ep_event_instance_get_ep_event (source_instance); + EventPipeProvider *provider = ep_event_get_provider (source_event); + const ep_char16_t *provider_name_utf16 = ep_provider_get_provider_name_utf16 (provider); + const uint8_t *payload_data = ep_event_instance_get_data (source_instance); + uint32_t payload_data_len = ep_event_instance_get_data_len (source_instance); + uint32_t provider_name_len = (ep_rt_utf16_string_len (provider_name_utf16) + 1) * sizeof (ep_char16_t); + uint32_t instance_payload_size = sizeof (metadata_id) + provider_name_len + payload_data_len; + + // Allocate the payload. + instance_payload = ep_rt_byte_array_alloc (instance_payload_size); + ep_raise_error_if_nok (instance_payload != NULL); + + // Fill the buffer with the payload. + uint8_t *current = instance_payload; + + memcpy(current, &metadata_id, sizeof(metadata_id)); + current += sizeof(metadata_id); + + memcpy(current, provider_name_utf16, provider_name_len); + current += provider_name_len; + + // Write the incoming payload data. + memcpy(current, payload_data, payload_data_len); + + // Construct the metadata event instance. + EventPipeEventMetadataEvent *instance = ep_event_metdata_event_alloc ( + ep_config_get_metadata_event (config), + ep_rt_current_processor_get_number (), + ep_rt_current_thread_get_id (), + instance_payload, + instance_payload_size, + NULL /* pActivityId */, + NULL /* pRelatedActivityId */); + + ep_raise_error_if_nok (instance != NULL); + instance_payload = NULL; + + EP_ASSERT (ep_event_get_need_stack (ep_config_get_metadata_event (config)) == false); + + // Set the timestamp to match the source event, because the metadata event + // will be emitted right before the source event. + ep_event_instance_set_timestamp ((EventPipeEventInstance *)instance, ep_event_instance_get_timestamp (source_instance)); + +ep_on_exit: + return instance; + +ep_on_error: + ep_rt_byte_array_free (instance_payload); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_config_delete_deferred_providers (EventPipeConfiguration *config) +{ + ep_rt_config_requires_lock_not_held (); + + ep_return_void_if_nok (config != NULL); + + EP_CONFIG_LOCK_ENTER + ep_config_delete_deferred_providers_lock_held (config); + EP_CONFIG_LOCK_EXIT + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return; + +ep_on_error: + ep_exit_error_handler (); +} + +EventPipeSessionProvider * +ep_config_get_session_provider_lock_held ( + const EventPipeConfiguration *config, + const EventPipeSession *session, + const EventPipeProvider *provider) +{ + ep_rt_config_requires_lock_held (); + + ep_return_null_if_nok (config != NULL && session != NULL); + + EventPipeSessionProvider *existing_provider = ep_session_get_session_provider_lock_held (session, provider); + + ep_rt_config_requires_lock_held (); + return existing_provider; +} + +EventPipeProvider * +ep_config_get_provider_lock_held ( + EventPipeConfiguration *config, + const ep_char8_t *name) +{ + ep_rt_config_requires_lock_held (); + + ep_return_null_if_nok (config != NULL && name != NULL); + + // The provider list should be non-NULL, but can be NULL on shutdown. + ep_return_null_if_nok (ep_rt_provider_list_is_empty (ep_config_get_provider_list_cref (config)) != true); + EventPipeProvider *provider = ep_rt_provider_list_find_by_name (ep_config_get_provider_list_cref (config), name); + + ep_rt_config_requires_lock_held (); + return provider; +} + +EventPipeProvider * +ep_config_create_provider_lock_held ( + EventPipeConfiguration *config, + const ep_char8_t *provider_name, + EventPipeCallback callback_func, + void *callback_data, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue) +{ + ep_rt_config_requires_lock_held (); + + ep_return_null_if_nok (config != NULL && provider_name != NULL); + + EventPipeProvider *provider = ep_provider_alloc (config, provider_name, callback_func, callback_data); + ep_raise_error_if_nok (provider != NULL); + ep_raise_error_if_nok (config_register_provider_lock_held (config, provider, provider_callback_data_queue) == true); + +ep_on_exit: + ep_rt_config_requires_lock_held (); + return provider; + +ep_on_error: + ep_config_delete_provider_lock_held (config, provider); + + provider = NULL; + ep_exit_error_handler (); +} + +void +ep_config_delete_provider_lock_held ( + EventPipeConfiguration *config, + EventPipeProvider *provider) +{ + ep_rt_config_requires_lock_held (); + + ep_return_void_if_nok (config != NULL); + + config_unregister_provider_lock_held (config, provider); + ep_provider_free (provider); + + ep_rt_config_requires_lock_held (); + return; +} + +void +ep_config_delete_deferred_providers_lock_held (EventPipeConfiguration *config) +{ + ep_rt_config_requires_lock_held (); + + ep_return_void_if_nok (config != NULL); + + // The provider list should be non-NULL, but can be NULL on shutdown. + const ep_rt_provider_list_t *provider_list = ep_config_get_provider_list_ref (config); + if (!ep_rt_provider_list_is_empty (provider_list)) { + ep_rt_provider_list_iterator_t iterator; + ep_rt_provider_list_iterator_begin (provider_list, &iterator); + + while (!ep_rt_provider_list_iterator_end (provider_list, &iterator)) { + EventPipeProvider *provider = ep_rt_provider_list_iterator_value (&iterator); + EP_ASSERT (provider != NULL); + + // Get next item before deleting current. + ep_rt_provider_list_iterator_next (provider_list, &iterator); + if (ep_provider_get_delete_deferred (provider)) + ep_config_delete_provider_lock_held (config, provider); + } + } + + ep_rt_config_requires_lock_held (); + return; +} + +void +ep_config_enable_disable_lock_held ( + EventPipeConfiguration *config, + const EventPipeSession *session, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue, + bool enable) +{ + ep_rt_config_requires_lock_held (); + + ep_return_void_if_nok (config != NULL && session != NULL); + + // The provider list should be non-NULL, but can be NULL on shutdown. + const ep_rt_provider_list_t *provider_list = ep_config_get_provider_list_cref (config); + if (!ep_rt_provider_list_is_empty (provider_list)) { + ep_rt_provider_list_iterator_t iterator; + for (ep_rt_provider_list_iterator_begin (provider_list, &iterator); !ep_rt_provider_list_iterator_end (provider_list, &iterator); ep_rt_provider_list_iterator_next (provider_list, &iterator)) { + EventPipeProvider *provider = ep_rt_provider_list_iterator_value (&iterator); + if (provider) { + // Enable/Disable the provider if it has been configured. + EventPipeSessionProvider *session_provider = ep_config_get_session_provider_lock_held (config, session, provider); + if (session_provider) { + int64_t keyword_for_all_sessions; + EventPipeEventLevel level_for_all_sessions; + EventPipeProviderCallbackData provider_callback_data; + config_compute_keyword_and_level_lock_held (config, provider, &keyword_for_all_sessions, &level_for_all_sessions); + if (enable) { + ep_provider_set_config_lock_held ( + provider, + keyword_for_all_sessions, + level_for_all_sessions, + ep_session_get_mask (session), + ep_session_provider_get_keywords (session_provider), + ep_session_provider_get_logging_level (session_provider), + ep_session_provider_get_filter_data (session_provider), + &provider_callback_data); + } else { + ep_provider_unset_config_lock_held ( + provider, + keyword_for_all_sessions, + level_for_all_sessions, + ep_session_get_mask (session), + ep_session_provider_get_keywords (session_provider), + ep_session_provider_get_logging_level (session_provider), + ep_session_provider_get_filter_data (session_provider), + &provider_callback_data); + } + ep_provider_callback_data_queue_enqueue (provider_callback_data_queue, &provider_callback_data); + } + } + } + } + + ep_rt_config_requires_lock_held (); + return; +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_configuration; +const char quiet_linker_empty_file_warning_eventpipe_configuration = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-config.h b/src/mono/mono/eventpipe/ep-config.h new file mode 100644 index 00000000000000..577b78f8643bc0 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-config.h @@ -0,0 +1,184 @@ +#ifndef __EVENTPIPE_CONFIGURATION_H__ +#define __EVENTPIPE_CONFIGURATION_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +/* + * EventPipeConfiguration. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeConfiguration { +#else +struct _EventPipeConfiguration_Internal { +#endif + ep_rt_provider_list_t provider_list; + EventPipeProvider *config_provider; + EventPipeEvent *metadata_event; + ep_char8_t *config_provider_name; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeConfiguration { + uint8_t _internal [sizeof (struct _EventPipeConfiguration_Internal)]; +}; +#endif + +EP_DEFINE_GETTER_REF(EventPipeConfiguration *, config, ep_rt_provider_list_t *, provider_list) +EP_DEFINE_GETTER(EventPipeConfiguration *, config, EventPipeProvider *, config_provider) +EP_DEFINE_SETTER(EventPipeConfiguration *, config, EventPipeProvider *, config_provider) +EP_DEFINE_GETTER(EventPipeConfiguration *, config, EventPipeEvent *, metadata_event) +EP_DEFINE_SETTER(EventPipeConfiguration *, config, EventPipeEvent *, metadata_event) +EP_DEFINE_GETTER(EventPipeConfiguration *, config, const ep_char8_t *, config_provider_name) + +static +inline +const ep_char8_t * +ep_config_get_default_provider_name_utf8 (void) +{ + return "Microsoft-DotNETCore-EventPipeConfiguration"; +} + +static +inline +const ep_char8_t * +ep_config_get_public_provider_name_utf8 (void) +{ + return "Microsoft-Windows-DotNETRuntime"; +} + +static +inline +const ep_char8_t * +ep_config_get_rundown_provider_name_utf8 (void) +{ + return "Microsoft-Windows-DotNETRuntimeRundown"; +} + +static +inline +EventPipeConfiguration * +ep_config_get (void) +{ + // Singelton. + extern EventPipeConfiguration _ep_config; + return &_ep_config; +} + +EventPipeConfiguration * +ep_config_init (EventPipeConfiguration *config); + +void +ep_config_shutdown (EventPipeConfiguration *config); + +EventPipeProvider * +ep_config_create_provider ( + EventPipeConfiguration *config, + const ep_char8_t *provider_name, + EventPipeCallback callback_func, + void *callback_data, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue); + +void +ep_config_delete_provider ( + EventPipeConfiguration *config, + EventPipeProvider *provider); + +void +ep_config_enable ( + EventPipeConfiguration *config, + const EventPipeSession *session, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue); + +void +ep_config_disable ( + EventPipeConfiguration *config, + const EventPipeSession *session, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue); + +EventPipeEventMetadataEvent * +ep_config_build_event_metadata_event ( + EventPipeConfiguration *config, + const EventPipeEventInstance *source_instance, + uint32_t metadata_id); + +void +ep_config_delete_deferred_providers (EventPipeConfiguration *config); + +EventPipeSessionProvider * +ep_config_get_session_provider_lock_held ( + const EventPipeConfiguration *config, + const EventPipeSession *session, + const EventPipeProvider *provider); + +EventPipeProvider * +ep_config_get_provider_lock_held ( + EventPipeConfiguration *config, + const ep_char8_t *name); + +EventPipeProvider * +ep_config_create_provider_lock_held ( + EventPipeConfiguration *config, + const ep_char8_t *provider_name, + EventPipeCallback callback_func, + void *callback_data, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue); + +void +ep_config_delete_provider_lock_held ( + EventPipeConfiguration *config, + EventPipeProvider *provider); + +void +ep_config_delete_deferred_providers_lock_held (EventPipeConfiguration *config); + +void +ep_config_enable_disable_lock_held ( + EventPipeConfiguration *config, + const EventPipeSession *session, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue, + bool enable); + +/* + * EventPipeEventMetadataEvent. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeEventMetadataEvent { +#else +struct _EventPipeEventMetadataEvent_Internal { +#endif + EventPipeEventInstance event_instance; + uint8_t *payload_buffer; + uint32_t payload_buffer_len; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeEventMetadataEvent { + uint8_t _internal [sizeof (struct _EventPipeEventMetadataEvent_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventPipeEventMetadataEvent *, event_metadata_event, uint8_t *, payload_buffer) +EP_DEFINE_GETTER(EventPipeEventMetadataEvent *, event_instance, uint32_t, payload_buffer_len) + + +EventPipeEventMetadataEvent * +ep_event_metdata_event_alloc ( + EventPipeEvent *ep_event, + uint32_t proc_num, + uint64_t thread_id, + uint8_t *data, + uint32_t data_len, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +void +ep_event_metdata_event_free (EventPipeEventMetadataEvent *metadata_event); + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_CONFIGURATION_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-event-instance-internals.c b/src/mono/mono/eventpipe/ep-event-instance-internals.c new file mode 100644 index 00000000000000..123675616d8f9a --- /dev/null +++ b/src/mono/mono/eventpipe/ep-event-instance-internals.c @@ -0,0 +1,143 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#define EP_IMPL_GETTER_SETTER +#include "ep.h" + +/* + * EventPipeEventInstance. + */ + +EventPipeEventInstance * +ep_event_instance_alloc ( + EventPipeEvent *ep_event, + uint32_t proc_num, + uint64_t thread_id, + const uint8_t *data, + uint32_t data_len, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + EventPipeEventInstance *instance = ep_rt_object_alloc (EventPipeEventInstance); + ep_raise_error_if_nok (instance != NULL); + + ep_raise_error_if_nok (ep_event_instance_init ( + instance, + ep_event, + proc_num, + thread_id, + data, + data_len, + activity_id, + related_activity_id) != NULL); + +ep_on_exit: + return instance; + +ep_on_error: + ep_event_instance_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +EventPipeEventInstance * +ep_event_instance_init ( + EventPipeEventInstance *event_instance, + EventPipeEvent *ep_event, + uint32_t proc_num, + uint64_t thread_id, + const uint8_t *data, + uint32_t data_len, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + EP_ASSERT (event_instance != NULL); + ep_return_null_if_nok (ep_event != NULL); + +#ifdef EP_CHECKED_BUILD + event_instance->debug_event_start = 0xDEADBEEF; + event_instance->debug_event_end = 0xCAFEBABE; +#endif + + event_instance->ep_event = ep_event; + event_instance->proc_num = proc_num; + event_instance->thread_id = thread_id; + + if (activity_id) + memcpy (&(event_instance->activity_id), activity_id, EP_ACTIVITY_ID_SIZE); + + if (related_activity_id) + memcpy (&(event_instance->related_activity_id), related_activity_id, EP_ACTIVITY_ID_SIZE); + + event_instance->data = data; + event_instance->data_len = data_len; + + event_instance->timestamp = ep_perf_counter_query (); + EP_ASSERT (event_instance->timestamp > 0); + + ep_event_instance_ensure_consistency (event_instance); + + return event_instance; +} + +void +ep_event_instance_fini (EventPipeEventInstance *ep_event_instance) +{ + ; +} + +void +ep_event_instance_free (EventPipeEventInstance *ep_event_instance) +{ + ep_return_void_if_nok (ep_event_instance != NULL); + + ep_event_instance_fini (ep_event_instance); + ep_rt_object_free (ep_event_instance); +} + +/* + * EventPipeSequencePoint. + */ + +EventPipeSequencePoint * +ep_sequence_point_init (EventPipeSequencePoint *sequence_point) +{ + EP_ASSERT (sequence_point != NULL); + + sequence_point->timestamp = 0; + sequence_point->thread_sequence_numbers.table = NULL; + sequence_point->thread_sequence_numbers.count = 0; + + return sequence_point; +} + +void +ep_sequence_point_fini (EventPipeSequencePoint *sequence_point) +{ + ep_return_void_if_nok (sequence_point != NULL); + + // Each entry in the map owns a ref-count on the corresponding thread + if (sequence_point->thread_sequence_numbers.table) { + ep_rt_thread_sequence_number_hash_map_iterator_t iterator; + for ( + ep_rt_thread_sequence_number_map_iterator_begin (&sequence_point->thread_sequence_numbers, &iterator); + !ep_rt_thread_sequence_number_map_iterator_end (&sequence_point->thread_sequence_numbers, &iterator); + ep_rt_thread_sequence_number_map_iterator_next (&sequence_point->thread_sequence_numbers, &iterator)) { + + EventPipeThreadSessionState *key = ep_rt_thread_sequence_number_map_iterator_key (&iterator); + ep_thread_release (ep_thread_session_state_get_thread (key)); + } + } +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_event_instance_internals; +const char quiet_linker_empty_file_warning_eventpipe_event_instance_internals = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-event-instance.c b/src/mono/mono/eventpipe/ep-event-instance.c new file mode 100644 index 00000000000000..1702b5d922c878 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-event-instance.c @@ -0,0 +1,93 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#include "ep.h" + +/* + * EventPipeEventInstance. + */ + +bool +ep_event_instance_ensure_consistency (const EventPipeEventInstance *ep_event_instance) +{ +#ifdef EP_CHECKED_BUILD + EP_ASSERT (ep_event_instance_get_debug_event_start (ep_event_instance) == 0xDEADBEEF); + EP_ASSERT (ep_event_instance_get_debug_event_end (ep_event_instance) == 0xCAFEBABE); +#endif + + return true; +} + +uint32_t +ep_event_instance_get_aligned_total_size ( + const EventPipeEventInstance *ep_event_instance, + EventPipeSerializationFormat format) +{ + // Calculate the size of the total payload so that it can be written to the file. + uint32_t payload_len = 0; + + if (format == EP_SERIALIZATION_FORMAT_NETPERF_V3) { + payload_len = + // Metadata ID + ep_event_instance_sizeof_metadata_id (ep_event_instance) + + // Thread ID + sizeof (int32_t) + + // TimeStamp + ep_event_instance_sizeof_timestamp (ep_event_instance) + + // Activity ID + EP_ACTIVITY_ID_SIZE + + // Related Activity ID + EP_ACTIVITY_ID_SIZE + + // Data payload length + ep_event_instance_sizeof_data_len (ep_event_instance) + + // Event payload data + ep_event_instance_get_data_len (ep_event_instance) + + // Prepended stack payload size in bytes + sizeof (uint32_t) + + // Stack payload size + ep_stack_contents_get_size (ep_event_instance_get_stack_contents_cref (ep_event_instance)); + } else if (format == EP_SERIALIZATION_FORMAT_NETTRACE_V4) { + payload_len = + // Metadata ID + ep_event_instance_sizeof_metadata_id (ep_event_instance) + + // Sequence number (implied by the buffer containing the event instance) + sizeof (uint32_t) + + // Thread ID + sizeof (int32_t) + + // Capture Thread ID (implied by the buffer containing the event instance) + sizeof (uint64_t) + + // ProcNumber + ep_event_instance_sizeof_proc_num (ep_event_instance) + + // Stack intern table id + sizeof (uint32_t) + + // TimeStamp + ep_event_instance_sizeof_timestamp (ep_event_instance) + + // Activity ID + EP_ACTIVITY_ID_SIZE + + // Related Activity ID + EP_ACTIVITY_ID_SIZE + + // Data payload length + ep_event_instance_sizeof_data_len (ep_event_instance) + + // Event payload data + ep_event_instance_get_data_len (ep_event_instance); + } else { + EP_ASSERT (!"Unrecognized format"); + } + + // round up to FAST_SERIALIZER_ALIGNMENT_SIZE bytes + if (payload_len % FAST_SERIALIZER_ALIGNMENT_SIZE != 0) + payload_len += FAST_SERIALIZER_ALIGNMENT_SIZE - (payload_len % FAST_SERIALIZER_ALIGNMENT_SIZE); + + return payload_len; +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_event_instance; +const char quiet_linker_empty_file_warning_eventpipe_event_instance = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-event-instance.h b/src/mono/mono/eventpipe/ep-event-instance.h new file mode 100644 index 00000000000000..391e7d36f3774c --- /dev/null +++ b/src/mono/mono/eventpipe/ep-event-instance.h @@ -0,0 +1,122 @@ +#ifndef __EVENTPIPE_EVENTINSTANCE_H__ +#define __EVENTPIPE_EVENTINSTANCE_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +/* + * EventPipeEventInstance. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeEventInstance { +#else +struct _EventPipeEventInstance_Internal { +#endif +#ifdef EP_CHECKED_BUILD + uint32_t debug_event_start; + uint32_t debug_event_end; +#endif + EventPipeEvent *ep_event; + uint32_t metadata_id; + uint32_t proc_num; + uint64_t thread_id; + uint64_t timestamp; + uint8_t activity_id [EP_ACTIVITY_ID_SIZE]; + uint8_t related_activity_id [EP_ACTIVITY_ID_SIZE]; + const uint8_t *data; + uint32_t data_len; + EventPipeStackContents stack_contents; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeEventInstance { + uint8_t _internal [sizeof (struct _EventPipeEventInstance_Internal)]; +}; +#endif + +#ifdef EP_CHECKED_BUILD +EP_DEFINE_GETTER(EventPipeEventInstance *, event_instance, uint32_t, debug_event_start) +EP_DEFINE_GETTER(EventPipeEventInstance *, event_instance, uint32_t, debug_event_end) +#endif +EP_DEFINE_GETTER(EventPipeEventInstance *, event_instance, EventPipeEvent *, ep_event) +EP_DEFINE_GETTER(EventPipeEventInstance *, event_instance, uint32_t, metadata_id) +EP_DEFINE_SETTER(EventPipeEventInstance *, event_instance, uint32_t, metadata_id) +EP_DEFINE_GETTER(EventPipeEventInstance *, event_instance, uint32_t, proc_num) +EP_DEFINE_GETTER(EventPipeEventInstance *, event_instance, uint64_t, thread_id) +EP_DEFINE_GETTER(EventPipeEventInstance *, event_instance, uint64_t, timestamp) +EP_DEFINE_SETTER(EventPipeEventInstance *, event_instance, uint64_t, timestamp) +EP_DEFINE_GETTER_ARRAY_REF(EventPipeEventInstance *, event_instance, uint8_t *, const uint8_t *, activity_id, activity_id[0]) +EP_DEFINE_GETTER_ARRAY_REF(EventPipeEventInstance *, event_instance, uint8_t *, const uint8_t *, related_activity_id, related_activity_id[0]) +EP_DEFINE_GETTER(EventPipeEventInstance *, event_instance, const uint8_t *, data) +EP_DEFINE_GETTER(EventPipeEventInstance *, event_instance, uint32_t, data_len) +EP_DEFINE_GETTER_REF(EventPipeEventInstance *, event_instance, EventPipeStackContents *, stack_contents) + +EventPipeEventInstance * +ep_event_instance_alloc ( + EventPipeEvent *ep_event, + uint32_t proc_num, + uint64_t thread_id, + const uint8_t *data, + uint32_t data_len, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +EventPipeEventInstance * +ep_event_instance_init ( + EventPipeEventInstance *ep_event_instance, + EventPipeEvent *ep_event, + uint32_t proc_num, + uint64_t thread_id, + const uint8_t *data, + uint32_t data_len, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +void +ep_event_instance_fini (EventPipeEventInstance *ep_event_instance); + +void +ep_event_instance_free (EventPipeEventInstance *ep_event_instance); + +bool +ep_event_instance_ensure_consistency (const EventPipeEventInstance *ep_event_instance); + +uint32_t +ep_event_instance_get_aligned_total_size ( + const EventPipeEventInstance *ep_event_instance, + EventPipeSerializationFormat format); + +/* + * EventPipeSequencePoint. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeSequencePoint { +#else +struct _EventPipeSequencePoint_Internal { +#endif + uint64_t timestamp; + ep_rt_thread_sequence_number_hash_map_t thread_sequence_numbers; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeSequencePoint { + uint8_t _internal [sizeof (struct _EventPipeSequencePoint_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventPipeSequencePoint *, sequence_point, uint64_t, timestamp) +EP_DEFINE_GETTER_REF(EventPipeSequencePoint *, sequence_point, ep_rt_thread_sequence_number_hash_map_t *, thread_sequence_numbers) + +EventPipeSequencePoint * +ep_sequence_point_init (EventPipeSequencePoint *sequence_point); + +void +ep_sequence_point_fini (EventPipeSequencePoint *sequence_point); + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_EVENTINSTANCE_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-event-internals.c b/src/mono/mono/eventpipe/ep-event-internals.c new file mode 100644 index 00000000000000..02c9469d28f590 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-event-internals.c @@ -0,0 +1,111 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#define EP_IMPL_GETTER_SETTER +#include "ep.h" + +/* + * Forward declares of all static functions. + */ + +static +void +event_build_minimum_metadata ( + EventPipeEvent *ep_event, + uint8_t **metadata, + uint32_t *metadata_len); + +/* + * EventPipeEvent. + */ + +static +void +event_build_minimum_metadata ( + EventPipeEvent *ep_event, + uint8_t **metadata, + uint32_t *metadata_len) +{ + EP_ASSERT (ep_event != NULL); + EP_ASSERT (metadata != NULL); + EP_ASSERT (metadata_len != NULL); + + size_t output_len = 0; + ep_char16_t empty_string [1] = { 0 }; + *metadata = ep_metadata_generator_generate_event_metadata ( + ep_event->event_id, + empty_string, + ep_event->keywords, + ep_event->event_version, + ep_event->level, + NULL, + 0, + &output_len); + + *metadata_len = (uint32_t)output_len; +} + +EventPipeEvent * +ep_event_alloc ( + EventPipeProvider *provider, + uint64_t keywords, + uint32_t event_id, + uint32_t event_version, + EventPipeEventLevel level, + bool need_stack, + const uint8_t *metadata, + uint32_t metadata_len) +{ + ep_return_null_if_nok (provider != NULL); + + EventPipeEvent *instance = ep_rt_object_alloc (EventPipeEvent); + ep_raise_error_if_nok (instance != NULL); + + instance->provider = provider; + instance->keywords = keywords; + instance->event_id = event_id; + instance->event_version = event_version; + instance->level = level; + instance->need_stack = need_stack; + instance->enabled_mask = 0; + + if (metadata != NULL) { + instance->metadata = ep_rt_byte_array_alloc (metadata_len); + ep_raise_error_if_nok (instance->metadata != NULL); + + memcpy (instance->metadata, metadata, metadata_len); + instance->metadata_len = metadata_len; + } else { + // if metadata is not provided, we have to build the minimum version. It's required by the serialization contract. + event_build_minimum_metadata (instance, &(instance->metadata), &(instance->metadata_len)); + } + +ep_on_exit: + return instance; + +ep_on_error: + ep_event_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_event_free (EventPipeEvent *ep_event) +{ + ep_return_void_if_nok (ep_event != NULL); + + ep_rt_byte_array_free (ep_event->metadata); + ep_rt_object_free (ep_event); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_event_internals; +const char quiet_linker_empty_file_warning_eventpipe_event_internals = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-event-payload-internals.c b/src/mono/mono/eventpipe/ep-event-payload-internals.c new file mode 100644 index 00000000000000..1be0b43138e751 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-event-payload-internals.c @@ -0,0 +1,70 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#define EP_IMPL_GETTER_SETTER +#include "ep.h" + +/* + * EventData. + */ + +EventData * +ep_event_data_alloc ( + uint64_t ptr, + uint32_t size, + uint32_t reserved) +{ + EventData *instance = ep_rt_object_alloc (EventData); + ep_raise_error_if_nok (ep_event_data_init (instance, ptr, size,reserved)); + +ep_on_exit: + return instance; + +ep_on_error: + ep_event_data_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +EventData * +ep_event_data_init ( + EventData *event_data, + uint64_t ptr, + uint32_t size, + uint32_t reserved) +{ + EP_ASSERT (event_data != NULL); + + event_data->ptr = ptr; + event_data->size = size; + event_data->reserved = reserved; + + return event_data; +} + +void +ep_event_data_fini (EventData *event_data) +{ + ; +} + +void +ep_event_data_free (EventData *event_data) +{ + ep_return_void_if_nok (event_data != NULL); + + ep_event_data_fini (event_data); + ep_rt_object_free (event_data); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_event_payload_internals; +const char quiet_linker_empty_file_warning_eventpipe_event_payload_internals = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-event-payload.h b/src/mono/mono/eventpipe/ep-event-payload.h new file mode 100644 index 00000000000000..58532d7b1416a6 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-event-payload.h @@ -0,0 +1,54 @@ +#ifndef __EVENTPIPE_EVENT_PAYLOAD_H__ +#define __EVENTPIPE_EVENT_PAYLOAD_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +/* + * EventData. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventData { +#else +struct _EventData_Internal { +#endif + uint64_t ptr; + uint32_t size; + uint32_t reserved; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventData { + uint8_t _internal [sizeof (struct _EventData_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventData *, event_data, uint64_t, ptr) +EP_DEFINE_GETTER(EventData *, event_data, uint32_t, size) +EP_DEFINE_GETTER(EventData *, event_data, uint32_t, reserved) + +EventData * +ep_event_data_alloc ( + uint64_t ptr, + uint32_t size, + uint32_t reserved); + +EventData * +ep_event_data_init ( + EventData *event_data, + uint64_t ptr, + uint32_t size, + uint32_t reserved); + +void +ep_event_data_fini (EventData *event_data); + +void +ep_event_data_free (EventData *event_data); + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_EVENT_PAYLOAD_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-event-source-internals.c b/src/mono/mono/eventpipe/ep-event-source-internals.c new file mode 100644 index 00000000000000..e283a37030a34a --- /dev/null +++ b/src/mono/mono/eventpipe/ep-event-source-internals.c @@ -0,0 +1,99 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#define EP_IMPL_GETTER_SETTER +#include "ep.h" + +/* + * EventPipeEventSource. + */ + +EventPipeEventSource * +ep_event_source_alloc (void) +{ + ep_char16_t *command_line_arg_utf16 = NULL; + ep_char16_t *event_name_utf16 = NULL; + uint8_t *metadata = NULL; + + EventPipeEventSource *instance = ep_rt_object_alloc (EventPipeEventSource); + ep_raise_error_if_nok (instance != NULL); + + instance->provider = ep_create_provider (ep_provider_get_default_name_utf8 (), NULL, NULL); + ep_raise_error_if_nok (instance->provider != NULL); + + // Generate metadata. + EventPipeParameterDesc params [1]; + const uint32_t params_len = EP_ARRAY_SIZE (params); + + command_line_arg_utf16 = ep_rt_utf8_to_utf16_string ("CommandLine", -1); + ep_raise_error_if_nok (command_line_arg_utf16 != NULL); + + ep_parameter_desc_init (params, EP_PARAMETER_TYPE_STRING, command_line_arg_utf16); + + event_name_utf16 = ep_rt_utf8_to_utf16_string ("ProcessInfo", -1); + ep_raise_error_if_nok (event_name_utf16 != NULL); + + size_t metadata_len = 0; + metadata = ep_metadata_generator_generate_event_metadata ( + 1, /* eventID */ + event_name_utf16, + 0, /* keywords */ + 0, /* version */ + EP_EVENT_LEVEL_LOG_ALWAYS, + params, + params_len, + &metadata_len); + + ep_raise_error_if_nok (metadata != NULL); + + // Add the event. + instance->process_info_event = ep_provider_add_event ( + instance->provider, + 1, /* eventID */ + 0, /* keywords */ + 0, /* eventVersion */ + EP_EVENT_LEVEL_LOG_ALWAYS, + false, /* needStack */ + metadata, + (uint32_t)metadata_len); + + ep_raise_error_if_nok (instance->process_info_event); + + // Delete the metadata after the event is created. + // The metadata blob will be copied into EventPipe-owned memory. + ep_rt_byte_array_free (metadata); + + // Delete the strings after the event is created. + // The strings will be copied into EventPipe-owned memory. + ep_rt_utf16_string_free (event_name_utf16); + ep_rt_utf16_string_free (command_line_arg_utf16); + +ep_on_exit: + return instance; + +ep_on_error: + ep_rt_byte_array_free (metadata); + ep_rt_utf16_string_free (event_name_utf16); + ep_rt_utf16_string_free (command_line_arg_utf16); + ep_event_source_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_event_source_free (EventPipeEventSource *event_source) +{ + ep_provider_free (event_source->provider); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_event_source_internals; +const char quiet_linker_empty_file_warning_eventpipe_event_source_internals = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-event-source.c b/src/mono/mono/eventpipe/ep-event-source.c new file mode 100644 index 00000000000000..94b1283e3b414c --- /dev/null +++ b/src/mono/mono/eventpipe/ep-event-source.c @@ -0,0 +1,52 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#include "ep.h" + +/* + * EventPipeEventSource. + */ + +static EventPipeEventSource *event_source_instance; + +void +ep_event_source_enable ( + EventPipeEventSource *event_source, + EventPipeSession *session) +{ + ep_return_void_if_nok (event_source != NULL); + ep_return_void_if_nok (session != NULL); + + EventPipeSessionProvider *session_provider = ep_session_provider_alloc (ep_event_source_get_provider_name (event_source), (uint64_t)-1, EP_EVENT_LEVEL_LOG_ALWAYS, NULL); + if (session_provider != NULL) + ep_session_add_session_provider (session, session_provider); +} + +void +ep_event_source_send_process_info ( + EventPipeEventSource * event_source, + const ep_char16_t *command_line) +{ + ep_return_void_if_nok (event_source != NULL); + + EventData data [1]; + ep_event_data_init (data, (uint64_t)command_line, (uint32_t)((ep_rt_utf16_string_len (command_line) + 1) * sizeof (ep_char16_t)), 0); + ep_write_event (ep_event_source_get_process_info_event (event_source), data, EP_ARRAY_SIZE (data), NULL, NULL); +} + +EventPipeEventSource * +ep_event_source_get (void) +{ + return event_source_instance; +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_event_source; +const char quiet_linker_empty_file_warning_eventpipe_event_source = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-event-source.h b/src/mono/mono/eventpipe/ep-event-source.h new file mode 100644 index 00000000000000..3a2195c27778f2 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-event-source.h @@ -0,0 +1,51 @@ +#ifndef __EVENTPIPE_EVENT_SOURCE_H__ +#define __EVENTPIPE_EVENT_SOURCE_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +/* + * EventPipeEventSource. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeEventSource { +#else +struct _EventPipeEventSource_Internal { +#endif + const ep_char8_t *provider_name; + EventPipeProvider *provider; + const ep_char8_t *process_info_event_name; + EventPipeEvent *process_info_event; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeEventSource { + uint8_t _internal [sizeof (struct _EventPipeEventSource_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventPipeEventSource *, event_source, const ep_char8_t *, provider_name) +EP_DEFINE_GETTER(EventPipeEventSource *, event_source, const ep_char8_t *, process_info_event_name) +EP_DEFINE_GETTER(EventPipeEventSource *, event_source, EventPipeEvent *, process_info_event) + +EventPipeEventSource * +ep_event_source_alloc (void); + +void +ep_event_source_free (EventPipeEventSource *event_source); + +void +ep_event_source_enable (EventPipeEventSource *event_source, EventPipeSession *session); + +void +ep_event_source_send_process_info (EventPipeEventSource *event_source, const ep_char16_t *command_line); + +EventPipeEventSource * +ep_event_source_get (void); + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_EVENT_SOURCE_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-event.h b/src/mono/mono/eventpipe/ep-event.h new file mode 100644 index 00000000000000..8f0418b638ab9c --- /dev/null +++ b/src/mono/mono/eventpipe/ep-event.h @@ -0,0 +1,64 @@ +#ifndef __EVENTPIPE_EVENT_H__ +#define __EVENTPIPE_EVENT_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +/* + * EventPipeEvent. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeEvent { +#else +struct _EventPipeEvent_Internal { +#endif + EventPipeProvider *provider; + uint64_t keywords; + uint32_t event_id; + uint32_t event_version; + EventPipeEventLevel level; + bool need_stack; + volatile int64_t enabled_mask; + uint8_t *metadata; + uint32_t metadata_len; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeEvent { + uint8_t _internal [sizeof (struct _EventPipeEvent_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventPipeEvent *, event, EventPipeProvider *, provider) +EP_DEFINE_GETTER(EventPipeEvent *, event, uint64_t, keywords) +EP_DEFINE_GETTER(EventPipeEvent *, event, uint32_t, event_id) +EP_DEFINE_GETTER(EventPipeEvent *, event, uint32_t, event_version) +EP_DEFINE_GETTER(EventPipeEvent *, event, EventPipeEventLevel, level) +EP_DEFINE_GETTER(EventPipeEvent *, event, bool, need_stack) +EP_DEFINE_GETTER(EventPipeEvent *, event, int64_t, enabled_mask) +EP_DEFINE_SETTER(EventPipeEvent *, event, int64_t, enabled_mask) +EP_DEFINE_GETTER(EventPipeEvent *, event, uint8_t *, metadata) +EP_DEFINE_SETTER(EventPipeEvent *, event, uint8_t *, metadata) +EP_DEFINE_GETTER(EventPipeEvent *, event, uint32_t, metadata_len) +EP_DEFINE_SETTER(EventPipeEvent *, event, uint32_t, metadata_len) + +EventPipeEvent * +ep_event_alloc ( + EventPipeProvider *provider, + uint64_t keywords, + uint32_t event_id, + uint32_t event_version, + EventPipeEventLevel level, + bool need_stack, + const uint8_t *metadata, + uint32_t metadata_len); + +void +ep_event_free (EventPipeEvent * ep_event); + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_EVENT_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-file-internals.c b/src/mono/mono/eventpipe/ep-file-internals.c new file mode 100644 index 00000000000000..b10351d792ea3e --- /dev/null +++ b/src/mono/mono/eventpipe/ep-file-internals.c @@ -0,0 +1,295 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#define EP_IMPL_GETTER_SETTER +#include "ep.h" + +/* + * Forward declares of all static functions. + */ + +static +void +file_fast_serialize_func (void *object, FastSerializer *fast_serializer); + +static +const ep_char8_t * +file_get_type_name_func (void *object); + +static +void +file_free_func (void *object); + +static +uint32_t +stack_hash_key_hash_func (const void *key); + +static +bool +stack_hash_key_eq_func (const void *key1, const void *key2); + +static +void +stack_hash_value_free_func (void *entry); + +/* + * EventPipeFile. + */ + +static +void +file_free_func (void *object) +{ + ep_file_free ((EventPipeFile*)object); +} + +static +void +file_fast_serialize_func (void *object, FastSerializer *fast_serializer) +{ + EP_ASSERT (object != NULL && fast_serializer != NULL); + + EventPipeFile *file = (EventPipeFile *)object; + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&file->file_open_system_time, sizeof (file->file_open_system_time)); + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&file->file_open_timestamp, sizeof (file->file_open_timestamp)); + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&file->timestamp_frequency, sizeof (file->timestamp_frequency)); + + // the beginning of V3 + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&file->pointer_size, sizeof (file->pointer_size)); + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&file->current_process_id, sizeof (file->current_process_id)); + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&file->number_of_processors, sizeof (file->number_of_processors)); + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&file->sampling_rate_in_ns, sizeof (file->sampling_rate_in_ns)); +} + +static +const ep_char8_t * +file_get_type_name_func (void *object) +{ + EP_ASSERT (object != NULL); + return "Trace"; +} + +static +FastSerializableObjectVtable +file_vtable = { + file_free_func, + file_fast_serialize_func, + file_get_type_name_func }; + +static +uint32_t +stack_hash_key_hash_func (const void *key) +{ + EP_ASSERT (key != NULL); + return ((const StackHashKey *)key)->hash; +} + +static +bool +stack_hash_key_eq_func (const void *key1, const void *key2) +{ + EP_ASSERT (key1 != NULL && key2 != NULL); + + const StackHashKey * stack_hash_key1 = (const StackHashKey *)key1; + const StackHashKey * stack_hash_key2 = (const StackHashKey *)key2; + + return stack_hash_key1->stack_size_in_bytes == stack_hash_key2->stack_size_in_bytes && + !memcmp (stack_hash_key1->stack_bytes, stack_hash_key2->stack_bytes, stack_hash_key1->stack_size_in_bytes); +} + +static +void +stack_hash_value_free_func (void *entry) +{ + ep_stack_hash_entry_free ((StackHashEntry *)entry); +} + +static +void +file_write_end (EventPipeFile *file) +{ + EP_ASSERT (file != NULL && ep_file_get_fast_serializer (file) != NULL); + + ep_file_flush (file, EP_FILE_FLUSH_FLAGS_ALL_BLOCKS); + + // "After the last EventBlock is emitted, the stream is ended by emitting a NullReference Tag which indicates that there are no more objects in the stream to read." + // see https://github.com/Microsoft/perfview/blob/master/src/TraceEvent/EventPipe/EventPipeFormat.md for more + ep_fast_serializer_write_tag (ep_file_get_fast_serializer (file), FAST_SERIALIZER_TAGS_NULL_REFERENCE, NULL, 0); +} + +EventPipeFile * +ep_file_alloc ( + StreamWriter *stream_writer, + EventPipeSerializationFormat format) +{ + EventPipeFile *instance = ep_rt_object_alloc (EventPipeFile); + ep_raise_error_if_nok (instance != NULL); + + ep_fast_serializable_object_init ( + &instance->fast_serializable_object, + &file_vtable, + ep_file_get_file_version (format), + ep_file_get_file_minimum_version (format), + format >= EP_SERIALIZATION_FORMAT_NETTRACE_V4); + + instance->stream_writer = stream_writer; + instance->format = format; + + instance->event_block = ep_event_block_alloc (100 * 1024, format); + ep_raise_error_if_nok (instance->event_block != NULL); + + instance->metadata_block = ep_metadata_block_alloc (100 * 1024); + ep_raise_error_if_nok (instance->metadata_block); + + instance->stack_block = ep_stack_block_alloc (100 * 1024); + ep_raise_error_if_nok (instance->stack_block != NULL); + + // File start time information. + instance->file_open_system_time = ep_rt_system_time_get (); + instance->file_open_timestamp = ep_perf_counter_query (); + instance->timestamp_frequency = ep_perf_frequency_query (); + + instance->pointer_size = SIZEOF_VOID_P; + instance->current_process_id = ep_rt_current_process_get_id (); + instance->number_of_processors = ep_rt_processors_get_count (); + + instance->sampling_rate_in_ns = ep_rt_sample_profiler_get_sampling_rate (); + + ep_rt_metadata_labels_alloc (&instance->metadata_ids, NULL, NULL, NULL, NULL); + ep_raise_error_if_nok (instance->metadata_ids.table); + + ep_rt_stack_hash_alloc (&instance->stack_hash, stack_hash_key_hash_func, stack_hash_key_eq_func, NULL, stack_hash_value_free_func); + ep_raise_error_if_nok (instance->stack_hash.table); + + // Start at 0 - The value is always incremented prior to use, so the first ID will be 1. + ep_rt_volatile_store_uint32_t (&instance->metadata_id_counter, 0); + + // Start at 0 - The value is always incremented prior to use, so the first ID will be 1. + instance->stack_id_counter = 0; + +#ifdef EP_CHECKED_BUILD + instance->last_sorted_timestamp = ep_perf_counter_query (); +#endif + +ep_on_exit: + return instance; + +ep_on_error: + ep_file_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_file_free (EventPipeFile *file) +{ + ep_return_void_if_nok (file != NULL); + + if (file->event_block != NULL && file->fast_serializer != NULL) + file_write_end (file); + + ep_event_block_free (file->event_block); + ep_metadata_block_free (file->metadata_block); + ep_stack_block_free (file->stack_block); + ep_fast_serializer_free (file->fast_serializer); + ep_rt_metadata_labels_free (&file->metadata_ids); + ep_rt_stack_hash_free (&file->stack_hash); + + // If there's no fast_serializer, stream_writer ownership + // have not been passed along and needs to be freed by file. + if (!file->fast_serializer) + ep_stream_writer_free_vcall (file->stream_writer); + + ep_fast_serializable_object_fini (&file->fast_serializable_object); + ep_rt_object_free (file); +} + +/* + * StackHashEntry. + */ + +StackHashEntry * +ep_stack_hash_entry_alloc ( + const EventPipeStackContents *stack_contents, + uint32_t id, + uint32_t hash) +{ + ep_return_null_if_nok (stack_contents != NULL); + + uint32_t stack_size = ep_stack_contents_get_size (stack_contents); + StackHashEntry *entry = (StackHashEntry *)ep_rt_byte_array_alloc (offsetof (StackHashEntry, stack_bytes) + stack_size); + ep_raise_error_if_nok (entry != NULL); + + entry->id = id; + entry->key.hash = hash; + entry->key.stack_size_in_bytes = stack_size; + entry->key.stack_bytes = entry->stack_bytes; + memcpy (entry->stack_bytes, ep_stack_contents_get_pointer (stack_contents), stack_size); + +ep_on_exit: + return entry; + +ep_on_error: + ep_stack_hash_entry_free (entry); + + entry = NULL; + ep_exit_error_handler (); +} + +void +ep_stack_hash_entry_free (StackHashEntry *stack_hash_entry) +{ + ep_return_void_if_nok (stack_hash_entry != NULL); + ep_rt_byte_array_free ((uint8_t *)stack_hash_entry); +} + +/* + * StackHashKey. + */ + +static +inline +uint32_t +hash_bytes (const uint8_t *data, size_t data_len) +{ + EP_ASSERT (data != NULL); + + uint32_t hash = 5381; + const uint8_t *data_end = data + data_len; + for (/**/ ; data < data_end; data++) + hash = ((hash << 5) + hash) ^ *data; + return hash; +} + +StackHashKey * +ep_stack_hash_key_init ( + StackHashKey *key, + const EventPipeStackContents *stack_contents) +{ + EP_ASSERT (key != NULL); + ep_return_null_if_nok (stack_contents != NULL); + + key->stack_bytes = ep_stack_contents_get_pointer (stack_contents); + key->stack_size_in_bytes = ep_stack_contents_get_size (stack_contents); + key->hash = hash_bytes (key->stack_bytes, key->stack_size_in_bytes); + + return key; +} + +void +ep_stack_hash_key_fini (StackHashKey *key) +{ + ; +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_file_internals; +const char quiet_linker_empty_file_warning_eventpipe_file_internals = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-file.c b/src/mono/mono/eventpipe/ep-file.c new file mode 100644 index 00000000000000..e16acabc0b0d22 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-file.c @@ -0,0 +1,331 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#include "ep.h" + +/* + * Forward declares of all static functions. + */ + +static +uint32_t +file_get_stack_id ( + EventPipeFile *file, + EventPipeEventInstance *event_instance); + +static +uint32_t +file_generate_metadata_id (EventPipeFile *file); + +static +uint32_t +file_get_metadata_id ( + EventPipeFile *file, + EventPipeEvent *ep_event); + +static +void +file_write_event_to_block ( + EventPipeFile *file, + EventPipeEventInstance *event_instance, + uint32_t metadata_id, + uint64_t capture_thread_id, + uint32_t sequence_number, + uint32_t stack_id, + bool is_sotred_event); + +static +void +file_save_metadata_id ( + EventPipeFile *file, + EventPipeEvent *ep_event, + uint32_t metadata_id); + +/* + * EventPipeFile. + */ + +static +uint32_t +file_get_stack_id ( + EventPipeFile *file, + EventPipeEventInstance * event_instance) +{ + EP_ASSERT (file != NULL && event_instance != NULL); + EP_ASSERT (ep_file_get_format (file) >= EP_SERIALIZATION_FORMAT_NETTRACE_V4); + EP_ASSERT (ep_file_get_stack_block (file) != NULL); + + uint32_t stack_id = 0; + EventPipeStackContents *stack_contents = ep_event_instance_get_stack_contents_ref (event_instance); + EventPipeStackBlock *stack_block = ep_file_get_stack_block (file); + ep_rt_stack_hash_map_t *stack_hash = ep_file_get_stack_hash_ref (file); + StackHashEntry *entry = NULL; + StackHashKey key; + ep_stack_hash_key_init (&key, stack_contents); + if (!ep_rt_stack_hash_lookup (stack_hash, &key, &entry)) { + stack_id = ep_file_get_stack_id_counter (file) + 1; + ep_file_set_stack_id_counter (file, stack_id); + entry = ep_stack_hash_entry_alloc (stack_contents, stack_id, ep_stack_hash_key_get_hash (&key)); + if (entry) + ep_rt_stack_hash_add (stack_hash, ep_stack_hash_entry_get_key_ref (entry), entry); + + if (!ep_stack_block_write_stack (stack_block, stack_id, stack_contents)) { + // we can't write this stack to the current block (it's full) + // so we write what we have in the block to the serializer + ep_file_flush (file, EP_FILE_FLUSH_FLAGS_STACK_BLOCK); + bool result = ep_stack_block_write_stack (stack_block, stack_id, stack_contents); + EP_ASSERT (result == true); // we should never fail to add event to a clear block (if we do the max size is too small) + } + } else { + stack_id = ep_stack_hash_entry_get_id (entry); + } + + ep_stack_hash_key_fini (&key); + return stack_id; +} + +static +uint32_t +file_get_metadata_id ( + EventPipeFile *file, + EventPipeEvent *ep_event) +{ + EP_ASSERT (file != NULL && ep_event != NULL); + EP_ASSERT (ep_file_get_metadata_ids_cref (file) != NULL); + + uint32_t metadata_ids; + if (ep_rt_metadata_labels_lookup (ep_file_get_metadata_ids_cref (file), ep_event, &metadata_ids)) { + EP_ASSERT (metadata_ids != 0); + return metadata_ids; + } + + return 0; +} + +static +uint32_t +file_generate_metadata_id (EventPipeFile *file) +{ + return ep_rt_atomic_inc_uint32_t (ep_file_get_metadata_id_counter_ref (file)); +} + +static +void +file_write_event_to_block ( + EventPipeFile *file, + EventPipeEventInstance *event_instance, + uint32_t metadata_id, + uint64_t capture_thread_id, + uint32_t sequence_number, + uint32_t stack_id, + bool is_sotred_event) +{ + EP_ASSERT (file != NULL && event_instance != NULL); + EP_ASSERT (ep_file_get_event_block (file) != NULL); + EP_ASSERT (ep_file_get_metadata_block (file) != NULL); + + ep_event_instance_set_metadata_id (event_instance, metadata_id); + + // If we are flushing events we need to flush metadata and stacks as well + // to ensure referenced metadata/stacks were written to the file before the + // event which referenced them. + EventPipeFileFlushFlags flags = EP_FILE_FLUSH_FLAGS_ALL_BLOCKS; + EventPipeEventBlockBase *block = (EventPipeEventBlockBase *)ep_file_get_event_block (file); + if(metadata_id == 0 && ep_file_get_format (file) >= EP_SERIALIZATION_FORMAT_NETTRACE_V4) { + flags = EP_FILE_FLUSH_FLAGS_METADATA_BLOCK; + block = (EventPipeEventBlockBase *)ep_file_get_metadata_block (file); + } + + if (ep_event_block_base_write_event (block, event_instance, capture_thread_id, sequence_number, stack_id, is_sotred_event)) + return; // the block is not full, we added the event and continue + + // we can't write this event to the current block (it's full) + // so we write what we have in the block to the serializer + ep_file_flush (file, flags); + + bool result = ep_event_block_base_write_event (block, event_instance, capture_thread_id, sequence_number, stack_id, is_sotred_event); + EP_ASSERT (result == true); // we should never fail to add event to a clear block (if we do the max size is too small) +} + +static +void +file_save_metadata_id ( + EventPipeFile *file, + EventPipeEvent *ep_event, + uint32_t metadata_id) +{ + EP_ASSERT (file != NULL && ep_event != NULL); + EP_ASSERT (metadata_id > 0); + EP_ASSERT (ep_file_get_metadata_ids_cref (file) != NULL); + + // If a pre-existing metadata label exists, remove it. + uint32_t old_id; + if (ep_rt_metadata_labels_lookup (ep_file_get_metadata_ids_cref (file), ep_event, &old_id)) + ep_rt_metadata_labels_remove (ep_file_get_metadata_ids_ref (file), ep_event); + + // Add the metadata label. + ep_rt_metadata_labels_add (ep_file_get_metadata_ids_ref (file), ep_event, metadata_id); +} + +bool +ep_file_initialize_file (EventPipeFile *file) +{ + ep_return_false_if_nok (file != NULL); + + EP_ASSERT (ep_file_get_stream_writer (file) != NULL); + EP_ASSERT (ep_file_get_fast_serializer (file) == NULL); + + bool success = true; + if (ep_file_get_format (file) >= EP_SERIALIZATION_FORMAT_NETTRACE_V4) { + const ep_char8_t header[] = "Nettrace"; + const uint32_t bytes_to_write = EP_ARRAY_SIZE (header) - 1; + uint32_t bytes_written = 0; + success = ep_stream_writer_write (ep_file_get_stream_writer (file), (const uint8_t *)header, bytes_to_write, &bytes_written) && bytes_written == bytes_to_write; + } + + if (success) { + // Create the file stream and write the FastSerialization header. + ep_file_set_fast_serializer (file, ep_fast_serializer_alloc (ep_file_get_stream_writer (file))); + + // Write the first object to the file. + if (ep_file_get_fast_serializer (file)) + ep_fast_serializer_write_object (ep_file_get_fast_serializer (file), (FastSerializableObject *)file); + } + + return success; +} + +void +ep_file_write_event ( + EventPipeFile *file, + EventPipeEventInstance *event_instance, + uint64_t capture_thread_id, + uint32_t sequence_number, + bool is_sorted_event) +{ + ep_return_void_if_nok (file != NULL && event_instance != NULL); + EP_ASSERT (ep_file_get_fast_serializer (file) != NULL); + + EventPipeEventMetadataEvent *metadata_instance = NULL; + +#ifdef EP_CHECKED_BUILD + EP_ASSERT (ep_event_instance_get_timestamp (event_instance) >= ep_file_get_last_sorted_timestamp (file)); + if (is_sorted_event) + ep_file_set_last_sorted_timestamp (file, ep_event_instance_get_timestamp (event_instance)); +#endif + + uint32_t stack_id = 0; + if (ep_file_get_format (file) >= EP_SERIALIZATION_FORMAT_NETTRACE_V4) + stack_id = file_get_stack_id (file, event_instance); + + // Check to see if we've seen this event type before. + // If not, then write the event metadata to the event stream first. + unsigned int metadata_id = file_get_metadata_id (file, ep_event_instance_get_ep_event (event_instance)); + if(metadata_id == 0) { + metadata_id = file_generate_metadata_id (file); + + metadata_instance = ep_build_event_metadata_event (event_instance, metadata_id); + ep_raise_error_if_nok (metadata_instance != NULL); + + file_write_event_to_block (file, (EventPipeEventInstance *)metadata_instance, 0, 0, 0, 0, true); // metadataId=0 breaks recursion and represents the metadata event. + file_save_metadata_id (file, ep_event_instance_get_ep_event (event_instance), metadata_id); + } + + file_write_event_to_block (file, event_instance, metadata_id, capture_thread_id, sequence_number, stack_id, is_sorted_event); + +ep_on_exit: + ep_event_metdata_event_free (metadata_instance); + return; + +ep_on_error: + ep_exit_error_handler (); +} + +void +ep_file_write_sequence_point ( + EventPipeFile *file, + EventPipeSequencePoint *sequence_point) +{ + ep_return_void_if_nok (file != NULL && sequence_point != NULL); + EP_ASSERT (ep_file_get_fast_serializer (file) != NULL); + + if (ep_file_get_format (file) < EP_SERIALIZATION_FORMAT_NETTRACE_V4) + return; // sequence points aren't used in NetPerf format + + ep_file_flush (file, EP_FILE_FLUSH_FLAGS_ALL_BLOCKS); + EventPipeSequencePointBlock sequence_point_block; + + ep_sequence_point_block_init (&sequence_point_block, sequence_point); + ep_fast_serializer_write_object (ep_file_get_fast_serializer (file), (FastSerializableObject *)&sequence_point_block); + ep_sequence_point_block_fini (&sequence_point_block); + + // stack cache resets on sequence points + ep_file_set_stack_id_counter (file, 0); + ep_rt_stack_hash_remove_all (ep_file_get_stack_hash_ref (file)); +} + +void +ep_file_flush ( + EventPipeFile *file, + EventPipeFileFlushFlags flags) +{ + // Write existing buffer to the stream/file regardless of whether it is full or not. + ep_return_void_if_nok (file != NULL && ep_file_get_fast_serializer (file) != NULL && ep_file_get_metadata_block (file) != NULL && + ep_file_get_stack_block (file) != NULL && ep_file_get_event_block (file) != NULL); + + if ((ep_metadata_block_get_bytes_written (ep_file_get_metadata_block (file)) != 0) && ((flags & EP_FILE_FLUSH_FLAGS_METADATA_BLOCK) != 0)) { + EP_ASSERT (ep_file_get_format (file) >= EP_SERIALIZATION_FORMAT_NETTRACE_V4); + ep_metadata_block_serialize (ep_file_get_metadata_block (file), ep_file_get_fast_serializer (file)); + ep_metadata_block_clear (ep_file_get_metadata_block (file)); + } + + if ((ep_stack_block_get_bytes_written (ep_file_get_stack_block (file)) != 0) && ((flags & EP_FILE_FLUSH_FLAGS_STACK_BLOCK) != 0)) { + EP_ASSERT (ep_file_get_format (file) >= EP_SERIALIZATION_FORMAT_NETTRACE_V4); + ep_stack_block_serialize (ep_file_get_stack_block (file), ep_file_get_fast_serializer (file)); + ep_stack_block_clear (ep_file_get_stack_block (file)); + } + + if ((ep_event_block_get_bytes_written (ep_file_get_event_block (file)) != 0) && ((flags & EP_FILE_FLUSH_FLAGS_EVENT_BLOCK) != 0)) { + ep_event_block_serialize (ep_file_get_event_block (file), ep_file_get_fast_serializer (file)); + ep_event_block_clear (ep_file_get_event_block (file)); + } +} + +int32_t +ep_file_get_file_version (EventPipeSerializationFormat format) +{ + switch (format) { + case EP_SERIALIZATION_FORMAT_NETPERF_V3 : + return 3; + case EP_SERIALIZATION_FORMAT_NETTRACE_V4 : + return 4; + default : + EP_ASSERT (!"Unrecognized EventPipeSerializationFormat"); + return 0; + } +} + +int32_t +ep_file_get_file_minimum_version (EventPipeSerializationFormat format) +{ + switch (format) { + case EP_SERIALIZATION_FORMAT_NETPERF_V3 : + return 0; + case EP_SERIALIZATION_FORMAT_NETTRACE_V4 : + return 4; + default : + EP_ASSERT (!"Unrecognized EventPipeSerializationFormat"); + return 0; + } +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_file; +const char quiet_linker_empty_file_warning_eventpipe_file = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-file.h b/src/mono/mono/eventpipe/ep-file.h new file mode 100644 index 00000000000000..7c78e405e9464d --- /dev/null +++ b/src/mono/mono/eventpipe/ep-file.h @@ -0,0 +1,164 @@ +#ifndef __EVENTPIPE_FILE_H__ +#define __EVENTPIPE_FILE_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +/* + * EventPipeFile. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeFile { +#else +struct _EventPipeFile_Internal { +#endif + FastSerializableObject fast_serializable_object; + StreamWriter *stream_writer; + FastSerializer *fast_serializer; + EventPipeEventBlock *event_block; + EventPipeMetadataBlock *metadata_block; + EventPipeStackBlock *stack_block; + ep_rt_metadata_labels_hash_map_t metadata_ids; + ep_rt_stack_hash_map_t stack_hash; + uint64_t file_open_system_time; + uint64_t file_open_timestamp; + uint64_t timestamp_frequency; +#ifdef EP_CHECKED_BUILD + uint64_t last_sorted_timestamp; +#endif + uint32_t pointer_size; + uint32_t current_process_id; + uint32_t number_of_processors; + uint32_t sampling_rate_in_ns; + uint32_t stack_id_counter; + volatile uint32_t metadata_id_counter; + EventPipeSerializationFormat format; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeFile { + uint8_t _internal [sizeof (struct _EventPipeFile_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventPipeFile *, file, StreamWriter *, stream_writer) +EP_DEFINE_GETTER(EventPipeFile *, file, FastSerializer *, fast_serializer) +EP_DEFINE_SETTER(EventPipeFile *, file, FastSerializer *, fast_serializer) +EP_DEFINE_GETTER(EventPipeFile *, file, EventPipeEventBlock *, event_block) +EP_DEFINE_GETTER(EventPipeFile *, file, EventPipeMetadataBlock *, metadata_block) +EP_DEFINE_GETTER_REF(EventPipeFile *, file, ep_rt_metadata_labels_hash_map_t *, metadata_ids) +EP_DEFINE_GETTER_REF(EventPipeFile *, file, ep_rt_stack_hash_map_t *, stack_hash) +EP_DEFINE_GETTER(EventPipeFile *, file, EventPipeStackBlock *, stack_block) +EP_DEFINE_GETTER(EventPipeFile *, file, EventPipeSerializationFormat, format) +EP_DEFINE_GETTER(EventPipeFile *, file, uint32_t, stack_id_counter); +EP_DEFINE_SETTER(EventPipeFile *, file, uint32_t, stack_id_counter); +EP_DEFINE_GETTER_REF(EventPipeFile *, file, volatile uint32_t *, metadata_id_counter) +#ifdef EP_CHECKED_BUILD +EP_DEFINE_GETTER(EventPipeFile *, file, uint64_t, last_sorted_timestamp) +EP_DEFINE_SETTER(EventPipeFile *, file, uint64_t, last_sorted_timestamp) +#endif + +EventPipeFile * +ep_file_alloc ( + StreamWriter *stream_writer, + EventPipeSerializationFormat format); + +void +ep_file_free (EventPipeFile *file); + +bool +ep_file_initialize_file (EventPipeFile *file); + +void +ep_file_write_event ( + EventPipeFile *file, + EventPipeEventInstance * event_instance, + uint64_t capture_thread_id, + uint32_t sequence_number, + bool is_sorted_event); + +void +ep_file_write_sequence_point ( + EventPipeFile *file, + EventPipeSequencePoint *sequence_point); + +void +ep_file_flush ( + EventPipeFile *file, + EventPipeFileFlushFlags flags); + +int32_t +ep_file_get_file_version (EventPipeSerializationFormat format); + +int32_t +ep_file_get_file_minimum_version (EventPipeSerializationFormat format); + +/* + * StackHashKey. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _StackHashKey { +#else +struct _StackHashKey_Internal { +#endif + uint8_t *stack_bytes; + uint32_t hash; + uint32_t stack_size_in_bytes; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _StackHashKey { + uint8_t _internal [sizeof (struct _StackHashKey_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(StackHashKey *, stack_hash_key, uint32_t, hash) + +StackHashKey * +ep_stack_hash_key_init ( + StackHashKey *key, + const EventPipeStackContents *stack_contents); + +void +ep_stack_hash_key_fini (StackHashKey *key); + +/* + * StackHashEntry. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _StackHashEntry { +#else +struct _StackHashEntry_Internal { +#endif + StackHashKey key; + uint32_t id; + // This is the first byte of StackSizeInBytes bytes of stack data + uint8_t stack_bytes[1]; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _StackHashEntry { + uint8_t _internal [sizeof (struct _StackHashEntry_Internal)]; +}; +#endif + +EP_DEFINE_GETTER_REF(StackHashEntry *, stack_hash_entry, StackHashKey *, key) +EP_DEFINE_GETTER(StackHashEntry *, stack_hash_entry, uint32_t, id) + +StackHashEntry * +ep_stack_hash_entry_alloc ( + const EventPipeStackContents *stack_contents, + uint32_t id, + uint32_t hash); + +void +ep_stack_hash_entry_free (StackHashEntry *stack_hash_entry); + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_FILE_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-internals.c b/src/mono/mono/eventpipe/ep-internals.c new file mode 100644 index 00000000000000..58bc70df0e89b3 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-internals.c @@ -0,0 +1,242 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" + +#ifndef EP_INLINE_GETTER_SETTER +#define EP_IMPL_GETTER_SETTER +#define EP_DEFINE_GETTER(instance_type, instance_type_name, return_type, instance_field_name) \ + return_type ep_ ## instance_type_name ## _get_ ## instance_field_name (const instance_type instance) { return instance-> instance_field_name; } \ + size_t ep_ ## instance_type_name ## _sizeof_ ## instance_field_name (const instance_type instance) { return sizeof (instance-> instance_field_name); } +#define EP_DEFINE_GETTER_REF(instance_type, instance_type_name, return_type, instance_field_name) \ + return_type ep_ ## instance_type_name ## _get_ ## instance_field_name ## _ref (instance_type instance) { return &(instance-> instance_field_name); } \ + const return_type ep_ ## instance_type_name ## _get_ ## instance_field_name ## _cref (const instance_type instance) { return &(instance-> instance_field_name); } +#define EP_DEFINE_GETTER_ARRAY_REF(instance_type, instance_type_name, return_type, const_return_type, instance_field_name, instance_field) \ + return_type ep_ ## instance_type_name ## _get_ ## instance_field_name ## _ref (instance_type instance) { return &(instance-> instance_field); } \ + const_return_type ep_ ## instance_type_name ## _get_ ## instance_field_name ## _cref (const instance_type instance) { return &(instance-> instance_field); } +#define EP_DEFINE_SETTER(instance_type, instance_type_name, instance_field_type, instance_field_name) \ + void ep_ ## instance_type_name ## _set_ ## instance_field_name (instance_type instance, instance_field_type instance_field_name) { instance-> instance_field_name = instance_field_name; } +#endif + +#include "ep.h" + +// Option to include all internal source files into ep-internals.c. +#ifdef EP_INCLUDE_SOURCE_FILES +#define EP_FORCE_INCLUDE_SOURCE_FILES +#include "ep-block-internals.c" +#include "ep-buffer-manager-internals.c" +#include "ep-config-internals.c" +#include "ep-event-internals.c" +#include "ep-event-instance-internals.c" +#include "ep-event-payload-internals.c" +#include "ep-event-source-internals.c" +#include "ep-file-internals.c" +#include "ep-metadata-generator-internals.c" +#include "ep-provider-internals.c" +#include "ep-session-internals.c" +#include "ep-session-provider-internals.c" +#include "ep-stream-internals.c" +#include "ep-thread-internals.c" +#endif + +/* + * EventFilterDescriptor. + */ + +EventFilterDescriptor * +ep_event_filter_desc_alloc ( + uint64_t ptr, + uint32_t size, + uint32_t type) +{ + EventFilterDescriptor *instance = ep_rt_object_alloc (EventFilterDescriptor); + ep_raise_error_if_nok (ep_event_filter_desc_init (instance, ptr, size, type) != NULL); + +ep_on_exit: + return instance; + +ep_on_error: + ep_event_filter_desc_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +EventFilterDescriptor * +ep_event_filter_desc_init ( + EventFilterDescriptor *event_filter_desc, + uint64_t ptr, + uint32_t size, + uint32_t type) +{ + EP_ASSERT (event_filter_desc != NULL); + + event_filter_desc->ptr = ptr; + event_filter_desc->size = size; + event_filter_desc->type = type; + + return event_filter_desc; +} + +void +ep_event_filter_desc_fini (EventFilterDescriptor * filter_desc) +{ + ; +} + +void +ep_event_filter_desc_free (EventFilterDescriptor * filter_desc) +{ + ep_return_void_if_nok (filter_desc != NULL); + + ep_event_filter_desc_fini (filter_desc); + ep_rt_object_free (filter_desc); +} + +/* + * EventPipeProviderCallbackDataQueue. + */ + +EventPipeProviderCallbackDataQueue * +ep_provider_callback_data_queue_init (EventPipeProviderCallbackDataQueue *provider_callback_data_queue) +{ + ep_return_null_if_nok (provider_callback_data_queue != NULL); + ep_rt_provider_callback_data_queue_alloc (&provider_callback_data_queue->queue); + return provider_callback_data_queue; +} + +void +ep_provider_callback_data_queue_fini (EventPipeProviderCallbackDataQueue *provider_callback_data_queue) +{ + ep_return_void_if_nok (provider_callback_data_queue != NULL); + ep_rt_provider_callback_data_queue_free (&provider_callback_data_queue->queue); +} + +/* + * EventPipeProviderCallbackData. + */ + +EventPipeProviderCallbackData * +ep_provider_callback_data_alloc ( + const ep_char8_t *filter_data, + EventPipeCallback callback_function, + void *callback_data, + int64_t keywords, + EventPipeEventLevel provider_level, + bool enabled) +{ + EventPipeProviderCallbackData *instance = ep_rt_object_alloc (EventPipeProviderCallbackData); + ep_raise_error_if_nok (instance != NULL); + + ep_raise_error_if_nok (ep_provider_callback_data_init ( + instance, + filter_data, + callback_function, + callback_data, + keywords, + provider_level, + enabled) != NULL); + +ep_on_exit: + return instance; + +ep_on_error: + instance = NULL; + ep_exit_error_handler (); +} + +EventPipeProviderCallbackData * +ep_provider_callback_data_alloc_copy (EventPipeProviderCallbackData *provider_callback_data_src) +{ + EventPipeProviderCallbackData *instance = ep_rt_object_alloc (EventPipeProviderCallbackData); + ep_raise_error_if_nok (instance != NULL); + + if (provider_callback_data_src) + *instance = *provider_callback_data_src; + +ep_on_exit: + return instance; + +ep_on_error: + instance = NULL; + ep_exit_error_handler (); +} + +EventPipeProviderCallbackData * +ep_provider_callback_data_init ( + EventPipeProviderCallbackData *provider_callback_data, + const ep_char8_t *filter_data, + EventPipeCallback callback_function, + void *callback_data, + int64_t keywords, + EventPipeEventLevel provider_level, + bool enabled) +{ + ep_return_null_if_nok (provider_callback_data != NULL); + + provider_callback_data->filter_data = filter_data; + provider_callback_data->callback_function = callback_function; + provider_callback_data->callback_data = callback_data; + provider_callback_data->keywords = keywords; + provider_callback_data->provider_level = provider_level; + provider_callback_data->enabled = enabled; + + return provider_callback_data; +} + +EventPipeProviderCallbackData * +ep_provider_callback_data_init_copy ( + EventPipeProviderCallbackData *provider_callback_data_dst, + EventPipeProviderCallbackData *provider_callback_data_src) +{ + ep_return_null_if_nok (provider_callback_data_dst != NULL && provider_callback_data_src != NULL); + *provider_callback_data_dst = *provider_callback_data_src; + return provider_callback_data_dst; +} + +void +ep_provider_callback_data_fini (EventPipeProviderCallbackData *provider_callback_data) +{ + ; +} + +void +ep_provider_callback_data_free (EventPipeProviderCallbackData *provider_callback_data) +{ + ep_return_void_if_nok (provider_callback_data != NULL); + ep_rt_object_free (provider_callback_data); +} + +/* + * EventPipeProviderConfiguration. + */ + +EventPipeProviderConfiguration * +ep_provider_config_init ( + EventPipeProviderConfiguration *provider_config, + const ep_char8_t *provider_name, + uint64_t keywords, + uint32_t logging_level, + const ep_char8_t *filter_data) +{ + EP_ASSERT (provider_config != NULL); + ep_return_null_if_nok (provider_name != NULL); + + provider_config->provider_name = provider_name; + provider_config->keywords = keywords; + provider_config->logging_level = logging_level; + provider_config->filter_data = filter_data; + + return provider_config; +} + +void +ep_provider_config_fini (EventPipeProviderConfiguration *provider_config) +{ + ; +} + +#endif /* ENABLE_PERFTRACING */ + +extern const char quiet_linker_empty_file_warning_eventpipe_internals; +const char quiet_linker_empty_file_warning_eventpipe_internals = 0; diff --git a/src/mono/mono/eventpipe/ep-metadata-generator-internals.c b/src/mono/mono/eventpipe/ep-metadata-generator-internals.c new file mode 100644 index 00000000000000..e2c8e76421d16e --- /dev/null +++ b/src/mono/mono/eventpipe/ep-metadata-generator-internals.c @@ -0,0 +1,40 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#define EP_IMPL_GETTER_SETTER +#include "ep.h" + +/* + * EventPipeParameterDesc. + */ + +EventPipeParameterDesc * +ep_parameter_desc_init ( + EventPipeParameterDesc *parameter_desc, + EventPipeParameterType type, + const ep_char16_t *name) +{ + EP_ASSERT (parameter_desc != NULL); + + parameter_desc->type = type; + parameter_desc->name = name; + + return parameter_desc; +} + +void +ep_parameter_desc_fini (EventPipeParameterDesc *parameter_desc) +{ + ; +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_metadata_generator_internals; +const char quiet_linker_empty_file_warning_eventpipe_metadata_generator_internals = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-metadata-generator.c b/src/mono/mono/eventpipe/ep-metadata-generator.c new file mode 100644 index 00000000000000..4fd80356e96497 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-metadata-generator.c @@ -0,0 +1,106 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#include "ep.h" + +/* + * EventPipeMetadataGenerator. + */ + +uint8_t * +ep_metadata_generator_generate_event_metadata ( + uint32_t event_id, + const ep_char16_t *event_name, + uint64_t keywords, + uint32_t version, + EventPipeEventLevel level, + EventPipeParameterDesc *params, + uint32_t params_len, + size_t *metadata_len) +{ + ep_return_null_if_nok (event_name != NULL); + ep_return_null_if_nok (params_len == 0 || params != NULL); + ep_return_null_if_nok (metadata_len != NULL); + + // The order of fields is defined in coreclr\src\mscorlib\shared\System\Diagnostics\Tracing\EventSource.cs DefineEventPipeEvents method + // eventID : 4 bytes + // eventName : (eventName.Length + 1) * 2 bytes + // keywords : 8 bytes + // eventVersion : 4 bytes + // level : 4 bytes + // parameterCount : 4 bytes + size_t event_name_len = ep_rt_utf16_string_len (event_name); + *metadata_len = 24 + ((event_name_len + 1) * sizeof (ep_char16_t)); + + // Each parameter has a 4 byte TypeCode + (parameterName.Length + 1) * 2 bytes. + for (uint32_t i = 0; i < params_len; ++i) { + EP_ASSERT (ep_parameter_desc_get_name (¶ms [i]) != NULL); + *metadata_len += (4 + ((ep_rt_utf16_string_len (ep_parameter_desc_get_name (¶ms [i])) + 1) * sizeof (ep_char16_t))); + } + + // Allocate a metadata blob. + uint8_t *buffer = ep_rt_byte_array_alloc (*metadata_len); + ep_raise_error_if_nok (buffer != NULL); + + uint8_t * current = buffer; + + // Write the event ID. + memcpy (current, &event_id, sizeof (event_id)); + current += sizeof (event_id); + + // Write the event name. + memcpy (current, event_name, (event_name_len + 1) * sizeof (ep_char16_t)); + current += (event_name_len + 1) * sizeof (ep_char16_t); + + // Write the keywords. + memcpy (current, &keywords, sizeof (keywords)); + current += sizeof (keywords); + + // Write the version. + memcpy (current, &version, sizeof (version)); + current += sizeof (version); + + // Write the level. + memcpy (current, &level, sizeof (level)); + current += sizeof (level); + + // Write the parameter count. + memcpy(current, ¶ms_len, sizeof (params_len)); + current += sizeof (params_len); + + // Write the parameter descriptions. + for (uint32_t i = 0; i < params_len; ++i) { + EventPipeParameterType const param_type = ep_parameter_desc_get_type (¶ms [i]); + const ep_char16_t *const param_name = ep_parameter_desc_get_name (¶ms [i]); + size_t const param_name_len = ep_rt_utf16_string_len (param_name); + + memcpy (current, ¶m_type, sizeof (param_type)); + current += sizeof (param_type); + + memcpy (current, param_name, (param_name_len + 1) * sizeof (ep_char16_t)); + current += (param_name_len + 1) * sizeof (ep_char16_t); + } + + EP_ASSERT (*metadata_len == (size_t)(current - buffer)); + +ep_on_exit: + return buffer; + +ep_on_error: + ep_rt_byte_array_free (buffer); + *metadata_len = 0; + + buffer = NULL; + ep_exit_error_handler (); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_metadata_generator; +const char quiet_linker_empty_file_warning_eventpipe_metadata_generator = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-metadata-generator.h b/src/mono/mono/eventpipe/ep-metadata-generator.h new file mode 100644 index 00000000000000..5f1d90a7ca27b1 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-metadata-generator.h @@ -0,0 +1,57 @@ +#ifndef __EVENTPIPE_METADATA_GENERATOR_H__ +#define __EVENTPIPE_METADATA_GENERATOR_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +/* + * EventPipeMetadataGenerator. + */ + +uint8_t * +ep_metadata_generator_generate_event_metadata ( + uint32_t event_id, + const ep_char16_t *event_name, + uint64_t keywords, + uint32_t version, + EventPipeEventLevel level, + EventPipeParameterDesc *params, + uint32_t params_len, + size_t *metadata_len); + +/* + * EventPipeParameterDesc. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeParameterDesc { +#else +struct _EventPipeParameterDesc_Internal { +#endif + EventPipeParameterType type; + const ep_char16_t *name; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeParameterDesc { + uint8_t _internal [sizeof (struct _EventPipeParameterDesc_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventPipeParameterDesc *, parameter_desc, EventPipeParameterType, type) +EP_DEFINE_GETTER(EventPipeParameterDesc *, parameter_desc, const ep_char16_t *, name) + +EventPipeParameterDesc * +ep_parameter_desc_init ( + EventPipeParameterDesc *parameter_desc, + EventPipeParameterType type, + const ep_char16_t *name); + +void +ep_parameter_desc_fini (EventPipeParameterDesc *parameter_desc); + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_METADATA_GENERATOR_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-provider-internals.c b/src/mono/mono/eventpipe/ep-provider-internals.c new file mode 100644 index 00000000000000..a93197ae766635 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-provider-internals.c @@ -0,0 +1,86 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#define EP_IMPL_GETTER_SETTER +#include "ep.h" + +/* + * Forward declares of all static functions. + */ + +static +void +event_free_func (void *ep_event); + +/* + * EventPipeProvider. + */ + +static +void +event_free_func (void *ep_event) +{ + ep_event_free ((EventPipeEvent *)ep_event); +} + +EventPipeProvider * +ep_provider_alloc ( + EventPipeConfiguration *config, + const ep_char8_t *provider_name, + EventPipeCallback callback_func, + void *callback_data) +{ + ep_return_false_if_nok (config != NULL && provider_name != NULL); + + EventPipeProvider *instance = ep_rt_object_alloc (EventPipeProvider); + ep_raise_error_if_nok (instance != NULL); + + instance->provider_name = ep_rt_utf8_string_dup (provider_name); + ep_raise_error_if_nok (instance->provider_name != NULL); + + instance->provider_name_utf16 = ep_rt_utf8_to_utf16_string (provider_name, ep_rt_utf8_string_len (provider_name)); + ep_raise_error_if_nok (instance->provider_name_utf16 != NULL); + + instance->keywords = 0; + instance->provider_level = EP_EVENT_LEVEL_CRITICAL; + instance->callback_func = callback_func; + instance->callback_data = callback_data; + instance->config = config; + instance->delete_deferred = false; + instance->sessions = 0; + +ep_on_exit: + return instance; + +ep_on_error: + ep_provider_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_provider_free (EventPipeProvider * provider) +{ + ep_return_void_if_nok (provider != NULL); + + //TODO: CoreCLR takes the lock before manipulating the list, but since complete object is + // going away and list is only owned by provider, meaning that if we had a race related + // to the list, it will crash anyways once lock is released and list is gone. + ep_rt_event_list_free (&provider->event_list, event_free_func); + + ep_rt_utf16_string_free (provider->provider_name_utf16); + ep_rt_utf8_string_free (provider->provider_name); + ep_rt_object_free (provider); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_provider_internals; +const char quiet_linker_empty_file_warning_eventpipe_provider_internals = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-provider.c b/src/mono/mono/eventpipe/ep-provider.c new file mode 100644 index 00000000000000..5e87cfbf7619d5 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-provider.c @@ -0,0 +1,317 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#include "ep.h" + +/* + * Forward declares of all static functions. + */ + +static +const EventPipeProviderCallbackData * +provider_prepare_callback_data ( + EventPipeProvider *provider, + int64_t keywords, + EventPipeEventLevel provider_level, + const ep_char8_t *filter_data, + EventPipeProviderCallbackData *provider_callback_data); + +static +void +provider_refresh_all_events (EventPipeProvider *provider); + +static +void +provider_refresh_event_state_lock_held (EventPipeEvent *ep_event); + +static +int64_t +provider_compute_event_enable_mask_lock_held ( + const EventPipeConfiguration *config, + const EventPipeProvider *provider, + int64_t keywords, + EventPipeEventLevel event_level); + +/* + * EventPipeProvider. + */ + +static +const EventPipeProviderCallbackData * +provider_prepare_callback_data ( + EventPipeProvider *provider, + int64_t keywords, + EventPipeEventLevel provider_level, + const ep_char8_t *filter_data, + EventPipeProviderCallbackData *provider_callback_data) +{ + EP_ASSERT (provider != NULL && provider_callback_data != NULL); + + return ep_provider_callback_data_init ( + provider_callback_data, + filter_data, + ep_provider_get_callback_func (provider), + ep_provider_get_callback_data (provider), + keywords, + provider_level, + (ep_provider_get_sessions (provider) != 0)); +} + +static +void +provider_refresh_all_events (EventPipeProvider *provider) +{ + EP_ASSERT (provider != NULL); + ep_rt_config_requires_lock_held (); + + const ep_rt_event_list_t *event_list = ep_provider_get_event_list_cref (provider); + EP_ASSERT (event_list != NULL); + + ep_rt_event_list_iterator_t iterator; + for (ep_rt_event_list_iterator_begin (event_list, &iterator); !ep_rt_provider_list_iterator_end (event_list, &iterator); ep_rt_provider_list_iterator_next (event_list, &iterator)) + provider_refresh_event_state_lock_held(ep_rt_event_list_iterator_value (&iterator)); + + ep_rt_config_requires_lock_held (); + return; +} + +static +void +provider_refresh_event_state_lock_held (EventPipeEvent *ep_event) +{ + ep_rt_config_requires_lock_held (); + EP_ASSERT (ep_event != NULL); + + EventPipeProvider *provider = ep_event_get_provider (ep_event); + EP_ASSERT (provider != NULL); + + EventPipeConfiguration *config = ep_provider_get_config (provider); + EP_ASSERT (config != NULL); + + int64_t enable_mask = provider_compute_event_enable_mask_lock_held (config, provider, ep_event_get_keywords (ep_event), ep_event_get_level (ep_event)); + ep_event_set_enabled_mask (ep_event, enable_mask); + + ep_rt_config_requires_lock_held (); + return; +} + +static +int64_t +provider_compute_event_enable_mask_lock_held ( + const EventPipeConfiguration *config, + const EventPipeProvider *provider, + int64_t keywords, + EventPipeEventLevel event_level) +{ + ep_rt_config_requires_lock_held (); + EP_ASSERT (provider != NULL); + + int64_t result = 0; + bool provider_enabled = ep_provider_get_enabled (provider); + for (int i = 0; i < EP_MAX_NUMBER_OF_SESSIONS; i++) { + // Entering EventPipe lock gave us a barrier, we don't need more of them. + EventPipeSession *session = ep_volatile_load_session_without_barrier (i); + if (session) { + EventPipeSessionProvider *session_provider = ep_config_get_session_provider_lock_held (config, session, provider); + if (session_provider) { + int64_t session_keyword = ep_session_provider_get_keywords (session_provider); + EventPipeEventLevel session_level = ep_session_provider_get_logging_level (session_provider); + // The event is enabled if: + // - The provider is enabled. + // - The event keywords are unspecified in the manifest (== 0) or when masked with the enabled config are != 0. + // - The event level is LogAlways or the provider's verbosity level is set to greater than the event's verbosity level in the manifest. + bool keyword_enabled = (keywords == 0) || ((session_keyword & keywords) != 0); + bool level_enabled = ((event_level == EP_EVENT_LEVEL_LOG_ALWAYS) || (session_level >= event_level)); + if (provider_enabled && keyword_enabled && level_enabled) + result = result | ep_session_get_mask (session); + } + } + } + + ep_rt_config_requires_lock_held (); + return result; +} + +EventPipeEvent * +ep_provider_add_event ( + EventPipeProvider *provider, + uint32_t event_id, + uint64_t keywords, + uint32_t event_version, + EventPipeEventLevel level, + bool need_stack, + const uint8_t *metadata, + uint32_t metadata_len) +{ + ep_rt_config_requires_lock_not_held (); + + ep_return_null_if_nok (provider != NULL); + + EventPipeEvent *instance = ep_event_alloc ( + provider, + keywords, + event_id, + event_version, + level, + need_stack, + metadata, + metadata_len); + + ep_return_null_if_nok (instance != NULL); + + // Take the config lock before inserting a new event. + EP_CONFIG_LOCK_ENTER + ep_rt_event_list_append (ep_provider_get_event_list_ref (provider), instance); + provider_refresh_event_state_lock_held (instance); + EP_CONFIG_LOCK_EXIT + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return instance; + +ep_on_error: + instance = NULL; + ep_exit_error_handler (); +} + +const EventPipeProviderCallbackData * +ep_provider_set_config_lock_held ( + EventPipeProvider *provider, + int64_t keywords_for_all_sessions, + EventPipeEventLevel level_for_all_sessions, + uint64_t session_mask, + int64_t keywords, + EventPipeEventLevel level, + const ep_char8_t *filter_data, + EventPipeProviderCallbackData *callback_data) +{ + ep_rt_config_requires_lock_held (); + + ep_return_null_if_nok (provider != NULL); + + EP_ASSERT ((ep_provider_get_sessions (provider) & session_mask) == 0); + ep_provider_set_sessions (provider, (ep_provider_get_sessions (provider) | session_mask)); + ep_provider_set_keywords (provider, keywords_for_all_sessions); + ep_provider_set_provider_level (provider, level_for_all_sessions); + + provider_refresh_all_events (provider); + provider_prepare_callback_data (provider, ep_provider_get_keywords (provider), ep_provider_get_provider_level (provider), filter_data, callback_data); + + ep_rt_config_requires_lock_held (); + return callback_data; +} + +const EventPipeProviderCallbackData * +ep_provider_unset_config_lock_held ( + EventPipeProvider *provider, + int64_t keywords_for_all_sessions, + EventPipeEventLevel level_for_all_sessions, + uint64_t session_mask, + int64_t keywords, + EventPipeEventLevel level, + const ep_char8_t *filter_data, + EventPipeProviderCallbackData *callback_data) +{ + ep_rt_config_requires_lock_held (); + + ep_return_null_if_nok (provider != NULL); + + EP_ASSERT ((ep_provider_get_sessions (provider) & session_mask) != 0); + if (ep_provider_get_sessions (provider) & session_mask) + ep_provider_set_sessions (provider, (ep_provider_get_sessions (provider) & ~session_mask)); + + ep_provider_set_keywords (provider, keywords_for_all_sessions); + ep_provider_set_provider_level (provider, level_for_all_sessions); + + provider_refresh_all_events (provider); + provider_prepare_callback_data (provider, ep_provider_get_keywords (provider), ep_provider_get_provider_level (provider), filter_data, callback_data); + + ep_rt_config_requires_lock_held (); + return callback_data; +} + +void +ep_provider_invoke_callback (EventPipeProviderCallbackData *provider_callback_data) +{ + // Lock should not be held when invoking callback. + ep_rt_config_requires_lock_not_held (); + + ep_return_void_if_nok (provider_callback_data != NULL); + + const ep_char8_t *filter_data = ep_provider_callback_data_get_filter_data (provider_callback_data); + EventPipeCallback callback_function = ep_provider_callback_data_get_callback_function (provider_callback_data); + bool enabled = ep_provider_callback_data_get_enabled (provider_callback_data); + int64_t keywords = ep_provider_callback_data_get_keywords (provider_callback_data); + EventPipeEventLevel provider_level = ep_provider_callback_data_get_provider_level (provider_callback_data); + void *callback_data = ep_provider_callback_data_get_callback_data (provider_callback_data); + + bool is_event_filter_desc_init = false; + EventFilterDescriptor event_filter_desc; + uint8_t *buffer = NULL; + + if (filter_data) { + // The callback is expecting that filter data to be a concatenated list + // of pairs of null terminated strings. The first member of the pair is + // the key and the second is the value. + // To convert to this format we need to convert all '=' and ';' + // characters to '\0', except when in a quoted string. + const uint32_t filter_data_len = ep_rt_utf8_string_len (filter_data); + uint32_t buffer_size = filter_data_len + 1; + + buffer = ep_rt_byte_array_alloc (buffer_size); + ep_raise_error_if_nok (buffer != NULL); + + bool is_quoted_value = false; + uint32_t j = 0; + + for (uint32_t i = 0; i < buffer_size; ++i) { + // if a value is a quoted string, leave the quotes out from the destination + // and don't replace `=` or `;` characters until leaving the quoted section + // e.g., key="a;value=";foo=bar --> { key\0a;value=\0foo\0bar\0 } + if (filter_data [i] == '"') { + is_quoted_value = !is_quoted_value; + continue; + } + buffer [j++] = ((filter_data [i] == '=' || filter_data [i] == ';') && !is_quoted_value) ? '\0' : filter_data [i]; + } + + // In case we skipped over quotes in the filter string, shrink the buffer size accordingly + if (j < filter_data_len) + buffer_size = j + 1; + + ep_event_filter_desc_init (&event_filter_desc, (uint64_t)buffer, buffer_size, 0); + is_event_filter_desc_init = true; + } + + if (callback_function && !ep_rt_process_detach ()) { + (*callback_function)( + NULL, /* provider_id */ + enabled ? 1 : 0, + (uint8_t)provider_level, + (uint64_t)keywords, + 0, /* match_all_keywords */ + is_event_filter_desc_init ? &event_filter_desc : NULL, + callback_data /* CallbackContext */); + } + +ep_on_exit: + if (is_event_filter_desc_init) + ep_event_filter_desc_fini (&event_filter_desc); + + ep_rt_byte_array_free (buffer); + return; + +ep_on_error: + ep_exit_error_handler (); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_provider; +const char quiet_linker_empty_file_warning_eventpipe_provider = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-provider.h b/src/mono/mono/eventpipe/ep-provider.h new file mode 100644 index 00000000000000..3d95ec81223825 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-provider.h @@ -0,0 +1,123 @@ +#ifndef __EVENTPIPE_PROVIDER_H__ +#define __EVENTPIPE_PROVIDER_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +/* + * EventPipeProvider. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeProvider { +#else +struct _EventPipeProvider_Internal { +#endif + ep_char8_t *provider_name; + ep_char16_t *provider_name_utf16; + int64_t keywords; + EventPipeEventLevel provider_level; + ep_rt_event_list_t event_list; + EventPipeCallback callback_func; + void *callback_data; + EventPipeConfiguration *config; + bool delete_deferred; + uint64_t sessions; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeProvider { + uint8_t _internal [sizeof (struct _EventPipeProvider_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventPipeProvider *, provider, const ep_char8_t *, provider_name) +EP_DEFINE_GETTER(EventPipeProvider *, provider, const ep_char16_t *, provider_name_utf16) +EP_DEFINE_GETTER(EventPipeProvider *, provider, uint64_t, keywords) +EP_DEFINE_SETTER(EventPipeProvider *, provider, uint64_t, keywords) +EP_DEFINE_GETTER(EventPipeProvider *, provider, EventPipeEventLevel, provider_level) +EP_DEFINE_SETTER(EventPipeProvider *, provider, EventPipeEventLevel, provider_level) +EP_DEFINE_GETTER_REF(EventPipeProvider *, provider, ep_rt_event_list_t *, event_list) +EP_DEFINE_GETTER(EventPipeProvider *, provider, EventPipeCallback, callback_func) +EP_DEFINE_GETTER(EventPipeProvider *, provider, void *, callback_data) +EP_DEFINE_GETTER(EventPipeProvider *, provider, EventPipeConfiguration *, config) +EP_DEFINE_GETTER(EventPipeProvider *, provider, bool, delete_deferred) +EP_DEFINE_SETTER(EventPipeProvider *, provider, bool, delete_deferred) +EP_DEFINE_GETTER(EventPipeProvider *, provider, uint64_t, sessions) +EP_DEFINE_SETTER(EventPipeProvider *, provider, uint64_t, sessions) + +static +inline +bool +ep_provider_get_enabled (const EventPipeProvider *provider) +{ + return ep_provider_get_sessions (provider) != 0; +} + +static +inline +const ep_char8_t * +ep_provider_get_wildcard_name_utf8 (void) +{ + return "*"; +} + +static +inline +const ep_char8_t * +ep_provider_get_default_name_utf8 (void) +{ + return "Microsoft-DotNETCore-EventPipe"; +} + +EventPipeProvider * +ep_provider_alloc ( + EventPipeConfiguration *config, + const ep_char8_t *provider_name, + EventPipeCallback callback_func, + void *callback_data); + +void +ep_provider_free (EventPipeProvider * provider); + +EventPipeEvent * +ep_provider_add_event ( + EventPipeProvider *provider, + uint32_t event_id, + uint64_t keywords, + uint32_t event_version, + EventPipeEventLevel level, + bool need_stack, + const uint8_t *metadata, + uint32_t metadata_len); + +const EventPipeProviderCallbackData * +ep_provider_set_config_lock_held ( + EventPipeProvider *provider, + int64_t keywords_for_all_sessions, + EventPipeEventLevel level_for_all_sessions, + uint64_t session_mask, + int64_t keywords, + EventPipeEventLevel level, + const ep_char8_t *filter_data, + EventPipeProviderCallbackData *callback_data); + +const EventPipeProviderCallbackData * +ep_provider_unset_config_lock_held ( + EventPipeProvider *provider, + int64_t keywords_for_all_sessions, + EventPipeEventLevel level_for_all_sessions, + uint64_t session_mask, + int64_t keywords, + EventPipeEventLevel level, + const ep_char8_t *filter_data, + EventPipeProviderCallbackData *callback_data); + +void +ep_provider_invoke_callback (EventPipeProviderCallbackData *provider_callback_data); + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_PROVIDER_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-rt-config-mono.h b/src/mono/mono/eventpipe/ep-rt-config-mono.h new file mode 100644 index 00000000000000..0e5eb527c2f78a --- /dev/null +++ b/src/mono/mono/eventpipe/ep-rt-config-mono.h @@ -0,0 +1,7 @@ +#ifndef __EVENTPIPE_RT_CONFIG_MONO_H__ +#define __EVENTPIPE_RT_CONFIG_MONO_H__ + +#include +#define EP_RT_MONO_USE_STATIC_RUNTIME + +#endif /* __EVENTPIPE_RT_CONFIG_MONO_H__ */ diff --git a/src/mono/mono/eventpipe/ep-rt-config.h b/src/mono/mono/eventpipe/ep-rt-config.h new file mode 100644 index 00000000000000..5c1499ca72c89f --- /dev/null +++ b/src/mono/mono/eventpipe/ep-rt-config.h @@ -0,0 +1,9 @@ +#ifndef __EVENTPIPE_RT_CONFIG_H__ +#define __EVENTPIPE_RT_CONFIG_H__ + +#include "ep-rt-config-mono.h" + +#define EP_INLINE_GETTER_SETTER +#define EP_INCLUDE_SOURCE_FILES + +#endif /* __EVENTPIPE_RT_CONFIG_H__ */ diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c new file mode 100644 index 00000000000000..26d3df4a2fda6a --- /dev/null +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -0,0 +1,14 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" + +#include "ep.h" + +ep_rt_spin_lock_handle_t _ep_rt_mono_config_lock = {0}; +EventPipeMonoFuncTable _ep_rt_mono_func_table = {0}; + +#endif /* ENABLE_PERFTRACING */ + +extern const char quiet_linker_empty_file_warning_eventpipe_rt_mono; +const char quiet_linker_empty_file_warning_eventpipe_rt_mono = 0; diff --git a/src/mono/mono/eventpipe/ep-rt-mono.h b/src/mono/mono/eventpipe/ep-rt-mono.h new file mode 100644 index 00000000000000..8bcb8a1b39505c --- /dev/null +++ b/src/mono/mono/eventpipe/ep-rt-mono.h @@ -0,0 +1,1108 @@ +// Implementation of ep-rt.h targeting Mono runtime. +#ifndef __EVENTPIPE_RT_MONO_H__ +#define __EVENTPIPE_RT_MONO_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "ep.h" + +#undef EP_ARRAY_SIZE +#define EP_ARRAY_SIZE(expr) G_N_ELEMENTS(expr) + +#undef EP_INFINITE_WAIT +#define EP_INFINITE_WAIT MONO_INFINITE_WAIT + +//TODO: Should make sure block is executed in safe mode. +#undef EP_GCX_PREEMP_ENTER +#define EP_GCX_PREEMP_ENTER { + +//TODO: Should make sure block is returned back to previous mode. +#undef EP_GCX_PREEMP_EXIT +#define EP_GCX_PREEMP_EXIT } + +#define EP_RT_DEFINE_LIST(list_name, list_type, item_type) \ + static inline void ep_rt_ ## list_name ## _free (list_type *list, void (*callback)(void *)) { \ + for (GSList *l = list->list; l; l = l->next) { \ + if (callback != NULL) \ + callback (l->data); \ + } \ + g_slist_free (list->list); \ + list->list = NULL; \ + } \ + static inline void ep_rt_ ## list_name ## _clear (list_type *list, void (*callback)(void *)) { ep_rt_ ## list_name ## _free (list, callback); } \ + static inline void ep_rt_ ## list_name ## _append (list_type *list, item_type item) { list->list = g_slist_append (list->list, ((gpointer)(gsize)item)); } \ + static inline void ep_rt_ ## list_name ## _remove (list_type *list, const item_type item) { list->list = g_slist_remove (list->list, ((gconstpointer)(const gsize)item)); } \ + static inline bool ep_rt_ ## list_name ## _find (const list_type *list, const item_type item_to_find, item_type *found_item) { \ + GSList *found_glist_item = g_slist_find (list->list, ((gconstpointer)(const gsize)item_to_find)); \ + *found_item = (found_glist_item != NULL) ? ((item_type)(gsize)(found_glist_item->data)) : ((item_type)(gsize)NULL); \ + return *found_item != NULL; \ + } \ + static inline bool ep_rt_ ## list_name ## _is_empty (const list_type *list) { return list->list == NULL; } + +#define EP_RT_DEFINE_LIST_ITERATOR(list_name, list_type, iterator_type, item_type) \ + static inline void ep_rt_ ## list_name ## _iterator_begin (const list_type *list, iterator_type *iterator) { iterator->iterator = list->list; } \ + static inline bool ep_rt_ ## list_name ## _iterator_end (const list_type *list, const iterator_type *iterator) { return iterator->iterator == NULL; } \ + static inline void ep_rt_ ## list_name ## _iterator_next (const list_type *list, iterator_type *iterator) { iterator->iterator = iterator->iterator->next; } \ + static inline item_type ep_rt_ ## list_name ## _iterator_value (const iterator_type *iterator) { return ((item_type)(gsize)(iterator->iterator->data)); } + +#define EP_RT_DEFINE_QUEUE(queue_name, queue_type, item_type) \ + static inline void ep_rt_ ## queue_name ## _alloc (queue_type *queue) { \ + queue->queue = g_queue_new ();\ + } \ + static inline void ep_rt_ ## queue_name ## _free (queue_type *queue) { \ + g_queue_free (queue->queue); \ + queue->queue = NULL; \ + } \ + static inline void ep_rt_ ## queue_name ## _pop_head (queue_type *queue, item_type *item) { \ + *item = ((item_type)(gsize)g_queue_pop_head (queue->queue)); \ + } \ + static inline void ep_rt_ ## queue_name ## _push_head (queue_type *queue, item_type item) { \ + g_queue_push_head (queue->queue, ((gpointer)(gsize)item)); \ + } \ + static inline void ep_rt_ ## queue_name ## _push_tail (queue_type *queue, item_type item) { \ + g_queue_push_tail (queue->queue, ((gpointer)(gsize)item)); \ + } \ + static inline bool ep_rt_ ## queue_name ## _is_empty (const queue_type *queue) { \ + return g_queue_is_empty (queue->queue); \ + } + +#define EP_RT_DEFINE_HASH_MAP(hash_map_name, hash_map_type, key_type, value_type) \ + static inline void ep_rt_ ## hash_map_name ## _alloc (hash_map_type *hash_map, uint32_t (*hash_callback)(const void *), bool (*eq_callback)(const void *, const void *), void (*key_free_callback)(void *), void (*value_free_callback)(void *)) { \ + hash_map->table = g_hash_table_new_full ((GHashFunc)hash_callback, (GEqualFunc)eq_callback, (GDestroyNotify)key_free_callback, (GDestroyNotify)value_free_callback); \ + hash_map->count = 0;\ + } \ + static inline void ep_rt_ ## hash_map_name ## _free (hash_map_type *hash_map) { \ + g_hash_table_destroy (hash_map->table); \ + hash_map->table = NULL; \ + hash_map->count = 0; \ + } \ + static inline void ep_rt_ ## hash_map_name ## _add (hash_map_type *hash_map, key_type key, value_type value) { \ + g_hash_table_replace (hash_map->table, (gpointer)key, ((gpointer)(gsize)value)); \ + hash_map->count++; \ + } \ + static inline void ep_rt_ ## hash_map_name ## _remove (hash_map_type *hash_map, const key_type key) { \ + if (g_hash_table_remove (hash_map->table, (gconstpointer)key)) \ + hash_map->count--; \ + } \ + static inline void ep_rt_ ## hash_map_name ## _remove_all (hash_map_type *hash_map) { \ + g_hash_table_remove_all (hash_map->table); \ + hash_map->count = 0; \ + } \ + static inline bool ep_rt_ ## hash_map_name ## _lookup (const hash_map_type *hash_map, const key_type key, value_type *value) { \ + gpointer _value = NULL; \ + bool result = g_hash_table_lookup_extended (hash_map->table, (gconstpointer)key, NULL, &_value); \ + *value = ((value_type)(gsize)_value); \ + return result; \ + } \ + static inline uint32_t ep_rt_ ## hash_map_name ## _count (const hash_map_type *hash_map) { \ + return hash_map->count; \ + } + +#define EP_RT_DEFINE_HASH_MAP_ITERATOR(hash_map_name, hash_map_type, iterator_type, key_type, value_type) \ + static inline void ep_rt_ ## hash_map_name ## _iterator_begin (const hash_map_type *hash_map, iterator_type *iterator) { \ + g_hash_table_iter_init (&iterator->iterator, hash_map->table); \ + if (hash_map->table) \ + iterator->end = g_hash_table_iter_next (&iterator->iterator, &iterator->key, &iterator->value); \ + else \ + iterator->end = true; \ + } \ + static inline bool ep_rt_ ## hash_map_name ## _iterator_end (const hash_map_type *hash_map, const iterator_type *iterator) { \ + return iterator->end; \ + } \ + static inline void ep_rt_ ## hash_map_name ## _iterator_next (const hash_map_type *hash_map, iterator_type *iterator) { \ + iterator->end = g_hash_table_iter_next (&iterator->iterator, &iterator->key, &iterator->value); \ + } \ + static inline key_type ep_rt_ ## hash_map_name ## _iterator_key (const iterator_type *iterator) { \ + return ((key_type)(gsize)iterator->key); \ + } \ + static inline value_type ep_rt_ ## hash_map_name ## _iterator_value (const iterator_type *iterator) { \ + return ((value_type)(gsize)iterator->value); \ + } + +typedef gint64 (*ep_rt_mono_100ns_ticks_func)(void); +typedef gint64 (*ep_rt_mono_100ns_datetime_func)(void); +typedef int (*ep_rt_mono_cpu_count_func)(void); +typedef int (*ep_rt_mono_process_current_pid_func)(void); +typedef MonoNativeThreadId (*ep_rt_mono_native_thread_id_get_func)(void); +typedef gboolean (*ep_rt_mono_native_thread_id_equals_func)(MonoNativeThreadId, MonoNativeThreadId); +typedef mono_bool (*ep_rt_mono_runtime_is_shutting_down_func)(void); +typedef gboolean (*ep_rt_mono_rand_try_get_bytes_func)(guchar *buffer, gssize buffer_size, MonoError *error); +typedef EventPipeThread * (*ep_rt_mono_thread_get_func)(void); +typedef EventPipeThread * (*ep_rt_mono_thread_get_or_create_func)(void); +typedef void (*ep_rt_mono_thread_exited_func)(void); +typedef gpointer (*ep_rt_mono_w32file_create_func)(const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs); +typedef gboolean (*ep_rt_mono_w32file_write_func)(gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error); +typedef gboolean (*ep_rt_mono_w32file_close_func)(gpointer handle); + +typedef struct _EventPipeMonoFuncTable { + ep_rt_mono_100ns_ticks_func ep_rt_mono_100ns_ticks; + ep_rt_mono_100ns_datetime_func ep_rt_mono_100ns_datetime; + ep_rt_mono_process_current_pid_func ep_rt_mono_process_current_pid; + ep_rt_mono_cpu_count_func ep_rt_mono_cpu_count; + ep_rt_mono_native_thread_id_get_func ep_rt_mono_native_thread_id_get; + ep_rt_mono_native_thread_id_equals_func ep_rt_mono_native_thread_id_equals; + ep_rt_mono_runtime_is_shutting_down_func ep_rt_mono_runtime_is_shutting_down; + ep_rt_mono_rand_try_get_bytes_func ep_rt_mono_rand_try_get_bytes; + ep_rt_mono_thread_get_func ep_rt_mono_thread_get; + ep_rt_mono_thread_get_or_create_func ep_rt_mono_thread_get_or_create; + ep_rt_mono_thread_exited_func ep_rt_mono_thread_exited; + ep_rt_mono_w32file_create_func ep_rt_mono_w32file_create; + ep_rt_mono_w32file_write_func ep_rt_mono_w32file_write; + ep_rt_mono_w32file_close_func ep_rt_mono_w32file_close; +} EventPipeMonoFuncTable; + +typedef EventPipeThreadHolder * (*ep_rt_thread_holder_alloc_func)(void); +typedef void (*ep_rt_thread_holder_free_func)(EventPipeThreadHolder *thread_holder); + +static +inline +ep_rt_spin_lock_handle_t * +ep_rt_mono_config_lock_get (void) +{ + extern ep_rt_spin_lock_handle_t _ep_rt_mono_config_lock; + return &_ep_rt_mono_config_lock; +} + +static +inline +EventPipeMonoFuncTable * +ep_rt_mono_func_table_get (void) +{ + extern EventPipeMonoFuncTable _ep_rt_mono_func_table; + return &_ep_rt_mono_func_table; +} + +MONO_PROFILER_API +void +mono_eventpipe_init ( + EventPipeMonoFuncTable *table, + ep_rt_thread_holder_alloc_func thread_holder_alloc_func, + ep_rt_thread_holder_free_func thread_holder_free_func); + +MONO_PROFILER_API +void +mono_eventpipe_fini (void); + +/* +* Helpers +*/ + +static +inline +MonoNativeThreadId +ep_rt_mono_native_thread_id_get (void) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + return mono_native_thread_id_get (); +#else + return ep_rt_mono_func_table_get ()->ep_rt_mono_native_thread_id_get (); +#endif +} + +static +inline +gboolean +ep_rt_mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + return mono_native_thread_id_equals (id1, id2); +#else + return ep_rt_mono_func_table_get ()->ep_rt_mono_native_thread_id_equals (id1, id2); +#endif +} + +static +inline +gboolean +ep_rt_mono_rand_try_get_bytes (guchar *buffer, gssize buffer_size, MonoError *error) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + extern gpointer ep_rt_mono_rand_provider; + g_assert (ep_rt_mono_rand_provider != NULL); + return mono_rand_try_get_bytes (&ep_rt_mono_rand_provider, buffer, buffer_size, error); +#else + return ep_rt_mono_func_table_get ()->ep_rt_mono_rand_try_get_bytes (buffer, buffer_size, error); +#endif +} + +static +inline +void +ep_rt_mono_thread_exited (void) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + extern gboolean ep_rt_mono_initialized; + extern MonoNativeTlsKey ep_rt_mono_thread_holder_tls_id; + if (ep_rt_mono_initialized) { + EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (ep_rt_mono_thread_holder_tls_id); + if (thread_holder) + ep_thread_holder_free (thread_holder); + mono_native_tls_set_value (ep_rt_mono_thread_holder_tls_id, NULL); + } +#else + ep_rt_mono_func_table_get ()->ep_rt_mono_thread_exited (); +#endif +} + +static +inline +gpointer +ep_rt_mono_w32file_create (const gunichar2 *name, guint32 fileaccess, guint32 sharemode, guint32 createmode, guint32 attrs) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + return mono_w32file_create (name, fileaccess, sharemode, createmode, attrs); +#else + return ep_rt_mono_func_table_get ()->ep_rt_mono_w32file_create (name, fileaccess, sharemode, createmode, attrs); +#endif +} + +static +inline +gboolean +ep_rt_mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, guint32 *byteswritten, gint32 *win32error) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + return mono_w32file_write (handle, buffer, numbytes, byteswritten, win32error); +#else + return ep_rt_mono_func_table_get ()->ep_rt_mono_w32file_write (handle, buffer, numbytes, byteswritten, win32error); +#endif +} + +static +inline +gboolean +ep_rt_mono_w32file_close (gpointer handle) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + return mono_w32file_close (handle); +#else + return ep_rt_mono_func_table_get ()->ep_rt_mono_w32file_close (handle); +#endif +} + +/* +* Atomics. +*/ + +static +inline +uint32_t +ep_rt_atomic_inc_uint32_t (volatile uint32_t *value) +{ + return (uint32_t)mono_atomic_inc_i32 ((volatile gint32 *)value); +} + +static +inline +uint32_t +ep_rt_atomic_dec_uint32_t (volatile uint32_t *value) +{ + return (uint32_t)mono_atomic_dec_i32 ((volatile gint32 *)value); +} + +static +inline +int32_t +ep_rt_atomic_inc_int32_t (volatile int32_t *value) +{ + return (int32_t)mono_atomic_inc_i32 ((volatile gint32 *)value); +} + +static +inline +int32_t +ep_rt_atomic_dec_int32_t (volatile int32_t *value) +{ + return (int32_t)mono_atomic_dec_i32 ((volatile gint32 *)value); +} + +/* + * EventPipe. + */ + +static +EventPipeThreadHolder * +thread_holder_alloc_func (void) +{ + return ep_thread_holder_alloc (ep_thread_alloc()); +} + +static +void +thread_holder_free_func (EventPipeThreadHolder * thread_holder) +{ + ep_thread_holder_free (thread_holder); +} + +static +inline +void +ep_rt_init (void) +{ + mono_eventpipe_init (ep_rt_mono_func_table_get (), thread_holder_alloc_func, thread_holder_free_func); + ep_rt_spin_lock_alloc (ep_rt_mono_config_lock_get ()); +} + +static +inline +void +ep_rt_shutdown (void) +{ + ep_rt_spin_lock_free (ep_rt_mono_config_lock_get ()); + mono_eventpipe_fini (); +} + +static +inline +bool +ep_rt_config_aquire (void) +{ + ep_rt_spin_lock_aquire (ep_rt_mono_config_lock_get ()); + return true; +} + +static +inline +void +ep_rt_config_release (void) +{ + ep_rt_spin_lock_release (ep_rt_mono_config_lock_get ()); +} + +#ifdef EP_CHECKED_BUILD +static +inline +void +ep_rt_config_requires_lock_held (void) +{ + ep_rt_spin_lock_requires_lock_held (ep_rt_mono_config_lock_get ()); +} + +static +inline +void +ep_rt_config_requires_lock_not_held (void) +{ + ep_rt_spin_lock_requires_lock_not_held (ep_rt_mono_config_lock_get ()); +} +#endif + +/* + * EventPipeEvent. + */ + +EP_RT_DEFINE_LIST (event_list, ep_rt_event_list_t, EventPipeEvent *) +EP_RT_DEFINE_LIST_ITERATOR (event_list, ep_rt_event_list_t, ep_rt_event_list_iterator_t, EventPipeEvent *) + +/* + * EventPipeFile. + */ + +EP_RT_DEFINE_HASH_MAP(metadata_labels, ep_rt_metadata_labels_hash_map_t, EventPipeEvent *, uint32_t) +EP_RT_DEFINE_HASH_MAP(stack_hash, ep_rt_stack_hash_map_t, StackHashKey *, StackHashEntry *) +EP_RT_DEFINE_HASH_MAP_ITERATOR(stack_hash, ep_rt_stack_hash_map_t, ep_rt_stack_hash_map_iterator_t, StackHashKey *, StackHashEntry *) + +/* + * EventPipeProvider. + */ + +EP_RT_DEFINE_LIST (provider_list, ep_rt_provider_list_t, EventPipeProvider *) +EP_RT_DEFINE_LIST_ITERATOR (provider_list, ep_rt_provider_list_t, ep_rt_provider_list_iterator_t, EventPipeProvider *) + +EP_RT_DEFINE_QUEUE (provider_callback_data_queue, ep_rt_provider_callback_data_queue_t, EventPipeProviderCallbackData *) + +static +inline +int +compare_provider_name ( + gconstpointer a, + gconstpointer b) +{ + return (a) ? ep_rt_utf8_string_compare (ep_provider_get_provider_name ((EventPipeProvider *)a), (const ep_char8_t *)b) : 1; +} + +static +inline +EventPipeProvider * +ep_rt_provider_list_find_by_name ( + const ep_rt_provider_list_t *list, + const ep_char8_t *name) +{ + GSList *item = g_slist_find_custom (list->list, name, compare_provider_name); + return (item != NULL) ? (EventPipeProvider *)item->data : NULL; +} + +/* + * EventPipeSampleProfiler. + */ + +static +inline +void +ep_rt_sample_profiler_init (EventPipeProviderCallbackDataQueue *provider_callback_data_queue) +{ + //TODO: Not supported. +} + +static +inline +void +ep_rt_sample_profiler_enable (void) +{ + //TODO: Not supported. +} + +static +inline +void +ep_rt_sample_profiler_disable (void) +{ + //TODO: Not supported. +} + +static +uint32_t +ep_rt_sample_profiler_get_sampling_rate (void) +{ + //TODO: Not supported. + return 0; +} + +/* + * EvetPipeSessionProvider. + */ + +EP_RT_DEFINE_LIST (session_provider_list, ep_rt_session_provider_list_t, EventPipeSessionProvider *) +EP_RT_DEFINE_LIST_ITERATOR (session_provider_list, ep_rt_session_provider_list_t, ep_rt_session_provider_list_iterator_t, EventPipeSessionProvider *) + +static +inline +int +compare_session_provider_name ( + gconstpointer a, + gconstpointer b) +{ + return (a) ? ep_rt_utf8_string_compare (ep_session_provider_get_provider_name ((EventPipeSessionProvider *)a), (const ep_char8_t *)b) : 1; +} + +static +inline +EventPipeSessionProvider * +ep_rt_session_provider_list_find_by_name ( + const ep_rt_session_provider_list_t *list, + const ep_char8_t *name) +{ + GSList *item = g_slist_find_custom (list->list, name, compare_provider_name); + return (item != NULL) ? (EventPipeSessionProvider *)item->data : NULL; +} + +/* + * Arrays. + */ + +static +inline +uint8_t * +ep_rt_byte_array_alloc (size_t len) +{ + return g_new(uint8_t, len); +} + +static +inline +void +ep_rt_byte_array_free (uint8_t *ptr) +{ + g_free (ptr); +} + +/* + * Event. + */ + +static +inline +void +ep_rt_wait_event_alloc (ep_rt_wait_event_handle_t *wait_event) +{ + EP_ASSERT (wait_event != NULL); + wait_event->event = g_new0 (MonoOSEvent, 1); + if (wait_event->event) + mono_os_event_init (wait_event->event, false); +} + +static +inline +void +ep_rt_wait_event_free (ep_rt_wait_event_handle_t *wait_event) +{ + if (wait_event != NULL && wait_event->event != NULL) { + mono_os_event_destroy (wait_event->event); + g_free (wait_event->event); + wait_event->event = NULL; + } +} + +static +inline +bool +ep_rt_wait_event_set (ep_rt_wait_event_handle_t *wait_event) +{ + EP_ASSERT (wait_event != NULL && wait_event->event != NULL); + mono_os_event_set (wait_event->event); + return true; +} + +static +inline +int32_t +ep_rt_wait_event_wait ( + ep_rt_wait_event_handle_t *wait_event, + uint32_t timeout, + bool alertable) +{ + EP_ASSERT (wait_event != NULL && wait_event->event != NULL); + return mono_os_event_wait_one (wait_event->event, timeout, alertable); +} + +static +inline +EventPipeWaitHandle +ep_rt_wait_event_get_wait_handle (ep_rt_wait_event_handle_t *wait_event) +{ + EP_ASSERT (wait_event != NULL); + return (EventPipeWaitHandle)wait_event; +} + +/* + * Misc. + */ + +static +inline +bool +ep_rt_process_detach (void) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + return (bool)mono_runtime_is_shutting_down (); +#else + return (bool)ep_rt_mono_func_table_get ()->ep_rt_mono_runtime_is_shutting_down (); +#endif +} + +static +inline +void +ep_rt_create_activity_id ( + uint8_t *activity_id, + uint32_t activity_id_len) +{ + EP_ASSERT (activity_id_len == EP_ACTIVITY_ID_SIZE); + + ERROR_DECL (error); + ep_rt_mono_rand_try_get_bytes ((guchar *)activity_id, EP_ACTIVITY_ID_SIZE, error); + + const uint16_t version_mask = 0xF000; + const uint16_t random_guid_version = 0x4000; + const uint8_t clock_seq_hi_and_reserved_mask = 0xC0; + const uint8_t clock_seq_hi_and_reserved_value = 0x80; + + // Modify bits indicating the type of the GUID + uint8_t *activity_id_c = activity_id + sizeof (uint32_t) + sizeof (uint16_t); + uint8_t *activity_id_d = activity_id + sizeof (uint32_t) + sizeof (uint16_t) + sizeof (uint16_t); + + uint16_t c; + memcpy (&c, activity_id_c, sizeof (c)); + + uint8_t d; + memcpy (&d, activity_id_d, sizeof (d)); + + // time_hi_and_version + c = ((c & ~version_mask) | random_guid_version); + // clock_seq_hi_and_reserved + d = ((d & ~clock_seq_hi_and_reserved_mask) | clock_seq_hi_and_reserved_value); + + memcpy (activity_id_c, &c, sizeof (c)); + memcpy (activity_id_d, &d, sizeof (d)); +} + +/* + * Objects. + */ + +#undef ep_rt_object_alloc +#define ep_rt_object_alloc(obj_type) (g_new0 (obj_type, 1)) + +static +inline +void +ep_rt_object_free (void *ptr) +{ + g_free (ptr); +} + +/* + * PAL. + */ + +static +inline +uint32_t +ep_rt_current_process_get_id (void) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + return (uint32_t)mono_process_current_pid (); +#else + return (uint32_t)ep_rt_mono_func_table_get ()->ep_rt_mono_process_current_pid (); +#endif +} + +static +inline +uint32_t +ep_rt_current_processor_get_number (void) +{ + return 0xFFFFFFFF; +} + +static +inline +uint32_t +ep_rt_processors_get_count (void) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + return (uint32_t)mono_cpu_count (); +#else + return (uint32_t)ep_rt_mono_func_table_get ()->ep_rt_mono_cpu_count (); +#endif +} + +static +inline +size_t +ep_rt_current_thread_get_id (void) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + return MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()); +#else + return MONO_NATIVE_THREAD_ID_TO_UINT (ep_rt_mono_func_table_get ()->ep_rt_mono_native_thread_id_get ()); +#endif +} + +static +inline +uint64_t +ep_rt_perf_counter_query (void) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + return (uint64_t)mono_100ns_ticks (); +#else + return (uint64_t)ep_rt_mono_func_table_get ()->ep_rt_mono_100ns_ticks (); +#endif +} + +static +inline +uint64_t +ep_rt_perf_frequency_query (void) +{ + //Counter uses resolution of 100ns ticks. + return 100 * 1000 * 1000; +} + +static +inline +uint64_t +ep_rt_system_time_get (void) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + return (uint64_t)mono_100ns_datetime (); +#else + return (uint64_t)ep_rt_mono_func_table_get ()->ep_rt_mono_100ns_datetime (); +#endif +} + +static +inline +const ep_char8_t * +ep_rt_command_line_get (void) +{ + //TODO: Implement. + return ""; +} + +static +inline +ep_rt_file_handle_t +ep_rt_file_open_write (const ep_char8_t *path) +{ + ep_char16_t *path_utf16 = ep_rt_utf8_to_utf16_string (path, -1); + ep_return_null_if_nok (path_utf16 != NULL); + + gpointer file_handle = ep_rt_mono_w32file_create (path_utf16, GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, FileAttributes_Normal); + ep_rt_utf16_string_free (path_utf16); + + return file_handle; +} + +static +bool +ep_rt_file_close (ep_rt_file_handle_t file_handle) +{ + ep_return_false_if_nok (file_handle != NULL); + return ep_rt_mono_w32file_close (file_handle); +} + +static +bool +ep_rt_file_write ( + ep_rt_file_handle_t file_handle, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written) +{ + ep_return_false_if_nok (file_handle != NULL); + EP_ASSERT (buffer != NULL); + + gint32 win32_error; + bool result = ep_rt_mono_w32file_write (file_handle, buffer, bytes_to_write, bytes_written, &win32_error); + if (result) + *bytes_written = bytes_to_write; + + return result; +} + +/* +* SpinLock. +*/ + +static +inline +void +ep_rt_spin_lock_alloc (ep_rt_spin_lock_handle_t *spin_lock) +{ +#ifdef EP_CHECKED_BUILD + spin_lock->lock_is_held = false; +#endif + spin_lock->lock = g_new0 (MonoCoopMutex, 1); + if (spin_lock->lock) + mono_coop_mutex_init (spin_lock->lock); +} + +static +inline +void +ep_rt_spin_lock_free (ep_rt_spin_lock_handle_t *spin_lock) +{ + if (spin_lock && spin_lock->lock) { + mono_coop_mutex_destroy (spin_lock->lock); + g_free (spin_lock->lock); + spin_lock->lock = NULL; + } +} + +static +inline +void +ep_rt_spin_lock_aquire (ep_rt_spin_lock_handle_t *spin_lock) +{ + if (spin_lock && spin_lock->lock) { + mono_coop_mutex_lock (spin_lock->lock); +#ifdef EP_CHECKED_BUILD + spin_lock->owning_thread_id = ep_rt_mono_native_thread_id_get (); + spin_lock->lock_is_held = true; +#endif + } +} + +static +inline +void +ep_rt_spin_lock_release (ep_rt_spin_lock_handle_t *spin_lock) +{ + if (spin_lock && spin_lock->lock) { +#ifdef EP_CHECKED_BUILD + spin_lock->lock_is_held = false; +#endif + mono_coop_mutex_unlock (spin_lock->lock); + } +} + +#ifdef EP_CHECKED_BUILD +static +inline +void +ep_rt_spin_lock_requires_lock_held (const ep_rt_spin_lock_handle_t *spin_lock) +{ + g_assert (spin_lock->lock_is_held && ep_rt_mono_native_thread_id_equals (spin_lock->owning_thread_id, ep_rt_mono_native_thread_id_get ())); +} + +static +inline +void +ep_rt_spin_lock_requires_lock_not_held (const ep_rt_spin_lock_handle_t *spin_lock) +{ + g_assert (!spin_lock->lock_is_held || (spin_lock->lock_is_held && !ep_rt_mono_native_thread_id_equals (spin_lock->owning_thread_id, ep_rt_mono_native_thread_id_get ()))); +} +#endif + +/* + * String. + */ + +static +inline +size_t +ep_rt_utf8_string_len (const ep_char8_t *str) +{ + return g_utf8_strlen ((const gchar *)str, -1); +} + +static +inline +int +ep_rt_utf8_string_compare ( + const ep_char8_t *str1, + const ep_char8_t *str2) +{ + return strcmp ((const char *)str1, (const char *)str2); +} + +static +inline +ep_char16_t * +ep_rt_utf8_to_utf16_string ( + const ep_char8_t *str, + size_t len) +{ + return (ep_char16_t *)(g_utf8_to_utf16 ((const gchar *)str, len, NULL, NULL, NULL)); +} + +static +inline +ep_char8_t * +ep_rt_utf8_string_dup (const ep_char8_t *str) +{ + return g_strdup (str); +} + +static +inline +void +ep_rt_utf8_string_free (ep_char8_t *str) +{ + g_free (str); +} + +static +inline +size_t +ep_rt_utf16_string_len (const ep_char16_t *str) +{ + return g_utf16_len ((const gunichar2 *)str); +} + +static +inline +ep_char8_t * +ep_rt_utf16_to_utf8_string ( + const ep_char16_t *str, + size_t len) +{ + return g_utf16_to_utf8 ((const gunichar2 *)str, len, NULL, NULL, NULL); +} + +static +inline +void +ep_rt_utf16_string_free (ep_char16_t *str) +{ + g_free (str); +} + +static +inline +const ep_char8_t * +ep_rt_managed_command_line_get (void) +{ + //TODO: Implement. + return ""; +} + +/* + * Thread. + */ +static +inline +void +ep_rt_thread_setup (void) +{ + //TODO: Is this needed on Mono runtime? Looks like a thread attach, making sure thread is attached to runtime. +} + +static +inline +EventPipeThread * +ep_rt_thread_get (void) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + extern MonoNativeTlsKey ep_rt_mono_thread_holder_tls_id; + EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (ep_rt_mono_thread_holder_tls_id); + return thread_holder ? ep_thread_holder_get_thread (thread_holder) : NULL; +#else + return ep_rt_mono_func_table_get ()->ep_rt_mono_thread_get (); +#endif +} + +static +inline +EventPipeThread * +ep_rt_thread_get_or_create (void) +{ +#ifdef EP_RT_MONO_USE_STATIC_RUNTIME + extern MonoNativeTlsKey ep_rt_mono_thread_holder_tls_id; + EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (ep_rt_mono_thread_holder_tls_id); + if (!thread_holder) { + thread_holder = thread_holder_alloc_func (); + mono_native_tls_set_value (ep_rt_mono_thread_holder_tls_id, thread_holder); + } + return ep_thread_holder_get_thread (thread_holder); +#else + return ep_rt_mono_func_table_get ()->ep_rt_mono_thread_get_or_create (); +#endif +} + +/* + * ThreadSequenceNumberMap. + */ + +EP_RT_DEFINE_HASH_MAP(thread_sequence_number_map, ep_rt_thread_sequence_number_hash_map_t, EventPipeThreadSessionState *, uint32_t) +EP_RT_DEFINE_HASH_MAP_ITERATOR(thread_sequence_number_map, ep_rt_thread_sequence_number_hash_map_t, ep_rt_thread_sequence_number_hash_map_iterator_t, EventPipeThreadSessionState *, uint32_t) + +/* + * Volatile. + */ + +static +inline +uint32_t +ep_rt_volatile_load_uint32_t (const volatile uint32_t *ptr) +{ + return mono_atomic_load_i32 ((volatile gint32 *)ptr); +} + +static +inline +uint32_t +ep_rt_volatile_load_uint32_t_without_barrier (const volatile uint32_t *ptr) +{ + uint32_t value = *ptr; + return value; +} + +static +inline +void +ep_rt_volatile_store_uint32_t ( + volatile uint32_t *ptr, + uint32_t value) +{ + mono_atomic_store_i32 ((volatile gint32 *)ptr, (gint32)value); +} + +static +inline +void +ep_rt_volatile_store_uint32_t_without_barrier ( + volatile uint32_t *ptr, + uint32_t value) +{ + *ptr = value; +} + +static +inline +uint64_t +ep_rt_volatile_load_uint64_t (const volatile uint64_t *ptr) +{ + return mono_atomic_load_i64 ((volatile gint64 *)ptr); +} + +static +inline +uint64_t +ep_rt_volatile_load_uint64_t_without_barrier (const volatile uint64_t *ptr) +{ + uint64_t value = *ptr; + return value; +} + +static +inline +void +ep_rt_volatile_store_uint64_t ( + volatile uint64_t *ptr, + uint64_t value) +{ + mono_atomic_store_i64 ((volatile gint64 *)ptr, (gint64)value); +} + +static +inline +void +ep_rt_volatile_store_uint64_t_without_barrier ( + volatile uint64_t *ptr, + uint64_t value) +{ + *ptr = value; +} + +static +inline +void * +ep_rt_volatile_load_ptr (volatile void **ptr) +{ + return mono_atomic_load_ptr ((volatile gpointer *)ptr); +} + +static +inline +void * +ep_rt_volatile_load_ptr_without_barrier (volatile void **ptr) +{ + void *value = (void *)(*ptr); + return value; +} + +static +inline +void +ep_rt_volatile_store_ptr ( + volatile void **ptr, + void *value) +{ + mono_atomic_store_ptr ((volatile gpointer *)ptr, (gpointer)value); +} + +static +inline +void +ep_rt_volatile_store_ptr_without_barrier ( + volatile void **ptr, + void *value) +{ + *ptr = value; +} + +#endif /* ENABLE_PERFTRACING */ +#endif /* __EVENTPIPE_RT_MONO_H__ */ diff --git a/src/mono/mono/eventpipe/ep-rt-types-mono.h b/src/mono/mono/eventpipe/ep-rt-types-mono.h new file mode 100644 index 00000000000000..266f1ee25cd1f8 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-rt-types-mono.h @@ -0,0 +1,96 @@ +// Implementation of ep-rt-types.h targeting Mono runtime. +#ifndef __EVENTPIPE_RT_TYPES_MONO_H__ +#define __EVENTPIPE_RT_TYPES_MONO_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include +#include +#include +#include + +//#ifdef ENABLE_CHECKED_BUILD +#define EP_CHECKED_BUILD +//#endif + +#undef EP_ASSERT +//#define EP_ASSERT(expr) g_assert_checked(expr) +#define EP_ASSERT(expr) g_assert(expr) + +#undef EP_LIKELY +#define EP_LIKELY(expr) G_LIKELY(expr) + +#undef EP_UNLIKELY +#define EP_UNLIKELY(expr) G_UNLIKELY(expr) + +struct _rt_mono_list_internal_t { + GSList *list; +}; + +struct _rt_mono_list_iterator_internal_t { + GSList *iterator; +}; + +typedef struct _rt_mono_list_internal_t ep_rt_provider_list_t; +typedef struct _rt_mono_list_iterator_internal_t ep_rt_provider_list_iterator_t; + +typedef struct _rt_mono_list_internal_t ep_rt_event_list_t; +typedef struct _rt_mono_list_iterator_internal_t ep_rt_event_list_iterator_t; + +typedef struct _rt_mono_list_internal_t ep_rt_session_provider_list_t; +typedef struct _rt_mono_list_iterator_internal_t ep_rt_session_provider_list_iterator_t; + +struct _rt_mono_queue_internal_t { + GQueue *queue; +}; + +typedef struct _rt_mono_queue_internal_t ep_rt_provider_callback_data_queue_t; +typedef struct _rt_mono_queue_iterator_internal_t ep_rt_provider_callback_data_queue_iterator_t; + +struct _rt_mono_table_internal_t { + GHashTable *table; + uint32_t count; +}; + +struct _rt_mono_table_iterator_internal_t { + GHashTableIter iterator; + gpointer key; + gpointer value; + bool end; +}; + +typedef struct _rt_mono_table_internal_t ep_rt_metadata_labels_hash_map_t; +typedef struct _rt_mono_iterator_table_internal_t ep_rt_metadata_labels_hash_map_iterator_t; + +typedef struct _rt_mono_table_internal_t ep_rt_stack_hash_map_t; +typedef struct _rt_mono_table_iterator_internal_t ep_rt_stack_hash_map_iterator_t; + +typedef struct _rt_mono_table_internal_t ep_rt_thread_sequence_number_hash_map_t; +typedef struct _rt_mono_table_iterator_internal_t ep_rt_thread_sequence_number_hash_map_iterator_t; + +typedef MonoThreadHandle ep_rt_thread_handle_t; +typedef gpointer ep_rt_file_handle_t; +typedef gpointer ep_rt_ipc_handle_t; +typedef MonoMethod ep_rt_method_desc_t; + +struct _rt_mono_event_internal_t { + MonoOSEvent *event; +}; + +typedef struct _rt_mono_event_internal_t ep_rt_wait_event_handle_t; + +struct _rt_mono_lock_internal_t { + MonoCoopMutex *lock; +#ifdef EP_CHECKED_BUILD + MonoNativeThreadId owning_thread_id; + bool lock_is_held; +#endif +}; + +typedef struct _rt_mono_lock_internal_t ep_rt_lock_handle_t; +typedef ep_rt_lock_handle_t ep_rt_spin_lock_handle_t; + +#endif /* ENABLE_PERFTRACING */ +#endif /* __EVENTPIPE_RT_TYPES_MONO_H__ */ diff --git a/src/mono/mono/eventpipe/ep-rt-types.h b/src/mono/mono/eventpipe/ep-rt-types.h new file mode 100644 index 00000000000000..cb0a9af82fa6d3 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-rt-types.h @@ -0,0 +1,22 @@ +#ifndef __EVENTPIPE_RT_TYPES_H__ +#define __EVENTPIPE_RT_TYPES_H__ + +#define EP_ASSERT(expr) ep_rt_redefine +#define EP_LIKELY(expr) ep_rt_redefine +#define EP_UNLIKELY(expr) ep_rt_redefine + +/* + * ErrorHandling. + */ + +#define ep_raise_error_if_nok(expr) do { if (EP_UNLIKELY(!(expr))) goto ep_on_error; } while (0) +#define ep_raise_error() do { goto ep_on_error; } while (0) +#define ep_exit_error_handler() do { goto ep_on_exit; } while (0) +#define ep_return_null_if_nok(expr) do { if (EP_UNLIKELY(!(expr))) return NULL; } while (0) +#define ep_return_void_if_nok(expr) do { if (EP_UNLIKELY(!(expr))) return; } while (0) +#define ep_return_false_if_nok(expr) do { if (EP_UNLIKELY(!(expr))) return false; } while (0) +#define ep_return_zero_if_nok(expr) do { if (EP_UNLIKELY(!(expr))) return 0; } while (0) + +#include "ep-rt-types-mono.h" + +#endif /* __EVENTPIPE_RT_TYPES_H__ */ diff --git a/src/mono/mono/eventpipe/ep-rt.h b/src/mono/mono/eventpipe/ep-rt.h new file mode 100644 index 00000000000000..0bcdbc8cd36240 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-rt.h @@ -0,0 +1,482 @@ +#ifndef __EVENTPIPE_RT_H__ +#define __EVENTPIPE_RT_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +#define EP_ARRAY_SIZE(expr) ep_rt_redefine +#define EP_INFINITE_WAIT ep_rt_redefine + +#define EP_GCX_PREEMP_ENTER ep_rt_redefine +#define EP_GCX_PREEMP_EXIT ep_rt_redefine + +#define EP_RT_DECLARE_LIST(list_name, list_type, item_type) \ + static void ep_rt_ ## list_name ## _free (list_type *list, void (*callback)(void *)); \ + static void ep_rt_ ## list_name ## _clear (list_type *list, void (*callback)(void *)); \ + static void ep_rt_ ## list_name ## _append (list_type *list, item_type item); \ + static void ep_rt_ ## list_name ## _remove (list_type *list, const item_type item); \ + static bool ep_rt_ ## list_name ## _find (const list_type *list, const item_type item_to_find, item_type *found_item); \ + static bool ep_rt_ ## list_name ## _is_empty (const list_type *list); + +#define EP_RT_DECLARE_LIST_ITERATOR(list_name, list_type, iterator_type, item_type) \ + static void ep_rt_ ## list_name ## _iterator_begin (const list_type *list, iterator_type *iterator); \ + static bool ep_rt_ ## list_name ## _iterator_end (const list_type *list, const iterator_type *iterator); \ + static void ep_rt_ ## list_name ## _iterator_next (const list_type *list, iterator_type *iterator); \ + static item_type ep_rt_ ## list_name ## _iterator_value (const iterator_type *iterator); + +#define EP_RT_DECLARE_QUEUE(queue_name, queue_type, item_type) \ + static void ep_rt_ ## queue_name ## _alloc (queue_type *queue); \ + static void ep_rt_ ## queue_name ## _free (queue_type *queue); \ + static void ep_rt_ ## queue_name ## _pop_head (queue_type *queue, item_type *item); \ + static void ep_rt_ ## queue_name ## _push_head (queue_type *queue, item_type item); \ + static void ep_rt_ ## queue_name ## _push_tail (queue_type *queue, item_type item); \ + static bool ep_rt_ ## queue_name ## _is_empty (const queue_type *queue); + +#define EP_RT_DECLARE_HASH_MAP(hash_map_name, hash_map_type, key_type, value_type) \ + static void ep_rt_ ## hash_map_name ## _alloc (hash_map_type *hash_map, uint32_t (*hash_callback)(const void *), bool (*eq_callback)(const void *, const void *), void (*key_free_callback)(void *), void (*value_free_callback)(void *)); \ + static void ep_rt_ ## hash_map_name ## _free (hash_map_type *hash_map); \ + static void ep_rt_ ## hash_map_name ## _add (hash_map_type *hash_map, key_type key, value_type value); \ + static void ep_rt_ ## hash_map_name ## _remove (hash_map_type *hash_map, const key_type key); \ + static void ep_rt_ ## hash_map_name ## _remove_all (hash_map_type *hash_map); \ + static bool ep_rt_ ## hash_map_name ## _lookup (const hash_map_type *hash_map, const key_type key, value_type *value); \ + static uint32_t ep_rt_ ## hash_map_name ## _count (const hash_map_type *hash_map); + +#define EP_RT_DECLARE_HASH_MAP_ITERATOR(hash_map_name, hash_map_type, iterator_type, key_type, value_type) \ + static void ep_rt_ ## hash_map_name ## _iterator_begin (const hash_map_type *hash_map, iterator_type *iterator); \ + static bool ep_rt_ ## hash_map_name ## _iterator_end (const hash_map_type *hash_map, const iterator_type *iterator); \ + static void ep_rt_ ## hash_map_name ## _iterator_next (const hash_map_type *hash_map, iterator_type *iterator); \ + static key_type ep_rt_ ## hash_map_name ## _iterator_key (const iterator_type *iterator); \ + static value_type ep_rt_ ## hash_map_name ## _iterator_value (const iterator_type *iterator); + +/* +* Atomics. +*/ + +static +uint32_t +ep_rt_atomic_inc_uint32_t (volatile uint32_t *value); + +static +uint32_t +ep_rt_atomic_dec_uint32_t (volatile uint32_t *value); + +static +int32_t +ep_rt_atomic_inc_int32_t (volatile int32_t *value); + +static +int32_t +ep_rt_atomic_dec_int32_t (volatile int32_t *value); + +/* + * EventPipe. + */ + +static +void +ep_rt_init (void); + +static +void +ep_rt_shutdown (void); + +static +bool +ep_rt_config_aquire (void); + +static +void +ep_rt_config_release (void); + +#ifdef EP_CHECKED_BUILD +static +void +ep_rt_config_requires_lock_held (void); + +static +void +ep_rt_config_requires_lock_not_held (void); +#else +#define ep_rt_config_requires_lock_held() +#define ep_rt_config_requires_lock_not_held() +#endif + +/* + * EventPipeEvent. + */ + +EP_RT_DECLARE_LIST (event_list, ep_rt_event_list_t, EventPipeEvent *) +EP_RT_DECLARE_LIST_ITERATOR (event_list, ep_rt_event_list_t, ep_rt_event_list_iterator_t, EventPipeEvent *) + +/* + * EventPipeFile. + */ + +EP_RT_DECLARE_HASH_MAP(metadata_labels, ep_rt_metadata_labels_hash_map_t, EventPipeEvent *, uint32_t) +EP_RT_DECLARE_HASH_MAP(stack_hash, ep_rt_stack_hash_map_t, StackHashKey *, StackHashEntry *) +EP_RT_DECLARE_HASH_MAP_ITERATOR(stack_hash, ep_rt_stack_hash_map_t, ep_rt_stack_hash_map_iterator_t, StackHashKey *, StackHashEntry *) + +/* + * EventPipeProvider. + */ + +EP_RT_DECLARE_LIST (provider_list, ep_rt_provider_list_t, EventPipeProvider *) +EP_RT_DECLARE_LIST_ITERATOR (provider_list, ep_rt_provider_list_t, ep_rt_provider_list_iterator_t, EventPipeProvider *) + +EP_RT_DECLARE_QUEUE (provider_callback_data_queue, ep_rt_provider_callback_data_queue_t, EventPipeProviderCallbackData *) + +static +EventPipeProvider * +ep_rt_provider_list_find_by_name ( + const ep_rt_provider_list_t *list, + const ep_char8_t *name); + +/* + * EventPipeSampleProfiler. + */ + +static +void +ep_rt_sample_profiler_init (EventPipeProviderCallbackDataQueue *provider_callback_data_queue); + +static +void +ep_rt_sample_profiler_enable (void); + +static +void +ep_rt_sample_profiler_disable (void); + +static +uint32_t +ep_rt_sample_profiler_get_sampling_rate (void); + +/* + * EventPipeSessionProvider. + */ + +EP_RT_DECLARE_LIST (session_provider_list, ep_rt_session_provider_list_t, EventPipeSessionProvider *) +EP_RT_DECLARE_LIST_ITERATOR (session_provider_list, ep_rt_session_provider_list_t, ep_rt_session_provider_list_iterator_t, EventPipeSessionProvider *) + +static +EventPipeSessionProvider * +ep_rt_session_provider_list_find_by_name ( + const ep_rt_session_provider_list_t *list, + const ep_char8_t *name); + +/* + * Arrays. + */ + +static +uint8_t * +ep_rt_byte_array_alloc (size_t len); + +static +void +ep_rt_byte_array_free (uint8_t *ptr); + +/* + * Event. + */ + +static +void +ep_rt_wait_event_alloc (ep_rt_wait_event_handle_t *wait_event); + +static +void +ep_rt_wait_event_free (ep_rt_wait_event_handle_t *wait_event); + +static +bool +ep_rt_wait_event_set (ep_rt_wait_event_handle_t *wait_event); + +static +int32_t +ep_rt_wait_event_wait ( + ep_rt_wait_event_handle_t *wait_event, + uint32_t timeout, + bool alertable); + +static +EventPipeWaitHandle +ep_rt_wait_event_get_handle (ep_rt_wait_event_handle_t *wait_event); + +/* + * Misc. + */ + +static +bool +ep_rt_process_detach (void); + +static +void +ep_rt_create_activity_id ( + uint8_t *activity_id, + uint32_t activity_id_len); + +/* + * Objects. + */ + +#define ep_rt_object_alloc(obj_type) ep_rt_redefine + +static +void +ep_rt_object_free (void *ptr); + +/* + * PAL. + */ + +static +uint32_t +ep_rt_current_process_get_id (void); + +static +uint32_t +ep_rt_current_processor_get_number (void); + +static +uint32_t +ep_rt_processors_get_count (void); + +static +size_t +ep_rt_current_thread_get_id (void); + +static +uint64_t +ep_rt_perf_counter_query (void); + +static +uint64_t +ep_rt_perf_frequency_query (void); + +static +uint64_t +ep_rt_system_time_get (void); + +static +const ep_char8_t * +ep_rt_command_line_get (void); + +static +ep_rt_file_handle_t +ep_rt_file_open_write (const ep_char8_t *path); + +static +bool +ep_rt_file_close (ep_rt_file_handle_t file_handle); + +static +bool +ep_rt_file_write ( + ep_rt_file_handle_t file_handle, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written); + +/* +* SpinLock. +*/ + +static +void +ep_rt_spin_lock_alloc (ep_rt_spin_lock_handle_t *spin_lock); + +static +void +ep_rt_spin_lock_free (ep_rt_spin_lock_handle_t *spin_lock); + +static +void +ep_rt_spin_lock_aquire (ep_rt_spin_lock_handle_t *spin_lock); + +static +void +ep_rt_spin_lock_release (ep_rt_spin_lock_handle_t *spin_lock); + +#ifdef EP_CHECKED_BUILD +static +void +ep_rt_spin_lock_requires_lock_held (const ep_rt_spin_lock_handle_t *spin_lock); + +static +void +ep_rt_spin_lock_requires_lock_not_held (const ep_rt_spin_lock_handle_t *spin_lock); +#else +#define ep_rt_spin_lock_requires_lock_held(spin_lock) +#define ep_rt_spin_lock_requires_lock_not_held(spin_lock) +#endif + +/* + * String. + */ + +static +size_t +ep_rt_utf8_string_len (const ep_char8_t *str); + +static +int +ep_rt_utf8_string_compare ( + const ep_char8_t *str1, + const ep_char8_t *str2); + +static +ep_char8_t * +ep_rt_utf8_string_dup (const ep_char8_t *str); + +static +ep_char16_t * +ep_rt_utf8_to_utf16_string ( + const ep_char8_t *str, + size_t len); + +static +void +ep_rt_utf8_string_free (ep_char8_t *str); + +static +size_t +ep_rt_utf16_string_len (const ep_char16_t *str); + +static +ep_char8_t * +ep_rt_utf16_to_utf8_string ( + const ep_char16_t *str, + size_t len); + +static +void +ep_rt_utf16_string_free (ep_char16_t *str); + +static +const ep_char8_t * +ep_rt_managed_command_line_get (void); + +/* + * Thread. + */ +static +void +ep_rt_thread_setup (void); + +static +EventPipeThread * +ep_rt_thread_get (void); + +static +EventPipeThread * +ep_rt_thread_get_or_create (void); + + +/* + * ThreadSequenceNumberMap. + */ + +EP_RT_DECLARE_HASH_MAP(thread_sequence_number_map, ep_rt_thread_sequence_number_hash_map_t, EventPipeThreadSessionState *, uint32_t) +EP_RT_DECLARE_HASH_MAP_ITERATOR(thread_sequence_number_map, ep_rt_thread_sequence_number_hash_map_t, ep_rt_thread_sequence_number_hash_map_iterator_t, EventPipeThreadSessionState *, uint32_t) + + +/* + * Volatile. + */ + +static +uint32_t +ep_rt_volatile_load_uint32_t (const volatile uint32_t *ptr); + +static +uint32_t +ep_rt_volatile_load_uint32_t_without_barrier (const volatile uint32_t *ptr); + +static +void +ep_rt_volatile_store_uint32_t ( + volatile uint32_t *ptr, + uint32_t value); + +static +void +ep_rt_volatile_store_uint32_t_without_barrier ( + volatile uint32_t *ptr, + uint32_t value); + +static +uint64_t +ep_rt_volatile_load_uint64_t (const volatile uint64_t *ptr); + +static +uint64_t +ep_rt_volatile_load_uint64_t_without_barrier (const volatile uint64_t *ptr); + +static +void +ep_rt_volatile_store_uint64_t ( + volatile uint64_t *ptr, + uint64_t value); + +static +void +ep_rt_volatile_store_uint64_t_without_barrier ( + volatile uint64_t *ptr, + uint64_t value); + +static +void * +ep_rt_volatile_load_ptr (volatile void **ptr); + +static +void * +ep_rt_volatile_load_ptr_without_barrier (volatile void **ptr); + +static +void +ep_rt_volatile_store_ptr ( + volatile void **ptr, + void *value); + +static +void +ep_rt_volatile_store_ptr_without_barrier ( + volatile void **ptr, + void *value); + +/* + * Enter/Exit config lock helper used with error handling macros. + */ + +#define EP_CONFIG_LOCK_ENTER \ +{ \ + ep_rt_config_requires_lock_not_held (); \ + bool _owns_lock = ep_rt_config_aquire (); \ + bool _no_error = false; \ + if (EP_UNLIKELY((!_owns_lock))) \ + goto _ep_on_lock_exit; + +#define EP_CONFIG_LOCK_EXIT \ + _no_error = true; \ +_ep_on_lock_exit: \ + if (EP_UNLIKELY((!_owns_lock))) \ + goto ep_on_error; \ + ep_rt_config_requires_lock_held (); \ + ep_rt_config_release (); \ + if (EP_UNLIKELY((!_no_error))) \ + goto ep_on_error; \ + ep_rt_config_requires_lock_not_held (); \ +} + +#define ep_raise_error_if_nok_holding_lock(expr) do { if (EP_UNLIKELY(!(expr))) goto _ep_on_lock_exit; } while (0) +#define ep_raise_error_holding_lock() do { goto _ep_on_lock_exit; } while (0) + +#include "ep-rt-mono.h" + +#endif /* ENABLE_PERFTRACING */ +#endif /* __EVENTPIPE_RT_H__ */ diff --git a/src/mono/mono/eventpipe/ep-session-internals.c b/src/mono/mono/eventpipe/ep-session-internals.c new file mode 100644 index 00000000000000..3ed2a1101cc221 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-session-internals.c @@ -0,0 +1,123 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#define EP_IMPL_GETTER_SETTER +#include "ep.h" + +/* + * EventPipeSession. + */ + +EventPipeSession * +ep_session_alloc ( + uint32_t index, + const ep_char8_t *output_path, + IpcStream *stream, + EventPipeSessionType session_type, + EventPipeSerializationFormat format, + bool rundown_requested, + uint32_t circular_buffer_size_in_mb, + const EventPipeProviderConfiguration *providers, + uint32_t providers_len, + bool rundown_enabled) +{ + ep_rt_config_requires_lock_held (); + + ep_return_null_if_nok (index < EP_MAX_NUMBER_OF_SESSIONS && format < EP_SERIALIZATION_FORMAT_COUNT && circular_buffer_size_in_mb > 0 && providers_len > 0 && providers != NULL); + + FileStreamWriter *file_stream_writer = NULL; + IpcStreamWriter *ipc_stream_writer = NULL; + + EventPipeSession *instance = ep_rt_object_alloc (EventPipeSession); + ep_raise_error_if_nok (instance != NULL); + + instance->providers = ep_session_provider_list_alloc (providers, providers_len); + ep_raise_error_if_nok (instance->providers != NULL); + + instance->index = index; + instance->rundown_enabled = rundown_enabled ? 1 : 0; + instance->session_type = session_type; + instance->format = format; + instance->rundown_requested = rundown_requested; + + size_t sequence_point_alloc_budget = 0; + + // Hard coded 10MB for now, we'll probably want to make + // this configurable later. + if (instance->session_type != EP_SESSION_TYPE_LISTENER && instance->format >= EP_SERIALIZATION_FORMAT_NETTRACE_V4) { + sequence_point_alloc_budget = 10 * 1024 * 1024; + } + + instance->buffer_manager = ep_buffer_manager_alloc (instance, ((size_t)circular_buffer_size_in_mb) << 20, sequence_point_alloc_budget); + ep_raise_error_if_nok (instance->buffer_manager != NULL); + + // Create the event pipe file. + // A NULL output path means that we should not write the results to a file. + // This is used in the EventListener case. + switch (session_type) { + case EP_SESSION_TYPE_FILE : + if (output_path) { + file_stream_writer = ep_file_stream_writer_alloc (output_path); + instance->file = ep_file_alloc (ep_file_stream_writer_get_stream_writer_ref (file_stream_writer), format); + ep_raise_error_if_nok (instance->file != NULL); + file_stream_writer = NULL; + } + break; + + case EP_SESSION_TYPE_IPCSTREAM: + ipc_stream_writer = ep_ipc_stream_writer_alloc ((uint64_t)instance, stream); + ep_raise_error_if_nok (ipc_stream_writer != NULL); + instance->file = ep_file_alloc (ep_ipc_stream_writer_get_stream_writer_ref (ipc_stream_writer), format); + ep_raise_error_if_nok (instance->file != NULL); + ipc_stream_writer = NULL; + break; + + default: + break; + } + + instance->session_start_time = ep_rt_system_time_get (); + instance->session_start_timestamp = ep_perf_counter_query (); + + ep_rt_wait_event_alloc (&instance->rt_thread_shutdown_event); + +ep_on_exit: + ep_rt_config_requires_lock_held (); + return instance; + +ep_on_error: + ep_file_stream_writer_free (file_stream_writer); + ep_ipc_stream_writer_free (ipc_stream_writer); + ep_session_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_session_free (EventPipeSession *session) +{ + ep_return_void_if_nok (session != NULL); + + EP_ASSERT (ep_session_get_ipc_streaming_enabled (session) == false); + + ep_rt_wait_event_free (&session->rt_thread_shutdown_event); + + ep_session_provider_list_free (session->providers); + + ep_buffer_manager_free (session->buffer_manager); + ep_file_free (session->file); + + ep_rt_object_free (session); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_session_internals; +const char quiet_linker_empty_file_warning_eventpipe_session_internals = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-session-provider-internals.c b/src/mono/mono/eventpipe/ep-session-provider-internals.c new file mode 100644 index 00000000000000..5c71bb7ef7af32 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-session-provider-internals.c @@ -0,0 +1,135 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#define EP_IMPL_GETTER_SETTER +#include "ep.h" + +/* + * Forward declares of all static functions. + */ + +static +void +session_provider_free_func (void *session_provider); + +/* + * EventPipeSessionProvider. + */ + +static +void +session_provider_free_func (void *session_provider) +{ + ep_session_provider_free ((EventPipeSessionProvider *)session_provider); +} + +EventPipeSessionProvider * +ep_session_provider_alloc ( + const ep_char8_t *provider_name, + uint64_t keywords, + EventPipeEventLevel logging_level, + const ep_char8_t *filter_data) +{ + EventPipeSessionProvider *instance = ep_rt_object_alloc (EventPipeSessionProvider); + ep_raise_error_if_nok (instance != NULL); + + if (provider_name) { + instance->provider_name = ep_rt_utf8_string_dup (provider_name); + ep_raise_error_if_nok (instance->provider_name != NULL); + } + + if (filter_data) { + instance->filter_data = ep_rt_utf8_string_dup (filter_data); + ep_raise_error_if_nok (instance->filter_data != NULL); + } + + instance->keywords = keywords; + instance->logging_level = logging_level; + +ep_on_exit: + return instance; + +ep_on_error: + ep_session_provider_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_session_provider_free (EventPipeSessionProvider * session_provider) +{ + ep_return_void_if_nok (session_provider != NULL); + + ep_rt_utf8_string_free (session_provider->filter_data); + ep_rt_utf8_string_free (session_provider->provider_name); + ep_rt_object_free (session_provider); +} + +/* + * EventPipeSessionProviderList. + */ + +EventPipeSessionProviderList * +ep_session_provider_list_alloc ( + const EventPipeProviderConfiguration *configs, + uint32_t configs_len) +{ + ep_return_null_if_nok ((configs_len == 0) || (configs_len > 0 && configs != NULL)); + + EventPipeSessionProviderList *instance = ep_rt_object_alloc (EventPipeSessionProviderList); + ep_raise_error_if_nok (instance != NULL); + + instance->catch_all_provider = NULL; + + for (uint32_t i = 0; i < configs_len; ++i) { + const EventPipeProviderConfiguration *config = &configs [i]; + EP_ASSERT (config != NULL); + + // Enable all events if the provider name == '*', all keywords are on and the requested level == verbose. + if ((ep_rt_utf8_string_compare(ep_provider_get_wildcard_name_utf8 (), config->provider_name) == 0) && + (config->keywords == 0xFFFFFFFFFFFFFFFF) && + ((config->logging_level == EP_EVENT_LEVEL_VERBOSE) && (instance->catch_all_provider == NULL))) { + instance->catch_all_provider = ep_session_provider_alloc (NULL, 0xFFFFFFFFFFFFFFFF, EP_EVENT_LEVEL_VERBOSE, NULL ); + ep_raise_error_if_nok (instance->catch_all_provider != NULL); + } + else { + EventPipeSessionProvider * session_provider = ep_session_provider_alloc ( + config->provider_name, + config->keywords, + config->logging_level, + config->filter_data); + ep_rt_session_provider_list_append (&instance->providers, session_provider); + } + } + +ep_on_exit: + return instance; + +ep_on_error: + ep_session_provider_list_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_session_provider_list_free (EventPipeSessionProviderList *session_provider_list) +{ + ep_return_void_if_nok (session_provider_list != NULL); + + ep_rt_session_provider_list_free (&session_provider_list->providers, session_provider_free_func); + ep_session_provider_free (session_provider_list->catch_all_provider); + ep_rt_object_free (session_provider_list); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_session_provider_internals; +const char quiet_linker_empty_file_warning_eventpipe_session_provider_internals = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-session-provider.c b/src/mono/mono/eventpipe/ep-session-provider.c new file mode 100644 index 00000000000000..08b6db7f5a0c33 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-session-provider.c @@ -0,0 +1,60 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#include "ep.h" + +/* + * Forward declares of all static functions. + */ + +static +void +session_provider_free_func (void *session_provider); + +/* + * EventPipeSessionProvider. + */ + +static +void +session_provider_free_func (void *session_provider) +{ + ep_session_provider_free ((EventPipeSessionProvider *)session_provider); +} + +/* + * EventPipeSessionProviderList. + */ + +void +ep_session_provider_list_clear (EventPipeSessionProviderList *session_provider_list) +{ + ep_return_void_if_nok (session_provider_list != NULL); + ep_rt_session_provider_list_clear (ep_session_provider_list_get_providers_ref (session_provider_list), session_provider_free_func); +} + +bool +ep_session_provider_list_is_empty (const EventPipeSessionProviderList *session_provider_list) +{ + return (ep_rt_provider_list_is_empty (ep_session_provider_list_get_providers_cref (session_provider_list)) && ep_session_provider_list_get_catch_all_provider (session_provider_list) == NULL); +} + +void +ep_session_provider_list_add_session_provider ( + EventPipeSessionProviderList *session_provider_list, + EventPipeSessionProvider *session_provider) +{ + ep_return_void_if_nok (session_provider != NULL); + ep_rt_session_provider_list_append (ep_session_provider_list_get_providers_ref (session_provider_list), session_provider); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_session_provider; +const char quiet_linker_empty_file_warning_eventpipe_session_provider = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-session-provider.h b/src/mono/mono/eventpipe/ep-session-provider.h new file mode 100644 index 00000000000000..7a2812f09f2e55 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-session-provider.h @@ -0,0 +1,86 @@ +#ifndef __EVENTPIPE_SESSION_PROVIDER_H__ +#define __EVENTPIPE_SESSION_PROVIDER_H__ + +#include "ep-rt-config.h" + +#ifdef ENABLE_PERFTRACING +#include "ep-types.h" + +/* + * EventPipeSessionProvider. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeSessionProvider { +#else +struct _EventPipeSessionProvider_Internal { +#endif + ep_char8_t *provider_name; + uint64_t keywords; + EventPipeEventLevel logging_level; + ep_char8_t *filter_data; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeSessionProvider { + uint8_t _internal [sizeof (struct _EventPipeSessionProvider_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventPipeSessionProvider *, session_provider, const ep_char8_t *, provider_name) +EP_DEFINE_GETTER(EventPipeSessionProvider *, session_provider, uint64_t, keywords) +EP_DEFINE_GETTER(EventPipeSessionProvider *, session_provider, EventPipeEventLevel, logging_level) +EP_DEFINE_GETTER(EventPipeSessionProvider *, session_provider, const ep_char8_t *, filter_data) + +EventPipeSessionProvider * +ep_session_provider_alloc ( + const ep_char8_t *provider_name, + uint64_t keywords, + EventPipeEventLevel logging_level, + const ep_char8_t *filter_data); + +void +ep_session_provider_free (EventPipeSessionProvider * session_provider); + +/* +* EventPipeSessionProviderList. + */ +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeSessionProviderList { +#else +struct _EventPipeSessionProviderList_Internal { +#endif + ep_rt_session_provider_list_t providers; + EventPipeSessionProvider *catch_all_provider; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeSessionProviderList { + uint8_t _internal [sizeof (struct _EventPipeSessionProviderList_Internal)]; +}; +#endif + +EP_DEFINE_GETTER_REF(EventPipeSessionProviderList *, session_provider_list, ep_rt_session_provider_list_t *, providers) +EP_DEFINE_GETTER(EventPipeSessionProviderList *, session_provider_list, EventPipeSessionProvider *, catch_all_provider) + +EventPipeSessionProviderList * +ep_session_provider_list_alloc ( + const EventPipeProviderConfiguration *configs, + uint32_t configs_len); + +void +ep_session_provider_list_free (EventPipeSessionProviderList *session_provider_list); + +void +ep_session_provider_list_clear (EventPipeSessionProviderList *session_provider_list); + +bool +ep_session_provider_list_is_empty (const EventPipeSessionProviderList *session_provider_list); + +void +ep_session_provider_list_add_session_provider ( + EventPipeSessionProviderList *session_provider_list, + EventPipeSessionProvider *session_provider); + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_SESSION_PROVIDER_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-session.c b/src/mono/mono/eventpipe/ep-session.c new file mode 100644 index 00000000000000..f4e4caa67e869a --- /dev/null +++ b/src/mono/mono/eventpipe/ep-session.c @@ -0,0 +1,255 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#include "ep.h" + +/* + * Forward declares of all static functions. + */ + +static +void +session_disable_ipc_streaming_thread (EventPipeSession *session); + +static +void +session_create_ipc_streaming_thread_lock_held (EventPipeSession *session); + +/* + * EventPipeSession. + */ + +static +void +session_create_ipc_streaming_thread_lock_held (EventPipeSession *session) +{ + //TODO: Implement. +} + +static +void +session_disable_ipc_streaming_thread (EventPipeSession *session) +{ + EP_ASSERT (ep_session_get_session_type (session) == EP_SESSION_TYPE_IPCSTREAM); + EP_ASSERT (ep_session_get_ipc_streaming_enabled (session)); + + EP_ASSERT (!ep_rt_process_detach ()); + + // The IPC streaming thread will watch this value and exit + // when profiling is disabled. + ep_session_set_ipc_streaming_enabled (session, false); + + // Thread could be waiting on the event that there is new data to read. + ep_rt_wait_event_set (ep_buffer_manager_get_rt_wait_event_ref (ep_session_get_buffer_manager (session))); + + // Wait for the sampling thread to clean itself up. + ep_rt_wait_event_handle_t *rt_thread_shutdown_event = ep_session_get_rt_thread_shutdown_event_ref (session); + ep_rt_wait_event_wait (rt_thread_shutdown_event, EP_INFINITE_WAIT, false /* bAlertable */); + ep_rt_wait_event_free (rt_thread_shutdown_event); +} + +EventPipeSessionProvider * +ep_session_get_session_provider_lock_held ( + const EventPipeSession *session, + const EventPipeProvider *provider) +{ + ep_rt_config_requires_lock_held (); + + ep_return_null_if_nok (session != NULL && provider != NULL); + + EventPipeSessionProviderList *providers = ep_session_get_providers (session); + ep_return_null_if_nok (providers != NULL); + + EventPipeSessionProvider *catch_all = ep_session_provider_list_get_catch_all_provider (providers); + if (catch_all) + return catch_all; + + EventPipeSessionProvider *session_provider = ep_rt_session_provider_list_find_by_name (ep_session_provider_list_get_providers_ref (providers), ep_provider_get_provider_name (provider)); + + ep_rt_config_requires_lock_held (); + return session_provider; +} + +void +ep_session_enable_rundown_lock_held (EventPipeSession *session) +{ + ep_rt_config_requires_lock_held (); + + ep_return_void_if_nok (session != NULL); + + //TODO: This is CoreCLR specific keywords for native ETW events (ending up in event pipe). + //! The keywords below seems to correspond to: + //! LoaderKeyword (0x00000008) + //! JitKeyword (0x00000010) + //! NgenKeyword (0x00000020) + //! unused_keyword (0x00000100) + //! JittedMethodILToNativeMapKeyword (0x00020000) + //! ThreadTransferKeyword (0x80000000) + const uint64_t keywords = 0x80020138; + const uint32_t verbose_logging_level = (uint32_t)EP_EVENT_LEVEL_VERBOSE; + + EventPipeProviderConfiguration rundown_providers [2]; + uint32_t rundown_providers_len = EP_ARRAY_SIZE (rundown_providers); + + ep_provider_config_init (&rundown_providers [0], ep_config_get_public_provider_name_utf8 (), keywords, verbose_logging_level, NULL); // Public provider. + ep_provider_config_init (&rundown_providers [1], ep_config_get_rundown_provider_name_utf8 (), keywords, verbose_logging_level, NULL); // Rundown provider. + + //TODO: This is CoreCLR specific provider. + // update the provider context here since the callback doesn't happen till we actually try to do rundown. + //MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context.EventPipeProvider.Level = VerboseLoggingLevel; + //MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context.EventPipeProvider.EnabledKeywordsBitmask = Keywords; + //MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context.EventPipeProvider.IsEnabled = true; + + // Update provider list with rundown configuration. + for (uint32_t i = 0; i < rundown_providers_len; ++i) { + const EventPipeProviderConfiguration *config = &rundown_providers [i]; + + EventPipeSessionProvider *session_provider = ep_session_provider_alloc ( + ep_provider_config_get_provider_name (config), + ep_provider_config_get_keywords (config), + ep_provider_config_get_logging_level (config), + ep_provider_config_get_filter_data (config)); + + ep_session_add_session_provider (session, session_provider); + } + + ep_session_set_rundown_enabled (session, true); + + ep_rt_config_requires_lock_held (); + return; +} + +void +ep_session_execute_rundown_lock_held (EventPipeSession *session) +{ + //TODO: Implement. This is mainly runtime specific implementation + //since it will emit native trace events into the pipe (using CoreCLR's ETW support). +} + +void +ep_session_suspend_write_event_lock_held (EventPipeSession *session) +{ + //TODO: Implement. +} + +void +ep_session_write_sequence_point_unbuffered_lock_held (EventPipeSession *session) +{ + //TODO: Implement. +} + +void +ep_session_start_streaming_lock_held (EventPipeSession *session) +{ + ep_rt_config_requires_lock_held (); + + ep_return_void_if_nok (session != NULL); + + if (ep_session_get_file (session) != NULL) + ep_file_initialize_file (ep_session_get_file (session)); + + if (ep_session_get_session_type (session) == EP_SESSION_TYPE_IPCSTREAM) + session_create_ipc_streaming_thread_lock_held (session); + + ep_rt_config_requires_lock_held (); + return; +} + +bool +ep_session_is_valid (const EventPipeSession *session) +{ + return !ep_session_provider_list_is_empty (ep_session_get_providers (session)); +} + +void +ep_session_add_session_provider (EventPipeSession *session, EventPipeSessionProvider *session_provider) +{ + ep_return_void_if_nok (session != NULL); + ep_session_provider_list_add_session_provider (ep_session_get_providers (session), session_provider); +} + +void +ep_session_disable (EventPipeSession *session) +{ + ep_return_void_if_nok (session != NULL); + if (ep_session_get_session_type (session) == EP_SESSION_TYPE_IPCSTREAM && ep_session_get_ipc_streaming_enabled (session)) + session_disable_ipc_streaming_thread (session); + + bool ignored; + ep_session_write_all_buffers_to_file (session, &ignored); + ep_session_provider_list_clear (ep_session_get_providers (session)); +} + +bool +ep_session_write_all_buffers_to_file (EventPipeSession *session, bool *events_written) +{ + //TODO: Implement. + *events_written = false; + return true; +} + +EventPipeEventInstance * +ep_session_get_next_event (EventPipeSession *session) +{ + //TODO: Implement. + return NULL; +} + +EventPipeWaitHandle +ep_session_get_wait_event (EventPipeSession *session) +{ + ep_raise_error_if_nok (session != NULL); + + EventPipeBufferManager *buffer_manager = ep_session_get_buffer_manager (session); + ep_raise_error_if_nok (buffer_manager != NULL); + + return ep_rt_wait_event_get_wait_handle (ep_buffer_manager_get_rt_wait_event_ref (buffer_manager)); + +ep_on_error: + return 0; +} + +uint64_t +ep_session_get_mask (const EventPipeSession *session) +{ + return ((uint64_t)1 << ep_session_get_index (session)); +} + +bool +ep_session_get_rundown_enabled (const EventPipeSession *session) +{ + return (ep_rt_volatile_load_uint32_t(ep_session_get_rundown_enabled_cref (session)) ? true : false); +} + +void +ep_session_set_rundown_enabled ( + EventPipeSession *session, + bool enabled) +{ + ep_rt_volatile_store_uint32_t (ep_session_get_rundown_enabled_ref (session), (enabled) ? 1 : 0); +} + +bool +ep_session_get_ipc_streaming_enabled (const EventPipeSession *session) +{ + return (ep_rt_volatile_load_uint32_t(ep_session_get_ipc_streaming_enabled_cref (session)) ? true : false); +} + +void +ep_session_set_ipc_streaming_enabled ( + EventPipeSession *session, + bool enabled) +{ + ep_rt_volatile_store_uint32_t (ep_session_get_ipc_streaming_enabled_ref (session), (enabled) ? 1 : 0); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_session; +const char quiet_linker_empty_file_warning_eventpipe_session = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-session.h b/src/mono/mono/eventpipe/ep-session.h new file mode 100644 index 00000000000000..cfcf1476938be7 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-session.h @@ -0,0 +1,130 @@ +#ifndef __EVENTPIPE_SESSION_H__ +#define __EVENTPIPE_SESSION_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +/* + * EventPipeSession. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeSession { +#else +struct _EventPipeSession_Internal { +#endif + uint32_t index; + EventPipeSessionProviderList *providers; + EventPipeBufferManager *buffer_manager; + volatile uint32_t rundown_enabled; + EventPipeSessionType session_type; + EventPipeSerializationFormat format; + bool rundown_requested; + uint64_t session_start_time; + uint64_t session_start_timestamp; + EventPipeFile *file; + volatile uint32_t ipc_streaming_enabled; + EventPipeThread ipc_streaming_thread; + ep_rt_wait_event_handle_t rt_thread_shutdown_event; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeSession { + uint8_t _internal [sizeof (struct _EventPipeSession_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventPipeSession *, session, uint32_t, index) +EP_DEFINE_GETTER(EventPipeSession *, session, EventPipeSessionProviderList *, providers) +EP_DEFINE_GETTER(EventPipeSession *, session, EventPipeBufferManager *, buffer_manager) +EP_DEFINE_GETTER_REF(EventPipeSession *, session, volatile uint32_t *, rundown_enabled) +EP_DEFINE_GETTER(EventPipeSession *, session, EventPipeSessionType, session_type) +EP_DEFINE_GETTER(EventPipeSession *, session, EventPipeSerializationFormat, format) +EP_DEFINE_GETTER(EventPipeSession *, session, bool, rundown_requested) +EP_DEFINE_GETTER(EventPipeSession *, session, uint64_t, session_start_time) +EP_DEFINE_GETTER(EventPipeSession *, session, uint64_t, session_start_timestamp) +EP_DEFINE_GETTER(EventPipeSession *, session, EventPipeFile *, file) +EP_DEFINE_GETTER_REF(EventPipeSession *, session, volatile uint32_t *, ipc_streaming_enabled) +EP_DEFINE_GETTER_REF(EventPipeSession *, session, EventPipeThread *, ipc_streaming_thread) +EP_DEFINE_GETTER_REF(EventPipeSession *, session, ep_rt_wait_event_handle_t *, rt_thread_shutdown_event) + +EventPipeSession * +ep_session_alloc ( + uint32_t index, + const ep_char8_t *output_path, + IpcStream *stream, + EventPipeSessionType session_type, + EventPipeSerializationFormat format, + bool rundown_requested, + uint32_t circular_buffer_size_in_mb, + const EventPipeProviderConfiguration *providers, + uint32_t providers_len, + bool rundown_enabled); + +void +ep_session_free (EventPipeSession *session); + +EventPipeSessionProvider * +ep_session_get_session_provider_lock_held ( + const EventPipeSession *session, + const EventPipeProvider *provider); + +void +ep_session_enable_rundown_lock_held (EventPipeSession *session); + +void +ep_session_execute_rundown_lock_held (EventPipeSession *session); + +void +ep_session_suspend_write_event_lock_held (EventPipeSession *session); + +void +ep_session_write_sequence_point_unbuffered_lock_held (EventPipeSession *session); + +void +ep_session_start_streaming_lock_held (EventPipeSession *session); + +bool +ep_session_is_valid (const EventPipeSession *session); + +void +ep_session_add_session_provider ( + EventPipeSession *session, + EventPipeSessionProvider *session_provider); + +void +ep_session_disable (EventPipeSession *session); + +bool +ep_session_write_all_buffers_to_file (EventPipeSession *session, bool *events_written); + +EventPipeEventInstance * +ep_session_get_next_event (EventPipeSession *session); + +EventPipeWaitHandle +ep_session_get_wait_event (EventPipeSession *session); + +uint64_t +ep_session_get_mask (const EventPipeSession *session); + +bool +ep_session_get_rundown_enabled (const EventPipeSession *session); + +void +ep_session_set_rundown_enabled ( + EventPipeSession *session, + bool enabled); + +bool +ep_session_get_ipc_streaming_enabled (const EventPipeSession *session); + +void +ep_session_set_ipc_streaming_enabled ( + EventPipeSession *session, + bool enabled); + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_SESSION_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-stack-contents.h b/src/mono/mono/eventpipe/ep-stack-contents.h new file mode 100644 index 00000000000000..6ffe98d657004b --- /dev/null +++ b/src/mono/mono/eventpipe/ep-stack-contents.h @@ -0,0 +1,172 @@ +#ifndef __EVENTPIPE_STACKCONTENTS_H__ +#define __EVENTPIPE_STACKCONTENTS_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +/* + * EventPipeStackContents. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeStackContents { +#else +struct _EventPipeStackContents_Internal { +#endif + // Array of IP values from a stack crawl. + // Top of stack is at index 0. + uintptr_t stack_frames [EP_MAX_STACK_DEPTH]; +#ifdef EP_CHECKED_BUILD + // Parallel array of MethodDesc pointers. + // Used for debug-only stack printing. + ep_rt_method_desc_t *methods [EP_MAX_STACK_DEPTH]; +#endif + + // The next available slot in stack_frames. + uint32_t next_available_frame; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeStackContents { + uint8_t _internal [sizeof (struct _EventPipeStackContents_Internal)]; +}; +#endif + +EP_DEFINE_GETTER_ARRAY_REF(EventPipeStackContents *, stack_contents, uintptr_t *, const uintptr_t *, stack_frames, stack_frames[0]) +#ifdef EP_CHECKED_BUILD +EP_DEFINE_GETTER_ARRAY_REF(EventPipeStackContents *, stack_contents, ep_rt_method_desc_t **, ep_rt_method_desc_t *const*, methods, methods[0]) +#endif +EP_DEFINE_GETTER(EventPipeStackContents *, stack_contents, uint32_t, next_available_frame) +EP_DEFINE_SETTER(EventPipeStackContents *, stack_contents, uint32_t, next_available_frame) + +EventPipeStackContents * +ep_stack_contents_alloc (void); + +EventPipeStackContents * +ep_stack_contents_init (EventPipeStackContents *stack_contents); + +void +ep_stack_contents_fini (EventPipeStackContents *stack_contents); + +void +ep_stack_contents_free (EventPipeStackContents *stack_contents); + +static +inline +void +ep_stack_contents_copyto ( + EventPipeStackContents *stack_contents, + EventPipeStackContents *dest) +{ + memcpy ( + ep_stack_contents_get_stack_frames_ref (dest), + ep_stack_contents_get_stack_frames_ref (stack_contents), + ep_stack_contents_get_next_available_frame (stack_contents) * sizeof (uintptr_t)); + +#ifdef EP_CHECKED_BUILD + memcpy ( + ep_stack_contents_get_methods_ref (dest), + ep_stack_contents_get_methods_ref (stack_contents), + ep_stack_contents_get_next_available_frame (stack_contents) * sizeof (ep_rt_method_desc_t *)); +#endif + + ep_stack_contents_set_next_available_frame (dest, ep_stack_contents_get_next_available_frame (stack_contents)); +} + +static +inline +void +ep_stack_contents_reset (EventPipeStackContents *stack_contents) +{ + ep_stack_contents_set_next_available_frame (stack_contents, 0); +} + +static +inline +bool +ep_stack_contents_is_empty (EventPipeStackContents *stack_contents) +{ + return (ep_stack_contents_get_next_available_frame (stack_contents) == 0); +} + +static +inline +uint32_t +ep_stack_contents_get_length (EventPipeStackContents *stack_contents) +{ + return ep_stack_contents_get_next_available_frame (stack_contents); +} + +static +inline +uintptr_t +ep_stack_contents_get_ip ( + EventPipeStackContents *stack_contents, + uint32_t frame_index) +{ + EP_ASSERT (frame_index < EP_MAX_STACK_DEPTH); + if (frame_index >= EP_MAX_STACK_DEPTH) + return 0; + + return ep_stack_contents_get_stack_frames_cref (stack_contents)[frame_index]; +} + +#ifdef EP_CHECKED_BUILD +static +inline +ep_rt_method_desc_t * +ep_stack_contents_get_method ( + EventPipeStackContents *stack_contents, + uint32_t frame_index) +{ + EP_ASSERT (frame_index < EP_MAX_STACK_DEPTH); + if (frame_index >= EP_MAX_STACK_DEPTH) + return NULL; + + return ep_stack_contents_get_methods_cref (stack_contents)[frame_index]; +} +#endif + +static +inline +void +ep_stack_contents_append ( + EventPipeStackContents *stack_contents, + uintptr_t control_pc, + ep_rt_method_desc_t *method) +{ + EP_ASSERT (stack_contents != NULL); + uint32_t next_frame = ep_stack_contents_get_next_available_frame (stack_contents); + if (next_frame < EP_MAX_STACK_DEPTH) { + ep_stack_contents_get_stack_frames_ref (stack_contents)[next_frame] = control_pc; +#ifdef EP_CHECKED_BUILD + ep_stack_contents_get_methods_ref (stack_contents)[next_frame] = method; +#endif + next_frame++; + ep_stack_contents_set_next_available_frame (stack_contents, next_frame); + } +} + +static +inline +uint8_t * +ep_stack_contents_get_pointer (const EventPipeStackContents *stack_contents) +{ + EP_ASSERT (stack_contents != NULL); + return (uint8_t *)ep_stack_contents_get_stack_frames_cref (stack_contents); +} + +static +inline +uint32_t +ep_stack_contents_get_size (const EventPipeStackContents *stack_contents) +{ + EP_ASSERT (stack_contents != NULL); + return (ep_stack_contents_get_next_available_frame (stack_contents) * sizeof (uintptr_t)); +} + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_STACKCONTENTS_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-stream-internals.c b/src/mono/mono/eventpipe/ep-stream-internals.c new file mode 100644 index 00000000000000..c62c857552aecc --- /dev/null +++ b/src/mono/mono/eventpipe/ep-stream-internals.c @@ -0,0 +1,392 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#define EP_IMPL_GETTER_SETTER +#include "ep.h" + +/* + * Forward declares of all static functions. + */ + +static +void +file_stream_writer_free_func (void *stream); + +static +bool +file_stream_writer_write_func ( + void *stream, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written); + +static +void +file_write_end (EventPipeFile *file); + +static +void +ipc_stream_writer_free_func (void *stream); + +static +bool +ipc_stream_writer_write_func ( + void *stream, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written); + +/* + * FastSerializableObject. + */ + +FastSerializableObject * +ep_fast_serializable_object_init ( + FastSerializableObject *fast_serializable_object, + FastSerializableObjectVtable *vtable, + int32_t object_version, + int32_t min_reader_version, + bool is_private) +{ + EP_ASSERT (fast_serializable_object != NULL && vtable != NULL); + + fast_serializable_object->vtable = vtable; + fast_serializable_object->object_version = object_version; + fast_serializable_object->min_reader_version = min_reader_version; + fast_serializable_object->is_private = is_private; + + return fast_serializable_object; +} + +void +ep_fast_serializable_object_fini (FastSerializableObject *fast_serializable_ojbect) +{ + ; +} + +void +ep_fast_serializable_object_free_vcall (FastSerializableObject *fast_serializable_ojbect) +{ + ep_return_void_if_nok (fast_serializable_ojbect != NULL); + + EP_ASSERT (fast_serializable_ojbect->vtable != NULL); + FastSerializableObjectVtable *vtable = fast_serializable_ojbect->vtable; + + EP_ASSERT (vtable->free_func != NULL); + vtable->free_func (fast_serializable_ojbect); +} + +void +ep_fast_serializable_object_fast_serialize_vcall ( + FastSerializableObject *fast_serializable_ojbect, + FastSerializer *fast_serializer) +{ + EP_ASSERT (fast_serializable_ojbect != NULL && fast_serializable_ojbect->vtable != NULL); + FastSerializableObjectVtable *vtable = fast_serializable_ojbect->vtable; + + EP_ASSERT (vtable->fast_serialize_func != NULL); + vtable->fast_serialize_func (fast_serializable_ojbect, fast_serializer); +} + +const ep_char8_t * +ep_fast_serializable_object_get_type_name_vcall (FastSerializableObject *fast_serializable_ojbect) +{ + EP_ASSERT (fast_serializable_ojbect != NULL && fast_serializable_ojbect->vtable != NULL); + FastSerializableObjectVtable *vtable = fast_serializable_ojbect->vtable; + + EP_ASSERT (vtable->get_type_name_func != NULL); + return vtable->get_type_name_func (fast_serializable_ojbect); +} + +/* + * FastSerializer. + */ +FastSerializer * +ep_fast_serializer_alloc (StreamWriter *stream_writer) +{ + ep_return_null_if_nok (stream_writer != NULL); + + FastSerializer *instance = ep_rt_object_alloc (FastSerializer); + ep_raise_error_if_nok (instance != NULL); + + // Ownership transfered. + instance->stream_writer = stream_writer; + instance->required_padding = 0; + instance->write_error_encountered = false; + + const ep_char8_t signature[] = "!FastSerialization.1"; // the consumer lib expects exactly the same string, it must not be changed + uint32_t signature_len = EP_ARRAY_SIZE (signature) - 1; + ep_fast_serializer_write_string (instance, signature, signature_len); + +ep_on_exit: + return instance; + +ep_on_error: + ep_fast_serializer_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_fast_serializer_free (FastSerializer *fast_serializer) +{ + ep_return_void_if_nok (fast_serializer != NULL); + + EP_ASSERT (fast_serializer->stream_writer != NULL); + ep_stream_writer_free_vcall (fast_serializer->stream_writer); + + ep_rt_object_free (fast_serializer); +} + +/* + * FileStream. + */ + +FileStream * +ep_file_stream_alloc (void) +{ + return ep_rt_object_alloc (FileStream); +} + +void +ep_file_stream_free (FileStream *file_stream) +{ + ep_return_void_if_nok (file_stream != NULL); + + ep_file_stream_close (file_stream); + ep_rt_object_free (file_stream); +} + +/* + * FileStreamWriter. + */ + +static +void +file_stream_writer_free_func (void *stream) +{ + ep_file_stream_writer_free ((FileStreamWriter *)stream); +} + +static +bool +file_stream_writer_write_func ( + void *stream, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written) +{ + EP_ASSERT (stream != NULL); + + return ep_file_stream_writer_write ( + (FileStreamWriter *)stream, + buffer, + bytes_to_write, + bytes_written); +} + +static StreamWriterVtable file_stream_writer_vtable = { + file_stream_writer_free_func, + file_stream_writer_write_func }; + +FileStreamWriter * +ep_file_stream_writer_alloc (const ep_char8_t *output_file_path) +{ + ep_return_null_if_nok (output_file_path != NULL); + + FileStreamWriter *instance = ep_rt_object_alloc (FileStreamWriter); + ep_raise_error_if_nok (instance != NULL); + + ep_raise_error_if_nok (ep_stream_writer_init ( + &instance->stream_writer, + &file_stream_writer_vtable) != NULL); + + instance->file_stream = ep_file_stream_alloc (); + ep_raise_error_if_nok (instance->file_stream != NULL); + + if (!ep_file_stream_open_write (instance->file_stream, output_file_path)) { + EP_ASSERT (!"Unable to open file for write."); + ep_raise_error (); + } + +ep_on_exit: + return instance; + +ep_on_error: + ep_file_stream_writer_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_file_stream_writer_free (FileStreamWriter *file_stream_writer) +{ + ep_return_void_if_nok (file_stream_writer != NULL); + + ep_file_stream_free (file_stream_writer->file_stream); + ep_stream_writer_fini (&file_stream_writer->stream_writer); + ep_rt_object_free (file_stream_writer); +} + +/* + * IpcStream. + */ + +IpcStream * +ep_ipc_stream_alloc (ep_rt_ipc_handle_t rt_ipc) +{ + IpcStream *instance = ep_rt_object_alloc (IpcStream); + ep_raise_error_if_nok (instance != NULL); + + //Transfer ownership. + instance->rt_ipc = rt_ipc; + +ep_on_exit: + return instance; + +ep_on_error: + ep_ipc_stream_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_ipc_stream_free (IpcStream *ipc_stream) +{ + ep_return_void_if_nok (ipc_stream != NULL); + + ep_ipc_stream_flush (ipc_stream); + ep_ipc_stream_disconnect (ipc_stream); + ep_ipc_stream_close (ipc_stream); + + ep_rt_object_free (ipc_stream); +} + +/* + * IpcStreamWriter. + */ + +static +void +ipc_stream_writer_free_func (void *stream) +{ + ep_ipc_stream_writer_free ((IpcStreamWriter *)stream); +} + +static +bool +ipc_stream_writer_write_func ( + void *stream, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written) +{ + EP_ASSERT (stream != NULL); + + return ep_ipc_stream_writer_write ( + (IpcStreamWriter *)stream, + buffer, + bytes_to_write, + bytes_written); +} + +static StreamWriterVtable ipc_stream_writer_vtable = { + ipc_stream_writer_free_func, + ipc_stream_writer_write_func }; + +IpcStreamWriter * +ep_ipc_stream_writer_alloc ( + uint64_t id, + IpcStream *stream) +{ + IpcStreamWriter *instance = ep_rt_object_alloc (IpcStreamWriter); + ep_raise_error_if_nok (instance != NULL); + + ep_raise_error_if_nok (ep_stream_writer_init ( + &instance->stream_writer, + &ipc_stream_writer_vtable) != NULL); + + //Ownership transfered. + instance->ipc_stream = stream; + +ep_on_exit: + return instance; + +ep_on_error: + ep_ipc_stream_writer_free (instance); + + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_ipc_stream_writer_free (IpcStreamWriter *ipc_stream_writer) +{ + ep_return_void_if_nok (ipc_stream_writer != NULL); + + ep_ipc_stream_free (ipc_stream_writer->ipc_stream); + ep_stream_writer_fini (&ipc_stream_writer->stream_writer); + ep_rt_object_free (ipc_stream_writer); +} + +/* + * StreamWriter. + */ + +StreamWriter * +ep_stream_writer_init ( + StreamWriter *stream_writer, + StreamWriterVtable *vtable) +{ + EP_ASSERT (stream_writer != NULL && vtable != NULL); + + stream_writer->vtable = vtable; + + return stream_writer; +} + +void +ep_stream_writer_fini (StreamWriter *stream_writer) +{ + ; +} + +void +ep_stream_writer_free_vcall (StreamWriter *stream_writer) +{ + ep_return_void_if_nok (stream_writer != NULL); + + EP_ASSERT (stream_writer->vtable != NULL); + StreamWriterVtable *vtable = stream_writer->vtable; + + EP_ASSERT (vtable->free_func != NULL); + vtable->free_func (stream_writer); +} + +bool +ep_stream_writer_write_vcall ( + StreamWriter *stream_writer, + const uint8_t *buffer, + const uint32_t bytes_to_write, + uint32_t *bytes_written) +{ + EP_ASSERT (stream_writer != NULL && stream_writer->vtable != NULL); + StreamWriterVtable *vtable = stream_writer->vtable; + + EP_ASSERT (vtable->write_func != NULL); + return vtable->write_func (stream_writer, buffer, bytes_to_write, bytes_written); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_stream_internals; +const char quiet_linker_empty_file_warning_eventpipe_stream_internals = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-stream.c b/src/mono/mono/eventpipe/ep-stream.c new file mode 100644 index 00000000000000..5d9ee0060aa38f --- /dev/null +++ b/src/mono/mono/eventpipe/ep-stream.c @@ -0,0 +1,280 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#include "ep.h" + +/* + * Forward declares of all static functions. + */ + +static +void +fast_serializer_write_serialization_type ( + FastSerializer *fast_serializer, + FastSerializableObject *fast_serializable_ojbect); + +/* + * FastSerializableObject. + */ + +void +ep_fast_serializable_object_fast_serialize ( + FastSerializableObject *fast_serializable_ojbect, + FastSerializer *fast_serializer) +{ + ep_fast_serializable_object_fast_serialize_vcall (fast_serializable_ojbect, fast_serializer); +} + +const ep_char8_t * +ep_fast_serializable_object_get_type_name (FastSerializableObject *fast_serializable_ojbect) +{ + return ep_fast_serializable_object_get_type_name_vcall (fast_serializable_ojbect); +} + +/* + * FastSerializer. + */ + +static +void +fast_serializer_write_serialization_type ( + FastSerializer *fast_serializer, + FastSerializableObject *fast_serializable_ojbect) +{ + ep_return_void_if_nok (fast_serializable_ojbect != NULL); + + // Write the BeginObject tag. + ep_fast_serializer_write_tag (fast_serializer, ep_fast_serializable_object_get_is_private (fast_serializable_ojbect) ? FAST_SERIALIZER_TAGS_BEGIN_PRIVATE_OBJECT : FAST_SERIALIZER_TAGS_BEGIN_OBJECT, NULL, 0); + + // Write a NullReferenceTag, which implies that the following fields belong to SerializationType. + ep_fast_serializer_write_tag (fast_serializer, FAST_SERIALIZER_TAGS_NULL_REFERENCE, NULL, 0); + + // Write the SerializationType version fields. + int32_t serialization_type [2]; + serialization_type [0] = ep_fast_serializable_object_get_object_version (fast_serializable_ojbect); + serialization_type [1] = ep_fast_serializable_object_get_min_reader_version (fast_serializable_ojbect); + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)serialization_type, sizeof (serialization_type)); + + // Write the SerializationType TypeName field. + const ep_char8_t *type_name = ep_fast_serializable_object_get_type_name_vcall (fast_serializable_ojbect); + if (type_name) + ep_fast_serializer_write_string (fast_serializer, type_name, (uint32_t)ep_rt_utf8_string_len (type_name)); + + // Write the EndObject tag. + ep_fast_serializer_write_tag (fast_serializer, FAST_SERIALIZER_TAGS_END_OBJECT, NULL, 0); +} + +void +ep_fast_serializer_write_buffer ( + FastSerializer *fast_serializer, + const uint8_t *buffer, + uint32_t buffer_len) +{ + ep_return_void_if_nok (fast_serializer != NULL && buffer != NULL && buffer_len > 0); + ep_return_void_if_nok (ep_fast_serializer_get_write_error_encountered (fast_serializer) != true && ep_fast_serializer_get_stream_writer (fast_serializer) != NULL); + + uint32_t bytes_written = 0; + bool result = ep_stream_writer_write (ep_fast_serializer_get_stream_writer (fast_serializer), buffer, buffer_len, &bytes_written); + + uint32_t required_padding = ep_fast_serializer_get_required_padding (fast_serializer); + required_padding = (FAST_SERIALIZER_ALIGNMENT_SIZE + required_padding - (bytes_written & FAST_SERIALIZER_ALIGNMENT_SIZE)) % FAST_SERIALIZER_ALIGNMENT_SIZE; + ep_fast_serializer_set_required_padding (fast_serializer, required_padding); + + // This will cause us to stop writing to the file. + // The file will still remain open until shutdown so that we don't + // have to take a lock at this level when we touch the file stream. + ep_fast_serializer_set_write_error_encountered (fast_serializer, ((buffer_len != bytes_written) || !result)); +} + +void +ep_fast_serializer_write_object ( + FastSerializer *fast_serializer, + FastSerializableObject *fast_serializable_ojbect) +{ + ep_return_void_if_nok (fast_serializer != NULL && fast_serializable_ojbect != NULL); + + ep_fast_serializer_write_tag (fast_serializer, ep_fast_serializable_object_get_is_private (fast_serializable_ojbect) ? FAST_SERIALIZER_TAGS_BEGIN_PRIVATE_OBJECT : FAST_SERIALIZER_TAGS_BEGIN_OBJECT, NULL, 0); + + fast_serializer_write_serialization_type (fast_serializer, fast_serializable_ojbect); + + // Ask the object to serialize itself using the current serializer. + ep_fast_serializable_object_fast_serialize_vcall (fast_serializable_ojbect, fast_serializer); + + ep_fast_serializer_write_tag (fast_serializer, FAST_SERIALIZER_TAGS_END_OBJECT, NULL, 0); +} + +void +ep_fast_serializer_write_string ( + FastSerializer *fast_serializer, + const ep_char8_t *contents, + uint32_t contents_len) +{ + // Write teh string length. + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)&contents_len, sizeof (contents_len)); + + //Wirte the string contents. + ep_fast_serializer_write_buffer (fast_serializer, (const uint8_t *)contents, contents_len); +} + +void +ep_fast_serializer_write_tag ( + FastSerializer *fast_serializer, + FastSerializerTags tag, + const uint8_t *payload, + uint32_t payload_len) +{ + uint8_t tag_as_byte = tag; + ep_fast_serializer_write_buffer (fast_serializer, &tag_as_byte, sizeof (tag_as_byte)); + if (payload != NULL) { + EP_ASSERT (payload_len > 0); + ep_fast_serializer_write_buffer (fast_serializer, payload, payload_len); + } +} + +/* +* FileStream. +*/ + +bool +ep_file_stream_open_write ( + FileStream *file_stream, + const ep_char8_t *path) +{ + ep_return_false_if_nok (file_stream != NULL); + + ep_rt_file_handle_t rt_file = ep_rt_file_open_write (path); + ep_raise_error_if_nok (rt_file != NULL); + + ep_file_stream_set_rt_file (file_stream, rt_file); + return true; + +ep_on_error: + return false; +} + +bool +ep_file_stream_close (FileStream *file_stream) +{ + ep_return_false_if_nok (file_stream != NULL); + return ep_rt_file_close (ep_file_stream_get_rt_file (file_stream)); +} + +bool +ep_file_stream_write ( + FileStream *file_stream, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written) +{ + ep_return_false_if_nok (file_stream != NULL && buffer != NULL && bytes_to_write > 0 && bytes_written != NULL); + return ep_rt_file_write (ep_file_stream_get_rt_file (file_stream), buffer, bytes_to_write, bytes_written); +} + +/* + * FileStreamWriter. + */ + +bool +ep_file_stream_writer_write ( + FileStreamWriter *file_stream_writer, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written) +{ + ep_return_false_if_nok (file_stream_writer != NULL && buffer != NULL && bytes_to_write > 0 && bytes_written != NULL); + + ep_raise_error_if_nok (ep_file_stream_writer_get_file_stream (file_stream_writer) != NULL); + + return ep_file_stream_write (ep_file_stream_writer_get_file_stream (file_stream_writer), buffer, bytes_to_write, bytes_written); + +ep_on_error: + *bytes_written = 0; + return false; +} + +/* +* IpcStream. +*/ + +bool +ep_ipc_stream_flush (IpcStream *ipc_stream) +{ + //TODO: Implement. + return false; +} + +bool +ep_ipc_stream_disconnect (IpcStream *ipc_stream) +{ + //TODO: Implement. + return false; +} + +bool +ep_ipc_stream_close (IpcStream *ipc_stream) +{ + //TODO: Implement. + return false; +} + +bool +ep_ipc_stream_write ( + IpcStream *ipc_stream, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written) +{ + //TODO: Implement. + return false; +} + +/* + * IpcStreamWriter. + */ + +bool +ep_ipc_stream_writer_write ( + IpcStreamWriter *ipc_stream_writer, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written) +{ + ep_return_false_if_nok (ipc_stream_writer != NULL && buffer != NULL && bytes_to_write > 0 && bytes_written != NULL); + + ep_raise_error_if_nok (ep_ipc_stream_writer_get_ipc_stream (ipc_stream_writer) != NULL); + + return ep_ipc_stream_write (ep_ipc_stream_writer_get_ipc_stream (ipc_stream_writer), buffer, bytes_to_write, bytes_written); + +ep_on_error: + *bytes_written = 0; + return false; +} + +/* + * StreamWriter. + */ + +bool +ep_stream_writer_write ( + StreamWriter *stream_writer, + const uint8_t *buffer, + const uint32_t bytes_to_write, + uint32_t *bytes_written) +{ + return ep_stream_writer_write_vcall ( + stream_writer, + buffer, + bytes_to_write, + bytes_written); +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_stream; +const char quiet_linker_empty_file_warning_eventpipe_stream = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-stream.h b/src/mono/mono/eventpipe/ep-stream.h new file mode 100644 index 00000000000000..16d9c9e49b8e38 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-stream.h @@ -0,0 +1,364 @@ +#ifndef __EVENTPIPE_STREAM_H__ +#define __EVENTPIPE_STREAM_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +// the enumeration has a specific set of values to keep it compatible with consumer library +// it's sibling is defined in https://github.com/Microsoft/perfview/blob/10d1f92b242c98073b3817ac5ee6d98cd595d39b/src/FastSerialization/FastSerialization.cs#L2295 +typedef enum +{ + FAST_SERIALIZER_TAGS_ERROR = 0, // To improve debugabilty, 0 is an illegal tag. + FAST_SERIALIZER_TAGS_NULL_REFERENCE = 1, // Tag for a null object forwardReference. + FAST_SERIALIZER_TAGS_OBJECT_REFERENCE = 2, // Followed by StreamLabel + // 3 used to belong to ForwardReference, which got removed in V3 + FAST_SERIALIZER_TAGS_BEGIN_OBJECT = 4, // Followed by Type object, object data, tagged EndObject + FAST_SERIALIZER_TAGS_BEGIN_PRIVATE_OBJECT = 5, // Like beginObject, but not placed in interning table on deserialiation + FAST_SERIALIZER_TAGS_END_OBJECT = 6, // Placed after an object to mark its end. + // 7 used to belong to ForwardDefinition, which got removed in V3 + FAST_SERIALIZER_TAGS_BYTE = 8, + FAST_SERIALIZER_TAGS_INT16, + FAST_SERIALIZER_TAGS_INT32, + FAST_SERIALIZER_TAGS_INT64, + FAST_SERIALIZER_TAGS_SKIP_REGION, + FAST_SERIALIZER_TAGS_STRING, + FAST_SERIALIZER_TAGS_BLOB, + FAST_SERIALIZER_TAGS_LIMIT // Just past the last valid tag, used for asserts. +} FastSerializerTags; + +/* + * StreamWriter. + */ + +typedef void (*StreamWriterFreeFunc)(void *stream); +typedef bool (*StreamWriterWriteFunc)(void *stream, const uint8_t *buffer, const uint32_t bytes_to_write, uint32_t *bytes_written); + +struct _StreamWriterVtable { + StreamWriterFreeFunc free_func; + StreamWriterWriteFunc write_func; +}; + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _StreamWriter { +#else +struct _StreamWriter_Internal { +#endif + StreamWriterVtable *vtable; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _StreamWriter { + uint8_t _internal [sizeof (struct _StreamWriter_Internal)]; +}; +#endif + +StreamWriter * +ep_stream_writer_init ( + StreamWriter *stream_writer, + StreamWriterVtable *vtable); + +void +ep_stream_writer_fini (StreamWriter *stream_writer); + +bool +ep_stream_writer_write ( + StreamWriter *stream_writer, + const uint8_t *buffer, + const uint32_t bytes_to_write, + uint32_t *bytes_written); + +void +ep_stream_writer_free_vcall (StreamWriter *stream_writer); + +bool +ep_stream_writer_write_vcall ( + StreamWriter *stream_writer, + const uint8_t *buffer, + const uint32_t bytes_to_write, + uint32_t *bytes_written); + +/* + * FastSerializableObject. + */ + +typedef void (*FastSerializableObjectFreeFunc)(void *object); +typedef void (*FastSerializableObjectFastSerializeFunc)(void *object, FastSerializer *fast_serializer); +typedef const ep_char8_t * (*FastSerializableObjectGetTypeNameFunc)(void *object); + +struct _FastSerializableObjectVtable { + FastSerializableObjectFreeFunc free_func; + FastSerializableObjectFastSerializeFunc fast_serialize_func; + FastSerializableObjectGetTypeNameFunc get_type_name_func; +}; + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _FastSerializableObject { +#else +struct _FastSerializableObject_Internal { +#endif + FastSerializableObjectVtable *vtable; + int32_t object_version; + int32_t min_reader_version; + bool is_private; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _FastSerializableObject { + uint8_t _internal [sizeof (struct _FastSerializableObject_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(FastSerializableObject *, fast_serializable_object, int32_t, object_version) +EP_DEFINE_GETTER(FastSerializableObject *, fast_serializable_object, int32_t, min_reader_version) +EP_DEFINE_GETTER(FastSerializableObject *, fast_serializable_object, bool, is_private) + +FastSerializableObject * +ep_fast_serializable_object_init ( + FastSerializableObject *fast_serializable_object, + FastSerializableObjectVtable *vtable, + int32_t object_version, + int32_t min_reader_version, + bool is_private); + +void +ep_fast_serializable_object_fini (FastSerializableObject *fast_serializable_object); + +void +ep_fast_serializable_object_fast_serialize ( + FastSerializableObject *fast_serializable_ojbect, + FastSerializer *fast_serializer); + +const ep_char8_t * +ep_fast_serializable_object_get_type_name (FastSerializableObject *fast_serializable_ojbect); + +void +ep_fast_serializable_object_free_vcall (FastSerializableObject *fast_serializable_ojbect); + +const ep_char8_t * +ep_fast_serializable_object_get_type_name_vcall (FastSerializableObject *fast_serializable_ojbect); + +void +ep_fast_serializable_object_fast_serialize_vcall ( + FastSerializableObject *fast_serializable_ojbect, + FastSerializer *fast_serializer); + +/* + * FastSerializer. + */ + +#define FAST_SERIALIZER_ALIGNMENT_SIZE 4 + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _FastSerializer { +#else +struct _FastSerializer_Internal { +#endif + StreamWriter *stream_writer; + uint32_t required_padding; + bool write_error_encountered; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _FastSerializer { + uint8_t _internal [sizeof (struct _FastSerializer_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(FastSerializer *, fast_serializer, StreamWriter *, stream_writer) +EP_DEFINE_GETTER(FastSerializer *, fast_serializer, uint32_t, required_padding) +EP_DEFINE_SETTER(FastSerializer *, fast_serializer, uint32_t, required_padding) +EP_DEFINE_GETTER(FastSerializer *, fast_serializer, bool, write_error_encountered) +EP_DEFINE_SETTER(FastSerializer *, fast_serializer, bool, write_error_encountered) + +FastSerializer * +ep_fast_serializer_alloc (StreamWriter *stream_writer); + +void +ep_fast_serializer_free (FastSerializer *fast_serializer); + +void +ep_fast_serializer_write_buffer ( + FastSerializer *fast_serializer, + const uint8_t *buffer, + uint32_t buffer_len); + +void +ep_fast_serializer_write_object ( + FastSerializer *fast_serializer, + FastSerializableObject *fast_serializable_ojbect); + +void +ep_fast_serializer_write_string ( + FastSerializer *fast_serializer, + const ep_char8_t *contents, + uint32_t contents_len); + +void +ep_fast_serializer_write_tag ( + FastSerializer *fast_serializer, + FastSerializerTags tag, + const uint8_t *payload, + uint32_t payload_len); + +/* +* FileStream. +*/ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _FileStream { +#else +struct _FileStream_Internal { +#endif + ep_rt_file_handle_t rt_file; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _FileStream { + uint8_t _internal [sizeof (struct _FileStream_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(FileStream *, file_stream, ep_rt_file_handle_t, rt_file) +EP_DEFINE_SETTER(FileStream *, file_stream, ep_rt_file_handle_t, rt_file) + +FileStream * +ep_file_stream_alloc (void); + +void +ep_file_stream_free (FileStream *file_stream); + +bool +ep_file_stream_open_write ( + FileStream *file_stream, + const ep_char8_t *path); + +bool +ep_file_stream_close (FileStream *file_stream); + +bool +ep_file_stream_write ( + FileStream *file_stream, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written); + +/* + * FileStreamWriter. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _FileStreamWriter { +#else +struct _FileStreamWriter_Internal { +#endif + StreamWriter stream_writer; + FileStream *file_stream; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _FileStreamWriter { + uint8_t _internal [sizeof (struct _FileStreamWriter_Internal)]; +}; +#endif + +EP_DEFINE_GETTER_REF(FileStreamWriter *, file_stream_writer, StreamWriter *, stream_writer) +EP_DEFINE_GETTER(FileStreamWriter *, file_stream_writer, FileStream *, file_stream) + +FileStreamWriter * +ep_file_stream_writer_alloc (const ep_char8_t *output_file_path); + +void +ep_file_stream_writer_free (FileStreamWriter *file_stream_writer); + +bool +ep_file_stream_writer_write ( + FileStreamWriter *file_stream_writer, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written); + +/* + * IpcStream. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +//TODO: Implement. +struct _IpcStream { +#else +struct _IpcStream_Internal { +#endif + ep_rt_ipc_handle_t rt_ipc; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _IpcStream { + uint8_t _internal [sizeof (struct _IpcStream_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(IpcStream *, ipc_stream, ep_rt_ipc_handle_t, rt_ipc) + +IpcStream * +ep_ipc_stream_alloc (ep_rt_ipc_handle_t rt_ipc); + +void +ep_ipc_stream_free (IpcStream *ipc_stream); + +bool +ep_ipc_stream_flush (IpcStream *stream); + +bool +ep_ipc_stream_disconnect (IpcStream *stream); + +bool +ep_ipc_stream_close (IpcStream *stream); + +bool +ep_ipc_stream_write ( + IpcStream *stream, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written); + +/* + * IpcStreamWriter. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _IpcStreamWriter { +#else +struct _IpcStreamWriter_Internal { +#endif + StreamWriter stream_writer; + IpcStream *ipc_stream; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _IpcStreamWriter { + uint8_t _internal [sizeof (struct _IpcStreamWriter_Internal)]; +}; +#endif + +EP_DEFINE_GETTER_REF(IpcStreamWriter *, ipc_stream_writer, StreamWriter *, stream_writer) +EP_DEFINE_GETTER(IpcStreamWriter *, ipc_stream_writer, IpcStream *, ipc_stream) + +IpcStreamWriter * +ep_ipc_stream_writer_alloc ( + uint64_t id, + IpcStream *stream); + +void +ep_ipc_stream_writer_free (IpcStreamWriter *ipc_stream_writer); + +bool +ep_ipc_stream_writer_write ( + IpcStreamWriter *ipc_stream_writer, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written); + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_STREAM_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-thread-internals.c b/src/mono/mono/eventpipe/ep-thread-internals.c new file mode 100644 index 00000000000000..da2d7ad2b624f2 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-thread-internals.c @@ -0,0 +1,219 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#define EP_IMPL_GETTER_SETTER +#include "ep.h" + +/* + * EventPipeThread. + */ + +EventPipeThread * +ep_thread_alloc (void) +{ + EventPipeThread *instance = ep_rt_object_alloc (EventPipeThread); + ep_raise_error_if_nok (instance != NULL); + + ep_rt_spin_lock_alloc (&instance->rt_lock); + ep_raise_error_if_nok (instance->rt_lock.lock != NULL); + + instance->os_thread_id = ep_rt_current_thread_get_id (); + memset (instance->session_state, 0, sizeof (instance->session_state)); + +ep_on_exit: + return instance; + +ep_on_error: + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_thread_free (EventPipeThread *thread) +{ + ep_return_void_if_nok (thread != NULL); + + EP_ASSERT (ep_rt_volatile_load_uint32_t ((const volatile uint32_t *)&thread->ref_count) == 0); + +#ifdef EP_CHECKED_BUILD + for (uint32_t i = 0; i < EP_MAX_NUMBER_OF_SESSIONS; ++i) { + EP_ASSERT (thread->session_state [i] == NULL); + } +#endif + + ep_rt_spin_lock_free (&thread->rt_lock); + ep_rt_object_free (thread); +} + +/* + * EventPipeThreadHolder. + */ + +EventPipeThreadHolder * +ep_thread_holder_alloc (EventPipeThread *thread) +{ + ep_return_null_if_nok (thread != NULL); + + EventPipeThreadHolder *instance = ep_rt_object_alloc (EventPipeThreadHolder); + ep_raise_error_if_nok (instance != NULL); + ep_raise_error_if_nok (ep_thread_holder_init (instance, thread) != NULL); + +ep_on_exit: + return instance; + +ep_on_error: + instance = NULL; + ep_exit_error_handler (); +} + +EventPipeThreadHolder * +ep_thread_holder_init ( + EventPipeThreadHolder *thread_holder, + EventPipeThread *thread) +{ + ep_return_null_if_nok (thread_holder != NULL && thread != NULL); + + thread_holder->thread = thread; + ep_thread_addref (thread_holder->thread); + + return thread_holder; +} + +void +ep_thread_holder_fini (EventPipeThreadHolder *thread_holder) +{ + ep_return_void_if_nok (thread_holder != NULL && thread_holder->thread); + ep_thread_release (thread_holder->thread); +} + +void +ep_thread_holder_free (EventPipeThreadHolder *thread_holder) +{ + ep_return_void_if_nok (thread_holder != NULL); + ep_thread_holder_fini (thread_holder); + ep_rt_object_free (thread_holder); +} + +/* + * EventPipeThreadSessionState. + */ + +EventPipeThreadSessionState * +ep_thread_session_state_alloc ( + EventPipeThread *thread, + EventPipeSession *session, + EventPipeBufferManager *buffer_manager) +{ + EventPipeThreadSessionState *instance = ep_rt_object_alloc (EventPipeThreadSessionState); + ep_raise_error_if_nok (instance != NULL); + + ep_raise_error_if_nok (ep_thread_holder_init (&instance->thread_holder, thread) != NULL); + + instance->session = session; + instance->sequence_number = 1; + +#ifdef EP_CHECKED_BUILD + instance->buffer_manager = buffer_manager; +#endif + +ep_on_exit: + return instance; + +ep_on_error: + instance = NULL; + ep_exit_error_handler (); +} + +void +ep_thread_session_state_free (EventPipeThreadSessionState *thread_session_state) +{ + ep_return_void_if_nok (thread_session_state != NULL); + ep_thread_holder_fini (&thread_session_state->thread_holder); + ep_rt_object_free (thread_session_state); +} + +EventPipeThread * +ep_thread_session_state_get_thread (const EventPipeThreadSessionState *thread_session_state) +{ + EP_ASSERT (thread_session_state != NULL); + return thread_session_state->thread_holder.thread; +} + +EventPipeBuffer * +ep_thread_session_state_get_write_buffer (const EventPipeThreadSessionState *thread_session_state) +{ + EP_ASSERT (thread_session_state != NULL); + ep_thread_requires_lock_held (thread_session_state->thread_holder.thread); + + EP_ASSERT ((thread_session_state->write_buffer == NULL) || (ep_rt_volatile_load_uint32_t (&thread_session_state->write_buffer->state) == EP_BUFFER_STATE_WRITABLE)); + return thread_session_state->write_buffer; +} + +void +ep_thread_session_state_set_write_buffer ( + EventPipeThreadSessionState *thread_session_state, + EventPipeBuffer *new_buffer) +{ + EP_ASSERT (thread_session_state != NULL); + ep_thread_requires_lock_held (thread_session_state->thread_holder.thread); + + EP_ASSERT ((new_buffer == NULL) || (ep_rt_volatile_load_uint32_t (&thread_session_state->write_buffer->state) == EP_BUFFER_STATE_WRITABLE)); + EP_ASSERT ((thread_session_state->write_buffer == NULL) || (ep_rt_volatile_load_uint32_t (&thread_session_state->write_buffer->state) == EP_BUFFER_STATE_WRITABLE)); + + if (thread_session_state->write_buffer) + ep_buffer_convert_to_read_only (thread_session_state->write_buffer); + + thread_session_state->write_buffer = new_buffer; +} + +EventPipeBufferList * +ep_thread_session_state_get_buffer_list (const EventPipeThreadSessionState *thread_session_state) +{ + EP_ASSERT (thread_session_state != NULL); + ep_buffer_manager_requires_lock_held (thread_session_state->buffer_manager); + return thread_session_state->buffer_list; +} + +void +ep_thread_session_state_set_buffer_list ( + EventPipeThreadSessionState *thread_session_state, + EventPipeBufferList *new_buffer_list) +{ + EP_ASSERT (thread_session_state != NULL); + ep_buffer_manager_requires_lock_held (thread_session_state->buffer_manager); + thread_session_state->buffer_list = new_buffer_list; +} + +uint32_t +ep_thread_session_state_get_volatile_sequence_number (const EventPipeThreadSessionState *thread_session_state) +{ + EP_ASSERT (thread_session_state != NULL); + return ep_rt_volatile_load_uint32_t_without_barrier (&thread_session_state->sequence_number); +} + +uint32_t +ep_thread_session_state_get_sequence_number (const EventPipeThreadSessionState *thread_session_state) +{ + EP_ASSERT (thread_session_state != NULL); + ep_thread_requires_lock_held (thread_session_state->thread_holder.thread); + return ep_rt_volatile_load_uint32_t_without_barrier (&thread_session_state->sequence_number); +} + +void +ep_thread_session_state_increment_sequence_number (EventPipeThreadSessionState *thread_session_state) +{ + EP_ASSERT (thread_session_state != NULL); + ep_thread_requires_lock_held (thread_session_state->thread_holder.thread); + thread_session_state->sequence_number++; +} + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_thread_internals; +const char quiet_linker_empty_file_warning_eventpipe_thread_internals = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-thread.c b/src/mono/mono/eventpipe/ep-thread.c new file mode 100644 index 00000000000000..68632bea401b0d --- /dev/null +++ b/src/mono/mono/eventpipe/ep-thread.c @@ -0,0 +1,157 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#if !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) + +#include "ep.h" + +/* + * EventPipeThread. + */ + +void +ep_thread_addref (EventPipeThread *thread) +{ + EP_ASSERT (thread != NULL); + ep_rt_atomic_inc_int32_t (ep_thread_get_ref_count_ref (thread)); +} + +void +ep_thread_release (EventPipeThread *thread) +{ + EP_ASSERT (thread != NULL); + if (ep_rt_atomic_dec_int32_t (ep_thread_get_ref_count_ref (thread)) == 0) + ep_thread_free (thread); +} + +EventPipeThread * +ep_thread_get (void) +{ + return ep_rt_thread_get (); +} + +EventPipeThread * +ep_thread_get_or_create (void) +{ + return ep_rt_thread_get_or_create (); +} + +void +ep_thread_create_activity_id ( + uint8_t *activity_id, + uint32_t activity_id_len) +{ + ep_return_void_if_nok (activity_id != NULL); + ep_rt_create_activity_id (activity_id, activity_id_len); +} + +void +ep_thread_get_activity_id ( + EventPipeThread *thread, + uint8_t *activity_id, + uint32_t activity_id_len) +{ + ep_return_void_if_nok (thread != NULL && activity_id != NULL); + EP_ASSERT (activity_id_len == EP_ACTIVITY_ID_SIZE); + memcpy (activity_id, ep_thread_get_activity_id_cref (thread), EP_ACTIVITY_ID_SIZE); +} + +void +ep_thread_set_activity_id ( + EventPipeThread *thread, + const uint8_t *activity_id, + uint32_t activity_id_len) +{ + ep_return_void_if_nok (thread != NULL && activity_id != NULL); + EP_ASSERT (activity_id_len == EP_ACTIVITY_ID_SIZE); + memcpy (ep_thread_get_activity_id_ref (thread), activity_id, EP_ACTIVITY_ID_SIZE); +} + +void +ep_thread_set_session_write_in_progress ( + EventPipeThread *thread, + uint32_t session_index) +{ + ep_return_void_if_nok (thread != NULL); + ep_rt_volatile_store_uint32_t (ep_thread_get_writing_event_in_progress_ref (thread), session_index); +} + +uint32_t +ep_thread_get_session_write_in_progress (const EventPipeThread *thread) +{ + ep_return_zero_if_nok (thread != NULL); + return ep_rt_volatile_load_uint32_t (ep_thread_get_writing_event_in_progress_cref (thread)); +} + +EventPipeThreadSessionState * +ep_thread_get_or_create_session_state ( + EventPipeThread *thread, + EventPipeSession *session) +{ + ep_return_null_if_nok (thread != NULL && session != NULL); + EP_ASSERT (ep_session_get_index (session) < EP_MAX_NUMBER_OF_SESSIONS); + ep_thread_requires_lock_held (thread); + + EventPipeThreadSessionState *state = ep_thread_get_session_state_ref (thread)[ep_session_get_index (session)]; + if (!state) { + state = ep_thread_session_state_alloc (thread, session, ep_session_get_buffer_manager (session)); + ep_thread_get_session_state_ref (thread)[ep_session_get_index (session)] = state; + } + + return state; +} + +EventPipeThreadSessionState * +ep_thread_get_session_state ( + const EventPipeThread *thread, + EventPipeSession *session) +{ + ep_return_null_if_nok (thread != NULL && session != NULL); + EP_ASSERT (ep_session_get_index (session) < EP_MAX_NUMBER_OF_SESSIONS); + ep_thread_requires_lock_held (thread); + + EventPipeThreadSessionState *const state = ep_thread_get_session_state_cref (thread)[ep_session_get_index (session)]; + EP_ASSERT (state != NULL); + return state; +} + +void +ep_thread_delete_session_state ( + EventPipeThread *thread, + EventPipeSession *session) +{ + ep_return_void_if_nok (thread != NULL && session != NULL); + ep_thread_requires_lock_held (thread); + + uint32_t index = ep_session_get_index (session); + EP_ASSERT (index < EP_MAX_NUMBER_OF_SESSIONS); + EventPipeThreadSessionState *state = ep_thread_get_session_state_ref (thread)[index]; + EP_ASSERT (state != NULL); + ep_thread_session_state_free (state); + ep_thread_get_session_state_ref (thread)[index] = NULL; +} + +#ifdef EP_CHECKED_BUILD +void +ep_thread_requires_lock_held (const EventPipeThread *thread) +{ + EP_ASSERT (thread != NULL); + ep_rt_spin_lock_requires_lock_held (ep_thread_get_rt_lock_cref (thread)); +} + +void +ep_thread_requires_lock_not_held (const EventPipeThread *thread) +{ + EP_ASSERT (thread != NULL); + ep_rt_spin_lock_requires_lock_not_held (ep_thread_get_rt_lock_cref (thread)); +} +#endif + +#endif /* !defined(EP_INCLUDE_SOURCE_FILES) || defined(EP_FORCE_INCLUDE_SOURCE_FILES) */ +#endif /* ENABLE_PERFTRACING */ + +#ifndef EP_INCLUDE_SOURCE_FILES +extern const char quiet_linker_empty_file_warning_eventpipe_thread; +const char quiet_linker_empty_file_warning_eventpipe_thread = 0; +#endif diff --git a/src/mono/mono/eventpipe/ep-thread.h b/src/mono/mono/eventpipe/ep-thread.h new file mode 100644 index 00000000000000..23d0e5093f2374 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-thread.h @@ -0,0 +1,233 @@ +#ifndef __EVENTPIPE_THREAD_H__ +#define __EVENTPIPE_THREAD_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" + +/* + * EventPipeThread. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeThread { +#else +struct _EventPipeThread_Internal { +#endif + EventPipeThreadSessionState *session_state [EP_MAX_NUMBER_OF_SESSIONS]; + uint8_t activity_id [EP_ACTIVITY_ID_SIZE]; + EventPipeSession *rundown_session; + size_t os_thread_id; + ep_rt_thread_handle_t rt_thread; + ep_rt_spin_lock_handle_t rt_lock; + int32_t ref_count; + volatile uint32_t writing_event_in_progress; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeThread { + uint8_t _internal [sizeof (struct _EventPipeThread_Internal)]; +}; +#endif + +EP_DEFINE_GETTER_ARRAY_REF(EventPipeThread *, thread, EventPipeThreadSessionState **, EventPipeThreadSessionState *const*, session_state, session_state[0]); +EP_DEFINE_GETTER_ARRAY_REF(EventPipeThread *, thread, uint8_t *, const uint8_t *, activity_id, activity_id[0]); +EP_DEFINE_GETTER(EventPipeThread *, thread, EventPipeSession *, rundown_session); +EP_DEFINE_SETTER(EventPipeThread *, thread, EventPipeSession *, rundown_session); +EP_DEFINE_GETTER(EventPipeThread *, thread, size_t, os_thread_id); +EP_DEFINE_GETTER_REF(EventPipeThread *, thread, ep_rt_spin_lock_handle_t *, rt_lock); +EP_DEFINE_GETTER_REF(EventPipeThread *, thread, int32_t *, ref_count); +EP_DEFINE_GETTER_REF(EventPipeThread *, thread, volatile uint32_t *, writing_event_in_progress); + +EventPipeThread * +ep_thread_alloc (void); + +void +ep_thread_free (EventPipeThread *thread); + +void +ep_thread_addref (EventPipeThread *thread); + +void +ep_thread_release (EventPipeThread *thread); + +EventPipeThread * +ep_thread_get (void); + +EventPipeThread * +ep_thread_get_or_create (void); + +void +ep_thread_create_activity_id ( + uint8_t *activity_id, + uint32_t activity_id_len); + +void +ep_thread_get_activity_id ( + EventPipeThread *thread, + uint8_t *activity_id, + uint32_t activity_id_len); + +void +ep_thread_set_activity_id ( + EventPipeThread *thread, + const uint8_t *activity_id, + uint32_t activity_id_len); + +static +inline +void +ep_thread_set_as_rundown_thread ( + EventPipeThread *thread, + EventPipeSession *session) +{ + EP_ASSERT (thread != NULL); + ep_thread_set_rundown_session (thread, session); +} + +static +inline +bool +ep_thread_is_rundown_thread (const EventPipeThread *thread) +{ + EP_ASSERT (thread != NULL); + return (ep_thread_get_rundown_session (thread) != NULL); +} + +#ifdef EP_CHECKED_BUILD +void +ep_thread_requires_lock_held (const EventPipeThread *thread); + +void +ep_thread_requires_lock_not_held (const EventPipeThread *thread); +#else +#define ep_thread_requires_lock_held(x) +#define ep_thread_requires_lock_not_held(x) +#endif + +void +ep_thread_set_session_write_in_progress ( + EventPipeThread *thread, + uint32_t session_index); + +uint32_t +ep_thread_get_session_write_in_progress (const EventPipeThread *thread); + +EventPipeThreadSessionState * +ep_thread_get_or_create_session_state ( + EventPipeThread *thread, + EventPipeSession *session); + +EventPipeThreadSessionState * +ep_thread_get_session_state ( + const EventPipeThread *thread, + EventPipeSession *session); + +void +ep_thread_delete_session_state ( + EventPipeThread *thread, + EventPipeSession *session); + +/* + * EventPipeThreadHolder. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeThreadHolder { +#else +struct _EventPipeThreadHolder_Internal { +#endif + EventPipeThread *thread; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeThreadHolder { + uint8_t _internal [sizeof (struct _EventPipeThreadHolder_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventPipeThreadHolder *, thread_holder, EventPipeThread *, thread) + +EventPipeThreadHolder * +ep_thread_holder_alloc (EventPipeThread *thread); + +EventPipeThreadHolder * +ep_thread_holder_init ( + EventPipeThreadHolder *thread_holder, + EventPipeThread *thread); + +void +ep_thread_holder_fini (EventPipeThreadHolder *thread_holder); + +void +ep_thread_holder_free (EventPipeThreadHolder *thread_holder); + +/* + * EventPipeThreadSessionState. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeThreadSessionState { +#else +struct _EventPipeThreadSessionState_Internal { +#endif + EventPipeThreadHolder thread_holder; + EventPipeSession *session; + EventPipeBuffer *write_buffer; + EventPipeBufferList *buffer_list; +#ifdef EP_CHECKED_BUILD + EventPipeBufferManager *buffer_manager; +#endif + volatile uint32_t sequence_number; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeThreadSessionState { + uint8_t _internal [sizeof (struct _EventPipeThreadSessionState_Internal)]; +}; +#endif + +EP_DEFINE_GETTER_REF(EventPipeThreadSessionState *, thread_session_state, EventPipeThreadHolder *, thread_holder) +EP_DEFINE_GETTER(EventPipeThreadSessionState *, thread_session_state, EventPipeSession *, session) + +EventPipeThreadSessionState * +ep_thread_session_state_alloc ( + EventPipeThread *thread, + EventPipeSession *session, + EventPipeBufferManager *buffer_manager); + +void +ep_thread_session_state_free (EventPipeThreadSessionState *thread_session_state); + +EventPipeThread * +ep_thread_session_state_get_thread (const EventPipeThreadSessionState *thread_session_state); + +EventPipeBuffer * +ep_thread_session_state_get_write_buffer (const EventPipeThreadSessionState *thread_session_state); + +void +ep_thread_session_state_set_write_buffer ( + EventPipeThreadSessionState *thread_session_state, + EventPipeBuffer *new_buffer); + +EventPipeBufferList * +ep_thread_session_state_get_buffer_list (const EventPipeThreadSessionState *thread_session_state); + +void +ep_thread_session_state_set_buffer_list ( + EventPipeThreadSessionState *thread_session_state, + EventPipeBufferList *new_buffer_list); + +uint32_t +ep_thread_session_state_get_volatile_sequence_number (const EventPipeThreadSessionState *thread_session_state); + +uint32_t +ep_thread_session_state_get_sequence_number (const EventPipeThreadSessionState *thread_session_state); + +void +ep_thread_session_state_increment_sequence_number (EventPipeThreadSessionState *thread_session_state); + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_THREAD_H__ **/ diff --git a/src/mono/mono/eventpipe/ep-types.h b/src/mono/mono/eventpipe/ep-types.h new file mode 100644 index 00000000000000..7e25f32016c963 --- /dev/null +++ b/src/mono/mono/eventpipe/ep-types.h @@ -0,0 +1,388 @@ +#ifndef __EVENTPIPE_TYPES_H__ +#define __EVENTPIPE_TYPES_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include +#include +#include "ep-rt-types.h" + +/* + * EventPipe Structs. + */ + +typedef struct _EventData EventData; +typedef struct _EventFilterDescriptor EventFilterDescriptor; +typedef struct _EventPipeBuffer EventPipeBuffer; +typedef struct _EventPipeBufferList EventPipeBufferList; +typedef struct _EventPipeBufferManager EventPipeBufferManager; +typedef struct _EventPipeBlock EventPipeBlock; +typedef struct _EventPipeBlockVtable EventPipeBlockVtable; +typedef struct _EventPipeConfiguration EventPipeConfiguration; +typedef struct _EventPipeEvent EventPipeEvent; +typedef struct _EventPipeEventBlockBase EventPipeEventBlockBase; +typedef struct _EventPipeEventBlock EventPipeEventBlock; +typedef struct _EventPipeEventHeader EventPipeEventHeader; +typedef struct _EventPipeEventInstance EventPipeEventInstance; +typedef struct _EventPipeEventMetadataEvent EventPipeEventMetadataEvent; +typedef struct _EventPipeEventSource EventPipeEventSource; +typedef struct _EventPipeFile EventPipeFile; +typedef struct _EventPipeMetadataBlock EventPipeMetadataBlock; +typedef struct _EventPipeParameterDesc EventPipeParameterDesc; +typedef struct _EventPipeProvider EventPipeProvider; +typedef struct _EventPipeProviderCallbackData EventPipeProviderCallbackData; +typedef struct _EventPipeProviderCallbackDataQueue EventPipeProviderCallbackDataQueue; +typedef struct _EventPipeProviderConfiguration EventPipeProviderConfiguration; +typedef struct _EventPipeSession EventPipeSession; +typedef struct _EventPipeSessionProvider EventPipeSessionProvider; +typedef struct _EventPipeSessionProviderList EventPipeSessionProviderList; +typedef struct _EventPipeSequencePoint EventPipeSequencePoint; +typedef struct _EventPipeSequencePointBlock EventPipeSequencePointBlock; +typedef struct _EventPipeStackBlock EventPipeStackBlock; +typedef struct _EventPipeStackContents EventPipeStackContents; +typedef struct _EventPipeThread EventPipeThread; +typedef struct _EventPipeThreadHolder EventPipeThreadHolder; +typedef struct _EventPipeThreadSessionState EventPipeThreadSessionState; +typedef struct _FastSerializableObject FastSerializableObject; +typedef struct _FastSerializableObjectVtable FastSerializableObjectVtable; +typedef struct _FastSerializer FastSerializer; +typedef struct _FileStream FileStream; +typedef struct _FileStreamWriter FileStreamWriter; +typedef struct _IpcStream IpcStream; +typedef struct _IpcStreamWriter IpcStreamWriter; +typedef struct _StackHashEntry StackHashEntry; +typedef struct _StackHashKey StackHashKey; +typedef struct _StreamWriter StreamWriter; +typedef struct _StreamWriterVtable StreamWriterVtable; + +#ifdef EP_INLINE_GETTER_SETTER +#ifndef EP_DEFINE_GETTER +#define EP_DEFINE_GETTER(instance_type, instance_type_name, return_type, instance_field_name) \ + static inline return_type ep_ ## instance_type_name ## _get_ ## instance_field_name (const instance_type instance) { return instance-> instance_field_name; } \ + static inline size_t ep_ ## instance_type_name ## _sizeof_ ## instance_field_name (const instance_type instance) { return sizeof (instance-> instance_field_name); } +#endif + +#ifndef EP_DEFINE_GETTER_REF +#define EP_DEFINE_GETTER_REF(instance_type, instance_type_name, return_type, instance_field_name) \ + static inline return_type ep_ ## instance_type_name ## _get_ ## instance_field_name ## _ref (instance_type instance) { return &(instance-> instance_field_name); } \ + static inline const return_type ep_ ## instance_type_name ## _get_ ## instance_field_name ## _cref (const instance_type instance) { return &(instance-> instance_field_name); } +#endif + +#ifndef EP_DEFINE_GETTER_ARRAY_REF +#define EP_DEFINE_GETTER_ARRAY_REF(instance_type, instance_type_name, return_type, const_return_type, instance_field_name, instance_field) \ + static inline return_type ep_ ## instance_type_name ## _get_ ## instance_field_name ## _ref (instance_type instance) { return &(instance-> instance_field); } \ + static inline const_return_type ep_ ## instance_type_name ## _get_ ## instance_field_name ## _cref (const instance_type instance) { return &(instance-> instance_field); } +#endif + +#ifndef EP_DEFINE_SETTER +#define EP_DEFINE_SETTER(instance_type, instance_type_name, instance_field_type, instance_field_name) static inline void ep_ ## instance_type_name ## _set_ ## instance_field_name (instance_type instance, instance_field_type instance_field_name) { instance-> instance_field_name = instance_field_name; } +#endif +#else +#ifndef EP_DEFINE_GETTER +#define EP_DEFINE_GETTER(instance_type, instance_type_name, return_type, instance_field_name) \ + return_type ep_ ## instance_type_name ## _get_ ## instance_field_name (const instance_type instance); \ + size_t ep_ ## instance_type_name ## _sizeof_ ## instance_field_name (const instance_type instance); +#endif + +#ifndef EP_DEFINE_GETTER_REF +#define EP_DEFINE_GETTER_REF(instance_type, instance_type_name, return_type, instance_field_name) \ + return_type ep_ ## instance_type_name ## _get_ ## instance_field_name ## _ref (instance_type instance); \ + const return_type ep_ ## instance_type_name ## _get_ ## instance_field_name ## _cref (const instance_type instance); +#endif + +#ifndef EP_DEFINE_GETTER_ARRAY_REF +#define EP_DEFINE_GETTER_ARRAY_REF(instance_type, instance_type_name, return_type, const_return_type, instance_field_name, instance_field) \ + return_type ep_ ## instance_type_name ## _get_ ## instance_field_name ## _ref (instance_type instance); \ + const_return_type ep_ ## instance_type_name ## _get_ ## instance_field_name ## _cref (const instance_type instance); +#endif + +#ifndef EP_DEFINE_SETTER +#define EP_DEFINE_SETTER(instance_type, instance_type_name, instance_field_type, instance_field_name) \ + void ep_ ## instance_type_name ## _set_ ## instance_field_name (instance_type instance, instance_field_type instance_field_name); +#endif +#endif + +#define EP_MAX_NUMBER_OF_SESSIONS 64 + +#define EP_ACTIVITY_ID_SIZE 16 + +#define EP_MAX_STACK_DEPTH 100 + +/* + * EventPipe Enums. + */ + +typedef enum { + EP_BUFFER_STATE_WRITABLE = 0, + EP_BUFFER_STATE_READ_ONLY = 1 +} EventPipeBufferState; + +typedef enum { + EP_EVENT_LEVEL_LOG_ALWAYS, + EP_EVENT_LEVEL_CRITICAL, + EP_EVENT_LEVEL_ERROR, + EP_EVENT_LEVEL_WARNING, + EP_EVENT_LEVEL_INFORMATIONAL, + EP_EVENT_LEVEL_VERBOSE +} EventPipeEventLevel; + +typedef enum { + EP_FILE_FLUSH_FLAGS_EVENT_BLOCK = 1, + EP_FILE_FLUSH_FLAGS_METADATA_BLOCK = 2, + EP_FILE_FLUSH_FLAGS_STACK_BLOCK = 4, + EP_FILE_FLUSH_FLAGS_ALL_BLOCKS = EP_FILE_FLUSH_FLAGS_EVENT_BLOCK | EP_FILE_FLUSH_FLAGS_METADATA_BLOCK | EP_FILE_FLUSH_FLAGS_STACK_BLOCK +} EventPipeFileFlushFlags; + +// Represents the type of an event parameter. +// This enum is derived from the managed TypeCode type, though +// not all of these values are available in TypeCode. +// For example, Guid does not exist in TypeCode. +// Keep this in sync with COR_PRF_EVENTPIPE_PARAM_TYPE defined in +// corprof.idl +typedef enum { + EP_PARAMETER_TYPE_EMPTY = 0, // Null reference + EP_PARAMETER_TYPE_OBJECT = 1, // Instance that isn't a value + EP_PARAMETER_TYPE_DB_NULL = 2, // Database null value + EP_PARAMETER_TYPE_BOOLEAN = 3, // Boolean + EP_PARAMETER_TYPE_CHAR = 4, // Unicode character + EP_PARAMETER_TYPE_SBYTE = 5, // Signed 8-bit integer + EP_PARAMETER_TYPE_BYTE = 6, // Unsigned 8-bit integer + EP_PARAMETER_TYPE_INT16 = 7, // Signed 16-bit integer + EP_PARAMETER_TYPE_UINT16 = 8, // Unsigned 16-bit integer + EP_PARAMETER_TYPE_INT32 = 9, // Signed 32-bit integer + EP_PARAMETER_TYPE_UINT32 = 10, // Unsigned 32-bit integer + EP_PARAMETER_TYPE_INT64 = 11, // Signed 64-bit integer + EP_PARAMETER_TYPE_UINT64 = 12, // Unsigned 64-bit integer + EP_PARAMETER_TYPE_SINGLE = 13, // IEEE 32-bit float + EP_PARAMETER_TYPE_DOUBLE = 14, // IEEE 64-bit double + EP_PARAMETER_TYPE_DECIMAL = 15, // Decimal + EP_PARAMETER_TYPE_DATE_TIME = 16, // DateTime + EP_PARAMETER_TYPE_GUID = 17, // Guid + EP_PARAMETER_TYPE_STRING = 18 // Unicode character string +} EventPipeParameterType; + +typedef enum { + EP_SERIALIZATION_FORMAT_NETPERF_V3, + EP_SERIALIZATION_FORMAT_NETTRACE_V4, + EP_SERIALIZATION_FORMAT_COUNT +} EventPipeSerializationFormat; + +typedef enum { + EP_SESSION_TYPE_FILE, + EP_SESSION_TYPE_LISTENER, + EP_SESSION_TYPE_IPCSTREAM +} EventPipeSessionType ; + +typedef enum { + EP_STATE_NOT_INITIALIZED, + EP_STATE_INITIALIZED, + EP_STATE_SHUTTING_DOWN +} EventPipeState; + +/* + * EventPipe Basic Types. + */ + +typedef intptr_t EventPipeWaitHandle; +typedef uint64_t EventPipeSessionID; +typedef char ep_char8_t; +typedef unsigned short ep_char16_t; + +/* + * EventPipe Callbacks. + */ + +// Define the event pipe callback to match the ETW callback signature. +typedef void (*EventPipeCallback)( + const uint8_t *source_id, + unsigned long is_enabled, + uint8_t level, + uint64_t match_any_keywords, + uint64_t match_all_keywords, + EventFilterDescriptor *filter_data, + void *callback_context); + +/* + * EventFilterDescriptor. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventFilterDescriptor { +#else +struct _EventFilterDescriptor_Internal { +#endif + uint64_t ptr; + uint32_t size; + uint32_t type; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventFilterDescriptor { + uint8_t _internal [sizeof (struct _EventFilterDescriptor_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventFilterDescriptor *, event_filter_desc, uint64_t, ptr) +EP_DEFINE_GETTER(EventFilterDescriptor *, event_filter_desc, uint32_t, size) +EP_DEFINE_GETTER(EventFilterDescriptor *, event_filter_desc, uint32_t, type) + +EventFilterDescriptor * +ep_event_filter_desc_alloc ( + uint64_t ptr, + uint32_t size, + uint32_t type); + +EventFilterDescriptor * +ep_event_filter_desc_init ( + EventFilterDescriptor *event_filter_desc, + uint64_t ptr, + uint32_t size, + uint32_t type +); + +void +ep_event_filter_desc_fini (EventFilterDescriptor * filter_desc); + +void +ep_event_filter_desc_free (EventFilterDescriptor * filter_desc); + +/* + * EventPipeProviderCallbackData. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeProviderCallbackData { +#else +struct _EventPipeProviderCallbackData_Internal { +#endif + const ep_char8_t *filter_data; + EventPipeCallback callback_function; + void *callback_data; + int64_t keywords; + EventPipeEventLevel provider_level; + bool enabled; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeProviderCallbackData { + uint8_t _internal [sizeof (struct _EventPipeProviderCallbackData_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventPipeProviderCallbackData *, provider_callback_data, const ep_char8_t *, filter_data) +EP_DEFINE_GETTER(EventPipeProviderCallbackData *, provider_callback_data, EventPipeCallback, callback_function) +EP_DEFINE_GETTER(EventPipeProviderCallbackData *, provider_callback_data, void *, callback_data) +EP_DEFINE_GETTER(EventPipeProviderCallbackData *, provider_callback_data, int64_t, keywords) +EP_DEFINE_GETTER(EventPipeProviderCallbackData *, provider_callback_data, EventPipeEventLevel, provider_level) +EP_DEFINE_GETTER(EventPipeProviderCallbackData *, provider_callback_data, bool, enabled) + +EventPipeProviderCallbackData * +ep_provider_callback_data_alloc ( + const ep_char8_t *filter_data, + EventPipeCallback callback_function, + void *callback_data, + int64_t keywords, + EventPipeEventLevel provider_level, + bool enabled); + +EventPipeProviderCallbackData * +ep_provider_callback_data_alloc_copy (EventPipeProviderCallbackData *provider_callback_data_src); + +EventPipeProviderCallbackData * +ep_provider_callback_data_init ( + EventPipeProviderCallbackData *provider_callback_data, + const ep_char8_t *filter_data, + EventPipeCallback callback_function, + void *callback_data, + int64_t keywords, + EventPipeEventLevel provider_level, + bool enabled); + +EventPipeProviderCallbackData * +ep_provider_callback_data_init_copy ( + EventPipeProviderCallbackData *provider_callback_data_dst, + EventPipeProviderCallbackData *provider_callback_data_src); + +void +ep_provider_callback_data_fini (EventPipeProviderCallbackData *provider_callback_data); + +void +ep_provider_callback_data_free (EventPipeProviderCallbackData *provider_callback_data); + +/* + * EventPipeProviderCallbackDataQueue. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeProviderCallbackDataQueue { +#else +struct _EventPipeProviderCallbackDataQueue_Internal { +#endif + ep_rt_provider_callback_data_queue_t queue; +}; + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeProviderCallbackDataQueue { + uint8_t _internal [sizeof (struct _EventPipeProviderCallbackDataQueue_Internal)]; +}; +#endif + +EP_DEFINE_GETTER_REF(EventPipeProviderCallbackDataQueue *, provider_callback_data_queue, ep_rt_provider_callback_data_queue_t *, queue) + +EventPipeProviderCallbackDataQueue * +ep_provider_callback_data_queue_init (EventPipeProviderCallbackDataQueue *provider_callback_data_queue); + +void +ep_provider_callback_data_queue_fini (EventPipeProviderCallbackDataQueue *provider_callback_data_queue); + +void +ep_provider_callback_data_queue_enqueue ( + EventPipeProviderCallbackDataQueue *provider_callback_data_queue, + EventPipeProviderCallbackData *provider_callback_data); + +bool +ep_provider_callback_data_queue_try_dequeue ( + EventPipeProviderCallbackDataQueue *provider_callback_data_queue, + EventPipeProviderCallbackData *provider_callback_data); + +/* + * EventPipeProviderConfiguration. + */ + +#if defined(EP_INLINE_GETTER_SETTER) || defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeProviderConfiguration { +#else +struct _EventPipeProviderConfiguration_Internal { +#endif + const ep_char8_t *provider_name; + uint64_t keywords; + EventPipeEventLevel logging_level; + const ep_char8_t *filter_data; +}; + + +#if !defined(EP_INLINE_GETTER_SETTER) && !defined(EP_IMPL_GETTER_SETTER) +struct _EventPipeProviderConfiguration { + uint8_t _internal [sizeof (struct _EventPipeProviderConfiguration_Internal)]; +}; +#endif + +EP_DEFINE_GETTER(EventPipeProviderConfiguration *, provider_config, const ep_char8_t *, provider_name) +EP_DEFINE_GETTER(EventPipeProviderConfiguration *, provider_config, uint64_t, keywords) +EP_DEFINE_GETTER(EventPipeProviderConfiguration *, provider_config, EventPipeEventLevel, logging_level) +EP_DEFINE_GETTER(EventPipeProviderConfiguration *, provider_config, const ep_char8_t *, filter_data) + +EventPipeProviderConfiguration * +ep_provider_config_init ( + EventPipeProviderConfiguration *provider_config, + const ep_char8_t *provider_name, + uint64_t keywords, + uint32_t logging_level, + const ep_char8_t *filter_data); + +void +ep_provider_config_fini (EventPipeProviderConfiguration *provider_config); + +#endif /* ENABLE_PERFTRACING */ +#endif /* __EVENTPIPE_TYPES_H__ */ diff --git a/src/mono/mono/eventpipe/ep.c b/src/mono/mono/eventpipe/ep.c new file mode 100644 index 00000000000000..3725a8281eb8f6 --- /dev/null +++ b/src/mono/mono/eventpipe/ep.c @@ -0,0 +1,711 @@ +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep.h" + +// Option to include all internal source files into ep.c. +#ifdef EP_INCLUDE_SOURCE_FILES +#define EP_FORCE_INCLUDE_SOURCE_FILES +#include "ep-block.c" +#include "ep-buffer-manager.c" +#include "ep-config.c" +#include "ep-event-instance.c" +#include "ep-event-source.c" +#include "ep-file.c" +#include "ep-metadata-generator.c" +#include "ep-provider.c" +#include "ep-session.c" +#include "ep-session-provider.c" +#include "ep-stream.c" +#include "ep-thread.c" +#endif + +/* + * Forward declares of all static functions. + */ + +static +bool +enabled_lock_held (void); + +static +uint32_t +generate_session_index_lock_held (void); + +static +bool +is_session_id_in_collection_lock_held (EventPipeSessionID id); + +static +EventPipeSessionID +enable_lock_held ( + const ep_char8_t *output_path, + uint32_t circular_buffer_size_in_mb, + const EventPipeProviderConfiguration *providers, + uint32_t providers_len, + EventPipeSessionType session_type, + EventPipeSerializationFormat format, + bool rundown_requested, + IpcStream *stream, + bool enable_sample_profiler, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue); + +static +void +log_process_info_event (EventPipeEventSource *event_source); + +static +void +disable_lock_held ( + EventPipeSessionID id, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue); + +static +void +disable ( + EventPipeSessionID id, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue); + +/* + * Global volatile varaibles, only to be accessed through inlined volatile access functions. + */ + +volatile EventPipeState _ep_state = EP_STATE_NOT_INITIALIZED; + +volatile uint32_t _ep_number_of_sessions = 0; + +volatile EventPipeSession *_ep_sessions [EP_MAX_NUMBER_OF_SESSIONS] = { 0 }; + +volatile uint64_t _ep_allow_write = 0; + +/* + * EventPipe. + */ + +static +bool +enabled_lock_held (void) +{ + ep_rt_config_requires_lock_held (); + return (ep_volatile_load_eventpipe_state_without_barrier () >= EP_STATE_INITIALIZED && + ep_volatile_load_number_of_sessions_without_barrier () > 0); +} + +static +uint32_t +generate_session_index_lock_held (void) +{ + ep_rt_config_requires_lock_held (); + + for (uint32_t i = 0; i < EP_MAX_NUMBER_OF_SESSIONS; ++i) + if (ep_volatile_load_session_without_barrier (i) == NULL) + return i; + return EP_MAX_NUMBER_OF_SESSIONS; +} + +static +bool +is_session_id_in_collection_lock_held (EventPipeSessionID session_id) +{ + ep_rt_config_requires_lock_held (); + EP_ASSERT (session_id != 0); + + const EventPipeSession *const session = (EventPipeSession *)session_id; + for (uint32_t i = 0; i < EP_MAX_NUMBER_OF_SESSIONS; ++i) { + if (ep_volatile_load_session (i) == session) { + EP_ASSERT (i == ep_session_get_index (session)); + return true; + } + } + + return false; +} + +static +EventPipeSessionID +enable_lock_held ( + const ep_char8_t *output_path, + uint32_t circular_buffer_size_in_mb, + const EventPipeProviderConfiguration *providers, + uint32_t providers_len, + EventPipeSessionType session_type, + EventPipeSerializationFormat format, + bool rundown_requested, + IpcStream *stream, + bool enable_sample_profiler, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue) +{ + ep_rt_config_requires_lock_held (); + EP_ASSERT (format < EP_SERIALIZATION_FORMAT_COUNT); + EP_ASSERT (circular_buffer_size_in_mb > 0); + EP_ASSERT (providers_len > 0 && providers != NULL); + EP_ASSERT ((session_type == EP_SESSION_TYPE_FILE && output_path != NULL) ||(session_type == EP_SESSION_TYPE_IPCSTREAM && stream != NULL)); + + EventPipeSession *session = NULL; + EventPipeSessionID session_id = 0; + + ep_raise_error_if_nok (ep_volatile_load_eventpipe_state () == EP_STATE_INITIALIZED); + + const uint32_t session_index = generate_session_index_lock_held (); + ep_raise_error_if_nok (session_index < EP_MAX_NUMBER_OF_SESSIONS); + + session = ep_session_alloc ( + session_index, + output_path, + stream, + session_type, + format, + rundown_requested, + circular_buffer_size_in_mb, + providers, + providers_len, + FALSE); + + ep_raise_error_if_nok (session != NULL && ep_session_is_valid (session) == true); + + session_id = (EventPipeSessionID)session; + + // Return if the index is invalid. + if (ep_session_get_index (session) >= EP_MAX_NUMBER_OF_SESSIONS) { + EP_ASSERT (!"Session index was out of range."); + ep_raise_error (); + } + + if (ep_volatile_load_number_of_sessions () >= EP_MAX_NUMBER_OF_SESSIONS) { + EP_ASSERT (!"max number of sessions reached."); + ep_raise_error (); + } + + // Register the SampleProfiler the very first time (if supported). + ep_rt_sample_profiler_init (provider_callback_data_queue); + + // Enable the EventPipe EventSource. + ep_event_source_enable (ep_event_source_get (), session); + + // Save the session. + if (ep_volatile_load_session_without_barrier (ep_session_get_index (session)) != NULL) { + EP_ASSERT (!"Attempting to override an existing session."); + ep_raise_error (); + } + + ep_volatile_store_session (ep_session_get_index (session), session); + + ep_volatile_store_allow_write (ep_volatile_load_allow_write () | ep_session_get_mask (session)); + ep_volatile_store_number_of_sessions (ep_volatile_load_number_of_sessions () + 1); + + // Enable tracing. + ep_config_enable_disable_lock_held (ep_config_get (), session, provider_callback_data_queue, true); + + session = NULL; + + // Enable the sample profiler (if supported). + if (enable_sample_profiler) + ep_rt_sample_profiler_enable (); + +ep_on_exit: + ep_rt_config_requires_lock_held (); + return session_id; + +ep_on_error: + ep_session_free (session); + + session_id = 0; + ep_exit_error_handler (); +} + +static +void +log_process_info_event (EventPipeEventSource *event_source) +{ + // Get the managed command line. + const ep_char8_t *cmd_line = ep_rt_managed_command_line_get (); + + if (cmd_line == NULL) + cmd_line = ep_rt_command_line_get (); + + // Log the process information event. + ep_char16_t *cmd_line_utf16 = ep_rt_utf8_to_utf16_string (cmd_line, -1); + if (cmd_line_utf16 != NULL) { + ep_event_source_send_process_info (event_source, cmd_line_utf16); + ep_rt_utf16_string_free (cmd_line_utf16); + } +} + +static +void +disable_lock_held ( + EventPipeSessionID id, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue) +{ + ep_rt_config_requires_lock_held (); + EP_ASSERT (id != 0); + EP_ASSERT (ep_volatile_load_number_of_sessions () > 0); + + if (is_session_id_in_collection_lock_held (id)) { + EventPipeSession *const session = (EventPipeSession *)id; + + // Disable the profiler. + ep_rt_sample_profiler_disable (); + + // Log the process information event. + log_process_info_event (ep_event_source_get ()); + + // Disable session tracing. + ep_config_enable_disable_lock_held (ep_config_get (), session, provider_callback_data_queue, false); + + ep_session_disable (session); // WriteAllBuffersToFile, and remove providers. + + // Do rundown before fully stopping the session unless rundown wasn't requested + if (ep_session_get_rundown_requested (session)) { + ep_session_enable_rundown_lock_held (session); // Set Rundown provider. + EventPipeThread *const thread = ep_thread_get (); + if (thread != NULL) { + ep_thread_set_as_rundown_thread (thread, session); + { + ep_config_enable_disable_lock_held (ep_config_get (), session, provider_callback_data_queue, true); + { + ep_session_execute_rundown_lock_held (session); + } + ep_config_enable_disable_lock_held (ep_config_get (), session, provider_callback_data_queue, false); + } + ep_thread_set_as_rundown_thread (thread, NULL); + } else { + EP_ASSERT (!"Failed to get or create the EventPipeThread for rundown events."); + } + } + + ep_volatile_store_allow_write (ep_volatile_load_allow_write () & ~(ep_session_get_mask (session))); + ep_session_suspend_write_event_lock_held (session); + + bool ignored; + ep_session_write_all_buffers_to_file (session, &ignored); // Flush the buffers to the stream/file + + ep_volatile_store_number_of_sessions (ep_volatile_load_number_of_sessions () - 1); + + // At this point, we should not be writing events to this session anymore + // This is a good time to remove the session from the array. + EP_ASSERT (ep_volatile_load_session (ep_session_get_index (session)) == session); + + // Remove the session from the array, and mask. + ep_volatile_store_session (ep_session_get_index (session), NULL); + + // Write a final sequence point to the file now that all events have + // been emitted. + ep_session_write_sequence_point_unbuffered_lock_held (session); + + ep_session_free (session); + + // Providers can't be deleted during tracing because they may be needed when serializing the file. + ep_config_delete_deferred_providers_lock_held (ep_config_get ()); + } + + ep_rt_config_requires_lock_held (); + return; +} + +static +void +disable ( + EventPipeSessionID id, + EventPipeProviderCallbackDataQueue *provider_callback_data_queue) +{ + ep_rt_config_requires_lock_not_held (); + + EP_CONFIG_LOCK_ENTER + disable_lock_held (id, provider_callback_data_queue); + EP_CONFIG_LOCK_EXIT + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return; + +ep_on_error: + ep_exit_error_handler (); +} + +EventPipeSessionID +ep_enable ( + const ep_char8_t *output_path, + uint32_t circular_buffer_size_in_mb, + const EventPipeProviderConfiguration *providers, + uint32_t providers_len, + EventPipeSessionType session_type, + EventPipeSerializationFormat format, + bool rundown_requested, + IpcStream *stream, + bool enable_sample_profiler) +{ + ep_rt_config_requires_lock_not_held (); + EP_ASSERT (format < EP_SERIALIZATION_FORMAT_COUNT); + EP_ASSERT (circular_buffer_size_in_mb > 0); + EP_ASSERT (providers_len > 0 && providers != NULL); + + // If the state or arguments are invalid, bail here. + if (session_type == EP_SESSION_TYPE_FILE && output_path == NULL) + return 0; + if (session_type == EP_SESSION_TYPE_IPCSTREAM && stream == NULL) + return 0; + + EventPipeSessionID session_id = 0; + EventPipeProviderCallbackDataQueue callback_data_queue; + EventPipeProviderCallbackData provider_callback_data; + EventPipeProviderCallbackDataQueue *provider_callback_data_queue = ep_provider_callback_data_queue_init (&callback_data_queue); + + EP_CONFIG_LOCK_ENTER + session_id = enable_lock_held ( + output_path, + circular_buffer_size_in_mb, + providers, + providers_len, + session_type, + format, + rundown_requested, + stream, + enable_sample_profiler, + provider_callback_data_queue); + EP_CONFIG_LOCK_EXIT + + while (ep_provider_callback_data_queue_try_dequeue (provider_callback_data_queue, &provider_callback_data)) + ep_provider_invoke_callback (&provider_callback_data); + +ep_on_exit: + ep_provider_callback_data_queue_fini (provider_callback_data_queue); + ep_rt_config_requires_lock_not_held (); + return session_id; + +ep_on_error: + session_id = 0; + ep_exit_error_handler (); +} + +void +ep_disable (EventPipeSessionID id) +{ + ep_rt_config_requires_lock_not_held (); + + //TODO: Why is this needed? Just to make sure thread is attached to runtime for + //EP_GCX_PREEMP_ENTER/EP_GCX_PREEMP_EXIT to work? + ep_rt_thread_setup (); + + if (id == 0) + return; + + // Don't block GC during clean-up. + EP_GCX_PREEMP_ENTER + + EventPipeProviderCallbackDataQueue callback_data_queue; + EventPipeProviderCallbackData provider_callback_data; + EventPipeProviderCallbackDataQueue *provider_callback_data_queue = ep_provider_callback_data_queue_init (&callback_data_queue); + + disable (id, provider_callback_data_queue); + + while (ep_provider_callback_data_queue_try_dequeue (provider_callback_data_queue, &provider_callback_data)) + ep_provider_invoke_callback (&provider_callback_data); + + ep_provider_callback_data_queue_fini (provider_callback_data_queue); + + EP_GCX_PREEMP_EXIT + + ep_rt_config_requires_lock_not_held (); + return; +} + +EventPipeSession * +ep_get_session (EventPipeSessionID session_id) +{ + ep_rt_config_requires_lock_not_held (); + + EP_CONFIG_LOCK_ENTER + + if (ep_volatile_load_eventpipe_state () == EP_STATE_NOT_INITIALIZED) { + EP_ASSERT (!"EventPipe::GetSession invoked before EventPipe was initialized."); + ep_raise_error_holding_lock (); + } + + ep_raise_error_if_nok_holding_lock (is_session_id_in_collection_lock_held (session_id) == true); + + EP_CONFIG_LOCK_EXIT + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return (EventPipeSession *)session_id; + +ep_on_error: + session_id = 0; + ep_exit_error_handler (); +} + +bool +ep_enabled (void) +{ + //TODO: Validate if ever called without holding lock, if so should check be atomic? + return (ep_volatile_load_eventpipe_state () >= EP_STATE_INITIALIZED && + ep_volatile_load_number_of_sessions () > 0); +} + +EventPipeProvider * +ep_create_provider ( + const ep_char8_t *provider_name, + EventPipeCallback callback_func, + void *callback_data) +{ + ep_rt_config_requires_lock_not_held (); + + ep_return_null_if_nok (provider_name != NULL); + + EventPipeProvider *provider = NULL; + EventPipeProviderCallbackDataQueue data_queue; + EventPipeProviderCallbackData provider_callback_data; + EventPipeProviderCallbackDataQueue *provider_callback_data_queue = ep_provider_callback_data_queue_init (&data_queue); + + EP_CONFIG_LOCK_ENTER + provider = ep_config_create_provider_lock_held (ep_config_get (), provider_name, callback_func, callback_data, provider_callback_data_queue); + ep_raise_error_if_nok_holding_lock (provider != NULL); + EP_CONFIG_LOCK_EXIT + + while (ep_provider_callback_data_queue_try_dequeue (provider_callback_data_queue, &provider_callback_data)) + ep_provider_invoke_callback (&provider_callback_data); + +ep_on_exit: + ep_provider_callback_data_queue_fini (provider_callback_data_queue); + ep_rt_config_requires_lock_not_held (); + return provider; + +ep_on_error: + ep_delete_provider (provider); + + provider = NULL; + ep_exit_error_handler (); +} + +void +ep_delete_provider (EventPipeProvider *provider) +{ + ep_rt_config_requires_lock_not_held (); + + ep_return_void_if_nok (provider != NULL); + + // Take the lock to make sure that we don't have a race + // between disabling tracing and deleting a provider + // where we hold a provider after tracing has been disabled. + EP_CONFIG_LOCK_ENTER + if (enabled_lock_held ()) { + // Save the provider until the end of the tracing session. + ep_provider_set_delete_deferred (provider, true); + } else { + ep_config_delete_provider_lock_held (ep_config_get (), provider); + } + EP_CONFIG_LOCK_EXIT + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return; + +ep_on_error: + ep_exit_error_handler (); +} + +EventPipeProvider * +ep_get_provider (const ep_char8_t *provider_name) +{ + ep_rt_config_requires_lock_not_held (); + + ep_return_null_if_nok (provider_name != NULL); + + EventPipeProvider *provider = NULL; + + EP_CONFIG_LOCK_ENTER + provider = ep_config_get_provider_lock_held (ep_config_get (), provider_name); + ep_raise_error_if_nok_holding_lock (provider != NULL); + EP_CONFIG_LOCK_EXIT + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return provider; + +ep_on_error: + provider = NULL; + ep_exit_error_handler (); +} + +void +ep_init (void) +{ + ep_rt_init (); + ep_rt_config_requires_lock_not_held (); + + //TODO: Implement. Locking pattern between init/shutdown is racy but same as CoreCLR. Needs to be revisited. + if (ep_volatile_load_eventpipe_state () != EP_STATE_NOT_INITIALIZED) { + EP_ASSERT (!"EventPipe already initialized."); + return; + } + + for (uint32_t i = 0; i < EP_MAX_NUMBER_OF_SESSIONS; ++i) + ep_volatile_store_session (i, NULL); + + if (ep_config_init (ep_config_get ())) { + EP_CONFIG_LOCK_ENTER + ep_volatile_store_eventpipe_state_without_barrier (EP_STATE_INITIALIZED); + EP_CONFIG_LOCK_EXIT + } + + //TODO: Implement. + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return; + +ep_on_error: + ep_exit_error_handler (); +} + +void +ep_finish_init (void) +{ + //TODO: Implement. +} + +void +ep_shutdown (void) +{ + ep_rt_config_requires_lock_not_held (); + + //TODO: Locking pattern between init/shutdown is racy but same as CoreCLR. Needs to be revisited. + ep_return_void_if_nok (ep_volatile_load_eventpipe_state () != EP_STATE_SHUTTING_DOWN); + ep_return_void_if_nok (!ep_rt_process_detach ()); + ep_return_void_if_nok (ep_volatile_load_eventpipe_state () == EP_STATE_INITIALIZED); + + EP_CONFIG_LOCK_ENTER + ep_volatile_store_eventpipe_state_without_barrier (EP_STATE_SHUTTING_DOWN); + EP_CONFIG_LOCK_EXIT + + for (uint32_t i = 0; i < EP_MAX_NUMBER_OF_SESSIONS; ++i) { + EventPipeSession *session = ep_volatile_load_session (i); + if (session) + ep_disable ((EventPipeSessionID)session); + } + + // dotnet/coreclr: issue 24850: EventPipe shutdown race conditions + // Deallocating providers/events here might cause AV if a WriteEvent + // was to occur. Thus, we are not doing this cleanup. + + // // Remove EventPipeEventSource first since it tries to use the data structures that we remove below. + // // We need to do this after disabling sessions since those try to write to EventPipeEventSource. + // delete s_pEventSource; + // s_pEventSource = nullptr; + // s_config.Shutdown(); + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + ep_rt_shutdown (); + return; + +ep_on_error: + ep_exit_error_handler (); +} + +EventPipeEventMetadataEvent * +ep_build_event_metadata_event ( + EventPipeEventInstance *event_instance, + uint32_t metadata_id) +{ + return ep_config_build_event_metadata_event (ep_config_get (), event_instance, metadata_id); +} + +void +ep_write_event ( + EventPipeEvent *ep_event, + EventData *event_data, + uint32_t event_data_len, + const uint8_t *activity_id, + const uint8_t *related_activity_id) +{ + //TODO: Implement. +} + +EventPipeEventInstance * +ep_get_next_event (EventPipeSessionID session_id) +{ + ep_rt_config_requires_lock_not_held (); + + // Only fetch the next event if a tracing session exists. + // The buffer manager is not disposed until the process is shutdown. + EventPipeSession *const session = ep_get_session (session_id); + return session ? ep_session_get_next_event (session) : NULL; +} + +EventPipeWaitHandle +ep_get_wait_handle (EventPipeSessionID session_id) +{ + EventPipeSession *const session = ep_get_session (session_id); + return session ? ep_session_get_wait_event (session) : 0; +} + +void +ep_start_streaming (EventPipeSessionID session_id) +{ + ep_rt_config_requires_lock_not_held (); + + EP_CONFIG_LOCK_ENTER + ep_raise_error_if_nok_holding_lock (is_session_id_in_collection_lock_held (session_id) == true); + EventPipeSession *const session = (EventPipeSession *)session_id; + ep_session_start_streaming_lock_held (session); + EP_CONFIG_LOCK_EXIT + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return; + +ep_on_error: + ep_exit_error_handler (); +} + +/* + * EventPipePerf. + */ + +uint64_t +ep_perf_counter_query (void) +{ + return ep_rt_perf_counter_query (); +} + +uint64_t +ep_perf_frequency_query (void) +{ + return ep_rt_perf_frequency_query (); +} + +/* + * EventPipeProviderCallbackDataQueue. + */ + +void +ep_provider_callback_data_queue_enqueue ( + EventPipeProviderCallbackDataQueue *provider_callback_data_queue, + EventPipeProviderCallbackData *provider_callback_data) +{ + ep_return_void_if_nok (provider_callback_data_queue != NULL); + ep_rt_provider_callback_data_queue_push_tail (ep_provider_callback_data_queue_get_queue_ref (provider_callback_data_queue), ep_provider_callback_data_alloc_copy (provider_callback_data)); +} + +bool +ep_provider_callback_data_queue_try_dequeue ( + EventPipeProviderCallbackDataQueue *provider_callback_data_queue, + EventPipeProviderCallbackData *provider_callback_data) +{ + ep_return_false_if_nok (provider_callback_data_queue != NULL && ep_rt_provider_callback_data_queue_is_empty (ep_provider_callback_data_queue_get_queue_ref (provider_callback_data_queue)) != true); + + EventPipeProviderCallbackData *value = NULL; + ep_rt_provider_callback_data_queue_pop_head (ep_provider_callback_data_queue_get_queue_ref (provider_callback_data_queue), &value); + ep_provider_callback_data_init_copy (provider_callback_data, value); + ep_provider_callback_data_free (value); + + return true; +} + +#endif /* ENABLE_PERFTRACING */ + +extern const char quiet_linker_empty_file_warning_eventpipe; +const char quiet_linker_empty_file_warning_eventpipe = 0; diff --git a/src/mono/mono/eventpipe/ep.h b/src/mono/mono/eventpipe/ep.h new file mode 100644 index 00000000000000..ca11989aa415b5 --- /dev/null +++ b/src/mono/mono/eventpipe/ep.h @@ -0,0 +1,272 @@ +#ifndef __EVENTPIPE_H__ +#define __EVENTPIPE_H__ + +#include + +#ifdef ENABLE_PERFTRACING +#include "ep-rt-config.h" +#include "ep-types.h" +#include "ep-stream.h" +#include "ep-thread.h" +#include "ep-block.h" +#include "ep-event-payload.h" +#include "ep-buffer.h" +#include "ep-buffer-manager.h" +#include "ep-stack-contents.h" +#include "ep-event.h" +#include "ep-event-instance.h" +#include "ep-config.h" +#include "ep-event-source.h" +#include "ep-file.h" +#include "ep-metadata-generator.h" +#include "ep-provider.h" +#include "ep-session.h" +#include "ep-session-provider.h" +#include "ep-rt.h" + +/* + * Globals and volatile access functions. + */ + +static +inline +EventPipeState +ep_volatile_load_eventpipe_state (void) +{ + extern volatile EventPipeState _ep_state; + return (EventPipeState)ep_rt_volatile_load_uint32_t ((const volatile uint32_t *)&_ep_state); +} + +static +inline +EventPipeState +ep_volatile_load_eventpipe_state_without_barrier (void) +{ + extern volatile EventPipeState _ep_state; + return (EventPipeState)ep_rt_volatile_load_uint32_t_without_barrier ((const volatile uint32_t *)&_ep_state); +} + +static +inline +void +ep_volatile_store_eventpipe_state (EventPipeState state) +{ + extern volatile EventPipeState _ep_state; + ep_rt_volatile_store_uint32_t ((volatile uint32_t *)&_ep_state, state); +} + +static +inline +void +ep_volatile_store_eventpipe_state_without_barrier (EventPipeState state) +{ + extern volatile EventPipeState _ep_state; + ep_rt_volatile_store_uint32_t_without_barrier ((volatile uint32_t *)&_ep_state, state); +} + +static +inline +EventPipeSession * +ep_volatile_load_session (size_t index) +{ + extern volatile EventPipeSession *_ep_sessions [EP_MAX_NUMBER_OF_SESSIONS]; + return (EventPipeSession *)ep_rt_volatile_load_ptr ((volatile void **)(&_ep_sessions [index])); +} + +static +inline +EventPipeSession * +ep_volatile_load_session_without_barrier (size_t index) +{ + extern volatile EventPipeSession *_ep_sessions [EP_MAX_NUMBER_OF_SESSIONS]; + return (EventPipeSession *)ep_rt_volatile_load_ptr_without_barrier ((volatile void **)(&_ep_sessions [index])); +} + +static +inline +void +ep_volatile_store_session (size_t index, EventPipeSession *session) +{ + extern volatile EventPipeSession *_ep_sessions [EP_MAX_NUMBER_OF_SESSIONS]; + ep_rt_volatile_store_ptr ((volatile void **)(&_ep_sessions [index]), session); +} + +static +inline +void +ep_volatile_store_session_without_barrier (size_t index, EventPipeSession *session) +{ + extern volatile EventPipeSession *_ep_sessions [EP_MAX_NUMBER_OF_SESSIONS]; + ep_rt_volatile_store_ptr_without_barrier ((volatile void **)(&_ep_sessions [index]), session); +} + +static +inline +uint32_t +ep_volatile_load_number_of_sessions (void) +{ + extern volatile uint32_t _ep_number_of_sessions; + return ep_rt_volatile_load_uint32_t (&_ep_number_of_sessions); +} + +static +inline +uint32_t +ep_volatile_load_number_of_sessions_without_barrier (void) +{ + extern volatile uint32_t _ep_number_of_sessions; + return ep_rt_volatile_load_uint32_t_without_barrier (&_ep_number_of_sessions); +} + +static +inline +void +ep_volatile_store_number_of_sessions (uint32_t number_of_sessions) +{ + extern volatile uint32_t _ep_number_of_sessions; + ep_rt_volatile_store_uint32_t (&_ep_number_of_sessions, number_of_sessions); +} + +static +inline +void +ep_volatile_store_number_of_sessions_without_barrier (uint32_t number_of_sessions) +{ + extern volatile uint32_t _ep_number_of_sessions; + ep_rt_volatile_store_uint32_t_without_barrier (&_ep_number_of_sessions, number_of_sessions); +} + +static +inline +uint64_t +ep_volatile_load_allow_write (void) +{ + extern volatile uint64_t _ep_allow_write; + return ep_rt_volatile_load_uint64_t (&_ep_allow_write); +} + +static +inline +uint64_t +ep_volatile_load_allow_write_without_barrier (void) +{ + extern volatile uint64_t _ep_allow_write; + return ep_rt_volatile_load_uint64_t_without_barrier (&_ep_allow_write); +} + +static +inline +void +ep_volatile_store_allow_write (uint64_t allow_write) +{ + extern volatile uint64_t _ep_allow_write; + ep_rt_volatile_store_uint64_t (&_ep_allow_write, allow_write); +} + +static +inline +void +ep_volatile_store_allow_write_without_barrier (uint64_t allow_write) +{ + extern volatile uint64_t _ep_allow_write; + ep_rt_volatile_store_uint64_t_without_barrier (&_ep_allow_write, allow_write); +} + +/* + * EventPipe. + */ + +EventPipeSessionID +ep_enable ( + const ep_char8_t *output_path, + uint32_t circular_buffer_size_in_mb, + const EventPipeProviderConfiguration *providers, + uint32_t providers_len, + EventPipeSessionType session_type, + EventPipeSerializationFormat format, + bool rundown_requested, + IpcStream *stream, + bool enable_sample_profiler); + +void +ep_disable (EventPipeSessionID id); + +EventPipeSession * +ep_get_session (EventPipeSessionID session_id); + +bool +ep_enabled (void); + +EventPipeProvider * +ep_create_provider ( + const ep_char8_t *provider_name, + EventPipeCallback callback_func, + void *callback_data); + +void +ep_delete_provider (EventPipeProvider *provider); + +EventPipeProvider * +ep_get_provider (const ep_char8_t *provider_name); + +void +ep_init (void); + +void +ep_finish_init (void); + +void +ep_shutdown (void); + +EventPipeEventMetadataEvent * +ep_build_event_metadata_event ( + EventPipeEventInstance *event_instance, + uint32_t metadata_id); + +void +ep_write_event ( + EventPipeEvent *ep_event, + EventData *event_data, + uint32_t event_data_len, + const uint8_t *activity_id, + const uint8_t *related_activity_id); + +EventPipeEventInstance * +ep_get_next_event (EventPipeSessionID session_id); + +EventPipeWaitHandle +ep_get_wait_handle (EventPipeSessionID session_id); + +void +ep_start_streaming (EventPipeSessionID session_id); + +/* + * EventPipePerf. + */ + +uint64_t +ep_perf_counter_query (void); + +uint64_t +ep_perf_frequency_query (void); + +#else /* ENABLE_PERFTRACING */ + +static +inline +void +ep_init (void) +{ + ; +} + +static +inline +void +ep_shutdown (void) +{ + ; +} + +#endif /* ENABLE_PERFTRACING */ +#endif /** __EVENTPIPE_H__ **/ diff --git a/src/mono/mono/eventpipe/test/Directory.Build.props b/src/mono/mono/eventpipe/test/Directory.Build.props new file mode 100644 index 00000000000000..4de865b5f1e158 --- /dev/null +++ b/src/mono/mono/eventpipe/test/Directory.Build.props @@ -0,0 +1,3 @@ + + + diff --git a/src/mono/mono/eventpipe/test/Directory.Build.targets b/src/mono/mono/eventpipe/test/Directory.Build.targets new file mode 100644 index 00000000000000..c43cec29bd65d2 --- /dev/null +++ b/src/mono/mono/eventpipe/test/Directory.Build.targets @@ -0,0 +1,3 @@ + + + diff --git a/src/mono/mono/eventpipe/test/Makefile.am b/src/mono/mono/eventpipe/test/Makefile.am new file mode 100644 index 00000000000000..4513e50da6326a --- /dev/null +++ b/src/mono/mono/eventpipe/test/Makefile.am @@ -0,0 +1,56 @@ +MAKEFLAGS := $(MAKEFLAGS) --no-builtin-rules + +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/mono $(GLIB_CFLAGS) + +if HOST_DARWIN +test_ldflags = -framework CoreFoundation -framework Foundation +endif + +sgen_libs = \ + $(top_builddir)/mono/metadata/libmonoruntimesgen.la \ + $(top_builddir)/mono/sgen/libmonosgen.la \ + $(top_builddir)/mono/utils/libmonoutils.la \ + $(top_builddir)/mono/eglib/libeglib.la + +mini_libs = \ + $(top_builddir)/mono/mini/libmini.la + +if !DISABLE_INTERPRETER +mini_libs += $(top_builddir)/mono/mini/libmono-ee-interp.la +endif + +if !DISABLE_DEBUGGER_AGENT +mini_libs += $(top_builddir)/mono/mini/libmono-dbg.la +endif + +eventpipe_libs = \ + $(top_builddir)/mono/eventpipe/libeventpipe.la + +CFLAGS = $(filter-out @CXX_REMOVE_CFLAGS@, @CFLAGS@) + +if !HOST_WIN32 +if ENABLE_PERFTRACING + +test_eventpipe_SOURCES = \ +ep-test-runner.c \ +ep-test-driver.c \ +ep-fake-tests.c \ +ep-fastserializer-tests.c \ +ep-provider-callback-dataqueue-tests.c \ +ep-setup-tests.c \ +ep-tests.c \ +ep-file-tests.c \ +ep-session-tests.c \ +ep-teardown-tests.c \ +ep-thread-tests.c \ +ep-tests-debug.h \ +ep-tests.h + +test_eventpipe_CFLAGS = $(AM_CFLAGS) $(SGEN_DEFINES) +test_eventpipe_LDADD = $(mini_libs) $(sgen_libs) $(eventpipe_libs) +test_eventpipe_LDFLAGS = $(test_ldflags) + +noinst_PROGRAMS = test-eventpipe + +endif ENABLE_PERFTRACING +endif !HOST_WIN32 diff --git a/src/mono/mono/eventpipe/test/ep-fake-tests.c b/src/mono/mono/eventpipe/test/ep-fake-tests.c new file mode 100644 index 00000000000000..86bc2521018939 --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-fake-tests.c @@ -0,0 +1 @@ +#include "mono/eglib/test/fake.c" diff --git a/src/mono/mono/eventpipe/test/ep-fastserializer-tests.c b/src/mono/mono/eventpipe/test/ep-fastserializer-tests.c new file mode 100644 index 00000000000000..0d39f7e6f294a8 --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-fastserializer-tests.c @@ -0,0 +1,346 @@ +#include "mono/eventpipe/ep.h" +#include "eglib/test/test.h" + +#define TEST_PROVIDER_NAME "MyTestProvider" + +typedef struct _MemoryStreamWriter { + StreamWriter stream_writer; + uint8_t buffer [1024]; + uint8_t *current_ptr; +} MemoryStreamWriter; + +static +void +memory_stream_writer_free_func (void *stream) +{ + g_free ((MemoryStreamWriter *)stream); +} + +static +bool +memory_stream_writer_write_func ( + void *stream, + const uint8_t *buffer, + uint32_t bytes_to_write, + uint32_t *bytes_written) +{ + *bytes_written = 0; + + MemoryStreamWriter *memory_stream = (MemoryStreamWriter *)stream; + if (!stream) + return false; + + if ((memory_stream->current_ptr + bytes_to_write) > (memory_stream->buffer + sizeof (memory_stream->buffer))) + return false; + + memcpy (memory_stream->current_ptr, buffer, bytes_to_write); + memory_stream->current_ptr += bytes_to_write; + *bytes_written = bytes_to_write; + + return true; +} + +static StreamWriterVtable memory_stream_writer_vtable = { + memory_stream_writer_free_func, + memory_stream_writer_write_func }; + +static RESULT +test_fast_serializer_object_fast_serialize (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + MemoryStreamWriter *stream_writer = NULL; + FastSerializer *fast_serializer = NULL; + EventPipeProvider *provider = NULL; + EventPipeEvent *ep_event = NULL; + EventPipeEventInstance *ep_event_instance = NULL; + EventPipeEventBlock *event_block = NULL; + + // Use memory stream for testing. + stream_writer = g_new0 (MemoryStreamWriter, 1); + ep_raise_error_if_nok (stream_writer != NULL); + + test_location = 1; + + stream_writer->current_ptr = stream_writer->buffer; + ep_stream_writer_init (&stream_writer->stream_writer, &memory_stream_writer_vtable); + + fast_serializer = ep_fast_serializer_alloc ((StreamWriter *)stream_writer); + ep_raise_error_if_nok (fast_serializer != NULL); + stream_writer = NULL; + + test_location = 2; + + provider = ep_create_provider (TEST_PROVIDER_NAME, NULL, NULL); + ep_raise_error_if_nok (provider != NULL); + + test_location = 3; + + ep_event = ep_event_alloc (provider, 1, 1, 1, EP_EVENT_LEVEL_VERBOSE, false, NULL, 0); + ep_raise_error_if_nok (ep_event != NULL); + + test_location = 4; + + ep_event_instance = ep_event_instance_alloc (ep_event, 0, 0, NULL, 0, NULL, NULL); + event_block = ep_event_block_alloc (1024, EP_SERIALIZATION_FORMAT_NETTRACE_V4); + ep_raise_error_if_nok (ep_event_instance != NULL && event_block != NULL); + + test_location = 5; + + ep_raise_error_if_nok (ep_event_block_base_write_event ((EventPipeEventBlockBase *)event_block, ep_event_instance, 0, 1, 0, false) == true); + + test_location = 6; + + ep_fast_serializable_object_fast_serialize ((FastSerializableObject *)event_block, fast_serializer); + + //Check memory stream results. + stream_writer = (MemoryStreamWriter *)ep_fast_serializer_get_stream_writer (fast_serializer); + if (stream_writer->buffer == stream_writer->current_ptr) { + result = FAILED ("fast_serialize for EventPipeEventBlock didn't write any data into MemoryStreamWriter"); + ep_raise_error (); + } + +ep_on_exit: + ep_event_instance_free (ep_event_instance); + ep_event_block_free (event_block); + ep_event_free (ep_event); + ep_delete_provider (provider); + ep_fast_serializer_free (fast_serializer); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_fast_serializer_event_block_free_vcall (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeEventBlock *event_block = ep_event_block_alloc (1024, EP_SERIALIZATION_FORMAT_NETTRACE_V4); + ep_raise_error_if_nok (event_block != NULL); + + test_location = 1; + + ep_fast_serializable_object_free_vcall ((FastSerializableObject *)event_block); + +ep_on_exit: + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_fast_serializer_metadata_block_free_vcall (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeMetadataBlock *metadata_block = ep_metadata_block_alloc (1024); + ep_raise_error_if_nok (metadata_block != NULL); + + test_location = 1; + + ep_fast_serializable_object_free_vcall ((FastSerializableObject *)metadata_block); + +ep_on_exit: + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_fast_serializer_sequence_point_block_free_vcall (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeSequencePoint sequence_point; + EventPipeSequencePointBlock *sequence_point_block = NULL; + + ep_raise_error_if_nok (ep_sequence_point_init (&sequence_point) != NULL); + + test_location = 1; + + sequence_point_block = ep_sequence_point_block_alloc (&sequence_point); + ep_raise_error_if_nok (sequence_point_block != NULL); + + test_location = 2; + + ep_fast_serializable_object_free_vcall ((FastSerializableObject *)sequence_point_block); + +ep_on_exit: + ep_sequence_point_fini (&sequence_point); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_fast_serializer_stack_block_free_vcall (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeStackBlock *stack_block = ep_stack_block_alloc (1024); + ep_raise_error_if_nok (stack_block != NULL); + + test_location = 1; + + ep_fast_serializable_object_free_vcall ((FastSerializableObject *)stack_block); + +ep_on_exit: + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_fast_serializer_event_block_get_type_name (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeEventBlock *event_block = ep_event_block_alloc (1024, EP_SERIALIZATION_FORMAT_NETTRACE_V4); + ep_raise_error_if_nok (event_block != NULL); + + test_location = 1; + + const char *type_name = (char *)ep_fast_serializable_object_get_type_name ((FastSerializableObject *)event_block); + if (strcmp (type_name, "EventBlock")) { + result = FAILED ("get_type_name for EventPipeEventBlock returned unexpected value, retrieved: %s, expected: %s", type_name, "EventBlock"); + ep_raise_error (); + } + +ep_on_exit: + ep_event_block_free (event_block); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_fast_serializer_metadata_block_get_type_name (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeMetadataBlock *metadata_block = ep_metadata_block_alloc (1024); + ep_raise_error_if_nok (metadata_block != NULL); + + test_location = 1; + + const char *type_name = (char *)ep_fast_serializable_object_get_type_name ((FastSerializableObject *)metadata_block); + if (strcmp (type_name, "MetadataBlock")) { + result = FAILED ("get_type_name for EventPipeMetadataBlock returned unexpected value, retrieved: %s, expected: %s", type_name, "MetadataBlock"); + ep_raise_error (); + } + +ep_on_exit: + ep_metadata_block_free (metadata_block); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_fast_serializer_sequence_point_block_get_type_name (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeSequencePoint sequence_point; + EventPipeSequencePointBlock *sequence_point_block = NULL; + + ep_raise_error_if_nok (ep_sequence_point_init (&sequence_point) != NULL); + + test_location = 1; + + sequence_point_block = ep_sequence_point_block_alloc (&sequence_point); + ep_raise_error_if_nok (sequence_point_block != NULL); + + test_location = 2; + + const char *type_name = (char *)ep_fast_serializable_object_get_type_name ((FastSerializableObject *)sequence_point_block); + if (strcmp (type_name, "SPBlock")) { + result = FAILED ("get_type_name for EventPipeSequencePointBlock returned unexpected value, retrieved: %s, expected: %s", type_name, "SPBlock"); + ep_raise_error (); + } + +ep_on_exit: + ep_sequence_point_block_free (sequence_point_block); + ep_sequence_point_fini (&sequence_point); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_fast_serializer_stack_block_get_type_name (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeStackBlock *stack_block = ep_stack_block_alloc (1024); + ep_raise_error_if_nok (stack_block != NULL); + + test_location = 1; + + const char *type_name = (char *)ep_fast_serializable_object_get_type_name ((FastSerializableObject *)stack_block); + if (strcmp (type_name, "StackBlock")) { + result = FAILED ("get_type_name for EventPipeStackBlock returned unexpected value, retrieved: %s, expected: %s", type_name, "StackBlock"); + ep_raise_error (); + } + +ep_on_exit: + ep_stack_block_free (stack_block); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +//TODO: Add perf test just doing write into fast serializer with different event types (no event alloc/instancing). Write into void +//stream but still write into same memory buffer to do something. + +static Test ep_fastserializer_tests [] = { + {"fast_serializer_object_fast_serialize", test_fast_serializer_object_fast_serialize}, + {"test_fast_serializer_event_block_free_vcall", test_fast_serializer_event_block_free_vcall}, + {"test_fast_serializer_metadata_block_free_vcall", test_fast_serializer_metadata_block_free_vcall}, + {"test_fast_serializer_sequence_point_block_free_vcall", test_fast_serializer_sequence_point_block_free_vcall}, + {"test_fast_serializer_stack_block_free_vcall", test_fast_serializer_stack_block_free_vcall}, + {"test_fast_serializer_event_block_get_type_name", test_fast_serializer_event_block_get_type_name}, + {"test_fast_serializer_metadata_block_get_type_name", test_fast_serializer_metadata_block_get_type_name}, + {"test_fast_serializer_sequence_point_block_get_type_name", test_fast_serializer_sequence_point_block_get_type_name}, + {"test_fast_serializer_stack_block_get_type_name", test_fast_serializer_stack_block_get_type_name}, + {NULL, NULL} +}; + +DEFINE_TEST_GROUP_INIT(ep_fastserializer_tests_init, ep_fastserializer_tests) diff --git a/src/mono/mono/eventpipe/test/ep-file-tests.c b/src/mono/mono/eventpipe/test/ep-file-tests.c new file mode 100644 index 00000000000000..696d2442c9baf4 --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-file-tests.c @@ -0,0 +1,172 @@ +#include "mono/eventpipe/ep.h" +#include "eglib/test/test.h" + +#define TEST_PROVIDER_NAME "MyTestProvider" +#define TEST_FILE "./ep_test_create_file.txt" + +static RESULT +test_create_file (EventPipeSerializationFormat format) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeFile *file = NULL; + FileStreamWriter *file_stream_writer = NULL; + + file_stream_writer = ep_file_stream_writer_alloc (TEST_FILE); + ep_raise_error_if_nok (file_stream_writer != NULL); + + test_location = 1; + + file = ep_file_alloc ((StreamWriter *)file_stream_writer, format); + ep_raise_error_if_nok (file != NULL); + + file_stream_writer = NULL; + if (!ep_file_initialize_file (file)) { + result = FAILED ("ep_file_initialize_file failed"); + ep_raise_error (); + } + + test_location = 2; + + ep_file_flush (file, EP_FILE_FLUSH_FLAGS_ALL_BLOCKS); + + test_location = 3; + +ep_on_exit: + ep_file_free (file); + ep_file_stream_writer_free (file_stream_writer); + + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_file_write_event (EventPipeSerializationFormat format, bool write_event, bool write_sequence_point) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeFile *file = NULL; + FileStreamWriter *file_stream_writer = NULL; + EventPipeProvider *provider = NULL; + EventPipeEvent *ep_event = NULL; + EventPipeEventInstance *ep_event_instance = NULL; + EventPipeEventMetadataEvent *metadata_event = NULL; + + file_stream_writer = ep_file_stream_writer_alloc (TEST_FILE); + ep_raise_error_if_nok (file_stream_writer != NULL); + + test_location = 1; + + file = ep_file_alloc ((StreamWriter *)file_stream_writer, format); + ep_raise_error_if_nok (file != NULL); + + file_stream_writer = NULL; + if (!ep_file_initialize_file (file)) { + result = FAILED ("ep_file_initialize_file failed"); + ep_raise_error (); + } + + test_location = 2; + + if (write_event) { + provider = ep_create_provider (TEST_PROVIDER_NAME, NULL, NULL); + ep_raise_error_if_nok (provider != NULL); + + test_location = 3; + + ep_event = ep_event_alloc (provider, 1, 1, 1, EP_EVENT_LEVEL_VERBOSE, false, NULL, 0); + ep_raise_error_if_nok (ep_event != NULL); + + test_location = 4; + + ep_event_instance = ep_event_instance_alloc (ep_event, 0, 0, NULL, 0, NULL, NULL); + ep_raise_error_if_nok (ep_event_instance != NULL); + + test_location = 5; + + metadata_event = ep_build_event_metadata_event (ep_event_instance, 1); + ep_raise_error_if_nok (metadata_event != NULL); + + ep_file_write_event (file, (EventPipeEventInstance *)metadata_event, 1, 1 , true); + } + + if (write_sequence_point) { + EventPipeSequencePoint sequence_point; + ep_sequence_point_init (&sequence_point); + ep_file_write_sequence_point (file, &sequence_point); + ep_sequence_point_fini (&sequence_point); + } + + ep_file_flush (file, EP_FILE_FLUSH_FLAGS_ALL_BLOCKS); + + test_location = 6; + +ep_on_exit: + ep_delete_provider (provider); + ep_event_free (ep_event); + ep_event_instance_free (ep_event_instance); + ep_event_metdata_event_free (metadata_event); + ep_file_free (file); + ep_file_stream_writer_free (file_stream_writer); + + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_create_file_netperf_v3 (void) +{ + return test_create_file (EP_SERIALIZATION_FORMAT_NETPERF_V3); +} + +static RESULT +test_create_file_nettrace_v4 (void) +{ + return test_create_file (EP_SERIALIZATION_FORMAT_NETTRACE_V4); +} + +static RESULT +test_file_write_event_netperf_v3 (void) +{ + return test_file_write_event (EP_SERIALIZATION_FORMAT_NETPERF_V3, true, false); +} + +static RESULT +test_file_write_event_nettrace_v4 (void) +{ + return test_file_write_event (EP_SERIALIZATION_FORMAT_NETTRACE_V4, true, false); +} + +static RESULT +test_file_write_sequence_point_netperf_v3 (void) +{ + return test_file_write_event (EP_SERIALIZATION_FORMAT_NETPERF_V3, false, true); +} + +static RESULT +test_file_write_sequence_point_nettrace_v4 (void) +{ + return test_file_write_event (EP_SERIALIZATION_FORMAT_NETTRACE_V4, false, true); +} + +static Test ep_file_tests [] = { + {"test_create_file_netperf_v3", test_create_file_netperf_v3}, + {"test_create_file_nettrace_v4", test_create_file_nettrace_v4}, + {"test_file_write_event_netperf_v3", test_file_write_event_netperf_v3}, + {"test_file_write_event_nettrace_v4", test_file_write_event_nettrace_v4}, + {"test_file_write_sequence_point_netperf_v3", test_file_write_sequence_point_netperf_v3}, + {"test_file_write_sequence_point_nettrace_v4", test_file_write_sequence_point_nettrace_v4}, + {NULL, NULL} +}; + +DEFINE_TEST_GROUP_INIT(ep_file_tests_init, ep_file_tests) diff --git a/src/mono/mono/eventpipe/test/ep-provider-callback-dataqueue-tests.c b/src/mono/mono/eventpipe/test/ep-provider-callback-dataqueue-tests.c new file mode 100644 index 00000000000000..06a45c4c6a5e71 --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-provider-callback-dataqueue-tests.c @@ -0,0 +1,98 @@ +#include "mono/eventpipe/ep.h" +#include "eglib/test/test.h" + +#define TEST_PROVIDER_NAME "MyTestProvider" +#define TEST_FILE "./ep_test_create_file.txt" + +#ifdef _CRTDBG_MAP_ALLOC +static _CrtMemState eventpipe_memory_start_snapshot; +static _CrtMemState eventpipe_memory_end_snapshot; +static _CrtMemState eventpipe_memory_diff_snapshot; +#endif + +static RESULT +test_provider_callback_data_queue_setup (void) +{ +#ifdef _CRTDBG_MAP_ALLOC + _CrtMemCheckpoint (&eventpipe_memory_start_snapshot); +#endif + return NULL; +} + +static +void +provider_callback ( + const uint8_t *source_id, + unsigned long is_enabled, + uint8_t level, + uint64_t match_any_keywords, + uint64_t match_all_keywords, + EventFilterDescriptor *filter_data, + void *callback_context) +{ + ; +} + +static RESULT +test_provider_callback_data_queue (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeProviderCallbackDataQueue callback_data_queue; + EventPipeProviderCallbackDataQueue *provider_callback_data_queue = ep_provider_callback_data_queue_init (&callback_data_queue); + + EventPipeProviderCallbackData enqueue_callback_data; + EventPipeProviderCallbackData *provider_enqueue_callback_data = ep_provider_callback_data_init ( + &enqueue_callback_data, + "", + provider_callback, + NULL, + 1, + EP_EVENT_LEVEL_LOG_ALWAYS, + true); + + for (uint32_t i = 0; i < 1000; ++i) + ep_provider_callback_data_queue_enqueue (provider_callback_data_queue, provider_enqueue_callback_data); + + EventPipeProviderCallbackData dequeue_callback_data; + uint32_t deque_counter = 0; + while (ep_provider_callback_data_queue_try_dequeue (provider_callback_data_queue, &dequeue_callback_data)) + deque_counter++; + + if (deque_counter != 1000) { + result = FAILED ("Unexpected number of provider callback invokes"); + ep_raise_error (); + } + +ep_on_exit: + ep_provider_callback_data_queue_fini (provider_callback_data_queue); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_provider_callback_data_queue_teardown (void) +{ +#ifdef _CRTDBG_MAP_ALLOC + _CrtMemCheckpoint (&eventpipe_memory_end_snapshot); + if ( _CrtMemDifference( &eventpipe_memory_diff_snapshot, &eventpipe_memory_start_snapshot, &eventpipe_memory_end_snapshot) ) { + _CrtMemDumpStatistics( &eventpipe_memory_diff_snapshot ); + return FAILED ("Memory leak detected!"); + } +#endif + return NULL; +} + +static Test ep_provider_callback_data_queue_tests [] = { + {"test_provider_callback_data_queue_setup", test_provider_callback_data_queue_setup}, + {"test_provider_callback_data_queue", test_provider_callback_data_queue}, + {"test_provider_callback_data_queue_teardown", test_provider_callback_data_queue_teardown}, + {NULL, NULL} +}; + +DEFINE_TEST_GROUP_INIT(ep_provider_callback_data_queue_tests_init, ep_provider_callback_data_queue_tests) diff --git a/src/mono/mono/eventpipe/test/ep-session-tests.c b/src/mono/mono/eventpipe/test/ep-session-tests.c new file mode 100644 index 00000000000000..c9ef8fa79acfe0 --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-session-tests.c @@ -0,0 +1,244 @@ +#include "mono/eventpipe/ep.h" +#include "eglib/test/test.h" + +#define TEST_PROVIDER_NAME "MyTestProvider" +#define TEST_FILE "./ep_test_create_file.txt" + +#ifdef _CRTDBG_MAP_ALLOC +static _CrtMemState eventpipe_memory_start_snapshot; +static _CrtMemState eventpipe_memory_end_snapshot; +static _CrtMemState eventpipe_memory_diff_snapshot; +#endif + +static RESULT +test_session_setup (void) +{ +#ifdef _CRTDBG_MAP_ALLOC + _CrtMemCheckpoint (&eventpipe_memory_start_snapshot); +#endif + return NULL; +} + +static RESULT +test_create_delete_session (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + EventPipeSession *test_session = NULL; + + EventPipeProviderConfiguration provider_config; + ep_raise_error_if_nok (ep_provider_config_init (&provider_config, TEST_PROVIDER_NAME, 1, EP_EVENT_LEVEL_LOG_ALWAYS, "") != NULL); + + test_location = 1; + + EP_CONFIG_LOCK_ENTER + test_session = ep_session_alloc ( + 1, + TEST_FILE, + NULL, + EP_SESSION_TYPE_FILE, + EP_SERIALIZATION_FORMAT_NETTRACE_V4, + false, + 1, + &provider_config, + 1, + false); + EP_CONFIG_LOCK_EXIT + + ep_raise_error_if_nok (test_session != NULL); + +ep_on_exit: + ep_session_free (test_session); + if (test_location != 0) + ep_provider_config_fini (&provider_config); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_add_session_providers (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + EventPipeSession *test_session = NULL; + EventPipeSessionProvider *test_session_provider = NULL; + + EventPipeProviderConfiguration provider_config; + ep_raise_error_if_nok (ep_provider_config_init (&provider_config, TEST_PROVIDER_NAME, 1, EP_EVENT_LEVEL_LOG_ALWAYS, "") != NULL); + + test_location = 1; + + EP_CONFIG_LOCK_ENTER + test_session = ep_session_alloc ( + 1, + TEST_FILE, + NULL, + EP_SESSION_TYPE_FILE, + EP_SERIALIZATION_FORMAT_NETTRACE_V4, + false, + 1, + &provider_config, + 1, + false); + EP_CONFIG_LOCK_EXIT + + ep_raise_error_if_nok (test_session != NULL); + + test_location = 2; + + if (!ep_session_is_valid (test_session)) { + result = FAILED ("ep_session_is_valid returned false with session providers"); + ep_raise_error (); + } + + test_location = 3; + + test_session_provider = ep_session_provider_alloc (TEST_PROVIDER_NAME, 1, EP_EVENT_LEVEL_LOG_ALWAYS, ""); + ep_raise_error_if_nok (test_session_provider != NULL); + + test_location = 4; + + ep_session_add_session_provider (test_session, test_session_provider); + test_session_provider = NULL; + + if (!ep_session_is_valid (test_session)) { + result = FAILED ("ep_session_is_valid returned false with session providers"); + ep_raise_error (); + } + + test_location = 5; + + ep_session_disable (test_session); + + if (ep_session_is_valid (test_session)) { + result = FAILED ("ep_session_is_valid returned true without session providers"); + ep_raise_error (); + } + +ep_on_exit: + ep_session_free (test_session); + if (test_location != 0) + ep_provider_config_fini (&provider_config); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_session_special_get_set (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + EventPipeSession *test_session = NULL; + + EventPipeProviderConfiguration provider_config; + EventPipeProviderConfiguration *current_provider_config = ep_provider_config_init (&provider_config, TEST_PROVIDER_NAME, 1, EP_EVENT_LEVEL_LOG_ALWAYS, ""); + ep_raise_error_if_nok (current_provider_config != NULL); + + test_location = 1; + + EP_CONFIG_LOCK_ENTER + test_session = ep_session_alloc ( + 1, + TEST_FILE, + NULL, + EP_SESSION_TYPE_FILE, + EP_SERIALIZATION_FORMAT_NETTRACE_V4, + false, + 1, + current_provider_config, + 1, + false); + EP_CONFIG_LOCK_EXIT + + ep_raise_error_if_nok (test_session != NULL); + + test_location = 2; + + if (ep_session_get_rundown_enabled (test_session)) { + result = FAILED ("ep_session_get_rundown_enabled returned true, should be false"); + ep_raise_error (); + } + + test_location = 3; + + ep_session_set_rundown_enabled (test_session, true); + + if (!ep_session_get_rundown_enabled (test_session)) { + result = FAILED ("ep_session_get_rundown_enabled returned false, should be true"); + ep_raise_error (); + } + + test_location = 4; + + if (ep_session_get_ipc_streaming_enabled (test_session)) { + result = FAILED ("ep_session_get_ipc_streaming_enabled returned true, should be false"); + ep_raise_error (); + } + + test_location = 5; + + ep_session_set_ipc_streaming_enabled (test_session, true); + + if (!ep_session_get_ipc_streaming_enabled (test_session)) { + result = FAILED ("ep_session_set_ipc_streaming_enabled returned false, should be true"); + ep_raise_error (); + } + + ep_session_set_ipc_streaming_enabled (test_session, false); + + test_location = 6; + + if (!ep_session_get_wait_event (test_session)) { + result = FAILED ("ep_session_get_wait_event failed"); + ep_raise_error (); + } + + test_location = 7; + + if (!ep_session_get_mask (test_session)) { + result = FAILED ("Unexpected session mask"); + ep_raise_error (); + } + +ep_on_exit: + ep_session_free (test_session); + ep_provider_config_fini (current_provider_config); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_session_teardown (void) +{ +#ifdef _CRTDBG_MAP_ALLOC + _CrtMemCheckpoint (&eventpipe_memory_end_snapshot); + if ( _CrtMemDifference( &eventpipe_memory_diff_snapshot, &eventpipe_memory_start_snapshot, &eventpipe_memory_end_snapshot) ) { + _CrtMemDumpStatistics( &eventpipe_memory_diff_snapshot ); + return FAILED ("Memory leak detected!"); + } +#endif + return NULL; +} + +static Test ep_session_tests [] = { + {"test_session_setup", test_session_setup}, + {"test_create_delete_session", test_create_delete_session}, + {"test_add_session_providers", test_add_session_providers}, + {"test_session_special_get_set", test_session_special_get_set}, + {"test_session_teardown", test_session_teardown}, + {NULL, NULL} +}; + +DEFINE_TEST_GROUP_INIT(ep_session_tests_init, ep_session_tests) diff --git a/src/mono/mono/eventpipe/test/ep-setup-tests.c b/src/mono/mono/eventpipe/test/ep-setup-tests.c new file mode 100644 index 00000000000000..30e51463bc1697 --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-setup-tests.c @@ -0,0 +1,27 @@ +#include "mono/eventpipe/ep.h" +#include "eglib/test/test.h" +#include +#include + +MonoDomain *eventpipe_test_domain; + +static RESULT +test_setup (void) +{ + char *core_root = g_getenv ("CORE_ROOT"); + if (core_root) { + mono_set_assemblies_path (core_root); + g_free (core_root); + } + + eventpipe_test_domain = mono_jit_init_version_for_test_only ("eventpipe-tests", "v4.0.30319"); + + return NULL; +} + +static Test ep_setup_tests [] = { + {"test_setup", test_setup}, + {NULL, NULL} +}; + +DEFINE_TEST_GROUP_INIT(ep_setup_tests_init, ep_setup_tests) diff --git a/src/mono/mono/eventpipe/test/ep-teardown-tests.c b/src/mono/mono/eventpipe/test/ep-teardown-tests.c new file mode 100644 index 00000000000000..3800f9360e7259 --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-teardown-tests.c @@ -0,0 +1,25 @@ +#include "mono/eventpipe/ep.h" +#include "eglib/test/test.h" +#include + +#define TEST_FILE "./ep_test_create_file.txt" + +extern MonoDomain *eventpipe_test_domain; + +static RESULT +test_teardown (void) +{ + if (eventpipe_test_domain) + mono_jit_cleanup (eventpipe_test_domain); + + unlink (TEST_FILE); + + return NULL; +} + +static Test ep_teardown_tests [] = { + {"test_teardown", test_teardown}, + {NULL, NULL} +}; + +DEFINE_TEST_GROUP_INIT(ep_teardown_tests_init, ep_teardown_tests) diff --git a/src/mono/mono/eventpipe/test/ep-test-driver.c b/src/mono/mono/eventpipe/test/ep-test-driver.c new file mode 100644 index 00000000000000..a1aa730b814c7e --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-test-driver.c @@ -0,0 +1,5 @@ +#define DRIVER_EXTERNAL_TESTS +#define DRIVER_NAME "eventpipe-tests" + +#include "ep-tests.h" +#include "mono/eglib/test/driver.c" diff --git a/src/mono/mono/eventpipe/test/ep-test-runner.c b/src/mono/mono/eventpipe/test/ep-test-runner.c new file mode 100644 index 00000000000000..7e9072000f9212 --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-test-runner.c @@ -0,0 +1 @@ +#include "mono/eglib/test/test.c" diff --git a/src/mono/mono/eventpipe/test/ep-test.sln b/src/mono/mono/eventpipe/test/ep-test.sln new file mode 100644 index 00000000000000..4431637a8dbb8e --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-test.sln @@ -0,0 +1,127 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30011.22 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ep-test", "ep-test.vcxproj", "{AF48E883-A558-4027-8934-32CFD2750D04}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eglib", "..\..\..\msvc\eglib.vcxproj", "{158073ED-99AE-4196-9EDC-DDB2344F8466}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmonoutils", "..\..\..\msvc\libmonoutils.vcxproj", "{8FC2B0C8-51AD-49DF-851F-5D01A77A75E4}" + ProjectSection(ProjectDependencies) = postProject + {C36612BD-22D3-4B95-85E2-7FDC4FC5D740} = {C36612BD-22D3-4B95-85E2-7FDC4FC5D740} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmonoruntime", "..\..\..\msvc\libmonoruntime.vcxproj", "{C36612BD-22D3-4B95-85E2-7FDC4FC5D739}" + ProjectSection(ProjectDependencies) = postProject + {C36612BD-22D3-4B95-85E2-7FDC4FC5D740} = {C36612BD-22D3-4B95-85E2-7FDC4FC5D740} + {8FC2B0C8-51AD-49DF-851F-5D01A77A75E4} = {8FC2B0C8-51AD-49DF-851F-5D01A77A75E4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libgcmonosgen", "..\..\..\msvc\libgcmonosgen.vcxproj", "{C36612BD-22D3-4B95-85E2-7FDC4FC5D740}" + ProjectSection(ProjectDependencies) = postProject + {158073ED-99AE-4196-9EDC-DDB2344F8466} = {158073ED-99AE-4196-9EDC-DDB2344F8466} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmini", "..\..\..\msvc\libmini.vcxproj", "{88D2EB79-592D-45F8-B849-AE021C1D983A}" + ProjectSection(ProjectDependencies) = postProject + {C36612BD-22D3-4B95-85E2-7FDC4FC5D739} = {C36612BD-22D3-4B95-85E2-7FDC4FC5D739} + {C36612BD-22D3-4B95-85E2-7FDC4FC5D740} = {C36612BD-22D3-4B95-85E2-7FDC4FC5D740} + {8FC2B0C8-51AD-49DF-851F-5D01A77A75E4} = {8FC2B0C8-51AD-49DF-851F-5D01A77A75E4} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "static-mono-runtime", "static-mono-runtime", "{B46B84C3-14C4-4C81-B4A3-CE5292663515}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmono-static", "..\..\..\msvc\libmono-static.vcxproj", "{CB0D9E92-293C-439C-9AC7-C5F59B6E0772}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "build-init", "..\..\..\msvc\build-init.vcxproj", "{92AE7622-5F58-4234-9A26-9EC71876B3F4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AF48E883-A558-4027-8934-32CFD2750D04}.Debug|Win32.ActiveCfg = Debug|Win32 + {AF48E883-A558-4027-8934-32CFD2750D04}.Debug|Win32.Build.0 = Debug|Win32 + {AF48E883-A558-4027-8934-32CFD2750D04}.Debug|x64.ActiveCfg = Debug|x64 + {AF48E883-A558-4027-8934-32CFD2750D04}.Debug|x64.Build.0 = Debug|x64 + {AF48E883-A558-4027-8934-32CFD2750D04}.Release|Win32.ActiveCfg = Release|Win32 + {AF48E883-A558-4027-8934-32CFD2750D04}.Release|Win32.Build.0 = Release|Win32 + {AF48E883-A558-4027-8934-32CFD2750D04}.Release|x64.ActiveCfg = Release|x64 + {AF48E883-A558-4027-8934-32CFD2750D04}.Release|x64.Build.0 = Release|x64 + {158073ED-99AE-4196-9EDC-DDB2344F8466}.Debug|Win32.ActiveCfg = Debug|Win32 + {158073ED-99AE-4196-9EDC-DDB2344F8466}.Debug|Win32.Build.0 = Debug|Win32 + {158073ED-99AE-4196-9EDC-DDB2344F8466}.Debug|x64.ActiveCfg = Debug|x64 + {158073ED-99AE-4196-9EDC-DDB2344F8466}.Debug|x64.Build.0 = Debug|x64 + {158073ED-99AE-4196-9EDC-DDB2344F8466}.Release|Win32.ActiveCfg = Release|Win32 + {158073ED-99AE-4196-9EDC-DDB2344F8466}.Release|Win32.Build.0 = Release|Win32 + {158073ED-99AE-4196-9EDC-DDB2344F8466}.Release|x64.ActiveCfg = Release|x64 + {158073ED-99AE-4196-9EDC-DDB2344F8466}.Release|x64.Build.0 = Release|x64 + {8FC2B0C8-51AD-49DF-851F-5D01A77A75E4}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FC2B0C8-51AD-49DF-851F-5D01A77A75E4}.Debug|Win32.Build.0 = Debug|Win32 + {8FC2B0C8-51AD-49DF-851F-5D01A77A75E4}.Debug|x64.ActiveCfg = Debug|x64 + {8FC2B0C8-51AD-49DF-851F-5D01A77A75E4}.Debug|x64.Build.0 = Debug|x64 + {8FC2B0C8-51AD-49DF-851F-5D01A77A75E4}.Release|Win32.ActiveCfg = Release|Win32 + {8FC2B0C8-51AD-49DF-851F-5D01A77A75E4}.Release|Win32.Build.0 = Release|Win32 + {8FC2B0C8-51AD-49DF-851F-5D01A77A75E4}.Release|x64.ActiveCfg = Release|x64 + {8FC2B0C8-51AD-49DF-851F-5D01A77A75E4}.Release|x64.Build.0 = Release|x64 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D739}.Debug|Win32.ActiveCfg = Debug|Win32 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D739}.Debug|Win32.Build.0 = Debug|Win32 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D739}.Debug|x64.ActiveCfg = Debug|x64 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D739}.Debug|x64.Build.0 = Debug|x64 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D739}.Release|Win32.ActiveCfg = Release|Win32 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D739}.Release|Win32.Build.0 = Release|Win32 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D739}.Release|x64.ActiveCfg = Release|x64 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D739}.Release|x64.Build.0 = Release|x64 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D740}.Debug|Win32.ActiveCfg = Debug|Win32 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D740}.Debug|Win32.Build.0 = Debug|Win32 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D740}.Debug|x64.ActiveCfg = Debug|x64 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D740}.Debug|x64.Build.0 = Debug|x64 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D740}.Release|Win32.ActiveCfg = Release|Win32 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D740}.Release|Win32.Build.0 = Release|Win32 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D740}.Release|x64.ActiveCfg = Release|x64 + {C36612BD-22D3-4B95-85E2-7FDC4FC5D740}.Release|x64.Build.0 = Release|x64 + {88D2EB79-592D-45F8-B849-AE021C1D983A}.Debug|Win32.ActiveCfg = Debug|Win32 + {88D2EB79-592D-45F8-B849-AE021C1D983A}.Debug|Win32.Build.0 = Debug|Win32 + {88D2EB79-592D-45F8-B849-AE021C1D983A}.Debug|x64.ActiveCfg = Debug|x64 + {88D2EB79-592D-45F8-B849-AE021C1D983A}.Debug|x64.Build.0 = Debug|x64 + {88D2EB79-592D-45F8-B849-AE021C1D983A}.Release|Win32.ActiveCfg = Release|Win32 + {88D2EB79-592D-45F8-B849-AE021C1D983A}.Release|Win32.Build.0 = Release|Win32 + {88D2EB79-592D-45F8-B849-AE021C1D983A}.Release|x64.ActiveCfg = Release|x64 + {88D2EB79-592D-45F8-B849-AE021C1D983A}.Release|x64.Build.0 = Release|x64 + {CB0D9E92-293C-439C-9AC7-C5F59B6E0772}.Debug|Win32.ActiveCfg = Debug|Win32 + {CB0D9E92-293C-439C-9AC7-C5F59B6E0772}.Debug|Win32.Build.0 = Debug|Win32 + {CB0D9E92-293C-439C-9AC7-C5F59B6E0772}.Debug|x64.ActiveCfg = Debug|x64 + {CB0D9E92-293C-439C-9AC7-C5F59B6E0772}.Debug|x64.Build.0 = Debug|x64 + {CB0D9E92-293C-439C-9AC7-C5F59B6E0772}.Release|Win32.ActiveCfg = Release|Win32 + {CB0D9E92-293C-439C-9AC7-C5F59B6E0772}.Release|Win32.Build.0 = Release|Win32 + {CB0D9E92-293C-439C-9AC7-C5F59B6E0772}.Release|x64.ActiveCfg = Release|x64 + {CB0D9E92-293C-439C-9AC7-C5F59B6E0772}.Release|x64.Build.0 = Release|x64 + {92AE7622-5F58-4234-9A26-9EC71876B3F4}.Debug|Win32.ActiveCfg = Debug|Win32 + {92AE7622-5F58-4234-9A26-9EC71876B3F4}.Debug|Win32.Build.0 = Debug|Win32 + {92AE7622-5F58-4234-9A26-9EC71876B3F4}.Debug|x64.ActiveCfg = Debug|x64 + {92AE7622-5F58-4234-9A26-9EC71876B3F4}.Debug|x64.Build.0 = Debug|x64 + {92AE7622-5F58-4234-9A26-9EC71876B3F4}.Release|Win32.ActiveCfg = Release|Win32 + {92AE7622-5F58-4234-9A26-9EC71876B3F4}.Release|Win32.Build.0 = Release|Win32 + {92AE7622-5F58-4234-9A26-9EC71876B3F4}.Release|x64.ActiveCfg = Release|x64 + {92AE7622-5F58-4234-9A26-9EC71876B3F4}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {158073ED-99AE-4196-9EDC-DDB2344F8466} = {B46B84C3-14C4-4C81-B4A3-CE5292663515} + {8FC2B0C8-51AD-49DF-851F-5D01A77A75E4} = {B46B84C3-14C4-4C81-B4A3-CE5292663515} + {C36612BD-22D3-4B95-85E2-7FDC4FC5D739} = {B46B84C3-14C4-4C81-B4A3-CE5292663515} + {C36612BD-22D3-4B95-85E2-7FDC4FC5D740} = {B46B84C3-14C4-4C81-B4A3-CE5292663515} + {88D2EB79-592D-45F8-B849-AE021C1D983A} = {B46B84C3-14C4-4C81-B4A3-CE5292663515} + {CB0D9E92-293C-439C-9AC7-C5F59B6E0772} = {B46B84C3-14C4-4C81-B4A3-CE5292663515} + {92AE7622-5F58-4234-9A26-9EC71876B3F4} = {B46B84C3-14C4-4C81-B4A3-CE5292663515} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {CE83F76A-FA5A-4DF0-B015-5D802539DEFC} + EndGlobalSection +EndGlobal diff --git a/src/mono/mono/eventpipe/test/ep-test.vcxproj b/src/mono/mono/eventpipe/test/ep-test.vcxproj new file mode 100644 index 00000000000000..6687c5d70819c7 --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-test.vcxproj @@ -0,0 +1,186 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + ..\..\.. + + + + + + + + + + + + + + + + + + + + + {cb0d9e92-293c-439c-9ac7-c5f59b6e0772} + + + + {AF48E883-A558-4027-8934-32CFD2750D04} + eventpipe + Win32Proj + 10.0 + + + + Application + false + $(DefaultPlatformToolset) + Unicode + + + Application + $(DefaultPlatformToolset) + true + Unicode + + + Application + false + $(DefaultPlatformToolset) + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + + + + + + + + + + + + + + + + + + + + + false + $(ProjectName)$(MONO_TARGET_SUFFIX) + $(MONO_BUILD_DIR_PREFIX)$(Platform)\bin\$(Configuration)\ + $(MONO_BUILD_DIR_PREFIX)$(Platform)\obj\$(ProjectName)$(MONO_TARGET_SUFFIX)\$(Configuration)\ + + + false + $(ProjectName)$(MONO_TARGET_SUFFIX) + $(MONO_BUILD_DIR_PREFIX)$(Platform)\bin\$(Configuration)\ + $(MONO_BUILD_DIR_PREFIX)$(Platform)\obj\$(ProjectName)$(MONO_TARGET_SUFFIX)\$(Configuration)\ + + + true + $(ProjectName)$(MONO_TARGET_SUFFIX) + $(MONO_BUILD_DIR_PREFIX)$(Platform)\bin\$(Configuration)\ + $(MONO_BUILD_DIR_PREFIX)$(Platform)\obj\$(ProjectName)$(MONO_TARGET_SUFFIX)\$(Configuration)\ + + + true + $(ProjectName)$(MONO_TARGET_SUFFIX) + $(MONO_BUILD_DIR_PREFIX)$(Platform)\bin\$(Configuration)\ + $(MONO_BUILD_DIR_PREFIX)$(Platform)\obj\$(ProjectName)$(MONO_TARGET_SUFFIX)\$(Configuration)\ + + + + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(MONO_EGLIB_SOURCE_DIR);%(AdditionalIncludeDirectories) + Level4 + Disabled + $(ProjectDir)ep-tests-debug.h + + + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + Console + + + + + Level4 + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(MONO_EGLIB_SOURCE_DIR);%(AdditionalIncludeDirectories) + true + true + true + + + %(AdditionalLibraryDirectories) + Console + %(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + + + X64 + + + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(MONO_EGLIB_SOURCE_DIR);%(AdditionalIncludeDirectories) + Level4 + Disabled + $(ProjectDir)ep-tests-debug.h + + + %(AdditionalDependencies) + %(AdditionalLibraryDirectories) + Console + + + + + X64 + + + Level4 + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(MONO_EGLIB_SOURCE_DIR);%(AdditionalIncludeDirectories) + true + true + true + + + %(AdditionalLibraryDirectories) + Console + %(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + + + + \ No newline at end of file diff --git a/src/mono/mono/eventpipe/test/ep-test.vcxproj.filters b/src/mono/mono/eventpipe/test/ep-test.vcxproj.filters new file mode 100644 index 00000000000000..e9d41287b865a3 --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-test.vcxproj.filters @@ -0,0 +1,63 @@ + + + + + Source Files\tests + + + Source Files\tests + + + Source Files\tests + + + Source Files\tests + + + Source Files\tests + + + Source Files\tests + + + Source Files\tests + + + Source Files\tests + + + Source Files\testframework + + + Source Files\testframework + + + Source Files\testframework + + + + + {d0fb7679-6e47-42a8-bd98-9c31c4bb065a} + + + {ee850408-9c60-43ab-8845-133cdd03c67a} + + + {0bf8953c-e42a-464e-b422-a451238f319f} + + + {29232fda-0808-499c-9d29-f079a62967e7} + + + {e0fbc587-715b-4470-be21-7645cfe77e5a} + + + + + Header Files\tests + + + Header Files\tests + + + \ No newline at end of file diff --git a/src/mono/mono/eventpipe/test/ep-tests-debug.h b/src/mono/mono/eventpipe/test/ep-tests-debug.h new file mode 100644 index 00000000000000..e86795ea3ff5fe --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-tests-debug.h @@ -0,0 +1,8 @@ +#ifndef __EVENTPIPE_TESTS_DEBUG_H__ +#define __EVENTPIPE_TESTS_DEBUG_H__ + +#define _CRTDBG_MAP_ALLOC +#include +#include + +#endif /* __EVENTPIPE_TESTS_DEBUG_H__ */ diff --git a/src/mono/mono/eventpipe/test/ep-tests.c b/src/mono/mono/eventpipe/test/ep-tests.c new file mode 100644 index 00000000000000..2cc0ddb1bad87e --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-tests.c @@ -0,0 +1,399 @@ +#include "mono/eventpipe/ep.h" +#include "eglib/test/test.h" + +#define TEST_PROVIDER_NAME "MyTestProvider" +#define TEST_FILE "./ep_test_create_file.txt" + +#ifdef _CRTDBG_MAP_ALLOC +static _CrtMemState eventpipe_memory_start_snapshot; +static _CrtMemState eventpipe_memory_end_snapshot; +static _CrtMemState eventpipe_memory_diff_snapshot; +#endif + +static RESULT +test_eventpipe_setup (void) +{ +#ifdef _CRTDBG_MAP_ALLOC + _CrtMemCheckpoint (&eventpipe_memory_start_snapshot); +#endif + return NULL; +} + +static RESULT +test_create_delete_provider (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeProvider *test_provider = ep_create_provider (TEST_PROVIDER_NAME, NULL, NULL); + if (!test_provider) { + result = FAILED ("Failed to create provider %s, ep_create_provider returned NULL", TEST_PROVIDER_NAME); + ep_raise_error (); + } + +ep_on_exit: + ep_delete_provider (test_provider); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_stress_create_delete_provider (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeProvider *test_providers [1000] = {0}; + + for (uint32_t i = 0; i < 1000; ++i) { + char *provider_name = g_strdup_printf (TEST_PROVIDER_NAME "_%i", i); + test_providers [i] = ep_create_provider (provider_name, NULL, NULL); + g_free (provider_name); + + if (!test_providers [i]) { + result = FAILED ("Failed to create provider %s_%i, ep_create_provider returned NULL", TEST_PROVIDER_NAME, i); + ep_raise_error (); + } + } + +ep_on_exit: + for (uint32_t i = 0; i < 1000; ++i) { + if (test_providers [i]) + ep_delete_provider (test_providers [i]); + } + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_get_provider (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeProvider *test_provider = ep_create_provider (TEST_PROVIDER_NAME, NULL, NULL); + if (!test_provider) { + result = FAILED ("Failed to create provider %s, ep_create_provider returned NULL", TEST_PROVIDER_NAME); + ep_raise_error (); + } + + test_location = 1; + + EventPipeProvider *returned_test_provider = ep_get_provider (TEST_PROVIDER_NAME); + if (!returned_test_provider) { + result = FAILED ("Failed to get provider %s, ep_get_provider returned NULL", TEST_PROVIDER_NAME); + ep_raise_error (); + } + + test_location = 2; + + ep_delete_provider (test_provider); + test_provider = NULL; + + returned_test_provider = ep_get_provider (TEST_PROVIDER_NAME); + if (returned_test_provider) { + result = FAILED ("Provider %s, still returned from ep_get_provider after deleted", TEST_PROVIDER_NAME); + ep_raise_error (); + } + +ep_on_exit: + ep_delete_provider (test_provider); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_create_same_provider_twice (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeProvider *test_provider = ep_create_provider (TEST_PROVIDER_NAME, NULL, NULL); + if (!test_provider) { + result = FAILED ("Failed to create provider %s, ep_create_provider returned NULL", TEST_PROVIDER_NAME); + ep_raise_error (); + } + + test_location = 1; + + EventPipeProvider *returned_test_provider = ep_get_provider (TEST_PROVIDER_NAME); + if (!returned_test_provider) { + result = FAILED ("Failed to get provider %s, ep_get_provider returned NULL", TEST_PROVIDER_NAME); + ep_raise_error (); + } + + test_location = 2; + + EventPipeProvider *test_provider2 = ep_create_provider (TEST_PROVIDER_NAME, NULL, NULL); + if (test_provider2) { + result = FAILED ("Creating an already existing provider %s, succeeded", TEST_PROVIDER_NAME); + ep_raise_error (); + } + + test_location = 3; + + returned_test_provider = ep_get_provider (TEST_PROVIDER_NAME); + if (!returned_test_provider) { + result = FAILED ("Failed to get provider %s, ep_get_provider returned NULL", TEST_PROVIDER_NAME); + ep_raise_error (); + } + +ep_on_exit: + ep_delete_provider (test_provider); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + + +static RESULT +test_enable_disable (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeSessionID session_id = 0; + EventPipeProviderConfiguration provider_config; + EventPipeProviderConfiguration *current_provider_config =ep_provider_config_init (&provider_config, TEST_PROVIDER_NAME, 1, EP_EVENT_LEVEL_LOG_ALWAYS, ""); + ep_raise_error_if_nok (current_provider_config != NULL); + + test_location = 1; + + session_id = ep_enable ( + TEST_FILE, + 1, + current_provider_config, + 1, + EP_SESSION_TYPE_FILE, + EP_SERIALIZATION_FORMAT_NETTRACE_V4, + false, + NULL, + false); + + if (!session_id) { + result = FAILED ("Failed to enable session"); + ep_raise_error (); + } + + test_location = 2; + + if (!ep_enabled ()) { + result = FAILED ("event pipe disabled"); + ep_raise_error (); + } + +ep_on_exit: + ep_disable (session_id); + ep_provider_config_fini (current_provider_config); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static bool provider_callback_data; + +static +void +provider_callback ( + const uint8_t *source_id, + unsigned long is_enabled, + uint8_t level, + uint64_t match_any_keywords, + uint64_t match_all_keywords, + EventFilterDescriptor *filter_data, + void *callback_context) +{ + *(bool *)callback_context = true; +} + +static RESULT +test_create_delete_provider_with_callback (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeSessionID session_id = 0; + EventPipeProvider *test_provider = NULL; + EventPipeProviderConfiguration provider_config; + + EventPipeProviderConfiguration *current_provider_config =ep_provider_config_init (&provider_config, TEST_PROVIDER_NAME, 1, EP_EVENT_LEVEL_LOG_ALWAYS, ""); + ep_raise_error_if_nok (current_provider_config != NULL); + + test_location = 1; + + session_id = ep_enable ( + TEST_FILE, + 1, + current_provider_config, + 1, + EP_SESSION_TYPE_FILE, + EP_SERIALIZATION_FORMAT_NETTRACE_V4, + false, + NULL, + false); + + if (!session_id) { + result = FAILED ("Failed to enable session"); + ep_raise_error (); + } + + test_location = 2; + + test_provider = ep_create_provider (TEST_PROVIDER_NAME, provider_callback, &provider_callback_data); + ep_raise_error_if_nok (test_provider != NULL); + + test_location = 3; + + if (!provider_callback_data) { + result = FAILED ("Provider callback not called"); + ep_raise_error (); + } + +ep_on_exit: + ep_delete_provider (test_provider); + ep_disable (session_id); + ep_provider_config_fini (current_provider_config); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_build_event_metadata (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeProvider *provider = NULL; + EventPipeEvent *ep_event = NULL; + EventPipeEventInstance *ep_event_instance = NULL; + EventPipeEventMetadataEvent *metadata_event = NULL; + + provider = ep_create_provider (TEST_PROVIDER_NAME, NULL, NULL); + ep_raise_error_if_nok (provider != NULL); + + test_location = 1; + + ep_event = ep_event_alloc (provider, 1, 1, 1, EP_EVENT_LEVEL_VERBOSE, false, NULL, 0); + ep_raise_error_if_nok (ep_event != NULL); + + test_location = 2; + + ep_event_instance = ep_event_instance_alloc (ep_event, 0, 0, NULL, 0, NULL, NULL); + ep_raise_error_if_nok (ep_event_instance != NULL); + + test_location = 3; + + metadata_event = ep_build_event_metadata_event (ep_event_instance, 1); + ep_raise_error_if_nok (metadata_event != NULL); + + test_location = 4; + +ep_on_exit: + ep_delete_provider (provider); + ep_event_free (ep_event); + ep_event_instance_free (ep_event_instance); + ep_event_metdata_event_free (metadata_event); + + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_start_session_streaming (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeSessionID session_id = 0; + EventPipeProviderConfiguration provider_config; + + EventPipeProviderConfiguration *current_provider_config =ep_provider_config_init (&provider_config, TEST_PROVIDER_NAME, 1, EP_EVENT_LEVEL_LOG_ALWAYS, ""); + ep_raise_error_if_nok (current_provider_config != NULL); + + test_location = 1; + + session_id = ep_enable ( + TEST_FILE, + 1, + current_provider_config, + 1, + EP_SESSION_TYPE_FILE, + EP_SERIALIZATION_FORMAT_NETTRACE_V4, + false, + NULL, + false); + + if (!session_id) { + result = FAILED ("Failed to enable session"); + ep_raise_error (); + } + + test_location = 2; + + ep_start_streaming (session_id); + +ep_on_exit: + ep_disable (session_id); + ep_provider_config_fini (current_provider_config); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_eventpipe_teardown (void) +{ +#ifdef _CRTDBG_MAP_ALLOC + _CrtMemCheckpoint (&eventpipe_memory_end_snapshot); + if ( _CrtMemDifference( &eventpipe_memory_diff_snapshot, &eventpipe_memory_start_snapshot, &eventpipe_memory_end_snapshot) ) { + _CrtMemDumpStatistics( &eventpipe_memory_diff_snapshot ); + return FAILED ("Memory leak detected!"); + } +#endif + return NULL; +} + +static Test ep_tests [] = { + {"test_eventpipe_setup", test_eventpipe_setup}, + {"test_create_delete_provider", test_create_delete_provider}, + {"test_stress_create_delete_provider", test_stress_create_delete_provider}, + {"test_get_provider", test_get_provider}, + {"test_create_same_provider_twice", test_create_same_provider_twice}, + {"test_enable_disable", test_enable_disable}, + {"test_create_delete_provider_with_callback", test_create_delete_provider_with_callback}, + {"test_build_event_metadata", test_build_event_metadata}, + {"test_start_session_streaming", test_start_session_streaming}, + {"test_eventpipe_teardown", test_eventpipe_teardown}, + {NULL, NULL} +}; + +DEFINE_TEST_GROUP_INIT(ep_tests_init, ep_tests) diff --git a/src/mono/mono/eventpipe/test/ep-tests.h b/src/mono/mono/eventpipe/test/ep-tests.h new file mode 100644 index 00000000000000..c8e56be313a6e4 --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-tests.h @@ -0,0 +1,30 @@ +#ifndef _EVENTPIPE_TESTS_H +#define _EVENTPIPE_TESTS_H + +#include "eglib/test/test.h" + +DEFINE_TEST_GROUP_INIT_H(ep_setup_tests_init); +DEFINE_TEST_GROUP_INIT_H(ep_fastserializer_tests_init); +DEFINE_TEST_GROUP_INIT_H(ep_provider_callback_data_queue_tests_init); +DEFINE_TEST_GROUP_INIT_H(ep_file_tests_init); +DEFINE_TEST_GROUP_INIT_H(ep_session_tests_init); +DEFINE_TEST_GROUP_INIT_H(ep_thread_tests_init); +DEFINE_TEST_GROUP_INIT_H(ep_tests_init); +DEFINE_TEST_GROUP_INIT_H(fake_tests_init); +DEFINE_TEST_GROUP_INIT_H(ep_teardown_tests_init); + +const +static Group test_groups [] = { + {"setup", ep_setup_tests_init}, + {"fastserialzier", ep_fastserializer_tests_init}, + {"provider-callback-dataqueue", ep_provider_callback_data_queue_tests_init}, + {"file", ep_file_tests_init}, + {"session", ep_session_tests_init}, + {"thread", ep_thread_tests_init}, + {"eventpipe", ep_tests_init}, + {"fake", fake_tests_init}, + {"teardown", ep_teardown_tests_init}, + {NULL, NULL} +}; + +#endif /* _EVENTPIPE_TESTS_H */ diff --git a/src/mono/mono/eventpipe/test/ep-thread-tests.c b/src/mono/mono/eventpipe/test/ep-thread-tests.c new file mode 100644 index 00000000000000..9f68befe532a03 --- /dev/null +++ b/src/mono/mono/eventpipe/test/ep-thread-tests.c @@ -0,0 +1,478 @@ +#include "mono/eventpipe/ep.h" +#include "eglib/test/test.h" + +#define TEST_FILE "./ep_test_create_file.txt" + +#ifdef _CRTDBG_MAP_ALLOC +static _CrtMemState eventpipe_memory_start_snapshot; +static _CrtMemState eventpipe_memory_end_snapshot; +static _CrtMemState eventpipe_memory_diff_snapshot; +#endif + +static RESULT +test_thread_setup (void) +{ +#ifdef _CRTDBG_MAP_ALLOC + _CrtMemCheckpoint (&eventpipe_memory_start_snapshot); +#endif + return NULL; +} + +static RESULT +test_create_free_thread (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeThread *thread = ep_thread_alloc (); + if (!thread) { + result = FAILED ("Failed to create thread"); + ep_raise_error (); + } + +ep_on_exit: + ep_thread_free (thread); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_addref_release_thread (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeThread *thread = ep_thread_alloc (); + if (!thread) { + result = FAILED ("Failed to create thread"); + ep_raise_error (); + } + + test_location = 1; + + if (ep_rt_volatile_load_uint32_t ((const volatile uint32_t *)ep_thread_get_ref_count_ref (thread)) != 0) { + result = FAILED ("Ref count should start at 0"); + ep_raise_error (); + } + + test_location = 2; + + ep_thread_addref (thread); + + if (ep_rt_volatile_load_uint32_t ((const volatile uint32_t *)ep_thread_get_ref_count_ref (thread)) != 1) { + result = FAILED ("addref should increment 1"); + ep_raise_error (); + } + + test_location = 3; + + ep_thread_release (thread); + thread = NULL; + +ep_on_exit: + ep_thread_free (thread); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_get_or_create_thread (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeThread *thread = ep_thread_get (); + if (thread) { + result = FAILED ("ep_thread_get should return NULL"); + ep_raise_error (); + } + + test_location = 1; + + thread = ep_thread_get_or_create (); + if (!thread) { + result = FAILED ("ep_thread_get_or_create should not return NULL"); + ep_raise_error (); + } + + test_location = 2; + + thread = ep_thread_get (); + if (!thread) { + result = FAILED ("ep_thread_get should not return NULL"); + ep_raise_error (); + } + + test_location = 3; + + if (ep_rt_volatile_load_uint32_t ((const volatile uint32_t *)ep_thread_get_ref_count_ref (thread)) != 1) { + result = FAILED ("thread ref count should be 1"); + ep_raise_error (); + } + + test_location = 4; + + // Need to emulate a thread exit to make sure TLS gets cleaned up for current thread + // or we will get memory leaks reported. + ep_rt_mono_thread_exited (); + + thread = ep_thread_get (); + if (thread) { + result = FAILED ("ep_thread_get should return NULL"); + ep_raise_error (); + } + +ep_on_exit: + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_thread_activity_id (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + uint8_t empty_id [EP_ACTIVITY_ID_SIZE] = {0}; + uint8_t current_activity_id [EP_ACTIVITY_ID_SIZE]; + uint8_t new_activity_id [EP_ACTIVITY_ID_SIZE]; + + ep_thread_create_activity_id (new_activity_id, sizeof (new_activity_id)); + if (!memcmp (empty_id, new_activity_id, sizeof (new_activity_id))) { + result = FAILED ("Created activity id is empty"); + ep_raise_error (); + } + + test_location = 1; + + EventPipeThread *thread = ep_thread_get (); + if (thread) { + result = FAILED ("ep_thread_get should return NULL"); + ep_raise_error (); + } + + test_location = 2; + + thread = ep_thread_get_or_create (); + if (!thread) { + result = FAILED ("ep_thread_get_or_create should not return NULL"); + ep_raise_error (); + } + + test_location = 3; + + ep_thread_get_activity_id (thread, current_activity_id, sizeof (current_activity_id)); + if (memcmp (empty_id, current_activity_id, sizeof (current_activity_id))) { + result = FAILED ("Current activity id is not empty"); + ep_raise_error (); + } + + test_location = 4; + + ep_thread_set_activity_id (thread, new_activity_id, sizeof (new_activity_id)); + + ep_thread_get_activity_id (thread, current_activity_id, sizeof (current_activity_id)); + if (memcmp (new_activity_id, current_activity_id, sizeof (current_activity_id))) { + result = FAILED ("Current activity id doesn't match previously set activity id"); + ep_raise_error (); + } + + test_location = 5; + + // Need to emulate a thread exit to make sure TLS gets cleaned up for current thread + // or we will get memory leaks reported. + ep_rt_mono_thread_exited (); + + thread = ep_thread_get (); + if (thread) { + result = FAILED ("ep_thread_get should return NULL"); + ep_raise_error (); + } + +ep_on_exit: + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_thread_is_rundown_thread (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeThread *thread = ep_thread_alloc (); + if (!thread) { + result = FAILED ("Failed to create thread"); + ep_raise_error (); + } + + test_location = 1; + + if (ep_thread_is_rundown_thread (thread)) { + result = FAILED ("Thread is a rundown thread"); + ep_raise_error (); + } + + test_location = 2; + + EventPipeSession dummy_session; + ep_thread_set_as_rundown_thread (thread, &dummy_session); + if (!ep_thread_is_rundown_thread (thread)) { + result = FAILED ("Thread is not a rundown thread"); + ep_raise_error (); + } + + test_location = 3; + + if (ep_thread_get_rundown_session (thread) != &dummy_session) { + result = FAILED ("Unexpected rundown session"); + ep_raise_error (); + } + + test_location = 4; + + ep_thread_set_as_rundown_thread (thread, NULL); + + if (ep_thread_is_rundown_thread (thread)) { + result = FAILED ("Thread is a rundown thread"); + ep_raise_error (); + } + +ep_on_exit: + ep_thread_free (thread); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_thread_lock (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeThread *thread = ep_thread_alloc (); + if (!thread) { + result = FAILED ("Failed to create thread"); + ep_raise_error (); + } + + test_location = 1; + + ep_thread_requires_lock_not_held (thread); + + ep_rt_spin_lock_aquire (ep_thread_get_rt_lock_ref (thread)); + + ep_thread_requires_lock_held (thread); + + ep_rt_spin_lock_release (ep_thread_get_rt_lock_ref (thread)); + + ep_thread_requires_lock_not_held (thread); + +ep_on_exit: + ep_thread_free (thread); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_thread_session_write (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + + EventPipeThread *thread = ep_thread_alloc (); + if (!thread) { + result = FAILED ("Failed to create thread"); + ep_raise_error (); + } + + test_location = 1; + + uint32_t session_write = ep_thread_get_session_write_in_progress (thread); + if (session_write) { + result = FAILED ("Session write is in progress"); + ep_raise_error (); + } + + test_location = 2; + + ep_thread_set_session_write_in_progress (thread, 1); + + session_write = ep_thread_get_session_write_in_progress (thread); + if (session_write != 1) { + result = FAILED ("Wrong session id in write progress"); + ep_raise_error (); + } + + test_location = 3; + + ep_thread_set_session_write_in_progress (thread, 0); + + session_write = ep_thread_get_session_write_in_progress (thread); + if (session_write) { + result = FAILED ("Session write is in progress"); + ep_raise_error (); + } + +ep_on_exit: + ep_thread_free (thread); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_thread_session_state (void) +{ + RESULT result = NULL; + uint32_t test_location = 0; + EventPipeThread *thread = NULL; + EventPipeProviderConfiguration *provider_config = NULL; + EventPipeSession *session = NULL; + EventPipeThreadSessionState *session_state = NULL; + + thread = ep_thread_alloc (); + if (!thread) { + result = FAILED ("Failed to create thread"); + ep_raise_error (); + } + + ep_thread_addref (thread); + + test_location = 1; + + { + EventPipeProviderConfiguration dummy_config; + if (!ep_provider_config_init (&dummy_config, "DummyProvider", 0, 0, "")) { + result = FAILED ("Failed to init provider config"); + ep_raise_error (); + } + provider_config = &dummy_config; + } + + test_location = 2; + + EP_CONFIG_LOCK_ENTER + session = ep_session_alloc ( + 1, + TEST_FILE, + NULL, + EP_SESSION_TYPE_FILE, + EP_SERIALIZATION_FORMAT_NETTRACE_V4, + false, + 1, + provider_config, + 1, + false); + EP_CONFIG_LOCK_EXIT + + if (!session) { + result = FAILED ("Failed to alloc session"); + ep_raise_error (); + } + + test_location = 3; + + ep_rt_spin_lock_aquire (ep_thread_get_rt_lock_ref (thread)); + session_state = ep_thread_get_or_create_session_state (thread, session); + ep_rt_spin_lock_release (ep_thread_get_rt_lock_ref (thread)); + + if (!session_state) { + result = FAILED ("Failed to alloc session state"); + ep_raise_error (); + } + + test_location = 4; + + ep_rt_spin_lock_aquire (ep_thread_get_rt_lock_ref (thread)); + EventPipeThreadSessionState *current_session_state = ep_thread_get_or_create_session_state (thread, session); + ep_rt_spin_lock_release (ep_thread_get_rt_lock_ref (thread)); + + if (current_session_state != session_state) { + result = FAILED ("Second call to get_or_create_session_state allocated new session_state"); + ep_raise_error (); + } + + test_location = 5; + + ep_rt_spin_lock_aquire (ep_thread_get_rt_lock_ref (thread)); + current_session_state = ep_thread_get_session_state (thread, session); + ep_rt_spin_lock_release (ep_thread_get_rt_lock_ref (thread)); + + if (current_session_state != session_state) { + result = FAILED ("Call to get_session_state allocated returned unexpected session"); + ep_raise_error (); + } + +ep_on_exit: + if (thread && session_state) { + ep_rt_spin_lock_aquire (ep_thread_get_rt_lock_ref (thread)); + ep_thread_delete_session_state (thread, session); + ep_rt_spin_lock_release (ep_thread_get_rt_lock_ref (thread)); + } + ep_session_free (session); + ep_provider_config_fini (provider_config); + ep_thread_release (thread); + return result; + +ep_on_error: + if (!result) + result = FAILED ("Failed at test location=%i", test_location); + ep_exit_error_handler (); +} + +static RESULT +test_thread_teardown (void) +{ +#ifdef _CRTDBG_MAP_ALLOC + _CrtMemCheckpoint (&eventpipe_memory_end_snapshot); + if ( _CrtMemDifference( &eventpipe_memory_diff_snapshot, &eventpipe_memory_start_snapshot, &eventpipe_memory_end_snapshot) ) { + _CrtMemDumpStatistics( &eventpipe_memory_diff_snapshot ); + return FAILED ("Memory leak detected!"); + } +#endif + return NULL; +} + +static Test ep_thread_tests [] = { + {"test_thread_setup", test_thread_setup}, + {"test_create_free_thread", test_create_free_thread}, + {"test_addref_release_thread", test_addref_release_thread}, + {"test_get_or_create_thread", test_get_or_create_thread}, + {"test_thread_activity_id", test_thread_activity_id}, + {"test_thread_is_rundown_thread", test_thread_is_rundown_thread}, + {"test_thread_lock", test_thread_lock}, + {"test_thread_session_write", test_thread_session_write}, + {"test_thread_session_state", test_thread_session_state}, + {"test_thread_teardown", test_thread_teardown}, + {NULL, NULL} +}; + +DEFINE_TEST_GROUP_INIT(ep_thread_tests_init, ep_thread_tests) diff --git a/src/mono/mono/metadata/Makefile.am b/src/mono/mono/metadata/Makefile.am index 0415d87bee410c..d9ad09f5cca39d 100644 --- a/src/mono/mono/metadata/Makefile.am +++ b/src/mono/mono/metadata/Makefile.am @@ -91,6 +91,10 @@ if !ENABLE_ILGEN ilgen_libraries = libmono-ilgen.la endif +if ENABLE_PERFTRACING +eventpipe_libs = $(top_builddir)/mono/eventpipe/libeventpipe.la +endif + BUNDLE_ZLIB_PATH=$(top_builddir)/mono/zlib/libz.la if HAVE_STATIC_ZLIB @@ -103,7 +107,7 @@ Z_LIBS=$(BUNDLE_ZLIB_PATH) endif endif -noinst_LTLIBRARIES = libmonoruntime-config.la $(support_libraries) $(boehm_libraries) $(sgen_libraries) +noinst_LTLIBRARIES = libmonoruntime-config.la $(support_libraries) $(boehm_libraries) $(sgen_libraries) $(shim_libraries) lib_LTLIBRARIES = $(icall_table_libraries) $(ilgen_libraries) @@ -136,6 +140,26 @@ libmonoruntime_support_la_SOURCES = support.c libmonoruntime_support_la_LDFLAGS = $(Z_LIBS) libmonoruntime_support_la_CFLAGS = $(filter-out @CXX_REMOVE_CFLAGS@, @CFLAGS@) @ZLIB_CFLAGS@ +if ENABLE_NETCORE +if HAVE_SYS_ICU +shim_libraries = libmonoruntime-shimglobalization.la + +nodist_libmonoruntime_shimglobalization_la_SOURCES = \ + @ICU_SHIM_PATH@/pal_calendarData.c \ + @ICU_SHIM_PATH@/pal_casing.c \ + @ICU_SHIM_PATH@/pal_collation.c \ + @ICU_SHIM_PATH@/pal_idna.c \ + @ICU_SHIM_PATH@/pal_locale.c \ + @ICU_SHIM_PATH@/pal_localeNumberData.c \ + @ICU_SHIM_PATH@/pal_localeStringData.c \ + @ICU_SHIM_PATH@/pal_normalization.c \ + @ICU_SHIM_PATH@/pal_timeZoneInfo.c \ + @ICU_SHIM_PATH@/pal_icushim.c + +libmonoruntime_shimglobalization_la_CFLAGS = @ICU_CFLAGS@ -I$(top_srcdir)/../libraries/Native/Unix/Common/ +endif +endif + # # This library contains the icall tables if the runtime was configured with --disable-icall-tables # @@ -149,7 +173,7 @@ if BITCODE if WASM libmono_icall_table_la_LIBADD = # empty to avoid duplicate symbols when enabling dynamic linking else -libmono_icall_table_la_LIBADD = $(glib_libs) ../utils/libmonoutils.la ../sgen/libmonosgen.la libmonoruntimesgen.la +libmono_icall_table_la_LIBADD = $(glib_libs) ../utils/libmonoutils.la ../sgen/libmonosgen.la $(eventpipe_libs) libmonoruntimesgen.la endif endif endif @@ -173,7 +197,7 @@ if BITCODE if WASM libmono_ilgen_la_LIBADD = # empty to avoid duplicate symbols when enabling dynamic linking else -libmono_ilgen_la_LIBADD = $(glib_libs) ../utils/libmonoutils.la ../sgen/libmonosgen.la libmonoruntimesgen.la +libmono_ilgen_la_LIBADD = $(glib_libs) ../utils/libmonoutils.la ../sgen/libmonosgen.la $(eventpipe_libs) libmonoruntimesgen.la endif endif endif @@ -240,6 +264,7 @@ common_sources = \ domain-internals.h \ environment.c \ environment.h \ + icall-eventpipe.c \ exception.c \ exception.h \ exception-internals.h \ @@ -424,12 +449,12 @@ if !ENABLE_MSVC_ONLY libmonoruntime_la_SOURCES = $(common_sources) $(icall_tables_sources) $(ilgen_sources) $(gc_dependent_sources) $(null_gc_sources) $(boehm_sources) # Add CXX_ADD_CFLAGS per-library until/unless https://github.com/dotnet/corefx/pull/31342. libmonoruntime_la_CFLAGS = $(BOEHM_DEFINES) @CXX_ADD_CFLAGS@ -libmonoruntime_la_LIBADD = libmonoruntime-config.la $(support_libraries) +libmonoruntime_la_LIBADD = libmonoruntime-config.la $(support_libraries) $(shim_libraries) libmonoruntimesgen_la_SOURCES = $(common_sources) $(icall_tables_sources) $(ilgen_sources) $(gc_dependent_sources) $(sgen_sources) # Add CXX_ADD_CFLAGS per-library until/unless https://github.com/dotnet/corefx/pull/31342. libmonoruntimesgen_la_CFLAGS = $(SGEN_DEFINES) @CXX_ADD_CFLAGS@ -libmonoruntimesgen_la_LIBADD = libmonoruntime-config.la $(support_libraries) +libmonoruntimesgen_la_LIBADD = libmonoruntime-config.la $(support_libraries) $(shim_libraries) endif # !ENABLE_MSVC_ONLY diff --git a/src/mono/mono/metadata/assembly-load-context.c b/src/mono/mono/metadata/assembly-load-context.c index 017c62bf83b8c8..7aa927d21af219 100644 --- a/src/mono/mono/metadata/assembly-load-context.c +++ b/src/mono/mono/metadata/assembly-load-context.c @@ -9,6 +9,7 @@ #include "mono/metadata/icall-decl.h" #include "mono/metadata/loader-internals.h" #include "mono/metadata/loaded-images-internals.h" +#include "mono/metadata/mono-private-unstable.h" #include "mono/utils/mono-error-internals.h" #include "mono/utils/mono-logger-internals.h" @@ -172,6 +173,21 @@ mono_alc_is_default (MonoAssemblyLoadContext *alc) return alc == mono_alc_domain (alc)->default_alc; } +MonoAssemblyLoadContext * +mono_alc_from_gchandle (MonoGCHandle alc_gchandle) +{ + MonoManagedAssemblyLoadContextHandle managed_alc = MONO_HANDLE_CAST (MonoManagedAssemblyLoadContext, mono_gchandle_get_target_handle (alc_gchandle)); + MonoAssemblyLoadContext *alc = (MonoAssemblyLoadContext *)MONO_HANDLE_GETVAL (managed_alc, native_assembly_load_context); + return alc; +} + +MonoGCHandle +mono_alc_get_default_gchandle (void) +{ + // Because the default domain is never unloadable, this should be a strong handle and never change + return mono_domain_default_alc (mono_domain_get ())->gchandle; +} + static MonoAssembly* invoke_resolve_method (MonoMethod *resolve_method, MonoAssemblyLoadContext *alc, MonoAssemblyName *aname, MonoError *error) { diff --git a/src/mono/mono/metadata/assembly.c b/src/mono/mono/metadata/assembly.c index 0dca99f38b23f1..a62a0fe9692899 100644 --- a/src/mono/mono/metadata/assembly.c +++ b/src/mono/mono/metadata/assembly.c @@ -45,6 +45,7 @@ #include #include #include +#include #ifndef HOST_WIN32 #include @@ -2161,8 +2162,9 @@ typedef struct AssemblyPreLoadHook AssemblyPreLoadHook; struct AssemblyPreLoadHook { AssemblyPreLoadHook *next; union { - MonoAssemblyPreLoadFunc v1; - MonoAssemblyPreLoadFuncV2 v2; + MonoAssemblyPreLoadFunc v1; // legacy internal use + MonoAssemblyPreLoadFuncV2 v2; // current internal use + MonoAssemblyPreLoadFuncV3 v3; // netcore external use } func; gpointer user_data; gint32 version; @@ -2182,8 +2184,18 @@ invoke_assembly_preload_hook (MonoAssemblyLoadContext *alc, MonoAssemblyName *an assembly = hook->func.v1 (aname, apath, hook->user_data); else { ERROR_DECL (error); - g_assert (hook->version == 2); - assembly = hook->func.v2 (alc, aname, apath, FALSE, hook->user_data, error); + g_assert (hook->version == 2 || hook->version == 3); + if (hook->version == 2) + assembly = hook->func.v2 (alc, aname, apath, FALSE, hook->user_data, error); + else { // v3 +#ifdef ENABLE_NETCORE + MonoGCHandle strong_gchandle = mono_gchandle_from_handle (mono_gchandle_get_target_handle (alc->gchandle), TRUE); + assembly = hook->func.v3 (strong_gchandle, aname, apath, hook->user_data, error); + mono_gchandle_free_internal (strong_gchandle); +#else + assembly = hook->func.v3 (NULL, aname, apath, hook->user_data, error); +#endif + } /* TODO: propagage error out to callers */ mono_error_assert_ok (error); } @@ -2278,6 +2290,29 @@ mono_install_assembly_preload_hook_v2 (MonoAssemblyPreLoadFuncV2 func, gpointer } } +void +mono_install_assembly_preload_hook_v3 (MonoAssemblyPreLoadFuncV3 func, gpointer user_data, gboolean append) +{ + AssemblyPreLoadHook *hook; + + g_return_if_fail (func != NULL); + + hook = g_new0 (AssemblyPreLoadHook, 1); + hook->version = 3; + hook->func.v3 = func; + hook->user_data = user_data; + + if (append && assembly_preload_hook != NULL) { + AssemblyPreLoadHook *old = assembly_preload_hook; + while (old->next != NULL) + old = old->next; + old->next = hook; + } else { + hook->next = assembly_preload_hook; + assembly_preload_hook = hook; + } +} + static void free_assembly_preload_hooks (void) { @@ -4806,9 +4841,8 @@ mono_assembly_request_byname (MonoAssemblyName *aname, const MonoAssemblyByNameR result = prevent_reference_assembly_from_running (result, refonly); } #else - result = netcore_load_reference (aname, req->request.alc, req->requesting_assembly, !req->no_postload_search); - - if (!result && bundles != NULL) { + result = NULL; + if (bundles != NULL) { MonoImageOpenStatus status; MonoImage *image; image = mono_assembly_open_from_bundle (req->request.alc, aname->name, &status, FALSE); @@ -4819,10 +4853,31 @@ mono_assembly_request_byname (MonoAssemblyName *aname, const MonoAssemblyByNameR if (image) result = mono_assembly_request_load_from (image, aname->name, &req->request, &status); } + if (!result) + result = netcore_load_reference (aname, req->request.alc, req->requesting_assembly, !req->no_postload_search); #endif return result; } +MonoAssembly * +mono_assembly_load_full_alc (MonoGCHandle alc_gchandle, MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status) +{ + MonoAssembly *res; + MONO_ENTER_GC_UNSAFE; + MonoAssemblyByNameRequest req; +#ifdef ENABLE_NETCORE + MonoAssemblyLoadContext *alc = mono_alc_from_gchandle (alc_gchandle); +#else + MonoAssemblyLoadContext *alc = mono_domain_default_alc (mono_domain_get ()); +#endif + mono_assembly_request_prepare_byname (&req, MONO_ASMCTX_DEFAULT, alc); + req.requesting_assembly = NULL; + req.basedir = basedir; + res = mono_assembly_request_byname (aname, &req, status); + MONO_EXIT_GC_UNSAFE; + return res; +} + /** * mono_assembly_load_full: * \param aname A MonoAssemblyName with the assembly name to load. diff --git a/src/mono/mono/metadata/class-init.c b/src/mono/mono/metadata/class-init.c index 748a64d6116f68..5dc2e54c72a97f 100644 --- a/src/mono/mono/metadata/class-init.c +++ b/src/mono/mono/metadata/class-init.c @@ -33,7 +33,6 @@ #undef REALLY_INCLUDE_CLASS_DEF #endif - gboolean mono_print_vtable = FALSE; gboolean mono_align_small_structs = FALSE; #ifdef ENABLE_NETCORE @@ -3800,8 +3799,6 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ } break; case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: { - guint8 *ref_bitmap; - real_size = 0; for (i = 0; i < top; i++) { gint32 align; @@ -3846,40 +3843,35 @@ mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_ real_size = MAX (real_size, size + field_offsets [i]); } - if (klass->has_references) { - ref_bitmap = g_new0 (guint8, real_size / TARGET_SIZEOF_VOID_P); - - /* Check for overlapping reference and non-reference fields */ - for (i = 0; i < top; i++) { - MonoType *ftype; - + /* check for incorrectly aligned or overlapped by a non-object field */ +#ifdef ENABLE_NETCORE + guint8 *layout_check; + if (has_references) { + layout_check = g_new0 (guint8, real_size); + for (i = 0; i < top && !mono_class_has_failure (klass); i++) { field = &klass->fields [i]; - - if (mono_field_is_deleted (field)) - continue; - if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) + if (!field) continue; - ftype = mono_type_get_underlying_type (field->type); - if (MONO_TYPE_IS_REFERENCE (ftype)) - ref_bitmap [field_offsets [i] / TARGET_SIZEOF_VOID_P] = 1; - } - for (i = 0; i < top; i++) { - field = &klass->fields [i]; - if (mono_field_is_deleted (field)) continue; if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) continue; - - // FIXME: Too much code does this -#if 0 - if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / TARGET_SIZEOF_VOID_P]) { - mono_class_set_type_load_failure (klass, "Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass->name, field_offsets [i]); + int align = 0; + int size = mono_type_size (field->type, &align); + MonoType *ftype = mono_type_get_underlying_type (field->type); + ftype = mono_type_get_basic_type_from_generic (ftype); + guint8 type = type_has_references (klass, ftype) ? 1 : 2; + for (int j = 0; j < size; j++) { + if (layout_check [field_offsets [i] + j] != 0 && layout_check [field_offsets [i] + j] != type) { + mono_class_set_type_load_failure (klass, "Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass->name, field->offset); + break; + } + layout_check [field_offsets [i] + j] = type; } -#endif } - g_free (ref_bitmap); + g_free (layout_check); } +#endif instance_size = MAX (real_size, instance_size); if (!((layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && explicit_size)) { @@ -4237,6 +4229,48 @@ generic_array_methods (MonoClass *klass) return generic_array_method_num; } +static int array_get_method_count (MonoClass *klass) +{ + MonoType *klass_byval_arg = m_class_get_byval_arg (klass); + if (klass_byval_arg->type == MONO_TYPE_ARRAY) + /* Regular array */ + /* ctor([int32]*rank) */ + /* ctor([int32]*rank*2) */ + /* Get */ + /* Set */ + /* Address */ + return 5; + else if (klass_byval_arg->type == MONO_TYPE_SZARRAY && klass->rank == 1 && klass->element_class->rank) + /* Jagged arrays are typed as MONO_TYPE_SZARRAY but have an extra ctor in .net which creates an array of arrays */ + /* ctor([int32]) */ + /* ctor([int32], [int32]) */ + /* Get */ + /* Set */ + /* Address */ + return 5; + else + /* Vectors don't have additional constructor since a zero lower bound is assumed */ + /* ctor([int32]*rank) */ + /* Get */ + /* Set */ + /* Address */ + return 4; +} + +static gboolean array_supports_additional_ctor_method (MonoClass *klass) +{ + MonoType *klass_byval_arg = m_class_get_byval_arg (klass); + if (klass_byval_arg->type == MONO_TYPE_ARRAY) + /* Regular array */ + return TRUE; + else if (klass_byval_arg->type == MONO_TYPE_SZARRAY && klass->rank == 1 && klass->element_class->rank) + /* Jagged array */ + return TRUE; + else + /* Vector */ + return FALSE; +} + /* * Global pool of interface IDs, represented as a bitset. * LOCKING: Protected by the classes lock. @@ -4522,7 +4556,7 @@ mono_class_init_internal (MonoClass *klass) } if (klass->rank) { - array_method_count = 3 + (klass->rank > 1? 2: 1); + array_method_count = array_get_method_count (klass); if (klass->interface_count) { int count_generic = generic_array_methods (klass); @@ -4951,18 +4985,12 @@ mono_class_setup_methods (MonoClass *klass) MonoMethodSignature *sig; int count_generic = 0, first_generic = 0; int method_num = 0; - gboolean jagged_ctor = FALSE; - count = 3 + (klass->rank > 1? 2: 1); + count = array_get_method_count (klass); mono_class_setup_interfaces (klass, error); g_assert (is_ok (error)); /*FIXME can this fail for array types?*/ - if (klass->rank == 1 && klass->element_class->rank) { - jagged_ctor = TRUE; - count ++; - } - if (klass->interface_count) { count_generic = generic_array_methods (klass); first_generic = count; @@ -4980,7 +5008,8 @@ mono_class_setup_methods (MonoClass *klass) amethod = create_array_method (klass, ".ctor", sig); methods [method_num++] = amethod; - if (klass->rank > 1) { + + if (array_supports_additional_ctor_method (klass)) { sig = mono_metadata_signature_alloc (klass->image, klass->rank * 2); sig->ret = mono_get_void_type (); sig->pinvoke = TRUE; @@ -4992,18 +5021,6 @@ mono_class_setup_methods (MonoClass *klass) methods [method_num++] = amethod; } - if (jagged_ctor) { - /* Jagged arrays have an extra ctor in .net which creates an array of arrays */ - sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1); - sig->ret = mono_get_void_type (); - sig->pinvoke = TRUE; - sig->hasthis = TRUE; - for (i = 0; i < klass->rank + 1; ++i) - sig->params [i] = mono_get_int32_type (); - amethod = create_array_method (klass, ".ctor", sig); - methods [method_num++] = amethod; - } - /* element Get (idx11, [idx2, ...]) */ sig = mono_metadata_signature_alloc (klass->image, klass->rank); sig->ret = m_class_get_byval_arg (m_class_get_element_class (klass)); diff --git a/src/mono/mono/metadata/class-internals.h b/src/mono/mono/metadata/class-internals.h index d503e3e5c0b07d..f00ea0345beebe 100644 --- a/src/mono/mono/metadata/class-internals.h +++ b/src/mono/mono/metadata/class-internals.h @@ -828,9 +828,6 @@ mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext * gpointer mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean check_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error); -gpointer -mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error); - gpointer mono_runtime_create_delegate_trampoline (MonoClass *klass); diff --git a/src/mono/mono/metadata/debug-mono-ppdb.c b/src/mono/mono/metadata/debug-mono-ppdb.c index 64dcadefc0a99f..a5634f6c1e4cd0 100644 --- a/src/mono/mono/metadata/debug-mono-ppdb.c +++ b/src/mono/mono/metadata/debug-mono-ppdb.c @@ -87,40 +87,52 @@ get_pe_debug_info (MonoImage *image, guint8 *out_guid, gint32 *out_age, gint32 * int *ppdb_uncompressed_size, int *ppdb_compressed_size) { MonoPEDirEntry *debug_dir_entry; - ImageDebugDirectory *debug_dir; + ImageDebugDirectory debug_dir; int idx; gboolean guid_found = FALSE; + guint8 *data; *ppdb_data = NULL; - debug_dir_entry = &image->image_info->cli_header.datadir.pe_debug; + debug_dir_entry = (MonoPEDirEntry *) &image->image_info->cli_header.datadir.pe_debug; if (!debug_dir_entry->size) return FALSE; int offset = mono_cli_rva_image_map (image, debug_dir_entry->rva); for (idx = 0; idx < debug_dir_entry->size / sizeof (ImageDebugDirectory); ++idx) { - debug_dir = (ImageDebugDirectory*)(image->raw_data + offset) + idx; - if (debug_dir->type == DEBUG_DIR_ENTRY_CODEVIEW && debug_dir->major_version == 0x100 && debug_dir->minor_version == 0x504d) { + data = (guint8 *) ((ImageDebugDirectory *) (image->raw_data + offset) + idx); + debug_dir.characteristics = read32(data); + debug_dir.time_date_stamp = read32(data + 4); + debug_dir.major_version = read16(data + 8); + debug_dir.minor_version = read16(data + 10); + debug_dir.type = read32(data + 12); + debug_dir.size_of_data = read32(data + 16); + debug_dir.address = read32(data + 20); + debug_dir.pointer = read32(data + 24); + + if (debug_dir.type == DEBUG_DIR_ENTRY_CODEVIEW && debug_dir.major_version == 0x100 && debug_dir.minor_version == 0x504d) { /* This is a 'CODEVIEW' debug directory */ - CodeviewDebugDirectory *dir = (CodeviewDebugDirectory*)(image->raw_data + debug_dir->pointer); - - if (dir->signature == 0x53445352) { - memcpy (out_guid, dir->guid, 16); - *out_age = dir->age; - *out_timestamp = debug_dir->time_date_stamp; + CodeviewDebugDirectory dir; + data = (guint8 *) (image->raw_data + debug_dir.pointer); + dir.signature = read32(data); + + if (dir.signature == 0x53445352) { + memcpy (out_guid, data + 4, 16); + *out_age = read32(data + 20); + *out_timestamp = debug_dir.time_date_stamp; guid_found = TRUE; } } - if (debug_dir->type == DEBUG_DIR_ENTRY_PPDB && debug_dir->major_version >= 0x100 && debug_dir->minor_version == 0x100) { + if (debug_dir.type == DEBUG_DIR_ENTRY_PPDB && debug_dir.major_version >= 0x100 && debug_dir.minor_version == 0x100) { /* Embedded PPDB blob */ /* See src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.EmbeddedPortablePdb.cs in corefx */ - guint8 *data = (guint8*)(image->raw_data + debug_dir->pointer); + data = (guint8*)(image->raw_data + debug_dir.pointer); guint32 magic = read32 (data); g_assert (magic == EMBEDDED_PPDB_MAGIC); guint32 size = read32 (data + 4); *ppdb_data = data + 8; *ppdb_uncompressed_size = size; - *ppdb_compressed_size = debug_dir->size_of_data - 8; + *ppdb_compressed_size = debug_dir.size_of_data - 8; } } return guid_found; @@ -156,7 +168,7 @@ mono_ppdb_load_file (MonoImage *image, const guint8 *raw_contents, int size) MonoImageOpenStatus status; guint8 pe_guid [16]; gint32 pe_age; - gint32 pe_timestamp; + gint32 pe_timestamp, pdb_timestamp; guint8 *ppdb_data = NULL; guint8 *to_free = NULL; int ppdb_size = 0, ppdb_compressed_size = 0; @@ -230,7 +242,8 @@ mono_ppdb_load_file (MonoImage *image, const guint8 *raw_contents, int size) g_assert (pdb_stream); /* The pdb id is a concentation of the pe guid and the timestamp */ - if (memcmp (pe_guid, pdb_stream->guid, 16) != 0 || memcmp (&pe_timestamp, pdb_stream->guid + 16, 4) != 0) { + pdb_timestamp = read32(pdb_stream->guid + 16); + if (memcmp (pe_guid, pdb_stream->guid, 16) != 0 || pe_timestamp != pdb_timestamp) { g_warning ("Symbol file %s doesn't match image %s", ppdb_image->name, image->name); mono_image_close (ppdb_image); @@ -484,7 +497,7 @@ mono_ppdb_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrAr if (source_files) sindexes = g_ptr_array_new (); - if (!method->token) + if (!method->token || tables [MONO_TABLE_METHODBODY].rows == 0) return; method_idx = mono_metadata_token_index (method->token); diff --git a/src/mono/mono/metadata/exception.c b/src/mono/mono/metadata/exception.c index 400895d8909458..2f298104945933 100644 --- a/src/mono/mono/metadata/exception.c +++ b/src/mono/mono/metadata/exception.c @@ -200,6 +200,7 @@ create_exception_two_strings (MonoClass *klass, MonoStringHandle a1, MonoStringH method = m; break; } + g_assert (method); gpointer args [ ] = { MONO_HANDLE_RAW (a1), MONO_HANDLE_RAW (a2) }; diff --git a/src/mono/mono/metadata/external-only.c b/src/mono/mono/metadata/external-only.c index 8e3c782080fee0..0ccb35a0facdb5 100644 --- a/src/mono/mono/metadata/external-only.c +++ b/src/mono/mono/metadata/external-only.c @@ -45,6 +45,12 @@ mono_gchandle_new (MonoObject *obj, mono_bool pinned) MONO_EXTERNAL_ONLY_GC_UNSAFE (uint32_t, (uint32_t)(size_t)mono_gchandle_new_internal (obj, pinned)); } +MonoGCHandle +mono_gchandle_new_v2 (MonoObject *obj, mono_bool pinned) +{ + MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoGCHandle, mono_gchandle_new_internal (obj, pinned)); +} + /** * mono_gchandle_new_weakref: * \param obj managed object to get a handle for @@ -72,6 +78,12 @@ mono_gchandle_new_weakref (MonoObject *obj, mono_bool track_resurrection) MONO_EXTERNAL_ONLY_GC_UNSAFE (uint32_t, (uint32_t)(size_t)mono_gchandle_new_weakref_internal (obj, track_resurrection)); } +MonoGCHandle +mono_gchandle_new_weakref_v2 (MonoObject *obj, mono_bool track_resurrection) +{ + MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoGCHandle, mono_gchandle_new_weakref_internal (obj, track_resurrection)); +} + /** * mono_gchandle_get_target: * \param gchandle a GCHandle's handle. @@ -88,6 +100,12 @@ mono_gchandle_get_target (uint32_t gchandle) MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoObject*, mono_gchandle_get_target_internal ((MonoGCHandle)(size_t)gchandle)); } +MonoObject* +mono_gchandle_get_target_v2 (MonoGCHandle gchandle) +{ + MONO_EXTERNAL_ONLY_GC_UNSAFE (MonoObject*, mono_gchandle_get_target_internal (gchandle)); +} + /** * mono_gchandle_free: * \param gchandle a GCHandle's handle. @@ -107,6 +125,12 @@ mono_gchandle_free (uint32_t gchandle) MONO_EXTERNAL_ONLY_VOID (mono_gchandle_free_internal ((MonoGCHandle)(size_t)gchandle)); } +void +mono_gchandle_free_v2 (MonoGCHandle gchandle) +{ + MONO_EXTERNAL_ONLY_VOID (mono_gchandle_free_internal (gchandle)); +} + /* GC write barriers support */ /** diff --git a/src/mono/mono/metadata/icall-eventpipe.c b/src/mono/mono/metadata/icall-eventpipe.c new file mode 100644 index 00000000000000..9f64e90cc44dbe --- /dev/null +++ b/src/mono/mono/metadata/icall-eventpipe.c @@ -0,0 +1,489 @@ +#include +#include +#include + +#ifdef ENABLE_NETCORE +#include + +#ifdef ENABLE_PERFTRACING +#include +#include + +#include +#include +#include +#include +#include +#include + +typedef enum _EventPipeActivityControlCode { + EP_ACTIVITY_CONTROL_GET_ID = 1, + EP_ACTIVITY_CONTROL_SET_ID = 2, + EP_ACTIVITY_CONTROL_CREATE_ID = 3, + EP_ACTIVITY_CONTROL_GET_SET_ID = 4, + EP_ACTIVITY_CONTROL_CREATE_SET_ID = 5 +} EventPipeActivityControlCode; + +typedef struct _EventPipeProviderConfigurationNative { + gunichar2 *provider_name; + uint64_t keywords; + uint32_t logging_level; + gunichar2 *filter_data; +} EventPipeProviderConfigurationNative; + +typedef struct _EventProviderEventData { + uint64_t ptr; + uint32_t size; + uint32_t reserved; +} EventProviderEventData; + +typedef struct _EventPipeSessionInfo { + int64_t starttime_as_utc_filetime; + int64_t start_timestamp; + int64_t timestamp_frequency; +} EventPipeSessionInfo; + +typedef struct _EventPipeEventInstanceData { + intptr_t provider_id; + uint32_t event_id; + uint32_t thread_id; + int64_t timestamp; + uint8_t activity_id [EP_ACTIVITY_ID_SIZE]; + uint8_t related_activity_id [EP_ACTIVITY_ID_SIZE]; + const uint8_t *payload; + uint32_t payload_len; +} EventPipeEventInstanceData; + +gboolean ep_rt_mono_initialized; +MonoNativeTlsKey ep_rt_mono_thread_holder_tls_id; +gpointer ep_rt_mono_rand_provider; + +static ep_rt_thread_holder_alloc_func thread_holder_alloc_callback_func; +static ep_rt_thread_holder_free_func thread_holder_free_callback_func; + +void +mono_eventpipe_raise_thread_exited (uint64_t); + +static +gboolean +rand_try_get_bytes_func (guchar *buffer, gssize buffer_size, MonoError *error) +{ + g_assert (ep_rt_mono_rand_provider != NULL); + return mono_rand_try_get_bytes (&ep_rt_mono_rand_provider, buffer, buffer_size, error); +} + +static +EventPipeThread * +eventpipe_thread_get (void) +{ + EventPipeThreadHolder *thread_holder = mono_native_tls_get_value (ep_rt_mono_thread_holder_tls_id); + return thread_holder ? ep_thread_holder_get_thread (thread_holder) : NULL; +} + +static +EventPipeThread * +eventpipe_thread_get_or_create (void) +{ + EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (ep_rt_mono_thread_holder_tls_id); + if (!thread_holder && thread_holder_alloc_callback_func) { + thread_holder = thread_holder_alloc_callback_func (); + mono_native_tls_set_value (ep_rt_mono_thread_holder_tls_id, thread_holder); + } + return ep_thread_holder_get_thread (thread_holder); +} + +static +void +eventpipe_thread_exited (void) +{ + if (ep_rt_mono_initialized) { + EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (ep_rt_mono_thread_holder_tls_id); + if (thread_holder && thread_holder_free_callback_func) + thread_holder_free_callback_func (thread_holder); + mono_native_tls_set_value (ep_rt_mono_thread_holder_tls_id, NULL); + } +} + +static +void +profiler_eventpipe_thread_exited (MonoProfiler *prof, uintptr_t tid) +{ + eventpipe_thread_exited (); +} + +void +mono_eventpipe_init ( + EventPipeMonoFuncTable *table, + ep_rt_thread_holder_alloc_func thread_holder_alloc_func, + ep_rt_thread_holder_free_func thread_holder_free_func) +{ + g_assert (table != NULL); + table->ep_rt_mono_100ns_datetime = mono_100ns_datetime; + table->ep_rt_mono_100ns_ticks = mono_100ns_ticks; + table->ep_rt_mono_cpu_count = mono_cpu_count; + table->ep_rt_mono_process_current_pid = mono_process_current_pid; + table->ep_rt_mono_native_thread_id_get = mono_native_thread_id_get; + table->ep_rt_mono_native_thread_id_equals = mono_native_thread_id_equals; + table->ep_rt_mono_runtime_is_shutting_down = mono_runtime_is_shutting_down; + table->ep_rt_mono_rand_try_get_bytes = rand_try_get_bytes_func; + table->ep_rt_mono_thread_get = eventpipe_thread_get; + table->ep_rt_mono_thread_get_or_create = eventpipe_thread_get_or_create; + table->ep_rt_mono_thread_exited = eventpipe_thread_exited; + table->ep_rt_mono_w32file_close = mono_w32file_close; + table->ep_rt_mono_w32file_create = mono_w32file_create; + table->ep_rt_mono_w32file_write = mono_w32file_write; + + thread_holder_alloc_callback_func = thread_holder_alloc_func; + thread_holder_free_callback_func = thread_holder_free_func; + mono_native_tls_alloc (&ep_rt_mono_thread_holder_tls_id, NULL); + + mono_100ns_ticks (); + mono_rand_open (); + ep_rt_mono_rand_provider = mono_rand_init (NULL, 0); + + ep_rt_mono_initialized = TRUE; + + MonoProfilerHandle profiler = mono_profiler_create (NULL); + mono_profiler_set_thread_stopped_callback (profiler, profiler_eventpipe_thread_exited); +} + +void +mono_eventpipe_fini (void) +{ + if (ep_rt_mono_initialized) + mono_rand_close (ep_rt_mono_rand_provider); + + ep_rt_mono_rand_provider = NULL; + thread_holder_alloc_callback_func = NULL; + thread_holder_free_callback_func = NULL; + ep_rt_mono_initialized = FALSE; +} + +gconstpointer +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_CreateProvider ( + MonoStringHandle provider_name, + MonoDelegateHandle callback_func, + MonoError *error) +{ + EventPipeProvider *provider = NULL; + + if (MONO_HANDLE_IS_NULL (provider_name)) { + mono_error_set_argument_null (error, "providerName", ""); + return NULL; + } + + char *provider_name_utf8 = mono_string_handle_to_utf8 (provider_name, error); + + //TODO: Need to pin delegate if we switch to safe mode or maybe we should get funcptr in icall? + provider = ep_create_provider (provider_name_utf8, MONO_HANDLE_GETVAL (callback_func, delegate_trampoline), NULL); + + g_free (provider_name_utf8); + return provider; +} + +intptr_t +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_DefineEvent ( + intptr_t provider_handle, + uint32_t event_id, + int64_t keywords, + uint32_t event_version, + uint32_t level, + const uint8_t *metadata, + uint32_t metadata_len) +{ + g_assert (provider_handle != 0); + + EventPipeProvider *provider = (EventPipeProvider *)provider_handle; + EventPipeEvent *ep_event = ep_provider_add_event (provider, event_id, (uint64_t)keywords, event_version, (EventPipeEventLevel)level, /* needStack = */ true, metadata, metadata_len); + + g_assert (ep_event != NULL); + return (intptr_t)ep_event; +} + +void +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_DeleteProvider (intptr_t provider_handle) +{ + if (provider_handle) { + ep_delete_provider ((EventPipeProvider *)provider_handle); + } +} + +void +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_Disable (uint64_t session_id) +{ + ep_disable (session_id); +} + +uint64_t +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_Enable ( + const gunichar2 *output_file, + /* EventPipeSerializationFormat */int32_t format, + uint32_t circular_buffer_size_mb, + /* EventPipeProviderConfigurationNative[] */const void *providers, + uint32_t providers_len) +{ + ERROR_DECL (error); + EventPipeSessionID session_id = 0; + + if (circular_buffer_size_mb == 0 || format > EP_SERIALIZATION_FORMAT_COUNT || providers_len == 0 || providers == NULL) + return 0; + + char *output_file_utf8 = mono_utf16_to_utf8 (output_file, g_utf16_len (output_file), error); + + session_id = ep_enable ( + output_file_utf8, + circular_buffer_size_mb, + providers, + providers_len, + output_file != NULL ? EP_SESSION_TYPE_FILE : EP_SESSION_TYPE_LISTENER, + (EventPipeSerializationFormat)format, + true, + NULL, + true); + ep_start_streaming (session_id); + + g_free (output_file_utf8); + return session_id; +} + +int32_t +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_EventActivityIdControl ( + uint32_t control_code, + /* GUID * */uint8_t *activity_id) +{ + int32_t result = 0; + EventPipeThread *thread = ep_thread_get (); + + if (thread == NULL) + return 1; + + uint8_t current_activity_id [EP_ACTIVITY_ID_SIZE]; + EventPipeActivityControlCode activity_control_code = (EventPipeActivityControlCode)control_code; + switch (activity_control_code) { + case EP_ACTIVITY_CONTROL_GET_ID: + ep_thread_get_activity_id (thread, activity_id, EP_ACTIVITY_ID_SIZE); + break; + case EP_ACTIVITY_CONTROL_SET_ID: + ep_thread_set_activity_id (thread, activity_id, EP_ACTIVITY_ID_SIZE); + break; + case EP_ACTIVITY_CONTROL_CREATE_ID: + ep_thread_create_activity_id (activity_id, EP_ACTIVITY_ID_SIZE); + break; + case EP_ACTIVITY_CONTROL_GET_SET_ID: + ep_thread_get_activity_id (thread, activity_id, EP_ACTIVITY_ID_SIZE); + ep_thread_create_activity_id (current_activity_id, G_N_ELEMENTS (current_activity_id)); + ep_thread_set_activity_id (thread, current_activity_id, G_N_ELEMENTS (current_activity_id)); + break; + default: + result = 1; + break; + } + + return result; +} + +MonoBoolean +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetNextEvent ( + uint64_t session_id, + /* EventPipeEventInstanceData * */void *instance) +{ + g_assert (instance != NULL); + + EventPipeEventInstance *const next_instance = ep_get_next_event (session_id); + EventPipeEventInstanceData *const data = (EventPipeEventInstanceData *)instance; + if (next_instance && data) { + const EventPipeEvent *const ep_event = ep_event_instance_get_ep_event (next_instance); + if (ep_event) { + data->provider_id = (intptr_t)ep_event_get_provider (ep_event); + data->event_id = ep_event_get_event_id (ep_event); + } + data->thread_id = ep_event_instance_get_thread_id (next_instance); + data->timestamp = ep_event_instance_get_timestamp (next_instance); + memcpy (&data->activity_id, ep_event_instance_get_activity_id_cref (next_instance), EP_ACTIVITY_ID_SIZE); + memcpy (&data->related_activity_id, ep_event_instance_get_related_activity_id_cref (next_instance), EP_ACTIVITY_ID_SIZE); + data->payload = ep_event_instance_get_data (next_instance); + data->payload_len = ep_event_instance_get_data_len (next_instance); + } + + return next_instance != NULL; +} + +intptr_t +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetProvider (const gunichar2 *provider_name) +{ + ERROR_DECL (error); + char * provider_name_utf8 = NULL; + EventPipeProvider *provider = NULL; + + if (provider_name) { + provider_name_utf8 = mono_utf16_to_utf8 (provider_name, g_utf16_len (provider_name), error); + provider = ep_get_provider (provider_name_utf8); + } + + g_free (provider_name_utf8); + return (intptr_t)provider; +} + +MonoBoolean +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetSessionInfo ( + uint64_t session_id, + /* EventPipeSessionInfo * */void *session_info) +{ + bool result = false; + if (session_info) { + EventPipeSession *session = ep_get_session ((EventPipeSessionID)session_id); + if (session) { + EventPipeSessionInfo *instance = (EventPipeSessionInfo *)session_info; + instance->starttime_as_utc_filetime = ep_session_get_session_start_time (session); + instance->start_timestamp = ep_session_get_session_start_timestamp (session); + instance->timestamp_frequency = ep_perf_frequency_query (); + result = true; + } + } + + return result; +} + +intptr_t +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetWaitHandle (uint64_t session_id) +{ + return (intptr_t)ep_get_wait_handle (session_id); +} + +void +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_WriteEventData ( + intptr_t event_handle, + /* EventProviderEventData[] */const void *event_data, + uint32_t data_len, + /* GUID * */const uint8_t *activity_id, + /* GUID * */const uint8_t *related_activity_id) +{ + ; +} + +#else /* ENABLE_PERFTRACING */ + +gconstpointer +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_CreateProvider ( + MonoStringHandle provider_name, + MonoDelegateHandle callback_func, + MonoError *error) +{ + mono_error_set_not_implemented (error, "System.Diagnostics.Tracing.EventPipeInternal.CreateProvider"); + return NULL; +} + +intptr_t +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_DefineEvent ( + intptr_t provider_handle, + uint32_t event_id, + int64_t keywords, + uint32_t event_version, + uint32_t level, + const uint8_t *metadata, + uint32_t metadata_len) +{ + ERROR_DECL (error); + mono_error_set_not_implemented (error, "System.Diagnostics.Tracing.EventPipeInternal.DefineEvent"); + mono_error_set_pending_exception (error); + return 0; +} + +void +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_DeleteProvider (intptr_t provider_handle) +{ + ERROR_DECL (error); + mono_error_set_not_implemented (error, "System.Diagnostics.Tracing.EventPipeInternal.DeleteProvider"); + mono_error_set_pending_exception (error); +} + +void +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_Disable (uint64_t session_id) +{ + ERROR_DECL (error); + mono_error_set_not_implemented (error, "System.Diagnostics.Tracing.EventPipeInternal.Disable"); + mono_error_set_pending_exception (error); +} + +uint64_t +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_Enable ( + const gunichar2 *output_file, + /* EventPipeSerializationFormat */int32_t format, + uint32_t circular_buffer_size_mb, + /* EventPipeProviderConfigurationNative[] */const void *providers, + uint32_t providers_len) +{ + ERROR_DECL (error); + mono_error_set_not_implemented (error, "System.Diagnostics.Tracing.EventPipeInternal.Enable"); + mono_error_set_pending_exception (error); + return 0; +} + +int32_t +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_EventActivityIdControl ( + uint32_t control_code, + /* GUID * */uint8_t *activity_id) +{ + ERROR_DECL (error); + mono_error_set_not_implemented (error, "System.Diagnostics.Tracing.EventPipeInternal.EventActivityIdControl"); + mono_error_set_pending_exception (error); + return 0; +} + +MonoBoolean +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetNextEvent ( + uint64_t session_id, + /* EventPipeEventInstanceData * */void *instance) +{ + ERROR_DECL (error); + mono_error_set_not_implemented (error, "System.Diagnostics.Tracing.EventPipeInternal.GetNextEvent"); + mono_error_set_pending_exception (error); + return FALSE; +} + +intptr_t +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetProvider (const gunichar2 *provider_name) +{ + ERROR_DECL (error); + mono_error_set_not_implemented (error, "System.Diagnostics.Tracing.EventPipeInternal.GetProvider"); + mono_error_set_pending_exception (error); + return 0; +} + +MonoBoolean +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetSessionInfo ( + uint64_t session_id, + /* EventPipeSessionInfo * */void *session_info) +{ + ERROR_DECL (error); + mono_error_set_not_implemented (error, "System.Diagnostics.Tracing.EventPipeInternal.GetSessionInfo"); + mono_error_set_pending_exception (error); + return FALSE; +} + +intptr_t +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetWaitHandle (uint64_t session_id) +{ + ERROR_DECL (error); + mono_error_set_not_implemented (error, "System.Diagnostics.Tracing.EventPipeInternal.GetWaitHandle"); + mono_error_set_pending_exception (error); + return 0; +} + +void +ves_icall_System_Diagnostics_Tracing_EventPipeInternal_WriteEventData ( + intptr_t event_handle, + /* EventProviderEventData[] */const void *event_data, + uint32_t data_len, + /* GUID * */const uint8_t *activity_id, + /* GUID * */const uint8_t *related_activity_id) +{ + ERROR_DECL (error); + mono_error_set_not_implemented (error, "System.Diagnostics.Tracing.EventPipeInternal.WriteEventData"); + mono_error_set_pending_exception (error); +} + +#endif /* ENABLE_PERFTRACING */ +#endif /* ENABLE_NETCORE */ + +MONO_EMPTY_SOURCE_FILE (eventpipe_rt_mono); diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index a39cf2c832d26a..c51006c362ed12 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -1859,7 +1859,7 @@ type_from_parsed_name (MonoTypeNameParse *info, MonoStackCrawlMark *stack_mark, // is messed up when we go to construct the Local as the type arg... // // By contrast, if we started with Mine> we'd go in with assembly->image - // as the root and then even the detour into generics would still not screw us when we went to load Local. + // as the root and then even the detour into generics would still not cause issues when we went to load Local. if (!info->assembly.name && !type) { /* try mscorlib */ type = mono_reflection_get_type_checked (alc, rootimage, NULL, info, ignoreCase, TRUE, &type_resolve, error); @@ -7310,7 +7310,7 @@ ves_icall_System_Delegate_CreateDelegate_internal (MonoReflectionTypeHandle ref_ return_val_if_nok (error, NULL_HANDLE); } - mono_delegate_ctor_with_method (delegate, target, NULL, method, error); + mono_delegate_ctor (delegate, target, NULL, method, error); return_val_if_nok (error, NULL_HANDLE); return delegate; } @@ -8427,115 +8427,6 @@ ves_icall_System_Diagnostics_Debugger_Log (int level, MonoString *volatile* cate mono_get_runtime_callbacks ()->debug_log (level, *category, *message); } -#ifdef ENABLE_NETCORE -#define EVENT_PIPE_DUMMY_PROVIDER_ID 1 -#define EVENT_PIPE_DUMMY_SESSION_ID 1 -#define EVENT_PIPE_DUMMY_EVENT_ID 1 -#define EVENT_PIPE_ERROR_SUCCESS 0 -#define EVENT_PIPE_INVALID_WAIT_HANDLE 0 - -typedef enum _EventPipeSerializationFormat{ - NetPerf, - NetTrace -} EventPipeSerializationFormat; - -typedef struct _EventPipeProviderConfigurationNative { - gunichar2 *provider_name; - uint64_t keywords; - uint32_t logging_level; - gunichar2 *filter_data; -} EventPipeProviderConfigurationNative; - -typedef struct _EventProviderEventData { - uint64_t ptr; - uint32_t size; - uint32_t reserved; -} EventProviderEventData; - -typedef struct _EventPipeSessionInfo { - int64_t starttime_as_utc_filetime; - int64_t start_timestamp; - int64_t timestamp_frequency; -} EventPipeSessionInfo; - -typedef struct _EventPipeEventInstanceData { - intptr_t provider_id; - uint32_t event_id; - uint32_t thread_id; - int64_t timestamp; - uint8_t activity_id[16]; - uint8_t related_activity_id[16]; - const uint8_t *payload; - uint32_t payload_length; -} EventPipeEventInstanceData; - -gconstpointer -ves_icall_System_Diagnostics_Tracing_EventPipeInternal_CreateProvider (MonoStringHandle provider_name, MonoDelegateHandle callback_func, MonoError *error) -{ - return GUINT_TO_POINTER (EVENT_PIPE_DUMMY_PROVIDER_ID); -} - -intptr_t -ves_icall_System_Diagnostics_Tracing_EventPipeInternal_DefineEvent (intptr_t prov_handle, uint32_t event_id, int64_t keywords, uint32_t event_version, uint32_t level, const uint8_t *metadata, uint32_t metadata_len) -{ - return EVENT_PIPE_DUMMY_EVENT_ID; -} - -void -ves_icall_System_Diagnostics_Tracing_EventPipeInternal_DeleteProvider (intptr_t prov_handle) -{ - ; -} - -void -ves_icall_System_Diagnostics_Tracing_EventPipeInternal_Disable (uint64_t session_id) -{ - ; -} - -uint64_t -ves_icall_System_Diagnostics_Tracing_EventPipeInternal_Enable (const_gunichar2_ptr output_file, /* EventPipeSerializationFormat */int32_t format, uint32_t circular_buffer_size_mb, /* EventPipeProviderConfigurationNative[] */const void *providers, uint32_t num_providers) -{ - return EVENT_PIPE_DUMMY_SESSION_ID; -} - -int32_t -ves_icall_System_Diagnostics_Tracing_EventPipeInternal_EventActivityIdControl (uint32_t control_code, /* GUID * */uint8_t *activity_id) -{ - return EVENT_PIPE_ERROR_SUCCESS; -} - -MonoBoolean -ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetNextEvent (uint64_t session_id, /* EventPipeEventInstanceData * */void *instance) -{ - return FALSE; -} - -intptr_t -ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetProvider (const_gunichar2_ptr provider_name) -{ - return EVENT_PIPE_DUMMY_PROVIDER_ID; -} - -MonoBoolean -ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetSessionInfo (uint64_t session_id, /* EventPipeSessionInfo * */void *session_info) -{ - return FALSE; -} - -intptr_t -ves_icall_System_Diagnostics_Tracing_EventPipeInternal_GetWaitHandle (uint64_t session_id) -{ - return EVENT_PIPE_INVALID_WAIT_HANDLE; -} - -void -ves_icall_System_Diagnostics_Tracing_EventPipeInternal_WriteEventData (intptr_t event_handle, /* EventProviderEventData[] */const void *event_data, uint32_t data_count, /* GUID * */const uint8_t *activity_id, /* GUID * */const uint8_t *related_activity_id) -{ - ; -} -#endif /* ENABLE_NETCORE */ - #ifndef HOST_WIN32 static inline void mono_icall_write_windows_debug_string (const gunichar2 *message) diff --git a/src/mono/mono/metadata/image.c b/src/mono/mono/metadata/image.c index 3d4d47c6c01777..0fda88735990c9 100644 --- a/src/mono/mono/metadata/image.c +++ b/src/mono/mono/metadata/image.c @@ -2286,6 +2286,7 @@ mono_wrapper_caches_free (MonoWrapperCaches *cache) free_hash (cache->delegate_invoke_cache); free_hash (cache->delegate_begin_invoke_cache); free_hash (cache->delegate_end_invoke_cache); + free_hash (cache->delegate_bound_static_invoke_cache); free_hash (cache->runtime_invoke_signature_cache); free_hash (cache->delegate_abstract_invoke_cache); @@ -2430,7 +2431,6 @@ mono_image_close_except_pools (MonoImage *image) g_hash_table_destroy (image->name_cache); } - free_hash (image->delegate_bound_static_invoke_cache); free_hash (image->ldfld_wrapper_cache); free_hash (image->ldflda_wrapper_cache); free_hash (image->stfld_wrapper_cache); diff --git a/src/mono/mono/metadata/jit-icall-reg.h b/src/mono/mono/metadata/jit-icall-reg.h index 125c0b5a8ae923..a21b9f04676c06 100644 --- a/src/mono/mono/metadata/jit-icall-reg.h +++ b/src/mono/mono/metadata/jit-icall-reg.h @@ -77,7 +77,6 @@ MONO_JIT_ICALL (__emul_fconv_to_i4) \ MONO_JIT_ICALL (__emul_fconv_to_i8) \ MONO_JIT_ICALL (__emul_fconv_to_ovf_i8) \ MONO_JIT_ICALL (__emul_fconv_to_ovf_u8) \ -MONO_JIT_ICALL (__emul_fconv_to_ovf_u8_un) \ MONO_JIT_ICALL (__emul_fconv_to_r4) \ MONO_JIT_ICALL (__emul_fconv_to_u) \ MONO_JIT_ICALL (__emul_fconv_to_u1) \ @@ -115,7 +114,6 @@ MONO_JIT_ICALL (__emul_op_irem_un) \ MONO_JIT_ICALL (__emul_rconv_to_i8) \ MONO_JIT_ICALL (__emul_rconv_to_ovf_i8) \ MONO_JIT_ICALL (__emul_rconv_to_ovf_u8) \ -MONO_JIT_ICALL (__emul_rconv_to_ovf_u8_un) \ MONO_JIT_ICALL (__emul_rconv_to_u4) \ MONO_JIT_ICALL (__emul_rconv_to_u8) \ MONO_JIT_ICALL (__emul_rrem) \ @@ -309,6 +307,7 @@ MONO_JIT_ICALL (mono_throw_method_access) \ MONO_JIT_ICALL (mono_throw_bad_image) \ MONO_JIT_ICALL (mono_trace_enter_method) \ MONO_JIT_ICALL (mono_trace_leave_method) \ +MONO_JIT_ICALL (mono_trace_tail_method) \ MONO_JIT_ICALL (mono_upgrade_remote_class_wrapper) \ MONO_JIT_ICALL (mono_value_copy_internal) \ MONO_JIT_ICALL (mono_x86_start_gsharedvt_call) \ diff --git a/src/mono/mono/metadata/loader-internals.h b/src/mono/mono/metadata/loader-internals.h index faf94e2e7196f2..07f6e7186c8857 100644 --- a/src/mono/mono/metadata/loader-internals.h +++ b/src/mono/mono/metadata/loader-internals.h @@ -13,6 +13,16 @@ #include #include +#ifdef ENABLE_NETCORE +#if defined(TARGET_OSX) +#define MONO_LOADER_LIBRARY_NAME "libcoreclr.dylib" +#elif defined(TARGET_ANDROID) +#define MONO_LOADER_LIBRARY_NAME "libruntime-android.so" +#else +#define MONO_LOADER_LIBRARY_NAME "libcoreclr.so" +#endif +#endif + typedef struct _MonoLoadedImages MonoLoadedImages; typedef struct _MonoAssemblyLoadContext MonoAssemblyLoadContext; @@ -103,6 +113,9 @@ mono_alc_invoke_resolve_using_resolving_event_nofail (MonoAssemblyLoadContext *a MonoAssembly* mono_alc_invoke_resolve_using_resolve_satellite_nofail (MonoAssemblyLoadContext *alc, MonoAssemblyName *aname); +MonoAssemblyLoadContext * +mono_alc_from_gchandle (MonoGCHandle alc_gchandle); + #endif /* ENABLE_NETCORE */ static inline MonoDomain * diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c index 927124d29d0614..30b6b55b506ba6 100644 --- a/src/mono/mono/metadata/marshal.c +++ b/src/mono/mono/metadata/marshal.c @@ -512,7 +512,7 @@ mono_ftnptr_to_delegate_impl (MonoClass *klass, gpointer ftn, MonoError *error) gpointer compiled_ptr = mono_compile_method_checked (wrapper, error); goto_if_nok (error, leave); - mono_delegate_ctor_with_method (MONO_HANDLE_CAST (MonoObject, d), this_obj, compiled_ptr, wrapper, error); + mono_delegate_ctor (MONO_HANDLE_CAST (MonoObject, d), this_obj, compiled_ptr, wrapper, error); goto_if_nok (error, leave); } @@ -2228,7 +2228,11 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt return res; cache_key = method->klass; } else if (static_method_with_first_arg_bound) { - cache = get_cache (&get_method_image (target_method)->delegate_bound_static_invoke_cache, + GHashTable **cache_ptr; + + cache_ptr = &mono_method_get_wrapper_cache (target_method)->delegate_bound_static_invoke_cache; + + cache = get_cache (cache_ptr, (GHashFunc)mono_signature_hash, (GCompareFunc)mono_metadata_signature_equal); /* @@ -5191,11 +5195,13 @@ ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArrayHan { g_assert_not_netcore (); - MonoGCHandle gchandle = 0; - gsize const bytes = copy_managed_common (src, dest, start_index, length, (gpointer*)&managed_source_addr, &gchandle, error); - if (bytes) - memmove (dest, managed_source_addr, bytes); // no references should be involved - mono_gchandle_free_internal (gchandle); + if (length != 0) { + MonoGCHandle gchandle = 0; + gsize const bytes = copy_managed_common (src, dest, start_index, length, (gpointer*)&managed_source_addr, &gchandle, error); + if (bytes) + memmove (dest, managed_source_addr, bytes); // no references should be involved + mono_gchandle_free_internal (gchandle); + } } void @@ -5208,11 +5214,13 @@ ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gconstpoin { g_assert_not_netcore (); - MonoGCHandle gchandle = 0; - gsize const bytes = copy_managed_common (dest, src, start_index, length, &managed_dest_addr, &gchandle, error); - if (bytes) - memmove (managed_dest_addr, src, bytes); // no references should be involved - mono_gchandle_free_internal (gchandle); + if (length != 0) { + MonoGCHandle gchandle = 0; + gsize const bytes = copy_managed_common (dest, src, start_index, length, &managed_dest_addr, &gchandle, error); + if (bytes) + memmove (managed_dest_addr, src, bytes); // no references should be involved + mono_gchandle_free_internal (gchandle); + } } MonoStringHandle @@ -6260,6 +6268,36 @@ mono_marshal_asany_impl (MonoObjectHandle o, MonoMarshalNative string_encoding, return res; } + case MONO_TYPE_SZARRAY: { + //TODO: Implement structs and in-params for all value types + MonoClass *klass = t->data.klass; + MonoClass *eklass = m_class_get_element_class (klass); + MonoArray *arr = (MonoArray *) MONO_HANDLE_RAW (o); + + // we only support char[] for in-params; we return a pointer to the managed heap here, and that's not 'in'-safe + if ((param_attrs & PARAM_ATTRIBUTE_IN) && eklass != mono_get_char_class ()) + break; + + if (m_class_get_rank (klass) > 1) + break; + + if (arr->bounds) + if (arr->bounds->lower_bound != 0) + break; + + if (mono_class_is_auto_layout (eklass)) + break; + + if (m_class_is_valuetype (eklass) && (mono_class_is_explicit_layout (eklass) || m_class_is_blittable (eklass) || m_class_is_enumtype (eklass))) + return arr->vector; + + if (eklass == mono_get_char_class ()) { + char *res = mono_utf16_to_utf8 ((mono_unichar2 *) arr->vector, arr->max_length, error); + return_val_if_nok (error, NULL); + return res; + } + break; + } default: break; } @@ -6320,6 +6358,20 @@ mono_marshal_free_asany_impl (MonoObjectHandle o, gpointer ptr, MonoMarshalNativ mono_marshal_free (ptr); break; } + case MONO_TYPE_SZARRAY: { + MonoClass *klass = t->data.klass; + MonoClass *eklass = m_class_get_element_class (klass); + MonoArray *arr = (MonoArray *) MONO_HANDLE_RAW (o); + + if (eklass != mono_get_char_class ()) + break; + + mono_unichar2 *utf16_array = g_utf8_to_utf16 ((const char *)ptr, arr->max_length, NULL, NULL, NULL); + g_free (ptr); + memcpy (arr->vector, utf16_array, arr->max_length * sizeof (mono_unichar2)); + g_free (utf16_array); + break; + } default: break; } @@ -6544,8 +6596,8 @@ mono_marshal_free_dynamic_wrappers (MonoMethod *method) if (image->wrapper_caches.delegate_abstract_invoke_cache) g_hash_table_foreach_remove (image->wrapper_caches.delegate_abstract_invoke_cache, signature_pointer_pair_matches_pointer, method); // FIXME: Need to clear the caches in other images as well - if (image->delegate_bound_static_invoke_cache) - g_hash_table_remove (image->delegate_bound_static_invoke_cache, mono_method_signature_internal (method)); + if (image->wrapper_caches.delegate_bound_static_invoke_cache) + g_hash_table_remove (image->wrapper_caches.delegate_bound_static_invoke_cache, mono_method_signature_internal (method)); if (marshal_mutex_initialized) mono_marshal_unlock (); diff --git a/src/mono/mono/metadata/metadata-internals.h b/src/mono/mono/metadata/metadata-internals.h index 30b7f4e78d3b6d..561748a33842af 100644 --- a/src/mono/mono/metadata/metadata-internals.h +++ b/src/mono/mono/metadata/metadata-internals.h @@ -251,6 +251,7 @@ typedef struct { * indexed by SignaturePointerPair */ GHashTable *delegate_abstract_invoke_cache; + GHashTable *delegate_bound_static_invoke_cache; /* * indexed by MonoMethod pointers @@ -502,7 +503,6 @@ struct _MonoImage { /* * indexed by SignaturePointerPair */ - GHashTable *delegate_bound_static_invoke_cache; GHashTable *native_func_wrapper_cache; /* diff --git a/src/mono/mono/metadata/metadata-verify.c b/src/mono/mono/metadata/metadata-verify.c index 5ec4fd19093eff..e83baa4a05e8d2 100644 --- a/src/mono/mono/metadata/metadata-verify.c +++ b/src/mono/mono/metadata/metadata-verify.c @@ -3967,7 +3967,7 @@ mono_verifier_verify_pe_data (MonoImage *image, MonoError *error) error_init (error); - if (!mono_verifier_is_enabled_for_image (image)) + if (!mono_verifier_is_enabled_for_image (image) && !mono_verifier_is_enabled_for_pe_only()) return TRUE; init_verify_context (&ctx, image); diff --git a/src/mono/mono/metadata/mono-private-unstable.h b/src/mono/mono/metadata/mono-private-unstable.h index 7fd11db4d7828c..c7d2531a7c744c 100644 --- a/src/mono/mono/metadata/mono-private-unstable.h +++ b/src/mono/mono/metadata/mono-private-unstable.h @@ -14,6 +14,17 @@ #include +typedef MonoGCHandle MonoAssemblyLoadContextGCHandle; +MONO_API MONO_RT_EXTERNAL_ONLY MonoAssembly * +mono_assembly_load_full_alc (MonoAssemblyLoadContextGCHandle alc_gchandle, MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status); + +typedef MonoAssembly * (*MonoAssemblyPreLoadFuncV3) (MonoAssemblyLoadContextGCHandle alc_gchandle, MonoAssemblyName *aname, char **assemblies_path, void *user_data, MonoError *error); + +MONO_API MONO_RT_EXTERNAL_ONLY void +mono_install_assembly_preload_hook_v3 (MonoAssemblyPreLoadFuncV3 func, void *user_data, mono_bool append); + +MONO_API MONO_RT_EXTERNAL_ONLY MonoAssemblyLoadContextGCHandle +mono_alc_get_default_gchandle (void); #endif /*__MONO_METADATA_MONO_PRIVATE_UNSTABLE_H__*/ diff --git a/src/mono/mono/metadata/native-library.c b/src/mono/mono/metadata/native-library.c index 91b88a79f8b323..6b441a96e93ed6 100644 --- a/src/mono/mono/metadata/native-library.c +++ b/src/mono/mono/metadata/native-library.c @@ -758,7 +758,7 @@ netcore_lookup_native_library (MonoAssemblyLoadContext *alc, MonoImage *image, c // We allow a special name to dlopen from the running process namespace, which is not present in CoreCLR if (strcmp (scope, "__Internal") == 0) { if (!internal_module) - internal_module = mono_dl_open (NULL, MONO_DL_LAZY, &error_msg); + internal_module = mono_dl_open_self (&error_msg); module = internal_module; if (!module) { @@ -1240,6 +1240,9 @@ lookup_pinvoke_call_impl (MonoMethod *method, MonoLookupPInvokeStatus *status_ou #endif #ifdef ENABLE_NETCORE +#ifndef HOST_WIN32 +retry_with_libcoreclr: +#endif // FIXME: these flags are not getting passed correctly module = netcore_lookup_native_library (alc, image, new_scope, 0); #else @@ -1262,6 +1265,13 @@ lookup_pinvoke_call_impl (MonoMethod *method, MonoLookupPInvokeStatus *status_ou addr = pinvoke_probe_for_symbol (module, piinfo, new_import, &error_msg); if (!addr) { +#if defined(ENABLE_NETCORE) && !defined(HOST_WIN32) + if (strcmp (new_scope, "__Internal") == 0) { + g_free ((char *)new_scope); + new_scope = g_strdup (MONO_LOADER_LIBRARY_NAME); + goto retry_with_libcoreclr; + } +#endif status_out->err_code = LOOKUP_PINVOKE_ERR_NO_SYM; status_out->err_arg = g_strdup (new_import); goto exit; diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index 0b369effebb52c..ee34045d181ad6 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -820,10 +820,9 @@ typedef struct { void (*set_cast_details) (MonoClass *from, MonoClass *to); void (*debug_log) (int level, MonoString *category, MonoString *message); gboolean (*debug_log_is_enabled) (void); - void (*init_delegate) (MonoDelegateHandle delegate, MonoError *error); + void (*init_delegate) (MonoDelegateHandle delegate, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error); MonoObject* (*runtime_invoke) (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error); void* (*compile_method) (MonoMethod *method, MonoError *error); - gpointer (*create_jump_trampoline) (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error); gpointer (*create_jit_trampoline) (MonoDomain *domain, MonoMethod *method, MonoError *error); /* used to free a dynamic method */ void (*free_method) (MonoDomain *domain, MonoMethod *method); @@ -881,11 +880,8 @@ mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod * void mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error); -gboolean -mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error); - -gboolean -mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error); +void +mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error); MonoMethod * mono_get_delegate_invoke_checked (MonoClass *klass, MonoError *error); @@ -1647,6 +1643,30 @@ typedef struct { MonoProperty *prop; } CattrNamedArg; +#ifdef ENABLE_NETCORE +// Keep in sync with System.Runtime.Loader.AssemblyLoadContext.InternalState +typedef enum { + ALIVE = 0, + UNLOADING = 1 +} MonoManagedAssemblyLoadContextInternalState; + +// Keep in sync with System.Runtime.Loader.AssemblyLoadContext +typedef struct { + MonoObject object; + MonoObject *unload_lock; + MonoEvent *resolving_unmaned_dll; + MonoEvent *resolving; + MonoEvent *unloading; + MonoString *name; + gpointer *native_assembly_load_context; + gint64 id; + gint32 internal_state; + MonoBoolean is_collectible; +} MonoManagedAssemblyLoadContext; + +TYPED_HANDLE_DECL (MonoManagedAssemblyLoadContext); +#endif + /* All MonoInternalThread instances should be pinned, so it's safe to use the raw ptr. However * for uniformity, icall wrapping will make handles anyway. So this is the method for getting the payload. */ diff --git a/src/mono/mono/metadata/object-offsets.h b/src/mono/mono/metadata/object-offsets.h index 9a36613866d77b..82f901714646ef 100644 --- a/src/mono/mono/metadata/object-offsets.h +++ b/src/mono/mono/metadata/object-offsets.h @@ -298,6 +298,14 @@ DECL_OFFSET(CallContext, stack_size) DECL_OFFSET(CallContext, stack) #endif +#if defined(TARGET_X86) +DECL_OFFSET(CallContext, eax) +DECL_OFFSET(CallContext, edx) +DECL_OFFSET(CallContext, fret) +DECL_OFFSET(CallContext, stack_size) +DECL_OFFSET(CallContext, stack) +#endif + #if defined(TARGET_X86) DECL_OFFSET(GSharedVtCallInfo, stack_usage) DECL_OFFSET(GSharedVtCallInfo, vret_slot) diff --git a/src/mono/mono/metadata/object.c b/src/mono/mono/metadata/object.c index 952b2be7c1cc0e..c9bacf3ad2aa65 100644 --- a/src/mono/mono/metadata/object.c +++ b/src/mono/mono/metadata/object.c @@ -802,18 +802,6 @@ mono_compile_method_checked (MonoMethod *method, MonoError *error) return res; } -gpointer -mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error) -{ - gpointer res; - - MONO_REQ_GC_NEUTRAL_MODE; - - error_init (error); - res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error); - return res; -} - gpointer mono_runtime_create_delegate_trampoline (MonoClass *klass) { @@ -8714,7 +8702,7 @@ mono_print_unhandled_exception (MonoObject *exc) } /** - * mono_delegate_ctor_with_method: + * mono_delegate_ctor: * \param this pointer to an uninitialized delegate object * \param target target object * \param addr pointer to native code @@ -8724,82 +8712,22 @@ mono_print_unhandled_exception (MonoObject *exc) * associated with \p addr. This is useful when sharing generic code. * In that case \p addr will most probably not be associated with the * correct instantiation of the method. - * On failure returns FALSE and sets \p error. + * If \method is NULL, it is looked up using \addr in the JIT info tables. */ -gboolean -mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error) +void +mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error) { MONO_REQ_GC_UNSAFE_MODE; - error_init (error); MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj); - g_assert (!MONO_HANDLE_IS_NULL (this_obj)); + UnlockedIncrement (&mono_stats.delegate_creations); MonoClass *klass = mono_handle_class (this_obj); g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class)); - if (method) - MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method); - - UnlockedIncrement (&mono_stats.delegate_creations); - - if (addr) - MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr); - -#ifndef DISABLE_REMOTING - if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) { - if (callbacks.interp_get_remoting_invoke) { - MONO_HANDLE_SETVAL (delegate, interp_method, gpointer, callbacks.interp_get_remoting_invoke (method, addr, error)); - } else { - g_assert (method); - method = mono_marshal_get_remoting_invoke (method, error); - return_val_if_nok (error, FALSE); - MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error)); - } - return_val_if_nok (error, FALSE); - } -#endif - - MONO_HANDLE_SET (delegate, target, target); - MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate))); - g_assert (callbacks.init_delegate); - callbacks.init_delegate (delegate, error); - return_val_if_nok (error, FALSE); - return TRUE; -} - -/** - * mono_delegate_ctor: - * \param this pointer to an uninitialized delegate object - * \param target target object - * \param addr pointer to native code - * \param error set on error. - * This is used to initialize a delegate. - * On failure returns FALSE and sets \p error. - */ -gboolean -mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error) -{ - MONO_REQ_GC_UNSAFE_MODE; - - error_init (error); - MonoDomain *domain = mono_domain_get (); - MonoJitInfo *ji; - MonoMethod *method = NULL; - - g_assert (addr); - - ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)); - /* Shared code */ - if (!ji && domain != mono_get_root_domain ()) - ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr)); - if (ji) { - method = mono_jit_info_get_method (ji); - g_assert (!mono_class_is_gtd (method->klass)); - } - - return mono_delegate_ctor_with_method (this_obj, target, addr, method, error); + /* Done by the EE */ + callbacks.init_delegate (delegate, target, addr, method, error); } /** diff --git a/src/mono/mono/metadata/object.h b/src/mono/mono/metadata/object.h index da19d3d5590302..f421c6c1a33beb 100644 --- a/src/mono/mono/metadata/object.h +++ b/src/mono/mono/metadata/object.h @@ -372,6 +372,11 @@ MONO_API MONO_RT_EXTERNAL_ONLY uint32_t mono_gchandle_new_weakref (MonoObjec MONO_API MONO_RT_EXTERNAL_ONLY MonoObject* mono_gchandle_get_target (uint32_t gchandle); MONO_API MONO_RT_EXTERNAL_ONLY void mono_gchandle_free (uint32_t gchandle); +MONO_API MONO_RT_EXTERNAL_ONLY MonoGCHandle mono_gchandle_new_v2 (MonoObject *obj, mono_bool pinned); +MONO_API MONO_RT_EXTERNAL_ONLY MonoGCHandle mono_gchandle_new_weakref_v2 (MonoObject *obj, mono_bool track_resurrection); +MONO_API MONO_RT_EXTERNAL_ONLY MonoObject* mono_gchandle_get_target_v2 (MonoGCHandle gchandle); +MONO_API MONO_RT_EXTERNAL_ONLY void mono_gchandle_free_v2 (MonoGCHandle gchandle); + /* Reference queue support * * A reference queue is used to get notifications of when objects are collected. diff --git a/src/mono/mono/metadata/reflection.c b/src/mono/mono/metadata/reflection.c index c6f2d7fd3340ab..c28ce829a49908 100644 --- a/src/mono/mono/metadata/reflection.c +++ b/src/mono/mono/metadata/reflection.c @@ -1958,7 +1958,7 @@ _mono_reflection_get_type_from_info (MonoAssemblyLoadContext *alc, MonoTypeNameP MonoAssemblyByNameRequest req; mono_assembly_request_prepare_byname (&req, MONO_ASMCTX_DEFAULT, alc); req.requesting_assembly = NULL; - req.basedir = image->assembly->basedir; + req.basedir = image ? image->assembly->basedir : NULL; assembly = mono_assembly_request_byname (&info->assembly, &req, NULL); if (!assembly) return NULL; diff --git a/src/mono/mono/metadata/threads.c b/src/mono/mono/metadata/threads.c index 0a293811b9d106..53fba02f33df06 100644 --- a/src/mono/mono/metadata/threads.c +++ b/src/mono/mono/metadata/threads.c @@ -83,16 +83,8 @@ mono_native_thread_join_handle (HANDLE thread_handle, gboolean close_handle); #include #endif -#if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64) -#define USE_TKILL_ON_ANDROID 1 -#endif - #ifdef HOST_ANDROID #include - -#ifdef USE_TKILL_ON_ANDROID -extern int tkill (pid_t tid, int signal); -#endif #endif #include "icall-decl.h" diff --git a/src/mono/mono/metadata/verify-internals.h b/src/mono/mono/metadata/verify-internals.h index 3a4976bee31cc4..e4783e0e352b05 100644 --- a/src/mono/mono/metadata/verify-internals.h +++ b/src/mono/mono/metadata/verify-internals.h @@ -12,6 +12,7 @@ typedef enum { MONO_VERIFIER_MODE_OFF, + MONO_VERIFIER_PE_ONLY, MONO_VERIFIER_MODE_VALID, MONO_VERIFIER_MODE_VERIFIABLE, MONO_VERIFIER_MODE_STRICT @@ -23,6 +24,7 @@ void mono_verifier_enable_verify_all (void); gboolean mono_verifier_is_enabled_for_image (MonoImage *image); gboolean mono_verifier_is_enabled_for_method (MonoMethod *method); gboolean mono_verifier_is_enabled_for_class (MonoClass *klass); +gboolean mono_verifier_is_enabled_for_pe_only (void); gboolean mono_verifier_is_method_full_trust (MonoMethod *method); gboolean mono_verifier_is_class_full_trust (MonoClass *klass); diff --git a/src/mono/mono/metadata/verify.c b/src/mono/mono/metadata/verify.c index 0214e6f458a179..295e146a068347 100644 --- a/src/mono/mono/metadata/verify.c +++ b/src/mono/mono/metadata/verify.c @@ -6126,13 +6126,19 @@ gboolean mono_verifier_is_enabled_for_class (MonoClass *klass) { MonoImage *image = m_class_get_image (klass); - return verify_all || (verifier_mode > MONO_VERIFIER_MODE_OFF && !(image->assembly && image->assembly->in_gac) && image != mono_defaults.corlib); + return verify_all || (verifier_mode > MONO_VERIFIER_PE_ONLY && !(image->assembly && image->assembly->in_gac) && image != mono_defaults.corlib); } gboolean mono_verifier_is_enabled_for_image (MonoImage *image) { - return verify_all || verifier_mode > MONO_VERIFIER_MODE_OFF; + return verify_all || verifier_mode > MONO_VERIFIER_PE_ONLY; +} + +gboolean +mono_verifier_is_enabled_for_pe_only () +{ + return verify_all || verifier_mode == MONO_VERIFIER_PE_ONLY; } /* diff --git a/src/mono/mono/metadata/w32file-unix.c b/src/mono/mono/metadata/w32file-unix.c index 819bbba68188a2..5ec7f54ddb5e6e 100644 --- a/src/mono/mono/metadata/w32file-unix.c +++ b/src/mono/mono/metadata/w32file-unix.c @@ -2528,7 +2528,7 @@ CopyFile (const gunichar2 *name, const gunichar2 *dest_name, gboolean fail_if_ex if (fail_if_exists) { dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_CREAT | O_EXCL, st.st_mode); } else { - /* FIXME: it kinda sucks that this code path potentially scans + /* FIXME: it's bad that this code path potentially scans * the directory twice due to the weird mono_w32error_set_last() * behavior. */ dest_fd = _wapi_open (utf8_dest, O_WRONLY | O_TRUNC, st.st_mode); diff --git a/src/mono/mono/metadata/w32handle.c b/src/mono/mono/metadata/w32handle.c index 17a4b9d68dd903..6de478863912b7 100644 --- a/src/mono/mono/metadata/w32handle.c +++ b/src/mono/mono/metadata/w32handle.c @@ -597,7 +597,6 @@ mono_w32handle_lock_handles (MonoW32Handle **handles_data, gsize nhandles) if (!handles_data [i]) continue; if (!mono_w32handle_trylock (handles_data [i])) { - /* Bummer */ for (j = i - 1; j >= 0; j--) { if (!handles_data [j]) diff --git a/src/mono/mono/metadata/w32process-unix.c b/src/mono/mono/metadata/w32process-unix.c index e9bda36b1c2636..eb535beadc7479 100644 --- a/src/mono/mono/metadata/w32process-unix.c +++ b/src/mono/mono/metadata/w32process-unix.c @@ -1034,7 +1034,6 @@ mono_w32process_module_get_name (gpointer handle, gpointer module, gunichar2 **s procname = mono_unicode_from_external (procname_ext, &bytes); if (procname == NULL) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_PROCESS, "%s: Can't get procname %p", __func__, handle); - /* bugger */ g_free (procname_ext); mono_w32handle_unref (handle_data); return FALSE; @@ -1522,9 +1521,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, * 5) $PATH * * Just to make things more interesting, tokens can contain - * white space if they are surrounded by quotation marks. I'm - * beginning to understand just why windows apps are generally - * so crap, with an API like this :-( + * white space if they are surrounded by quotation marks. */ if (appname != NULL) { cmd = mono_unicode_to_external_checked (appname, error); diff --git a/src/mono/mono/metadata/w32socket.c b/src/mono/mono/metadata/w32socket.c index d33caec57b7e8b..6b93083d7b1c5e 100644 --- a/src/mono/mono/metadata/w32socket.c +++ b/src/mono/mono/metadata/w32socket.c @@ -679,8 +679,8 @@ convert_sockopt_level_and_name (MonoSocketOptionLevel mono_level, MonoSocketOpti *system_name = TCP_NODELAY; break; #if 0 - /* The documentation is talking complete - * bollocks here: rfc-1222 is titled + /* The documentation is + * very vague here: rfc-1222 is titled * 'Advancing the NSFNET Routing Architecture' * and doesn't mention either of the words * "expedite" or "urgent". diff --git a/src/mono/mono/mini/Makefile.am.in b/src/mono/mono/mini/Makefile.am.in index 4fa894984cc16e..a8e9891def5b77 100755 --- a/src/mono/mono/mini/Makefile.am.in +++ b/src/mono/mono/mini/Makefile.am.in @@ -29,6 +29,10 @@ endif glib_libs = $(monodir)/mono/eglib/libeglib.la +if ENABLE_PERFTRACING +eventpipe_libs = $(monodir)/mono/eventpipe/libeventpipe.la +endif + boehm_libs= \ $(monodir)/mono/metadata/libmonoruntime.la \ $(monodir)/mono/utils/libmonoutils.la \ @@ -39,6 +43,7 @@ sgen_libs = \ $(monodir)/mono/metadata/libmonoruntimesgen.la \ $(monodir)/mono/sgen/libmonosgen.la \ $(monodir)/mono/utils/libmonoutils.la \ + $(eventpipe_libs) \ $(glib_libs) if ENABLE_LLVM diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index bab6b97bf51d08..adb9cab48538c6 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -68,6 +68,7 @@ #include "mini-gc.h" #include "mini-llvm.h" #include "mini-runtime.h" +#include "interp/interp.h" static MonoMethod* try_get_method_nofail (MonoClass *klass, const char *method_name, int param_count, int flags) @@ -8608,7 +8609,7 @@ add_gsharedvt_wrappers (MonoAotCompile *acfg, MonoMethodSignature *sig, gboolean if (gsharedvt_out && g_hash_table_lookup (acfg->gsharedvt_out_signatures, sig)) add_out = FALSE; - if (!add_in && !add_out) + if (!add_in && !add_out && !interp_in) return; if (mini_is_gsharedvt_variable_signature (sig)) @@ -8637,7 +8638,6 @@ add_gsharedvt_wrappers (MonoAotCompile *acfg, MonoMethodSignature *sig, gboolean if (interp_in) { wrapper = mini_get_interp_in_wrapper (sig); add_extra_method (acfg, wrapper); - //printf ("X: %s\n", mono_method_full_name (wrapper, 1)); } #endif } @@ -8965,7 +8965,16 @@ compile_method (MonoAotCompile *acfg, MonoMethod *method) for (l = cfg->interp_in_signatures; l; l = l->next) { MonoMethodSignature *sig = mono_metadata_signature_dup ((MonoMethodSignature*)l->data); - add_gsharedvt_wrappers (acfg, sig, TRUE, FALSE, FALSE); + /* + * Interpreter methods in llvmonly+interp mode are called using gsharedvt_in wrappers, + * since we already generate those in llvmonly mode. But methods with a large + * number of arguments need special processing (see interp_create_method_pointer_llvmonly), + * which only interp_in wrappers do. + */ + if (sig->param_count > MAX_INTERP_ENTRY_ARGS) + add_gsharedvt_wrappers (acfg, sig, FALSE, FALSE, TRUE); + else + add_gsharedvt_wrappers (acfg, sig, TRUE, FALSE, FALSE); } } else if (mono_aot_mode_is_full (&acfg->aot_opts) && mono_aot_mode_is_interp (&acfg->aot_opts)) { /* The interpreter uses these wrappers to call aot-ed code */ @@ -10399,7 +10408,7 @@ emit_method_info_table (MonoAotCompile *acfg) if (acfg->cfgs [i]) method_flags [acfg->cfgs [i]->method_index] = acfg->cfgs [i]->aot_method_flags; } - emit_aot_data (acfg, MONO_AOT_TABLE_FLAGS_TABLE, "method_flags_table", method_flags, acfg->nmethods); + emit_aot_data (acfg, MONO_AOT_TABLE_METHOD_FLAGS_TABLE, "method_flags_table", method_flags, acfg->nmethods); } #endif /* #if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) */ diff --git a/src/mono/mono/mini/aot-runtime-wasm.c b/src/mono/mono/mini/aot-runtime-wasm.c index ccc5a26510c931..8f26a725abde73 100644 --- a/src/mono/mono/mini/aot-runtime-wasm.c +++ b/src/mono/mono/mini/aot-runtime-wasm.c @@ -63,13 +63,7 @@ type_to_c (MonoType *t) } } -#if TARGET_SIZEOF_VOID_P == 4 -#define FIDX(x) ((x) * 2) -#else #define FIDX(x) (x) -#endif - - typedef union { gint64 l; diff --git a/src/mono/mono/mini/aot-runtime.c b/src/mono/mono/mini/aot-runtime.c index 43dda8c8451fdd..df3f5b614779c5 100644 --- a/src/mono/mono/mini/aot-runtime.c +++ b/src/mono/mono/mini/aot-runtime.c @@ -126,6 +126,7 @@ struct MonoAotModule { guint8 *plt_end; guint8 *blob; gpointer weak_field_indexes; + guint8 *method_flags_table; /* Maps method indexes to their code */ gpointer *methods; /* Sorted array of method addresses */ @@ -147,6 +148,8 @@ struct MonoAotModule { guint32 *unbox_trampolines_end; guint32 *unbox_trampoline_addresses; guint8 *unwind_info; + /* Maps method index -> unbox tramp */ + gpointer *unbox_tramp_per_method; /* Points to the mono EH data created by LLVM */ guint8 *mono_eh_frame; @@ -2191,7 +2194,7 @@ load_aot_module (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer } g_free (aot_name); } -#ifndef PLATFORM_ANDROID +#if !defined(PLATFORM_ANDROID) && !defined(TARGET_WASM) if (!sofile) { char *basename = g_path_get_basename (assembly->image->name); aot_name = g_strdup_printf ("%s/mono/aot-cache/%s/%s%s", mono_assembly_getrootdir(), MONO_ARCHITECTURE, basename, MONO_SOLIB_EXT); @@ -2377,6 +2380,7 @@ load_aot_module (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer amodule->got_info_offsets = (guint32*)amodule->tables [MONO_AOT_TABLE_GOT_INFO_OFFSETS]; amodule->llvm_got_info_offsets = (guint32*)amodule->tables [MONO_AOT_TABLE_LLVM_GOT_INFO_OFFSETS]; amodule->weak_field_indexes = (guint32*)amodule->tables [MONO_AOT_TABLE_WEAK_FIELD_INDEXES]; + amodule->method_flags_table = (guint8*)amodule->tables [MONO_AOT_TABLE_METHOD_FLAGS_TABLE]; } else { amodule->blob = (guint8*)info->blob; amodule->method_info_offsets = (guint32 *)info->method_info_offsets; @@ -2388,6 +2392,7 @@ load_aot_module (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, gpointer amodule->got_info_offsets = (guint32*)info->got_info_offsets; amodule->llvm_got_info_offsets = (guint32*)info->llvm_got_info_offsets; amodule->weak_field_indexes = (guint32*)info->weak_field_indexes; + amodule->method_flags_table = (guint8*)info->method_flags_table; } amodule->unbox_trampolines = (guint32 *)info->unbox_trampolines; amodule->unbox_trampolines_end = (guint32 *)info->unbox_trampolines_end; @@ -4348,7 +4353,7 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM } if (mono_llvm_only) { - guint8 flags = amodule->info.method_flags_table [method_index]; + guint8 flags = amodule->method_flags_table [method_index]; /* The caller needs to looks this up, but its hard to do without constructing the full MonoJitInfo, so save it here */ if (flags & MONO_AOT_METHOD_FLAG_GSHAREDVT_VARIABLE) { mono_aot_lock (); @@ -4633,7 +4638,7 @@ init_method (MonoAotModule *amodule, gpointer info, guint32 method_index, MonoMe p += 4; code = (guint8 *)amodule->methods [method_index]; - guint8 flags = amodule->info.method_flags_table [method_index]; + guint8 flags = amodule->method_flags_table [method_index]; if (flags & MONO_AOT_METHOD_FLAG_HAS_CCTOR) klass_to_run_ctor = decode_klass_ref (amodule, p, &p, error); @@ -5641,7 +5646,6 @@ read_page_trampoline_uwinfo (MonoTrampInfo *info, int tramp_type, gboolean is_ge static unsigned char* get_new_trampoline_from_page (int tramp_type) { - MonoImage *image; TrampolinePage *page; int count; void *tpage; @@ -6048,6 +6052,16 @@ mono_aot_get_unbox_trampoline (MonoMethod *method, gpointer addr) return mono_aot_get_unbox_arbitrary_trampoline (addr); } + if (!amodule->unbox_tramp_per_method) { + gpointer arr = g_new0 (gpointer, amodule->info.nmethods); + mono_memory_barrier (); + gpointer old_arr = mono_atomic_cas_ptr ((volatile gpointer*)&amodule->unbox_tramp_per_method, arr, NULL); + if (old_arr) + g_free (arr); + } + if (amodule->unbox_tramp_per_method [method_index]) + return amodule->unbox_tramp_per_method [method_index]; + if (amodule->info.llvm_unbox_tramp_indexes) { int unbox_tramp_idx; @@ -6066,6 +6080,10 @@ mono_aot_get_unbox_trampoline (MonoMethod *method, gpointer addr) g_assert (unbox_tramp_idx < amodule->info.llvm_unbox_tramp_num); code = ((gpointer*)(amodule->info.llvm_unbox_trampolines))[unbox_tramp_idx]; g_assert (code); + + mono_memory_barrier (); + amodule->unbox_tramp_per_method [method_index] = code; + return code; } @@ -6073,8 +6091,12 @@ mono_aot_get_unbox_trampoline (MonoMethod *method, gpointer addr) gpointer (*get_tramp) (int) = (gpointer (*)(int))amodule->info.llvm_get_unbox_tramp; code = get_tramp (method_index); - if (code) + if (code) { + mono_memory_barrier (); + amodule->unbox_tramp_per_method [method_index] = code; + return code; + } } ut = amodule->unbox_trampolines; @@ -6111,9 +6133,14 @@ mono_aot_get_unbox_trampoline (MonoMethod *method, gpointer addr) return FALSE; } + tinfo->method = method; tinfo->code_size = *(guint32*)symbol_addr; + tinfo->unwind_ops = mono_arch_get_cie_program (); mono_aot_tramp_info_register (tinfo, NULL); + mono_memory_barrier (); + amodule->unbox_tramp_per_method [method_index] = code; + /* The caller expects an ftnptr */ return mono_create_ftnptr (mono_domain_get (), code); } diff --git a/src/mono/mono/mini/aot-runtime.h b/src/mono/mono/mini/aot-runtime.h index c8b2f1c09ccdd1..c4171fab12a3aa 100644 --- a/src/mono/mono/mini/aot-runtime.h +++ b/src/mono/mono/mini/aot-runtime.h @@ -11,7 +11,7 @@ #include "mini.h" /* Version number of the AOT file format */ -#define MONO_AOT_FILE_VERSION 177 +#define MONO_AOT_FILE_VERSION 178 #define MONO_AOT_TRAMP_PAGE_SIZE 16384 @@ -87,17 +87,17 @@ typedef enum { typedef enum { MONO_AOT_TABLE_BLOB, - MONO_AOT_TABLE_IMAGE_TABLE, MONO_AOT_TABLE_CLASS_NAME, + MONO_AOT_TABLE_CLASS_INFO_OFFSETS, MONO_AOT_TABLE_METHOD_INFO_OFFSETS, MONO_AOT_TABLE_EX_INFO_OFFSETS, - MONO_AOT_TABLE_CLASS_INFO_OFFSETS, - MONO_AOT_TABLE_GOT_INFO_OFFSETS, - MONO_AOT_TABLE_LLVM_GOT_INFO_OFFSETS, MONO_AOT_TABLE_EXTRA_METHOD_INFO_OFFSETS, MONO_AOT_TABLE_EXTRA_METHOD_TABLE, + MONO_AOT_TABLE_GOT_INFO_OFFSETS, + MONO_AOT_TABLE_LLVM_GOT_INFO_OFFSETS, + MONO_AOT_TABLE_IMAGE_TABLE, MONO_AOT_TABLE_WEAK_FIELD_INDEXES, - MONO_AOT_TABLE_FLAGS_TABLE, + MONO_AOT_TABLE_METHOD_FLAGS_TABLE, MONO_AOT_TABLE_NUM } MonoAotFileTable; diff --git a/src/mono/mono/mini/branch-opts.c b/src/mono/mono/mini/branch-opts.c index 67eabd7c082f14..df8954784aefe2 100644 --- a/src/mono/mono/mini/branch-opts.c +++ b/src/mono/mono/mini/branch-opts.c @@ -1252,7 +1252,7 @@ mono_optimize_branches (MonoCompile *cfg) int filter = FILTER_IL_SEQ_POINT; /* - * Some crazy loops could cause the code below to go into an infinite + * Possibly some loops could cause the code below to go into an infinite * loop, see bug #53003 for an example. To prevent this, we put an upper * bound on the number of iterations. */ diff --git a/src/mono/mono/mini/cfold.c b/src/mono/mono/mini/cfold.c index 19f2a376fbcad0..7c082475aeed3c 100644 --- a/src/mono/mono/mini/cfold.c +++ b/src/mono/mono/mini/cfold.c @@ -13,7 +13,7 @@ #include "mini.h" #include "ir-emit.h" -/* WTF is this doing here?!?!? */ +/* What is this doing here?!?!? */ int mono_is_power_of_two (guint32 val) { diff --git a/src/mono/mono/mini/cpu-s390x.md b/src/mono/mono/mini/cpu-s390x.md index 14029f688cc634..34295c32bde99c 100644 --- a/src/mono/mono/mini/cpu-s390x.md +++ b/src/mono/mono/mini/cpu-s390x.md @@ -187,7 +187,7 @@ loadu1_membase: dest:i src1:b len:30 loadu2_membase: dest:i src1:b len:30 loadu4_mem: dest:i len:8 loadu4_membase: dest:i src1:b len:30 -localloc: dest:i src1:i len:106 +localloc: dest:i src1:i len:110 memory_barrier: len:10 move: dest:i src1:i len:4 mul_imm: dest:i src1:i len:24 @@ -207,11 +207,11 @@ rcall_reg: dest:f src1:i len:8 clob:c rcall_membase: dest:f src1:b len:12 clob:c rem_un_imm: dest:i src1:i len:24 s390_bkchain: len:8 dest:i src1:i -s390_move: len:48 dest:b src1:b +s390_move: len:48 src2:b src1:b s390_setf4ret: dest:f src1:f len:4 sbb: dest:i src1:i src2:i len:6 sbb_imm: dest:i src1:i len:14 -seq_point: len:54 +seq_point: len:64 il_seq_point: len:0 sext_i4: dest:i src1:i len:4 zext_i4: dest:i src1:i len:4 @@ -236,8 +236,9 @@ sub_imm: dest:i src1:i len:18 sub_ovf_carry: dest:i src1:1 src2:i len:28 sub_ovf_un_carry: dest:i src1:1 src2:i len:12 subcc: dest:i src1:i src2:i len:12 -tailcall: len:120 clob:c -tailcall_membase: src1:b len:120 clob:c +tailcall: len:32 clob:c +tailcall_reg: len:32 clob:c +tailcall_membase: src1:b len:32 clob:c # Tailcall parameters are moved with one instruction per 256 bytes, # of stacked parameters. Zero and six are the most common diff --git a/src/mono/mono/mini/debugger-agent.c b/src/mono/mono/mini/debugger-agent.c index 7dbbe7499e1b36..f76e887e6db885 100644 --- a/src/mono/mono/mini/debugger-agent.c +++ b/src/mono/mono/mini/debugger-agent.c @@ -1832,6 +1832,21 @@ buffer_add_data (Buffer *buf, guint8 *data, int len) buf->p += len; } +static void +buffer_add_utf16 (Buffer *buf, guint8 *data, int len) +{ +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + buffer_make_room (buf, len); + memcpy (buf->p, data, len); +#else + for (int i=0; ip[i] = data[i+1]; + buf->p[i+1] = data[i]; + } +#endif + buf->p += len; +} + static void buffer_add_string (Buffer *buf, const char *str) { @@ -4574,7 +4589,16 @@ get_object_id_for_debugger_method (MonoClass* async_builder_class) ERROR_DECL (error); GPtrArray *array = mono_class_get_methods_by_name (async_builder_class, "get_ObjectIdForDebugger", 0x24, 1, FALSE, error); mono_error_assert_ok (error); - g_assert (array->len == 1); + if (array->len != 1) { + g_ptr_array_free (array, TRUE); + //if we don't find method get_ObjectIdForDebugger we try to find the property Task to continue async debug. + MonoProperty *prop = mono_class_get_property_from_name_internal (async_builder_class, "Task"); + if (!prop) { + DEBUG_PRINTF (1, "Impossible to debug async methods.\n"); + return NULL; + } + return prop->get; + } MonoMethod *method = (MonoMethod *)g_ptr_array_index (array, 0); g_ptr_array_free (array, TRUE); return method; @@ -4592,7 +4616,9 @@ get_class_to_get_builder_field(DbgEngineStackFrame *frame) MonoGenericContext context; MonoType *inflated_type; - g_assert (this_obj); + if (!this_obj) + return NULL; + context = mono_get_generic_context_from_stack_frame (frame->ji, this_obj->vtable); inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (original_class), &context, error); mono_error_assert_ok (error); /* FIXME don't swallow the error */ @@ -4617,7 +4643,8 @@ get_async_method_builder (DbgEngineStackFrame *frame) klass = get_class_to_get_builder_field(frame); builder_field = mono_class_get_field_from_name_full (klass, "<>t__builder", NULL); - g_assert (builder_field); + if (!builder_field) + return NULL; this_addr = get_this_addr (frame); if (!this_addr) @@ -4656,7 +4683,8 @@ get_this_async_id (DbgEngineStackFrame *frame) return 0; builder_field = mono_class_get_field_from_name_full (get_class_to_get_builder_field(frame), "<>t__builder", NULL); - g_assert (builder_field); + if (!builder_field) + return 0; tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id); if (tls) { @@ -4665,6 +4693,11 @@ get_this_async_id (DbgEngineStackFrame *frame) } method = get_object_id_for_debugger_method (mono_class_from_mono_type_internal (builder_field->type)); + if (!method) { + if (tls) + tls->disable_breakpoints = old_disable_breakpoints; + return 0; + } obj = mono_runtime_try_invoke (method, builder, NULL, &ex, error); mono_error_assert_ok (error); @@ -4680,9 +4713,11 @@ static gboolean set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame) { MonoClassField *builder_field = mono_class_get_field_from_name_full (get_class_to_get_builder_field(frame), "<>t__builder", NULL); - g_assert (builder_field); + if (!builder_field) + return FALSE; gpointer builder = get_async_method_builder (frame); - g_assert (builder); + if (!builder) + return FALSE; MonoMethod* method = get_set_notification_method (mono_class_from_mono_type_internal (builder_field->type)); if (method == NULL) @@ -5035,7 +5070,7 @@ ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args) mono_loader_unlock (); g_assert (tls); if (!tls->context.valid) { - DEBUG_PRINTF (1, "Received a single step request on a thread with no managed frames."); + DEBUG_PRINTF (1, "Received a single step request on a thread with no managed frames.\n"); return ERR_INVALID_ARGUMENT; } @@ -5056,7 +5091,10 @@ ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args) * We are stopped at a throw site. Stepping should go to the catch site. */ frame = tls->catch_frame; - g_assert (frame.type == FRAME_TYPE_MANAGED || frame.type == FRAME_TYPE_INTERP); + if (frame.type != FRAME_TYPE_MANAGED && frame.type != FRAME_TYPE_INTERP) { + DEBUG_PRINTF (1, "Current frame is not managed nor interpreter.\n"); + return ERR_INVALID_ARGUMENT; + } /* * Find the seq point corresponding to the landing site ip, which is the first seq @@ -5065,7 +5103,10 @@ ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args) found_sp = mono_find_next_seq_point_for_native_offset (frame.domain, frame.method, frame.native_offset, &info, &args->sp); if (!found_sp) no_seq_points_found (frame.method, frame.native_offset); - g_assert (found_sp); + if (!found_sp) { + DEBUG_PRINTF (1, "Could not find next sequence point.\n"); + return ERR_INVALID_ARGUMENT; + } method = frame.method; @@ -5110,7 +5151,10 @@ ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *args) found_sp = mono_find_prev_seq_point_for_native_offset (frame->de.domain, frame->de.method, frame->de.native_offset, &info, &args->sp); if (!found_sp) no_seq_points_found (frame->de.method, frame->de.native_offset); - g_assert (found_sp); + if (!found_sp) { + DEBUG_PRINTF (1, "Could not find next sequence point.\n"); + return ERR_INVALID_ARGUMENT; + } method = frame->de.method; } } @@ -6549,7 +6593,10 @@ do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, guint8 else { ERROR_DECL (error); this_arg = mono_object_new_checked (domain, m->klass, error); - mono_error_assert_ok (error); + if (!is_ok (error)) { + mono_error_cleanup (error); + return ERR_INVALID_ARGUMENT; + } } } else { return ERR_INVALID_ARGUMENT; @@ -8843,7 +8890,11 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g if (mono_class_get_context (klass)) { ERROR_DECL (error); result = mono_class_inflate_generic_method_full_checked (result, klass, mono_class_get_context (klass), error); - g_assert (is_ok (error)); /* FIXME don't swallow the error */ + if (!is_ok (error)) { + add_error_string (buf, mono_error_get_message (error)); + mono_error_cleanup (error); + return ERR_INVALID_ARGUMENT; + } } } } @@ -8981,7 +9032,12 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g char *s; s = mono_string_to_utf8_checked_internal ((MonoString *)val, error); - mono_error_assert_ok (error); + if (!is_ok (error)) { + add_error_string (buf, mono_error_get_message (error)); + mono_error_cleanup (error); + g_free (s); + return ERR_INVALID_ARGUMENT; + } buffer_add_byte (buf, TOKEN_TYPE_STRING); buffer_add_string (buf, s); g_free (s); @@ -9044,7 +9100,11 @@ method_commands_internal (int command, MonoMethod *method, MonoDomain *domain, g tmp_context.method_inst = ginst; inflated = mono_class_inflate_generic_method_checked (method, &tmp_context, error); - g_assert (is_ok (error)); /* FIXME don't swallow the error */ + if (!is_ok (error)) { + add_error_string (buf, mono_error_get_message (error)); + mono_error_cleanup (error); + return ERR_INVALID_ARGUMENT; + } if (!mono_verifier_is_method_valid_generic_instantiation (inflated)) return ERR_INVALID_ARGUMENT; buffer_add_methodid (buf, domain, inflated); @@ -9134,7 +9194,8 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf) mono_loader_lock (); tls = (DebuggerTlsData *)mono_g_hash_table_lookup (thread_to_tls, thread); mono_loader_unlock (); - g_assert (tls); + if (tls == NULL) + return ERR_UNLOADED; compute_frame_info (thread, tls, TRUE); //the last parameter is TRUE to force that the frame info that will be send is synchronised with the debugged thread @@ -9470,7 +9531,10 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf) set_interp_var (m_class_get_this_arg (frame->actual_method->klass), addr, val_buf); } else { var = jit->this_var; - g_assert (var); + if (!var) { + add_error_string (buf, "Invalid this object"); + return ERR_INVALID_ARGUMENT; + } set_var (m_class_get_this_arg (frame->actual_method->klass), var, &frame->ctx, frame->de.domain, val_buf, frame->reg_locations, &tls->restore_state.ctx); } @@ -9513,9 +9577,11 @@ array_commands (int command, guint8 *p, guint8 *end, Buffer *buf) index = decode_int (p, &p, end); len = decode_int (p, &p, end); - g_assert (index >= 0 && len >= 0); + if (index < 0 || len < 0) + return ERR_INVALID_ARGUMENT; // Reordered to avoid integer overflow - g_assert (!(index > arr->max_length - len)); + if (index > arr->max_length - len) + return ERR_INVALID_ARGUMENT; esize = mono_array_element_size (arr->obj.vtable->klass); for (i = index; i < index + len; ++i) { @@ -9527,9 +9593,11 @@ array_commands (int command, guint8 *p, guint8 *end, Buffer *buf) index = decode_int (p, &p, end); len = decode_int (p, &p, end); - g_assert (index >= 0 && len >= 0); + if (index < 0 || len < 0) + return ERR_INVALID_ARGUMENT; // Reordered to avoid integer overflow - g_assert (!(index > arr->max_length - len)); + if (index > arr->max_length - len) + return ERR_INVALID_ARGUMENT; esize = mono_array_element_size (arr->obj.vtable->klass); for (i = index; i < index + len; ++i) { @@ -9571,7 +9639,7 @@ string_commands (int command, guint8 *p, guint8 *end, Buffer *buf) } if (use_utf16) { buffer_add_int (buf, mono_string_length_internal (str) * 2); - buffer_add_data (buf, (guint8*)mono_string_chars_internal (str), mono_string_length_internal (str) * 2); + buffer_add_utf16 (buf, (guint8*)mono_string_chars_internal (str), mono_string_length_internal (str) * 2); } else { ERROR_DECL (error); s = mono_string_to_utf8_checked_internal (str, error); diff --git a/src/mono/mono/mini/decompose.c b/src/mono/mono/mini/decompose.c index bb1916d3b8c061..b36a7ecc255a33 100644 --- a/src/mono/mono/mini/decompose.c +++ b/src/mono/mono/mini/decompose.c @@ -430,18 +430,6 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins) ins->opcode = OP_FMOVE; break; - case OP_FCONV_TO_OVF_I1_UN: - case OP_FCONV_TO_OVF_I2_UN: - case OP_FCONV_TO_OVF_I4_UN: - case OP_FCONV_TO_OVF_I8_UN: - case OP_FCONV_TO_OVF_U1_UN: - case OP_FCONV_TO_OVF_U2_UN: - case OP_FCONV_TO_OVF_U4_UN: - case OP_FCONV_TO_OVF_I_UN: - case OP_FCONV_TO_OVF_U_UN: - mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("float conv.ovf.un opcodes not supported.")); - break; - case OP_IDIV: case OP_IREM: case OP_IDIV_UN: diff --git a/src/mono/mono/mini/dwarfwriter.c b/src/mono/mono/mini/dwarfwriter.c index bf2ff736feb33f..c93151ec613c4f 100644 --- a/src/mono/mono/mini/dwarfwriter.c +++ b/src/mono/mono/mini/dwarfwriter.c @@ -181,6 +181,12 @@ emit_int32 (MonoDwarfWriter *w, int value) mono_img_writer_emit_int32 (w->w, value); } +static void +emit_symbol (MonoDwarfWriter *w, const char *symbol) +{ + mono_img_writer_emit_symbol (w->w, symbol); +} + static void emit_symbol_diff (MonoDwarfWriter *w, const char *end, const char* start, int offset) { @@ -799,6 +805,7 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, const char *cu_name, GSLis w->cie_program = base_unwind_program; emit_section_change (w, ".debug_abbrev", 0); + emit_label (w, ".Ldebug_abbrev_start"); emit_dwarf_abbrev (w, ABBREV_COMPILE_UNIT, DW_TAG_compile_unit, TRUE, compile_unit_attr, G_N_ELEMENTS (compile_unit_attr)); emit_dwarf_abbrev (w, ABBREV_SUBPROGRAM, DW_TAG_subprogram, TRUE, @@ -842,7 +849,7 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, const char *cu_name, GSLis emit_symbol_diff (w, ".Ldebug_info_end", ".Ldebug_info_begin", 0); /* length */ emit_label (w, ".Ldebug_info_begin"); emit_int16 (w, 0x2); /* DWARF version 2 */ - emit_int32 (w, 0); /* .debug_abbrev offset */ + emit_symbol (w, ".Ldebug_abbrev_start"); /* .debug_abbrev offset */ emit_byte (w, sizeof (target_mgreg_t)); /* address size */ /* Compilation unit */ diff --git a/src/mono/mono/mini/exceptions-s390x.c b/src/mono/mono/mini/exceptions-s390x.c index a64d657edca6c4..82ea9232d80936 100644 --- a/src/mono/mono/mini/exceptions-s390x.c +++ b/src/mono/mono/mini/exceptions-s390x.c @@ -58,6 +58,7 @@ #include #include #include +#include #include "mini.h" #include "mini-s390x.h" @@ -495,6 +496,7 @@ mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, StackFrameInfo *frame) { gpointer ip = (gpointer) MONO_CONTEXT_GET_IP (ctx); + guint8 *epilog = NULL; memset (frame, 0, sizeof (StackFrameInfo)); frame->ji = ji; @@ -517,10 +519,13 @@ mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, address = (char *)ip - (char *)ji->code_start; + if (ji->has_arch_eh_info) + epilog = (guint8*)ji->code_start + ji->code_size - mono_jinfo_get_epilog_size (ji); + memcpy(®s, &ctx->uc_mcontext.gregs, sizeof(regs)); gboolean success = mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, (guint8 *) ji->code_start + ji->code_size, - ip, NULL, regs, 16, save_locations, + ip, epilog ? &epilog : NULL, regs, 16, save_locations, MONO_MAX_IREGS, &cfa); if (!success) @@ -558,6 +563,85 @@ mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, /*========================= End of Function ========================*/ +static void +altstack_handle_and_restore (MonoContext *ctx, gpointer obj, guint32 flags) +{ + MonoContext mctx; + MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), MONO_CONTEXT_GET_IP (ctx), NULL); + gboolean stack_ovf = (flags & 1) != 0; + gboolean nullref = (flags & 2) != 0; + + if (!ji || (!stack_ovf && !nullref)) { + if (mono_dump_start ()) + mono_handle_native_crash (mono_get_signame (SIGSEGV), ctx, NULL); + /* if couldn't dump or if mono_handle_native_crash returns, abort */ + abort (); + } + + mctx = *ctx; + + mono_handle_exception (&mctx, obj); + if (stack_ovf) { + MonoJitTlsData *jit_tls = mono_tls_get_jit_tls (); + jit_tls->stack_ovf_pending = 1; + } + mono_restore_context (&mctx); +} + +void +mono_arch_handle_altstack_exception (void *sigctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, gpointer fault_addr, gboolean stack_ovf) +{ +#ifdef MONO_ARCH_USE_SIGACTION + MonoContext *uc = (MonoContext *) sigctx; + MonoContext *uc_copy; + MonoException *exc = NULL; + MonoJitTlsData *jit_tls = NULL; + gboolean nullref = TRUE; + uintptr_t sp; + + jit_tls = mono_tls_get_jit_tls(); + g_assert (jit_tls); + + /* use TLS as temporary storage as we want to avoid + * (1) stack allocation on the application stack + * (2) calling malloc, because it is not async-safe + * (3) using a global storage, because this function is not reentrant + * + * tls->orig_ex_ctx is used by the stack walker, which shouldn't be running at this point. + */ + uc_copy = &jit_tls->orig_ex_ctx; + + if (!mono_is_addr_implicit_null_check (fault_addr)) + nullref = FALSE; + + if (stack_ovf) + exc = mono_domain_get ()->stack_overflow_ex; + + /* + * Setup the call frame on the application stack so that control is + * returned there and exception handling can continue. we want the call + * frame to be minimal as possible, for example no argument passing that + * requires allocation on the stack, as this wouldn't be encoded in unwind + * information for the caller frame. + */ + sp = (uintptr_t) (UCONTEXT_SP(uc)); + sp = sp - S390_MINIMAL_STACK_SIZE; + + mono_sigctx_to_monoctx (uc, uc_copy); + g_assert ((uintptr_t) mono_arch_ip_from_context (uc) == (uintptr_t) UCONTEXT_IP (uc_copy)); + + /* At the return form the signal handler execution starts in altstack_handle_and_restore() */ + UCONTEXT_REG_Rn(uc, 14) = (uintptr_t) UCONTEXT_IP(uc); + UCONTEXT_IP(uc) = (uintptr_t) altstack_handle_and_restore; + UCONTEXT_REG_Rn(uc, 1) = (uintptr_t) sp; + UCONTEXT_REG_Rn(uc, S390_FIRST_ARG_REG) = (uintptr_t) uc_copy; + UCONTEXT_REG_Rn(uc, S390_FIRST_ARG_REG + 1) = (uintptr_t) exc; + UCONTEXT_REG_Rn(uc, S390_FIRST_ARG_REG + 2) = (stack_ovf ? 1 : 0) | (nullref ? 2 : 0); +#endif +} + +/*========================= End of Function ========================*/ + /*------------------------------------------------------------------*/ /* */ /* Name - handle_signal_exception */ @@ -683,6 +767,25 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) /*========================= End of Function ========================*/ +/** + * + * @brief Setup CTX so execution resumes at FUNC + * + * @param[in] Context to be resumed + * @param[in] Location to be resumed at + * + * Set the IP of the passed context to the address so that on resumption + * we jump to this location + */ + +void +mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func) +{ + MONO_CONTEXT_SET_IP (ctx, func); +} + +/*========================= End of Function ========================*/ + /*------------------------------------------------------------------*/ /* */ /* Name - mono_arch_is_int_overflow */ diff --git a/src/mono/mono/mini/exceptions-x86.c b/src/mono/mono/mini/exceptions-x86.c index 22e54bc9258a51..d8f6f769a1c519 100644 --- a/src/mono/mono/mini/exceptions-x86.c +++ b/src/mono/mono/mini/exceptions-x86.c @@ -1242,3 +1242,15 @@ mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func) MONO_CONTEXT_SET_IP (ctx, func); } + +void +mono_arch_undo_ip_adjustment (MonoContext *ctx) +{ + ctx->eip++; +} + +void +mono_arch_do_ip_adjustment (MonoContext *ctx) +{ + ctx->eip--; +} diff --git a/src/mono/mono/mini/iltests.il b/src/mono/mono/mini/iltests.il index ba6aba836d4737..93076a944ca0bc 100644 --- a/src/mono/mono/mini/iltests.il +++ b/src/mono/mono/mini/iltests.il @@ -17,7 +17,7 @@ .method static public int32 Main(string[] args) il managed { .entrypoint - + ldtoken Tests call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) ldarg.0 @@ -3557,4 +3557,292 @@ L3: IL_0024: ret } + .method private hidebysig static int32 validate_alloc_array_length_lbound(class [mscorlib]System.Array test_array) cil managed + { + // Code size 88 (0x58) + .maxstack 2 + .locals init ([0] bool V_0, [1] int32 V_1, [2] bool V_2, [3] bool V_3, [4] bool V_4) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: callvirt instance int32 [mscorlib]System.Array::get_Length() + IL_0007: ldc.i4.6 + IL_0008: ceq + IL_000a: ldc.i4.0 + IL_000b: ceq + IL_000d: stloc.0 + IL_000e: ldloc.0 + IL_000f: brfalse.s IL_0015 + IL_0011: ldc.i4.1 + IL_0012: stloc.1 + IL_0013: br.s IL_0056 + IL_0015: ldarg.0 + IL_0016: callvirt instance int32 [mscorlib]System.Array::get_Rank() + IL_001b: ldc.i4.1 + IL_001c: ceq + IL_001e: ldc.i4.0 + IL_001f: ceq + IL_0021: stloc.2 + IL_0022: ldloc.2 + IL_0023: brfalse.s IL_0029 + IL_0025: ldc.i4.2 + IL_0026: stloc.1 + IL_0027: br.s IL_0056 + IL_0029: ldarg.0 + IL_002a: ldc.i4.0 + IL_002b: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0030: ldc.i4 0x2710 + IL_0031: cgt.un + IL_0033: stloc.3 + IL_0034: ldloc.3 + IL_0035: brfalse.s IL_003b + IL_0037: ldc.i4.3 + IL_0038: stloc.1 + IL_0039: br.s IL_0056 + IL_003b: ldarg.0 + IL_003c: ldc.i4.0 + IL_003d: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0042: ldc.i4 0x2715 + IL_0043: ceq + IL_0045: ldc.i4.0 + IL_0046: ceq + IL_0048: stloc.s V_4 + IL_004a: ldloc.s V_4 + IL_004c: brfalse.s IL_0052 + IL_004e: ldc.i4.4 + IL_004f: stloc.1 + IL_0050: br.s IL_0056 + IL_0052: ldc.i4.0 + IL_0053: stloc.1 + IL_0054: br.s IL_0056 + IL_0056: ldloc.1 + IL_0057: ret + } + + .method public hidebysig static int32 test_0_alloc_array_int16_length_lbound() cil managed + { + .maxstack 2 + .locals init ([0] int16[] test_array, [1] int32 V_1) + ldc.i4 10000 + ldc.i4 6 + newobj instance void int16[10000...10005]::.ctor(int32, int32) + call int32 class Tests::validate_alloc_array_length_lbound(class [mscorlib]System.Array) + ret + } + + .method public hidebysig static int32 test_0_alloc_array_int32_length_lbound() cil managed + { + .maxstack 2 + .locals init ([0] int32[] test_array, [1] int32 V_1) + ldc.i4 10000 + ldc.i4 6 + newobj instance void int32[10000...10005]::.ctor(int32, int32) + call int32 class Tests::validate_alloc_array_length_lbound(class [mscorlib]System.Array) + ret + } + + .method public hidebysig static int32 test_0_alloc_array_int64_length_lbound() cil managed + { + .maxstack 2 + .locals init ([0] int64[] test_array, [1] int32 V_1) + ldc.i4 10000 + ldc.i4 6 + newobj instance void int64[10000...10005]::.ctor(int32, int32) + call int32 class Tests::validate_alloc_array_length_lbound(class [mscorlib]System.Array) + ret + } + + .method public hidebysig static int32 test_0_alloc_array_float32_length_lbound() cil managed + { + .maxstack 2 + .locals init ([0] float32[] test_array, [1] int32 V_1) + ldc.i4 10000 + ldc.i4 6 + newobj instance void float32[10000...10005]::.ctor(int32, int32) + call int32 class Tests::validate_alloc_array_length_lbound(class [mscorlib]System.Array) + ret + } + + .method public hidebysig static int32 test_0_alloc_array_float64_length_lbound() cil managed + { + .maxstack 2 + .locals init ([0] float64[] test_array, [1] int32 V_1) + ldc.i4 10000 + ldc.i4 6 + newobj instance void float64[10000...10005]::.ctor(int32, int32) + call int32 class Tests::validate_alloc_array_length_lbound(class [mscorlib]System.Array) + ret + } + + .method private hidebysig static int32 test_0_two_dimensional_array_bounds() cil managed + { + .maxstack 5 + .locals init (int32[,] arr) + ldc.i4 100 + ldc.i4 27 + ldc.i4 200 + ldc.i4 31 + newobj instance void int32[,]::.ctor(int32, int32, int32, int32) + stloc arr + + ldc.i4 1 + ldloc arr + ldc.i4 0 + callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + ldc.i4 100 + bne.un exit + pop + + ldc.i4 2 + ldloc arr + ldc.i4 0 + callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + ldc.i4 126 + bne.un exit + pop + + ldc.i4 3 + ldloc arr + ldc.i4 1 + callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + ldc.i4 200 + bne.un exit + pop + + ldc.i4 4 + ldloc arr + ldc.i4 1 + callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + ldc.i4 230 + bne.un exit + pop + + ldc.i4 5 + ldloc arr + ldc.i4 100 + ldc.i4 200 + ldc.i4 1234 + call instance void int32[,]::Set(int32, int32, int32) + ldloc arr + ldc.i4 100 + ldc.i4 200 + call instance int32 int32[,]::Get(int32, int32) + ldc.i4 1234 + bne.un exit + pop + + ldc.i4 6 + ldloc arr + ldc.i4 126 + ldc.i4 230 + ldc.i4 5678 + call instance void int32[,]::Set(int32, int32, int32) + ldloc arr + ldc.i4 126 + ldc.i4 230 + call instance int32 int32[,]::Get(int32, int32) + ldc.i4 5678 + bne.un exit + pop + + ldc.i4 0 + exit: + ret + } + + .method private hidebysig static int32 test_0_five_dimensional_array() cil managed + { + .maxstack 12 + .locals init (int32[,,,,] arr) + ldc.i4 100 + ldc.i4 2 + ldc.i4 200 + ldc.i4 3 + ldc.i4 300 + ldc.i4 4 + ldc.i4 400 + ldc.i4 5 + ldc.i4 500 + ldc.i4 6 + newobj instance void int32[,,,,]::.ctor( + int32, int32, int32, int32, int32, int32, + int32, int32, int32, int32) + stloc arr + + ldc.i4 1 + ldloc arr + ldc.i4 0 + callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + ldc.i4 100 + bne.un exit + pop + + ldc.i4 2 + ldloc arr + ldc.i4 0 + callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + ldc.i4 101 + bne.un exit + pop + + ldc.i4 3 + ldloc arr + ldc.i4 4 + callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + ldc.i4 500 + bne.un exit + pop + + ldc.i4 4 + ldloc arr + ldc.i4 4 + callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + ldc.i4 505 + bne.un exit + pop + + ldc.i4 5 + ldloc arr + ldc.i4 100 + ldc.i4 200 + ldc.i4 300 + ldc.i4 400 + ldc.i4 500 + ldc.i4 1234 + call instance void int32[,,,,]::Set(int32, int32, int32, int32, int32, int32) + ldloc arr + ldc.i4 100 + ldc.i4 200 + ldc.i4 300 + ldc.i4 400 + ldc.i4 500 + call instance int32 int32[,,,,]::Get(int32, int32, int32, int32, int32) + ldc.i4 1234 + bne.un exit + pop + + ldc.i4 6 + ldloc arr + ldc.i4 101 + ldc.i4 202 + ldc.i4 303 + ldc.i4 404 + ldc.i4 505 + ldc.i4 5678 + call instance void int32[,,,,]::Set(int32, int32, int32, int32, int32, int32) + ldloc arr + ldc.i4 101 + ldc.i4 202 + ldc.i4 303 + ldc.i4 404 + ldc.i4 505 + call instance int32 int32[,,,,]::Get(int32, int32, int32, int32, int32) + ldc.i4 5678 + bne.un exit + pop + + ldc.i4 0 + exit: + ret + } + } diff --git a/src/mono/mono/mini/image-writer.c b/src/mono/mono/mini/image-writer.c index 7314c5ee8308a9..b191269667aa4e 100644 --- a/src/mono/mono/mini/image-writer.c +++ b/src/mono/mono/mini/image-writer.c @@ -410,11 +410,14 @@ create_reloc (MonoImageWriter *acfg, const char *end, const char* start, int off BinReloc *reloc; reloc = (BinReloc *)mono_mempool_alloc0 (acfg->mempool, sizeof (BinReloc)); reloc->val1 = mono_mempool_strdup (acfg->mempool, end); - if (strcmp (start, ".") == 0) { - reloc->val2_section = acfg->cur_section; - reloc->val2_offset = acfg->cur_section->cur_offset; - } else { - reloc->val2 = mono_mempool_strdup (acfg->mempool, start); + if (start) + { + if (strcmp (start, ".") == 0) { + reloc->val2_section = acfg->cur_section; + reloc->val2_offset = acfg->cur_section->cur_offset; + } else { + reloc->val2 = mono_mempool_strdup (acfg->mempool, start); + } } reloc->offset = offset; reloc->section = acfg->cur_section; @@ -424,6 +427,13 @@ create_reloc (MonoImageWriter *acfg, const char *end, const char* start, int off return reloc; } +static void +bin_writer_emit_symbol (MonoImageWriter *acfg, const char *symbol) +{ + create_reloc (acfg, symbol, NULL, 0); + acfg->cur_section->cur_offset += 4; +} + static void bin_writer_emit_symbol_diff (MonoImageWriter *acfg, const char *end, const char* start, int offset) { @@ -1924,6 +1934,23 @@ asm_writer_emit_int32 (MonoImageWriter *acfg, int value) fprintf (acfg->fp, "%d", value); } +static void +asm_writer_emit_symbol (MonoImageWriter *acfg, const char *symbol) +{ + if (acfg->mode != EMIT_LONG) { + acfg->mode = EMIT_LONG; + acfg->col_count = 0; + } + + symbol = get_label (symbol); + + if ((acfg->col_count++ % 8) == 0) + fprintf (acfg->fp, "\n\t%s ", AS_INT32_DIRECTIVE); + else + fprintf (acfg->fp, ","); + fprintf (acfg->fp, "%s", symbol); +} + static void asm_writer_emit_symbol_diff (MonoImageWriter *acfg, const char *end, const char* start, int offset) { @@ -2213,6 +2240,19 @@ mono_img_writer_emit_int32 (MonoImageWriter *acfg, int value) #endif } +void +mono_img_writer_emit_symbol (MonoImageWriter *acfg, const char *symbol) +{ +#ifdef USE_BIN_WRITER + if (acfg->use_bin_writer) + bin_writer_emit_symbol (acfg, symbol); + else + asm_writer_emit_symbol (acfg, symbol); +#else + asm_writer_emit_symbol (acfg, symbol); +#endif +} + void mono_img_writer_emit_symbol_diff (MonoImageWriter *acfg, const char *end, const char* start, int offset) { diff --git a/src/mono/mono/mini/image-writer.h b/src/mono/mono/mini/image-writer.h index 0c34246422e8b9..309ec37c059a77 100644 --- a/src/mono/mono/mini/image-writer.h +++ b/src/mono/mono/mini/image-writer.h @@ -98,6 +98,8 @@ void mono_img_writer_emit_int16 (MonoImageWriter *w, int value); void mono_img_writer_emit_int32 (MonoImageWriter *w, int value); +void mono_img_writer_emit_symbol (MonoImageWriter *w, const char *symbol); + void mono_img_writer_emit_symbol_diff (MonoImageWriter *w, const char *end, const char* start, int offset); void mono_img_writer_emit_zero_bytes (MonoImageWriter *w, int num); diff --git a/src/mono/mono/mini/interp/interp-internals.h b/src/mono/mono/mini/interp/interp-internals.h index b335170438670c..b88e969bab9d6a 100644 --- a/src/mono/mono/mini/interp/interp-internals.h +++ b/src/mono/mono/mini/interp/interp-internals.h @@ -151,6 +151,7 @@ struct InterpMethod { gpointer jit_wrapper; gpointer jit_addr; MonoMethodSignature *jit_sig; + gint32 jit_vt_res_size; gpointer jit_entry; gpointer llvmonly_unbox_entry; MonoType *rtype; @@ -181,7 +182,11 @@ typedef struct _StackFragment StackFragment; struct _StackFragment { guint8 *pos, *end; struct _StackFragment *next; - double data [1]; +#if SIZEOF_VOID_P == 4 + /* Align data field to MINT_VT_ALIGNMENT */ + gint32 pad; +#endif + double data [MONO_ZERO_LEN_ARRAY]; }; typedef struct { @@ -201,7 +206,6 @@ typedef struct { const unsigned short *ip; GSList *finally_ips; FrameClauseArgs *clause_args; - gboolean is_void : 1; } InterpState; struct InterpFrame { diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index bd1807c64d1651..4ac1b20a67f183 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -221,12 +221,11 @@ frame_stack_free (FrameStack *stack) * Reinitialize a frame. */ static void -reinit_frame (InterpFrame *frame, InterpFrame *parent, InterpMethod *imethod, stackval *stack_args, stackval *retval) +reinit_frame (InterpFrame *frame, InterpFrame *parent, InterpMethod *imethod, stackval *stack_args) { frame->parent = parent; frame->imethod = imethod; frame->stack_args = stack_args; - frame->retval = retval; frame->stack = NULL; frame->ip = NULL; frame->state.ip = NULL; @@ -1146,22 +1145,25 @@ interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, con static MonoObject* ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error) { - uintptr_t *lengths; - intptr_t *lower_bounds; - int i; - - lengths = g_newa (uintptr_t, m_class_get_rank (klass) * 2); - for (i = 0; i < param_count; ++i) { - lengths [i] = values->data.i; - values ++; - } - if (m_class_get_rank (klass) == param_count) { - /* Only lengths provided. */ - lower_bounds = NULL; - } else { + int rank = m_class_get_rank (klass); + uintptr_t *lengths = g_newa (uintptr_t, rank * 2); + intptr_t *lower_bounds = NULL; + if (2 * rank == param_count) { + for (int l = 0; l < 2; ++l) { + int src = l; + int dst = l * rank; + for (int r = 0; r < rank; ++r, src += 2, ++dst) { + lengths [dst] = values [src].data.i; + } + } /* lower bounds are first. */ lower_bounds = (intptr_t *) lengths; - lengths += m_class_get_rank (klass); + lengths += rank; + } else { + /* Only lengths provided. */ + for (int i = 0; i < param_count; ++i) { + lengths [i] = values [i].data.i; + } } return (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, error); } @@ -1287,16 +1289,9 @@ static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, Int break; #endif case MONO_TYPE_R4: -#if SIZEOF_VOID_P == 8 case MONO_TYPE_R8: -#endif margs->flen++; break; -#if SIZEOF_VOID_P == 4 - case MONO_TYPE_R8: - margs->flen += 2; - break; -#endif default: g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype); } @@ -1381,11 +1376,7 @@ static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, Int #if DEBUG_INTERP g_print ("build_args_from_sig: margs->fargs [%d]: %p (%f) (frame @ %d)\n", int_f, margs->fargs [int_f], margs->fargs [int_f], i); #endif -#if SIZEOF_VOID_P == 4 - int_f += 2; -#else - int_f++; -#endif + int_f ++; break; default: g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype); @@ -1666,7 +1657,7 @@ interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpoint MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoDelegate, this_obj), interp_method, gpointer, imethod); - mono_delegate_ctor (this_obj, target, entry, error); + mono_delegate_ctor (this_obj, target, entry, imethod->method, error); } /* @@ -2310,6 +2301,21 @@ do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpF rmethod->jit_addr = addr; rmethod->jit_sig = sig; + + if (sig->ret->type != MONO_TYPE_VOID) { + int mt = mint_type (sig->ret); + if (mt == MINT_TYPE_VT) { + MonoClass *klass = mono_class_from_mono_type_internal (sig->ret); + /* + * We cache this size here, instead of the instruction stream of the + * calling instruction, to save space for common callvirt instructions + * that could end up doing a jit call. + */ + gint32 size = mono_class_value_size (klass, NULL); + rmethod->jit_vt_res_size = ALIGN_TO (size, MINT_VT_ALIGNMENT); + } + } + mono_memory_barrier (); rmethod->jit_wrapper = jit_wrapper; @@ -2497,7 +2503,7 @@ do_transform_method (InterpFrame *frame, ThreadContext *context) return mono_error_convert_to_exception (error); } -static guchar* +static void copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, guchar *vt_sp_start) { stackval *first_arg = sp - csig->param_count; @@ -2506,8 +2512,9 @@ copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, guchar *vt_sp_sta /* * We need to have the varargs linearly on the stack so the ArgIterator * can iterate over them. We pass the signature first and then copy them - * one by one on the vtstack. At the end we pass the original vt_stack - * so the callee (MINT_ARGLIST) can find the varargs space. + * one by one on the vtstack. The callee (MINT_ARGLIST) will be able to + * find this space by adding the current vt_sp pointer in the parent frame + * with the amount of vtstack space used by the parameters. */ *(gpointer*)vt_sp = csig; vt_sp += sizeof (gpointer); @@ -2520,13 +2527,6 @@ copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, guchar *vt_sp_sta stackval_to_data (csig->params [i], &first_arg [i], vt_sp, FALSE); vt_sp += arg_size; } - - vt_sp += sizeof (gpointer); - vt_sp = (guchar*)ALIGN_PTR_TO (vt_sp, MINT_VT_ALIGNMENT); - - ((gpointer*)vt_sp) [-1] = vt_sp_start; - - return vt_sp; } /* @@ -2539,8 +2539,6 @@ copy_varargs_vtstack (MonoMethodSignature *csig, stackval *sp, guchar *vt_sp_sta * this/static * ret/void * 16 arguments -> 64 functions. */ -#define MAX_INTERP_ENTRY_ARGS 8 - #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \ InterpEntryData data; \ (data).rmethod = (_method); \ @@ -2827,8 +2825,14 @@ interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoE * to use a ftndesc. The caller uses a normal signature, while the * entry functions use a gsharedvt_in signature, so wrap the entry function in * a gsharedvt_in_sig wrapper. + * We use a gsharedvt_in_sig wrapper instead of an interp_in wrapper, because they + * are mostly the same, and they are already generated. The exception is the + * wrappers for methods with more than 8 arguments, those are different. */ - wrapper = mini_get_gsharedvt_in_sig_wrapper (sig); + if (sig->param_count > MAX_INTERP_ENTRY_ARGS) + wrapper = mini_get_interp_in_wrapper (sig); + else + wrapper = mini_get_gsharedvt_in_sig_wrapper (sig); entry_wrapper = mono_jit_compile_method_jit_only (wrapper, error); mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"", @@ -2836,8 +2840,7 @@ interp_create_method_pointer_llvmonly (MonoMethod *method, gboolean unbox, MonoE mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL)); if (sig->param_count > MAX_INTERP_ENTRY_ARGS) { - g_assert_not_reached (); - //entry_func = (gpointer)interp_entry_general; + entry_func = (gpointer)interp_entry_general; } else if (sig->hasthis) { if (sig->ret->type == MONO_TYPE_VOID) entry_func = entry_funcs_instance [sig->param_count]; @@ -2949,7 +2952,7 @@ interp_create_method_pointer (MonoMethod *method, gboolean compile, MonoError *e } } else { #ifndef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE - mono_error_assertf_ok (error, "couldn't compile wrapper \"%s\" for \"%s\"", + g_assertion_message ("couldn't compile wrapper \"%s\" for \"%s\"", mono_method_get_name_full (wrapper, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL), mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL)); #else @@ -3137,25 +3140,10 @@ mono_interp_isinst (MonoObject* object, MonoClass* klass) return isinst; } -// Do not inline use of alloca. -// Do not inline in case order of frame addresses matters. -static MONO_NEVER_INLINE void -mono_interp_calli_nat_dynamic_pinvoke ( - // Parameters are sorted by name. - guchar* code, - ThreadContext* context, - MonoMethodSignature* csignature, - MonoError* error, - InterpFrame *parent_frame, - stackval *retval, - stackval *sp) +static MONO_NEVER_INLINE InterpMethod* +mono_interp_get_native_func_wrapper (InterpMethod* imethod, MonoMethodSignature* csignature, guchar* code) { - InterpFrame frame = {parent_frame, NULL, sp, retval}; - - // Recompute to limit parameters, which can also contribute to caller stack. - InterpMethod* const imethod = parent_frame->imethod; - - g_assert (imethod->method->dynamic && csignature->pinvoke); + ERROR_DECL(error); /* Pinvoke call is missing the wrapper. See mono_get_native_calli_wrapper */ MonoMarshalSpec** mspecs = g_newa0 (MonoMarshalSpec*, csignature->param_count + 1); @@ -3169,13 +3157,10 @@ mono_interp_calli_nat_dynamic_pinvoke ( if (mspecs [i]) mono_metadata_free_marshal_spec (mspecs [i]); - { - ERROR_DECL (error); - frame.imethod = mono_interp_get_imethod (imethod->domain, m, error); - mono_error_cleanup (error); /* FIXME: don't swallow the error */ - } + InterpMethod *cmethod = mono_interp_get_imethod (imethod->domain, m, error); + mono_error_cleanup (error); /* FIXME: don't swallow the error */ - interp_exec_method (&frame, context, NULL, error); + return cmethod; } // Do not inline in case order of frame addresses matters. @@ -3345,7 +3330,6 @@ method_entry (ThreadContext *context, InterpFrame *frame, frame->state.ip = ip; \ frame->state.sp = sp; \ frame->state.vt_sp = vt_sp; \ - frame->state.is_void = is_void; \ frame->state.finally_ips = finally_ips; \ frame->state.clause_args = clause_args; \ } while (0) @@ -3354,7 +3338,6 @@ method_entry (ThreadContext *context, InterpFrame *frame, #define LOAD_INTERP_STATE(frame) do { \ ip = frame->state.ip; \ sp = frame->state.sp; \ - is_void = frame->state.is_void; \ vt_sp = frame->state.vt_sp; \ finally_ips = frame->state.finally_ips; \ clause_args = frame->state.clause_args; \ @@ -3382,8 +3365,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs { InterpMethod *cmethod; MonoException *ex; - gboolean is_void; - stackval *retval; /* Interpreter main loop state (InterpState) */ const guint16 *ip = NULL; @@ -3435,13 +3416,13 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs #if defined(ENABLE_HYBRID_SUSPEND) || defined(ENABLE_COOP_SUSPEND) mono_threads_safepoint (); #endif +main_loop: /* * using while (ip < end) may result in a 15% performance drop, * but it may be useful for debug */ while (1) { MintOpcode opcode; -main_loop: /* g_assert (sp >= frame->stack); */ /* g_assert(vt_sp - vtalloc <= frame->imethod->vt_stack_size); */ DUMP_INSTR(); @@ -3469,7 +3450,12 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; MINT_IN_CASE(MINT_ARGLIST) sp->data.p = vt_sp; - *(gpointer*)sp->data.p = ((gpointer*)frame->retval->data.p) [-1]; + /* + * We know we have been called by an MINT_CALL_VARARG and the amount of vtstack + * used by the parameters is at ip [-1] (the last argument to MINT_CALL_VARARG that + * is embedded in the instruction stream). + */ + *(gpointer*)sp->data.p = frame->parent->state.vt_sp + frame->parent->state.ip [-1]; vt_sp += ALIGN_TO (sizeof (gpointer), MINT_VT_ALIGNMENT); ++ip; ++sp; @@ -3572,6 +3558,13 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs ip++; MINT_IN_BREAK; } + MINT_IN_CASE(MINT_POP_VT) { + int i32 = READ32 (ip + 1); + vt_sp -= ALIGN_TO (i32, MINT_VT_ALIGNMENT); + sp--; + ip += 3; + MINT_IN_BREAK; + } MINT_IN_CASE(MINT_POP1) { sp [-2] = sp [-1]; sp--; @@ -3617,7 +3610,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs } MINT_IN_CASE(MINT_CALL_DELEGATE) { MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]]; - is_void = csignature->ret->type == MONO_TYPE_VOID; int param_count = csignature->param_count; MonoDelegate *del = (MonoDelegate*) sp [-param_count - 1].data.o; gboolean is_multicast = del->method == NULL; @@ -3656,8 +3648,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs } } cmethod = del_imethod; - retval = sp; - sp->data.p = vt_sp; + vt_sp -= ip [2]; sp -= param_count + 1; if (!is_multicast) { if (cmethod->param_count == param_count + 1) { @@ -3681,7 +3672,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs memmove (sp, sp + 1, param_count * sizeof (stackval)); } } - ip += 2; + ip += 3; goto call; } @@ -3691,7 +3682,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs frame->ip = ip; csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]]; - ip += 2; --sp; cmethod = (InterpMethod*)sp->data.p; @@ -3700,14 +3690,11 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */ } - is_void = csignature->ret->type == MONO_TYPE_VOID; - retval = is_void ? NULL : sp; - - sp->data.p = vt_sp; /* decrement by the actual number of args */ sp -= csignature->param_count; if (csignature->hasthis) --sp; + vt_sp -= ip [2]; if (csignature->hasthis) { MonoObject *this_arg = (MonoObject*)sp->data.p; @@ -3717,6 +3704,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs sp [0].data.p = unboxed; } } + ip += 3; goto call; } @@ -3735,58 +3723,73 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs ip += 4; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_CALLI_NAT) { + MINT_IN_CASE(MINT_CALLI_NAT_DYNAMIC) { MonoMethodSignature* csignature; frame->ip = ip; csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]]; + --sp; + guchar* code = (guchar*)sp->data.p; + + /* decrement by the actual number of args */ + sp -= csignature->param_count; + if (csignature->hasthis) + --sp; + vt_sp -= ip [2]; + + cmethod = mono_interp_get_native_func_wrapper (frame->imethod, csignature, code); + ip += 3; + goto call; + } + MINT_IN_CASE(MINT_CALLI_NAT) { + MonoMethodSignature* csignature; + stackval retval; + + frame->ip = ip; + + csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]]; + --sp; guchar* const code = (guchar*)sp->data.p; - retval = sp; - sp->data.p = vt_sp; /* decrement by the actual number of args */ sp -= csignature->param_count; if (csignature->hasthis) --sp; + vt_sp -= ip [2]; + /* If this is a vt return, the pinvoke will write the result directly to vt_sp */ + retval.data.p = vt_sp; - if (frame->imethod->method->dynamic && csignature->pinvoke) { - mono_interp_calli_nat_dynamic_pinvoke (code, context, csignature, error, frame, retval, sp); - } else { - const gboolean save_last_error = ip [-3 + 2]; - ves_pinvoke_method (csignature, (MonoFuncV)code, context, frame, retval, save_last_error, sp); - } + gboolean save_last_error = ip [4]; + ves_pinvoke_method (csignature, (MonoFuncV)code, context, frame, &retval, save_last_error, sp); CHECK_RESUME_STATE (context); if (csignature->ret->type != MONO_TYPE_VOID) { - *sp = *retval; + *sp = retval; + vt_sp += ip [3]; sp++; } + ip += 5; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_CALLVIRT_FAST) - MINT_IN_CASE(MINT_VCALLVIRT_FAST) { + MINT_IN_CASE(MINT_CALLVIRT_FAST) { MonoObject *this_arg; - is_void = *ip == MINT_VCALLVIRT_FAST; int slot; frame->ip = ip; cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]]; slot = (gint16)ip [2]; - ip += 3; - sp->data.p = vt_sp; - - retval = is_void ? NULL : sp; /* decrement by the actual number of args */ sp -= cmethod->param_count + cmethod->hasthis; - + vt_sp -= ip [3]; this_arg = (MonoObject*)sp->data.p; + ip += 4; cmethod = get_virtual_method_fast (cmethod, this_arg->vtable, slot); if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) { @@ -3824,8 +3827,10 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs CHECK_RESUME_STATE (context); - if (cmethod->rtype->type != MONO_TYPE_VOID) + if (cmethod->rtype->type != MONO_TYPE_VOID) { sp++; + vt_sp += cmethod->jit_vt_res_size; + } } MINT_IN_BREAK; @@ -3839,59 +3844,56 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs csig = (MonoMethodSignature*) frame->imethod->data_items [ip [2]]; frame->ip = ip; - - // Retval must be set unconditionally due to MINT_ARGLIST. - // is_void guides exit_frame instead of retval nullness. - retval = sp; - is_void = csig->ret->type == MONO_TYPE_VOID; - /* Push all vararg arguments from normal sp to vt_sp together with the signature */ - vt_sp = copy_varargs_vtstack (csig, sp, vt_sp); - - ip += 3; - sp->data.p = vt_sp; + copy_varargs_vtstack (csig, sp, vt_sp); + vt_sp -= ip [3]; /* decrement by the actual number of args */ // FIXME This seems excessive: frame and csig param_count. sp -= cmethod->param_count + cmethod->hasthis + csig->param_count - csig->sentinelpos; + ip += 4; goto call; } - MINT_IN_CASE(MINT_VCALL) - MINT_IN_CASE(MINT_CALL) - MINT_IN_CASE(MINT_CALLVIRT) - MINT_IN_CASE(MINT_VCALLVIRT) { + MINT_IN_CASE(MINT_CALLVIRT) { // FIXME CALLVIRT opcodes are not used on netcore. We should kill them. - // FIXME braces from here until call: label. - is_void = *ip == MINT_VCALL || *ip == MINT_VCALLVIRT; - gboolean is_virtual; - is_virtual = *ip == MINT_CALLVIRT || *ip == MINT_VCALLVIRT; - cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]]; - sp->data.p = vt_sp; - retval = is_void ? NULL : sp; /* decrement by the actual number of args */ sp -= ip [2]; + vt_sp -= ip [3]; - if (is_virtual) { - MonoObject *this_arg = (MonoObject*)sp->data.p; + MonoObject *this_arg = (MonoObject*)sp->data.p; - cmethod = get_virtual_method (cmethod, this_arg->vtable); - if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) { - /* unbox */ - gpointer unboxed = mono_object_unbox_internal (this_arg); - sp [0].data.p = unboxed; - } + cmethod = get_virtual_method (cmethod, this_arg->vtable); + if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) { + /* unbox */ + gpointer unboxed = mono_object_unbox_internal (this_arg); + sp [0].data.p = unboxed; } frame->ip = ip; #ifdef ENABLE_EXPERIMENT_TIERED ip += 5; #else - ip += 3; + ip += 4; +#endif + goto call; + } + MINT_IN_CASE(MINT_CALL) { + cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]]; + + /* decrement by the actual number of args */ + sp -= ip [2]; + vt_sp -= ip [3]; + + frame->ip = ip; +#ifdef ENABLE_EXPERIMENT_TIERED + ip += 5; +#else + ip += 4; #endif -call:; +call: /* * Make a non-recursive call by loading the new interpreter state based on child frame, * and going back to the main loop. @@ -3907,7 +3909,7 @@ call:; // Not free currently, but will be when allocation attempted. frame->next_free = child_frame; } - reinit_frame (child_frame, frame, cmethod, sp, retval); + reinit_frame (child_frame, frame, cmethod, sp); frame = child_frame; } if (method_entry (context, frame, @@ -3930,18 +3932,21 @@ call:; error_init_reuse (error); frame->ip = ip; sp -= rmethod->param_count + rmethod->hasthis; + vt_sp -= ip [2]; do_jit_call (sp, vt_sp, context, frame, rmethod, error); if (!is_ok (error)) { MonoException *ex = mono_error_convert_to_exception (error); THROW_EX (ex, ip); } - ip += 2; CHECK_RESUME_STATE (context); - if (rmethod->rtype->type != MONO_TYPE_VOID) + if (rmethod->rtype->type != MONO_TYPE_VOID) { sp++; + vt_sp += rmethod->jit_vt_res_size; + } + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_JIT_CALL2) { @@ -3974,7 +3979,7 @@ call:; MonoMethodSignature *sig = (MonoMethodSignature*) frame->imethod->data_items [ip [2]]; sp->data.p = vt_sp; - retval = sp; + stackval *retval = sp; sp -= sig->param_count; if (sig->hasthis) @@ -3996,7 +4001,13 @@ call:; } MINT_IN_CASE(MINT_RET) --sp; - *frame->retval = *sp; + if (frame->parent) { + frame->parent->state.sp [0] = *sp; + frame->parent->state.sp++; + } else { + // FIXME This can only happen in a few wrappers. Add separate opcode for it + *frame->retval = *sp; + } if (sp > frame->stack) g_warning_d ("ret: more values on stack: %d", sp - frame->stack); goto exit_frame; @@ -4005,9 +4016,19 @@ call:; g_warning_ds ("ret.void: more values on stack: %d %s", sp - frame->stack, mono_method_full_name (frame->imethod->method, TRUE)); goto exit_frame; MINT_IN_CASE(MINT_RET_VT) { + gpointer dest_vt; int const i32 = READ32 (ip + 1); --sp; - memcpy(frame->retval->data.p, sp->data.p, i32); + if (frame->parent) { + dest_vt = frame->parent->state.vt_sp; + /* Push the valuetype in the parent frame */ + frame->parent->state.sp [0].data.p = dest_vt; + frame->parent->state.sp++; + frame->parent->state.vt_sp += ALIGN_TO (i32, MINT_VT_ALIGNMENT); + } else { + dest_vt = frame->retval->data.p; + } + memcpy (dest_vt, sp->data.p, i32); if (sp > frame->stack) g_warning_d ("ret.vt: more values on stack: %d", sp - frame->stack); goto exit_frame; @@ -4977,6 +4998,22 @@ call:; ip += 3; MINT_IN_BREAK; } + MINT_IN_CASE(MINT_NEWOBJ_STRING) { + frame->ip = ip; + + cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]]; + + const int param_count = ip [2]; + if (param_count) { + sp -= param_count; + memmove (sp + 1, sp, param_count * sizeof (stackval)); + } + // `this` is implicit null. The created string will be returned + // by the call, even though the call has void return (?!). + sp->data.p = NULL; + ip += 3; + goto call; + } MINT_IN_CASE(MINT_NEWOBJ_FAST) { MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [3]]; INIT_VTABLE (vtable); @@ -5060,8 +5097,6 @@ call:; // on the stack before the call, instead of the call forming it. call_newobj: ++sp; // Point sp at added extra param, after return value. - is_void = TRUE; - retval = NULL; goto call; MINT_IN_CASE(MINT_NEWOBJ) { @@ -5099,15 +5134,6 @@ call:; g_assert (!m_class_is_valuetype (newobj_class)); - // This branch could be avoided. Move it to transform, and use a new opcode NEWOBJ_STRING. - if (newobj_class == mono_defaults.string_class) { - retval = sp; - ++sp; - sp->data.p = NULL; // first parameter - is_void = TRUE; - goto call; - } - MonoDomain* const domain = frame->imethod->domain; MonoVTable *vtable = mono_class_vtable_checked (domain, newobj_class, error); if (!is_ok (error) || !mono_runtime_class_init_full (vtable, error)) { @@ -5140,26 +5166,13 @@ call:; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_CTOR) { - MonoMethodSignature *csig; - guint32 token; - - frame->ip = ip; - token = ip [1]; - ip += 2; - - InterpMethod *cmethod = (InterpMethod*)frame->imethod->data_items [token]; - csig = mono_method_signature_internal (cmethod->method); - - g_assert (csig->hasthis); - sp -= csig->param_count; - - gpointer arg0 = sp [0].data.p; - + gpointer arg0 = sp [-1].data.p; gpointer *byreference_this = (gpointer*)vt_sp; *byreference_this = arg0; /* Followed by a VTRESULT opcode which will push the result on the stack */ - ++sp; + /* FIXME kill MINT_VTRESULT */ + ip++; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) { @@ -7186,8 +7199,6 @@ call:; if (!clause_args && frame->parent && frame->parent->state.ip) { /* Return to the main loop after a non-recursive interpreter call */ //printf ("R: %s -> %s %p\n", mono_method_get_full_name (frame->imethod->method), mono_method_get_full_name (frame->parent->imethod->method), frame->parent->state.ip); - stackval *retval = frame->retval; - InterpFrame* const child_frame = frame; frame = frame->parent; @@ -7197,10 +7208,6 @@ call:; CHECK_RESUME_STATE (context); - if (!is_void) { - *sp = *retval; - sp ++; - } goto main_loop; } diff --git a/src/mono/mono/mini/interp/interp.h b/src/mono/mono/mini/interp/interp.h index 40c9e96829e23b..198d423f7f4f51 100644 --- a/src/mono/mono/mini/interp/interp.h +++ b/src/mono/mono/mini/interp/interp.h @@ -14,6 +14,8 @@ #define INTERP_ICALL_TRAMP_FARGS 4 #endif +#define MAX_INTERP_ENTRY_ARGS 8 + struct _InterpMethodArguments { size_t ilen; gpointer *iargs; diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 15171dcd00e89d..fd8691ba36b131 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -16,6 +16,7 @@ OPDEF(MINT_LDNULL, "ldnull", 1, Pop0, Push1, MintOpNoArgs) OPDEF(MINT_DUP, "dup", 1, Pop1, Push2, MintOpNoArgs) OPDEF(MINT_DUP_VT, "dup.vt", 3, Pop1, Push2, MintOpInt) OPDEF(MINT_POP, "pop", 1, Pop1, Push0, MintOpNoArgs) +OPDEF(MINT_POP_VT, "pop.vt", 3, Pop1, Push0, MintOpNoArgs) OPDEF(MINT_POP1, "pop1", 1, Pop2, Push1, MintOpNoArgs) OPDEF(MINT_RET, "ret", 1, Pop1, Push0, MintOpNoArgs) @@ -380,6 +381,7 @@ OPDEF(MINT_ENDFILTER, "endfilter", 1, Pop0, Push0, MintOpNoArgs) OPDEF(MINT_NEWOBJ, "newobj", 2, VarPop, Push1, MintOpMethodToken) OPDEF(MINT_NEWOBJ_ARRAY, "newobj_array", 3, VarPop, Push1, MintOpMethodToken) +OPDEF(MINT_NEWOBJ_STRING, "newobj_string", 3, VarPop, Push1, MintOpMethodToken) OPDEF(MINT_NEWOBJ_FAST, "newobj_fast", 4, VarPop, Push1, MintOpMethodToken) OPDEF(MINT_NEWOBJ_VT_FAST, "newobj_vt_fast", 3, VarPop, Push1, MintOpMethodToken) OPDEF(MINT_NEWOBJ_VTST_FAST, "newobj_vtst_fast", 4, VarPop, Push1, MintOpMethodToken) @@ -698,17 +700,15 @@ OPDEF(MINT_ARRAY_ELEMENT_SIZE, "array_element_size", 1, Pop1, Push1, MintOpNoArg OPDEF(MINT_ARRAY_IS_PRIMITIVE, "array_is_primitive", 1, Pop1, Push1, MintOpNoArgs) /* Calls */ -OPDEF(MINT_CALL, "call", 3, VarPop, Push1, MintOpMethodToken) -OPDEF(MINT_VCALL, "vcall", 3, VarPop, Push0, MintOpMethodToken) -OPDEF(MINT_CALLVIRT, "callvirt", 3, VarPop, Push1, MintOpMethodToken) -OPDEF(MINT_VCALLVIRT, "vcallvirt", 3, VarPop, Push0, MintOpMethodToken) -OPDEF(MINT_CALLVIRT_FAST, "callvirt.fast", 3, VarPop, Push1, MintOpMethodToken) -OPDEF(MINT_VCALLVIRT_FAST, "vcallvirt.fast", 3, VarPop, Push0, MintOpMethodToken) -OPDEF(MINT_CALL_DELEGATE, "call.delegate", 2, VarPop, VarPush, MintOpMethodToken) -OPDEF(MINT_CALLI, "calli", 2, VarPop, VarPush, MintOpMethodToken) -OPDEF(MINT_CALLI_NAT, "calli.nat", 3, VarPop, VarPush, MintOpMethodToken) +OPDEF(MINT_CALL, "call", 4, VarPop, Push1, MintOpMethodToken) +OPDEF(MINT_CALLVIRT, "callvirt", 4, VarPop, Push1, MintOpMethodToken) +OPDEF(MINT_CALLVIRT_FAST, "callvirt.fast", 4, VarPop, Push1, MintOpMethodToken) +OPDEF(MINT_CALL_DELEGATE, "call.delegate", 3, VarPop, VarPush, MintOpMethodToken) +OPDEF(MINT_CALLI, "calli", 3, VarPop, VarPush, MintOpMethodToken) +OPDEF(MINT_CALLI_NAT, "calli.nat", 5, VarPop, VarPush, MintOpMethodToken) +OPDEF(MINT_CALLI_NAT_DYNAMIC, "calli.nat.dynamic", 3, VarPop, VarPush, MintOpMethodToken) OPDEF(MINT_CALLI_NAT_FAST, "calli.nat.fast", 4, VarPop, VarPush, MintOpMethodToken) -OPDEF(MINT_CALL_VARARG, "call.vararg", 3, VarPop, VarPush, MintOpMethodToken) +OPDEF(MINT_CALL_VARARG, "call.vararg", 4, VarPop, VarPush, MintOpMethodToken) OPDEF(MINT_CALLRUN, "callrun", 3, VarPop, VarPush, MintOpNoArgs) OPDEF(MINT_ICALL_V_V, "mono_icall_v_v", 2, Pop0, Push0, MintOpClassToken) /* not really */ @@ -726,7 +726,7 @@ OPDEF(MINT_ICALL_PPPPP_P, "mono_icall_ppppp_p", 2, Pop5, Push1, MintOpClassToken OPDEF(MINT_ICALL_PPPPPP_V, "mono_icall_pppppp_v", 2, Pop6, Push0, MintOpClassToken) OPDEF(MINT_ICALL_PPPPPP_P, "mono_icall_pppppp_p", 2, Pop6, Push1, MintOpClassToken) // FIXME: MintOp -OPDEF(MINT_JIT_CALL, "mono_jit_call", 2, VarPop, VarPush, MintOpNoArgs) +OPDEF(MINT_JIT_CALL, "mono_jit_call", 3, VarPop, VarPush, MintOpNoArgs) OPDEF(MINT_JIT_CALL2, "mono_jit_call2", 5, VarPop, VarPush, MintOpNoArgs) OPDEF(MINT_MONO_LDPTR, "mono_ldptr", 2, Pop0, Push1, MintOpClassToken) @@ -811,7 +811,7 @@ OPDEF(MINT_PROF_COVERAGE_STORE, "prof_coverage_store", 5, Pop0, Push0, MintOpLon OPDEF(MINT_INTRINS_ENUM_HASFLAG, "intrins_enum_hasflag", 2, Pop2, Push1, MintOpClassToken) OPDEF(MINT_INTRINS_GET_HASHCODE, "intrins_get_hashcode", 1, Pop1, Push1, MintOpNoArgs) OPDEF(MINT_INTRINS_GET_TYPE, "intrins_get_type", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_INTRINS_BYREFERENCE_CTOR, "intrins_byreference_ctor", 2, VarPop, Push1, MintOpClassToken) +OPDEF(MINT_INTRINS_BYREFERENCE_CTOR, "intrins_byreference_ctor", 1, Pop1, Push1, MintOpClassToken) OPDEF(MINT_INTRINS_BYREFERENCE_GET_VALUE, "intrins_byreference_get_value", 1, Pop1, Push1, MintOpNoArgs) OPDEF(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET, "intrins_unsafe_add_byte_offset", 1, Pop2, Push1, MintOpNoArgs) OPDEF(MINT_INTRINS_UNSAFE_BYTE_OFFSET, "intrins_unsafe_byte_offset", 1, Pop2, Push1, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index cc68c160677bfb..4bca4e3752c660 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2169,7 +2169,6 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target guint32 vt_res_size = 0; int op = -1; int native = 0; - int is_void = 0; int need_null_check = is_virtual; gboolean is_delegate_invoke = FALSE; @@ -2368,10 +2367,12 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target vararg_stack = ALIGN_TO (vararg_stack, align); vararg_stack += arg_size; } - /* allocate space for the pointer to varargs space start */ - vararg_stack += sizeof (gpointer); - vt_stack_used += ALIGN_TO (vararg_stack, MINT_VT_ALIGNMENT); + /* + * MINT_CALL_VARARG needs this space on the vt stack. Make sure the + * vtstack space is sufficient. + */ PUSH_VT (td, vararg_stack); + POP_VT (td, vararg_stack); } if (need_null_check) { @@ -2418,6 +2419,8 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target vt_stack_used += size; } } + /* Pop the vt stack used by the arguments */ + td->vt_sp -= vt_stack_used; /* need to handle typedbyref ... */ if (csignature->ret->type != MONO_TYPE_VOID) { @@ -2435,8 +2438,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target PUSH_VT(td, vt_res_size); } PUSH_TYPE(td, stack_type[mt], klass); - } else - is_void = TRUE; + } if (op >= 0) { interp_add_ins (td, op); @@ -2459,40 +2461,62 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target interp_add_ins (td, MINT_JIT_CALL); td->last_ins->data [0] = get_data_item_index (td, (void *)mono_interp_get_imethod (domain, target_method, error)); mono_error_assert_ok (error); + td->last_ins->data [1] = vt_stack_used; } else { -#ifndef MONO_ARCH_HAS_NO_PROPER_MONOCTX - /* Try using fast icall path for simple signatures */ - if (native && !method->dynamic) - op = interp_icall_op_for_sig (csignature); -#endif - if (csignature->call_convention == MONO_CALL_VARARG) - interp_add_ins (td, MINT_CALL_VARARG); - else if (is_delegate_invoke) - interp_add_ins (td, MINT_CALL_DELEGATE); - else if (calli) - interp_add_ins (td, native ? ((op != -1) ? MINT_CALLI_NAT_FAST : MINT_CALLI_NAT) : MINT_CALLI); - else if (is_virtual && !mono_class_is_marshalbyref (target_method->klass)) - interp_add_ins (td, is_void ? MINT_VCALLVIRT_FAST : MINT_CALLVIRT_FAST); - else if (is_virtual) - interp_add_ins (td, is_void ? MINT_VCALLVIRT : MINT_CALLVIRT); - else - interp_add_ins (td, is_void ? MINT_VCALL : MINT_CALL); - if (is_delegate_invoke) { + interp_add_ins (td, MINT_CALL_DELEGATE); td->last_ins->data [0] = get_data_item_index (td, (void *)csignature); + td->last_ins->data [1] = vt_stack_used; } else if (calli) { - td->last_ins->data [0] = get_data_item_index (td, (void *)csignature); +#ifndef MONO_ARCH_HAS_NO_PROPER_MONOCTX + /* Try using fast icall path for simple signatures */ + if (native && !method->dynamic) + op = interp_icall_op_for_sig (csignature); +#endif if (op != -1) { - td->last_ins->data[1] = op; - if (td->last_ins->opcode == MINT_CALLI_NAT_FAST) - td->last_ins->data[2] = save_last_error; - } else if (op == -1 && td->last_ins->opcode == MINT_CALLI_NAT) { - td->last_ins->data[1] = save_last_error; + interp_add_ins (td, MINT_CALLI_NAT_FAST); + td->last_ins->data [1] = op; + td->last_ins->data [2] = save_last_error; + } else if (native && method->dynamic && csignature->pinvoke) { + interp_add_ins (td, MINT_CALLI_NAT_DYNAMIC); + td->last_ins->data [1] = vt_stack_used; + } else if (native) { + interp_add_ins (td, MINT_CALLI_NAT); +#ifdef TARGET_X86 + /* Windows not tested/supported yet */ + g_assertf (csignature->call_convention == MONO_CALL_DEFAULT || csignature->call_convention == MONO_CALL_C, "Interpreter supports only cdecl pinvoke on x86"); +#endif + td->last_ins->data [1] = vt_stack_used; + td->last_ins->data [2] = vt_res_size; + td->last_ins->data [3] = save_last_error; + } else { + interp_add_ins (td, MINT_CALLI); + td->last_ins->data [1] = vt_stack_used; } + td->last_ins->data [0] = get_data_item_index (td, (void *)csignature); } else { InterpMethod *imethod = mono_interp_get_imethod (domain, target_method, error); + return_val_if_nok (error, FALSE); + + if (csignature->call_convention == MONO_CALL_VARARG) { + interp_add_ins (td, MINT_CALL_VARARG); + td->last_ins->data [1] = get_data_item_index (td, (void *)csignature); + } else if (is_virtual && !mono_class_is_marshalbyref (target_method->klass)) { + interp_add_ins (td, MINT_CALLVIRT_FAST); + if (mono_class_is_interface (target_method->klass)) + td->last_ins->data [1] = -2 * MONO_IMT_SIZE + mono_method_get_imt_slot (target_method); + else + td->last_ins->data [1] = mono_method_get_vtable_slot (target_method); + } else if (is_virtual) { + interp_add_ins (td, MINT_CALLVIRT); + td->last_ins->data [1] = imethod->param_count + imethod->hasthis; + } else { + interp_add_ins (td, MINT_CALL); + td->last_ins->data [1] = imethod->param_count + imethod->hasthis; + } td->last_ins->data [0] = get_data_item_index (td, (void *)imethod); - td->last_ins->data [1] = imethod->param_count + imethod->hasthis; + td->last_ins->data [2] = vt_stack_used; + #ifdef ENABLE_EXPERIMENT_TIERED if (MINT_IS_PATCHABLE_CALL (td->last_ins->opcode)) { g_assert (!calli && !is_virtual); @@ -2500,25 +2524,9 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target g_hash_table_insert (td->patchsite_hash, td->last_ins, target_method); } #endif - return_val_if_nok (error, FALSE); - if (csignature->call_convention == MONO_CALL_VARARG) - td->last_ins->data [1] = get_data_item_index (td, (void *)csignature); - else if (is_virtual && !mono_class_is_marshalbyref (target_method->klass)) { - /* FIXME Use fastpath also for MBRO. Asserts in mono_method_get_vtable_slot */ - if (mono_class_is_interface (target_method->klass)) - td->last_ins->data [1] = -2 * MONO_IMT_SIZE + mono_method_get_imt_slot (target_method); - else - td->last_ins->data [1] = mono_method_get_vtable_slot (target_method); - } } } td->ip += 5; - if (vt_stack_used != 0 || vt_res_size != 0) { - interp_add_ins (td, MINT_VTRESULT); - td->last_ins->data [0] = vt_res_size; - WRITE32_INS (td->last_ins, 1, &vt_stack_used); - td->vt_sp -= vt_stack_used; - } return TRUE; } @@ -2897,7 +2905,7 @@ interp_emit_memory_barrier (TransformData *td, int kind) } while (0) static void -interp_method_compute_offsets (TransformData *td, InterpMethod *imethod, MonoMethodSignature *signature, MonoMethodHeader *header) +interp_method_compute_offsets (TransformData *td, InterpMethod *imethod, MonoMethodSignature *signature, MonoMethodHeader *header, MonoError *error) { int i, offset, size, align; @@ -2908,6 +2916,12 @@ interp_method_compute_offsets (TransformData *td, InterpMethod *imethod, MonoMet offset = 0; for (i = 0; i < header->num_locals; ++i) { size = mono_type_size (header->locals [i], &align); + if (header->locals [i]->type == MONO_TYPE_VALUETYPE) { + if (mono_class_has_failure (header->locals [i]->data.klass)) { + mono_error_set_for_class_failure (error, header->locals [i]->data.klass); + return; + } + } offset += align - 1; offset &= ~(align - 1); imethod->local_offsets [i] = offset; @@ -2935,7 +2949,8 @@ interp_method_compute_offsets (TransformData *td, InterpMethod *imethod, MonoMet void mono_test_interp_method_compute_offsets (TransformData *td, InterpMethod *imethod, MonoMethodSignature *signature, MonoMethodHeader *header) { - interp_method_compute_offsets (td, imethod, signature, header); + ERROR_DECL (error); + interp_method_compute_offsets (td, imethod, signature, header, error); } /* Return false is failure to init basic blocks due to being in inline method */ @@ -3726,14 +3741,15 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, } case CEE_POP: CHECK_STACK(td, 1); - SIMPLE_OP(td, MINT_POP); if (td->sp [-1].type == STACK_TYPE_VT) { int size = mono_class_value_size (td->sp [-1].klass, NULL); size = ALIGN_TO (size, MINT_VT_ALIGNMENT); - interp_add_ins (td, MINT_VTRESULT); - td->last_ins->data [0] = 0; - WRITE32_INS (td->last_ins, 1, &size); + interp_add_ins (td, MINT_POP_VT); + WRITE32_INS (td->last_ins, 0, &size); td->vt_sp -= size; + td->ip++; + } else { + SIMPLE_OP(td, MINT_POP); } --td->sp; break; @@ -4597,13 +4613,16 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_add_ins (td, MINT_NEWOBJ_ARRAY); td->last_ins->data [0] = get_data_item_index (td, m->klass); td->last_ins->data [1] = csignature->param_count; + } else if (klass == mono_defaults.string_class) { + interp_add_ins (td, MINT_NEWOBJ_STRING); + td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); + td->last_ins->data [1] = csignature->param_count; } else if (m_class_get_image (klass) == mono_defaults.corlib && !strcmp (m_class_get_name (m->klass), "ByReference`1") && !strcmp (m->name, ".ctor")) { /* public ByReference(ref T value) */ g_assert (csignature->hasthis && csignature->param_count == 1); interp_add_ins (td, MINT_INTRINS_BYREFERENCE_CTOR); - td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); } else if (klass != mono_defaults.string_class && !mono_class_is_marshalbyref (klass) && !mono_class_has_finalizer (klass) && @@ -6419,16 +6438,10 @@ get_inst_stack_usage (TransformData *td, InterpInst *ins, int *pop, int *push) case MINT_JIT_CALL: case MINT_CALL: case MINT_CALLVIRT: - case MINT_CALLVIRT_FAST: - case MINT_VCALL: - case MINT_VCALLVIRT: - case MINT_VCALLVIRT_FAST: { + case MINT_CALLVIRT_FAST: { InterpMethod *imethod = (InterpMethod*) td->data_items [ins->data [0]]; *pop = imethod->param_count + imethod->hasthis; - if (opcode == MINT_JIT_CALL) - *push = imethod->rtype->type != MONO_TYPE_VOID; - else - *push = opcode == MINT_CALL || opcode == MINT_CALLVIRT || opcode == MINT_CALLVIRT_FAST; + *push = imethod->rtype->type != MONO_TYPE_VOID; break; } #ifndef ENABLE_NETCORE @@ -6447,6 +6460,7 @@ get_inst_stack_usage (TransformData *td, InterpInst *ins, int *pop, int *push) } case MINT_CALLI: case MINT_CALLI_NAT: + case MINT_CALLI_NAT_DYNAMIC: case MINT_CALLI_NAT_FAST: { MonoMethodSignature *csignature = (MonoMethodSignature*) td->data_items [ins->data [0]]; *pop = csignature->param_count + csignature->hasthis + 1; @@ -6477,6 +6491,7 @@ get_inst_stack_usage (TransformData *td, InterpInst *ins, int *pop, int *push) break; } case MINT_NEWOBJ_ARRAY: + case MINT_NEWOBJ_STRING: *pop = ins->data [1]; *push = 1; break; @@ -6491,12 +6506,6 @@ get_inst_stack_usage (TransformData *td, InterpInst *ins, int *pop, int *push) *push = 1; break; } - case MINT_INTRINS_BYREFERENCE_CTOR: { - InterpMethod *imethod = (InterpMethod*) td->data_items [ins->data [0]]; - *pop = imethod->param_count; - *push = 1; - break; - } default: g_assert_not_reached (); } @@ -7215,6 +7224,10 @@ interp_cprop (TransformData *td) } if (sp->ins) { + // If the top of stack is not pushed by a ldloc, we are introducing a + // new dependency on the src_local since we are adding a movloc from it. + if (!MINT_IS_LDLOC (sp->ins->opcode)) + local_ref_count [src_local]++; interp_clear_ins (td, sp->ins); interp_clear_ins (td, ins); @@ -7331,7 +7344,7 @@ interp_cprop (TransformData *td) sp [-i].ins = NULL; memset (sp, 0, sizeof (StackContentInfo)); sp++; - } else if (ins->opcode == MINT_POP) { + } else if (ins->opcode == MINT_POP || ins->opcode == MINT_POP_VT) { sp--; if (sp->ins) { // The top of the stack is not used by any instructions. Kill both the @@ -7596,7 +7609,8 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG if (td->prof_coverage) td->coverage_info = mono_profiler_coverage_alloc (method, header->code_size); - interp_method_compute_offsets (td, rtm, mono_method_signature_internal (method), header); + interp_method_compute_offsets (td, rtm, mono_method_signature_internal (method), header, error); + goto_if_nok (error, exit); if (verbose_method_name) { const char *name = verbose_method_name; @@ -7630,7 +7644,8 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG generate_compacted_code (td); if (td->verbose_level) { - g_print ("Runtime method: %s %p, VT stack size: %d\n", mono_method_full_name (method, TRUE), rtm, td->max_vt_sp); + g_print ("Runtime method: %s %p\n", mono_method_full_name (method, TRUE), rtm); + g_print ("Locals size %d, VT stack size: %d\n", td->total_locals_size, td->max_vt_sp); g_print ("Calculated stack size: %d, stated size: %d\n", td->max_stack_height, header->max_stack); dump_mint_code (td->new_code, td->new_code_end); } diff --git a/src/mono/mono/mini/jit-icalls.c b/src/mono/mono/mini/jit-icalls.c index 2f3c0f293d9ee7..b50d3163996a87 100644 --- a/src/mono/mono/mini/jit-icalls.c +++ b/src/mono/mono/mini/jit-icalls.c @@ -67,6 +67,7 @@ ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared) { ERROR_DECL (error); MonoMethod *res; + gpointer addr; if (obj == NULL) { mono_error_set_null_reference (error); @@ -93,8 +94,28 @@ ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared) } /* An rgctx wrapper is added by the trampolines no need to do it here */ + gboolean need_unbox = m_class_is_valuetype (res->klass) && !m_class_is_valuetype (method->klass); + if (need_unbox) { + /* + * We can't return a jump trampoline here, because the trampoline code + * can't determine whenever to add an unbox trampoline (ldvirtftn) or + * not (ldftn). So compile the method here. + */ + addr = mono_compile_method_checked (res, error); + if (!is_ok (error)) { + mono_error_set_pending_exception (error); + return NULL; + } - return mono_ldftn (res); + if (mono_llvm_only && mono_method_needs_static_rgctx_invoke (res, FALSE)) + // FIXME: + g_assert_not_reached (); + + addr = mini_add_method_trampoline (res, addr, mono_method_needs_static_rgctx_invoke (res, FALSE), TRUE); + } else { + addr = mono_ldftn (res); + } + return addr; } void* @@ -983,12 +1004,6 @@ mono_fconv_ovf_u8 (double v) return res; } -guint64 -mono_fconv_ovf_u8_un (double v) -{ - return mono_fconv_ovf_u8 (v); -} - #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8 gint64 mono_rconv_i8 (float v) @@ -1026,12 +1041,6 @@ mono_rconv_ovf_u8 (float v) return res; } -guint64 -mono_rconv_ovf_u8_un (float v) -{ - return mono_rconv_ovf_u8 (v); -} - #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8 double mono_lconv_to_r8 (gint64 a) @@ -1475,7 +1484,7 @@ ves_icall_mono_delegate_ctor (MonoObject *this_obj_raw, MonoObject *target_raw, mono_error_set_pending_exception (error); goto leave; } - mono_delegate_ctor (this_obj, target, addr, error); + mono_delegate_ctor (this_obj, target, addr, NULL, error); mono_error_set_pending_exception (error); leave: diff --git a/src/mono/mono/mini/jit-icalls.h b/src/mono/mono/mini/jit-icalls.h index 8e781ec8d389b0..41ebae89ceee56 100644 --- a/src/mono/mono/mini/jit-icalls.h +++ b/src/mono/mono/mini/jit-icalls.h @@ -86,16 +86,12 @@ ICALL_EXTERN_C gint64 mono_fconv_ovf_i8 (double v); ICALL_EXTERN_C guint64 mono_fconv_ovf_u8 (double v); -ICALL_EXTERN_C guint64 mono_fconv_ovf_u8_un (double v); - ICALL_EXTERN_C gint64 mono_rconv_i8 (float v); ICALL_EXTERN_C gint64 mono_rconv_ovf_i8 (float v); ICALL_EXTERN_C guint64 mono_rconv_ovf_u8 (float v); -ICALL_EXTERN_C guint64 mono_rconv_ovf_u8_un (float v); - ICALL_EXTERN_C double mono_lconv_to_r8 (gint64 a); ICALL_EXTERN_C double mono_conv_to_r8 (gint32 a); diff --git a/src/mono/mono/mini/llvm-intrinsics.h b/src/mono/mono/mini/llvm-intrinsics.h index 74b2ed3d62eff1..f937df8bb8bf52 100644 --- a/src/mono/mono/mini/llvm-intrinsics.h +++ b/src/mono/mono/mini/llvm-intrinsics.h @@ -206,7 +206,10 @@ INTRINS(SSE_TESTZ, x86_sse41_ptestz) INTRINS(SSE_PBLENDVB, x86_sse41_pblendvb) INTRINS(SSE_BLENDVPS, x86_sse41_blendvps) INTRINS(SSE_BLENDVPD, x86_sse41_blendvpd) +#if LLVM_API_VERSION < 700 +// Clang 7 and above use a sequence of IR operations to represent pmuldq. INTRINS(SSE_PMULDQ, x86_sse41_pmuldq) +#endif INTRINS(SSE_PHMINPOSUW, x86_sse41_phminposuw) INTRINS(SSE_MPSADBW, x86_sse41_mpsadbw) INTRINS(PCLMULQDQ, x86_pclmulqdq) diff --git a/src/mono/mono/mini/llvm-jit.cpp b/src/mono/mono/mini/llvm-jit.cpp index 325e09c2cc3830..1c16963c2909f2 100644 --- a/src/mono/mono/mini/llvm-jit.cpp +++ b/src/mono/mono/mini/llvm-jit.cpp @@ -185,7 +185,7 @@ init_function_pass_manager (legacy::FunctionPassManager &fpm) } else { auto info = reg->getPassInfo (pass->getPassID()); auto name = info->getPassArgument (); - printf("Opt pass is ignored: %.*s\n", name.size(), name.data()); + printf("Opt pass is ignored: %.*s\n", (int) name.size(), name.data()); } } // -place-safepoints pass is mandatory diff --git a/src/mono/mono/mini/m2n-gen.cs b/src/mono/mono/mini/m2n-gen.cs deleted file mode 100644 index eb2378ea66a6b4..00000000000000 --- a/src/mono/mono/mini/m2n-gen.cs +++ /dev/null @@ -1,247 +0,0 @@ -using System; -using System.Linq; -using System.Collections.Generic; - -class EmitCtx -{ - int iarg, farg; - - public string Emit (char c) { - switch (c) { - case 'I': - iarg += 1; - return $"(int)(gssize)margs->iargs [{iarg - 1}]"; - case 'F': - farg += 1; - return $"*(float*)&margs->fargs [FIDX ({farg - 1})]"; - case 'L': - iarg += 2; - return $"get_long_arg (margs, {iarg - 2})"; - case 'D': - farg += 1; - return $"margs->fargs [FIDX ({farg - 1})]"; - default: - throw new Exception ("IDK how to handle " + c); - } - } -} - -class Driver { - static string[] cookies = new string[] { - "V", - "VI", - "VII", - "VIII", - "VIIII", - "VIIIII", - "VIIIIII", - "VIIIIIII", - "VIIIIIIII", - "VIIIIIIIII", - "VIIIIIIIIII", - "VIIIIIIIIIII", - "VIIIIIIIIIIII", - "VIIIIIIIIIIIII", - "VIIIIIIIIIIIIII", - "I", - "II", - "III", - "IIII", - "IIIII", - "IIIIII", - "IIIIIII", - "IIIIIIII", - "IIIIIIIII", - "IIIIIIIIII", - "IIIIIIIIIII", - "IIIIIIIIIIII", - "IIIIIIIIIIIII", - "IIIIIIIIIIIIII", - "IILIIII", - "IF", - "ID", - "IIF", - "IIFI", - "IIFF", - "IFFII", - "IIFII", - "IIFFI", - "IIFFF", - "IIFFFI", - "IIFFII", - "IIFIII", - "IIFFFFI", - "IIFFFFII", - "IIIF", - "IIIFI", - "IIIFII", - "IIIFIII", - "IIIIF", - "IIIIFI", - "IIIIFII", - "IIIIFIII", - "IIIFFFF", - "IIIFFFFF", - "IIFFFFFF", - "IIIFFFFFF", - "IIIIIIIF", - "IIIIIIIFF", - "IIFFFFFFFF", - "IIIFFFFFFFF", - "IIIIIIFII", - "IIIFFFFFFFFIII", - "IIIIIFFFFIIII", - "IFFFFFFI", - "IIFFIII", - "ILI", - "IILLI", - "L", - "LL", - "LI", - "LIL", - "LILI", - "LILII", - "DD", - "DDI", - "DDD", - "DDDD", - "VIF", - "VIFF", - "VIFFFF", - "VIFFFFF", - "VIFFFFFF", - "VIFFFFFI", - "VIIFFI", - "FF", - "FFI", - "FFF", - "FFFF", - "DI", - "FI", - "IIL", - "IILI", - "IILIIIL", - "IILLLI", - "IDIII", - "LII", - "VID", - "VILLI", - "DID", - "DIDD", - "FIF", - "FIFF", - "LILL", - "VIL", - }; - - static string TypeToSigType (char c) { - switch (c) { - case 'V': return "void"; - case 'I': return "int"; - case 'L': return "gint64"; - case 'F': return "float"; - case 'D': return "double"; - default: - throw new Exception ("Can't handle " + c); - } - } - - static void Main (string[] args) { - Console.WriteLine ("/*"); - Console.WriteLine ("* DON'T EDIT THIS FILE"); - Console.WriteLine ("* This file was generated by m2n-gen.cs - use it instead."); - Console.WriteLine ("*/"); - foreach (var c in cookies) { - Console.WriteLine ("static void"); - Console.WriteLine ($"wasm_invoke_{c.ToLower ()} (void *target_func, InterpMethodArguments *margs)"); - Console.WriteLine ("{"); - - - Console.Write ($"\ttypedef {TypeToSigType (c [0])} (*T)("); - for (int i = 1; i < c.Length; ++i) { - char p = c [i]; - if (i > 1) - Console.Write (", "); - Console.Write ($"{TypeToSigType (p)} arg_{i - 1}"); - } - if (c.Length == 1) - Console.Write ("void"); - - Console.WriteLine (");\n\tT func = (T)target_func;"); - - var ctx = new EmitCtx (); - - Console.Write ("\t"); - if (c [0] != 'V') - Console.Write ($"{TypeToSigType (c [0])} res = "); - - Console.Write ("func ("); - for (int i = 1; i < c.Length; ++i) { - char p = c [i]; - if (i > 1) - Console.Write (", "); - Console.Write (ctx.Emit (p)); - } - Console.WriteLine (");"); - - if (c [0] != 'V') - Console.WriteLine ($"\t*({TypeToSigType (c [0])}*)margs->retval = res;"); - - Console.WriteLine ("\n}\n"); - } - - Console.WriteLine ("static void\nicall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodArguments *margs)"); - Console.WriteLine ("{"); - - if (args.Any(a => a == "--flat")) { - for (int i = 0; i < cookies.Length; ++i) { - var c = cookies [i]; - Console.Write ("\t"); - if (i > 0) - Console.Write ("else "); - Console.WriteLine ($"if (!strcmp (\"{c}\", cookie))"); - Console.WriteLine ($"\t\twasm_invoke_{c.ToLower ()} (target_func, margs);"); - } - Console.WriteLine ("\telse {"); - Console.WriteLine ("\t\tg_error (\"CANNOT HANDLE COOKIE %s\\n\", cookie);"); - Console.WriteLine ("\t}"); - } else { - Array.Sort (cookies); - WritePartition (cookies, 0); - Console.WriteLine ("\tg_error (\"CANNOT HANDLE COOKIE %s\\n\", cookie);"); - } - - Console.WriteLine ("}"); - } - - static void WritePartition (IEnumerable set, int pos = 0, int depth = 0) { - var prefix = "\t"; - for (var c = 0; c < pos; c++) - prefix += "\t"; - - var checks = 0; - - var groups = set.OrderBy (s => -s.Length).Where (s => s.Length > pos).GroupBy (s => s.Skip(pos).First().ToString()); - foreach (var g in groups) { - Console.WriteLine ($"{prefix}{Elif (checks)} (cookie[{pos}] == '{g.Key}') {{"); - WritePartition (g.ToList (), pos + 1, checks + depth); - Console.WriteLine ($"{prefix}}}"); - checks++; - } - - var hits = set.Where (s => s.Length == pos); - if (hits.Any ()) { - Console.WriteLine ($"{prefix}{Elif (checks++)} (cookie[{pos}] == '\\0') {{"); - - var h = hits.First (); - Console.WriteLine ($"{prefix}\t// found: {h} depth {pos + checks + depth}"); - Console.WriteLine ($"{prefix}\twasm_invoke_{h.ToLower ()} (target_func, margs);"); - Console.WriteLine ($"{prefix}\treturn;"); - Console.WriteLine ($"{prefix}}}"); - } - - string Elif (int c) { - return c == 0 ? "if" : "else if"; - } - } -} diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 8f953e7891b523..6ec2d8b3fc2c23 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -1101,6 +1101,9 @@ type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2) case STACK_I8: ins->opcode = OP_LCONV_TO_R_UN; break; + case STACK_R4: + ins->opcode = OP_RCONV_TO_R8; + break; case STACK_R8: ins->opcode = OP_FMOVE; break; @@ -8430,8 +8433,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b case MONO_CEE_CONV_OVF_I1: case MONO_CEE_CONV_OVF_I2: case MONO_CEE_CONV_OVF_I: - case MONO_CEE_CONV_OVF_U: + case MONO_CEE_CONV_OVF_I1_UN: + case MONO_CEE_CONV_OVF_I2_UN: + case MONO_CEE_CONV_OVF_I4_UN: + case MONO_CEE_CONV_OVF_I8_UN: + case MONO_CEE_CONV_OVF_I_UN: if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) { + /* floats are always signed, _UN has no effect */ ADD_UNOP (CEE_CONV_OVF_I8); ADD_UNOP (il_op); } else { @@ -8441,23 +8449,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b case MONO_CEE_CONV_OVF_U1: case MONO_CEE_CONV_OVF_U2: case MONO_CEE_CONV_OVF_U4: + case MONO_CEE_CONV_OVF_U: + case MONO_CEE_CONV_OVF_U1_UN: + case MONO_CEE_CONV_OVF_U2_UN: + case MONO_CEE_CONV_OVF_U4_UN: + case MONO_CEE_CONV_OVF_U8_UN: + case MONO_CEE_CONV_OVF_U_UN: if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) { + /* floats are always signed, _UN has no effect */ ADD_UNOP (CEE_CONV_OVF_U8); ADD_UNOP (il_op); } else { ADD_UNOP (il_op); } break; - case MONO_CEE_CONV_OVF_I1_UN: - case MONO_CEE_CONV_OVF_I2_UN: - case MONO_CEE_CONV_OVF_I4_UN: - case MONO_CEE_CONV_OVF_I8_UN: - case MONO_CEE_CONV_OVF_U1_UN: - case MONO_CEE_CONV_OVF_U2_UN: - case MONO_CEE_CONV_OVF_U4_UN: - case MONO_CEE_CONV_OVF_U8_UN: - case MONO_CEE_CONV_OVF_I_UN: - case MONO_CEE_CONV_OVF_U_UN: case MONO_CEE_CONV_U2: case MONO_CEE_CONV_U1: case MONO_CEE_CONV_I: @@ -8722,19 +8727,30 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (mini_class_is_system_array (cmethod->klass)) { *sp = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD); - /* Optimize the common cases */ - MonoJitICallId function = MONO_JIT_ICALL_ZeroIsReserved;; + MonoJitICallId function = MONO_JIT_ICALL_ZeroIsReserved; + int rank = m_class_get_rank (cmethod->klass); int n = fsig->param_count; - switch (n) { - case 1: function = MONO_JIT_ICALL_mono_array_new_1; - break; - case 2: function = MONO_JIT_ICALL_mono_array_new_2; - break; - case 3: function = MONO_JIT_ICALL_mono_array_new_3; - break; - case 4: function = MONO_JIT_ICALL_mono_array_new_4; - break; - default: + /* Optimize the common cases, use ctor using length for each rank (no lbound). */ + if (n == rank) { + switch (n) { + case 1: function = MONO_JIT_ICALL_mono_array_new_1; + break; + case 2: function = MONO_JIT_ICALL_mono_array_new_2; + break; + case 3: function = MONO_JIT_ICALL_mono_array_new_3; + break; + case 4: function = MONO_JIT_ICALL_mono_array_new_4; + break; + default: + break; + } + } + + /* Instancing jagged arrays should not end up here since ctor (int32, int32) for an array with rank 1 represents length and lbound. */ + g_assert (!(rank == 1 && fsig->param_count == 2 && m_class_get_rank (m_class_get_element_class (cmethod->klass)))); + + /* Regular case, rank > 4 or legnth, lbound specified per rank. */ + if (function == MONO_JIT_ICALL_ZeroIsReserved) { // FIXME Maximum value of param_count? Realistically 64. Fits in imm? if (!array_new_localalloc_ins) { MONO_INST_NEW (cfg, array_new_localalloc_ins, OP_LOCALLOC_IMM); @@ -8744,9 +8760,25 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } array_new_localalloc_ins->inst_imm = MAX (array_new_localalloc_ins->inst_imm, n * sizeof (target_mgreg_t)); int dreg = array_new_localalloc_ins->dreg; - for (int i = 0; i < n; ++i) { - NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, dreg, i * sizeof (target_mgreg_t), sp [i + 1]->dreg); - MONO_ADD_INS (cfg->cbb, ins); + if (2 * rank == n) { + /* [lbound, length, lbound, length, ...] + * mono_array_new_n_icall expects a non-interleaved list of + * lbounds and lengths, so deinterleave here. + */ + for (int l = 0; l < 2; ++l) { + int src = l; + int dst = l * rank; + for (int r = 0; r < rank; ++r, src += 2, ++dst) { + NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, dreg, dst * sizeof (target_mgreg_t), sp [src + 1]->dreg); + MONO_ADD_INS (cfg->cbb, ins); + } + } + } else { + /* [length, length, length, ...] */ + for (int i = 0; i < n; ++i) { + NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, dreg, i * sizeof (target_mgreg_t), sp [i + 1]->dreg); + MONO_ADD_INS (cfg->cbb, ins); + } } EMIT_NEW_ICONST (cfg, ins, n); sp [1] = ins; @@ -8755,7 +8787,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b sp [2] = ins; // FIXME Adjust sp by n - 3? Attempts failed. function = MONO_JIT_ICALL_mono_array_new_n_icall; - break; } alloc = mono_emit_jit_icall_id (cfg, function, sp); } else if (cmethod->string_ctor) { @@ -8893,6 +8924,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b MonoInst *val; MonoClass *enum_class; MonoMethod *has_flag; + MonoMethodSignature *has_flag_sig; --sp; val = *sp; @@ -8946,8 +8978,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b (has_flag = mini_get_method (cfg, method, callvirt_token, NULL, generic_context)) && has_flag->klass == mono_defaults.enum_class && !strcmp (has_flag->name, "HasFlag") && - has_flag->signature->hasthis && - has_flag->signature->param_count == 1) { + (has_flag_sig = mono_method_signature_internal (has_flag)) && + has_flag_sig->hasthis && + has_flag_sig->param_count == 1) { CHECK_TYPELOAD (enum_class); if (enum_class == klass) { @@ -9284,7 +9317,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b klass = field->parent; } else { + klass = NULL; field = mono_field_from_token_checked (image, token, &klass, generic_context, cfg->error); + if (!field) + CHECK_TYPELOAD (klass); CHECK_CFG_ERROR; } if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field)) @@ -11041,7 +11077,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b ensure_method_is_allowed_to_call_method (cfg, method, ctor_method); if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) { - /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/ + /*BAD IMPL: We must not add a null check for virtual invoke delegates.*/ if (mono_method_signature_internal (invoke)->param_count == mono_method_signature_internal (cmethod)->param_count) { MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0); MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException"); diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index f9974690302ccc..a33c414825b980 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -2242,8 +2242,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) t = mini_get_underlying_type (t); //XXX what about ArgGSharedVtOnStack here? - // FIXME tailcall is not always yet initialized. - if (ainfo->storage == ArgOnStack && !MONO_TYPE_ISSTRUCT (t) && !call->tailcall) { + if (ainfo->storage == ArgOnStack && !MONO_TYPE_ISSTRUCT (t)) { if (!t->byref) { if (t->type == MONO_TYPE_R4) MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, AMD64_RSP, ainfo->offset, in->dreg); @@ -2302,18 +2301,9 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) case ArgValuetypeAddrOnStack: case ArgGSharedVtInReg: case ArgGSharedVtOnStack: { - // FIXME tailcall is not always yet initialized. - if (ainfo->storage == ArgOnStack && !MONO_TYPE_ISSTRUCT (t) && !call->tailcall) + if (ainfo->storage == ArgOnStack && !MONO_TYPE_ISSTRUCT (t)) /* Already emitted above */ break; - //FIXME what about ArgGSharedVtOnStack ? - // FIXME tailcall is not always yet initialized. - if (ainfo->storage == ArgOnStack && call->tailcall) { - MonoInst *call_inst = (MonoInst*)call; - cfg->args [i]->flags |= MONO_INST_VOLATILE; - EMIT_NEW_ARGSTORE (cfg, call_inst, i, in); - break; - } guint32 align; guint32 size; diff --git a/src/mono/mono/mini/mini-arm.c b/src/mono/mono/mini/mini-arm.c index 55825042dc64c2..b315929e20490a 100644 --- a/src/mono/mono/mini/mini-arm.c +++ b/src/mono/mono/mini/mini-arm.c @@ -1637,7 +1637,10 @@ arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) return &ccontext->gregs [ainfo->reg]; case RegTypeHFA: case RegTypeFP: - return &ccontext->fregs [ainfo->reg]; + if (IS_HARD_FLOAT) + return &ccontext->fregs [ainfo->reg]; + else + return &ccontext->gregs [ainfo->reg]; case RegTypeBase: return ccontext->stack + ainfo->offset; default: diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 8a8a5b070637b9..7907193b5e0ffd 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1035,6 +1035,16 @@ mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code) return (MonoVTable*)regs [MONO_ARCH_RGCTX_REG]; } +GSList* +mono_arch_get_cie_program (void) +{ + GSList *l = NULL; + + mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ARMREG_SP, 0); + + return l; +} + host_mgreg_t mono_arch_context_get_int_reg (MonoContext *ctx, int reg) { diff --git a/src/mono/mono/mini/mini-generic-sharing.c b/src/mono/mono/mini/mini-generic-sharing.c index 9bf9c2cf528e89..7ef020e8c5548a 100644 --- a/src/mono/mono/mini/mini-generic-sharing.c +++ b/src/mono/mono/mini/mini-generic-sharing.c @@ -26,6 +26,7 @@ #include "aot-runtime.h" #include "mini-runtime.h" #include "llvmonly-runtime.h" +#include "interp/interp.h" #define ALLOW_PARTIAL_SHARING TRUE //#define ALLOW_PARTIAL_SHARING FALSE @@ -1335,8 +1336,10 @@ get_wrapper_shared_type (MonoType *t) /* Returns the intptr type for types that are passed in a single register */ static MonoType* -get_wrapper_shared_type_reg (MonoType *t) +get_wrapper_shared_type_reg (MonoType *t, gboolean pinvoke) { + MonoType *orig_t = t; + t = get_wrapper_shared_type (t); if (t->byref) return t; @@ -1364,6 +1367,15 @@ get_wrapper_shared_type_reg (MonoType *t) case MONO_TYPE_ARRAY: case MONO_TYPE_PTR: return mono_get_int_type (); + case MONO_TYPE_GENERICINST: + if (orig_t->type == MONO_TYPE_VALUETYPE && pinvoke) + /* + * These are translated to instances of Mono.ValueTuple, but generic types + * cannot be passed in pinvoke. + */ + return orig_t; + else + return t; default: return t; } @@ -1375,9 +1387,9 @@ mini_get_underlying_reg_signature (MonoMethodSignature *sig) MonoMethodSignature *res = mono_metadata_signature_dup (sig); int i; - res->ret = get_wrapper_shared_type_reg (sig->ret); + res->ret = get_wrapper_shared_type_reg (sig->ret, sig->pinvoke); for (i = 0; i < sig->param_count; ++i) - res->params [i] = get_wrapper_shared_type_reg (sig->params [i]); + res->params [i] = get_wrapper_shared_type_reg (sig->params [i], sig->pinvoke); res->generic_param_count = 0; res->is_inflated = 0; @@ -1700,7 +1712,7 @@ mini_get_interp_in_wrapper (MonoMethodSignature *sig) return res; } - if (sig->param_count > 8) + if (sig->param_count > MAX_INTERP_ENTRY_ARGS) /* Call the generic interpreter entry point, the specialized ones only handle a limited number of arguments */ generic = TRUE; diff --git a/src/mono/mono/mini/mini-llvm-cpp.cpp b/src/mono/mono/mini/mini-llvm-cpp.cpp index cbe40546561f72..e9ef8782222943 100644 --- a/src/mono/mono/mini/mini-llvm-cpp.cpp +++ b/src/mono/mono/mini/mini-llvm-cpp.cpp @@ -229,6 +229,13 @@ mono_llvm_build_weighted_branch (LLVMBuilderRef builder, LLVMValueRef cond, LLVM return wrap (ins); } +LLVMValueRef +mono_llvm_build_exact_ashr (LLVMBuilderRef builder, LLVMValueRef lhs, LLVMValueRef rhs) { + auto b = unwrap (builder); + auto ins = b->CreateAShr (unwrap (lhs), unwrap (rhs), "", true); + return wrap (ins); +} + void mono_llvm_add_string_metadata (LLVMValueRef insref, const char* label, const char* text) { diff --git a/src/mono/mono/mini/mini-llvm-cpp.h b/src/mono/mono/mini/mini-llvm-cpp.h index d9b2e427c79328..9173b6341e4f6b 100644 --- a/src/mono/mono/mini/mini-llvm-cpp.h +++ b/src/mono/mono/mini/mini-llvm-cpp.h @@ -104,6 +104,9 @@ mono_llvm_build_cmpxchg (LLVMBuilderRef builder, LLVMValueRef addr, LLVMValueRef LLVMValueRef mono_llvm_build_weighted_branch (LLVMBuilderRef builder, LLVMValueRef cond, LLVMBasicBlockRef t, LLVMBasicBlockRef f, uint32_t t_weight, uint32_t f_weight); +LLVMValueRef +mono_llvm_build_exact_ashr (LLVMBuilderRef builder, LLVMValueRef lhs, LLVMValueRef rhs); + void mono_llvm_add_string_metadata (LLVMValueRef insref, const char* label, const char* text); diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index f5aef1fd1b3967..fa99c276130ed9 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -4572,14 +4572,19 @@ emit_landing_pad (EmitContext *ctx, int group_index, int group_size) } static LLVMValueRef -create_const_vector_i32 (const int *mask, int count) +create_const_vector (LLVMTypeRef t, const int *vals, int count) { - LLVMValueRef *llvm_mask = g_new (LLVMValueRef, count); + g_assert (count <= 16); + LLVMValueRef llvm_vals [16]; for (int i = 0; i < count; i++) - llvm_mask [i] = LLVMConstInt (LLVMInt32Type (), mask [i], FALSE); - LLVMValueRef vec = LLVMConstVector (llvm_mask, count); - g_free (llvm_mask); - return vec; + llvm_vals [i] = LLVMConstInt (t, vals [i], FALSE); + return LLVMConstVector (llvm_vals, count); +} + +static LLVMValueRef +create_const_vector_i32 (const int *mask, int count) +{ + return create_const_vector (LLVMInt32Type (), mask, count); } static LLVMValueRef @@ -8582,10 +8587,23 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) } case OP_SSE41_MUL: { - // NOTE: LLVM 7 and later use shifts here - // however, pmuldq is still available so I guess it's fine to keep using it +#if LLVM_API_VERSION < 700 LLVMValueRef args [] = { lhs, rhs }; values [ins->dreg] = call_intrins (ctx, INTRINS_SSE_PMULDQ, args, dname); +#else + const int shift_vals [] = { 32, 32 }; + const LLVMValueRef args [] = { + convert (ctx, lhs, sse_i8_t), + convert (ctx, rhs, sse_i8_t), + }; + LLVMValueRef mul_args [2] = { 0 }; + LLVMValueRef shift_vec = create_const_vector (LLVMInt64Type (), shift_vals, 2); + for (int i = 0; i < 2; ++i) { + LLVMValueRef padded = LLVMBuildShl (builder, args [i], shift_vec, ""); + mul_args[i] = mono_llvm_build_exact_ashr (builder, padded, shift_vec); + } + values [ins->dreg] = LLVMBuildNSWMul (builder, mul_args [0], mul_args [1], dname); +#endif break; } diff --git a/src/mono/mono/mini/mini-ops.h b/src/mono/mono/mini/mini-ops.h index 15baeb13156489..2e255fc0a38358 100644 --- a/src/mono/mono/mini/mini-ops.h +++ b/src/mono/mono/mini/mini-ops.h @@ -1405,7 +1405,7 @@ MINI_OP(OP_S390_LOADARG, "s390_loadarg", NONE, NONE, NONE) MINI_OP(OP_S390_ARGREG, "s390_argreg", NONE, NONE, NONE) MINI_OP(OP_S390_ARGPTR, "s390_argptr", NONE, NONE, NONE) MINI_OP(OP_S390_STKARG, "s390_stkarg", NONE, NONE, NONE) -MINI_OP(OP_S390_MOVE, "s390_move", IREG, IREG, NONE) +MINI_OP(OP_S390_MOVE, "s390_move", NONE, IREG, IREG) MINI_OP(OP_S390_SETF4RET, "s390_setf4ret", FREG, FREG, NONE) MINI_OP(OP_S390_BKCHAIN, "s390_bkchain", IREG, IREG, NONE) MINI_OP(OP_S390_LADD, "s390_long_add", LREG, IREG, IREG) diff --git a/src/mono/mono/mini/mini-posix.c b/src/mono/mono/mini/mini-posix.c index 7f9537423d1795..f477464aa1d26f 100644 --- a/src/mono/mono/mini/mini-posix.c +++ b/src/mono/mono/mini/mini-posix.c @@ -70,6 +70,7 @@ #include #include #include +#include #include #include "mini.h" @@ -517,48 +518,11 @@ static volatile gint32 sampling_thread_running; #ifdef HOST_DARWIN -static clock_serv_t sampling_clock_service; +static clock_serv_t sampling_clock; static void -clock_init (MonoProfilerSampleMode mode) +clock_init_for_profiler (MonoProfilerSampleMode mode) { - kern_return_t ret; - - do { - ret = host_get_clock_service (mach_host_self (), SYSTEM_CLOCK, &sampling_clock_service); - } while (ret == KERN_ABORTED); - - if (ret != KERN_SUCCESS) - g_error ("%s: host_get_clock_service () returned %d", __func__, ret); -} - -static void -clock_cleanup (void) -{ - kern_return_t ret; - - do { - ret = mach_port_deallocate (mach_task_self (), sampling_clock_service); - } while (ret == KERN_ABORTED); - - if (ret != KERN_SUCCESS) - g_error ("%s: mach_port_deallocate () returned %d", __func__, ret); -} - -static guint64 -clock_get_time_ns (void) -{ - kern_return_t ret; - mach_timespec_t mach_ts; - - do { - ret = clock_get_time (sampling_clock_service, &mach_ts); - } while (ret == KERN_ABORTED); - - if (ret != KERN_SUCCESS) - g_error ("%s: clock_get_time () returned %d", __func__, ret); - - return ((guint64) mach_ts.tv_sec * 1000000000) + (guint64) mach_ts.tv_nsec; } static void @@ -571,7 +535,7 @@ clock_sleep_ns_abs (guint64 ns_abs) then.tv_nsec = ns_abs % 1000000000; do { - ret = clock_sleep (sampling_clock_service, TIME_ABSOLUTE, then, &remain_unused); + ret = clock_sleep (sampling_clock, TIME_ABSOLUTE, then, &remain_unused); if (ret != KERN_SUCCESS && ret != KERN_ABORTED) g_error ("%s: clock_sleep () returned %d", __func__, ret); @@ -580,10 +544,10 @@ clock_sleep_ns_abs (guint64 ns_abs) #else -static clockid_t sampling_posix_clock; +static clockid_t sampling_clock; static void -clock_init (MonoProfilerSampleMode mode) +clock_init_for_profiler (MonoProfilerSampleMode mode) { switch (mode) { case MONO_PROFILER_SAMPLE_MODE_PROCESS: { @@ -601,34 +565,18 @@ clock_init (MonoProfilerSampleMode mode) * those systems, we fall back to CLOCK_MONOTONIC if we get EINVAL. */ if (clock_nanosleep (CLOCK_PROCESS_CPUTIME_ID, TIMER_ABSTIME, &ts, NULL) != EINVAL) { - sampling_posix_clock = CLOCK_PROCESS_CPUTIME_ID; + sampling_clock = CLOCK_PROCESS_CPUTIME_ID; break; } #endif // fallthrough } - case MONO_PROFILER_SAMPLE_MODE_REAL: sampling_posix_clock = CLOCK_MONOTONIC; break; + case MONO_PROFILER_SAMPLE_MODE_REAL: sampling_clock = CLOCK_MONOTONIC; break; default: g_assert_not_reached (); break; } } -static void -clock_cleanup (void) -{ -} - -static guint64 -clock_get_time_ns (void) -{ - struct timespec ts; - - if (clock_gettime (sampling_posix_clock, &ts) == -1) - g_error ("%s: clock_gettime () returned -1, errno = %d", __func__, errno); - - return ((guint64) ts.tv_sec * 1000000000) + (guint64) ts.tv_nsec; -} - static void clock_sleep_ns_abs (guint64 ns_abs) { @@ -640,7 +588,7 @@ clock_sleep_ns_abs (guint64 ns_abs) then.tv_nsec = ns_abs % 1000000000; do { - ret = clock_nanosleep (sampling_posix_clock, TIMER_ABSTIME, &then, NULL); + ret = clock_nanosleep (sampling_clock, TIMER_ABSTIME, &then, NULL); if (ret != 0 && ret != EINTR) g_error ("%s: clock_nanosleep () returned %d", __func__, ret); @@ -675,7 +623,7 @@ clock_sleep_ns_abs (guint64 ns_abs) * nanoseconds). */ do { - diff = (gint64) ns_abs - (gint64) clock_get_time_ns (); + diff = (gint64) ns_abs - (gint64) mono_clock_get_time_ns (sampling_clock); if (diff <= 0) break; @@ -743,16 +691,17 @@ sampling_thread_func (gpointer unused) goto init; } - clock_init (mode); + mono_clock_init (&sampling_clock); + clock_init_for_profiler (mode); - for (guint64 sleep = clock_get_time_ns (); mono_atomic_load_i32 (&sampling_thread_running); clock_sleep_ns_abs (sleep)) { + for (guint64 sleep = mono_clock_get_time_ns (sampling_clock); mono_atomic_load_i32 (&sampling_thread_running); clock_sleep_ns_abs (sleep)) { uint32_t freq; MonoProfilerSampleMode new_mode; mono_profiler_get_sample_mode (NULL, &new_mode, &freq); if (new_mode != mode) { - clock_cleanup (); + mono_clock_cleanup (sampling_clock); goto init; } @@ -774,7 +723,7 @@ sampling_thread_func (gpointer unused) } FOREACH_THREAD_SAFE_END } - clock_cleanup (); + mono_clock_cleanup (sampling_clock); done: mono_atomic_store_i32 (&sampling_thread_exiting, 1); diff --git a/src/mono/mono/mini/mini-profiler.c b/src/mono/mono/mini/mini-profiler.c index 8f7071426cd4de..46240cae89af2e 100644 --- a/src/mono/mono/mini/mini-profiler.c +++ b/src/mono/mono/mini/mini-profiler.c @@ -150,13 +150,13 @@ mini_profiler_emit_tail_call (MonoCompile *cfg, MonoMethod *target) EMIT_NEW_PCONST (cfg, iargs [1], NULL); if (target) - EMIT_NEW_METHODCONST (cfg, iargs [2], target); + EMIT_NEW_METHODCONST (cfg, iargs [2], target); else EMIT_NEW_PCONST (cfg, iargs [2], NULL); /* void mono_profiler_raise_method_tail_call (MonoMethod *method, MonoMethod *target) */ if (trace) - mono_emit_jit_icall (cfg, mono_trace_leave_method, iargs); + mono_emit_jit_icall (cfg, mono_trace_tail_method, iargs); else mono_emit_jit_icall (cfg, mono_profiler_raise_method_tail_call, iargs); } diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index 1d217a6c9d0184..ca2a59cf11a202 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -70,9 +70,14 @@ #include #include #include +#include #include #include +#ifdef ENABLE_PERFTRACING +#include +#endif + #include "mini.h" #include "seq-points.h" #include "tasklets.h" @@ -515,6 +520,7 @@ mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboo copy->code = info->code; copy->code_size = info->code_size; copy->name = g_strdup (info->name); + copy->method = info->method; if (info->unwind_ops) { copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, ©->uw_info_len); @@ -545,8 +551,8 @@ mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboo mono_jit_lock (); tramp_infos = g_slist_prepend (tramp_infos, copy); mono_jit_unlock (); - } else if (copy->uw_info) { - /* Only register trampolines that have unwind infos */ + } else if (copy->uw_info || info->method) { + /* Only register trampolines that have unwind info */ register_trampoline_jit_info (domain, copy); } @@ -1934,6 +1940,7 @@ static FILE *perf_dump_file; static mono_mutex_t perf_dump_mutex; static void *perf_dump_mmap_addr = MAP_FAILED; static guint32 perf_dump_pid; +static clockid_t clock_id = CLOCK_MONOTONIC; enum { JIT_DUMP_MAGIC = 0x4A695444, @@ -1984,7 +1991,6 @@ typedef struct } JitCodeLoadRecord; static void add_file_header_info (FileHeader *header); -static guint64 get_time_stamp_ns (void); static void add_basic_JitCodeLoadRecord_info (JitCodeLoadRecord *record); void @@ -2025,18 +2031,10 @@ add_file_header_info (FileHeader *header) header->elf_mach = ELF_MACHINE; header->pad1 = 0; header->pid = perf_dump_pid; - header->timestamp = get_time_stamp_ns (); + header->timestamp = mono_clock_get_time_ns (clock_id); header->flags = 0; } -static guint64 -get_time_stamp_ns (void) -{ - struct timespec ts; - int result = clock_gettime (CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000000000ULL + ts.tv_nsec; -} - void mono_emit_jit_dump (MonoJitInfo *jinfo, gpointer code) { @@ -2059,7 +2057,7 @@ mono_emit_jit_dump (MonoJitInfo *jinfo, gpointer code) // TODO: write debugInfo and unwindInfo immediately before the JitCodeLoadRecord (while lock is held). - record.header.timestamp = get_time_stamp_ns (); + record.header.timestamp = mono_clock_get_time_ns (clock_id); fwrite (&record, sizeof (record), 1, perf_dump_file); fwrite (jinfo->d.method->name, nameLen + 1, 1, perf_dump_file); @@ -2073,7 +2071,7 @@ static void add_basic_JitCodeLoadRecord_info (JitCodeLoadRecord *record) { record->header.id = JIT_CODE_LOAD; - record->header.timestamp = get_time_stamp_ns (); + record->header.timestamp = mono_clock_get_time_ns (clock_id); record->pid = perf_dump_pid; record->tid = syscall (SYS_gettid); } @@ -3755,7 +3753,7 @@ create_delegate_method_ptr (MonoMethod *method, MonoError *error) func = mono_compile_method_checked (method, error); return_val_if_nok (error, NULL); } else { - gpointer trampoline = mono_runtime_create_jump_trampoline (mono_domain_get (), method, TRUE, error); + gpointer trampoline = mono_create_jump_trampoline (mono_domain_get (), method, TRUE, error); return_val_if_nok (error, NULL); func = mono_create_ftnptr (mono_domain_get (), trampoline); } @@ -3763,9 +3761,52 @@ create_delegate_method_ptr (MonoMethod *method, MonoError *error) } static void -mini_init_delegate (MonoDelegateHandle delegate, MonoError *error) +mini_init_delegate (MonoDelegateHandle delegate, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error) { MonoDelegate *del = MONO_HANDLE_RAW (delegate); + MonoDomain *domain = MONO_HANDLE_DOMAIN (delegate); + + if (!method) { + MonoJitInfo *ji; + + g_assert (addr); + ji = mono_jit_info_table_find_internal (domain, mono_get_addr_from_ftnptr (addr), TRUE, TRUE); + /* Shared code */ + if (!ji && domain != mono_get_root_domain ()) + ji = mono_jit_info_table_find_internal (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr), TRUE, TRUE); + if (ji) { + if (ji->is_trampoline) { + /* Could be an unbox trampoline etc. */ + method = ji->d.tramp_info->method; + } else { + method = mono_jit_info_get_method (ji); + g_assert (!mono_class_is_gtd (method->klass)); + } + } + } + + if (method) + MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method); + + if (addr) + MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr); + +#ifndef DISABLE_REMOTING + if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) { + if (mono_use_interpreter) { + MONO_HANDLE_SETVAL (delegate, interp_method, gpointer, mini_get_interp_callbacks ()->get_remoting_invoke (method, addr, error)); + } else { + g_assert (method); + method = mono_marshal_get_remoting_invoke (method, error); + return_if_nok (error); + MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error)); + } + return_if_nok (error); + } +#endif + + MONO_HANDLE_SET (delegate, target, target); + MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, mono_create_delegate_trampoline (domain, mono_handle_class (delegate))); if (mono_use_interpreter) { mini_get_interp_callbacks ()->init_delegate (del, error); @@ -4384,7 +4425,6 @@ mini_init (const char *filename, const char *runtime_version) #define JIT_TRAMPOLINES_WORK #ifdef JIT_TRAMPOLINES_WORK callbacks.compile_method = mono_jit_compile_method; - callbacks.create_jump_trampoline = mono_create_jump_trampoline; callbacks.create_jit_trampoline = mono_create_jit_trampoline; callbacks.create_delegate_trampoline = mono_create_delegate_trampoline; callbacks.free_method = mono_jit_free_method; @@ -4495,6 +4535,10 @@ mini_init (const char *filename, const char *runtime_version) mono_install_get_class_from_name (mono_aot_get_class_from_name); mono_install_jit_info_find_in_aot (mono_aot_find_jit_info); +#ifdef ENABLE_PERFTRACING + ep_init (); +#endif + mono_profiler_state.context_enable = mini_profiler_context_enable; mono_profiler_state.context_get_this = mini_profiler_context_get_this; mono_profiler_state.context_get_argument = mini_profiler_context_get_argument; @@ -4631,6 +4675,7 @@ register_icalls (void) register_icall (mono_trace_enter_method, mono_icall_sig_void_ptr_ptr_ptr, TRUE); register_icall (mono_trace_leave_method, mono_icall_sig_void_ptr_ptr_ptr, TRUE); + register_icall (mono_trace_tail_method, mono_icall_sig_void_ptr_ptr_ptr, TRUE); g_assert (mono_get_lmf_addr == mono_tls_get_lmf_addr); register_icall (mono_jit_set_domain, mono_icall_sig_void_ptr, TRUE); register_icall (mono_domain_get, mono_icall_sig_ptr, TRUE); @@ -4711,10 +4756,8 @@ register_icalls (void) #endif register_opcode_emulation (OP_FCONV_TO_OVF_I8, __emul_fconv_to_ovf_i8, mono_icall_sig_long_double, mono_fconv_ovf_i8, FALSE); register_opcode_emulation (OP_FCONV_TO_OVF_U8, __emul_fconv_to_ovf_u8, mono_icall_sig_ulong_double, mono_fconv_ovf_u8, FALSE); - register_opcode_emulation (OP_FCONV_TO_OVF_U8_UN, __emul_fconv_to_ovf_u8_un, mono_icall_sig_ulong_double, mono_fconv_ovf_u8_un, FALSE); register_opcode_emulation (OP_RCONV_TO_OVF_I8, __emul_rconv_to_ovf_i8, mono_icall_sig_long_float, mono_rconv_ovf_i8, FALSE); register_opcode_emulation (OP_RCONV_TO_OVF_U8, __emul_rconv_to_ovf_u8, mono_icall_sig_ulong_float, mono_rconv_ovf_u8, FALSE); - register_opcode_emulation (OP_RCONV_TO_OVF_U8_UN, __emul_rconv_to_ovf_u8_un, mono_icall_sig_ulong_float, mono_rconv_ovf_u8_un, FALSE); #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8 register_opcode_emulation (OP_FCONV_TO_I8, __emul_fconv_to_i8, mono_icall_sig_long_double, mono_fconv_i8, FALSE); @@ -4957,6 +5000,9 @@ mini_cleanup (MonoDomain *domain) mono_runtime_print_stats (); jit_stats_cleanup (); mono_jit_dump_cleanup (); +#ifdef ENABLE_PERFTRACING + ep_shutdown (); +#endif } #else void diff --git a/src/mono/mono/mini/mini-s390x.c b/src/mono/mono/mini/mini-s390x.c index 7771fec126dc0b..ed36872f124dab 100644 --- a/src/mono/mono/mini/mini-s390x.c +++ b/src/mono/mono/mini/mini-s390x.c @@ -1,8 +1,9 @@ /** - * \file - * Function - S/390 backend for the Mono code generator. + * @file + * @author - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com) * - * Name - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com) + * @section description + * Function - S/390 backend for the Mono code generator. * * Date - January, 2004 * @@ -16,7 +17,7 @@ /* D e f i n e s */ /*------------------------------------------------------------------*/ -#define MAX_ARCH_DELEGATE_PARAMS 7 +#define MAX_ARCH_DELEGATE_PARAMS 10 #define EMIT_COND_BRANCH(ins,cond) \ { \ @@ -210,104 +211,6 @@ if (ins->inst_true_bb->native_offset) { \ } \ s390_ldgr (code, s390_f14, s390_r1); -#define MONO_EMIT_NEW_MOVE(cfg,dest,offset,src,imm,size) do { \ - MonoInst *inst; \ - int sReg, dReg; \ - MONO_INST_NEW (cfg, inst, OP_NOP); \ - if (size > 256) { \ - inst->dreg = dest; \ - inst->inst_offset = offset; \ - inst->sreg1 = src; \ - inst->inst_imm = imm; \ - } else { \ - if (s390_is_uimm12(offset)) { \ - inst->dreg = dest; \ - inst->inst_offset = offset; \ - } else { \ - dReg = mono_alloc_preg (cfg); \ - MONO_EMIT_NEW_BIALU_IMM(cfg, OP_ADD_IMM, \ - dReg, dest, offset); \ - inst->dreg = dReg; \ - inst->inst_offset = 0; \ - } \ - if (s390_is_uimm12(imm)) { \ - inst->sreg1 = src; \ - inst->inst_imm = imm; \ - } else { \ - sReg = mono_alloc_preg (cfg); \ - MONO_EMIT_NEW_BIALU_IMM(cfg, OP_ADD_IMM, \ - sReg, src, imm); \ - inst->sreg1 = sReg; \ - inst->inst_imm = 0; \ - } \ - } \ - inst->opcode = OP_S390_MOVE; \ - inst->backend.size = size; \ - MONO_ADD_INS (cfg->cbb, inst); \ - } while (0) - -#define MONO_OUTPUT_VTR(cfg, size, dr, sr, so) do { \ - int reg = mono_alloc_preg (cfg); \ - switch (size) { \ - case 0: \ - MONO_EMIT_NEW_ICONST(cfg, reg, 0); \ - break; \ - case 1: \ - MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU1_MEMBASE, \ - reg, sr, so); \ - break; \ - case 2: \ - MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU2_MEMBASE, \ - reg, sr, so); \ - break; \ - case 4: \ - MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADI4_MEMBASE, \ - reg, sr, so); \ - break; \ - case 8: \ - MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADI8_MEMBASE, \ - reg, sr, so); \ - break; \ - } \ - mono_call_inst_add_outarg_reg(cfg, call, reg, dr, FALSE); \ -} while (0) - -#define MONO_OUTPUT_VTS(cfg, size, dr, dx, sr, so) do { \ - int tmpr; \ - switch (size) { \ - case 0: \ - tmpr = mono_alloc_preg (cfg); \ - MONO_EMIT_NEW_ICONST(cfg, tmpr, 0); \ - MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, \ - dr, dx, tmpr); \ - break; \ - case 1: \ - tmpr = mono_alloc_preg (cfg); \ - MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU1_MEMBASE, \ - tmpr, sr, so); \ - MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, \ - dr, dx, tmpr); \ - break; \ - case 2: \ - tmpr = mono_alloc_preg (cfg); \ - MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU2_MEMBASE, \ - tmpr, sr, so); \ - MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, \ - dr, dx, tmpr); \ - break; \ - case 4: \ - tmpr = mono_alloc_preg (cfg); \ - MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADI4_MEMBASE, \ - tmpr, sr, so); \ - MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, \ - dr, dx, tmpr); \ - break; \ - case 8: \ - MONO_EMIT_NEW_MOVE (cfg, dr, dx, sr, so, size); \ - break; \ - } \ -} while (0) - #undef DEBUG #define DEBUG(a) if (cfg->verbose_level > 1) a @@ -315,9 +218,6 @@ if (ins->inst_true_bb->native_offset) { \ #define S390_TRACE_STACK_SIZE (5*sizeof(gpointer)+4*sizeof(gdouble)) -#define BREAKPOINT_SIZE sizeof(breakpoint_t) -#define S390X_NOP_SIZE sizeof(RR_Format) - #define MAX(a, b) ((a) > (b) ? (a) : (b)) /* @@ -368,24 +268,19 @@ if (ins->inst_true_bb->native_offset) { \ /* T y p e d e f s */ /*------------------------------------------------------------------*/ +/** + * Track stack use + */ typedef struct { guint stack_size, - local_size, code_size, parm_size, - offset, - offStruct, retStruct; } size_data; -typedef struct InstList InstList; - -struct InstList { - InstList *prev; - InstList *next; - MonoInst *data; -}; - +/** + * ABI - register use in calls etc. + */ typedef enum { RegTypeGeneral, RegTypeBase, @@ -393,13 +288,14 @@ typedef enum { RegTypeFPR4, RegTypeStructByVal, RegTypeStructByValInFP, - RegTypeStructByAddr, - RegTypeStructByAddrOnStack + RegTypeStructByAddr } ArgStorage; +/** + * Track method arguments + */ typedef struct { gint32 offset; /* offset from caller's stack */ - gint32 offparm; /* offset from callee's stack */ guint16 vtsize; /* in param area */ guint8 reg; ArgStorage regtype; @@ -407,6 +303,9 @@ typedef struct { gint32 type; /* Data type of argument */ } ArgInfo; +/** + * Call information - parameters and stack use for s390x ABI + */ struct CallInfo { int nargs; int lastgr; @@ -420,29 +319,23 @@ struct CallInfo { ArgInfo args [1]; }; +/** + * Registers used in parameter passing + */ typedef struct { gint64 gr[5]; /* R2-R6 */ gdouble fp[3]; /* F0-F2 */ } __attribute__ ((__packed__)) RegParm; -typedef struct { - RR_Format basr; - RI_Format j; - void *pTrigger; - RXY_Format lg; - RXY_Format trigger; -} __attribute__ ((__packed__)) breakpoint_t; - /*========================= End of Typedefs ========================*/ /*------------------------------------------------------------------*/ /* P r o t o t y p e s */ /*------------------------------------------------------------------*/ -static void indent (int); static guint8 * backUpStackPtr(MonoCompile *, guint8 *); static void add_general (guint *, size_data *, ArgInfo *); -static void add_stackParm (guint *, size_data *, ArgInfo *, gint); +static void add_stackParm (guint *, size_data *, ArgInfo *, gint, ArgStorage); static void add_float (guint *, size_data *, ArgInfo *, gboolean); static CallInfo * get_call_info (MonoMemPool *, MonoMethodSignature *); static guchar * emit_float_to_int (MonoCompile *, guchar *, int, int, int, gboolean); @@ -455,23 +348,19 @@ static void compare_and_branch(MonoBasicBlock *, MonoInst *, int, gboolean); /* G l o b a l V a r i a b l e s */ /*------------------------------------------------------------------*/ -__thread int indent_level = 0; -__thread FILE *trFd = NULL; -int curThreadNo = 0; - -/* - * The code generated for sequence points reads from this location, - * which is made read-only when single stepping is enabled. +/** + * The single-step trampoline */ -static gpointer ss_trigger_page; +static gpointer ss_trampoline; -/* - * Enabled breakpoints read from this trigger page +/** + * The breakpoint trampoline */ -static gpointer bp_trigger_page; - -breakpoint_t breakpointCode; +static gpointer bp_trampoline; +/** + * Constants used in debugging - map general register names + */ static const char * grNames[] = { "s390_r0", "s390_sp", "s390_r2", "s390_r3", "s390_r4", "s390_r5", "s390_r6", "s390_r7", "s390_r8", "s390_r9", @@ -479,6 +368,9 @@ static const char * grNames[] = { "s390_r15" }; +/** + * Constants used in debugging - map floating point register names + */ static const char * fpNames[] = { "s390_f0", "s390_f1", "s390_f2", "s390_f3", "s390_f4", "s390_f5", "s390_f6", "s390_f7", "s390_f8", "s390_f9", @@ -486,6 +378,9 @@ static const char * fpNames[] = { "s390_f15" }; +/** + * Constants used in debugging - map vector register names + */ static const char * vrNames[] = { "vr0", "vr1", "vr2", "vr3", "vr4", "vr5", "vr6", "vr7", "vr8", "vr9", "vr10", "vr11", "vr12", "vr13", "vr14", "vr15", @@ -493,16 +388,25 @@ static const char * vrNames[] = { "vr24", "vr25", "vr26", "vr27", "vr28", "vr29", "vr30", "vr31" }; +#if 0 +/** + * Constants used in debugging - ABI register types + */ +static const char *typeParm[] = { "General", "Base", "FPR8", "FPR4", "StructByVal", + "StructByValInFP", "ByAddr"}; +#endif + /*====================== End of Global Variables ===================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_regname */ -/* */ -/* Function - Returns the name of the register specified by */ -/* the input parameter. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Return general register name + * + * @param[in] register number + * @returns Name of register + * + * Returns the name of the general register specified by the input parameter. + */ const char* mono_arch_regname (int reg) @@ -515,14 +419,15 @@ mono_arch_regname (int reg) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_fregname */ -/* */ -/* Function - Returns the name of the register specified by */ -/* the input parameter. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Return floating point register name + * + * @param[in] register number + * @returns Name of register + * + * Returns the name of the FP register specified by the input parameter. + */ const char* mono_arch_fregname (int reg) @@ -535,14 +440,15 @@ mono_arch_fregname (int reg) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_xregname */ -/* */ -/* Function - Returns the name of the register specified by */ -/* the input parameter. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Return vector register name + * + * @param[in] register number + * @returns Name of register + * + * Returns the name of the vector register specified by the input parameter. + */ const char * mono_arch_xregname (int reg) @@ -555,21 +461,18 @@ mono_arch_xregname (int reg) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - arch_get_argument_info */ -/* */ -/* Function - Gathers information on parameters such as size, */ -/* alignment, and padding. arg_info should be large */ -/* enough to hold param_count + 1 entries. */ -/* */ -/* Parameters - @csig - Method signature */ -/* @param_count - No. of parameters to consider */ -/* @arg_info - An array to store the result info */ -/* */ -/* Returns - Size of the activation frame */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific return argument information + * + * @param[in] @csig - Method signature + * @param[in] @param_count - Number of parameters to consider + * @param[out] @arg_info - An array in which to store results + * @returns Size of the activation frame + * + * Gathers information on parameters such as size, alignment, and padding. + * arg_info should be large * enough to hold param_count + 1 entries. + */ int mono_arch_get_argument_info (MonoMethodSignature *csig, @@ -620,62 +523,193 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - emit_unwind_regs. */ -/* */ -/* Function - Emit unwind information for a range of registers. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Emit an s390x move operation + * + * @param[in] @cfg - MonoCompile control block + * @param[in] @dr - Destination register + * @param[in] @ins - Current instruction + * @param[in] @src - Instruction representing the source of move + * + * Emit a move instruction for VT parameters + */ static void __inline__ -emit_unwind_regs(MonoCompile *cfg, guint8 *code, int start, int end, long offset) +emit_new_move(MonoCompile *cfg, int dr, MonoInst *ins, MonoInst *src) { - int i; + MonoCallInst *call = (MonoCallInst *) ins->inst_p0; + ArgInfo *ainfo = (ArgInfo *) ins->inst_p1; + MonoInst *vtcopy = mono_compile_create_var (cfg, m_class_get_byval_arg (src->klass), OP_LOCAL); + MonoInst *load; + MonoInst *move; + int size; + + if (call->signature->pinvoke) { + size = mono_type_native_stack_size (m_class_get_byval_arg (src->klass), NULL); + vtcopy->backend.is_pinvoke = 1; + } else { + size = ins->backend.size; + } - for (i = start; i < end; i++) { - mono_emit_unwind_op_offset (cfg, code, i, offset); - mini_gc_set_slot_type_from_cfa (cfg, offset, SLOT_NOREF); - offset += sizeof(gulong); + EMIT_NEW_VARLOADA (cfg, load, vtcopy, vtcopy->inst_vtype); + + MONO_INST_NEW (cfg, move, OP_S390_MOVE); + move->sreg2 = load->dreg; + move->inst_offset = 0; + move->sreg1 = src->dreg; + move->inst_imm = 0; + move->backend.size = size; + MONO_ADD_INS (cfg->cbb, move); + if (dr != 0) + MONO_EMIT_NEW_UNALU(cfg, OP_MOVE, dr, load->dreg); + else + MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, + ainfo->reg, ainfo->offset, load->dreg); +} + +/*========================= End of Function ========================*/ + +/** + * + * @brief Generate output sequence for VT register parameters + * + * @param[in] @cfg - MonoCompile control block + * @param[in] @dr - Destination register + * @param[in] @ins - Current instruction + * @param[in] @src - Instruction representing the source + * + * Emit the output of structures for calls whose address is placed in a register. + */ + +static void __inline__ +emit_outarg_vtr(MonoCompile *cfg, MonoInst *ins, MonoInst *src) +{ + MonoCallInst *call = (MonoCallInst *) ins->inst_p0; + ArgInfo *ainfo = (ArgInfo *) ins->inst_p1; + int reg = mono_alloc_preg (cfg); + + switch (ins->backend.size) { + case 0: + MONO_EMIT_NEW_ICONST(cfg, reg, 0); + break; + case 1: + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU1_MEMBASE, + reg, src->dreg, 0); + break; + case 2: + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU2_MEMBASE, + reg, src->dreg, 0); + break; + case 4: + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADI4_MEMBASE, + reg, src->dreg, 0); + break; + case 8: + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADI8_MEMBASE, + reg, src->dreg, 0); + break; + default: + emit_new_move (cfg, reg, ins, src); } + mono_call_inst_add_outarg_reg(cfg, call, reg, ainfo->reg, FALSE); } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - retFitsInReg. */ -/* */ -/* Function - Determines if a value can be returned in one or */ -/* two registers. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Generate output sequence for VT stack parameters + * + * @param[in] @cfg - MonoCompile control block + * @param[in] @dr - Destination register + * @param[in] @ins - Current instruction + * @param[in] @src - Instruction representing the source + * + * Emit the output of structures for calls whose address is placed on the stack + */ -static gboolean -retFitsInReg(guint32 size) +static void __inline__ +emit_outarg_vts(MonoCompile *cfg, MonoInst *ins, MonoInst *src) { - switch (size) { + ArgInfo *ainfo = (ArgInfo *) ins->inst_p1; + int tmpr = mono_alloc_preg (cfg); + + switch (ins->backend.size) { case 0: + MONO_EMIT_NEW_ICONST(cfg, tmpr, 0); + MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, + ainfo->reg, ainfo->offset, tmpr); + break; case 1: + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU1_MEMBASE, + tmpr, src->dreg, 0); + MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, + ainfo->reg, ainfo->offset, tmpr); + break; case 2: + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADU2_MEMBASE, + tmpr, src->dreg, 0); + MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, + ainfo->reg, ainfo->offset, tmpr); + break; case 4: + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADI4_MEMBASE, + tmpr, src->dreg, 0); + MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, + ainfo->reg, ainfo->offset, tmpr); + break; case 8: - return (TRUE); + MONO_EMIT_NEW_LOAD_MEMBASE_OP(cfg, OP_LOADI8_MEMBASE, + tmpr, src->dreg, 0); + MONO_EMIT_NEW_STORE_MEMBASE(cfg, OP_STORE_MEMBASE_REG, + ainfo->reg, ainfo->offset, tmpr); break; - default: - return (FALSE); + default: { + emit_new_move (cfg, 0, ins, src); + } } } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - backStackPtr. */ -/* */ -/* Function - Restore Stack Pointer to previous frame. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Generate unwind information for range of registers + * + * @param[in] @cfg - MonoCompile control block + * @param[in] @code - Location of code + * @param[in] @start - Starting register + * @param[in] @end - Ending register + * @param[in] @offset - Offset in stack + * + * Emit unwind information for a range of registers. + */ + +static void __inline__ +emit_unwind_regs(MonoCompile *cfg, guint8 *code, int start, int end, long offset) +{ + int i; + + for (i = start; i < end; i++) { + mono_emit_unwind_op_offset (cfg, code, i, offset); + mini_gc_set_slot_type_from_cfa (cfg, offset, SLOT_NOREF); + offset += sizeof(gulong); + } +} + +/*========================= End of Function ========================*/ + +/** + * + * @brief Get previous stack frame pointer + * + * @param[in] @cfg - MonoCompile control block + * @param[in] @code - Location of code + * @returns Previous stack pointer + * + * Retrieve the stack pointer of the previous frame + */ static guint8 * backUpStackPtr(MonoCompile *cfg, guint8 *code) @@ -687,15 +721,16 @@ backUpStackPtr(MonoCompile *cfg, guint8 *code) } else { if (cfg->frame_reg != STK_BASE) s390_lgr (code, STK_BASE, cfg->frame_reg); - if (s390_is_imm16 (stackSize)) { s390_aghi (code, STK_BASE, stackSize); - } else { - while (stackSize > 32767) { - s390_aghi (code, STK_BASE, 32767); - stackSize -= 32767; + } else if (s390_is_imm32 (stackSize)) { + s390_agfi (code, STK_BASE, stackSize); + } else { + while (stackSize > INT_MAX) { + s390_aghi (code, STK_BASE, INT_MAX); + stackSize -= INT_MAX; } - s390_aghi (code, STK_BASE, stackSize); + s390_agfi (code, STK_BASE, stackSize); } } @@ -704,129 +739,12 @@ backUpStackPtr(MonoCompile *cfg, guint8 *code) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - indent */ -/* */ -/* Function - Perform nice indenting to current level */ -/* */ -/*------------------------------------------------------------------*/ - -static void -indent (int diff) { - int v; - if (diff < 0) - indent_level += diff; - v = indent_level; - fprintf (trFd, "%p [%3d] ",(void *)pthread_self(),v); - while (v-- > 0) { - fprintf (trFd, ". "); - } - if (diff > 0) - indent_level += diff; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - cvtMonoType */ -/* */ -/* Function - Convert a mono-type to a string. */ -/* */ -/*------------------------------------------------------------------*/ - -static const char * -cvtMonoType(MonoTypeEnum t) -{ - switch(t) - { - case MONO_TYPE_END: - return "MONO_TYPE_END"; - case MONO_TYPE_VOID: - return "MONO_TYPE_VOID"; - case MONO_TYPE_BOOLEAN: - return "MONO_TYPE_BOOLEAN"; - case MONO_TYPE_CHAR: - return "MONO_TYPE_CHAR"; - case MONO_TYPE_I1: - return "MONO_TYPE_I1"; - case MONO_TYPE_U1: - return "MONO_TYPE_U1"; - case MONO_TYPE_I2: - return "MONO_TYPE_I2"; - case MONO_TYPE_U2: - return "MONO_TYPE_U2"; - case MONO_TYPE_I4: - return "MONO_TYPE_I4"; - case MONO_TYPE_U4: - return "MONO_TYPE_U4"; - case MONO_TYPE_I8: - return "MONO_TYPE_I8"; - case MONO_TYPE_U8: - return "MONO_TYPE_U8"; - case MONO_TYPE_R4: - return "MONO_TYPE_R4"; - case MONO_TYPE_R8: - return "MONO_TYPE_R8"; - case MONO_TYPE_STRING: - return "MONO_TYPE_STRING"; - case MONO_TYPE_PTR: - return "MONO_TYPE_PTR"; - case MONO_TYPE_BYREF: - return "MONO_TYPE_BYREF"; - case MONO_TYPE_VALUETYPE: - return "MONO_TYPE_VALUETYPE"; - case MONO_TYPE_CLASS: - return "MONO_TYPE_CLASS"; - case MONO_TYPE_VAR: - return "MONO_TYPE_VAR"; - case MONO_TYPE_ARRAY: - return "MONO_TYPE_ARRAY"; - case MONO_TYPE_GENERICINST: - return "MONO_TYPE_GENERICINST"; - case MONO_TYPE_TYPEDBYREF: - return "MONO_TYPE_TYPEDBYREF"; - case MONO_TYPE_I: - return "MONO_TYPE_I"; - case MONO_TYPE_U: - return "MONO_TYPE_U"; - case MONO_TYPE_FNPTR: - return "MONO_TYPE_FNPTR"; - case MONO_TYPE_OBJECT: - return "MONO_TYPE_OBJECT"; - case MONO_TYPE_SZARRAY: - return "MONO_TYPE_SZARRAY"; - case MONO_TYPE_MVAR: - return "MONO_TYPE_MVAR"; - case MONO_TYPE_CMOD_REQD: - return "MONO_TYPE_CMOD_REQD"; - case MONO_TYPE_CMOD_OPT: - return "MONO_TYPE_CMOD_OPT"; - case MONO_TYPE_INTERNAL: - return "MONO_TYPE_INTERNAL"; - case MONO_TYPE_MODIFIER: - return "MONO_TYPE_MODIFIER"; - case MONO_TYPE_SENTINEL: - return "MONO_TYPE_SENTINEL"; - case MONO_TYPE_PINNED: - return "MONO_TYPE_PINNED"; - default: - ; - } - return "unknown"; -} - -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_cpu_init */ -/* */ -/* Function - Perform CPU specific initialization to execute */ -/* managed code. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific CPU initialization + * + * Perform CPU specific initialization to execute managed code. + */ void mono_arch_cpu_init (void) @@ -835,63 +753,52 @@ mono_arch_cpu_init (void) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_init. */ -/* */ -/* Function - Initialize architecture specific code. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Archictecture specific initialization + * + * + * Initialize architecture specific code: + * - Define trigger pages for debugger + * - Generate breakpoint code stub + */ void mono_arch_init (void) { - guint8 *code; - mono_set_partial_sharing_supported (FALSE); - ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ, MONO_MEM_ACCOUNT_OTHER); - bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ, MONO_MEM_ACCOUNT_OTHER); - mono_mprotect (bp_trigger_page, mono_pagesize (), 0); - - code = (guint8 *) &breakpointCode; - s390_basr(code, s390_r13, 0); - s390_j(code, 6); - s390_llong(code, 0); - s390_lg(code, s390_r13, 0, s390_r13, 4); - s390_lg(code, s390_r0, 0, s390_r13, 0); + if (!mono_aot_only) + bp_trampoline = mini_get_breakpoint_trampoline(); } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_cleanup. */ -/* */ -/* Function - Cleanup architecture specific code . */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific cleaup code + * + * + * Clean up before termination: + * - Free the trigger pages + */ void mono_arch_cleanup (void) { - if (ss_trigger_page) - mono_vfree (ss_trigger_page, mono_pagesize (), MONO_MEM_ACCOUNT_OTHER); - if (bp_trigger_page) - mono_vfree (bp_trigger_page, mono_pagesize (), MONO_MEM_ACCOUNT_OTHER); } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_have_fast_tls */ -/* */ -/* Function - Returns whether we use fast inlined thread local */ -/* storage managed access, instead of falling back */ -/* to native code. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific check for fast TLS access + * + * @returns True + * + * Returns whether we use fast inlined thread local storage managed access, + * instead of falling back to native code. + */ gboolean mono_arch_have_fast_tls (void) @@ -901,35 +808,39 @@ mono_arch_have_fast_tls (void) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_cpu_optimizations */ -/* */ -/* Function - Returns the optimizations supported on this CPU */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific check of mono optimizations + * + * @param[out] @exclude_mask - Optimization exclusion mask + * @returns Optimizations supported on this CPU + * + * Returns the optimizations supported on this CPU + */ guint32 mono_arch_cpu_optimizations (guint32 *exclude_mask) { guint32 opts = 0; - /*----------------------------------------------------------*/ - /* No s390-specific optimizations yet */ - /*----------------------------------------------------------*/ + /* + * No s390-specific optimizations yet + */ *exclude_mask = MONO_OPT_LINEARS; return opts; } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_get_allocatable_int_vars */ -/* */ -/* Function - */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific allocation of integer variables + * + * @param[in] @cfg - MonoCompile control block + * @returns A list of integer variables + * + * Returns a list of allocatable integer variables + */ GList * mono_arch_get_allocatable_int_vars (MonoCompile *cfg) @@ -962,13 +873,15 @@ mono_arch_get_allocatable_int_vars (MonoCompile *cfg) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_global_int_regs */ -/* */ -/* Function - Return a list of usable integer registers. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific determination of usable integer registers + * + * @param[in] @cfg - MonoCompile control block + * @returns A list of allocatable registers + * + * Returns a list of usable integer registers + */ GList * mono_arch_get_global_int_regs (MonoCompile *cfg) @@ -996,13 +909,15 @@ mono_arch_get_global_int_regs (MonoCompile *cfg) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_flush_icache */ -/* */ -/* Function - Flush the CPU icache. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific flush of instruction cache + * + * @param[in] @code - Start of code + * @param[in] @size - Amount to be flushed + * + * Flush the CPU icache. + */ void mono_arch_flush_icache (guint8 *code, gint size) @@ -1011,14 +926,16 @@ mono_arch_flush_icache (guint8 *code, gint size) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - add_general */ -/* */ -/* Function - Determine code and stack size incremements for a */ -/* parameter. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Add an integer register parameter + * + * @param[in] @gr - Address of current register number + * @param[in] @sz - Stack size data + * @param[in] @ainfo - Parameter information + * + * Assign a parameter to a general register or spill it onto the stack + */ static void inline add_general (guint *gr, size_data *sz, ArgInfo *ainfo) @@ -1026,14 +943,13 @@ add_general (guint *gr, size_data *sz, ArgInfo *ainfo) if (*gr > S390_LAST_ARG_REG) { sz->stack_size = S390_ALIGN(sz->stack_size, sizeof(long)); ainfo->offset = sz->stack_size; - ainfo->reg = STK_BASE; + ainfo->reg = STK_BASE; ainfo->regtype = RegTypeBase; sz->stack_size += sizeof(long); - sz->local_size += sizeof(long); - sz->offStruct += sizeof(long); sz->code_size += 12; } else { ainfo->reg = *gr; + ainfo->regtype = RegTypeGeneral; sz->code_size += 8; } (*gr) ++; @@ -1041,34 +957,33 @@ add_general (guint *gr, size_data *sz, ArgInfo *ainfo) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - add_stackParm */ -/* */ -/* Function - Determine code and stack size incremements for a */ -/* parameter. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Add a structure variable to parameter list + * + * @param[in] @gr - Address of current register number + * @param[in] @sz - Stack size data + * @param[in] @ainfo - Parameter information + * @param[in] @size - Size of parameter + * @param[in] @type - Type of stack parameter (reference or value) + * + * Assign a structure address to a register or spill it onto the stack + */ static void inline -add_stackParm (guint *gr, size_data *sz, ArgInfo *ainfo, gint size) +add_stackParm (guint *gr, size_data *sz, ArgInfo *ainfo, gint size, ArgStorage type) { if (*gr > S390_LAST_ARG_REG) { sz->stack_size = S390_ALIGN(sz->stack_size, sizeof(long)); ainfo->reg = STK_BASE; - ainfo->offset = sz->stack_size; - ainfo->regtype = RegTypeStructByAddrOnStack; - sz->stack_size += sizeof (target_mgreg_t); + ainfo->offset = sz->stack_size; + sz->stack_size += sizeof (target_mgreg_t); sz->parm_size += sizeof(gpointer); - sz->offStruct += sizeof(gpointer); } else { ainfo->reg = *gr; - ainfo->offset = sz->stack_size; - ainfo->regtype = RegTypeStructByAddr; } (*gr) ++; - ainfo->offparm = sz->offset; - sz->offset = S390_ALIGN(sz->offset+size, sizeof(long)); + ainfo->regtype = type; ainfo->size = size; ainfo->vtsize = size; sz->parm_size += size; @@ -1076,14 +991,17 @@ add_stackParm (guint *gr, size_data *sz, ArgInfo *ainfo, gint size) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - add_float */ -/* */ -/* Function - Determine code and stack size incremements for a */ -/* float parameter. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Add a floating point register parameter + * + * @param[in] @fr - Address of current register number + * @param[in] @sz - Stack size data + * @param[in] @ainfo - Parameter information + * @param[in] @isDouble - Precision of parameter + * + * Assign a parameter to a FP register or spill it onto the stack + */ static void inline add_float (guint *fr, size_data *sz, ArgInfo *ainfo, gboolean isDouble) @@ -1102,24 +1020,24 @@ add_float (guint *fr, size_data *sz, ArgInfo *ainfo, gboolean isDouble) ainfo->reg = STK_BASE; sz->code_size += 4; sz->stack_size += sizeof(double); - sz->local_size += sizeof(double); - sz->offStruct += sizeof(double); ainfo->regtype = RegTypeBase; } } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - get_call_info */ -/* */ -/* Function - Determine the amount of space required for code */ -/* and stack. In addition determine starting points */ -/* for stack-based parameters, and area for struct- */ -/* ures being returned on the stack. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Extract information about call parameters and stack use + * + * @param[in] @mp - Mono Memory Pool + * @param[in] @sig - Mono Method Signature + * @returns Information about the parameters and stack usage for a call + * + * Determine the amount of space required for code and stack. In addition + * determine starting points for stack-based parameters, and area for + * structures being returned on the stack. + */ static CallInfo * get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) @@ -1144,12 +1062,9 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) cinfo->sig = sig; sz = &cinfo->sz; sz->retStruct = 0; - sz->offset = 0; - sz->offStruct = S390_MINIMAL_STACK_SIZE; sz->stack_size = S390_MINIMAL_STACK_SIZE; sz->code_size = 0; sz->parm_size = 0; - sz->local_size = 0; align = 0; size = 0; @@ -1174,6 +1089,10 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) case MONO_TYPE_OBJECT: case MONO_TYPE_PTR: case MONO_TYPE_FNPTR: + case MONO_TYPE_CLASS: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_ARRAY: + case MONO_TYPE_STRING: cinfo->ret.reg = s390_r2; sz->code_size += 4; break; @@ -1207,11 +1126,16 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) cinfo->ret.vtsize = size; break; } - case MONO_TYPE_TYPEDBYREF: - size = MONO_ABI_SIZEOF (MonoTypedRef); + case MONO_TYPE_TYPEDBYREF: { + MonoClass *klass = mono_class_from_mono_type_internal (sig->ret); + size = mini_type_stack_size_full (m_class_get_byval_arg (klass), NULL, sig->pinvoke); + cinfo->struct_ret = 1; cinfo->ret.size = size; cinfo->ret.vtsize = size; + // cinfo->ret.reg = s390_r2; + // sz->code_size += 4; + } break; case MONO_TYPE_VOID: break; @@ -1254,7 +1178,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) if (cinfo->struct_ret) { cinfo->ret.reg = gr; - gr ++; + gr++; } } @@ -1320,6 +1244,9 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) case MONO_TYPE_PTR: case MONO_TYPE_FNPTR: case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_ARRAY: cinfo->args[nParm].size = sizeof(gpointer); add_general (&gr, sz, cinfo->args+nParm); nParm++; @@ -1397,41 +1324,16 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) cinfo->args[nParm].size = size; cinfo->args[nParm].regtype = RegTypeStructByVal; nParm++; - sz->local_size += sizeof(long); break; default: - add_stackParm(&gr, sz, cinfo->args+nParm, size); + add_stackParm(&gr, sz, cinfo->args+nParm, size, RegTypeStructByVal); nParm++; } } break; case MONO_TYPE_TYPEDBYREF: { - int size = MONO_ABI_SIZEOF (MonoTypedRef); - - cinfo->args[nParm].vtsize = 0; - cinfo->args[nParm].size = 0; - - switch (size) { - /*----------------------------------*/ - /* On S/390, structures of size 1, */ - /* 2, 4, and 8 bytes are passed in */ - /* (a) register(s). */ - /*----------------------------------*/ - case 0: - case 1: - case 2: - case 4: - case 8: - add_general(&gr, sz, cinfo->args+nParm); - cinfo->args[nParm].size = size; - cinfo->args[nParm].regtype = RegTypeStructByVal; - nParm++; - sz->local_size += sizeof(long); - break; - default: - add_stackParm(&gr, sz, cinfo->args+nParm, size); - nParm++; - } + add_stackParm(&gr, sz, cinfo->args+nParm, sizeof(uintptr_t), RegTypeStructByAddr); + nParm++; } break; default: @@ -1471,8 +1373,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) } cinfo->lastgr = gr; - sz->stack_size = sz->stack_size + sz->local_size + sz->parm_size + - sz->offset; + sz->stack_size = sz->stack_size + sz->parm_size; sz->stack_size = S390_ALIGN(sz->stack_size, sizeof(long)); return (cinfo); @@ -1480,17 +1381,15 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_allocate_vars */ -/* */ -/* Function - Set var information according to the calling */ -/* convention for S/390. The local var stuff should */ -/* most likely be split in another method. */ -/* */ -/* Parameter - @m - Compile unit. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific allocation of variables + * + * @param[in] @cfg - Compile control block + * + * Set var information according to the calling convention for s390x. + * + */ void mono_arch_allocate_vars (MonoCompile *cfg) @@ -1527,20 +1426,9 @@ mono_arch_allocate_vars (MonoCompile *cfg) if (frame_reg != STK_BASE) cfg->used_int_regs |= (1LL << frame_reg); - sig = mono_method_signature_internal (cfg->method); + sig = mono_method_signature_internal (cfg->method); - cinfo = get_call_info (cfg->mempool, sig); - - if (!cinfo->struct_ret) { - switch (mini_get_underlying_type (sig->ret)->type) { - case MONO_TYPE_VOID: - break; - default: - cfg->ret->opcode = OP_REGVAR; - cfg->ret->dreg = s390_r2; - break; - } - } + cinfo = get_call_info (cfg->mempool, sig); /*--------------------------------------------------------------*/ /* local vars are at a positive offset from the stack pointer */ @@ -1555,27 +1443,27 @@ mono_arch_allocate_vars (MonoCompile *cfg) cfg->sig_cookie = 0; - if (cinfo->struct_ret) { - inst = cfg->vret_addr; - offset = S390_ALIGN(offset, sizeof(gpointer)); - inst->inst_offset = offset; - inst->opcode = OP_REGOFFSET; - inst->inst_basereg = frame_reg; - offset += sizeof(gpointer); - if (G_UNLIKELY (cfg->verbose_level > 1)) { - printf ("vret_addr ="); - mono_print_ins (cfg->vret_addr); - } - } + if (MONO_TYPE_ISSTRUCT(sig->ret)) { + cfg->ret->opcode = OP_REGVAR; + cfg->ret->inst_c0 = cfg->ret->dreg = cinfo->ret.reg; + } else { + switch (mini_get_underlying_type (sig->ret)->type) { + case MONO_TYPE_VOID: + break; + default: + cfg->ret->opcode = OP_REGVAR; + cfg->ret->inst_c0 = cfg->ret->dreg = cinfo->ret.reg; + } + } if (sig->hasthis) { inst = cfg->args [0]; if (inst->opcode != OP_REGVAR) { inst->opcode = OP_REGOFFSET; inst->inst_basereg = frame_reg; - offset = S390_ALIGN(offset, sizeof(gpointer)); + offset = S390_ALIGN(offset, sizeof(gpointer)); inst->inst_offset = offset; - offset += sizeof (target_mgreg_t); + offset += sizeof (target_mgreg_t); } curinst = sArg = 1; } else { @@ -1596,46 +1484,69 @@ mono_arch_allocate_vars (MonoCompile *cfg) size = sizeof (target_mgreg_t); - inst->opcode = OP_REGOFFSET; - inst->inst_basereg = frame_reg; - offset = S390_ALIGN (offset, sizeof (target_mgreg_t)); - inst->inst_offset = offset; + if (cinfo->args [iParm].reg == STK_BASE) { - /* Add a level of indirection */ - MONO_INST_NEW (cfg, indir, 0); - *indir = *inst; - inst->opcode = OP_VTARG_ADDR; - inst->inst_left = indir; - } - break; - case RegTypeStructByAddrOnStack : { - MonoInst *indir; - - size = sizeof (target_mgreg_t); - - /* Similar to the == STK_BASE case below */ - cfg->arch.bkchain_reg = s390_r12; - cfg->used_int_regs |= 1 << cfg->arch.bkchain_reg; + /* Similar to the == STK_BASE case below */ + cfg->arch.bkchain_reg = s390_r12; + cfg->used_int_regs |= 1 << cfg->arch.bkchain_reg; - inst->opcode = OP_REGOFFSET; - inst->dreg = mono_alloc_preg (cfg); - inst->inst_basereg = cfg->arch.bkchain_reg; - inst->inst_offset = cinfo->args [iParm].offset; + inst->opcode = OP_REGOFFSET; + inst->dreg = mono_alloc_preg (cfg); + inst->inst_basereg = cfg->arch.bkchain_reg; + inst->inst_offset = cinfo->args [iParm].offset; + } else { + inst->opcode = OP_REGOFFSET; + inst->dreg = cinfo->args [iParm].reg; + inst->opcode = OP_REGOFFSET; + inst->dreg = mono_alloc_preg (cfg); + inst->inst_basereg = cfg->frame_reg; + // inst->inst_offset = cinfo->args [iParm].offset; + inst->inst_offset = offset; + } /* Add a level of indirection */ MONO_INST_NEW (cfg, indir, 0); *indir = *inst; inst->opcode = OP_VTARG_ADDR; inst->inst_left = indir; - break; } - case RegTypeStructByVal : - size = cinfo->args[iParm].size; - offset = S390_ALIGN(offset, size); - inst->opcode = OP_REGOFFSET; - inst->inst_basereg = frame_reg; - inst->inst_offset = offset; break; + case RegTypeStructByVal : { + MonoInst *indir; + + cfg->arch.bkchain_reg = s390_r12; + cfg->used_int_regs |= 1 << cfg->arch.bkchain_reg; + size = cinfo->args[iParm].size; + + if (cinfo->args [iParm].reg == STK_BASE) { + int offStruct = 0; + switch(size) { + case 0: case 1: case 2: case 4: case 8: + offStruct = (size < 8 ? sizeof(uintptr_t) - size : 0); + default: + inst->opcode = OP_REGOFFSET; + inst->dreg = mono_alloc_preg (cfg); + inst->inst_basereg = cfg->arch.bkchain_reg; + inst->inst_offset = cinfo->args [iParm].offset + offStruct; + } + } else { + offset = S390_ALIGN(offset, sizeof(uintptr_t)); + inst->opcode = OP_REGOFFSET; + inst->inst_basereg = cfg->frame_reg; + inst->inst_offset = offset; + } + switch (size) { + case 0 : case 1 : case 2 : case 4 : case 8 : + break; + default : + /* Add a level of indirection */ + MONO_INST_NEW (cfg, indir, 0); + *indir = *inst; + inst->opcode = OP_VTARG_ADDR; + inst->inst_left = indir; + } + } + break; default : if (cinfo->args [iParm].reg == STK_BASE) { /* @@ -1649,24 +1560,23 @@ mono_arch_allocate_vars (MonoCompile *cfg) inst->opcode = OP_REGOFFSET; inst->inst_basereg = cfg->arch.bkchain_reg; - size = (cinfo->args[iParm].size < 8 - ? 8 - cinfo->args[iParm].size - : 0); + size = (cinfo->args[iParm].size < 8 + ? 8 - cinfo->args[iParm].size + : 0); inst->inst_offset = cinfo->args [iParm].offset + size; size = sizeof (long); } else { inst->opcode = OP_REGOFFSET; inst->inst_basereg = frame_reg; - size = (cinfo->args[iParm].size < 8 - ? sizeof(int) - : sizeof(long)); - offset = S390_ALIGN(offset, size); + size = (cinfo->args[iParm].size < 8 + ? sizeof(int) + : sizeof(long)); + offset = S390_ALIGN(offset, size); if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) inst->inst_offset = offset; else inst->inst_offset = offset + (8 - size); } - break; } offset += MAX(size, 8); } @@ -1701,6 +1611,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) DEBUG (g_print("allocating local %d to %ld, size: %d\n", iVar, inst->inst_offset, size)); } + offset = S390_ALIGN(offset, sizeof(uintptr_t)); cfg->locals_max_stack_offset = offset; @@ -1708,7 +1619,7 @@ mono_arch_allocate_vars (MonoCompile *cfg) /* Reserve space to save LMF and caller saved registers */ /*------------------------------------------------------*/ if (cfg->method->save_lmf) - offset += sizeof (MonoLMF); + offset += sizeof (MonoLMF); /*------------------------------------------------------*/ /* align the offset */ @@ -1730,38 +1641,56 @@ mono_arch_allocate_vars (MonoCompile *cfg) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_create_vars */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific creation of variables + * + * @param[in] @cfg - Compile control block + * + * Create variables for the method. + * + */ void mono_arch_create_vars (MonoCompile *cfg) { - MonoMethodSignature *sig; - CallInfo *cinfo; - - sig = mono_method_signature_internal (cfg->method); - - cinfo = get_call_info (cfg->mempool, sig); + MonoMethodSignature *sig = mono_method_signature_internal (cfg->method); - if (cinfo->struct_ret) { + if (MONO_TYPE_ISSTRUCT (sig->ret)) { cfg->vret_addr = mono_compile_create_var (cfg, mono_get_int_type (), OP_ARG); if (G_UNLIKELY (cfg->verbose_level > 1)) { printf ("vret_addr = "); mono_print_ins (cfg->vret_addr); } } + + if (cfg->gen_sdb_seq_points) { + MonoInst *ins; + + ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL); + ins->flags |= MONO_INST_VOLATILE; + cfg->arch.ss_tramp_var = ins; + + ins = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL); + ins->flags |= MONO_INST_VOLATILE; + cfg->arch.bp_tramp_var = ins; + } } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - add_outarg_reg2. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Add a register to the call operation + * + * @param[in] @cfg - Compile control block + * @param[in] @call - Call Instruction + * @param[in] @storage - Register use type + * @param[in] @reg - Register number + * @param[in] @tree - Call arguments + * + * Add register use information to the call sequence + */ static void add_outarg_reg2 (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, MonoInst *tree) @@ -1797,11 +1726,16 @@ add_outarg_reg2 (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int r /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - emit_sig_cookie. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Emit a signature cookine + * + * @param[in] @cfg - Compile control block + * @param[in] @call - Call Instruction + * @param[in] @cinfo - Call Information + * + * Emit the signature cooke as a parameter + */ static void emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) @@ -1811,12 +1745,12 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) cfg->disable_aot = TRUE; - /*----------------------------------------------------------*/ - /* mono_ArgIterator_Setup assumes the signature cookie is */ - /* passed first and all the arguments which were before it */ - /* passed on the stack after the signature. So compensate */ - /* by passing a different signature. */ - /*----------------------------------------------------------*/ + /* + * mono_ArgIterator_Setup assumes the signature cookie is + * passed first and all the arguments which were before it + * passed on the stack after the signature. So compensate + * by passing a different signature. + */ tmpSig = mono_metadata_signature_dup (call->signature); tmpSig->param_count -= call->signature->sentinelpos; tmpSig->sentinelpos = 0; @@ -1836,11 +1770,16 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_emit_call */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific emission of a call operation + * + * @param[in] @cfg - Compile control block + * @param[in] @call - Call Instruction + * + * Process all parameters for a call and generate the sequence of + * operations to perform the call according to the s390x ABI. + */ void mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) @@ -1859,11 +1798,10 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) cinfo = get_call_info (cfg->mempool, sig); - stackSize = cinfo->sz.stack_size + cinfo->sz.local_size + - cinfo->sz.parm_size + cinfo->sz.offset; + stackSize = cinfo->sz.stack_size + cinfo->sz.parm_size; call->stack_usage = MAX(stackSize, call->stack_usage); lParamArea = MAX((call->stack_usage-S390_MINIMAL_STACK_SIZE-cinfo->sz.parm_size), 0); - cfg->param_area = MAX(((signed) cfg->param_area), lParamArea); + cfg->param_area = MAX(((signed) cfg->param_area), lParamArea); /* FIXME */ cfg->flags |= MONO_CFG_HAS_CALLS; if (cinfo->struct_ret) { @@ -1907,32 +1845,10 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) break; } case RegTypeStructByVal : - case RegTypeStructByAddr : - case RegTypeStructByAddrOnStack : { - guint32 align; - guint32 size; - - if (sig->params [i - sig->hasthis]->type == MONO_TYPE_TYPEDBYREF) { - size = MONO_ABI_SIZEOF (MonoTypedRef); - align = sizeof (target_mgreg_t); - } - else - if (sig->pinvoke) - size = mono_type_native_stack_size (m_class_get_byval_arg (in->klass), &align); - else { - /* - * Other backends use mono_type_stack_size (), but that - * aligns the size to 8, which is larger than the size of - * the source, leading to reads of invalid memory if the - * source is at the end of address space. - */ - size = mono_class_value_size (in->klass, &align); - } + case RegTypeStructByAddr : { g_assert (in->klass); - ainfo->offparm += cinfo->sz.offStruct; - MONO_INST_NEW (cfg, ins, OP_OUTARG_VT); ins->sreg1 = in->dreg; ins->klass = in->klass; @@ -1977,46 +1893,32 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) emit_sig_cookie (cfg, call, cinfo); } - if (cinfo->struct_ret) { - MonoInst *vtarg; - - MONO_INST_NEW (cfg, vtarg, OP_MOVE); - vtarg->sreg1 = call->vret_var->dreg; - vtarg->dreg = mono_alloc_preg (cfg); - MONO_ADD_INS (cfg->cbb, vtarg); - - mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->struct_ret, FALSE); - } } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_emit_outarg_vt */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific Value Type parameter processing + * + * @param[in] @cfg - Compile control block + * @param[in] @call - Call Instruction + * @param[in] @src - Source parameter + * + * Process value type parameters for a call operation + */ void mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) { - MonoCallInst *call = (MonoCallInst*)ins->inst_p0; - ArgInfo *ainfo = (ArgInfo*)ins->inst_p1; - int size = ins->backend.size; + MonoCallInst *call = (MonoCallInst*) ins->inst_p0; + ArgInfo *ainfo = (ArgInfo *) ins->inst_p1; if (ainfo->regtype == RegTypeStructByVal) { - /* - arg->ins.sreg1 = ainfo->reg; - arg->ins.opcode = OP_OUTARG_VT; - arg->size = ainfo->size; - arg->offset = ainfo->offset; - arg->offPrm = ainfo->offparm + cinfo->sz.offStruct; - */ if (ainfo->reg != STK_BASE) { - MONO_OUTPUT_VTR (cfg, size, ainfo->reg, src->dreg, 0); + emit_outarg_vtr (cfg, ins, src); } else { - MONO_OUTPUT_VTS (cfg, size, ainfo->reg, ainfo->offset, - src->dreg, 0); + emit_outarg_vts (cfg, ins, src); } } else if (ainfo->regtype == RegTypeStructByValInFP) { int dreg = mono_alloc_freg (cfg); @@ -2075,11 +1977,16 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_emit_setret */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific call value return processing + * + * @param[in] @cfg - Compile control block + * @param[in] @method - Method + * @param[in] @val - Instruction representing the result returned to method + * + * Create the sequence to unload the value returned from a call + */ void mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) @@ -2101,14 +2008,18 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - compare_and_branch */ -/* */ -/* Function - Form a peephole pass at the code looking for */ -/* simple optimizations. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Replace compound compare/branch operations with single operation + * + * @param[in] @bb - Basic block + * @param[in] @ins - Current instruction + * @param[in] @cc - Condition code of branch + * @param[in] @logical - Whether comparison is signed or logical + * + * Form a peephole pass at the code looking for simple optimizations + * that will combine compare/branch instructions into a single operation. + */ static void compare_and_branch(MonoBasicBlock *bb, MonoInst *ins, int cc, gboolean logical) @@ -2159,14 +2070,16 @@ compare_and_branch(MonoBasicBlock *bb, MonoInst *ins, int cc, gboolean logical) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_peephole_pass_1 */ -/* */ -/* Function - Form a peephole pass at the code looking for */ -/* simple optimizations. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecure-specific peephole pass 1 processing + * + * @param[in] @cfg - Compile control block + * @param[in] @bb - Basic block + * + * Form a peephole pass at the code looking for compare and branch + * optimizations. + */ void mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb) @@ -2224,14 +2137,15 @@ mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_peephole_pass_2 */ -/* */ -/* Function - Form a peephole pass at the code looking for */ -/* simple optimizations. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecure-specific peephole pass 2 processing + * + * @param[in] @cfg - Compile control block + * @param[in] @bb - Basic block + * + * Form a peephole pass at the code looking for simple optimizations. + */ void mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) @@ -2256,11 +2170,15 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_lowering_pass. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecure-specific lowering pass processing + * + * @param[in] @cfg - Compile control block + * @param[in] @bb - Basic block + * + * Form a lowering pass at the code looking for simple optimizations. + */ void mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) @@ -2297,16 +2215,22 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - emit_float_to_int */ -/* */ -/* Function - Create instructions which will convert a floating */ -/* point value to integer. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Emit float-to-int sequence + * + * @param[in] @cfg - Compile control block + * @param[in] @code - Current instruction area + * @param[in] @dreg - Destination general register + * @param[in] @sreg - Source floating point register + * @param[in] @size - Size of destination + * @param[in] @is_signed - Destination is signed/unsigned + * @returns Next instruction location + * + * Emit instructions to convert a single precision floating point value to an integer + */ -static guchar* +static guchar * emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed) { /* sreg is a float, dreg is an integer reg. */ @@ -2362,14 +2286,20 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - emit_double_to_int */ -/* */ -/* Function - Create instructions which will convert a floating */ -/* point value to integer. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Emit double-to-int sequence + * + * @param[in] @cfg - Compile control block + * @param[in] @code - Current instruction area + * @param[in] @dreg - Destination general register + * @param[in] @sreg - Source floating point register + * @param[in] @size - Size of destination + * @param[in] @is_signed - Destination is signed/unsigned + * @returns Next instruction location + * + * Emit instructions to convert a single precision floating point value to an integer + */ static guchar* emit_double_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed) @@ -2427,14 +2357,15 @@ emit_double_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - is_unsigned. */ -/* */ -/* Function - Return TRUE if next opcode is checking for un- */ -/* signed value. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Check if branch is for unsigned comparison + * + * @param[in] @next - Next instruction + * @returns True if the branch is for an unsigned comparison + * + * Determine if next instruction is a branch for an unsigned comparison + */ static gboolean is_unsigned (MonoInst *next) @@ -2463,14 +2394,16 @@ is_unsigned (MonoInst *next) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_output_basic_block */ -/* */ -/* Function - Perform the "real" work of emitting instructions */ -/* that will do the work of in the basic block. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecutre-specific processing of a basic block + * + * @param[in] @cfg - Compile control block + * @param[in] @bb - Basic block + * + * Process instructions within basic block emitting s390x instructions + * based on the VM operation codes + */ void mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) @@ -2715,14 +2648,23 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_LADD_IMM: { - if (ins->dreg != ins->sreg1) { - s390_lgr (code, ins->dreg, ins->sreg1); - } - if (s390_is_imm32 (ins->inst_imm)) { - s390_agfi (code, ins->dreg, ins->inst_imm); - } else { - S390_SET (code, s390_r0, ins->inst_imm); - s390_agr (code, ins->dreg, s390_r0); + if (mono_hwcap_s390x_has_mlt) { + if (s390_is_imm16 (ins->inst_imm)) { + s390_aghik(code, ins->dreg, ins->sreg1, ins->inst_imm); + } else { + S390_SET (code, s390_r0, ins->inst_imm); + s390_agrk (code, ins->dreg, ins->sreg1, s390_r0); + } + } else { + if (ins->dreg != ins->sreg1) { + s390_lgr (code, ins->dreg, ins->sreg1); + } + if (s390_is_imm32 (ins->inst_imm)) { + s390_agfi (code, ins->dreg, ins->inst_imm); + } else { + S390_SET (code, s390_r0, ins->inst_imm); + s390_agr (code, ins->dreg, s390_r0); + } } } break; @@ -3523,7 +3465,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (!cfg->r4fp) s390_ledbr (code, ins->dreg, ins->sreg1); break; - case OP_TLS_GET: { + case OP_TLS_GET: { if (s390_is_imm16 (ins->inst_offset)) { s390_lghi (code, s390_r13, ins->inst_offset); } else if (s390_is_imm32 (ins->inst_offset)) { @@ -3537,7 +3479,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_lg (code, ins->dreg, s390_r13, s390_r1, 0); } break; - case OP_TLS_SET: { + case OP_TLS_SET: { if (s390_is_imm16 (ins->inst_offset)) { s390_lghi (code, s390_r13, ins->inst_offset); } else if (s390_is_imm32 (ins->inst_offset)) { @@ -3557,78 +3499,81 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) g_assert (ins->next); break; case OP_TAILCALL : + case OP_TAILCALL_REG : case OP_TAILCALL_MEMBASE : { MonoCallInst *call = (MonoCallInst *) ins; - MonoMethod *method = call->method; - MonoMethodSignature *sig = mono_method_signature_internal (method); - CallInfo *cinfo = get_call_info (NULL, sig); - int32_t stackUsage = (cinfo->sz.stack_size - S390_MINIMAL_STACK_SIZE), - stackOffset = S390_MINIMAL_STACK_SIZE; - if (cfg->method->save_lmf) - restoreLMF(code, cfg->frame_reg, cfg->stack_usage); - - s390_lgr (code, s390_r12, cfg->frame_reg); + /* + * Restore SP to caller's SP + */ code = backUpStackPtr(cfg, code); - while (stackUsage > 256) { - s390_mvc (code, 256, STK_BASE, stackOffset, - s390_r12, stackOffset); - stackUsage -= 256; - stackOffset += 256; - } + /* + * If the destination is specified as a register or membase then + * save destination so it doesn't get overwritten by the restores + */ + if (ins->opcode != OP_TAILCALL) + s390_lgr (code, s390_r1, ins->sreg1); - if (stackUsage > 0) - s390_mvc (code, stackUsage, STK_BASE, stackOffset, - s390_r12, stackOffset); + /* + * If the IMT/RGCTX register is in use then don't restore over it + */ + if ((call->used_iregs & (MONO_ARCH_RGCTX_REG << 1)) || (call->rgctx_reg)) + s390_lgr (code, s390_r0, MONO_ARCH_RGCTX_REG); + /* + * If R6 is used for a parameter then don't restore the other + * parameter registers are volatile + */ + if (call->used_iregs & (1 << 6)) + s390_lmg (code, s390_r7, s390_r14, STK_BASE, S390_NONPARM_SAVE_OFFSET); + else + s390_lmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); - s390_lmg (code, s390_r6, s390_r13, STK_BASE, S390_REG_SAVE_OFFSET); + if ((call->used_iregs & (MONO_ARCH_RGCTX_REG << 1)) || (call->rgctx_reg)) + s390_lgr (code, MONO_ARCH_RGCTX_REG, s390_r0); - if (cfg->arch.used_fp_regs != 0) { - int32_t fpOffset = sizeof(double); - for (int i=8; i<16; i++) { + /* + * Restore any FP registers that have been altered + */ + if (cfg->arch.fpSize != 0) { + int fpOffset = -cfg->arch.fpSize; + for (int i = 8; i < 16; i++) { if (cfg->arch.used_fp_regs & (1 << i)) { - s390_ld (code, i, cfg->arch.fpSize, STK_BASE, fpOffset); + s390_ldy (code, i, 0, STK_BASE, fpOffset); fpOffset += sizeof(double); } } } - s390_lg (code, s390_r14, 0, STK_BASE, S390_RET_ADDR_OFFSET); - if (ins->opcode == OP_TAILCALL_MEMBASE) { - if (mono_hwcap_s390x_has_mie2) { - s390_bi (code, 0, ins->sreg1, ins->inst_offset); + if (ins->opcode == OP_TAILCALL_REG) { + s390_br (code, s390_r1); + } else { + if (ins->opcode == OP_TAILCALL_MEMBASE) { + if (mono_hwcap_s390x_has_mie2) { + s390_bi (code, 0, s390_r1, ins->inst_offset); + } else { + s390_lg (code, s390_r1, 0, s390_r1, ins->inst_offset); + s390_br (code, s390_r1); + } } else { - s390_lg (code, s390_r1, 0, ins->sreg1, ins->inst_offset); - s390_br (code, s390_r1); + mono_add_patch_info (cfg, code - cfg->native_code, + MONO_PATCH_INFO_METHOD_JUMP, + call->method); + s390_jcl (code, S390_CC_UN, 0); } - } else { - mono_add_patch_info (cfg, code - cfg->native_code, - MONO_PATCH_INFO_METHOD_JUMP, - call->method); - s390_jcl (code, S390_CC_UN, 0); } - - g_free (cinfo); } break; case OP_CHECK_THIS: { /* ensure ins->sreg1 is not NULL */ s390_lg (code, s390_r0, 0, ins->sreg1, 0); s390_ltgr (code, s390_r0, s390_r0); -// EMIT_COND_SYSTEM_EXCEPTION (S390_CC_ZR, "NullReferenceException"); } break; case OP_ARGLIST: { const int offset = cfg->sig_cookie + cfg->stack_usage; - if (s390_is_imm16 (offset)) { - s390_lghi (code, s390_r0, offset); - } else if (s390_is_imm32 (offset)) { - s390_lgfi (code, s390_r0, offset); - } else { - S390_SET (code, s390_r0, offset); - } + S390_SET (code, s390_r0, offset); s390_agr (code, s390_r0, cfg->frame_reg); s390_stg (code, s390_r0, 0, ins->sreg1, 0); } @@ -3690,46 +3635,49 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) } break; case OP_LOCALLOC: { - int alloca_skip; int area_offset; if (cfg->param_area == 0) - alloca_skip = S390_MINIMAL_STACK_SIZE; + area_offset = S390_MINIMAL_STACK_SIZE; else - alloca_skip = cfg->param_area; + area_offset = cfg->param_area; + + area_offset = S390_ALIGN(area_offset, S390_STACK_ALIGNMENT); - area_offset = S390_ALIGN(alloca_skip, S390_STACK_ALIGNMENT); + /* + * Get alloc size and round to doubleword + */ s390_lgr (code, s390_r1, ins->sreg1); - if (ins->flags & MONO_INST_INIT) - s390_lgr (code, s390_r0, ins->sreg1); s390_aghi (code, s390_r1, 14); s390_srlg (code, s390_r1, s390_r1, 0, 3); s390_sllg (code, s390_r1, s390_r1, 0, 3); - if (cfg->method->save_lmf) { - /*----------------------------------*/ - /* we have to adjust lmf ebp value */ - /*----------------------------------*/ - int lmfOffset = cfg->stack_usage - sizeof(MonoLMF); - s390_lgr (code, s390_r13, cfg->frame_reg); - if (s390_is_imm16(lmfOffset)) { - s390_aghi (code, s390_r13, lmfOffset); - } else if (s390_is_imm32(lmfOffset)) { - s390_agfi (code, s390_r13, lmfOffset); - } else { - S390_SET (code, s390_r13, lmfOffset); - } - s390_lgr (code, s390_r14, STK_BASE); - s390_sgr (code, s390_r14, s390_r1); - s390_stg (code, s390_r14, 0, s390_r13, - MONO_STRUCT_OFFSET(MonoLMF, ebp)); - } + /* + * If we need to initialize then hold on to the length + */ + if (ins->flags & MONO_INST_INIT) + s390_lgr (code, s390_r0, s390_r1); + + /* + * Adjust the stack pointer and save the backchain + */ s390_lg (code, s390_r13, 0, STK_BASE, 0); s390_sgr (code, STK_BASE, s390_r1); s390_stg (code, s390_r13, 0, STK_BASE, 0); + + /* + * Skip the stack save requirements and point to localloc area + * and ensure it's correctly aligned + */ s390_la (code, ins->dreg, 0, STK_BASE, area_offset); + s390_aghi (code, ins->dreg, 7); s390_srlg (code, ins->dreg, ins->dreg, 0, 3); s390_sllg (code, ins->dreg, ins->dreg, 0, 3); + + /* + * If we need to zero the area then clear from localloc start + * using the length we saved earlier + */ if (ins->flags & MONO_INST_INIT) { s390_lgr (code, s390_r1, s390_r0); s390_lgr (code, s390_r0, ins->dreg); @@ -3739,6 +3687,23 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_jo (code, -2); s390_lgr (code, s390_r12, s390_r14); } + + /* + * If we have an LMF then we have to adjust its BP + */ + if (cfg->method->save_lmf) { + int lmfOffset = cfg->stack_usage - sizeof(MonoLMF); + + if (s390_is_imm16(lmfOffset)) { + s390_lghi (code, s390_r13, lmfOffset); + } else if (s390_is_imm32(lmfOffset)) { + s390_lgfi (code, s390_r13, lmfOffset); + } else { + S390_SET (code, s390_r13, lmfOffset); + } + s390_stg (code, s390_r15, s390_r13, cfg->frame_reg, + MONO_STRUCT_OFFSET(MonoLMF, ebp)); + } } break; case OP_THROW: { @@ -3810,31 +3775,56 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) mono_add_seq_point (cfg, bb, ins, code - cfg->native_code); break; case OP_SEQ_POINT: { - int i; + + MonoInst *var; + RI_Format *o[2]; + guint16 displace; if (cfg->compile_aot) NOT_IMPLEMENTED; + if (ins->flags & MONO_INST_SINGLE_STEP_LOC) { + var = cfg->arch.ss_tramp_var; + s390_lg (code, s390_r1, 0, var->inst_basereg, var->inst_offset); + if (mono_hwcap_s390x_has_eif) { + s390_ltg (code, s390_r14, 0, s390_r1, 0); + } else { + s390_lg (code, s390_r14, 0, s390_r1, 0); + s390_ltgr (code, s390_r14, s390_r14); + } + o[0] = (RI_Format *) code; + s390_jz (code, 4); + s390_lgr (code, s390_r1, cfg->frame_reg); + s390_basr (code, s390_r14, s390_r14); + displace = ((uintptr_t) code - (uintptr_t) o[0]) / 2; + o[0]->i2 = displace; + } + /* - * Read from the single stepping trigger page. This will cause a - * SIGSEGV when single stepping is enabled. - * We do this _before_ the breakpoint, so single stepping after - * a breakpoint is hit will step to the next IL offset. + * This is the address which is saved in seq points, */ - if (ins->flags & MONO_INST_SINGLE_STEP_LOC) { - breakpointCode.pTrigger = ss_trigger_page; - memcpy(code, (void *) &breakpointCode, BREAKPOINT_SIZE); - code += BREAKPOINT_SIZE; - } - mono_add_seq_point (cfg, bb, ins, code - cfg->native_code); - /* - * A placeholder for a possible breakpoint inserted by - * mono_arch_set_breakpoint (). - */ - for (i = 0; i < (BREAKPOINT_SIZE / S390X_NOP_SIZE); ++i) - s390_nop (code); + var = cfg->arch.bp_tramp_var; + s390_lghi (code, s390_r1, 0); + s390_ltgr (code, s390_r1, s390_r1); + o[0] = (RI_Format *) code; + s390_jz (code, 0); + s390_lg (code, s390_r1, 0, var->inst_basereg, var->inst_offset); + if (mono_hwcap_s390x_has_eif) { + s390_ltg (code, s390_r14, 0, s390_r1, 0); + } else { + s390_lg (code, s390_r1, 0, s390_r1, 0); + s390_ltgr (code, s390_r14, s390_r1); + } + o[1] = (RI_Format *) code; + s390_jz (code, 4); + s390_lgr (code, s390_r1, cfg->frame_reg); + s390_basr (code, s390_r14, s390_r14); + displace = ((uintptr_t) code - (uintptr_t) o[0]) / 2; + o[0]->i2 = displace; + displace = ((uintptr_t) code - (uintptr_t) o[1]) / 2; + o[1]->i2 = displace; /* * Add an additional nop so skipping the bp doesn't cause the ip to point @@ -3858,7 +3848,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) s390_jo (code, 0); CODEPTR(code, jump); mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID, - GUINT_TO_POINTER (MONO_JIT_ICALL_mono_generic_class_init)); + GUINT_TO_POINTER (MONO_JIT_ICALL_mono_generic_class_init)); S390_CALL_TEMPLATE(code, s390_r14); PTRSLOT (code, jump); @@ -4059,26 +4049,34 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /* floating point opcodes */ case OP_R8CONST: { - if (*((double *) ins->inst_p0) == 0) { + double d = *(double *) ins->inst_p0; + if (d == 0) { s390_lzdr (code, ins->dreg); + if (mono_signbit (d) != 0) + s390_lndbr (code, ins->dreg, ins->dreg); } else { - S390_SET (code, s390_r13, ins->inst_p0); - s390_ld (code, ins->dreg, 0, s390_r13, 0); + S390_SET (code, s390_r13, ins->inst_p0); + s390_ld (code, ins->dreg, 0, s390_r13, 0); } } break; case OP_R4CONST: { - if (*((float *) ins->inst_p0) == 0) { - if (cfg->r4fp) + float f = *(float *) ins->inst_p0; + if (f == 0) { + if (cfg->r4fp) { s390_lzer (code, ins->dreg); - else + if (mono_signbit (f) != 0) + s390_lnebr (code, ins->dreg, ins->dreg); + } else { s390_lzdr (code, ins->dreg); + if (mono_signbit (f) != 0) + s390_lndbr (code, ins->dreg, ins->dreg); + } } else { - S390_SET (code, s390_r13, ins->inst_p0); - if (cfg->r4fp) { - S390_LONG (code, ley, le, ins->dreg, 0, s390_r13, 0); - } else { - s390_ldeb (code, ins->dreg, 0, s390_r13, 0); + S390_SET (code, s390_r13, ins->inst_p0); + s390_le (code, ins->dreg, 0, s390_r13, 0); + if (!cfg->r4fp) { + s390_ldebr (code, ins->dreg, ins->dreg); } } } @@ -4098,11 +4096,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) S390_LONG (code, stey, ste, ins->sreg1, 0, ins->inst_destbasereg, ins->inst_offset); } else { - s390_lgdr (code, s390_r0, s390_f15); - s390_ledbr (code, s390_f15, ins->sreg1); - S390_LONG (code, stey, ste, s390_f15, 0, + s390_ledbr (code, ins->sreg1, ins->sreg1); + S390_LONG (code, stey, ste, ins->sreg1, 0, ins->inst_destbasereg, ins->inst_offset); - s390_ldgr (code, s390_f15, s390_r0); + s390_ldebr (code, ins->sreg1, ins->sreg1); } } break; @@ -4317,12 +4314,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_FSUB: { CHECK_SRCDST_NCOM_F(sdbr); - // s390_sdbr (code, ins->dreg, src2); } break; case OP_RSUB: { CHECK_SRCDST_NCOM_F(sebr); - // s390_sebr (code, ins->dreg, src2); } break; case OP_FMUL: { @@ -4337,12 +4332,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_FDIV: { CHECK_SRCDST_NCOM_F(ddbr); - // s390_ddbr (code, ins->dreg, src2); } break; case OP_RDIV: { CHECK_SRCDST_NCOM_F(debr); - //s390_debr (code, ins->dreg, src2); } break; case OP_FNEG: { @@ -4545,10 +4538,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) case OP_S390_MOVE: { if (ins->backend.size > 0) { if (ins->backend.size <= 256) { - s390_mvc (code, ins->backend.size, ins->dreg, + s390_mvc (code, ins->backend.size, ins->sreg2, ins->inst_offset, ins->sreg1, ins->inst_imm); } else { - s390_lgr (code, s390_r0, ins->dreg); + s390_lgr (code, s390_r0, ins->sreg2); if (ins->inst_offset > 0) { if (s390_is_imm16 (ins->inst_offset)) { s390_aghi (code, s390_r0, ins->inst_offset); @@ -4587,8 +4580,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_ATOMIC_ADD_I8: { if (mono_hwcap_s390x_has_ia) { - s390_laag (code, ins->dreg, ins->sreg2, ins->inst_basereg, ins->inst_offset); - s390_agr (code, ins->dreg, ins->sreg2); + s390_laag(code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset); + s390_lg (code, ins->dreg, 0, ins->inst_basereg, ins->inst_offset); } else { s390_lgr (code, s390_r1, ins->sreg2); s390_lg (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset); @@ -4608,8 +4601,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) break; case OP_ATOMIC_ADD_I4: { if (mono_hwcap_s390x_has_ia) { - s390_laa (code, ins->dreg, ins->sreg2, ins->inst_basereg, ins->inst_offset); - s390_ar (code, ins->dreg, ins->sreg2); + s390_laa (code, s390_r0, ins->sreg2, ins->inst_basereg, ins->inst_offset); + s390_lgf (code, ins->dreg, 0, ins->inst_basereg, ins->inst_offset); } else { s390_lgfr(code, s390_r1, ins->sreg2); s390_lgf (code, s390_r0, 0, ins->inst_basereg, ins->inst_offset); @@ -5310,13 +5303,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_register_lowlevel_calls */ -/* */ -/* Function - Register routines to help with --trace operation. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific registration of lowlevel calls + * + * Register routines to register optimized lowlevel operations + */ void mono_arch_register_lowlevel_calls (void) @@ -5325,15 +5317,21 @@ mono_arch_register_lowlevel_calls (void) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_patch_code */ -/* */ -/* Function - Process the patch data created during the */ -/* instruction build process. This resolves jumps, */ -/* calls, variables etc. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific patching of instructions and data + * + * @param[in] @cfg - Compile control block + * @param[in] @method - Current method + * @param[in] @domain - Current Mono Domain + * @param[in] @code - Current innstruction pointer + * @param[in] @ji - Jump information + * @param[in] @run_cctors - Whether class constructors need to be initialized + * @param[in] @error - Error control block + * + * Process the patch data created during the instruction build process. + * This resolves jumps, calls, variables etc. + */ void mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, @@ -5402,14 +5400,19 @@ mono_arch_patch_code (MonoCompile *cfg, MonoMethod *method, MonoDomain *domain, /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_emit_prolog */ -/* */ -/* Function - Create the instruction sequence for a function */ -/* prolog. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific prolog generation + * + * @param[in] @cfg - Compile control block + * @returns Location of code code generated + * + * Create the instruction sequence for entry into a method: + * - Determine stack size + * - Save preserved registers + * - Unload parameters + * - Determine if LMF needs saving and generate that sequence + */ guint8 * mono_arch_emit_prolog (MonoCompile *cfg) @@ -5433,27 +5436,39 @@ mono_arch_emit_prolog (MonoCompile *cfg) cfg->native_code = code = g_malloc (cfg->code_size); + /** + * Create unwind information + */ mono_emit_unwind_op_def_cfa (cfg, code, STK_BASE, 0); emit_unwind_regs(cfg, code, s390_r6, s390_r14, S390_REG_SAVE_OFFSET); - s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); mono_emit_unwind_op_offset (cfg, code, s390_r14, S390_RET_ADDR_OFFSET); + s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); mini_gc_set_slot_type_from_cfa (cfg, S390_RET_ADDR_OFFSET, SLOT_NOREF); if (cfg->arch.bkchain_reg != -1) s390_lgr (code, cfg->arch.bkchain_reg, STK_BASE); + /* + * If there are local allocations the R11 becomes the frame register + */ if (cfg->flags & MONO_CFG_HAS_ALLOCA) { cfg->used_int_regs |= 1 << s390_r11; } + /* + * Check if FP registers need preserving + */ if ((cfg->arch.used_fp_regs & S390_FP_SAVE_MASK) != 0) { - for (int i=8; i<16; i++) { + for (int i = s390_f8; i <= s390_f15; i++) { if (cfg->arch.used_fp_regs & (1 << i)) fpOffset += sizeof(double); } - fpOffset = S390_ALIGN(fpOffset, 16); + fpOffset = S390_ALIGN(fpOffset, sizeof(double)); } cfg->arch.fpSize = fpOffset; + /* + * Calculate stack requirements + */ alloc_size = cfg->stack_offset + fpOffset; cfg->stack_usage = cfa_offset = alloc_size; @@ -5477,7 +5492,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) s390_lgr (code, s390_r1, s390_r11); s390_aghi (code, s390_r1, -fpOffset); - for (int i=8; i<16; i++) { + for (int i = s390_f8; i <= s390_f15; i++) { if (cfg->arch.used_fp_regs & (1 << i)) { emit_unwind_regs(cfg, code, 16+i, 16+i, stkOffset+fpOffset); s390_std (code, i, 0, s390_r1, stkOffset); @@ -5498,11 +5513,23 @@ mono_arch_emit_prolog (MonoCompile *cfg) g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET); s390_stg (code, MONO_ARCH_RGCTX_REG, 0, - cfg->rgctx_var->inst_basereg, - cfg->rgctx_var->inst_offset); + cfg->rgctx_var->inst_basereg, + cfg->rgctx_var->inst_offset); } - /* compute max_offset in order to use short forward jumps +#if 0 +printf("ns: %s k: %s m: %s\n",method->klass->name_space,method->klass->name,method->name);fflush(stdout); +// Tests:set_ip +if ((strcmp(method->klass->name_space,"") == 0) && + (strcmp(method->klass->name,"Tests") == 0) && + (strcmp(method->name, "set_ip") == 0)) { + // (strcmp("CancellationToken,TaskCreationOptions,TaskContinuationOptions,TaskScheduler",mono_signature_get_desc(method->signature, FALSE)) != 0)) { + printf("SIGNATURE: %s\n",mono_signature_get_desc(method->signature, FALSE)); fflush(stdout); + s390_j (code, 0); +} +#endif + + /* compute max_offset in order to use short forward jumps * we always do it on s390 because the immediate displacement * for jumps is too small */ @@ -5528,6 +5555,10 @@ mono_arch_emit_prolog (MonoCompile *cfg) s390_stg (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); } + /** + * Process the arguments passed to the method + */ + for (i = 0; i < sig->param_count + sig->hasthis; ++i) { ArgInfo *ainfo = cinfo->args + i; inst = cfg->args [pos]; @@ -5580,14 +5611,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) s390_ste (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); } else if (ainfo->regtype == RegTypeStructByVal) { int doffset = inst->inst_offset; - int reg; - if (ainfo->reg != STK_BASE) - reg = ainfo->reg; - else { - reg = s390_r0; - s390_lgr (code, s390_r13, STK_BASE); - s390_aghi (code, s390_r13, alloc_size); - } size = (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE ? mono_class_native_size(mono_class_from_mono_type_internal (inst->inst_vtype), NULL) @@ -5595,29 +5618,27 @@ mono_arch_emit_prolog (MonoCompile *cfg) switch (size) { case 1: - if (ainfo->reg == STK_BASE) - s390_ic (code, reg, 0, s390_r13, ainfo->offset+7); - s390_stc (code, reg, 0, inst->inst_basereg, doffset); + if (ainfo->reg != STK_BASE) + s390_stc (code, ainfo->reg, 0, inst->inst_basereg, doffset); break; case 2: - if (ainfo->reg == STK_BASE) - s390_lh (code, reg, 0, s390_r13, ainfo->offset+6); - s390_sth (code, reg, 0, inst->inst_basereg, doffset); + if (ainfo->reg != STK_BASE) + s390_sth (code, ainfo->reg, 0, inst->inst_basereg, doffset); break; case 4: - if (ainfo->reg == STK_BASE) - s390_l (code, reg, 0, s390_r13, ainfo->offset+4); - s390_st (code, reg, 0, inst->inst_basereg, doffset); + if (ainfo->reg != STK_BASE) + s390_st (code, ainfo->reg, 0, inst->inst_basereg, doffset); break; case 8: - if (ainfo->reg == STK_BASE) - s390_lg (code, reg, 0, s390_r13, ainfo->offset); - s390_stg (code, reg, 0, inst->inst_basereg, doffset); + if (ainfo->reg != STK_BASE) + s390_stg (code, ainfo->reg, 0, inst->inst_basereg, doffset); break; + default: + if (ainfo->reg != STK_BASE) + s390_stg (code, ainfo->reg, 0, STK_BASE, doffset); } } else if (ainfo->regtype == RegTypeStructByAddr) { s390_stg (code, ainfo->reg, 0, inst->inst_basereg, inst->inst_offset); - } else if (ainfo->regtype == RegTypeStructByAddrOnStack) { } else g_assert_not_reached (); } @@ -5625,75 +5646,75 @@ mono_arch_emit_prolog (MonoCompile *cfg) } if (method->save_lmf) { - /*---------------------------------------------------------------*/ - /* build the MonoLMF structure on the stack - see mini-s390x.h */ - /*---------------------------------------------------------------*/ + /** + * Build the MonoLMF structure on the stack - see mini-s390x.h + */ lmfOffset = alloc_size - sizeof(MonoLMF); s390_lgr (code, s390_r13, cfg->frame_reg); s390_aghi (code, s390_r13, lmfOffset); - /*---------------------------------------------------------------*/ - /* Preserve the parameter registers while we fix up the lmf */ - /*---------------------------------------------------------------*/ + /* + * Preserve the parameter registers while we fix up the lmf + */ s390_stmg (code, s390_r2, s390_r6, s390_r13, MONO_STRUCT_OFFSET(MonoLMF, pregs)); for (i = 0; i < 5; i++) mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, pregs) + i * sizeof(gulong), SLOT_NOREF); - /*---------------------------------------------------------------*/ - /* On return from this call r2 have the address of the &lmf */ - /*---------------------------------------------------------------*/ + /* + * On return from this call r2 have the address of the &lmf + */ mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_ICALL_ID, GUINT_TO_POINTER (MONO_JIT_ICALL_mono_tls_get_lmf_addr_extern)); S390_CALL_TEMPLATE(code, s390_r1); - /*---------------------------------------------------------------*/ - /* Set lmf.lmf_addr = jit_tls->lmf */ - /*---------------------------------------------------------------*/ + /* + * Set lmf.lmf_addr = jit_tls->lmf + */ s390_stg (code, s390_r2, 0, s390_r13, MONO_STRUCT_OFFSET(MonoLMF, lmf_addr)); mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, lmf_addr), SLOT_NOREF); - /*---------------------------------------------------------------*/ - /* Get current lmf */ - /*---------------------------------------------------------------*/ + /* + * Get current lmf + */ s390_lg (code, s390_r0, 0, s390_r2, 0); - /*---------------------------------------------------------------*/ - /* Set our lmf as the current lmf */ - /*---------------------------------------------------------------*/ + /* + * Set our lmf as the current lmf + */ s390_stg (code, s390_r13, 0, s390_r2, 0); - /*---------------------------------------------------------------*/ - /* Have our lmf.previous_lmf point to the last lmf */ - /*---------------------------------------------------------------*/ + /* + * Have our lmf.previous_lmf point to the last lmf + */ s390_stg (code, s390_r0, 0, s390_r13, MONO_STRUCT_OFFSET(MonoLMF, previous_lmf)); mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), SLOT_NOREF); - /*---------------------------------------------------------------*/ - /* save method info */ - /*---------------------------------------------------------------*/ + /* + * Save method info + */ S390_SET (code, s390_r1, method); s390_stg (code, s390_r1, 0, s390_r13, MONO_STRUCT_OFFSET(MonoLMF, method)); mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, method), SLOT_NOREF); - /*---------------------------------------------------------------*/ - /* save the current IP */ - /*---------------------------------------------------------------*/ + /* + * Save the current IP + */ s390_stg (code, STK_BASE, 0, s390_r13, MONO_STRUCT_OFFSET(MonoLMF, ebp)); s390_basr (code, s390_r1, 0); s390_stg (code, s390_r1, 0, s390_r13, MONO_STRUCT_OFFSET(MonoLMF, eip)); mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, ebp), SLOT_NOREF); mini_gc_set_slot_type_from_fp (cfg, lmfOffset + MONO_STRUCT_OFFSET (MonoLMF, eip), SLOT_NOREF); - /*---------------------------------------------------------------*/ - /* Save general and floating point registers */ - /*---------------------------------------------------------------*/ + /* + * Save general and floating point registers + */ s390_stmg (code, s390_r2, s390_r12, s390_r13, MONO_STRUCT_OFFSET(MonoLMF, gregs) + 2 * sizeof(gulong)); for (i = 0; i < 11; i++) @@ -5707,9 +5728,9 @@ mono_arch_emit_prolog (MonoCompile *cfg) fpOffset += sizeof(double); } - /*---------------------------------------------------------------*/ - /* Restore the parameter registers now that we've set up the lmf */ - /*---------------------------------------------------------------*/ + /* + * Restore the parameter registers now that we've set up the lmf + */ s390_lmg (code, s390_r2, s390_r6, s390_r13, MONO_STRUCT_OFFSET(MonoLMF, pregs)); } @@ -5788,6 +5809,24 @@ mono_arch_emit_prolog (MonoCompile *cfg) } } + if (cfg->gen_sdb_seq_points) { + MonoInst *seq; + + /* Initialize ss_tramp_var */ + seq = cfg->arch.ss_tramp_var; + g_assert (seq->opcode == OP_REGOFFSET); + + S390_SET (code, s390_r1, (guint64) &ss_trampoline); + s390_stg (code, s390_r1, 0, seq->inst_basereg, seq->inst_offset); + + /* Initialize bp_tramp_var */ + seq = cfg->arch.bp_tramp_var; + g_assert (seq->opcode == OP_REGOFFSET); + + S390_SET (code, s390_r1, (guint64) &bp_trampoline); + s390_stg (code, s390_r1, 0, seq->inst_basereg, seq->inst_offset); + } + set_code_cursor (cfg, code); return code; @@ -5795,20 +5834,21 @@ mono_arch_emit_prolog (MonoCompile *cfg) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_emit_epilog */ -/* */ -/* Function - Emit the instructions for a function epilog. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecutre-specific epilog generation + * + * @param[in] @cfg - Compile control block + * + * Create the instruction sequence for exit from a method + */ void mono_arch_emit_epilog (MonoCompile *cfg) { MonoMethod *method = cfg->method; guint8 *code; - int max_epilog_size = 96; + int max_epilog_size = 96, i; int fpOffset = 0; if (cfg->method->save_lmf) @@ -5816,10 +5856,19 @@ mono_arch_emit_epilog (MonoCompile *cfg) code = realloc_code (cfg, max_epilog_size); + cfg->has_unwind_info_for_epilog = TRUE; + + /* Mark the start of the epilog */ + mono_emit_unwind_op_mark_loc (cfg, code, 0); + + /* Save the uwind state which is needed by the out-of-line code */ + mono_emit_unwind_op_remember_state (cfg, code); + if (method->save_lmf) restoreLMF(code, cfg->frame_reg, cfg->stack_usage); code = backUpStackPtr(cfg, code); + mono_emit_unwind_op_def_cfa (cfg, code, STK_BASE, 0); if (cfg->arch.fpSize != 0) { fpOffset = -cfg->arch.fpSize; @@ -5832,21 +5881,27 @@ mono_arch_emit_epilog (MonoCompile *cfg) } s390_lmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); + for (i = s390_r6; i < s390_r15; i++) + mono_emit_unwind_op_same_value (cfg, code, i); s390_br (code, s390_r14); + /* Restore the unwind state to be the same as before the epilog */ + mono_emit_unwind_op_restore_state (cfg, code); + set_code_cursor (cfg, code); } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_emit_exceptions */ -/* */ -/* Function - Emit the blocks to handle exception conditions. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific exception emission + * + * @param[in] @cfg - Compile control block + * + * Create the instruction sequence for exception handling + */ void mono_arch_emit_exceptions (MonoCompile *cfg) @@ -5871,25 +5926,23 @@ mono_arch_emit_exceptions (MonoCompile *cfg) code = realloc_code (cfg, code_size); - /*---------------------------------------------------------------------*/ - /* Add code to raise exceptions */ - /*---------------------------------------------------------------------*/ + /* + * Add code to raise exceptions + */ for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) { switch (patch_info->type) { case MONO_PATCH_INFO_EXC: { guint8 *ip = patch_info->ip.i + cfg->native_code; MonoClass *exc_class; - guint64 throw_ip; - /*-----------------------------------------------------*/ - /* Patch the branch in epilog to come here */ - /*-----------------------------------------------------*/ + /* + * Patch the branch in epilog to come here + */ s390_patch_rel (ip + 2, (guint64) S390_RELATIVE(code,ip)); exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", patch_info->data.name); - throw_ip = patch_info->ip.i; for (iExc = 0; iExc < nThrows; ++iExc) if (exc_classes [iExc] == exc_class) @@ -5906,18 +5959,18 @@ mono_arch_emit_exceptions (MonoCompile *cfg) exc_throw_start [nThrows] = code; } - /*---------------------------------------------*/ - /* Patch the parameter passed to the handler */ - /*---------------------------------------------*/ + /* + * Patch the parameter passed to the handler + */ S390_SET (code, s390_r2, m_class_get_type_token (exc_class)); - /*---------------------------------------------*/ - /* Load return address & parameter register */ - /*---------------------------------------------*/ + /* + * Load return address & parameter register + */ s390_larl (code, s390_r14, (guint64)S390_RELATIVE((patch_info->ip.i + cfg->native_code + 8), code)); - /*---------------------------------------------*/ - /* Reuse the current patch to set the jump */ - /*---------------------------------------------*/ + /* + * Reuse the current patch to set the jump + */ patch_info->type = MONO_PATCH_INFO_JIT_ICALL_ID; patch_info->data.jit_icall_id = MONO_JIT_ICALL_mono_arch_throw_corlib_exception; patch_info->ip.i = code - cfg->native_code; @@ -5935,13 +5988,13 @@ mono_arch_emit_exceptions (MonoCompile *cfg) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_finish_init */ -/* */ -/* Function - Setup the JIT's Thread Level Specific Data. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific finishing of initialization + * + * Perform any architectural-specific operations at the conclusion of + * the initialization phase + */ void mono_arch_finish_init (void) @@ -5950,29 +6003,38 @@ mono_arch_finish_init (void) /*========================= End of Function ========================*/ -/*========================= End of Function ========================*/ - -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_emit_inst_for_method */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific instruction emission for method + * + * @param[in] @cfg - Compile Control block + * @param[in] @cmethod - Current method + * @param[in] @fsig - Method signature + * @param[in] @args - Arguments to method + * @returns Instruction(s) required for architecture + * + * Provide any architectural shortcuts for specific methods. + */ -MonoInst* +MonoInst * mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) { - return NULL; + MonoInst *ins = NULL; + + return ins; } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_decompose_opts */ -/* */ -/* Function - Decompose opcode into a System z opcode. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Decompose opcode into a System z operation + * + * @param[in] @cfg - Compile Control block + * @param[in] @ins - Mono Instruction + * + * Substitute a System z instruction for a Mono operation. + */ void mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins) @@ -6013,18 +6075,19 @@ mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_regalloc_cost */ -/* */ -/* Function - Determine the cost, in the number of memory */ -/* references, of the action of allocating the var- */ -/* iable VMV into a register during global register */ -/* allocation. */ -/* */ -/* Returns - Cost */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Determine the cost of allocation a variable + * + * @param[in] @cfg - Compile Control block + * @param[in] @vmv - Mono Method Variable + * @returns Cost (hardcoded on s390x to 2) + * + * Determine the cost, in the number of memory references, of the action + * of allocating the variable VMV into a register during global register + * allocation. + * + */ guint32 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv) @@ -6035,15 +6098,13 @@ mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_flush_register_windows */ -/* */ -/* Function - */ -/* */ -/* Returns - */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architectural specific register window flushing + * + * Not applicable for s390x so we just do nothing + * + */ void mono_arch_flush_register_windows (void) @@ -6052,16 +6113,19 @@ mono_arch_flush_register_windows (void) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_is_inst_imm */ -/* */ -/* Function - Determine if operand qualifies as an immediate */ -/* value. For s390 this is a value -32768-32768 */ -/* */ -/* Returns - True|False - is [not] immediate value. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architectural specific check if value may be immediate + * + * @param[in] @opcode - Operation code + * @param[in] @imm_opcode - Immediate operation code + * @param[in] @imm - Value to be examined + * @returns True if it is a valid immediate value + * + * Determine if operand qualifies as an immediate value. For s390x + * this is a value in the range -2**32/2**32-1 + * + */ gboolean mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm) @@ -6071,15 +6135,15 @@ mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_get_patch_offset */ -/* */ -/* Function - Dummy entry point until s390x supports aot. */ -/* */ -/* Returns - Offset for patch. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architectural specific patch offset value for AOT + * + * @param[in] @code - Location of code to check + * @returns Offset + * + * Dummy entry point if/when s390x supports AOT. + */ guint32 mono_arch_get_patch_offset (guint8 *code) @@ -6089,15 +6153,16 @@ mono_arch_get_patch_offset (guint8 *code) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_context_get_int_reg. */ -/* */ -/* Function - */ -/* */ -/* Returns - Return a register from the context. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architectural specific returning of register from context + * + * @param[in] @ctx - Mono context + * @param[in] @reg - Register number to be returned + * @returns Contents of the register from the context + * + * Return a register from the context. + */ host_mgreg_t mono_arch_context_get_int_reg (MonoContext *ctx, int reg) @@ -6107,13 +6172,16 @@ mono_arch_context_get_int_reg (MonoContext *ctx, int reg) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_context_set_int_reg. */ -/* */ -/* Function - Set a value in a specified register. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architectural specific setting of a register in the context + * + * @param[in] @ctx - Mono context + * @param[in] @reg - Register number to be returned + * @param[in] @val - Value to be set + * + * Set the specified register in the context with the value passed + */ void mono_arch_context_set_int_reg (MonoContext *ctx, int reg, host_mgreg_t val) @@ -6123,13 +6191,17 @@ mono_arch_context_set_int_reg (MonoContext *ctx, int reg, host_mgreg_t val) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_get_this_arg_from_call. */ -/* */ -/* Function - */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architectural specific returning of the "this" value from context + * + * @param[in] @ctx - Mono context + * @param[in] @code - Current location + * @returns Pointer to the "this" object + * + * Extract register 2 from the context as for s390x this is where the + * this parameter is passed + */ gpointer mono_arch_get_this_arg_from_call (host_mgreg_t *regs, guint8 *code) @@ -6139,16 +6211,21 @@ mono_arch_get_this_arg_from_call (host_mgreg_t *regs, guint8 *code) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - get_delegate_invoke_impl. */ -/* */ -/* Function - */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Delegation trampoline processing + * + * @param[in] @info - Trampoline information + * @param[in] @has_target - Use target from delegation + * @param[in] @param_count - Count of parameters + * @param[in] @aot - AOT indicator + * @returns Next instruction location + * + * Process the delegation trampolines + */ -static guint8* -get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 param_count, gboolean aot) +static guint8 * +get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, MonoMethodSignature *sig, gboolean aot) { guint8 *code, *start; @@ -6166,17 +6243,32 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 par mono_arch_flush_icache (start, size); MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL)); } else { - int size, i; + int size, i, offset = S390_MINIMAL_STACK_SIZE, iReg = s390_r2; + CallInfo *cinfo = get_call_info (NULL, sig); - size = 32 + param_count * 8; + size = 32 + sig->param_count * 8; start = code = mono_global_codeman_reserve (size); - s390_lg (code, s390_r1, 0, s390_r2, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr)); + s390_lg (code, s390_r1, 0, s390_r2, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr)); /* slide down the arguments */ - for (i = 0; i < param_count; ++i) { - s390_lgr (code, (s390_r2 + i), (s390_r2 + i + 1)); + for (i = 0; i < sig->param_count; ++i) { + switch(cinfo->args[i].regtype) { + case RegTypeGeneral : + if (iReg < S390_LAST_ARG_REG) { + s390_lgr (code, iReg, (iReg + 1)); + } else { + s390_lg (code, iReg, 0, STK_BASE, offset); + } + iReg++; + break; + default : + s390_mvc (code, sizeof(uintptr_t), STK_BASE, offset, STK_BASE, offset+sizeof(uintptr_t)); + offset += sizeof(uintptr_t); + } } - s390_br (code, s390_r1); + s390_br (code, s390_r1); + + g_free (cinfo); g_assert ((code - start) <= size); @@ -6187,7 +6279,7 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 par if (has_target) { *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL); } else { - char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", param_count); + char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count); *info = mono_tramp_info_create (name, start, code - start, NULL, NULL); g_free (name); } @@ -6197,49 +6289,57 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 par /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_get_delegate_invoke_impls. */ -/* */ -/* Function - */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific delegation trampolines processing + * + * @returns List of trampolines + * + * Return a list of MonoTrampInfo structures for the delegate invoke impl trampolines. + */ GSList* mono_arch_get_delegate_invoke_impls (void) { GSList *res = NULL; MonoTrampInfo *info; - int i; get_delegate_invoke_impl (&info, TRUE, 0, TRUE); res = g_slist_prepend (res, info); - for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) { - get_delegate_invoke_impl (&info, FALSE, i, TRUE); +#if 0 + for (int i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) { + get_delegate_invoke_impl (&info, FALSE, NULL, TRUE); res = g_slist_prepend (res, info); } +#endif return res; } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_get_delegate_invoke_impl. */ -/* */ -/* Function - */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific delegation trampoline processing + * + * @param[in] @sig - Method signature + * @param[in] @has_target - Whether delegation contains a target + * @returns Trampoline + * + * Return a pointer to a delegation trampoline + */ gpointer mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target) { guint8 *code, *start; + if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS) + return NULL; + /* FIXME: Support more cases */ - if (MONO_TYPE_ISSTRUCT (sig->ret)) + if (MONO_TYPE_ISSTRUCT (mini_get_underlying_type (sig->ret))) return NULL; if (has_target) { @@ -6252,7 +6352,7 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target"); } else { MonoTrampInfo *info; - start = get_delegate_invoke_impl (&info, TRUE, 0, FALSE); + start = get_delegate_invoke_impl (&info, TRUE, sig, FALSE); mono_tramp_info_register (info, NULL); } @@ -6269,7 +6369,6 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe if (!mono_is_regsize_var (sig->params [i])) return NULL; - code = cache [sig->param_count]; if (code) return code; @@ -6280,7 +6379,7 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe g_free (name); } else { MonoTrampInfo *info; - start = get_delegate_invoke_impl (&info, FALSE, sig->param_count, FALSE); + start = get_delegate_invoke_impl (&info, FALSE, sig, FALSE); mono_tramp_info_register (info, NULL); } @@ -6293,13 +6392,18 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_get_delegate_virtual_invoke_impl. */ -/* */ -/* Function - */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific delegation virtual trampoline processing + * + * @param[in] @sig - Method signature + * @param[in] @method - Method + * @param[in] @offset - Offset into vtable + * @param[in] @load_imt_reg - Whether to load the LMT register + * @returns Trampoline + * + * Return a pointer to a delegation virtual trampoline + */ gpointer mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, @@ -6311,21 +6415,21 @@ mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod start = code = mono_global_codeman_reserve (size); /* - * Replace the "this" argument with the target - */ + * Replace the "this" argument with the target + */ s390_lgr (code, s390_r1, s390_r2); s390_lg (code, s390_r2, 0, s390_r1, MONO_STRUCT_OFFSET(MonoDelegate, target)); /* - * Load the IMT register, if needed - */ + * Load the IMT register, if needed + */ if (load_imt_reg) { s390_lg (code, MONO_ARCH_IMT_REG, 0, s390_r1, MONO_STRUCT_OFFSET(MonoDelegate, method)); } /* - * Load the vTable - */ + * Load the vTable + */ s390_lg (code, s390_r1, 0, s390_r2, MONO_STRUCT_OFFSET(MonoObject, vtable)); if (offset != 0) { s390_agfi(code, s390_r1, offset); @@ -6341,13 +6445,19 @@ mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_build_imt_trampoline. */ -/* */ -/* Function - */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific build of IMT trampoline + * + * @param[in] @vtable - Mono VTable + * @param[in] @domain - Mono Domain + * @param[in] @imt_entries - List of IMT check items + * @param[in] @count - Count of items + * @param[in] @fail_tramp - Pointer to a failure trampoline + * @returns Trampoline + * + * Return a pointer to an IMT trampoline + */ gpointer mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, @@ -6486,14 +6596,16 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_find_imt_method. */ -/* */ -/* Function - Get the method address from MONO_ARCH_IMT_REG */ -/* found in the save area. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific return of pointer to IMT method + * + * @param[in] @regs - Context registers + * @param[in] @code - Current location + * @returns Pointer to IMT method + * + * Extract the value of the IMT register from the context + */ MonoMethod* mono_arch_find_imt_method (host_mgreg_t *regs, guint8 *code) @@ -6503,13 +6615,17 @@ mono_arch_find_imt_method (host_mgreg_t *regs, guint8 *code) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_find_static_call_vtable */ -/* */ -/* Function - Find the static call vtable. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific return of pointer static call vtable. + * + * @param[in] @regs - Context registers + * @param[in] @code - Current location + * @returns Pointer to static call vtable + * + * Extract the value of the RGCTX register from the context which + * points to the static call vtable. + */ MonoVTable* mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code) @@ -6519,13 +6635,14 @@ mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_get_cie_program */ -/* */ -/* Function - Find the static call vtable. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific return of unwind bytecode for DWARF CIE + * + * @returns Unwind byte code + * + * Returns the unwind bytecode for DWARF CIE + */ GSList* mono_arch_get_cie_program (void) @@ -6541,193 +6658,217 @@ mono_arch_get_cie_program (void) #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_set_breakpoint. */ -/* */ -/* Function - Set a breakpoint at the native code corresponding */ -/* to JI at NATIVE_OFFSET. The location should */ -/* contain code emitted by OP_SEQ_POINT. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific setting of a breakpoint + * + * @param[in] @ji - Mono JIT Information + * @param[in] @ip - Insruction pointer + * + * Set a breakpoint at the native code corresponding to JI at NATIVE_OFFSET. + * The location should contain code emitted by OP_SEQ_POINT. + */ void mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip) { - guint8 *code = ip; + guint8 *bp = ip; + + /* IP should point to a LGHI R1,0 */ + g_assert (bp[0] == 0xa7); - breakpointCode.pTrigger = bp_trigger_page; - memcpy(code, (void *) &breakpointCode, BREAKPOINT_SIZE); - code += BREAKPOINT_SIZE; + /* Replace it with a LGHI R1,1 */ + s390_lghi (bp, s390_r1, 1); } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_clear_breakpoint. */ -/* */ -/* Function - Clear the breakpoint at IP. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific clearing of a breakpoint + * + * @param[in] @ji - Mono JIT Information + * @param[in] @ip - Insruction pointer + * + * Replace the breakpoint with a no-operation. + */ void mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip) { - guint8 *code = ip; - int i; + guint8 *bp = ip; - for (i = 0; i < (BREAKPOINT_SIZE / S390X_NOP_SIZE); i++) - s390_nop(code); + /* IP should point to a LGHI R1,1 */ + g_assert (bp[0] == 0xa7); + + /* Replace it with a LGHI R1,0 */ + s390_lghi (bp, s390_r1, 0); } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_is_breakpoint_event. */ -/* */ -/* Function - */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific check if this is a breakpoint event + * + * @param[in] @info - Signal information + * @param[in] @sigctx - Signal context + * @returns True if this is a breakpoint event + * + * We use soft breakpoints so always return FALSE + */ gboolean mono_arch_is_breakpoint_event (void *info, void *sigctx) { - siginfo_t* sinfo = (siginfo_t*) info; - - /* - * Sometimes the address is off by 4 - */ - if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128) - return TRUE; - else - return FALSE; + /* We use soft breakpoints on s390x */ + return FALSE; } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_skip_breakpoint. */ -/* */ -/* Function - Modify the CTX so the IP is placed after the */ -/* breakpoint instruction, so when we resume, the */ -/* instruction is not executed again. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific skip of a breakpoint + * + * @param[in] @ctx - Mono Context + * @param[in] @ji - Mono JIT information + * + * We use soft breakpoints so this is a no-op + */ void mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji) { - MONO_CONTEXT_SET_IP (ctx, ((guint8*)MONO_CONTEXT_GET_IP (ctx) + sizeof(RXY_Format))); + g_assert_not_reached (); } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_start_single_stepping. */ -/* */ -/* Function - Start single stepping. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific start of single stepping + * + * Unprotect the trigger page to enable single stepping + */ void mono_arch_start_single_stepping (void) { - mono_mprotect (ss_trigger_page, mono_pagesize (), 0); + ss_trampoline = mini_get_single_step_trampoline(); } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_stop_single_stepping. */ -/* */ -/* Function - Stop single stepping. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific stop of single stepping + * + * Write-protect the trigger page to disable single stepping + */ void mono_arch_stop_single_stepping (void) { - mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ); + ss_trampoline = NULL; } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_is_single_step_event. */ -/* */ -/* Function - Return whether the machine state in sigctx cor- */ -/* responds to a single step event. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific check if single stepping event + * + * @param[in] @info - Signal information + * @param[in] @sigctx - Signal context + * @returns True if this is a single stepping event + * + * Return whether the machine state in sigctx corresponds to a single step event. + * On s390x we use soft breakpoints so return FALSE + */ gboolean mono_arch_is_single_step_event (void *info, void *sigctx) { - siginfo_t* sinfo = (siginfo_t*) info; - - /* - * Sometimes the address is off by 4 - */ - if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128) - return TRUE; - else - return FALSE; + /* We use soft breakpoints on s390x */ + return FALSE; } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_skip_single_step. */ -/* */ -/* Function - Modify the ctx so the IP is placed after the */ -/* single step trigger instruction, so that the */ -/* instruction is not executed again. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific skip of a single stepping event + * + * @param[in] @ctx - Mono Context + * + * Modify the ctx so the IP is placed after the single step trigger + * instruction, so that the instruction is not executed again. + * On s390x we use soft breakpoints so we shouldn't get here + */ void mono_arch_skip_single_step (MonoContext *ctx) { - MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + BREAKPOINT_SIZE); + g_assert_not_reached(); } /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_create_seq_point_info. */ -/* */ -/* Function - Return a pointer to a data struction which is */ -/* used by the sequence point implementation in */ -/* AOTed code. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific creation of sequence point information + * + * @param[in] @domain - Mono Domain + * @param[in] @code - Current location pointer + * @returns Sequence Point Information + * + * Return a pointer to a data struction which is used by the sequence + * point implementation in AOTed code. A no-op on s390x until AOT is + * ever supported. + */ -SeqPointInfo* +SeqPointInfo * mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code) { - NOT_IMPLEMENTED; - return NULL; + SeqPointInfo *info; + MonoJitInfo *ji; + + mono_domain_lock (domain); + info = (SeqPointInfo *)g_hash_table_lookup (domain_jit_info (domain)->arch_seq_points, code); + mono_domain_unlock (domain); + + if (!info) { + ji = mono_jit_info_table_find (domain, code); + g_assert (ji); + + // FIXME: Optimize the size + info = (SeqPointInfo *)g_malloc0 (sizeof (SeqPointInfo) + (ji->code_size * sizeof (gpointer))); + + info->ss_tramp_addr = &ss_trampoline; + + mono_domain_lock (domain); + g_hash_table_insert (domain_jit_info(domain)->arch_seq_points, code, info); + mono_domain_unlock (domain); + } + + return info; + } /*========================= End of Function ========================*/ #endif -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_opcode_supported. */ -/* */ -/* Function - Check if a given op code is supported. */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Architecture-specific check of supported operation codes + * + * @param[in] @opcode - Operation code to be checked + * @returns True if operation code is supported + * + * Check if a mono operation is supported in hardware. + */ gboolean mono_arch_opcode_supported (int opcode) @@ -6745,16 +6886,22 @@ mono_arch_opcode_supported (int opcode) /*========================= End of Function ========================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_tailcall_supported. */ -/* */ -/* Function - Check if a tailcall is supported. */ -/* */ -/*------------------------------------------------------------------*/ - #ifndef DISABLE_JIT +/** + * + * @brief Architecture-specific check of tailcall support + * + * @param[in] @cfg - Mono Compile control block + * @param[in] @caller_sig - Signature of caller + * @param[in] @callee_sig - Signature of callee + * @param[in] @virtual_ - Whether this a virtual call + * @returns True if the tailcall operation is supported + * + * Check if a tailcall may be made from caller to callee based on a + * number of conditions including parameter types and stack sizes + */ + gboolean mono_arch_tailcall_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig, gboolean virtual_) { @@ -6764,27 +6911,64 @@ mono_arch_tailcall_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, CallInfo *caller_info = get_call_info (NULL, caller_sig); CallInfo *callee_info = get_call_info (NULL, callee_sig); - gboolean res = IS_SUPPORTED_TAILCALL (callee_info->stack_usage <= caller_info->stack_usage) - && IS_SUPPORTED_TAILCALL (callee_info->struct_ret == caller_info->struct_ret) - && IS_SUPPORTED_TAILCALL (memcmp (&callee_info->ret, &caller_info->ret, sizeof (caller_info->ret)) == 0); + gboolean res = IS_SUPPORTED_TAILCALL (callee_info->stack_usage <= caller_info->stack_usage); - // valuetypes passed semantic-byvalue ABI-byref are often to a local. - // FIXME ABIs vary as to if this local is in the parameter area or not, - // so this check might not be needed. + // Any call that would result in parameters being placed on the stack cannot be "tailed" as it may + // result in the callers parameter variables being overwritten. ArgInfo const * const ainfo = callee_info->args + callee_sig->hasthis; for (int i = 0; res && i < callee_sig->param_count; ++i) { - res = IS_SUPPORTED_TAILCALL (ainfo [i].regtype != RegTypeStructByAddr) - && IS_SUPPORTED_TAILCALL (ainfo [i].regtype != RegTypeStructByAddrOnStack); + switch(ainfo[i].regtype) { + case RegTypeGeneral : + case RegTypeFP : + case RegTypeFPR4 : + case RegTypeStructByValInFP : + res = TRUE; + break; + case RegTypeBase : + res = FALSE; + break; + case RegTypeStructByAddr : + if (ainfo[i].reg == STK_BASE) + res = FALSE; + else + res = TRUE; + break; + case RegTypeStructByVal : + if (ainfo[i].reg == STK_BASE) + res = FALSE; + else { + switch(ainfo[i].size) { + case 0: case 1: case 2: case 4: case 8: + res = TRUE; + break; + default: + res = FALSE; + } + } + break; + } } g_free (caller_info); g_free (callee_info); - return res; + return(res); } +/*========================= End of Function ========================*/ + #endif +/** + * + * @brief Architecture-specific load function + * + * @param[in] @jit_call_id - JIT callee identifier + * @returns Pointer to load function trampoline + * + * A no-operation on s390x until if/when it supports AOT. + */ + gpointer mono_arch_load_function (MonoJitICallId jit_icall_id) { diff --git a/src/mono/mono/mini/mini-s390x.h b/src/mono/mono/mini/mini-s390x.h index 660fb9cf22e2ec..2efcafbd456b1d 100644 --- a/src/mono/mono/mini/mini-s390x.h +++ b/src/mono/mono/mini/mini-s390x.h @@ -29,10 +29,15 @@ struct MonoLMF { gdouble fregs[16]; }; +/** + * Platform-specific compile control information + */ typedef struct MonoCompileArch { - int bkchain_reg; - uint32_t used_fp_regs; - int fpSize; + int bkchain_reg; /** Register being used as stack backchain */ + uint32_t used_fp_regs; /** Floating point register use mask */ + int fpSize; /** Size of floating point save area */ + MonoInst *ss_tramp_var; /** Single-step variable */ + MonoInst *bp_tramp_var; /** Breakpoint variable */ } MonoCompileArch; typedef struct @@ -43,7 +48,13 @@ typedef struct void *return_address; } MonoS390StackFrame; -// #define MONO_ARCH_SIGSEGV_ON_ALTSTACK 1 +/* Structure used by the sequence points */ +struct SeqPointInfo { + gpointer ss_tramp_addr; + gpointer bp_addrs [MONO_ZERO_LEN_ARRAY]; +}; + +#define MONO_ARCH_SIGSEGV_ON_ALTSTACK 1 #define MONO_ARCH_EMULATE_LCONV_TO_R8_UN 1 #define MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS 1 #define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS 1 @@ -65,6 +76,10 @@ typedef struct #define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1 #define MONO_ARCH_HAVE_TRACK_FPREGS 1 #define MONO_ARCH_HAVE_OPTIMIZED_DIV 1 +#define MONO_ARCH_HAVE_OP_TAILCALL_MEMBASE 1 +#define MONO_ARCH_HAVE_OP_TAILCALL_REG 1 +#define MONO_ARCH_HAVE_SDB_TRAMPOLINES 1 +#define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1 #define S390_STACK_ALIGNMENT 8 #define S390_FIRST_ARG_REG s390_r2 @@ -127,7 +142,7 @@ typedef struct // Does the ABI have a volatile non-parameter register, so tailcall // can pass context to generics or interfaces? -#define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 0 // FIXME? +#define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 1 // FIXME? /*-----------------------------------------------*/ /* Macros used to generate instructions */ diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index 737028ff611899..603b331d1f0ba9 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -37,23 +37,21 @@ EMSCRIPTEN_KEEPALIVE int mono_wasm_setup_single_step (int kind); EMSCRIPTEN_KEEPALIVE void mono_wasm_get_object_properties (int object_id, gboolean expand_value_types); EMSCRIPTEN_KEEPALIVE void mono_wasm_get_array_values (int object_id); EMSCRIPTEN_KEEPALIVE void mono_wasm_get_array_value_expanded (int object_id, int idx); +EMSCRIPTEN_KEEPALIVE void mono_wasm_invoke_getter_on_object (int object_id, const char* name); //JS functions imported that we use -extern void mono_wasm_add_frame (int il_offset, int method_token, const char *assembly_name); +extern void mono_wasm_add_frame (int il_offset, int method_token, const char *assembly_name, const char *method_name); extern void mono_wasm_fire_bp (void); -extern void mono_wasm_add_bool_var (gint8); -extern void mono_wasm_add_number_var (double); -extern void mono_wasm_add_string_var (const char*); -extern void mono_wasm_add_obj_var (const char*, guint64); -extern void mono_wasm_add_value_type_unexpanded_var (const char*); -extern void mono_wasm_begin_value_type_var (const char*); +extern void mono_wasm_add_obj_var (const char*, const char*, guint64); +extern void mono_wasm_add_value_type_unexpanded_var (const char*, const char*); +extern void mono_wasm_begin_value_type_var (const char*, const char*); extern void mono_wasm_end_value_type_var (void); extern void mono_wasm_add_enum_var (const char*, const char*, guint64); -extern void mono_wasm_add_func_var (const char*, guint64); -extern void mono_wasm_add_array_var (const char*, guint64); +extern void mono_wasm_add_func_var (const char*, const char*, guint64); extern void mono_wasm_add_properties_var (const char*, gint32); extern void mono_wasm_add_array_item (int); extern void mono_wasm_set_is_async_method (guint64); +extern void mono_wasm_add_typed_value (const char *type, const char *str_value, double value); G_END_DECLS @@ -67,6 +65,21 @@ static GHashTable *objrefs; static GHashTable *obj_to_objref; static int objref_id = 0; +static const char* +all_getters_allowed_class_names[] = { + "System.DateTime", + "System.DateTimeOffset", + "System.TimeSpan" +}; + +static const char* +to_string_as_descr_names[] = { + "System.DateTime", + "System.DateTimeOffset", + "System.Decimal", + "System.TimeSpan" +}; + #define THREAD_TO_INTERNAL(thread) (thread)->internal_thread static void @@ -276,7 +289,7 @@ ss_create_init_args (SingleStepReq *ss_req, SingleStepArgs *ss_args) compute_frames (); memset (ss_args, 0, sizeof (*ss_args)); - //BIG WTF, should not happen maybe should assert? + // This shouldn't happen - maybe should assert here ? if (frames->len == 0) { DEBUG_PRINTF (1, "SINGLE STEPPING FOUND NO FRAMES"); return DBG_NOT_SUSPENDED; @@ -508,7 +521,7 @@ mono_wasm_breakpoint_hit (void) EMSCRIPTEN_KEEPALIVE int mono_wasm_current_bp_id (void) { - DEBUG_PRINTF (1, "COMPUTING breapoint ID\n"); + DEBUG_PRINTF (2, "COMPUTING breakpoint ID\n"); //FIXME handle compiled case /* Interpreter */ @@ -575,6 +588,7 @@ list_frames (MonoStackFrameInfo *info, MonoContext *ctx, gpointer data) { SeqPoint sp; MonoMethod *method; + char *method_full_name; //skip wrappers if (info->type != FRAME_TYPE_MANAGED && info->type != FRAME_TYPE_INTERP) @@ -594,6 +608,7 @@ list_frames (MonoStackFrameInfo *info, MonoContext *ctx, gpointer data) if (!mono_find_prev_seq_point_for_native_offset (mono_get_root_domain (), method, info->native_offset, NULL, &sp)) DEBUG_PRINTF (1, "Failed to lookup sequence point\n"); + method_full_name = mono_method_full_name (method, FALSE); while (method->is_inflated) method = ((MonoMethodInflated*)method)->declaring; @@ -602,7 +617,7 @@ list_frames (MonoStackFrameInfo *info, MonoContext *ctx, gpointer data) if (method->wrapper_type == MONO_WRAPPER_NONE) { DEBUG_PRINTF (2, "adding off %d token %d assembly name %s\n", sp.il_offset, mono_metadata_token_index (method->token), assembly_name); - mono_wasm_add_frame (sp.il_offset, mono_metadata_token_index (method->token), assembly_name); + mono_wasm_add_frame (sp.il_offset, mono_metadata_token_index (method->token), assembly_name, method_full_name); } g_free (assembly_name); @@ -616,6 +631,72 @@ mono_wasm_enum_frames (void) mono_walk_stack_with_ctx (list_frames, NULL, MONO_UNWIND_NONE, NULL); } +static char* +invoke_to_string (const char *class_name, MonoClass *klass, gpointer addr) +{ + MonoObject *exc; + MonoString *mstr; + char *ret_str; + ERROR_DECL (error); + MonoObject *obj; + + // TODO: this is for a specific use case right now, + // (invoke ToString() get a preview/description for *some* types) + // and we don't want to report errors for that. + if (m_class_is_valuetype (klass)) { + MonoMethod *method; + + MONO_STATIC_POINTER_INIT (MonoMethod, to_string) + to_string = mono_class_get_method_from_name_checked (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC, error); + mono_error_assert_ok (error); + MONO_STATIC_POINTER_INIT_END (MonoMethod, to_string) + + method = mono_class_get_virtual_method (klass, to_string, FALSE, error); + if (!method) + return NULL; + + MonoString *mstr = (MonoString*) mono_runtime_try_invoke (method, addr , NULL, &exc, error); + if (exc || !is_ok (error)) { + DEBUG_PRINTF (1, "Failed to invoke ToString for %s\n", class_name); + return NULL; + } + + return mono_string_to_utf8_checked_internal (mstr, error); + } + + obj = *(MonoObject**)addr; + if (!obj) + return NULL; + + mstr = mono_object_try_to_string (obj, &exc, error); + if (exc || !is_ok (error)) + return NULL; + + ret_str = mono_string_to_utf8_checked_internal (mstr, error); + if (!is_ok (error)) + return NULL; + + return ret_str; +} + +static char* +get_to_string_description (const char* class_name, MonoClass *klass, gpointer addr) +{ + if (!class_name || !klass || !addr) + return NULL; + + if (strcmp (class_name, "System.Guid") == 0) + return mono_guid_to_string (addr); + + for (int i = 0; i < G_N_ELEMENTS (to_string_as_descr_names); i ++) { + if (strcmp (to_string_as_descr_names [i], class_name) == 0) { + return invoke_to_string (class_name, klass, addr); + } + } + + return NULL; +} + typedef struct { int cur_frame; int target_frame; @@ -623,6 +704,28 @@ typedef struct { int *pos; } FrameDescData; +/* + * this returns a string formatted like + * + * :[]: + * + * .. which is consumed by `mono_wasm_add_func_var`. It is used for + * generating this for the delegate, and it's target. + */ +static char* +mono_method_to_desc_for_js (MonoMethod *method, gboolean include_namespace) +{ + MonoMethodSignature *sig = mono_method_signature_internal (method); + char *ret_desc = mono_type_full_name (sig->ret); + char *args_desc = mono_signature_get_desc (sig, include_namespace); + + char *sig_desc = g_strdup_printf ("%s:%s:%s", ret_desc, args_desc, method->name); + + g_free (ret_desc); + g_free (args_desc); + return sig_desc; +} + static guint64 read_enum_value (const char *mem, int type) { @@ -664,49 +767,64 @@ static gboolean describe_value(MonoType * type, gpointer addr, gboolean expandVa ERROR_DECL (error); switch (type->type) { case MONO_TYPE_BOOLEAN: - mono_wasm_add_bool_var (*(gint8*)addr); + mono_wasm_add_typed_value ("bool", NULL, *(gint8*)addr); break; case MONO_TYPE_I1: - mono_wasm_add_number_var (*(gint8*)addr); + mono_wasm_add_typed_value ("number", NULL, *(gint8*)addr); break; case MONO_TYPE_U1: - mono_wasm_add_number_var (*(guint8*)addr); + mono_wasm_add_typed_value ("number", NULL, *(guint8*)addr); break; case MONO_TYPE_CHAR: + mono_wasm_add_typed_value ("char", NULL, *(guint16*)addr); + break; case MONO_TYPE_U2: - mono_wasm_add_number_var (*(guint16*)addr); + mono_wasm_add_typed_value ("number", NULL, *(guint16*)addr); break; case MONO_TYPE_I2: - mono_wasm_add_number_var (*(gint16*)addr); + mono_wasm_add_typed_value ("number", NULL, *(gint16*)addr); break; case MONO_TYPE_I4: case MONO_TYPE_I: - mono_wasm_add_number_var (*(gint32*)addr); + mono_wasm_add_typed_value ("number", NULL, *(gint32*)addr); break; case MONO_TYPE_U4: case MONO_TYPE_U: - mono_wasm_add_number_var (*(guint32*)addr); + mono_wasm_add_typed_value ("number", NULL, *(guint32*)addr); break; case MONO_TYPE_I8: - mono_wasm_add_number_var (*(gint64*)addr); + mono_wasm_add_typed_value ("number", NULL, *(gint64*)addr); break; case MONO_TYPE_U8: - mono_wasm_add_number_var (*(guint64*)addr); + mono_wasm_add_typed_value ("number", NULL, *(guint64*)addr); break; case MONO_TYPE_R4: - mono_wasm_add_number_var (*(float*)addr); + mono_wasm_add_typed_value ("number", NULL, *(float*)addr); break; case MONO_TYPE_R8: - mono_wasm_add_number_var (*(double*)addr); + mono_wasm_add_typed_value ("number", NULL, *(double*)addr); break; + case MONO_TYPE_PTR: + case MONO_TYPE_FNPTR: { + char *class_name = mono_type_full_name (type); + const void *val = *(const void **)addr; + char *val_str = g_strdup_printf ("(%s) %p", class_name, val); + + mono_wasm_add_typed_value ("pointer", val_str, (guint32)val); + + g_free (val_str); + g_free (class_name); + break; + } + case MONO_TYPE_STRING: { MonoString *str_obj = *(MonoString **)addr; if (!str_obj) { - mono_wasm_add_string_var (NULL); + mono_wasm_add_typed_value ("string", NULL, 0); } else { char *str = mono_string_to_utf8_checked_internal (str_obj, error); mono_error_assert_ok (error); /* FIXME report error */ - mono_wasm_add_string_var (str); + mono_wasm_add_typed_value ("string", str, 0); g_free (str); } break; @@ -729,12 +847,34 @@ static gboolean describe_value(MonoType * type, gpointer addr, gboolean expandVa char *class_name = mono_type_full_name (type); int obj_id = get_object_id (obj); - if (type->type == MONO_TYPE_SZARRAY || type->type == MONO_TYPE_ARRAY) { - mono_wasm_add_array_var (class_name, obj_id); - } else if (m_class_is_delegate (klass)) { - mono_wasm_add_func_var (class_name, obj_id); + if (type-> type == MONO_TYPE_ARRAY || type->type == MONO_TYPE_SZARRAY) { + MonoArray *array = (MonoArray *)obj; + EM_ASM ({ + MONO.mono_wasm_add_typed_value ('array', $0, { objectId: $1, length: $2 }); + }, class_name, obj_id, mono_array_length_internal (array)); + } else if (m_class_is_delegate (klass) || (type->type == MONO_TYPE_GENERICINST && m_class_is_delegate (type->data.generic_class->container_class))) { + MonoMethod *method; + + if (type->type == MONO_TYPE_GENERICINST) + klass = type->data.generic_class->container_class; + + method = mono_get_delegate_invoke_internal (klass); + if (!method) { + DEBUG_PRINTF (2, "Could not get a method for the delegate for %s\n", class_name); + break; + } + + MonoMethod *tm = ((MonoDelegate *)obj)->method; + char *tm_desc = NULL; + if (tm) + tm_desc = mono_method_to_desc_for_js (tm, FALSE); + + mono_wasm_add_func_var (class_name, tm_desc, obj_id); + g_free (tm_desc); } else { - mono_wasm_add_obj_var (class_name, obj_id); + char *to_string_val = get_to_string_description (class_name, klass, addr); + mono_wasm_add_obj_var (class_name, to_string_val, obj_id); + g_free (to_string_val); } g_free (class_name); break; @@ -779,12 +919,17 @@ static gboolean describe_value(MonoType * type, gpointer addr, gboolean expandVa mono_wasm_add_enum_var (class_name, enum_members->str, value__); g_string_free (enum_members, TRUE); } else if (expandValueType) { - mono_wasm_begin_value_type_var (class_name); + char *to_string_val = get_to_string_description (class_name, klass, addr); + mono_wasm_begin_value_type_var (class_name, to_string_val); + g_free (to_string_val); + // FIXME: isAsyncLocalThis describe_object_properties_for_klass ((MonoObject*)addr, klass, FALSE, expandValueType); mono_wasm_end_value_type_var (); } else { - mono_wasm_add_value_type_unexpanded_var (class_name); + char *to_string_val = get_to_string_description (class_name, klass, addr); + mono_wasm_add_value_type_unexpanded_var (class_name, to_string_val); + g_free (to_string_val); } g_free (class_name); break; @@ -792,7 +937,7 @@ static gboolean describe_value(MonoType * type, gpointer addr, gboolean expandVa default: { char *type_name = mono_type_full_name (type); char *msg = g_strdup_printf("can't handle type %s [%p, %x]", type_name, type, type->type); - mono_wasm_add_string_var (msg); + mono_wasm_add_typed_value ("string", msg, 0); g_free (msg); g_free (type_name); } @@ -800,6 +945,37 @@ static gboolean describe_value(MonoType * type, gpointer addr, gboolean expandVa return TRUE; } +static gboolean +are_getters_allowed (const char *class_name) +{ + for (int i = 0; i < G_N_ELEMENTS (all_getters_allowed_class_names); i ++) { + if (strcmp (class_name, all_getters_allowed_class_names [i]) == 0) + return TRUE; + } + + return FALSE; +} + +static void +invoke_and_describe_getter_value (MonoObject *obj, MonoProperty *p) +{ + ERROR_DECL (error); + MonoObject *res; + MonoObject *exc; + + MonoMethodSignature *sig = mono_method_signature_internal (p->get); + + res = mono_runtime_try_invoke (p->get, obj, NULL, &exc, error); + if (!is_ok (error) && exc == NULL) + exc = (MonoObject*) mono_error_convert_to_exception (error); + if (exc) + describe_value (mono_get_object_type (), &exc, TRUE); + else if (!res || !m_class_is_valuetype (mono_object_class (res))) + describe_value (sig->ret, &res, TRUE); + else + describe_value (sig->ret, mono_object_unbox_internal (res), TRUE); +} + static void describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAsyncLocalThis, gboolean expandValueType) { @@ -807,9 +983,10 @@ describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAs MonoProperty *p; MonoMethodSignature *sig; gpointer iter = NULL; - ERROR_DECL (error); gboolean is_valuetype; int pnum; + char *klass_name; + gboolean getters_allowed; g_assert (klass); is_valuetype = m_class_is_valuetype(klass); @@ -841,12 +1018,13 @@ describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAs describe_value (f->type, field_addr, is_valuetype | expandValueType); } + klass_name = mono_class_full_name (klass); + getters_allowed = are_getters_allowed (klass_name); + iter = NULL; pnum = 0; while ((p = mono_class_get_properties (klass, &iter))) { - DEBUG_PRINTF (2, "mono_class_get_properties - %s - %s\n", p->name, p->get->name); if (p->get->name) { //if get doesn't have name means that doesn't have a getter implemented and we don't want to show value, like VS debug - char *class_name; if (isAsyncLocalThis && (p->name[0] != '<' || (p->name[0] == '<' && p->name[1] == '>'))) continue; @@ -854,32 +1032,52 @@ describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAs sig = mono_method_signature_internal (p->get); // automatic properties will get skipped - class_name = mono_class_full_name (mono_class_from_mono_type_internal (sig->ret)); - mono_wasm_add_string_var (class_name); - g_free (class_name); + if (!getters_allowed) { + // not allowed to call the getter here + char *ret_class_name = mono_class_full_name (mono_class_from_mono_type_internal (sig->ret)); + + // getters not supported for valuetypes, yet + gboolean invokable = !is_valuetype && sig->param_count == 0; + mono_wasm_add_typed_value ("getter", ret_class_name, invokable); + + g_free (ret_class_name); + continue; + } -#if false // Disabled for now, as we don't want to invoke getters if (is_valuetype && mono_class_from_mono_type_internal (sig->ret) == klass) { // Property of the same valuetype, avoid endlessly recursion! - mono_wasm_add_string_var (mono_class_full_name (klass)); + mono_wasm_add_typed_value ("getter", klass_name, 0); continue; } - res = mono_runtime_try_invoke (p->get, obj, NULL, &exc, error); - if (!is_ok (error) && exc == NULL) - exc = (MonoObject*) mono_error_convert_to_exception (error); - if (exc) - describe_value (mono_get_object_type (), &exc, TRUE); - else if (!res || !m_class_is_valuetype (mono_object_class (res))) - describe_value (sig->ret, &res, TRUE); - else - describe_value (sig->ret, mono_object_unbox_internal (res), TRUE); -#endif + invoke_and_describe_getter_value (obj, p); } pnum ++; } } +/* + * We return a `Target` property only for now. + * In future, we could add a `MethodInfo` too. + */ +static gboolean +describe_delegate_properties (MonoObject *obj) +{ + MonoClass *klass = mono_object_class(obj); + if (!m_class_is_delegate (klass)) + return FALSE; + + // Target, like in VS - what is this field supposed to be, anyway?? + MonoMethod *tm = ((MonoDelegate *)obj)->method; + char * sig_desc = mono_method_to_desc_for_js (tm, FALSE); + + mono_wasm_add_properties_var ("Target", -1); + mono_wasm_add_func_var (NULL, sig_desc, -1); + + g_free (sig_desc); + return TRUE; +} + static gboolean describe_object_properties (guint64 objectId, gboolean isAsyncLocalThis, gboolean expandValueType) { @@ -896,10 +1094,46 @@ describe_object_properties (guint64 objectId, gboolean isAsyncLocalThis, gboolea return FALSE; } - describe_object_properties_for_klass (obj, obj->vtable->klass, isAsyncLocalThis, expandValueType); + if (m_class_is_delegate (mono_object_class (obj))) { + // delegates get the same id format as regular objects + describe_delegate_properties (obj); + } else { + describe_object_properties_for_klass (obj, obj->vtable->klass, isAsyncLocalThis, expandValueType); + } + return TRUE; } +static gboolean +invoke_getter_on_object (guint64 objectId, const char *name) +{ + ObjRef *ref = (ObjRef *)g_hash_table_lookup (objrefs, GINT_TO_POINTER (objectId)); + if (!ref) { + DEBUG_PRINTF (1, "invoke_getter_on_object no objRef found for id %llu\n", objectId); + return FALSE; + } + + MonoObject *obj = mono_gchandle_get_target_internal (ref->handle); + if (!obj) { + DEBUG_PRINTF (1, "invoke_getter_on_object !obj\n"); + return FALSE; + } + + MonoClass *klass = mono_object_class (obj); + gpointer iter = NULL; + MonoProperty *p; + while ((p = mono_class_get_properties (klass, &iter))) { + //if get doesn't have name means that doesn't have a getter implemented and we don't want to show value, like VS debug + if (!p->get->name || strcasecmp (p->name, name) != 0) + continue; + + invoke_and_describe_getter_value (obj, p); + return TRUE; + } + + return FALSE; +} + static gboolean describe_array_values (guint64 objectId) { @@ -972,11 +1206,18 @@ describe_non_async_this (InterpFrame *frame, MonoMethod *method) if (mono_method_signature_internal (method)->hasthis) { addr = mini_get_interp_callbacks ()->frame_get_this (frame); MonoObject *obj = *(MonoObject**)addr; - char *class_name = mono_class_full_name (obj->vtable->klass); + MonoClass *klass = method->klass; + MonoType *type = m_class_get_byval_arg (method->klass); mono_wasm_add_properties_var ("this", -1); - mono_wasm_add_obj_var (class_name, get_object_id(obj)); - g_free (class_name); + + if (m_class_is_valuetype (klass)) { + describe_value (type, obj, TRUE); + } else { + // this is an object, and we can retrieve the valuetypes in it later + // through the object id + describe_value (type, addr, FALSE); + } } } @@ -1077,6 +1318,11 @@ mono_wasm_get_array_value_expanded (int object_id, int idx) describe_array_value_expanded (object_id, idx); } +EMSCRIPTEN_KEEPALIVE void +mono_wasm_invoke_getter_on_object (int object_id, const char* name) +{ + invoke_getter_on_object (object_id, name); +} // Functions required by debugger-state-machine. gsize mono_debugger_tls_thread_id (DebuggerTlsData *debuggerTlsData) diff --git a/src/mono/mono/mini/mini-wasm.c b/src/mono/mono/mini/mini-wasm.c index 8f1eef7f0c150d..70e182efef6cb4 100644 --- a/src/mono/mono/mini/mini-wasm.c +++ b/src/mono/mono/mini/mini-wasm.c @@ -455,6 +455,14 @@ mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code) return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG]; } +GSList* +mono_arch_get_cie_program (void) +{ + GSList *l = NULL; + + return l; +} + gpointer mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp) { diff --git a/src/mono/mono/mini/mini-windows.c b/src/mono/mono/mini/mini-windows.c index 673aeefeeede3b..eca60112441632 100644 --- a/src/mono/mono/mini/mini-windows.c +++ b/src/mono/mono/mini/mini-windows.c @@ -383,16 +383,13 @@ mono_setup_thread_context(DWORD thread_id, MonoContext *mono_context) handle = OpenThread (THREAD_ALL_ACCESS, FALSE, thread_id); g_assert (handle); - context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; + context.ContextFlags = CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_CONTROL; if (!GetThreadContext (handle, &context)) { CloseHandle (handle); return FALSE; } - g_assert (context.ContextFlags & CONTEXT_INTEGER); - g_assert (context.ContextFlags & CONTEXT_CONTROL); - memset (mono_context, 0, sizeof (MonoContext)); mono_sigctx_to_monoctx (&context, mono_context); diff --git a/src/mono/mono/mini/mini-x86.c b/src/mono/mono/mini/mini-x86.c index 464dc5d969d617..e717acdec85271 100644 --- a/src/mono/mono/mini/mini-x86.c +++ b/src/mono/mono/mini/mini-x86.c @@ -567,6 +567,112 @@ static gboolean storage_in_ireg (ArgStorage storage) return (storage == ArgInIReg || storage == ArgValuetypeInReg); } +static int +arg_need_temp (ArgInfo *ainfo) +{ + /* + * We always fetch the double value from the fpstack. In that case, we + * need to have a separate tmp that is the double value casted to float + */ + if (ainfo->storage == ArgOnFloatFpStack) + return sizeof (float); + return 0; +} + +static gpointer +arg_get_storage (CallContext *ccontext, ArgInfo *ainfo) +{ + switch (ainfo->storage) { + case ArgOnStack: + return ccontext->stack + ainfo->offset; + case ArgOnDoubleFpStack: + return &ccontext->fret; + case ArgInIReg: + /* If pair, the storage is for EDX:EAX */ + return &ccontext->eax; + default: + g_error ("Arg storage type not yet supported"); + } +} + +static void +arg_get_val (CallContext *ccontext, ArgInfo *ainfo, gpointer dest) +{ + g_assert (ainfo->storage == ArgOnFloatFpStack); + + *(float*) dest = (float)ccontext->fret; +} + +void +mono_arch_set_native_call_context_args (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig) +{ + CallInfo *cinfo = get_call_info (NULL, sig); + const MonoEECallbacks *interp_cb = mini_get_interp_callbacks (); + gpointer storage; + ArgInfo *ainfo; + + memset (ccontext, 0, sizeof (CallContext)); + + ccontext->stack_size = ALIGN_TO (cinfo->stack_usage, MONO_ARCH_FRAME_ALIGNMENT); + if (ccontext->stack_size) + ccontext->stack = (guint8*)g_calloc (1, ccontext->stack_size); + + if (sig->ret->type != MONO_TYPE_VOID) { + ainfo = &cinfo->ret; + if (ainfo->storage == ArgOnStack) { + /* This is a value type return. The pointer to vt storage is pushed as first argument */ + g_assert (ainfo->offset == 0); + g_assert (ainfo->nslots == 1); + storage = interp_cb->frame_arg_to_storage ((MonoInterpFrameHandle)frame, sig, -1); + *(host_mgreg_t*)ccontext->stack = (host_mgreg_t)storage; + } + } + + g_assert (!sig->hasthis); + + for (int i = 0; i < sig->param_count; i++) { + ainfo = &cinfo->args [i]; + + storage = arg_get_storage (ccontext, ainfo); + + interp_cb->frame_arg_to_data ((MonoInterpFrameHandle)frame, sig, i, storage); + } + + g_free (cinfo); +} + +void +mono_arch_get_native_call_context_ret (CallContext *ccontext, gpointer frame, MonoMethodSignature *sig) +{ + const MonoEECallbacks *interp_cb; + CallInfo *cinfo; + ArgInfo *ainfo; + gpointer storage; + + /* No return value */ + if (sig->ret->type == MONO_TYPE_VOID) + return; + + interp_cb = mini_get_interp_callbacks (); + cinfo = get_call_info (NULL, sig); + ainfo = &cinfo->ret; + + /* Check if return value was stored directly at address passed in reg */ + if (cinfo->ret.storage != ArgOnStack) { + int temp_size = arg_need_temp (ainfo); + + if (temp_size) { + storage = alloca (temp_size); + arg_get_val (ccontext, ainfo, storage); + } else { + storage = arg_get_storage (ccontext, ainfo); + } + interp_cb->data_to_frame_arg ((MonoInterpFrameHandle)frame, sig, -1, storage); + } + + g_free (cinfo); +} + /* * mono_arch_get_argument_info: * @csig: a method signature diff --git a/src/mono/mono/mini/mini-x86.h b/src/mono/mono/mini/mini-x86.h index 6791b57074e9f4..6d44cb5f2bf187 100644 --- a/src/mono/mono/mini/mini-x86.h +++ b/src/mono/mono/mini/mini-x86.h @@ -204,6 +204,10 @@ typedef struct { #define MONO_ARCH_HAVE_GET_TRAMPOLINES 1 #define MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE 1 +#define MONO_ARCH_INTERPRETER_SUPPORTED 1 +#define MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED 1 +#define MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP 1 + #define MONO_ARCH_HAVE_CMOV_OPS 1 #ifdef MONO_ARCH_SIMD_INTRINSICS @@ -332,6 +336,17 @@ struct CallInfo { ArgInfo args [1]; }; +typedef struct { + /* EAX:EDX */ + host_mgreg_t eax; + host_mgreg_t edx; + /* Floating point return value read from the top of x86 fpstack */ + double fret; + /* Stack usage, used for passing params on stack */ + guint32 stack_size; + guint8 *stack; +} CallContext; + guint32 mono_x86_get_this_arg_offset (MonoMethodSignature *sig); diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 0e632d0f4f6172..1d09d6d4668d44 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -1943,8 +1943,8 @@ enum { /* * Information about a trampoline function. */ - struct MonoTrampInfo - { +struct MonoTrampInfo +{ /* * The native code of the trampoline. Not owned by this structure. */ @@ -1966,6 +1966,11 @@ enum { MonoJitICallInfo *jit_icall_info; + /* + * The method the trampoline is associated with, if any. + */ + MonoMethod *method; + /* * Encoded unwind info loaded from AOT images */ diff --git a/src/mono/mono/mini/monovm.c b/src/mono/mono/mini/monovm.c index d1aff44ed68f6a..8abade8827f5e5 100644 --- a/src/mono/mono/mini/monovm.c +++ b/src/mono/mono/mini/monovm.c @@ -181,6 +181,12 @@ parse_properties (int propertyCount, const char **propertyKeys, const char **pro } else if (prop_len == 30 && !strncmp (propertyKeys [i], "System.Globalization.Invariant", 30)) { // TODO: Ideally we should propagate this through AppContext options g_setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", propertyValues [i], TRUE); + } else if (prop_len == 27 && !strncmp (propertyKeys [i], "System.Globalization.UseNls", 27)) { + // TODO: Ideally we should propagate this through AppContext options + g_setenv ("DOTNET_SYSTEM_GLOBALIZATION_USENLS", propertyValues [i], TRUE); + } else if (prop_len == 32 && !strncmp (propertyKeys [i], "System.Globalization.AppLocalIcu", 32)) { + // TODO: Ideally we should propagate this through AppContext options + g_setenv ("DOTNET_SYSTEM_GLOBALIZATION_APPLOCALICU", propertyValues [i], TRUE); } else { #if 0 // can't use mono logger, it's not initialized yet. diff --git a/src/mono/mono/mini/simd-intrinsics-netcore.c b/src/mono/mono/mini/simd-intrinsics-netcore.c index ea4c1a9574c02b..50f904bcd0fee3 100644 --- a/src/mono/mono/mini/simd-intrinsics-netcore.c +++ b/src/mono/mono/mini/simd-intrinsics-netcore.c @@ -4,6 +4,7 @@ #include #include +#include "mini.h" #if defined(DISABLE_JIT) @@ -18,7 +19,6 @@ mono_simd_intrinsics_init (void) * Only LLVM is supported as a backend. */ -#include "mini.h" #include "mini-runtime.h" #include "ir-emit.h" #ifdef ENABLE_LLVM diff --git a/src/mono/mono/mini/trace.c b/src/mono/mono/mini/trace.c index 0f22f0fec2dbce..0e28cc773ee22f 100644 --- a/src/mono/mono/mini/trace.c +++ b/src/mono/mono/mini/trace.c @@ -442,6 +442,34 @@ mono_trace_leave_method (MonoMethod *method, MonoJitInfo *ji, MonoProfilerCallCo mono_atomic_store_release (&output_lock, 0); } +void +mono_trace_tail_method (MonoMethod *method, MonoJitInfo *ji, MonoMethod *target) +{ + char *fname, *tname; + + if (!trace_spec.enabled) + return; + + fname = mono_method_full_name (method, TRUE); + tname = mono_method_full_name (target, TRUE); + indent (-1); + + while (output_lock != 0 || mono_atomic_cas_i32 (&output_lock, 1, 0) != 0) + mono_thread_info_yield (); + + /* FIXME: Might be better to pass the ji itself from the JIT */ + if (!ji) + ji = mini_jit_info_table_find (mono_domain_get (), (char *)MONO_RETURN_ADDRESS (), NULL); + + printf ("TAILC:%c %s->%s\n", frame_kind (ji), fname, tname); + fflush (stdout); + + g_free (fname); + g_free (tname); + + mono_atomic_store_release (&output_lock, 0); +} + void mono_trace_enable (gboolean enable) { diff --git a/src/mono/mono/mini/trace.h b/src/mono/mono/mini/trace.h index 8a53d08a64b9fb..19b443c8bb957e 100644 --- a/src/mono/mono/mini/trace.h +++ b/src/mono/mono/mini/trace.h @@ -16,6 +16,10 @@ ICALL_EXTERN_C void mono_trace_leave_method (MonoMethod *method, MonoJitInfo *ji, MonoProfilerCallContext *ctx); +ICALL_EXTERN_C +void +mono_trace_tail_method (MonoMethod *method, MonoJitInfo *ji, MonoMethod *target); + void mono_trace_enable (gboolean enable); gboolean mono_trace_is_enabled (void); gboolean mono_trace_eval_exception (MonoClass *klass); diff --git a/src/mono/mono/mini/tramp-s390x.c b/src/mono/mono/mini/tramp-s390x.c index 1911d919ab942a..2e068dda65d1fe 100644 --- a/src/mono/mono/mini/tramp-s390x.c +++ b/src/mono/mono/mini/tramp-s390x.c @@ -1,12 +1,15 @@ /** - * \file - * Function - JIT trampoline code for S/390. + * @file + * + * @author Neale Ferguson * - * Name - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com) + * @section description + * + * Function - JIT trampoline code for S/390. * * Date - January, 2004 * - * Derivation - From exceptions-x86 & exceptions-ppc + * Derivation - From tramp-x86 & tramp-ppc * Paolo Molaro (lupus@ximian.com) * Dietmar Maurer (dietmar@ximian.com) * @@ -50,6 +53,7 @@ #include "mini-runtime.h" #include "support-s390x.h" #include "jit-icalls.h" +#include "debugger-agent.h" #include "mono/utils/mono-tls-inline.h" /*========================= End of Includes ========================*/ @@ -79,20 +83,19 @@ typedef struct { /*====================== End of Global Variables ===================*/ -/*------------------------------------------------------------------*/ -/* */ -/* Name - mono_arch_get_unbox_trampoline */ -/* */ -/* Function - Return a pointer to a trampoline which does the */ -/* unboxing before calling the method. */ -/* */ -/* When value type methods are called through the */ -/* vtable we need to unbox the 'this' argument. */ -/* */ -/* Parameters - method - Methd pointer */ -/* addr - Pointer to native code for method */ -/* */ -/*------------------------------------------------------------------*/ +/** + * + * @brief Build the unbox trampoline + * + * @param[in] Method pointer + * @param[in] Pointer to native code for method + * + * Return a pointer to a trampoline which does the unboxing before + * calling the method. + * + * When value type methods are called through the + * vtable we need to unbox the 'this' argument. + */ gpointer mono_arch_get_unbox_trampoline (MonoMethod *method, gpointer addr) @@ -122,6 +125,127 @@ mono_arch_get_unbox_trampoline (MonoMethod *method, gpointer addr) /*========================= End of Function ========================*/ +/** + * + * @brief Build the SDB trampoline + * + * @param[in] Type of trampoline (ss or bp) + * @param[in] MonoTrampInfo + * @param[in] Ahead of time indicator + * + * Return a trampoline which captures the current context, passes it to + * mono_debugger_agent_single_step_from_context ()/mono_debugger_agent_breakpoint_from_context (), + * then restores the (potentially changed) context. + */ + +guint8 * +mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gboolean aot) +{ + int tramp_size = 512; + int i, framesize, ctx_offset, + gr_offset, fp_offset, ip_offset, + sp_offset; + guint8 *code, *buf; + void *ep; + GSList *unwind_ops = NULL; + MonoJumpInfo *ji = NULL; + + code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size); + + framesize = S390_MINIMAL_STACK_SIZE; + + ctx_offset = framesize; + framesize += sizeof (MonoContext); + + framesize = ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT); + + /** + * Create unwind information - On entry s390_r1 has value of method's frame reg + */ + mono_add_unwind_op_def_cfa (unwind_ops, code, buf, STK_BASE, 0); + s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); + gr_offset = S390_REG_SAVE_OFFSET; + for (i = s390_r6; i < s390_r15; i++) { + mono_add_unwind_op_offset (unwind_ops, code, buf, i, gr_offset); + gr_offset += sizeof(uintptr_t); + } + + s390_lgr (code, s390_r0, STK_BASE); + s390_aghi (code, STK_BASE, -framesize); + mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, framesize); + mono_add_unwind_op_fp_alloc (unwind_ops, code, buf, STK_BASE, 0); + s390_stg (code, s390_r0, 0, STK_BASE, 0); + + gr_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_mcontext.gregs); + sp_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_mcontext.gregs[15]); + ip_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_mcontext.psw.addr); + + /* Initialize a MonoContext structure on the stack */ + s390_stmg (code, s390_r0, s390_r14, STK_BASE, gr_offset); + s390_stg (code, s390_r1, 0, STK_BASE, sp_offset); + sp_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_stack.ss_sp); + s390_stg (code, s390_r1, 0, STK_BASE, sp_offset); + s390_stg (code, s390_r14, 0, STK_BASE, ip_offset); + + fp_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_mcontext.fpregs.fprs); + for (i = s390_f0; i < s390_f15; ++i) { + s390_std (code, i, 0, STK_BASE, fp_offset); + fp_offset += sizeof(double); + } + + /* + * Call the single step/breakpoint function in sdb using + * the context address as the parameter + */ + s390_la (code, s390_r2, 0, STK_BASE, ctx_offset); + + if (single_step) + ep = (mini_get_dbg_callbacks())->single_step_from_context; + else + ep = (mini_get_dbg_callbacks())->breakpoint_from_context; + + S390_SET (code, s390_r1, ep); + s390_basr (code, s390_r14, s390_r1); + + /* + * Restore volatiles + */ + s390_lmg (code, s390_r0, s390_r5, STK_BASE, gr_offset); + + /* + * Restore FP registers + */ + fp_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_mcontext.fpregs.fprs); + for (i = s390_f0; i < s390_f15; ++i) { + s390_ld (code, i, 0, STK_BASE, fp_offset); + fp_offset += sizeof(double); + } + + /* + * Load the IP from the context to pick up any SET_IP command results + */ + s390_lg (code, s390_r14, 0, STK_BASE, ip_offset); + + /* + * Restore everything else from the on-entry values + */ + s390_aghi (code, STK_BASE, framesize); + mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, -framesize); + s390_lmg (code, s390_r6, s390_r13, STK_BASE, S390_REG_SAVE_OFFSET); + s390_br (code, s390_r14); + + g_assertf ((code - buf) <= tramp_size, "%d %d", (int)(code - buf), tramp_size); + mono_arch_flush_icache (code, code - buf); + + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); + g_assert (code - buf <= tramp_size); + + const char *tramp_name = single_step ? "sdb_single_step_trampoline" : "sdb_breakpoint_trampoline"; + *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops); + + return buf; +} + /*------------------------------------------------------------------*/ /* */ /* Name - mono_arch_patch_callsite */ @@ -204,9 +328,17 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf stack size big enough to save our registers. -----------------------------------------------------------*/ + mono_add_unwind_op_def_cfa (unwind_ops, code, buf, STK_BASE, 0); s390_stmg (buf, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET); + offset = S390_REG_SAVE_OFFSET; + for (i = s390_r6; i < s390_r15; i++) { + mono_add_unwind_op_offset (unwind_ops, code, buf, i, offset); + offset += sizeof(uintptr_t); + } + s390_lgr (buf, s390_r11, s390_r15); s390_aghi (buf, STK_BASE, -sizeof(trampStack_t)); + mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, sizeof(trampStack_t)); s390_stg (buf, s390_r11, 0, STK_BASE, 0); /*---------------------------------------------------------------*/ @@ -360,6 +492,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf * R14 contains the return address to our caller */ s390_lgr (buf, STK_BASE, s390_r11); + // mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, -sizeof(trampStack_t)); s390_lmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); if (MONO_TRAMPOLINE_TYPE_MUST_RETURN(tramp_type)) { diff --git a/src/mono/mono/mini/tramp-x86.c b/src/mono/mono/mini/tramp-x86.c index 196a3bf9ad818f..10900c8113d716 100644 --- a/src/mono/mono/mini/tramp-x86.c +++ b/src/mono/mono/mini/tramp-x86.c @@ -719,3 +719,92 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo return buf; } + +gpointer +mono_arch_get_interp_to_native_trampoline (MonoTrampInfo **info) +{ +#ifndef DISABLE_INTERPRETER + guint8 *start = NULL, *code; + guint8 *label_start_copy, *label_exit_copy; + MonoJumpInfo *ji = NULL; + GSList *unwind_ops = NULL; + int buf_len; + int ccontext_offset, target_offset; + + buf_len = 512; + start = code = (guint8 *) mono_global_codeman_reserve (buf_len); + + x86_push_reg (code, X86_EBP); + /* args are on the stack, above saved EBP and pushed return EIP */ + target_offset = 2 * sizeof (target_mgreg_t); + ccontext_offset = target_offset + sizeof (target_mgreg_t); + x86_mov_reg_reg (code, X86_EBP, X86_ESP); + + /* Save some used regs and align stack to 16 bytes */ + x86_push_reg (code, X86_EDI); + x86_push_reg (code, X86_ESI); + + /* load pointer to CallContext* into ESI */ + x86_mov_reg_membase (code, X86_ESI, X86_EBP, ccontext_offset, sizeof (target_mgreg_t)); + + /* allocate the stack space necessary for the call */ + x86_mov_reg_membase (code, X86_ECX, X86_ESI, MONO_STRUCT_OFFSET (CallContext, stack_size), sizeof (target_mgreg_t)); + x86_alu_reg_reg (code, X86_SUB, X86_ESP, X86_ECX); + + /* copy stack from the CallContext, ESI = source, EDI = dest, ECX bytes to copy */ + x86_mov_reg_membase (code, X86_ESI, X86_ESI, MONO_STRUCT_OFFSET (CallContext, stack), sizeof (target_mgreg_t)); + x86_mov_reg_reg (code, X86_EDI, X86_ESP); + + label_start_copy = code; + x86_test_reg_reg (code, X86_ECX, X86_ECX); + label_exit_copy = code; + x86_branch8 (code, X86_CC_Z, 0, FALSE); + x86_mov_reg_membase (code, X86_EDX, X86_ESI, 0, sizeof (target_mgreg_t)); + x86_mov_membase_reg (code, X86_EDI, 0, X86_EDX, sizeof (target_mgreg_t)); + x86_alu_reg_imm (code, X86_ADD, X86_EDI, sizeof (target_mgreg_t)); + x86_alu_reg_imm (code, X86_ADD, X86_ESI, sizeof (target_mgreg_t)); + x86_alu_reg_imm (code, X86_SUB, X86_ECX, sizeof (target_mgreg_t)); + x86_jump_code (code, label_start_copy); + x86_patch (label_exit_copy, code); + + /* load target addr */ + x86_mov_reg_membase (code, X86_EAX, X86_EBP, target_offset, sizeof (target_mgreg_t)); + + /* call into native function */ + x86_call_reg (code, X86_EAX); + + /* Save return values into CallContext* */ + x86_mov_reg_membase (code, X86_ESI, X86_EBP, ccontext_offset, sizeof (target_mgreg_t)); + x86_mov_membase_reg (code, X86_ESI, MONO_STRUCT_OFFSET (CallContext, eax), X86_EAX, sizeof (target_mgreg_t)); + x86_mov_membase_reg (code, X86_ESI, MONO_STRUCT_OFFSET (CallContext, edx), X86_EDX, sizeof (target_mgreg_t)); + + /* + * We always pop ST0, even if we don't have return value. We seem to get away with + * this because fpstack is either empty or has one fp return value on top and the cpu + * doesn't trap if we read top of empty stack. + */ + x86_fst_membase (code, X86_ESI, MONO_STRUCT_OFFSET (CallContext, fret), TRUE, TRUE); + + /* restore ESI, EDI which were saved below rbp */ + x86_mov_reg_membase (code, X86_EDI, X86_EBP, - sizeof (target_mgreg_t), sizeof (target_mgreg_t)); + x86_mov_reg_membase (code, X86_ESI, X86_EBP, - 2 * sizeof (target_mgreg_t), sizeof (target_mgreg_t)); + x86_mov_reg_reg (code, X86_ESP, X86_EBP); + + x86_pop_reg (code, X86_EBP); + + x86_ret (code); + + g_assertf ((code - start) <= buf_len, "%d %d", (int)(code - start), buf_len); + + mono_arch_flush_icache (start, code - start); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); + + if (info) + *info = mono_tramp_info_create ("interp_to_native_trampoline", start, code - start, ji, unwind_ops); + + return start; +#else + g_assert_not_reached (); + return NULL; +#endif /* DISABLE_INTERPRETER */ +} diff --git a/src/mono/mono/mini/unwind.c b/src/mono/mono/mini/unwind.c index 55e2db32c83500..721f7f3a2d2ca2 100644 --- a/src/mono/mono/mini/unwind.c +++ b/src/mono/mono/mini/unwind.c @@ -310,6 +310,7 @@ mono_print_unwind_info (guint8 *unwind_info, int unwind_info_len) switch (op) { case DW_CFA_advance_loc: pos += *p & 0x3f; + printf ("CFA: [%x] advance loc\n",pos); p ++; break; case DW_CFA_offset: @@ -419,14 +420,14 @@ mono_unwind_ops_encode_full (GSList *unwind_ops, guint32 *out_len, gboolean enab *p ++ = DW_CFA_advance_loc4; guint32 v = (guint32)(op->when - loc); memcpy (p, &v, 4); - g_assert (read32 (p) == (guint32)(op->when - loc)); + g_assert (read32 (p) == GUINT32_TO_LE((guint32)(op->when - loc))); p += 4; loc = op->when; } else if (op->when - loc >= 256) { *p ++ = DW_CFA_advance_loc2; guint16 v = (guint16)(op->when - loc); memcpy (p, &v, 2); - g_assert (read16 (p) == (guint32)(op->when - loc)); + g_assert (read16 (p) == GUINT16_TO_LE((guint32)(op->when - loc))); p += 2; loc = op->when; } else if (op->when - loc >= 32) { diff --git a/src/mono/mono/mini/wasm_m2n_invoke.g.h b/src/mono/mono/mini/wasm_m2n_invoke.g.h index aea7e9698ad3de..f1e6fde4edd667 100644 --- a/src/mono/mono/mini/wasm_m2n_invoke.g.h +++ b/src/mono/mono/mini/wasm_m2n_invoke.g.h @@ -1,6 +1,6 @@ /* -* DON'T EDIT THIS FILE -* This file was generated by m2n-gen.cs - use it instead. +* GENERATED FILE, DON'T EDIT +* Generated by wasm-tuner.exe --gen-interp-to-native */ static void wasm_invoke_v (void *target_func, InterpMethodArguments *margs) @@ -1017,6 +1017,371 @@ wasm_invoke_vil (void *target_func, InterpMethodArguments *margs) } +static void +wasm_invoke_fifff (void *target_func, InterpMethodArguments *margs) +{ + typedef float (*T)(int arg_0, float arg_1, float arg_2, float arg_3); + T func = (T)target_func; + float res = func ((int)(gssize)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], *(float*)&margs->fargs [FIDX (2)]); + *(float*)margs->retval = res; + +} + +static void +wasm_invoke_fii (void *target_func, InterpMethodArguments *margs) +{ + typedef float (*T)(int arg_0, int arg_1); + T func = (T)target_func; + float res = func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1]); + *(float*)margs->retval = res; + +} + +static void +wasm_invoke_fiii (void *target_func, InterpMethodArguments *margs) +{ + typedef float (*T)(int arg_0, int arg_1, int arg_2); + T func = (T)target_func; + float res = func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2]); + *(float*)margs->retval = res; + +} + +static void +wasm_invoke_fiiiiii (void *target_func, InterpMethodArguments *margs) +{ + typedef float (*T)(int arg_0, int arg_1, int arg_2, int arg_3, int arg_4, int arg_5); + T func = (T)target_func; + float res = func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3], (int)(gssize)margs->iargs [4], (int)(gssize)margs->iargs [5]); + *(float*)margs->retval = res; + +} + +static void +wasm_invoke_iffffiiii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(float arg_0, float arg_1, float arg_2, float arg_3, int arg_4, int arg_5, int arg_6, int arg_7); + T func = (T)target_func; + int res = func (*(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], *(float*)&margs->fargs [FIDX (2)], *(float*)&margs->fargs [FIDX (3)], (int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iffi (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(float arg_0, float arg_1, int arg_2); + T func = (T)target_func; + int res = func (*(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [0]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iffif (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(float arg_0, float arg_1, int arg_2, float arg_3); + T func = (T)target_func; + int res = func (*(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [0], *(float*)&margs->fargs [FIDX (2)]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iffifi (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(float arg_0, float arg_1, int arg_2, float arg_3, int arg_4); + T func = (T)target_func; + int res = func (*(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [0], *(float*)&margs->fargs [FIDX (2)], (int)(gssize)margs->iargs [1]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_ifi (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(float arg_0, int arg_1); + T func = (T)target_func; + int res = func (*(float*)&margs->fargs [FIDX (0)], (int)(gssize)margs->iargs [0]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_ifiii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(float arg_0, int arg_1, int arg_2, int arg_3); + T func = (T)target_func; + int res = func (*(float*)&margs->fargs [FIDX (0)], (int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iififiiiii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, float arg_1, int arg_2, float arg_3, int arg_4, int arg_5, int arg_6, int arg_7, int arg_8); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], (int)(gssize)margs->iargs [1], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3], (int)(gssize)margs->iargs [4], (int)(gssize)margs->iargs [5], (int)(gssize)margs->iargs [6]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iififiiiiii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, float arg_1, int arg_2, float arg_3, int arg_4, int arg_5, int arg_6, int arg_7, int arg_8, int arg_9); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], (int)(gssize)margs->iargs [1], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3], (int)(gssize)margs->iargs [4], (int)(gssize)margs->iargs [5], (int)(gssize)margs->iargs [6], (int)(gssize)margs->iargs [7]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iifiiiii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, float arg_1, int arg_2, int arg_3, int arg_4, int arg_5, int arg_6); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3], (int)(gssize)margs->iargs [4], (int)(gssize)margs->iargs [5]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iifiiiiii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, float arg_1, int arg_2, int arg_3, int arg_4, int arg_5, int arg_6, int arg_7); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3], (int)(gssize)margs->iargs [4], (int)(gssize)margs->iargs [5], (int)(gssize)margs->iargs [6]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiifffii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, int arg_1, float arg_2, float arg_3, float arg_4, int arg_5, int arg_6); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], *(float*)&margs->fargs [FIDX (2)], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiiffifffii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, int arg_1, float arg_2, float arg_3, int arg_4, float arg_5, float arg_6, float arg_7, int arg_8, int arg_9); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [2], *(float*)&margs->fargs [FIDX (2)], *(float*)&margs->fargs [FIDX (3)], *(float*)&margs->fargs [FIDX (4)], (int)(gssize)margs->iargs [3], (int)(gssize)margs->iargs [4]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiiffiffii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, int arg_1, float arg_2, float arg_3, int arg_4, float arg_5, float arg_6, int arg_7, int arg_8); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [2], *(float*)&margs->fargs [FIDX (2)], *(float*)&margs->fargs [FIDX (3)], (int)(gssize)margs->iargs [3], (int)(gssize)margs->iargs [4]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiiffii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, int arg_1, float arg_2, float arg_3, int arg_4, int arg_5); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiiffiiiii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, int arg_1, float arg_2, float arg_3, int arg_4, int arg_5, int arg_6, int arg_7, int arg_8); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3], (int)(gssize)margs->iargs [4], (int)(gssize)margs->iargs [5], (int)(gssize)margs->iargs [6]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiiiif (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, int arg_1, int arg_2, int arg_3, float arg_4); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3], *(float*)&margs->fargs [FIDX (0)]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiiiifii (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, int arg_1, int arg_2, int arg_3, float arg_4, int arg_5, int arg_6); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3], *(float*)&margs->fargs [FIDX (0)], (int)(gssize)margs->iargs [4], (int)(gssize)margs->iargs [5]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiiiiiffi (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, int arg_1, int arg_2, int arg_3, int arg_4, float arg_5, float arg_6, int arg_7); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3], (int)(gssize)margs->iargs [4], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [5]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_iiiiiiiffi (void *target_func, InterpMethodArguments *margs) +{ + typedef int (*T)(int arg_0, int arg_1, int arg_2, int arg_3, int arg_4, int arg_5, float arg_6, float arg_7, int arg_8); + T func = (T)target_func; + int res = func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3], (int)(gssize)margs->iargs [4], (int)(gssize)margs->iargs [5], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [6]); + *(int*)margs->retval = res; + +} + +static void +wasm_invoke_vifff (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, float arg_1, float arg_2, float arg_3); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], *(float*)&margs->fargs [FIDX (2)]); + +} + +static void +wasm_invoke_viffffi (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, float arg_1, float arg_2, float arg_3, float arg_4, int arg_5); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], *(float*)&margs->fargs [FIDX (2)], *(float*)&margs->fargs [FIDX (3)], (int)(gssize)margs->iargs [1]); + +} + +static void +wasm_invoke_vifffi (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, float arg_1, float arg_2, float arg_3, int arg_4); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], *(float*)&margs->fargs [FIDX (2)], (int)(gssize)margs->iargs [1]); + +} + +static void +wasm_invoke_vifffiiff (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, float arg_1, float arg_2, float arg_3, int arg_4, int arg_5, float arg_6, float arg_7); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], *(float*)&margs->fargs [FIDX (2)], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], *(float*)&margs->fargs [FIDX (3)], *(float*)&margs->fargs [FIDX (4)]); + +} + +static void +wasm_invoke_viffi (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, float arg_1, float arg_2, int arg_3); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [1]); + +} + +static void +wasm_invoke_vifi (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, float arg_1, int arg_2); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], *(float*)&margs->fargs [FIDX (0)], (int)(gssize)margs->iargs [1]); + +} + +static void +wasm_invoke_viiff (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, int arg_1, float arg_2, float arg_3); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)]); + +} + +static void +wasm_invoke_viiffff (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, int arg_1, float arg_2, float arg_3, float arg_4, float arg_5); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], *(float*)&margs->fargs [FIDX (2)], *(float*)&margs->fargs [FIDX (3)]); + +} + +static void +wasm_invoke_viiffii (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, int arg_1, float arg_2, float arg_3, int arg_4, int arg_5); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3]); + +} + +static void +wasm_invoke_viiif (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, int arg_1, int arg_2, float arg_3); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], *(float*)&margs->fargs [FIDX (0)]); + +} + +static void +wasm_invoke_viiiffii (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, int arg_1, int arg_2, float arg_3, float arg_4, int arg_5, int arg_6); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [3], (int)(gssize)margs->iargs [4]); + +} + +static void +wasm_invoke_viiiffiii (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, int arg_1, int arg_2, float arg_3, float arg_4, int arg_5, int arg_6, int arg_7); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], *(float*)&margs->fargs [FIDX (0)], *(float*)&margs->fargs [FIDX (1)], (int)(gssize)margs->iargs [3], (int)(gssize)margs->iargs [4], (int)(gssize)margs->iargs [5]); + +} + +static void +wasm_invoke_viiifii (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, int arg_1, int arg_2, float arg_3, int arg_4, int arg_5); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], *(float*)&margs->fargs [FIDX (0)], (int)(gssize)margs->iargs [3], (int)(gssize)margs->iargs [4]); + +} + +static void +wasm_invoke_viiifiii (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, int arg_1, int arg_2, float arg_3, int arg_4, int arg_5, int arg_6); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], *(float*)&margs->fargs [FIDX (0)], (int)(gssize)margs->iargs [3], (int)(gssize)margs->iargs [4], (int)(gssize)margs->iargs [5]); + +} + +static void +wasm_invoke_viiiif (void *target_func, InterpMethodArguments *margs) +{ + typedef void (*T)(int arg_0, int arg_1, int arg_2, int arg_3, float arg_4); + T func = (T)target_func; + func ((int)(gssize)margs->iargs [0], (int)(gssize)margs->iargs [1], (int)(gssize)margs->iargs [2], (int)(gssize)margs->iargs [3], *(float*)&margs->fargs [FIDX (0)]); + +} + static void icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodArguments *margs) { @@ -1095,27 +1460,96 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr return; } } + else if (cookie[5] == 'F') { + if (cookie[6] == '\0') { + // found: VIIIIF depth 8 + wasm_invoke_viiiif (target_func, margs); + return; + } + } else if (cookie[5] == '\0') { - // found: VIIII depth 7 + // found: VIIII depth 8 wasm_invoke_viiii (target_func, margs); return; } } + else if (cookie[4] == 'F') { + if (cookie[5] == 'F') { + if (cookie[6] == 'I') { + if (cookie[7] == 'I') { + if (cookie[8] == 'I') { + if (cookie[9] == '\0') { + // found: VIIIFFIII depth 11 + wasm_invoke_viiiffiii (target_func, margs); + return; + } + } + else if (cookie[8] == '\0') { + // found: VIIIFFII depth 11 + wasm_invoke_viiiffii (target_func, margs); + return; + } + } + } + } + else if (cookie[5] == 'I') { + if (cookie[6] == 'I') { + if (cookie[7] == 'I') { + if (cookie[8] == '\0') { + // found: VIIIFIII depth 11 + wasm_invoke_viiifiii (target_func, margs); + return; + } + } + else if (cookie[7] == '\0') { + // found: VIIIFII depth 11 + wasm_invoke_viiifii (target_func, margs); + return; + } + } + } + else if (cookie[5] == '\0') { + // found: VIIIF depth 9 + wasm_invoke_viiif (target_func, margs); + return; + } + } else if (cookie[4] == '\0') { - // found: VIII depth 6 + // found: VIII depth 7 wasm_invoke_viii (target_func, margs); return; } } else if (cookie[3] == 'F') { if (cookie[4] == 'F') { - if (cookie[5] == 'I') { - if (cookie[6] == '\0') { - // found: VIIFFI depth 8 + if (cookie[5] == 'F') { + if (cookie[6] == 'F') { + if (cookie[7] == '\0') { + // found: VIIFFFF depth 9 + wasm_invoke_viiffff (target_func, margs); + return; + } + } + } + else if (cookie[5] == 'I') { + if (cookie[6] == 'I') { + if (cookie[7] == '\0') { + // found: VIIFFII depth 10 + wasm_invoke_viiffii (target_func, margs); + return; + } + } + else if (cookie[6] == '\0') { + // found: VIIFFI depth 10 wasm_invoke_viiffi (target_func, margs); return; } } + else if (cookie[5] == '\0') { + // found: VIIFF depth 9 + wasm_invoke_viiff (target_func, margs); + return; + } } } else if (cookie[3] == '\0') { @@ -1127,43 +1561,87 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr else if (cookie[2] == 'F') { if (cookie[3] == 'F') { if (cookie[4] == 'F') { - if (cookie[5] == 'F') { + if (cookie[5] == 'I') { + if (cookie[6] == 'I') { + if (cookie[7] == 'F') { + if (cookie[8] == 'F') { + if (cookie[9] == '\0') { + // found: VIFFFIIFF depth 11 + wasm_invoke_vifffiiff (target_func, margs); + return; + } + } + } + } + else if (cookie[6] == '\0') { + // found: VIFFFI depth 9 + wasm_invoke_vifffi (target_func, margs); + return; + } + } + else if (cookie[5] == 'F') { if (cookie[6] == 'F') { if (cookie[7] == 'F') { if (cookie[8] == '\0') { - // found: VIFFFFFF depth 10 + // found: VIFFFFFF depth 11 wasm_invoke_viffffff (target_func, margs); return; } } else if (cookie[7] == 'I') { if (cookie[8] == '\0') { - // found: VIFFFFFI depth 11 + // found: VIFFFFFI depth 12 wasm_invoke_vifffffi (target_func, margs); return; } } else if (cookie[7] == '\0') { - // found: VIFFFFF depth 11 + // found: VIFFFFF depth 12 wasm_invoke_vifffff (target_func, margs); return; } } + else if (cookie[6] == 'I') { + if (cookie[7] == '\0') { + // found: VIFFFFI depth 11 + wasm_invoke_viffffi (target_func, margs); + return; + } + } else if (cookie[6] == '\0') { - // found: VIFFFF depth 9 + // found: VIFFFF depth 11 wasm_invoke_viffff (target_func, margs); return; } } + else if (cookie[5] == '\0') { + // found: VIFFF depth 9 + wasm_invoke_vifff (target_func, margs); + return; + } + } + else if (cookie[4] == 'I') { + if (cookie[5] == '\0') { + // found: VIFFI depth 8 + wasm_invoke_viffi (target_func, margs); + return; + } } else if (cookie[4] == '\0') { - // found: VIFF depth 7 + // found: VIFF depth 8 wasm_invoke_viff (target_func, margs); return; } } + else if (cookie[3] == 'I') { + if (cookie[4] == '\0') { + // found: VIFI depth 7 + wasm_invoke_vifi (target_func, margs); + return; + } + } else if (cookie[3] == '\0') { - // found: VIF depth 6 + // found: VIF depth 7 wasm_invoke_vif (target_func, margs); return; } @@ -1245,8 +1723,61 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr } } else if (cookie[7] == '\0') { - // found: IIIFFFF depth 10 - wasm_invoke_iiiffff (target_func, margs); + // found: IIIFFFF depth 10 + wasm_invoke_iiiffff (target_func, margs); + return; + } + } + else if (cookie[6] == 'I') { + if (cookie[7] == 'I') { + if (cookie[8] == '\0') { + // found: IIIFFFII depth 11 + wasm_invoke_iiifffii (target_func, margs); + return; + } + } + } + } + else if (cookie[5] == 'I') { + if (cookie[6] == 'F') { + if (cookie[7] == 'F') { + if (cookie[8] == 'F') { + if (cookie[9] == 'I') { + if (cookie[10] == 'I') { + if (cookie[11] == '\0') { + // found: IIIFFIFFFII depth 14 + wasm_invoke_iiiffifffii (target_func, margs); + return; + } + } + } + } + else if (cookie[8] == 'I') { + if (cookie[9] == 'I') { + if (cookie[10] == '\0') { + // found: IIIFFIFFII depth 14 + wasm_invoke_iiiffiffii (target_func, margs); + return; + } + } + } + } + } + else if (cookie[6] == 'I') { + if (cookie[7] == 'I') { + if (cookie[8] == 'I') { + if (cookie[9] == 'I') { + if (cookie[10] == '\0') { + // found: IIIFFIIIII depth 14 + wasm_invoke_iiiffiiiii (target_func, margs); + return; + } + } + } + } + else if (cookie[7] == '\0') { + // found: IIIFFII depth 12 + wasm_invoke_iiiffii (target_func, margs); return; } } @@ -1334,8 +1865,15 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr } else if (cookie[7] == 'F') { if (cookie[8] == 'F') { - if (cookie[9] == '\0') { - // found: IIIIIIIFF depth 13 + if (cookie[9] == 'I') { + if (cookie[10] == '\0') { + // found: IIIIIIIFFI depth 14 + wasm_invoke_iiiiiiiffi (target_func, margs); + return; + } + } + else if (cookie[9] == '\0') { + // found: IIIIIIIFF depth 14 wasm_invoke_iiiiiiiff (target_func, margs); return; } @@ -1353,10 +1891,19 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr } } else if (cookie[6] == 'F') { - if (cookie[7] == 'I') { + if (cookie[7] == 'F') { + if (cookie[8] == 'I') { + if (cookie[9] == '\0') { + // found: IIIIIIFFI depth 13 + wasm_invoke_iiiiiiffi (target_func, margs); + return; + } + } + } + else if (cookie[7] == 'I') { if (cookie[8] == 'I') { if (cookie[9] == '\0') { - // found: IIIIIIFII depth 13 + // found: IIIIIIFII depth 14 wasm_invoke_iiiiiifii (target_func, margs); return; } @@ -1389,6 +1936,20 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr } } } + else if (cookie[6] == 'I') { + if (cookie[7] == 'I') { + if (cookie[8] == '\0') { + // found: IIIIIFII depth 13 + wasm_invoke_iiiiifii (target_func, margs); + return; + } + } + } + else if (cookie[6] == '\0') { + // found: IIIIIF depth 12 + wasm_invoke_iiiiif (target_func, margs); + return; + } } else if (cookie[5] == '\0') { // found: IIIII depth 10 @@ -1437,7 +1998,68 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr } } else if (cookie[2] == 'F') { - if (cookie[3] == 'F') { + if (cookie[3] == 'I') { + if (cookie[4] == 'F') { + if (cookie[5] == 'I') { + if (cookie[6] == 'I') { + if (cookie[7] == 'I') { + if (cookie[8] == 'I') { + if (cookie[9] == 'I') { + if (cookie[10] == 'I') { + if (cookie[11] == '\0') { + // found: IIFIFIIIIII depth 14 + wasm_invoke_iififiiiiii (target_func, margs); + return; + } + } + else if (cookie[10] == '\0') { + // found: IIFIFIIIII depth 14 + wasm_invoke_iififiiiii (target_func, margs); + return; + } + } + } + } + } + } + } + else if (cookie[4] == 'I') { + if (cookie[5] == 'I') { + if (cookie[6] == 'I') { + if (cookie[7] == 'I') { + if (cookie[8] == 'I') { + if (cookie[9] == '\0') { + // found: IIFIIIIII depth 13 + wasm_invoke_iifiiiiii (target_func, margs); + return; + } + } + else if (cookie[8] == '\0') { + // found: IIFIIIII depth 13 + wasm_invoke_iifiiiii (target_func, margs); + return; + } + } + } + else if (cookie[6] == '\0') { + // found: IIFIII depth 11 + wasm_invoke_iifiii (target_func, margs); + return; + } + } + else if (cookie[5] == '\0') { + // found: IIFII depth 10 + wasm_invoke_iifii (target_func, margs); + return; + } + } + else if (cookie[4] == '\0') { + // found: IIFI depth 9 + wasm_invoke_iifi (target_func, margs); + return; + } + } + else if (cookie[3] == 'F') { if (cookie[4] == 'F') { if (cookie[5] == 'F') { if (cookie[6] == 'F') { @@ -1445,14 +2067,14 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr if (cookie[8] == 'F') { if (cookie[9] == 'F') { if (cookie[10] == '\0') { - // found: IIFFFFFFFF depth 13 + // found: IIFFFFFFFF depth 14 wasm_invoke_iiffffffff (target_func, margs); return; } } } else if (cookie[8] == '\0') { - // found: IIFFFFFF depth 12 + // found: IIFFFFFF depth 13 wasm_invoke_iiffffff (target_func, margs); return; } @@ -1461,13 +2083,13 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr else if (cookie[6] == 'I') { if (cookie[7] == 'I') { if (cookie[8] == '\0') { - // found: IIFFFFII depth 12 + // found: IIFFFFII depth 13 wasm_invoke_iiffffii (target_func, margs); return; } } else if (cookie[7] == '\0') { - // found: IIFFFFI depth 12 + // found: IIFFFFI depth 13 wasm_invoke_iiffffi (target_func, margs); return; } @@ -1475,13 +2097,13 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr } else if (cookie[5] == 'I') { if (cookie[6] == '\0') { - // found: IIFFFI depth 10 + // found: IIFFFI depth 11 wasm_invoke_iifffi (target_func, margs); return; } } else if (cookie[5] == '\0') { - // found: IIFFF depth 10 + // found: IIFFF depth 11 wasm_invoke_iifff (target_func, margs); return; } @@ -1490,50 +2112,29 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr if (cookie[5] == 'I') { if (cookie[6] == 'I') { if (cookie[7] == '\0') { - // found: IIFFIII depth 11 + // found: IIFFIII depth 12 wasm_invoke_iiffiii (target_func, margs); return; } } else if (cookie[6] == '\0') { - // found: IIFFII depth 11 + // found: IIFFII depth 12 wasm_invoke_iiffii (target_func, margs); return; } } else if (cookie[5] == '\0') { - // found: IIFFI depth 10 + // found: IIFFI depth 11 wasm_invoke_iiffi (target_func, margs); return; } } else if (cookie[4] == '\0') { - // found: IIFF depth 9 + // found: IIFF depth 10 wasm_invoke_iiff (target_func, margs); return; } } - else if (cookie[3] == 'I') { - if (cookie[4] == 'I') { - if (cookie[5] == 'I') { - if (cookie[6] == '\0') { - // found: IIFIII depth 10 - wasm_invoke_iifiii (target_func, margs); - return; - } - } - else if (cookie[5] == '\0') { - // found: IIFII depth 10 - wasm_invoke_iifii (target_func, margs); - return; - } - } - else if (cookie[4] == '\0') { - // found: IIFI depth 9 - wasm_invoke_iifi (target_func, margs); - return; - } - } else if (cookie[3] == '\0') { // found: IIF depth 8 wasm_invoke_iif (target_func, margs); @@ -1600,11 +2201,24 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr if (cookie[2] == 'F') { if (cookie[3] == 'F') { if (cookie[4] == 'F') { - if (cookie[5] == 'F') { + if (cookie[5] == 'I') { + if (cookie[6] == 'I') { + if (cookie[7] == 'I') { + if (cookie[8] == 'I') { + if (cookie[9] == '\0') { + // found: IFFFFIIII depth 12 + wasm_invoke_iffffiiii (target_func, margs); + return; + } + } + } + } + } + else if (cookie[5] == 'F') { if (cookie[6] == 'F') { if (cookie[7] == 'I') { if (cookie[8] == '\0') { - // found: IFFFFFFI depth 11 + // found: IFFFFFFI depth 12 wasm_invoke_iffffffi (target_func, margs); return; } @@ -1614,17 +2228,52 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr } } else if (cookie[3] == 'I') { - if (cookie[4] == 'I') { + if (cookie[4] == 'F') { + if (cookie[5] == 'I') { + if (cookie[6] == '\0') { + // found: IFFIFI depth 10 + wasm_invoke_iffifi (target_func, margs); + return; + } + } + else if (cookie[5] == '\0') { + // found: IFFIF depth 10 + wasm_invoke_iffif (target_func, margs); + return; + } + } + else if (cookie[4] == 'I') { if (cookie[5] == '\0') { - // found: IFFII depth 9 + // found: IFFII depth 10 wasm_invoke_iffii (target_func, margs); return; } } + else if (cookie[4] == '\0') { + // found: IFFI depth 10 + wasm_invoke_iffi (target_func, margs); + return; + } + } + } + else if (cookie[2] == 'I') { + if (cookie[3] == 'I') { + if (cookie[4] == 'I') { + if (cookie[5] == '\0') { + // found: IFIII depth 9 + wasm_invoke_ifiii (target_func, margs); + return; + } + } + } + else if (cookie[3] == '\0') { + // found: IFI depth 8 + wasm_invoke_ifi (target_func, margs); + return; } } else if (cookie[2] == '\0') { - // found: IF depth 6 + // found: IF depth 7 wasm_invoke_if (target_func, margs); return; } @@ -1662,58 +2311,141 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr return; } } + else if (cookie[0] == 'F') { + if (cookie[1] == 'I') { + if (cookie[2] == 'I') { + if (cookie[3] == 'I') { + if (cookie[4] == 'I') { + if (cookie[5] == 'I') { + if (cookie[6] == 'I') { + if (cookie[7] == '\0') { + // found: FIIIIII depth 10 + wasm_invoke_fiiiiii (target_func, margs); + return; + } + } + } + } + else if (cookie[4] == '\0') { + // found: FIII depth 8 + wasm_invoke_fiii (target_func, margs); + return; + } + } + else if (cookie[3] == '\0') { + // found: FII depth 7 + wasm_invoke_fii (target_func, margs); + return; + } + } + else if (cookie[2] == 'F') { + if (cookie[3] == 'F') { + if (cookie[4] == 'F') { + if (cookie[5] == '\0') { + // found: FIFFF depth 9 + wasm_invoke_fifff (target_func, margs); + return; + } + } + else if (cookie[4] == '\0') { + // found: FIFF depth 9 + wasm_invoke_fiff (target_func, margs); + return; + } + } + else if (cookie[3] == '\0') { + // found: FIF depth 8 + wasm_invoke_fif (target_func, margs); + return; + } + } + else if (cookie[2] == '\0') { + // found: FI depth 7 + wasm_invoke_fi (target_func, margs); + return; + } + } + else if (cookie[1] == 'F') { + if (cookie[2] == 'F') { + if (cookie[3] == 'F') { + if (cookie[4] == '\0') { + // found: FFFF depth 8 + wasm_invoke_ffff (target_func, margs); + return; + } + } + else if (cookie[3] == '\0') { + // found: FFF depth 8 + wasm_invoke_fff (target_func, margs); + return; + } + } + else if (cookie[2] == 'I') { + if (cookie[3] == '\0') { + // found: FFI depth 8 + wasm_invoke_ffi (target_func, margs); + return; + } + } + else if (cookie[2] == '\0') { + // found: FF depth 8 + wasm_invoke_ff (target_func, margs); + return; + } + } + } else if (cookie[0] == 'L') { if (cookie[1] == 'I') { if (cookie[2] == 'L') { if (cookie[3] == 'I') { if (cookie[4] == 'I') { if (cookie[5] == '\0') { - // found: LILII depth 8 + // found: LILII depth 9 wasm_invoke_lilii (target_func, margs); return; } } else if (cookie[4] == '\0') { - // found: LILI depth 8 + // found: LILI depth 9 wasm_invoke_lili (target_func, margs); return; } } else if (cookie[3] == 'L') { if (cookie[4] == '\0') { - // found: LILL depth 8 + // found: LILL depth 9 wasm_invoke_lill (target_func, margs); return; } } else if (cookie[3] == '\0') { - // found: LIL depth 8 + // found: LIL depth 9 wasm_invoke_lil (target_func, margs); return; } } else if (cookie[2] == 'I') { if (cookie[3] == '\0') { - // found: LII depth 7 + // found: LII depth 8 wasm_invoke_lii (target_func, margs); return; } } else if (cookie[2] == '\0') { - // found: LI depth 7 + // found: LI depth 8 wasm_invoke_li (target_func, margs); return; } } else if (cookie[1] == 'L') { if (cookie[2] == '\0') { - // found: LL depth 6 + // found: LL depth 7 wasm_invoke_ll (target_func, margs); return; } } else if (cookie[1] == '\0') { - // found: L depth 6 + // found: L depth 7 wasm_invoke_l (target_func, margs); return; } @@ -1723,26 +2455,26 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr if (cookie[2] == 'D') { if (cookie[3] == 'D') { if (cookie[4] == '\0') { - // found: DDDD depth 8 + // found: DDDD depth 9 wasm_invoke_dddd (target_func, margs); return; } } else if (cookie[3] == '\0') { - // found: DDD depth 8 + // found: DDD depth 9 wasm_invoke_ddd (target_func, margs); return; } } else if (cookie[2] == 'I') { if (cookie[3] == '\0') { - // found: DDI depth 8 + // found: DDI depth 9 wasm_invoke_ddi (target_func, margs); return; } } else if (cookie[2] == '\0') { - // found: DD depth 8 + // found: DD depth 9 wasm_invoke_dd (target_func, margs); return; } @@ -1751,74 +2483,23 @@ icall_trampoline_dispatch (const char *cookie, void *target_func, InterpMethodAr if (cookie[2] == 'D') { if (cookie[3] == 'D') { if (cookie[4] == '\0') { - // found: DIDD depth 9 + // found: DIDD depth 10 wasm_invoke_didd (target_func, margs); return; } } else if (cookie[3] == '\0') { - // found: DID depth 9 + // found: DID depth 10 wasm_invoke_did (target_func, margs); return; } } else if (cookie[2] == '\0') { - // found: DI depth 8 + // found: DI depth 9 wasm_invoke_di (target_func, margs); return; } } } - else if (cookie[0] == 'F') { - if (cookie[1] == 'F') { - if (cookie[2] == 'F') { - if (cookie[3] == 'F') { - if (cookie[4] == '\0') { - // found: FFFF depth 9 - wasm_invoke_ffff (target_func, margs); - return; - } - } - else if (cookie[3] == '\0') { - // found: FFF depth 9 - wasm_invoke_fff (target_func, margs); - return; - } - } - else if (cookie[2] == 'I') { - if (cookie[3] == '\0') { - // found: FFI depth 9 - wasm_invoke_ffi (target_func, margs); - return; - } - } - else if (cookie[2] == '\0') { - // found: FF depth 9 - wasm_invoke_ff (target_func, margs); - return; - } - } - else if (cookie[1] == 'I') { - if (cookie[2] == 'F') { - if (cookie[3] == 'F') { - if (cookie[4] == '\0') { - // found: FIFF depth 10 - wasm_invoke_fiff (target_func, margs); - return; - } - } - else if (cookie[3] == '\0') { - // found: FIF depth 10 - wasm_invoke_fif (target_func, margs); - return; - } - } - else if (cookie[2] == '\0') { - // found: FI depth 9 - wasm_invoke_fi (target_func, margs); - return; - } - } - } g_error ("CANNOT HANDLE COOKIE %s\n", cookie); } diff --git a/src/mono/mono/profiler/Makefile.am b/src/mono/mono/profiler/Makefile.am index acb1057e311c82..5380a405ebc275 100644 --- a/src/mono/mono/profiler/Makefile.am +++ b/src/mono/mono/profiler/Makefile.am @@ -14,7 +14,9 @@ if !HOST_WIN32 if !DISABLE_LIBRARIES if !DISABLE_PROFILER +if !DISABLE_EXECUTABLES bin_PROGRAMS = mprof-report +endif if HAVE_VTUNE vtune_libs = \ diff --git a/src/mono/mono/sgen/sgen-nursery-allocator.c b/src/mono/mono/sgen/sgen-nursery-allocator.c index eb26dd36eb0d5c..c4ac6b2c67381b 100644 --- a/src/mono/mono/sgen/sgen-nursery-allocator.c +++ b/src/mono/mono/sgen/sgen-nursery-allocator.c @@ -793,7 +793,7 @@ sgen_build_nursery_fragments (GCMemSection *nursery_section) SGEN_LOG (1, "Nursery fully pinned"); for (pin_entry = pin_start; pin_entry < pin_end; ++pin_entry) { GCObject *p = (GCObject *)*pin_entry; - SGEN_LOG (3, "Bastard pinning obj %p (%s), size: %ld", p, sgen_client_vtable_get_name (SGEN_LOAD_VTABLE (p)), (long)sgen_safe_object_get_size (p)); + SGEN_LOG (3, "Bad pinning obj %p (%s), size: %ld", p, sgen_client_vtable_get_name (SGEN_LOAD_VTABLE (p)), (long)sgen_safe_object_get_size (p)); } } return fragment_total; diff --git a/src/mono/mono/tests/Makefile.am b/src/mono/mono/tests/Makefile.am index 8261429fe2f0e2..6b20fc9c525b87 100755 --- a/src/mono/mono/tests/Makefile.am +++ b/src/mono/mono/tests/Makefile.am @@ -1720,6 +1720,11 @@ LLVM_DISABLED_TESTS = \ LLVM_DISABLED_TESTS += \ weak-fields.exe +if HOST_WIN32 +# https://github.com/mono/mono/issues/19603 +LLVM_DISABLED_TESTS += sgen-bridge.exe +endif + LLVM = $(filter --llvm, $(MONO_ENV_OPTIONS) $(AOT_BUILD_FLAGS)) # The two finalizer tests only work under sgen @@ -1942,72 +1947,17 @@ INTERP_DISABLED_TESTS += calli_sig_check.exe # Test is too sensitive. INTERP_DISABLED_TESTS += localloc-noinit.exe - -# bug-48015.exe: be careful when re-enabling, it happens that it returns with exit code 0, but doesn't actually execute the test. +INTERP_DISABLED_TESTS += dim-diamondshape.exe +INTERP_DISABLED_TESTS += pinvoke3.exe +INTERP_DISABLED_TESTS += cominterop.exe # bug-60862.exe: missing support to map IP->method; only works on platforms with altstack support. -# bug-60843.exe: something goes wrong when turning the decoded enum value into a boxed enum, so the loaded value ends up being random bytes - -if ARM -INTERP_DISABLED_TESTS += \ - appdomain-unload-callback.exe \ - appdomain-unload.exe \ - assemblyresolve_event6.exe \ - async-with-cb-throws.exe \ - block_guard_restore_aligment_on_exit.exe \ - bug-323114.exe \ - bug-335131.2.exe \ - bug-415577.exe \ - bug-45841-fpstack-exceptions.exe \ - bug-48015.exe \ - bug-60862.exe \ - bug-80307.exe \ - bug-80392.2.exe \ - bug445361.exe \ - calliGenericTest.exe \ - cominterop.exe \ - context-static.exe \ - delegate-async-exit.exe \ - delegate-delegate-exit.exe \ - delegate-exit.exe \ - delegate1.exe \ - delegate3.exe \ - delegate5.exe \ - delegate8.exe \ - delegate9.exe \ - dim-diamondshape.exe \ - dynamic-method-stack-traces.exe \ - even-odd.exe \ - exception18.exe \ - field-access.exe \ - finalizer-exception.exe \ - handleref.exe \ - monitor-abort.exe \ - nullable_boxing.2.exe \ - pinvoke2.exe \ - pinvoke3.exe \ - remoting2.exe \ - remoting3.exe \ - safehandle.2.exe \ - stackframes-async.2.exe \ - static-constructor.exe \ - threadpool-exceptions2.exe \ - threadpool-exceptions3.exe \ - threadpool-exceptions4.exe \ - threadpool-exceptions5.exe \ - threadpool-exceptions6.exe \ - thunks.exe \ - typeload-unaligned.exe \ - vararg.exe \ - vararg2.exe \ - vararg3.exe -endif +INTERP_DISABLED_TESTS += bug-60862.exe +# bug-48015.exe: remoting test that fails on fullaotinterp scenarios +INTERP_DISABLED_TESTS += bug-48015.exe if ARM64 INTERP_DISABLED_TESTS += \ - bug-48015.exe \ - bug-80307.exe \ - dim-diamondshape.exe \ - pinvoke3.exe + bug-80307.exe # Test is too sensitive. DISABLED_TESTS += localloc-noinit.exe @@ -2019,16 +1969,6 @@ if HOST_WIN32 DISABLED_TESTS += localloc-noinit.exe endif -if AMD64 -INTERP_DISABLED_TESTS += \ - assemblyresolve_event6.exe \ - bug-48015.exe \ - bug-60862.exe \ - cominterop.exe \ - dim-diamondshape.exe \ - pinvoke3.exe -endif - TESTS_CS=$(filter-out $(DISABLED_TESTS),$(TESTS_CS_SRC:.cs=.exe)) TESTS_IL=$(filter-out $(DISABLED_TESTS),$(TESTS_IL_SRC:.il=.exe)) TESTS_BENCH=$(filter-out $(DISABLED_TESTS),$(TESTS_BENCH_SRC:.cs=.exe)) diff --git a/src/mono/mono/tests/sgen-toggleref.cs b/src/mono/mono/tests/sgen-toggleref.cs index 372263f908d008..6ce7980ed5a1e5 100644 --- a/src/mono/mono/tests/sgen-toggleref.cs +++ b/src/mono/mono/tests/sgen-toggleref.cs @@ -19,17 +19,43 @@ public class Toggleref { } } -[StructLayout (LayoutKind.Explicit)] public struct Helper { - [FieldOffset(0)] - IntPtr ptr; - [FieldOffset(0)] - object obj; + private class ObjectWrapper + { + public object Object; + } + + private class IntPtrWrapper + { + public IntPtr Value; + } + + [StructLayout(LayoutKind.Explicit)] + private struct ObjectReinterpreter + { + [FieldOffset(0)] public ObjectWrapper AsObject; + [FieldOffset(0)] public IntPtrWrapper AsIntPtr; + } + + private static object mutualObject; + private static ObjectReinterpreter reinterpreter; + + static Helper() + { + Helper.mutualObject = new object(); + Helper.reinterpreter = new ObjectReinterpreter(); + Helper.reinterpreter.AsObject = new ObjectWrapper(); + } + public static IntPtr ObjToPtr (object obj) { - Helper h = default (Helper); - h.obj = obj; - return h.ptr; + lock (Helper.mutualObject) + { + Helper.reinterpreter.AsObject.Object = obj; + IntPtr address = Helper.reinterpreter.AsIntPtr.Value; + Helper.reinterpreter.AsObject.Object = null; + return address; + } } } diff --git a/src/mono/mono/tools/offsets-tool/offsets-tool.py b/src/mono/mono/tools/offsets-tool/offsets-tool.py index d44e436e22985b..f9f7170aac3194 100644 --- a/src/mono/mono/tools/offsets-tool/offsets-tool.py +++ b/src/mono/mono/tools/offsets-tool/offsets-tool.py @@ -125,6 +125,11 @@ def require_emscipten_path (args): self.target = Target ("TARGET_ARM64", "TARGET_IOS", IOS_DEFINES) self.target_args += ["-arch", "arm64"] self.target_args += ["-isysroot", args.sysroot] + elif "i386-apple-darwin10" == args.abi: + require_sysroot (args) + self.target = Target ("TARGET_X86", "", IOS_DEFINES) + self.target_args += ["-arch", "i386"] + self.target_args += ["-isysroot", args.sysroot] # watchOS elif "armv7k-apple-darwin" == args.abi: diff --git a/src/mono/mono/unit-tests/test-mono-callspec.c b/src/mono/mono/unit-tests/test-mono-callspec.c index 186286c22c5342..147ad4f26e2d51 100644 --- a/src/mono/mono/unit-tests/test-mono-callspec.c +++ b/src/mono/mono/unit-tests/test-mono-callspec.c @@ -182,7 +182,7 @@ test_mono_callspec_main (void) MonoMethod *meth; MonoImageOpenStatus status; - //FIXME This is a fugly hack due to embedding simply not working from the tree + //FIXME This is a hack due to embedding simply not working from the tree mono_set_assemblies_path ("../../mcs/class/lib/net_4_x"); test_methods = g_array_new (FALSE, TRUE, sizeof (MonoMethod *)); diff --git a/src/mono/mono/utils/mono-context.c b/src/mono/mono/utils/mono-context.c index 59af9256a562df..62b1febb644fbd 100644 --- a/src/mono/mono/utils/mono-context.c +++ b/src/mono/mono/utils/mono-context.c @@ -233,6 +233,22 @@ mono_sigctx_to_monoctx (void *sigctx, MonoContext *mctx) mctx->gregs [AMD64_R13] = context->R13; mctx->gregs [AMD64_R14] = context->R14; mctx->gregs [AMD64_R15] = context->R15; + memcpy (&(mctx->fregs [AMD64_XMM0]), &(context->Xmm0), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM1]), &(context->Xmm1), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM2]), &(context->Xmm2), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM3]), &(context->Xmm3), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM4]), &(context->Xmm4), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM5]), &(context->Xmm5), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM6]), &(context->Xmm6), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM7]), &(context->Xmm7), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM8]), &(context->Xmm8), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM9]), &(context->Xmm9), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM10]), &(context->Xmm10), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM11]), &(context->Xmm11), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM12]), &(context->Xmm12), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM13]), &(context->Xmm13), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM14]), &(context->Xmm14), sizeof (MonoContextSimdReg)); + memcpy (&(mctx->fregs [AMD64_XMM15]), &(context->Xmm15), sizeof (MonoContextSimdReg)); #elif defined(__HAIKU__) // Haiku uses sigcontext because there's no ucontext struct sigcontext *ctx = (struct sigcontext *)sigctx; @@ -326,6 +342,22 @@ mono_monoctx_to_sigctx (MonoContext *mctx, void *sigctx) context->R13 = mctx->gregs [AMD64_R13]; context->R14 = mctx->gregs [AMD64_R14]; context->R15 = mctx->gregs [AMD64_R15]; + memcpy (&(context->Xmm0), &(mctx->fregs [AMD64_XMM0]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm1), &(mctx->fregs [AMD64_XMM1]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm2), &(mctx->fregs [AMD64_XMM2]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm3), &(mctx->fregs [AMD64_XMM3]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm4), &(mctx->fregs [AMD64_XMM4]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm5), &(mctx->fregs [AMD64_XMM5]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm6), &(mctx->fregs [AMD64_XMM6]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm7), &(mctx->fregs [AMD64_XMM7]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm8), &(mctx->fregs [AMD64_XMM8]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm9), &(mctx->fregs [AMD64_XMM9]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm10), &(mctx->fregs [AMD64_XMM10]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm11), &(mctx->fregs [AMD64_XMM11]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm12), &(mctx->fregs [AMD64_XMM12]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm13), &(mctx->fregs [AMD64_XMM13]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm14), &(mctx->fregs [AMD64_XMM14]), sizeof (MonoContextSimdReg)); + memcpy (&(context->Xmm15), &(mctx->fregs [AMD64_XMM15]), sizeof (MonoContextSimdReg)); #elif defined(__HAIKU__) // Haiku uses sigcontext because there's no ucontext struct sigcontext *ctx = (struct sigcontext *)sigctx; diff --git a/src/mono/mono/utils/mono-dl-posix.c b/src/mono/mono/utils/mono-dl-posix.c index 1900a1acf5621b..a6c767c8285dbe 100644 --- a/src/mono/mono/utils/mono-dl-posix.c +++ b/src/mono/mono/utils/mono-dl-posix.c @@ -136,10 +136,10 @@ mono_dl_convert_flags (int flags) #ifdef ENABLE_NETCORE // Specifying both will default to LOCAL - if (flags & MONO_DL_LOCAL) - lflags |= RTLD_LOCAL; - else if (flags & MONO_DL_GLOBAL) + if (flags & MONO_DL_GLOBAL && !(flags & MONO_DL_LOCAL)) lflags |= RTLD_GLOBAL; + else + lflags |= RTLD_LOCAL; #else lflags = flags & MONO_DL_LOCAL ? RTLD_LOCAL : RTLD_GLOBAL; #endif diff --git a/src/mono/mono/utils/mono-dl.c b/src/mono/mono/utils/mono-dl.c index 8b4aedd179ac91..32fc1daed7dbc7 100644 --- a/src/mono/mono/utils/mono-dl.c +++ b/src/mono/mono/utils/mono-dl.c @@ -21,6 +21,9 @@ #include #include #include +#if defined(ENABLE_NETCORE) && defined(TARGET_ANDROID) +#include +#endif // Contains LIBC_SO definition #ifdef HAVE_GNU_LIB_NAMES_H @@ -168,6 +171,37 @@ fix_libc_name (const char *name) } #endif +/** + * mono_dl_open_self: + * \param error_msg pointer for error message on failure + * + * Returns a handle to the main program, on android x86 it's not possible to + * call dl_open(null), it returns a null handle, so this function returns RTLD_DEFAULT + * handle in this platform. + */ +MonoDl* +mono_dl_open_self (char **error_msg) +{ +#if defined(ENABLE_NETCORE) && defined(TARGET_ANDROID) + MonoDl *module; + if (error_msg) + *error_msg = NULL; + module = (MonoDl *) g_malloc (sizeof (MonoDl)); + if (!module) { + if (error_msg) + *error_msg = g_strdup ("Out of memory"); + return NULL; + } + mono_refcount_init (module, NULL); + module->handle = RTLD_DEFAULT; + module->dl_fallback = NULL; + module->full_name = NULL; + return module; +#else + return mono_dl_open (NULL, MONO_DL_LAZY, error_msg); +#endif +} + /** * mono_dl_open: * \param name name of file containing shared module diff --git a/src/mono/mono/utils/mono-dl.h b/src/mono/mono/utils/mono-dl.h index 6236d98b1e59b7..6efee6feabfd5b 100644 --- a/src/mono/mono/utils/mono-dl.h +++ b/src/mono/mono/utils/mono-dl.h @@ -43,6 +43,8 @@ char* mono_dl_build_path (const char *directory, const char *name, void ** MonoDl* mono_dl_open_runtime_lib (const char *lib_name, int flags, char **error_msg); +MonoDl* mono_dl_open_self (char **error_msg); + //Platform API for mono_dl const char* mono_dl_get_so_prefix (void); diff --git a/src/mono/mono/utils/mono-hwcap-s390x.c b/src/mono/mono/utils/mono-hwcap-s390x.c index f6a6dfa9a5aebc..5c24a15e5e1b3a 100644 --- a/src/mono/mono/utils/mono-hwcap-s390x.c +++ b/src/mono/mono/utils/mono-hwcap-s390x.c @@ -86,7 +86,7 @@ typedef struct { uint8_t mie2:1; // 058 - Miscellaneous execution facility 2 uint8_t x005:1; // 059 - Undefined uint8_t x006:1; // 060 - Undefined - uint8_t x007:1; // 061 - Undefined + uint8_t mie3:1; // 061 - Miscellaneous execution facility 3 uint8_t ibm06:1; // 062 - Assigned to IBM uint8_t x008:1; // 063 - Undefined uint8_t x009:1; // 064 - Undefined @@ -106,7 +106,8 @@ typedef struct { uint8_t edat2:1; // 078 - Enhanced DAT 2 uint8_t x010:1; // 079 - Undefined uint8_t dfppc:1; // 080 - DFP packed conversion - uint8_t x011:7; // 081-87 - Undefined + uint8_t ppaf:1; // 081 - PPA in order facility + uint8_t x011:6; // 082-87 - Undefined uint8_t x012[5]; // 088-127 - Undefined uint8_t ibm12:1; // 128 - Assigned to IBM uint8_t vec:1; // 129 - Vector facility @@ -126,11 +127,18 @@ typedef struct { uint8_t irbm:1; // 145 - Insert Reference Bits Multiple Facility uint8_t mse8:1; // 146 - Message Security Assist Extension 8 uint8_t ibm14:1; // 147 - Reserved for IBM use - uint8_t x016:4; // 148-151 - Undefined - uint8_t x017[2]; // 152-167 - Undefined + uint8_t vef2:1; // 148 - Vector Execution Facility 2 + uint8_t mpsk:1; // 149 - Move Page and Set Key Facility + uint8_t x016:1; // 150 - Undefined + uint8_t dfcf:1; // 151 - Deflate Conversion Facility + uint8_t vpde:1; // 152 - Vector Packed Decimal Enhancement Facility + uint8_t x017:2; // 153-154 - Undefined + uint8_t msa9:1; // 155 - Message Security Assist Facility 9 + uint8_t x018:4; // 156-159 - Undefined + uint8_t x019; // 160-167 - Undefined uint8_t esac:1; // 168 - ESA/390 Compatibility Mode Facility - uint8_t x018:7; // 169-175 - Undefined - uint8_t x019[10]; // 176-256 Undefined + uint8_t x020:7; // 169-175 - Undefined + uint8_t x021[10]; // 176-256 Undefined } __attribute__ ((__packed__)) __attribute__ ((__aligned__(8))) facilityList_t; void @@ -153,5 +161,8 @@ mono_hwcap_arch_init (void) mono_hwcap_s390x_has_ia = facs.ia; mono_hwcap_s390x_has_gie = facs.gie; mono_hwcap_s390x_has_mie2 = facs.mie2; + mono_hwcap_s390x_has_mie3 = facs.mie3; mono_hwcap_s390x_has_gs = facs.gs; + mono_hwcap_s390x_has_vef2 = facs.vef2; + mono_hwcap_s390x_has_eif = facs.eif; } diff --git a/src/mono/mono/utils/mono-hwcap-vars.h b/src/mono/mono/utils/mono-hwcap-vars.h index a7846dbbecc701..b408568c729f4d 100644 --- a/src/mono/mono/utils/mono-hwcap-vars.h +++ b/src/mono/mono/utils/mono-hwcap-vars.h @@ -56,7 +56,10 @@ MONO_HWCAP_VAR(s390x_has_mlt) MONO_HWCAP_VAR(s390x_has_ia) MONO_HWCAP_VAR(s390x_has_gie) MONO_HWCAP_VAR(s390x_has_mie2) +MONO_HWCAP_VAR(s390x_has_mie3) MONO_HWCAP_VAR(s390x_has_gs) +MONO_HWCAP_VAR(s390x_has_vef2) +MONO_HWCAP_VAR(s390x_has_eif) #elif defined (TARGET_SPARC) || defined (TARGET_SPARC64) diff --git a/src/mono/mono/utils/mono-sigcontext.h b/src/mono/mono/utils/mono-sigcontext.h index b23b70614f507d..9a73dff7c520cd 100644 --- a/src/mono/mono/utils/mono-sigcontext.h +++ b/src/mono/mono/utils/mono-sigcontext.h @@ -324,6 +324,9 @@ typedef struct ucontext { #endif #if defined(__linux__) + +/* don't rely on glibc to include this for us, musl won't */ +#include typedef ucontext_t os_ucontext; #ifdef __mono_ppc64__ @@ -535,8 +538,12 @@ typedef struct ucontext # include # endif -# define UCONTEXT_GREGS(ctx) (((ucontext_t *)(ctx))->uc_mcontext.gregs) -# define UCONTEXT_FREGS(ctx) (((ucontext_t *)(ctx))->uc_mcontext.fpregs->fprs) +# define UCONTEXT_GREGS(ctx) (((ucontext_t *)(ctx))->uc_mcontext.gregs) +# define UCONTEXT_FREGS(ctx) (((ucontext_t *)(ctx))->uc_mcontext.fpregs->fprs) +# define UCONTEXT_REG_Rn(ctx, n) (((ucontext_t *)(ctx))->uc_mcontext.gregs[(n)]) +# define UCONTEXT_SP(ctx) (((ucontext_t *)(ctx))->uc_stack.ss_sp) +# define UCONTEXT_IP(ctx) (((ucontext_t *)(ctx))->uc_mcontext.psw.addr) + #endif #elif defined (TARGET_RISCV) diff --git a/src/mono/mono/utils/mono-state.c b/src/mono/mono/utils/mono-state.c index 717c88cfb07a9b..7333818f3a2a78 100644 --- a/src/mono/mono/utils/mono-state.c +++ b/src/mono/mono/utils/mono-state.c @@ -1202,22 +1202,6 @@ mono_crash_dump (const char *jsonFile, MonoStackHash *hashes) return; } -#endif // DISABLE_CRASH_REPORTING - -static volatile int32_t dump_status; - -gboolean -mono_dump_start (void) -{ - return (mono_atomic_xchg_i32(&dump_status, 1) == 0); // return true if we started the dump -} - -gboolean -mono_dump_complete (void) -{ - return (mono_atomic_xchg_i32(&dump_status, 0) == 1); // return true if we completed the dump -} - static char *saved_failfast_msg; /** @@ -1237,3 +1221,19 @@ mono_crash_get_failfast_msg (void) { return saved_failfast_msg; } + +#endif // DISABLE_CRASH_REPORTING + +static volatile int32_t dump_status; + +gboolean +mono_dump_start (void) +{ + return (mono_atomic_xchg_i32(&dump_status, 1) == 0); // return true if we started the dump +} + +gboolean +mono_dump_complete (void) +{ + return (mono_atomic_xchg_i32(&dump_status, 0) == 1); // return true if we completed the dump +} diff --git a/src/mono/mono/utils/mono-threads-posix.c b/src/mono/mono/utils/mono-threads-posix.c index 33afc458a79283..c3ddb64d565231 100644 --- a/src/mono/mono/utils/mono-threads-posix.c +++ b/src/mono/mono/utils/mono-threads-posix.c @@ -32,11 +32,9 @@ #include -#if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64) +#if !defined(ENABLE_NETCORE) && defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64) +// tkill was deprecated and removed in the recent versions of Android NDK #define USE_TKILL_ON_ANDROID 1 -#endif - -#ifdef USE_TKILL_ON_ANDROID extern int tkill (pid_t tid, int signal); #endif @@ -310,6 +308,15 @@ mono_native_thread_set_name (MonoNativeThreadId tid, const char *name) pthread_setname_np (tid, "%s", (void*)n); } #elif defined (HAVE_PTHREAD_SETNAME_NP) +#if defined (__linux__) + /* Ignore requests to set the main thread name because it causes the + * value returned by Process.ProcessName to change. + */ + MonoNativeThreadId main_thread_tid; + if (mono_native_thread_id_main_thread_known (&main_thread_tid) && + mono_native_thread_id_equals (tid, main_thread_tid)) + return; +#endif if (!name) { pthread_setname_np (tid, ""); } else { diff --git a/src/mono/mono/utils/mono-threads-windows.c b/src/mono/mono/utils/mono-threads-windows.c index 378c2a9028184c..8e94bf2db258c5 100644 --- a/src/mono/mono/utils/mono-threads-windows.c +++ b/src/mono/mono/utils/mono-threads-windows.c @@ -200,7 +200,7 @@ mono_threads_suspend_begin_async_suspend (MonoThreadInfo *info, gboolean interru /* suspended request, this will wait until thread is suspended and thread context has been collected */ /* and returned. */ CONTEXT context; - context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; + context.ContextFlags = CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_CONTROL; if (!GetThreadContext (handle, &context)) { result = ResumeThread (handle); g_assert (result == 1); @@ -289,19 +289,16 @@ mono_threads_suspend_begin_async_resume (MonoThreadInfo *info) info->async_target = NULL; info->user_data = NULL; - context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; + context.ContextFlags = CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_CONTROL; if (!GetThreadContext (handle, &context)) { THREADS_SUSPEND_DEBUG ("RESUME FAILED (GetThreadContext), id=%p, err=%u\n", GUINT_TO_POINTER (mono_thread_info_get_tid (info)), GetLastError ()); return FALSE; } - g_assert (context.ContextFlags & CONTEXT_INTEGER); - g_assert (context.ContextFlags & CONTEXT_CONTROL); - mono_monoctx_to_sigctx (&ctx, &context); - context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; + context.ContextFlags = CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_CONTROL; res = SetThreadContext (handle, &context); if (!res) { THREADS_SUSPEND_DEBUG ("RESUME FAILED (SetThreadContext), id=%p, err=%u\n", GUINT_TO_POINTER (mono_thread_info_get_tid (info)), GetLastError ()); diff --git a/src/mono/mono/utils/mono-threads.c b/src/mono/mono/utils/mono-threads.c index a4cec2c3be1a00..8fb5deefd8608a 100644 --- a/src/mono/mono/utils/mono-threads.c +++ b/src/mono/mono/utils/mono-threads.c @@ -442,6 +442,53 @@ thread_handle_destroy (gpointer data) g_free (thread_handle); } +static gboolean native_thread_id_main_thread_known; +static MonoNativeThreadId native_thread_id_main_thread; + +/** + * mono_native_thread_id_main_thread_known: + * + * If the main thread of the process has interacted with Mono (in the sense + * that it has a MonoThreadInfo associated with it), return \c TRUE and write + * its MonoNativeThreadId to \c main_thread_tid. + * + * Otherwise return \c FALSE. + */ +gboolean +mono_native_thread_id_main_thread_known (MonoNativeThreadId *main_thread_tid) +{ + if (!native_thread_id_main_thread_known) + return FALSE; + g_assert (main_thread_tid); + *main_thread_tid = native_thread_id_main_thread; + return TRUE; +} + +/* + * Saves the MonoNativeThreadId (on Linux pthread_t) of the current thread if + * it is the main thread. + * + * The main thread is (on Linux) the one whose OS thread id (on Linux pid_t) is + * equal to the process id. + * + * We have to do this at thread registration time because in embedding + * scenarios we can't count on the main thread to be the one that calls + * mono_jit_init, or other runtime initialization functions. + */ +static void +native_thread_set_main_thread (void) +{ + if (native_thread_id_main_thread_known) + return; +#if defined(__linux__) + if (mono_native_thread_os_id_get () == (guint64)getpid ()) { + native_thread_id_main_thread = mono_native_thread_id_get (); + mono_memory_barrier (); + native_thread_id_main_thread_known = TRUE; + } +#endif +} + static gboolean register_thread (MonoThreadInfo *info) { @@ -451,6 +498,7 @@ register_thread (MonoThreadInfo *info) info->small_id = mono_thread_info_register_small_id (); mono_thread_info_set_tid (info, mono_native_thread_id_get ()); + native_thread_set_main_thread (); info->handle = g_new0 (MonoThreadHandle, 1); mono_refcount_init (info->handle, thread_handle_destroy); diff --git a/src/mono/mono/utils/mono-threads.h b/src/mono/mono/utils/mono-threads.h index a949b42f659a82..c47a33d9774463 100644 --- a/src/mono/mono/utils/mono-threads.h +++ b/src/mono/mono/utils/mono-threads.h @@ -643,6 +643,9 @@ void mono_threads_coop_end_global_suspend (void); MONO_API MonoNativeThreadId mono_native_thread_id_get (void); +gboolean +mono_native_thread_id_main_thread_known (MonoNativeThreadId *main_thread_tid); + /* * This does _not_ return the same value as mono_native_thread_id_get, except on Windows. * On POSIX, mono_native_thread_id_get returns the value from pthread_self, which is then diff --git a/src/mono/mono/utils/mono-time.c b/src/mono/mono/utils/mono-time.c index 6874cc3781c2e1..25e22aea2a5d71 100644 --- a/src/mono/mono/utils/mono-time.c +++ b/src/mono/mono/utils/mono-time.c @@ -15,6 +15,12 @@ #include #endif +#ifdef HOST_DARWIN +#include +#include +#endif + + #include #include @@ -229,3 +235,94 @@ mono_100ns_datetime_from_timeval (struct timeval tv) #endif +#if defined(HOST_DARWIN) + +void +mono_clock_init (mono_clock_id_t *clk_id) +{ + kern_return_t ret; + + do { + ret = host_get_clock_service (mach_host_self (), SYSTEM_CLOCK, clk_id); + } while (ret == KERN_ABORTED); + + if (ret != KERN_SUCCESS) + g_error ("%s: host_get_clock_service () returned %d", __func__, ret); +} + +void +mono_clock_cleanup (mono_clock_id_t clk_id) +{ + kern_return_t ret; + + do { + ret = mach_port_deallocate (mach_task_self (), clk_id); + } while (ret == KERN_ABORTED); + + if (ret != KERN_SUCCESS) + g_error ("%s: mach_port_deallocate () returned %d", __func__, ret); +} + +guint64 +mono_clock_get_time_ns (mono_clock_id_t clk_id) +{ + kern_return_t ret; + mach_timespec_t mach_ts; + + do { + ret = clock_get_time (clk_id, &mach_ts); + } while (ret == KERN_ABORTED); + + if (ret != KERN_SUCCESS) + g_error ("%s: clock_get_time () returned %d", __func__, ret); + + return ((guint64) mach_ts.tv_sec * 1000000000) + (guint64) mach_ts.tv_nsec; +} + +#elif defined(__linux__) + +void +mono_clock_init (mono_clock_id_t *clk_id) +{ +} + +void +mono_clock_cleanup (mono_clock_id_t clk_id) +{ +} + +guint64 +mono_clock_get_time_ns (mono_clock_id_t clk_id) +{ + struct timespec ts; + + if (clock_gettime (clk_id, &ts) == -1) + g_error ("%s: clock_gettime () returned -1, errno = %d", __func__, errno); + + return ((guint64) ts.tv_sec * 1000000000) + (guint64) ts.tv_nsec; +} + +#else + +void +mono_clock_init (mono_clock_id_t *clk_id) +{ + // TODO: need to implement this function for PC + g_assert_not_reached (); +} + +void +mono_clock_cleanup (mono_clock_id_t clk_id) +{ + // TODO: need to implement this function for PC + g_assert_not_reached (); +} + +guint64 +mono_clock_get_time_ns (mono_clock_id_t clk_id) +{ + // TODO: need to implement time stamp function for PC + g_assert_not_reached (); +} + +#endif diff --git a/src/mono/mono/utils/mono-time.h b/src/mono/mono/utils/mono-time.h index 3f0634a544f208..9455ce77e4ed26 100644 --- a/src/mono/mono/utils/mono-time.h +++ b/src/mono/mono/utils/mono-time.h @@ -29,6 +29,20 @@ gint64 mono_100ns_datetime (void); gint64 mono_100ns_datetime_from_timeval (struct timeval tv); #endif +#if defined(HOST_DARWIN) +#include +typedef clock_serv_t mono_clock_id_t; +#elif defined(__linux__) +#include +typedef clockid_t mono_clock_id_t; +#else +typedef void *mono_clock_id_t; +#endif + +void mono_clock_init (mono_clock_id_t *clk_id); +void mono_clock_cleanup (mono_clock_id_t clk_id); +guint64 mono_clock_get_time_ns (mono_clock_id_t clk_id); + /* Stopwatch class for internal runtime use */ typedef struct { gint64 start, stop; diff --git a/src/mono/mono/utils/win64.asm b/src/mono/mono/utils/win64.asm index 7f23a04ffe8077..669e96a9beb8d1 100644 --- a/src/mono/mono/utils/win64.asm +++ b/src/mono/mono/utils/win64.asm @@ -36,6 +36,23 @@ mono_context_get_current PROC mov rax, qword ptr [rsp] mov [rcx + 80h], rax + movaps xmmword ptr [rcx + 90h], xmm0 + movaps xmmword ptr [rcx + 0A0h], xmm1 + movaps xmmword ptr [rcx + 0B0h], xmm2 + movaps xmmword ptr [rcx + 0C0h], xmm3 + movaps xmmword ptr [rcx + 0D0h], xmm4 + movaps xmmword ptr [rcx + 0E0h], xmm5 + movaps xmmword ptr [rcx + 0F0h], xmm6 + movaps xmmword ptr [rcx + 100h], xmm7 + movaps xmmword ptr [rcx + 110h], xmm8 + movaps xmmword ptr [rcx + 120h], xmm9 + movaps xmmword ptr [rcx + 130h], xmm10 + movaps xmmword ptr [rcx + 140h], xmm11 + movaps xmmword ptr [rcx + 150h], xmm12 + movaps xmmword ptr [rcx + 160h], xmm13 + movaps xmmword ptr [rcx + 170h], xmm14 + movaps xmmword ptr [rcx + 180h], xmm15 + ret mono_context_get_current endP diff --git a/src/mono/msbuild/Directory.Build.props b/src/mono/msbuild/Directory.Build.props new file mode 100644 index 00000000000000..c3f2519a25b0c0 --- /dev/null +++ b/src/mono/msbuild/Directory.Build.props @@ -0,0 +1,9 @@ + + + + + $(NetCoreAppCurrent) + $([MSBuild]::NormalizeDirectory('$(BaseOutputPath)', '$(TargetFramework)-$(MonoConfiguration)')) + enable + + diff --git a/src/mono/msvc/build-init.vcxproj b/src/mono/msvc/build-init.vcxproj index 8d15e191ac40d7..8b36028ea476c9 100644 --- a/src/mono/msvc/build-init.vcxproj +++ b/src/mono/msvc/build-init.vcxproj @@ -142,6 +142,7 @@ <_EnableDefines Condition="'$(MONO_ENABLE_LLVM)' == 'true'">$(_EnableDefines);ENABLE_LLVM;ENABLE_LLVM_RUNTIME <_EnableDefines Condition="'$(MONO_ENABLE_NETCORE)' == 'true'">$(_EnableDefines);ENABLE_NETCORE + <_EnableDefines Condition="'$(MONO_ENABLE_PERFTRACING)' == 'true'">$(_EnableDefines);ENABLE_PERFTRACING <_HaveDefines Condition="'$(MONO_ENABLE_BTLS)' == 'true'">$(_HaveDefines);HAVE_BTLS <_EnableDefines>$(_EnableDefines.Trim(';')) <_HaveDefines>$(_HaveDefines.Trim(';')) diff --git a/src/mono/msvc/libeventpipe.targets b/src/mono/msvc/libeventpipe.targets new file mode 100644 index 00000000000000..9758f292b376c7 --- /dev/null +++ b/src/mono/msvc/libeventpipe.targets @@ -0,0 +1,149 @@ + + + + false + true + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + $(ExcludeEventPipeFromBuild) + CompileAsC + + + + diff --git a/src/mono/msvc/libeventpipe.targets.filters b/src/mono/msvc/libeventpipe.targets.filters new file mode 100644 index 00000000000000..1bb9dcffc7bc35 --- /dev/null +++ b/src/mono/msvc/libeventpipe.targets.filters @@ -0,0 +1,172 @@ + + + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + + + {D6D64FF2-7951-44D8-B965-4593893CEF35} + + + {B372B1CF-F13A-43B8-97E0-DF7A9563D4AE} + + + diff --git a/src/mono/msvc/libmono-dynamic.vcxproj b/src/mono/msvc/libmono-dynamic.vcxproj index 3b1fab1c678a23..cd120b7cfb16fe 100644 --- a/src/mono/msvc/libmono-dynamic.vcxproj +++ b/src/mono/msvc/libmono-dynamic.vcxproj @@ -94,10 +94,9 @@ - /D /NODEFAULTLIB:LIBCD" " %(AdditionalOptions) Disabled - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);%(AdditionalIncludeDirectories) - WIN32;WIN32_LEAN_AND_MEAN;$(GC_DEFINES);MONO_DLL_EXPORT;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);_DEBUG;%(PreprocessorDefinitions) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) + WIN32;WIN32_LEAN_AND_MEAN;$(GC_DEFINES);MONO_DLL_EXPORT;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);$(SHIM_GLOBALIZATION_DEFINES);_DEBUG;%(PreprocessorDefinitions) 4996;4018;4244;%(DisableSpecificWarnings) Level3 @@ -121,10 +120,9 @@ X64 - /D /NODEFAULTLIB:LIBCD" " %(AdditionalOptions) Disabled - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);%(AdditionalIncludeDirectories) - WIN32;WIN32_LEAN_AND_MEAN;$(GC_DEFINES);MONO_DLL_EXPORT;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);WIN64;_DEBUG;%(PreprocessorDefinitions) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) + WIN32;WIN32_LEAN_AND_MEAN;$(GC_DEFINES);MONO_DLL_EXPORT;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);$(SHIM_GLOBALIZATION_DEFINES);WIN64;_DEBUG;%(PreprocessorDefinitions) 4996;4018;4244;%(DisableSpecificWarnings) Level3 @@ -145,10 +143,9 @@ - /D /NODEFAULTLIB:LIBCD" " %(AdditionalOptions) true - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);%(AdditionalIncludeDirectories) - WIN32;WIN32_LEAN_AND_MEAN;$(GC_DEFINES);MONO_DLL_EXPORT;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);NDEBUG;%(PreprocessorDefinitions) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) + WIN32;WIN32_LEAN_AND_MEAN;$(GC_DEFINES);MONO_DLL_EXPORT;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);$(SHIM_GLOBALIZATION_DEFINES);NDEBUG;%(PreprocessorDefinitions) true Level3 true @@ -174,10 +171,9 @@ X64 - /D /NODEFAULTLIB:LIBCD" " %(AdditionalOptions) true - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);%(AdditionalIncludeDirectories) - WIN32;WIN32_LEAN_AND_MEAN;$(GC_DEFINES);MONO_DLL_EXPORT;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);WIN64;NDEBUG;%(PreprocessorDefinitions) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) + WIN32;WIN32_LEAN_AND_MEAN;$(GC_DEFINES);MONO_DLL_EXPORT;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);$(SHIM_GLOBALIZATION_DEFINES);WIN64;NDEBUG;%(PreprocessorDefinitions) true Level3 true diff --git a/src/mono/msvc/libmonoruntime-common.targets b/src/mono/msvc/libmonoruntime-common.targets index 3e6f62e64d1558..316efc8a4fc23a 100644 --- a/src/mono/msvc/libmonoruntime-common.targets +++ b/src/mono/msvc/libmonoruntime-common.targets @@ -36,6 +36,7 @@ + diff --git a/src/mono/msvc/libmonoruntime-common.targets.filters b/src/mono/msvc/libmonoruntime-common.targets.filters index d614b6bcc49f7e..fb4a4e3c840604 100644 --- a/src/mono/msvc/libmonoruntime-common.targets.filters +++ b/src/mono/msvc/libmonoruntime-common.targets.filters @@ -97,6 +97,9 @@ Source Files$(MonoRuntimeFilterSubFolder)\common + + Source Files$(MonoRuntimeFilterSubFolder)\common + Source Files$(MonoRuntimeFilterSubFolder)\common diff --git a/src/mono/msvc/libmonoruntime.targets b/src/mono/msvc/libmonoruntime.targets index ba371e200fef98..ef506c56f4555c 100644 --- a/src/mono/msvc/libmonoruntime.targets +++ b/src/mono/msvc/libmonoruntime.targets @@ -1,6 +1,8 @@ + + diff --git a/src/mono/msvc/libmonoruntime.targets.filters b/src/mono/msvc/libmonoruntime.targets.filters index 870a2b19f6e217..6add73fc2df6d5 100644 --- a/src/mono/msvc/libmonoruntime.targets.filters +++ b/src/mono/msvc/libmonoruntime.targets.filters @@ -1,6 +1,8 @@  + + diff --git a/src/mono/msvc/libmonoruntime.vcxproj b/src/mono/msvc/libmonoruntime.vcxproj index 4c009edd823914..2541712d4817e7 100644 --- a/src/mono/msvc/libmonoruntime.vcxproj +++ b/src/mono/msvc/libmonoruntime.vcxproj @@ -97,8 +97,8 @@ Level3 Disabled - WIN32;WIN32_LEAN_AND_MEAN;_LIB;$(GC_DEFINES);_DEBUG;%(PreprocessorDefinitions) - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);%(AdditionalIncludeDirectories) + WIN32;WIN32_LEAN_AND_MEAN;_LIB;$(GC_DEFINES);$(SHIM_GLOBALIZATION_DEFINES);_DEBUG;%(PreprocessorDefinitions) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) $(IntDir)$(TargetName).pdb ProgramDatabase @@ -111,8 +111,8 @@ Level3 Disabled - WIN32;WIN32_LEAN_AND_MEAN;_LIB;$(GC_DEFINES);WIN64;_DEBUG;%(PreprocessorDefinitions) - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);%(AdditionalIncludeDirectories) + WIN32;WIN32_LEAN_AND_MEAN;_LIB;$(GC_DEFINES);$(SHIM_GLOBALIZATION_DEFINES);WIN64;_DEBUG;%(PreprocessorDefinitions) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) $(IntDir)$(TargetName).pdb ProgramDatabase @@ -125,8 +125,8 @@ Level3 true - WIN32;WIN32_LEAN_AND_MEAN;_LIB;$(GC_DEFINES);NDEBUG;%(PreprocessorDefinitions) - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);%(AdditionalIncludeDirectories) + WIN32;WIN32_LEAN_AND_MEAN;_LIB;$(GC_DEFINES);$(SHIM_GLOBALIZATION_DEFINES);NDEBUG;%(PreprocessorDefinitions) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) $(IntDir)$(TargetName).pdb true @@ -141,8 +141,8 @@ Level3 true - WIN32;WIN32_LEAN_AND_MEAN;_LIB;$(GC_DEFINES);WIN64;NDEBUG;%(PreprocessorDefinitions) - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);%(AdditionalIncludeDirectories) + WIN32;WIN32_LEAN_AND_MEAN;_LIB;$(GC_DEFINES);$(SHIM_GLOBALIZATION_DEFINES);WIN64;NDEBUG;%(PreprocessorDefinitions) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) $(IntDir)$(TargetName).pdb true diff --git a/src/mono/msvc/mono.props b/src/mono/msvc/mono.props index e71f2cc330d6db..dbfed0b19f4a29 100644 --- a/src/mono/msvc/mono.props +++ b/src/mono/msvc/mono.props @@ -28,8 +28,11 @@ false + false true - false + + false + true .. @@ -45,6 +48,9 @@ $(MONO_LIBGC_INCLUDE_DIR) $(MONO_EGLIB_SOURCE_DIR) 610 + $(top_srcdir)/../libraries/Native/Unix/System.Globalization.Native + $(top_srcdir)/../libraries/Native/Unix/Common + $(SHIM_GLOBALIZATION_COMMON);$(SHIM_GLOBALIZATION) $(MONO_DIR)/external/llvm-project/llvm/include @@ -58,6 +64,7 @@ HAVE_SGEN_GC;HAVE_MOVING_COLLECTOR;HAVE_WRITE_BARRIERS;HAVE_CONC_GC_AS_DEFAULT $(SGEN_DEFINES) + TARGET_WINDOWS;PALEXPORT=extern "C" __declspec(dllexport) libgcmonosgen.lib -sgen $(MONO_BUILD_DIR_PREFIX)sgen/ @@ -120,6 +127,9 @@ $(MONO_ENABLE_NETCORE) + + $(MONO_ENABLE_PERFTRACING) + HAVE_CONFIG_H diff --git a/src/mono/msvc/mono.winconfig.targets b/src/mono/msvc/mono.winconfig.targets index d8e39ca7ad2dc7..62e92339ee2660 100644 --- a/src/mono/msvc/mono.winconfig.targets +++ b/src/mono/msvc/mono.winconfig.targets @@ -124,7 +124,8 @@ "ENABLE_LLVM_RUNTIME", "ENABLE_HYBRID_SUSPEND", "ENABLE_COOP_SUSPEND", - "ENABLE_NETCORE" }; + "ENABLE_NETCORE", + "ENABLE_PERFTRACING" }; var enableFeatures = GetConfigFeatures(path, ".*#define.*ENABLE_.*1"); if (enableDefines != null) diff --git a/src/mono/msvc/shimglobalization.targets b/src/mono/msvc/shimglobalization.targets new file mode 100644 index 00000000000000..19bc337ba6c287 --- /dev/null +++ b/src/mono/msvc/shimglobalization.targets @@ -0,0 +1,51 @@ + + + + + CompileAsCpp + + + CompileAsCpp + + + CompileAsCpp + + + CompileAsCpp + + + CompileAsCpp + + + CompileAsCpp + + + CompileAsCpp + + + CompileAsCpp + + + CompileAsCpp + + + CompileAsCpp + + + + + + + + + + + + + + + + + + + diff --git a/src/mono/msvc/shimglobalization.targets.filters b/src/mono/msvc/shimglobalization.targets.filters new file mode 100644 index 00000000000000..106d7b8717996c --- /dev/null +++ b/src/mono/msvc/shimglobalization.targets.filters @@ -0,0 +1,87 @@ + + + + + Source Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Source Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Source Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Source Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Source Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Source Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Source Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Source Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Source Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Source Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + Header Files$(MonoRuntimeFilterSubFolder)\shimglobalization + + + + + + + diff --git a/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj index 48967bb3cbc8c8..97710f8acf8029 100644 --- a/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -1,4 +1,4 @@ - + @@ -186,7 +186,6 @@ - @@ -273,7 +272,6 @@ - @@ -282,7 +280,6 @@ - diff --git a/src/mono/netcore/System.Private.CoreLib/src/LinkerDescriptor/System.Private.CoreLib.xml b/src/mono/netcore/System.Private.CoreLib/src/LinkerDescriptor/System.Private.CoreLib.xml index c5d0285668d545..3489337befd197 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/LinkerDescriptor/System.Private.CoreLib.xml +++ b/src/mono/netcore/System.Private.CoreLib/src/LinkerDescriptor/System.Private.CoreLib.xml @@ -14,7 +14,8 @@ - + + @@ -254,6 +255,8 @@ + + @@ -299,6 +302,8 @@ + + @@ -381,6 +386,9 @@ + + + @@ -657,6 +665,8 @@ + + @@ -811,5 +821,9 @@ + + + + diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Array.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Array.Mono.cs index 908a3baa8e7615..e04efea520a939 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Array.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Array.Mono.cs @@ -9,13 +9,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System { public partial class Array @@ -61,7 +54,7 @@ public static unsafe void Clear(Array array, int index, int length) int lowerBound = array.GetLowerBound(0); int elementSize = array.GetElementSize(); - nuint numComponents = (nuint)Unsafe.As(array).Count; + nuint numComponents = (nuint)(nint)Unsafe.As(array).Count; int offset = index - lowerBound; diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Attribute.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Attribute.Mono.cs index fc6c82a6dcc5fa..c362e7792c1f63 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Attribute.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Attribute.Mono.cs @@ -12,7 +12,8 @@ public partial class Attribute { if (attributeType == null) throw new ArgumentNullException(nameof(attributeType)); - if (!attributeType.IsSubclassOf(typeof(Attribute)) && attributeType != typeof(Attribute) && attributeType != typeof(CustomAttribute)) + if (!attributeType.IsSubclassOf(typeof(Attribute)) && !attributeType.IsInterface + && attributeType != typeof(Attribute) && attributeType != typeof(CustomAttribute)) throw new ArgumentException(SR.Argument_MustHaveAttributeBaseClass + " " + attributeType.FullName); object[] attrs = CustomAttribute.GetCustomAttributes(element, attributeType, inherit); diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Buffer.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Buffer.Mono.cs index b4772965b6ad33..6f04b9742a55a2 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Buffer.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Buffer.Mono.cs @@ -4,13 +4,6 @@ using System.Runtime.CompilerServices; -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if TARGET_64BIT -using nuint = System.UInt64; -#else -using nuint = System.UInt32; -#endif - namespace System { public partial class Buffer diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/GC.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/GC.Mono.cs index 945356c17dec59..b7ac9cfaf4cdfb 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/GC.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/GC.Mono.cs @@ -113,7 +113,7 @@ public static int GetGeneration(WeakReference wo) { object? obj = wo.Target; if (obj == null) - throw new ArgumentException(); + throw new ArgumentException(null, nameof(wo)); return GetGeneration(obj); } diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Mono.cs deleted file mode 100644 index 911499ea842e37..00000000000000 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Mono.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace System.Globalization -{ - internal static partial class GlobalizationMode - { - internal static bool Invariant { get; } = GetGlobalizationInvariantMode(); - - private static bool GetInvariantSwitchValue() - { - string? val = Environment.GetEnvironmentVariable("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT"); - if (val != null) - return bool.IsTrueStringIgnoreCase(val) || val.Equals("1"); - return false; - } - } -} diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.Mono.cs deleted file mode 100644 index c31e58411a852a..00000000000000 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.Mono.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Runtime.CompilerServices; - -namespace System.Globalization -{ - internal partial class GlobalizationMode - { - private static bool GetGlobalizationInvariantMode() - { - bool invariantEnabled = GetInvariantSwitchValue(); - if (invariantEnabled) - return true; - - LoadICU(); - return false; - } - - // Keep this in a separate method to avoid loading the native lib in invariant mode - [MethodImplAttribute(MethodImplOptions.NoInlining)] - private static void LoadICU() - { - int res = Interop.Globalization.LoadICU(); - if (res == 0) - { - string message = "Couldn't find a valid ICU package installed on the system. " + - "Set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support."; - Environment.FailFast(message); - } - } - } -} diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Windows.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Windows.Mono.cs deleted file mode 100644 index 326723995fed63..00000000000000 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Windows.Mono.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace System.Globalization -{ - internal partial class GlobalizationMode - { - private static bool GetGlobalizationInvariantMode() - { - return GetInvariantSwitchValue(); - } - } -} \ No newline at end of file diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/CustomAttribute.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/CustomAttribute.cs index e21888056a3fa4..76c1e4e8b529cc 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/CustomAttribute.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/CustomAttribute.cs @@ -551,7 +551,7 @@ internal static bool IsDefined(ICustomAttributeProvider obj, Type attributeType, { if (attributeType == null) throw new ArgumentNullException(nameof(attributeType)); - if (!attributeType.IsSubclassOf(typeof(Attribute)) && attributeType != typeof(Attribute)) + if (!attributeType.IsSubclassOf(typeof(Attribute)) && !attributeType.IsInterface && attributeType != typeof(Attribute)) throw new ArgumentException(SR.Argument_MustHaveAttributeBaseClass + " " + attributeType.FullName); AttributeUsageAttribute? usage = null; diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.Mono.cs index 8f40153db0f3dc..53faf4ad11b766 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.Mono.cs @@ -325,7 +325,7 @@ public override Module Module public override string ToString() { - return "ConstructorBuilder ['" + type.Name + "']"; + return "Name: " + Name; } internal void fixup() diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/EnumBuilder.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/EnumBuilder.Mono.cs index ca53d05ed0e625..e1ae8c2983eb8a 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/EnumBuilder.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/EnumBuilder.Mono.cs @@ -452,6 +452,8 @@ public override bool IsAssignableFrom([NotNullWhen(true)] TypeInfo? typeInfo) } public override bool IsTypeDefinition => true; + + public override bool IsByRefLike => false; } } #endif diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/EventOnTypeBuilderInst.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/EventOnTypeBuilderInst.cs index f2f088b7d234bd..d7a71d3ed754dc 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/EventOnTypeBuilderInst.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/EventOnTypeBuilderInst.cs @@ -28,7 +28,7 @@ // #if MONO_FEATURE_SRE -using System.Collections; +using System.Collections.Generic; using System.Runtime.InteropServices; namespace System.Reflection.Emit @@ -90,15 +90,13 @@ public override MethodInfo[] GetOtherMethods(bool nonPublic) if (other == null) return Array.Empty(); - ArrayList ar = new ArrayList(); + List res = new List(); foreach (MethodInfo method in other) { if (nonPublic || method.IsPublic) - ar.Add(TypeBuilder.GetMethod(instantiation, method)); + res.Add(TypeBuilder.GetMethod(instantiation, method)); } - MethodInfo[] res = new MethodInfo[ar.Count]; - ar.CopyTo(res, 0); - return res; + return res.ToArray(); } public override Type DeclaringType diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs index d9cb98d453e0a1..04490cad975afa 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/GenericTypeParameterBuilder.cs @@ -493,6 +493,8 @@ internal override bool IsUserType return false; } } + + public override bool IsByRefLike => false; } } #endif diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.Mono.cs index 0c9f12ad193aa6..5f6e79e580c332 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.Mono.cs @@ -154,7 +154,7 @@ private FieldBuilder DefineDataImpl(string name, int size, FieldAttributes attri { if (name == null) throw new ArgumentNullException(nameof(name)); - if (name == string.Empty) + if (name.Length == 0) throw new ArgumentException("name cannot be empty", nameof(name)); if (global_type_created != null) throw new InvalidOperationException("global fields already created"); diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.Mono.cs index bccfb62b5d72e3..4ee8768fcb03a8 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.Mono.cs @@ -32,7 +32,7 @@ // #if MONO_FEATURE_SRE -using System.Collections; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; @@ -261,7 +261,7 @@ public void AddInterfaceImplementation(Type interfaceType) if (interfaceType == null) throw new ArgumentNullException(nameof(interfaceType)); if (interfaceType.IsByRef) - throw new ArgumentException(nameof(interfaceType)); + throw new ArgumentException(SR.Argument_CannotGetTypeTokenForByRef); check_not_created(); if (interfaces != null) @@ -479,7 +479,7 @@ public ConstructorBuilder DefineDefaultConstructor(MethodAttributes attributes) if (IsInterface) throw new InvalidOperationException(); if ((attributes & (MethodAttributes.Static | MethodAttributes.Virtual)) > 0) - throw new ArgumentException(nameof(attributes)); + throw new ArgumentException(SR.Arg_NoStaticVirtual); if (parent != null) parent_type = parent; @@ -974,7 +974,7 @@ internal ConstructorInfo[] GetConstructorsInternal(BindingFlags bindingAttr) { if (ctors == null) return Array.Empty(); - ArrayList l = new ArrayList(); + List result = new List(); bool match; MethodAttributes mattrs; @@ -1007,11 +1007,9 @@ internal ConstructorInfo[] GetConstructorsInternal(BindingFlags bindingAttr) } if (!match) continue; - l.Add(c); + result.Add(c); } - ConstructorInfo[] result = new ConstructorInfo[l.Count]; - l.CopyTo(result); - return result; + return result.ToArray(); } public override Type GetElementType() @@ -1096,7 +1094,7 @@ private MethodInfo[] GetMethodsByName(string? name, BindingFlags bindingAttr, bo if (((bindingAttr & BindingFlags.DeclaredOnly) == 0) && (parent != null)) { MethodInfo[] parent_methods = parent.GetMethods(bindingAttr); - ArrayList parent_candidates = new ArrayList(parent_methods.Length); + List parent_candidates = new List(parent_methods.Length); bool flatten = (bindingAttr & BindingFlags.FlattenHierarchy) != 0; @@ -1139,7 +1137,7 @@ private MethodInfo[] GetMethodsByName(string? name, BindingFlags bindingAttr, bo if (candidates == null) return Array.Empty(); - ArrayList l = new ArrayList(); + List result = new List(); foreach (MethodInfo c in candidates) { @@ -1177,12 +1175,9 @@ private MethodInfo[] GetMethodsByName(string? name, BindingFlags bindingAttr, bo } if (!match) continue; - l.Add(c); + result.Add(c); } - - MethodInfo[] result = new MethodInfo[l.Count]; - l.CopyTo(result); - return result; + return result.ToArray(); } public override MethodInfo[] GetMethods(BindingFlags bindingAttr) @@ -1239,7 +1234,7 @@ public override Type[] GetNestedTypes(BindingFlags bindingAttr) throw new NotSupportedException(); bool match; - ArrayList result = new ArrayList(); + List result = new List(); if (subtypes == null) return EmptyTypes; @@ -1260,9 +1255,7 @@ public override Type[] GetNestedTypes(BindingFlags bindingAttr) continue; result.Add(t); } - Type[] r = new Type[result.Count]; - result.CopyTo(r); - return r; + return result.ToArray(); } public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) @@ -1522,7 +1515,7 @@ public EventBuilder DefineEvent(string name, EventAttributes attributes, Type ev { check_name(nameof(name), name); if (eventtype == null) - throw new ArgumentNullException("type"); + throw new ArgumentNullException(nameof(eventtype)); check_not_created(); if (eventtype.IsByRef) throw new ArgumentException(SR.Argument_CannotGetTypeTokenForByRef); @@ -1604,7 +1597,7 @@ public void SetParent(Type? parent) else { if (parent.IsInterface) - throw new ArgumentException(nameof(parent)); + throw new ArgumentException(SR.Argument_CannotSetParentToInterface); this.parent = parent; } this.parent = ResolveUserType(this.parent); @@ -1885,7 +1878,7 @@ public static FieldInfo GetField(Type type, FieldInfo field) throw new ArgumentException("The specified field must be declared on a generic type definition.", nameof(field)); if (field.DeclaringType != type.GetGenericTypeDefinition()) - throw new ArgumentException("field declaring type is not the generic type definition of type", "method"); + throw new ArgumentException("field declaring type is not the generic type definition of type", nameof(field)); FieldInfo res = type.GetField(field); if (res == null) @@ -2042,6 +2035,8 @@ private static void throw_argument_ConstantDoesntMatch() } public override bool IsTypeDefinition => true; + + public override bool IsByRefLike => false; } } #endif diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilderInstantiation.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilderInstantiation.cs index 44978aa30fbede..60335b4aff6b5c 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilderInstantiation.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilderInstantiation.cs @@ -32,7 +32,7 @@ // #if MONO_FEATURE_SRE -using System.Collections; +using System.Collections.Generic; using System.Globalization; using System.Text; using System.Runtime.InteropServices; @@ -53,7 +53,9 @@ internal sealed class TypeBuilderInstantiation : #pragma warning restore 649 #endregion - private Hashtable? fields, ctors, methods; + private Dictionary? fields; + private Dictionary? ctors; + private Dictionary? methods; internal TypeBuilderInstantiation() { @@ -167,28 +169,28 @@ protected override bool IsValueTypeImpl() internal override MethodInfo GetMethod(MethodInfo fromNoninstanciated) { if (methods == null) - methods = new Hashtable(); + methods = new Dictionary(); if (!methods.ContainsKey(fromNoninstanciated)) methods[fromNoninstanciated] = new MethodOnTypeBuilderInst(this, fromNoninstanciated); - return (MethodInfo)methods[fromNoninstanciated]!; + return methods[fromNoninstanciated]!; } internal override ConstructorInfo GetConstructor(ConstructorInfo fromNoninstanciated) { if (ctors == null) - ctors = new Hashtable(); + ctors = new Dictionary(); if (!ctors.ContainsKey(fromNoninstanciated)) ctors[fromNoninstanciated] = new ConstructorOnTypeBuilderInst(this, fromNoninstanciated); - return (ConstructorInfo)ctors[fromNoninstanciated]!; + return ctors[fromNoninstanciated]!; } internal override FieldInfo GetField(FieldInfo fromNoninstanciated) { if (fields == null) - fields = new Hashtable(); + fields = new Dictionary(); if (!fields.ContainsKey(fromNoninstanciated)) fields[fromNoninstanciated] = new FieldOnTypeBuilderInst(this, fromNoninstanciated); - return (FieldInfo)fields[fromNoninstanciated]!; + return fields[fromNoninstanciated]!; } public override MethodInfo[] GetMethods(BindingFlags bf) diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs index 5d110fefdaebb5..d4efac98e0a4e8 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/RuntimeModule.cs @@ -197,7 +197,7 @@ Type GetType(string className, bool throwOnError, bool ignoreCase) { if (className == null) throw new ArgumentNullException(nameof(className)); - if (className == string.Empty) + if (className.Length == 0) throw new ArgumentException("Type name can't be empty"); return assembly.InternalGetType(this, className, throwOnError, ignoreCase); } diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs index 5dcda6d90fed66..7c80ba8fb5c6b4 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.Mono.cs @@ -8,8 +8,10 @@ public partial class RuntimeHelpers { public static void InitializeArray(Array array, RuntimeFieldHandle fldHandle) { - if (array == null || fldHandle.Value == IntPtr.Zero) - throw new ArgumentNullException(); + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (fldHandle.Value == IntPtr.Zero) + throw new ArgumentNullException(nameof(fldHandle)); InitializeArray(array, fldHandle.Value); } diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs index 6f16baaa8e8365..185ddbff42972b 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs @@ -4,6 +4,8 @@ using System.Reflection; using System.Runtime.CompilerServices; +using System.Threading; +using System.Collections.Generic; namespace System.Runtime.InteropServices { @@ -354,6 +356,85 @@ public static unsafe IntPtr StringToBSTR(string? s) return BufferToBSTR(fixed_s, s.Length); } + private sealed class MarshalerInstanceKeyComparer : IEqualityComparer<(Type, string)> + { + public bool Equals((Type, string) lhs, (Type, string) rhs) + { + return lhs.CompareTo(rhs) == 0; + } + + public int GetHashCode((Type, string) key) + { + return key.GetHashCode(); + } + } + + private static Dictionary<(Type, string), ICustomMarshaler>? MarshalerInstanceCache; + + internal static ICustomMarshaler? GetCustomMarshalerInstance(Type type, string cookie) + { + var key = (type, cookie); + + LazyInitializer.EnsureInitialized( + ref MarshalerInstanceCache, + () => new Dictionary<(Type, string), ICustomMarshaler>(new MarshalerInstanceKeyComparer()) + ); + + ICustomMarshaler? result; + bool gotExistingInstance; + lock (MarshalerInstanceCache) + gotExistingInstance = MarshalerInstanceCache.TryGetValue(key, out result); + + if (!gotExistingInstance) + { + RuntimeMethodInfo? getInstanceMethod; + try + { + getInstanceMethod = (RuntimeMethodInfo?)type.GetMethod( + "GetInstance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod, + null, new Type[] { typeof(string) }, null + ); + } + catch (AmbiguousMatchException) + { + throw new ApplicationException($"Custom marshaler '{type.FullName}' implements multiple static GetInstance methods that take a single string parameter."); + } + + if ((getInstanceMethod == null) || + (getInstanceMethod.ReturnType != typeof(ICustomMarshaler))) + { + throw new ApplicationException($"Custom marshaler '{type.FullName}' does not implement a static GetInstance method that takes a single string parameter and returns an ICustomMarshaler."); + } + + Exception? exc; + try + { + result = (ICustomMarshaler?)getInstanceMethod.InternalInvoke(null, new object[] { cookie }, out exc); + } + catch (Exception e) + { + // FIXME: mscorlib's legacyUnhandledExceptionPolicy is apparently 1, + // so exceptions are thrown instead of being passed through the outparam + exc = e; + result = null; + } + + if (exc != null) + { + var edi = System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(exc); + edi.Throw(); + } + + if (result == null) + throw new ApplicationException($"A call to GetInstance() for custom marshaler '{type.FullName}' returned null, which is not allowed."); + + lock (MarshalerInstanceCache) + MarshalerInstanceCache[key] = result; + } + + return result; + } + #region PlatformNotSupported public static int GetExceptionCode() diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.Mono.cs index 05e3f76354345e..4a35247b1c1373 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.Mono.cs @@ -7,9 +7,11 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; +using Internal.Runtime.CompilerServices; namespace System.Runtime.Loader { + [StructLayout(LayoutKind.Sequential)] public partial class AssemblyLoadContext { internal IntPtr NativeALC @@ -116,13 +118,25 @@ public void StartProfileOptimization(string? profile) // success. private static Assembly? MonoResolveUsingResolvingEvent(IntPtr gchALC, string assemblyName) { - return ResolveUsingResolvingEvent(gchALC, new AssemblyName(assemblyName)); + AssemblyLoadContext context; + // This check exists because the function can be called early in startup, before the default ALC is initialized + if (gchALC == IntPtr.Zero) + context = Default; + else + context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchALC).Target)!; + return context.ResolveUsingEvent(new AssemblyName(assemblyName)); } // Invoked by Mono to resolve requests to load satellite assemblies. private static Assembly? MonoResolveUsingResolveSatelliteAssembly(IntPtr gchALC, string assemblyName) { - return ResolveSatelliteAssembly(gchALC, new AssemblyName(assemblyName)); + AssemblyLoadContext context; + // This check exists because the function can be called early in startup, before the default ALC is initialized + if (gchALC == IntPtr.Zero) + context = Default; + else + context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchALC).Target)!; + return context.ResolveSatelliteAssembly(new AssemblyName(assemblyName)); } private static AssemblyLoadContext GetAssemblyLoadContext(IntPtr gchManagedAssemblyLoadContext) @@ -148,15 +162,13 @@ private static void MonoResolveUnmanagedDllUsingEvent(string unmanagedDllName, A dll = context.GetResolvedUnmanagedDll(assembly, unmanagedDllName); } - #region Copied from AssemblyLoadContext.CoreCLR.cs, modified until our AssemblyBuilder implementation is functional private static RuntimeAssembly? GetRuntimeAssembly(Assembly? asm) { return asm == null ? null : asm is RuntimeAssembly rtAssembly ? rtAssembly : - //asm is System.Reflection.Emit.AssemblyBuilder ab ? ab.InternalAssembly : + asm is System.Reflection.Emit.AssemblyBuilder ab ? Unsafe.As(ab) : // Mono AssemblyBuilder is also a RuntimeAssembly, see AssemblyBuilder.Mono.cs null; } - #endregion } } diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeType.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeType.Mono.cs index 9628d4956bcf03..71ff174e23d246 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeType.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeType.Mono.cs @@ -873,7 +873,7 @@ public override MemberInfo[] GetMembers(BindingFlags bindingAttr) protected override PropertyInfo? GetPropertyImpl( string name, BindingFlags bindingAttr, Binder? binder, Type? returnType, Type[]? types, ParameterModifier[]? modifiers) { - if (name == null) throw new ArgumentNullException(); + if (name == null) throw new ArgumentNullException(nameof(name)); ListBuilder candidates = GetPropertyCandidates(name, bindingAttr, types, false); @@ -911,7 +911,7 @@ public override MemberInfo[] GetMembers(BindingFlags bindingAttr) public override EventInfo? GetEvent(string name, BindingFlags bindingAttr) { - if (name == null) throw new ArgumentNullException(); + if (name == null) throw new ArgumentNullException(nameof(name)); bool ignoreCase; MemberListType listType; @@ -978,7 +978,7 @@ public override MemberInfo[] GetMembers(BindingFlags bindingAttr) public override Type? GetInterface(string fullname, bool ignoreCase) { - if (fullname == null) throw new ArgumentNullException(); + if (fullname == null) throw new ArgumentNullException(nameof(fullname)); BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.NonPublic; @@ -1031,7 +1031,7 @@ public override MemberInfo[] GetMembers(BindingFlags bindingAttr) public override Type? GetNestedType(string fullname, BindingFlags bindingAttr) { - if (fullname == null) throw new ArgumentNullException(); + if (fullname == null) throw new ArgumentNullException(nameof(fullname)); bool ignoreCase; bindingAttr &= ~BindingFlags.Static; @@ -1059,7 +1059,7 @@ public override MemberInfo[] GetMembers(BindingFlags bindingAttr) public override MemberInfo[] GetMember(string name, MemberTypes type, BindingFlags bindingAttr) { - if (name == null) throw new ArgumentNullException(); + if (name == null) throw new ArgumentNullException(nameof(name)); ListBuilder methods = default; ListBuilder constructors = default; diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeTypeHandle.cs b/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeTypeHandle.cs index 7df75e09b91781..90a36a0230f5cc 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeTypeHandle.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeTypeHandle.cs @@ -289,7 +289,7 @@ internal static bool IsTypeDefinition(RuntimeType type) if (typeName == null) throw new ArgumentNullException(nameof(typeName)); - if (typeName == string.Empty) + if (typeName.Length == 0) if (throwOnError) throw new TypeLoadException("A null or zero length string does not represent a valid Type."); else diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Threading/ThreadPool.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Threading/ThreadPool.Mono.cs index 023574d2180021..ae757df4df4335 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Threading/ThreadPool.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Threading/ThreadPool.Mono.cs @@ -8,11 +8,7 @@ namespace System.Threading { public static partial class ThreadPool { - private static void EnsureInitialized() - { - ThreadPoolGlobals.threadPoolInitialized = true; - ThreadPoolGlobals.enableWorkerTracking = false; - } + private static bool GetEnableWorkerTracking() => false; internal static void ReportThreadStatus(bool isWorking) { @@ -46,4 +42,4 @@ public static bool BindHandle(SafeHandle osHandle) private static long PendingUnmanagedWorkItemCount => 0; } -} \ No newline at end of file +} diff --git a/src/mono/netcore/gen-xunit-runner/Program.cs b/src/mono/netcore/gen-xunit-runner/Program.cs index a73bbecdfd5287..1bd127cef1f115 100644 --- a/src/mono/netcore/gen-xunit-runner/Program.cs +++ b/src/mono/netcore/gen-xunit-runner/Program.cs @@ -283,7 +283,6 @@ static int Main (string[] args) args = args.Where (s => s != String.Empty).Concat (extra_args).ToArray (); // Despite a lot of effort, couldn't get dotnet to load these assemblies from the sdk dir, so copy them to our binary dir -// File.Copy ($"{sdkdir}/Microsoft.DotNet.PlatformAbstractions.dll", AppContext.BaseDirectory, true); File.Copy ($"{sdkdir}/TestUtilities.dll", AppContext.BaseDirectory, true); File.Copy ($"{sdkdir}/Microsoft.DotNet.XUnitExtensions.dll", AppContext.BaseDirectory, true); diff --git a/src/mono/netcore/sample/Android/Makefile b/src/mono/netcore/sample/Android/Makefile new file mode 100644 index 00000000000000..5ce28d98d9486b --- /dev/null +++ b/src/mono/netcore/sample/Android/Makefile @@ -0,0 +1,18 @@ +MONO_CONFIG=Release +MONO_ARCH=arm64 +DOTNET := ../../../../.././dotnet.sh + +all: runtimepack run + +appbuilder: + $(DOTNET) build -c Release ../../../../../tools-local/tasks/mobile.tasks/AndroidAppBuilder/AndroidAppBuilder.csproj + +runtimepack: + ../../../../.././build.sh Mono+Libs -os Android -arch $(MONO_ARCH) -c $(MONO_CONFIG) + +run: clean appbuilder + $(DOTNET) publish -c $(MONO_CONFIG) -r android-$(MONO_ARCH) \ + /p:Platform=$(MONO_ARCH) /p:DeployAndRun=true + +clean: + rm -rf bin diff --git a/src/mono/netcore/sample/Android/Program.cs b/src/mono/netcore/sample/Android/Program.cs new file mode 100644 index 00000000000000..4e61d6fc4b829e --- /dev/null +++ b/src/mono/netcore/sample/Android/Program.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +public static class Program +{ + public static int Main(string[] args) + { + Console.WriteLine("Hello, Android!"); // logcat + return 42; + } +} diff --git a/src/mono/netcore/sample/Android/Program.csproj b/src/mono/netcore/sample/Android/Program.csproj new file mode 100644 index 00000000000000..6f452e61dfeded --- /dev/null +++ b/src/mono/netcore/sample/Android/Program.csproj @@ -0,0 +1,70 @@ + + + Exe + bin + Portable + $(NetCoreAppCurrent) + $(ArtifactsBinDir)lib-runtime-packs\$(NetCoreAppCurrent)-Android-$(Configuration)-$(TargetArchitecture)\runtimes\android-$(TargetArchitecture) + $(ArtifactsBinDir)AndroidAppBuilder\$(Configuration)\$(NetCoreAppCurrent) + false + true + <_TrimmerDefaultAction>link + + + + + + + $(ArtifactsDir)bin\lib-runtime-packs\$(NetCoreAppCurrent)-Android-$(Configuration)-$(Platform) + + + + + + + + + + + arm64-v8a + armeabi-v7a + x86_64 + $(Platform) + $(MSBuildThisFileDirectory)$(PublishDir)\apk + False + True + $(ANDROID_SDK_ROOT)\platform-tools\adb + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mono/netcore/sample/iOS/.gitignore b/src/mono/netcore/sample/iOS/.gitignore deleted file mode 100644 index 8a7ad91c1a79c9..00000000000000 --- a/src/mono/netcore/sample/iOS/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -bin/ -xcode/ -*.o -*.dll \ No newline at end of file diff --git a/src/mono/netcore/sample/iOS/CMakeLists.txt b/src/mono/netcore/sample/iOS/CMakeLists.txt deleted file mode 100644 index 8821f84621e05f..00000000000000 --- a/src/mono/netcore/sample/iOS/CMakeLists.txt +++ /dev/null @@ -1,53 +0,0 @@ -cmake_minimum_required(VERSION 3.14.5) - -project(HelloiOS) - -file(GLOB DLLS *.dll) -file(GLOB DLLS_AOT *.dll.o) -file(GLOB DLLS_PDB *.pdb) - -set(APP_RESOURCES - ${DLLS} - ${DLLS_PDB} -) - -add_executable( - HelloiOS - main.m - runtime.h - runtime.m - ${APP_RESOURCES} -) - -if (MONO_ARCH STREQUAL arm64) - add_definitions(-DDEVICE) -endif() - -include_directories("../../../../../artifacts/bin/mono/iOS.${MONO_ARCH}.${MONO_CONFIG}/include/mono-2.0") - -set_target_properties(HelloiOS PROPERTIES - MACOSX_BUNDLE TRUE - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Plist.in - XCODE_ATTRIBUTE_ENABLE_BITCODE "NO" - XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING "NO" - RESOURCE "${APP_RESOURCES}" -) - -# FIXME: `XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING` should not be NO -# investigate why `PALEXPORT` doesn't preserve symbols - -target_link_libraries( - HelloiOS - "-framework Foundation" - "-framework Security" - "-framework UIKit" - "-framework GSS" - "-lz" - "-liconv" - "-force_load ../../../../../artifacts/bin/mono/iOS.${MONO_ARCH}.${MONO_CONFIG}/libmono.a" - "-force_load ../../../../../artifacts/bin/native/netcoreapp5.0-iOS-${MONO_CONFIG}-${MONO_ARCH}/libSystem.IO.Compression.Native.a" - "-force_load ../../../../../artifacts/bin/native/netcoreapp5.0-iOS-${MONO_CONFIG}-${MONO_ARCH}/libSystem.Native.a" - "-force_load ../../../../../artifacts/bin/native/netcoreapp5.0-iOS-${MONO_CONFIG}-${MONO_ARCH}/libSystem.Net.Security.Native.a" - "-force_load ../../../../../artifacts/bin/native/netcoreapp5.0-iOS-${MONO_CONFIG}-${MONO_ARCH}/libSystem.Security.Cryptography.Native.Apple.a" - ${DLLS_AOT} -) \ No newline at end of file diff --git a/src/mono/netcore/sample/iOS/Makefile b/src/mono/netcore/sample/iOS/Makefile index 91c98bcfa81618..36dec2bc18dabf 100644 --- a/src/mono/netcore/sample/iOS/Makefile +++ b/src/mono/netcore/sample/iOS/Makefile @@ -1,75 +1,21 @@ MONO_CONFIG=Debug +MONO_ARCH=x64 +DOTNET := ../../../../.././dotnet.sh +USE_LLVM=True -# change to x64 for simulator -MONO_ARCH=arm64 -ARTIFACTS_BIN=../../../../../artifacts/bin/ -ARTIFACTS_BCL=$(ARTIFACTS_BIN)runtime/netcoreapp5.0-iOS-$(MONO_CONFIG)-$(MONO_ARCH) -ARTIFACTS_MONO=$(ARTIFACTS_BIN)/mono/iOS.$(MONO_ARCH).$(MONO_CONFIG) +all: runtimepack run -DOTNET := $(shell cd ../../ && bash init-tools.sh | tail -1) -SYSROOT := $(shell xcrun --sdk iphoneos --show-sdk-path) +TOOLS_DIR=../../../../../tools-local/tasks/mobile.tasks +appbuilder: + $(DOTNET) build -c Release $(TOOLS_DIR)/AotCompilerTask/MonoAOTCompiler.csproj + $(DOTNET) build -c Release $(TOOLS_DIR)/AppleAppBuilder/AppleAppBuilder.csproj -BCL_LIBS = \ - System.Runtime.dll \ - System.Runtime.Extensions.dll \ - System.Collections.dll \ - System.Core.dll \ - System.Threading.dll \ - System.Threading.Tasks.dll \ - System.Linq.dll \ - System.Memory.dll \ - System.Runtime.InteropServices.dll \ - System.Text.Encoding.Extensions.dll \ - Microsoft.Win32.Primitives.dll \ - System.Console.dll +runtimepack: + ../../../../.././build.sh Mono+Libs -os iOS -arch $(MONO_ARCH) -c $(MONO_CONFIG) -all: mono-libraries aot-all xcode - -# rebuild mono and libraries for iOS and arm64 or x64 -mono-libraries: - ../../../../.././build.sh -os iOS -arch $(MONO_ARCH) --subsetCategory mono-libraries - -# once a new library is added here it should also be -# added in mono_ios_register_modules() (runtime.m) -aot-all: prepare - make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_MONO)/System.Private.CoreLib.dll - for lib in $(BCL_LIBS); do make aot-lib-${MONO_ARCH} LIB=$(ARTIFACTS_BCL)/$$lib; done - make aot-program - -# recompile Program.cs AOT -aot-program: - $(DOTNET) build -c Debug Program.csproj - make aot-lib-${MONO_ARCH} LIB=bin/Program.dll - -# we need to copy some BCL libs to ARTIFACTS_MONO -# to be able to aot other bcl libs -prepare: - for lib in $(BCL_LIBS); do cp $(ARTIFACTS_BCL)/$$lib $(ARTIFACTS_MONO); done - -# we'll use regular jit for simulator -aot-lib-x64: - cp $(LIB) $(notdir $(LIB)) - -aot-lib-arm64: - DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 MONO_PATH=$(ARTIFACTS_MONO) \ - $(ARTIFACTS_MONO)/cross/./mono-aot-cross -O=gsharedvt,float32 --nollvm --debug \ - --aot=mtriple=arm64-ios,static,asmonly,direct-icalls,no-direct-calls,dwarfdebug,full $(LIB) && \ - clang -isysroot $(SYSROOT) -miphoneos-version-min=10.1 -arch arm64 -c $(LIB).s - cp $(LIB) $(notdir $(LIB)) - -# generate an xcode project -xcode: - cmake -S. -BXcode -GXcode \ - -DCMAKE_SYSTEM_NAME=iOS \ - "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.1 \ - -DCMAKE_INSTALL_PREFIX=`pwd`/_install \ - -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=NO \ - -DCMAKE_IOS_INSTALL_COMBINED=YES \ - -DMONO_CONFIG=$(MONO_CONFIG) \ - -DMONO_ARCH=$(MONO_ARCH) +run: clean appbuilder + $(DOTNET) publish -c $(MONO_CONFIG) /p:TargetArchitecture=$(MONO_ARCH) \ + /p:UseLLVM=$(USE_LLVM) /p:UseAotForSimulator=true clean: - rm -rf *.dll - rm -rf *.dll.o - rm -rf Xcode \ No newline at end of file + rm -rf bin diff --git a/src/mono/netcore/sample/iOS/Plist.in b/src/mono/netcore/sample/iOS/Plist.in deleted file mode 100644 index 16b261c0240a65..00000000000000 --- a/src/mono/netcore/sample/iOS/Plist.in +++ /dev/null @@ -1,37 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en-US - CFBundleExecutable - HelloiOS - CFBundleIdentifier - net.dot.HelloiOS - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - HelloiOS - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - - - diff --git a/src/mono/netcore/sample/iOS/Program.cs b/src/mono/netcore/sample/iOS/Program.cs index c1f99af192632c..2b43cf7f527429 100644 --- a/src/mono/netcore/sample/iOS/Program.cs +++ b/src/mono/netcore/sample/iOS/Program.cs @@ -1,4 +1,8 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using System.Threading; using System.Threading.Tasks; using System.Runtime.InteropServices; @@ -45,5 +49,6 @@ public static async Task Main(string[] args) } Console.WriteLine("Done!"); + await Task.Delay(-1); } } \ No newline at end of file diff --git a/src/mono/netcore/sample/iOS/Program.csproj b/src/mono/netcore/sample/iOS/Program.csproj index 0b65c426b4f93d..f08d1806b4f4c6 100644 --- a/src/mono/netcore/sample/iOS/Program.csproj +++ b/src/mono/netcore/sample/iOS/Program.csproj @@ -1,9 +1,86 @@ - Exe bin + Portable $(NetCoreAppCurrent) + iOS + $(ArtifactsBinDir)lib-runtime-packs\$(NetCoreAppCurrent)-iOS-$(Configuration)-$(TargetArchitecture)\runtimes\ios-$(TargetArchitecture) + false + ios-$(TargetArchitecture) + true + <_TrimmerDefaultAction>link + True + + + + + $(ArtifactsDir)bin\lib-runtime-packs\$(NetCoreAppCurrent)-iOS-$(Configuration)-$(TargetArchitecture) + + + + + + + + + + + + + $(MSBuildThisFileDirectory)$(PublishDir)\app + iPhone 11 + + + + + + + + @(MonoAOTCompilerDefaultAotArguments, ';') + @(MonoAOTCompilerDefaultProcessArguments, ';') + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mono/netcore/sample/iOS/main.m b/src/mono/netcore/sample/iOS/main.m index d3c688109f8b3b..374a094b4a1aa2 100644 --- a/src/mono/netcore/sample/iOS/main.m +++ b/src/mono/netcore/sample/iOS/main.m @@ -1,3 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + #import #import "runtime.h" diff --git a/src/mono/netcore/sample/iOS/runtime.h b/src/mono/netcore/sample/iOS/runtime.h deleted file mode 100644 index ddddd96c8373c9..00000000000000 --- a/src/mono/netcore/sample/iOS/runtime.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef runtime_h -#define runtime_h - -void mono_ios_runtime_init (void); - -#endif /* runtime_h */ diff --git a/src/mono/netcore/sample/iOS/runtime.m b/src/mono/netcore/sample/iOS/runtime.m deleted file mode 100644 index 424b4d8d65fd08..00000000000000 --- a/src/mono/netcore/sample/iOS/runtime.m +++ /dev/null @@ -1,299 +0,0 @@ -#import -#include -#include -#include -#include -#include -#include -#include -#include - -#import -#include -#include - -// no-op for iOS and tvOS. -// watchOS is not supported yet. -#define MONO_ENTER_GC_UNSAFE -#define MONO_EXIT_GC_UNSAFE - -static os_log_t stdout_log; - -static char *bundle_path; - -const char * -get_bundle_path (void) -{ - if (bundle_path) - return bundle_path; - - NSBundle* main_bundle = [NSBundle mainBundle]; - NSString* path = [main_bundle bundlePath]; - bundle_path = strdup ([path UTF8String]); - - return bundle_path; -} - -static unsigned char * -load_aot_data (MonoAssembly *assembly, int size, void *user_data, void **out_handle) -{ - *out_handle = NULL; - - char path [1024]; - int res; - - MonoAssemblyName *assembly_name = mono_assembly_get_name (assembly); - const char *aname = mono_assembly_name_get_name (assembly_name); - const char *bundle = get_bundle_path (); - - os_log_info (OS_LOG_DEFAULT, "Looking for aot data for assembly '%s'.", aname); - res = snprintf (path, sizeof (path) - 1, "%s/%s.aotdata", bundle, aname); - assert (res > 0); - - int fd = open (path, O_RDONLY); - if (fd < 0) { - os_log_info (OS_LOG_DEFAULT, "Could not load the aot data for %s from %s: %s\n", aname, path, strerror (errno)); - return NULL; - } - - void *ptr = mmap (NULL, size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); - if (ptr == MAP_FAILED) { - os_log_info (OS_LOG_DEFAULT, "Could not map the aot file for %s: %s\n", aname, strerror (errno)); - close (fd); - return NULL; - } - - close (fd); - os_log_info (OS_LOG_DEFAULT, "Loaded aot data for %s.\n", aname); - *out_handle = ptr; - return (unsigned char *) ptr; -} - -static void -free_aot_data (MonoAssembly *assembly, int size, void *user_data, void *handle) -{ - munmap (handle, size); -} - -static MonoAssembly* -load_assembly (const char *name, const char *culture) -{ - const char *bundle = get_bundle_path (); - char filename [1024]; - char path [1024]; - int res; - - os_log_info (OS_LOG_DEFAULT, "assembly_preload_hook: %{public}s %{public}s %{public}s\n", name, culture, bundle); - - int len = strlen (name); - int has_extension = len > 3 && name [len - 4] == '.' && (!strcmp ("exe", name + (len - 3)) || !strcmp ("dll", name + (len - 3))); - - // add extensions if required. - strlcpy (filename, name, sizeof (filename)); - if (!has_extension) { - strlcat (filename, ".dll", sizeof (filename)); - } - - if (culture && strcmp (culture, "")) - res = snprintf (path, sizeof (path) - 1, "%s/%s/%s", bundle, culture, filename); - else - res = snprintf (path, sizeof (path) - 1, "%s/%s", bundle, filename); - assert (res > 0); - - struct stat buffer; - if (stat (path, &buffer) == 0) { - MonoAssembly *assembly = mono_assembly_open (path, NULL); - assert (assembly); - return assembly; - } - return NULL; -} - -static MonoAssembly* -assembly_preload_hook (MonoAssemblyName *aname, char **assemblies_path, void* user_data) -{ - const char *name = mono_assembly_name_get_name (aname); - const char *culture = mono_assembly_name_get_culture (aname); - return load_assembly (name, culture); -} - -char * -strdup_printf (const char *msg, ...) -{ - va_list args; - char *formatted = NULL; - va_start (args, msg); - vasprintf (&formatted, msg, args); - va_end (args); - return formatted; -} - -static MonoObject * -fetch_exception_property (MonoObject *obj, const char *name, bool is_virtual) -{ - MonoMethod *get = NULL; - MonoMethod *get_virt = NULL; - MonoObject *exc = NULL; - - get = mono_class_get_method_from_name (mono_get_exception_class (), name, 0); - if (get) { - if (is_virtual) { - get_virt = mono_object_get_virtual_method (obj, get); - if (get_virt) - get = get_virt; - } - - return (MonoObject *) mono_runtime_invoke (get, obj, NULL, &exc); - } else { - printf ("Could not find the property System.Exception.%s", name); - } - - return NULL; -} - -static char * -fetch_exception_property_string (MonoObject *obj, const char *name, bool is_virtual) -{ - MonoString *str = (MonoString *) fetch_exception_property (obj, name, is_virtual); - return str ? mono_string_to_utf8 (str) : NULL; -} - -void -unhandled_exception_handler (MonoObject *exc, void *user_data) -{ - NSMutableString *msg = [[NSMutableString alloc] init]; - - MonoClass *type = mono_object_get_class (exc); - char *type_name = strdup_printf ("%s.%s", mono_class_get_namespace (type), mono_class_get_name (type)); - char *trace = fetch_exception_property_string (exc, "get_StackTrace", true); - char *message = fetch_exception_property_string (exc, "get_Message", true); - - [msg appendString:@"Unhandled managed exceptions:\n"]; - [msg appendFormat: @"%s (%s)\n%s\n", message, type_name, trace ? trace : ""]; - - free (trace); - free (message); - free (type_name); - - os_log_info (OS_LOG_DEFAULT, "%@", msg); - os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", 1); - exit (1); -} - -void -log_callback (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) -{ - os_log_info (OS_LOG_DEFAULT, "(%s %s) %s", log_domain, log_level, message); - if (fatal) { - os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", 1); - exit (1); - } -} - -static void -register_dllmap (void) -{ - mono_dllmap_insert (NULL, "libSystem.Native", NULL, "__Internal", NULL); - mono_dllmap_insert (NULL, "libSystem.IO.Compression.Native", NULL, "__Internal", NULL); - mono_dllmap_insert (NULL, "libSystem.Security.Cryptography.Native.Apple", NULL, "__Internal", NULL); -} - -void mono_jit_set_aot_mode (MonoAotMode mode); - -#if DEVICE -extern void *mono_aot_module_Program_info; -extern void *mono_aot_module_System_Private_CoreLib_info; -extern void *mono_aot_module_System_Runtime_info; -extern void *mono_aot_module_System_Runtime_Extensions_info; -extern void *mono_aot_module_System_Collections_info; -extern void *mono_aot_module_System_Core_info; -extern void *mono_aot_module_System_Threading_info; -extern void *mono_aot_module_System_Threading_Tasks_info; -extern void *mono_aot_module_System_Linq_info; -extern void *mono_aot_module_System_Memory_info; -extern void *mono_aot_module_System_Runtime_InteropServices_info; -extern void *mono_aot_module_System_Text_Encoding_Extensions_info; -extern void *mono_aot_module_Microsoft_Win32_Primitives_info; -extern void *mono_aot_module_System_Console_info; -extern void *mono_aot_module_Program_info; - -void mono_ios_register_modules (void) -{ - mono_aot_register_module (mono_aot_module_Program_info); - mono_aot_register_module (mono_aot_module_System_Private_CoreLib_info); - mono_aot_register_module (mono_aot_module_System_Runtime_info); - mono_aot_register_module (mono_aot_module_System_Runtime_Extensions_info); - mono_aot_register_module (mono_aot_module_System_Collections_info); - mono_aot_register_module (mono_aot_module_System_Core_info); - mono_aot_register_module (mono_aot_module_System_Threading_info); - mono_aot_register_module (mono_aot_module_System_Threading_Tasks_info); - mono_aot_register_module (mono_aot_module_System_Linq_info); - mono_aot_register_module (mono_aot_module_System_Memory_info); - mono_aot_register_module (mono_aot_module_System_Runtime_InteropServices_info); - mono_aot_register_module (mono_aot_module_System_Text_Encoding_Extensions_info); - mono_aot_register_module (mono_aot_module_Microsoft_Win32_Primitives_info); - mono_aot_register_module (mono_aot_module_System_Console_info); - mono_aot_register_module (mono_aot_module_Program_info); -} - -void mono_ios_setup_execution_mode (void) -{ - mono_jit_set_aot_mode (MONO_AOT_MODE_FULL); -} -#endif - -void -mono_ios_runtime_init (void) -{ - // for now, only Invariant Mode is supported (FIXME: integrate ICU) - setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", TRUE); - // uncomment for debug output: - // - // setenv ("MONO_LOG_LEVEL", "debug", TRUE); - // setenv ("MONO_LOG_MASK", "all", TRUE); - - stdout_log = os_log_create ("net.dot.mono", "stdout"); - - bool wait_for_debugger = FALSE; - char* executable = "Program.dll"; - - const char* bundle = get_bundle_path (); - chdir (bundle); - - register_dllmap (); - -#if DEVICE - // register modules - mono_ios_register_modules (); - mono_ios_setup_execution_mode (); -#endif - - mono_debug_init (MONO_DEBUG_FORMAT_MONO); - mono_install_assembly_preload_hook (assembly_preload_hook, NULL); - mono_install_load_aot_data_hook (load_aot_data, free_aot_data, NULL); - mono_install_unhandled_exception_hook (unhandled_exception_handler, NULL); - mono_trace_set_log_handler (log_callback, NULL); - mono_set_signal_chaining (TRUE); - mono_set_crash_chaining (TRUE); - - if (wait_for_debugger) { - char* options[] = { "--debugger-agent=transport=dt_socket,server=y,address=0.0.0.0:55555" }; - mono_jit_parse_options (1, options); - } - mono_jit_init_version ("dotnet.ios", "mobile"); - -#if DEVICE - // device runtimes are configured to use lazy gc thread creation - MONO_ENTER_GC_UNSAFE; - mono_gc_init_finalizer_thread (); - MONO_EXIT_GC_UNSAFE; -#endif - - MonoAssembly *assembly = load_assembly (executable, NULL); - assert (assembly); - os_log_info (OS_LOG_DEFAULT, "Executable: %{public}s", executable); - - int res = mono_jit_exec (mono_domain_get (), assembly, 1, &executable); - // Print this so apps parsing logs can detect when we exited - os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", res); -} diff --git a/src/mono/netcore/sample/wasm/Makefile b/src/mono/netcore/sample/wasm/Makefile new file mode 100644 index 00000000000000..aed078c63ebf1a --- /dev/null +++ b/src/mono/netcore/sample/wasm/Makefile @@ -0,0 +1,19 @@ +TOP=../../../../.. + +DOTNET_Q_ARGS=--nologo -v:q -consoleloggerparameters:NoSummary + +CONFIG?=Release + +all: build + +build: + $(TOP)/.dotnet/dotnet build $(DOTNET_Q_ARGS) /p:TargetArchitecture=wasm /p:TargetOS=Browser /p:Configuration=$(CONFIG) WasmSample.csproj + +clean: + rm -rf bin + +run: + cd bin/$(CONFIG)/publish && ~/.jsvu/v8 --expose_wasm runtime.js -- --enable-gc --run WasmSample.dll + +runtimepack: + EMSDK_PATH=$(abspath $(TOP)/src/mono/wasm/emsdk) $(TOP)/build.sh -c $(CONFIG) -os Browser -arch wasm -subset Mono+Libs diff --git a/src/mono/netcore/sample/wasm/Program.cs b/src/mono/netcore/sample/wasm/Program.cs new file mode 100644 index 00000000000000..58a6f578393e5a --- /dev/null +++ b/src/mono/netcore/sample/wasm/Program.cs @@ -0,0 +1,12 @@ +// -*- indent-tabs-mode: nil -*- +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; + +public class Test +{ + public static void Main (String[] args) { + Console.WriteLine ("Hello, World!"); + } +} diff --git a/src/mono/netcore/sample/wasm/WasmSample.csproj b/src/mono/netcore/sample/wasm/WasmSample.csproj new file mode 100644 index 00000000000000..1bf65d18fbea7b --- /dev/null +++ b/src/mono/netcore/sample/wasm/WasmSample.csproj @@ -0,0 +1,40 @@ + + + Exe + bin + false + $(NetCoreAppCurrent) + wasm + Browser + $(ArtifactsDir)bin\lib-runtime-packs\$(NetCoreAppCurrent)-$(TargetOS)-$(Configuration)-$(TargetArchitecture)\runtimes\browser-wasm + $(MSBuildThisFileDirectory)\obj\$(Configuration)\wasm + $(MSBuildThisFileDirectory)\bin\$(Configuration)\publish + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mono/netcore/tools/jitdiff/jitdiff.csproj b/src/mono/netcore/tools/jitdiff/jitdiff.csproj index 074afffcc1877d..bc6e2702ca8a66 100755 --- a/src/mono/netcore/tools/jitdiff/jitdiff.csproj +++ b/src/mono/netcore/tools/jitdiff/jitdiff.csproj @@ -1,7 +1,7 @@ Exe - netcoreapp5.0 + $(NetCoreAppCurrent) false diff --git a/src/mono/wasm/.gitignore b/src/mono/wasm/.gitignore new file mode 100644 index 00000000000000..88ea00659140dd --- /dev/null +++ b/src/mono/wasm/.gitignore @@ -0,0 +1 @@ +/emsdk_env.sh diff --git a/src/mono/wasm/Makefile b/src/mono/wasm/Makefile new file mode 100644 index 00000000000000..412ec94a18578b --- /dev/null +++ b/src/mono/wasm/Makefile @@ -0,0 +1,102 @@ +TOP=$(realpath $(CURDIR)/../../..) +-include Make.config + +# +# These variables are set by wasm.targets +# +EMSDK_PATH?=emsdk +CONFIG?=Release +BINDIR?=$(TOP)/artifacts/bin +OBJDIR?=$(TOP)/artifacts/obj +PINVOKE_TABLE?=$(TOP)/artifacts/obj/mono/Browser.wasm.$(CONFIG)/wasm/pinvoke-table.h +MONO_BIN_DIR?=$(BINDIR)/mono/Browser.wasm.$(CONFIG) +SYS_NATIVE_DIR?=$(OBJDIR)/native/net5.0-Browser-$(CONFIG)-wasm/System.Native +BUILDS_BIN_DIR?=$(BINDIR)/native/net5.0-Browser-$(CONFIG)-wasm/wasm/runtimes + +all: build-native + +# +# EMSCRIPTEN SETUP +# +# If EMSDK_PATH is not set by the caller, download and setup a local emsdk install. +# + +EMSCRIPTEN_VERSION=1.39.11 +EMSDK_LOCAL_PATH=emsdk +EMCC=source $(CURDIR)/emsdk_env.sh && emcc + +.stamp-wasm-install-and-select-$(EMSCRIPTEN_VERSION): + rm -rf $(EMSDK_LOCAL_PATH) + git clone https://github.com/emscripten-core/emsdk.git $(EMSDK_LOCAL_PATH) + cd $(EMSDK_LOCAL_PATH) && git checkout $(EMSCRIPTEN_VERSION) + cd $(EMSDK_LOCAL_PATH) && ./emsdk install $(EMSCRIPTEN_VERSION) + cd $(EMSDK_LOCAL_PATH) && ./emsdk activate --embedded $(EMSCRIPTEN_VERSION) + touch $@ + +ifeq ($(EMSDK_PATH),emsdk) +provision-wasm: .stamp-wasm-install-and-select-$(EMSCRIPTEN_VERSION) +else +provision-wasm: +endif + +# emsdk_env.sh calls emsdk construct_env which is a bit slow so make a copy +emsdk_env.sh: | provision-wasm + cd $(EMSDK_PATH) && ./emsdk construct_env $(CURDIR)/emsdk_env.sh + +MONO_OBJ_DIR=$(OBJDIR)/mono/Browser.wasm.$(CONFIG) +MONO_INCLUDE_DIR=$(MONO_BIN_DIR)/include/mono-2.0 +BUILDS_OBJ_DIR=$(MONO_OBJ_DIR)/wasm/runtimes +MONO_LIBS = \ + $(MONO_BIN_DIR)/{libmono-ee-interp.a,libmonosgen-2.0.a,libmono-ilgen.a,libmono-icall-table.a} \ + ${SYS_NATIVE_DIR}/libSystem.Native.a + +EMCC_FLAGS=--profiling-funcs -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN=1 -s ALIASING_FUNCTION_POINTERS=0 -s NO_EXIT_RUNTIME=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'FS_createPath', 'FS_createDataFile', 'cwrap', 'setValue', 'getValue', 'UTF8ToString', 'addFunction']" -s "EXPORTED_FUNCTIONS=['_putchar']" --source-map-base http://example.com -s WASM_OBJECT_FILES=0 -s FORCE_FILESYSTEM=1 -s USE_ZLIB=1 +EMCC_DEBUG_FLAGS =-g -Os -s ASSERTIONS=1 -DENABLE_NETCORE=1 +EMCC_RELEASE_FLAGS=-Oz --llvm-opts 2 --llvm-lto 1 -DENABLE_NETCORE=1 + +# +# Interpreter builds +# + +# $(1) - name +# $(2) - runtime dir +# $(3) - EMCC_FLAGS +# $(4) - libs +define InterpBuildTemplate + +$(BUILDS_BIN_DIR)/$(1)/: + mkdir -p $$@ + +$(BUILDS_OBJ_DIR)/$(1)/: + mkdir -p $$@ + +$(BUILDS_BIN_DIR)/$(1)/dotnet.js: $(BUILDS_OBJ_DIR)/$(1)/driver.o $(BUILDS_OBJ_DIR)/$(1)/corebindings.o runtime/library_mono.js runtime/binding_support.js runtime/dotnet_support.js $(5) | $(BUILDS_BIN_DIR)/$(1)/ emsdk_env.sh + $(EMCC) $(EMCC_FLAGS) $(3) --js-library runtime/library_mono.js --js-library runtime/binding_support.js --js-library runtime/dotnet_support.js $(BUILDS_OBJ_DIR)/$(1)/driver.o $(BUILDS_OBJ_DIR)/$(1)/corebindings.o $(4) -o $(BUILDS_BIN_DIR)/$(1)/dotnet.js + +$(BUILDS_OBJ_DIR)/$(1)/pinvoke-table.h: $(PINVOKE_TABLE) | $(BUILDS_OBJ_DIR)/$(1)/ + if cmp -s $(PINVOKE_TABLE) $$@ ; then : ; else cp $(PINVOKE_TABLE) $$@ ; fi + +$(BUILDS_OBJ_DIR)/$(1)/driver.o: runtime/driver.c runtime/corebindings.c $(BUILDS_OBJ_DIR)/$(1)/pinvoke-table.h $(5) | $(BUILDS_OBJ_DIR)/$(1)/ emsdk_env.sh + $(EMCC) $(EMCC_FLAGS) $(3) -Oz -DCORE_BINDINGS -I$(BUILDS_OBJ_DIR)/$(1) -I$(MONO_INCLUDE_DIR) runtime/driver.c -c -o $$@ + +$(BUILDS_OBJ_DIR)/$(1)/corebindings.o: runtime/corebindings.c | $(BUILDS_OBJ_DIR)/$(1)/ emsdk_env.sh + $(EMCC) $(3) -Oz -I$(MONO_INCLUDE_DIR) runtime/corebindings.c -c -o $$@ + +build-native: $(BUILDS_BIN_DIR)/$(1)/dotnet.js + +build-interp-$(1): $(BUILDS_BIN_DIR)/$(1)/dotnet.js + +endef + +$(eval $(call InterpBuildTemplate,debug,,$(EMCC_DEBUG_FLAGS),$(MONO_LIBS))) +$(eval $(call InterpBuildTemplate,release,,$(EMCC_RELEASE_FLAGS),$(MONO_LIBS))) + +build: + EMSDK_PATH=$(PWD)/wasm/emsdk ../../../.dotnet/dotnet build /p:TargetArchitecture=wasm /p:TargetOS=Browser /p:Configuration=$(CONFIG) + +clean-emsdk: + $(RM) -rf $(EMSDK_LOCAL_PATH) + +clean: + $(RM) -rf $(BUILDS_BIN_DIR) $(BUILDS_OBJ_DIR) + $(RM) emsdk_env.sh diff --git a/src/mono/wasm/runtime-test.js b/src/mono/wasm/runtime-test.js new file mode 100644 index 00000000000000..10e4fa6ff4816d --- /dev/null +++ b/src/mono/wasm/runtime-test.js @@ -0,0 +1,339 @@ +// -*- mode: js; js-indent-level: 4; -*- +// +// Run runtime tests under a JS shell or a browser +// + +//glue code to deal with the differences between chrome, ch, d8, jsc and sm. +var is_browser = typeof window != "undefined"; + +if (is_browser) { + // We expect to be run by tests/runtime/run.js which passes in the arguments using http parameters + var url = new URL (decodeURI (window.location)); + arguments = []; + for (var v of url.searchParams) { + if (v [0] == "arg") { + console.log ("URL ARG: " + v [0] + "=" + v [1]); + arguments.push (v [1]); + } + } +} + +if (is_browser || typeof print === "undefined") + print = console.log; + +// JavaScript core does not have a console defined +if (typeof console === "undefined") { + var Console = function () { + this.log = function(msg){ print(msg) }; + }; + console = new Console(); +} + +if (typeof console !== "undefined") { + if (!console.debug) + console.debug = console.log; + if (!console.trace) + console.trace = console.log; + if (!console.warn) + console.warn = console.log; +} + +if (typeof crypto == 'undefined') { + // /dev/random doesn't work on js shells, so define our own + // See library_fs.js:createDefaultDevices () + var crypto = { + getRandomValues: function (buffer) { + buffer[0] = (Math.random()*256)|0; + } + } +} + +try { + if (typeof arguments == "undefined") + arguments = WScript.Arguments; + load = WScript.LoadScriptFile; + read = WScript.LoadBinaryFile; +} catch (e) { +} + +try { + if (typeof arguments == "undefined") { + if (typeof scriptArgs !== "undefined") + arguments = scriptArgs; + } +} catch (e) { +} +//end of all the nice shell glue code. + +// set up a global variable to be accessed in App.init +var testArguments = arguments; + +function test_exit (exit_code) { + if (is_browser) { + // Notify the puppeteer script + Module.exit_code = exit_code; + print ("WASM EXIT " + exit_code); + } else { + Module.wasm_exit (exit_code); + } +} + +function fail_exec (reason) { + print (reason); + test_exit (1); +} + +function inspect_object (o) { + var r = ""; + for(var p in o) { + var t = typeof o[p]; + r += "'" + p + "' => '" + t + "', "; + } + return r; +} + +// Preprocess arguments +var args = testArguments; +print("Arguments: " + testArguments); +profilers = []; +setenv = {}; +runtime_args = []; +enable_gc = false; +enable_zoneinfo = false; +while (true) { + if (args [0].startsWith ("--profile=")) { + var arg = args [0].substring ("--profile=".length); + + profilers.push (arg); + + args = args.slice (1); + } else if (args [0].startsWith ("--setenv=")) { + var arg = args [0].substring ("--setenv=".length); + var parts = arg.split ('='); + if (parts.length != 2) + fail_exec ("Error: malformed argument: '" + args [0]); + setenv [parts [0]] = parts [1]; + args = args.slice (1); + } else if (args [0].startsWith ("--runtime-arg=")) { + var arg = args [0].substring ("--runtime-arg=".length); + runtime_args.push (arg); + args = args.slice (1); + } else if (args [0] == "--enable-gc") { + enable_gc = true; + args = args.slice (1); + } else if (args [0] == "--enable-zoneinfo") { + enable_zoneinfo = true; + args = args.slice (1); + } else { + break; + } +} +testArguments = args; + +if (typeof window == "undefined") + load ("mono-config.js"); + +var Module = { + mainScriptUrlOrBlob: "dotnet.js", + + print: function(x) { print ("WASM: " + x) }, + printErr: function(x) { print ("WASM-ERR: " + x) }, + + onAbort: function(x) { + print ("ABORT: " + x); + var err = new Error(); + print ("Stacktrace: \n"); + print (err.stack); + test_exit (1); + }, + + onRuntimeInitialized: function () { + // Have to set env vars here to enable setting MONO_LOG_LEVEL etc. + var wasm_setenv = Module.cwrap ('mono_wasm_setenv', 'void', ['string', 'string']); + for (var variable in setenv) { + MONO.mono_wasm_setenv (variable, setenv [variable]); + } + + if (enable_gc) { + var f = Module.cwrap ('mono_wasm_enable_on_demand_gc', 'void', []); + f (); + } + if (enable_zoneinfo) { + // Load the zoneinfo data into the VFS rooted at /zoneinfo + FS.mkdir("zoneinfo"); + Module['FS_createPath']('/', 'zoneinfo', true, true); + Module['FS_createPath']('/zoneinfo', 'Indian', true, true); + Module['FS_createPath']('/zoneinfo', 'Atlantic', true, true); + Module['FS_createPath']('/zoneinfo', 'US', true, true); + Module['FS_createPath']('/zoneinfo', 'Brazil', true, true); + Module['FS_createPath']('/zoneinfo', 'Pacific', true, true); + Module['FS_createPath']('/zoneinfo', 'Arctic', true, true); + Module['FS_createPath']('/zoneinfo', 'America', true, true); + Module['FS_createPath']('/zoneinfo/America', 'Indiana', true, true); + Module['FS_createPath']('/zoneinfo/America', 'Argentina', true, true); + Module['FS_createPath']('/zoneinfo/America', 'Kentucky', true, true); + Module['FS_createPath']('/zoneinfo/America', 'North_Dakota', true, true); + Module['FS_createPath']('/zoneinfo', 'Australia', true, true); + Module['FS_createPath']('/zoneinfo', 'Etc', true, true); + Module['FS_createPath']('/zoneinfo', 'Asia', true, true); + Module['FS_createPath']('/zoneinfo', 'Antarctica', true, true); + Module['FS_createPath']('/zoneinfo', 'Europe', true, true); + Module['FS_createPath']('/zoneinfo', 'Mexico', true, true); + Module['FS_createPath']('/zoneinfo', 'Africa', true, true); + Module['FS_createPath']('/zoneinfo', 'Chile', true, true); + Module['FS_createPath']('/zoneinfo', 'Canada', true, true); + var zoneInfoData = read ('zoneinfo.data', 'binary'); + var metadata = JSON.parse(read ("mono-webassembly-zoneinfo-fs-smd.js.metadata", 'utf-8')); + var files = metadata.files; + for (var i = 0; i < files.length; ++i) { + var byteArray = zoneInfoData.subarray(files[i].start, files[i].end); + var stream = FS.open(files[i].filename, 'w+'); + FS.write(stream, byteArray, 0, byteArray.length, 0); + FS.close(stream); + } + } + MONO.mono_load_runtime_and_bcl ( + config.vfs_prefix, + config.deploy_prefix, + config.enable_debugging, + config.file_list, + function () { + App.init (); + }, + function (asset) + { + if (typeof window != 'undefined') { + return fetch (asset, { credentials: 'same-origin' }); + } else { + // The default mono_load_runtime_and_bcl defaults to using + // fetch to load the assets. It also provides a way to set a + // fetch promise callback. + // Here we wrap the file read in a promise and fake a fetch response + // structure. + return new Promise((resolve, reject) => { + var response = { ok: true, url: asset, + arrayBuffer: function() { + return new Promise((resolve2, reject2) => { + resolve2(new Uint8Array (read (asset, 'binary'))); + } + )} + } + resolve(response) + }) + } + } + ); + }, +}; + +if (typeof window == "undefined") + load ("dotnet.js"); + +const IGNORE_PARAM_COUNT = -1; + +var App = { + init: function () { + + var assembly_load = Module.cwrap ('mono_wasm_assembly_load', 'number', ['string']) + var find_class = Module.cwrap ('mono_wasm_assembly_find_class', 'number', ['number', 'string', 'string']) + var find_method = Module.cwrap ('mono_wasm_assembly_find_method', 'number', ['number', 'string', 'number']) + var runtime_invoke = Module.cwrap ('mono_wasm_invoke_method', 'number', ['number', 'number', 'number', 'number']); + var string_from_js = Module.cwrap ('mono_wasm_string_from_js', 'number', ['string']); + var assembly_get_entry_point = Module.cwrap ('mono_wasm_assembly_get_entry_point', 'number', ['number']); + var string_get_utf8 = Module.cwrap ('mono_wasm_string_get_utf8', 'string', ['number']); + var string_array_new = Module.cwrap ('mono_wasm_string_array_new', 'number', ['number']); + var obj_array_set = Module.cwrap ('mono_wasm_obj_array_set', 'void', ['number', 'number', 'number']); + var exit = Module.cwrap ('mono_wasm_exit', 'void', ['number']); + var wasm_setenv = Module.cwrap ('mono_wasm_setenv', 'void', ['string', 'string']); + var wasm_set_main_args = Module.cwrap ('mono_wasm_set_main_args', 'void', ['number', 'number']); + var wasm_strdup = Module.cwrap ('mono_wasm_strdup', 'number', ['string']); + var unbox_int = Module.cwrap ('mono_unbox_int', 'number', ['number']); + + Module.wasm_exit = Module.cwrap ('mono_wasm_exit', 'void', ['number']); + + Module.print("Initializing....."); + + for (var i = 0; i < profilers.length; ++i) { + var init = Module.cwrap ('mono_wasm_load_profiler_' + profilers [i], 'void', ['string']) + + init (""); + } + + if (args[0] == "--regression") { + var exec_regression = Module.cwrap ('mono_wasm_exec_regression', 'number', ['number', 'string']) + + var res = 0; + try { + res = exec_regression (10, args[1]); + Module.print ("REGRESSION RESULT: " + res); + } catch (e) { + Module.print ("ABORT: " + e); + print (e.stack); + res = 1; + } + + if (res) + fail_exec ("REGRESSION TEST FAILED"); + + return; + } + + if (runtime_args.length > 0) + MONO.mono_wasm_set_runtime_options (runtime_args); + + if (args[0] == "--run") { + // Run an exe + if (args.length == 1) + fail_exec ("Error: Missing main executable argument."); + main_assembly = assembly_load (args[1]); + if (main_assembly == 0) + fail_exec ("Error: Unable to load main executable '" + args[1] + "'"); + main_method = assembly_get_entry_point (main_assembly); + if (main_method == 0) + fail_exec ("Error: Main (string[]) method not found."); + + var app_args = string_array_new (args.length - 2); + for (var i = 2; i < args.length; ++i) { + obj_array_set (app_args, i - 2, string_from_js (args [i])); + } + + var main_argc = args.length - 2 + 1; + var main_argv = Module._malloc (main_argc * 4); + aindex = 0; + Module.setValue (main_argv + (aindex * 4), wasm_strdup (args [1]), "i32") + aindex += 1; + for (var i = 2; i < args.length; ++i) { + Module.setValue (main_argv + (aindex * 4), wasm_strdup (args [i]), "i32"); + aindex += 1; + } + wasm_set_main_args (main_argc, main_argv); + + try { + var invoke_args = Module._malloc (4); + Module.setValue (invoke_args, app_args, "i32"); + var eh_exc = Module._malloc (4); + Module.setValue (eh_exc, 0, "i32"); + var res = runtime_invoke (main_method, 0, invoke_args, eh_exc); + var eh_res = Module.getValue (eh_exc, "i32"); + if (eh_res != 0) { + print ("Exception:" + string_get_utf8 (res)); + test_exit (1); + } + var exit_code = unbox_int (res); + if (exit_code != 0) + test_exit (exit_code); + } catch (ex) { + print ("JS exception: " + ex); + print (ex.stack); + test_exit (1); + } + + if (is_browser) + test_exit (0); + + return; + } else { + fail_exec ("Unhanded argument: " + args [0]); + } + }, +}; diff --git a/src/mono/wasm/runtime/binding_support.js b/src/mono/wasm/runtime/binding_support.js new file mode 100644 index 00000000000000..c97e327373e600 --- /dev/null +++ b/src/mono/wasm/runtime/binding_support.js @@ -0,0 +1,1276 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +var BindingSupportLib = { + $BINDING__postset: 'BINDING.export_functions (Module);', + $BINDING: { + BINDING_ASM: "[System.Runtime.InteropServices.JavaScript]System.Runtime.InteropServices.JavaScript.Runtime", + mono_wasm_object_registry: [], + mono_wasm_ref_counter: 0, + mono_wasm_free_list: [], + mono_wasm_marshal_enum_as_int: false, + mono_bindings_init: function (binding_asm) { + this.BINDING_ASM = binding_asm; + }, + + export_functions: function (module) { + module ["mono_bindings_init"] = BINDING.mono_bindings_init.bind(BINDING); + module ["mono_method_invoke"] = BINDING.call_method.bind(BINDING); + module ["mono_method_get_call_signature"] = BINDING.mono_method_get_call_signature.bind(BINDING); + module ["mono_method_resolve"] = BINDING.resolve_method_fqn.bind(BINDING); + module ["mono_bind_static_method"] = BINDING.bind_static_method.bind(BINDING); + module ["mono_call_static_method"] = BINDING.call_static_method.bind(BINDING); + module ["mono_bind_assembly_entry_point"] = BINDING.bind_assembly_entry_point.bind(BINDING); + module ["mono_call_assembly_entry_point"] = BINDING.call_assembly_entry_point.bind(BINDING); + }, + + bindings_lazy_init: function () { + if (this.init) + return; + + this.assembly_load = Module.cwrap ('mono_wasm_assembly_load', 'number', ['string']); + this.find_class = Module.cwrap ('mono_wasm_assembly_find_class', 'number', ['number', 'string', 'string']); + this.find_method = Module.cwrap ('mono_wasm_assembly_find_method', 'number', ['number', 'string', 'number']); + this.invoke_method = Module.cwrap ('mono_wasm_invoke_method', 'number', ['number', 'number', 'number', 'number']); + this.mono_string_get_utf8 = Module.cwrap ('mono_wasm_string_get_utf8', 'number', ['number']); + this.js_string_to_mono_string = Module.cwrap ('mono_wasm_string_from_js', 'number', ['string']); + this.mono_get_obj_type = Module.cwrap ('mono_wasm_get_obj_type', 'number', ['number']); + this.mono_unbox_int = Module.cwrap ('mono_unbox_int', 'number', ['number']); + this.mono_unbox_float = Module.cwrap ('mono_wasm_unbox_float', 'number', ['number']); + this.mono_array_length = Module.cwrap ('mono_wasm_array_length', 'number', ['number']); + this.mono_array_get = Module.cwrap ('mono_wasm_array_get', 'number', ['number', 'number']); + this.mono_obj_array_new = Module.cwrap ('mono_wasm_obj_array_new', 'number', ['number']); + this.mono_obj_array_set = Module.cwrap ('mono_wasm_obj_array_set', 'void', ['number', 'number', 'number']); + this.mono_unbox_enum = Module.cwrap ('mono_wasm_unbox_enum', 'number', ['number']); + this.assembly_get_entry_point = Module.cwrap ('mono_wasm_assembly_get_entry_point', 'number', ['number']); + + // receives a byteoffset into allocated Heap with a size. + this.mono_typed_array_new = Module.cwrap ('mono_wasm_typed_array_new', 'number', ['number','number','number','number']); + + var binding_fqn_asm = this.BINDING_ASM.substring(this.BINDING_ASM.indexOf ("[") + 1, this.BINDING_ASM.indexOf ("]")).trim(); + var binding_fqn_class = this.BINDING_ASM.substring (this.BINDING_ASM.indexOf ("]") + 1).trim(); + + this.binding_module = this.assembly_load (binding_fqn_asm); + if (!this.binding_module) + throw "Can't find bindings module assembly: " + binding_fqn_asm; + + if (binding_fqn_class !== null && typeof binding_fqn_class !== "undefined") + { + var namespace = "System.Runtime.InteropServices.JavaScript"; + var classname = binding_fqn_class.length > 0 ? binding_fqn_class : "Runtime"; + if (binding_fqn_class.indexOf(".") != -1) { + var idx = binding_fqn_class.lastIndexOf("."); + namespace = binding_fqn_class.substring (0, idx); + classname = binding_fqn_class.substring (idx + 1); + } + } + + var wasm_runtime_class = this.find_class (this.binding_module, namespace, classname) + if (!wasm_runtime_class) + throw "Can't find " + binding_fqn_class + " class"; + + var get_method = function(method_name) { + var res = BINDING.find_method (wasm_runtime_class, method_name, -1) + if (!res) + throw "Can't find method " + namespace + "." + classname + ":" + method_name; + return res; + } + this.bind_js_obj = get_method ("BindJSObject"); + this.bind_core_clr_obj = get_method ("BindCoreCLRObject"); + this.bind_existing_obj = get_method ("BindExistingObject"); + this.unbind_js_obj = get_method ("UnBindJSObject"); + this.unbind_js_obj_and_free = get_method ("UnBindJSObjectAndFree"); + this.unbind_raw_obj_and_free = get_method ("UnBindRawJSObjectAndFree"); + this.get_js_id = get_method ("GetJSObjectId"); + this.get_raw_mono_obj = get_method ("GetDotNetObject"); + + this.box_js_int = get_method ("BoxInt"); + this.box_js_double = get_method ("BoxDouble"); + this.box_js_bool = get_method ("BoxBool"); + this.is_simple_array = get_method ("IsSimpleArray"); + this.get_core_type = get_method ("GetCoreType"); + this.setup_js_cont = get_method ("SetupJSContinuation"); + + this.create_tcs = get_method ("CreateTaskSource"); + this.set_tcs_result = get_method ("SetTaskSourceResult"); + this.set_tcs_failure = get_method ("SetTaskSourceFailure"); + this.tcs_get_task_and_bind = get_method ("GetTaskAndBind"); + this.get_call_sig = get_method ("GetCallSignature"); + + this.object_to_string = get_method ("ObjectToString"); + this.get_date_value = get_method ("GetDateValue"); + this.create_date_time = get_method ("CreateDateTime"); + this.create_uri = get_method ("CreateUri"); + + this.init = true; + }, + + get_js_obj: function (js_handle) { + if (js_handle > 0) + return this.mono_wasm_require_handle(js_handle); + return null; + }, + + conv_string: function (mono_obj) { + return MONO.string_decoder.copy (mono_obj); + }, + + is_nested_array: function (ele) { + return this.call_method (this.is_simple_array, null, "mi", [ ele ]); + }, + + mono_array_to_js_array: function (mono_array) { + if (mono_array == 0) + return null; + + var res = []; + var len = this.mono_array_length (mono_array); + for (var i = 0; i < len; ++i) + { + var ele = this.mono_array_get (mono_array, i); + if (this.is_nested_array(ele)) + res.push(this.mono_array_to_js_array(ele)); + else + res.push (this.unbox_mono_obj (ele)); + } + + return res; + }, + + js_array_to_mono_array: function (js_array) { + var mono_array = this.mono_obj_array_new (js_array.length); + for (var i = 0; i < js_array.length; ++i) { + this.mono_obj_array_set (mono_array, i, this.js_to_mono_obj (js_array [i])); + } + return mono_array; + }, + + unbox_mono_obj: function (mono_obj) { + if (mono_obj == 0) + return undefined; + var type = this.mono_get_obj_type (mono_obj); + //See MARSHAL_TYPE_ defines in driver.c + switch (type) { + case 1: // int + return this.mono_unbox_int (mono_obj); + case 2: // float + return this.mono_unbox_float (mono_obj); + case 3: //string + return this.conv_string (mono_obj); + case 4: //vts + throw new Error ("no idea on how to unbox value types"); + case 5: { // delegate + var obj = this.extract_js_obj (mono_obj); + return function () { + return BINDING.invoke_delegate (obj, arguments); + }; + } + case 6: {// Task + + if (typeof Promise === "undefined" || typeof Promise.resolve === "undefined") + throw new Error ("Promises are not supported thus C# Tasks can not work in this context."); + + var obj = this.extract_js_obj (mono_obj); + var cont_obj = null; + var promise = new Promise (function (resolve, reject) { + cont_obj = { + resolve: resolve, + reject: reject + }; + }); + + this.call_method (this.setup_js_cont, null, "mo", [ mono_obj, cont_obj ]); + obj.__mono_js_cont__ = cont_obj.__mono_gchandle__; + cont_obj.__mono_js_task__ = obj.__mono_gchandle__; + return promise; + } + + case 7: // ref type + return this.extract_js_obj (mono_obj); + + case 8: // bool + return this.mono_unbox_int (mono_obj) != 0; + + case 9: // enum + + if(this.mono_wasm_marshal_enum_as_int) + { + return this.mono_unbox_enum (mono_obj); + } + else + { + enumValue = this.call_method(this.object_to_string, null, "m", [ mono_obj ]); + } + + return enumValue; + + + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + { + throw new Error ("Marshalling of primitive arrays are not supported. Use the corresponding TypedArray instead."); + } + case 20: // clr .NET DateTime + var dateValue = this.call_method(this.get_date_value, null, "md", [ mono_obj ]); + return new Date(dateValue); + case 21: // clr .NET DateTimeOffset + var dateoffsetValue = this.call_method(this.object_to_string, null, "m", [ mono_obj ]); + return dateoffsetValue; + case 22: // clr .NET Uri + var uriValue = this.call_method(this.object_to_string, null, "m", [ mono_obj ]); + return uriValue; + default: + throw new Error ("no idea on how to unbox object kind " + type); + } + }, + + create_task_completion_source: function () { + return this.call_method (this.create_tcs, null, "i", [ -1 ]); + }, + + set_task_result: function (tcs, result) { + tcs.is_mono_tcs_result_set = true; + this.call_method (this.set_tcs_result, null, "oo", [ tcs, result ]); + if (tcs.is_mono_tcs_task_bound) + this.free_task_completion_source(tcs); + }, + + set_task_failure: function (tcs, reason) { + tcs.is_mono_tcs_result_set = true; + this.call_method (this.set_tcs_failure, null, "os", [ tcs, reason.toString () ]); + if (tcs.is_mono_tcs_task_bound) + this.free_task_completion_source(tcs); + }, + + // https://github.com/Planeshifter/emscripten-examples/blob/master/01_PassingArrays/sum_post.js + js_typedarray_to_heap: function(typedArray){ + var numBytes = typedArray.length * typedArray.BYTES_PER_ELEMENT; + var ptr = Module._malloc(numBytes); + var heapBytes = new Uint8Array(Module.HEAPU8.buffer, ptr, numBytes); + heapBytes.set(new Uint8Array(typedArray.buffer, typedArray.byteOffset, numBytes)); + return heapBytes; + }, + js_to_mono_obj: function (js_obj) { + this.bindings_lazy_init (); + + // determines if the javascript object is a Promise or Promise like which can happen + // when using an external Promise library. The javascript object should be marshalled + // as managed Task objects. + // + // Example is when Bluebird is included in a web page using a script tag, it overwrites the + // global Promise object by default with its own version of Promise. + function isThenable() { + // When using an external Promise library the Promise.resolve may not be sufficient + // to identify the object as a Promise. + return Promise.resolve(js_obj) === js_obj || + ((typeof js_obj === "object" || typeof js_obj === "function") && typeof js_obj.then === "function") + } + + switch (true) { + case js_obj === null: + case typeof js_obj === "undefined": + return 0; + case typeof js_obj === "number": + if (parseInt(js_obj) == js_obj) + return this.call_method (this.box_js_int, null, "im", [ js_obj ]); + return this.call_method (this.box_js_double, null, "dm", [ js_obj ]); + case typeof js_obj === "string": + return this.js_string_to_mono_string (js_obj); + case typeof js_obj === "boolean": + return this.call_method (this.box_js_bool, null, "im", [ js_obj ]); + case isThenable() === true: + var the_task = this.try_extract_mono_obj (js_obj); + if (the_task) + return the_task; + var tcs = this.create_task_completion_source (); + js_obj.then (function (result) { + BINDING.set_task_result (tcs, result); + }, function (reason) { + BINDING.set_task_failure (tcs, reason); + }) + return this.get_task_and_bind (tcs, js_obj); + case js_obj.constructor.name === "Date": + // We may need to take into account the TimeZone Offset + return this.call_method(this.create_date_time, null, "dm", [ js_obj.getTime() ]); + default: + return this.extract_mono_obj (js_obj); + } + }, + js_to_mono_uri: function (js_obj) { + this.bindings_lazy_init (); + + switch (true) { + case js_obj === null: + case typeof js_obj === "undefined": + return 0; + case typeof js_obj === "string": + return this.call_method(this.create_uri, null, "sm", [ js_obj ]) + default: + return this.extract_mono_obj (js_obj); + } + }, + js_typed_array_to_array : function (js_obj) { + + // JavaScript typed arrays are array-like objects and provide a mechanism for accessing + // raw binary data. (...) To achieve maximum flexibility and efficiency, JavaScript typed arrays + // split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object) + // is an object representing a chunk of data; it has no format to speak of, and offers no + // mechanism for accessing its contents. In order to access the memory contained in a buffer, + // you need to use a view. A view provides a context — that is, a data type, starting offset, + // and number of elements — that turns the data into an actual typed array. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays + if (!!(js_obj.buffer instanceof ArrayBuffer && js_obj.BYTES_PER_ELEMENT)) + { + var arrayType = 0; + if (js_obj instanceof Int8Array) + arrayType = 11; + if (js_obj instanceof Uint8Array) + arrayType = 12; + if (js_obj instanceof Uint8ClampedArray) + arrayType = 12; + if (js_obj instanceof Int16Array) + arrayType = 13; + if (js_obj instanceof Uint16Array) + arrayType = 14; + if (js_obj instanceof Int32Array) + arrayType = 15; + if (js_obj instanceof Uint32Array) + arrayType = 16; + if (js_obj instanceof Float32Array) + arrayType = 17; + if (js_obj instanceof Float64Array) + arrayType = 18; + + var heapBytes = this.js_typedarray_to_heap(js_obj); + var bufferArray = this.mono_typed_array_new(heapBytes.byteOffset, js_obj.length, js_obj.BYTES_PER_ELEMENT, arrayType); + Module._free(heapBytes.byteOffset); + return bufferArray; + } + else { + throw new Error("Object '" + js_obj + "' is not a typed array"); + } + + + }, + // Copy the existing typed array to the heap pointed to by the pinned array address + // typed array memory -> copy to heap -> address of managed pinned array + typedarray_copy_to : function (typed_array, pinned_array, begin, end, bytes_per_element) { + + // JavaScript typed arrays are array-like objects and provide a mechanism for accessing + // raw binary data. (...) To achieve maximum flexibility and efficiency, JavaScript typed arrays + // split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object) + // is an object representing a chunk of data; it has no format to speak of, and offers no + // mechanism for accessing its contents. In order to access the memory contained in a buffer, + // you need to use a view. A view provides a context — that is, a data type, starting offset, + // and number of elements — that turns the data into an actual typed array. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays + if (!!(typed_array.buffer instanceof ArrayBuffer && typed_array.BYTES_PER_ELEMENT)) + { + // Some sanity checks of what is being asked of us + // lets play it safe and throw an error here instead of assuming to much. + // Better safe than sorry later + if (bytes_per_element !== typed_array.BYTES_PER_ELEMENT) + throw new Error("Inconsistent element sizes: TypedArray.BYTES_PER_ELEMENT '" + typed_array.BYTES_PER_ELEMENT + "' sizeof managed element: '" + bytes_per_element + "'"); + + // how much space we have to work with + var num_of_bytes = (end - begin) * bytes_per_element; + // how much typed buffer space are we talking about + var view_bytes = typed_array.length * typed_array.BYTES_PER_ELEMENT; + // only use what is needed. + if (num_of_bytes > view_bytes) + num_of_bytes = view_bytes; + + // offset index into the view + var offset = begin * bytes_per_element; + + // Create a view over the heap pointed to by the pinned array address + var heapBytes = new Uint8Array(Module.HEAPU8.buffer, pinned_array + offset, num_of_bytes); + // Copy the bytes of the typed array to the heap. + heapBytes.set(new Uint8Array(typed_array.buffer, typed_array.byteOffset, num_of_bytes)); + + return num_of_bytes; + } + else { + throw new Error("Object '" + typed_array + "' is not a typed array"); + } + + }, + // Copy the pinned array address from pinned_array allocated on the heap to the typed array. + // adress of managed pinned array -> copy from heap -> typed array memory + typedarray_copy_from : function (typed_array, pinned_array, begin, end, bytes_per_element) { + + // JavaScript typed arrays are array-like objects and provide a mechanism for accessing + // raw binary data. (...) To achieve maximum flexibility and efficiency, JavaScript typed arrays + // split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object) + // is an object representing a chunk of data; it has no format to speak of, and offers no + // mechanism for accessing its contents. In order to access the memory contained in a buffer, + // you need to use a view. A view provides a context — that is, a data type, starting offset, + // and number of elements — that turns the data into an actual typed array. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays + if (!!(typed_array.buffer instanceof ArrayBuffer && typed_array.BYTES_PER_ELEMENT)) + { + // Some sanity checks of what is being asked of us + // lets play it safe and throw an error here instead of assuming to much. + // Better safe than sorry later + if (bytes_per_element !== typed_array.BYTES_PER_ELEMENT) + throw new Error("Inconsistent element sizes: TypedArray.BYTES_PER_ELEMENT '" + typed_array.BYTES_PER_ELEMENT + "' sizeof managed element: '" + bytes_per_element + "'"); + + // how much space we have to work with + var num_of_bytes = (end - begin) * bytes_per_element; + // how much typed buffer space are we talking about + var view_bytes = typed_array.length * typed_array.BYTES_PER_ELEMENT; + // only use what is needed. + if (num_of_bytes > view_bytes) + num_of_bytes = view_bytes; + + // Create a new view for mapping + var typedarrayBytes = new Uint8Array(typed_array.buffer, 0, num_of_bytes); + // offset index into the view + var offset = begin * bytes_per_element; + // Set view bytes to value from HEAPU8 + typedarrayBytes.set(Module.HEAPU8.subarray(pinned_array + offset, pinned_array + offset + num_of_bytes)); + return num_of_bytes; + } + else { + throw new Error("Object '" + typed_array + "' is not a typed array"); + } + + }, + // Creates a new typed array from pinned array address from pinned_array allocated on the heap to the typed array. + // adress of managed pinned array -> copy from heap -> typed array memory + typed_array_from : function (pinned_array, begin, end, bytes_per_element, type) { + + // typed array + var newTypedArray = 0; + + switch (type) + { + case 5: + newTypedArray = new Int8Array(end - begin); + break; + case 6: + newTypedArray = new Uint8Array(end - begin); + break; + case 7: + newTypedArray = new Int16Array(end - begin); + break; + case 8: + newTypedArray = new Uint16Array(end - begin); + break; + case 9: + newTypedArray = new Int32Array(end - begin); + break; + case 10: + newTypedArray = new Uint32Array(end - begin); + break; + case 13: + newTypedArray = new Float32Array(end - begin); + break; + case 14: + newTypedArray = new Float64Array(end - begin); + break; + case 15: // This is a special case because the typed array is also byte[] + newTypedArray = new Uint8ClampedArray(end - begin); + break; + } + + this.typedarray_copy_from(newTypedArray, pinned_array, begin, end, bytes_per_element); + return newTypedArray; + }, + js_to_mono_enum: function (method, parmIdx, js_obj) { + this.bindings_lazy_init (); + + if (js_obj === null || typeof js_obj === "undefined") + return 0; + + var monoObj = this.js_to_mono_obj(js_obj); + // Check enum contract + var monoEnum = this.call_method(this.object_to_enum, null, "iimm", [ method, parmIdx, monoObj ]) + // return the unboxed enum value. + return this.mono_unbox_enum(monoEnum); + }, + wasm_binding_obj_new: function (js_obj_id, type) + { + return this.call_method (this.bind_js_obj, null, "io", [js_obj_id, type]); + }, + wasm_bind_existing: function (mono_obj, js_id) + { + return this.call_method (this.bind_existing_obj, null, "mi", [mono_obj, js_id]); + }, + + wasm_bind_core_clr_obj: function (js_id, gc_handle) + { + return this.call_method (this.bind_core_clr_obj, null, "ii", [js_id, gc_handle]); + }, + + wasm_unbind_js_obj: function (js_obj_id) + { + this.call_method (this.unbind_js_obj, null, "i", [js_obj_id]); + }, + + wasm_unbind_js_obj_and_free: function (js_obj_id) + { + this.call_method (this.unbind_js_obj_and_free, null, "i", [js_obj_id]); + }, + + wasm_get_js_id: function (mono_obj) + { + return this.call_method (this.get_js_id, null, "m", [mono_obj]); + }, + + wasm_get_raw_obj: function (gchandle) + { + return this.call_method (this.get_raw_mono_obj, null, "im", [gchandle]); + }, + + try_extract_mono_obj:function (js_obj) { + if (js_obj === null || typeof js_obj === "undefined" || typeof js_obj.__mono_gchandle__ === "undefined") + return 0; + return this.wasm_get_raw_obj (js_obj.__mono_gchandle__); + }, + + mono_method_get_call_signature: function(method) { + this.bindings_lazy_init (); + + return this.call_method (this.get_call_sig, null, "i", [ method ]); + }, + + get_task_and_bind: function (tcs, js_obj) { + var gc_handle = this.mono_wasm_free_list.length ? this.mono_wasm_free_list.pop() : this.mono_wasm_ref_counter++; + var task_gchandle = this.call_method (this.tcs_get_task_and_bind, null, "oi", [ tcs, gc_handle + 1 ]); + js_obj.__mono_gchandle__ = task_gchandle; + this.mono_wasm_object_registry[gc_handle] = js_obj; + this.free_task_completion_source(tcs); + tcs.is_mono_tcs_task_bound = true; + js_obj.__mono_bound_tcs__ = tcs.__mono_gchandle__; + tcs.__mono_bound_task__ = js_obj.__mono_gchandle__; + return this.wasm_get_raw_obj (js_obj.__mono_gchandle__); + }, + + free_task_completion_source: function (tcs) { + if (tcs.is_mono_tcs_result_set) + { + this.call_method (this.unbind_raw_obj_and_free, null, "ii", [ tcs.__mono_gchandle__ ]); + } + if (tcs.__mono_bound_task__) + { + this.call_method (this.unbind_raw_obj_and_free, null, "ii", [ tcs.__mono_bound_task__ ]); + } + }, + + extract_mono_obj: function (js_obj) { + + if (js_obj === null || typeof js_obj === "undefined") + return 0; + + if (!js_obj.is_mono_bridged_obj) { + var gc_handle = this.mono_wasm_register_obj(js_obj); + return this.wasm_get_raw_obj (gc_handle); + } + + + return this.wasm_get_raw_obj (js_obj.__mono_gchandle__); + }, + + extract_js_obj: function (mono_obj) { + if (mono_obj == 0) + return null; + + var js_id = this.wasm_get_js_id (mono_obj); + if (js_id > 0) + return this.mono_wasm_require_handle(js_id); + + var gcHandle = this.mono_wasm_free_list.length ? this.mono_wasm_free_list.pop() : this.mono_wasm_ref_counter++; + var js_obj = { + __mono_gchandle__: this.wasm_bind_existing(mono_obj, gcHandle + 1), + is_mono_bridged_obj: true + }; + + this.mono_wasm_object_registry[gcHandle] = js_obj; + return js_obj; + }, + + /* + args_marshal is a string with one character per parameter that tells how to marshal it, here are the valid values: + + i: int32 + j: int32 - Enum with underlying type of int32 + l: int64 + k: int64 - Enum with underlying type of int64 + f: float + d: double + s: string + o: js object will be converted to a C# object (this will box numbers/bool/promises) + m: raw mono object. Don't use it unless you know what you're doing + + additionally you can append 'm' to args_marshal beyond `args.length` if you don't want the return value marshaled + */ + call_method: function (method, this_arg, args_marshal, args) { + this.bindings_lazy_init (); + + // Allocate memory for error + var has_args = args !== null && typeof args !== "undefined" && args.length > 0; + var has_args_marshal = args_marshal !== null && typeof args_marshal !== "undefined" && args_marshal.length > 0; + + if (has_args_marshal && (!has_args || args.length > args_marshal.length)) + throw Error("Parameter count mismatch."); + + var args_start = null; + var buffer = null; + var exception_out = null; + + // check if the method signature needs argument mashalling + if (has_args_marshal && has_args) { + var i; + + var converters = this.converters; + if (!converters) { + converters = new Map (); + converters.set ('m', { steps: [{ }], size: 0}); + converters.set ('s', { steps: [{ convert: this.js_string_to_mono_string.bind (this)}], size: 0}); + converters.set ('o', { steps: [{ convert: this.js_to_mono_obj.bind (this)}], size: 0}); + converters.set ('u', { steps: [{ convert: this.js_to_mono_uri.bind (this)}], size: 0}); + converters.set ('k', { steps: [{ convert: this.js_to_mono_enum.bind (this), indirect: 'i64'}], size: 8}); + converters.set ('j', { steps: [{ convert: this.js_to_mono_enum.bind (this), indirect: 'i32'}], size: 8}); + converters.set ('i', { steps: [{ indirect: 'i32'}], size: 8}); + converters.set ('l', { steps: [{ indirect: 'i64'}], size: 8}); + converters.set ('f', { steps: [{ indirect: 'float'}], size: 8}); + converters.set ('d', { steps: [{ indirect: 'double'}], size: 8}); + this.converters = converters; + } + + var converter = converters.get (args_marshal); + if (!converter) { + var steps = []; + var size = 0; + + for (i = 0; i < args_marshal.length; ++i) { + var conv = this.converters.get (args_marshal[i]); + if (!conv) + throw Error ("Unknown parameter type " + type); + + steps.push (conv.steps[0]); + size += conv.size; + } + converter = { steps: steps, size: size }; + converters.set (args_marshal, converter); + } + + // assume at least 8 byte alignment from malloc + buffer = Module._malloc (converter.size + (args.length * 4) + 4); + var indirect_start = buffer; // buffer + buffer % 8 + exception_out = indirect_start + converter.size; + args_start = exception_out + 4; + + var slot = args_start; + var indirect_value = indirect_start; + for (i = 0; i < args.length; ++i) { + var handler = converter.steps[i]; + var obj = handler.convert ? handler.convert (args[i], method, i) : args[i]; + + if (handler.indirect) { + Module.setValue (indirect_value, obj, handler.indirect); + obj = indirect_value; + indirect_value += 8; + } + + Module.setValue (slot, obj, "*"); + slot += 4; + } + } else { + // only marshal the exception + exception_out = buffer = Module._malloc (4); + } + + Module.setValue (exception_out, 0, "*"); + + var res = this.invoke_method (method, this_arg, args_start, exception_out); + var eh_res = Module.getValue (exception_out, "*"); + + Module._free (buffer); + + if (eh_res != 0) { + var msg = this.conv_string (res); + throw new Error (msg); //the convention is that invoke_method ToString () any outgoing exception + } + + if (has_args_marshal && has_args) { + if (args_marshal.length >= args.length && args_marshal [args.length] === "m") + return res; + } + + return this.unbox_mono_obj (res); + }, + + invoke_delegate: function (delegate_obj, js_args) { + this.bindings_lazy_init (); + + if (!this.delegate_dynamic_invoke) { + if (!this.corlib) + this.corlib = this.assembly_load ("mscorlib"); + if (!this.delegate_class) + this.delegate_class = this.find_class (this.corlib, "System", "Delegate"); + if (!this.delegate_class) + { + throw new Error("System.Delegate class can not be resolved."); + } + this.delegate_dynamic_invoke = this.find_method (this.delegate_class, "DynamicInvoke", -1); + } + var mono_args = this.js_array_to_mono_array (js_args); + if (!this.delegate_dynamic_invoke) + throw new Error("System.Delegate.DynamicInvoke method can not be resolved."); + // Note: the single 'm' passed here is causing problems with AOT. Changed to "mo" again. + // This may need more analysis if causes problems again. + return this.call_method (this.delegate_dynamic_invoke, this.extract_mono_obj (delegate_obj), "mo", [ mono_args ]); + }, + + resolve_method_fqn: function (fqn) { + var assembly = fqn.substring(fqn.indexOf ("[") + 1, fqn.indexOf ("]")).trim(); + fqn = fqn.substring (fqn.indexOf ("]") + 1).trim(); + + var methodname = fqn.substring(fqn.indexOf (":") + 1); + fqn = fqn.substring (0, fqn.indexOf (":")).trim (); + + var namespace = ""; + var classname = fqn; + if (fqn.indexOf(".") != -1) { + var idx = fqn.lastIndexOf("."); + namespace = fqn.substring (0, idx); + classname = fqn.substring (idx + 1); + } + + var asm = this.assembly_load (assembly); + if (!asm) + throw new Error ("Could not find assembly: " + assembly); + + var klass = this.find_class(asm, namespace, classname); + if (!klass) + throw new Error ("Could not find class: " + namespace + ":" +classname); + + var method = this.find_method (klass, methodname, -1); + if (!method) + throw new Error ("Could not find method: " + methodname); + return method; + }, + + call_static_method: function (fqn, args, signature) { + this.bindings_lazy_init (); + + var method = this.resolve_method_fqn (fqn); + + if (typeof signature === "undefined") + signature = Module.mono_method_get_call_signature (method); + + return this.call_method (method, null, signature, args); + }, + + bind_static_method: function (fqn, signature) { + this.bindings_lazy_init (); + + var method = this.resolve_method_fqn (fqn); + + if (typeof signature === "undefined") + signature = Module.mono_method_get_call_signature (method); + + return function() { + return BINDING.call_method (method, null, signature, arguments); + }; + }, + bind_assembly_entry_point: function (assembly) { + this.bindings_lazy_init (); + + var asm = this.assembly_load (assembly); + if (!asm) + throw new Error ("Could not find assembly: " + assembly); + + var method = this.assembly_get_entry_point(asm); + if (!method) + throw new Error ("Could not find entry point for assembly: " + assembly); + + if (typeof signature === "undefined") + signature = Module.mono_method_get_call_signature (method); + + return function() { + return BINDING.call_method (method, null, signature, arguments); + }; + }, + call_assembly_entry_point: function (assembly, args, signature) { + this.bindings_lazy_init (); + + var asm = this.assembly_load (assembly); + if (!asm) + throw new Error ("Could not find assembly: " + assembly); + + var method = this.assembly_get_entry_point(asm); + if (!method) + throw new Error ("Could not find entry point for assembly: " + assembly); + + if (typeof signature === "undefined") + signature = Module.mono_method_get_call_signature (method); + + return this.call_method (method, null, signature, args); + }, + wasm_get_core_type: function (obj) + { + return this.call_method (this.get_core_type, null, "so", [ "WebAssembly.Core."+obj.constructor.name ]); + }, + get_wasm_type: function(obj) { + var coreType = obj[Symbol.for("wasm type")]; + if (typeof coreType === "undefined") { + coreType = this.wasm_get_core_type(obj); + if (typeof coreType !== "undefined") { + obj.constructor.prototype[Symbol.for("wasm type")] = coreType; + } + } + return coreType; + }, + // Object wrapping helper functions to handle reference handles that will + // be used in managed code. + mono_wasm_register_obj: function(obj) { + + var gc_handle = undefined; + if (obj !== null && typeof obj !== "undefined") + { + gc_handle = obj.__mono_gchandle__; + + if (typeof gc_handle === "undefined") { + var handle = this.mono_wasm_free_list.length ? + this.mono_wasm_free_list.pop() : this.mono_wasm_ref_counter++; + obj.__mono_jshandle__ = handle; + // Obtain the JS -> C# type mapping. + var wasm_type = this.get_wasm_type(obj); + gc_handle = obj.__mono_gchandle__ = this.wasm_binding_obj_new(handle + 1, wasm_type); + this.mono_wasm_object_registry[handle] = obj; + + } + } + return gc_handle; + }, + mono_wasm_require_handle: function(handle) { + if (handle > 0) + return this.mono_wasm_object_registry[handle - 1]; + return null; + }, + mono_wasm_unregister_obj: function(js_id) { + var obj = this.mono_wasm_object_registry[js_id - 1]; + if (typeof obj !== "undefined" && obj !== null) { + // if this is the global object then do not + // unregister it. + if (typeof ___mono_wasm_global___ !== "undefined" && ___mono_wasm_global___ === obj) + return obj; + + var gc_handle = obj.__mono_gchandle__; + if (typeof gc_handle !== "undefined") { + this.wasm_unbind_js_obj_and_free(js_id); + + obj.__mono_gchandle__ = undefined; + obj.__mono_jshandle__ = undefined; + + this.mono_wasm_object_registry[js_id - 1] = undefined; + this.mono_wasm_free_list.push(js_id - 1); + } + } + return obj; + }, + mono_wasm_free_handle: function(handle) { + this.mono_wasm_unregister_obj(handle); + }, + mono_wasm_free_raw_object: function(js_id) { + var obj = this.mono_wasm_object_registry[js_id - 1]; + if (typeof obj !== "undefined" && obj !== null) { + // if this is the global object then do not + // unregister it. + if (typeof ___mono_wasm_global___ !== "undefined" && ___mono_wasm_global___ === obj) + return obj; + + var gc_handle = obj.__mono_gchandle__; + if (typeof gc_handle !== "undefined") { + + obj.__mono_gchandle__ = undefined; + obj.__mono_jshandle__ = undefined; + + this.mono_wasm_object_registry[js_id - 1] = undefined; + this.mono_wasm_free_list.push(js_id - 1); + } + } + return obj; + }, + mono_wasm_get_global: function() { + function testGlobal(obj) { + obj['___mono_wasm_global___'] = obj; + var success = typeof ___mono_wasm_global___ === 'object' && obj['___mono_wasm_global___'] === obj; + if (!success) { + delete obj['___mono_wasm_global___']; + } + return success; + } + if (typeof ___mono_wasm_global___ === 'object') { + return ___mono_wasm_global___; + } + if (typeof global === 'object' && testGlobal(global)) { + ___mono_wasm_global___ = global; + } else if (typeof window === 'object' && testGlobal(window)) { + ___mono_wasm_global___ = window; + } else if (testGlobal((function(){return Function;})()('return this')())) { + + ___mono_wasm_global___ = (function(){return Function;})()('return this')(); + + } + if (typeof ___mono_wasm_global___ === 'object') { + return ___mono_wasm_global___; + } + throw Error('Unable to get mono wasm global object.'); + }, + + }, + + mono_wasm_invoke_js_with_args: function(js_handle, method_name, args, is_exception) { + BINDING.bindings_lazy_init (); + + var obj = BINDING.get_js_obj (js_handle); + if (!obj) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'"); + } + + var js_name = BINDING.conv_string (method_name); + if (!js_name) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Invalid method name object '" + method_name + "'"); + } + + var js_args = BINDING.mono_array_to_js_array(args); + + var res; + try { + var m = obj [js_name]; + if (typeof m === "undefined") + throw new Error("Method: '" + js_name + "' not found for: '" + Object.prototype.toString.call(obj) + "'"); + var res = m.apply (obj, js_args); + return BINDING.js_to_mono_obj (res); + } catch (e) { + var res = e.toString (); + setValue (is_exception, 1, "i32"); + if (res === null || res === undefined) + res = "unknown exception"; + return BINDING.js_string_to_mono_string (res); + } + }, + mono_wasm_get_object_property: function(js_handle, property_name, is_exception) { + BINDING.bindings_lazy_init (); + + var obj = BINDING.mono_wasm_require_handle (js_handle); + if (!obj) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'"); + } + + var js_name = BINDING.conv_string (property_name); + if (!js_name) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Invalid property name object '" + js_name + "'"); + } + + var res; + try { + var m = obj [js_name]; + if (m === Object(m) && obj.__is_mono_proxied__) + m.__is_mono_proxied__ = true; + + return BINDING.js_to_mono_obj (m); + } catch (e) { + var res = e.toString (); + setValue (is_exception, 1, "i32"); + if (res === null || typeof res === "undefined") + res = "unknown exception"; + return BINDING.js_string_to_mono_string (res); + } + }, + mono_wasm_set_object_property: function (js_handle, property_name, value, createIfNotExist, hasOwnProperty, is_exception) { + + BINDING.bindings_lazy_init (); + + var requireObject = BINDING.mono_wasm_require_handle (js_handle); + if (!requireObject) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'"); + } + + var property = BINDING.conv_string (property_name); + if (!property) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Invalid property name object '" + property_name + "'"); + } + + var result = false; + + var js_value = BINDING.unbox_mono_obj(value); + + if (createIfNotExist) { + requireObject[property] = js_value; + result = true; + } + else { + result = false; + if (!createIfNotExist) + { + if (!requireObject.hasOwnProperty(property)) + return false; + } + if (hasOwnProperty === true) { + if (requireObject.hasOwnProperty(property)) { + requireObject[property] = js_value; + result = true; + } + } + else { + requireObject[property] = js_value; + result = true; + } + + } + return BINDING.call_method (BINDING.box_js_bool, null, "im", [ result ]); + }, + mono_wasm_get_by_index: function(js_handle, property_index, is_exception) { + BINDING.bindings_lazy_init (); + + var obj = BINDING.mono_wasm_require_handle (js_handle); + if (!obj) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'"); + } + + try { + var m = obj [property_index]; + return BINDING.js_to_mono_obj (m); + } catch (e) { + var res = e.toString (); + setValue (is_exception, 1, "i32"); + if (res === null || typeof res === "undefined") + res = "unknown exception"; + return BINDING.js_string_to_mono_string (res); + } + }, + mono_wasm_set_by_index: function(js_handle, property_index, value, is_exception) { + BINDING.bindings_lazy_init (); + + var obj = BINDING.mono_wasm_require_handle (js_handle); + if (!obj) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'"); + } + + var js_value = BINDING.unbox_mono_obj(value); + + try { + obj [property_index] = js_value; + return true; + } catch (e) { + var res = e.toString (); + setValue (is_exception, 1, "i32"); + if (res === null || typeof res === "undefined") + res = "unknown exception"; + return BINDING.js_string_to_mono_string (res); + } + }, + mono_wasm_get_global_object: function(global_name, is_exception) { + BINDING.bindings_lazy_init (); + + var js_name = BINDING.conv_string (global_name); + + var globalObj = undefined; + + if (!js_name) { + globalObj = BINDING.mono_wasm_get_global(); + } + else { + globalObj = BINDING.mono_wasm_get_global()[js_name]; + } + + if (globalObj === null || typeof globalObj === undefined) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Global object '" + js_name + "' not found."); + } + + return BINDING.js_to_mono_obj (globalObj); + }, + mono_wasm_release_handle: function(js_handle, is_exception) { + BINDING.bindings_lazy_init (); + + BINDING.mono_wasm_free_handle(js_handle); + }, + mono_wasm_release_object: function(js_handle, is_exception) { + BINDING.bindings_lazy_init (); + + BINDING.mono_wasm_free_raw_object(js_handle); + }, + mono_wasm_bind_core_object: function(js_handle, gc_handle, is_exception) { + BINDING.bindings_lazy_init (); + + var requireObject = BINDING.mono_wasm_require_handle (js_handle); + if (!requireObject) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'"); + } + + BINDING.wasm_bind_core_clr_obj(js_handle, gc_handle ); + requireObject.__mono_gchandle__ = gc_handle; + return gc_handle; + }, + mono_wasm_bind_host_object: function(js_handle, gc_handle, is_exception) { + BINDING.bindings_lazy_init (); + + var requireObject = BINDING.mono_wasm_require_handle (js_handle); + if (!requireObject) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'"); + } + + BINDING.wasm_bind_core_clr_obj(js_handle, gc_handle ); + requireObject.__mono_gchandle__ = gc_handle; + return gc_handle; + }, + mono_wasm_new: function (core_name, args, is_exception) { + BINDING.bindings_lazy_init (); + + var js_name = BINDING.conv_string (core_name); + + if (!js_name) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Core object '" + js_name + "' not found."); + } + + var coreObj = BINDING.mono_wasm_get_global()[js_name]; + + if (coreObj === null || typeof coreObj === "undefined") { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("JavaScript host object '" + js_name + "' not found."); + } + + var js_args = BINDING.mono_array_to_js_array(args); + + try { + + // This is all experimental !!!!!! + var allocator = function(constructor, js_args) { + // Not sure if we should be checking for anything here + var argsList = new Array(); + argsList[0] = constructor; + if (js_args) + argsList = argsList.concat(js_args); + var obj = new (constructor.bind.apply(constructor, argsList )); + return obj; + }; + + var res = allocator(coreObj, js_args); + var gc_handle = BINDING.mono_wasm_free_list.length ? BINDING.mono_wasm_free_list.pop() : BINDING.mono_wasm_ref_counter++; + BINDING.mono_wasm_object_registry[gc_handle] = res; + return BINDING.js_to_mono_obj (gc_handle + 1); + } catch (e) { + var res = e.toString (); + setValue (is_exception, 1, "i32"); + if (res === null || res === undefined) + res = "Error allocating object."; + return BINDING.js_string_to_mono_string (res); + } + + }, + mono_wasm_new_object: function(object_handle_or_function, args, is_exception) { + BINDING.bindings_lazy_init (); + + if (!object_handle_or_function) { + return BINDING.js_to_mono_obj ({}); + } + else { + + var requireObject; + if (typeof object_handle_or_function === 'function') + requireObject = object_handle_or_function; + else + requireObject = BINDING.mono_wasm_require_handle (object_handle_or_function); + + if (!requireObject) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + object_handle_or_function + "'"); + } + + var js_args = BINDING.mono_array_to_js_array(args); + + try { + + // This is all experimental !!!!!! + var allocator = function(constructor, js_args) { + // Not sure if we should be checking for anything here + var argsList = new Array(); + argsList[0] = constructor; + if (js_args) + argsList = argsList.concat(js_args); + var obj = new (constructor.bind.apply(constructor, argsList )); + return obj; + }; + + var res = allocator(requireObject, js_args); + return BINDING.extract_mono_obj (res); + } catch (e) { + var res = e.toString (); + setValue (is_exception, 1, "i32"); + if (res === null || res === undefined) + res = "Error allocating object."; + return BINDING.js_string_to_mono_string (res); + } + } + + }, + mono_wasm_typed_array_to_array: function(js_handle, is_exception) { + BINDING.bindings_lazy_init (); + + var requireObject = BINDING.mono_wasm_require_handle (js_handle); + if (!requireObject) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'"); + } + + return BINDING.js_typed_array_to_array(requireObject); + }, + mono_wasm_typed_array_copy_to: function(js_handle, pinned_array, begin, end, bytes_per_element, is_exception) { + BINDING.bindings_lazy_init (); + + var requireObject = BINDING.mono_wasm_require_handle (js_handle); + if (!requireObject) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'"); + } + + var res = BINDING.typedarray_copy_to(requireObject, pinned_array, begin, end, bytes_per_element); + return BINDING.js_to_mono_obj (res) + }, + mono_wasm_typed_array_from: function(pinned_array, begin, end, bytes_per_element, type, is_exception) { + BINDING.bindings_lazy_init (); + var res = BINDING.typed_array_from(pinned_array, begin, end, bytes_per_element, type); + return BINDING.js_to_mono_obj (res) + }, + mono_wasm_typed_array_copy_from: function(js_handle, pinned_array, begin, end, bytes_per_element, is_exception) { + BINDING.bindings_lazy_init (); + + var requireObject = BINDING.mono_wasm_require_handle (js_handle); + if (!requireObject) { + setValue (is_exception, 1, "i32"); + return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'"); + } + + var res = BINDING.typedarray_copy_from(requireObject, pinned_array, begin, end, bytes_per_element); + return BINDING.js_to_mono_obj (res) + }, + + +}; + +autoAddDeps(BindingSupportLib, '$BINDING') +mergeInto(LibraryManager.library, BindingSupportLib) diff --git a/src/mono/wasm/runtime/corebindings.c b/src/mono/wasm/runtime/corebindings.c new file mode 100644 index 00000000000000..4b78715bc0b218 --- /dev/null +++ b/src/mono/wasm/runtime/corebindings.c @@ -0,0 +1,179 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +#include +#include +#include +#include +#include +#include + +#include + +//JS funcs +extern MonoObject* mono_wasm_invoke_js_with_args (int js_handle, MonoString *method, MonoArray *args, int *is_exception); +extern MonoObject* mono_wasm_get_object_property (int js_handle, MonoString *propertyName, int *is_exception); +extern MonoObject* mono_wasm_get_by_index (int js_handle, int property_index, int *is_exception); +extern MonoObject* mono_wasm_set_object_property (int js_handle, MonoString *propertyName, MonoObject *value, int createIfNotExist, int hasOwnProperty, int *is_exception); +extern MonoObject* mono_wasm_set_by_index (int js_handle, int property_index, MonoObject *value, int *is_exception); +extern MonoObject* mono_wasm_get_global_object (MonoString *global_name, int *is_exception); +extern void* mono_wasm_release_handle (int js_handle, int *is_exception); +extern void* mono_wasm_release_object (int js_handle, int *is_exception); +extern MonoObject* mono_wasm_new_object (int js_handle, MonoArray *args, int *is_exception); +extern MonoObject* mono_wasm_new (MonoString *core_name, MonoArray *args, int *is_exception); +extern int mono_wasm_bind_core_object (int js_handle, int gc_handle, int *is_exception); +extern int mono_wasm_bind_host_object (int js_handle, int gc_handle, int *is_exception); +extern MonoObject* mono_wasm_typed_array_to_array (int js_handle, int *is_exception); +extern MonoObject* mono_wasm_typed_array_copy_to (int js_handle, int ptr, int begin, int end, int bytes_per_element, int *is_exception); +extern MonoObject* mono_wasm_typed_array_from (int ptr, int begin, int end, int bytes_per_element, int type, int *is_exception); +extern MonoObject* mono_wasm_typed_array_copy_from (int js_handle, int ptr, int begin, int end, int bytes_per_element, int *is_exception); + +// Compiles a JavaScript function from the function data passed. +// Note: code snippet is not a function definition. Instead it must create and return a function instance. +EM_JS(MonoObject*, compile_function, (int snippet_ptr, int len, int *is_exception), { + try { + var data = MONO.string_decoder.decode (snippet_ptr, snippet_ptr + len); + var wrapper = '(function () { ' + data + ' })'; + var funcFactory = eval(wrapper); + var func = funcFactory(); + if (typeof func !== 'function') { + throw new Error('Code must return an instance of a JavaScript function. ' + + 'Please use `return` statement to return a function.'); + } + setValue (is_exception, 0, "i32"); + return BINDING.js_to_mono_obj (func); + } + catch (e) + { + res = e.toString (); + setValue (is_exception, 1, "i32"); + if (res === null || res === undefined) + res = "unknown exception"; + return BINDING.js_to_mono_obj (res); + } +}); + +static MonoObject* +mono_wasm_compile_function (MonoString *str, int *is_exception) +{ + if (str == NULL) + return NULL; + //char *native_val = mono_string_to_utf8 (str); + mono_unichar2 *native_val = mono_string_chars (str); + int native_len = mono_string_length (str) * 2; + + MonoObject* native_res = compile_function((int)native_val, native_len, is_exception); + mono_free (native_val); + if (native_res == NULL) + return NULL; + return native_res; +} + +void core_initialize_internals () +{ + mono_add_internal_call ("Interop/Runtime::InvokeJSWithArgs", mono_wasm_invoke_js_with_args); + mono_add_internal_call ("Interop/Runtime::GetObjectProperty", mono_wasm_get_object_property); + mono_add_internal_call ("Interop/Runtime::GetByIndex", mono_wasm_get_by_index); + mono_add_internal_call ("Interop/Runtime::SetObjectProperty", mono_wasm_set_object_property); + mono_add_internal_call ("Interop/Runtime::SetByIndex", mono_wasm_set_by_index); + mono_add_internal_call ("Interop/Runtime::GetGlobalObject", mono_wasm_get_global_object); + mono_add_internal_call ("Interop/Runtime::ReleaseHandle", mono_wasm_release_handle); + mono_add_internal_call ("Interop/Runtime::ReleaseObject", mono_wasm_release_object); + mono_add_internal_call ("Interop/Runtime::NewObjectJS", mono_wasm_new_object); + mono_add_internal_call ("Interop/Runtime::BindCoreObject", mono_wasm_bind_core_object); + mono_add_internal_call ("Interop/Runtime::BindHostObject", mono_wasm_bind_host_object); + mono_add_internal_call ("Interop/Runtime::New", mono_wasm_new); + mono_add_internal_call ("Interop/Runtime::TypedArrayToArray", mono_wasm_typed_array_to_array); + mono_add_internal_call ("Interop/Runtime::TypedArrayCopyTo", mono_wasm_typed_array_copy_to); + mono_add_internal_call ("Interop/Runtime::TypedArrayFrom", mono_wasm_typed_array_from); + mono_add_internal_call ("Interop/Runtime::TypedArrayCopyFrom", mono_wasm_typed_array_copy_from); + mono_add_internal_call ("Interop/Runtime::CompileFunction", mono_wasm_compile_function); + +} + +// Int8Array | int8_t | byte or SByte (signed byte) +// Uint8Array | uint8_t | byte or Byte (unsigned byte) +// Uint8ClampedArray| uint8_t | byte or Byte (unsigned byte) +// Int16Array | int16_t | short (signed short) +// Uint16Array | uint16_t | ushort (unsigned short) +// Int32Array | int32_t | int (signed integer) +// Uint32Array | uint32_t | uint (unsigned integer) +// Float32Array | float | float +// Float64Array | double | double +// typed array marshalling +#define MARSHAL_ARRAY_BYTE 11 +#define MARSHAL_ARRAY_UBYTE 12 +#define MARSHAL_ARRAY_SHORT 13 +#define MARSHAL_ARRAY_USHORT 14 +#define MARSHAL_ARRAY_INT 15 +#define MARSHAL_ARRAY_UINT 16 +#define MARSHAL_ARRAY_FLOAT 17 +#define MARSHAL_ARRAY_DOUBLE 18 + +EMSCRIPTEN_KEEPALIVE MonoArray* +mono_wasm_typed_array_new (char *arr, int length, int size, int type) +{ + MonoClass *typeClass = mono_get_byte_class(); // default is Byte + switch (type) { + case MARSHAL_ARRAY_BYTE: + typeClass = mono_get_sbyte_class(); + break; + case MARSHAL_ARRAY_SHORT: + typeClass = mono_get_int16_class(); + break; + case MARSHAL_ARRAY_USHORT: + typeClass = mono_get_uint16_class(); + break; + case MARSHAL_ARRAY_INT: + typeClass = mono_get_int32_class(); + break; + case MARSHAL_ARRAY_UINT: + typeClass = mono_get_uint32_class(); + break; + case MARSHAL_ARRAY_FLOAT: + typeClass = mono_get_single_class(); + break; + case MARSHAL_ARRAY_DOUBLE: + typeClass = mono_get_double_class(); + break; + } + + MonoArray *buffer; + + buffer = mono_array_new (mono_get_root_domain(), typeClass, length); + memcpy(mono_array_addr_with_size(buffer, sizeof(char), 0), arr, length * size); + + return buffer; +} + +EMSCRIPTEN_KEEPALIVE int +mono_wasm_unbox_enum (MonoObject *obj) +{ + if (!obj) + return 0; + + MonoType *type = mono_class_get_type (mono_object_get_class(obj)); + + void *ptr = mono_object_unbox (obj); + switch (mono_type_get_type(mono_type_get_underlying_type (type))) { + case MONO_TYPE_I1: + case MONO_TYPE_U1: + return *(unsigned char*)ptr; + case MONO_TYPE_I2: + return *(short*)ptr; + case MONO_TYPE_U2: + return *(unsigned short*)ptr; + case MONO_TYPE_I4: + return *(int*)ptr; + case MONO_TYPE_U4: + return *(unsigned int*)ptr; + // WASM doesn't support returning longs to JS + // case MONO_TYPE_I8: + // case MONO_TYPE_U8: + default: + printf ("Invalid type %d to mono_unbox_enum\n", mono_type_get_type(mono_type_get_underlying_type (type))); + return 0; + } +} + + diff --git a/src/mono/wasm/runtime/dotnet_support.js b/src/mono/wasm/runtime/dotnet_support.js new file mode 100644 index 00000000000000..e2db502123e4ad --- /dev/null +++ b/src/mono/wasm/runtime/dotnet_support.js @@ -0,0 +1,96 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +var DotNetSupportLib = { + $DOTNET: { + _dotnet_get_global: function() { + function testGlobal(obj) { + obj['___dotnet_global___'] = obj; + var success = typeof ___dotnet_global___ === 'object' && obj['___dotnet_global___'] === obj; + if (!success) { + delete obj['___dotnet_global___']; + } + return success; + } + if (typeof ___dotnet_global___ === 'object') { + return ___dotnet_global___; + } + if (typeof global === 'object' && testGlobal(global)) { + ___dotnet_global___ = global; + } else if (typeof window === 'object' && testGlobal(window)) { + ___dotnet_global___ = window; + } + if (typeof ___dotnet_global___ === 'object') { + return ___dotnet_global___; + } + throw Error('unable to get DotNet global object.'); + }, + conv_string: function (mono_obj) { + return MONO.string_decoder.copy (mono_obj); + } + }, + mono_wasm_invoke_js_marshalled: function(exceptionMessage, asyncHandleLongPtr, functionName, argsJson) { + + var mono_string = DOTNET._dotnet_get_global()._mono_string_cached + || (DOTNET._dotnet_get_global()._mono_string_cached = Module.cwrap('mono_wasm_string_from_js', 'number', ['string'])); + + try { + // Passing a .NET long into JS via Emscripten is tricky. The method here is to pass + // as pointer to the long, then combine two reads from the HEAPU32 array. + // Even though JS numbers can't represent the full range of a .NET long, it's OK + // because we'll never exceed Number.MAX_SAFE_INTEGER (2^53 - 1) in this case. + //var u32Index = $1 >> 2; + var u32Index = asyncHandleLongPtr >> 2; + var asyncHandleJsNumber = Module.HEAPU32[u32Index + 1]*4294967296 + Module.HEAPU32[u32Index]; + + // var funcNameJsString = UTF8ToString (functionName); + // var argsJsonJsString = argsJson && UTF8ToString (argsJson); + var funcNameJsString = DOTNET.conv_string(functionName); + var argsJsonJsString = argsJson && DOTNET.conv_string (argsJson); + + var dotNetExports = DOTNET._dotnet_get_global().DotNet; + if (!dotNetExports) { + throw new Error('The Microsoft.JSInterop.js library is not loaded.'); + } + + if (asyncHandleJsNumber) { + dotNetExports.jsCallDispatcher.beginInvokeJSFromDotNet(asyncHandleJsNumber, funcNameJsString, argsJsonJsString); + return 0; + } else { + var resultJson = dotNetExports.jsCallDispatcher.invokeJSFromDotNet(funcNameJsString, argsJsonJsString); + return resultJson === null ? 0 : mono_string(resultJson); + } + } catch (ex) { + var exceptionJsString = ex.message + '\n' + ex.stack; + var exceptionSystemString = mono_string(exceptionJsString); + setValue (exceptionMessage, exceptionSystemString, 'i32'); // *exceptionMessage = exceptionSystemString; + return 0; + } + }, + mono_wasm_invoke_js_unmarshalled: function(exceptionMessage, funcName, arg0, arg1, arg2) { + try { + // Get the function you're trying to invoke + var funcNameJsString = DOTNET.conv_string(funcName); + var dotNetExports = DOTNET._dotnet_get_global().DotNet; + if (!dotNetExports) { + throw new Error('The Microsoft.JSInterop.js library is not loaded.'); + } + var funcInstance = dotNetExports.jsCallDispatcher.findJSFunction(funcNameJsString); + + return funcInstance.call(null, arg0, arg1, arg2); + } catch (ex) { + var exceptionJsString = ex.message + '\n' + ex.stack; + var mono_string = Module.cwrap('mono_wasm_string_from_js', 'number', ['string']); // TODO: Cache + var exceptionSystemString = mono_string(exceptionJsString); + setValue (exceptionMessage, exceptionSystemString, 'i32'); // *exceptionMessage = exceptionSystemString; + return 0; + } + } + + +}; + +autoAddDeps(DotNetSupportLib, '$DOTNET') +mergeInto(LibraryManager.library, DotNetSupportLib) + diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c new file mode 100644 index 00000000000000..c55ecba5a4c878 --- /dev/null +++ b/src/mono/wasm/runtime/driver.c @@ -0,0 +1,759 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "pinvoke-table.h" + +#ifdef CORE_BINDINGS +void core_initialize_internals (); +#endif + +// Blazor specific custom routines - see dotnet_support.js for backing code +extern void* mono_wasm_invoke_js_marshalled (MonoString **exceptionMessage, void *asyncHandleLongPtr, MonoString *funcName, MonoString *argsJson); +extern void* mono_wasm_invoke_js_unmarshalled (MonoString **exceptionMessage, MonoString *funcName, void* arg0, void* arg1, void* arg2); + +void mono_wasm_enable_debugging (int); + +void mono_ee_interp_init (const char *opts); +void mono_marshal_ilgen_init (void); +void mono_method_builder_ilgen_init (void); +void mono_sgen_mono_ilgen_init (void); +void mono_icall_table_init (void); +void mono_aot_register_module (void **aot_info); +char *monoeg_g_getenv(const char *variable); +int monoeg_g_setenv(const char *variable, const char *value, int overwrite); +void mono_free (void*); +int32_t mini_parse_debug_option (const char *option); + +static MonoClass* datetime_class; +static MonoClass* datetimeoffset_class; +static MonoClass* uri_class; + +int mono_wasm_enable_gc; + +/* Not part of public headers */ +#define MONO_ICALL_TABLE_CALLBACKS_VERSION 2 + +typedef struct { + int version; + void* (*lookup) (MonoMethod *method, char *classname, char *methodname, char *sigstart, int32_t *uses_handles); + const char* (*lookup_icall_symbol) (void* func); +} MonoIcallTableCallbacks; + +void +mono_install_icall_table_callbacks (const MonoIcallTableCallbacks *cb); + +int mono_regression_test_step (int verbose_level, char *image, char *method_name); +void mono_trace_init (void); + +#define g_new(type, size) ((type *) malloc (sizeof (type) * (size))) +#define g_new0(type, size) ((type *) calloc (sizeof (type), (size))) + +static MonoDomain *root_domain; + +static MonoString* +mono_wasm_invoke_js (MonoString *str, int *is_exception) +{ + if (str == NULL) + return NULL; + + mono_unichar2 *native_val = mono_string_chars (str); + int native_len = mono_string_length (str) * 2; + + mono_unichar2 *native_res = (mono_unichar2*)EM_ASM_INT ({ + var str = MONO.string_decoder.decode ($0, $0 + $1); + try { + var res = eval (str); + if (res === null || res == undefined) + return 0; + res = res.toString (); + setValue ($2, 0, "i32"); + } catch (e) { + res = e.toString (); + setValue ($2, 1, "i32"); + if (res === null || res === undefined) + res = "unknown exception"; + } + var buff = Module._malloc((res.length + 1) * 2); + stringToUTF16 (res, buff, (res.length + 1) * 2); + return buff; + }, (int)native_val, native_len, is_exception); + + if (native_res == NULL) + return NULL; + + MonoString *res = mono_string_from_utf16 (native_res); + free (native_res); + return res; +} + +static void +wasm_logger (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) +{ + if (fatal) { + EM_ASM( + var err = new Error(); + console.log ("Stacktrace: \n"); + console.log (err.stack); + ); + + fprintf (stderr, "%s\n", message); + fflush (stderr); + + abort (); + } else { + fprintf (stdout, "L: %s\n", message); + } +} + +#ifdef DRIVER_GEN +#include "driver-gen.c" +#endif + +typedef struct WasmAssembly_ WasmAssembly; + +struct WasmAssembly_ { + MonoBundledAssembly assembly; + WasmAssembly *next; +}; + +static WasmAssembly *assemblies; +static int assembly_count; + +EMSCRIPTEN_KEEPALIVE void +mono_wasm_add_assembly (const char *name, const unsigned char *data, unsigned int size) +{ + int len = strlen (name); + if (!strcasecmp (".pdb", &name [len - 4])) { + char *new_name = strdup (name); + //FIXME handle debugging assemblies with .exe extension + strcpy (&new_name [len - 3], "dll"); + mono_register_symfile_for_assembly (new_name, data, size); + return; + } + WasmAssembly *entry = g_new0 (WasmAssembly, 1); + entry->assembly.name = strdup (name); + entry->assembly.data = data; + entry->assembly.size = size; + entry->next = assemblies; + assemblies = entry; + ++assembly_count; +} + +EMSCRIPTEN_KEEPALIVE void +mono_wasm_setenv (const char *name, const char *value) +{ + monoeg_g_setenv (strdup (name), strdup (value), 1); +} + +#ifdef ENABLE_NETCORE +static void *sysglobal_native_handle; +#endif + +static void* +wasm_dl_load (const char *name, int flags, char **err, void *user_data) +{ + for (int i = 0; i < sizeof (pinvoke_tables) / sizeof (void*); ++i) { + if (!strcmp (name, pinvoke_names [i])) + return pinvoke_tables [i]; + } + +#ifdef ENABLE_NETCORE + if (!strcmp (name, "System.Globalization.Native")) + return sysglobal_native_handle; +#endif + +#if WASM_SUPPORTS_DLOPEN + return dlopen(name, flags); +#endif + + return NULL; +} + +static mono_bool +wasm_dl_is_pinvoke_tables (void* handle) +{ + for (int i = 0; i < sizeof (pinvoke_tables) / sizeof (void*); ++i) { + if (pinvoke_tables [i] == handle) { + return 1; + } + } + return 0; +} + +static void* +wasm_dl_symbol (void *handle, const char *name, char **err, void *user_data) +{ +#ifdef ENABLE_NETCORE + if (handle == sysglobal_native_handle) + assert (0); +#endif + +#if WASM_SUPPORTS_DLOPEN + if (!wasm_dl_is_pinvoke_tables (handle)) { + return dlsym (handle, name); + } +#endif + + PinvokeImport *table = (PinvokeImport*)handle; + for (int i = 0; table [i].name; ++i) { + if (!strcmp (table [i].name, name)) + return table [i].func; + } + return NULL; +} + +#ifdef ENABLE_NETCORE +/* Missing System.Native symbols */ +int SystemNative_CloseNetworkChangeListenerSocket (int a) { return 0; } +int SystemNative_CreateNetworkChangeListenerSocket (int a) { return 0; } +void SystemNative_ReadEvents (int a,int b) {} +int SystemNative_SchedGetAffinity (int a,int b) { return 0; } +int SystemNative_SchedSetAffinity (int a,int b) { return 0; } +#endif + +#if !defined(ENABLE_AOT) || defined(EE_MODE_LLVMONLY_INTERP) +#define NEED_INTERP 1 +#ifndef LINK_ICALLS +// FIXME: llvm+interp mode needs this to call icalls +#define NEED_NORMAL_ICALL_TABLES 1 +#endif +#endif + +#ifdef LINK_ICALLS + +#include "icall-table.h" + +static int +compare_int (const void *k1, const void *k2) +{ + return *(int*)k1 - *(int*)k2; +} + +static void* +icall_table_lookup (MonoMethod *method, char *classname, char *methodname, char *sigstart, int32_t *uses_handles) +{ + uint32_t token = mono_method_get_token (method); + assert (token); + assert ((token & MONO_TOKEN_METHOD_DEF) == MONO_TOKEN_METHOD_DEF); + uint32_t token_idx = token - MONO_TOKEN_METHOD_DEF; + + int *indexes = NULL; + int indexes_size = 0; + uint8_t *handles = NULL; + void **funcs = NULL; + + *uses_handles = 0; + + const char *image_name = mono_image_get_name (mono_class_get_image (mono_method_get_class (method))); + +#ifdef ICALL_TABLE_mscorlib + if (!strcmp (image_name, "mscorlib") || !strcmp (image_name, "System.Private.CoreLib")) { + indexes = mscorlib_icall_indexes; + indexes_size = sizeof (mscorlib_icall_indexes) / 4; + handles = mscorlib_icall_handles; + funcs = mscorlib_icall_funcs; + assert (sizeof (mscorlib_icall_indexes [0]) == 4); + } +#ifdef ICALL_TABLE_System + if (!strcmp (image_name, "System")) { + indexes = System_icall_indexes; + indexes_size = sizeof (System_icall_indexes) / 4; + handles = System_icall_handles; + funcs = System_icall_funcs; + } +#endif + assert (indexes); + + void *p = bsearch (&token_idx, indexes, indexes_size, 4, compare_int); + if (!p) { + return NULL; + printf ("wasm: Unable to lookup icall: %s\n", mono_method_get_name (method)); + exit (1); + } + + uint32_t idx = (int*)p - indexes; + *uses_handles = handles [idx]; + + //printf ("ICALL: %s %x %d %d\n", methodname, token, idx, (int)(funcs [idx])); + + return funcs [idx]; +#endif +} + +static const char* +icall_table_lookup_symbol (void *func) +{ + assert (0); + return NULL; +} + +#endif + +void mono_initialize_internals () +{ + mono_add_internal_call ("WebAssembly.Runtime::InvokeJS", mono_wasm_invoke_js); + // TODO: what happens when two types in different assemblies have the same FQN? + + // Blazor specific custom routines - see dotnet_support.js for backing code + mono_add_internal_call ("WebAssembly.JSInterop.InternalCalls::InvokeJSMarshalled", mono_wasm_invoke_js_marshalled); + mono_add_internal_call ("WebAssembly.JSInterop.InternalCalls::InvokeJSUnmarshalled", mono_wasm_invoke_js_unmarshalled); + +#ifdef CORE_BINDINGS + core_initialize_internals(); +#endif + +} + +EMSCRIPTEN_KEEPALIVE void +mono_wasm_load_runtime (const char *managed_path, int enable_debugging) +{ + const char *interp_opts = ""; + + monoeg_g_setenv ("MONO_LOG_LEVEL", "debug", 0); + monoeg_g_setenv ("MONO_LOG_MASK", "gc", 0); +#ifdef ENABLE_NETCORE + monoeg_g_setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", 0); +#endif + + mini_parse_debug_option ("top-runtime-invoke-unhandled"); + + mono_dl_fallback_register (wasm_dl_load, wasm_dl_symbol, NULL, NULL); + +#ifdef ENABLE_AOT + // Defined in driver-gen.c + register_aot_modules (); +#ifdef EE_MODE_LLVMONLY_INTERP + mono_jit_set_aot_mode (MONO_AOT_MODE_LLVMONLY_INTERP); +#else + mono_jit_set_aot_mode (MONO_AOT_MODE_LLVMONLY); +#endif +#else + mono_jit_set_aot_mode (MONO_AOT_MODE_INTERP_LLVMONLY); + if (enable_debugging) { + // Disable optimizations which interfere with debugging + interp_opts = "-all"; + mono_wasm_enable_debugging (enable_debugging); + } +#endif + +#ifdef LINK_ICALLS + /* Link in our own linked icall table */ + static const MonoIcallTableCallbacks mono_icall_table_callbacks = + { + MONO_ICALL_TABLE_CALLBACKS_VERSION, + icall_table_lookup, + icall_table_lookup_symbol + }; + mono_install_icall_table_callbacks (&mono_icall_table_callbacks); +#endif + +#ifdef NEED_NORMAL_ICALL_TABLES + mono_icall_table_init (); +#endif +#ifdef NEED_INTERP + mono_ee_interp_init (interp_opts); + mono_marshal_ilgen_init (); + mono_method_builder_ilgen_init (); + mono_sgen_mono_ilgen_init (); +#endif + + if (assembly_count) { + MonoBundledAssembly **bundle_array = g_new0 (MonoBundledAssembly*, assembly_count + 1); + WasmAssembly *cur = assemblies; + int i = 0; + while (cur) { + bundle_array [i] = &cur->assembly; + cur = cur->next; + ++i; + } + mono_register_bundled_assemblies ((const MonoBundledAssembly **)bundle_array); + } + + mono_trace_init (); + mono_trace_set_log_handler (wasm_logger, NULL); + root_domain = mono_jit_init_version ("mono", "v4.0.30319"); + + mono_initialize_internals(); + + mono_thread_set_main (mono_thread_current ()); +} + +EMSCRIPTEN_KEEPALIVE MonoAssembly* +mono_wasm_assembly_load (const char *name) +{ + MonoImageOpenStatus status; + MonoAssemblyName* aname = mono_assembly_name_new (name); + if (!name) + return NULL; + + MonoAssembly *res = mono_assembly_load (aname, NULL, &status); + mono_assembly_name_free (aname); + + return res; +} + +EMSCRIPTEN_KEEPALIVE MonoClass* +mono_wasm_assembly_find_class (MonoAssembly *assembly, const char *namespace, const char *name) +{ + return mono_class_from_name (mono_assembly_get_image (assembly), namespace, name); +} + +EMSCRIPTEN_KEEPALIVE MonoMethod* +mono_wasm_assembly_find_method (MonoClass *klass, const char *name, int arguments) +{ + return mono_class_get_method_from_name (klass, name, arguments); +} + +EMSCRIPTEN_KEEPALIVE MonoObject* +mono_wasm_invoke_method (MonoMethod *method, MonoObject *this_arg, void *params[], MonoObject **out_exc) +{ + MonoObject *exc = NULL; + MonoObject *res; + + if (out_exc) + *out_exc = NULL; + res = mono_runtime_invoke (method, this_arg, params, &exc); + if (exc) { + if (out_exc) + *out_exc = exc; + + MonoObject *exc2 = NULL; + res = (MonoObject*)mono_object_to_string (exc, &exc2); + if (exc2) + res = (MonoObject*) mono_string_new (root_domain, "Exception Double Fault"); + return res; + } + + MonoMethodSignature *sig = mono_method_signature (method); + MonoType *type = mono_signature_get_return_type (sig); + // If the method return type is void return null + // This gets around a memory access crash when the result return a value when + // a void method is invoked. + if (mono_type_get_type (type) == MONO_TYPE_VOID) + return NULL; + + return res; +} + +EMSCRIPTEN_KEEPALIVE MonoMethod* +mono_wasm_assembly_get_entry_point (MonoAssembly *assembly) +{ + MonoImage *image; + MonoMethod *method; + + image = mono_assembly_get_image (assembly); + uint32_t entry = mono_image_get_entry_point (image); + if (!entry) + return NULL; + + return mono_get_method (image, entry, NULL); +} + +EMSCRIPTEN_KEEPALIVE char * +mono_wasm_string_get_utf8 (MonoString *str) +{ + return mono_string_to_utf8 (str); //XXX JS is responsible for freeing this +} + +EMSCRIPTEN_KEEPALIVE void +mono_wasm_string_convert (MonoString *str) +{ + if (str == NULL) + return; + + mono_unichar2 *native_val = mono_string_chars (str); + int native_len = mono_string_length (str) * 2; + + EM_ASM ({ + MONO.string_decoder.decode($0, $0 + $1, true); + }, (int)native_val, native_len); +} + +EMSCRIPTEN_KEEPALIVE MonoString * +mono_wasm_string_from_js (const char *str) +{ + if (str) + return mono_string_new (root_domain, str); + else + return NULL; +} + +static int +class_is_task (MonoClass *klass) +{ + if (!strcmp ("System.Threading.Tasks", mono_class_get_namespace (klass)) && + (!strcmp ("Task", mono_class_get_name (klass)) || !strcmp ("Task`1", mono_class_get_name (klass)))) + return 1; + + return 0; +} + +MonoClass* mono_get_uri_class(MonoException** exc) +{ + MonoAssembly* assembly = mono_wasm_assembly_load ("System"); + if (!assembly) + return NULL; + MonoClass* klass = mono_wasm_assembly_find_class(assembly, "System", "Uri"); + return klass; +} + +#define MARSHAL_TYPE_INT 1 +#define MARSHAL_TYPE_FP 2 +#define MARSHAL_TYPE_STRING 3 +#define MARSHAL_TYPE_VT 4 +#define MARSHAL_TYPE_DELEGATE 5 +#define MARSHAL_TYPE_TASK 6 +#define MARSHAL_TYPE_OBJECT 7 +#define MARSHAL_TYPE_BOOL 8 +#define MARSHAL_TYPE_ENUM 9 +#define MARSHAL_TYPE_DATE 20 +#define MARSHAL_TYPE_DATEOFFSET 21 +#define MARSHAL_TYPE_URI 22 + +// typed array marshalling +#define MARSHAL_ARRAY_BYTE 11 +#define MARSHAL_ARRAY_UBYTE 12 +#define MARSHAL_ARRAY_SHORT 13 +#define MARSHAL_ARRAY_USHORT 14 +#define MARSHAL_ARRAY_INT 15 +#define MARSHAL_ARRAY_UINT 16 +#define MARSHAL_ARRAY_FLOAT 17 +#define MARSHAL_ARRAY_DOUBLE 18 + +EMSCRIPTEN_KEEPALIVE int +mono_wasm_get_obj_type (MonoObject *obj) +{ + if (!obj) + return 0; + + if (!datetime_class) + datetime_class = mono_class_from_name (mono_get_corlib(), "System", "DateTime"); + if (!datetimeoffset_class) + datetimeoffset_class = mono_class_from_name (mono_get_corlib(), "System", "DateTimeOffset"); + if (!uri_class) { + MonoException** exc = NULL; + uri_class = mono_get_uri_class(exc); + } + + MonoClass *klass = mono_object_get_class (obj); + MonoType *type = mono_class_get_type (klass); + + switch (mono_type_get_type (type)) { + // case MONO_TYPE_CHAR: prob should be done not as a number? + case MONO_TYPE_BOOLEAN: + return MARSHAL_TYPE_BOOL; + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_I: // IntPtr + return MARSHAL_TYPE_INT; + case MONO_TYPE_R4: + case MONO_TYPE_R8: + return MARSHAL_TYPE_FP; + case MONO_TYPE_STRING: + return MARSHAL_TYPE_STRING; + case MONO_TYPE_SZARRAY: { // simple zero based one-dim-array + MonoClass *eklass = mono_class_get_element_class(klass); + MonoType *etype = mono_class_get_type (eklass); + + switch (mono_type_get_type (etype)) { + case MONO_TYPE_U1: + return MARSHAL_ARRAY_UBYTE; + case MONO_TYPE_I1: + return MARSHAL_ARRAY_BYTE; + case MONO_TYPE_U2: + return MARSHAL_ARRAY_USHORT; + case MONO_TYPE_I2: + return MARSHAL_ARRAY_SHORT; + case MONO_TYPE_U4: + return MARSHAL_ARRAY_UINT; + case MONO_TYPE_I4: + return MARSHAL_ARRAY_INT; + case MONO_TYPE_R4: + return MARSHAL_ARRAY_FLOAT; + case MONO_TYPE_R8: + return MARSHAL_ARRAY_DOUBLE; + default: + return MARSHAL_TYPE_OBJECT; + } + } + default: + if (klass == datetime_class) + return MARSHAL_TYPE_DATE; + if (klass == datetimeoffset_class) + return MARSHAL_TYPE_DATEOFFSET; + if (uri_class && mono_class_is_assignable_from(uri_class, klass)) + return MARSHAL_TYPE_URI; + if (mono_class_is_enum (klass)) + return MARSHAL_TYPE_ENUM; + if (!mono_type_is_reference (type)) //vt + return MARSHAL_TYPE_VT; + if (mono_class_is_delegate (klass)) + return MARSHAL_TYPE_DELEGATE; + if (class_is_task(klass)) + return MARSHAL_TYPE_TASK; + + return MARSHAL_TYPE_OBJECT; + } +} + +EMSCRIPTEN_KEEPALIVE int +mono_unbox_int (MonoObject *obj) +{ + if (!obj) + return 0; + MonoType *type = mono_class_get_type (mono_object_get_class(obj)); + + void *ptr = mono_object_unbox (obj); + switch (mono_type_get_type (type)) { + case MONO_TYPE_I1: + case MONO_TYPE_BOOLEAN: + return *(signed char*)ptr; + case MONO_TYPE_U1: + return *(unsigned char*)ptr; + case MONO_TYPE_I2: + return *(short*)ptr; + case MONO_TYPE_U2: + return *(unsigned short*)ptr; + case MONO_TYPE_I4: + case MONO_TYPE_I: + return *(int*)ptr; + case MONO_TYPE_U4: + return *(unsigned int*)ptr; + // WASM doesn't support returning longs to JS + // case MONO_TYPE_I8: + // case MONO_TYPE_U8: + default: + printf ("Invalid type %d to mono_unbox_int\n", mono_type_get_type (type)); + return 0; + } +} + +EMSCRIPTEN_KEEPALIVE double +mono_wasm_unbox_float (MonoObject *obj) +{ + if (!obj) + return 0; + MonoType *type = mono_class_get_type (mono_object_get_class(obj)); + + void *ptr = mono_object_unbox (obj); + switch (mono_type_get_type (type)) { + case MONO_TYPE_R4: + return *(float*)ptr; + case MONO_TYPE_R8: + return *(double*)ptr; + default: + printf ("Invalid type %d to mono_wasm_unbox_float\n", mono_type_get_type (type)); + return 0; + } +} + +EMSCRIPTEN_KEEPALIVE int +mono_wasm_array_length (MonoArray *array) +{ + return mono_array_length (array); +} + +EMSCRIPTEN_KEEPALIVE MonoObject* +mono_wasm_array_get (MonoArray *array, int idx) +{ + return mono_array_get (array, MonoObject*, idx); +} + +EMSCRIPTEN_KEEPALIVE MonoArray* +mono_wasm_obj_array_new (int size) +{ + return mono_array_new (root_domain, mono_get_object_class (), size); +} + +EMSCRIPTEN_KEEPALIVE void +mono_wasm_obj_array_set (MonoArray *array, int idx, MonoObject *obj) +{ + mono_array_setref (array, idx, obj); +} + +EMSCRIPTEN_KEEPALIVE MonoArray* +mono_wasm_string_array_new (int size) +{ + return mono_array_new (root_domain, mono_get_string_class (), size); +} + +EMSCRIPTEN_KEEPALIVE int +mono_wasm_exec_regression (int verbose_level, char *image) +{ + return mono_regression_test_step (verbose_level, image, NULL) ? 0 : 1; +} + +EMSCRIPTEN_KEEPALIVE int +mono_wasm_exit (int exit_code) +{ + exit (exit_code); +} + +EMSCRIPTEN_KEEPALIVE void +mono_wasm_set_main_args (int argc, char* argv[]) +{ + mono_runtime_set_main_args (argc, argv); +} + +EMSCRIPTEN_KEEPALIVE int +mono_wasm_strdup (const char *s) +{ + return (int)strdup (s); +} + +EMSCRIPTEN_KEEPALIVE void +mono_wasm_parse_runtime_options (int argc, char* argv[]) +{ + mono_jit_parse_options (argc, argv); +} + +EMSCRIPTEN_KEEPALIVE void +mono_wasm_enable_on_demand_gc (void) +{ + mono_wasm_enable_gc = 1; +} + +// Returns the local timezone default is UTC. +EM_JS(size_t, mono_wasm_timezone_get_local_name, (), +{ + var res = "UTC"; + try { + res = Intl.DateTimeFormat().resolvedOptions().timeZone; + } catch(e) {} + + var buff = Module._malloc((res.length + 1) * 2); + stringToUTF16 (res, buff, (res.length + 1) * 2); + return buff; +}) + +void +mono_timezone_get_local_name (MonoString **result) +{ + // WASM returns back an int pointer to a string UTF16 buffer. + // We then cast to `mono_unichar2*`. Returning `mono_unichar2*` from the JavaScript call will + // result in cast warnings from the compiler. + mono_unichar2 *tzd_local_name = (mono_unichar2*)mono_wasm_timezone_get_local_name (); + *result = mono_string_from_utf16 (tzd_local_name); + free (tzd_local_name); +} diff --git a/src/mono/wasm/runtime/library_mono.js b/src/mono/wasm/runtime/library_mono.js new file mode 100644 index 00000000000000..61e6234949d50f --- /dev/null +++ b/src/mono/wasm/runtime/library_mono.js @@ -0,0 +1,1000 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +var MonoSupportLib = { + $MONO__postset: 'MONO.export_functions (Module);', + $MONO: { + pump_count: 0, + timeout_queue: [], + _vt_stack: [], + mono_wasm_runtime_is_ready : false, + mono_wasm_ignore_pdb_load_errors: true, + pump_message: function () { + if (!this.mono_background_exec) + this.mono_background_exec = Module.cwrap ("mono_background_exec", null); + while (MONO.timeout_queue.length > 0) { + --MONO.pump_count; + MONO.timeout_queue.shift()(); + } + while (MONO.pump_count > 0) { + --MONO.pump_count; + this.mono_background_exec (); + } + }, + + export_functions: function (module) { + module ["pump_message"] = MONO.pump_message; + module ["mono_load_runtime_and_bcl"] = MONO.mono_load_runtime_and_bcl; + }, + + mono_text_decoder: undefined, + string_decoder: { + copy: function (mono_string) { + if (mono_string == 0) + return null; + + if (!this.mono_wasm_string_convert) + this.mono_wasm_string_convert = Module.cwrap ("mono_wasm_string_convert", null, ['number']); + + this.mono_wasm_string_convert (mono_string); + var result = this.result; + this.result = undefined; + return result; + }, + decode: function (start, end, save) { + if (!MONO.mono_text_decoder) { + MONO.mono_text_decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-16le') : undefined; + } + + var str = ""; + if (MONO.mono_text_decoder) { + // When threading is enabled, TextDecoder does not accept a view of a + // SharedArrayBuffer, we must make a copy of the array first. + var subArray = typeof SharedArrayBuffer !== 'undefined' && Module.HEAPU8.buffer instanceof SharedArrayBuffer + ? Module.HEAPU8.slice(start, end) + : Module.HEAPU8.subarray(start, end); + + str = MONO.mono_text_decoder.decode(subArray); + } else { + for (var i = 0; i < end - start; i+=2) { + var char = Module.getValue (start + i, 'i16'); + str += String.fromCharCode (char); + } + } + if (save) + this.result = str; + + return str; + }, + }, + + mono_wasm_get_call_stack: function() { + if (!this.mono_wasm_current_bp_id) + this.mono_wasm_current_bp_id = Module.cwrap ("mono_wasm_current_bp_id", 'number'); + if (!this.mono_wasm_enum_frames) + this.mono_wasm_enum_frames = Module.cwrap ("mono_wasm_enum_frames", null); + + var bp_id = this.mono_wasm_current_bp_id (); + this.active_frames = []; + this.mono_wasm_enum_frames (); + + var the_frames = this.active_frames; + this.active_frames = []; + return { + "breakpoint_id": bp_id, + "frames": the_frames, + }; + }, + + _fixup_name_value_objects: function (var_list) { + var out_list = []; + + var _fixup_value = function (value) { + if (value != null && value != undefined) { + var descr = value.description; + if (descr == null || descr == undefined) + value.description = '' + value.value; + } + return value; + }; + + var i = 0; + while (i < var_list.length) { + var o = var_list [i]; + var name = o.name; + if (name == null || name == undefined) { + i ++; + o.value = _fixup_value(o.value); + out_list.push (o); + continue; + } + + if (i + 1 < var_list.length) + o.value = _fixup_value(var_list[i + 1].value); + + out_list.push (o); + i += 2; + } + + return out_list; + }, + + _filter_automatic_properties: function (props) { + var names_found = {}; + var final_var_list = []; + + for (var i in props) { + var p = props [i]; + if (p.name in names_found) + continue; + + if (p.name.endsWith ("k__BackingField")) + p.name = p.name.replace ("k__BackingField", "") + .replace ('<', '') + .replace ('>', ''); + + names_found [p.name] = p.name; + final_var_list.push (p); + } + + return final_var_list; + }, + + mono_wasm_get_variables: function(scope, var_list) { + if (!this.mono_wasm_get_var_info) + this.mono_wasm_get_var_info = Module.cwrap ("mono_wasm_get_var_info", null, [ 'number', 'number', 'number']); + + this.var_info = []; + var numBytes = var_list.length * Int32Array.BYTES_PER_ELEMENT; + var ptr = Module._malloc(numBytes); + var heapBytes = new Int32Array(Module.HEAP32.buffer, ptr, numBytes); + for (let i=0; i') > 0) + res [i].name = name.substring (1, name.indexOf ('>')); + } + + if (this._async_method_objectId != 0) { + for (let i in res) { + if (res [i].value.isValueType != undefined && res [i].value.isValueType) + res [i].value.objectId = `dotnet:valuetype:${this._async_method_objectId}:${res [i].fieldOffset}`; + } + } + + this._post_process_details(res); + this.var_info = [] + + return res; + }, + + mono_wasm_get_object_properties: function(objId, expandValueTypes) { + if (!this.mono_wasm_get_object_properties_info) + this.mono_wasm_get_object_properties_info = Module.cwrap ("mono_wasm_get_object_properties", null, [ 'number', 'bool' ]); + + this.var_info = []; + this.mono_wasm_get_object_properties_info (objId, expandValueTypes); + + var res = MONO._filter_automatic_properties (MONO._fixup_name_value_objects (this.var_info)); + for (var i = 0; i < res.length; i++) { + if (res [i].value.isValueType != undefined && res [i].value.isValueType) + res [i].value.objectId = `dotnet:valuetype:${objId}:${res [i].fieldOffset}`; + } + + this.var_info = []; + + return res; + }, + + mono_wasm_get_array_values: function(objId) { + if (!this.mono_wasm_get_array_values_info) + this.mono_wasm_get_array_values_info = Module.cwrap ("mono_wasm_get_array_values", null, [ 'number' ]); + + this.var_info = []; + this.mono_wasm_get_array_values_info (objId); + + var res = MONO._fixup_name_value_objects (this.var_info); + for (var i = 0; i < res.length; i++) { + if (res [i].value.isValueType != undefined && res [i].value.isValueType) + res [i].value.objectId = `dotnet:array:${objId}:${i}`; + } + + this.var_info = []; + + return res; + }, + + mono_wasm_get_array_value_expanded: function(objId, idx) { + if (!this.mono_wasm_get_array_value_expanded_info) + this.mono_wasm_get_array_value_expanded_info = Module.cwrap ("mono_wasm_get_array_value_expanded", null, [ 'number', 'number' ]); + + this.var_info = []; + this.mono_wasm_get_array_value_expanded_info (objId, idx); + + var res = MONO._fixup_name_value_objects (this.var_info); + // length should be exactly one! + if (res [0].value.isValueType != undefined && res [0].value.isValueType) + res [0].value.objectId = `dotnet:array:${objId}:${idx}`; + + this.var_info = []; + + return res; + }, + + _post_process_details: function (details) { + if (details == undefined) + return {}; + + if (details.length > 0) + this._extract_and_cache_value_types(details); + + return details; + }, + + _next_value_type_id: function () { + return ++this._next_value_type_id_var; + }, + + _extract_and_cache_value_types: function (var_list) { + if (var_list == undefined || !Array.isArray (var_list) || var_list.length == 0) + return var_list; + + for (let i in var_list) { + var value = var_list [i].value; + if (value == undefined || value.type != "object") + continue; + + if (value.isValueType != true || value.expanded != true) // undefined would also give us false + continue; + + var objectId = value.objectId; + if (objectId == undefined) + objectId = `dotnet:valuetype:${this._next_value_type_id ()}`; + value.objectId = objectId; + + this._extract_and_cache_value_types (value.members); + + this._value_types_cache [objectId] = value.members; + delete value.members; + } + + return var_list; + }, + + _get_details_for_value_type: function (objectId, fetchDetailsFn) { + if (objectId in this._value_types_cache) + return this._value_types_cache[objectId]; + + this._post_process_details (fetchDetailsFn()); + if (objectId in this._value_types_cache) + return this._value_types_cache[objectId]; + + // return error + throw new Error (`Could not get details for ${objectId}`); + }, + + _is_object_id_array: function (objectId) { + // Keep this in sync with `_get_array_details` + return (objectId.startsWith ('dotnet:array:') && objectId.split (':').length == 3); + }, + + _get_array_details: function (objectId, objectIdParts) { + // Keep this in sync with `_is_object_id_array` + switch (objectIdParts.length) { + case 3: + return this._post_process_details (this.mono_wasm_get_array_values(objectIdParts[2])); + + case 4: + var arrayObjectId = objectIdParts[2]; + var arrayIdx = objectIdParts[3]; + return this._get_details_for_value_type( + objectId, () => this.mono_wasm_get_array_value_expanded(arrayObjectId, arrayIdx)); + + default: + throw new Error (`object id format not supported : ${objectId}`); + } + }, + + mono_wasm_get_details: function (objectId, args) { + var parts = objectId.split(":"); + if (parts[0] != "dotnet") + throw new Error ("Can't handle non-dotnet object ids. ObjectId: " + objectId); + + switch (parts[1]) { + case "object": + if (parts.length != 3) + throw new Error(`exception this time: Invalid object id format: ${objectId}`); + + return this._post_process_details(this.mono_wasm_get_object_properties(parts[2], false)); + + case "array": + return this._get_array_details(objectId, parts); + + case "valuetype": + if (parts.length != 3 && parts.length != 4) { + // dotnet:valuetype:vtid + // dotnet:valuetype:containerObjectId:vtId + throw new Error(`Invalid object id format: ${objectId}`); + } + + var containerObjectId = parts[2]; + return this._get_details_for_value_type(objectId, () => this.mono_wasm_get_object_properties(containerObjectId, true)); + + case "cfo_res": { + if (!(objectId in this._call_function_res_cache)) + throw new Error(`Could not find any object with id ${objectId}`); + + var real_obj = this._call_function_res_cache [objectId]; + if (args.accessorPropertiesOnly) { + // var val_accessors = JSON.stringify ([ + // { + // name: "__proto__", + // get: { type: "function", className: "Function", description: "function get __proto__ () {}", objectId: "dotnet:cfo_res:9999" }, + // set: { type: "function", className: "Function", description: "function set __proto__ () {}", objectId: "dotnet:cfo_res:8888" }, + // isOwn: false + // }], undefined, 4); + return { __value_as_json_string__: "[]" }; + } + + // behaving as if (args.ownProperties == true) + var descriptors = Object.getOwnPropertyDescriptors (real_obj); + var own_properties = []; + Object.keys (descriptors).forEach (k => { + var new_obj; + var prop_desc = descriptors [k]; + if (typeof prop_desc.value == "object") { + // convert `{value: { type='object', ... }}` + // to `{ name: 'foo', value: { type='object', ... }} + new_obj = Object.assign ({ name: k}, prop_desc); + } else { + // This is needed for values that were not added by us, + // thus are like { value: 5 } + // instead of { value: { type = 'number', value: 5 }} + // + // This can happen, for eg., when `length` gets added for arrays + // or `__proto__`. + new_obj = { + name: k, + // merge/add `type` and `description` to `d.value` + value: Object.assign ({ type: (typeof prop_desc.value), description: '' + prop_desc.value }, + prop_desc) + }; + } + + own_properties.push (new_obj); + }); + + return { __value_as_json_string__: JSON.stringify (own_properties) }; + } + + default: + throw new Error(`Unknown object id format: ${objectId}`); + } + }, + + _cache_call_function_res: function (obj) { + var id = `dotnet:cfo_res:${this._next_call_function_res_id++}`; + this._call_function_res_cache[id] = obj; + return id; + }, + + mono_wasm_release_object: function (objectId) { + if (objectId in this._cache_call_function_res) + delete this._cache_call_function_res[objectId]; + }, + + mono_wasm_call_function_on: function (request) { + var objId = request.objectId; + var proxy; + + if (objId in this._call_function_res_cache) { + proxy = this._call_function_res_cache [objId]; + } else if (!objId.startsWith ('dotnet:cfo_res:')) { + var details = this.mono_wasm_get_details(objId); + var target_is_array = this._is_object_id_array (objId); + proxy = target_is_array ? [] : {}; + + Object.keys(details).forEach(p => { + var prop = details[p]; + if (target_is_array) { + proxy.push(prop.value); + } else { + if (prop.name != undefined) + proxy [prop.name] = prop.value; + else // when can this happen?? + proxy[''+p] = prop.value; + } + }); + } + + var fn_args = request.arguments != undefined ? request.arguments.map(a => a.value) : []; + var fn_eval_str = `var fn = ${request.functionDeclaration}; fn.call (proxy, ...[${fn_args}]);`; + + var fn_res = eval (fn_eval_str); + if (request.returnByValue) + return fn_res; + + if (fn_res == undefined) + throw Error ('Function returned undefined result'); + + var fn_res_id = this._cache_call_function_res (fn_res); + if (Object.getPrototypeOf (fn_res) == Array.prototype) { + return { + type: "object", + subtype: "array", + className: "Array", + description: `Array(${fn_res.length})`, + objectId: fn_res_id + }; + } else { + return { type: "object", className: "Object", description: "Object", objectId: fn_res_id }; + } + }, + + mono_wasm_start_single_stepping: function (kind) { + console.log (">> mono_wasm_start_single_stepping " + kind); + if (!this.mono_wasm_setup_single_step) + this.mono_wasm_setup_single_step = Module.cwrap ("mono_wasm_setup_single_step", 'number', [ 'number']); + + this._next_value_type_id_var = 0; + this._value_types_cache = {}; + + return this.mono_wasm_setup_single_step (kind); + }, + + mono_wasm_runtime_ready: function () { + this.mono_wasm_runtime_is_ready = true; + // DO NOT REMOVE - magic debugger init function + console.debug ("mono_wasm_runtime_ready", "fe00e07a-5519-4dfe-b35a-f867dbaf2e28"); + + this._next_value_type_id_var = 0; + this._value_types_cache = {}; + + // FIXME: where should this go? + this._next_call_function_res_id = 0; + this._call_function_res_cache = {}; + }, + + mono_wasm_set_breakpoint: function (assembly, method_token, il_offset) { + if (!this.mono_wasm_set_bp) + this.mono_wasm_set_bp = Module.cwrap ('mono_wasm_set_breakpoint', 'number', ['string', 'number', 'number']); + + return this.mono_wasm_set_bp (assembly, method_token, il_offset) + }, + + mono_wasm_remove_breakpoint: function (breakpoint_id) { + if (!this.mono_wasm_del_bp) + this.mono_wasm_del_bp = Module.cwrap ('mono_wasm_remove_breakpoint', 'number', ['number']); + + return this.mono_wasm_del_bp (breakpoint_id); + }, + + // Set environment variable NAME to VALUE + // Should be called before mono_load_runtime_and_bcl () in most cases + mono_wasm_setenv: function (name, value) { + if (!this.wasm_setenv) + this.wasm_setenv = Module.cwrap ('mono_wasm_setenv', null, ['string', 'string']); + this.wasm_setenv (name, value); + }, + + mono_wasm_set_runtime_options: function (options) { + if (!this.wasm_parse_runtime_options) + this.wasm_parse_runtime_options = Module.cwrap ('mono_wasm_parse_runtime_options', null, ['number', 'number']); + var argv = Module._malloc (options.length * 4); + var wasm_strdup = Module.cwrap ('mono_wasm_strdup', 'number', ['string']); + aindex = 0; + for (var i = 0; i < options.length; ++i) { + Module.setValue (argv + (aindex * 4), wasm_strdup (options [i]), "i32"); + aindex += 1; + } + this.wasm_parse_runtime_options (options.length, argv); + }, + + // + // Initialize the AOT profiler with OPTIONS. + // Requires the AOT profiler to be linked into the app. + // options = { write_at: "", send_to: "" } + // should be in the format ::. + // write_at defaults to 'WebAssembly.Runtime::StopProfile'. + // send_to defaults to 'WebAssembly.Runtime::DumpAotProfileData'. + // DumpAotProfileData stores the data into Module.aot_profile_data. + // + mono_wasm_init_aot_profiler: function (options) { + if (options == null) + options = {} + if (!('write_at' in options)) + options.write_at = 'WebAssembly.Runtime::StopProfile'; + if (!('send_to' in options)) + options.send_to = 'WebAssembly.Runtime::DumpAotProfileData'; + var arg = "aot:write-at-method=" + options.write_at + ",send-to-method=" + options.send_to; + Module.ccall ('mono_wasm_load_profiler_aot', null, ['string'], [arg]); + }, + + // options = { write_at: "", send_to: "" } + // should be in the format ::. + // write_at defaults to 'WebAssembly.Runtime::StopProfile'. + // send_to defaults to 'WebAssembly.Runtime::DumpCoverageProfileData'. + // DumpCoverageProfileData stores the data into Module.coverage_profile_data. + mono_wasm_init_coverage_profiler: function (options) { + if (options == null) + options = {} + if (!('write_at' in options)) + options.write_at = 'WebAssembly.Runtime::StopProfile'; + if (!('send_to' in options)) + options.send_to = 'WebAssembly.Runtime::DumpCoverageProfileData'; + var arg = "coverage:write-at-method=" + options.write_at + ",send-to-method=" + options.send_to; + Module.ccall ('mono_wasm_load_profiler_coverage', null, ['string'], [arg]); + }, + + mono_load_runtime_and_bcl: function (vfs_prefix, deploy_prefix, enable_debugging, file_list, loaded_cb, fetch_file_cb) { + var pending = file_list.length; + var loaded_files = []; + var mono_wasm_add_assembly = Module.cwrap ('mono_wasm_add_assembly', null, ['string', 'number', 'number']); + + if (!fetch_file_cb) { + if (ENVIRONMENT_IS_NODE) { + var fs = require('fs'); + fetch_file_cb = function (asset) { + console.log("MONO_WASM: Loading... " + asset); + var binary = fs.readFileSync (asset); + var resolve_func2 = function(resolve, reject) { + resolve(new Uint8Array (binary)); + }; + + var resolve_func1 = function(resolve, reject) { + var response = { + ok: true, + url: asset, + arrayBuffer: function() { + return new Promise(resolve_func2); + } + }; + resolve(response); + }; + + return new Promise(resolve_func1); + }; + } else { + fetch_file_cb = function (asset) { + return fetch (asset, { credentials: 'same-origin' }); + } + } + } + + file_list.forEach (function(file_name) { + + var fetch_promise = fetch_file_cb (locateFile(deploy_prefix + "/" + file_name)); + + fetch_promise.then (function (response) { + if (!response.ok) { + // If it's a 404 on a .pdb, we don't want to block the app from starting up. + // We'll just skip that file and continue (though the 404 is logged in the console). + if (response.status === 404 && file_name.match(/\.pdb$/) && MONO.mono_wasm_ignore_pdb_load_errors) { + --pending; + throw "MONO-WASM: Skipping failed load for .pdb file: '" + file_name + "'"; + } + else { + throw "MONO_WASM: Failed to load file: '" + file_name + "'"; + } + } + else { + loaded_files.push (response.url); + return response ['arrayBuffer'] (); + } + }).then (function (blob) { + var asm = new Uint8Array (blob); + var memory = Module._malloc(asm.length); + var heapBytes = new Uint8Array(Module.HEAPU8.buffer, memory, asm.length); + heapBytes.set (asm); + mono_wasm_add_assembly (file_name, memory, asm.length); + + //console.log ("MONO_WASM: Loaded: " + file_name); + --pending; + if (pending == 0) { + MONO.loaded_files = loaded_files; + var load_runtime = Module.cwrap ('mono_wasm_load_runtime', null, ['string', 'number']); + + console.log ("MONO_WASM: Initializing mono runtime"); + if (ENVIRONMENT_IS_SHELL || ENVIRONMENT_IS_NODE) { + try { + load_runtime (vfs_prefix, enable_debugging); + } catch (ex) { + print ("MONO_WASM: load_runtime () failed: " + ex); + var err = new Error(); + print ("MONO_WASM: Stacktrace: \n"); + print (err.stack); + + var wasm_exit = Module.cwrap ('mono_wasm_exit', null, ['number']); + wasm_exit (1); + } + } else { + load_runtime (vfs_prefix, enable_debugging); + } + MONO.mono_wasm_runtime_ready (); + loaded_cb (); + } + }); + }); + }, + + mono_wasm_get_loaded_files: function() { + console.log(">>>mono_wasm_get_loaded_files"); + return this.loaded_files; + }, + + mono_wasm_clear_all_breakpoints: function() { + if (!this.mono_clear_bps) + this.mono_clear_bps = Module.cwrap ('mono_wasm_clear_all_breakpoints', null); + + this.mono_clear_bps (); + }, + + mono_wasm_add_null_var: function(className) + { + fixed_class_name = MONO._mono_csharp_fixup_class_name(Module.UTF8ToString (className)); + if (!fixed_class_name) { + // Eg, when a @className is passed from js itself, like + // mono_wasm_add_null_var ("string") + fixed_class_name = className; + } + MONO.var_info.push ({value: { + type: "object", + className: fixed_class_name, + description: fixed_class_name, + subtype: "null" + }}); + }, + + _mono_wasm_add_string_var: function(var_value) { + if (var_value == 0) { + MONO.mono_wasm_add_null_var ("string"); + return; + } + + MONO.var_info.push({ + value: { + type: "string", + value: var_value, + } + }); + }, + + _mono_wasm_add_getter_var: function(className) { + fixed_class_name = MONO._mono_csharp_fixup_class_name (className); + var value = `${fixed_class_name} { get; }`; + MONO.var_info.push({ + value: { + type: "symbol", + value: value, + description: value + } + }); + }, + + _mono_wasm_add_array_var: function(className, objectId, length) { + fixed_class_name = MONO._mono_csharp_fixup_class_name(className); + if (objectId == 0) { + MONO.mono_wasm_add_null_var (fixed_class_name); + return; + } + + MONO.var_info.push({ + value: { + type: "object", + subtype: "array", + className: fixed_class_name, + description: `${fixed_class_name}(${length})`, + objectId: "dotnet:array:"+ objectId, + } + }); + }, + + mono_wasm_add_typed_value: function (type, str_value, value) { + var type_str = type; + if (typeof type != 'string') + type_str = Module.UTF8ToString (type); + if (typeof str_value != 'string') + str_value = Module.UTF8ToString (str_value); + + switch (type_str) { + case "bool": + MONO.var_info.push ({ + value: { + type: "boolean", + value: value != 0 + } + }); + break; + + case "char": + MONO.var_info.push ({ + value: { + type: "symbol", + value: `${value} '${String.fromCharCode (value)}'` + } + }); + break; + + case "number": + MONO.var_info.push ({ + value: { + type: "number", + value: value + } + }); + break; + + case "string": + MONO._mono_wasm_add_string_var (str_value); + break; + + case "getter": + MONO._mono_wasm_add_getter_var (str_value); + break; + + case "array": + MONO._mono_wasm_add_array_var (str_value, value.objectId, value.length); + break; + + case "pointer": { + MONO.var_info.push ({ + value: { + type: "symbol", + value: str_value, + description: str_value + } + }); + } + break; + + default: { + var msg = `'${str_value}' ${value}`; + + MONO.var_info.push ({ + value: { + type: "symbol", + value: msg, + description: msg + } + }); + break; + } + } + }, + + _mono_csharp_fixup_class_name: function(className) + { + // Fix up generic names like Foo`2 to Foo + // and nested class names like Foo/Bar to Foo.Bar + return className.replace(/\//g, '.').replace(/`\d+/g, ''); + }, + }, + + mono_wasm_add_typed_value: function (type, str_value, value) { + MONO.mono_wasm_add_typed_value (type, str_value, value); + }, + + mono_wasm_add_properties_var: function(name, field_offset) { + MONO.var_info.push({ + name: Module.UTF8ToString (name), + fieldOffset: field_offset + }); + }, + + mono_wasm_set_is_async_method: function(objectId) { + MONO._async_method_objectId = objectId; + }, + + mono_wasm_begin_value_type_var: function(className, toString) { + fixed_class_name = MONO._mono_csharp_fixup_class_name(Module.UTF8ToString (className)); + var vt_obj = { + value: { + type: "object", + className: fixed_class_name, + description: (toString == 0 ? fixed_class_name : Module.UTF8ToString (toString)), + // objectId will be generated by MonoProxy + expanded: true, + isValueType: true, + members: [] + } + }; + if (MONO._vt_stack.length == 0) + MONO._old_var_info = MONO.var_info; + + MONO.var_info = vt_obj.value.members; + MONO._vt_stack.push (vt_obj); + }, + + mono_wasm_end_value_type_var: function() { + var top_vt_obj_popped = MONO._vt_stack.pop (); + top_vt_obj_popped.value.members = MONO._filter_automatic_properties ( + MONO._fixup_name_value_objects (top_vt_obj_popped.value.members)); + + if (MONO._vt_stack.length == 0) { + MONO.var_info = MONO._old_var_info; + MONO.var_info.push(top_vt_obj_popped); + } else { + var top_obj = MONO._vt_stack [MONO._vt_stack.length - 1]; + top_obj.value.members.push (top_vt_obj_popped); + MONO.var_info = top_obj.value.members; + } + }, + + mono_wasm_add_value_type_unexpanded_var: function (className, toString) { + fixed_class_name = MONO._mono_csharp_fixup_class_name(Module.UTF8ToString (className)); + MONO.var_info.push({ + value: { + type: "object", + className: fixed_class_name, + description: (toString == 0 ? fixed_class_name : Module.UTF8ToString (toString)), + // objectId added when enumerating object's properties + expanded: false, + isValueType: true + } + }); + }, + + mono_wasm_add_enum_var: function(className, members, value) { + // FIXME: flags + // + + // group0: Monday:0 + // group1: Monday + // group2: 0 + var re = new RegExp (`[,]?([^,:]+):(${value}(?=,)|${value}$)`, 'g') + var members_str = Module.UTF8ToString (members); + + var match = re.exec(members_str); + var member_name = match == null ? ('' + value) : match [1]; + + fixed_class_name = MONO._mono_csharp_fixup_class_name(Module.UTF8ToString (className)); + MONO.var_info.push({ + value: { + type: "object", + className: fixed_class_name, + description: member_name, + isEnum: true + } + }); + }, + + mono_wasm_add_array_item: function(position) { + MONO.var_info.push({ + name: `${position}` + }); + }, + + mono_wasm_add_obj_var: function(className, toString, objectId) { + if (objectId == 0) { + MONO.mono_wasm_add_null_var (className); + return; + } + + fixed_class_name = MONO._mono_csharp_fixup_class_name(Module.UTF8ToString (className)); + MONO.var_info.push({ + value: { + type: "object", + className: fixed_class_name, + description: (toString == 0 ? fixed_class_name : Module.UTF8ToString (toString)), + objectId: "dotnet:object:"+ objectId, + } + }); + }, + + /* + * @className, and @targetName are in the following format: + * + * :[]: + */ + mono_wasm_add_func_var: function (className, targetName, objectId) { + if (objectId == 0) { + MONO.mono_wasm_add_null_var ( + MONO._mono_csharp_fixup_class_name (Module.UTF8ToString (className))); + return; + } + + function args_to_sig (args_str) { + var parts = args_str.split (":"); + // TODO: min length = 3? + parts = parts.map (a => MONO._mono_csharp_fixup_class_name (a)); + + // method name at the end + var method_name = parts.pop (); + + // ret type at the beginning + var ret_sig = parts [0]; + var args_sig = parts.splice (1).join (', '); + return `${ret_sig} ${method_name} (${args_sig})`; + } + + var tgt_sig; + if (targetName != 0) + tgt_sig = args_to_sig (Module.UTF8ToString (targetName)); + + var type_name = MONO._mono_csharp_fixup_class_name (Module.UTF8ToString (className)); + + if (objectId == -1) { + // Target property + MONO.var_info.push ({ + value: { + type: "symbol", + value: tgt_sig, + description: tgt_sig, + } + }); + } else { + MONO.var_info.push ({ + value: { + type: "object", + className: type_name, + description: tgt_sig, + objectId: "dotnet:object:" + objectId, + } + }); + } + }, + + mono_wasm_add_frame: function(il, method, assembly_name, method_full_name) { + var parts = Module.UTF8ToString (method_full_name).split (":", 2); + MONO.active_frames.push( { + il_pos: il, + method_token: method, + assembly_name: Module.UTF8ToString (assembly_name), + // Extract just the method name from `{class_name}:{method_name}` + method_name: parts [parts.length - 1] + }); + }, + + schedule_background_exec: function () { + ++MONO.pump_count; + if (ENVIRONMENT_IS_WEB) { + window.setTimeout (MONO.pump_message, 0); + } else if (ENVIRONMENT_IS_WORKER) { + self.setTimeout (MONO.pump_message, 0); + } else if (ENVIRONMENT_IS_NODE) { + global.setTimeout (MONO.pump_message, 0); + } + }, + + mono_set_timeout: function (timeout, id) { + if (!this.mono_set_timeout_exec) + this.mono_set_timeout_exec = Module.cwrap ("mono_set_timeout_exec", null, [ 'number' ]); + if (ENVIRONMENT_IS_WEB) { + window.setTimeout (function () { + this.mono_set_timeout_exec (id); + }, timeout); + } else if (ENVIRONMENT_IS_WORKER) { + self.setTimeout (function () { + this.mono_set_timeout_exec (id); + }, timeout); + } else if (ENVIRONMENT_IS_NODE) { + global.setTimeout (function () { + global.mono_set_timeout_exec (id); + }, timeout); + } else { + ++MONO.pump_count; + MONO.timeout_queue.push(function() { + this.mono_set_timeout_exec (id); + }) + } + }, + + mono_wasm_fire_bp: function () { + console.log ("mono_wasm_fire_bp"); + debugger; + } +}; + +autoAddDeps(MonoSupportLib, '$MONO') +mergeInto(LibraryManager.library, MonoSupportLib) diff --git a/src/mono/wasm/runtime/linker-preserves.xml b/src/mono/wasm/runtime/linker-preserves.xml new file mode 100644 index 00000000000000..2e46279b8793af --- /dev/null +++ b/src/mono/wasm/runtime/linker-preserves.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/mono/wasm/wasm.targets b/src/mono/wasm/wasm.targets new file mode 100644 index 00000000000000..0e088e5cb0751d --- /dev/null +++ b/src/mono/wasm/wasm.targets @@ -0,0 +1,41 @@ + + + + + + $(ArtifactsObjDir)wasm/pinvoke-table.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools-local/dotnet-deb-tool/dotnet-deb-tool.csproj b/tools-local/dotnet-deb-tool/dotnet-deb-tool.csproj index cdbeffee0734fd..fdbc3608f9f05c 100644 --- a/tools-local/dotnet-deb-tool/dotnet-deb-tool.csproj +++ b/tools-local/dotnet-deb-tool/dotnet-deb-tool.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent) diff --git a/tools-local/scripts/dev/master-build-deb-rpm-docker.sh b/tools-local/scripts/dev/master-build-deb-rpm-docker.sh index e96460ece185dc..feb9747aa718fa 100755 --- a/tools-local/scripts/dev/master-build-deb-rpm-docker.sh +++ b/tools-local/scripts/dev/master-build-deb-rpm-docker.sh @@ -62,18 +62,10 @@ package() { shift containerized "$image" bash -c " - eng/common/msbuild.sh \ - tools-local/tasks/installer.tasks/installer.tasks.csproj \ - /t:Restore /t:Build /t:CreateHostMachineInfoFile \ - /p:Configuration=Release \ - /p:TargetOS=Linux \ - /p:PortableBuild=false \ - /p:TargetArchitecture=x64 \ - /bl:artifacts/msbuild.$name.traversaldependencies.binlog; ./build.sh \ --ci \ + --subset installer /p:OfficialBuildId=20190101.1 \ - /p:Subset=Installer \ /p:UsePrebuiltPortableBinariesForInstallers=true \ /p:SharedFrameworkPublishDir=/work/artifacts/obj/linux-x64.Release/sharedFrameworkPublish/ \ /p:InstallerSourceOSPlatformConfig=linux-x64.Release \ diff --git a/tools-local/tasks/installer.tasks/CopyNupkgAndChangeVersion.cs b/tools-local/tasks/installer.tasks/CopyNupkgAndChangeVersion.cs deleted file mode 100644 index 35f7a42121402c..00000000000000 --- a/tools-local/tasks/installer.tasks/CopyNupkgAndChangeVersion.cs +++ /dev/null @@ -1,149 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Build.Framework; -using Newtonsoft.Json.Linq; -using NuGet.Versioning; -using System; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Xml.Linq; - -namespace Microsoft.DotNet.Build.Tasks -{ - public class CopyNupkgAndChangeVersion : BuildTask - { - [Required] - public string SourceFile { get; set; } - - [Required] - public string TargetFile { get; set; } - - [Required] - public string OriginalVersion { get; set; } - - [Required] - public string TargetVersion { get; set; } - - public string[] DependencyPackageIdsToChange { get; set; } - - public override bool Execute() - { - Directory.CreateDirectory(Path.GetDirectoryName(TargetFile)); - File.Copy(SourceFile, TargetFile, true); - - using (ZipArchive zip = ZipFile.Open(TargetFile, ZipArchiveMode.Update)) - { - RewriteNuspec(zip); - RewriteRuntimeJson(zip); - } - - return !Log.HasLoggedErrors; - } - - private void RewriteNuspec(ZipArchive zip) - { - foreach (var nuspec in zip.Entries.Where(e => e.FullName.EndsWith(".nuspec"))) - { - Rewrite(nuspec, s => - { - XDocument content = XDocument.Parse(s); - - RewriteNuspecPackageVersion(content); - RewriteNuspecDependencyVersions(content); - - return content.ToString(); - }); - } - } - - private void RewriteRuntimeJson(ZipArchive zip) - { - foreach (var runtimeJson in zip.Entries.Where(e => e.FullName == "runtime.json")) - { - Rewrite(runtimeJson, s => - { - JObject content = JObject.Parse(s); - - RewriteRuntimeJsonVersions(content); - - return content.ToString(); - }); - } - } - - private void RewriteNuspecPackageVersion(XDocument content) - { - XElement versionElement = content - .Element(CreateQualifiedName(content, "package")) - .Element(CreateQualifiedName(content, "metadata")) - .Element(CreateQualifiedName(content, "version")); - - if (versionElement.Value != OriginalVersion) - { - Log.LogError( - $"Original version is '{versionElement.Value}', " + - $"expected '{OriginalVersion}'"); - } - - versionElement.Value = TargetVersion; - } - - private void RewriteNuspecDependencyVersions(XDocument content) - { - foreach (var dependency in content - .Descendants(CreateQualifiedName(content, "dependency")) - .Where(x => - x.Attribute("version").Value == OriginalVersion && - DependencyPackageIdsToChange?.Contains(x.Attribute("id").Value) == true)) - { - dependency.Value = TargetVersion; - } - } - - private void RewriteRuntimeJsonVersions(JObject content) - { - var versionProperties = content - .Descendants() - .OfType() - .Where(p => - p.Value is JValue v && - v.Type == JTokenType.String); - - foreach (var p in versionProperties) - { - var range = VersionRange.Parse(p.Value.Value()); - - if (range.MinVersion.OriginalVersion == OriginalVersion) - { - var newRange = new VersionRange( - NuGetVersion.Parse(TargetVersion), - range.Float); - - p.Value = newRange.ToString(); - } - } - } - - private static XName CreateQualifiedName(XDocument doc, string name) - { - return doc.Root.GetDefaultNamespace().GetName(name); - } - - private static void Rewrite(ZipArchiveEntry entry, Func rewrite) - { - using (var stream = entry.Open()) - using (var reader = new StreamReader(stream)) - using (var writer = new StreamWriter(stream)) - { - var content = rewrite(reader.ReadToEnd()); - - stream.Position = 0; - stream.SetLength(0); - writer.Write(content); - } - } - } -} diff --git a/tools-local/tasks/installer.tasks/CreateFrameworkListFile.cs b/tools-local/tasks/installer.tasks/CreateFrameworkListFile.cs deleted file mode 100644 index 36a3dd59386c08..00000000000000 --- a/tools-local/tasks/installer.tasks/CreateFrameworkListFile.cs +++ /dev/null @@ -1,211 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Build.Framework; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Xml.Linq; - -namespace Microsoft.DotNet.Build.Tasks -{ - public class CreateFrameworkListFile : BuildTask - { - /// - /// Files to extract basic information from and include in the list. - /// - [Required] - public ITaskItem[] Files { get; set; } - - /// - /// A list of assembly names with classification info such as Profile. A - /// Profile="%(Profile)" attribute is included in the framework list for the matching Files - /// item if %(Profile) contains text. - /// - /// If *any* FileClassifications are passed: - /// - /// *Every* file that ends up listed in the framework list must have a matching - /// FileClassification. - /// - /// Additionally, every FileClassification must find exactly one File. - /// - /// This task fails if the conditions aren't met. This ensures the classification doesn't - /// become out of date when the list of files changes. - /// - /// %(Identity): Assembly name (including ".dll"). - /// %(Profile): List of profiles that apply, semicolon-delimited. - /// %(ReferencedByDefault): Empty (default) or "true"/"false". Indicates whether this file - /// should be referenced by default when the SDK uses this framework. - /// - public ITaskItem[] FileClassifications { get; set; } - - [Required] - public string TargetFile { get; set; } - - public string[] TargetFilePrefixes { get; set; } - - /// - /// Extra attributes to place on the root node. - /// - /// %(Identity): Attribute name. - /// %(Value): Attribute value. - /// - public ITaskItem[] RootAttributes { get; set; } - - public override bool Execute() - { - XAttribute[] rootAttributes = RootAttributes - ?.Select(item => new XAttribute(item.ItemSpec, item.GetMetadata("Value"))) - .ToArray(); - - var frameworkManifest = new XElement("FileList", rootAttributes); - - Dictionary fileClassLookup = FileClassifications - ?.ToDictionary( - item => item.ItemSpec, - item => item, - StringComparer.OrdinalIgnoreCase); - - var usedFileClasses = new HashSet(); - - foreach (var f in Files - .Where(IsTargetPathIncluded) - .Select(item => new - { - Item = item, - Filename = Path.GetFileName(item.ItemSpec), - TargetPath = item.GetMetadata("TargetPath"), - AssemblyName = FileUtilities.GetAssemblyName(item.ItemSpec), - FileVersion = FileUtilities.GetFileVersion(item.ItemSpec), - IsNative = item.GetMetadata("IsNative") == "true", - IsSymbolFile = item.GetMetadata("IsSymbolFile") == "true", - IsResourceFile = item.ItemSpec - .EndsWith(".resources.dll", StringComparison.OrdinalIgnoreCase) - }) - .Where(f => - !f.IsSymbolFile && - (f.Filename.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) || f.IsNative)) - // Remove duplicate files this task is given. - .GroupBy(f => f.Item.ItemSpec) - .Select(g => g.First()) - // Make order stable between builds. - .OrderBy(f => f.TargetPath, StringComparer.Ordinal) - .ThenBy(f => f.Filename, StringComparer.Ordinal)) - { - string type = "Managed"; - - if (f.IsNative) - { - type = "Native"; - } - else if (f.IsResourceFile) - { - type = "Resources"; - } - - string path = Path.Combine(f.TargetPath, f.Filename).Replace('\\', '/'); - - if (path.StartsWith("runtimes/")) - { - var pathParts = path.Split('/'); - if (pathParts.Length > 1 && pathParts[1].Contains("_")) - { - // This file is a runtime file with a "rid" containing "_". This is assumed - // to mean it's a cross-targeting tool and shouldn't be deployed in a - // self-contained app. Leave it off the list. - continue; - } - } - - var element = new XElement( - "File", - new XAttribute("Type", type), - new XAttribute("Path", path)); - - if (f.IsResourceFile) - { - element.Add( - new XAttribute("Culture", Path.GetFileName(Path.GetDirectoryName(path)))); - } - - if (f.AssemblyName != null) - { - byte[] publicKeyToken = f.AssemblyName.GetPublicKeyToken(); - string publicKeyTokenHex; - - if (publicKeyToken != null) - { - publicKeyTokenHex = BitConverter.ToString(publicKeyToken) - .ToLowerInvariant() - .Replace("-", ""); - } - else - { - Log.LogError($"No public key token found for assembly {f.Item.ItemSpec}"); - publicKeyTokenHex = ""; - } - - element.Add( - new XAttribute("AssemblyName", f.AssemblyName.Name), - new XAttribute("PublicKeyToken", publicKeyTokenHex), - new XAttribute("AssemblyVersion", f.AssemblyName.Version)); - } - else if (!f.IsNative) - { - // This file isn't managed and isn't native. Leave it off the list. - continue; - } - - element.Add(new XAttribute("FileVersion", f.FileVersion)); - - if (fileClassLookup != null) - { - if (fileClassLookup.TryGetValue(f.Filename, out ITaskItem classItem)) - { - string profile = classItem.GetMetadata("Profile"); - - if (!string.IsNullOrEmpty(profile)) - { - element.Add(new XAttribute("Profile", profile)); - } - - string referencedByDefault = classItem.GetMetadata("ReferencedByDefault"); - - if (!string.IsNullOrEmpty(referencedByDefault)) - { - element.Add(new XAttribute("ReferencedByDefault", referencedByDefault)); - } - - usedFileClasses.Add(f.Filename); - } - else - { - Log.LogError($"File matches no classification: {f.Filename}"); - } - } - - frameworkManifest.Add(element); - } - - foreach (var unused in fileClassLookup - ?.Keys.Except(usedFileClasses).OrderBy(p => p) - ?? Enumerable.Empty()) - { - Log.LogError($"Classification matches no files: {unused}"); - } - - Directory.CreateDirectory(Path.GetDirectoryName(TargetFile)); - File.WriteAllText(TargetFile, frameworkManifest.ToString()); - - return !Log.HasLoggedErrors; - } - - private bool IsTargetPathIncluded(ITaskItem item) - { - return TargetFilePrefixes - ?.Any(prefix => item.GetMetadata("TargetPath")?.StartsWith(prefix) == true) ?? true; - } - } -} diff --git a/tools-local/tasks/installer.tasks/ExecWithRetries.cs b/tools-local/tasks/installer.tasks/ExecWithRetries.cs deleted file mode 100644 index 5e57c39f458195..00000000000000 --- a/tools-local/tasks/installer.tasks/ExecWithRetries.cs +++ /dev/null @@ -1,116 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// Initially copied from https://github.com/dotnet/buildtools/blob/6736870b84e06b75e7df32bb84d442db1b2afa10/src/Microsoft.DotNet.Build.Tasks/ExecWithRetries.cs - -using Microsoft.Build.Framework; -using Microsoft.Build.Tasks; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.DotNet.Build.Tasks -{ - /// - /// Run a command and retry if the exit code is not 0. - /// - public class ExecWithRetries : BuildTask - { - [Required] - public string Command { get; set; } - - public string WorkingDirectory { get; set; } - - public bool IgnoreStandardErrorWarningFormat { get; set; } - - public int MaxAttempts { get; set; } = 5; - - /// - /// Base, in seconds, raised to the power of the number of retries so far. - /// - public double RetryDelayBase { get; set; } = 6; - - /// - /// A constant, in seconds, added to (base^retries) to find the delay before retrying. - /// - /// The default is -1 to make the first retry instant, because ((base^0)-1) == 0. - /// - public double RetryDelayConstant { get; set; } = -1; - - /// - /// MSBuild message importance to use when logging stdout messages from the command. Default - /// is "High". - /// - public string StandardOutputImportance { get; set; } - - /// - /// MSBuild message importance to use when logging stderr messages from the command. Default - /// is "High". - /// - public string StandardErrorImportance { get; set; } - - private CancellationTokenSource _cancelTokenSource = new CancellationTokenSource(); - - private Exec _runningExec; - - public void Cancel() - { - _runningExec?.Cancel(); - _cancelTokenSource.Cancel(); - } - - public override bool Execute() - { - for (int i = 0; i < MaxAttempts; i++) - { - _runningExec = new Exec - { - BuildEngine = BuildEngine, - Command = Command, - WorkingDirectory = WorkingDirectory, - IgnoreStandardErrorWarningFormat = IgnoreStandardErrorWarningFormat, - StandardOutputImportance = StandardOutputImportance, - StandardErrorImportance = StandardErrorImportance, - LogStandardErrorAsError = false, - IgnoreExitCode = true - }; - - if (!_runningExec.Execute()) - { - Log.LogError("Child Exec task failed to execute."); - break; - } - - int exitCode = _runningExec.ExitCode; - if (exitCode == 0) - { - return true; - } - - string message = $"Exec FAILED: exit code {exitCode} (attempt {i + 1}/{MaxAttempts})"; - - if (i + 1 == MaxAttempts || _cancelTokenSource.IsCancellationRequested) - { - Log.LogError(message); - break; - } - - TimeSpan delay = TimeSpan.FromSeconds( - Math.Pow(RetryDelayBase, i) + RetryDelayConstant); - - Log.LogMessage(MessageImportance.High, $"{message} -- Retrying after {delay}..."); - - try - { - Task.Delay(delay, _cancelTokenSource.Token).Wait(); - } - catch (AggregateException e) when (e.InnerException is TaskCanceledException) - { - break; - } - } - return false; - } - } -} diff --git a/tools-local/tasks/installer.tasks/GenerateDebRepoUploadJsonFile.cs b/tools-local/tasks/installer.tasks/GenerateDebRepoUploadJsonFile.cs deleted file mode 100644 index 51e373915cb277..00000000000000 --- a/tools-local/tasks/installer.tasks/GenerateDebRepoUploadJsonFile.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Build.Framework; -using System.IO; - - -namespace Microsoft.DotNet.Build.Tasks -{ - public partial class GenerateDebRepoUploadJsonFile : BuildTask - { - private const string _debianRevisionNumber = "1"; - [Required] - public string RepoId { get; set; } - [Required] - public string UploadJsonFilename { get; set; } - [Required] - public string PackageName { get; set; } - [Required] - public string PackageVersion { get; set; } - [Required] - public string UploadUrl { get; set; } - - public override bool Execute() - { - File.Delete(UploadJsonFilename); - - using (var fileStream = File.Create(UploadJsonFilename)) - { - using (StreamWriter sw = new StreamWriter(fileStream)) - { - sw.WriteLine("{"); - sw.WriteLine($" \"name\":\"{PackageName}\","); - sw.WriteLine($" \"version\":\"{PackageVersion}-{_debianRevisionNumber}\","); - sw.WriteLine($" \"repositoryId\":\"{RepoId}\","); - sw.WriteLine($" \"sourceUrl\":\"{UploadUrl}\""); - sw.WriteLine("}"); - } - } - return !Log.HasLoggedErrors; - } - } -} \ No newline at end of file diff --git a/tools-local/tasks/installer.tasks/GenerateJsonObjectString.cs b/tools-local/tasks/installer.tasks/GenerateJsonObjectString.cs deleted file mode 100644 index 558c4b1654eeed..00000000000000 --- a/tools-local/tasks/installer.tasks/GenerateJsonObjectString.cs +++ /dev/null @@ -1,145 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Build.Framework; -using System; -using System.IO; -using System.Linq; -using System.Text; - -namespace Microsoft.DotNet.Build.Tasks -{ - public class GenerateJsonObjectString : BuildTask - { - private static readonly string __indent1 = new string(' ', 4); - private static readonly string __indent2 = new string(' ', 8); - - /// - /// Properties to include. If multiple properties have the same name, each property value is - /// included in an array. Only specify one value metadata: the first value is used. - /// - /// %(Identity): Name of the property. - /// %(String): String value of the property. This task adds quotes around it in the JSON. - /// %(Object): Object value of the property. Create this with a nested call to this task. - /// - [Required] - public ITaskItem[] Properties { get; set; } - - /// - /// If set, also write the output JSON string to this file. - /// - public string TargetFile { get; set; } - - [Output] - public string Json { get; set; } - - public override bool Execute() - { - var result = new StringBuilder(); - result.AppendLine("{"); - - bool firstProperty = true; - - foreach (var group in Properties.GroupBy(item => item.ItemSpec)) - { - if (firstProperty) - { - firstProperty = false; - } - else - { - result.AppendLine(","); - } - - result.Append(__indent1); - result.Append("\""); - result.Append(group.Key); - result.Append("\": "); - - if (group.Count() == 1) - { - ITaskItem item = group.First(); - WriteProperty(result, item, __indent1); - } - else - { - result.AppendLine("["); - - bool firstArrayLine = true; - - foreach (ITaskItem item in group) - { - if (firstArrayLine) - { - firstArrayLine = false; - } - else - { - result.AppendLine(","); - } - - result.Append(__indent2); - WriteProperty(result, item, __indent2); - } - - result.AppendLine(); - result.Append(__indent1); - result.Append("]"); - } - } - - result.AppendLine(); - result.AppendLine("}"); - - Json = result.ToString(); - - if (!string.IsNullOrEmpty(TargetFile)) - { - Directory.CreateDirectory(Path.GetDirectoryName(TargetFile)); - File.WriteAllText(TargetFile, Json); - } - - return !Log.HasLoggedErrors; - } - - private void WriteProperty(StringBuilder result, ITaskItem item, string indent) - { - string stringValue = item.GetMetadata("String"); - string objectValue = item.GetMetadata("Object"); - - if (!string.IsNullOrEmpty(stringValue)) - { - result.Append("\""); - result.Append(stringValue); - result.Append("\""); - } - else if (!string.IsNullOrEmpty(objectValue)) - { - bool firstObjectLine = true; - - foreach (var line in objectValue.Split( - new[] {Environment.NewLine}, - StringSplitOptions.RemoveEmptyEntries)) - { - if (firstObjectLine) - { - firstObjectLine = false; - } - else - { - result.AppendLine(); - result.Append(indent); - } - - result.Append(line); - } - } - else - { - Log.LogError($"Item '{item.ItemSpec}' has no String or Object value."); - result.Append("null"); - } - } - } -} diff --git a/tools-local/tasks/installer.tasks/GetTargetMachineInfo.cs b/tools-local/tasks/installer.tasks/GetTargetMachineInfo.cs deleted file mode 100644 index 67aa53b36ec139..00000000000000 --- a/tools-local/tasks/installer.tasks/GetTargetMachineInfo.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Build.Framework; -using System.Runtime.InteropServices; - -namespace Microsoft.DotNet.Build.Tasks -{ - public class GetTargetMachineInfo : BuildTask - { - [Output] - public string TargetOS { get; set; } - - [Output] - public string TargetArch { get; set; } - - [Output] - public string RuntimeIdentifier { get; set; } - - public override bool Execute() - { - switch (RuntimeInformation.OSArchitecture) - { - case Architecture.X64: - TargetArch = "x64"; - break; - case Architecture.X86: - TargetArch = "x86"; - break; - case Architecture.Arm: - TargetArch = "arm"; - break; - case Architecture.Arm64: - TargetArch = "arm64"; - break; - } - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - TargetOS = "Windows_NT"; - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - TargetOS = "Linux"; - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - TargetOS = "OSX"; - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("FREEBSD"))) - TargetOS = "FreeBSD"; - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("NETBSD"))) - TargetOS = "NetBSD"; - - RuntimeIdentifier = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment.GetRuntimeIdentifier(); - - if (TargetArch == null) - { - Log.LogError("{0} is null", nameof(TargetArch)); - return false; - } - - if (TargetOS == null) - { - Log.LogError("{0} is null", nameof(TargetOS)); - return false; - } - - return true; - } - } -} diff --git a/tools-local/tasks/installer.tasks/ProcessSharedFrameworkDeps.cs b/tools-local/tasks/installer.tasks/ProcessSharedFrameworkDeps.cs deleted file mode 100644 index 687a8c1448b756..00000000000000 --- a/tools-local/tasks/installer.tasks/ProcessSharedFrameworkDeps.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using Microsoft.Extensions.DependencyModel; -using NuGet.Common; -using NuGet.ProjectModel; -using System; -using System.IO; -using System.Linq; - -namespace Microsoft.DotNet.Build.Tasks -{ - public partial class ProcessSharedFrameworkDeps : Task - { - [Required] - public string AssetsFilePath { get; set; } - - [Required] - public string DepsFilePath { get; set; } - - [Required] - public string[] PackagesToRemove { get; set; } - - [Required] - public string Runtime { get; set; } - - [Required] - public string BuildTasksAssemblyPath { get; set; } - - public override bool Execute() - { - EnsureInitialized(BuildTasksAssemblyPath); - - ExecuteCore(); - - return true; - } - - private void ExecuteCore() - { - DependencyContext context; - using (var depsStream = File.OpenRead(DepsFilePath)) - { - context = new DependencyContextJsonReader().Read(depsStream); - } - - LockFile lockFile = LockFileUtilities.GetLockFile(AssetsFilePath, NullLogger.Instance); - if (lockFile == null) - { - throw new ArgumentException($"Could not load a LockFile at '{AssetsFilePath}'.", nameof(AssetsFilePath)); - } - - var manager = new RuntimeGraphManager(); - var graph = manager.Collect(lockFile); - var expandedGraph = manager.Expand(graph, Runtime); - - var trimmedRuntimeLibraries = context.RuntimeLibraries; - - if (PackagesToRemove != null && PackagesToRemove.Any()) - { - trimmedRuntimeLibraries = RuntimeReference.RemoveReferences(context.RuntimeLibraries, PackagesToRemove); - } - - context = new DependencyContext( - context.Target, - context.CompilationOptions, - context.CompileLibraries, - trimmedRuntimeLibraries, - expandedGraph - ); - - using (var depsStream = File.Create(DepsFilePath)) - { - new DependencyContextWriter().Write(context, depsStream); - } - } - - partial void EnsureInitialized(string buildTasksAssemblyPath); - } -} diff --git a/tools-local/tasks/installer.tasks/RuntimeGraphManager.cs b/tools-local/tasks/installer.tasks/RuntimeGraphManager.cs deleted file mode 100644 index 2bedeef64b8440..00000000000000 --- a/tools-local/tasks/installer.tasks/RuntimeGraphManager.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Extensions.DependencyModel; -using NuGet.Packaging; -using NuGet.ProjectModel; -using NuGet.RuntimeModel; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace Microsoft.DotNet.Build.Tasks -{ - internal class RuntimeGraphManager - { - private const string RuntimeJsonFileName = "runtime.json"; - - public RuntimeGraph Collect(LockFile lockFile) - { - string userPackageFolder = lockFile.PackageFolders.FirstOrDefault()?.Path; - var fallBackFolders = lockFile.PackageFolders.Skip(1).Select(f => f.Path); - var packageResolver = new FallbackPackagePathResolver(userPackageFolder, fallBackFolders); - - var graph = RuntimeGraph.Empty; - foreach (var library in lockFile.Libraries) - { - if (string.Equals(library.Type, "package", StringComparison.OrdinalIgnoreCase)) - { - var runtimeJson = library.Files.FirstOrDefault(f => f == RuntimeJsonFileName); - if (runtimeJson != null) - { - var libraryPath = packageResolver.GetPackageDirectory(library.Name, library.Version); - var runtimeJsonFullName = Path.Combine(libraryPath, runtimeJson); - graph = RuntimeGraph.Merge(graph, JsonRuntimeFormat.ReadRuntimeGraph(runtimeJsonFullName)); - } - } - } - return graph; - } - - public IEnumerable Expand(RuntimeGraph runtimeGraph, string runtime) - { - var importers = FindImporters(runtimeGraph, runtime); - foreach (var importer in importers) - { - // ExpandRuntime return runtime itself as first item so we are skiping it - yield return new RuntimeFallbacks(importer, runtimeGraph.ExpandRuntime(importer).Skip(1)); - } - } - - private IEnumerable FindImporters(RuntimeGraph runtimeGraph, string runtime) - { - foreach (var runtimePair in runtimeGraph.Runtimes) - { - var expanded = runtimeGraph.ExpandRuntime(runtimePair.Key); - if (expanded.Contains(runtime)) - { - yield return runtimePair.Key; - } - } - } - } -} diff --git a/tools-local/tasks/installer.tasks/RuntimeReference.cs b/tools-local/tasks/installer.tasks/RuntimeReference.cs deleted file mode 100644 index ead20e864c0627..00000000000000 --- a/tools-local/tasks/installer.tasks/RuntimeReference.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Extensions.DependencyModel; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Microsoft.DotNet.Build.Tasks -{ - internal class RuntimeReference - { - public static List RemoveReferences(IReadOnlyList runtimeLibraries, IEnumerable packages) - { - List result = new List(); - - foreach (var runtimeLib in runtimeLibraries) - { - if (string.IsNullOrEmpty(packages.FirstOrDefault(elem => runtimeLib.Name.Equals(elem, StringComparison.OrdinalIgnoreCase)))) - { - List toRemoveDependecy = new List(); - foreach (var dependency in runtimeLib.Dependencies) - { - if (!string.IsNullOrEmpty(packages.FirstOrDefault(elem => dependency.Name.Equals(elem, StringComparison.OrdinalIgnoreCase)))) - { - toRemoveDependecy.Add(dependency); - } - } - - if (toRemoveDependecy.Count > 0) - { - List modifiedDependencies = new List(); - foreach (var dependency in runtimeLib.Dependencies) - { - if (!toRemoveDependecy.Contains(dependency)) - { - modifiedDependencies.Add(dependency); - } - } - - - result.Add(new RuntimeLibrary(runtimeLib.Type, - runtimeLib.Name, - runtimeLib.Version, - runtimeLib.Hash, - runtimeLib.RuntimeAssemblyGroups, - runtimeLib.NativeLibraryGroups, - runtimeLib.ResourceAssemblies, - modifiedDependencies, - runtimeLib.Serviceable)); - - } - else if (string.IsNullOrEmpty(packages.FirstOrDefault(elem => runtimeLib.Name.Equals(elem, StringComparison.OrdinalIgnoreCase)))) - { - result.Add(runtimeLib); - } - } - } - return result; - } - } -} diff --git a/tools-local/tasks/installer.tasks/StabilizeWixFileId.cs b/tools-local/tasks/installer.tasks/StabilizeWixFileId.cs deleted file mode 100644 index 6a76df1df2bd40..00000000000000 --- a/tools-local/tasks/installer.tasks/StabilizeWixFileId.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Build.Framework; -using System; -using System.Diagnostics; -using System.Linq; -using System.Xml.Linq; - -namespace Microsoft.DotNet.Build.Tasks -{ - /// - /// In a WiX source file, replaces the Id of a File with some given string in order to stabilize - /// it. This allows external tooling such as signature validators to rely on a stable identifier - /// for certain files. - /// - public class StabilizeWixFileId : BuildTask - { - /// - /// File to read from. This is expected to be an output from heat.exe. - /// - /// Expected format: - /// - /// - /// - /// - /// - /// - /// - /// ... - /// - [Required] - public string SourceFile { get; set; } - - /// - /// File to write to. May be the same as SourceFile. - /// - [Required] - public string OutputFile { get; set; } - - /// - /// Set of files to stabilize. This matches the end of the "Source" attribute in the WiX - /// source file. If exactly one match isn't found in the WiX source file, this task fails. - /// - /// %(Identity): The file source to replace. - /// %(ReplacementId): The replacement for Id that won't change per-build. - /// - [Required] - public ITaskItem[] FileElementToStabilize { get; set; } - - public override bool Execute() - { - XDocument content = XDocument.Load(SourceFile); - - XNamespace rootNamespace = content.Root.GetDefaultNamespace(); - XName GetQualifiedName(string name) => rootNamespace.GetName(name); - - foreach (var file in FileElementToStabilize) - { - string replacement = file.GetMetadata("ReplacementId"); - - if (string.IsNullOrEmpty(replacement)) - { - Log.LogError($"{nameof(FileElementToStabilize)} {file.ItemSpec} has null/empty ReplacementId metadata."); - continue; - } - - XElement[] matchingFileElements = content.Element(GetQualifiedName("Wix")) - .Elements(GetQualifiedName("Fragment")) - .SelectMany(f => f.Elements(GetQualifiedName("ComponentGroup"))) - .SelectMany(cg => cg.Elements(GetQualifiedName("Component"))) - .SelectMany(c => c.Elements(GetQualifiedName("File"))) - .Where(f => f.Attribute("Source")?.Value - ?.EndsWith(file.ItemSpec, StringComparison.OrdinalIgnoreCase) == true) - .ToArray(); - - if (matchingFileElements.Length != 1) - { - Log.LogError( - $"Expected 1 match for '{file.ItemSpec}', found {matchingFileElements.Length}: " + - string.Join(", ", matchingFileElements.Select(e => e.ToString()))); - - continue; - } - - XAttribute nameAttribute = matchingFileElements[0].Attribute("Id"); - - if (nameAttribute is null) - { - Log.LogError($"Match has no Id attribute: {matchingFileElements[0]}"); - continue; - } - - Log.LogMessage( - $"Setting '{file.ItemSpec}' Id to '{replacement}' for File with Source " + - matchingFileElements[0].Attribute("Source").Value); - - nameAttribute.Value = replacement; - } - - content.Save(OutputFile); - - return !Log.HasLoggedErrors; - } - } -} diff --git a/tools-local/tasks/installer.tasks/ZipFileExtractToDirectory.cs b/tools-local/tasks/installer.tasks/ZipFileExtractToDirectory.cs deleted file mode 100644 index e03a860819ec33..00000000000000 --- a/tools-local/tasks/installer.tasks/ZipFileExtractToDirectory.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Build.Framework; -using System; -using System.IO; -using System.IO.Compression; - -namespace Microsoft.DotNet.Build.Tasks -{ - public sealed class ZipFileExtractToDirectory : BuildTask - { - /// - /// The path to the archive to be extracted. - /// - [Required] - public string SourceArchive { get; set; } - - /// - /// The path of the directory to extract into. - /// - [Required] - public string DestinationDirectory { get; set; } - - /// - /// Indicates if the destination directory should be overwritten if it already exists. - /// - public bool OverwriteDestination { get; set; } - - /// - /// File entries to include in the extraction. Entries are relative - /// paths inside the archive. If null or empty, all files are extracted. - /// - public ITaskItem[] Include { get; set; } - - public override bool Execute() - { - try - { - if (Directory.Exists(DestinationDirectory)) - { - if (OverwriteDestination) - { - Log.LogMessage(MessageImportance.Low, $"'{DestinationDirectory}' already exists, trying to delete before unzipping..."); - Directory.Delete(DestinationDirectory, recursive: true); - } - else - { - Log.LogWarning($"'{DestinationDirectory}' already exists. Did you forget to set '{nameof(OverwriteDestination)}' to true?"); - } - } - - Log.LogMessage(MessageImportance.High, "Decompressing '{0}' into '{1}'...", SourceArchive, DestinationDirectory); - Directory.CreateDirectory(Path.GetDirectoryName(DestinationDirectory)); - - using (ZipArchive archive = ZipFile.OpenRead(SourceArchive)) - { - if (Include?.Length > 0) - { - foreach (ITaskItem entryItem in Include) - { - ZipArchiveEntry entry = archive.GetEntry(entryItem.ItemSpec); - string destinationPath = Path.Combine(DestinationDirectory, entryItem.ItemSpec); - - Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); - entry.ExtractToFile(destinationPath, overwrite: false); - } - } - else - { - archive.ExtractToDirectory(DestinationDirectory); - } - } - } - catch (Exception e) - { - // We have 2 log calls because we want a nice error message but we also want to capture the callstack in the log. - Log.LogError("An exception has occurred while trying to decompress '{0}' into '{1}'.", SourceArchive, DestinationDirectory); - Log.LogErrorFromException(e, /*show stack=*/ true, /*show detail=*/ true, DestinationDirectory); - return false; - } - return true; - } - } -} diff --git a/tools-local/tasks/installer.tasks/ZipFileGetEntries.cs b/tools-local/tasks/installer.tasks/ZipFileGetEntries.cs deleted file mode 100644 index 56b1e3804e1870..00000000000000 --- a/tools-local/tasks/installer.tasks/ZipFileGetEntries.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using System; -using System.IO.Compression; -using System.Linq; - -namespace Microsoft.DotNet.Build.Tasks -{ - public sealed class ZipFileGetEntries : BuildTask - { - /// - /// The path to the archive. - /// - [Required] - public string TargetArchive { get; set; } - - /// - /// Generated items where each ItemSpec is the relative location of a - /// file entry in the zip archive. - /// - [Output] - public ITaskItem[] Entries { get; set; } - - public override bool Execute() - { - try - { - using (ZipArchive archive = ZipFile.OpenRead(TargetArchive)) - { - Entries = archive.Entries - // Escape '%' so encoded '+' in the nupkg stays encoded through MSBuild. - .Select(e => new TaskItem(e.FullName.Replace("%", "%25"))) - .ToArray(); - } - } - catch (Exception e) - { - // We have 2 log calls because we want a nice error message but we also want to capture the callstack in the log. - Log.LogError($"An exception has occurred while trying to read entries from '{TargetArchive}'."); - Log.LogErrorFromException(e, /*show stack=*/ true, /*show detail=*/ true, TargetArchive); - return false; - } - return true; - } - } -} diff --git a/tools-local/tasks/installer.tasks/installer.tasks.csproj b/tools-local/tasks/installer.tasks/installer.tasks.csproj index 2ed742bb359556..356f22ac74eb9c 100644 --- a/tools-local/tasks/installer.tasks/installer.tasks.csproj +++ b/tools-local/tasks/installer.tasks/installer.tasks.csproj @@ -1,5 +1,4 @@ - - + netstandard2.0 $(TargetFrameworks);net46 @@ -14,7 +13,6 @@ - @@ -44,28 +42,4 @@ - - - - - - - - - -<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <HostMachineRid>$(HostMachineRid)</HostMachineRid> - </PropertyGroup> -</Project> - - - - - - diff --git a/tools-local/tasks/mobile.tasks/AndroidAppBuilder/AndroidAppBuilder.cs b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/AndroidAppBuilder.cs new file mode 100644 index 00000000000000..baaa1c7f18e2fe --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/AndroidAppBuilder.cs @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +public class AndroidAppBuilderTask : Task +{ + [Required] + public string SourceDir { get; set; } = ""!; + + [Required] + public string MonoRuntimeHeaders { get; set; } = ""!; + + /// + /// This library will be used as an entry-point (e.g. TestRunner.dll) + /// + [Required] + public string MainLibraryFileName { get; set; } = ""!; + + /// + /// Target arch, can be 'x86', 'x86_64', 'armeabi-v7a' or 'arm64-v8a' + /// + [Required] + public string Abi { get; set; } = ""!; + + public string? ProjectName { get; set; } + + public string? OutputDir { get; set; } + + public string? AndroidSdk { get; set; } + + public string? AndroidNdk { get; set; } + + public string? MinApiLevel { get; set; } + + public string? BuildApiLevel { get; set; } + + public string? BuildToolsVersion { get; set; } + + public bool StripDebugSymbols { get; set; } + + [Output] + public string ApkBundlePath { get; set; } = ""!; + + [Output] + public string ApkPackageId { get; set; } = ""!; + + public override bool Execute() + { + Utils.Logger = Log; + + var apkBuilder = new ApkBuilder(); + apkBuilder.ProjectName = ProjectName; + apkBuilder.OutputDir = OutputDir; + apkBuilder.AndroidSdk = AndroidSdk; + apkBuilder.AndroidNdk = AndroidNdk; + apkBuilder.MinApiLevel = MinApiLevel; + apkBuilder.BuildApiLevel = BuildApiLevel; + apkBuilder.BuildToolsVersion = BuildToolsVersion; + apkBuilder.StripDebugSymbols = StripDebugSymbols; + (ApkBundlePath, ApkPackageId) = apkBuilder.BuildApk(SourceDir, Abi, MainLibraryFileName, MonoRuntimeHeaders); + + return true; + } +} diff --git a/tools-local/tasks/mobile.tasks/AndroidAppBuilder/AndroidAppBuilder.csproj b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/AndroidAppBuilder.csproj new file mode 100644 index 00000000000000..179ca9aa2af4ab --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/AndroidAppBuilder.csproj @@ -0,0 +1,23 @@ + + + $(NetCoreAppCurrent) + Library + true + false + enable + + + + + + + + + + + + + + + + diff --git a/tools-local/tasks/mobile.tasks/AndroidAppBuilder/ApkBuilder.cs b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/ApkBuilder.cs new file mode 100644 index 00000000000000..e7fcebdd08eb1f --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/ApkBuilder.cs @@ -0,0 +1,281 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +public class ApkBuilder +{ + private const string DefaultMinApiLevel = "21"; + + public string? ProjectName { get; set; } + public string? AndroidNdk { get; set; } + public string? AndroidSdk { get; set; } + public string? MinApiLevel { get; set; } + public string? BuildApiLevel { get; set; } + public string? BuildToolsVersion { get; set; } + public string? OutputDir { get; set; } + public bool StripDebugSymbols { get; set; } + + public (string apk, string packageId) BuildApk( + string sourceDir, string abi, string entryPointLib, string monoRuntimeHeaders) + { + if (!Directory.Exists(sourceDir)) + throw new ArgumentException($"sourceDir='{sourceDir}' is empty or doesn't exist"); + + if (string.IsNullOrEmpty(abi)) + throw new ArgumentException("abi shoudln't be empty (e.g. x86, x86_64, armeabi-v7a or arm64-v8a"); + + if (string.IsNullOrEmpty(entryPointLib)) + throw new ArgumentException("entryPointLib shouldn't be empty"); + + if (!File.Exists(Path.Combine(sourceDir, entryPointLib))) + throw new ArgumentException($"{entryPointLib} was not found in sourceDir='{sourceDir}'"); + + if (string.IsNullOrEmpty(ProjectName)) + ProjectName = Path.GetFileNameWithoutExtension(entryPointLib); + + if (string.IsNullOrEmpty(OutputDir)) + OutputDir = Path.Combine(sourceDir, "bin-" + abi); + + if (ProjectName.Contains(' ')) + throw new ArgumentException($"ProjectName='{ProjectName}' shouldn't not contain spaces."); + + if (string.IsNullOrEmpty(AndroidSdk)) + AndroidSdk = Environment.GetEnvironmentVariable("ANDROID_SDK_ROOT"); + + if (string.IsNullOrEmpty(AndroidNdk)) + AndroidNdk = Environment.GetEnvironmentVariable("ANDROID_NDK_ROOT"); + + if (string.IsNullOrEmpty(AndroidSdk) || !Directory.Exists(AndroidSdk)) + throw new ArgumentException($"Android SDK='{AndroidSdk}' was not found or empty (can be set via ANDROID_SDK_ROOT envvar)."); + + if (string.IsNullOrEmpty(AndroidNdk) || !Directory.Exists(AndroidNdk)) + throw new ArgumentException($"Android NDK='{AndroidNdk}' was not found or empty (can be set via ANDROID_NDK_ROOT envvar)."); + + // Try to get the latest build-tools version if not specified + if (string.IsNullOrEmpty(BuildToolsVersion)) + BuildToolsVersion = GetLatestBuildTools(AndroidSdk); + + // Try to get the latest API level if not specified + if (string.IsNullOrEmpty(BuildApiLevel)) + BuildApiLevel = GetLatestApiLevel(AndroidSdk); + + if (string.IsNullOrEmpty(MinApiLevel)) + MinApiLevel = DefaultMinApiLevel; + + // make sure BuildApiLevel >= MinApiLevel + // only if these api levels are not "preview" (not integers) + if (int.TryParse(BuildApiLevel, out int intApi) && + int.TryParse(MinApiLevel, out int intMinApi) && + intApi < intMinApi) + { + throw new ArgumentException($"BuildApiLevel={BuildApiLevel} <= MinApiLevel={MinApiLevel}. " + + "Make sure you've downloaded some recent build-tools in Android SDK"); + } + + string buildToolsFolder = Path.Combine(AndroidSdk, "build-tools", BuildToolsVersion); + if (!Directory.Exists(buildToolsFolder)) + throw new ArgumentException($"{buildToolsFolder} was not found."); + + Directory.CreateDirectory(OutputDir); + Directory.CreateDirectory(Path.Combine(OutputDir, "bin")); + Directory.CreateDirectory(Path.Combine(OutputDir, "obj")); + Directory.CreateDirectory(Path.Combine(OutputDir, "assets-tozip")); + Directory.CreateDirectory(Path.Combine(OutputDir, "assets")); + + var extensionsToIgnore = new List { ".so", ".a", ".gz" }; + if (StripDebugSymbols) + { + extensionsToIgnore.Add(".pdb"); + extensionsToIgnore.Add(".dbg"); + } + + // Copy AppDir to OutputDir/assets-tozip (ignore native files) + // these files then will be zipped and copied to apk/assets/assets.zip + Utils.DirectoryCopy(sourceDir, Path.Combine(OutputDir, "assets-tozip"), file => + { + string fileName = Path.GetFileName(file); + string extension = Path.GetExtension(file); + + if (extensionsToIgnore.Contains(extension)) + { + // ignore native files, those go to lib/%abi% + // also, aapt is not happy about zip files + return false; + } + if (fileName.StartsWith(".")) + { + // aapt complains on such files + return false; + } + return true; + }); + + // tools: + string dx = Path.Combine(buildToolsFolder, "dx"); + string aapt = Path.Combine(buildToolsFolder, "aapt"); + string zipalign = Path.Combine(buildToolsFolder, "zipalign"); + string apksigner = Path.Combine(buildToolsFolder, "apksigner"); + string androidJar = Path.Combine(AndroidSdk, "platforms", "android-" + BuildApiLevel, "android.jar"); + string androidToolchain = Path.Combine(AndroidNdk, "build", "cmake", "android.toolchain.cmake"); + string keytool = "keytool"; + string javac = "javac"; + string cmake = "cmake"; + string zip = "zip"; + + Utils.RunProcess(zip, workingDir: Path.Combine(OutputDir, "assets-tozip"), args: "-q -r ../assets/assets.zip ."); + Directory.Delete(Path.Combine(OutputDir, "assets-tozip"), true); + + if (!File.Exists(androidJar)) + throw new ArgumentException($"API level={BuildApiLevel} is not downloaded in Android SDK"); + + // 1. Build libruntime-android.so` via cmake + + string monoRuntimeLib = Path.Combine(sourceDir, "libmonosgen-2.0.a"); + if (!File.Exists(monoRuntimeLib)) + throw new ArgumentException($"libmonosgen-2.0.a was not found in {sourceDir}"); + + string cmakeLists = Utils.GetEmbeddedResource("CMakeLists-android.txt") + .Replace("%MonoInclude%", monoRuntimeHeaders) + .Replace("%NativeLibrariesToLink%", monoRuntimeLib); + File.WriteAllText(Path.Combine(OutputDir, "CMakeLists.txt"), cmakeLists); + + string runtimeAndroidSrc = Utils.GetEmbeddedResource("runtime-android.c") + .Replace("%EntryPointLibName%", Path.GetFileName(entryPointLib) + .Replace("%RID%", GetRid(abi))); + File.WriteAllText(Path.Combine(OutputDir, "runtime-android.c"), runtimeAndroidSrc); + + string cmakeGenArgs = $"-DCMAKE_TOOLCHAIN_FILE={androidToolchain} -DANDROID_ABI=\"{abi}\" -DANDROID_STL=none " + + $"-DANDROID_NATIVE_API_LEVEL={MinApiLevel} -B runtime-android"; + + string cmakeBuildArgs = "--build runtime-android"; + + if (StripDebugSymbols) + { + // Use "-s" to strip debug symbols, it complains it's unused but it works + cmakeGenArgs+= " -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_C_FLAGS=\"-s -Wno-unused-command-line-argument\""; + cmakeBuildArgs += " --config MinSizeRel"; + } + else + { + cmakeGenArgs += " -DCMAKE_BUILD_TYPE=Debug"; + cmakeBuildArgs += " --config Debug"; + } + + Utils.RunProcess(cmake, workingDir: OutputDir, args: cmakeGenArgs); + Utils.RunProcess(cmake, workingDir: OutputDir, args: cmakeBuildArgs); + + // 2. Compile Java files + + string javaSrcFolder = Path.Combine(OutputDir, "src", "net", "dot"); + Directory.CreateDirectory(javaSrcFolder); + + string packageId = $"net.dot.{ProjectName}"; + + File.WriteAllText(Path.Combine(javaSrcFolder, "MainActivity.java"), + Utils.GetEmbeddedResource("MainActivity.java")); + File.WriteAllText(Path.Combine(javaSrcFolder, "MonoRunner.java"), + Utils.GetEmbeddedResource("MonoRunner.java")); + File.WriteAllText(Path.Combine(OutputDir, "AndroidManifest.xml"), + Utils.GetEmbeddedResource("AndroidManifest.xml") + .Replace("%PackageName%", packageId) + .Replace("%MinSdkLevel%", MinApiLevel)); + + string javaCompilerArgs = $"-d obj -classpath src -bootclasspath {androidJar} -source 1.8 -target 1.8 "; + Utils.RunProcess(javac, javaCompilerArgs + Path.Combine(javaSrcFolder, "MainActivity.java"), workingDir: OutputDir); + Utils.RunProcess(javac, javaCompilerArgs + Path.Combine(javaSrcFolder, "MonoRunner.java"), workingDir: OutputDir); + Utils.RunProcess(dx, "--dex --output=classes.dex obj", workingDir: OutputDir); + + // 3. Generate APK + + string apkFile = Path.Combine(OutputDir, "bin", $"{ProjectName}.unaligned.apk"); + Utils.RunProcess(aapt, $"package -f -m -F {apkFile} -A assets -M AndroidManifest.xml -I {androidJar}", workingDir: OutputDir); + + var dynamicLibs = new List(); + dynamicLibs.Add(Path.Combine(OutputDir, "runtime-android", "libruntime-android.so")); + dynamicLibs.AddRange(Directory.GetFiles(sourceDir, "*.so")); + + // add all *.so files to lib/%abi%/ + Directory.CreateDirectory(Path.Combine(OutputDir, "lib", abi)); + foreach (var dynamicLib in dynamicLibs) + { + string dynamicLibName = Path.GetFileName(dynamicLib); + if (dynamicLibName == "libmonosgen-2.0.so") + { + // we link mono runtime statically into libruntime-android.so + continue; + } + + // NOTE: we can run android-strip tool from NDK to shrink native binaries here even more. + + string destRelative = Path.Combine("lib", abi, dynamicLibName); + File.Copy(dynamicLib, Path.Combine(OutputDir, destRelative), true); + Utils.RunProcess(aapt, $"add {apkFile} {destRelative}", workingDir: OutputDir); + } + Utils.RunProcess(aapt, $"add {apkFile} classes.dex", workingDir: OutputDir); + + // 4. Align APK + + string alignedApk = Path.Combine(OutputDir, "bin", $"{ProjectName}.apk"); + Utils.RunProcess(zipalign, $"-v 4 {apkFile} {alignedApk}", workingDir: OutputDir); + // we don't need the unaligned one any more + File.Delete(apkFile); + + // 5. Generate key + + string signingKey = Path.Combine(OutputDir, "debug.keystore"); + if (!File.Exists(signingKey)) + { + Utils.RunProcess(keytool, "-genkey -v -keystore debug.keystore -storepass android -alias " + + "androiddebugkey -keypass android -keyalg RSA -keysize 2048 -noprompt " + + "-dname \"CN=Android Debug,O=Android,C=US\"", workingDir: OutputDir, silent: true); + } + + // 6. Sign APK + + Utils.RunProcess(apksigner, $"sign --min-sdk-version {MinApiLevel} --ks debug.keystore " + + $"--ks-pass pass:android --key-pass pass:android {alignedApk}", workingDir: OutputDir); + + Utils.LogInfo($"\nAPK size: {(new FileInfo(alignedApk).Length / 1000_000.0):0.#} Mb.\n"); + + return (alignedApk, packageId); + } + + private static string GetRid(string abi) => abi switch + { + "arm64-v8a" => "android-arm64", + "armeabi-v7a" => "android-arm", + "x86_64" => "android-x64", + _ => "android-" + abi + }; + + /// + /// Scan android SDK for build tools (ignore preview versions) + /// + private static string GetLatestBuildTools(string androidSdkDir) + { + string? buildTools = Directory.GetDirectories(Path.Combine(androidSdkDir, "build-tools")) + .Select(Path.GetFileName) + .Where(file => !file!.Contains("-")) + .Select(file => Version.TryParse(Path.GetFileName(file), out Version? version) ? version : default) + .OrderByDescending(v => v) + .FirstOrDefault()?.ToString(); + + if (string.IsNullOrEmpty(buildTools)) + throw new ArgumentException($"Android SDK ({androidSdkDir}) doesn't contain build-tools."); + + return buildTools; + } + + /// + /// Scan android SDK for api levels (ignore preview versions) + /// + private static string GetLatestApiLevel(string androidSdkDir) + { + return Directory.GetDirectories(Path.Combine(androidSdkDir, "platforms")) + .Select(file => int.TryParse(Path.GetFileName(file).Replace("android-", ""), out int apiLevel) ? apiLevel : -1) + .OrderByDescending(v => v) + .FirstOrDefault() + .ToString(); + } +} diff --git a/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/AndroidManifest.xml b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/AndroidManifest.xml new file mode 100644 index 00000000000000..12371dbd782af8 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/CMakeLists-android.txt b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/CMakeLists-android.txt new file mode 100644 index 00000000000000..18727daa906057 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/CMakeLists-android.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.10) + +project(runtime-android) + +add_library( + runtime-android + SHARED + runtime-android.c) + +include_directories("%MonoInclude%") + +target_link_libraries( + runtime-android + %NativeLibrariesToLink% + libz.so + log + "-u GlobalizationNative_LoadICU" + "-u GlobalizationNative_GetLatestJapaneseEra" + "-u GlobalizationNative_ChangeCase" + "-u GlobalizationNative_CloseSortHandle" + "-u GlobalizationNative_GetLocales" + "-u GlobalizationNative_GetLocaleInfoInt" + "-u GlobalizationNative_GetLocaleTimeFormat" + "-u GlobalizationNative_ToUnicode" + "-u GlobalizationNative_NormalizeString" + "-u GlobalizationNative_GetTimeZoneDisplayName") diff --git a/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/MainActivity.java b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/MainActivity.java new file mode 100644 index 00000000000000..2d9114fd3b52b8 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/MainActivity.java @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +package net.dot; + +import android.app.AlertDialog; +import android.app.Activity; +import android.os.Bundle; + +public class MainActivity extends Activity +{ + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this); + dlgAlert.setMessage("Use `adb shell am instrument -w " + getApplicationContext().getPackageName() + "net.dot.MonoRunner` to run the tests."); + dlgAlert.create().show(); + } +} diff --git a/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/MonoRunner.java b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/MonoRunner.java new file mode 100644 index 00000000000000..6acedccf6ac2e2 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/MonoRunner.java @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +package net.dot; + +import android.app.Instrumentation; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.res.AssetManager; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.app.Activity; +import android.os.Environment; +import android.net.Uri; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.BufferedInputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +public class MonoRunner extends Instrumentation +{ + static MonoRunner inst; + + static { + System.loadLibrary("runtime-android"); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + start(); + } + + @Override + public void onStart() { + super.onStart(); + + MonoRunner.inst = this; + Context context = getContext(); + String filesDir = context.getFilesDir().getAbsolutePath(); + String cacheDir = context.getCacheDir().getAbsolutePath(); + File docsPath = context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS); + if (docsPath == null) { + docsPath = context.getCacheDir(); + } + String docsDir = docsPath.getAbsolutePath(); + + // unzip libs and test files to filesDir + unzipAssets(context, filesDir, "assets.zip"); + + Log.i("DOTNET", "initRuntime"); + int retcode = initRuntime(filesDir, cacheDir, docsDir); + runOnMainSync(new Runnable() { + public void run() { + Bundle result = new Bundle(); + result.putInt("return-code", retcode); + // Xharness cli expects "test-results-path" with test results + result.putString("test-results-path", docsDir + "/testResults.xml"); + finish(retcode, result); + } + }); + } + + static void unzipAssets(Context context, String toPath, String zipName) { + AssetManager assetManager = context.getAssets(); + try { + InputStream inputStream = assetManager.open(zipName); + ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(inputStream)); + ZipEntry zipEntry; + byte[] buffer = new byte[4096]; + while ((zipEntry = zipInputStream.getNextEntry()) != null) { + String fileOrDirectory = zipEntry.getName(); + Uri.Builder builder = new Uri.Builder(); + builder.scheme("file"); + builder.appendPath(toPath); + builder.appendPath(fileOrDirectory); + String fullToPath = builder.build().getPath(); + if (zipEntry.isDirectory()) { + File directory = new File(fullToPath); + directory.mkdirs(); + continue; + } + Log.i("DOTNET", "Extracting asset to " + fullToPath); + int count = 0; + FileOutputStream fileOutputStream = new FileOutputStream(fullToPath); + while ((count = zipInputStream.read(buffer)) != -1) { + fileOutputStream.write(buffer, 0, count); + } + fileOutputStream.close(); + zipInputStream.closeEntry(); + } + zipInputStream.close(); + } catch (IOException e) { + Log.e("DOTNET", e.getLocalizedMessage()); + } + } + + native int initRuntime(String libsDir, String cacheDir, String docsDir); +} diff --git a/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/runtime-android.c b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/runtime-android.c new file mode 100644 index 00000000000000..4a2af6a62ead79 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Templates/runtime-android.c @@ -0,0 +1,211 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *bundle_path; + +#define LOG_INFO(fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, "DOTNET", fmt, ##__VA_ARGS__) +#define LOG_ERROR(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, "DOTNET", fmt, ##__VA_ARGS__) + +static MonoAssembly* +load_assembly (const char *name, const char *culture) +{ + char filename [1024]; + char path [1024]; + int res; + + LOG_INFO ("assembly_preload_hook: %s %s %s\n", name, culture, bundle_path); + + int len = strlen (name); + int has_extension = len > 3 && name [len - 4] == '.' && (!strcmp ("exe", name + (len - 3)) || !strcmp ("dll", name + (len - 3))); + + // add extensions if required. + strlcpy (filename, name, sizeof (filename)); + if (!has_extension) { + strlcat (filename, ".dll", sizeof (filename)); + } + + if (culture && strcmp (culture, "")) + res = snprintf (path, sizeof (path) - 1, "%s/%s/%s", bundle_path, culture, filename); + else + res = snprintf (path, sizeof (path) - 1, "%s/%s", bundle_path, filename); + assert (res > 0); + + struct stat buffer; + if (stat (path, &buffer) == 0) { + MonoAssembly *assembly = mono_assembly_open (path, NULL); + assert (assembly); + return assembly; + } + return NULL; +} + +static MonoAssembly* +assembly_preload_hook (MonoAssemblyName *aname, char **assemblies_path, void* user_data) +{ + const char *name = mono_assembly_name_get_name (aname); + const char *culture = mono_assembly_name_get_culture (aname); + return load_assembly (name, culture); +} + +char * +strdup_printf (const char *msg, ...) +{ + va_list args; + char *formatted = NULL; + va_start (args, msg); + vasprintf (&formatted, msg, args); + va_end (args); + return formatted; +} + +static MonoObject * +fetch_exception_property (MonoObject *obj, const char *name, bool is_virtual) +{ + MonoMethod *get = NULL; + MonoMethod *get_virt = NULL; + MonoObject *exc = NULL; + + get = mono_class_get_method_from_name (mono_get_exception_class (), name, 0); + if (get) { + if (is_virtual) { + get_virt = mono_object_get_virtual_method (obj, get); + if (get_virt) + get = get_virt; + } + + return (MonoObject *) mono_runtime_invoke (get, obj, NULL, &exc); + } else { + printf ("Could not find the property System.Exception.%s", name); + } + + return NULL; +} + +static char * +fetch_exception_property_string (MonoObject *obj, const char *name, bool is_virtual) +{ + MonoString *str = (MonoString *) fetch_exception_property (obj, name, is_virtual); + return str ? mono_string_to_utf8 (str) : NULL; +} + +void +unhandled_exception_handler (MonoObject *exc, void *user_data) +{ + MonoClass *type = mono_object_get_class (exc); + char *type_name = strdup_printf ("%s.%s", mono_class_get_namespace (type), mono_class_get_name (type)); + char *trace = fetch_exception_property_string (exc, "get_StackTrace", true); + char *message = fetch_exception_property_string (exc, "get_Message", true); + + LOG_ERROR("UnhandledException: %s %s %s", type_name, message, trace); + + free (trace); + free (message); + free (type_name); + exit (1); +} + +void +log_callback (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) +{ + LOG_INFO ("(%s %s) %s", log_domain, log_level, message); + if (fatal) { + LOG_ERROR ("Exit code: %d.", 1); + exit (1); + } +} + +int +mono_mobile_runtime_init (void) +{ + // uncomment for debug output: + // + // setenv ("MONO_LOG_LEVEL", "debug", TRUE); + // setenv ("MONO_LOG_MASK", "all", TRUE); + + bool wait_for_debugger = false; + chdir (bundle_path); + + // TODO: set TRUSTED_PLATFORM_ASSEMBLIES, APP_PATHS and NATIVE_DLL_SEARCH_DIRECTORIES + + const char* appctx_keys[2]; + appctx_keys[0] = "RUNTIME_IDENTIFIER"; + appctx_keys[1] = "APP_CONTEXT_BASE_DIRECTORY"; + + const char* appctx_values[2]; + appctx_values[0] = "%RID%"; + appctx_values[1] = bundle_path; + + monovm_initialize(2, appctx_keys, appctx_values); + + mono_debug_init (MONO_DEBUG_FORMAT_MONO); + mono_install_assembly_preload_hook (assembly_preload_hook, NULL); + mono_install_unhandled_exception_hook (unhandled_exception_handler, NULL); + mono_trace_set_log_handler (log_callback, NULL); + mono_set_signal_chaining (true); + mono_set_crash_chaining (true); + + if (wait_for_debugger) { + char* options[] = { "--debugger-agent=transport=dt_socket,server=y,address=0.0.0.0:55555" }; + mono_jit_parse_options (1, options); + } + mono_jit_init_version ("dotnet.android", "mobile"); + + const char* executable = "%EntryPointLibName%"; + MonoAssembly *assembly = load_assembly (executable, NULL); + assert (assembly); + LOG_INFO ("Executable: %s", executable); + + char *managed_argv [1]; + managed_argv[0] = bundle_path; + + int res = mono_jit_exec (mono_domain_get (), assembly, 1, managed_argv); + LOG_INFO ("Exit code: %d.", res); + return res; +} + +static void +strncpy_str (JNIEnv *env, char *buff, jstring str, int nbuff) +{ + jboolean isCopy = 0; + const char *copy_buff = (*env)->GetStringUTFChars (env, str, &isCopy); + strncpy (buff, copy_buff, nbuff); + if (isCopy) + (*env)->ReleaseStringUTFChars (env, str, copy_buff); +} + +int +Java_net_dot_MonoRunner_initRuntime (JNIEnv* env, jobject thiz, jstring j_files_dir, jstring j_cache_dir, jstring j_docs_dir) +{ + char file_dir[2048]; + char cache_dir[2048]; + char docs_dir[2048]; + strncpy_str (env, file_dir, j_files_dir, sizeof(file_dir)); + strncpy_str (env, cache_dir, j_cache_dir, sizeof(cache_dir)); + strncpy_str (env, docs_dir, j_docs_dir, sizeof(docs_dir)); + + bundle_path = file_dir; + setenv ("HOME", bundle_path, true); + setenv ("TMPDIR", cache_dir, true); + setenv ("DOCSDIR", docs_dir, true); + return mono_mobile_runtime_init (); +} diff --git a/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Utils.cs b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Utils.cs new file mode 100644 index 00000000000000..bc23f927ae26f6 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/Utils.cs @@ -0,0 +1,114 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +internal class Utils +{ + public static string GetEmbeddedResource(string file) + { + using Stream stream = typeof(Utils).Assembly + .GetManifestResourceStream($"{typeof(Utils).Assembly.GetName().Name}.Templates.{file}")!; + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + public static string RunProcess( + string path, + string args = "", + IDictionary? envVars = null, + string? workingDir = null, + bool ignoreErrors = false, + bool silent = true) + { + LogInfo($"Running: {path} {args}"); + var outputBuilder = new StringBuilder(); + var errorBuilder = new StringBuilder(); + var processStartInfo = new ProcessStartInfo + { + FileName = path, + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardError = true, + RedirectStandardOutput = true, + Arguments = args, + }; + + if (workingDir != null) + processStartInfo.WorkingDirectory = workingDir; + + if (envVars != null) + { + foreach (KeyValuePair envVar in envVars) + processStartInfo.EnvironmentVariables[envVar.Key] = envVar.Value; + } + + Process? process = Process.Start(processStartInfo); + if (process == null) + throw new ArgumentException($"Process.Start({path} {args}) returned null process"); + + process.ErrorDataReceived += (sender, e) => + { + if (!silent) + { + LogError(e.Data); + outputBuilder.AppendLine(e.Data); + } + errorBuilder.AppendLine(e.Data); + }; + process.OutputDataReceived += (sender, e) => + { + if (!silent) + { + LogInfo(e.Data); + outputBuilder.AppendLine(e.Data); + } + }; + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + process.WaitForExit(); + + if (!ignoreErrors && process.ExitCode != 0) + throw new Exception("Error: " + errorBuilder); + + return outputBuilder.ToString().Trim('\r','\n'); + } + + public static void DirectoryCopy(string sourceDir, string destDir, Func predicate) + { + string[] files = Directory.GetFiles(sourceDir, "*", SearchOption.AllDirectories); + foreach (string file in files) + { + if (!predicate(file)) + continue; + + string relativePath = Path.GetRelativePath(sourceDir, file); + string? relativeDir = Path.GetDirectoryName(relativePath); + if (!string.IsNullOrEmpty(relativeDir)) + Directory.CreateDirectory(Path.Combine(destDir, relativeDir)); + + File.Copy(file, Path.Combine(destDir, relativePath), true); + } + } + + public static TaskLoggingHelper? Logger { get; set; } + + public static void LogInfo(string? msg) + { + if (msg != null) + Logger?.LogMessage(MessageImportance.High, msg); + } + + public static void LogError(string? msg) + { + if (msg != null) + Logger?.LogError(msg); + } +} diff --git a/tools-local/tasks/mobile.tasks/AotCompilerTask/MonoAOTCompiler.cs b/tools-local/tasks/mobile.tasks/AotCompilerTask/MonoAOTCompiler.cs new file mode 100644 index 00000000000000..8f8643ae606d7f --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -0,0 +1,256 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Concurrent; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +public class MonoAOTCompiler : Microsoft.Build.Utilities.Task +{ + /// + /// Path to AOT cross-compiler binary (mono-aot-cross) + /// + [Required] + public string CompilerBinaryPath { get; set; } = ""!; + + /// + /// Assemblies to be AOTd. They need to be in a self-contained directory. + /// + /// Metadata: + /// - AotArguments: semicolon-separated list of options that will be passed to --aot= + /// - ProcessArguments: semicolon-separated list of options that will be passed to the AOT compiler itself + /// + [Required] + public ITaskItem[] Assemblies { get; set; } = Array.Empty(); + + /// + /// Assemblies which were AOT compiled. + /// + /// Successful AOT compilation will set the following metadata on the items: + /// - AssemblerFile (when using OutputType=AsmOnly) + /// - ObjectFile (when using OutputType=Normal) + /// - AotDataFile + /// - LlvmObjectFile (if using LLVM) + /// - LlvmBitcodeFile (if using LLVM-only) + /// + [Output] + public ITaskItem[]? CompiledAssemblies { get; set; } + + /// + /// Disable parallel AOT compilation + /// + public bool DisableParallelAot { get; set; } + + /// + /// Use LLVM for AOT compilation. + /// The cross-compiler must be built with LLVM support + /// + public bool UseLLVM { get; set; } + + /// + /// Choose between 'Normal', 'Full', 'LLVMOnly'. + /// LLVMOnly means to use only LLVM for FullAOT, AOT result will be a LLVM Bitcode file (the cross-compiler must be built with LLVM support) + /// + public string Mode { get; set; } = nameof(MonoAotMode.Normal); + + /// + /// Choose between 'Normal', 'AsmOnly' + /// AsmOnly means the AOT compiler will produce .s assembly code instead of an .o object file. + /// + public string OutputType { get; set; } = nameof(MonoAotOutputType.Normal); + + /// + /// Path to the directory where LLVM binaries (opt and llc) are found. + /// It's required if UseLLVM is set + /// + public string? LLVMPath { get; set; } + + /// + /// Path to the directory where msym artifacts are stored. + /// + public string? MsymPath { get; set; } + + ConcurrentBag compiledAssemblies = new ConcurrentBag(); + MonoAotMode parsedAotMode; + MonoAotOutputType parsedOutputType; + + public override bool Execute() + { + Utils.Logger = Log; + + if (string.IsNullOrEmpty(CompilerBinaryPath)) + { + throw new ArgumentException($"'{nameof(CompilerBinaryPath)}' is required.", nameof(CompilerBinaryPath)); + } + + if (!File.Exists(CompilerBinaryPath)) + { + throw new ArgumentException($"'{CompilerBinaryPath}' doesn't exist.", nameof(CompilerBinaryPath)); + } + + if (Assemblies.Length == 0) + { + throw new ArgumentException($"'{nameof(Assemblies)}' is required.", nameof(Assemblies)); + } + + if (UseLLVM && string.IsNullOrEmpty(LLVMPath)) + { + // prevent using some random llc/opt from PATH (installed with clang) + throw new ArgumentException($"'{nameof(LLVMPath)}' is required when '{nameof(UseLLVM)}' is true.", nameof(LLVMPath)); + } + + switch (Mode) + { + case "Normal": parsedAotMode = MonoAotMode.Normal; break; + case "Full": parsedAotMode = MonoAotMode.Full; break; + case "LLVMOnly": parsedAotMode = MonoAotMode.LLVMOnly; break; + default: + throw new ArgumentException($"'{nameof(Mode)}' must be one of: '{nameof(MonoAotMode.Normal)}', '{nameof(MonoAotMode.Full)}', '{nameof(MonoAotMode.LLVMOnly)}'. Received: '{Mode}'.", nameof(Mode)); + } + + switch (OutputType) + { + case "Normal": parsedOutputType = MonoAotOutputType.Normal; break; + case "AsmOnly": parsedOutputType = MonoAotOutputType.AsmOnly; break; + default: + throw new ArgumentException($"'{nameof(OutputType)}' must be one of: '{nameof(MonoAotOutputType.Normal)}', '{nameof(MonoAotOutputType.AsmOnly)}'. Received: '{OutputType}'.", nameof(OutputType)); + } + + if (parsedAotMode == MonoAotMode.LLVMOnly && !UseLLVM) + { + throw new ArgumentException($"'{nameof(UseLLVM)}' must be true when '{nameof(Mode)}' is {nameof(MonoAotMode.LLVMOnly)}.", nameof(UseLLVM)); + } + + Parallel.ForEach(Assemblies, + new ParallelOptions { MaxDegreeOfParallelism = DisableParallelAot ? 1 : Environment.ProcessorCount }, + assemblyItem => PrecompileLibrary (assemblyItem)); + + CompiledAssemblies = compiledAssemblies.ToArray(); + + return true; + } + + private void PrecompileLibrary(ITaskItem assemblyItem) + { + string assembly = assemblyItem.ItemSpec; + string directory = Path.GetDirectoryName(assembly)!; + var aotAssembly = new TaskItem(assembly); + var aotArgs = new List(); + var processArgs = new List(); + + var a = assemblyItem.GetMetadata("AotArguments"); + if (a != null) + { + aotArgs.AddRange(a.Split(";", StringSplitOptions.RemoveEmptyEntries)); + } + + var p = assemblyItem.GetMetadata("ProcessArguments"); + if (p != null) + { + processArgs.AddRange(p.Split(";", StringSplitOptions.RemoveEmptyEntries)); + } + + Utils.LogInfo($"[AOT] {assembly}"); + + processArgs.Add("--debug"); + + // add LLVM options + if (UseLLVM) + { + processArgs.Add("--llvm"); + + aotArgs.Add($"nodebug"); // can't use debug symbols with LLVM + aotArgs.Add($"llvm-path={LLVMPath}"); + } + else + { + processArgs.Add("--nollvm"); + } + + // compute output mode and file names + if (parsedAotMode == MonoAotMode.LLVMOnly) + { + aotArgs.Add("llvmonly"); + + string llvmBitcodeFile = Path.ChangeExtension(assembly, ".dll.bc"); + aotArgs.Add($"outfile={llvmBitcodeFile}"); + aotAssembly.SetMetadata("LlvmBitcodeFile", llvmBitcodeFile); + } + else + { + if (parsedAotMode == MonoAotMode.Full) + { + aotArgs.Add("full"); + } + + if (parsedOutputType == MonoAotOutputType.AsmOnly) + { + aotArgs.Add("asmonly"); + + string assemblerFile = Path.ChangeExtension(assembly, ".dll.s"); + aotArgs.Add($"outfile={assemblerFile}"); + aotAssembly.SetMetadata("AssemblerFile", assemblerFile); + } + else + { + string objectFile = Path.ChangeExtension(assembly, ".dll.o"); + aotArgs.Add($"outfile={objectFile}"); + aotAssembly.SetMetadata("ObjectFile", objectFile); + } + + if (UseLLVM) + { + string llvmObjectFile = Path.ChangeExtension(assembly, ".dll-llvm.o"); + aotArgs.Add($"llvm-outfile={llvmObjectFile}"); + aotAssembly.SetMetadata("LlvmObjectFile", llvmObjectFile); + } + } + + // pass msym-dir if specified + if (MsymPath != null) + { + aotArgs.Add($"msym-dir={MsymPath}"); + } + + string aotDataFile = Path.ChangeExtension(assembly, ".aotdata"); + aotArgs.Add($"data-outfile={aotDataFile}"); + aotAssembly.SetMetadata("AotDataFile", aotDataFile); + + // we need to quote the entire --aot arguments here to make sure it is parsed + // on Windows as one argument. Otherwise it will be split up into multiple + // values, which wont work. + processArgs.Add($"\"--aot={String.Join(",", aotArgs)}\""); + + processArgs.Add(assembly); + + var envVariables = new Dictionary + { + {"MONO_PATH", directory}, + {"MONO_ENV_OPTIONS", String.Empty} // we do not want options to be provided out of band to the cross compilers + }; + + // run the AOT compiler + Utils.RunProcess(CompilerBinaryPath, String.Join(" ", processArgs), envVariables, directory); + + compiledAssemblies.Add(aotAssembly); + } +} + +public enum MonoAotMode +{ + Normal, + Full, + LLVMOnly, +} + +public enum MonoAotOutputType +{ + Normal, + AsmOnly, +} \ No newline at end of file diff --git a/tools-local/tasks/mobile.tasks/AotCompilerTask/MonoAOTCompiler.csproj b/tools-local/tasks/mobile.tasks/AotCompilerTask/MonoAOTCompiler.csproj new file mode 100644 index 00000000000000..b487236cc36277 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AotCompilerTask/MonoAOTCompiler.csproj @@ -0,0 +1,24 @@ + + + $(NetCoreAppCurrent) + Library + true + false + enable + + + + + + + + + + + + + + PreserveNewest + + + diff --git a/tools-local/tasks/mobile.tasks/AotCompilerTask/MonoAOTCompiler.props b/tools-local/tasks/mobile.tasks/AotCompilerTask/MonoAOTCompiler.props new file mode 100644 index 00000000000000..6824a7fc1c6f10 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AotCompilerTask/MonoAOTCompiler.props @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/tools-local/tasks/mobile.tasks/AotCompilerTask/Utils.cs b/tools-local/tasks/mobile.tasks/AotCompilerTask/Utils.cs new file mode 100644 index 00000000000000..ac649c9661843b --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AotCompilerTask/Utils.cs @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +internal class Utils +{ + public static string RunProcess( + string path, + string args = "", + IDictionary? envVars = null, + string? workingDir = null, + bool ignoreErrors = false) + { + LogInfo($"Running: {path} {args}"); + var outputBuilder = new StringBuilder(); + var errorBuilder = new StringBuilder(); + var processStartInfo = new ProcessStartInfo + { + FileName = path, + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardError = true, + RedirectStandardOutput = true, + Arguments = args, + }; + + if (workingDir != null) + { + processStartInfo.WorkingDirectory = workingDir; + } + + if (envVars != null) + { + foreach (KeyValuePair envVar in envVars) + { + processStartInfo.EnvironmentVariables[envVar.Key] = envVar.Value; + } + } + + Process process = Process.Start(processStartInfo)!; + process.ErrorDataReceived += (sender, e) => + { + LogError(e.Data); + outputBuilder.AppendLine(e.Data); + errorBuilder.AppendLine(e.Data); + }; + process.OutputDataReceived += (sender, e) => + { + LogInfo(e.Data); + outputBuilder.AppendLine(e.Data); + }; + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + process.WaitForExit(); + if (process.ExitCode != 0) + { + throw new Exception("Error: " + errorBuilder); + } + + return outputBuilder.ToString().Trim('\r','\n'); + } + + public static TaskLoggingHelper? Logger { get; set; } + + public static void LogInfo(string? msg) + { + if (msg != null) + { + Logger?.LogMessage(MessageImportance.High, msg); + } + } + + public static void LogError(string? msg) + { + if (msg != null) + { + Logger?.LogError(msg); + } + } +} diff --git a/tools-local/tasks/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs b/tools-local/tasks/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs new file mode 100644 index 00000000000000..39ba74d890f459 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs @@ -0,0 +1,239 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Linq; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +public class AppleAppBuilderTask : Task +{ + /// + /// ProjectName is used as an app name, bundleId and xcode project name + /// + [Required] + public string ProjectName { get; set; } = ""!; + + /// + /// Target directory with *dll and other content to be AOT'd and/or bundled + /// + [Required] + public string AppDir { get; set; } = ""!; + + /// + /// Path to Mono public headers (*.h) + /// + [Required] + public string MonoRuntimeHeaders { get; set; } = ""!; + + /// + /// This library will be used as an entry-point (e.g. TestRunner.dll) + /// + [Required] + public string MainLibraryFileName { get; set; } = ""!; + + /// + /// List of paths to assemblies to be included in the app. For AOT builds the 'ObjectFile' metadata key needs to point to the object file. + /// + [Required] + public ITaskItem[] Assemblies { get; set; } = Array.Empty(); + + /// + /// Path to store build artifacts + /// + public string? OutputDirectory { get; set; } + + /// + /// Produce optimized binaries and use 'Release' config in xcode + /// + public bool Optimized { get; set; } + + /// + /// Target arch, can be "arm64" (device) or "x64" (simulator) at the moment + /// + [Required] + public string Arch { get; set; } = ""!; + + /// + /// DEVELOPER_TEAM provisioning, needed for arm64 builds. + /// + public string? DevTeamProvisioning { get; set; } + + /// + /// Build *.app bundle (using XCode for now) + /// + public bool BuildAppBundle { get; set; } + + /// + /// Generate xcode project + /// + public bool GenerateXcodeProject { get; set; } + + /// + /// Files to be ignored in AppDir + /// + public ITaskItem[]? ExcludeFromAppDir { get; set; } + + /// + /// Path to a custom main.m with custom UI + /// A default one is used if it's not set + /// + public string? NativeMainSource { get; set; } + + /// + /// Use Console-style native UI template + /// (use NativeMainSource to override) + /// + public bool UseConsoleUITemplate { get; set; } + + /// + /// Path to *.app bundle + /// + [Output] + public string AppBundlePath { get; set; } = ""!; + + /// + /// Prefer FullAOT mode for Simulator over JIT + /// + public bool UseAotForSimulator { get; set; } + + /// + /// Path to xcode project + /// + [Output] + public string XcodeProjectPath { get; set; } = ""!; + + public override bool Execute() + { + Utils.Logger = Log; + bool isDevice = Arch.Equals("arm64", StringComparison.InvariantCultureIgnoreCase); + + if (!File.Exists(Path.Combine(AppDir, MainLibraryFileName))) + { + throw new ArgumentException($"MainLibraryFileName='{MainLibraryFileName}' was not found in AppDir='{AppDir}'"); + } + + if (ProjectName.Contains(" ")) + { + throw new ArgumentException($"ProjectName='{ProjectName}' should not contain spaces"); + } + + string[] excludes = new string[0]; + if (ExcludeFromAppDir != null) + { + excludes = ExcludeFromAppDir + .Where(i => !string.IsNullOrEmpty(i.ItemSpec)) + .Select(i => i.ItemSpec) + .ToArray(); + } + + string binDir = Path.Combine(AppDir, $"bin-{ProjectName}-{Arch}"); + if (!string.IsNullOrEmpty(OutputDirectory)) + { + binDir = OutputDirectory; + } + Directory.CreateDirectory(binDir); + + var assemblerFiles = new List(); + foreach (ITaskItem file in Assemblies) + { + // use AOT files if available + var obj = file.GetMetadata("AssemblerFile"); + if (!String.IsNullOrEmpty(obj)) + { + assemblerFiles.Add(obj); + } + } + + if ((isDevice || UseAotForSimulator) && !assemblerFiles.Any()) + { + throw new InvalidOperationException("Need list of AOT files for device builds."); + } + + // generate modules.m + GenerateLinkAllFile( + assemblerFiles, + Path.Combine(binDir, "modules.m")); + + if (GenerateXcodeProject) + { + XcodeProjectPath = Xcode.GenerateXCode(ProjectName, MainLibraryFileName, assemblerFiles, + AppDir, binDir, MonoRuntimeHeaders, !isDevice, UseConsoleUITemplate, UseAotForSimulator, Optimized, NativeMainSource); + + if (BuildAppBundle) + { + if (isDevice && string.IsNullOrEmpty(DevTeamProvisioning)) + { + // DevTeamProvisioning shouldn't be empty for arm64 builds + Utils.LogInfo("DevTeamProvisioning is not set, BuildAppBundle step is skipped."); + } + else + { + AppBundlePath = Xcode.BuildAppBundle( + Path.Combine(binDir, ProjectName, ProjectName + ".xcodeproj"), + Arch, Optimized, DevTeamProvisioning); + } + } + } + + return true; + } + + private static void GenerateLinkAllFile(IEnumerable asmFiles, string outputFile) + { + // Generates 'modules.m' in order to register all managed libraries + // + // + // extern void *mono_aot_module_Lib1_info; + // extern void *mono_aot_module_Lib2_info; + // ... + // + // void mono_ios_register_modules (void) + // { + // mono_aot_register_module (mono_aot_module_Lib1_info); + // mono_aot_register_module (mono_aot_module_Lib2_info); + // ... + // } + + Utils.LogInfo("Generating 'modules.m'..."); + + var lsDecl = new StringBuilder(); + lsDecl + .AppendLine("#include ") + .AppendLine("#include ") + .AppendLine() + .AppendLine("#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR)") + .AppendLine(); + + var lsUsage = new StringBuilder(); + lsUsage + .AppendLine("void mono_ios_register_modules (void)") + .AppendLine("{"); + foreach (string asmFile in asmFiles) + { + string symbol = "mono_aot_module_" + + Path.GetFileName(asmFile) + .Replace(".dll.s", "") + .Replace(".", "_") + .Replace("-", "_") + "_info"; + + lsDecl.Append("extern void *").Append(symbol).Append(';').AppendLine(); + lsUsage.Append("\tmono_aot_register_module (").Append(symbol).Append(");").AppendLine(); + } + lsDecl + .AppendLine() + .Append(lsUsage) + .AppendLine("}") + .AppendLine() + .AppendLine("#endif") + .AppendLine(); + + File.WriteAllText(outputFile, lsDecl.ToString()); + Utils.LogInfo($"Saved to {outputFile}."); + } +} diff --git a/tools-local/tasks/mobile.tasks/AppleAppBuilder/AppleAppBuilder.csproj b/tools-local/tasks/mobile.tasks/AppleAppBuilder/AppleAppBuilder.csproj new file mode 100644 index 00000000000000..255150988f9c7d --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AppleAppBuilder/AppleAppBuilder.csproj @@ -0,0 +1,23 @@ + + + $(NetCoreAppCurrent) + Library + true + false + enable + + + + + + + + + + + + + + + + diff --git a/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/CMakeLists.txt.template b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/CMakeLists.txt.template new file mode 100644 index 00000000000000..ecd3d6c1e614d4 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/CMakeLists.txt.template @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.16) + +project(%ProjectName%) +enable_language(OBJC ASM) + +set(APP_RESOURCES +%AppResources% +) + +add_executable( + %ProjectName% + %MainSource% + runtime.h + runtime.m + modules.m + ${APP_RESOURCES} +) + +%AotSources% + +%Defines% + +include_directories("%MonoInclude%") + +set_target_properties(%ProjectName% PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist + XCODE_ATTRIBUTE_ENABLE_BITCODE "NO" + XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING "NO" + RESOURCE "${APP_RESOURCES}" +) + +# FIXME: `XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING` should not be NO + +target_link_libraries( + %ProjectName% + "-framework Foundation" + "-framework Security" + "-framework UIKit" + "-framework GSS" + "-lz" + "-liconv" +%NativeLibrariesToLink% +) diff --git a/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/Info.plist.template b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/Info.plist.template new file mode 100644 index 00000000000000..c8c0f53f160b5e --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/Info.plist.template @@ -0,0 +1,37 @@ + + + + + CFBundleDevelopmentRegion + en-US + CFBundleExecutable + %BundleIdentifier% + CFBundleIdentifier + net.dot.%BundleIdentifier% + CFBundleName + %BundleIdentifier% + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + + + diff --git a/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/main-console.m b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/main-console.m new file mode 100644 index 00000000000000..847d5787aae85b --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/main-console.m @@ -0,0 +1,94 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#import +#import "runtime.h" +#include + +@interface ViewController : UIViewController +@end + +@interface AppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@property (strong, nonatomic) ViewController *controller; +@end + +@implementation AppDelegate +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.controller = [[ViewController alloc] initWithNibName:nil bundle:nil]; + self.window.rootViewController = self.controller; + [self.window makeKeyAndVisible]; + return YES; +} +@end + +UILabel *summaryLabel; +UITextView* logLabel; + +@implementation ViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame]; + logLabel = [[UITextView alloc] initWithFrame: + CGRectMake(2.0, 50.0, applicationFrame.size.width - 2.0, applicationFrame.size.height - 50.0)]; + logLabel.font = [UIFont systemFontOfSize:9.0]; + logLabel.backgroundColor = [UIColor blackColor]; + logLabel.textColor = [UIColor greenColor]; + logLabel.scrollEnabled = YES; + logLabel.alwaysBounceVertical = YES; + logLabel.editable = NO; + logLabel.clipsToBounds = YES; + + summaryLabel = [[UILabel alloc] initWithFrame: CGRectMake(10.0, 0.0, applicationFrame.size.width - 10.0, 50)]; + summaryLabel.textColor = [UIColor whiteColor]; + summaryLabel.font = [UIFont boldSystemFontOfSize: 12]; + summaryLabel.numberOfLines = 2; + summaryLabel.textAlignment = NSTextAlignmentLeft; +#ifdef TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR) + summaryLabel.text = @"Loading..."; +#else + summaryLabel.text = @"Jitting..."; +#endif + [self.view addSubview:logLabel]; + [self.view addSubview:summaryLabel]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + mono_ios_runtime_init (); + }); +} + +@end + +// can be called from C# to update UI +void +mono_ios_set_summary (const char* value) +{ + NSString* nsstr = [NSString stringWithUTF8String:value]; + dispatch_async(dispatch_get_main_queue(), ^{ + summaryLabel.text = nsstr; + }); +} + +// can be called from C# to update UI +void +mono_ios_append_output (const char* value) +{ + NSString* nsstr = [NSString stringWithUTF8String:value]; + dispatch_async(dispatch_get_main_queue(), ^{ + logLabel.text = [logLabel.text stringByAppendingString:nsstr]; + CGRect caretRect = [logLabel caretRectForPosition:logLabel.endOfDocument]; + [logLabel scrollRectToVisible:caretRect animated:NO]; + [logLabel setScrollEnabled:NO]; + [logLabel setScrollEnabled:YES]; + }); +} + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/main-simple.m b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/main-simple.m new file mode 100644 index 00000000000000..d68fa3b670c029 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/main-simple.m @@ -0,0 +1,82 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#import +#import "runtime.h" + +@interface ViewController : UIViewController +@end + +@interface AppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@property (strong, nonatomic) ViewController *controller; +@end + +@implementation AppDelegate +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.controller = [[ViewController alloc] initWithNibName:nil bundle:nil]; + self.window.rootViewController = self.controller; + [self.window makeKeyAndVisible]; + return YES; +} +@end + +UILabel *label; +void (*clickHandlerPtr)(void); + +@implementation ViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + label = [[UILabel alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + label.textColor = [UIColor greenColor]; + label.font = [UIFont boldSystemFontOfSize: 30]; + label.numberOfLines = 2; + label.textAlignment = NSTextAlignmentCenter; + label.text = @"Hello, wire me up!\n(dllimport ios_set_text)"; + [self.view addSubview:label]; + + UIButton *button = [UIButton buttonWithType:UIButtonTypeInfoDark]; + [button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; + [button setFrame:CGRectMake(50, 300, 200, 50)]; + [button setTitle:@"Click me (wire me up)" forState:UIControlStateNormal]; + [button setExclusiveTouch:YES]; + [self.view addSubview:button]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + mono_ios_runtime_init (); + }); +} +-(void) buttonClicked:(UIButton*)sender +{ + if (clickHandlerPtr) + clickHandlerPtr(); +} + +@end + +// called from C# sample +void +ios_register_button_click (void* ptr) +{ + clickHandlerPtr = ptr; +} + +// called from C# sample +void +ios_set_text (const char* value) +{ + NSString* nsstr = [NSString stringWithUTF8String:strdup(value)]; + dispatch_async(dispatch_get_main_queue(), ^{ + label.text = nsstr; + }); +} + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/runtime.h b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/runtime.h new file mode 100644 index 00000000000000..bbfca3240e67e9 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/runtime.h @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#ifndef runtime_h +#define runtime_h + +void mono_ios_runtime_init (void); + +#endif /* runtime_h */ diff --git a/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/runtime.m b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/runtime.m new file mode 100644 index 00000000000000..45b277365c29b9 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/runtime.m @@ -0,0 +1,270 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#import +#include +#include +#include +#include +#include +#include +#include +#include +#include +#import +#include +#include + +static char *bundle_path; + +// no-op for iOS and tvOS. +// watchOS is not supported yet. +#define MONO_ENTER_GC_UNSAFE +#define MONO_EXIT_GC_UNSAFE + +const char * +get_bundle_path (void) +{ + if (bundle_path) + return bundle_path; + NSBundle* main_bundle = [NSBundle mainBundle]; + NSString* path = [main_bundle bundlePath]; + bundle_path = strdup ([path UTF8String]); + + return bundle_path; +} + +static unsigned char * +load_aot_data (MonoAssembly *assembly, int size, void *user_data, void **out_handle) +{ + *out_handle = NULL; + + char path [1024]; + int res; + + MonoAssemblyName *assembly_name = mono_assembly_get_name (assembly); + const char *aname = mono_assembly_name_get_name (assembly_name); + const char *bundle = get_bundle_path (); + + os_log_info (OS_LOG_DEFAULT, "Looking for aot data for assembly '%s'.", aname); + res = snprintf (path, sizeof (path) - 1, "%s/%s.aotdata", bundle, aname); + assert (res > 0); + + int fd = open (path, O_RDONLY); + if (fd < 0) { + os_log_info (OS_LOG_DEFAULT, "Could not load the aot data for %s from %s: %s\n", aname, path, strerror (errno)); + return NULL; + } + + void *ptr = mmap (NULL, size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); + if (ptr == MAP_FAILED) { + os_log_info (OS_LOG_DEFAULT, "Could not map the aot file for %s: %s\n", aname, strerror (errno)); + close (fd); + return NULL; + } + + close (fd); + os_log_info (OS_LOG_DEFAULT, "Loaded aot data for %s.\n", aname); + *out_handle = ptr; + return (unsigned char *) ptr; +} + +static void +free_aot_data (MonoAssembly *assembly, int size, void *user_data, void *handle) +{ + munmap (handle, size); +} + +static MonoAssembly* +load_assembly (const char *name, const char *culture) +{ + const char *bundle = get_bundle_path (); + char filename [1024]; + char path [1024]; + int res; + + os_log_info (OS_LOG_DEFAULT, "assembly_preload_hook: %{public}s %{public}s %{public}s\n", name, culture, bundle); + + int len = strlen (name); + int has_extension = len > 3 && name [len - 4] == '.' && (!strcmp ("exe", name + (len - 3)) || !strcmp ("dll", name + (len - 3))); + + // add extensions if required. + strlcpy (filename, name, sizeof (filename)); + if (!has_extension) { + strlcat (filename, ".dll", sizeof (filename)); + } + + if (culture && strcmp (culture, "")) + res = snprintf (path, sizeof (path) - 1, "%s/%s/%s", bundle, culture, filename); + else + res = snprintf (path, sizeof (path) - 1, "%s/%s", bundle, filename); + assert (res > 0); + + struct stat buffer; + if (stat (path, &buffer) == 0) { + MonoAssembly *assembly = mono_assembly_open (path, NULL); + assert (assembly); + return assembly; + } + return NULL; +} + +static MonoAssembly* +assembly_preload_hook (MonoAssemblyName *aname, char **assemblies_path, void* user_data) +{ + const char *name = mono_assembly_name_get_name (aname); + const char *culture = mono_assembly_name_get_culture (aname); + return load_assembly (name, culture); +} + +char * +strdup_printf (const char *msg, ...) +{ + va_list args; + char *formatted = NULL; + va_start (args, msg); + vasprintf (&formatted, msg, args); + va_end (args); + return formatted; +} + +static MonoObject * +fetch_exception_property (MonoObject *obj, const char *name, bool is_virtual) +{ + MonoMethod *get = NULL; + MonoMethod *get_virt = NULL; + MonoObject *exc = NULL; + + get = mono_class_get_method_from_name (mono_get_exception_class (), name, 0); + if (get) { + if (is_virtual) { + get_virt = mono_object_get_virtual_method (obj, get); + if (get_virt) + get = get_virt; + } + + return (MonoObject *) mono_runtime_invoke (get, obj, NULL, &exc); + } else { + printf ("Could not find the property System.Exception.%s", name); + } + + return NULL; +} + +static char * +fetch_exception_property_string (MonoObject *obj, const char *name, bool is_virtual) +{ + MonoString *str = (MonoString *) fetch_exception_property (obj, name, is_virtual); + return str ? mono_string_to_utf8 (str) : NULL; +} + +void +unhandled_exception_handler (MonoObject *exc, void *user_data) +{ + NSMutableString *msg = [[NSMutableString alloc] init]; + + MonoClass *type = mono_object_get_class (exc); + char *type_name = strdup_printf ("%s.%s", mono_class_get_namespace (type), mono_class_get_name (type)); + char *trace = fetch_exception_property_string (exc, "get_StackTrace", true); + char *message = fetch_exception_property_string (exc, "get_Message", true); + + [msg appendString:@"Unhandled managed exceptions:\n"]; + [msg appendFormat: @"%s (%s)\n%s\n", message, type_name, trace ? trace : ""]; + + free (trace); + free (message); + free (type_name); + + os_log_info (OS_LOG_DEFAULT, "%@", msg); + os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", 1); + exit (1); +} + +void +log_callback (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) +{ + os_log_info (OS_LOG_DEFAULT, "(%s %s) %s", log_domain, log_level, message); + if (fatal) { + os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", 1); + exit (1); + } +} + +static void +register_dllmap (void) +{ +//%DllMap% +} + +#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR) +void mono_jit_set_aot_mode (MonoAotMode mode); +void mono_ios_register_modules (void); +#endif + +void +mono_ios_runtime_init (void) +{ + // for now, only Invariant Mode is supported (FIXME: integrate ICU) + setenv ("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", TRUE); + // uncomment for debug output: + // + // setenv ("MONO_LOG_LEVEL", "debug", TRUE); + // setenv ("MONO_LOG_MASK", "all", TRUE); + + id args_array = [[NSProcessInfo processInfo] arguments]; + assert ([args_array count] <= 128); + const char *managed_argv [128]; + int argi; + for (argi = 0; argi < [args_array count]; argi++) { + NSString* arg = [args_array objectAtIndex: argi]; + managed_argv[argi] = [arg UTF8String]; + } + + bool wait_for_debugger = FALSE; + + const char* bundle = get_bundle_path (); + chdir (bundle); + + // TODO: set TRUSTED_PLATFORM_ASSEMBLIES, APP_PATHS and NATIVE_DLL_SEARCH_DIRECTORIES + monovm_initialize(0, NULL, NULL); + +#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR) + register_dllmap (); + // register modules + mono_ios_register_modules (); + mono_jit_set_aot_mode (MONO_AOT_MODE_FULL); +#endif + + mono_debug_init (MONO_DEBUG_FORMAT_MONO); + mono_install_assembly_preload_hook (assembly_preload_hook, NULL); + mono_install_load_aot_data_hook (load_aot_data, free_aot_data, NULL); + mono_install_unhandled_exception_hook (unhandled_exception_handler, NULL); + mono_trace_set_log_handler (log_callback, NULL); + mono_set_signal_chaining (TRUE); + mono_set_crash_chaining (TRUE); + + if (wait_for_debugger) { + char* options[] = { "--debugger-agent=transport=dt_socket,server=y,address=0.0.0.0:55555" }; + mono_jit_parse_options (1, options); + } + mono_jit_init_version ("dotnet.ios", "mobile"); + +#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR) + // device runtimes are configured to use lazy gc thread creation + MONO_ENTER_GC_UNSAFE; + mono_gc_init_finalizer_thread (); + MONO_EXIT_GC_UNSAFE; +#endif + + const char* executable = "%EntryPointLibName%"; + MonoAssembly *assembly = load_assembly (executable, NULL); + assert (assembly); + os_log_info (OS_LOG_DEFAULT, "Executable: %{public}s", executable); + + int res = mono_jit_exec (mono_domain_get (), assembly, argi, managed_argv); + // Print this so apps parsing logs can detect when we exited + os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", res); + + exit (res); +} diff --git a/tools-local/tasks/mobile.tasks/AppleAppBuilder/Utils.cs b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Utils.cs new file mode 100644 index 00000000000000..41d16cb86ad909 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Utils.cs @@ -0,0 +1,96 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +internal class Utils +{ + public static string GetEmbeddedResource(string file) + { + using Stream stream = typeof(Utils).Assembly + .GetManifestResourceStream("AppleAppBuilder.Templates." + file)!; + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + public static string RunProcess( + string path, + string args = "", + IDictionary? envVars = null, + string? workingDir = null, + bool ignoreErrors = false) + { + LogInfo($"Running: {path} {args}"); + var outputBuilder = new StringBuilder(); + var errorBuilder = new StringBuilder(); + var processStartInfo = new ProcessStartInfo + { + FileName = path, + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardError = true, + RedirectStandardOutput = true, + Arguments = args, + }; + + if (workingDir != null) + { + processStartInfo.WorkingDirectory = workingDir; + } + + if (envVars != null) + { + foreach (KeyValuePair envVar in envVars) + { + processStartInfo.EnvironmentVariables[envVar.Key] = envVar.Value; + } + } + + Process process = Process.Start(processStartInfo)!; + process.ErrorDataReceived += (sender, e) => + { + LogError(e.Data); + outputBuilder.AppendLine(e.Data); + errorBuilder.AppendLine(e.Data); + }; + process.OutputDataReceived += (sender, e) => + { + LogInfo(e.Data); + outputBuilder.AppendLine(e.Data); + }; + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + process.WaitForExit(); + if (process.ExitCode != 0) + { + throw new Exception("Error: " + errorBuilder); + } + + return outputBuilder.ToString().Trim('\r','\n'); + } + + public static TaskLoggingHelper? Logger { get; set; } + + public static void LogInfo(string? msg) + { + if (msg != null) + { + Logger?.LogMessage(MessageImportance.High, msg); + } + } + + public static void LogError(string? msg) + { + if (msg != null) + { + Logger?.LogError(msg); + } + } +} diff --git a/tools-local/tasks/mobile.tasks/AppleAppBuilder/Xcode.cs b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Xcode.cs new file mode 100644 index 00000000000000..76ec75c0d3225d --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Xcode.cs @@ -0,0 +1,170 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +internal class Xcode +{ + public static string Sysroot { get; } = Utils.RunProcess("xcrun", "--sdk iphoneos --show-sdk-path"); + + public static string GenerateXCode( + string projectName, + string entryPointLib, + IEnumerable asmFiles, + string workspace, + string binDir, + string monoInclude, + bool preferDylibs, + bool useConsoleUiTemplate, + bool useAotForSimulator, + bool stripDebugSymbols, + string? nativeMainSource = null) + { + // bundle everything as resources excluding native files + var excludes = new List { ".dll.o", ".dll.s", ".dwarf", ".m", ".h", ".a", ".bc", "libmonosgen-2.0.dylib" }; + if (stripDebugSymbols) + { + excludes.Add(".pdb"); + } + + string[] resources = Directory.GetFiles(workspace) + .Where(f => !excludes.Any(e => f.EndsWith(e, StringComparison.InvariantCultureIgnoreCase))) + .Concat(Directory.GetFiles(binDir, "*.aotdata")) + .ToArray(); + + if (string.IsNullOrEmpty(nativeMainSource)) + { + // use built-in main.m (with default UI) if it's not set + nativeMainSource = Path.Combine(binDir, "main.m"); + File.WriteAllText(nativeMainSource, Utils.GetEmbeddedResource(useConsoleUiTemplate ? "main-console.m" : "main-simple.m")); + } + else + { + string newMainPath = Path.Combine(binDir, "main.m"); + if (nativeMainSource != newMainPath) + { + File.Copy(nativeMainSource, Path.Combine(binDir, "main.m"), true); + nativeMainSource = newMainPath; + } + } + + string cmakeLists = Utils.GetEmbeddedResource("CMakeLists.txt.template") + .Replace("%ProjectName%", projectName) + .Replace("%AppResources%", string.Join(Environment.NewLine, resources.Select(r => " " + r))) + .Replace("%MainSource%", nativeMainSource) + .Replace("%MonoInclude%", monoInclude); + + string[] dylibs = Directory.GetFiles(workspace, "*.dylib"); + string toLink = ""; + foreach (string lib in Directory.GetFiles(workspace, "*.a")) + { + string libName = Path.GetFileNameWithoutExtension(lib); + // libmono must always be statically linked, for other librarires we can use dylibs + bool dylibExists = libName != "libmonosgen-2.0" && dylibs.Any(dylib => Path.GetFileName(dylib) == libName + ".dylib"); + + if (!preferDylibs || !dylibExists) + { + // these libraries are pinvoked + // -force_load will be removed once we enable direct-pinvokes for AOT + toLink += $" \"-force_load {lib}\"{Environment.NewLine}"; + } + } + + string aotSources = ""; + foreach (string asm in asmFiles) + { + // these libraries are linked via modules.m + var name = Path.GetFileNameWithoutExtension(asm); + aotSources += $"add_library({name} OBJECT {asm}){Environment.NewLine}"; + toLink += $" {name}{Environment.NewLine}"; + } + + cmakeLists = cmakeLists.Replace("%NativeLibrariesToLink%", toLink); + cmakeLists = cmakeLists.Replace("%AotSources%", aotSources); + cmakeLists = cmakeLists.Replace("%Defines%", + useAotForSimulator ? "add_definitions(-DUSE_AOT_FOR_SIMULATOR=1)" : ""); + + string plist = Utils.GetEmbeddedResource("Info.plist.template") + .Replace("%BundleIdentifier%", projectName); + + File.WriteAllText(Path.Combine(binDir, "Info.plist"), plist); + File.WriteAllText(Path.Combine(binDir, "CMakeLists.txt"), cmakeLists); + + var cmakeArgs = new StringBuilder(); + cmakeArgs + .Append("-S.") + .Append(" -B").Append(projectName) + .Append(" -GXcode") + .Append(" -DCMAKE_SYSTEM_NAME=iOS") + .Append(" \"-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64\"") + .Append(" -DCMAKE_OSX_DEPLOYMENT_TARGET=10.1") + .Append(" -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=NO"); + + File.WriteAllText(Path.Combine(binDir, "runtime.h"), + Utils.GetEmbeddedResource("runtime.h")); + + // forward pinvokes to "__Internal" + var dllMap = new StringBuilder(); + foreach (string aFile in Directory.GetFiles(workspace, "*.a")) + { + string aFileName = Path.GetFileNameWithoutExtension(aFile); + dllMap.AppendLine($" mono_dllmap_insert (NULL, \"{aFileName}\", NULL, \"__Internal\", NULL);"); + + // also register with or without "lib" prefix + aFileName = aFileName.StartsWith("lib") ? aFileName.Remove(0, 3) : "lib" + aFileName; + dllMap.AppendLine($" mono_dllmap_insert (NULL, \"{aFileName}\", NULL, \"__Internal\", NULL);"); + } + + File.WriteAllText(Path.Combine(binDir, "runtime.m"), + Utils.GetEmbeddedResource("runtime.m") + .Replace("//%DllMap%", dllMap.ToString()) + .Replace("%EntryPointLibName%", Path.GetFileName(entryPointLib))); + + Utils.RunProcess("cmake", cmakeArgs.ToString(), workingDir: binDir); + + return Path.Combine(binDir, projectName, projectName + ".xcodeproj"); + } + + public static string BuildAppBundle( + string xcodePrjPath, string architecture, bool optimized, string? devTeamProvisioning = null) + { + string sdk = ""; + var args = new StringBuilder(); + args.Append("ONLY_ACTIVE_ARCH=NO"); + if (architecture == "arm64") + { + sdk = "iphoneos"; + args.Append(" -arch arm64") + .Append(" -sdk iphoneos") + .Append(" -allowProvisioningUpdates") + .Append(" DEVELOPMENT_TEAM=").Append(devTeamProvisioning); + } + else + { + sdk = "iphonesimulator"; + args.Append(" -arch x86_64") + .Append(" -sdk iphonesimulator"); + } + + string config = optimized ? "Release" : "Debug"; + args.Append(" -configuration ").Append(config); + + Utils.RunProcess("xcodebuild", args.ToString(), workingDir: Path.GetDirectoryName(xcodePrjPath)); + + string appPath = Path.Combine(Path.GetDirectoryName(xcodePrjPath)!, config + "-" + sdk, + Path.GetFileNameWithoutExtension(xcodePrjPath) + ".app"); + + long appSize = new DirectoryInfo(appPath) + .EnumerateFiles("*", SearchOption.AllDirectories) + .Sum(file => file.Length); + + Utils.LogInfo($"\nAPP size: {(appSize / 1000_000.0):0.#} Mb.\n"); + + return appPath; + } +} diff --git a/tools-local/tasks/mobile.tasks/WasmAppBuilder/PInvokeTableGenerator.cs b/tools-local/tasks/mobile.tasks/WasmAppBuilder/PInvokeTableGenerator.cs new file mode 100644 index 00000000000000..dd72774b5d9888 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/WasmAppBuilder/PInvokeTableGenerator.cs @@ -0,0 +1,146 @@ +// -*- indent-tabs-mode: nil -*- +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Reflection; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +public class PInvokeTableGenerator : Task +{ + [Required] + public ITaskItem[]? Modules { get; set; } + [Required] + public ITaskItem[]? Assemblies { get; set; } + [Required] + public string? OutputPath { get; set; } + + public override bool Execute () { + GenPInvokeTable (Modules!.Select (item => item.ItemSpec).ToArray (), Assemblies!.Select (item => item.ItemSpec).ToArray ()); + return true; + } + + void GenPInvokeTable (string[] pinvokeModules, string[] assemblies) { + var modules = new Dictionary (); + foreach (var module in pinvokeModules) + modules [module] = module; + + var pinvokes = new List (); + + var resolver = new PathAssemblyResolver (assemblies); + var mlc = new MetadataLoadContext (resolver, "System.Private.CoreLib"); + foreach (var aname in assemblies) { + var a = mlc.LoadFromAssemblyPath (aname); + foreach (var type in a.GetTypes ()) + CollectPInvokes (pinvokes, type); + } + + Log.LogMessage (MessageImportance.Normal, $"Generating pinvoke table to '{OutputPath}'."); + + using (var w = File.CreateText (OutputPath!)) { + EmitPInvokeTable (w, modules, pinvokes); + } + } + + void CollectPInvokes (List pinvokes, Type type) { + foreach (var method in type.GetMethods (BindingFlags.DeclaredOnly|BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance)) { + if ((method.Attributes & MethodAttributes.PinvokeImpl) == 0) + continue; + var dllimport = method.CustomAttributes.First (attr => attr.AttributeType.Name == "DllImportAttribute"); + var module = (string)dllimport.ConstructorArguments [0].Value!; + var entrypoint = (string)dllimport.NamedArguments.First (arg => arg.MemberName == "EntryPoint").TypedValue.Value!; + pinvokes.Add (new PInvoke (entrypoint, module, method)); + } + } + + void EmitPInvokeTable (StreamWriter w, Dictionary modules, List pinvokes) { + w.WriteLine ("// GENERATED FILE, DO NOT MODIFY"); + w.WriteLine ("typedef struct {"); + w.WriteLine ("const char *name;"); + w.WriteLine ("void *func;"); + w.WriteLine ("} PinvokeImport;"); + w.WriteLine (); + + foreach (var pinvoke in pinvokes) { + if (modules.ContainsKey (pinvoke.Module)) + w.WriteLine (GenPInvokeDecl (pinvoke)); + } + + foreach (var module in modules.Keys) { + string symbol = module.Replace (".", "_") + "_imports"; + w.WriteLine ("static PinvokeImport " + symbol + " [] = {"); + foreach (var pinvoke in pinvokes) { + if (pinvoke.Module == module) + w.WriteLine ("{\"" + pinvoke.EntryPoint + "\", " + pinvoke.EntryPoint + "},"); + } + w.WriteLine ("{NULL, NULL}"); + w.WriteLine ("};"); + } + w.Write ("static void *pinvoke_tables[] = { "); + foreach (var module in modules.Keys) { + string symbol = module.Replace (".", "_") + "_imports"; + w.Write (symbol + ","); + } + w.WriteLine ("};"); + w.Write ("static char *pinvoke_names[] = { "); + foreach (var module in modules.Keys) { + w.Write ("\"" + module + "\"" + ","); + } + w.WriteLine ("};"); + } + + string MapType (Type t) { + string name = t.Name; + if (name == "Void") + return "void"; + else if (name == "Double") + return "double"; + else if (name == "Single") + return "float"; + else if (name == "Int64") + return "int64_t"; + else if (name == "UInt64") + return "uint64_t"; + else + return "int"; + } + + string GenPInvokeDecl (PInvoke pinvoke) { + var sb = new StringBuilder (); + var method = pinvoke.Method; + sb.Append (MapType (method.ReturnType)); + sb.Append ($" {pinvoke.EntryPoint} ("); + int pindex = 0; + var pars = method.GetParameters (); + foreach (var p in pars) { + if (pindex > 0) + sb.Append (","); + sb.Append (MapType (pars [pindex].ParameterType)); + pindex ++; + } + sb.Append (");"); + return sb.ToString (); + } +} + +class PInvoke +{ + public PInvoke (string entry_point, string module, MethodInfo method) { + EntryPoint = entry_point; + Module = module; + Method = method; + } + + public string EntryPoint; + public string Module; + public MethodInfo Method; +} diff --git a/tools-local/tasks/mobile.tasks/WasmAppBuilder/WasmAppBuilder.cs b/tools-local/tasks/mobile.tasks/WasmAppBuilder/WasmAppBuilder.cs new file mode 100644 index 00000000000000..ce6839f4f62758 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/WasmAppBuilder/WasmAppBuilder.cs @@ -0,0 +1,123 @@ +// -*- indent-tabs-mode: nil -*- +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Reflection; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +public class WasmAppBuilder : Task +{ + // FIXME: Document + + [Required] + public string? AppDir { get; set; } + [Required] + public string? RuntimePackDir { get; set; } + [Required] + public string? MainAssembly { get; set; } + [Required] + public string? MainJS { get; set; } + [Required] + public ITaskItem[]? AssemblySearchPaths { get; set; } + public ITaskItem[]? ExtraAssemblies { get; set; } + + Dictionary? Assemblies; + Resolver? Resolver; + + public override bool Execute () { + if (!File.Exists (MainAssembly)) + throw new ArgumentException ($"File MainAssembly='{MainAssembly}' doesn't exist."); + if (!File.Exists (MainJS)) + throw new ArgumentException ($"File MainJS='{MainJS}' doesn't exist."); + + var paths = new List (); + Assemblies = new Dictionary (); + + // Collect and load assemblies used by the app + foreach (var v in AssemblySearchPaths!) { + var dir = v.ItemSpec; + if (!Directory.Exists (dir)) + throw new ArgumentException ($"Directory '{dir}' doesn't exist or not a directory."); + paths.Add (dir); + } + Resolver = new Resolver (paths); + var mlc = new MetadataLoadContext (Resolver, "System.Private.CoreLib"); + + var mainAssembly = mlc.LoadFromAssemblyPath (MainAssembly); + Add (mlc, mainAssembly); + + if (ExtraAssemblies != null) { + foreach (var item in ExtraAssemblies) { + var refAssembly = mlc.LoadFromAssemblyPath (item.ItemSpec); + Add (mlc, refAssembly); + } + } + + // Create app + Directory.CreateDirectory (AppDir!); + Directory.CreateDirectory (Path.Join (AppDir, "managed")); + foreach (var assembly in Assemblies!.Values) + File.Copy (assembly.Location, Path.Join (AppDir, "managed", Path.GetFileName (assembly.Location)), true); + foreach (var f in new string [] { "dotnet.wasm", "dotnet.js" }) + File.Copy (Path.Join (RuntimePackDir, "native", "wasm", "runtimes", "release", f), Path.Join (AppDir, f), true); + File.Copy (MainJS!, Path.Join (AppDir, "runtime.js"), true); + + using (var sw = File.CreateText (Path.Join (AppDir, "mono-config.js"))) { + sw.WriteLine ("config = {"); + sw.WriteLine ("\tvfs_prefix: \"managed\","); + sw.WriteLine ("\tdeploy_prefix: \"managed\","); + sw.WriteLine ("\tenable_debugging: 0,"); + sw.WriteLine ("\tfile_list: ["); + foreach (var assembly in Assemblies.Values) { + sw.Write ("\"" + Path.GetFileName (assembly.Location) + "\""); + sw.Write (", "); + } + sw.WriteLine ("],"); + sw.WriteLine ("}"); + } + + using (var sw = File.CreateText (Path.Join (AppDir, "run-v8.sh"))) { + sw.WriteLine ("v8 --expose_wasm runtime.js -- --enable-gc --run " + Path.GetFileName (MainAssembly) + " $*"); + } + + return true; + } + + void Add (MetadataLoadContext mlc, Assembly assembly) { + Assemblies! [assembly.GetName ().Name!] = assembly; + foreach (var aname in assembly.GetReferencedAssemblies ()) { + var refAssembly = mlc.LoadFromAssemblyName (aname); + Add (mlc, refAssembly); + } + } +} + +class Resolver : MetadataAssemblyResolver +{ + List SearchPaths; + + public Resolver (List searchPaths) { + this.SearchPaths = searchPaths; + } + + public override Assembly? Resolve (MetadataLoadContext context, AssemblyName assemblyName) { + var name = assemblyName.Name; + foreach (var dir in SearchPaths) { + var path = Path.Combine (dir, name + ".dll"); + if (File.Exists (path)) { + Console.WriteLine (path); + return context.LoadFromAssemblyPath (path); + } + } + return null; + } +} diff --git a/tools-local/tasks/mobile.tasks/WasmAppBuilder/WasmAppBuilder.csproj b/tools-local/tasks/mobile.tasks/WasmAppBuilder/WasmAppBuilder.csproj new file mode 100644 index 00000000000000..ab82b35f708073 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/WasmAppBuilder/WasmAppBuilder.csproj @@ -0,0 +1,23 @@ + + + $(NetCoreAppCurrent) + Library + false + enable + + + + + + + + + + + + + + + diff --git a/tools-local/tasks/tasks.proj b/tools-local/tasks/tasks.proj new file mode 100644 index 00000000000000..a81e2f9590eb62 --- /dev/null +++ b/tools-local/tasks/tasks.proj @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + $([MSBuild]::NormalizePath('$(ArtifactsObjDir)', '$(MSBuildProjectName)', 'Debug', 'build-semaphore.txt')) + + + + + + + \ No newline at end of file